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

Pull vfs pile 1 from Al Viro:
 "Unfortunately, this merge window it'll have a be a lot of small piles -
  my fault, actually, for not keeping #for-next in anything that would
  resemble a sane shape ;-/

  This pile: assorted fixes (the first 3 are -stable fodder, IMO) and
  cleanups + %pd/%pD formats (dentry/file pathname, up to 4 last
  components) + several long-standing patches from various folks.

  There definitely will be a lot more (starting with Miklos'
  check_submount_and_drop() series)"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (26 commits)
  direct-io: Handle O_(D)SYNC AIO
  direct-io: Implement generic deferred AIO completions
  add formats for dentry/file pathnames
  kvm eventfd: switch to fdget
  powerpc kvm: use fdget
  switch fchmod() to fdget
  switch epoll_ctl() to fdget
  switch copy_module_from_fd() to fdget
  git simplify nilfs check for busy subtree
  ibmasmfs: don't bother passing superblock when not needed
  don't pass superblock to hypfs_{mkdir,create*}
  don't pass superblock to hypfs_diag_create_files
  don't pass superblock to hypfs_vm_create_files()
  oprofile: get rid of pointless forward declarations of struct super_block
  oprofilefs_create_...() do not need superblock argument
  oprofilefs_mkdir() doesn't need superblock argument
  don't bother with passing superblock to oprofile_create_stats_files()
  oprofile: don't bother with passing superblock to ->create_files()
  don't bother passing sb to oprofile_create_files()
  coh901318: don't open-code simple_read_from_buffer()
  ...
diff --git a/CREDITS b/CREDITS
index 206d0fc..646a0a9 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1120,6 +1120,7 @@
 D: Improved mmap and munmap handling
 D: General mm minor tidyups
 D: autofs v4 maintainer
+D: Xen subsystem
 S: 987 Alabama St
 S: San Francisco
 S: CA, 94110
diff --git a/Documentation/ABI/stable/sysfs-bus-usb b/Documentation/ABI/stable/sysfs-bus-usb
new file mode 100644
index 0000000..2be603c
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-bus-usb
@@ -0,0 +1,142 @@
+What:		/sys/bus/usb/devices/.../power/persist
+Date:		May 2007
+KernelVersion:	2.6.23
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		If CONFIG_USB_PERSIST is set, then each USB device directory
+		will contain a file named power/persist.  The file holds a
+		boolean value (0 or 1) indicating whether or not the
+		"USB-Persist" facility is enabled for the device.  Since the
+		facility is inherently dangerous, it is disabled by default
+		for all devices except hubs.  For more information, see
+		Documentation/usb/persist.txt.
+
+What:		/sys/bus/usb/devices/.../power/autosuspend
+Date:		March 2007
+KernelVersion:	2.6.21
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		Each USB device directory will contain a file named
+		power/autosuspend.  This file holds the time (in seconds)
+		the device must be idle before it will be autosuspended.
+		0 means the device will be autosuspended as soon as
+		possible.  Negative values will prevent the device from
+		being autosuspended at all, and writing a negative value
+		will resume the device if it is already suspended.
+
+		The autosuspend delay for newly-created devices is set to
+		the value of the usbcore.autosuspend module parameter.
+
+What:		/sys/bus/usb/device/.../power/connected_duration
+Date:		January 2008
+KernelVersion:	2.6.25
+Contact:	Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+		If CONFIG_PM_RUNTIME is enabled then this file
+		is present.  When read, it returns the total time (in msec)
+		that the USB device has been connected to the machine.  This
+		file is read-only.
+Users:
+		PowerTOP <power@bughost.org>
+		http://www.lesswatts.org/projects/powertop/
+
+What:		/sys/bus/usb/device/.../power/active_duration
+Date:		January 2008
+KernelVersion:	2.6.25
+Contact:	Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+		If CONFIG_PM_RUNTIME is enabled then this file
+		is present.  When read, it returns the total time (in msec)
+		that the USB device has been active, i.e. not in a suspended
+		state.  This file is read-only.
+
+		Tools can use this file and the connected_duration file to
+		compute the percentage of time that a device has been active.
+		For example,
+		echo $((100 * `cat active_duration` / `cat connected_duration`))
+		will give an integer percentage.  Note that this does not
+		account for counter wrap.
+Users:
+		PowerTOP <power@bughost.org>
+		http://www.lesswatts.org/projects/powertop/
+
+What:		/sys/bus/usb/devices/<busnum>-<port[.port]>...:<config num>-<interface num>/supports_autosuspend
+Date:		January 2008
+KernelVersion:	2.6.27
+Contact:	Sarah Sharp <sarah.a.sharp@intel.com>
+Description:
+		When read, this file returns 1 if the interface driver
+		for this interface supports autosuspend.  It also
+		returns 1 if no driver has claimed this interface, as an
+		unclaimed interface will not stop the device from being
+		autosuspended if all other interface drivers are idle.
+		The file returns 0 if autosuspend support has not been
+		added to the driver.
+Users:
+		USB PM tool
+		git://git.moblin.org/users/sarah/usb-pm-tool/
+
+What:		/sys/bus/usb/device/.../avoid_reset_quirk
+Date:		December 2009
+Contact:	Oliver Neukum <oliver@neukum.org>
+Description:
+		Writing 1 to this file tells the kernel that this
+		device will morph into another mode when it is reset.
+		Drivers will not use reset for error handling for
+		such devices.
+Users:
+		usb_modeswitch
+
+What:		/sys/bus/usb/devices/.../devnum
+KernelVersion:	since at least 2.6.18
+Description:
+		Device address on the USB bus.
+Users:
+		libusb
+
+What:		/sys/bus/usb/devices/.../bConfigurationValue
+KernelVersion:	since at least 2.6.18
+Description:
+		bConfigurationValue of the *active* configuration for the
+		device. Writing 0 or -1 to bConfigurationValue will reset the
+		active configuration (unconfigure the device). Writing
+		another value will change the active configuration.
+
+		Note that some devices, in violation of the USB spec, have a
+		configuration with a value equal to 0. Writing 0 to
+		bConfigurationValue for these devices will install that
+		configuration, rather then unconfigure the device.
+
+		Writing -1 will always unconfigure the device.
+Users:
+		libusb
+
+What:		/sys/bus/usb/devices/.../busnum
+KernelVersion:	2.6.22
+Description:
+		Bus-number of the USB-bus the device is connected to.
+Users:
+		libusb
+
+What:		/sys/bus/usb/devices/.../descriptors
+KernelVersion:	2.6.26
+Description:
+		Binary file containing cached descriptors of the device. The
+		binary data consists of the device descriptor followed by the
+		descriptors for each configuration of the device.
+		Note that the wTotalLength of the config descriptors can not
+		be trusted, as the device may have a smaller config descriptor
+		than it advertises. The bLength field of each (sub) descriptor
+		can be trusted, and can be used to seek forward one (sub)
+		descriptor at a time until the next config descriptor is found.
+		All descriptors read from this file are in bus-endian format
+Users:
+		libusb
+
+What:		/sys/bus/usb/devices/.../speed
+KernelVersion:	since at least 2.6.18
+Description:
+		Speed the device is connected with to the usb-host in
+		Mbit / second. IE one of 1.5 / 12 / 480 / 5000.
+Users:
+		libusb
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index dda81ff..39c8de0 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -351,6 +351,7 @@
 		6kohm_to_gnd: connected to ground via a 6kOhm resistor,
 		20kohm_to_gnd: connected to ground via a 20kOhm resistor,
 		100kohm_to_gnd: connected to ground via an 100kOhm resistor,
+		500kohm_to_gnd: connected to ground via a 500kOhm resistor,
 		three_state: left floating.
 		For a list of available output power down options read
 		outX_powerdown_mode_available. If Y is not present the
@@ -792,3 +793,21 @@
 Description:
 		This attribute is used to read the amount of quadrature error
 		present in the device at a given time.
+
+What:		/sys/.../iio:deviceX/in_accelX_power_mode
+KernelVersion:	3.11
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Specifies the chip power mode.
+		low_noise: reduce noise level from ADC,
+		low_power: enable low current consumption.
+		For a list of available output power modes read
+		in_accel_power_mode_available.
+
+What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
+KernelVersion:	3.4.0
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Writing '1' stores the current device configuration into
+		on-chip EEPROM. After power-up or chip reset the device will
+		automatically load the saved configuration.
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
index 2ce9c3f..a91aeab 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
+++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
@@ -18,14 +18,6 @@
 		Reading returns either '1' or '0'. '1' means that the
 		pllY is locked.
 
-What:		/sys/bus/iio/devices/iio:deviceX/store_eeprom
-KernelVersion:	3.4.0
-Contact:	linux-iio@vger.kernel.org
-Description:
-		Writing '1' stores the current device configuration into
-		on-chip EEPROM. After power-up or chip reset the device will
-		automatically load the saved configuration.
-
 What:		/sys/bus/iio/devices/iio:deviceX/sync_dividers
 KernelVersion:	3.4.0
 Contact:	linux-iio@vger.kernel.org
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
index d89aded..1254457 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
+++ b/Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
@@ -18,4 +18,4 @@
 		adjust the reference frequency accordingly.
 		The value written has no effect until out_altvoltageY_frequency
 		is updated. Consider to use out_altvoltageY_powerdown to power
-		down the PLL and it's RFOut buffers during REFin changes.
+		down the PLL and its RFOut buffers during REFin changes.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 9759b8c..1430f584b 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -1,81 +1,3 @@
-What:		/sys/bus/usb/devices/.../power/autosuspend
-Date:		March 2007
-KernelVersion:	2.6.21
-Contact:	Alan Stern <stern@rowland.harvard.edu>
-Description:
-		Each USB device directory will contain a file named
-		power/autosuspend.  This file holds the time (in seconds)
-		the device must be idle before it will be autosuspended.
-		0 means the device will be autosuspended as soon as
-		possible.  Negative values will prevent the device from
-		being autosuspended at all, and writing a negative value
-		will resume the device if it is already suspended.
-
-		The autosuspend delay for newly-created devices is set to
-		the value of the usbcore.autosuspend module parameter.
-
-What:		/sys/bus/usb/devices/.../power/persist
-Date:		May 2007
-KernelVersion:	2.6.23
-Contact:	Alan Stern <stern@rowland.harvard.edu>
-Description:
-		If CONFIG_USB_PERSIST is set, then each USB device directory
-		will contain a file named power/persist.  The file holds a
-		boolean value (0 or 1) indicating whether or not the
-		"USB-Persist" facility is enabled for the device.  Since the
-		facility is inherently dangerous, it is disabled by default
-		for all devices except hubs.  For more information, see
-		Documentation/usb/persist.txt.
-
-What:		/sys/bus/usb/device/.../power/connected_duration
-Date:		January 2008
-KernelVersion:	2.6.25
-Contact:	Sarah Sharp <sarah.a.sharp@intel.com>
-Description:
-		If CONFIG_PM_RUNTIME is enabled then this file
-		is present.  When read, it returns the total time (in msec)
-		that the USB device has been connected to the machine.  This
-		file is read-only.
-Users:
-		PowerTOP <power@bughost.org>
-		http://www.lesswatts.org/projects/powertop/
-
-What:		/sys/bus/usb/device/.../power/active_duration
-Date:		January 2008
-KernelVersion:	2.6.25
-Contact:	Sarah Sharp <sarah.a.sharp@intel.com>
-Description:
-		If CONFIG_PM_RUNTIME is enabled then this file
-		is present.  When read, it returns the total time (in msec)
-		that the USB device has been active, i.e. not in a suspended
-		state.  This file is read-only.
-
-		Tools can use this file and the connected_duration file to
-		compute the percentage of time that a device has been active.
-		For example,
-		echo $((100 * `cat active_duration` / `cat connected_duration`))
-		will give an integer percentage.  Note that this does not
-		account for counter wrap.
-Users:
-		PowerTOP <power@bughost.org>
-		http://www.lesswatts.org/projects/powertop/
-
-What:		/sys/bus/usb/device/<busnum>-<devnum>...:<config num>-<interface num>/supports_autosuspend
-Date:		January 2008
-KernelVersion:	2.6.27
-Contact:	Sarah Sharp <sarah.a.sharp@intel.com>
-Description:
-		When read, this file returns 1 if the interface driver
-		for this interface supports autosuspend.  It also
-		returns 1 if no driver has claimed this interface, as an
-		unclaimed interface will not stop the device from being
-		autosuspended if all other interface drivers are idle.
-		The file returns 0 if autosuspend support has not been
-		added to the driver.
-Users:
-		USB PM tool
-		git://git.moblin.org/users/sarah/usb-pm-tool/
-
 What:		/sys/bus/usb/device/.../authorized
 Date:		July 2008
 KernelVersion:	2.6.26
@@ -172,17 +94,6 @@
 		device IDs, exactly like reading from the entry
 		"/sys/bus/usb/drivers/.../new_id"
 
-What:		/sys/bus/usb/device/.../avoid_reset_quirk
-Date:		December 2009
-Contact:	Oliver Neukum <oliver@neukum.org>
-Description:
-		Writing 1 to this file tells the kernel that this
-		device will morph into another mode when it is reset.
-		Drivers will not use reset for error handling for
-		such devices.
-Users:
-		usb_modeswitch
-
 What:		/sys/bus/usb/devices/.../power/usb2_hardware_lpm
 Date:		September 2011
 Contact:	Andiry Xu <andiry.xu@amd.com>
diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt
index 7f40c72..273e654d 100644
--- a/Documentation/RCU/RTFP.txt
+++ b/Documentation/RCU/RTFP.txt
@@ -39,7 +39,7 @@
 write-side contention and parallelize the other write-side overheads by
 providing a fine-grained locking design, however, it would be interesting
 to see how much of the performance advantage reported in 1990 remains
-in 2004.
+today.
 
 At about this same time, Adams [Adams91] described ``chaotic relaxation'',
 where the normal barriers between successive iterations of convergent
@@ -86,9 +86,9 @@
 [McKenney98].
 
 In 1999, the Tornado and K42 groups described their "generations"
-mechanism, which quite similar to RCU [Gamsa99].  These operating systems
-made pervasive use of RCU in place of "existence locks", which greatly
-simplifies locking hierarchies.
+mechanism, which is quite similar to RCU [Gamsa99].  These operating
+systems made pervasive use of RCU in place of "existence locks", which
+greatly simplifies locking hierarchies and helps avoid deadlocks.
 
 2001 saw the first RCU presentation involving Linux [McKenney01a]
 at OLS.  The resulting abundance of RCU patches was presented the
@@ -106,8 +106,11 @@
 form of memory barriers.  Researchers at Sun worked along similar lines
 in the same timeframe [HerlihyLM02].  These techniques can be thought
 of as inside-out reference counts, where the count is represented by the
-number of hazard pointers referencing a given data structure (rather than
-the more conventional counter field within the data structure itself).
+number of hazard pointers referencing a given data structure rather than
+the more conventional counter field within the data structure itself.
+The key advantage of inside-out reference counts is that they can be
+stored in immortal variables, thus allowing races between access and
+deletion to be avoided.
 
 By the same token, RCU can be thought of as a "bulk reference count",
 where some form of reference counter covers all reference by a given CPU
@@ -179,7 +182,25 @@
 (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].
+Lockers" LWN article [NeilBrown2011MeetTheLockers].  Some academic
+work looked at debugging uses of RCU [Seyster:2011:RFA:2075416.2075425].
+
+In 2012, Josh Triplett received his Ph.D. with his dissertation
+covering RCU-protected resizable hash tables and the relationship
+between memory barriers and read-side traversal order:  If the updater
+is making changes in the opposite direction from the read-side traveral
+order, the updater need only execute a memory-barrier instruction,
+but if in the same direction, the updater needs to wait for a grace
+period between the individual updates [JoshTriplettPhD].  Also in 2012,
+after seventeen years of attempts, an RCU paper made it into a top-flight
+academic journal, IEEE Transactions on Parallel and Distributed Systems
+[MathieuDesnoyers2012URCU].  A group of researchers in Spain applied
+user-level RCU to crowd simulation [GuillermoVigueras2012RCUCrowd], and
+another group of researchers in Europe produced a formal description of
+RCU based on separation logic [AlexeyGotsman2012VerifyGraceExtended],
+which was published in the 2013 European Symposium on Programming
+[AlexeyGotsman2013ESOPRCU].
+
 
 
 Bibtex Entries
@@ -193,13 +214,12 @@
 ,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.
+	http://portal.acm.org/citation.cfm?id=320619&dl=GUIDE,
+	[Viewed December 3, 2007]
 }
 }
 
@@ -309,7 +329,7 @@
 ,doi = {http://doi.acm.org/10.1145/42392.42399}
 ,publisher = {ACM}
 ,address = {New York, NY, USA}
-,annotation= {
+,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
@@ -346,8 +366,9 @@
 }
 }
 
-@Book{Adams91
-,Author="Gregory R. Adams"
+# Was Adams91, see also syncrefs.bib.
+@Book{Andrews91textbook
+,Author="Gregory R. Andrews"
 ,title="Concurrent Programming, Principles, and Practices"
 ,Publisher="Benjamin Cummins"
 ,Year="1991"
@@ -398,39 +419,39 @@
 }
 }
 
-@conference{Pu95a,
-Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and
+@conference{Pu95a
+,Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and
 Crispin Cowan and Jon Inouye and Lakshmi Kethana and Jonathan Walpole and
-Ke Zhang",
-Title = "Optimistic Incremental Specialization: Streamlining a Commercial
-Operating System",
-Booktitle = "15\textsuperscript{th} ACM Symposium on
-Operating Systems Principles (SOSP'95)",
-address = "Copper Mountain, CO",
-month="December",
-year="1995",
-pages="314-321",
-annotation="
+Ke Zhang"
+,Title = "Optimistic Incremental Specialization: Streamlining a Commercial
+,Operating System"
+,Booktitle = "15\textsuperscript{th} ACM Symposium on
+,Operating Systems Principles (SOSP'95)"
+,address = "Copper Mountain, CO"
+,month="December"
+,year="1995"
+,pages="314-321"
+,annotation={
 	Uses a replugger, but with a flag to signal when people are
 	using the resource at hand.  Only one reader at a time.
-"
+}
 }
 
-@conference{Cowan96a,
-Author = "Crispin Cowan and Tito Autrey and Charles Krasic and
-Calton Pu and Jonathan Walpole",
-Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System",
-Booktitle = "International Conference on Configurable Distributed Systems
-(ICCDS'96)",
-address = "Annapolis, MD",
-month="May",
-year="1996",
-pages="108",
-isbn="0-8186-7395-8",
-annotation="
+@conference{Cowan96a
+,Author = "Crispin Cowan and Tito Autrey and Charles Krasic and
+,Calton Pu and Jonathan Walpole"
+,Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System"
+,Booktitle = "International Conference on Configurable Distributed Systems
+(ICCDS'96)"
+,address = "Annapolis, MD"
+,month="May"
+,year="1996"
+,pages="108"
+,isbn="0-8186-7395-8"
+,annotation={
 	Uses a replugger, but with a counter to signal when people are
 	using the resource at hand.  Allows multiple readers.
-"
+}
 }
 
 @techreport{Slingwine95
@@ -493,14 +514,13 @@
 ,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.
+	http://www.rdrop.com/users/paulmck/RCU/rclockpdcsproof.pdf
+	[Viewed December 3, 2007]
 }
 }
 
@@ -514,13 +534,12 @@
 ,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).
+	http://www.usenix.org/events/osdi99/full_papers/gamsa/gamsa.pdf
+	[Viewed August 30, 2006]
 }
 }
 
@@ -611,9 +630,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100259266316456&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
 	Memory-barrier and Alpha thread.  100 messages, not too bad...
-"
+}
 }
 
 @unpublished{Spraul01
@@ -624,10 +643,10 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=100264675012867&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
 	Suggested burying memory barriers in Linux's list-manipulation
 	primitives.
-"
+}
 }
 
 @unpublished{LinusTorvalds2001a
@@ -638,6 +657,8 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2001/10/13/105}
 [Viewed August 21, 2004]"
+,annotation={
+}
 }
 
 @unpublished{Blanchard02a
@@ -657,10 +678,10 @@
 ,Month="June"
 ,Year="2002"
 ,pages="289-300"
-,annotation="
+,annotation={
 	Measured scalability of Linux 2.4 kernel's directory-entry cache
 	(dcache), and measured some scalability enhancements.
-"
+}
 }
 
 @Conference{McKenney02a
@@ -674,10 +695,10 @@
 ,note="Available:
 \url{http://www.linux.org.uk/~ajh/ols2002_proceedings.pdf.gz}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
 	Presented and compared a number of RCU implementations for the
 	Linux kernel.
-"
+}
 }
 
 @unpublished{Sarma02a
@@ -688,9 +709,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=102645767914212&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
 	Compare fastwalk and RCU for dcache.  RCU won.
-"
+}
 }
 
 @unpublished{Barbieri02
@@ -701,9 +722,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=103082050621241&w=2}
 [Viewed: June 23, 2004]"
-,annotation="
+,annotation={
 	Suggested RCU for vfs\_shared\_cred.
-"
+}
 }
 
 @unpublished{Dickins02a
@@ -722,10 +743,10 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=103462075416638&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,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
@@ -736,14 +757,14 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2003/3/9/205}
 [Viewed March 13, 2006]"
-,annotation="
+,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
@@ -758,9 +779,9 @@
 ,volume="42"
 ,number="1"
 ,pages="60-76"
-,annotation="
+,annotation={
 	Use of RCU to enable hot-swapping for autonomic behavior in K42.
-"
+}
 }
 
 @unpublished{Seigh03
@@ -769,9 +790,9 @@
 ,Year="2003"
 ,Month="March"
 ,note="email correspondence"
-,annotation="
+,annotation={
 	Described the relationship of the VM/XA passive serialization to RCU.
-"
+}
 }
 
 @Conference{Arcangeli03
@@ -785,14 +806,12 @@
 ,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="
+,annotation={
 	Compared updated RCU implementations for the Linux kernel, and
 	described System V IPC use of RCU, including order-of-magnitude
 	performance improvements.
-"
+	http://www.rdrop.com/users/paulmck/RCU/rcu.FREENIX.2003.06.14.pdf
+}
 }
 
 @Conference{Soules03a
@@ -820,10 +839,10 @@
 ,note="Available:
 \url{http://www.linuxjournal.com/article/6993}
 [Viewed November 14, 2007]"
-,annotation="
+,annotation={
 	Reader-friendly intro to RCU, with the infamous old-man-and-brat
 	cartoon.
-"
+}
 }
 
 @unpublished{Sarma03a
@@ -832,7 +851,9 @@
 ,month="December"
 ,year="2003"
 ,note="Message ID: 20031222180114.GA2248@in.ibm.com"
-,annotation="dipankar/ct.2004.03.27/RCUll.2003.12.22.patch"
+,annotation={
+	dipankar/ct.2004.03.27/RCUll.2003.12.22.patch
+}
 }
 
 @techreport{Friedberg03a
@@ -844,11 +865,11 @@
 ,number="US Patent 6,662,184"
 ,month="December"
 ,pages="112"
-,annotation="
+,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
@@ -860,12 +881,11 @@
 ,volume="1"
 ,number="118"
 ,pages="38-46"
-,note="Available:
-\url{http://www.linuxjournal.com/node/7124}
-[Viewed December 26, 2010]"
-,annotation="
+,annotation={
 	Reader friendly intro to dcache and RCU.
-"
+	http://www.linuxjournal.com/node/7124
+	[Viewed December 26, 2010]
+}
 }
 
 @Conference{McKenney04b
@@ -879,10 +899,10 @@
 \url{http://www.linux.org.au/conf/2004/abstracts.html#90}
 \url{http://www.rdrop.com/users/paulmck/RCU/lockperf.2004.01.17a.pdf}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
 	Compares performance of RCU to that of other locking primitives
 	over a number of CPUs (x86, Opteron, Itanium, and PPC).
-"
+}
 }
 
 @unpublished{Sarma04a
@@ -891,7 +911,9 @@
 ,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"
+,annotation={
+	Head of thread: dipankar/2004.03.23/rcu-low-lat.1.patch
+}
 }
 
 @unpublished{Sarma04b
@@ -900,7 +922,9 @@
 ,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"
+,annotation={
+	dipankar/rcuth.2004.03.24/rcu-throttle.patch
+}
 }
 
 @unpublished{Spraul04a
@@ -911,9 +935,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=108546407726602&w=2}
 [Viewed June 23, 2004]"
-,annotation="
+,annotation={
 	Hierarchical-bitmap patch for RCU infrastructure.
-"
+}
 }
 
 @unpublished{Steiner04a
@@ -950,10 +974,12 @@
 ,year="2004"
 ,month="June"
 ,pages="182-191"
-,annotation="
+,annotation={
 	Describes and compares a number of modifications to the Linux RCU
 	implementation that make it friendly to realtime applications.
-"
+	https://www.usenix.org/conference/2004-usenix-annual-technical-conference/making-rcu-safe-deep-sub-millisecond-response
+	[Viewed July 26, 2012]
+}
 }
 
 @phdthesis{PaulEdwardMcKenneyPhD
@@ -964,14 +990,13 @@
 ,school="OGI School of Science and Engineering at
 Oregon Health and Sciences University"
 ,year="2004"
-,note="Available:
-\url{http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf}
-[Viewed October 15, 2004]"
-,annotation="
+,annotation={
 	Describes RCU implementations and presents design patterns
 	corresponding to common uses of RCU in several operating-system
 	kernels.
-"
+	http://www.rdrop.com/users/paulmck/RCU/RCUdissertation.2004.07.14e1.pdf
+	[Viewed October 15, 2004]
+}
 }
 
 @unpublished{PaulEMcKenney2004rcu:dereference
@@ -982,9 +1007,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2004/8/6/237}
 [Viewed June 8, 2010]"
-,annotation="
+,annotation={
 	Introduce rcu_dereference().
-"
+}
 }
 
 @unpublished{JimHouston04a
@@ -995,11 +1020,11 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2004/8/30/87}
 [Viewed February 17, 2005]"
-,annotation="
+,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
@@ -1010,9 +1035,9 @@
 ,note="Available:
 \url{http://www.cs.toronto.edu/~tomhart/masters_thesis.html}
 [Viewed October 15, 2004]"
-,annotation="
+,annotation={
 	Proposes comparing RCU to lock-free methods for the Linux kernel.
-"
+}
 }
 
 @unpublished{Vaddagiri04a
@@ -1023,9 +1048,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?t=109395731700004&r=1&w=2}
 [Viewed October 18, 2004]"
-,annotation="
+,annotation={
 	Srivatsa's RCU patch for tcp_ehash lookup.
-"
+}
 }
 
 @unpublished{Thirumalai04a
@@ -1036,9 +1061,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?t=109144217400003&r=1&w=2}
 [Viewed October 18, 2004]"
-,annotation="
+,annotation={
 	Ravikiran's lockfree FD patch.
-"
+}
 }
 
 @unpublished{Thirumalai04b
@@ -1049,9 +1074,9 @@
 ,note="Available:
 \url{http://marc.theaimsgroup.com/?l=linux-kernel&m=109152521410459&w=2}
 [Viewed October 18, 2004]"
-,annotation="
+,annotation={
 	Ravikiran's lockfree FD patch.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2004rcu:assign:pointer
@@ -1062,9 +1087,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2004/10/23/241}
 [Viewed June 8, 2010]"
-,annotation="
+,annotation={
 	Introduce rcu_assign_pointer().
-"
+}
 }
 
 @unpublished{JamesMorris04a
@@ -1073,12 +1098,12 @@
 ,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="
+,note="\url{http://marc.theaimsgroup.com/?l=linux-kernel&m=110054979416004&w=2}"
+,annotation={
 	James Morris posts Kaigai Kohei's patch to LKML.
-"
+	[Viewed December 10, 2004]
+	Kaigai's patch is at https://lkml.org/lkml/2004/9/27/52
+}
 }
 
 @unpublished{JamesMorris04b
@@ -1089,9 +1114,9 @@
 ,note="Available:
 \url{http://www.livejournal.com/users/james_morris/2153.html}
 [Viewed December 10, 2004]"
-,annotation="
+,annotation={
 	RCU helps SELinux performance.  ;-)  Made LWN.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005RCUSemantics
@@ -1103,9 +1128,9 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/rcu-semantics.2005.01.30a.pdf}
 [Viewed December 6, 2009]"
-,annotation="
+,annotation={
 	Early derivation of RCU semantics.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005e
@@ -1117,10 +1142,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2005/3/17/199}
 [Viewed September 5, 2005]"
-,annotation="
+,annotation={
 	First posting showing how RCU can be safely adapted for
 	preemptable RCU read side critical sections.
-"
+}
 }
 
 @unpublished{EsbenNeilsen2005a
@@ -1132,12 +1157,12 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2005/3/18/122}
 [Viewed March 30, 2006]"
-,annotation="
+,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
+	is indefinite grace periods...  But this is OK for experimentation
 	and testing.
-"
+}
 }
 
 @unpublished{TomHart05a
@@ -1149,10 +1174,10 @@
 ,note="Available:
 \url{ftp://ftp.cs.toronto.edu/csrg-technical-reports/515/}
 [Viewed March 4, 2005]"
-,annotation="
+,annotation={
 	Comparison of RCU, QBSR, and EBSR.  RCU wins for read-mostly
 	workloads.  ;-)
-"
+}
 }
 
 @unpublished{JonCorbet2005DeprecateSyncKernel
@@ -1164,10 +1189,10 @@
 ,note="Available:
 \url{http://lwn.net/Articles/134484/}
 [Viewed May 3, 2005]"
-,annotation="
+,annotation={
 	Jon Corbet describes deprecation of synchronize_kernel()
 	in favor of synchronize_rcu() and synchronize_sched().
-"
+}
 }
 
 @unpublished{PaulMcKenney05a
@@ -1178,10 +1203,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2005/5/9/185}
 [Viewed May 13, 2005]"
-,annotation="
+,annotation={
 	First publication of working lock-based deferred free patches
 	for the CONFIG_PREEMPT_RT environment.
-"
+}
 }
 
 @conference{PaulMcKenney05b
@@ -1194,10 +1219,10 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/realtimeRCU.2005.04.23a.pdf}
 [Viewed May 13, 2005]"
-,annotation="
+,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
@@ -1208,9 +1233,9 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/}
 [Viewed May 25, 2005]"
-,annotation="
+,annotation={
 	Paul McKenney's home page.
-"
+}
 }
 
 @unpublished{PaulEMcKenneyRCUPage
@@ -1221,9 +1246,9 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU}
 [Viewed May 25, 2005]"
-,annotation="
+,annotation={
 	Paul McKenney's RCU page.
-"
+}
 }
 
 @unpublished{JosephSeigh2005a
@@ -1232,10 +1257,10 @@
 ,month="July"
 ,year="2005"
 ,note="Personal communication"
-,annotation="
+,annotation={
 	Joe Seigh announcing his atomic-ptr-plus project.
 	http://sourceforge.net/projects/atomic-ptr-plus/
-"
+}
 }
 
 @unpublished{JosephSeigh2005b
@@ -1247,9 +1272,9 @@
 ,note="Available:
 \url{http://sourceforge.net/projects/atomic-ptr-plus/}
 [Viewed August 8, 2005]"
-,annotation="
+,annotation={
 	Joe Seigh's atomic-ptr-plus project.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005c
@@ -1261,9 +1286,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2005/8/1/155}
 [Viewed March 14, 2006]"
-,annotation="
+,annotation={
 	First operating counter-based realtime RCU patch posted to LKML.
-"
+}
 }
 
 @unpublished{PaulMcKenney2005d
@@ -1275,11 +1300,11 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2005/8/8/108}
 [Viewed March 14, 2006]"
-,annotation="
+,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
@@ -1291,9 +1316,25 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2005/10/1/70}
 [Viewed March 14, 2006]"
-,annotation="
+,annotation={
 	First rcutorture patch.
-"
+}
+}
+
+@unpublished{DavidSMiller2006HashedLocking
+,Author="David S. Miller"
+,Title="Re: [{PATCH}, {RFC}] {RCU} : {OOM} avoidance and lower latency"
+,month="January"
+,day="6"
+,year="2006"
+,note="Available:
+\url{https://lkml.org/lkml/2006/1/7/22}
+[Viewed February 29, 2012]"
+,annotation={
+	David Miller's view on hashed arrays of locks: used to really
+	like it, but time he saw an opportunity for this technique,
+	something else always proved superior.  Partitioning or RCU.  ;-)
+}
 }
 
 @conference{ThomasEHart2006a
@@ -1309,10 +1350,10 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/hart_ipdps06.pdf}
 [Viewed April 28, 2008]"
-,annotation="
+,annotation={
 	Compares QSBR, HPBR, EBR, and lock-free reference counting.
 	http://www.cs.toronto.edu/~tomhart/perflab/ipdps06.tgz
-"
+}
 }
 
 @unpublished{NickPiggin2006radixtree
@@ -1324,9 +1365,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2006/6/20/238}
 [Viewed March 25, 2008]"
-,annotation="
+,annotation={
 	RCU-protected radix tree.
-"
+}
 }
 
 @Conference{PaulEMcKenney2006b
@@ -1341,9 +1382,9 @@
 \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="
+,annotation={
 	Described how to improve the -rt implementation of realtime RCU.
-"
+}
 }
 
 @unpublished{WikipediaRCU
@@ -1354,12 +1395,11 @@
 ,month="July"
 ,day="8"
 ,year="2006"
-,note="Available:
-\url{http://en.wikipedia.org/wiki/Read-copy-update}
-[Viewed August 21, 2006]"
-,annotation="
+,note="\url{http://en.wikipedia.org/wiki/Read-copy-update}"
+,annotation={
 	Wikipedia RCU page as of July 8 2006.
-"
+	[Viewed August 21, 2006]
+}
 }
 
 @Conference{NickPiggin2006LocklessPageCache
@@ -1372,9 +1412,9 @@
 ,note="Available:
 \url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184}
 [Viewed January 11, 2009]"
-,annotation="
+,annotation={
 	Uses RCU-protected radix tree for a lockless page cache.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2006c
@@ -1388,9 +1428,9 @@
 Revised:
 \url{http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf}
 [Viewed August 21, 2006]"
-,annotation="
+,annotation={
 	LWN article introducing SRCU.
-"
+}
 }
 
 @unpublished{RobertOlsson2006a
@@ -1399,12 +1439,11 @@
 ,month="August"
 ,day="18"
 ,year="2006"
-,note="Available:
-\url{http://www.nada.kth.se/~snilsson/publications/TRASH/trash.pdf}
-[Viewed March 4, 2011]"
-,annotation="
+,note="\url{http://www.nada.kth.se/~snilsson/publications/TRASH/trash.pdf}"
+,annotation={
 	RCU-protected dynamic trie-hash combination.
-"
+	[Viewed March 4, 2011]
+}
 }
 
 @unpublished{ChristophHellwig2006RCU2SRCU
@@ -1426,10 +1465,10 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/linuxusage.html}
 [Viewed January 14, 2007]"
-,annotation="
+,annotation={
 	Paul McKenney's RCU page showing graphs plotting Linux-kernel
 	usage of RCU.
-"
+}
 }
 
 @unpublished{PaulEMcKenneyRCUusageRawDataPage
@@ -1440,10 +1479,10 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html}
 [Viewed January 14, 2007]"
-,annotation="
+,annotation={
 	Paul McKenney's RCU page showing Linux usage of RCU in tabular
 	form, with links to corresponding cscope databases.
-"
+}
 }
 
 @unpublished{GauthamShenoy2006RCUrwlock
@@ -1455,13 +1494,13 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2006/10/26/73}
 [Viewed January 26, 2009]"
-,annotation="
+,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
@@ -1474,11 +1513,11 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2006/11/17/56}
 [Viewed May 28, 2007]"
-,annotation="
+,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
@@ -1491,10 +1530,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2006/11/19/69}
 [Viewed May 28, 2007]"
-,annotation="
+,annotation={
 	First cut of QRCU.  Expanded/corrected versions followed.
 	Used to be OlegNesterov2007QRCU, now time-corrected.
-"
+}
 }
 
 @unpublished{OlegNesterov2006aQRCU
@@ -1506,10 +1545,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2006/11/29/330}
 [Viewed November 26, 2008]"
-,annotation="
+,annotation={
 	Expanded/corrected version of QRCU.
 	Used to be OlegNesterov2007aQRCU, now time-corrected.
-"
+}
 }
 
 @unpublished{EvgeniyPolyakov2006RCUslowdown
@@ -1521,10 +1560,10 @@
 ,note="Available:
 \url{http://www.ioremap.net/node/41}
 [Viewed October 28, 2008]"
-,annotation="
+,annotation={
 	Using RCU as a pure delay leads to a 2.5x slowdown in skbs in
 	the Linux kernel.
-"
+}
 }
 
 @inproceedings{ChrisMatthews2006ClusteredObjectsRCU
@@ -1541,7 +1580,8 @@
 ,annotation={
 	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}
@@ -1557,7 +1597,8 @@
 ,address = {New York, NY, USA}
 ,annotation={
 	Describes relationship of K42 generations to RCU.
-}}
+}
+}
 
 # CoreyMinyard2007list_splice_rcu
 @unpublished{CoreyMinyard2007list:splice:rcu
@@ -1569,9 +1610,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2007/1/3/112}
 [Viewed May 28, 2007]"
-,annotation="
+,annotation={
 	Patch for list_splice_rcu().
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007rcubarrier
@@ -1583,9 +1624,9 @@
 ,note="Available:
 \url{http://lwn.net/Articles/217484/}
 [Viewed November 22, 2007]"
-,annotation="
+,annotation={
 	LWN article introducing the rcu_barrier() primitive.
-"
+}
 }
 
 @unpublished{PeterZijlstra2007SyncBarrier
@@ -1597,10 +1638,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2007/1/28/34}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
 	RCU-like implementation for frequent updaters and rare readers(!).
 	Subsumed into QRCU.  Maybe...
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007BoostRCU
@@ -1609,14 +1650,13 @@
 ,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="
+,note="\url{http://lwn.net/Articles/220677/}"
+,annotation={
 	LWN article introducing RCU priority boosting.
-"
+	Revised:
+	http://www.rdrop.com/users/paulmck/RCU/RCUbooststate.2007.04.16a.pdf
+	[Viewed September 7, 2007]
+}
 }
 
 @unpublished{PaulMcKenney2007QRCUpatch
@@ -1628,9 +1668,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2007/2/25/18}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
 	Patch for QRCU supplying lock-free fast path.
-"
+}
 }
 
 @article{JonathanAppavoo2007K42RCU
@@ -1647,7 +1687,8 @@
 ,address = {New York, NY, USA}
 ,annotation={
 	Role of RCU in K42.
-}}
+}
+}
 
 @conference{RobertOlsson2007Trash
 ,Author="Robert Olsson and Stefan Nilsson"
@@ -1658,9 +1699,9 @@
 ,note="Available:
 \url{http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=4281239}
 [Viewed October 1, 2010]"
-,annotation="
+,annotation={
 	RCU-protected dynamic trie-hash combination.
-"
+}
 }
 
 @conference{PeterZijlstra2007ConcurrentPagecacheRCU
@@ -1673,10 +1714,10 @@
 ,note="Available:
 \url{http://ols.108.redhat.com/2007/Reprints/zijlstra-Reprint.pdf}
 [Viewed April 14, 2008]"
-,annotation="
+,annotation={
 	Page-cache modifications permitting RCU readers and concurrent
 	updates.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007whatisRCU
@@ -1701,11 +1742,11 @@
 ,note="Available:
 \url{http://lwn.net/Articles/243851/}
 [Viewed September 8, 2007]"
-,annotation="
+,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
@@ -1714,12 +1755,12 @@
 ,month="August"
 ,day="3"
 ,year="2007"
-,note="Preprint:
+,note="Available:
 \url{http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm}
 [Viewed December 7, 2009]"
-,annotation="
+,annotation={
 	RCU for C++, parts 1 and 2.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007WG21DDOannotation
@@ -1728,12 +1769,12 @@
 ,month="September"
 ,day="18"
 ,year="2008"
-,note="Preprint:
+,note="Available:
 \url{http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2782.htm}
 [Viewed December 7, 2009]"
-,annotation="
+,annotation={
 	RCU for C++, part 2, updated many times.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007PreemptibleRCUPatch
@@ -1745,10 +1786,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2007/9/10/213}
 [Viewed October 25, 2007]"
-,annotation="
+,annotation={
 	Final patch for preemptable RCU to -rt.  (Later patches were
 	to mainline, eventually incorporated.)
-"
+}
 }
 
 @unpublished{PaulEMcKenney2007PreemptibleRCU
@@ -1760,9 +1801,9 @@
 ,note="Available:
 \url{http://lwn.net/Articles/253651/}
 [Viewed October 25, 2007]"
-,annotation="
+,annotation={
 	LWN article describing the design of preemptible RCU.
-"
+}
 }
 
 @article{ThomasEHart2007a
@@ -1783,6 +1824,7 @@
 }
 }
 
+# MathieuDesnoyers2007call_rcu_schedNeeded
 @unpublished{MathieuDesnoyers2007call:rcu:schedNeeded
 ,Author="Mathieu Desnoyers"
 ,Title="Re: [patch 1/2] {Linux} Kernel Markers - Support Multiple Probes"
@@ -1792,9 +1834,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2007/12/20/244}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
 	Request for call_rcu_sched() and rcu_barrier_sched().
-"
+}
 }
 
 
@@ -1815,11 +1857,11 @@
 ,note="Available:
 \url{http://lwn.net/Articles/262464/}
 [Viewed December 27, 2007]"
-,annotation="
+,annotation={
 	Lays out the three basic components of RCU: (1) publish-subscribe,
 	(2) wait for pre-existing readers to complete, and (2) maintain
 	multiple versions.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008WhatIsRCUUsage
@@ -1831,7 +1873,7 @@
 ,note="Available:
 \url{http://lwn.net/Articles/263130/}
 [Viewed January 4, 2008]"
-,annotation="
+,annotation={
 	Lays out six uses of RCU:
 	1. RCU is a Reader-Writer Lock Replacement
 	2. RCU is a Restricted Reference-Counting Mechanism
@@ -1839,7 +1881,7 @@
 	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
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008WhatIsRCUAPI
@@ -1851,10 +1893,10 @@
 ,note="Available:
 \url{http://lwn.net/Articles/264090/}
 [Viewed January 10, 2008]"
-,annotation="
+,annotation={
 	Gives an overview of the Linux-kernel RCU API and a brief annotated RCU
 	bibliography.
-"
+}
 }
 
 #
@@ -1872,10 +1914,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2008/1/29/208}
 [Viewed March 27, 2008]"
-,annotation="
+,annotation={
 	Patch that prevents preemptible RCU from unnecessarily waking
 	up dynticks-idle CPUs.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2008LKMLDependencyOrdering
@@ -1887,9 +1929,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2008/2/2/255}
 [Viewed October 18, 2008]"
-,annotation="
+,annotation={
 	Explanation of compilers violating dependency ordering.
-"
+}
 }
 
 @Conference{PaulEMcKenney2008Beijing
@@ -1916,24 +1958,26 @@
 ,note="Available:
 \url{http://lwn.net/Articles/279077/}
 [Viewed April 24, 2008]"
-,annotation="
+,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-June"
+,Month="May"
 ,journal="IBM Systems Journal"
 ,volume="47"
 ,number="2"
 ,pages="221-236"
-,annotation="
+,annotation={
 	RCU, realtime RCU, sleepable RCU, performance.
-"
+	http://www.research.ibm.com/journal/sj/472/guniguntala.pdf
+	[Viewed April 24, 2008]
+}
 }
 
 @unpublished{LaiJiangshan2008NewClassicAlgorithm
@@ -1945,11 +1989,11 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2008/6/2/539}
 [Viewed December 10, 2008]"
-,annotation="
+,annotation={
 	Updated RCU classic algorithm.  Introduced multi-tailed list
 	for RCU callbacks and also pulling common code into
 	__call_rcu().
-"
+}
 }
 
 @article{PaulEMcKenney2008RCUOSR
@@ -1966,6 +2010,7 @@
 ,address="New York, NY, USA"
 ,annotation={
 	Linux changed RCU to a far greater degree than RCU has changed Linux.
+	http://portal.acm.org/citation.cfm?doid=1400097.1400099
 }
 }
 
@@ -1978,10 +2023,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2008/8/21/336}
 [Viewed December 8, 2008]"
-,annotation="
+,annotation={
 	State-based RCU.  One key thing that this patch does is to
 	separate the dynticks handling of NMIs and IRQs.
-"
+}
 }
 
 @unpublished{ManfredSpraul2008dyntickIRQNMI
@@ -1993,12 +2038,13 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2008/9/6/86}
 [Viewed December 8, 2008]"
-,annotation="
+,annotation={
 	Manfred notes a fix required to my attempt to separate irq
 	and NMI processing for hierarchical RCU's dynticks interface.
-"
+}
 }
 
+# Was PaulEMcKenney2011cyclicRCU
 @techreport{PaulEMcKenney2008cyclicRCU
 ,author="Paul E. McKenney"
 ,title="Efficient Support of Consistent Cyclic Search With Read-Copy Update"
@@ -2008,11 +2054,11 @@
 ,number="US Patent 7,426,511"
 ,month="September"
 ,pages="23"
-,annotation="
+,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
@@ -2021,13 +2067,12 @@
 ,month="November"
 ,day="3"
 ,year="2008"
-,note="Available:
-\url{http://lwn.net/Articles/305782/}
-[Viewed November 6, 2008]"
-,annotation="
+,note="\url{http://lwn.net/Articles/305782/}"
+,annotation={
 	RCU with combining-tree-based grace-period detection,
 	permitting it to handle thousands of CPUs.
-"
+	[Viewed November 6, 2008]
+}
 }
 
 @unpublished{PaulEMcKenney2009BloatwatchRCU
@@ -2039,10 +2084,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2009/1/14/449}
 [Viewed January 15, 2009]"
-,annotation="
+,annotation={
 	Small-footprint implementation of RCU for uniprocessor
 	embedded applications -- and also for exposition purposes.
-"
+}
 }
 
 @conference{PaulEMcKenney2009MaliciousURCU
@@ -2055,9 +2100,9 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/urcutorture.2009.01.22a.pdf}
 [Viewed February 2, 2009]"
-,annotation="
+,annotation={
 	Realtime RCU and torture-testing RCU uses.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009URCU
@@ -2066,16 +2111,14 @@
 ,month="February"
 ,day="5"
 ,year="2009"
-,note="Available:
-\url{http://lkml.org/lkml/2009/2/5/572}
-\url{http://lttng.org/urcu}
-[Viewed February 20, 2009]"
-,annotation="
+,note="\url{http://lttng.org/urcu}"
+,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
-"
+	http://lkml.org/lkml/2009/2/5/572
+}
 }
 
 @unpublished{PaulEMcKenney2009LWNBloatWatchRCU
@@ -2087,9 +2130,24 @@
 ,note="Available:
 \url{http://lwn.net/Articles/323929/}
 [Viewed March 20, 2009]"
-,annotation="
+,annotation={
 	Uniprocessor assumptions allow simplified RCU implementation.
-"
+}
+}
+
+@unpublished{EvgeniyPolyakov2009EllipticsNetwork
+,Author="Evgeniy Polyakov"
+,Title="The Elliptics Network"
+,month="April"
+,day="17"
+,year="2009"
+,note="Available:
+\url{http://www.ioremap.net/projects/elliptics}
+[Viewed April 30, 2009]"
+,annotation={
+	Distributed hash table with transactions, using elliptic
+	hash functions to distribute data.
+}
 }
 
 @unpublished{PaulEMcKenney2009expeditedRCU
@@ -2101,9 +2159,9 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2009/6/25/306}
 [Viewed August 16, 2009]"
-,annotation="
+,annotation={
 	First posting of expedited RCU to be accepted into -tip.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2009fastRTRCU
@@ -2115,21 +2173,21 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2009/7/23/294}
 [Viewed August 15, 2009]"
-,annotation="
+,annotation={
 	First posting of simple and fast preemptable RCU.
-"
+}
 }
 
-@InProceedings{JoshTriplett2009RPHash
+@unpublished{JoshTriplett2009RPHash
 ,Author="Josh Triplett"
 ,Title="Scalable concurrent hash tables via relativistic programming"
 ,month="September"
 ,year="2009"
-,booktitle="Linux Plumbers Conference 2009"
-,annotation="
+,note="Linux Plumbers Conference presentation"
+,annotation={
 	RP fun with hash tables.
-	See also JoshTriplett2010RPHash
-"
+	Superseded by JoshTriplett2010RPHash
+}
 }
 
 @phdthesis{MathieuDesnoyersPhD
@@ -2154,9 +2212,9 @@
 ,note="Available:
 \url{http://wiki.cs.pdx.edu/rp/}
 [Viewed December 9, 2009]"
-,annotation="
+,annotation={
 	Main Relativistic Programming Wiki.
-"
+}
 }
 
 @conference{PaulEMcKenney2009DeterministicRCU
@@ -2180,9 +2238,9 @@
 ,note="Available:
 \url{http://paulmck.livejournal.com/14639.html}
 [Viewed June 4, 2010]"
-,annotation="
+,annotation={
 	Day-one bug in Tree RCU that took forever to track down.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009defer:rcu
@@ -2193,10 +2251,10 @@
 ,note="Available:
 \url{http://lkml.org/lkml/2009/10/18/129}
 [Viewed December 29, 2009]"
-,annotation="
+,annotation={
 	Mathieu proposed defer_rcu() with fixed-size per-thread pool
 	of RCU callbacks.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009VerifPrePub
@@ -2205,10 +2263,10 @@
 ,month="December"
 ,year="2009"
 ,note="Submitted to IEEE TPDS"
-,annotation="
+,annotation={
 	OOMem model for Mathieu's user-level RCU mechanical proof of
 	correctness.
-"
+}
 }
 
 @unpublished{MathieuDesnoyers2009URCUPrePub
@@ -2216,15 +2274,15 @@
 ,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="
+,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
@@ -2240,7 +2298,8 @@
 ,address = {New York, NY, USA}
 ,annotation={
 	Uses RCU to protect metadata used in dynamic analysis.
-}}
+}
+}
 
 @conference{PaulEMcKenney2010SimpleOptRCU
 ,Author="Paul E. McKenney"
@@ -2252,10 +2311,10 @@
 ,note="Available:
 \url{http://www.rdrop.com/users/paulmck/RCU/SimplicityThruOptimization.2010.01.21f.pdf}
 [Viewed October 10, 2010]"
-,annotation="
+,annotation={
 	TREE_PREEMPT_RCU optimizations greatly simplified the old
 	PREEMPT_RCU implementation.
-"
+}
 }
 
 @unpublished{PaulEMcKenney2010LockdepRCU
@@ -2264,12 +2323,11 @@
 ,month="February"
 ,year="2010"
 ,day="1"
-,note="Available:
-\url{https://lwn.net/Articles/371986/}
-[Viewed June 4, 2010]"
-,annotation="
+,note="\url{https://lwn.net/Articles/371986/}"
+,annotation={
 	CONFIG_PROVE_RCU, or at least an early version.
-"
+	[Viewed June 4, 2010]
+}
 }
 
 @unpublished{AviKivity2010KVM2RCU
@@ -2280,10 +2338,10 @@
 ,note="Available:
 \url{http://www.mail-archive.com/kvm@vger.kernel.org/msg28640.html}
 [Viewed March 20, 2010]"
-,annotation="
+,annotation={
 	Use of RCU permits KVM to increase the size of guest OSes from
 	16 CPUs to 64 CPUs.
-"
+}
 }
 
 @unpublished{HerbertXu2010RCUResizeHash
@@ -2297,7 +2355,19 @@
 ,annotation={
 	Use a pair of list_head structures to support RCU-protected
 	resizable hash tables.
-}}
+}
+}
+
+@mastersthesis{AbhinavDuggal2010Masters
+,author="Abhinav Duggal"
+,title="Stopping Data Races Using Redflag"
+,school="Stony Brook University"
+,year="2010"
+,annotation={
+	Data-race detector incorporating RCU.
+	http://www.filesystems.org/docs/abhinav-thesis/abhinav_thesis.pdf
+}
+}
 
 @article{JoshTriplett2010RPHash
 ,author="Josh Triplett and Paul E. McKenney and Jonathan Walpole"
@@ -2310,7 +2380,8 @@
 ,annotation={
 	RP fun with hash tables.
 	http://portal.acm.org/citation.cfm?id=1842733.1842750
-}}
+}
+}
 
 @unpublished{PaulEMcKenney2010RCUAPI
 ,Author="Paul E. McKenney"
@@ -2318,12 +2389,11 @@
 ,month="December"
 ,day="8"
 ,year="2010"
-,note="Available:
-\url{http://lwn.net/Articles/418853/}
-[Viewed December 8, 2010]"
-,annotation="
+,note="\url{http://lwn.net/Articles/418853/}"
+,annotation={
 	Includes updated software-engineering features.
-"
+	[Viewed December 8, 2010]
+}
 }
 
 @mastersthesis{AndrejPodzimek2010masters
@@ -2338,7 +2408,8 @@
 	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"
@@ -2358,7 +2429,8 @@
 	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}
@@ -2392,12 +2464,12 @@
 ,number="US Patent 7,953,778"
 ,month="May"
 ,pages="34"
-,annotation="
+,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
@@ -2408,7 +2480,7 @@
 ,year = {2011}
 ,pages = {145--158}
 ,numpages = {14}
-,url={http://www.usenix.org/event/atc11/tech/final_files/atc11_proceedings.pdf}
+,url={http://www.usenix.org/event/atc11/tech/final_files/Triplett.pdf}
 ,publisher = {The USENIX Association}
 ,address = {Portland, OR USA}
 }
@@ -2419,27 +2491,58 @@
 ,month="July"
 ,day="27"
 ,year="2011"
-,note="Available:
-\url{http://lwn.net/Articles/453002/}
-[Viewed July 27, 2011]"
-,annotation="
+,note="\url{http://lwn.net/Articles/453002/}"
+,annotation={
 	Analysis of the RCU trainwreck in Linux kernel 3.0.
-"
+	[Viewed July 27, 2011]
+}
 }
 
 @unpublished{NeilBrown2011MeetTheLockers
 ,Author="Neil Brown"
-,Title="Meet the Lockers"
+,Title="Meet the {Lockers}"
 ,month="August"
 ,day="3"
 ,year="2011"
 ,note="Available:
 \url{http://lwn.net/Articles/453685/}
 [Viewed September 2, 2011]"
-,annotation="
+,annotation={
 	The Locker family as an analogy for locking, reference counting,
 	RCU, and seqlock.
-"
+}
+}
+
+@inproceedings{Seyster:2011:RFA:2075416.2075425
+,author = {Seyster, Justin and Radhakrishnan, Prabakar and Katoch, Samriti and Duggal, Abhinav and Stoller, Scott D. and Zadok, Erez}
+,title = {Redflag: a framework for analysis of Kernel-level concurrency}
+,booktitle = {Proceedings of the 11th international conference on Algorithms and architectures for parallel processing - Volume Part I}
+,series = {ICA3PP'11}
+,year = {2011}
+,isbn = {978-3-642-24649-4}
+,location = {Melbourne, Australia}
+,pages = {66--79}
+,numpages = {14}
+,url = {http://dl.acm.org/citation.cfm?id=2075416.2075425}
+,acmid = {2075425}
+,publisher = {Springer-Verlag}
+,address = {Berlin, Heidelberg}
+}
+
+@phdthesis{JoshTriplettPhD
+,author="Josh Triplett"
+,title="Relativistic Causal Ordering: A Memory Model for Scalable Concurrent Data Structures"
+,school="Portland State University"
+,year="2012"
+,annotation={
+	RCU-protected hash tables, barriers vs. read-side traversal order.
+	.
+	If the updater is making changes in the opposite direction from
+	the read-side traveral order, the updater need only execute a
+	memory-barrier instruction, but if in the same direction, the
+	updater needs to wait for a grace period between the individual
+	updates.
+}
 }
 
 @article{MathieuDesnoyers2012URCU
@@ -2459,5 +2562,150 @@
 	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
+	http://www.computer.org/cms/Computer.org/dl/trans/td/2012/02/extras/ttd2012020375s.pdf
+}
+}
+
+@inproceedings{AustinClements2012RCULinux:mmapsem
+,author = {Austin Clements and Frans Kaashoek and Nickolai Zeldovich}
+,title = {Scalable Address Spaces Using {RCU} Balanced Trees}
+,booktitle = {Architectural Support for Programming Languages and Operating Systems (ASPLOS 2012)}
+,month = {March}
+,year = {2012}
+,pages = {199--210}
+,numpages = {12}
+,publisher = {ACM}
+,address = {London, UK}
+,url="http://people.csail.mit.edu/nickolai/papers/clements-bonsai.pdf"
+}
+
+@unpublished{PaulEMcKenney2012ELCbattery
+,Author="Paul E. McKenney"
+,Title="Making {RCU} Safe For Battery-Powered Devices"
+,month="February"
+,day="15"
+,year="2012"
+,note="Available:
+\url{http://www.rdrop.com/users/paulmck/RCU/RCUdynticks.2012.02.15b.pdf}
+[Viewed March 1, 2012]"
+,annotation={
+	RCU_FAST_NO_HZ, round 2.
+}
+}
+
+@article{GuillermoVigueras2012RCUCrowd
+,author = {Vigueras, Guillermo and Ordu\~{n}a, Juan M. and Lozano, Miguel}
+,day = {25}
+,doi = {10.1007/s11227-012-0766-x}
+,issn = {0920-8542}
+,journal = {The Journal of Supercomputing}
+,keywords = {linux, simulation}
+,month = apr
+,posted-at = {2012-05-03 09:12:04}
+,priority = {2}
+,title = {{A Read-Copy Update based parallel server for distributed crowd simulations}}
+,url = {http://dx.doi.org/10.1007/s11227-012-0766-x}
+,year = {2012}
+}
+
+
+@unpublished{JonCorbet2012ACCESS:ONCE
+,Author="Jon Corbet"
+,Title="{ACCESS\_ONCE()}"
+,month="August"
+,day="1"
+,year="2012"
+,note="\url{http://lwn.net/Articles/508991/}"
+,annotation={
+	A couple of simple specific compiler optimizations that motivate
+	ACCESS_ONCE().
+}
+}
+
+@unpublished{AlexeyGotsman2012VerifyGraceExtended
+,Author="Alexey Gotsman and Noam Rinetzky and Hongseok Yang"
+,Title="Verifying Highly Concurrent Algorithms with Grace (extended version)"
+,month="July"
+,day="10"
+,year="2012"
+,note="\url{http://software.imdea.org/~gotsman/papers/recycling-esop13-ext.pdf}"
+,annotation={
+	Separation-logic formulation of RCU uses.
+}
+}
+
+@unpublished{PaulMcKenney2012RCUUsage
+,Author="Paul E. McKenney and Silas Boyd-Wickizer and Jonathan Walpole"
+,Title="{RCU} Usage In the Linux Kernel: One Decade Later"
+,month="September"
+,day="17"
+,year="2012"
+,url=http://rdrop.com/users/paulmck/techreports/survey.2012.09.17a.pdf
+,note="Technical report paulmck.2012.09.17"
+,annotation={
+	Overview of the first variant of no-CBs CPUs for RCU.
+}
+}
+
+@unpublished{JonCorbet2012NOCB
+,Author="Jon Corbet"
+,Title="Relocating RCU callbacks"
+,month="October"
+,day="31"
+,year="2012"
+,note="\url{http://lwn.net/Articles/522262/}"
+,annotation={
+	Overview of the first variant of no-CBs CPUs for RCU.
+}
+}
+
+@phdthesis{JustinSeyster2012PhD
+,author="Justin Seyster"
+,title="Runtime Verification of Kernel-Level Concurrency Using Compiler-Based Instrumentation"
+,school="Stony Brook University"
+,year="2012"
+,annotation={
+	Looking for data races, including those involving RCU.
+	Proposal:
+	http://www.fsl.cs.sunysb.edu/docs/jseyster-proposal/redflag.pdf
+	Dissertation:
+	http://www.fsl.cs.sunysb.edu/docs/jseyster-dissertation/redflag.pdf
+}
+}
+
+@unpublished{PaulEMcKenney2013RCUUsage
+,Author="Paul E. McKenney and Silas Boyd-Wickizer and Jonathan Walpole"
+,Title="{RCU} Usage in the {Linux} Kernel: One Decade Later"
+,month="February"
+,day="24"
+,year="2013"
+,note="\url{http://rdrop.com/users/paulmck/techreports/RCUUsage.2013.02.24a.pdf}"
+,annotation={
+	Usage of RCU within the Linux kernel.
+}
+}
+
+@inproceedings{AlexeyGotsman2013ESOPRCU
+,author = {Alexey Gotsman and Noam Rinetzky and Hongseok Yang}
+,title = {Verifying concurrent memory reclamation algorithms with grace}
+,booktitle = {ESOP'13: European Symposium on Programming}
+,year = {2013}
+,pages = {249--269}
+,publisher = {Springer}
+,address = {Rome, Italy}
+,annotation={
+	http://software.imdea.org/~gotsman/papers/recycling-esop13.pdf
+}
+}
+
+@unpublished{PaulEMcKenney2013NoTinyPreempt
+,Author="Paul E. McKenney"
+,Title="Simplifying RCU"
+,month="March"
+,day="6"
+,year="2013"
+,note="\url{http://lwn.net/Articles/541037/}"
+,annotation={
+	Getting rid of TINY_PREEMPT_RCU.
 }
 }
diff --git a/Documentation/RCU/rcubarrier.txt b/Documentation/RCU/rcubarrier.txt
index 2e319d1..b10cfe7 100644
--- a/Documentation/RCU/rcubarrier.txt
+++ b/Documentation/RCU/rcubarrier.txt
@@ -70,10 +70,14 @@
 
 rcu_barrier()
 
-We instead need the rcu_barrier() primitive. This primitive is similar
-to synchronize_rcu(), but instead of waiting solely for a grace
-period to elapse, it also waits for all outstanding RCU callbacks to
-complete. Pseudo-code using rcu_barrier() is as follows:
+We instead need the rcu_barrier() primitive.  Rather than waiting for
+a grace period to elapse, rcu_barrier() waits for all outstanding RCU
+callbacks to complete.  Please note that rcu_barrier() does -not- imply
+synchronize_rcu(), in particular, if there are no RCU callbacks queued
+anywhere, rcu_barrier() is within its rights to return immediately,
+without waiting for a grace period to elapse.
+
+Pseudo-code using rcu_barrier() is as follows:
 
    1. Prevent any new RCU callbacks from being posted.
    2. Execute rcu_barrier().
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index d8a5023..dac02a6 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -42,6 +42,16 @@
 fqs_stutter	Wait time (in seconds) between consecutive bursts
 		of calls to force_quiescent_state().
 
+gp_normal	Make the fake writers use normal synchronous grace-period
+		primitives.
+
+gp_exp		Make the fake writers use expedited synchronous grace-period
+		primitives.  If both gp_normal and gp_exp are set, or
+		if neither gp_normal nor gp_exp are set, then randomly
+		choose the primitive so that about 50% are normal and
+		50% expedited.  By default, neither are set, which
+		gives best overall test coverage.
+
 irqreader	Says to invoke RCU readers from irq level.  This is currently
 		done via timers.  Defaults to "1" for variants of RCU that
 		permit this.  (Or, more accurately, variants of RCU that do
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index 19fa98e..40282e6 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -50,8 +50,6 @@
 
 cpufreq_driver.name -		The name of this driver.
 
-cpufreq_driver.owner -		THIS_MODULE;
-
 cpufreq_driver.init -		A pointer to the per-CPU initialization 
 				function.
 
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index 20746e5..06fc760 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -1,10 +1,14 @@
 * ARM architected timer
 
-ARM cores may have a per-core architected timer, which provides per-cpu timers.
+ARM cores may have a per-core architected timer, which provides per-cpu timers,
+or a memory mapped architected timer, which provides up to 8 frames with a
+physical and optional virtual timer per frame.
 
-The timer is attached to a GIC to deliver its per-processor interrupts.
+The per-core architected timer is attached to a GIC to deliver its
+per-processor interrupts via PPIs. The memory mapped timer is attached to a GIC
+to deliver its interrupts via SPIs.
 
-** Timer node properties:
+** CP15 Timer node properties:
 
 - compatible : Should at least contain one of
 	"arm,armv7-timer"
@@ -26,3 +30,52 @@
 			     <1 10 0xf08>;
 		clock-frequency = <100000000>;
 	};
+
+** Memory mapped timer node properties:
+
+- compatible : Should at least contain "arm,armv7-timer-mem".
+
+- clock-frequency : The frequency of the main counter, in Hz. Optional.
+
+- reg : The control frame base address.
+
+Note that #address-cells, #size-cells, and ranges shall be present to ensure
+the CPU can address a frame's registers.
+
+A timer node has up to 8 frame sub-nodes, each with the following properties:
+
+- frame-number: 0 to 7.
+
+- interrupts : Interrupt list for physical and virtual timers in that order.
+  The virtual timer interrupt is optional.
+
+- reg : The first and second view base addresses in that order. The second view
+  base address is optional.
+
+- status : "disabled" indicates the frame is not available for use. Optional.
+
+Example:
+
+	timer@f0000000 {
+		compatible = "arm,armv7-timer-mem";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		reg = <0xf0000000 0x1000>;
+		clock-frequency = <50000000>;
+
+		frame@f0001000 {
+			frame-number = <0>
+			interrupts = <0 13 0x8>,
+				     <0 14 0x8>;
+			reg = <0xf0001000 0x1000>,
+			      <0xf0002000 0x1000>;
+		};
+
+		frame@f0003000 {
+			frame-number = <1>
+			interrupts = <0 15 0x8>;
+			reg = <0xf0003000 0x1000>;
+			status = "disabled";
+		};
+	};
diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index 16769d9..723c205 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -1,18 +1,15 @@
 * AT91's Analog to Digital Converter (ADC)
 
 Required properties:
-  - compatible: Should be "atmel,at91sam9260-adc"
+  - compatible: Should be "atmel,<chip>-adc"
+    <chip> can be "at91sam9260", "at91sam9g45" or "at91sam9x5"
   - reg: Should contain ADC registers location and length
   - interrupts: Should contain the IRQ line for the ADC
-  - atmel,adc-channel-base: Offset of the first channel data register
   - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
     device
-  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
   - atmel,adc-num-channels: Number of channels available in the ADC
   - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
     defined in the datasheet
-  - atmel,adc-status-register: Offset of the Interrupt Status Register
-  - atmel,adc-trigger-register: Offset of the Trigger Register
   - atmel,adc-vref: Reference voltage in millivolts for the conversions
   - atmel,adc-res: List of resolution in bits supported by the ADC. List size
 		   must be two at least.
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 3ec0c5c..89de156 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,27 +4,17 @@
 Each SATA controller should have its own node.
 
 Required properties:
-- compatible        : compatible list, contains "calxeda,hb-ahci" or "snps,spear-ahci"
+- compatible        : compatible list, contains "snps,spear-ahci"
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
 Optional properties:
-- calxeda,port-phys: phandle-combophy and lane assignment, which maps each
-			SATA port to a combophy and a lane within that
-			combophy
-- calxeda,sgpio-gpio: phandle-gpio bank, bit offset, and default on or off,
-			which indicates that the driver supports SGPIO
-			indicator lights using the indicated GPIOs
-- calxeda,led-order : a u32 array that map port numbers to offsets within the
-			SGPIO bitstream.
 - dma-coherent      : Present if dma operations are coherent
 
 Example:
         sata@ffe08000 {
-		compatible = "calxeda,hb-ahci";
-                reg = <0xffe08000 0x1000>;
-                interrupts = <115>;
-		calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1
-					&combophy0 2 &combophy0 3>;
+		compatible = "snps,spear-ahci";
+		reg = <0xffe08000 0x1000>;
+		interrupts = <115>;
 
         };
diff --git a/Documentation/devicetree/bindings/ata/sata_highbank.txt b/Documentation/devicetree/bindings/ata/sata_highbank.txt
new file mode 100644
index 0000000..aa83407
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/sata_highbank.txt
@@ -0,0 +1,44 @@
+* Calxeda AHCI SATA Controller
+
+SATA nodes are defined to describe on-chip Serial ATA controllers.
+The Calxeda SATA controller mostly conforms to the AHCI interface
+with some special extensions to add functionality.
+Each SATA controller should have its own node.
+
+Required properties:
+- compatible        : compatible list, contains "calxeda,hb-ahci"
+- interrupts        : <interrupt mapping for SATA IRQ>
+- reg               : <registers mapping>
+
+Optional properties:
+- dma-coherent      : Present if dma operations are coherent
+- calxeda,port-phys : phandle-combophy and lane assignment, which maps each
+			SATA port to a combophy and a lane within that
+			combophy
+- calxeda,sgpio-gpio: phandle-gpio bank, bit offset, and default on or off,
+			which indicates that the driver supports SGPIO
+			indicator lights using the indicated GPIOs
+- calxeda,led-order : a u32 array that map port numbers to offsets within the
+			SGPIO bitstream.
+- calxeda,tx-atten  : a u32 array that contains TX attenuation override
+			codes, one per port. The upper 3 bytes are always
+			0 and thus ignored.
+- calxeda,pre-clocks : a u32 that indicates the number of additional clock
+			cycles to transmit before sending an SGPIO pattern
+- calxeda,post-clocks: a u32 that indicates the number of additional clock
+			cycles to transmit after sending an SGPIO pattern
+
+Example:
+        sata@ffe08000 {
+		compatible = "calxeda,hb-ahci";
+		reg = <0xffe08000 0x1000>;
+		interrupts = <115>;
+		dma-coherent;
+		calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1
+					&combophy0 2 &combophy0 3>;
+		calxeda,sgpio-gpio =<&gpioh 5 1 &gpioh 6 1 &gpioh 7 1>;
+		calxeda,led-order = <4 0 1 2 3>;
+		calxeda,tx-atten = <0xff 22 0xff 0xff 23>;
+		calxeda,pre-clocks = <10>;
+		calxeda,post-clocks = <0>;
+        };
diff --git a/Documentation/devicetree/bindings/extcon/extcon-twl.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
similarity index 67%
rename from Documentation/devicetree/bindings/extcon/extcon-twl.txt
rename to Documentation/devicetree/bindings/extcon/extcon-palmas.txt
index 58f531a..7dab6a8 100644
--- a/Documentation/devicetree/bindings/extcon/extcon-twl.txt
+++ b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
@@ -1,15 +1,15 @@
-EXTCON FOR TWL CHIPS
+EXTCON FOR PALMAS/TWL CHIPS
 
 PALMAS USB COMPARATOR
 Required Properties:
  - compatible : Should be "ti,palmas-usb" or "ti,twl6035-usb"
- - vbus-supply : phandle to the regulator device tree node.
 
 Optional Properties:
  - ti,wakeup : To enable the wakeup comparator in probe
+ - ti,enable-id-detection: Perform ID detection.
+ - ti,enable-vbus-detection: Perform VBUS detection.
 
 palmas-usb {
        compatible = "ti,twl6035-usb", "ti,palmas-usb";
-       vbus-supply = <&smps10_reg>;
        ti,wakeup;
 };
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index d933af3..6cec6ff 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -75,23 +75,36 @@
 		gpio-controller;
 	};
 
-2.1) gpio-controller and pinctrl subsystem
-------------------------------------------
+2.1) gpio- and pin-controller interaction
+-----------------------------------------
 
-gpio-controller on a SOC might be tightly coupled with the pinctrl
-subsystem, in the sense that the pins can be used by other functions
-together with optional gpio feature.
+Some or all of the GPIOs provided by a GPIO controller may be routed to pins
+on the package via a pin controller. This allows muxing those pins between
+GPIO and other functions.
 
-While the pin allocation is totally managed by the pin ctrl subsystem,
-gpio (under gpiolib) is still maintained by gpio drivers. It may happen
-that different pin ranges in a SoC is managed by different gpio drivers.
+It is useful to represent which GPIOs correspond to which pins on which pin
+controllers. The gpio-ranges property described below represents this, and
+contains information structures as follows:
 
-This makes it logical to let gpio drivers announce their pin ranges to
-the pin ctrl subsystem and call 'pinctrl_request_gpio' in order to
-request the corresponding pin before any gpio usage.
+	gpio-range-list ::= <single-gpio-range> [gpio-range-list]
+	single-gpio-range ::=
+			<pinctrl-phandle> <gpio-base> <pinctrl-base> <count>
+	gpio-phandle : phandle to pin controller node.
+	gpio-base : Base GPIO ID in the GPIO controller
+	pinctrl-base : Base pinctrl pin ID in the pin controller
+	count : The number of GPIOs/pins in this range
 
-For this, the gpio controller can use a pinctrl phandle and pins to
-announce the pinrange to the pin ctrl subsystem. For example,
+The "pin controller node" mentioned above must conform to the bindings
+described in ../pinctrl/pinctrl-bindings.txt.
+
+Previous versions of this binding required all pin controller nodes that
+were referenced by any gpio-ranges property to contain a property named
+#gpio-range-cells with value <3>. This requirement is now deprecated.
+However, that property may still exist in older device trees for
+compatibility reasons, and would still be required even in new device
+trees that need to be compatible with older software.
+
+Example:
 
 	qe_pio_e: gpio-controller@1460 {
 		#gpio-cells = <2>;
@@ -99,16 +112,8 @@
 		reg = <0x1460 0x18>;
 		gpio-controller;
 		gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
+	};
 
-    }
-
-where,
-   &pinctrl1 and &pinctrl2 is the phandle to the pinctrl DT node.
-
-   Next values specify the base pin and number of pins for the range
-   handled by 'qe_pio_e' gpio. In the given example from base pin 20 to
-   pin 29 under pinctrl1 with gpio offset 0 and pin 50 to pin 69 under
-   pinctrl2 with gpio offset 10 is handled by this gpio controller.
-
-The pinctrl node must have "#gpio-range-cells" property to show number of
-arguments to pass with phandle from gpio controllers node.
+Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
+pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's
+pins 50..59.
diff --git a/Documentation/devicetree/bindings/iio/accel/bma180.txt b/Documentation/devicetree/bindings/iio/accel/bma180.txt
new file mode 100644
index 0000000..c593357
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/accel/bma180.txt
@@ -0,0 +1,24 @@
+* Bosch BMA180 triaxial acceleration sensor
+
+http://omapworld.com/BMA180_111_1002839.pdf
+
+Required properties:
+
+  - compatible : should be "bosch,bma180"
+  - reg : the I2C address of the sensor
+
+Optional properties:
+
+  - interrupt-parent : should be the phandle for the interrupt controller
+
+  - interrupts : interrupt mapping for GPIO IRQ, it should by configured with
+		flags IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING
+
+Example:
+
+bma180@40 {
+	compatible = "bosch,bma180";
+	reg = <0x40>;
+	interrupt-parent = <&gpio6>;
+	interrupts = <18 (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/nuvoton-nau7802.txt b/Documentation/devicetree/bindings/iio/adc/nuvoton-nau7802.txt
new file mode 100644
index 0000000..e9582e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/nuvoton-nau7802.txt
@@ -0,0 +1,18 @@
+* Nuvoton NAU7802 Analog to Digital Converter (ADC)
+
+Required properties:
+  - compatible: Should be "nuvoton,nau7802"
+  - reg: Should contain the ADC I2C address
+
+Optional properties:
+  - nuvoton,vldo: Internal reference voltage in millivolts to be
+    configured valid values are between 2400 mV and 4500 mV.
+  - interrupts: IRQ line for the ADC. If not used the driver will use
+    polling.
+
+Example:
+adc2: nau7802@2a {
+	compatible = "nuvoton,nau7802";
+	reg = <0x2a>;
+	nuvoton,vldo = <3000>;
+};
diff --git a/Documentation/devicetree/bindings/iio/light/apds9300.txt b/Documentation/devicetree/bindings/iio/light/apds9300.txt
new file mode 100644
index 0000000..d6f66c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/apds9300.txt
@@ -0,0 +1,22 @@
+* Avago APDS9300 ambient light sensor
+
+http://www.avagotech.com/docs/AV02-1077EN
+
+Required properties:
+
+  - compatible : should be "avago,apds9300"
+  - reg : the I2C address of the sensor
+
+Optional properties:
+
+  - interrupt-parent : should be the phandle for the interrupt controller
+  - interrupts : interrupt mapping for GPIO IRQ
+
+Example:
+
+apds9300@39 {
+	compatible = "avago,apds9300";
+	reg = <0x39>;
+	interrupt-parent = <&gpio2>;
+	interrupts = <29 8>;
+};
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
index 38e51ad..a45ae08 100644
--- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt
+++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt
@@ -7,9 +7,30 @@
 - reg: Should contain SSC registers location and length
 - interrupts: Should contain SSC interrupt
 
-Example:
+
+Required properties for devices compatible with "atmel,at91sam9g45-ssc":
+- dmas: DMA specifier, consisting of a phandle to DMA controller node,
+  the memory interface and SSC DMA channel ID (for tx and rx).
+  See Documentation/devicetree/bindings/dma/atmel-dma.txt for details.
+- dma-names: Must be "tx", "rx".
+
+Examples:
+- PDC transfer:
 ssc0: ssc@fffbc000 {
 	compatible = "atmel,at91rm9200-ssc";
 	reg = <0xfffbc000 0x4000>;
 	interrupts = <14 4 5>;
 };
+
+- DMA transfer:
+ssc0: ssc@f0010000 {
+      compatible = "atmel,at91sam9g45-ssc";
+      reg = <0xf0010000 0x4000>;
+      interrupts = <28 4 5>;
+      dmas = <&dma0 1 13>,
+	     <&dma0 1 14>;
+      dma-names = "tx", "rx";
+      pinctrl-names = "default";
+      pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+      status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt
index e2371f5..eabcb4b 100644
--- a/Documentation/devicetree/bindings/pci/designware-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt
@@ -18,6 +18,7 @@
 - interrupt-map-mask and interrupt-map: standard PCI properties
 	to define the mapping of the PCIe interface to interrupt
 	numbers.
+- num-lanes: number of lanes to use
 - reset-gpio: gpio pin number of power good signal
 
 Example:
@@ -41,6 +42,7 @@
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 0 0>;
 		interrupt-map = <0x0 0 &gic 53>;
+		num-lanes = <4>;
 	};
 
 	pcie@2a0000 {
@@ -60,6 +62,7 @@
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 0 0>;
 		interrupt-map = <0x0 0 &gic 56>;
+		num-lanes = <4>;
 	};
 
 Board specific DT Entry:
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
index aeb3c99..1958ca9 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -127,21 +127,20 @@
 nodes, is again defined entirely by the binding for the individual pin
 controller device.
 
-== Using generic pinconfig options ==
+== Generic pin configuration node content ==
 
-Generic pinconfig parameters can be used by defining a separate node containing
-the applicable parameters (and optional values), like:
+Many data items that are represented in a pin configuration node are common
+and generic. Pin control bindings should use the properties defined below
+where they are applicable; not all of these properties are relevant or useful
+for all hardware or binding structures. Each individual binding document
+should state which of these generic properties, if any, are used, and the
+structure of the DT nodes that contain these properties.
 
-pcfg_pull_up: pcfg_pull_up {
-	bias-pull-up;
-	drive-strength = <20>;
-};
+Supported generic properties are:
 
-This node should then be referenced in the appropriate pinctrl node as a phandle
-and parsed in the driver using the pinconf_generic_parse_dt_config function.
-
-Supported configuration parameters are:
-
+pins			- the list of pins that properties in the node
+			  apply to
+function		- the mux function to select
 bias-disable		- disable any pin bias
 bias-high-impedance	- high impedance mode ("third-state", "floating")
 bias-bus-hold		- latch weakly
@@ -160,7 +159,21 @@
 output-low		- set the pin to output mode with low level
 output-high		- set the pin to output mode with high level
 
-Arguments for parameters:
+Some of the generic properties take arguments. For those that do, the
+arguments are described below.
+
+- pins takes a list of pin names or IDs as a required argument. The specific
+  binding for the hardware defines:
+  - Whether the entries are integers or strings, and their meaning.
+
+- function takes a list of function names/IDs as a required argument. The
+  specific binding for the hardware defines:
+  - Whether the entries are integers or strings, and their meaning.
+  - Whether only a single entry is allowed (which is applied to all entries
+    in the pins property), or whether there may alternatively be one entry per
+    entry in the pins property, in which case the list lengths must match, and
+    for each list index i, the function at list index i is applied to the pin
+    at list index i.
 
 - bias-pull-up, -down and -pin-default take as optional argument on hardware
   supporting it the pull strength in Ohm. bias-disable will disable the pull.
@@ -170,7 +183,5 @@
 - input-debounce takes the debounce time in usec as argument
   or 0 to disable debouncing
 
-All parameters not listed here, do not take an argument.
-
 More in-depth documentation on these parameters can be found in
 <include/linux/pinctrl/pinconfig-generic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
new file mode 100644
index 0000000..734d9b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
@@ -0,0 +1,96 @@
+Palmas Pincontrol bindings
+
+The pins of Palmas device can be set on different option and provides
+the configuration for Pull UP/DOWN, open drain etc.
+
+Required properties:
+- compatible: It must be one of following:
+  - "ti,palmas-pinctrl" for Palma series of the pincontrol.
+  - "ti,tps65913-pinctrl" for Palma series device TPS65913.
+  - "ti,tps80036-pinctrl" for Palma series device TPS80036.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Palmas's pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+list of pins. This configuration can include the mux function to select on
+those pin(s), and various pin configuration parameters, such as pull-up,
+open drain.
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+Optional properties:
+- ti,palmas-enable-dvfs1: Enable DVFS1. Configure pins for DVFS1 mode.
+	Selection primary or secondary function associated to I2C2_SCL_SCE,
+	I2C2_SDA_SDO pin/pad for DVFS1 interface
+- ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode.
+	Selection primary or secondary function associated to GPADC_START
+	and SYSEN2 pin/pad for DVFS2 interface
+
+This binding uses the following generic properties as defined in
+pinctrl-bindings.txt:
+
+Required: pins
+Options: function, bias-disable, bias-pull-up, bias-pull-down,
+	 bias-pin-default, drive-open-drain.
+
+Note that many of these properties are only valid for certain specific pins.
+See the Palmas device datasheet for complete details regarding which pins
+support which functionality.
+
+Valid values for pin names are:
+	gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6, gpio7, gpio8, gpio9,
+	gpio10, gpio11, gpio12, gpio13, gpio14, gpio15, vac, powergood,
+	nreswarm, pwrdown, gpadc_start, reset_in, nsleep, enable1, enable2,
+	int.
+
+Valid value of function names are:
+	gpio, led, pwm, regen, sysen, clk32kgaudio, id, vbus_det, chrg_det,
+	vac, vacok, powergood, usb_psel, msecure, pwrhold, int, nreswarm,
+	simrsto, simrsti, low_vbat, wireless_chrg1, rcm, pwrdown, gpadc_start,
+	reset_in, nsleep, enable.
+
+There are 4 special functions: opt0, opt1, opt2 and opt3. If any of these
+functions is selected then directly pins register will be written with 0, 1, 2
+or 3 respectively if it is valid for that pins or list of pins.
+
+Example:
+	palmas: tps65913 {
+		....
+		pinctrl {
+			compatible = "ti,tps65913-pinctrl";
+			ti,palmas-enable-dvfs1;
+			pinctrl-names = "default";
+			pinctrl-0 = <&palmas_pins_state>;
+
+			palmas_pins_state: pinmux {
+				gpio0 {
+					pins = "gpio0";
+					function = "id";
+					bias-pull-up;
+				};
+
+				vac {
+					pins = "vac";
+					function = "vacok";
+					bias-pull-down;
+				};
+
+				gpio5 {
+					pins = "gpio5";
+					function = "opt0";
+					drive-open-drain = <1>;
+				};
+			};
+		};
+		....
+	};
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index 36281e7..257677d 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -12,6 +12,7 @@
   - "samsung,s3c2440-pinctrl": for S3C2440-compatible pin-controller,
   - "samsung,s3c2450-pinctrl": for S3C2450-compatible pin-controller,
   - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller,
+  - "samsung,s5pv210-pinctrl": for S5PV210-compatible pin-controller,
   - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
   - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
   - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
@@ -128,7 +129,7 @@
      - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller
        found on Samsung S3C64xx SoCs,
      - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller
-       found on Samsung Exynos4210 SoC.
+       found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs.
    - interrupt-parent: phandle of the interrupt parent to which the external
      wakeup interrupts are forwarded to.
    - interrupts: interrupt used by multiplexed wakeup interrupts.
diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
index de0eaed..8031148 100644
--- a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -2,11 +2,9 @@
 
 Required properties:
 - compatible: should be "atmel,tcb-pwm"
-- #pwm-cells: Should be 3.  The first cell specifies the per-chip index
-  of the PWM to use, the second cell is the period in nanoseconds and
-  bit 0 in the third cell is used to encode the polarity of PWM output.
-  Set bit 0 of the third cell in PWM specifier to 1 for inverse polarity &
-  set to 0 for normal polarity.
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+  the cells format. The only third cell flag supported by this binding is
+  PWM_POLARITY_INVERTED.
 - tc-block: The Timer Counter block to use as a PWM chip.
 
 Example:
diff --git a/Documentation/devicetree/bindings/pwm/imx-pwm.txt b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
index 8522bfb..b50d7a6d 100644
--- a/Documentation/devicetree/bindings/pwm/imx-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/imx-pwm.txt
@@ -3,8 +3,8 @@
 Required properties:
 - compatible: should be "fsl,<soc>-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2.  The first cell specifies the per-chip index
-  of the PWM to use and the second cell is the period in nanoseconds.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
 - interrupts: The interrupt for the pwm controller
 
 Example:
diff --git a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
index 9e3f8f1..96cdde5 100644
--- a/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/mxs-pwm.txt
@@ -3,8 +3,8 @@
 Required properties:
 - compatible: should be "fsl,imx23-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: should be 2.  The first cell specifies the per-chip index
-  of the PWM to use and the second cell is the period in nanoseconds.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
 - fsl,pwm-number: the number of PWM devices
 
 Example:
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
index 01438ec..c3fc57a 100644
--- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
@@ -5,9 +5,8 @@
   - "nvidia,tegra20-pwm"
   - "nvidia,tegra30-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: On Tegra the number of cells used to specify a PWM is 2. The
-  first cell specifies the per-chip index of the PWM to use and the second
-  cell is the period in nanoseconds.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
index 1e3dfe7..f84ec9d 100644
--- a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
@@ -3,8 +3,8 @@
 
 Required properties:
   - compatible: "nxp,pca9685-pwm"
-  - #pwm-cells: should be 2. The first cell specifies the per-chip index
-    of the PWM to use and the second cell is the period in nanoseconds.
+  - #pwm-cells: Should be 2. See pwm.txt in this directory for a description of
+    the cells format.
     The index 16 is the ALLCALL channel, that sets all PWM channels at the same
     time.
 
diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
index ac67c68..4caa1a7 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.txt
@@ -19,13 +19,9 @@
 - reg: base address and size of register area
 - interrupts: list of timer interrupts (one interrupt per timer, starting at
   timer 0)
-- #pwm-cells: number of cells used for PWM specifier - must be 3
-   the specifier format is as follows:
-     - phandle to PWM controller node
-     - index of PWM channel (from 0 to 4)
-     - PWM signal period in nanoseconds
-     - bitmask of optional PWM flags:
-        0x1 - invert PWM signal
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+  the cells format. The only third cell flag supported by this binding is
+  PWM_POLARITY_INVERTED.
 
 Optional properties:
 - samsung,pwm-outputs: list of PWM channels used as PWM outputs on particular
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
index 681afad..fb81179 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
@@ -4,11 +4,9 @@
 - compatible: Must be "ti,<soc>-ecap".
   for am33xx - compatible = "ti,am33xx-ecap";
   for da850  - compatible = "ti,da850-ecap", "ti,am33xx-ecap";
-- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
-  First cell specifies the per-chip index of the PWM to use, the second
-  cell is the period in nanoseconds and bit 0 in the third cell is used to
-  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
-  to 1 for inverse polarity & set to 0 for normal polarity.
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+  the cells format. The PWM channel index ranges from 0 to 4. The only third
+  cell flag supported by this binding is PWM_POLARITY_INVERTED.
 - reg: physical base address and size of the registers map.
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
index 337c6fc..9c100b2 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
@@ -4,11 +4,9 @@
 - compatible: Must be "ti,<soc>-ehrpwm".
   for am33xx - compatible = "ti,am33xx-ehrpwm";
   for da850  - compatible = "ti,da850-ehrpwm", "ti,am33xx-ehrpwm";
-- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
-  First cell specifies the per-chip index of the PWM to use, the second
-  cell is the period in nanoseconds and bit 0 in the third cell is used to
-  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
-  to 1 for inverse polarity & set to 0 for normal polarity.
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+  the cells format. The only third cell flag supported by this binding is
+  PWM_POLARITY_INVERTED.
 - reg: physical base address and size of the registers map.
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt
index 06e6724..8556263 100644
--- a/Documentation/devicetree/bindings/pwm/pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm.txt
@@ -43,13 +43,14 @@
 pwm-specifier typically encodes the chip-relative PWM number and the PWM
 period in nanoseconds.
 
-Optionally, the pwm-specifier can encode a number of flags in a third cell:
-- bit 0: PWM signal polarity (0: normal polarity, 1: inverse polarity)
+Optionally, the pwm-specifier can encode a number of flags (defined in
+<dt-bindings/pwm/pwm.h>) in a third cell:
+- PWM_POLARITY_INVERTED: invert the PWM signal polarity
 
 Example with optional PWM specifier for inverse polarity
 
 	bl: backlight {
-		pwms = <&pwm 0 5000000 1>;
+		pwms = <&pwm 0 5000000 PWM_POLARITY_INVERTED>;
 		pwm-names = "backlight";
 	};
 
diff --git a/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
new file mode 100644
index 0000000..b067e84
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/renesas,tpu-pwm.txt
@@ -0,0 +1,28 @@
+* Renesas R-Car Timer Pulse Unit PWM Controller
+
+Required Properties:
+
+  - compatible: should be one of the following.
+    - "renesas,tpu-r8a73a4": for R8A77A4 (R-Mobile APE6) compatible PWM controller.
+    - "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) compatible PWM controller.
+    - "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) compatible PWM controller.
+    - "renesas,tpu-sh7372": for SH7372 (SH-Mobile AP4) compatible PWM controller.
+    - "renesas,tpu": for generic R-Car TPU PWM controller.
+
+  - reg: Base address and length of each memory resource used by the PWM
+    controller hardware module.
+
+  - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+    the cells format. The only third cell flag supported by this binding is
+    PWM_POLARITY_INVERTED.
+
+Please refer to pwm.txt in this directory for details of the common PWM bindings
+used by client devices.
+
+Example: R8A7740 (R-Car A1) TPU controller node
+
+	tpu: pwm@e6600000 {
+		compatible = "renesas,tpu-r8a7740", "renesas,tpu";
+		reg = <0xe6600000 0x100>;
+		#pwm-cells = <3>;
+	};
diff --git a/Documentation/devicetree/bindings/pwm/spear-pwm.txt b/Documentation/devicetree/bindings/pwm/spear-pwm.txt
index 3ac779d..b486de2 100644
--- a/Documentation/devicetree/bindings/pwm/spear-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/spear-pwm.txt
@@ -5,9 +5,8 @@
   - "st,spear320-pwm"
   - "st,spear1340-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: number of cells used to specify PWM which is fixed to 2 on
-  SPEAr. The first cell specifies the per-chip index of the PWM to use and
-  the second cell is the period in nanoseconds.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
index 2943ee5..4e32bee 100644
--- a/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
@@ -6,8 +6,8 @@
 
 Required properties:
 - compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm"
-- #pwm-cells: should be 2.  The first cell specifies the per-chip index
-  of the PWM to use and the second cell is the period in nanoseconds.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
index cb64f3a..9f4b460 100644
--- a/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
+++ b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
@@ -6,8 +6,8 @@
 
 Required properties:
 - compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled"
-- #pwm-cells: should be 2.  The first cell specifies the per-chip index
-  of the PWM to use and the second cell is the period in nanoseconds.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+  the cells format.
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
index d21d82d..a76390e 100644
--- a/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
@@ -3,11 +3,9 @@
 Required properties:
 - compatible: should be "via,vt8500-pwm"
 - reg: physical base address and length of the controller's registers
-- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
-  First cell specifies the per-chip index of the PWM to use, the second
-  cell is the period in nanoseconds and bit 0 in the third cell is used to
-  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
-  to 1 for inverse polarity & set to 0 for normal polarity.
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+  the cells format. The only third cell flag supported by this binding is
+  PWM_POLARITY_INVERTED.
 - clocks: phandle to the PWM source clock
 
 Example:
diff --git a/Documentation/devicetree/bindings/regulator/88pm800.txt b/Documentation/devicetree/bindings/regulator/88pm800.txt
new file mode 100644
index 0000000..e8a54c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/88pm800.txt
@@ -0,0 +1,38 @@
+Marvell 88PM800 regulator
+
+Required properties:
+- compatible: "marvell,88pm800"
+- reg: I2C slave address
+- regulators: A node that houses a sub-node for each regulator within the
+  device. Each sub-node is identified using the node's name (or the deprecated
+  regulator-compatible property if present), with valid values listed below.
+  The content of each sub-node is defined by the standard binding for
+  regulators; see regulator.txt.
+
+The valid names for regulators are:
+
+  buck1, buck2, buck3, buck4, buck5, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7,
+  ldo8, ldo9, ldo10, ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19
+
+Example:
+
+	pmic: 88pm800@31 {
+		compatible = "marvell,88pm800";
+		reg = <0x31>;
+
+		regulators {
+			buck1 {
+			        regulator-min-microvolt = <600000>;
+			        regulator-max-microvolt = <3950000>;
+			        regulator-boot-on;
+			        regulator-always-on;
+			};
+			ldo1 {
+			        regulator-min-microvolt = <600000>;
+			        regulator-max-microvolt = <15000000>;
+			        regulator-boot-on;
+			        regulator-always-on;
+			};
+...
+		};
+	};
diff --git a/Documentation/devicetree/bindings/regulator/max8660.txt b/Documentation/devicetree/bindings/regulator/max8660.txt
new file mode 100644
index 0000000..8ba994d
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/max8660.txt
@@ -0,0 +1,47 @@
+Maxim MAX8660 voltage regulator
+
+Required properties:
+- compatible: must be one of "maxim,max8660", "maxim,max8661"
+- reg: I2C slave address, usually 0x34
+- any required generic properties defined in regulator.txt
+
+Example:
+
+	i2c_master {
+		max8660@34 {
+			compatible = "maxim,max8660";
+			reg = <0x34>;
+
+			regulators {
+				regulator@0 {
+					regulator-compatible= "V3(DCDC)";
+					regulator-min-microvolt = <725000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@1 {
+					regulator-compatible= "V4(DCDC)";
+					regulator-min-microvolt = <725000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator@2 {
+					regulator-compatible= "V5(LDO)";
+					regulator-min-microvolt = <1700000>;
+					regulator-max-microvolt = <2000000>;
+				};
+
+				regulator@3 {
+					regulator-compatible= "V6(LDO)";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				regulator@4 {
+					regulator-compatible= "V7(LDO)";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <3300000>;
+				};
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt
index 30b0581..a22e4c7 100644
--- a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt
+++ b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt
@@ -25,8 +25,8 @@
 	       Additional custom properties  are listed below.
 
 	       For ti,palmas-pmic - smps12, smps123, smps3 depending on OTP,
-	       smps45, smps457, smps7 depending on variant, smps6, smps[8-10],
-	       ldo[1-9], ldoln, ldousb.
+	       smps45, smps457, smps7 depending on variant, smps6, smps[8-9],
+	       smps10_out2, smps10_out1, do[1-9], ldoln, ldousb.
 
 	       Optional sub-node properties:
 	       ti,warm-reset - maintain voltage during warm reset(boolean)
diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
new file mode 100644
index 0000000..fc989b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt
@@ -0,0 +1,115 @@
+PFUZE100 family of regulators
+
+Required properties:
+- compatible: "fsl,pfuze100"
+- reg: I2C slave address
+
+Required child node:
+- regulators: This is the list of child nodes that specify the regulator
+  initialization data for defined regulators. Please refer to below doc
+  Documentation/devicetree/bindings/regulator/regulator.txt.
+
+  The valid names for regulators are:
+  sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+	pmic: pfuze100@08 {
+		compatible = "fsl,pfuze100";
+		reg = <0x08>;
+
+		regulators {
+			sw1a_reg: sw1ab {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <6250>;
+			};
+
+			sw1c_reg: sw1c {
+				regulator-min-microvolt = <300000>;
+				regulator-max-microvolt = <1875000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw2_reg: sw2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3a_reg: sw3a {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw3b_reg: sw3b {
+				regulator-min-microvolt = <400000>;
+				regulator-max-microvolt = <1975000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			sw4_reg: sw4 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			swbst_reg: swbst {
+				regulator-min-microvolt = <5000000>;
+				regulator-max-microvolt = <5150000>;
+			};
+
+			snvs_reg: vsnvs {
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <3000000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vref_reg: vrefddr {
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			vgen1_reg: vgen1 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen2_reg: vgen2 {
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1550000>;
+			};
+
+			vgen3_reg: vgen3 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+			};
+
+			vgen4_reg: vgen4 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen5_reg: vgen5 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+
+			vgen6_reg: vgen6 {
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-always-on;
+			};
+		};
+	};
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 48a3b8e..2bd8f09 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -12,6 +12,8 @@
 - regulator-allow-bypass: allow the regulator to go into bypass mode
 - <name>-supply: phandle to the parent supply/regulator node
 - regulator-ramp-delay: ramp delay for regulator(in uV/uS)
+  For hardwares which support disabling ramp rate, it should be explicitly
+  intialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay.
 
 Deprecated properties:
 - regulator-compatible: If a regulator chip contains multiple
diff --git a/Documentation/devicetree/bindings/tty/serial/arc-uart.txt b/Documentation/devicetree/bindings/serial/arc-uart.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/arc-uart.txt
rename to Documentation/devicetree/bindings/serial/arc-uart.txt
diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt
new file mode 100644
index 0000000..2191dcb
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt
@@ -0,0 +1,43 @@
+* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
+
+Required properties:
+- compatible: Should be "atmel,<chip>-usart"
+  The compatible <chip> indicated will be the first SoC to support an
+  additional mode or an USART new feature.
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Optional properties:
+- atmel,use-dma-rx: use of PDC or DMA for receiving data
+- atmel,use-dma-tx: use of PDC or DMA for transmitting data
+- add dma bindings for dma transfer:
+	- dmas: DMA specifier, consisting of a phandle to DMA controller node,
+		memory peripheral interface and USART DMA channel ID, FIFO configuration.
+		Refer to dma.txt and atmel-dma.txt for details.
+	- dma-names: "rx" for RX channel, "tx" for TX channel.
+
+<chip> compatible description:
+- at91rm9200:  legacy USART support
+- at91sam9260: generic USART implementation for SAM9 SoCs
+
+Example:
+- use PDC:
+	usart0: serial@fff8c000 {
+		compatible = "atmel,at91sam9260-usart";
+		reg = <0xfff8c000 0x4000>;
+		interrupts = <7>;
+		atmel,use-dma-rx;
+		atmel,use-dma-tx;
+	};
+
+- use DMA:
+	usart0: serial@f001c000 {
+		compatible = "atmel,at91sam9260-usart";
+		reg = <0xf001c000 0x100>;
+		interrupts = <12 4 5>;
+		atmel,use-dma-rx;
+		atmel,use-dma-tx;
+		dmas = <&dma0 2 0x3>,
+		       <&dma0 2 0x204>;
+		dma-names = "tx", "rx";
+	};
diff --git a/Documentation/devicetree/bindings/tty/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/efm32-uart.txt
rename to Documentation/devicetree/bindings/serial/efm32-uart.txt
diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
index c58573b..35ae1fb 100644
--- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
@@ -1,35 +1,29 @@
-* Freescale i.MX UART controller
+* Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
 
 Required properties:
-- compatible : should be "fsl,imx21-uart"
+- compatible : Should be "fsl,<soc>-uart"
 - reg : Address and length of the register set for the device
-- interrupts : Should contain UART interrupt number
+- interrupts : Should contain uart interrupt
 
 Optional properties:
-- fsl,uart-has-rtscts: indicate that RTS/CTS signals are used
+- fsl,uart-has-rtscts : Indicate the uart has rts and cts
+- fsl,irda-mode : Indicate the uart supports irda mode
+- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
+                  is DCE mode by default.
 
 Note: Each uart controller should have an alias correctly numbered
 in "aliases" node.
 
 Example:
 
-- From imx51.dtsi:
 aliases {
 	serial0 = &uart1;
-	serial1 = &uart2;
-	serial2 = &uart3;
 };
 
 uart1: serial@73fbc000 {
 	compatible = "fsl,imx51-uart", "fsl,imx21-uart";
 	reg = <0x73fbc000 0x4000>;
 	interrupts = <31>;
-	status = "disabled";
-}
-
-- From imx51-babbage.dts:
-uart1: serial@73fbc000 {
 	fsl,uart-has-rtscts;
-	status = "okay";
+	fsl,dte-mode;
 };
-
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt
rename to Documentation/devicetree/bindings/serial/fsl-lpuart.txt
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
similarity index 85%
rename from Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt
rename to Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
index 2c00ec6..59a40f1 100644
--- a/Documentation/devicetree/bindings/tty/serial/fsl-mxs-auart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
@@ -10,6 +10,10 @@
   Refer to dma.txt and fsl-mxs-dma.txt for details.
 - dma-names: "rx" for RX channel, "tx" for TX channel.
 
+Optional properties:
+- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines,
+	it also means you enable the DMA support for this UART.
+
 Example:
 auart0: serial@8006a000 {
 	compatible = "fsl,imx28-auart", "fsl,imx23-auart";
diff --git a/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt b/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt
new file mode 100644
index 0000000..669b814
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt
@@ -0,0 +1,65 @@
+Device tree bindings for Marvell PXA SSP ports
+
+Required properties:
+
+	- compatible:	Must be one of
+				mrvl,pxa25x-ssp
+				mvrl,pxa25x-nssp
+				mrvl,pxa27x-ssp
+				mrvl,pxa3xx-ssp
+				mvrl,pxa168-ssp
+				mrvl,pxa910-ssp
+				mrvl,ce4100-ssp
+				mrvl,lpss-ssp
+
+	- reg:		The memory base
+	- dmas:		Two dma phandles, one for rx, one for tx
+	- dma-names:	Must be "rx", "tx"
+
+
+Example for PXA3xx:
+
+	ssp0: ssp@41000000 {
+		compatible = "mrvl,pxa3xx-ssp";
+		reg = <0x41000000 0x40>;
+		ssp-id = <1>;
+		interrupts = <24>;
+		clock-names = "pxa27x-ssp.0";
+		dmas = <&dma 13
+			&dma 14>;
+		dma-names = "rx", "tx";
+	};
+
+	ssp1: ssp@41700000 {
+		compatible = "mrvl,pxa3xx-ssp";
+		reg = <0x41700000 0x40>;
+		ssp-id = <2>;
+		interrupts = <16>;
+		clock-names = "pxa27x-ssp.1";
+		dmas = <&dma 15
+			&dma 16>;
+		dma-names = "rx", "tx";
+	};
+
+	ssp2: ssp@41900000 {
+		compatibl3 = "mrvl,pxa3xx-ssp";
+		reg = <0x41900000 0x40>;
+		ssp-id = <3>;
+		interrupts = <0>;
+		clock-names = "pxa27x-ssp.2";
+		dmas = <&dma 66
+			&dma 67>;
+		dma-names = "rx", "tx";
+	};
+
+	ssp3: ssp@41a00000 {
+		compatible = "mrvl,pxa3xx-ssp";
+		reg = <0x41a00000 0x40>;
+		ssp-id = <4>;
+		interrupts = <13>;
+		clock-names = "pxa27x-ssp.3";
+		dmas = <&dma 2
+			&dma 3>;
+		dma-names = "rx", "tx";
+	};
+
diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/serial/nxp-lpc32xx-hsuart.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
rename to Documentation/devicetree/bindings/serial/nxp-lpc32xx-hsuart.txt
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/serial/of-serial.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/of-serial.txt
rename to Documentation/devicetree/bindings/serial/of-serial.txt
diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uart.txt b/Documentation/devicetree/bindings/serial/qcom,msm-uart.txt
new file mode 100644
index 0000000..ce8c901
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/qcom,msm-uart.txt
@@ -0,0 +1,25 @@
+* MSM Serial UART
+
+The MSM serial UART hardware is designed for low-speed use cases where a
+dma-engine isn't needed. From a software perspective it's mostly compatible
+with the MSM serial UARTDM except that it only supports reading and writing one
+character at a time.
+
+Required properties:
+- compatible: Should contain "qcom,msm-uart"
+- reg: Should contain UART register location and length.
+- interrupts: Should contain UART interrupt.
+- clocks: Should contain the core clock.
+- clock-names: Should be "core".
+
+Example:
+
+A uart device at 0xa9c00000 with interrupt 11.
+
+serial@a9c00000 {
+	compatible = "qcom,msm-uart";
+	reg = <0xa9c00000 0x1000>;
+	interrupts = <11>;
+	clocks = <&uart_cxc>;
+	clock-names = "core";
+};
diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt
new file mode 100644
index 0000000..ffa5b78
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt
@@ -0,0 +1,53 @@
+* MSM Serial UARTDM
+
+The MSM serial UARTDM hardware is designed for high-speed use cases where the
+transmit and/or receive channels can be offloaded to a dma-engine. From a
+software perspective it's mostly compatible with the MSM serial UART except
+that it supports reading and writing multiple characters at a time.
+
+Required properties:
+- compatible: Should contain at least "qcom,msm-uartdm".
+              A more specific property should be specified as follows depending
+	      on the version:
+		"qcom,msm-uartdm-v1.1"
+		"qcom,msm-uartdm-v1.2"
+		"qcom,msm-uartdm-v1.3"
+		"qcom,msm-uartdm-v1.4"
+- reg: Should contain UART register locations and lengths. The first
+       register shall specify the main control registers. An optional second
+       register location shall specify the GSBI control region.
+       "qcom,msm-uartdm-v1.3" is the only compatible value that might
+       need the GSBI control region.
+- interrupts: Should contain UART interrupt.
+- clocks: Should contain the core clock and the AHB clock.
+- clock-names: Should be "core" for the core clock and "iface" for the
+	       AHB clock.
+
+Optional properties:
+- dmas: Should contain dma specifiers for transmit and receive channels
+- dma-names: Should contain "tx" for transmit and "rx" for receive channels
+
+Examples:
+
+A uartdm v1.4 device with dma capabilities.
+
+serial@f991e000 {
+	compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+	reg = <0xf991e000 0x1000>;
+	interrupts = <0 108 0x0>;
+	clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>;
+	clock-names = "core", "iface";
+	dmas = <&dma0 0>, <&dma0 1>;
+	dma-names = "tx", "rx";
+};
+
+A uartdm v1.3 device without dma capabilities and part of a GSBI complex.
+
+serial@19c40000 {
+	compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+	reg = <0x19c40000 0x1000>,
+	      <0x19c00000 0x1000>;
+	interrupts = <0 195 0x0>;
+	clocks = <&gsbi5_uart_cxc>, <&gsbi5_ahb_cxc>;
+	clock-names = "core", "iface";
+};
diff --git a/Documentation/devicetree/bindings/serial/sirf-uart.txt b/Documentation/devicetree/bindings/serial/sirf-uart.txt
new file mode 100644
index 0000000..a2dfc65
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/sirf-uart.txt
@@ -0,0 +1,33 @@
+* CSR SiRFprimaII/atlasVI Universal Synchronous Asynchronous Receiver/Transmitter *
+
+Required properties:
+- compatible : Should be "sirf,prima2-uart" or "sirf, prima2-usp-uart"
+- reg : Offset and length of the register set for the device
+- interrupts : Should contain uart interrupt
+- fifosize : Should define hardware rx/tx fifo size
+- clocks : Should contain uart clock number
+
+Optional properties:
+- sirf,uart-has-rtscts: we have hardware flow controller pins in hardware
+- rts-gpios: RTS pin for USP-based UART if sirf,uart-has-rtscts is true
+- cts-gpios: CTS pin for USP-based UART if sirf,uart-has-rtscts is true
+
+Example:
+
+uart0: uart@b0050000 {
+	cell-index = <0>;
+	compatible = "sirf,prima2-uart";
+	reg = <0xb0050000 0x1000>;
+	interrupts = <17>;
+	fifosize = <128>;
+	clocks = <&clks 13>;
+};
+
+On the board-specific dts, we can put rts-gpios and cts-gpios like
+
+usp@b0090000 {
+	compatible = "sirf,prima2-usp-uart";
+	sirf,uart-has-rtscts;
+	rts-gpios = <&gpio 15 0>;
+	cts-gpios = <&gpio 46 0>;
+};
diff --git a/Documentation/devicetree/bindings/tty/serial/snps-dw-apb-uart.txt b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/snps-dw-apb-uart.txt
rename to Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
diff --git a/Documentation/devicetree/bindings/serial/st-asc.txt b/Documentation/devicetree/bindings/serial/st-asc.txt
new file mode 100644
index 0000000..75d877f
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/st-asc.txt
@@ -0,0 +1,18 @@
+*st-asc(Serial Port)
+
+Required properties:
+- compatible : Should be "st,asc".
+- reg, reg-names, interrupts, interrupt-names	: Standard way to define device
+			resources with names. look in
+			Documentation/devicetree/bindings/resource-names.txt
+
+Optional properties:
+- st,hw-flow-ctrl	bool flag to enable hardware flow control.
+- st,force-m1		bool flat to force asc to be in Mode-1 recommeded
+			for high bit rates (above 19.2K)
+Example:
+serial@fe440000{
+    compatible    = "st,asc";
+    reg         = <0xfe440000 0x2c>;
+    interrupts     =  <0 209 0>;
+};
diff --git a/Documentation/devicetree/bindings/tty/serial/via,vt8500-uart.txt b/Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
similarity index 100%
rename from Documentation/devicetree/bindings/tty/serial/via,vt8500-uart.txt
rename to Documentation/devicetree/bindings/serial/via,vt8500-uart.txt
diff --git a/Documentation/devicetree/bindings/sound/ak4554.c b/Documentation/devicetree/bindings/sound/ak4554.c
new file mode 100644
index 0000000..934fa02
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ak4554.c
@@ -0,0 +1,11 @@
+AK4554 ADC/DAC
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak4554"
+
+Example:
+
+ak4554-adc-dac {
+	compatible = "asahi-kasei,ak4554";
+};
diff --git a/Documentation/devicetree/bindings/sound/alc5632.txt b/Documentation/devicetree/bindings/sound/alc5632.txt
index 8608f74..ffd886d 100644
--- a/Documentation/devicetree/bindings/sound/alc5632.txt
+++ b/Documentation/devicetree/bindings/sound/alc5632.txt
@@ -13,6 +13,25 @@
   - #gpio-cells : Should be two. The first cell is the pin number and the
     second cell is used to specify optional parameters (currently unused).
 
+Pins on the device (for linking into audio routes):
+
+  * SPK_OUTP
+  * SPK_OUTN
+  * HP_OUT_L
+  * HP_OUT_R
+  * AUX_OUT_P
+  * AUX_OUT_N
+  * LINE_IN_L
+  * LINE_IN_R
+  * PHONE_P
+  * PHONE_N
+  * MIC1_P
+  * MIC1_N
+  * MIC2_P
+  * MIC2_N
+  * MICBIAS1
+  * DMICDAT
+
 Example:
 
 alc5632: alc5632@1e {
diff --git a/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt b/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
new file mode 100644
index 0000000..0720857
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
@@ -0,0 +1,35 @@
+* Atmel at91sam9x5ek wm8731 audio complex
+
+Required properties:
+  - compatible: "atmel,sam9x5-wm8731-audio"
+  - atmel,model: The user-visible name of this sound complex.
+  - atmel,ssc-controller: The phandle of the SSC controller
+  - atmel,audio-codec: The phandle of the WM8731 audio codec
+  - atmel,audio-routing: A list of the connections between audio components.
+    Each entry is a pair of strings, the first being the connection's sink,
+    the second being the connection's source.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headphone Jack
+ * Line In Jack
+
+wm8731 pins:
+cf Documentation/devicetree/bindings/sound/wm8731.txt
+
+Example:
+sound {
+	compatible = "atmel,sam9x5-wm8731-audio";
+
+	atmel,model = "wm8731 @ AT91SAM9X5EK";
+
+	atmel,audio-routing =
+		"Headphone Jack", "RHPOUT",
+		"Headphone Jack", "LHPOUT",
+		"LLINEIN", "Line In Jack",
+		"RLINEIN", "Line In Jack";
+
+	atmel,ssc-controller = <&ssc0>;
+	atmel,audio-codec = <&wm8731>;
+};
diff --git a/Documentation/devicetree/bindings/sound/atmel-wm8904.txt b/Documentation/devicetree/bindings/sound/atmel-wm8904.txt
new file mode 100644
index 0000000..8bbe50c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/atmel-wm8904.txt
@@ -0,0 +1,55 @@
+Atmel ASoC driver with wm8904 audio codec complex
+
+Required properties:
+  - compatible: "atmel,asoc-wm8904"
+  - atmel,model: The user-visible name of this sound complex.
+  - atmel,audio-routing: A list of the connections between audio components.
+    Each entry is a pair of strings, the first being the connection's sink,
+    the second being the connection's source. Valid names for sources and
+    sinks are the WM8904's pins, and the jacks on the board:
+
+    WM8904 pins:
+
+    * IN1L
+    * IN1R
+    * IN2L
+    * IN2R
+    * IN3L
+    * IN3R
+    * HPOUTL
+    * HPOUTR
+    * LINEOUTL
+    * LINEOUTR
+    * MICBIAS
+
+    Board connectors:
+
+    * Headphone Jack
+    * Line In Jack
+    * Mic
+
+  - atmel,ssc-controller: The phandle of the SSC controller
+  - atmel,audio-codec: The phandle of the WM8904 audio codec
+
+Optional properties:
+  - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
+
+Example:
+sound {
+	compatible = "atmel,asoc-wm8904";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_pck0_as_mck>;
+
+	atmel,model = "wm8904 @ AT91SAM9N12EK";
+
+	atmel,audio-routing =
+		"Headphone Jack", "HPOUTL",
+		"Headphone Jack", "HPOUTR",
+		"IN2L", "Line In Jack",
+		"IN2R", "Line In Jack",
+		"Mic", "MICBIAS",
+		"IN1L", "Mic";
+
+	atmel,ssc-controller = <&ssc0>;
+	atmel,audio-codec = <&wm8904>;
+};
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
new file mode 100644
index 0000000..f2ae335
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -0,0 +1,54 @@
+Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Freescale S/PDIF audio block is a stereo transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+  - compatible : Compatible list, must contain "fsl,imx35-spdif".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : Contains the spdif interrupt.
+
+  - dmas : Generic dma devicetree binding as described in
+  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+	"core"		The core clock of spdif controller
+	"rxtx<0-7>"	Clock source list for tx and rx clock.
+			This clock list should be identical to
+			the source list connecting to the spdif
+			clock mux in "SPDIF Transceiver Clock
+			Diagram" of SoC reference manual. It
+			can also be referred to TxClk_Source
+			bit of register SPDIF_STC.
+
+Example:
+
+spdif: spdif@02004000 {
+	compatible = "fsl,imx35-spdif";
+	reg = <0x02004000 0x4000>;
+	interrupts = <0 52 0x04>;
+	dmas = <&sdma 14 18 0>,
+	       <&sdma 15 18 0>;
+	dma-names = "rx", "tx";
+
+	clocks = <&clks 197>, <&clks 3>,
+	       <&clks 197>, <&clks 107>,
+	       <&clks 0>, <&clks 118>,
+	       <&clks 62>, <&clks 139>,
+	       <&clks 0>;
+	clock-names = "core", "rxtx0",
+		"rxtx1", "rxtx2",
+		"rxtx3", "rxtx4",
+		"rxtx5", "rxtx6",
+		"rxtx7";
+
+	status = "okay";
+};
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt b/Documentation/devicetree/bindings/sound/fsl,ssi.txt
similarity index 87%
rename from Documentation/devicetree/bindings/powerpc/fsl/ssi.txt
rename to Documentation/devicetree/bindings/sound/fsl,ssi.txt
index 5ff76c9..4303b6a 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/ssi.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,ssi.txt
@@ -43,10 +43,22 @@
                     together.  This would still allow different sample sizes,
                     but not different sample rates.
 
+Required are also ac97 link bindings if ac97 is used. See
+Documentation/devicetree/bindings/sound/soc-ac97link.txt for the necessary
+bindings.
+
 Optional properties:
 - codec-handle:     Phandle to a 'codec' node that defines an audio
                     codec connected to this SSI.  This node is typically
                     a child of an I2C or other control node.
+- fsl,fiq-stream-filter: Bool property. Disabled DMA and use FIQ instead to
+		    filter the codec stream. This is necessary for some boards
+		    where an incompatible codec is connected to this SSI, e.g.
+		    on pca100 and pcm043.
+- dmas:		    Generic dma devicetree binding as described in
+		    Documentation/devicetree/bindings/dma/dma.txt.
+- dma-names:	    Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
+		    is not defined.
 
 Child 'codec' node required properties:
 - compatible:       Compatible list, contains the name of the codec
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
new file mode 100644
index 0000000..7d13479
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
@@ -0,0 +1,34 @@
+Freescale i.MX audio complex with S/PDIF transceiver
+
+Required properties:
+
+  - compatible : "fsl,imx-audio-spdif"
+
+  - model : The user-visible name of this sound complex
+
+  - spdif-controller : The phandle of the i.MX S/PDIF controller
+
+
+Optional properties:
+
+  - spdif-out : This is a boolean property. If present, the transmitting
+    function of S/PDIF will be enabled, indicating there's a physical
+    S/PDIF out connector/jack on the board or it's connecting to some
+    other IP block, such as an HDMI encoder/display-controller.
+
+  - spdif-in : This is a boolean property. If present, the receiving
+    function of S/PDIF will be enabled, indicating there's a physical
+    S/PDIF in connector/jack on the board.
+
+* Note: At least one of these two properties should be set in the DT binding.
+
+
+Example:
+
+sound-spdif {
+	compatible = "fsl,imx-audio-spdif";
+	model = "imx-spdif";
+	spdif-controller = <&spdif>;
+	spdif-out;
+	spdif-in;
+};
diff --git a/Documentation/devicetree/bindings/sound/imx-audmux.txt b/Documentation/devicetree/bindings/sound/imx-audmux.txt
index 215aa98..f88a00e 100644
--- a/Documentation/devicetree/bindings/sound/imx-audmux.txt
+++ b/Documentation/devicetree/bindings/sound/imx-audmux.txt
@@ -5,6 +5,15 @@
   or "fsl,imx31-audmux" for the version firstly used on i.MX31.
 - reg : Should contain AUDMUX registers location and length
 
+An initial configuration can be setup using child nodes.
+
+Required properties of optional child nodes:
+- fsl,audmux-port : Integer of the audmux port that is configured by this
+  child node.
+- fsl,port-config : List of configuration options for the specific port. For
+  imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For
+  imx21-audmux it is a list of pcr values.
+
 Example:
 
 audmux@021d8000 {
diff --git a/Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt b/Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt
new file mode 100644
index 0000000..74c9ba6
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt
@@ -0,0 +1,28 @@
+Marvell PXA SSP CPU DAI bindings
+
+Required properties:
+
+	compatible	Must be "mrvl,pxa-ssp-dai"
+	port		A phandle reference to a PXA ssp upstream device
+
+Example:
+
+	/* upstream device */
+
+	ssp0: ssp@41000000 {
+		compatible = "mrvl,pxa3xx-ssp";
+		reg = <0x41000000 0x40>;
+		interrupts = <24>;
+		clock-names = "pxa27x-ssp.0";
+		dmas = <&dma 13
+			&dma 14>;
+		dma-names = "rx", "tx";
+	};
+
+	/* DAI as user */
+
+	ssp_dai0: ssp_dai@0 {
+		compatible = "mrvl,pxa-ssp-dai";
+		port = <&ssp0>;
+	};
+
diff --git a/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt b/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt
new file mode 100644
index 0000000..551fbb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt
@@ -0,0 +1,15 @@
+DT bindings for ARM PXA2xx PCM platform driver
+
+This is just a dummy driver that registers the PXA ASoC platform driver.
+It does not have any resources assigned.
+
+Required properties:
+
+	- compatible		'mrvl,pxa-pcm-audio'
+
+Example:
+
+	pxa_pcm_audio: snd_soc_pxa_audio {
+		compatible = "mrvl,pxa-pcm-audio";
+	};
+
diff --git a/Documentation/devicetree/bindings/sound/mvebu-audio.txt b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
new file mode 100644
index 0000000..7e5fd37
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mvebu-audio.txt
@@ -0,0 +1,29 @@
+* mvebu (Kirkwood, Dove, Armada 370) audio controller
+
+Required properties:
+
+- compatible: "marvell,mvebu-audio"
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- interrupts: list of two irq numbers.
+  The first irq is used for data flow and the second one is used for errors.
+
+- clocks: one or two phandles.
+  The first one is mandatory and defines the internal clock.
+  The second one is optional and defines an external clock.
+
+- clock-names: names associated to the clocks:
+	"internal" for the internal clock
+	"extclk" for the external clock
+
+Example:
+
+i2s1: audio-controller@b4000 {
+	compatible = "marvell,mvebu-audio";
+	reg = <0xb4000 0x2210>;
+	interrupts = <21>, <22>;
+	clocks = <&gate_clk 13>;
+	clock-names = "internal";
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
index 05ffecb..8b8903e 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
@@ -11,28 +11,8 @@
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the ALC5632's pins:
-
-  ALC5632 pins:
-
-  * SPK_OUTP
-  * SPK_OUTN
-  * HP_OUT_L
-  * HP_OUT_R
-  * AUX_OUT_P
-  * AUX_OUT_N
-  * LINE_IN_L
-  * LINE_IN_R
-  * PHONE_P
-  * PHONE_N
-  * MIC1_P
-  * MIC1_N
-  * MIC2_P
-  * MIC2_N
-  * MICBIAS1
-  * DMICDAT
-
-  Board connectors:
+  sinks are the ALC5632's pins as documented in the binding for the device
+  and:
 
   * Headset Stereophone
   * Int Spk
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
index d130818..dc62249 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
@@ -11,32 +11,12 @@
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the RT5640's pins, and the jacks on the board:
-
-  RT5640 pins:
-
-  * DMIC1
-  * DMIC2
-  * MICBIAS1
-  * IN1P
-  * IN1R
-  * IN2P
-  * IN2R
-  * HPOL
-  * HPOR
-  * LOUTL
-  * LOUTR
-  * MONOP
-  * MONON
-  * SPOLP
-  * SPOLN
-  * SPORP
-  * SPORN
-
-  Board connectors:
+  sinks are the RT5640's pins (as documented in its binding), and the jacks
+  on the board:
 
   * Headphones
   * Speakers
+  * Mic Jack
 
 - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
   connected to the CODEC.
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt
index d145106..aab6ce0 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt
@@ -11,31 +11,8 @@
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the WM8753's pins, and the jacks on the board:
-
-  WM8753 pins:
-
-  * LOUT1
-  * LOUT2
-  * ROUT1
-  * ROUT2
-  * MONO1
-  * MONO2
-  * OUT3
-  * OUT4
-  * LINE1
-  * LINE2
-  * RXP
-  * RXN
-  * ACIN
-  * ACOP
-  * MIC1N
-  * MIC1
-  * MIC2N
-  * MIC2
-  * Mic Bias
-
-  Board connectors:
+  sinks are the WM8753's pins as documented in the binding for the WM8753,
+  and the jacks on the board:
 
   * Headphone Jack
   * Mic Jack
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
index 3bf722d..4b44dfb 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
@@ -11,28 +11,8 @@
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the WM8903's pins, and the jacks on the board:
-
-  WM8903 pins:
-
-  * IN1L
-  * IN1R
-  * IN2L
-  * IN2R
-  * IN3L
-  * IN3R
-  * DMICDAT
-  * HPOUTL
-  * HPOUTR
-  * LINEOUTL
-  * LINEOUTR
-  * LOP
-  * LON
-  * ROP
-  * RON
-  * MICBIAS
-
-  Board connectors:
+  sinks are the WM8903's pins (documented in the WM8903 binding document),
+  and the jacks on the board:
 
   * Headphone Jack
   * Int Spk
diff --git a/Documentation/devicetree/bindings/sound/pcm1792a.txt b/Documentation/devicetree/bindings/sound/pcm1792a.txt
new file mode 100644
index 0000000..970ba1e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/pcm1792a.txt
@@ -0,0 +1,18 @@
+Texas Instruments pcm1792a DT bindings
+
+This driver supports the SPI bus.
+
+Required properties:
+
+ - compatible: "ti,pcm1792a"
+
+For required properties on SPI, please consult
+Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Examples:
+
+	codec_spi: 1792a@0 {
+		compatible = "ti,pcm1792a";
+		spi-max-frequency = <600000>;
+	};
+
diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt
index 005bcb2..068a114 100644
--- a/Documentation/devicetree/bindings/sound/rt5640.txt
+++ b/Documentation/devicetree/bindings/sound/rt5640.txt
@@ -18,6 +18,26 @@
 
 - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
 
+Pins on the device (for linking into audio routes):
+
+  * DMIC1
+  * DMIC2
+  * MICBIAS1
+  * IN1P
+  * IN1R
+  * IN2P
+  * IN2R
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * MONOP
+  * MONON
+  * SPOLP
+  * SPOLN
+  * SPORP
+  * SPORN
+
 Example:
 
 rt5640 {
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
index 025e66b..7386d44 100644
--- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
@@ -2,7 +2,15 @@
 
 Required SoC Specific Properties:
 
-- compatible : "samsung,i2s-v5"
+- compatible : should be one of the following.
+   - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
+   - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
+     secondary fifo, s/w reset control and internal mux for root clk src.
+   - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
+     secondary fifo, s/w reset control, internal mux for root clk src and
+     TDM support. TDM (Time division multiplexing) is to allow transfer of
+     multiple channel audio data on single data line.
+
 - reg: physical base address of the controller and length of memory mapped
   region.
 - dmas: list of DMA controller phandle and DMA request line ordered pairs.
@@ -21,13 +29,6 @@
 
 Optional SoC Specific Properties:
 
-- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel
-  support, this flag is enabled.
-- samsung,supports-rstclr: This flag should be set if I2S software reset bit
-  control is required. When this flag is set I2S software reset bit will be
-  enabled or disabled based on need.
-- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA,
-  then this flag is enabled.
 - samsung,idma-addr: Internal DMA register base address of the audio
   sub system(used in secondary sound source).
 - pinctrl-0: Should specify pin control groups used for this controller.
@@ -36,7 +37,7 @@
 Example:
 
 i2s0: i2s@03830000 {
-	compatible = "samsung,i2s-v5";
+	compatible = "samsung,s5pv210-i2s";
 	reg = <0x03830000 0x100>;
 	dmas = <&pdma0 10
 		&pdma0 9
@@ -46,9 +47,6 @@
 		<&clock_audss EXYNOS_I2S_BUS>,
 		<&clock_audss EXYNOS_SCLK_I2S>;
 	clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
-	samsung,supports-6ch;
-	samsung,supports-rstclr;
-	samsung,supports-secdai;
 	samsung,idma-addr = <0x03000000>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&i2s0_bus>;
diff --git a/Documentation/devicetree/bindings/sound/soc-ac97link.txt b/Documentation/devicetree/bindings/sound/soc-ac97link.txt
new file mode 100644
index 0000000..80152a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/soc-ac97link.txt
@@ -0,0 +1,28 @@
+AC97 link bindings
+
+These bindings can be included within any other device node.
+
+Required properties:
+ - pinctrl-names: Has to contain following states to setup the correct
+   pinmuxing for the used gpios:
+	"ac97-running": AC97-link is active
+	"ac97-reset": AC97-link reset state
+	"ac97-warm-reset": AC97-link warm reset state
+ - ac97-gpios: List of gpio phandles with args in the order ac97-sync,
+   ac97-sdata, ac97-reset
+
+
+Example:
+
+ssi {
+	...
+
+	pinctrl-names = "default", "ac97-running", "ac97-reset", "ac97-warm-reset";
+	pinctrl-0 = <&ac97link_running>;
+	pinctrl-1 = <&ac97link_running>;
+	pinctrl-2 = <&ac97link_reset>;
+	pinctrl-3 = <&ac97link_warm_reset>;
+	ac97-gpios = <&gpio3 20 0 &gpio3 22 0 &gpio3 28 0>;
+
+	...
+};
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm1681.txt b/Documentation/devicetree/bindings/sound/ti,pcm1681.txt
new file mode 100644
index 0000000..4df1718
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,pcm1681.txt
@@ -0,0 +1,15 @@
+Texas Instruments PCM1681 8-channel PWM Processor
+
+Required properties:
+
+ - compatible:		Should contain "ti,pcm1681".
+ - reg:			The i2c address. Should contain <0x4c>.
+
+Examples:
+
+	i2c_bus {
+		pcm1681@4c {
+			compatible = "ti,pcm1681";
+			reg = <0x4c>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
index f47c3f5..705a6b1 100644
--- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
+++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
@@ -3,7 +3,14 @@
 The tlv320aic3x serial control bus communicates through I2C protocols
 
 Required properties:
-- compatible - "string" -  "ti,tlv320aic3x"
+
+- compatible - "string" - One of:
+    "ti,tlv320aic3x" - Generic TLV320AIC3x device
+    "ti,tlv320aic33" - TLV320AIC33
+    "ti,tlv320aic3007" - TLV320AIC3007
+    "ti,tlv320aic3106" - TLV320AIC3106
+
+
 - reg - <int> -  I2C slave address
 
 
diff --git a/Documentation/devicetree/bindings/sound/wm8731.txt b/Documentation/devicetree/bindings/sound/wm8731.txt
index 15f7004..236690e 100644
--- a/Documentation/devicetree/bindings/sound/wm8731.txt
+++ b/Documentation/devicetree/bindings/sound/wm8731.txt
@@ -16,3 +16,12 @@
 	compatible = "wlf,wm8731";
 	reg = <0x1a>;
 };
+
+Available audio endpoints for an audio-routing table:
+ * LOUT: Left Channel Line Output
+ * ROUT: Right Channel Line Output
+ * LHPOUT: Left Channel Headphone Output
+ * RHPOUT: Right Channel Headphone Output
+ * LLINEIN: Left Channel Line Input
+ * RLINEIN: Right Channel Line Input
+ * MICIN: Microphone Input
diff --git a/Documentation/devicetree/bindings/sound/wm8753.txt b/Documentation/devicetree/bindings/sound/wm8753.txt
index e65277a..8eee612 100644
--- a/Documentation/devicetree/bindings/sound/wm8753.txt
+++ b/Documentation/devicetree/bindings/sound/wm8753.txt
@@ -10,9 +10,31 @@
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
 
+Pins on the device (for linking into audio routes):
+
+  * LOUT1
+  * LOUT2
+  * ROUT1
+  * ROUT2
+  * MONO1
+  * MONO2
+  * OUT3
+  * OUT4
+  * LINE1
+  * LINE2
+  * RXP
+  * RXN
+  * ACIN
+  * ACOP
+  * MIC1N
+  * MIC1
+  * MIC2N
+  * MIC2
+  * Mic Bias
+
 Example:
 
-codec: wm8737@1a {
+codec: wm8753@1a {
 	compatible = "wlf,wm8753";
 	reg = <0x1a>;
 };
diff --git a/Documentation/devicetree/bindings/sound/wm8903.txt b/Documentation/devicetree/bindings/sound/wm8903.txt
index f102cbc..94ec32c 100644
--- a/Documentation/devicetree/bindings/sound/wm8903.txt
+++ b/Documentation/devicetree/bindings/sound/wm8903.txt
@@ -28,6 +28,25 @@
     performed. If any entry has the value 0xffffffff, that GPIO's
     configuration will not be modified.
 
+Pins on the device (for linking into audio routes):
+
+  * IN1L
+  * IN1R
+  * IN2L
+  * IN2R
+  * IN3L
+  * IN3R
+  * DMICDAT
+  * HPOUTL
+  * HPOUTR
+  * LINEOUTL
+  * LINEOUTR
+  * LOP
+  * LON
+  * ROP
+  * RON
+  * MICBIAS
+
 Example:
 
 codec: wm8903@1a {
diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt
index f2f3e80..e045e90 100644
--- a/Documentation/devicetree/bindings/sound/wm8994.txt
+++ b/Documentation/devicetree/bindings/sound/wm8994.txt
@@ -32,6 +32,10 @@
     The second cell is the flags, encoded as the trigger masks from
     Documentation/devicetree/bindings/interrupts.txt
 
+  - clocks : A list of up to two phandle and clock specifier pairs
+  - clock-names : A list of clock names sorted in the same order as clocks.
+                  Valid clock names are "MCLK1" and "MCLK2".
+
   - wlf,gpio-cfg : A list of GPIO configuration register values. If absent,
     no configuration of these registers is performed. If any value is
     over 0xffff then the register will be left as default. If present 11
diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt
new file mode 100644
index 0000000..a590ca5
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/efm32-spi.txt
@@ -0,0 +1,34 @@
+* Energy Micro EFM32 SPI
+
+Required properties:
+- #address-cells: see spi-bus.txt
+- #size-cells: see spi-bus.txt
+- compatible: should be "efm32,spi"
+- reg: Offset and length of the register set for the controller
+- interrupts: pair specifying rx and tx irq
+- clocks: phandle to the spi clock
+- cs-gpios: see spi-bus.txt
+- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
+
+Example:
+
+spi1: spi@0x4000c400 { /* USART1 */
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "efm32,spi";
+	reg = <0x4000c400 0x400>;
+	interrupts = <15 16>;
+	clocks = <&cmu 20>;
+	cs-gpios = <&gpio 51 1>; // D3
+	location = <1>;
+	status = "ok";
+
+	ks8851@0 {
+		compatible = "ks8851";
+		spi-max-frequency = <6000000>;
+		reg = <0>;
+		interrupt-parent = <&boardfpga>;
+		interrupts = <4>;
+		status = "ok";
+	};
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index 296015e..800dafe 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -55,6 +55,16 @@
     		chip select active high
 - spi-3wire       - (optional) Empty property indicating device requires
     		    3-wire mode.
+- spi-tx-bus-width - (optional) The bus width(number of data wires) that
+                      used for MOSI. Defaults to 1 if not present.
+- spi-rx-bus-width - (optional) The bus width(number of data wires) that
+                      used for MISO. Defaults to 1 if not present.
+
+Some SPI controllers and devices support Dual and Quad SPI transfer mode.
+It allows data in SPI system transfered in 2 wires(DUAL) or 4 wires(QUAD).
+Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is
+only 1(SINGLE), 2(DUAL) and 4(QUAD).
+Dual/Quad mode is not allowed when 3-wire mode is used.
 
 If a gpio chipselect is used for the SPI slave the gpio number will be passed
 via the cs_gpio
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
new file mode 100644
index 0000000..a1fb303
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
@@ -0,0 +1,42 @@
+ARM Freescale DSPI controller
+
+Required properties:
+- compatible : "fsl,vf610-dspi"
+- reg : Offset and length of the register set for the device
+- interrupts : Should contain SPI controller interrupt
+- clocks: from common clock binding: handle to dspi clock.
+- clock-names: from common clock binding: Shall be "dspi".
+- pinctrl-0: pin control group to be used for this controller.
+- pinctrl-names: must contain a "default" entry.
+- spi-num-chipselects : the number of the chipselect signals.
+- bus-num : the slave chip chipselect signal number.
+Example:
+
+dspi0@4002c000 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	compatible = "fsl,vf610-dspi";
+	reg = <0x4002c000 0x1000>;
+	interrupts = <0 67 0x04>;
+	clocks = <&clks VF610_CLK_DSPI0>;
+	clock-names = "dspi";
+	spi-num-chipselects = <5>;
+	bus-num = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_dspi0_1>;
+	status = "okay";
+
+	sflash: at26df081a@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "atmel,at26df081a";
+		spi-max-frequency = <16000000>;
+		spi-cpol;
+		spi-cpha;
+		reg = <0>;
+		linux,modalias = "m25p80";
+		modal = "at26df081a";
+	};
+};
+
+
diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt
new file mode 100644
index 0000000..1f9641a
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt
@@ -0,0 +1,22 @@
+TI QSPI controller.
+
+Required properties:
+- compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi".
+- reg: Should contain QSPI registers location and length.
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+- ti,hwmods: Name of the hwmod associated to the QSPI
+
+Recommended properties:
+- spi-max-frequency: Definition as per
+                     Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+qspi: qspi@4b300000 {
+	compatible = "ti,dra7xxx-qspi";
+	reg = <0x4b300000 0x100>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	spi-max-frequency = <25000000>;
+	ti,hwmods = "qspi";
+};
diff --git a/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt b/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt
new file mode 100644
index 0000000..da2d510
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/moxa,moxart-timer.txt
@@ -0,0 +1,17 @@
+MOXA ART timer
+
+Required properties:
+
+- compatible : Must be "moxa,moxart-timer"
+- reg : Should contain registers location and length
+- interrupts : Should contain the timer interrupt number
+- clocks : Should contain phandle for the clock that drives the counter
+
+Example:
+
+	timer: timer@98400000 {
+		compatible = "moxa,moxart-timer";
+		reg = <0x98400000 0x42>;
+		interrupts = <19 1>;
+		clocks = <&coreclk>;
+	};
diff --git a/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt b/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
deleted file mode 100644
index a49d9a1..0000000
--- a/Documentation/devicetree/bindings/tty/serial/atmel-usart.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
-
-Required properties:
-- compatible: Should be "atmel,<chip>-usart"
-  The compatible <chip> indicated will be the first SoC to support an
-  additional mode or an USART new feature.
-- reg: Should contain registers location and length
-- interrupts: Should contain interrupt
-
-Optional properties:
-- atmel,use-dma-rx: use of PDC or DMA for receiving data
-- atmel,use-dma-tx: use of PDC or DMA for transmitting data
-
-<chip> compatible description:
-- at91rm9200:  legacy USART support
-- at91sam9260: generic USART implementation for SAM9 SoCs
-
-Example:
-
-	usart0: serial@fff8c000 {
-		compatible = "atmel,at91sam9260-usart";
-		reg = <0xfff8c000 0x4000>;
-		interrupts = <7>;
-		atmel,use-dma-rx;
-		atmel,use-dma-tx;
-	};
-
diff --git a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt b/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
deleted file mode 100644
index c662eb3..0000000
--- a/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-* Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
-
-Required properties:
-- compatible : Should be "fsl,<soc>-uart"
-- reg : Address and length of the register set for the device
-- interrupts : Should contain uart interrupt
-
-Optional properties:
-- fsl,uart-has-rtscts : Indicate the uart has rts and cts
-- fsl,irda-mode : Indicate the uart supports irda mode
-- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
-                  is DCE mode by default.
-
-Example:
-
-serial@73fbc000 {
-	compatible = "fsl,imx51-uart", "fsl,imx21-uart";
-	reg = <0x73fbc000 0x4000>;
-	interrupts = <31>;
-	fsl,uart-has-rtscts;
-	fsl,dte-mode;
-};
diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
deleted file mode 100644
index aef383e..0000000
--- a/Documentation/devicetree/bindings/tty/serial/msm_serial.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* Qualcomm MSM UART
-
-Required properties:
-- compatible :
-	- "qcom,msm-uart", and one of "qcom,msm-hsuart" or
-	  "qcom,msm-lsuart".
-- reg : offset and length of the register set for the device
-	for the hsuart operating in compatible mode, there should be a
-	second pair describing the gsbi registers.
-- interrupts : should contain the uart interrupt.
-
-There are two different UART blocks used in MSM devices,
-"qcom,msm-hsuart" and "qcom,msm-lsuart".  The msm-serial driver is
-able to handle both of these, and matches against the "qcom,msm-uart"
-as the compatibility.
-
-The registers for the "qcom,msm-hsuart" device need to specify both
-register blocks, even for the common driver.
-
-Example:
-
-	uart@19c400000 {
-		compatible = "qcom,msm-hsuart", "qcom,msm-uart";
-		reg = <0x19c40000 0x1000>,
-		      <0x19c00000 0x1000>;
-		interrupts = <195>;
-	};
diff --git a/Documentation/devicetree/bindings/tty/serial/qca,ar9330-uart.txt b/Documentation/devicetree/bindings/tty/serial/qca,ar9330-uart.txt
new file mode 100644
index 0000000..c5e032c
--- /dev/null
+++ b/Documentation/devicetree/bindings/tty/serial/qca,ar9330-uart.txt
@@ -0,0 +1,34 @@
+* Qualcomm Atheros AR9330 High-Speed UART
+
+Required properties:
+
+- compatible: Must be "qca,ar9330-uart"
+
+- reg: Specifies the physical base address of the controller and
+  the length of the memory mapped region.
+
+- interrupt-parent: The phandle for the interrupt controller that
+  services interrupts for this device.
+
+- interrupts: Specifies the interrupt source of the parent interrupt
+  controller. The format of the interrupt specifier depends on the
+  parent interrupt controller.
+
+Additional requirements:
+
+  Each UART port must have an alias correctly numbered in "aliases"
+  node.
+
+Example:
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	uart0: uart@18020000 {
+		compatible = "qca,ar9330-uart";
+		reg = <0x18020000 0x14>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <3>;
+	};
diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt
index dc9dc8c..20c2ff2 100644
--- a/Documentation/devicetree/bindings/usb/am33xx-usb.txt
+++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt
@@ -1,35 +1,197 @@
-AM33XX MUSB GLUE
- - compatible : Should be "ti,musb-am33xx"
- - reg : offset and length of register sets, first usbss, then for musb instances
- - interrupts : usbss, musb instance interrupts in order
- - ti,hwmods : must be "usb_otg_hs"
- - multipoint : Should be "1" indicating the musb controller supports
-   multipoint. This is a MUSB configuration-specific setting.
- - num-eps : Specifies the number of endpoints. This is also a
-   MUSB configuration-specific setting. Should be set to "16"
- - ram-bits : Specifies the ram address size. Should be set to "12"
- - port0-mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
-   represents PERIPHERAL.
- - port1-mode : Should be "1" to represent HOST. "3" signifies OTG and "2"
-   represents PERIPHERAL.
- - power : Should be "250". This signifies the controller can supply up to
-   500mA when operating in host mode.
+  AM33xx MUSB
+~~~~~~~~~~~~~~~
+- compatible: ti,am33xx-usb
+- reg: offset and length of the usbss register sets
+- ti,hwmods : must be "usb_otg_hs"
+
+The glue layer contains multiple child nodes. It is required the have
+at least a control module node, USB node and a PHY node. The second USB
+node and its PHY node is optional. The DMA node is also optional.
+
+Reset module
+~~~~~~~~~~~~
+- compatible: ti,am335x-usb-ctrl-module
+- reg: offset and length of the "USB control registers" in the "Control
+  Module" block. A second offset and length for the USB wake up control
+  in the same memory block.
+- reg-names: "phy_ctrl" for the "USB control registers" and "wakeup" for
+  the USB wake up control register.
+
+USB PHY
+~~~~~~~
+compatible: ti,am335x-usb-phy
+reg: offset and length of the "USB PHY" register space
+ti,ctrl_mod: reference to the "reset module" node
+reg-names: phy
+The PHY should have a "phy" alias numbered properly in the alias
+node.
+
+USB
+~~~
+- compatible: ti,musb-am33xx
+- reg: offset and length of "USB Controller Registers", and offset and
+  length of "USB Core" register space.
+- reg-names: control for the ""USB Controller Registers" and "mc" for
+  "USB Core" register space
+- interrupts: USB interrupt number
+- interrupt-names: mc
+- dr_mode: Should be one of "host", "peripheral" or "otg".
+- mentor,multipoint: Should be "1" indicating the musb controller supports
+  multipoint. This is a MUSB configuration-specific setting.
+- mentor,num-eps: Specifies the number of endpoints. This is also a
+  MUSB configuration-specific setting. Should be set to "16"
+- mentor,ram-bits: Specifies the ram address size. Should be set to "12"
+- mentor,power: Should be "500". This signifies the controller can supply up to
+  500mA when operating in host mode.
+- phys: reference to the USB phy
+- dmas: specifies the dma channels
+- dma-names: specifies the names of the channels. Use "rxN" for receive
+  and "txN" for transmit endpoints. N specifies the endpoint number.
+
+The controller should have an "usb" alias numbered properly in the alias
+node.
+
+DMA
+~~~
+- compatible: ti,am3359-cppi41
+- reg: offset and length of the following register spaces: USBSS, USB
+  CPPI DMA Controller, USB CPPI DMA Scheduler, USB Queue Manager
+- reg-names: glue, controller, scheduler, queuemgr
+- #dma-cells: should be set to 2. The first number represents the
+  endpoint number (0 … 14 for endpoints 1 … 15 on instance 0 and 15 … 29
+  for endpoints 1 … 15 on instance 1). The second number is 0 for RX and
+  1 for TX transfers.
+- #dma-channels: should be set to 30 representing the 15 endpoints for
+  each USB instance.
 
 Example:
+~~~~~~~~
+The following example contains all the nodes as used on am335x-evm:
 
-usb@47400000  {
-	compatible = "ti,musb-am33xx";
-	reg = <0x47400000 0x1000	/* usbss */
-	       0x47401000 0x800		/* musb instance 0 */
-	       0x47401800 0x800>;	/* musb instance 1 */
-	interrupts = <17		/* usbss */
-		      18		/* musb instance 0 */
-		      19>;		/* musb instance 1 */
-	multipoint = <1>;
-	num-eps = <16>;
-	ram-bits = <12>;
-	port0-mode = <3>;
-	port1-mode = <3>;
-	power = <250>;
+aliases {
+	usb0 = &usb0;
+	usb1 = &usb1;
+	phy0 = &usb0_phy;
+	phy1 = &usb1_phy;
+};
+
+usb: usb@47400000 {
+	compatible = "ti,am33xx-usb";
+	reg = <0x47400000 0x1000>;
+	ranges;
+	#address-cells = <1>;
+	#size-cells = <1>;
 	ti,hwmods = "usb_otg_hs";
+
+	ctrl_mod: control@44e10000 {
+		compatible = "ti,am335x-usb-ctrl-module";
+		reg = <0x44e10620 0x10
+			0x44e10648 0x4>;
+		reg-names = "phy_ctrl", "wakeup";
+	};
+
+	usb0_phy: usb-phy@47401300 {
+		compatible = "ti,am335x-usb-phy";
+		reg = <0x47401300 0x100>;
+		reg-names = "phy";
+		ti,ctrl_mod = <&ctrl_mod>;
+	};
+
+	usb0: usb@47401000 {
+		compatible = "ti,musb-am33xx";
+		reg = <0x47401400 0x400
+			0x47401000 0x200>;
+		reg-names = "mc", "control";
+
+		interrupts = <18>;
+		interrupt-names = "mc";
+		dr_mode = "otg"
+		mentor,multipoint = <1>;
+		mentor,num-eps = <16>;
+		mentor,ram-bits = <12>;
+		mentor,power = <500>;
+		phys = <&usb0_phy>;
+
+		dmas = <&cppi41dma  0 0 &cppi41dma  1 0
+			&cppi41dma  2 0 &cppi41dma  3 0
+			&cppi41dma  4 0 &cppi41dma  5 0
+			&cppi41dma  6 0 &cppi41dma  7 0
+			&cppi41dma  8 0 &cppi41dma  9 0
+			&cppi41dma 10 0 &cppi41dma 11 0
+			&cppi41dma 12 0 &cppi41dma 13 0
+			&cppi41dma 14 0 &cppi41dma  0 1
+			&cppi41dma  1 1 &cppi41dma  2 1
+			&cppi41dma  3 1 &cppi41dma  4 1
+			&cppi41dma  5 1 &cppi41dma  6 1
+			&cppi41dma  7 1 &cppi41dma  8 1
+			&cppi41dma  9 1 &cppi41dma 10 1
+			&cppi41dma 11 1 &cppi41dma 12 1
+			&cppi41dma 13 1 &cppi41dma 14 1>;
+		dma-names =
+			"rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+			"rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+			"rx14", "rx15",
+			"tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+			"tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+			"tx14", "tx15";
+	};
+
+	usb1_phy: usb-phy@47401b00 {
+		compatible = "ti,am335x-usb-phy";
+		reg = <0x47401b00 0x100>;
+		reg-names = "phy";
+		ti,ctrl_mod = <&ctrl_mod>;
+	};
+
+	usb1: usb@47401800 {
+		compatible = "ti,musb-am33xx";
+		reg = <0x47401c00 0x400
+			0x47401800 0x200>;
+		reg-names = "mc", "control";
+		interrupts = <19>;
+		interrupt-names = "mc";
+		dr_mode = "host"
+		mentor,multipoint = <1>;
+		mentor,num-eps = <16>;
+		mentor,ram-bits = <12>;
+		mentor,power = <500>;
+		phys = <&usb1_phy>;
+
+		dmas = <&cppi41dma 15 0 &cppi41dma 16 0
+			&cppi41dma 17 0 &cppi41dma 18 0
+			&cppi41dma 19 0 &cppi41dma 20 0
+			&cppi41dma 21 0 &cppi41dma 22 0
+			&cppi41dma 23 0 &cppi41dma 24 0
+			&cppi41dma 25 0 &cppi41dma 26 0
+			&cppi41dma 27 0 &cppi41dma 28 0
+			&cppi41dma 29 0 &cppi41dma 15 1
+			&cppi41dma 16 1 &cppi41dma 17 1
+			&cppi41dma 18 1 &cppi41dma 19 1
+			&cppi41dma 20 1 &cppi41dma 21 1
+			&cppi41dma 22 1 &cppi41dma 23 1
+			&cppi41dma 24 1 &cppi41dma 25 1
+			&cppi41dma 26 1 &cppi41dma 27 1
+			&cppi41dma 28 1 &cppi41dma 29 1>;
+		dma-names =
+			"rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+			"rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+			"rx14", "rx15",
+			"tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+			"tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+			"tx14", "tx15";
+	};
+
+	cppi41dma: dma-controller@07402000 {
+		compatible = "ti,am3359-cppi41";
+		reg =  <0x47400000 0x1000
+			0x47402000 0x1000
+			0x47403000 0x1000
+			0x47404000 0x4000>;
+		reg-names = "glue", "controller", "scheduler", "queuemgr";
+		interrupts = <17>;
+		interrupt-names = "glue";
+		#dma-cells = <2>;
+		#dma-channels = <30>;
+		#dma-requests = <256>;
+	};
 };
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 7a95c65..e807635 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -3,10 +3,12 @@
 DWC3- USB3 CONTROLLER
 
 Required properties:
- - compatible: must be "synopsys,dwc3"
+ - compatible: must be "snps,dwc3"
  - reg : Address and length of the register set for the device
  - interrupts: Interrupts used by the dwc3 controller.
- - usb-phy : array of phandle for the PHY device
+ - usb-phy : array of phandle for the PHY device.  The first element
+   in the array is expected to be a handle to the USB2/HS PHY and
+   the second element is expected to be a handle to the USB3/SS PHY
 
 Optional properties:
  - tx-fifo-resize: determines if the FIFO *has* to be reallocated.
@@ -14,7 +16,7 @@
 This is usually a subnode to DWC3 glue to which it is connected.
 
 dwc3@4a030000 {
-	compatible = "synopsys,dwc3";
+	compatible = "snps,dwc3";
 	reg = <0x4a030000 0xcfff>;
 	interrupts = <0 92 4>
 	usb-phy = <&usb2_phy>, <&usb3,phy>;
diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt
new file mode 100644
index 0000000..477d5bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/generic.txt
@@ -0,0 +1,24 @@
+Generic USB Properties
+
+Optional properties:
+ - maximum-speed: tells USB controllers we want to work up to a certain
+			speed. Valid arguments are "super-speed", "high-speed",
+			"full-speed" and "low-speed". In case this isn't passed
+			via DT, USB controllers should default to their maximum
+			HW capability.
+ - dr_mode: tells Dual-Role USB controllers that we want to work on a
+			particular mode. Valid arguments are "host",
+			"peripheral" and "otg". In case this attribute isn't
+			passed via DT, USB DRD controllers should default to
+			OTG.
+
+This is an attribute to a USB controller such as:
+
+dwc3@4a030000 {
+	compatible = "synopsys,dwc3";
+	reg = <0x4a030000 0xcfff>;
+	interrupts = <0 92 4>
+	usb-phy = <&usb2_phy>, <&usb3,phy>;
+	maximum-speed = "super-speed";
+	dr_mode = "otg";
+};
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
index c4c9e9e..ba797d3 100644
--- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-usb-phy.txt
@@ -3,7 +3,7 @@
 The device node for Tegra SOC USB PHY:
 
 Required properties :
- - compatible : Should be "nvidia,tegra20-usb-phy".
+ - compatible : Should be "nvidia,tegra<chip>-usb-phy".
  - reg : Defines the following set of registers, in the order listed:
    - The PHY's own register set.
      Always present.
@@ -24,17 +24,26 @@
 Required properties for phy_type == ulpi:
   - nvidia,phy-reset-gpio : The GPIO used to reset the PHY.
 
-Required PHY timing params for utmi phy:
+Required PHY timing params for utmi phy, for all chips:
   - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before
     start of sync launches RxActive
   - nvidia,elastic-limit : Variable FIFO Depth of elastic input store
   - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait
     before declare IDLE.
   - nvidia,term-range-adj : Range adjusment on terminations
-  - nvidia,xcvr-setup : HS driver output control
+  - Either one of the following for HS driver output control:
+    - nvidia,xcvr-setup : integer, uses the provided value.
+    - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read
+      from the on-chip fuses
+    If both are provided, nvidia,xcvr-setup-use-fuses takes precedence.
   - nvidia,xcvr-lsfslew : LS falling slew rate control.
   - nvidia,xcvr-lsrslew :  LS rising slew rate control.
 
+Required PHY timing params for utmi phy, only on Tegra30 and above:
+  - nvidia,xcvr-hsslew : HS slew rate control.
+  - nvidia,hssquelch-level : HS squelch detector level.
+  - nvidia,hsdiscon-level : HS disconnect detector level.
+
 Optional properties:
   - nvidia,has-legacy-mode : boolean indicates whether this controller can
     operate in legacy mode (as APX 2500 / 2600). In legacy mode some
@@ -48,5 +57,5 @@
       peripheral means it is device controller
       otg means it can operate as either ("on the go")
 
-Required properties for dr_mode == otg:
+VBUS control (required for dr_mode == otg, optional for dr_mode == host):
   - vbus-supply: regulator for VBUS
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index 57e71f6..9088ab0 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -53,6 +53,11 @@
    It should be set to "1" for HW mode and "2" for SW mode.
  - ranges: the child address space are mapped 1:1 onto the parent address space
 
+Optional Properties:
+ - extcon : phandle for the extcon device omap dwc3 uses to detect
+   connect/disconnect events.
+ - vbus-supply : phandle to the regulator device tree node if needed.
+
 Sub-nodes:
 The dwc3 core should be added as subnode to omap dwc3 glue.
 - dwc3 :
diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
new file mode 100644
index 0000000..b83d428
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
@@ -0,0 +1,40 @@
+Samsung High Speed USB OTG controller
+-----------------------------
+
+The Samsung HSOTG IP can be found on Samsung SoCs, from S3C6400 onwards.
+It gives functionality of OTG-compliant USB 2.0 host and device with
+support for USB 2.0 high-speed (480Mbps) and full-speed (12 Mbps)
+operation.
+
+Currently only device mode is supported.
+
+Binding details
+-----
+
+Required properties:
+- compatible: "samsung,s3c6400-hsotg" should be used for all currently
+    supported SoC,
+- interrupt-parent: phandle for the interrupt controller to which the
+    interrupt signal of the HSOTG block is routed,
+- interrupts: specifier of interrupt signal of interrupt controller,
+    according to bindings of interrupt controller,
+- clocks: contains an array of clock specifiers:
+    - first entry: OTG clock
+- clock-names: contains array of clock names:
+    - first entry: must be "otg"
+- vusb_d-supply: phandle to voltage regulator of digital section,
+- vusb_a-supply: phandle to voltage regulator of analog section.
+
+Example
+-----
+
+	hsotg@12480000 {
+		compatible = "samsung,s3c6400-hsotg";
+		reg = <0x12480000 0x20000>;
+		interrupts = <0 71 0>;
+		clocks = <&clock 305>;
+		clock-names = "otg";
+		vusb_d-supply = <&vusb_reg>;
+		vusb_a-supply = <&vusbdac_reg>;
+	};
+
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
new file mode 100644
index 0000000..5752df0
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
@@ -0,0 +1,14 @@
+USB xHCI controllers
+
+Required properties:
+  - compatible: should be "xhci-platform".
+  - reg: should contain address and length of the standard XHCI
+    register set for the device.
+  - interrupts: one XHCI interrupt should be described here.
+
+Example:
+	usb@f0931000 {
+		compatible = "xhci-platform";
+		reg = <0xf0931000 0x8c8>;
+		interrupts = <0x0 0x4e 0x0>;
+	};
diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt
index 8c5be48..a018da4 100644
--- a/Documentation/devicetree/bindings/usb/usb3503.txt
+++ b/Documentation/devicetree/bindings/usb/usb3503.txt
@@ -1,8 +1,11 @@
 SMSC USB3503 High-Speed Hub Controller
 
 Required properties:
-- compatible: Should be "smsc,usb3503".
-- reg: Specifies the i2c slave address, it should be 0x08.
+- compatible: Should be "smsc,usb3503" or "smsc,usb3503a".
+
+Optional properties:
+- reg: Specifies the i2c slave address, it is required and should be 0x08
+       if I2C is used.
 - connect-gpios: Should specify GPIO for connect.
 - disabled-ports: Should specify the ports unused.
 	'1' or '2' or '3' are availe for this property to describe the port
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 366ce9b..ec4d713 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -11,6 +11,7 @@
 apm	Applied Micro Circuits Corporation (APM)
 arm	ARM Ltd.
 atmel	Atmel Corporation
+avago	Avago Technologies
 bosch	Bosch Sensortec GmbH
 brcm	Broadcom Corporation
 cavium	Cavium, Inc.
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index b467145..fb57d85 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -237,6 +237,12 @@
   devm_kzalloc()
   devm_kfree()
 
+IIO
+  devm_iio_device_alloc()
+  devm_iio_device_free()
+  devm_iio_trigger_alloc()
+  devm_iio_trigger_free()
+
 IO region
   devm_request_region()
   devm_request_mem_region()
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index f7cbf57..b91cfaa 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -144,11 +144,12 @@
 			mount the device. This will enable 'journal_checksum'
 			internally.
 
+journal_path=path
 journal_dev=devnum	When the external journal device's major/minor numbers
-			have changed, this option allows the user to specify
+			have changed, these options allow the user to specify
 			the new journal location.  The journal device is
-			identified through its new major/minor numbers encoded
-			in devnum.
+			identified through either its new major/minor numbers
+			encoded in devnum, or via a path to the device.
 
 norecovery		Don't load the journal on mounting.  Note that
 noload			if the filesystem was not unmounted cleanly,
diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
index f6fe9c2..063b80d 100644
--- a/Documentation/hwmon/ads1015
+++ b/Documentation/hwmon/ads1015
@@ -6,6 +6,10 @@
     Prefix: 'ads1015'
     Datasheet: Publicly available at the Texas Instruments website :
                http://focus.ti.com/lit/ds/symlink/ads1015.pdf
+  * Texas Instruments ADS1115
+    Prefix: 'ads1115'
+    Datasheet: Publicly available at the Texas Instruments website :
+               http://focus.ti.com/lit/ds/symlink/ads1115.pdf
 
 Authors:
         Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
@@ -13,9 +17,9 @@
 Description
 -----------
 
-This driver implements support for the Texas Instruments ADS1015.
+This driver implements support for the Texas Instruments ADS1015/ADS1115.
 
-This device is a 12-bit A-D converter with 4 inputs.
+This device is a 12/16-bit A-D converter with 4 inputs.
 
 The inputs can be used single ended or in certain differential combinations.
 
diff --git a/Documentation/hwmon/htu21 b/Documentation/hwmon/htu21
new file mode 100644
index 0000000..f39a215
--- /dev/null
+++ b/Documentation/hwmon/htu21
@@ -0,0 +1,46 @@
+Kernel driver htu21
+===================
+
+Supported chips:
+  * Measurement Specialties HTU21D
+    Prefix: 'htu21'
+    Addresses scanned: none
+    Datasheet: Publicly available at the Measurement Specialties website
+    http://www.meas-spec.com/downloads/HTU21D.pdf
+
+
+Author:
+  William Markezana <william.markezana@meas-spec.com>
+
+Description
+-----------
+
+The HTU21D is a humidity and temperature sensor in a DFN package of
+only 3 x 3 mm footprint and 0.9 mm height.
+
+The devices communicate with the I2C protocol. All sensors are set to the
+same I2C address 0x40, so an entry with I2C_BOARD_INFO("htu21", 0x40) can
+be used in the board setup code.
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices
+for details.
+
+sysfs-Interface
+---------------
+
+temp1_input - temperature input
+humidity1_input - humidity input
+
+Notes
+-----
+
+The driver uses the default resolution settings of 12 bit for humidity and 14
+bit for temperature, which results in typical measurement times of 11 ms for
+humidity and 44 ms for temperature. To keep self heating below 0.1 degree
+Celsius, the device should not be active for more than 10% of the time. For
+this reason, the driver performs no more than two measurements per second and
+reports cached information if polled more frequently.
+
+Different resolutions, the on-chip heater, using the CRC checksum and reading
+the serial number are not supported yet.
diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp
index 90956b6..4dfdc8f 100644
--- a/Documentation/hwmon/k10temp
+++ b/Documentation/hwmon/k10temp
@@ -12,6 +12,7 @@
 * AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series)
 * AMD Family 14h processors: "Brazos" (C/E/G/Z-Series)
 * AMD Family 15h processors: "Bulldozer" (FX-Series), "Trinity"
+* AMD Family 16h processors: "Kabini"
 
   Prefix: 'k10temp'
   Addresses scanned: PCI space
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 15356ac..479eeaf 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -235,10 +235,61 @@
 			Format: To spoof as Windows 98: ="Microsoft Windows"
 
 	acpi_osi=	[HW,ACPI] Modify list of supported OS interface strings
-			acpi_osi="string1"	# add string1 -- only one string
-			acpi_osi="!string2"	# remove built-in string2
+			acpi_osi="string1"	# add string1
+			acpi_osi="!string2"	# remove string2
+			acpi_osi=!*		# remove all strings
+			acpi_osi=!		# disable all built-in OS vendor
+						  strings
 			acpi_osi=		# disable all strings
 
+			'acpi_osi=!' can be used in combination with single or
+			multiple 'acpi_osi="string1"' to support specific OS
+			vendor string(s).  Note that such command can only
+			affect the default state of the OS vendor strings, thus
+			it cannot affect the default state of the feature group
+			strings and the current state of the OS vendor strings,
+			specifying it multiple times through kernel command line
+			is meaningless.  This command is useful when one do not
+			care about the state of the feature group strings which
+			should be controlled by the OSPM.
+			Examples:
+			  1. 'acpi_osi=! acpi_osi="Windows 2000"' is equivalent
+			     to 'acpi_osi="Windows 2000" acpi_osi=!', they all
+			     can make '_OSI("Windows 2000")' TRUE.
+
+			'acpi_osi=' cannot be used in combination with other
+			'acpi_osi=' command lines, the _OSI method will not
+			exist in the ACPI namespace.  NOTE that such command can
+			only affect the _OSI support state, thus specifying it
+			multiple times through kernel command line is also
+			meaningless.
+			Examples:
+			  1. 'acpi_osi=' can make 'CondRefOf(_OSI, Local1)'
+			     FALSE.
+
+			'acpi_osi=!*' can be used in combination with single or
+			multiple 'acpi_osi="string1"' to support specific
+			string(s).  Note that such command can affect the
+			current state of both the OS vendor strings and the
+			feature group strings, thus specifying it multiple times
+			through kernel command line is meaningful.  But it may
+			still not able to affect the final state of a string if
+			there are quirks related to this string.  This command
+			is useful when one want to control the state of the
+			feature group strings to debug BIOS issues related to
+			the OSPM features.
+			Examples:
+			  1. 'acpi_osi="Module Device" acpi_osi=!*' can make
+			     '_OSI("Module Device")' FALSE.
+			  2. 'acpi_osi=!* acpi_osi="Module Device"' can make
+			     '_OSI("Module Device")' TRUE.
+			  3. 'acpi_osi=! acpi_osi=!* acpi_osi="Windows 2000"' is
+			     equivalent to
+			     'acpi_osi=!* acpi_osi=! acpi_osi="Windows 2000"'
+			     and
+			     'acpi_osi=!* acpi_osi="Windows 2000" acpi_osi=!',
+			     they all will make '_OSI("Windows 2000")' TRUE.
+
 	acpi_pm_good	[X86]
 			Override the pmtimer bug detection: force the kernel
 			to assume that this machine's pmtimer latches its value
@@ -2953,7 +3004,7 @@
 			improve throughput, but will also increase the
 			amount of memory reserved for use by the client.
 
-	swapaccount[=0|1]
+	swapaccount=[0|1]
 			[KNL] Enable accounting of swap in memory resource
 			controller if no parameter or 1 is given or disable
 			it if 0 is given (See Documentation/cgroups/memory.txt)
@@ -3322,6 +3373,10 @@
 			            them quite hard to use for exploits but
 			            might break your system.
 
+	vt.color=	[VT] Default text color.
+			Format: 0xYX, X = foreground, Y = background.
+			Default: 0x07 = light gray on black.
+
 	vt.cur_default=	[VT] Default cursor shape.
 			Format: 0xCCBBAA, where AA, BB, and CC are the same as
 			the parameters of the <Esc>[?A;B;Cc escape sequence;
@@ -3361,6 +3416,12 @@
 			overridden by individual drivers. 0 will hide
 			cursors, 1 will display them.
 
+	vt.italic=	[VT] Default color for italic text; 0-15.
+			Default: 2 = green.
+
+	vt.underline=	[VT] Default color for underlined text; 0-15.
+			Default: 3 = cyan.
+
 	watchdog timers	[HW,WDT] For information on watchdog timers,
 			see Documentation/watchdog/watchdog-parameters.txt
 			or other driver-specific files in the
diff --git a/Documentation/ko_KR/HOWTO b/Documentation/ko_KR/HOWTO
index 2f48f20..680e646 100644
--- a/Documentation/ko_KR/HOWTO
+++ b/Documentation/ko_KR/HOWTO
@@ -182,8 +182,8 @@
 프로젝트를 봐야 한다.
     http://kernelnewbies.org
 그곳은 거의 모든 종류의 기본적인 커널 개발 질문들(질문하기 전에 먼저
-아카이브를 찾아봐라. 과거에 이미 답변되었을 수도 있다)을 할수있는 도움이
-될만한 메일링 리스트가 있다. 또한 실시간으로 질문 할수 있는 IRC 채널도
+아카이브를 찾아봐라. 과거에 이미 답변되었을 수도 있다)을 할 수 있는 도움이
+될만한 메일링 리스트가 있다. 또한 실시간으로 질문 할 수 있는 IRC 채널도
 가지고 있으며 리눅스 커널 개발을 배우는 데 유용한 문서들을 보유하고 있다.
 
 웹사이트는 코드구성, 서브시스템들, 그리고 현재 프로젝트들
@@ -245,7 +245,7 @@
     것을 기억해라. 왜냐하면 변경이 자체내에서만 발생하고 추가된 코드가
     드라이버 외부의 다른 부분에는 영향을 주지 않으므로 그런 변경은
     회귀(역자주: 이전에는 존재하지 않았지만 새로운 기능추가나 변경으로 인해
-		생겨난 버그)를 일으킬 만한 위험을 가지고 있지 않기 때문이다. -rc1이
+    생겨난 버그)를 일으킬 만한 위험을 가지고 있지 않기 때문이다. -rc1이
     배포된 이후에 git를 사용하여 패치들을 Linus에게 보낼수 있지만 패치들은
     공식적인 메일링 리스트로 보내서 검토를 받을 필요가 있다.
   - 새로운 -rc는 Linus가 현재 git tree가 테스트 하기에 충분히 안정된 상태에
@@ -455,7 +455,7 @@
  - 의견
  - 변경을 위한 요구
  - 당위성을 위한 요구
- - 고요
+ - 침묵
 
 기억하라. 이것들은 여러분의 패치가 커널로 들어가기 위한 과정이다. 여러분의
 패치들은 비판과 다른 의견을 받을 수 있고 그것들을 기술적인 레벨로 평가하고
@@ -472,7 +472,7 @@
 가능한한 가장 좋은 기술적인 해답을 찾고 있는 커뮤니티에서는 항상
 어떤 패치가 얼마나 좋은지에 관하여 다른 의견들이 있을 수 있다. 여러분은
 협조적이어야 하고 기꺼이 여러분의 생각을 커널 내에 맞추어야 한다. 아니면
-적어도 여러분의 것이 가치있다는 것을 중명하여야 한다. 잘못된 것도 여러분이
+적어도 여러분의 것이 가치있다는 것을 증명하여야 한다. 잘못된 것도 여러분이
 올바른 방향의 해결책으로 이끌어갈 의지가 있다면 받아들여질 것이라는 점을
 기억하라.
 
@@ -488,21 +488,21 @@
 커널 커뮤니티는 가장 전통적인 회사의 개발 환경과는 다르다. 여기에 여러분들의
 문제를 피하기 위한 목록이 있다.
   여러분들이 제안한 변경들에 관하여 말할 때 좋은 것들 :
-    - "이것은 여러 문제들을 해겹합니다."
-    - "이것은 2000 라인의 코드를 제거합니다."
+    - "이것은 여러 문제들을 해결합니다."
+    - "이것은 2000 라인의 코드를 줄입니다."
     - "이것은 내가 말하려는 것에 관해 설명하는 패치입니다."
-    - "나는 5개의 다른 아키텍쳐에서 그것을 테스트했슴으로..."
-    - "여기에 일련의 작은 패치들이 있슴음로..."
-    - "이것은 일반적인 머신에서 성능을 향상시킴으로..."
+    - "나는 5개의 다른 아키텍쳐에서 그것을 테스트 했으므로..."
+    - "여기에 일련의 작은 패치들이 있으므로..."
+    - "이것은 일반적인 머신에서 성능을 향상함으로..."
 
   여러분들이 말할 때 피해야 할 좋지 않은 것들 :
-    - "우리를 그것을 AIT/ptx/Solaris에서 이러한 방법으로 했다. 그러므로 그것은 좋은 것임에 틀립없다..."
+    - "우리는 그것을 AIX/ptx/Solaris에서 이러한 방법으로 했다. 그러므로 그것은 좋은 것임에 틀림없다..."
     - "나는 20년동안 이것을 해왔다. 그러므로..."
     - "이것은 돈을 벌기위해 나의 회사가 필요로 하는 것이다."
     - "이것은 우리의 엔터프라이즈 상품 라인을 위한 것이다."
     - "여기에 나의 생각을 말하고 있는 1000 페이지 설계 문서가 있다."
     - "나는 6달동안 이것을 했으니..."
-    - "여기에 5000라인 짜리 패치가 있으니..."
+    - "여기에 5000 라인 짜리 패치가 있으니..."
     - "나는 현재 뒤죽박죽인 것을 재작성했다. 그리고 여기에..."
     - "나는 마감시한을 가지고 있으므로 이 패치는 지금 적용될 필요가 있다."
 
@@ -574,6 +574,7 @@
 또한 완성되지 않았고 "나중에 수정될 것이다." 와 같은 것들을 포함하는
 패치들은 받아들여지지 않을 것이라는 점을 유념하라.
 
+
 변경을 정당화해라
 -----------------
 
diff --git a/Documentation/ko_KR/stable_api_nonsense.txt b/Documentation/ko_KR/stable_api_nonsense.txt
index 8f2b0e1..51f85ad 100644
--- a/Documentation/ko_KR/stable_api_nonsense.txt
+++ b/Documentation/ko_KR/stable_api_nonsense.txt
@@ -106,12 +106,12 @@
 ---------------------------------
 
 리눅스 커널 드라이버를 계속해서 메인 커널 트리에 반영하지 않고
-유지보수하려고 하는 사름들과 이 문제를 논의하게 되면 훨씬 더
+유지보수하려고 하는 사람들과 이 문제를 논의하게 되면 훨씬 더
 "논란의 여지가 많은" 주제가 될 것이다.
 
 리눅스 커널 개발은 끊임없이 빠른 속도로 이루어지고 있으며 결코
 느슨해진 적이 없다. 커널 개발자들이 현재 인터페이스들에서 버그를
-발견하거나 무엇인가 할수 있는 더 좋은 방법을 찾게 되었다고 하자.
+발견하거나 무엇인가 할 수 있는 더 좋은 방법을 찾게 되었다고 하자.
 그들이 발견한 것을 실행한다면 아마도 더 잘 동작하도록 현재 인터페이스들을
 수정하게 될 것이다. 그들이 그런 일을 하게되면 함수 이름들은 변하게 되고,
 구조체들은 늘어나거나 줄어들게 되고, 함수 파라미터들은 재작업될 것이다.
@@ -174,7 +174,7 @@
 동작하는 것을 보장한다.
 
 메인 커널 트리에 여러분의 드라이버를 반영하면 얻게 되는 장점들은 다음과 같다.
-   - 관리의 드는 비용(원래 개발자의)은 줄어줄면서 드라이버의 질은 향상될 것이다.
+   - 관리에 드는 비용(원래 개발자의)은 줄어줄면서 드라이버의 질은 향상될 것이다.
    - 다른 개발자들이 여러분의 드라이버에 기능들을 추가 할 것이다.
    - 다른 사람들은 여러분의 드라이버에 버그를 발견하고 수정할 것이다.
    - 다른 사람들은 여러분의 드라이버의 개선점을 찾을 줄 것이다.
diff --git a/Documentation/laptops/asus-laptop.txt b/Documentation/laptops/asus-laptop.txt
index 69f9fb3..79a1bc6 100644
--- a/Documentation/laptops/asus-laptop.txt
+++ b/Documentation/laptops/asus-laptop.txt
@@ -8,8 +8,8 @@
 
  This driver provides support for extra features of ACPI-compatible ASUS laptops.
  It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
- VICTOR XP7210 for example). It makes all the extra buttons generate standard
- ACPI events that go through /proc/acpi/events and input events (like keyboards).
+ VICTOR XP7210 for example). It makes all the extra buttons generate input
+ events (like keyboards).
  On some models adds support for changing the display brightness and output,
  switching the LCD backlight on and off, and most importantly, allows you to
  blink those fancy LEDs intended for reporting mail and wireless status.
@@ -55,8 +55,8 @@
   DSDT) to me.
 
   That's all, now, all the events generated by the hotkeys of your laptop
-  should be reported in your /proc/acpi/event entry. You can check with
-  "acpi_listen".
+  should be reported via netlink events. You can check with
+  "acpi_genl monitor" (part of the acpica project).
 
   Hotkeys are also reported as input keys (like keyboards) you can check
   which key are supported using "xev" under X11.
diff --git a/Documentation/laptops/sony-laptop.txt b/Documentation/laptops/sony-laptop.txt
index 0d5ac7f..978b1e61 100644
--- a/Documentation/laptops/sony-laptop.txt
+++ b/Documentation/laptops/sony-laptop.txt
@@ -12,10 +12,10 @@
 ------------------
 Some models report hotkeys through the SNC or SPIC devices, such events are
 reported both through the ACPI subsystem as acpi events and through the INPUT
-subsystem. See the logs of acpid or /proc/acpi/event and
-/proc/bus/input/devices to find out what those events are and which input
-devices are created by the driver. Additionally, loading the driver with the
-debug option will report all events in the kernel log.
+subsystem. See the logs of /proc/bus/input/devices to find out what those
+events are and which input devices are created by the driver.
+Additionally, loading the driver with the debug option will report all events
+in the kernel log.
 
 The "scancodes" passed to the input system (that can be remapped with udev)
 are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index cf7bc6c..86c5236 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -329,20 +329,6 @@
 
 		This attribute has poll()/select() support.
 
-	hotkey_report_mode:
-		Returns the state of the procfs ACPI event report mode
-		filter for hot keys.  If it is set to 1 (the default),
-		all hot key presses are reported both through the input
-		layer and also as ACPI events through procfs (but not
-		through netlink).  If it is set to 2, hot key presses
-		are reported only through the input layer.
-
-		This attribute is read-only in kernels 2.6.23 or later,
-		and read-write on earlier kernels.
-
-		May return -EPERM (write access locked out by module
-		parameter) or -EACCES (read-only).
-
 	wakeup_reason:
 		Set to 1 if the system is waking up because the user
 		requested a bay ejection.  Set to 2 if the system is
@@ -518,24 +504,21 @@
 Non hotkey ACPI HKEY event map:
 -------------------------------
 
-Events that are not propagated by the driver, except for legacy
-compatibility purposes when hotkey_report_mode is set to 1:
-
-0x5001		Lid closed
-0x5002		Lid opened
-0x5009		Tablet swivel: switched to tablet mode
-0x500A		Tablet swivel: switched to normal mode
-0x7000		Radio Switch may have changed state
-
 Events that are never propagated by the driver:
 
 0x2304		System is waking up from suspend to undock
 0x2305		System is waking up from suspend to eject bay
 0x2404		System is waking up from hibernation to undock
 0x2405		System is waking up from hibernation to eject bay
+0x5001		Lid closed
+0x5002		Lid opened
+0x5009		Tablet swivel: switched to tablet mode
+0x500A		Tablet swivel: switched to normal mode
 0x5010		Brightness level changed/control event
 0x6000		KEYBOARD: Numlock key pressed
 0x6005		KEYBOARD: Fn key pressed (TO BE VERIFIED)
+0x7000		Radio Switch may have changed state
+
 
 Events that are propagated by the driver to userspace:
 
@@ -574,50 +557,6 @@
 cycle, or a system shutdown.  Obviously, something is very wrong if this
 happens.
 
-Compatibility notes:
-
-ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never
-supported the input layer, and sent events over the procfs ACPI event
-interface.
-
-To avoid sending duplicate events over the input layer and the ACPI
-event interface, thinkpad-acpi 0.16 implements a module parameter
-(hotkey_report_mode), and also a sysfs device attribute with the same
-name.
-
-Make no mistake here: userspace is expected to switch to using the input
-layer interface of thinkpad-acpi, together with the ACPI netlink event
-interface in kernels 2.6.23 and later, or with the ACPI procfs event
-interface in kernels 2.6.22 and earlier.
-
-If no hotkey_report_mode module parameter is specified (or it is set to
-zero), the driver defaults to mode 1 (see below), and on kernels 2.6.22
-and earlier, also allows one to change the hotkey_report_mode through
-sysfs.  In kernels 2.6.23 and later, where the netlink ACPI event
-interface is available, hotkey_report_mode cannot be changed through
-sysfs (it is read-only).
-
-If the hotkey_report_mode module parameter is set to 1 or 2, it cannot
-be changed later through sysfs (any writes will return -EPERM to signal
-that hotkey_report_mode was locked.  On 2.6.23 and later, where
-hotkey_report_mode cannot be changed at all, writes will return -EACCES).
-
-hotkey_report_mode set to 1 makes the driver export through the procfs
-ACPI event interface all hot key presses (which are *also* sent to the
-input layer).  This is a legacy compatibility behaviour, and it is also
-the default mode of operation for the driver.
-
-hotkey_report_mode set to 2 makes the driver filter out the hot key
-presses from the procfs ACPI event interface, so these events will only
-be sent through the input layer.  Userspace that has been updated to use
-the thinkpad-acpi input layer interface should set hotkey_report_mode to
-2.
-
-Hot key press events are never sent to the ACPI netlink event interface.
-Really up-to-date userspace under kernel 2.6.23 and later is to use the
-netlink interface and the input layer interface, and don't bother at all
-with hotkey_report_mode.
-
 
 Brightness hotkey notes:
 
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index fa5d8a9..c8c42e6 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -531,9 +531,10 @@
 code:
 
 	q = &a;
-	if (p)
+	if (p) {
+		<data dependency barrier>
 		q = &b;
-	<data dependency barrier>
+	}
 	x = *q;
 
 This will not have the desired effect because there is no actual data
@@ -542,9 +543,10 @@
 required is:
 
 	q = &a;
-	if (p)
+	if (p) {
+		<read barrier>
 		q = &b;
-	<read barrier>
+	}
 	x = *q;
 
 
diff --git a/Documentation/memory-hotplug.txt b/Documentation/memory-hotplug.txt
index 8e5eacb..8fd254c 100644
--- a/Documentation/memory-hotplug.txt
+++ b/Documentation/memory-hotplug.txt
@@ -210,13 +210,15 @@
 
 4.2 Notify memory hot-add event by hand
 ------------
-In some environments, especially virtualized environment, firmware will not
-notify memory hotplug event to the kernel. For such environment, "probe"
-interface is supported. This interface depends on CONFIG_ARCH_MEMORY_PROBE.
+On powerpc, the firmware does not notify a memory hotplug event to the kernel.
+Therefore, "probe" interface is supported to notify the event to the kernel.
+This interface depends on CONFIG_ARCH_MEMORY_PROBE.
 
-Now, CONFIG_ARCH_MEMORY_PROBE is supported only by powerpc but it does not
-contain highly architecture codes. Please add config if you need "probe"
-interface.
+CONFIG_ARCH_MEMORY_PROBE is supported on powerpc only. On x86, this config
+option is disabled by default since ACPI notifies a memory hotplug event to
+the kernel, which performs its hotplug operation as the result. Please
+enable this option if you need the "probe" interface for testing purposes
+on x86.
 
 Probe interface is located at
 /sys/devices/system/memory/probe
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index 052e13a..c0ffd30 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -81,7 +81,7 @@
 	struct pinctrl_dev *pctl;
 
 	pctl = pinctrl_register(&foo_desc, <PARENT>, NULL);
-	if (IS_ERR(pctl))
+	if (!pctl)
 		pr_err("could not register foo pin driver\n");
 }
 
@@ -795,18 +795,97 @@
 GPIO mode pitfalls
 ==================
 
-Sometime the developer may be confused by a datasheet talking about a pin
-being possible to set into "GPIO mode". It appears that what hardware
-engineers mean with "GPIO mode" is not necessarily the use case that is
-implied in the kernel interface <linux/gpio.h>: a pin that you grab from
-kernel code and then either listen for input or drive high/low to
-assert/deassert some external line.
+Due to the naming conventions used by hardware engineers, where "GPIO"
+is taken to mean different things than what the kernel does, the developer
+may be confused by a datasheet talking about a pin being possible to set
+into "GPIO mode". It appears that what hardware engineers mean with
+"GPIO mode" is not necessarily the use case that is implied in the kernel
+interface <linux/gpio.h>: a pin that you grab from kernel code and then
+either listen for input or drive high/low to assert/deassert some
+external line.
 
 Rather hardware engineers think that "GPIO mode" means that you can
 software-control a few electrical properties of the pin that you would
 not be able to control if the pin was in some other mode, such as muxed in
 for a device.
 
+The GPIO portions of a pin and its relation to a certain pin controller
+configuration and muxing logic can be constructed in several ways. Here
+are two examples:
+
+(A)
+                       pin config
+                       logic regs
+                       |               +- SPI
+     Physical pins --- pad --- pinmux -+- I2C
+                               |       +- mmc
+                               |       +- GPIO
+                               pin
+                               multiplex
+                               logic regs
+
+Here some electrical properties of the pin can be configured no matter
+whether the pin is used for GPIO or not. If you multiplex a GPIO onto a
+pin, you can also drive it high/low from "GPIO" registers.
+Alternatively, the pin can be controlled by a certain peripheral, while
+still applying desired pin config properties. GPIO functionality is thus
+orthogonal to any other device using the pin.
+
+In this arrangement the registers for the GPIO portions of the pin controller,
+or the registers for the GPIO hardware module are likely to reside in a
+separate memory range only intended for GPIO driving, and the register
+range dealing with pin config and pin multiplexing get placed into a
+different memory range and a separate section of the data sheet.
+
+(B)
+
+                       pin config
+                       logic regs
+                       |               +- SPI
+     Physical pins --- pad --- pinmux -+- I2C
+                       |       |       +- mmc
+                       |       |
+                       GPIO    pin
+                               multiplex
+                               logic regs
+
+In this arrangement, the GPIO functionality can always be enabled, such that
+e.g. a GPIO input can be used to "spy" on the SPI/I2C/MMC signal while it is
+pulsed out. It is likely possible to disrupt the traffic on the pin by doing
+wrong things on the GPIO block, as it is never really disconnected. It is
+possible that the GPIO, pin config and pin multiplex registers are placed into
+the same memory range and the same section of the data sheet, although that
+need not be the case.
+
+From a kernel point of view, however, these are different aspects of the
+hardware and shall be put into different subsystems:
+
+- Registers (or fields within registers) that control electrical
+  properties of the pin such as biasing and drive strength should be
+  exposed through the pinctrl subsystem, as "pin configuration" settings.
+
+- Registers (or fields within registers) that control muxing of signals
+  from various other HW blocks (e.g. I2C, MMC, or GPIO) onto pins should
+  be exposed through the pinctrl subssytem, as mux functions.
+
+- Registers (or fields within registers) that control GPIO functionality
+  such as setting a GPIO's output value, reading a GPIO's input value, or
+  setting GPIO pin direction should be exposed through the GPIO subsystem,
+  and if they also support interrupt capabilities, through the irqchip
+  abstraction.
+
+Depending on the exact HW register design, some functions exposed by the
+GPIO subsystem may call into the pinctrl subsystem in order to
+co-ordinate register settings across HW modules. In particular, this may
+be needed for HW with separate GPIO and pin controller HW modules, where
+e.g. GPIO direction is determined by a register in the pin controller HW
+module rather than the GPIO HW module.
+
+Electrical properties of the pin such as biasing and drive strength
+may be placed at some pin-specific register in all cases or as part
+of the GPIO register in case (B) especially. This doesn't mean that such
+properties necessarily pertain to what the Linux kernel calls "GPIO".
+
 Example: a pin is usually muxed in to be used as a UART TX line. But during
 system sleep, we need to put this pin into "GPIO mode" and ground it.
 
@@ -856,7 +935,7 @@
     PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, 0),
 };
 
-static struct pinctrl_map __initdata pinmap[] = {
+static struct pinctrl_map pinmap[] __initdata = {
     PIN_MAP_MUX_GROUP("uart", PINCTRL_STATE_DEFAULT, "pinctrl-foo",
                       "u0_group", "u0"),
     PIN_MAP_CONFIGS_PIN("uart", PINCTRL_STATE_DEFAULT, "pinctrl-foo",
@@ -951,7 +1030,7 @@
 it even more compact which assumes you want to use pinctrl-foo and position
 0 for mapping, for example:
 
-static struct pinctrl_map __initdata mapping[] = {
+static struct pinctrl_map mapping[] __initdata = {
 	PIN_MAP_MUX_GROUP("foo-i2c.o", PINCTRL_STATE_DEFAULT, "pinctrl-foo", NULL, "i2c0"),
 };
 
@@ -970,7 +1049,7 @@
 	FOO_SLEW_RATE_SLOW,
 };
 
-static struct pinctrl_map __initdata mapping[] = {
+static struct pinctrl_map mapping[] __initdata = {
 	PIN_MAP_MUX_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "i2c0"),
 	PIN_MAP_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
 	PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
@@ -984,7 +1063,7 @@
 be empty. Table entry macro PIN_MAP_DUMMY_STATE serves the purpose of defining
 a named state without causing any pin controller to be programmed:
 
-static struct pinctrl_map __initdata mapping[] = {
+static struct pinctrl_map mapping[] __initdata = {
 	PIN_MAP_DUMMY_STATE("foo-i2c.0", PINCTRL_STATE_DEFAULT),
 };
 
diff --git a/Documentation/scsi/LICENSE.qla4xxx b/Documentation/scsi/LICENSE.qla4xxx
index 78c169f..fcc27ad 100644
--- a/Documentation/scsi/LICENSE.qla4xxx
+++ b/Documentation/scsi/LICENSE.qla4xxx
@@ -1,4 +1,4 @@
-Copyright (c) 2003-2012 QLogic Corporation
+Copyright (c) 2003-2013 QLogic Corporation
 QLogic Linux iSCSI Driver
 
 This program includes a device driver for Linux 3.x.
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 809d72b..a46ddb8 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -244,6 +244,7 @@
   5stack-no-fp	D965 5stack without front panel
   dell-3stack	Dell Dimension E520
   dell-bios	Fixes with Dell BIOS setup
+  dell-bios-amic Fixes with Dell BIOS setup including analog mic
   volknob	Fixes with volume-knob widget 0x24
   auto		BIOS setup (default)
 
diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt
index c3c912d..42a0a39 100644
--- a/Documentation/sound/alsa/HD-Audio.txt
+++ b/Documentation/sound/alsa/HD-Audio.txt
@@ -454,6 +454,8 @@
 - need_dac_fix (bool): limits the DACs depending on the channel count
 - primary_hp (bool): probe headphone jacks as the primary outputs;
   default true
+- multi_io (bool): try probing multi-I/O config (e.g. shared
+  line-in/surround, mic/clfe jacks)
 - multi_cap_vol (bool): provide multiple capture volumes
 - inv_dmic_split (bool): provide split internal mic volume/switch for
   phase-inverted digital mics
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index 2331eb2..f21edb9 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -215,7 +215,7 @@
 	/* if your mach-* infrastructure doesn't support kernels that can
 	 * run on multiple boards, pdata wouldn't benefit from "__init".
 	 */
-	static struct mysoc_spi_data __initdata pdata = { ... };
+	static struct mysoc_spi_data pdata __initdata = { ... };
 
 	static __init board_init(void)
 	{
diff --git a/Documentation/timers/NO_HZ.txt b/Documentation/timers/NO_HZ.txt
index 8869758..cca122f 100644
--- a/Documentation/timers/NO_HZ.txt
+++ b/Documentation/timers/NO_HZ.txt
@@ -24,8 +24,8 @@
 	workloads, you will normally -not- want this option.
 
 These three cases are described in the following three sections, followed
-by a third section on RCU-specific considerations and a fourth and final
-section listing known issues.
+by a third section on RCU-specific considerations, a fourth section
+discussing testing, and a fifth and final section listing known issues.
 
 
 NEVER OMIT SCHEDULING-CLOCK TICKS
@@ -121,14 +121,15 @@
 "nohz_full=1,6-8" says that CPUs 1, 6, 7, and 8 are to be adaptive-ticks
 CPUs.  Note that you are prohibited from marking all of the CPUs as
 adaptive-tick CPUs:  At least one non-adaptive-tick CPU must remain
-online to handle timekeeping tasks in order to ensure that system calls
-like gettimeofday() returns accurate values on adaptive-tick CPUs.
-(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no
-running user processes to observe slight drifts in clock rate.)
-Therefore, the boot CPU is prohibited from entering adaptive-ticks
-mode.  Specifying a "nohz_full=" mask that includes the boot CPU will
-result in a boot-time error message, and the boot CPU will be removed
-from the mask.
+online to handle timekeeping tasks in order to ensure that system
+calls like gettimeofday() returns accurate values on adaptive-tick CPUs.
+(This is not an issue for CONFIG_NO_HZ_IDLE=y because there are no running
+user processes to observe slight drifts in clock rate.)  Therefore, the
+boot CPU is prohibited from entering adaptive-ticks mode.  Specifying a
+"nohz_full=" mask that includes the boot CPU will result in a boot-time
+error message, and the boot CPU will be removed from the mask.  Note that
+this means that your system must have at least two CPUs in order for
+CONFIG_NO_HZ_FULL=y to do anything for you.
 
 Alternatively, the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter specifies
 that all CPUs other than the boot CPU are adaptive-ticks CPUs.  This
@@ -232,6 +233,29 @@
 where you want them to run.
 
 
+TESTING
+
+So you enable all the OS-jitter features described in this document,
+but do not see any change in your workload's behavior.  Is this because
+your workload isn't affected that much by OS jitter, or is it because
+something else is in the way?  This section helps answer this question
+by providing a simple OS-jitter test suite, which is available on branch
+master of the following git archive:
+
+git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git
+
+Clone this archive and follow the instructions in the README file.
+This test procedure will produce a trace that will allow you to evaluate
+whether or not you have succeeded in removing OS jitter from your system.
+If this trace shows that you have removed OS jitter as much as is
+possible, then you can conclude that your workload is not all that
+sensitive to OS jitter.
+
+Note: this test requires that your system have at least two CPUs.
+We do not currently have a good way to remove OS jitter from single-CPU
+systems.
+
+
 KNOWN ISSUES
 
 o	Dyntick-idle slows transitions to and from idle slightly.
diff --git a/Documentation/tpm/xen-tpmfront.txt b/Documentation/tpm/xen-tpmfront.txt
new file mode 100644
index 0000000..69346de
--- /dev/null
+++ b/Documentation/tpm/xen-tpmfront.txt
@@ -0,0 +1,113 @@
+Virtual TPM interface for Xen
+
+Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA)
+
+This document describes the virtual Trusted Platform Module (vTPM) subsystem for
+Xen. The reader is assumed to have familiarity with building and installing Xen,
+Linux, and a basic understanding of the TPM and vTPM concepts.
+
+INTRODUCTION
+
+The goal of this work is to provide a TPM functionality to a virtual guest
+operating system (in Xen terms, a DomU).  This allows programs to interact with
+a TPM in a virtual system the same way they interact with a TPM on the physical
+system.  Each guest gets its own unique, emulated, software TPM.  However, each
+of the vTPM's secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain,
+which seals the secrets to the Physical TPM.  If the process of creating each of
+these domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends
+the chain of trust rooted in the hardware TPM to virtual machines in Xen. Each
+major component of vTPM is implemented as a separate domain, providing secure
+separation guaranteed by the hypervisor. The vTPM domains are implemented in
+mini-os to reduce memory and processor overhead.
+
+This mini-os vTPM subsystem was built on top of the previous vTPM work done by
+IBM and Intel corporation.
+
+
+DESIGN OVERVIEW
+---------------
+
+The architecture of vTPM is described below:
+
++------------------+
+|    Linux DomU    | ...
+|       |  ^       |
+|       v  |       |
+|   xen-tpmfront   |
++------------------+
+        |  ^
+        v  |
++------------------+
+| mini-os/tpmback  |
+|       |  ^       |
+|       v  |       |
+|  vtpm-stubdom    | ...
+|       |  ^       |
+|       v  |       |
+| mini-os/tpmfront |
++------------------+
+        |  ^
+        v  |
++------------------+
+| mini-os/tpmback  |
+|       |  ^       |
+|       v  |       |
+| vtpmmgr-stubdom  |
+|       |  ^       |
+|       v  |       |
+| mini-os/tpm_tis  |
++------------------+
+        |  ^
+        v  |
++------------------+
+|   Hardware TPM   |
++------------------+
+
+ * Linux DomU: The Linux based guest that wants to use a vTPM. There may be
+	       more than one of these.
+
+ * xen-tpmfront.ko: Linux kernel virtual TPM frontend driver. This driver
+                    provides vTPM access to a Linux-based DomU.
+
+ * mini-os/tpmback: Mini-os TPM backend driver. The Linux frontend driver
+		    connects to this backend driver to facilitate communications
+		    between the Linux DomU and its vTPM. This driver is also
+		    used by vtpmmgr-stubdom to communicate with vtpm-stubdom.
+
+ * vtpm-stubdom: A mini-os stub domain that implements a vTPM. There is a
+		 one to one mapping between running vtpm-stubdom instances and
+                 logical vtpms on the system. The vTPM Platform Configuration
+                 Registers (PCRs) are normally all initialized to zero.
+
+ * mini-os/tpmfront: Mini-os TPM frontend driver. The vTPM mini-os domain
+		     vtpm-stubdom uses this driver to communicate with
+		     vtpmmgr-stubdom. This driver is also used in mini-os
+		     domains such as pv-grub that talk to the vTPM domain.
+
+ * vtpmmgr-stubdom: A mini-os domain that implements the vTPM manager. There is
+		    only one vTPM manager and it should be running during the
+		    entire lifetime of the machine.  This domain regulates
+		    access to the physical TPM on the system and secures the
+		    persistent state of each vTPM.
+
+ * mini-os/tpm_tis: Mini-os TPM version 1.2 TPM Interface Specification (TIS)
+                    driver. This driver used by vtpmmgr-stubdom to talk directly to
+                    the hardware TPM. Communication is facilitated by mapping
+                    hardware memory pages into vtpmmgr-stubdom.
+
+ * Hardware TPM: The physical TPM that is soldered onto the motherboard.
+
+
+INTEGRATION WITH XEN
+--------------------
+
+Support for the vTPM driver was added in Xen using the libxl toolstack in Xen
+4.3.  See the Xen documentation (docs/misc/vtpm.txt) for details on setting up
+the vTPM and vTPM Manager stub domains.  Once the stub domains are running, a
+vTPM device is set up in the same manner as a disk or network device in the
+domain's configuration file.
+
+In order to use features such as IMA that require a TPM to be loaded prior to
+the initrd, the xen-tpmfront driver must be compiled in to the kernel.  If not
+using such features, the driver can be compiled as a module and will be loaded
+as usual.
diff --git a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt
index 00d2c64..50da0d4 100644
--- a/Documentation/usb/URB.txt
+++ b/Documentation/usb/URB.txt
@@ -195,13 +195,12 @@
 
 The handler is of the following type:
 
-	typedef void (*usb_complete_t)(struct urb *, struct pt_regs *)
+	typedef void (*usb_complete_t)(struct urb *)
 
-I.e., it gets the URB that caused the completion call, plus the
-register values at the time of the corresponding interrupt (if any).
-In the completion handler, you should have a look at urb->status to
-detect any USB errors. Since the context parameter is included in the URB,
-you can pass information to the completion handler. 
+I.e., it gets the URB that caused the completion call. In the completion
+handler, you should have a look at urb->status to detect any USB errors.
+Since the context parameter is included in the URB, you can pass
+information to the completion handler.
 
 Note that even when an error (or unlink) is reported, data may have been
 transferred.  That's because USB transfers are packetized; it might take
@@ -210,12 +209,12 @@
 
 
 NOTE:  ***** WARNING *****
-NEVER SLEEP IN A COMPLETION HANDLER.  These are normally called
-during hardware interrupt processing.  If you can, defer substantial
-work to a tasklet (bottom half) to keep system latencies low.  You'll
-probably need to use spinlocks to protect data structures you manipulate
-in completion handlers.
+NEVER SLEEP IN A COMPLETION HANDLER.  These are often called in atomic
+context.
 
+In the current kernel, completion handlers run with local interrupts
+disabled, but in the future this will be changed, so don't assume that
+local IRQs are always disabled inside completion handlers.
 
 1.8. How to do isochronous (ISO) transfers?
 
diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt
index c9c3f0f..98be919 100644
--- a/Documentation/usb/proc_usb_info.txt
+++ b/Documentation/usb/proc_usb_info.txt
@@ -54,9 +54,12 @@
 
 These files can be read as binary data.  The binary data consists
 of first the device descriptor, then the descriptors for each
-configuration of the device.  Multi-byte fields in the device and
-configuration descriptors, but not other descriptors, are converted
-to host endianness by the kernel.  This information is also shown
+configuration of the device.  Multi-byte fields in the device descriptor
+are converted to host endianness by the kernel.  The configuration
+descriptors are in bus endian format! The configuration descriptor
+are wTotalLength bytes apart. If a device returns less configuration
+descriptor data than indicated by wTotalLength there will be a hole in
+the file for the missing bytes.  This information is also shown
 in text form by the /proc/bus/usb/devices file, described later.
 
 These files may also be used to write user-level drivers for the USB
diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt
index 83afe65..22ff659 100644
--- a/Documentation/virtual/kvm/cpuid.txt
+++ b/Documentation/virtual/kvm/cpuid.txt
@@ -43,6 +43,10 @@
 KVM_FEATURE_ASYNC_PF               ||     4 || async pf can be enabled by
                                    ||       || writing to msr 0x4b564d02
 ------------------------------------------------------------------------------
+KVM_FEATURE_PV_UNHALT              ||     7 || guest checks this feature bit
+                                   ||       || before enabling paravirtualized
+                                   ||       || spinlock support.
+------------------------------------------------------------------------------
 KVM_FEATURE_CLOCKSOURCE_STABLE_BIT ||    24 || host will warn if no guest-side
                                    ||       || per-cpu warps are expected in
                                    ||       || kvmclock.
diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
index ea113b5..022198e 100644
--- a/Documentation/virtual/kvm/hypercalls.txt
+++ b/Documentation/virtual/kvm/hypercalls.txt
@@ -64,3 +64,17 @@
 shared page that contains parts of supervisor visible register state.
 The guest can map this shared page to access its supervisor register through
 memory using this hypercall.
+
+5. KVM_HC_KICK_CPU
+------------------------
+Architecture: x86
+Status: active
+Purpose: Hypercall used to wakeup a vcpu from HLT state
+Usage example : A vcpu of a paravirtualized guest that is busywaiting in guest
+kernel mode for an event to occur (ex: a spinlock to become available) can
+execute HLT instruction once it has busy-waited for more than a threshold
+time-interval. Execution of HLT instruction would cause the hypervisor to put
+the vcpu to sleep until occurence of an appropriate event. Another vcpu of the
+same guest can wakeup the sleeping vcpu by issuing KVM_HC_KICK_CPU hypercall,
+specifying APIC ID (a1) of the vcpu to be woken up. An additional argument (a0)
+is used in the hypercall for future use.
diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt
index a6ab4b6..f81a65b 100644
--- a/Documentation/workqueue.txt
+++ b/Documentation/workqueue.txt
@@ -85,32 +85,31 @@
 Special purpose threads, called worker threads, execute the functions
 off of the queue, one after the other.  If no work is queued, the
 worker threads become idle.  These worker threads are managed in so
-called thread-pools.
+called worker-pools.
 
 The cmwq design differentiates between the user-facing workqueues that
 subsystems and drivers queue work items on and the backend mechanism
-which manages thread-pools and processes the queued work items.
+which manages worker-pools and processes the queued work items.
 
-The backend is called gcwq.  There is one gcwq for each possible CPU
-and one gcwq to serve work items queued on unbound workqueues.  Each
-gcwq has two thread-pools - one for normal work items and the other
-for high priority ones.
+There are two worker-pools, one for normal work items and the other
+for high priority ones, for each possible CPU and some extra
+worker-pools to serve work items queued on unbound workqueues - the
+number of these backing pools is dynamic.
 
 Subsystems and drivers can create and queue work items through special
 workqueue API functions as they see fit. They can influence some
 aspects of the way the work items are executed by setting flags on the
 workqueue they are putting the work item on. These flags include
-things like CPU locality, reentrancy, concurrency limits, priority and
-more.  To get a detailed overview refer to the API description of
+things like CPU locality, concurrency limits, priority and more.  To
+get a detailed overview refer to the API description of
 alloc_workqueue() below.
 
-When a work item is queued to a workqueue, the target gcwq and
-thread-pool is determined according to the queue parameters and
-workqueue attributes and appended on the shared worklist of the
-thread-pool.  For example, unless specifically overridden, a work item
-of a bound workqueue will be queued on the worklist of either normal
-or highpri thread-pool of the gcwq that is associated to the CPU the
-issuer is running on.
+When a work item is queued to a workqueue, the target worker-pool is
+determined according to the queue parameters and workqueue attributes
+and appended on the shared worklist of the worker-pool.  For example,
+unless specifically overridden, a work item of a bound workqueue will
+be queued on the worklist of either normal or highpri worker-pool that
+is associated to the CPU the issuer is running on.
 
 For any worker pool implementation, managing the concurrency level
 (how many execution contexts are active) is an important issue.  cmwq
@@ -118,14 +117,14 @@
 Minimal to save resources and sufficient in that the system is used at
 its full capacity.
 
-Each thread-pool bound to an actual CPU implements concurrency
-management by hooking into the scheduler.  The thread-pool is notified
+Each worker-pool bound to an actual CPU implements concurrency
+management by hooking into the scheduler.  The worker-pool is notified
 whenever an active worker wakes up or sleeps and keeps track of the
 number of the currently runnable workers.  Generally, work items are
 not expected to hog a CPU and consume many cycles.  That means
 maintaining just enough concurrency to prevent work processing from
 stalling should be optimal.  As long as there are one or more runnable
-workers on the CPU, the thread-pool doesn't start execution of a new
+workers on the CPU, the worker-pool doesn't start execution of a new
 work, but, when the last running worker goes to sleep, it immediately
 schedules a new worker so that the CPU doesn't sit idle while there
 are pending work items.  This allows using a minimal number of workers
@@ -135,19 +134,20 @@
 for kthreads, so cmwq holds onto idle ones for a while before killing
 them.
 
-For an unbound wq, the above concurrency management doesn't apply and
-the thread-pools for the pseudo unbound CPU try to start executing all
-work items as soon as possible.  The responsibility of regulating
-concurrency level is on the users.  There is also a flag to mark a
-bound wq to ignore the concurrency management.  Please refer to the
-API section for details.
+For unbound workqueues, the number of backing pools is dynamic.
+Unbound workqueue can be assigned custom attributes using
+apply_workqueue_attrs() and workqueue will automatically create
+backing worker pools matching the attributes.  The responsibility of
+regulating concurrency level is on the users.  There is also a flag to
+mark a bound wq to ignore the concurrency management.  Please refer to
+the API section for details.
 
 Forward progress guarantee relies on that workers can be created when
 more execution contexts are necessary, which in turn is guaranteed
 through the use of rescue workers.  All work items which might be used
 on code paths that handle memory reclaim are required to be queued on
 wq's that have a rescue-worker reserved for execution under memory
-pressure.  Else it is possible that the thread-pool deadlocks waiting
+pressure.  Else it is possible that the worker-pool deadlocks waiting
 for execution contexts to free up.
 
 
@@ -166,25 +166,15 @@
 
 @flags:
 
-  WQ_NON_REENTRANT
-
-	By default, a wq guarantees non-reentrance only on the same
-	CPU.  A work item may not be executed concurrently on the same
-	CPU by multiple workers but is allowed to be executed
-	concurrently on multiple CPUs.  This flag makes sure
-	non-reentrance is enforced across all CPUs.  Work items queued
-	to a non-reentrant wq are guaranteed to be executed by at most
-	one worker system-wide at any given time.
-
   WQ_UNBOUND
 
-	Work items queued to an unbound wq are served by a special
-	gcwq which hosts workers which are not bound to any specific
-	CPU.  This makes the wq behave as a simple execution context
-	provider without concurrency management.  The unbound gcwq
-	tries to start execution of work items as soon as possible.
-	Unbound wq sacrifices locality but is useful for the following
-	cases.
+	Work items queued to an unbound wq are served by the special
+	woker-pools which host workers which are not bound to any
+	specific CPU.  This makes the wq behave as a simple execution
+	context provider without concurrency management.  The unbound
+	worker-pools try to start execution of work items as soon as
+	possible.  Unbound wq sacrifices locality but is useful for
+	the following cases.
 
 	* Wide fluctuation in the concurrency level requirement is
 	  expected and using bound wq may end up creating large number
@@ -209,10 +199,10 @@
   WQ_HIGHPRI
 
 	Work items of a highpri wq are queued to the highpri
-	thread-pool of the target gcwq.  Highpri thread-pools are
+	worker-pool of the target cpu.  Highpri worker-pools are
 	served by worker threads with elevated nice level.
 
-	Note that normal and highpri thread-pools don't interact with
+	Note that normal and highpri worker-pools don't interact with
 	each other.  Each maintain its separate pool of workers and
 	implements concurrency management among its workers.
 
@@ -221,7 +211,7 @@
 	Work items of a CPU intensive wq do not contribute to the
 	concurrency level.  In other words, runnable CPU intensive
 	work items will not prevent other work items in the same
-	thread-pool from starting execution.  This is useful for bound
+	worker-pool from starting execution.  This is useful for bound
 	work items which are expected to hog CPU cycles so that their
 	execution is regulated by the system scheduler.
 
@@ -233,6 +223,10 @@
 
 	This flag is meaningless for unbound wq.
 
+Note that the flag WQ_NON_REENTRANT no longer exists as all workqueues
+are now non-reentrant - any work item is guaranteed to be executed by
+at most one worker system-wide at any given time.
+
 @max_active:
 
 @max_active determines the maximum number of execution contexts per
@@ -254,9 +248,9 @@
 
 Some users depend on the strict execution ordering of ST wq.  The
 combination of @max_active of 1 and WQ_UNBOUND is used to achieve this
-behavior.  Work items on such wq are always queued to the unbound gcwq
-and only one work item can be active at any given time thus achieving
-the same ordering property as ST wq.
+behavior.  Work items on such wq are always queued to the unbound
+worker-pools and only one work item can be active at any given time thus
+achieving the same ordering property as ST wq.
 
 
 5. Example Execution Scenarios
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index e9e8ddb..1228b22 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -176,6 +176,11 @@
 
   acpi=noirq	Don't route interrupts
 
+  acpi=nocmcff	Disable firmware first mode for corrected errors. This
+		disables parsing the HEST CMC error source to check if
+		firmware has set the FF flag. This may result in
+		duplicate corrected error reports.
+
 PCI
 
   pci=off		Don't use PCI
diff --git a/MAINTAINERS b/MAINTAINERS
index 229c66b..4bb5689 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -595,6 +595,7 @@
 F:	sound/soc/codecs/adau*
 F:	sound/soc/codecs/adav*
 F:	sound/soc/codecs/ad1*
+F:	sound/soc/codecs/ad7*
 F:	sound/soc/codecs/ssm*
 F:	sound/soc/codecs/sigmadsp.*
 
@@ -813,7 +814,7 @@
 F:	drivers/dma/sirf-dma.c
 F:	drivers/i2c/busses/i2c-sirf.c
 F:	drivers/mmc/host/sdhci-sirf.c
-F:	drivers/pinctrl/pinctrl-sirf.c
+F:	drivers/pinctrl/sirf/
 F:	drivers/spi/spi-sirf.c
 
 ARM/EBSA110 MACHINE SUPPORT
@@ -1547,6 +1548,13 @@
 S:	Maintained
 F:	drivers/net/wireless/atmel*
 
+ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
+M:      Bradley Grove <linuxdrivers@attotech.com>
+L:      linux-scsi@vger.kernel.org
+W:      http://www.attotech.com
+S:      Supported
+F:      drivers/scsi/esas2r
+
 AUDIT SUBSYSTEM
 M:	Al Viro <viro@zeniv.linux.org.uk>
 M:	Eric Paris <eparis@redhat.com>
@@ -1823,6 +1831,12 @@
 S:	Supported
 F:	drivers/scsi/bnx2fc/
 
+BROADCOM BNX2I 1/10 GIGABIT iSCSI DRIVER
+M:	Eddie Wai <eddie.wai@broadcom.com>
+L:	linux-scsi@vger.kernel.org
+S:	Supported
+F:	drivers/scsi/bnx2i/
+
 BROADCOM SPECIFIC AMBA DRIVER (BCMA)
 M:	Rafał Miłecki <zajec5@gmail.com>
 L:	linux-wireless@vger.kernel.org
@@ -2112,6 +2126,13 @@
 S:	Maintained
 F:	include/linux/clk.h
 
+CLOCKSOURCE, CLOCKEVENT DRIVERS
+M:	Daniel Lezcano <daniel.lezcano@linaro.org>
+M:	Thomas Gleixner <tglx@linutronix.de>
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
+S:	Supported
+F:	drivers/clocksource
+
 CISCO FCOE HBA DRIVER
 M:	Hiral Patel <hiralpat@cisco.com>
 M:	Suma Ramars <sramars@cisco.com>
@@ -5884,7 +5905,7 @@
 F:	include/linux/i2c-omap.h
 
 OMAP DEVICE TREE SUPPORT
-M:	Benoît Cousson <b-cousson@ti.com>
+M:	Benoît Cousson <bcousson@baylibre.com>
 M:	Tony Lindgren <tony@atomide.com>
 L:	linux-omap@vger.kernel.org
 L:	devicetree@vger.kernel.org
@@ -5964,14 +5985,14 @@
 F:	drivers/char/hw_random/omap-rng.c
 
 OMAP HWMOD SUPPORT
-M:	Benoît Cousson <b-cousson@ti.com>
+M:	Benoît Cousson <bcousson@baylibre.com>
 M:	Paul Walmsley <paul@pwsan.com>
 L:	linux-omap@vger.kernel.org
 S:	Maintained
 F:	arch/arm/mach-omap2/omap_hwmod.*
 
 OMAP HWMOD DATA FOR OMAP4-BASED DEVICES
-M:	Benoît Cousson <b-cousson@ti.com>
+M:	Benoît Cousson <bcousson@baylibre.com>
 L:	linux-omap@vger.kernel.org
 S:	Maintained
 F:	arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -6066,7 +6087,7 @@
 M:	Pawel Moll <pawel.moll@arm.com>
 M:	Mark Rutland <mark.rutland@arm.com>
 M:	Stephen Warren <swarren@wwwdotorg.org>
-M:	Ian Campbell <ian.campbell@citrix.com>
+M:	Ian Campbell <ijc+devicetree@hellion.org.uk>
 L:	devicetree@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/
@@ -6676,11 +6697,11 @@
 F:	drivers/scsi/qla2xxx/
 
 QLOGIC QLA4XXX iSCSI DRIVER
-M:	Ravi Anand <ravi.anand@qlogic.com>
 M:	Vikas Chaudhary <vikas.chaudhary@qlogic.com>
 M:	iscsi-driver@qlogic.com
 L:	linux-scsi@vger.kernel.org
 S:	Supported
+F:	Documentation/scsi/LICENSE.qla4xxx
 F:	drivers/scsi/qla4xxx/
 
 QLOGIC QLA3XXX NETWORK DRIVER
@@ -7143,7 +7164,7 @@
 F:	include/linux/mmc/dw_mmc.h
 F:	drivers/mmc/host/dw_mmc*
 
-TIMEKEEPING, NTP
+TIMEKEEPING, CLOCKSOURCE CORE, NTP
 M:	John Stultz <john.stultz@linaro.org>
 M:	Thomas Gleixner <tglx@linutronix.de>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
@@ -7156,7 +7177,6 @@
 F:	kernel/time/clocksource.c
 F:	kernel/time/time*.c
 F:	kernel/time/ntp.c
-F:	drivers/clocksource
 
 TLG2300 VIDEO4LINUX-2 DRIVER
 M:	Huang Shijie <shijie8@gmail.com>
@@ -7675,6 +7695,17 @@
 F:	include/uapi/sound/
 F:	sound/
 
+SOUND - COMPRESSED AUDIO
+M:	Vinod Koul <vinod.koul@intel.com>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
+S:	Supported
+F:	Documentation/sound/alsa/compress_offload.txt
+F:	include/sound/compress_driver.h
+F:	include/uapi/sound/compress_*
+F:	sound/core/compress_offload.c
+F:	sound/soc/soc-compress.c
+
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 M:	Liam Girdwood <lgirdwood@gmail.com>
 M:	Mark Brown <broonie@kernel.org>
@@ -7682,6 +7713,7 @@
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:	http://alsa-project.org/main/index.php/ASoC
 S:	Supported
+F:	Documentation/sound/alsa/soc/
 F:	sound/soc/
 F:	include/sound/soc*
 
@@ -7890,11 +7922,11 @@
 F:	drivers/staging/nvec/
 
 STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON)
-M:	Andres Salomon <dilinger@queued.net>
-M:	Chris Ball <cjb@laptop.org>
+M:	Jens Frederich <jfrederich@gmail.com>
+M:	Daniel Drake <dsd@laptop.org>
 M:	Jon Nettleton <jon.nettleton@gmail.com>
 W:	http://wiki.laptop.org/go/DCON
-S:	Odd Fixes
+S:	Maintained
 F:	drivers/staging/olpc_dcon/
 
 STAGING - OZMO DEVICES USB OVER WIFI DRIVER
@@ -8803,7 +8835,6 @@
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
 S:	Supported
 F:	Documentation/usb/
-F:	drivers/net/usb/
 F:	drivers/usb/
 F:	include/linux/usb.h
 F:	include/linux/usb/
@@ -9247,9 +9278,9 @@
 
 XEN HYPERVISOR INTERFACE
 M:	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-M:	Jeremy Fitzhardinge <jeremy@goop.org>
-L:	xen-devel@lists.xensource.com (moderated for non-subscribers)
-L:	virtualization@lists.linux-foundation.org
+M:	Boris Ostrovsky <boris.ostrovsky@oracle.com>
+M:	David Vrabel <david.vrabel@citrix.com>
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/x86/xen/
 F:	drivers/*/xen-*front.c
@@ -9260,35 +9291,35 @@
 
 XEN HYPERVISOR ARM
 M:	Stefano Stabellini <stefano.stabellini@eu.citrix.com>
-L:	xen-devel@lists.xensource.com (moderated for non-subscribers)
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/arm/xen/
 F:	arch/arm/include/asm/xen/
 
 XEN HYPERVISOR ARM64
 M:	Stefano Stabellini <stefano.stabellini@eu.citrix.com>
-L:	xen-devel@lists.xensource.com (moderated for non-subscribers)
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/arm64/xen/
 F:	arch/arm64/include/asm/xen/
 
 XEN NETWORK BACKEND DRIVER
 M:	Ian Campbell <ian.campbell@citrix.com>
-L:	xen-devel@lists.xensource.com (moderated for non-subscribers)
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 L:	netdev@vger.kernel.org
 S:	Supported
 F:	drivers/net/xen-netback/*
 
 XEN PCI SUBSYSTEM
 M:	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-L:	xen-devel@lists.xensource.com (moderated for non-subscribers)
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/x86/pci/*xen*
 F:	drivers/pci/*xen*
 
 XEN SWIOTLB SUBSYSTEM
 M:	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-L:	xen-devel@lists.xensource.com (moderated for non-subscribers)
+L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/x86/xen/*swiotlb*
 F:	drivers/xen/*swiotlb*
diff --git a/Makefile b/Makefile
index a5a55f4..fe8204b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 11
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION =
 NAME = Linux for Workgroups
 
 # *DOCUMENTATION*
diff --git a/arch/arc/lib/strchr-700.S b/arch/arc/lib/strchr-700.S
index 99c1047..9c548c7 100644
--- a/arch/arc/lib/strchr-700.S
+++ b/arch/arc/lib/strchr-700.S
@@ -39,9 +39,18 @@
 	ld.a	r2,[r0,4]
 	sub	r12,r6,r7
 	bic	r12,r12,r6
+#ifdef __LITTLE_ENDIAN__
 	and	r7,r12,r4
 	breq	r7,0,.Loop ; For speed, we want this branch to be unaligned.
 	b	.Lfound_char ; Likewise this one.
+#else
+	and	r12,r12,r4
+	breq	r12,0,.Loop ; For speed, we want this branch to be unaligned.
+	lsr_s	r12,r12,7
+	bic 	r2,r7,r6
+	b.d	.Lfound_char_b
+	and_s	r2,r2,r12
+#endif
 ; /* We require this code address to be unaligned for speed...  */
 .Laligned:
 	ld_s	r2,[r0]
@@ -95,6 +104,7 @@
 	lsr	r7,r7,7
 
 	bic	r2,r7,r6
+.Lfound_char_b:
 	norm	r2,r2
 	sub_s	r0,r0,4
 	asr_s	r2,r2,3
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 43594d5..cd5c1c9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2064,8 +2064,7 @@
 
 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
-	  initially work for you.  It may help to enable device hotplugging
-	  support.
+	  initially work for you.
 
 config ATAGS_PROC
 	bool "Export atags in procfs"
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 444b4ed..d318987d 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -120,6 +120,35 @@
 			status = "okay";
 		};
 
+		musb: usb@47400000 {
+			status = "okay";
+
+			control@44e10000 {
+				status = "okay";
+			};
+
+			usb-phy@47401300 {
+				status = "okay";
+			};
+
+			usb-phy@47401b00 {
+				status = "okay";
+			};
+
+			usb@47401000 {
+				status = "okay";
+			};
+
+			usb@47401800 {
+				status = "okay";
+				dr_mode = "host";
+			};
+
+			dma-controller@07402000  {
+				status = "okay";
+			};
+		};
+
 		i2c0: i2c@44e0b000 {
 			pinctrl-names = "default";
 			pinctrl-0 = <&i2c0_pins>;
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 3aee1a4..e8ec875 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -171,6 +171,35 @@
 			};
 		};
 
+		musb: usb@47400000 {
+			status = "okay";
+
+			control@44e10000 {
+				status = "okay";
+			};
+
+			usb-phy@47401300 {
+				status = "okay";
+			};
+
+			usb-phy@47401b00 {
+				status = "okay";
+			};
+
+			usb@47401000 {
+				status = "okay";
+			};
+
+			usb@47401800 {
+				status = "okay";
+				dr_mode = "host";
+			};
+
+			dma-controller@07402000  {
+				status = "okay";
+			};
+		};
+
 		i2c1: i2c@4802a000 {
 			pinctrl-names = "default";
 			pinctrl-0 = <&i2c1_pins>;
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 0c8ad17..4f339fa 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -14,6 +14,7 @@
 /dts-v1/;
 
 #include "am33xx.dtsi"
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "TI AM335x EVM-SK";
@@ -207,6 +208,22 @@
 			};
 		};
 
+		musb: usb@47400000 {
+			status = "okay";
+
+			control@44e10000 {
+				status = "okay";
+			};
+
+			usb-phy@47401300 {
+				status = "okay";
+			};
+
+			usb@47401000 {
+				status = "okay";
+			};
+		};
+
 		epwmss2: epwmss@48304000 {
 			status = "okay";
 
@@ -298,7 +315,7 @@
 
 	backlight {
 		compatible = "pwm-backlight";
-		pwms = <&ecap2 0 50000 1>;
+		pwms = <&ecap2 0 50000 PWM_POLARITY_INVERTED>;
 		brightness-levels = <0 58 61 66 75 90 125 170 255>;
 		default-brightness-level = <8>;
 	};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 38b446b..f9c5da9 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -26,6 +26,10 @@
 		serial5 = &uart5;
 		d_can0 = &dcan0;
 		d_can1 = &dcan1;
+		usb0 = &usb0;
+		usb1 = &usb1;
+		phy0 = &usb0_phy;
+		phy1 = &usb1_phy;
 	};
 
 	cpus {
@@ -333,21 +337,132 @@
 			status = "disabled";
 		};
 
-		usb@47400000 {
-			compatible = "ti,musb-am33xx";
-			reg = <0x47400000 0x1000	/* usbss */
-			       0x47401000 0x800		/* musb instance 0 */
-			       0x47401800 0x800>;	/* musb instance 1 */
-			interrupts = <17		/* usbss */
-				      18		/* musb instance 0 */
-				      19>;		/* musb instance 1 */
-			multipoint = <1>;
-			num-eps = <16>;
-			ram-bits = <12>;
-			port0-mode = <3>;
-			port1-mode = <3>;
-			power = <250>;
+		usb: usb@47400000 {
+			compatible = "ti,am33xx-usb";
+			reg = <0x47400000 0x1000>;
+			ranges;
+			#address-cells = <1>;
+			#size-cells = <1>;
 			ti,hwmods = "usb_otg_hs";
+			status = "disabled";
+
+			ctrl_mod: control@44e10000 {
+				compatible = "ti,am335x-usb-ctrl-module";
+				reg = <0x44e10620 0x10
+					0x44e10648 0x4>;
+				reg-names = "phy_ctrl", "wakeup";
+				status = "disabled";
+			};
+
+			usb0_phy: usb-phy@47401300 {
+				compatible = "ti,am335x-usb-phy";
+				reg = <0x47401300 0x100>;
+				reg-names = "phy";
+				status = "disabled";
+				ti,ctrl_mod = <&ctrl_mod>;
+			};
+
+			usb0: usb@47401000 {
+				compatible = "ti,musb-am33xx";
+				status = "disabled";
+				reg = <0x47401400 0x400
+					0x47401000 0x200>;
+				reg-names = "mc", "control";
+
+				interrupts = <18>;
+				interrupt-names = "mc";
+				dr_mode = "otg";
+				mentor,multipoint = <1>;
+				mentor,num-eps = <16>;
+				mentor,ram-bits = <12>;
+				mentor,power = <500>;
+				phys = <&usb0_phy>;
+
+				dmas = <&cppi41dma  0 0 &cppi41dma  1 0
+					&cppi41dma  2 0 &cppi41dma  3 0
+					&cppi41dma  4 0 &cppi41dma  5 0
+					&cppi41dma  6 0 &cppi41dma  7 0
+					&cppi41dma  8 0 &cppi41dma  9 0
+					&cppi41dma 10 0 &cppi41dma 11 0
+					&cppi41dma 12 0 &cppi41dma 13 0
+					&cppi41dma 14 0 &cppi41dma  0 1
+					&cppi41dma  1 1 &cppi41dma  2 1
+					&cppi41dma  3 1 &cppi41dma  4 1
+					&cppi41dma  5 1 &cppi41dma  6 1
+					&cppi41dma  7 1 &cppi41dma  8 1
+					&cppi41dma  9 1 &cppi41dma 10 1
+					&cppi41dma 11 1 &cppi41dma 12 1
+					&cppi41dma 13 1 &cppi41dma 14 1>;
+				dma-names =
+					"rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+					"rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+					"rx14", "rx15",
+					"tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+					"tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+					"tx14", "tx15";
+			};
+
+			usb1_phy: usb-phy@47401b00 {
+				compatible = "ti,am335x-usb-phy";
+				reg = <0x47401b00 0x100>;
+				reg-names = "phy";
+				status = "disabled";
+				ti,ctrl_mod = <&ctrl_mod>;
+			};
+
+			usb1: usb@47401800 {
+				compatible = "ti,musb-am33xx";
+				status = "disabled";
+				reg = <0x47401c00 0x400
+					0x47401800 0x200>;
+				reg-names = "mc", "control";
+				interrupts = <19>;
+				interrupt-names = "mc";
+				dr_mode = "otg";
+				mentor,multipoint = <1>;
+				mentor,num-eps = <16>;
+				mentor,ram-bits = <12>;
+				mentor,power = <500>;
+				phys = <&usb1_phy>;
+
+				dmas = <&cppi41dma 15 0 &cppi41dma 16 0
+					&cppi41dma 17 0 &cppi41dma 18 0
+					&cppi41dma 19 0 &cppi41dma 20 0
+					&cppi41dma 21 0 &cppi41dma 22 0
+					&cppi41dma 23 0 &cppi41dma 24 0
+					&cppi41dma 25 0 &cppi41dma 26 0
+					&cppi41dma 27 0 &cppi41dma 28 0
+					&cppi41dma 29 0 &cppi41dma 15 1
+					&cppi41dma 16 1 &cppi41dma 17 1
+					&cppi41dma 18 1 &cppi41dma 19 1
+					&cppi41dma 20 1 &cppi41dma 21 1
+					&cppi41dma 22 1 &cppi41dma 23 1
+					&cppi41dma 24 1 &cppi41dma 25 1
+					&cppi41dma 26 1 &cppi41dma 27 1
+					&cppi41dma 28 1 &cppi41dma 29 1>;
+				dma-names =
+					"rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7",
+					"rx8", "rx9", "rx10", "rx11", "rx12", "rx13",
+					"rx14", "rx15",
+					"tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7",
+					"tx8", "tx9", "tx10", "tx11", "tx12", "tx13",
+					"tx14", "tx15";
+			};
+
+			cppi41dma: dma-controller@07402000 {
+				compatible = "ti,am3359-cppi41";
+				reg =  <0x47400000 0x1000
+					0x47402000 0x1000
+					0x47403000 0x1000
+					0x47404000 0x4000>;
+				reg-names = "glue", "controller", "scheduler", "queuemgr";
+				interrupts = <17>;
+				interrupt-names = "glue";
+				#dma-cells = <2>;
+				#dma-channels = <30>;
+				#dma-requests = <256>;
+				status = "disabled";
+			};
 		};
 
 		epwmss0: epwmss@48300000 {
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index d59b70c..3d77dbe 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -14,11 +14,11 @@
 	compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9";
 
 	chosen {
-		bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
+		bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
 	};
 
 	memory {
-		reg = <0x20000000 0x10000000>;
+		reg = <0x20000000 0x8000000>;
 	};
 
 	clocks {
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
index b753855..49e3c45 100644
--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -94,8 +94,9 @@
 
 		usb0: ohci@00600000 {
 			status = "okay";
-			num-ports = <2>;
-			atmel,vbus-gpio = <&pioD 19 GPIO_ACTIVE_LOW
+			num-ports = <3>;
+			atmel,vbus-gpio = <0 /* &pioD 18 GPIO_ACTIVE_LOW *//* Activate to have access to port A */
+					   &pioD 19 GPIO_ACTIVE_LOW
 					   &pioD 20 GPIO_ACTIVE_LOW
 					  >;
 		};
diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
index a0f2721..8678e0c 100644
--- a/arch/arm/boot/dts/atlas6.dtsi
+++ b/arch/arm/boot/dts/atlas6.dtsi
@@ -329,6 +329,12 @@
 						sirf,function = "uart0";
 					};
 				};
+				uart0_noflow_pins_a: uart0@1 {
+					uart {
+						sirf,pins = "uart0_nostreamctrlgrp";
+						sirf,function = "uart0_nostreamctrl";
+					};
+				};
 				uart1_pins_a: uart1@0 {
 					uart {
 						sirf,pins = "uart1grp";
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index ef57277..376090f 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -405,7 +405,7 @@
 	};
 
 	i2s0: i2s@03830000 {
-		compatible = "samsung,i2s-v5";
+		compatible = "samsung,s5pv210-i2s";
 		reg = <0x03830000 0x100>;
 		dmas = <&pdma0 10
 			&pdma0 9
@@ -415,16 +415,13 @@
 			<&clock_audss EXYNOS_I2S_BUS>,
 			<&clock_audss EXYNOS_SCLK_I2S>;
 		clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
-		samsung,supports-6ch;
-		samsung,supports-rstclr;
-		samsung,supports-secdai;
 		samsung,idma-addr = <0x03000000>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&i2s0_bus>;
 	};
 
 	i2s1: i2s@12D60000 {
-		compatible = "samsung,i2s-v5";
+		compatible = "samsung,s3c6410-i2s";
 		reg = <0x12D60000 0x100>;
 		dmas = <&pdma1 12
 			&pdma1 11>;
@@ -436,7 +433,7 @@
 	};
 
 	i2s2: i2s@12D70000 {
-		compatible = "samsung,i2s-v5";
+		compatible = "samsung,s3c6410-i2s";
 		reg = <0x12D70000 0x100>;
 		dmas = <&pdma0 12
 			&pdma0 11>;
diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
index ff7f5d8..586134e 100644
--- a/arch/arm/boot/dts/exynos5440.dtsi
+++ b/arch/arm/boot/dts/exynos5440.dtsi
@@ -248,6 +248,7 @@
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 0 0>;
 		interrupt-map = <0x0 0 &gic 53>;
+		num-lanes = <4>;
 	};
 
 	pcie@2a0000 {
@@ -267,5 +268,6 @@
 		#interrupt-cells = <1>;
 		interrupt-map-mask = <0 0 0 0>;
 		interrupt-map = <0x0 0 &gic 56>;
+		num-lanes = <4>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts
index e035f46..15715d9 100644
--- a/arch/arm/boot/dts/imx28-evk.dts
+++ b/arch/arm/boot/dts/imx28-evk.dts
@@ -220,6 +220,7 @@
 			auart0: serial@8006a000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&auart0_pins_a>;
+				fsl,uart-has-rtscts;
 				status = "okay";
 			};
 
diff --git a/arch/arm/boot/dts/msm8660-surf.dts b/arch/arm/boot/dts/msm8660-surf.dts
index cdc010e..386d428 100644
--- a/arch/arm/boot/dts/msm8660-surf.dts
+++ b/arch/arm/boot/dts/msm8660-surf.dts
@@ -38,7 +38,7 @@
 	};
 
 	serial@19c40000 {
-		compatible = "qcom,msm-hsuart", "qcom,msm-uart";
+		compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
 		reg = <0x19c40000 0x1000>,
 		      <0x19c00000 0x1000>;
 		interrupts = <0 195 0x0>;
diff --git a/arch/arm/boot/dts/msm8960-cdp.dts b/arch/arm/boot/dts/msm8960-cdp.dts
index 9c1167b0..93e9f7e 100644
--- a/arch/arm/boot/dts/msm8960-cdp.dts
+++ b/arch/arm/boot/dts/msm8960-cdp.dts
@@ -38,7 +38,7 @@
 	};
 
 	serial@16440000 {
-		compatible = "qcom,msm-hsuart", "qcom,msm-uart";
+		compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
 		reg = <0x16440000 0x1000>,
 		      <0x16400000 0x1000>;
 		interrupts = <0 154 0x0>;
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index e643620..07be2cd 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -644,7 +644,7 @@
 			utmi-mode = <2>;
 			ranges;
 			dwc3@4a030000 {
-				compatible = "synopsys,dwc3";
+				compatible = "snps,dwc3";
 				reg = <0x4a030000 0x1000>;
 				interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
 				usb-phy = <&usb2_phy>, <&usb3_phy>;
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 365760b..c824253 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -566,7 +566,6 @@
 
 	usb@c5000000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
 		dr_mode = "otg";
 	};
 
@@ -830,6 +829,8 @@
 			regulator-max-microvolt = <5000000>;
 			enable-active-high;
 			gpio = <&gpio 24 0>; /* PD0 */
+			regulator-always-on;
+			regulator-boot-on;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
index ed4b901..1e9d33a 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -312,7 +312,6 @@
 
 	usb@c5000000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb-phy@c5000000 {
@@ -412,6 +411,8 @@
 			regulator-max-microvolt = <5000000>;
 			enable-active-high;
 			gpio = <&gpio 170 0>; /* PV2 */
+			regulator-always-on;
+			regulator-boot-on;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
index ab67c94..c703197 100644
--- a/arch/arm/boot/dts/tegra20-whistler.dts
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -509,7 +509,6 @@
 
 	usb@c5000000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&tca6416 0 GPIO_ACTIVE_HIGH>;
 	};
 
 	usb-phy@c5000000 {
@@ -519,7 +518,6 @@
 
 	usb@c5008000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&tca6416 1 GPIO_ACTIVE_HIGH>;
 	};
 
 	usb-phy@c5008000 {
@@ -588,6 +586,8 @@
 			regulator-max-microvolt = <5000000>;
 			enable-active-high;
 			gpio = <&tca6416 0 0>; /* GPIO_PMU0 */
+			regulator-always-on;
+			regulator-boot-on;
 		};
 
 		vbus3_reg: regulator@3 {
@@ -598,6 +598,8 @@
 			regulator-max-microvolt = <5000000>;
 			enable-active-high;
 			gpio = <&tca6416 1 0>; /* GPIO_PMU1 */
+			regulator-always-on;
+			regulator-boot-on;
 		};
 	};
 
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 9653fd8..e457083 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -477,13 +477,13 @@
 			 <&tegra_car TEGRA20_CLK_USBD>;
 		clock-names = "reg", "pll_u", "timer", "utmi-pads";
 		nvidia,has-legacy-mode;
-		hssync_start_delay = <9>;
-		idle_wait_delay = <17>;
-		elastic_limit = <16>;
-		term_range_adj = <6>;
-		xcvr_setup = <9>;
-		xcvr_lsfslew = <1>;
-		xcvr_lsrslew = <1>;
+		nvidia,hssync-start-delay = <9>;
+		nvidia,idle-wait-delay = <17>;
+		nvidia,elastic-limit = <16>;
+		nvidia,term-range-adj = <6>;
+		nvidia,xcvr-setup = <9>;
+		nvidia,xcvr-lsfslew = <1>;
+		nvidia,xcvr-lsrslew = <1>;
 		status = "disabled";
 	};
 
@@ -527,13 +527,13 @@
 			 <&tegra_car TEGRA20_CLK_CLK_M>,
 			 <&tegra_car TEGRA20_CLK_USBD>;
 		clock-names = "reg", "pll_u", "timer", "utmi-pads";
-		hssync_start_delay = <9>;
-		idle_wait_delay = <17>;
-		elastic_limit = <16>;
-		term_range_adj = <6>;
-		xcvr_setup = <9>;
-		xcvr_lsfslew = <2>;
-		xcvr_lsrslew = <2>;
+		nvidia,hssync-start-delay = <9>;
+		nvidia,idle-wait-delay = <17>;
+		nvidia,elastic-limit = <16>;
+		nvidia,term-range-adj = <6>;
+		nvidia,xcvr-setup = <9>;
+		nvidia,xcvr-lsfslew = <2>;
+		nvidia,xcvr-lsrslew = <2>;
 		status = "disabled";
 	};
 
diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts
index 90e913f..7a563d2 100644
--- a/arch/arm/boot/dts/wm8850-w70v2.dts
+++ b/arch/arm/boot/dts/wm8850-w70v2.dts
@@ -11,13 +11,14 @@
 
 /dts-v1/;
 /include/ "wm8850.dtsi"
+#include <dt-bindings/pwm/pwm.h>
 
 / {
 	model = "Wondermedia WM8850-W70v2 Tablet";
 
 	backlight {
 		compatible = "pwm-backlight";
-		pwms = <&pwm 0 50000 1>;	/* duty inverted */
+		pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
 
 		brightness-levels = <0 40 60 80 100 130 190 255>;
 		default-brightness-level = <5>;
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index 62e968c..1f36b82 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -104,6 +104,7 @@
 CONFIG_VLAN_8021Q=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CMA=y
+CONFIG_DMA_CMA=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 5339e6a..5465f56 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -78,6 +78,7 @@
 CONFIG_MAC80211_RC_DEFAULT_PID=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CMA=y
+CONFIG_DMA_CMA=y
 CONFIG_CONNECTOR=y
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 1effb43..92d0a149 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -79,6 +79,7 @@
 CONFIG_DEVTMPFS_MOUNT=y
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 CONFIG_CMA=y
+CONFIG_DMA_CMA=y
 CONFIG_MTD=y
 CONFIG_MTD_M25P80=y
 CONFIG_PROC_DEVICETREE=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index e406d57..5665134 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -17,7 +17,8 @@
  * nicely work out which register we want, and chuck away the rest of
  * the code. At least it does so with a recent GCC (4.6.3).
  */
-static inline void arch_timer_reg_write(const int access, const int reg, u32 val)
+static __always_inline
+void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
 {
 	if (access == ARCH_TIMER_PHYS_ACCESS) {
 		switch (reg) {
@@ -28,9 +29,7 @@
 			asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
 			break;
 		}
-	}
-
-	if (access == ARCH_TIMER_VIRT_ACCESS) {
+	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
 		switch (reg) {
 		case ARCH_TIMER_REG_CTRL:
 			asm volatile("mcr p15, 0, %0, c14, c3, 1" : : "r" (val));
@@ -44,7 +43,8 @@
 	isb();
 }
 
-static inline u32 arch_timer_reg_read(const int access, const int reg)
+static __always_inline
+u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
 {
 	u32 val = 0;
 
@@ -57,9 +57,7 @@
 			asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
 			break;
 		}
-	}
-
-	if (access == ARCH_TIMER_VIRT_ACCESS) {
+	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
 		switch (reg) {
 		case ARCH_TIMER_REG_CTRL:
 			asm volatile("mrc p15, 0, %0, c14, c3, 1" : "=r" (val));
diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h
index 3ed37b4..e072bb2 100644
--- a/arch/arm/include/asm/dma-contiguous.h
+++ b/arch/arm/include/asm/dma-contiguous.h
@@ -2,7 +2,7 @@
 #define ASMARM_DMA_CONTIGUOUS_H
 
 #ifdef __KERNEL__
-#ifdef CONFIG_CMA
+#ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
 #include <asm-generic/dma-contiguous.h>
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 472ac70..9b28c41 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -64,7 +64,7 @@
 
 static inline void kvm_set_pte(pte_t *pte, pte_t new_pte)
 {
-	pte_val(*pte) = new_pte;
+	*pte = new_pte;
 	/*
 	 * flush_pmd_entry just takes a void pointer and cleans the necessary
 	 * cache entries, so we can reuse the function for ptes.
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 261fcc8..88e14d7 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -525,11 +525,6 @@
 			 * Assign resources.
 			 */
 			pci_bus_assign_resources(bus);
-
-			/*
-			 * Enable bridges
-			 */
-			pci_enable_bridges(bus);
 		}
 
 		/*
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 5859c8b..2ee8a17 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -169,6 +169,11 @@
 	}
 }
 
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+	return (phys_id & MPIDR_HWID_BITMASK) == cpu_logical_map(cpu);
+}
+
 /**
  * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
  * @dt_phys: physical address of dt blob
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index fc79202..918875d 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -89,7 +89,8 @@
 
 	memcpy(base + offset, start, length);
 	if (!cache_is_vipt_nonaliasing())
-		flush_icache_range(base + offset, offset + length);
+		flush_icache_range((unsigned long)base + offset, offset +
+				   length);
 	flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
 }
 
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index d7c82df..57221e3 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -82,6 +82,7 @@
 	crash_save_cpu(&regs, smp_processor_id());
 	flush_cache_all();
 
+	set_cpu_online(smp_processor_id(), false);
 	atomic_dec(&waiting_for_crash_ipi);
 	while (1)
 		cpu_relax();
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index c5a5954..85a8737 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -74,12 +74,8 @@
 	{NULL, },
 };
 
-struct cpu_capacity {
-	unsigned long hwid;
-	unsigned long capacity;
-};
-
-struct cpu_capacity *cpu_capacity;
+unsigned long *__cpu_capacity;
+#define cpu_capacity(cpu)	__cpu_capacity[cpu]
 
 unsigned long middle_capacity = 1;
 
@@ -100,15 +96,19 @@
 	unsigned long capacity = 0;
 	int alloc_size, cpu = 0;
 
-	alloc_size = nr_cpu_ids * sizeof(struct cpu_capacity);
-	cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
+	alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity);
+	__cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
 
-	while ((cn = of_find_node_by_type(cn, "cpu"))) {
-		const u32 *rate, *reg;
+	for_each_possible_cpu(cpu) {
+		const u32 *rate;
 		int len;
 
-		if (cpu >= num_possible_cpus())
-			break;
+		/* too early to use cpu->of_node */
+		cn = of_get_cpu_node(cpu, NULL);
+		if (!cn) {
+			pr_err("missing device node for CPU %d\n", cpu);
+			continue;
+		}
 
 		for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++)
 			if (of_device_is_compatible(cn, cpu_eff->compatible))
@@ -124,12 +124,6 @@
 			continue;
 		}
 
-		reg = of_get_property(cn, "reg", &len);
-		if (!reg || len != 4) {
-			pr_err("%s missing reg property\n", cn->full_name);
-			continue;
-		}
-
 		capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency;
 
 		/* Save min capacity of the system */
@@ -140,13 +134,9 @@
 		if (capacity > max_capacity)
 			max_capacity = capacity;
 
-		cpu_capacity[cpu].capacity = capacity;
-		cpu_capacity[cpu++].hwid = be32_to_cpup(reg);
+		cpu_capacity(cpu) = capacity;
 	}
 
-	if (cpu < num_possible_cpus())
-		cpu_capacity[cpu].hwid = (unsigned long)(-1);
-
 	/* If min and max capacities are equals, we bypass the update of the
 	 * cpu_scale because all CPUs have the same capacity. Otherwise, we
 	 * compute a middle_capacity factor that will ensure that the capacity
@@ -154,9 +144,7 @@
 	 * SCHED_POWER_SCALE, which is the default value, but with the
 	 * constraint explained near table_efficiency[].
 	 */
-	if (min_capacity == max_capacity)
-		cpu_capacity[0].hwid = (unsigned long)(-1);
-	else if (4*max_capacity < (3*(max_capacity + min_capacity)))
+	if (4*max_capacity < (3*(max_capacity + min_capacity)))
 		middle_capacity = (min_capacity + max_capacity)
 				>> (SCHED_POWER_SHIFT+1);
 	else
@@ -170,23 +158,12 @@
  * boot. The update of all CPUs is in O(n^2) for heteregeneous system but the
  * function returns directly for SMP system.
  */
-void update_cpu_power(unsigned int cpu, unsigned long hwid)
+void update_cpu_power(unsigned int cpu)
 {
-	unsigned int idx = 0;
-
-	/* look for the cpu's hwid in the cpu capacity table */
-	for (idx = 0; idx < num_possible_cpus(); idx++) {
-		if (cpu_capacity[idx].hwid == hwid)
-			break;
-
-		if (cpu_capacity[idx].hwid == -1)
-			return;
-	}
-
-	if (idx == num_possible_cpus())
+	if (!cpu_capacity(cpu))
 		return;
 
-	set_power_scale(cpu, cpu_capacity[idx].capacity / middle_capacity);
+	set_power_scale(cpu, cpu_capacity(cpu) / middle_capacity);
 
 	printk(KERN_INFO "CPU%u: update cpu_power %lu\n",
 		cpu, arch_scale_freq_power(NULL, cpu));
@@ -194,7 +171,7 @@
 
 #else
 static inline void parse_dt_topology(void) {}
-static inline void update_cpu_power(unsigned int cpuid, unsigned int mpidr) {}
+static inline void update_cpu_power(unsigned int cpuid) {}
 #endif
 
  /*
@@ -281,7 +258,7 @@
 
 	update_siblings_masks(cpuid);
 
-	update_cpu_power(cpuid, mpidr & MPIDR_HWID_BITMASK);
+	update_cpu_power(cpuid);
 
 	printk(KERN_INFO "CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
 		cpuid, cpu_topology[cpuid].thread_id,
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 741f66a..9c697db 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -219,6 +219,10 @@
 	return -EINVAL;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				   struct kvm_memory_slot *memslot,
 				   struct kvm_userspace_memory_region *mem,
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 4a51990..db9cf69 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -146,7 +146,11 @@
 #define access_pmintenclr pm_fake
 
 /* Architected CP15 registers.
- * Important: Must be sorted ascending by CRn, CRM, Op1, Op2
+ * CRn denotes the primary register number, but is copied to the CRm in the
+ * user space API for 64-bit register access in line with the terminology used
+ * in the ARM ARM.
+ * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
+ *            registers preceding 32-bit ones.
  */
 static const struct coproc_reg cp15_regs[] = {
 	/* CSSELR: swapped by interrupt.S. */
@@ -154,8 +158,8 @@
 			NULL, reset_unknown, c0_CSSELR },
 
 	/* TTBR0/TTBR1: swapped by interrupt.S. */
-	{ CRm( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
-	{ CRm( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
+	{ CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
+	{ CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
 
 	/* TTBCR: swapped by interrupt.S. */
 	{ CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
@@ -182,7 +186,7 @@
 			NULL, reset_unknown, c6_IFAR },
 
 	/* PAR swapped by interrupt.S */
-	{ CRn( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
+	{ CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
 
 	/*
 	 * DC{C,I,CI}SW operations:
@@ -399,12 +403,13 @@
 			      | KVM_REG_ARM_OPC1_MASK))
 			return false;
 		params->is_64bit = true;
-		params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
+		/* CRm to CRn: see cp15_to_index for details */
+		params->CRn = ((id & KVM_REG_ARM_CRM_MASK)
 			       >> KVM_REG_ARM_CRM_SHIFT);
 		params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
 			       >> KVM_REG_ARM_OPC1_SHIFT);
 		params->Op2 = 0;
-		params->CRn = 0;
+		params->CRm = 0;
 		return true;
 	default:
 		return false;
@@ -898,7 +903,14 @@
 	if (reg->is_64) {
 		val |= KVM_REG_SIZE_U64;
 		val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
-		val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT);
+		/*
+		 * CRn always denotes the primary coproc. reg. nr. for the
+		 * in-kernel representation, but the user space API uses the
+		 * CRm for the encoding, because it is modelled after the
+		 * MRRC/MCRR instructions: see the ARM ARM rev. c page
+		 * B3-1445
+		 */
+		val |= (reg->CRn << KVM_REG_ARM_CRM_SHIFT);
 	} else {
 		val |= KVM_REG_SIZE_U32;
 		val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
diff --git a/arch/arm/kvm/coproc.h b/arch/arm/kvm/coproc.h
index b7301d3..0461d5c 100644
--- a/arch/arm/kvm/coproc.h
+++ b/arch/arm/kvm/coproc.h
@@ -135,6 +135,8 @@
 		return -1;
 	if (i1->CRn != i2->CRn)
 		return i1->CRn - i2->CRn;
+	if (i1->is_64 != i2->is_64)
+		return i2->is_64 - i1->is_64;
 	if (i1->CRm != i2->CRm)
 		return i1->CRm - i2->CRm;
 	if (i1->Op1 != i2->Op1)
@@ -145,6 +147,7 @@
 
 #define CRn(_x)		.CRn = _x
 #define CRm(_x) 	.CRm = _x
+#define CRm64(_x)       .CRn = _x, .CRm = 0
 #define Op1(_x) 	.Op1 = _x
 #define Op2(_x) 	.Op2 = _x
 #define is64		.is_64 = true
diff --git a/arch/arm/kvm/coproc_a15.c b/arch/arm/kvm/coproc_a15.c
index 685063a..cf93472 100644
--- a/arch/arm/kvm/coproc_a15.c
+++ b/arch/arm/kvm/coproc_a15.c
@@ -114,7 +114,11 @@
 
 /*
  * A15-specific CP15 registers.
- * Important: Must be sorted ascending by CRn, CRM, Op1, Op2
+ * CRn denotes the primary register number, but is copied to the CRm in the
+ * user space API for 64-bit register access in line with the terminology used
+ * in the ARM ARM.
+ * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
+ *            registers preceding 32-bit ones.
  */
 static const struct coproc_reg a15_regs[] = {
 	/* MPIDR: we use VMPIDR for guest access. */
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 16cd4ba..85dd84b 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -492,10 +492,10 @@
 	.section ".rodata"
 
 und_die_str:
-	.ascii	"unexpected undefined exception in Hyp mode at: %#08x"
+	.ascii	"unexpected undefined exception in Hyp mode at: %#08x\n"
 pabt_die_str:
-	.ascii	"unexpected prefetch abort in Hyp mode at: %#08x"
+	.ascii	"unexpected prefetch abort in Hyp mode at: %#08x\n"
 dabt_die_str:
-	.ascii	"unexpected data abort in Hyp mode at: %#08x"
+	.ascii	"unexpected data abort in Hyp mode at: %#08x\n"
 svc_die_str:
-	.ascii	"unexpected HVC/SVC trap in Hyp mode at: %#08x"
+	.ascii	"unexpected HVC/SVC trap in Hyp mode at: %#08x\n"
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index b8e06b7..0c25d94 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -63,7 +63,8 @@
 static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 		      struct kvm_exit_mmio *mmio)
 {
-	unsigned long rt, len;
+	unsigned long rt;
+	int len;
 	bool is_write, sign_extend;
 
 	if (kvm_vcpu_dabt_isextabt(vcpu)) {
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index ca6bea4..0988d9e 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -85,6 +85,12 @@
 	return p;
 }
 
+static bool page_empty(void *ptr)
+{
+	struct page *ptr_page = virt_to_page(ptr);
+	return page_count(ptr_page) == 1;
+}
+
 static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
 {
 	pmd_t *pmd_table = pmd_offset(pud, 0);
@@ -103,12 +109,6 @@
 	put_page(virt_to_page(pmd));
 }
 
-static bool pmd_empty(pmd_t *pmd)
-{
-	struct page *pmd_page = virt_to_page(pmd);
-	return page_count(pmd_page) == 1;
-}
-
 static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
 {
 	if (pte_present(*pte)) {
@@ -118,12 +118,6 @@
 	}
 }
 
-static bool pte_empty(pte_t *pte)
-{
-	struct page *pte_page = virt_to_page(pte);
-	return page_count(pte_page) == 1;
-}
-
 static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
 			unsigned long long start, u64 size)
 {
@@ -132,37 +126,37 @@
 	pmd_t *pmd;
 	pte_t *pte;
 	unsigned long long addr = start, end = start + size;
-	u64 range;
+	u64 next;
 
 	while (addr < end) {
 		pgd = pgdp + pgd_index(addr);
 		pud = pud_offset(pgd, addr);
 		if (pud_none(*pud)) {
-			addr += PUD_SIZE;
+			addr = pud_addr_end(addr, end);
 			continue;
 		}
 
 		pmd = pmd_offset(pud, addr);
 		if (pmd_none(*pmd)) {
-			addr += PMD_SIZE;
+			addr = pmd_addr_end(addr, end);
 			continue;
 		}
 
 		pte = pte_offset_kernel(pmd, addr);
 		clear_pte_entry(kvm, pte, addr);
-		range = PAGE_SIZE;
+		next = addr + PAGE_SIZE;
 
 		/* If we emptied the pte, walk back up the ladder */
-		if (pte_empty(pte)) {
+		if (page_empty(pte)) {
 			clear_pmd_entry(kvm, pmd, addr);
-			range = PMD_SIZE;
-			if (pmd_empty(pmd)) {
+			next = pmd_addr_end(addr, end);
+			if (page_empty(pmd) && !page_empty(pud)) {
 				clear_pud_entry(kvm, pud, addr);
-				range = PUD_SIZE;
+				next = pud_addr_end(addr, end);
 			}
 		}
 
-		addr += range;
+		addr = next;
 	}
 }
 
diff --git a/arch/arm/kvm/reset.c b/arch/arm/kvm/reset.c
index b7840e7..71e08ba 100644
--- a/arch/arm/kvm/reset.c
+++ b/arch/arm/kvm/reset.c
@@ -40,7 +40,7 @@
 };
 
 static const struct kvm_irq_level a15_vtimer_irq = {
-	.irq = 27,
+	{ .irq = 27 },
 	.level = 1,
 };
 
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
index a8e73ed..b1d640f 100644
--- a/arch/arm/kvm/trace.h
+++ b/arch/arm/kvm/trace.h
@@ -59,10 +59,9 @@
 		__entry->ipa			= ipa;
 	),
 
-	TP_printk("guest fault at PC %#08lx (hxfar %#08lx, "
-		  "ipa %#16llx, hsr %#08lx",
-		  __entry->vcpu_pc, __entry->hxfar,
-		  __entry->ipa, __entry->hsr)
+	TP_printk("ipa %#llx, hsr %#08lx, hxfar %#08lx, pc %#08lx",
+		  __entry->ipa, __entry->hsr,
+		  __entry->hxfar, __entry->vcpu_pc)
 );
 
 TRACE_EVENT(kvm_irq_line,
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 2abee66..916e5a1 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -227,6 +227,8 @@
 	CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
 	CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
 	CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+	CLKDEV_CON_DEV_ID("usart", "f8040000.serial", &uart0_clk),
+	CLKDEV_CON_DEV_ID("usart", "f8044000.serial", &uart1_clk),
 	CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
 	CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
index 8e7ed5c..048a57f 100644
--- a/arch/arm/mach-at91/include/mach/at91_adc.h
+++ b/arch/arm/mach-at91/include/mach/at91_adc.h
@@ -28,9 +28,12 @@
 #define			AT91_ADC_TRGSEL_EXTERNAL	(6 << 1)
 #define		AT91_ADC_LOWRES		(1 << 4)	/* Low Resolution */
 #define		AT91_ADC_SLEEP		(1 << 5)	/* Sleep Mode */
-#define		AT91_ADC_PRESCAL	(0x3f << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9260	(0x3f << 8)	/* Prescalar Rate Selection */
+#define		AT91_ADC_PRESCAL_9G45	(0xff << 8)
 #define			AT91_ADC_PRESCAL_(x)	((x) << 8)
-#define		AT91_ADC_STARTUP	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9260	(0x1f << 16)	/* Startup Up Time */
+#define		AT91_ADC_STARTUP_9G45	(0x7f << 16)
+#define		AT91_ADC_STARTUP_9X5	(0xf << 16)
 #define			AT91_ADC_STARTUP_(x)	((x) << 16)
 #define		AT91_ADC_SHTIM		(0xf  << 24)	/* Sample & Hold Time */
 #define			AT91_ADC_SHTIM_(x)	((x) << 24)
@@ -48,6 +51,9 @@
 #define		AT91_ADC_ENDRX		(1 << 18)	/* End of RX Buffer */
 #define		AT91_ADC_RXFUFF		(1 << 19)	/* RX Buffer Full */
 
+#define AT91_ADC_SR_9X5		0x30		/* Status Register for 9x5 */
+#define		AT91_ADC_SR_DRDY_9X5	(1 << 24)	/* Data Ready */
+
 #define AT91_ADC_LCDR		0x20		/* Last Converted Data Register */
 #define		AT91_ADC_LDATA		(0x3ff)
 
@@ -58,4 +64,10 @@
 #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
 #define		AT91_ADC_DATA		(0x3ff)
 
+#define AT91_ADC_CDR0_9X5	(0x50)			/* Channel Data Register 0 for 9X5 */
+
+#define AT91_ADC_TRGR_9260	AT91_ADC_MR
+#define AT91_ADC_TRGR_9G45	0x08
+#define AT91_ADC_TRGR_9X5	0xC0
+
 #endif
diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c
index dff4ddc..139e42d 100644
--- a/arch/arm/mach-davinci/board-dm355-leopard.c
+++ b/arch/arm/mach-davinci/board-dm355-leopard.c
@@ -75,6 +75,7 @@
 	.parts			= davinci_nand_partitions,
 	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),
 	.ecc_mode		= NAND_ECC_HW_SYNDROME,
+	.ecc_bits		= 4,
 	.bbt_options		= NAND_BBT_USE_FLASH,
 };
 
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index a33686a..fa4bfaf 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -153,6 +153,7 @@
 	.parts		= davinci_evm_nandflash_partition,
 	.nr_parts	= ARRAY_SIZE(davinci_evm_nandflash_partition),
 	.ecc_mode	= NAND_ECC_HW,
+	.ecc_bits	= 1,
 	.bbt_options	= NAND_BBT_USE_FLASH,
 	.timing		= &davinci_evm_nandflash_timing,
 };
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index fbb8e5a..0c005e8 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -90,6 +90,7 @@
 	.parts			= davinci_nand_partitions,
 	.nr_parts		= ARRAY_SIZE(davinci_nand_partitions),
 	.ecc_mode		= NAND_ECC_HW,
+	.ecc_bits		= 1,
 	.options		= 0,
 };
 
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
index 2bc112a..808233b 100644
--- a/arch/arm/mach-davinci/board-neuros-osd2.c
+++ b/arch/arm/mach-davinci/board-neuros-osd2.c
@@ -88,6 +88,7 @@
 	.parts		= davinci_ntosd2_nandflash_partition,
 	.nr_parts	= ARRAY_SIZE(davinci_ntosd2_nandflash_partition),
 	.ecc_mode	= NAND_ECC_HW,
+	.ecc_bits	= 1,
 	.bbt_options	= NAND_BBT_USE_FLASH,
 };
 
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 36aef3a..f1ac1c9 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -65,7 +65,7 @@
 	.states[1]		= {
 		.enter			= davinci_enter_idle,
 		.exit_latency		= 10,
-		.target_residency	= 100000,
+		.target_residency	= 10000,
 		.flags			= CPUIDLE_FLAG_TIME_VALID,
 		.name			= "DDR SR",
 		.desc			= "WFI and DDR Self Refresh",
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 00247c7..304f069 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -108,8 +108,8 @@
 	orion_clkdev_add(NULL, "sdhci-dove.1", sdio1);
 	orion_clkdev_add(NULL, "orion_nand", nand);
 	orion_clkdev_add(NULL, "cafe1000-ccic.0", camera);
-	orion_clkdev_add(NULL, "kirkwood-i2s.0", i2s0);
-	orion_clkdev_add(NULL, "kirkwood-i2s.1", i2s1);
+	orion_clkdev_add(NULL, "mvebu-audio.0", i2s0);
+	orion_clkdev_add(NULL, "mvebu-audio.1", i2s1);
 	orion_clkdev_add(NULL, "mv_crypto", crypto);
 	orion_clkdev_add(NULL, "dove-ac97", ac97);
 	orion_clkdev_add(NULL, "dove-pdma", pdma);
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 7be13f8..a02f275 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -254,13 +254,12 @@
 {
 	struct device_node *np;
 
-	np = of_find_node_by_path("/cpus/cpu@0");
+	np = of_node_get(cpu_dev->of_node);
 	if (!np) {
 		pr_warn("failed to find cpu0 node\n");
 		return;
 	}
 
-	cpu_dev->of_node = np;
 	if (of_init_opp_table(cpu_dev)) {
 		pr_warn("failed to init OPP table\n");
 		goto put_node;
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index e9238b5..1663de0 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -264,7 +264,7 @@
 	orion_clkdev_add(NULL, MV_XOR_NAME ".1", xor1);
 	orion_clkdev_add("0", "pcie", pex0);
 	orion_clkdev_add("1", "pcie", pex1);
-	orion_clkdev_add(NULL, "kirkwood-i2s", audio);
+	orion_clkdev_add(NULL, "mvebu-audio", audio);
 	orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".0", runit);
 	orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".1", runit);
 
@@ -560,7 +560,7 @@
 /*****************************************************************************
  * Audio
  ****************************************************************************/
-static struct resource kirkwood_i2s_resources[] = {
+static struct resource kirkwood_audio_resources[] = {
 	[0] = {
 		.start  = AUDIO_PHYS_BASE,
 		.end    = AUDIO_PHYS_BASE + SZ_16K - 1,
@@ -573,29 +573,23 @@
 	},
 };
 
-static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+static struct kirkwood_asoc_platform_data kirkwood_audio_data = {
 	.burst       = 128,
 };
 
-static struct platform_device kirkwood_i2s_device = {
-	.name		= "kirkwood-i2s",
+static struct platform_device kirkwood_audio_device = {
+	.name		= "mvebu-audio",
 	.id		= -1,
-	.num_resources	= ARRAY_SIZE(kirkwood_i2s_resources),
-	.resource	= kirkwood_i2s_resources,
+	.num_resources	= ARRAY_SIZE(kirkwood_audio_resources),
+	.resource	= kirkwood_audio_resources,
 	.dev		= {
-		.platform_data	= &kirkwood_i2s_data,
+		.platform_data	= &kirkwood_audio_data,
 	},
 };
 
-static struct platform_device kirkwood_pcm_device = {
-	.name		= "kirkwood-pcm-audio",
-	.id		= -1,
-};
-
 void __init kirkwood_audio_init(void)
 {
-	platform_device_register(&kirkwood_i2s_device);
-	platform_device_register(&kirkwood_pcm_device);
+	platform_device_register(&kirkwood_audio_device);
 }
 
 /*****************************************************************************
diff --git a/arch/arm/mach-msm/devices-msm7x00.c b/arch/arm/mach-msm/devices-msm7x00.c
index 6d50fb9..d83404d 100644
--- a/arch/arm/mach-msm/devices-msm7x00.c
+++ b/arch/arm/mach-msm/devices-msm7x00.c
@@ -456,9 +456,9 @@
 	CLK_PCOM("tsif_ref_clk",	TSIF_REF_CLK,	NULL, 0),
 	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
 	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART1_CLK,	"msm_serial.0", OFF),
-	CLK_PCOM("uart_clk",	UART2_CLK,	"msm_serial.1", 0),
-	CLK_PCOM("uart_clk",	UART3_CLK,	"msm_serial.2", OFF),
+	CLK_PCOM("core",	UART1_CLK,	"msm_serial.0", OFF),
+	CLK_PCOM("core",	UART2_CLK,	"msm_serial.1", 0),
+	CLK_PCOM("core",	UART3_CLK,	"msm_serial.2", OFF),
 	CLK_PCOM("uart1dm_clk",	UART1DM_CLK,	NULL, OFF),
 	CLK_PCOM("uart2dm_clk",	UART2DM_CLK,	NULL, 0),
 	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	"msm_hsusb", OFF),
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index d4db75a..14e2869 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -211,7 +211,7 @@
 	CLK_PCOM("spi_pclk",	SPI_P_CLK,	NULL, 0),
 	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
 	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART2_CLK,	"msm_serial.1", 0),
+	CLK_PCOM("core",	UART2_CLK,	"msm_serial.1", 0),
 	CLK_PCOM("usb_phy_clk",	USB_PHY_CLK,	NULL, 0),
 	CLK_PCOM("usb_hs_clk",		USB_HS_CLK,		NULL, OFF),
 	CLK_PCOM("usb_hs_pclk",		USB_HS_P_CLK,		NULL, OFF),
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index f551811..2ed89b2 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -358,9 +358,9 @@
 	CLK_PCOM("tsif_ref_clk",	TSIF_REF_CLK,	NULL, 0),
 	CLK_PCOM("tv_dac_clk",	TV_DAC_CLK,	NULL, 0),
 	CLK_PCOM("tv_enc_clk",	TV_ENC_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART1_CLK,	NULL, OFF),
-	CLK_PCOM("uart_clk",	UART2_CLK,	NULL, 0),
-	CLK_PCOM("uart_clk",	UART3_CLK,	"msm_serial.2", OFF),
+	CLK_PCOM("core",	UART1_CLK,	NULL, OFF),
+	CLK_PCOM("core",	UART2_CLK,	NULL, 0),
+	CLK_PCOM("core",	UART3_CLK,	"msm_serial.2", OFF),
 	CLK_PCOM("uartdm_clk",	UART1DM_CLK,	NULL, OFF),
 	CLK_PCOM("uartdm_clk",	UART2DM_CLK,	NULL, 0),
 	CLK_PCOM("usb_hs_clk",	USB_HS_CLK,	NULL, OFF),
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index ce81d30..594b63d 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -29,45 +29,40 @@
 #include "pmsu.h"
 #include "coherency.h"
 
+static struct clk *__init get_cpu_clk(int cpu)
+{
+	struct clk *cpu_clk;
+	struct device_node *np = of_get_cpu_node(cpu, NULL);
+
+	if (WARN(!np, "missing cpu node\n"))
+		return NULL;
+	cpu_clk = of_clk_get(np, 0);
+	if (WARN_ON(IS_ERR(cpu_clk)))
+		return NULL;
+	return cpu_clk;
+}
+
 void __init set_secondary_cpus_clock(void)
 {
-	int thiscpu;
+	int thiscpu, cpu;
 	unsigned long rate;
-	struct clk *cpu_clk = NULL;
-	struct device_node *np = NULL;
+	struct clk *cpu_clk;
 
 	thiscpu = smp_processor_id();
-	for_each_node_by_type(np, "cpu") {
-		int err;
-		int cpu;
-
-		err = of_property_read_u32(np, "reg", &cpu);
-		if (WARN_ON(err))
-			return;
-
-		if (cpu == thiscpu) {
-			cpu_clk = of_clk_get(np, 0);
-			break;
-		}
-	}
-	if (WARN_ON(IS_ERR(cpu_clk)))
+	cpu_clk = get_cpu_clk(thiscpu);
+	if (!cpu_clk)
 		return;
 	clk_prepare_enable(cpu_clk);
 	rate = clk_get_rate(cpu_clk);
 
 	/* set all the other CPU clk to the same rate than the boot CPU */
-	for_each_node_by_type(np, "cpu") {
-		int err;
-		int cpu;
-
-		err = of_property_read_u32(np, "reg", &cpu);
-		if (WARN_ON(err))
+	for_each_possible_cpu(cpu) {
+		if (cpu == thiscpu)
+			continue;
+		cpu_clk = get_cpu_clk(cpu);
+		if (!cpu_clk)
 			return;
-
-		if (cpu != thiscpu) {
-			cpu_clk = of_clk_get(np, 0);
-			clk_set_rate(cpu_clk, rate);
-		}
+		clk_set_rate(cpu_clk, rate);
 	}
 }
 
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index f6eeb87..827d150 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -122,11 +122,7 @@
 };
 
 static struct musb_hdrc_platform_data tusb_data = {
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 	.mode		= MUSB_OTG,
-#else
-	.mode		= MUSB_HOST,
-#endif
 	.set_power	= tusb_set_power,
 	.min_power	= 25,	/* x2 = 50 mA drawn from VBUS as peripheral */
 	.power		= 100,	/* Max 100 mA VBUS for host mode */
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 04c1165..1c6ae5f 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -33,7 +33,7 @@
 #include <linux/mtd/nand.h>
 #include <linux/mmc/host.h>
 #include <linux/usb/phy.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
@@ -279,7 +279,7 @@
 static struct gpio_led gpio_leds[];
 
 /* PHY's VCC regulator might be added later, so flag that we need it */
-static struct nop_usb_xceiv_platform_data hsusb2_phy_data = {
+static struct usb_phy_gen_xceiv_platform_data hsusb2_phy_data = {
 	.needs_vcc = true,
 };
 
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 8c02626..52bdddd 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -33,7 +33,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/musb.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/smsc911x.h>
 
 #include <linux/wl12xx.h>
@@ -468,7 +468,7 @@
 static struct regulator_consumer_supply omap3evm_vaux2_supplies[] = {
 	REGULATOR_SUPPLY("VDD_CSIPHY1", "omap3isp"),	/* OMAP ISP */
 	REGULATOR_SUPPLY("VDD_CSIPHY2", "omap3isp"),	/* OMAP ISP */
-	REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"),	/* hsusb port 2 */
+	REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"),	/* hsusb port 2 */
 	REGULATOR_SUPPLY("vaux2", NULL),
 };
 
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index b1547a0..d2b455e 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -352,7 +352,7 @@
 };
 
 static struct regulator_consumer_supply pandora_usb_phy_supply[] = {
-	REGULATOR_SUPPLY("vcc", "nop_usb_xceiv.2"),	/* hsusb port 2 */
+	REGULATOR_SUPPLY("vcc", "usb_phy_gen_xceiv.2"),	/* hsusb port 2 */
 };
 
 /* ads7846 on SPI and 2 nub controllers on I2C */
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index d2ea68e..773510556 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -85,7 +85,7 @@
 
 static struct omap_musb_board_data musb_board_data = {
 	.interface_type		= MUSB_INTERFACE_ULPI,
-	.mode			= MUSB_PERIPHERAL,
+	.mode			= MUSB_OTG,
 	.power			= 0,
 };
 
diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c
index d940e53..b456b44 100644
--- a/arch/arm/mach-omap2/i2c.c
+++ b/arch/arm/mach-omap2/i2c.c
@@ -181,7 +181,7 @@
 				 sizeof(struct omap_i2c_bus_platform_data));
 	WARN(IS_ERR(pdev), "Could not build omap_device for %s\n", name);
 
-	return PTR_RET(pdev);
+	return PTR_ERR_OR_ZERO(pdev);
 }
 
 static  int __init omap_i2c_cmdline(void)
diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c
index 2eb19d4..e83a6a4 100644
--- a/arch/arm/mach-omap2/usb-host.c
+++ b/arch/arm/mach-omap2/usb-host.c
@@ -28,7 +28,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/usb/phy.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include "soc.h"
 #include "omap_device.h"
@@ -349,7 +349,7 @@
 	/* .init_data filled later */
 };
 
-static const char *nop_name = "nop_usb_xceiv"; /* NOP PHY driver */
+static const char *nop_name = "usb_phy_gen_xceiv"; /* NOP PHY driver */
 static const char *reg_name = "reg-fixed-voltage"; /* Regulator driver */
 
 /**
@@ -460,9 +460,9 @@
 		pdevinfo.name = nop_name;
 		pdevinfo.id = phy->port;
 		pdevinfo.data = phy->platform_data;
-		pdevinfo.size_data = sizeof(struct nop_usb_xceiv_platform_data);
-
-		scnprintf(phy_id, MAX_STR, "nop_usb_xceiv.%d",
+		pdevinfo.size_data =
+			sizeof(struct usb_phy_gen_xceiv_platform_data);
+		scnprintf(phy_id, MAX_STR, "usb_phy_gen_xceiv.%d",
 					phy->port);
 		pdev = platform_device_register_full(&pdevinfo);
 		if (IS_ERR(pdev)) {
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 8c4de27..bc89723 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -38,11 +38,8 @@
 };
 
 static struct musb_hdrc_platform_data musb_plat = {
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
 	.mode		= MUSB_OTG,
-#else
-	.mode		= MUSB_HOST,
-#endif
+
 	/* .clock is set dynamically */
 	.config		= &musb_config,
 
diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index 2c70f74..e110b6d 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -42,7 +42,6 @@
 
 DT_MACHINE_START(ATLAS6_DT, "Generic ATLAS6 (Flattened Device Tree)")
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
-	.nr_irqs	= 128,
 	.map_io         = sirfsoc_map_io,
 	.init_time	= sirfsoc_init_time,
 	.init_late	= sirfsoc_init_late,
@@ -59,7 +58,6 @@
 
 DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
-	.nr_irqs	= 128,
 	.map_io         = sirfsoc_map_io,
 	.init_time	= sirfsoc_init_time,
 	.dma_zone_size	= SZ_256M,
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index 0d1e412..fc97cfd 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -29,7 +29,6 @@
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
 #include <linux/pda_power.h>
-#include <linux/platform_data/tegra_usb.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
@@ -46,40 +45,6 @@
 #include "fuse.h"
 #include "iomap.h"
 
-static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
-	.operating_mode = TEGRA_USB_OTG,
-	.power_down_on_bus_suspend = 1,
-	.vbus_gpio = -1,
-};
-
-static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
-	.reset_gpio = -1,
-	.clk = "cdev2",
-};
-
-static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
-	.phy_config = &tegra_ehci2_ulpi_phy_config,
-	.operating_mode = TEGRA_USB_HOST,
-	.power_down_on_bus_suspend = 1,
-	.vbus_gpio = -1,
-};
-
-static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
-	.operating_mode = TEGRA_USB_HOST,
-	.power_down_on_bus_suspend = 1,
-	.vbus_gpio = -1,
-};
-
-static struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
-	OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5000000, "tegra-ehci.0",
-		       &tegra_ehci1_pdata),
-	OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5004000, "tegra-ehci.1",
-		       &tegra_ehci2_pdata),
-	OF_DEV_AUXDATA("nvidia,tegra20-ehci", 0xC5008000, "tegra-ehci.2",
-		       &tegra_ehci3_pdata),
-	{}
-};
-
 static void __init tegra_dt_init(void)
 {
 	struct soc_device_attribute *soc_dev_attr;
@@ -112,8 +77,7 @@
 	 * devices
 	 */
 out:
-	of_platform_populate(NULL, of_default_bus_match_table,
-				tegra20_auxdata_lookup, parent);
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
 }
 
 static void __init trimslice_init(void)
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index bf9b6be..fe1f3e2 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -4,7 +4,6 @@
 
 obj-y				:= cpu.o devices.o devices-common.o \
 				   id.o usb.o timer.o pm.o
-obj-$(CONFIG_CPU_IDLE)          += cpuidle.o
 obj-$(CONFIG_CACHE_L2X0)	+= cache-l2x0.o
 obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o
 obj-$(CONFIG_MACH_MOP500)	+= board-mop500.o board-mop500-sdi.o \
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index db5c2ca..cd2c88e 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -809,15 +809,18 @@
 	  the CPU type fitted to the system.  This permits binaries to be
 	  run on ARMv4 through to ARMv7 without modification.
 
+	  See Documentation/arm/kernel_user_helpers.txt for details.
+
 	  However, the fixed address nature of these helpers can be used
 	  by ROP (return orientated programming) authors when creating
 	  exploits.
 
 	  If all of the binaries and libraries which run on your platform
 	  are built specifically for your platform, and make no use of
-	  these helpers, then you can turn this option off.  However,
-	  when such an binary or library is run, it will receive a SIGILL
-	  signal, which will terminate the program.
+	  these helpers, then you can turn this option off to hinder
+	  such exploits. However, in that case, if a binary or library
+	  relying on those helpers is run, it will receive a SIGILL signal,
+	  which will terminate the program.
 
 	  Say N here only if you are absolutely certain that you do not
 	  need these helpers; otherwise, the safe option is to say Y.
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 7f9b179..dbddc07 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -358,7 +358,7 @@
 	if (!pages)
 		goto no_pages;
 
-	if (IS_ENABLED(CONFIG_CMA))
+	if (IS_ENABLED(CONFIG_DMA_CMA))
 		ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page,
 					      atomic_pool_init);
 	else
@@ -670,7 +670,7 @@
 		addr = __alloc_simple_buffer(dev, size, gfp, &page);
 	else if (!(gfp & __GFP_WAIT))
 		addr = __alloc_from_pool(size, &page);
-	else if (!IS_ENABLED(CONFIG_CMA))
+	else if (!IS_ENABLED(CONFIG_DMA_CMA))
 		addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
 	else
 		addr = __alloc_from_contiguous(dev, size, prot, &page, caller);
@@ -759,7 +759,7 @@
 		__dma_free_buffer(page, size);
 	} else if (__free_from_pool(cpu_addr, size)) {
 		return;
-	} else if (!IS_ENABLED(CONFIG_CMA)) {
+	} else if (!IS_ENABLED(CONFIG_DMA_CMA)) {
 		__dma_free_remap(cpu_addr, size);
 		__dma_free_buffer(page, size);
 	} else {
diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c
index 8e11e96..c83f27b 100644
--- a/arch/arm/plat-pxa/ssp.c
+++ b/arch/arm/plat-pxa/ssp.c
@@ -30,6 +30,8 @@
 #include <linux/platform_device.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
@@ -60,6 +62,30 @@
 }
 EXPORT_SYMBOL(pxa_ssp_request);
 
+struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
+				      const char *label)
+{
+	struct ssp_device *ssp = NULL;
+
+	mutex_lock(&ssp_lock);
+
+	list_for_each_entry(ssp, &ssp_list, node) {
+		if (ssp->of_node == of_node && ssp->use_count == 0) {
+			ssp->use_count++;
+			ssp->label = label;
+			break;
+		}
+	}
+
+	mutex_unlock(&ssp_lock);
+
+	if (&ssp->node == &ssp_list)
+		return NULL;
+
+	return ssp;
+}
+EXPORT_SYMBOL(pxa_ssp_request_of);
+
 void pxa_ssp_free(struct ssp_device *ssp)
 {
 	mutex_lock(&ssp_lock);
@@ -72,96 +98,126 @@
 }
 EXPORT_SYMBOL(pxa_ssp_free);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ssp_of_ids[] = {
+	{ .compatible = "mrvl,pxa25x-ssp",	.data = (void *) PXA25x_SSP },
+	{ .compatible = "mvrl,pxa25x-nssp",	.data = (void *) PXA25x_NSSP },
+	{ .compatible = "mrvl,pxa27x-ssp",	.data = (void *) PXA27x_SSP },
+	{ .compatible = "mrvl,pxa3xx-ssp",	.data = (void *) PXA3xx_SSP },
+	{ .compatible = "mvrl,pxa168-ssp",	.data = (void *) PXA168_SSP },
+	{ .compatible = "mrvl,pxa910-ssp",	.data = (void *) PXA910_SSP },
+	{ .compatible = "mrvl,ce4100-ssp",	.data = (void *) CE4100_SSP },
+	{ .compatible = "mrvl,lpss-ssp",	.data = (void *) LPSS_SSP },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
+#endif
+
 static int pxa_ssp_probe(struct platform_device *pdev)
 {
-	const struct platform_device_id *id = platform_get_device_id(pdev);
 	struct resource *res;
 	struct ssp_device *ssp;
-	int ret = 0;
+	struct device *dev = &pdev->dev;
 
-	ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
-	if (ssp == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory");
+	ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL);
+	if (ssp == NULL)
 		return -ENOMEM;
-	}
+
 	ssp->pdev = pdev;
 
-	ssp->clk = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(ssp->clk)) {
-		ret = PTR_ERR(ssp->clk);
-		goto err_free;
-	}
+	ssp->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(ssp->clk))
+		return PTR_ERR(ssp->clk);
 
-	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
-	}
-	ssp->drcmr_rx = res->start;
+	if (dev->of_node) {
+		struct of_phandle_args dma_spec;
+		struct device_node *np = dev->of_node;
 
-	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-	if (res == NULL) {
-		dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
+		/*
+		 * FIXME: we should allocate the DMA channel from this
+		 * context and pass the channel down to the ssp users.
+		 * For now, we lookup the rx and tx indices manually
+		 */
+
+		/* rx */
+		of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+					   0, &dma_spec);
+		ssp->drcmr_rx = dma_spec.args[0];
+		of_node_put(dma_spec.np);
+
+		/* tx */
+		of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+					   1, &dma_spec);
+		ssp->drcmr_tx = dma_spec.args[0];
+		of_node_put(dma_spec.np);
+	} else {
+		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+		if (res == NULL) {
+			dev_err(dev, "no SSP RX DRCMR defined\n");
+			return -ENODEV;
+		}
+		ssp->drcmr_rx = res->start;
+
+		res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+		if (res == NULL) {
+			dev_err(dev, "no SSP TX DRCMR defined\n");
+			return -ENODEV;
+		}
+		ssp->drcmr_tx = res->start;
 	}
-	ssp->drcmr_tx = res->start;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res == NULL) {
-		dev_err(&pdev->dev, "no memory resource defined\n");
-		ret = -ENODEV;
-		goto err_free_clk;
+		dev_err(dev, "no memory resource defined\n");
+		return -ENODEV;
 	}
 
-	res = request_mem_region(res->start, resource_size(res),
-			pdev->name);
+	res = devm_request_mem_region(dev, res->start, resource_size(res),
+				      pdev->name);
 	if (res == NULL) {
-		dev_err(&pdev->dev, "failed to request memory resource\n");
-		ret = -EBUSY;
-		goto err_free_clk;
+		dev_err(dev, "failed to request memory resource\n");
+		return -EBUSY;
 	}
 
 	ssp->phys_base = res->start;
 
-	ssp->mmio_base = ioremap(res->start, resource_size(res));
+	ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res));
 	if (ssp->mmio_base == NULL) {
-		dev_err(&pdev->dev, "failed to ioremap() registers\n");
-		ret = -ENODEV;
-		goto err_free_mem;
+		dev_err(dev, "failed to ioremap() registers\n");
+		return -ENODEV;
 	}
 
 	ssp->irq = platform_get_irq(pdev, 0);
 	if (ssp->irq < 0) {
-		dev_err(&pdev->dev, "no IRQ resource defined\n");
-		ret = -ENODEV;
-		goto err_free_io;
+		dev_err(dev, "no IRQ resource defined\n");
+		return -ENODEV;
 	}
 
-	/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
-	 * starts from 0, do a translation here
-	 */
-	ssp->port_id = pdev->id + 1;
+	if (dev->of_node) {
+		const struct of_device_id *id =
+			of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
+		ssp->type = (int) id->data;
+	} else {
+		const struct platform_device_id *id =
+			platform_get_device_id(pdev);
+		ssp->type = (int) id->driver_data;
+
+		/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
+		 * starts from 0, do a translation here
+		 */
+		ssp->port_id = pdev->id + 1;
+	}
+
 	ssp->use_count = 0;
-	ssp->type = (int)id->driver_data;
+	ssp->of_node = dev->of_node;
 
 	mutex_lock(&ssp_lock);
 	list_add(&ssp->node, &ssp_list);
 	mutex_unlock(&ssp_lock);
 
 	platform_set_drvdata(pdev, ssp);
-	return 0;
 
-err_free_io:
-	iounmap(ssp->mmio_base);
-err_free_mem:
-	release_mem_region(res->start, resource_size(res));
-err_free_clk:
-	clk_put(ssp->clk);
-err_free:
-	kfree(ssp);
-	return ret;
+	return 0;
 }
 
 static int pxa_ssp_remove(struct platform_device *pdev)
@@ -201,8 +257,9 @@
 	.probe		= pxa_ssp_probe,
 	.remove		= pxa_ssp_remove,
 	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "pxa2xx-ssp",
+		.owner		= THIS_MODULE,
+		.name		= "pxa2xx-ssp",
+		.of_match_table	= of_match_ptr(pxa_ssp_of_ids),
 	},
 	.id_table	= ssp_id_table,
 };
diff --git a/arch/arm/plat-samsung/init.c b/arch/arm/plat-samsung/init.c
index 3e5c461..50a3ea0 100644
--- a/arch/arm/plat-samsung/init.c
+++ b/arch/arm/plat-samsung/init.c
@@ -55,12 +55,13 @@
 
 	printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
 
-	if (cpu->map_io == NULL || cpu->init == NULL) {
+	if (cpu->init == NULL) {
 		printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
 		panic("Unsupported Samsung CPU");
 	}
 
-	cpu->map_io();
+	if (cpu->map_io)
+		cpu->map_io();
 }
 
 /* s3c24xx_init_clocks
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
index 0cc40ae..98b10ba 100644
--- a/arch/arm/plat-samsung/s3c-dma-ops.c
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -82,7 +82,8 @@
 static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
 {
 	struct cb_data *data;
-	int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
+	dma_addr_t pos = param->buf;
+	dma_addr_t end = param->buf + param->len;
 
 	list_for_each_entry(data, &dma_list, node)
 		if (data->ch == ch)
@@ -94,7 +95,15 @@
 		data->fp_param = param->fp_param;
 	}
 
-	s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
+	if (param->cap != DMA_CYCLIC) {
+		s3c2410_dma_enqueue(ch, (void *)data, param->buf, param->len);
+		return 0;
+	}
+
+	while (pos < end) {
+		s3c2410_dma_enqueue(ch, (void *)data, pos, param->period);
+		pos += param->period;
+	}
 
 	return 0;
 }
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index c9770ba..8a6295c 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -170,6 +170,7 @@
 	per_cpu(xen_vcpu, cpu) = vcpup;
 
 	enable_percpu_irq(xen_events_irq, 0);
+	put_cpu();
 }
 
 static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index 98abd47..c9f1d28 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -26,7 +26,13 @@
 
 #include <clocksource/arm_arch_timer.h>
 
-static inline void arch_timer_reg_write(int access, int reg, u32 val)
+/*
+ * These register accessors are marked inline so the compiler can
+ * nicely work out which register we want, and chuck away the rest of
+ * the code.
+ */
+static __always_inline
+void arch_timer_reg_write_cp15(int access, enum arch_timer_reg reg, u32 val)
 {
 	if (access == ARCH_TIMER_PHYS_ACCESS) {
 		switch (reg) {
@@ -36,8 +42,6 @@
 		case ARCH_TIMER_REG_TVAL:
 			asm volatile("msr cntp_tval_el0, %0" : : "r" (val));
 			break;
-		default:
-			BUILD_BUG();
 		}
 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
 		switch (reg) {
@@ -47,17 +51,14 @@
 		case ARCH_TIMER_REG_TVAL:
 			asm volatile("msr cntv_tval_el0, %0" : : "r" (val));
 			break;
-		default:
-			BUILD_BUG();
 		}
-	} else {
-		BUILD_BUG();
 	}
 
 	isb();
 }
 
-static inline u32 arch_timer_reg_read(int access, int reg)
+static __always_inline
+u32 arch_timer_reg_read_cp15(int access, enum arch_timer_reg reg)
 {
 	u32 val;
 
@@ -69,8 +70,6 @@
 		case ARCH_TIMER_REG_TVAL:
 			asm volatile("mrs %0, cntp_tval_el0" : "=r" (val));
 			break;
-		default:
-			BUILD_BUG();
 		}
 	} else if (access == ARCH_TIMER_VIRT_ACCESS) {
 		switch (reg) {
@@ -80,11 +79,7 @@
 		case ARCH_TIMER_REG_TVAL:
 			asm volatile("mrs %0, cntv_tval_el0" : "=r" (val));
 			break;
-		default:
-			BUILD_BUG();
 		}
-	} else {
-		BUILD_BUG();
 	}
 
 	return val;
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index c92de41..b25763b 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -42,14 +42,15 @@
 #define	TPIDR_EL1	18	/* Thread ID, Privileged */
 #define	AMAIR_EL1	19	/* Aux Memory Attribute Indirection Register */
 #define	CNTKCTL_EL1	20	/* Timer Control Register (EL1) */
+#define	PAR_EL1		21	/* Physical Address Register */
 /* 32bit specific registers. Keep them at the end of the range */
-#define	DACR32_EL2	21	/* Domain Access Control Register */
-#define	IFSR32_EL2	22	/* Instruction Fault Status Register */
-#define	FPEXC32_EL2	23	/* Floating-Point Exception Control Register */
-#define	DBGVCR32_EL2	24	/* Debug Vector Catch Register */
-#define	TEECR32_EL1	25	/* ThumbEE Configuration Register */
-#define	TEEHBR32_EL1	26	/* ThumbEE Handler Base Register */
-#define	NR_SYS_REGS	27
+#define	DACR32_EL2	22	/* Domain Access Control Register */
+#define	IFSR32_EL2	23	/* Instruction Fault Status Register */
+#define	FPEXC32_EL2	24	/* Floating-Point Exception Control Register */
+#define	DBGVCR32_EL2	25	/* Debug Vector Catch Register */
+#define	TEECR32_EL1	26	/* ThumbEE Configuration Register */
+#define	TEEHBR32_EL1	27	/* ThumbEE Handler Base Register */
+#define	NR_SYS_REGS	28
 
 /* 32bit mapping */
 #define c0_MPIDR	(MPIDR_EL1 * 2)	/* MultiProcessor ID Register */
@@ -69,6 +70,8 @@
 #define c5_AIFSR	(AFSR1_EL1 * 2)	/* Auxiliary Instr Fault Status R */
 #define c6_DFAR		(FAR_EL1 * 2)	/* Data Fault Address Register */
 #define c6_IFAR		(c6_DFAR + 1)	/* Instruction Fault Address Register */
+#define c7_PAR		(PAR_EL1 * 2)	/* Physical Address Register */
+#define c7_PAR_high	(c7_PAR + 1)	/* PAR top 32 bits */
 #define c10_PRRR	(MAIR_EL1 * 2)	/* Primary Region Remap Register */
 #define c10_NMRR	(c10_PRRR + 1)	/* Normal Memory Remap Register */
 #define c12_VBAR	(VBAR_EL1 * 2)	/* Vector Base Address Register */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 644d739..0859a4d 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -129,7 +129,7 @@
 	struct kvm_mmu_memory_cache mmu_page_cache;
 
 	/* Target CPU and feature flags */
-	u32 target;
+	int target;
 	DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
 
 	/* Detect first run of a vcpu */
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 9ba33c4..12e6ccb 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -107,7 +107,12 @@
 static int
 armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
 {
-	int mapping = (*event_map)[config];
+	int mapping;
+
+	if (config >= PERF_COUNT_HW_MAX)
+		return -EINVAL;
+
+	mapping = (*event_map)[config];
 	return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
 }
 
@@ -317,6 +322,9 @@
 	struct hw_perf_event fake_event = event->hw;
 	struct pmu *leader_pmu = event->group_leader->pmu;
 
+	if (is_software_event(event))
+		return 1;
+
 	if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
 		return 1;
 
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index ff985e3..1ac0bbb 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -214,6 +214,7 @@
 	mrs	x21,	tpidr_el1
 	mrs	x22, 	amair_el1
 	mrs	x23, 	cntkctl_el1
+	mrs	x24,	par_el1
 
 	stp	x4, x5, [x3]
 	stp	x6, x7, [x3, #16]
@@ -225,6 +226,7 @@
 	stp	x18, x19, [x3, #112]
 	stp	x20, x21, [x3, #128]
 	stp	x22, x23, [x3, #144]
+	str	x24, [x3, #160]
 .endm
 
 .macro restore_sysregs
@@ -243,6 +245,7 @@
 	ldp	x18, x19, [x3, #112]
 	ldp	x20, x21, [x3, #128]
 	ldp	x22, x23, [x3, #144]
+	ldr	x24, [x3, #160]
 
 	msr	vmpidr_el2,	x4
 	msr	csselr_el1,	x5
@@ -264,6 +267,7 @@
 	msr	tpidr_el1,	x21
 	msr	amair_el1,	x22
 	msr	cntkctl_el1,	x23
+	msr	par_el1,	x24
 .endm
 
 .macro skip_32bit_state tmp, target
@@ -600,6 +604,8 @@
 
 // void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 ENTRY(__kvm_tlb_flush_vmid_ipa)
+	dsb	ishst
+
 	kern_hyp_va	x0
 	ldr	x2, [x0, #KVM_VTTBR]
 	msr	vttbr_el2, x2
@@ -621,6 +627,7 @@
 ENDPROC(__kvm_tlb_flush_vmid_ipa)
 
 ENTRY(__kvm_flush_vm_context)
+	dsb	ishst
 	tlbi	alle1is
 	ic	ialluis
 	dsb	sy
@@ -753,6 +760,10 @@
 	 */
 	tbnz	x1, #7, 1f	// S1PTW is set
 
+	/* Preserve PAR_EL1 */
+	mrs	x3, par_el1
+	push	x3, xzr
+
 	/*
 	 * Permission fault, HPFAR_EL2 is invalid.
 	 * Resolve the IPA the hard way using the guest VA.
@@ -766,6 +777,8 @@
 
 	/* Read result */
 	mrs	x3, par_el1
+	pop	x0, xzr			// Restore PAR_EL1 from the stack
+	msr	par_el1, x0
 	tbnz	x3, #0, 3f		// Bail out if we failed the translation
 	ubfx	x3, x3, #12, #36	// Extract IPA
 	lsl	x3, x3, #4		// and present it like HPFAR
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 9492360..02e9d09 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -211,6 +211,9 @@
 	/* FAR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
 	  NULL, reset_unknown, FAR_EL1 },
+	/* PAR_EL1 */
+	{ Op0(0b11), Op1(0b000), CRn(0b0111), CRm(0b0100), Op2(0b000),
+	  NULL, reset_unknown, PAR_EL1 },
 
 	/* PMINTENSET_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index 0aa35f0..deb6784 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -320,7 +320,7 @@
  *  are examined.
  */
 
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
 #if 0
 	printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number);
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 5a768ad..5666422 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -43,6 +43,7 @@
 	select SYSCTL_ARCH_UNALIGN_NO_WARN
 	select HAVE_MOD_ARCH_SPECIFIC
 	select MODULES_USE_ELF_RELA
+	select ARCH_USE_CMPXCHG_LOCKREF
 	default y
 	help
 	  The Itanium Processor Family is Intel's 64-bit successor to
@@ -565,9 +566,9 @@
 
 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
-	  initially work for you.  It may help to enable device hotplugging
-	  support.  As of this writing the exact hardware interface is
-	  strongly in flux, so no good recommendation can be made.
+	  initially work for you.  As of this writing the exact hardware
+	  interface is strongly in flux, so no good recommendation can be
+	  made.
 
 config CRASH_DUMP
 	  bool "kernel crash dumps"
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 05b03ec..a3456f3 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -3,3 +3,4 @@
 generic-y += exec.h
 generic-y += kvm_para.h
 generic-y += trace_clock.h
+generic-y += vtime.h
\ No newline at end of file
diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index 54ff557..45698cd 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -102,6 +102,11 @@
 	return ((tmp - (tmp >> TICKET_SHIFT)) & TICKET_MASK) > 1;
 }
 
+static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock)
+{
+	return !(((lock.lock >> TICKET_SHIFT) ^ lock.lock) & TICKET_MASK);
+}
+
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
 	return __ticket_spin_is_locked(lock);
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 5b2dc0d..bdfd878 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1560,6 +1560,10 @@
 	return 0;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 		struct kvm_memory_slot *memslot,
 		struct kvm_userspace_memory_region *mem,
diff --git a/arch/m68k/amiga/platform.c b/arch/m68k/amiga/platform.c
index 6083088..dacd9f9 100644
--- a/arch/m68k/amiga/platform.c
+++ b/arch/m68k/amiga/platform.c
@@ -56,7 +56,7 @@
 	n = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2;
 	pdev = platform_device_register_simple("amiga-zorro", -1,
 					       zorro_resources, n);
-	return PTR_RET(pdev);
+	return PTR_ERR_OR_ZERO(pdev);
 }
 
 subsys_initcall(amiga_init_bus);
diff --git a/arch/m68k/emu/natfeat.c b/arch/m68k/emu/natfeat.c
index fa277ae..121a666 100644
--- a/arch/m68k/emu/natfeat.c
+++ b/arch/m68k/emu/natfeat.c
@@ -18,11 +18,11 @@
 #include <asm/machdep.h>
 #include <asm/natfeat.h>
 
-extern long nf_get_id2(const char *feature_name);
+extern long nf_get_id_phys(unsigned long feature_name);
 
 asm("\n"
-"	.global nf_get_id2,nf_call\n"
-"nf_get_id2:\n"
+"	.global nf_get_id_phys,nf_call\n"
+"nf_get_id_phys:\n"
 "	.short	0x7300\n"
 "	rts\n"
 "nf_call:\n"
@@ -31,7 +31,7 @@
 "1:	moveq.l	#0,%d0\n"
 "	rts\n"
 "	.section __ex_table,\"a\"\n"
-"	.long	nf_get_id2,1b\n"
+"	.long	nf_get_id_phys,1b\n"
 "	.long	nf_call,1b\n"
 "	.previous");
 EXPORT_SYMBOL_GPL(nf_call);
@@ -46,7 +46,7 @@
 	if (n >= sizeof(name_copy))
 		return 0;
 
-	return nf_get_id2(name_copy);
+	return nf_get_id_phys(virt_to_phys(name_copy));
 }
 EXPORT_SYMBOL_GPL(nf_get_id);
 
@@ -58,7 +58,7 @@
 
 	va_start(ap, fmt);
 	n = vsnprintf(buf, 256, fmt, ap);
-	nf_call(nf_get_id("NF_STDERR"), buf);
+	nf_call(nf_get_id("NF_STDERR"), virt_to_phys(buf));
 	va_end(ap);
 }
 
@@ -83,7 +83,7 @@
 	id = nf_get_id("NF_NAME");
 	if (!id)
 		return;
-	nf_call(id, buf, 256);
+	nf_call(id, virt_to_phys(buf), 256);
 	buf[255] = 0;
 
 	pr_info("NatFeats found (%s, %lu.%lu)\n", buf, version >> 16,
diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c
index e301133..0721858 100644
--- a/arch/m68k/emu/nfblock.c
+++ b/arch/m68k/emu/nfblock.c
@@ -41,8 +41,8 @@
 static inline s32 nfhd_get_capacity(u32 major, u32 minor, u32 *blocks,
 				    u32 *blocksize)
 {
-	return nf_call(nfhd_id + NFHD_GET_CAPACITY, major, minor, blocks,
-		       blocksize);
+	return nf_call(nfhd_id + NFHD_GET_CAPACITY, major, minor,
+		       virt_to_phys(blocks), virt_to_phys(blocksize));
 }
 
 static LIST_HEAD(nfhd_list);
diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 6685bf4..57e8c8f 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/uaccess.h>
+#include <linux/io.h>
 
 #include <asm/natfeat.h>
 
@@ -25,17 +26,18 @@
 static void nfputs(const char *str, unsigned int count)
 {
 	char buf[68];
+	unsigned long phys = virt_to_phys(buf);
 
 	buf[64] = 0;
 	while (count > 64) {
 		memcpy(buf, str, 64);
-		nf_call(stderr_id, buf);
+		nf_call(stderr_id, phys);
 		str += 64;
 		count -= 64;
 	}
 	memcpy(buf, str, count);
 	buf[count] = 0;
-	nf_call(stderr_id, buf);
+	nf_call(stderr_id, phys);
 }
 
 static void nfcon_write(struct console *con, const char *str,
@@ -79,7 +81,7 @@
 {
 	char temp[2] = { ch, 0 };
 
-	nf_call(stderr_id, temp);
+	nf_call(stderr_id, virt_to_phys(temp));
 	return 1;
 }
 
diff --git a/arch/m68k/emu/nfeth.c b/arch/m68k/emu/nfeth.c
index 695cd73..a0985fd 100644
--- a/arch/m68k/emu/nfeth.c
+++ b/arch/m68k/emu/nfeth.c
@@ -195,7 +195,8 @@
 	char mac[ETH_ALEN], host_ip[32], local_ip[32];
 	int err;
 
-	if (!nf_call(nfEtherID + XIF_GET_MAC, unit, mac, ETH_ALEN))
+	if (!nf_call(nfEtherID + XIF_GET_MAC, unit, virt_to_phys(mac),
+		     ETH_ALEN))
 		return NULL;
 
 	dev = alloc_etherdev(sizeof(struct nfeth_private));
@@ -217,9 +218,9 @@
 	}
 
 	nf_call(nfEtherID + XIF_GET_IPHOST, unit,
-		host_ip, sizeof(host_ip));
+		virt_to_phys(host_ip), sizeof(host_ip));
 	nf_call(nfEtherID + XIF_GET_IPATARI, unit,
-		local_ip, sizeof(local_ip));
+		virt_to_phys(local_ip), sizeof(local_ip));
 
 	netdev_info(dev, KBUILD_MODNAME " addr:%s (%s) HWaddr:%pM\n", host_ip,
 		    local_ip, mac);
diff --git a/arch/m68k/include/asm/irqflags.h b/arch/m68k/include/asm/irqflags.h
index 7ef4115..a823cd7 100644
--- a/arch/m68k/include/asm/irqflags.h
+++ b/arch/m68k/include/asm/irqflags.h
@@ -3,7 +3,7 @@
 
 #include <linux/types.h>
 #ifdef CONFIG_MMU
-#include <linux/hardirq.h>
+#include <linux/preempt_mask.h>
 #endif
 #include <linux/preempt.h>
 #include <asm/thread_info.h>
@@ -67,6 +67,10 @@
 
 static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
+	if (MACH_IS_ATARI) {
+		/* Ignore HSYNC = ipl 2 on Atari */
+		return (flags & ~(ALLOWINT | 0x200)) != 0;
+	}
 	return (flags & ~ALLOWINT) != 0;
 }
 
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index bea6bcf..7eb9792 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -90,7 +90,7 @@
 		return -ENODEV;
 
 	pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
-	return PTR_RET(pdev);
+	return PTR_ERR_OR_ZERO(pdev);
 }
 
 module_init(rtc_init);
diff --git a/arch/m68k/platform/coldfire/pci.c b/arch/m68k/platform/coldfire/pci.c
index b33f97a..df96792 100644
--- a/arch/m68k/platform/coldfire/pci.c
+++ b/arch/m68k/platform/coldfire/pci.c
@@ -319,7 +319,6 @@
 	pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
 	pci_bus_size_bridges(rootbus);
 	pci_bus_assign_resources(rootbus);
-	pci_enable_bridges(rootbus);
 	return 0;
 }
 
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 658542b..078bb74 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -338,6 +338,6 @@
 		return -ENODEV;
 
 	pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
-	return PTR_RET(pdev);
+	return PTR_ERR_OR_ZERO(pdev);
 }
 arch_initcall(q40_add_kbd_device);
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index 20c5e8e..9977816 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -50,9 +50,6 @@
 
 extern void kdump_move_device_tree(void);
 
-/* CPU OF node matching */
-struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
-
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e12764c..dccd7ce 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2305,9 +2305,9 @@
 
 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
-	  initially work for you.  It may help to enable device hotplugging
-	  support.  As of this writing the exact hardware interface is
-	  strongly in flux, so no good recommendation can be made.
+	  initially work for you.  As of this writing the exact hardware
+	  interface is strongly in flux, so no good recommendation can be
+	  made.
 
 config CRASH_DUMP
 	  bool "Kernel crash dumps"
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 1765bab..faf84c5 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -1335,8 +1335,9 @@
 
 	return len;
 }
+static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill);
 
-static ssize_t show_ntcs(struct device *cd, struct device_attribute *attr,
+static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr,
 			 char *buf)
 {
 	struct vpe *vpe = get_vpe(tclimit);
@@ -1344,7 +1345,7 @@
 	return sprintf(buf, "%d\n", vpe->ntcs);
 }
 
-static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
+static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t len)
 {
 	struct vpe *vpe = get_vpe(tclimit);
@@ -1365,12 +1366,14 @@
 out_einval:
 	return -EINVAL;
 }
+static DEVICE_ATTR_RW(ntcs);
 
-static struct device_attribute vpe_class_attributes[] = {
-	__ATTR(kill, S_IWUSR, NULL, store_kill),
-	__ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs),
-	{}
+static struct attribute vpe_attrs[] = {
+	&dev_attr_kill.attr,
+	&dev_attr_ntcs.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(vpe);
 
 static void vpe_device_release(struct device *cd)
 {
@@ -1381,7 +1384,7 @@
 	.name = "vpe",
 	.owner = THIS_MODULE,
 	.dev_release = vpe_device_release,
-	.dev_attrs = vpe_class_attributes,
+	.dev_groups = vpe_groups,
 };
 
 struct device vpe_device;
diff --git a/arch/mips/kvm/kvm_locore.S b/arch/mips/kvm/kvm_locore.S
index dca2aa6..bbace09 100644
--- a/arch/mips/kvm/kvm_locore.S
+++ b/arch/mips/kvm/kvm_locore.S
@@ -1,13 +1,13 @@
 /*
-* This file is subject to the terms and conditions of the GNU General Public
-* License.  See the file "COPYING" in the main directory of this archive
-* for more details.
-*
-* Main entry point for the guest, exception handling.
-*
-* Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
-* Authors: Sanjay Lal <sanjayl@kymasys.com>
-*/
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Main entry point for the guest, exception handling.
+ *
+ * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
+ * Authors: Sanjay Lal <sanjayl@kymasys.com>
+ */
 
 #include <asm/asm.h>
 #include <asm/asmmacro.h>
@@ -55,195 +55,193 @@
  * a0: run
  * a1: vcpu
  */
+	.set	noreorder
+	.set	noat
 
 FEXPORT(__kvm_mips_vcpu_run)
-    .set    push
-    .set    noreorder
-    .set    noat
+	/* k0/k1 not being used in host kernel context */
+	INT_ADDIU k1, sp, -PT_SIZE
+	LONG_S	$0, PT_R0(k1)
+	LONG_S	$1, PT_R1(k1)
+	LONG_S	$2, PT_R2(k1)
+	LONG_S	$3, PT_R3(k1)
 
-    /* k0/k1 not being used in host kernel context */
-	addiu  		k1,sp, -PT_SIZE
-    LONG_S	    $0, PT_R0(k1)
-    LONG_S     	$1, PT_R1(k1)
-    LONG_S     	$2, PT_R2(k1)
-    LONG_S     	$3, PT_R3(k1)
+	LONG_S	$4, PT_R4(k1)
+	LONG_S	$5, PT_R5(k1)
+	LONG_S	$6, PT_R6(k1)
+	LONG_S	$7, PT_R7(k1)
 
-    LONG_S     	$4, PT_R4(k1)
-    LONG_S     	$5, PT_R5(k1)
-    LONG_S     	$6, PT_R6(k1)
-    LONG_S     	$7, PT_R7(k1)
+	LONG_S	$8,  PT_R8(k1)
+	LONG_S	$9,  PT_R9(k1)
+	LONG_S	$10, PT_R10(k1)
+	LONG_S	$11, PT_R11(k1)
+	LONG_S	$12, PT_R12(k1)
+	LONG_S	$13, PT_R13(k1)
+	LONG_S	$14, PT_R14(k1)
+	LONG_S	$15, PT_R15(k1)
+	LONG_S	$16, PT_R16(k1)
+	LONG_S	$17, PT_R17(k1)
 
-    LONG_S     	$8,  PT_R8(k1)
-    LONG_S     	$9,  PT_R9(k1)
-    LONG_S     	$10, PT_R10(k1)
-    LONG_S     	$11, PT_R11(k1)
-    LONG_S     	$12, PT_R12(k1)
-    LONG_S     	$13, PT_R13(k1)
-    LONG_S     	$14, PT_R14(k1)
-    LONG_S     	$15, PT_R15(k1)
-    LONG_S     	$16, PT_R16(k1)
-    LONG_S     	$17, PT_R17(k1)
-
-    LONG_S     	$18, PT_R18(k1)
-    LONG_S     	$19, PT_R19(k1)
-    LONG_S     	$20, PT_R20(k1)
-    LONG_S     	$21, PT_R21(k1)
-    LONG_S     	$22, PT_R22(k1)
-    LONG_S     	$23, PT_R23(k1)
-    LONG_S     	$24, PT_R24(k1)
-    LONG_S     	$25, PT_R25(k1)
+	LONG_S	$18, PT_R18(k1)
+	LONG_S	$19, PT_R19(k1)
+	LONG_S	$20, PT_R20(k1)
+	LONG_S	$21, PT_R21(k1)
+	LONG_S	$22, PT_R22(k1)
+	LONG_S	$23, PT_R23(k1)
+	LONG_S	$24, PT_R24(k1)
+	LONG_S	$25, PT_R25(k1)
 
 	/* XXXKYMA k0/k1 not saved, not being used if we got here through an ioctl() */
 
-    LONG_S     	$28, PT_R28(k1)
-    LONG_S     	$29, PT_R29(k1)
-    LONG_S     	$30, PT_R30(k1)
-    LONG_S     	$31, PT_R31(k1)
+	LONG_S	$28, PT_R28(k1)
+	LONG_S	$29, PT_R29(k1)
+	LONG_S	$30, PT_R30(k1)
+	LONG_S	$31, PT_R31(k1)
 
-    /* Save hi/lo */
-	mflo		v0
-	LONG_S		v0, PT_LO(k1)
-	mfhi   		v1
-	LONG_S		v1, PT_HI(k1)
+	/* Save hi/lo */
+	mflo	v0
+	LONG_S	v0, PT_LO(k1)
+	mfhi	v1
+	LONG_S	v1, PT_HI(k1)
 
 	/* Save host status */
-	mfc0		v0, CP0_STATUS
-	LONG_S		v0, PT_STATUS(k1)
+	mfc0	v0, CP0_STATUS
+	LONG_S	v0, PT_STATUS(k1)
 
 	/* Save host ASID, shove it into the BVADDR location */
-	mfc0 		v1,CP0_ENTRYHI
-	andi		v1, 0xff
-	LONG_S		v1, PT_HOST_ASID(k1)
+	mfc0	v1, CP0_ENTRYHI
+	andi	v1, 0xff
+	LONG_S	v1, PT_HOST_ASID(k1)
 
-    /* Save DDATA_LO, will be used to store pointer to vcpu */
-    mfc0        v1, CP0_DDATA_LO
-    LONG_S      v1, PT_HOST_USERLOCAL(k1)
+	/* Save DDATA_LO, will be used to store pointer to vcpu */
+	mfc0	v1, CP0_DDATA_LO
+	LONG_S	v1, PT_HOST_USERLOCAL(k1)
 
-    /* DDATA_LO has pointer to vcpu */
-    mtc0        a1,CP0_DDATA_LO
+	/* DDATA_LO has pointer to vcpu */
+	mtc0	a1, CP0_DDATA_LO
 
-    /* Offset into vcpu->arch */
-	addiu		k1, a1, VCPU_HOST_ARCH
+	/* Offset into vcpu->arch */
+	INT_ADDIU k1, a1, VCPU_HOST_ARCH
 
-    /* Save the host stack to VCPU, used for exception processing when we exit from the Guest */
-    LONG_S      sp, VCPU_HOST_STACK(k1)
+	/*
+	 * Save the host stack to VCPU, used for exception processing
+	 * when we exit from the Guest
+	 */
+	LONG_S	sp, VCPU_HOST_STACK(k1)
 
-    /* Save the kernel gp as well */
-    LONG_S      gp, VCPU_HOST_GP(k1)
+	/* Save the kernel gp as well */
+	LONG_S	gp, VCPU_HOST_GP(k1)
 
 	/* Setup status register for running the guest in UM, interrupts are disabled */
-	li			k0,(ST0_EXL | KSU_USER| ST0_BEV)
-	mtc0		k0,CP0_STATUS
-    ehb
+	li	k0, (ST0_EXL | KSU_USER | ST0_BEV)
+	mtc0	k0, CP0_STATUS
+	ehb
 
-    /* load up the new EBASE */
-    LONG_L      k0, VCPU_GUEST_EBASE(k1)
-    mtc0        k0,CP0_EBASE
+	/* load up the new EBASE */
+	LONG_L	k0, VCPU_GUEST_EBASE(k1)
+	mtc0	k0, CP0_EBASE
 
-    /* Now that the new EBASE has been loaded, unset BEV, set interrupt mask as it was
-     * but make sure that timer interrupts are enabled
-     */
-    li          k0,(ST0_EXL | KSU_USER | ST0_IE)
-    andi        v0, v0, ST0_IM
-    or          k0, k0, v0
-    mtc0        k0,CP0_STATUS
-    ehb
+	/*
+	 * Now that the new EBASE has been loaded, unset BEV, set
+	 * interrupt mask as it was but make sure that timer interrupts
+	 * are enabled
+	 */
+	li	k0, (ST0_EXL | KSU_USER | ST0_IE)
+	andi	v0, v0, ST0_IM
+	or	k0, k0, v0
+	mtc0	k0, CP0_STATUS
+	ehb
 
 
 	/* Set Guest EPC */
-	LONG_L		t0, VCPU_PC(k1)
-	mtc0		t0, CP0_EPC
+	LONG_L	t0, VCPU_PC(k1)
+	mtc0	t0, CP0_EPC
 
 FEXPORT(__kvm_mips_load_asid)
-    /* Set the ASID for the Guest Kernel */
-    sll         t0, t0, 1                       /* with kseg0 @ 0x40000000, kernel */
-                                                /* addresses shift to 0x80000000 */
-    bltz        t0, 1f                          /* If kernel */
-	addiu       t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
-    addiu       t1, k1, VCPU_GUEST_USER_ASID    /* else user */
+	/* Set the ASID for the Guest Kernel */
+	INT_SLL	t0, t0, 1	/* with kseg0 @ 0x40000000, kernel */
+			        /* addresses shift to 0x80000000 */
+	bltz	t0, 1f		/* If kernel */
+	 INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
+	INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
 1:
-    /* t1: contains the base of the ASID array, need to get the cpu id  */
-    LONG_L      t2, TI_CPU($28)             /* smp_processor_id */
-    sll         t2, t2, 2                   /* x4 */
-    addu        t3, t1, t2
-    LONG_L      k0, (t3)
-    andi        k0, k0, 0xff
-	mtc0		k0,CP0_ENTRYHI
-    ehb
+	     /* t1: contains the base of the ASID array, need to get the cpu id  */
+	LONG_L	t2, TI_CPU($28)             /* smp_processor_id */
+	INT_SLL	t2, t2, 2                   /* x4 */
+	REG_ADDU t3, t1, t2
+	LONG_L	k0, (t3)
+	andi	k0, k0, 0xff
+	mtc0	k0, CP0_ENTRYHI
+	ehb
 
-    /* Disable RDHWR access */
-    mtc0    zero,  CP0_HWRENA
+	/* Disable RDHWR access */
+	mtc0	zero, CP0_HWRENA
 
-    /* Now load up the Guest Context from VCPU */
-    LONG_L     	$1, VCPU_R1(k1)
-    LONG_L     	$2, VCPU_R2(k1)
-    LONG_L     	$3, VCPU_R3(k1)
+	/* Now load up the Guest Context from VCPU */
+	LONG_L	$1, VCPU_R1(k1)
+	LONG_L	$2, VCPU_R2(k1)
+	LONG_L	$3, VCPU_R3(k1)
 
-    LONG_L     	$4, VCPU_R4(k1)
-    LONG_L     	$5, VCPU_R5(k1)
-    LONG_L     	$6, VCPU_R6(k1)
-    LONG_L     	$7, VCPU_R7(k1)
+	LONG_L	$4, VCPU_R4(k1)
+	LONG_L	$5, VCPU_R5(k1)
+	LONG_L	$6, VCPU_R6(k1)
+	LONG_L	$7, VCPU_R7(k1)
 
-    LONG_L     	$8,  VCPU_R8(k1)
-    LONG_L     	$9,  VCPU_R9(k1)
-    LONG_L     	$10, VCPU_R10(k1)
-    LONG_L     	$11, VCPU_R11(k1)
-    LONG_L     	$12, VCPU_R12(k1)
-    LONG_L     	$13, VCPU_R13(k1)
-    LONG_L     	$14, VCPU_R14(k1)
-    LONG_L     	$15, VCPU_R15(k1)
-    LONG_L     	$16, VCPU_R16(k1)
-    LONG_L     	$17, VCPU_R17(k1)
-    LONG_L     	$18, VCPU_R18(k1)
-    LONG_L     	$19, VCPU_R19(k1)
-    LONG_L     	$20, VCPU_R20(k1)
-    LONG_L     	$21, VCPU_R21(k1)
-    LONG_L     	$22, VCPU_R22(k1)
-    LONG_L     	$23, VCPU_R23(k1)
-    LONG_L     	$24, VCPU_R24(k1)
-    LONG_L     	$25, VCPU_R25(k1)
+	LONG_L	$8, VCPU_R8(k1)
+	LONG_L	$9, VCPU_R9(k1)
+	LONG_L	$10, VCPU_R10(k1)
+	LONG_L	$11, VCPU_R11(k1)
+	LONG_L	$12, VCPU_R12(k1)
+	LONG_L	$13, VCPU_R13(k1)
+	LONG_L	$14, VCPU_R14(k1)
+	LONG_L	$15, VCPU_R15(k1)
+	LONG_L	$16, VCPU_R16(k1)
+	LONG_L	$17, VCPU_R17(k1)
+	LONG_L	$18, VCPU_R18(k1)
+	LONG_L	$19, VCPU_R19(k1)
+	LONG_L	$20, VCPU_R20(k1)
+	LONG_L	$21, VCPU_R21(k1)
+	LONG_L	$22, VCPU_R22(k1)
+	LONG_L	$23, VCPU_R23(k1)
+	LONG_L	$24, VCPU_R24(k1)
+	LONG_L	$25, VCPU_R25(k1)
 
-    /* k0/k1 loaded up later */
+	/* k0/k1 loaded up later */
 
-    LONG_L     	$28, VCPU_R28(k1)
-    LONG_L     	$29, VCPU_R29(k1)
-    LONG_L     	$30, VCPU_R30(k1)
-    LONG_L     	$31, VCPU_R31(k1)
+	LONG_L	$28, VCPU_R28(k1)
+	LONG_L	$29, VCPU_R29(k1)
+	LONG_L	$30, VCPU_R30(k1)
+	LONG_L	$31, VCPU_R31(k1)
 
-    /* Restore hi/lo */
-	LONG_L		k0, VCPU_LO(k1)
-	mtlo		k0
+	/* Restore hi/lo */
+	LONG_L	k0, VCPU_LO(k1)
+	mtlo	k0
 
-	LONG_L		k0, VCPU_HI(k1)
-	mthi   		k0
+	LONG_L	k0, VCPU_HI(k1)
+	mthi	k0
 
 FEXPORT(__kvm_mips_load_k0k1)
 	/* Restore the guest's k0/k1 registers */
-    LONG_L     	k0, VCPU_R26(k1)
-    LONG_L     	k1, VCPU_R27(k1)
+	LONG_L	k0, VCPU_R26(k1)
+	LONG_L	k1, VCPU_R27(k1)
 
-    /* Jump to guest */
+	/* Jump to guest */
 	eret
-	.set	pop
 
 VECTOR(MIPSX(exception), unknown)
 /*
  * Find out what mode we came from and jump to the proper handler.
  */
-    .set    push
-	.set	noat
-    .set    noreorder
-    mtc0    k0, CP0_ERROREPC    #01: Save guest k0
-    ehb                         #02:
+	mtc0	k0, CP0_ERROREPC	#01: Save guest k0
+	ehb				#02:
 
-    mfc0    k0, CP0_EBASE       #02: Get EBASE
-    srl     k0, k0, 10          #03: Get rid of CPUNum
-    sll     k0, k0, 10          #04
-    LONG_S  k1, 0x3000(k0)      #05: Save k1 @ offset 0x3000
-    addiu   k0, k0, 0x2000      #06: Exception handler is installed @ offset 0x2000
-	j	k0				        #07: jump to the function
-	nop				        	#08: branch delay slot
-	.set	push
+	mfc0	k0, CP0_EBASE		#02: Get EBASE
+	INT_SRL	k0, k0, 10		#03: Get rid of CPUNum
+	INT_SLL	k0, k0, 10		#04
+	LONG_S	k1, 0x3000(k0)		#05: Save k1 @ offset 0x3000
+	INT_ADDIU k0, k0, 0x2000		#06: Exception handler is installed @ offset 0x2000
+	j	k0			#07: jump to the function
+	 nop				#08: branch delay slot
 VECTOR_END(MIPSX(exceptionEnd))
 .end MIPSX(exception)
 
@@ -253,329 +251,327 @@
  *
  */
 NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra)
-    .set    push
-    .set    noat
-    .set    noreorder
+	/* Get the VCPU pointer from DDTATA_LO */
+	mfc0	k1, CP0_DDATA_LO
+	INT_ADDIU k1, k1, VCPU_HOST_ARCH
 
-    /* Get the VCPU pointer from DDTATA_LO */
-    mfc0        k1, CP0_DDATA_LO
-	addiu		k1, k1, VCPU_HOST_ARCH
+	/* Start saving Guest context to VCPU */
+	LONG_S	$0, VCPU_R0(k1)
+	LONG_S	$1, VCPU_R1(k1)
+	LONG_S	$2, VCPU_R2(k1)
+	LONG_S	$3, VCPU_R3(k1)
+	LONG_S	$4, VCPU_R4(k1)
+	LONG_S	$5, VCPU_R5(k1)
+	LONG_S	$6, VCPU_R6(k1)
+	LONG_S	$7, VCPU_R7(k1)
+	LONG_S	$8, VCPU_R8(k1)
+	LONG_S	$9, VCPU_R9(k1)
+	LONG_S	$10, VCPU_R10(k1)
+	LONG_S	$11, VCPU_R11(k1)
+	LONG_S	$12, VCPU_R12(k1)
+	LONG_S	$13, VCPU_R13(k1)
+	LONG_S	$14, VCPU_R14(k1)
+	LONG_S	$15, VCPU_R15(k1)
+	LONG_S	$16, VCPU_R16(k1)
+	LONG_S	$17, VCPU_R17(k1)
+	LONG_S	$18, VCPU_R18(k1)
+	LONG_S	$19, VCPU_R19(k1)
+	LONG_S	$20, VCPU_R20(k1)
+	LONG_S	$21, VCPU_R21(k1)
+	LONG_S	$22, VCPU_R22(k1)
+	LONG_S	$23, VCPU_R23(k1)
+	LONG_S	$24, VCPU_R24(k1)
+	LONG_S	$25, VCPU_R25(k1)
 
-    /* Start saving Guest context to VCPU */
-    LONG_S  $0, VCPU_R0(k1)
-    LONG_S  $1, VCPU_R1(k1)
-    LONG_S  $2, VCPU_R2(k1)
-    LONG_S  $3, VCPU_R3(k1)
-    LONG_S  $4, VCPU_R4(k1)
-    LONG_S  $5, VCPU_R5(k1)
-    LONG_S  $6, VCPU_R6(k1)
-    LONG_S  $7, VCPU_R7(k1)
-    LONG_S  $8, VCPU_R8(k1)
-    LONG_S  $9, VCPU_R9(k1)
-    LONG_S  $10, VCPU_R10(k1)
-    LONG_S  $11, VCPU_R11(k1)
-    LONG_S  $12, VCPU_R12(k1)
-    LONG_S  $13, VCPU_R13(k1)
-    LONG_S  $14, VCPU_R14(k1)
-    LONG_S  $15, VCPU_R15(k1)
-    LONG_S  $16, VCPU_R16(k1)
-    LONG_S  $17,VCPU_R17(k1)
-    LONG_S  $18, VCPU_R18(k1)
-    LONG_S  $19, VCPU_R19(k1)
-    LONG_S  $20, VCPU_R20(k1)
-    LONG_S  $21, VCPU_R21(k1)
-    LONG_S  $22, VCPU_R22(k1)
-    LONG_S  $23, VCPU_R23(k1)
-    LONG_S  $24, VCPU_R24(k1)
-    LONG_S  $25, VCPU_R25(k1)
+	/* Guest k0/k1 saved later */
 
-    /* Guest k0/k1 saved later */
+	LONG_S	$28, VCPU_R28(k1)
+	LONG_S	$29, VCPU_R29(k1)
+	LONG_S	$30, VCPU_R30(k1)
+	LONG_S	$31, VCPU_R31(k1)
 
-    LONG_S  $28, VCPU_R28(k1)
-    LONG_S  $29, VCPU_R29(k1)
-    LONG_S  $30, VCPU_R30(k1)
-    LONG_S  $31, VCPU_R31(k1)
+	/* We need to save hi/lo and restore them on
+	 * the way out
+	 */
+	mfhi	t0
+	LONG_S	t0, VCPU_HI(k1)
 
-    /* We need to save hi/lo and restore them on
-     * the way out
-     */
-    mfhi    t0
-    LONG_S  t0, VCPU_HI(k1)
+	mflo	t0
+	LONG_S	t0, VCPU_LO(k1)
 
-    mflo    t0
-    LONG_S  t0, VCPU_LO(k1)
+	/* Finally save guest k0/k1 to VCPU */
+	mfc0	t0, CP0_ERROREPC
+	LONG_S	t0, VCPU_R26(k1)
 
-    /* Finally save guest k0/k1 to VCPU */
-    mfc0    t0, CP0_ERROREPC
-    LONG_S  t0, VCPU_R26(k1)
+	/* Get GUEST k1 and save it in VCPU */
+	PTR_LI	t1, ~0x2ff
+	mfc0	t0, CP0_EBASE
+	and	t0, t0, t1
+	LONG_L	t0, 0x3000(t0)
+	LONG_S	t0, VCPU_R27(k1)
 
-    /* Get GUEST k1 and save it in VCPU */
-    la      t1, ~0x2ff
-    mfc0    t0, CP0_EBASE
-    and     t0, t0, t1
-    LONG_L  t0, 0x3000(t0)
-    LONG_S  t0, VCPU_R27(k1)
+	/* Now that context has been saved, we can use other registers */
 
-    /* Now that context has been saved, we can use other registers */
+	/* Restore vcpu */
+	mfc0	a1, CP0_DDATA_LO
+	move	s1, a1
 
-    /* Restore vcpu */
-    mfc0        a1, CP0_DDATA_LO
-    move        s1, a1
+	/* Restore run (vcpu->run) */
+	LONG_L	a0, VCPU_RUN(a1)
+	/* Save pointer to run in s0, will be saved by the compiler */
+	move	s0, a0
 
-   /* Restore run (vcpu->run) */
-    LONG_L      a0, VCPU_RUN(a1)
-    /* Save pointer to run in s0, will be saved by the compiler */
-    move        s0, a0
+	/* Save Host level EPC, BadVaddr and Cause to VCPU, useful to
+	 * process the exception */
+	mfc0	k0,CP0_EPC
+	LONG_S	k0, VCPU_PC(k1)
+
+	mfc0	k0, CP0_BADVADDR
+	LONG_S	k0, VCPU_HOST_CP0_BADVADDR(k1)
+
+	mfc0	k0, CP0_CAUSE
+	LONG_S	k0, VCPU_HOST_CP0_CAUSE(k1)
+
+	mfc0	k0, CP0_ENTRYHI
+	LONG_S	k0, VCPU_HOST_ENTRYHI(k1)
+
+	/* Now restore the host state just enough to run the handlers */
+
+	/* Swtich EBASE to the one used by Linux */
+	/* load up the host EBASE */
+	mfc0	v0, CP0_STATUS
+
+	.set	at
+	or	k0, v0, ST0_BEV
+	.set	noat
+
+	mtc0	k0, CP0_STATUS
+	ehb
+
+	LONG_L	k0, VCPU_HOST_EBASE(k1)
+	mtc0	k0,CP0_EBASE
 
 
-    /* Save Host level EPC, BadVaddr and Cause to VCPU, useful to process the exception */
-    mfc0    k0,CP0_EPC
-    LONG_S  k0, VCPU_PC(k1)
+	/* Now that the new EBASE has been loaded, unset BEV and KSU_USER */
+	.set	at
+	and	v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE)
+	or	v0, v0, ST0_CU0
+	.set	noat
+	mtc0	v0, CP0_STATUS
+	ehb
 
-    mfc0    k0, CP0_BADVADDR
-    LONG_S  k0, VCPU_HOST_CP0_BADVADDR(k1)
+	/* Load up host GP */
+	LONG_L	gp, VCPU_HOST_GP(k1)
 
-    mfc0    k0, CP0_CAUSE
-    LONG_S  k0, VCPU_HOST_CP0_CAUSE(k1)
+	/* Need a stack before we can jump to "C" */
+	LONG_L	sp, VCPU_HOST_STACK(k1)
 
-    mfc0    k0, CP0_ENTRYHI
-    LONG_S  k0, VCPU_HOST_ENTRYHI(k1)
+	/* Saved host state */
+	INT_ADDIU sp, sp, -PT_SIZE
 
-    /* Now restore the host state just enough to run the handlers */
+	/* XXXKYMA do we need to load the host ASID, maybe not because the
+	 * kernel entries are marked GLOBAL, need to verify
+	 */
 
-    /* Swtich EBASE to the one used by Linux */
-    /* load up the host EBASE */
-    mfc0        v0, CP0_STATUS
+	/* Restore host DDATA_LO */
+	LONG_L	k0, PT_HOST_USERLOCAL(sp)
+	mtc0	k0, CP0_DDATA_LO
 
-    .set at
-	or          k0, v0, ST0_BEV
-    .set noat
+	/* Restore RDHWR access */
+	PTR_LI	k0, 0x2000000F
+	mtc0	k0, CP0_HWRENA
 
-    mtc0        k0, CP0_STATUS
-    ehb
-
-    LONG_L      k0, VCPU_HOST_EBASE(k1)
-    mtc0        k0,CP0_EBASE
-
-
-    /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */
-    .set at
-	and         v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE)
-    or          v0, v0, ST0_CU0
-    .set noat
-    mtc0        v0, CP0_STATUS
-    ehb
-
-    /* Load up host GP */
-    LONG_L  gp, VCPU_HOST_GP(k1)
-
-    /* Need a stack before we can jump to "C" */
-    LONG_L  sp, VCPU_HOST_STACK(k1)
-
-    /* Saved host state */
-    addiu   sp,sp, -PT_SIZE
-
-    /* XXXKYMA do we need to load the host ASID, maybe not because the
-     * kernel entries are marked GLOBAL, need to verify
-     */
-
-    /* Restore host DDATA_LO */
-    LONG_L      k0, PT_HOST_USERLOCAL(sp)
-    mtc0        k0, CP0_DDATA_LO
-
-    /* Restore RDHWR access */
-    la      k0, 0x2000000F
-    mtc0    k0,  CP0_HWRENA
-
-    /* Jump to handler */
+	/* Jump to handler */
 FEXPORT(__kvm_mips_jump_to_handler)
-    /* XXXKYMA: not sure if this is safe, how large is the stack?? */
-    /* Now jump to the kvm_mips_handle_exit() to see if we can deal with this in the kernel */
-    la          t9,kvm_mips_handle_exit
-    jalr.hb     t9
-    addiu       sp,sp, -CALLFRAME_SIZ           /* BD Slot */
+	/* XXXKYMA: not sure if this is safe, how large is the stack??
+	 * Now jump to the kvm_mips_handle_exit() to see if we can deal
+	 * with this in the kernel */
+	PTR_LA	t9, kvm_mips_handle_exit
+	jalr.hb	t9
+	 INT_ADDIU sp, sp, -CALLFRAME_SIZ           /* BD Slot */
 
-    /* Return from handler Make sure interrupts are disabled */
-    di
-    ehb
+	/* Return from handler Make sure interrupts are disabled */
+	di
+	ehb
 
-    /* XXXKYMA: k0/k1 could have been blown away if we processed an exception
-     * while we were handling the exception from the guest, reload k1
-     */
-    move        k1, s1
-	addiu		k1, k1, VCPU_HOST_ARCH
+	/* XXXKYMA: k0/k1 could have been blown away if we processed
+	 * an exception while we were handling the exception from the
+	 * guest, reload k1
+	 */
 
-    /* Check return value, should tell us if we are returning to the host (handle I/O etc)
-     * or resuming the guest
-     */
-    andi        t0, v0, RESUME_HOST
-    bnez        t0, __kvm_mips_return_to_host
-    nop
+	move	k1, s1
+	INT_ADDIU k1, k1, VCPU_HOST_ARCH
+
+	/* Check return value, should tell us if we are returning to the
+	 * host (handle I/O etc)or resuming the guest
+	 */
+	andi	t0, v0, RESUME_HOST
+	bnez	t0, __kvm_mips_return_to_host
+	 nop
 
 __kvm_mips_return_to_guest:
-    /* Put the saved pointer to vcpu (s1) back into the DDATA_LO Register */
-    mtc0        s1, CP0_DDATA_LO
+	/* Put the saved pointer to vcpu (s1) back into the DDATA_LO Register */
+	mtc0	s1, CP0_DDATA_LO
 
-    /* Load up the Guest EBASE to minimize the window where BEV is set */
-    LONG_L      t0, VCPU_GUEST_EBASE(k1)
+	/* Load up the Guest EBASE to minimize the window where BEV is set */
+	LONG_L	t0, VCPU_GUEST_EBASE(k1)
 
-    /* Switch EBASE back to the one used by KVM */
-    mfc0        v1, CP0_STATUS
-    .set at
-	or          k0, v1, ST0_BEV
-    .set noat
-    mtc0        k0, CP0_STATUS
-    ehb
-    mtc0        t0,CP0_EBASE
+	/* Switch EBASE back to the one used by KVM */
+	mfc0	v1, CP0_STATUS
+	.set	at
+	or	k0, v1, ST0_BEV
+	.set	noat
+	mtc0	k0, CP0_STATUS
+	ehb
+	mtc0	t0, CP0_EBASE
 
-    /* Setup status register for running guest in UM */
-    .set at
-    or     v1, v1, (ST0_EXL | KSU_USER | ST0_IE)
-    and     v1, v1, ~ST0_CU0
-    .set noat
-    mtc0    v1, CP0_STATUS
-    ehb
-
+	/* Setup status register for running guest in UM */
+	.set	at
+	or	v1, v1, (ST0_EXL | KSU_USER | ST0_IE)
+	and	v1, v1, ~ST0_CU0
+	.set	noat
+	mtc0	v1, CP0_STATUS
+	ehb
 
 	/* Set Guest EPC */
-	LONG_L		t0, VCPU_PC(k1)
-	mtc0		t0, CP0_EPC
+	LONG_L	t0, VCPU_PC(k1)
+	mtc0	t0, CP0_EPC
 
-    /* Set the ASID for the Guest Kernel */
-    sll         t0, t0, 1                       /* with kseg0 @ 0x40000000, kernel */
-                                                /* addresses shift to 0x80000000 */
-    bltz        t0, 1f                          /* If kernel */
-	addiu       t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
-    addiu       t1, k1, VCPU_GUEST_USER_ASID    /* else user */
+	/* Set the ASID for the Guest Kernel */
+	INT_SLL	t0, t0, 1	/* with kseg0 @ 0x40000000, kernel */
+				/* addresses shift to 0x80000000 */
+	bltz	t0, 1f		/* If kernel */
+	 INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID  /* (BD)  */
+	INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID    /* else user */
 1:
-    /* t1: contains the base of the ASID array, need to get the cpu id  */
-    LONG_L      t2, TI_CPU($28)             /* smp_processor_id */
-    sll         t2, t2, 2                   /* x4 */
-    addu        t3, t1, t2
-    LONG_L      k0, (t3)
-    andi        k0, k0, 0xff
-	mtc0		k0,CP0_ENTRYHI
-    ehb
+	/* t1: contains the base of the ASID array, need to get the cpu id  */
+	LONG_L	t2, TI_CPU($28)		/* smp_processor_id */
+	INT_SLL	t2, t2, 2		/* x4 */
+	REG_ADDU t3, t1, t2
+	LONG_L	k0, (t3)
+	andi	k0, k0, 0xff
+	mtc0	k0,CP0_ENTRYHI
+	ehb
 
-    /* Disable RDHWR access */
-    mtc0    zero,  CP0_HWRENA
+	/* Disable RDHWR access */
+	mtc0    zero,  CP0_HWRENA
 
-    /* load the guest context from VCPU and return */
-    LONG_L  $0, VCPU_R0(k1)
-    LONG_L  $1, VCPU_R1(k1)
-    LONG_L  $2, VCPU_R2(k1)
-    LONG_L  $3, VCPU_R3(k1)
-    LONG_L  $4, VCPU_R4(k1)
-    LONG_L  $5, VCPU_R5(k1)
-    LONG_L  $6, VCPU_R6(k1)
-    LONG_L  $7, VCPU_R7(k1)
-    LONG_L  $8, VCPU_R8(k1)
-    LONG_L  $9, VCPU_R9(k1)
-    LONG_L  $10, VCPU_R10(k1)
-    LONG_L  $11, VCPU_R11(k1)
-    LONG_L  $12, VCPU_R12(k1)
-    LONG_L  $13, VCPU_R13(k1)
-    LONG_L  $14, VCPU_R14(k1)
-    LONG_L  $15, VCPU_R15(k1)
-    LONG_L  $16, VCPU_R16(k1)
-    LONG_L  $17, VCPU_R17(k1)
-    LONG_L  $18, VCPU_R18(k1)
-    LONG_L  $19, VCPU_R19(k1)
-    LONG_L  $20, VCPU_R20(k1)
-    LONG_L  $21, VCPU_R21(k1)
-    LONG_L  $22, VCPU_R22(k1)
-    LONG_L  $23, VCPU_R23(k1)
-    LONG_L  $24, VCPU_R24(k1)
-    LONG_L  $25, VCPU_R25(k1)
+	/* load the guest context from VCPU and return */
+	LONG_L	$0, VCPU_R0(k1)
+	LONG_L	$1, VCPU_R1(k1)
+	LONG_L	$2, VCPU_R2(k1)
+	LONG_L	$3, VCPU_R3(k1)
+	LONG_L	$4, VCPU_R4(k1)
+	LONG_L	$5, VCPU_R5(k1)
+	LONG_L	$6, VCPU_R6(k1)
+	LONG_L	$7, VCPU_R7(k1)
+	LONG_L	$8, VCPU_R8(k1)
+	LONG_L	$9, VCPU_R9(k1)
+	LONG_L	$10, VCPU_R10(k1)
+	LONG_L	$11, VCPU_R11(k1)
+	LONG_L	$12, VCPU_R12(k1)
+	LONG_L	$13, VCPU_R13(k1)
+	LONG_L	$14, VCPU_R14(k1)
+	LONG_L	$15, VCPU_R15(k1)
+	LONG_L	$16, VCPU_R16(k1)
+	LONG_L	$17, VCPU_R17(k1)
+	LONG_L	$18, VCPU_R18(k1)
+	LONG_L	$19, VCPU_R19(k1)
+	LONG_L	$20, VCPU_R20(k1)
+	LONG_L	$21, VCPU_R21(k1)
+	LONG_L	$22, VCPU_R22(k1)
+	LONG_L	$23, VCPU_R23(k1)
+	LONG_L	$24, VCPU_R24(k1)
+	LONG_L	$25, VCPU_R25(k1)
 
-    /* $/k1 loaded later */
-    LONG_L  $28, VCPU_R28(k1)
-    LONG_L  $29, VCPU_R29(k1)
-    LONG_L  $30, VCPU_R30(k1)
-    LONG_L  $31, VCPU_R31(k1)
+	/* $/k1 loaded later */
+	LONG_L	$28, VCPU_R28(k1)
+	LONG_L	$29, VCPU_R29(k1)
+	LONG_L	$30, VCPU_R30(k1)
+	LONG_L	$31, VCPU_R31(k1)
 
 FEXPORT(__kvm_mips_skip_guest_restore)
-    LONG_L  k0, VCPU_HI(k1)
-    mthi    k0
+	LONG_L	k0, VCPU_HI(k1)
+	mthi	k0
 
-    LONG_L  k0, VCPU_LO(k1)
-    mtlo    k0
+	LONG_L	k0, VCPU_LO(k1)
+	mtlo	k0
 
-    LONG_L  k0, VCPU_R26(k1)
-    LONG_L  k1, VCPU_R27(k1)
+	LONG_L	k0, VCPU_R26(k1)
+	LONG_L	k1, VCPU_R27(k1)
 
-    eret
+	eret
 
 __kvm_mips_return_to_host:
-    /* EBASE is already pointing to Linux */
-    LONG_L  k1, VCPU_HOST_STACK(k1)
-	addiu  	k1,k1, -PT_SIZE
+	/* EBASE is already pointing to Linux */
+	LONG_L	k1, VCPU_HOST_STACK(k1)
+	INT_ADDIU k1,k1, -PT_SIZE
 
-    /* Restore host DDATA_LO */
-    LONG_L      k0, PT_HOST_USERLOCAL(k1)
-    mtc0        k0, CP0_DDATA_LO
+	/* Restore host DDATA_LO */
+	LONG_L	k0, PT_HOST_USERLOCAL(k1)
+	mtc0	k0, CP0_DDATA_LO
 
-    /* Restore host ASID */
-    LONG_L      k0, PT_HOST_ASID(sp)
-    andi        k0, 0xff
-    mtc0        k0,CP0_ENTRYHI
-    ehb
+	/* Restore host ASID */
+	LONG_L	k0, PT_HOST_ASID(sp)
+	andi	k0, 0xff
+	mtc0	k0,CP0_ENTRYHI
+	ehb
 
-    /* Load context saved on the host stack */
-    LONG_L  $0, PT_R0(k1)
-    LONG_L  $1, PT_R1(k1)
+	/* Load context saved on the host stack */
+	LONG_L	$0, PT_R0(k1)
+	LONG_L	$1, PT_R1(k1)
 
-    /* r2/v0 is the return code, shift it down by 2 (arithmetic) to recover the err code  */
-    sra     k0, v0, 2
-    move    $2, k0
+	/* r2/v0 is the return code, shift it down by 2 (arithmetic)
+	 * to recover the err code  */
+	INT_SRA	k0, v0, 2
+	move	$2, k0
 
-    LONG_L  $3, PT_R3(k1)
-    LONG_L  $4, PT_R4(k1)
-    LONG_L  $5, PT_R5(k1)
-    LONG_L  $6, PT_R6(k1)
-    LONG_L  $7, PT_R7(k1)
-    LONG_L  $8, PT_R8(k1)
-    LONG_L  $9, PT_R9(k1)
-    LONG_L  $10, PT_R10(k1)
-    LONG_L  $11, PT_R11(k1)
-    LONG_L  $12, PT_R12(k1)
-    LONG_L  $13, PT_R13(k1)
-    LONG_L  $14, PT_R14(k1)
-    LONG_L  $15, PT_R15(k1)
-    LONG_L  $16, PT_R16(k1)
-    LONG_L  $17, PT_R17(k1)
-    LONG_L  $18, PT_R18(k1)
-    LONG_L  $19, PT_R19(k1)
-    LONG_L  $20, PT_R20(k1)
-    LONG_L  $21, PT_R21(k1)
-    LONG_L  $22, PT_R22(k1)
-    LONG_L  $23, PT_R23(k1)
-    LONG_L  $24, PT_R24(k1)
-    LONG_L  $25, PT_R25(k1)
+	LONG_L	$3, PT_R3(k1)
+	LONG_L	$4, PT_R4(k1)
+	LONG_L	$5, PT_R5(k1)
+	LONG_L	$6, PT_R6(k1)
+	LONG_L	$7, PT_R7(k1)
+	LONG_L	$8, PT_R8(k1)
+	LONG_L	$9, PT_R9(k1)
+	LONG_L	$10, PT_R10(k1)
+	LONG_L	$11, PT_R11(k1)
+	LONG_L	$12, PT_R12(k1)
+	LONG_L	$13, PT_R13(k1)
+	LONG_L	$14, PT_R14(k1)
+	LONG_L	$15, PT_R15(k1)
+	LONG_L	$16, PT_R16(k1)
+	LONG_L	$17, PT_R17(k1)
+	LONG_L	$18, PT_R18(k1)
+	LONG_L	$19, PT_R19(k1)
+	LONG_L	$20, PT_R20(k1)
+	LONG_L	$21, PT_R21(k1)
+	LONG_L	$22, PT_R22(k1)
+	LONG_L	$23, PT_R23(k1)
+	LONG_L	$24, PT_R24(k1)
+	LONG_L	$25, PT_R25(k1)
 
-    /* Host k0/k1 were not saved */
+	/* Host k0/k1 were not saved */
 
-    LONG_L  $28, PT_R28(k1)
-    LONG_L  $29, PT_R29(k1)
-    LONG_L  $30, PT_R30(k1)
+	LONG_L	$28, PT_R28(k1)
+	LONG_L	$29, PT_R29(k1)
+	LONG_L	$30, PT_R30(k1)
 
-    LONG_L  k0, PT_HI(k1)
-    mthi    k0
+	LONG_L	k0, PT_HI(k1)
+	mthi	k0
 
-    LONG_L  k0, PT_LO(k1)
-    mtlo    k0
+	LONG_L	k0, PT_LO(k1)
+	mtlo	k0
 
-    /* Restore RDHWR access */
-    la      k0, 0x2000000F
-    mtc0    k0,  CP0_HWRENA
+	/* Restore RDHWR access */
+	PTR_LI	k0, 0x2000000F
+	mtc0	k0,  CP0_HWRENA
 
 
-    /* Restore RA, which is the address we will return to */
-    LONG_L  ra, PT_R31(k1)
-    j       ra
-    nop
+	/* Restore RA, which is the address we will return to */
+	LONG_L  ra, PT_R31(k1)
+	j       ra
+	 nop
 
-    .set    pop
 VECTOR_END(MIPSX(GuestExceptionEnd))
 .end MIPSX(GuestException)
 
@@ -627,24 +623,23 @@
 
 #define HW_SYNCI_Step       $1
 LEAF(MIPSX(SyncICache))
-    .set    push
+	.set	push
 	.set	mips32r2
-    beq     a1, zero, 20f
-    nop
-    addu    a1, a0, a1
-    rdhwr   v0, HW_SYNCI_Step
-    beq     v0, zero, 20f
-    nop
-
+	beq	a1, zero, 20f
+	 nop
+	REG_ADDU a1, a0, a1
+	rdhwr	v0, HW_SYNCI_Step
+	beq	v0, zero, 20f
+	 nop
 10:
-    synci   0(a0)
-    addu    a0, a0, v0
-    sltu    v1, a0, a1
-    bne     v1, zero, 10b
-    nop
-    sync
+	synci	0(a0)
+	REG_ADDU a0, a0, v0
+	sltu	v1, a0, a1
+	bne	v1, zero, 10b
+	 nop
+	sync
 20:
-    jr.hb   ra
-    nop
-    .set pop
+	jr.hb	ra
+	 nop
+	.set	pop
 END(MIPSX(SyncICache))
diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c
index dd203e5..a7b0445 100644
--- a/arch/mips/kvm/kvm_mips.c
+++ b/arch/mips/kvm/kvm_mips.c
@@ -208,6 +208,10 @@
 	return 0;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
                                 struct kvm_memory_slot *memslot,
                                 struct kvm_userspace_memory_region *mem,
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index e773659..46048d2 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -803,6 +803,32 @@
 				dec_insn.next_pc_inc;
 		return 1;
 		break;
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+	case lwc2_op: /* This is bbit0 on Octeon */
+		if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0)
+			*contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
+		else
+			*contpc = regs->cp0_epc + 8;
+		return 1;
+	case ldc2_op: /* This is bbit032 on Octeon */
+		if ((regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32))) == 0)
+			*contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
+		else
+			*contpc = regs->cp0_epc + 8;
+		return 1;
+	case swc2_op: /* This is bbit1 on Octeon */
+		if (regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt))
+			*contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
+		else
+			*contpc = regs->cp0_epc + 8;
+		return 1;
+	case sdc2_op: /* This is bbit132 on Octeon */
+		if (regs->regs[insn.i_format.rs] & (1ull<<(insn.i_format.rt + 32)))
+			*contpc = regs->cp0_epc + 4 + (insn.i_format.simmediate << 2);
+		else
+			*contpc = regs->cp0_epc + 8;
+		return 1;
+#endif
 	case cop0_op:
 	case cop1_op:
 	case cop2_op:
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 594e60d..33e7aa5 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -113,7 +113,6 @@
 		if (!pci_has_flag(PCI_PROBE_ONLY)) {
 			pci_bus_size_bridges(bus);
 			pci_bus_assign_resources(bus);
-			pci_enable_bridges(bus);
 		}
 	}
 }
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
index dd0ab98..f9407e1 100644
--- a/arch/mips/sni/a20r.c
+++ b/arch/mips/sni/a20r.c
@@ -122,7 +122,6 @@
 
 static struct sccnxp_pdata sccnxp_data = {
 	.reg_shift	= 2,
-	.frequency	= 3686400,
 	.mctrl_cfg[0]	= MCTRL_SIG(DTR_OP, LINE_OP7) |
 			  MCTRL_SIG(RTS_OP, LINE_OP3) |
 			  MCTRL_SIG(DSR_IP, LINE_IP5) |
diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h
index bbb34e5..eb59bfe 100644
--- a/arch/openrisc/include/asm/prom.h
+++ b/arch/openrisc/include/asm/prom.h
@@ -44,9 +44,6 @@
 
 extern void kdump_move_device_tree(void);
 
-/* CPU OF node matching */
-struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
-
 /* Get the MAC address */
 extern const void *of_get_mac_address(struct device_node *np);
 
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index dbd9d3c..5aecda0 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -369,9 +369,9 @@
 
 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
-	  initially work for you.  It may help to enable device hotplugging
-	  support.  As of this writing the exact hardware interface is
-	  strongly in flux, so no good recommendation can be made.
+	  initially work for you.  As of this writing the exact hardware
+	  interface is strongly in flux, so no good recommendation can be
+	  made.
 
 config CRASH_DUMP
 	bool "Build a kdump crash kernel"
@@ -979,6 +979,7 @@
 	  must live at a different physical address than the primary
 	  kernel.
 
+# This value must have zeroes in the bottom 60 bits otherwise lots will break
 config PAGE_OFFSET
 	hex
 	default "0xc000000000000000"
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index 650757c..704e6f1 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -2,3 +2,4 @@
 generic-y += clkdev.h
 generic-y += rwsem.h
 generic-y += trace_clock.h
+generic-y += vtime.h
\ No newline at end of file
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 08891d0..fa19e2f 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -334,6 +334,27 @@
 	return r;
 }
 
+/*
+ * Like kvmppc_get_last_inst(), but for fetching a sc instruction.
+ * Because the sc instruction sets SRR0 to point to the following
+ * instruction, we have to fetch from pc - 4.
+ */
+static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
+{
+	ulong pc = kvmppc_get_pc(vcpu) - 4;
+	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+	u32 r;
+
+	/* Load the instruction manually if it failed to do so in the
+	 * exit path */
+	if (svcpu->last_inst == KVM_INST_FETCH_FAILED)
+		kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false);
+
+	r = svcpu->last_inst;
+	svcpu_put(svcpu);
+	return r;
+}
+
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
@@ -446,6 +467,23 @@
 	return vcpu->arch.last_inst;
 }
 
+/*
+ * Like kvmppc_get_last_inst(), but for fetching a sc instruction.
+ * Because the sc instruction sets SRR0 to point to the following
+ * instruction, we have to fetch from pc - 4.
+ */
+static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
+{
+	ulong pc = kvmppc_get_pc(vcpu) - 4;
+
+	/* Load the instruction manually if it failed to do so in the
+	 * exit path */
+	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
+		kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
+
+	return vcpu->arch.last_inst;
+}
+
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.fault_dar;
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index a1ecb14..86d638a 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -37,7 +37,7 @@
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
 #define KVM_DEFAULT_HPT_ORDER	24	/* 16MB HPT by default */
-extern int kvm_hpt_order;		/* order of preallocated HPTs */
+extern unsigned long kvm_rma_pages;
 #endif
 
 #define VRMA_VSID	0x1ffffffUL	/* 1TB VSID reserved for VRMA */
@@ -100,7 +100,7 @@
 			/* (masks depend on page size) */
 			rb |= 0x1000;		/* page encoding in LP field */
 			rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
-			rb |= (va_low & 0xfe);	/* AVAL field (P7 doesn't seem to care) */
+			rb |= ((va_low << 4) & 0xf0);	/* AVAL field (P7 doesn't seem to care) */
 		}
 	} else {
 		/* 4kB page */
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index af326cd..3328353 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -183,13 +183,9 @@
 	struct page *pages[0];
 };
 
-struct kvmppc_linear_info {
-	void		*base_virt;
-	unsigned long	 base_pfn;
-	unsigned long	 npages;
-	struct list_head list;
-	atomic_t	 use_count;
-	int		 type;
+struct kvm_rma_info {
+	atomic_t use_count;
+	unsigned long base_pfn;
 };
 
 /* XICS components, defined in book3s_xics.c */
@@ -246,7 +242,7 @@
 	int tlbie_lock;
 	unsigned long lpcr;
 	unsigned long rmor;
-	struct kvmppc_linear_info *rma;
+	struct kvm_rma_info *rma;
 	unsigned long vrma_slb_v;
 	int rma_setup_done;
 	int using_mmu_notifiers;
@@ -259,7 +255,7 @@
 	spinlock_t slot_phys_lock;
 	cpumask_t need_tlb_flush;
 	struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
-	struct kvmppc_linear_info *hpt_li;
+	int hpt_cma_alloc;
 #endif /* CONFIG_KVM_BOOK3S_64_HV */
 #ifdef CONFIG_PPC_BOOK3S_64
 	struct list_head spapr_tce_tables;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index a5287fe..b15554a 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -137,10 +137,10 @@
 			     unsigned long ioba, unsigned long tce);
 extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm,
 				struct kvm_allocate_rma *rma);
-extern struct kvmppc_linear_info *kvm_alloc_rma(void);
-extern void kvm_release_rma(struct kvmppc_linear_info *ri);
-extern struct kvmppc_linear_info *kvm_alloc_hpt(void);
-extern void kvm_release_hpt(struct kvmppc_linear_info *li);
+extern struct kvm_rma_info *kvm_alloc_rma(void);
+extern void kvm_release_rma(struct kvm_rma_info *ri);
+extern struct page *kvm_alloc_hpt(unsigned long nr_pages);
+extern void kvm_release_hpt(struct page *page, unsigned long nr_pages);
 extern int kvmppc_core_init_vm(struct kvm *kvm);
 extern void kvmppc_core_destroy_vm(struct kvm *kvm);
 extern void kvmppc_core_free_memslot(struct kvm_memory_slot *free,
@@ -261,6 +261,7 @@
 struct openpic;
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
+extern void kvm_cma_reserve(void) __init;
 static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
 {
 	paca[cpu].kvm_hstate.xics_phys = addr;
@@ -281,13 +282,12 @@
 }
 
 extern void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu);
-extern void kvm_linear_init(void);
 
 #else
-static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
+static inline void __init kvm_cma_reserve(void)
 {}
 
-static inline void kvm_linear_init(void)
+static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
 {}
 
 static inline u32 kvmppc_get_xics_latch(void)
@@ -394,10 +394,15 @@
 	}
 }
 
-/* Please call after prepare_to_enter. This function puts the lazy ee state
-   back to normal mode, without actually enabling interrupts. */
-static inline void kvmppc_lazy_ee_enable(void)
+/*
+ * Please call after prepare_to_enter. This function puts the lazy ee and irq
+ * disabled tracking state back to normal mode, without actually enabling
+ * interrupts.
+ */
+static inline void kvmppc_fix_ee_before_entry(void)
 {
+	trace_hardirqs_on();
+
 #ifdef CONFIG_PPC64
 	/* Only need to enable IRQs by hard enabling them after this */
 	local_paca->irq_happened = 0;
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 988c812..b9f4262 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -211,9 +211,19 @@
 #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + VIRT_PHYS_OFFSET))
 #define __pa(x) ((unsigned long)(x) - VIRT_PHYS_OFFSET)
 #else
+#ifdef CONFIG_PPC64
+/*
+ * gcc miscompiles (unsigned long)(&static_var) - PAGE_OFFSET
+ * with -mcmodel=medium, so we use & and | instead of - and + on 64-bit.
+ */
+#define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) | PAGE_OFFSET))
+#define __pa(x) ((unsigned long)(x) & 0x0fffffffffffffffUL)
+
+#else /* 32-bit, non book E */
 #define __va(x) ((void *)(unsigned long)((phys_addr_t)(x) + PAGE_OFFSET - MEMORY_START))
 #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
 #endif
+#endif
 
 /*
  * Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 8b24926..3fd2f1b6 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -138,11 +138,11 @@
 #define	EVENT_PTR(_id, _suffix)		&EVENT_VAR(_id, _suffix).attr.attr
 
 #define	EVENT_ATTR(_name, _id, _suffix)					\
-	PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id,	\
+	PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_##_id,	\
 			power_events_sysfs_show)
 
 #define	GENERIC_EVENT_ATTR(_name, _id)	EVENT_ATTR(_name, _id, _g)
 #define	GENERIC_EVENT_PTR(_id)		EVENT_PTR(_id, _g)
 
-#define	POWER_EVENT_ATTR(_name, _id)	EVENT_ATTR(PM_##_name, _id, _p)
+#define	POWER_EVENT_ATTR(_name, _id)	EVENT_ATTR(_name, _id, _p)
 #define	POWER_EVENT_PTR(_id)		EVENT_PTR(_id, _p)
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index bc2da15..ac204e0 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -43,9 +43,6 @@
 
 extern void kdump_move_device_tree(void);
 
-/* CPU OF node matching */
-struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
-
 /* cache lookup */
 struct device_node *of_find_next_cache_node(struct device_node *np);
 
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 8207459..d8958be 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -454,6 +454,7 @@
 	DEFINE(VCPU_SPRG2, offsetof(struct kvm_vcpu, arch.shregs.sprg2));
 	DEFINE(VCPU_SPRG3, offsetof(struct kvm_vcpu, arch.shregs.sprg3));
 #endif
+	DEFINE(VCPU_SHARED_SPRG3, offsetof(struct kvm_vcpu_arch_shared, sprg3));
 	DEFINE(VCPU_SHARED_SPRG4, offsetof(struct kvm_vcpu_arch_shared, sprg4));
 	DEFINE(VCPU_SHARED_SPRG5, offsetof(struct kvm_vcpu_arch_shared, sprg5));
 	DEFINE(VCPU_SHARED_SPRG6, offsetof(struct kvm_vcpu_arch_shared, sprg6));
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index b20ff17..0adab06 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -105,7 +105,7 @@
 	struct dentry *dir = fault_create_debugfs_attr("fail_iommu",
 						       NULL, &fail_iommu);
 
-	return PTR_RET(dir);
+	return PTR_ERR_OR_ZERO(dir);
 }
 late_initcall(fail_iommu_debugfs);
 
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index d92f387..e2a0a16 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -35,7 +35,13 @@
 #include <asm/vdso_datapage.h>
 #include <asm/vio.h>
 #include <asm/mmu.h>
+#include <asm/machdep.h>
 
+
+/*
+ * This isn't a module but we expose that to userspace
+ * via /proc so leave the definitions here
+ */
 #define MODULE_VERS "1.9"
 #define MODULE_NAME "lparcfg"
 
@@ -418,7 +424,8 @@
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
 
-	if (plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
+	if (firmware_has_feature(FW_FEATURE_LPAR) &&
+	    plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
 		seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]);
 }
 
@@ -677,7 +684,6 @@
 }
 
 static const struct file_operations lparcfg_fops = {
-	.owner		= THIS_MODULE,
 	.read		= seq_read,
 	.write		= lparcfg_write,
 	.open		= lparcfg_open,
@@ -699,14 +705,4 @@
 	}
 	return 0;
 }
-
-static void __exit lparcfg_cleanup(void)
-{
-	remove_proc_subtree("powerpc/lparcfg", NULL);
-}
-
-module_init(lparcfg_init);
-module_exit(lparcfg_cleanup);
-MODULE_DESCRIPTION("Interface for LPAR configuration data");
-MODULE_AUTHOR("Dave Engebretsen");
-MODULE_LICENSE("GPL");
+machine_device_initcall(pseries, lparcfg_init);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 7d22a67..2b4a9a4 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1674,12 +1674,8 @@
 	/* Configure PCI Express settings */
 	if (bus && !pci_has_flag(PCI_PROBE_ONLY)) {
 		struct pci_bus *child;
-		list_for_each_entry(child, &bus->children, node) {
-			struct pci_dev *self = child->self;
-			if (!self)
-				continue;
-			pcie_bus_configure_settings(child, self->pcie_mpss);
-		}
+		list_for_each_entry(child, &bus->children, node)
+			pcie_bus_configure_settings(child);
 	}
 }
 
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index eb23ac9..1c14cd4 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -865,49 +865,10 @@
 __initcall(prom_reconfig_setup);
 #endif
 
-/* Find the device node for a given logical cpu number, also returns the cpu
- * local thread number (index in ibm,interrupt-server#s) if relevant and
- * asked for (non NULL)
- */
-struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
 {
-	int hardid;
-	struct device_node *np;
-
-	hardid = get_hard_smp_processor_id(cpu);
-
-	for_each_node_by_type(np, "cpu") {
-		const u32 *intserv;
-		unsigned int plen, t;
-
-		/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
-		 * fallback to "reg" property and assume no threads
-		 */
-		intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
-				&plen);
-		if (intserv == NULL) {
-			const u32 *reg = of_get_property(np, "reg", NULL);
-			if (reg == NULL)
-				continue;
-			if (*reg == hardid) {
-				if (thread)
-					*thread = 0;
-				return np;
-			}
-		} else {
-			plen /= sizeof(u32);
-			for (t = 0; t < plen; t++) {
-				if (hardid == intserv[t]) {
-					if (thread)
-						*thread = t;
-					return np;
-				}
-			}
-		}
-	}
-	return NULL;
+	return (int)phys_id == get_hard_smp_processor_id(cpu);
 }
-EXPORT_SYMBOL(of_get_cpu_node);
 
 #if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
 static struct debugfs_blob_wrapper flat_dt_blob;
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 389fb807..fe6a58c 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -229,6 +229,8 @@
 	/* Initialize the hash table or TLB handling */
 	early_init_mmu();
 
+	kvm_cma_reserve();
+
 	/*
 	 * Reserve any gigantic pages requested on the command line.
 	 * memblock needs to have been initialized by the time this is
@@ -609,8 +611,6 @@
 	/* Initialize the MMU context management stuff */
 	mmu_context_init();
 
-	kvm_linear_init();
-
 	/* Interrupt code needs to be 64K-aligned */
 	if ((unsigned long)_stext & 0xffff)
 		panic("Kernelbase not 64K-aligned (0x%lx)!\n",
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 65ab9e9..cdcc156 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -1049,7 +1049,7 @@
 
 	pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
 
-	return PTR_RET(pdev);
+	return PTR_ERR_OR_ZERO(pdev);
 }
 
 module_init(rtc_init);
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index eb643f8..ffaef2c 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -72,6 +72,7 @@
 	bool "KVM support for POWER7 and PPC970 using hypervisor mode in host"
 	depends on KVM_BOOK3S_64
 	select MMU_NOTIFIER
+	select CMA
 	---help---
 	  Support running unmodified book3s_64 guest kernels in
 	  virtual machines on POWER7 and PPC970 processors that have
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 008cd85..6646c95 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -81,6 +81,7 @@
 	book3s_64_vio_hv.o \
 	book3s_hv_ras.o \
 	book3s_hv_builtin.o \
+	book3s_hv_cma.o \
 	$(kvm-book3s_64-builtin-xics-objs-y)
 
 kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c
index 739bfba..7e345e0 100644
--- a/arch/powerpc/kvm/book3s_64_mmu.c
+++ b/arch/powerpc/kvm/book3s_64_mmu.c
@@ -182,10 +182,13 @@
 	hva_t ptegp;
 	u64 pteg[16];
 	u64 avpn = 0;
+	u64 v, r;
+	u64 v_val, v_mask;
+	u64 eaddr_mask;
 	int i;
-	u8 key = 0;
+	u8 pp, key = 0;
 	bool found = false;
-	int second = 0;
+	bool second = false;
 	ulong mp_ea = vcpu->arch.magic_page_ea;
 
 	/* Magic page override */
@@ -208,8 +211,16 @@
 		goto no_seg_found;
 
 	avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr);
+	v_val = avpn & HPTE_V_AVPN;
+
 	if (slbe->tb)
-		avpn |= SLB_VSID_B_1T;
+		v_val |= SLB_VSID_B_1T;
+	if (slbe->large)
+		v_val |= HPTE_V_LARGE;
+	v_val |= HPTE_V_VALID;
+
+	v_mask = SLB_VSID_B | HPTE_V_AVPN | HPTE_V_LARGE | HPTE_V_VALID |
+		HPTE_V_SECONDARY;
 
 do_second:
 	ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second);
@@ -227,90 +238,73 @@
 		key = 4;
 
 	for (i=0; i<16; i+=2) {
-		u64 v = pteg[i];
-		u64 r = pteg[i+1];
-
-		/* Valid check */
-		if (!(v & HPTE_V_VALID))
-			continue;
-		/* Hash check */
-		if ((v & HPTE_V_SECONDARY) != second)
-			continue;
-
-		/* AVPN compare */
-		if (HPTE_V_COMPARE(avpn, v)) {
-			u8 pp = (r & HPTE_R_PP) | key;
-			int eaddr_mask = 0xFFF;
-
-			gpte->eaddr = eaddr;
-			gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu,
-								    eaddr,
-								    data);
-			if (slbe->large)
-				eaddr_mask = 0xFFFFFF;
-			gpte->raddr = (r & HPTE_R_RPN) | (eaddr & eaddr_mask);
-			gpte->may_execute = ((r & HPTE_R_N) ? false : true);
-			gpte->may_read = false;
-			gpte->may_write = false;
-
-			switch (pp) {
-			case 0:
-			case 1:
-			case 2:
-			case 6:
-				gpte->may_write = true;
-				/* fall through */
-			case 3:
-			case 5:
-			case 7:
-				gpte->may_read = true;
-				break;
-			}
-
-			dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx "
-				"-> 0x%lx\n",
-				eaddr, avpn, gpte->vpage, gpte->raddr);
+		/* Check all relevant fields of 1st dword */
+		if ((pteg[i] & v_mask) == v_val) {
 			found = true;
 			break;
 		}
 	}
 
+	if (!found) {
+		if (second)
+			goto no_page_found;
+		v_val |= HPTE_V_SECONDARY;
+		second = true;
+		goto do_second;
+	}
+
+	v = pteg[i];
+	r = pteg[i+1];
+	pp = (r & HPTE_R_PP) | key;
+	eaddr_mask = 0xFFF;
+
+	gpte->eaddr = eaddr;
+	gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);
+	if (slbe->large)
+		eaddr_mask = 0xFFFFFF;
+	gpte->raddr = (r & HPTE_R_RPN & ~eaddr_mask) | (eaddr & eaddr_mask);
+	gpte->may_execute = ((r & HPTE_R_N) ? false : true);
+	gpte->may_read = false;
+	gpte->may_write = false;
+
+	switch (pp) {
+	case 0:
+	case 1:
+	case 2:
+	case 6:
+		gpte->may_write = true;
+		/* fall through */
+	case 3:
+	case 5:
+	case 7:
+		gpte->may_read = true;
+		break;
+	}
+
+	dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx "
+		"-> 0x%lx\n",
+		eaddr, avpn, gpte->vpage, gpte->raddr);
+
 	/* Update PTE R and C bits, so the guest's swapper knows we used the
 	 * page */
-	if (found) {
-		u32 oldr = pteg[i+1];
-
-		if (gpte->may_read) {
-			/* Set the accessed flag */
-			pteg[i+1] |= HPTE_R_R;
-		}
-		if (gpte->may_write) {
-			/* Set the dirty flag */
-			pteg[i+1] |= HPTE_R_C;
-		} else {
-			dprintk("KVM: Mapping read-only page!\n");
-		}
-
-		/* Write back into the PTEG */
-		if (pteg[i+1] != oldr)
-			copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
-
-		if (!gpte->may_read)
-			return -EPERM;
-		return 0;
-	} else {
-		dprintk("KVM MMU: No PTE found (ea=0x%lx sdr1=0x%llx "
-			"ptegp=0x%lx)\n",
-			eaddr, to_book3s(vcpu)->sdr1, ptegp);
-		for (i = 0; i < 16; i += 2)
-			dprintk("   %02d: 0x%llx - 0x%llx (0x%llx)\n",
-				i, pteg[i], pteg[i+1], avpn);
-
-		if (!second) {
-			second = HPTE_V_SECONDARY;
-			goto do_second;
-		}
+	if (gpte->may_read) {
+		/* Set the accessed flag */
+		r |= HPTE_R_R;
 	}
+	if (data && gpte->may_write) {
+		/* Set the dirty flag -- XXX even if not writing */
+		r |= HPTE_R_C;
+	}
+
+	/* Write back into the PTEG */
+	if (pteg[i+1] != r) {
+		pteg[i+1] = r;
+		copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
+	}
+
+	if (!gpte->may_read)
+		return -EPERM;
+	return 0;
 
 no_page_found:
 	return -ENOENT;
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 710d313..043eec8 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -37,6 +37,8 @@
 #include <asm/ppc-opcode.h>
 #include <asm/cputable.h>
 
+#include "book3s_hv_cma.h"
+
 /* POWER7 has 10-bit LPIDs, PPC970 has 6-bit LPIDs */
 #define MAX_LPID_970	63
 
@@ -52,8 +54,8 @@
 {
 	unsigned long hpt;
 	struct revmap_entry *rev;
-	struct kvmppc_linear_info *li;
-	long order = kvm_hpt_order;
+	struct page *page = NULL;
+	long order = KVM_DEFAULT_HPT_ORDER;
 
 	if (htab_orderp) {
 		order = *htab_orderp;
@@ -61,26 +63,23 @@
 			order = PPC_MIN_HPT_ORDER;
 	}
 
+	kvm->arch.hpt_cma_alloc = 0;
 	/*
-	 * If the user wants a different size from default,
 	 * try first to allocate it from the kernel page allocator.
+	 * We keep the CMA reserved for failed allocation.
 	 */
-	hpt = 0;
-	if (order != kvm_hpt_order) {
-		hpt = __get_free_pages(GFP_KERNEL|__GFP_ZERO|__GFP_REPEAT|
-				       __GFP_NOWARN, order - PAGE_SHIFT);
-		if (!hpt)
-			--order;
-	}
+	hpt = __get_free_pages(GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT |
+			       __GFP_NOWARN, order - PAGE_SHIFT);
 
 	/* Next try to allocate from the preallocated pool */
 	if (!hpt) {
-		li = kvm_alloc_hpt();
-		if (li) {
-			hpt = (ulong)li->base_virt;
-			kvm->arch.hpt_li = li;
-			order = kvm_hpt_order;
-		}
+		VM_BUG_ON(order < KVM_CMA_CHUNK_ORDER);
+		page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
+		if (page) {
+			hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
+			kvm->arch.hpt_cma_alloc = 1;
+		} else
+			--order;
 	}
 
 	/* Lastly try successively smaller sizes from the page allocator */
@@ -118,8 +117,8 @@
 	return 0;
 
  out_freehpt:
-	if (kvm->arch.hpt_li)
-		kvm_release_hpt(kvm->arch.hpt_li);
+	if (kvm->arch.hpt_cma_alloc)
+		kvm_release_hpt(page, 1 << (order - PAGE_SHIFT));
 	else
 		free_pages(hpt, order - PAGE_SHIFT);
 	return -ENOMEM;
@@ -165,8 +164,9 @@
 {
 	kvmppc_free_lpid(kvm->arch.lpid);
 	vfree(kvm->arch.revmap);
-	if (kvm->arch.hpt_li)
-		kvm_release_hpt(kvm->arch.hpt_li);
+	if (kvm->arch.hpt_cma_alloc)
+		kvm_release_hpt(virt_to_page(kvm->arch.hpt_virt),
+				1 << (kvm->arch.hpt_order - PAGE_SHIFT));
 	else
 		free_pages(kvm->arch.hpt_virt,
 			   kvm->arch.hpt_order - PAGE_SHIFT);
@@ -1579,7 +1579,7 @@
 	ctx->first_pass = 1;
 
 	rwflag = (ghf->flags & KVM_GET_HTAB_WRITE) ? O_WRONLY : O_RDONLY;
-	ret = anon_inode_getfd("kvm-htab", &kvm_htab_fops, ctx, rwflag);
+	ret = anon_inode_getfd("kvm-htab", &kvm_htab_fops, ctx, rwflag | O_CLOEXEC);
 	if (ret < 0) {
 		kvm_put_kvm(kvm);
 		return ret;
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
index b2d3f3b..54cf9bc 100644
--- a/arch/powerpc/kvm/book3s_64_vio.c
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -136,7 +136,7 @@
 	mutex_unlock(&kvm->lock);
 
 	return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
-				stt, O_RDWR);
+				stt, O_RDWR | O_CLOEXEC);
 
 fail:
 	if (stt) {
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c
index 1f6344c..360ce68 100644
--- a/arch/powerpc/kvm/book3s_emulate.c
+++ b/arch/powerpc/kvm/book3s_emulate.c
@@ -458,6 +458,7 @@
 	case SPRN_PMC4_GEKKO:
 	case SPRN_WPAR_GEKKO:
 	case SPRN_MSSSR0:
+	case SPRN_DABR:
 		break;
 unprivileged:
 	default:
@@ -555,6 +556,7 @@
 	case SPRN_PMC4_GEKKO:
 	case SPRN_WPAR_GEKKO:
 	case SPRN_MSSSR0:
+	case SPRN_DABR:
 		*spr_val = 0;
 		break;
 	default:
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 7629cd3..b0ee3bc 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -680,13 +680,12 @@
 }
 
 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
-                                  struct kvm_sregs *sregs)
+				  struct kvm_sregs *sregs)
 {
 	int i;
 
-	sregs->pvr = vcpu->arch.pvr;
-
 	memset(sregs, 0, sizeof(struct kvm_sregs));
+	sregs->pvr = vcpu->arch.pvr;
 	for (i = 0; i < vcpu->arch.slb_max; i++) {
 		sregs->u.s.ppc64.slb[i].slbe = vcpu->arch.slb[i].orige;
 		sregs->u.s.ppc64.slb[i].slbv = vcpu->arch.slb[i].origv;
@@ -696,7 +695,7 @@
 }
 
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
-                                  struct kvm_sregs *sregs)
+				  struct kvm_sregs *sregs)
 {
 	int i, j;
 
@@ -1511,10 +1510,10 @@
 
 static int kvm_rma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-	struct kvmppc_linear_info *ri = vma->vm_file->private_data;
 	struct page *page;
+	struct kvm_rma_info *ri = vma->vm_file->private_data;
 
-	if (vmf->pgoff >= ri->npages)
+	if (vmf->pgoff >= kvm_rma_pages)
 		return VM_FAULT_SIGBUS;
 
 	page = pfn_to_page(ri->base_pfn + vmf->pgoff);
@@ -1536,7 +1535,7 @@
 
 static int kvm_rma_release(struct inode *inode, struct file *filp)
 {
-	struct kvmppc_linear_info *ri = filp->private_data;
+	struct kvm_rma_info *ri = filp->private_data;
 
 	kvm_release_rma(ri);
 	return 0;
@@ -1549,18 +1548,27 @@
 
 long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret)
 {
-	struct kvmppc_linear_info *ri;
 	long fd;
+	struct kvm_rma_info *ri;
+	/*
+	 * Only do this on PPC970 in HV mode
+	 */
+	if (!cpu_has_feature(CPU_FTR_HVMODE) ||
+	    !cpu_has_feature(CPU_FTR_ARCH_201))
+		return -EINVAL;
+
+	if (!kvm_rma_pages)
+		return -EINVAL;
 
 	ri = kvm_alloc_rma();
 	if (!ri)
 		return -ENOMEM;
 
-	fd = anon_inode_getfd("kvm-rma", &kvm_rma_fops, ri, O_RDWR);
+	fd = anon_inode_getfd("kvm-rma", &kvm_rma_fops, ri, O_RDWR | O_CLOEXEC);
 	if (fd < 0)
 		kvm_release_rma(ri);
 
-	ret->rma_size = ri->npages << PAGE_SHIFT;
+	ret->rma_size = kvm_rma_pages << PAGE_SHIFT;
 	return fd;
 }
 
@@ -1725,7 +1733,7 @@
 {
 	int err = 0;
 	struct kvm *kvm = vcpu->kvm;
-	struct kvmppc_linear_info *ri = NULL;
+	struct kvm_rma_info *ri = NULL;
 	unsigned long hva;
 	struct kvm_memory_slot *memslot;
 	struct vm_area_struct *vma;
@@ -1803,7 +1811,7 @@
 
 	} else {
 		/* Set up to use an RMO region */
-		rma_size = ri->npages;
+		rma_size = kvm_rma_pages;
 		if (rma_size > memslot->npages)
 			rma_size = memslot->npages;
 		rma_size <<= PAGE_SHIFT;
@@ -1831,14 +1839,14 @@
 			/* POWER7 */
 			lpcr &= ~(LPCR_VPM0 | LPCR_VRMA_L);
 			lpcr |= rmls << LPCR_RMLS_SH;
-			kvm->arch.rmor = kvm->arch.rma->base_pfn << PAGE_SHIFT;
+			kvm->arch.rmor = ri->base_pfn << PAGE_SHIFT;
 		}
 		kvm->arch.lpcr = lpcr;
 		pr_info("KVM: Using RMO at %lx size %lx (LPCR = %lx)\n",
 			ri->base_pfn << PAGE_SHIFT, rma_size, lpcr);
 
 		/* Initialize phys addrs of pages in RMO */
-		npages = ri->npages;
+		npages = kvm_rma_pages;
 		porder = __ilog2(npages);
 		physp = memslot->arch.slot_phys;
 		if (physp) {
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index ec0a9e5..8cd0dae 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -13,33 +13,34 @@
 #include <linux/spinlock.h>
 #include <linux/bootmem.h>
 #include <linux/init.h>
+#include <linux/memblock.h>
+#include <linux/sizes.h>
 
 #include <asm/cputable.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
 
-#define KVM_LINEAR_RMA		0
-#define KVM_LINEAR_HPT		1
-
-static void __init kvm_linear_init_one(ulong size, int count, int type);
-static struct kvmppc_linear_info *kvm_alloc_linear(int type);
-static void kvm_release_linear(struct kvmppc_linear_info *ri);
-
-int kvm_hpt_order = KVM_DEFAULT_HPT_ORDER;
-EXPORT_SYMBOL_GPL(kvm_hpt_order);
-
-/*************** RMA *************/
-
+#include "book3s_hv_cma.h"
 /*
- * This maintains a list of RMAs (real mode areas) for KVM guests to use.
+ * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206)
+ * should be power of 2.
+ */
+#define HPT_ALIGN_PAGES		((1 << 18) >> PAGE_SHIFT) /* 256k */
+/*
+ * By default we reserve 5% of memory for hash pagetable allocation.
+ */
+static unsigned long kvm_cma_resv_ratio = 5;
+/*
+ * We allocate RMAs (real mode areas) for KVM guests from the KVM CMA area.
  * Each RMA has to be physically contiguous and of a size that the
  * hardware supports.  PPC970 and POWER7 support 64MB, 128MB and 256MB,
  * and other larger sizes.  Since we are unlikely to be allocate that
  * much physically contiguous memory after the system is up and running,
- * we preallocate a set of RMAs in early boot for KVM to use.
+ * we preallocate a set of RMAs in early boot using CMA.
+ * should be power of 2.
  */
-static unsigned long kvm_rma_size = 64 << 20;	/* 64MB */
-static unsigned long kvm_rma_count;
+unsigned long kvm_rma_pages = (1 << 27) >> PAGE_SHIFT;	/* 128MB */
+EXPORT_SYMBOL_GPL(kvm_rma_pages);
 
 /* Work out RMLS (real mode limit selector) field value for a given RMA size.
    Assumes POWER7 or PPC970. */
@@ -69,165 +70,114 @@
 
 static int __init early_parse_rma_size(char *p)
 {
+	unsigned long kvm_rma_size;
+
+	pr_debug("%s(%s)\n", __func__, p);
 	if (!p)
-		return 1;
-
+		return -EINVAL;
 	kvm_rma_size = memparse(p, &p);
-
+	/*
+	 * Check that the requested size is one supported in hardware
+	 */
+	if (lpcr_rmls(kvm_rma_size) < 0) {
+		pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size);
+		return -EINVAL;
+	}
+	kvm_rma_pages = kvm_rma_size >> PAGE_SHIFT;
 	return 0;
 }
 early_param("kvm_rma_size", early_parse_rma_size);
 
-static int __init early_parse_rma_count(char *p)
+struct kvm_rma_info *kvm_alloc_rma()
 {
-	if (!p)
-		return 1;
+	struct page *page;
+	struct kvm_rma_info *ri;
 
-	kvm_rma_count = simple_strtoul(p, NULL, 0);
-
-	return 0;
-}
-early_param("kvm_rma_count", early_parse_rma_count);
-
-struct kvmppc_linear_info *kvm_alloc_rma(void)
-{
-	return kvm_alloc_linear(KVM_LINEAR_RMA);
+	ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL);
+	if (!ri)
+		return NULL;
+	page = kvm_alloc_cma(kvm_rma_pages, kvm_rma_pages);
+	if (!page)
+		goto err_out;
+	atomic_set(&ri->use_count, 1);
+	ri->base_pfn = page_to_pfn(page);
+	return ri;
+err_out:
+	kfree(ri);
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(kvm_alloc_rma);
 
-void kvm_release_rma(struct kvmppc_linear_info *ri)
+void kvm_release_rma(struct kvm_rma_info *ri)
 {
-	kvm_release_linear(ri);
+	if (atomic_dec_and_test(&ri->use_count)) {
+		kvm_release_cma(pfn_to_page(ri->base_pfn), kvm_rma_pages);
+		kfree(ri);
+	}
 }
 EXPORT_SYMBOL_GPL(kvm_release_rma);
 
-/*************** HPT *************/
-
-/*
- * This maintains a list of big linear HPT tables that contain the GVA->HPA
- * memory mappings. If we don't reserve those early on, we might not be able
- * to get a big (usually 16MB) linear memory region from the kernel anymore.
- */
-
-static unsigned long kvm_hpt_count;
-
-static int __init early_parse_hpt_count(char *p)
+static int __init early_parse_kvm_cma_resv(char *p)
 {
+	pr_debug("%s(%s)\n", __func__, p);
 	if (!p)
-		return 1;
-
-	kvm_hpt_count = simple_strtoul(p, NULL, 0);
-
-	return 0;
+		return -EINVAL;
+	return kstrtoul(p, 0, &kvm_cma_resv_ratio);
 }
-early_param("kvm_hpt_count", early_parse_hpt_count);
+early_param("kvm_cma_resv_ratio", early_parse_kvm_cma_resv);
 
-struct kvmppc_linear_info *kvm_alloc_hpt(void)
+struct page *kvm_alloc_hpt(unsigned long nr_pages)
 {
-	return kvm_alloc_linear(KVM_LINEAR_HPT);
+	unsigned long align_pages = HPT_ALIGN_PAGES;
+
+	/* Old CPUs require HPT aligned on a multiple of its size */
+	if (!cpu_has_feature(CPU_FTR_ARCH_206))
+		align_pages = nr_pages;
+	return kvm_alloc_cma(nr_pages, align_pages);
 }
 EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
 
-void kvm_release_hpt(struct kvmppc_linear_info *li)
+void kvm_release_hpt(struct page *page, unsigned long nr_pages)
 {
-	kvm_release_linear(li);
+	kvm_release_cma(page, nr_pages);
 }
 EXPORT_SYMBOL_GPL(kvm_release_hpt);
 
-/*************** generic *************/
-
-static LIST_HEAD(free_linears);
-static DEFINE_SPINLOCK(linear_lock);
-
-static void __init kvm_linear_init_one(ulong size, int count, int type)
-{
-	unsigned long i;
-	unsigned long j, npages;
-	void *linear;
-	struct page *pg;
-	const char *typestr;
-	struct kvmppc_linear_info *linear_info;
-
-	if (!count)
-		return;
-
-	typestr = (type == KVM_LINEAR_RMA) ? "RMA" : "HPT";
-
-	npages = size >> PAGE_SHIFT;
-	linear_info = alloc_bootmem(count * sizeof(struct kvmppc_linear_info));
-	for (i = 0; i < count; ++i) {
-		linear = alloc_bootmem_align(size, size);
-		pr_debug("Allocated KVM %s at %p (%ld MB)\n", typestr, linear,
-			 size >> 20);
-		linear_info[i].base_virt = linear;
-		linear_info[i].base_pfn = __pa(linear) >> PAGE_SHIFT;
-		linear_info[i].npages = npages;
-		linear_info[i].type = type;
-		list_add_tail(&linear_info[i].list, &free_linears);
-		atomic_set(&linear_info[i].use_count, 0);
-
-		pg = pfn_to_page(linear_info[i].base_pfn);
-		for (j = 0; j < npages; ++j) {
-			atomic_inc(&pg->_count);
-			++pg;
-		}
-	}
-}
-
-static struct kvmppc_linear_info *kvm_alloc_linear(int type)
-{
-	struct kvmppc_linear_info *ri, *ret;
-
-	ret = NULL;
-	spin_lock(&linear_lock);
-	list_for_each_entry(ri, &free_linears, list) {
-		if (ri->type != type)
-			continue;
-
-		list_del(&ri->list);
-		atomic_inc(&ri->use_count);
-		memset(ri->base_virt, 0, ri->npages << PAGE_SHIFT);
-		ret = ri;
-		break;
-	}
-	spin_unlock(&linear_lock);
-	return ret;
-}
-
-static void kvm_release_linear(struct kvmppc_linear_info *ri)
-{
-	if (atomic_dec_and_test(&ri->use_count)) {
-		spin_lock(&linear_lock);
-		list_add_tail(&ri->list, &free_linears);
-		spin_unlock(&linear_lock);
-
-	}
-}
-
-/*
- * Called at boot time while the bootmem allocator is active,
- * to allocate contiguous physical memory for the hash page
- * tables for guests.
+/**
+ * kvm_cma_reserve() - reserve area for kvm hash pagetable
+ *
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory.
  */
-void __init kvm_linear_init(void)
+void __init kvm_cma_reserve(void)
 {
-	/* HPT */
-	kvm_linear_init_one(1 << kvm_hpt_order, kvm_hpt_count, KVM_LINEAR_HPT);
+	unsigned long align_size;
+	struct memblock_region *reg;
+	phys_addr_t selected_size = 0;
+	/*
+	 * We cannot use memblock_phys_mem_size() here, because
+	 * memblock_analyze() has not been called yet.
+	 */
+	for_each_memblock(memory, reg)
+		selected_size += memblock_region_memory_end_pfn(reg) -
+				 memblock_region_memory_base_pfn(reg);
 
-	/* RMA */
-	/* Only do this on PPC970 in HV mode */
-	if (!cpu_has_feature(CPU_FTR_HVMODE) ||
-	    !cpu_has_feature(CPU_FTR_ARCH_201))
-		return;
+	selected_size = (selected_size * kvm_cma_resv_ratio / 100) << PAGE_SHIFT;
+	if (selected_size) {
+		pr_debug("%s: reserving %ld MiB for global area\n", __func__,
+			 (unsigned long)selected_size / SZ_1M);
+		/*
+		 * Old CPUs require HPT aligned on a multiple of its size. So for them
+		 * make the alignment as max size we could request.
+		 */
+		if (!cpu_has_feature(CPU_FTR_ARCH_206))
+			align_size = __rounddown_pow_of_two(selected_size);
+		else
+			align_size = HPT_ALIGN_PAGES << PAGE_SHIFT;
 
-	if (!kvm_rma_size || !kvm_rma_count)
-		return;
-
-	/* Check that the requested size is one supported in hardware */
-	if (lpcr_rmls(kvm_rma_size) < 0) {
-		pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size);
-		return;
+		align_size = max(kvm_rma_pages << PAGE_SHIFT, align_size);
+		kvm_cma_declare_contiguous(selected_size, align_size);
 	}
-
-	kvm_linear_init_one(kvm_rma_size, kvm_rma_count, KVM_LINEAR_RMA);
 }
diff --git a/arch/powerpc/kvm/book3s_hv_cma.c b/arch/powerpc/kvm/book3s_hv_cma.c
new file mode 100644
index 0000000..d9d3d85
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_cma.c
@@ -0,0 +1,240 @@
+/*
+ * Contiguous Memory Allocator for ppc KVM hash pagetable  based on CMA
+ * for DMA mapping framework
+ *
+ * Copyright IBM Corporation, 2013
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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 optional) any later version of the license.
+ *
+ */
+#define pr_fmt(fmt) "kvm_cma: " fmt
+
+#ifdef CONFIG_CMA_DEBUG
+#ifndef DEBUG
+#  define DEBUG
+#endif
+#endif
+
+#include <linux/memblock.h>
+#include <linux/mutex.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+#include "book3s_hv_cma.h"
+
+struct kvm_cma {
+	unsigned long	base_pfn;
+	unsigned long	count;
+	unsigned long	*bitmap;
+};
+
+static DEFINE_MUTEX(kvm_cma_mutex);
+static struct kvm_cma kvm_cma_area;
+
+/**
+ * kvm_cma_declare_contiguous() - reserve area for contiguous memory handling
+ *			          for kvm hash pagetable
+ * @size:  Size of the reserved memory.
+ * @alignment:  Alignment for the contiguous memory area
+ *
+ * This function reserves memory for kvm cma area. It should be
+ * called by arch code when early allocator (memblock or bootmem)
+ * is still activate.
+ */
+long __init kvm_cma_declare_contiguous(phys_addr_t size, phys_addr_t alignment)
+{
+	long base_pfn;
+	phys_addr_t addr;
+	struct kvm_cma *cma = &kvm_cma_area;
+
+	pr_debug("%s(size %lx)\n", __func__, (unsigned long)size);
+
+	if (!size)
+		return -EINVAL;
+	/*
+	 * Sanitise input arguments.
+	 * We should be pageblock aligned for CMA.
+	 */
+	alignment = max(alignment, (phys_addr_t)(PAGE_SIZE << pageblock_order));
+	size = ALIGN(size, alignment);
+	/*
+	 * Reserve memory
+	 * Use __memblock_alloc_base() since
+	 * memblock_alloc_base() panic()s.
+	 */
+	addr = __memblock_alloc_base(size, alignment, 0);
+	if (!addr) {
+		base_pfn = -ENOMEM;
+		goto err;
+	} else
+		base_pfn = PFN_DOWN(addr);
+
+	/*
+	 * Each reserved area must be initialised later, when more kernel
+	 * subsystems (like slab allocator) are available.
+	 */
+	cma->base_pfn = base_pfn;
+	cma->count    = size >> PAGE_SHIFT;
+	pr_info("CMA: reserved %ld MiB\n", (unsigned long)size / SZ_1M);
+	return 0;
+err:
+	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
+	return base_pfn;
+}
+
+/**
+ * kvm_alloc_cma() - allocate pages from contiguous area
+ * @nr_pages: Requested number of pages.
+ * @align_pages: Requested alignment in number of pages
+ *
+ * This function allocates memory buffer for hash pagetable.
+ */
+struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages)
+{
+	int ret;
+	struct page *page = NULL;
+	struct kvm_cma *cma = &kvm_cma_area;
+	unsigned long chunk_count, nr_chunk;
+	unsigned long mask, pfn, pageno, start = 0;
+
+
+	if (!cma || !cma->count)
+		return NULL;
+
+	pr_debug("%s(cma %p, count %lu, align pages %lu)\n", __func__,
+		 (void *)cma, nr_pages, align_pages);
+
+	if (!nr_pages)
+		return NULL;
+	/*
+	 * align mask with chunk size. The bit tracks pages in chunk size
+	 */
+	VM_BUG_ON(!is_power_of_2(align_pages));
+	mask = (align_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT)) - 1;
+	BUILD_BUG_ON(PAGE_SHIFT > KVM_CMA_CHUNK_ORDER);
+
+	chunk_count = cma->count >>  (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
+	nr_chunk = nr_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
+
+	mutex_lock(&kvm_cma_mutex);
+	for (;;) {
+		pageno = bitmap_find_next_zero_area(cma->bitmap, chunk_count,
+						    start, nr_chunk, mask);
+		if (pageno >= chunk_count)
+			break;
+
+		pfn = cma->base_pfn + (pageno << (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT));
+		ret = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_CMA);
+		if (ret == 0) {
+			bitmap_set(cma->bitmap, pageno, nr_chunk);
+			page = pfn_to_page(pfn);
+			memset(pfn_to_kaddr(pfn), 0, nr_pages << PAGE_SHIFT);
+			break;
+		} else if (ret != -EBUSY) {
+			break;
+		}
+		pr_debug("%s(): memory range at %p is busy, retrying\n",
+			 __func__, pfn_to_page(pfn));
+		/* try again with a bit different memory target */
+		start = pageno + mask + 1;
+	}
+	mutex_unlock(&kvm_cma_mutex);
+	pr_debug("%s(): returned %p\n", __func__, page);
+	return page;
+}
+
+/**
+ * kvm_release_cma() - release allocated pages for hash pagetable
+ * @pages: Allocated pages.
+ * @nr_pages: Number of allocated pages.
+ *
+ * This function releases memory allocated by kvm_alloc_cma().
+ * It returns false when provided pages do not belong to contiguous area and
+ * true otherwise.
+ */
+bool kvm_release_cma(struct page *pages, unsigned long nr_pages)
+{
+	unsigned long pfn;
+	unsigned long nr_chunk;
+	struct kvm_cma *cma = &kvm_cma_area;
+
+	if (!cma || !pages)
+		return false;
+
+	pr_debug("%s(page %p count %lu)\n", __func__, (void *)pages, nr_pages);
+
+	pfn = page_to_pfn(pages);
+
+	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
+		return false;
+
+	VM_BUG_ON(pfn + nr_pages > cma->base_pfn + cma->count);
+	nr_chunk = nr_pages >>  (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
+
+	mutex_lock(&kvm_cma_mutex);
+	bitmap_clear(cma->bitmap,
+		     (pfn - cma->base_pfn) >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT),
+		     nr_chunk);
+	free_contig_range(pfn, nr_pages);
+	mutex_unlock(&kvm_cma_mutex);
+
+	return true;
+}
+
+static int __init kvm_cma_activate_area(unsigned long base_pfn,
+					unsigned long count)
+{
+	unsigned long pfn = base_pfn;
+	unsigned i = count >> pageblock_order;
+	struct zone *zone;
+
+	WARN_ON_ONCE(!pfn_valid(pfn));
+	zone = page_zone(pfn_to_page(pfn));
+	do {
+		unsigned j;
+		base_pfn = pfn;
+		for (j = pageblock_nr_pages; j; --j, pfn++) {
+			WARN_ON_ONCE(!pfn_valid(pfn));
+			/*
+			 * alloc_contig_range requires the pfn range
+			 * specified to be in the same zone. Make this
+			 * simple by forcing the entire CMA resv range
+			 * to be in the same zone.
+			 */
+			if (page_zone(pfn_to_page(pfn)) != zone)
+				return -EINVAL;
+		}
+		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
+	} while (--i);
+	return 0;
+}
+
+static int __init kvm_cma_init_reserved_areas(void)
+{
+	int bitmap_size, ret;
+	unsigned long chunk_count;
+	struct kvm_cma *cma = &kvm_cma_area;
+
+	pr_debug("%s()\n", __func__);
+	if (!cma->count)
+		return 0;
+	chunk_count = cma->count >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
+	bitmap_size = BITS_TO_LONGS(chunk_count) * sizeof(long);
+	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!cma->bitmap)
+		return -ENOMEM;
+
+	ret = kvm_cma_activate_area(cma->base_pfn, cma->count);
+	if (ret)
+		goto error;
+	return 0;
+
+error:
+	kfree(cma->bitmap);
+	return ret;
+}
+core_initcall(kvm_cma_init_reserved_areas);
diff --git a/arch/powerpc/kvm/book3s_hv_cma.h b/arch/powerpc/kvm/book3s_hv_cma.h
new file mode 100644
index 0000000..655144f
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_hv_cma.h
@@ -0,0 +1,27 @@
+/*
+ * Contiguous Memory Allocator for ppc KVM hash pagetable  based on CMA
+ * for DMA mapping framework
+ *
+ * Copyright IBM Corporation, 2013
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.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 optional) any later version of the license.
+ *
+ */
+
+#ifndef __POWERPC_KVM_CMA_ALLOC_H__
+#define __POWERPC_KVM_CMA_ALLOC_H__
+/*
+ * Both RMA and Hash page allocation will be multiple of 256K.
+ */
+#define KVM_CMA_CHUNK_ORDER	18
+
+extern struct page *kvm_alloc_cma(unsigned long nr_pages,
+				  unsigned long align_pages);
+extern bool kvm_release_cma(struct page *pages, unsigned long nr_pages);
+extern long kvm_cma_declare_contiguous(phys_addr_t size,
+				       phys_addr_t alignment) __init;
+#endif
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index fc25689..45e30d6 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -383,6 +383,80 @@
 	return old == 0;
 }
 
+/*
+ * tlbie/tlbiel is a bit different on the PPC970 compared to later
+ * processors such as POWER7; the large page bit is in the instruction
+ * not RB, and the top 16 bits and the bottom 12 bits of the VA
+ * in RB must be 0.
+ */
+static void do_tlbies_970(struct kvm *kvm, unsigned long *rbvalues,
+			  long npages, int global, bool need_sync)
+{
+	long i;
+
+	if (global) {
+		while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
+			cpu_relax();
+		if (need_sync)
+			asm volatile("ptesync" : : : "memory");
+		for (i = 0; i < npages; ++i) {
+			unsigned long rb = rbvalues[i];
+
+			if (rb & 1)		/* large page */
+				asm volatile("tlbie %0,1" : :
+					     "r" (rb & 0x0000fffffffff000ul));
+			else
+				asm volatile("tlbie %0,0" : :
+					     "r" (rb & 0x0000fffffffff000ul));
+		}
+		asm volatile("eieio; tlbsync; ptesync" : : : "memory");
+		kvm->arch.tlbie_lock = 0;
+	} else {
+		if (need_sync)
+			asm volatile("ptesync" : : : "memory");
+		for (i = 0; i < npages; ++i) {
+			unsigned long rb = rbvalues[i];
+
+			if (rb & 1)		/* large page */
+				asm volatile("tlbiel %0,1" : :
+					     "r" (rb & 0x0000fffffffff000ul));
+			else
+				asm volatile("tlbiel %0,0" : :
+					     "r" (rb & 0x0000fffffffff000ul));
+		}
+		asm volatile("ptesync" : : : "memory");
+	}
+}
+
+static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
+		      long npages, int global, bool need_sync)
+{
+	long i;
+
+	if (cpu_has_feature(CPU_FTR_ARCH_201)) {
+		/* PPC970 tlbie instruction is a bit different */
+		do_tlbies_970(kvm, rbvalues, npages, global, need_sync);
+		return;
+	}
+	if (global) {
+		while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
+			cpu_relax();
+		if (need_sync)
+			asm volatile("ptesync" : : : "memory");
+		for (i = 0; i < npages; ++i)
+			asm volatile(PPC_TLBIE(%1,%0) : :
+				     "r" (rbvalues[i]), "r" (kvm->arch.lpid));
+		asm volatile("eieio; tlbsync; ptesync" : : : "memory");
+		kvm->arch.tlbie_lock = 0;
+	} else {
+		if (need_sync)
+			asm volatile("ptesync" : : : "memory");
+		for (i = 0; i < npages; ++i)
+			asm volatile("tlbiel %0" : : "r" (rbvalues[i]));
+		asm volatile("ptesync" : : : "memory");
+	}
+}
+
 long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
 			unsigned long pte_index, unsigned long avpn,
 			unsigned long *hpret)
@@ -408,19 +482,7 @@
 	if (v & HPTE_V_VALID) {
 		hpte[0] &= ~HPTE_V_VALID;
 		rb = compute_tlbie_rb(v, hpte[1], pte_index);
-		if (global_invalidates(kvm, flags)) {
-			while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
-				cpu_relax();
-			asm volatile("ptesync" : : : "memory");
-			asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
-				     : : "r" (rb), "r" (kvm->arch.lpid));
-			asm volatile("ptesync" : : : "memory");
-			kvm->arch.tlbie_lock = 0;
-		} else {
-			asm volatile("ptesync" : : : "memory");
-			asm volatile("tlbiel %0" : : "r" (rb));
-			asm volatile("ptesync" : : : "memory");
-		}
+		do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
 		/* Read PTE low word after tlbie to get final R/C values */
 		remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]);
 	}
@@ -448,12 +510,11 @@
 	unsigned long *hp, *hptes[4], tlbrb[4];
 	long int i, j, k, n, found, indexes[4];
 	unsigned long flags, req, pte_index, rcbits;
-	long int local = 0;
+	int global;
 	long int ret = H_SUCCESS;
 	struct revmap_entry *rev, *revs[4];
 
-	if (atomic_read(&kvm->online_vcpus) == 1)
-		local = 1;
+	global = global_invalidates(kvm, 0);
 	for (i = 0; i < 4 && ret == H_SUCCESS; ) {
 		n = 0;
 		for (; i < 4; ++i) {
@@ -529,22 +590,7 @@
 			break;
 
 		/* Now that we've collected a batch, do the tlbies */
-		if (!local) {
-			while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
-				cpu_relax();
-			asm volatile("ptesync" : : : "memory");
-			for (k = 0; k < n; ++k)
-				asm volatile(PPC_TLBIE(%1,%0) : :
-					     "r" (tlbrb[k]),
-					     "r" (kvm->arch.lpid));
-			asm volatile("eieio; tlbsync; ptesync" : : : "memory");
-			kvm->arch.tlbie_lock = 0;
-		} else {
-			asm volatile("ptesync" : : : "memory");
-			for (k = 0; k < n; ++k)
-				asm volatile("tlbiel %0" : : "r" (tlbrb[k]));
-			asm volatile("ptesync" : : : "memory");
-		}
+		do_tlbies(kvm, tlbrb, n, global, true);
 
 		/* Read PTE low words after tlbie to get final R/C values */
 		for (k = 0; k < n; ++k) {
@@ -603,19 +649,7 @@
 	if (v & HPTE_V_VALID) {
 		rb = compute_tlbie_rb(v, r, pte_index);
 		hpte[0] = v & ~HPTE_V_VALID;
-		if (global_invalidates(kvm, flags)) {
-			while(!try_lock_tlbie(&kvm->arch.tlbie_lock))
-				cpu_relax();
-			asm volatile("ptesync" : : : "memory");
-			asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
-				     : : "r" (rb), "r" (kvm->arch.lpid));
-			asm volatile("ptesync" : : : "memory");
-			kvm->arch.tlbie_lock = 0;
-		} else {
-			asm volatile("ptesync" : : : "memory");
-			asm volatile("tlbiel %0" : : "r" (rb));
-			asm volatile("ptesync" : : : "memory");
-		}
+		do_tlbies(kvm, &rb, 1, global_invalidates(kvm, flags), true);
 		/*
 		 * If the host has this page as readonly but the guest
 		 * wants to make it read/write, reduce the permissions.
@@ -686,13 +720,7 @@
 
 	hptep[0] &= ~HPTE_V_VALID;
 	rb = compute_tlbie_rb(hptep[0], hptep[1], pte_index);
-	while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
-		cpu_relax();
-	asm volatile("ptesync" : : : "memory");
-	asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
-		     : : "r" (rb), "r" (kvm->arch.lpid));
-	asm volatile("ptesync" : : : "memory");
-	kvm->arch.tlbie_lock = 0;
+	do_tlbies(kvm, &rb, 1, 1, true);
 }
 EXPORT_SYMBOL_GPL(kvmppc_invalidate_hpte);
 
@@ -706,12 +734,7 @@
 	rbyte = (hptep[1] & ~HPTE_R_R) >> 8;
 	/* modify only the second-last byte, which contains the ref bit */
 	*((char *)hptep + 14) = rbyte;
-	while (!try_lock_tlbie(&kvm->arch.tlbie_lock))
-		cpu_relax();
-	asm volatile(PPC_TLBIE(%1,%0)"; eieio; tlbsync"
-		     : : "r" (rb), "r" (kvm->arch.lpid));
-	asm volatile("ptesync" : : : "memory");
-	kvm->arch.tlbie_lock = 0;
+	do_tlbies(kvm, &rb, 1, 1, false);
 }
 EXPORT_SYMBOL_GPL(kvmppc_clear_ref_hpte);
 
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index b02f91e..60dce5b 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1381,7 +1381,7 @@
 	cmpldi	r3,hcall_real_table_end - hcall_real_table
 	bge	guest_exit_cont
 	LOAD_REG_ADDR(r4, hcall_real_table)
-	lwzx	r3,r3,r4
+	lwax	r3,r3,r4
 	cmpwi	r3,0
 	beq	guest_exit_cont
 	add	r3,r3,r4
diff --git a/arch/powerpc/kvm/book3s_interrupts.S b/arch/powerpc/kvm/book3s_interrupts.S
index 48cbbf8..17cfae5 100644
--- a/arch/powerpc/kvm/book3s_interrupts.S
+++ b/arch/powerpc/kvm/book3s_interrupts.S
@@ -92,6 +92,11 @@
 	PPC_LL	r3, VCPU_HFLAGS(r4)
 	rldicl	r3, r3, 0, 63		/* r3 &= 1 */
 	stb	r3, HSTATE_RESTORE_HID5(r13)
+
+	/* Load up guest SPRG3 value, since it's user readable */
+	ld	r3, VCPU_SHARED(r4)
+	ld	r3, VCPU_SHARED_SPRG3(r3)
+	mtspr	SPRN_SPRG3, r3
 #endif /* CONFIG_PPC_BOOK3S_64 */
 
 	PPC_LL	r4, VCPU_SHADOW_MSR(r4)	/* get shadow_msr */
@@ -123,6 +128,15 @@
 	/* R7 = vcpu */
 	PPC_LL	r7, GPR4(r1)
 
+#ifdef CONFIG_PPC_BOOK3S_64
+	/*
+	 * Reload kernel SPRG3 value.
+	 * No need to save guest value as usermode can't modify SPRG3.
+	 */
+	ld	r3, PACA_SPRG3(r13)
+	mtspr	SPRN_SPRG3, r3
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
 	PPC_STL	r14, VCPU_GPR(R14)(r7)
 	PPC_STL	r15, VCPU_GPR(R15)(r7)
 	PPC_STL	r16, VCPU_GPR(R16)(r7)
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index c6e13d9..27db1e6 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -468,7 +468,8 @@
 		 * both the traditional FP registers and the added VSX
 		 * registers into thread.fpr[].
 		 */
-		giveup_fpu(current);
+		if (current->thread.regs->msr & MSR_FP)
+			giveup_fpu(current);
 		for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
 			vcpu_fpr[i] = thread_fpr[get_fpr_index(i)];
 
@@ -483,7 +484,8 @@
 
 #ifdef CONFIG_ALTIVEC
 	if (msr & MSR_VEC) {
-		giveup_altivec(current);
+		if (current->thread.regs->msr & MSR_VEC)
+			giveup_altivec(current);
 		memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr));
 		vcpu->arch.vscr = t->vscr;
 	}
@@ -575,8 +577,6 @@
 	printk(KERN_INFO "Loading up ext 0x%lx\n", msr);
 #endif
 
-	current->thread.regs->msr |= msr;
-
 	if (msr & MSR_FP) {
 		for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
 			thread_fpr[get_fpr_index(i)] = vcpu_fpr[i];
@@ -598,12 +598,32 @@
 #endif
 	}
 
+	current->thread.regs->msr |= msr;
 	vcpu->arch.guest_owned_ext |= msr;
 	kvmppc_recalc_shadow_msr(vcpu);
 
 	return RESUME_GUEST;
 }
 
+/*
+ * Kernel code using FP or VMX could have flushed guest state to
+ * the thread_struct; if so, get it back now.
+ */
+static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
+{
+	unsigned long lost_ext;
+
+	lost_ext = vcpu->arch.guest_owned_ext & ~current->thread.regs->msr;
+	if (!lost_ext)
+		return;
+
+	if (lost_ext & MSR_FP)
+		kvmppc_load_up_fpu();
+	if (lost_ext & MSR_VEC)
+		kvmppc_load_up_altivec();
+	current->thread.regs->msr |= lost_ext;
+}
+
 int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned int exit_nr)
 {
@@ -772,7 +792,7 @@
 	}
 	case BOOK3S_INTERRUPT_SYSCALL:
 		if (vcpu->arch.papr_enabled &&
-		    (kvmppc_get_last_inst(vcpu) == 0x44000022) &&
+		    (kvmppc_get_last_sc(vcpu) == 0x44000022) &&
 		    !(vcpu->arch.shared->msr & MSR_PR)) {
 			/* SC 1 papr hypercalls */
 			ulong cmd = kvmppc_get_gpr(vcpu, 3);
@@ -890,8 +910,9 @@
 			local_irq_enable();
 			r = s;
 		} else {
-			kvmppc_lazy_ee_enable();
+			kvmppc_fix_ee_before_entry();
 		}
+		kvmppc_handle_lost_ext(vcpu);
 	}
 
 	trace_kvm_book3s_reenter(r, vcpu);
@@ -1162,7 +1183,7 @@
 	if (vcpu->arch.shared->msr & MSR_FP)
 		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
 
-	kvmppc_lazy_ee_enable();
+	kvmppc_fix_ee_before_entry();
 
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index 94c1dd4..a3a5cb8 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -19,6 +19,7 @@
 #include <asm/hvcall.h>
 #include <asm/xics.h>
 #include <asm/debug.h>
+#include <asm/time.h>
 
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index dcc94f0..17722d8 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -674,8 +674,6 @@
 		goto out;
 	}
 
-	kvm_guest_enter();
-
 #ifdef CONFIG_PPC_FPU
 	/* Save userspace FPU state in stack */
 	enable_kernel_fp();
@@ -698,7 +696,7 @@
 	kvmppc_load_guest_fp(vcpu);
 #endif
 
-	kvmppc_lazy_ee_enable();
+	kvmppc_fix_ee_before_entry();
 
 	ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
@@ -1168,7 +1166,7 @@
 			local_irq_enable();
 			r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
 		} else {
-			kvmppc_lazy_ee_enable();
+			kvmppc_fix_ee_before_entry();
 		}
 	}
 
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index aca2e8f..07c0106 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -117,8 +117,6 @@
 			kvm_guest_exit();
 			continue;
 		}
-
-		trace_hardirqs_on();
 #endif
 
 		kvm_guest_enter();
@@ -420,6 +418,10 @@
 	return kvmppc_core_create_memslot(slot, npages);
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				   struct kvm_memory_slot *memslot,
 				   struct kvm_userspace_memory_region *mem,
diff --git a/arch/powerpc/perf/power7-events-list.h b/arch/powerpc/perf/power7-events-list.h
new file mode 100644
index 0000000..687790a
--- /dev/null
+++ b/arch/powerpc/perf/power7-events-list.h
@@ -0,0 +1,548 @@
+/*
+ * Performance counter support for POWER7 processors.
+ *
+ * Copyright 2013 Runzhen Wang, IBM Corporation.
+ *
+ * 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.
+ */
+
+EVENT(PM_IC_DEMAND_L2_BR_ALL,                 0x04898)
+EVENT(PM_GCT_UTIL_7_TO_10_SLOTS,              0x020a0)
+EVENT(PM_PMC2_SAVED,                          0x10022)
+EVENT(PM_CMPLU_STALL_DFU,                     0x2003c)
+EVENT(PM_VSU0_16FLOP,                         0x0a0a4)
+EVENT(PM_MRK_LSU_DERAT_MISS,                  0x3d05a)
+EVENT(PM_MRK_ST_CMPL,                         0x10034)
+EVENT(PM_NEST_PAIR3_ADD,                      0x40881)
+EVENT(PM_L2_ST_DISP,                          0x46180)
+EVENT(PM_L2_CASTOUT_MOD,                      0x16180)
+EVENT(PM_ISEG,                                0x020a4)
+EVENT(PM_MRK_INST_TIMEO,                      0x40034)
+EVENT(PM_L2_RCST_DISP_FAIL_ADDR,              0x36282)
+EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM,         0x0d0b6)
+EVENT(PM_IERAT_WR_64K,                        0x040be)
+EVENT(PM_MRK_DTLB_MISS_16M,                   0x4d05e)
+EVENT(PM_IERAT_MISS,                          0x100f6)
+EVENT(PM_MRK_PTEG_FROM_LMEM,                  0x4d052)
+EVENT(PM_FLOP,                                0x100f4)
+EVENT(PM_THRD_PRIO_4_5_CYC,                   0x040b4)
+EVENT(PM_BR_PRED_TA,                          0x040aa)
+EVENT(PM_CMPLU_STALL_FXU,                     0x20014)
+EVENT(PM_EXT_INT,                             0x200f8)
+EVENT(PM_VSU_FSQRT_FDIV,                      0x0a888)
+EVENT(PM_MRK_LD_MISS_EXPOSED_CYC,             0x1003e)
+EVENT(PM_LSU1_LDF,                            0x0c086)
+EVENT(PM_IC_WRITE_ALL,                        0x0488c)
+EVENT(PM_LSU0_SRQ_STFWD,                      0x0c0a0)
+EVENT(PM_PTEG_FROM_RL2L3_MOD,                 0x1c052)
+EVENT(PM_MRK_DATA_FROM_L31_SHR,               0x1d04e)
+EVENT(PM_DATA_FROM_L21_MOD,                   0x3c046)
+EVENT(PM_VSU1_SCAL_DOUBLE_ISSUED,             0x0b08a)
+EVENT(PM_VSU0_8FLOP,                          0x0a0a0)
+EVENT(PM_POWER_EVENT1,                        0x1006e)
+EVENT(PM_DISP_CLB_HELD_BAL,                   0x02092)
+EVENT(PM_VSU1_2FLOP,                          0x0a09a)
+EVENT(PM_LWSYNC_HELD,                         0x0209a)
+EVENT(PM_PTEG_FROM_DL2L3_SHR,                 0x3c054)
+EVENT(PM_INST_FROM_L21_MOD,                   0x34046)
+EVENT(PM_IERAT_XLATE_WR_16MPLUS,              0x040bc)
+EVENT(PM_IC_REQ_ALL,                          0x04888)
+EVENT(PM_DSLB_MISS,                           0x0d090)
+EVENT(PM_L3_MISS,                             0x1f082)
+EVENT(PM_LSU0_L1_PREF,                        0x0d0b8)
+EVENT(PM_VSU_SCALAR_SINGLE_ISSUED,            0x0b884)
+EVENT(PM_LSU1_DC_PREF_STREAM_CONFIRM_STRIDE,  0x0d0be)
+EVENT(PM_L2_INST,                             0x36080)
+EVENT(PM_VSU0_FRSP,                           0x0a0b4)
+EVENT(PM_FLUSH_DISP,                          0x02082)
+EVENT(PM_PTEG_FROM_L2MISS,                    0x4c058)
+EVENT(PM_VSU1_DQ_ISSUED,                      0x0b09a)
+EVENT(PM_CMPLU_STALL_LSU,                     0x20012)
+EVENT(PM_MRK_DATA_FROM_DMEM,                  0x1d04a)
+EVENT(PM_LSU_FLUSH_ULD,                       0x0c8b0)
+EVENT(PM_PTEG_FROM_LMEM,                      0x4c052)
+EVENT(PM_MRK_DERAT_MISS_16M,                  0x3d05c)
+EVENT(PM_THRD_ALL_RUN_CYC,                    0x2000c)
+EVENT(PM_MEM0_PREFETCH_DISP,                  0x20083)
+EVENT(PM_MRK_STALL_CMPLU_CYC_COUNT,           0x3003f)
+EVENT(PM_DATA_FROM_DL2L3_MOD,                 0x3c04c)
+EVENT(PM_VSU_FRSP,                            0x0a8b4)
+EVENT(PM_MRK_DATA_FROM_L21_MOD,               0x3d046)
+EVENT(PM_PMC1_OVERFLOW,                       0x20010)
+EVENT(PM_VSU0_SINGLE,                         0x0a0a8)
+EVENT(PM_MRK_PTEG_FROM_L3MISS,                0x2d058)
+EVENT(PM_MRK_PTEG_FROM_L31_SHR,               0x2d056)
+EVENT(PM_VSU0_VECTOR_SP_ISSUED,               0x0b090)
+EVENT(PM_VSU1_FEST,                           0x0a0ba)
+EVENT(PM_MRK_INST_DISP,                       0x20030)
+EVENT(PM_VSU0_COMPLEX_ISSUED,                 0x0b096)
+EVENT(PM_LSU1_FLUSH_UST,                      0x0c0b6)
+EVENT(PM_INST_CMPL,                           0x00002)
+EVENT(PM_FXU_IDLE,                            0x1000e)
+EVENT(PM_LSU0_FLUSH_ULD,                      0x0c0b0)
+EVENT(PM_MRK_DATA_FROM_DL2L3_MOD,             0x3d04c)
+EVENT(PM_LSU_LMQ_SRQ_EMPTY_ALL_CYC,           0x3001c)
+EVENT(PM_LSU1_REJECT_LMQ_FULL,                0x0c0a6)
+EVENT(PM_INST_PTEG_FROM_L21_MOD,              0x3e056)
+EVENT(PM_INST_FROM_RL2L3_MOD,                 0x14042)
+EVENT(PM_SHL_CREATED,                         0x05082)
+EVENT(PM_L2_ST_HIT,                           0x46182)
+EVENT(PM_DATA_FROM_DMEM,                      0x1c04a)
+EVENT(PM_L3_LD_MISS,                          0x2f082)
+EVENT(PM_FXU1_BUSY_FXU0_IDLE,                 0x4000e)
+EVENT(PM_DISP_CLB_HELD_RES,                   0x02094)
+EVENT(PM_L2_SN_SX_I_DONE,                     0x36382)
+EVENT(PM_GRP_CMPL,                            0x30004)
+EVENT(PM_STCX_CMPL,                           0x0c098)
+EVENT(PM_VSU0_2FLOP,                          0x0a098)
+EVENT(PM_L3_PREF_MISS,                        0x3f082)
+EVENT(PM_LSU_SRQ_SYNC_CYC,                    0x0d096)
+EVENT(PM_LSU_REJECT_ERAT_MISS,                0x20064)
+EVENT(PM_L1_ICACHE_MISS,                      0x200fc)
+EVENT(PM_LSU1_FLUSH_SRQ,                      0x0c0be)
+EVENT(PM_LD_REF_L1_LSU0,                      0x0c080)
+EVENT(PM_VSU0_FEST,                           0x0a0b8)
+EVENT(PM_VSU_VECTOR_SINGLE_ISSUED,            0x0b890)
+EVENT(PM_FREQ_UP,                             0x4000c)
+EVENT(PM_DATA_FROM_LMEM,                      0x3c04a)
+EVENT(PM_LSU1_LDX,                            0x0c08a)
+EVENT(PM_PMC3_OVERFLOW,                       0x40010)
+EVENT(PM_MRK_BR_MPRED,                        0x30036)
+EVENT(PM_SHL_MATCH,                           0x05086)
+EVENT(PM_MRK_BR_TAKEN,                        0x10036)
+EVENT(PM_CMPLU_STALL_BRU,                     0x4004e)
+EVENT(PM_ISLB_MISS,                           0x0d092)
+EVENT(PM_CYC,                                 0x0001e)
+EVENT(PM_DISP_HELD_THERMAL,                   0x30006)
+EVENT(PM_INST_PTEG_FROM_RL2L3_SHR,            0x2e054)
+EVENT(PM_LSU1_SRQ_STFWD,                      0x0c0a2)
+EVENT(PM_GCT_NOSLOT_BR_MPRED,                 0x4001a)
+EVENT(PM_1PLUS_PPC_CMPL,                      0x100f2)
+EVENT(PM_PTEG_FROM_DMEM,                      0x2c052)
+EVENT(PM_VSU_2FLOP,                           0x0a898)
+EVENT(PM_GCT_FULL_CYC,                        0x04086)
+EVENT(PM_MRK_DATA_FROM_L3_CYC,                0x40020)
+EVENT(PM_LSU_SRQ_S0_ALLOC,                    0x0d09d)
+EVENT(PM_MRK_DERAT_MISS_4K,                   0x1d05c)
+EVENT(PM_BR_MPRED_TA,                         0x040ae)
+EVENT(PM_INST_PTEG_FROM_L2MISS,               0x4e058)
+EVENT(PM_DPU_HELD_POWER,                      0x20006)
+EVENT(PM_RUN_INST_CMPL,                       0x400fa)
+EVENT(PM_MRK_VSU_FIN,                         0x30032)
+EVENT(PM_LSU_SRQ_S0_VALID,                    0x0d09c)
+EVENT(PM_GCT_EMPTY_CYC,                       0x20008)
+EVENT(PM_IOPS_DISP,                           0x30014)
+EVENT(PM_RUN_SPURR,                           0x10008)
+EVENT(PM_PTEG_FROM_L21_MOD,                   0x3c056)
+EVENT(PM_VSU0_1FLOP,                          0x0a080)
+EVENT(PM_SNOOP_TLBIE,                         0x0d0b2)
+EVENT(PM_DATA_FROM_L3MISS,                    0x2c048)
+EVENT(PM_VSU_SINGLE,                          0x0a8a8)
+EVENT(PM_DTLB_MISS_16G,                       0x1c05e)
+EVENT(PM_CMPLU_STALL_VECTOR,                  0x2001c)
+EVENT(PM_FLUSH,                               0x400f8)
+EVENT(PM_L2_LD_HIT,                           0x36182)
+EVENT(PM_NEST_PAIR2_AND,                      0x30883)
+EVENT(PM_VSU1_1FLOP,                          0x0a082)
+EVENT(PM_IC_PREF_REQ,                         0x0408a)
+EVENT(PM_L3_LD_HIT,                           0x2f080)
+EVENT(PM_GCT_NOSLOT_IC_MISS,                  0x2001a)
+EVENT(PM_DISP_HELD,                           0x10006)
+EVENT(PM_L2_LD,                               0x16080)
+EVENT(PM_LSU_FLUSH_SRQ,                       0x0c8bc)
+EVENT(PM_BC_PLUS_8_CONV,                      0x040b8)
+EVENT(PM_MRK_DATA_FROM_L31_MOD_CYC,           0x40026)
+EVENT(PM_CMPLU_STALL_VECTOR_LONG,             0x4004a)
+EVENT(PM_L2_RCST_BUSY_RC_FULL,                0x26282)
+EVENT(PM_TB_BIT_TRANS,                        0x300f8)
+EVENT(PM_THERMAL_MAX,                         0x40006)
+EVENT(PM_LSU1_FLUSH_ULD,                      0x0c0b2)
+EVENT(PM_LSU1_REJECT_LHS,                     0x0c0ae)
+EVENT(PM_LSU_LRQ_S0_ALLOC,                    0x0d09f)
+EVENT(PM_L3_CO_L31,                           0x4f080)
+EVENT(PM_POWER_EVENT4,                        0x4006e)
+EVENT(PM_DATA_FROM_L31_SHR,                   0x1c04e)
+EVENT(PM_BR_UNCOND,                           0x0409e)
+EVENT(PM_LSU1_DC_PREF_STREAM_ALLOC,           0x0d0aa)
+EVENT(PM_PMC4_REWIND,                         0x10020)
+EVENT(PM_L2_RCLD_DISP,                        0x16280)
+EVENT(PM_THRD_PRIO_2_3_CYC,                   0x040b2)
+EVENT(PM_MRK_PTEG_FROM_L2MISS,                0x4d058)
+EVENT(PM_IC_DEMAND_L2_BHT_REDIRECT,           0x04098)
+EVENT(PM_LSU_DERAT_MISS,                      0x200f6)
+EVENT(PM_IC_PREF_CANCEL_L2,                   0x04094)
+EVENT(PM_MRK_FIN_STALL_CYC_COUNT,             0x1003d)
+EVENT(PM_BR_PRED_CCACHE,                      0x040a0)
+EVENT(PM_GCT_UTIL_1_TO_2_SLOTS,               0x0209c)
+EVENT(PM_MRK_ST_CMPL_INT,                     0x30034)
+EVENT(PM_LSU_TWO_TABLEWALK_CYC,               0x0d0a6)
+EVENT(PM_MRK_DATA_FROM_L3MISS,                0x2d048)
+EVENT(PM_GCT_NOSLOT_CYC,                      0x100f8)
+EVENT(PM_LSU_SET_MPRED,                       0x0c0a8)
+EVENT(PM_FLUSH_DISP_TLBIE,                    0x0208a)
+EVENT(PM_VSU1_FCONV,                          0x0a0b2)
+EVENT(PM_DERAT_MISS_16G,                      0x4c05c)
+EVENT(PM_INST_FROM_LMEM,                      0x3404a)
+EVENT(PM_IC_DEMAND_L2_BR_REDIRECT,            0x0409a)
+EVENT(PM_CMPLU_STALL_SCALAR_LONG,             0x20018)
+EVENT(PM_INST_PTEG_FROM_L2,                   0x1e050)
+EVENT(PM_PTEG_FROM_L2,                        0x1c050)
+EVENT(PM_MRK_DATA_FROM_L21_SHR_CYC,           0x20024)
+EVENT(PM_MRK_DTLB_MISS_4K,                    0x2d05a)
+EVENT(PM_VSU0_FPSCR,                          0x0b09c)
+EVENT(PM_VSU1_VECT_DOUBLE_ISSUED,             0x0b082)
+EVENT(PM_MRK_PTEG_FROM_RL2L3_MOD,             0x1d052)
+EVENT(PM_MEM0_RQ_DISP,                        0x10083)
+EVENT(PM_L2_LD_MISS,                          0x26080)
+EVENT(PM_VMX_RESULT_SAT_1,                    0x0b0a0)
+EVENT(PM_L1_PREF,                             0x0d8b8)
+EVENT(PM_MRK_DATA_FROM_LMEM_CYC,              0x2002c)
+EVENT(PM_GRP_IC_MISS_NONSPEC,                 0x1000c)
+EVENT(PM_PB_NODE_PUMP,                        0x10081)
+EVENT(PM_SHL_MERGED,                          0x05084)
+EVENT(PM_NEST_PAIR1_ADD,                      0x20881)
+EVENT(PM_DATA_FROM_L3,                        0x1c048)
+EVENT(PM_LSU_FLUSH,                           0x0208e)
+EVENT(PM_LSU_SRQ_SYNC_COUNT,                  0x0d097)
+EVENT(PM_PMC2_OVERFLOW,                       0x30010)
+EVENT(PM_LSU_LDF,                             0x0c884)
+EVENT(PM_POWER_EVENT3,                        0x3006e)
+EVENT(PM_DISP_WT,                             0x30008)
+EVENT(PM_CMPLU_STALL_REJECT,                  0x40016)
+EVENT(PM_IC_BANK_CONFLICT,                    0x04082)
+EVENT(PM_BR_MPRED_CR_TA,                      0x048ae)
+EVENT(PM_L2_INST_MISS,                        0x36082)
+EVENT(PM_CMPLU_STALL_ERAT_MISS,               0x40018)
+EVENT(PM_NEST_PAIR2_ADD,                      0x30881)
+EVENT(PM_MRK_LSU_FLUSH,                       0x0d08c)
+EVENT(PM_L2_LDST,                             0x16880)
+EVENT(PM_INST_FROM_L31_SHR,                   0x1404e)
+EVENT(PM_VSU0_FIN,                            0x0a0bc)
+EVENT(PM_LARX_LSU,                            0x0c894)
+EVENT(PM_INST_FROM_RMEM,                      0x34042)
+EVENT(PM_DISP_CLB_HELD_TLBIE,                 0x02096)
+EVENT(PM_MRK_DATA_FROM_DMEM_CYC,              0x2002e)
+EVENT(PM_BR_PRED_CR,                          0x040a8)
+EVENT(PM_LSU_REJECT,                          0x10064)
+EVENT(PM_GCT_UTIL_3_TO_6_SLOTS,               0x0209e)
+EVENT(PM_CMPLU_STALL_END_GCT_NOSLOT,          0x10028)
+EVENT(PM_LSU0_REJECT_LMQ_FULL,                0x0c0a4)
+EVENT(PM_VSU_FEST,                            0x0a8b8)
+EVENT(PM_NEST_PAIR0_AND,                      0x10883)
+EVENT(PM_PTEG_FROM_L3,                        0x2c050)
+EVENT(PM_POWER_EVENT2,                        0x2006e)
+EVENT(PM_IC_PREF_CANCEL_PAGE,                 0x04090)
+EVENT(PM_VSU0_FSQRT_FDIV,                     0x0a088)
+EVENT(PM_MRK_GRP_CMPL,                        0x40030)
+EVENT(PM_VSU0_SCAL_DOUBLE_ISSUED,             0x0b088)
+EVENT(PM_GRP_DISP,                            0x3000a)
+EVENT(PM_LSU0_LDX,                            0x0c088)
+EVENT(PM_DATA_FROM_L2,                        0x1c040)
+EVENT(PM_MRK_DATA_FROM_RL2L3_MOD,             0x1d042)
+EVENT(PM_LD_REF_L1,                           0x0c880)
+EVENT(PM_VSU0_VECT_DOUBLE_ISSUED,             0x0b080)
+EVENT(PM_VSU1_2FLOP_DOUBLE,                   0x0a08e)
+EVENT(PM_THRD_PRIO_6_7_CYC,                   0x040b6)
+EVENT(PM_BC_PLUS_8_RSLV_TAKEN,                0x040ba)
+EVENT(PM_BR_MPRED_CR,                         0x040ac)
+EVENT(PM_L3_CO_MEM,                           0x4f082)
+EVENT(PM_LD_MISS_L1,                          0x400f0)
+EVENT(PM_DATA_FROM_RL2L3_MOD,                 0x1c042)
+EVENT(PM_LSU_SRQ_FULL_CYC,                    0x1001a)
+EVENT(PM_TABLEWALK_CYC,                       0x10026)
+EVENT(PM_MRK_PTEG_FROM_RMEM,                  0x3d052)
+EVENT(PM_LSU_SRQ_STFWD,                       0x0c8a0)
+EVENT(PM_INST_PTEG_FROM_RMEM,                 0x3e052)
+EVENT(PM_FXU0_FIN,                            0x10004)
+EVENT(PM_LSU1_L1_SW_PREF,                     0x0c09e)
+EVENT(PM_PTEG_FROM_L31_MOD,                   0x1c054)
+EVENT(PM_PMC5_OVERFLOW,                       0x10024)
+EVENT(PM_LD_REF_L1_LSU1,                      0x0c082)
+EVENT(PM_INST_PTEG_FROM_L21_SHR,              0x4e056)
+EVENT(PM_CMPLU_STALL_THRD,                    0x1001c)
+EVENT(PM_DATA_FROM_RMEM,                      0x3c042)
+EVENT(PM_VSU0_SCAL_SINGLE_ISSUED,             0x0b084)
+EVENT(PM_BR_MPRED_LSTACK,                     0x040a6)
+EVENT(PM_MRK_DATA_FROM_RL2L3_MOD_CYC,         0x40028)
+EVENT(PM_LSU0_FLUSH_UST,                      0x0c0b4)
+EVENT(PM_LSU_NCST,                            0x0c090)
+EVENT(PM_BR_TAKEN,                            0x20004)
+EVENT(PM_INST_PTEG_FROM_LMEM,                 0x4e052)
+EVENT(PM_GCT_NOSLOT_BR_MPRED_IC_MISS,         0x4001c)
+EVENT(PM_DTLB_MISS_4K,                        0x2c05a)
+EVENT(PM_PMC4_SAVED,                          0x30022)
+EVENT(PM_VSU1_PERMUTE_ISSUED,                 0x0b092)
+EVENT(PM_SLB_MISS,                            0x0d890)
+EVENT(PM_LSU1_FLUSH_LRQ,                      0x0c0ba)
+EVENT(PM_DTLB_MISS,                           0x300fc)
+EVENT(PM_VSU1_FRSP,                           0x0a0b6)
+EVENT(PM_VSU_VECTOR_DOUBLE_ISSUED,            0x0b880)
+EVENT(PM_L2_CASTOUT_SHR,                      0x16182)
+EVENT(PM_DATA_FROM_DL2L3_SHR,                 0x3c044)
+EVENT(PM_VSU1_STF,                            0x0b08e)
+EVENT(PM_ST_FIN,                              0x200f0)
+EVENT(PM_PTEG_FROM_L21_SHR,                   0x4c056)
+EVENT(PM_L2_LOC_GUESS_WRONG,                  0x26480)
+EVENT(PM_MRK_STCX_FAIL,                       0x0d08e)
+EVENT(PM_LSU0_REJECT_LHS,                     0x0c0ac)
+EVENT(PM_IC_PREF_CANCEL_HIT,                  0x04092)
+EVENT(PM_L3_PREF_BUSY,                        0x4f080)
+EVENT(PM_MRK_BRU_FIN,                         0x2003a)
+EVENT(PM_LSU1_NCLD,                           0x0c08e)
+EVENT(PM_INST_PTEG_FROM_L31_MOD,              0x1e054)
+EVENT(PM_LSU_NCLD,                            0x0c88c)
+EVENT(PM_LSU_LDX,                             0x0c888)
+EVENT(PM_L2_LOC_GUESS_CORRECT,                0x16480)
+EVENT(PM_THRESH_TIMEO,                        0x10038)
+EVENT(PM_L3_PREF_ST,                          0x0d0ae)
+EVENT(PM_DISP_CLB_HELD_SYNC,                  0x02098)
+EVENT(PM_VSU_SIMPLE_ISSUED,                   0x0b894)
+EVENT(PM_VSU1_SINGLE,                         0x0a0aa)
+EVENT(PM_DATA_TABLEWALK_CYC,                  0x3001a)
+EVENT(PM_L2_RC_ST_DONE,                       0x36380)
+EVENT(PM_MRK_PTEG_FROM_L21_MOD,               0x3d056)
+EVENT(PM_LARX_LSU1,                           0x0c096)
+EVENT(PM_MRK_DATA_FROM_RMEM,                  0x3d042)
+EVENT(PM_DISP_CLB_HELD,                       0x02090)
+EVENT(PM_DERAT_MISS_4K,                       0x1c05c)
+EVENT(PM_L2_RCLD_DISP_FAIL_ADDR,              0x16282)
+EVENT(PM_SEG_EXCEPTION,                       0x028a4)
+EVENT(PM_FLUSH_DISP_SB,                       0x0208c)
+EVENT(PM_L2_DC_INV,                           0x26182)
+EVENT(PM_PTEG_FROM_DL2L3_MOD,                 0x4c054)
+EVENT(PM_DSEG,                                0x020a6)
+EVENT(PM_BR_PRED_LSTACK,                      0x040a2)
+EVENT(PM_VSU0_STF,                            0x0b08c)
+EVENT(PM_LSU_FX_FIN,                          0x10066)
+EVENT(PM_DERAT_MISS_16M,                      0x3c05c)
+EVENT(PM_MRK_PTEG_FROM_DL2L3_MOD,             0x4d054)
+EVENT(PM_GCT_UTIL_11_PLUS_SLOTS,              0x020a2)
+EVENT(PM_INST_FROM_L3,                        0x14048)
+EVENT(PM_MRK_IFU_FIN,                         0x3003a)
+EVENT(PM_ITLB_MISS,                           0x400fc)
+EVENT(PM_VSU_STF,                             0x0b88c)
+EVENT(PM_LSU_FLUSH_UST,                       0x0c8b4)
+EVENT(PM_L2_LDST_MISS,                        0x26880)
+EVENT(PM_FXU1_FIN,                            0x40004)
+EVENT(PM_SHL_DEALLOCATED,                     0x05080)
+EVENT(PM_L2_SN_M_WR_DONE,                     0x46382)
+EVENT(PM_LSU_REJECT_SET_MPRED,                0x0c8a8)
+EVENT(PM_L3_PREF_LD,                          0x0d0ac)
+EVENT(PM_L2_SN_M_RD_DONE,                     0x46380)
+EVENT(PM_MRK_DERAT_MISS_16G,                  0x4d05c)
+EVENT(PM_VSU_FCONV,                           0x0a8b0)
+EVENT(PM_ANY_THRD_RUN_CYC,                    0x100fa)
+EVENT(PM_LSU_LMQ_FULL_CYC,                    0x0d0a4)
+EVENT(PM_MRK_LSU_REJECT_LHS,                  0x0d082)
+EVENT(PM_MRK_LD_MISS_L1_CYC,                  0x4003e)
+EVENT(PM_MRK_DATA_FROM_L2_CYC,                0x20020)
+EVENT(PM_INST_IMC_MATCH_DISP,                 0x30016)
+EVENT(PM_MRK_DATA_FROM_RMEM_CYC,              0x4002c)
+EVENT(PM_VSU0_SIMPLE_ISSUED,                  0x0b094)
+EVENT(PM_CMPLU_STALL_DIV,                     0x40014)
+EVENT(PM_MRK_PTEG_FROM_RL2L3_SHR,             0x2d054)
+EVENT(PM_VSU_FMA_DOUBLE,                      0x0a890)
+EVENT(PM_VSU_4FLOP,                           0x0a89c)
+EVENT(PM_VSU1_FIN,                            0x0a0be)
+EVENT(PM_NEST_PAIR1_AND,                      0x20883)
+EVENT(PM_INST_PTEG_FROM_RL2L3_MOD,            0x1e052)
+EVENT(PM_RUN_CYC,                             0x200f4)
+EVENT(PM_PTEG_FROM_RMEM,                      0x3c052)
+EVENT(PM_LSU_LRQ_S0_VALID,                    0x0d09e)
+EVENT(PM_LSU0_LDF,                            0x0c084)
+EVENT(PM_FLUSH_COMPLETION,                    0x30012)
+EVENT(PM_ST_MISS_L1,                          0x300f0)
+EVENT(PM_L2_NODE_PUMP,                        0x36480)
+EVENT(PM_INST_FROM_DL2L3_SHR,                 0x34044)
+EVENT(PM_MRK_STALL_CMPLU_CYC,                 0x3003e)
+EVENT(PM_VSU1_DENORM,                         0x0a0ae)
+EVENT(PM_MRK_DATA_FROM_L31_SHR_CYC,           0x20026)
+EVENT(PM_NEST_PAIR0_ADD,                      0x10881)
+EVENT(PM_INST_FROM_L3MISS,                    0x24048)
+EVENT(PM_EE_OFF_EXT_INT,                      0x02080)
+EVENT(PM_INST_PTEG_FROM_DMEM,                 0x2e052)
+EVENT(PM_INST_FROM_DL2L3_MOD,                 0x3404c)
+EVENT(PM_PMC6_OVERFLOW,                       0x30024)
+EVENT(PM_VSU_2FLOP_DOUBLE,                    0x0a88c)
+EVENT(PM_TLB_MISS,                            0x20066)
+EVENT(PM_FXU_BUSY,                            0x2000e)
+EVENT(PM_L2_RCLD_DISP_FAIL_OTHER,             0x26280)
+EVENT(PM_LSU_REJECT_LMQ_FULL,                 0x0c8a4)
+EVENT(PM_IC_RELOAD_SHR,                       0x04096)
+EVENT(PM_GRP_MRK,                             0x10031)
+EVENT(PM_MRK_ST_NEST,                         0x20034)
+EVENT(PM_VSU1_FSQRT_FDIV,                     0x0a08a)
+EVENT(PM_LSU0_FLUSH_LRQ,                      0x0c0b8)
+EVENT(PM_LARX_LSU0,                           0x0c094)
+EVENT(PM_IBUF_FULL_CYC,                       0x04084)
+EVENT(PM_MRK_DATA_FROM_DL2L3_SHR_CYC,         0x2002a)
+EVENT(PM_LSU_DC_PREF_STREAM_ALLOC,            0x0d8a8)
+EVENT(PM_GRP_MRK_CYC,                         0x10030)
+EVENT(PM_MRK_DATA_FROM_RL2L3_SHR_CYC,         0x20028)
+EVENT(PM_L2_GLOB_GUESS_CORRECT,               0x16482)
+EVENT(PM_LSU_REJECT_LHS,                      0x0c8ac)
+EVENT(PM_MRK_DATA_FROM_LMEM,                  0x3d04a)
+EVENT(PM_INST_PTEG_FROM_L3,                   0x2e050)
+EVENT(PM_FREQ_DOWN,                           0x3000c)
+EVENT(PM_PB_RETRY_NODE_PUMP,                  0x30081)
+EVENT(PM_INST_FROM_RL2L3_SHR,                 0x1404c)
+EVENT(PM_MRK_INST_ISSUED,                     0x10032)
+EVENT(PM_PTEG_FROM_L3MISS,                    0x2c058)
+EVENT(PM_RUN_PURR,                            0x400f4)
+EVENT(PM_MRK_GRP_IC_MISS,                     0x40038)
+EVENT(PM_MRK_DATA_FROM_L3,                    0x1d048)
+EVENT(PM_CMPLU_STALL_DCACHE_MISS,             0x20016)
+EVENT(PM_PTEG_FROM_RL2L3_SHR,                 0x2c054)
+EVENT(PM_LSU_FLUSH_LRQ,                       0x0c8b8)
+EVENT(PM_MRK_DERAT_MISS_64K,                  0x2d05c)
+EVENT(PM_INST_PTEG_FROM_DL2L3_MOD,            0x4e054)
+EVENT(PM_L2_ST_MISS,                          0x26082)
+EVENT(PM_MRK_PTEG_FROM_L21_SHR,               0x4d056)
+EVENT(PM_LWSYNC,                              0x0d094)
+EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM_STRIDE,  0x0d0bc)
+EVENT(PM_MRK_LSU_FLUSH_LRQ,                   0x0d088)
+EVENT(PM_INST_IMC_MATCH_CMPL,                 0x100f0)
+EVENT(PM_NEST_PAIR3_AND,                      0x40883)
+EVENT(PM_PB_RETRY_SYS_PUMP,                   0x40081)
+EVENT(PM_MRK_INST_FIN,                        0x30030)
+EVENT(PM_MRK_PTEG_FROM_DL2L3_SHR,             0x3d054)
+EVENT(PM_INST_FROM_L31_MOD,                   0x14044)
+EVENT(PM_MRK_DTLB_MISS_64K,                   0x3d05e)
+EVENT(PM_LSU_FIN,                             0x30066)
+EVENT(PM_MRK_LSU_REJECT,                      0x40064)
+EVENT(PM_L2_CO_FAIL_BUSY,                     0x16382)
+EVENT(PM_MEM0_WQ_DISP,                        0x40083)
+EVENT(PM_DATA_FROM_L31_MOD,                   0x1c044)
+EVENT(PM_THERMAL_WARN,                        0x10016)
+EVENT(PM_VSU0_4FLOP,                          0x0a09c)
+EVENT(PM_BR_MPRED_CCACHE,                     0x040a4)
+EVENT(PM_CMPLU_STALL_IFU,                     0x4004c)
+EVENT(PM_L1_DEMAND_WRITE,                     0x0408c)
+EVENT(PM_FLUSH_BR_MPRED,                      0x02084)
+EVENT(PM_MRK_DTLB_MISS_16G,                   0x1d05e)
+EVENT(PM_MRK_PTEG_FROM_DMEM,                  0x2d052)
+EVENT(PM_L2_RCST_DISP,                        0x36280)
+EVENT(PM_CMPLU_STALL,                         0x4000a)
+EVENT(PM_LSU_PARTIAL_CDF,                     0x0c0aa)
+EVENT(PM_DISP_CLB_HELD_SB,                    0x020a8)
+EVENT(PM_VSU0_FMA_DOUBLE,                     0x0a090)
+EVENT(PM_FXU0_BUSY_FXU1_IDLE,                 0x3000e)
+EVENT(PM_IC_DEMAND_CYC,                       0x10018)
+EVENT(PM_MRK_DATA_FROM_L21_SHR,               0x3d04e)
+EVENT(PM_MRK_LSU_FLUSH_UST,                   0x0d086)
+EVENT(PM_INST_PTEG_FROM_L3MISS,               0x2e058)
+EVENT(PM_VSU_DENORM,                          0x0a8ac)
+EVENT(PM_MRK_LSU_PARTIAL_CDF,                 0x0d080)
+EVENT(PM_INST_FROM_L21_SHR,                   0x3404e)
+EVENT(PM_IC_PREF_WRITE,                       0x0408e)
+EVENT(PM_BR_PRED,                             0x0409c)
+EVENT(PM_INST_FROM_DMEM,                      0x1404a)
+EVENT(PM_IC_PREF_CANCEL_ALL,                  0x04890)
+EVENT(PM_LSU_DC_PREF_STREAM_CONFIRM,          0x0d8b4)
+EVENT(PM_MRK_LSU_FLUSH_SRQ,                   0x0d08a)
+EVENT(PM_MRK_FIN_STALL_CYC,                   0x1003c)
+EVENT(PM_L2_RCST_DISP_FAIL_OTHER,             0x46280)
+EVENT(PM_VSU1_DD_ISSUED,                      0x0b098)
+EVENT(PM_PTEG_FROM_L31_SHR,                   0x2c056)
+EVENT(PM_DATA_FROM_L21_SHR,                   0x3c04e)
+EVENT(PM_LSU0_NCLD,                           0x0c08c)
+EVENT(PM_VSU1_4FLOP,                          0x0a09e)
+EVENT(PM_VSU1_8FLOP,                          0x0a0a2)
+EVENT(PM_VSU_8FLOP,                           0x0a8a0)
+EVENT(PM_LSU_LMQ_SRQ_EMPTY_CYC,               0x2003e)
+EVENT(PM_DTLB_MISS_64K,                       0x3c05e)
+EVENT(PM_THRD_CONC_RUN_INST,                  0x300f4)
+EVENT(PM_MRK_PTEG_FROM_L2,                    0x1d050)
+EVENT(PM_PB_SYS_PUMP,                         0x20081)
+EVENT(PM_VSU_FIN,                             0x0a8bc)
+EVENT(PM_MRK_DATA_FROM_L31_MOD,               0x1d044)
+EVENT(PM_THRD_PRIO_0_1_CYC,                   0x040b0)
+EVENT(PM_DERAT_MISS_64K,                      0x2c05c)
+EVENT(PM_PMC2_REWIND,                         0x30020)
+EVENT(PM_INST_FROM_L2,                        0x14040)
+EVENT(PM_GRP_BR_MPRED_NONSPEC,                0x1000a)
+EVENT(PM_INST_DISP,                           0x200f2)
+EVENT(PM_MEM0_RD_CANCEL_TOTAL,                0x30083)
+EVENT(PM_LSU0_DC_PREF_STREAM_CONFIRM,         0x0d0b4)
+EVENT(PM_L1_DCACHE_RELOAD_VALID,              0x300f6)
+EVENT(PM_VSU_SCALAR_DOUBLE_ISSUED,            0x0b888)
+EVENT(PM_L3_PREF_HIT,                         0x3f080)
+EVENT(PM_MRK_PTEG_FROM_L31_MOD,               0x1d054)
+EVENT(PM_CMPLU_STALL_STORE,                   0x2004a)
+EVENT(PM_MRK_FXU_FIN,                         0x20038)
+EVENT(PM_PMC4_OVERFLOW,                       0x10010)
+EVENT(PM_MRK_PTEG_FROM_L3,                    0x2d050)
+EVENT(PM_LSU0_LMQ_LHR_MERGE,                  0x0d098)
+EVENT(PM_BTAC_HIT,                            0x0508a)
+EVENT(PM_L3_RD_BUSY,                          0x4f082)
+EVENT(PM_LSU0_L1_SW_PREF,                     0x0c09c)
+EVENT(PM_INST_FROM_L2MISS,                    0x44048)
+EVENT(PM_LSU0_DC_PREF_STREAM_ALLOC,           0x0d0a8)
+EVENT(PM_L2_ST,                               0x16082)
+EVENT(PM_VSU0_DENORM,                         0x0a0ac)
+EVENT(PM_MRK_DATA_FROM_DL2L3_SHR,             0x3d044)
+EVENT(PM_BR_PRED_CR_TA,                       0x048aa)
+EVENT(PM_VSU0_FCONV,                          0x0a0b0)
+EVENT(PM_MRK_LSU_FLUSH_ULD,                   0x0d084)
+EVENT(PM_BTAC_MISS,                           0x05088)
+EVENT(PM_MRK_LD_MISS_EXPOSED_CYC_COUNT,       0x1003f)
+EVENT(PM_MRK_DATA_FROM_L2,                    0x1d040)
+EVENT(PM_LSU_DCACHE_RELOAD_VALID,             0x0d0a2)
+EVENT(PM_VSU_FMA,                             0x0a884)
+EVENT(PM_LSU0_FLUSH_SRQ,                      0x0c0bc)
+EVENT(PM_LSU1_L1_PREF,                        0x0d0ba)
+EVENT(PM_IOPS_CMPL,                           0x10014)
+EVENT(PM_L2_SYS_PUMP,                         0x36482)
+EVENT(PM_L2_RCLD_BUSY_RC_FULL,                0x46282)
+EVENT(PM_LSU_LMQ_S0_ALLOC,                    0x0d0a1)
+EVENT(PM_FLUSH_DISP_SYNC,                     0x02088)
+EVENT(PM_MRK_DATA_FROM_DL2L3_MOD_CYC,         0x4002a)
+EVENT(PM_L2_IC_INV,                           0x26180)
+EVENT(PM_MRK_DATA_FROM_L21_MOD_CYC,           0x40024)
+EVENT(PM_L3_PREF_LDST,                        0x0d8ac)
+EVENT(PM_LSU_SRQ_EMPTY_CYC,                   0x40008)
+EVENT(PM_LSU_LMQ_S0_VALID,                    0x0d0a0)
+EVENT(PM_FLUSH_PARTIAL,                       0x02086)
+EVENT(PM_VSU1_FMA_DOUBLE,                     0x0a092)
+EVENT(PM_1PLUS_PPC_DISP,                      0x400f2)
+EVENT(PM_DATA_FROM_L2MISS,                    0x200fe)
+EVENT(PM_SUSPENDED,                           0x00000)
+EVENT(PM_VSU0_FMA,                            0x0a084)
+EVENT(PM_CMPLU_STALL_SCALAR,                  0x40012)
+EVENT(PM_STCX_FAIL,                           0x0c09a)
+EVENT(PM_VSU0_FSQRT_FDIV_DOUBLE,              0x0a094)
+EVENT(PM_DC_PREF_DST,                         0x0d0b0)
+EVENT(PM_VSU1_SCAL_SINGLE_ISSUED,             0x0b086)
+EVENT(PM_L3_HIT,                              0x1f080)
+EVENT(PM_L2_GLOB_GUESS_WRONG,                 0x26482)
+EVENT(PM_MRK_DFU_FIN,                         0x20032)
+EVENT(PM_INST_FROM_L1,                        0x04080)
+EVENT(PM_BRU_FIN,                             0x10068)
+EVENT(PM_IC_DEMAND_REQ,                       0x04088)
+EVENT(PM_VSU1_FSQRT_FDIV_DOUBLE,              0x0a096)
+EVENT(PM_VSU1_FMA,                            0x0a086)
+EVENT(PM_MRK_LD_MISS_L1,                      0x20036)
+EVENT(PM_VSU0_2FLOP_DOUBLE,                   0x0a08c)
+EVENT(PM_LSU_DC_PREF_STRIDED_STREAM_CONFIRM,  0x0d8bc)
+EVENT(PM_INST_PTEG_FROM_L31_SHR,              0x2e056)
+EVENT(PM_MRK_LSU_REJECT_ERAT_MISS,            0x30064)
+EVENT(PM_MRK_DATA_FROM_L2MISS,                0x4d048)
+EVENT(PM_DATA_FROM_RL2L3_SHR,                 0x1c04c)
+EVENT(PM_INST_FROM_PREF,                      0x14046)
+EVENT(PM_VSU1_SQ,                             0x0b09e)
+EVENT(PM_L2_LD_DISP,                          0x36180)
+EVENT(PM_L2_DISP_ALL,                         0x46080)
+EVENT(PM_THRD_GRP_CMPL_BOTH_CYC,              0x10012)
+EVENT(PM_VSU_FSQRT_FDIV_DOUBLE,               0x0a894)
+EVENT(PM_BR_MPRED,                            0x400f6)
+EVENT(PM_INST_PTEG_FROM_DL2L3_SHR,            0x3e054)
+EVENT(PM_VSU_1FLOP,                           0x0a880)
+EVENT(PM_HV_CYC,                              0x2000a)
+EVENT(PM_MRK_LSU_FIN,                         0x40032)
+EVENT(PM_MRK_DATA_FROM_RL2L3_SHR,             0x1d04c)
+EVENT(PM_DTLB_MISS_16M,                       0x4c05e)
+EVENT(PM_LSU1_LMQ_LHR_MERGE,                  0x0d09a)
+EVENT(PM_IFU_FIN,                             0x40066)
diff --git a/arch/powerpc/perf/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c
index d1821b8..56c67bc 100644
--- a/arch/powerpc/perf/power7-pmu.c
+++ b/arch/powerpc/perf/power7-pmu.c
@@ -53,37 +53,13 @@
 /*
  * Power7 event codes.
  */
-#define	PME_PM_CYC			0x1e
-#define	PME_PM_GCT_NOSLOT_CYC		0x100f8
-#define	PME_PM_CMPLU_STALL		0x4000a
-#define	PME_PM_INST_CMPL		0x2
-#define	PME_PM_LD_REF_L1		0xc880
-#define	PME_PM_LD_MISS_L1		0x400f0
-#define	PME_PM_BRU_FIN			0x10068
-#define	PME_PM_BR_MPRED			0x400f6
+#define EVENT(_name, _code) \
+	PME_##_name = _code,
 
-#define PME_PM_CMPLU_STALL_FXU			0x20014
-#define PME_PM_CMPLU_STALL_DIV			0x40014
-#define PME_PM_CMPLU_STALL_SCALAR		0x40012
-#define PME_PM_CMPLU_STALL_SCALAR_LONG		0x20018
-#define PME_PM_CMPLU_STALL_VECTOR		0x2001c
-#define PME_PM_CMPLU_STALL_VECTOR_LONG		0x4004a
-#define PME_PM_CMPLU_STALL_LSU			0x20012
-#define PME_PM_CMPLU_STALL_REJECT		0x40016
-#define PME_PM_CMPLU_STALL_ERAT_MISS		0x40018
-#define PME_PM_CMPLU_STALL_DCACHE_MISS		0x20016
-#define PME_PM_CMPLU_STALL_STORE		0x2004a
-#define PME_PM_CMPLU_STALL_THRD			0x1001c
-#define PME_PM_CMPLU_STALL_IFU			0x4004c
-#define PME_PM_CMPLU_STALL_BRU			0x4004e
-#define PME_PM_GCT_NOSLOT_IC_MISS		0x2001a
-#define PME_PM_GCT_NOSLOT_BR_MPRED		0x4001a
-#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS	0x4001c
-#define PME_PM_GRP_CMPL				0x30004
-#define PME_PM_1PLUS_PPC_CMPL			0x100f2
-#define PME_PM_CMPLU_STALL_DFU			0x2003c
-#define PME_PM_RUN_CYC				0x200f4
-#define PME_PM_RUN_INST_CMPL			0x400fa
+enum {
+#include "power7-events-list.h"
+};
+#undef EVENT
 
 /*
  * Layout of constraint bits:
@@ -398,96 +374,36 @@
 };
 
 
-GENERIC_EVENT_ATTR(cpu-cycles,			CYC);
-GENERIC_EVENT_ATTR(stalled-cycles-frontend,	GCT_NOSLOT_CYC);
-GENERIC_EVENT_ATTR(stalled-cycles-backend,	CMPLU_STALL);
-GENERIC_EVENT_ATTR(instructions,		INST_CMPL);
-GENERIC_EVENT_ATTR(cache-references,		LD_REF_L1);
-GENERIC_EVENT_ATTR(cache-misses,		LD_MISS_L1);
-GENERIC_EVENT_ATTR(branch-instructions,		BRU_FIN);
-GENERIC_EVENT_ATTR(branch-misses,		BR_MPRED);
+GENERIC_EVENT_ATTR(cpu-cycles,			PM_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-frontend,	PM_GCT_NOSLOT_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-backend,	PM_CMPLU_STALL);
+GENERIC_EVENT_ATTR(instructions,		PM_INST_CMPL);
+GENERIC_EVENT_ATTR(cache-references,		PM_LD_REF_L1);
+GENERIC_EVENT_ATTR(cache-misses,		PM_LD_MISS_L1);
+GENERIC_EVENT_ATTR(branch-instructions,		PM_BRU_FIN);
+GENERIC_EVENT_ATTR(branch-misses,		PM_BR_MPRED);
 
-POWER_EVENT_ATTR(CYC,				CYC);
-POWER_EVENT_ATTR(GCT_NOSLOT_CYC,		GCT_NOSLOT_CYC);
-POWER_EVENT_ATTR(CMPLU_STALL,			CMPLU_STALL);
-POWER_EVENT_ATTR(INST_CMPL,			INST_CMPL);
-POWER_EVENT_ATTR(LD_REF_L1,			LD_REF_L1);
-POWER_EVENT_ATTR(LD_MISS_L1,			LD_MISS_L1);
-POWER_EVENT_ATTR(BRU_FIN,			BRU_FIN)
-POWER_EVENT_ATTR(BR_MPRED,			BR_MPRED);
+#define EVENT(_name, _code)     POWER_EVENT_ATTR(_name, _name);
+#include "power7-events-list.h"
+#undef EVENT
 
-POWER_EVENT_ATTR(CMPLU_STALL_FXU,		CMPLU_STALL_FXU);
-POWER_EVENT_ATTR(CMPLU_STALL_DIV,		CMPLU_STALL_DIV);
-POWER_EVENT_ATTR(CMPLU_STALL_SCALAR,		CMPLU_STALL_SCALAR);
-POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG,	CMPLU_STALL_SCALAR_LONG);
-POWER_EVENT_ATTR(CMPLU_STALL_VECTOR,		CMPLU_STALL_VECTOR);
-POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG,	CMPLU_STALL_VECTOR_LONG);
-POWER_EVENT_ATTR(CMPLU_STALL_LSU,		CMPLU_STALL_LSU);
-POWER_EVENT_ATTR(CMPLU_STALL_REJECT,		CMPLU_STALL_REJECT);
-
-POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS,		CMPLU_STALL_ERAT_MISS);
-POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS,	CMPLU_STALL_DCACHE_MISS);
-POWER_EVENT_ATTR(CMPLU_STALL_STORE,		CMPLU_STALL_STORE);
-POWER_EVENT_ATTR(CMPLU_STALL_THRD,		CMPLU_STALL_THRD);
-POWER_EVENT_ATTR(CMPLU_STALL_IFU,		CMPLU_STALL_IFU);
-POWER_EVENT_ATTR(CMPLU_STALL_BRU,		CMPLU_STALL_BRU);
-POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS,		GCT_NOSLOT_IC_MISS);
-
-POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED,		GCT_NOSLOT_BR_MPRED);
-POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS,	GCT_NOSLOT_BR_MPRED_IC_MISS);
-POWER_EVENT_ATTR(GRP_CMPL,			GRP_CMPL);
-POWER_EVENT_ATTR(1PLUS_PPC_CMPL,		1PLUS_PPC_CMPL);
-POWER_EVENT_ATTR(CMPLU_STALL_DFU,		CMPLU_STALL_DFU);
-POWER_EVENT_ATTR(RUN_CYC,			RUN_CYC);
-POWER_EVENT_ATTR(RUN_INST_CMPL,			RUN_INST_CMPL);
+#define EVENT(_name, _code)     POWER_EVENT_PTR(_name),
 
 static struct attribute *power7_events_attr[] = {
-	GENERIC_EVENT_PTR(CYC),
-	GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
-	GENERIC_EVENT_PTR(CMPLU_STALL),
-	GENERIC_EVENT_PTR(INST_CMPL),
-	GENERIC_EVENT_PTR(LD_REF_L1),
-	GENERIC_EVENT_PTR(LD_MISS_L1),
-	GENERIC_EVENT_PTR(BRU_FIN),
-	GENERIC_EVENT_PTR(BR_MPRED),
+	GENERIC_EVENT_PTR(PM_CYC),
+	GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
+	GENERIC_EVENT_PTR(PM_CMPLU_STALL),
+	GENERIC_EVENT_PTR(PM_INST_CMPL),
+	GENERIC_EVENT_PTR(PM_LD_REF_L1),
+	GENERIC_EVENT_PTR(PM_LD_MISS_L1),
+	GENERIC_EVENT_PTR(PM_BRU_FIN),
+	GENERIC_EVENT_PTR(PM_BR_MPRED),
 
-	POWER_EVENT_PTR(CYC),
-	POWER_EVENT_PTR(GCT_NOSLOT_CYC),
-	POWER_EVENT_PTR(CMPLU_STALL),
-	POWER_EVENT_PTR(INST_CMPL),
-	POWER_EVENT_PTR(LD_REF_L1),
-	POWER_EVENT_PTR(LD_MISS_L1),
-	POWER_EVENT_PTR(BRU_FIN),
-	POWER_EVENT_PTR(BR_MPRED),
-
-	POWER_EVENT_PTR(CMPLU_STALL_FXU),
-	POWER_EVENT_PTR(CMPLU_STALL_DIV),
-	POWER_EVENT_PTR(CMPLU_STALL_SCALAR),
-	POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG),
-	POWER_EVENT_PTR(CMPLU_STALL_VECTOR),
-	POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG),
-	POWER_EVENT_PTR(CMPLU_STALL_LSU),
-	POWER_EVENT_PTR(CMPLU_STALL_REJECT),
-
-	POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS),
-	POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS),
-	POWER_EVENT_PTR(CMPLU_STALL_STORE),
-	POWER_EVENT_PTR(CMPLU_STALL_THRD),
-	POWER_EVENT_PTR(CMPLU_STALL_IFU),
-	POWER_EVENT_PTR(CMPLU_STALL_BRU),
-	POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS),
-	POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED),
-
-	POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS),
-	POWER_EVENT_PTR(GRP_CMPL),
-	POWER_EVENT_PTR(1PLUS_PPC_CMPL),
-	POWER_EVENT_PTR(CMPLU_STALL_DFU),
-	POWER_EVENT_PTR(RUN_CYC),
-	POWER_EVENT_PTR(RUN_INST_CMPL),
+	#include "power7-events-list.h"
+	#undef EVENT
 	NULL
 };
 
-
 static struct attribute_group power7_pmu_events_group = {
 	.name = "events",
 	.attrs = power7_events_attr,
diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c
index cba1e6b..ce73ce8 100644
--- a/arch/powerpc/platforms/ps3/time.c
+++ b/arch/powerpc/platforms/ps3/time.c
@@ -90,7 +90,7 @@
 
 	pdev = platform_device_register_simple("rtc-ps3", -1, NULL, 0);
 
-	return PTR_RET(pdev);
+	return PTR_ERR_OR_ZERO(pdev);
 }
 
 module_init(ps3_rtc_init);
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 6a5f2b1..d276cd3 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -539,36 +539,6 @@
 }
 
 #ifdef CONFIG_PSTORE
-/* Derived from logfs_uncompress */
-int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
-{
-	int err, ret;
-
-	ret = -EIO;
-	err = zlib_inflateInit(&stream);
-	if (err != Z_OK)
-		goto error;
-
-	stream.next_in = in;
-	stream.avail_in = inlen;
-	stream.total_in = 0;
-	stream.next_out = out;
-	stream.avail_out = outlen;
-	stream.total_out = 0;
-
-	err = zlib_inflate(&stream, Z_FINISH);
-	if (err != Z_STREAM_END)
-		goto error;
-
-	err = zlib_inflateEnd(&stream);
-	if (err != Z_OK)
-		goto error;
-
-	ret = stream.total_out;
-error:
-	return ret;
-}
-
 static int nvram_pstore_open(struct pstore_info *psi)
 {
 	/* Reset the iterator to start reading partitions again */
@@ -584,7 +554,7 @@
  * @part:               pstore writes data to registered buffer in parts,
  *                      part number will indicate the same.
  * @count:              Indicates oops count
- * @hsize:              Size of header added by pstore
+ * @compressed:         Flag to indicate the log is compressed
  * @size:               number of bytes written to the registered buffer
  * @psi:                registered pstore_info structure
  *
@@ -595,7 +565,7 @@
 static int nvram_pstore_write(enum pstore_type_id type,
 				enum kmsg_dump_reason reason,
 				u64 *id, unsigned int part, int count,
-				size_t hsize, size_t size,
+				bool compressed, size_t size,
 				struct pstore_info *psi)
 {
 	int rc;
@@ -611,30 +581,11 @@
 	oops_hdr->report_length = (u16) size;
 	oops_hdr->timestamp = get_seconds();
 
-	if (big_oops_buf) {
-		rc = zip_oops(size);
-		/*
-		 * If compression fails copy recent log messages from
-		 * big_oops_buf to oops_data.
-		 */
-		if (rc != 0) {
-			size_t diff = size - oops_data_sz + hsize;
-
-			if (size > oops_data_sz) {
-				memcpy(oops_data, big_oops_buf, hsize);
-				memcpy(oops_data + hsize, big_oops_buf + diff,
-					oops_data_sz - hsize);
-
-				oops_hdr->report_length = (u16) oops_data_sz;
-			} else
-				memcpy(oops_data, big_oops_buf, size);
-		} else
-			err_type = ERR_TYPE_KERNEL_PANIC_GZ;
-	}
+	if (compressed)
+		err_type = ERR_TYPE_KERNEL_PANIC_GZ;
 
 	rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
-		(int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
-		count);
+		(int) (sizeof(*oops_hdr) + size), err_type, count);
 
 	if (rc != 0)
 		return rc;
@@ -650,12 +601,12 @@
  */
 static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
 				int *count, struct timespec *time, char **buf,
-				struct pstore_info *psi)
+				bool *compressed, struct pstore_info *psi)
 {
 	struct oops_log_info *oops_hdr;
 	unsigned int err_type, id_no, size = 0;
 	struct nvram_os_partition *part = NULL;
-	char *buff = NULL, *big_buff = NULL;
+	char *buff = NULL;
 	int sig = 0;
 	loff_t p;
 
@@ -719,8 +670,7 @@
 		*id = id_no;
 
 	if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
-		int length, unzipped_len;
-		size_t hdr_size;
+		size_t length, hdr_size;
 
 		oops_hdr = (struct oops_log_info *)buff;
 		if (oops_hdr->version < OOPS_HDR_VERSION) {
@@ -741,23 +691,10 @@
 		memcpy(*buf, buff + hdr_size, length);
 		kfree(buff);
 
-		if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
-			big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
-			if (!big_buff)
-				return -ENOMEM;
-
-			unzipped_len = nvram_decompress(*buf, big_buff,
-						length, big_oops_buf_sz);
-
-			if (unzipped_len < 0) {
-				pr_err("nvram: decompression failed, returned "
-					"rc %d\n", unzipped_len);
-				kfree(big_buff);
-			} else {
-				*buf = big_buff;
-				length = unzipped_len;
-			}
-		}
+		if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
+			*compressed = true;
+		else
+			*compressed = false;
 		return length;
 	}
 
@@ -777,13 +714,8 @@
 {
 	int rc = 0;
 
-	if (big_oops_buf) {
-		nvram_pstore_info.buf = big_oops_buf;
-		nvram_pstore_info.bufsize = big_oops_buf_sz;
-	} else {
-		nvram_pstore_info.buf = oops_data;
-		nvram_pstore_info.bufsize = oops_data_sz;
-	}
+	nvram_pstore_info.buf = oops_data;
+	nvram_pstore_info.bufsize = oops_data_sz;
 
 	rc = pstore_register(&nvram_pstore_info);
 	if (rc != 0)
@@ -802,7 +734,6 @@
 static void __init nvram_init_oops_partition(int rtas_partition_exists)
 {
 	int rc;
-	size_t size;
 
 	rc = pseries_nvram_init_os_partition(&oops_log_partition);
 	if (rc != 0) {
@@ -823,6 +754,11 @@
 	oops_data = oops_buf + sizeof(struct oops_log_info);
 	oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
 
+	rc = nvram_pstore_init();
+
+	if (!rc)
+		return;
+
 	/*
 	 * Figure compression (preceded by elimination of each line's <n>
 	 * severity prefix) will reduce the oops/panic report to at most
@@ -831,9 +767,8 @@
 	big_oops_buf_sz = (oops_data_sz * 100) / 45;
 	big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
 	if (big_oops_buf) {
-		size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
-			zlib_inflate_workspacesize());
-		stream.workspace = kmalloc(size, GFP_KERNEL);
+		stream.workspace =  kmalloc(zlib_deflate_workspacesize(
+					WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
 		if (!stream.workspace) {
 			pr_err("nvram: No memory for compression workspace; "
 				"skipping compression of %s partition data\n",
@@ -847,11 +782,6 @@
 		stream.workspace = NULL;
 	}
 
-	rc = nvram_pstore_init();
-
-	if (!rc)
-		return;
-
 	rc = kmsg_dump_register(&nvram_kmsg_dumper);
 	if (rc != 0) {
 		pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c
index af79e1e..af0f9be 100644
--- a/arch/powerpc/sysdev/rtc_cmos_setup.c
+++ b/arch/powerpc/sysdev/rtc_cmos_setup.c
@@ -62,7 +62,7 @@
 	pd = platform_device_register_simple("rtc_cmos", -1,
 					     &res[0], num_res);
 
-	return PTR_RET(pd);
+	return PTR_ERR_OR_ZERO(pd);
 }
 fs_initcall(add_rtc);
 
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8a4cae7..8b7892bf6 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -116,6 +116,7 @@
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	select HAVE_GENERIC_HARDIRQS
 	select HAVE_KERNEL_BZIP2
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZ4
@@ -445,6 +446,16 @@
 	  This allows you to specify the maximum number of PCI functions which
 	  this kernel will support.
 
+config PCI_NR_MSI
+	int "Maximum number of MSI interrupts (64-32768)"
+	range 64 32768
+	default "256"
+	help
+	  This defines the number of virtual interrupts the kernel will
+	  provide for MSI interrupts. If you configure your system to have
+	  too few drivers will fail to allocate MSI interrupts for all
+	  PCI devices.
+
 source "drivers/pci/Kconfig"
 source "drivers/pci/pcie/Kconfig"
 source "drivers/pci/hotplug/Kconfig"
diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c
index bb5dd49..17ab8b7 100644
--- a/arch/s390/hypfs/hypfs_dbfs.c
+++ b/arch/s390/hypfs/hypfs_dbfs.c
@@ -105,7 +105,7 @@
 int hypfs_dbfs_init(void)
 {
 	dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
-	return PTR_RET(dbfs_dir);
+	return PTR_ERR_OR_ZERO(dbfs_dir);
 }
 
 void hypfs_dbfs_exit(void)
diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h
index 4066cee..4bbb595 100644
--- a/arch/s390/include/asm/airq.h
+++ b/arch/s390/include/asm/airq.h
@@ -9,6 +9,8 @@
 #ifndef _ASM_S390_AIRQ_H
 #define _ASM_S390_AIRQ_H
 
+#include <linux/bit_spinlock.h>
+
 struct airq_struct {
 	struct hlist_node list;		/* Handler queueing. */
 	void (*handler)(struct airq_struct *);	/* Thin-interrupt handler */
@@ -23,4 +25,69 @@
 int register_adapter_interrupt(struct airq_struct *airq);
 void unregister_adapter_interrupt(struct airq_struct *airq);
 
+/* Adapter interrupt bit vector */
+struct airq_iv {
+	unsigned long *vector;	/* Adapter interrupt bit vector */
+	unsigned long *avail;	/* Allocation bit mask for the bit vector */
+	unsigned long *bitlock;	/* Lock bit mask for the bit vector */
+	unsigned long *ptr;	/* Pointer associated with each bit */
+	unsigned int *data;	/* 32 bit value associated with each bit */
+	unsigned long bits;	/* Number of bits in the vector */
+	unsigned long end;	/* Number of highest allocated bit + 1 */
+	spinlock_t lock;	/* Lock to protect alloc & free */
+};
+
+#define AIRQ_IV_ALLOC	1	/* Use an allocation bit mask */
+#define AIRQ_IV_BITLOCK	2	/* Allocate the lock bit mask */
+#define AIRQ_IV_PTR	4	/* Allocate the ptr array */
+#define AIRQ_IV_DATA	8	/* Allocate the data array */
+
+struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags);
+void airq_iv_release(struct airq_iv *iv);
+unsigned long airq_iv_alloc_bit(struct airq_iv *iv);
+void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit);
+unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
+			   unsigned long end);
+
+static inline unsigned long airq_iv_end(struct airq_iv *iv)
+{
+	return iv->end;
+}
+
+static inline void airq_iv_lock(struct airq_iv *iv, unsigned long bit)
+{
+	const unsigned long be_to_le = BITS_PER_LONG - 1;
+	bit_spin_lock(bit ^ be_to_le, iv->bitlock);
+}
+
+static inline void airq_iv_unlock(struct airq_iv *iv, unsigned long bit)
+{
+	const unsigned long be_to_le = BITS_PER_LONG - 1;
+	bit_spin_unlock(bit ^ be_to_le, iv->bitlock);
+}
+
+static inline void airq_iv_set_data(struct airq_iv *iv, unsigned long bit,
+				    unsigned int data)
+{
+	iv->data[bit] = data;
+}
+
+static inline unsigned int airq_iv_get_data(struct airq_iv *iv,
+					    unsigned long bit)
+{
+	return iv->data[bit];
+}
+
+static inline void airq_iv_set_ptr(struct airq_iv *iv, unsigned long bit,
+				   unsigned long ptr)
+{
+	iv->ptr[bit] = ptr;
+}
+
+static inline unsigned long airq_iv_get_ptr(struct airq_iv *iv,
+					    unsigned long bit)
+{
+	return iv->ptr[bit];
+}
+
 #endif /* _ASM_S390_AIRQ_H */
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index 7d46767..10135a3 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -216,7 +216,7 @@
 	addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
 	asm volatile(
 		"	oc	%O0(1,%R0),%1"
-		: "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" );
+		: "+Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc");
 }
 
 static inline void 
@@ -244,7 +244,7 @@
 	addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
 	asm volatile(
 		"	nc	%O0(1,%R0),%1"
-		: "=Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) : "cc" );
+		: "+Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) : "cc");
 }
 
 static inline void 
@@ -271,7 +271,7 @@
 	addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
 	asm volatile(
 		"	xc	%O0(1,%R0),%1"
-		: "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" );
+		: "+Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc");
 }
 
 static inline void 
@@ -301,7 +301,7 @@
 	ch = *(unsigned char *) addr;
 	asm volatile(
 		"	oc	%O0(1,%R0),%1"
-		: "=Q" (*(char *) addr)	: "Q" (_oi_bitmap[nr & 7])
+		: "+Q" (*(char *) addr)	: "Q" (_oi_bitmap[nr & 7])
 		: "cc", "memory");
 	return (ch >> (nr & 7)) & 1;
 }
@@ -320,7 +320,7 @@
 	ch = *(unsigned char *) addr;
 	asm volatile(
 		"	nc	%O0(1,%R0),%1"
-		: "=Q" (*(char *) addr)	: "Q" (_ni_bitmap[nr & 7])
+		: "+Q" (*(char *) addr)	: "Q" (_ni_bitmap[nr & 7])
 		: "cc", "memory");
 	return (ch >> (nr & 7)) & 1;
 }
@@ -339,7 +339,7 @@
 	ch = *(unsigned char *) addr;
 	asm volatile(
 		"	xc	%O0(1,%R0),%1"
-		: "=Q" (*(char *) addr)	: "Q" (_oi_bitmap[nr & 7])
+		: "+Q" (*(char *) addr)	: "Q" (_oi_bitmap[nr & 7])
 		: "cc", "memory");
 	return (ch >> (nr & 7)) & 1;
 }
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index ffb8989..d426250 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -296,6 +296,7 @@
 	return 0;
 }
 
+void channel_subsystem_reinit(void);
 extern void css_schedule_reprobe(void);
 
 extern void reipl_ccw_dev(struct ccw_dev_id *id);
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h
index d2ff4137..f65bd36 100644
--- a/arch/s390/include/asm/cputime.h
+++ b/arch/s390/include/asm/cputime.h
@@ -13,9 +13,6 @@
 #include <asm/div64.h>
 
 
-#define __ARCH_HAS_VTIME_ACCOUNT
-#define __ARCH_HAS_VTIME_TASK_SWITCH
-
 /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
 
 typedef unsigned long long __nocast cputime_t;
diff --git a/arch/s390/include/asm/hardirq.h b/arch/s390/include/asm/hardirq.h
index 0c82ba8..a908d29 100644
--- a/arch/s390/include/asm/hardirq.h
+++ b/arch/s390/include/asm/hardirq.h
@@ -20,4 +20,9 @@
 
 #define HARDIRQ_BITS	8
 
+static inline void ack_bad_irq(unsigned int irq)
+{
+	printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+
 #endif /* __ASM_HARDIRQ_H */
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index bd90359..11eae5f 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -17,6 +17,9 @@
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 		     pte_t *ptep, pte_t pte);
+pte_t huge_ptep_get(pte_t *ptep);
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+			      unsigned long addr, pte_t *ptep);
 
 /*
  * If the arch doesn't supply something else, assume that hugepage
@@ -38,147 +41,75 @@
 int arch_prepare_hugepage(struct page *page);
 void arch_release_hugepage(struct page *page);
 
-static inline pte_t huge_pte_wrprotect(pte_t pte)
+static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
+				  pte_t *ptep)
 {
-	pte_val(pte) |= _PAGE_RO;
-	return pte;
+	pte_val(*ptep) = _SEGMENT_ENTRY_EMPTY;
 }
 
-static inline int huge_pte_none(pte_t pte)
-{
-	return (pte_val(pte) & _SEGMENT_ENTRY_INV) &&
-		!(pte_val(pte) & _SEGMENT_ENTRY_RO);
-}
-
-static inline pte_t huge_ptep_get(pte_t *ptep)
-{
-	pte_t pte = *ptep;
-	unsigned long mask;
-
-	if (!MACHINE_HAS_HPAGE) {
-		ptep = (pte_t *) (pte_val(pte) & _SEGMENT_ENTRY_ORIGIN);
-		if (ptep) {
-			mask = pte_val(pte) &
-				(_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
-			pte = pte_mkhuge(*ptep);
-			pte_val(pte) |= mask;
-		}
-	}
-	return pte;
-}
-
-static inline void __pmd_csp(pmd_t *pmdp)
-{
-	register unsigned long reg2 asm("2") = pmd_val(*pmdp);
-	register unsigned long reg3 asm("3") = pmd_val(*pmdp) |
-					       _SEGMENT_ENTRY_INV;
-	register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5;
-
-	asm volatile(
-		"	csp %1,%3"
-		: "=m" (*pmdp)
-		: "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc");
-}
-
-static inline void huge_ptep_invalidate(struct mm_struct *mm,
-					unsigned long address, pte_t *ptep)
-{
-	pmd_t *pmdp = (pmd_t *) ptep;
-
-	if (MACHINE_HAS_IDTE)
-		__pmd_idte(address, pmdp);
-	else
-		__pmd_csp(pmdp);
-	pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY;
-}
-
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
-					    unsigned long addr, pte_t *ptep)
-{
-	pte_t pte = huge_ptep_get(ptep);
-
-	huge_ptep_invalidate(mm, addr, ptep);
-	return pte;
-}
-
-#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
-({									    \
-	int __changed = !pte_same(huge_ptep_get(__ptep), __entry);	    \
-	if (__changed) {						    \
-		huge_ptep_invalidate((__vma)->vm_mm, __addr, __ptep);	    \
-		set_huge_pte_at((__vma)->vm_mm, __addr, __ptep, __entry);   \
-	}								    \
-	__changed;							    \
-})
-
-#define huge_ptep_set_wrprotect(__mm, __addr, __ptep)			\
-({									\
-	pte_t __pte = huge_ptep_get(__ptep);				\
-	if (huge_pte_write(__pte)) {					\
-		huge_ptep_invalidate(__mm, __addr, __ptep);		\
-		set_huge_pte_at(__mm, __addr, __ptep,			\
-				huge_pte_wrprotect(__pte));		\
-	}								\
-})
-
 static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
 					 unsigned long address, pte_t *ptep)
 {
-	huge_ptep_invalidate(vma->vm_mm, address, ptep);
+	huge_ptep_get_and_clear(vma->vm_mm, address, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+					     unsigned long addr, pte_t *ptep,
+					     pte_t pte, int dirty)
+{
+	int changed = !pte_same(huge_ptep_get(ptep), pte);
+	if (changed) {
+		huge_ptep_get_and_clear(vma->vm_mm, addr, ptep);
+		set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+	}
+	return changed;
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+					   unsigned long addr, pte_t *ptep)
+{
+	pte_t pte = huge_ptep_get_and_clear(mm, addr, ptep);
+	set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte));
 }
 
 static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
 {
-	pte_t pte;
-	pmd_t pmd;
+	return mk_pte(page, pgprot);
+}
 
-	pmd = mk_pmd_phys(page_to_phys(page), pgprot);
-	pte_val(pte) = pmd_val(pmd);
-	return pte;
+static inline int huge_pte_none(pte_t pte)
+{
+	return pte_none(pte);
 }
 
 static inline int huge_pte_write(pte_t pte)
 {
-	pmd_t pmd;
-
-	pmd_val(pmd) = pte_val(pte);
-	return pmd_write(pmd);
+	return pte_write(pte);
 }
 
 static inline int huge_pte_dirty(pte_t pte)
 {
-	/* No dirty bit in the segment table entry. */
-	return 0;
+	return pte_dirty(pte);
 }
 
 static inline pte_t huge_pte_mkwrite(pte_t pte)
 {
-	pmd_t pmd;
-
-	pmd_val(pmd) = pte_val(pte);
-	pte_val(pte) = pmd_val(pmd_mkwrite(pmd));
-	return pte;
+	return pte_mkwrite(pte);
 }
 
 static inline pte_t huge_pte_mkdirty(pte_t pte)
 {
-	/* No dirty bit in the segment table entry. */
-	return pte;
+	return pte_mkdirty(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+	return pte_wrprotect(pte);
 }
 
 static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pmd_t pmd;
-
-	pmd_val(pmd) = pte_val(pte);
-	pte_val(pte) = pmd_val(pmd_modify(pmd, newprot));
-	return pte;
-}
-
-static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
-				  pte_t *ptep)
-{
-	pmd_clear((pmd_t *) ptep);
+	return pte_modify(pte, newprot);
 }
 
 #endif /* _ASM_S390_HUGETLB_H */
diff --git a/arch/s390/include/asm/hw_irq.h b/arch/s390/include/asm/hw_irq.h
index 7e3d258..ee96a8b 100644
--- a/arch/s390/include/asm/hw_irq.h
+++ b/arch/s390/include/asm/hw_irq.h
@@ -4,19 +4,8 @@
 #include <linux/msi.h>
 #include <linux/pci.h>
 
-static inline struct msi_desc *irq_get_msi_desc(unsigned int irq)
-{
-	return __irq_get_msi_desc(irq);
-}
-
-/* Must be called with msi map lock held */
-static inline int irq_set_msi_desc(unsigned int irq, struct msi_desc *msi)
-{
-	if (!msi)
-		return -EINVAL;
-
-	msi->irq = irq;
-	return 0;
-}
+void __init init_airq_interrupts(void);
+void __init init_cio_interrupts(void);
+void __init init_ext_interrupts(void);
 
 #endif
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index 87c17bf..1eaa362 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -1,17 +1,28 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
+#define EXT_INTERRUPT	1
+#define IO_INTERRUPT	2
+#define THIN_INTERRUPT	3
+
+#define NR_IRQS_BASE	4
+
+#ifdef CONFIG_PCI_NR_MSI
+# define NR_IRQS	(NR_IRQS_BASE + CONFIG_PCI_NR_MSI)
+#else
+# define NR_IRQS	NR_IRQS_BASE
+#endif
+
+/* This number is used when no interrupt has been assigned */
+#define NO_IRQ		0
+
+#ifndef __ASSEMBLY__
+
 #include <linux/hardirq.h>
 #include <linux/percpu.h>
 #include <linux/cache.h>
 #include <linux/types.h>
 
-enum interruption_main_class {
-	EXTERNAL_INTERRUPT,
-	IO_INTERRUPT,
-	NR_IRQS
-};
-
 enum interruption_class {
 	IRQEXT_CLK,
 	IRQEXT_EXC,
@@ -72,14 +83,8 @@
 void measurement_alert_subclass_register(void);
 void measurement_alert_subclass_unregister(void);
 
-#ifdef CONFIG_LOCKDEP
-#  define disable_irq_nosync_lockdep(irq)	disable_irq_nosync(irq)
-#  define disable_irq_nosync_lockdep_irqsave(irq, flags) \
-						disable_irq_nosync(irq)
-#  define disable_irq_lockdep(irq)		disable_irq(irq)
-#  define enable_irq_lockdep(irq)		enable_irq(irq)
-#  define enable_irq_lockdep_irqrestore(irq, flags) \
-						enable_irq(irq)
-#endif
+#define irq_canonicalize(irq)  (irq)
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_IRQ_H */
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 3238d40..e87ecaa 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -274,6 +274,14 @@
 	int css_support;
 };
 
+#define KVM_HVA_ERR_BAD		(-1UL)
+#define KVM_HVA_ERR_RO_BAD	(-2UL)
+
+static inline bool kvm_is_error_hva(unsigned long addr)
+{
+	return IS_ERR_VALUE(addr);
+}
+
 extern int sie64a(struct kvm_s390_sie_block *, u64 *);
 extern char sie_exit;
 #endif
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h
index 6340178..ff132ac 100644
--- a/arch/s390/include/asm/mmu.h
+++ b/arch/s390/include/asm/mmu.h
@@ -12,8 +12,6 @@
 	unsigned long asce_bits;
 	unsigned long asce_limit;
 	unsigned long vdso_base;
-	/* Cloned contexts will be created with extended page tables. */
-	unsigned int alloc_pgste:1;
 	/* The mmu context has extended page tables. */
 	unsigned int has_pgste:1;
 } mm_context_t;
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 084e775..9f973d8 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -21,24 +21,7 @@
 #ifdef CONFIG_64BIT
 	mm->context.asce_bits |= _ASCE_TYPE_REGION3;
 #endif
-	if (current->mm && current->mm->context.alloc_pgste) {
-		/*
-		 * alloc_pgste indicates, that any NEW context will be created
-		 * with extended page tables. The old context is unchanged. The
-		 * page table allocation and the page table operations will
-		 * look at has_pgste to distinguish normal and extended page
-		 * tables. The only way to create extended page tables is to
-		 * set alloc_pgste and then create a new context (e.g. dup_mm).
-		 * The page table allocation is called after init_new_context
-		 * and if has_pgste is set, it will create extended page
-		 * tables.
-		 */
-		mm->context.has_pgste = 1;
-		mm->context.alloc_pgste = 1;
-	} else {
-		mm->context.has_pgste = 0;
-		mm->context.alloc_pgste = 0;
-	}
+	mm->context.has_pgste = 0;
 	mm->context.asce_limit = STACK_TOP_MAX;
 	crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
 	return 0;
@@ -77,8 +60,7 @@
 	WARN_ON(atomic_read(&prev->context.attach_count) < 0);
 	atomic_inc(&next->context.attach_count);
 	/* Check for TLBs not flushed yet */
-	if (next->context.flush_mm)
-		__tlb_flush_mm(next);
+	__tlb_flush_mm_lazy(next);
 }
 
 #define enter_lazy_tlb(mm,tsk)	do { } while (0)
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 5d64fb7..1e51f29 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -32,16 +32,6 @@
 
 void storage_key_init_range(unsigned long start, unsigned long end);
 
-static inline unsigned long pfmf(unsigned long function, unsigned long address)
-{
-	asm volatile(
-		"	.insn	rre,0xb9af0000,%[function],%[address]"
-		: [address] "+a" (address)
-		: [function] "d" (function)
-		: "memory");
-	return address;
-}
-
 static inline void clear_page(void *page)
 {
 	register unsigned long reg1 asm ("1") = 0;
@@ -150,15 +140,6 @@
 #define _PAGE_FP_BIT		0x08	/* HW fetch protection bit	*/
 #define _PAGE_ACC_BITS		0xf0	/* HW access control bits	*/
 
-/*
- * Test and clear referenced bit in storage key.
- */
-#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-static inline int page_test_and_clear_young(unsigned long pfn)
-{
-	return page_reset_referenced(pfn << PAGE_SHIFT);
-}
-
 struct page;
 void arch_free_page(struct page *page, int order);
 void arch_alloc_page(struct page *page, int order);
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 6e577ba..c290f13 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -6,6 +6,7 @@
 /* must be set before including pci_clp.h */
 #define PCI_BAR_COUNT	6
 
+#include <linux/pci.h>
 #include <asm-generic/pci.h>
 #include <asm-generic/pci-dma-compat.h>
 #include <asm/pci_clp.h>
@@ -53,14 +54,9 @@
 	atomic64_t unmapped_pages;
 } __packed __aligned(16);
 
-struct msi_map {
-	unsigned long irq;
-	struct msi_desc *msi;
-	struct hlist_node msi_chain;
-};
-
-#define ZPCI_NR_MSI_VECS	64
-#define ZPCI_MSI_MASK		(ZPCI_NR_MSI_VECS - 1)
+#define ZPCI_MSI_VEC_BITS	11
+#define ZPCI_MSI_VEC_MAX	(1 << ZPCI_MSI_VEC_BITS)
+#define ZPCI_MSI_VEC_MASK	(ZPCI_MSI_VEC_MAX - 1)
 
 enum zpci_state {
 	ZPCI_FN_STATE_RESERVED,
@@ -91,8 +87,7 @@
 
 	/* IRQ stuff */
 	u64		msi_addr;	/* MSI address */
-	struct zdev_irq_map *irq_map;
-	struct msi_map *msi_map[ZPCI_NR_MSI_VECS];
+	struct airq_iv *aibv;		/* adapter interrupt bit vector */
 	unsigned int	aisb;		/* number of the summary bit */
 
 	/* DMA stuff */
@@ -122,11 +117,6 @@
 	struct dentry	*debugfs_perf;
 };
 
-struct pci_hp_callback_ops {
-	int (*create_slot)	(struct zpci_dev *zdev);
-	void (*remove_slot)	(struct zpci_dev *zdev);
-};
-
 static inline bool zdev_enabled(struct zpci_dev *zdev)
 {
 	return (zdev->fh & (1UL << 31)) ? true : false;
@@ -146,32 +136,38 @@
 int zpci_unregister_ioat(struct zpci_dev *, u8);
 
 /* CLP */
-int clp_find_pci_devices(void);
+int clp_scan_pci_devices(void);
+int clp_rescan_pci_devices(void);
+int clp_rescan_pci_devices_simple(void);
 int clp_add_pci_device(u32, u32, int);
 int clp_enable_fh(struct zpci_dev *, u8);
 int clp_disable_fh(struct zpci_dev *);
 
-/* MSI */
-struct msi_desc *__irq_get_msi_desc(unsigned int);
-int zpci_msi_set_mask_bits(struct msi_desc *, u32, u32);
-int zpci_setup_msi_irq(struct zpci_dev *, struct msi_desc *, unsigned int, int);
-void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);
-int zpci_msihash_init(void);
-void zpci_msihash_exit(void);
-
 #ifdef CONFIG_PCI
 /* Error handling and recovery */
 void zpci_event_error(void *);
 void zpci_event_availability(void *);
+void zpci_rescan(void);
 #else /* CONFIG_PCI */
 static inline void zpci_event_error(void *e) {}
 static inline void zpci_event_availability(void *e) {}
+static inline void zpci_rescan(void) {}
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_HOTPLUG_PCI_S390
+int zpci_init_slot(struct zpci_dev *);
+void zpci_exit_slot(struct zpci_dev *);
+#else /* CONFIG_HOTPLUG_PCI_S390 */
+static inline int zpci_init_slot(struct zpci_dev *zdev)
+{
+	return 0;
+}
+static inline void zpci_exit_slot(struct zpci_dev *zdev) {}
+#endif /* CONFIG_HOTPLUG_PCI_S390 */
+
 /* Helpers */
 struct zpci_dev *get_zdev(struct pci_dev *);
 struct zpci_dev *get_zdev_by_fid(u32);
-bool zpci_fid_present(u32);
 
 /* sysfs */
 int zpci_sysfs_add_device(struct device *);
@@ -181,14 +177,6 @@
 int zpci_dma_init(void);
 void zpci_dma_exit(void);
 
-/* Hotplug */
-extern struct mutex zpci_list_lock;
-extern struct list_head zpci_list;
-extern unsigned int s390_pci_probe;
-
-void zpci_register_hp_ops(struct pci_hp_callback_ops *);
-void zpci_deregister_hp_ops(void);
-
 /* FMB */
 int zpci_fmb_enable_device(struct zpci_dev *);
 int zpci_fmb_disable_device(struct zpci_dev *);
diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
index e6a2bdd..df6eac9 100644
--- a/arch/s390/include/asm/pci_insn.h
+++ b/arch/s390/include/asm/pci_insn.h
@@ -79,11 +79,11 @@
 } __packed;
 
 
-int s390pci_mod_fc(u64 req, struct zpci_fib *fib);
-int s390pci_refresh_trans(u64 fn, u64 addr, u64 range);
-int s390pci_load(u64 *data, u64 req, u64 offset);
-int s390pci_store(u64 data, u64 req, u64 offset);
-int s390pci_store_block(const u64 *data, u64 req, u64 offset);
-void set_irq_ctrl(u16 ctl, char *unused, u8 isc);
+int zpci_mod_fc(u64 req, struct zpci_fib *fib);
+int zpci_refresh_trans(u64 fn, u64 addr, u64 range);
+int zpci_load(u64 *data, u64 req, u64 offset);
+int zpci_store(u64 data, u64 req, u64 offset);
+int zpci_store_block(const u64 *data, u64 req, u64 offset);
+void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc);
 
 #endif
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h
index 83a9caa..d194d54 100644
--- a/arch/s390/include/asm/pci_io.h
+++ b/arch/s390/include/asm/pci_io.h
@@ -36,7 +36,7 @@
 	u64 data;								\
 	int rc;									\
 										\
-	rc = s390pci_load(&data, req, ZPCI_OFFSET(addr));			\
+	rc = zpci_load(&data, req, ZPCI_OFFSET(addr));				\
 	if (rc)									\
 		data = -1ULL;							\
 	return (RETTYPE) data;							\
@@ -50,7 +50,7 @@
 	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH);		\
 	u64 data = (VALTYPE) val;						\
 										\
-	s390pci_store(data, req, ZPCI_OFFSET(addr));				\
+	zpci_store(data, req, ZPCI_OFFSET(addr));				\
 }
 
 zpci_read(8, u64)
@@ -83,7 +83,7 @@
 		val = 0;		/* let FW report error */
 		break;
 	}
-	return s390pci_store(val, req, offset);
+	return zpci_store(val, req, offset);
 }
 
 static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
@@ -91,7 +91,7 @@
 	u64 data;
 	int cc;
 
-	cc = s390pci_load(&data, req, offset);
+	cc = zpci_load(&data, req, offset);
 	if (cc)
 		goto out;
 
@@ -115,7 +115,7 @@
 
 static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
 {
-	return s390pci_store_block(data, req, offset);
+	return zpci_store_block(data, req, offset);
 }
 
 static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 75fb726..9b60a36 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -217,63 +217,57 @@
 
 /* Hardware bits in the page table entry */
 #define _PAGE_CO	0x100		/* HW Change-bit override */
-#define _PAGE_RO	0x200		/* HW read-only bit  */
+#define _PAGE_PROTECT	0x200		/* HW read-only bit  */
 #define _PAGE_INVALID	0x400		/* HW invalid bit    */
+#define _PAGE_LARGE	0x800		/* Bit to mark a large pte */
 
 /* Software bits in the page table entry */
-#define _PAGE_SWT	0x001		/* SW pte type bit t */
-#define _PAGE_SWX	0x002		/* SW pte type bit x */
-#define _PAGE_SWC	0x004		/* SW pte changed bit */
-#define _PAGE_SWR	0x008		/* SW pte referenced bit */
-#define _PAGE_SWW	0x010		/* SW pte write bit */
-#define _PAGE_SPECIAL	0x020		/* SW associated with special page */
+#define _PAGE_PRESENT	0x001		/* SW pte present bit */
+#define _PAGE_TYPE	0x002		/* SW pte type bit */
+#define _PAGE_YOUNG	0x004		/* SW pte young bit */
+#define _PAGE_DIRTY	0x008		/* SW pte dirty bit */
+#define _PAGE_READ	0x010		/* SW pte read bit */
+#define _PAGE_WRITE	0x020		/* SW pte write bit */
+#define _PAGE_SPECIAL	0x040		/* SW associated with special page */
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /* Set of bits not changed in pte_modify */
 #define _PAGE_CHG_MASK		(PAGE_MASK | _PAGE_SPECIAL | _PAGE_CO | \
-				 _PAGE_SWC | _PAGE_SWR)
-
-/* Six different types of pages. */
-#define _PAGE_TYPE_EMPTY	0x400
-#define _PAGE_TYPE_NONE		0x401
-#define _PAGE_TYPE_SWAP		0x403
-#define _PAGE_TYPE_FILE		0x601	/* bit 0x002 is used for offset !! */
-#define _PAGE_TYPE_RO		0x200
-#define _PAGE_TYPE_RW		0x000
+				 _PAGE_DIRTY | _PAGE_YOUNG)
 
 /*
- * Only four types for huge pages, using the invalid bit and protection bit
- * of a segment table entry.
- */
-#define _HPAGE_TYPE_EMPTY	0x020	/* _SEGMENT_ENTRY_INV */
-#define _HPAGE_TYPE_NONE	0x220
-#define _HPAGE_TYPE_RO		0x200	/* _SEGMENT_ENTRY_RO  */
-#define _HPAGE_TYPE_RW		0x000
-
-/*
- * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
- * pte_none and pte_file to find out the pte type WITHOUT holding the page
- * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to
- * invalidate a given pte. ipte sets the hw invalid bit and clears all tlbs
- * for the page. The page table entry is set to _PAGE_TYPE_EMPTY afterwards.
- * This change is done while holding the lock, but the intermediate step
- * of a previously valid pte with the hw invalid bit set can be observed by
- * handle_pte_fault. That makes it necessary that all valid pte types with
- * the hw invalid bit set must be distinguishable from the four pte types
- * empty, none, swap and file.
+ * handle_pte_fault uses pte_present, pte_none and pte_file to find out the
+ * pte type WITHOUT holding the page table lock. The _PAGE_PRESENT bit
+ * is used to distinguish present from not-present ptes. It is changed only
+ * with the page table lock held.
  *
- *			irxt  ipte  irxt
- * _PAGE_TYPE_EMPTY	1000   ->   1000
- * _PAGE_TYPE_NONE	1001   ->   1001
- * _PAGE_TYPE_SWAP	1011   ->   1011
- * _PAGE_TYPE_FILE	11?1   ->   11?1
- * _PAGE_TYPE_RO	0100   ->   1100
- * _PAGE_TYPE_RW	0000   ->   1000
+ * The following table gives the different possible bit combinations for
+ * the pte hardware and software bits in the last 12 bits of a pte:
  *
- * pte_none is true for bits combinations 1000, 1010, 1100, 1110
- * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
- * pte_file is true for bits combinations 1101, 1111
- * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
+ *				842100000000
+ *				000084210000
+ *				000000008421
+ *				.IR...wrdytp
+ * empty			.10...000000
+ * swap				.10...xxxx10
+ * file				.11...xxxxx0
+ * prot-none, clean, old	.11...000001
+ * prot-none, clean, young	.11...000101
+ * prot-none, dirty, old	.10...001001
+ * prot-none, dirty, young	.10...001101
+ * read-only, clean, old	.11...010001
+ * read-only, clean, young	.01...010101
+ * read-only, dirty, old	.11...011001
+ * read-only, dirty, young	.01...011101
+ * read-write, clean, old	.11...110001
+ * read-write, clean, young	.01...110101
+ * read-write, dirty, old	.10...111001
+ * read-write, dirty, young	.00...111101
+ *
+ * pte_present is true for the bit pattern .xx...xxxxx1, (pte & 0x001) == 0x001
+ * pte_none    is true for the bit pattern .10...xxxx00, (pte & 0x603) == 0x400
+ * pte_file    is true for the bit pattern .11...xxxxx0, (pte & 0x601) == 0x600
+ * pte_swap    is true for the bit pattern .10...xxxx10, (pte & 0x603) == 0x402
  */
 
 #ifndef CONFIG_64BIT
@@ -286,14 +280,25 @@
 #define _ASCE_TABLE_LENGTH	0x7f	/* 128 x 64 entries = 8k	    */
 
 /* Bits in the segment table entry */
+#define _SEGMENT_ENTRY_BITS	0x7fffffffUL	/* Valid segment table bits */
 #define _SEGMENT_ENTRY_ORIGIN	0x7fffffc0UL	/* page table origin	    */
-#define _SEGMENT_ENTRY_RO	0x200	/* page protection bit		    */
-#define _SEGMENT_ENTRY_INV	0x20	/* invalid segment table entry	    */
+#define _SEGMENT_ENTRY_PROTECT	0x200	/* page protection bit		    */
+#define _SEGMENT_ENTRY_INVALID	0x20	/* invalid segment table entry	    */
 #define _SEGMENT_ENTRY_COMMON	0x10	/* common segment bit		    */
 #define _SEGMENT_ENTRY_PTL	0x0f	/* page table length		    */
+#define _SEGMENT_ENTRY_NONE	_SEGMENT_ENTRY_PROTECT
 
 #define _SEGMENT_ENTRY		(_SEGMENT_ENTRY_PTL)
-#define _SEGMENT_ENTRY_EMPTY	(_SEGMENT_ENTRY_INV)
+#define _SEGMENT_ENTRY_EMPTY	(_SEGMENT_ENTRY_INVALID)
+
+/*
+ * Segment table entry encoding (I = invalid, R = read-only bit):
+ *		..R...I.....
+ * prot-none	..1...1.....
+ * read-only	..1...0.....
+ * read-write	..0...0.....
+ * empty	..0...1.....
+ */
 
 /* Page status table bits for virtualization */
 #define PGSTE_ACC_BITS	0xf0000000UL
@@ -303,9 +308,7 @@
 #define PGSTE_HC_BIT	0x00200000UL
 #define PGSTE_GR_BIT	0x00040000UL
 #define PGSTE_GC_BIT	0x00020000UL
-#define PGSTE_UR_BIT	0x00008000UL
-#define PGSTE_UC_BIT	0x00004000UL	/* user dirty (migration) */
-#define PGSTE_IN_BIT	0x00002000UL	/* IPTE notify bit */
+#define PGSTE_IN_BIT	0x00008000UL	/* IPTE notify bit */
 
 #else /* CONFIG_64BIT */
 
@@ -324,8 +327,8 @@
 
 /* Bits in the region table entry */
 #define _REGION_ENTRY_ORIGIN	~0xfffUL/* region/segment table origin	    */
-#define _REGION_ENTRY_RO	0x200	/* region protection bit	    */
-#define _REGION_ENTRY_INV	0x20	/* invalid region table entry	    */
+#define _REGION_ENTRY_PROTECT	0x200	/* region protection bit	    */
+#define _REGION_ENTRY_INVALID	0x20	/* invalid region table entry	    */
 #define _REGION_ENTRY_TYPE_MASK	0x0c	/* region/segment table type mask   */
 #define _REGION_ENTRY_TYPE_R1	0x0c	/* region first table type	    */
 #define _REGION_ENTRY_TYPE_R2	0x08	/* region second table type	    */
@@ -333,29 +336,47 @@
 #define _REGION_ENTRY_LENGTH	0x03	/* region third length		    */
 
 #define _REGION1_ENTRY		(_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_LENGTH)
-#define _REGION1_ENTRY_EMPTY	(_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INV)
+#define _REGION1_ENTRY_EMPTY	(_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID)
 #define _REGION2_ENTRY		(_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_LENGTH)
-#define _REGION2_ENTRY_EMPTY	(_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INV)
+#define _REGION2_ENTRY_EMPTY	(_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID)
 #define _REGION3_ENTRY		(_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
-#define _REGION3_ENTRY_EMPTY	(_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV)
+#define _REGION3_ENTRY_EMPTY	(_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID)
 
 #define _REGION3_ENTRY_LARGE	0x400	/* RTTE-format control, large page  */
 #define _REGION3_ENTRY_RO	0x200	/* page protection bit		    */
 #define _REGION3_ENTRY_CO	0x100	/* change-recording override	    */
 
 /* Bits in the segment table entry */
+#define _SEGMENT_ENTRY_BITS	0xfffffffffffffe33UL
+#define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff1ff33UL
 #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address	    */
 #define _SEGMENT_ENTRY_ORIGIN	~0x7ffUL/* segment table origin		    */
-#define _SEGMENT_ENTRY_RO	0x200	/* page protection bit		    */
-#define _SEGMENT_ENTRY_INV	0x20	/* invalid segment table entry	    */
+#define _SEGMENT_ENTRY_PROTECT	0x200	/* page protection bit		    */
+#define _SEGMENT_ENTRY_INVALID	0x20	/* invalid segment table entry	    */
 
 #define _SEGMENT_ENTRY		(0)
-#define _SEGMENT_ENTRY_EMPTY	(_SEGMENT_ENTRY_INV)
+#define _SEGMENT_ENTRY_EMPTY	(_SEGMENT_ENTRY_INVALID)
 
 #define _SEGMENT_ENTRY_LARGE	0x400	/* STE-format control, large page   */
 #define _SEGMENT_ENTRY_CO	0x100	/* change-recording override   */
+#define _SEGMENT_ENTRY_SPLIT	0x001	/* THP splitting bit */
+#define _SEGMENT_ENTRY_YOUNG	0x002	/* SW segment young bit */
+#define _SEGMENT_ENTRY_NONE	_SEGMENT_ENTRY_YOUNG
+
+/*
+ * Segment table entry encoding (R = read-only, I = invalid, y = young bit):
+ *			..R...I...y.
+ * prot-none, old	..0...1...1.
+ * prot-none, young	..1...1...1.
+ * read-only, old	..1...1...0.
+ * read-only, young	..1...0...1.
+ * read-write, old	..0...1...0.
+ * read-write, young	..0...0...1.
+ * The segment table origin is used to distinguish empty (origin==0) from
+ * read-write, old segment table entries (origin!=0)
+ */
+
 #define _SEGMENT_ENTRY_SPLIT_BIT 0	/* THP splitting bit number */
-#define _SEGMENT_ENTRY_SPLIT	(1UL << _SEGMENT_ENTRY_SPLIT_BIT)
 
 /* Set of bits not changed in pmd_modify */
 #define _SEGMENT_CHG_MASK	(_SEGMENT_ENTRY_ORIGIN | _SEGMENT_ENTRY_LARGE \
@@ -369,9 +390,7 @@
 #define PGSTE_HC_BIT	0x0020000000000000UL
 #define PGSTE_GR_BIT	0x0004000000000000UL
 #define PGSTE_GC_BIT	0x0002000000000000UL
-#define PGSTE_UR_BIT	0x0000800000000000UL
-#define PGSTE_UC_BIT	0x0000400000000000UL	/* user dirty (migration) */
-#define PGSTE_IN_BIT	0x0000200000000000UL	/* IPTE notify bit */
+#define PGSTE_IN_BIT	0x0000800000000000UL	/* IPTE notify bit */
 
 #endif /* CONFIG_64BIT */
 
@@ -386,14 +405,18 @@
 /*
  * Page protection definitions.
  */
-#define PAGE_NONE	__pgprot(_PAGE_TYPE_NONE)
-#define PAGE_RO		__pgprot(_PAGE_TYPE_RO)
-#define PAGE_RW		__pgprot(_PAGE_TYPE_RO | _PAGE_SWW)
-#define PAGE_RWC	__pgprot(_PAGE_TYPE_RW | _PAGE_SWW | _PAGE_SWC)
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_INVALID)
+#define PAGE_READ	__pgprot(_PAGE_PRESENT | _PAGE_READ | \
+				 _PAGE_INVALID | _PAGE_PROTECT)
+#define PAGE_WRITE	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+				 _PAGE_INVALID | _PAGE_PROTECT)
 
-#define PAGE_KERNEL	PAGE_RWC
-#define PAGE_SHARED	PAGE_KERNEL
-#define PAGE_COPY	PAGE_RO
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+				 _PAGE_YOUNG | _PAGE_DIRTY)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+				 _PAGE_YOUNG | _PAGE_DIRTY)
+#define PAGE_KERNEL_RO	__pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_YOUNG | \
+				 _PAGE_PROTECT)
 
 /*
  * On s390 the page table entry has an invalid bit and a read-only bit.
@@ -402,35 +425,31 @@
  */
          /*xwr*/
 #define __P000	PAGE_NONE
-#define __P001	PAGE_RO
-#define __P010	PAGE_RO
-#define __P011	PAGE_RO
-#define __P100	PAGE_RO
-#define __P101	PAGE_RO
-#define __P110	PAGE_RO
-#define __P111	PAGE_RO
+#define __P001	PAGE_READ
+#define __P010	PAGE_READ
+#define __P011	PAGE_READ
+#define __P100	PAGE_READ
+#define __P101	PAGE_READ
+#define __P110	PAGE_READ
+#define __P111	PAGE_READ
 
 #define __S000	PAGE_NONE
-#define __S001	PAGE_RO
-#define __S010	PAGE_RW
-#define __S011	PAGE_RW
-#define __S100	PAGE_RO
-#define __S101	PAGE_RO
-#define __S110	PAGE_RW
-#define __S111	PAGE_RW
+#define __S001	PAGE_READ
+#define __S010	PAGE_WRITE
+#define __S011	PAGE_WRITE
+#define __S100	PAGE_READ
+#define __S101	PAGE_READ
+#define __S110	PAGE_WRITE
+#define __S111	PAGE_WRITE
 
 /*
  * Segment entry (large page) protection definitions.
  */
-#define SEGMENT_NONE	__pgprot(_HPAGE_TYPE_NONE)
-#define SEGMENT_RO	__pgprot(_HPAGE_TYPE_RO)
-#define SEGMENT_RW	__pgprot(_HPAGE_TYPE_RW)
-
-static inline int mm_exclusive(struct mm_struct *mm)
-{
-	return likely(mm == current->active_mm &&
-		      atomic_read(&mm->context.attach_count) <= 1);
-}
+#define SEGMENT_NONE	__pgprot(_SEGMENT_ENTRY_INVALID | \
+				 _SEGMENT_ENTRY_NONE)
+#define SEGMENT_READ	__pgprot(_SEGMENT_ENTRY_INVALID | \
+				 _SEGMENT_ENTRY_PROTECT)
+#define SEGMENT_WRITE	__pgprot(_SEGMENT_ENTRY_INVALID)
 
 static inline int mm_has_pgste(struct mm_struct *mm)
 {
@@ -467,7 +486,7 @@
 {
 	if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R2)
 		return 0;
-	return (pgd_val(pgd) & _REGION_ENTRY_INV) != 0UL;
+	return (pgd_val(pgd) & _REGION_ENTRY_INVALID) != 0UL;
 }
 
 static inline int pgd_bad(pgd_t pgd)
@@ -478,7 +497,7 @@
 	 * invalid for either table entry.
 	 */
 	unsigned long mask =
-		~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INV &
+		~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID &
 		~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
 	return (pgd_val(pgd) & mask) != 0;
 }
@@ -494,7 +513,7 @@
 {
 	if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3)
 		return 0;
-	return (pud_val(pud) & _REGION_ENTRY_INV) != 0UL;
+	return (pud_val(pud) & _REGION_ENTRY_INVALID) != 0UL;
 }
 
 static inline int pud_large(pud_t pud)
@@ -512,7 +531,7 @@
 	 * invalid for either table entry.
 	 */
 	unsigned long mask =
-		~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INV &
+		~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID &
 		~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
 	return (pud_val(pud) & mask) != 0;
 }
@@ -521,30 +540,36 @@
 
 static inline int pmd_present(pmd_t pmd)
 {
-	unsigned long mask = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO;
-	return (pmd_val(pmd) & mask) == _HPAGE_TYPE_NONE ||
-	       !(pmd_val(pmd) & _SEGMENT_ENTRY_INV);
+	return pmd_val(pmd) != _SEGMENT_ENTRY_INVALID;
 }
 
 static inline int pmd_none(pmd_t pmd)
 {
-	return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) &&
-	       !(pmd_val(pmd) & _SEGMENT_ENTRY_RO);
+	return pmd_val(pmd) == _SEGMENT_ENTRY_INVALID;
 }
 
 static inline int pmd_large(pmd_t pmd)
 {
 #ifdef CONFIG_64BIT
-	return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
+	return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0;
 #else
 	return 0;
 #endif
 }
 
+static inline int pmd_prot_none(pmd_t pmd)
+{
+	return (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) &&
+		(pmd_val(pmd) & _SEGMENT_ENTRY_NONE);
+}
+
 static inline int pmd_bad(pmd_t pmd)
 {
-	unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV;
-	return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY;
+#ifdef CONFIG_64BIT
+	if (pmd_large(pmd))
+		return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0;
+#endif
+	return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0;
 }
 
 #define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
@@ -563,31 +588,40 @@
 #define __HAVE_ARCH_PMD_WRITE
 static inline int pmd_write(pmd_t pmd)
 {
-	return (pmd_val(pmd) & _SEGMENT_ENTRY_RO) == 0;
+	if (pmd_prot_none(pmd))
+		return 0;
+	return (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) == 0;
 }
 
 static inline int pmd_young(pmd_t pmd)
 {
-	return 0;
-}
-
-static inline int pte_none(pte_t pte)
-{
-	return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
+	int young = 0;
+#ifdef CONFIG_64BIT
+	if (pmd_prot_none(pmd))
+		young = (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT) != 0;
+	else
+		young = (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0;
+#endif
+	return young;
 }
 
 static inline int pte_present(pte_t pte)
 {
-	unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT | _PAGE_SWX;
-	return (pte_val(pte) & mask) == _PAGE_TYPE_NONE ||
-		(!(pte_val(pte) & _PAGE_INVALID) &&
-		 !(pte_val(pte) & _PAGE_SWT));
+	/* Bit pattern: (pte & 0x001) == 0x001 */
+	return (pte_val(pte) & _PAGE_PRESENT) != 0;
+}
+
+static inline int pte_none(pte_t pte)
+{
+	/* Bit pattern: pte == 0x400 */
+	return pte_val(pte) == _PAGE_INVALID;
 }
 
 static inline int pte_file(pte_t pte)
 {
-	unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT;
-	return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
+	/* Bit pattern: (pte & 0x601) == 0x600 */
+	return (pte_val(pte) & (_PAGE_INVALID | _PAGE_PROTECT | _PAGE_PRESENT))
+		== (_PAGE_INVALID | _PAGE_PROTECT);
 }
 
 static inline int pte_special(pte_t pte)
@@ -634,6 +668,15 @@
 #endif
 }
 
+static inline pgste_t pgste_get(pte_t *ptep)
+{
+	unsigned long pgste = 0;
+#ifdef CONFIG_PGSTE
+	pgste = *(unsigned long *)(ptep + PTRS_PER_PTE);
+#endif
+	return __pgste(pgste);
+}
+
 static inline void pgste_set(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
@@ -644,33 +687,28 @@
 static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-	unsigned long address, bits;
-	unsigned char skey;
+	unsigned long address, bits, skey;
 
 	if (pte_val(*ptep) & _PAGE_INVALID)
 		return pgste;
 	address = pte_val(*ptep) & PAGE_MASK;
-	skey = page_get_storage_key(address);
+	skey = (unsigned long) page_get_storage_key(address);
 	bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
-	/* Clear page changed & referenced bit in the storage key */
-	if (bits & _PAGE_CHANGED)
+	if (!(pgste_val(pgste) & PGSTE_HC_BIT) && (bits & _PAGE_CHANGED)) {
+		/* Transfer dirty + referenced bit to host bits in pgste */
+		pgste_val(pgste) |= bits << 52;
 		page_set_storage_key(address, skey ^ bits, 0);
-	else if (bits)
+	} else if (!(pgste_val(pgste) & PGSTE_HR_BIT) &&
+		   (bits & _PAGE_REFERENCED)) {
+		/* Transfer referenced bit to host bit in pgste */
+		pgste_val(pgste) |= PGSTE_HR_BIT;
 		page_reset_referenced(address);
+	}
 	/* Transfer page changed & referenced bit to guest bits in pgste */
 	pgste_val(pgste) |= bits << 48;		/* GR bit & GC bit */
-	/* Get host changed & referenced bits from pgste */
-	bits |= (pgste_val(pgste) & (PGSTE_HR_BIT | PGSTE_HC_BIT)) >> 52;
-	/* Transfer page changed & referenced bit to kvm user bits */
-	pgste_val(pgste) |= bits << 45;		/* PGSTE_UR_BIT & PGSTE_UC_BIT */
-	/* Clear relevant host bits in pgste. */
-	pgste_val(pgste) &= ~(PGSTE_HR_BIT | PGSTE_HC_BIT);
-	pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
 	/* Copy page access key and fetch protection bit to pgste */
-	pgste_val(pgste) |=
-		(unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
-	/* Transfer referenced bit to pte */
-	pte_val(*ptep) |= (bits & _PAGE_REFERENCED) << 1;
+	pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
+	pgste_val(pgste) |= (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
 #endif
 	return pgste;
 
@@ -679,24 +717,11 @@
 static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-	int young;
-
 	if (pte_val(*ptep) & _PAGE_INVALID)
 		return pgste;
 	/* Get referenced bit from storage key */
-	young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
-	if (young)
-		pgste_val(pgste) |= PGSTE_GR_BIT;
-	/* Get host referenced bit from pgste */
-	if (pgste_val(pgste) & PGSTE_HR_BIT) {
-		pgste_val(pgste) &= ~PGSTE_HR_BIT;
-		young = 1;
-	}
-	/* Transfer referenced bit to kvm user bits and pte */
-	if (young) {
-		pgste_val(pgste) |= PGSTE_UR_BIT;
-		pte_val(*ptep) |= _PAGE_SWR;
-	}
+	if (page_reset_referenced(pte_val(*ptep) & PAGE_MASK))
+		pgste_val(pgste) |= PGSTE_HR_BIT | PGSTE_GR_BIT;
 #endif
 	return pgste;
 }
@@ -723,13 +748,13 @@
 
 static inline void pgste_set_pte(pte_t *ptep, pte_t entry)
 {
-	if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_SWW)) {
+	if (!MACHINE_HAS_ESOP && (pte_val(entry) & _PAGE_WRITE)) {
 		/*
 		 * Without enhanced suppression-on-protection force
 		 * the dirty bit on for all writable ptes.
 		 */
-		pte_val(entry) |= _PAGE_SWC;
-		pte_val(entry) &= ~_PAGE_RO;
+		pte_val(entry) |= _PAGE_DIRTY;
+		pte_val(entry) &= ~_PAGE_PROTECT;
 	}
 	*ptep = entry;
 }
@@ -841,21 +866,17 @@
  */
 static inline int pte_write(pte_t pte)
 {
-	return (pte_val(pte) & _PAGE_SWW) != 0;
+	return (pte_val(pte) & _PAGE_WRITE) != 0;
 }
 
 static inline int pte_dirty(pte_t pte)
 {
-	return (pte_val(pte) & _PAGE_SWC) != 0;
+	return (pte_val(pte) & _PAGE_DIRTY) != 0;
 }
 
 static inline int pte_young(pte_t pte)
 {
-#ifdef CONFIG_PGSTE
-	if (pte_val(pte) & _PAGE_SWR)
-		return 1;
-#endif
-	return 0;
+	return (pte_val(pte) & _PAGE_YOUNG) != 0;
 }
 
 /*
@@ -880,12 +901,12 @@
 
 static inline void pmd_clear(pmd_t *pmdp)
 {
-	pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
+	pmd_val(*pmdp) = _SEGMENT_ENTRY_INVALID;
 }
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+	pte_val(*ptep) = _PAGE_INVALID;
 }
 
 /*
@@ -896,55 +917,63 @@
 {
 	pte_val(pte) &= _PAGE_CHG_MASK;
 	pte_val(pte) |= pgprot_val(newprot);
-	if ((pte_val(pte) & _PAGE_SWC) && (pte_val(pte) & _PAGE_SWW))
-		pte_val(pte) &= ~_PAGE_RO;
+	/*
+	 * newprot for PAGE_NONE, PAGE_READ and PAGE_WRITE has the
+	 * invalid bit set, clear it again for readable, young pages
+	 */
+	if ((pte_val(pte) & _PAGE_YOUNG) && (pte_val(pte) & _PAGE_READ))
+		pte_val(pte) &= ~_PAGE_INVALID;
+	/*
+	 * newprot for PAGE_READ and PAGE_WRITE has the page protection
+	 * bit set, clear it again for writable, dirty pages
+	 */
+	if ((pte_val(pte) & _PAGE_DIRTY) && (pte_val(pte) & _PAGE_WRITE))
+		pte_val(pte) &= ~_PAGE_PROTECT;
 	return pte;
 }
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
-	pte_val(pte) &= ~_PAGE_SWW;
-	/* Do not clobber _PAGE_TYPE_NONE pages!  */
-	if (!(pte_val(pte) & _PAGE_INVALID))
-		pte_val(pte) |= _PAGE_RO;
+	pte_val(pte) &= ~_PAGE_WRITE;
+	pte_val(pte) |= _PAGE_PROTECT;
 	return pte;
 }
 
 static inline pte_t pte_mkwrite(pte_t pte)
 {
-	pte_val(pte) |= _PAGE_SWW;
-	if (pte_val(pte) & _PAGE_SWC)
-		pte_val(pte) &= ~_PAGE_RO;
+	pte_val(pte) |= _PAGE_WRITE;
+	if (pte_val(pte) & _PAGE_DIRTY)
+		pte_val(pte) &= ~_PAGE_PROTECT;
 	return pte;
 }
 
 static inline pte_t pte_mkclean(pte_t pte)
 {
-	pte_val(pte) &= ~_PAGE_SWC;
-	/* Do not clobber _PAGE_TYPE_NONE pages!  */
-	if (!(pte_val(pte) & _PAGE_INVALID))
-		pte_val(pte) |= _PAGE_RO;
+	pte_val(pte) &= ~_PAGE_DIRTY;
+	pte_val(pte) |= _PAGE_PROTECT;
 	return pte;
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
-	pte_val(pte) |= _PAGE_SWC;
-	if (pte_val(pte) & _PAGE_SWW)
-		pte_val(pte) &= ~_PAGE_RO;
+	pte_val(pte) |= _PAGE_DIRTY;
+	if (pte_val(pte) & _PAGE_WRITE)
+		pte_val(pte) &= ~_PAGE_PROTECT;
 	return pte;
 }
 
 static inline pte_t pte_mkold(pte_t pte)
 {
-#ifdef CONFIG_PGSTE
-	pte_val(pte) &= ~_PAGE_SWR;
-#endif
+	pte_val(pte) &= ~_PAGE_YOUNG;
+	pte_val(pte) |= _PAGE_INVALID;
 	return pte;
 }
 
 static inline pte_t pte_mkyoung(pte_t pte)
 {
+	pte_val(pte) |= _PAGE_YOUNG;
+	if (pte_val(pte) & _PAGE_READ)
+		pte_val(pte) &= ~_PAGE_INVALID;
 	return pte;
 }
 
@@ -957,7 +986,7 @@
 #ifdef CONFIG_HUGETLB_PAGE
 static inline pte_t pte_mkhuge(pte_t pte)
 {
-	pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
+	pte_val(pte) |= _PAGE_LARGE;
 	return pte;
 }
 #endif
@@ -974,8 +1003,8 @@
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_get_lock(ptep);
 		pgste = pgste_update_all(ptep, pgste);
-		dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT);
-		pgste_val(pgste) &= ~PGSTE_UC_BIT;
+		dirty = !!(pgste_val(pgste) & PGSTE_HC_BIT);
+		pgste_val(pgste) &= ~PGSTE_HC_BIT;
 		pgste_set_unlock(ptep, pgste);
 		return dirty;
 	}
@@ -994,42 +1023,13 @@
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_get_lock(ptep);
 		pgste = pgste_update_young(ptep, pgste);
-		young = !!(pgste_val(pgste) & PGSTE_UR_BIT);
-		pgste_val(pgste) &= ~PGSTE_UR_BIT;
+		young = !!(pgste_val(pgste) & PGSTE_HR_BIT);
+		pgste_val(pgste) &= ~PGSTE_HR_BIT;
 		pgste_set_unlock(ptep, pgste);
 	}
 	return young;
 }
 
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
-					    unsigned long addr, pte_t *ptep)
-{
-	pgste_t pgste;
-	pte_t pte;
-
-	if (mm_has_pgste(vma->vm_mm)) {
-		pgste = pgste_get_lock(ptep);
-		pgste = pgste_update_young(ptep, pgste);
-		pte = *ptep;
-		*ptep = pte_mkold(pte);
-		pgste_set_unlock(ptep, pgste);
-		return pte_young(pte);
-	}
-	return 0;
-}
-
-#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
-static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
-					 unsigned long address, pte_t *ptep)
-{
-	/* No need to flush TLB
-	 * On s390 reference bits are in storage key and never in TLB
-	 * With virtualization we handle the reference bit, without we
-	 * we can simply return */
-	return ptep_test_and_clear_young(vma, address, ptep);
-}
-
 static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
 {
 	if (!(pte_val(*ptep) & _PAGE_INVALID)) {
@@ -1047,6 +1047,51 @@
 	}
 }
 
+static inline void ptep_flush_lazy(struct mm_struct *mm,
+				   unsigned long address, pte_t *ptep)
+{
+	int active = (mm == current->active_mm) ? 1 : 0;
+
+	if (atomic_read(&mm->context.attach_count) > active)
+		__ptep_ipte(address, ptep);
+	else
+		mm->context.flush_mm = 1;
+}
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+					    unsigned long addr, pte_t *ptep)
+{
+	pgste_t pgste;
+	pte_t pte;
+	int young;
+
+	if (mm_has_pgste(vma->vm_mm)) {
+		pgste = pgste_get_lock(ptep);
+		pgste = pgste_ipte_notify(vma->vm_mm, addr, ptep, pgste);
+	}
+
+	pte = *ptep;
+	__ptep_ipte(addr, ptep);
+	young = pte_young(pte);
+	pte = pte_mkold(pte);
+
+	if (mm_has_pgste(vma->vm_mm)) {
+		pgste_set_pte(ptep, pte);
+		pgste_set_unlock(ptep, pgste);
+	} else
+		*ptep = pte;
+
+	return young;
+}
+
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
+					 unsigned long address, pte_t *ptep)
+{
+	return ptep_test_and_clear_young(vma, address, ptep);
+}
+
 /*
  * This is hard to understand. ptep_get_and_clear and ptep_clear_flush
  * both clear the TLB for the unmapped pte. The reason is that
@@ -1067,16 +1112,14 @@
 	pgste_t pgste;
 	pte_t pte;
 
-	mm->context.flush_mm = 1;
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_get_lock(ptep);
 		pgste = pgste_ipte_notify(mm, address, ptep, pgste);
 	}
 
 	pte = *ptep;
-	if (!mm_exclusive(mm))
-		__ptep_ipte(address, ptep);
-	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+	ptep_flush_lazy(mm, address, ptep);
+	pte_val(*ptep) = _PAGE_INVALID;
 
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_update_all(&pte, pgste);
@@ -1093,15 +1136,14 @@
 	pgste_t pgste;
 	pte_t pte;
 
-	mm->context.flush_mm = 1;
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_get_lock(ptep);
 		pgste_ipte_notify(mm, address, ptep, pgste);
 	}
 
 	pte = *ptep;
-	if (!mm_exclusive(mm))
-		__ptep_ipte(address, ptep);
+	ptep_flush_lazy(mm, address, ptep);
+	pte_val(*ptep) |= _PAGE_INVALID;
 
 	if (mm_has_pgste(mm)) {
 		pgste = pgste_update_all(&pte, pgste);
@@ -1117,7 +1159,7 @@
 	pgste_t pgste;
 
 	if (mm_has_pgste(mm)) {
-		pgste = *(pgste_t *)(ptep + PTRS_PER_PTE);
+		pgste = pgste_get(ptep);
 		pgste_set_key(ptep, pgste, pte);
 		pgste_set_pte(ptep, pte);
 		pgste_set_unlock(ptep, pgste);
@@ -1139,7 +1181,7 @@
 
 	pte = *ptep;
 	__ptep_ipte(address, ptep);
-	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+	pte_val(*ptep) = _PAGE_INVALID;
 
 	if (mm_has_pgste(vma->vm_mm)) {
 		pgste = pgste_update_all(&pte, pgste);
@@ -1163,18 +1205,17 @@
 	pgste_t pgste;
 	pte_t pte;
 
-	if (mm_has_pgste(mm)) {
+	if (!full && mm_has_pgste(mm)) {
 		pgste = pgste_get_lock(ptep);
-		if (!full)
-			pgste = pgste_ipte_notify(mm, address, ptep, pgste);
+		pgste = pgste_ipte_notify(mm, address, ptep, pgste);
 	}
 
 	pte = *ptep;
 	if (!full)
-		__ptep_ipte(address, ptep);
-	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+		ptep_flush_lazy(mm, address, ptep);
+	pte_val(*ptep) = _PAGE_INVALID;
 
-	if (mm_has_pgste(mm)) {
+	if (!full && mm_has_pgste(mm)) {
 		pgste = pgste_update_all(&pte, pgste);
 		pgste_set_unlock(ptep, pgste);
 	}
@@ -1189,14 +1230,12 @@
 	pte_t pte = *ptep;
 
 	if (pte_write(pte)) {
-		mm->context.flush_mm = 1;
 		if (mm_has_pgste(mm)) {
 			pgste = pgste_get_lock(ptep);
 			pgste = pgste_ipte_notify(mm, address, ptep, pgste);
 		}
 
-		if (!mm_exclusive(mm))
-			__ptep_ipte(address, ptep);
+		ptep_flush_lazy(mm, address, ptep);
 		pte = pte_wrprotect(pte);
 
 		if (mm_has_pgste(mm)) {
@@ -1240,7 +1279,7 @@
 {
 	pte_t __pte;
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
-	return __pte;
+	return pte_mkyoung(__pte);
 }
 
 static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
@@ -1248,10 +1287,8 @@
 	unsigned long physpage = page_to_phys(page);
 	pte_t __pte = mk_pte_phys(physpage, pgprot);
 
-	if ((pte_val(__pte) & _PAGE_SWW) && PageDirty(page)) {
-		pte_val(__pte) |= _PAGE_SWC;
-		pte_val(__pte) &= ~_PAGE_RO;
-	}
+	if (pte_write(__pte) && PageDirty(page))
+		__pte = pte_mkdirty(__pte);
 	return __pte;
 }
 
@@ -1313,7 +1350,7 @@
 	unsigned long sto = (unsigned long) pmdp -
 			    pmd_index(address) * sizeof(pmd_t);
 
-	if (!(pmd_val(*pmdp) & _SEGMENT_ENTRY_INV)) {
+	if (!(pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID)) {
 		asm volatile(
 			"	.insn	rrf,0xb98e0000,%2,%3,0,0"
 			: "=m" (*pmdp)
@@ -1324,24 +1361,68 @@
 	}
 }
 
+static inline void __pmd_csp(pmd_t *pmdp)
+{
+	register unsigned long reg2 asm("2") = pmd_val(*pmdp);
+	register unsigned long reg3 asm("3") = pmd_val(*pmdp) |
+					       _SEGMENT_ENTRY_INVALID;
+	register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5;
+
+	asm volatile(
+		"	csp %1,%3"
+		: "=m" (*pmdp)
+		: "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc");
+}
+
 #if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)
 static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
 {
 	/*
-	 * pgprot is PAGE_NONE, PAGE_RO, or PAGE_RW (see __Pxxx / __Sxxx)
+	 * pgprot is PAGE_NONE, PAGE_READ, or PAGE_WRITE (see __Pxxx / __Sxxx)
 	 * Convert to segment table entry format.
 	 */
 	if (pgprot_val(pgprot) == pgprot_val(PAGE_NONE))
 		return pgprot_val(SEGMENT_NONE);
-	if (pgprot_val(pgprot) == pgprot_val(PAGE_RO))
-		return pgprot_val(SEGMENT_RO);
-	return pgprot_val(SEGMENT_RW);
+	if (pgprot_val(pgprot) == pgprot_val(PAGE_READ))
+		return pgprot_val(SEGMENT_READ);
+	return pgprot_val(SEGMENT_WRITE);
+}
+
+static inline pmd_t pmd_mkyoung(pmd_t pmd)
+{
+#ifdef CONFIG_64BIT
+	if (pmd_prot_none(pmd)) {
+		pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
+	} else {
+		pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG;
+		pmd_val(pmd) &= ~_SEGMENT_ENTRY_INVALID;
+	}
+#endif
+	return pmd;
+}
+
+static inline pmd_t pmd_mkold(pmd_t pmd)
+{
+#ifdef CONFIG_64BIT
+	if (pmd_prot_none(pmd)) {
+		pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT;
+	} else {
+		pmd_val(pmd) &= ~_SEGMENT_ENTRY_YOUNG;
+		pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID;
+	}
+#endif
+	return pmd;
 }
 
 static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
 {
+	int young;
+
+	young = pmd_young(pmd);
 	pmd_val(pmd) &= _SEGMENT_CHG_MASK;
 	pmd_val(pmd) |= massage_pgprot_pmd(newprot);
+	if (young)
+		pmd = pmd_mkyoung(pmd);
 	return pmd;
 }
 
@@ -1349,18 +1430,29 @@
 {
 	pmd_t __pmd;
 	pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot);
-	return __pmd;
+	return pmd_mkyoung(__pmd);
 }
 
 static inline pmd_t pmd_mkwrite(pmd_t pmd)
 {
-	/* Do not clobber _HPAGE_TYPE_NONE pages! */
-	if (!(pmd_val(pmd) & _SEGMENT_ENTRY_INV))
-		pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO;
+	/* Do not clobber PROT_NONE segments! */
+	if (!pmd_prot_none(pmd))
+		pmd_val(pmd) &= ~_SEGMENT_ENTRY_PROTECT;
 	return pmd;
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */
 
+static inline void pmdp_flush_lazy(struct mm_struct *mm,
+				   unsigned long address, pmd_t *pmdp)
+{
+	int active = (mm == current->active_mm) ? 1 : 0;
+
+	if ((atomic_read(&mm->context.attach_count) & 0xffff) > active)
+		__pmd_idte(address, pmdp);
+	else
+		mm->context.flush_mm = 1;
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
 #define __HAVE_ARCH_PGTABLE_DEPOSIT
@@ -1378,7 +1470,7 @@
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 			      pmd_t *pmdp, pmd_t entry)
 {
-	if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1)
+	if (!(pmd_val(entry) & _SEGMENT_ENTRY_INVALID) && MACHINE_HAS_EDAT1)
 		pmd_val(entry) |= _SEGMENT_ENTRY_CO;
 	*pmdp = entry;
 }
@@ -1391,7 +1483,9 @@
 
 static inline pmd_t pmd_wrprotect(pmd_t pmd)
 {
-	pmd_val(pmd) |= _SEGMENT_ENTRY_RO;
+	/* Do not clobber PROT_NONE segments! */
+	if (!pmd_prot_none(pmd))
+		pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
 	return pmd;
 }
 
@@ -1401,50 +1495,16 @@
 	return pmd;
 }
 
-static inline pmd_t pmd_mkold(pmd_t pmd)
-{
-	/* No referenced bit in the segment table entry. */
-	return pmd;
-}
-
-static inline pmd_t pmd_mkyoung(pmd_t pmd)
-{
-	/* No referenced bit in the segment table entry. */
-	return pmd;
-}
-
 #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
 static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
 					    unsigned long address, pmd_t *pmdp)
 {
-	unsigned long pmd_addr = pmd_val(*pmdp) & HPAGE_MASK;
-	long tmp, rc;
-	int counter;
+	pmd_t pmd;
 
-	rc = 0;
-	if (MACHINE_HAS_RRBM) {
-		counter = PTRS_PER_PTE >> 6;
-		asm volatile(
-			"0:	.insn	rre,0xb9ae0000,%0,%3\n"	/* rrbm */
-			"	ogr	%1,%0\n"
-			"	la	%3,0(%4,%3)\n"
-			"	brct	%2,0b\n"
-			: "=&d" (tmp), "+&d" (rc), "+d" (counter),
-			  "+a" (pmd_addr)
-			: "a" (64 * 4096UL) : "cc");
-		rc = !!rc;
-	} else {
-		counter = PTRS_PER_PTE;
-		asm volatile(
-			"0:	rrbe	0,%2\n"
-			"	la	%2,0(%3,%2)\n"
-			"	brc	12,1f\n"
-			"	lhi	%0,1\n"
-			"1:	brct	%1,0b\n"
-			: "+d" (rc), "+d" (counter), "+a" (pmd_addr)
-			: "a" (4096UL) : "cc");
-	}
-	return rc;
+	pmd = *pmdp;
+	__pmd_idte(address, pmdp);
+	*pmdp = pmd_mkold(pmd);
+	return pmd_young(pmd);
 }
 
 #define __HAVE_ARCH_PMDP_GET_AND_CLEAR
@@ -1510,10 +1570,8 @@
  * exception will occur instead of a page translation exception. The
  * specifiation exception has the bad habit not to store necessary
  * information in the lowcore.
- * Bit 21 and bit 22 are the page invalid bit and the page protection
- * bit. We set both to indicate a swapped page.
- * Bit 30 and 31 are used to distinguish the different page types. For
- * a swapped page these bits need to be zero.
+ * Bits 21, 22, 30 and 31 are used to indicate the page type.
+ * A swap pte is indicated by bit pattern (pte & 0x603) == 0x402
  * This leaves the bits 1-19 and bits 24-29 to store type and offset.
  * We use the 5 bits from 25-29 for the type and the 20 bits from 1-19
  * plus 24 for the offset.
@@ -1527,10 +1585,8 @@
  * exception will occur instead of a page translation exception. The
  * specifiation exception has the bad habit not to store necessary
  * information in the lowcore.
- * Bit 53 and bit 54 are the page invalid bit and the page protection
- * bit. We set both to indicate a swapped page.
- * Bit 62 and 63 are used to distinguish the different page types. For
- * a swapped page these bits need to be zero.
+ * Bits 53, 54, 62 and 63 are used to indicate the page type.
+ * A swap pte is indicated by bit pattern (pte & 0x603) == 0x402
  * This leaves the bits 0-51 and bits 56-61 to store type and offset.
  * We use the 5 bits from 57-61 for the type and the 53 bits from 0-51
  * plus 56 for the offset.
@@ -1547,7 +1603,7 @@
 {
 	pte_t pte;
 	offset &= __SWP_OFFSET_MASK;
-	pte_val(pte) = _PAGE_TYPE_SWAP | ((type & 0x1f) << 2) |
+	pte_val(pte) = _PAGE_INVALID | _PAGE_TYPE | ((type & 0x1f) << 2) |
 		((offset & 1UL) << 7) | ((offset & ~1UL) << 11);
 	return pte;
 }
@@ -1570,7 +1626,7 @@
 
 #define pgoff_to_pte(__off) \
 	((pte_t) { ((((__off) & 0x7f) << 1) + (((__off) >> 7) << 12)) \
-		   | _PAGE_TYPE_FILE })
+		   | _PAGE_INVALID | _PAGE_PROTECT })
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index b0e6435..0eb3750 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -43,6 +43,7 @@
 #ifndef CONFIG_64BIT
 
 #define TASK_SIZE		(1UL << 31)
+#define TASK_MAX_SIZE		(1UL << 31)
 #define TASK_UNMAPPED_BASE	(1UL << 30)
 
 #else /* CONFIG_64BIT */
@@ -51,6 +52,7 @@
 #define TASK_UNMAPPED_BASE	(test_thread_flag(TIF_31BIT) ? \
 					(1UL << 30) : (1UL << 41))
 #define TASK_SIZE		TASK_SIZE_OF(current)
+#define TASK_MAX_SIZE		(1UL << 53)
 
 #endif /* CONFIG_64BIT */
 
diff --git a/arch/s390/include/asm/serial.h b/arch/s390/include/asm/serial.h
new file mode 100644
index 0000000..5b3e48e
--- /dev/null
+++ b/arch/s390/include/asm/serial.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_S390_SERIAL_H
+#define _ASM_S390_SERIAL_H
+
+#define BASE_BAUD 0
+
+#endif /* _ASM_S390_SERIAL_H */
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h
index 80b6f11..6dbd5597 100644
--- a/arch/s390/include/asm/switch_to.h
+++ b/arch/s390/include/asm/switch_to.h
@@ -8,6 +8,7 @@
 #define __ASM_SWITCH_TO_H
 
 #include <linux/thread_info.h>
+#include <asm/ptrace.h>
 
 extern struct task_struct *__switch_to(void *, void *);
 extern void update_cr_regs(struct task_struct *task);
@@ -68,12 +69,16 @@
 
 static inline void save_access_regs(unsigned int *acrs)
 {
-	asm volatile("stam 0,15,%0" : "=Q" (*acrs));
+	typedef struct { int _[NUM_ACRS]; } acrstype;
+
+	asm volatile("stam 0,15,%0" : "=Q" (*(acrstype *)acrs));
 }
 
 static inline void restore_access_regs(unsigned int *acrs)
 {
-	asm volatile("lam 0,15,%0" : : "Q" (*acrs));
+	typedef struct { int _[NUM_ACRS]; } acrstype;
+
+	asm volatile("lam 0,15,%0" : : "Q" (*(acrstype *)acrs));
 }
 
 #define switch_to(prev,next,last) do {					\
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h
index 6d6d92b..2cb846c 100644
--- a/arch/s390/include/asm/tlb.h
+++ b/arch/s390/include/asm/tlb.h
@@ -63,13 +63,14 @@
 
 static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 {
+	__tlb_flush_mm_lazy(tlb->mm);
 	tlb_table_flush(tlb);
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
 				  unsigned long start, unsigned long end)
 {
-	tlb_table_flush(tlb);
+	tlb_flush_mmu(tlb);
 }
 
 /*
diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h
index 6b32af3..f9fef04 100644
--- a/arch/s390/include/asm/tlbflush.h
+++ b/arch/s390/include/asm/tlbflush.h
@@ -86,7 +86,7 @@
 		__tlb_flush_full(mm);
 }
 
-static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
+static inline void __tlb_flush_mm_lazy(struct mm_struct * mm)
 {
 	if (mm->context.flush_mm) {
 		__tlb_flush_mm(mm);
@@ -118,13 +118,13 @@
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
-	__tlb_flush_mm_cond(mm);
+	__tlb_flush_mm_lazy(mm);
 }
 
 static inline void flush_tlb_range(struct vm_area_struct *vma,
 				   unsigned long start, unsigned long end)
 {
-	__tlb_flush_mm_cond(vma->vm_mm);
+	__tlb_flush_mm_lazy(vma->vm_mm);
 }
 
 static inline void flush_tlb_kernel_range(unsigned long start,
diff --git a/arch/s390/include/asm/vtime.h b/arch/s390/include/asm/vtime.h
new file mode 100644
index 0000000..af9896c
--- /dev/null
+++ b/arch/s390/include/asm/vtime.h
@@ -0,0 +1,7 @@
+#ifndef _S390_VTIME_H
+#define _S390_VTIME_H
+
+#define __ARCH_HAS_VTIME_ACCOUNT
+#define __ARCH_HAS_VTIME_TASK_SWITCH
+
+#endif /* _S390_VTIME_H */
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index be7a408..cc30d1f 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -18,6 +18,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/sigp.h>
+#include <asm/irq.h>
 
 __PT_R0      =	__PT_GPRS
 __PT_R1      =	__PT_GPRS + 4
@@ -435,6 +436,11 @@
 io_loop:
 	l	%r1,BASED(.Ldo_IRQ)
 	lr	%r2,%r11		# pass pointer to pt_regs
+	lhi	%r3,IO_INTERRUPT
+	tm	__PT_INT_CODE+8(%r11),0x80	# adapter interrupt ?
+	jz	io_call
+	lhi	%r3,THIN_INTERRUPT
+io_call:
 	basr	%r14,%r1		# call do_IRQ
 	tm	__LC_MACHINE_FLAGS+2,0x10	# MACHINE_FLAG_LPAR
 	jz	io_return
@@ -584,9 +590,10 @@
 	mvc	__PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
 	mvc	__PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
 	TRACE_IRQS_OFF
+	l	%r1,BASED(.Ldo_IRQ)
 	lr	%r2,%r11		# pass pointer to pt_regs
-	l	%r1,BASED(.Ldo_extint)
-	basr	%r14,%r1		# call do_extint
+	lhi	%r3,EXT_INTERRUPT
+	basr	%r14,%r1		# call do_IRQ
 	j	io_return
 
 /*
@@ -879,13 +886,13 @@
 	stm	%r9,%r10,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2)
 	# prepare return psw
-	n	%r8,BASED(cleanup_idle_wait)	# clear wait state bit
+	n	%r8,BASED(cleanup_idle_wait)	# clear irq & wait state bits
 	l	%r9,24(%r11)			# return from psw_idle
 	br	%r14
 cleanup_idle_insn:
 	.long	psw_idle_lpsw + 0x80000000
 cleanup_idle_wait:
-	.long	0xfffdffff
+	.long	0xfcfdffff
 
 /*
  * Integer constants
@@ -902,7 +909,6 @@
 .Ldo_machine_check:	.long	s390_do_machine_check
 .Lhandle_mcck:		.long	s390_handle_mcck
 .Ldo_IRQ:		.long	do_IRQ
-.Ldo_extint:		.long	do_extint
 .Ldo_signal:		.long	do_signal
 .Ldo_notify_resume:	.long	do_notify_resume
 .Ldo_per_trap:		.long	do_per_trap
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 1c039d0..2b2188b 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -19,6 +19,7 @@
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/sigp.h>
+#include <asm/irq.h>
 
 __PT_R0      =	__PT_GPRS
 __PT_R1      =	__PT_GPRS + 8
@@ -468,6 +469,11 @@
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 io_loop:
 	lgr	%r2,%r11		# pass pointer to pt_regs
+	lghi	%r3,IO_INTERRUPT
+	tm	__PT_INT_CODE+8(%r11),0x80	# adapter interrupt ?
+	jz	io_call
+	lghi	%r3,THIN_INTERRUPT
+io_call:
 	brasl	%r14,do_IRQ
 	tm	__LC_MACHINE_FLAGS+6,0x10	# MACHINE_FLAG_LPAR
 	jz	io_return
@@ -623,7 +629,8 @@
 	TRACE_IRQS_OFF
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
 	lgr	%r2,%r11		# pass pointer to pt_regs
-	brasl	%r14,do_extint
+	lghi	%r3,EXT_INTERRUPT
+	brasl	%r14,do_IRQ
 	j	io_return
 
 /*
@@ -922,7 +929,7 @@
 	stg	%r9,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2)
 	# prepare return psw
-	nihh	%r8,0xfffd		# clear wait state bit
+	nihh	%r8,0xfcfd		# clear irq & wait state bits
 	lg	%r9,48(%r11)		# return from psw_idle
 	br	%r14
 cleanup_idle_insn:
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 54b0995..b34ba0e 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -22,6 +22,7 @@
 #include <asm/cputime.h>
 #include <asm/lowcore.h>
 #include <asm/irq.h>
+#include <asm/hw_irq.h>
 #include "entry.h"
 
 DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat);
@@ -42,9 +43,10 @@
  * Since the external and I/O interrupt fields are already sums we would end
  * up with having a sum which accounts each interrupt twice.
  */
-static const struct irq_class irqclass_main_desc[NR_IRQS] = {
-	[EXTERNAL_INTERRUPT] = {.name = "EXT"},
-	[IO_INTERRUPT]	     = {.name = "I/O"}
+static const struct irq_class irqclass_main_desc[NR_IRQS_BASE] = {
+	[EXT_INTERRUPT]  = {.name = "EXT"},
+	[IO_INTERRUPT]	 = {.name = "I/O"},
+	[THIN_INTERRUPT] = {.name = "AIO"},
 };
 
 /*
@@ -86,6 +88,28 @@
 	[CPU_RST]    = {.name = "RST", .desc = "[CPU] CPU Restart"},
 };
 
+void __init init_IRQ(void)
+{
+	irq_reserve_irqs(0, THIN_INTERRUPT);
+	init_cio_interrupts();
+	init_airq_interrupts();
+	init_ext_interrupts();
+}
+
+void do_IRQ(struct pt_regs *regs, int irq)
+{
+	struct pt_regs *old_regs;
+
+	old_regs = set_irq_regs(regs);
+	irq_enter();
+	if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
+		/* Serve timer interrupts first. */
+		clock_comparator_work();
+	generic_handle_irq(irq);
+	irq_exit();
+	set_irq_regs(old_regs);
+}
+
 /*
  * show_interrupts is needed by /proc/interrupts.
  */
@@ -100,27 +124,36 @@
 		for_each_online_cpu(cpu)
 			seq_printf(p, "CPU%d       ", cpu);
 		seq_putc(p, '\n');
+		goto out;
 	}
 	if (irq < NR_IRQS) {
+		if (irq >= NR_IRQS_BASE)
+			goto out;
 		seq_printf(p, "%s: ", irqclass_main_desc[irq].name);
 		for_each_online_cpu(cpu)
-			seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[irq]);
+			seq_printf(p, "%10u ", kstat_irqs_cpu(irq, cpu));
 		seq_putc(p, '\n');
-		goto skip_arch_irqs;
+		goto out;
 	}
 	for (irq = 0; irq < NR_ARCH_IRQS; irq++) {
 		seq_printf(p, "%s: ", irqclass_sub_desc[irq].name);
 		for_each_online_cpu(cpu)
-			seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).irqs[irq]);
+			seq_printf(p, "%10u ",
+				   per_cpu(irq_stat, cpu).irqs[irq]);
 		if (irqclass_sub_desc[irq].desc)
 			seq_printf(p, "  %s", irqclass_sub_desc[irq].desc);
 		seq_putc(p, '\n');
 	}
-skip_arch_irqs:
+out:
 	put_online_cpus();
 	return 0;
 }
 
+int arch_show_interrupts(struct seq_file *p, int prec)
+{
+	return 0;
+}
+
 /*
  * Switch to the asynchronous interrupt stack for softirq execution.
  */
@@ -159,14 +192,6 @@
 	local_irq_restore(flags);
 }
 
-#ifdef CONFIG_PROC_FS
-void init_irq_proc(void)
-{
-	if (proc_mkdir("irq", NULL))
-		create_prof_cpu_mask();
-}
-#endif
-
 /*
  * ext_int_hash[index] is the list head for all external interrupts that hash
  * to this index.
@@ -183,14 +208,6 @@
 /* ext_int_hash_lock protects the handler lists for external interrupts */
 DEFINE_SPINLOCK(ext_int_hash_lock);
 
-static void __init init_external_interrupts(void)
-{
-	int idx;
-
-	for (idx = 0; idx < ARRAY_SIZE(ext_int_hash); idx++)
-		INIT_LIST_HEAD(&ext_int_hash[idx]);
-}
-
 static inline int ext_hash(u16 code)
 {
 	return (code + (code >> 9)) & 0xff;
@@ -234,20 +251,13 @@
 }
 EXPORT_SYMBOL(unregister_external_interrupt);
 
-void __irq_entry do_extint(struct pt_regs *regs)
+static irqreturn_t do_ext_interrupt(int irq, void *dummy)
 {
+	struct pt_regs *regs = get_irq_regs();
 	struct ext_code ext_code;
-	struct pt_regs *old_regs;
 	struct ext_int_info *p;
 	int index;
 
-	old_regs = set_irq_regs(regs);
-	irq_enter();
-	if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) {
-		/* Serve timer interrupts first. */
-		clock_comparator_work();
-	}
-	kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
 	ext_code = *(struct ext_code *) &regs->int_code;
 	if (ext_code.code != 0x1004)
 		__get_cpu_var(s390_idle).nohz_delay = 1;
@@ -259,13 +269,25 @@
 			p->handler(ext_code, regs->int_parm,
 				   regs->int_parm_long);
 	rcu_read_unlock();
-	irq_exit();
-	set_irq_regs(old_regs);
+
+	return IRQ_HANDLED;
 }
 
-void __init init_IRQ(void)
+static struct irqaction external_interrupt = {
+	.name	 = "EXT",
+	.handler = do_ext_interrupt,
+};
+
+void __init init_ext_interrupts(void)
 {
-	init_external_interrupts();
+	int idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(ext_int_hash); idx++)
+		INIT_LIST_HEAD(&ext_int_hash[idx]);
+
+	irq_set_chip_and_handler(EXT_INTERRUPT,
+				 &dummy_irq_chip, handle_percpu_irq);
+	setup_irq(EXT_INTERRUPT, &external_interrupt);
 }
 
 static DEFINE_SPINLOCK(sc_irq_lock);
@@ -313,69 +335,3 @@
 	spin_unlock(&ma_subclass_lock);
 }
 EXPORT_SYMBOL(measurement_alert_subclass_unregister);
-
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
-	/*
-	 * Not needed, the handler is protected by a lock and IRQs that occur
-	 * after the handler is deleted are just NOPs.
-	 */
-}
-EXPORT_SYMBOL_GPL(synchronize_irq);
-#endif
-
-#ifndef CONFIG_PCI
-
-/* Only PCI devices have dynamically-defined IRQ handlers */
-
-int request_irq(unsigned int irq, irq_handler_t handler,
-		unsigned long irqflags, const char *devname, void *dev_id)
-{
-	return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-	WARN_ON(1);
-}
-EXPORT_SYMBOL_GPL(free_irq);
-
-void enable_irq(unsigned int irq)
-{
-	WARN_ON(1);
-}
-EXPORT_SYMBOL_GPL(enable_irq);
-
-void disable_irq(unsigned int irq)
-{
-	WARN_ON(1);
-}
-EXPORT_SYMBOL_GPL(disable_irq);
-
-#endif /* !CONFIG_PCI */
-
-void disable_irq_nosync(unsigned int irq)
-{
-	disable_irq(irq);
-}
-EXPORT_SYMBOL_GPL(disable_irq_nosync);
-
-unsigned long probe_irq_on(void)
-{
-	return 0;
-}
-EXPORT_SYMBOL_GPL(probe_irq_on);
-
-int probe_irq_off(unsigned long val)
-{
-	return 0;
-}
-EXPORT_SYMBOL_GPL(probe_irq_off);
-
-unsigned int probe_irq_mask(unsigned long val)
-{
-	return val;
-}
-EXPORT_SYMBOL_GPL(probe_irq_mask);
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 3388b2b..adbbe7f 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -105,14 +105,31 @@
 		fixup |= FIXUP_RETURN_REGISTER;
 		break;
 	case 0xeb:
-		if ((insn[2] & 0xff) == 0x44 ||	/* bxhg  */
-		    (insn[2] & 0xff) == 0x45)	/* bxleg */
+		switch (insn[2] & 0xff) {
+		case 0x44: /* bxhg  */
+		case 0x45: /* bxleg */
 			fixup = FIXUP_BRANCH_NOT_TAKEN;
+			break;
+		}
 		break;
 	case 0xe3:	/* bctg	*/
 		if ((insn[2] & 0xff) == 0x46)
 			fixup = FIXUP_BRANCH_NOT_TAKEN;
 		break;
+	case 0xec:
+		switch (insn[2] & 0xff) {
+		case 0xe5: /* clgrb */
+		case 0xe6: /* cgrb  */
+		case 0xf6: /* crb   */
+		case 0xf7: /* clrb  */
+		case 0xfc: /* cgib  */
+		case 0xfd: /* cglib */
+		case 0xfe: /* cib   */
+		case 0xff: /* clib  */
+			fixup = FIXUP_BRANCH_NOT_TAKEN;
+			break;
+		}
+		break;
 	}
 	return fixup;
 }
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 504175e..c4c0338 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -214,10 +214,7 @@
 			: "0", "cc");
 #endif
 	/* Revalidate clock comparator register */
-	if (S390_lowcore.clock_comparator == -1)
-		set_clock_comparator(S390_lowcore.mcck_clock);
-	else
-		set_clock_comparator(S390_lowcore.clock_comparator);
+	set_clock_comparator(S390_lowcore.clock_comparator);
 	/* Check if old PSW is valid */
 	if (!mci->wp)
 		/*
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 2bc3edd..c5dbb33 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -71,6 +71,7 @@
 	}
 	/* Halt the cpu and keep track of cpu time accounting. */
 	vtime_stop_cpu();
+	local_irq_enable();
 }
 
 void arch_cpu_idle_exit(void)
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index e9fadb0..9556905 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -60,11 +60,11 @@
 
 		__ctl_store(cr, 0, 2);
 		cr_new[1] = cr[1];
-		/* Set or clear transaction execution TXC/PIFO bits 8 and 9. */
+		/* Set or clear transaction execution TXC bit 8. */
 		if (task->thread.per_flags & PER_FLAG_NO_TE)
-			cr_new[0] = cr[0] & ~(3UL << 54);
+			cr_new[0] = cr[0] & ~(1UL << 55);
 		else
-			cr_new[0] = cr[0] | (3UL << 54);
+			cr_new[0] = cr[0] | (1UL << 55);
 		/* Set or clear transaction execution TDC bits 62 and 63. */
 		cr_new[2] = cr[2] & ~3UL;
 		if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
@@ -1299,7 +1299,7 @@
 
 	if (!name || *name != 'r')
 		return -EINVAL;
-	if (strict_strtoul(name + 1, 10, &offset))
+	if (kstrtoul(name + 1, 10, &offset))
 		return -EINVAL;
 	if (offset >= NUM_GPRS)
 		return -EINVAL;
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index c479d2f..737bff3 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -10,6 +10,9 @@
 #include <linux/suspend.h>
 #include <linux/mm.h>
 #include <asm/ctl_reg.h>
+#include <asm/ipl.h>
+#include <asm/cio.h>
+#include <asm/pci.h>
 
 /*
  * References to section boundaries
@@ -211,3 +214,11 @@
 	__ctl_set_bit(0,28);
 	local_mcck_enable();
 }
+
+/* Called at the end of swsusp_arch_resume */
+void s390_early_resume(void)
+{
+	lgr_info_log();
+	channel_subsystem_reinit();
+	zpci_rescan();
+}
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index c487be4..6b09fdf 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -281,11 +281,8 @@
 	lghi	%r2,0
 	brasl	%r14,arch_set_page_states
 
-	/* Log potential guest relocation */
-	brasl	%r14,lgr_info_log
-
-	/* Reinitialize the channel subsystem */
-	brasl	%r14,channel_subsystem_reinit
+	/* Call arch specific early resume code */
+	brasl	%r14,s390_early_resume
 
 	/* Return 0 */
 	lmg	%r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 876546b..064c308 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -92,7 +92,6 @@
 	struct clock_event_device *cd;
 
 	S390_lowcore.clock_comparator = -1ULL;
-	set_clock_comparator(S390_lowcore.clock_comparator);
 	cd = &__get_cpu_var(comparators);
 	cd->event_handler(cd);
 }
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index d777628..05d75c4 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -63,7 +63,7 @@
 	else if (strncmp(s, "off", 4) == 0)
 		vdso_enabled = 0;
 	else {
-		rc = strict_strtoul(s, 0, &val);
+		rc = kstrtoul(s, 0, &val);
 		vdso_enabled = rc ? 0 : !!val;
 	}
 	return !rc;
@@ -113,11 +113,11 @@
 
 	clear_table((unsigned long *) segment_table, _SEGMENT_ENTRY_EMPTY,
 		    PAGE_SIZE << SEGMENT_ORDER);
-	clear_table((unsigned long *) page_table, _PAGE_TYPE_EMPTY,
+	clear_table((unsigned long *) page_table, _PAGE_INVALID,
 		    256*sizeof(unsigned long));
 
 	*(unsigned long *) segment_table = _SEGMENT_ENTRY + page_table;
-	*(unsigned long *) page_table = _PAGE_RO + page_frame;
+	*(unsigned long *) page_table = _PAGE_PROTECT + page_frame;
 
 	psal = (u32 *) (page_table + 256*sizeof(unsigned long));
 	aste = psal + 32;
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 9b9c1b7..abcfab5 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -19,6 +19,7 @@
 #include <asm/irq_regs.h>
 #include <asm/cputime.h>
 #include <asm/vtimer.h>
+#include <asm/vtime.h>
 #include <asm/irq.h>
 #include "entry.h"
 
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 3074475..3a74d8a 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -119,12 +119,21 @@
 	 * The layout is as follows:
 	 * - gpr 2 contains the subchannel id (passed as addr)
 	 * - gpr 3 contains the virtqueue index (passed as datamatch)
+	 * - gpr 4 contains the index on the bus (optionally)
 	 */
-	ret = kvm_io_bus_write(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS,
-				vcpu->run->s.regs.gprs[2],
-				8, &vcpu->run->s.regs.gprs[3]);
+	ret = kvm_io_bus_write_cookie(vcpu->kvm, KVM_VIRTIO_CCW_NOTIFY_BUS,
+				      vcpu->run->s.regs.gprs[2],
+				      8, &vcpu->run->s.regs.gprs[3],
+				      vcpu->run->s.regs.gprs[4]);
 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
-	/* kvm_io_bus_write returns -EOPNOTSUPP if it found no match. */
+
+	/*
+	 * Return cookie in gpr 2, but don't overwrite the register if the
+	 * diagnose will be handled by userspace.
+	 */
+	if (ret != -EOPNOTSUPP)
+		vcpu->run->s.regs.gprs[2] = ret;
+	/* kvm_io_bus_write_cookie returns -EOPNOTSUPP if it found no match. */
 	return ret < 0 ? ret : 0;
 }
 
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h
index 302e0e5..99d789e 100644
--- a/arch/s390/kvm/gaccess.h
+++ b/arch/s390/kvm/gaccess.h
@@ -42,9 +42,11 @@
 ({								\
 	__typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\
 	int __mask = sizeof(__typeof__(*(gptr))) - 1;		\
-	int __ret = PTR_RET((void __force *)__uptr);		\
+	int __ret;						\
 								\
-	if (!__ret) {						\
+	if (IS_ERR((void __force *)__uptr)) {			\
+		__ret = PTR_ERR((void __force *)__uptr);	\
+	} else {						\
 		BUG_ON((unsigned long)__uptr & __mask);		\
 		__ret = get_user(x, __uptr);			\
 	}							\
@@ -55,9 +57,11 @@
 ({								\
 	__typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\
 	int __mask = sizeof(__typeof__(*(gptr))) - 1;		\
-	int __ret = PTR_RET((void __force *)__uptr);		\
+	int __ret;						\
 								\
-	if (!__ret) {						\
+	if (IS_ERR((void __force *)__uptr)) {			\
+		__ret = PTR_ERR((void __force *)__uptr);	\
+	} else {						\
 		BUG_ON((unsigned long)__uptr & __mask);		\
 		__ret = put_user(x, __uptr);			\
 	}							\
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 34c1c9a..776dafe 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -28,6 +28,7 @@
 #include <asm/pgtable.h>
 #include <asm/nmi.h>
 #include <asm/switch_to.h>
+#include <asm/facility.h>
 #include <asm/sclp.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
@@ -84,9 +85,15 @@
 	{ NULL }
 };
 
-static unsigned long long *facilities;
+unsigned long *vfacilities;
 static struct gmap_notifier gmap_notifier;
 
+/* test availability of vfacility */
+static inline int test_vfacility(unsigned long nr)
+{
+	return __test_facility(nr, (void *) vfacilities);
+}
+
 /* Section: not file related */
 int kvm_arch_hardware_enable(void *garbage)
 {
@@ -387,7 +394,7 @@
 	vcpu->arch.sie_block->ecb   = 6;
 	vcpu->arch.sie_block->ecb2  = 8;
 	vcpu->arch.sie_block->eca   = 0xC1002001U;
-	vcpu->arch.sie_block->fac   = (int) (long) facilities;
+	vcpu->arch.sie_block->fac   = (int) (long) vfacilities;
 	hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
 	tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
 		     (unsigned long) vcpu);
@@ -1063,6 +1070,10 @@
 	return 0;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+}
+
 /* Section: memory related */
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				   struct kvm_memory_slot *memslot,
@@ -1129,20 +1140,20 @@
 	 * to hold the maximum amount of facilities. On the other hand, we
 	 * only set facilities that are known to work in KVM.
 	 */
-	facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
-	if (!facilities) {
+	vfacilities = (unsigned long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
+	if (!vfacilities) {
 		kvm_exit();
 		return -ENOMEM;
 	}
-	memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
-	facilities[0] &= 0xff82fff3f47c0000ULL;
-	facilities[1] &= 0x001c000000000000ULL;
+	memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
+	vfacilities[0] &= 0xff82fff3f47c0000UL;
+	vfacilities[1] &= 0x001c000000000000UL;
 	return 0;
 }
 
 static void __exit kvm_s390_exit(void)
 {
-	free_page((unsigned long) facilities);
+	free_page((unsigned long) vfacilities);
 	kvm_exit();
 }
 
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 028ca9f..dc99f1c 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -24,6 +24,9 @@
 
 typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
 
+/* declare vfacilities extern */
+extern unsigned long *vfacilities;
+
 /* negativ values are error codes, positive values for internal conditions */
 #define SIE_INTERCEPT_RERUNVCPU		(1<<0)
 #define SIE_INTERCEPT_UCONTROL		(1<<1)
@@ -112,6 +115,13 @@
 	return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
 }
 
+/* Set the condition code in the guest program status word */
+static inline void kvm_s390_set_psw_cc(struct kvm_vcpu *vcpu, unsigned long cc)
+{
+	vcpu->arch.sie_block->gpsw.mask &= ~(3UL << 44);
+	vcpu->arch.sie_block->gpsw.mask |= cc << 44;
+}
+
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
 enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
 void kvm_s390_tasklet(unsigned long parm);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 4cdc54e..59200ee 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -164,8 +164,7 @@
 	kfree(inti);
 no_interrupt:
 	/* Set condition code and we're done. */
-	vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-	vcpu->arch.sie_block->gpsw.mask |= (cc & 3ul) << 44;
+	kvm_s390_set_psw_cc(vcpu, cc);
 	return 0;
 }
 
@@ -220,15 +219,13 @@
 		 * Set condition code 3 to stop the guest from issueing channel
 		 * I/O instructions.
 		 */
-		vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-		vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
+		kvm_s390_set_psw_cc(vcpu, 3);
 		return 0;
 	}
 }
 
 static int handle_stfl(struct kvm_vcpu *vcpu)
 {
-	unsigned int facility_list;
 	int rc;
 
 	vcpu->stat.instruction_stfl++;
@@ -236,15 +233,13 @@
 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
-	/* only pass the facility bits, which we can handle */
-	facility_list = S390_lowcore.stfl_fac_list & 0xff82fff3;
-
 	rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
-			   &facility_list, sizeof(facility_list));
+			   vfacilities, 4);
 	if (rc)
 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-	VCPU_EVENT(vcpu, 5, "store facility list value %x", facility_list);
-	trace_kvm_s390_handle_stfl(vcpu, facility_list);
+	VCPU_EVENT(vcpu, 5, "store facility list value %x",
+		   *(unsigned int *) vfacilities);
+	trace_kvm_s390_handle_stfl(vcpu, *(unsigned int *) vfacilities);
 	return 0;
 }
 
@@ -387,7 +382,7 @@
 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
 
 	if (fc > 3) {
-		vcpu->arch.sie_block->gpsw.mask |= 3ul << 44;	  /* cc 3 */
+		kvm_s390_set_psw_cc(vcpu, 3);
 		return 0;
 	}
 
@@ -397,7 +392,7 @@
 
 	if (fc == 0) {
 		vcpu->run->s.regs.gprs[0] = 3 << 28;
-		vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);  /* cc 0 */
+		kvm_s390_set_psw_cc(vcpu, 0);
 		return 0;
 	}
 
@@ -431,12 +426,11 @@
 	}
 	trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
 	free_page(mem);
-	vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+	kvm_s390_set_psw_cc(vcpu, 0);
 	vcpu->run->s.regs.gprs[0] = 0;
 	return 0;
 out_no_data:
-	/* condition code 3 */
-	vcpu->arch.sie_block->gpsw.mask |= 3ul << 44;
+	kvm_s390_set_psw_cc(vcpu, 3);
 out_exception:
 	free_page(mem);
 	return rc;
@@ -494,12 +488,12 @@
 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
 
 	/* This basically extracts the mask half of the psw. */
-	vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000;
+	vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000UL;
 	vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32;
 	if (reg2) {
-		vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000;
+		vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000UL;
 		vcpu->run->s.regs.gprs[reg2] |=
-			vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffff;
+			vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffffUL;
 	}
 	return 0;
 }
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index c61b9fa..57c87d7 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -44,7 +44,6 @@
 	do {
 		set_clock_comparator(end);
 		vtime_stop_cpu();
-		local_irq_disable();
 	} while (get_tod_clock() < end);
 	lockdep_on();
 	__ctl_load(cr0, 0, 0);
@@ -64,7 +63,6 @@
 			set_clock_comparator(end);
 		}
 		vtime_stop_cpu();
-		local_irq_disable();
 		if (clock_saved)
 			local_tick_enable(clock_saved);
 	} while (get_tod_clock() < end);
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 50ea137..1694d73 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -86,28 +86,28 @@
 	switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
 	case _ASCE_TYPE_REGION1:
 		table = table + ((address >> 53) & 0x7ff);
-		if (unlikely(*table & _REGION_ENTRY_INV))
+		if (unlikely(*table & _REGION_ENTRY_INVALID))
 			return -0x39UL;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		/* fallthrough */
 	case _ASCE_TYPE_REGION2:
 		table = table + ((address >> 42) & 0x7ff);
-		if (unlikely(*table & _REGION_ENTRY_INV))
+		if (unlikely(*table & _REGION_ENTRY_INVALID))
 			return -0x3aUL;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		/* fallthrough */
 	case _ASCE_TYPE_REGION3:
 		table = table + ((address >> 31) & 0x7ff);
-		if (unlikely(*table & _REGION_ENTRY_INV))
+		if (unlikely(*table & _REGION_ENTRY_INVALID))
 			return -0x3bUL;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		/* fallthrough */
 	case _ASCE_TYPE_SEGMENT:
 		table = table + ((address >> 20) & 0x7ff);
-		if (unlikely(*table & _SEGMENT_ENTRY_INV))
+		if (unlikely(*table & _SEGMENT_ENTRY_INVALID))
 			return -0x10UL;
 		if (unlikely(*table & _SEGMENT_ENTRY_LARGE)) {
-			if (write && (*table & _SEGMENT_ENTRY_RO))
+			if (write && (*table & _SEGMENT_ENTRY_PROTECT))
 				return -0x04UL;
 			return (*table & _SEGMENT_ENTRY_ORIGIN_LARGE) +
 				(address & ~_SEGMENT_ENTRY_ORIGIN_LARGE);
@@ -117,7 +117,7 @@
 	table = table + ((address >> 12) & 0xff);
 	if (unlikely(*table & _PAGE_INVALID))
 		return -0x11UL;
-	if (write && (*table & _PAGE_RO))
+	if (write && (*table & _PAGE_PROTECT))
 		return -0x04UL;
 	return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
 }
@@ -130,13 +130,13 @@
 	unsigned long *table = (unsigned long *)__pa(mm->pgd);
 
 	table = table + ((address >> 20) & 0x7ff);
-	if (unlikely(*table & _SEGMENT_ENTRY_INV))
+	if (unlikely(*table & _SEGMENT_ENTRY_INVALID))
 		return -0x10UL;
 	table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
 	table = table + ((address >> 12) & 0xff);
 	if (unlikely(*table & _PAGE_INVALID))
 		return -0x11UL;
-	if (write && (*table & _PAGE_RO))
+	if (write && (*table & _PAGE_PROTECT))
 		return -0x04UL;
 	return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
 }
diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c
index 3ad65b0..46d517c 100644
--- a/arch/s390/mm/dump_pagetables.c
+++ b/arch/s390/mm/dump_pagetables.c
@@ -53,7 +53,7 @@
 		seq_printf(m, "I\n");
 		return;
 	}
-	seq_printf(m, "%s", pr & _PAGE_RO ? "RO " : "RW ");
+	seq_printf(m, "%s", pr & _PAGE_PROTECT ? "RO " : "RW ");
 	seq_printf(m, "%s", pr & _PAGE_CO ? "CO " : "   ");
 	seq_putc(m, '\n');
 }
@@ -105,12 +105,12 @@
 }
 
 /*
- * The actual page table walker functions. In order to keep the implementation
- * of print_prot() short, we only check and pass _PAGE_INVALID and _PAGE_RO
- * flags to note_page() if a region, segment or page table entry is invalid or
- * read-only.
- * After all it's just a hint that the current level being walked contains an
- * invalid or read-only entry.
+ * The actual page table walker functions. In order to keep the
+ * implementation of print_prot() short, we only check and pass
+ * _PAGE_INVALID and _PAGE_PROTECT flags to note_page() if a region,
+ * segment or page table entry is invalid or read-only.
+ * After all it's just a hint that the current level being walked
+ * contains an invalid or read-only entry.
  */
 static void walk_pte_level(struct seq_file *m, struct pg_state *st,
 			   pmd_t *pmd, unsigned long addr)
@@ -122,14 +122,14 @@
 	for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) {
 		st->current_address = addr;
 		pte = pte_offset_kernel(pmd, addr);
-		prot = pte_val(*pte) & (_PAGE_RO | _PAGE_INVALID);
+		prot = pte_val(*pte) & (_PAGE_PROTECT | _PAGE_INVALID);
 		note_page(m, st, prot, 4);
 		addr += PAGE_SIZE;
 	}
 }
 
 #ifdef CONFIG_64BIT
-#define _PMD_PROT_MASK (_SEGMENT_ENTRY_RO | _SEGMENT_ENTRY_CO)
+#define _PMD_PROT_MASK (_SEGMENT_ENTRY_PROTECT | _SEGMENT_ENTRY_CO)
 #else
 #define _PMD_PROT_MASK 0
 #endif
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 1f5315d1..5d758db 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -24,7 +24,7 @@
 	pte_t *ptep, pte;
 	struct page *page;
 
-	mask = (write ? _PAGE_RO : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
+	mask = (write ? _PAGE_PROTECT : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
 
 	ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
 	do {
@@ -55,8 +55,8 @@
 	struct page *head, *page, *tail;
 	int refs;
 
-	result = write ? 0 : _SEGMENT_ENTRY_RO;
-	mask = result | _SEGMENT_ENTRY_INV;
+	result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
+	mask = result | _SEGMENT_ENTRY_INVALID;
 	if ((pmd_val(pmd) & mask) != result)
 		return 0;
 	VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index 121089d..248445f 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -8,21 +8,127 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 
+static inline pmd_t __pte_to_pmd(pte_t pte)
+{
+	int none, young, prot;
+	pmd_t pmd;
+
+	/*
+	 * Convert encoding		  pte bits	  pmd bits
+	 *				.IR...wrdytp	..R...I...y.
+	 * empty			.10...000000 -> ..0...1...0.
+	 * prot-none, clean, old	.11...000001 -> ..0...1...1.
+	 * prot-none, clean, young	.11...000101 -> ..1...1...1.
+	 * prot-none, dirty, old	.10...001001 -> ..0...1...1.
+	 * prot-none, dirty, young	.10...001101 -> ..1...1...1.
+	 * read-only, clean, old	.11...010001 -> ..1...1...0.
+	 * read-only, clean, young	.01...010101 -> ..1...0...1.
+	 * read-only, dirty, old	.11...011001 -> ..1...1...0.
+	 * read-only, dirty, young	.01...011101 -> ..1...0...1.
+	 * read-write, clean, old	.11...110001 -> ..0...1...0.
+	 * read-write, clean, young	.01...110101 -> ..0...0...1.
+	 * read-write, dirty, old	.10...111001 -> ..0...1...0.
+	 * read-write, dirty, young	.00...111101 -> ..0...0...1.
+	 * Huge ptes are dirty by definition, a clean pte is made dirty
+	 * by the conversion.
+	 */
+	if (pte_present(pte)) {
+		pmd_val(pmd) = pte_val(pte) & PAGE_MASK;
+		if (pte_val(pte) & _PAGE_INVALID)
+			pmd_val(pmd) |= _SEGMENT_ENTRY_INVALID;
+		none = (pte_val(pte) & _PAGE_PRESENT) &&
+			!(pte_val(pte) & _PAGE_READ) &&
+			!(pte_val(pte) & _PAGE_WRITE);
+		prot = (pte_val(pte) & _PAGE_PROTECT) &&
+			!(pte_val(pte) & _PAGE_WRITE);
+		young = pte_val(pte) & _PAGE_YOUNG;
+		if (none || young)
+			pmd_val(pmd) |= _SEGMENT_ENTRY_YOUNG;
+		if (prot || (none && young))
+			pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
+	} else
+		pmd_val(pmd) = _SEGMENT_ENTRY_INVALID;
+	return pmd;
+}
+
+static inline pte_t __pmd_to_pte(pmd_t pmd)
+{
+	pte_t pte;
+
+	/*
+	 * Convert encoding	  pmd bits	  pte bits
+	 *			..R...I...y.	.IR...wrdytp
+	 * empty		..0...1...0. -> .10...000000
+	 * prot-none, old	..0...1...1. -> .10...001001
+	 * prot-none, young	..1...1...1. -> .10...001101
+	 * read-only, old	..1...1...0. -> .11...011001
+	 * read-only, young	..1...0...1. -> .01...011101
+	 * read-write, old	..0...1...0. -> .10...111001
+	 * read-write, young	..0...0...1. -> .00...111101
+	 * Huge ptes are dirty by definition
+	 */
+	if (pmd_present(pmd)) {
+		pte_val(pte) = _PAGE_PRESENT | _PAGE_LARGE | _PAGE_DIRTY |
+			(pmd_val(pmd) & PAGE_MASK);
+		if (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID)
+			pte_val(pte) |= _PAGE_INVALID;
+		if (pmd_prot_none(pmd)) {
+			if (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT)
+				pte_val(pte) |= _PAGE_YOUNG;
+		} else {
+			pte_val(pte) |= _PAGE_READ;
+			if (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT)
+				pte_val(pte) |= _PAGE_PROTECT;
+			else
+				pte_val(pte) |= _PAGE_WRITE;
+			if (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG)
+				pte_val(pte) |= _PAGE_YOUNG;
+		}
+	} else
+		pte_val(pte) = _PAGE_INVALID;
+	return pte;
+}
 
 void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
-				   pte_t *pteptr, pte_t pteval)
+		     pte_t *ptep, pte_t pte)
 {
-	pmd_t *pmdp = (pmd_t *) pteptr;
-	unsigned long mask;
+	pmd_t pmd;
 
+	pmd = __pte_to_pmd(pte);
 	if (!MACHINE_HAS_HPAGE) {
-		pteptr = (pte_t *) pte_page(pteval)[1].index;
-		mask = pte_val(pteval) &
-				(_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
-		pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
-	}
+		pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
+		pmd_val(pmd) |= pte_page(pte)[1].index;
+	} else
+		pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO;
+	*(pmd_t *) ptep = pmd;
+}
 
-	pmd_val(*pmdp) = pte_val(pteval);
+pte_t huge_ptep_get(pte_t *ptep)
+{
+	unsigned long origin;
+	pmd_t pmd;
+
+	pmd = *(pmd_t *) ptep;
+	if (!MACHINE_HAS_HPAGE && pmd_present(pmd)) {
+		origin = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN;
+		pmd_val(pmd) &= ~_SEGMENT_ENTRY_ORIGIN;
+		pmd_val(pmd) |= *(unsigned long *) origin;
+	}
+	return __pmd_to_pte(pmd);
+}
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+			      unsigned long addr, pte_t *ptep)
+{
+	pmd_t *pmdp = (pmd_t *) ptep;
+	pte_t pte = huge_ptep_get(ptep);
+
+	if (MACHINE_HAS_IDTE)
+		__pmd_idte(addr, pmdp);
+	else
+		__pmd_csp(pmdp);
+	pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
+	return pte;
 }
 
 int arch_prepare_hugepage(struct page *page)
@@ -58,7 +164,7 @@
 	ptep = (pte_t *) page[1].index;
 	if (!ptep)
 		return;
-	clear_table((unsigned long *) ptep, _PAGE_TYPE_EMPTY,
+	clear_table((unsigned long *) ptep, _PAGE_INVALID,
 		    PTRS_PER_PTE * sizeof(pte_t));
 	page_table_free(&init_mm, (unsigned long *) ptep);
 	page[1].index = 0;
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index 80adfbf..9903974 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -118,7 +118,7 @@
 		pte = pte_offset_kernel(pmd, address);
 		if (!enable) {
 			__ptep_ipte(address, pte);
-			pte_val(*pte) = _PAGE_TYPE_EMPTY;
+			pte_val(*pte) = _PAGE_INVALID;
 			continue;
 		}
 		pte_val(*pte) = __pa(address);
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index a8154a1..bf7c0dc 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -161,7 +161,7 @@
 	struct gmap_rmap *rmap;
 	struct page *page;
 
-	if (*table & _SEGMENT_ENTRY_INV)
+	if (*table & _SEGMENT_ENTRY_INVALID)
 		return 0;
 	page = pfn_to_page(*table >> PAGE_SHIFT);
 	mp = (struct gmap_pgtable *) page->index;
@@ -172,7 +172,7 @@
 		kfree(rmap);
 		break;
 	}
-	*table = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
+	*table = mp->vmaddr | _SEGMENT_ENTRY_INVALID | _SEGMENT_ENTRY_PROTECT;
 	return 1;
 }
 
@@ -258,7 +258,7 @@
 		return -ENOMEM;
 	new = (unsigned long *) page_to_phys(page);
 	crst_table_init(new, init);
-	if (*table & _REGION_ENTRY_INV) {
+	if (*table & _REGION_ENTRY_INVALID) {
 		list_add(&page->lru, &gmap->crst_list);
 		*table = (unsigned long) new | _REGION_ENTRY_LENGTH |
 			(*table & _REGION_ENTRY_TYPE_MASK);
@@ -292,22 +292,22 @@
 	for (off = 0; off < len; off += PMD_SIZE) {
 		/* Walk the guest addr space page table */
 		table = gmap->table + (((to + off) >> 53) & 0x7ff);
-		if (*table & _REGION_ENTRY_INV)
+		if (*table & _REGION_ENTRY_INVALID)
 			goto out;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + (((to + off) >> 42) & 0x7ff);
-		if (*table & _REGION_ENTRY_INV)
+		if (*table & _REGION_ENTRY_INVALID)
 			goto out;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + (((to + off) >> 31) & 0x7ff);
-		if (*table & _REGION_ENTRY_INV)
+		if (*table & _REGION_ENTRY_INVALID)
 			goto out;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + (((to + off) >> 20) & 0x7ff);
 
 		/* Clear segment table entry in guest address space. */
 		flush |= gmap_unlink_segment(gmap, table);
-		*table = _SEGMENT_ENTRY_INV;
+		*table = _SEGMENT_ENTRY_INVALID;
 	}
 out:
 	spin_unlock(&gmap->mm->page_table_lock);
@@ -335,7 +335,7 @@
 
 	if ((from | to | len) & (PMD_SIZE - 1))
 		return -EINVAL;
-	if (len == 0 || from + len > PGDIR_SIZE ||
+	if (len == 0 || from + len > TASK_MAX_SIZE ||
 	    from + len < from || to + len < to)
 		return -EINVAL;
 
@@ -345,17 +345,17 @@
 	for (off = 0; off < len; off += PMD_SIZE) {
 		/* Walk the gmap address space page table */
 		table = gmap->table + (((to + off) >> 53) & 0x7ff);
-		if ((*table & _REGION_ENTRY_INV) &&
+		if ((*table & _REGION_ENTRY_INVALID) &&
 		    gmap_alloc_table(gmap, table, _REGION2_ENTRY_EMPTY))
 			goto out_unmap;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + (((to + off) >> 42) & 0x7ff);
-		if ((*table & _REGION_ENTRY_INV) &&
+		if ((*table & _REGION_ENTRY_INVALID) &&
 		    gmap_alloc_table(gmap, table, _REGION3_ENTRY_EMPTY))
 			goto out_unmap;
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + (((to + off) >> 31) & 0x7ff);
-		if ((*table & _REGION_ENTRY_INV) &&
+		if ((*table & _REGION_ENTRY_INVALID) &&
 		    gmap_alloc_table(gmap, table, _SEGMENT_ENTRY_EMPTY))
 			goto out_unmap;
 		table = (unsigned long *) (*table & _REGION_ENTRY_ORIGIN);
@@ -363,7 +363,8 @@
 
 		/* Store 'from' address in an invalid segment table entry. */
 		flush |= gmap_unlink_segment(gmap, table);
-		*table = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | (from + off);
+		*table =  (from + off) | (_SEGMENT_ENTRY_INVALID |
+					  _SEGMENT_ENTRY_PROTECT);
 	}
 	spin_unlock(&gmap->mm->page_table_lock);
 	up_read(&gmap->mm->mmap_sem);
@@ -384,15 +385,15 @@
 	unsigned long *table;
 
 	table = gmap->table + ((address >> 53) & 0x7ff);
-	if (unlikely(*table & _REGION_ENTRY_INV))
+	if (unlikely(*table & _REGION_ENTRY_INVALID))
 		return ERR_PTR(-EFAULT);
 	table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 	table = table + ((address >> 42) & 0x7ff);
-	if (unlikely(*table & _REGION_ENTRY_INV))
+	if (unlikely(*table & _REGION_ENTRY_INVALID))
 		return ERR_PTR(-EFAULT);
 	table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 	table = table + ((address >> 31) & 0x7ff);
-	if (unlikely(*table & _REGION_ENTRY_INV))
+	if (unlikely(*table & _REGION_ENTRY_INVALID))
 		return ERR_PTR(-EFAULT);
 	table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 	table = table + ((address >> 20) & 0x7ff);
@@ -422,11 +423,11 @@
 		return PTR_ERR(segment_ptr);
 	/* Convert the gmap address to an mm address. */
 	segment = *segment_ptr;
-	if (!(segment & _SEGMENT_ENTRY_INV)) {
+	if (!(segment & _SEGMENT_ENTRY_INVALID)) {
 		page = pfn_to_page(segment >> PAGE_SHIFT);
 		mp = (struct gmap_pgtable *) page->index;
 		return mp->vmaddr | (address & ~PMD_MASK);
-	} else if (segment & _SEGMENT_ENTRY_RO) {
+	} else if (segment & _SEGMENT_ENTRY_PROTECT) {
 		vmaddr = segment & _SEGMENT_ENTRY_ORIGIN;
 		return vmaddr | (address & ~PMD_MASK);
 	}
@@ -517,8 +518,8 @@
 	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
 	mp = (struct gmap_pgtable *) page->index;
 	list_for_each_entry_safe(rmap, next, &mp->mapper, list) {
-		*rmap->entry =
-			_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
+		*rmap->entry = mp->vmaddr | (_SEGMENT_ENTRY_INVALID |
+					     _SEGMENT_ENTRY_PROTECT);
 		list_del(&rmap->list);
 		kfree(rmap);
 		flush = 1;
@@ -545,13 +546,13 @@
 	/* Convert the gmap address to an mm address. */
 	while (1) {
 		segment = *segment_ptr;
-		if (!(segment & _SEGMENT_ENTRY_INV)) {
+		if (!(segment & _SEGMENT_ENTRY_INVALID)) {
 			/* Page table is present */
 			page = pfn_to_page(segment >> PAGE_SHIFT);
 			mp = (struct gmap_pgtable *) page->index;
 			return mp->vmaddr | (address & ~PMD_MASK);
 		}
-		if (!(segment & _SEGMENT_ENTRY_RO))
+		if (!(segment & _SEGMENT_ENTRY_PROTECT))
 			/* Nothing mapped in the gmap address space. */
 			break;
 		rc = gmap_connect_pgtable(address, segment, segment_ptr, gmap);
@@ -586,25 +587,25 @@
 	while (address < to) {
 		/* Walk the gmap address space page table */
 		table = gmap->table + ((address >> 53) & 0x7ff);
-		if (unlikely(*table & _REGION_ENTRY_INV)) {
+		if (unlikely(*table & _REGION_ENTRY_INVALID)) {
 			address = (address + PMD_SIZE) & PMD_MASK;
 			continue;
 		}
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + ((address >> 42) & 0x7ff);
-		if (unlikely(*table & _REGION_ENTRY_INV)) {
+		if (unlikely(*table & _REGION_ENTRY_INVALID)) {
 			address = (address + PMD_SIZE) & PMD_MASK;
 			continue;
 		}
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + ((address >> 31) & 0x7ff);
-		if (unlikely(*table & _REGION_ENTRY_INV)) {
+		if (unlikely(*table & _REGION_ENTRY_INVALID)) {
 			address = (address + PMD_SIZE) & PMD_MASK;
 			continue;
 		}
 		table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
 		table = table + ((address >> 20) & 0x7ff);
-		if (unlikely(*table & _SEGMENT_ENTRY_INV)) {
+		if (unlikely(*table & _SEGMENT_ENTRY_INVALID)) {
 			address = (address + PMD_SIZE) & PMD_MASK;
 			continue;
 		}
@@ -687,7 +688,7 @@
 			continue;
 		/* Set notification bit in the pgste of the pte */
 		entry = *ptep;
-		if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_RO)) == 0) {
+		if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) {
 			pgste = pgste_get_lock(ptep);
 			pgste_val(pgste) |= PGSTE_IN_BIT;
 			pgste_set_unlock(ptep, pgste);
@@ -731,6 +732,11 @@
 	spin_unlock(&gmap_notifier_lock);
 }
 
+static inline int page_table_with_pgste(struct page *page)
+{
+	return atomic_read(&page->_mapcount) == 0;
+}
+
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
 						    unsigned long vmaddr)
 {
@@ -750,10 +756,11 @@
 	mp->vmaddr = vmaddr & PMD_MASK;
 	INIT_LIST_HEAD(&mp->mapper);
 	page->index = (unsigned long) mp;
-	atomic_set(&page->_mapcount, 3);
+	atomic_set(&page->_mapcount, 0);
 	table = (unsigned long *) page_to_phys(page);
-	clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE/2);
-	clear_table(table + PTRS_PER_PTE, 0, PAGE_SIZE/2);
+	clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
+	clear_table(table + PTRS_PER_PTE, PGSTE_HR_BIT | PGSTE_HC_BIT,
+		    PAGE_SIZE/2);
 	return table;
 }
 
@@ -791,26 +798,21 @@
 	pgste_val(new) |= (key & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48;
 	pgste_val(new) |= (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
 	if (!(pte_val(*ptep) & _PAGE_INVALID)) {
-		unsigned long address, bits;
-		unsigned char skey;
+		unsigned long address, bits, skey;
 
 		address = pte_val(*ptep) & PAGE_MASK;
-		skey = page_get_storage_key(address);
+		skey = (unsigned long) page_get_storage_key(address);
 		bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
+		skey = key & (_PAGE_ACC_BITS | _PAGE_FP_BIT);
 		/* Set storage key ACC and FP */
-		page_set_storage_key(address,
-				(key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)),
-				!nq);
-
+		page_set_storage_key(address, skey, !nq);
 		/* Merge host changed & referenced into pgste  */
 		pgste_val(new) |= bits << 52;
-		/* Transfer skey changed & referenced bit to kvm user bits */
-		pgste_val(new) |= bits << 45;	/* PGSTE_UR_BIT & PGSTE_UC_BIT */
 	}
 	/* changing the guest storage key is considered a change of the page */
 	if ((pgste_val(new) ^ pgste_val(old)) &
 	    (PGSTE_ACC_BITS | PGSTE_FP_BIT | PGSTE_GR_BIT | PGSTE_GC_BIT))
-		pgste_val(new) |= PGSTE_UC_BIT;
+		pgste_val(new) |= PGSTE_HC_BIT;
 
 	pgste_set_unlock(ptep, new);
 	pte_unmap_unlock(*ptep, ptl);
@@ -821,6 +823,11 @@
 
 #else /* CONFIG_PGSTE */
 
+static inline int page_table_with_pgste(struct page *page)
+{
+	return 0;
+}
+
 static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
 						    unsigned long vmaddr)
 {
@@ -878,7 +885,7 @@
 		pgtable_page_ctor(page);
 		atomic_set(&page->_mapcount, 1);
 		table = (unsigned long *) page_to_phys(page);
-		clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+		clear_table(table, _PAGE_INVALID, PAGE_SIZE);
 		spin_lock_bh(&mm->context.list_lock);
 		list_add(&page->lru, &mm->context.pgtable_list);
 	} else {
@@ -897,12 +904,12 @@
 	struct page *page;
 	unsigned int bit, mask;
 
-	if (mm_has_pgste(mm)) {
+	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+	if (page_table_with_pgste(page)) {
 		gmap_disconnect_pgtable(mm, table);
 		return page_table_free_pgste(table);
 	}
 	/* Free 1K/2K page table fragment of a 4K page */
-	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
 	bit = 1 << ((__pa(table) & ~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t)));
 	spin_lock_bh(&mm->context.list_lock);
 	if ((atomic_read(&page->_mapcount) & FRAG_MASK) != FRAG_MASK)
@@ -940,14 +947,14 @@
 	unsigned int bit, mask;
 
 	mm = tlb->mm;
-	if (mm_has_pgste(mm)) {
+	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+	if (page_table_with_pgste(page)) {
 		gmap_disconnect_pgtable(mm, table);
 		table = (unsigned long *) (__pa(table) | FRAG_MASK);
 		tlb_remove_table(tlb, table);
 		return;
 	}
 	bit = 1 << ((__pa(table) & ~PAGE_MASK) / (PTRS_PER_PTE*sizeof(pte_t)));
-	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
 	spin_lock_bh(&mm->context.list_lock);
 	if ((atomic_read(&page->_mapcount) & FRAG_MASK) != FRAG_MASK)
 		list_del(&page->lru);
@@ -1007,7 +1014,6 @@
 	struct mmu_table_batch **batch = &tlb->batch;
 
 	if (*batch) {
-		__tlb_flush_mm(tlb->mm);
 		call_rcu_sched(&(*batch)->rcu, tlb_remove_table_rcu);
 		*batch = NULL;
 	}
@@ -1017,11 +1023,12 @@
 {
 	struct mmu_table_batch **batch = &tlb->batch;
 
+	tlb->mm->context.flush_mm = 1;
 	if (*batch == NULL) {
 		*batch = (struct mmu_table_batch *)
 			__get_free_page(GFP_NOWAIT | __GFP_NOWARN);
 		if (*batch == NULL) {
-			__tlb_flush_mm(tlb->mm);
+			__tlb_flush_mm_lazy(tlb->mm);
 			tlb_remove_table_one(table);
 			return;
 		}
@@ -1029,40 +1036,124 @@
 	}
 	(*batch)->tables[(*batch)->nr++] = table;
 	if ((*batch)->nr == MAX_TABLE_BATCH)
-		tlb_table_flush(tlb);
+		tlb_flush_mmu(tlb);
 }
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-void thp_split_vma(struct vm_area_struct *vma)
+static inline void thp_split_vma(struct vm_area_struct *vma)
 {
 	unsigned long addr;
-	struct page *page;
 
-	for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
-		page = follow_page(vma, addr, FOLL_SPLIT);
-	}
+	for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE)
+		follow_page(vma, addr, FOLL_SPLIT);
 }
 
-void thp_split_mm(struct mm_struct *mm)
+static inline void thp_split_mm(struct mm_struct *mm)
 {
-	struct vm_area_struct *vma = mm->mmap;
+	struct vm_area_struct *vma;
 
-	while (vma != NULL) {
+	for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
 		thp_split_vma(vma);
 		vma->vm_flags &= ~VM_HUGEPAGE;
 		vma->vm_flags |= VM_NOHUGEPAGE;
-		vma = vma->vm_next;
 	}
+	mm->def_flags |= VM_NOHUGEPAGE;
+}
+#else
+static inline void thp_split_mm(struct mm_struct *mm)
+{
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+static unsigned long page_table_realloc_pmd(struct mmu_gather *tlb,
+				struct mm_struct *mm, pud_t *pud,
+				unsigned long addr, unsigned long end)
+{
+	unsigned long next, *table, *new;
+	struct page *page;
+	pmd_t *pmd;
+
+	pmd = pmd_offset(pud, addr);
+	do {
+		next = pmd_addr_end(addr, end);
+again:
+		if (pmd_none_or_clear_bad(pmd))
+			continue;
+		table = (unsigned long *) pmd_deref(*pmd);
+		page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+		if (page_table_with_pgste(page))
+			continue;
+		/* Allocate new page table with pgstes */
+		new = page_table_alloc_pgste(mm, addr);
+		if (!new) {
+			mm->context.has_pgste = 0;
+			continue;
+		}
+		spin_lock(&mm->page_table_lock);
+		if (likely((unsigned long *) pmd_deref(*pmd) == table)) {
+			/* Nuke pmd entry pointing to the "short" page table */
+			pmdp_flush_lazy(mm, addr, pmd);
+			pmd_clear(pmd);
+			/* Copy ptes from old table to new table */
+			memcpy(new, table, PAGE_SIZE/2);
+			clear_table(table, _PAGE_INVALID, PAGE_SIZE/2);
+			/* Establish new table */
+			pmd_populate(mm, pmd, (pte_t *) new);
+			/* Free old table with rcu, there might be a walker! */
+			page_table_free_rcu(tlb, table);
+			new = NULL;
+		}
+		spin_unlock(&mm->page_table_lock);
+		if (new) {
+			page_table_free_pgste(new);
+			goto again;
+		}
+	} while (pmd++, addr = next, addr != end);
+
+	return addr;
+}
+
+static unsigned long page_table_realloc_pud(struct mmu_gather *tlb,
+				   struct mm_struct *mm, pgd_t *pgd,
+				   unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pud_t *pud;
+
+	pud = pud_offset(pgd, addr);
+	do {
+		next = pud_addr_end(addr, end);
+		if (pud_none_or_clear_bad(pud))
+			continue;
+		next = page_table_realloc_pmd(tlb, mm, pud, addr, next);
+	} while (pud++, addr = next, addr != end);
+
+	return addr;
+}
+
+static void page_table_realloc(struct mmu_gather *tlb, struct mm_struct *mm,
+			       unsigned long addr, unsigned long end)
+{
+	unsigned long next;
+	pgd_t *pgd;
+
+	pgd = pgd_offset(mm, addr);
+	do {
+		next = pgd_addr_end(addr, end);
+		if (pgd_none_or_clear_bad(pgd))
+			continue;
+		next = page_table_realloc_pud(tlb, mm, pgd, addr, next);
+	} while (pgd++, addr = next, addr != end);
+}
+
 /*
  * switch on pgstes for its userspace process (for kvm)
  */
 int s390_enable_sie(void)
 {
 	struct task_struct *tsk = current;
-	struct mm_struct *mm, *old_mm;
+	struct mm_struct *mm = tsk->mm;
+	struct mmu_gather tlb;
 
 	/* Do we have switched amode? If no, we cannot do sie */
 	if (s390_user_mode == HOME_SPACE_MODE)
@@ -1072,57 +1163,16 @@
 	if (mm_has_pgste(tsk->mm))
 		return 0;
 
-	/* lets check if we are allowed to replace the mm */
-	task_lock(tsk);
-	if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
-#ifdef CONFIG_AIO
-	    !hlist_empty(&tsk->mm->ioctx_list) ||
-#endif
-	    tsk->mm != tsk->active_mm) {
-		task_unlock(tsk);
-		return -EINVAL;
-	}
-	task_unlock(tsk);
-
-	/* we copy the mm and let dup_mm create the page tables with_pgstes */
-	tsk->mm->context.alloc_pgste = 1;
-	/* make sure that both mms have a correct rss state */
-	sync_mm_rss(tsk->mm);
-	mm = dup_mm(tsk);
-	tsk->mm->context.alloc_pgste = 0;
-	if (!mm)
-		return -ENOMEM;
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+	down_write(&mm->mmap_sem);
 	/* split thp mappings and disable thp for future mappings */
 	thp_split_mm(mm);
-	mm->def_flags |= VM_NOHUGEPAGE;
-#endif
-
-	/* Now lets check again if something happened */
-	task_lock(tsk);
-	if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
-#ifdef CONFIG_AIO
-	    !hlist_empty(&tsk->mm->ioctx_list) ||
-#endif
-	    tsk->mm != tsk->active_mm) {
-		mmput(mm);
-		task_unlock(tsk);
-		return -EINVAL;
-	}
-
-	/* ok, we are alone. No ptrace, no threads, etc. */
-	old_mm = tsk->mm;
-	tsk->mm = tsk->active_mm = mm;
-	preempt_disable();
-	update_mm(mm, tsk);
-	atomic_inc(&mm->context.attach_count);
-	atomic_dec(&old_mm->context.attach_count);
-	cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-	preempt_enable();
-	task_unlock(tsk);
-	mmput(old_mm);
-	return 0;
+	/* Reallocate the page tables with pgstes */
+	mm->context.has_pgste = 1;
+	tlb_gather_mmu(&tlb, mm, 0, TASK_SIZE);
+	page_table_realloc(&tlb, mm, 0, TASK_SIZE);
+	tlb_finish_mmu(&tlb, 0, TASK_SIZE);
+	up_write(&mm->mmap_sem);
+	return mm->context.has_pgste ? 0 : -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(s390_enable_sie);
 
@@ -1198,9 +1248,9 @@
 		list_del(lh);
 	}
 	ptep = (pte_t *) pgtable;
-	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+	pte_val(*ptep) = _PAGE_INVALID;
 	ptep++;
-	pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+	pte_val(*ptep) = _PAGE_INVALID;
 	return pgtable;
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 8b268fc..bcfb70b 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -69,7 +69,7 @@
 		pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t));
 	if (!pte)
 		return NULL;
-	clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
+	clear_table((unsigned long *) pte, _PAGE_INVALID,
 		    PTRS_PER_PTE * sizeof(pte_t));
 	return pte;
 }
@@ -101,7 +101,7 @@
 		    !(address & ~PUD_MASK) && (address + PUD_SIZE <= end)) {
 			pud_val(*pu_dir) = __pa(address) |
 				_REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE |
-				(ro ? _REGION_ENTRY_RO : 0);
+				(ro ? _REGION_ENTRY_PROTECT : 0);
 			address += PUD_SIZE;
 			continue;
 		}
@@ -118,7 +118,8 @@
 		    !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) {
 			pmd_val(*pm_dir) = __pa(address) |
 				_SEGMENT_ENTRY | _SEGMENT_ENTRY_LARGE |
-				(ro ? _SEGMENT_ENTRY_RO : 0);
+				_SEGMENT_ENTRY_YOUNG |
+				(ro ? _SEGMENT_ENTRY_PROTECT : 0);
 			address += PMD_SIZE;
 			continue;
 		}
@@ -131,7 +132,8 @@
 		}
 
 		pt_dir = pte_offset_kernel(pm_dir, address);
-		pte_val(*pt_dir) = __pa(address) | (ro ? _PAGE_RO : 0);
+		pte_val(*pt_dir) = __pa(address) |
+			pgprot_val(ro ? PAGE_KERNEL_RO : PAGE_KERNEL);
 		address += PAGE_SIZE;
 	}
 	ret = 0;
@@ -154,7 +156,7 @@
 	pte_t *pt_dir;
 	pte_t  pte;
 
-	pte_val(pte) = _PAGE_TYPE_EMPTY;
+	pte_val(pte) = _PAGE_INVALID;
 	while (address < end) {
 		pg_dir = pgd_offset_k(address);
 		if (pgd_none(*pg_dir)) {
@@ -255,7 +257,8 @@
 			new_page =__pa(vmem_alloc_pages(0));
 			if (!new_page)
 				goto out;
-			pte_val(*pt_dir) = __pa(new_page);
+			pte_val(*pt_dir) =
+				__pa(new_page) | pgprot_val(PAGE_KERNEL);
 		}
 		address += PAGE_SIZE;
 	}
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile
index 086a2e3..a9e1dc4 100644
--- a/arch/s390/pci/Makefile
+++ b/arch/s390/pci/Makefile
@@ -2,5 +2,5 @@
 # Makefile for the s390 PCI subsystem.
 #
 
-obj-$(CONFIG_PCI)	+= pci.o pci_dma.o pci_clp.o pci_msi.o pci_sysfs.o \
+obj-$(CONFIG_PCI)	+= pci.o pci_dma.o pci_clp.o pci_sysfs.o \
 			   pci_event.o pci_debug.o pci_insn.o
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index e2956ad..f17a834 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -42,45 +42,26 @@
 #define	SIC_IRQ_MODE_SINGLE		1
 
 #define ZPCI_NR_DMA_SPACES		1
-#define ZPCI_MSI_VEC_BITS		6
 #define ZPCI_NR_DEVICES			CONFIG_PCI_NR_FUNCTIONS
 
 /* list of all detected zpci devices */
-LIST_HEAD(zpci_list);
-EXPORT_SYMBOL_GPL(zpci_list);
-DEFINE_MUTEX(zpci_list_lock);
-EXPORT_SYMBOL_GPL(zpci_list_lock);
+static LIST_HEAD(zpci_list);
+static DEFINE_SPINLOCK(zpci_list_lock);
 
-static struct pci_hp_callback_ops *hotplug_ops;
+static void zpci_enable_irq(struct irq_data *data);
+static void zpci_disable_irq(struct irq_data *data);
+
+static struct irq_chip zpci_irq_chip = {
+	.name = "zPCI",
+	.irq_unmask = zpci_enable_irq,
+	.irq_mask = zpci_disable_irq,
+};
 
 static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
 static DEFINE_SPINLOCK(zpci_domain_lock);
 
-struct callback {
-	irq_handler_t	handler;
-	void		*data;
-};
-
-struct zdev_irq_map {
-	unsigned long	aibv;		/* AI bit vector */
-	int		msi_vecs;	/* consecutive MSI-vectors used */
-	int		__unused;
-	struct callback	cb[ZPCI_NR_MSI_VECS]; /* callback handler array */
-	spinlock_t	lock;		/* protect callbacks against de-reg */
-};
-
-struct intr_bucket {
-	/* amap of adapters, one bit per dev, corresponds to one irq nr */
-	unsigned long	*alloc;
-	/* AI summary bit, global page for all devices */
-	unsigned long	*aisb;
-	/* pointer to aibv and callback data in zdev */
-	struct zdev_irq_map *imap[ZPCI_NR_DEVICES];
-	/* protects the whole bucket struct */
-	spinlock_t	lock;
-};
-
-static struct intr_bucket *bucket;
+static struct airq_iv *zpci_aisb_iv;
+static struct airq_iv *zpci_aibv[ZPCI_NR_DEVICES];
 
 /* Adapter interrupt definitions */
 static void zpci_irq_handler(struct airq_struct *airq);
@@ -96,27 +77,8 @@
 struct zpci_iomap_entry *zpci_iomap_start;
 EXPORT_SYMBOL_GPL(zpci_iomap_start);
 
-/* highest irq summary bit */
-static int __read_mostly aisb_max;
-
-static struct kmem_cache *zdev_irq_cache;
 static struct kmem_cache *zdev_fmb_cache;
 
-static inline int irq_to_msi_nr(unsigned int irq)
-{
-	return irq & ZPCI_MSI_MASK;
-}
-
-static inline int irq_to_dev_nr(unsigned int irq)
-{
-	return irq >> ZPCI_MSI_VEC_BITS;
-}
-
-static inline struct zdev_irq_map *get_imap(unsigned int irq)
-{
-	return bucket->imap[irq_to_dev_nr(irq)];
-}
-
 struct zpci_dev *get_zdev(struct pci_dev *pdev)
 {
 	return (struct zpci_dev *) pdev->sysdata;
@@ -126,22 +88,17 @@
 {
 	struct zpci_dev *tmp, *zdev = NULL;
 
-	mutex_lock(&zpci_list_lock);
+	spin_lock(&zpci_list_lock);
 	list_for_each_entry(tmp, &zpci_list, entry) {
 		if (tmp->fid == fid) {
 			zdev = tmp;
 			break;
 		}
 	}
-	mutex_unlock(&zpci_list_lock);
+	spin_unlock(&zpci_list_lock);
 	return zdev;
 }
 
-bool zpci_fid_present(u32 fid)
-{
-	return (get_zdev_by_fid(fid) != NULL) ? true : false;
-}
-
 static struct zpci_dev *get_zdev_by_bus(struct pci_bus *bus)
 {
 	return (bus && bus->sysdata) ? (struct zpci_dev *) bus->sysdata : NULL;
@@ -160,8 +117,7 @@
 EXPORT_SYMBOL_GPL(pci_proc_domain);
 
 /* Modify PCI: Register adapter interruptions */
-static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb,
-			      u64 aibv)
+static int zpci_set_airq(struct zpci_dev *zdev)
 {
 	u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT);
 	struct zpci_fib *fib;
@@ -172,14 +128,14 @@
 		return -ENOMEM;
 
 	fib->isc = PCI_ISC;
-	fib->noi = zdev->irq_map->msi_vecs;
 	fib->sum = 1;		/* enable summary notifications */
-	fib->aibv = aibv;
-	fib->aibvo = 0;		/* every function has its own page */
-	fib->aisb = (u64) bucket->aisb + aisb / 8;
-	fib->aisbo = aisb & ZPCI_MSI_MASK;
+	fib->noi = airq_iv_end(zdev->aibv);
+	fib->aibv = (unsigned long) zdev->aibv->vector;
+	fib->aibvo = 0;		/* each zdev has its own interrupt vector */
+	fib->aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8;
+	fib->aisbo = zdev->aisb & 63;
 
-	rc = s390pci_mod_fc(req, fib);
+	rc = zpci_mod_fc(req, fib);
 	pr_debug("%s mpcifc returned noi: %d\n", __func__, fib->noi);
 
 	free_page((unsigned long) fib);
@@ -209,7 +165,7 @@
 	fib->iota = args->iota;
 	fib->fmb_addr = args->fmb_addr;
 
-	rc = s390pci_mod_fc(req, fib);
+	rc = zpci_mod_fc(req, fib);
 	free_page((unsigned long) fib);
 	return rc;
 }
@@ -234,7 +190,7 @@
 }
 
 /* Modify PCI: Unregister adapter interruptions */
-static int zpci_unregister_airq(struct zpci_dev *zdev)
+static int zpci_clear_airq(struct zpci_dev *zdev)
 {
 	struct mod_pci_args args = { 0, 0, 0, 0 };
 
@@ -283,7 +239,7 @@
 	u64 data;
 	int rc;
 
-	rc = s390pci_load(&data, req, offset);
+	rc = zpci_load(&data, req, offset);
 	if (!rc) {
 		data = data << ((8 - len) * 8);
 		data = le64_to_cpu(data);
@@ -301,25 +257,46 @@
 
 	data = cpu_to_le64(data);
 	data = data >> ((8 - len) * 8);
-	rc = s390pci_store(data, req, offset);
+	rc = zpci_store(data, req, offset);
 	return rc;
 }
 
-void enable_irq(unsigned int irq)
+static int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag)
 {
-	struct msi_desc *msi = irq_get_msi_desc(irq);
+	int offset, pos;
+	u32 mask_bits;
+
+	if (msi->msi_attrib.is_msix) {
+		offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_VECTOR_CTRL;
+		msi->masked = readl(msi->mask_base + offset);
+		writel(flag, msi->mask_base + offset);
+	} else if (msi->msi_attrib.maskbit) {
+		pos = (long) msi->mask_base;
+		pci_read_config_dword(msi->dev, pos, &mask_bits);
+		mask_bits &= ~(mask);
+		mask_bits |= flag & mask;
+		pci_write_config_dword(msi->dev, pos, mask_bits);
+	} else
+		return 0;
+
+	msi->msi_attrib.maskbit = !!flag;
+	return 1;
+}
+
+static void zpci_enable_irq(struct irq_data *data)
+{
+	struct msi_desc *msi = irq_get_msi_desc(data->irq);
 
 	zpci_msi_set_mask_bits(msi, 1, 0);
 }
-EXPORT_SYMBOL_GPL(enable_irq);
 
-void disable_irq(unsigned int irq)
+static void zpci_disable_irq(struct irq_data *data)
 {
-	struct msi_desc *msi = irq_get_msi_desc(irq);
+	struct msi_desc *msi = irq_get_msi_desc(data->irq);
 
 	zpci_msi_set_mask_bits(msi, 1, 1);
 }
-EXPORT_SYMBOL_GPL(disable_irq);
 
 void pcibios_fixup_bus(struct pci_bus *bus)
 {
@@ -404,152 +381,147 @@
 	.write = pci_write,
 };
 
-/* store the last handled bit to implement fair scheduling of devices */
-static DEFINE_PER_CPU(unsigned long, next_sbit);
-
 static void zpci_irq_handler(struct airq_struct *airq)
 {
-	unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit);
-	int rescan = 0, max = aisb_max;
-	struct zdev_irq_map *imap;
+	unsigned long si, ai;
+	struct airq_iv *aibv;
+	int irqs_on = 0;
 
 	inc_irq_stat(IRQIO_PCI);
-	sbit = start;
+	for (si = 0;;) {
+		/* Scan adapter summary indicator bit vector */
+		si = airq_iv_scan(zpci_aisb_iv, si, airq_iv_end(zpci_aisb_iv));
+		if (si == -1UL) {
+			if (irqs_on++)
+				/* End of second scan with interrupts on. */
+				break;
+			/* First scan complete, reenable interrupts. */
+			zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+			si = 0;
+			continue;
+		}
 
-scan:
-	/* find summary_bit */
-	for_each_set_bit_left_cont(sbit, bucket->aisb, max) {
-		clear_bit(63 - (sbit & 63), bucket->aisb + (sbit >> 6));
-		last = sbit;
-
-		/* find vector bit */
-		imap = bucket->imap[sbit];
-		for_each_set_bit_left(mbit, &imap->aibv, imap->msi_vecs) {
+		/* Scan the adapter interrupt vector for this device. */
+		aibv = zpci_aibv[si];
+		for (ai = 0;;) {
+			ai = airq_iv_scan(aibv, ai, airq_iv_end(aibv));
+			if (ai == -1UL)
+				break;
 			inc_irq_stat(IRQIO_MSI);
-			clear_bit(63 - mbit, &imap->aibv);
-
-			spin_lock(&imap->lock);
-			if (imap->cb[mbit].handler)
-				imap->cb[mbit].handler(mbit,
-					imap->cb[mbit].data);
-			spin_unlock(&imap->lock);
+			airq_iv_lock(aibv, ai);
+			generic_handle_irq(airq_iv_get_data(aibv, ai));
+			airq_iv_unlock(aibv, ai);
 		}
 	}
-
-	if (rescan)
-		goto out;
-
-	/* scan the skipped bits */
-	if (start > 0) {
-		sbit = 0;
-		max = start;
-		start = 0;
-		goto scan;
-	}
-
-	/* enable interrupts again */
-	set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
-
-	/* check again to not lose initiative */
-	rmb();
-	max = aisb_max;
-	sbit = find_first_bit_left(bucket->aisb, max);
-	if (sbit != max) {
-		rescan++;
-		goto scan;
-	}
-out:
-	/* store next device bit to scan */
-	__get_cpu_var(next_sbit) = (++last >= aisb_max) ? 0 : last;
 }
 
-/* msi_vecs - number of requested interrupts, 0 place function to error state */
-static int zpci_setup_msi(struct pci_dev *pdev, int msi_vecs)
+int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
 {
 	struct zpci_dev *zdev = get_zdev(pdev);
-	unsigned int aisb, msi_nr;
+	unsigned int hwirq, irq, msi_vecs;
+	unsigned long aisb;
+	struct msi_desc *msi;
+	struct msi_msg msg;
+	int rc;
+
+	pr_debug("%s: requesting %d MSI-X interrupts...", __func__, nvec);
+	if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI)
+		return -EINVAL;
+	msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX);
+	msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI);
+
+	/* Allocate adapter summary indicator bit */
+	rc = -EIO;
+	aisb = airq_iv_alloc_bit(zpci_aisb_iv);
+	if (aisb == -1UL)
+		goto out;
+	zdev->aisb = aisb;
+
+	/* Create adapter interrupt vector */
+	rc = -ENOMEM;
+	zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK);
+	if (!zdev->aibv)
+		goto out_si;
+
+	/* Wire up shortcut pointer */
+	zpci_aibv[aisb] = zdev->aibv;
+
+	/* Request MSI interrupts */
+	hwirq = 0;
+	list_for_each_entry(msi, &pdev->msi_list, list) {
+		rc = -EIO;
+		irq = irq_alloc_desc(0);	/* Alloc irq on node 0 */
+		if (irq == NO_IRQ)
+			goto out_msi;
+		rc = irq_set_msi_desc(irq, msi);
+		if (rc)
+			goto out_msi;
+		irq_set_chip_and_handler(irq, &zpci_irq_chip,
+					 handle_simple_irq);
+		msg.data = hwirq;
+		msg.address_lo = zdev->msi_addr & 0xffffffff;
+		msg.address_hi = zdev->msi_addr >> 32;
+		write_msi_msg(irq, &msg);
+		airq_iv_set_data(zdev->aibv, hwirq, irq);
+		hwirq++;
+	}
+
+	/* Enable adapter interrupts */
+	rc = zpci_set_airq(zdev);
+	if (rc)
+		goto out_msi;
+
+	return (msi_vecs == nvec) ? 0 : msi_vecs;
+
+out_msi:
+	list_for_each_entry(msi, &pdev->msi_list, list) {
+		if (hwirq-- == 0)
+			break;
+		irq_set_msi_desc(msi->irq, NULL);
+		irq_free_desc(msi->irq);
+		msi->msg.address_lo = 0;
+		msi->msg.address_hi = 0;
+		msi->msg.data = 0;
+		msi->irq = 0;
+	}
+	zpci_aibv[aisb] = NULL;
+	airq_iv_release(zdev->aibv);
+out_si:
+	airq_iv_free_bit(zpci_aisb_iv, aisb);
+out:
+	dev_err(&pdev->dev, "register MSI failed with: %d\n", rc);
+	return rc;
+}
+
+void arch_teardown_msi_irqs(struct pci_dev *pdev)
+{
+	struct zpci_dev *zdev = get_zdev(pdev);
 	struct msi_desc *msi;
 	int rc;
 
-	/* store the number of used MSI vectors */
-	zdev->irq_map->msi_vecs = min(msi_vecs, ZPCI_NR_MSI_VECS);
+	pr_info("%s: on pdev: %p\n", __func__, pdev);
 
-	spin_lock(&bucket->lock);
-	aisb = find_first_zero_bit(bucket->alloc, PAGE_SIZE);
-	/* alloc map exhausted? */
-	if (aisb == PAGE_SIZE) {
-		spin_unlock(&bucket->lock);
-		return -EIO;
-	}
-	set_bit(aisb, bucket->alloc);
-	spin_unlock(&bucket->lock);
-
-	zdev->aisb = aisb;
-	if (aisb + 1 > aisb_max)
-		aisb_max = aisb + 1;
-
-	/* wire up IRQ shortcut pointer */
-	bucket->imap[zdev->aisb] = zdev->irq_map;
-	pr_debug("%s: imap[%u] linked to %p\n", __func__, zdev->aisb, zdev->irq_map);
-
-	/* TODO: irq number 0 wont be found if we return less than requested MSIs.
-	 * ignore it for now and fix in common code.
-	 */
-	msi_nr = aisb << ZPCI_MSI_VEC_BITS;
-
-	list_for_each_entry(msi, &pdev->msi_list, list) {
-		rc = zpci_setup_msi_irq(zdev, msi, msi_nr,
-					  aisb << ZPCI_MSI_VEC_BITS);
-		if (rc)
-			return rc;
-		msi_nr++;
-	}
-
-	rc = zpci_register_airq(zdev, aisb, (u64) &zdev->irq_map->aibv);
-	if (rc) {
-		clear_bit(aisb, bucket->alloc);
-		dev_err(&pdev->dev, "register MSI failed with: %d\n", rc);
-		return rc;
-	}
-	return (zdev->irq_map->msi_vecs == msi_vecs) ?
-		0 : zdev->irq_map->msi_vecs;
-}
-
-static void zpci_teardown_msi(struct pci_dev *pdev)
-{
-	struct zpci_dev *zdev = get_zdev(pdev);
-	struct msi_desc *msi;
-	int aisb, rc;
-
-	rc = zpci_unregister_airq(zdev);
+	/* Disable adapter interrupts */
+	rc = zpci_clear_airq(zdev);
 	if (rc) {
 		dev_err(&pdev->dev, "deregister MSI failed with: %d\n", rc);
 		return;
 	}
 
-	msi = list_first_entry(&pdev->msi_list, struct msi_desc, list);
-	aisb = irq_to_dev_nr(msi->irq);
+	/* Release MSI interrupts */
+	list_for_each_entry(msi, &pdev->msi_list, list) {
+		zpci_msi_set_mask_bits(msi, 1, 1);
+		irq_set_msi_desc(msi->irq, NULL);
+		irq_free_desc(msi->irq);
+		msi->msg.address_lo = 0;
+		msi->msg.address_hi = 0;
+		msi->msg.data = 0;
+		msi->irq = 0;
+	}
 
-	list_for_each_entry(msi, &pdev->msi_list, list)
-		zpci_teardown_msi_irq(zdev, msi);
-
-	clear_bit(aisb, bucket->alloc);
-	if (aisb + 1 == aisb_max)
-		aisb_max--;
-}
-
-int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
-{
-	pr_debug("%s: requesting %d MSI-X interrupts...", __func__, nvec);
-	if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI)
-		return -EINVAL;
-	return zpci_setup_msi(pdev, nvec);
-}
-
-void arch_teardown_msi_irqs(struct pci_dev *pdev)
-{
-	pr_info("%s: on pdev: %p\n", __func__, pdev);
-	zpci_teardown_msi(pdev);
+	zpci_aibv[zdev->aisb] = NULL;
+	airq_iv_release(zdev->aibv);
+	airq_iv_free_bit(zpci_aisb_iv, zdev->aisb);
 }
 
 static void zpci_map_resources(struct zpci_dev *zdev)
@@ -564,8 +536,6 @@
 			continue;
 		pdev->resource[i].start = (resource_size_t) pci_iomap(pdev, i, 0);
 		pdev->resource[i].end = pdev->resource[i].start + len - 1;
-		pr_debug("BAR%i: -> start: %Lx  end: %Lx\n",
-			i, pdev->resource[i].start, pdev->resource[i].end);
 	}
 }
 
@@ -589,162 +559,47 @@
 
 	/* Alloc memory for our private pci device data */
 	zdev = kzalloc(sizeof(*zdev), GFP_KERNEL);
-	if (!zdev)
-		return ERR_PTR(-ENOMEM);
-
-	/* Alloc aibv & callback space */
-	zdev->irq_map = kmem_cache_zalloc(zdev_irq_cache, GFP_KERNEL);
-	if (!zdev->irq_map)
-		goto error;
-	WARN_ON((u64) zdev->irq_map & 0xff);
-	return zdev;
-
-error:
-	kfree(zdev);
-	return ERR_PTR(-ENOMEM);
+	return zdev ? : ERR_PTR(-ENOMEM);
 }
 
 void zpci_free_device(struct zpci_dev *zdev)
 {
-	kmem_cache_free(zdev_irq_cache, zdev->irq_map);
 	kfree(zdev);
 }
 
-/*
- * Too late for any s390 specific setup, since interrupts must be set up
- * already which requires DMA setup too and the pci scan will access the
- * config space, which only works if the function handle is enabled.
- */
-int pcibios_enable_device(struct pci_dev *pdev, int mask)
-{
-	struct resource *res;
-	u16 cmd;
-	int i;
-
-	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-
-	for (i = 0; i < PCI_BAR_COUNT; i++) {
-		res = &pdev->resource[i];
-
-		if (res->flags & IORESOURCE_IO)
-			return -EINVAL;
-
-		if (res->flags & IORESOURCE_MEM)
-			cmd |= PCI_COMMAND_MEMORY;
-	}
-	pci_write_config_word(pdev, PCI_COMMAND, cmd);
-	return 0;
-}
-
 int pcibios_add_platform_entries(struct pci_dev *pdev)
 {
 	return zpci_sysfs_add_device(&pdev->dev);
 }
 
-int zpci_request_irq(unsigned int irq, irq_handler_t handler, void *data)
-{
-	int msi_nr = irq_to_msi_nr(irq);
-	struct zdev_irq_map *imap;
-	struct msi_desc *msi;
-
-	msi = irq_get_msi_desc(irq);
-	if (!msi)
-		return -EIO;
-
-	imap = get_imap(irq);
-	spin_lock_init(&imap->lock);
-
-	pr_debug("%s: register handler for IRQ:MSI %d:%d\n", __func__, irq >> 6, msi_nr);
-	imap->cb[msi_nr].handler = handler;
-	imap->cb[msi_nr].data = data;
-
-	/*
-	 * The generic MSI code returns with the interrupt disabled on the
-	 * card, using the MSI mask bits. Firmware doesn't appear to unmask
-	 * at that level, so we do it here by hand.
-	 */
-	zpci_msi_set_mask_bits(msi, 1, 0);
-	return 0;
-}
-
-void zpci_free_irq(unsigned int irq)
-{
-	struct zdev_irq_map *imap = get_imap(irq);
-	int msi_nr = irq_to_msi_nr(irq);
-	unsigned long flags;
-
-	pr_debug("%s: for irq: %d\n", __func__, irq);
-
-	spin_lock_irqsave(&imap->lock, flags);
-	imap->cb[msi_nr].handler = NULL;
-	imap->cb[msi_nr].data = NULL;
-	spin_unlock_irqrestore(&imap->lock, flags);
-}
-
-int request_irq(unsigned int irq, irq_handler_t handler,
-		unsigned long irqflags, const char *devname, void *dev_id)
-{
-	pr_debug("%s: irq: %d  handler: %p  flags: %lx  dev: %s\n",
-		__func__, irq, handler, irqflags, devname);
-
-	return zpci_request_irq(irq, handler, dev_id);
-}
-EXPORT_SYMBOL_GPL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-	zpci_free_irq(irq);
-}
-EXPORT_SYMBOL_GPL(free_irq);
-
 static int __init zpci_irq_init(void)
 {
-	int cpu, rc;
-
-	bucket = kzalloc(sizeof(*bucket), GFP_KERNEL);
-	if (!bucket)
-		return -ENOMEM;
-
-	bucket->aisb = (unsigned long *) get_zeroed_page(GFP_KERNEL);
-	if (!bucket->aisb) {
-		rc = -ENOMEM;
-		goto out_aisb;
-	}
-
-	bucket->alloc = (unsigned long *) get_zeroed_page(GFP_KERNEL);
-	if (!bucket->alloc) {
-		rc = -ENOMEM;
-		goto out_alloc;
-	}
+	int rc;
 
 	rc = register_adapter_interrupt(&zpci_airq);
 	if (rc)
-		goto out_ai;
+		goto out;
 	/* Set summary to 1 to be called every time for the ISC. */
 	*zpci_airq.lsi_ptr = 1;
 
-	for_each_online_cpu(cpu)
-		per_cpu(next_sbit, cpu) = 0;
+	rc = -ENOMEM;
+	zpci_aisb_iv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC);
+	if (!zpci_aisb_iv)
+		goto out_airq;
 
-	spin_lock_init(&bucket->lock);
-	set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+	zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
 	return 0;
 
-out_ai:
-	free_page((unsigned long) bucket->alloc);
-out_alloc:
-	free_page((unsigned long) bucket->aisb);
-out_aisb:
-	kfree(bucket);
+out_airq:
+	unregister_adapter_interrupt(&zpci_airq);
+out:
 	return rc;
 }
 
 static void zpci_irq_exit(void)
 {
-	free_page((unsigned long) bucket->alloc);
-	free_page((unsigned long) bucket->aisb);
+	airq_iv_release(zpci_aisb_iv);
 	unregister_adapter_interrupt(&zpci_airq);
-	kfree(bucket);
 }
 
 static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
@@ -801,16 +656,49 @@
 int pcibios_add_device(struct pci_dev *pdev)
 {
 	struct zpci_dev *zdev = get_zdev(pdev);
+	struct resource *res;
+	int i;
+
+	zdev->pdev = pdev;
+	zpci_map_resources(zdev);
+
+	for (i = 0; i < PCI_BAR_COUNT; i++) {
+		res = &pdev->resource[i];
+		if (res->parent || !res->flags)
+			continue;
+		pci_claim_resource(pdev, i);
+	}
+
+	return 0;
+}
+
+int pcibios_enable_device(struct pci_dev *pdev, int mask)
+{
+	struct zpci_dev *zdev = get_zdev(pdev);
+	struct resource *res;
+	u16 cmd;
+	int i;
 
 	zdev->pdev = pdev;
 	zpci_debug_init_device(zdev);
 	zpci_fmb_enable_device(zdev);
 	zpci_map_resources(zdev);
 
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	for (i = 0; i < PCI_BAR_COUNT; i++) {
+		res = &pdev->resource[i];
+
+		if (res->flags & IORESOURCE_IO)
+			return -EINVAL;
+
+		if (res->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
 	return 0;
 }
 
-void pcibios_release_device(struct pci_dev *pdev)
+void pcibios_disable_device(struct pci_dev *pdev)
 {
 	struct zpci_dev *zdev = get_zdev(pdev);
 
@@ -898,6 +786,8 @@
 	rc = zpci_dma_init_device(zdev);
 	if (rc)
 		goto out_dma;
+
+	zdev->state = ZPCI_FN_STATE_ONLINE;
 	return 0;
 
 out_dma:
@@ -926,18 +816,16 @@
 		rc = zpci_enable_device(zdev);
 		if (rc)
 			goto out_free;
-
-		zdev->state = ZPCI_FN_STATE_ONLINE;
 	}
 	rc = zpci_scan_bus(zdev);
 	if (rc)
 		goto out_disable;
 
-	mutex_lock(&zpci_list_lock);
+	spin_lock(&zpci_list_lock);
 	list_add_tail(&zdev->entry, &zpci_list);
-	if (hotplug_ops)
-		hotplug_ops->create_slot(zdev);
-	mutex_unlock(&zpci_list_lock);
+	spin_unlock(&zpci_list_lock);
+
+	zpci_init_slot(zdev);
 
 	return 0;
 
@@ -967,15 +855,10 @@
 
 static int zpci_mem_init(void)
 {
-	zdev_irq_cache = kmem_cache_create("PCI_IRQ_cache", sizeof(struct zdev_irq_map),
-				L1_CACHE_BYTES, SLAB_HWCACHE_ALIGN, NULL);
-	if (!zdev_irq_cache)
-		goto error_zdev;
-
 	zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
 				16, 0, NULL);
 	if (!zdev_fmb_cache)
-		goto error_fmb;
+		goto error_zdev;
 
 	/* TODO: use realloc */
 	zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start),
@@ -986,8 +869,6 @@
 
 error_iomap:
 	kmem_cache_destroy(zdev_fmb_cache);
-error_fmb:
-	kmem_cache_destroy(zdev_irq_cache);
 error_zdev:
 	return -ENOMEM;
 }
@@ -995,28 +876,10 @@
 static void zpci_mem_exit(void)
 {
 	kfree(zpci_iomap_start);
-	kmem_cache_destroy(zdev_irq_cache);
 	kmem_cache_destroy(zdev_fmb_cache);
 }
 
-void zpci_register_hp_ops(struct pci_hp_callback_ops *ops)
-{
-	mutex_lock(&zpci_list_lock);
-	hotplug_ops = ops;
-	mutex_unlock(&zpci_list_lock);
-}
-EXPORT_SYMBOL_GPL(zpci_register_hp_ops);
-
-void zpci_deregister_hp_ops(void)
-{
-	mutex_lock(&zpci_list_lock);
-	hotplug_ops = NULL;
-	mutex_unlock(&zpci_list_lock);
-}
-EXPORT_SYMBOL_GPL(zpci_deregister_hp_ops);
-
-unsigned int s390_pci_probe;
-EXPORT_SYMBOL_GPL(s390_pci_probe);
+static unsigned int s390_pci_probe;
 
 char * __init pcibios_setup(char *str)
 {
@@ -1044,16 +907,12 @@
 
 	rc = zpci_debug_init();
 	if (rc)
-		return rc;
+		goto out;
 
 	rc = zpci_mem_init();
 	if (rc)
 		goto out_mem;
 
-	rc = zpci_msihash_init();
-	if (rc)
-		goto out_hash;
-
 	rc = zpci_irq_init();
 	if (rc)
 		goto out_irq;
@@ -1062,7 +921,7 @@
 	if (rc)
 		goto out_dma;
 
-	rc = clp_find_pci_devices();
+	rc = clp_scan_pci_devices();
 	if (rc)
 		goto out_find;
 
@@ -1073,11 +932,15 @@
 out_dma:
 	zpci_irq_exit();
 out_irq:
-	zpci_msihash_exit();
-out_hash:
 	zpci_mem_exit();
 out_mem:
 	zpci_debug_exit();
+out:
 	return rc;
 }
-subsys_initcall(pci_base_init);
+subsys_initcall_sync(pci_base_init);
+
+void zpci_rescan(void)
+{
+	clp_rescan_pci_devices_simple();
+}
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index 2e95396..475563c 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -36,9 +36,9 @@
 	return cc;
 }
 
-static void *clp_alloc_block(void)
+static void *clp_alloc_block(gfp_t gfp_mask)
 {
-	return (void *) __get_free_pages(GFP_KERNEL, get_order(CLP_BLK_SIZE));
+	return (void *) __get_free_pages(gfp_mask, get_order(CLP_BLK_SIZE));
 }
 
 static void clp_free_block(void *ptr)
@@ -70,7 +70,7 @@
 	struct clp_req_rsp_query_pci_grp *rrb;
 	int rc;
 
-	rrb = clp_alloc_block();
+	rrb = clp_alloc_block(GFP_KERNEL);
 	if (!rrb)
 		return -ENOMEM;
 
@@ -113,7 +113,7 @@
 	struct clp_req_rsp_query_pci *rrb;
 	int rc;
 
-	rrb = clp_alloc_block();
+	rrb = clp_alloc_block(GFP_KERNEL);
 	if (!rrb)
 		return -ENOMEM;
 
@@ -179,9 +179,9 @@
 static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
 {
 	struct clp_req_rsp_set_pci *rrb;
-	int rc, retries = 1000;
+	int rc, retries = 100;
 
-	rrb = clp_alloc_block();
+	rrb = clp_alloc_block(GFP_KERNEL);
 	if (!rrb)
 		return -ENOMEM;
 
@@ -199,7 +199,7 @@
 			retries--;
 			if (retries < 0)
 				break;
-			msleep(1);
+			msleep(20);
 		}
 	} while (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY);
 
@@ -245,49 +245,12 @@
 	return rc;
 }
 
-static void clp_check_pcifn_entry(struct clp_fh_list_entry *entry)
+static int clp_list_pci(struct clp_req_rsp_list_pci *rrb,
+			void (*cb)(struct clp_fh_list_entry *entry))
 {
-	int present, rc;
-
-	if (!entry->vendor_id)
-		return;
-
-	/* TODO: be a little bit more scalable */
-	present = zpci_fid_present(entry->fid);
-
-	if (present)
-		pr_debug("%s: device %x already present\n", __func__, entry->fid);
-
-	/* skip already used functions */
-	if (present && entry->config_state)
-		return;
-
-	/* aev 306: function moved to stand-by state */
-	if (present && !entry->config_state) {
-		/*
-		 * The handle is already disabled, that means no iota/irq freeing via
-		 * the firmware interfaces anymore. Need to free resources manually
-		 * (DMA memory, debug, sysfs)...
-		 */
-		zpci_stop_device(get_zdev_by_fid(entry->fid));
-		return;
-	}
-
-	rc = clp_add_pci_device(entry->fid, entry->fh, entry->config_state);
-	if (rc)
-		pr_err("Failed to add fid: 0x%x\n", entry->fid);
-}
-
-int clp_find_pci_devices(void)
-{
-	struct clp_req_rsp_list_pci *rrb;
 	u64 resume_token = 0;
 	int entries, i, rc;
 
-	rrb = clp_alloc_block();
-	if (!rrb)
-		return -ENOMEM;
-
 	do {
 		memset(rrb, 0, sizeof(*rrb));
 		rrb->request.hdr.len = sizeof(rrb->request);
@@ -316,12 +279,101 @@
 		resume_token = rrb->response.resume_token;
 
 		for (i = 0; i < entries; i++)
-			clp_check_pcifn_entry(&rrb->response.fh_list[i]);
+			cb(&rrb->response.fh_list[i]);
 	} while (resume_token);
 
 	pr_debug("Maximum number of supported PCI functions: %u\n",
 		rrb->response.max_fn);
 out:
+	return rc;
+}
+
+static void __clp_add(struct clp_fh_list_entry *entry)
+{
+	if (!entry->vendor_id)
+		return;
+
+	clp_add_pci_device(entry->fid, entry->fh, entry->config_state);
+}
+
+static void __clp_rescan(struct clp_fh_list_entry *entry)
+{
+	struct zpci_dev *zdev;
+
+	if (!entry->vendor_id)
+		return;
+
+	zdev = get_zdev_by_fid(entry->fid);
+	if (!zdev) {
+		clp_add_pci_device(entry->fid, entry->fh, entry->config_state);
+		return;
+	}
+
+	if (!entry->config_state) {
+		/*
+		 * The handle is already disabled, that means no iota/irq freeing via
+		 * the firmware interfaces anymore. Need to free resources manually
+		 * (DMA memory, debug, sysfs)...
+		 */
+		zpci_stop_device(zdev);
+	}
+}
+
+static void __clp_update(struct clp_fh_list_entry *entry)
+{
+	struct zpci_dev *zdev;
+
+	if (!entry->vendor_id)
+		return;
+
+	zdev = get_zdev_by_fid(entry->fid);
+	if (!zdev)
+		return;
+
+	zdev->fh = entry->fh;
+}
+
+int clp_scan_pci_devices(void)
+{
+	struct clp_req_rsp_list_pci *rrb;
+	int rc;
+
+	rrb = clp_alloc_block(GFP_KERNEL);
+	if (!rrb)
+		return -ENOMEM;
+
+	rc = clp_list_pci(rrb, __clp_add);
+
+	clp_free_block(rrb);
+	return rc;
+}
+
+int clp_rescan_pci_devices(void)
+{
+	struct clp_req_rsp_list_pci *rrb;
+	int rc;
+
+	rrb = clp_alloc_block(GFP_KERNEL);
+	if (!rrb)
+		return -ENOMEM;
+
+	rc = clp_list_pci(rrb, __clp_rescan);
+
+	clp_free_block(rrb);
+	return rc;
+}
+
+int clp_rescan_pci_devices_simple(void)
+{
+	struct clp_req_rsp_list_pci *rrb;
+	int rc;
+
+	rrb = clp_alloc_block(GFP_NOWAIT);
+	if (!rrb)
+		return -ENOMEM;
+
+	rc = clp_list_pci(rrb, __clp_update);
+
 	clp_free_block(rrb);
 	return rc;
 }
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index a2343c1..7e5573a 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -10,6 +10,7 @@
 #include <linux/export.h>
 #include <linux/iommu-helper.h>
 #include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
 #include <linux/pci.h>
 #include <asm/pci_dma.h>
 
@@ -170,8 +171,8 @@
 		 */
 		goto no_refresh;
 
-	rc = s390pci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
-				   nr_pages * PAGE_SIZE);
+	rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
+				nr_pages * PAGE_SIZE);
 
 no_refresh:
 	spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
@@ -407,7 +408,6 @@
 
 int zpci_dma_init_device(struct zpci_dev *zdev)
 {
-	unsigned int bitmap_order;
 	int rc;
 
 	spin_lock_init(&zdev->iommu_bitmap_lock);
@@ -421,12 +421,7 @@
 
 	zdev->iommu_size = (unsigned long) high_memory - PAGE_OFFSET;
 	zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
-	bitmap_order = get_order(zdev->iommu_pages / 8);
-	pr_info("iommu_size: 0x%lx  iommu_pages: 0x%lx  bitmap_order: %i\n",
-		 zdev->iommu_size, zdev->iommu_pages, bitmap_order);
-
-	zdev->iommu_bitmap = (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
-						       bitmap_order);
+	zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
 	if (!zdev->iommu_bitmap) {
 		rc = -ENOMEM;
 		goto out_reg;
@@ -451,8 +446,7 @@
 {
 	zpci_unregister_ioat(zdev, 0);
 	dma_cleanup_tables(zdev);
-	free_pages((unsigned long) zdev->iommu_bitmap,
-		   get_order(zdev->iommu_pages / 8));
+	vfree(zdev->iommu_bitmap);
 	zdev->iommu_bitmap = NULL;
 	zdev->next_bit = 0;
 }
diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c
index ec62e3a..0aecaf9 100644
--- a/arch/s390/pci/pci_event.c
+++ b/arch/s390/pci/pci_event.c
@@ -69,7 +69,7 @@
 		clp_add_pci_device(ccdf->fid, ccdf->fh, 0);
 		break;
 	case 0x0306:
-		clp_find_pci_devices();
+		clp_rescan_pci_devices();
 		break;
 	default:
 		break;
diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c
index 22eeb9d..85267c0 100644
--- a/arch/s390/pci/pci_insn.c
+++ b/arch/s390/pci/pci_insn.c
@@ -27,7 +27,7 @@
 	return cc;
 }
 
-int s390pci_mod_fc(u64 req, struct zpci_fib *fib)
+int zpci_mod_fc(u64 req, struct zpci_fib *fib)
 {
 	u8 cc, status;
 
@@ -61,7 +61,7 @@
 	return cc;
 }
 
-int s390pci_refresh_trans(u64 fn, u64 addr, u64 range)
+int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
 {
 	u8 cc, status;
 
@@ -78,7 +78,7 @@
 }
 
 /* Set Interruption Controls */
-void set_irq_ctrl(u16 ctl, char *unused, u8 isc)
+void zpci_set_irq_ctrl(u16 ctl, char *unused, u8 isc)
 {
 	asm volatile (
 		"	.insn	rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
@@ -109,7 +109,7 @@
 	return cc;
 }
 
-int s390pci_load(u64 *data, u64 req, u64 offset)
+int zpci_load(u64 *data, u64 req, u64 offset)
 {
 	u8 status;
 	int cc;
@@ -125,7 +125,7 @@
 			    __func__, cc, status, req, offset);
 	return (cc > 0) ? -EIO : cc;
 }
-EXPORT_SYMBOL_GPL(s390pci_load);
+EXPORT_SYMBOL_GPL(zpci_load);
 
 /* PCI Store */
 static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
@@ -147,7 +147,7 @@
 	return cc;
 }
 
-int s390pci_store(u64 data, u64 req, u64 offset)
+int zpci_store(u64 data, u64 req, u64 offset)
 {
 	u8 status;
 	int cc;
@@ -163,7 +163,7 @@
 			__func__, cc, status, req, offset);
 	return (cc > 0) ? -EIO : cc;
 }
-EXPORT_SYMBOL_GPL(s390pci_store);
+EXPORT_SYMBOL_GPL(zpci_store);
 
 /* PCI Store Block */
 static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
@@ -183,7 +183,7 @@
 	return cc;
 }
 
-int s390pci_store_block(const u64 *data, u64 req, u64 offset)
+int zpci_store_block(const u64 *data, u64 req, u64 offset)
 {
 	u8 status;
 	int cc;
@@ -199,4 +199,4 @@
 			    __func__, cc, status, req, offset);
 	return (cc > 0) ? -EIO : cc;
 }
-EXPORT_SYMBOL_GPL(s390pci_store_block);
+EXPORT_SYMBOL_GPL(zpci_store_block);
diff --git a/arch/s390/pci/pci_msi.c b/arch/s390/pci/pci_msi.c
deleted file mode 100644
index b097aed..0000000
--- a/arch/s390/pci/pci_msi.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright IBM Corp. 2012
- *
- * Author(s):
- *   Jan Glauber <jang@linux.vnet.ibm.com>
- */
-
-#define COMPONENT "zPCI"
-#define pr_fmt(fmt) COMPONENT ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/rculist.h>
-#include <linux/hash.h>
-#include <linux/pci.h>
-#include <linux/msi.h>
-#include <asm/hw_irq.h>
-
-/* mapping of irq numbers to msi_desc */
-static struct hlist_head *msi_hash;
-static const unsigned int msi_hash_bits = 8;
-#define MSI_HASH_BUCKETS (1U << msi_hash_bits)
-#define msi_hashfn(nr)	hash_long(nr, msi_hash_bits)
-
-static DEFINE_SPINLOCK(msi_map_lock);
-
-struct msi_desc *__irq_get_msi_desc(unsigned int irq)
-{
-	struct msi_map *map;
-
-	hlist_for_each_entry_rcu(map,
-			&msi_hash[msi_hashfn(irq)], msi_chain)
-		if (map->irq == irq)
-			return map->msi;
-	return NULL;
-}
-
-int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag)
-{
-	if (msi->msi_attrib.is_msix) {
-		int offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_VECTOR_CTRL;
-		msi->masked = readl(msi->mask_base + offset);
-		writel(flag, msi->mask_base + offset);
-	} else {
-		if (msi->msi_attrib.maskbit) {
-			int pos;
-			u32 mask_bits;
-
-			pos = (long) msi->mask_base;
-			pci_read_config_dword(msi->dev, pos, &mask_bits);
-			mask_bits &= ~(mask);
-			mask_bits |= flag & mask;
-			pci_write_config_dword(msi->dev, pos, mask_bits);
-		} else {
-			return 0;
-		}
-	}
-
-	msi->msi_attrib.maskbit = !!flag;
-	return 1;
-}
-
-int zpci_setup_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi,
-			unsigned int nr, int offset)
-{
-	struct msi_map *map;
-	struct msi_msg msg;
-	int rc;
-
-	map = kmalloc(sizeof(*map), GFP_KERNEL);
-	if (map == NULL)
-		return -ENOMEM;
-
-	map->irq = nr;
-	map->msi = msi;
-	zdev->msi_map[nr & ZPCI_MSI_MASK] = map;
-	INIT_HLIST_NODE(&map->msi_chain);
-
-	pr_debug("%s hashing irq: %u  to bucket nr: %llu\n",
-		__func__, nr, msi_hashfn(nr));
-	hlist_add_head_rcu(&map->msi_chain, &msi_hash[msi_hashfn(nr)]);
-
-	spin_lock(&msi_map_lock);
-	rc = irq_set_msi_desc(nr, msi);
-	if (rc) {
-		spin_unlock(&msi_map_lock);
-		hlist_del_rcu(&map->msi_chain);
-		kfree(map);
-		zdev->msi_map[nr & ZPCI_MSI_MASK] = NULL;
-		return rc;
-	}
-	spin_unlock(&msi_map_lock);
-
-	msg.data = nr - offset;
-	msg.address_lo = zdev->msi_addr & 0xffffffff;
-	msg.address_hi = zdev->msi_addr >> 32;
-	write_msi_msg(nr, &msg);
-	return 0;
-}
-
-void zpci_teardown_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi)
-{
-	int irq = msi->irq & ZPCI_MSI_MASK;
-	struct msi_map *map;
-
-	msi->msg.address_lo = 0;
-	msi->msg.address_hi = 0;
-	msi->msg.data = 0;
-	msi->irq = 0;
-	zpci_msi_set_mask_bits(msi, 1, 1);
-
-	spin_lock(&msi_map_lock);
-	map = zdev->msi_map[irq];
-	hlist_del_rcu(&map->msi_chain);
-	kfree(map);
-	zdev->msi_map[irq] = NULL;
-	spin_unlock(&msi_map_lock);
-}
-
-/*
- * The msi hash table has 256 entries which is good for 4..20
- * devices (a typical device allocates 10 + CPUs MSI's). Maybe make
- * the hash table size adjustable later.
- */
-int __init zpci_msihash_init(void)
-{
-	unsigned int i;
-
-	msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL);
-	if (!msi_hash)
-		return -ENOMEM;
-
-	for (i = 0; i < MSI_HASH_BUCKETS; i++)
-		INIT_HLIST_HEAD(&msi_hash[i]);
-	return 0;
-}
-
-void __init zpci_msihash_exit(void)
-{
-	kfree(msi_hash);
-}
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
index e99a255..cf8a12f 100644
--- a/arch/s390/pci/pci_sysfs.c
+++ b/arch/s390/pci/pci_sysfs.c
@@ -48,11 +48,38 @@
 }
 static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL);
 
+static void recover_callback(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct zpci_dev *zdev = get_zdev(pdev);
+	int ret;
+
+	pci_stop_and_remove_bus_device(pdev);
+	ret = zpci_disable_device(zdev);
+	if (ret)
+		return;
+
+	ret = zpci_enable_device(zdev);
+	if (ret)
+		return;
+
+	pci_rescan_bus(zdev->bus);
+}
+
+static ssize_t store_recover(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int rc = device_schedule_callback(dev, recover_callback);
+	return rc ? rc : count;
+}
+static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover);
+
 static struct device_attribute *zpci_dev_attrs[] = {
 	&dev_attr_function_id,
 	&dev_attr_function_handle,
 	&dev_attr_pchid,
 	&dev_attr_pfgid,
+	&dev_attr_recover,
 	NULL,
 };
 
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 1020dd8..1018ed3 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -643,9 +643,9 @@
 
 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
-	  initially work for you.  It may help to enable device hotplugging
-	  support.  As of this writing the exact hardware interface is
-	  strongly in flux, so no good recommendation can be made.
+	  initially work for you.  As of this writing the exact hardware
+	  interface is strongly in flux, so no good recommendation can be
+	  made.
 
 config CRASH_DUMP
 	bool "kernel crash dumps (EXPERIMENTAL)"
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 102f5d5..60ed3e1 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -69,7 +69,6 @@
 
 		pci_bus_size_bridges(bus);
 		pci_bus_assign_resources(bus);
-		pci_enable_bridges(bus);
 	} else {
 		pci_free_resource_list(&resources);
 	}
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index d306225..e3abfd4 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -91,13 +91,11 @@
 
 int __init sh_mobile_setup_cpuidle(void)
 {
-	int ret;
-
 	if (sh_mobile_sleep_supported & SUSP_SH_SF)
 		cpuidle_driver.states[1].disabled = false;
 
 	if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
 		cpuidle_driver.states[2].disabled = false;
 
-	return cpuidle_register(&cpuidle_driver);
+	return cpuidle_register(&cpuidle_driver, NULL);
 }
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index d5e86c9..d15c0d8 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -89,9 +89,6 @@
 #define topology_core_id(cpu)                   (cpu)
 #define topology_core_cpumask(cpu)              ((void)(cpu), cpu_online_mask)
 #define topology_thread_cpumask(cpu)            cpumask_of(cpu)
-
-/* indicates that pointers to the topology struct cpumask maps are valid */
-#define arch_provides_topology_pointers         yes
 #endif
 
 #endif /* _ASM_TILE_TOPOLOGY_H */
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index 1142563..6640e7b 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -508,13 +508,8 @@
 						rc_dev_cap.word);
 
 	/* Configure PCI Express MPS setting. */
-	list_for_each_entry(child, &root_bus->children, node) {
-		struct pci_dev *self = child->self;
-		if (!self)
-			continue;
-
-		pcie_bus_configure_settings(child, self->pcie_mpss);
-	}
+	list_for_each_entry(child, &root_bus->children, node)
+		pcie_bus_configure_settings(child);
 
 	/*
 	 * Set the mac_config register in trio based on the MPS/MRS of the link.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b32ebf9..5c0ed72 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -16,6 +16,7 @@
 	def_bool y
 	depends on 64BIT
 	select X86_DEV_DMA_OPS
+	select ARCH_USE_CMPXCHG_LOCKREF
 
 ### Arch settings
 config X86
@@ -81,7 +82,6 @@
 	select HAVE_USER_RETURN_NOTIFIER
 	select ARCH_BINFMT_ELF_RANDOMIZE_PIE
 	select HAVE_ARCH_JUMP_LABEL
-	select HAVE_TEXT_POKE_SMP
 	select HAVE_GENERIC_HARDIRQS
 	select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
 	select SPARSE_IRQ
@@ -632,6 +632,7 @@
 config PARAVIRT_SPINLOCKS
 	bool "Paravirtualization layer for spinlocks"
 	depends on PARAVIRT && SMP
+	select UNINLINE_SPIN_UNLOCK
 	---help---
 	  Paravirtualized spinlocks allow a pvops backend to replace the
 	  spinlock implementation with something virtualization-friendly
@@ -656,6 +657,15 @@
 	  underlying device model, the host provides the guest with
 	  timing infrastructure such as time of day, and system time
 
+config KVM_DEBUG_FS
+	bool "Enable debug information for KVM Guests in debugfs"
+	depends on KVM_GUEST && DEBUG_FS
+	default n
+	---help---
+	  This option enables collection of various statistics for KVM guest.
+	  Statistics are displayed in debugfs filesystem. Enabling this option
+	  may incur significant overhead.
+
 source "arch/x86/lguest/Kconfig"
 
 config PARAVIRT_TIME_ACCOUNTING
@@ -1344,8 +1354,12 @@
 	depends on ARCH_SPARSEMEM_ENABLE
 
 config ARCH_MEMORY_PROBE
-	def_bool y
+	bool "Enable sysfs memory/probe interface"
 	depends on X86_64 && MEMORY_HOTPLUG
+	help
+	  This option enables a sysfs memory/probe interface for testing.
+	  See Documentation/memory-hotplug.txt for more information.
+	  If you are unsure how to answer this question, answer N.
 
 config ARCH_PROC_KCORE_TEXT
 	def_bool y
@@ -1627,9 +1641,9 @@
 
 	  It is an ongoing process to be certain the hardware in a machine
 	  is properly shutdown, so do not be surprised if this code does not
-	  initially work for you.  It may help to enable device hotplugging
-	  support.  As of this writing the exact hardware interface is
-	  strongly in flux, so no good recommendation can be made.
+	  initially work for you.  As of this writing the exact hardware
+	  interface is strongly in flux, so no good recommendation can be
+	  made.
 
 config CRASH_DUMP
 	bool "kernel crash dumps"
@@ -1716,9 +1730,10 @@
 	depends on X86_32 && RELOCATABLE
 
 config PHYSICAL_ALIGN
-	hex "Alignment value to which kernel should be aligned" if X86_32
+	hex "Alignment value to which kernel should be aligned"
 	default "0x1000000"
-	range 0x2000 0x1000000
+	range 0x2000 0x1000000 if X86_32
+	range 0x200000 0x1000000 if X86_64
 	---help---
 	  This value puts the alignment restrictions on physical address
 	  where kernel is loaded and run from. Kernel is compiled for an
@@ -1736,6 +1751,9 @@
 	  end result is that kernel runs from a physical address meeting
 	  above alignment restrictions.
 
+	  On 32-bit this value must be a multiple of 0x2000. On 64-bit
+	  this value must be a multiple of 0x200000.
+
 	  Don't change this unless you know what you are doing.
 
 config HOTPLUG_CPU
@@ -2270,6 +2288,32 @@
 
 source "drivers/rapidio/Kconfig"
 
+config X86_SYSFB
+	bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
+	help
+	  Firmwares often provide initial graphics framebuffers so the BIOS,
+	  bootloader or kernel can show basic video-output during boot for
+	  user-guidance and debugging. Historically, x86 used the VESA BIOS
+	  Extensions and EFI-framebuffers for this, which are mostly limited
+	  to x86.
+	  This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
+	  framebuffers so the new generic system-framebuffer drivers can be
+	  used on x86. If the framebuffer is not compatible with the generic
+	  modes, it is adverticed as fallback platform framebuffer so legacy
+	  drivers like efifb, vesafb and uvesafb can pick it up.
+	  If this option is not selected, all system framebuffers are always
+	  marked as fallback platform framebuffers as usual.
+
+	  Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
+	  not be able to pick up generic system framebuffers if this option
+	  is selected. You are highly encouraged to enable simplefb as
+	  replacement if you select this option. simplefb can correctly deal
+	  with generic system framebuffers. But you should still keep vesafb
+	  and others enabled as fallback if a system framebuffer is
+	  incompatible with simplefb.
+
+	  If unsure, say Y.
+
 endmenu
 
 
@@ -2332,10 +2376,6 @@
 	def_bool y
 	depends on X86_32
 
-config HAVE_TEXT_POKE_SMP
-	bool
-	select STOP_MACHINE if SMP
-
 config X86_DEV_DMA_OPS
 	bool
 	depends on X86_64 || STA2X11
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 07639c6..41250fb 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -16,6 +16,10 @@
 # e.g.: obj-y += foo_$(BITS).o
 export BITS
 
+ifdef CONFIG_X86_NEED_RELOCS
+        LDFLAGS_vmlinux := --emit-relocs
+endif
+
 ifeq ($(CONFIG_X86_32),y)
         BITS := 32
         UTS_MACHINE := i386
@@ -25,10 +29,6 @@
         KBUILD_AFLAGS += $(biarch)
         KBUILD_CFLAGS += $(biarch)
 
-        ifdef CONFIG_RELOCATABLE
-                LDFLAGS_vmlinux := --emit-relocs
-        endif
-
         KBUILD_CFLAGS += -msoft-float -mregparm=3 -freg-struct-return
 
         # Never want PIC in a 32-bit kernel, prevent breakage with GCC built
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 5b75319..ef72bae 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -355,6 +355,7 @@
 size_t strnlen(const char *s, size_t maxlen);
 unsigned int atou(const char *s);
 unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
+size_t strlen(const char *s);
 
 /* tty.c */
 void puts(const char *);
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 1e3184f..5d6f6891 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -181,8 +181,9 @@
 /*
  * Do the decompression, and jump to the new kernel..
  */
-	leal	z_extract_offset_negative(%ebx), %ebp
 				/* push arguments for decompress_kernel: */
+	pushl	$z_output_len	/* decompressed length */
+	leal	z_extract_offset_negative(%ebx), %ebp
 	pushl	%ebp		/* output address */
 	pushl	$z_input_len	/* input_len */
 	leal	input_data(%ebx), %eax
@@ -191,33 +192,7 @@
 	pushl	%eax		/* heap area */
 	pushl	%esi		/* real mode pointer */
 	call	decompress_kernel
-	addl	$20, %esp
-
-#if CONFIG_RELOCATABLE
-/*
- * Find the address of the relocations.
- */
-	leal	z_output_len(%ebp), %edi
-
-/*
- * Calculate the delta between where vmlinux was compiled to run
- * and where it was actually loaded.
- */
-	movl	%ebp, %ebx
-	subl	$LOAD_PHYSICAL_ADDR, %ebx
-	jz	2f	/* Nothing to be done if loaded at compiled addr. */
-/*
- * Process relocations.
- */
-
-1:	subl	$4, %edi
-	movl	(%edi), %ecx
-	testl	%ecx, %ecx
-	jz	2f
-	addl	%ebx, -__PAGE_OFFSET(%ebx, %ecx)
-	jmp	1b
-2:
-#endif
+	addl	$24, %esp
 
 /*
  * Jump to the decompressed kernel.
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 06e71c2c..c337422 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -338,6 +338,7 @@
 	leaq	input_data(%rip), %rdx  /* input_data */
 	movl	$z_input_len, %ecx	/* input_len */
 	movq	%rbp, %r8		/* output target address */
+	movq	$z_output_len, %r9	/* decompressed length */
 	call	decompress_kernel
 	popq	%rsi
 
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 0319c88..434f077 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -271,6 +271,79 @@
 		asm("hlt");
 }
 
+#if CONFIG_X86_NEED_RELOCS
+static void handle_relocations(void *output, unsigned long output_len)
+{
+	int *reloc;
+	unsigned long delta, map, ptr;
+	unsigned long min_addr = (unsigned long)output;
+	unsigned long max_addr = min_addr + output_len;
+
+	/*
+	 * Calculate the delta between where vmlinux was linked to load
+	 * and where it was actually loaded.
+	 */
+	delta = min_addr - LOAD_PHYSICAL_ADDR;
+	if (!delta) {
+		debug_putstr("No relocation needed... ");
+		return;
+	}
+	debug_putstr("Performing relocations... ");
+
+	/*
+	 * The kernel contains a table of relocation addresses. Those
+	 * addresses have the final load address of the kernel in virtual
+	 * memory. We are currently working in the self map. So we need to
+	 * create an adjustment for kernel memory addresses to the self map.
+	 * This will involve subtracting out the base address of the kernel.
+	 */
+	map = delta - __START_KERNEL_map;
+
+	/*
+	 * Process relocations: 32 bit relocations first then 64 bit after.
+	 * Two sets of binary relocations are added to the end of the kernel
+	 * before compression. Each relocation table entry is the kernel
+	 * address of the location which needs to be updated stored as a
+	 * 32-bit value which is sign extended to 64 bits.
+	 *
+	 * Format is:
+	 *
+	 * kernel bits...
+	 * 0 - zero terminator for 64 bit relocations
+	 * 64 bit relocation repeated
+	 * 0 - zero terminator for 32 bit relocations
+	 * 32 bit relocation repeated
+	 *
+	 * So we work backwards from the end of the decompressed image.
+	 */
+	for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
+		int extended = *reloc;
+		extended += map;
+
+		ptr = (unsigned long)extended;
+		if (ptr < min_addr || ptr > max_addr)
+			error("32-bit relocation outside of kernel!\n");
+
+		*(uint32_t *)ptr += delta;
+	}
+#ifdef CONFIG_X86_64
+	for (reloc--; *reloc; reloc--) {
+		long extended = *reloc;
+		extended += map;
+
+		ptr = (unsigned long)extended;
+		if (ptr < min_addr || ptr > max_addr)
+			error("64-bit relocation outside of kernel!\n");
+
+		*(uint64_t *)ptr += delta;
+	}
+#endif
+}
+#else
+static inline void handle_relocations(void *output, unsigned long output_len)
+{ }
+#endif
+
 static void parse_elf(void *output)
 {
 #ifdef CONFIG_X86_64
@@ -325,7 +398,8 @@
 asmlinkage void decompress_kernel(void *rmode, memptr heap,
 				  unsigned char *input_data,
 				  unsigned long input_len,
-				  unsigned char *output)
+				  unsigned char *output,
+				  unsigned long output_len)
 {
 	real_mode = rmode;
 
@@ -365,6 +439,7 @@
 	debug_putstr("\nDecompressing Linux... ");
 	decompress(input_data, input_len, NULL, NULL, output, NULL, error);
 	parse_elf(output);
+	handle_relocations(output, output_len);
 	debug_putstr("done.\nBooting the kernel.\n");
 	return;
 }
diff --git a/arch/x86/boot/printf.c b/arch/x86/boot/printf.c
index cdac91c..565083c 100644
--- a/arch/x86/boot/printf.c
+++ b/arch/x86/boot/printf.c
@@ -55,7 +55,7 @@
 	locase = (type & SMALL);
 	if (type & LEFT)
 		type &= ~ZEROPAD;
-	if (base < 2 || base > 36)
+	if (base < 2 || base > 16)
 		return NULL;
 	c = (type & ZEROPAD) ? '0' : ' ';
 	sign = 0;
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index bccfca6..665a730 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -457,7 +457,7 @@
 		else
 			put_user_ex(0, &frame->uc.uc_flags);
 		put_user_ex(0, &frame->uc.uc_link);
-		err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
+		compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
 
 		if (ksig->ka.sa.sa_flags & SA_RESTORER)
 			restorer = ksig->ka.sa.sa_restorer;
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 474dc1b..4299eb0 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -452,7 +452,7 @@
 
 	CFI_ENDPROC
 	
-	.macro PTREGSCALL label, func, arg
+	.macro PTREGSCALL label, func
 	ALIGN
 GLOBAL(\label)
 	leaq \func(%rip),%rax
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 2dfac58..b1977ba 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -86,6 +86,7 @@
 extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
 extern int acpi_fix_pin2_polarity;
+extern int acpi_disable_cmcff;
 
 extern u8 acpi_sci_flags;
 extern int acpi_sci_override_gsi;
@@ -168,6 +169,7 @@
 
 #define acpi_lapic 0
 #define acpi_ioapic 0
+#define acpi_disable_cmcff 0
 static inline void acpi_noirq_set(void) { }
 static inline void acpi_disable_pci(void) { }
 static inline void disable_acpi(void) { }
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 58ed6d9..0a3f9c9 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -5,6 +5,7 @@
 #include <linux/stddef.h>
 #include <linux/stringify.h>
 #include <asm/asm.h>
+#include <asm/ptrace.h>
 
 /*
  * Alternative inline assembly for SMP.
@@ -220,20 +221,11 @@
  * no thread can be preempted in the instructions being modified (no iret to an
  * invalid instruction possible) or if the instructions are changed from a
  * consistent state to another consistent state atomically.
- * More care must be taken when modifying code in the SMP case because of
- * Intel's errata. text_poke_smp() takes care that errata, but still
- * doesn't support NMI/MCE handler code modifying.
  * On the local CPU you need to be protected again NMI or MCE handlers seeing an
  * inconsistent instruction while you patch.
  */
-struct text_poke_param {
-	void *addr;
-	const void *opcode;
-	size_t len;
-};
-
 extern void *text_poke(void *addr, const void *opcode, size_t len);
-extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
-extern void text_poke_smp_batch(struct text_poke_param *params, int n);
+extern int poke_int3_handler(struct pt_regs *regs);
+extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
 
 #endif /* _ASM_X86_ALTERNATIVE_H */
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index f8119b5..1d2091a 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -715,4 +715,6 @@
 	ack_APIC_irq();
 }
 
+extern void ioapic_zap_locks(void);
+
 #endif /* _ASM_X86_APIC_H */
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 1c2d247..4582e8e 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -3,21 +3,25 @@
 
 #ifdef __ASSEMBLY__
 # define __ASM_FORM(x)	x
+# define __ASM_FORM_RAW(x)     x
 # define __ASM_FORM_COMMA(x) x,
 #else
 # define __ASM_FORM(x)	" " #x " "
+# define __ASM_FORM_RAW(x)     #x
 # define __ASM_FORM_COMMA(x) " " #x ","
 #endif
 
 #ifdef CONFIG_X86_32
 # define __ASM_SEL(a,b) __ASM_FORM(a)
+# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a)
 #else
 # define __ASM_SEL(a,b) __ASM_FORM(b)
+# define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(b)
 #endif
 
 #define __ASM_SIZE(inst, ...)	__ASM_SEL(inst##l##__VA_ARGS__, \
 					  inst##q##__VA_ARGS__)
-#define __ASM_REG(reg)		__ASM_SEL(e##reg, r##reg)
+#define __ASM_REG(reg)         __ASM_SEL_RAW(e##reg, r##reg)
 
 #define _ASM_PTR	__ASM_SEL(.long, .quad)
 #define _ASM_ALIGN	__ASM_SEL(.balign 4, .balign 8)
diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h
index 6dfd019..41639ce 100644
--- a/arch/x86/include/asm/bitops.h
+++ b/arch/x86/include/asm/bitops.h
@@ -15,6 +15,14 @@
 #include <linux/compiler.h>
 #include <asm/alternative.h>
 
+#if BITS_PER_LONG == 32
+# define _BITOPS_LONG_SHIFT 5
+#elif BITS_PER_LONG == 64
+# define _BITOPS_LONG_SHIFT 6
+#else
+# error "Unexpected BITS_PER_LONG"
+#endif
+
 #define BIT_64(n)			(U64_C(1) << (n))
 
 /*
@@ -59,7 +67,7 @@
  * restricted to acting on a single-word quantity.
  */
 static __always_inline void
-set_bit(unsigned int nr, volatile unsigned long *addr)
+set_bit(long nr, volatile unsigned long *addr)
 {
 	if (IS_IMMEDIATE(nr)) {
 		asm volatile(LOCK_PREFIX "orb %1,%0"
@@ -81,7 +89,7 @@
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static inline void __set_bit(int nr, volatile unsigned long *addr)
+static inline void __set_bit(long nr, volatile unsigned long *addr)
 {
 	asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
 }
@@ -97,7 +105,7 @@
  * in order to ensure changes are visible on other processors.
  */
 static __always_inline void
-clear_bit(int nr, volatile unsigned long *addr)
+clear_bit(long nr, volatile unsigned long *addr)
 {
 	if (IS_IMMEDIATE(nr)) {
 		asm volatile(LOCK_PREFIX "andb %1,%0"
@@ -118,13 +126,13 @@
  * clear_bit() is atomic and implies release semantics before the memory
  * operation. It can be used for an unlock.
  */
-static inline void clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
+static inline void clear_bit_unlock(long nr, volatile unsigned long *addr)
 {
 	barrier();
 	clear_bit(nr, addr);
 }
 
-static inline void __clear_bit(int nr, volatile unsigned long *addr)
+static inline void __clear_bit(long nr, volatile unsigned long *addr)
 {
 	asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
 }
@@ -141,7 +149,7 @@
  * No memory barrier is required here, because x86 cannot reorder stores past
  * older loads. Same principle as spin_unlock.
  */
-static inline void __clear_bit_unlock(unsigned nr, volatile unsigned long *addr)
+static inline void __clear_bit_unlock(long nr, volatile unsigned long *addr)
 {
 	barrier();
 	__clear_bit(nr, addr);
@@ -159,7 +167,7 @@
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static inline void __change_bit(int nr, volatile unsigned long *addr)
+static inline void __change_bit(long nr, volatile unsigned long *addr)
 {
 	asm volatile("btc %1,%0" : ADDR : "Ir" (nr));
 }
@@ -173,7 +181,7 @@
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void change_bit(int nr, volatile unsigned long *addr)
+static inline void change_bit(long nr, volatile unsigned long *addr)
 {
 	if (IS_IMMEDIATE(nr)) {
 		asm volatile(LOCK_PREFIX "xorb %1,%0"
@@ -194,7 +202,7 @@
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int test_and_set_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -212,7 +220,7 @@
  * This is the same as test_and_set_bit on x86.
  */
 static __always_inline int
-test_and_set_bit_lock(int nr, volatile unsigned long *addr)
+test_and_set_bit_lock(long nr, volatile unsigned long *addr)
 {
 	return test_and_set_bit(nr, addr);
 }
@@ -226,7 +234,7 @@
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
-static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_set_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -245,7 +253,7 @@
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -272,7 +280,7 @@
  * accessed from a hypervisor on the same CPU if running in a VM: don't change
  * this without also updating arch/x86/kernel/kvm.c
  */
-static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -284,7 +292,7 @@
 }
 
 /* WARNING: non atomic and it can be reordered! */
-static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_change_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -304,7 +312,7 @@
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int test_and_change_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -315,13 +323,13 @@
 	return oldbit;
 }
 
-static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
+static __always_inline int constant_test_bit(long nr, const volatile unsigned long *addr)
 {
-	return ((1UL << (nr % BITS_PER_LONG)) &
-		(addr[nr / BITS_PER_LONG])) != 0;
+	return ((1UL << (nr & (BITS_PER_LONG-1))) &
+		(addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
 }
 
-static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
+static inline int variable_test_bit(long nr, volatile const unsigned long *addr)
 {
 	int oldbit;
 
diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h
index 653668d..4a8cb8d 100644
--- a/arch/x86/include/asm/bootparam_utils.h
+++ b/arch/x86/include/asm/bootparam_utils.h
@@ -35,9 +35,9 @@
 	 */
 	if (boot_params->sentinel) {
 		/* fields in boot_params are left uninitialized, clear them */
-		memset(&boot_params->olpc_ofw_header, 0,
+		memset(&boot_params->ext_ramdisk_image, 0,
 		       (char *)&boot_params->efi_info -
-			(char *)&boot_params->olpc_ofw_header);
+			(char *)&boot_params->ext_ramdisk_image);
 		memset(&boot_params->kbd_status, 0,
 		       (char *)&boot_params->hdr -
 		       (char *)&boot_params->kbd_status);
diff --git a/arch/x86/include/asm/checksum_32.h b/arch/x86/include/asm/checksum_32.h
index 46fc474..f50de69 100644
--- a/arch/x86/include/asm/checksum_32.h
+++ b/arch/x86/include/asm/checksum_32.h
@@ -49,9 +49,15 @@
 						 int len, __wsum sum,
 						 int *err_ptr)
 {
+	__wsum ret;
+
 	might_sleep();
-	return csum_partial_copy_generic((__force void *)src, dst,
-					 len, sum, err_ptr, NULL);
+	stac();
+	ret = csum_partial_copy_generic((__force void *)src, dst,
+					len, sum, err_ptr, NULL);
+	clac();
+
+	return ret;
 }
 
 /*
@@ -176,10 +182,16 @@
 					   int len, __wsum sum,
 					   int *err_ptr)
 {
+	__wsum ret;
+
 	might_sleep();
-	if (access_ok(VERIFY_WRITE, dst, len))
-		return csum_partial_copy_generic(src, (__force void *)dst,
-						 len, sum, NULL, err_ptr);
+	if (access_ok(VERIFY_WRITE, dst, len)) {
+		stac();
+		ret = csum_partial_copy_generic(src, (__force void *)dst,
+						len, sum, NULL, err_ptr);
+		clac();
+		return ret;
+	}
 
 	if (len)
 		*err_ptr = -EFAULT;
diff --git a/arch/x86/include/asm/checksum_64.h b/arch/x86/include/asm/checksum_64.h
index 9bfdc41..e6fd8a0 100644
--- a/arch/x86/include/asm/checksum_64.h
+++ b/arch/x86/include/asm/checksum_64.h
@@ -133,7 +133,7 @@
 
 
 /* Do not call this directly. Use the wrappers below */
-extern __wsum csum_partial_copy_generic(const void *src, const void *dst,
+extern __visible __wsum csum_partial_copy_generic(const void *src, const void *dst,
 					int len, __wsum sum,
 					int *src_err_ptr, int *dst_err_ptr);
 
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 47538a6..d3f5c63 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -366,9 +366,10 @@
  */
 static __always_inline __pure bool __static_cpu_has(u16 bit)
 {
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+#ifdef CC_HAVE_ASM_GOTO
 
 #ifdef CONFIG_X86_DEBUG_STATIC_CPU_HAS
+
 		/*
 		 * Catch too early usage of this before alternatives
 		 * have run.
@@ -384,6 +385,7 @@
 			 ".previous\n"
 			 /* skipping size check since replacement size = 0 */
 			 : : "i" (X86_FEATURE_ALWAYS) : : t_warn);
+
 #endif
 
 		asm goto("1: jmp %l[t_no]\n"
@@ -406,7 +408,9 @@
 		warn_pre_alternatives();
 		return false;
 #endif
-#else /* GCC_VERSION >= 40500 */
+
+#else /* CC_HAVE_ASM_GOTO */
+
 		u8 flag;
 		/* Open-coded due to __stringify() in ALTERNATIVE() */
 		asm volatile("1: movb $0,%0\n"
@@ -427,7 +431,8 @@
 			     ".previous\n"
 			     : "=qm" (flag) : "i" (bit));
 		return flag;
-#endif
+
+#endif /* CC_HAVE_ASM_GOTO */
 }
 
 #define static_cpu_has(bit)					\
@@ -441,7 +446,7 @@
 
 static __always_inline __pure bool _static_cpu_has_safe(u16 bit)
 {
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 5
+#ifdef CC_HAVE_ASM_GOTO
 /*
  * We need to spell the jumps to the compiler because, depending on the offset,
  * the replacement jump can be bigger than the original jump, and this we cannot
@@ -475,7 +480,7 @@
 		return false;
 	t_dynamic:
 		return __static_cpu_has_safe(bit);
-#else /* GCC_VERSION >= 40500 */
+#else
 		u8 flag;
 		/* Open-coded due to __stringify() in ALTERNATIVE() */
 		asm volatile("1: movb $2,%0\n"
@@ -511,7 +516,7 @@
 			     : "=qm" (flag)
 			     : "i" (bit), "i" (X86_FEATURE_ALWAYS));
 		return (flag == 2 ? __static_cpu_has_safe(bit) : flag);
-#endif
+#endif /* CC_HAVE_ASM_GOTO */
 }
 
 #define static_cpu_has_safe(bit)				\
diff --git a/arch/x86/include/asm/e820.h b/arch/x86/include/asm/e820.h
index cccd07f..779c2ef 100644
--- a/arch/x86/include/asm/e820.h
+++ b/arch/x86/include/asm/e820.h
@@ -29,7 +29,7 @@
 extern int e820_search_gap(unsigned long *gapstart, unsigned long *gapsize,
 			unsigned long start_addr, unsigned long long end_addr);
 struct setup_data;
-extern void parse_e820_ext(struct setup_data *data);
+extern void parse_e820_ext(u64 phys_addr, u32 data_len);
 
 #if defined(CONFIG_X86_64) || \
 	(defined(CONFIG_X86_32) && defined(CONFIG_HIBERNATION))
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index e4ac559..92b3bae 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -26,56 +26,56 @@
 #include <asm/sections.h>
 
 /* Interrupt handlers registered during init_IRQ */
-extern void apic_timer_interrupt(void);
-extern void x86_platform_ipi(void);
-extern void kvm_posted_intr_ipi(void);
-extern void error_interrupt(void);
-extern void irq_work_interrupt(void);
+extern asmlinkage void apic_timer_interrupt(void);
+extern asmlinkage void x86_platform_ipi(void);
+extern asmlinkage void kvm_posted_intr_ipi(void);
+extern asmlinkage void error_interrupt(void);
+extern asmlinkage void irq_work_interrupt(void);
 
-extern void spurious_interrupt(void);
-extern void thermal_interrupt(void);
-extern void reschedule_interrupt(void);
+extern asmlinkage void spurious_interrupt(void);
+extern asmlinkage void thermal_interrupt(void);
+extern asmlinkage void reschedule_interrupt(void);
 
-extern void invalidate_interrupt(void);
-extern void invalidate_interrupt0(void);
-extern void invalidate_interrupt1(void);
-extern void invalidate_interrupt2(void);
-extern void invalidate_interrupt3(void);
-extern void invalidate_interrupt4(void);
-extern void invalidate_interrupt5(void);
-extern void invalidate_interrupt6(void);
-extern void invalidate_interrupt7(void);
-extern void invalidate_interrupt8(void);
-extern void invalidate_interrupt9(void);
-extern void invalidate_interrupt10(void);
-extern void invalidate_interrupt11(void);
-extern void invalidate_interrupt12(void);
-extern void invalidate_interrupt13(void);
-extern void invalidate_interrupt14(void);
-extern void invalidate_interrupt15(void);
-extern void invalidate_interrupt16(void);
-extern void invalidate_interrupt17(void);
-extern void invalidate_interrupt18(void);
-extern void invalidate_interrupt19(void);
-extern void invalidate_interrupt20(void);
-extern void invalidate_interrupt21(void);
-extern void invalidate_interrupt22(void);
-extern void invalidate_interrupt23(void);
-extern void invalidate_interrupt24(void);
-extern void invalidate_interrupt25(void);
-extern void invalidate_interrupt26(void);
-extern void invalidate_interrupt27(void);
-extern void invalidate_interrupt28(void);
-extern void invalidate_interrupt29(void);
-extern void invalidate_interrupt30(void);
-extern void invalidate_interrupt31(void);
+extern asmlinkage void invalidate_interrupt(void);
+extern asmlinkage void invalidate_interrupt0(void);
+extern asmlinkage void invalidate_interrupt1(void);
+extern asmlinkage void invalidate_interrupt2(void);
+extern asmlinkage void invalidate_interrupt3(void);
+extern asmlinkage void invalidate_interrupt4(void);
+extern asmlinkage void invalidate_interrupt5(void);
+extern asmlinkage void invalidate_interrupt6(void);
+extern asmlinkage void invalidate_interrupt7(void);
+extern asmlinkage void invalidate_interrupt8(void);
+extern asmlinkage void invalidate_interrupt9(void);
+extern asmlinkage void invalidate_interrupt10(void);
+extern asmlinkage void invalidate_interrupt11(void);
+extern asmlinkage void invalidate_interrupt12(void);
+extern asmlinkage void invalidate_interrupt13(void);
+extern asmlinkage void invalidate_interrupt14(void);
+extern asmlinkage void invalidate_interrupt15(void);
+extern asmlinkage void invalidate_interrupt16(void);
+extern asmlinkage void invalidate_interrupt17(void);
+extern asmlinkage void invalidate_interrupt18(void);
+extern asmlinkage void invalidate_interrupt19(void);
+extern asmlinkage void invalidate_interrupt20(void);
+extern asmlinkage void invalidate_interrupt21(void);
+extern asmlinkage void invalidate_interrupt22(void);
+extern asmlinkage void invalidate_interrupt23(void);
+extern asmlinkage void invalidate_interrupt24(void);
+extern asmlinkage void invalidate_interrupt25(void);
+extern asmlinkage void invalidate_interrupt26(void);
+extern asmlinkage void invalidate_interrupt27(void);
+extern asmlinkage void invalidate_interrupt28(void);
+extern asmlinkage void invalidate_interrupt29(void);
+extern asmlinkage void invalidate_interrupt30(void);
+extern asmlinkage void invalidate_interrupt31(void);
 
-extern void irq_move_cleanup_interrupt(void);
-extern void reboot_interrupt(void);
-extern void threshold_interrupt(void);
+extern asmlinkage void irq_move_cleanup_interrupt(void);
+extern asmlinkage void reboot_interrupt(void);
+extern asmlinkage void threshold_interrupt(void);
 
-extern void call_function_interrupt(void);
-extern void call_function_single_interrupt(void);
+extern asmlinkage void call_function_interrupt(void);
+extern asmlinkage void call_function_single_interrupt(void);
 
 #ifdef CONFIG_TRACING
 /* Interrupt handlers registered during init_IRQ */
@@ -172,22 +172,18 @@
 extern void eisa_set_level_irq(unsigned int irq);
 
 /* SMP */
-extern void smp_apic_timer_interrupt(struct pt_regs *);
-extern void smp_spurious_interrupt(struct pt_regs *);
-extern void smp_x86_platform_ipi(struct pt_regs *);
-extern void smp_error_interrupt(struct pt_regs *);
+extern __visible void smp_apic_timer_interrupt(struct pt_regs *);
+extern __visible void smp_spurious_interrupt(struct pt_regs *);
+extern __visible void smp_x86_platform_ipi(struct pt_regs *);
+extern __visible void smp_error_interrupt(struct pt_regs *);
 #ifdef CONFIG_X86_IO_APIC
 extern asmlinkage void smp_irq_move_cleanup_interrupt(void);
 #endif
 #ifdef CONFIG_SMP
-extern void smp_reschedule_interrupt(struct pt_regs *);
-extern void smp_call_function_interrupt(struct pt_regs *);
-extern void smp_call_function_single_interrupt(struct pt_regs *);
-#ifdef CONFIG_X86_32
-extern void smp_invalidate_interrupt(struct pt_regs *);
-#else
-extern asmlinkage void smp_invalidate_interrupt(struct pt_regs *);
-#endif
+extern __visible void smp_reschedule_interrupt(struct pt_regs *);
+extern __visible void smp_call_function_interrupt(struct pt_regs *);
+extern __visible void smp_call_function_single_interrupt(struct pt_regs *);
+extern __visible void smp_invalidate_interrupt(struct pt_regs *);
 #endif
 
 extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void);
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index 2d4b5e6..e42f758 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -33,7 +33,7 @@
 	const char	*name;
 
 	/* Detection routine */
-	bool		(*detect)(void);
+	uint32_t	(*detect)(void);
 
 	/* Adjust CPU feature bits (run once per CPU) */
 	void		(*set_cpu_features)(struct cpuinfo_x86 *);
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
index 57873be..0ea10f27 100644
--- a/arch/x86/include/asm/irq.h
+++ b/arch/x86/include/asm/irq.h
@@ -33,7 +33,7 @@
 extern void native_init_IRQ(void);
 extern bool handle_irq(unsigned irq, struct pt_regs *regs);
 
-extern unsigned int do_IRQ(struct pt_regs *regs);
+extern __visible unsigned int do_IRQ(struct pt_regs *regs);
 
 /* Interrupt vector management */
 extern DECLARE_BITMAP(used_vectors, NR_VECTORS);
diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h
index 5a6d287..9454c16 100644
--- a/arch/x86/include/asm/kprobes.h
+++ b/arch/x86/include/asm/kprobes.h
@@ -49,10 +49,10 @@
 #define flush_insn_slot(p)	do { } while (0)
 
 /* optinsn template addresses */
-extern kprobe_opcode_t optprobe_template_entry;
-extern kprobe_opcode_t optprobe_template_val;
-extern kprobe_opcode_t optprobe_template_call;
-extern kprobe_opcode_t optprobe_template_end;
+extern __visible kprobe_opcode_t optprobe_template_entry;
+extern __visible kprobe_opcode_t optprobe_template_val;
+extern __visible kprobe_opcode_t optprobe_template_call;
+extern __visible kprobe_opcode_t optprobe_template_end;
 #define MAX_OPTIMIZED_LENGTH (MAX_INSN_SIZE + RELATIVE_ADDR_SIZE)
 #define MAX_OPTINSN_SIZE 				\
 	(((unsigned long)&optprobe_template_end -	\
@@ -62,7 +62,7 @@
 extern const int kretprobe_blacklist_size;
 
 void arch_remove_kprobe(struct kprobe *p);
-void kretprobe_trampoline(void);
+asmlinkage void kretprobe_trampoline(void);
 
 /* Architecture specific copy of original instruction*/
 struct arch_specific_insn {
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f87f7fc..c76ff74 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -286,6 +286,7 @@
 	u64 *pae_root;
 	u64 *lm_root;
 	u64 rsvd_bits_mask[2][4];
+	u64 bad_mt_xwr;
 
 	/*
 	 * Bitmap: bit set = last pte in walk
@@ -323,6 +324,7 @@
 	u64 global_ovf_ctrl;
 	u64 counter_bitmask[2];
 	u64 global_ctrl_mask;
+	u64 reserved_bits;
 	u8 version;
 	struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC];
 	struct kvm_pmc fixed_counters[INTEL_PMC_MAX_FIXED];
@@ -511,6 +513,14 @@
 	 * instruction.
 	 */
 	bool write_fault_to_shadow_pgtable;
+
+	/* set at EPT violation at this point */
+	unsigned long exit_qualification;
+
+	/* pv related host specific info */
+	struct {
+		bool pv_unhalted;
+	} pv;
 };
 
 struct kvm_lpage_info {
@@ -802,8 +812,8 @@
 extern u32  kvm_max_guest_tsc_khz;
 
 enum emulation_result {
-	EMULATE_DONE,       /* no further processing */
-	EMULATE_DO_MMIO,      /* kvm_run filled with mmio request */
+	EMULATE_DONE,         /* no further processing */
+	EMULATE_USER_EXIT,    /* kvm_run ready for userspace exit */
 	EMULATE_FAIL,         /* can't emulate this instruction */
 };
 
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index 695399f..1df1159 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -85,26 +85,20 @@
 	return ret;
 }
 
+static inline uint32_t kvm_cpuid_base(void)
+{
+	if (boot_cpu_data.cpuid_level < 0)
+		return 0;	/* So we don't blow up on old processors */
+
+	if (cpu_has_hypervisor)
+		return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
+
+	return 0;
+}
+
 static inline bool kvm_para_available(void)
 {
-	unsigned int eax, ebx, ecx, edx;
-	char signature[13];
-
-	if (boot_cpu_data.cpuid_level < 0)
-		return false;	/* So we don't blow up on old processors */
-
-	if (cpu_has_hypervisor) {
-		cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
-		memcpy(signature + 0, &ebx, 4);
-		memcpy(signature + 4, &ecx, 4);
-		memcpy(signature + 8, &edx, 4);
-		signature[12] = 0;
-
-		if (strcmp(signature, "KVMKVMKVM") == 0)
-			return true;
-	}
-
-	return false;
+	return kvm_cpuid_base() != 0;
 }
 
 static inline unsigned int kvm_arch_para_features(void)
@@ -118,10 +112,20 @@
 void kvm_async_pf_task_wake(u32 token);
 u32 kvm_read_and_reset_pf_reason(void);
 extern void kvm_disable_steal_time(void);
-#else
-#define kvm_guest_init() do { } while (0)
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+void __init kvm_spinlock_init(void);
+#else /* !CONFIG_PARAVIRT_SPINLOCKS */
+static inline void kvm_spinlock_init(void)
+{
+}
+#endif /* CONFIG_PARAVIRT_SPINLOCKS */
+
+#else /* CONFIG_KVM_GUEST */
+#define kvm_guest_init() do {} while (0)
 #define kvm_async_pf_task_wait(T) do {} while(0)
 #define kvm_async_pf_task_wake(T) do {} while(0)
+
 static inline u32 kvm_read_and_reset_pf_reason(void)
 {
 	return 0;
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 29e3093..cbe6b9e 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -32,11 +32,20 @@
 #define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
 #define MCI_STATUS_S	 (1ULL<<56)  /* Signaled machine check */
 #define MCI_STATUS_AR	 (1ULL<<55)  /* Action required */
-#define MCACOD		  0xffff     /* MCA Error Code */
+
+/*
+ * Note that the full MCACOD field of IA32_MCi_STATUS MSR is
+ * bits 15:0.  But bit 12 is the 'F' bit, defined for corrected
+ * errors to indicate that errors are being filtered by hardware.
+ * We should mask out bit 12 when looking for specific signatures
+ * of uncorrected errors - so the F bit is deliberately skipped
+ * in this #define.
+ */
+#define MCACOD		  0xefff     /* MCA Error Code */
 
 /* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
 #define MCACOD_SCRUB	0x00C0	/* 0xC0-0xCF Memory Scrubbing */
-#define MCACOD_SCRUBMSK	0xfff0
+#define MCACOD_SCRUBMSK	0xeff0	/* Skip bit 12 ('F' bit) */
 #define MCACOD_L3WB	0x017A	/* L3 Explicit Writeback */
 #define MCACOD_DATA	0x0134	/* Data Load */
 #define MCACOD_INSTR	0x0150	/* Instruction Fetch */
@@ -188,6 +197,9 @@
 				    const char __user *ubuf,
 				    size_t usize, loff_t *off));
 
+/* Disable CMCI/polling for MCA bank claimed by firmware */
+extern void mce_disable_bank(int bank);
+
 /*
  * Exception handler
  */
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
index 50e5c58..4c01917 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -59,7 +59,7 @@
 
 extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
 extern int apply_microcode_amd(int cpu);
-extern enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size);
+extern enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
 
 #ifdef CONFIG_MICROCODE_AMD_EARLY
 #ifdef CONFIG_X86_32
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index cdbf367..be12c53 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -45,22 +45,28 @@
 		/* Re-load page tables */
 		load_cr3(next->pgd);
 
-		/* stop flush ipis for the previous mm */
+		/* Stop flush ipis for the previous mm */
 		cpumask_clear_cpu(cpu, mm_cpumask(prev));
 
-		/*
-		 * load the LDT, if the LDT is different:
-		 */
+		/* Load the LDT, if the LDT is different: */
 		if (unlikely(prev->context.ldt != next->context.ldt))
 			load_LDT_nolock(&next->context);
 	}
 #ifdef CONFIG_SMP
-	else {
+	  else {
 		this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
 		BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next);
 
-		if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
-			/* We were in lazy tlb mode and leave_mm disabled
+		if (!cpumask_test_cpu(cpu, mm_cpumask(next))) {
+			/*
+			 * On established mms, the mm_cpumask is only changed
+			 * from irq context, from ptep_clear_flush() while in
+			 * lazy tlb mode, and here. Irqs are blocked during
+			 * schedule, protecting us from simultaneous changes.
+			 */
+			cpumask_set_cpu(cpu, mm_cpumask(next));
+			/*
+			 * We were in lazy tlb mode and leave_mm disabled
 			 * tlb flush IPI delivery. We must reload CR3
 			 * to make sure to use no freed page tables.
 			 */
diff --git a/arch/x86/include/asm/mutex_64.h b/arch/x86/include/asm/mutex_64.h
index 2c543ff..e7e6751 100644
--- a/arch/x86/include/asm/mutex_64.h
+++ b/arch/x86/include/asm/mutex_64.h
@@ -16,6 +16,20 @@
  *
  * Atomically decrements @v and calls <fail_fn> if the result is negative.
  */
+#ifdef CC_HAVE_ASM_GOTO
+static inline void __mutex_fastpath_lock(atomic_t *v,
+					 void (*fail_fn)(atomic_t *))
+{
+	asm volatile goto(LOCK_PREFIX "   decl %0\n"
+			  "   jns %l[exit]\n"
+			  : : "m" (v->counter)
+			  : "memory", "cc"
+			  : exit);
+	fail_fn(v);
+exit:
+	return;
+}
+#else
 #define __mutex_fastpath_lock(v, fail_fn)			\
 do {								\
 	unsigned long dummy;					\
@@ -32,6 +46,7 @@
 		     : "rax", "rsi", "rdx", "rcx",		\
 		       "r8", "r9", "r10", "r11", "memory");	\
 } while (0)
+#endif
 
 /**
  *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
@@ -56,6 +71,20 @@
  *
  * Atomically increments @v and calls <fail_fn> if the result is nonpositive.
  */
+#ifdef CC_HAVE_ASM_GOTO
+static inline void __mutex_fastpath_unlock(atomic_t *v,
+					   void (*fail_fn)(atomic_t *))
+{
+	asm volatile goto(LOCK_PREFIX "   incl %0\n"
+			  "   jg %l[exit]\n"
+			  : : "m" (v->counter)
+			  : "memory", "cc"
+			  : exit);
+	fail_fn(v);
+exit:
+	return;
+}
+#else
 #define __mutex_fastpath_unlock(v, fail_fn)			\
 do {								\
 	unsigned long dummy;					\
@@ -72,6 +101,7 @@
 		     : "rax", "rsi", "rdx", "rcx",		\
 		       "r8", "r9", "r10", "r11", "memory");	\
 } while (0)
+#endif
 
 #define __mutex_slowpath_needs_to_unlock()	1
 
diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h
index ef17af0..f48b17d 100644
--- a/arch/x86/include/asm/page_32_types.h
+++ b/arch/x86/include/asm/page_32_types.h
@@ -15,6 +15,8 @@
  */
 #define __PAGE_OFFSET		_AC(CONFIG_PAGE_OFFSET, UL)
 
+#define __START_KERNEL_map	__PAGE_OFFSET
+
 #define THREAD_SIZE_ORDER	1
 #define THREAD_SIZE		(PAGE_SIZE << THREAD_SIZE_ORDER)
 
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 6c896fb..43dcd80 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -32,11 +32,6 @@
  */
 #define __PAGE_OFFSET           _AC(0xffff880000000000, UL)
 
-#define __PHYSICAL_START	((CONFIG_PHYSICAL_START +	 	\
-				  (CONFIG_PHYSICAL_ALIGN - 1)) &	\
-				 ~(CONFIG_PHYSICAL_ALIGN - 1))
-
-#define __START_KERNEL		(__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map	_AC(0xffffffff80000000, UL)
 
 /* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index 54c9787..f97fbe3 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -33,6 +33,11 @@
 	(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
 	 VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+#define __PHYSICAL_START	ALIGN(CONFIG_PHYSICAL_START, \
+				      CONFIG_PHYSICAL_ALIGN)
+
+#define __START_KERNEL		(__START_KERNEL_map + __PHYSICAL_START)
+
 #ifdef CONFIG_X86_64
 #include <asm/page_64_types.h>
 #else
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index cfdc9ee..401f350 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -712,36 +712,16 @@
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PARAVIRT_SPINLOCKS)
 
-static inline int arch_spin_is_locked(struct arch_spinlock *lock)
+static __always_inline void __ticket_lock_spinning(struct arch_spinlock *lock,
+							__ticket_t ticket)
 {
-	return PVOP_CALL1(int, pv_lock_ops.spin_is_locked, lock);
+	PVOP_VCALLEE2(pv_lock_ops.lock_spinning, lock, ticket);
 }
 
-static inline int arch_spin_is_contended(struct arch_spinlock *lock)
+static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock,
+							__ticket_t ticket)
 {
-	return PVOP_CALL1(int, pv_lock_ops.spin_is_contended, lock);
-}
-#define arch_spin_is_contended	arch_spin_is_contended
-
-static __always_inline void arch_spin_lock(struct arch_spinlock *lock)
-{
-	PVOP_VCALL1(pv_lock_ops.spin_lock, lock);
-}
-
-static __always_inline void arch_spin_lock_flags(struct arch_spinlock *lock,
-						  unsigned long flags)
-{
-	PVOP_VCALL2(pv_lock_ops.spin_lock_flags, lock, flags);
-}
-
-static __always_inline int arch_spin_trylock(struct arch_spinlock *lock)
-{
-	return PVOP_CALL1(int, pv_lock_ops.spin_trylock, lock);
-}
-
-static __always_inline void arch_spin_unlock(struct arch_spinlock *lock)
-{
-	PVOP_VCALL1(pv_lock_ops.spin_unlock, lock);
+	PVOP_VCALL2(pv_lock_ops.unlock_kick, lock, ticket);
 }
 
 #endif
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 0db1fca..aab8f67 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -327,13 +327,15 @@
 };
 
 struct arch_spinlock;
+#ifdef CONFIG_SMP
+#include <asm/spinlock_types.h>
+#else
+typedef u16 __ticket_t;
+#endif
+
 struct pv_lock_ops {
-	int (*spin_is_locked)(struct arch_spinlock *lock);
-	int (*spin_is_contended)(struct arch_spinlock *lock);
-	void (*spin_lock)(struct arch_spinlock *lock);
-	void (*spin_lock_flags)(struct arch_spinlock *lock, unsigned long flags);
-	int (*spin_trylock)(struct arch_spinlock *lock);
-	void (*spin_unlock)(struct arch_spinlock *lock);
+	struct paravirt_callee_save lock_spinning;
+	void (*unlock_kick)(struct arch_spinlock *lock, __ticket_t ticket);
 };
 
 /* This contains all the paravirt structures: we get a convenient
@@ -387,7 +389,8 @@
 
 /* Simple instruction patching code. */
 #define DEF_NATIVE(ops, name, code) 					\
-	extern const char start_##ops##_##name[], end_##ops##_##name[];	\
+	extern const char start_##ops##_##name[] __visible,		\
+			  end_##ops##_##name[] __visible;		\
 	asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
 
 unsigned paravirt_patch_nop(void);
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 1c00631..8d16bef 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -22,7 +22,8 @@
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
+	__visible;
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
 extern spinlock_t pgd_lock;
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 24cf5ae..987c75e 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -412,7 +412,7 @@
 	};
 };
 
-DECLARE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union);
+DECLARE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union) __visible;
 DECLARE_INIT_PER_CPU(irq_stack_union);
 
 DECLARE_PER_CPU(char *, irq_stack_ptr);
@@ -942,33 +942,19 @@
 
 extern u16 amd_get_nb_id(int cpu);
 
-struct aperfmperf {
-	u64 aperf, mperf;
-};
-
-static inline void get_aperfmperf(struct aperfmperf *am)
+static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
 {
-	WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_APERFMPERF));
+	uint32_t base, eax, signature[3];
 
-	rdmsrl(MSR_IA32_APERF, am->aperf);
-	rdmsrl(MSR_IA32_MPERF, am->mperf);
-}
+	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+		cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
 
-#define APERFMPERF_SHIFT 10
+		if (!memcmp(sig, signature, 12) &&
+		    (leaves == 0 || ((eax - base) >= leaves)))
+			return base;
+	}
 
-static inline
-unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,
-				    struct aperfmperf *new)
-{
-	u64 aperf = new->aperf - old->aperf;
-	u64 mperf = new->mperf - old->mperf;
-	unsigned long ratio = aperf;
-
-	mperf >>= APERFMPERF_SHIFT;
-	if (mperf)
-		ratio = div64_u64(aperf, mperf);
-
-	return ratio;
+	return 0;
 }
 
 extern unsigned long arch_align_stack(unsigned long sp);
diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h
index 109a9dd..be8269b 100644
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -93,7 +93,6 @@
 
 struct pvclock_vsyscall_time_info {
 	struct pvclock_vcpu_time_info pvti;
-	u32 migrate_count;
 } __attribute__((__aligned__(SMP_CACHE_BYTES)));
 
 #define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index b7bf350..3475554 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -6,6 +6,8 @@
 
 #define COMMAND_LINE_SIZE 2048
 
+#include <linux/linkage.h>
+
 #ifdef __i386__
 
 #include <linux/pfn.h>
@@ -108,11 +110,11 @@
 extern void probe_roms(void);
 #ifdef __i386__
 
-void __init i386_start_kernel(void);
+asmlinkage void __init i386_start_kernel(void);
 
 #else
-void __init x86_64_start_kernel(char *real_mode);
-void __init x86_64_start_reservations(char *real_mode_data);
+asmlinkage void __init x86_64_start_kernel(char *real_mode);
+asmlinkage void __init x86_64_start_reservations(char *real_mode_data);
 
 #endif /* __i386__ */
 #endif /* _SETUP */
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 2f4d924..645cad2 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -101,7 +101,7 @@
 	asm volatile("wbinvd": : :"memory");
 }
 
-extern void native_load_gs_index(unsigned);
+extern asmlinkage void native_load_gs_index(unsigned);
 
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index e3ddd7d..bf156de 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -1,11 +1,14 @@
 #ifndef _ASM_X86_SPINLOCK_H
 #define _ASM_X86_SPINLOCK_H
 
+#include <linux/jump_label.h>
 #include <linux/atomic.h>
 #include <asm/page.h>
 #include <asm/processor.h>
 #include <linux/compiler.h>
 #include <asm/paravirt.h>
+#include <asm/bitops.h>
+
 /*
  * Your basic SMP spinlocks, allowing only a single CPU anywhere
  *
@@ -34,6 +37,36 @@
 # define UNLOCK_LOCK_PREFIX
 #endif
 
+/* How long a lock should spin before we consider blocking */
+#define SPIN_THRESHOLD	(1 << 15)
+
+extern struct static_key paravirt_ticketlocks_enabled;
+static __always_inline bool static_key_false(struct static_key *key);
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+
+static inline void __ticket_enter_slowpath(arch_spinlock_t *lock)
+{
+	set_bit(0, (volatile unsigned long *)&lock->tickets.tail);
+}
+
+#else  /* !CONFIG_PARAVIRT_SPINLOCKS */
+static __always_inline void __ticket_lock_spinning(arch_spinlock_t *lock,
+							__ticket_t ticket)
+{
+}
+static inline void __ticket_unlock_kick(arch_spinlock_t *lock,
+							__ticket_t ticket)
+{
+}
+
+#endif /* CONFIG_PARAVIRT_SPINLOCKS */
+
+static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock)
+{
+	return lock.tickets.head == lock.tickets.tail;
+}
+
 /*
  * Ticket locks are conceptually two parts, one indicating the current head of
  * the queue, and the other indicating the current tail. The lock is acquired
@@ -47,90 +80,108 @@
  * in the high part, because a wide xadd increment of the low part would carry
  * up and contaminate the high part.
  */
-static __always_inline void __ticket_spin_lock(arch_spinlock_t *lock)
+static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
 {
-	register struct __raw_tickets inc = { .tail = 1 };
+	register struct __raw_tickets inc = { .tail = TICKET_LOCK_INC };
 
 	inc = xadd(&lock->tickets, inc);
+	if (likely(inc.head == inc.tail))
+		goto out;
 
+	inc.tail &= ~TICKET_SLOWPATH_FLAG;
 	for (;;) {
-		if (inc.head == inc.tail)
-			break;
-		cpu_relax();
-		inc.head = ACCESS_ONCE(lock->tickets.head);
+		unsigned count = SPIN_THRESHOLD;
+
+		do {
+			if (ACCESS_ONCE(lock->tickets.head) == inc.tail)
+				goto out;
+			cpu_relax();
+		} while (--count);
+		__ticket_lock_spinning(lock, inc.tail);
 	}
-	barrier();		/* make sure nothing creeps before the lock is taken */
+out:	barrier();	/* make sure nothing creeps before the lock is taken */
 }
 
-static __always_inline int __ticket_spin_trylock(arch_spinlock_t *lock)
+static __always_inline int arch_spin_trylock(arch_spinlock_t *lock)
 {
 	arch_spinlock_t old, new;
 
 	old.tickets = ACCESS_ONCE(lock->tickets);
-	if (old.tickets.head != old.tickets.tail)
+	if (old.tickets.head != (old.tickets.tail & ~TICKET_SLOWPATH_FLAG))
 		return 0;
 
-	new.head_tail = old.head_tail + (1 << TICKET_SHIFT);
+	new.head_tail = old.head_tail + (TICKET_LOCK_INC << TICKET_SHIFT);
 
 	/* cmpxchg is a full barrier, so nothing can move before it */
 	return cmpxchg(&lock->head_tail, old.head_tail, new.head_tail) == old.head_tail;
 }
 
-static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
+static inline void __ticket_unlock_slowpath(arch_spinlock_t *lock,
+					    arch_spinlock_t old)
 {
-	__add(&lock->tickets.head, 1, UNLOCK_LOCK_PREFIX);
+	arch_spinlock_t new;
+
+	BUILD_BUG_ON(((__ticket_t)NR_CPUS) != NR_CPUS);
+
+	/* Perform the unlock on the "before" copy */
+	old.tickets.head += TICKET_LOCK_INC;
+
+	/* Clear the slowpath flag */
+	new.head_tail = old.head_tail & ~(TICKET_SLOWPATH_FLAG << TICKET_SHIFT);
+
+	/*
+	 * If the lock is uncontended, clear the flag - use cmpxchg in
+	 * case it changes behind our back though.
+	 */
+	if (new.tickets.head != new.tickets.tail ||
+	    cmpxchg(&lock->head_tail, old.head_tail,
+					new.head_tail) != old.head_tail) {
+		/*
+		 * Lock still has someone queued for it, so wake up an
+		 * appropriate waiter.
+		 */
+		__ticket_unlock_kick(lock, old.tickets.head);
+	}
 }
 
-static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
+static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+	if (TICKET_SLOWPATH_FLAG &&
+	    static_key_false(&paravirt_ticketlocks_enabled)) {
+		arch_spinlock_t prev;
+
+		prev = *lock;
+		add_smp(&lock->tickets.head, TICKET_LOCK_INC);
+
+		/* add_smp() is a full mb() */
+
+		if (unlikely(lock->tickets.tail & TICKET_SLOWPATH_FLAG))
+			__ticket_unlock_slowpath(lock, prev);
+	} else
+		__add(&lock->tickets.head, TICKET_LOCK_INC, UNLOCK_LOCK_PREFIX);
+}
+
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
 	struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
 
 	return tmp.tail != tmp.head;
 }
 
-static inline int __ticket_spin_is_contended(arch_spinlock_t *lock)
+static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
 	struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
 
-	return (__ticket_t)(tmp.tail - tmp.head) > 1;
-}
-
-#ifndef CONFIG_PARAVIRT_SPINLOCKS
-
-static inline int arch_spin_is_locked(arch_spinlock_t *lock)
-{
-	return __ticket_spin_is_locked(lock);
-}
-
-static inline int arch_spin_is_contended(arch_spinlock_t *lock)
-{
-	return __ticket_spin_is_contended(lock);
+	return (__ticket_t)(tmp.tail - tmp.head) > TICKET_LOCK_INC;
 }
 #define arch_spin_is_contended	arch_spin_is_contended
 
-static __always_inline void arch_spin_lock(arch_spinlock_t *lock)
-{
-	__ticket_spin_lock(lock);
-}
-
-static __always_inline int arch_spin_trylock(arch_spinlock_t *lock)
-{
-	return __ticket_spin_trylock(lock);
-}
-
-static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)
-{
-	__ticket_spin_unlock(lock);
-}
-
 static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
 						  unsigned long flags)
 {
 	arch_spin_lock(lock);
 }
 
-#endif	/* CONFIG_PARAVIRT_SPINLOCKS */
-
 static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
 {
 	while (arch_spin_is_locked(lock))
diff --git a/arch/x86/include/asm/spinlock_types.h b/arch/x86/include/asm/spinlock_types.h
index ad0ad07..4f1bea1 100644
--- a/arch/x86/include/asm/spinlock_types.h
+++ b/arch/x86/include/asm/spinlock_types.h
@@ -1,13 +1,17 @@
 #ifndef _ASM_X86_SPINLOCK_TYPES_H
 #define _ASM_X86_SPINLOCK_TYPES_H
 
-#ifndef __LINUX_SPINLOCK_TYPES_H
-# error "please don't include this file directly"
-#endif
-
 #include <linux/types.h>
 
-#if (CONFIG_NR_CPUS < 256)
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+#define __TICKET_LOCK_INC	2
+#define TICKET_SLOWPATH_FLAG	((__ticket_t)1)
+#else
+#define __TICKET_LOCK_INC	1
+#define TICKET_SLOWPATH_FLAG	((__ticket_t)0)
+#endif
+
+#if (CONFIG_NR_CPUS < (256 / __TICKET_LOCK_INC))
 typedef u8  __ticket_t;
 typedef u16 __ticketpair_t;
 #else
@@ -15,6 +19,8 @@
 typedef u32 __ticketpair_t;
 #endif
 
+#define TICKET_LOCK_INC	((__ticket_t)__TICKET_LOCK_INC)
+
 #define TICKET_SHIFT	(sizeof(__ticket_t) * 8)
 
 typedef struct arch_spinlock {
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index 4ec45b3..d7f3b3b 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -2,8 +2,8 @@
 #define _ASM_X86_SWITCH_TO_H
 
 struct task_struct; /* one of the stranger aspects of C forward declarations */
-struct task_struct *__switch_to(struct task_struct *prev,
-				struct task_struct *next);
+__visible struct task_struct *__switch_to(struct task_struct *prev,
+					   struct task_struct *next);
 struct tss_struct;
 void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
 		      struct tss_struct *tss);
diff --git a/arch/x86/include/asm/sync_bitops.h b/arch/x86/include/asm/sync_bitops.h
index 9d09b40..05af3b3 100644
--- a/arch/x86/include/asm/sync_bitops.h
+++ b/arch/x86/include/asm/sync_bitops.h
@@ -26,9 +26,9 @@
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void sync_set_bit(int nr, volatile unsigned long *addr)
+static inline void sync_set_bit(long nr, volatile unsigned long *addr)
 {
-	asm volatile("lock; btsl %1,%0"
+	asm volatile("lock; bts %1,%0"
 		     : "+m" (ADDR)
 		     : "Ir" (nr)
 		     : "memory");
@@ -44,9 +44,9 @@
  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  * in order to ensure changes are visible on other processors.
  */
-static inline void sync_clear_bit(int nr, volatile unsigned long *addr)
+static inline void sync_clear_bit(long nr, volatile unsigned long *addr)
 {
-	asm volatile("lock; btrl %1,%0"
+	asm volatile("lock; btr %1,%0"
 		     : "+m" (ADDR)
 		     : "Ir" (nr)
 		     : "memory");
@@ -61,9 +61,9 @@
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static inline void sync_change_bit(int nr, volatile unsigned long *addr)
+static inline void sync_change_bit(long nr, volatile unsigned long *addr)
 {
-	asm volatile("lock; btcl %1,%0"
+	asm volatile("lock; btc %1,%0"
 		     : "+m" (ADDR)
 		     : "Ir" (nr)
 		     : "memory");
@@ -77,11 +77,11 @@
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int sync_test_and_set_bit(int nr, volatile unsigned long *addr)
+static inline int sync_test_and_set_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
-	asm volatile("lock; btsl %2,%1\n\tsbbl %0,%0"
+	asm volatile("lock; bts %2,%1\n\tsbbl %0,%0"
 		     : "=r" (oldbit), "+m" (ADDR)
 		     : "Ir" (nr) : "memory");
 	return oldbit;
@@ -95,11 +95,11 @@
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int sync_test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int sync_test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
-	asm volatile("lock; btrl %2,%1\n\tsbbl %0,%0"
+	asm volatile("lock; btr %2,%1\n\tsbbl %0,%0"
 		     : "=r" (oldbit), "+m" (ADDR)
 		     : "Ir" (nr) : "memory");
 	return oldbit;
@@ -113,11 +113,11 @@
  * This operation is atomic and cannot be reordered.
  * It also implies a memory barrier.
  */
-static inline int sync_test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int sync_test_and_change_bit(long nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
-	asm volatile("lock; btcl %2,%1\n\tsbbl %0,%0"
+	asm volatile("lock; btc %2,%1\n\tsbbl %0,%0"
 		     : "=r" (oldbit), "+m" (ADDR)
 		     : "Ir" (nr) : "memory");
 	return oldbit;
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index 2e188d6..aea284b 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -20,7 +20,8 @@
 #include <asm/thread_info.h>	/* for TS_COMPAT */
 #include <asm/unistd.h>
 
-extern const unsigned long sys_call_table[];
+typedef void (*sys_call_ptr_t)(void);
+extern const sys_call_ptr_t sys_call_table[];
 
 /*
  * Only the low 32 bits of orig_ax are meaningful, so we return int.
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index 2917a64..592a6a6 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -24,7 +24,7 @@
 asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
 
 /* kernel/signal.c */
-long sys_rt_sigreturn(void);
+asmlinkage long sys_rt_sigreturn(void);
 
 /* kernel/tls.c */
 asmlinkage long sys_set_thread_area(struct user_desc __user *);
@@ -34,7 +34,7 @@
 #ifdef CONFIG_X86_32
 
 /* kernel/signal.c */
-unsigned long sys_sigreturn(void);
+asmlinkage unsigned long sys_sigreturn(void);
 
 /* kernel/vm86_32.c */
 asmlinkage long sys_vm86old(struct vm86_struct __user *);
@@ -44,7 +44,7 @@
 
 /* X86_64 only */
 /* kernel/process_64.c */
-long sys_arch_prctl(int, unsigned long);
+asmlinkage long sys_arch_prctl(int, unsigned long);
 
 /* kernel/sys_x86_64.c */
 asmlinkage long sys_mmap(unsigned long, unsigned long, unsigned long,
diff --git a/arch/x86/include/asm/sysfb.h b/arch/x86/include/asm/sysfb.h
new file mode 100644
index 0000000..2aeb3e2
--- /dev/null
+++ b/arch/x86/include/asm/sysfb.h
@@ -0,0 +1,98 @@
+#ifndef _ARCH_X86_KERNEL_SYSFB_H
+#define _ARCH_X86_KERNEL_SYSFB_H
+
+/*
+ * Generic System Framebuffers on x86
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.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/kernel.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/screen_info.h>
+
+enum {
+	M_I17,		/* 17-Inch iMac */
+	M_I20,		/* 20-Inch iMac */
+	M_I20_SR,	/* 20-Inch iMac (Santa Rosa) */
+	M_I24,		/* 24-Inch iMac */
+	M_I24_8_1,	/* 24-Inch iMac, 8,1th gen */
+	M_I24_10_1,	/* 24-Inch iMac, 10,1th gen */
+	M_I27_11_1,	/* 27-Inch iMac, 11,1th gen */
+	M_MINI,		/* Mac Mini */
+	M_MINI_3_1,	/* Mac Mini, 3,1th gen */
+	M_MINI_4_1,	/* Mac Mini, 4,1th gen */
+	M_MB,		/* MacBook */
+	M_MB_2,		/* MacBook, 2nd rev. */
+	M_MB_3,		/* MacBook, 3rd rev. */
+	M_MB_5_1,	/* MacBook, 5th rev. */
+	M_MB_6_1,	/* MacBook, 6th rev. */
+	M_MB_7_1,	/* MacBook, 7th rev. */
+	M_MB_SR,	/* MacBook, 2nd gen, (Santa Rosa) */
+	M_MBA,		/* MacBook Air */
+	M_MBA_3,	/* Macbook Air, 3rd rev */
+	M_MBP,		/* MacBook Pro */
+	M_MBP_2,	/* MacBook Pro 2nd gen */
+	M_MBP_2_2,	/* MacBook Pro 2,2nd gen */
+	M_MBP_SR,	/* MacBook Pro (Santa Rosa) */
+	M_MBP_4,	/* MacBook Pro, 4th gen */
+	M_MBP_5_1,	/* MacBook Pro, 5,1th gen */
+	M_MBP_5_2,	/* MacBook Pro, 5,2th gen */
+	M_MBP_5_3,	/* MacBook Pro, 5,3rd gen */
+	M_MBP_6_1,	/* MacBook Pro, 6,1th gen */
+	M_MBP_6_2,	/* MacBook Pro, 6,2th gen */
+	M_MBP_7_1,	/* MacBook Pro, 7,1th gen */
+	M_MBP_8_2,	/* MacBook Pro, 8,2nd gen */
+	M_UNKNOWN	/* placeholder */
+};
+
+struct efifb_dmi_info {
+	char *optname;
+	unsigned long base;
+	int stride;
+	int width;
+	int height;
+	int flags;
+};
+
+#ifdef CONFIG_EFI
+
+extern struct efifb_dmi_info efifb_dmi_list[];
+void sysfb_apply_efi_quirks(void);
+
+#else /* CONFIG_EFI */
+
+static inline void sysfb_apply_efi_quirks(void)
+{
+}
+
+#endif /* CONFIG_EFI */
+
+#ifdef CONFIG_X86_SYSFB
+
+bool parse_mode(const struct screen_info *si,
+		struct simplefb_platform_data *mode);
+int create_simplefb(const struct screen_info *si,
+		    const struct simplefb_platform_data *mode);
+
+#else /* CONFIG_X86_SYSFB */
+
+static inline bool parse_mode(const struct screen_info *si,
+			      struct simplefb_platform_data *mode)
+{
+	return false;
+}
+
+static inline int create_simplefb(const struct screen_info *si,
+				  const struct simplefb_platform_data *mode)
+{
+	return -EINVAL;
+}
+
+#endif /* CONFIG_X86_SYSFB */
+
+#endif /* _ARCH_X86_KERNEL_SYSFB_H */
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index 095b215..d35f24e 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -124,9 +124,6 @@
 #define topology_core_id(cpu)			(cpu_data(cpu).cpu_core_id)
 #define topology_core_cpumask(cpu)		(per_cpu(cpu_core_map, cpu))
 #define topology_thread_cpumask(cpu)		(per_cpu(cpu_sibling_map, cpu))
-
-/* indicates that pointers to the topology cpumask_t maps are valid */
-#define arch_provides_topology_pointers		yes
 #endif
 
 static inline void arch_fix_phys_package_id(int num, u32 slot)
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 88eae2a..7036cb6 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -6,11 +6,7 @@
 #include <asm/debugreg.h>
 #include <asm/siginfo.h>			/* TRAP_TRACE, ... */
 
-#ifdef CONFIG_X86_32
-#define dotraplinkage
-#else
-#define dotraplinkage asmlinkage
-#endif
+#define dotraplinkage __visible
 
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index c91e8b9..235be70 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -49,6 +49,7 @@
 extern void mark_tsc_unstable(char *reason);
 extern int unsynchronized_tsc(void);
 extern int check_tsc_unstable(void);
+extern int check_tsc_disabled(void);
 extern unsigned long native_calibrate_tsc(void);
 
 extern int tsc_clocksource_reliable;
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 5ee2687..5838fa9 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -153,16 +153,19 @@
  * Careful: we have to cast the result to the type of the pointer
  * for sign reasons.
  *
- * The use of %edx as the register specifier is a bit of a
+ * The use of _ASM_DX as the register specifier is a bit of a
  * simplification, as gcc only cares about it as the starting point
  * and not size: for a 64-bit value it will use %ecx:%edx on 32 bits
  * (%ecx being the next register in gcc's x86 register sequence), and
  * %rdx on 64 bits.
+ *
+ * Clang/LLVM cares about the size of the register, but still wants
+ * the base register for something that ends up being a pair.
  */
 #define get_user(x, ptr)						\
 ({									\
 	int __ret_gu;							\
-	register __inttype(*(ptr)) __val_gu asm("%edx");		\
+	register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX);		\
 	__chk_user_ptr(ptr);						\
 	might_fault();							\
 	asm volatile("call __get_user_%P3"				\
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index f3e01a2..966502d 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -387,6 +387,7 @@
 #define VMX_EPT_EXTENT_INDIVIDUAL_ADDR		0
 #define VMX_EPT_EXTENT_CONTEXT			1
 #define VMX_EPT_EXTENT_GLOBAL			2
+#define VMX_EPT_EXTENT_SHIFT			24
 
 #define VMX_EPT_EXECUTE_ONLY_BIT		(1ull)
 #define VMX_EPT_PAGE_WALK_4_BIT			(1ull << 6)
@@ -394,6 +395,7 @@
 #define VMX_EPTP_WB_BIT				(1ull << 14)
 #define VMX_EPT_2MB_PAGE_BIT			(1ull << 16)
 #define VMX_EPT_1GB_PAGE_BIT			(1ull << 17)
+#define VMX_EPT_INVEPT_BIT			(1ull << 20)
 #define VMX_EPT_AD_BIT				    (1ull << 21)
 #define VMX_EPT_EXTENT_CONTEXT_BIT		(1ull << 25)
 #define VMX_EPT_EXTENT_GLOBAL_BIT		(1ull << 26)
diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h
index de656ac..d76ac40 100644
--- a/arch/x86/include/asm/vvar.h
+++ b/arch/x86/include/asm/vvar.h
@@ -35,7 +35,7 @@
 
 #define DEFINE_VVAR(type, name)						\
 	type name							\
-	__attribute__((section(".vvar_" #name), aligned(16)))
+	__attribute__((section(".vvar_" #name), aligned(16))) __visible
 
 #define VVAR(name) (*vvaraddr_ ## name)
 
diff --git a/arch/x86/include/asm/xen/events.h b/arch/x86/include/asm/xen/events.h
index ca842f2..608a79d 100644
--- a/arch/x86/include/asm/xen/events.h
+++ b/arch/x86/include/asm/xen/events.h
@@ -7,6 +7,7 @@
 	XEN_CALL_FUNCTION_SINGLE_VECTOR,
 	XEN_SPIN_UNLOCK_VECTOR,
 	XEN_IRQ_WORK_VECTOR,
+	XEN_NMI_VECTOR,
 
 	XEN_NR_IPIS,
 };
diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h
index 125f344..d866959 100644
--- a/arch/x86/include/asm/xen/hypervisor.h
+++ b/arch/x86/include/asm/xen/hypervisor.h
@@ -40,21 +40,7 @@
 
 static inline uint32_t xen_cpuid_base(void)
 {
-	uint32_t base, eax, ebx, ecx, edx;
-	char signature[13];
-
-	for (base = 0x40000000; base < 0x40010000; base += 0x100) {
-		cpuid(base, &eax, &ebx, &ecx, &edx);
-		*(uint32_t *)(signature + 0) = ebx;
-		*(uint32_t *)(signature + 4) = ecx;
-		*(uint32_t *)(signature + 8) = edx;
-		signature[12] = 0;
-
-		if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
-			return base;
-	}
-
-	return 0;
+	return hypervisor_cpuid_base("XenVMMXenVMM", 2);
 }
 
 #ifdef CONFIG_XEN
diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h
index 06fdbd9..94dc8ca 100644
--- a/arch/x86/include/uapi/asm/kvm_para.h
+++ b/arch/x86/include/uapi/asm/kvm_para.h
@@ -23,6 +23,7 @@
 #define KVM_FEATURE_ASYNC_PF		4
 #define KVM_FEATURE_STEAL_TIME		5
 #define KVM_FEATURE_PV_EOI		6
+#define KVM_FEATURE_PV_UNHALT		7
 
 /* The last 8 bits are used to indicate how to interpret the flags field
  * in pvclock structure. If no bits are set, all flags are ignored.
diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h
index d651082..0e79420 100644
--- a/arch/x86/include/uapi/asm/vmx.h
+++ b/arch/x86/include/uapi/asm/vmx.h
@@ -65,6 +65,7 @@
 #define EXIT_REASON_EOI_INDUCED         45
 #define EXIT_REASON_EPT_VIOLATION       48
 #define EXIT_REASON_EPT_MISCONFIG       49
+#define EXIT_REASON_INVEPT              50
 #define EXIT_REASON_PREEMPTION_TIMER    52
 #define EXIT_REASON_WBINVD              54
 #define EXIT_REASON_XSETBV              55
@@ -106,12 +107,13 @@
 	{ EXIT_REASON_APIC_ACCESS,           "APIC_ACCESS" }, \
 	{ EXIT_REASON_EPT_VIOLATION,         "EPT_VIOLATION" }, \
 	{ EXIT_REASON_EPT_MISCONFIG,         "EPT_MISCONFIG" }, \
+	{ EXIT_REASON_INVEPT,                "INVEPT" }, \
+	{ EXIT_REASON_PREEMPTION_TIMER,      "PREEMPTION_TIMER" }, \
 	{ EXIT_REASON_WBINVD,                "WBINVD" }, \
 	{ EXIT_REASON_APIC_WRITE,            "APIC_WRITE" }, \
 	{ EXIT_REASON_EOI_INDUCED,           "EOI_INDUCED" }, \
 	{ EXIT_REASON_INVALID_STATE,         "INVALID_STATE" }, \
 	{ EXIT_REASON_INVD,                  "INVD" }, \
-	{ EXIT_REASON_INVPCID,               "INVPCID" }, \
-	{ EXIT_REASON_PREEMPTION_TIMER,      "PREEMPTION_TIMER" }
+	{ EXIT_REASON_INVPCID,               "INVPCID" }
 
 #endif /* _UAPIVMX_H */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 88d99ea..a5408b9 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -103,6 +103,9 @@
 obj-$(CONFIG_SWIOTLB)			+= pci-swiotlb.o
 obj-$(CONFIG_OF)			+= devicetree.o
 obj-$(CONFIG_UPROBES)			+= uprobes.o
+obj-y					+= sysfb.o
+obj-$(CONFIG_X86_SYSFB)			+= sysfb_simplefb.o
+obj-$(CONFIG_EFI)			+= sysfb_efi.o
 
 obj-$(CONFIG_PERF_EVENTS)		+= perf_regs.o
 obj-$(CONFIG_TRACING)			+= tracepoint.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 2627a81..40c7660 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -67,6 +67,7 @@
 int acpi_lapic;
 int acpi_ioapic;
 int acpi_strict;
+int acpi_disable_cmcff;
 
 u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
@@ -141,16 +142,8 @@
 }
 
 /*
- * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
- * to map the target physical address. The problem is that set_fixmap()
- * provides a single page, and it is possible that the page is not
- * sufficient.
- * By using this area, we can map up to MAX_IO_APICS pages temporarily,
- * i.e. until the next __va_range() call.
- *
- * Important Safety Note:  The fixed I/O APIC page numbers are *subtracted*
- * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
- * count idx down while incrementing the phys address.
+ * This is just a simple wrapper around early_ioremap(),
+ * with sanity checks for phys == 0 and size == 0.
  */
 char *__init __acpi_map_table(unsigned long phys, unsigned long size)
 {
@@ -160,6 +153,7 @@
 
 	return early_ioremap(phys, size);
 }
+
 void __init __acpi_unmap_table(char *map, unsigned long size)
 {
 	if (!map || !size)
@@ -199,7 +193,7 @@
 {
 	unsigned int ver = 0;
 
-	if (id >= (MAX_LOCAL_APIC-1)) {
+	if (id >= MAX_LOCAL_APIC) {
 		printk(KERN_INFO PREFIX "skipped apicid that is too big\n");
 		return;
 	}
@@ -1120,6 +1114,7 @@
 	int ioapic;
 	int ioapic_pin;
 	struct io_apic_irq_attr irq_attr;
+	int ret;
 
 	if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
 		return gsi;
@@ -1149,7 +1144,9 @@
 	set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
 			     trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
 			     polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
-	io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr);
+	ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr);
+	if (ret < 0)
+		gsi = INT_MIN;
 
 	return gsi;
 }
@@ -1626,6 +1623,10 @@
 	/* "acpi=copy_dsdt" copys DSDT */
 	else if (strcmp(arg, "copy_dsdt") == 0) {
 		acpi_gbl_copy_dsdt_locally = 1;
+	}
+	/* "acpi=nocmcff" disables FF mode for corrected errors */
+	else if (strcmp(arg, "nocmcff") == 0) {
+		acpi_disable_cmcff = 1;
 	} else {
 		/* Core will printk when we return error. */
 		return -EINVAL;
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index c15cf9a..15e8563 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -11,6 +11,7 @@
 #include <linux/memory.h>
 #include <linux/stop_machine.h>
 #include <linux/slab.h>
+#include <linux/kdebug.h>
 #include <asm/alternative.h>
 #include <asm/sections.h>
 #include <asm/pgtable.h>
@@ -596,97 +597,93 @@
 	return addr;
 }
 
-/*
- * Cross-modifying kernel text with stop_machine().
- * This code originally comes from immediate value.
- */
-static atomic_t stop_machine_first;
-static int wrote_text;
-
-struct text_poke_params {
-	struct text_poke_param *params;
-	int nparams;
-};
-
-static int __kprobes stop_machine_text_poke(void *data)
+static void do_sync_core(void *info)
 {
-	struct text_poke_params *tpp = data;
-	struct text_poke_param *p;
-	int i;
-
-	if (atomic_xchg(&stop_machine_first, 0)) {
-		for (i = 0; i < tpp->nparams; i++) {
-			p = &tpp->params[i];
-			text_poke(p->addr, p->opcode, p->len);
-		}
-		smp_wmb();	/* Make sure other cpus see that this has run */
-		wrote_text = 1;
-	} else {
-		while (!wrote_text)
-			cpu_relax();
-		smp_mb();	/* Load wrote_text before following execution */
-	}
-
-	for (i = 0; i < tpp->nparams; i++) {
-		p = &tpp->params[i];
-		flush_icache_range((unsigned long)p->addr,
-				   (unsigned long)p->addr + p->len);
-	}
-	/*
-	 * Intel Archiecture Software Developer's Manual section 7.1.3 specifies
-	 * that a core serializing instruction such as "cpuid" should be
-	 * executed on _each_ core before the new instruction is made visible.
-	 */
 	sync_core();
-	return 0;
+}
+
+static bool bp_patching_in_progress;
+static void *bp_int3_handler, *bp_int3_addr;
+
+int poke_int3_handler(struct pt_regs *regs)
+{
+	/* bp_patching_in_progress */
+	smp_rmb();
+
+	if (likely(!bp_patching_in_progress))
+		return 0;
+
+	if (user_mode_vm(regs) || regs->ip != (unsigned long)bp_int3_addr)
+		return 0;
+
+	/* set up the specified breakpoint handler */
+	regs->ip = (unsigned long) bp_int3_handler;
+
+	return 1;
+
 }
 
 /**
- * text_poke_smp - Update instructions on a live kernel on SMP
- * @addr: address to modify
- * @opcode: source of the copy
- * @len: length to copy
+ * text_poke_bp() -- update instructions on live kernel on SMP
+ * @addr:	address to patch
+ * @opcode:	opcode of new instruction
+ * @len:	length to copy
+ * @handler:	address to jump to when the temporary breakpoint is hit
  *
- * Modify multi-byte instruction by using stop_machine() on SMP. This allows
- * user to poke/set multi-byte text on SMP. Only non-NMI/MCE code modifying
- * should be allowed, since stop_machine() does _not_ protect code against
- * NMI and MCE.
+ * Modify multi-byte instruction by using int3 breakpoint on SMP.
+ * We completely avoid stop_machine() here, and achieve the
+ * synchronization using int3 breakpoint.
  *
- * Note: Must be called under get_online_cpus() and text_mutex.
+ * The way it is done:
+ *	- add a int3 trap to the address that will be patched
+ *	- sync cores
+ *	- update all but the first byte of the patched range
+ *	- sync cores
+ *	- replace the first byte (int3) by the first byte of
+ *	  replacing opcode
+ *	- sync cores
+ *
+ * Note: must be called under text_mutex.
  */
-void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
+void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler)
 {
-	struct text_poke_params tpp;
-	struct text_poke_param p;
+	unsigned char int3 = 0xcc;
 
-	p.addr = addr;
-	p.opcode = opcode;
-	p.len = len;
-	tpp.params = &p;
-	tpp.nparams = 1;
-	atomic_set(&stop_machine_first, 1);
-	wrote_text = 0;
-	/* Use __stop_machine() because the caller already got online_cpus. */
-	__stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
+	bp_int3_handler = handler;
+	bp_int3_addr = (u8 *)addr + sizeof(int3);
+	bp_patching_in_progress = true;
+	/*
+	 * Corresponding read barrier in int3 notifier for
+	 * making sure the in_progress flags is correctly ordered wrt.
+	 * patching
+	 */
+	smp_wmb();
+
+	text_poke(addr, &int3, sizeof(int3));
+
+	on_each_cpu(do_sync_core, NULL, 1);
+
+	if (len - sizeof(int3) > 0) {
+		/* patch all but the first byte */
+		text_poke((char *)addr + sizeof(int3),
+			  (const char *) opcode + sizeof(int3),
+			  len - sizeof(int3));
+		/*
+		 * According to Intel, this core syncing is very likely
+		 * not necessary and we'd be safe even without it. But
+		 * better safe than sorry (plus there's not only Intel).
+		 */
+		on_each_cpu(do_sync_core, NULL, 1);
+	}
+
+	/* patch the first byte */
+	text_poke(addr, opcode, sizeof(int3));
+
+	on_each_cpu(do_sync_core, NULL, 1);
+
+	bp_patching_in_progress = false;
+	smp_wmb();
+
 	return addr;
 }
 
-/**
- * text_poke_smp_batch - Update instructions on a live kernel on SMP
- * @params: an array of text_poke parameters
- * @n: the number of elements in params.
- *
- * Modify multi-byte instruction by using stop_machine() on SMP. Since the
- * stop_machine() is heavy task, it is better to aggregate text_poke requests
- * and do it once if possible.
- *
- * Note: Must be called under get_online_cpus() and text_mutex.
- */
-void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
-{
-	struct text_poke_params tpp = {.params = params, .nparams = n};
-
-	atomic_set(&stop_machine_first, 1);
-	wrote_text = 0;
-	__stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
-}
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index 3048ded..59554dc 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -20,6 +20,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
 	{}
 };
@@ -27,6 +28,7 @@
 
 static const struct pci_device_id amd_nb_link_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
 	{}
 };
@@ -81,13 +83,20 @@
 			next_northbridge(misc, amd_nb_misc_ids);
 		node_to_amd_nb(i)->link = link =
 			next_northbridge(link, amd_nb_link_ids);
-        }
+	}
 
+	/* GART present only on Fam15h upto model 0fh */
 	if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
-	    boot_cpu_data.x86 == 0x15)
+	    (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model < 0x10))
 		amd_northbridges.flags |= AMD_NB_GART;
 
 	/*
+	 * Check for L3 cache presence.
+	 */
+	if (!cpuid_edx(0x80000006))
+		return 0;
+
+	/*
 	 * Some CPU families support L3 Cache Index Disable. There are some
 	 * limitations because of E382 and E388 on family 0x10.
 	 */
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index eca89c5..a7eb82d 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -913,7 +913,7 @@
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
  */
-void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
+__visible void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
@@ -932,7 +932,7 @@
 	set_irq_regs(old_regs);
 }
 
-void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
+__visible void __irq_entry smp_trace_apic_timer_interrupt(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
@@ -1946,14 +1946,14 @@
 		"should never happen.\n", smp_processor_id());
 }
 
-void smp_spurious_interrupt(struct pt_regs *regs)
+__visible void smp_spurious_interrupt(struct pt_regs *regs)
 {
 	entering_irq();
 	__smp_spurious_interrupt();
 	exiting_irq();
 }
 
-void smp_trace_spurious_interrupt(struct pt_regs *regs)
+__visible void smp_trace_spurious_interrupt(struct pt_regs *regs)
 {
 	entering_irq();
 	trace_spurious_apic_entry(SPURIOUS_APIC_VECTOR);
@@ -2002,14 +2002,14 @@
 
 }
 
-void smp_error_interrupt(struct pt_regs *regs)
+__visible void smp_error_interrupt(struct pt_regs *regs)
 {
 	entering_irq();
 	__smp_error_interrupt(regs);
 	exiting_irq();
 }
 
-void smp_trace_error_interrupt(struct pt_regs *regs)
+__visible void smp_trace_error_interrupt(struct pt_regs *regs)
 {
 	entering_irq();
 	trace_error_apic_entry(ERROR_APIC_VECTOR);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 9ed796c..e63a5bd 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1534,6 +1534,11 @@
 	}
 }
 
+void ioapic_zap_locks(void)
+{
+	raw_spin_lock_init(&ioapic_lock);
+}
+
 __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
 {
 	union IO_APIC_reg_00 reg_00;
@@ -3375,12 +3380,15 @@
 {
 	unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin;
 	int ret;
+	struct IO_APIC_route_entry orig_entry;
 
 	/* Avoid redundant programming */
 	if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) {
-		pr_debug("Pin %d-%d already programmed\n",
-			 mpc_ioapic_id(ioapic_idx), pin);
-		return 0;
+		pr_debug("Pin %d-%d already programmed\n", mpc_ioapic_id(ioapic_idx), pin);
+		orig_entry = ioapic_read_entry(attr->ioapic, pin);
+		if (attr->trigger == orig_entry.trigger && attr->polarity == orig_entry.polarity)
+			return 0;
+		return -EBUSY;
 	}
 	ret = io_apic_setup_irq_pin(irq, node, attr);
 	if (!ret)
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 53a4e27..3ab0343 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -392,7 +392,7 @@
 /*
  * Local variables
  */
-static struct {
+__visible struct {
 	unsigned long	offset;
 	unsigned short	segment;
 } apm_bios_entry;
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index f654ece..903a264 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -66,8 +66,8 @@
  *	performance at the same time..
  */
 
-extern void vide(void);
-__asm__(".align 4\nvide: ret");
+extern __visible void vide(void);
+__asm__(".globl vide\n\t.align 4\nvide: ret");
 
 static void init_amd_k5(struct cpuinfo_x86 *c)
 {
@@ -512,7 +512,7 @@
 
 static const int amd_erratum_383[];
 static const int amd_erratum_400[];
-static bool cpu_has_amd_erratum(const int *erratum);
+static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum);
 
 static void init_amd(struct cpuinfo_x86 *c)
 {
@@ -729,11 +729,11 @@
 		value &= ~(1ULL << 24);
 		wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
 
-		if (cpu_has_amd_erratum(amd_erratum_383))
+		if (cpu_has_amd_erratum(c, amd_erratum_383))
 			set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
 	}
 
-	if (cpu_has_amd_erratum(amd_erratum_400))
+	if (cpu_has_amd_erratum(c, amd_erratum_400))
 		set_cpu_bug(c, X86_BUG_AMD_APIC_C1E);
 
 	rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
@@ -878,23 +878,13 @@
 static const int amd_erratum_383[] =
 	AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
 
-static bool cpu_has_amd_erratum(const int *erratum)
+
+static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
 {
-	struct cpuinfo_x86 *cpu = __this_cpu_ptr(&cpu_info);
 	int osvw_id = *erratum++;
 	u32 range;
 	u32 ms;
 
-	/*
-	 * If called early enough that current_cpu_data hasn't been initialized
-	 * yet, fall back to boot_cpu_data.
-	 */
-	if (cpu->x86 == 0)
-		cpu = &boot_cpu_data;
-
-	if (cpu->x86_vendor != X86_VENDOR_AMD)
-		return false;
-
 	if (osvw_id >= 0 && osvw_id < 65536 &&
 	    cpu_has(cpu, X86_FEATURE_OSVW)) {
 		u64 osvw_len;
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 25eb274..2793d1f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1076,7 +1076,7 @@
 				    (unsigned long) debug_idt_table };
 
 DEFINE_PER_CPU_FIRST(union irq_stack_union,
-		     irq_stack_union) __aligned(PAGE_SIZE);
+		     irq_stack_union) __aligned(PAGE_SIZE) __visible;
 
 /*
  * The following four percpu variables are hot.  Align current_task to
@@ -1093,7 +1093,7 @@
 DEFINE_PER_CPU(char *, irq_stack_ptr) =
 	init_per_cpu_var(irq_stack_union.irq_stack) + IRQ_STACK_SIZE - 64;
 
-DEFINE_PER_CPU(unsigned int, irq_count) = -1;
+DEFINE_PER_CPU(unsigned int, irq_count) __visible = -1;
 
 DEFINE_PER_CPU(struct task_struct *, fpu_owner_task);
 
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index 8727921..36ce402 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -25,11 +25,6 @@
 #include <asm/processor.h>
 #include <asm/hypervisor.h>
 
-/*
- * Hypervisor detect order.  This is specified explicitly here because
- * some hypervisors might implement compatibility modes for other
- * hypervisors and therefore need to be detected in specific sequence.
- */
 static const __initconst struct hypervisor_x86 * const hypervisors[] =
 {
 #ifdef CONFIG_XEN_PVHVM
@@ -49,15 +44,19 @@
 detect_hypervisor_vendor(void)
 {
 	const struct hypervisor_x86 *h, * const *p;
+	uint32_t pri, max_pri = 0;
 
 	for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
 		h = *p;
-		if (h->detect()) {
+		pri = h->detect();
+		if (pri != 0 && pri > max_pri) {
+			max_pri = pri;
 			x86_hyper = h;
-			printk(KERN_INFO "Hypervisor detected: %s\n", h->name);
-			break;
 		}
 	}
+
+	if (max_pri)
+		printk(KERN_INFO "Hypervisor detected: %s\n", x86_hyper->name);
 }
 
 void init_hypervisor(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
index 5b7d4fa..09edd0b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -25,15 +25,18 @@
 struct dentry *mce_get_debugfs_dir(void);
 
 extern struct mce_bank *mce_banks;
+extern mce_banks_t mce_banks_ce_disabled;
 
 #ifdef CONFIG_X86_MCE_INTEL
 unsigned long mce_intel_adjust_timer(unsigned long interval);
 void mce_intel_cmci_poll(void);
 void mce_intel_hcpu_update(unsigned long cpu);
+void cmci_disable_bank(int bank);
 #else
 # define mce_intel_adjust_timer mce_adjust_timer_default
 static inline void mce_intel_cmci_poll(void) { }
 static inline void mce_intel_hcpu_update(unsigned long cpu) { }
+static inline void cmci_disable_bank(int bank) { }
 #endif
 
 void mce_timer_kick(unsigned long interval);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 87a65c9..b3218cd 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -97,6 +97,15 @@
 	[0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
 };
 
+/*
+ * MCA banks controlled through firmware first for corrected errors.
+ * This is a global list of banks for which we won't enable CMCI and we
+ * won't poll. Firmware controls these banks and is responsible for
+ * reporting corrected errors through GHES. Uncorrected/recoverable
+ * errors are still notified through a machine check.
+ */
+mce_banks_t mce_banks_ce_disabled;
+
 static DEFINE_PER_CPU(struct work_struct, mce_work);
 
 static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
@@ -1935,6 +1944,25 @@
 	&mce_chrdev_ops,
 };
 
+static void __mce_disable_bank(void *arg)
+{
+	int bank = *((int *)arg);
+	__clear_bit(bank, __get_cpu_var(mce_poll_banks));
+	cmci_disable_bank(bank);
+}
+
+void mce_disable_bank(int bank)
+{
+	if (bank >= mca_cfg.banks) {
+		pr_warn(FW_BUG
+			"Ignoring request to disable invalid MCA bank %d.\n",
+			bank);
+		return;
+	}
+	set_bit(bank, mce_banks_ce_disabled);
+	on_each_cpu(__mce_disable_bank, &bank, 1);
+}
+
 /*
  * mce=off Disables machine check
  * mce=no_cmci Disables CMCI
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index d5640530..4cfe045 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -203,6 +203,10 @@
 		if (test_bit(i, owned))
 			continue;
 
+		/* Skip banks in firmware first mode */
+		if (test_bit(i, mce_banks_ce_disabled))
+			continue;
+
 		rdmsrl(MSR_IA32_MCx_CTL2(i), val);
 
 		/* Already owned by someone else? */
@@ -271,6 +275,19 @@
 	local_irq_restore(flags);
 }
 
+/* Caller must hold the lock on cmci_discover_lock */
+static void __cmci_disable_bank(int bank)
+{
+	u64 val;
+
+	if (!test_bit(bank, __get_cpu_var(mce_banks_owned)))
+		return;
+	rdmsrl(MSR_IA32_MCx_CTL2(bank), val);
+	val &= ~MCI_CTL2_CMCI_EN;
+	wrmsrl(MSR_IA32_MCx_CTL2(bank), val);
+	__clear_bit(bank, __get_cpu_var(mce_banks_owned));
+}
+
 /*
  * Disable CMCI on this CPU for all banks it owns when it goes down.
  * This allows other CPUs to claim the banks on rediscovery.
@@ -280,20 +297,12 @@
 	unsigned long flags;
 	int i;
 	int banks;
-	u64 val;
 
 	if (!cmci_supported(&banks))
 		return;
 	raw_spin_lock_irqsave(&cmci_discover_lock, flags);
-	for (i = 0; i < banks; i++) {
-		if (!test_bit(i, __get_cpu_var(mce_banks_owned)))
-			continue;
-		/* Disable CMCI */
-		rdmsrl(MSR_IA32_MCx_CTL2(i), val);
-		val &= ~MCI_CTL2_CMCI_EN;
-		wrmsrl(MSR_IA32_MCx_CTL2(i), val);
-		__clear_bit(i, __get_cpu_var(mce_banks_owned));
-	}
+	for (i = 0; i < banks; i++)
+		__cmci_disable_bank(i);
 	raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
 }
 
@@ -327,6 +336,19 @@
 		cmci_discover(banks);
 }
 
+void cmci_disable_bank(int bank)
+{
+	int banks;
+	unsigned long flags;
+
+	if (!cmci_supported(&banks))
+		return;
+
+	raw_spin_lock_irqsave(&cmci_discover_lock, flags);
+	__cmci_disable_bank(bank);
+	raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
+}
+
 static void intel_init_cmci(void)
 {
 	int banks;
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 8f4be53..71a39f3 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -27,20 +27,23 @@
 struct ms_hyperv_info ms_hyperv;
 EXPORT_SYMBOL_GPL(ms_hyperv);
 
-static bool __init ms_hyperv_platform(void)
+static uint32_t  __init ms_hyperv_platform(void)
 {
 	u32 eax;
 	u32 hyp_signature[3];
 
 	if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
-		return false;
+		return 0;
 
 	cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
 	      &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
 
-	return eax >= HYPERV_CPUID_MIN &&
-		eax <= HYPERV_CPUID_MAX &&
-		!memcmp("Microsoft Hv", hyp_signature, 12);
+	if (eax >= HYPERV_CPUID_MIN &&
+	    eax <= HYPERV_CPUID_MAX &&
+	    !memcmp("Microsoft Hv", hyp_signature, 12))
+		return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
+
+	return 0;
 }
 
 static cycle_t read_hv_clock(struct clocksource *arg)
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index a7c7305..8355c84 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1884,6 +1884,7 @@
 void arch_perf_update_userpage(struct perf_event_mmap_page *userpg, u64 now)
 {
 	userpg->cap_usr_time = 0;
+	userpg->cap_usr_time_zero = 0;
 	userpg->cap_usr_rdpmc = x86_pmu.attr_rdpmc;
 	userpg->pmc_width = x86_pmu.cntval_bits;
 
@@ -1897,6 +1898,11 @@
 	userpg->time_mult = this_cpu_read(cyc2ns);
 	userpg->time_shift = CYC2NS_SCALE_FACTOR;
 	userpg->time_offset = this_cpu_read(cyc2ns_offset) - now;
+
+	if (sched_clock_stable && !check_tsc_disabled()) {
+		userpg->cap_usr_time_zero = 1;
+		userpg->time_zero = this_cpu_read(cyc2ns_offset);
+	}
 }
 
 /*
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 97e557b..cc16faa 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -641,6 +641,8 @@
 
 extern struct event_constraint intel_atom_pebs_event_constraints[];
 
+extern struct event_constraint intel_slm_pebs_event_constraints[];
+
 extern struct event_constraint intel_nehalem_pebs_event_constraints[];
 
 extern struct event_constraint intel_westmere_pebs_event_constraints[];
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index 4cbe032..beeb7cc 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -347,8 +347,7 @@
 	struct amd_nb *nb;
 	int i;
 
-	nb = kmalloc_node(sizeof(struct amd_nb), GFP_KERNEL | __GFP_ZERO,
-			  cpu_to_node(cpu));
+	nb = kzalloc_node(sizeof(struct amd_nb), GFP_KERNEL, cpu_to_node(cpu));
 	if (!nb)
 		return NULL;
 
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index a45d8d4..0abf674 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -81,7 +81,8 @@
 
 static struct extra_reg intel_nehalem_extra_regs[] __read_mostly =
 {
-	INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
 	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b),
 	EVENT_EXTRA_END
 };
@@ -143,8 +144,9 @@
 
 static struct extra_reg intel_westmere_extra_regs[] __read_mostly =
 {
-	INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
-	INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff, RSP_1),
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0xffff, RSP_1),
 	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b),
 	EVENT_EXTRA_END
 };
@@ -162,16 +164,27 @@
 	EVENT_CONSTRAINT_END
 };
 
+static struct event_constraint intel_slm_event_constraints[] __read_mostly =
+{
+	FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
+	FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
+	FIXED_EVENT_CONSTRAINT(0x013c, 2), /* CPU_CLK_UNHALTED.REF */
+	FIXED_EVENT_CONSTRAINT(0x0300, 2), /* pseudo CPU_CLK_UNHALTED.REF */
+	EVENT_CONSTRAINT_END
+};
+
 static struct extra_reg intel_snb_extra_regs[] __read_mostly = {
-	INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
-	INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3f807f8fffull, RSP_1),
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0x3f807f8fffull, RSP_1),
 	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
 	EVENT_EXTRA_END
 };
 
 static struct extra_reg intel_snbep_extra_regs[] __read_mostly = {
-	INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0),
-	INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1),
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x01bb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1),
 	INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
 	EVENT_EXTRA_END
 };
@@ -882,6 +895,140 @@
  },
 };
 
+static struct extra_reg intel_slm_extra_regs[] __read_mostly =
+{
+	/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
+	INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x768005ffff, RSP_0),
+	INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0x768005ffff, RSP_1),
+	EVENT_EXTRA_END
+};
+
+#define SLM_DMND_READ		SNB_DMND_DATA_RD
+#define SLM_DMND_WRITE		SNB_DMND_RFO
+#define SLM_DMND_PREFETCH	(SNB_PF_DATA_RD|SNB_PF_RFO)
+
+#define SLM_SNP_ANY		(SNB_SNP_NONE|SNB_SNP_MISS|SNB_NO_FWD|SNB_HITM)
+#define SLM_LLC_ACCESS		SNB_RESP_ANY
+#define SLM_LLC_MISS		(SLM_SNP_ANY|SNB_NON_DRAM)
+
+static __initconst const u64 slm_hw_cache_extra_regs
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = SLM_DMND_READ|SLM_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = SLM_DMND_READ|SLM_LLC_MISS,
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = SLM_DMND_WRITE|SLM_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = SLM_DMND_WRITE|SLM_LLC_MISS,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = SLM_DMND_PREFETCH|SLM_LLC_ACCESS,
+		[ C(RESULT_MISS)   ] = SLM_DMND_PREFETCH|SLM_LLC_MISS,
+	},
+ },
+};
+
+static __initconst const u64 slm_hw_cache_event_ids
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [ C(L1D) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x0104, /* LD_DCU_MISS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(L1I ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x0380, /* ICACHE.ACCESSES */
+		[ C(RESULT_MISS)   ] = 0x0280, /* ICACGE.MISSES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(LL  ) ] = {
+	[ C(OP_READ) ] = {
+		/* OFFCORE_RESPONSE.ANY_DATA.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_DATA.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_WRITE) ] = {
+		/* OFFCORE_RESPONSE.ANY_RFO.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.ANY_RFO.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+	[ C(OP_PREFETCH) ] = {
+		/* OFFCORE_RESPONSE.PREFETCH.LOCAL_CACHE */
+		[ C(RESULT_ACCESS) ] = 0x01b7,
+		/* OFFCORE_RESPONSE.PREFETCH.ANY_LLC_MISS */
+		[ C(RESULT_MISS)   ] = 0x01b7,
+	},
+ },
+ [ C(DTLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0x0804, /* LD_DTLB_MISS */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = 0,
+		[ C(RESULT_MISS)   ] = 0,
+	},
+ },
+ [ C(ITLB) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c0, /* INST_RETIRED.ANY_P */
+		[ C(RESULT_MISS)   ] = 0x0282, /* ITLB.MISSES */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+ [ C(BPU ) ] = {
+	[ C(OP_READ) ] = {
+		[ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ANY */
+		[ C(RESULT_MISS)   ] = 0x00c5, /* BP_INST_RETIRED.MISPRED */
+	},
+	[ C(OP_WRITE) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+	[ C(OP_PREFETCH) ] = {
+		[ C(RESULT_ACCESS) ] = -1,
+		[ C(RESULT_MISS)   ] = -1,
+	},
+ },
+};
+
 static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event)
 {
 	/* user explicitly requested branch sampling */
@@ -1301,11 +1448,11 @@
 
 	if (idx == EXTRA_REG_RSP_0) {
 		event->hw.config &= ~INTEL_ARCH_EVENT_MASK;
-		event->hw.config |= 0x01b7;
+		event->hw.config |= x86_pmu.extra_regs[EXTRA_REG_RSP_0].event;
 		event->hw.extra_reg.reg = MSR_OFFCORE_RSP_0;
 	} else if (idx == EXTRA_REG_RSP_1) {
 		event->hw.config &= ~INTEL_ARCH_EVENT_MASK;
-		event->hw.config |= 0x01bb;
+		event->hw.config |= x86_pmu.extra_regs[EXTRA_REG_RSP_1].event;
 		event->hw.extra_reg.reg = MSR_OFFCORE_RSP_1;
 	}
 }
@@ -2176,6 +2323,21 @@
 		pr_cont("Atom events, ");
 		break;
 
+	case 55: /* Atom 22nm "Silvermont" */
+		memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
+			sizeof(hw_cache_event_ids));
+		memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
+		       sizeof(hw_cache_extra_regs));
+
+		intel_pmu_lbr_init_atom();
+
+		x86_pmu.event_constraints = intel_slm_event_constraints;
+		x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
+		x86_pmu.extra_regs = intel_slm_extra_regs;
+		x86_pmu.er_flags |= ERF_HAS_RSP_1;
+		pr_cont("Silvermont events, ");
+		break;
+
 	case 37: /* 32 nm nehalem, "Clarkdale" */
 	case 44: /* 32 nm nehalem, "Gulftown" */
 	case 47: /* 32 nm Xeon E7 */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 3065c57..63438aa 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -224,7 +224,7 @@
 	if (!x86_pmu.pebs)
 		return 0;
 
-	buffer = kmalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+	buffer = kzalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL, node);
 	if (unlikely(!buffer))
 		return -ENOMEM;
 
@@ -262,7 +262,7 @@
 	if (!x86_pmu.bts)
 		return 0;
 
-	buffer = kmalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+	buffer = kzalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL, node);
 	if (unlikely(!buffer))
 		return -ENOMEM;
 
@@ -295,7 +295,7 @@
 	int node = cpu_to_node(cpu);
 	struct debug_store *ds;
 
-	ds = kmalloc_node(sizeof(*ds), GFP_KERNEL | __GFP_ZERO, node);
+	ds = kzalloc_node(sizeof(*ds), GFP_KERNEL, node);
 	if (unlikely(!ds))
 		return -ENOMEM;
 
@@ -517,6 +517,32 @@
 	EVENT_CONSTRAINT_END
 };
 
+struct event_constraint intel_slm_pebs_event_constraints[] = {
+	INTEL_UEVENT_CONSTRAINT(0x0103, 0x1), /* REHABQ.LD_BLOCK_ST_FORWARD_PS */
+	INTEL_UEVENT_CONSTRAINT(0x0803, 0x1), /* REHABQ.LD_SPLITS_PS */
+	INTEL_UEVENT_CONSTRAINT(0x0204, 0x1), /* MEM_UOPS_RETIRED.L2_HIT_LOADS_PS */
+	INTEL_UEVENT_CONSTRAINT(0x0404, 0x1), /* MEM_UOPS_RETIRED.L2_MISS_LOADS_PS */
+	INTEL_UEVENT_CONSTRAINT(0x0804, 0x1), /* MEM_UOPS_RETIRED.DTLB_MISS_LOADS_PS */
+	INTEL_UEVENT_CONSTRAINT(0x2004, 0x1), /* MEM_UOPS_RETIRED.HITM_PS */
+	INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY_PS */
+	INTEL_UEVENT_CONSTRAINT(0x00c4, 0x1), /* BR_INST_RETIRED.ALL_BRANCHES_PS */
+	INTEL_UEVENT_CONSTRAINT(0x7ec4, 0x1), /* BR_INST_RETIRED.JCC_PS */
+	INTEL_UEVENT_CONSTRAINT(0xbfc4, 0x1), /* BR_INST_RETIRED.FAR_BRANCH_PS */
+	INTEL_UEVENT_CONSTRAINT(0xebc4, 0x1), /* BR_INST_RETIRED.NON_RETURN_IND_PS */
+	INTEL_UEVENT_CONSTRAINT(0xf7c4, 0x1), /* BR_INST_RETIRED.RETURN_PS */
+	INTEL_UEVENT_CONSTRAINT(0xf9c4, 0x1), /* BR_INST_RETIRED.CALL_PS */
+	INTEL_UEVENT_CONSTRAINT(0xfbc4, 0x1), /* BR_INST_RETIRED.IND_CALL_PS */
+	INTEL_UEVENT_CONSTRAINT(0xfdc4, 0x1), /* BR_INST_RETIRED.REL_CALL_PS */
+	INTEL_UEVENT_CONSTRAINT(0xfec4, 0x1), /* BR_INST_RETIRED.TAKEN_JCC_PS */
+	INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_MISP_RETIRED.ALL_BRANCHES_PS */
+	INTEL_UEVENT_CONSTRAINT(0x7ec5, 0x1), /* BR_INST_MISP_RETIRED.JCC_PS */
+	INTEL_UEVENT_CONSTRAINT(0xebc5, 0x1), /* BR_INST_MISP_RETIRED.NON_RETURN_IND_PS */
+	INTEL_UEVENT_CONSTRAINT(0xf7c5, 0x1), /* BR_INST_MISP_RETIRED.RETURN_PS */
+	INTEL_UEVENT_CONSTRAINT(0xfbc5, 0x1), /* BR_INST_MISP_RETIRED.IND_CALL_PS */
+	INTEL_UEVENT_CONSTRAINT(0xfec5, 0x1), /* BR_INST_MISP_RETIRED.TAKEN_JCC_PS */
+	EVENT_CONSTRAINT_END
+};
+
 struct event_constraint intel_nehalem_pebs_event_constraints[] = {
 	INTEL_PLD_CONSTRAINT(0x100b, 0xf),      /* MEM_INST_RETIRED.* */
 	INTEL_EVENT_CONSTRAINT(0x0f, 0xf),    /* MEM_UNCORE_RETIRED.* */
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 1fb6c72..fd8011e 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -6,6 +6,8 @@
 /* pci bus to socket mapping */
 static int pcibus_to_physid[256] = { [0 ... 255] = -1, };
 
+static struct pci_dev *extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX];
+
 static DEFINE_RAW_SPINLOCK(uncore_box_lock);
 
 /* mask of cpus that collect uncore events */
@@ -45,6 +47,24 @@
 DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
 DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
 DEFINE_UNCORE_FORMAT_ATTR(filter_band3, filter_band3, "config1:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(match_rds, match_rds, "config1:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid30, match_rnid30, "config1:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(match_rnid4, match_rnid4, "config1:31");
+DEFINE_UNCORE_FORMAT_ATTR(match_dnid, match_dnid, "config1:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(match_mc, match_mc, "config1:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(match_opc, match_opc, "config1:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(match_vnw, match_vnw, "config1:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(match0, match0, "config1:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(match1, match1, "config1:32-63");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rds, mask_rds, "config2:48-51");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid30, mask_rnid30, "config2:32-35");
+DEFINE_UNCORE_FORMAT_ATTR(mask_rnid4, mask_rnid4, "config2:31");
+DEFINE_UNCORE_FORMAT_ATTR(mask_dnid, mask_dnid, "config2:13-17");
+DEFINE_UNCORE_FORMAT_ATTR(mask_mc, mask_mc, "config2:9-12");
+DEFINE_UNCORE_FORMAT_ATTR(mask_opc, mask_opc, "config2:5-8");
+DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
+DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
+DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
 
 static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
 {
@@ -281,7 +301,7 @@
 };
 
 static struct attribute *snbep_uncore_pcu_formats_attr[] = {
-	&format_attr_event.attr,
+	&format_attr_event_ext.attr,
 	&format_attr_occ_sel.attr,
 	&format_attr_edge.attr,
 	&format_attr_inv.attr,
@@ -301,6 +321,24 @@
 	&format_attr_edge.attr,
 	&format_attr_inv.attr,
 	&format_attr_thresh8.attr,
+	&format_attr_match_rds.attr,
+	&format_attr_match_rnid30.attr,
+	&format_attr_match_rnid4.attr,
+	&format_attr_match_dnid.attr,
+	&format_attr_match_mc.attr,
+	&format_attr_match_opc.attr,
+	&format_attr_match_vnw.attr,
+	&format_attr_match0.attr,
+	&format_attr_match1.attr,
+	&format_attr_mask_rds.attr,
+	&format_attr_mask_rnid30.attr,
+	&format_attr_mask_rnid4.attr,
+	&format_attr_mask_dnid.attr,
+	&format_attr_mask_mc.attr,
+	&format_attr_mask_opc.attr,
+	&format_attr_mask_vnw.attr,
+	&format_attr_mask0.attr,
+	&format_attr_mask1.attr,
 	NULL,
 };
 
@@ -356,13 +394,16 @@
 	SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
 };
 
+#define SNBEP_UNCORE_PCI_OPS_COMMON_INIT()			\
+	.init_box	= snbep_uncore_pci_init_box,		\
+	.disable_box	= snbep_uncore_pci_disable_box,		\
+	.enable_box	= snbep_uncore_pci_enable_box,		\
+	.disable_event	= snbep_uncore_pci_disable_event,	\
+	.read_counter	= snbep_uncore_pci_read_counter
+
 static struct intel_uncore_ops snbep_uncore_pci_ops = {
-	.init_box	= snbep_uncore_pci_init_box,
-	.disable_box	= snbep_uncore_pci_disable_box,
-	.enable_box	= snbep_uncore_pci_enable_box,
-	.disable_event	= snbep_uncore_pci_disable_event,
-	.enable_event	= snbep_uncore_pci_enable_event,
-	.read_counter	= snbep_uncore_pci_read_counter,
+	SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+	.enable_event	= snbep_uncore_pci_enable_event,	\
 };
 
 static struct event_constraint snbep_uncore_cbox_constraints[] = {
@@ -726,6 +767,61 @@
 	NULL,
 };
 
+enum {
+	SNBEP_PCI_QPI_PORT0_FILTER,
+	SNBEP_PCI_QPI_PORT1_FILTER,
+};
+
+static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	if ((hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK) == 0x38) {
+		reg1->idx = 0;
+		reg1->reg = SNBEP_Q_Py_PCI_PMON_PKT_MATCH0;
+		reg1->config = event->attr.config1;
+		reg2->reg = SNBEP_Q_Py_PCI_PMON_PKT_MASK0;
+		reg2->config = event->attr.config2;
+	}
+	return 0;
+}
+
+static void snbep_qpi_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+	struct pci_dev *pdev = box->pci_dev;
+	struct hw_perf_event *hwc = &event->hw;
+	struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+	struct hw_perf_event_extra *reg2 = &hwc->branch_reg;
+
+	if (reg1->idx != EXTRA_REG_NONE) {
+		int idx = box->pmu->pmu_idx + SNBEP_PCI_QPI_PORT0_FILTER;
+		struct pci_dev *filter_pdev = extra_pci_dev[box->phys_id][idx];
+		WARN_ON_ONCE(!filter_pdev);
+		if (filter_pdev) {
+			pci_write_config_dword(filter_pdev, reg1->reg,
+						(u32)reg1->config);
+			pci_write_config_dword(filter_pdev, reg1->reg + 4,
+						(u32)(reg1->config >> 32));
+			pci_write_config_dword(filter_pdev, reg2->reg,
+						(u32)reg2->config);
+			pci_write_config_dword(filter_pdev, reg2->reg + 4,
+						(u32)(reg2->config >> 32));
+		}
+	}
+
+	pci_write_config_dword(pdev, hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops snbep_uncore_qpi_ops = {
+	SNBEP_UNCORE_PCI_OPS_COMMON_INIT(),
+	.enable_event		= snbep_qpi_enable_event,
+	.hw_config		= snbep_qpi_hw_config,
+	.get_constraint		= uncore_get_constraint,
+	.put_constraint		= uncore_put_constraint,
+};
+
 #define SNBEP_UNCORE_PCI_COMMON_INIT()				\
 	.perf_ctr	= SNBEP_PCI_PMON_CTR0,			\
 	.event_ctl	= SNBEP_PCI_PMON_CTL0,			\
@@ -755,17 +851,18 @@
 };
 
 static struct intel_uncore_type snbep_uncore_qpi = {
-	.name		= "qpi",
-	.num_counters   = 4,
-	.num_boxes	= 2,
-	.perf_ctr_bits	= 48,
-	.perf_ctr	= SNBEP_PCI_PMON_CTR0,
-	.event_ctl	= SNBEP_PCI_PMON_CTL0,
-	.event_mask	= SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
-	.box_ctl	= SNBEP_PCI_PMON_BOX_CTL,
-	.ops		= &snbep_uncore_pci_ops,
-	.event_descs	= snbep_uncore_qpi_events,
-	.format_group	= &snbep_uncore_qpi_format_group,
+	.name			= "qpi",
+	.num_counters		= 4,
+	.num_boxes		= 2,
+	.perf_ctr_bits		= 48,
+	.perf_ctr		= SNBEP_PCI_PMON_CTR0,
+	.event_ctl		= SNBEP_PCI_PMON_CTL0,
+	.event_mask		= SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+	.box_ctl		= SNBEP_PCI_PMON_BOX_CTL,
+	.num_shared_regs	= 1,
+	.ops			= &snbep_uncore_qpi_ops,
+	.event_descs		= snbep_uncore_qpi_events,
+	.format_group		= &snbep_uncore_qpi_format_group,
 };
 
 
@@ -807,43 +904,53 @@
 static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = {
 	{ /* Home Agent */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
-		.driver_data = SNBEP_PCI_UNCORE_HA,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_HA, 0),
 	},
 	{ /* MC Channel 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
-		.driver_data = SNBEP_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 0),
 	},
 	{ /* MC Channel 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
-		.driver_data = SNBEP_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 1),
 	},
 	{ /* MC Channel 2 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
-		.driver_data = SNBEP_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 2),
 	},
 	{ /* MC Channel 3 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
-		.driver_data = SNBEP_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_IMC, 3),
 	},
 	{ /* QPI Port 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
-		.driver_data = SNBEP_PCI_UNCORE_QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 0),
 	},
 	{ /* QPI Port 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
-		.driver_data = SNBEP_PCI_UNCORE_QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_QPI, 1),
 	},
 	{ /* R2PCIe */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
-		.driver_data = SNBEP_PCI_UNCORE_R2PCIE,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R2PCIE, 0),
 	},
 	{ /* R3QPI Link 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
-		.driver_data = SNBEP_PCI_UNCORE_R3QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 0),
 	},
 	{ /* R3QPI Link 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
-		.driver_data = SNBEP_PCI_UNCORE_R3QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(SNBEP_PCI_UNCORE_R3QPI, 1),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c86),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT0_FILTER),
+	},
+	{ /* QPI Port 0 filter  */
+		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3c96),
+		.driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+						   SNBEP_PCI_QPI_PORT1_FILTER),
 	},
 	{ /* end: all zeroes */ }
 };
@@ -1256,71 +1363,71 @@
 static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = {
 	{ /* Home Agent 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
-		.driver_data = IVT_PCI_UNCORE_HA,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 0),
 	},
 	{ /* Home Agent 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
-		.driver_data = IVT_PCI_UNCORE_HA,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_HA, 1),
 	},
 	{ /* MC0 Channel 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 0),
 	},
 	{ /* MC0 Channel 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 1),
 	},
 	{ /* MC0 Channel 3 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 2),
 	},
 	{ /* MC0 Channel 4 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 3),
 	},
 	{ /* MC1 Channel 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 4),
 	},
 	{ /* MC1 Channel 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 5),
 	},
 	{ /* MC1 Channel 3 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 6),
 	},
 	{ /* MC1 Channel 4 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
-		.driver_data = IVT_PCI_UNCORE_IMC,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_IMC, 7),
 	},
 	{ /* QPI0 Port 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
-		.driver_data = IVT_PCI_UNCORE_QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 0),
 	},
 	{ /* QPI0 Port 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
-		.driver_data = IVT_PCI_UNCORE_QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 1),
 	},
 	{ /* QPI1 Port 2 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
-		.driver_data = IVT_PCI_UNCORE_QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_QPI, 2),
 	},
 	{ /* R2PCIe */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
-		.driver_data = IVT_PCI_UNCORE_R2PCIE,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R2PCIE, 0),
 	},
 	{ /* R3QPI0 Link 0 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
-		.driver_data = IVT_PCI_UNCORE_R3QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 0),
 	},
 	{ /* R3QPI0 Link 1 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
-		.driver_data = IVT_PCI_UNCORE_R3QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 1),
 	},
 	{ /* R3QPI1 Link 2 */
 		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
-		.driver_data = IVT_PCI_UNCORE_R3QPI,
+		.driver_data = UNCORE_PCI_DEV_DATA(IVT_PCI_UNCORE_R3QPI, 2),
 	},
 	{ /* end: all zeroes */ }
 };
@@ -2606,7 +2713,7 @@
 
 	size = sizeof(*box) + type->num_shared_regs * sizeof(struct intel_uncore_extra_reg);
 
-	box = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO, cpu_to_node(cpu));
+	box = kzalloc_node(size, GFP_KERNEL, cpu_to_node(cpu));
 	if (!box)
 		return NULL;
 
@@ -3167,16 +3274,24 @@
 /*
  * add a pci uncore device
  */
-static int uncore_pci_add(struct intel_uncore_type *type, struct pci_dev *pdev)
+static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct intel_uncore_pmu *pmu;
 	struct intel_uncore_box *box;
-	int i, phys_id;
+	struct intel_uncore_type *type;
+	int phys_id;
 
 	phys_id = pcibus_to_physid[pdev->bus->number];
 	if (phys_id < 0)
 		return -ENODEV;
 
+	if (UNCORE_PCI_DEV_TYPE(id->driver_data) == UNCORE_EXTRA_PCI_DEV) {
+		extra_pci_dev[phys_id][UNCORE_PCI_DEV_IDX(id->driver_data)] = pdev;
+		pci_set_drvdata(pdev, NULL);
+		return 0;
+	}
+
+	type = pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)];
 	box = uncore_alloc_box(type, 0);
 	if (!box)
 		return -ENOMEM;
@@ -3185,21 +3300,11 @@
 	 * for performance monitoring unit with multiple boxes,
 	 * each box has a different function id.
 	 */
-	for (i = 0; i < type->num_boxes; i++) {
-		pmu = &type->pmus[i];
-		if (pmu->func_id == pdev->devfn)
-			break;
-		if (pmu->func_id < 0) {
-			pmu->func_id = pdev->devfn;
-			break;
-		}
-		pmu = NULL;
-	}
-
-	if (!pmu) {
-		kfree(box);
-		return -EINVAL;
-	}
+	pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
+	if (pmu->func_id < 0)
+		pmu->func_id = pdev->devfn;
+	else
+		WARN_ON_ONCE(pmu->func_id != pdev->devfn);
 
 	box->phys_id = phys_id;
 	box->pci_dev = pdev;
@@ -3217,9 +3322,22 @@
 static void uncore_pci_remove(struct pci_dev *pdev)
 {
 	struct intel_uncore_box *box = pci_get_drvdata(pdev);
-	struct intel_uncore_pmu *pmu = box->pmu;
-	int cpu, phys_id = pcibus_to_physid[pdev->bus->number];
+	struct intel_uncore_pmu *pmu;
+	int i, cpu, phys_id = pcibus_to_physid[pdev->bus->number];
 
+	box = pci_get_drvdata(pdev);
+	if (!box) {
+		for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) {
+			if (extra_pci_dev[phys_id][i] == pdev) {
+				extra_pci_dev[phys_id][i] = NULL;
+				break;
+			}
+		}
+		WARN_ON_ONCE(i >= UNCORE_EXTRA_PCI_DEV_MAX);
+		return;
+	}
+
+	pmu = box->pmu;
 	if (WARN_ON_ONCE(phys_id != box->phys_id))
 		return;
 
@@ -3240,12 +3358,6 @@
 	kfree(box);
 }
 
-static int uncore_pci_probe(struct pci_dev *pdev,
-			    const struct pci_device_id *id)
-{
-	return uncore_pci_add(pci_uncores[id->driver_data], pdev);
-}
-
 static int __init uncore_pci_init(void)
 {
 	int ret;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index 47b3d00..a80ab71 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -12,6 +12,15 @@
 #define UNCORE_PMC_IDX_FIXED		UNCORE_PMC_IDX_MAX_GENERIC
 #define UNCORE_PMC_IDX_MAX		(UNCORE_PMC_IDX_FIXED + 1)
 
+#define UNCORE_PCI_DEV_DATA(type, idx)	((type << 8) | idx)
+#define UNCORE_PCI_DEV_TYPE(data)	((data >> 8) & 0xff)
+#define UNCORE_PCI_DEV_IDX(data)	(data & 0xff)
+#define UNCORE_EXTRA_PCI_DEV		0xff
+#define UNCORE_EXTRA_PCI_DEV_MAX	2
+
+/* support up to 8 sockets */
+#define UNCORE_SOCKET_MAX		8
+
 #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff)
 
 /* SNB event control */
@@ -108,6 +117,7 @@
 				(SNBEP_PMON_CTL_EV_SEL_MASK | \
 				 SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
 				 SNBEP_PMON_CTL_EDGE_DET | \
+				 SNBEP_PMON_CTL_EV_SEL_EXT | \
 				 SNBEP_PMON_CTL_INVERT | \
 				 SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
 				 SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 7076878..628a059 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -93,7 +93,7 @@
  * serial key should be enough, as this will always have a VMware
  * specific string when running under VMware hypervisor.
  */
-static bool __init vmware_platform(void)
+static uint32_t __init vmware_platform(void)
 {
 	if (cpu_has_hypervisor) {
 		unsigned int eax;
@@ -102,12 +102,12 @@
 		cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
 		      &hyper_vendor_id[1], &hyper_vendor_id[2]);
 		if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
-			return true;
+			return CPUID_VMWARE_INFO_LEAF;
 	} else if (dmi_available && dmi_name_in_serial("VMware") &&
 		   __vmware_platform())
-		return true;
+		return 1;
 
-	return false;
+	return 0;
 }
 
 /*
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 74467fe..e0e0841 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -128,7 +128,9 @@
 	cpu_emergency_svm_disable();
 
 	lapic_shutdown();
-#if defined(CONFIG_X86_IO_APIC)
+#ifdef CONFIG_X86_IO_APIC
+	/* Prevent crash_kexec() from deadlocking on ioapic_lock. */
+	ioapic_zap_locks();
 	disable_IO_APIC();
 #endif
 #ifdef CONFIG_HPET_TIMER
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index d32abea..174da5f 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -658,15 +658,18 @@
  * boot_params.e820_map, others are passed via SETUP_E820_EXT node of
  * linked list of struct setup_data, which is parsed here.
  */
-void __init parse_e820_ext(struct setup_data *sdata)
+void __init parse_e820_ext(u64 phys_addr, u32 data_len)
 {
 	int entries;
 	struct e820entry *extmap;
+	struct setup_data *sdata;
 
+	sdata = early_memremap(phys_addr, data_len);
 	entries = sdata->len / sizeof(struct e820entry);
 	extmap = (struct e820entry *)(sdata->data);
 	__append_e820_map(extmap, entries);
 	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+	early_iounmap(sdata, data_len);
 	printk(KERN_INFO "e820: extended physical RAM map:\n");
 	e820_print_map("extended");
 }
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 138463a..06f87be 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -29,7 +29,7 @@
 	reserve_ebda_region();
 }
 
-void __init i386_start_kernel(void)
+asmlinkage void __init i386_start_kernel(void)
 {
 	sanitize_boot_params(&boot_params);
 
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 55b6761..1be8e43 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -137,7 +137,7 @@
 	}
 }
 
-void __init x86_64_start_kernel(char * real_mode_data)
+asmlinkage void __init x86_64_start_kernel(char * real_mode_data)
 {
 	int i;
 
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 5dd87a8..81ba276 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -409,6 +409,7 @@
 /*
  * Check if it is 486
  */
+	movb $4,X86			# at least 486
 	cmpl $-1,X86_CPUID
 	je is486
 
@@ -436,7 +437,6 @@
 	movl %edx,X86_CAPABILITY
 
 is486:
-	movb $4,X86
 	movl $0x50022,%ecx	# set AM, WP, NE and MP
 	movl %cr0,%eax
 	andl $0x80000011,%eax	# Save PG,PE,ET
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 3a8185c..22d0687 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -177,7 +177,7 @@
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
+__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
@@ -215,7 +215,7 @@
 		x86_platform_ipi_callback();
 }
 
-void smp_x86_platform_ipi(struct pt_regs *regs)
+__visible void smp_x86_platform_ipi(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
@@ -229,7 +229,7 @@
 /*
  * Handler for POSTED_INTERRUPT_VECTOR.
  */
-void smp_kvm_posted_intr_ipi(struct pt_regs *regs)
+__visible void smp_kvm_posted_intr_ipi(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
@@ -247,7 +247,7 @@
 }
 #endif
 
-void smp_trace_x86_platform_ipi(struct pt_regs *regs)
+__visible void smp_trace_x86_platform_ipi(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
index 636a55e..1de84e3 100644
--- a/arch/x86/kernel/irq_work.c
+++ b/arch/x86/kernel/irq_work.c
@@ -22,14 +22,14 @@
 	irq_work_run();
 }
 
-void smp_irq_work_interrupt(struct pt_regs *regs)
+__visible void smp_irq_work_interrupt(struct pt_regs *regs)
 {
 	irq_work_entering_irq();
 	__smp_irq_work_interrupt();
 	exiting_irq();
 }
 
-void smp_trace_irq_work_interrupt(struct pt_regs *regs)
+__visible void smp_trace_irq_work_interrupt(struct pt_regs *regs)
 {
 	irq_work_entering_irq();
 	trace_irq_work_entry(IRQ_WORK_VECTOR);
diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c
index 2889b3d..460f5d9 100644
--- a/arch/x86/kernel/jump_label.c
+++ b/arch/x86/kernel/jump_label.c
@@ -37,7 +37,19 @@
 	} else
 		memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
 
-	(*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
+	/*
+	 * Make text_poke_bp() a default fallback poker.
+	 *
+	 * At the time the change is being done, just ignore whether we
+	 * are doing nop -> jump or jump -> nop transition, and assume
+	 * always nop being the 'currently valid' instruction
+	 *
+	 */
+	if (poker)
+		(*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
+	else
+		text_poke_bp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE,
+			     (void *)entry->code + JUMP_LABEL_NOP_SIZE);
 }
 
 void arch_jump_label_transform(struct jump_entry *entry,
@@ -45,7 +57,7 @@
 {
 	get_online_cpus();
 	mutex_lock(&text_mutex);
-	__jump_label_transform(entry, type, text_poke_smp);
+	__jump_label_transform(entry, type, NULL);
 	mutex_unlock(&text_mutex);
 	put_online_cpus();
 }
diff --git a/arch/x86/kernel/kprobes/common.h b/arch/x86/kernel/kprobes/common.h
index 2e9d4b5..c6ee63f 100644
--- a/arch/x86/kernel/kprobes/common.h
+++ b/arch/x86/kernel/kprobes/common.h
@@ -82,14 +82,9 @@
 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;
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 211bce4..79a3f96 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -661,7 +661,7 @@
 /*
  * Called from kretprobe_trampoline
  */
-static __used __kprobes void *trampoline_handler(struct pt_regs *regs)
+__visible __used __kprobes void *trampoline_handler(struct pt_regs *regs)
 {
 	struct kretprobe_instance *ri = NULL;
 	struct hlist_head *head, empty_rp;
@@ -1068,7 +1068,7 @@
 
 int __init arch_init_kprobes(void)
 {
-	return arch_init_optprobes();
+	return 0;
 }
 
 int __kprobes arch_trampoline_kprobe(struct kprobe *p)
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index 76dc6f0..898160b 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -88,9 +88,7 @@
 	*(unsigned long *)addr = val;
 }
 
-static void __used __kprobes kprobes_optinsn_template_holder(void)
-{
-	asm volatile (
+asm (
 			".global optprobe_template_entry\n"
 			"optprobe_template_entry:\n"
 #ifdef CONFIG_X86_64
@@ -129,7 +127,6 @@
 #endif
 			".global optprobe_template_end\n"
 			"optprobe_template_end:\n");
-}
 
 #define TMPL_MOVE_IDX \
 	((long)&optprobe_template_val - (long)&optprobe_template_entry)
@@ -371,31 +368,6 @@
 	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.
@@ -403,37 +375,38 @@
 void __kprobes arch_optimize_kprobes(struct list_head *oplist)
 {
 	struct optimized_kprobe *op, *tmp;
-	int c = 0;
+	u8 insn_buf[RELATIVEJUMP_SIZE];
 
 	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;
-	}
+		s32 rel = (s32)((long)op->optinsn.insn -
+			((long)op->kp.addr + RELATIVEJUMP_SIZE));
 
-	/*
-	 * 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);
+		WARN_ON(kprobe_disabled(&op->kp));
+
+		/* 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;
+
+		text_poke_bp(op->kp.addr, insn_buf, RELATIVEJUMP_SIZE,
+			     op->optinsn.insn);
+
+		list_del_init(&op->list);
+	}
 }
 
-static void __kprobes setup_unoptimize_kprobe(struct text_poke_param *tprm,
-					      u8 *insn_buf,
-					      struct optimized_kprobe *op)
+/* Replace a relative jump with a breakpoint (int3).  */
+void __kprobes arch_unoptimize_kprobe(struct optimized_kprobe *op)
 {
+	u8 insn_buf[RELATIVEJUMP_SIZE];
+
 	/* 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;
+	text_poke_bp(op->kp.addr, insn_buf, RELATIVEJUMP_SIZE,
+		     op->optinsn.insn);
 }
 
 /*
@@ -444,34 +417,11 @@
 				    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);
+		arch_unoptimize_kprobe(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
@@ -491,22 +441,3 @@
 	}
 	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/kvm.c b/arch/x86/kernel/kvm.c
index a96d32c..697b93a 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -34,6 +34,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/kprobes.h>
+#include <linux/debugfs.h>
 #include <asm/timer.h>
 #include <asm/cpu.h>
 #include <asm/traps.h>
@@ -419,6 +420,7 @@
 	WARN_ON(kvm_register_clock("primary cpu clock"));
 	kvm_guest_cpu_init();
 	native_smp_prepare_boot_cpu();
+	kvm_spinlock_init();
 }
 
 static void kvm_guest_cpu_online(void *dummy)
@@ -498,11 +500,9 @@
 #endif
 }
 
-static bool __init kvm_detect(void)
+static uint32_t __init kvm_detect(void)
 {
-	if (!kvm_para_available())
-		return false;
-	return true;
+	return kvm_cpuid_base();
 }
 
 const struct hypervisor_x86 x86_hyper_kvm __refconst = {
@@ -523,3 +523,263 @@
 	return 0;
 }
 arch_initcall(activate_jump_labels);
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+
+/* Kick a cpu by its apicid. Used to wake up a halted vcpu */
+static void kvm_kick_cpu(int cpu)
+{
+	int apicid;
+	unsigned long flags = 0;
+
+	apicid = per_cpu(x86_cpu_to_apicid, cpu);
+	kvm_hypercall2(KVM_HC_KICK_CPU, flags, apicid);
+}
+
+enum kvm_contention_stat {
+	TAKEN_SLOW,
+	TAKEN_SLOW_PICKUP,
+	RELEASED_SLOW,
+	RELEASED_SLOW_KICKED,
+	NR_CONTENTION_STATS
+};
+
+#ifdef CONFIG_KVM_DEBUG_FS
+#define HISTO_BUCKETS	30
+
+static struct kvm_spinlock_stats
+{
+	u32 contention_stats[NR_CONTENTION_STATS];
+	u32 histo_spin_blocked[HISTO_BUCKETS+1];
+	u64 time_blocked;
+} spinlock_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+	u8 ret;
+	u8 old;
+
+	old = ACCESS_ONCE(zero_stats);
+	if (unlikely(old)) {
+		ret = cmpxchg(&zero_stats, old, 0);
+		/* This ensures only one fellow resets the stat */
+		if (ret == old)
+			memset(&spinlock_stats, 0, sizeof(spinlock_stats));
+	}
+}
+
+static inline void add_stats(enum kvm_contention_stat var, u32 val)
+{
+	check_zero();
+	spinlock_stats.contention_stats[var] += val;
+}
+
+
+static inline u64 spin_time_start(void)
+{
+	return sched_clock();
+}
+
+static void __spin_time_accum(u64 delta, u32 *array)
+{
+	unsigned index;
+
+	index = ilog2(delta);
+	check_zero();
+
+	if (index < HISTO_BUCKETS)
+		array[index]++;
+	else
+		array[HISTO_BUCKETS]++;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+	u32 delta;
+
+	delta = sched_clock() - start;
+	__spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+	spinlock_stats.time_blocked += delta;
+}
+
+static struct dentry *d_spin_debug;
+static struct dentry *d_kvm_debug;
+
+struct dentry *kvm_init_debugfs(void)
+{
+	d_kvm_debug = debugfs_create_dir("kvm", NULL);
+	if (!d_kvm_debug)
+		printk(KERN_WARNING "Could not create 'kvm' debugfs directory\n");
+
+	return d_kvm_debug;
+}
+
+static int __init kvm_spinlock_debugfs(void)
+{
+	struct dentry *d_kvm;
+
+	d_kvm = kvm_init_debugfs();
+	if (d_kvm == NULL)
+		return -ENOMEM;
+
+	d_spin_debug = debugfs_create_dir("spinlocks", d_kvm);
+
+	debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
+
+	debugfs_create_u32("taken_slow", 0444, d_spin_debug,
+		   &spinlock_stats.contention_stats[TAKEN_SLOW]);
+	debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
+		   &spinlock_stats.contention_stats[TAKEN_SLOW_PICKUP]);
+
+	debugfs_create_u32("released_slow", 0444, d_spin_debug,
+		   &spinlock_stats.contention_stats[RELEASED_SLOW]);
+	debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
+		   &spinlock_stats.contention_stats[RELEASED_SLOW_KICKED]);
+
+	debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+			   &spinlock_stats.time_blocked);
+
+	debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+		     spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
+
+	return 0;
+}
+fs_initcall(kvm_spinlock_debugfs);
+#else  /* !CONFIG_KVM_DEBUG_FS */
+static inline void add_stats(enum kvm_contention_stat var, u32 val)
+{
+}
+
+static inline u64 spin_time_start(void)
+{
+	return 0;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+}
+#endif  /* CONFIG_KVM_DEBUG_FS */
+
+struct kvm_lock_waiting {
+	struct arch_spinlock *lock;
+	__ticket_t want;
+};
+
+/* cpus 'waiting' on a spinlock to become available */
+static cpumask_t waiting_cpus;
+
+/* Track spinlock on which a cpu is waiting */
+static DEFINE_PER_CPU(struct kvm_lock_waiting, klock_waiting);
+
+static void kvm_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
+{
+	struct kvm_lock_waiting *w;
+	int cpu;
+	u64 start;
+	unsigned long flags;
+
+	if (in_nmi())
+		return;
+
+	w = &__get_cpu_var(klock_waiting);
+	cpu = smp_processor_id();
+	start = spin_time_start();
+
+	/*
+	 * Make sure an interrupt handler can't upset things in a
+	 * partially setup state.
+	 */
+	local_irq_save(flags);
+
+	/*
+	 * The ordering protocol on this is that the "lock" pointer
+	 * may only be set non-NULL if the "want" ticket is correct.
+	 * If we're updating "want", we must first clear "lock".
+	 */
+	w->lock = NULL;
+	smp_wmb();
+	w->want = want;
+	smp_wmb();
+	w->lock = lock;
+
+	add_stats(TAKEN_SLOW, 1);
+
+	/*
+	 * This uses set_bit, which is atomic but we should not rely on its
+	 * reordering gurantees. So barrier is needed after this call.
+	 */
+	cpumask_set_cpu(cpu, &waiting_cpus);
+
+	barrier();
+
+	/*
+	 * Mark entry to slowpath before doing the pickup test to make
+	 * sure we don't deadlock with an unlocker.
+	 */
+	__ticket_enter_slowpath(lock);
+
+	/*
+	 * check again make sure it didn't become free while
+	 * we weren't looking.
+	 */
+	if (ACCESS_ONCE(lock->tickets.head) == want) {
+		add_stats(TAKEN_SLOW_PICKUP, 1);
+		goto out;
+	}
+
+	/*
+	 * halt until it's our turn and kicked. Note that we do safe halt
+	 * for irq enabled case to avoid hang when lock info is overwritten
+	 * in irq spinlock slowpath and no spurious interrupt occur to save us.
+	 */
+	if (arch_irqs_disabled_flags(flags))
+		halt();
+	else
+		safe_halt();
+
+out:
+	cpumask_clear_cpu(cpu, &waiting_cpus);
+	w->lock = NULL;
+	local_irq_restore(flags);
+	spin_time_accum_blocked(start);
+}
+PV_CALLEE_SAVE_REGS_THUNK(kvm_lock_spinning);
+
+/* Kick vcpu waiting on @lock->head to reach value @ticket */
+static void kvm_unlock_kick(struct arch_spinlock *lock, __ticket_t ticket)
+{
+	int cpu;
+
+	add_stats(RELEASED_SLOW, 1);
+	for_each_cpu(cpu, &waiting_cpus) {
+		const struct kvm_lock_waiting *w = &per_cpu(klock_waiting, cpu);
+		if (ACCESS_ONCE(w->lock) == lock &&
+		    ACCESS_ONCE(w->want) == ticket) {
+			add_stats(RELEASED_SLOW_KICKED, 1);
+			kvm_kick_cpu(cpu);
+			break;
+		}
+	}
+}
+
+/*
+ * Setup pv_lock_ops to exploit KVM_FEATURE_PV_UNHALT if present.
+ */
+void __init kvm_spinlock_init(void)
+{
+	if (!kvm_para_available())
+		return;
+	/* Does host kernel support KVM_FEATURE_PV_UNHALT? */
+	if (!kvm_para_has_feature(KVM_FEATURE_PV_UNHALT))
+		return;
+
+	printk(KERN_INFO "KVM setup paravirtual spinlock\n");
+
+	static_key_slow_inc(&paravirt_ticketlocks_enabled);
+
+	pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(kvm_lock_spinning);
+	pv_lock_ops.unlock_kick = kvm_unlock_kick;
+}
+#endif	/* CONFIG_PARAVIRT_SPINLOCKS */
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index 7a0adb7..7123b5d 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -145,10 +145,9 @@
 	return 0;
 }
 
-static unsigned int verify_patch_size(int cpu, u32 patch_size,
+static unsigned int verify_patch_size(u8 family, u32 patch_size,
 				      unsigned int size)
 {
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
 	u32 max_size;
 
 #define F1XH_MPB_MAX_SIZE 2048
@@ -156,7 +155,7 @@
 #define F15H_MPB_MAX_SIZE 4096
 #define F16H_MPB_MAX_SIZE 3458
 
-	switch (c->x86) {
+	switch (family) {
 	case 0x14:
 		max_size = F14H_MPB_MAX_SIZE;
 		break;
@@ -277,9 +276,8 @@
  * driver cannot continue functioning normally. In such cases, we tear
  * down everything we've used up so far and exit.
  */
-static int verify_and_add_patch(unsigned int cpu, u8 *fw, unsigned int leftover)
+static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover)
 {
-	struct cpuinfo_x86 *c = &cpu_data(cpu);
 	struct microcode_header_amd *mc_hdr;
 	struct ucode_patch *patch;
 	unsigned int patch_size, crnt_size, ret;
@@ -299,7 +297,7 @@
 
 	/* check if patch is for the current family */
 	proc_fam = ((proc_fam >> 8) & 0xf) + ((proc_fam >> 20) & 0xff);
-	if (proc_fam != c->x86)
+	if (proc_fam != family)
 		return crnt_size;
 
 	if (mc_hdr->nb_dev_id || mc_hdr->sb_dev_id) {
@@ -308,7 +306,7 @@
 		return crnt_size;
 	}
 
-	ret = verify_patch_size(cpu, patch_size, leftover);
+	ret = verify_patch_size(family, patch_size, leftover);
 	if (!ret) {
 		pr_err("Patch-ID 0x%08x: size mismatch.\n", mc_hdr->patch_id);
 		return crnt_size;
@@ -339,7 +337,8 @@
 	return crnt_size;
 }
 
-static enum ucode_state __load_microcode_amd(int cpu, const u8 *data, size_t size)
+static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
+					     size_t size)
 {
 	enum ucode_state ret = UCODE_ERROR;
 	unsigned int leftover;
@@ -362,7 +361,7 @@
 	}
 
 	while (leftover) {
-		crnt_size = verify_and_add_patch(cpu, fw, leftover);
+		crnt_size = verify_and_add_patch(family, fw, leftover);
 		if (crnt_size < 0)
 			return ret;
 
@@ -373,22 +372,22 @@
 	return UCODE_OK;
 }
 
-enum ucode_state load_microcode_amd(int cpu, const u8 *data, size_t size)
+enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
 {
 	enum ucode_state ret;
 
 	/* free old equiv table */
 	free_equiv_cpu_table();
 
-	ret = __load_microcode_amd(cpu, data, size);
+	ret = __load_microcode_amd(family, data, size);
 
 	if (ret != UCODE_OK)
 		cleanup();
 
 #if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
 	/* save BSP's matching patch for early load */
-	if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
-		struct ucode_patch *p = find_patch(cpu);
+	if (cpu_data(smp_processor_id()).cpu_index == boot_cpu_data.cpu_index) {
+		struct ucode_patch *p = find_patch(smp_processor_id());
 		if (p) {
 			memset(amd_bsp_mpb, 0, MPB_MAX_SIZE);
 			memcpy(amd_bsp_mpb, p->data, min_t(u32, ksize(p->data),
@@ -441,7 +440,7 @@
 		goto fw_release;
 	}
 
-	ret = load_microcode_amd(cpu, fw->data, fw->size);
+	ret = load_microcode_amd(c->x86, fw->data, fw->size);
 
  fw_release:
 	release_firmware(fw);
diff --git a/arch/x86/kernel/microcode_amd_early.c b/arch/x86/kernel/microcode_amd_early.c
index 1d14ffe..6073104 100644
--- a/arch/x86/kernel/microcode_amd_early.c
+++ b/arch/x86/kernel/microcode_amd_early.c
@@ -238,25 +238,17 @@
 	uci->cpu_sig.sig = cpuid_eax(0x00000001);
 }
 #else
-static void collect_cpu_info_amd_early(struct cpuinfo_x86 *c,
-						 struct ucode_cpu_info *uci)
+void load_ucode_amd_ap(void)
 {
+	unsigned int cpu = smp_processor_id();
+	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 	u32 rev, eax;
 
 	rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
 	eax = cpuid_eax(0x00000001);
 
-	uci->cpu_sig.sig = eax;
 	uci->cpu_sig.rev = rev;
-	c->microcode = rev;
-	c->x86 = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
-}
-
-void load_ucode_amd_ap(void)
-{
-	unsigned int cpu = smp_processor_id();
-
-	collect_cpu_info_amd_early(&cpu_data(cpu), ucode_cpu_info + cpu);
+	uci->cpu_sig.sig = eax;
 
 	if (cpu && !ucode_loaded) {
 		void *ucode;
@@ -265,8 +257,10 @@
 			return;
 
 		ucode = (void *)(initrd_start + ucode_offset);
-		if (load_microcode_amd(0, ucode, ucode_size) != UCODE_OK)
+		eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
+		if (load_microcode_amd(eax, ucode, ucode_size) != UCODE_OK)
 			return;
+
 		ucode_loaded = true;
 	}
 
@@ -278,6 +272,8 @@
 {
 	enum ucode_state ret;
 	void *ucode;
+	u32 eax;
+
 #ifdef CONFIG_X86_32
 	unsigned int bsp = boot_cpu_data.cpu_index;
 	struct ucode_cpu_info *uci = ucode_cpu_info + bsp;
@@ -293,7 +289,10 @@
 		return 0;
 
 	ucode = (void *)(initrd_start + ucode_offset);
-	ret = load_microcode_amd(0, ucode, ucode_size);
+	eax   = cpuid_eax(0x00000001);
+	eax   = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
+
+	ret = load_microcode_amd(eax, ucode, ucode_size);
 	if (ret != UCODE_OK)
 		return -EINVAL;
 
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
index 676b8c7..bbb6c73 100644
--- a/arch/x86/kernel/paravirt-spinlocks.c
+++ b/arch/x86/kernel/paravirt-spinlocks.c
@@ -4,25 +4,17 @@
  */
 #include <linux/spinlock.h>
 #include <linux/module.h>
+#include <linux/jump_label.h>
 
 #include <asm/paravirt.h>
 
-static inline void
-default_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags)
-{
-	arch_spin_lock(lock);
-}
-
 struct pv_lock_ops pv_lock_ops = {
 #ifdef CONFIG_SMP
-	.spin_is_locked = __ticket_spin_is_locked,
-	.spin_is_contended = __ticket_spin_is_contended,
-
-	.spin_lock = __ticket_spin_lock,
-	.spin_lock_flags = default_spin_lock_flags,
-	.spin_trylock = __ticket_spin_trylock,
-	.spin_unlock = __ticket_spin_unlock,
+	.lock_spinning = __PV_IS_CALLEE_SAVE(paravirt_nop),
+	.unlock_kick = paravirt_nop,
 #endif
 };
 EXPORT_SYMBOL(pv_lock_ops);
 
+struct static_key paravirt_ticketlocks_enabled = STATIC_KEY_INIT_FALSE;
+EXPORT_SYMBOL(paravirt_ticketlocks_enabled);
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index cd6de64..884aa40 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -324,7 +324,7 @@
 	.steal_clock = native_steal_clock,
 };
 
-struct pv_irq_ops pv_irq_ops = {
+__visible struct pv_irq_ops pv_irq_ops = {
 	.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
 	.restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
 	.irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
@@ -336,7 +336,7 @@
 #endif
 };
 
-struct pv_cpu_ops pv_cpu_ops = {
+__visible struct pv_cpu_ops pv_cpu_ops = {
 	.cpuid = native_cpuid,
 	.get_debugreg = native_get_debugreg,
 	.set_debugreg = native_set_debugreg,
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 83369e5..c83516b 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -36,7 +36,7 @@
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */
-DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
+__visible DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
 
 #ifdef CONFIG_X86_64
 static DEFINE_PER_CPU(unsigned char, is_idle);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index f8adefc..884f98f 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -247,7 +247,7 @@
  * the task-switch, and shows up in ret_from_fork in entry.S,
  * for example.
  */
-__notrace_funcgraph struct task_struct *
+__visible __notrace_funcgraph struct task_struct *
 __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread,
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 05646ba..bb1dc51 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -52,7 +52,7 @@
 
 asmlinkage extern void ret_from_fork(void);
 
-DEFINE_PER_CPU(unsigned long, old_rsp);
+asmlinkage DEFINE_PER_CPU(unsigned long, old_rsp);
 
 /* Prints also some state that isn't saved in the pt_regs */
 void __show_regs(struct pt_regs *regs, int all)
@@ -274,7 +274,7 @@
  * Kprobes not supported here. Set the probe on schedule instead.
  * Function graph tracer not supported too.
  */
-__notrace_funcgraph struct task_struct *
+__visible __notrace_funcgraph struct task_struct *
 __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
 	struct thread_struct *prev = &prev_p->thread;
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
index 2cb9470..a16bae3 100644
--- a/arch/x86/kernel/pvclock.c
+++ b/arch/x86/kernel/pvclock.c
@@ -128,46 +128,7 @@
 	set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
 }
 
-static struct pvclock_vsyscall_time_info *pvclock_vdso_info;
-
-static struct pvclock_vsyscall_time_info *
-pvclock_get_vsyscall_user_time_info(int cpu)
-{
-	if (!pvclock_vdso_info) {
-		BUG();
-		return NULL;
-	}
-
-	return &pvclock_vdso_info[cpu];
-}
-
-struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu)
-{
-	return &pvclock_get_vsyscall_user_time_info(cpu)->pvti;
-}
-
 #ifdef CONFIG_X86_64
-static int pvclock_task_migrate(struct notifier_block *nb, unsigned long l,
-			        void *v)
-{
-	struct task_migration_notifier *mn = v;
-	struct pvclock_vsyscall_time_info *pvti;
-
-	pvti = pvclock_get_vsyscall_user_time_info(mn->from_cpu);
-
-	/* this is NULL when pvclock vsyscall is not initialized */
-	if (unlikely(pvti == NULL))
-		return NOTIFY_DONE;
-
-	pvti->migrate_count++;
-
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block pvclock_migrate = {
-	.notifier_call = pvclock_task_migrate,
-};
-
 /*
  * Initialize the generic pvclock vsyscall state.  This will allocate
  * a/some page(s) for the per-vcpu pvclock information, set up a
@@ -181,17 +142,12 @@
 
 	WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE);
 
-	pvclock_vdso_info = i;
-
 	for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
 		__set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
 			     __pa(i) + (idx*PAGE_SIZE),
 			     PAGE_KERNEL_VVAR);
 	}
 
-
-	register_task_migration_notifier(&pvclock_migrate);
-
 	return 0;
 }
 #endif
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f8ec578..f0de629 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -206,9 +206,9 @@
 
 
 #if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64)
-unsigned long mmu_cr4_features;
+__visible unsigned long mmu_cr4_features;
 #else
-unsigned long mmu_cr4_features = X86_CR4_PAE;
+__visible unsigned long mmu_cr4_features = X86_CR4_PAE;
 #endif
 
 /* Boot loader ID and version as integers, for the benefit of proc_dointvec */
@@ -426,25 +426,23 @@
 static void __init parse_setup_data(void)
 {
 	struct setup_data *data;
-	u64 pa_data;
+	u64 pa_data, pa_next;
 
 	pa_data = boot_params.hdr.setup_data;
 	while (pa_data) {
-		u32 data_len, map_len;
+		u32 data_len, map_len, data_type;
 
 		map_len = max(PAGE_SIZE - (pa_data & ~PAGE_MASK),
 			      (u64)sizeof(struct setup_data));
 		data = early_memremap(pa_data, map_len);
 		data_len = data->len + sizeof(struct setup_data);
-		if (data_len > map_len) {
-			early_iounmap(data, map_len);
-			data = early_memremap(pa_data, data_len);
-			map_len = data_len;
-		}
+		data_type = data->type;
+		pa_next = data->next;
+		early_iounmap(data, map_len);
 
-		switch (data->type) {
+		switch (data_type) {
 		case SETUP_E820_EXT:
-			parse_e820_ext(data);
+			parse_e820_ext(pa_data, data_len);
 			break;
 		case SETUP_DTB:
 			add_dtb(pa_data);
@@ -452,8 +450,7 @@
 		default:
 			break;
 		}
-		pa_data = data->next;
-		early_iounmap(data, map_len);
+		pa_data = pa_next;
 	}
 }
 
@@ -1070,7 +1067,7 @@
 
 	cleanup_highmap();
 
-	memblock.current_limit = ISA_END_ADDRESS;
+	memblock_set_current_limit(ISA_END_ADDRESS);
 	memblock_x86_fill();
 
 	/*
@@ -1103,7 +1100,7 @@
 
 	setup_real_mode();
 
-	memblock.current_limit = get_max_mapped();
+	memblock_set_current_limit(get_max_mapped());
 	dma_contiguous_reserve(0);
 
 	/*
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index cf91358..9e5de68 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -358,7 +358,7 @@
 		else
 			put_user_ex(0, &frame->uc.uc_flags);
 		put_user_ex(0, &frame->uc.uc_link);
-		err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
+		save_altstack_ex(&frame->uc.uc_stack, regs->sp);
 
 		/* Set up to return from userspace.  */
 		restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -423,7 +423,7 @@
 		else
 			put_user_ex(0, &frame->uc.uc_flags);
 		put_user_ex(0, &frame->uc.uc_link);
-		err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
+		save_altstack_ex(&frame->uc.uc_stack, regs->sp);
 
 		/* Set up to return from userspace.  If provided, use a stub
 		   already in userspace.  */
@@ -490,7 +490,7 @@
 		else
 			put_user_ex(0, &frame->uc.uc_flags);
 		put_user_ex(0, &frame->uc.uc_link);
-		err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
+		compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp);
 		put_user_ex(0, &frame->uc.uc__pad0);
 
 		if (ksig->ka.sa.sa_flags & SA_RESTORER) {
@@ -533,7 +533,7 @@
  * Do a signal return; undo the signal stack.
  */
 #ifdef CONFIG_X86_32
-unsigned long sys_sigreturn(void)
+asmlinkage unsigned long sys_sigreturn(void)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct sigframe __user *frame;
@@ -562,7 +562,7 @@
 }
 #endif /* CONFIG_X86_32 */
 
-long sys_rt_sigreturn(void)
+asmlinkage long sys_rt_sigreturn(void)
 {
 	struct pt_regs *regs = current_pt_regs();
 	struct rt_sigframe __user *frame;
@@ -728,7 +728,7 @@
  * notification of userspace execution resumption
  * - triggered by the TIF_WORK_MASK flags
  */
-void
+__visible void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
 	user_exit();
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index cdaa347..7c3a5a6 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -256,7 +256,7 @@
 	scheduler_ipi();
 }
 
-void smp_reschedule_interrupt(struct pt_regs *regs)
+__visible void smp_reschedule_interrupt(struct pt_regs *regs)
 {
 	ack_APIC_irq();
 	__smp_reschedule_interrupt();
@@ -271,7 +271,7 @@
 	irq_enter();
 }
 
-void smp_trace_reschedule_interrupt(struct pt_regs *regs)
+__visible void smp_trace_reschedule_interrupt(struct pt_regs *regs)
 {
 	/*
 	 * Need to call irq_enter() before calling the trace point.
@@ -295,14 +295,14 @@
 	inc_irq_stat(irq_call_count);
 }
 
-void smp_call_function_interrupt(struct pt_regs *regs)
+__visible void smp_call_function_interrupt(struct pt_regs *regs)
 {
 	smp_entering_irq();
 	__smp_call_function_interrupt();
 	exiting_irq();
 }
 
-void smp_trace_call_function_interrupt(struct pt_regs *regs)
+__visible void smp_trace_call_function_interrupt(struct pt_regs *regs)
 {
 	smp_entering_irq();
 	trace_call_function_entry(CALL_FUNCTION_VECTOR);
@@ -317,14 +317,14 @@
 	inc_irq_stat(irq_call_count);
 }
 
-void smp_call_function_single_interrupt(struct pt_regs *regs)
+__visible void smp_call_function_single_interrupt(struct pt_regs *regs)
 {
 	smp_entering_irq();
 	__smp_call_function_single_interrupt();
 	exiting_irq();
 }
 
-void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
+__visible void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
 {
 	smp_entering_irq();
 	trace_call_function_single_entry(CALL_FUNCTION_SINGLE_VECTOR);
diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c
index 48f8375..30277e2 100644
--- a/arch/x86/kernel/sys_x86_64.c
+++ b/arch/x86/kernel/sys_x86_64.c
@@ -101,7 +101,7 @@
 				*begin = new_begin;
 		}
 	} else {
-		*begin = mmap_legacy_base();
+		*begin = current->mm->mmap_legacy_base;
 		*end = TASK_SIZE;
 	}
 }
diff --git a/arch/x86/kernel/syscall_32.c b/arch/x86/kernel/syscall_32.c
index 147fcd4..e9bcd57 100644
--- a/arch/x86/kernel/syscall_32.c
+++ b/arch/x86/kernel/syscall_32.c
@@ -15,7 +15,7 @@
 
 extern asmlinkage void sys_ni_syscall(void);
 
-const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
+__visible const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
 	/*
 	 * Smells like a compiler bug -- it doesn't work
 	 * when the & below is removed.
diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c
index 5c7f8c2..4ac730b 100644
--- a/arch/x86/kernel/syscall_64.c
+++ b/arch/x86/kernel/syscall_64.c
@@ -4,6 +4,7 @@
 #include <linux/sys.h>
 #include <linux/cache.h>
 #include <asm/asm-offsets.h>
+#include <asm/syscall.h>
 
 #define __SYSCALL_COMMON(nr, sym, compat) __SYSCALL_64(nr, sym, compat)
 
@@ -19,11 +20,9 @@
 
 #define __SYSCALL_64(nr, sym, compat) [nr] = sym,
 
-typedef void (*sys_call_ptr_t)(void);
-
 extern void sys_ni_syscall(void);
 
-const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
+asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
 	/*
 	 * Smells like a compiler bug -- it doesn't work
 	 * when the & below is removed.
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
new file mode 100644
index 0000000..193ec2c
--- /dev/null
+++ b/arch/x86/kernel/sysfb.c
@@ -0,0 +1,74 @@
+/*
+ * Generic System Framebuffers on x86
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.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.
+ */
+
+/*
+ * Simple-Framebuffer support for x86 systems
+ * Create a platform-device for any available boot framebuffer. The
+ * simple-framebuffer platform device is already available on DT systems, so
+ * this module parses the global "screen_info" object and creates a suitable
+ * platform device compatible with the "simple-framebuffer" DT object. If
+ * the framebuffer is incompatible, we instead create a legacy
+ * "vesa-framebuffer", "efi-framebuffer" or "platform-framebuffer" device and
+ * pass the screen_info as platform_data. This allows legacy drivers
+ * to pick these devices up without messing with simple-framebuffer drivers.
+ * The global "screen_info" is still valid at all times.
+ *
+ * If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer"
+ * platform devices, but only use legacy framebuffer devices for
+ * backwards compatibility.
+ *
+ * TODO: We set the dev_id field of all platform-devices to 0. This allows
+ * other x86 OF/DT parsers to create such devices, too. However, they must
+ * start at offset 1 for this to work.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <asm/sysfb.h>
+
+static __init int sysfb_init(void)
+{
+	struct screen_info *si = &screen_info;
+	struct simplefb_platform_data mode;
+	struct platform_device *pd;
+	const char *name;
+	bool compatible;
+	int ret;
+
+	sysfb_apply_efi_quirks();
+
+	/* try to create a simple-framebuffer device */
+	compatible = parse_mode(si, &mode);
+	if (compatible) {
+		ret = create_simplefb(si, &mode);
+		if (!ret)
+			return 0;
+	}
+
+	/* if the FB is incompatible, create a legacy framebuffer device */
+	if (si->orig_video_isVGA == VIDEO_TYPE_EFI)
+		name = "efi-framebuffer";
+	else if (si->orig_video_isVGA == VIDEO_TYPE_VLFB)
+		name = "vesa-framebuffer";
+	else
+		name = "platform-framebuffer";
+
+	pd = platform_device_register_resndata(NULL, name, 0,
+					       NULL, 0, si, sizeof(*si));
+	return IS_ERR(pd) ? PTR_ERR(pd) : 0;
+}
+
+/* must execute after PCI subsystem for EFI quirks */
+device_initcall(sysfb_init);
diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c
new file mode 100644
index 0000000..b285d4e
--- /dev/null
+++ b/arch/x86/kernel/sysfb_efi.c
@@ -0,0 +1,214 @@
+/*
+ * Generic System Framebuffers on x86
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * EFI Quirks Copyright (c) 2006 Edgar Hucek <gimli@dark-green.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.
+ */
+
+/*
+ * EFI Quirks
+ * Several EFI systems do not correctly advertise their boot framebuffers.
+ * Hence, we use this static table of known broken machines and fix up the
+ * information so framebuffer drivers can load corectly.
+ */
+
+#include <linux/dmi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/screen_info.h>
+#include <video/vga.h>
+#include <asm/sysfb.h>
+
+enum {
+	OVERRIDE_NONE = 0x0,
+	OVERRIDE_BASE = 0x1,
+	OVERRIDE_STRIDE = 0x2,
+	OVERRIDE_HEIGHT = 0x4,
+	OVERRIDE_WIDTH = 0x8,
+};
+
+struct efifb_dmi_info efifb_dmi_list[] = {
+	[M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */
+	[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE },
+	[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */
+	[M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE },
+	[M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE },
+	[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE },
+	[M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE },
+	[M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	/* 11" Macbook Air 3,1 passes the wrong stride */
+	[M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE },
+	[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */
+	[M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
+	[M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE },
+	[M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
+	[M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
+	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
+};
+
+#define choose_value(dmivalue, fwvalue, field, flags) ({	\
+		typeof(fwvalue) _ret_ = fwvalue;		\
+		if ((flags) & (field))				\
+			_ret_ = dmivalue;			\
+		else if ((fwvalue) == 0)			\
+			_ret_ = dmivalue;			\
+		_ret_;						\
+	})
+
+static int __init efifb_set_system(const struct dmi_system_id *id)
+{
+	struct efifb_dmi_info *info = id->driver_data;
+
+	if (info->base == 0 && info->height == 0 && info->width == 0 &&
+	    info->stride == 0)
+		return 0;
+
+	/* Trust the bootloader over the DMI tables */
+	if (screen_info.lfb_base == 0) {
+#if defined(CONFIG_PCI)
+		struct pci_dev *dev = NULL;
+		int found_bar = 0;
+#endif
+		if (info->base) {
+			screen_info.lfb_base = choose_value(info->base,
+				screen_info.lfb_base, OVERRIDE_BASE,
+				info->flags);
+
+#if defined(CONFIG_PCI)
+			/* make sure that the address in the table is actually
+			 * on a VGA device's PCI BAR */
+
+			for_each_pci_dev(dev) {
+				int i;
+				if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+					continue;
+				for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+					resource_size_t start, end;
+
+					start = pci_resource_start(dev, i);
+					if (start == 0)
+						break;
+					end = pci_resource_end(dev, i);
+					if (screen_info.lfb_base >= start &&
+					    screen_info.lfb_base < end) {
+						found_bar = 1;
+					}
+				}
+			}
+			if (!found_bar)
+				screen_info.lfb_base = 0;
+#endif
+		}
+	}
+	if (screen_info.lfb_base) {
+		screen_info.lfb_linelength = choose_value(info->stride,
+			screen_info.lfb_linelength, OVERRIDE_STRIDE,
+			info->flags);
+		screen_info.lfb_width = choose_value(info->width,
+			screen_info.lfb_width, OVERRIDE_WIDTH,
+			info->flags);
+		screen_info.lfb_height = choose_value(info->height,
+			screen_info.lfb_height, OVERRIDE_HEIGHT,
+			info->flags);
+		if (screen_info.orig_video_isVGA == 0)
+			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+	} else {
+		screen_info.lfb_linelength = 0;
+		screen_info.lfb_width = 0;
+		screen_info.lfb_height = 0;
+		screen_info.orig_video_isVGA = 0;
+		return 0;
+	}
+
+	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
+			 "(%dx%d, stride %d)\n", id->ident,
+			 screen_info.lfb_base, screen_info.lfb_width,
+			 screen_info.lfb_height, screen_info.lfb_linelength);
+
+	return 1;
+}
+
+#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
+	{							\
+		efifb_set_system,				\
+		name,						\
+		{						\
+			DMI_MATCH(DMI_BIOS_VENDOR, vendor),	\
+			DMI_MATCH(DMI_PRODUCT_NAME, name)	\
+		},						\
+		&efifb_dmi_list[enumid]				\
+	}
+
+static const struct dmi_system_id efifb_dmi_system_table[] __initconst = {
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
+	/* At least one of these two will be right; maybe both? */
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
+	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2),
+	{},
+};
+
+__init void sysfb_apply_efi_quirks(void)
+{
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
+	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
+		dmi_check_system(efifb_dmi_system_table);
+}
diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
new file mode 100644
index 0000000..22513e9
--- /dev/null
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -0,0 +1,95 @@
+/*
+ * Generic System Framebuffers on x86
+ * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.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.
+ */
+
+/*
+ * simple-framebuffer probing
+ * Try to convert "screen_info" into a "simple-framebuffer" compatible mode.
+ * If the mode is incompatible, we return "false" and let the caller create
+ * legacy nodes instead.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/platform_data/simplefb.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <asm/sysfb.h>
+
+static const char simplefb_resname[] = "BOOTFB";
+static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
+
+/* try parsing x86 screen_info into a simple-framebuffer mode struct */
+__init bool parse_mode(const struct screen_info *si,
+		       struct simplefb_platform_data *mode)
+{
+	const struct simplefb_format *f;
+	__u8 type;
+	unsigned int i;
+
+	type = si->orig_video_isVGA;
+	if (type != VIDEO_TYPE_VLFB && type != VIDEO_TYPE_EFI)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+		f = &formats[i];
+		if (si->lfb_depth == f->bits_per_pixel &&
+		    si->red_size == f->red.length &&
+		    si->red_pos == f->red.offset &&
+		    si->green_size == f->green.length &&
+		    si->green_pos == f->green.offset &&
+		    si->blue_size == f->blue.length &&
+		    si->blue_pos == f->blue.offset &&
+		    si->rsvd_size == f->transp.length &&
+		    si->rsvd_pos == f->transp.offset) {
+			mode->format = f->name;
+			mode->width = si->lfb_width;
+			mode->height = si->lfb_height;
+			mode->stride = si->lfb_linelength;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+__init int create_simplefb(const struct screen_info *si,
+			   const struct simplefb_platform_data *mode)
+{
+	struct platform_device *pd;
+	struct resource res;
+	unsigned long len;
+
+	/* don't use lfb_size as it may contain the whole VMEM instead of only
+	 * the part that is occupied by the framebuffer */
+	len = mode->height * mode->stride;
+	len = PAGE_ALIGN(len);
+	if (len > si->lfb_size << 16) {
+		printk(KERN_WARNING "sysfb: VRAM smaller than advertised\n");
+		return -EINVAL;
+	}
+
+	/* setup IORESOURCE_MEM as framebuffer memory */
+	memset(&res, 0, sizeof(res));
+	res.flags = IORESOURCE_MEM;
+	res.name = simplefb_resname;
+	res.start = si->lfb_base;
+	res.end = si->lfb_base + len - 1;
+	if (res.end <= res.start)
+		return -EINVAL;
+
+	pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
+					       &res, 1, mode, sizeof(*mode));
+	if (IS_ERR(pd))
+		return PTR_ERR(pd);
+
+	return 0;
+}
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index addf7b5..91a4496 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -301,6 +301,15 @@
 	return 0;
 }
 
+static int tboot_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b)
+{
+	if (!tboot_enabled())
+		return 0;
+
+	pr_warning("tboot is not able to suspend on platforms with reduced hardware sleep (ACPIv5)");
+	return -ENODEV;
+}
+
 static atomic_t ap_wfs_count;
 
 static int tboot_wait_for_aps(int num_aps)
@@ -422,6 +431,7 @@
 #endif
 
 	acpi_os_set_prepare_sleep(&tboot_sleep);
+	acpi_os_set_prepare_extended_sleep(&tboot_extended_sleep);
 	return 0;
 }
 
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 1b23a1c..8c8093b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -58,6 +58,7 @@
 #include <asm/mce.h>
 #include <asm/fixmap.h>
 #include <asm/mach_traps.h>
+#include <asm/alternative.h>
 
 #ifdef CONFIG_X86_64
 #include <asm/x86_init.h>
@@ -327,6 +328,9 @@
 	    ftrace_int3_handler(regs))
 		return;
 #endif
+	if (poke_int3_handler(regs))
+		return;
+
 	prev_state = exception_enter();
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
 	if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 6ff4924..930e5d4 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -89,6 +89,12 @@
 }
 EXPORT_SYMBOL_GPL(check_tsc_unstable);
 
+int check_tsc_disabled(void)
+{
+	return tsc_disabled;
+}
+EXPORT_SYMBOL_GPL(check_tsc_disabled);
+
 #ifdef CONFIG_X86_TSC
 int __init notsc_setup(char *str)
 {
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index a20ecb5..b110fe6 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -413,7 +413,8 @@
 			     (1 << KVM_FEATURE_CLOCKSOURCE2) |
 			     (1 << KVM_FEATURE_ASYNC_PF) |
 			     (1 << KVM_FEATURE_PV_EOI) |
-			     (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
+			     (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) |
+			     (1 << KVM_FEATURE_PV_UNHALT);
 
 		if (sched_info_on())
 			entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index afc1124..5439117 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -79,16 +79,6 @@
 	*((u32 *) (apic->regs + reg_off)) = val;
 }
 
-static inline int apic_test_and_set_vector(int vec, void *bitmap)
-{
-	return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
-static inline int apic_test_and_clear_vector(int vec, void *bitmap)
-{
-	return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
 static inline int apic_test_vector(int vec, void *bitmap)
 {
 	return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -331,10 +321,10 @@
 }
 EXPORT_SYMBOL_GPL(kvm_apic_update_irr);
 
-static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
+static inline void apic_set_irr(int vec, struct kvm_lapic *apic)
 {
 	apic->irr_pending = true;
-	return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
+	apic_set_vector(vec, apic->regs + APIC_IRR);
 }
 
 static inline int apic_search_irr(struct kvm_lapic *apic)
@@ -681,32 +671,28 @@
 		if (unlikely(!apic_enabled(apic)))
 			break;
 
+		result = 1;
+
 		if (dest_map)
 			__set_bit(vcpu->vcpu_id, dest_map);
 
-		if (kvm_x86_ops->deliver_posted_interrupt) {
-			result = 1;
+		if (kvm_x86_ops->deliver_posted_interrupt)
 			kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
-		} else {
-			result = !apic_test_and_set_irr(vector, apic);
-
-			if (!result) {
-				if (trig_mode)
-					apic_debug("level trig mode repeatedly "
-						"for vector %d", vector);
-				goto out;
-			}
+		else {
+			apic_set_irr(vector, apic);
 
 			kvm_make_request(KVM_REQ_EVENT, vcpu);
 			kvm_vcpu_kick(vcpu);
 		}
-out:
 		trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode,
-				trig_mode, vector, !result);
+					  trig_mode, vector, false);
 		break;
 
 	case APIC_DM_REMRD:
-		apic_debug("Ignoring delivery mode 3\n");
+		result = 1;
+		vcpu->arch.pv.pv_unhalted = 1;
+		kvm_make_request(KVM_REQ_EVENT, vcpu);
+		kvm_vcpu_kick(vcpu);
 		break;
 
 	case APIC_DM_SMI:
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 9e9285a..6e2d2c8 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -132,8 +132,8 @@
 	(PAGE_MASK & ~((1ULL << (PAGE_SHIFT + (((level) - 1) \
 					    * PT32_LEVEL_BITS))) - 1))
 
-#define PT64_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK \
-			| PT64_NX_MASK)
+#define PT64_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | shadow_user_mask \
+			| shadow_x_mask | shadow_nx_mask)
 
 #define ACC_EXEC_MASK    1
 #define ACC_WRITE_MASK   PT_WRITABLE_MASK
@@ -331,11 +331,6 @@
 	return pte & PT_PAGE_SIZE_MASK;
 }
 
-static int is_dirty_gpte(unsigned long pte)
-{
-	return pte & PT_DIRTY_MASK;
-}
-
 static int is_rmap_spte(u64 pte)
 {
 	return is_shadow_present_pte(pte);
@@ -2052,12 +2047,18 @@
 	return __shadow_walk_next(iterator, *iterator->sptep);
 }
 
-static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp)
+static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp, bool accessed)
 {
 	u64 spte;
 
+	BUILD_BUG_ON(VMX_EPT_READABLE_MASK != PT_PRESENT_MASK ||
+			VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
+
 	spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK |
-	       shadow_user_mask | shadow_x_mask | shadow_accessed_mask;
+	       shadow_user_mask | shadow_x_mask;
+
+	if (accessed)
+		spte |= shadow_accessed_mask;
 
 	mmu_spte_set(sptep, spte);
 }
@@ -2574,14 +2575,6 @@
 	mmu_free_roots(vcpu);
 }
 
-static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level)
-{
-	int bit7;
-
-	bit7 = (gpte >> 7) & 1;
-	return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0;
-}
-
 static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
 				     bool no_dirty_log)
 {
@@ -2594,26 +2587,6 @@
 	return gfn_to_pfn_memslot_atomic(slot, gfn);
 }
 
-static bool prefetch_invalid_gpte(struct kvm_vcpu *vcpu,
-				  struct kvm_mmu_page *sp, u64 *spte,
-				  u64 gpte)
-{
-	if (is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL))
-		goto no_present;
-
-	if (!is_present_gpte(gpte))
-		goto no_present;
-
-	if (!(gpte & PT_ACCESSED_MASK))
-		goto no_present;
-
-	return false;
-
-no_present:
-	drop_spte(vcpu->kvm, spte);
-	return true;
-}
-
 static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
 				    struct kvm_mmu_page *sp,
 				    u64 *start, u64 *end)
@@ -2710,7 +2683,7 @@
 					      iterator.level - 1,
 					      1, ACC_ALL, iterator.sptep);
 
-			link_shadow_page(iterator.sptep, sp);
+			link_shadow_page(iterator.sptep, sp, true);
 		}
 	}
 	return emulate;
@@ -2808,7 +2781,7 @@
 	return ret;
 }
 
-static bool page_fault_can_be_fast(struct kvm_vcpu *vcpu, u32 error_code)
+static bool page_fault_can_be_fast(u32 error_code)
 {
 	/*
 	 * Do not fix the mmio spte with invalid generation number which
@@ -2861,7 +2834,7 @@
 	bool ret = false;
 	u64 spte = 0ull;
 
-	if (!page_fault_can_be_fast(vcpu, error_code))
+	if (!page_fault_can_be_fast(error_code))
 		return false;
 
 	walk_shadow_page_lockless_begin(vcpu);
@@ -3209,6 +3182,7 @@
 	mmu_sync_roots(vcpu);
 	spin_unlock(&vcpu->kvm->mmu_lock);
 }
+EXPORT_SYMBOL_GPL(kvm_mmu_sync_roots);
 
 static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr,
 				  u32 access, struct x86_exception *exception)
@@ -3478,6 +3452,7 @@
 	++vcpu->stat.tlb_flush;
 	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
 }
+EXPORT_SYMBOL_GPL(kvm_mmu_flush_tlb);
 
 static void paging_new_cr3(struct kvm_vcpu *vcpu)
 {
@@ -3501,18 +3476,6 @@
 	nonpaging_free(vcpu);
 }
 
-static inline void protect_clean_gpte(unsigned *access, unsigned gpte)
-{
-	unsigned mask;
-
-	BUILD_BUG_ON(PT_WRITABLE_MASK != ACC_WRITE_MASK);
-
-	mask = (unsigned)~ACC_WRITE_MASK;
-	/* Allow write access to dirty gptes */
-	mask |= (gpte >> (PT_DIRTY_SHIFT - PT_WRITABLE_SHIFT)) & PT_WRITABLE_MASK;
-	*access &= mask;
-}
-
 static bool sync_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
 			   unsigned access, int *nr_present)
 {
@@ -3530,16 +3493,6 @@
 	return false;
 }
 
-static inline unsigned gpte_access(struct kvm_vcpu *vcpu, u64 gpte)
-{
-	unsigned access;
-
-	access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
-	access &= ~(gpte >> PT64_NX_SHIFT);
-
-	return access;
-}
-
 static inline bool is_last_gpte(struct kvm_mmu *mmu, unsigned level, unsigned gpte)
 {
 	unsigned index;
@@ -3549,6 +3502,11 @@
 	return mmu->last_pte_bitmap & (1 << index);
 }
 
+#define PTTYPE_EPT 18 /* arbitrary */
+#define PTTYPE PTTYPE_EPT
+#include "paging_tmpl.h"
+#undef PTTYPE
+
 #define PTTYPE 64
 #include "paging_tmpl.h"
 #undef PTTYPE
@@ -3563,6 +3521,8 @@
 	int maxphyaddr = cpuid_maxphyaddr(vcpu);
 	u64 exb_bit_rsvd = 0;
 
+	context->bad_mt_xwr = 0;
+
 	if (!context->nx)
 		exb_bit_rsvd = rsvd_bits(63, 63);
 	switch (context->root_level) {
@@ -3618,7 +3578,40 @@
 	}
 }
 
-static void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu)
+static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu,
+		struct kvm_mmu *context, bool execonly)
+{
+	int maxphyaddr = cpuid_maxphyaddr(vcpu);
+	int pte;
+
+	context->rsvd_bits_mask[0][3] =
+		rsvd_bits(maxphyaddr, 51) | rsvd_bits(3, 7);
+	context->rsvd_bits_mask[0][2] =
+		rsvd_bits(maxphyaddr, 51) | rsvd_bits(3, 6);
+	context->rsvd_bits_mask[0][1] =
+		rsvd_bits(maxphyaddr, 51) | rsvd_bits(3, 6);
+	context->rsvd_bits_mask[0][0] = rsvd_bits(maxphyaddr, 51);
+
+	/* large page */
+	context->rsvd_bits_mask[1][3] = context->rsvd_bits_mask[0][3];
+	context->rsvd_bits_mask[1][2] =
+		rsvd_bits(maxphyaddr, 51) | rsvd_bits(12, 29);
+	context->rsvd_bits_mask[1][1] =
+		rsvd_bits(maxphyaddr, 51) | rsvd_bits(12, 20);
+	context->rsvd_bits_mask[1][0] = context->rsvd_bits_mask[0][0];
+
+	for (pte = 0; pte < 64; pte++) {
+		int rwx_bits = pte & 7;
+		int mt = pte >> 3;
+		if (mt == 0x2 || mt == 0x3 || mt == 0x7 ||
+				rwx_bits == 0x2 || rwx_bits == 0x6 ||
+				(rwx_bits == 0x4 && !execonly))
+			context->bad_mt_xwr |= (1ull << pte);
+	}
+}
+
+static void update_permission_bitmask(struct kvm_vcpu *vcpu,
+		struct kvm_mmu *mmu, bool ept)
 {
 	unsigned bit, byte, pfec;
 	u8 map;
@@ -3636,12 +3629,16 @@
 			w = bit & ACC_WRITE_MASK;
 			u = bit & ACC_USER_MASK;
 
-			/* Not really needed: !nx will cause pte.nx to fault */
-			x |= !mmu->nx;
-			/* Allow supervisor writes if !cr0.wp */
-			w |= !is_write_protection(vcpu) && !uf;
-			/* Disallow supervisor fetches of user code if cr4.smep */
-			x &= !(smep && u && !uf);
+			if (!ept) {
+				/* Not really needed: !nx will cause pte.nx to fault */
+				x |= !mmu->nx;
+				/* Allow supervisor writes if !cr0.wp */
+				w |= !is_write_protection(vcpu) && !uf;
+				/* Disallow supervisor fetches of user code if cr4.smep */
+				x &= !(smep && u && !uf);
+			} else
+				/* Not really needed: no U/S accesses on ept  */
+				u = 1;
 
 			fault = (ff && !x) || (uf && !u) || (wf && !w);
 			map |= fault << bit;
@@ -3676,7 +3673,7 @@
 	context->root_level = level;
 
 	reset_rsvds_bits_mask(vcpu, context);
-	update_permission_bitmask(vcpu, context);
+	update_permission_bitmask(vcpu, context, false);
 	update_last_pte_bitmap(vcpu, context);
 
 	ASSERT(is_pae(vcpu));
@@ -3706,7 +3703,7 @@
 	context->root_level = PT32_ROOT_LEVEL;
 
 	reset_rsvds_bits_mask(vcpu, context);
-	update_permission_bitmask(vcpu, context);
+	update_permission_bitmask(vcpu, context, false);
 	update_last_pte_bitmap(vcpu, context);
 
 	context->new_cr3 = paging_new_cr3;
@@ -3768,7 +3765,7 @@
 		context->gva_to_gpa = paging32_gva_to_gpa;
 	}
 
-	update_permission_bitmask(vcpu, context);
+	update_permission_bitmask(vcpu, context, false);
 	update_last_pte_bitmap(vcpu, context);
 
 	return 0;
@@ -3800,6 +3797,33 @@
 }
 EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu);
 
+int kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context,
+		bool execonly)
+{
+	ASSERT(vcpu);
+	ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa));
+
+	context->shadow_root_level = kvm_x86_ops->get_tdp_level();
+
+	context->nx = true;
+	context->new_cr3 = paging_new_cr3;
+	context->page_fault = ept_page_fault;
+	context->gva_to_gpa = ept_gva_to_gpa;
+	context->sync_page = ept_sync_page;
+	context->invlpg = ept_invlpg;
+	context->update_pte = ept_update_pte;
+	context->free = paging_free;
+	context->root_level = context->shadow_root_level;
+	context->root_hpa = INVALID_PAGE;
+	context->direct_map = false;
+
+	update_permission_bitmask(vcpu, context, true);
+	reset_rsvds_bits_mask_ept(vcpu, context, execonly);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_init_shadow_ept_mmu);
+
 static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
 {
 	int r = kvm_init_shadow_mmu(vcpu, vcpu->arch.walk_mmu);
@@ -3847,7 +3871,7 @@
 		g_context->gva_to_gpa = paging32_gva_to_gpa_nested;
 	}
 
-	update_permission_bitmask(vcpu, g_context);
+	update_permission_bitmask(vcpu, g_context, false);
 	update_last_pte_bitmap(vcpu, g_context);
 
 	return 0;
@@ -3923,8 +3947,8 @@
 		return true;
 	if ((old ^ new) & PT64_BASE_ADDR_MASK)
 		return true;
-	old ^= PT64_NX_MASK;
-	new ^= PT64_NX_MASK;
+	old ^= shadow_nx_mask;
+	new ^= shadow_nx_mask;
 	return (old & ~new & PT64_PERM_MASK) != 0;
 }
 
@@ -4182,7 +4206,7 @@
 	switch (er) {
 	case EMULATE_DONE:
 		return 1;
-	case EMULATE_DO_MMIO:
+	case EMULATE_USER_EXIT:
 		++vcpu->stat.mmio_exits;
 		/* fall through */
 	case EMULATE_FAIL:
@@ -4390,11 +4414,8 @@
 	/*
 	 * The very rare case: if the generation-number is round,
 	 * zap all shadow pages.
-	 *
-	 * The max value is MMIO_MAX_GEN - 1 since it is not called
-	 * when mark memslot invalid.
 	 */
-	if (unlikely(kvm_current_mmio_generation(kvm) >= (MMIO_MAX_GEN - 1))) {
+	if (unlikely(kvm_current_mmio_generation(kvm) >= MMIO_MAX_GEN)) {
 		printk_ratelimited(KERN_INFO "kvm: zapping shadow pages for mmio generation wraparound\n");
 		kvm_mmu_invalidate_zap_all_pages(kvm);
 	}
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 5b59c57..77e044a 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -71,6 +71,8 @@
 
 int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
 int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
+int kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context,
+		bool execonly);
 
 static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
 {
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 7769699..0433301 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -23,6 +23,13 @@
  * so the code in this file is compiled twice, once per pte size.
  */
 
+/*
+ * This is used to catch non optimized PT_GUEST_(DIRTY|ACCESS)_SHIFT macro
+ * uses for EPT without A/D paging type.
+ */
+extern u64 __pure __using_nonexistent_pte_bit(void)
+	       __compiletime_error("wrong use of PT_GUEST_(DIRTY|ACCESS)_SHIFT");
+
 #if PTTYPE == 64
 	#define pt_element_t u64
 	#define guest_walker guest_walker64
@@ -32,6 +39,10 @@
 	#define PT_LVL_OFFSET_MASK(lvl) PT64_LVL_OFFSET_MASK(lvl)
 	#define PT_INDEX(addr, level) PT64_INDEX(addr, level)
 	#define PT_LEVEL_BITS PT64_LEVEL_BITS
+	#define PT_GUEST_ACCESSED_MASK PT_ACCESSED_MASK
+	#define PT_GUEST_DIRTY_MASK PT_DIRTY_MASK
+	#define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT
+	#define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT
 	#ifdef CONFIG_X86_64
 	#define PT_MAX_FULL_LEVELS 4
 	#define CMPXCHG cmpxchg
@@ -49,7 +60,26 @@
 	#define PT_INDEX(addr, level) PT32_INDEX(addr, level)
 	#define PT_LEVEL_BITS PT32_LEVEL_BITS
 	#define PT_MAX_FULL_LEVELS 2
+	#define PT_GUEST_ACCESSED_MASK PT_ACCESSED_MASK
+	#define PT_GUEST_DIRTY_MASK PT_DIRTY_MASK
+	#define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT
+	#define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT
 	#define CMPXCHG cmpxchg
+#elif PTTYPE == PTTYPE_EPT
+	#define pt_element_t u64
+	#define guest_walker guest_walkerEPT
+	#define FNAME(name) ept_##name
+	#define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK
+	#define PT_LVL_ADDR_MASK(lvl) PT64_LVL_ADDR_MASK(lvl)
+	#define PT_LVL_OFFSET_MASK(lvl) PT64_LVL_OFFSET_MASK(lvl)
+	#define PT_INDEX(addr, level) PT64_INDEX(addr, level)
+	#define PT_LEVEL_BITS PT64_LEVEL_BITS
+	#define PT_GUEST_ACCESSED_MASK 0
+	#define PT_GUEST_DIRTY_MASK 0
+	#define PT_GUEST_DIRTY_SHIFT __using_nonexistent_pte_bit()
+	#define PT_GUEST_ACCESSED_SHIFT __using_nonexistent_pte_bit()
+	#define CMPXCHG cmpxchg64
+	#define PT_MAX_FULL_LEVELS 4
 #else
 	#error Invalid PTTYPE value
 #endif
@@ -80,6 +110,40 @@
 	return (gpte & PT_LVL_ADDR_MASK(lvl)) >> PAGE_SHIFT;
 }
 
+static inline void FNAME(protect_clean_gpte)(unsigned *access, unsigned gpte)
+{
+	unsigned mask;
+
+	/* dirty bit is not supported, so no need to track it */
+	if (!PT_GUEST_DIRTY_MASK)
+		return;
+
+	BUILD_BUG_ON(PT_WRITABLE_MASK != ACC_WRITE_MASK);
+
+	mask = (unsigned)~ACC_WRITE_MASK;
+	/* Allow write access to dirty gptes */
+	mask |= (gpte >> (PT_GUEST_DIRTY_SHIFT - PT_WRITABLE_SHIFT)) &
+		PT_WRITABLE_MASK;
+	*access &= mask;
+}
+
+static bool FNAME(is_rsvd_bits_set)(struct kvm_mmu *mmu, u64 gpte, int level)
+{
+	int bit7 = (gpte >> 7) & 1, low6 = gpte & 0x3f;
+
+	return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) |
+		((mmu->bad_mt_xwr & (1ull << low6)) != 0);
+}
+
+static inline int FNAME(is_present_gpte)(unsigned long pte)
+{
+#if PTTYPE != PTTYPE_EPT
+	return is_present_gpte(pte);
+#else
+	return pte & 7;
+#endif
+}
+
 static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
 			       pt_element_t __user *ptep_user, unsigned index,
 			       pt_element_t orig_pte, pt_element_t new_pte)
@@ -103,6 +167,42 @@
 	return (ret != orig_pte);
 }
 
+static bool FNAME(prefetch_invalid_gpte)(struct kvm_vcpu *vcpu,
+				  struct kvm_mmu_page *sp, u64 *spte,
+				  u64 gpte)
+{
+	if (FNAME(is_rsvd_bits_set)(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL))
+		goto no_present;
+
+	if (!FNAME(is_present_gpte)(gpte))
+		goto no_present;
+
+	/* if accessed bit is not supported prefetch non accessed gpte */
+	if (PT_GUEST_ACCESSED_MASK && !(gpte & PT_GUEST_ACCESSED_MASK))
+		goto no_present;
+
+	return false;
+
+no_present:
+	drop_spte(vcpu->kvm, spte);
+	return true;
+}
+
+static inline unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, u64 gpte)
+{
+	unsigned access;
+#if PTTYPE == PTTYPE_EPT
+	access = ((gpte & VMX_EPT_WRITABLE_MASK) ? ACC_WRITE_MASK : 0) |
+		((gpte & VMX_EPT_EXECUTABLE_MASK) ? ACC_EXEC_MASK : 0) |
+		ACC_USER_MASK;
+#else
+	access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
+	access &= ~(gpte >> PT64_NX_SHIFT);
+#endif
+
+	return access;
+}
+
 static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
 					     struct kvm_mmu *mmu,
 					     struct guest_walker *walker,
@@ -114,18 +214,23 @@
 	gfn_t table_gfn;
 	int ret;
 
+	/* dirty/accessed bits are not supported, so no need to update them */
+	if (!PT_GUEST_DIRTY_MASK)
+		return 0;
+
 	for (level = walker->max_level; level >= walker->level; --level) {
 		pte = orig_pte = walker->ptes[level - 1];
 		table_gfn = walker->table_gfn[level - 1];
 		ptep_user = walker->ptep_user[level - 1];
 		index = offset_in_page(ptep_user) / sizeof(pt_element_t);
-		if (!(pte & PT_ACCESSED_MASK)) {
+		if (!(pte & PT_GUEST_ACCESSED_MASK)) {
 			trace_kvm_mmu_set_accessed_bit(table_gfn, index, sizeof(pte));
-			pte |= PT_ACCESSED_MASK;
+			pte |= PT_GUEST_ACCESSED_MASK;
 		}
-		if (level == walker->level && write_fault && !is_dirty_gpte(pte)) {
+		if (level == walker->level && write_fault &&
+				!(pte & PT_GUEST_DIRTY_MASK)) {
 			trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
-			pte |= PT_DIRTY_MASK;
+			pte |= PT_GUEST_DIRTY_MASK;
 		}
 		if (pte == orig_pte)
 			continue;
@@ -170,7 +275,7 @@
 	if (walker->level == PT32E_ROOT_LEVEL) {
 		pte = mmu->get_pdptr(vcpu, (addr >> 30) & 3);
 		trace_kvm_mmu_paging_element(pte, walker->level);
-		if (!is_present_gpte(pte))
+		if (!FNAME(is_present_gpte)(pte))
 			goto error;
 		--walker->level;
 	}
@@ -179,7 +284,7 @@
 	ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
 	       (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0);
 
-	accessed_dirty = PT_ACCESSED_MASK;
+	accessed_dirty = PT_GUEST_ACCESSED_MASK;
 	pt_access = pte_access = ACC_ALL;
 	++walker->level;
 
@@ -215,17 +320,17 @@
 
 		trace_kvm_mmu_paging_element(pte, walker->level);
 
-		if (unlikely(!is_present_gpte(pte)))
+		if (unlikely(!FNAME(is_present_gpte)(pte)))
 			goto error;
 
-		if (unlikely(is_rsvd_bits_set(&vcpu->arch.mmu, pte,
-					      walker->level))) {
+		if (unlikely(FNAME(is_rsvd_bits_set)(mmu, pte,
+					             walker->level))) {
 			errcode |= PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
 			goto error;
 		}
 
 		accessed_dirty &= pte;
-		pte_access = pt_access & gpte_access(vcpu, pte);
+		pte_access = pt_access & FNAME(gpte_access)(vcpu, pte);
 
 		walker->ptes[walker->level - 1] = pte;
 	} while (!is_last_gpte(mmu, walker->level, pte));
@@ -248,13 +353,15 @@
 	walker->gfn = real_gpa >> PAGE_SHIFT;
 
 	if (!write_fault)
-		protect_clean_gpte(&pte_access, pte);
+		FNAME(protect_clean_gpte)(&pte_access, pte);
 	else
 		/*
-		 * On a write fault, fold the dirty bit into accessed_dirty by
-		 * shifting it one place right.
+		 * On a write fault, fold the dirty bit into accessed_dirty.
+		 * For modes without A/D bits support accessed_dirty will be
+		 * always clear.
 		 */
-		accessed_dirty &= pte >> (PT_DIRTY_SHIFT - PT_ACCESSED_SHIFT);
+		accessed_dirty &= pte >>
+			(PT_GUEST_DIRTY_SHIFT - PT_GUEST_ACCESSED_SHIFT);
 
 	if (unlikely(!accessed_dirty)) {
 		ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault);
@@ -279,6 +386,25 @@
 	walker->fault.vector = PF_VECTOR;
 	walker->fault.error_code_valid = true;
 	walker->fault.error_code = errcode;
+
+#if PTTYPE == PTTYPE_EPT
+	/*
+	 * Use PFERR_RSVD_MASK in error_code to to tell if EPT
+	 * misconfiguration requires to be injected. The detection is
+	 * done by is_rsvd_bits_set() above.
+	 *
+	 * We set up the value of exit_qualification to inject:
+	 * [2:0] - Derive from [2:0] of real exit_qualification at EPT violation
+	 * [5:3] - Calculated by the page walk of the guest EPT page tables
+	 * [7:8] - Derived from [7:8] of real exit_qualification
+	 *
+	 * The other bits are set to 0.
+	 */
+	if (!(errcode & PFERR_RSVD_MASK)) {
+		vcpu->arch.exit_qualification &= 0x187;
+		vcpu->arch.exit_qualification |= ((pt_access & pte) & 0x7) << 3;
+	}
+#endif
 	walker->fault.address = addr;
 	walker->fault.nested_page_fault = mmu != vcpu->arch.walk_mmu;
 
@@ -293,6 +419,7 @@
 					access);
 }
 
+#if PTTYPE != PTTYPE_EPT
 static int FNAME(walk_addr_nested)(struct guest_walker *walker,
 				   struct kvm_vcpu *vcpu, gva_t addr,
 				   u32 access)
@@ -300,6 +427,7 @@
 	return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.nested_mmu,
 					addr, access);
 }
+#endif
 
 static bool
 FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
@@ -309,14 +437,14 @@
 	gfn_t gfn;
 	pfn_t pfn;
 
-	if (prefetch_invalid_gpte(vcpu, sp, spte, gpte))
+	if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte))
 		return false;
 
 	pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
 
 	gfn = gpte_to_gfn(gpte);
-	pte_access = sp->role.access & gpte_access(vcpu, gpte);
-	protect_clean_gpte(&pte_access, gpte);
+	pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+	FNAME(protect_clean_gpte)(&pte_access, gpte);
 	pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
 			no_dirty_log && (pte_access & ACC_WRITE_MASK));
 	if (is_error_pfn(pfn))
@@ -446,7 +574,7 @@
 			goto out_gpte_changed;
 
 		if (sp)
-			link_shadow_page(it.sptep, sp);
+			link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
 	}
 
 	for (;
@@ -466,7 +594,7 @@
 
 		sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
 				      true, direct_access, it.sptep);
-		link_shadow_page(it.sptep, sp);
+		link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
 	}
 
 	clear_sp_write_flooding_count(it.sptep);
@@ -727,6 +855,7 @@
 	return gpa;
 }
 
+#if PTTYPE != PTTYPE_EPT
 static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,
 				      u32 access,
 				      struct x86_exception *exception)
@@ -745,6 +874,7 @@
 
 	return gpa;
 }
+#endif
 
 /*
  * Using the cached information from sp->gfns is safe because:
@@ -785,15 +915,15 @@
 					  sizeof(pt_element_t)))
 			return -EINVAL;
 
-		if (prefetch_invalid_gpte(vcpu, sp, &sp->spt[i], gpte)) {
+		if (FNAME(prefetch_invalid_gpte)(vcpu, sp, &sp->spt[i], gpte)) {
 			vcpu->kvm->tlbs_dirty++;
 			continue;
 		}
 
 		gfn = gpte_to_gfn(gpte);
 		pte_access = sp->role.access;
-		pte_access &= gpte_access(vcpu, gpte);
-		protect_clean_gpte(&pte_access, gpte);
+		pte_access &= FNAME(gpte_access)(vcpu, gpte);
+		FNAME(protect_clean_gpte)(&pte_access, gpte);
 
 		if (sync_mmio_spte(vcpu->kvm, &sp->spt[i], gfn, pte_access,
 		      &nr_present))
@@ -830,3 +960,7 @@
 #undef gpte_to_gfn
 #undef gpte_to_gfn_lvl
 #undef CMPXCHG
+#undef PT_GUEST_ACCESSED_MASK
+#undef PT_GUEST_DIRTY_MASK
+#undef PT_GUEST_DIRTY_SHIFT
+#undef PT_GUEST_ACCESSED_SHIFT
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index c53e797..5c4f631 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -160,7 +160,7 @@
 
 static void reprogram_counter(struct kvm_pmc *pmc, u32 type,
 		unsigned config, bool exclude_user, bool exclude_kernel,
-		bool intr)
+		bool intr, bool in_tx, bool in_tx_cp)
 {
 	struct perf_event *event;
 	struct perf_event_attr attr = {
@@ -173,6 +173,10 @@
 		.exclude_kernel = exclude_kernel,
 		.config = config,
 	};
+	if (in_tx)
+		attr.config |= HSW_IN_TX;
+	if (in_tx_cp)
+		attr.config |= HSW_IN_TX_CHECKPOINTED;
 
 	attr.sample_period = (-pmc->counter) & pmc_bitmask(pmc);
 
@@ -226,7 +230,9 @@
 
 	if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE |
 				ARCH_PERFMON_EVENTSEL_INV |
-				ARCH_PERFMON_EVENTSEL_CMASK))) {
+				ARCH_PERFMON_EVENTSEL_CMASK |
+				HSW_IN_TX |
+				HSW_IN_TX_CHECKPOINTED))) {
 		config = find_arch_event(&pmc->vcpu->arch.pmu, event_select,
 				unit_mask);
 		if (config != PERF_COUNT_HW_MAX)
@@ -239,7 +245,9 @@
 	reprogram_counter(pmc, type, config,
 			!(eventsel & ARCH_PERFMON_EVENTSEL_USR),
 			!(eventsel & ARCH_PERFMON_EVENTSEL_OS),
-			eventsel & ARCH_PERFMON_EVENTSEL_INT);
+			eventsel & ARCH_PERFMON_EVENTSEL_INT,
+			(eventsel & HSW_IN_TX),
+			(eventsel & HSW_IN_TX_CHECKPOINTED));
 }
 
 static void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 en_pmi, int idx)
@@ -256,7 +264,7 @@
 			arch_events[fixed_pmc_events[idx]].event_type,
 			!(en & 0x2), /* exclude user */
 			!(en & 0x1), /* exclude kernel */
-			pmi);
+			pmi, false, false);
 }
 
 static inline u8 fixed_en_pmi(u64 ctrl, int idx)
@@ -408,7 +416,7 @@
 		} else if ((pmc = get_gp_pmc(pmu, index, MSR_P6_EVNTSEL0))) {
 			if (data == pmc->eventsel)
 				return 0;
-			if (!(data & 0xffffffff00200000ull)) {
+			if (!(data & pmu->reserved_bits)) {
 				reprogram_gp_counter(pmc, data);
 				return 0;
 			}
@@ -450,6 +458,7 @@
 	pmu->counter_bitmask[KVM_PMC_GP] = 0;
 	pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
 	pmu->version = 0;
+	pmu->reserved_bits = 0xffffffff00200000ull;
 
 	entry = kvm_find_cpuid_entry(vcpu, 0xa, 0);
 	if (!entry)
@@ -478,6 +487,12 @@
 	pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
 		(((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED);
 	pmu->global_ctrl_mask = ~pmu->global_ctrl;
+
+	entry = kvm_find_cpuid_entry(vcpu, 7, 0);
+	if (entry &&
+	    (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) &&
+	    (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM)))
+		pmu->reserved_bits ^= HSW_IN_TX|HSW_IN_TX_CHECKPOINTED;
 }
 
 void kvm_pmu_init(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 064d0be..1f1da43 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -373,6 +373,7 @@
 	 * we must keep them pinned while L2 runs.
 	 */
 	struct page *apic_access_page;
+	u64 msr_ia32_feature_control;
 };
 
 #define POSTED_INTR_ON  0
@@ -711,10 +712,10 @@
 	kvm_release_page_clean(page);
 }
 
+static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu);
 static u64 construct_eptp(unsigned long root_hpa);
 static void kvm_cpu_vmxon(u64 addr);
 static void kvm_cpu_vmxoff(void);
-static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
 static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
 static void vmx_set_segment(struct kvm_vcpu *vcpu,
 			    struct kvm_segment *var, int seg);
@@ -1039,12 +1040,16 @@
 		(vmcs12->secondary_vm_exec_control & bit);
 }
 
-static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12,
-	struct kvm_vcpu *vcpu)
+static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
 {
 	return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
 }
 
+static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
+{
+	return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
+}
+
 static inline bool is_exception(u32 intr_info)
 {
 	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
@@ -2155,6 +2160,7 @@
 static u32 nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high;
 static u32 nested_vmx_entry_ctls_low, nested_vmx_entry_ctls_high;
 static u32 nested_vmx_misc_low, nested_vmx_misc_high;
+static u32 nested_vmx_ept_caps;
 static __init void nested_vmx_setup_ctls_msrs(void)
 {
 	/*
@@ -2190,14 +2196,17 @@
 	 * If bit 55 of VMX_BASIC is off, bits 0-8 and 10, 11, 13, 14, 16 and
 	 * 17 must be 1.
 	 */
+	rdmsr(MSR_IA32_VMX_EXIT_CTLS,
+		nested_vmx_exit_ctls_low, nested_vmx_exit_ctls_high);
 	nested_vmx_exit_ctls_low = VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR;
 	/* Note that guest use of VM_EXIT_ACK_INTR_ON_EXIT is not supported. */
+	nested_vmx_exit_ctls_high &=
 #ifdef CONFIG_X86_64
-	nested_vmx_exit_ctls_high = VM_EXIT_HOST_ADDR_SPACE_SIZE;
-#else
-	nested_vmx_exit_ctls_high = 0;
+		VM_EXIT_HOST_ADDR_SPACE_SIZE |
 #endif
-	nested_vmx_exit_ctls_high |= VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR;
+		VM_EXIT_LOAD_IA32_PAT | VM_EXIT_SAVE_IA32_PAT;
+	nested_vmx_exit_ctls_high |= (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR |
+				      VM_EXIT_LOAD_IA32_EFER);
 
 	/* entry controls */
 	rdmsr(MSR_IA32_VMX_ENTRY_CTLS,
@@ -2205,8 +2214,12 @@
 	/* If bit 55 of VMX_BASIC is off, bits 0-8 and 12 must be 1. */
 	nested_vmx_entry_ctls_low = VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR;
 	nested_vmx_entry_ctls_high &=
-		VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_IA32E_MODE;
-	nested_vmx_entry_ctls_high |= VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR;
+#ifdef CONFIG_X86_64
+		VM_ENTRY_IA32E_MODE |
+#endif
+		VM_ENTRY_LOAD_IA32_PAT;
+	nested_vmx_entry_ctls_high |= (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR |
+				       VM_ENTRY_LOAD_IA32_EFER);
 
 	/* cpu-based controls */
 	rdmsr(MSR_IA32_VMX_PROCBASED_CTLS,
@@ -2241,6 +2254,22 @@
 		SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES |
 		SECONDARY_EXEC_WBINVD_EXITING;
 
+	if (enable_ept) {
+		/* nested EPT: emulate EPT also to L1 */
+		nested_vmx_secondary_ctls_high |= SECONDARY_EXEC_ENABLE_EPT;
+		nested_vmx_ept_caps = VMX_EPT_PAGE_WALK_4_BIT |
+			 VMX_EPTP_WB_BIT | VMX_EPT_INVEPT_BIT;
+		nested_vmx_ept_caps &= vmx_capability.ept;
+		/*
+		 * Since invept is completely emulated we support both global
+		 * and context invalidation independent of what host cpu
+		 * supports
+		 */
+		nested_vmx_ept_caps |= VMX_EPT_EXTENT_GLOBAL_BIT |
+			VMX_EPT_EXTENT_CONTEXT_BIT;
+	} else
+		nested_vmx_ept_caps = 0;
+
 	/* miscellaneous data */
 	rdmsr(MSR_IA32_VMX_MISC, nested_vmx_misc_low, nested_vmx_misc_high);
 	nested_vmx_misc_low &= VMX_MISC_PREEMPTION_TIMER_RATE_MASK |
@@ -2282,8 +2311,11 @@
 
 	switch (msr_index) {
 	case MSR_IA32_FEATURE_CONTROL:
-		*pdata = 0;
-		break;
+		if (nested_vmx_allowed(vcpu)) {
+			*pdata = to_vmx(vcpu)->nested.msr_ia32_feature_control;
+			break;
+		}
+		return 0;
 	case MSR_IA32_VMX_BASIC:
 		/*
 		 * This MSR reports some information about VMX support. We
@@ -2346,8 +2378,8 @@
 					nested_vmx_secondary_ctls_high);
 		break;
 	case MSR_IA32_VMX_EPT_VPID_CAP:
-		/* Currently, no nested ept or nested vpid */
-		*pdata = 0;
+		/* Currently, no nested vpid support */
+		*pdata = nested_vmx_ept_caps;
 		break;
 	default:
 		return 0;
@@ -2356,14 +2388,24 @@
 	return 1;
 }
 
-static int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+static int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
+	u32 msr_index = msr_info->index;
+	u64 data = msr_info->data;
+	bool host_initialized = msr_info->host_initiated;
+
 	if (!nested_vmx_allowed(vcpu))
 		return 0;
 
-	if (msr_index == MSR_IA32_FEATURE_CONTROL)
-		/* TODO: the right thing. */
+	if (msr_index == MSR_IA32_FEATURE_CONTROL) {
+		if (!host_initialized &&
+				to_vmx(vcpu)->nested.msr_ia32_feature_control
+				& FEATURE_CONTROL_LOCKED)
+			return 0;
+		to_vmx(vcpu)->nested.msr_ia32_feature_control = data;
 		return 1;
+	}
+
 	/*
 	 * No need to treat VMX capability MSRs specially: If we don't handle
 	 * them, handle_wrmsr will #GP(0), which is correct (they are readonly)
@@ -2494,7 +2536,7 @@
 			return 1;
 		/* Otherwise falls through */
 	default:
-		if (vmx_set_vmx_msr(vcpu, msr_index, data))
+		if (vmx_set_vmx_msr(vcpu, msr_info))
 			break;
 		msr = find_msr_entry(vmx, msr_index);
 		if (msr) {
@@ -5302,9 +5344,13 @@
 
 	/* It is a write fault? */
 	error_code = exit_qualification & (1U << 1);
+	/* It is a fetch fault? */
+	error_code |= (exit_qualification & (1U << 2)) << 2;
 	/* ept page table is present? */
 	error_code |= (exit_qualification >> 3) & 0x1;
 
+	vcpu->arch.exit_qualification = exit_qualification;
+
 	return kvm_mmu_page_fault(vcpu, gpa, error_code, NULL, 0);
 }
 
@@ -5438,7 +5484,8 @@
 
 		err = emulate_instruction(vcpu, EMULTYPE_NO_REEXECUTE);
 
-		if (err == EMULATE_DO_MMIO) {
+		if (err == EMULATE_USER_EXIT) {
+			++vcpu->stat.mmio_exits;
 			ret = 0;
 			goto out;
 		}
@@ -5567,8 +5614,47 @@
 		free_loaded_vmcs(&vmx->vmcs01);
 }
 
+/*
+ * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
+ * set the success or error code of an emulated VMX instruction, as specified
+ * by Vol 2B, VMX Instruction Reference, "Conventions".
+ */
+static void nested_vmx_succeed(struct kvm_vcpu *vcpu)
+{
+	vmx_set_rflags(vcpu, vmx_get_rflags(vcpu)
+			& ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
+			    X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF));
+}
+
+static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu)
+{
+	vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
+			& ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF |
+			    X86_EFLAGS_SF | X86_EFLAGS_OF))
+			| X86_EFLAGS_CF);
+}
+
 static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
-				 u32 vm_instruction_error);
+					u32 vm_instruction_error)
+{
+	if (to_vmx(vcpu)->nested.current_vmptr == -1ull) {
+		/*
+		 * failValid writes the error number to the current VMCS, which
+		 * can't be done there isn't a current VMCS.
+		 */
+		nested_vmx_failInvalid(vcpu);
+		return;
+	}
+	vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
+			& ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
+			    X86_EFLAGS_SF | X86_EFLAGS_OF))
+			| X86_EFLAGS_ZF);
+	get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error;
+	/*
+	 * We don't need to force a shadow sync because
+	 * VM_INSTRUCTION_ERROR is not shadowed
+	 */
+}
 
 /*
  * Emulate the VMXON instruction.
@@ -5583,6 +5669,8 @@
 	struct kvm_segment cs;
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	struct vmcs *shadow_vmcs;
+	const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
+		| FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
 
 	/* The Intel VMX Instruction Reference lists a bunch of bits that
 	 * are prerequisite to running VMXON, most notably cr4.VMXE must be
@@ -5611,6 +5699,13 @@
 		skip_emulated_instruction(vcpu);
 		return 1;
 	}
+
+	if ((vmx->nested.msr_ia32_feature_control & VMXON_NEEDED_FEATURES)
+			!= VMXON_NEEDED_FEATURES) {
+		kvm_inject_gp(vcpu, 0);
+		return 1;
+	}
+
 	if (enable_shadow_vmcs) {
 		shadow_vmcs = alloc_vmcs();
 		if (!shadow_vmcs)
@@ -5628,6 +5723,7 @@
 	vmx->nested.vmxon = true;
 
 	skip_emulated_instruction(vcpu);
+	nested_vmx_succeed(vcpu);
 	return 1;
 }
 
@@ -5712,6 +5808,7 @@
 		return 1;
 	free_nested(to_vmx(vcpu));
 	skip_emulated_instruction(vcpu);
+	nested_vmx_succeed(vcpu);
 	return 1;
 }
 
@@ -5768,48 +5865,6 @@
 	return 0;
 }
 
-/*
- * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
- * set the success or error code of an emulated VMX instruction, as specified
- * by Vol 2B, VMX Instruction Reference, "Conventions".
- */
-static void nested_vmx_succeed(struct kvm_vcpu *vcpu)
-{
-	vmx_set_rflags(vcpu, vmx_get_rflags(vcpu)
-			& ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
-			    X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF));
-}
-
-static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu)
-{
-	vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
-			& ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF |
-			    X86_EFLAGS_SF | X86_EFLAGS_OF))
-			| X86_EFLAGS_CF);
-}
-
-static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
-					u32 vm_instruction_error)
-{
-	if (to_vmx(vcpu)->nested.current_vmptr == -1ull) {
-		/*
-		 * failValid writes the error number to the current VMCS, which
-		 * can't be done there isn't a current VMCS.
-		 */
-		nested_vmx_failInvalid(vcpu);
-		return;
-	}
-	vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
-			& ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
-			    X86_EFLAGS_SF | X86_EFLAGS_OF))
-			| X86_EFLAGS_ZF);
-	get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error;
-	/*
-	 * We don't need to force a shadow sync because
-	 * VM_INSTRUCTION_ERROR is not shadowed
-	 */
-}
-
 /* Emulate the VMCLEAR instruction */
 static int handle_vmclear(struct kvm_vcpu *vcpu)
 {
@@ -5972,8 +6027,8 @@
 	unsigned long field;
 	u64 field_value;
 	struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
-	unsigned long *fields = (unsigned long *)shadow_read_write_fields;
-	int num_fields = max_shadow_read_write_fields;
+	const unsigned long *fields = shadow_read_write_fields;
+	const int num_fields = max_shadow_read_write_fields;
 
 	vmcs_load(shadow_vmcs);
 
@@ -6002,12 +6057,11 @@
 
 static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
 {
-	unsigned long *fields[] = {
-		(unsigned long *)shadow_read_write_fields,
-		(unsigned long *)shadow_read_only_fields
+	const unsigned long *fields[] = {
+		shadow_read_write_fields,
+		shadow_read_only_fields
 	};
-	int num_lists =  ARRAY_SIZE(fields);
-	int max_fields[] = {
+	const int max_fields[] = {
 		max_shadow_read_write_fields,
 		max_shadow_read_only_fields
 	};
@@ -6018,7 +6072,7 @@
 
 	vmcs_load(shadow_vmcs);
 
-	for (q = 0; q < num_lists; q++) {
+	for (q = 0; q < ARRAY_SIZE(fields); q++) {
 		for (i = 0; i < max_fields[q]; i++) {
 			field = fields[q][i];
 			vmcs12_read_any(&vmx->vcpu, field, &field_value);
@@ -6248,6 +6302,74 @@
 	return 1;
 }
 
+/* Emulate the INVEPT instruction */
+static int handle_invept(struct kvm_vcpu *vcpu)
+{
+	u32 vmx_instruction_info, types;
+	unsigned long type;
+	gva_t gva;
+	struct x86_exception e;
+	struct {
+		u64 eptp, gpa;
+	} operand;
+	u64 eptp_mask = ((1ull << 51) - 1) & PAGE_MASK;
+
+	if (!(nested_vmx_secondary_ctls_high & SECONDARY_EXEC_ENABLE_EPT) ||
+	    !(nested_vmx_ept_caps & VMX_EPT_INVEPT_BIT)) {
+		kvm_queue_exception(vcpu, UD_VECTOR);
+		return 1;
+	}
+
+	if (!nested_vmx_check_permission(vcpu))
+		return 1;
+
+	if (!kvm_read_cr0_bits(vcpu, X86_CR0_PE)) {
+		kvm_queue_exception(vcpu, UD_VECTOR);
+		return 1;
+	}
+
+	vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+	type = kvm_register_read(vcpu, (vmx_instruction_info >> 28) & 0xf);
+
+	types = (nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6;
+
+	if (!(types & (1UL << type))) {
+		nested_vmx_failValid(vcpu,
+				VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+		return 1;
+	}
+
+	/* According to the Intel VMX instruction reference, the memory
+	 * operand is read even if it isn't needed (e.g., for type==global)
+	 */
+	if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
+			vmx_instruction_info, &gva))
+		return 1;
+	if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &operand,
+				sizeof(operand), &e)) {
+		kvm_inject_page_fault(vcpu, &e);
+		return 1;
+	}
+
+	switch (type) {
+	case VMX_EPT_EXTENT_CONTEXT:
+		if ((operand.eptp & eptp_mask) !=
+				(nested_ept_get_cr3(vcpu) & eptp_mask))
+			break;
+	case VMX_EPT_EXTENT_GLOBAL:
+		kvm_mmu_sync_roots(vcpu);
+		kvm_mmu_flush_tlb(vcpu);
+		nested_vmx_succeed(vcpu);
+		break;
+	default:
+		BUG_ON(1);
+		break;
+	}
+
+	skip_emulated_instruction(vcpu);
+	return 1;
+}
+
 /*
  * The exit handlers return 1 if the exit was handled fully and guest execution
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
@@ -6292,6 +6414,7 @@
 	[EXIT_REASON_PAUSE_INSTRUCTION]       = handle_pause,
 	[EXIT_REASON_MWAIT_INSTRUCTION]	      = handle_invalid_op,
 	[EXIT_REASON_MONITOR_INSTRUCTION]     = handle_invalid_op,
+	[EXIT_REASON_INVEPT]                  = handle_invept,
 };
 
 static const int kvm_vmx_max_exit_handlers =
@@ -6518,6 +6641,7 @@
 	case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD:
 	case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE:
 	case EXIT_REASON_VMOFF: case EXIT_REASON_VMON:
+	case EXIT_REASON_INVEPT:
 		/*
 		 * VMX instructions trap unconditionally. This allows L1 to
 		 * emulate them for its L2 guest, i.e., allows 3-level nesting!
@@ -6550,7 +6674,20 @@
 		return nested_cpu_has2(vmcs12,
 			SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES);
 	case EXIT_REASON_EPT_VIOLATION:
+		/*
+		 * L0 always deals with the EPT violation. If nested EPT is
+		 * used, and the nested mmu code discovers that the address is
+		 * missing in the guest EPT table (EPT12), the EPT violation
+		 * will be injected with nested_ept_inject_page_fault()
+		 */
+		return 0;
 	case EXIT_REASON_EPT_MISCONFIG:
+		/*
+		 * L2 never uses directly L1's EPT, but rather L0's own EPT
+		 * table (shadow on EPT) or a merged EPT table that L0 built
+		 * (EPT on EPT). So any problems with the structure of the
+		 * table is L0's fault.
+		 */
 		return 0;
 	case EXIT_REASON_PREEMPTION_TIMER:
 		return vmcs12->pin_based_vm_exec_control &
@@ -6638,7 +6775,7 @@
 
 	if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked &&
 	    !(is_guest_mode(vcpu) && nested_cpu_has_virtual_nmis(
-	                                get_vmcs12(vcpu), vcpu)))) {
+					get_vmcs12(vcpu))))) {
 		if (vmx_interrupt_allowed(vcpu)) {
 			vmx->soft_vnmi_blocked = 0;
 		} else if (vmx->vnmi_blocked_time > 1000000000LL &&
@@ -7326,6 +7463,48 @@
 		entry->ecx |= bit(X86_FEATURE_VMX);
 }
 
+static void nested_ept_inject_page_fault(struct kvm_vcpu *vcpu,
+		struct x86_exception *fault)
+{
+	struct vmcs12 *vmcs12;
+	nested_vmx_vmexit(vcpu);
+	vmcs12 = get_vmcs12(vcpu);
+
+	if (fault->error_code & PFERR_RSVD_MASK)
+		vmcs12->vm_exit_reason = EXIT_REASON_EPT_MISCONFIG;
+	else
+		vmcs12->vm_exit_reason = EXIT_REASON_EPT_VIOLATION;
+	vmcs12->exit_qualification = vcpu->arch.exit_qualification;
+	vmcs12->guest_physical_address = fault->address;
+}
+
+/* Callbacks for nested_ept_init_mmu_context: */
+
+static unsigned long nested_ept_get_cr3(struct kvm_vcpu *vcpu)
+{
+	/* return the page table to be shadowed - in our case, EPT12 */
+	return get_vmcs12(vcpu)->ept_pointer;
+}
+
+static int nested_ept_init_mmu_context(struct kvm_vcpu *vcpu)
+{
+	int r = kvm_init_shadow_ept_mmu(vcpu, &vcpu->arch.mmu,
+			nested_vmx_ept_caps & VMX_EPT_EXECUTE_ONLY_BIT);
+
+	vcpu->arch.mmu.set_cr3           = vmx_set_cr3;
+	vcpu->arch.mmu.get_cr3           = nested_ept_get_cr3;
+	vcpu->arch.mmu.inject_page_fault = nested_ept_inject_page_fault;
+
+	vcpu->arch.walk_mmu              = &vcpu->arch.nested_mmu;
+
+	return r;
+}
+
+static void nested_ept_uninit_mmu_context(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.walk_mmu = &vcpu->arch.mmu;
+}
+
 /*
  * prepare_vmcs02 is called when the L1 guest hypervisor runs its nested
  * L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it
@@ -7388,7 +7567,7 @@
 		vmcs12->guest_interruptibility_info);
 	vmcs_write32(GUEST_SYSENTER_CS, vmcs12->guest_sysenter_cs);
 	kvm_set_dr(vcpu, 7, vmcs12->guest_dr7);
-	vmcs_writel(GUEST_RFLAGS, vmcs12->guest_rflags);
+	vmx_set_rflags(vcpu, vmcs12->guest_rflags);
 	vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
 		vmcs12->guest_pending_dbg_exceptions);
 	vmcs_writel(GUEST_SYSENTER_ESP, vmcs12->guest_sysenter_esp);
@@ -7508,15 +7687,24 @@
 	vcpu->arch.cr0_guest_owned_bits &= ~vmcs12->cr0_guest_host_mask;
 	vmcs_writel(CR0_GUEST_HOST_MASK, ~vcpu->arch.cr0_guest_owned_bits);
 
-	/* Note: IA32_MODE, LOAD_IA32_EFER are modified by vmx_set_efer below */
-	vmcs_write32(VM_EXIT_CONTROLS,
-		vmcs12->vm_exit_controls | vmcs_config.vmexit_ctrl);
-	vmcs_write32(VM_ENTRY_CONTROLS, vmcs12->vm_entry_controls |
+	/* L2->L1 exit controls are emulated - the hardware exit is to L0 so
+	 * we should use its exit controls. Note that VM_EXIT_LOAD_IA32_EFER
+	 * bits are further modified by vmx_set_efer() below.
+	 */
+	vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
+
+	/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
+	 * emulated by vmx_set_efer(), below.
+	 */
+	vmcs_write32(VM_ENTRY_CONTROLS,
+		(vmcs12->vm_entry_controls & ~VM_ENTRY_LOAD_IA32_EFER &
+			~VM_ENTRY_IA32E_MODE) |
 		(vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE));
 
-	if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT)
+	if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) {
 		vmcs_write64(GUEST_IA32_PAT, vmcs12->guest_ia32_pat);
-	else if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT)
+		vcpu->arch.pat = vmcs12->guest_ia32_pat;
+	} else if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT)
 		vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat);
 
 
@@ -7538,6 +7726,11 @@
 		vmx_flush_tlb(vcpu);
 	}
 
+	if (nested_cpu_has_ept(vmcs12)) {
+		kvm_mmu_unload(vcpu);
+		nested_ept_init_mmu_context(vcpu);
+	}
+
 	if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)
 		vcpu->arch.efer = vmcs12->guest_ia32_efer;
 	else if (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE)
@@ -7565,6 +7758,16 @@
 	kvm_set_cr3(vcpu, vmcs12->guest_cr3);
 	kvm_mmu_reset_context(vcpu);
 
+	/*
+	 * L1 may access the L2's PDPTR, so save them to construct vmcs12
+	 */
+	if (enable_ept) {
+		vmcs_write64(GUEST_PDPTR0, vmcs12->guest_pdptr0);
+		vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1);
+		vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2);
+		vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
+	}
+
 	kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp);
 	kvm_register_write(vcpu, VCPU_REGS_RIP, vmcs12->guest_rip);
 }
@@ -7887,6 +8090,22 @@
 	vmcs12->guest_pending_dbg_exceptions =
 		vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS);
 
+	/*
+	 * In some cases (usually, nested EPT), L2 is allowed to change its
+	 * own CR3 without exiting. If it has changed it, we must keep it.
+	 * Of course, if L0 is using shadow page tables, GUEST_CR3 was defined
+	 * by L0, not L1 or L2, so we mustn't unconditionally copy it to vmcs12.
+	 *
+	 * Additionally, restore L2's PDPTR to vmcs12.
+	 */
+	if (enable_ept) {
+		vmcs12->guest_cr3 = vmcs_read64(GUEST_CR3);
+		vmcs12->guest_pdptr0 = vmcs_read64(GUEST_PDPTR0);
+		vmcs12->guest_pdptr1 = vmcs_read64(GUEST_PDPTR1);
+		vmcs12->guest_pdptr2 = vmcs_read64(GUEST_PDPTR2);
+		vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3);
+	}
+
 	vmcs12->vm_entry_controls =
 		(vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) |
 		(vmcs_read32(VM_ENTRY_CONTROLS) & VM_ENTRY_IA32E_MODE);
@@ -7948,6 +8167,8 @@
 static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
 				   struct vmcs12 *vmcs12)
 {
+	struct kvm_segment seg;
+
 	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_EFER)
 		vcpu->arch.efer = vmcs12->host_ia32_efer;
 	else if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE)
@@ -7982,7 +8203,9 @@
 	vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK);
 	kvm_set_cr4(vcpu, vmcs12->host_cr4);
 
-	/* shadow page tables on either EPT or shadow page tables */
+	if (nested_cpu_has_ept(vmcs12))
+		nested_ept_uninit_mmu_context(vcpu);
+
 	kvm_set_cr3(vcpu, vmcs12->host_cr3);
 	kvm_mmu_reset_context(vcpu);
 
@@ -8001,23 +8224,61 @@
 	vmcs_writel(GUEST_SYSENTER_EIP, vmcs12->host_ia32_sysenter_eip);
 	vmcs_writel(GUEST_IDTR_BASE, vmcs12->host_idtr_base);
 	vmcs_writel(GUEST_GDTR_BASE, vmcs12->host_gdtr_base);
-	vmcs_writel(GUEST_TR_BASE, vmcs12->host_tr_base);
-	vmcs_writel(GUEST_GS_BASE, vmcs12->host_gs_base);
-	vmcs_writel(GUEST_FS_BASE, vmcs12->host_fs_base);
-	vmcs_write16(GUEST_ES_SELECTOR, vmcs12->host_es_selector);
-	vmcs_write16(GUEST_CS_SELECTOR, vmcs12->host_cs_selector);
-	vmcs_write16(GUEST_SS_SELECTOR, vmcs12->host_ss_selector);
-	vmcs_write16(GUEST_DS_SELECTOR, vmcs12->host_ds_selector);
-	vmcs_write16(GUEST_FS_SELECTOR, vmcs12->host_fs_selector);
-	vmcs_write16(GUEST_GS_SELECTOR, vmcs12->host_gs_selector);
-	vmcs_write16(GUEST_TR_SELECTOR, vmcs12->host_tr_selector);
 
-	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT)
+	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) {
 		vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat);
+		vcpu->arch.pat = vmcs12->host_ia32_pat;
+	}
 	if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
 		vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL,
 			vmcs12->host_ia32_perf_global_ctrl);
 
+	/* Set L1 segment info according to Intel SDM
+	    27.5.2 Loading Host Segment and Descriptor-Table Registers */
+	seg = (struct kvm_segment) {
+		.base = 0,
+		.limit = 0xFFFFFFFF,
+		.selector = vmcs12->host_cs_selector,
+		.type = 11,
+		.present = 1,
+		.s = 1,
+		.g = 1
+	};
+	if (vmcs12->vm_exit_controls & VM_EXIT_HOST_ADDR_SPACE_SIZE)
+		seg.l = 1;
+	else
+		seg.db = 1;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_CS);
+	seg = (struct kvm_segment) {
+		.base = 0,
+		.limit = 0xFFFFFFFF,
+		.type = 3,
+		.present = 1,
+		.s = 1,
+		.db = 1,
+		.g = 1
+	};
+	seg.selector = vmcs12->host_ds_selector;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_DS);
+	seg.selector = vmcs12->host_es_selector;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_ES);
+	seg.selector = vmcs12->host_ss_selector;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_SS);
+	seg.selector = vmcs12->host_fs_selector;
+	seg.base = vmcs12->host_fs_base;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_FS);
+	seg.selector = vmcs12->host_gs_selector;
+	seg.base = vmcs12->host_gs_base;
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_GS);
+	seg = (struct kvm_segment) {
+		.base = vmcs12->host_tr_base,
+		.limit = 0x67,
+		.selector = vmcs12->host_tr_selector,
+		.type = 11,
+		.present = 1
+	};
+	vmx_set_segment(vcpu, &seg, VCPU_SREG_TR);
+
 	kvm_set_dr(vcpu, 7, 0x400);
 	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 }
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d21bce5..e5ca72a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -682,17 +682,6 @@
 		 */
 	}
 
-	/*
-	 * Does the new cr3 value map to physical memory? (Note, we
-	 * catch an invalid cr3 even in real-mode, because it would
-	 * cause trouble later on when we turn on paging anyway.)
-	 *
-	 * A real CPU would silently accept an invalid cr3 and would
-	 * attempt to use it - with largely undefined (and often hard
-	 * to debug) behavior on the guest side.
-	 */
-	if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
-		return 1;
 	vcpu->arch.cr3 = cr3;
 	__set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail);
 	vcpu->arch.mmu.new_cr3(vcpu);
@@ -850,7 +839,8 @@
 #ifdef CONFIG_X86_64
 	MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
-	MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
+	MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
+	MSR_IA32_FEATURE_CONTROL
 };
 
 static unsigned num_msrs_to_save;
@@ -1457,6 +1447,29 @@
 #endif
 }
 
+static void kvm_gen_update_masterclock(struct kvm *kvm)
+{
+#ifdef CONFIG_X86_64
+	int i;
+	struct kvm_vcpu *vcpu;
+	struct kvm_arch *ka = &kvm->arch;
+
+	spin_lock(&ka->pvclock_gtod_sync_lock);
+	kvm_make_mclock_inprogress_request(kvm);
+	/* no guest entries from this point */
+	pvclock_update_vm_gtod_copy(kvm);
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+
+	/* guest entries allowed */
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		clear_bit(KVM_REQ_MCLOCK_INPROGRESS, &vcpu->requests);
+
+	spin_unlock(&ka->pvclock_gtod_sync_lock);
+#endif
+}
+
 static int kvm_guest_time_update(struct kvm_vcpu *v)
 {
 	unsigned long flags, this_tsc_khz;
@@ -3806,6 +3819,7 @@
 		delta = user_ns.clock - now_ns;
 		local_irq_enable();
 		kvm->arch.kvmclock_offset = delta;
+		kvm_gen_update_masterclock(kvm);
 		break;
 	}
 	case KVM_GET_CLOCK: {
@@ -4955,6 +4969,97 @@
 static int complete_emulated_mmio(struct kvm_vcpu *vcpu);
 static int complete_emulated_pio(struct kvm_vcpu *vcpu);
 
+static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7,
+				unsigned long *db)
+{
+	u32 dr6 = 0;
+	int i;
+	u32 enable, rwlen;
+
+	enable = dr7;
+	rwlen = dr7 >> 16;
+	for (i = 0; i < 4; i++, enable >>= 2, rwlen >>= 4)
+		if ((enable & 3) && (rwlen & 15) == type && db[i] == addr)
+			dr6 |= (1 << i);
+	return dr6;
+}
+
+static void kvm_vcpu_check_singlestep(struct kvm_vcpu *vcpu, int *r)
+{
+	struct kvm_run *kvm_run = vcpu->run;
+
+	/*
+	 * Use the "raw" value to see if TF was passed to the processor.
+	 * Note that the new value of the flags has not been saved yet.
+	 *
+	 * This is correct even for TF set by the guest, because "the
+	 * processor will not generate this exception after the instruction
+	 * that sets the TF flag".
+	 */
+	unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
+
+	if (unlikely(rflags & X86_EFLAGS_TF)) {
+		if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) {
+			kvm_run->debug.arch.dr6 = DR6_BS | DR6_FIXED_1;
+			kvm_run->debug.arch.pc = vcpu->arch.singlestep_rip;
+			kvm_run->debug.arch.exception = DB_VECTOR;
+			kvm_run->exit_reason = KVM_EXIT_DEBUG;
+			*r = EMULATE_USER_EXIT;
+		} else {
+			vcpu->arch.emulate_ctxt.eflags &= ~X86_EFLAGS_TF;
+			/*
+			 * "Certain debug exceptions may clear bit 0-3.  The
+			 * remaining contents of the DR6 register are never
+			 * cleared by the processor".
+			 */
+			vcpu->arch.dr6 &= ~15;
+			vcpu->arch.dr6 |= DR6_BS;
+			kvm_queue_exception(vcpu, DB_VECTOR);
+		}
+	}
+}
+
+static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r)
+{
+	struct kvm_run *kvm_run = vcpu->run;
+	unsigned long eip = vcpu->arch.emulate_ctxt.eip;
+	u32 dr6 = 0;
+
+	if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) &&
+	    (vcpu->arch.guest_debug_dr7 & DR7_BP_EN_MASK)) {
+		dr6 = kvm_vcpu_check_hw_bp(eip, 0,
+					   vcpu->arch.guest_debug_dr7,
+					   vcpu->arch.eff_db);
+
+		if (dr6 != 0) {
+			kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1;
+			kvm_run->debug.arch.pc = kvm_rip_read(vcpu) +
+				get_segment_base(vcpu, VCPU_SREG_CS);
+
+			kvm_run->debug.arch.exception = DB_VECTOR;
+			kvm_run->exit_reason = KVM_EXIT_DEBUG;
+			*r = EMULATE_USER_EXIT;
+			return true;
+		}
+	}
+
+	if (unlikely(vcpu->arch.dr7 & DR7_BP_EN_MASK)) {
+		dr6 = kvm_vcpu_check_hw_bp(eip, 0,
+					   vcpu->arch.dr7,
+					   vcpu->arch.db);
+
+		if (dr6 != 0) {
+			vcpu->arch.dr6 &= ~15;
+			vcpu->arch.dr6 |= dr6;
+			kvm_queue_exception(vcpu, DB_VECTOR);
+			*r = EMULATE_DONE;
+			return true;
+		}
+	}
+
+	return false;
+}
+
 int x86_emulate_instruction(struct kvm_vcpu *vcpu,
 			    unsigned long cr2,
 			    int emulation_type,
@@ -4975,6 +5080,16 @@
 
 	if (!(emulation_type & EMULTYPE_NO_DECODE)) {
 		init_emulate_ctxt(vcpu);
+
+		/*
+		 * We will reenter on the same instruction since
+		 * we do not set complete_userspace_io.  This does not
+		 * handle watchpoints yet, those would be handled in
+		 * the emulate_ops.
+		 */
+		if (kvm_vcpu_check_breakpoint(vcpu, &r))
+			return r;
+
 		ctxt->interruptibility = 0;
 		ctxt->have_exception = false;
 		ctxt->perm_ok = false;
@@ -5031,17 +5146,18 @@
 		inject_emulated_exception(vcpu);
 		r = EMULATE_DONE;
 	} else if (vcpu->arch.pio.count) {
-		if (!vcpu->arch.pio.in)
+		if (!vcpu->arch.pio.in) {
+			/* FIXME: return into emulator if single-stepping.  */
 			vcpu->arch.pio.count = 0;
-		else {
+		} else {
 			writeback = false;
 			vcpu->arch.complete_userspace_io = complete_emulated_pio;
 		}
-		r = EMULATE_DO_MMIO;
+		r = EMULATE_USER_EXIT;
 	} else if (vcpu->mmio_needed) {
 		if (!vcpu->mmio_is_write)
 			writeback = false;
-		r = EMULATE_DO_MMIO;
+		r = EMULATE_USER_EXIT;
 		vcpu->arch.complete_userspace_io = complete_emulated_mmio;
 	} else if (r == EMULATION_RESTART)
 		goto restart;
@@ -5050,10 +5166,12 @@
 
 	if (writeback) {
 		toggle_interruptibility(vcpu, ctxt->interruptibility);
-		kvm_set_rflags(vcpu, ctxt->eflags);
 		kvm_make_request(KVM_REQ_EVENT, vcpu);
 		vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
 		kvm_rip_write(vcpu, ctxt->eip);
+		if (r == EMULATE_DONE)
+			kvm_vcpu_check_singlestep(vcpu, &r);
+		kvm_set_rflags(vcpu, ctxt->eflags);
 	} else
 		vcpu->arch.emulate_regs_need_sync_to_vcpu = true;
 
@@ -5347,7 +5465,7 @@
 int kvm_arch_init(void *opaque)
 {
 	int r;
-	struct kvm_x86_ops *ops = (struct kvm_x86_ops *)opaque;
+	struct kvm_x86_ops *ops = opaque;
 
 	if (kvm_x86_ops) {
 		printk(KERN_ERR "kvm: already loaded the other module\n");
@@ -5495,6 +5613,23 @@
 	return 1;
 }
 
+/*
+ * kvm_pv_kick_cpu_op:  Kick a vcpu.
+ *
+ * @apicid - apicid of vcpu to be kicked.
+ */
+static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
+{
+	struct kvm_lapic_irq lapic_irq;
+
+	lapic_irq.shorthand = 0;
+	lapic_irq.dest_mode = 0;
+	lapic_irq.dest_id = apicid;
+
+	lapic_irq.delivery_mode = APIC_DM_REMRD;
+	kvm_irq_delivery_to_apic(kvm, 0, &lapic_irq, NULL);
+}
+
 int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 {
 	unsigned long nr, a0, a1, a2, a3, ret;
@@ -5528,6 +5663,10 @@
 	case KVM_HC_VAPIC_POLL_IRQ:
 		ret = 0;
 		break;
+	case KVM_HC_KICK_CPU:
+		kvm_pv_kick_cpu_op(vcpu->kvm, a0, a1);
+		ret = 0;
+		break;
 	default:
 		ret = -KVM_ENOSYS;
 		break;
@@ -5689,29 +5828,6 @@
 	kvm_make_request(KVM_REQ_EVENT, vcpu);
 }
 
-static void kvm_gen_update_masterclock(struct kvm *kvm)
-{
-#ifdef CONFIG_X86_64
-	int i;
-	struct kvm_vcpu *vcpu;
-	struct kvm_arch *ka = &kvm->arch;
-
-	spin_lock(&ka->pvclock_gtod_sync_lock);
-	kvm_make_mclock_inprogress_request(kvm);
-	/* no guest entries from this point */
-	pvclock_update_vm_gtod_copy(kvm);
-
-	kvm_for_each_vcpu(i, vcpu, kvm)
-		set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
-
-	/* guest entries allowed */
-	kvm_for_each_vcpu(i, vcpu, kvm)
-		clear_bit(KVM_REQ_MCLOCK_INPROGRESS, &vcpu->requests);
-
-	spin_unlock(&ka->pvclock_gtod_sync_lock);
-#endif
-}
-
 static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 {
 	u64 eoi_exit_bitmap[4];
@@ -5950,6 +6066,7 @@
 				kvm_apic_accept_events(vcpu);
 				switch(vcpu->arch.mp_state) {
 				case KVM_MP_STATE_HALTED:
+					vcpu->arch.pv.pv_unhalted = false;
 					vcpu->arch.mp_state =
 						KVM_MP_STATE_RUNNABLE;
 				case KVM_MP_STATE_RUNNABLE:
@@ -6061,6 +6178,8 @@
 
 	if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
 		vcpu->mmio_needed = 0;
+
+		/* FIXME: return into emulator if single-stepping.  */
 		if (vcpu->mmio_is_write)
 			return 1;
 		vcpu->mmio_read_completed = 1;
@@ -6249,7 +6368,12 @@
 				    struct kvm_mp_state *mp_state)
 {
 	kvm_apic_accept_events(vcpu);
-	mp_state->mp_state = vcpu->arch.mp_state;
+	if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED &&
+					vcpu->arch.pv.pv_unhalted)
+		mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
+	else
+		mp_state->mp_state = vcpu->arch.mp_state;
+
 	return 0;
 }
 
@@ -6770,6 +6894,7 @@
 	BUG_ON(vcpu->kvm == NULL);
 	kvm = vcpu->kvm;
 
+	vcpu->arch.pv.pv_unhalted = false;
 	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
 	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_bsp(vcpu))
 		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
@@ -7019,6 +7144,15 @@
 	return -ENOMEM;
 }
 
+void kvm_arch_memslots_updated(struct kvm *kvm)
+{
+	/*
+	 * memslots->generation has been incremented.
+	 * mmio generation may have reached its maximum value.
+	 */
+	kvm_mmu_invalidate_mmio_sptes(kvm);
+}
+
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				struct kvm_memory_slot *memslot,
 				struct kvm_userspace_memory_region *mem,
@@ -7079,11 +7213,6 @@
 	 */
 	if ((change != KVM_MR_DELETE) && (mem->flags & KVM_MEM_LOG_DIRTY_PAGES))
 		kvm_mmu_slot_remove_write_access(kvm, mem->slot);
-	/*
-	 * If memory slot is created, or moved, we need to clear all
-	 * mmio sptes.
-	 */
-	kvm_mmu_invalidate_mmio_sptes(kvm);
 }
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
@@ -7103,6 +7232,7 @@
 		!vcpu->arch.apf.halted)
 		|| !list_empty_careful(&vcpu->async_pf.done)
 		|| kvm_apic_has_events(vcpu)
+		|| vcpu->arch.pv.pv_unhalted
 		|| atomic_read(&vcpu->arch.nmi_queued) ||
 		(kvm_arch_interrupt_allowed(vcpu) &&
 		 kvm_cpu_has_interrupt(vcpu));
diff --git a/arch/x86/lib/csum-wrappers_64.c b/arch/x86/lib/csum-wrappers_64.c
index 25b7ae8..7609e0e 100644
--- a/arch/x86/lib/csum-wrappers_64.c
+++ b/arch/x86/lib/csum-wrappers_64.c
@@ -6,6 +6,7 @@
  */
 #include <asm/checksum.h>
 #include <linux/module.h>
+#include <asm/smap.h>
 
 /**
  * csum_partial_copy_from_user - Copy and checksum from user space.
@@ -52,8 +53,10 @@
 			len -= 2;
 		}
 	}
+	stac();
 	isum = csum_partial_copy_generic((__force const void *)src,
 				dst, len, isum, errp, NULL);
+	clac();
 	if (unlikely(*errp))
 		goto out_err;
 
@@ -82,6 +85,8 @@
 csum_partial_copy_to_user(const void *src, void __user *dst,
 			  int len, __wsum isum, int *errp)
 {
+	__wsum ret;
+
 	might_sleep();
 
 	if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) {
@@ -105,8 +110,11 @@
 	}
 
 	*errp = 0;
-	return csum_partial_copy_generic(src, (void __force *)dst,
-					 len, isum, NULL, errp);
+	stac();
+	ret = csum_partial_copy_generic(src, (void __force *)dst,
+					len, isum, NULL, errp);
+	clac();
+	return ret;
 }
 EXPORT_SYMBOL(csum_partial_copy_to_user);
 
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c
index 906fea3..c905e89 100644
--- a/arch/x86/lib/usercopy_64.c
+++ b/arch/x86/lib/usercopy_64.c
@@ -68,7 +68,7 @@
  * Since protection fault in copy_from/to_user is not a normal situation,
  * it is not necessary to optimize tail handling.
  */
-unsigned long
+__visible unsigned long
 copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
 {
 	char c;
diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt
index 5d7e51f..533a85e 100644
--- a/arch/x86/lib/x86-opcode-map.txt
+++ b/arch/x86/lib/x86-opcode-map.txt
@@ -1,10 +1,8 @@
 # x86 Opcode Maps
 #
 # This is (mostly) based on following documentations.
-# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2
-#   (#325383-040US, October 2011)
-# - Intel(R) Advanced Vector Extensions Programming Reference
-#   (#319433-011,JUNE 2011).
+# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C
+#   (#326018-047US, June 2013)
 #
 #<Opcode maps>
 # Table: table-name
@@ -29,6 +27,7 @@
 #  - (F3): the last prefix is 0xF3
 #  - (F2): the last prefix is 0xF2
 #  - (!F3) : the last prefix is not 0xF3 (including non-last prefix case)
+#  - (66&F2): Both 0x66 and 0xF2 prefixes are specified.
 
 Table: one byte opcode
 Referrer:
@@ -246,8 +245,8 @@
 c3: RETN
 c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
 c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
-c6: Grp11 Eb,Ib (1A)
-c7: Grp11 Ev,Iz (1A)
+c6: Grp11A Eb,Ib (1A)
+c7: Grp11B Ev,Iz (1A)
 c8: ENTER Iw,Ib
 c9: LEAVE (d64)
 ca: RETF Iw
@@ -293,8 +292,8 @@
 # 0xf0 - 0xff
 f0: LOCK (Prefix)
 f1:
-f2: REPNE (Prefix)
-f3: REP/REPE (Prefix)
+f2: REPNE (Prefix) | XACQUIRE (Prefix)
+f3: REP/REPE (Prefix) | XRELEASE (Prefix)
 f4: HLT
 f5: CMC
 f6: Grp3_1 Eb (1A)
@@ -326,7 +325,8 @@
 0a:
 0b: UD2 (1B)
 0c:
-0d: NOP Ev | GrpP
+# AMD's prefetch group. Intel supports prefetchw(/1) only.
+0d: GrpP
 0e: FEMMS
 # 3DNow! uses the last imm byte as opcode extension.
 0f: 3DNow! Pq,Qq,Ib
@@ -729,12 +729,12 @@
 dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
 de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
 df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
-f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2)
-f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2)
+f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2)
+f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2)
 f2: ANDN Gy,By,Ey (v)
 f3: Grp17 (1A)
 f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
-f6: MULX By,Gy,rDX,Ey (F2),(v)
+f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v)
 f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
 EndTable
 
@@ -861,8 +861,8 @@
 
 GrpTable: Grp7
 0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
-1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001)
-2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B)
+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B)
+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B)
 3: LIDT Ms
 4: SMSW Mw/Rv
 5:
@@ -880,15 +880,21 @@
 GrpTable: Grp9
 1: CMPXCHG8B/16B Mq/Mdq
 6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B)
-7: VMPTRST Mq | VMPTRST Mq (F3)
+7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B)
 EndTable
 
 GrpTable: Grp10
 EndTable
 
-GrpTable: Grp11
-# Note: the operands are given by group opcode
-0: MOV
+# Grp11A and Grp11B are expressed as Grp11 in Intel SDM
+GrpTable: Grp11A
+0: MOV Eb,Ib
+7: XABORT Ib (000),(11B)
+EndTable
+
+GrpTable: Grp11B
+0: MOV Eb,Iz
+7: XBEGIN Jz (000),(11B)
 EndTable
 
 GrpTable: Grp12
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 2ec29ac..04664cd 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -78,8 +78,8 @@
 	return __va(pfn << PAGE_SHIFT);
 }
 
-/* need 4 4k for initial PMD_SIZE, 4k for 0-ISA_END_ADDRESS */
-#define INIT_PGT_BUF_SIZE	(5 * PAGE_SIZE)
+/* need 3 4k for initial PMD_SIZE,  3 4k for 0-ISA_END_ADDRESS */
+#define INIT_PGT_BUF_SIZE	(6 * PAGE_SIZE)
 RESERVE_BRK(early_pgt_alloc, INIT_PGT_BUF_SIZE);
 void  __init early_alloc_pgt_buf(void)
 {
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 0215e2c..799580c 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -487,7 +487,7 @@
 	unsigned long offset;
 	resource_size_t last_addr;
 	unsigned int nrpages;
-	enum fixed_addresses idx0, idx;
+	enum fixed_addresses idx;
 	int i, slot;
 
 	WARN_ON(system_state != SYSTEM_BOOTING);
@@ -540,8 +540,7 @@
 	/*
 	 * Ok, go for it..
 	 */
-	idx0 = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
-	idx = idx0;
+	idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
 	while (nrpages > 0) {
 		early_set_fixmap(idx, phys_addr, prot);
 		phys_addr += PAGE_SIZE;
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index f63778c..25e7e13 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -98,7 +98,7 @@
  * Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64
  * does, but not when emulating X86_32
  */
-unsigned long mmap_legacy_base(void)
+static unsigned long mmap_legacy_base(void)
 {
 	if (mmap_is_ia32())
 		return TASK_UNMAPPED_BASE;
@@ -112,11 +112,13 @@
  */
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
+	mm->mmap_legacy_base = mmap_legacy_base();
+	mm->mmap_base = mmap_base();
+
 	if (mmap_is_legacy()) {
-		mm->mmap_base = mmap_legacy_base();
+		mm->mmap_base = mm->mmap_legacy_base;
 		mm->get_unmapped_area = arch_get_unmapped_area;
 	} else {
-		mm->mmap_base = mmap_base();
 		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
 	}
 }
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index cdd0da9..266ca91 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -146,6 +146,7 @@
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
 	u64 start, end;
+	u32 hotpluggable;
 	int node, pxm;
 
 	if (srat_disabled())
@@ -154,7 +155,8 @@
 		goto out_err_bad_srat;
 	if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
 		goto out_err;
-	if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
+	hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE;
+	if (hotpluggable && !save_add_info())
 		goto out_err;
 
 	start = ma->base_address;
@@ -174,9 +176,10 @@
 
 	node_set(node, numa_nodes_parsed);
 
-	printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n",
-	       node, pxm,
-	       (unsigned long long) start, (unsigned long long) end - 1);
+	pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s\n",
+		node, pxm,
+		(unsigned long long) start, (unsigned long long) end - 1,
+		hotpluggable ? " hotplug" : "");
 
 	return 0;
 out_err_bad_srat:
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index d641897..b30e937 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -568,13 +568,8 @@
 	 */
 	if (bus) {
 		struct pci_bus *child;
-		list_for_each_entry(child, &bus->children, node) {
-			struct pci_dev *self = child->self;
-			if (!self)
-				continue;
-
-			pcie_bus_configure_settings(child, self->pcie_mpss);
-		}
+		list_for_each_entry(child, &bus->children, node)
+			pcie_bus_configure_settings(child);
 	}
 
 	if (bus && node != -1) {
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 94919e3..db6b1ab 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -210,6 +210,8 @@
 		r = &dev->resource[idx];
 		if (!r->flags)
 			continue;
+		if (r->parent)	/* Already allocated */
+			continue;
 		if (!r->start || pci_claim_resource(dev, idx) < 0) {
 			/*
 			 * Something is wrong with the region.
@@ -318,6 +320,8 @@
 	r = &dev->resource[PCI_ROM_RESOURCE];
 	if (!r->flags || !r->start)
 		return;
+	if (r->parent) /* Already allocated */
+		return;
 
 	if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
 		r->end -= r->start;
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 082e881..5596c7b 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -700,7 +700,7 @@
 	if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
 		return -ENODEV;
 
-	if (start > end)
+	if (start > end || !addr)
 		return -EINVAL;
 
 	mutex_lock(&pci_mmcfg_lock);
@@ -716,11 +716,6 @@
 		return -EEXIST;
 	}
 
-	if (!addr) {
-		mutex_unlock(&pci_mmcfg_lock);
-		return -EINVAL;
-	}
-
 	rc = -EBUSY;
 	cfg = pci_mmconfig_alloc(seg, start, end, addr);
 	if (cfg == NULL) {
diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c
index 6eb18c4..903fded 100644
--- a/arch/x86/pci/mrst.c
+++ b/arch/x86/pci/mrst.c
@@ -23,11 +23,11 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/smp.h>
 
-#include <asm/acpi.h>
 #include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/smp.h>
 #include <asm/pci_x86.h>
 #include <asm/hw_irq.h>
 #include <asm/io_apic.h>
@@ -43,7 +43,7 @@
 #define PCI_FIXED_BAR_4_SIZE	0x14
 #define PCI_FIXED_BAR_5_SIZE	0x1c
 
-static int pci_soc_mode = 0;
+static int pci_soc_mode;
 
 /**
  * fixed_bar_cap - return the offset of the fixed BAR cap if found
@@ -141,7 +141,8 @@
  */
 static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg)
 {
-	/* This is a workaround for A0 LNC bug where PCI status register does
+	/*
+	 * This is a workaround for A0 LNC bug where PCI status register does
 	 * not have new CAP bit set. can not be written by SW either.
 	 *
 	 * PCI header type in real LNC indicates a single function device, this
@@ -154,7 +155,7 @@
 				|| devfn == PCI_DEVFN(0, 0)
 				|| devfn == PCI_DEVFN(3, 0)))
 		return 1;
-	return 0; /* langwell on others */
+	return 0; /* Langwell on others */
 }
 
 static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
@@ -172,7 +173,8 @@
 {
 	int offset;
 
-	/* On MRST, there is no PCI ROM BAR, this will cause a subsequent read
+	/*
+	 * On MRST, there is no PCI ROM BAR, this will cause a subsequent read
 	 * to ROM BAR return 0 then being ignored.
 	 */
 	if (where == PCI_ROM_ADDRESS)
@@ -210,7 +212,8 @@
 
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 
-	/* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
+	/*
+	 * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
 	 * IOAPIC RTE entries, so we just enable RTE for the device.
 	 */
 	irq_attr.ioapic = mp_find_ioapic(dev->irq);
@@ -235,7 +238,7 @@
  */
 int __init pci_mrst_init(void)
 {
-	printk(KERN_INFO "Intel MID platform detected, using MID PCI ops\n");
+	pr_info("Intel MID platform detected, using MID PCI ops\n");
 	pci_mmcfg_late_init();
 	pcibios_enable_irq = mrst_pci_irq_enable;
 	pci_root_ops = pci_mrst_ops;
@@ -244,17 +247,21 @@
 	return 1;
 }
 
-/* Langwell devices are not true pci devices, they are not subject to 10 ms
- * d3 to d0 delay required by pci spec.
+/*
+ * Langwell devices are not true PCI devices; they are not subject to 10 ms
+ * d3 to d0 delay required by PCI spec.
  */
 static void pci_d3delay_fixup(struct pci_dev *dev)
 {
-	/* PCI fixups are effectively decided compile time. If we have a dual
-	   SoC/non-SoC kernel we don't want to mangle d3 on non SoC devices */
-        if (!pci_soc_mode)
-            return;
-	/* true pci devices in lincroft should allow type 1 access, the rest
-	 * are langwell fake pci devices.
+	/*
+	 * PCI fixups are effectively decided compile time. If we have a dual
+	 * SoC/non-SoC kernel we don't want to mangle d3 on non-SoC devices.
+	 */
+	if (!pci_soc_mode)
+		return;
+	/*
+	 * True PCI devices in Lincroft should allow type 1 access, the rest
+	 * are Langwell fake PCI devices.
 	 */
 	if (type1_access_ok(dev->bus->number, dev->devfn, PCI_DEVICE_ID))
 		return;
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 1cf5b30..424f4c9 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -25,10 +25,10 @@
 #include <asm/cpu.h>
 
 #ifdef CONFIG_X86_32
-unsigned long saved_context_ebx;
-unsigned long saved_context_esp, saved_context_ebp;
-unsigned long saved_context_esi, saved_context_edi;
-unsigned long saved_context_eflags;
+__visible unsigned long saved_context_ebx;
+__visible unsigned long saved_context_esp, saved_context_ebp;
+__visible unsigned long saved_context_esi, saved_context_edi;
+__visible unsigned long saved_context_eflags;
 #endif
 struct saved_context saved_context;
 
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index a0fde91..304fca2 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -20,26 +20,26 @@
 #include <asm/suspend.h>
 
 /* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
+extern __visible const void __nosave_begin, __nosave_end;
 
 /* Defined in hibernate_asm_64.S */
-extern int restore_image(void);
+extern asmlinkage int restore_image(void);
 
 /*
  * Address to jump to in the last phase of restore in order to get to the image
  * kernel's text (this value is passed in the image header).
  */
-unsigned long restore_jump_address;
+unsigned long restore_jump_address __visible;
 
 /*
  * Value of the cr3 register from before the hibernation (this value is passed
  * in the image header).
  */
-unsigned long restore_cr3;
+unsigned long restore_cr3 __visible;
 
-pgd_t *temp_level4_pgt;
+pgd_t *temp_level4_pgt __visible;
 
-void *relocated_restore_code;
+void *relocated_restore_code __visible;
 
 static void *alloc_pgt_page(void *context)
 {
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
index e6773dc..093a892 100644
--- a/arch/x86/tools/gen-insn-attr-x86.awk
+++ b/arch/x86/tools/gen-insn-attr-x86.awk
@@ -68,7 +68,7 @@
 
 	lprefix1_expr = "\\((66|!F3)\\)"
 	lprefix2_expr = "\\(F3\\)"
-	lprefix3_expr = "\\((F2|!F3)\\)"
+	lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)"
 	lprefix_expr = "\\((66|F2|F3)\\)"
 	max_lprefix = 4
 
@@ -83,6 +83,8 @@
 	prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
 	prefix_num["REPNE"] = "INAT_PFX_REPNE"
 	prefix_num["REP/REPE"] = "INAT_PFX_REPE"
+	prefix_num["XACQUIRE"] = "INAT_PFX_REPNE"
+	prefix_num["XRELEASE"] = "INAT_PFX_REPE"
 	prefix_num["LOCK"] = "INAT_PFX_LOCK"
 	prefix_num["SEG=CS"] = "INAT_PFX_CS"
 	prefix_num["SEG=DS"] = "INAT_PFX_DS"
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index c74436e..72074d5 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -85,15 +85,18 @@
 	cycle_t ret;
 	u64 last;
 	u32 version;
-	u32 migrate_count;
 	u8 flags;
 	unsigned cpu, cpu1;
 
 
 	/*
-	 * When looping to get a consistent (time-info, tsc) pair, we
-	 * also need to deal with the possibility we can switch vcpus,
-	 * so make sure we always re-fetch time-info for the current vcpu.
+	 * Note: hypervisor must guarantee that:
+	 * 1. cpu ID number maps 1:1 to per-CPU pvclock time info.
+	 * 2. that per-CPU pvclock time info is updated if the
+	 *    underlying CPU changes.
+	 * 3. that version is increased whenever underlying CPU
+	 *    changes.
+	 *
 	 */
 	do {
 		cpu = __getcpu() & VGETCPU_CPU_MASK;
@@ -104,8 +107,6 @@
 
 		pvti = get_pvti(cpu);
 
-		migrate_count = pvti->migrate_count;
-
 		version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
 
 		/*
@@ -117,8 +118,7 @@
 		cpu1 = __getcpu() & VGETCPU_CPU_MASK;
 	} while (unlikely(cpu != cpu1 ||
 			  (pvti->pvti.version & 1) ||
-			  pvti->pvti.version != version ||
-			  pvti->migrate_count != migrate_count));
+			  pvti->pvti.version != version));
 
 	if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT)))
 		*mode = VCLOCK_NONE;
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 193097e..2fc216d 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -427,8 +427,7 @@
 
 	if (!xen_initial_domain())
 		cpuid_leaf1_edx_mask &=
-			~((1 << X86_FEATURE_APIC) |  /* disable local APIC */
-			  (1 << X86_FEATURE_ACPI));  /* disable ACPI */
+			~((1 << X86_FEATURE_ACPI));  /* disable ACPI */
 
 	cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_X2APIC % 32));
 
@@ -735,8 +734,7 @@
 		addr = (unsigned long)xen_int3;
 	else if (addr == (unsigned long)stack_segment)
 		addr = (unsigned long)xen_stack_segment;
-	else if (addr == (unsigned long)double_fault ||
-		 addr == (unsigned long)nmi) {
+	else if (addr == (unsigned long)double_fault) {
 		/* Don't need to handle these */
 		return 0;
 #ifdef CONFIG_X86_MCE
@@ -747,7 +745,12 @@
 		 */
 		;
 #endif
-	} else {
+	} else if (addr == (unsigned long)nmi)
+		/*
+		 * Use the native version as well.
+		 */
+		;
+	else {
 		/* Some other trap using IST? */
 		if (WARN_ON(val->ist != 0))
 			return 0;
@@ -1710,6 +1713,8 @@
 
 	xen_hvm_init_shared_info();
 
+	xen_panic_handler_init();
+
 	if (xen_feature(XENFEAT_hvm_callback_vector))
 		xen_have_vector_callback = 1;
 	xen_hvm_smp_init();
@@ -1720,15 +1725,12 @@
 	xen_hvm_init_mmu_ops();
 }
 
-static bool __init xen_hvm_platform(void)
+static uint32_t __init xen_hvm_platform(void)
 {
 	if (xen_pv_domain())
-		return false;
+		return 0;
 
-	if (!xen_cpuid_base())
-		return false;
-
-	return true;
+	return xen_cpuid_base();
 }
 
 bool xen_hvm_need_lapic(void)
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index 01a4dc0..0da7f86 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -47,23 +47,18 @@
 	/* convert from IF type flag */
 	flags = !(flags & X86_EFLAGS_IF);
 
-	/* There's a one instruction preempt window here.  We need to
-	   make sure we're don't switch CPUs between getting the vcpu
-	   pointer and updating the mask. */
+	/* See xen_irq_enable() for why preemption must be disabled. */
 	preempt_disable();
 	vcpu = this_cpu_read(xen_vcpu);
 	vcpu->evtchn_upcall_mask = flags;
-	preempt_enable_no_resched();
-
-	/* Doesn't matter if we get preempted here, because any
-	   pending event will get dealt with anyway. */
 
 	if (flags == 0) {
-		preempt_check_resched();
 		barrier(); /* unmask then check (avoid races) */
 		if (unlikely(vcpu->evtchn_upcall_pending))
 			xen_force_evtchn_callback();
-	}
+		preempt_enable();
+	} else
+		preempt_enable_no_resched();
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_restore_fl);
 
@@ -82,10 +77,12 @@
 {
 	struct vcpu_info *vcpu;
 
-	/* We don't need to worry about being preempted here, since
-	   either a) interrupts are disabled, so no preemption, or b)
-	   the caller is confused and is trying to re-enable interrupts
-	   on an indeterminate processor. */
+	/*
+	 * We may be preempted as soon as vcpu->evtchn_upcall_mask is
+	 * cleared, so disable preemption to ensure we check for
+	 * events on the VCPU we are still running on.
+	 */
+	preempt_disable();
 
 	vcpu = this_cpu_read(xen_vcpu);
 	vcpu->evtchn_upcall_mask = 0;
@@ -96,6 +93,8 @@
 	barrier(); /* unmask then check (avoid races) */
 	if (unlikely(vcpu->evtchn_upcall_pending))
 		xen_force_evtchn_callback();
+
+	preempt_enable();
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);
 
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 95fb2aa..0d4ec35 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -161,6 +161,7 @@
 #include <asm/xen/page.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
+#include <xen/balloon.h>
 #include <xen/grant_table.h>
 
 #include "multicalls.h"
@@ -967,7 +968,10 @@
 	if (kmap_op != NULL) {
 		if (!PageHighMem(page)) {
 			struct multicall_space mcs;
-			struct gnttab_unmap_grant_ref *unmap_op;
+			struct gnttab_unmap_and_replace *unmap_op;
+			struct page *scratch_page = get_balloon_scratch_page();
+			unsigned long scratch_page_address = (unsigned long)
+				__va(page_to_pfn(scratch_page) << PAGE_SHIFT);
 
 			/*
 			 * It might be that we queued all the m2p grant table
@@ -990,21 +994,25 @@
 			}
 
 			mcs = xen_mc_entry(
-					sizeof(struct gnttab_unmap_grant_ref));
+					sizeof(struct gnttab_unmap_and_replace));
 			unmap_op = mcs.args;
 			unmap_op->host_addr = kmap_op->host_addr;
+			unmap_op->new_addr = scratch_page_address;
 			unmap_op->handle = kmap_op->handle;
-			unmap_op->dev_bus_addr = 0;
 
 			MULTI_grant_table_op(mcs.mc,
-					GNTTABOP_unmap_grant_ref, unmap_op, 1);
+					GNTTABOP_unmap_and_replace, unmap_op, 1);
 
 			xen_mc_issue(PARAVIRT_LAZY_MMU);
 
-			set_pte_at(&init_mm, address, ptep,
-					pfn_pte(pfn, PAGE_KERNEL));
-			__flush_tlb_single(address);
+			mcs = __xen_mc_entry(0);
+			MULTI_update_va_mapping(mcs.mc, scratch_page_address,
+					pfn_pte(page_to_pfn(get_balloon_scratch_page()),
+					PAGE_KERNEL_RO), 0);
+			xen_mc_issue(PARAVIRT_LAZY_MMU);
+
 			kmap_op->host_addr = 0;
+			put_balloon_scratch_page();
 		}
 	}
 
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 056d11f..09f3059 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -33,6 +33,9 @@
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_hypervisor_callback[];
 extern const char xen_failsafe_callback[];
+#ifdef CONFIG_X86_64
+extern const char nmi[];
+#endif
 extern void xen_sysenter_target(void);
 extern void xen_syscall_target(void);
 extern void xen_syscall32_target(void);
@@ -215,13 +218,19 @@
 	unsigned long pfn;
 
 	/*
-	 * If the PFNs are currently mapped, the VA mapping also needs
-	 * to be updated to be 1:1.
+	 * If the PFNs are currently mapped, clear the mappings
+	 * (except for the ISA region which must be 1:1 mapped) to
+	 * release the refcounts (in Xen) on the original frames.
 	 */
-	for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++)
+	for (pfn = start_pfn; pfn <= max_pfn_mapped && pfn < end_pfn; pfn++) {
+		pte_t pte = __pte_ma(0);
+
+		if (pfn < PFN_UP(ISA_END_ADDRESS))
+			pte = mfn_pte(pfn, PAGE_KERNEL_IO);
+
 		(void)HYPERVISOR_update_va_mapping(
-			(unsigned long)__va(pfn << PAGE_SHIFT),
-			mfn_pte(pfn, PAGE_KERNEL_IO), 0);
+			(unsigned long)__va(pfn << PAGE_SHIFT), pte, 0);
+	}
 
 	if (start_pfn < nr_pages)
 		*released += xen_release_chunk(
@@ -313,6 +322,17 @@
 	e820_add_region(start, end - start, type);
 }
 
+void xen_ignore_unusable(struct e820entry *list, size_t map_size)
+{
+	struct e820entry *entry;
+	unsigned int i;
+
+	for (i = 0, entry = list; i < map_size; i++, entry++) {
+		if (entry->type == E820_UNUSABLE)
+			entry->type = E820_RAM;
+	}
+}
+
 /**
  * machine_specific_memory_setup - Hook for machine specific memory setup.
  **/
@@ -353,6 +373,17 @@
 	}
 	BUG_ON(rc);
 
+	/*
+	 * Xen won't allow a 1:1 mapping to be created to UNUSABLE
+	 * regions, so if we're using the machine memory map leave the
+	 * region as RAM as it is in the pseudo-physical map.
+	 *
+	 * UNUSABLE regions in domUs are not handled and will need
+	 * a patch in the future.
+	 */
+	if (xen_initial_domain())
+		xen_ignore_unusable(map, memmap.nr_entries);
+
 	/* Make sure the Xen-supplied memory map is well-ordered. */
 	sanitize_e820_map(map, memmap.nr_entries, &memmap.nr_entries);
 
@@ -525,7 +556,13 @@
 	}
 #endif /* CONFIG_X86_64 */
 }
-
+void __cpuinit xen_enable_nmi(void)
+{
+#ifdef CONFIG_X86_64
+	if (register_callback(CALLBACKTYPE_nmi, nmi))
+		BUG();
+#endif
+}
 void __init xen_arch_setup(void)
 {
 	xen_panic_handler_init();
@@ -543,7 +580,7 @@
 
 	xen_enable_sysenter();
 	xen_enable_syscall();
-
+	xen_enable_nmi();
 #ifdef CONFIG_ACPI
 	if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
 		printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index ca92754..9235842 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -279,6 +279,7 @@
 
 	xen_filter_cpu_maps();
 	xen_setup_vcpu_info_placement();
+	xen_init_spinlocks();
 }
 
 static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
@@ -572,6 +573,12 @@
 	case IRQ_WORK_VECTOR:
 		xen_vector = XEN_IRQ_WORK_VECTOR;
 		break;
+#ifdef CONFIG_X86_64
+	case NMI_VECTOR:
+	case APIC_DM_NMI: /* Some use that instead of NMI_VECTOR */
+		xen_vector = XEN_NMI_VECTOR;
+		break;
+#endif
 	default:
 		xen_vector = -1;
 		printk(KERN_ERR "xen: vector 0x%x is not implemented\n",
@@ -680,7 +687,6 @@
 {
 	smp_ops = xen_smp_ops;
 	xen_fill_possible_map();
-	xen_init_spinlocks();
 }
 
 static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
@@ -694,8 +700,15 @@
 static int xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
 	int rc;
-	rc = native_cpu_up(cpu, tidle);
-	WARN_ON (xen_smp_intr_init(cpu));
+	/*
+	 * xen_smp_intr_init() needs to run before native_cpu_up()
+	 * so that IPI vectors are set up on the booting CPU before
+	 * it is marked online in native_cpu_up().
+	*/
+	rc = xen_smp_intr_init(cpu);
+	WARN_ON(rc);
+	if (!rc)
+		rc =  native_cpu_up(cpu, tidle);
 	return rc;
 }
 
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index cf3caee..0438b93 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -17,45 +17,44 @@
 #include "xen-ops.h"
 #include "debugfs.h"
 
+enum xen_contention_stat {
+	TAKEN_SLOW,
+	TAKEN_SLOW_PICKUP,
+	TAKEN_SLOW_SPURIOUS,
+	RELEASED_SLOW,
+	RELEASED_SLOW_KICKED,
+	NR_CONTENTION_STATS
+};
+
+
 #ifdef CONFIG_XEN_DEBUG_FS
+#define HISTO_BUCKETS	30
 static struct xen_spinlock_stats
 {
-	u64 taken;
-	u32 taken_slow;
-	u32 taken_slow_nested;
-	u32 taken_slow_pickup;
-	u32 taken_slow_spurious;
-	u32 taken_slow_irqenable;
-
-	u64 released;
-	u32 released_slow;
-	u32 released_slow_kicked;
-
-#define HISTO_BUCKETS	30
-	u32 histo_spin_total[HISTO_BUCKETS+1];
-	u32 histo_spin_spinning[HISTO_BUCKETS+1];
+	u32 contention_stats[NR_CONTENTION_STATS];
 	u32 histo_spin_blocked[HISTO_BUCKETS+1];
-
-	u64 time_total;
-	u64 time_spinning;
 	u64 time_blocked;
 } spinlock_stats;
 
 static u8 zero_stats;
 
-static unsigned lock_timeout = 1 << 10;
-#define TIMEOUT lock_timeout
-
 static inline void check_zero(void)
 {
-	if (unlikely(zero_stats)) {
-		memset(&spinlock_stats, 0, sizeof(spinlock_stats));
-		zero_stats = 0;
+	u8 ret;
+	u8 old = ACCESS_ONCE(zero_stats);
+	if (unlikely(old)) {
+		ret = cmpxchg(&zero_stats, old, 0);
+		/* This ensures only one fellow resets the stat */
+		if (ret == old)
+			memset(&spinlock_stats, 0, sizeof(spinlock_stats));
 	}
 }
 
-#define ADD_STATS(elem, val)			\
-	do { check_zero(); spinlock_stats.elem += (val); } while(0)
+static inline void add_stats(enum xen_contention_stat var, u32 val)
+{
+	check_zero();
+	spinlock_stats.contention_stats[var] += val;
+}
 
 static inline u64 spin_time_start(void)
 {
@@ -74,22 +73,6 @@
 		array[HISTO_BUCKETS]++;
 }
 
-static inline void spin_time_accum_spinning(u64 start)
-{
-	u32 delta = xen_clocksource_read() - start;
-
-	__spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
-	spinlock_stats.time_spinning += delta;
-}
-
-static inline void spin_time_accum_total(u64 start)
-{
-	u32 delta = xen_clocksource_read() - start;
-
-	__spin_time_accum(delta, spinlock_stats.histo_spin_total);
-	spinlock_stats.time_total += delta;
-}
-
 static inline void spin_time_accum_blocked(u64 start)
 {
 	u32 delta = xen_clocksource_read() - start;
@@ -99,19 +82,15 @@
 }
 #else  /* !CONFIG_XEN_DEBUG_FS */
 #define TIMEOUT			(1 << 10)
-#define ADD_STATS(elem, val)	do { (void)(val); } while(0)
+static inline void add_stats(enum xen_contention_stat var, u32 val)
+{
+}
 
 static inline u64 spin_time_start(void)
 {
 	return 0;
 }
 
-static inline void spin_time_accum_total(u64 start)
-{
-}
-static inline void spin_time_accum_spinning(u64 start)
-{
-}
 static inline void spin_time_accum_blocked(u64 start)
 {
 }
@@ -134,227 +113,123 @@
 	asm(LOCK_PREFIX " decw %0" : "+m" ((xl)->spinners) : : "memory");
 #endif
 
-struct xen_spinlock {
-	unsigned char lock;		/* 0 -> free; 1 -> locked */
-	xen_spinners_t spinners;	/* count of waiting cpus */
+struct xen_lock_waiting {
+	struct arch_spinlock *lock;
+	__ticket_t want;
 };
 
-static int xen_spin_is_locked(struct arch_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-	return xl->lock != 0;
-}
-
-static int xen_spin_is_contended(struct arch_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-	/* Not strictly true; this is only the count of contended
-	   lock-takers entering the slow path. */
-	return xl->spinners != 0;
-}
-
-static int xen_spin_trylock(struct arch_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-	u8 old = 1;
-
-	asm("xchgb %b0,%1"
-	    : "+q" (old), "+m" (xl->lock) : : "memory");
-
-	return old == 0;
-}
-
-static DEFINE_PER_CPU(char *, irq_name);
 static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
+static DEFINE_PER_CPU(char *, irq_name);
+static DEFINE_PER_CPU(struct xen_lock_waiting, lock_waiting);
+static cpumask_t waiting_cpus;
 
-/*
- * Mark a cpu as interested in a lock.  Returns the CPU's previous
- * lock of interest, in case we got preempted by an interrupt.
- */
-static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
+static void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
 {
-	struct xen_spinlock *prev;
-
-	prev = __this_cpu_read(lock_spinners);
-	__this_cpu_write(lock_spinners, xl);
-
-	wmb();			/* set lock of interest before count */
-
-	inc_spinners(xl);
-
-	return prev;
-}
-
-/*
- * Mark a cpu as no longer interested in a lock.  Restores previous
- * lock of interest (NULL for none).
- */
-static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock *prev)
-{
-	dec_spinners(xl);
-	wmb();			/* decrement count before restoring lock */
-	__this_cpu_write(lock_spinners, prev);
-}
-
-static noinline int xen_spin_lock_slow(struct arch_spinlock *lock, bool irq_enable)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-	struct xen_spinlock *prev;
 	int irq = __this_cpu_read(lock_kicker_irq);
-	int ret;
+	struct xen_lock_waiting *w = &__get_cpu_var(lock_waiting);
+	int cpu = smp_processor_id();
 	u64 start;
+	unsigned long flags;
 
 	/* If kicker interrupts not initialized yet, just spin */
 	if (irq == -1)
-		return 0;
+		return;
 
 	start = spin_time_start();
 
-	/* announce we're spinning */
-	prev = spinning_lock(xl);
+	/*
+	 * Make sure an interrupt handler can't upset things in a
+	 * partially setup state.
+	 */
+	local_irq_save(flags);
+	/*
+	 * We don't really care if we're overwriting some other
+	 * (lock,want) pair, as that would mean that we're currently
+	 * in an interrupt context, and the outer context had
+	 * interrupts enabled.  That has already kicked the VCPU out
+	 * of xen_poll_irq(), so it will just return spuriously and
+	 * retry with newly setup (lock,want).
+	 *
+	 * The ordering protocol on this is that the "lock" pointer
+	 * may only be set non-NULL if the "want" ticket is correct.
+	 * If we're updating "want", we must first clear "lock".
+	 */
+	w->lock = NULL;
+	smp_wmb();
+	w->want = want;
+	smp_wmb();
+	w->lock = lock;
 
-	ADD_STATS(taken_slow, 1);
-	ADD_STATS(taken_slow_nested, prev != NULL);
+	/* This uses set_bit, which atomic and therefore a barrier */
+	cpumask_set_cpu(cpu, &waiting_cpus);
+	add_stats(TAKEN_SLOW, 1);
 
-	do {
-		unsigned long flags;
+	/* clear pending */
+	xen_clear_irq_pending(irq);
 
-		/* clear pending */
-		xen_clear_irq_pending(irq);
+	/* Only check lock once pending cleared */
+	barrier();
 
-		/* check again make sure it didn't become free while
-		   we weren't looking  */
-		ret = xen_spin_trylock(lock);
-		if (ret) {
-			ADD_STATS(taken_slow_pickup, 1);
+	/*
+	 * Mark entry to slowpath before doing the pickup test to make
+	 * sure we don't deadlock with an unlocker.
+	 */
+	__ticket_enter_slowpath(lock);
 
-			/*
-			 * If we interrupted another spinlock while it
-			 * was blocking, make sure it doesn't block
-			 * without rechecking the lock.
-			 */
-			if (prev != NULL)
-				xen_set_irq_pending(irq);
-			goto out;
-		}
+	/*
+	 * check again make sure it didn't become free while
+	 * we weren't looking
+	 */
+	if (ACCESS_ONCE(lock->tickets.head) == want) {
+		add_stats(TAKEN_SLOW_PICKUP, 1);
+		goto out;
+	}
 
-		flags = arch_local_save_flags();
-		if (irq_enable) {
-			ADD_STATS(taken_slow_irqenable, 1);
-			raw_local_irq_enable();
-		}
+	/* Allow interrupts while blocked */
+	local_irq_restore(flags);
 
-		/*
-		 * Block until irq becomes pending.  If we're
-		 * interrupted at this point (after the trylock but
-		 * before entering the block), then the nested lock
-		 * handler guarantees that the irq will be left
-		 * pending if there's any chance the lock became free;
-		 * xen_poll_irq() returns immediately if the irq is
-		 * pending.
-		 */
-		xen_poll_irq(irq);
+	/*
+	 * If an interrupt happens here, it will leave the wakeup irq
+	 * pending, which will cause xen_poll_irq() to return
+	 * immediately.
+	 */
 
-		raw_local_irq_restore(flags);
+	/* Block until irq becomes pending (or perhaps a spurious wakeup) */
+	xen_poll_irq(irq);
+	add_stats(TAKEN_SLOW_SPURIOUS, !xen_test_irq_pending(irq));
 
-		ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
-	} while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
+	local_irq_save(flags);
 
 	kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
-
 out:
-	unspinning_lock(xl, prev);
+	cpumask_clear_cpu(cpu, &waiting_cpus);
+	w->lock = NULL;
+
+	local_irq_restore(flags);
+
 	spin_time_accum_blocked(start);
-
-	return ret;
 }
+PV_CALLEE_SAVE_REGS_THUNK(xen_lock_spinning);
 
-static inline void __xen_spin_lock(struct arch_spinlock *lock, bool irq_enable)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-	unsigned timeout;
-	u8 oldval;
-	u64 start_spin;
-
-	ADD_STATS(taken, 1);
-
-	start_spin = spin_time_start();
-
-	do {
-		u64 start_spin_fast = spin_time_start();
-
-		timeout = TIMEOUT;
-
-		asm("1: xchgb %1,%0\n"
-		    "   testb %1,%1\n"
-		    "   jz 3f\n"
-		    "2: rep;nop\n"
-		    "   cmpb $0,%0\n"
-		    "   je 1b\n"
-		    "   dec %2\n"
-		    "   jnz 2b\n"
-		    "3:\n"
-		    : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
-		    : "1" (1)
-		    : "memory");
-
-		spin_time_accum_spinning(start_spin_fast);
-
-	} while (unlikely(oldval != 0 &&
-			  (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
-
-	spin_time_accum_total(start_spin);
-}
-
-static void xen_spin_lock(struct arch_spinlock *lock)
-{
-	__xen_spin_lock(lock, false);
-}
-
-static void xen_spin_lock_flags(struct arch_spinlock *lock, unsigned long flags)
-{
-	__xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
-}
-
-static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
+static void xen_unlock_kick(struct arch_spinlock *lock, __ticket_t next)
 {
 	int cpu;
 
-	ADD_STATS(released_slow, 1);
+	add_stats(RELEASED_SLOW, 1);
 
-	for_each_online_cpu(cpu) {
-		/* XXX should mix up next cpu selection */
-		if (per_cpu(lock_spinners, cpu) == xl) {
-			ADD_STATS(released_slow_kicked, 1);
+	for_each_cpu(cpu, &waiting_cpus) {
+		const struct xen_lock_waiting *w = &per_cpu(lock_waiting, cpu);
+
+		/* Make sure we read lock before want */
+		if (ACCESS_ONCE(w->lock) == lock &&
+		    ACCESS_ONCE(w->want) == next) {
+			add_stats(RELEASED_SLOW_KICKED, 1);
 			xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+			break;
 		}
 	}
 }
 
-static void xen_spin_unlock(struct arch_spinlock *lock)
-{
-	struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-	ADD_STATS(released, 1);
-
-	smp_wmb();		/* make sure no writes get moved after unlock */
-	xl->lock = 0;		/* release lock */
-
-	/*
-	 * Make sure unlock happens before checking for waiting
-	 * spinners.  We need a strong barrier to enforce the
-	 * write-read ordering to different memory locations, as the
-	 * CPU makes no implied guarantees about their ordering.
-	 */
-	mb();
-
-	if (unlikely(xl->spinners))
-		xen_spin_unlock_slow(xl);
-}
-
 static irqreturn_t dummy_handler(int irq, void *dev_id)
 {
 	BUG();
@@ -408,6 +283,8 @@
 	per_cpu(irq_name, cpu) = NULL;
 }
 
+static bool xen_pvspin __initdata = true;
+
 void __init xen_init_spinlocks(void)
 {
 	/*
@@ -417,16 +294,24 @@
 	if (xen_hvm_domain())
 		return;
 
-	BUILD_BUG_ON(sizeof(struct xen_spinlock) > sizeof(arch_spinlock_t));
+	if (!xen_pvspin) {
+		printk(KERN_DEBUG "xen: PV spinlocks disabled\n");
+		return;
+	}
 
-	pv_lock_ops.spin_is_locked = xen_spin_is_locked;
-	pv_lock_ops.spin_is_contended = xen_spin_is_contended;
-	pv_lock_ops.spin_lock = xen_spin_lock;
-	pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
-	pv_lock_ops.spin_trylock = xen_spin_trylock;
-	pv_lock_ops.spin_unlock = xen_spin_unlock;
+	static_key_slow_inc(&paravirt_ticketlocks_enabled);
+
+	pv_lock_ops.lock_spinning = PV_CALLEE_SAVE(xen_lock_spinning);
+	pv_lock_ops.unlock_kick = xen_unlock_kick;
 }
 
+static __init int xen_parse_nopvspin(char *arg)
+{
+	xen_pvspin = false;
+	return 0;
+}
+early_param("xen_nopvspin", xen_parse_nopvspin);
+
 #ifdef CONFIG_XEN_DEBUG_FS
 
 static struct dentry *d_spin_debug;
@@ -442,37 +327,21 @@
 
 	debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
 
-	debugfs_create_u32("timeout", 0644, d_spin_debug, &lock_timeout);
-
-	debugfs_create_u64("taken", 0444, d_spin_debug, &spinlock_stats.taken);
 	debugfs_create_u32("taken_slow", 0444, d_spin_debug,
-			   &spinlock_stats.taken_slow);
-	debugfs_create_u32("taken_slow_nested", 0444, d_spin_debug,
-			   &spinlock_stats.taken_slow_nested);
+			   &spinlock_stats.contention_stats[TAKEN_SLOW]);
 	debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
-			   &spinlock_stats.taken_slow_pickup);
+			   &spinlock_stats.contention_stats[TAKEN_SLOW_PICKUP]);
 	debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
-			   &spinlock_stats.taken_slow_spurious);
-	debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
-			   &spinlock_stats.taken_slow_irqenable);
+			   &spinlock_stats.contention_stats[TAKEN_SLOW_SPURIOUS]);
 
-	debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
 	debugfs_create_u32("released_slow", 0444, d_spin_debug,
-			   &spinlock_stats.released_slow);
+			   &spinlock_stats.contention_stats[RELEASED_SLOW]);
 	debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
-			   &spinlock_stats.released_slow_kicked);
+			   &spinlock_stats.contention_stats[RELEASED_SLOW_KICKED]);
 
-	debugfs_create_u64("time_spinning", 0444, d_spin_debug,
-			   &spinlock_stats.time_spinning);
 	debugfs_create_u64("time_blocked", 0444, d_spin_debug,
 			   &spinlock_stats.time_blocked);
-	debugfs_create_u64("time_total", 0444, d_spin_debug,
-			   &spinlock_stats.time_total);
 
-	debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
-				spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
-	debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
-				spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
 	debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
 				spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
 
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 86782c5..95f8c61 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -105,9 +105,9 @@
 /* Declare an asm function, along with symbols needed to make it
    inlineable */
 #define DECL_ASM(ret, name, ...)		\
-	ret name(__VA_ARGS__);			\
-	extern char name##_end[];		\
-	extern char name##_reloc[]		\
+	__visible ret name(__VA_ARGS__);	\
+	extern char name##_end[] __visible;	\
+	extern char name##_reloc[] __visible
 
 DECL_ASM(void, xen_irq_enable_direct, void);
 DECL_ASM(void, xen_irq_disable_direct, void);
@@ -115,11 +115,11 @@
 DECL_ASM(void, xen_restore_fl_direct, unsigned long);
 
 /* These are not functions, and cannot be called normally */
-void xen_iret(void);
-void xen_sysexit(void);
-void xen_sysret32(void);
-void xen_sysret64(void);
-void xen_adjust_exception_frame(void);
+__visible void xen_iret(void);
+__visible void xen_sysexit(void);
+__visible void xen_sysret32(void);
+__visible void xen_sysret64(void);
+__visible void xen_adjust_exception_frame(void);
 
 extern int xen_panic_handler_init(void);
 
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 290792a..e90c7c1 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -437,10 +437,10 @@
 	return &blkg->rl;
 }
 
-static int blkcg_reset_stats(struct cgroup *cgroup, struct cftype *cftype,
-			     u64 val)
+static int blkcg_reset_stats(struct cgroup_subsys_state *css,
+			     struct cftype *cftype, u64 val)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
+	struct blkcg *blkcg = css_to_blkcg(css);
 	struct blkcg_gq *blkg;
 	int i;
 
@@ -614,15 +614,13 @@
 {
 	struct blkcg_policy *pol = blkcg_policy[pd->plid];
 	struct blkcg_gq *pos_blkg;
-	struct cgroup *pos_cgrp;
-	u64 sum;
+	struct cgroup_subsys_state *pos_css;
+	u64 sum = 0;
 
 	lockdep_assert_held(pd->blkg->q->queue_lock);
 
-	sum = blkg_stat_read((void *)pd + off);
-
 	rcu_read_lock();
-	blkg_for_each_descendant_pre(pos_blkg, pos_cgrp, pd_to_blkg(pd)) {
+	blkg_for_each_descendant_pre(pos_blkg, pos_css, pd_to_blkg(pd)) {
 		struct blkg_policy_data *pos_pd = blkg_to_pd(pos_blkg, pol);
 		struct blkg_stat *stat = (void *)pos_pd + off;
 
@@ -649,16 +647,14 @@
 {
 	struct blkcg_policy *pol = blkcg_policy[pd->plid];
 	struct blkcg_gq *pos_blkg;
-	struct cgroup *pos_cgrp;
-	struct blkg_rwstat sum;
+	struct cgroup_subsys_state *pos_css;
+	struct blkg_rwstat sum = { };
 	int i;
 
 	lockdep_assert_held(pd->blkg->q->queue_lock);
 
-	sum = blkg_rwstat_read((void *)pd + off);
-
 	rcu_read_lock();
-	blkg_for_each_descendant_pre(pos_blkg, pos_cgrp, pd_to_blkg(pd)) {
+	blkg_for_each_descendant_pre(pos_blkg, pos_css, pd_to_blkg(pd)) {
 		struct blkg_policy_data *pos_pd = blkg_to_pd(pos_blkg, pol);
 		struct blkg_rwstat *rwstat = (void *)pos_pd + off;
 		struct blkg_rwstat tmp;
@@ -765,18 +761,18 @@
 
 /**
  * blkcg_css_offline - cgroup css_offline callback
- * @cgroup: cgroup of interest
+ * @css: css of interest
  *
- * This function is called when @cgroup is about to go away and responsible
- * for shooting down all blkgs associated with @cgroup.  blkgs should be
+ * This function is called when @css is about to go away and responsible
+ * for shooting down all blkgs associated with @css.  blkgs should be
  * removed while holding both q and blkcg locks.  As blkcg lock is nested
  * inside q lock, this function performs reverse double lock dancing.
  *
  * This is the blkcg counterpart of ioc_release_fn().
  */
-static void blkcg_css_offline(struct cgroup *cgroup)
+static void blkcg_css_offline(struct cgroup_subsys_state *css)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	spin_lock_irq(&blkcg->lock);
 
@@ -798,21 +794,21 @@
 	spin_unlock_irq(&blkcg->lock);
 }
 
-static void blkcg_css_free(struct cgroup *cgroup)
+static void blkcg_css_free(struct cgroup_subsys_state *css)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	if (blkcg != &blkcg_root)
 		kfree(blkcg);
 }
 
-static struct cgroup_subsys_state *blkcg_css_alloc(struct cgroup *cgroup)
+static struct cgroup_subsys_state *
+blkcg_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	static atomic64_t id_seq = ATOMIC64_INIT(0);
 	struct blkcg *blkcg;
-	struct cgroup *parent = cgroup->parent;
 
-	if (!parent) {
+	if (!parent_css) {
 		blkcg = &blkcg_root;
 		goto done;
 	}
@@ -883,14 +879,15 @@
  * 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 blkcg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static int blkcg_can_attach(struct cgroup_subsys_state *css,
+			    struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 	struct io_context *ioc;
 	int ret = 0;
 
 	/* task_lock() is needed to avoid races with exit_io_context() */
-	cgroup_taskset_for_each(task, cgrp, tset) {
+	cgroup_taskset_for_each(task, css, tset) {
 		task_lock(task);
 		ioc = task->io_context;
 		if (ioc && atomic_read(&ioc->nr_tasks) > 1)
@@ -1127,7 +1124,7 @@
 
 	/* kill the intf files first */
 	if (pol->cftypes)
-		cgroup_rm_cftypes(&blkio_subsys, pol->cftypes);
+		cgroup_rm_cftypes(pol->cftypes);
 
 	/* unregister and update blkgs */
 	blkcg_policy[pol->plid] = NULL;
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 8056c03..ae6969a 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -179,22 +179,20 @@
 void blkg_conf_finish(struct blkg_conf_ctx *ctx);
 
 
-static inline struct blkcg *cgroup_to_blkcg(struct cgroup *cgroup)
+static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css)
 {
-	return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id),
-			    struct blkcg, css);
+	return css ? container_of(css, struct blkcg, css) : NULL;
 }
 
 static inline struct blkcg *task_blkcg(struct task_struct *tsk)
 {
-	return container_of(task_subsys_state(tsk, blkio_subsys_id),
-			    struct blkcg, css);
+	return css_to_blkcg(task_css(tsk, blkio_subsys_id));
 }
 
 static inline struct blkcg *bio_blkcg(struct bio *bio)
 {
 	if (bio && bio->bi_css)
-		return container_of(bio->bi_css, struct blkcg, css);
+		return css_to_blkcg(bio->bi_css);
 	return task_blkcg(current);
 }
 
@@ -206,9 +204,7 @@
  */
 static inline struct blkcg *blkcg_parent(struct blkcg *blkcg)
 {
-	struct cgroup *pcg = blkcg->css.cgroup->parent;
-
-	return pcg ? cgroup_to_blkcg(pcg) : NULL;
+	return css_to_blkcg(css_parent(&blkcg->css));
 }
 
 /**
@@ -288,32 +284,33 @@
 /**
  * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
  * @d_blkg: loop cursor pointing to the current descendant
- * @pos_cgrp: used for iteration
+ * @pos_css: used for iteration
  * @p_blkg: target blkg to walk descendants of
  *
  * Walk @c_blkg through the descendants of @p_blkg.  Must be used with RCU
  * read locked.  If called under either blkcg or queue lock, the iteration
  * is guaranteed to include all and only online blkgs.  The caller may
- * update @pos_cgrp by calling cgroup_rightmost_descendant() to skip
- * subtree.
+ * update @pos_css by calling css_rightmost_descendant() to skip subtree.
+ * @p_blkg is included in the iteration and the first node to be visited.
  */
-#define blkg_for_each_descendant_pre(d_blkg, pos_cgrp, p_blkg)		\
-	cgroup_for_each_descendant_pre((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
-		if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
+#define blkg_for_each_descendant_pre(d_blkg, pos_css, p_blkg)		\
+	css_for_each_descendant_pre((pos_css), &(p_blkg)->blkcg->css)	\
+		if (((d_blkg) = __blkg_lookup(css_to_blkcg(pos_css),	\
 					      (p_blkg)->q, false)))
 
 /**
  * blkg_for_each_descendant_post - post-order walk of a blkg's descendants
  * @d_blkg: loop cursor pointing to the current descendant
- * @pos_cgrp: used for iteration
+ * @pos_css: used for iteration
  * @p_blkg: target blkg to walk descendants of
  *
  * Similar to blkg_for_each_descendant_pre() but performs post-order
- * traversal instead.  Synchronization rules are the same.
+ * traversal instead.  Synchronization rules are the same.  @p_blkg is
+ * included in the iteration and the last node to be visited.
  */
-#define blkg_for_each_descendant_post(d_blkg, pos_cgrp, p_blkg)		\
-	cgroup_for_each_descendant_post((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
-		if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
+#define blkg_for_each_descendant_post(d_blkg, pos_css, p_blkg)		\
+	css_for_each_descendant_post((pos_css), &(p_blkg)->blkcg->css)	\
+		if (((d_blkg) = __blkg_lookup(css_to_blkcg(pos_css),	\
 					      (p_blkg)->q, false)))
 
 /**
@@ -576,7 +573,6 @@
 static inline void blkcg_deactivate_policy(struct request_queue *q,
 					   const struct blkcg_policy *pol) { }
 
-static inline struct blkcg *cgroup_to_blkcg(struct cgroup *cgroup) { return NULL; }
 static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; }
 
 static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg,
diff --git a/block/blk-core.c b/block/blk-core.c
index 93a18d1..c045053 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2318,6 +2318,12 @@
 		case -ETIMEDOUT:
 			error_type = "timeout";
 			break;
+		case -ENOSPC:
+			error_type = "critical space allocation";
+			break;
+		case -ENODATA:
+			error_type = "critical medium";
+			break;
 		case -EIO:
 		default:
 			error_type = "I/O";
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 08a32df..8331aba 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -1293,10 +1293,10 @@
 	return __blkg_prfill_rwstat(sf, pd, &rwstat);
 }
 
-static int tg_print_cpu_rwstat(struct cgroup *cgrp, struct cftype *cft,
-			       struct seq_file *sf)
+static int tg_print_cpu_rwstat(struct cgroup_subsys_state *css,
+			       struct cftype *cft, struct seq_file *sf)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	blkcg_print_blkgs(sf, blkcg, tg_prfill_cpu_rwstat, &blkcg_policy_throtl,
 			  cft->private, true);
@@ -1325,31 +1325,31 @@
 	return __blkg_prfill_u64(sf, pd, v);
 }
 
-static int tg_print_conf_u64(struct cgroup *cgrp, struct cftype *cft,
-			     struct seq_file *sf)
+static int tg_print_conf_u64(struct cgroup_subsys_state *css,
+			     struct cftype *cft, struct seq_file *sf)
 {
-	blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp), tg_prfill_conf_u64,
+	blkcg_print_blkgs(sf, css_to_blkcg(css), tg_prfill_conf_u64,
 			  &blkcg_policy_throtl, cft->private, false);
 	return 0;
 }
 
-static int tg_print_conf_uint(struct cgroup *cgrp, struct cftype *cft,
-			      struct seq_file *sf)
+static int tg_print_conf_uint(struct cgroup_subsys_state *css,
+			      struct cftype *cft, struct seq_file *sf)
 {
-	blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp), tg_prfill_conf_uint,
+	blkcg_print_blkgs(sf, css_to_blkcg(css), tg_prfill_conf_uint,
 			  &blkcg_policy_throtl, cft->private, false);
 	return 0;
 }
 
-static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
-		       bool is_u64)
+static int tg_set_conf(struct cgroup_subsys_state *css, struct cftype *cft,
+		       const char *buf, bool is_u64)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 	struct blkg_conf_ctx ctx;
 	struct throtl_grp *tg;
 	struct throtl_service_queue *sq;
 	struct blkcg_gq *blkg;
-	struct cgroup *pos_cgrp;
+	struct cgroup_subsys_state *pos_css;
 	int ret;
 
 	ret = blkg_conf_prep(blkcg, &blkcg_policy_throtl, buf, &ctx);
@@ -1379,8 +1379,7 @@
 	 * restrictions in the whole hierarchy and allows them to bypass
 	 * blk-throttle.
 	 */
-	tg_update_has_rules(tg);
-	blkg_for_each_descendant_pre(blkg, pos_cgrp, ctx.blkg)
+	blkg_for_each_descendant_pre(blkg, pos_css, ctx.blkg)
 		tg_update_has_rules(blkg_to_tg(blkg));
 
 	/*
@@ -1403,16 +1402,16 @@
 	return 0;
 }
 
-static int tg_set_conf_u64(struct cgroup *cgrp, struct cftype *cft,
+static int tg_set_conf_u64(struct cgroup_subsys_state *css, struct cftype *cft,
 			   const char *buf)
 {
-	return tg_set_conf(cgrp, cft, buf, true);
+	return tg_set_conf(css, cft, buf, true);
 }
 
-static int tg_set_conf_uint(struct cgroup *cgrp, struct cftype *cft,
+static int tg_set_conf_uint(struct cgroup_subsys_state *css, struct cftype *cft,
 			    const char *buf)
 {
-	return tg_set_conf(cgrp, cft, buf, false);
+	return tg_set_conf(css, cft, buf, false);
 }
 
 static struct cftype throtl_files[] = {
@@ -1623,7 +1622,7 @@
 {
 	struct throtl_data *td = q->td;
 	struct blkcg_gq *blkg;
-	struct cgroup *pos_cgrp;
+	struct cgroup_subsys_state *pos_css;
 	struct bio *bio;
 	int rw;
 
@@ -1636,11 +1635,9 @@
 	 * better to walk service_queue tree directly but blkg walk is
 	 * easier.
 	 */
-	blkg_for_each_descendant_post(blkg, pos_cgrp, td->queue->root_blkg)
+	blkg_for_each_descendant_post(blkg, pos_css, td->queue->root_blkg)
 		tg_drain_bios(&blkg_to_tg(blkg)->service_queue);
 
-	tg_drain_bios(&td_root_tg(td)->service_queue);
-
 	/* finally, transfer bios from top-level tg's into the td */
 	tg_drain_bios(&td->service_queue);
 
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index d5bbdcf..dabb9d0 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1607,12 +1607,11 @@
 	return __blkg_prfill_u64(sf, pd, cfqg->dev_weight);
 }
 
-static int cfqg_print_weight_device(struct cgroup *cgrp, struct cftype *cft,
-				    struct seq_file *sf)
+static int cfqg_print_weight_device(struct cgroup_subsys_state *css,
+				    struct cftype *cft, struct seq_file *sf)
 {
-	blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp),
-			  cfqg_prfill_weight_device, &blkcg_policy_cfq, 0,
-			  false);
+	blkcg_print_blkgs(sf, css_to_blkcg(css), cfqg_prfill_weight_device,
+			  &blkcg_policy_cfq, 0, false);
 	return 0;
 }
 
@@ -1626,35 +1625,34 @@
 	return __blkg_prfill_u64(sf, pd, cfqg->dev_leaf_weight);
 }
 
-static int cfqg_print_leaf_weight_device(struct cgroup *cgrp,
+static int cfqg_print_leaf_weight_device(struct cgroup_subsys_state *css,
 					 struct cftype *cft,
 					 struct seq_file *sf)
 {
-	blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp),
-			  cfqg_prfill_leaf_weight_device, &blkcg_policy_cfq, 0,
-			  false);
+	blkcg_print_blkgs(sf, css_to_blkcg(css), cfqg_prfill_leaf_weight_device,
+			  &blkcg_policy_cfq, 0, false);
 	return 0;
 }
 
-static int cfq_print_weight(struct cgroup *cgrp, struct cftype *cft,
+static int cfq_print_weight(struct cgroup_subsys_state *css, struct cftype *cft,
 			    struct seq_file *sf)
 {
-	seq_printf(sf, "%u\n", cgroup_to_blkcg(cgrp)->cfq_weight);
+	seq_printf(sf, "%u\n", css_to_blkcg(css)->cfq_weight);
 	return 0;
 }
 
-static int cfq_print_leaf_weight(struct cgroup *cgrp, struct cftype *cft,
-				 struct seq_file *sf)
+static int cfq_print_leaf_weight(struct cgroup_subsys_state *css,
+				 struct cftype *cft, struct seq_file *sf)
 {
-	seq_printf(sf, "%u\n",
-		   cgroup_to_blkcg(cgrp)->cfq_leaf_weight);
+	seq_printf(sf, "%u\n", css_to_blkcg(css)->cfq_leaf_weight);
 	return 0;
 }
 
-static int __cfqg_set_weight_device(struct cgroup *cgrp, struct cftype *cft,
-				    const char *buf, bool is_leaf_weight)
+static int __cfqg_set_weight_device(struct cgroup_subsys_state *css,
+				    struct cftype *cft, const char *buf,
+				    bool is_leaf_weight)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 	struct blkg_conf_ctx ctx;
 	struct cfq_group *cfqg;
 	int ret;
@@ -1680,22 +1678,22 @@
 	return ret;
 }
 
-static int cfqg_set_weight_device(struct cgroup *cgrp, struct cftype *cft,
-				  const char *buf)
+static int cfqg_set_weight_device(struct cgroup_subsys_state *css,
+				  struct cftype *cft, const char *buf)
 {
-	return __cfqg_set_weight_device(cgrp, cft, buf, false);
+	return __cfqg_set_weight_device(css, cft, buf, false);
 }
 
-static int cfqg_set_leaf_weight_device(struct cgroup *cgrp, struct cftype *cft,
-				       const char *buf)
+static int cfqg_set_leaf_weight_device(struct cgroup_subsys_state *css,
+				       struct cftype *cft, const char *buf)
 {
-	return __cfqg_set_weight_device(cgrp, cft, buf, true);
+	return __cfqg_set_weight_device(css, cft, buf, true);
 }
 
-static int __cfq_set_weight(struct cgroup *cgrp, struct cftype *cft, u64 val,
-			    bool is_leaf_weight)
+static int __cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
+			    u64 val, bool is_leaf_weight)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 	struct blkcg_gq *blkg;
 
 	if (val < CFQ_WEIGHT_MIN || val > CFQ_WEIGHT_MAX)
@@ -1727,30 +1725,32 @@
 	return 0;
 }
 
-static int cfq_set_weight(struct cgroup *cgrp, struct cftype *cft, u64 val)
+static int cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft,
+			  u64 val)
 {
-	return __cfq_set_weight(cgrp, cft, val, false);
+	return __cfq_set_weight(css, cft, val, false);
 }
 
-static int cfq_set_leaf_weight(struct cgroup *cgrp, struct cftype *cft, u64 val)
+static int cfq_set_leaf_weight(struct cgroup_subsys_state *css,
+			       struct cftype *cft, u64 val)
 {
-	return __cfq_set_weight(cgrp, cft, val, true);
+	return __cfq_set_weight(css, cft, val, true);
 }
 
-static int cfqg_print_stat(struct cgroup *cgrp, struct cftype *cft,
+static int cfqg_print_stat(struct cgroup_subsys_state *css, struct cftype *cft,
 			   struct seq_file *sf)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	blkcg_print_blkgs(sf, blkcg, blkg_prfill_stat, &blkcg_policy_cfq,
 			  cft->private, false);
 	return 0;
 }
 
-static int cfqg_print_rwstat(struct cgroup *cgrp, struct cftype *cft,
-			     struct seq_file *sf)
+static int cfqg_print_rwstat(struct cgroup_subsys_state *css,
+			     struct cftype *cft, struct seq_file *sf)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	blkcg_print_blkgs(sf, blkcg, blkg_prfill_rwstat, &blkcg_policy_cfq,
 			  cft->private, true);
@@ -1773,20 +1773,20 @@
 	return __blkg_prfill_rwstat(sf, pd, &sum);
 }
 
-static int cfqg_print_stat_recursive(struct cgroup *cgrp, struct cftype *cft,
-				     struct seq_file *sf)
+static int cfqg_print_stat_recursive(struct cgroup_subsys_state *css,
+				     struct cftype *cft, struct seq_file *sf)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	blkcg_print_blkgs(sf, blkcg, cfqg_prfill_stat_recursive,
 			  &blkcg_policy_cfq, cft->private, false);
 	return 0;
 }
 
-static int cfqg_print_rwstat_recursive(struct cgroup *cgrp, struct cftype *cft,
-				       struct seq_file *sf)
+static int cfqg_print_rwstat_recursive(struct cgroup_subsys_state *css,
+				       struct cftype *cft, struct seq_file *sf)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	blkcg_print_blkgs(sf, blkcg, cfqg_prfill_rwstat_recursive,
 			  &blkcg_policy_cfq, cft->private, true);
@@ -1810,10 +1810,10 @@
 }
 
 /* print avg_queue_size */
-static int cfqg_print_avg_queue_size(struct cgroup *cgrp, struct cftype *cft,
-				     struct seq_file *sf)
+static int cfqg_print_avg_queue_size(struct cgroup_subsys_state *css,
+				     struct cftype *cft, struct seq_file *sf)
 {
-	struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
+	struct blkcg *blkcg = css_to_blkcg(css);
 
 	blkcg_print_blkgs(sf, blkcg, cfqg_prfill_avg_queue_size,
 			  &blkcg_policy_cfq, 0, false);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 100bd72..3278a21 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -91,24 +91,6 @@
 	  Thus this option is a debug option that helps to write ACPI drivers
 	  and can be used to identify ACPI code or EC firmware bugs.
 
-config ACPI_PROC_EVENT
-	bool "Deprecated /proc/acpi/event support"
-	depends on PROC_FS
-	default y
-	help
-	  A user-space daemon, acpid, typically reads /proc/acpi/event
-	  and handles all ACPI-generated events.
-
-	  These events are now delivered to user-space either
-	  via the input layer or as netlink events.
-
-	  This build option enables the old code for legacy
-	  user-space implementation.  After some time, this will
-	  be moved under CONFIG_ACPI_PROCFS, and then deleted.
-
-	  Say Y here to retain the old behaviour.  Say N if your
-	  user-space is newer than kernel 2.6.23 (September 2007).
-
 config ACPI_AC
 	tristate "AC Adapter"
 	depends on X86
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 4f4e741..f37beaa3 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -267,7 +267,6 @@
 			msleep(ac_sleep_before_get_state_ms);
 
 		acpi_ac_get_state(ac);
-		acpi_bus_generate_proc_event(device, event, (u32) ac->state);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event,
 						  (u32) ac->state);
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 27bb6a9..fc6008f 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -231,16 +231,19 @@
 static unsigned int ps_tsk_num;
 static int create_power_saving_task(void)
 {
-	int rc = -ENOMEM;
+	int rc;
 
 	ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
 		(void *)(unsigned long)ps_tsk_num,
 		"acpi_pad/%d", ps_tsk_num);
-	rc = PTR_RET(ps_tsks[ps_tsk_num]);
-	if (!rc)
-		ps_tsk_num++;
-	else
+
+	if (IS_ERR(ps_tsks[ps_tsk_num])) {
+		rc = PTR_ERR(ps_tsks[ps_tsk_num]);
 		ps_tsks[ps_tsk_num] = NULL;
+	} else {
+		rc = 0;
+		ps_tsk_num++;
+	}
 
 	return rc;
 }
@@ -452,7 +455,6 @@
 	switch (event) {
 	case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
 		acpi_pad_handle_notify(handle);
-		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 			dev_name(&device->dev), event, 0);
 		break;
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index fafec5d..1bde127 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -52,7 +52,7 @@
 	struct platform_device_info pdevinfo;
 	struct resource_list_entry *rentry;
 	struct list_head resource_list;
-	struct resource *resources;
+	struct resource *resources = NULL;
 	int count;
 
 	/* If the ACPI node already has a physical device attached, skip it. */
@@ -61,20 +61,22 @@
 
 	INIT_LIST_HEAD(&resource_list);
 	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
-	if (count <= 0)
+	if (count < 0) {
 		return 0;
+	} else if (count > 0) {
+		resources = kmalloc(count * sizeof(struct resource),
+				    GFP_KERNEL);
+		if (!resources) {
+			dev_err(&adev->dev, "No memory for resources\n");
+			acpi_dev_free_resource_list(&resource_list);
+			return -ENOMEM;
+		}
+		count = 0;
+		list_for_each_entry(rentry, &resource_list, node)
+			resources[count++] = rentry->res;
 
-	resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
-	if (!resources) {
-		dev_err(&adev->dev, "No memory for resources\n");
 		acpi_dev_free_resource_list(&resource_list);
-		return -ENOMEM;
 	}
-	count = 0;
-	list_for_each_entry(rentry, &resource_list, node)
-		resources[count++] = rentry->res;
-
-	acpi_dev_free_resource_list(&resource_list);
 
 	memset(&pdevinfo, 0, sizeof(pdevinfo));
 	/*
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 5a74a9c..f29e06e 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -178,14 +178,17 @@
 	if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
 		return -ENODEV;
 
+	cpu_maps_update_begin();
+	cpu_hotplug_begin();
+
 	ret = acpi_map_lsapic(pr->handle, &pr->id);
 	if (ret)
-		return ret;
+		goto out;
 
 	ret = arch_register_cpu(pr->id);
 	if (ret) {
 		acpi_unmap_lsapic(pr->id);
-		return ret;
+		goto out;
 	}
 
 	/*
@@ -195,7 +198,11 @@
 	 */
 	pr_info("CPU%d has been hot-added\n", pr->id);
 	pr->flags.need_hotplug_init = 1;
-	return 0;
+
+out:
+	cpu_hotplug_done();
+	cpu_maps_update_done();
+	return ret;
 }
 #else
 static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
@@ -452,11 +459,15 @@
 	per_cpu(processor_device_array, pr->id) = NULL;
 	per_cpu(processors, pr->id) = NULL;
 
+	cpu_maps_update_begin();
+	cpu_hotplug_begin();
+
 	/* Remove the CPU. */
-	get_online_cpus();
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
-	put_online_cpus();
+
+	cpu_hotplug_done();
+	cpu_maps_update_done();
 
 	try_offline_node(cpu_to_node(pr->id));
 
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index b8d3811..90e846f 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -138,6 +138,12 @@
  */
 u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE);
 
+/*
+ * We keep track of the latest version of Windows that has been requested by
+ * the BIOS.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_osi_data, 0);
+
 /* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
 
 struct acpi_table_fadt acpi_gbl_FADT;
@@ -285,7 +291,6 @@
 ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
 ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
 ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN u8 acpi_gbl_osi_data;
 ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
 ACPI_EXTERN struct acpi_address_range
     *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX];
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index d4a49016..0ed0066 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -942,6 +942,9 @@
 
 #define ACPI_OSI_INVALID                0x01
 #define ACPI_OSI_DYNAMIC                0x02
+#define ACPI_OSI_FEATURE                0x04
+#define ACPI_OSI_DEFAULT_INVALID        0x08
+#define ACPI_OSI_OPTIONAL_FEATURE       (ACPI_OSI_FEATURE | ACPI_OSI_DEFAULT_INVALID | ACPI_OSI_INVALID)
 
 struct acpi_port_info {
 	char *name;
@@ -1030,6 +1033,7 @@
 	u8 type;
 	u8 flags;
 	u8 resolved;
+	u8 emitted;
 };
 
 /* Values for Flags field above */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index b83dc32..40b04bd 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -104,8 +104,8 @@
 		       acpi_handle start_object,
 		       u32 max_depth,
 		       u32 flags,
-		       acpi_walk_callback pre_order_visit,
-		       acpi_walk_callback post_order_visit,
+		       acpi_walk_callback descending_callback,
+		       acpi_walk_callback ascending_callback,
 		       void *context, void **return_value);
 
 struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 7755e91..c54f42c 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -47,6 +47,13 @@
 acpi_status acpi_allocate_root_table(u32 initial_table_count);
 
 /*
+ * tbxfroot - Root pointer utilities
+ */
+acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
+u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
+
+/*
  * tbfadt - FADT parse/convert/validate
  */
 void acpi_tb_parse_fadt(u32 table_index);
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 3c76ede..d5a62a6 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -470,6 +470,8 @@
 
 acpi_status acpi_ut_remove_interface(acpi_string interface_name);
 
+acpi_status acpi_ut_update_interfaces(u8 action);
+
 struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
 
 acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
@@ -616,7 +618,7 @@
 
 acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer);
 
-void acpi_ut_print_string(char *string, u8 max_length);
+void acpi_ut_print_string(char *string, u16 max_length);
 
 void ut_convert_backslashes(char *pathname);
 
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 9037f17..7842700 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -125,7 +125,6 @@
 		/* GPE block 0 exists (has both length and address > 0) */
 
 		register_count0 = (u16)(acpi_gbl_FADT.gpe0_block_length / 2);
-
 		gpe_number_max =
 		    (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
 
@@ -204,16 +203,6 @@
 		goto cleanup;
 	}
 
-	/* Check for Max GPE number out-of-range */
-
-	if (gpe_number_max > ACPI_GPE_MAX) {
-		ACPI_ERROR((AE_INFO,
-			    "Maximum GPE number from FADT is too large: 0x%X",
-			    gpe_number_max));
-		status = AE_BAD_VALUE;
-		goto cleanup;
-	}
-
       cleanup:
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 	return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index c740f24..4d046fa 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -338,6 +338,7 @@
 {
 	u8 *target;
 	char *name;
+	const char *reference_name;
 	u8 count;
 
 	if (!info) {
@@ -426,10 +427,9 @@
 
 		case ACPI_EXD_REFERENCE:
 
+			reference_name = acpi_ut_get_reference_name(obj_desc);
 			acpi_ex_out_string("Class Name",
-					   ACPI_CAST_PTR(char,
-							 acpi_ut_get_reference_name
-							 (obj_desc)));
+					   ACPI_CAST_PTR(char, reference_name));
 			acpi_ex_dump_reference_obj(obj_desc);
 			break;
 
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index 814b4a3..2cdd41d 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -962,10 +962,17 @@
 					 */
 					return_desc =
 					    *(operand[0]->reference.where);
-					if (return_desc) {
-						acpi_ut_add_reference
-						    (return_desc);
+					if (!return_desc) {
+						/*
+						 * Element is NULL, do not allow the dereference.
+						 * This provides compatibility with other ACPI
+						 * implementations.
+						 */
+						return_ACPI_STATUS
+						    (AE_AML_UNINITIALIZED_ELEMENT);
 					}
+
+					acpi_ut_add_reference(return_desc);
 					break;
 
 				default:
@@ -990,11 +997,40 @@
 									 acpi_namespace_node
 									 *)
 									return_desc);
+					if (!return_desc) {
+						break;
+					}
+
+					/*
+					 * June 2013:
+					 * buffer_fields/field_units require additional resolution
+					 */
+					switch (return_desc->common.type) {
+					case ACPI_TYPE_BUFFER_FIELD:
+					case ACPI_TYPE_LOCAL_REGION_FIELD:
+					case ACPI_TYPE_LOCAL_BANK_FIELD:
+					case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+						status =
+						    acpi_ex_read_data_from_field
+						    (walk_state, return_desc,
+						     &temp_desc);
+						if (ACPI_FAILURE(status)) {
+							goto cleanup;
+						}
+
+						return_desc = temp_desc;
+						break;
+
+					default:
+
+						/* Add another reference to the object */
+
+						acpi_ut_add_reference
+						    (return_desc);
+						break;
+					}
 				}
-
-				/* Add another reference to the object! */
-
-				acpi_ut_add_reference(return_desc);
 				break;
 
 			default:
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 5e5f762..4140768 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -43,6 +43,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <linux/acpi.h>
 #include "accommon.h"
 
 #define _COMPONENT          ACPI_HARDWARE
@@ -128,6 +129,14 @@
 
 	ACPI_FLUSH_CPU_CACHE();
 
+	status = acpi_os_prepare_extended_sleep(sleep_state,
+						acpi_gbl_sleep_type_a,
+						acpi_gbl_sleep_type_b);
+	if (ACPI_SKIP(status))
+		return_ACPI_STATUS(AE_OK);
+	if (ACPI_FAILURE(status))
+		return_ACPI_STATUS(status);
+
 	/*
 	 * Set the SLP_TYP and SLP_EN bits.
 	 *
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 0c1a8bb..2d7d22e 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -100,8 +100,13 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
-	status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
+	/* ACPI 5.0A: PM Timer is optional */
 
+	if (!acpi_gbl_FADT.xpm_timer_block.address) {
+		return_ACPI_STATUS(AE_SUPPORT);
+	}
+
+	status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
 	return_ACPI_STATUS(status);
 }
 
@@ -148,6 +153,12 @@
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
+	/* ACPI 5.0A: PM Timer is optional */
+
+	if (!acpi_gbl_FADT.xpm_timer_block.address) {
+		return_ACPI_STATUS(AE_SUPPORT);
+	}
+
 	/*
 	 * Compute Tick Delta:
 	 * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 24b71a0..098e766 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -151,6 +151,15 @@
 	}
 
 	/*
+	 *
+	 * 4) If there is no return value and it is optional, just return
+	 * AE_OK (_WAK).
+	 */
+	if (!(*return_object_ptr)) {
+		goto exit;
+	}
+
+	/*
 	 * For returned Package objects, check the type of all sub-objects.
 	 * Note: Package may have been newly created by call above.
 	 */
@@ -268,7 +277,12 @@
 
 	acpi_ut_get_expected_return_types(type_buffer, expected_btypes);
 
-	if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
+	if (!return_object) {
+		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+				      info->node_flags,
+				      "Expected return object of type %s",
+				      type_buffer));
+	} else if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
 		ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
 				      info->node_flags,
 				      "Return type mismatch - found %s, expected %s",
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index e70911a..e81f15e 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -156,9 +156,9 @@
  *              max_depth           - Depth to which search is to reach
  *              flags               - Whether to unlock the NS before invoking
  *                                    the callback routine
- *              pre_order_visit     - Called during tree pre-order visit
+ *              descending_callback - Called during tree descent
  *                                    when an object of "Type" is found
- *              post_order_visit    - Called during tree post-order visit
+ *              ascending_callback  - Called during tree ascent
  *                                    when an object of "Type" is found
  *              context             - Passed to user function(s) above
  *              return_value        - from the user_function if terminated
@@ -185,8 +185,8 @@
 		       acpi_handle start_node,
 		       u32 max_depth,
 		       u32 flags,
-		       acpi_walk_callback pre_order_visit,
-		       acpi_walk_callback post_order_visit,
+		       acpi_walk_callback descending_callback,
+		       acpi_walk_callback ascending_callback,
 		       void *context, void **return_value)
 {
 	acpi_status status;
@@ -255,22 +255,22 @@
 			}
 
 			/*
-			 * Invoke the user function, either pre-order or post-order
+			 * Invoke the user function, either descending, ascending,
 			 * or both.
 			 */
 			if (!node_previously_visited) {
-				if (pre_order_visit) {
+				if (descending_callback) {
 					status =
-					    pre_order_visit(child_node, level,
-							    context,
-							    return_value);
+					    descending_callback(child_node,
+								level, context,
+								return_value);
 				}
 			} else {
-				if (post_order_visit) {
+				if (ascending_callback) {
 					status =
-					    post_order_visit(child_node, level,
-							     context,
-							     return_value);
+					    ascending_callback(child_node,
+							       level, context,
+							       return_value);
 				}
 			}
 
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index f553cfd..b38b4b0 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -533,9 +533,9 @@
  * PARAMETERS:  type                - acpi_object_type to search for
  *              start_object        - Handle in namespace where search begins
  *              max_depth           - Depth to which search is to reach
- *              pre_order_visit     - Called during tree pre-order visit
+ *              descending_callback - Called during tree descent
  *                                    when an object of "Type" is found
- *              post_order_visit    - Called during tree post-order visit
+ *              ascending_callback  - Called during tree ascent
  *                                    when an object of "Type" is found
  *              context             - Passed to user function(s) above
  *              return_value        - Location where return value of
@@ -563,8 +563,8 @@
 acpi_walk_namespace(acpi_object_type type,
 		    acpi_handle start_object,
 		    u32 max_depth,
-		    acpi_walk_callback pre_order_visit,
-		    acpi_walk_callback post_order_visit,
+		    acpi_walk_callback descending_callback,
+		    acpi_walk_callback ascending_callback,
 		    void *context, void **return_value)
 {
 	acpi_status status;
@@ -574,7 +574,7 @@
 	/* Parameter validation */
 
 	if ((type > ACPI_TYPE_LOCAL_MAX) ||
-	    (!max_depth) || (!pre_order_visit && !post_order_visit)) {
+	    (!max_depth) || (!descending_callback && !ascending_callback)) {
 		return_ACPI_STATUS(AE_BAD_PARAMETER);
 	}
 
@@ -606,9 +606,9 @@
 	}
 
 	status = acpi_ns_walk_namespace(type, start_object, max_depth,
-					ACPI_NS_WALK_UNLOCK, pre_order_visit,
-					post_order_visit, context,
-					return_value);
+					ACPI_NS_WALK_UNLOCK,
+					descending_callback, ascending_callback,
+					context, return_value);
 
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index f3a4d95..83c1644 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -158,6 +158,7 @@
 {
 	acpi_status status;
 	struct acpi_namespace_node *node;
+	char *node_name;
 
 	/* Parameter validation */
 
@@ -202,7 +203,8 @@
 
 	/* Just copy the ACPI name from the Node and zero terminate it */
 
-	ACPI_MOVE_NAME(buffer->pointer, acpi_ut_get_node_name(node));
+	node_name = acpi_ut_get_node_name(node);
+	ACPI_MOVE_NAME(buffer->pointer, node_name);
 	((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0;
 	status = AE_OK;
 
@@ -379,9 +381,14 @@
 		 * Get extra info for ACPI Device/Processor objects only:
 		 * Run the _STA, _ADR and, sx_w, and _sx_d methods.
 		 *
-		 * Note: none of these methods are required, so they may or may
+		 * Notes: none of these methods are required, so they may or may
 		 * not be present for this device. The Info->Valid bitfield is used
 		 * to indicate which methods were found and run successfully.
+		 *
+		 * For _STA, if the method does not exist, then (as per the ACPI
+		 * specification), the returned current_status flags will indicate
+		 * that the device is present/functional/enabled. Otherwise, the
+		 * current_status flags reflect the value returned from _STA.
 		 */
 
 		/* Execute the Device._STA method */
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 33b00d2..9d99f21 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -117,7 +117,7 @@
 	 ACPI_FADT_OFFSET(pm_timer_block),
 	 ACPI_FADT_OFFSET(pm_timer_length),
 	 ACPI_PM_TIMER_WIDTH,
-	 ACPI_FADT_REQUIRED},
+	 ACPI_FADT_SEPARATE_LENGTH},	/* ACPI 5.0A: Timer is optional */
 
 	{"Gpe0Block",
 	 ACPI_FADT_OFFSET(xgpe0_block),
@@ -574,7 +574,7 @@
 
 		if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
 			/*
-			 * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+			 * Field is required (Pm1a_event, Pm1a_control).
 			 * Both the address and length must be non-zero.
 			 */
 			if (!address64->address || !length) {
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 7c2ecfb..948c95e 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -48,11 +48,6 @@
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbxfroot")
 
-/* Local prototypes */
-static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
-
-static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_validate_rsdp
@@ -64,8 +59,7 @@
  * DESCRIPTION: Validate the RSDP (ptr)
  *
  ******************************************************************************/
-
-static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
+acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
 {
 
 	/*
@@ -74,7 +68,7 @@
 	 * Note: Sometimes there exists more than one RSDP in memory; the valid
 	 * RSDP has a valid checksum, all others have an invalid checksum.
 	 */
-	if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP,
+	if (ACPI_STRNCMP((char *)rsdp->signature, ACPI_SIG_RSDP,
 			 sizeof(ACPI_SIG_RSDP) - 1) != 0) {
 
 		/* Nope, BAD Signature */
@@ -231,7 +225,7 @@
  * DESCRIPTION: Search a block of memory for the RSDP signature
  *
  ******************************************************************************/
-static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
+u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)
 {
 	acpi_status status;
 	u8 *mem_rover;
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index ee83adb..4fd6897 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -239,7 +239,8 @@
  * RETURN:      Status
  *
  * DESCRIPTION: Executes _STA for selected device and stores results in
- *              *Flags.
+ *              *Flags. If _STA does not exist, then the device is assumed
+ *              to be present/functional/enabled (as per the ACPI spec).
  *
  *              NOTE: Internal function, no parameter validation
  *
@@ -257,6 +258,11 @@
 					 ACPI_BTYPE_INTEGER, &obj_desc);
 	if (ACPI_FAILURE(status)) {
 		if (AE_NOT_FOUND == status) {
+			/*
+			 * if _STA does not exist, then (as per the ACPI specification),
+			 * the returned flags will indicate that the device is present,
+			 * functional, and enabled.
+			 */
 			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
 					  "_STA on %4.4s was not found, assuming device is present\n",
 					  acpi_ut_get_node_name(device_node)));
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index f736448..d6f26bf 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -336,7 +336,6 @@
 	acpi_gbl_trace_dbg_layer = 0;
 	acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
 	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
-	acpi_gbl_osi_data = 0;
 	acpi_gbl_osi_mutex = NULL;
 	acpi_gbl_reg_methods_executed = FALSE;
 
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 7e80772..8856bd3 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -77,21 +77,20 @@
 
 	/* Feature Group Strings */
 
-	{"Extended Address Space Descriptor", NULL, 0, 0}
+	{"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0},
 
 	/*
 	 * All "optional" feature group strings (features that are implemented
-	 * by the host) should be dynamically added by the host via
-	 * acpi_install_interface and should not be manually added here.
-	 *
-	 * Examples of optional feature group strings:
-	 *
-	 * "Module Device"
-	 * "Processor Device"
-	 * "3.0 Thermal Model"
-	 * "3.0 _SCP Extensions"
-	 * "Processor Aggregator Device"
+	 * by the host) should be dynamically modified to VALID by the host via
+	 * acpi_install_interface or acpi_update_interfaces. Such optional feature
+	 * group strings are set as INVALID by default here.
 	 */
+
+	{"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+	{"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+	{"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+	{"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
+	{"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}
 };
 
 /*******************************************************************************
@@ -158,11 +157,20 @@
 	while (next_interface) {
 		acpi_gbl_supported_interfaces = next_interface->next;
 
-		/* Only interfaces added at runtime can be freed */
-
 		if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+
+			/* Only interfaces added at runtime can be freed */
+
 			ACPI_FREE(next_interface->name);
 			ACPI_FREE(next_interface);
+		} else {
+			/* Interface is in static list. Reset it to invalid or valid. */
+
+			if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) {
+				next_interface->flags |= ACPI_OSI_INVALID;
+			} else {
+				next_interface->flags &= ~ACPI_OSI_INVALID;
+			}
 		}
 
 		next_interface = acpi_gbl_supported_interfaces;
@@ -278,6 +286,49 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ut_update_interfaces
+ *
+ * PARAMETERS:  action              - Actions to be performed during the
+ *                                    update
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
+ *              strings or/and feature group strings.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_update_interfaces(u8 action)
+{
+	struct acpi_interface_info *next_interface;
+
+	next_interface = acpi_gbl_supported_interfaces;
+	while (next_interface) {
+		if (((next_interface->flags & ACPI_OSI_FEATURE) &&
+		     (action & ACPI_FEATURE_STRINGS)) ||
+		    (!(next_interface->flags & ACPI_OSI_FEATURE) &&
+		     (action & ACPI_VENDOR_STRINGS))) {
+			if (action & ACPI_DISABLE_INTERFACES) {
+
+				/* Mark the interfaces as invalid */
+
+				next_interface->flags |= ACPI_OSI_INVALID;
+			} else {
+				/* Mark the interfaces as valid */
+
+				next_interface->flags &= ~ACPI_OSI_INVALID;
+			}
+		}
+
+		next_interface = next_interface->next;
+	}
+
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ut_get_interface
  *
  * PARAMETERS:  interface_name      - The interface to find
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index c53759b..cb1e9cc 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -333,7 +333,8 @@
  * FUNCTION:    acpi_ut_print_string
  *
  * PARAMETERS:  string          - Null terminated ASCII string
- *              max_length      - Maximum output length
+ *              max_length      - Maximum output length. Used to constrain the
+ *                                length of strings during debug output only.
  *
  * RETURN:      None
  *
@@ -342,7 +343,7 @@
  *
  ******************************************************************************/
 
-void acpi_ut_print_string(char *string, u8 max_length)
+void acpi_ut_print_string(char *string, u16 max_length)
 {
 	u32 i;
 
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 6505774..03a211e 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -389,6 +389,34 @@
 
 /*****************************************************************************
  *
+ * FUNCTION:    acpi_update_interfaces
+ *
+ * PARAMETERS:  action              - Actions to be performed during the
+ *                                    update
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
+ *              string or/and feature group strings.
+ *
+ ****************************************************************************/
+acpi_status acpi_update_interfaces(u8 action)
+{
+	acpi_status status;
+
+	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	status = acpi_ut_update_interfaces(action);
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+	return (status);
+}
+
+/*****************************************************************************
+ *
  * FUNCTION:    acpi_check_address_range
  *
  * PARAMETERS:  space_id            - Address space ID
@@ -402,6 +430,7 @@
  *              ASL operation region address ranges.
  *
  ****************************************************************************/
+
 u32
 acpi_check_address_range(acpi_adr_space_type space_id,
 			 acpi_physical_address address,
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 88d0b0f..26311f2 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -39,7 +39,8 @@
 
 #include "apei-internal.h"
 
-#define ERST_PFX "ERST: "
+#undef pr_fmt
+#define pr_fmt(fmt) "ERST: " fmt
 
 /* ERST command status */
 #define ERST_STATUS_SUCCESS			0x0
@@ -109,8 +110,7 @@
 static int erst_timedout(u64 *t, u64 spin_unit)
 {
 	if ((s64)*t < spin_unit) {
-		pr_warning(FW_WARN ERST_PFX
-			   "Firmware does not respond in time\n");
+		pr_warn(FW_WARN "Firmware does not respond in time.\n");
 		return 1;
 	}
 	*t -= spin_unit;
@@ -186,8 +186,8 @@
 
 	if (ctx->value > FIRMWARE_MAX_STALL) {
 		if (!in_nmi())
-			pr_warning(FW_WARN ERST_PFX
-			"Too long stall time for stall instruction: %llx.\n",
+			pr_warn(FW_WARN
+			"Too long stall time for stall instruction: 0x%llx.\n",
 				   ctx->value);
 		stall_time = FIRMWARE_MAX_STALL;
 	} else
@@ -206,8 +206,8 @@
 
 	if (ctx->var1 > FIRMWARE_MAX_STALL) {
 		if (!in_nmi())
-			pr_warning(FW_WARN ERST_PFX
-		"Too long stall time for stall while true instruction: %llx.\n",
+			pr_warn(FW_WARN
+		"Too long stall time for stall while true instruction: 0x%llx.\n",
 				   ctx->var1);
 		stall_time = FIRMWARE_MAX_STALL;
 	} else
@@ -271,8 +271,7 @@
 
 	/* ioremap does not work in interrupt context */
 	if (in_interrupt()) {
-		pr_warning(ERST_PFX
-			   "MOVE_DATA can not be used in interrupt context");
+		pr_warn("MOVE_DATA can not be used in interrupt context.\n");
 		return -EBUSY;
 	}
 
@@ -284,8 +283,10 @@
 	if (!src)
 		return -ENOMEM;
 	dst = ioremap(ctx->dst_base + offset, ctx->var2);
-	if (!dst)
+	if (!dst) {
+		iounmap(src);
 		return -ENOMEM;
+	}
 
 	memmove(dst, src, ctx->var2);
 
@@ -522,8 +523,7 @@
 				     ERST_RECORD_ID_CACHE_SIZE_MAX);
 		if (new_size <= erst_record_id_cache.size) {
 			if (printk_ratelimit())
-				pr_warning(FW_WARN ERST_PFX
-					   "too many record ID!\n");
+				pr_warn(FW_WARN "too many record IDs!\n");
 			return 0;
 		}
 		alloc_size = new_size * sizeof(entries[0]);
@@ -759,8 +759,7 @@
 static void pr_unimpl_nvram(void)
 {
 	if (printk_ratelimit())
-		pr_warning(ERST_PFX
-		"NVRAM ERST Log Address Range is not implemented yet\n");
+		pr_warn("NVRAM ERST Log Address Range not implemented yet.\n");
 }
 
 static int __erst_write_to_nvram(const struct cper_record_header *record)
@@ -933,9 +932,9 @@
 static int erst_close_pstore(struct pstore_info *psi);
 static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
 			   struct timespec *time, char **buf,
-			   struct pstore_info *psi);
+			   bool *compressed, struct pstore_info *psi);
 static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
-		       u64 *id, unsigned int part, int count, size_t hsize,
+		       u64 *id, unsigned int part, int count, bool compressed,
 		       size_t size, struct pstore_info *psi);
 static int erst_clearer(enum pstore_type_id type, u64 id, int count,
 			struct timespec time, struct pstore_info *psi);
@@ -956,6 +955,9 @@
 #define CPER_SECTION_TYPE_DMESG						\
 	UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54,	\
 		0x94, 0x19, 0xeb, 0x12)
+#define CPER_SECTION_TYPE_DMESG_Z					\
+	UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d,	\
+		0x34, 0xdd, 0xfa, 0xc6)
 #define CPER_SECTION_TYPE_MCE						\
 	UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96,	\
 		0x04, 0x4a, 0x38, 0xfc)
@@ -989,7 +991,7 @@
 
 static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
 			   struct timespec *time, char **buf,
-			   struct pstore_info *psi)
+			   bool *compressed, struct pstore_info *psi)
 {
 	int rc;
 	ssize_t len = 0;
@@ -1034,7 +1036,12 @@
 	}
 	memcpy(*buf, rcd->data, len - sizeof(*rcd));
 	*id = record_id;
+	*compressed = false;
 	if (uuid_le_cmp(rcd->sec_hdr.section_type,
+			CPER_SECTION_TYPE_DMESG_Z) == 0) {
+		*type = PSTORE_TYPE_DMESG;
+		*compressed = true;
+	} else if (uuid_le_cmp(rcd->sec_hdr.section_type,
 			CPER_SECTION_TYPE_DMESG) == 0)
 		*type = PSTORE_TYPE_DMESG;
 	else if (uuid_le_cmp(rcd->sec_hdr.section_type,
@@ -1055,7 +1062,7 @@
 }
 
 static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
-		       u64 *id, unsigned int part, int count, size_t hsize,
+		       u64 *id, unsigned int part, int count, bool compressed,
 		       size_t size, struct pstore_info *psi)
 {
 	struct cper_pstore_record *rcd = (struct cper_pstore_record *)
@@ -1085,7 +1092,10 @@
 	rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
 	switch (type) {
 	case PSTORE_TYPE_DMESG:
-		rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
+		if (compressed)
+			rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG_Z;
+		else
+			rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
 		break;
 	case PSTORE_TYPE_MCE:
 		rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
@@ -1120,7 +1130,7 @@
 		goto err;
 
 	if (erst_disable) {
-		pr_info(ERST_PFX
+		pr_info(
 	"Error Record Serialization Table (ERST) support is disabled.\n");
 		goto err;
 	}
@@ -1131,14 +1141,14 @@
 		goto err;
 	else if (ACPI_FAILURE(status)) {
 		const char *msg = acpi_format_exception(status);
-		pr_err(ERST_PFX "Failed to get table, %s\n", msg);
+		pr_err("Failed to get table, %s\n", msg);
 		rc = -EINVAL;
 		goto err;
 	}
 
 	rc = erst_check_table(erst_tab);
 	if (rc) {
-		pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
+		pr_err(FW_BUG "ERST table is invalid.\n");
 		goto err;
 	}
 
@@ -1156,21 +1166,19 @@
 	rc = erst_get_erange(&erst_erange);
 	if (rc) {
 		if (rc == -ENODEV)
-			pr_info(ERST_PFX
+			pr_info(
 	"The corresponding hardware device or firmware implementation "
 	"is not available.\n");
 		else
-			pr_err(ERST_PFX
-			       "Failed to get Error Log Address Range.\n");
+			pr_err("Failed to get Error Log Address Range.\n");
 		goto err_unmap_reg;
 	}
 
 	r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
 	if (!r) {
-		pr_err(ERST_PFX
-		"Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
-		(unsigned long long)erst_erange.base,
-		(unsigned long long)erst_erange.base + erst_erange.size);
+		pr_err("Can not request [mem %#010llx-%#010llx] for ERST.\n",
+		       (unsigned long long)erst_erange.base,
+		       (unsigned long long)erst_erange.base + erst_erange.size - 1);
 		rc = -EIO;
 		goto err_unmap_reg;
 	}
@@ -1180,7 +1188,7 @@
 	if (!erst_erange.vaddr)
 		goto err_release_erange;
 
-	pr_info(ERST_PFX
+	pr_info(
 	"Error Record Serialization Table (ERST) support is initialized.\n");
 
 	buf = kmalloc(erst_erange.size, GFP_KERNEL);
@@ -1192,15 +1200,15 @@
 		rc = pstore_register(&erst_info);
 		if (rc) {
 			if (rc != -EPERM)
-				pr_info(ERST_PFX
-				"Could not register with persistent store\n");
+				pr_info(
+				"Could not register with persistent store.\n");
 			erst_info.buf = NULL;
 			erst_info.bufsize = 0;
 			kfree(buf);
 		}
 	} else
-		pr_err(ERST_PFX
-		"Failed to allocate %lld bytes for persistent store error log\n",
+		pr_err(
+		"Failed to allocate %lld bytes for persistent store error log.\n",
 		erst_erange.size);
 
 	return 0;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index ec9b57d..8ec37bb 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -409,6 +409,34 @@
 	ghes->flags &= ~GHES_TO_CLEAR;
 }
 
+static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev)
+{
+#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
+	unsigned long pfn;
+	int sec_sev = ghes_severity(gdata->error_severity);
+	struct cper_sec_mem_err *mem_err;
+	mem_err = (struct cper_sec_mem_err *)(gdata + 1);
+
+	if (sec_sev == GHES_SEV_CORRECTED &&
+	    (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) &&
+	    (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)) {
+		pfn = mem_err->physical_addr >> PAGE_SHIFT;
+		if (pfn_valid(pfn))
+			memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE);
+		else if (printk_ratelimit())
+			pr_warn(FW_WARN GHES_PFX
+			"Invalid address in generic error data: %#llx\n",
+			mem_err->physical_addr);
+	}
+	if (sev == GHES_SEV_RECOVERABLE &&
+	    sec_sev == GHES_SEV_RECOVERABLE &&
+	    mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
+		pfn = mem_err->physical_addr >> PAGE_SHIFT;
+		memory_failure_queue(pfn, 0, 0);
+	}
+#endif
+}
+
 static void ghes_do_proc(struct ghes *ghes,
 			 const struct acpi_hest_generic_status *estatus)
 {
@@ -428,15 +456,7 @@
 			apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED,
 						  mem_err);
 #endif
-#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
-			if (sev == GHES_SEV_RECOVERABLE &&
-			    sec_sev == GHES_SEV_RECOVERABLE &&
-			    mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) {
-				unsigned long pfn;
-				pfn = mem_err->physical_addr >> PAGE_SHIFT;
-				memory_failure_queue(pfn, 0, 0);
-			}
-#endif
+			ghes_handle_memory_failure(gdata, sev);
 		}
 #ifdef CONFIG_ACPI_APEI_PCIEAER
 		else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index f5ef5d5..f5e37f3 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -36,6 +36,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <acpi/apei.h>
+#include <asm/mce.h>
 
 #include "apei-internal.h"
 
@@ -121,6 +122,41 @@
 }
 EXPORT_SYMBOL_GPL(apei_hest_parse);
 
+/*
+ * Check if firmware advertises firmware first mode. We need FF bit to be set
+ * along with a set of MC banks which work in FF mode.
+ */
+static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data)
+{
+#ifdef CONFIG_X86_MCE
+	int i;
+	struct acpi_hest_ia_corrected *cmc;
+	struct acpi_hest_ia_error_bank *mc_bank;
+
+	if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
+		return 0;
+
+	cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
+	if (!cmc->enabled)
+		return 0;
+
+	/*
+	 * We expect HEST to provide a list of MC banks that report errors
+	 * in firmware first mode. Otherwise, return non-zero value to
+	 * indicate that we are done parsing HEST.
+	 */
+	if (!(cmc->flags & ACPI_HEST_FIRMWARE_FIRST) || !cmc->num_hardware_banks)
+		return 1;
+
+	pr_info(HEST_PFX "Enabling Firmware First mode for corrected errors.\n");
+
+	mc_bank = (struct acpi_hest_ia_error_bank *)(cmc + 1);
+	for (i = 0; i < cmc->num_hardware_banks; i++, mc_bank++)
+		mce_disable_bank(mc_bank->bank_number);
+#endif
+	return 1;
+}
+
 struct ghes_arr {
 	struct platform_device **ghes_devs;
 	unsigned int count;
@@ -227,6 +263,9 @@
 		goto err;
 	}
 
+	if (!acpi_disable_cmcff)
+		apei_hest_parse(hest_parse_cmc, NULL);
+
 	if (!ghes_disable) {
 		rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
 		if (rc)
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index d405fba..2c9958c 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -527,18 +527,14 @@
 static int acpi_battery_set_alarm(struct acpi_battery *battery)
 {
 	acpi_status status = 0;
-	union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER };
-	struct acpi_object_list arg_list = { 1, &arg0 };
 
 	if (!acpi_battery_present(battery) ||
 	    !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags))
 		return -ENODEV;
 
-	arg0.integer.value = battery->alarm;
-
 	mutex_lock(&battery->lock);
-	status = acpi_evaluate_object(battery->device->handle, "_BTP",
-				 &arg_list, NULL);
+	status = acpi_execute_simple_method(battery->device->handle, "_BTP",
+					    battery->alarm);
 	mutex_unlock(&battery->lock);
 
 	if (ACPI_FAILURE(status))
@@ -550,12 +546,8 @@
 
 static int acpi_battery_init_alarm(struct acpi_battery *battery)
 {
-	acpi_status status = AE_OK;
-	acpi_handle handle = NULL;
-
 	/* See if alarms are supported, and if so, set default */
-	status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
-	if (ACPI_FAILURE(status)) {
+	if (!acpi_has_method(battery->device->handle, "_BTP")) {
 		clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags);
 		return 0;
 	}
@@ -1036,8 +1028,6 @@
 	if (event == ACPI_BATTERY_NOTIFY_INFO)
 		acpi_battery_refresh(battery);
 	acpi_battery_update(battery);
-	acpi_bus_generate_proc_event(device, event,
-				     acpi_battery_present(battery));
 	acpi_bus_generate_netlink_event(device->pnp.device_class,
 					dev_name(&device->dev), event,
 					acpi_battery_present(battery));
@@ -1068,7 +1058,7 @@
 {
 	int result = 0;
 	struct acpi_battery *battery = NULL;
-	acpi_handle handle;
+
 	if (!device)
 		return -EINVAL;
 	battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
@@ -1080,8 +1070,7 @@
 	device->driver_data = battery;
 	mutex_init(&battery->lock);
 	mutex_init(&battery->sysfs_lock);
-	if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle,
-			"_BIX", &handle)))
+	if (acpi_has_method(battery->device->handle, "_BIX"))
 		set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
 	result = acpi_battery_update(battery);
 	if (result)
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c
index be60399..a83e3c6 100644
--- a/drivers/acpi/bgrt.c
+++ b/drivers/acpi/bgrt.c
@@ -51,20 +51,14 @@
 }
 static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);
 
-static ssize_t show_image(struct file *file, struct kobject *kobj,
+static ssize_t image_read(struct file *file, struct kobject *kobj,
 	       struct bin_attribute *attr, char *buf, loff_t off, size_t count)
 {
 	memcpy(buf, attr->private + off, count);
 	return count;
 }
 
-static struct bin_attribute image_attr = {
-	.attr = {
-		.name = "image",
-		.mode = S_IRUGO,
-	},
-	.read = show_image,
-};
+static BIN_ATTR_RO(image, 0);	/* size gets filled in later */
 
 static struct attribute *bgrt_attributes[] = {
 	&dev_attr_version.attr,
@@ -75,8 +69,14 @@
 	NULL,
 };
 
+static struct bin_attribute *bgrt_bin_attributes[] = {
+	&bin_attr_image,
+	NULL,
+};
+
 static struct attribute_group bgrt_attribute_group = {
 	.attrs = bgrt_attributes,
+	.bin_attrs = bgrt_bin_attributes,
 };
 
 static int __init bgrt_init(void)
@@ -86,9 +86,8 @@
 	if (!bgrt_image)
 		return -ENODEV;
 
-	sysfs_bin_attr_init(&image_attr);
-	image_attr.private = bgrt_image;
-	image_attr.size = bgrt_image_size;
+	bin_attr_image.private = bgrt_image;
+	bin_attr_image.size = bgrt_image_size;
 
 	bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
 	if (!bgrt_kobj)
@@ -98,14 +97,8 @@
 	if (ret)
 		goto out_kobject;
 
-	ret = sysfs_create_bin_file(bgrt_kobj, &image_attr);
-	if (ret)
-		goto out_group;
-
 	return 0;
 
-out_group:
-	sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
 out_kobject:
 	kobject_put(bgrt_kobj);
 	return ret;
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index cb96296..9515f18 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -192,6 +192,12 @@
 	acpi_osi_setup("!Windows 2009");
 	return 0;
 }
+static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)
+{
+	printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+	acpi_osi_setup("!Windows 2012");
+	return 0;
+}
 
 static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
 	{
@@ -267,6 +273,30 @@
 		     DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),
 		},
 	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "ASUS Zenbook Prime UX31A",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "UX31A"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Dell Inspiron 15R SE",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_win8,
+	.ident = "Lenovo ThinkPad Edge E530",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "3259A2G"),
+		},
+	},
 
 	/*
 	 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a5bb33b..b587ec8 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -89,27 +89,6 @@
                                 Device Management
    -------------------------------------------------------------------------- */
 
-int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
-{
-	acpi_status status;
-
-	if (!device)
-		return -EINVAL;
-
-	/* TBD: Support fixed-feature devices */
-
-	status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
-	if (ACPI_FAILURE(status) || !*device) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
-				  handle));
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-EXPORT_SYMBOL(acpi_bus_get_device);
-
 acpi_status acpi_bus_get_status_handle(acpi_handle handle,
 				       unsigned long long *sta)
 {
@@ -346,104 +325,6 @@
 }
 
 /* --------------------------------------------------------------------------
-                                Event Management
-   -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_ACPI_PROC_EVENT
-static DEFINE_SPINLOCK(acpi_bus_event_lock);
-
-LIST_HEAD(acpi_bus_event_list);
-DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
-
-extern int event_is_open;
-
-int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
-{
-	struct acpi_bus_event *event;
-	unsigned long flags;
-
-	/* drop event on the floor if no one's listening */
-	if (!event_is_open)
-		return 0;
-
-	event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
-	if (!event)
-		return -ENOMEM;
-
-	strcpy(event->device_class, device_class);
-	strcpy(event->bus_id, bus_id);
-	event->type = type;
-	event->data = data;
-
-	spin_lock_irqsave(&acpi_bus_event_lock, flags);
-	list_add_tail(&event->node, &acpi_bus_event_list);
-	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
-
-	wake_up_interruptible(&acpi_bus_event_queue);
-
-	return 0;
-
-}
-
-EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
-
-int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
-{
-	if (!device)
-		return -EINVAL;
-	return acpi_bus_generate_proc_event4(device->pnp.device_class,
-					     device->pnp.bus_id, type, data);
-}
-
-EXPORT_SYMBOL(acpi_bus_generate_proc_event);
-
-int acpi_bus_receive_event(struct acpi_bus_event *event)
-{
-	unsigned long flags;
-	struct acpi_bus_event *entry = NULL;
-
-	DECLARE_WAITQUEUE(wait, current);
-
-
-	if (!event)
-		return -EINVAL;
-
-	if (list_empty(&acpi_bus_event_list)) {
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&acpi_bus_event_queue, &wait);
-
-		if (list_empty(&acpi_bus_event_list))
-			schedule();
-
-		remove_wait_queue(&acpi_bus_event_queue, &wait);
-		set_current_state(TASK_RUNNING);
-
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
-
-	spin_lock_irqsave(&acpi_bus_event_lock, flags);
-	if (!list_empty(&acpi_bus_event_list)) {
-		entry = list_entry(acpi_bus_event_list.next,
-				   struct acpi_bus_event, node);
-		list_del(&entry->node);
-	}
-	spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
-
-	if (!entry)
-		return -ENODEV;
-
-	memcpy(event, entry, sizeof(struct acpi_bus_event));
-
-	kfree(entry);
-
-	return 0;
-}
-
-#endif	/* CONFIG_ACPI_PROC_EVENT */
-
-/* --------------------------------------------------------------------------
                              Notification Handling
    -------------------------------------------------------------------------- */
 
@@ -499,19 +380,6 @@
 	 */
 }
 
-static BLOCKING_NOTIFIER_HEAD(acpi_bus_notify_list);
-int register_acpi_bus_notifier(struct notifier_block *nb)
-{
-	return blocking_notifier_chain_register(&acpi_bus_notify_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_acpi_bus_notifier);
-
-void unregister_acpi_bus_notifier(struct notifier_block *nb)
-{
-	blocking_notifier_chain_unregister(&acpi_bus_notify_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_acpi_bus_notifier);
-
 /**
  * acpi_bus_notify
  * ---------------
@@ -525,9 +393,6 @@
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
 			  type, handle));
 
-	blocking_notifier_call_chain(&acpi_bus_notify_list,
-		type, (void *)handle);
-
 	switch (type) {
 
 	case ACPI_NOTIFY_BUS_CHECK:
@@ -593,8 +458,6 @@
 static int __init acpi_bus_init_irq(void)
 {
 	acpi_status status;
-	union acpi_object arg = { ACPI_TYPE_INTEGER };
-	struct acpi_object_list arg_list = { 1, &arg };
 	char *message = NULL;
 
 
@@ -623,9 +486,7 @@
 
 	printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
 
-	arg.integer.value = acpi_irq_model;
-
-	status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
+	status = acpi_execute_simple_method(NULL, "\\_PIC", acpi_irq_model);
 	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
 		return -ENODEV;
@@ -715,7 +576,6 @@
 {
 	int result;
 	acpi_status status;
-	extern acpi_status acpi_os_initialize1(void);
 
 	acpi_os_initialize1();
 
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index d2e617b..a557738 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -303,8 +303,6 @@
 
 			pm_wakeup_event(&device->dev, 0);
 		}
-
-		acpi_bus_generate_proc_event(device, event, ++button->pushed);
 		break;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 4ab807d..59d3202f 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -159,26 +159,29 @@
 	int result = 0;
 	bool cut_power = false;
 
-	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
+	if (!device || !device->flags.power_manageable
+	    || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
 		return -EINVAL;
 
 	/* Make sure this is a valid target state */
 
 	if (state == device->power.state) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n",
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n",
+				  device->pnp.bus_id,
 				  acpi_power_state_string(state)));
 		return 0;
 	}
 
 	if (!device->power.states[state].flags.valid) {
-		printk(KERN_WARNING PREFIX "Device does not support %s\n",
-		       acpi_power_state_string(state));
+		dev_warn(&device->dev, "Power state %s not supported\n",
+			 acpi_power_state_string(state));
 		return -ENODEV;
 	}
 	if (device->parent && (state < device->parent->power.state)) {
-		printk(KERN_WARNING PREFIX
-			      "Cannot set device to a higher-powered"
-			      " state than parent\n");
+		dev_warn(&device->dev,
+			 "Cannot transition to power state %s for parent in %s\n",
+			 acpi_power_state_string(state),
+			 acpi_power_state_string(device->parent->power.state));
 		return -ENODEV;
 	}
 
@@ -191,8 +194,8 @@
 
 	if (state < device->power.state && state != ACPI_STATE_D0
 	    && device->power.state >= ACPI_STATE_D3_HOT) {
-		printk(KERN_WARNING PREFIX
-			"Cannot transition to non-D0 state from D3\n");
+		dev_warn(&device->dev,
+			 "Cannot transition to non-D0 state from D3\n");
 		return -ENODEV;
 	}
 
@@ -219,10 +222,8 @@
 
  end:
 	if (result) {
-		printk(KERN_WARNING PREFIX
-			      "Device [%s] failed to transition to %s\n",
-			      device->pnp.bus_id,
-			      acpi_power_state_string(state));
+		dev_warn(&device->dev, "Failed to change power state to %s\n",
+			 acpi_power_state_string(state));
 	} else {
 		device->power.state = state;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -244,13 +245,6 @@
 	if (result)
 		return result;
 
-	if (!device->flags.power_manageable) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				"Device [%s] is not power manageable\n",
-				dev_name(&device->dev)));
-		return -ENODEV;
-	}
-
 	return acpi_device_set_power(device, state);
 }
 EXPORT_SYMBOL(acpi_bus_set_power);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 8265607..05ea4be 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -51,8 +51,6 @@
 	" the driver to wait for userspace to write the undock sysfs file "
 	" before undocking");
 
-static struct atomic_notifier_head dock_notifier_list;
-
 static const struct acpi_device_id dock_device_ids[] = {
 	{"LNXDOCK", 0},
 	{"", 0},
@@ -63,8 +61,6 @@
 	acpi_handle handle;
 	unsigned long last_dock_time;
 	u32 flags;
-	spinlock_t dd_lock;
-	struct mutex hp_lock;
 	struct list_head dependent_devices;
 
 	struct list_head sibling;
@@ -91,6 +87,12 @@
 #define DOCK_EVENT	3
 #define UNDOCK_EVENT	2
 
+enum dock_callback_type {
+	DOCK_CALL_HANDLER,
+	DOCK_CALL_FIXUP,
+	DOCK_CALL_UEVENT,
+};
+
 /*****************************************************************************
  *                         Dock Dependent device functions                   *
  *****************************************************************************/
@@ -101,7 +103,7 @@
  *
  * Add the dependent device to the dock's dependent device list.
  */
-static int
+static int __init
 add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
 {
 	struct dock_dependent_device *dd;
@@ -112,14 +114,21 @@
 
 	dd->handle = handle;
 	INIT_LIST_HEAD(&dd->list);
-
-	spin_lock(&ds->dd_lock);
 	list_add_tail(&dd->list, &ds->dependent_devices);
-	spin_unlock(&ds->dd_lock);
 
 	return 0;
 }
 
+static void remove_dock_dependent_devices(struct dock_station *ds)
+{
+	struct dock_dependent_device *dd, *aux;
+
+	list_for_each_entry_safe(dd, aux, &ds->dependent_devices, list) {
+		list_del(&dd->list);
+		kfree(dd);
+	}
+}
+
 /**
  * dock_init_hotplug - Initialize a hotplug device on a docking station.
  * @dd: Dock-dependent device.
@@ -135,19 +144,16 @@
 	int ret = 0;
 
 	mutex_lock(&hotplug_lock);
-
-	if (dd->hp_context) {
+	if (WARN_ON(dd->hp_context)) {
 		ret = -EEXIST;
 	} else {
 		dd->hp_refcount = 1;
 		dd->hp_ops = ops;
 		dd->hp_context = context;
 		dd->hp_release = release;
+		if (init)
+			init(context);
 	}
-
-	if (!WARN_ON(ret) && init)
-		init(context);
-
 	mutex_unlock(&hotplug_lock);
 	return ret;
 }
@@ -162,27 +168,22 @@
  */
 static void dock_release_hotplug(struct dock_dependent_device *dd)
 {
-	void (*release)(void *) = NULL;
-	void *context = NULL;
-
 	mutex_lock(&hotplug_lock);
-
 	if (dd->hp_context && !--dd->hp_refcount) {
+		void (*release)(void *) = dd->hp_release;
+		void *context = dd->hp_context;
+
 		dd->hp_ops = NULL;
-		context = dd->hp_context;
 		dd->hp_context = NULL;
-		release = dd->hp_release;
 		dd->hp_release = NULL;
+		if (release)
+			release(context);
 	}
-
-	if (release && context)
-		release(context);
-
 	mutex_unlock(&hotplug_lock);
 }
 
 static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
-			       bool uevent)
+			       enum dock_callback_type cb_type)
 {
 	acpi_notify_handler cb = NULL;
 	bool run = false;
@@ -192,8 +193,18 @@
 	if (dd->hp_context) {
 		run = true;
 		dd->hp_refcount++;
-		if (dd->hp_ops)
-			cb = uevent ? dd->hp_ops->uevent : dd->hp_ops->handler;
+		if (dd->hp_ops) {
+			switch (cb_type) {
+			case DOCK_CALL_FIXUP:
+				cb = dd->hp_ops->fixup;
+				break;
+			case DOCK_CALL_UEVENT:
+				cb = dd->hp_ops->uevent;
+				break;
+			default:
+				cb = dd->hp_ops->handler;
+			}
+		}
 	}
 
 	mutex_unlock(&hotplug_lock);
@@ -220,63 +231,17 @@
 {
 	struct dock_dependent_device *dd;
 
-	spin_lock(&ds->dd_lock);
-	list_for_each_entry(dd, &ds->dependent_devices, list) {
-		if (handle == dd->handle) {
-			spin_unlock(&ds->dd_lock);
+	list_for_each_entry(dd, &ds->dependent_devices, list)
+		if (handle == dd->handle)
 			return dd;
-		}
-	}
-	spin_unlock(&ds->dd_lock);
+
 	return NULL;
 }
 
 /*****************************************************************************
  *                         Dock functions                                    *
  *****************************************************************************/
-/**
- * is_dock - see if a device is a dock station
- * @handle: acpi handle of the device
- *
- * If an acpi object has a _DCK method, then it is by definition a dock
- * station, so return true.
- */
-static int is_dock(acpi_handle handle)
-{
-	acpi_status status;
-	acpi_handle tmp;
-
-	status = acpi_get_handle(handle, "_DCK", &tmp);
-	if (ACPI_FAILURE(status))
-		return 0;
-	return 1;
-}
-
-static int is_ejectable(acpi_handle handle)
-{
-	acpi_status status;
-	acpi_handle tmp;
-
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-	if (ACPI_FAILURE(status))
-		return 0;
-	return 1;
-}
-
-static int is_ata(acpi_handle handle)
-{
-	acpi_handle tmp;
-
-	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
-	   (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
-	   (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
-	   (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
-		return 1;
-
-	return 0;
-}
-
-static int is_battery(acpi_handle handle)
+static int __init is_battery(acpi_handle handle)
 {
 	struct acpi_device_info *info;
 	int ret = 1;
@@ -292,17 +257,13 @@
 	return ret;
 }
 
-static int is_ejectable_bay(acpi_handle handle)
+/* Check whether ACPI object is an ejectable battery or disk bay */
+static bool __init is_ejectable_bay(acpi_handle handle)
 {
-	acpi_handle phandle;
+	if (acpi_has_method(handle, "_EJ0") && is_battery(handle))
+		return true;
 
-	if (!is_ejectable(handle))
-		return 0;
-	if (is_battery(handle) || is_ata(handle))
-		return 1;
-	if (!acpi_get_parent(handle, &phandle) && is_ata(phandle))
-		return 1;
-	return 0;
+	return acpi_bay_match(handle);
 }
 
 /**
@@ -320,7 +281,7 @@
 	if (!dock_station_count)
 		return 0;
 
-	if (is_dock(handle))
+	if (acpi_dock_match(handle))
 		return 1;
 
 	list_for_each_entry(dock_station, &dock_stations, sibling)
@@ -359,10 +320,8 @@
  *  handle if one does not exist already.  This should cause
  *  acpi to scan for drivers for the given devices, and call
  *  matching driver's add routine.
- *
- *  Returns a pointer to the acpi_device corresponding to the handle.
  */
-static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
+static void dock_create_acpi_device(acpi_handle handle)
 {
 	struct acpi_device *device;
 	int ret;
@@ -375,10 +334,7 @@
 		ret = acpi_bus_scan(handle);
 		if (ret)
 			pr_debug("error adding bus, %x\n", -ret);
-
-		acpi_bus_get_device(handle, &device);
 	}
-	return device;
 }
 
 /**
@@ -397,9 +353,29 @@
 }
 
 /**
- * hotplug_dock_devices - insert or remove devices on the dock station
+ * hot_remove_dock_devices - Remove dock station devices.
+ * @ds: Dock station.
+ */
+static void hot_remove_dock_devices(struct dock_station *ds)
+{
+	struct dock_dependent_device *dd;
+
+	/*
+	 * Walk the list in reverse order so that devices that have been added
+	 * last are removed first (in case there are some indirect dependencies
+	 * between them).
+	 */
+	list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
+		dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST, false);
+
+	list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
+		dock_remove_acpi_device(dd->handle);
+}
+
+/**
+ * hotplug_dock_devices - Insert devices on a dock station.
  * @ds: the dock station
- * @event: either bus check or eject request
+ * @event: either bus check or device check request
  *
  * Some devices on the dock station need to have drivers called
  * to perform hotplug operations after a dock event has occurred.
@@ -410,27 +386,21 @@
 {
 	struct dock_dependent_device *dd;
 
-	mutex_lock(&ds->hp_lock);
+	/* Call driver specific post-dock fixups. */
+	list_for_each_entry(dd, &ds->dependent_devices, list)
+		dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
+
+	/* Call driver specific hotplug functions. */
+	list_for_each_entry(dd, &ds->dependent_devices, list)
+		dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
 
 	/*
-	 * First call driver specific hotplug functions
+	 * Now make sure that an acpi_device is created for each dependent
+	 * device.  That will cause scan handlers to be attached to device
+	 * objects or acpi_drivers to be stopped/started if they are present.
 	 */
 	list_for_each_entry(dd, &ds->dependent_devices, list)
-		dock_hotplug_event(dd, event, false);
-
-	/*
-	 * Now make sure that an acpi_device is created for each
-	 * dependent device, or removed if this is an eject request.
-	 * This will cause acpi_drivers to be stopped/started if they
-	 * exist
-	 */
-	list_for_each_entry(dd, &ds->dependent_devices, list) {
-		if (event == ACPI_NOTIFY_EJECT_REQUEST)
-			dock_remove_acpi_device(dd->handle);
-		else
-			dock_create_acpi_device(dd->handle);
-	}
-	mutex_unlock(&ds->hp_lock);
+		dock_create_acpi_device(dd->handle);
 }
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
@@ -453,44 +423,13 @@
 		kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 
 	list_for_each_entry(dd, &ds->dependent_devices, list)
-		dock_hotplug_event(dd, event, true);
+		dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
 
 	if (num != DOCK_EVENT)
 		kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 /**
- * eject_dock - respond to a dock eject request
- * @ds: the dock station
- *
- * This is called after _DCK is called, to execute the dock station's
- * _EJ0 method.
- */
-static void eject_dock(struct dock_station *ds)
-{
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
-	acpi_status status;
-	acpi_handle tmp;
-
-	/* all dock devices should have _EJ0, but check anyway */
-	status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
-	if (ACPI_FAILURE(status)) {
-		pr_debug("No _EJ0 support for dock device\n");
-		return;
-	}
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = 1;
-
-	status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL);
-	if (ACPI_FAILURE(status))
-		pr_debug("Failed to evaluate _EJ0!\n");
-}
-
-/**
  * handle_dock - handle a dock event
  * @ds: the dock station
  * @dock: to dock, or undock - that is the question
@@ -550,27 +489,6 @@
 	ds->flags &= ~(DOCK_UNDOCKING);
 }
 
-static void dock_lock(struct dock_station *ds, int lock)
-{
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
-	acpi_status status;
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = !!lock;
-	status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		if (lock)
-			acpi_handle_warn(ds->handle,
-				"Locking device failed (0x%x)\n", status);
-		else
-			acpi_handle_warn(ds->handle,
-				"Unlocking device failed (0x%x)\n", status);
-	}
-}
-
 /**
  * dock_in_progress - see if we are in the middle of handling a dock event
  * @ds: the dock station
@@ -588,37 +506,6 @@
 }
 
 /**
- * register_dock_notifier - add yourself to the dock notifier list
- * @nb: the callers notifier block
- *
- * If a driver wishes to be notified about dock events, they can
- * use this function to put a notifier block on the dock notifier list.
- * this notifier call chain will be called after a dock event, but
- * before hotplugging any new devices.
- */
-int register_dock_notifier(struct notifier_block *nb)
-{
-	if (!dock_station_count)
-		return -ENODEV;
-
-	return atomic_notifier_chain_register(&dock_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_dock_notifier);
-
-/**
- * unregister_dock_notifier - remove yourself from the dock notifier list
- * @nb: the callers notifier block
- */
-void unregister_dock_notifier(struct notifier_block *nb)
-{
-	if (!dock_station_count)
-		return;
-
-	atomic_notifier_chain_unregister(&dock_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_dock_notifier);
-
-/**
  * register_hotplug_dock_device - register a hotplug function
  * @handle: the handle of the device
  * @ops: handlers to call after docking
@@ -703,10 +590,10 @@
 	 */
 	dock_event(ds, event, UNDOCK_EVENT);
 
-	hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+	hot_remove_dock_devices(ds);
 	undock(ds);
-	dock_lock(ds, 0);
-	eject_dock(ds);
+	acpi_evaluate_lck(ds->handle, 0);
+	acpi_evaluate_ej0(ds->handle);
 	if (dock_present(ds)) {
 		acpi_handle_err(ds->handle, "Unable to undock!\n");
 		return -EBUSY;
@@ -717,18 +604,17 @@
 
 /**
  * dock_notify - act upon an acpi dock notification
- * @handle: the dock station handle
+ * @ds: dock station
  * @event: the acpi event
- * @data: our driver data struct
  *
  * If we are notified to dock, then check to see if the dock is
  * present and then dock.  Notify all drivers of the dock event,
  * and then hotplug and devices that may need hotplugging.
  */
-static void dock_notify(acpi_handle handle, u32 event, void *data)
+static void dock_notify(struct dock_station *ds, u32 event)
 {
-	struct dock_station *ds = data;
-	struct acpi_device *tmp;
+	acpi_handle handle = ds->handle;
+	struct acpi_device *ad;
 	int surprise_removal = 0;
 
 	/*
@@ -751,8 +637,7 @@
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
-		if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
-		   &tmp)) {
+		if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
 			begin_dock(ds);
 			dock(ds);
 			if (!dock_present(ds)) {
@@ -760,12 +645,10 @@
 				complete_dock(ds);
 				break;
 			}
-			atomic_notifier_call_chain(&dock_notifier_list,
-						   event, NULL);
 			hotplug_dock_devices(ds, event);
 			complete_dock(ds);
 			dock_event(ds, event, DOCK_EVENT);
-			dock_lock(ds, 1);
+			acpi_evaluate_lck(ds->handle, 1);
 			acpi_update_all_gpes();
 			break;
 		}
@@ -789,9 +672,8 @@
 }
 
 struct dock_data {
-	acpi_handle handle;
-	unsigned long event;
 	struct dock_station *ds;
+	u32 event;
 };
 
 static void acpi_dock_deferred_cb(void *context)
@@ -799,52 +681,31 @@
 	struct dock_data *data = context;
 
 	acpi_scan_lock_acquire();
-	dock_notify(data->handle, data->event, data->ds);
+	dock_notify(data->ds, data->event);
 	acpi_scan_lock_release();
 	kfree(data);
 }
 
-static int acpi_dock_notifier_call(struct notifier_block *this,
-	unsigned long event, void *data)
+static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
 {
-	struct dock_station *dock_station;
-	acpi_handle handle = data;
+	struct dock_data *dd;
 
 	if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
 	   && event != ACPI_NOTIFY_EJECT_REQUEST)
-		return 0;
+		return;
 
-	acpi_scan_lock_acquire();
+	dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+	if (dd) {
+		acpi_status status;
 
-	list_for_each_entry(dock_station, &dock_stations, sibling) {
-		if (dock_station->handle == handle) {
-			struct dock_data *dd;
-			acpi_status status;
-
-			dd = kmalloc(sizeof(*dd), GFP_KERNEL);
-			if (!dd)
-				break;
-
-			dd->handle = handle;
-			dd->event = event;
-			dd->ds = dock_station;
-			status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
-							 dd);
-			if (ACPI_FAILURE(status))
-				kfree(dd);
-
-			break;
-		}
+		dd->ds = data;
+		dd->event = event;
+		status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
+		if (ACPI_FAILURE(status))
+			kfree(dd);
 	}
-
-	acpi_scan_lock_release();
-	return 0;
 }
 
-static struct notifier_block dock_acpi_notifier = {
-	.notifier_call = acpi_dock_notifier_call,
-};
-
 /**
  * find_dock_devices - find devices on the dock station
  * @handle: the handle of the device we are examining
@@ -856,29 +717,16 @@
  * check to see if an object has an _EJD method.  If it does, then it
  * will see if it is dependent on the dock station.
  */
-static acpi_status
-find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
+					    void *context, void **rv)
 {
-	acpi_status status;
-	acpi_handle tmp, parent;
 	struct dock_station *ds = context;
+	acpi_handle ejd = NULL;
 
-	status = acpi_bus_get_ejd(handle, &tmp);
-	if (ACPI_FAILURE(status)) {
-		/* try the parent device as well */
-		status = acpi_get_parent(handle, &parent);
-		if (ACPI_FAILURE(status))
-			goto fdd_out;
-		/* see if parent is dependent on dock */
-		status = acpi_bus_get_ejd(parent, &tmp);
-		if (ACPI_FAILURE(status))
-			goto fdd_out;
-	}
-
-	if (tmp == ds->handle)
+	acpi_bus_get_ejd(handle, &ejd);
+	if (ejd == ds->handle)
 		add_dock_dependent_device(ds, handle);
 
-fdd_out:
 	return AE_OK;
 }
 
@@ -988,13 +836,13 @@
  */
 static int __init dock_add(acpi_handle handle)
 {
-	int ret, id;
-	struct dock_station ds, *dock_station;
+	struct dock_station *dock_station, ds = { NULL, };
 	struct platform_device *dd;
+	acpi_status status;
+	int ret;
 
-	id = dock_station_count;
-	memset(&ds, 0, sizeof(ds));
-	dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
+	dd = platform_device_register_data(NULL, "dock", dock_station_count,
+					   &ds, sizeof(ds));
 	if (IS_ERR(dd))
 		return PTR_ERR(dd);
 
@@ -1004,18 +852,15 @@
 	dock_station->dock_device = dd;
 	dock_station->last_dock_time = jiffies - HZ;
 
-	mutex_init(&dock_station->hp_lock);
-	spin_lock_init(&dock_station->dd_lock);
 	INIT_LIST_HEAD(&dock_station->sibling);
-	ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 	INIT_LIST_HEAD(&dock_station->dependent_devices);
 
 	/* we want the dock device to send uevents */
 	dev_set_uevent_suppress(&dd->dev, 0);
 
-	if (is_dock(handle))
+	if (acpi_dock_match(handle))
 		dock_station->flags |= DOCK_IS_DOCK;
-	if (is_ata(handle))
+	if (acpi_ata_match(handle))
 		dock_station->flags |= DOCK_IS_ATA;
 	if (is_battery(handle))
 		dock_station->flags |= DOCK_IS_BAT;
@@ -1034,11 +879,19 @@
 	if (ret)
 		goto err_rmgroup;
 
+	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					     dock_notify_handler, dock_station);
+	if (ACPI_FAILURE(status)) {
+		ret = -ENODEV;
+		goto err_rmgroup;
+	}
+
 	dock_station_count++;
 	list_add(&dock_station->sibling, &dock_stations);
 	return 0;
 
 err_rmgroup:
+	remove_dock_dependent_devices(dock_station);
 	sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
 err_unregister:
 	platform_device_unregister(dd);
@@ -1055,10 +908,10 @@
  *
  * This is called by acpi_walk_namespace to look for dock stations and bays.
  */
-static __init acpi_status
+static acpi_status __init
 find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
-	if (is_dock(handle) || is_ejectable_bay(handle))
+	if (acpi_dock_match(handle) || is_ejectable_bay(handle))
 		dock_add(handle);
 
 	return AE_OK;
@@ -1078,7 +931,6 @@
 		return;
 	}
 
-	register_acpi_bus_notifier(&dock_acpi_notifier);
 	pr_info(PREFIX "%s: %d docks/bays found\n",
 		ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
 }
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 80403c1..a06d983 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -948,7 +948,7 @@
 	return 0;
 }
 
-static struct dmi_system_id __initdata ec_dmi_table[] = {
+static struct dmi_system_id ec_dmi_table[] __initdata = {
 	{
 	ec_skip_dsdt_scan, "Compal JFL92", {
 	DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
@@ -987,6 +987,10 @@
 	ec_skip_dsdt_scan, "HP Folio 13", {
 	DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
 	DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
+	{
+	ec_validate_ecdt, "ASUS hardware", {
+	DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
+	DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
 	{},
 };
 
@@ -1049,10 +1053,8 @@
 		* which needs it, has fake EC._INI method, so use it as flag.
 		* Keep boot_ec struct as it will be needed soon.
 		*/
-		acpi_handle dummy;
 		if (!dmi_name_in_vendors("ASUS") ||
-		    ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
-							&dummy)))
+		    !acpi_has_method(boot_ec->handle, "_INI"))
 			return -ENODEV;
 	}
 install:
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 1442737..8247fcd 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -21,100 +21,6 @@
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("event");
 
-#ifdef CONFIG_ACPI_PROC_EVENT
-/* Global vars for handling event proc entry */
-static DEFINE_SPINLOCK(acpi_system_event_lock);
-int event_is_open = 0;
-extern struct list_head acpi_bus_event_list;
-extern wait_queue_head_t acpi_bus_event_queue;
-
-static int acpi_system_open_event(struct inode *inode, struct file *file)
-{
-	spin_lock_irq(&acpi_system_event_lock);
-
-	if (event_is_open)
-		goto out_busy;
-
-	event_is_open = 1;
-
-	spin_unlock_irq(&acpi_system_event_lock);
-	return 0;
-
-      out_busy:
-	spin_unlock_irq(&acpi_system_event_lock);
-	return -EBUSY;
-}
-
-static ssize_t
-acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
-		       loff_t * ppos)
-{
-	int result = 0;
-	struct acpi_bus_event event;
-	static char str[ACPI_MAX_STRING];
-	static int chars_remaining = 0;
-	static char *ptr;
-
-	if (!chars_remaining) {
-		memset(&event, 0, sizeof(struct acpi_bus_event));
-
-		if ((file->f_flags & O_NONBLOCK)
-		    && (list_empty(&acpi_bus_event_list)))
-			return -EAGAIN;
-
-		result = acpi_bus_receive_event(&event);
-		if (result)
-			return result;
-
-		chars_remaining = sprintf(str, "%s %s %08x %08x\n",
-					  event.device_class ? event.
-					  device_class : "<unknown>",
-					  event.bus_id ? event.
-					  bus_id : "<unknown>", event.type,
-					  event.data);
-		ptr = str;
-	}
-
-	if (chars_remaining < count) {
-		count = chars_remaining;
-	}
-
-	if (copy_to_user(buffer, ptr, count))
-		return -EFAULT;
-
-	*ppos += count;
-	chars_remaining -= count;
-	ptr += count;
-
-	return count;
-}
-
-static int acpi_system_close_event(struct inode *inode, struct file *file)
-{
-	spin_lock_irq(&acpi_system_event_lock);
-	event_is_open = 0;
-	spin_unlock_irq(&acpi_system_event_lock);
-	return 0;
-}
-
-static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &acpi_bus_event_queue, wait);
-	if (!list_empty(&acpi_bus_event_list))
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-static const struct file_operations acpi_system_event_ops = {
-	.owner = THIS_MODULE,
-	.open = acpi_system_open_event,
-	.read = acpi_system_read_event,
-	.release = acpi_system_close_event,
-	.poll = acpi_system_poll_event,
-	.llseek = default_llseek,
-};
-#endif	/* CONFIG_ACPI_PROC_EVENT */
-
 /* ACPI notifier chain */
 static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
 
@@ -280,9 +186,6 @@
 
 static int __init acpi_event_init(void)
 {
-#ifdef CONFIG_ACPI_PROC_EVENT
-	struct proc_dir_entry *entry;
-#endif
 	int error = 0;
 
 	if (acpi_disabled)
@@ -293,15 +196,6 @@
 	if (error)
 		printk(KERN_WARNING PREFIX
 		       "Failed to create genetlink family for ACPI event\n");
-
-#ifdef CONFIG_ACPI_PROC_EVENT
-	/* 'event' [R] */
-	entry = proc_create("event", S_IRUSR, acpi_root_dir,
-			    &acpi_system_event_ops);
-	if (!entry)
-		return -ENODEV;
-#endif
-
 	return 0;
 }
 
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 5b02a0a..41ade65 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -93,7 +93,7 @@
 	if (result)
 		return result;
 
-	*state = (acpi_state == ACPI_STATE_D3 ? 0 :
+	*state = (acpi_state == ACPI_STATE_D3_COLD ? 0 :
 		 (acpi_state == ACPI_STATE_D0 ? 1 : -1));
 	return 0;
 }
@@ -108,7 +108,7 @@
 		return -EINVAL;
 
 	result = acpi_bus_set_power(device->handle,
-				state ? ACPI_STATE_D0 : ACPI_STATE_D3);
+				state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
 
 	return result;
 }
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 408f6b2..9467229 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -173,6 +173,15 @@
 }
 EXPORT_SYMBOL_GPL(acpi_find_child);
 
+static void acpi_physnode_link_name(char *buf, unsigned int node_id)
+{
+	if (node_id > 0)
+		snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
+			 PHYSICAL_NODE_STRING "%u", node_id);
+	else
+		strcpy(buf, PHYSICAL_NODE_STRING);
+}
+
 int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
 	struct acpi_device *acpi_dev;
@@ -216,8 +225,15 @@
 	list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
 		/* Sanity check. */
 		if (pn->dev == dev) {
+			mutex_unlock(&acpi_dev->physical_node_lock);
+
 			dev_warn(dev, "Already associated with ACPI node\n");
-			goto err_free;
+			kfree(physical_node);
+			if (ACPI_HANDLE(dev) != handle)
+				goto err;
+
+			put_device(dev);
+			return 0;
 		}
 		if (pn->node_id == node_id) {
 			physnode_list = &pn->node;
@@ -230,20 +246,23 @@
 	list_add(&physical_node->node, physnode_list);
 	acpi_dev->physical_node_count++;
 
-	mutex_unlock(&acpi_dev->physical_node_lock);
-
 	if (!ACPI_HANDLE(dev))
 		ACPI_HANDLE_SET(dev, acpi_dev->handle);
 
-	if (!physical_node->node_id)
-		strcpy(physical_node_name, PHYSICAL_NODE_STRING);
-	else
-		sprintf(physical_node_name,
-			"physical_node%d", physical_node->node_id);
+	acpi_physnode_link_name(physical_node_name, node_id);
 	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
-			physical_node_name);
+				   physical_node_name);
+	if (retval)
+		dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
+			physical_node_name, retval);
+
 	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
-		"firmware_node");
+				   "firmware_node");
+	if (retval)
+		dev_err(dev, "Failed to create link firmware_node (%d)\n",
+			retval);
+
+	mutex_unlock(&acpi_dev->physical_node_lock);
 
 	if (acpi_dev->wakeup.flags.valid)
 		device_set_wakeup_capable(dev, true);
@@ -254,11 +273,6 @@
 	ACPI_HANDLE_SET(dev, NULL);
 	put_device(dev);
 	return retval;
-
- err_free:
-	mutex_unlock(&acpi_dev->physical_node_lock);
-	kfree(physical_node);
-	goto err;
 }
 EXPORT_SYMBOL_GPL(acpi_bind_one);
 
@@ -267,48 +281,37 @@
 	struct acpi_device_physical_node *entry;
 	struct acpi_device *acpi_dev;
 	acpi_status status;
-	struct list_head *node, *next;
 
 	if (!ACPI_HANDLE(dev))
 		return 0;
 
 	status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev);
-	if (ACPI_FAILURE(status))
-		goto err;
+	if (ACPI_FAILURE(status)) {
+		dev_err(dev, "Oops, ACPI handle corrupt in %s()\n", __func__);
+		return -EINVAL;
+	}
 
 	mutex_lock(&acpi_dev->physical_node_lock);
-	list_for_each_safe(node, next, &acpi_dev->physical_node_list) {
-		char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
 
-		entry = list_entry(node, struct acpi_device_physical_node,
-			node);
-		if (entry->dev != dev)
-			continue;
+	list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
+		if (entry->dev == dev) {
+			char physnode_name[PHYSICAL_NODE_NAME_SIZE];
 
-		list_del(node);
+			list_del(&entry->node);
+			acpi_dev->physical_node_count--;
 
-		acpi_dev->physical_node_count--;
+			acpi_physnode_link_name(physnode_name, entry->node_id);
+			sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
+			sysfs_remove_link(&dev->kobj, "firmware_node");
+			ACPI_HANDLE_SET(dev, NULL);
+			/* acpi_bind_one() increase refcnt by one. */
+			put_device(dev);
+			kfree(entry);
+			break;
+		}
 
-		if (!entry->node_id)
-			strcpy(physical_node_name, PHYSICAL_NODE_STRING);
-		else
-			sprintf(physical_node_name,
-				"physical_node%d", entry->node_id);
-
-		sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
-		sysfs_remove_link(&dev->kobj, "firmware_node");
-		ACPI_HANDLE_SET(dev, NULL);
-		/* acpi_bind_one increase refcnt by one */
-		put_device(dev);
-		kfree(entry);
-	}
 	mutex_unlock(&acpi_dev->physical_node_lock);
-
 	return 0;
-
-err:
-	dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
-	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(acpi_unbind_one);
 
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 5da44e8..20f4233 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -23,6 +23,7 @@
 
 #define PREFIX "ACPI: "
 
+acpi_status acpi_os_initialize1(void);
 int init_acpi_device_notify(void);
 int acpi_scan_init(void);
 #ifdef	CONFIG_ACPI_PCI_SLOT
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 33e609f..2e82e5d 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -159,7 +159,7 @@
  * distance than the others.
  * Do some quick checks here and only use the SLIT if it passes.
  */
-static __init int slit_valid(struct acpi_table_slit *slit)
+static int __init slit_valid(struct acpi_table_slit *slit)
 {
 	int i, j;
 	int d = slit->locality_count;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 6ab2c35..e5f416c 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -52,6 +52,7 @@
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/processor.h>
+#include "internal.h"
 
 #define _COMPONENT		ACPI_OS_SERVICES
 ACPI_MODULE_NAME("osl");
@@ -79,6 +80,8 @@
 
 static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
 				      u32 pm1b_ctrl);
+static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a,
+				      u32 val_b);
 
 static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
@@ -140,7 +143,8 @@
 	unsigned int	enable:1;
 	unsigned int	dmi:1;
 	unsigned int	cmdline:1;
-} osi_linux = {0, 0, 0};
+	unsigned int	default_disabling:1;
+} osi_linux = {0, 0, 0, 0};
 
 static u32 acpi_osi_handler(acpi_string interface, u32 supported)
 {
@@ -563,10 +567,6 @@
 	ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
 	ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL };
 
-/* Non-fatal errors: Affected tables/files are ignored */
-#define INVALID_TABLE(x, path, name)					\
-	{ pr_err("ACPI OVERRIDE: " x " [%s%s]\n", path, name); continue; }
-
 #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
 
 /* Must not increase 10 or needs code modification below */
@@ -593,9 +593,11 @@
 		data += offset;
 		size -= offset;
 
-		if (file.size < sizeof(struct acpi_table_header))
-			INVALID_TABLE("Table smaller than ACPI header",
-				      cpio_path, file.name);
+		if (file.size < sizeof(struct acpi_table_header)) {
+			pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n",
+				cpio_path, file.name);
+			continue;
+		}
 
 		table = file.data;
 
@@ -603,15 +605,21 @@
 			if (!memcmp(table->signature, table_sigs[sig], 4))
 				break;
 
-		if (!table_sigs[sig])
-			INVALID_TABLE("Unknown signature",
-				      cpio_path, file.name);
-		if (file.size != table->length)
-			INVALID_TABLE("File length does not match table length",
-				      cpio_path, file.name);
-		if (acpi_table_checksum(file.data, table->length))
-			INVALID_TABLE("Bad table checksum",
-				      cpio_path, file.name);
+		if (!table_sigs[sig]) {
+			pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
+				cpio_path, file.name);
+			continue;
+		}
+		if (file.size != table->length) {
+			pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n",
+				cpio_path, file.name);
+			continue;
+		}
+		if (acpi_table_checksum(file.data, table->length)) {
+			pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n",
+				cpio_path, file.name);
+			continue;
+		}
 
 		pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n",
 			table->signature, cpio_path, file.name, table->length);
@@ -1351,8 +1359,8 @@
 	bool enable;
 };
 
-static struct osi_setup_entry __initdata
-		osi_setup_entries[OSI_STRING_ENTRIES_MAX] = {
+static struct osi_setup_entry
+		osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
 	{"Module Device", true},
 	{"Processor Device", true},
 	{"3.0 _SCP Extensions", true},
@@ -1376,6 +1384,17 @@
 
 	if (*str == '!') {
 		str++;
+		if (*str == '\0') {
+			osi_linux.default_disabling = 1;
+			return;
+		} else if (*str == '*') {
+			acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS);
+			for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+				osi = &osi_setup_entries[i];
+				osi->enable = false;
+			}
+			return;
+		}
 		enable = false;
 	}
 
@@ -1441,6 +1460,13 @@
 	int i;
 	acpi_status status;
 
+	if (osi_linux.default_disabling) {
+		status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
+
+		if (ACPI_SUCCESS(status))
+			printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n");
+	}
+
 	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
 		osi = &osi_setup_entries[i];
 		str = osi->string;
@@ -1779,6 +1805,28 @@
 	__acpi_os_prepare_sleep = func;
 }
 
+acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
+				  u32 val_b)
+{
+	int rc = 0;
+	if (__acpi_os_prepare_extended_sleep)
+		rc = __acpi_os_prepare_extended_sleep(sleep_state,
+					     val_a, val_b);
+	if (rc < 0)
+		return AE_ERROR;
+	else if (rc > 0)
+		return AE_CTRL_SKIP;
+
+	return AE_OK;
+}
+
+void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
+			       u32 val_a, u32 val_b))
+{
+	__acpi_os_prepare_extended_sleep = func;
+}
+
+
 void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
 			void (*func)(struct work_struct *work))
 {
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 5917839..d3874f4 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -378,6 +378,7 @@
 	struct acpi_pci_root *root;
 	u32 flags, base_flags;
 	acpi_handle handle = device->handle;
+	bool no_aspm = false, clear_aspm = false;
 
 	root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
 	if (!root)
@@ -437,27 +438,6 @@
 	flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
 	acpi_pci_osc_support(root, flags);
 
-	/*
-	 * TBD: Need PCI interface for enumeration/configuration of roots.
-	 */
-
-	/*
-	 * Scan the Root Bridge
-	 * --------------------
-	 * Must do this prior to any attempt to bind the root device, as the
-	 * PCI namespace does not get created until this call is made (and
-	 * thus the root bridge's pci_dev does not exist).
-	 */
-	root->bus = pci_acpi_scan_root(root);
-	if (!root->bus) {
-		dev_err(&device->dev,
-			"Bus %04x:%02x not present in PCI namespace\n",
-			root->segment, (unsigned int)root->secondary.start);
-		result = -ENODEV;
-		goto end;
-	}
-
-	/* Indicate support for various _OSC capabilities. */
 	if (pci_ext_cfg_avail())
 		flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
 	if (pcie_aspm_support_enabled()) {
@@ -471,7 +451,7 @@
 		if (ACPI_FAILURE(status)) {
 			dev_info(&device->dev, "ACPI _OSC support "
 				"notification failed, disabling PCIe ASPM\n");
-			pcie_no_aspm();
+			no_aspm = true;
 			flags = base_flags;
 		}
 	}
@@ -503,7 +483,7 @@
 				 * We have ASPM control, but the FADT indicates
 				 * that it's unsupported. Clear it.
 				 */
-				pcie_clear_aspm(root->bus);
+				clear_aspm = true;
 			}
 		} else {
 			dev_info(&device->dev,
@@ -512,7 +492,14 @@
 				acpi_format_exception(status), flags);
 			dev_info(&device->dev,
 				 "ACPI _OSC control for PCIe not granted, disabling ASPM\n");
-			pcie_no_aspm();
+			/*
+			 * We want to disable ASPM here, but aspm_disabled
+			 * needs to remain in its state from boot so that we
+			 * properly handle PCIe 1.1 devices.  So we set this
+			 * flag here, to defer the action until after the ACPI
+			 * root scan.
+			 */
+			no_aspm = true;
 		}
 	} else {
 		dev_info(&device->dev,
@@ -520,16 +507,40 @@
 			 "(_OSC support mask: 0x%02x)\n", flags);
 	}
 
+	/*
+	 * TBD: Need PCI interface for enumeration/configuration of roots.
+	 */
+
+	/*
+	 * Scan the Root Bridge
+	 * --------------------
+	 * Must do this prior to any attempt to bind the root device, as the
+	 * PCI namespace does not get created until this call is made (and
+	 * thus the root bridge's pci_dev does not exist).
+	 */
+	root->bus = pci_acpi_scan_root(root);
+	if (!root->bus) {
+		dev_err(&device->dev,
+			"Bus %04x:%02x not present in PCI namespace\n",
+			root->segment, (unsigned int)root->secondary.start);
+		result = -ENODEV;
+		goto end;
+	}
+
+	if (clear_aspm) {
+		dev_info(&device->dev, "Disabling ASPM (FADT indicates it is unsupported)\n");
+		pcie_clear_aspm(root->bus);
+	}
+	if (no_aspm)
+		pcie_no_aspm();
+
 	pci_acpi_add_bus_pm_notifier(device, root->bus);
 	if (device->wakeup.flags.run_wake)
 		device_set_run_wake(root->bus->bridge, true);
 
 	if (system_state != SYSTEM_BOOTING) {
 		pcibios_resource_survey_bus(root->bus);
-		pci_assign_unassigned_bus_resources(root->bus);
-
-		/* need to after hot-added ioapic is registered */
-		pci_enable_bridges(root->bus);
+		pci_assign_unassigned_root_bus_resources(root->bus);
 	}
 
 	pci_bus_add_devices(root->bus);
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index 033d117..d678a18 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -159,12 +159,16 @@
 	return AE_OK;
 }
 
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
+void acpi_pci_slot_enumerate(struct pci_bus *bus)
 {
-	mutex_lock(&slot_list_lock);
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
-			    register_slot, NULL, bus, NULL);
-	mutex_unlock(&slot_list_lock);
+	acpi_handle handle = ACPI_HANDLE(bus->bridge);
+
+	if (handle) {
+		mutex_lock(&slot_list_lock);
+		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+				    register_slot, NULL, bus, NULL);
+		mutex_unlock(&slot_list_lock);
+	}
 }
 
 void acpi_pci_slot_remove(struct pci_bus *bus)
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 5c28c89..0dbe5cd 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -637,9 +637,7 @@
 	}
 
 	/* Execute _PSW */
-	arg_list.count = 1;
-	in_arg[0].integer.value = enable;
-	status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+	status = acpi_execute_simple_method(dev->handle, "_PSW", enable);
 	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
 		printk(KERN_ERR PREFIX "_PSW execution failed\n");
 		dev->wakeup.flags.valid = 0;
@@ -786,7 +784,7 @@
 		}
 	}
 
-	*state = ACPI_STATE_D3;
+	*state = ACPI_STATE_D3_COLD;
 	return 0;
 }
 
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a5e9f4a..cf34d90 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -28,7 +28,7 @@
 	return 0;
 }
 
-static struct dmi_system_id __initdata processor_idle_dmi_table[] = {
+static struct dmi_system_id processor_idle_dmi_table[] __initdata = {
 	{
 	set_no_mwait, "Extensa 5220", {
 	DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 870eaf5..e534ba6 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -91,21 +91,17 @@
 		acpi_processor_ppc_has_changed(pr, 1);
 		if (saved == pr->performance_platform_limit)
 			break;
-		acpi_bus_generate_proc_event(device, event,
-					pr->performance_platform_limit);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event,
 						  pr->performance_platform_limit);
 		break;
 	case ACPI_PROCESSOR_NOTIFY_POWER:
 		acpi_processor_cst_has_changed(pr);
-		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
 	case ACPI_PROCESSOR_NOTIFY_THROTTLING:
 		acpi_processor_tstate_has_changed(pr);
-		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
@@ -179,7 +175,9 @@
 	acpi_processor_load_module(pr);
 #endif
 	acpi_processor_get_throttling_info(pr);
-	acpi_processor_get_limit_info(pr);
+
+	if (pr->flags.throttling)
+		pr->flags.limit = 1;
 
 	if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
 		acpi_processor_power_init(pr);
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 1e9732d..51d7948 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -164,17 +164,12 @@
 		{.type = ACPI_TYPE_INTEGER,},
 	};
 	struct acpi_object_list arg_list = {2, params};
-	acpi_handle temp;
 
-	params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
-	params[1].integer.value =  status;
-
-	/* when there is no _OST , skip it */
-	if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp)))
-		return;
-
-	acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
-	return;
+	if (acpi_has_method(handle, "_OST")) {
+		params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
+		params[1].integer.value =  status;
+		acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+	}
 }
 
 int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
@@ -468,14 +463,11 @@
 int acpi_processor_get_performance_info(struct acpi_processor *pr)
 {
 	int result = 0;
-	acpi_status status = AE_OK;
-	acpi_handle handle = NULL;
 
 	if (!pr || !pr->performance || !pr->handle)
 		return -EINVAL;
 
-	status = acpi_get_handle(pr->handle, "_PCT", &handle);
-	if (ACPI_FAILURE(status)) {
+	if (!acpi_has_method(pr->handle, "_PCT")) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "ACPI-based processor performance control unavailable\n"));
 		return -ENODEV;
@@ -501,7 +493,7 @@
 	 */
  update_bios:
 #ifdef CONFIG_X86
-	if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){
+	if (acpi_has_method(pr->handle, "_PPC")) {
 		if(boot_cpu_has(X86_FEATURE_EST))
 			printk(KERN_WARNING FW_BUG "BIOS needs update for CPU "
 			       "frequency support\n");
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index e8e6527..d1d2e7f 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -186,18 +186,6 @@
 
 #endif
 
-int acpi_processor_get_limit_info(struct acpi_processor *pr)
-{
-
-	if (!pr)
-		return -EINVAL;
-
-	if (pr->flags.throttling)
-		pr->flags.limit = 1;
-
-	return 0;
-}
-
 /* thermal coolign device callbacks */
 static int acpi_processor_max_state(struct acpi_processor *pr)
 {
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 3322b47..b7201fc 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -505,14 +505,12 @@
 			   void *preproc_data)
 {
 	struct res_proc_context c;
-	acpi_handle not_used;
 	acpi_status status;
 
 	if (!adev || !adev->handle || !list_empty(list))
 		return -EINVAL;
 
-	status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
-	if (ACPI_FAILURE(status))
+	if (!acpi_has_method(adev->handle, METHOD_NAME__CRS))
 		return 0;
 
 	c.list = list;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index b6241ee..aef7e1c 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -873,14 +873,9 @@
 	u8 saved_charger_state = sbs->charger_present;
 	u8 saved_battery_state;
 	acpi_ac_get_present(sbs);
-	if (sbs->charger_present != saved_charger_state) {
-#ifdef CONFIG_ACPI_PROC_EVENT
-		acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
-					      ACPI_SBS_NOTIFY_STATUS,
-					      sbs->charger_present);
-#endif
+	if (sbs->charger_present != saved_charger_state)
 		kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
-	}
+
 	if (sbs->manager_present) {
 		for (id = 0; id < MAX_SBS_BAT; ++id) {
 			if (!(sbs->batteries_supported & (1 << id)))
@@ -890,12 +885,6 @@
 			acpi_battery_read(bat);
 			if (saved_battery_state == bat->present)
 				continue;
-#ifdef CONFIG_ACPI_PROC_EVENT
-			acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
-						      bat->name,
-						      ACPI_SBS_NOTIFY_STATUS,
-						      bat->present);
-#endif
 			kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
 		}
 	}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 8a46c92..61d090b 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -193,9 +193,6 @@
 static int acpi_scan_hot_remove(struct acpi_device *device)
 {
 	acpi_handle handle = device->handle;
-	acpi_handle not_used;
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
 	struct device *errdev;
 	acpi_status status;
 	unsigned long long sta;
@@ -258,32 +255,15 @@
 	put_device(&device->dev);
 	device = NULL;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
-		arg_list.count = 1;
-		arg_list.pointer = &arg;
-		arg.type = ACPI_TYPE_INTEGER;
-		arg.integer.value = 0;
-		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
-	}
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = 1;
-
+	acpi_evaluate_lck(handle, 0);
 	/*
 	 * TBD: _EJD support.
 	 */
-	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-	if (ACPI_FAILURE(status)) {
-		if (status == AE_NOT_FOUND) {
-			return -ENODEV;
-		} else {
-			acpi_handle_warn(handle, "Eject failed (0x%x)\n",
-								status);
-			return -EIO;
-		}
-	}
+	status = acpi_evaluate_ej0(handle);
+	if (status == AE_NOT_FOUND)
+		return -ENODEV;
+	else if (ACPI_FAILURE(status))
+		return -EIO;
 
 	/*
 	 * Verify if eject was indeed successful.  If not, log an error
@@ -307,6 +287,7 @@
 	struct acpi_device *device = NULL;
 	struct acpi_scan_handler *handler;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+	int error;
 
 	mutex_lock(&acpi_scan_lock);
 
@@ -321,17 +302,13 @@
 	}
 	acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
 				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
-	if (handler->hotplug.mode == AHM_CONTAINER) {
-		device->flags.eject_pending = true;
+	if (handler->hotplug.mode == AHM_CONTAINER)
 		kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-	} else {
-		int error;
 
-		get_device(&device->dev);
-		error = acpi_scan_hot_remove(device);
-		if (error)
-			goto err_out;
-	}
+	get_device(&device->dev);
+	error = acpi_scan_hot_remove(device);
+	if (error)
+		goto err_out;
 
  out:
 	mutex_unlock(&acpi_scan_lock);
@@ -516,7 +493,6 @@
 	struct acpi_eject_event *ej_event;
 	acpi_object_type not_used;
 	acpi_status status;
-	u32 ost_source;
 	int ret;
 
 	if (!count || buf[0] != '1')
@@ -530,43 +506,28 @@
 	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
 		return -ENODEV;
 
-	mutex_lock(&acpi_scan_lock);
-
-	if (acpi_device->flags.eject_pending) {
-		/* ACPI eject notification event. */
-		ost_source = ACPI_NOTIFY_EJECT_REQUEST;
-		acpi_device->flags.eject_pending = 0;
-	} else {
-		/* Eject initiated by user space. */
-		ost_source = ACPI_OST_EC_OSPM_EJECT;
-	}
 	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
 	if (!ej_event) {
 		ret = -ENOMEM;
 		goto err_out;
 	}
-	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
 				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
 	ej_event->device = acpi_device;
-	ej_event->event = ost_source;
+	ej_event->event = ACPI_OST_EC_OSPM_EJECT;
 	get_device(&acpi_device->dev);
 	status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
-	if (ACPI_FAILURE(status)) {
-		put_device(&acpi_device->dev);
-		kfree(ej_event);
-		ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
-		goto err_out;
-	}
-	ret = count;
+	if (ACPI_SUCCESS(status))
+		return count;
 
- out:
-	mutex_unlock(&acpi_scan_lock);
-	return ret;
+	put_device(&acpi_device->dev);
+	kfree(ej_event);
+	ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
 
  err_out:
-	acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+	acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
 				  ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
-	goto out;
+	return ret;
 }
 
 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -654,7 +615,6 @@
 {
 	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_status status;
-	acpi_handle temp;
 	unsigned long long sun;
 	int result = 0;
 
@@ -680,8 +640,7 @@
 	/*
 	 * If device has _STR, 'description' file is created
 	 */
-	status = acpi_get_handle(dev->handle, "_STR", &temp);
-	if (ACPI_SUCCESS(status)) {
+	if (acpi_has_method(dev->handle, "_STR")) {
 		status = acpi_evaluate_object(dev->handle, "_STR",
 					NULL, &buffer);
 		if (ACPI_FAILURE(status))
@@ -711,8 +670,7 @@
          * If device has _EJ0, 'eject' file is created that is used to trigger
          * hot-removal function from userland.
          */
-	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-	if (ACPI_SUCCESS(status)) {
+	if (acpi_has_method(dev->handle, "_EJ0")) {
 		result = device_create_file(&dev->dev, &dev_attr_eject);
 		if (result)
 			return result;
@@ -734,9 +692,6 @@
 
 static void acpi_device_remove_files(struct acpi_device *dev)
 {
-	acpi_status status;
-	acpi_handle temp;
-
 	if (dev->flags.power_manageable) {
 		device_remove_file(&dev->dev, &dev_attr_power_state);
 		if (dev->power.flags.power_resources)
@@ -747,20 +702,17 @@
 	/*
 	 * If device has _STR, remove 'description' file
 	 */
-	status = acpi_get_handle(dev->handle, "_STR", &temp);
-	if (ACPI_SUCCESS(status)) {
+	if (acpi_has_method(dev->handle, "_STR")) {
 		kfree(dev->pnp.str_obj);
 		device_remove_file(&dev->dev, &dev_attr_description);
 	}
 	/*
 	 * If device has _EJ0, remove 'eject' file.
 	 */
-	status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(dev->handle, "_EJ0"))
 		device_remove_file(&dev->dev, &dev_attr_eject);
 
-	status = acpi_get_handle(dev->handle, "_SUN", &temp);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(dev->handle, "_SUN"))
 		device_remove_file(&dev->dev, &dev_attr_sun);
 
 	if (dev->pnp.unique_id)
@@ -999,6 +951,28 @@
 	.uevent		= acpi_device_uevent,
 };
 
+static void acpi_bus_data_handler(acpi_handle handle, void *context)
+{
+	/* Intentionally empty. */
+}
+
+int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
+{
+	acpi_status status;
+
+	if (!device)
+		return -EINVAL;
+
+	status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
+	if (ACPI_FAILURE(status) || !*device) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
+				  handle));
+		return -ENODEV;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_device);
+
 int acpi_device_add(struct acpi_device *device,
 		    void (*release)(struct device *))
 {
@@ -1210,14 +1184,6 @@
 }
 EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
 
-void acpi_bus_data_handler(acpi_handle handle, void *context)
-{
-
-	/* TBD */
-
-	return;
-}
-
 static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
 					struct acpi_device_wakeup *wakeup)
 {
@@ -1336,13 +1302,10 @@
 
 static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 {
-	acpi_handle temp;
-	acpi_status status = 0;
 	int err;
 
 	/* Presence of _PRW indicates wake capable */
-	status = acpi_get_handle(device->handle, "_PRW", &temp);
-	if (ACPI_FAILURE(status))
+	if (!acpi_has_method(device->handle, "_PRW"))
 		return;
 
 	err = acpi_bus_extract_wakeup_device_power_package(device->handle,
@@ -1372,7 +1335,6 @@
 	struct acpi_device_power_state *ps = &device->power.states[state];
 	char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' };
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	acpi_handle handle;
 	acpi_status status;
 
 	INIT_LIST_HEAD(&ps->resources);
@@ -1395,8 +1357,7 @@
 
 	/* Evaluate "_PSx" to see if we can do explicit sets */
 	pathname[2] = 'S';
-	status = acpi_get_handle(device->handle, pathname, &handle);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(device->handle, pathname))
 		ps->flags.explicit_set = 1;
 
 	/*
@@ -1415,28 +1376,21 @@
 
 static void acpi_bus_get_power_flags(struct acpi_device *device)
 {
-	acpi_status status;
-	acpi_handle handle;
 	u32 i;
 
 	/* Presence of _PS0|_PR0 indicates 'power manageable' */
-	status = acpi_get_handle(device->handle, "_PS0", &handle);
-	if (ACPI_FAILURE(status)) {
-		status = acpi_get_handle(device->handle, "_PR0", &handle);
-		if (ACPI_FAILURE(status))
-			return;
-	}
+	if (!acpi_has_method(device->handle, "_PS0") &&
+	    !acpi_has_method(device->handle, "_PR0"))
+		return;
 
 	device->flags.power_manageable = 1;
 
 	/*
 	 * Power Management Flags
 	 */
-	status = acpi_get_handle(device->handle, "_PSC", &handle);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(device->handle, "_PSC"))
 		device->power.flags.explicit_get = 1;
-	status = acpi_get_handle(device->handle, "_IRC", &handle);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(device->handle, "_IRC"))
 		device->power.flags.inrush_current = 1;
 
 	/*
@@ -1450,8 +1404,8 @@
 	/* Set defaults for D0 and D3 states (always valid) */
 	device->power.states[ACPI_STATE_D0].flags.valid = 1;
 	device->power.states[ACPI_STATE_D0].power = 100;
-	device->power.states[ACPI_STATE_D3].flags.valid = 1;
-	device->power.states[ACPI_STATE_D3].power = 0;
+	device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
+	device->power.states[ACPI_STATE_D3_COLD].power = 0;
 
 	/* Set D3cold's explicit_set flag if _PS3 exists. */
 	if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
@@ -1470,28 +1424,18 @@
 
 static void acpi_bus_get_flags(struct acpi_device *device)
 {
-	acpi_status status = AE_OK;
-	acpi_handle temp = NULL;
-
 	/* Presence of _STA indicates 'dynamic_status' */
-	status = acpi_get_handle(device->handle, "_STA", &temp);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(device->handle, "_STA"))
 		device->flags.dynamic_status = 1;
 
 	/* Presence of _RMV indicates 'removable' */
-	status = acpi_get_handle(device->handle, "_RMV", &temp);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(device->handle, "_RMV"))
 		device->flags.removable = 1;
 
 	/* Presence of _EJD|_EJ0 indicates 'ejectable' */
-	status = acpi_get_handle(device->handle, "_EJD", &temp);
-	if (ACPI_SUCCESS(status))
+	if (acpi_has_method(device->handle, "_EJD") ||
+	    acpi_has_method(device->handle, "_EJ0"))
 		device->flags.ejectable = 1;
-	else {
-		status = acpi_get_handle(device->handle, "_EJ0", &temp);
-		if (ACPI_SUCCESS(status))
-			device->flags.ejectable = 1;
-	}
 }
 
 static void acpi_device_get_busid(struct acpi_device *device)
@@ -1533,46 +1477,45 @@
 }
 
 /*
+ * acpi_ata_match - see if an acpi object is an ATA device
+ *
+ * If an acpi object has one of the ACPI ATA methods defined,
+ * then we can safely call it an ATA device.
+ */
+bool acpi_ata_match(acpi_handle handle)
+{
+	return acpi_has_method(handle, "_GTF") ||
+	       acpi_has_method(handle, "_GTM") ||
+	       acpi_has_method(handle, "_STM") ||
+	       acpi_has_method(handle, "_SDD");
+}
+
+/*
  * acpi_bay_match - see if an acpi object is an ejectable driver bay
  *
  * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
  * then we can safely call it an ejectable drive bay
  */
-static int acpi_bay_match(acpi_handle handle)
+bool acpi_bay_match(acpi_handle handle)
 {
-	acpi_status status;
-	acpi_handle tmp;
 	acpi_handle phandle;
 
-	status = acpi_get_handle(handle, "_EJ0", &tmp);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
+	if (!acpi_has_method(handle, "_EJ0"))
+		return false;
+	if (acpi_ata_match(handle))
+		return true;
+	if (ACPI_FAILURE(acpi_get_parent(handle, &phandle)))
+		return false;
 
-	if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
-		(ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
-		(ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
-		(ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
-		return 0;
-
-	if (acpi_get_parent(handle, &phandle))
-		return -ENODEV;
-
-        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
-                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
-                return 0;
-
-	return -ENODEV;
+	return acpi_ata_match(phandle);
 }
 
 /*
  * acpi_dock_match - see if an acpi object has a _DCK method
  */
-static int acpi_dock_match(acpi_handle handle)
+bool acpi_dock_match(acpi_handle handle)
 {
-	acpi_handle tmp;
-	return acpi_get_handle(handle, "_DCK", &tmp);
+	return acpi_has_method(handle, "_DCK");
 }
 
 const char *acpi_device_hid(struct acpi_device *device)
@@ -1610,34 +1553,26 @@
  * lacks the SMBUS01 HID and the methods do not have the necessary "_"
  * prefix.  Work around this.
  */
-static int acpi_ibm_smbus_match(acpi_handle handle)
+static bool acpi_ibm_smbus_match(acpi_handle handle)
 {
-	acpi_handle h_dummy;
-	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
-	int result;
+	char node_name[ACPI_PATH_SEGMENT_LENGTH];
+	struct acpi_buffer path = { sizeof(node_name), node_name };
 
 	if (!dmi_name_in_vendors("IBM"))
-		return -ENODEV;
+		return false;
 
 	/* Look for SMBS object */
-	result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
-	if (result)
-		return result;
-
-	if (strcmp("SMBS", path.pointer)) {
-		result = -ENODEV;
-		goto out;
-	}
+	if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &path)) ||
+	    strcmp("SMBS", path.pointer))
+		return false;
 
 	/* Does it have the necessary (but misnamed) methods? */
-	result = -ENODEV;
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
-	    ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
-	    ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
-		result = 0;
-out:
-	kfree(path.pointer);
-	return result;
+	if (acpi_has_method(handle, "SBI") &&
+	    acpi_has_method(handle, "SBR") &&
+	    acpi_has_method(handle, "SBW"))
+		return true;
+
+	return false;
 }
 
 static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
@@ -1685,11 +1620,11 @@
 		 */
 		if (acpi_is_video_device(handle))
 			acpi_add_id(pnp, ACPI_VIDEO_HID);
-		else if (ACPI_SUCCESS(acpi_bay_match(handle)))
+		else if (acpi_bay_match(handle))
 			acpi_add_id(pnp, ACPI_BAY_HID);
-		else if (ACPI_SUCCESS(acpi_dock_match(handle)))
+		else if (acpi_dock_match(handle))
 			acpi_add_id(pnp, ACPI_DOCK_HID);
-		else if (!acpi_ibm_smbus_match(handle))
+		else if (acpi_ibm_smbus_match(handle))
 			acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
 		else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
 			acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
@@ -1900,7 +1835,6 @@
 	struct acpi_device *device = NULL;
 	int type;
 	unsigned long long sta;
-	acpi_status status;
 	int result;
 
 	acpi_bus_get_device(handle, &device);
@@ -1921,10 +1855,8 @@
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
 	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
 		struct acpi_device_wakeup wakeup;
-		acpi_handle temp;
 
-		status = acpi_get_handle(handle, "_PRW", &temp);
-		if (ACPI_SUCCESS(status)) {
+		if (acpi_has_method(handle, "_PRW")) {
 			acpi_bus_extract_wakeup_device_power_package(handle,
 								     &wakeup);
 			acpi_power_resources_list_free(&wakeup.resources);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 187ab61..14df305 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -31,12 +31,9 @@
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
-	union acpi_object in_arg = { ACPI_TYPE_INTEGER };
-	struct acpi_object_list arg_list = { 1, &in_arg };
-	acpi_status status = AE_OK;
+	acpi_status status;
 
-	in_arg.integer.value = acpi_state;
-	status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
+	status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state);
 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 		/*
 		 * OS can't evaluate the _TTS object correctly. Some warning
@@ -141,7 +138,7 @@
 	return 0;
 }
 
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+static struct dmi_system_id acpisleep_dmi_table[] __initdata = {
 	{
 	.callback = init_old_suspend_ordering,
 	.ident = "Abit KN9 (nForce4 variant)",
@@ -423,10 +420,21 @@
 }
 
 /**
- *	acpi_pm_end - Finish up suspend sequence.
+ * acpi_pm_start - Start system PM transition.
+ */
+static void acpi_pm_start(u32 acpi_state)
+{
+	acpi_target_sleep_state = acpi_state;
+	acpi_sleep_tts_switch(acpi_target_sleep_state);
+	acpi_scan_lock_acquire();
+}
+
+/**
+ * acpi_pm_end - Finish up system PM transition.
  */
 static void acpi_pm_end(void)
 {
+	acpi_scan_lock_release();
 	/*
 	 * This is necessary in case acpi_pm_finish() is not called during a
 	 * failing transition to a sleep state.
@@ -454,21 +462,19 @@
 static int acpi_suspend_begin(suspend_state_t pm_state)
 {
 	u32 acpi_state = acpi_suspend_states[pm_state];
-	int error = 0;
+	int error;
 
 	error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
 	if (error)
 		return error;
 
-	if (sleep_states[acpi_state]) {
-		acpi_target_sleep_state = acpi_state;
-		acpi_sleep_tts_switch(acpi_target_sleep_state);
-	} else {
-		printk(KERN_ERR "ACPI does not support this state: %d\n",
-			pm_state);
-		error = -ENOSYS;
+	if (!sleep_states[acpi_state]) {
+		pr_err("ACPI does not support sleep state S%u\n", acpi_state);
+		return -ENOSYS;
 	}
-	return error;
+
+	acpi_pm_start(acpi_state);
+	return 0;
 }
 
 /**
@@ -634,10 +640,8 @@
 	int error;
 
 	error = nvs_nosave ? 0 : suspend_nvs_alloc();
-	if (!error) {
-		acpi_target_sleep_state = ACPI_STATE_S4;
-		acpi_sleep_tts_switch(acpi_target_sleep_state);
-	}
+	if (!error)
+		acpi_pm_start(ACPI_STATE_S4);
 
 	return error;
 }
@@ -716,8 +720,10 @@
 	if (!error) {
 		if (!nvs_nosave)
 			error = suspend_nvs_alloc();
-		if (!error)
+		if (!error) {
 			acpi_target_sleep_state = ACPI_STATE_S4;
+			acpi_scan_lock_acquire();
+		}
 	}
 	return error;
 }
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index a33821c..6a03293 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -50,11 +50,6 @@
 
 #define ACPI_THERMAL_CLASS		"thermal_zone"
 #define ACPI_THERMAL_DEVICE_NAME	"Thermal Zone"
-#define ACPI_THERMAL_FILE_STATE		"state"
-#define ACPI_THERMAL_FILE_TEMPERATURE	"temperature"
-#define ACPI_THERMAL_FILE_TRIP_POINTS	"trip_points"
-#define ACPI_THERMAL_FILE_COOLING_MODE	"cooling_mode"
-#define ACPI_THERMAL_FILE_POLLING_FREQ	"polling_frequency"
 #define ACPI_THERMAL_NOTIFY_TEMPERATURE	0x80
 #define ACPI_THERMAL_NOTIFY_THRESHOLDS	0x81
 #define ACPI_THERMAL_NOTIFY_DEVICES	0x82
@@ -190,7 +185,6 @@
 	struct thermal_zone_device *thermal_zone;
 	int tz_enabled;
 	int kelvin_offset;
-	struct mutex lock;
 };
 
 /* --------------------------------------------------------------------------
@@ -239,26 +233,16 @@
 
 static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
 {
-	acpi_status status = AE_OK;
-	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-	struct acpi_object_list arg_list = { 1, &arg0 };
-	acpi_handle handle = NULL;
-
-
 	if (!tz)
 		return -EINVAL;
 
-	status = acpi_get_handle(tz->device->handle, "_SCP", &handle);
-	if (ACPI_FAILURE(status)) {
+	if (!acpi_has_method(tz->device->handle, "_SCP")) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
 		return -ENODEV;
-	}
-
-	arg0.integer.value = mode;
-
-	status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
-	if (ACPI_FAILURE(status))
+	} else if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
+							   "_SCP", mode))) {
 		return -ENODEV;
+	}
 
 	return 0;
 }
@@ -491,14 +475,14 @@
 			break;
 	}
 
-	if (flag & ACPI_TRIPS_DEVICES) {
-		memset(&devices, 0, sizeof(struct acpi_handle_list));
+	if ((flag & ACPI_TRIPS_DEVICES)
+	    && acpi_has_method(tz->device->handle, "_TZD")) {
+		memset(&devices, 0, sizeof(devices));
 		status = acpi_evaluate_reference(tz->device->handle, "_TZD",
 						NULL, &devices);
-		if (memcmp(&tz->devices, &devices,
-				sizeof(struct acpi_handle_list))) {
-			memcpy(&tz->devices, &devices,
-				sizeof(struct acpi_handle_list));
+		if (ACPI_SUCCESS(status)
+		    && memcmp(&tz->devices, &devices, sizeof(devices))) {
+			tz->devices = devices;
 			ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 		}
 	}
@@ -769,7 +753,6 @@
 	else
 		return 0;
 
-	acpi_bus_generate_proc_event(tz->device, type, 1);
 	acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
 					dev_name(&tz->device->dev), type, 1);
 
@@ -850,12 +833,13 @@
 		if (ACPI_SUCCESS(status) && (dev == device)) {
 			if (bind)
 				result = thermal_zone_bind_cooling_device
-						(thermal, -1, cdev,
-						 THERMAL_NO_LIMIT,
+						(thermal, THERMAL_TRIPS_NONE,
+						 cdev, THERMAL_NO_LIMIT,
 						 THERMAL_NO_LIMIT);
 			else
 				result = thermal_zone_unbind_cooling_device
-						(thermal, -1, cdev);
+						(thermal, THERMAL_TRIPS_NONE,
+						 cdev);
 			if (result)
 				goto failed;
 		}
@@ -980,14 +964,12 @@
 	case ACPI_THERMAL_NOTIFY_THRESHOLDS:
 		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
 		acpi_thermal_check(tz);
-		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
 	case ACPI_THERMAL_NOTIFY_DEVICES:
 		acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
 		acpi_thermal_check(tz);
-		acpi_bus_generate_proc_event(device, event, 0);
 		acpi_bus_generate_netlink_event(device->pnp.device_class,
 						  dev_name(&device->dev), event, 0);
 		break;
@@ -1101,8 +1083,6 @@
 	strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
 	device->driver_data = tz;
-	mutex_init(&tz->lock);
-
 
 	result = acpi_thermal_get_info(tz);
 	if (result)
@@ -1135,7 +1115,6 @@
 	tz = acpi_driver_data(device);
 
 	acpi_thermal_unregister_thermal_zone(tz);
-	mutex_destroy(&tz->lock);
 	kfree(tz);
 	return 0;
 }
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 74437130..552248b 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -495,3 +495,73 @@
 	kfree(buffer.pointer);
 }
 EXPORT_SYMBOL(acpi_handle_printk);
+
+/**
+ * acpi_has_method: Check whether @handle has a method named @name
+ * @handle: ACPI device handle
+ * @name: name of object or method
+ *
+ * Check whether @handle has a method named @name.
+ */
+bool acpi_has_method(acpi_handle handle, char *name)
+{
+	acpi_handle tmp;
+
+	return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp));
+}
+EXPORT_SYMBOL(acpi_has_method);
+
+acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
+				       u64 arg)
+{
+	union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
+	struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };
+
+	obj.integer.value = arg;
+
+	return acpi_evaluate_object(handle, method, &arg_list, NULL);
+}
+EXPORT_SYMBOL(acpi_execute_simple_method);
+
+/**
+ * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations
+ * @handle: ACPI device handle
+ *
+ * Evaluate device's _EJ0 method for hotplug operations.
+ */
+acpi_status acpi_evaluate_ej0(acpi_handle handle)
+{
+	acpi_status status;
+
+	status = acpi_execute_simple_method(handle, "_EJ0", 1);
+	if (status == AE_NOT_FOUND)
+		acpi_handle_warn(handle, "No _EJ0 support for device\n");
+	else if (ACPI_FAILURE(status))
+		acpi_handle_warn(handle, "Eject failed (0x%x)\n", status);
+
+	return status;
+}
+
+/**
+ * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device
+ * @handle: ACPI device handle
+ * @lock: lock device if non-zero, otherwise unlock device
+ *
+ * Evaluate device's _LCK method if present to lock/unlock device
+ */
+acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
+{
+	acpi_status status;
+
+	status = acpi_execute_simple_method(handle, "_LCK", !!lock);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		if (lock)
+			acpi_handle_warn(handle,
+				"Locking device failed (0x%x)\n", status);
+		else
+			acpi_handle_warn(handle,
+				"Unlocking device failed (0x%x)\n", status);
+	}
+
+	return status;
+}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index e1284b8..aebcf63 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1,5 +1,5 @@
 /*
- *  video.c - ACPI Video Driver ($Revision:$)
+ *  video.c - ACPI Video Driver
  *
  *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
  *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
@@ -88,7 +88,7 @@
 static bool use_bios_initial_backlight = 1;
 module_param(use_bios_initial_backlight, bool, 0644);
 
-static int register_count = 0;
+static int register_count;
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device);
 static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
@@ -118,26 +118,26 @@
 };
 
 struct acpi_video_bus_cap {
-	u8 _DOS:1;		/*Enable/Disable output switching */
-	u8 _DOD:1;		/*Enumerate all devices attached to display adapter */
-	u8 _ROM:1;		/*Get ROM Data */
-	u8 _GPD:1;		/*Get POST Device */
-	u8 _SPD:1;		/*Set POST Device */
-	u8 _VPO:1;		/*Video POST Options */
+	u8 _DOS:1;		/* Enable/Disable output switching */
+	u8 _DOD:1;		/* Enumerate all devices attached to display adapter */
+	u8 _ROM:1;		/* Get ROM Data */
+	u8 _GPD:1;		/* Get POST Device */
+	u8 _SPD:1;		/* Set POST Device */
+	u8 _VPO:1;		/* Video POST Options */
 	u8 reserved:2;
 };
 
 struct acpi_video_device_attrib {
 	u32 display_index:4;	/* A zero-based instance of the Display */
-	u32 display_port_attachment:4;	/*This field differentiates the display type */
-	u32 display_type:4;	/*Describe the specific type in use */
-	u32 vendor_specific:4;	/*Chipset Vendor Specific */
-	u32 bios_can_detect:1;	/*BIOS can detect the device */
-	u32 depend_on_vga:1;	/*Non-VGA output device whose power is related to 
+	u32 display_port_attachment:4;	/* This field differentiates the display type */
+	u32 display_type:4;	/* Describe the specific type in use */
+	u32 vendor_specific:4;	/* Chipset Vendor Specific */
+	u32 bios_can_detect:1;	/* BIOS can detect the device */
+	u32 depend_on_vga:1;	/* Non-VGA output device whose power is related to
 				   the VGA device. */
-	u32 pipe_id:3;		/*For VGA multiple-head devices. */
-	u32 reserved:10;	/*Must be 0 */
-	u32 device_id_scheme:1;	/*Device ID Scheme */
+	u32 pipe_id:3;		/* For VGA multiple-head devices. */
+	u32 reserved:10;	/* Must be 0 */
+	u32 device_id_scheme:1;	/* Device ID Scheme */
 };
 
 struct acpi_video_enumerated_device {
@@ -174,19 +174,17 @@
 };
 
 struct acpi_video_device_cap {
-	u8 _ADR:1;		/*Return the unique ID */
-	u8 _BCL:1;		/*Query list of brightness control levels supported */
-	u8 _BCM:1;		/*Set the brightness level */
+	u8 _ADR:1;		/* Return the unique ID */
+	u8 _BCL:1;		/* Query list of brightness control levels supported */
+	u8 _BCM:1;		/* Set the brightness level */
 	u8 _BQC:1;		/* Get current brightness level */
 	u8 _BCQ:1;		/* Some buggy BIOS uses _BCQ instead of _BQC */
-	u8 _DDC:1;		/*Return the EDID for this device */
+	u8 _DDC:1;		/* Return the EDID for this device */
 };
 
 struct acpi_video_brightness_flags {
 	u8 _BCL_no_ac_battery_levels:1;	/* no AC/Battery levels in _BCL */
-	u8 _BCL_reversed:1;		/* _BCL package is in a reversed order*/
-	u8 _BCL_use_index:1;		/* levels in _BCL are index values */
-	u8 _BCM_use_index:1;		/* input of _BCM is an index value */
+	u8 _BCL_reversed:1;		/* _BCL package is in a reversed order */
 	u8 _BQC_use_index:1;		/* _BQC returns an index value */
 };
 
@@ -231,21 +229,22 @@
 static int acpi_video_switch_brightness(struct acpi_video_device *device,
 					 int event);
 
-/*backlight device sysfs support*/
+/* backlight device sysfs support */
 static int acpi_video_get_brightness(struct backlight_device *bd)
 {
 	unsigned long long cur_level;
 	int i;
-	struct acpi_video_device *vd =
-		(struct acpi_video_device *)bl_get_data(bd);
+	struct acpi_video_device *vd = bl_get_data(bd);
 
 	if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
 		return -EINVAL;
 	for (i = 2; i < vd->brightness->count; i++) {
 		if (vd->brightness->levels[i] == cur_level)
-			/* The first two entries are special - see page 575
-			   of the ACPI spec 3.0 */
-			return i-2;
+			/*
+			 * The first two entries are special - see page 575
+			 * of the ACPI spec 3.0
+			 */
+			return i - 2;
 	}
 	return 0;
 }
@@ -253,8 +252,7 @@
 static int acpi_video_set_brightness(struct backlight_device *bd)
 {
 	int request_level = bd->props.brightness + 2;
-	struct acpi_video_device *vd =
-		(struct acpi_video_device *)bl_get_data(bd);
+	struct acpi_video_device *vd = bl_get_data(bd);
 
 	return acpi_video_device_lcd_set_level(vd,
 				vd->brightness->levels[request_level]);
@@ -302,11 +300,11 @@
 	struct acpi_video_device *video = acpi_driver_data(device);
 	int level;
 
-	if ( state >= video->brightness->count - 2)
+	if (state >= video->brightness->count - 2)
 		return -EINVAL;
 
 	state = video->brightness->count - state;
-	level = video->brightness->levels[state -1];
+	level = video->brightness->levels[state - 1];
 	return acpi_video_device_lcd_set_level(video, level);
 }
 
@@ -316,9 +314,11 @@
 	.set_cur_state = video_set_cur_state,
 };
 
-/* --------------------------------------------------------------------------
-                               Video Management
-   -------------------------------------------------------------------------- */
+/*
+ * --------------------------------------------------------------------------
+ *                             Video Management
+ * --------------------------------------------------------------------------
+ */
 
 static int
 acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
@@ -345,7 +345,7 @@
 
 	return 0;
 
-      err:
+err:
 	kfree(buffer.pointer);
 
 	return status;
@@ -355,14 +355,10 @@
 acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
 {
 	int status;
-	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-	struct acpi_object_list args = { 1, &arg0 };
 	int state;
 
-	arg0.integer.value = level;
-
-	status = acpi_evaluate_object(device->dev->handle, "_BCM",
-				      &args, NULL);
+	status = acpi_execute_simple_method(device->dev->handle,
+					    "_BCM", level);
 	if (ACPI_FAILURE(status)) {
 		ACPI_ERROR((AE_INFO, "Evaluating _BCM failed"));
 		return -EIO;
@@ -546,7 +542,7 @@
 				if (device->brightness->levels[i] == *level) {
 					device->brightness->curr = *level;
 					return 0;
-			}
+				}
 			/*
 			 * BQC returned an invalid level.
 			 * Stop using it.
@@ -556,7 +552,8 @@
 				      buf));
 			device->cap._BQC = device->cap._BCQ = 0;
 		} else {
-			/* Fixme:
+			/*
+			 * Fixme:
 			 * should we return an error or ignore this failure?
 			 * dev->brightness->curr is a cached value which stores
 			 * the correct current backlight level in most cases.
@@ -615,8 +612,8 @@
 
 /*
  *  Arg:
- *  	video		: video bus device pointer
- *	bios_flag	: 
+ *	video		: video bus device pointer
+ *	bios_flag	:
  *		0.	The system BIOS should NOT automatically switch(toggle)
  *			the active display output.
  *		1.	The system BIOS should automatically switch (toggle) the
@@ -628,9 +625,9 @@
  *	lcd_flag	:
  *		0.	The system BIOS should automatically control the brightness level
  *			of the LCD when the power changes from AC to DC
- *		1. 	The system BIOS should NOT automatically control the brightness 
+ *		1.	The system BIOS should NOT automatically control the brightness
  *			level of the LCD when the power changes from AC to DC.
- * Return Value:
+ *  Return Value:
  *		-EINVAL	wrong arg.
  */
 
@@ -638,18 +635,15 @@
 acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
 {
 	acpi_status status;
-	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-	struct acpi_object_list args = { 1, &arg0 };
 
 	if (!video->cap._DOS)
 		return 0;
 
 	if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
 		return -EINVAL;
-	arg0.integer.value = (lcd_flag << 2) | bios_flag;
-	video->dos_setting = arg0.integer.value;
-	status = acpi_evaluate_object(video->device->handle, "_DOS",
-		&args, NULL);
+	video->dos_setting = (lcd_flag << 2) | bios_flag;
+	status = acpi_execute_simple_method(video->device->handle, "_DOS",
+					    (lcd_flag << 2) | bios_flag);
 	if (ACPI_FAILURE(status))
 		return -EIO;
 
@@ -717,8 +711,8 @@
 
 
 /*
- *  Arg:	
- *  	device	: video output device (LCD, CRT, ..)
+ *  Arg:
+ *	device	: video output device (LCD, CRT, ..)
  *
  *  Return Value:
  *	Maximum brightness level
@@ -806,16 +800,6 @@
 	br->count = count;
 	device->brightness = br;
 
-	/* Check the input/output of _BQC/_BCL/_BCM */
-	if ((max_level < 100) && (max_level <= (count - 2)))
-		br->flags._BCL_use_index = 1;
-
-	/*
-	 * _BCM is always consistent with _BCL,
-	 * at least for all the laptops we have ever seen.
-	 */
-	br->flags._BCM_use_index = br->flags._BCL_use_index;
-
 	/* _BQC uses INDEX while _BCL uses VALUE in some laptops */
 	br->curr = level = max_level;
 
@@ -877,7 +861,7 @@
  *	device	: video output device (LCD, CRT, ..)
  *
  *  Return Value:
- *  	None
+ *	None
  *
  *  Find out all required AML methods defined under the output
  *  device.
@@ -885,31 +869,21 @@
 
 static void acpi_video_device_find_cap(struct acpi_video_device *device)
 {
-	acpi_handle h_dummy1;
-
-	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
+	if (acpi_has_method(device->dev->handle, "_ADR"))
 		device->cap._ADR = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
+	if (acpi_has_method(device->dev->handle, "_BCL"))
 		device->cap._BCL = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
+	if (acpi_has_method(device->dev->handle, "_BCM"))
 		device->cap._BCM = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+	if (acpi_has_method(device->dev->handle, "_BQC")) {
 		device->cap._BQC = 1;
-	else if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCQ",
-				&h_dummy1))) {
+	} else if (acpi_has_method(device->dev->handle, "_BCQ")) {
 		printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n");
 		device->cap._BCQ = 1;
 	}
 
-	if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
+	if (acpi_has_method(device->dev->handle, "_DDC"))
 		device->cap._DDC = 1;
-	}
-
-	if (acpi_video_init_brightness(device))
-		return;
 
 	if (acpi_video_backlight_support()) {
 		struct backlight_properties props;
@@ -917,9 +891,12 @@
 		acpi_handle acpi_parent;
 		struct device *parent = NULL;
 		int result;
-		static int count = 0;
+		static int count;
 		char *name;
 
+		result = acpi_video_init_brightness(device);
+		if (result)
+			return;
 		name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
 		if (!name)
 			return;
@@ -979,46 +956,33 @@
 		if (result)
 			printk(KERN_ERR PREFIX "Create sysfs link\n");
 
-	} else {
-		/* Remove the brightness object. */
-		kfree(device->brightness->levels);
-		kfree(device->brightness);
-		device->brightness = NULL;
 	}
 }
 
 /*
- *  Arg:	
- *  	device	: video output device (VGA)
+ *  Arg:
+ *	device	: video output device (VGA)
  *
  *  Return Value:
- *  	None
+ *	None
  *
  *  Find out all required AML methods defined under the video bus device.
  */
 
 static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
 {
-	acpi_handle h_dummy1;
-
-	if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
+	if (acpi_has_method(video->device->handle, "_DOS"))
 		video->cap._DOS = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
+	if (acpi_has_method(video->device->handle, "_DOD"))
 		video->cap._DOD = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
+	if (acpi_has_method(video->device->handle, "_ROM"))
 		video->cap._ROM = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
+	if (acpi_has_method(video->device->handle, "_GPD"))
 		video->cap._GPD = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
+	if (acpi_has_method(video->device->handle, "_SPD"))
 		video->cap._SPD = 1;
-	}
-	if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
+	if (acpi_has_method(video->device->handle, "_VPO"))
 		video->cap._VPO = 1;
-	}
 }
 
 /*
@@ -1039,7 +1003,8 @@
 		return -ENODEV;
 	pci_dev_put(dev);
 
-	/* Since there is no HID, CID and so on for VGA driver, we have
+	/*
+	 * Since there is no HID, CID and so on for VGA driver, we have
 	 * to check well known required nodes.
 	 */
 
@@ -1069,12 +1034,14 @@
 	return status;
 }
 
-/* --------------------------------------------------------------------------
-                                 Driver Interface
-   -------------------------------------------------------------------------- */
+/*
+ * --------------------------------------------------------------------------
+ *                               Driver Interface
+ * --------------------------------------------------------------------------
+ */
 
 /* device interface */
-static struct acpi_video_device_attrib*
+static struct acpi_video_device_attrib *
 acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
 {
 	struct acpi_video_enumerated_device *ids;
@@ -1112,7 +1079,7 @@
 	unsigned long long device_id;
 	int status, device_type;
 	struct acpi_video_device *data;
-	struct acpi_video_device_attrib* attribute;
+	struct acpi_video_device_attrib *attribute;
 
 	status =
 	    acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
@@ -1134,7 +1101,7 @@
 
 	attribute = acpi_video_get_device_attr(video, device_id);
 
-	if((attribute != NULL) && attribute->device_id_scheme) {
+	if (attribute && attribute->device_id_scheme) {
 		switch (attribute->display_type) {
 		case ACPI_VIDEO_DISPLAY_CRT:
 			data->flags.crt = 1;
@@ -1152,24 +1119,24 @@
 			data->flags.unknown = 1;
 			break;
 		}
-		if(attribute->bios_can_detect)
+		if (attribute->bios_can_detect)
 			data->flags.bios = 1;
 	} else {
 		/* Check for legacy IDs */
 		device_type = acpi_video_get_device_type(video, device_id);
 		/* Ignore bits 16 and 18-20 */
 		switch (device_type & 0xffe2ffff) {
-			case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
-				data->flags.crt = 1;
-				break;
-			case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
-				data->flags.lcd = 1;
-				break;
-			case ACPI_VIDEO_DISPLAY_LEGACY_TV:
-				data->flags.tvout = 1;
-				break;
-			default:
-				data->flags.unknown = 1;
+		case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
+			data->flags.crt = 1;
+			break;
+		case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
+			data->flags.lcd = 1;
+			break;
+		case ACPI_VIDEO_DISPLAY_LEGACY_TV:
+			data->flags.tvout = 1;
+			break;
+		default:
+			data->flags.unknown = 1;
 		}
 	}
 
@@ -1192,12 +1159,12 @@
 
 /*
  *  Arg:
- *  	video	: video bus device 
+ *	video	: video bus device
  *
  *  Return:
- *  	none
- *  
- *  Enumerate the video device list of the video bus, 
+ *	none
+ *
+ *  Enumerate the video device list of the video bus,
  *  bind the ids with the corresponding video devices
  *  under the video bus.
  */
@@ -1216,13 +1183,13 @@
 
 /*
  *  Arg:
- *  	video	: video bus device 
- *  	device	: video output device under the video 
- *  		bus
+ *	video	: video bus device
+ *	device	: video output device under the video
+ *		bus
  *
  *  Return:
- *  	none
- *  
+ *	none
+ *
  *  Bind the ids with the corresponding video devices
  *  under the video bus.
  */
@@ -1245,11 +1212,11 @@
 
 /*
  *  Arg:
- *  	video	: video bus device 
+ *	video	: video bus device
  *
  *  Return:
- *  	< 0	: error
- *  
+ *	< 0	: error
+ *
  *  Call _DOD to enumerate all devices attached to display adapter
  *
  */
@@ -1310,7 +1277,7 @@
 	video->attached_array = active_list;
 	video->attached_count = count;
 
- out:
+out:
 	kfree(buffer.pointer);
 	return status;
 }
@@ -1577,7 +1544,6 @@
 	switch (event) {
 	case ACPI_VIDEO_NOTIFY_SWITCH:	/* User requested a switch,
 					 * most likely via hotkey. */
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_SWITCHVIDEOMODE;
 		break;
 
@@ -1585,20 +1551,16 @@
 					 * connector. */
 		acpi_video_device_enumerate(video);
 		acpi_video_device_rebind(video);
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_SWITCHVIDEOMODE;
 		break;
 
 	case ACPI_VIDEO_NOTIFY_CYCLE:	/* Cycle Display output hotkey pressed. */
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_SWITCHVIDEOMODE;
 		break;
 	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:	/* Next Display output hotkey pressed. */
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_VIDEO_NEXT;
 		break;
 	case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:	/* previous Display output hotkey pressed. */
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_VIDEO_PREV;
 		break;
 
@@ -1641,31 +1603,26 @@
 	case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:	/* Cycle brightness */
 		if (brightness_switch_enabled)
 			acpi_video_switch_brightness(video_device, event);
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_BRIGHTNESS_CYCLE;
 		break;
 	case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:	/* Increase brightness */
 		if (brightness_switch_enabled)
 			acpi_video_switch_brightness(video_device, event);
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_BRIGHTNESSUP;
 		break;
 	case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:	/* Decrease brightness */
 		if (brightness_switch_enabled)
 			acpi_video_switch_brightness(video_device, event);
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_BRIGHTNESSDOWN;
 		break;
 	case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:	/* zero brightness */
 		if (brightness_switch_enabled)
 			acpi_video_switch_brightness(video_device, event);
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_BRIGHTNESS_ZERO;
 		break;
 	case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:	/* display device off */
 		if (brightness_switch_enabled)
 			acpi_video_switch_brightness(video_device, event);
-		acpi_bus_generate_proc_event(device, event, 0);
 		keycode = KEY_DISPLAY_OFF;
 		break;
 	default:
@@ -1765,7 +1722,7 @@
 	if (!strcmp(device->pnp.bus_id, "VID")) {
 		if (instance)
 			device->pnp.bus_id[3] = '0' + instance;
-		instance ++;
+		instance++;
 	}
 	/* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
 	if (!strcmp(device->pnp.bus_id, "VGA")) {
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index c339774..940edbf 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -53,14 +53,13 @@
 			  void **retyurn_value)
 {
 	long *cap = context;
-	acpi_handle h_dummy;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_BCM", &h_dummy)) &&
-	    ACPI_SUCCESS(acpi_get_handle(handle, "_BCL", &h_dummy))) {
+	if (acpi_has_method(handle, "_BCM") &&
+	    acpi_has_method(handle, "_BCL")) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
 				  "support\n"));
 		*cap |= ACPI_VIDEO_BACKLIGHT;
-		if (ACPI_FAILURE(acpi_get_handle(handle, "_BQC", &h_dummy)))
+		if (!acpi_has_method(handle, "_BQC"))
 			printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
 				"cannot determine initial brightness\n");
 		/* We have backlight support, no need to scan further */
@@ -79,22 +78,20 @@
  */
 long acpi_is_video_device(acpi_handle handle)
 {
-	acpi_handle h_dummy;
 	long video_caps = 0;
 
 	/* Is this device able to support video switching ? */
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) ||
-	    ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy)))
+	if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
 		video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
 
 	/* Is this device able to retrieve a video ROM ? */
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy)))
+	if (acpi_has_method(handle, "_ROM"))
 		video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
 
 	/* Is this device able to configure which video head to be POSTed ? */
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) &&
-	    ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) &&
-	    ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy)))
+	if (acpi_has_method(handle, "_VPO") &&
+	    acpi_has_method(handle, "_GPD") &&
+	    acpi_has_method(handle, "_SPD"))
 		video_caps |= ACPI_VIDEO_DEVICE_POSTING;
 
 	/* Only check for backlight functionality if one of the above hit. */
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index db4380d..9d715ae 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1295,6 +1295,14 @@
 		 */
 		if (!(hpriv->flags & AHCI_HFLAG_NO_FPDMA_AA))
 			pi.flags |= ATA_FLAG_FPDMA_AA;
+
+		/*
+		 * All AHCI controllers should be forward-compatible
+		 * with the new auxiliary field. This code should be
+		 * conditionalized if any buggy AHCI controllers are
+		 * encountered.
+		 */
+		pi.flags |= ATA_FLAG_FPDMA_AUX;
 	}
 
 	if (hpriv->cap & HOST_CAP_PMP)
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index cf4e702..4ba8b04 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -34,14 +34,6 @@
 	u8	tf[REGS_PER_GTF];	/* regs. 0x1f1 - 0x1f7 */
 } __packed;
 
-/*
- *	Helper - belongs in the PCI layer somewhere eventually
- */
-static int is_pci_dev(struct device *dev)
-{
-	return (dev->bus == &pci_bus_type);
-}
-
 static void ata_acpi_clear_gtf(struct ata_device *dev)
 {
 	kfree(dev->gtf_cache);
@@ -49,47 +41,18 @@
 }
 
 /**
- * ata_ap_acpi_handle - provide the acpi_handle for an ata_port
- * @ap: the acpi_handle returned will correspond to this port
- *
- * Returns the acpi_handle for the ACPI namespace object corresponding to
- * the ata_port passed into the function, or NULL if no such object exists
- */
-acpi_handle ata_ap_acpi_handle(struct ata_port *ap)
-{
-	if (ap->flags & ATA_FLAG_ACPI_SATA)
-		return NULL;
-
-	return ap->scsi_host ?
-		DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev) : NULL;
-}
-EXPORT_SYMBOL(ata_ap_acpi_handle);
-
-/**
  * ata_dev_acpi_handle - provide the acpi_handle for an ata_device
- * @dev: the acpi_device returned will correspond to this port
+ * @dev: the acpi_handle returned will correspond to this device
  *
  * Returns the acpi_handle for the ACPI namespace object corresponding to
  * the ata_device passed into the function, or NULL if no such object exists
+ * or ACPI is disabled for this device due to consecutive errors.
  */
 acpi_handle ata_dev_acpi_handle(struct ata_device *dev)
 {
-	acpi_integer adr;
-	struct ata_port *ap = dev->link->ap;
-
-	if (libata_noacpi || dev->flags & ATA_DFLAG_ACPI_DISABLED)
-		return NULL;
-
-	if (ap->flags & ATA_FLAG_ACPI_SATA) {
-		if (!sata_pmp_attached(ap))
-			adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
-		else
-			adr = SATA_ADR(ap->port_no, dev->link->pmp);
-		return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), adr);
-	} else
-		return acpi_get_child(ata_ap_acpi_handle(ap), dev->devno);
+	return dev->flags & ATA_DFLAG_ACPI_DISABLED ?
+			NULL : ACPI_HANDLE(&dev->tdev);
 }
-EXPORT_SYMBOL(ata_dev_acpi_handle);
 
 /* @ap and @dev are the same as ata_acpi_handle_hotplug() */
 static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
@@ -156,10 +119,8 @@
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
-	if (wait) {
+	if (wait)
 		ata_port_wait_eh(ap);
-		flush_work(&ap->hotplug_task.work);
-	}
 }
 
 static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data)
@@ -216,37 +177,55 @@
 	.uevent = ata_acpi_ap_uevent,
 };
 
-void ata_acpi_hotplug_init(struct ata_host *host)
+/* bind acpi handle to pata port */
+void ata_acpi_bind_port(struct ata_port *ap)
 {
-	int i;
+	acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
 
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-		acpi_handle handle;
-		struct ata_device *dev;
+	if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle)
+		return;
 
-		if (!ap)
-			continue;
+	ACPI_HANDLE_SET(&ap->tdev, acpi_get_child(host_handle, ap->port_no));
 
-		handle = ata_ap_acpi_handle(ap);
-		if (handle) {
-			/* we might be on a docking station */
-			register_hotplug_dock_device(handle,
-						     &ata_acpi_ap_dock_ops, ap,
-						     NULL, NULL);
-		}
+	if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
+		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
 
-		ata_for_each_dev(dev, &ap->link, ALL) {
-			handle = ata_dev_acpi_handle(dev);
-			if (!handle)
-				continue;
+	/* we might be on a docking station */
+	register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev),
+				     &ata_acpi_ap_dock_ops, ap, NULL, NULL);
+}
 
-			/* we might be on a docking station */
-			register_hotplug_dock_device(handle,
-						     &ata_acpi_dev_dock_ops,
-						     dev, NULL, NULL);
-		}
+void ata_acpi_bind_dev(struct ata_device *dev)
+{
+	struct ata_port *ap = dev->link->ap;
+	acpi_handle port_handle = ACPI_HANDLE(&ap->tdev);
+	acpi_handle host_handle = ACPI_HANDLE(ap->host->dev);
+	acpi_handle parent_handle;
+	u64 adr;
+
+	/*
+	 * For both sata/pata devices, host handle is required.
+	 * For pata device, port handle is also required.
+	 */
+	if (libata_noacpi || !host_handle ||
+			(!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle))
+		return;
+
+	if (ap->flags & ATA_FLAG_ACPI_SATA) {
+		if (!sata_pmp_attached(ap))
+			adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+		else
+			adr = SATA_ADR(ap->port_no, dev->link->pmp);
+		parent_handle = host_handle;
+	} else {
+		adr = dev->devno;
+		parent_handle = port_handle;
 	}
+
+	ACPI_HANDLE_SET(&dev->tdev, acpi_get_child(parent_handle, adr));
+
+	register_hotplug_dock_device(ata_dev_acpi_handle(dev),
+				     &ata_acpi_dev_dock_ops, dev, NULL, NULL);
 }
 
 /**
@@ -270,18 +249,34 @@
 		struct ata_port *ap = host->ports[i];
 		const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
 
-		if (ata_ap_acpi_handle(ap) && gtm)
+		if (ACPI_HANDLE(&ap->tdev) && gtm)
 			ata_acpi_stm(ap, gtm);
 	}
 }
 
-static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle,
-			  struct ata_acpi_gtm *gtm)
+/**
+ * ata_acpi_gtm - execute _GTM
+ * @ap: target ATA port
+ * @gtm: out parameter for _GTM result
+ *
+ * Evaluate _GTM and store the result in @gtm.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
+ */
+int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
 {
 	struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
 	union acpi_object *out_obj;
 	acpi_status status;
 	int rc = 0;
+	acpi_handle handle = ACPI_HANDLE(&ap->tdev);
+
+	if (!handle)
+		return -EINVAL;
 
 	status = acpi_evaluate_object(handle, "_GTM", NULL, &output);
 
@@ -317,27 +312,6 @@
 	return rc;
 }
 
-/**
- * ata_acpi_gtm - execute _GTM
- * @ap: target ATA port
- * @gtm: out parameter for _GTM result
- *
- * Evaluate _GTM and store the result in @gtm.
- *
- * LOCKING:
- * EH context.
- *
- * RETURNS:
- * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
- */
-int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
-{
-	if (ata_ap_acpi_handle(ap))
-		return __ata_acpi_gtm(ap, ata_ap_acpi_handle(ap), gtm);
-	else
-		return -EINVAL;
-}
-
 EXPORT_SYMBOL_GPL(ata_acpi_gtm);
 
 /**
@@ -374,8 +348,8 @@
 	input.count = 3;
 	input.pointer = in_params;
 
-	status = acpi_evaluate_object(ata_ap_acpi_handle(ap), "_STM", &input,
-				      NULL);
+	status = acpi_evaluate_object(ACPI_HANDLE(&ap->tdev), "_STM",
+				      &input, NULL);
 
 	if (status == AE_NOT_FOUND)
 		return -ENOENT;
@@ -850,7 +824,7 @@
 	const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
 	struct ata_device *dev;
 
-	if (ata_ap_acpi_handle(ap) && gtm) {
+	if (ACPI_HANDLE(&ap->tdev) && gtm) {
 		/* _GTM valid */
 
 		/* restore timing parameters */
@@ -894,8 +868,7 @@
 		d_max_in = ACPI_STATE_D3_HOT;
 
 out:
-	return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev,
-					  NULL, d_max_in);
+	return acpi_pm_device_sleep_state(&dev->tdev, NULL, d_max_in);
 }
 
 static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state)
@@ -932,7 +905,7 @@
 	struct ata_device *dev;
 	acpi_handle port_handle;
 
-	port_handle = ata_ap_acpi_handle(ap);
+	port_handle = ACPI_HANDLE(&ap->tdev);
 	if (!port_handle)
 		return;
 
@@ -947,11 +920,11 @@
 			continue;
 
 		acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ?
-						ACPI_STATE_D0 : ACPI_STATE_D3);
+					ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
 	}
 
 	if (!(state.event & PM_EVENT_RESUME))
-		acpi_bus_set_power(port_handle, ACPI_STATE_D3);
+		acpi_bus_set_power(port_handle, ACPI_STATE_D3_COLD);
 }
 
 /**
@@ -1063,109 +1036,16 @@
 	ata_acpi_clear_gtf(dev);
 }
 
-static int compat_pci_ata(struct ata_port *ap)
+void ata_scsi_acpi_bind(struct ata_device *dev)
 {
-	struct device *dev = ap->tdev.parent;
-	struct pci_dev *pdev;
-
-	if (!is_pci_dev(dev))
-		return 0;
-
-	pdev = to_pci_dev(dev);
-
-	if ((pdev->class >> 8) != PCI_CLASS_STORAGE_SATA &&
-	    (pdev->class >> 8) != PCI_CLASS_STORAGE_IDE)
-		return 0;
-
-	return 1;
+	acpi_handle handle = ata_dev_acpi_handle(dev);
+	if (handle)
+		acpi_dev_pm_add_dependent(handle, &dev->sdev->sdev_gendev);
 }
 
-static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
+void ata_scsi_acpi_unbind(struct ata_device *dev)
 {
-	if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA)
-		return -ENODEV;
-
-	*handle = acpi_get_child(DEVICE_ACPI_HANDLE(ap->tdev.parent),
-			ap->port_no);
-
-	if (!*handle)
-		return -ENODEV;
-
-	if (__ata_acpi_gtm(ap, *handle, &ap->__acpi_init_gtm) == 0)
-		ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
-
-	return 0;
-}
-
-static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
-				acpi_handle *handle)
-{
-	struct ata_device *ata_dev;
-
-	if (ap->flags & ATA_FLAG_ACPI_SATA) {
-		if (!sata_pmp_attached(ap))
-			ata_dev = &ap->link.device[sdev->id];
-		else
-			ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id];
-	}
-	else {
-		ata_dev = &ap->link.device[sdev->id];
-	}
-
-	*handle = ata_dev_acpi_handle(ata_dev);
-
-	if (!*handle)
-		return -ENODEV;
-
-	return 0;
-}
-
-static int is_ata_port(const struct device *dev)
-{
-	return dev->type == &ata_port_type;
-}
-
-static struct ata_port *dev_to_ata_port(struct device *dev)
-{
-	while (!is_ata_port(dev)) {
-		if (!dev->parent)
-			return NULL;
-		dev = dev->parent;
-	}
-	return to_ata_port(dev);
-}
-
-static int ata_acpi_find_device(struct device *dev, acpi_handle *handle)
-{
-	struct ata_port *ap = dev_to_ata_port(dev);
-
-	if (!ap)
-		return -ENODEV;
-
-	if (!compat_pci_ata(ap))
-		return -ENODEV;
-
-	if (scsi_is_host_device(dev))
-		return ata_acpi_bind_host(ap, handle);
-	else if (scsi_is_sdev_device(dev)) {
-		struct scsi_device *sdev = to_scsi_device(dev);
-
-		return ata_acpi_bind_device(ap, sdev, handle);
-	} else
-		return -ENODEV;
-}
-
-static struct acpi_bus_type ata_acpi_bus = {
-	.name = "ATA",
-	.find_device = ata_acpi_find_device,
-};
-
-int ata_acpi_register(void)
-{
-	return scsi_register_acpi_bus_type(&ata_acpi_bus);
-}
-
-void ata_acpi_unregister(void)
-{
-	scsi_unregister_acpi_bus_type(&ata_acpi_bus);
+	acpi_handle handle = ata_dev_acpi_handle(dev);
+	if (handle)
+		acpi_dev_pm_remove_dependent(handle, &dev->sdev->sdev_gendev);
 }
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index c24354d..83b1a9f 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -569,10 +569,10 @@
 	fis[14] = 0;
 	fis[15] = tf->ctl;
 
-	fis[16] = 0;
-	fis[17] = 0;
-	fis[18] = 0;
-	fis[19] = 0;
+	fis[16] = tf->auxiliary & 0xff;
+	fis[17] = (tf->auxiliary >> 8) & 0xff;
+	fis[18] = (tf->auxiliary >> 16) & 0xff;
+	fis[19] = (tf->auxiliary >> 24) & 0xff;
 }
 
 /**
@@ -2139,6 +2139,22 @@
 	else
 		snprintf(desc, desc_sz, "NCQ (depth %d/%d)%s", hdepth,
 			ddepth, aa_desc);
+
+	if ((ap->flags & ATA_FLAG_FPDMA_AUX) &&
+	    ata_id_has_ncq_send_and_recv(dev->id)) {
+		err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
+					     0, ap->sector_buf, 1);
+		if (err_mask) {
+			ata_dev_dbg(dev,
+				    "failed to get NCQ Send/Recv Log Emask 0x%x\n",
+				    err_mask);
+		} else {
+			dev->flags |= ATA_DFLAG_NCQ_SEND_RECV;
+			memcpy(dev->ncq_send_recv_cmds, ap->sector_buf,
+				ATA_LOG_NCQ_SEND_RECV_SIZE);
+		}
+	}
+
 	return 0;
 }
 
@@ -6150,8 +6166,6 @@
 	if (rc)
 		goto err_tadd;
 
-	ata_acpi_hotplug_init(host);
-
 	/* set cable, sata_spd_limit and report */
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
@@ -6632,8 +6646,6 @@
 
 	ata_parse_force_param();
 
-	ata_acpi_register();
-
 	rc = ata_sff_init();
 	if (rc) {
 		kfree(ata_force_tbl);
@@ -6660,7 +6672,6 @@
 	ata_release_transport(ata_scsi_transport_template);
 	libata_transport_exit();
 	ata_sff_exit();
-	ata_acpi_unregister();
 	kfree(ata_force_tbl);
 }
 
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 1c41722..20fd337 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -289,24 +289,24 @@
 
 	/* Disable sending Early R_OK.
 	 * With "cached read" HDD testing and multiple ports busy on a SATA
-	 * host controller, 3726 PMP will very rarely drop a deferred
+	 * host controller, 3x26 PMP will very rarely drop a deferred
 	 * R_OK that was intended for the host. Symptom will be all
 	 * 5 drives under test will timeout, get reset, and recover.
 	 */
-	if (vendor == 0x1095 && devid == 0x3726) {
+	if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
 		u32 reg;
 
 		err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, &reg);
 		if (err_mask) {
 			rc = -EIO;
-			reason = "failed to read Sil3726 Private Register";
+			reason = "failed to read Sil3x26 Private Register";
 			goto fail;
 		}
 		reg &= ~0x1;
 		err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
 		if (err_mask) {
 			rc = -EIO;
-			reason = "failed to write Sil3726 Private Register";
+			reason = "failed to write Sil3x26 Private Register";
 			goto fail;
 		}
 	}
@@ -383,8 +383,8 @@
 	u16 devid = sata_pmp_gscr_devid(gscr);
 	struct ata_link *link;
 
-	if (vendor == 0x1095 && devid == 0x3726) {
-		/* sil3726 quirks */
+	if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
+		/* sil3x26 quirks */
 		ata_for_each_link(link, ap, EDGE) {
 			/* link reports offline after LPM */
 			link->flags |= ATA_LFLAG_NO_LPM;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index b1e880a..97a0cef 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -49,7 +49,6 @@
 #include <linux/hdreg.h>
 #include <linux/uaccess.h>
 #include <linux/suspend.h>
-#include <linux/pm_qos.h>
 #include <asm/unaligned.h>
 
 #include "libata.h"
@@ -3100,12 +3099,25 @@
 	buf = page_address(sg_page(scsi_sglist(scmd)));
 	size = ata_set_lba_range_entries(buf, 512, block, n_block);
 
-	tf->protocol = ATA_PROT_DMA;
-	tf->hob_feature = 0;
-	tf->feature = ATA_DSM_TRIM;
-	tf->hob_nsect = (size / 512) >> 8;
-	tf->nsect = size / 512;
-	tf->command = ATA_CMD_DSM;
+	if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) {
+		/* Newer devices support queued TRIM commands */
+		tf->protocol = ATA_PROT_NCQ;
+		tf->command = ATA_CMD_FPDMA_SEND;
+		tf->hob_nsect = ATA_SUBCMD_FPDMA_SEND_DSM & 0x1f;
+		tf->nsect = qc->tag << 3;
+		tf->hob_feature = (size / 512) >> 8;
+		tf->feature = size / 512;
+
+		tf->auxiliary = 1;
+	} else {
+		tf->protocol = ATA_PROT_DMA;
+		tf->hob_feature = 0;
+		tf->feature = ATA_DSM_TRIM;
+		tf->hob_nsect = (size / 512) >> 8;
+		tf->nsect = size / 512;
+		tf->command = ATA_CMD_DSM;
+	}
+
 	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 |
 		     ATA_TFLAG_WRITE;
 
@@ -3667,9 +3679,7 @@
 			if (!IS_ERR(sdev)) {
 				dev->sdev = sdev;
 				scsi_device_put(sdev);
-				if (zpodd_dev_enabled(dev))
-					dev_pm_qos_expose_flags(
-							&sdev->sdev_gendev, 0);
+				ata_scsi_acpi_bind(dev);
 			} else {
 				dev->sdev = NULL;
 			}
@@ -3757,6 +3767,8 @@
 	struct scsi_device *sdev;
 	unsigned long flags;
 
+	ata_scsi_acpi_unbind(dev);
+
 	/* Alas, we need to grab scan_mutex to ensure SCSI device
 	 * state doesn't change underneath us and thus
 	 * scsi_device_get() always succeeds.  The mutex locking can
@@ -3766,9 +3778,6 @@
 	mutex_lock(&ap->scsi_host->scan_mutex);
 	spin_lock_irqsave(ap->lock, flags);
 
-	if (zpodd_dev_enabled(dev))
-		zpodd_exit(dev);
-
 	/* clearing dev->sdev is protected by host lock */
 	sdev = dev->sdev;
 	dev->sdev = NULL;
@@ -3818,6 +3827,9 @@
 		dev->flags &= ~ATA_DFLAG_DETACHED;
 		spin_unlock_irqrestore(ap->lock, flags);
 
+		if (zpodd_dev_enabled(dev))
+			zpodd_exit(dev);
+
 		ata_scsi_remove_dev(dev);
 	}
 }
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index 077a856..150a917 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -287,6 +287,7 @@
 	dev->release = ata_tport_release;
 	dev_set_name(dev, "ata%d", ap->print_id);
 	transport_setup_device(dev);
+	ata_acpi_bind_port(ap);
 	error = device_add(dev);
 	if (error) {
 		goto tport_err;
@@ -644,6 +645,7 @@
 		dev_set_name(dev, "dev%d.%d.0", ap->print_id, link->pmp);
 
 	transport_setup_device(dev);
+	ata_acpi_bind_dev(ata_dev);
 	error = device_add(dev);
 	if (error) {
 		ata_tdev_free(ata_dev);
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
index cd8daf4..68f9e32 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -2,6 +2,7 @@
 #include <linux/cdrom.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
+#include <linux/pm_qos.h>
 #include <scsi/scsi_device.h>
 
 #include "libata.h"
@@ -190,8 +191,8 @@
 	sdev_disable_disk_events(dev->sdev);
 
 	zpodd->powered_off = true;
-	device_set_run_wake(&dev->sdev->sdev_gendev, true);
-	acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true);
+	device_set_run_wake(&dev->tdev, true);
+	acpi_pm_device_run_wake(&dev->tdev, true);
 }
 
 /* Disable runtime wake capability if it is enabled */
@@ -200,8 +201,8 @@
 	struct zpodd *zpodd = dev->zpodd;
 
 	if (zpodd->powered_off) {
-		acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false);
-		device_set_run_wake(&dev->sdev->sdev_gendev, false);
+		acpi_pm_device_run_wake(&dev->tdev, false);
+		device_set_run_wake(&dev->tdev, false);
 	}
 }
 
@@ -262,7 +263,7 @@
 
 static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
 {
-	acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->sdev->sdev_gendev);
+	acpi_handle handle = ata_dev_acpi_handle(dev);
 	acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev);
 }
 
@@ -290,6 +291,7 @@
 	ata_acpi_add_pm_notifier(dev);
 	zpodd->dev = dev;
 	dev->zpodd = zpodd;
+	dev_pm_qos_expose_flags(&dev->tdev, 0);
 }
 
 void zpodd_exit(struct ata_device *dev)
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 577d902..eeeb778 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -118,11 +118,11 @@
 extern int ata_acpi_on_devcfg(struct ata_device *dev);
 extern void ata_acpi_on_disable(struct ata_device *dev);
 extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
-extern int ata_acpi_register(void);
-extern void ata_acpi_unregister(void);
-extern void ata_acpi_bind(struct ata_device *dev);
-extern void ata_acpi_unbind(struct ata_device *dev);
-extern void ata_acpi_hotplug_init(struct ata_host *host);
+extern void ata_acpi_bind_port(struct ata_port *ap);
+extern void ata_acpi_bind_dev(struct ata_device *dev);
+extern acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
+extern void ata_scsi_acpi_bind(struct ata_device *dev);
+extern void ata_scsi_acpi_unbind(struct ata_device *dev);
 #else
 static inline void ata_acpi_dissociate(struct ata_host *host) { }
 static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -131,11 +131,10 @@
 static inline void ata_acpi_on_disable(struct ata_device *dev) { }
 static inline void ata_acpi_set_state(struct ata_port *ap,
 				      pm_message_t state) { }
-static inline int ata_acpi_register(void) { return 0; }
-static inline void ata_acpi_unregister(void) { }
-static inline void ata_acpi_bind(struct ata_device *dev) { }
-static inline void ata_acpi_unbind(struct ata_device *dev) { }
-static inline void ata_acpi_hotplug_init(struct ata_host *host) {}
+static inline void ata_acpi_bind_port(struct ata_port *ap) {}
+static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
+static inline void ata_scsi_acpi_bind(struct ata_device *dev) {}
+static inline void ata_scsi_acpi_unbind(struct ata_device *dev) {}
 #endif
 
 /* libata-scsi.c */
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index 09723b7..73212c9 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -39,7 +39,7 @@
 {
 	struct ata_port *ap = link->ap;
 	struct pata_acpi *acpi = ap->private_data;
-	if (ata_ap_acpi_handle(ap) == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+	if (ACPI_HANDLE(&ap->tdev) == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
 		return -ENODEV;
 
 	return ata_sff_prereset(link, deadline);
@@ -195,7 +195,7 @@
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	struct pata_acpi *acpi;
 
-	if (ata_ap_acpi_handle(ap) == NULL)
+	if (ACPI_HANDLE(&ap->tdev) == NULL)
 		return -ENODEV;
 
 	acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 848ed32..853f610 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -654,7 +654,7 @@
 	ata_sff_freeze(ap);
 }
 
-void arasan_cf_error_handler(struct ata_port *ap)
+static void arasan_cf_error_handler(struct ata_port *ap)
 {
 	struct arasan_cf_dev *acdev = ap->host->private_data;
 
@@ -683,7 +683,7 @@
 	ata_sff_queue_work(&acdev->work);
 }
 
-unsigned int arasan_cf_qc_issue(struct ata_queued_cmd *qc)
+static unsigned int arasan_cf_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct arasan_cf_dev *acdev = ap->host->private_data;
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 8d493b4..d59d523 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -271,7 +271,7 @@
 
 	struct device		 *dev = &pdev->dev;
 	struct at32_ide_info	 *info;
-	struct ide_platform_data *board = pdev->dev.platform_data;
+	struct ide_platform_data *board = dev_get_platdata(&pdev->dev);
 	struct resource		 *res;
 
 	int irq;
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index 5364f97..d63ee8f 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -315,7 +315,7 @@
 
 static int pata_at91_probe(struct platform_device *pdev)
 {
-	struct at91_cf_data *board = pdev->dev.platform_data;
+	struct at91_cf_data *board = dev_get_platdata(&pdev->dev);
 	struct device *dev = &pdev->dev;
 	struct at91_ide_info *info;
 	struct resource *mem_res;
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index dcc6b24..1ec53f8 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -48,7 +48,7 @@
 	u16 *buf16 = (u16 *) buf;
 	struct ata_port *ap = dev->link->ap;
 	void __iomem *mmio = ap->ioaddr.data_addr;
-	struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
+	struct ixp4xx_pata_data *data = dev_get_platdata(ap->host->dev);
 
 	/* set the expansion bus in 16bit mode and restore
 	 * 8 bit mode after the transaction.
@@ -143,7 +143,7 @@
 	struct resource *cs0, *cs1;
 	struct ata_host *host;
 	struct ata_port *ap;
-	struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+	struct ixp4xx_pata_data *data = dev_get_platdata(&pdev->dev);
 
 	cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index e73bef3..c51bbb9 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -1037,7 +1037,7 @@
 	union cvmx_mio_boot_dma_cfgx dma_cfg;
 	union cvmx_mio_boot_dma_intx dma_int;
 
-	struct octeon_cf_port *cf_port = dev->platform_data;
+	struct octeon_cf_port *cf_port = dev_get_platdata(dev);
 
 	if (cf_port->dma_base) {
 		/* Stop and clear the dma engine.  */
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 71e0937..0279488 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -180,7 +180,7 @@
 	struct resource *io_res;
 	struct resource *ctl_res;
 	struct resource *irq_res;
-	struct pata_platform_info *pp_info = pdev->dev.platform_data;
+	struct pata_platform_info *pp_info = dev_get_platdata(&pdev->dev);
 
 	/*
 	 * Simple resource validation ..
diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c
index 942ef94..a6f05ac 100644
--- a/drivers/ata/pata_pxa.c
+++ b/drivers/ata/pata_pxa.c
@@ -238,7 +238,7 @@
 	struct resource *ctl_res;
 	struct resource *dma_res;
 	struct resource *irq_res;
-	struct pata_pxa_pdata *pdata = pdev->dev.platform_data;
+	struct pata_pxa_pdata *pdata = dev_get_platdata(&pdev->dev);
 	int ret = 0;
 
 	/*
diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c
index 6ef27e9..898e544 100644
--- a/drivers/ata/pata_samsung_cf.c
+++ b/drivers/ata/pata_samsung_cf.c
@@ -241,8 +241,8 @@
 /*
  * pata_s3c_data_xfer - Transfer data by PIO
  */
-unsigned int pata_s3c_data_xfer(struct ata_device *dev, unsigned char *buf,
-				unsigned int buflen, int rw)
+static unsigned int pata_s3c_data_xfer(struct ata_device *dev,
+				unsigned char *buf, unsigned int buflen, int rw)
 {
 	struct ata_port *ap = dev->link->ap;
 	struct s3c_ide_info *info = ap->host->private_data;
@@ -418,7 +418,7 @@
 	.set_piomode		= pata_s3c_set_piomode,
 };
 
-static void pata_s3c_enable(void *s3c_ide_regbase, bool state)
+static void pata_s3c_enable(void __iomem *s3c_ide_regbase, bool state)
 {
 	u32 temp = readl(s3c_ide_regbase + S3C_ATA_CTRL);
 	temp = state ? (temp | 1) : (temp & ~1);
@@ -475,7 +475,7 @@
 
 static int __init pata_s3c_probe(struct platform_device *pdev)
 {
-	struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
+	struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev);
 	struct device *dev = &pdev->dev;
 	struct s3c_ide_info *info;
 	struct resource *res;
@@ -617,7 +617,7 @@
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct ata_host *host = platform_get_drvdata(pdev);
-	struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
+	struct s3c_ide_platdata *pdata = dev_get_platdata(&pdev->dev);
 	struct s3c_ide_info *info = host->private_data;
 
 	pata_s3c_hwinit(info, pdata);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 19720a0..851bd3f 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -293,6 +293,7 @@
 {
 	struct sata_fsl_host_priv *host_priv = host->private_data;
 	void __iomem *hcr_base = host_priv->hcr_base;
+	unsigned long flags;
 
 	if (count > ICC_MAX_INT_COUNT_THRESHOLD)
 		count = ICC_MAX_INT_COUNT_THRESHOLD;
@@ -305,12 +306,12 @@
 			(count > ICC_MIN_INT_COUNT_THRESHOLD))
 		ticks = ICC_SAFE_INT_TICKS;
 
-	spin_lock(&host->lock);
+	spin_lock_irqsave(&host->lock, flags);
 	iowrite32((count << 24 | ticks), hcr_base + ICC);
 
 	intr_coalescing_count = count;
 	intr_coalescing_ticks = ticks;
-	spin_unlock(&host->lock);
+	spin_unlock_irqrestore(&host->lock, flags);
 
 	DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n",
 			intr_coalescing_count, intr_coalescing_ticks);
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index d047d92..7f5e5d9 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -46,14 +46,19 @@
 #define CR_BUSY				0x0001
 #define CR_START			0x0001
 #define CR_WR_RDN			0x0002
+#define CPHY_TX_INPUT_STS		0x2001
 #define CPHY_RX_INPUT_STS		0x2002
-#define CPHY_SATA_OVERRIDE	 	0x4000
-#define CPHY_OVERRIDE			0x2005
+#define CPHY_SATA_TX_OVERRIDE		0x8000
+#define CPHY_SATA_RX_OVERRIDE	 	0x4000
+#define CPHY_TX_OVERRIDE		0x2004
+#define CPHY_RX_OVERRIDE		0x2005
 #define SPHY_LANE			0x100
 #define SPHY_HALF_RATE			0x0001
 #define CPHY_SATA_DPLL_MODE		0x0700
 #define CPHY_SATA_DPLL_SHIFT		8
 #define CPHY_SATA_DPLL_RESET		(1 << 11)
+#define CPHY_SATA_TX_ATTEN		0x1c00
+#define CPHY_SATA_TX_ATTEN_SHIFT	10
 #define CPHY_PHY_COUNT			6
 #define CPHY_LANE_COUNT			4
 #define CPHY_PORT_COUNT			(CPHY_PHY_COUNT * CPHY_LANE_COUNT)
@@ -66,6 +71,7 @@
 	void __iomem *phy_base;
 	u8 lane_mapping;
 	u8 phy_devs;
+	u8 tx_atten;
 };
 static struct phy_lane_info port_data[CPHY_PORT_COUNT];
 
@@ -76,9 +82,11 @@
 #define SGPIO_PINS			3
 #define SGPIO_PORTS			8
 
-/* can be cast as an ahci_host_priv for compatibility with most functions */
 struct ecx_plat_data {
 	u32		n_ports;
+	/* number of extra clocks that the SGPIO PIC controller expects */
+	u32		pre_clocks;
+	u32		post_clocks;
 	unsigned	sgpio_gpio[SGPIO_PINS];
 	u32		sgpio_pattern;
 	u32		port_to_sgpio[SGPIO_PORTS];
@@ -86,11 +94,11 @@
 
 #define SGPIO_SIGNALS			3
 #define ECX_ACTIVITY_BITS		0x300000
-#define ECX_ACTIVITY_SHIFT		2
+#define ECX_ACTIVITY_SHIFT		0
 #define ECX_LOCATE_BITS			0x80000
 #define ECX_LOCATE_SHIFT		1
 #define ECX_FAULT_BITS			0x400000
-#define ECX_FAULT_SHIFT			0
+#define ECX_FAULT_SHIFT			2
 static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
 				u32 shift)
 {
@@ -155,6 +163,9 @@
 	spin_lock_irqsave(&sgpio_lock, flags);
 	ecx_parse_sgpio(pdata, ap->port_no, state);
 	sgpio_out = pdata->sgpio_pattern;
+	for (i = 0; i < pdata->pre_clocks; i++)
+		ecx_led_cycle_clock(pdata);
+
 	gpio_set_value(pdata->sgpio_gpio[SLOAD], 1);
 	ecx_led_cycle_clock(pdata);
 	gpio_set_value(pdata->sgpio_gpio[SLOAD], 0);
@@ -167,6 +178,8 @@
 		sgpio_out >>= 1;
 		ecx_led_cycle_clock(pdata);
 	}
+	for (i = 0; i < pdata->post_clocks; i++)
+		ecx_led_cycle_clock(pdata);
 
 	/* save off new led state for port/slot */
 	emp->led_state = state;
@@ -201,6 +214,11 @@
 	of_property_read_u32_array(np, "calxeda,led-order",
 						pdata->port_to_sgpio,
 						pdata->n_ports);
+	if (of_property_read_u32(np, "calxeda,pre-clocks", &pdata->pre_clocks))
+		pdata->pre_clocks = 0;
+	if (of_property_read_u32(np, "calxeda,post-clocks",
+				&pdata->post_clocks))
+		pdata->post_clocks = 0;
 
 	/* store em_loc */
 	hpriv->em_loc = 0;
@@ -259,8 +277,27 @@
 	if (unlikely(port_data[sata_port].phy_base == NULL))
 		return;
 	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+	tmp &= ~CPHY_SATA_RX_OVERRIDE;
+	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
+}
+
+static void cphy_override_tx_attenuation(u8 sata_port, u32 val)
+{
+	u8 lane = port_data[sata_port].lane_mapping;
+	u32 tmp;
+
+	if (val & 0x8)
+		return;
+
+	tmp = combo_phy_read(sata_port, CPHY_TX_INPUT_STS + lane * SPHY_LANE);
+	tmp &= ~CPHY_SATA_TX_OVERRIDE;
+	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+	tmp |= CPHY_SATA_TX_OVERRIDE;
+	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
+
+	tmp |= (val << CPHY_SATA_TX_ATTEN_SHIFT) & CPHY_SATA_TX_ATTEN;
+	combo_phy_write(sata_port, CPHY_TX_OVERRIDE + lane * SPHY_LANE, tmp);
 }
 
 static void cphy_override_rx_mode(u8 sata_port, u32 val)
@@ -268,21 +305,21 @@
 	u8 lane = port_data[sata_port].lane_mapping;
 	u32 tmp;
 	tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
-	tmp &= ~CPHY_SATA_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+	tmp &= ~CPHY_SATA_RX_OVERRIDE;
+	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
 
-	tmp |= CPHY_SATA_OVERRIDE;
-	combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+	tmp |= CPHY_SATA_RX_OVERRIDE;
+	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
 
 	tmp &= ~CPHY_SATA_DPLL_MODE;
 	tmp |= val << CPHY_SATA_DPLL_SHIFT;
-	combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
 
 	tmp |= CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
 
 	tmp &= ~CPHY_SATA_DPLL_RESET;
-	combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
+	combo_phy_write(sata_port, CPHY_RX_OVERRIDE + lane * SPHY_LANE, tmp);
 
 	msleep(15);
 }
@@ -299,16 +336,20 @@
 						lane * SPHY_LANE);
 	} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
 	cphy_override_rx_mode(sata_port, 3);
+	cphy_override_tx_attenuation(sata_port, port_data[sata_port].tx_atten);
 }
 
 static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
 {
 	struct device_node *sata_node = dev->of_node;
-	int phy_count = 0, phy, port = 0;
+	int phy_count = 0, phy, port = 0, i;
 	void __iomem *cphy_base[CPHY_PHY_COUNT];
 	struct device_node *phy_nodes[CPHY_PHY_COUNT];
+	u32 tx_atten[CPHY_PORT_COUNT];
+
 	memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
 	memset(phy_nodes, 0, sizeof(struct device_node*) * CPHY_PHY_COUNT);
+	memset(tx_atten, 0xff, CPHY_PORT_COUNT);
 
 	do {
 		u32 tmp;
@@ -336,6 +377,10 @@
 		of_node_put(phy_data.np);
 		port += 1;
 	} while (port < CPHY_PORT_COUNT);
+	of_property_read_u32_array(sata_node, "calxeda,tx-atten",
+				tx_atten, port);
+	for (i = 0; i < port; i++)
+		port_data[i].tx_atten = (u8) tx_atten[i];
 	return 0;
 }
 
@@ -479,6 +524,9 @@
 	if (hpriv->cap & HOST_CAP_PMP)
 		pi.flags |= ATA_FLAG_PMP;
 
+	if (hpriv->cap & HOST_CAP_64)
+		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
+
 	/* CAP.NP sometimes indicate the index of the last enabled
 	 * port, at other times, that of the last possible port, so
 	 * determining the maximum port number requires looking at
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 35c6b6d..56be3181 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -553,10 +553,15 @@
 	u32			irq_mask_offset;
 	u32			unmask_all_irqs;
 
-#if defined(CONFIG_HAVE_CLK)
+	/*
+	 * Needed on some devices that require their clocks to be enabled.
+	 * These are optional: if the platform device does not have any
+	 * clocks, they won't be used.  Also, if the underlying hardware
+	 * does not support the common clock framework (CONFIG_HAVE_CLK=n),
+	 * all the clock operations become no-ops (see clk.h).
+	 */
 	struct clk		*clk;
 	struct clk              **port_clks;
-#endif
 	/*
 	 * These consistent DMA memory pools give us guaranteed
 	 * alignment for hardware-accessed data structures,
@@ -4032,9 +4037,7 @@
 	struct resource *res;
 	int n_ports = 0, irq = 0;
 	int rc;
-#if defined(CONFIG_HAVE_CLK)
 	int port;
-#endif
 
 	ata_print_version_once(&pdev->dev, DRV_VERSION);
 
@@ -4058,7 +4061,7 @@
 		of_property_read_u32(pdev->dev.of_node, "nr-ports", &n_ports);
 		irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
 	} else {
-		mv_platform_data = pdev->dev.platform_data;
+		mv_platform_data = dev_get_platdata(&pdev->dev);
 		n_ports = mv_platform_data->n_ports;
 		irq = platform_get_irq(pdev, 0);
 	}
@@ -4068,13 +4071,11 @@
 
 	if (!host || !hpriv)
 		return -ENOMEM;
-#if defined(CONFIG_HAVE_CLK)
 	hpriv->port_clks = devm_kzalloc(&pdev->dev,
 					sizeof(struct clk *) * n_ports,
 					GFP_KERNEL);
 	if (!hpriv->port_clks)
 		return -ENOMEM;
-#endif
 	host->private_data = hpriv;
 	hpriv->n_ports = n_ports;
 	hpriv->board_idx = chip_soc;
@@ -4084,7 +4085,6 @@
 				   resource_size(res));
 	hpriv->base -= SATAHC0_REG_BASE;
 
-#if defined(CONFIG_HAVE_CLK)
 	hpriv->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(hpriv->clk))
 		dev_notice(&pdev->dev, "cannot get optional clkdev\n");
@@ -4098,7 +4098,6 @@
 		if (!IS_ERR(hpriv->port_clks[port]))
 			clk_prepare_enable(hpriv->port_clks[port]);
 	}
-#endif
 
 	/*
 	 * (Re-)program MBUS remapping windows if we are asked to.
@@ -4124,7 +4123,6 @@
 		return 0;
 
 err:
-#if defined(CONFIG_HAVE_CLK)
 	if (!IS_ERR(hpriv->clk)) {
 		clk_disable_unprepare(hpriv->clk);
 		clk_put(hpriv->clk);
@@ -4135,7 +4133,6 @@
 			clk_put(hpriv->port_clks[port]);
 		}
 	}
-#endif
 
 	return rc;
 }
@@ -4151,13 +4148,10 @@
 static int mv_platform_remove(struct platform_device *pdev)
 {
 	struct ata_host *host = platform_get_drvdata(pdev);
-#if defined(CONFIG_HAVE_CLK)
 	struct mv_host_priv *hpriv = host->private_data;
 	int port;
-#endif
 	ata_host_detach(host);
 
-#if defined(CONFIG_HAVE_CLK)
 	if (!IS_ERR(hpriv->clk)) {
 		clk_disable_unprepare(hpriv->clk);
 		clk_put(hpriv->clk);
@@ -4168,7 +4162,6 @@
 			clk_put(hpriv->port_clks[port]);
 		}
 	}
-#endif
 	return 0;
 }
 
@@ -4428,9 +4421,6 @@
 #endif
 #endif
 
-static int mv_platform_probe(struct platform_device *pdev);
-static int mv_platform_remove(struct platform_device *pdev);
-
 static int __init mv_init(void)
 {
 	int rc = -ENODEV;
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 8108eb0..c2d95e9 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -778,10 +778,6 @@
 	int irq;
 	int ret = 0;
 
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (mem == NULL)
-		return -EINVAL;
-
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0)
 		return -EINVAL;
@@ -807,6 +803,7 @@
 
 	host->private_data = priv;
 
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	priv->base = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(priv->base)) {
 		ret = PTR_ERR(priv->base);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5daa259..e373671 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -200,11 +200,9 @@
 	  APIs extension; the file's descriptor can then be passed on to other
 	  driver.
 
-config CMA
-	bool "Contiguous Memory Allocator"
-	depends on HAVE_DMA_CONTIGUOUS && HAVE_MEMBLOCK
-	select MIGRATION
-	select MEMORY_ISOLATION
+config DMA_CMA
+	bool "DMA Contiguous Memory Allocator"
+	depends on HAVE_DMA_CONTIGUOUS && CMA
 	help
 	  This enables the Contiguous Memory Allocator which allows drivers
 	  to allocate big physically-contiguous blocks of memory for use with
@@ -213,17 +211,7 @@
 	  For more information see <include/linux/dma-contiguous.h>.
 	  If unsure, say "n".
 
-if CMA
-
-config CMA_DEBUG
-	bool "CMA debug messages (DEVELOPMENT)"
-	depends on DEBUG_KERNEL
-	help
-	  Turns on debug messages in CMA.  This produces KERN_DEBUG
-	  messages for every CMA call as well as various messages while
-	  processing calls such as dma_alloc_from_contiguous().
-	  This option does not affect warning and error messages.
-
+if  DMA_CMA
 comment "Default contiguous memory area size:"
 
 config CMA_SIZE_MBYTES
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 48029aa..94e8a80 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -6,7 +6,7 @@
 			   attribute_container.o transport_class.o \
 			   topology.o
 obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o
-obj-$(CONFIG_CMA) += dma-contiguous.o
+obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y			+= power/
 obj-$(CONFIG_HAS_DMA)	+= dma-mapping.o
 obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b8bdfe6..2cbc677 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -119,6 +119,16 @@
 	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
 }
 
+extern int driver_add_groups(struct device_driver *drv,
+			     const struct attribute_group **groups);
+extern void driver_remove_groups(struct device_driver *drv,
+				 const struct attribute_group **groups);
+
+extern int device_add_groups(struct device *dev,
+			     const struct attribute_group **groups);
+extern void device_remove_groups(struct device *dev,
+				 const struct attribute_group **groups);
+
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index d414331..4c289ab 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/mutex.h>
+#include <linux/sysfs.h>
 #include "base.h"
 #include "power/power.h"
 
@@ -165,8 +166,8 @@
 static struct kset *bus_kset;
 
 /* Manually detach a device from its associated driver. */
-static ssize_t driver_unbind(struct device_driver *drv,
-			     const char *buf, size_t count)
+static ssize_t unbind_store(struct device_driver *drv, const char *buf,
+			    size_t count)
 {
 	struct bus_type *bus = bus_get(drv->bus);
 	struct device *dev;
@@ -185,15 +186,15 @@
 	bus_put(bus);
 	return err;
 }
-static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+static DRIVER_ATTR_WO(unbind);
 
 /*
  * Manually attach a device to a driver.
  * Note: the driver must want to bind to the device,
  * it is not possible to override the driver's id table.
  */
-static ssize_t driver_bind(struct device_driver *drv,
-			   const char *buf, size_t count)
+static ssize_t bind_store(struct device_driver *drv, const char *buf,
+			  size_t count)
 {
 	struct bus_type *bus = bus_get(drv->bus);
 	struct device *dev;
@@ -221,7 +222,7 @@
 	bus_put(bus);
 	return err;
 }
-static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
+static DRIVER_ATTR_WO(bind);
 
 static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
 {
@@ -460,7 +461,7 @@
 	if (!bus->dev_attrs)
 		return 0;
 
-	for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+	for (i = 0; bus->dev_attrs[i].attr.name; i++) {
 		error = device_create_file(dev, &bus->dev_attrs[i]);
 		if (error) {
 			while (--i >= 0)
@@ -476,7 +477,7 @@
 	int i;
 
 	if (bus->dev_attrs) {
-		for (i = 0; attr_name(bus->dev_attrs[i]); i++)
+		for (i = 0; bus->dev_attrs[i].attr.name; i++)
 			device_remove_file(dev, &bus->dev_attrs[i]);
 	}
 }
@@ -499,6 +500,9 @@
 		error = device_add_attrs(bus, dev);
 		if (error)
 			goto out_put;
+		error = device_add_groups(dev, bus->dev_groups);
+		if (error)
+			goto out_groups;
 		error = sysfs_create_link(&bus->p->devices_kset->kobj,
 						&dev->kobj, dev_name(dev));
 		if (error)
@@ -513,6 +517,8 @@
 
 out_subsys:
 	sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
+out_groups:
+	device_remove_groups(dev, bus->dev_groups);
 out_id:
 	device_remove_attrs(bus, dev);
 out_put:
@@ -575,6 +581,7 @@
 	sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
 			  dev_name(dev));
 	device_remove_attrs(dev->bus, dev);
+	device_remove_groups(dev, dev->bus->dev_groups);
 	if (klist_node_attached(&dev->p->knode_bus))
 		klist_del(&dev->p->knode_bus);
 
@@ -590,7 +597,7 @@
 	int i;
 
 	if (bus->drv_attrs) {
-		for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
+		for (i = 0; bus->drv_attrs[i].attr.name; i++) {
 			error = driver_create_file(drv, &bus->drv_attrs[i]);
 			if (error)
 				goto err;
@@ -610,7 +617,7 @@
 	int i;
 
 	if (bus->drv_attrs) {
-		for (i = 0; attr_name(bus->drv_attrs[i]); i++)
+		for (i = 0; bus->drv_attrs[i].attr.name; i++)
 			driver_remove_file(drv, &bus->drv_attrs[i]);
 	}
 }
@@ -659,8 +666,8 @@
 	bus_remove_file(bus, &bus_attr_drivers_probe);
 }
 
-static ssize_t driver_uevent_store(struct device_driver *drv,
-				   const char *buf, size_t count)
+static ssize_t uevent_store(struct device_driver *drv, const char *buf,
+			    size_t count)
 {
 	enum kobject_action action;
 
@@ -668,7 +675,7 @@
 		kobject_uevent(&drv->p->kobj, action);
 	return count;
 }
-static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+static DRIVER_ATTR_WO(uevent);
 
 /**
  * bus_add_driver - Add a driver to the bus.
@@ -719,6 +726,10 @@
 		printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
 			__func__, drv->name);
 	}
+	error = driver_add_groups(drv, bus->drv_groups);
+	if (error)
+		printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
+			__func__, drv->name);
 
 	if (!drv->suppress_bind_attrs) {
 		error = add_bind_files(drv);
@@ -756,6 +767,7 @@
 	if (!drv->suppress_bind_attrs)
 		remove_bind_files(drv);
 	driver_remove_attrs(drv->bus, drv);
+	driver_remove_groups(drv, drv->bus->drv_groups);
 	driver_remove_file(drv, &driver_attr_uevent);
 	klist_remove(&drv->p->knode_bus);
 	pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
@@ -846,7 +858,7 @@
 	int i;
 
 	if (bus->bus_attrs) {
-		for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
+		for (i = 0; bus->bus_attrs[i].attr.name; i++) {
 			error = bus_create_file(bus, &bus->bus_attrs[i]);
 			if (error)
 				goto err;
@@ -865,11 +877,23 @@
 	int i;
 
 	if (bus->bus_attrs) {
-		for (i = 0; attr_name(bus->bus_attrs[i]); i++)
+		for (i = 0; bus->bus_attrs[i].attr.name; i++)
 			bus_remove_file(bus, &bus->bus_attrs[i]);
 	}
 }
 
+static int bus_add_groups(struct bus_type *bus,
+			  const struct attribute_group **groups)
+{
+	return sysfs_create_groups(&bus->p->subsys.kobj, groups);
+}
+
+static void bus_remove_groups(struct bus_type *bus,
+			      const struct attribute_group **groups)
+{
+	sysfs_remove_groups(&bus->p->subsys.kobj, groups);
+}
+
 static void klist_devices_get(struct klist_node *n)
 {
 	struct device_private *dev_prv = to_device_private_bus(n);
@@ -962,10 +986,15 @@
 	retval = bus_add_attrs(bus);
 	if (retval)
 		goto bus_attrs_fail;
+	retval = bus_add_groups(bus, bus->bus_groups);
+	if (retval)
+		goto bus_groups_fail;
 
 	pr_debug("bus: '%s': registered\n", bus->name);
 	return 0;
 
+bus_groups_fail:
+	bus_remove_attrs(bus);
 bus_attrs_fail:
 	remove_probe_files(bus);
 bus_probe_files_fail:
@@ -996,6 +1025,7 @@
 	if (bus->dev_root)
 		device_unregister(bus->dev_root);
 	bus_remove_attrs(bus);
+	bus_remove_groups(bus, bus->bus_groups);
 	remove_probe_files(bus);
 	kset_unregister(bus->p->drivers_kset);
 	kset_unregister(bus->p->devices_kset);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 3ce8454..8b7818b 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -135,7 +135,7 @@
 	int error = 0;
 
 	if (cls->class_attrs) {
-		for (i = 0; attr_name(cls->class_attrs[i]); i++) {
+		for (i = 0; cls->class_attrs[i].attr.name; i++) {
 			error = class_create_file(cls, &cls->class_attrs[i]);
 			if (error)
 				goto error;
@@ -154,7 +154,7 @@
 	int i;
 
 	if (cls->class_attrs) {
-		for (i = 0; attr_name(cls->class_attrs[i]); i++)
+		for (i = 0; cls->class_attrs[i].attr.name; i++)
 			class_remove_file(cls, &cls->class_attrs[i]);
 	}
 }
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8856d74..c7cfadc 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -26,6 +26,7 @@
 #include <linux/async.h>
 #include <linux/pm_runtime.h>
 #include <linux/netdevice.h>
+#include <linux/sysfs.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -36,9 +37,9 @@
 #else
 long sysfs_deprecated = 0;
 #endif
-static __init int sysfs_deprecated_setup(char *arg)
+static int __init sysfs_deprecated_setup(char *arg)
 {
-	return strict_strtol(arg, 10, &sysfs_deprecated);
+	return kstrtol(arg, 10, &sysfs_deprecated);
 }
 early_param("sysfs.deprecated", sysfs_deprecated_setup);
 #endif
@@ -49,6 +50,28 @@
 struct kobject *sysfs_dev_char_kobj;
 struct kobject *sysfs_dev_block_kobj;
 
+static DEFINE_MUTEX(device_hotplug_lock);
+
+void lock_device_hotplug(void)
+{
+	mutex_lock(&device_hotplug_lock);
+}
+
+void unlock_device_hotplug(void)
+{
+	mutex_unlock(&device_hotplug_lock);
+}
+
+int lock_device_hotplug_sysfs(void)
+{
+	if (mutex_trylock(&device_hotplug_lock))
+		return 0;
+
+	/* Avoid busy looping (5 ms of sleep should do). */
+	msleep(5);
+	return restart_syscall();
+}
+
 #ifdef CONFIG_BLOCK
 static inline int device_is_not_partition(struct device *dev)
 {
@@ -345,7 +368,7 @@
 	.uevent =	dev_uevent,
 };
 
-static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
+static ssize_t uevent_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	struct kobject *top_kobj;
@@ -388,7 +411,7 @@
 	return count;
 }
 
-static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
+static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
 	enum kobject_action action;
@@ -399,22 +422,20 @@
 		dev_err(dev, "uevent: unknown action-string\n");
 	return count;
 }
+static DEVICE_ATTR_RW(uevent);
 
-static struct device_attribute uevent_attr =
-	__ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
-
-static ssize_t show_online(struct device *dev, struct device_attribute *attr,
+static ssize_t online_show(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	bool val;
 
-	lock_device_hotplug();
+	device_lock(dev);
 	val = !dev->offline;
-	unlock_device_hotplug();
+	device_unlock(dev);
 	return sprintf(buf, "%u\n", val);
 }
 
-static ssize_t store_online(struct device *dev, struct device_attribute *attr,
+static ssize_t online_store(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
 	bool val;
@@ -424,14 +445,15 @@
 	if (ret < 0)
 		return ret;
 
-	lock_device_hotplug();
+	ret = lock_device_hotplug_sysfs();
+	if (ret)
+		return ret;
+
 	ret = val ? device_online(dev) : device_offline(dev);
 	unlock_device_hotplug();
 	return ret < 0 ? ret : count;
 }
-
-static struct device_attribute online_attr =
-	__ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+static DEVICE_ATTR_RW(online);
 
 static int device_add_attributes(struct device *dev,
 				 struct device_attribute *attrs)
@@ -440,7 +462,7 @@
 	int i;
 
 	if (attrs) {
-		for (i = 0; attr_name(attrs[i]); i++) {
+		for (i = 0; attrs[i].attr.name; i++) {
 			error = device_create_file(dev, &attrs[i]);
 			if (error)
 				break;
@@ -458,7 +480,7 @@
 	int i;
 
 	if (attrs)
-		for (i = 0; attr_name(attrs[i]); i++)
+		for (i = 0; attrs[i].attr.name; i++)
 			device_remove_file(dev, &attrs[i]);
 }
 
@@ -469,7 +491,7 @@
 	int i;
 
 	if (attrs) {
-		for (i = 0; attr_name(attrs[i]); i++) {
+		for (i = 0; attrs[i].attr.name; i++) {
 			error = device_create_bin_file(dev, &attrs[i]);
 			if (error)
 				break;
@@ -487,38 +509,19 @@
 	int i;
 
 	if (attrs)
-		for (i = 0; attr_name(attrs[i]); i++)
+		for (i = 0; attrs[i].attr.name; i++)
 			device_remove_bin_file(dev, &attrs[i]);
 }
 
-static int device_add_groups(struct device *dev,
-			     const struct attribute_group **groups)
+int device_add_groups(struct device *dev, const struct attribute_group **groups)
 {
-	int error = 0;
-	int i;
-
-	if (groups) {
-		for (i = 0; groups[i]; i++) {
-			error = sysfs_create_group(&dev->kobj, groups[i]);
-			if (error) {
-				while (--i >= 0)
-					sysfs_remove_group(&dev->kobj,
-							   groups[i]);
-				break;
-			}
-		}
-	}
-	return error;
+	return sysfs_create_groups(&dev->kobj, groups);
 }
 
-static void device_remove_groups(struct device *dev,
-				 const struct attribute_group **groups)
+void device_remove_groups(struct device *dev,
+			  const struct attribute_group **groups)
 {
-	int i;
-
-	if (groups)
-		for (i = 0; groups[i]; i++)
-			sysfs_remove_group(&dev->kobj, groups[i]);
+	sysfs_remove_groups(&dev->kobj, groups);
 }
 
 static int device_add_attrs(struct device *dev)
@@ -550,7 +553,7 @@
 		goto err_remove_type_groups;
 
 	if (device_supports_offline(dev) && !dev->offline_disabled) {
-		error = device_create_file(dev, &online_attr);
+		error = device_create_file(dev, &dev_attr_online);
 		if (error)
 			goto err_remove_type_groups;
 	}
@@ -578,7 +581,7 @@
 	struct class *class = dev->class;
 	const struct device_type *type = dev->type;
 
-	device_remove_file(dev, &online_attr);
+	device_remove_file(dev, &dev_attr_online);
 	device_remove_groups(dev, dev->groups);
 
 	if (type)
@@ -591,15 +594,12 @@
 	}
 }
 
-
-static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
+static ssize_t dev_show(struct device *dev, struct device_attribute *attr,
 			char *buf)
 {
 	return print_dev_t(buf, dev->devt);
 }
-
-static struct device_attribute devt_attr =
-	__ATTR(dev, S_IRUGO, show_dev, NULL);
+static DEVICE_ATTR_RO(dev);
 
 /* /sys/devices/ */
 struct kset *devices_kset;
@@ -626,6 +626,7 @@
 
 	return error;
 }
+EXPORT_SYMBOL_GPL(device_create_file);
 
 /**
  * device_remove_file - remove sysfs attribute file.
@@ -638,6 +639,7 @@
 	if (dev)
 		sysfs_remove_file(&dev->kobj, &attr->attr);
 }
+EXPORT_SYMBOL_GPL(device_remove_file);
 
 /**
  * device_create_bin_file - create sysfs binary attribute file for device.
@@ -748,6 +750,7 @@
 	device_pm_init(dev);
 	set_dev_node(dev, -1);
 }
+EXPORT_SYMBOL_GPL(device_initialize);
 
 struct kobject *virtual_device_parent(struct device *dev)
 {
@@ -1100,12 +1103,12 @@
 	if (platform_notify)
 		platform_notify(dev);
 
-	error = device_create_file(dev, &uevent_attr);
+	error = device_create_file(dev, &dev_attr_uevent);
 	if (error)
 		goto attrError;
 
 	if (MAJOR(dev->devt)) {
-		error = device_create_file(dev, &devt_attr);
+		error = device_create_file(dev, &dev_attr_dev);
 		if (error)
 			goto ueventattrError;
 
@@ -1172,9 +1175,9 @@
 		device_remove_sys_dev_entry(dev);
  devtattrError:
 	if (MAJOR(dev->devt))
-		device_remove_file(dev, &devt_attr);
+		device_remove_file(dev, &dev_attr_dev);
  ueventattrError:
-	device_remove_file(dev, &uevent_attr);
+	device_remove_file(dev, &dev_attr_uevent);
  attrError:
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
@@ -1187,6 +1190,7 @@
 	dev->p = NULL;
 	goto done;
 }
+EXPORT_SYMBOL_GPL(device_add);
 
 /**
  * device_register - register a device with the system.
@@ -1211,6 +1215,7 @@
 	device_initialize(dev);
 	return device_add(dev);
 }
+EXPORT_SYMBOL_GPL(device_register);
 
 /**
  * get_device - increment reference count for device.
@@ -1224,6 +1229,7 @@
 {
 	return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL;
 }
+EXPORT_SYMBOL_GPL(get_device);
 
 /**
  * put_device - decrement reference count.
@@ -1235,6 +1241,7 @@
 	if (dev)
 		kobject_put(&dev->kobj);
 }
+EXPORT_SYMBOL_GPL(put_device);
 
 /**
  * device_del - delete device from system.
@@ -1266,7 +1273,7 @@
 	if (MAJOR(dev->devt)) {
 		devtmpfs_delete_node(dev);
 		device_remove_sys_dev_entry(dev);
-		device_remove_file(dev, &devt_attr);
+		device_remove_file(dev, &dev_attr_dev);
 	}
 	if (dev->class) {
 		device_remove_class_symlinks(dev);
@@ -1281,7 +1288,7 @@
 		klist_del(&dev->knode_class);
 		mutex_unlock(&dev->class->p->mutex);
 	}
-	device_remove_file(dev, &uevent_attr);
+	device_remove_file(dev, &dev_attr_uevent);
 	device_remove_attrs(dev);
 	bus_remove_device(dev);
 	device_pm_remove(dev);
@@ -1297,6 +1304,7 @@
 	kobject_del(&dev->kobj);
 	put_device(parent);
 }
+EXPORT_SYMBOL_GPL(device_del);
 
 /**
  * device_unregister - unregister device from system.
@@ -1315,6 +1323,7 @@
 	device_del(dev);
 	put_device(dev);
 }
+EXPORT_SYMBOL_GPL(device_unregister);
 
 static struct device *next_device(struct klist_iter *i)
 {
@@ -1403,6 +1412,7 @@
 	klist_iter_exit(&i);
 	return error;
 }
+EXPORT_SYMBOL_GPL(device_for_each_child);
 
 /**
  * device_find_child - device iterator for locating a particular device.
@@ -1437,6 +1447,7 @@
 	klist_iter_exit(&i);
 	return child;
 }
+EXPORT_SYMBOL_GPL(device_find_child);
 
 int __init devices_init(void)
 {
@@ -1464,33 +1475,6 @@
 	return -ENOMEM;
 }
 
-EXPORT_SYMBOL_GPL(device_for_each_child);
-EXPORT_SYMBOL_GPL(device_find_child);
-
-EXPORT_SYMBOL_GPL(device_initialize);
-EXPORT_SYMBOL_GPL(device_add);
-EXPORT_SYMBOL_GPL(device_register);
-
-EXPORT_SYMBOL_GPL(device_del);
-EXPORT_SYMBOL_GPL(device_unregister);
-EXPORT_SYMBOL_GPL(get_device);
-EXPORT_SYMBOL_GPL(put_device);
-
-EXPORT_SYMBOL_GPL(device_create_file);
-EXPORT_SYMBOL_GPL(device_remove_file);
-
-static DEFINE_MUTEX(device_hotplug_lock);
-
-void lock_device_hotplug(void)
-{
-	mutex_lock(&device_hotplug_lock);
-}
-
-void unlock_device_hotplug(void)
-{
-	mutex_unlock(&device_hotplug_lock);
-}
-
 static int device_check_offline(struct device *dev, void *not_used)
 {
 	int ret;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4c358bc..848ebbd 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/percpu.h>
 #include <linux/acpi.h>
+#include <linux/of.h>
 
 #include "base.h"
 
@@ -43,11 +44,14 @@
 	struct cpu *cpu = container_of(dev, struct cpu, dev);
 	int cpuid = dev->id;
 	int from_nid, to_nid;
-	int ret;
+	int ret = -ENODEV;
 
 	cpu_hotplug_driver_lock();
 
 	from_nid = cpu_to_node(cpuid);
+	if (from_nid == NUMA_NO_NODE)
+		goto out;
+
 	ret = cpu_up(cpuid);
 	/*
 	 * When hot adding memory to memoryless node and enabling a cpu
@@ -57,6 +61,7 @@
 	if (from_nid != to_nid)
 		change_cpu_under_node(cpu, from_nid, to_nid);
 
+ out:
 	cpu_hotplug_driver_unlock();
 	return ret;
 }
@@ -289,6 +294,7 @@
 	cpu->dev.release = cpu_device_release;
 	cpu->dev.offline_disabled = !cpu->hotpluggable;
 	cpu->dev.offline = !cpu_online(num);
+	cpu->dev.of_node = of_get_cpu_node(num, NULL);
 #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
 	cpu->dev.bus->uevent = arch_cpu_uevent;
 #endif
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 6687ba7..1219ab7 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -680,7 +680,7 @@
 	d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir,
 			write, &dma_buf_debug_fops);
 
-	return PTR_RET(d);
+	return PTR_ERR_OR_ZERO(d);
 }
 #else
 static inline int dma_buf_init_debugfs(void)
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 0ca5442..6c9cdaa 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -134,7 +134,7 @@
 
 static DEFINE_MUTEX(cma_mutex);
 
-static __init int cma_activate_area(unsigned long base_pfn, unsigned long count)
+static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
 {
 	unsigned long pfn = base_pfn;
 	unsigned i = count >> pageblock_order;
@@ -156,7 +156,7 @@
 	return 0;
 }
 
-static __init struct cma *cma_create_area(unsigned long base_pfn,
+static struct cma * __init cma_create_area(unsigned long base_pfn,
 				     unsigned long count)
 {
 	int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 974e301..9e29943 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/sysfs.h>
 #include "base.h"
 
 static struct device *next_device(struct klist_iter *i)
@@ -123,34 +124,16 @@
 }
 EXPORT_SYMBOL_GPL(driver_remove_file);
 
-static int driver_add_groups(struct device_driver *drv,
-			     const struct attribute_group **groups)
+int driver_add_groups(struct device_driver *drv,
+		      const struct attribute_group **groups)
 {
-	int error = 0;
-	int i;
-
-	if (groups) {
-		for (i = 0; groups[i]; i++) {
-			error = sysfs_create_group(&drv->p->kobj, groups[i]);
-			if (error) {
-				while (--i >= 0)
-					sysfs_remove_group(&drv->p->kobj,
-							   groups[i]);
-				break;
-			}
-		}
-	}
-	return error;
+	return sysfs_create_groups(&drv->p->kobj, groups);
 }
 
-static void driver_remove_groups(struct device_driver *drv,
-				 const struct attribute_group **groups)
+void driver_remove_groups(struct device_driver *drv,
+			  const struct attribute_group **groups)
 {
-	int i;
-
-	if (groups)
-		for (i = 0; groups[i]; i++)
-			sysfs_remove_group(&drv->p->kobj, groups[i]);
+	sysfs_remove_groups(&drv->p->kobj, groups);
 }
 
 /**
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a439602..10a4467 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -486,9 +486,8 @@
 	.notifier_call = fw_shutdown_notify,
 };
 
-static ssize_t firmware_timeout_show(struct class *class,
-				     struct class_attribute *attr,
-				     char *buf)
+static ssize_t timeout_show(struct class *class, struct class_attribute *attr,
+			    char *buf)
 {
 	return sprintf(buf, "%d\n", loading_timeout);
 }
@@ -506,9 +505,8 @@
  *
  *	Note: zero means 'wait forever'.
  **/
-static ssize_t firmware_timeout_store(struct class *class,
-				      struct class_attribute *attr,
-				      const char *buf, size_t count)
+static ssize_t timeout_store(struct class *class, struct class_attribute *attr,
+			     const char *buf, size_t count)
 {
 	loading_timeout = simple_strtol(buf, NULL, 10);
 	if (loading_timeout < 0)
@@ -518,8 +516,7 @@
 }
 
 static struct class_attribute firmware_class_attrs[] = {
-	__ATTR(timeout, S_IWUSR | S_IRUGO,
-		firmware_timeout_show, firmware_timeout_store),
+	__ATTR_RW(timeout),
 	__ATTR_NULL
 };
 
@@ -868,8 +865,15 @@
 		goto err_del_dev;
 	}
 
+	mutex_lock(&fw_lock);
+	list_add(&buf->pending_list, &pending_fw_head);
+	mutex_unlock(&fw_lock);
+
 	retval = device_create_file(f_dev, &dev_attr_loading);
 	if (retval) {
+		mutex_lock(&fw_lock);
+		list_del_init(&buf->pending_list);
+		mutex_unlock(&fw_lock);
 		dev_err(f_dev, "%s: device_create_file failed\n", __func__);
 		goto err_del_bin_attr;
 	}
@@ -884,10 +888,6 @@
 		kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
 	}
 
-	mutex_lock(&fw_lock);
-	list_add(&buf->pending_list, &pending_fw_head);
-	mutex_unlock(&fw_lock);
-
 	wait_for_completion(&buf->completion);
 
 	cancel_delayed_work_sync(&fw_priv->timeout_work);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 2b7813e..9e59f65 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -16,7 +16,6 @@
 #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/memory.h>
-#include <linux/kobject.h>
 #include <linux/memory_hotplug.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
@@ -30,6 +29,8 @@
 
 #define MEMORY_CLASS_NAME	"memory"
 
+#define to_memory_block(dev) container_of(dev, struct memory_block, dev)
+
 static int sections_per_block;
 
 static inline int base_memory_block_id(int section_nr)
@@ -77,7 +78,7 @@
 
 static void memory_block_release(struct device *dev)
 {
-	struct memory_block *mem = container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 
 	kfree(mem);
 }
@@ -110,8 +111,7 @@
 static ssize_t show_mem_start_phys_index(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct memory_block *mem =
-		container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 	unsigned long phys_index;
 
 	phys_index = mem->start_section_nr / sections_per_block;
@@ -121,8 +121,7 @@
 static ssize_t show_mem_end_phys_index(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct memory_block *mem =
-		container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 	unsigned long phys_index;
 
 	phys_index = mem->end_section_nr / sections_per_block;
@@ -137,10 +136,11 @@
 {
 	unsigned long i, pfn;
 	int ret = 1;
-	struct memory_block *mem =
-		container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 
 	for (i = 0; i < sections_per_block; i++) {
+		if (!present_section_nr(mem->start_section_nr + i))
+			continue;
 		pfn = section_nr_to_pfn(mem->start_section_nr + i);
 		ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
 	}
@@ -154,8 +154,7 @@
 static ssize_t show_mem_state(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	struct memory_block *mem =
-		container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 	ssize_t len = 0;
 
 	/*
@@ -261,9 +260,8 @@
 	return ret;
 }
 
-static int __memory_block_change_state(struct memory_block *mem,
-		unsigned long to_state, unsigned long from_state_req,
-		int online_type)
+static int memory_block_change_state(struct memory_block *mem,
+		unsigned long to_state, unsigned long from_state_req)
 {
 	int ret = 0;
 
@@ -273,105 +271,91 @@
 	if (to_state == MEM_OFFLINE)
 		mem->state = MEM_GOING_OFFLINE;
 
-	ret = memory_block_action(mem->start_section_nr, to_state, online_type);
+	ret = memory_block_action(mem->start_section_nr, to_state,
+				mem->online_type);
+
 	mem->state = ret ? from_state_req : to_state;
+
 	return ret;
 }
 
+/* The device lock serializes operations on memory_subsys_[online|offline] */
 static int memory_subsys_online(struct device *dev)
 {
-	struct memory_block *mem = container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 	int ret;
 
-	mutex_lock(&mem->state_mutex);
+	if (mem->state == MEM_ONLINE)
+		return 0;
 
-	ret = mem->state == MEM_ONLINE ? 0 :
-		__memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE,
-					    ONLINE_KEEP);
+	/*
+	 * If we are called from store_mem_state(), online_type will be
+	 * set >= 0 Otherwise we were called from the device online
+	 * attribute and need to set the online_type.
+	 */
+	if (mem->online_type < 0)
+		mem->online_type = ONLINE_KEEP;
 
-	mutex_unlock(&mem->state_mutex);
+	ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
+
+	/* clear online_type */
+	mem->online_type = -1;
+
 	return ret;
 }
 
 static int memory_subsys_offline(struct device *dev)
 {
-	struct memory_block *mem = container_of(dev, struct memory_block, dev);
-	int ret;
+	struct memory_block *mem = to_memory_block(dev);
 
-	mutex_lock(&mem->state_mutex);
+	if (mem->state == MEM_OFFLINE)
+		return 0;
 
-	ret = mem->state == MEM_OFFLINE ? 0 :
-		__memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
-
-	mutex_unlock(&mem->state_mutex);
-	return ret;
+	return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
 }
 
-static int __memory_block_change_state_uevent(struct memory_block *mem,
-		unsigned long to_state, unsigned long from_state_req,
-		int online_type)
-{
-	int ret = __memory_block_change_state(mem, to_state, from_state_req,
-					      online_type);
-	if (!ret) {
-		switch (mem->state) {
-		case MEM_OFFLINE:
-			kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
-			break;
-		case MEM_ONLINE:
-			kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
-			break;
-		default:
-			break;
-		}
-	}
-	return ret;
-}
-
-static int memory_block_change_state(struct memory_block *mem,
-		unsigned long to_state, unsigned long from_state_req,
-		int online_type)
-{
-	int ret;
-
-	mutex_lock(&mem->state_mutex);
-	ret = __memory_block_change_state_uevent(mem, to_state, from_state_req,
-						 online_type);
-	mutex_unlock(&mem->state_mutex);
-
-	return ret;
-}
 static ssize_t
 store_mem_state(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct memory_block *mem;
-	bool offline;
-	int ret = -EINVAL;
+	struct memory_block *mem = to_memory_block(dev);
+	int ret, online_type;
 
-	mem = container_of(dev, struct memory_block, dev);
+	ret = lock_device_hotplug_sysfs();
+	if (ret)
+		return ret;
 
-	lock_device_hotplug();
+	if (!strncmp(buf, "online_kernel", min_t(int, count, 13)))
+		online_type = ONLINE_KERNEL;
+	else if (!strncmp(buf, "online_movable", min_t(int, count, 14)))
+		online_type = ONLINE_MOVABLE;
+	else if (!strncmp(buf, "online", min_t(int, count, 6)))
+		online_type = ONLINE_KEEP;
+	else if (!strncmp(buf, "offline", min_t(int, count, 7)))
+		online_type = -1;
+	else
+		return -EINVAL;
 
-	if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) {
-		offline = false;
-		ret = memory_block_change_state(mem, MEM_ONLINE,
-						MEM_OFFLINE, ONLINE_KERNEL);
-	} else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) {
-		offline = false;
-		ret = memory_block_change_state(mem, MEM_ONLINE,
-						MEM_OFFLINE, ONLINE_MOVABLE);
-	} else if (!strncmp(buf, "online", min_t(int, count, 6))) {
-		offline = false;
-		ret = memory_block_change_state(mem, MEM_ONLINE,
-						MEM_OFFLINE, ONLINE_KEEP);
-	} else if(!strncmp(buf, "offline", min_t(int, count, 7))) {
-		offline = true;
-		ret = memory_block_change_state(mem, MEM_OFFLINE,
-						MEM_ONLINE, -1);
+	switch (online_type) {
+	case ONLINE_KERNEL:
+	case ONLINE_MOVABLE:
+	case ONLINE_KEEP:
+		/*
+		 * mem->online_type is not protected so there can be a
+		 * race here.  However, when racing online, the first
+		 * will succeed and the second will just return as the
+		 * block will already be online.  The online type
+		 * could be either one, but that is expected.
+		 */
+		mem->online_type = online_type;
+		ret = device_online(&mem->dev);
+		break;
+	case -1:
+		ret = device_offline(&mem->dev);
+		break;
+	default:
+		ret = -EINVAL; /* should never happen */
 	}
-	if (!ret)
-		dev->offline = offline;
 
 	unlock_device_hotplug();
 
@@ -392,8 +376,7 @@
 static ssize_t show_phys_device(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct memory_block *mem =
-		container_of(dev, struct memory_block, dev);
+	struct memory_block *mem = to_memory_block(dev);
 	return sprintf(buf, "%d\n", mem->phys_device);
 }
 
@@ -469,7 +452,7 @@
 	u64 pfn;
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	if (strict_strtoull(buf, 0, &pfn) < 0)
+	if (kstrtoull(buf, 0, &pfn) < 0)
 		return -EINVAL;
 	pfn >>= PAGE_SHIFT;
 	if (!pfn_valid(pfn))
@@ -488,7 +471,7 @@
 	u64 pfn;
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	if (strict_strtoull(buf, 0, &pfn) < 0)
+	if (kstrtoull(buf, 0, &pfn) < 0)
 		return -EINVAL;
 	pfn >>= PAGE_SHIFT;
 	ret = memory_failure(pfn, 0, 0);
@@ -525,7 +508,7 @@
 		put_device(&hint->dev);
 	if (!dev)
 		return NULL;
-	return container_of(dev, struct memory_block, dev);
+	return to_memory_block(dev);
 }
 
 /*
@@ -565,16 +548,13 @@
 static
 int register_memory(struct memory_block *memory)
 {
-	int error;
-
 	memory->dev.bus = &memory_subsys;
 	memory->dev.id = memory->start_section_nr / sections_per_block;
 	memory->dev.release = memory_block_release;
 	memory->dev.groups = memory_memblk_attr_groups;
 	memory->dev.offline = memory->state == MEM_OFFLINE;
 
-	error = device_register(&memory->dev);
-	return error;
+	return device_register(&memory->dev);
 }
 
 static int init_memory_block(struct memory_block **memory,
@@ -595,7 +575,6 @@
 	mem->end_section_nr = mem->start_section_nr + sections_per_block - 1;
 	mem->state = state;
 	mem->section_count++;
-	mutex_init(&mem->state_mutex);
 	start_pfn = section_nr_to_pfn(mem->start_section_nr);
 	mem->phys_device = arch_get_memory_phys_device(start_pfn);
 
@@ -605,55 +584,57 @@
 	return ret;
 }
 
-static int add_memory_section(int nid, struct mem_section *section,
-			struct memory_block **mem_p,
-			unsigned long state, enum mem_add_context context)
+static int add_memory_block(int base_section_nr)
 {
-	struct memory_block *mem = NULL;
-	int scn_nr = __section_nr(section);
-	int ret = 0;
+	struct memory_block *mem;
+	int i, ret, section_count = 0, section_nr;
 
-	mutex_lock(&mem_sysfs_mutex);
-
-	if (context == BOOT) {
-		/* same memory block ? */
-		if (mem_p && *mem_p)
-			if (scn_nr >= (*mem_p)->start_section_nr &&
-			    scn_nr <= (*mem_p)->end_section_nr) {
-				mem = *mem_p;
-				kobject_get(&mem->dev.kobj);
-			}
-	} else
-		mem = find_memory_block(section);
-
-	if (mem) {
-		mem->section_count++;
-		kobject_put(&mem->dev.kobj);
-	} else {
-		ret = init_memory_block(&mem, section, state);
-		/* store memory_block pointer for next loop */
-		if (!ret && context == BOOT)
-			if (mem_p)
-				*mem_p = mem;
+	for (i = base_section_nr;
+	     (i < base_section_nr + sections_per_block) && i < NR_MEM_SECTIONS;
+	     i++) {
+		if (!present_section_nr(i))
+			continue;
+		if (section_count == 0)
+			section_nr = i;
+		section_count++;
 	}
 
-	if (!ret) {
-		if (context == HOTPLUG &&
-		    mem->section_count == sections_per_block)
-			ret = register_mem_sect_under_node(mem, nid);
-	}
-
-	mutex_unlock(&mem_sysfs_mutex);
-	return ret;
+	if (section_count == 0)
+		return 0;
+	ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
+	if (ret)
+		return ret;
+	mem->section_count = section_count;
+	return 0;
 }
 
+
 /*
  * need an interface for the VM to add new memory regions,
  * but without onlining it.
  */
 int register_new_memory(int nid, struct mem_section *section)
 {
-	return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
+	int ret = 0;
+	struct memory_block *mem;
+
+	mutex_lock(&mem_sysfs_mutex);
+
+	mem = find_memory_block(section);
+	if (mem) {
+		mem->section_count++;
+		put_device(&mem->dev);
+	} else {
+		ret = init_memory_block(&mem, section, MEM_OFFLINE);
+		if (ret)
+			goto out;
+	}
+
+	if (mem->section_count == sections_per_block)
+		ret = register_mem_sect_under_node(mem, nid);
+out:
+	mutex_unlock(&mem_sysfs_mutex);
+	return ret;
 }
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
@@ -663,7 +644,7 @@
 	BUG_ON(memory->dev.bus != &memory_subsys);
 
 	/* drop the ref. we got in remove_memory_block() */
-	kobject_put(&memory->dev.kobj);
+	put_device(&memory->dev);
 	device_unregister(&memory->dev);
 }
 
@@ -680,7 +661,7 @@
 	if (mem->section_count == 0)
 		unregister_memory(mem);
 	else
-		kobject_put(&mem->dev.kobj);
+		put_device(&mem->dev);
 
 	mutex_unlock(&mem_sysfs_mutex);
 	return 0;
@@ -733,7 +714,6 @@
 	int ret;
 	int err;
 	unsigned long block_sz;
-	struct memory_block *mem = NULL;
 
 	ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
 	if (ret)
@@ -746,17 +726,13 @@
 	 * Create entries for memory sections that were found
 	 * during boot and have been initialized
 	 */
-	for (i = 0; i < NR_MEM_SECTIONS; i++) {
-		if (!present_section_nr(i))
-			continue;
-		/* don't need to reuse memory_block if only one per block */
-		err = add_memory_section(0, __nr_to_section(i),
-				 (sections_per_block == 1) ? NULL : &mem,
-					 MEM_ONLINE,
-					 BOOT);
+	mutex_lock(&mem_sysfs_mutex);
+	for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {
+		err = add_memory_block(i);
 		if (!ret)
 			ret = err;
 	}
+	mutex_unlock(&mem_sysfs_mutex);
 
 out:
 	if (ret)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3c3197a..4f8bef3 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -672,11 +672,13 @@
 
 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
+static DEVICE_ATTR_RO(modalias);
 
-static struct device_attribute platform_dev_attrs[] = {
-	__ATTR_RO(modalias),
-	__ATTR_NULL,
+static struct attribute *platform_dev_attrs[] = {
+	&dev_attr_modalias.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(platform_dev);
 
 static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -893,7 +895,7 @@
 
 struct bus_type platform_bus_type = {
 	.name		= "platform",
-	.dev_attrs	= platform_dev_attrs,
+	.dev_groups	= platform_dev_groups,
 	.match		= platform_match,
 	.uevent		= platform_uevent,
 	.pm		= &platform_dev_pm_ops,
@@ -1054,7 +1056,7 @@
  * @epdrv: early platform driver structure
  * @id: id to match against
  */
-static  __init struct platform_device *
+static struct platform_device * __init
 early_platform_match(struct early_platform_driver *epdrv, int id)
 {
 	struct platform_device *pd;
@@ -1072,7 +1074,7 @@
  * @epdrv: early platform driver structure
  * @id: return true if id or above exists
  */
-static  __init int early_platform_left(struct early_platform_driver *epdrv,
+static int __init early_platform_left(struct early_platform_driver *epdrv,
 				       int id)
 {
 	struct platform_device *pd;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 5a9b656..9f098a8 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/async.h>
 #include <linux/suspend.h>
+#include <trace/events/power.h>
 #include <linux/cpuidle.h>
 #include "../base.h"
 #include "power.h"
@@ -56,6 +57,30 @@
 
 static int async_error;
 
+static char *pm_verb(int event)
+{
+	switch (event) {
+	case PM_EVENT_SUSPEND:
+		return "suspend";
+	case PM_EVENT_RESUME:
+		return "resume";
+	case PM_EVENT_FREEZE:
+		return "freeze";
+	case PM_EVENT_QUIESCE:
+		return "quiesce";
+	case PM_EVENT_HIBERNATE:
+		return "hibernate";
+	case PM_EVENT_THAW:
+		return "thaw";
+	case PM_EVENT_RESTORE:
+		return "restore";
+	case PM_EVENT_RECOVER:
+		return "recover";
+	default:
+		return "(unknown PM event)";
+	}
+}
+
 /**
  * device_pm_sleep_init - Initialize system suspend-related device fields.
  * @dev: Device object being initialized.
@@ -172,16 +197,21 @@
 }
 
 static void initcall_debug_report(struct device *dev, ktime_t calltime,
-				  int error)
+				  int error, pm_message_t state, char *info)
 {
-	ktime_t delta, rettime;
+	ktime_t rettime;
+	s64 nsecs;
+
+	rettime = ktime_get();
+	nsecs = (s64) ktime_to_ns(ktime_sub(rettime, calltime));
 
 	if (pm_print_times_enabled) {
-		rettime = ktime_get();
-		delta = ktime_sub(rettime, calltime);
 		pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
-			error, (unsigned long long)ktime_to_ns(delta) >> 10);
+			error, (unsigned long long)nsecs >> 10);
 	}
+
+	trace_device_pm_report_time(dev, info, nsecs, pm_verb(state.event),
+				    error);
 }
 
 /**
@@ -309,30 +339,6 @@
 	return NULL;
 }
 
-static char *pm_verb(int event)
-{
-	switch (event) {
-	case PM_EVENT_SUSPEND:
-		return "suspend";
-	case PM_EVENT_RESUME:
-		return "resume";
-	case PM_EVENT_FREEZE:
-		return "freeze";
-	case PM_EVENT_QUIESCE:
-		return "quiesce";
-	case PM_EVENT_HIBERNATE:
-		return "hibernate";
-	case PM_EVENT_THAW:
-		return "thaw";
-	case PM_EVENT_RESTORE:
-		return "restore";
-	case PM_EVENT_RECOVER:
-		return "recover";
-	default:
-		return "(unknown PM event)";
-	}
-}
-
 static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
 {
 	dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
@@ -379,7 +385,7 @@
 	error = cb(dev);
 	suspend_report_result(cb, error);
 
-	initcall_debug_report(dev, calltime, error);
+	initcall_debug_report(dev, calltime, error, state, info);
 
 	return error;
 }
@@ -1027,7 +1033,8 @@
  * @cb: Suspend callback to execute.
  */
 static int legacy_suspend(struct device *dev, pm_message_t state,
-			  int (*cb)(struct device *dev, pm_message_t state))
+			  int (*cb)(struct device *dev, pm_message_t state),
+			  char *info)
 {
 	int error;
 	ktime_t calltime;
@@ -1037,7 +1044,7 @@
 	error = cb(dev, state);
 	suspend_report_result(cb, error);
 
-	initcall_debug_report(dev, calltime, error);
+	initcall_debug_report(dev, calltime, error, state, info);
 
 	return error;
 }
@@ -1097,7 +1104,8 @@
 			goto Run;
 		} else if (dev->class->suspend) {
 			pm_dev_dbg(dev, state, "legacy class ");
-			error = legacy_suspend(dev, state, dev->class->suspend);
+			error = legacy_suspend(dev, state, dev->class->suspend,
+						"legacy class ");
 			goto End;
 		}
 	}
@@ -1108,7 +1116,8 @@
 			callback = pm_op(dev->bus->pm, state);
 		} else if (dev->bus->suspend) {
 			pm_dev_dbg(dev, state, "legacy bus ");
-			error = legacy_suspend(dev, state, dev->bus->suspend);
+			error = legacy_suspend(dev, state, dev->bus->suspend,
+						"legacy bus ");
 			goto End;
 		}
 	}
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index c8ec186..ef89897 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -460,6 +460,7 @@
 	srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(opp_add);
 
 /**
  * opp_set_availability() - helper to set the availability of an opp
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a53ebd2..03e089a 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -206,7 +206,7 @@
 	if (!dev->power.use_autosuspend)
 		return -EIO;
 
-	if (strict_strtol(buf, 10, &delay) != 0 || delay != (int) delay)
+	if (kstrtol(buf, 10, &delay) != 0 || delay != (int) delay)
 		return -EINVAL;
 
 	device_lock(dev);
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 29c8316..57f7778 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -128,9 +128,6 @@
 	void *cache;
 	u32 cache_dirty;
 
-	unsigned long *cache_present;
-	unsigned int cache_present_nbits;
-
 	struct reg_default *patch;
 	int patch_regs;
 
@@ -203,6 +200,7 @@
 			unsigned int reg, unsigned int value);
 int regcache_sync(struct regmap *map);
 int regcache_sync_block(struct regmap *map, void *block,
+			unsigned long *cache_present,
 			unsigned int block_base, unsigned int start,
 			unsigned int end);
 
@@ -218,16 +216,6 @@
 bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
 		      unsigned int val);
 int regcache_lookup_reg(struct regmap *map, unsigned int reg);
-int regcache_set_reg_present(struct regmap *map, unsigned int reg);
-
-static inline bool regcache_reg_present(struct regmap *map, unsigned int reg)
-{
-	if (!map->cache_present)
-		return true;
-	if (reg > map->cache_present_nbits)
-		return false;
-	return map->cache_present[BIT_WORD(reg)] & BIT_MASK(reg);
-}
 
 int _regmap_raw_write(struct regmap *map, unsigned int reg,
 		      const void *val, size_t val_len, bool async);
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 5c1435c..930cad4 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -29,6 +29,8 @@
 	unsigned int base_reg;
 	/* block of adjacent registers */
 	void *block;
+	/* Which registers are present */
+	long *cache_present;
 	/* number of registers available in the block */
 	unsigned int blklen;
 } __attribute__ ((packed));
@@ -57,6 +59,7 @@
 					 struct regcache_rbtree_node *rbnode,
 					 unsigned int idx, unsigned int val)
 {
+	set_bit(idx, rbnode->cache_present);
 	regcache_set_val(map, rbnode->block, idx, val);
 }
 
@@ -146,13 +149,13 @@
 	map->lock(map->lock_arg);
 
 	mem_size = sizeof(*rbtree_ctx);
-	mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
 
 	for (node = rb_first(&rbtree_ctx->root); node != NULL;
 	     node = rb_next(node)) {
 		n = container_of(node, struct regcache_rbtree_node, node);
 		mem_size += sizeof(*n);
 		mem_size += (n->blklen * map->cache_word_size);
+		mem_size += BITS_TO_LONGS(n->blklen) * sizeof(long);
 
 		regcache_rbtree_get_base_top_reg(map, n, &base, &top);
 		this_registers = ((top - base) / map->reg_stride) + 1;
@@ -245,6 +248,7 @@
 		rbtree_node = rb_entry(next, struct regcache_rbtree_node, node);
 		next = rb_next(&rbtree_node->node);
 		rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+		kfree(rbtree_node->cache_present);
 		kfree(rbtree_node->block);
 		kfree(rbtree_node);
 	}
@@ -265,7 +269,7 @@
 	rbnode = regcache_rbtree_lookup(map, reg);
 	if (rbnode) {
 		reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
-		if (!regcache_reg_present(map, reg))
+		if (!test_bit(reg_tmp, rbnode->cache_present))
 			return -ENOENT;
 		*value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
 	} else {
@@ -278,27 +282,45 @@
 
 static int regcache_rbtree_insert_to_block(struct regmap *map,
 					   struct regcache_rbtree_node *rbnode,
-					   unsigned int pos, unsigned int reg,
+					   unsigned int base_reg,
+					   unsigned int top_reg,
+					   unsigned int reg,
 					   unsigned int value)
 {
+	unsigned int blklen;
+	unsigned int pos, offset;
+	unsigned long *present;
 	u8 *blk;
 
+	blklen = (top_reg - base_reg) / map->reg_stride + 1;
+	pos = (reg - base_reg) / map->reg_stride;
+	offset = (rbnode->base_reg - base_reg) / map->reg_stride;
+
 	blk = krealloc(rbnode->block,
-		       (rbnode->blklen + 1) * map->cache_word_size,
+		       blklen * map->cache_word_size,
 		       GFP_KERNEL);
 	if (!blk)
 		return -ENOMEM;
 
+	present = krealloc(rbnode->cache_present,
+		    BITS_TO_LONGS(blklen) * sizeof(*present), GFP_KERNEL);
+	if (!present) {
+		kfree(blk);
+		return -ENOMEM;
+	}
+
 	/* insert the register value in the correct place in the rbnode block */
-	memmove(blk + (pos + 1) * map->cache_word_size,
-		blk + pos * map->cache_word_size,
-		(rbnode->blklen - pos) * map->cache_word_size);
+	if (pos == 0) {
+		memmove(blk + offset * map->cache_word_size,
+			blk, rbnode->blklen * map->cache_word_size);
+		bitmap_shift_right(present, present, offset, blklen);
+	}
 
 	/* update the rbnode block, its size and the base register */
 	rbnode->block = blk;
-	rbnode->blklen++;
-	if (!pos)
-		rbnode->base_reg = reg;
+	rbnode->blklen = blklen;
+	rbnode->base_reg = base_reg;
+	rbnode->cache_present = present;
 
 	regcache_rbtree_set_register(map, rbnode, pos, value);
 	return 0;
@@ -325,25 +347,34 @@
 
 		if (i != map->rd_table->n_yes_ranges) {
 			range = &map->rd_table->yes_ranges[i];
-			rbnode->blklen = range->range_max - range->range_min
-				+ 1;
+			rbnode->blklen = (range->range_max - range->range_min) /
+				map->reg_stride	+ 1;
 			rbnode->base_reg = range->range_min;
 		}
 	}
 
 	if (!rbnode->blklen) {
-		rbnode->blklen = sizeof(*rbnode);
+		rbnode->blklen = 1;
 		rbnode->base_reg = reg;
 	}
 
 	rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
 				GFP_KERNEL);
-	if (!rbnode->block) {
-		kfree(rbnode);
-		return NULL;
-	}
+	if (!rbnode->block)
+		goto err_free;
+
+	rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) *
+		sizeof(*rbnode->cache_present), GFP_KERNEL);
+	if (!rbnode->cache_present)
+		goto err_free_block;
 
 	return rbnode;
+
+err_free_block:
+	kfree(rbnode->block);
+err_free:
+	kfree(rbnode);
+	return NULL;
 }
 
 static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
@@ -353,15 +384,9 @@
 	struct regcache_rbtree_node *rbnode, *rbnode_tmp;
 	struct rb_node *node;
 	unsigned int reg_tmp;
-	unsigned int pos;
-	int i;
 	int ret;
 
 	rbtree_ctx = map->cache;
-	/* update the reg_present bitmap, make space if necessary */
-	ret = regcache_set_reg_present(map, reg);
-	if (ret < 0)
-		return ret;
 
 	/* if we can't locate it in the cached rbnode we'll have
 	 * to traverse the rbtree looking for it.
@@ -371,30 +396,43 @@
 		reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
 		regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
 	} else {
+		unsigned int base_reg, top_reg;
+		unsigned int new_base_reg, new_top_reg;
+		unsigned int min, max;
+		unsigned int max_dist;
+
+		max_dist = map->reg_stride * sizeof(*rbnode_tmp) /
+			map->cache_word_size;
+		if (reg < max_dist)
+			min = 0;
+		else
+			min = reg - max_dist;
+		max = reg + max_dist;
+
 		/* look for an adjacent register to the one we are about to add */
 		for (node = rb_first(&rbtree_ctx->root); node;
 		     node = rb_next(node)) {
 			rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
 					      node);
-			for (i = 0; i < rbnode_tmp->blklen; i++) {
-				reg_tmp = rbnode_tmp->base_reg +
-						(i * map->reg_stride);
-				if (abs(reg_tmp - reg) != map->reg_stride)
-					continue;
-				/* decide where in the block to place our register */
-				if (reg_tmp + map->reg_stride == reg)
-					pos = i + 1;
-				else
-					pos = i;
-				ret = regcache_rbtree_insert_to_block(map,
-								      rbnode_tmp,
-								      pos, reg,
-								      value);
-				if (ret)
-					return ret;
-				rbtree_ctx->cached_rbnode = rbnode_tmp;
-				return 0;
+
+			regcache_rbtree_get_base_top_reg(map, rbnode_tmp,
+				&base_reg, &top_reg);
+
+			if (base_reg <= max && top_reg >= min) {
+				new_base_reg = min(reg, base_reg);
+				new_top_reg = max(reg, top_reg);
+			} else {
+				continue;
 			}
+
+			ret = regcache_rbtree_insert_to_block(map, rbnode_tmp,
+							      new_base_reg,
+							      new_top_reg, reg,
+							      value);
+			if (ret)
+				return ret;
+			rbtree_ctx->cached_rbnode = rbnode_tmp;
+			return 0;
 		}
 
 		/* We did not manage to find a place to insert it in
@@ -418,30 +456,34 @@
 	struct regcache_rbtree_ctx *rbtree_ctx;
 	struct rb_node *node;
 	struct regcache_rbtree_node *rbnode;
+	unsigned int base_reg, top_reg;
+	unsigned int start, end;
 	int ret;
-	int base, end;
 
 	rbtree_ctx = map->cache;
 	for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
 		rbnode = rb_entry(node, struct regcache_rbtree_node, node);
 
-		if (rbnode->base_reg > max)
+		regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+			&top_reg);
+		if (base_reg > max)
 			break;
-		if (rbnode->base_reg + rbnode->blklen < min)
+		if (top_reg < min)
 			continue;
 
-		if (min > rbnode->base_reg)
-			base = min - rbnode->base_reg;
+		if (min > base_reg)
+			start = (min - base_reg) / map->reg_stride;
 		else
-			base = 0;
+			start = 0;
 
-		if (max < rbnode->base_reg + rbnode->blklen)
-			end = max - rbnode->base_reg + 1;
+		if (max < top_reg)
+			end = (max - base_reg) / map->reg_stride + 1;
 		else
 			end = rbnode->blklen;
 
-		ret = regcache_sync_block(map, rbnode->block, rbnode->base_reg,
-					  base, end);
+		ret = regcache_sync_block(map, rbnode->block,
+					  rbnode->cache_present,
+					  rbnode->base_reg, start, end);
 		if (ret != 0)
 			return ret;
 	}
@@ -449,6 +491,42 @@
 	return regmap_async_complete(map);
 }
 
+static int regcache_rbtree_drop(struct regmap *map, unsigned int min,
+				unsigned int max)
+{
+	struct regcache_rbtree_ctx *rbtree_ctx;
+	struct regcache_rbtree_node *rbnode;
+	struct rb_node *node;
+	unsigned int base_reg, top_reg;
+	unsigned int start, end;
+
+	rbtree_ctx = map->cache;
+	for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
+		rbnode = rb_entry(node, struct regcache_rbtree_node, node);
+
+		regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg,
+			&top_reg);
+		if (base_reg > max)
+			break;
+		if (top_reg < min)
+			continue;
+
+		if (min > base_reg)
+			start = (min - base_reg) / map->reg_stride;
+		else
+			start = 0;
+
+		if (max < top_reg)
+			end = (max - base_reg) / map->reg_stride + 1;
+		else
+			end = rbnode->blklen;
+
+		bitmap_clear(rbnode->cache_present, start, end - start);
+	}
+
+	return 0;
+}
+
 struct regcache_ops regcache_rbtree_ops = {
 	.type = REGCACHE_RBTREE,
 	.name = "rbtree",
@@ -456,5 +534,6 @@
 	.exit = regcache_rbtree_exit,
 	.read = regcache_rbtree_read,
 	.write = regcache_rbtree_write,
-	.sync = regcache_rbtree_sync
+	.sync = regcache_rbtree_sync,
+	.drop = regcache_rbtree_drop,
 };
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 3455f83..d6c2d69 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -121,8 +121,6 @@
 	map->reg_defaults_raw = config->reg_defaults_raw;
 	map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8);
 	map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw;
-	map->cache_present = NULL;
-	map->cache_present_nbits = 0;
 
 	map->cache = NULL;
 	map->cache_ops = cache_types[i];
@@ -181,7 +179,6 @@
 
 	BUG_ON(!map->cache_ops);
 
-	kfree(map->cache_present);
 	kfree(map->reg_defaults);
 	if (map->cache_free)
 		kfree(map->reg_defaults_raw);
@@ -241,9 +238,6 @@
 
 	BUG_ON(!map->cache_ops);
 
-	if (!regmap_writeable(map, reg))
-		return -EIO;
-
 	if (!regmap_volatile(map, reg))
 		return map->cache_ops->write(map, reg, value);
 
@@ -410,22 +404,16 @@
 int regcache_drop_region(struct regmap *map, unsigned int min,
 			 unsigned int max)
 {
-	unsigned int reg;
 	int ret = 0;
 
-	if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
+	if (!map->cache_ops || !map->cache_ops->drop)
 		return -EINVAL;
 
 	map->lock(map->lock_arg);
 
 	trace_regcache_drop_region(map->dev, min, max);
 
-	if (map->cache_present)
-		for (reg = min; reg < max + 1; reg++)
-			clear_bit(reg, map->cache_present);
-
-	if (map->cache_ops && map->cache_ops->drop)
-		ret = map->cache_ops->drop(map, min, max);
+	ret = map->cache_ops->drop(map, min, max);
 
 	map->unlock(map->lock_arg);
 
@@ -493,42 +481,6 @@
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
 
-int regcache_set_reg_present(struct regmap *map, unsigned int reg)
-{
-	unsigned long *cache_present;
-	unsigned int cache_present_size;
-	unsigned int nregs;
-	int i;
-
-	nregs = reg + 1;
-	cache_present_size = BITS_TO_LONGS(nregs);
-	cache_present_size *= sizeof(long);
-
-	if (!map->cache_present) {
-		cache_present = kmalloc(cache_present_size, GFP_KERNEL);
-		if (!cache_present)
-			return -ENOMEM;
-		bitmap_zero(cache_present, nregs);
-		map->cache_present = cache_present;
-		map->cache_present_nbits = nregs;
-	}
-
-	if (nregs > map->cache_present_nbits) {
-		cache_present = krealloc(map->cache_present,
-					 cache_present_size, GFP_KERNEL);
-		if (!cache_present)
-			return -ENOMEM;
-		for (i = 0; i < nregs; i++)
-			if (i >= map->cache_present_nbits)
-				clear_bit(i, cache_present);
-		map->cache_present = cache_present;
-		map->cache_present_nbits = nregs;
-	}
-
-	set_bit(reg, map->cache_present);
-	return 0;
-}
-
 bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
 		      unsigned int val)
 {
@@ -620,7 +572,16 @@
 		return -ENOENT;
 }
 
+static bool regcache_reg_present(unsigned long *cache_present, unsigned int idx)
+{
+	if (!cache_present)
+		return true;
+
+	return test_bit(idx, cache_present);
+}
+
 static int regcache_sync_block_single(struct regmap *map, void *block,
+				      unsigned long *cache_present,
 				      unsigned int block_base,
 				      unsigned int start, unsigned int end)
 {
@@ -630,7 +591,7 @@
 	for (i = start; i < end; i++) {
 		regtmp = block_base + (i * map->reg_stride);
 
-		if (!regcache_reg_present(map, regtmp))
+		if (!regcache_reg_present(cache_present, i))
 			continue;
 
 		val = regcache_get_val(map, block, i);
@@ -681,6 +642,7 @@
 }
 
 static int regcache_sync_block_raw(struct regmap *map, void *block,
+			    unsigned long *cache_present,
 			    unsigned int block_base, unsigned int start,
 			    unsigned int end)
 {
@@ -693,7 +655,7 @@
 	for (i = start; i < end; i++) {
 		regtmp = block_base + (i * map->reg_stride);
 
-		if (!regcache_reg_present(map, regtmp)) {
+		if (!regcache_reg_present(cache_present, i)) {
 			ret = regcache_sync_block_raw_flush(map, &data,
 							    base, regtmp);
 			if (ret != 0)
@@ -724,13 +686,14 @@
 }
 
 int regcache_sync_block(struct regmap *map, void *block,
+			unsigned long *cache_present,
 			unsigned int block_base, unsigned int start,
 			unsigned int end)
 {
 	if (regmap_can_raw_write(map))
-		return regcache_sync_block_raw(map, block, block_base,
-					       start, end);
+		return regcache_sync_block_raw(map, block, cache_present,
+					       block_base, start, end);
 	else
-		return regcache_sync_block_single(map, block, block_base,
-						  start, end);
+		return regcache_sync_block_single(map, block, cache_present,
+						  block_base, start, end);
 }
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 5349575..de11eca 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -85,8 +85,8 @@
 	unsigned int reg_offset;
 
 	/* Suppress the cache if we're using a subrange */
-	if (from)
-		return from;
+	if (base)
+		return base;
 
 	/*
 	 * If we don't have a cache build one so we don't have to do a
@@ -281,7 +281,7 @@
 	reg = simple_strtoul(start, &start, 16);
 	while (*start == ' ')
 		start++;
-	if (strict_strtoul(start, 16, &value))
+	if (kstrtoul(start, 16, &value))
 		return -EINVAL;
 
 	/* Userspace has been fiddling around behind the kernel's back */
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 1643e88..d10456f 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -418,6 +418,31 @@
 				reg, ret);
 			goto err_alloc;
 		}
+
+		if (!chip->init_ack_masked)
+			continue;
+
+		/* Ack masked but set interrupts */
+		reg = chip->status_base +
+			(i * map->reg_stride * d->irq_reg_stride);
+		ret = regmap_read(map, reg, &d->status_buf[i]);
+		if (ret != 0) {
+			dev_err(map->dev, "Failed to read IRQ status: %d\n",
+				ret);
+			goto err_alloc;
+		}
+
+		if (d->status_buf[i] && chip->ack_base) {
+			reg = chip->ack_base +
+				(i * map->reg_stride * d->irq_reg_stride);
+			ret = regmap_write(map, reg,
+					d->status_buf[i] & d->mask_buf[i]);
+			if (ret != 0) {
+				dev_err(map->dev, "Failed to ack 0x%x: %d\n",
+					reg, ret);
+				goto err_alloc;
+			}
+		}
 	}
 
 	/* Wake is disabled by default */
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index e0d0c7d..7d689a1 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -303,6 +303,7 @@
 }
 
 static void regmap_lock_spinlock(void *__map)
+__acquires(&map->spinlock)
 {
 	struct regmap *map = __map;
 	unsigned long flags;
@@ -312,6 +313,7 @@
 }
 
 static void regmap_unlock_spinlock(void *__map)
+__releases(&map->spinlock)
 {
 	struct regmap *map = __map;
 	spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
@@ -687,6 +689,10 @@
 			unsigned win_max = win_min +
 					   config->ranges[j].window_len - 1;
 
+			/* Allow data window inside its own virtual range */
+			if (j == i)
+				continue;
+
 			if (range_cfg->range_min <= sel_reg &&
 			    sel_reg <= range_cfg->range_max) {
 				dev_err(map->dev,
@@ -1261,6 +1267,9 @@
 	int ret;
 	void *context = _regmap_map_get_context(map);
 
+	if (!regmap_writeable(map, reg))
+		return -EIO;
+
 	if (!map->cache_bypass && !map->defer_caching) {
 		ret = regcache_write(map, reg, val);
 		if (ret != 0)
@@ -1888,13 +1897,10 @@
 int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
 			  int num_regs)
 {
+	struct reg_default *p;
 	int i, ret;
 	bool bypass;
 
-	/* If needed the implementation can be extended to support this */
-	if (map->patch)
-		return -EBUSY;
-
 	map->lock(map->lock_arg);
 
 	bypass = map->cache_bypass;
@@ -1911,11 +1917,13 @@
 		}
 	}
 
-	map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
-	if (map->patch != NULL) {
-		memcpy(map->patch, regs,
-		       num_regs * sizeof(struct reg_default));
-		map->patch_regs = num_regs;
+	p = krealloc(map->patch,
+		     sizeof(struct reg_default) * (map->patch_regs + num_regs),
+		     GFP_KERNEL);
+	if (p) {
+		memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
+		map->patch = p;
+		map->patch_regs += num_regs;
 	} else {
 		ret = -ENOMEM;
 	}
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 2f5919e..94ffee3 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -62,25 +62,6 @@
 }
 #endif
 
-#ifdef arch_provides_topology_pointers
-#define define_siblings_show_map(name)					\
-static ssize_t show_##name(struct device *dev,				\
-			   struct device_attribute *attr, char *buf)	\
-{									\
-	unsigned int cpu = dev->id;					\
-	return show_cpumap(0, topology_##name(cpu), buf);		\
-}
-
-#define define_siblings_show_list(name)					\
-static ssize_t show_##name##_list(struct device *dev,			\
-				  struct device_attribute *attr,	\
-				  char *buf)				\
-{									\
-	unsigned int cpu = dev->id;					\
-	return show_cpumap(1, topology_##name(cpu), buf);		\
-}
-
-#else
 #define define_siblings_show_map(name)					\
 static ssize_t show_##name(struct device *dev,				\
 			   struct device_attribute *attr, char *buf)	\
@@ -95,7 +76,6 @@
 {									\
 	return show_cpumap(1, topology_##name(dev->id), buf);		\
 }
-#endif
 
 #define define_siblings_show_func(name)		\
 	define_siblings_show_map(name); define_siblings_show_list(name)
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 4ad2ad9..191cd17 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -397,15 +397,19 @@
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping);
 static void rbd_spec_put(struct rbd_spec *spec);
 
-static struct bus_attribute rbd_bus_attrs[] = {
-	__ATTR(add, S_IWUSR, NULL, rbd_add),
-	__ATTR(remove, S_IWUSR, NULL, rbd_remove),
-	__ATTR_NULL
+static BUS_ATTR(add, S_IWUSR, NULL, rbd_add);
+static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove);
+
+static struct attribute *rbd_bus_attrs[] = {
+	&bus_attr_add.attr,
+	&bus_attr_remove.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(rbd_bus);
 
 static struct bus_type rbd_bus_type = {
 	.name		= "rbd",
-	.bus_attrs	= rbd_bus_attrs,
+	.bus_groups	= rbd_bus_groups,
 };
 
 static void rbd_root_dev_release(struct device *dev)
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 7332889..2009266 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -122,17 +122,8 @@
 
 static void __init cci_ace_init_ports(void)
 {
-	int port, ac, cpu;
-	u64 hwid;
-	const u32 *cell;
-	struct device_node *cpun, *cpus;
-
-	cpus = of_find_node_by_path("/cpus");
-	if (WARN(!cpus, "Missing cpus node, bailing out\n"))
-		return;
-
-	if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac)))
-		ac = of_n_addr_cells(cpus);
+	int port, cpu;
+	struct device_node *cpun;
 
 	/*
 	 * Port index look-up speeds up the function disabling ports by CPU,
@@ -141,18 +132,13 @@
 	 * The stashed index array is initialized for all possible CPUs
 	 * at probe time.
 	 */
-	for_each_child_of_node(cpus, cpun) {
-		if (of_node_cmp(cpun->type, "cpu"))
-			continue;
-		cell = of_get_property(cpun, "reg", NULL);
-		if (WARN(!cell, "%s: missing reg property\n", cpun->full_name))
+	for_each_possible_cpu(cpu) {
+		/* too early to use cpu->of_node */
+		cpun = of_get_cpu_node(cpu, NULL);
+
+		if (WARN(!cpun, "Missing cpu device node\n"))
 			continue;
 
-		hwid = of_read_number(cell, ac);
-		cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK);
-
-		if (cpu < 0 || !cpu_possible(cpu))
-			continue;
 		port = __cci_ace_get_port(cpun, ACE_PORT);
 		if (port < 0)
 			continue;
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 9746705..0671e45 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -95,6 +95,7 @@
 	struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
 	return sprintf(buf, "%u\n", bsr_dev->bsr_bytes);
 }
+static DEVICE_ATTR_RO(bsr_size);
 
 static ssize_t
 bsr_stride_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -102,20 +103,23 @@
 	struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
 	return sprintf(buf, "%u\n", bsr_dev->bsr_stride);
 }
+static DEVICE_ATTR_RO(bsr_stride);
 
 static ssize_t
-bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf)
+bsr_length_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
 	return sprintf(buf, "%llu\n", bsr_dev->bsr_len);
 }
+static DEVICE_ATTR_RO(bsr_length);
 
-static struct device_attribute bsr_dev_attrs[] = {
-	__ATTR(bsr_size, S_IRUGO, bsr_size_show, NULL),
-	__ATTR(bsr_stride, S_IRUGO, bsr_stride_show, NULL),
-	__ATTR(bsr_length, S_IRUGO, bsr_len_show, NULL),
-	__ATTR_NULL
+static struct attribute *bsr_dev_attrs[] = {
+	&dev_attr_bsr_size.attr,
+	&dev_attr_bsr_stride.attr,
+	&dev_attr_bsr_length.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(bsr_dev);
 
 static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
 {
@@ -308,7 +312,7 @@
 		ret = PTR_ERR(bsr_class);
 		goto out_err_1;
 	}
-	bsr_class->dev_attrs = bsr_dev_attrs;
+	bsr_class->dev_groups = bsr_dev_groups;
 
 	ret = alloc_chrdev_region(&bsr_dev, 0, BSR_MAX_DEVS, "bsr");
 	bsr_major = MAJOR(bsr_dev);
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index d5a5f02..ec318bf 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -810,6 +810,7 @@
 		struct ipmi_recv   __user *precv64;
 		struct ipmi_recv   recv64;
 
+		memset(&recv64, 0, sizeof(recv64));
 		if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
 			return -EFAULT;
 
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 4445fa1..ec4e10f 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -1848,7 +1848,7 @@
 			 int              retries,
 			 unsigned int     retry_time_ms)
 {
-	unsigned char saddr, lun;
+	unsigned char saddr = 0, lun = 0;
 	int           rv;
 
 	if (!user)
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index af4b23f..15e4a60 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -71,6 +71,11 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 
+#ifdef CONFIG_PARISC
+#include <asm/hardware.h>	/* for register_parisc_driver() stuff */
+#include <asm/parisc-device.h>
+#endif
+
 #define PFX "ipmi_si: "
 
 /* Measure times between events in the driver. */
@@ -298,6 +303,9 @@
 #ifdef CONFIG_ACPI
 static int pnp_registered;
 #endif
+#ifdef CONFIG_PARISC
+static int parisc_registered;
+#endif
 
 static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
 static int num_max_busy_us;
@@ -2279,6 +2287,8 @@
 	.remove		= ipmi_pnp_remove,
 	.id_table	= pnp_dev_table,
 };
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
 #endif
 
 #ifdef CONFIG_DMI
@@ -2697,6 +2707,62 @@
 	.remove		= ipmi_remove,
 };
 
+#ifdef CONFIG_PARISC
+static int ipmi_parisc_probe(struct parisc_device *dev)
+{
+	struct smi_info *info;
+
+	info = smi_info_alloc();
+
+	if (!info) {
+		dev_err(&dev->dev,
+			"could not allocate memory for PARISC probe\n");
+		return -ENOMEM;
+	}
+
+	info->si_type		= SI_KCS;
+	info->addr_source	= SI_DEVICETREE;
+	info->io_setup		= mem_setup;
+	info->io.addr_type	= IPMI_MEM_ADDR_SPACE;
+	info->io.addr_data	= dev->hpa.start;
+	info->io.regsize	= 1;
+	info->io.regspacing	= 1;
+	info->io.regshift	= 0;
+	info->irq		= 0; /* no interrupt */
+	info->irq_setup		= NULL;
+	info->dev		= &dev->dev;
+
+	dev_dbg(&dev->dev, "addr 0x%lx\n", info->io.addr_data);
+
+	dev_set_drvdata(&dev->dev, info);
+
+	if (add_smi(info)) {
+		kfree(info);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int ipmi_parisc_remove(struct parisc_device *dev)
+{
+	cleanup_one_si(dev_get_drvdata(&dev->dev));
+	return 0;
+}
+
+static struct parisc_device_id ipmi_parisc_tbl[] = {
+	{ HPHW_MC, HVERSION_REV_ANY_ID, 0x004, 0xC0 },
+	{ 0, }
+};
+
+static struct parisc_driver ipmi_parisc_driver = {
+	.name =		"ipmi",
+	.id_table =	ipmi_parisc_tbl,
+	.probe =	ipmi_parisc_probe,
+	.remove =	ipmi_parisc_remove,
+};
+#endif /* CONFIG_PARISC */
+
 static int wait_for_msg_done(struct smi_info *smi_info)
 {
 	enum si_sm_result     smi_result;
@@ -3462,6 +3528,13 @@
 		spmi_find_bmc();
 #endif
 
+#ifdef CONFIG_PARISC
+	register_parisc_driver(&ipmi_parisc_driver);
+	parisc_registered = 1;
+	/* poking PC IO addresses will crash machine, don't do it */
+	si_trydefaults = 0;
+#endif
+
 	/* We prefer devices with interrupts, but in the case of a machine
 	   with multiple BMCs we assume that there will be several instances
 	   of a given type so if we succeed in registering a type then also
@@ -3608,6 +3681,10 @@
 	if (pnp_registered)
 		pnp_unregister_driver(&ipmi_pnp_driver);
 #endif
+#ifdef CONFIG_PARISC
+	if (parisc_registered)
+		unregister_parisc_driver(&ipmi_parisc_driver);
+#endif
 
 	platform_driver_unregister(&ipmi_driver);
 
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 5c5cc00..d39cca6 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1182,14 +1182,14 @@
 		}
 		count++;
 
-		if (gis & (BIT1 + BIT0)) {
+		if (gis & (BIT1 | BIT0)) {
 			isr = read_reg16(info, CHB + ISR);
 			if (isr & IRQ_DCD)
 				dcd_change(info, tty);
 			if (isr & IRQ_CTS)
 				cts_change(info, tty);
 		}
-		if (gis & (BIT3 + BIT2))
+		if (gis & (BIT3 | BIT2))
 		{
 			isr = read_reg16(info, CHA + ISR);
 			if (isr & IRQ_TIMER) {
@@ -1210,7 +1210,7 @@
 			if (isr & IRQ_RXTIME) {
 				issue_command(info, CHA, CMD_RXFIFO_READ);
 			}
-			if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) {
+			if (isr & (IRQ_RXEOM | IRQ_RXFIFO)) {
 				if (info->params.mode == MGSL_MODE_HDLC)
 					rx_ready_hdlc(info, isr & IRQ_RXEOM);
 				else
@@ -3031,11 +3031,11 @@
 	unsigned char val;
 
 	/* CCR1:02..00  CM[2..0] Clock Mode = 111 (clock mode 7) */
-	val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0);
+	val = read_reg(info, CHA + CCR1) | (BIT2 | BIT1 | BIT0);
 	write_reg(info, CHA + CCR1, val);
 
 	/* CCR2:04 SSEL Clock source select, 1=submode b */
-	val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5);
+	val = read_reg(info, CHA + CCR2) | (BIT4 | BIT5);
 	write_reg(info, CHA + CCR2, val);
 
 	/* set LinkSpeed if available, otherwise default to 2Mbps */
@@ -3125,10 +3125,10 @@
 		val |= BIT4;
 		break;		// FM0
 	case HDLC_ENCODING_BIPHASE_MARK:
-		val |= BIT4 + BIT2;
+		val |= BIT4 | BIT2;
 		break;		// FM1
 	case HDLC_ENCODING_BIPHASE_LEVEL:
-		val |= BIT4 + BIT3;
+		val |= BIT4 | BIT3;
 		break;		// Manchester
 	}
 	write_reg(info, CHA + CCR0, val);
@@ -3185,7 +3185,7 @@
 	 */
 	val = 0x00;
 	if (info->params.crc_type == HDLC_CRC_NONE)
-		val |= BIT2 + BIT1;
+		val |= BIT2 | BIT1;
 	if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE)
 		val |= BIT5;
 	switch (info->params.preamble_length)
@@ -3197,7 +3197,7 @@
 		val |= BIT6;
 		break;
 	case HDLC_PREAMBLE_LENGTH_64BITS:
-		val |= BIT7 + BIT6;
+		val |= BIT7 | BIT6;
 		break;
 	}
 	write_reg(info, CHA + CCR3, val);
@@ -3264,8 +3264,8 @@
 		clear_reg_bits(info, CHA + PVR, BIT3);
 
 	irq_enable(info, CHA,
-			 IRQ_RXEOM + IRQ_RXFIFO + IRQ_ALLSENT +
-			 IRQ_UNDERRUN + IRQ_TXFIFO);
+			 IRQ_RXEOM | IRQ_RXFIFO | IRQ_ALLSENT |
+			 IRQ_UNDERRUN | IRQ_TXFIFO);
 	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
 	wait_command_complete(info, CHA);
 	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
@@ -3582,8 +3582,8 @@
 	} else
 		clear_reg_bits(info, CHA + PVR, BIT3);
 	irq_enable(info, CHA,
-			  IRQ_RXEOM + IRQ_RXFIFO + IRQ_BREAK_ON + IRQ_RXTIME +
-			  IRQ_ALLSENT + IRQ_TXFIFO);
+			  IRQ_RXEOM | IRQ_RXFIFO | IRQ_BREAK_ON | IRQ_RXTIME |
+			  IRQ_ALLSENT | IRQ_TXFIFO);
 	issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
 	wait_command_complete(info, CHA);
 	read_reg16(info, CHA + ISR);	/* clear pending IRQs */
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index bf2349db..7cc1fe22 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -876,11 +876,6 @@
 	if (useinput)
 		sonypi_report_input_event(event);
 
-#ifdef CONFIG_ACPI
-	if (sonypi_acpi_device)
-		acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
-#endif
-
 	kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
 			sizeof(event), &sonypi_device.fifo_lock);
 	kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
index 7faeb1c..0e506ba 100644
--- a/drivers/char/tile-srom.c
+++ b/drivers/char/tile-srom.c
@@ -279,33 +279,37 @@
 	return fixed_size_llseek(file, offset, origin, srom->total_size);
 }
 
-static ssize_t total_show(struct device *dev,
-			  struct device_attribute *attr, char *buf)
+static ssize_t total_size_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct srom_dev *srom = dev_get_drvdata(dev);
 	return sprintf(buf, "%u\n", srom->total_size);
 }
+static DEVICE_ATTR_RO(total_size);
 
-static ssize_t sector_show(struct device *dev,
-			   struct device_attribute *attr, char *buf)
+static ssize_t sector_size_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct srom_dev *srom = dev_get_drvdata(dev);
 	return sprintf(buf, "%u\n", srom->sector_size);
 }
+static DEVICE_ATTR_RO(sector_size);
 
-static ssize_t page_show(struct device *dev,
-			 struct device_attribute *attr, char *buf)
+static ssize_t page_size_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct srom_dev *srom = dev_get_drvdata(dev);
 	return sprintf(buf, "%u\n", srom->page_size);
 }
+static DEVICE_ATTR_RO(page_size);
 
-static struct device_attribute srom_dev_attrs[] = {
-	__ATTR(total_size, S_IRUGO, total_show, NULL),
-	__ATTR(sector_size, S_IRUGO, sector_show, NULL),
-	__ATTR(page_size, S_IRUGO, page_show, NULL),
-	__ATTR_NULL
+static struct attribute *srom_dev_attrs[] = {
+	&dev_attr_total_size.attr,
+	&dev_attr_sector_size.attr,
+	&dev_attr_page_size.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(srom_dev);
 
 static char *srom_devnode(struct device *dev, umode_t *mode)
 {
@@ -349,7 +353,7 @@
 
 	dev = device_create(srom_class, &platform_bus,
 			    MKDEV(srom_major, index), srom, "%d", index);
-	return PTR_RET(dev);
+	return PTR_ERR_OR_ZERO(dev);
 }
 
 /** srom_init() - Initialize the driver's module. */
@@ -418,7 +422,7 @@
 		result = PTR_ERR(srom_class);
 		goto fail_cdev;
 	}
-	srom_class->dev_attrs = srom_dev_attrs;
+	srom_class->dev_groups = srom_dev_groups;
 	srom_class->devnode = srom_devnode;
 
 	/* Do per-partition initialization */
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index dbfd564..94c0c74 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -91,4 +91,16 @@
         To compile this driver as a module, choose M here; the module will be
         called tpm_stm_st33_i2c.
 
+config TCG_XEN
+	tristate "XEN TPM Interface"
+	depends on TCG_TPM && XEN
+	select XEN_XENBUS_FRONTEND
+	---help---
+	  If you want to make TPM support available to a Xen user domain,
+	  say Yes and it will be accessible from within Linux. See
+	  the manpages for xl, xl.conf, and docs/misc/vtpm.txt in
+	  the Xen source repository for more details.
+	  To compile this driver as a module, choose M here; the module
+	  will be called xen-tpmfront.
+
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index a3736c9..eb41ff9 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -18,3 +18,4 @@
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
 obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
 obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
+obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
new file mode 100644
index 0000000..7a7929b
--- /dev/null
+++ b/drivers/char/tpm/xen-tpmfront.c
@@ -0,0 +1,473 @@
+/*
+ * Implementation of the Xen vTPM device frontend
+ *
+ * Author:  Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * 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/errno.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <xen/events.h>
+#include <xen/interface/io/tpmif.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+#include <xen/page.h>
+#include "tpm.h"
+
+struct tpm_private {
+	struct tpm_chip *chip;
+	struct xenbus_device *dev;
+
+	struct vtpm_shared_page *shr;
+
+	unsigned int evtchn;
+	int ring_ref;
+	domid_t backend_id;
+};
+
+enum status_bits {
+	VTPM_STATUS_RUNNING  = 0x1,
+	VTPM_STATUS_IDLE     = 0x2,
+	VTPM_STATUS_RESULT   = 0x4,
+	VTPM_STATUS_CANCELED = 0x8,
+};
+
+static u8 vtpm_status(struct tpm_chip *chip)
+{
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	switch (priv->shr->state) {
+	case VTPM_STATE_IDLE:
+		return VTPM_STATUS_IDLE | VTPM_STATUS_CANCELED;
+	case VTPM_STATE_FINISH:
+		return VTPM_STATUS_IDLE | VTPM_STATUS_RESULT;
+	case VTPM_STATE_SUBMIT:
+	case VTPM_STATE_CANCEL: /* cancel requested, not yet canceled */
+		return VTPM_STATUS_RUNNING;
+	default:
+		return 0;
+	}
+}
+
+static bool vtpm_req_canceled(struct tpm_chip *chip, u8 status)
+{
+	return status & VTPM_STATUS_CANCELED;
+}
+
+static void vtpm_cancel(struct tpm_chip *chip)
+{
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	priv->shr->state = VTPM_STATE_CANCEL;
+	wmb();
+	notify_remote_via_evtchn(priv->evtchn);
+}
+
+static unsigned int shr_data_offset(struct vtpm_shared_page *shr)
+{
+	return sizeof(*shr) + sizeof(u32) * shr->nr_extra_pages;
+}
+
+static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	struct vtpm_shared_page *shr = priv->shr;
+	unsigned int offset = shr_data_offset(shr);
+
+	u32 ordinal;
+	unsigned long duration;
+
+	if (offset > PAGE_SIZE)
+		return -EINVAL;
+
+	if (offset + count > PAGE_SIZE)
+		return -EINVAL;
+
+	/* Wait for completion of any existing command or cancellation */
+	if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->vendor.timeout_c,
+			&chip->vendor.read_queue, true) < 0) {
+		vtpm_cancel(chip);
+		return -ETIME;
+	}
+
+	memcpy(offset + (u8 *)shr, buf, count);
+	shr->length = count;
+	barrier();
+	shr->state = VTPM_STATE_SUBMIT;
+	wmb();
+	notify_remote_via_evtchn(priv->evtchn);
+
+	ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal);
+	duration = tpm_calc_ordinal_duration(chip, ordinal);
+
+	if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration,
+			&chip->vendor.read_queue, true) < 0) {
+		/* got a signal or timeout, try to cancel */
+		vtpm_cancel(chip);
+		return -ETIME;
+	}
+
+	return count;
+}
+
+static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	struct vtpm_shared_page *shr = priv->shr;
+	unsigned int offset = shr_data_offset(shr);
+	size_t length = shr->length;
+
+	if (shr->state == VTPM_STATE_IDLE)
+		return -ECANCELED;
+
+	/* In theory the wait at the end of _send makes this one unnecessary */
+	if (wait_for_tpm_stat(chip, VTPM_STATUS_RESULT, chip->vendor.timeout_c,
+			&chip->vendor.read_queue, true) < 0) {
+		vtpm_cancel(chip);
+		return -ETIME;
+	}
+
+	if (offset > PAGE_SIZE)
+		return -EIO;
+
+	if (offset + length > PAGE_SIZE)
+		length = PAGE_SIZE - offset;
+
+	if (length > count)
+		length = count;
+
+	memcpy(buf, offset + (u8 *)shr, length);
+
+	return length;
+}
+
+ssize_t tpm_show_locality(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	u8 locality = priv->shr->locality;
+
+	return sprintf(buf, "%d\n", locality);
+}
+
+ssize_t tpm_store_locality(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t len)
+{
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	u8 val;
+
+	int rv = kstrtou8(buf, 0, &val);
+	if (rv)
+		return rv;
+
+	priv->shr->locality = val;
+
+	return len;
+}
+
+static const struct file_operations vtpm_ops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = tpm_open,
+	.read = tpm_read,
+	.write = tpm_write,
+	.release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
+		NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
+static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
+static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
+static DEVICE_ATTR(locality, S_IRUGO | S_IWUSR, tpm_show_locality,
+		tpm_store_locality);
+
+static struct attribute *vtpm_attrs[] = {
+	&dev_attr_pubek.attr,
+	&dev_attr_pcrs.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_active.attr,
+	&dev_attr_owned.attr,
+	&dev_attr_temp_deactivated.attr,
+	&dev_attr_caps.attr,
+	&dev_attr_cancel.attr,
+	&dev_attr_durations.attr,
+	&dev_attr_timeouts.attr,
+	&dev_attr_locality.attr,
+	NULL,
+};
+
+static struct attribute_group vtpm_attr_grp = {
+	.attrs = vtpm_attrs,
+};
+
+#define TPM_LONG_TIMEOUT   (10 * 60 * HZ)
+
+static const struct tpm_vendor_specific tpm_vtpm = {
+	.status = vtpm_status,
+	.recv = vtpm_recv,
+	.send = vtpm_send,
+	.cancel = vtpm_cancel,
+	.req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
+	.req_complete_val  = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
+	.req_canceled      = vtpm_req_canceled,
+	.attr_group = &vtpm_attr_grp,
+	.miscdev = {
+		.fops = &vtpm_ops,
+	},
+	.duration = {
+		TPM_LONG_TIMEOUT,
+		TPM_LONG_TIMEOUT,
+		TPM_LONG_TIMEOUT,
+	},
+};
+
+static irqreturn_t tpmif_interrupt(int dummy, void *dev_id)
+{
+	struct tpm_private *priv = dev_id;
+
+	switch (priv->shr->state) {
+	case VTPM_STATE_IDLE:
+	case VTPM_STATE_FINISH:
+		wake_up_interruptible(&priv->chip->vendor.read_queue);
+		break;
+	case VTPM_STATE_SUBMIT:
+	case VTPM_STATE_CANCEL:
+	default:
+		break;
+	}
+	return IRQ_HANDLED;
+}
+
+static int setup_chip(struct device *dev, struct tpm_private *priv)
+{
+	struct tpm_chip *chip;
+
+	chip = tpm_register_hardware(dev, &tpm_vtpm);
+	if (!chip)
+		return -ENODEV;
+
+	init_waitqueue_head(&chip->vendor.read_queue);
+
+	priv->chip = chip;
+	TPM_VPRIV(chip) = priv;
+
+	return 0;
+}
+
+/* caller must clean up in case of errors */
+static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
+{
+	struct xenbus_transaction xbt;
+	const char *message = NULL;
+	int rv;
+
+	priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+	if (!priv->shr) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+		return -ENOMEM;
+	}
+
+	rv = xenbus_grant_ring(dev, virt_to_mfn(priv->shr));
+	if (rv < 0)
+		return rv;
+
+	priv->ring_ref = rv;
+
+	rv = xenbus_alloc_evtchn(dev, &priv->evtchn);
+	if (rv)
+		return rv;
+
+	rv = bind_evtchn_to_irqhandler(priv->evtchn, tpmif_interrupt, 0,
+				       "tpmif", priv);
+	if (rv <= 0) {
+		xenbus_dev_fatal(dev, rv, "allocating TPM irq");
+		return rv;
+	}
+	priv->chip->vendor.irq = rv;
+
+ again:
+	rv = xenbus_transaction_start(&xbt);
+	if (rv) {
+		xenbus_dev_fatal(dev, rv, "starting transaction");
+		return rv;
+	}
+
+	rv = xenbus_printf(xbt, dev->nodename,
+			"ring-ref", "%u", priv->ring_ref);
+	if (rv) {
+		message = "writing ring-ref";
+		goto abort_transaction;
+	}
+
+	rv = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+			priv->evtchn);
+	if (rv) {
+		message = "writing event-channel";
+		goto abort_transaction;
+	}
+
+	rv = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1");
+	if (rv) {
+		message = "writing feature-protocol-v2";
+		goto abort_transaction;
+	}
+
+	rv = xenbus_transaction_end(xbt, 0);
+	if (rv == -EAGAIN)
+		goto again;
+	if (rv) {
+		xenbus_dev_fatal(dev, rv, "completing transaction");
+		return rv;
+	}
+
+	xenbus_switch_state(dev, XenbusStateInitialised);
+
+	return 0;
+
+ abort_transaction:
+	xenbus_transaction_end(xbt, 1);
+	if (message)
+		xenbus_dev_error(dev, rv, "%s", message);
+
+	return rv;
+}
+
+static void ring_free(struct tpm_private *priv)
+{
+	if (!priv)
+		return;
+
+	if (priv->ring_ref)
+		gnttab_end_foreign_access(priv->ring_ref, 0,
+				(unsigned long)priv->shr);
+	else
+		free_page((unsigned long)priv->shr);
+
+	if (priv->chip && priv->chip->vendor.irq)
+		unbind_from_irqhandler(priv->chip->vendor.irq, priv);
+
+	kfree(priv);
+}
+
+static int tpmfront_probe(struct xenbus_device *dev,
+		const struct xenbus_device_id *id)
+{
+	struct tpm_private *priv;
+	int rv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating priv structure");
+		return -ENOMEM;
+	}
+
+	rv = setup_chip(&dev->dev, priv);
+	if (rv) {
+		kfree(priv);
+		return rv;
+	}
+
+	rv = setup_ring(dev, priv);
+	if (rv) {
+		tpm_remove_hardware(&dev->dev);
+		ring_free(priv);
+		return rv;
+	}
+
+	tpm_get_timeouts(priv->chip);
+
+	dev_set_drvdata(&dev->dev, priv->chip);
+
+	return rv;
+}
+
+static int tpmfront_remove(struct xenbus_device *dev)
+{
+	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
+	struct tpm_private *priv = TPM_VPRIV(chip);
+	tpm_remove_hardware(&dev->dev);
+	ring_free(priv);
+	TPM_VPRIV(chip) = NULL;
+	return 0;
+}
+
+static int tpmfront_resume(struct xenbus_device *dev)
+{
+	/* A suspend/resume/migrate will interrupt a vTPM anyway */
+	tpmfront_remove(dev);
+	return tpmfront_probe(dev, NULL);
+}
+
+static void backend_changed(struct xenbus_device *dev,
+		enum xenbus_state backend_state)
+{
+	int val;
+
+	switch (backend_state) {
+	case XenbusStateInitialised:
+	case XenbusStateConnected:
+		if (dev->state == XenbusStateConnected)
+			break;
+
+		if (xenbus_scanf(XBT_NIL, dev->otherend,
+				"feature-protocol-v2", "%d", &val) < 0)
+			val = 0;
+		if (!val) {
+			xenbus_dev_fatal(dev, -EINVAL,
+					"vTPM protocol 2 required");
+			return;
+		}
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+	case XenbusStateClosed:
+		device_unregister(&dev->dev);
+		xenbus_frontend_closed(dev);
+		break;
+	default:
+		break;
+	}
+}
+
+static const struct xenbus_device_id tpmfront_ids[] = {
+	{ "vtpm" },
+	{ "" }
+};
+MODULE_ALIAS("xen:vtpm");
+
+static DEFINE_XENBUS_DRIVER(tpmfront, ,
+		.probe = tpmfront_probe,
+		.remove = tpmfront_remove,
+		.resume = tpmfront_resume,
+		.otherend_changed = backend_changed,
+	);
+
+static int __init xen_tpmfront_init(void)
+{
+	if (!xen_domain())
+		return -ENODEV;
+
+	return xenbus_register_frontend(&tpmfront_driver);
+}
+module_init(xen_tpmfront_init);
+
+static void __exit xen_tpmfront_exit(void)
+{
+	xenbus_unregister_driver(&tpmfront_driver);
+}
+module_exit(xen_tpmfront_exit);
+
+MODULE_AUTHOR("Daniel De Graaf <dgdegra@tycho.nsa.gov>");
+MODULE_DESCRIPTION("Xen vTPM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8b00c5c..704d6d3 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -18,6 +18,7 @@
 obj-$(CONFIG_ORION_TIMER)	+= time-orion.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_ARCH_MARCO)	+= timer-marco.o
+obj-$(CONFIG_ARCH_MOXART)	+= moxart_timer.o
 obj-$(CONFIG_ARCH_MXS)		+= mxs_timer.o
 obj-$(CONFIG_ARCH_PRIMA2)	+= timer-prima2.o
 obj-$(CONFIG_SUN4I_TIMER)	+= sun4i_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index ffadd83..fbd9ccd 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -16,13 +16,39 @@
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
 #include <linux/of_irq.h>
+#include <linux/of_address.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include <asm/arch_timer.h>
 #include <asm/virt.h>
 
 #include <clocksource/arm_arch_timer.h>
 
+#define CNTTIDR		0x08
+#define CNTTIDR_VIRT(n)	(BIT(1) << ((n) * 4))
+
+#define CNTVCT_LO	0x08
+#define CNTVCT_HI	0x0c
+#define CNTFRQ		0x10
+#define CNTP_TVAL	0x28
+#define CNTP_CTL	0x2c
+#define CNTV_TVAL	0x38
+#define CNTV_CTL	0x3c
+
+#define ARCH_CP15_TIMER	BIT(0)
+#define ARCH_MEM_TIMER	BIT(1)
+static unsigned arch_timers_present __initdata;
+
+static void __iomem *arch_counter_base;
+
+struct arch_timer {
+	void __iomem *base;
+	struct clock_event_device evt;
+};
+
+#define to_arch_timer(e) container_of(e, struct arch_timer, evt)
+
 static u32 arch_timer_rate;
 
 enum ppi_nr {
@@ -38,19 +64,83 @@
 static struct clock_event_device __percpu *arch_timer_evt;
 
 static bool arch_timer_use_virtual = true;
+static bool arch_timer_mem_use_virtual;
 
 /*
  * Architected system timer support.
  */
 
-static inline irqreturn_t timer_handler(const int access,
+static __always_inline
+void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val,
+			  struct clock_event_device *clk)
+{
+	if (access == ARCH_TIMER_MEM_PHYS_ACCESS) {
+		struct arch_timer *timer = to_arch_timer(clk);
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			writel_relaxed(val, timer->base + CNTP_CTL);
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			writel_relaxed(val, timer->base + CNTP_TVAL);
+			break;
+		}
+	} else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) {
+		struct arch_timer *timer = to_arch_timer(clk);
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			writel_relaxed(val, timer->base + CNTV_CTL);
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			writel_relaxed(val, timer->base + CNTV_TVAL);
+			break;
+		}
+	} else {
+		arch_timer_reg_write_cp15(access, reg, val);
+	}
+}
+
+static __always_inline
+u32 arch_timer_reg_read(int access, enum arch_timer_reg reg,
+			struct clock_event_device *clk)
+{
+	u32 val;
+
+	if (access == ARCH_TIMER_MEM_PHYS_ACCESS) {
+		struct arch_timer *timer = to_arch_timer(clk);
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			val = readl_relaxed(timer->base + CNTP_CTL);
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			val = readl_relaxed(timer->base + CNTP_TVAL);
+			break;
+		}
+	} else if (access == ARCH_TIMER_MEM_VIRT_ACCESS) {
+		struct arch_timer *timer = to_arch_timer(clk);
+		switch (reg) {
+		case ARCH_TIMER_REG_CTRL:
+			val = readl_relaxed(timer->base + CNTV_CTL);
+			break;
+		case ARCH_TIMER_REG_TVAL:
+			val = readl_relaxed(timer->base + CNTV_TVAL);
+			break;
+		}
+	} else {
+		val = arch_timer_reg_read_cp15(access, reg);
+	}
+
+	return val;
+}
+
+static __always_inline irqreturn_t timer_handler(const int access,
 					struct clock_event_device *evt)
 {
 	unsigned long ctrl;
-	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+
+	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt);
 	if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
 		ctrl |= ARCH_TIMER_CTRL_IT_MASK;
-		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt);
 		evt->event_handler(evt);
 		return IRQ_HANDLED;
 	}
@@ -72,15 +162,30 @@
 	return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt);
 }
 
-static inline void timer_set_mode(const int access, int mode)
+static irqreturn_t arch_timer_handler_phys_mem(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	return timer_handler(ARCH_TIMER_MEM_PHYS_ACCESS, evt);
+}
+
+static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt);
+}
+
+static __always_inline void timer_set_mode(const int access, int mode,
+				  struct clock_event_device *clk)
 {
 	unsigned long ctrl;
 	switch (mode) {
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
-		ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+		ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk);
 		ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
-		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+		arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
 		break;
 	default:
 		break;
@@ -90,60 +195,108 @@
 static void arch_timer_set_mode_virt(enum clock_event_mode mode,
 				     struct clock_event_device *clk)
 {
-	timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode);
+	timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode, clk);
 }
 
 static void arch_timer_set_mode_phys(enum clock_event_mode mode,
 				     struct clock_event_device *clk)
 {
-	timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode);
+	timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk);
 }
 
-static inline void set_next_event(const int access, unsigned long evt)
+static void arch_timer_set_mode_virt_mem(enum clock_event_mode mode,
+					 struct clock_event_device *clk)
+{
+	timer_set_mode(ARCH_TIMER_MEM_VIRT_ACCESS, mode, clk);
+}
+
+static void arch_timer_set_mode_phys_mem(enum clock_event_mode mode,
+					 struct clock_event_device *clk)
+{
+	timer_set_mode(ARCH_TIMER_MEM_PHYS_ACCESS, mode, clk);
+}
+
+static __always_inline void set_next_event(const int access, unsigned long evt,
+					   struct clock_event_device *clk)
 {
 	unsigned long ctrl;
-	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL);
+	ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk);
 	ctrl |= ARCH_TIMER_CTRL_ENABLE;
 	ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
-	arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt);
-	arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl);
+	arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt, clk);
+	arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk);
 }
 
 static int arch_timer_set_next_event_virt(unsigned long evt,
-					  struct clock_event_device *unused)
+					  struct clock_event_device *clk)
 {
-	set_next_event(ARCH_TIMER_VIRT_ACCESS, evt);
+	set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk);
 	return 0;
 }
 
 static int arch_timer_set_next_event_phys(unsigned long evt,
-					  struct clock_event_device *unused)
+					  struct clock_event_device *clk)
 {
-	set_next_event(ARCH_TIMER_PHYS_ACCESS, evt);
+	set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk);
 	return 0;
 }
 
+static int arch_timer_set_next_event_virt_mem(unsigned long evt,
+					      struct clock_event_device *clk)
+{
+	set_next_event(ARCH_TIMER_MEM_VIRT_ACCESS, evt, clk);
+	return 0;
+}
+
+static int arch_timer_set_next_event_phys_mem(unsigned long evt,
+					      struct clock_event_device *clk)
+{
+	set_next_event(ARCH_TIMER_MEM_PHYS_ACCESS, evt, clk);
+	return 0;
+}
+
+static void __arch_timer_setup(unsigned type,
+			       struct clock_event_device *clk)
+{
+	clk->features = CLOCK_EVT_FEAT_ONESHOT;
+
+	if (type == ARCH_CP15_TIMER) {
+		clk->features |= CLOCK_EVT_FEAT_C3STOP;
+		clk->name = "arch_sys_timer";
+		clk->rating = 450;
+		clk->cpumask = cpumask_of(smp_processor_id());
+		if (arch_timer_use_virtual) {
+			clk->irq = arch_timer_ppi[VIRT_PPI];
+			clk->set_mode = arch_timer_set_mode_virt;
+			clk->set_next_event = arch_timer_set_next_event_virt;
+		} else {
+			clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
+			clk->set_mode = arch_timer_set_mode_phys;
+			clk->set_next_event = arch_timer_set_next_event_phys;
+		}
+	} else {
+		clk->name = "arch_mem_timer";
+		clk->rating = 400;
+		clk->cpumask = cpu_all_mask;
+		if (arch_timer_mem_use_virtual) {
+			clk->set_mode = arch_timer_set_mode_virt_mem;
+			clk->set_next_event =
+				arch_timer_set_next_event_virt_mem;
+		} else {
+			clk->set_mode = arch_timer_set_mode_phys_mem;
+			clk->set_next_event =
+				arch_timer_set_next_event_phys_mem;
+		}
+	}
+
+	clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk);
+
+	clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff);
+}
+
 static int arch_timer_setup(struct clock_event_device *clk)
 {
-	clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP;
-	clk->name = "arch_sys_timer";
-	clk->rating = 450;
-	if (arch_timer_use_virtual) {
-		clk->irq = arch_timer_ppi[VIRT_PPI];
-		clk->set_mode = arch_timer_set_mode_virt;
-		clk->set_next_event = arch_timer_set_next_event_virt;
-	} else {
-		clk->irq = arch_timer_ppi[PHYS_SECURE_PPI];
-		clk->set_mode = arch_timer_set_mode_phys;
-		clk->set_next_event = arch_timer_set_next_event_phys;
-	}
-
-	clk->cpumask = cpumask_of(smp_processor_id());
-
-	clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL);
-
-	clockevents_config_and_register(clk, arch_timer_rate,
-					0xf, 0x7fffffff);
+	__arch_timer_setup(ARCH_CP15_TIMER, clk);
 
 	if (arch_timer_use_virtual)
 		enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0);
@@ -158,27 +311,41 @@
 	return 0;
 }
 
-static int arch_timer_available(void)
+static void
+arch_timer_detect_rate(void __iomem *cntbase, struct device_node *np)
 {
-	u32 freq;
+	/* Who has more than one independent system counter? */
+	if (arch_timer_rate)
+		return;
 
-	if (arch_timer_rate == 0) {
-		freq = arch_timer_get_cntfrq();
-
-		/* Check the timer frequency. */
-		if (freq == 0) {
-			pr_warn("Architected timer frequency not available\n");
-			return -EINVAL;
-		}
-
-		arch_timer_rate = freq;
+	/* Try to determine the frequency from the device tree or CNTFRQ */
+	if (of_property_read_u32(np, "clock-frequency", &arch_timer_rate)) {
+		if (cntbase)
+			arch_timer_rate = readl_relaxed(cntbase + CNTFRQ);
+		else
+			arch_timer_rate = arch_timer_get_cntfrq();
 	}
 
-	pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n",
+	/* Check the timer frequency. */
+	if (arch_timer_rate == 0)
+		pr_warn("Architected timer frequency not available\n");
+}
+
+static void arch_timer_banner(unsigned type)
+{
+	pr_info("Architected %s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n",
+		     type & ARCH_CP15_TIMER ? "cp15" : "",
+		     type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  " and " : "",
+		     type & ARCH_MEM_TIMER ? "mmio" : "",
 		     (unsigned long)arch_timer_rate / 1000000,
 		     (unsigned long)(arch_timer_rate / 10000) % 100,
-		     arch_timer_use_virtual ? "virt" : "phys");
-	return 0;
+		     type & ARCH_CP15_TIMER ?
+			arch_timer_use_virtual ? "virt" : "phys" :
+			"",
+		     type == (ARCH_CP15_TIMER | ARCH_MEM_TIMER) ?  "/" : "",
+		     type & ARCH_MEM_TIMER ?
+			arch_timer_mem_use_virtual ? "virt" : "phys" :
+			"");
 }
 
 u32 arch_timer_get_rate(void)
@@ -186,19 +353,35 @@
 	return arch_timer_rate;
 }
 
-u64 arch_timer_read_counter(void)
+static u64 arch_counter_get_cntvct_mem(void)
 {
-	return arch_counter_get_cntvct();
+	u32 vct_lo, vct_hi, tmp_hi;
+
+	do {
+		vct_hi = readl_relaxed(arch_counter_base + CNTVCT_HI);
+		vct_lo = readl_relaxed(arch_counter_base + CNTVCT_LO);
+		tmp_hi = readl_relaxed(arch_counter_base + CNTVCT_HI);
+	} while (vct_hi != tmp_hi);
+
+	return ((u64) vct_hi << 32) | vct_lo;
 }
 
+/*
+ * Default to cp15 based access because arm64 uses this function for
+ * sched_clock() before DT is probed and the cp15 method is guaranteed
+ * to exist on arm64. arm doesn't use this before DT is probed so even
+ * if we don't have the cp15 accessors we won't have a problem.
+ */
+u64 (*arch_timer_read_counter)(void) = arch_counter_get_cntvct;
+
 static cycle_t arch_counter_read(struct clocksource *cs)
 {
-	return arch_counter_get_cntvct();
+	return arch_timer_read_counter();
 }
 
 static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
 {
-	return arch_counter_get_cntvct();
+	return arch_timer_read_counter();
 }
 
 static struct clocksource clocksource_counter = {
@@ -221,6 +404,23 @@
 	return &timecounter;
 }
 
+static void __init arch_counter_register(unsigned type)
+{
+	u64 start_count;
+
+	/* Register the CP15 based counter if we have one */
+	if (type & ARCH_CP15_TIMER)
+		arch_timer_read_counter = arch_counter_get_cntvct;
+	else
+		arch_timer_read_counter = arch_counter_get_cntvct_mem;
+
+	start_count = arch_timer_read_counter();
+	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
+	cyclecounter.mult = clocksource_counter.mult;
+	cyclecounter.shift = clocksource_counter.shift;
+	timecounter_init(&timecounter, &cyclecounter, start_count);
+}
+
 static void arch_timer_stop(struct clock_event_device *clk)
 {
 	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
@@ -265,22 +465,12 @@
 	int err;
 	int ppi;
 
-	err = arch_timer_available();
-	if (err)
-		goto out;
-
 	arch_timer_evt = alloc_percpu(struct clock_event_device);
 	if (!arch_timer_evt) {
 		err = -ENOMEM;
 		goto out;
 	}
 
-	clocksource_register_hz(&clocksource_counter, arch_timer_rate);
-	cyclecounter.mult = clocksource_counter.mult;
-	cyclecounter.shift = clocksource_counter.shift;
-	timecounter_init(&timecounter, &cyclecounter,
-			 arch_counter_get_cntvct());
-
 	if (arch_timer_use_virtual) {
 		ppi = arch_timer_ppi[VIRT_PPI];
 		err = request_percpu_irq(ppi, arch_timer_handler_virt,
@@ -331,24 +521,77 @@
 	return err;
 }
 
+static int __init arch_timer_mem_register(void __iomem *base, unsigned int irq)
+{
+	int ret;
+	irq_handler_t func;
+	struct arch_timer *t;
+
+	t = kzalloc(sizeof(*t), GFP_KERNEL);
+	if (!t)
+		return -ENOMEM;
+
+	t->base = base;
+	t->evt.irq = irq;
+	__arch_timer_setup(ARCH_MEM_TIMER, &t->evt);
+
+	if (arch_timer_mem_use_virtual)
+		func = arch_timer_handler_virt_mem;
+	else
+		func = arch_timer_handler_phys_mem;
+
+	ret = request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &t->evt);
+	if (ret) {
+		pr_err("arch_timer: Failed to request mem timer irq\n");
+		kfree(t);
+	}
+
+	return ret;
+}
+
+static const struct of_device_id arch_timer_of_match[] __initconst = {
+	{ .compatible   = "arm,armv7-timer",    },
+	{ .compatible   = "arm,armv8-timer",    },
+	{},
+};
+
+static const struct of_device_id arch_timer_mem_of_match[] __initconst = {
+	{ .compatible   = "arm,armv7-timer-mem", },
+	{},
+};
+
+static void __init arch_timer_common_init(void)
+{
+	unsigned mask = ARCH_CP15_TIMER | ARCH_MEM_TIMER;
+
+	/* Wait until both nodes are probed if we have two timers */
+	if ((arch_timers_present & mask) != mask) {
+		if (of_find_matching_node(NULL, arch_timer_mem_of_match) &&
+				!(arch_timers_present & ARCH_MEM_TIMER))
+			return;
+		if (of_find_matching_node(NULL, arch_timer_of_match) &&
+				!(arch_timers_present & ARCH_CP15_TIMER))
+			return;
+	}
+
+	arch_timer_banner(arch_timers_present);
+	arch_counter_register(arch_timers_present);
+	arch_timer_arch_init();
+}
+
 static void __init arch_timer_init(struct device_node *np)
 {
-	u32 freq;
 	int i;
 
-	if (arch_timer_get_rate()) {
+	if (arch_timers_present & ARCH_CP15_TIMER) {
 		pr_warn("arch_timer: multiple nodes in dt, skipping\n");
 		return;
 	}
 
-	/* Try to determine the frequency from the device tree or CNTFRQ */
-	if (!of_property_read_u32(np, "clock-frequency", &freq))
-		arch_timer_rate = freq;
-
+	arch_timers_present |= ARCH_CP15_TIMER;
 	for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++)
 		arch_timer_ppi[i] = irq_of_parse_and_map(np, i);
-
-	of_node_put(np);
+	arch_timer_detect_rate(NULL, np);
 
 	/*
 	 * If HYP mode is available, we know that the physical timer
@@ -369,7 +612,73 @@
 	}
 
 	arch_timer_register();
-	arch_timer_arch_init();
+	arch_timer_common_init();
 }
 CLOCKSOURCE_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_init);
 CLOCKSOURCE_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_init);
+
+static void __init arch_timer_mem_init(struct device_node *np)
+{
+	struct device_node *frame, *best_frame = NULL;
+	void __iomem *cntctlbase, *base;
+	unsigned int irq;
+	u32 cnttidr;
+
+	arch_timers_present |= ARCH_MEM_TIMER;
+	cntctlbase = of_iomap(np, 0);
+	if (!cntctlbase) {
+		pr_err("arch_timer: Can't find CNTCTLBase\n");
+		return;
+	}
+
+	cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
+	iounmap(cntctlbase);
+
+	/*
+	 * Try to find a virtual capable frame. Otherwise fall back to a
+	 * physical capable frame.
+	 */
+	for_each_available_child_of_node(np, frame) {
+		int n;
+
+		if (of_property_read_u32(frame, "frame-number", &n)) {
+			pr_err("arch_timer: Missing frame-number\n");
+			of_node_put(best_frame);
+			of_node_put(frame);
+			return;
+		}
+
+		if (cnttidr & CNTTIDR_VIRT(n)) {
+			of_node_put(best_frame);
+			best_frame = frame;
+			arch_timer_mem_use_virtual = true;
+			break;
+		}
+		of_node_put(best_frame);
+		best_frame = of_node_get(frame);
+	}
+
+	base = arch_counter_base = of_iomap(best_frame, 0);
+	if (!base) {
+		pr_err("arch_timer: Can't map frame's registers\n");
+		of_node_put(best_frame);
+		return;
+	}
+
+	if (arch_timer_mem_use_virtual)
+		irq = irq_of_parse_and_map(best_frame, 1);
+	else
+		irq = irq_of_parse_and_map(best_frame, 0);
+	of_node_put(best_frame);
+	if (!irq) {
+		pr_err("arch_timer: Frame missing %s irq",
+		       arch_timer_mem_use_virtual ? "virt" : "phys");
+		return;
+	}
+
+	arch_timer_detect_rate(base, np);
+	arch_timer_mem_register(base, irq);
+	arch_timer_common_init();
+}
+CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
+		       arch_timer_mem_init);
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c
index 4cbe28c..b2bb3a4b 100644
--- a/drivers/clocksource/cadence_ttc_timer.c
+++ b/drivers/clocksource/cadence_ttc_timer.c
@@ -21,7 +21,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/slab.h>
-#include <linux/clk-provider.h>
+#include <linux/sched_clock.h>
 
 /*
  * This driver configures the 2 16-bit count-up timers as follows:
@@ -95,6 +95,8 @@
 #define to_ttc_timer_clkevent(x) \
 		container_of(x, struct ttc_timer_clockevent, ce)
 
+static void __iomem *ttc_sched_clock_val_reg;
+
 /**
  * ttc_set_interval - Set the timer interval value
  *
@@ -156,6 +158,11 @@
 				TTC_COUNT_VAL_OFFSET);
 }
 
+static u32 notrace ttc_sched_clock_read(void)
+{
+	return __raw_readl(ttc_sched_clock_val_reg);
+}
+
 /**
  * ttc_set_next_event - Sets the time interval for next event
  *
@@ -297,6 +304,10 @@
 		kfree(ttccs);
 		return;
 	}
+
+	ttc_sched_clock_val_reg = base + TTC_COUNT_VAL_OFFSET;
+	setup_sched_clock(ttc_sched_clock_read, 16,
+			clk_get_rate(ttccs->ttc.clk) / PRESCALE);
 }
 
 static int ttc_rate_change_clockevent_cb(struct notifier_block *nb,
diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c
new file mode 100644
index 0000000..5eb2c35
--- /dev/null
+++ b/drivers/clocksource/moxart_timer.c
@@ -0,0 +1,165 @@
+/*
+ * MOXA ART SoCs timer handling.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * 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/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/clocksource.h>
+#include <linux/bitops.h>
+
+#define TIMER1_BASE		0x00
+#define TIMER2_BASE		0x10
+#define TIMER3_BASE		0x20
+
+#define REG_COUNT		0x0 /* writable */
+#define REG_LOAD		0x4
+#define REG_MATCH1		0x8
+#define REG_MATCH2		0xC
+
+#define TIMER_CR		0x30
+#define TIMER_INTR_STATE	0x34
+#define TIMER_INTR_MASK		0x38
+
+/*
+ * TIMER_CR flags:
+ *
+ * TIMEREG_CR_*_CLOCK	0: PCLK, 1: EXT1CLK
+ * TIMEREG_CR_*_INT	overflow interrupt enable bit
+ */
+#define TIMEREG_CR_1_ENABLE	BIT(0)
+#define TIMEREG_CR_1_CLOCK	BIT(1)
+#define TIMEREG_CR_1_INT	BIT(2)
+#define TIMEREG_CR_2_ENABLE	BIT(3)
+#define TIMEREG_CR_2_CLOCK	BIT(4)
+#define TIMEREG_CR_2_INT	BIT(5)
+#define TIMEREG_CR_3_ENABLE	BIT(6)
+#define TIMEREG_CR_3_CLOCK	BIT(7)
+#define TIMEREG_CR_3_INT	BIT(8)
+#define TIMEREG_CR_COUNT_UP	BIT(9)
+
+#define TIMER1_ENABLE		(TIMEREG_CR_2_ENABLE | TIMEREG_CR_1_ENABLE)
+#define TIMER1_DISABLE		(TIMEREG_CR_2_ENABLE)
+
+static void __iomem *base;
+static unsigned int clock_count_per_tick;
+
+static void moxart_clkevt_mode(enum clock_event_mode mode,
+			       struct clock_event_device *clk)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_RESUME:
+	case CLOCK_EVT_MODE_ONESHOT:
+		writel(TIMER1_DISABLE, base + TIMER_CR);
+		writel(~0, base + TIMER1_BASE + REG_LOAD);
+		break;
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD);
+		writel(TIMER1_ENABLE, base + TIMER_CR);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	default:
+		writel(TIMER1_DISABLE, base + TIMER_CR);
+		break;
+	}
+}
+
+static int moxart_clkevt_next_event(unsigned long cycles,
+				    struct clock_event_device *unused)
+{
+	u32 u;
+
+	writel(TIMER1_DISABLE, base + TIMER_CR);
+
+	u = readl(base + TIMER1_BASE + REG_COUNT) - cycles;
+	writel(u, base + TIMER1_BASE + REG_MATCH1);
+
+	writel(TIMER1_ENABLE, base + TIMER_CR);
+
+	return 0;
+}
+
+static struct clock_event_device moxart_clockevent = {
+	.name		= "moxart_timer",
+	.rating		= 200,
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= moxart_clkevt_mode,
+	.set_next_event	= moxart_clkevt_next_event,
+};
+
+static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction moxart_timer_irq = {
+	.name		= "moxart-timer",
+	.flags		= IRQF_TIMER,
+	.handler	= moxart_timer_interrupt,
+	.dev_id		= &moxart_clockevent,
+};
+
+static void __init moxart_timer_init(struct device_node *node)
+{
+	int ret, irq;
+	unsigned long pclk;
+	struct clk *clk;
+
+	base = of_iomap(node, 0);
+	if (!base)
+		panic("%s: of_iomap failed\n", node->full_name);
+
+	irq = irq_of_parse_and_map(node, 0);
+	if (irq <= 0)
+		panic("%s: irq_of_parse_and_map failed\n", node->full_name);
+
+	ret = setup_irq(irq, &moxart_timer_irq);
+	if (ret)
+		panic("%s: setup_irq failed\n", node->full_name);
+
+	clk = of_clk_get(node, 0);
+	if (IS_ERR(clk))
+		panic("%s: of_clk_get failed\n", node->full_name);
+
+	pclk = clk_get_rate(clk);
+
+	if (clocksource_mmio_init(base + TIMER2_BASE + REG_COUNT,
+				  "moxart_timer", pclk, 200, 32,
+				  clocksource_mmio_readl_down))
+		panic("%s: clocksource_mmio_init failed\n", node->full_name);
+
+	clock_count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
+
+	writel(~0, base + TIMER2_BASE + REG_LOAD);
+	writel(TIMEREG_CR_2_ENABLE, base + TIMER_CR);
+
+	moxart_clockevent.cpumask = cpumask_of(0);
+	moxart_clockevent.irq = irq;
+
+	/*
+	 * documentation is not publicly available:
+	 * min_delta / max_delta obtained by trial-and-error,
+	 * max_delta 0xfffffffe should be ok because count
+	 * register size is u32
+	 */
+	clockevents_config_and_register(&moxart_clockevent, pclk,
+					0x4, 0xfffffffe);
+}
+CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c
index d4674e7..8ead025 100644
--- a/drivers/clocksource/sun4i_timer.c
+++ b/drivers/clocksource/sun4i_timer.c
@@ -19,42 +19,83 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqreturn.h>
+#include <linux/sched_clock.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 
 #define TIMER_IRQ_EN_REG	0x00
-#define TIMER_IRQ_EN(val)		(1 << val)
+#define TIMER_IRQ_EN(val)		BIT(val)
 #define TIMER_IRQ_ST_REG	0x04
 #define TIMER_CTL_REG(val)	(0x10 * val + 0x10)
-#define TIMER_CTL_ENABLE		(1 << 0)
-#define TIMER_CTL_AUTORELOAD		(1 << 1)
-#define TIMER_CTL_ONESHOT		(1 << 7)
-#define TIMER_INTVAL_REG(val)	(0x10 * val + 0x14)
-#define TIMER_CNTVAL_REG(val)	(0x10 * val + 0x18)
-
-#define TIMER_SCAL		16
+#define TIMER_CTL_ENABLE		BIT(0)
+#define TIMER_CTL_RELOAD		BIT(1)
+#define TIMER_CTL_CLK_SRC(val)		(((val) & 0x3) << 2)
+#define TIMER_CTL_CLK_SRC_OSC24M		(1)
+#define TIMER_CTL_CLK_PRES(val)		(((val) & 0x7) << 4)
+#define TIMER_CTL_ONESHOT		BIT(7)
+#define TIMER_INTVAL_REG(val)	(0x10 * (val) + 0x14)
+#define TIMER_CNTVAL_REG(val)	(0x10 * (val) + 0x18)
 
 static void __iomem *timer_base;
+static u32 ticks_per_jiffy;
+
+/*
+ * When we disable a timer, we need to wait at least for 2 cycles of
+ * the timer source clock. We will use for that the clocksource timer
+ * that is already setup and runs at the same frequency than the other
+ * timers, and we never will be disabled.
+ */
+static void sun4i_clkevt_sync(void)
+{
+	u32 old = readl(timer_base + TIMER_CNTVAL_REG(1));
+
+	while ((old - readl(timer_base + TIMER_CNTVAL_REG(1))) < 3)
+		cpu_relax();
+}
+
+static void sun4i_clkevt_time_stop(u8 timer)
+{
+	u32 val = readl(timer_base + TIMER_CTL_REG(timer));
+	writel(val & ~TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(timer));
+	sun4i_clkevt_sync();
+}
+
+static void sun4i_clkevt_time_setup(u8 timer, unsigned long delay)
+{
+	writel(delay, timer_base + TIMER_INTVAL_REG(timer));
+}
+
+static void sun4i_clkevt_time_start(u8 timer, bool periodic)
+{
+	u32 val = readl(timer_base + TIMER_CTL_REG(timer));
+
+	if (periodic)
+		val &= ~TIMER_CTL_ONESHOT;
+	else
+		val |= TIMER_CTL_ONESHOT;
+
+	writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
+	       timer_base + TIMER_CTL_REG(timer));
+}
 
 static void sun4i_clkevt_mode(enum clock_event_mode mode,
 			      struct clock_event_device *clk)
 {
-	u32 u = readl(timer_base + TIMER_CTL_REG(0));
-
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
-		u &= ~(TIMER_CTL_ONESHOT);
-		writel(u | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG(0));
+		sun4i_clkevt_time_stop(0);
+		sun4i_clkevt_time_setup(0, ticks_per_jiffy);
+		sun4i_clkevt_time_start(0, true);
 		break;
-
 	case CLOCK_EVT_MODE_ONESHOT:
-		writel(u | TIMER_CTL_ONESHOT, timer_base + TIMER_CTL_REG(0));
+		sun4i_clkevt_time_stop(0);
+		sun4i_clkevt_time_start(0, false);
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
 	case CLOCK_EVT_MODE_SHUTDOWN:
 	default:
-		writel(u & ~(TIMER_CTL_ENABLE), timer_base + TIMER_CTL_REG(0));
+		sun4i_clkevt_time_stop(0);
 		break;
 	}
 }
@@ -62,10 +103,9 @@
 static int sun4i_clkevt_next_event(unsigned long evt,
 				   struct clock_event_device *unused)
 {
-	u32 u = readl(timer_base + TIMER_CTL_REG(0));
-	writel(evt, timer_base + TIMER_CNTVAL_REG(0));
-	writel(u | TIMER_CTL_ENABLE | TIMER_CTL_AUTORELOAD,
-	       timer_base + TIMER_CTL_REG(0));
+	sun4i_clkevt_time_stop(0);
+	sun4i_clkevt_time_setup(0, evt);
+	sun4i_clkevt_time_start(0, false);
 
 	return 0;
 }
@@ -96,6 +136,11 @@
 	.dev_id = &sun4i_clockevent,
 };
 
+static u32 sun4i_timer_sched_read(void)
+{
+	return ~readl(timer_base + TIMER_CNTVAL_REG(1));
+}
+
 static void __init sun4i_timer_init(struct device_node *node)
 {
 	unsigned long rate = 0;
@@ -114,22 +159,23 @@
 	clk = of_clk_get(node, 0);
 	if (IS_ERR(clk))
 		panic("Can't get timer clock");
+	clk_prepare_enable(clk);
 
 	rate = clk_get_rate(clk);
 
-	writel(rate / (TIMER_SCAL * HZ),
-	       timer_base + TIMER_INTVAL_REG(0));
+	writel(~0, timer_base + TIMER_INTVAL_REG(1));
+	writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
+	       TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
+	       timer_base + TIMER_CTL_REG(1));
 
-	/* set clock source to HOSC, 16 pre-division */
-	val = readl(timer_base + TIMER_CTL_REG(0));
-	val &= ~(0x07 << 4);
-	val &= ~(0x03 << 2);
-	val |= (4 << 4) | (1 << 2);
-	writel(val, timer_base + TIMER_CTL_REG(0));
+	setup_sched_clock(sun4i_timer_sched_read, 32, rate);
+	clocksource_mmio_init(timer_base + TIMER_CNTVAL_REG(1), node->name,
+			      rate, 300, 32, clocksource_mmio_readl_down);
 
-	/* set mode to auto reload */
-	val = readl(timer_base + TIMER_CTL_REG(0));
-	writel(val | TIMER_CTL_AUTORELOAD, timer_base + TIMER_CTL_REG(0));
+	ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
+
+	writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
+	       timer_base + TIMER_CTL_REG(0));
 
 	ret = setup_irq(irq, &sun4i_timer_irq);
 	if (ret)
@@ -141,8 +187,8 @@
 
 	sun4i_clockevent.cpumask = cpumask_of(0);
 
-	clockevents_config_and_register(&sun4i_clockevent, rate / TIMER_SCAL,
-					0x1, 0xff);
+	clockevents_config_and_register(&sun4i_clockevent, rate, 0x1,
+					0xffffffff);
 }
 CLOCKSOURCE_OF_DECLARE(sun4i, "allwinner,sun4i-timer",
 		       sun4i_timer_init);
diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c
index ecbeb68..9c7f018 100644
--- a/drivers/clocksource/time-orion.c
+++ b/drivers/clocksource/time-orion.c
@@ -19,7 +19,7 @@
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/spinlock.h>
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
 
 #define TIMER_CTRL		0x00
 #define  TIMER0_EN		BIT(0)
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index de4d5d9..0fa204b 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -17,37 +17,47 @@
 	  big.LITTLE platform. This gets frequency tables from DT.
 
 config ARM_EXYNOS_CPUFREQ
-	bool "SAMSUNG EXYNOS SoCs"
-	depends on ARCH_EXYNOS
+	bool
 	select CPU_FREQ_TABLE
-	default y
-	help
-	  This adds the CPUFreq driver common part for Samsung
-	  EXYNOS SoCs.
-
-	  If in doubt, say N.
 
 config ARM_EXYNOS4210_CPUFREQ
-	def_bool CPU_EXYNOS4210
+	bool "SAMSUNG EXYNOS4210"
+	depends on CPU_EXYNOS4210
+	default y
+	select ARM_EXYNOS_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS4210
 	  SoC (S5PV310 or S5PC210).
 
+	  If in doubt, say N.
+
 config ARM_EXYNOS4X12_CPUFREQ
-	def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+	bool "SAMSUNG EXYNOS4x12"
+	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+	default y
+	select ARM_EXYNOS_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS4X12
 	  SoC (EXYNOS4212 or EXYNOS4412).
 
+	  If in doubt, say N.
+
 config ARM_EXYNOS5250_CPUFREQ
-	def_bool SOC_EXYNOS5250
+	bool "SAMSUNG EXYNOS5250"
+	depends on SOC_EXYNOS5250
+	default y
+	select ARM_EXYNOS_CPUFREQ
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
 
+	  If in doubt, say N.
+
 config ARM_EXYNOS5440_CPUFREQ
-	def_bool SOC_EXYNOS5440
+	bool "SAMSUNG EXYNOS5440"
+	depends on SOC_EXYNOS5440
 	depends on HAVE_CLK && PM_OPP && OF
+	default y
 	select CPU_FREQ_TABLE
 	help
 	  This adds the CPUFreq driver for Samsung EXYNOS5440
@@ -55,6 +65,8 @@
 	  different than previous exynos controllers so not using
 	  the common exynos framework.
 
+	  If in doubt, say N.
+
 config ARM_HIGHBANK_CPUFREQ
 	tristate "Calxeda Highbank-based"
 	depends on ARCH_HIGHBANK
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index d345b5a..ad5866c 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -23,7 +23,7 @@
 # powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers.
 # speedstep-* is preferred over p4-clockmod.
 
-obj-$(CONFIG_X86_ACPI_CPUFREQ)		+= acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ)		+= acpi-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K8)		+= powernow-k8.o
 obj-$(CONFIG_X86_PCC_CPUFREQ)		+= pcc-cpufreq.o
 obj-$(CONFIG_X86_POWERNOW_K6)		+= powernow-k6.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 3926402..a1260b4 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -45,7 +45,6 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
-#include "mperf.h"
 
 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
@@ -198,7 +197,7 @@
 	return sprintf(buf, "%u\n", boost_enabled);
 }
 
-static struct freq_attr cpb = __ATTR(cpb, 0644, show_cpb, store_cpb);
+cpufreq_freq_attr_rw(cpb);
 #endif
 
 static int check_est_cpu(unsigned int cpuid)
@@ -710,7 +709,7 @@
 		return blacklisted;
 #endif
 
-	data = kzalloc(sizeof(struct acpi_cpufreq_data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -800,7 +799,7 @@
 		goto err_unreg;
 	}
 
-	data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+	data->freq_table = kmalloc(sizeof(*data->freq_table) *
 		    (perf->state_count+1), GFP_KERNEL);
 	if (!data->freq_table) {
 		result = -ENOMEM;
@@ -861,10 +860,6 @@
 	/* notify BIOS that we exist */
 	acpi_processor_notify_smm(THIS_MODULE);
 
-	/* Check for APERF/MPERF support in hardware */
-	if (boot_cpu_has(X86_FEATURE_APERFMPERF))
-		acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
-
 	pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
 	for (i = 0; i < perf->state_count; i++)
 		pr_debug("     %cP%d: %d MHz, %d mW, %d uS\n",
@@ -941,7 +936,6 @@
 	.exit		= acpi_cpufreq_cpu_exit,
 	.resume		= acpi_cpufreq_resume,
 	.name		= "acpi-cpufreq",
-	.owner		= THIS_MODULE,
 	.attr		= acpi_cpufreq_attr,
 };
 
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
index fd9e3ea..480c0bd 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -19,12 +19,11 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/device.h>
 #include <linux/export.h>
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/opp.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -34,27 +33,13 @@
 /* get cpu node with valid operating-points */
 static struct device_node *get_cpu_node_with_valid_op(int cpu)
 {
-	struct device_node *np = NULL, *parent;
-	int count = 0;
+	struct device_node *np = of_cpu_device_node_get(cpu);
 
-	parent = of_find_node_by_path("/cpus");
-	if (!parent) {
-		pr_err("failed to find OF /cpus\n");
-		return NULL;
+	if (!of_get_property(np, "operating-points", NULL)) {
+		of_node_put(np);
+		np = NULL;
 	}
 
-	for_each_child_of_node(parent, np) {
-		if (count++ != cpu)
-			continue;
-		if (!of_get_property(np, "operating-points", NULL)) {
-			of_node_put(np);
-			np = NULL;
-		}
-
-		break;
-	}
-
-	of_node_put(parent);
 	return np;
 }
 
@@ -63,11 +48,12 @@
 	struct device_node *np;
 	int ret;
 
-	np = get_cpu_node_with_valid_op(cpu_dev->id);
-	if (!np)
-		return -ENODATA;
+	np = of_node_get(cpu_dev->of_node);
+	if (!np) {
+		pr_err("failed to find cpu%d node\n", cpu_dev->id);
+		return -ENOENT;
+	}
 
-	cpu_dev->of_node = np;
 	ret = of_init_opp_table(cpu_dev);
 	of_node_put(np);
 
@@ -79,9 +65,11 @@
 	struct device_node *np;
 	u32 transition_latency = CPUFREQ_ETERNAL;
 
-	np = get_cpu_node_with_valid_op(cpu_dev->id);
-	if (!np)
+	np = of_node_get(cpu_dev->of_node);
+	if (!np) {
+		pr_info("Failed to find cpu node. Use CPUFREQ_ETERNAL transition latency\n");
 		return CPUFREQ_ETERNAL;
+	}
 
 	of_property_read_u32(np, "clock-latency", &transition_latency);
 	of_node_put(np);
diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c
index 6544887..e0c38d9 100644
--- a/drivers/cpufreq/at32ap-cpufreq.c
+++ b/drivers/cpufreq/at32ap-cpufreq.c
@@ -108,7 +108,6 @@
 
 static struct cpufreq_driver at32_driver = {
 	.name		= "at32ap",
-	.owner		= THIS_MODULE,
 	.init		= at32_cpufreq_driver_init,
 	.verify		= at32_verify_speed,
 	.target		= at32_set_target,
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index 9cdbbd2..ef05978 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -225,7 +225,6 @@
 	.get = bfin_getfreq_khz,
 	.init = __bfin_cpu_init,
 	.name = "bfin cpufreq",
-	.owner = THIS_MODULE,
 	.attr = bfin_freq_attr,
 };
 
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index ad1fde2..cbfffa9 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -69,7 +69,7 @@
 
 	cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
 
-	if (cpu_reg) {
+	if (!IS_ERR(cpu_reg)) {
 		rcu_read_lock();
 		opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
 		if (IS_ERR(opp)) {
@@ -90,7 +90,7 @@
 		 freqs.new / 1000, volt ? volt / 1000 : -1);
 
 	/* scaling up?  scale voltage before frequency */
-	if (cpu_reg && freqs.new > freqs.old) {
+	if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) {
 		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
 		if (ret) {
 			pr_err("failed to scale voltage up: %d\n", ret);
@@ -102,14 +102,14 @@
 	ret = clk_set_rate(cpu_clk, freq_exact);
 	if (ret) {
 		pr_err("failed to set clock rate: %d\n", ret);
-		if (cpu_reg)
+		if (!IS_ERR(cpu_reg))
 			regulator_set_voltage_tol(cpu_reg, volt_old, tol);
 		freqs.new = freqs.old;
 		goto post_notify;
 	}
 
 	/* scaling down?  scale voltage after frequency */
-	if (cpu_reg && freqs.new < freqs.old) {
+	if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) {
 		ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
 		if (ret) {
 			pr_err("failed to scale voltage down: %d\n", ret);
@@ -174,30 +174,18 @@
 
 static int cpu0_cpufreq_probe(struct platform_device *pdev)
 {
-	struct device_node *np, *parent;
+	struct device_node *np;
 	int ret;
 
-	parent = of_find_node_by_path("/cpus");
-	if (!parent) {
-		pr_err("failed to find OF /cpus\n");
+	cpu_dev = &pdev->dev;
+
+	np = of_node_get(cpu_dev->of_node);
+	if (!np) {
+		pr_err("failed to find cpu0 node\n");
 		return -ENOENT;
 	}
 
-	for_each_child_of_node(parent, np) {
-		if (of_get_property(np, "operating-points", NULL))
-			break;
-	}
-
-	if (!np) {
-		pr_err("failed to find cpu0 node\n");
-		ret = -ENOENT;
-		goto out_put_parent;
-	}
-
-	cpu_dev = &pdev->dev;
-	cpu_dev->of_node = np;
-
-	cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
+	cpu_reg = devm_regulator_get_optional(cpu_dev, "cpu0");
 	if (IS_ERR(cpu_reg)) {
 		/*
 		 * If cpu0 regulator supply node is present, but regulator is
@@ -210,7 +198,6 @@
 		}
 		pr_warn("failed to get cpu0 regulator: %ld\n",
 			PTR_ERR(cpu_reg));
-		cpu_reg = NULL;
 	}
 
 	cpu_clk = devm_clk_get(cpu_dev, NULL);
@@ -269,15 +256,12 @@
 	}
 
 	of_node_put(np);
-	of_node_put(parent);
 	return 0;
 
 out_free_table:
 	opp_free_cpufreq_table(cpu_dev, &freq_table);
 out_put_node:
 	of_node_put(np);
-out_put_parent:
-	of_node_put(parent);
 	return ret;
 }
 
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index af1542d..b83d45f6 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -379,7 +379,6 @@
 	.get = nforce2_get,
 	.init = nforce2_cpu_init,
 	.exit = nforce2_cpu_exit,
-	.owner = THIS_MODULE,
 };
 
 #ifdef MODULE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index f0a5e2b..5c75e31 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -17,24 +17,17 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <asm/cputime.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/notifier.h>
+#include <linux/cpu.h>
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/tick.h>
 #include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/cpu.h>
-#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/slab.h>
 #include <linux/syscore_ops.h>
-
+#include <linux/tick.h>
 #include <trace/events/power.h>
 
 /**
@@ -44,8 +37,10 @@
  */
 static struct cpufreq_driver *cpufreq_driver;
 static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
 static DEFINE_RWLOCK(cpufreq_driver_lock);
 static DEFINE_MUTEX(cpufreq_governor_lock);
+static LIST_HEAD(cpufreq_policy_list);
 
 #ifdef CONFIG_HOTPLUG_CPU
 /* This one keeps track of the previously set governor of a removed CPU */
@@ -69,15 +64,14 @@
  * - Lock should not be held across
  *     __cpufreq_governor(data, CPUFREQ_GOV_STOP);
  */
-static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
 static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
 
 #define lock_policy_rwsem(mode, cpu)					\
 static int lock_policy_rwsem_##mode(int cpu)				\
 {									\
-	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);		\
-	BUG_ON(policy_cpu == -1);					\
-	down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));		\
+	struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);	\
+	BUG_ON(!policy);						\
+	down_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu));		\
 									\
 	return 0;							\
 }
@@ -88,14 +82,20 @@
 #define unlock_policy_rwsem(mode, cpu)					\
 static void unlock_policy_rwsem_##mode(int cpu)				\
 {									\
-	int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);		\
-	BUG_ON(policy_cpu == -1);					\
-	up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu));		\
+	struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);	\
+	BUG_ON(!policy);						\
+	up_##mode(&per_cpu(cpu_policy_rwsem, policy->cpu));		\
 }
 
 unlock_policy_rwsem(read, cpu);
 unlock_policy_rwsem(write, cpu);
 
+/*
+ * rwsem to guarantee that cpufreq driver module doesn't unload during critical
+ * sections
+ */
+static DECLARE_RWSEM(cpufreq_rwsem);
+
 /* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy,
 		unsigned int event);
@@ -183,78 +183,46 @@
 }
 EXPORT_SYMBOL_GPL(get_cpu_idle_time);
 
-static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
+struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
 {
-	struct cpufreq_policy *data;
+	struct cpufreq_policy *policy = NULL;
 	unsigned long flags;
 
-	if (cpu >= nr_cpu_ids)
-		goto err_out;
+	if (cpufreq_disabled() || (cpu >= nr_cpu_ids))
+		return NULL;
+
+	if (!down_read_trylock(&cpufreq_rwsem))
+		return NULL;
 
 	/* get the cpufreq driver */
 	read_lock_irqsave(&cpufreq_driver_lock, flags);
 
-	if (!cpufreq_driver)
-		goto err_out_unlock;
-
-	if (!try_module_get(cpufreq_driver->owner))
-		goto err_out_unlock;
-
-	/* get the CPU */
-	data = per_cpu(cpufreq_cpu_data, cpu);
-
-	if (!data)
-		goto err_out_put_module;
-
-	if (!sysfs && !kobject_get(&data->kobj))
-		goto err_out_put_module;
+	if (cpufreq_driver) {
+		/* get the CPU */
+		policy = per_cpu(cpufreq_cpu_data, cpu);
+		if (policy)
+			kobject_get(&policy->kobj);
+	}
 
 	read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-	return data;
 
-err_out_put_module:
-	module_put(cpufreq_driver->owner);
-err_out_unlock:
-	read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-err_out:
-	return NULL;
-}
+	if (!policy)
+		up_read(&cpufreq_rwsem);
 
-struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
-{
-	if (cpufreq_disabled())
-		return NULL;
-
-	return __cpufreq_cpu_get(cpu, false);
+	return policy;
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
 
-static struct cpufreq_policy *cpufreq_cpu_get_sysfs(unsigned int cpu)
-{
-	return __cpufreq_cpu_get(cpu, true);
-}
-
-static void __cpufreq_cpu_put(struct cpufreq_policy *data, bool sysfs)
-{
-	if (!sysfs)
-		kobject_put(&data->kobj);
-	module_put(cpufreq_driver->owner);
-}
-
-void cpufreq_cpu_put(struct cpufreq_policy *data)
+void cpufreq_cpu_put(struct cpufreq_policy *policy)
 {
 	if (cpufreq_disabled())
 		return;
 
-	__cpufreq_cpu_put(data, false);
+	kobject_put(&policy->kobj);
+	up_read(&cpufreq_rwsem);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
 
-static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
-{
-	__cpufreq_cpu_put(data, true);
-}
-
 /*********************************************************************
  *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
  *********************************************************************/
@@ -459,8 +427,8 @@
 show_one(scaling_max_freq, max);
 show_one(scaling_cur_freq, cur);
 
-static int __cpufreq_set_policy(struct cpufreq_policy *data,
-				struct cpufreq_policy *policy);
+static int __cpufreq_set_policy(struct cpufreq_policy *policy,
+				struct cpufreq_policy *new_policy);
 
 /**
  * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
@@ -699,12 +667,12 @@
 	struct cpufreq_policy *policy = to_policy(kobj);
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret = -EINVAL;
-	policy = cpufreq_cpu_get_sysfs(policy->cpu);
-	if (!policy)
-		goto no_policy;
+
+	if (!down_read_trylock(&cpufreq_rwsem))
+		goto exit;
 
 	if (lock_policy_rwsem_read(policy->cpu) < 0)
-		goto fail;
+		goto up_read;
 
 	if (fattr->show)
 		ret = fattr->show(policy, buf);
@@ -712,9 +680,10 @@
 		ret = -EIO;
 
 	unlock_policy_rwsem_read(policy->cpu);
-fail:
-	cpufreq_cpu_put_sysfs(policy);
-no_policy:
+
+up_read:
+	up_read(&cpufreq_rwsem);
+exit:
 	return ret;
 }
 
@@ -724,12 +693,12 @@
 	struct cpufreq_policy *policy = to_policy(kobj);
 	struct freq_attr *fattr = to_attr(attr);
 	ssize_t ret = -EINVAL;
-	policy = cpufreq_cpu_get_sysfs(policy->cpu);
-	if (!policy)
-		goto no_policy;
+
+	if (!down_read_trylock(&cpufreq_rwsem))
+		goto exit;
 
 	if (lock_policy_rwsem_write(policy->cpu) < 0)
-		goto fail;
+		goto up_read;
 
 	if (fattr->store)
 		ret = fattr->store(policy, buf, count);
@@ -737,9 +706,10 @@
 		ret = -EIO;
 
 	unlock_policy_rwsem_write(policy->cpu);
-fail:
-	cpufreq_cpu_put_sysfs(policy);
-no_policy:
+
+up_read:
+	up_read(&cpufreq_rwsem);
+exit:
 	return ret;
 }
 
@@ -805,41 +775,32 @@
 EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
 
 /* symlink affected CPUs */
-static int cpufreq_add_dev_symlink(unsigned int cpu,
-				   struct cpufreq_policy *policy)
+static int cpufreq_add_dev_symlink(struct cpufreq_policy *policy)
 {
 	unsigned int j;
 	int ret = 0;
 
 	for_each_cpu(j, policy->cpus) {
-		struct cpufreq_policy *managed_policy;
 		struct device *cpu_dev;
 
-		if (j == cpu)
+		if (j == policy->cpu)
 			continue;
 
-		pr_debug("CPU %u already managed, adding link\n", j);
-		managed_policy = cpufreq_cpu_get(cpu);
+		pr_debug("Adding link for CPU: %u\n", j);
 		cpu_dev = get_cpu_device(j);
 		ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
 					"cpufreq");
-		if (ret) {
-			cpufreq_cpu_put(managed_policy);
-			return ret;
-		}
+		if (ret)
+			break;
 	}
 	return ret;
 }
 
-static int cpufreq_add_dev_interface(unsigned int cpu,
-				     struct cpufreq_policy *policy,
+static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
 				     struct device *dev)
 {
-	struct cpufreq_policy new_policy;
 	struct freq_attr **drv_attr;
-	unsigned long flags;
 	int ret = 0;
-	unsigned int j;
 
 	/* prepare interface data */
 	ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
@@ -871,18 +832,24 @@
 			goto err_out_kobj_put;
 	}
 
-	write_lock_irqsave(&cpufreq_driver_lock, flags);
-	for_each_cpu(j, policy->cpus) {
-		per_cpu(cpufreq_cpu_data, j) = policy;
-		per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
-	}
-	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
-	ret = cpufreq_add_dev_symlink(cpu, policy);
+	ret = cpufreq_add_dev_symlink(policy);
 	if (ret)
 		goto err_out_kobj_put;
 
-	memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
+	return ret;
+
+err_out_kobj_put:
+	kobject_put(&policy->kobj);
+	wait_for_completion(&policy->kobj_unregister);
+	return ret;
+}
+
+static void cpufreq_init_policy(struct cpufreq_policy *policy)
+{
+	struct cpufreq_policy new_policy;
+	int ret = 0;
+
+	memcpy(&new_policy, policy, sizeof(*policy));
 	/* assure that the starting sequence is run in __cpufreq_set_policy */
 	policy->governor = NULL;
 
@@ -896,72 +863,106 @@
 		if (cpufreq_driver->exit)
 			cpufreq_driver->exit(policy);
 	}
-	return ret;
-
-err_out_kobj_put:
-	kobject_put(&policy->kobj);
-	wait_for_completion(&policy->kobj_unregister);
-	return ret;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
-				  struct device *dev)
+static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
+				  unsigned int cpu, struct device *dev,
+				  bool frozen)
 {
-	struct cpufreq_policy *policy;
 	int ret = 0, has_target = !!cpufreq_driver->target;
 	unsigned long flags;
 
-	policy = cpufreq_cpu_get(sibling);
-	WARN_ON(!policy);
+	if (has_target) {
+		ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+		if (ret) {
+			pr_err("%s: Failed to stop governor\n", __func__);
+			return ret;
+		}
+	}
 
-	if (has_target)
-		__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
-
-	lock_policy_rwsem_write(sibling);
+	lock_policy_rwsem_write(policy->cpu);
 
 	write_lock_irqsave(&cpufreq_driver_lock, flags);
 
 	cpumask_set_cpu(cpu, policy->cpus);
-	per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
 	per_cpu(cpufreq_cpu_data, cpu) = policy;
 	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-	unlock_policy_rwsem_write(sibling);
+	unlock_policy_rwsem_write(policy->cpu);
 
 	if (has_target) {
-		__cpufreq_governor(policy, CPUFREQ_GOV_START);
-		__cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+		if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
+			(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+			pr_err("%s: Failed to start governor\n", __func__);
+			return ret;
+		}
 	}
 
-	ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
-	if (ret) {
-		cpufreq_cpu_put(policy);
-		return ret;
-	}
+	/* Don't touch sysfs links during light-weight init */
+	if (!frozen)
+		ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
 
-	return 0;
+	return ret;
 }
 #endif
 
-/**
- * cpufreq_add_dev - add a CPU device
- *
- * Adds the cpufreq interface for a CPU device.
- *
- * The Oracle says: try running cpufreq registration/unregistration concurrently
- * with with cpu hotplugging and all hell will break loose. Tried to clean this
- * mess up, but more thorough testing is needed. - Mathieu
- */
-static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
+{
+	struct cpufreq_policy *policy;
+	unsigned long flags;
+
+	write_lock_irqsave(&cpufreq_driver_lock, flags);
+
+	policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
+
+	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+	return policy;
+}
+
+static struct cpufreq_policy *cpufreq_policy_alloc(void)
+{
+	struct cpufreq_policy *policy;
+
+	policy = kzalloc(sizeof(*policy), GFP_KERNEL);
+	if (!policy)
+		return NULL;
+
+	if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
+		goto err_free_policy;
+
+	if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
+		goto err_free_cpumask;
+
+	INIT_LIST_HEAD(&policy->policy_list);
+	return policy;
+
+err_free_cpumask:
+	free_cpumask_var(policy->cpus);
+err_free_policy:
+	kfree(policy);
+
+	return NULL;
+}
+
+static void cpufreq_policy_free(struct cpufreq_policy *policy)
+{
+	free_cpumask_var(policy->related_cpus);
+	free_cpumask_var(policy->cpus);
+	kfree(policy);
+}
+
+static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
+			     bool frozen)
 {
 	unsigned int j, cpu = dev->id;
 	int ret = -ENOMEM;
 	struct cpufreq_policy *policy;
 	unsigned long flags;
 #ifdef CONFIG_HOTPLUG_CPU
+	struct cpufreq_policy *tpolicy;
 	struct cpufreq_governor *gov;
-	int sibling;
 #endif
 
 	if (cpu_is_offline(cpu))
@@ -977,43 +978,38 @@
 		cpufreq_cpu_put(policy);
 		return 0;
 	}
+#endif
+
+	if (!down_read_trylock(&cpufreq_rwsem))
+		return 0;
 
 #ifdef CONFIG_HOTPLUG_CPU
 	/* Check if this cpu was hot-unplugged earlier and has siblings */
 	read_lock_irqsave(&cpufreq_driver_lock, flags);
-	for_each_online_cpu(sibling) {
-		struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
-		if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
+	list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
+		if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
 			read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-			return cpufreq_add_policy_cpu(cpu, sibling, dev);
+			ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev, frozen);
+			up_read(&cpufreq_rwsem);
+			return ret;
 		}
 	}
 	read_unlock_irqrestore(&cpufreq_driver_lock, flags);
 #endif
-#endif
 
-	if (!try_module_get(cpufreq_driver->owner)) {
-		ret = -EINVAL;
-		goto module_out;
-	}
+	if (frozen)
+		/* Restore the saved policy when doing light-weight init */
+		policy = cpufreq_policy_restore(cpu);
+	else
+		policy = cpufreq_policy_alloc();
 
-	policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
 	if (!policy)
 		goto nomem_out;
 
-	if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
-		goto err_free_policy;
-
-	if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
-		goto err_free_cpumask;
-
 	policy->cpu = cpu;
 	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	cpumask_copy(policy->cpus, cpumask_of(cpu));
 
-	/* Initially set CPU itself as the policy_cpu */
-	per_cpu(cpufreq_policy_cpu, cpu) = cpu;
-
 	init_completion(&policy->kobj_unregister);
 	INIT_WORK(&policy->update, handle_update);
 
@@ -1050,12 +1046,26 @@
 	}
 #endif
 
-	ret = cpufreq_add_dev_interface(cpu, policy, dev);
-	if (ret)
-		goto err_out_unregister;
+	write_lock_irqsave(&cpufreq_driver_lock, flags);
+	for_each_cpu(j, policy->cpus)
+		per_cpu(cpufreq_cpu_data, j) = policy;
+	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+	if (!frozen) {
+		ret = cpufreq_add_dev_interface(policy, dev);
+		if (ret)
+			goto err_out_unregister;
+	}
+
+	write_lock_irqsave(&cpufreq_driver_lock, flags);
+	list_add(&policy->policy_list, &cpufreq_policy_list);
+	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+	cpufreq_init_policy(policy);
 
 	kobject_uevent(&policy->kobj, KOBJ_ADD);
-	module_put(cpufreq_driver->owner);
+	up_read(&cpufreq_rwsem);
+
 	pr_debug("initialization complete\n");
 
 	return 0;
@@ -1066,32 +1076,33 @@
 		per_cpu(cpufreq_cpu_data, j) = NULL;
 	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-	kobject_put(&policy->kobj);
-	wait_for_completion(&policy->kobj_unregister);
-
 err_set_policy_cpu:
-	per_cpu(cpufreq_policy_cpu, cpu) = -1;
-	free_cpumask_var(policy->related_cpus);
-err_free_cpumask:
-	free_cpumask_var(policy->cpus);
-err_free_policy:
-	kfree(policy);
+	cpufreq_policy_free(policy);
 nomem_out:
-	module_put(cpufreq_driver->owner);
-module_out:
+	up_read(&cpufreq_rwsem);
+
 	return ret;
 }
 
+/**
+ * cpufreq_add_dev - add a CPU device
+ *
+ * Adds the cpufreq interface for a CPU device.
+ *
+ * The Oracle says: try running cpufreq registration/unregistration concurrently
+ * with with cpu hotplugging and all hell will break loose. Tried to clean this
+ * mess up, but more thorough testing is needed. - Mathieu
+ */
+static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
+{
+	return __cpufreq_add_dev(dev, sif, false);
+}
+
 static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
 {
-	int j;
-
 	policy->last_cpu = policy->cpu;
 	policy->cpu = cpu;
 
-	for_each_cpu(j, policy->cpus)
-		per_cpu(cpufreq_policy_cpu, j) = cpu;
-
 #ifdef CONFIG_CPU_FREQ_TABLE
 	cpufreq_frequency_table_update_policy_cpu(policy);
 #endif
@@ -1099,6 +1110,37 @@
 			CPUFREQ_UPDATE_POLICY_CPU, policy);
 }
 
+static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
+					   unsigned int old_cpu, bool frozen)
+{
+	struct device *cpu_dev;
+	int ret;
+
+	/* first sibling now owns the new sysfs dir */
+	cpu_dev = get_cpu_device(cpumask_first(policy->cpus));
+
+	/* Don't touch sysfs files during light-weight tear-down */
+	if (frozen)
+		return cpu_dev->id;
+
+	sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
+	ret = kobject_move(&policy->kobj, &cpu_dev->kobj);
+	if (ret) {
+		pr_err("%s: Failed to move kobj: %d", __func__, ret);
+
+		WARN_ON(lock_policy_rwsem_write(old_cpu));
+		cpumask_set_cpu(old_cpu, policy->cpus);
+		unlock_policy_rwsem_write(old_cpu);
+
+		ret = sysfs_create_link(&cpu_dev->kobj, &policy->kobj,
+					"cpufreq");
+
+		return -EINVAL;
+	}
+
+	return cpu_dev->id;
+}
+
 /**
  * __cpufreq_remove_dev - remove a CPU device
  *
@@ -1107,111 +1149,126 @@
  * This routine frees the rwsem before returning.
  */
 static int __cpufreq_remove_dev(struct device *dev,
-		struct subsys_interface *sif)
+				struct subsys_interface *sif, bool frozen)
 {
-	unsigned int cpu = dev->id, ret, cpus;
+	unsigned int cpu = dev->id, cpus;
+	int new_cpu, ret;
 	unsigned long flags;
-	struct cpufreq_policy *data;
+	struct cpufreq_policy *policy;
 	struct kobject *kobj;
 	struct completion *cmp;
-	struct device *cpu_dev;
 
 	pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
 
 	write_lock_irqsave(&cpufreq_driver_lock, flags);
 
-	data = per_cpu(cpufreq_cpu_data, cpu);
-	per_cpu(cpufreq_cpu_data, cpu) = NULL;
+	policy = per_cpu(cpufreq_cpu_data, cpu);
+
+	/* Save the policy somewhere when doing a light-weight tear-down */
+	if (frozen)
+		per_cpu(cpufreq_cpu_data_fallback, cpu) = policy;
 
 	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-	if (!data) {
+	if (!policy) {
 		pr_debug("%s: No cpu_data found\n", __func__);
 		return -EINVAL;
 	}
 
-	if (cpufreq_driver->target)
-		__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+	if (cpufreq_driver->target) {
+		ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+		if (ret) {
+			pr_err("%s: Failed to stop governor\n", __func__);
+			return ret;
+		}
+	}
 
 #ifdef CONFIG_HOTPLUG_CPU
 	if (!cpufreq_driver->setpolicy)
 		strncpy(per_cpu(cpufreq_cpu_governor, cpu),
-			data->governor->name, CPUFREQ_NAME_LEN);
+			policy->governor->name, CPUFREQ_NAME_LEN);
 #endif
 
 	WARN_ON(lock_policy_rwsem_write(cpu));
-	cpus = cpumask_weight(data->cpus);
+	cpus = cpumask_weight(policy->cpus);
 
 	if (cpus > 1)
-		cpumask_clear_cpu(cpu, data->cpus);
+		cpumask_clear_cpu(cpu, policy->cpus);
 	unlock_policy_rwsem_write(cpu);
 
-	if (cpu != data->cpu) {
+	if (cpu != policy->cpu && !frozen) {
 		sysfs_remove_link(&dev->kobj, "cpufreq");
 	} else if (cpus > 1) {
-		/* first sibling now owns the new sysfs dir */
-		cpu_dev = get_cpu_device(cpumask_first(data->cpus));
-		sysfs_remove_link(&cpu_dev->kobj, "cpufreq");
-		ret = kobject_move(&data->kobj, &cpu_dev->kobj);
-		if (ret) {
-			pr_err("%s: Failed to move kobj: %d", __func__, ret);
 
+		new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen);
+		if (new_cpu >= 0) {
 			WARN_ON(lock_policy_rwsem_write(cpu));
-			cpumask_set_cpu(cpu, data->cpus);
-
-			write_lock_irqsave(&cpufreq_driver_lock, flags);
-			per_cpu(cpufreq_cpu_data, cpu) = data;
-			write_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
+			update_policy_cpu(policy, new_cpu);
 			unlock_policy_rwsem_write(cpu);
 
-			ret = sysfs_create_link(&cpu_dev->kobj, &data->kobj,
-					"cpufreq");
-			return -EINVAL;
+			if (!frozen) {
+				pr_debug("%s: policy Kobject moved to cpu: %d "
+					 "from: %d\n",__func__, new_cpu, cpu);
+			}
 		}
-
-		WARN_ON(lock_policy_rwsem_write(cpu));
-		update_policy_cpu(data, cpu_dev->id);
-		unlock_policy_rwsem_write(cpu);
-		pr_debug("%s: policy Kobject moved to cpu: %d from: %d\n",
-				__func__, cpu_dev->id, cpu);
 	}
 
 	/* If cpu is last user of policy, free policy */
 	if (cpus == 1) {
-		if (cpufreq_driver->target)
-			__cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
-		lock_policy_rwsem_read(cpu);
-		kobj = &data->kobj;
-		cmp = &data->kobj_unregister;
-		unlock_policy_rwsem_read(cpu);
-		kobject_put(kobj);
-
-		/* we need to make sure that the underlying kobj is actually
-		 * not referenced anymore by anybody before we proceed with
-		 * unloading.
-		 */
-		pr_debug("waiting for dropping of refcount\n");
-		wait_for_completion(cmp);
-		pr_debug("wait complete\n");
-
-		if (cpufreq_driver->exit)
-			cpufreq_driver->exit(data);
-
-		free_cpumask_var(data->related_cpus);
-		free_cpumask_var(data->cpus);
-		kfree(data);
-	} else {
-		pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
-		cpufreq_cpu_put(data);
 		if (cpufreq_driver->target) {
-			__cpufreq_governor(data, CPUFREQ_GOV_START);
-			__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+			ret = __cpufreq_governor(policy,
+					CPUFREQ_GOV_POLICY_EXIT);
+			if (ret) {
+				pr_err("%s: Failed to exit governor\n",
+						__func__);
+				return ret;
+			}
+		}
+
+		if (!frozen) {
+			lock_policy_rwsem_read(cpu);
+			kobj = &policy->kobj;
+			cmp = &policy->kobj_unregister;
+			unlock_policy_rwsem_read(cpu);
+			kobject_put(kobj);
+
+			/*
+			 * We need to make sure that the underlying kobj is
+			 * actually not referenced anymore by anybody before we
+			 * proceed with unloading.
+			 */
+			pr_debug("waiting for dropping of refcount\n");
+			wait_for_completion(cmp);
+			pr_debug("wait complete\n");
+		}
+
+		/*
+		 * Perform the ->exit() even during light-weight tear-down,
+		 * since this is a core component, and is essential for the
+		 * subsequent light-weight ->init() to succeed.
+		 */
+		if (cpufreq_driver->exit)
+			cpufreq_driver->exit(policy);
+
+		/* Remove policy from list of active policies */
+		write_lock_irqsave(&cpufreq_driver_lock, flags);
+		list_del(&policy->policy_list);
+		write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+		if (!frozen)
+			cpufreq_policy_free(policy);
+	} else {
+		if (cpufreq_driver->target) {
+			if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
+					(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
+				pr_err("%s: Failed to start governor\n",
+						__func__);
+				return ret;
+			}
 		}
 	}
 
-	per_cpu(cpufreq_policy_cpu, cpu) = -1;
+	per_cpu(cpufreq_cpu_data, cpu) = NULL;
 	return 0;
 }
 
@@ -1223,7 +1280,7 @@
 	if (cpu_is_offline(cpu))
 		return 0;
 
-	retval = __cpufreq_remove_dev(dev, sif);
+	retval = __cpufreq_remove_dev(dev, sif, false);
 	return retval;
 }
 
@@ -1344,10 +1401,9 @@
 unsigned int cpufreq_get(unsigned int cpu)
 {
 	unsigned int ret_freq = 0;
-	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
 
-	if (!policy)
-		goto out;
+	if (!down_read_trylock(&cpufreq_rwsem))
+		return 0;
 
 	if (unlikely(lock_policy_rwsem_read(cpu)))
 		goto out_policy;
@@ -1357,8 +1413,8 @@
 	unlock_policy_rwsem_read(cpu);
 
 out_policy:
-	cpufreq_cpu_put(policy);
-out:
+	up_read(&cpufreq_rwsem);
+
 	return ret_freq;
 }
 EXPORT_SYMBOL(cpufreq_get);
@@ -1381,23 +1437,23 @@
 	int ret = 0;
 
 	int cpu = smp_processor_id();
-	struct cpufreq_policy *cpu_policy;
+	struct cpufreq_policy *policy;
 
 	pr_debug("suspending cpu %u\n", cpu);
 
 	/* If there's no policy for the boot CPU, we have nothing to do. */
-	cpu_policy = cpufreq_cpu_get(cpu);
-	if (!cpu_policy)
+	policy = cpufreq_cpu_get(cpu);
+	if (!policy)
 		return 0;
 
 	if (cpufreq_driver->suspend) {
-		ret = cpufreq_driver->suspend(cpu_policy);
+		ret = cpufreq_driver->suspend(policy);
 		if (ret)
 			printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
-					"step on CPU %u\n", cpu_policy->cpu);
+					"step on CPU %u\n", policy->cpu);
 	}
 
-	cpufreq_cpu_put(cpu_policy);
+	cpufreq_cpu_put(policy);
 	return ret;
 }
 
@@ -1419,28 +1475,28 @@
 	int ret = 0;
 
 	int cpu = smp_processor_id();
-	struct cpufreq_policy *cpu_policy;
+	struct cpufreq_policy *policy;
 
 	pr_debug("resuming cpu %u\n", cpu);
 
 	/* If there's no policy for the boot CPU, we have nothing to do. */
-	cpu_policy = cpufreq_cpu_get(cpu);
-	if (!cpu_policy)
+	policy = cpufreq_cpu_get(cpu);
+	if (!policy)
 		return;
 
 	if (cpufreq_driver->resume) {
-		ret = cpufreq_driver->resume(cpu_policy);
+		ret = cpufreq_driver->resume(policy);
 		if (ret) {
 			printk(KERN_ERR "cpufreq: resume failed in ->resume "
-					"step on CPU %u\n", cpu_policy->cpu);
+					"step on CPU %u\n", policy->cpu);
 			goto fail;
 		}
 	}
 
-	schedule_work(&cpu_policy->update);
+	schedule_work(&policy->update);
 
 fail:
-	cpufreq_cpu_put(cpu_policy);
+	cpufreq_cpu_put(policy);
 }
 
 static struct syscore_ops cpufreq_syscore_ops = {
@@ -1594,18 +1650,6 @@
 }
 EXPORT_SYMBOL_GPL(cpufreq_driver_target);
 
-int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
-{
-	if (cpufreq_disabled())
-		return 0;
-
-	if (!cpufreq_driver->getavg)
-		return 0;
-
-	return cpufreq_driver->getavg(policy, cpu);
-}
-EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
-
 /*
  * when "event" is CPUFREQ_GOV_LIMITS
  */
@@ -1640,8 +1684,9 @@
 		}
 	}
 
-	if (!try_module_get(policy->governor->owner))
-		return -EINVAL;
+	if (event == CPUFREQ_GOV_POLICY_INIT)
+		if (!try_module_get(policy->governor->owner))
+			return -EINVAL;
 
 	pr_debug("__cpufreq_governor for CPU %u, event %u\n",
 						policy->cpu, event);
@@ -1677,11 +1722,8 @@
 		mutex_unlock(&cpufreq_governor_lock);
 	}
 
-	/* we keep one module reference alive for
-			each CPU governed by this CPU */
-	if ((event != CPUFREQ_GOV_START) || ret)
-		module_put(policy->governor->owner);
-	if ((event == CPUFREQ_GOV_STOP) && !ret)
+	if (((event == CPUFREQ_GOV_POLICY_INIT) && ret) ||
+			((event == CPUFREQ_GOV_POLICY_EXIT) && !ret))
 		module_put(policy->governor->owner);
 
 	return ret;
@@ -1761,7 +1803,7 @@
 	if (!cpu_policy)
 		return -EINVAL;
 
-	memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy));
+	memcpy(policy, cpu_policy, sizeof(*policy));
 
 	cpufreq_cpu_put(cpu_policy);
 	return 0;
@@ -1772,95 +1814,94 @@
  * data   : current policy.
  * policy : policy to be set.
  */
-static int __cpufreq_set_policy(struct cpufreq_policy *data,
-				struct cpufreq_policy *policy)
+static int __cpufreq_set_policy(struct cpufreq_policy *policy,
+				struct cpufreq_policy *new_policy)
 {
 	int ret = 0, failed = 1;
 
-	pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
-		policy->min, policy->max);
+	pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu,
+		new_policy->min, new_policy->max);
 
-	memcpy(&policy->cpuinfo, &data->cpuinfo,
-				sizeof(struct cpufreq_cpuinfo));
+	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-	if (policy->min > data->max || policy->max < data->min) {
+	if (new_policy->min > policy->max || new_policy->max < policy->min) {
 		ret = -EINVAL;
 		goto error_out;
 	}
 
 	/* verify the cpu speed can be set within this limit */
-	ret = cpufreq_driver->verify(policy);
+	ret = cpufreq_driver->verify(new_policy);
 	if (ret)
 		goto error_out;
 
 	/* adjust if necessary - all reasons */
 	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-			CPUFREQ_ADJUST, policy);
+			CPUFREQ_ADJUST, new_policy);
 
 	/* adjust if necessary - hardware incompatibility*/
 	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-			CPUFREQ_INCOMPATIBLE, policy);
+			CPUFREQ_INCOMPATIBLE, new_policy);
 
 	/*
 	 * verify the cpu speed can be set within this limit, which might be
 	 * different to the first one
 	 */
-	ret = cpufreq_driver->verify(policy);
+	ret = cpufreq_driver->verify(new_policy);
 	if (ret)
 		goto error_out;
 
 	/* notification of the new policy */
 	blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-			CPUFREQ_NOTIFY, policy);
+			CPUFREQ_NOTIFY, new_policy);
 
-	data->min = policy->min;
-	data->max = policy->max;
+	policy->min = new_policy->min;
+	policy->max = new_policy->max;
 
 	pr_debug("new min and max freqs are %u - %u kHz\n",
-					data->min, data->max);
+					policy->min, policy->max);
 
 	if (cpufreq_driver->setpolicy) {
-		data->policy = policy->policy;
+		policy->policy = new_policy->policy;
 		pr_debug("setting range\n");
-		ret = cpufreq_driver->setpolicy(policy);
+		ret = cpufreq_driver->setpolicy(new_policy);
 	} else {
-		if (policy->governor != data->governor) {
+		if (new_policy->governor != policy->governor) {
 			/* save old, working values */
-			struct cpufreq_governor *old_gov = data->governor;
+			struct cpufreq_governor *old_gov = policy->governor;
 
 			pr_debug("governor switch\n");
 
 			/* end old governor */
-			if (data->governor) {
-				__cpufreq_governor(data, CPUFREQ_GOV_STOP);
-				unlock_policy_rwsem_write(policy->cpu);
-				__cpufreq_governor(data,
+			if (policy->governor) {
+				__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+				unlock_policy_rwsem_write(new_policy->cpu);
+				__cpufreq_governor(policy,
 						CPUFREQ_GOV_POLICY_EXIT);
-				lock_policy_rwsem_write(policy->cpu);
+				lock_policy_rwsem_write(new_policy->cpu);
 			}
 
 			/* start new governor */
-			data->governor = policy->governor;
-			if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
-				if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) {
+			policy->governor = new_policy->governor;
+			if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {
+				if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) {
 					failed = 0;
 				} else {
-					unlock_policy_rwsem_write(policy->cpu);
-					__cpufreq_governor(data,
+					unlock_policy_rwsem_write(new_policy->cpu);
+					__cpufreq_governor(policy,
 							CPUFREQ_GOV_POLICY_EXIT);
-					lock_policy_rwsem_write(policy->cpu);
+					lock_policy_rwsem_write(new_policy->cpu);
 				}
 			}
 
 			if (failed) {
 				/* new governor failed, so re-start old one */
 				pr_debug("starting governor %s failed\n",
-							data->governor->name);
+							policy->governor->name);
 				if (old_gov) {
-					data->governor = old_gov;
-					__cpufreq_governor(data,
+					policy->governor = old_gov;
+					__cpufreq_governor(policy,
 							CPUFREQ_GOV_POLICY_INIT);
-					__cpufreq_governor(data,
+					__cpufreq_governor(policy,
 							   CPUFREQ_GOV_START);
 				}
 				ret = -EINVAL;
@@ -1869,7 +1910,7 @@
 			/* might be a policy change, too, so fall through */
 		}
 		pr_debug("governor: change or update limits\n");
-		__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+		ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
 	}
 
 error_out:
@@ -1885,11 +1926,11 @@
  */
 int cpufreq_update_policy(unsigned int cpu)
 {
-	struct cpufreq_policy *data = cpufreq_cpu_get(cpu);
-	struct cpufreq_policy policy;
+	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+	struct cpufreq_policy new_policy;
 	int ret;
 
-	if (!data) {
+	if (!policy) {
 		ret = -ENODEV;
 		goto no_policy;
 	}
@@ -1900,34 +1941,34 @@
 	}
 
 	pr_debug("updating policy for CPU %u\n", cpu);
-	memcpy(&policy, data, sizeof(struct cpufreq_policy));
-	policy.min = data->user_policy.min;
-	policy.max = data->user_policy.max;
-	policy.policy = data->user_policy.policy;
-	policy.governor = data->user_policy.governor;
+	memcpy(&new_policy, policy, sizeof(*policy));
+	new_policy.min = policy->user_policy.min;
+	new_policy.max = policy->user_policy.max;
+	new_policy.policy = policy->user_policy.policy;
+	new_policy.governor = policy->user_policy.governor;
 
 	/*
 	 * BIOS might change freq behind our back
 	 * -> ask driver for current freq and notify governors about a change
 	 */
 	if (cpufreq_driver->get) {
-		policy.cur = cpufreq_driver->get(cpu);
-		if (!data->cur) {
+		new_policy.cur = cpufreq_driver->get(cpu);
+		if (!policy->cur) {
 			pr_debug("Driver did not initialize current freq");
-			data->cur = policy.cur;
+			policy->cur = new_policy.cur;
 		} else {
-			if (data->cur != policy.cur && cpufreq_driver->target)
-				cpufreq_out_of_sync(cpu, data->cur,
-								policy.cur);
+			if (policy->cur != new_policy.cur && cpufreq_driver->target)
+				cpufreq_out_of_sync(cpu, policy->cur,
+								new_policy.cur);
 		}
 	}
 
-	ret = __cpufreq_set_policy(data, &policy);
+	ret = __cpufreq_set_policy(policy, &new_policy);
 
 	unlock_policy_rwsem_write(cpu);
 
 fail:
-	cpufreq_cpu_put(data);
+	cpufreq_cpu_put(policy);
 no_policy:
 	return ret;
 }
@@ -1938,21 +1979,26 @@
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	struct device *dev;
+	bool frozen = false;
 
 	dev = get_cpu_device(cpu);
 	if (dev) {
-		switch (action) {
+
+		if (action & CPU_TASKS_FROZEN)
+			frozen = true;
+
+		switch (action & ~CPU_TASKS_FROZEN) {
 		case CPU_ONLINE:
-		case CPU_ONLINE_FROZEN:
-			cpufreq_add_dev(dev, NULL);
+			__cpufreq_add_dev(dev, NULL, frozen);
+			cpufreq_update_policy(cpu);
 			break;
+
 		case CPU_DOWN_PREPARE:
-		case CPU_DOWN_PREPARE_FROZEN:
-			__cpufreq_remove_dev(dev, NULL);
+			__cpufreq_remove_dev(dev, NULL, frozen);
 			break;
+
 		case CPU_DOWN_FAILED:
-		case CPU_DOWN_FAILED_FROZEN:
-			cpufreq_add_dev(dev, NULL);
+			__cpufreq_add_dev(dev, NULL, frozen);
 			break;
 		}
 	}
@@ -2059,9 +2105,13 @@
 	subsys_interface_unregister(&cpufreq_interface);
 	unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
 
+	down_write(&cpufreq_rwsem);
 	write_lock_irqsave(&cpufreq_driver_lock, flags);
+
 	cpufreq_driver = NULL;
+
 	write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+	up_write(&cpufreq_rwsem);
 
 	return 0;
 }
@@ -2074,10 +2124,8 @@
 	if (cpufreq_disabled())
 		return -ENODEV;
 
-	for_each_possible_cpu(cpu) {
-		per_cpu(cpufreq_policy_cpu, cpu) = -1;
+	for_each_possible_cpu(cpu)
 		init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
-	}
 
 	cpufreq_global_kobject = kobject_create();
 	BUG_ON(!cpufreq_global_kobject);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index f97cb3d..f62d822 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -11,19 +11,7 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/cpufreq.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/notifier.h>
-#include <linux/percpu-defs.h>
 #include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
 #include "cpufreq_governor.h"
 
 /* Conservative governor macros */
@@ -79,8 +67,6 @@
 			return;
 
 		dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
-		if (dbs_info->requested_freq > policy->max)
-			dbs_info->requested_freq = policy->max;
 
 		__cpufreq_driver_target(policy, dbs_info->requested_freq,
 			CPUFREQ_RELATION_H);
@@ -101,8 +87,6 @@
 			return;
 
 		dbs_info->requested_freq -= get_freq_target(cs_tuners, policy);
-		if (dbs_info->requested_freq < policy->min)
-			dbs_info->requested_freq = policy->min;
 
 		__cpufreq_driver_target(policy, dbs_info->requested_freq,
 				CPUFREQ_RELATION_L);
@@ -329,7 +313,7 @@
 {
 	struct cs_dbs_tuners *tuners;
 
-	tuners = kzalloc(sizeof(struct cs_dbs_tuners), GFP_KERNEL);
+	tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
 	if (!tuners) {
 		pr_err("%s: kzalloc failed\n", __func__);
 		return -ENOMEM;
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index e59afaa..0806c31 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -16,15 +16,9 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <asm/cputime.h>
-#include <linux/cpufreq.h>
-#include <linux/cpumask.h>
 #include <linux/export.h>
 #include <linux/kernel_stat.h>
-#include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
 
 #include "cpufreq_governor.h"
 
@@ -53,7 +47,7 @@
 
 	policy = cdbs->cur_policy;
 
-	/* Get Absolute Load (in terms of freq for ondemand gov) */
+	/* Get Absolute Load */
 	for_each_cpu(j, policy->cpus) {
 		struct cpu_dbs_common_info *j_cdbs;
 		u64 cur_wall_time, cur_idle_time;
@@ -104,14 +98,6 @@
 
 		load = 100 * (wall_time - idle_time) / wall_time;
 
-		if (dbs_data->cdata->governor == GOV_ONDEMAND) {
-			int freq_avg = __cpufreq_driver_getavg(policy, j);
-			if (freq_avg <= 0)
-				freq_avg = policy->cur;
-
-			load *= freq_avg;
-		}
-
 		if (load > max_load)
 			max_load = load;
 	}
@@ -133,8 +119,18 @@
 {
 	int i;
 
+	if (!policy->governor_enabled)
+		return;
+
 	if (!all_cpus) {
-		__gov_queue_work(smp_processor_id(), dbs_data, delay);
+		/*
+		 * Use raw_smp_processor_id() to avoid preemptible warnings.
+		 * We know that this is only called with all_cpus == false from
+		 * works that have been queued with *_work_on() functions and
+		 * those works are canceled during CPU_DOWN_PREPARE so they
+		 * can't possibly run on any other CPU.
+		 */
+		__gov_queue_work(raw_smp_processor_id(), dbs_data, delay);
 	} else {
 		for_each_cpu(i, policy->cpus)
 			__gov_queue_work(i, dbs_data, delay);
@@ -244,7 +240,7 @@
 
 		policy->governor_data = dbs_data;
 
-		/* policy latency is in nS. Convert it to uS first */
+		/* policy latency is in ns. Convert it to us first */
 		latency = policy->cpuinfo.transition_latency / 1000;
 		if (latency == 0)
 			latency = 1;
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index d5f12b4..88cd39f 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -18,19 +18,18 @@
 #define _CPUFREQ_GOVERNOR_H
 
 #include <linux/cpufreq.h>
-#include <linux/kobject.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/workqueue.h>
-#include <linux/sysfs.h>
 
 /*
  * The polling frequency depends on the capability of the processor. Default
  * polling frequency is 1000 times the transition latency of the processor. The
- * governor will work on any processor with transition latency <= 10mS, using
+ * governor will work on any processor with transition latency <= 10ms, using
  * appropriate sampling rate.
  *
- * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL)
- * this governor will not work. All times here are in uS.
+ * For CPUs with transition latency > 10ms (mostly drivers with CPUFREQ_ETERNAL)
+ * this governor will not work. All times here are in us (micro seconds).
  */
 #define MIN_SAMPLING_RATE_RATIO			(2)
 #define LATENCY_MULTIPLIER			(1000)
@@ -163,13 +162,12 @@
 	unsigned int enable:1;
 };
 
-/* Per policy Governers sysfs tunables */
+/* Per policy Governors sysfs tunables */
 struct od_dbs_tuners {
 	unsigned int ignore_nice_load;
 	unsigned int sampling_rate;
 	unsigned int sampling_down_factor;
 	unsigned int up_threshold;
-	unsigned int adj_up_threshold;
 	unsigned int powersave_bias;
 	unsigned int io_is_busy;
 };
@@ -183,7 +181,7 @@
 	unsigned int freq_step;
 };
 
-/* Common Governer data across policies */
+/* Common Governor data across policies */
 struct dbs_data;
 struct common_dbs_data {
 	/* Common across governors */
@@ -207,7 +205,7 @@
 	void *gov_ops;
 };
 
-/* Governer Per policy data */
+/* Governor Per policy data */
 struct dbs_data {
 	struct common_dbs_data *cdata;
 	unsigned int min_sampling_rate;
@@ -223,7 +221,7 @@
 	void (*powersave_bias_init_cpu)(int cpu);
 	unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
 			unsigned int freq_next, unsigned int relation);
-	void (*freq_increase)(struct cpufreq_policy *p, unsigned int freq);
+	void (*freq_increase)(struct cpufreq_policy *policy, unsigned int freq);
 };
 
 struct cs_ops {
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index c087347..32f26f6 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -12,28 +12,16 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/cpufreq.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
+#include <linux/cpu.h>
 #include <linux/percpu-defs.h>
 #include <linux/slab.h>
-#include <linux/sysfs.h>
 #include <linux/tick.h>
-#include <linux/types.h>
-#include <linux/cpu.h>
-
 #include "cpufreq_governor.h"
 
 /* On-demand governor macros */
-#define DEF_FREQUENCY_DOWN_DIFFERENTIAL		(10)
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
 #define DEF_SAMPLING_DOWN_FACTOR		(1)
 #define MAX_SAMPLING_DOWN_FACTOR		(100000)
-#define MICRO_FREQUENCY_DOWN_DIFFERENTIAL	(3)
 #define MICRO_FREQUENCY_UP_THRESHOLD		(95)
 #define MICRO_FREQUENCY_MIN_SAMPLE_RATE		(10000)
 #define MIN_FREQUENCY_UP_THRESHOLD		(11)
@@ -144,31 +132,27 @@
 	}
 }
 
-static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
+static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
 {
-	struct dbs_data *dbs_data = p->governor_data;
+	struct dbs_data *dbs_data = policy->governor_data;
 	struct od_dbs_tuners *od_tuners = dbs_data->tuners;
 
 	if (od_tuners->powersave_bias)
-		freq = od_ops.powersave_bias_target(p, freq,
+		freq = od_ops.powersave_bias_target(policy, freq,
 				CPUFREQ_RELATION_H);
-	else if (p->cur == p->max)
+	else if (policy->cur == policy->max)
 		return;
 
-	__cpufreq_driver_target(p, freq, od_tuners->powersave_bias ?
+	__cpufreq_driver_target(policy, freq, od_tuners->powersave_bias ?
 			CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
 }
 
 /*
  * Every sampling_rate, we check, if current idle time is less than 20%
- * (default), then we try to increase frequency. Every sampling_rate, we look
- * for the lowest frequency which can sustain the load while keeping idle time
- * over 30%. If such a frequency exist, we try to decrease to this frequency.
- *
- * Any frequency increase takes it to the maximum frequency. Frequency reduction
- * happens at minimum steps of 5% (default) of current frequency
+ * (default), then we try to increase frequency. Else, we adjust the frequency
+ * proportional to load.
  */
-static void od_check_cpu(int cpu, unsigned int load_freq)
+static void od_check_cpu(int cpu, unsigned int load)
 {
 	struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
 	struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
@@ -178,36 +162,21 @@
 	dbs_info->freq_lo = 0;
 
 	/* Check for frequency increase */
-	if (load_freq > od_tuners->up_threshold * policy->cur) {
+	if (load > od_tuners->up_threshold) {
 		/* If switching to max speed, apply sampling_down_factor */
 		if (policy->cur < policy->max)
 			dbs_info->rate_mult =
 				od_tuners->sampling_down_factor;
 		dbs_freq_increase(policy, policy->max);
 		return;
-	}
-
-	/* Check for frequency decrease */
-	/* if we cannot reduce the frequency anymore, break out early */
-	if (policy->cur == policy->min)
-		return;
-
-	/*
-	 * The optimal frequency is the frequency that is the lowest that can
-	 * support the current CPU usage without triggering the up policy. To be
-	 * safe, we focus 10 points under the threshold.
-	 */
-	if (load_freq < od_tuners->adj_up_threshold
-			* policy->cur) {
+	} else {
+		/* Calculate the next frequency proportional to load */
 		unsigned int freq_next;
-		freq_next = load_freq / od_tuners->adj_up_threshold;
+		freq_next = load * policy->cpuinfo.max_freq / 100;
 
 		/* No longer fully busy, reset rate_mult */
 		dbs_info->rate_mult = 1;
 
-		if (freq_next < policy->min)
-			freq_next = policy->min;
-
 		if (!od_tuners->powersave_bias) {
 			__cpufreq_driver_target(policy, freq_next,
 					CPUFREQ_RELATION_L);
@@ -374,9 +343,6 @@
 			input < MIN_FREQUENCY_UP_THRESHOLD) {
 		return -EINVAL;
 	}
-	/* Calculate the new adj_up_threshold */
-	od_tuners->adj_up_threshold += input;
-	od_tuners->adj_up_threshold -= od_tuners->up_threshold;
 
 	od_tuners->up_threshold = input;
 	return count;
@@ -513,7 +479,7 @@
 	u64 idle_time;
 	int cpu;
 
-	tuners = kzalloc(sizeof(struct od_dbs_tuners), GFP_KERNEL);
+	tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
 	if (!tuners) {
 		pr_err("%s: kzalloc failed\n", __func__);
 		return -ENOMEM;
@@ -525,8 +491,6 @@
 	if (idle_time != -1ULL) {
 		/* Idle micro accounting is supported. Use finer thresholds */
 		tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
-		tuners->adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
-			MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
 		/*
 		 * In nohz/micro accounting case we set the minimum frequency
 		 * not depending on HZ, but fixed (very low). The deferred
@@ -535,8 +499,6 @@
 		dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
 	} else {
 		tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
-		tuners->adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
-			DEF_FREQUENCY_DOWN_DIFFERENTIAL;
 
 		/* For correct statistics, we need 10 ticks for each measure */
 		dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index 9fef7d6..cf117de 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -12,10 +12,9 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/cpufreq.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 static int cpufreq_governor_performance(struct cpufreq_policy *policy,
 					unsigned int event)
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 32109a1..e3b874c 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -12,10 +12,9 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/cpufreq.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
 					unsigned int event)
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d37568c..04452f0 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -9,17 +9,10 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/kernel.h>
-#include <linux/slab.h>
 #include <linux/cpu.h>
-#include <linux/sysfs.h>
 #include <linux/cpufreq.h>
 #include <linux/module.h>
-#include <linux/jiffies.h>
-#include <linux/percpu.h>
-#include <linux/kobject.h>
-#include <linux/spinlock.h>
-#include <linux/notifier.h>
+#include <linux/slab.h>
 #include <asm/cputime.h>
 
 static spinlock_t cpufreq_stats_lock;
@@ -200,22 +193,22 @@
 {
 	unsigned int i, j, count = 0, ret = 0;
 	struct cpufreq_stats *stat;
-	struct cpufreq_policy *data;
+	struct cpufreq_policy *current_policy;
 	unsigned int alloc_size;
 	unsigned int cpu = policy->cpu;
 	if (per_cpu(cpufreq_stats_table, cpu))
 		return -EBUSY;
-	stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
+	stat = kzalloc(sizeof(*stat), GFP_KERNEL);
 	if ((stat) == NULL)
 		return -ENOMEM;
 
-	data = cpufreq_cpu_get(cpu);
-	if (data == NULL) {
+	current_policy = cpufreq_cpu_get(cpu);
+	if (current_policy == NULL) {
 		ret = -EINVAL;
 		goto error_get_fail;
 	}
 
-	ret = sysfs_create_group(&data->kobj, &stats_attr_group);
+	ret = sysfs_create_group(&current_policy->kobj, &stats_attr_group);
 	if (ret)
 		goto error_out;
 
@@ -258,10 +251,10 @@
 	stat->last_time = get_jiffies_64();
 	stat->last_index = freq_table_get_index(stat, policy->cur);
 	spin_unlock(&cpufreq_stats_lock);
-	cpufreq_cpu_put(data);
+	cpufreq_cpu_put(current_policy);
 	return 0;
 error_out:
-	cpufreq_cpu_put(data);
+	cpufreq_cpu_put(current_policy);
 error_get_fail:
 	kfree(stat);
 	per_cpu(cpufreq_stats_table, cpu) = NULL;
@@ -348,16 +341,10 @@
 	unsigned int cpu = (unsigned long)hcpu;
 
 	switch (action) {
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		cpufreq_update_policy(cpu);
-		break;
 	case CPU_DOWN_PREPARE:
-	case CPU_DOWN_PREPARE_FROZEN:
 		cpufreq_stats_free_sysfs(cpu);
 		break;
 	case CPU_DEAD:
-	case CPU_DEAD_FROZEN:
 		cpufreq_stats_free_table(cpu);
 		break;
 	}
@@ -390,8 +377,6 @@
 		return ret;
 
 	register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
-	for_each_online_cpu(cpu)
-		cpufreq_update_policy(cpu);
 
 	ret = cpufreq_register_notifier(&notifier_trans_block,
 				CPUFREQ_TRANSITION_NOTIFIER);
diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c
index ee142c4..cb8276d 100644
--- a/drivers/cpufreq/cris-artpec3-cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -111,7 +111,6 @@
 	.init	= cris_freq_cpu_init,
 	.exit	= cris_freq_cpu_exit,
 	.name	= "cris_freq",
-	.owner	= THIS_MODULE,
 	.attr	= cris_freq_attr,
 };
 
diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c
index 1295223..72328f7 100644
--- a/drivers/cpufreq/cris-etraxfs-cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -108,7 +108,6 @@
 	.init = cris_freq_cpu_init,
 	.exit = cris_freq_cpu_exit,
 	.name = "cris_freq",
-	.owner = THIS_MODULE,
 	.attr = cris_freq_attr,
 };
 
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index a60efae..09f64cc 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -54,7 +54,7 @@
 /* Minimum necessary to get acpi_processor_get_bios_limit() working */
 static int eps_acpi_init(void)
 {
-	eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance),
+	eps_acpi_cpu_perf = kzalloc(sizeof(*eps_acpi_cpu_perf),
 				      GFP_KERNEL);
 	if (!eps_acpi_cpu_perf)
 		return -ENOMEM;
@@ -366,7 +366,7 @@
 		states = 2;
 
 	/* Allocate private data and frequency table for current cpu */
-	centaur = kzalloc(sizeof(struct eps_cpu_data)
+	centaur = kzalloc(sizeof(*centaur)
 		    + (states + 1) * sizeof(struct cpufreq_frequency_table),
 		    GFP_KERNEL);
 	if (!centaur)
@@ -436,7 +436,6 @@
 	.exit		= eps_cpu_exit,
 	.get		= eps_get,
 	.name		= "e_powersaver",
-	.owner		= THIS_MODULE,
 	.attr		= eps_attr,
 };
 
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index 658d860..823a400 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -274,7 +274,6 @@
 	.init		= elanfreq_cpu_init,
 	.exit		= elanfreq_cpu_exit,
 	.name		= "elanfreq",
-	.owner		= THIS_MODULE,
 	.attr		= elanfreq_attr,
 };
 
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 0d32f02..0fac344 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -289,7 +289,7 @@
 {
 	int ret = -EINVAL;
 
-	exynos_info = kzalloc(sizeof(struct exynos_dvfs_info), GFP_KERNEL);
+	exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
 	if (!exynos_info)
 		return -ENOMEM;
 
@@ -332,7 +332,6 @@
 	regulator_put(arm_regulator);
 err_vdd_arm:
 	kfree(exynos_info);
-	pr_debug("%s: failed initialization\n", __func__);
 	return -EINVAL;
 }
 late_initcall(exynos_cpufreq_init);
diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h
index 92b852e..7f25cee 100644
--- a/drivers/cpufreq/exynos-cpufreq.h
+++ b/drivers/cpufreq/exynos-cpufreq.h
@@ -43,6 +43,27 @@
 	bool (*need_apll_change)(unsigned int, unsigned int);
 };
 
+#ifdef CONFIG_ARM_EXYNOS4210_CPUFREQ
 extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
+#else
+static inline int exynos4210_cpufreq_init(struct exynos_dvfs_info *info)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+#ifdef CONFIG_ARM_EXYNOS4X12_CPUFREQ
 extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
+#else
+static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ
 extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
+#else
+static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
+{
+	return -EOPNOTSUPP;
+}
+#endif
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index 0c74018..d514c15 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -238,6 +238,9 @@
 	freqs.old = dvfs_info->cur_frequency;
 	freqs.new = freq_table[index].frequency;
 
+	if (freqs.old == freqs.new)
+		goto out;
+
 	cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
 
 	/* Set the target frequency in all C0_3_PSTATE register */
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index f0d8741..f111454a 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -11,10 +11,8 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/cpufreq.h>
+#include <linux/module.h>
 
 /*********************************************************************
  *                     FREQUENCY TABLE HELPERS                       *
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index 3dfc99b..70442c7 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -183,7 +183,7 @@
  * gx_detect_chipset:
  *
  **/
-static __init struct pci_dev *gx_detect_chipset(void)
+static struct pci_dev * __init gx_detect_chipset(void)
 {
 	struct pci_dev *gx_pci = NULL;
 
@@ -446,7 +446,6 @@
 	.target		= cpufreq_gx_target,
 	.init		= cpufreq_gx_cpu_init,
 	.name		= "gx-suspmod",
-	.owner		= THIS_MODULE,
 };
 
 static int __init cpufreq_gx_init(void)
@@ -466,7 +465,7 @@
 
 	pr_debug("geode suspend modulation available.\n");
 
-	params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
+	params = kzalloc(sizeof(*params), GFP_KERNEL);
 	if (params == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c
index b61b5a3..794123f 100644
--- a/drivers/cpufreq/highbank-cpufreq.c
+++ b/drivers/cpufreq/highbank-cpufreq.c
@@ -69,24 +69,18 @@
 	if (!of_machine_is_compatible("calxeda,highbank"))
 		return -ENODEV;
 
-	for_each_child_of_node(of_find_node_by_path("/cpus"), np)
-		if (of_get_property(np, "operating-points", NULL))
-			break;
+	cpu_dev = get_cpu_device(0);
+	if (!cpu_dev) {
+		pr_err("failed to get highbank cpufreq device\n");
+		return -ENODEV;
+	}
 
+	np = of_node_get(cpu_dev->of_node);
 	if (!np) {
 		pr_err("failed to find highbank cpufreq node\n");
 		return -ENOENT;
 	}
 
-	cpu_dev = get_cpu_device(0);
-	if (!cpu_dev) {
-		pr_err("failed to get highbank cpufreq device\n");
-		ret = -ENODEV;
-		goto out_put_node;
-	}
-
-	cpu_dev->of_node = np;
-
 	cpu_clk = clk_get(cpu_dev, NULL);
 	if (IS_ERR(cpu_clk)) {
 		ret = PTR_ERR(cpu_clk);
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index 573c14e..3e14f03 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -274,7 +274,7 @@
 
 	pr_debug("acpi_cpufreq_cpu_init\n");
 
-	data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return (-ENOMEM);
 
@@ -304,7 +304,7 @@
 	}
 
 	/* alloc freq_table */
-	data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) *
+	data->freq_table = kmalloc(sizeof(*data->freq_table) *
 	                           (data->acpi_data.state_count + 1),
 	                           GFP_KERNEL);
 	if (!data->freq_table) {
@@ -409,7 +409,6 @@
 	.init		= acpi_cpufreq_cpu_init,
 	.exit		= acpi_cpufreq_cpu_exit,
 	.name		= "acpi-cpufreq",
-	.owner		= THIS_MODULE,
 	.attr           = acpi_cpufreq_attr,
 };
 
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index e37cdae..3e39654 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -117,28 +117,11 @@
 	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
 	 *  - Disable pll2_pfd2_396m_clk
 	 */
-	clk_prepare_enable(pll2_pfd2_396m_clk);
 	clk_set_parent(step_clk, pll2_pfd2_396m_clk);
 	clk_set_parent(pll1_sw_clk, step_clk);
 	if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
 		clk_set_rate(pll1_sys_clk, freqs.new * 1000);
-		/*
-		 * If we are leaving 396 MHz set-point, we need to enable
-		 * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
-		 * their use count correct.
-		 */
-		if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
-			clk_prepare_enable(pll1_sys_clk);
-			clk_disable_unprepare(pll2_pfd2_396m_clk);
-		}
 		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
-		clk_disable_unprepare(pll2_pfd2_396m_clk);
-	} else {
-		/*
-		 * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
-		 * to provide the frequency.
-		 */
-		clk_disable_unprepare(pll1_sys_clk);
 	}
 
 	/* Ensure the arm clock divider is what we expect */
@@ -221,14 +204,12 @@
 
 	cpu_dev = &pdev->dev;
 
-	np = of_find_node_by_path("/cpus/cpu@0");
+	np = of_node_get(cpu_dev->of_node);
 	if (!np) {
 		dev_err(cpu_dev, "failed to find cpu0 node\n");
 		return -ENOENT;
 	}
 
-	cpu_dev->of_node = np;
-
 	arm_clk = devm_clk_get(cpu_dev, "arm");
 	pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys");
 	pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw");
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 7cde885..6efd96c 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -665,7 +665,6 @@
 	.init		= intel_pstate_cpu_init,
 	.exit		= intel_pstate_cpu_exit,
 	.name		= "intel_pstate",
-	.owner		= THIS_MODULE,
 };
 
 static int __initdata no_load;
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index c233ea6..ba10658 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -14,7 +14,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/cpufreq.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <asm/proc-fns.h>
@@ -158,7 +158,6 @@
 	.init	= kirkwood_cpufreq_cpu_init,
 	.exit	= kirkwood_cpufreq_cpu_exit,
 	.name	= "kirkwood-cpufreq",
-	.owner	= THIS_MODULE,
 	.attr	= kirkwood_cpufreq_attr,
 };
 
@@ -175,9 +174,11 @@
 	if (IS_ERR(priv.base))
 		return PTR_ERR(priv.base);
 
-	np = of_find_node_by_path("/cpus/cpu@0");
-	if (!np)
+	np = of_cpu_device_node_get(0);
+	if (!np) {
+		dev_err(&pdev->dev, "failed to get cpu device node\n");
 		return -ENODEV;
+	}
 
 	priv.cpu_clk = of_clk_get_by_name(np, "cpu_clk");
 	if (IS_ERR(priv.cpu_clk)) {
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 8c49261..4ada1cc 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -948,7 +948,6 @@
 	.init	= longhaul_cpu_init,
 	.exit	= longhaul_cpu_exit,
 	.name	= "longhaul",
-	.owner	= THIS_MODULE,
 	.attr	= longhaul_attr,
 };
 
diff --git a/drivers/cpufreq/longrun.c b/drivers/cpufreq/longrun.c
index 0fe041d..5aa0316 100644
--- a/drivers/cpufreq/longrun.c
+++ b/drivers/cpufreq/longrun.c
@@ -286,7 +286,6 @@
 	.get		= longrun_get,
 	.init		= longrun_cpu_init,
 	.name		= "longrun",
-	.owner		= THIS_MODULE,
 };
 
 static const struct x86_cpu_id longrun_ids[] = {
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index 9536852c..7bc3c44 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -158,7 +158,6 @@
 };
 
 static struct cpufreq_driver loongson2_cpufreq_driver = {
-	.owner = THIS_MODULE,
 	.name = "loongson2",
 	.init = loongson2_cpufreq_cpu_init,
 	.verify = loongson2_cpufreq_verify,
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index cdd6291..6168d77 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -24,7 +24,7 @@
 #include <linux/completion.h>
 #include <linux/mutex.h>
 #include <linux/time.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
 
 #define DBG(fmt...) pr_debug(fmt)
 
@@ -190,7 +190,6 @@
 
 static struct cpufreq_driver maple_cpufreq_driver = {
 	.name		= "maple",
-	.owner		= THIS_MODULE,
 	.flags		= CPUFREQ_CONST_LOOPS,
 	.init		= maple_cpufreq_cpu_init,
 	.verify		= maple_cpufreq_verify,
@@ -201,7 +200,6 @@
 
 static int __init maple_cpufreq_init(void)
 {
-	struct device_node *cpus;
 	struct device_node *cpunode;
 	unsigned int psize;
 	unsigned long max_freq;
@@ -217,24 +215,11 @@
 	    !of_machine_is_compatible("Momentum,Apache"))
 		return 0;
 
-	cpus = of_find_node_by_path("/cpus");
-	if (cpus == NULL) {
-		DBG("No /cpus node !\n");
-		return -ENODEV;
-	}
-
 	/* Get first CPU node */
-	for (cpunode = NULL;
-	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
-		const u32 *reg = of_get_property(cpunode, "reg", NULL);
-		if (reg == NULL || (*reg) != 0)
-			continue;
-		if (!strcmp(cpunode->type, "cpu"))
-			break;
-	}
+	cpunode = of_cpu_device_node_get(0);
 	if (cpunode == NULL) {
 		printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
-		goto bail_cpus;
+		goto bail_noprops;
 	}
 
 	/* Check 970FX for now */
@@ -290,14 +275,11 @@
 	rc = cpufreq_register_driver(&maple_cpufreq_driver);
 
 	of_node_put(cpunode);
-	of_node_put(cpus);
 
 	return rc;
 
 bail_noprops:
 	of_node_put(cpunode);
-bail_cpus:
-	of_node_put(cpus);
 
 	return rc;
 }
diff --git a/drivers/cpufreq/mperf.c b/drivers/cpufreq/mperf.c
deleted file mode 100644
index 911e193..0000000
--- a/drivers/cpufreq/mperf.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/cpufreq.h>
-#include <linux/slab.h>
-
-#include "mperf.h"
-
-static DEFINE_PER_CPU(struct aperfmperf, acfreq_old_perf);
-
-/* Called via smp_call_function_single(), on the target CPU */
-static void read_measured_perf_ctrs(void *_cur)
-{
-	struct aperfmperf *am = _cur;
-
-	get_aperfmperf(am);
-}
-
-/*
- * Return the measured active (C0) frequency on this CPU since last call
- * to this function.
- * Input: cpu number
- * Return: Average CPU frequency in terms of max frequency (zero on error)
- *
- * We use IA32_MPERF and IA32_APERF MSRs to get the measured performance
- * over a period of time, while CPU is in C0 state.
- * IA32_MPERF counts at the rate of max advertised frequency
- * IA32_APERF counts at the rate of actual CPU frequency
- * Only IA32_APERF/IA32_MPERF ratio is architecturally defined and
- * no meaning should be associated with absolute values of these MSRs.
- */
-unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy,
-					unsigned int cpu)
-{
-	struct aperfmperf perf;
-	unsigned long ratio;
-	unsigned int retval;
-
-	if (smp_call_function_single(cpu, read_measured_perf_ctrs, &perf, 1))
-		return 0;
-
-	ratio = calc_aperfmperf_ratio(&per_cpu(acfreq_old_perf, cpu), &perf);
-	per_cpu(acfreq_old_perf, cpu) = perf;
-
-	retval = (policy->cpuinfo.max_freq * ratio) >> APERFMPERF_SHIFT;
-
-	return retval;
-}
-EXPORT_SYMBOL_GPL(cpufreq_get_measured_perf);
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/mperf.h b/drivers/cpufreq/mperf.h
deleted file mode 100644
index 5dbf295..0000000
--- a/drivers/cpufreq/mperf.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- *  (c) 2010 Advanced Micro Devices, Inc.
- *  Your use of this code is subject to the terms and conditions of the
- *  GNU general public license version 2. See "COPYING" or
- *  http://www.gnu.org/licenses/gpl.html
- */
-
-unsigned int cpufreq_get_measured_perf(struct cpufreq_policy *policy,
-					unsigned int cpu);
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 9ee7817..2f0a2a6 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -279,7 +279,6 @@
 	.exit		= cpufreq_p4_cpu_exit,
 	.get		= cpufreq_p4_get,
 	.name		= "p4-clockmod",
-	.owner		= THIS_MODULE,
 	.attr		= p4clockmod_attr,
 };
 
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index b704da4..534e43a 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -297,7 +297,6 @@
 
 static struct cpufreq_driver pas_cpufreq_driver = {
 	.name		= "pas-cpufreq",
-	.owner		= THIS_MODULE,
 	.flags		= CPUFREQ_CONST_LOOPS,
 	.init		= pas_cpufreq_cpu_init,
 	.exit		= pas_cpufreq_cpu_exit,
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 1581fcc..d81c4e5 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -587,7 +587,6 @@
 	.init = pcc_cpufreq_cpu_init,
 	.exit = pcc_cpufreq_cpu_exit,
 	.name = "pcc-cpufreq",
-	.owner = THIS_MODULE,
 };
 
 static int __init pcc_cpufreq_init(void)
diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c
index 3104fad..a096cd3 100644
--- a/drivers/cpufreq/pmac32-cpufreq.c
+++ b/drivers/cpufreq/pmac32-cpufreq.c
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/hardirq.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
@@ -477,7 +478,6 @@
 	.flags		= CPUFREQ_PM_NO_WARN,
 	.attr		= pmac_cpu_freqs_attr,
 	.name		= "powermac",
-	.owner		= THIS_MODULE,
 };
 
 
@@ -649,8 +649,8 @@
 	if (strstr(cmd_line, "nocpufreq"))
 		return 0;
 
-	/* Assume only one CPU */
-	cpunode = of_find_node_by_type(NULL, "cpu");
+	/* Get first CPU node */
+	cpunode = of_cpu_device_node_get(0);
 	if (!cpunode)
 		goto out;
 
diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c
index 7ba4234..3a51ad7 100644
--- a/drivers/cpufreq/pmac64-cpufreq.c
+++ b/drivers/cpufreq/pmac64-cpufreq.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/mutex.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
@@ -371,7 +372,6 @@
 
 static struct cpufreq_driver g5_cpufreq_driver = {
 	.name		= "powermac",
-	.owner		= THIS_MODULE,
 	.flags		= CPUFREQ_CONST_LOOPS,
 	.init		= g5_cpufreq_cpu_init,
 	.verify		= g5_cpufreq_verify,
@@ -383,9 +383,8 @@
 
 #ifdef CONFIG_PMAC_SMU
 
-static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
+static int __init g5_neo2_cpufreq_init(struct device_node *cpunode)
 {
-	struct device_node *cpunode;
 	unsigned int psize, ssize;
 	unsigned long max_freq;
 	char *freq_method, *volt_method;
@@ -405,20 +404,6 @@
 	else
 		return -ENODEV;
 
-	/* Get first CPU node */
-	for (cpunode = NULL;
-	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
-		const u32 *reg = of_get_property(cpunode, "reg", NULL);
-		if (reg == NULL || (*reg) != 0)
-			continue;
-		if (!strcmp(cpunode->type, "cpu"))
-			break;
-	}
-	if (cpunode == NULL) {
-		printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
-		return -ENODEV;
-	}
-
 	/* Check 970FX for now */
 	valp = of_get_property(cpunode, "cpu-version", NULL);
 	if (!valp) {
@@ -447,9 +432,8 @@
 		if (!shdr)
 			goto bail_noprops;
 		g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
-		ssize = (shdr->len * sizeof(u32)) -
-			sizeof(struct smu_sdbp_header);
-		g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
+		ssize = (shdr->len * sizeof(u32)) - sizeof(*shdr);
+		g5_fvt_count = ssize / sizeof(*g5_fvt_table);
 		g5_fvt_cur = 0;
 
 		/* Sanity checking */
@@ -537,9 +521,9 @@
 #endif /* CONFIG_PMAC_SMU */
 
 
-static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
+static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
 {
-	struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
+	struct device_node *cpuid = NULL, *hwclock = NULL;
 	const u8 *eeprom = NULL;
 	const u32 *valp;
 	u64 max_freq, min_freq, ih, il;
@@ -548,17 +532,6 @@
 	DBG("cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and"
 	    " RackMac3,1...\n");
 
-	/* Get first CPU node */
-	for (cpunode = NULL;
-	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
-		if (!strcmp(cpunode->type, "cpu"))
-			break;
-	}
-	if (cpunode == NULL) {
-		printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
-		return -ENODEV;
-	}
-
 	/* Lookup the cpuid eeprom node */
         cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
 	if (cpuid != NULL)
@@ -718,25 +691,25 @@
 
 static int __init g5_cpufreq_init(void)
 {
-	struct device_node *cpus;
+	struct device_node *cpunode;
 	int rc = 0;
 
-	cpus = of_find_node_by_path("/cpus");
-	if (cpus == NULL) {
-		DBG("No /cpus node !\n");
+	/* Get first CPU node */
+	cpunode = of_cpu_device_node_get(0);
+	if (cpunode == NULL) {
+		pr_err("cpufreq: Can't find any CPU node\n");
 		return -ENODEV;
 	}
 
 	if (of_machine_is_compatible("PowerMac7,2") ||
 	    of_machine_is_compatible("PowerMac7,3") ||
 	    of_machine_is_compatible("RackMac3,1"))
-		rc = g5_pm72_cpufreq_init(cpus);
+		rc = g5_pm72_cpufreq_init(cpunode);
 #ifdef CONFIG_PMAC_SMU
 	else
-		rc = g5_neo2_cpufreq_init(cpus);
+		rc = g5_neo2_cpufreq_init(cpunode);
 #endif /* CONFIG_PMAC_SMU */
 
-	of_node_put(cpus);
 	return rc;
 }
 
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index ea8e103..85f1c8c 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -207,7 +207,6 @@
 	.exit		= powernow_k6_cpu_exit,
 	.get		= powernow_k6_get,
 	.name		= "powernow-k6",
-	.owner		= THIS_MODULE,
 	.attr		= powernow_k6_attr,
 };
 
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 9558708..14ce480 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -177,7 +177,7 @@
 	unsigned int speed;
 	u8 fid, vid;
 
-	powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
+	powernow_table = kzalloc((sizeof(*powernow_table) *
 				(number_scales + 1)), GFP_KERNEL);
 	if (!powernow_table)
 		return -ENOMEM;
@@ -309,8 +309,7 @@
 		goto err0;
 	}
 
-	acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance),
-				      GFP_KERNEL);
+	acpi_processor_perf = kzalloc(sizeof(*acpi_processor_perf), GFP_KERNEL);
 	if (!acpi_processor_perf) {
 		retval = -ENOMEM;
 		goto err0;
@@ -346,7 +345,7 @@
 		goto err2;
 	}
 
-	powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) *
+	powernow_table = kzalloc((sizeof(*powernow_table) *
 				(number_scales + 1)), GFP_KERNEL);
 	if (!powernow_table) {
 		retval = -ENOMEM;
@@ -497,7 +496,7 @@
 					"relevant to this CPU).\n",
 					psb->numpst);
 
-			p += sizeof(struct psb_s);
+			p += sizeof(*psb);
 
 			pst = (struct pst_s *) p;
 
@@ -510,12 +509,12 @@
 				    (maxfid == pst->maxfid) &&
 				    (startvid == pst->startvid)) {
 					print_pst_entry(pst, j);
-					p = (char *)pst + sizeof(struct pst_s);
+					p = (char *)pst + sizeof(*pst);
 					ret = get_ranges(p);
 					return ret;
 				} else {
 					unsigned int k;
-					p = (char *)pst + sizeof(struct pst_s);
+					p = (char *)pst + sizeof(*pst);
 					for (k = 0; k < number_scales; k++)
 						p += 2;
 				}
@@ -717,7 +716,6 @@
 	.init		= powernow_cpu_init,
 	.exit		= powernow_cpu_exit,
 	.name		= "powernow-k7",
-	.owner		= THIS_MODULE,
 	.attr		= powernow_table_attr,
 };
 
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index c39d189..2344a9e 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -623,7 +623,7 @@
 	if (check_pst_table(data, pst, maxvid))
 		return -EINVAL;
 
-	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
+	powernow_table = kmalloc((sizeof(*powernow_table)
 		* (data->numps + 1)), GFP_KERNEL);
 	if (!powernow_table) {
 		printk(KERN_ERR PFX "powernow_table memory alloc failure\n");
@@ -793,7 +793,7 @@
 	}
 
 	/* fill in data->powernow_table */
-	powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
+	powernow_table = kmalloc((sizeof(*powernow_table)
 		* (data->acpi_data.state_count + 1)), GFP_KERNEL);
 	if (!powernow_table) {
 		pr_debug("powernow_table memory alloc failure\n");
@@ -1106,7 +1106,7 @@
 	if (rc)
 		return -ENODEV;
 
-	data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		printk(KERN_ERR PFX "unable to alloc powernow_k8_data");
 		return -ENOMEM;
@@ -1240,7 +1240,6 @@
 	.exit		= powernowk8_cpu_exit,
 	.get		= powernowk8_get,
 	.name		= "powernow-k8",
-	.owner		= THIS_MODULE,
 	.attr		= powernow_k8_attr,
 };
 
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 3cae452..60e81d5 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -300,7 +300,6 @@
 
 static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
 	.name		= "ppc_cpufreq",
-	.owner		= THIS_MODULE,
 	.flags		= CPUFREQ_CONST_LOOPS,
 	.init		= corenet_cpufreq_cpu_init,
 	.exit		= __exit_p(corenet_cpufreq_cpu_exit),
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index 5936f8d..2e448f0 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -181,7 +181,6 @@
 	.init		= cbe_cpufreq_cpu_init,
 	.exit		= cbe_cpufreq_cpu_exit,
 	.name		= "cbe-cpufreq",
-	.owner		= THIS_MODULE,
 	.flags		= CPUFREQ_CONST_LOOPS,
 };
 
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index fb3981a..8749eaf 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -191,7 +191,7 @@
 	return ret;
 }
 
-static __init void pxa_cpufreq_init_voltages(void)
+static void __init pxa_cpufreq_init_voltages(void)
 {
 	vcc_core = regulator_get(NULL, "vcc_core");
 	if (IS_ERR(vcc_core)) {
@@ -207,7 +207,7 @@
 	return 0;
 }
 
-static __init void pxa_cpufreq_init_voltages(void) { }
+static void __init pxa_cpufreq_init_voltages(void) { }
 #endif
 
 static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index 9c92ef0..d26306f 100644
--- a/drivers/cpufreq/pxa3xx-cpufreq.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -213,10 +213,12 @@
 	policy->cur = policy->min = policy->max;
 
 	if (cpu_is_pxa300() || cpu_is_pxa310())
-		ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa300_freqs));
+		ret = setup_freqs_table(policy, pxa300_freqs,
+					ARRAY_SIZE(pxa300_freqs));
 
 	if (cpu_is_pxa320())
-		ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa320_freqs));
+		ret = setup_freqs_table(policy, pxa320_freqs,
+					ARRAY_SIZE(pxa320_freqs));
 
 	if (ret) {
 		pr_err("failed to setup frequency table\n");
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index ce5b9fc..22dcb81 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -524,7 +524,6 @@
 };
 
 static struct cpufreq_driver s3c2416_cpufreq_driver = {
-	.owner		= THIS_MODULE,
 	.flags          = 0,
 	.verify		= s3c2416_cpufreq_verify_speed,
 	.target		= s3c2416_cpufreq_set_target,
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 87781eb..b0f343f 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -392,7 +392,7 @@
 	return 0;
 }
 
-static __init int s3c_cpufreq_initclks(void)
+static int __init s3c_cpufreq_initclks(void)
 {
 	_clk_mpll = s3c_cpufreq_clk_get(NULL, "mpll");
 	_clk_xtal = s3c_cpufreq_clk_get(NULL, "xtal");
@@ -522,7 +522,7 @@
 	/* Copy the board information so that each board can make this
 	 * initdata. */
 
-	ours = kzalloc(sizeof(struct s3c_cpufreq_board), GFP_KERNEL);
+	ours = kzalloc(sizeof(*ours), GFP_KERNEL);
 	if (ours == NULL) {
 		printk(KERN_ERR "%s: no memory\n", __func__);
 		return -ENOMEM;
@@ -615,7 +615,7 @@
 	size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0);
 	size++;
 
-	ftab = kmalloc(sizeof(struct cpufreq_frequency_table) * size, GFP_KERNEL);
+	ftab = kmalloc(sizeof(*ftab) * size, GFP_KERNEL);
 	if (!ftab) {
 		printk(KERN_ERR "%s: no memory for tables\n", __func__);
 		return -ENOMEM;
@@ -691,7 +691,7 @@
 	struct cpufreq_frequency_table *vals;
 	unsigned int size;
 
-	size = sizeof(struct cpufreq_frequency_table) * (plls_no + 1);
+	size = sizeof(*vals) * (plls_no + 1);
 
 	vals = kmalloc(size, GFP_KERNEL);
 	if (vals) {
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 13bb4ba..8a72b0c 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -263,7 +263,6 @@
 }
 
 static struct cpufreq_driver s3c64xx_cpufreq_driver = {
-	.owner		= THIS_MODULE,
 	.flags          = 0,
 	.verify		= s3c64xx_cpufreq_verify_speed,
 	.target		= s3c64xx_cpufreq_set_target,
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 77a2109..d6f6c6f 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -147,7 +147,6 @@
 	.init	= sc520_freq_cpu_init,
 	.exit	= sc520_freq_cpu_exit,
 	.name	= "sc520_freq",
-	.owner	= THIS_MODULE,
 	.attr	= sc520_freq_attr,
 };
 
diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index 73adb64..ffc6d24 100644
--- a/drivers/cpufreq/sh-cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -160,7 +160,6 @@
 };
 
 static struct cpufreq_driver sh_cpufreq_driver = {
-	.owner		= THIS_MODULE,
 	.name		= "sh",
 	.get		= sh_cpufreq_get,
 	.target		= sh_cpufreq_target,
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 93061a40..cf5bc2c 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -351,12 +351,11 @@
 		struct cpufreq_driver *driver;
 
 		ret = -ENOMEM;
-		driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
+		driver = kzalloc(sizeof(*driver), GFP_KERNEL);
 		if (!driver)
 			goto err_out;
 
-		us2e_freq_table = kzalloc(
-			(NR_CPUS * sizeof(struct us2e_freq_percpu_info)),
+		us2e_freq_table = kzalloc((NR_CPUS * sizeof(*us2e_freq_table)),
 			GFP_KERNEL);
 		if (!us2e_freq_table)
 			goto err_out;
@@ -366,7 +365,6 @@
 		driver->target = us2e_freq_target;
 		driver->get = us2e_freq_get;
 		driver->exit = us2e_freq_cpu_exit;
-		driver->owner = THIS_MODULE,
 		strcpy(driver->name, "UltraSPARC-IIe");
 
 		cpufreq_us2e_driver = driver;
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index 880ee29..ac76b48 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -212,12 +212,11 @@
 		struct cpufreq_driver *driver;
 
 		ret = -ENOMEM;
-		driver = kzalloc(sizeof(struct cpufreq_driver), GFP_KERNEL);
+		driver = kzalloc(sizeof(*driver), GFP_KERNEL);
 		if (!driver)
 			goto err_out;
 
-		us3_freq_table = kzalloc(
-			(NR_CPUS * sizeof(struct us3_freq_percpu_info)),
+		us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)),
 			GFP_KERNEL);
 		if (!us3_freq_table)
 			goto err_out;
@@ -227,7 +226,6 @@
 		driver->target = us3_freq_target;
 		driver->get = us3_freq_get;
 		driver->exit = us3_freq_cpu_exit;
-		driver->owner = THIS_MODULE,
 		strcpy(driver->name, "UltraSPARC-III");
 
 		cpufreq_us3_driver = driver;
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index c3efa7f..19e364fa 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -18,7 +18,7 @@
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
@@ -223,7 +223,7 @@
 	const __be32 *val;
 	int cnt, i, ret;
 
-	np = of_find_node_by_path("/cpus/cpu@0");
+	np = of_cpu_device_node_get(0);
 	if (!np) {
 		pr_err("No cpu node found");
 		return -ENODEV;
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 0915e71..f897d51 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -575,7 +575,6 @@
 	.target		= centrino_target,
 	.get		= get_cur_freq,
 	.attr           = centrino_attr,
-	.owner		= THIS_MODULE,
 };
 
 /*
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index e2e5aa9..5355abb 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -378,7 +378,6 @@
 	.init	= speedstep_cpu_init,
 	.exit	= speedstep_cpu_exit,
 	.get	= speedstep_get,
-	.owner	= THIS_MODULE,
 	.attr	= speedstep_attr,
 };
 
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index f5a6b70..abfba4f 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -375,7 +375,6 @@
 	.exit		= speedstep_cpu_exit,
 	.get		= speedstep_get,
 	.resume		= speedstep_resume,
-	.owner		= THIS_MODULE,
 	.attr		= speedstep_attr,
 };
 
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index cd66b85..a7b876f 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -255,7 +255,7 @@
 
 static int __init tegra_cpufreq_init(void)
 {
-	cpu_clk = clk_get_sys(NULL, "cpu");
+	cpu_clk = clk_get_sys(NULL, "cclk");
 	if (IS_ERR(cpu_clk))
 		return PTR_ERR(cpu_clk);
 
@@ -263,7 +263,7 @@
 	if (IS_ERR(pll_x_clk))
 		return PTR_ERR(pll_x_clk);
 
-	pll_p_clk = clk_get_sys(NULL, "pll_p_cclk");
+	pll_p_clk = clk_get_sys(NULL, "pll_p");
 	if (IS_ERR(pll_p_clk))
 		return PTR_ERR(pll_p_clk);
 
diff --git a/drivers/cpufreq/unicore2-cpufreq.c b/drivers/cpufreq/unicore2-cpufreq.c
index 12fc904..b225f04 100644
--- a/drivers/cpufreq/unicore2-cpufreq.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -24,7 +24,7 @@
 /* make sure that only the "userspace" governor is run
  * -- anything else wouldn't make sense on this platform, anyway.
  */
-int ucv2_verify_speed(struct cpufreq_policy *policy)
+static int ucv2_verify_speed(struct cpufreq_policy *policy)
 {
 	if (policy->cpu)
 		return -EINVAL;
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 0e2cd5c..b3fb81d 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -1,5 +1,6 @@
+menu "CPU Idle"
 
-menuconfig CPU_IDLE
+config CPU_IDLE
 	bool "CPU idle PM support"
 	default y if ACPI || PPC_PSERIES
 	select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE)
@@ -29,20 +30,13 @@
 	bool "Menu governor (for tickless system)"
 	default y
 
-config CPU_IDLE_CALXEDA
-	bool "CPU Idle Driver for Calxeda processors"
-	depends on ARCH_HIGHBANK
-	select ARM_CPU_SUSPEND
-	help
-	  Select this to enable cpuidle on Calxeda processors.
-
-config CPU_IDLE_ZYNQ
-	bool "CPU Idle Driver for Xilinx Zynq processors"
-	depends on ARCH_ZYNQ
-	help
-	  Select this to enable cpuidle on Xilinx Zynq processors.
+menu "ARM CPU Idle Drivers"
+depends on ARM
+source "drivers/cpuidle/Kconfig.arm"
+endmenu
 
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
 	def_bool n
+endmenu
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
new file mode 100644
index 0000000..b330219
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.arm
@@ -0,0 +1,29 @@
+#
+# ARM CPU Idle drivers
+#
+
+config ARM_HIGHBANK_CPUIDLE
+	bool "CPU Idle Driver for Calxeda processors"
+	depends on ARCH_HIGHBANK
+	select ARM_CPU_SUSPEND
+	help
+	  Select this to enable cpuidle on Calxeda processors.
+
+config ARM_KIRKWOOD_CPUIDLE
+	bool "CPU Idle Driver for Marvell Kirkwood SoCs"
+	depends on ARCH_KIRKWOOD
+	help
+	  This adds the CPU Idle driver for Marvell Kirkwood SoCs.
+
+config ARM_ZYNQ_CPUIDLE
+	bool "CPU Idle Driver for Xilinx Zynq processors"
+	depends on ARCH_ZYNQ
+	help
+	  Select this to enable cpuidle on Xilinx Zynq processors.
+
+config ARM_U8500_CPUIDLE
+	bool "Cpu Idle Driver for the ST-E u8500 processors"
+	depends on ARCH_U8500
+	help
+	  Select this to enable cpuidle for ST-E u8500 processors
+
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 8767a7b..0b9d200 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -5,6 +5,9 @@
 obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
 obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
 
-obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
-obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
-obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
+##################################################################################
+# ARM SoC drivers
+obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)	+= cpuidle-calxeda.o
+obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)	+= cpuidle-kirkwood.o
+obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)		+= cpuidle-zynq.o
+obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c
index 2a297f8..f8a8636 100644
--- a/drivers/cpuidle/coupled.c
+++ b/drivers/cpuidle/coupled.c
@@ -106,6 +106,7 @@
 	cpumask_t coupled_cpus;
 	int requested_state[NR_CPUS];
 	atomic_t ready_waiting_counts;
+	atomic_t abort_barrier;
 	int online_count;
 	int refcnt;
 	int prevent;
@@ -122,12 +123,19 @@
 static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb);
 
 /*
- * The cpuidle_coupled_poked_mask mask is used to avoid calling
+ * The cpuidle_coupled_poke_pending mask is used to avoid calling
  * __smp_call_function_single with the per cpu call_single_data struct already
  * in use.  This prevents a deadlock where two cpus are waiting for each others
  * call_single_data struct to be available
  */
-static cpumask_t cpuidle_coupled_poked_mask;
+static cpumask_t cpuidle_coupled_poke_pending;
+
+/*
+ * The cpuidle_coupled_poked mask is used to ensure that each cpu has been poked
+ * once to minimize entering the ready loop with a poke pending, which would
+ * require aborting and retrying.
+ */
+static cpumask_t cpuidle_coupled_poked;
 
 /**
  * cpuidle_coupled_parallel_barrier - synchronize all online coupled cpus
@@ -291,10 +299,11 @@
 	return state;
 }
 
-static void cpuidle_coupled_poked(void *info)
+static void cpuidle_coupled_handle_poke(void *info)
 {
 	int cpu = (unsigned long)info;
-	cpumask_clear_cpu(cpu, &cpuidle_coupled_poked_mask);
+	cpumask_set_cpu(cpu, &cpuidle_coupled_poked);
+	cpumask_clear_cpu(cpu, &cpuidle_coupled_poke_pending);
 }
 
 /**
@@ -313,7 +322,7 @@
 {
 	struct call_single_data *csd = &per_cpu(cpuidle_coupled_poke_cb, cpu);
 
-	if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poked_mask))
+	if (!cpumask_test_and_set_cpu(cpu, &cpuidle_coupled_poke_pending))
 		__smp_call_function_single(cpu, csd, 0);
 }
 
@@ -340,30 +349,19 @@
  * @coupled: the struct coupled that contains the current cpu
  * @next_state: the index in drv->states of the requested state for this cpu
  *
- * Updates the requested idle state for the specified cpuidle device,
- * poking all coupled cpus out of idle if necessary to let them see the new
- * state.
+ * Updates the requested idle state for the specified cpuidle device.
+ * Returns the number of waiting cpus.
  */
-static void cpuidle_coupled_set_waiting(int cpu,
+static int cpuidle_coupled_set_waiting(int cpu,
 		struct cpuidle_coupled *coupled, int next_state)
 {
-	int w;
-
 	coupled->requested_state[cpu] = next_state;
 
 	/*
-	 * If this is the last cpu to enter the waiting state, poke
-	 * all the other cpus out of their waiting state so they can
-	 * enter a deeper state.  This can race with one of the cpus
-	 * exiting the waiting state due to an interrupt and
-	 * decrementing waiting_count, see comment below.
-	 *
 	 * The atomic_inc_return provides a write barrier to order the write
 	 * to requested_state with the later write that increments ready_count.
 	 */
-	w = atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK;
-	if (w == coupled->online_count)
-		cpuidle_coupled_poke_others(cpu, coupled);
+	return atomic_inc_return(&coupled->ready_waiting_counts) & WAITING_MASK;
 }
 
 /**
@@ -410,19 +408,33 @@
  * been processed and the poke bit has been cleared.
  *
  * Other interrupts may also be processed while interrupts are enabled, so
- * need_resched() must be tested after turning interrupts off again to make sure
+ * need_resched() must be tested after this function returns to make sure
  * the interrupt didn't schedule work that should take the cpu out of idle.
  *
- * Returns 0 if need_resched was false, -EINTR if need_resched was true.
+ * Returns 0 if no poke was pending, 1 if a poke was cleared.
  */
 static int cpuidle_coupled_clear_pokes(int cpu)
 {
+	if (!cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending))
+		return 0;
+
 	local_irq_enable();
-	while (cpumask_test_cpu(cpu, &cpuidle_coupled_poked_mask))
+	while (cpumask_test_cpu(cpu, &cpuidle_coupled_poke_pending))
 		cpu_relax();
 	local_irq_disable();
 
-	return need_resched() ? -EINTR : 0;
+	return 1;
+}
+
+static bool cpuidle_coupled_any_pokes_pending(struct cpuidle_coupled *coupled)
+{
+	cpumask_t cpus;
+	int ret;
+
+	cpumask_and(&cpus, cpu_online_mask, &coupled->coupled_cpus);
+	ret = cpumask_and(&cpus, &cpuidle_coupled_poke_pending, &cpus);
+
+	return ret;
 }
 
 /**
@@ -449,31 +461,56 @@
 {
 	int entered_state = -1;
 	struct cpuidle_coupled *coupled = dev->coupled;
+	int w;
 
 	if (!coupled)
 		return -EINVAL;
 
 	while (coupled->prevent) {
-		if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+		cpuidle_coupled_clear_pokes(dev->cpu);
+		if (need_resched()) {
 			local_irq_enable();
 			return entered_state;
 		}
 		entered_state = cpuidle_enter_state(dev, drv,
 			dev->safe_state_index);
+		local_irq_disable();
 	}
 
 	/* Read barrier ensures online_count is read after prevent is cleared */
 	smp_rmb();
 
-	cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state);
+reset:
+	cpumask_clear_cpu(dev->cpu, &cpuidle_coupled_poked);
+
+	w = cpuidle_coupled_set_waiting(dev->cpu, coupled, next_state);
+	/*
+	 * If this is the last cpu to enter the waiting state, poke
+	 * all the other cpus out of their waiting state so they can
+	 * enter a deeper state.  This can race with one of the cpus
+	 * exiting the waiting state due to an interrupt and
+	 * decrementing waiting_count, see comment below.
+	 */
+	if (w == coupled->online_count) {
+		cpumask_set_cpu(dev->cpu, &cpuidle_coupled_poked);
+		cpuidle_coupled_poke_others(dev->cpu, coupled);
+	}
 
 retry:
 	/*
 	 * Wait for all coupled cpus to be idle, using the deepest state
-	 * allowed for a single cpu.
+	 * allowed for a single cpu.  If this was not the poking cpu, wait
+	 * for at least one poke before leaving to avoid a race where
+	 * two cpus could arrive at the waiting loop at the same time,
+	 * but the first of the two to arrive could skip the loop without
+	 * processing the pokes from the last to arrive.
 	 */
-	while (!cpuidle_coupled_cpus_waiting(coupled)) {
-		if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+	while (!cpuidle_coupled_cpus_waiting(coupled) ||
+			!cpumask_test_cpu(dev->cpu, &cpuidle_coupled_poked)) {
+		if (cpuidle_coupled_clear_pokes(dev->cpu))
+			continue;
+
+		if (need_resched()) {
 			cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
 			goto out;
 		}
@@ -485,14 +522,22 @@
 
 		entered_state = cpuidle_enter_state(dev, drv,
 			dev->safe_state_index);
+		local_irq_disable();
 	}
 
-	if (cpuidle_coupled_clear_pokes(dev->cpu)) {
+	cpuidle_coupled_clear_pokes(dev->cpu);
+	if (need_resched()) {
 		cpuidle_coupled_set_not_waiting(dev->cpu, coupled);
 		goto out;
 	}
 
 	/*
+	 * Make sure final poke status for this cpu is visible before setting
+	 * cpu as ready.
+	 */
+	smp_wmb();
+
+	/*
 	 * All coupled cpus are probably idle.  There is a small chance that
 	 * one of the other cpus just became active.  Increment the ready count,
 	 * and spin until all coupled cpus have incremented the counter. Once a
@@ -511,6 +556,28 @@
 		cpu_relax();
 	}
 
+	/*
+	 * Make sure read of all cpus ready is done before reading pending pokes
+	 */
+	smp_rmb();
+
+	/*
+	 * There is a small chance that a cpu left and reentered idle after this
+	 * cpu saw that all cpus were waiting.  The cpu that reentered idle will
+	 * have sent this cpu a poke, which will still be pending after the
+	 * ready loop.  The pending interrupt may be lost by the interrupt
+	 * controller when entering the deep idle state.  It's not possible to
+	 * clear a pending interrupt without turning interrupts on and handling
+	 * it, and it's too late to turn on interrupts here, so reset the
+	 * coupled idle state of all cpus and retry.
+	 */
+	if (cpuidle_coupled_any_pokes_pending(coupled)) {
+		cpuidle_coupled_set_done(dev->cpu, coupled);
+		/* Wait for all cpus to see the pending pokes */
+		cpuidle_coupled_parallel_barrier(dev, &coupled->abort_barrier);
+		goto reset;
+	}
+
 	/* all cpus have acked the coupled state */
 	next_state = cpuidle_coupled_get_state(dev, coupled);
 
@@ -596,7 +663,7 @@
 	coupled->refcnt++;
 
 	csd = &per_cpu(cpuidle_coupled_poke_cb, dev->cpu);
-	csd->func = cpuidle_coupled_poked;
+	csd->func = cpuidle_coupled_handle_poke;
 	csd->info = (void *)(unsigned long)dev->cpu;
 
 	return 0;
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c
index 0e6e408..3460584 100644
--- a/drivers/cpuidle/cpuidle-calxeda.c
+++ b/drivers/cpuidle/cpuidle-calxeda.c
@@ -35,7 +35,7 @@
 #include <asm/cp15.h>
 
 extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
-extern void *scu_base_addr;
+extern void __iomem *scu_base_addr;
 
 static noinline void calxeda_idle_restore(void)
 {
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c
index 521b0a7..41ba843 100644
--- a/drivers/cpuidle/cpuidle-kirkwood.c
+++ b/drivers/cpuidle/cpuidle-kirkwood.c
@@ -60,9 +60,6 @@
 	struct resource *res;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL)
-		return -EINVAL;
-
 	ddr_operation_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(ddr_operation_base))
 		return PTR_ERR(ddr_operation_base);
@@ -70,7 +67,7 @@
 	return cpuidle_register(&kirkwood_idle_driver, NULL);
 }
 
-int kirkwood_cpuidle_remove(struct platform_device *pdev)
+static int kirkwood_cpuidle_remove(struct platform_device *pdev)
 {
 	cpuidle_unregister(&kirkwood_idle_driver);
 	return 0;
diff --git a/arch/arm/mach-ux500/cpuidle.c b/drivers/cpuidle/cpuidle-ux500.c
similarity index 89%
rename from arch/arm/mach-ux500/cpuidle.c
rename to drivers/cpuidle/cpuidle-ux500.c
index a45dd09..e056465 100644
--- a/arch/arm/mach-ux500/cpuidle.c
+++ b/drivers/cpuidle/cpuidle-ux500.c
@@ -16,13 +16,11 @@
 #include <linux/smp.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/platform_data/arm-ux500-pm.h>
+#include <linux/platform_device.h>
 
 #include <asm/cpuidle.h>
 #include <asm/proc-fns.h>
 
-#include "db8500-regs.h"
-#include "id.h"
-
 static atomic_t master = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(master_lock);
 
@@ -113,11 +111,8 @@
 	.state_count = 2,
 };
 
-int __init ux500_idle_init(void)
+static int __init dbx500_cpuidle_probe(struct platform_device *pdev)
 {
-	if (!(cpu_is_u8500_family() || cpu_is_ux540_family()))
-		return -ENODEV;
-
 	/* Configure wake up reasons */
 	prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
 			     PRCMU_WAKEUP(ABB));
@@ -125,4 +120,12 @@
 	return cpuidle_register(&ux500_idle_driver, NULL);
 }
 
-device_initcall(ux500_idle_init);
+static struct platform_driver dbx500_cpuidle_plat_driver = {
+	.driver = {
+		.name = "cpuidle-dbx500",
+		.owner = THIS_MODULE,
+	},
+	.probe = dbx500_cpuidle_probe,
+};
+
+module_platform_driver(dbx500_cpuidle_plat_driver);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index fdc432f..d75040d 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -42,8 +42,6 @@
 	off = 1;
 }
 
-static int __cpuidle_register_device(struct cpuidle_device *dev);
-
 /**
  * cpuidle_play_dead - cpu off-lining
  *
@@ -278,7 +276,7 @@
  */
 int cpuidle_enable_device(struct cpuidle_device *dev)
 {
-	int ret, i;
+	int ret;
 	struct cpuidle_driver *drv;
 
 	if (!dev)
@@ -292,15 +290,12 @@
 	if (!drv || !cpuidle_curr_governor)
 		return -EIO;
 
+	if (!dev->registered)
+		return -EINVAL;
+
 	if (!dev->state_count)
 		dev->state_count = drv->state_count;
 
-	if (dev->registered == 0) {
-		ret = __cpuidle_register_device(dev);
-		if (ret)
-			return ret;
-	}
-
 	poll_idle_init(drv);
 
 	ret = cpuidle_add_device_sysfs(dev);
@@ -311,12 +306,6 @@
 	    (ret = cpuidle_curr_governor->enable(drv, dev)))
 		goto fail_sysfs;
 
-	for (i = 0; i < dev->state_count; i++) {
-		dev->states_usage[i].usage = 0;
-		dev->states_usage[i].time = 0;
-	}
-	dev->last_residency = 0;
-
 	smp_wmb();
 
 	dev->enabled = 1;
@@ -360,6 +349,23 @@
 
 EXPORT_SYMBOL_GPL(cpuidle_disable_device);
 
+static void __cpuidle_unregister_device(struct cpuidle_device *dev)
+{
+	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+
+	list_del(&dev->device_list);
+	per_cpu(cpuidle_devices, dev->cpu) = NULL;
+	module_put(drv->owner);
+}
+
+static int __cpuidle_device_init(struct cpuidle_device *dev)
+{
+	memset(dev->states_usage, 0, sizeof(dev->states_usage));
+	dev->last_residency = 0;
+
+	return 0;
+}
+
 /**
  * __cpuidle_register_device - internal register function called before register
  * and enable routines
@@ -377,24 +383,15 @@
 
 	per_cpu(cpuidle_devices, dev->cpu) = dev;
 	list_add(&dev->device_list, &cpuidle_detected_devices);
-	ret = cpuidle_add_sysfs(dev);
-	if (ret)
-		goto err_sysfs;
 
 	ret = cpuidle_coupled_register_device(dev);
-	if (ret)
-		goto err_coupled;
+	if (ret) {
+		__cpuidle_unregister_device(dev);
+		return ret;
+	}
 
 	dev->registered = 1;
 	return 0;
-
-err_coupled:
-	cpuidle_remove_sysfs(dev);
-err_sysfs:
-	list_del(&dev->device_list);
-	per_cpu(cpuidle_devices, dev->cpu) = NULL;
-	module_put(drv->owner);
-	return ret;
 }
 
 /**
@@ -403,25 +400,44 @@
  */
 int cpuidle_register_device(struct cpuidle_device *dev)
 {
-	int ret;
+	int ret = -EBUSY;
 
 	if (!dev)
 		return -EINVAL;
 
 	mutex_lock(&cpuidle_lock);
 
-	if ((ret = __cpuidle_register_device(dev))) {
-		mutex_unlock(&cpuidle_lock);
-		return ret;
-	}
+	if (dev->registered)
+		goto out_unlock;
 
-	cpuidle_enable_device(dev);
+	ret = __cpuidle_device_init(dev);
+	if (ret)
+		goto out_unlock;
+
+	ret = __cpuidle_register_device(dev);
+	if (ret)
+		goto out_unlock;
+
+	ret = cpuidle_add_sysfs(dev);
+	if (ret)
+		goto out_unregister;
+
+	ret = cpuidle_enable_device(dev);
+	if (ret)
+		goto out_sysfs;
+
 	cpuidle_install_idle_handler();
 
+out_unlock:
 	mutex_unlock(&cpuidle_lock);
 
-	return 0;
+	return ret;
 
+out_sysfs:
+	cpuidle_remove_sysfs(dev);
+out_unregister:
+	__cpuidle_unregister_device(dev);
+	goto out_unlock;
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_register_device);
@@ -432,8 +448,6 @@
  */
 void cpuidle_unregister_device(struct cpuidle_device *dev)
 {
-	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
-
 	if (dev->registered == 0)
 		return;
 
@@ -442,14 +456,12 @@
 	cpuidle_disable_device(dev);
 
 	cpuidle_remove_sysfs(dev);
-	list_del(&dev->device_list);
-	per_cpu(cpuidle_devices, dev->cpu) = NULL;
+
+	__cpuidle_unregister_device(dev);
 
 	cpuidle_coupled_unregister_device(dev);
 
 	cpuidle_resume_and_unlock();
-
-	module_put(drv->owner);
 }
 
 EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 9b78405..9f08e8c 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -192,14 +192,4 @@
 	return cpuidle_register_governor(&ladder_governor);
 }
 
-/**
- * exit_ladder - exits the governor
- */
-static void __exit exit_ladder(void)
-{
-	cpuidle_unregister_governor(&ladder_governor);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_ladder);
-module_exit(exit_ladder);
+postcore_initcall(init_ladder);
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index bc580b6..cf7f2f0 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -21,6 +21,15 @@
 #include <linux/math64.h>
 #include <linux/module.h>
 
+/*
+ * Please note when changing the tuning values:
+ * If (MAX_INTERESTING-1) * RESOLUTION > UINT_MAX, the result of
+ * a scaling operation multiplication may overflow on 32 bit platforms.
+ * In that case, #define RESOLUTION as ULL to get 64 bit result:
+ * #define RESOLUTION 1024ULL
+ *
+ * The default values do not overflow.
+ */
 #define BUCKETS 12
 #define INTERVALS 8
 #define RESOLUTION 1024
@@ -114,11 +123,11 @@
 	int             needs_update;
 
 	unsigned int	expected_us;
-	u64		predicted_us;
+	unsigned int	predicted_us;
 	unsigned int	exit_us;
 	unsigned int	bucket;
-	u64		correction_factor[BUCKETS];
-	u32		intervals[INTERVALS];
+	unsigned int	correction_factor[BUCKETS];
+	unsigned int	intervals[INTERVALS];
 	int		interval_ptr;
 };
 
@@ -199,16 +208,20 @@
  */
 static void get_typical_interval(struct menu_device *data)
 {
-	int i = 0, divisor = 0;
-	uint64_t max = 0, avg = 0, stddev = 0;
-	int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
+	int i, divisor;
+	unsigned int max, thresh;
+	uint64_t avg, stddev;
+
+	thresh = UINT_MAX; /* Discard outliers above this value */
 
 again:
 
-	/* first calculate average and standard deviation of the past */
-	max = avg = divisor = stddev = 0;
+	/* First calculate the average of past intervals */
+	max = 0;
+	avg = 0;
+	divisor = 0;
 	for (i = 0; i < INTERVALS; i++) {
-		int64_t value = data->intervals[i];
+		unsigned int value = data->intervals[i];
 		if (value <= thresh) {
 			avg += value;
 			divisor++;
@@ -218,15 +231,38 @@
 	}
 	do_div(avg, divisor);
 
+	/* Then try to determine standard deviation */
+	stddev = 0;
 	for (i = 0; i < INTERVALS; i++) {
-		int64_t value = data->intervals[i];
+		unsigned int value = data->intervals[i];
 		if (value <= thresh) {
 			int64_t diff = value - avg;
 			stddev += diff * diff;
 		}
 	}
 	do_div(stddev, divisor);
-	stddev = int_sqrt(stddev);
+	/*
+	 * The typical interval is obtained when standard deviation is small
+	 * or standard deviation is small compared to the average interval.
+	 *
+	 * int_sqrt() formal parameter type is unsigned long. When the
+	 * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor)
+	 * the resulting squared standard deviation exceeds the input domain
+	 * of int_sqrt on platforms where unsigned long is 32 bits in size.
+	 * In such case reject the candidate average.
+	 *
+	 * Use this result only if there is no timer to wake us up sooner.
+	 */
+	if (likely(stddev <= ULONG_MAX)) {
+		stddev = int_sqrt(stddev);
+		if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
+							|| stddev <= 20) {
+			if (data->expected_us > avg)
+				data->predicted_us = avg;
+			return;
+		}
+	}
+
 	/*
 	 * If we have outliers to the upside in our distribution, discard
 	 * those by setting the threshold to exclude these outliers, then
@@ -235,20 +271,12 @@
 	 *
 	 * This can deal with workloads that have long pauses interspersed
 	 * with sporadic activity with a bunch of short pauses.
-	 *
-	 * The typical interval is obtained when standard deviation is small
-	 * or standard deviation is small compared to the average interval.
 	 */
-	if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
-							|| stddev <= 20) {
-		data->predicted_us = avg;
+	if ((divisor * 4) <= INTERVALS * 3)
 		return;
 
-	} else if ((divisor * 4) > INTERVALS * 3) {
-		/* Exclude the max interval */
-		thresh = max - 1;
-		goto again;
-	}
+	thresh = max - 1;
+	goto again;
 }
 
 /**
@@ -293,8 +321,13 @@
 	if (data->correction_factor[data->bucket] == 0)
 		data->correction_factor[data->bucket] = RESOLUTION * DECAY;
 
-	/* Make sure to round up for half microseconds */
-	data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
+	/*
+	 * Force the result of multiplication to be 64 bits even if both
+	 * operands are 32 bits.
+	 * Make sure to round up for half microseconds.
+	 */
+	data->predicted_us = div_round64((uint64_t)data->expected_us *
+					 data->correction_factor[data->bucket],
 					 RESOLUTION * DECAY);
 
 	get_typical_interval(data);
@@ -360,7 +393,7 @@
 	unsigned int last_idle_us = cpuidle_get_last_residency(dev);
 	struct cpuidle_state *target = &drv->states[last_idx];
 	unsigned int measured_us;
-	u64 new_factor;
+	unsigned int new_factor;
 
 	/*
 	 * Ugh, this idle state doesn't support residency measurements, so we
@@ -381,10 +414,9 @@
 		measured_us -= data->exit_us;
 
 
-	/* update our correction ratio */
-
-	new_factor = data->correction_factor[data->bucket]
-			* (DECAY - 1) / DECAY;
+	/* Update our correction ratio */
+	new_factor = data->correction_factor[data->bucket];
+	new_factor -= new_factor / DECAY;
 
 	if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
 		new_factor += RESOLUTION * measured_us / data->expected_us;
@@ -397,9 +429,11 @@
 
 	/*
 	 * We don't want 0 as factor; we always want at least
-	 * a tiny bit of estimated time.
+	 * a tiny bit of estimated time. Fortunately, due to rounding,
+	 * new_factor will stay nonzero regardless of measured_us values
+	 * and the compiler can eliminate this test as long as DECAY > 1.
 	 */
-	if (new_factor == 0)
+	if (DECAY == 1 && unlikely(new_factor == 0))
 		new_factor = 1;
 
 	data->correction_factor[data->bucket] = new_factor;
@@ -442,14 +476,4 @@
 	return cpuidle_register_governor(&menu_governor);
 }
 
-/**
- * exit_menu - exits the governor
- */
-static void __exit exit_menu(void)
-{
-	cpuidle_unregister_governor(&menu_governor);
-}
-
-MODULE_LICENSE("GPL");
-module_init(init_menu);
-module_exit(exit_menu);
+postcore_initcall(init_menu);
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 428754a..8739cc0 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -11,8 +11,10 @@
 #include <linux/sysfs.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
+#include <linux/completion.h>
 #include <linux/capability.h>
 #include <linux/device.h>
+#include <linux/kobject.h>
 
 #include "cpuidle.h"
 
@@ -33,7 +35,8 @@
 
 	mutex_lock(&cpuidle_lock);
 	list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
-		if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
+		if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) -
+				    CPUIDLE_NAME_LEN - 2))
 			goto out;
 		i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
 	}
@@ -166,13 +169,28 @@
 #define define_one_rw(_name, show, store) \
 	static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
 
-#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
 #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
-static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
+
+struct cpuidle_device_kobj {
+	struct cpuidle_device *dev;
+	struct completion kobj_unregister;
+	struct kobject kobj;
+};
+
+static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj)
+{
+	struct cpuidle_device_kobj *kdev =
+		container_of(kobj, struct cpuidle_device_kobj, kobj);
+
+	return kdev->dev;
+}
+
+static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr,
+			    char *buf)
 {
 	int ret = -EIO;
-	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
-	struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+	struct cpuidle_device *dev = to_cpuidle_device(kobj);
+	struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
 
 	if (cattr->show) {
 		mutex_lock(&cpuidle_lock);
@@ -182,12 +200,12 @@
 	return ret;
 }
 
-static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
-		     const char * buf, size_t count)
+static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr,
+			     const char *buf, size_t count)
 {
 	int ret = -EIO;
-	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
-	struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
+	struct cpuidle_device *dev = to_cpuidle_device(kobj);
+	struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
 
 	if (cattr->store) {
 		mutex_lock(&cpuidle_lock);
@@ -204,9 +222,10 @@
 
 static void cpuidle_sysfs_release(struct kobject *kobj)
 {
-	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
+	struct cpuidle_device_kobj *kdev =
+		container_of(kobj, struct cpuidle_device_kobj, kobj);
 
-	complete(&dev->kobj_unregister);
+	complete(&kdev->kobj_unregister);
 }
 
 static struct kobj_type ktype_cpuidle = {
@@ -237,8 +256,8 @@
 
 #define define_store_state_ull_function(_name) \
 static ssize_t store_state_##_name(struct cpuidle_state *state, \
-		struct cpuidle_state_usage *state_usage, \
-		const char *buf, size_t size) \
+				   struct cpuidle_state_usage *state_usage, \
+				   const char *buf, size_t size)	\
 { \
 	unsigned long long value; \
 	int err; \
@@ -256,14 +275,16 @@
 
 #define define_show_state_ull_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
-			struct cpuidle_state_usage *state_usage, char *buf) \
+				  struct cpuidle_state_usage *state_usage, \
+				  char *buf)				\
 { \
 	return sprintf(buf, "%llu\n", state_usage->_name);\
 }
 
 #define define_show_state_str_function(_name) \
 static ssize_t show_state_##_name(struct cpuidle_state *state, \
-			struct cpuidle_state_usage *state_usage, char *buf) \
+				  struct cpuidle_state_usage *state_usage, \
+				  char *buf)				\
 { \
 	if (state->_name[0] == '\0')\
 		return sprintf(buf, "<null>\n");\
@@ -309,8 +330,9 @@
 #define kobj_to_state(k) (kobj_to_state_obj(k)->state)
 #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
 #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
-static ssize_t cpuidle_state_show(struct kobject * kobj,
-	struct attribute * attr ,char * buf)
+
+static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,
+				  char * buf)
 {
 	int ret = -EIO;
 	struct cpuidle_state *state = kobj_to_state(kobj);
@@ -323,8 +345,8 @@
 	return ret;
 }
 
-static ssize_t cpuidle_state_store(struct kobject *kobj,
-	struct attribute *attr, const char *buf, size_t size)
+static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,
+				   const char *buf, size_t size)
 {
 	int ret = -EIO;
 	struct cpuidle_state *state = kobj_to_state(kobj);
@@ -371,6 +393,7 @@
 {
 	int i, ret = -ENOMEM;
 	struct cpuidle_state_kobj *kobj;
+	struct cpuidle_device_kobj *kdev = device->kobj_dev;
 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
 
 	/* state statistics */
@@ -383,7 +406,7 @@
 		init_completion(&kobj->kobj_unregister);
 
 		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
-					   &device->kobj, "state%d", i);
+					   &kdev->kobj, "state%d", i);
 		if (ret) {
 			kfree(kobj);
 			goto error_state;
@@ -449,8 +472,8 @@
 	complete(&driver_kobj->kobj_unregister);
 }
 
-static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr,
-				   char * buf)
+static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr,
+				   char *buf)
 {
 	int ret = -EIO;
 	struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
@@ -500,6 +523,7 @@
 static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
 {
 	struct cpuidle_driver_kobj *kdrv;
+	struct cpuidle_device_kobj *kdev = dev->kobj_dev;
 	struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
 	int ret;
 
@@ -511,7 +535,7 @@
 	init_completion(&kdrv->kobj_unregister);
 
 	ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
-				   &dev->kobj, "driver");
+				   &kdev->kobj, "driver");
 	if (ret) {
 		kfree(kdrv);
 		return ret;
@@ -580,16 +604,28 @@
  */
 int cpuidle_add_sysfs(struct cpuidle_device *dev)
 {
+	struct cpuidle_device_kobj *kdev;
 	struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
 	int error;
 
-	init_completion(&dev->kobj_unregister);
+	kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
+	if (!kdev)
+		return -ENOMEM;
+	kdev->dev = dev;
+	dev->kobj_dev = kdev;
 
-	error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
-				     "cpuidle");
-	if (!error)
-		kobject_uevent(&dev->kobj, KOBJ_ADD);
-	return error;
+	init_completion(&kdev->kobj_unregister);
+
+	error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
+				   "cpuidle");
+	if (error) {
+		kfree(kdev);
+		return error;
+	}
+
+	kobject_uevent(&kdev->kobj, KOBJ_ADD);
+
+	return 0;
 }
 
 /**
@@ -598,6 +634,9 @@
  */
 void cpuidle_remove_sysfs(struct cpuidle_device *dev)
 {
-	kobject_put(&dev->kobj);
-	wait_for_completion(&dev->kobj_unregister);
+	struct cpuidle_device_kobj *kdev = dev->kobj_dev;
+
+	kobject_put(&kdev->kobj);
+	wait_for_completion(&kdev->kobj_unregister);
+	kfree(kdev);
 }
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index e94e619..c99c00d 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -703,7 +703,7 @@
 }
 EXPORT_SYMBOL(devfreq_remove_governor);
 
-static ssize_t show_governor(struct device *dev,
+static ssize_t governor_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
 	if (!to_devfreq(dev)->governor)
@@ -712,7 +712,7 @@
 	return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
 }
 
-static ssize_t store_governor(struct device *dev, struct device_attribute *attr,
+static ssize_t governor_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
 	struct devfreq *df = to_devfreq(dev);
@@ -754,9 +754,11 @@
 		ret = count;
 	return ret;
 }
-static ssize_t show_available_governors(struct device *d,
-				    struct device_attribute *attr,
-				    char *buf)
+static DEVICE_ATTR_RW(governor);
+
+static ssize_t available_governors_show(struct device *d,
+					struct device_attribute *attr,
+					char *buf)
 {
 	struct devfreq_governor *tmp_governor;
 	ssize_t count = 0;
@@ -775,9 +777,10 @@
 
 	return count;
 }
+static DEVICE_ATTR_RO(available_governors);
 
-static ssize_t show_freq(struct device *dev,
-			 struct device_attribute *attr, char *buf)
+static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
 {
 	unsigned long freq;
 	struct devfreq *devfreq = to_devfreq(dev);
@@ -788,20 +791,22 @@
 
 	return sprintf(buf, "%lu\n", devfreq->previous_freq);
 }
+static DEVICE_ATTR_RO(cur_freq);
 
-static ssize_t show_target_freq(struct device *dev,
-			struct device_attribute *attr, char *buf)
+static ssize_t target_freq_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
 }
+static DEVICE_ATTR_RO(target_freq);
 
-static ssize_t show_polling_interval(struct device *dev,
+static ssize_t polling_interval_show(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
 }
 
-static ssize_t store_polling_interval(struct device *dev,
+static ssize_t polling_interval_store(struct device *dev,
 				      struct device_attribute *attr,
 				      const char *buf, size_t count)
 {
@@ -821,8 +826,9 @@
 
 	return ret;
 }
+static DEVICE_ATTR_RW(polling_interval);
 
-static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
 	struct devfreq *df = to_devfreq(dev);
@@ -849,13 +855,13 @@
 	return ret;
 }
 
-static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq);
 }
 
-static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
 	struct devfreq *df = to_devfreq(dev);
@@ -881,16 +887,18 @@
 	mutex_unlock(&df->lock);
 	return ret;
 }
+static DEVICE_ATTR_RW(min_freq);
 
-static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr,
+static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
 }
+static DEVICE_ATTR_RW(max_freq);
 
-static ssize_t show_available_freqs(struct device *d,
-				    struct device_attribute *attr,
-				    char *buf)
+static ssize_t available_frequencies_show(struct device *d,
+					  struct device_attribute *attr,
+					  char *buf)
 {
 	struct devfreq *df = to_devfreq(d);
 	struct device *dev = df->dev.parent;
@@ -918,9 +926,10 @@
 
 	return count;
 }
+static DEVICE_ATTR_RO(available_frequencies);
 
-static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr,
-				char *buf)
+static ssize_t trans_stat_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct devfreq *devfreq = to_devfreq(dev);
 	ssize_t len;
@@ -959,20 +968,21 @@
 					devfreq->total_trans);
 	return len;
 }
+static DEVICE_ATTR_RO(trans_stat);
 
-static struct device_attribute devfreq_attrs[] = {
-	__ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor),
-	__ATTR(available_governors, S_IRUGO, show_available_governors, NULL),
-	__ATTR(cur_freq, S_IRUGO, show_freq, NULL),
-	__ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL),
-	__ATTR(target_freq, S_IRUGO, show_target_freq, NULL),
-	__ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
-	       store_polling_interval),
-	__ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
-	__ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
-	__ATTR(trans_stat, S_IRUGO, show_trans_table, NULL),
-	{ },
+static struct attribute *devfreq_attrs[] = {
+	&dev_attr_governor.attr,
+	&dev_attr_available_governors.attr,
+	&dev_attr_cur_freq.attr,
+	&dev_attr_available_frequencies.attr,
+	&dev_attr_target_freq.attr,
+	&dev_attr_polling_interval.attr,
+	&dev_attr_min_freq.attr,
+	&dev_attr_max_freq.attr,
+	&dev_attr_trans_stat.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(devfreq);
 
 static int __init devfreq_init(void)
 {
@@ -988,7 +998,7 @@
 		pr_err("%s: couldn't create workqueue\n", __FILE__);
 		return PTR_ERR(devfreq_wq);
 	}
-	devfreq_class->dev_attrs = devfreq_attrs;
+	devfreq_class->dev_groups = devfreq_groups;
 
 	return 0;
 }
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6825957..daa4da2 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -194,7 +194,7 @@
 	  Enable support for the CSR SiRFprimaII DMA engine.
 
 config TI_EDMA
-	tristate "TI EDMA support"
+	bool "TI EDMA support"
 	depends on ARCH_DAVINCI || ARCH_OMAP
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
@@ -287,6 +287,14 @@
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
 
+config TI_CPPI41
+	tristate "AM33xx CPPI41 DMA support"
+	depends on ARCH_OMAP
+	select DMA_ENGINE
+	help
+	  The Communications Port Programming Interface (CPPI) 4.1 DMA engine
+	  is currently used by the USB driver on AM335x platforms.
+
 config MMP_PDMA
 	bool "MMP PDMA support"
 	depends on (ARCH_MMP || ARCH_PXA)
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 5e0f2ef..6d62ec3 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -39,3 +39,4 @@
 obj-$(CONFIG_DMA_OMAP) += omap-dma.o
 obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
+obj-$(CONFIG_TI_CPPI41) += cppi41.o
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
new file mode 100644
index 0000000..7c82b92
--- /dev/null
+++ b/drivers/dma/cppi41.c
@@ -0,0 +1,1059 @@
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/of_dma.h>
+#include <linux/of_irq.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include "dmaengine.h"
+
+#define DESC_TYPE	27
+#define DESC_TYPE_HOST	0x10
+#define DESC_TYPE_TEARD	0x13
+
+#define TD_DESC_IS_RX	(1 << 16)
+#define TD_DESC_DMA_NUM	10
+
+#define DESC_LENGTH_BITS_NUM	21
+
+#define DESC_TYPE_USB	(5 << 26)
+#define DESC_PD_COMPLETE	(1 << 31)
+
+/* DMA engine */
+#define DMA_TDFDQ	4
+#define DMA_TXGCR(x)	(0x800 + (x) * 0x20)
+#define DMA_RXGCR(x)	(0x808 + (x) * 0x20)
+#define RXHPCRA0		4
+
+#define GCR_CHAN_ENABLE		(1 << 31)
+#define GCR_TEARDOWN		(1 << 30)
+#define GCR_STARV_RETRY		(1 << 24)
+#define GCR_DESC_TYPE_HOST	(1 << 14)
+
+/* DMA scheduler */
+#define DMA_SCHED_CTRL		0
+#define DMA_SCHED_CTRL_EN	(1 << 31)
+#define DMA_SCHED_WORD(x)	((x) * 4 + 0x800)
+
+#define SCHED_ENTRY0_CHAN(x)	((x) << 0)
+#define SCHED_ENTRY0_IS_RX	(1 << 7)
+
+#define SCHED_ENTRY1_CHAN(x)	((x) << 8)
+#define SCHED_ENTRY1_IS_RX	(1 << 15)
+
+#define SCHED_ENTRY2_CHAN(x)	((x) << 16)
+#define SCHED_ENTRY2_IS_RX	(1 << 23)
+
+#define SCHED_ENTRY3_CHAN(x)	((x) << 24)
+#define SCHED_ENTRY3_IS_RX	(1 << 31)
+
+/* Queue manager */
+/* 4 KiB of memory for descriptors, 2 for each endpoint */
+#define ALLOC_DECS_NUM		128
+#define DESCS_AREAS		1
+#define TOTAL_DESCS_NUM		(ALLOC_DECS_NUM * DESCS_AREAS)
+#define QMGR_SCRATCH_SIZE	(TOTAL_DESCS_NUM * 4)
+
+#define QMGR_LRAM0_BASE		0x80
+#define QMGR_LRAM_SIZE		0x84
+#define QMGR_LRAM1_BASE		0x88
+#define QMGR_MEMBASE(x)		(0x1000 + (x) * 0x10)
+#define QMGR_MEMCTRL(x)		(0x1004 + (x) * 0x10)
+#define QMGR_MEMCTRL_IDX_SH	16
+#define QMGR_MEMCTRL_DESC_SH	8
+
+#define QMGR_NUM_PEND	5
+#define QMGR_PEND(x)	(0x90 + (x) * 4)
+
+#define QMGR_PENDING_SLOT_Q(x)	(x / 32)
+#define QMGR_PENDING_BIT_Q(x)	(x % 32)
+
+#define QMGR_QUEUE_A(n)	(0x2000 + (n) * 0x10)
+#define QMGR_QUEUE_B(n)	(0x2004 + (n) * 0x10)
+#define QMGR_QUEUE_C(n)	(0x2008 + (n) * 0x10)
+#define QMGR_QUEUE_D(n)	(0x200c + (n) * 0x10)
+
+/* Glue layer specific */
+/* USBSS  / USB AM335x */
+#define USBSS_IRQ_STATUS	0x28
+#define USBSS_IRQ_ENABLER	0x2c
+#define USBSS_IRQ_CLEARR	0x30
+
+#define USBSS_IRQ_PD_COMP	(1 <<  2)
+
+struct cppi41_channel {
+	struct dma_chan chan;
+	struct dma_async_tx_descriptor txd;
+	struct cppi41_dd *cdd;
+	struct cppi41_desc *desc;
+	dma_addr_t desc_phys;
+	void __iomem *gcr_reg;
+	int is_tx;
+	u32 residue;
+
+	unsigned int q_num;
+	unsigned int q_comp_num;
+	unsigned int port_num;
+
+	unsigned td_retry;
+	unsigned td_queued:1;
+	unsigned td_seen:1;
+	unsigned td_desc_seen:1;
+};
+
+struct cppi41_desc {
+	u32 pd0;
+	u32 pd1;
+	u32 pd2;
+	u32 pd3;
+	u32 pd4;
+	u32 pd5;
+	u32 pd6;
+	u32 pd7;
+} __aligned(32);
+
+struct chan_queues {
+	u16 submit;
+	u16 complete;
+};
+
+struct cppi41_dd {
+	struct dma_device ddev;
+
+	void *qmgr_scratch;
+	dma_addr_t scratch_phys;
+
+	struct cppi41_desc *cd;
+	dma_addr_t descs_phys;
+	u32 first_td_desc;
+	struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
+
+	void __iomem *usbss_mem;
+	void __iomem *ctrl_mem;
+	void __iomem *sched_mem;
+	void __iomem *qmgr_mem;
+	unsigned int irq;
+	const struct chan_queues *queues_rx;
+	const struct chan_queues *queues_tx;
+	struct chan_queues td_queue;
+};
+
+#define FIST_COMPLETION_QUEUE	93
+static struct chan_queues usb_queues_tx[] = {
+	/* USB0 ENDP 1 */
+	[ 0] = { .submit = 32, .complete =  93},
+	[ 1] = { .submit = 34, .complete =  94},
+	[ 2] = { .submit = 36, .complete =  95},
+	[ 3] = { .submit = 38, .complete =  96},
+	[ 4] = { .submit = 40, .complete =  97},
+	[ 5] = { .submit = 42, .complete =  98},
+	[ 6] = { .submit = 44, .complete =  99},
+	[ 7] = { .submit = 46, .complete = 100},
+	[ 8] = { .submit = 48, .complete = 101},
+	[ 9] = { .submit = 50, .complete = 102},
+	[10] = { .submit = 52, .complete = 103},
+	[11] = { .submit = 54, .complete = 104},
+	[12] = { .submit = 56, .complete = 105},
+	[13] = { .submit = 58, .complete = 106},
+	[14] = { .submit = 60, .complete = 107},
+
+	/* USB1 ENDP1 */
+	[15] = { .submit = 62, .complete = 125},
+	[16] = { .submit = 64, .complete = 126},
+	[17] = { .submit = 66, .complete = 127},
+	[18] = { .submit = 68, .complete = 128},
+	[19] = { .submit = 70, .complete = 129},
+	[20] = { .submit = 72, .complete = 130},
+	[21] = { .submit = 74, .complete = 131},
+	[22] = { .submit = 76, .complete = 132},
+	[23] = { .submit = 78, .complete = 133},
+	[24] = { .submit = 80, .complete = 134},
+	[25] = { .submit = 82, .complete = 135},
+	[26] = { .submit = 84, .complete = 136},
+	[27] = { .submit = 86, .complete = 137},
+	[28] = { .submit = 88, .complete = 138},
+	[29] = { .submit = 90, .complete = 139},
+};
+
+static const struct chan_queues usb_queues_rx[] = {
+	/* USB0 ENDP 1 */
+	[ 0] = { .submit =  1, .complete = 109},
+	[ 1] = { .submit =  2, .complete = 110},
+	[ 2] = { .submit =  3, .complete = 111},
+	[ 3] = { .submit =  4, .complete = 112},
+	[ 4] = { .submit =  5, .complete = 113},
+	[ 5] = { .submit =  6, .complete = 114},
+	[ 6] = { .submit =  7, .complete = 115},
+	[ 7] = { .submit =  8, .complete = 116},
+	[ 8] = { .submit =  9, .complete = 117},
+	[ 9] = { .submit = 10, .complete = 118},
+	[10] = { .submit = 11, .complete = 119},
+	[11] = { .submit = 12, .complete = 120},
+	[12] = { .submit = 13, .complete = 121},
+	[13] = { .submit = 14, .complete = 122},
+	[14] = { .submit = 15, .complete = 123},
+
+	/* USB1 ENDP 1 */
+	[15] = { .submit = 16, .complete = 141},
+	[16] = { .submit = 17, .complete = 142},
+	[17] = { .submit = 18, .complete = 143},
+	[18] = { .submit = 19, .complete = 144},
+	[19] = { .submit = 20, .complete = 145},
+	[20] = { .submit = 21, .complete = 146},
+	[21] = { .submit = 22, .complete = 147},
+	[22] = { .submit = 23, .complete = 148},
+	[23] = { .submit = 24, .complete = 149},
+	[24] = { .submit = 25, .complete = 150},
+	[25] = { .submit = 26, .complete = 151},
+	[26] = { .submit = 27, .complete = 152},
+	[27] = { .submit = 28, .complete = 153},
+	[28] = { .submit = 29, .complete = 154},
+	[29] = { .submit = 30, .complete = 155},
+};
+
+struct cppi_glue_infos {
+	irqreturn_t (*isr)(int irq, void *data);
+	const struct chan_queues *queues_rx;
+	const struct chan_queues *queues_tx;
+	struct chan_queues td_queue;
+};
+
+static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
+{
+	return container_of(c, struct cppi41_channel, chan);
+}
+
+static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
+{
+	struct cppi41_channel *c;
+	u32 descs_size;
+	u32 desc_num;
+
+	descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM;
+
+	if (!((desc >= cdd->descs_phys) &&
+			(desc < (cdd->descs_phys + descs_size)))) {
+		return NULL;
+	}
+
+	desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc);
+	BUG_ON(desc_num >= ALLOC_DECS_NUM);
+	c = cdd->chan_busy[desc_num];
+	cdd->chan_busy[desc_num] = NULL;
+	return c;
+}
+
+static void cppi_writel(u32 val, void *__iomem *mem)
+{
+	__raw_writel(val, mem);
+}
+
+static u32 cppi_readl(void *__iomem *mem)
+{
+	return __raw_readl(mem);
+}
+
+static u32 pd_trans_len(u32 val)
+{
+	return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1);
+}
+
+static irqreturn_t cppi41_irq(int irq, void *data)
+{
+	struct cppi41_dd *cdd = data;
+	struct cppi41_channel *c;
+	u32 status;
+	int i;
+
+	status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS);
+	if (!(status & USBSS_IRQ_PD_COMP))
+		return IRQ_NONE;
+	cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS);
+
+	for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND;
+			i++) {
+		u32 val;
+		u32 q_num;
+
+		val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i));
+		if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) {
+			u32 mask;
+			/* set corresponding bit for completetion Q 93 */
+			mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE);
+			/* not set all bits for queues less than Q 93 */
+			mask--;
+			/* now invert and keep only Q 93+ set */
+			val &= ~mask;
+		}
+
+		if (val)
+			__iormb();
+
+		while (val) {
+			u32 desc;
+
+			q_num = __fls(val);
+			val &= ~(1 << q_num);
+			q_num += 32 * i;
+			desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(q_num));
+			desc &= ~0x1f;
+			c = desc_to_chan(cdd, desc);
+			if (WARN_ON(!c)) {
+				pr_err("%s() q %d desc %08x\n", __func__,
+						q_num, desc);
+				continue;
+			}
+			c->residue = pd_trans_len(c->desc->pd6) -
+				pd_trans_len(c->desc->pd0);
+
+			dma_cookie_complete(&c->txd);
+			c->txd.callback(c->txd.callback_param);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	dma_cookie_t cookie;
+
+	cookie = dma_cookie_assign(tx);
+
+	return cookie;
+}
+
+static int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct cppi41_channel *c = to_cpp41_chan(chan);
+
+	dma_cookie_init(chan);
+	dma_async_tx_descriptor_init(&c->txd, chan);
+	c->txd.tx_submit = cppi41_tx_submit;
+
+	if (!c->is_tx)
+		cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
+
+	return 0;
+}
+
+static void cppi41_dma_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+static enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
+	dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+	struct cppi41_channel *c = to_cpp41_chan(chan);
+	enum dma_status ret;
+
+	/* lock */
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (txstate && ret == DMA_SUCCESS)
+		txstate->residue = c->residue;
+	/* unlock */
+
+	return ret;
+}
+
+static void push_desc_queue(struct cppi41_channel *c)
+{
+	struct cppi41_dd *cdd = c->cdd;
+	u32 desc_num;
+	u32 desc_phys;
+	u32 reg;
+
+	desc_phys = lower_32_bits(c->desc_phys);
+	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+	WARN_ON(cdd->chan_busy[desc_num]);
+	cdd->chan_busy[desc_num] = c;
+
+	reg = (sizeof(struct cppi41_desc) - 24) / 4;
+	reg |= desc_phys;
+	cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+}
+
+static void cppi41_dma_issue_pending(struct dma_chan *chan)
+{
+	struct cppi41_channel *c = to_cpp41_chan(chan);
+	u32 reg;
+
+	c->residue = 0;
+
+	reg = GCR_CHAN_ENABLE;
+	if (!c->is_tx) {
+		reg |= GCR_STARV_RETRY;
+		reg |= GCR_DESC_TYPE_HOST;
+		reg |= c->q_comp_num;
+	}
+
+	cppi_writel(reg, c->gcr_reg);
+
+	/*
+	 * We don't use writel() but __raw_writel() so we have to make sure
+	 * that the DMA descriptor in coherent memory made to the main memory
+	 * before starting the dma engine.
+	 */
+	__iowmb();
+	push_desc_queue(c);
+}
+
+static u32 get_host_pd0(u32 length)
+{
+	u32 reg;
+
+	reg = DESC_TYPE_HOST << DESC_TYPE;
+	reg |= length;
+
+	return reg;
+}
+
+static u32 get_host_pd1(struct cppi41_channel *c)
+{
+	u32 reg;
+
+	reg = 0;
+
+	return reg;
+}
+
+static u32 get_host_pd2(struct cppi41_channel *c)
+{
+	u32 reg;
+
+	reg = DESC_TYPE_USB;
+	reg |= c->q_comp_num;
+
+	return reg;
+}
+
+static u32 get_host_pd3(u32 length)
+{
+	u32 reg;
+
+	/* PD3 = packet size */
+	reg = length;
+
+	return reg;
+}
+
+static u32 get_host_pd6(u32 length)
+{
+	u32 reg;
+
+	/* PD6 buffer size */
+	reg = DESC_PD_COMPLETE;
+	reg |= length;
+
+	return reg;
+}
+
+static u32 get_host_pd4_or_7(u32 addr)
+{
+	u32 reg;
+
+	reg = addr;
+
+	return reg;
+}
+
+static u32 get_host_pd5(void)
+{
+	u32 reg;
+
+	reg = 0;
+
+	return reg;
+}
+
+static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
+	struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len,
+	enum dma_transfer_direction dir, unsigned long tx_flags, void *context)
+{
+	struct cppi41_channel *c = to_cpp41_chan(chan);
+	struct cppi41_desc *d;
+	struct scatterlist *sg;
+	unsigned int i;
+	unsigned int num;
+
+	num = 0;
+	d = c->desc;
+	for_each_sg(sgl, sg, sg_len, i) {
+		u32 addr;
+		u32 len;
+
+		/* We need to use more than one desc once musb supports sg */
+		BUG_ON(num > 0);
+		addr = lower_32_bits(sg_dma_address(sg));
+		len = sg_dma_len(sg);
+
+		d->pd0 = get_host_pd0(len);
+		d->pd1 = get_host_pd1(c);
+		d->pd2 = get_host_pd2(c);
+		d->pd3 = get_host_pd3(len);
+		d->pd4 = get_host_pd4_or_7(addr);
+		d->pd5 = get_host_pd5();
+		d->pd6 = get_host_pd6(len);
+		d->pd7 = get_host_pd4_or_7(addr);
+
+		d++;
+	}
+
+	return &c->txd;
+}
+
+static int cpp41_cfg_chan(struct cppi41_channel *c,
+		struct dma_slave_config *cfg)
+{
+	return 0;
+}
+
+static void cppi41_compute_td_desc(struct cppi41_desc *d)
+{
+	d->pd0 = DESC_TYPE_TEARD << DESC_TYPE;
+}
+
+static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num)
+{
+	u32 desc;
+
+	desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num));
+	desc &= ~0x1f;
+	return desc;
+}
+
+static int cppi41_tear_down_chan(struct cppi41_channel *c)
+{
+	struct cppi41_dd *cdd = c->cdd;
+	struct cppi41_desc *td;
+	u32 reg;
+	u32 desc_phys;
+	u32 td_desc_phys;
+
+	td = cdd->cd;
+	td += cdd->first_td_desc;
+
+	td_desc_phys = cdd->descs_phys;
+	td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc);
+
+	if (!c->td_queued) {
+		cppi41_compute_td_desc(td);
+		__iowmb();
+
+		reg = (sizeof(struct cppi41_desc) - 24) / 4;
+		reg |= td_desc_phys;
+		cppi_writel(reg, cdd->qmgr_mem +
+				QMGR_QUEUE_D(cdd->td_queue.submit));
+
+		reg = GCR_CHAN_ENABLE;
+		if (!c->is_tx) {
+			reg |= GCR_STARV_RETRY;
+			reg |= GCR_DESC_TYPE_HOST;
+			reg |= c->q_comp_num;
+		}
+		reg |= GCR_TEARDOWN;
+		cppi_writel(reg, c->gcr_reg);
+		c->td_queued = 1;
+		c->td_retry = 100;
+	}
+
+	if (!c->td_seen) {
+		unsigned td_comp_queue;
+
+		if (c->is_tx)
+			td_comp_queue =  cdd->td_queue.complete;
+		else
+			td_comp_queue =  c->q_comp_num;
+
+		desc_phys = cppi41_pop_desc(cdd, td_comp_queue);
+		if (desc_phys) {
+			__iormb();
+
+			if (desc_phys == td_desc_phys) {
+				u32 pd0;
+				pd0 = td->pd0;
+				WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD);
+				WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX));
+				WARN_ON((pd0 & 0x1f) != c->port_num);
+			} else {
+				WARN_ON_ONCE(1);
+			}
+			c->td_seen = 1;
+		}
+	}
+	if (!c->td_desc_seen) {
+		desc_phys = cppi41_pop_desc(cdd, c->q_comp_num);
+		if (desc_phys) {
+			__iormb();
+			WARN_ON(c->desc_phys != desc_phys);
+			c->td_desc_seen = 1;
+		}
+	}
+	c->td_retry--;
+	/*
+	 * If the TX descriptor / channel is in use, the caller needs to poke
+	 * his TD bit multiple times. After that he hardware releases the
+	 * transfer descriptor followed by TD descriptor. Waiting seems not to
+	 * cause any difference.
+	 * RX seems to be thrown out right away. However once the TearDown
+	 * descriptor gets through we are done. If we have seens the transfer
+	 * descriptor before the TD we fetch it from enqueue, it has to be
+	 * there waiting for us.
+	 */
+	if (!c->td_seen && c->td_retry)
+		return -EAGAIN;
+
+	WARN_ON(!c->td_retry);
+	if (!c->td_desc_seen) {
+		desc_phys = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
+		WARN_ON(!desc_phys);
+	}
+
+	c->td_queued = 0;
+	c->td_seen = 0;
+	c->td_desc_seen = 0;
+	cppi_writel(0, c->gcr_reg);
+	return 0;
+}
+
+static int cppi41_stop_chan(struct dma_chan *chan)
+{
+	struct cppi41_channel *c = to_cpp41_chan(chan);
+	struct cppi41_dd *cdd = c->cdd;
+	u32 desc_num;
+	u32 desc_phys;
+	int ret;
+
+	ret = cppi41_tear_down_chan(c);
+	if (ret)
+		return ret;
+
+	desc_phys = lower_32_bits(c->desc_phys);
+	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+	WARN_ON(!cdd->chan_busy[desc_num]);
+	cdd->chan_busy[desc_num] = NULL;
+
+	return 0;
+}
+
+static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+	unsigned long arg)
+{
+	struct cppi41_channel *c = to_cpp41_chan(chan);
+	int ret;
+
+	switch (cmd) {
+	case DMA_SLAVE_CONFIG:
+		ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg);
+		break;
+
+	case DMA_TERMINATE_ALL:
+		ret = cppi41_stop_chan(chan);
+		break;
+
+	default:
+		ret = -ENXIO;
+		break;
+	}
+	return ret;
+}
+
+static void cleanup_chans(struct cppi41_dd *cdd)
+{
+	while (!list_empty(&cdd->ddev.channels)) {
+		struct cppi41_channel *cchan;
+
+		cchan = list_first_entry(&cdd->ddev.channels,
+				struct cppi41_channel, chan.device_node);
+		list_del(&cchan->chan.device_node);
+		kfree(cchan);
+	}
+}
+
+static int cppi41_add_chans(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+	struct cppi41_channel *cchan;
+	int i;
+	int ret;
+	u32 n_chans;
+
+	ret = of_property_read_u32(pdev->dev.of_node, "#dma-channels",
+			&n_chans);
+	if (ret)
+		return ret;
+	/*
+	 * The channels can only be used as TX or as RX. So we add twice
+	 * that much dma channels because USB can only do RX or TX.
+	 */
+	n_chans *= 2;
+
+	for (i = 0; i < n_chans; i++) {
+		cchan = kzalloc(sizeof(*cchan), GFP_KERNEL);
+		if (!cchan)
+			goto err;
+
+		cchan->cdd = cdd;
+		if (i & 1) {
+			cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1);
+			cchan->is_tx = 1;
+		} else {
+			cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1);
+			cchan->is_tx = 0;
+		}
+		cchan->port_num = i >> 1;
+		cchan->desc = &cdd->cd[i];
+		cchan->desc_phys = cdd->descs_phys;
+		cchan->desc_phys += i * sizeof(struct cppi41_desc);
+		cchan->chan.device = &cdd->ddev;
+		list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels);
+	}
+	cdd->first_td_desc = n_chans;
+
+	return 0;
+err:
+	cleanup_chans(cdd);
+	return -ENOMEM;
+}
+
+static void purge_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+	unsigned int mem_decs;
+	int i;
+
+	mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc);
+
+	for (i = 0; i < DESCS_AREAS; i++) {
+
+		cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i));
+		cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+		dma_free_coherent(&pdev->dev, mem_decs, cdd->cd,
+				cdd->descs_phys);
+	}
+}
+
+static void disable_sched(struct cppi41_dd *cdd)
+{
+	cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static void deinit_cpii41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+	disable_sched(cdd);
+
+	purge_descs(pdev, cdd);
+
+	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+	dma_free_coherent(&pdev->dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch,
+			cdd->scratch_phys);
+}
+
+static int init_descs(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+	unsigned int desc_size;
+	unsigned int mem_decs;
+	int i;
+	u32 reg;
+	u32 idx;
+
+	BUILD_BUG_ON(sizeof(struct cppi41_desc) &
+			(sizeof(struct cppi41_desc) - 1));
+	BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32);
+	BUILD_BUG_ON(ALLOC_DECS_NUM < 32);
+
+	desc_size = sizeof(struct cppi41_desc);
+	mem_decs = ALLOC_DECS_NUM * desc_size;
+
+	idx = 0;
+	for (i = 0; i < DESCS_AREAS; i++) {
+
+		reg = idx << QMGR_MEMCTRL_IDX_SH;
+		reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH;
+		reg |= ilog2(ALLOC_DECS_NUM) - 5;
+
+		BUILD_BUG_ON(DESCS_AREAS != 1);
+		cdd->cd = dma_alloc_coherent(&pdev->dev, mem_decs,
+				&cdd->descs_phys, GFP_KERNEL);
+		if (!cdd->cd)
+			return -ENOMEM;
+
+		cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i));
+		cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i));
+
+		idx += ALLOC_DECS_NUM;
+	}
+	return 0;
+}
+
+static void init_sched(struct cppi41_dd *cdd)
+{
+	unsigned ch;
+	unsigned word;
+	u32 reg;
+
+	word = 0;
+	cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
+	for (ch = 0; ch < 15 * 2; ch += 2) {
+
+		reg = SCHED_ENTRY0_CHAN(ch);
+		reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
+
+		reg |= SCHED_ENTRY2_CHAN(ch + 1);
+		reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX;
+		cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
+		word++;
+	}
+	reg = 15 * 2 * 2 - 1;
+	reg |= DMA_SCHED_CTRL_EN;
+	cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
+}
+
+static int init_cppi41(struct platform_device *pdev, struct cppi41_dd *cdd)
+{
+	int ret;
+
+	BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1));
+	cdd->qmgr_scratch = dma_alloc_coherent(&pdev->dev, QMGR_SCRATCH_SIZE,
+			&cdd->scratch_phys, GFP_KERNEL);
+	if (!cdd->qmgr_scratch)
+		return -ENOMEM;
+
+	cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
+	cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE);
+	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
+
+	ret = init_descs(pdev, cdd);
+	if (ret)
+		goto err_td;
+
+	cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ);
+	init_sched(cdd);
+	return 0;
+err_td:
+	deinit_cpii41(pdev, cdd);
+	return ret;
+}
+
+static struct platform_driver cpp41_dma_driver;
+/*
+ * The param format is:
+ * X Y
+ * X: Port
+ * Y: 0 = RX else TX
+ */
+#define INFO_PORT	0
+#define INFO_IS_TX	1
+
+static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
+{
+	struct cppi41_channel *cchan;
+	struct cppi41_dd *cdd;
+	const struct chan_queues *queues;
+	u32 *num = param;
+
+	if (chan->device->dev->driver != &cpp41_dma_driver.driver)
+		return false;
+
+	cchan = to_cpp41_chan(chan);
+
+	if (cchan->port_num != num[INFO_PORT])
+		return false;
+
+	if (cchan->is_tx && !num[INFO_IS_TX])
+		return false;
+	cdd = cchan->cdd;
+	if (cchan->is_tx)
+		queues = cdd->queues_tx;
+	else
+		queues = cdd->queues_rx;
+
+	BUILD_BUG_ON(ARRAY_SIZE(usb_queues_rx) != ARRAY_SIZE(usb_queues_tx));
+	if (WARN_ON(cchan->port_num > ARRAY_SIZE(usb_queues_rx)))
+		return false;
+
+	cchan->q_num = queues[cchan->port_num].submit;
+	cchan->q_comp_num = queues[cchan->port_num].complete;
+	return true;
+}
+
+static struct of_dma_filter_info cpp41_dma_info = {
+	.filter_fn = cpp41_dma_filter_fn,
+};
+
+static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
+		struct of_dma *ofdma)
+{
+	int count = dma_spec->args_count;
+	struct of_dma_filter_info *info = ofdma->of_dma_data;
+
+	if (!info || !info->filter_fn)
+		return NULL;
+
+	if (count != 2)
+		return NULL;
+
+	return dma_request_channel(info->dma_cap, info->filter_fn,
+			&dma_spec->args[0]);
+}
+
+static const struct cppi_glue_infos usb_infos = {
+	.isr = cppi41_irq,
+	.queues_rx = usb_queues_rx,
+	.queues_tx = usb_queues_tx,
+	.td_queue = { .submit = 31, .complete = 0 },
+};
+
+static const struct of_device_id cppi41_dma_ids[] = {
+	{ .compatible = "ti,am3359-cppi41", .data = &usb_infos},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cppi41_dma_ids);
+
+static const struct cppi_glue_infos *get_glue_info(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id;
+
+	of_id = of_match_node(cppi41_dma_ids, pdev->dev.of_node);
+	if (!of_id)
+		return NULL;
+	return of_id->data;
+}
+
+static int cppi41_dma_probe(struct platform_device *pdev)
+{
+	struct cppi41_dd *cdd;
+	const struct cppi_glue_infos *glue_info;
+	int irq;
+	int ret;
+
+	glue_info = get_glue_info(pdev);
+	if (!glue_info)
+		return -EINVAL;
+
+	cdd = kzalloc(sizeof(*cdd), GFP_KERNEL);
+	if (!cdd)
+		return -ENOMEM;
+
+	dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask);
+	cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources;
+	cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources;
+	cdd->ddev.device_tx_status = cppi41_dma_tx_status;
+	cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
+	cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
+	cdd->ddev.device_control = cppi41_dma_control;
+	cdd->ddev.dev = &pdev->dev;
+	INIT_LIST_HEAD(&cdd->ddev.channels);
+	cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
+
+	cdd->usbss_mem = of_iomap(pdev->dev.of_node, 0);
+	cdd->ctrl_mem = of_iomap(pdev->dev.of_node, 1);
+	cdd->sched_mem = of_iomap(pdev->dev.of_node, 2);
+	cdd->qmgr_mem = of_iomap(pdev->dev.of_node, 3);
+
+	if (!cdd->usbss_mem || !cdd->ctrl_mem || !cdd->sched_mem ||
+			!cdd->qmgr_mem) {
+		ret = -ENXIO;
+		goto err_remap;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	ret = pm_runtime_get_sync(&pdev->dev);
+	if (ret)
+		goto err_get_sync;
+
+	cdd->queues_rx = glue_info->queues_rx;
+	cdd->queues_tx = glue_info->queues_tx;
+	cdd->td_queue = glue_info->td_queue;
+
+	ret = init_cppi41(pdev, cdd);
+	if (ret)
+		goto err_init_cppi;
+
+	ret = cppi41_add_chans(pdev, cdd);
+	if (ret)
+		goto err_chans;
+
+	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (!irq)
+		goto err_irq;
+
+	cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER);
+
+	ret = request_irq(irq, glue_info->isr, IRQF_SHARED,
+			dev_name(&pdev->dev), cdd);
+	if (ret)
+		goto err_irq;
+	cdd->irq = irq;
+
+	ret = dma_async_device_register(&cdd->ddev);
+	if (ret)
+		goto err_dma_reg;
+
+	ret = of_dma_controller_register(pdev->dev.of_node,
+			cppi41_dma_xlate, &cpp41_dma_info);
+	if (ret)
+		goto err_of;
+
+	platform_set_drvdata(pdev, cdd);
+	return 0;
+err_of:
+	dma_async_device_unregister(&cdd->ddev);
+err_dma_reg:
+	free_irq(irq, cdd);
+err_irq:
+	cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+	cleanup_chans(cdd);
+err_chans:
+	deinit_cpii41(pdev, cdd);
+err_init_cppi:
+	pm_runtime_put(&pdev->dev);
+err_get_sync:
+	pm_runtime_disable(&pdev->dev);
+	iounmap(cdd->usbss_mem);
+	iounmap(cdd->ctrl_mem);
+	iounmap(cdd->sched_mem);
+	iounmap(cdd->qmgr_mem);
+err_remap:
+	kfree(cdd);
+	return ret;
+}
+
+static int cppi41_dma_remove(struct platform_device *pdev)
+{
+	struct cppi41_dd *cdd = platform_get_drvdata(pdev);
+
+	of_dma_controller_free(pdev->dev.of_node);
+	dma_async_device_unregister(&cdd->ddev);
+
+	cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR);
+	free_irq(cdd->irq, cdd);
+	cleanup_chans(cdd);
+	deinit_cpii41(pdev, cdd);
+	iounmap(cdd->usbss_mem);
+	iounmap(cdd->ctrl_mem);
+	iounmap(cdd->sched_mem);
+	iounmap(cdd->qmgr_mem);
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	kfree(cdd);
+	return 0;
+}
+
+static struct platform_driver cpp41_dma_driver = {
+	.probe  = cppi41_dma_probe,
+	.remove = cppi41_dma_remove,
+	.driver = {
+		.name = "cppi41-dma-engine",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(cppi41_dma_ids),
+	},
+};
+
+module_platform_driver(cpp41_dma_driver);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9e56745..99af4db 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -87,7 +87,8 @@
 	return chan_dev->chan;
 }
 
-static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t memcpy_count_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct dma_chan *chan;
 	unsigned long count = 0;
@@ -106,9 +107,10 @@
 
 	return err;
 }
+static DEVICE_ATTR_RO(memcpy_count);
 
-static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
-				      char *buf)
+static ssize_t bytes_transferred_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
 {
 	struct dma_chan *chan;
 	unsigned long count = 0;
@@ -127,8 +129,10 @@
 
 	return err;
 }
+static DEVICE_ATTR_RO(bytes_transferred);
 
-static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t in_use_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct dma_chan *chan;
 	int err;
@@ -143,13 +147,15 @@
 
 	return err;
 }
+static DEVICE_ATTR_RO(in_use);
 
-static struct device_attribute dma_attrs[] = {
-	__ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
-	__ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
-	__ATTR(in_use, S_IRUGO, show_in_use, NULL),
-	__ATTR_NULL
+static struct attribute *dma_dev_attrs[] = {
+	&dev_attr_memcpy_count.attr,
+	&dev_attr_bytes_transferred.attr,
+	&dev_attr_in_use.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(dma_dev);
 
 static void chan_dev_release(struct device *dev)
 {
@@ -167,7 +173,7 @@
 
 static struct class dma_devclass = {
 	.name		= "dma",
-	.dev_attrs	= dma_attrs,
+	.dev_groups	= dma_dev_groups,
 	.dev_release	= chan_dev_release,
 };
 
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 8b6a034..3c9e4e9 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -123,7 +123,7 @@
 	u32 reg = 0;
 
 	amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, &reg);
-	reg &= 0xfffffffe;
+	reg &= (pvt->model >= 0x30) ? ~3 : ~1;
 	reg |= dct;
 	amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
 }
@@ -133,8 +133,9 @@
 {
 	u8 dct  = 0;
 
+	/* For F15 M30h, the second dct is DCT 3, refer to BKDG Section 2.10 */
 	if (addr >= 0x140 && addr <= 0x1a0) {
-		dct   = 1;
+		dct   = (pvt->model >= 0x30) ? 3 : 1;
 		addr -= 0x100;
 	}
 
@@ -202,11 +203,11 @@
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u32 min_scrubrate = 0x5;
 
-	if (boot_cpu_data.x86 == 0xf)
+	if (pvt->fam == 0xf)
 		min_scrubrate = 0x0;
 
-	/* F15h Erratum #505 */
-	if (boot_cpu_data.x86 == 0x15)
+	/* Erratum #505 */
+	if (pvt->fam == 0x15 && pvt->model < 0x10)
 		f15h_select_dct(pvt, 0);
 
 	return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
@@ -218,8 +219,8 @@
 	u32 scrubval = 0;
 	int i, retval = -EINVAL;
 
-	/* F15h Erratum #505 */
-	if (boot_cpu_data.x86 == 0x15)
+	/* Erratum #505 */
+	if (pvt->fam == 0x15 && pvt->model < 0x10)
 		f15h_select_dct(pvt, 0);
 
 	amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval);
@@ -335,7 +336,7 @@
 	u64 csbase, csmask, base_bits, mask_bits;
 	u8 addr_shift;
 
-	if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
+	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
 		csbase		= pvt->csels[dct].csbases[csrow];
 		csmask		= pvt->csels[dct].csmasks[csrow];
 		base_bits	= GENMASK(21, 31) | GENMASK(9, 15);
@@ -343,10 +344,11 @@
 		addr_shift	= 4;
 
 	/*
-	* F16h needs two addr_shift values: 8 for high and 6 for low
-	* (cf. F16h BKDG).
-	*/
-	} else if (boot_cpu_data.x86 == 0x16) {
+	 * F16h and F15h, models 30h and later need two addr_shift values:
+	 * 8 for high and 6 for low (cf. F16h BKDG).
+	 */
+	} else if (pvt->fam == 0x16 ||
+		  (pvt->fam == 0x15 && pvt->model >= 0x30)) {
 		csbase          = pvt->csels[dct].csbases[csrow];
 		csmask          = pvt->csels[dct].csmasks[csrow >> 1];
 
@@ -367,7 +369,7 @@
 		csmask		= pvt->csels[dct].csmasks[csrow >> 1];
 		addr_shift	= 8;
 
-		if (boot_cpu_data.x86 == 0x15)
+		if (pvt->fam == 0x15)
 			base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13);
 		else
 			base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13);
@@ -447,14 +449,14 @@
 	struct amd64_pvt *pvt = mci->pvt_info;
 
 	/* only revE and later have the DRAM Hole Address Register */
-	if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
+	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_E) {
 		edac_dbg(1, "  revision %d for node %d does not support DHAR\n",
 			 pvt->ext_model, pvt->mc_node_id);
 		return 1;
 	}
 
 	/* valid for Fam10h and above */
-	if (boot_cpu_data.x86 >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
+	if (pvt->fam >= 0x10 && !dhar_mem_hoist_valid(pvt)) {
 		edac_dbg(1, "  Dram Memory Hoisting is DISABLED on this system\n");
 		return 1;
 	}
@@ -486,10 +488,8 @@
 	*hole_base = dhar_base(pvt);
 	*hole_size = (1ULL << 32) - *hole_base;
 
-	if (boot_cpu_data.x86 > 0xf)
-		*hole_offset = f10_dhar_offset(pvt);
-	else
-		*hole_offset = k8_dhar_offset(pvt);
+	*hole_offset = (pvt->fam > 0xf) ? f10_dhar_offset(pvt)
+					: k8_dhar_offset(pvt);
 
 	edac_dbg(1, "  DHAR info for node %d base 0x%lx offset 0x%lx size 0x%lx\n",
 		 pvt->mc_node_id, (unsigned long)*hole_base,
@@ -663,7 +663,7 @@
 	u8 bit;
 	unsigned long edac_cap = EDAC_FLAG_NONE;
 
-	bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
+	bit = (pvt->fam > 0xf || pvt->ext_model >= K8_REV_F)
 		? 19
 		: 17;
 
@@ -675,7 +675,7 @@
 
 static void amd64_debug_display_dimm_sizes(struct amd64_pvt *, u8);
 
-static void amd64_dump_dramcfg_low(u32 dclr, int chan)
+static void amd64_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
 {
 	edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
 
@@ -686,7 +686,7 @@
 	edac_dbg(1, "  PAR/ERR parity: %s\n",
 		 (dclr & BIT(8)) ?  "enabled" : "disabled");
 
-	if (boot_cpu_data.x86 == 0x10)
+	if (pvt->fam == 0x10)
 		edac_dbg(1, "  DCT 128bit mode width: %s\n",
 			 (dclr & BIT(11)) ?  "128b" : "64b");
 
@@ -709,21 +709,21 @@
 		 (pvt->nbcap & NBCAP_SECDED) ? "yes" : "no",
 		 (pvt->nbcap & NBCAP_CHIPKILL) ? "yes" : "no");
 
-	amd64_dump_dramcfg_low(pvt->dclr0, 0);
+	amd64_dump_dramcfg_low(pvt, pvt->dclr0, 0);
 
 	edac_dbg(1, "F3xB0 (Online Spare): 0x%08x\n", pvt->online_spare);
 
 	edac_dbg(1, "F1xF0 (DRAM Hole Address): 0x%08x, base: 0x%08x, offset: 0x%08x\n",
 		 pvt->dhar, dhar_base(pvt),
-		 (boot_cpu_data.x86 == 0xf) ? k8_dhar_offset(pvt)
-		 : f10_dhar_offset(pvt));
+		 (pvt->fam == 0xf) ? k8_dhar_offset(pvt)
+				   : f10_dhar_offset(pvt));
 
 	edac_dbg(1, "  DramHoleValid: %s\n", dhar_valid(pvt) ? "yes" : "no");
 
 	amd64_debug_display_dimm_sizes(pvt, 0);
 
 	/* everything below this point is Fam10h and above */
-	if (boot_cpu_data.x86 == 0xf)
+	if (pvt->fam == 0xf)
 		return;
 
 	amd64_debug_display_dimm_sizes(pvt, 1);
@@ -732,17 +732,20 @@
 
 	/* Only if NOT ganged does dclr1 have valid info */
 	if (!dct_ganging_enabled(pvt))
-		amd64_dump_dramcfg_low(pvt->dclr1, 1);
+		amd64_dump_dramcfg_low(pvt, pvt->dclr1, 1);
 }
 
 /*
- * see BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
+ * See BKDG, F2x[1,0][5C:40], F2[1,0][6C:60]
  */
 static void prep_chip_selects(struct amd64_pvt *pvt)
 {
-	if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
+	if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
 		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
 		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
+	} else if (pvt->fam == 0x15 && pvt->model >= 0x30) {
+		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
+		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
 	} else {
 		pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
 		pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 4;
@@ -768,7 +771,7 @@
 			edac_dbg(0, "  DCSB0[%d]=0x%08x reg: F2x%x\n",
 				 cs, *base0, reg0);
 
-		if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
+		if (pvt->fam == 0xf || dct_ganging_enabled(pvt))
 			continue;
 
 		if (!amd64_read_dct_pci_cfg(pvt, reg1, base1))
@@ -786,7 +789,7 @@
 			edac_dbg(0, "    DCSM0[%d]=0x%08x reg: F2x%x\n",
 				 cs, *mask0, reg0);
 
-		if (boot_cpu_data.x86 == 0xf || dct_ganging_enabled(pvt))
+		if (pvt->fam == 0xf || dct_ganging_enabled(pvt))
 			continue;
 
 		if (!amd64_read_dct_pci_cfg(pvt, reg1, mask1))
@@ -800,9 +803,9 @@
 	enum mem_type type;
 
 	/* F15h supports only DDR3 */
-	if (boot_cpu_data.x86 >= 0x15)
+	if (pvt->fam >= 0x15)
 		type = (pvt->dclr0 & BIT(16)) ?	MEM_DDR3 : MEM_RDDR3;
-	else if (boot_cpu_data.x86 == 0x10 || pvt->ext_model >= K8_REV_F) {
+	else if (pvt->fam == 0x10 || pvt->ext_model >= K8_REV_F) {
 		if (pvt->dchr0 & DDR3_MODE)
 			type = (pvt->dclr0 & BIT(16)) ?	MEM_DDR3 : MEM_RDDR3;
 		else
@@ -835,14 +838,13 @@
 }
 
 /* On F10h and later ErrAddr is MC4_ADDR[47:1] */
-static u64 get_error_address(struct mce *m)
+static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m)
 {
-	struct cpuinfo_x86 *c = &boot_cpu_data;
 	u64 addr;
 	u8 start_bit = 1;
 	u8 end_bit   = 47;
 
-	if (c->x86 == 0xf) {
+	if (pvt->fam == 0xf) {
 		start_bit = 3;
 		end_bit   = 39;
 	}
@@ -852,7 +854,7 @@
 	/*
 	 * Erratum 637 workaround
 	 */
-	if (c->x86 == 0x15) {
+	if (pvt->fam == 0x15) {
 		struct amd64_pvt *pvt;
 		u64 cc6_base, tmp_addr;
 		u32 tmp;
@@ -916,15 +918,15 @@
 static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
 {
 	struct amd_northbridge *nb;
-	struct pci_dev *misc, *f1 = NULL;
-	struct cpuinfo_x86 *c = &boot_cpu_data;
+	struct pci_dev *f1 = NULL;
+	unsigned int pci_func;
 	int off = range << 3;
 	u32 llim;
 
 	amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
 	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
 
-	if (c->x86 == 0xf)
+	if (pvt->fam == 0xf)
 		return;
 
 	if (!dram_rw(pvt, range))
@@ -934,15 +936,17 @@
 	amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
 
 	/* F15h: factor in CC6 save area by reading dst node's limit reg */
-	if (c->x86 != 0x15)
+	if (pvt->fam != 0x15)
 		return;
 
 	nb = node_to_amd_nb(dram_dst_node(pvt, range));
 	if (WARN_ON(!nb))
 		return;
 
-	misc = nb->misc;
-	f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
+	pci_func = (pvt->model == 0x30) ? PCI_DEVICE_ID_AMD_15H_M30H_NB_F1
+					: PCI_DEVICE_ID_AMD_15H_NB_F1;
+
+	f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
 	if (WARN_ON(!f1))
 		return;
 
@@ -1089,7 +1093,7 @@
 	int i, j, channels = 0;
 
 	/* On F10h, if we are in 128 bit mode, then we are using 2 channels */
-	if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
+	if (pvt->fam == 0x10 && (pvt->dclr0 & WIDTH_128))
 		return 2;
 
 	/*
@@ -1173,7 +1177,7 @@
 }
 
 /*
- * F16h has only limited cs_modes
+ * F16h and F15h model 30h have only limited cs_modes.
  */
 static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
 				unsigned cs_mode)
@@ -1190,7 +1194,7 @@
 static void read_dram_ctl_register(struct amd64_pvt *pvt)
 {
 
-	if (boot_cpu_data.x86 == 0xf)
+	if (pvt->fam == 0xf)
 		return;
 
 	if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
@@ -1218,6 +1222,29 @@
 }
 
 /*
+ * Determine channel (DCT) based on the interleaving mode (see F15h M30h BKDG,
+ * 2.10.12 Memory Interleaving Modes).
+ */
+static u8 f15_m30h_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
+				     u8 intlv_en, int num_dcts_intlv,
+				     u32 dct_sel)
+{
+	u8 channel = 0;
+	u8 select;
+
+	if (!(intlv_en))
+		return (u8)(dct_sel);
+
+	if (num_dcts_intlv == 2) {
+		select = (sys_addr >> 8) & 0x3;
+		channel = select ? 0x3 : 0;
+	} else if (num_dcts_intlv == 4)
+		channel = (sys_addr >> 8) & 0x7;
+
+	return channel;
+}
+
+/*
  * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
  * Interleaving Modes.
  */
@@ -1366,6 +1393,10 @@
 			 (in_addr & cs_mask), (cs_base & cs_mask));
 
 		if ((in_addr & cs_mask) == (cs_base & cs_mask)) {
+			if (pvt->fam == 0x15 && pvt->model >= 0x30) {
+				cs_found =  csrow;
+				break;
+			}
 			cs_found = f10_process_possible_spare(pvt, dct, csrow);
 
 			edac_dbg(1, " MATCH csrow=%d\n", cs_found);
@@ -1384,11 +1415,9 @@
 {
 	u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
 
-	if (boot_cpu_data.x86 == 0x10) {
+	if (pvt->fam == 0x10) {
 		/* only revC3 and revE have that feature */
-		if (boot_cpu_data.x86_model < 4 ||
-		    (boot_cpu_data.x86_model < 0xa &&
-		     boot_cpu_data.x86_mask < 3))
+		if (pvt->model < 4 || (pvt->model < 0xa && pvt->stepping < 3))
 			return sys_addr;
 	}
 
@@ -1492,20 +1521,143 @@
 	return cs_found;
 }
 
-static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
-				       int *chan_sel)
+static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
+					u64 sys_addr, int *chan_sel)
+{
+	int cs_found = -EINVAL;
+	int num_dcts_intlv = 0;
+	u64 chan_addr, chan_offset;
+	u64 dct_base, dct_limit;
+	u32 dct_cont_base_reg, dct_cont_limit_reg, tmp;
+	u8 channel, alias_channel, leg_mmio_hole, dct_sel, dct_offset_en;
+
+	u64 dhar_offset		= f10_dhar_offset(pvt);
+	u8 intlv_addr		= dct_sel_interleave_addr(pvt);
+	u8 node_id		= dram_dst_node(pvt, range);
+	u8 intlv_en		= dram_intlv_en(pvt, range);
+
+	amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &dct_cont_base_reg);
+	amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &dct_cont_limit_reg);
+
+	dct_offset_en		= (u8) ((dct_cont_base_reg >> 3) & BIT(0));
+	dct_sel			= (u8) ((dct_cont_base_reg >> 4) & 0x7);
+
+	edac_dbg(1, "(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
+		 range, sys_addr, get_dram_limit(pvt, range));
+
+	if (!(get_dram_base(pvt, range)  <= sys_addr) &&
+	    !(get_dram_limit(pvt, range) >= sys_addr))
+		return -EINVAL;
+
+	if (dhar_valid(pvt) &&
+	    dhar_base(pvt) <= sys_addr &&
+	    sys_addr < BIT_64(32)) {
+		amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
+			    sys_addr);
+		return -EINVAL;
+	}
+
+	/* Verify sys_addr is within DCT Range. */
+	dct_base = (u64) dct_sel_baseaddr(pvt);
+	dct_limit = (dct_cont_limit_reg >> 11) & 0x1FFF;
+
+	if (!(dct_cont_base_reg & BIT(0)) &&
+	    !(dct_base <= (sys_addr >> 27) &&
+	      dct_limit >= (sys_addr >> 27)))
+		return -EINVAL;
+
+	/* Verify number of dct's that participate in channel interleaving. */
+	num_dcts_intlv = (int) hweight8(intlv_en);
+
+	if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4))
+		return -EINVAL;
+
+	channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
+					     num_dcts_intlv, dct_sel);
+
+	/* Verify we stay within the MAX number of channels allowed */
+	if (channel > 4 || channel < 0)
+		return -EINVAL;
+
+	leg_mmio_hole = (u8) (dct_cont_base_reg >> 1 & BIT(0));
+
+	/* Get normalized DCT addr */
+	if (leg_mmio_hole && (sys_addr >= BIT_64(32)))
+		chan_offset = dhar_offset;
+	else
+		chan_offset = dct_base << 27;
+
+	chan_addr = sys_addr - chan_offset;
+
+	/* remove channel interleave */
+	if (num_dcts_intlv == 2) {
+		if (intlv_addr == 0x4)
+			chan_addr = ((chan_addr >> 9) << 8) |
+						(chan_addr & 0xff);
+		else if (intlv_addr == 0x5)
+			chan_addr = ((chan_addr >> 10) << 9) |
+						(chan_addr & 0x1ff);
+		else
+			return -EINVAL;
+
+	} else if (num_dcts_intlv == 4) {
+		if (intlv_addr == 0x4)
+			chan_addr = ((chan_addr >> 10) << 8) |
+							(chan_addr & 0xff);
+		else if (intlv_addr == 0x5)
+			chan_addr = ((chan_addr >> 11) << 9) |
+							(chan_addr & 0x1ff);
+		else
+			return -EINVAL;
+	}
+
+	if (dct_offset_en) {
+		amd64_read_pci_cfg(pvt->F1,
+				   DRAM_CONT_HIGH_OFF + (int) channel * 4,
+				   &tmp);
+		chan_addr +=  (u64) ((tmp >> 11) & 0xfff) << 27;
+	}
+
+	f15h_select_dct(pvt, channel);
+
+	edac_dbg(1, "   Normalized DCT addr: 0x%llx\n", chan_addr);
+
+	/*
+	 * Find Chip select:
+	 * if channel = 3, then alias it to 1. This is because, in F15 M30h,
+	 * there is support for 4 DCT's, but only 2 are currently functional.
+	 * They are DCT0 and DCT3. But we have read all registers of DCT3 into
+	 * pvt->csels[1]. So we need to use '1' here to get correct info.
+	 * Refer F15 M30h BKDG Section 2.10 and 2.10.3 for clarifications.
+	 */
+	alias_channel =  (channel == 3) ? 1 : channel;
+
+	cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, alias_channel);
+
+	if (cs_found >= 0)
+		*chan_sel = alias_channel;
+
+	return cs_found;
+}
+
+static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt,
+					u64 sys_addr,
+					int *chan_sel)
 {
 	int cs_found = -EINVAL;
 	unsigned range;
 
 	for (range = 0; range < DRAM_RANGES; range++) {
-
 		if (!dram_rw(pvt, range))
 			continue;
 
-		if ((get_dram_base(pvt, range)  <= sys_addr) &&
-		    (get_dram_limit(pvt, range) >= sys_addr)) {
+		if (pvt->fam == 0x15 && pvt->model >= 0x30)
+			cs_found = f15_m30h_match_to_this_node(pvt, range,
+							       sys_addr,
+							       chan_sel);
 
+		else if ((get_dram_base(pvt, range)  <= sys_addr) &&
+			 (get_dram_limit(pvt, range) >= sys_addr)) {
 			cs_found = f1x_match_to_this_node(pvt, range,
 							  sys_addr, chan_sel);
 			if (cs_found >= 0)
@@ -1554,7 +1706,7 @@
 	u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
 	u32 dbam  = ctrl ? pvt->dbam1 : pvt->dbam0;
 
-	if (boot_cpu_data.x86 == 0xf) {
+	if (pvt->fam == 0xf) {
 		/* K8 families < revF not supported yet */
 	       if (pvt->ext_model < K8_REV_F)
 			return;
@@ -1624,6 +1776,17 @@
 			.read_dct_pci_cfg	= f15_read_dct_pci_cfg,
 		}
 	},
+	[F15_M30H_CPUS] = {
+		.ctl_name = "F15h_M30h",
+		.f1_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1,
+		.f3_id = PCI_DEVICE_ID_AMD_15H_M30H_NB_F3,
+		.ops = {
+			.early_channel_count	= f1x_early_channel_count,
+			.map_sysaddr_to_csrow	= f1x_map_sysaddr_to_csrow,
+			.dbam_to_cs		= f16_dbam_to_chip_select,
+			.read_dct_pci_cfg	= f15_read_dct_pci_cfg,
+		}
+	},
 	[F16_CPUS] = {
 		.ctl_name = "F16h",
 		.f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
@@ -1860,7 +2023,7 @@
 
 	memset(&err, 0, sizeof(err));
 
-	sys_addr = get_error_address(m);
+	sys_addr = get_error_address(pvt, m);
 
 	if (ecc_type == 2)
 		err.syndrome = extract_syndrome(m->status);
@@ -1921,10 +2084,9 @@
  */
 static void read_mc_regs(struct amd64_pvt *pvt)
 {
-	struct cpuinfo_x86 *c = &boot_cpu_data;
+	unsigned range;
 	u64 msr_val;
 	u32 tmp;
-	unsigned range;
 
 	/*
 	 * Retrieve TOP_MEM and TOP_MEM2; no masking off of reserved bits since
@@ -1985,14 +2147,14 @@
 
 	pvt->ecc_sym_sz = 4;
 
-	if (c->x86 >= 0x10) {
+	if (pvt->fam >= 0x10) {
 		amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
-		if (c->x86 != 0x16)
+		if (pvt->fam != 0x16)
 			/* F16h has only DCT0 */
 			amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
 
 		/* F10h, revD and later can do x8 ECC too */
-		if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
+		if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25))
 			pvt->ecc_sym_sz = 8;
 	}
 	dump_misc_regs(pvt);
@@ -2086,7 +2248,7 @@
 		bool row_dct0 = !!csrow_enabled(i, 0, pvt);
 		bool row_dct1 = false;
 
-		if (boot_cpu_data.x86 != 0xf)
+		if (pvt->fam != 0xf)
 			row_dct1 = !!csrow_enabled(i, 1, pvt);
 
 		if (!row_dct0 && !row_dct1)
@@ -2104,7 +2266,7 @@
 		}
 
 		/* K8 has only one DCT */
-		if (boot_cpu_data.x86 != 0xf && row_dct1) {
+		if (pvt->fam != 0xf && row_dct1) {
 			int row_dct1_pages = amd64_csrow_nr_pages(pvt, 1, i);
 
 			csrow->channels[1]->dimm->nr_pages = row_dct1_pages;
@@ -2333,13 +2495,14 @@
 
 static int set_mc_sysfs_attrs(struct mem_ctl_info *mci)
 {
+	struct amd64_pvt *pvt = mci->pvt_info;
 	int rc;
 
 	rc = amd64_create_sysfs_dbg_files(mci);
 	if (rc < 0)
 		return rc;
 
-	if (boot_cpu_data.x86 >= 0x10) {
+	if (pvt->fam >= 0x10) {
 		rc = amd64_create_sysfs_inject_files(mci);
 		if (rc < 0)
 			return rc;
@@ -2350,9 +2513,11 @@
 
 static void del_mc_sysfs_attrs(struct mem_ctl_info *mci)
 {
+	struct amd64_pvt *pvt = mci->pvt_info;
+
 	amd64_remove_sysfs_dbg_files(mci);
 
-	if (boot_cpu_data.x86 >= 0x10)
+	if (pvt->fam >= 0x10)
 		amd64_remove_sysfs_inject_files(mci);
 }
 
@@ -2387,10 +2552,14 @@
  */
 static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
 {
-	u8 fam = boot_cpu_data.x86;
 	struct amd64_family_type *fam_type = NULL;
 
-	switch (fam) {
+	pvt->ext_model  = boot_cpu_data.x86_model >> 4;
+	pvt->stepping	= boot_cpu_data.x86_mask;
+	pvt->model	= boot_cpu_data.x86_model;
+	pvt->fam	= boot_cpu_data.x86;
+
+	switch (pvt->fam) {
 	case 0xf:
 		fam_type		= &amd64_family_types[K8_CPUS];
 		pvt->ops		= &amd64_family_types[K8_CPUS].ops;
@@ -2402,6 +2571,12 @@
 		break;
 
 	case 0x15:
+		if (pvt->model == 0x30) {
+			fam_type	= &amd64_family_types[F15_M30H_CPUS];
+			pvt->ops	= &amd64_family_types[F15_M30H_CPUS].ops;
+			break;
+		}
+
 		fam_type		= &amd64_family_types[F15_CPUS];
 		pvt->ops		= &amd64_family_types[F15_CPUS].ops;
 		break;
@@ -2416,10 +2591,8 @@
 		return NULL;
 	}
 
-	pvt->ext_model = boot_cpu_data.x86_model >> 4;
-
 	amd64_info("%s %sdetected (node %d).\n", fam_type->ctl_name,
-		     (fam == 0xf ?
+		     (pvt->fam == 0xf ?
 				(pvt->ext_model >= K8_REV_F  ? "revF or later "
 							     : "revE or earlier ")
 				 : ""), pvt->mc_node_id);
@@ -2470,8 +2643,15 @@
 	layers[0].size = pvt->csels[0].b_cnt;
 	layers[0].is_virt_csrow = true;
 	layers[1].type = EDAC_MC_LAYER_CHANNEL;
-	layers[1].size = pvt->channel_count;
+
+	/*
+	 * Always allocate two channels since we can have setups with DIMMs on
+	 * only one channel. Also, this simplifies handling later for the price
+	 * of a couple of KBs tops.
+	 */
+	layers[1].size = 2;
 	layers[1].is_virt_csrow = false;
+
 	mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
 	if (!mci)
 		goto err_siblings;
@@ -2579,6 +2759,8 @@
 	struct ecc_settings *s = ecc_stngs[nid];
 
 	mci = find_mci_by_dev(&pdev->dev);
+	WARN_ON(!mci);
+
 	del_mc_sysfs_attrs(mci);
 	/* Remove from EDAC CORE tracking list */
 	mci = edac_mc_del_mc(&pdev->dev);
@@ -2638,6 +2820,14 @@
 	},
 	{
 		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.class		= 0,
+		.class_mask	= 0,
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_AMD,
 		.device		= PCI_DEVICE_ID_AMD_16H_NB_F2,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 2c6f113..d2443cf 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -170,6 +170,8 @@
 /*
  * PCI-defined configuration space registers
  */
+#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b
+#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c
 #define PCI_DEVICE_ID_AMD_15H_NB_F1	0x1601
 #define PCI_DEVICE_ID_AMD_15H_NB_F2	0x1602
 #define PCI_DEVICE_ID_AMD_16H_NB_F1	0x1531
@@ -181,13 +183,22 @@
 #define DRAM_BASE_LO			0x40
 #define DRAM_LIMIT_LO			0x44
 
-#define dram_intlv_en(pvt, i)		((u8)((pvt->ranges[i].base.lo >> 8) & 0x7))
+/*
+ * F15 M30h D18F1x2[1C:00]
+ */
+#define DRAM_CONT_BASE			0x200
+#define DRAM_CONT_LIMIT			0x204
+
+/*
+ * F15 M30h D18F1x2[4C:40]
+ */
+#define DRAM_CONT_HIGH_OFF		0x240
+
 #define dram_rw(pvt, i)			((u8)(pvt->ranges[i].base.lo & 0x3))
 #define dram_intlv_sel(pvt, i)		((u8)((pvt->ranges[i].lim.lo >> 8) & 0x7))
 #define dram_dst_node(pvt, i)		((u8)(pvt->ranges[i].lim.lo & 0x7))
 
 #define DHAR				0xf0
-#define dhar_valid(pvt)			((pvt)->dhar & BIT(0))
 #define dhar_mem_hoist_valid(pvt)	((pvt)->dhar & BIT(1))
 #define dhar_base(pvt)			((pvt)->dhar & 0xff000000)
 #define k8_dhar_offset(pvt)		(((pvt)->dhar & 0x0000ff00) << 16)
@@ -234,8 +245,6 @@
 #define DDR3_MODE			BIT(8)
 
 #define DCT_SEL_LO			0x110
-#define dct_sel_baseaddr(pvt)		((pvt)->dct_sel_lo & 0xFFFFF800)
-#define dct_sel_interleave_addr(pvt)	(((pvt)->dct_sel_lo >> 6) & 0x3)
 #define dct_high_range_enabled(pvt)	((pvt)->dct_sel_lo & BIT(0))
 #define dct_interleave_enabled(pvt)	((pvt)->dct_sel_lo & BIT(2))
 
@@ -297,6 +306,7 @@
 	K8_CPUS = 0,
 	F10_CPUS,
 	F15_CPUS,
+	F15_M30H_CPUS,
 	F16_CPUS,
 	NUM_FAMILIES,
 };
@@ -337,6 +347,10 @@
 	struct pci_dev *F1, *F2, *F3;
 
 	u16 mc_node_id;		/* MC index of this MC node */
+	u8 fam;			/* CPU family */
+	u8 model;		/* ... model */
+	u8 stepping;		/* ... stepping */
+
 	int ext_model;		/* extended model value of this node */
 	int channel_count;
 
@@ -414,6 +428,14 @@
 	return ((status >> 47) & 0xff) | ((status >> 16) & 0xff00);
 }
 
+static inline u8 dct_sel_interleave_addr(struct amd64_pvt *pvt)
+{
+	if (pvt->fam == 0x15 && pvt->model >= 0x30)
+		return (((pvt->dct_sel_hi >> 9) & 0x1) << 2) |
+			((pvt->dct_sel_lo >> 6) & 0x3);
+
+	return	((pvt)->dct_sel_lo >> 6) & 0x3;
+}
 /*
  * per-node ECC settings descriptor
  */
@@ -504,3 +526,33 @@
 {
 	write_cr0(read_cr0() & ~X86_CR0_CD);
 }
+
+static inline u8 dram_intlv_en(struct amd64_pvt *pvt, unsigned int i)
+{
+	if (pvt->fam == 0x15 && pvt->model >= 0x30) {
+		u32 tmp;
+		amd64_read_pci_cfg(pvt->F1, DRAM_CONT_LIMIT, &tmp);
+		return (u8) tmp & 0xF;
+	}
+	return (u8) (pvt->ranges[i].base.lo >> 8) & 0x7;
+}
+
+static inline u8 dhar_valid(struct amd64_pvt *pvt)
+{
+	if (pvt->fam == 0x15 && pvt->model >= 0x30) {
+		u32 tmp;
+		amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &tmp);
+		return (tmp >> 1) & BIT(0);
+	}
+	return (pvt)->dhar & BIT(0);
+}
+
+static inline u32 dct_sel_baseaddr(struct amd64_pvt *pvt)
+{
+	if (pvt->fam == 0x15 && pvt->model >= 0x30) {
+		u32 tmp;
+		amd64_read_pci_cfg(pvt->F1, DRAM_CONT_BASE, &tmp);
+		return (tmp >> 11) & 0x1FFF;
+	}
+	return (pvt)->dct_sel_lo & 0xFFFFF800;
+}
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index 7f3c571..df6575f 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -789,7 +789,7 @@
 	.exit = cpc925_htlink_exit,
 	.check = cpc925_htlink_check,
 	},
-	{0}, /* Terminated by NULL */
+	{ }
 };
 
 /*
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index e7c32c4..9f7e0e60 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -58,8 +58,10 @@
 	if (!val)
 		return -EINVAL;
 
-	ret = strict_strtol(val, 0, &l);
-	if (ret == -EINVAL || ((int)l != l))
+	ret = kstrtol(val, 0, &l);
+	if (ret)
+		return ret;
+	if ((int)l != l)
 		return -EINVAL;
 	*((int *)kp->arg) = l;
 
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index aa44c17..be10a74 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -260,8 +260,7 @@
 	i3200_process_error_info(mci, &info);
 }
 
-
-void __iomem *i3200_map_mchbar(struct pci_dev *pdev)
+static void __iomem *i3200_map_mchbar(struct pci_dev *pdev)
 {
 	union {
 		u64 mchbar;
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index c9db24d..1a4df82 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -248,8 +248,7 @@
 	x38_process_error_info(mci, &info);
 }
 
-
-void __iomem *x38_map_mchbar(struct pci_dev *pdev)
+static void __iomem *x38_map_mchbar(struct pci_dev *pdev)
 {
 	union {
 		u64 mchbar;
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 63f454e..f1d54a3 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -14,6 +14,10 @@
 
 comment "Extcon Device Drivers"
 
+config OF_EXTCON
+	def_tristate y
+	depends on OF
+
 config EXTCON_GPIO
 	tristate "GPIO extcon support"
 	depends on GPIOLIB
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 540e2c3..759fdae 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -2,6 +2,8 @@
 # Makefile for external connector class (extcon) devices
 #
 
+obj-$(CONFIG_OF_EXTCON)		+= of_extcon.o
+
 obj-$(CONFIG_EXTCON)		+= extcon-class.o
 obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
 obj-$(CONFIG_EXTCON_ADC_JACK)	+= extcon-adc-jack.o
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index d0233cd..5985807 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -87,7 +87,8 @@
 {
 	struct adc_jack_data *data = _data;
 
-	schedule_delayed_work(&data->handler, data->handling_delay);
+	queue_delayed_work(system_power_efficient_wq,
+			   &data->handler, data->handling_delay);
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index 7a1b4a7..e557130 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -890,8 +890,9 @@
 
 handled:
 	if (info->detecting)
-		schedule_delayed_work(&info->micd_timeout_work,
-				      msecs_to_jiffies(info->micd_timeout));
+		queue_delayed_work(system_power_efficient_wq,
+				   &info->micd_timeout_work,
+				   msecs_to_jiffies(info->micd_timeout));
 
 	pm_runtime_mark_last_busy(info->dev);
 	mutex_unlock(&info->lock);
@@ -912,8 +913,9 @@
 	mutex_unlock(&info->lock);
 
 	if (debounce)
-		schedule_delayed_work(&info->micd_detect_work,
-				      msecs_to_jiffies(debounce));
+		queue_delayed_work(system_power_efficient_wq,
+				   &info->micd_detect_work,
+				   msecs_to_jiffies(debounce));
 	else
 		arizona_micd_detect(&info->micd_detect_work.work);
 
@@ -967,12 +969,14 @@
 	if (val == info->last_jackdet) {
 		dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
 		if (cancelled_hp)
-			schedule_delayed_work(&info->hpdet_work,
-					      msecs_to_jiffies(HPDET_DEBOUNCE));
+			queue_delayed_work(system_power_efficient_wq,
+					   &info->hpdet_work,
+					   msecs_to_jiffies(HPDET_DEBOUNCE));
 
 		if (cancelled_mic)
-			schedule_delayed_work(&info->micd_timeout_work,
-					      msecs_to_jiffies(info->micd_timeout));
+			queue_delayed_work(system_power_efficient_wq,
+					   &info->micd_timeout_work,
+					   msecs_to_jiffies(info->micd_timeout));
 
 		goto out;
 	}
@@ -994,8 +998,9 @@
 
 			arizona_start_mic(info);
 		} else {
-			schedule_delayed_work(&info->hpdet_work,
-					      msecs_to_jiffies(HPDET_DEBOUNCE));
+			queue_delayed_work(system_power_efficient_wq,
+					   &info->hpdet_work,
+					   msecs_to_jiffies(HPDET_DEBOUNCE));
 		}
 
 		regmap_update_bits(arizona->regmap,
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 18ccade..148382f 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -148,6 +148,7 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(state);
 
 static ssize_t name_show(struct device *dev, struct device_attribute *attr,
 		char *buf)
@@ -163,6 +164,7 @@
 
 	return sprintf(buf, "%s\n", dev_name(edev->dev));
 }
+static DEVICE_ATTR_RO(name);
 
 static ssize_t cable_name_show(struct device *dev,
 			       struct device_attribute *attr, char *buf)
@@ -527,11 +529,12 @@
 }
 EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
 
-static struct device_attribute extcon_attrs[] = {
-	__ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
-	__ATTR_RO(name),
-	__ATTR_NULL,
+static struct attribute *extcon_attrs[] = {
+	&dev_attr_state.attr,
+	&dev_attr_name.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(extcon);
 
 static int create_extcon_class(void)
 {
@@ -539,7 +542,7 @@
 		extcon_class = class_create(THIS_MODULE, "extcon");
 		if (IS_ERR(extcon_class))
 			return PTR_ERR(extcon_class);
-		extcon_class->dev_attrs = extcon_attrs;
+		extcon_class->dev_groups = extcon_groups;
 
 #if defined(CONFIG_ANDROID)
 		switch_class = class_compat_register("switch");
@@ -602,7 +605,8 @@
 	edev->dev->class = extcon_class;
 	edev->dev->release = extcon_dev_release;
 
-	dev_set_name(edev->dev, "%s", edev->name ? edev->name : dev_name(dev));
+	edev->name = edev->name ? edev->name : dev_name(dev);
+	dev_set_name(edev->dev, "%s", edev->name);
 
 	if (edev->max_supported) {
 		char buf[10];
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c
index 02bec32..f874c30 100644
--- a/drivers/extcon/extcon-gpio.c
+++ b/drivers/extcon/extcon-gpio.c
@@ -56,7 +56,7 @@
 {
 	struct gpio_extcon_data *extcon_data = dev_id;
 
-	schedule_delayed_work(&extcon_data->work,
+	queue_delayed_work(system_power_efficient_wq, &extcon_data->work,
 			      extcon_data->debounce_jiffies);
 	return IRQ_HANDLED;
 }
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index b752a0a..89fdd05 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -57,6 +57,7 @@
 		if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
 			palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
 			extcon_set_cable_state(&palmas_usb->edev, "USB", true);
+			dev_info(palmas_usb->dev, "USB cable is attached\n");
 		} else {
 			dev_dbg(palmas_usb->dev,
 				"Spurious connect event detected\n");
@@ -65,6 +66,7 @@
 		if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
 			palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
 			extcon_set_cable_state(&palmas_usb->edev, "USB", false);
+			dev_info(palmas_usb->dev, "USB cable is detached\n");
 		} else {
 			dev_dbg(palmas_usb->dev,
 				"Spurious disconnect event detected\n");
@@ -84,28 +86,23 @@
 
 	if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
 		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
-			PALMAS_USB_ID_INT_EN_HI_SET,
-			PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
-		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
-			PALMAS_USB_ID_INT_EN_HI_CLR,
-			PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
-		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
 			PALMAS_USB_ID_INT_LATCH_CLR,
 			PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
 		palmas_usb->linkstat = PALMAS_USB_STATE_ID;
 		extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
+		dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
 	} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
 		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
-			PALMAS_USB_ID_INT_EN_HI_SET,
-			PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
-		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
-			PALMAS_USB_ID_INT_EN_HI_CLR,
-			PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
-		palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
 			PALMAS_USB_ID_INT_LATCH_CLR,
 			PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
 		palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
 		extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
+		dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
+	} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
+				(!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
+		palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
+		extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
+		dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
 	}
 
 	return IRQ_HANDLED;
@@ -122,13 +119,17 @@
 
 	palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
 		PALMAS_USB_ID_INT_EN_HI_SET,
-		PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
+		PALMAS_USB_ID_INT_EN_HI_SET_ID_GND |
+		PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
 
-	palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
+	if (palmas_usb->enable_vbus_detection)
+		palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
 
 	/* cold plug for host mode needs this delay */
-	msleep(30);
-	palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
+	if (palmas_usb->enable_id_detection) {
+		msleep(30);
+		palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
+	}
 }
 
 static int palmas_usb_probe(struct platform_device *pdev)
@@ -139,21 +140,25 @@
 	struct palmas_usb *palmas_usb;
 	int status;
 
-	if (node && !pdata) {
-		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-
-		if (!pdata)
-			return -ENOMEM;
-
-		pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
-	} else if (!pdata) {
-		return -EINVAL;
-	}
-
 	palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
 	if (!palmas_usb)
 		return -ENOMEM;
 
+	if (node && !pdata) {
+		palmas_usb->wakeup = of_property_read_bool(node, "ti,wakeup");
+		palmas_usb->enable_id_detection = of_property_read_bool(node,
+						"ti,enable-id-detection");
+		palmas_usb->enable_vbus_detection = of_property_read_bool(node,
+						"ti,enable-vbus-detection");
+	} else {
+		palmas_usb->wakeup = true;
+		palmas_usb->enable_id_detection = true;
+		palmas_usb->enable_vbus_detection = true;
+
+		if (pdata)
+			palmas_usb->wakeup = pdata->wakeup;
+	}
+
 	palmas->usb = palmas_usb;
 	palmas_usb->palmas = palmas;
 
@@ -168,11 +173,10 @@
 	palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
 						PALMAS_VBUS_IRQ);
 
-	palmas_usb_wakeup(palmas, pdata->wakeup);
+	palmas_usb_wakeup(palmas, palmas_usb->wakeup);
 
 	platform_set_drvdata(pdev, palmas_usb);
 
-	palmas_usb->edev.name = "palmas-usb";
 	palmas_usb->edev.supported_cable = palmas_extcon_cable;
 	palmas_usb->edev.mutually_exclusive = mutually_exclusive;
 
@@ -182,28 +186,36 @@
 		return status;
 	}
 
-	status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq,
-			NULL, palmas_id_irq_handler,
-			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-			"palmas_usb_id", palmas_usb);
-	if (status < 0) {
-		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+	if (palmas_usb->enable_id_detection) {
+		status = devm_request_threaded_irq(palmas_usb->dev,
+				palmas_usb->id_irq,
+				NULL, palmas_id_irq_handler,
+				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+				IRQF_ONESHOT | IRQF_EARLY_RESUME,
+				"palmas_usb_id", palmas_usb);
+		if (status < 0) {
+			dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
 					palmas_usb->id_irq, status);
-		goto fail_extcon;
+			goto fail_extcon;
+		}
 	}
 
-	status = devm_request_threaded_irq(palmas_usb->dev,
-			palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler,
-			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-			"palmas_usb_vbus", palmas_usb);
-	if (status < 0) {
-		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
+	if (palmas_usb->enable_vbus_detection) {
+		status = devm_request_threaded_irq(palmas_usb->dev,
+				palmas_usb->vbus_irq, NULL,
+				palmas_vbus_irq_handler,
+				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+				IRQF_ONESHOT | IRQF_EARLY_RESUME,
+				"palmas_usb_vbus", palmas_usb);
+		if (status < 0) {
+			dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
 					palmas_usb->vbus_irq, status);
-		goto fail_extcon;
+			goto fail_extcon;
+		}
 	}
 
 	palmas_enable_irq(palmas_usb);
-
+	device_set_wakeup_capable(&pdev->dev, true);
 	return 0;
 
 fail_extcon:
@@ -221,6 +233,39 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int palmas_usb_suspend(struct device *dev)
+{
+	struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev)) {
+		if (palmas_usb->enable_vbus_detection)
+			enable_irq_wake(palmas_usb->vbus_irq);
+		if (palmas_usb->enable_id_detection)
+			enable_irq_wake(palmas_usb->id_irq);
+	}
+	return 0;
+}
+
+static int palmas_usb_resume(struct device *dev)
+{
+	struct palmas_usb *palmas_usb = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev)) {
+		if (palmas_usb->enable_vbus_detection)
+			disable_irq_wake(palmas_usb->vbus_irq);
+		if (palmas_usb->enable_id_detection)
+			disable_irq_wake(palmas_usb->id_irq);
+	}
+	return 0;
+};
+#endif
+
+static const struct dev_pm_ops palmas_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(palmas_usb_suspend,
+				palmas_usb_resume)
+};
+
 static struct of_device_id of_palmas_match_tbl[] = {
 	{ .compatible = "ti,palmas-usb", },
 	{ .compatible = "ti,twl6035-usb", },
@@ -234,6 +279,7 @@
 		.name = "palmas-usb",
 		.of_match_table = of_palmas_match_tbl,
 		.owner = THIS_MODULE,
+		.pm = &palmas_pm_ops,
 	},
 };
 
diff --git a/drivers/extcon/of_extcon.c b/drivers/extcon/of_extcon.c
new file mode 100644
index 0000000..72173ec
--- /dev/null
+++ b/drivers/extcon/of_extcon.c
@@ -0,0 +1,64 @@
+/*
+ * OF helpers for External connector (extcon) framework
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ * Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Chanwoo Choi <cw00.choi@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/slab.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/extcon/of_extcon.h>
+
+/*
+ * of_extcon_get_extcon_dev - Get the name of extcon device from devicetree
+ * @dev - instance to the given device
+ * @index - index into list of extcon_dev
+ *
+ * return the instance of extcon device
+ */
+struct extcon_dev *of_extcon_get_extcon_dev(struct device *dev, int index)
+{
+	struct device_node *node;
+	struct extcon_dev *edev;
+	struct platform_device *extcon_parent_dev;
+
+	if (!dev->of_node) {
+		dev_dbg(dev, "device does not have a device node entry\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	node = of_parse_phandle(dev->of_node, "extcon", index);
+	if (!node) {
+		dev_dbg(dev, "failed to get phandle in %s node\n",
+			dev->of_node->full_name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	extcon_parent_dev = of_find_device_by_node(node);
+	if (!extcon_parent_dev) {
+		dev_dbg(dev, "unable to find device by node\n");
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	edev = extcon_get_extcon_dev(dev_name(&extcon_parent_dev->dev));
+	if (!edev) {
+		dev_dbg(dev, "unable to get extcon device : %s\n",
+				dev_name(&extcon_parent_dev->dev));
+		return ERR_PTR(-ENODEV);
+	}
+
+	return edev;
+}
+EXPORT_SYMBOL_GPL(of_extcon_get_extcon_dev);
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 8e77c02..ff080ee 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -535,11 +535,12 @@
 
 static struct attribute_group dcdbas_attr_group = {
 	.attrs = dcdbas_dev_attrs,
+	.bin_attrs = dcdbas_bin_attrs,
 };
 
 static int dcdbas_probe(struct platform_device *dev)
 {
-	int i, error;
+	int error;
 
 	host_control_action = HC_ACTION_NONE;
 	host_control_smi_type = HC_SMITYPE_NONE;
@@ -555,18 +556,6 @@
 	if (error)
 		return error;
 
-	for (i = 0; dcdbas_bin_attrs[i]; i++) {
-		error = sysfs_create_bin_file(&dev->dev.kobj,
-					      dcdbas_bin_attrs[i]);
-		if (error) {
-			while (--i >= 0)
-				sysfs_remove_bin_file(&dev->dev.kobj,
-						      dcdbas_bin_attrs[i]);
-			sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
-			return error;
-		}
-	}
-
 	register_reboot_notifier(&dcdbas_reboot_nb);
 
 	dev_info(&dev->dev, "%s (version %s)\n",
@@ -577,11 +566,7 @@
 
 static int dcdbas_remove(struct platform_device *dev)
 {
-	int i;
-
 	unregister_reboot_notifier(&dcdbas_reboot_nb);
-	for (i = 0; dcdbas_bin_attrs[i]; i++)
-		sysfs_remove_bin_file(&dev->dev.kobj, dcdbas_bin_attrs[i]);
 	sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
 
 	return 0;
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index 73de5a9..5002d50 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -35,6 +35,7 @@
 	enum pstore_type_id *type;
 	int *count;
 	struct timespec *timespec;
+	bool *compressed;
 	char **buf;
 };
 
@@ -42,7 +43,7 @@
 {
 	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
 	struct pstore_read_data *cb_data = data;
-	char name[DUMP_NAME_LEN];
+	char name[DUMP_NAME_LEN], data_type;
 	int i;
 	int cnt;
 	unsigned int part;
@@ -54,12 +55,23 @@
 	for (i = 0; i < DUMP_NAME_LEN; i++)
 		name[i] = entry->var.VariableName[i];
 
-	if (sscanf(name, "dump-type%u-%u-%d-%lu",
+	if (sscanf(name, "dump-type%u-%u-%d-%lu-%c",
+		   cb_data->type, &part, &cnt, &time, &data_type) == 5) {
+		*cb_data->id = part;
+		*cb_data->count = cnt;
+		cb_data->timespec->tv_sec = time;
+		cb_data->timespec->tv_nsec = 0;
+		if (data_type == 'C')
+			*cb_data->compressed = true;
+		else
+			*cb_data->compressed = false;
+	} else if (sscanf(name, "dump-type%u-%u-%d-%lu",
 		   cb_data->type, &part, &cnt, &time) == 4) {
 		*cb_data->id = part;
 		*cb_data->count = cnt;
 		cb_data->timespec->tv_sec = time;
 		cb_data->timespec->tv_nsec = 0;
+		*cb_data->compressed = false;
 	} else if (sscanf(name, "dump-type%u-%u-%lu",
 			  cb_data->type, &part, &time) == 3) {
 		/*
@@ -71,6 +83,7 @@
 		*cb_data->count = 0;
 		cb_data->timespec->tv_sec = time;
 		cb_data->timespec->tv_nsec = 0;
+		*cb_data->compressed = false;
 	} else
 		return 0;
 
@@ -87,7 +100,8 @@
 
 static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
 			       int *count, struct timespec *timespec,
-			       char **buf, struct pstore_info *psi)
+			       char **buf, bool *compressed,
+			       struct pstore_info *psi)
 {
 	struct pstore_read_data data;
 
@@ -95,6 +109,7 @@
 	data.type = type;
 	data.count = count;
 	data.timespec = timespec;
+	data.compressed = compressed;
 	data.buf = buf;
 
 	return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data,
@@ -103,7 +118,7 @@
 
 static int efi_pstore_write(enum pstore_type_id type,
 		enum kmsg_dump_reason reason, u64 *id,
-		unsigned int part, int count, size_t hsize, size_t size,
+		unsigned int part, int count, bool compressed, size_t size,
 		struct pstore_info *psi)
 {
 	char name[DUMP_NAME_LEN];
@@ -111,8 +126,8 @@
 	efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
 	int i, ret = 0;
 
-	sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count,
-		get_seconds());
+	sprintf(name, "dump-type%u-%u-%d-%lu-%c", type, part, count,
+		get_seconds(), compressed ? 'C' : 'D');
 
 	for (i = 0; i < DUMP_NAME_LEN; i++)
 		efi_name[i] = name[i];
diff --git a/drivers/fmc/fmc-chardev.c b/drivers/fmc/fmc-chardev.c
index cc031db..ace6ef2 100644
--- a/drivers/fmc/fmc-chardev.c
+++ b/drivers/fmc/fmc-chardev.c
@@ -143,18 +143,17 @@
 	fc->misc.fops = &fc_fops;
 	fc->misc.name = kstrdup(dev_name(&fmc->dev), GFP_KERNEL);
 
-	spin_lock(&fc_lock);
 	ret = misc_register(&fc->misc);
 	if (ret < 0)
-		goto err_unlock;
+		goto out;
+	spin_lock(&fc_lock);
 	list_add(&fc->list, &fc_devices);
 	spin_unlock(&fc_lock);
 	dev_info(&fc->fmc->dev, "Created misc device \"%s\"\n",
 		 fc->misc.name);
 	return 0;
 
-err_unlock:
-	spin_unlock(&fc_lock);
+out:
 	kfree(fc->misc.name);
 	kfree(fc);
 	return ret;
@@ -174,10 +173,10 @@
 
 	spin_lock(&fc_lock);
 	list_del(&fc->list);
+	spin_unlock(&fc_lock);
 	misc_deregister(&fc->misc);
 	kfree(fc->misc.name);
 	kfree(fc);
-	spin_unlock(&fc_lock);
 
 	return 0;
 }
diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c
index 2cc680d..ee5b479 100644
--- a/drivers/fmc/fmc-write-eeprom.c
+++ b/drivers/fmc/fmc-write-eeprom.c
@@ -103,7 +103,7 @@
  * difficult to know in advance when probing the first card if others
  * are there.
  */
-int fwe_probe(struct fmc_device *fmc)
+static int fwe_probe(struct fmc_device *fmc)
 {
 	int err, index = 0;
 	const struct firmware *fw;
@@ -144,7 +144,7 @@
 	return 0;
 }
 
-int fwe_remove(struct fmc_device *fmc)
+static int fwe_remove(struct fmc_device *fmc)
 {
 	return 0;
 }
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index ece72a8..61c1d17 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -215,7 +215,7 @@
 
 	cma_obj = drm_gem_cma_create_with_handle(file_priv, dev,
 			args->size, &args->handle);
-	return PTR_RET(cma_obj);
+	return PTR_ERR_OR_ZERO(cma_obj);
 }
 EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create);
 
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 19e3660..3bc84145 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -500,7 +500,8 @@
 				  &status))
 		goto log_fail;
 
-	while (status == SDVO_CMD_STATUS_PENDING && retry--) {
+	while ((status == SDVO_CMD_STATUS_PENDING ||
+		status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && retry--) {
 		udelay(15);
 		if (!psb_intel_sdvo_read_byte(psb_intel_sdvo,
 					  SDVO_I2C_CMD_STATUS,
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
index dc53a52..9e65783 100644
--- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -85,9 +85,17 @@
 				   struct sg_table *sg,
 				   enum dma_data_direction dir)
 {
+	struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
+
+	mutex_lock(&obj->base.dev->struct_mutex);
+
 	dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
 	sg_free_table(sg);
 	kfree(sg);
+
+	i915_gem_object_unpin_pages(obj);
+
+	mutex_unlock(&obj->base.dev->struct_mutex);
 }
 
 static void i915_gem_dmabuf_release(struct dma_buf *dma_buf)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 6f51429..342f1f3 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -752,6 +752,8 @@
 					will not assert AGPBUSY# and will only
 					be delivered when out of C3. */
 #define   INSTPM_FORCE_ORDERING				(1<<7) /* GEN6+ */
+#define   INSTPM_TLB_INVALIDATE	(1<<9)
+#define   INSTPM_SYNC_FLUSH	(1<<5)
 #define ACTHD	        0x020c8
 #define FW_BLC		0x020d8
 #define FW_BLC2		0x020dc
@@ -4438,7 +4440,7 @@
 #define EDP_LINK_TRAIN_600MV_0DB_IVB		(0x30 <<22)
 #define EDP_LINK_TRAIN_600MV_3_5DB_IVB		(0x36 <<22)
 #define EDP_LINK_TRAIN_800MV_0DB_IVB		(0x38 <<22)
-#define EDP_LINK_TRAIN_800MV_3_5DB_IVB		(0x33 <<22)
+#define EDP_LINK_TRAIN_800MV_3_5DB_IVB		(0x3e <<22)
 
 /* legacy values */
 #define EDP_LINK_TRAIN_500MV_0DB_IVB		(0x00 <<22)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e38b457..be79f47 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10042,6 +10042,8 @@
 
 	u32 power_well_driver;
 
+	int num_transcoders;
+
 	struct intel_cursor_error_state {
 		u32 control;
 		u32 position;
@@ -10050,16 +10052,7 @@
 	} cursor[I915_MAX_PIPES];
 
 	struct intel_pipe_error_state {
-		enum transcoder cpu_transcoder;
-		u32 conf;
 		u32 source;
-
-		u32 htotal;
-		u32 hblank;
-		u32 hsync;
-		u32 vtotal;
-		u32 vblank;
-		u32 vsync;
 	} pipe[I915_MAX_PIPES];
 
 	struct intel_plane_error_state {
@@ -10071,6 +10064,19 @@
 		u32 surface;
 		u32 tile_offset;
 	} plane[I915_MAX_PIPES];
+
+	struct intel_transcoder_error_state {
+		enum transcoder cpu_transcoder;
+
+		u32 conf;
+
+		u32 htotal;
+		u32 hblank;
+		u32 hsync;
+		u32 vtotal;
+		u32 vblank;
+		u32 vsync;
+	} transcoder[4];
 };
 
 struct intel_display_error_state *
@@ -10078,9 +10084,17 @@
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_display_error_state *error;
-	enum transcoder cpu_transcoder;
+	int transcoders[] = {
+		TRANSCODER_A,
+		TRANSCODER_B,
+		TRANSCODER_C,
+		TRANSCODER_EDP,
+	};
 	int i;
 
+	if (INTEL_INFO(dev)->num_pipes == 0)
+		return NULL;
+
 	error = kmalloc(sizeof(*error), GFP_ATOMIC);
 	if (error == NULL)
 		return NULL;
@@ -10089,9 +10103,6 @@
 		error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
 
 	for_each_pipe(i) {
-		cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i);
-		error->pipe[i].cpu_transcoder = cpu_transcoder;
-
 		if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
 			error->cursor[i].control = I915_READ(CURCNTR(i));
 			error->cursor[i].position = I915_READ(CURPOS(i));
@@ -10115,14 +10126,25 @@
 			error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i));
 		}
 
-		error->pipe[i].conf = I915_READ(PIPECONF(cpu_transcoder));
 		error->pipe[i].source = I915_READ(PIPESRC(i));
-		error->pipe[i].htotal = I915_READ(HTOTAL(cpu_transcoder));
-		error->pipe[i].hblank = I915_READ(HBLANK(cpu_transcoder));
-		error->pipe[i].hsync = I915_READ(HSYNC(cpu_transcoder));
-		error->pipe[i].vtotal = I915_READ(VTOTAL(cpu_transcoder));
-		error->pipe[i].vblank = I915_READ(VBLANK(cpu_transcoder));
-		error->pipe[i].vsync = I915_READ(VSYNC(cpu_transcoder));
+	}
+
+	error->num_transcoders = INTEL_INFO(dev)->num_pipes;
+	if (HAS_DDI(dev_priv->dev))
+		error->num_transcoders++; /* Account for eDP. */
+
+	for (i = 0; i < error->num_transcoders; i++) {
+		enum transcoder cpu_transcoder = transcoders[i];
+
+		error->transcoder[i].cpu_transcoder = cpu_transcoder;
+
+		error->transcoder[i].conf = I915_READ(PIPECONF(cpu_transcoder));
+		error->transcoder[i].htotal = I915_READ(HTOTAL(cpu_transcoder));
+		error->transcoder[i].hblank = I915_READ(HBLANK(cpu_transcoder));
+		error->transcoder[i].hsync = I915_READ(HSYNC(cpu_transcoder));
+		error->transcoder[i].vtotal = I915_READ(VTOTAL(cpu_transcoder));
+		error->transcoder[i].vblank = I915_READ(VBLANK(cpu_transcoder));
+		error->transcoder[i].vsync = I915_READ(VSYNC(cpu_transcoder));
 	}
 
 	/* In the code above we read the registers without checking if the power
@@ -10144,22 +10166,16 @@
 {
 	int i;
 
+	if (!error)
+		return;
+
 	err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
 	if (HAS_POWER_WELL(dev))
 		err_printf(m, "PWR_WELL_CTL2: %08x\n",
 			   error->power_well_driver);
 	for_each_pipe(i) {
 		err_printf(m, "Pipe [%d]:\n", i);
-		err_printf(m, "  CPU transcoder: %c\n",
-			   transcoder_name(error->pipe[i].cpu_transcoder));
-		err_printf(m, "  CONF: %08x\n", error->pipe[i].conf);
 		err_printf(m, "  SRC: %08x\n", error->pipe[i].source);
-		err_printf(m, "  HTOTAL: %08x\n", error->pipe[i].htotal);
-		err_printf(m, "  HBLANK: %08x\n", error->pipe[i].hblank);
-		err_printf(m, "  HSYNC: %08x\n", error->pipe[i].hsync);
-		err_printf(m, "  VTOTAL: %08x\n", error->pipe[i].vtotal);
-		err_printf(m, "  VBLANK: %08x\n", error->pipe[i].vblank);
-		err_printf(m, "  VSYNC: %08x\n", error->pipe[i].vsync);
 
 		err_printf(m, "Plane [%d]:\n", i);
 		err_printf(m, "  CNTR: %08x\n", error->plane[i].control);
@@ -10180,5 +10196,17 @@
 		err_printf(m, "  POS: %08x\n", error->cursor[i].position);
 		err_printf(m, "  BASE: %08x\n", error->cursor[i].base);
 	}
+
+	for (i = 0; i < error->num_transcoders; i++) {
+		err_printf(m, "  CPU transcoder: %c\n",
+			   transcoder_name(error->transcoder[i].cpu_transcoder));
+		err_printf(m, "  CONF: %08x\n", error->transcoder[i].conf);
+		err_printf(m, "  HTOTAL: %08x\n", error->transcoder[i].htotal);
+		err_printf(m, "  HBLANK: %08x\n", error->transcoder[i].hblank);
+		err_printf(m, "  HSYNC: %08x\n", error->transcoder[i].hsync);
+		err_printf(m, "  VTOTAL: %08x\n", error->transcoder[i].vtotal);
+		err_printf(m, "  VBLANK: %08x\n", error->transcoder[i].vblank);
+		err_printf(m, "  VSYNC: %08x\n", error->transcoder[i].vsync);
+	}
 }
 #endif
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 664118d..079ef01 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -968,6 +968,18 @@
 
 	I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
 	POSTING_READ(mmio);
+
+	/* Flush the TLB for this page */
+	if (INTEL_INFO(dev)->gen >= 6) {
+		u32 reg = RING_INSTPM(ring->mmio_base);
+		I915_WRITE(reg,
+			   _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
+					      INSTPM_SYNC_FLUSH));
+		if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0,
+			     1000))
+			DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
+				  ring->name);
+	}
 }
 
 static int
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
index d829172..7a4e089 100644
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -98,6 +98,8 @@
 	u32 splitoff;
 	u32 s, e;
 
+	BUG_ON(!type);
+
 	list_for_each_entry(this, &mm->free, fl_entry) {
 		e = this->offset + this->length;
 		s = this->offset;
@@ -162,6 +164,8 @@
 	struct nouveau_mm_node *prev, *this, *next;
 	u32 mask = align - 1;
 
+	BUG_ON(!type);
+
 	list_for_each_entry_reverse(this, &mm->free, fl_entry) {
 		u32 e = this->offset + this->length;
 		u32 s = this->offset;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
index d550226..9d2cd20 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
@@ -20,8 +20,8 @@
 	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC];
 }
 
-#define nouveau_mc_create(p,e,o,d)                                             \
-	nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_mc_create(p,e,o,m,d)                                           \
+	nouveau_mc_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
 #define nouveau_mc_destroy(p) ({                                               \
 	struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc));        \
 })
@@ -33,7 +33,8 @@
 })
 
 int  nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
-			struct nouveau_oclass *, int, void **);
+			struct nouveau_oclass *, const struct nouveau_mc_intr *,
+			int, void **);
 void _nouveau_mc_dtor(struct nouveau_object *);
 int  _nouveau_mc_init(struct nouveau_object *);
 int  _nouveau_mc_fini(struct nouveau_object *, bool);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
index 19e3a9a..ab7ef0a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
@@ -40,15 +40,15 @@
 		return ret;
 
 	switch (pfb914 & 0x00000003) {
-	case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break;
-	case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000000: ram->type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000001: ram->type = NV_MEM_TYPE_DDR2; break;
+	case 0x00000002: ram->type = NV_MEM_TYPE_GDDR3; break;
 	case 0x00000003: break;
 	}
 
-	pfb->ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-	pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	pfb->ram->tags  =  nv_rd32(pfb, 0x100320);
+	ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->tags  =  nv_rd32(pfb, 0x100320);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
index 7192aa6..63a6aab 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
@@ -38,8 +38,8 @@
 	if (ret)
 		return ret;
 
-	pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	pfb->ram->type = NV_MEM_TYPE_STOLEN;
+	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->type = NV_MEM_TYPE_STOLEN;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
index bcca883..cce65cc 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
@@ -30,8 +30,9 @@
 	struct nouveau_ltcg base;
 	u32 part_nr;
 	u32 subp_nr;
-	struct nouveau_mm tags;
 	u32 num_tags;
+	u32 tag_base;
+	struct nouveau_mm tags;
 	struct nouveau_mm_node *tag_ram;
 };
 
@@ -117,10 +118,6 @@
 	u32 tag_size, tag_margin, tag_align;
 	int ret;
 
-	nv_wr32(priv, 0x17e8d8, priv->part_nr);
-	if (nv_device(pfb)->card_type >= NV_E0)
-		nv_wr32(priv, 0x17e000, priv->part_nr);
-
 	/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
 	priv->num_tags = (pfb->ram->size >> 17) / 4;
 	if (priv->num_tags > (1 << 17))
@@ -142,7 +139,7 @@
 	tag_size += tag_align;
 	tag_size  = (tag_size + 0xfff) >> 12; /* round up */
 
-	ret = nouveau_mm_tail(&pfb->vram, 0, tag_size, tag_size, 1,
+	ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
 	                      &priv->tag_ram);
 	if (ret) {
 		priv->num_tags = 0;
@@ -152,7 +149,7 @@
 		tag_base += tag_align - 1;
 		ret = do_div(tag_base, tag_align);
 
-		nv_wr32(priv, 0x17e8d4, tag_base);
+		priv->tag_base = tag_base;
 	}
 	ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
 
@@ -182,8 +179,6 @@
 	}
 	priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28;
 
-	nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
-
 	ret = nvc0_ltcg_init_tag_ram(pfb, priv);
 	if (ret)
 		return ret;
@@ -209,13 +204,32 @@
 	nouveau_ltcg_destroy(ltcg);
 }
 
+static int
+nvc0_ltcg_init(struct nouveau_object *object)
+{
+	struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
+	struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
+	int ret;
+
+	ret = nouveau_ltcg_init(ltcg);
+	if (ret)
+		return ret;
+
+	nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
+	nv_wr32(priv, 0x17e8d8, priv->part_nr);
+	if (nv_device(ltcg)->card_type >= NV_E0)
+		nv_wr32(priv, 0x17e000, priv->part_nr);
+	nv_wr32(priv, 0x17e8d4, priv->tag_base);
+	return 0;
+}
+
 struct nouveau_oclass
 nvc0_ltcg_oclass = {
 	.handle = NV_SUBDEV(LTCG, 0xc0),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nvc0_ltcg_ctor,
 		.dtor = nvc0_ltcg_dtor,
-		.init = _nouveau_ltcg_init,
+		.init = nvc0_ltcg_init,
 		.fini = _nouveau_ltcg_fini,
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
index 1c0330b..ec9cd6f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
@@ -80,7 +80,9 @@
 
 int
 nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-		   struct nouveau_oclass *oclass, int length, void **pobject)
+		   struct nouveau_oclass *oclass,
+		   const struct nouveau_mc_intr *intr_map,
+		   int length, void **pobject)
 {
 	struct nouveau_device *device = nv_device(parent);
 	struct nouveau_mc *pmc;
@@ -92,6 +94,8 @@
 	if (ret)
 		return ret;
 
+	pmc->intr_map = intr_map;
+
 	ret = request_irq(device->pdev->irq, nouveau_mc_intr,
 			  IRQF_SHARED, "nouveau", pmc);
 	if (ret < 0)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
index 8c76971..64aa4ed 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
@@ -50,12 +50,11 @@
 	struct nv04_mc_priv *priv;
 	int ret;
 
-	ret = nouveau_mc_create(parent, engine, oclass, &priv);
+	ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	priv->base.intr_map = nv04_mc_intr;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
index 5191937..d989178 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
@@ -36,12 +36,11 @@
 	struct nv44_mc_priv *priv;
 	int ret;
 
-	ret = nouveau_mc_create(parent, engine, oclass, &priv);
+	ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	priv->base.intr_map = nv04_mc_intr;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index f25fc5f..2b1afe2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -53,12 +53,11 @@
 	struct nv50_mc_priv *priv;
 	int ret;
 
-	ret = nouveau_mc_create(parent, engine, oclass, &priv);
+	ret = nouveau_mc_create(parent, engine, oclass, nv50_mc_intr, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	priv->base.intr_map = nv50_mc_intr;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
index e82fd21..0d57b4d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
@@ -54,12 +54,11 @@
 	struct nv98_mc_priv *priv;
 	int ret;
 
-	ret = nouveau_mc_create(parent, engine, oclass, &priv);
+	ret = nouveau_mc_create(parent, engine, oclass, nv98_mc_intr, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	priv->base.intr_map = nv98_mc_intr;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index c5da3ba..104175c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -57,12 +57,11 @@
 	struct nvc0_mc_priv *priv;
 	int ret;
 
-	ret = nouveau_mc_create(parent, engine, oclass, &priv);
+	ret = nouveau_mc_create(parent, engine, oclass, nvc0_mc_intr, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	priv->base.intr_map = nvc0_mc_intr;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 0782bd2..6a13ffb 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -606,6 +606,24 @@
 	regp->ramdac_a34 = 0x1;
 }
 
+static int
+nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
+{
+	struct nv04_display *disp = nv04_display(crtc->dev);
+	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+	int ret;
+
+	ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
+	if (ret == 0) {
+		if (disp->image[nv_crtc->index])
+			nouveau_bo_unpin(disp->image[nv_crtc->index]);
+		nouveau_bo_ref(nvfb->nvbo, &disp->image[nv_crtc->index]);
+	}
+
+	return ret;
+}
+
 /**
  * Sets up registers for the given mode/adjusted_mode pair.
  *
@@ -622,10 +640,15 @@
 	struct drm_device *dev = crtc->dev;
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nouveau_drm *drm = nouveau_drm(dev);
+	int ret;
 
 	NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
 	drm_mode_debug_printmodeline(adjusted_mode);
 
+	ret = nv_crtc_swap_fbs(crtc, old_fb);
+	if (ret)
+		return ret;
+
 	/* unlock must come after turning off FP_TG_CONTROL in output_prepare */
 	nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1);
 
@@ -722,6 +745,7 @@
 
 static void nv_crtc_destroy(struct drm_crtc *crtc)
 {
+	struct nv04_display *disp = nv04_display(crtc->dev);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 
 	if (!nv_crtc)
@@ -729,6 +753,10 @@
 
 	drm_crtc_cleanup(crtc);
 
+	if (disp->image[nv_crtc->index])
+		nouveau_bo_unpin(disp->image[nv_crtc->index]);
+	nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
+
 	nouveau_bo_unmap(nv_crtc->cursor.nvbo);
 	nouveau_bo_unpin(nv_crtc->cursor.nvbo);
 	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
@@ -754,6 +782,16 @@
 }
 
 static void
+nv_crtc_disable(struct drm_crtc *crtc)
+{
+	struct nv04_display *disp = nv04_display(crtc->dev);
+	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+	if (disp->image[nv_crtc->index])
+		nouveau_bo_unpin(disp->image[nv_crtc->index]);
+	nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
+}
+
+static void
 nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
 		  uint32_t size)
 {
@@ -791,7 +829,6 @@
 	struct drm_framebuffer *drm_fb;
 	struct nouveau_framebuffer *fb;
 	int arb_burst, arb_lwm;
-	int ret;
 
 	NV_DEBUG(drm, "index %d\n", nv_crtc->index);
 
@@ -801,10 +838,8 @@
 		return 0;
 	}
 
-
 	/* If atomic, we want to switch to the fb we were passed, so
-	 * now we update pointers to do that.  (We don't pin; just
-	 * assume we're already pinned and update the base address.)
+	 * now we update pointers to do that.
 	 */
 	if (atomic) {
 		drm_fb = passed_fb;
@@ -812,17 +847,6 @@
 	} else {
 		drm_fb = crtc->fb;
 		fb = nouveau_framebuffer(crtc->fb);
-		/* If not atomic, we can go ahead and pin, and unpin the
-		 * old fb we were passed.
-		 */
-		ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
-		if (ret)
-			return ret;
-
-		if (passed_fb) {
-			struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
-			nouveau_bo_unpin(ofb->nvbo);
-		}
 	}
 
 	nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -877,6 +901,9 @@
 nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 			struct drm_framebuffer *old_fb)
 {
+	int ret = nv_crtc_swap_fbs(crtc, old_fb);
+	if (ret)
+		return ret;
 	return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
 }
 
@@ -1027,6 +1054,7 @@
 	.mode_set_base = nv04_crtc_mode_set_base,
 	.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
 	.load_lut = nv_crtc_gamma_load,
+	.disable = nv_crtc_disable,
 };
 
 int
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index a0a031d..9928187 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -81,6 +81,7 @@
 	uint32_t saved_vga_font[4][16384];
 	uint32_t dac_users[4];
 	struct nouveau_object *core;
+	struct nouveau_bo *image[2];
 };
 
 static inline struct nv04_display *
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 907d20e..a03e75d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -577,6 +577,9 @@
 		ret = nv50_display_flip_next(crtc, fb, chan, 0);
 		if (ret)
 			goto fail_unreserve;
+	} else {
+		struct nv04_display *dispnv04 = nv04_display(dev);
+		nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]);
 	}
 
 	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
index 3af5bcd..625f80d 100644
--- a/drivers/gpu/drm/nouveau/nv40_pm.c
+++ b/drivers/gpu/drm/nouveau/nv40_pm.c
@@ -131,7 +131,7 @@
 	if (clk < pll->vco1.max_freq)
 		pll->vco2.max_freq = 0;
 
-	pclk->pll_calc(pclk, pll, clk, &coef);
+	ret = pclk->pll_calc(pclk, pll, clk, &coef);
 	if (ret == 0)
 		return -ERANGE;
 
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 274b8e1..9f19259 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2163,7 +2163,7 @@
 		WREG32(reg, tmp_);				\
 	} while (0)
 #define WREG32_AND(reg, and) WREG32_P(reg, 0, and)
-#define WREG32_OR(reg, or) WREG32_P(reg, or, ~or)
+#define WREG32_OR(reg, or) WREG32_P(reg, or, ~(or))
 #define WREG32_PLL_P(reg, val, mask)				\
 	do {							\
 		uint32_t tmp_ = RREG32_PLL(reg);		\
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index f1c1575..b79f4f5 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -356,6 +356,14 @@
 		return -EINVAL;
 	}
 
+	if (bo->tbo.sync_obj) {
+		r = radeon_fence_wait(bo->tbo.sync_obj, false);
+		if (r) {
+			DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
+			return r;
+		}
+	}
+
 	r = radeon_bo_kmap(bo, &ptr);
 	if (r) {
 		DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index bcc68ec..f5e92cf 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -744,10 +744,10 @@
 						 (const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers));
 		radeon_program_register_sequence(rdev,
 						 rv730_golden_registers,
-						 (const u32)ARRAY_SIZE(rv770_golden_registers));
+						 (const u32)ARRAY_SIZE(rv730_golden_registers));
 		radeon_program_register_sequence(rdev,
 						 rv730_mgcg_init,
-						 (const u32)ARRAY_SIZE(rv770_mgcg_init));
+						 (const u32)ARRAY_SIZE(rv730_mgcg_init));
 		break;
 	case CHIP_RV710:
 		radeon_program_register_sequence(rdev,
@@ -758,18 +758,18 @@
 						 (const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers));
 		radeon_program_register_sequence(rdev,
 						 rv710_golden_registers,
-						 (const u32)ARRAY_SIZE(rv770_golden_registers));
+						 (const u32)ARRAY_SIZE(rv710_golden_registers));
 		radeon_program_register_sequence(rdev,
 						 rv710_mgcg_init,
-						 (const u32)ARRAY_SIZE(rv770_mgcg_init));
+						 (const u32)ARRAY_SIZE(rv710_mgcg_init));
 		break;
 	case CHIP_RV740:
 		radeon_program_register_sequence(rdev,
 						 rv740_golden_registers,
-						 (const u32)ARRAY_SIZE(rv770_golden_registers));
+						 (const u32)ARRAY_SIZE(rv740_golden_registers));
 		radeon_program_register_sequence(rdev,
 						 rv740_mgcg_init,
-						 (const u32)ARRAY_SIZE(rv770_mgcg_init));
+						 (const u32)ARRAY_SIZE(rv740_mgcg_init));
 		break;
 	default:
 		break;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
index 3751730..1a0bf07 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
@@ -29,7 +29,9 @@
 #include <drm/drmP.h>
 #include <drm/ttm/ttm_bo_driver.h>
 
-#define VMW_PPN_SIZE sizeof(unsigned long)
+#define VMW_PPN_SIZE (sizeof(unsigned long))
+/* A future safe maximum remap size. */
+#define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
 
 static int vmw_gmr2_bind(struct vmw_private *dev_priv,
 			 struct page *pages[],
@@ -38,43 +40,61 @@
 {
 	SVGAFifoCmdDefineGMR2 define_cmd;
 	SVGAFifoCmdRemapGMR2 remap_cmd;
-	uint32_t define_size = sizeof(define_cmd) + 4;
-	uint32_t remap_size = VMW_PPN_SIZE * num_pages + sizeof(remap_cmd) + 4;
 	uint32_t *cmd;
 	uint32_t *cmd_orig;
+	uint32_t define_size = sizeof(define_cmd) + sizeof(*cmd);
+	uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ((num_pages % VMW_PPN_PER_REMAP) > 0);
+	uint32_t remap_size = VMW_PPN_SIZE * num_pages + (sizeof(remap_cmd) + sizeof(*cmd)) * remap_num;
+	uint32_t remap_pos = 0;
+	uint32_t cmd_size = define_size + remap_size;
 	uint32_t i;
 
-	cmd_orig = cmd = vmw_fifo_reserve(dev_priv, define_size + remap_size);
+	cmd_orig = cmd = vmw_fifo_reserve(dev_priv, cmd_size);
 	if (unlikely(cmd == NULL))
 		return -ENOMEM;
 
 	define_cmd.gmrId = gmr_id;
 	define_cmd.numPages = num_pages;
 
+	*cmd++ = SVGA_CMD_DEFINE_GMR2;
+	memcpy(cmd, &define_cmd, sizeof(define_cmd));
+	cmd += sizeof(define_cmd) / sizeof(*cmd);
+
+	/*
+	 * Need to split the command if there are too many
+	 * pages that goes into the gmr.
+	 */
+
 	remap_cmd.gmrId = gmr_id;
 	remap_cmd.flags = (VMW_PPN_SIZE > sizeof(*cmd)) ?
 		SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32;
-	remap_cmd.offsetPages = 0;
-	remap_cmd.numPages = num_pages;
 
-	*cmd++ = SVGA_CMD_DEFINE_GMR2;
-	memcpy(cmd, &define_cmd, sizeof(define_cmd));
-	cmd += sizeof(define_cmd) / sizeof(uint32);
+	while (num_pages > 0) {
+		unsigned long nr = min(num_pages, (unsigned long)VMW_PPN_PER_REMAP);
 
-	*cmd++ = SVGA_CMD_REMAP_GMR2;
-	memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
-	cmd += sizeof(remap_cmd) / sizeof(uint32);
+		remap_cmd.offsetPages = remap_pos;
+		remap_cmd.numPages = nr;
 
-	for (i = 0; i < num_pages; ++i) {
-		if (VMW_PPN_SIZE <= 4)
-			*cmd = page_to_pfn(*pages++);
-		else
-			*((uint64_t *)cmd) = page_to_pfn(*pages++);
+		*cmd++ = SVGA_CMD_REMAP_GMR2;
+		memcpy(cmd, &remap_cmd, sizeof(remap_cmd));
+		cmd += sizeof(remap_cmd) / sizeof(*cmd);
 
-		cmd += VMW_PPN_SIZE / sizeof(*cmd);
+		for (i = 0; i < nr; ++i) {
+			if (VMW_PPN_SIZE <= 4)
+				*cmd = page_to_pfn(*pages++);
+			else
+				*((uint64_t *)cmd) = page_to_pfn(*pages++);
+
+			cmd += VMW_PPN_SIZE / sizeof(*cmd);
+		}
+
+		num_pages -= nr;
+		remap_pos += nr;
 	}
 
-	vmw_fifo_commit(dev_priv, define_size + remap_size);
+	BUG_ON(cmd != cmd_orig + cmd_size / sizeof(*cmd));
+
+	vmw_fifo_commit(dev_priv, cmd_size);
 
 	return 0;
 }
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 36668d1..b8f1c77 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1917,11 +1917,13 @@
 
 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
+static DEVICE_ATTR_RO(modalias);
 
-static struct device_attribute hid_dev_attrs[] = {
-	__ATTR_RO(modalias),
-	__ATTR_NULL,
+static struct attribute *hid_dev_attrs[] = {
+	&dev_attr_modalias.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(hid_dev);
 
 static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -1949,7 +1951,7 @@
 
 static struct bus_type hid_bus_type = {
 	.name		= "hid",
-	.dev_attrs	= hid_dev_attrs,
+	.dev_groups	= hid_dev_groups,
 	.match		= hid_bus_match,
 	.probe		= hid_device_probe,
 	.remove		= hid_device_remove,
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 7132173..8fae6d1 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -590,6 +590,5 @@
 }
 
 MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
 module_init(mousevsc_init);
 module_exit(mousevsc_exit);
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
index 327f9b8..eed7f52 100644
--- a/drivers/hid/hid-roccat-arvo.c
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -75,6 +75,8 @@
 
 	return size;
 }
+static DEVICE_ATTR(mode_key, 0660,
+		   arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key);
 
 static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -123,6 +125,8 @@
 
 	return size;
 }
+static DEVICE_ATTR(key_mask, 0660,
+		   arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask);
 
 /* retval is 1-5 on success, < 0 on error */
 static int arvo_get_actual_profile(struct usb_device *usb_dev)
@@ -179,6 +183,9 @@
 	mutex_unlock(&arvo->arvo_lock);
 	return retval;
 }
+static DEVICE_ATTR(actual_profile, 0660,
+		   arvo_sysfs_show_actual_profile,
+		   arvo_sysfs_set_actual_profile);
 
 static ssize_t arvo_sysfs_write(struct file *fp,
 		struct kobject *kobj, void const *buf,
@@ -230,6 +237,8 @@
 	return arvo_sysfs_write(fp, kobj, buf, off, count,
 			sizeof(struct arvo_button), ARVO_COMMAND_BUTTON);
 }
+static BIN_ATTR(button, 0220, NULL, arvo_sysfs_write_button,
+		sizeof(struct arvo_button));
 
 static ssize_t arvo_sysfs_read_info(struct file *fp,
 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -238,31 +247,30 @@
 	return arvo_sysfs_read(fp, kobj, buf, off, count,
 			sizeof(struct arvo_info), ARVO_COMMAND_INFO);
 }
+static BIN_ATTR(info, 0440, arvo_sysfs_read_info, NULL,
+		sizeof(struct arvo_info));
 
-
-static struct device_attribute arvo_attributes[] = {
-	__ATTR(mode_key, 0660,
-			arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key),
-	__ATTR(key_mask, 0660,
-			arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask),
-	__ATTR(actual_profile, 0660,
-			arvo_sysfs_show_actual_profile,
-			arvo_sysfs_set_actual_profile),
-	__ATTR_NULL
+static struct attribute *arvo_attrs[] = {
+	&dev_attr_mode_key.attr,
+	&dev_attr_key_mask.attr,
+	&dev_attr_actual_profile.attr,
+	NULL,
 };
 
-static struct bin_attribute arvo_bin_attributes[] = {
-	{
-		.attr = { .name = "button", .mode = 0220 },
-		.size = sizeof(struct arvo_button),
-		.write = arvo_sysfs_write_button
-	},
-	{
-		.attr = { .name = "info", .mode = 0440 },
-		.size = sizeof(struct arvo_info),
-		.read = arvo_sysfs_read_info
-	},
-	__ATTR_NULL
+static struct bin_attribute *arvo_bin_attributes[] = {
+	&bin_attr_button,
+	&bin_attr_info,
+	NULL,
+};
+
+static const struct attribute_group arvo_group = {
+	.attrs = arvo_attrs,
+	.bin_attrs = arvo_bin_attributes,
+};
+
+static const struct attribute_group *arvo_groups[] = {
+	&arvo_group,
+	NULL,
 };
 
 static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
@@ -430,8 +438,7 @@
 	arvo_class = class_create(THIS_MODULE, "arvo");
 	if (IS_ERR(arvo_class))
 		return PTR_ERR(arvo_class);
-	arvo_class->dev_attrs = arvo_attributes;
-	arvo_class->dev_bin_attrs = arvo_bin_attributes;
+	arvo_class->dev_groups = arvo_groups;
 
 	retval = hid_register_driver(&arvo_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index 8023751..b7a4e10 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -109,12 +109,12 @@
 
 	return size;
 }
+static DEVICE_ATTR(actual_profile, 0660, isku_sysfs_show_actual_profile,
+		   isku_sysfs_set_actual_profile);
 
-static struct device_attribute isku_attributes[] = {
-	__ATTR(actual_profile, 0660,
-			isku_sysfs_show_actual_profile,
-			isku_sysfs_set_actual_profile),
-	__ATTR_NULL
+static struct attribute *isku_attrs[] = {
+	&dev_attr_actual_profile.attr,
+	NULL,
 };
 
 static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
@@ -184,7 +184,8 @@
 ISKU_SYSFS_W(thingy, THINGY)
 
 #define ISKU_BIN_ATTR_RW(thingy, THINGY) \
-{ \
+ISKU_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0660 }, \
 	.size = ISKU_SIZE_ ## THINGY, \
 	.read = isku_sysfs_read_ ## thingy, \
@@ -192,52 +193,64 @@
 }
 
 #define ISKU_BIN_ATTR_R(thingy, THINGY) \
-{ \
+ISKU_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0440 }, \
 	.size = ISKU_SIZE_ ## THINGY, \
 	.read = isku_sysfs_read_ ## thingy, \
 }
 
 #define ISKU_BIN_ATTR_W(thingy, THINGY) \
-{ \
+ISKU_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0220 }, \
 	.size = ISKU_SIZE_ ## THINGY, \
 	.write = isku_sysfs_write_ ## thingy \
 }
 
-ISKU_SYSFS_RW(macro, MACRO)
-ISKU_SYSFS_RW(keys_function, KEYS_FUNCTION)
-ISKU_SYSFS_RW(keys_easyzone, KEYS_EASYZONE)
-ISKU_SYSFS_RW(keys_media, KEYS_MEDIA)
-ISKU_SYSFS_RW(keys_thumbster, KEYS_THUMBSTER)
-ISKU_SYSFS_RW(keys_macro, KEYS_MACRO)
-ISKU_SYSFS_RW(keys_capslock, KEYS_CAPSLOCK)
-ISKU_SYSFS_RW(light, LIGHT)
-ISKU_SYSFS_RW(key_mask, KEY_MASK)
-ISKU_SYSFS_RW(last_set, LAST_SET)
-ISKU_SYSFS_W(talk, TALK)
-ISKU_SYSFS_W(talkfx, TALKFX)
-ISKU_SYSFS_R(info, INFO)
-ISKU_SYSFS_W(control, CONTROL)
-ISKU_SYSFS_W(reset, RESET)
+ISKU_BIN_ATTR_RW(macro, MACRO);
+ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION);
+ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE);
+ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA);
+ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER);
+ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO);
+ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK);
+ISKU_BIN_ATTR_RW(light, LIGHT);
+ISKU_BIN_ATTR_RW(key_mask, KEY_MASK);
+ISKU_BIN_ATTR_RW(last_set, LAST_SET);
+ISKU_BIN_ATTR_W(talk, TALK);
+ISKU_BIN_ATTR_W(talkfx, TALKFX);
+ISKU_BIN_ATTR_W(control, CONTROL);
+ISKU_BIN_ATTR_W(reset, RESET);
+ISKU_BIN_ATTR_R(info, INFO);
 
-static struct bin_attribute isku_bin_attributes[] = {
-	ISKU_BIN_ATTR_RW(macro, MACRO),
-	ISKU_BIN_ATTR_RW(keys_function, KEYS_FUNCTION),
-	ISKU_BIN_ATTR_RW(keys_easyzone, KEYS_EASYZONE),
-	ISKU_BIN_ATTR_RW(keys_media, KEYS_MEDIA),
-	ISKU_BIN_ATTR_RW(keys_thumbster, KEYS_THUMBSTER),
-	ISKU_BIN_ATTR_RW(keys_macro, KEYS_MACRO),
-	ISKU_BIN_ATTR_RW(keys_capslock, KEYS_CAPSLOCK),
-	ISKU_BIN_ATTR_RW(light, LIGHT),
-	ISKU_BIN_ATTR_RW(key_mask, KEY_MASK),
-	ISKU_BIN_ATTR_RW(last_set, LAST_SET),
-	ISKU_BIN_ATTR_W(talk, TALK),
-	ISKU_BIN_ATTR_W(talkfx, TALKFX),
-	ISKU_BIN_ATTR_R(info, INFO),
-	ISKU_BIN_ATTR_W(control, CONTROL),
-	ISKU_BIN_ATTR_W(reset, RESET),
-	__ATTR_NULL
+static struct bin_attribute *isku_bin_attributes[] = {
+	&bin_attr_macro,
+	&bin_attr_keys_function,
+	&bin_attr_keys_easyzone,
+	&bin_attr_keys_media,
+	&bin_attr_keys_thumbster,
+	&bin_attr_keys_macro,
+	&bin_attr_keys_capslock,
+	&bin_attr_light,
+	&bin_attr_key_mask,
+	&bin_attr_last_set,
+	&bin_attr_talk,
+	&bin_attr_talkfx,
+	&bin_attr_control,
+	&bin_attr_reset,
+	&bin_attr_info,
+	NULL,
+};
+
+static const struct attribute_group isku_group = {
+	.attrs = isku_attrs,
+	.bin_attrs = isku_bin_attributes,
+};
+
+static const struct attribute_group *isku_groups[] = {
+	&isku_group,
+	NULL,
 };
 
 static int isku_init_isku_device_struct(struct usb_device *usb_dev,
@@ -427,8 +440,7 @@
 	isku_class = class_create(THIS_MODULE, "isku");
 	if (IS_ERR(isku_class))
 		return PTR_ERR(isku_class);
-	isku_class->dev_attrs = isku_attributes;
-	isku_class->dev_bin_attrs = isku_bin_attributes;
+	isku_class->dev_groups = isku_groups;
 
 	retval = hid_register_driver(&isku_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 7fae070..6e614a8 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -324,6 +324,8 @@
 
 	return sizeof(struct kone_settings);
 }
+static BIN_ATTR(settings, 0660, kone_sysfs_read_settings,
+		kone_sysfs_write_settings, sizeof(struct kone_settings));
 
 static ssize_t kone_sysfs_read_profilex(struct file *fp,
 		struct kobject *kobj, struct bin_attribute *attr,
@@ -378,6 +380,19 @@
 
 	return sizeof(struct kone_profile);
 }
+#define PROFILE_ATTR(number)					\
+static struct bin_attribute bin_attr_profile##number = {	\
+	.attr = { .name = "profile##number", .mode = 0660 },	\
+	.size = sizeof(struct kone_profile),			\
+	.read = kone_sysfs_read_profilex,			\
+	.write = kone_sysfs_write_profilex,			\
+	.private = &profile_numbers[number-1],			\
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
 
 static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -386,6 +401,7 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
 }
+static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
 
 static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -394,6 +410,7 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
 }
+static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);
 
 /* weight is read each time, since we don't get informed when it's changed */
 static ssize_t kone_sysfs_show_weight(struct device *dev,
@@ -416,6 +433,7 @@
 		return retval;
 	return snprintf(buf, PAGE_SIZE, "%d\n", weight);
 }
+static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);
 
 static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -424,6 +442,8 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
 }
+static DEVICE_ATTR(firmware_version, 0440, kone_sysfs_show_firmware_version,
+		   NULL);
 
 static ssize_t kone_sysfs_show_tcu(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -524,6 +544,7 @@
 	mutex_unlock(&kone->kone_lock);
 	return retval;
 }
+static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);
 
 static ssize_t kone_sysfs_show_startup_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -570,15 +591,17 @@
 	mutex_unlock(&kone->kone_lock);
 	return size;
 }
+static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile,
+		   kone_sysfs_set_startup_profile);
 
-static struct device_attribute kone_attributes[] = {
+static struct attribute *kone_attrs[] = {
 	/*
 	 * Read actual dpi settings.
 	 * Returns raw value for further processing. Refer to enum
 	 * kone_polling_rates to get real value.
 	 */
-	__ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
-	__ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
+	&dev_attr_actual_dpi.attr,
+	&dev_attr_actual_profile.attr,
 
 	/*
 	 * The mouse can be equipped with one of four supplied weights from 5
@@ -587,7 +610,7 @@
 	 * by software. Refer to enum kone_weights to get corresponding real
 	 * weight.
 	 */
-	__ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
+	&dev_attr_weight.attr,
 
 	/*
 	 * Prints firmware version stored in mouse as integer.
@@ -595,66 +618,38 @@
 	 * to get the real version number the decimal point has to be shifted 2
 	 * positions to the left. E.g. a value of 138 means 1.38.
 	 */
-	__ATTR(firmware_version, 0440,
-			kone_sysfs_show_firmware_version, NULL),
+	&dev_attr_firmware_version.attr,
 
 	/*
 	 * Prints state of Tracking Control Unit as number where 0 = off and
 	 * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
 	 * activates the tcu
 	 */
-	__ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
+	&dev_attr_tcu.attr,
 
 	/* Prints and takes the number of the profile the mouse starts with */
-	__ATTR(startup_profile, 0660,
-			kone_sysfs_show_startup_profile,
-			kone_sysfs_set_startup_profile),
-	__ATTR_NULL
+	&dev_attr_startup_profile.attr,
+	NULL,
 };
 
-static struct bin_attribute kone_bin_attributes[] = {
-	{
-		.attr = { .name = "settings", .mode = 0660 },
-		.size = sizeof(struct kone_settings),
-		.read = kone_sysfs_read_settings,
-		.write = kone_sysfs_write_settings
-	},
-	{
-		.attr = { .name = "profile1", .mode = 0660 },
-		.size = sizeof(struct kone_profile),
-		.read = kone_sysfs_read_profilex,
-		.write = kone_sysfs_write_profilex,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2", .mode = 0660 },
-		.size = sizeof(struct kone_profile),
-		.read = kone_sysfs_read_profilex,
-		.write = kone_sysfs_write_profilex,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3", .mode = 0660 },
-		.size = sizeof(struct kone_profile),
-		.read = kone_sysfs_read_profilex,
-		.write = kone_sysfs_write_profilex,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4", .mode = 0660 },
-		.size = sizeof(struct kone_profile),
-		.read = kone_sysfs_read_profilex,
-		.write = kone_sysfs_write_profilex,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5", .mode = 0660 },
-		.size = sizeof(struct kone_profile),
-		.read = kone_sysfs_read_profilex,
-		.write = kone_sysfs_write_profilex,
-		.private = &profile_numbers[4]
-	},
-	__ATTR_NULL
+static struct bin_attribute *kone_bin_attributes[] = {
+	&bin_attr_settings,
+	&bin_attr_profile1,
+	&bin_attr_profile2,
+	&bin_attr_profile3,
+	&bin_attr_profile4,
+	&bin_attr_profile5,
+	NULL,
+};
+
+static const struct attribute_group kone_group = {
+	.attrs = kone_attrs,
+	.bin_attrs = kone_bin_attributes,
+};
+
+static const struct attribute_group *kone_groups[] = {
+	&kone_group,
+	NULL,
 };
 
 static int kone_init_kone_device_struct(struct usb_device *usb_dev,
@@ -891,8 +886,7 @@
 	kone_class = class_create(THIS_MODULE, "kone");
 	if (IS_ERR(kone_class))
 		return PTR_ERR(kone_class);
-	kone_class->dev_attrs = kone_attributes;
-	kone_class->dev_bin_attrs = kone_bin_attributes;
+	kone_class->dev_groups = kone_groups;
 
 	retval = hid_register_driver(&kone_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 6a48fa3..db4d8b6 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -156,7 +156,8 @@
 KONEPLUS_SYSFS_R(thingy, THINGY)
 
 #define KONEPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+KONEPLUS_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0660 }, \
 	.size = KONEPLUS_SIZE_ ## THINGY, \
 	.read = koneplus_sysfs_read_ ## thingy, \
@@ -164,28 +165,29 @@
 }
 
 #define KONEPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
+KONEPLUS_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0440 }, \
 	.size = KONEPLUS_SIZE_ ## THINGY, \
 	.read = koneplus_sysfs_read_ ## thingy, \
 }
 
 #define KONEPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+KONEPLUS_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0220 }, \
 	.size = KONEPLUS_SIZE_ ## THINGY, \
 	.write = koneplus_sysfs_write_ ## thingy \
 }
-
-KONEPLUS_SYSFS_W(control, CONTROL)
-KONEPLUS_SYSFS_RW(info, INFO)
-KONEPLUS_SYSFS_W(talk, TALK)
-KONEPLUS_SYSFS_W(macro, MACRO)
-KONEPLUS_SYSFS_RW(sensor, SENSOR)
-KONEPLUS_SYSFS_RW(tcu, TCU)
-KONEPLUS_SYSFS_R(tcu_image, TCU_IMAGE)
-KONEPLUS_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-KONEPLUS_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
+KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
+KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK);
+KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO);
+KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE);
+KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO);
+KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR);
+KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU);
+KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 
 static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -225,6 +227,25 @@
 			KONEPLUS_COMMAND_PROFILE_BUTTONS);
 }
 
+#define PROFILE_ATTR(number)						\
+static struct bin_attribute bin_attr_profile##number##_settings = {	\
+	.attr = { .name = "profile##number##_settings", .mode = 0440 },	\
+	.size = KONEPLUS_SIZE_PROFILE_SETTINGS,				\
+	.read = koneplus_sysfs_read_profilex_settings,			\
+	.private = &profile_numbers[number-1],				\
+};									\
+static struct bin_attribute bin_attr_profile##number##_buttons = {	\
+	.attr = { .name = "profile##number##_buttons", .mode = 0440 },	\
+	.size = KONEPLUS_SIZE_PROFILE_BUTTONS,				\
+	.read = koneplus_sysfs_read_profilex_buttons,			\
+	.private = &profile_numbers[number-1],				\
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
+
 static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -274,6 +295,12 @@
 
 	return size;
 }
+static DEVICE_ATTR(actual_profile, 0660,
+		   koneplus_sysfs_show_actual_profile,
+		   koneplus_sysfs_set_actual_profile);
+static DEVICE_ATTR(startup_profile, 0660,
+		   koneplus_sysfs_show_actual_profile,
+		   koneplus_sysfs_set_actual_profile);
 
 static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -293,90 +320,47 @@
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 }
+static DEVICE_ATTR(firmware_version, 0440,
+		   koneplus_sysfs_show_firmware_version, NULL);
 
-static struct device_attribute koneplus_attributes[] = {
-	__ATTR(actual_profile, 0660,
-			koneplus_sysfs_show_actual_profile,
-			koneplus_sysfs_set_actual_profile),
-	__ATTR(startup_profile, 0660,
-			koneplus_sysfs_show_actual_profile,
-			koneplus_sysfs_set_actual_profile),
-	__ATTR(firmware_version, 0440,
-			koneplus_sysfs_show_firmware_version, NULL),
-	__ATTR_NULL
+static struct attribute *koneplus_attrs[] = {
+	&dev_attr_actual_profile.attr,
+	&dev_attr_startup_profile.attr,
+	&dev_attr_firmware_version.attr,
+	NULL,
 };
 
-static struct bin_attribute koneplus_bin_attributes[] = {
-	KONEPLUS_BIN_ATTRIBUTE_W(control, CONTROL),
-	KONEPLUS_BIN_ATTRIBUTE_RW(info, INFO),
-	KONEPLUS_BIN_ATTRIBUTE_W(talk, TALK),
-	KONEPLUS_BIN_ATTRIBUTE_W(macro, MACRO),
-	KONEPLUS_BIN_ATTRIBUTE_RW(sensor, SENSOR),
-	KONEPLUS_BIN_ATTRIBUTE_RW(tcu, TCU),
-	KONEPLUS_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
-	KONEPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
-	KONEPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
-	{
-		.attr = { .name = "profile1_settings", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_SETTINGS,
-		.read = koneplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2_settings", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_SETTINGS,
-		.read = koneplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3_settings", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_SETTINGS,
-		.read = koneplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4_settings", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_SETTINGS,
-		.read = koneplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5_settings", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_SETTINGS,
-		.read = koneplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[4]
-	},
-	{
-		.attr = { .name = "profile1_buttons", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_BUTTONS,
-		.read = koneplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2_buttons", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_BUTTONS,
-		.read = koneplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3_buttons", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_BUTTONS,
-		.read = koneplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4_buttons", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_BUTTONS,
-		.read = koneplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5_buttons", .mode = 0440 },
-		.size = KONEPLUS_SIZE_PROFILE_BUTTONS,
-		.read = koneplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[4]
-	},
-	__ATTR_NULL
+static struct bin_attribute *koneplus_bin_attributes[] = {
+	&bin_attr_control,
+	&bin_attr_talk,
+	&bin_attr_macro,
+	&bin_attr_tcu_image,
+	&bin_attr_info,
+	&bin_attr_sensor,
+	&bin_attr_tcu,
+	&bin_attr_profile_settings,
+	&bin_attr_profile_buttons,
+	&bin_attr_profile1_settings,
+	&bin_attr_profile2_settings,
+	&bin_attr_profile3_settings,
+	&bin_attr_profile4_settings,
+	&bin_attr_profile5_settings,
+	&bin_attr_profile1_buttons,
+	&bin_attr_profile2_buttons,
+	&bin_attr_profile3_buttons,
+	&bin_attr_profile4_buttons,
+	&bin_attr_profile5_buttons,
+	NULL,
+};
+
+static const struct attribute_group koneplus_group = {
+	.attrs = koneplus_attrs,
+	.bin_attrs = koneplus_bin_attributes,
+};
+
+static const struct attribute_group *koneplus_groups[] = {
+	&koneplus_group,
+	NULL,
 };
 
 static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
@@ -572,8 +556,7 @@
 	koneplus_class = class_create(THIS_MODULE, "koneplus");
 	if (IS_ERR(koneplus_class))
 		return PTR_ERR(koneplus_class);
-	koneplus_class->dev_attrs = koneplus_attributes;
-	koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
+	koneplus_class->dev_groups = koneplus_groups;
 
 	retval = hid_register_driver(&koneplus_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
index c79d0b0..fa02b1f 100644
--- a/drivers/hid/hid-roccat-konepure.c
+++ b/drivers/hid/hid-roccat-konepure.c
@@ -94,7 +94,8 @@
 KONEPURE_SYSFS_R(thingy, THINGY)
 
 #define KONEPURE_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+KONEPURE_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0660 }, \
 	.size = KONEPURE_SIZE_ ## THINGY, \
 	.read = konepure_sysfs_read_ ## thingy, \
@@ -102,44 +103,56 @@
 }
 
 #define KONEPURE_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
+KONEPURE_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0440 }, \
 	.size = KONEPURE_SIZE_ ## THINGY, \
 	.read = konepure_sysfs_read_ ## thingy, \
 }
 
 #define KONEPURE_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+KONEPURE_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0220 }, \
 	.size = KONEPURE_SIZE_ ## THINGY, \
 	.write = konepure_sysfs_write_ ## thingy \
 }
 
-KONEPURE_SYSFS_RW(actual_profile, ACTUAL_PROFILE)
-KONEPURE_SYSFS_W(control, CONTROL)
-KONEPURE_SYSFS_RW(info, INFO)
-KONEPURE_SYSFS_W(talk, TALK)
-KONEPURE_SYSFS_W(macro, MACRO)
-KONEPURE_SYSFS_RW(sensor, SENSOR)
-KONEPURE_SYSFS_RW(tcu, TCU)
-KONEPURE_SYSFS_R(tcu_image, TCU_IMAGE)
-KONEPURE_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-KONEPURE_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
+KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE);
+KONEPURE_BIN_ATTRIBUTE_RW(info, INFO);
+KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR);
+KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU);
+KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
+KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL);
+KONEPURE_BIN_ATTRIBUTE_W(talk, TALK);
+KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO);
+KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE);
 
-static struct bin_attribute konepure_bin_attributes[] = {
-	KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE),
-	KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL),
-	KONEPURE_BIN_ATTRIBUTE_RW(info, INFO),
-	KONEPURE_BIN_ATTRIBUTE_W(talk, TALK),
-	KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO),
-	KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR),
-	KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU),
-	KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
-	KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
-	KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
-	__ATTR_NULL
+static struct bin_attribute *konepure_bin_attributes[] = {
+	&bin_attr_actual_profile,
+	&bin_attr_info,
+	&bin_attr_sensor,
+	&bin_attr_tcu,
+	&bin_attr_profile_settings,
+	&bin_attr_profile_buttons,
+	&bin_attr_control,
+	&bin_attr_talk,
+	&bin_attr_macro,
+	&bin_attr_tcu_image,
+	NULL,
 };
 
+static const struct attribute_group konepure_group = {
+	.bin_attrs = konepure_bin_attributes,
+};
+
+static const struct attribute_group *konepure_groups[] = {
+	&konepure_group,
+	NULL,
+};
+
+
 static int konepure_init_konepure_device_struct(struct usb_device *usb_dev,
 		struct konepure_device *konepure)
 {
@@ -282,7 +295,7 @@
 	konepure_class = class_create(THIS_MODULE, "konepure");
 	if (IS_ERR(konepure_class))
 		return PTR_ERR(konepure_class);
-	konepure_class->dev_bin_attrs = konepure_bin_attributes;
+	konepure_class->dev_groups = konepure_groups;
 
 	retval = hid_register_driver(&konepure_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
index b8b3778..8a0f299 100644
--- a/drivers/hid/hid-roccat-kovaplus.c
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -197,31 +197,25 @@
 KOVAPLUS_SYSFS_R(thingy, THINGY)
 
 #define KOVAPLUS_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+KOVAPLUS_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0660 }, \
 	.size = KOVAPLUS_SIZE_ ## THINGY, \
 	.read = kovaplus_sysfs_read_ ## thingy, \
 	.write = kovaplus_sysfs_write_ ## thingy \
 }
 
-#define KOVAPLUS_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
-	.attr = { .name = #thingy, .mode = 0440 }, \
-	.size = KOVAPLUS_SIZE_ ## THINGY, \
-	.read = kovaplus_sysfs_read_ ## thingy, \
-}
-
 #define KOVAPLUS_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+KOVAPLUS_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0220 }, \
 	.size = KOVAPLUS_SIZE_ ## THINGY, \
 	.write = kovaplus_sysfs_write_ ## thingy \
 }
-
-KOVAPLUS_SYSFS_W(control, CONTROL)
-KOVAPLUS_SYSFS_RW(info, INFO)
-KOVAPLUS_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-KOVAPLUS_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
+KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL);
+KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO);
+KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 
 static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -261,6 +255,25 @@
 			KOVAPLUS_COMMAND_PROFILE_BUTTONS);
 }
 
+#define PROFILE_ATTR(number)						\
+static struct bin_attribute bin_attr_profile##number##_settings = {	\
+	.attr = { .name = "profile##number##_settings", .mode = 0440 },	\
+	.size = KOVAPLUS_SIZE_PROFILE_SETTINGS,				\
+	.read = kovaplus_sysfs_read_profilex_settings,			\
+	.private = &profile_numbers[number-1],				\
+};									\
+static struct bin_attribute bin_attr_profile##number##_buttons = {	\
+	.attr = { .name = "profile##number##_buttons", .mode = 0440 },	\
+	.size = KOVAPLUS_SIZE_PROFILE_BUTTONS,				\
+	.read = kovaplus_sysfs_read_profilex_buttons,			\
+	.private = &profile_numbers[number-1],				\
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
+
 static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -310,6 +323,9 @@
 
 	return size;
 }
+static DEVICE_ATTR(actual_profile, 0660,
+		   kovaplus_sysfs_show_actual_profile,
+		   kovaplus_sysfs_set_actual_profile);
 
 static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -318,6 +334,7 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
 }
+static DEVICE_ATTR(actual_cpi, 0440, kovaplus_sysfs_show_actual_cpi, NULL);
 
 static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -326,6 +343,8 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
 }
+static DEVICE_ATTR(actual_sensitivity_x, 0440,
+		   kovaplus_sysfs_show_actual_sensitivity_x, NULL);
 
 static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -334,6 +353,8 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
 }
+static DEVICE_ATTR(actual_sensitivity_y, 0440,
+		   kovaplus_sysfs_show_actual_sensitivity_y, NULL);
 
 static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -353,88 +374,44 @@
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 }
+static DEVICE_ATTR(firmware_version, 0440,
+		   kovaplus_sysfs_show_firmware_version, NULL);
 
-static struct device_attribute kovaplus_attributes[] = {
-	__ATTR(actual_cpi, 0440,
-		kovaplus_sysfs_show_actual_cpi, NULL),
-	__ATTR(firmware_version, 0440,
-		kovaplus_sysfs_show_firmware_version, NULL),
-	__ATTR(actual_profile, 0660,
-		kovaplus_sysfs_show_actual_profile,
-		kovaplus_sysfs_set_actual_profile),
-	__ATTR(actual_sensitivity_x, 0440,
-		kovaplus_sysfs_show_actual_sensitivity_x, NULL),
-	__ATTR(actual_sensitivity_y, 0440,
-		kovaplus_sysfs_show_actual_sensitivity_y, NULL),
-	__ATTR_NULL
+static struct attribute *kovaplus_attrs[] = {
+	&dev_attr_actual_cpi.attr,
+	&dev_attr_firmware_version.attr,
+	&dev_attr_actual_profile.attr,
+	&dev_attr_actual_sensitivity_x.attr,
+	&dev_attr_actual_sensitivity_y.attr,
+	NULL,
 };
 
-static struct bin_attribute kovaplus_bin_attributes[] = {
-	KOVAPLUS_BIN_ATTRIBUTE_W(control, CONTROL),
-	KOVAPLUS_BIN_ATTRIBUTE_RW(info, INFO),
-	KOVAPLUS_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
-	KOVAPLUS_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
-	{
-		.attr = { .name = "profile1_settings", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
-		.read = kovaplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2_settings", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
-		.read = kovaplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3_settings", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
-		.read = kovaplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4_settings", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
-		.read = kovaplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5_settings", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_SETTINGS,
-		.read = kovaplus_sysfs_read_profilex_settings,
-		.private = &profile_numbers[4]
-	},
-	{
-		.attr = { .name = "profile1_buttons", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
-		.read = kovaplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2_buttons", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
-		.read = kovaplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3_buttons", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
-		.read = kovaplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4_buttons", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
-		.read = kovaplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5_buttons", .mode = 0440 },
-		.size = KOVAPLUS_SIZE_PROFILE_BUTTONS,
-		.read = kovaplus_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[4]
-	},
-	__ATTR_NULL
+static struct bin_attribute *kovaplus_bin_attributes[] = {
+	&bin_attr_control,
+	&bin_attr_info,
+	&bin_attr_profile_settings,
+	&bin_attr_profile_buttons,
+	&bin_attr_profile1_settings,
+	&bin_attr_profile2_settings,
+	&bin_attr_profile3_settings,
+	&bin_attr_profile4_settings,
+	&bin_attr_profile5_settings,
+	&bin_attr_profile1_buttons,
+	&bin_attr_profile2_buttons,
+	&bin_attr_profile3_buttons,
+	&bin_attr_profile4_buttons,
+	&bin_attr_profile5_buttons,
+	NULL,
+};
+
+static const struct attribute_group kovaplus_group = {
+	.attrs = kovaplus_attrs,
+	.bin_attrs = kovaplus_bin_attributes,
+};
+
+static const struct attribute_group *kovaplus_groups[] = {
+	&kovaplus_group,
+	NULL,
 };
 
 static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
@@ -662,8 +639,7 @@
 	kovaplus_class = class_create(THIS_MODULE, "kovaplus");
 	if (IS_ERR(kovaplus_class))
 		return PTR_ERR(kovaplus_class);
-	kovaplus_class->dev_attrs = kovaplus_attributes;
-	kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
+	kovaplus_class->dev_groups = kovaplus_groups;
 
 	retval = hid_register_driver(&kovaplus_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index d4f1e3b..5a6dbbe 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -156,7 +156,8 @@
 PYRA_SYSFS_R(thingy, THINGY)
 
 #define PYRA_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+PYRA_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0660 }, \
 	.size = PYRA_SIZE_ ## THINGY, \
 	.read = pyra_sysfs_read_ ## thingy, \
@@ -164,24 +165,25 @@
 }
 
 #define PYRA_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
+PYRA_SYSFS_R(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0440 }, \
 	.size = PYRA_SIZE_ ## THINGY, \
 	.read = pyra_sysfs_read_ ## thingy, \
 }
 
 #define PYRA_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+PYRA_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0220 }, \
 	.size = PYRA_SIZE_ ## THINGY, \
 	.write = pyra_sysfs_write_ ## thingy \
 }
 
-PYRA_SYSFS_W(control, CONTROL)
-PYRA_SYSFS_RW(info, INFO)
-PYRA_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
-PYRA_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
-PYRA_SYSFS_R(settings, SETTINGS)
+PYRA_BIN_ATTRIBUTE_W(control, CONTROL);
+PYRA_BIN_ATTRIBUTE_RW(info, INFO);
+PYRA_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS);
+PYRA_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS);
 
 static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
@@ -221,6 +223,25 @@
 			PYRA_COMMAND_PROFILE_BUTTONS);
 }
 
+#define PROFILE_ATTR(number)						\
+static struct bin_attribute bin_attr_profile##number##_settings = {	\
+	.attr = { .name = "profile##number##_settings", .mode = 0440 },	\
+	.size = PYRA_SIZE_PROFILE_SETTINGS,				\
+	.read = pyra_sysfs_read_profilex_settings,			\
+	.private = &profile_numbers[number-1],				\
+};									\
+static struct bin_attribute bin_attr_profile##number##_buttons = {	\
+	.attr = { .name = "profile##number##_buttons", .mode = 0440 },	\
+	.size = PYRA_SIZE_PROFILE_BUTTONS,				\
+	.read = pyra_sysfs_read_profilex_buttons,			\
+	.private = &profile_numbers[number-1],				\
+};
+PROFILE_ATTR(1);
+PROFILE_ATTR(2);
+PROFILE_ATTR(3);
+PROFILE_ATTR(4);
+PROFILE_ATTR(5);
+
 static ssize_t pyra_sysfs_write_settings(struct file *fp,
 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
 		loff_t off, size_t count)
@@ -258,6 +279,11 @@
 	return PYRA_SIZE_SETTINGS;
 }
 
+PYRA_SYSFS_R(settings, SETTINGS);
+static struct bin_attribute bin_attr_settings =
+	__BIN_ATTR(settings, (S_IWUSR | S_IRUGO),
+		   pyra_sysfs_read_settings, pyra_sysfs_write_settings,
+		   PYRA_SIZE_SETTINGS);
 
 static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -266,6 +292,7 @@
 			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
 }
+static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
 
 static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -282,6 +309,8 @@
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", settings.startup_profile);
 }
+static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
+static DEVICE_ATTR(startup_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
 
 static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -301,84 +330,44 @@
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", info.firmware_version);
 }
+static DEVICE_ATTR(firmware_version, 0440, pyra_sysfs_show_firmware_version,
+		   NULL);
 
-static struct device_attribute pyra_attributes[] = {
-	__ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL),
-	__ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL),
-	__ATTR(firmware_version, 0440,
-			pyra_sysfs_show_firmware_version, NULL),
-	__ATTR(startup_profile, 0440,
-			pyra_sysfs_show_actual_profile, NULL),
-	__ATTR_NULL
+static struct attribute *pyra_attrs[] = {
+	&dev_attr_actual_cpi.attr,
+	&dev_attr_actual_profile.attr,
+	&dev_attr_firmware_version.attr,
+	&dev_attr_startup_profile.attr,
+	NULL,
 };
 
-static struct bin_attribute pyra_bin_attributes[] = {
-	PYRA_BIN_ATTRIBUTE_W(control, CONTROL),
-	PYRA_BIN_ATTRIBUTE_RW(info, INFO),
-	PYRA_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
-	PYRA_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
-	PYRA_BIN_ATTRIBUTE_RW(settings, SETTINGS),
-	{
-		.attr = { .name = "profile1_settings", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_SETTINGS,
-		.read = pyra_sysfs_read_profilex_settings,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2_settings", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_SETTINGS,
-		.read = pyra_sysfs_read_profilex_settings,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3_settings", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_SETTINGS,
-		.read = pyra_sysfs_read_profilex_settings,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4_settings", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_SETTINGS,
-		.read = pyra_sysfs_read_profilex_settings,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5_settings", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_SETTINGS,
-		.read = pyra_sysfs_read_profilex_settings,
-		.private = &profile_numbers[4]
-	},
-	{
-		.attr = { .name = "profile1_buttons", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_BUTTONS,
-		.read = pyra_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[0]
-	},
-	{
-		.attr = { .name = "profile2_buttons", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_BUTTONS,
-		.read = pyra_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[1]
-	},
-	{
-		.attr = { .name = "profile3_buttons", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_BUTTONS,
-		.read = pyra_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[2]
-	},
-	{
-		.attr = { .name = "profile4_buttons", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_BUTTONS,
-		.read = pyra_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[3]
-	},
-	{
-		.attr = { .name = "profile5_buttons", .mode = 0440 },
-		.size = PYRA_SIZE_PROFILE_BUTTONS,
-		.read = pyra_sysfs_read_profilex_buttons,
-		.private = &profile_numbers[4]
-	},
-	__ATTR_NULL
+static struct bin_attribute *pyra_bin_attributes[] = {
+	&bin_attr_control,
+	&bin_attr_info,
+	&bin_attr_profile_settings,
+	&bin_attr_profile_buttons,
+	&bin_attr_settings,
+	&bin_attr_profile1_settings,
+	&bin_attr_profile2_settings,
+	&bin_attr_profile3_settings,
+	&bin_attr_profile4_settings,
+	&bin_attr_profile5_settings,
+	&bin_attr_profile1_buttons,
+	&bin_attr_profile2_buttons,
+	&bin_attr_profile3_buttons,
+	&bin_attr_profile4_buttons,
+	&bin_attr_profile5_buttons,
+	NULL,
+};
+
+static const struct attribute_group pyra_group = {
+	.attrs = pyra_attrs,
+	.bin_attrs = pyra_bin_attributes,
+};
+
+static const struct attribute_group *pyra_groups[] = {
+	&pyra_group,
+	NULL,
 };
 
 static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
@@ -600,8 +589,7 @@
 	pyra_class = class_create(THIS_MODULE, "pyra");
 	if (IS_ERR(pyra_class))
 		return PTR_ERR(pyra_class);
-	pyra_class->dev_attrs = pyra_attributes;
-	pyra_class->dev_bin_attrs = pyra_bin_attributes;
+	pyra_class->dev_groups = pyra_groups;
 
 	retval = hid_register_driver(&pyra_driver);
 	if (retval)
diff --git a/drivers/hid/hid-roccat-savu.c b/drivers/hid/hid-roccat-savu.c
index 31747a2..0332267 100644
--- a/drivers/hid/hid-roccat-savu.c
+++ b/drivers/hid/hid-roccat-savu.c
@@ -94,44 +94,48 @@
 SAVU_SYSFS_R(thingy, THINGY)
 
 #define SAVU_BIN_ATTRIBUTE_RW(thingy, THINGY) \
-{ \
+SAVU_SYSFS_RW(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0660 }, \
 	.size = SAVU_SIZE_ ## THINGY, \
 	.read = savu_sysfs_read_ ## thingy, \
 	.write = savu_sysfs_write_ ## thingy \
 }
 
-#define SAVU_BIN_ATTRIBUTE_R(thingy, THINGY) \
-{ \
-	.attr = { .name = #thingy, .mode = 0440 }, \
-	.size = SAVU_SIZE_ ## THINGY, \
-	.read = savu_sysfs_read_ ## thingy, \
-}
-
 #define SAVU_BIN_ATTRIBUTE_W(thingy, THINGY) \
-{ \
+SAVU_SYSFS_W(thingy, THINGY); \
+static struct bin_attribute bin_attr_##thingy = { \
 	.attr = { .name = #thingy, .mode = 0220 }, \
 	.size = SAVU_SIZE_ ## THINGY, \
 	.write = savu_sysfs_write_ ## thingy \
 }
 
-SAVU_SYSFS_W(control, CONTROL)
-SAVU_SYSFS_RW(profile, PROFILE)
-SAVU_SYSFS_RW(general, GENERAL)
-SAVU_SYSFS_RW(buttons, BUTTONS)
-SAVU_SYSFS_RW(macro, MACRO)
-SAVU_SYSFS_RW(info, INFO)
-SAVU_SYSFS_RW(sensor, SENSOR)
+SAVU_BIN_ATTRIBUTE_W(control, CONTROL);
+SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE);
+SAVU_BIN_ATTRIBUTE_RW(general, GENERAL);
+SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS);
+SAVU_BIN_ATTRIBUTE_RW(macro, MACRO);
+SAVU_BIN_ATTRIBUTE_RW(info, INFO);
+SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR);
 
-static struct bin_attribute savu_bin_attributes[] = {
-	SAVU_BIN_ATTRIBUTE_W(control, CONTROL),
-	SAVU_BIN_ATTRIBUTE_RW(profile, PROFILE),
-	SAVU_BIN_ATTRIBUTE_RW(general, GENERAL),
-	SAVU_BIN_ATTRIBUTE_RW(buttons, BUTTONS),
-	SAVU_BIN_ATTRIBUTE_RW(macro, MACRO),
-	SAVU_BIN_ATTRIBUTE_RW(info, INFO),
-	SAVU_BIN_ATTRIBUTE_RW(sensor, SENSOR),
-	__ATTR_NULL
+static struct bin_attribute *savu_bin_attributes[] = {
+	&bin_attr_control,
+	&bin_attr_profile,
+	&bin_attr_general,
+	&bin_attr_buttons,
+	&bin_attr_macro,
+	&bin_attr_info,
+	&bin_attr_sensor,
+	NULL,
+};
+
+static const struct attribute_group savu_group = {
+	.bin_attrs = savu_bin_attributes,
+};
+
+static const struct attribute_group *savu_groups[] = {
+	&savu_group,
+	NULL,
 };
 
 static int savu_init_savu_device_struct(struct usb_device *usb_dev,
@@ -294,7 +298,7 @@
 	savu_class = class_create(THIS_MODULE, "savu");
 	if (IS_ERR(savu_class))
 		return PTR_ERR(savu_class);
-	savu_class->dev_bin_attrs = savu_bin_attributes;
+	savu_class->dev_groups = savu_groups;
 
 	retval = hid_register_driver(&savu_driver);
 	if (retval)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 0df7590..bbff5f2 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -48,30 +48,39 @@
  * @negop is of type &struct icmsg_negotiate.
  * Set up and fill in default negotiate response message.
  *
- * The max_fw_version specifies the maximum framework version that
- * we can support and max _srv_version specifies the maximum service
- * version we can support. A special value MAX_SRV_VER can be
- * specified to indicate that we can handle the maximum version
- * exposed by the host.
+ * The fw_version specifies the  framework version that
+ * we can support and srv_version specifies the service
+ * version we can support.
  *
  * Mainly used by Hyper-V drivers.
  */
-void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
 				struct icmsg_negotiate *negop, u8 *buf,
-				int max_fw_version, int max_srv_version)
+				int fw_version, int srv_version)
 {
-	int icframe_vercnt;
-	int icmsg_vercnt;
+	int icframe_major, icframe_minor;
+	int icmsg_major, icmsg_minor;
+	int fw_major, fw_minor;
+	int srv_major, srv_minor;
 	int i;
+	bool found_match = false;
 
 	icmsghdrp->icmsgsize = 0x10;
+	fw_major = (fw_version >> 16);
+	fw_minor = (fw_version & 0xFFFF);
+
+	srv_major = (srv_version >> 16);
+	srv_minor = (srv_version & 0xFFFF);
 
 	negop = (struct icmsg_negotiate *)&buf[
 		sizeof(struct vmbuspipe_hdr) +
 		sizeof(struct icmsg_hdr)];
 
-	icframe_vercnt = negop->icframe_vercnt;
-	icmsg_vercnt = negop->icmsg_vercnt;
+	icframe_major = negop->icframe_vercnt;
+	icframe_minor = 0;
+
+	icmsg_major = negop->icmsg_vercnt;
+	icmsg_minor = 0;
 
 	/*
 	 * Select the framework version number we will
@@ -79,26 +88,48 @@
 	 */
 
 	for (i = 0; i < negop->icframe_vercnt; i++) {
-		if (negop->icversion_data[i].major <= max_fw_version)
-			icframe_vercnt = negop->icversion_data[i].major;
+		if ((negop->icversion_data[i].major == fw_major) &&
+		   (negop->icversion_data[i].minor == fw_minor)) {
+			icframe_major = negop->icversion_data[i].major;
+			icframe_minor = negop->icversion_data[i].minor;
+			found_match = true;
+		}
 	}
 
+	if (!found_match)
+		goto fw_error;
+
+	found_match = false;
+
 	for (i = negop->icframe_vercnt;
 		 (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
-		if (negop->icversion_data[i].major <= max_srv_version)
-			icmsg_vercnt = negop->icversion_data[i].major;
+		if ((negop->icversion_data[i].major == srv_major) &&
+		   (negop->icversion_data[i].minor == srv_minor)) {
+			icmsg_major = negop->icversion_data[i].major;
+			icmsg_minor = negop->icversion_data[i].minor;
+			found_match = true;
+		}
 	}
 
 	/*
-	 * Respond with the maximum framework and service
+	 * Respond with the framework and service
 	 * version numbers we can support.
 	 */
-	negop->icframe_vercnt = 1;
-	negop->icmsg_vercnt = 1;
-	negop->icversion_data[0].major = icframe_vercnt;
-	negop->icversion_data[0].minor = 0;
-	negop->icversion_data[1].major = icmsg_vercnt;
-	negop->icversion_data[1].minor = 0;
+
+fw_error:
+	if (!found_match) {
+		negop->icframe_vercnt = 0;
+		negop->icmsg_vercnt = 0;
+	} else {
+		negop->icframe_vercnt = 1;
+		negop->icmsg_vercnt = 1;
+	}
+
+	negop->icversion_data[0].major = icframe_major;
+	negop->icversion_data[0].minor = icframe_minor;
+	negop->icversion_data[1].major = icmsg_major;
+	negop->icversion_data[1].minor = icmsg_minor;
+	return found_match;
 }
 
 EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
@@ -262,6 +293,13 @@
 	}
 
 	/*
+	 * This state is used to indicate a successful open
+	 * so that when we do close the channel normally, we
+	 * can cleanup properly
+	 */
+	newchannel->state = CHANNEL_OPEN_STATE;
+
+	/*
 	 * Start the process of binding this offer to the driver
 	 * We need to set the DeviceObject field before calling
 	 * vmbus_child_dev_add()
@@ -287,13 +325,6 @@
 		kfree(newchannel->device_obj);
 
 		free_channel(newchannel);
-	} else {
-		/*
-		 * This state is used to indicate a successful open
-		 * so that when we do close the channel normally, we
-		 * can cleanup properly
-		 */
-		newchannel->state = CHANNEL_OPEN_STATE;
 	}
 }
 
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index ec3b8cd..8f4743a 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -195,7 +195,10 @@
 
 	do {
 		ret = vmbus_negotiate_version(msginfo, version);
-		if (ret == 0)
+		if (ret)
+			goto cleanup;
+
+		if (vmbus_connection.conn_state == CONNECTED)
 			break;
 
 		version = vmbus_get_next_version(version);
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index deb5c25..7e17a54 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -825,7 +825,6 @@
 	memset(&resp, 0, sizeof(struct dm_hot_add_response));
 	resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE;
 	resp.hdr.size = sizeof(struct dm_hot_add_response);
-	resp.hdr.trans_id = atomic_inc_return(&trans_id);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
 	pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
@@ -887,6 +886,7 @@
 		pr_info("Memory hot add failed\n");
 
 	dm->state = DM_INITIALIZED;
+	resp.hdr.trans_id = atomic_inc_return(&trans_id);
 	vmbus_sendpacket(dm->dev->channel, &resp,
 			sizeof(struct dm_hot_add_response),
 			(unsigned long)NULL,
@@ -1081,7 +1081,6 @@
 		bl_resp = (struct dm_balloon_response *)send_buffer;
 		memset(send_buffer, 0, PAGE_SIZE);
 		bl_resp->hdr.type = DM_BALLOON_RESPONSE;
-		bl_resp->hdr.trans_id = atomic_inc_return(&trans_id);
 		bl_resp->hdr.size = sizeof(struct dm_balloon_response);
 		bl_resp->more_pages = 1;
 
@@ -1109,6 +1108,7 @@
 		 */
 
 		do {
+			bl_resp->hdr.trans_id = atomic_inc_return(&trans_id);
 			ret = vmbus_sendpacket(dm_device.dev->channel,
 						bl_resp,
 						bl_resp->hdr.size,
@@ -1526,5 +1526,4 @@
 module_init(init_balloon_drv);
 
 MODULE_DESCRIPTION("Hyper-V Balloon");
-MODULE_VERSION(HV_DRV_VERSION);
 MODULE_LICENSE("GPL");
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index ed50e9e..28b0332 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -29,6 +29,16 @@
 #include <linux/hyperv.h>
 
 
+/*
+ * Pre win8 version numbers used in ws2008 and ws 2008 r2 (win7)
+ */
+#define WIN7_SRV_MAJOR   3
+#define WIN7_SRV_MINOR   0
+#define WIN7_SRV_MAJOR_MINOR     (WIN7_SRV_MAJOR << 16 | WIN7_SRV_MINOR)
+
+#define WIN8_SRV_MAJOR   4
+#define WIN8_SRV_MINOR   0
+#define WIN8_SRV_MAJOR_MINOR     (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
 
 /*
  * Global state maintained for transaction that is being processed.
@@ -76,7 +86,9 @@
 /*
  * Register the kernel component with the user-level daemon.
  * As part of this registration, pass the LIC version number.
+ * This number has no meaning, it satisfies the registration protocol.
  */
+#define HV_DRV_VERSION           "3.1"
 
 static void
 kvp_register(int reg_value)
@@ -593,8 +605,19 @@
 			sizeof(struct vmbuspipe_hdr)];
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+			/*
+			 * We start with win8 version and if the host cannot
+			 * support that we use the previous version.
+			 */
+			if (vmbus_prep_negotiate_resp(icmsghdrp, negop,
+				 recv_buffer, UTIL_FW_MAJOR_MINOR,
+				 WIN8_SRV_MAJOR_MINOR))
+				goto done;
+
 			vmbus_prep_negotiate_resp(icmsghdrp, negop,
-				 recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
+				 recv_buffer, UTIL_FW_MAJOR_MINOR,
+				 WIN7_SRV_MAJOR_MINOR);
+
 		} else {
 			kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
 				sizeof(struct vmbuspipe_hdr) +
@@ -626,6 +649,7 @@
 			return;
 
 		}
+done:
 
 		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
 			| ICMSGHDRFLAG_RESPONSE;
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 8ad5653..e4572f3 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -24,6 +24,10 @@
 #include <linux/workqueue.h>
 #include <linux/hyperv.h>
 
+#define VSS_MAJOR  5
+#define VSS_MINOR  0
+#define VSS_MAJOR_MINOR    (VSS_MAJOR << 16 | VSS_MINOR)
+
 
 
 /*
@@ -186,18 +190,8 @@
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 			vmbus_prep_negotiate_resp(icmsghdrp, negop,
-				 recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
-			/*
-			 * We currently negotiate the highest number the
-			 * host has presented. If this version is not
-			 * atleast 5.0, reject.
-			 */
-			negop = (struct icmsg_negotiate *)&recv_buffer[
-				sizeof(struct vmbuspipe_hdr) +
-				sizeof(struct icmsg_hdr)];
-
-			if (negop->icversion_data[1].major < 5)
-				negop->icframe_vercnt = 0;
+				 recv_buffer, UTIL_FW_MAJOR_MINOR,
+				 VSS_MAJOR_MINOR);
 		} else {
 			vss_msg = (struct hv_vss_msg *)&recv_buffer[
 				sizeof(struct vmbuspipe_hdr) +
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 2f561c5..cb82233 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -28,6 +28,18 @@
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
 
+#define SHUTDOWN_MAJOR	3
+#define SHUTDOWN_MINOR  0
+#define SHUTDOWN_MAJOR_MINOR	(SHUTDOWN_MAJOR << 16 | SHUTDOWN_MINOR)
+
+#define TIMESYNCH_MAJOR	3
+#define TIMESYNCH_MINOR 0
+#define TIMESYNCH_MAJOR_MINOR	(TIMESYNCH_MAJOR << 16 | TIMESYNCH_MINOR)
+
+#define HEARTBEAT_MAJOR	3
+#define HEARTBEAT_MINOR 0
+#define HEARTBEAT_MAJOR_MINOR	(HEARTBEAT_MAJOR << 16 | HEARTBEAT_MINOR)
+
 static void shutdown_onchannelcallback(void *context);
 static struct hv_util_service util_shutdown = {
 	.util_cb = shutdown_onchannelcallback,
@@ -87,7 +99,8 @@
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 			vmbus_prep_negotiate_resp(icmsghdrp, negop,
-					shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
+					shut_txf_buf, UTIL_FW_MAJOR_MINOR,
+					SHUTDOWN_MAJOR_MINOR);
 		} else {
 			shutdown_msg =
 				(struct shutdown_msg_data *)&shut_txf_buf[
@@ -213,7 +226,8 @@
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 			vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
-						MAX_SRV_VER, MAX_SRV_VER);
+						UTIL_FW_MAJOR_MINOR,
+						TIMESYNCH_MAJOR_MINOR);
 		} else {
 			timedatap = (struct ictimesync_data *)&time_txf_buf[
 				sizeof(struct vmbuspipe_hdr) +
@@ -253,7 +267,8 @@
 
 		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 			vmbus_prep_negotiate_resp(icmsghdrp, NULL,
-				hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
+				hbeat_txf_buf, UTIL_FW_MAJOR_MINOR,
+				HEARTBEAT_MAJOR_MINOR);
 		} else {
 			heartbeat_msg =
 				(struct heartbeat_msg_data *)&hbeat_txf_buf[
@@ -380,5 +395,4 @@
 module_exit(exit_hyperv_utils);
 
 MODULE_DESCRIPTION("Hyper-V Utilities");
-MODULE_VERSION(HV_DRV_VERSION);
 MODULE_LICENSE("GPL");
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index e8e071f..f9fe46f 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -816,7 +816,6 @@
 
 
 MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
 
 subsys_initcall(hv_acpi_init);
 module_exit(vmbus_exit);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e989f7f..b3ab9d4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -296,8 +296,8 @@
 	  If you say yes here you get support for the temperature
 	  sensor(s) inside your CPU. Supported are later revisions of
 	  the AMD Family 10h and all revisions of the AMD Family 11h,
-	  12h (Llano), 14h (Brazos) and 15h (Bulldozer/Trinity)
-	  microarchitectures.
+	  12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity) and
+	  16h (Kabini) microarchitectures.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called k10temp.
@@ -511,6 +511,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called hih6130.
 
+config SENSORS_HTU21
+	tristate "Measurement Specialties HTU21D humidity/temperature sensors"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Measurement Specialties
+	  HTU21D humidity and temperature sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called htu21.
+
 config SENSORS_CORETEMP
 	tristate "Intel Core/Core2/Atom temperature sensor"
 	depends on X86
@@ -1202,8 +1212,8 @@
 	tristate "Texas Instruments ADS1015"
 	depends on I2C
 	help
-	  If you say yes here you get support for Texas Instruments ADS1015
-	  12-bit 4-input ADC device.
+	  If you say yes here you get support for Texas Instruments
+	  ADS1015/ADS1115 12/16-bit 4-input ADC device.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called ads1015.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4f0fb52..ec7cde0 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -65,6 +65,7 @@
 obj-$(CONFIG_SENSORS_GL520SM)	+= gl520sm.o
 obj-$(CONFIG_SENSORS_GPIO_FAN)	+= gpio-fan.o
 obj-$(CONFIG_SENSORS_HIH6130)	+= hih6130.o
+obj-$(CONFIG_SENSORS_HTU21)	+= htu21.o
 obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
 obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 6351aba..a9e3d01 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -2,7 +2,7 @@
  * A hwmon driver for ACPI 4.0 power meters
  * Copyright (C) 2009 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -1001,7 +1001,7 @@
 	acpi_bus_unregister_driver(&acpi_power_meter_driver);
 }
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("ACPI 4.0 power meter driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 2798246..7f9dc2f 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -46,17 +46,28 @@
 	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
 
 /* Data rates in samples per second */
-static const unsigned int data_rate_table[8] = {
-	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
+static const unsigned int data_rate_table_1015[8] = {
+	128, 250, 490, 920, 1600, 2400, 3300, 3300
+};
+
+static const unsigned int data_rate_table_1115[8] = {
+	8, 16, 32, 64, 128, 250, 475, 860
+};
 
 #define ADS1015_DEFAULT_CHANNELS 0xff
 #define ADS1015_DEFAULT_PGA 2
 #define ADS1015_DEFAULT_DATA_RATE 4
 
+enum ads1015_chips {
+	ads1015,
+	ads1115,
+};
+
 struct ads1015_data {
 	struct device *hwmon_dev;
 	struct mutex update_lock; /* mutex protect updates */
 	struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
+	enum ads1015_chips id;
 };
 
 static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
@@ -66,6 +77,8 @@
 	unsigned int pga = data->channel_data[channel].pga;
 	unsigned int data_rate = data->channel_data[channel].data_rate;
 	unsigned int conversion_time_ms;
+	const unsigned int * const rate_table = data->id == ads1115 ?
+		data_rate_table_1115 : data_rate_table_1015;
 	int res;
 
 	mutex_lock(&data->update_lock);
@@ -75,7 +88,7 @@
 	if (res < 0)
 		goto err_unlock;
 	config = res;
-	conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]);
+	conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]);
 
 	/* setup and start single conversion */
 	config &= 0x001f;
@@ -113,8 +126,9 @@
 	struct ads1015_data *data = i2c_get_clientdata(client);
 	unsigned int pga = data->channel_data[channel].pga;
 	int fullscale = fullscale_table[pga];
+	const unsigned mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
 
-	return DIV_ROUND_CLOSEST(reg * fullscale, 0x7ff0);
+	return DIV_ROUND_CLOSEST(reg * fullscale, mask);
 }
 
 /* sysfs callback function */
@@ -257,7 +271,7 @@
 			    GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
-
+	data->id = id->driver_data;
 	i2c_set_clientdata(client, data);
 	mutex_init(&data->update_lock);
 
@@ -286,7 +300,8 @@
 }
 
 static const struct i2c_device_id ads1015_id[] = {
-	{ "ads1015", 0 },
+	{ "ads1015",  ads1015},
+	{ "ads1115",  ads1115},
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, ads1015_id);
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index ba962ac..7092c78 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -145,7 +145,7 @@
 static int ads7828_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	struct ads7828_platform_data *pdata = client->dev.platform_data;
+	struct ads7828_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct ads7828_data *data;
 	int err;
 
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c
index 69481d3..addb5a4 100644
--- a/drivers/hwmon/adt7462.c
+++ b/drivers/hwmon/adt7462.c
@@ -2,7 +2,7 @@
  * A hwmon driver for the Analog Devices ADT7462
  * Copyright (C) 2008 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -333,7 +333,7 @@
 			return 0x4C;
 		break;
 	}
-	return -ENODEV;
+	return 0;
 }
 
 static int ADT7462_REG_VOLT_MIN(struct adt7462_data *data, int which)
@@ -392,7 +392,7 @@
 			return 0x77;
 		break;
 	}
-	return -ENODEV;
+	return 0;
 }
 
 static int ADT7462_REG_VOLT(struct adt7462_data *data, int which)
@@ -1970,6 +1970,6 @@
 
 module_i2c_driver(adt7462_driver);
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("ADT7462 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 6099f50..0f4dea5 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -2,7 +2,7 @@
  * A hwmon driver for the Analog Devices ADT7470
  * Copyright (C) 2007 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -1314,6 +1314,6 @@
 
 module_i2c_driver(adt7470_driver);
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("ADT7470 driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 2e5e2dc..78be661 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -316,6 +316,18 @@
 	return tjmax;
 }
 
+static bool cpu_has_tjmax(struct cpuinfo_x86 *c)
+{
+	u8 model = c->x86_model;
+
+	return model > 0xe &&
+	       model != 0x1c &&
+	       model != 0x26 &&
+	       model != 0x27 &&
+	       model != 0x35 &&
+	       model != 0x36;
+}
+
 static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 {
 	int err;
@@ -328,7 +340,7 @@
 	 */
 	err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
 	if (err) {
-		if (c->x86_model > 0xe && c->x86_model != 0x1c)
+		if (cpu_has_tjmax(c))
 			dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
 	} else {
 		val = (eax >> 16) & 0xff;
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index f1d6b42..0918b91 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -77,7 +77,7 @@
 
 static void ds620_init_client(struct i2c_client *client)
 {
-	struct ds620_platform_data *ds620_info = client->dev.platform_data;
+	struct ds620_platform_data *ds620_info = dev_get_platdata(&client->dev);
 	u16 conf, new_conf;
 
 	new_conf = conf =
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 0c9f3da..15b7f52 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1375,7 +1375,7 @@
 
 static int f71805f_probe(struct platform_device *pdev)
 {
-	struct f71805f_sio_data *sio_data = pdev->dev.platform_data;
+	struct f71805f_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	struct f71805f_data *data;
 	struct resource *res;
 	int i, err;
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index cfb02dd..31b221e 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -2267,7 +2267,7 @@
 static int f71882fg_probe(struct platform_device *pdev)
 {
 	struct f71882fg_data *data;
-	struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
+	struct f71882fg_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	int nr_fans = f71882fg_nr_fans[sio_data->type];
 	int nr_temps = f71882fg_nr_temps[sio_data->type];
 	int err, i;
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 9e300e5..a837b94 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -832,7 +832,8 @@
 		const struct i2c_device_id *id)
 {
 	struct f75375_data *data;
-	struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
+	struct f75375s_platform_data *f75375s_pdata =
+			dev_get_platdata(&client->dev);
 	int err;
 
 	if (!i2c_check_functionality(client->adapter,
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
index 73adf01..b4b8b5b 100644
--- a/drivers/hwmon/g762.c
+++ b/drivers/hwmon/g762.c
@@ -717,7 +717,7 @@
 
 static int g762_pdata_prop_import(struct i2c_client *client)
 {
-	struct g762_platform_data *pdata = client->dev.platform_data;
+	struct g762_platform_data *pdata = dev_get_platdata(&client->dev);
 	int ret;
 
 	if (!pdata)
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 3104149..b7d6a57 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -495,7 +495,7 @@
 {
 	int err;
 	struct gpio_fan_data *fan_data;
-	struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 #ifdef CONFIG_OF_GPIO
 	if (!pdata) {
diff --git a/drivers/hwmon/htu21.c b/drivers/hwmon/htu21.c
new file mode 100644
index 0000000..839086e
--- /dev/null
+++ b/drivers/hwmon/htu21.c
@@ -0,0 +1,199 @@
+/*
+ * Measurement Specialties HTU21D humidity and temperature sensor driver
+ *
+ * Copyright (C) 2013 William Markezana <william.markezana@meas-spec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+
+/* HTU21 Commands */
+#define HTU21_T_MEASUREMENT_HM	0xE3
+#define HTU21_RH_MEASUREMENT_HM	0xE5
+
+struct htu21 {
+	struct device *hwmon_dev;
+	struct mutex lock;
+	bool valid;
+	unsigned long last_update;
+	int temperature;
+	int humidity;
+};
+
+static inline int htu21_temp_ticks_to_millicelsius(int ticks)
+{
+	ticks &= ~0x0003; /* clear status bits */
+	/*
+	 * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14,
+	 * optimized for integer fixed point (3 digits) arithmetic
+	 */
+	return ((21965 * ticks) >> 13) - 46850;
+}
+
+static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
+{
+	ticks &= ~0x0003; /* clear status bits */
+	/*
+	 * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14,
+	 * optimized for integer fixed point (3 digits) arithmetic
+	 */
+	return ((15625 * ticks) >> 13) - 6000;
+}
+
+static int htu21_update_measurements(struct i2c_client *client)
+{
+	int ret = 0;
+	struct htu21 *htu21 = i2c_get_clientdata(client);
+
+	mutex_lock(&htu21->lock);
+
+	if (time_after(jiffies, htu21->last_update + HZ / 2) ||
+	    !htu21->valid) {
+		ret = i2c_smbus_read_word_swapped(client,
+						  HTU21_T_MEASUREMENT_HM);
+		if (ret < 0)
+			goto out;
+		htu21->temperature = htu21_temp_ticks_to_millicelsius(ret);
+		ret = i2c_smbus_read_word_swapped(client,
+						  HTU21_RH_MEASUREMENT_HM);
+		if (ret < 0)
+			goto out;
+		htu21->humidity = htu21_rh_ticks_to_per_cent_mille(ret);
+		htu21->last_update = jiffies;
+		htu21->valid = true;
+	}
+out:
+	mutex_unlock(&htu21->lock);
+
+	return ret >= 0 ? 0 : ret;
+}
+
+static ssize_t htu21_show_temperature(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct htu21 *htu21 = i2c_get_clientdata(client);
+	int ret = htu21_update_measurements(client);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", htu21->temperature);
+}
+
+static ssize_t htu21_show_humidity(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct htu21 *htu21 = i2c_get_clientdata(client);
+	int ret = htu21_update_measurements(client);
+	if (ret < 0)
+		return ret;
+	return sprintf(buf, "%d\n", htu21->humidity);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+			  htu21_show_temperature, NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
+			  htu21_show_humidity, NULL, 0);
+
+static struct attribute *htu21_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_humidity1_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group htu21_group = {
+	.attrs = htu21_attributes,
+};
+
+static int htu21_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct htu21 *htu21;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+		dev_err(&client->dev,
+			"adapter does not support SMBus word transactions\n");
+		return -ENODEV;
+	}
+
+	htu21 = devm_kzalloc(&client->dev, sizeof(*htu21), GFP_KERNEL);
+	if (!htu21)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, htu21);
+
+	mutex_init(&htu21->lock);
+
+	err = sysfs_create_group(&client->dev.kobj, &htu21_group);
+	if (err) {
+		dev_dbg(&client->dev, "could not create sysfs files\n");
+		return err;
+	}
+	htu21->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(htu21->hwmon_dev)) {
+		dev_dbg(&client->dev, "unable to register hwmon device\n");
+		err = PTR_ERR(htu21->hwmon_dev);
+		goto error;
+	}
+
+	dev_info(&client->dev, "initialized\n");
+
+	return 0;
+
+error:
+	sysfs_remove_group(&client->dev.kobj, &htu21_group);
+	return err;
+}
+
+static int htu21_remove(struct i2c_client *client)
+{
+	struct htu21 *htu21 = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(htu21->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &htu21_group);
+
+	return 0;
+}
+
+static const struct i2c_device_id htu21_id[] = {
+	{ "htu21", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, htu21_id);
+
+static struct i2c_driver htu21_driver = {
+	.class = I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "htu21",
+	},
+	.probe       = htu21_probe,
+	.remove      = htu21_remove,
+	.id_table    = htu21_id,
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_DESCRIPTION("MEAS HTU21D humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index de058c2..6c0080a 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -3,7 +3,7 @@
  * temperature sensors
  * Copyright (C) 2007 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -609,7 +609,7 @@
 	platform_driver_unregister(&i5k_amb_driver);
 }
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index 1429f6e..e2b56a2 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -3,7 +3,7 @@
  * temperature/power/energy sensors and capping functionality.
  * Copyright (C) 2008 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -1103,7 +1103,7 @@
 		aem_delete(p1);
 }
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("IBM AEM power/temp/energy sensor driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index 74b365e..20ab0fb 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -2,7 +2,7 @@
  * A hwmon driver for the IBM PowerExecutive temperature/power sensors
  * Copyright (C) 2007 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -606,7 +606,7 @@
 		ibmpex_bmc_delete(p);
 }
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index d917a2d..18c0623 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -232,9 +232,9 @@
 	if (!data)
 		return -ENOMEM;
 
-	if (client->dev.platform_data) {
+	if (dev_get_platdata(&client->dev)) {
 		pdata =
-		  (struct ina2xx_platform_data *)client->dev.platform_data;
+		  (struct ina2xx_platform_data *)dev_get_platdata(&client->dev);
 		shunt = pdata->shunt_uohms;
 	} else if (!of_property_read_u32(client->dev.of_node,
 				"shunt-resistor", &val)) {
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 72b21d5..29ffa27 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1962,7 +1962,7 @@
 static void it87_remove_files(struct device *dev)
 {
 	struct it87_data *data = platform_get_drvdata(pdev);
-	struct it87_sio_data *sio_data = dev->platform_data;
+	struct it87_sio_data *sio_data = dev_get_platdata(dev);
 	int i;
 
 	sysfs_remove_group(&dev->kobj, &it87_group);
@@ -2014,7 +2014,7 @@
 	struct it87_data *data;
 	struct resource *res;
 	struct device *dev = &pdev->dev;
-	struct it87_sio_data *sio_data = dev->platform_data;
+	struct it87_sio_data *sio_data = dev_get_platdata(dev);
 	int err = 0, i;
 	int enable_pwm_interface;
 	int fan_beep_need_rw;
@@ -2316,7 +2316,7 @@
 /* Called when we have found a new IT87. */
 static void it87_init_device(struct platform_device *pdev)
 {
-	struct it87_sio_data *sio_data = pdev->dev.platform_data;
+	struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	struct it87_data *data = platform_get_drvdata(pdev);
 	int tmp, i;
 	u8 mask;
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index e3b037c..e633856 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -1,5 +1,5 @@
 /*
- * k10temp.c - AMD Family 10h/11h/12h/14h/15h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h processor hardware monitoring
  *
  * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
  *
@@ -211,6 +211,7 @@
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
 	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
+	{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 16e45d7..333092c 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -855,8 +855,8 @@
 {
 	struct lm87_data *data = i2c_get_clientdata(client);
 
-	if (client->dev.platform_data) {
-		data->channel = *(u8 *)client->dev.platform_data;
+	if (dev_get_platdata(&client->dev)) {
+		data->channel = *(u8 *)dev_get_platdata(&client->dev);
 		lm87_write_value(client,
 				 LM87_REG_CHANNEL_MODE, data->channel);
 	} else {
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
index b5ebb91..96dccaf 100644
--- a/drivers/hwmon/max197.c
+++ b/drivers/hwmon/max197.c
@@ -261,7 +261,7 @@
 {
 	int ch, ret;
 	struct max197_data *data;
-	struct max197_platform_data *pdata = pdev->dev.platform_data;
+	struct max197_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	enum max197_chips chip = platform_get_device_id(pdev)->driver_data;
 
 	if (pdata == NULL) {
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index 3e7b426..066e587 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -428,7 +428,7 @@
 {
 	struct max6639_data *data = i2c_get_clientdata(client);
 	struct max6639_platform_data *max6639_info =
-		client->dev.platform_data;
+		dev_get_platdata(&client->dev);
 	int i;
 	int rpm_range = 1; /* default: 4000 RPM */
 	int err;
diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c
index eedb322..d219c06 100644
--- a/drivers/hwmon/mcp3021.c
+++ b/drivers/hwmon/mcp3021.c
@@ -143,12 +143,13 @@
 		break;
 	}
 
-	if (client->dev.platform_data) {
-		data->vdd = *(u32 *)client->dev.platform_data;
+	if (dev_get_platdata(&client->dev)) {
+		data->vdd = *(u32 *)dev_get_platdata(&client->dev);
 		if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
 			return -EINVAL;
-	} else
+	} else {
 		data->vdd = MCP3021_VDD_REF;
+	}
 
 	err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
 	if (err)
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 99cec18..6eb03ce 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -33,9 +33,11 @@
  * Supports the following chips:
  *
  * Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
+ * nct6106d     9      3       3       6+3    0xc450 0xc1    0x5ca3
  * nct6775f     9      4       3       6+3    0xb470 0xc1    0x5ca3
  * nct6776f     9      5       3       6+3    0xc330 0xc1    0x5ca3
  * nct6779d    15      5       5       2+6    0xc560 0xc1    0x5ca3
+ * nct6791d    15      6       6       2+6    0xc800 0xc1    0x5ca3
  *
  * #temp lists the number of monitored temperature sources (first value) plus
  * the number of directly connectable temperature sensors (second value).
@@ -59,13 +61,15 @@
 
 #define USE_ALTERNATE
 
-enum kinds { nct6775, nct6776, nct6779 };
+enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 };
 
 /* used to set data->name = nct6775_device_names[data->sio_kind] */
 static const char * const nct6775_device_names[] = {
+	"nct6106",
 	"nct6775",
 	"nct6776",
 	"nct6779",
+	"nct6791",
 };
 
 static unsigned short force_id;
@@ -91,9 +95,11 @@
 #define SIO_REG_ENABLE		0x30	/* Logical device enable */
 #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
 
+#define SIO_NCT6106_ID		0xc450
 #define SIO_NCT6775_ID		0xb470
 #define SIO_NCT6776_ID		0xc330
 #define SIO_NCT6779_ID		0xc560
+#define SIO_NCT6791_ID		0xc800
 #define SIO_ID_MASK		0xFFF0
 
 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
@@ -167,7 +173,10 @@
 #define NUM_TEMP	10	/* Max number of temp attribute sets w/ limits*/
 #define NUM_TEMP_FIXED	6	/* Max number of fixed temp attribute sets */
 
-#define NUM_REG_ALARM	4	/* Max number of alarm registers */
+#define NUM_REG_ALARM	7	/* Max number of alarm registers */
+#define NUM_REG_BEEP	5	/* Max number of beep registers */
+
+#define NUM_FAN		6
 
 /* Common and NCT6775 specific data */
 
@@ -185,6 +194,7 @@
 
 #define NCT6775_REG_VBAT		0x5D
 #define NCT6775_REG_DIODE		0x5E
+#define NCT6775_DIODE_MASK		0x02
 
 #define NCT6775_REG_FANDIV1		0x506
 #define NCT6775_REG_FANDIV2		0x507
@@ -193,7 +203,7 @@
 
 static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
 
-/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+/* 0..15 voltages, 16..23 fans, 24..29 temperatures, 30..31 intrusion */
 
 static const s8 NCT6775_ALARM_BITS[] = {
 	0, 1, 2, 3, 8, 21, 20, 16,	/* in0.. in7 */
@@ -208,6 +218,23 @@
 #define TEMP_ALARM_BASE		24
 #define INTRUSION_ALARM_BASE	30
 
+static const u16 NCT6775_REG_BEEP[NUM_REG_BEEP] = { 0x56, 0x57, 0x453, 0x4e };
+
+/*
+ * 0..14 voltages, 15 global beep enable, 16..23 fans, 24..29 temperatures,
+ * 30..31 intrusion
+ */
+static const s8 NCT6775_BEEP_BITS[] = {
+	0, 1, 2, 3, 8, 9, 10, 16,	/* in0.. in7 */
+	17, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	21,				/* global beep enable */
+	6, 7, 11, 28, -1,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, -1 };			/* intrusion0, intrusion1 */
+
+#define BEEP_ENABLE_BASE		15
+
 static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
 static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
 
@@ -217,27 +244,32 @@
 
 /* Advanced Fan control, some values are common for all fans */
 
-static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 };
-static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 };
+static const u16 NCT6775_REG_TARGET[] = {
+	0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 };
+static const u16 NCT6775_REG_FAN_MODE[] = {
+	0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
 static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
-	0x103, 0x203, 0x303, 0x803, 0x903 };
+	0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 };
 static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
-	0x104, 0x204, 0x304, 0x804, 0x904 };
+	0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
 static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
-	0x105, 0x205, 0x305, 0x805, 0x905 };
-static const u16 NCT6775_REG_FAN_START_OUTPUT[]
-	= { 0x106, 0x206, 0x306, 0x806, 0x906 };
+	0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
+	0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 };
 static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
 static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
 
 static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
-	0x107, 0x207, 0x307, 0x807, 0x907 };
-static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
-static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
+	0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 };
+static const u16 NCT6775_REG_PWM[] = {
+	0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
+static const u16 NCT6775_REG_PWM_READ[] = {
+	0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 };
 
 static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
 static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
 static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 };
 
 static const u16 NCT6775_REG_TEMP[] = {
 	0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
@@ -253,25 +285,25 @@
 	0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
 
 static const u16 NCT6775_REG_TEMP_SEL[] = {
-	0x100, 0x200, 0x300, 0x800, 0x900 };
+	0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 };
 
 static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
-	0x139, 0x239, 0x339, 0x839, 0x939 };
+	0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
 static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
-	0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
+	0x13a, 0x23a, 0x33a, 0x83a, 0x93a, 0xa3a };
 static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
-	0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
+	0x13b, 0x23b, 0x33b, 0x83b, 0x93b, 0xa3b };
 static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
-	0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
+	0x13c, 0x23c, 0x33c, 0x83c, 0x93c, 0xa3c };
 static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
-	0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
+	0x13d, 0x23d, 0x33d, 0x83d, 0x93d, 0xa3d };
 
 static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
 
 static const u16 NCT6775_REG_AUTO_TEMP[] = {
-	0x121, 0x221, 0x321, 0x821, 0x921 };
+	0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
 static const u16 NCT6775_REG_AUTO_PWM[] = {
-	0x127, 0x227, 0x327, 0x827, 0x927 };
+	0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 };
 
 #define NCT6775_AUTO_TEMP(data, nr, p)	((data)->REG_AUTO_TEMP[nr] + (p))
 #define NCT6775_AUTO_PWM(data, nr, p)	((data)->REG_AUTO_PWM[nr] + (p))
@@ -279,9 +311,9 @@
 static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
 
 static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
-	0x135, 0x235, 0x335, 0x835, 0x935 };
+	0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
 static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
-	0x138, 0x238, 0x338, 0x838, 0x938 };
+	0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 };
 
 static const char *const nct6775_temp_label[] = {
 	"",
@@ -325,17 +357,28 @@
 	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
 	12, 9 };			/* intrusion0, intrusion1 */
 
-static const u16 NCT6776_REG_TOLERANCE_H[] = {
-	0x10c, 0x20c, 0x30c, 0x80c, 0x90c };
+static const u16 NCT6776_REG_BEEP[NUM_REG_BEEP] = { 0xb2, 0xb3, 0xb4, 0xb5 };
 
-static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 };
-static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 };
+static const s8 NCT6776_BEEP_BITS[] = {
+	0, 1, 2, 3, 4, 5, 6, 7,		/* in0.. in7 */
+	8, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	24,				/* global beep enable */
+	25, 26, 27, 28, 29,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, 18, 19, 20, 21,		/* temp1..temp6 */
+	30, 31 };			/* intrusion0, intrusion1 */
+
+static const u16 NCT6776_REG_TOLERANCE_H[] = {
+	0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c };
+
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
 
 static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
 static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
 
 static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
-	0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
+	0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
 
 static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
 	0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
@@ -390,14 +433,25 @@
 	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
 	12, 9 };			/* intrusion0, intrusion1 */
 
-static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 };
+static const s8 NCT6779_BEEP_BITS[] = {
+	0, 1, 2, 3, 4, 5, 6, 7,		/* in0.. in7 */
+	8, 9, 10, 11, 12, 13, 14,	/* in8..in14 */
+	24,				/* global beep enable */
+	25, 26, 27, 28, 29,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, -1, -1, -1, -1,		/* temp1..temp6 */
+	30, 31 };			/* intrusion0, intrusion1 */
+
+static const u16 NCT6779_REG_FAN[] = {
+	0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba };
 static const u16 NCT6779_REG_FAN_PULSES[] = {
-	0x644, 0x645, 0x646, 0x647, 0x648 };
+	0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
 
 static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
-	0x136, 0x236, 0x336, 0x836, 0x936 };
+	0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 };
+#define NCT6779_CRITICAL_PWM_ENABLE_MASK	0x01
 static const u16 NCT6779_REG_CRITICAL_PWM[] = {
-	0x137, 0x237, 0x337, 0x837, 0x937 };
+	0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 };
 
 static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
 static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
@@ -449,6 +503,122 @@
 static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
 	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
 
+/* NCT6791 specific data */
+
+#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE	0x28
+
+static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
+	0x459, 0x45A, 0x45B, 0x568, 0x45D };
+
+static const s8 NCT6791_ALARM_BITS[] = {
+	0, 1, 2, 3, 8, 21, 20, 16,	/* in0.. in7 */
+	17, 24, 25, 26, 27, 28, 29,	/* in8..in14 */
+	-1,				/* unused */
+	6, 7, 11, 10, 23, 33,		/* fan1..fan6 */
+	-1, -1,				/* unused */
+	4, 5, 13, -1, -1, -1,		/* temp1..temp6 */
+	12, 9 };			/* intrusion0, intrusion1 */
+
+
+/* NCT6102D/NCT6106D specific data */
+
+#define NCT6106_REG_VBAT	0x318
+#define NCT6106_REG_DIODE	0x319
+#define NCT6106_DIODE_MASK	0x01
+
+static const u16 NCT6106_REG_IN_MAX[] = {
+	0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9e, 0xa0, 0xa2 };
+static const u16 NCT6106_REG_IN_MIN[] = {
+	0x91, 0x93, 0x95, 0x97, 0x99, 0x9b, 0x9f, 0xa1, 0xa3 };
+static const u16 NCT6106_REG_IN[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 };
+
+static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 };
+static const u16 NCT6106_REG_TEMP_HYST[] = {
+	0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 };
+static const u16 NCT6106_REG_TEMP_OVER[] = {
+	0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd6 };
+static const u16 NCT6106_REG_TEMP_CRIT_L[] = {
+	0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4 };
+static const u16 NCT6106_REG_TEMP_CRIT_H[] = {
+	0xc1, 0xc5, 0xc9, 0xcf, 0xd1, 0xd5 };
+static const u16 NCT6106_REG_TEMP_OFFSET[] = { 0x311, 0x312, 0x313 };
+static const u16 NCT6106_REG_TEMP_CONFIG[] = {
+	0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc };
+
+static const u16 NCT6106_REG_FAN[] = { 0x20, 0x22, 0x24 };
+static const u16 NCT6106_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4 };
+static const u16 NCT6106_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0, 0 };
+static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4, 0, 0 };
+
+static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
+static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
+static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
+static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
+static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
+static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
+static const u16 NCT6106_REG_TEMP_SOURCE[] = {
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
+
+static const u16 NCT6106_REG_CRITICAL_TEMP[] = { 0x11a, 0x12a, 0x13a };
+static const u16 NCT6106_REG_CRITICAL_TEMP_TOLERANCE[] = {
+	0x11b, 0x12b, 0x13b };
+
+static const u16 NCT6106_REG_CRITICAL_PWM_ENABLE[] = { 0x11c, 0x12c, 0x13c };
+#define NCT6106_CRITICAL_PWM_ENABLE_MASK	0x10
+static const u16 NCT6106_REG_CRITICAL_PWM[] = { 0x11d, 0x12d, 0x13d };
+
+static const u16 NCT6106_REG_FAN_STEP_UP_TIME[] = { 0x114, 0x124, 0x134 };
+static const u16 NCT6106_REG_FAN_STEP_DOWN_TIME[] = { 0x115, 0x125, 0x135 };
+static const u16 NCT6106_REG_FAN_STOP_OUTPUT[] = { 0x116, 0x126, 0x136 };
+static const u16 NCT6106_REG_FAN_START_OUTPUT[] = { 0x117, 0x127, 0x137 };
+static const u16 NCT6106_REG_FAN_STOP_TIME[] = { 0x118, 0x128, 0x138 };
+static const u16 NCT6106_REG_TOLERANCE_H[] = { 0x112, 0x122, 0x132 };
+
+static const u16 NCT6106_REG_TARGET[] = { 0x111, 0x121, 0x131 };
+
+static const u16 NCT6106_REG_WEIGHT_TEMP_SEL[] = { 0x168, 0x178, 0x188 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP[] = { 0x169, 0x179, 0x189 };
+static const u16 NCT6106_REG_WEIGHT_TEMP_STEP_TOL[] = { 0x16a, 0x17a, 0x18a };
+static const u16 NCT6106_REG_WEIGHT_DUTY_STEP[] = { 0x16b, 0x17b, 0x17c };
+static const u16 NCT6106_REG_WEIGHT_TEMP_BASE[] = { 0x16c, 0x17c, 0x18c };
+static const u16 NCT6106_REG_WEIGHT_DUTY_BASE[] = { 0x16d, 0x17d, 0x18d };
+
+static const u16 NCT6106_REG_AUTO_TEMP[] = { 0x160, 0x170, 0x180 };
+static const u16 NCT6106_REG_AUTO_PWM[] = { 0x164, 0x174, 0x184 };
+
+static const u16 NCT6106_REG_ALARM[NUM_REG_ALARM] = {
+	0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d };
+
+static const s8 NCT6106_ALARM_BITS[] = {
+	0, 1, 2, 3, 4, 5, 7, 8,		/* in0.. in7 */
+	9, -1, -1, -1, -1, -1, -1,	/* in8..in14 */
+	-1,				/* unused */
+	32, 33, 34, -1, -1,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, 18, 19, 20, 21,		/* temp1..temp6 */
+	48, -1				/* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_BEEP[NUM_REG_BEEP] = {
+	0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4 };
+
+static const s8 NCT6106_BEEP_BITS[] = {
+	0, 1, 2, 3, 4, 5, 7, 8,		/* in0.. in7 */
+	9, 10, 11, 12, -1, -1, -1,	/* in8..in14 */
+	32,				/* global beep enable */
+	24, 25, 26, 27, 28,		/* fan1..fan5 */
+	-1, -1, -1,			/* unused */
+	16, 17, 18, 19, 20, 21,		/* temp1..temp6 */
+	34, -1				/* intrusion0, intrusion1 */
+};
+
+static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 };
+
+static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+	= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 };
+
 static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
 {
 	if (mode == 0 && pwm == 255)
@@ -550,13 +720,18 @@
 
 struct nct6775_data {
 	int addr;	/* IO base of hw monitor block */
+	int sioreg;	/* SIO register address */
 	enum kinds kind;
 	const char *name;
 
 	struct device *hwmon_dev;
+	struct attribute_group *group_in;
+	struct attribute_group *group_fan;
+	struct attribute_group *group_temp;
+	struct attribute_group *group_pwm;
 
-	u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
-				    * 3=temp_crit
+	u16 reg_temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+				    * 3=temp_crit, 4=temp_lcrit
 				    */
 	u8 temp_src[NUM_TEMP];
 	u16 reg_temp_config[NUM_TEMP];
@@ -566,8 +741,10 @@
 	u16 REG_CONFIG;
 	u16 REG_VBAT;
 	u16 REG_DIODE;
+	u8 DIODE_MASK;
 
 	const s8 *ALARM_BITS;
+	const s8 *BEEP_BITS;
 
 	const u16 *REG_VIN;
 	const u16 *REG_IN_MINMAX[2];
@@ -577,6 +754,7 @@
 	const u16 *REG_FAN_MODE;
 	const u16 *REG_FAN_MIN;
 	const u16 *REG_FAN_PULSES;
+	const u16 *FAN_PULSE_SHIFT;
 	const u16 *REG_FAN_TIME[3];
 
 	const u16 *REG_TOLERANCE_H;
@@ -590,6 +768,10 @@
 				 */
 	const u16 *REG_PWM_READ;
 
+	const u16 *REG_CRITICAL_PWM_ENABLE;
+	u8 CRITICAL_PWM_ENABLE_MASK;
+	const u16 *REG_CRITICAL_PWM;
+
 	const u16 *REG_AUTO_TEMP;
 	const u16 *REG_AUTO_PWM;
 
@@ -604,6 +786,7 @@
 	const u16 *REG_TEMP_OFFSET;
 
 	const u16 *REG_ALARM;
+	const u16 *REG_BEEP;
 
 	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
 	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
@@ -616,26 +799,30 @@
 	u8 bank;		/* current register bank */
 	u8 in_num;		/* number of in inputs we have */
 	u8 in[15][3];		/* [0]=in, [1]=in_max, [2]=in_min */
-	unsigned int rpm[5];
-	u16 fan_min[5];
-	u8 fan_pulses[5];
-	u8 fan_div[5];
+	unsigned int rpm[NUM_FAN];
+	u16 fan_min[NUM_FAN];
+	u8 fan_pulses[NUM_FAN];
+	u8 fan_div[NUM_FAN];
 	u8 has_pwm;
 	u8 has_fan;		/* some fan inputs can be disabled */
 	u8 has_fan_min;		/* some fans don't have min register */
 	bool has_fan_div;
 
-	u8 num_temp_alarms;	/* 2 or 3 */
+	u8 num_temp_alarms;	/* 2, 3, or 6 */
+	u8 num_temp_beeps;	/* 2, 3, or 6 */
 	u8 temp_fixed_num;	/* 3 or 6 */
 	u8 temp_type[NUM_TEMP_FIXED];
 	s8 temp_offset[NUM_TEMP_FIXED];
-	s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
-				* 3=temp_crit */
+	s16 temp[5][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+				* 3=temp_crit, 4=temp_lcrit */
 	u64 alarms;
+	u64 beeps;
 
 	u8 pwm_num;	/* number of pwm */
-	u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */
-	enum pwm_enable pwm_enable[5];
+	u8 pwm_mode[NUM_FAN];	/* 1->DC variable voltage,
+				 * 0->PWM variable duty cycle
+				 */
+	enum pwm_enable pwm_enable[NUM_FAN];
 			/* 0->off
 			 * 1->manual
 			 * 2->thermal cruise mode (also called SmartFan I)
@@ -643,35 +830,37 @@
 			 * 4->SmartFan III
 			 * 5->enhanced variable thermal cruise (SmartFan IV)
 			 */
-	u8 pwm[7][5];	/* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
-			 * [3]=pwm_max, [4]=pwm_step,
-			 * [5]=weight_duty_step, [6]=weight_duty_base
-			 */
+	u8 pwm[7][NUM_FAN];	/* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+				 * [3]=pwm_max, [4]=pwm_step,
+				 * [5]=weight_duty_step, [6]=weight_duty_base
+				 */
 
-	u8 target_temp[5];
+	u8 target_temp[NUM_FAN];
 	u8 target_temp_mask;
-	u32 target_speed[5];
-	u32 target_speed_tolerance[5];
+	u32 target_speed[NUM_FAN];
+	u32 target_speed_tolerance[NUM_FAN];
 	u8 speed_tolerance_limit;
 
-	u8 temp_tolerance[2][5];
+	u8 temp_tolerance[2][NUM_FAN];
 	u8 tolerance_mask;
 
-	u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+	u8 fan_time[3][NUM_FAN]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
 
 	/* Automatic fan speed control registers */
 	int auto_pwm_num;
-	u8 auto_pwm[5][7];
-	u8 auto_temp[5][7];
-	u8 pwm_temp_sel[5];
-	u8 pwm_weight_temp_sel[5];
-	u8 weight_temp[3][5];	/* 0->temp_step, 1->temp_step_tol,
-				 * 2->temp_base
-				 */
+	u8 auto_pwm[NUM_FAN][7];
+	u8 auto_temp[NUM_FAN][7];
+	u8 pwm_temp_sel[NUM_FAN];
+	u8 pwm_weight_temp_sel[NUM_FAN];
+	u8 weight_temp[3][NUM_FAN];	/* 0->temp_step, 1->temp_step_tol,
+					 * 2->temp_base
+					 */
 
 	u8 vid;
 	u8 vrm;
 
+	bool have_vid;
+
 	u16 have_temp;
 	u16 have_temp_fixed;
 	u16 have_in;
@@ -688,9 +877,145 @@
 	enum kinds kind;
 };
 
+struct sensor_device_template {
+	struct device_attribute dev_attr;
+	union {
+		struct {
+			u8 nr;
+			u8 index;
+		} s;
+		int index;
+	} u;
+	bool s2;	/* true if both index and nr are used */
+};
+
+struct sensor_device_attr_u {
+	union {
+		struct sensor_device_attribute a1;
+		struct sensor_device_attribute_2 a2;
+	} u;
+	char name[32];
+};
+
+#define __TEMPLATE_ATTR(_template, _mode, _show, _store) {	\
+	.attr = {.name = _template, .mode = _mode },		\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+#define SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store, _index)	\
+	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
+	  .u.index = _index,						\
+	  .s2 = false }
+
+#define SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
+				 _nr, _index)				\
+	{ .dev_attr = __TEMPLATE_ATTR(_template, _mode, _show, _store),	\
+	  .u.s.index = _index,						\
+	  .u.s.nr = _nr,						\
+	  .s2 = true }
+
+#define SENSOR_TEMPLATE(_name, _template, _mode, _show, _store, _index)	\
+static struct sensor_device_template sensor_dev_template_##_name	\
+	= SENSOR_DEVICE_TEMPLATE(_template, _mode, _show, _store,	\
+				 _index)
+
+#define SENSOR_TEMPLATE_2(_name, _template, _mode, _show, _store,	\
+			  _nr, _index)					\
+static struct sensor_device_template sensor_dev_template_##_name	\
+	= SENSOR_DEVICE_TEMPLATE_2(_template, _mode, _show, _store,	\
+				 _nr, _index)
+
+struct sensor_template_group {
+	struct sensor_device_template **templates;
+	umode_t (*is_visible)(struct kobject *, struct attribute *, int);
+	int base;
+};
+
+static struct attribute_group *
+nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+			  int repeat)
+{
+	struct attribute_group *group;
+	struct sensor_device_attr_u *su;
+	struct sensor_device_attribute *a;
+	struct sensor_device_attribute_2 *a2;
+	struct attribute **attrs;
+	struct sensor_device_template **t;
+	int err, i, j, count;
+
+	if (repeat <= 0)
+		return ERR_PTR(-EINVAL);
+
+	t = tg->templates;
+	for (count = 0; *t; t++, count++)
+		;
+
+	if (count == 0)
+		return ERR_PTR(-EINVAL);
+
+	group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
+	if (group == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	attrs = devm_kzalloc(dev, sizeof(*attrs) * (repeat * count + 1),
+			     GFP_KERNEL);
+	if (attrs == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	su = devm_kzalloc(dev, sizeof(*su) * repeat * count,
+			       GFP_KERNEL);
+	if (su == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	group->attrs = attrs;
+	group->is_visible = tg->is_visible;
+
+	for (i = 0; i < repeat; i++) {
+		t = tg->templates;
+		for (j = 0; *t != NULL; j++) {
+			snprintf(su->name, sizeof(su->name),
+				 (*t)->dev_attr.attr.name, tg->base + i);
+			if ((*t)->s2) {
+				a2 = &su->u.a2;
+				a2->dev_attr.attr.name = su->name;
+				a2->nr = (*t)->u.s.nr + i;
+				a2->index = (*t)->u.s.index;
+				a2->dev_attr.attr.mode =
+				  (*t)->dev_attr.attr.mode;
+				a2->dev_attr.show = (*t)->dev_attr.show;
+				a2->dev_attr.store = (*t)->dev_attr.store;
+				*attrs = &a2->dev_attr.attr;
+			} else {
+				a = &su->u.a1;
+				a->dev_attr.attr.name = su->name;
+				a->index = (*t)->u.index + i;
+				a->dev_attr.attr.mode =
+				  (*t)->dev_attr.attr.mode;
+				a->dev_attr.show = (*t)->dev_attr.show;
+				a->dev_attr.store = (*t)->dev_attr.store;
+				*attrs = &a->dev_attr.attr;
+			}
+			attrs++;
+			su++;
+			t++;
+		}
+	}
+
+	err = sysfs_create_group(&dev->kobj, group);
+	if (err)
+		return ERR_PTR(-ENOMEM);
+
+	return group;
+}
+
 static bool is_word_sized(struct nct6775_data *data, u16 reg)
 {
 	switch (data->kind) {
+	case nct6106:
+		return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
+		  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
+		  reg == 0x111 || reg == 0x121 || reg == 0x131;
 	case nct6775:
 		return (((reg & 0xff00) == 0x100 ||
 		    (reg & 0xff00) == 0x200) &&
@@ -714,8 +1039,9 @@
 		  ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
 		  reg == 0x73 || reg == 0x75 || reg == 0x77;
 	case nct6779:
+	case nct6791:
 		return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
-		  ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) ||
+		  ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
 		  reg == 0x402 ||
 		  reg == 0x63a || reg == 0x63c || reg == 0x63e ||
 		  reg == 0x640 || reg == 0x642 ||
@@ -1056,15 +1382,17 @@
 		case nct6776:
 			data->auto_pwm[i][data->auto_pwm_num] = 0xff;
 			break;
+		case nct6106:
 		case nct6779:
+		case nct6791:
 			reg = nct6775_read_value(data,
-					NCT6779_REG_CRITICAL_PWM_ENABLE[i]);
-			if (reg & 1)
-				data->auto_pwm[i][data->auto_pwm_num] =
-				  nct6775_read_value(data,
-					NCT6779_REG_CRITICAL_PWM[i]);
+					data->REG_CRITICAL_PWM_ENABLE[i]);
+			if (reg & data->CRITICAL_PWM_ENABLE_MASK)
+				reg = nct6775_read_value(data,
+					data->REG_CRITICAL_PWM[i]);
 			else
-				data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+				reg = 0xff;
+			data->auto_pwm[i][data->auto_pwm_num] = reg;
 			break;
 		}
 	}
@@ -1110,7 +1438,8 @@
 				data->fan_min[i] = nct6775_read_value(data,
 					   data->REG_FAN_MIN[i]);
 			data->fan_pulses[i] =
-			  nct6775_read_value(data, data->REG_FAN_PULSES[i]);
+			  (nct6775_read_value(data, data->REG_FAN_PULSES[i])
+				>> data->FAN_PULSE_SHIFT[i]) & 0x03;
 
 			nct6775_select_fan_div(dev, data, i, reg);
 		}
@@ -1143,6 +1472,15 @@
 			data->alarms |= ((u64)alarm) << (i << 3);
 		}
 
+		data->beeps = 0;
+		for (i = 0; i < NUM_REG_BEEP; i++) {
+			u8 beep;
+			if (!data->REG_BEEP[i])
+				continue;
+			beep = nct6775_read_value(data, data->REG_BEEP[i]);
+			data->beeps |= ((u64)beep) << (i << 3);
+		}
+
 		data->last_updated = jiffies;
 		data->valid = true;
 	}
@@ -1230,224 +1568,138 @@
 	return sprintf(buf, "%u\n", alarm);
 }
 
-static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
-static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
-static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
-static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0);
-static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0);
-static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0);
-static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0);
-static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0);
-static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0);
-static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0);
-static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0);
-static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0);
-static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0);
-static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0);
-static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0);
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6775_data *data = nct6775_update_device(dev);
+	int nr = data->BEEP_BITS[sattr->index];
 
-static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
-static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
-static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
-static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
-static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
-static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
-static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
-static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
-static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
-static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
-static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
-static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
+	return sprintf(buf, "%u\n",
+		       (unsigned int)((data->beeps >> nr) & 0x01));
+}
 
-static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 0, 1);
-static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 1, 1);
-static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 2, 1);
-static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 3, 1);
-static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 4, 1);
-static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 5, 1);
-static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 6, 1);
-static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 7, 1);
-static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 8, 1);
-static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 9, 1);
-static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 10, 1);
-static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 11, 1);
-static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 12, 1);
-static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 13, 1);
-static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 14, 1);
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
+	   size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int nr = data->BEEP_BITS[sattr->index];
+	int regindex = nr >> 3;
+	unsigned long val;
 
-static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 0, 2);
-static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 1, 2);
-static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 2, 2);
-static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 3, 2);
-static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 4, 2);
-static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 5, 2);
-static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 6, 2);
-static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 7, 2);
-static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 8, 2);
-static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 9, 2);
-static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 10, 2);
-static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 11, 2);
-static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 12, 2);
-static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 13, 2);
-static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg,
-			    store_in_reg, 14, 2);
+	int err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > 1)
+		return -EINVAL;
 
-static struct attribute *nct6775_attributes_in[15][5] = {
-	{
-		&sensor_dev_attr_in0_input.dev_attr.attr,
-		&sensor_dev_attr_in0_min.dev_attr.attr,
-		&sensor_dev_attr_in0_max.dev_attr.attr,
-		&sensor_dev_attr_in0_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in1_input.dev_attr.attr,
-		&sensor_dev_attr_in1_min.dev_attr.attr,
-		&sensor_dev_attr_in1_max.dev_attr.attr,
-		&sensor_dev_attr_in1_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in2_input.dev_attr.attr,
-		&sensor_dev_attr_in2_min.dev_attr.attr,
-		&sensor_dev_attr_in2_max.dev_attr.attr,
-		&sensor_dev_attr_in2_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in3_input.dev_attr.attr,
-		&sensor_dev_attr_in3_min.dev_attr.attr,
-		&sensor_dev_attr_in3_max.dev_attr.attr,
-		&sensor_dev_attr_in3_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in4_input.dev_attr.attr,
-		&sensor_dev_attr_in4_min.dev_attr.attr,
-		&sensor_dev_attr_in4_max.dev_attr.attr,
-		&sensor_dev_attr_in4_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in5_input.dev_attr.attr,
-		&sensor_dev_attr_in5_min.dev_attr.attr,
-		&sensor_dev_attr_in5_max.dev_attr.attr,
-		&sensor_dev_attr_in5_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in6_input.dev_attr.attr,
-		&sensor_dev_attr_in6_min.dev_attr.attr,
-		&sensor_dev_attr_in6_max.dev_attr.attr,
-		&sensor_dev_attr_in6_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in7_input.dev_attr.attr,
-		&sensor_dev_attr_in7_min.dev_attr.attr,
-		&sensor_dev_attr_in7_max.dev_attr.attr,
-		&sensor_dev_attr_in7_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in8_input.dev_attr.attr,
-		&sensor_dev_attr_in8_min.dev_attr.attr,
-		&sensor_dev_attr_in8_max.dev_attr.attr,
-		&sensor_dev_attr_in8_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in9_input.dev_attr.attr,
-		&sensor_dev_attr_in9_min.dev_attr.attr,
-		&sensor_dev_attr_in9_max.dev_attr.attr,
-		&sensor_dev_attr_in9_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in10_input.dev_attr.attr,
-		&sensor_dev_attr_in10_min.dev_attr.attr,
-		&sensor_dev_attr_in10_max.dev_attr.attr,
-		&sensor_dev_attr_in10_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in11_input.dev_attr.attr,
-		&sensor_dev_attr_in11_min.dev_attr.attr,
-		&sensor_dev_attr_in11_max.dev_attr.attr,
-		&sensor_dev_attr_in11_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in12_input.dev_attr.attr,
-		&sensor_dev_attr_in12_min.dev_attr.attr,
-		&sensor_dev_attr_in12_max.dev_attr.attr,
-		&sensor_dev_attr_in12_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in13_input.dev_attr.attr,
-		&sensor_dev_attr_in13_min.dev_attr.attr,
-		&sensor_dev_attr_in13_max.dev_attr.attr,
-		&sensor_dev_attr_in13_alarm.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_in14_input.dev_attr.attr,
-		&sensor_dev_attr_in14_min.dev_attr.attr,
-		&sensor_dev_attr_in14_max.dev_attr.attr,
-		&sensor_dev_attr_in14_alarm.dev_attr.attr,
-		NULL
-	},
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->beeps |= (1ULL << nr);
+	else
+		data->beeps &= ~(1ULL << nr);
+	nct6775_write_value(data, data->REG_BEEP[regindex],
+			    (data->beeps >> (regindex << 3)) & 0xff);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct nct6775_data *data = nct6775_update_device(dev);
+	unsigned int beep = 0;
+	int nr;
+
+	/*
+	 * For temperatures, there is no fixed mapping from registers to beep
+	 * enable bits. Beep enable bits are determined by the temperature
+	 * source mapping.
+	 */
+	nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+	if (nr >= 0) {
+		int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+		beep = (data->beeps >> bit) & 0x01;
+	}
+	return sprintf(buf, "%u\n", beep);
+}
+
+static ssize_t
+store_temp_beep(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int nr, bit, regindex;
+	unsigned long val;
+
+	int err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+	if (val > 1)
+		return -EINVAL;
+
+	nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
+	if (nr < 0)
+		return -ENODEV;
+
+	bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+	regindex = bit >> 3;
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->beeps |= (1ULL << bit);
+	else
+		data->beeps &= ~(1ULL << bit);
+	nct6775_write_value(data, data->REG_BEEP[regindex],
+			    (data->beeps >> (regindex << 3)) & 0xff);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static umode_t nct6775_in_is_visible(struct kobject *kobj,
+				     struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int in = index / 5;	/* voltage index */
+
+	if (!(data->have_in & (1 << in)))
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(in_input, "in%d_input", S_IRUGO, show_in_reg, NULL, 0, 0);
+SENSOR_TEMPLATE(in_alarm, "in%d_alarm", S_IRUGO, show_alarm, NULL, 0);
+SENSOR_TEMPLATE(in_beep, "in%d_beep", S_IWUSR | S_IRUGO, show_beep, store_beep,
+		0);
+SENSOR_TEMPLATE_2(in_min, "in%d_min", S_IWUSR | S_IRUGO, show_in_reg,
+		  store_in_reg, 0, 1);
+SENSOR_TEMPLATE_2(in_max, "in%d_max", S_IWUSR | S_IRUGO, show_in_reg,
+		  store_in_reg, 0, 2);
+
+/*
+ * nct6775_in_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_in_template[] = {
+	&sensor_dev_template_in_input,
+	&sensor_dev_template_in_alarm,
+	&sensor_dev_template_in_beep,
+	&sensor_dev_template_in_min,
+	&sensor_dev_template_in_max,
+	NULL
 };
 
-static const struct attribute_group nct6775_group_in[15] = {
-	{ .attrs = nct6775_attributes_in[0] },
-	{ .attrs = nct6775_attributes_in[1] },
-	{ .attrs = nct6775_attributes_in[2] },
-	{ .attrs = nct6775_attributes_in[3] },
-	{ .attrs = nct6775_attributes_in[4] },
-	{ .attrs = nct6775_attributes_in[5] },
-	{ .attrs = nct6775_attributes_in[6] },
-	{ .attrs = nct6775_attributes_in[7] },
-	{ .attrs = nct6775_attributes_in[8] },
-	{ .attrs = nct6775_attributes_in[9] },
-	{ .attrs = nct6775_attributes_in[10] },
-	{ .attrs = nct6775_attributes_in[11] },
-	{ .attrs = nct6775_attributes_in[12] },
-	{ .attrs = nct6775_attributes_in[13] },
-	{ .attrs = nct6775_attributes_in[14] },
+static struct sensor_template_group nct6775_in_template_group = {
+	.templates = nct6775_attributes_in_template,
+	.is_visible = nct6775_in_is_visible,
 };
 
 static ssize_t
@@ -1592,6 +1844,7 @@
 	int nr = sattr->index;
 	unsigned long val;
 	int err;
+	u8 reg;
 
 	err = kstrtoul(buf, 10, &val);
 	if (err < 0)
@@ -1602,60 +1855,68 @@
 
 	mutex_lock(&data->update_lock);
 	data->fan_pulses[nr] = val & 3;
-	nct6775_write_value(data, data->REG_FAN_PULSES[nr], val & 3);
+	reg = nct6775_read_value(data, data->REG_FAN_PULSES[nr]);
+	reg &= ~(0x03 << data->FAN_PULSE_SHIFT[nr]);
+	reg |= (val & 3) << data->FAN_PULSE_SHIFT[nr];
+	nct6775_write_value(data, data->REG_FAN_PULSES[nr], reg);
 	mutex_unlock(&data->update_lock);
 
 	return count;
 }
 
-static struct sensor_device_attribute sda_fan_input[] = {
-	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
-	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
-	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
-	SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
-	SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+static umode_t nct6775_fan_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int fan = index / 6;	/* fan index */
+	int nr = index % 6;	/* attribute index */
+
+	if (!(data->has_fan & (1 << fan)))
+		return 0;
+
+	if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
+		return 0;
+	if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
+		return 0;
+	if (nr == 4 && !(data->has_fan_min & (1 << fan)))
+		return 0;
+	if (nr == 5 && data->kind != nct6775)
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE(fan_input, "fan%d_input", S_IRUGO, show_fan, NULL, 0);
+SENSOR_TEMPLATE(fan_alarm, "fan%d_alarm", S_IRUGO, show_alarm, NULL,
+		FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_beep, "fan%d_beep", S_IWUSR | S_IRUGO, show_beep,
+		store_beep, FAN_ALARM_BASE);
+SENSOR_TEMPLATE(fan_pulses, "fan%d_pulses", S_IWUSR | S_IRUGO, show_fan_pulses,
+		store_fan_pulses, 0);
+SENSOR_TEMPLATE(fan_min, "fan%d_min", S_IWUSR | S_IRUGO, show_fan_min,
+		store_fan_min, 0);
+SENSOR_TEMPLATE(fan_div, "fan%d_div", S_IRUGO, show_fan_div, NULL, 0);
+
+/*
+ * nct6775_fan_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_fan_template[] = {
+	&sensor_dev_template_fan_input,
+	&sensor_dev_template_fan_alarm,	/* 1 */
+	&sensor_dev_template_fan_beep,	/* 2 */
+	&sensor_dev_template_fan_pulses,
+	&sensor_dev_template_fan_min,	/* 4 */
+	&sensor_dev_template_fan_div,	/* 5 */
+	NULL
 };
 
-static struct sensor_device_attribute sda_fan_alarm[] = {
-	SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE),
-	SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
-	SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
-	SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
-	SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 4),
-};
-
-static struct sensor_device_attribute sda_fan_min[] = {
-	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
-		    store_fan_min, 0),
-	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
-		    store_fan_min, 1),
-	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
-		    store_fan_min, 2),
-	SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
-		    store_fan_min, 3),
-	SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
-		    store_fan_min, 4),
-};
-
-static struct sensor_device_attribute sda_fan_pulses[] = {
-	SENSOR_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-		    store_fan_pulses, 0),
-	SENSOR_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-		    store_fan_pulses, 1),
-	SENSOR_ATTR(fan3_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-		    store_fan_pulses, 2),
-	SENSOR_ATTR(fan4_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-		    store_fan_pulses, 3),
-	SENSOR_ATTR(fan5_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
-		    store_fan_pulses, 4),
-};
-
-static struct sensor_device_attribute sda_fan_div[] = {
-	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
-	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
-	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
-	SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
-	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+static struct sensor_template_group nct6775_fan_template_group = {
+	.templates = nct6775_attributes_fan_template,
+	.is_visible = nct6775_fan_is_visible,
+	.base = 1,
 };
 
 static ssize_t
@@ -1752,7 +2013,7 @@
 	int nr = sattr->index;
 	unsigned long val;
 	int err;
-	u8 vbat, diode, bit;
+	u8 vbat, diode, vbit, dbit;
 
 	err = kstrtoul(buf, 10, &val);
 	if (err < 0)
@@ -1764,16 +2025,17 @@
 	mutex_lock(&data->update_lock);
 
 	data->temp_type[nr] = val;
-	vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr);
-	diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr);
-	bit = 0x02 << nr;
+	vbit = 0x02 << nr;
+	dbit = data->DIODE_MASK << nr;
+	vbat = nct6775_read_value(data, data->REG_VBAT) & ~vbit;
+	diode = nct6775_read_value(data, data->REG_DIODE) & ~dbit;
 	switch (val) {
 	case 1:	/* CPU diode (diode, current mode) */
-		vbat |= bit;
-		diode |= bit;
+		vbat |= vbit;
+		diode |= dbit;
 		break;
 	case 3: /* diode, voltage mode */
-		vbat |= bit;
+		vbat |= dbit;
 		break;
 	case 4:	/* thermistor */
 		break;
@@ -1785,142 +2047,83 @@
 	return count;
 }
 
-static struct sensor_device_attribute_2 sda_temp_input[] = {
-	SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
-	SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
-	SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0),
-	SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
-	SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
-	SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
-	SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
-	SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
-	SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
-	SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
+static umode_t nct6775_temp_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int temp = index / 10;	/* temp index */
+	int nr = index % 10;	/* attribute index */
+
+	if (!(data->have_temp & (1 << temp)))
+		return 0;
+
+	if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
+		return 0;				/* alarm */
+
+	if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
+		return 0;				/* beep */
+
+	if (nr == 4 && !data->reg_temp[1][temp])	/* max */
+		return 0;
+
+	if (nr == 5 && !data->reg_temp[2][temp])	/* max_hyst */
+		return 0;
+
+	if (nr == 6 && !data->reg_temp[3][temp])	/* crit */
+		return 0;
+
+	if (nr == 7 && !data->reg_temp[4][temp])	/* lcrit */
+		return 0;
+
+	/* offset and type only apply to fixed sensors */
+	if (nr > 7 && !(data->have_temp_fixed & (1 << temp)))
+		return 0;
+
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(temp_input, "temp%d_input", S_IRUGO, show_temp, NULL, 0, 0);
+SENSOR_TEMPLATE(temp_label, "temp%d_label", S_IRUGO, show_temp_label, NULL, 0);
+SENSOR_TEMPLATE_2(temp_max, "temp%d_max", S_IRUGO | S_IWUSR, show_temp,
+		  store_temp, 0, 1);
+SENSOR_TEMPLATE_2(temp_max_hyst, "temp%d_max_hyst", S_IRUGO | S_IWUSR,
+		  show_temp, store_temp, 0, 2);
+SENSOR_TEMPLATE_2(temp_crit, "temp%d_crit", S_IRUGO | S_IWUSR, show_temp,
+		  store_temp, 0, 3);
+SENSOR_TEMPLATE_2(temp_lcrit, "temp%d_lcrit", S_IRUGO | S_IWUSR, show_temp,
+		  store_temp, 0, 4);
+SENSOR_TEMPLATE(temp_offset, "temp%d_offset", S_IRUGO | S_IWUSR,
+		show_temp_offset, store_temp_offset, 0);
+SENSOR_TEMPLATE(temp_type, "temp%d_type", S_IRUGO | S_IWUSR, show_temp_type,
+		store_temp_type, 0);
+SENSOR_TEMPLATE(temp_alarm, "temp%d_alarm", S_IRUGO, show_temp_alarm, NULL, 0);
+SENSOR_TEMPLATE(temp_beep, "temp%d_beep", S_IRUGO | S_IWUSR, show_temp_beep,
+		store_temp_beep, 0);
+
+/*
+ * nct6775_temp_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct sensor_device_template *nct6775_attributes_temp_template[] = {
+	&sensor_dev_template_temp_input,
+	&sensor_dev_template_temp_label,
+	&sensor_dev_template_temp_alarm,	/* 2 */
+	&sensor_dev_template_temp_beep,		/* 3 */
+	&sensor_dev_template_temp_max,		/* 4 */
+	&sensor_dev_template_temp_max_hyst,	/* 5 */
+	&sensor_dev_template_temp_crit,		/* 6 */
+	&sensor_dev_template_temp_lcrit,	/* 7 */
+	&sensor_dev_template_temp_offset,	/* 8 */
+	&sensor_dev_template_temp_type,		/* 9 */
+	NULL
 };
 
-static struct sensor_device_attribute sda_temp_label[] = {
-	SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
-	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
-	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
-	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
-	SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
-	SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
-	SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
-	SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
-	SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
-	SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
-};
-
-static struct sensor_device_attribute_2 sda_temp_max[] = {
-	SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      0, 1),
-	SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      1, 1),
-	SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      2, 1),
-	SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      3, 1),
-	SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      4, 1),
-	SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      5, 1),
-	SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      6, 1),
-	SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      7, 1),
-	SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      8, 1),
-	SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      9, 1),
-};
-
-static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
-	SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      0, 2),
-	SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      1, 2),
-	SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      2, 2),
-	SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      3, 2),
-	SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      4, 2),
-	SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      5, 2),
-	SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      6, 2),
-	SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      7, 2),
-	SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      8, 2),
-	SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      9, 2),
-};
-
-static struct sensor_device_attribute_2 sda_temp_crit[] = {
-	SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      0, 3),
-	SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      1, 3),
-	SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      2, 3),
-	SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      3, 3),
-	SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      4, 3),
-	SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      5, 3),
-	SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      6, 3),
-	SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      7, 3),
-	SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      8, 3),
-	SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
-		      9, 3),
-};
-
-static struct sensor_device_attribute sda_temp_offset[] = {
-	SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-		    store_temp_offset, 0),
-	SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-		    store_temp_offset, 1),
-	SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-		    store_temp_offset, 2),
-	SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-		    store_temp_offset, 3),
-	SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-		    store_temp_offset, 4),
-	SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
-		    store_temp_offset, 5),
-};
-
-static struct sensor_device_attribute sda_temp_type[] = {
-	SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
-		    store_temp_type, 0),
-	SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
-		    store_temp_type, 1),
-	SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
-		    store_temp_type, 2),
-	SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
-		    store_temp_type, 3),
-	SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
-		    store_temp_type, 4),
-	SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
-		    store_temp_type, 5),
-};
-
-static struct sensor_device_attribute sda_temp_alarm[] = {
-	SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
-	SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
-	SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
-	SENSOR_ATTR(temp4_alarm, S_IRUGO, show_temp_alarm, NULL, 3),
-	SENSOR_ATTR(temp5_alarm, S_IRUGO, show_temp_alarm, NULL, 4),
-	SENSOR_ATTR(temp6_alarm, S_IRUGO, show_temp_alarm, NULL, 5),
-	SENSOR_ATTR(temp7_alarm, S_IRUGO, show_temp_alarm, NULL, 6),
-	SENSOR_ATTR(temp8_alarm, S_IRUGO, show_temp_alarm, NULL, 7),
-	SENSOR_ATTR(temp9_alarm, S_IRUGO, show_temp_alarm, NULL, 8),
-	SENSOR_ATTR(temp10_alarm, S_IRUGO, show_temp_alarm, NULL, 9),
+static struct sensor_template_group nct6775_temp_template_group = {
+	.templates = nct6775_attributes_temp_template,
+	.is_visible = nct6775_temp_is_visible,
+	.base = 1,
 };
 
 static ssize_t
@@ -2422,77 +2625,19 @@
 	return count;
 }
 
-static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0);
-
-static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-			  store_pwm_mode, 0);
-static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-			  store_pwm_mode, 1);
-static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-			  store_pwm_mode, 2);
-static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-			  store_pwm_mode, 3);
-static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
-			  store_pwm_mode, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-			  store_pwm_enable, 0);
-static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-			  store_pwm_enable, 1);
-static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-			  store_pwm_enable, 2);
-static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-			  store_pwm_enable, 3);
-static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
-			  store_pwm_enable, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_temp_sel, store_pwm_temp_sel, 0);
-static SENSOR_DEVICE_ATTR(pwm2_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_temp_sel, store_pwm_temp_sel, 1);
-static SENSOR_DEVICE_ATTR(pwm3_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_temp_sel, store_pwm_temp_sel, 2);
-static SENSOR_DEVICE_ATTR(pwm4_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_temp_sel, store_pwm_temp_sel, 3);
-static SENSOR_DEVICE_ATTR(pwm5_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_temp_sel, store_pwm_temp_sel, 4);
-
-static SENSOR_DEVICE_ATTR(pwm1_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-			  store_target_temp, 0);
-static SENSOR_DEVICE_ATTR(pwm2_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-			  store_target_temp, 1);
-static SENSOR_DEVICE_ATTR(pwm3_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-			  store_target_temp, 2);
-static SENSOR_DEVICE_ATTR(pwm4_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-			  store_target_temp, 3);
-static SENSOR_DEVICE_ATTR(pwm5_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
-			  store_target_temp, 4);
-
-static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, show_target_speed,
-			  store_target_speed, 0);
-static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, show_target_speed,
-			  store_target_speed, 1);
-static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, show_target_speed,
-			  store_target_speed, 2);
-static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, show_target_speed,
-			  store_target_speed, 3);
-static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, show_target_speed,
-			  store_target_speed, 4);
-
-static SENSOR_DEVICE_ATTR(fan1_tolerance, S_IWUSR | S_IRUGO,
-			    show_speed_tolerance, store_speed_tolerance, 0);
-static SENSOR_DEVICE_ATTR(fan2_tolerance, S_IWUSR | S_IRUGO,
-			    show_speed_tolerance, store_speed_tolerance, 1);
-static SENSOR_DEVICE_ATTR(fan3_tolerance, S_IWUSR | S_IRUGO,
-			    show_speed_tolerance, store_speed_tolerance, 2);
-static SENSOR_DEVICE_ATTR(fan4_tolerance, S_IWUSR | S_IRUGO,
-			    show_speed_tolerance, store_speed_tolerance, 3);
-static SENSOR_DEVICE_ATTR(fan5_tolerance, S_IWUSR | S_IRUGO,
-			    show_speed_tolerance, store_speed_tolerance, 4);
+SENSOR_TEMPLATE_2(pwm, "pwm%d", S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+SENSOR_TEMPLATE(pwm_mode, "pwm%d_mode", S_IWUSR | S_IRUGO, show_pwm_mode,
+		store_pwm_mode, 0);
+SENSOR_TEMPLATE(pwm_enable, "pwm%d_enable", S_IWUSR | S_IRUGO, show_pwm_enable,
+		store_pwm_enable, 0);
+SENSOR_TEMPLATE(pwm_temp_sel, "pwm%d_temp_sel", S_IWUSR | S_IRUGO,
+		show_pwm_temp_sel, store_pwm_temp_sel, 0);
+SENSOR_TEMPLATE(pwm_target_temp, "pwm%d_target_temp", S_IWUSR | S_IRUGO,
+		show_target_temp, store_target_temp, 0);
+SENSOR_TEMPLATE(fan_target, "fan%d_target", S_IWUSR | S_IRUGO,
+		show_target_speed, store_target_speed, 0);
+SENSOR_TEMPLATE(fan_tolerance, "fan%d_tolerance", S_IWUSR | S_IRUGO,
+		show_speed_tolerance, store_speed_tolerance, 0);
 
 /* Smart Fan registers */
 
@@ -2531,79 +2676,18 @@
 	return count;
 }
 
-static SENSOR_DEVICE_ATTR(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-			    0);
-static SENSOR_DEVICE_ATTR(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-			    1);
-static SENSOR_DEVICE_ATTR(pwm3_weight_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-			    2);
-static SENSOR_DEVICE_ATTR(pwm4_weight_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-			    3);
-static SENSOR_DEVICE_ATTR(pwm5_weight_temp_sel, S_IWUSR | S_IRUGO,
-			    show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
-			    4);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_tol, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_base, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_base, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_base, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_base, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_base, S_IWUSR | S_IRUGO,
-			    show_weight_temp, store_weight_temp, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_weight_duty_step, S_IWUSR | S_IRUGO,
-			    show_pwm, store_pwm, 0, 5);
-static SENSOR_DEVICE_ATTR_2(pwm2_weight_duty_step, S_IWUSR | S_IRUGO,
-			    show_pwm, store_pwm, 1, 5);
-static SENSOR_DEVICE_ATTR_2(pwm3_weight_duty_step, S_IWUSR | S_IRUGO,
-			    show_pwm, store_pwm, 2, 5);
-static SENSOR_DEVICE_ATTR_2(pwm4_weight_duty_step, S_IWUSR | S_IRUGO,
-			    show_pwm, store_pwm, 3, 5);
-static SENSOR_DEVICE_ATTR_2(pwm5_weight_duty_step, S_IWUSR | S_IRUGO,
-			    show_pwm, store_pwm, 4, 5);
-
-/* duty_base is not supported on all chips */
-static struct sensor_device_attribute_2 sda_weight_duty_base[] = {
-	SENSOR_ATTR_2(pwm1_weight_duty_base, S_IWUSR | S_IRUGO,
-		      show_pwm, store_pwm, 0, 6),
-	SENSOR_ATTR_2(pwm2_weight_duty_base, S_IWUSR | S_IRUGO,
-		      show_pwm, store_pwm, 1, 6),
-	SENSOR_ATTR_2(pwm3_weight_duty_base, S_IWUSR | S_IRUGO,
-		      show_pwm, store_pwm, 2, 6),
-	SENSOR_ATTR_2(pwm4_weight_duty_base, S_IWUSR | S_IRUGO,
-		      show_pwm, store_pwm, 3, 6),
-	SENSOR_ATTR_2(pwm5_weight_duty_base, S_IWUSR | S_IRUGO,
-		      show_pwm, store_pwm, 4, 6),
-};
+SENSOR_TEMPLATE(pwm_weight_temp_sel, "pwm%d_weight_temp_sel", S_IWUSR | S_IRUGO,
+		  show_pwm_weight_temp_sel, store_pwm_weight_temp_sel, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step, "pwm%d_weight_temp_step",
+		  S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 0);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_tol, "pwm%d_weight_temp_step_tol",
+		  S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 1);
+SENSOR_TEMPLATE_2(pwm_weight_temp_step_base, "pwm%d_weight_temp_step_base",
+		  S_IWUSR | S_IRUGO, show_weight_temp, store_weight_temp, 0, 2);
+SENSOR_TEMPLATE_2(pwm_weight_duty_step, "pwm%d_weight_duty_step",
+		  S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_weight_duty_base, "pwm%d_weight_duty_base",
+		  S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 6);
 
 static ssize_t
 show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
@@ -2651,227 +2735,6 @@
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
-			    store_fan_time, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_step_down_time, S_IWUSR | S_IRUGO,
-			    show_fan_time, store_fan_time, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_step_down_time, S_IWUSR | S_IRUGO,
-			    show_fan_time, store_fan_time, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_step_down_time, S_IWUSR | S_IRUGO,
-			    show_fan_time, store_fan_time, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_step_down_time, S_IWUSR | S_IRUGO,
-			    show_fan_time, store_fan_time, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_step_down_time, S_IWUSR | S_IRUGO,
-			    show_fan_time, store_fan_time, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_start, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_start, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_start, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_start, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_start, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 4, 1);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_floor, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 0, 2);
-static SENSOR_DEVICE_ATTR_2(pwm2_floor, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 1, 2);
-static SENSOR_DEVICE_ATTR_2(pwm3_floor, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 2, 2);
-static SENSOR_DEVICE_ATTR_2(pwm4_floor, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 3, 2);
-static SENSOR_DEVICE_ATTR_2(pwm5_floor, S_IWUSR | S_IRUGO, show_pwm,
-			    store_pwm, 4, 2);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 0, 0);
-static SENSOR_DEVICE_ATTR_2(pwm2_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 1, 0);
-static SENSOR_DEVICE_ATTR_2(pwm3_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 2, 0);
-static SENSOR_DEVICE_ATTR_2(pwm4_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 3, 0);
-static SENSOR_DEVICE_ATTR_2(pwm5_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 4, 0);
-
-static SENSOR_DEVICE_ATTR_2(pwm1_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 0, 1);
-static SENSOR_DEVICE_ATTR_2(pwm2_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 1, 1);
-static SENSOR_DEVICE_ATTR_2(pwm3_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 2, 1);
-static SENSOR_DEVICE_ATTR_2(pwm4_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 3, 1);
-static SENSOR_DEVICE_ATTR_2(pwm5_crit_temp_tolerance, S_IWUSR | S_IRUGO,
-			    show_temp_tolerance, store_temp_tolerance, 4, 1);
-
-/* pwm_max is not supported on all chips */
-static struct sensor_device_attribute_2 sda_pwm_max[] = {
-	SENSOR_ATTR_2(pwm1_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-		      0, 3),
-	SENSOR_ATTR_2(pwm2_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-		      1, 3),
-	SENSOR_ATTR_2(pwm3_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-		      2, 3),
-	SENSOR_ATTR_2(pwm4_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-		      3, 3),
-	SENSOR_ATTR_2(pwm5_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
-		      4, 3),
-};
-
-/* pwm_step is not supported on all chips */
-static struct sensor_device_attribute_2 sda_pwm_step[] = {
-	SENSOR_ATTR_2(pwm1_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 4),
-	SENSOR_ATTR_2(pwm2_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 4),
-	SENSOR_ATTR_2(pwm3_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 4),
-	SENSOR_ATTR_2(pwm4_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 4),
-	SENSOR_ATTR_2(pwm5_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 4),
-};
-
-static struct attribute *nct6775_attributes_pwm[5][20] = {
-	{
-		&sensor_dev_attr_pwm1.dev_attr.attr,
-		&sensor_dev_attr_pwm1_mode.dev_attr.attr,
-		&sensor_dev_attr_pwm1_enable.dev_attr.attr,
-		&sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm1_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm1_crit_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm1_target_temp.dev_attr.attr,
-		&sensor_dev_attr_fan1_target.dev_attr.attr,
-		&sensor_dev_attr_fan1_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
-		&sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
-		&sensor_dev_attr_pwm1_step_down_time.dev_attr.attr,
-		&sensor_dev_attr_pwm1_start.dev_attr.attr,
-		&sensor_dev_attr_pwm1_floor.dev_attr.attr,
-		&sensor_dev_attr_pwm1_weight_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm1_weight_temp_step.dev_attr.attr,
-		&sensor_dev_attr_pwm1_weight_temp_step_tol.dev_attr.attr,
-		&sensor_dev_attr_pwm1_weight_temp_step_base.dev_attr.attr,
-		&sensor_dev_attr_pwm1_weight_duty_step.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_pwm2.dev_attr.attr,
-		&sensor_dev_attr_pwm2_mode.dev_attr.attr,
-		&sensor_dev_attr_pwm2_enable.dev_attr.attr,
-		&sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm2_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm2_crit_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm2_target_temp.dev_attr.attr,
-		&sensor_dev_attr_fan2_target.dev_attr.attr,
-		&sensor_dev_attr_fan2_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
-		&sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
-		&sensor_dev_attr_pwm2_step_down_time.dev_attr.attr,
-		&sensor_dev_attr_pwm2_start.dev_attr.attr,
-		&sensor_dev_attr_pwm2_floor.dev_attr.attr,
-		&sensor_dev_attr_pwm2_weight_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm2_weight_temp_step.dev_attr.attr,
-		&sensor_dev_attr_pwm2_weight_temp_step_tol.dev_attr.attr,
-		&sensor_dev_attr_pwm2_weight_temp_step_base.dev_attr.attr,
-		&sensor_dev_attr_pwm2_weight_duty_step.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_pwm3.dev_attr.attr,
-		&sensor_dev_attr_pwm3_mode.dev_attr.attr,
-		&sensor_dev_attr_pwm3_enable.dev_attr.attr,
-		&sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm3_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm3_crit_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm3_target_temp.dev_attr.attr,
-		&sensor_dev_attr_fan3_target.dev_attr.attr,
-		&sensor_dev_attr_fan3_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
-		&sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
-		&sensor_dev_attr_pwm3_step_down_time.dev_attr.attr,
-		&sensor_dev_attr_pwm3_start.dev_attr.attr,
-		&sensor_dev_attr_pwm3_floor.dev_attr.attr,
-		&sensor_dev_attr_pwm3_weight_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm3_weight_temp_step.dev_attr.attr,
-		&sensor_dev_attr_pwm3_weight_temp_step_tol.dev_attr.attr,
-		&sensor_dev_attr_pwm3_weight_temp_step_base.dev_attr.attr,
-		&sensor_dev_attr_pwm3_weight_duty_step.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_pwm4.dev_attr.attr,
-		&sensor_dev_attr_pwm4_mode.dev_attr.attr,
-		&sensor_dev_attr_pwm4_enable.dev_attr.attr,
-		&sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm4_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm4_crit_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm4_target_temp.dev_attr.attr,
-		&sensor_dev_attr_fan4_target.dev_attr.attr,
-		&sensor_dev_attr_fan4_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
-		&sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
-		&sensor_dev_attr_pwm4_step_down_time.dev_attr.attr,
-		&sensor_dev_attr_pwm4_start.dev_attr.attr,
-		&sensor_dev_attr_pwm4_floor.dev_attr.attr,
-		&sensor_dev_attr_pwm4_weight_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm4_weight_temp_step.dev_attr.attr,
-		&sensor_dev_attr_pwm4_weight_temp_step_tol.dev_attr.attr,
-		&sensor_dev_attr_pwm4_weight_temp_step_base.dev_attr.attr,
-		&sensor_dev_attr_pwm4_weight_duty_step.dev_attr.attr,
-		NULL
-	},
-	{
-		&sensor_dev_attr_pwm5.dev_attr.attr,
-		&sensor_dev_attr_pwm5_mode.dev_attr.attr,
-		&sensor_dev_attr_pwm5_enable.dev_attr.attr,
-		&sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm5_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm5_crit_temp_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm5_target_temp.dev_attr.attr,
-		&sensor_dev_attr_fan5_target.dev_attr.attr,
-		&sensor_dev_attr_fan5_tolerance.dev_attr.attr,
-		&sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
-		&sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
-		&sensor_dev_attr_pwm5_step_down_time.dev_attr.attr,
-		&sensor_dev_attr_pwm5_start.dev_attr.attr,
-		&sensor_dev_attr_pwm5_floor.dev_attr.attr,
-		&sensor_dev_attr_pwm5_weight_temp_sel.dev_attr.attr,
-		&sensor_dev_attr_pwm5_weight_temp_step.dev_attr.attr,
-		&sensor_dev_attr_pwm5_weight_temp_step_tol.dev_attr.attr,
-		&sensor_dev_attr_pwm5_weight_temp_step_base.dev_attr.attr,
-		&sensor_dev_attr_pwm5_weight_duty_step.dev_attr.attr,
-		NULL
-	},
-};
-
-static const struct attribute_group nct6775_group_pwm[5] = {
-	{ .attrs = nct6775_attributes_pwm[0] },
-	{ .attrs = nct6775_attributes_pwm[1] },
-	{ .attrs = nct6775_attributes_pwm[2] },
-	{ .attrs = nct6775_attributes_pwm[3] },
-	{ .attrs = nct6775_attributes_pwm[4] },
-};
-
 static ssize_t
 show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -2927,17 +2790,19 @@
 			break;
 		case nct6776:
 			break; /* always enabled, nothing to do */
+		case nct6106:
 		case nct6779:
-			nct6775_write_value(data, NCT6779_REG_CRITICAL_PWM[nr],
+		case nct6791:
+			nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
 					    val);
 			reg = nct6775_read_value(data,
-					NCT6779_REG_CRITICAL_PWM_ENABLE[nr]);
+					data->REG_CRITICAL_PWM_ENABLE[nr]);
 			if (val == 255)
-				reg &= ~0x01;
+				reg &= ~data->CRITICAL_PWM_ENABLE_MASK;
 			else
-				reg |= 0x01;
+				reg |= data->CRITICAL_PWM_ENABLE_MASK;
 			nct6775_write_value(data,
-					    NCT6779_REG_CRITICAL_PWM_ENABLE[nr],
+					    data->REG_CRITICAL_PWM_ENABLE[nr],
 					    reg);
 			break;
 		}
@@ -2992,155 +2857,140 @@
 	return count;
 }
 
+static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
+				      struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	int pwm = index / 36;	/* pwm index */
+	int nr = index % 36;	/* attribute index */
+
+	if (!(data->has_pwm & (1 << pwm)))
+		return 0;
+
+	if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */
+		return 0;
+	if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */
+		return 0;
+	if (nr == 21 && data->REG_PWM[6] == NULL) /* weight_duty_base */
+		return 0;
+
+	if (nr >= 22 && nr <= 35) {		/* auto point */
+		int api = (nr - 22) / 2;	/* auto point index */
+
+		if (api > data->auto_pwm_num)
+			return 0;
+	}
+	return attr->mode;
+}
+
+SENSOR_TEMPLATE_2(pwm_stop_time, "pwm%d_stop_time", S_IWUSR | S_IRUGO,
+		  show_fan_time, store_fan_time, 0, 0);
+SENSOR_TEMPLATE_2(pwm_step_up_time, "pwm%d_step_up_time", S_IWUSR | S_IRUGO,
+		  show_fan_time, store_fan_time, 0, 1);
+SENSOR_TEMPLATE_2(pwm_step_down_time, "pwm%d_step_down_time", S_IWUSR | S_IRUGO,
+		  show_fan_time, store_fan_time, 0, 2);
+SENSOR_TEMPLATE_2(pwm_start, "pwm%d_start", S_IWUSR | S_IRUGO, show_pwm,
+		  store_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_floor, "pwm%d_floor", S_IWUSR | S_IRUGO, show_pwm,
+		  store_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_temp_tolerance, "pwm%d_temp_tolerance", S_IWUSR | S_IRUGO,
+		  show_temp_tolerance, store_temp_tolerance, 0, 0);
+SENSOR_TEMPLATE_2(pwm_crit_temp_tolerance, "pwm%d_crit_temp_tolerance",
+		  S_IWUSR | S_IRUGO, show_temp_tolerance, store_temp_tolerance,
+		  0, 1);
+
+SENSOR_TEMPLATE_2(pwm_max, "pwm%d_max", S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+		  0, 3);
+
+SENSOR_TEMPLATE_2(pwm_step, "pwm%d_step", S_IWUSR | S_IRUGO, show_pwm,
+		  store_pwm, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point1_pwm, "pwm%d_auto_point1_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 0);
+SENSOR_TEMPLATE_2(pwm_auto_point1_temp, "pwm%d_auto_point1_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 0);
+
+SENSOR_TEMPLATE_2(pwm_auto_point2_pwm, "pwm%d_auto_point2_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 1);
+SENSOR_TEMPLATE_2(pwm_auto_point2_temp, "pwm%d_auto_point2_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 1);
+
+SENSOR_TEMPLATE_2(pwm_auto_point3_pwm, "pwm%d_auto_point3_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 2);
+SENSOR_TEMPLATE_2(pwm_auto_point3_temp, "pwm%d_auto_point3_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 2);
+
+SENSOR_TEMPLATE_2(pwm_auto_point4_pwm, "pwm%d_auto_point4_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 3);
+SENSOR_TEMPLATE_2(pwm_auto_point4_temp, "pwm%d_auto_point4_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 3);
+
+SENSOR_TEMPLATE_2(pwm_auto_point5_pwm, "pwm%d_auto_point5_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 4);
+SENSOR_TEMPLATE_2(pwm_auto_point5_temp, "pwm%d_auto_point5_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 4);
+
+SENSOR_TEMPLATE_2(pwm_auto_point6_pwm, "pwm%d_auto_point6_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 5);
+SENSOR_TEMPLATE_2(pwm_auto_point6_temp, "pwm%d_auto_point6_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 5);
+
+SENSOR_TEMPLATE_2(pwm_auto_point7_pwm, "pwm%d_auto_point7_pwm",
+		  S_IWUSR | S_IRUGO, show_auto_pwm, store_auto_pwm, 0, 6);
+SENSOR_TEMPLATE_2(pwm_auto_point7_temp, "pwm%d_auto_point7_temp",
+		  S_IWUSR | S_IRUGO, show_auto_temp, store_auto_temp, 0, 6);
+
 /*
- * The number of auto-point trip points is chip dependent.
- * Need to check support while generating/removing attribute files.
+ * nct6775_pwm_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
  */
-static struct sensor_device_attribute_2 sda_auto_pwm_arrays[] = {
-	SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 0),
-	SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 0),
-	SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 1),
-	SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 1),
-	SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 2),
-	SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 2),
-	SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 3),
-	SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 3),
-	SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 4),
-	SENSOR_ATTR_2(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 4),
-	SENSOR_ATTR_2(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 5),
-	SENSOR_ATTR_2(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 5),
-	SENSOR_ATTR_2(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 0, 6),
-	SENSOR_ATTR_2(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 0, 6),
+static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
+	&sensor_dev_template_pwm,
+	&sensor_dev_template_pwm_mode,
+	&sensor_dev_template_pwm_enable,
+	&sensor_dev_template_pwm_temp_sel,
+	&sensor_dev_template_pwm_temp_tolerance,
+	&sensor_dev_template_pwm_crit_temp_tolerance,
+	&sensor_dev_template_pwm_target_temp,
+	&sensor_dev_template_fan_target,
+	&sensor_dev_template_fan_tolerance,
+	&sensor_dev_template_pwm_stop_time,
+	&sensor_dev_template_pwm_step_up_time,
+	&sensor_dev_template_pwm_step_down_time,
+	&sensor_dev_template_pwm_start,
+	&sensor_dev_template_pwm_floor,
+	&sensor_dev_template_pwm_weight_temp_sel,
+	&sensor_dev_template_pwm_weight_temp_step,
+	&sensor_dev_template_pwm_weight_temp_step_tol,
+	&sensor_dev_template_pwm_weight_temp_step_base,
+	&sensor_dev_template_pwm_weight_duty_step,
+	&sensor_dev_template_pwm_max,			/* 19 */
+	&sensor_dev_template_pwm_step,			/* 20 */
+	&sensor_dev_template_pwm_weight_duty_base,	/* 21 */
+	&sensor_dev_template_pwm_auto_point1_pwm,	/* 22 */
+	&sensor_dev_template_pwm_auto_point1_temp,
+	&sensor_dev_template_pwm_auto_point2_pwm,
+	&sensor_dev_template_pwm_auto_point2_temp,
+	&sensor_dev_template_pwm_auto_point3_pwm,
+	&sensor_dev_template_pwm_auto_point3_temp,
+	&sensor_dev_template_pwm_auto_point4_pwm,
+	&sensor_dev_template_pwm_auto_point4_temp,
+	&sensor_dev_template_pwm_auto_point5_pwm,
+	&sensor_dev_template_pwm_auto_point5_temp,
+	&sensor_dev_template_pwm_auto_point6_pwm,
+	&sensor_dev_template_pwm_auto_point6_temp,
+	&sensor_dev_template_pwm_auto_point7_pwm,
+	&sensor_dev_template_pwm_auto_point7_temp,	/* 35 */
 
-	SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 0),
-	SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 0),
-	SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 1),
-	SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 1),
-	SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 2),
-	SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 2),
-	SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 3),
-	SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 3),
-	SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 4),
-	SENSOR_ATTR_2(pwm2_auto_point5_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 4),
-	SENSOR_ATTR_2(pwm2_auto_point6_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 5),
-	SENSOR_ATTR_2(pwm2_auto_point6_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 5),
-	SENSOR_ATTR_2(pwm2_auto_point7_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 1, 6),
-	SENSOR_ATTR_2(pwm2_auto_point7_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 1, 6),
+	NULL
+};
 
-	SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 0),
-	SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 0),
-	SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 1),
-	SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 1),
-	SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 2),
-	SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 2),
-	SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 3),
-	SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 3),
-	SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 4),
-	SENSOR_ATTR_2(pwm3_auto_point5_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 4),
-	SENSOR_ATTR_2(pwm3_auto_point6_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 5),
-	SENSOR_ATTR_2(pwm3_auto_point6_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 5),
-	SENSOR_ATTR_2(pwm3_auto_point7_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 2, 6),
-	SENSOR_ATTR_2(pwm3_auto_point7_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 2, 6),
-
-	SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 0),
-	SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 0),
-	SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 1),
-	SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 1),
-	SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 2),
-	SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 2),
-	SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 3),
-	SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 3),
-	SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 4),
-	SENSOR_ATTR_2(pwm4_auto_point5_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 4),
-	SENSOR_ATTR_2(pwm4_auto_point6_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 5),
-	SENSOR_ATTR_2(pwm4_auto_point6_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 5),
-	SENSOR_ATTR_2(pwm4_auto_point7_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 3, 6),
-	SENSOR_ATTR_2(pwm4_auto_point7_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 3, 6),
-
-	SENSOR_ATTR_2(pwm5_auto_point1_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 0),
-	SENSOR_ATTR_2(pwm5_auto_point1_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 0),
-	SENSOR_ATTR_2(pwm5_auto_point2_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 1),
-	SENSOR_ATTR_2(pwm5_auto_point2_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 1),
-	SENSOR_ATTR_2(pwm5_auto_point3_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 2),
-	SENSOR_ATTR_2(pwm5_auto_point3_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 2),
-	SENSOR_ATTR_2(pwm5_auto_point4_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 3),
-	SENSOR_ATTR_2(pwm5_auto_point4_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 3),
-	SENSOR_ATTR_2(pwm5_auto_point5_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 4),
-	SENSOR_ATTR_2(pwm5_auto_point5_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 4),
-	SENSOR_ATTR_2(pwm5_auto_point6_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 5),
-	SENSOR_ATTR_2(pwm5_auto_point6_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 5),
-	SENSOR_ATTR_2(pwm5_auto_point7_pwm, S_IWUSR | S_IRUGO,
-		      show_auto_pwm, store_auto_pwm, 4, 6),
-	SENSOR_ATTR_2(pwm5_auto_point7_temp, S_IWUSR | S_IRUGO,
-		      show_auto_temp, store_auto_temp, 4, 6),
+static struct sensor_template_group nct6775_pwm_template_group = {
+	.templates = nct6775_attributes_pwm_template,
+	.is_visible = nct6775_pwm_is_visible,
+	.base = 1,
 };
 
 static ssize_t
@@ -3159,7 +3009,6 @@
 	       const char *buf, size_t count)
 {
 	struct nct6775_data *data = dev_get_drvdata(dev);
-	struct nct6775_sio_data *sio_data = dev->platform_data;
 	int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
 	unsigned long val;
 	u8 reg;
@@ -3175,19 +3024,19 @@
 	 * The CR registers are the same for all chips, and not all chips
 	 * support clearing the caseopen status through "regular" registers.
 	 */
-	ret = superio_enter(sio_data->sioreg);
+	ret = superio_enter(data->sioreg);
 	if (ret) {
 		count = ret;
 		goto error;
 	}
 
-	superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
-	reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+	superio_select(data->sioreg, NCT6775_LD_ACPI);
+	reg = superio_inb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
 	reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
-	superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+	superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
 	reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
-	superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
-	superio_exit(sio_data->sioreg);
+	superio_outb(data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+	superio_exit(data->sioreg);
 
 	data->valid = false;	/* Force cache refresh */
 error:
@@ -3195,11 +3044,59 @@
 	return count;
 }
 
-static struct sensor_device_attribute sda_caseopen[] = {
-	SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
-		    clear_caseopen, INTRUSION_ALARM_BASE),
-	SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
-		    clear_caseopen, INTRUSION_ALARM_BASE + 1),
+static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+			  clear_caseopen, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+			  clear_caseopen, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(intrusion0_beep, S_IWUSR | S_IRUGO, show_beep,
+			  store_beep, INTRUSION_ALARM_BASE);
+static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
+			  store_beep, INTRUSION_ALARM_BASE + 1);
+static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
+			  store_beep, BEEP_ENABLE_BASE);
+
+static umode_t nct6775_other_is_visible(struct kobject *kobj,
+					struct attribute *attr, int index)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct nct6775_data *data = dev_get_drvdata(dev);
+
+	if (index == 1 && !data->have_vid)
+		return 0;
+
+	if (index == 2 || index == 3) {
+		if (data->ALARM_BITS[INTRUSION_ALARM_BASE + index - 2] < 0)
+			return 0;
+	}
+
+	if (index == 4 || index == 5) {
+		if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 4] < 0)
+			return 0;
+	}
+
+	return attr->mode;
+}
+
+/*
+ * nct6775_other_is_visible uses the index into the following array
+ * to determine if attributes should be created or not.
+ * Any change in order or content must be matched.
+ */
+static struct attribute *nct6775_attributes_other[] = {
+	&dev_attr_name.attr,
+	&dev_attr_cpu0_vid.attr,				/* 1 */
+	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,	/* 2 */
+	&sensor_dev_attr_intrusion1_alarm.dev_attr.attr,	/* 3 */
+	&sensor_dev_attr_intrusion0_beep.dev_attr.attr,		/* 4 */
+	&sensor_dev_attr_intrusion1_beep.dev_attr.attr,		/* 5 */
+	&sensor_dev_attr_beep_enable.dev_attr.attr,		/* 6 */
+
+	NULL
+};
+
+static const struct attribute_group nct6775_group_other = {
+	.attrs = nct6775_attributes_other,
+	.is_visible = nct6775_other_is_visible,
 };
 
 /*
@@ -3208,58 +3105,18 @@
 
 static void nct6775_device_remove_files(struct device *dev)
 {
-	/*
-	 * some entries in the following arrays may not have been used in
-	 * device_create_file(), but device_remove_file() will ignore them
-	 */
-	int i;
 	struct nct6775_data *data = dev_get_drvdata(dev);
 
-	for (i = 0; i < data->pwm_num; i++)
-		sysfs_remove_group(&dev->kobj, &nct6775_group_pwm[i]);
+	if (data->group_pwm)
+		sysfs_remove_group(&dev->kobj, data->group_pwm);
+	if (data->group_in)
+		sysfs_remove_group(&dev->kobj, data->group_in);
+	if (data->group_fan)
+		sysfs_remove_group(&dev->kobj, data->group_fan);
+	if (data->group_temp)
+		sysfs_remove_group(&dev->kobj, data->group_temp);
 
-	for (i = 0; i < ARRAY_SIZE(sda_pwm_max); i++)
-		device_remove_file(dev, &sda_pwm_max[i].dev_attr);
-
-	for (i = 0; i < ARRAY_SIZE(sda_pwm_step); i++)
-		device_remove_file(dev, &sda_pwm_step[i].dev_attr);
-
-	for (i = 0; i < ARRAY_SIZE(sda_weight_duty_base); i++)
-		device_remove_file(dev, &sda_weight_duty_base[i].dev_attr);
-
-	for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++)
-		device_remove_file(dev, &sda_auto_pwm_arrays[i].dev_attr);
-
-	for (i = 0; i < data->in_num; i++)
-		sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);
-
-	for (i = 0; i < 5; i++) {
-		device_remove_file(dev, &sda_fan_input[i].dev_attr);
-		device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
-		device_remove_file(dev, &sda_fan_div[i].dev_attr);
-		device_remove_file(dev, &sda_fan_min[i].dev_attr);
-		device_remove_file(dev, &sda_fan_pulses[i].dev_attr);
-	}
-	for (i = 0; i < NUM_TEMP; i++) {
-		if (!(data->have_temp & (1 << i)))
-			continue;
-		device_remove_file(dev, &sda_temp_input[i].dev_attr);
-		device_remove_file(dev, &sda_temp_label[i].dev_attr);
-		device_remove_file(dev, &sda_temp_max[i].dev_attr);
-		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
-		device_remove_file(dev, &sda_temp_crit[i].dev_attr);
-		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
-		if (!(data->have_temp_fixed & (1 << i)))
-			continue;
-		device_remove_file(dev, &sda_temp_type[i].dev_attr);
-		device_remove_file(dev, &sda_temp_offset[i].dev_attr);
-	}
-
-	device_remove_file(dev, &sda_caseopen[0].dev_attr);
-	device_remove_file(dev, &sda_caseopen[1].dev_attr);
-
-	device_remove_file(dev, &dev_attr_name);
-	device_remove_file(dev, &dev_attr_cpu0_vid);
+	sysfs_remove_group(&dev->kobj, &nct6775_group_other);
 }
 
 /* Get the monitoring functions started */
@@ -3297,68 +3154,78 @@
 	for (i = 0; i < data->temp_fixed_num; i++) {
 		if (!(data->have_temp_fixed & (1 << i)))
 			continue;
-		if ((tmp & (0x02 << i)))	/* diode */
-			data->temp_type[i] = 3 - ((diode >> i) & 0x02);
+		if ((tmp & (data->DIODE_MASK << i)))	/* diode */
+			data->temp_type[i]
+			  = 3 - ((diode >> i) & data->DIODE_MASK);
 		else				/* thermistor */
 			data->temp_type[i] = 4;
 	}
 }
 
-static int
-nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
-			 struct nct6775_data *data)
+static void
+nct6775_check_fan_inputs(struct nct6775_data *data)
 {
+	bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
+	bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
+	int sioreg = data->sioreg;
 	int regval;
-	bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
-	bool pwm3pin, pwm4pin, pwm5pin;
-	int ret;
-
-	ret = superio_enter(sio_data->sioreg);
-	if (ret)
-		return ret;
 
 	/* fan4 and fan5 share some pins with the GPIO and serial flash */
 	if (data->kind == nct6775) {
-		regval = superio_inb(sio_data->sioreg, 0x2c);
+		regval = superio_inb(sioreg, 0x2c);
 
 		fan3pin = regval & (1 << 6);
-		fan3min = fan3pin;
 		pwm3pin = regval & (1 << 7);
 
 		/* On NCT6775, fan4 shares pins with the fdc interface */
-		fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
-		fan4min = 0;
-		fan5pin = 0;
-		pwm4pin = 0;
-		pwm5pin = 0;
+		fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
+		fan4min = false;
+		fan5pin = false;
+		fan6pin = false;
+		pwm4pin = false;
+		pwm5pin = false;
+		pwm6pin = false;
 	} else if (data->kind == nct6776) {
-		bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+		bool gpok = superio_inb(sioreg, 0x27) & 0x80;
 
-		superio_select(sio_data->sioreg, NCT6775_LD_HWM);
-		regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+		superio_select(sioreg, NCT6775_LD_HWM);
+		regval = superio_inb(sioreg, SIO_REG_ENABLE);
 
 		if (regval & 0x80)
 			fan3pin = gpok;
 		else
-			fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+			fan3pin = !(superio_inb(sioreg, 0x24) & 0x40);
 
 		if (regval & 0x40)
 			fan4pin = gpok;
 		else
-			fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01;
+			fan4pin = superio_inb(sioreg, 0x1C) & 0x01;
 
 		if (regval & 0x20)
 			fan5pin = gpok;
 		else
-			fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02;
+			fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
 
 		fan4min = fan4pin;
-		fan3min = fan3pin;
+		fan6pin = false;
 		pwm3pin = fan3pin;
-		pwm4pin = 0;
-		pwm5pin = 0;
-	} else {	/* NCT6779D */
-		regval = superio_inb(sio_data->sioreg, 0x1c);
+		pwm4pin = false;
+		pwm5pin = false;
+		pwm6pin = false;
+	} else if (data->kind == nct6106) {
+		regval = superio_inb(sioreg, 0x24);
+		fan3pin = !(regval & 0x80);
+		pwm3pin = regval & 0x08;
+
+		fan4pin = false;
+		fan4min = false;
+		fan5pin = false;
+		fan6pin = false;
+		pwm4pin = false;
+		pwm5pin = false;
+		pwm6pin = false;
+	} else {	/* NCT6779D or NCT6791D */
+		regval = superio_inb(sioreg, 0x1c);
 
 		fan3pin = !(regval & (1 << 5));
 		fan4pin = !(regval & (1 << 6));
@@ -3368,22 +3235,25 @@
 		pwm4pin = !(regval & (1 << 1));
 		pwm5pin = !(regval & (1 << 2));
 
-		fan3min = fan3pin;
 		fan4min = fan4pin;
+
+		if (data->kind == nct6791) {
+			regval = superio_inb(sioreg, 0x2d);
+			fan6pin = (regval & (1 << 1));
+			pwm6pin = (regval & (1 << 0));
+		} else {	/* NCT6779D */
+			fan6pin = false;
+			pwm6pin = false;
+		}
 	}
 
-	superio_exit(sio_data->sioreg);
-
-	data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
-	data->has_fan |= fan3pin << 2;
-	data->has_fan_min |= fan3min << 2;
-
-	data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
-	data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
-
-	data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4);
-
-	return 0;
+	/* fan 1 and 2 (0x03) are always present */
+	data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
+		(fan5pin << 4) | (fan6pin << 5);
+	data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
+		(fan5pin << 4);
+	data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
+		(pwm5pin << 4) | (pwm6pin << 5);
 }
 
 static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
@@ -3415,16 +3285,17 @@
 static int nct6775_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct nct6775_sio_data *sio_data = dev->platform_data;
+	struct nct6775_sio_data *sio_data = dev_get_platdata(dev);
 	struct nct6775_data *data;
 	struct resource *res;
 	int i, s, err = 0;
 	int src, mask, available;
 	const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
 	const u16 *reg_temp_alternate, *reg_temp_crit;
+	const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
 	int num_reg_temp;
-	bool have_vid = false;
 	u8 cr2a;
+	struct attribute_group *group;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
 	if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
@@ -3437,6 +3308,7 @@
 		return -ENOMEM;
 
 	data->kind = sio_data->kind;
+	data->sioreg = sio_data->sioreg;
 	data->addr = res->start;
 	mutex_init(&data->update_lock);
 	data->name = nct6775_device_names[data->kind];
@@ -3444,6 +3316,75 @@
 	platform_set_drvdata(pdev, data);
 
 	switch (data->kind) {
+	case nct6106:
+		data->in_num = 9;
+		data->pwm_num = 3;
+		data->auto_pwm_num = 4;
+		data->temp_fixed_num = 3;
+		data->num_temp_alarms = 6;
+		data->num_temp_beeps = 6;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+
+		data->temp_label = nct6776_temp_label;
+		data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+		data->REG_VBAT = NCT6106_REG_VBAT;
+		data->REG_DIODE = NCT6106_REG_DIODE;
+		data->DIODE_MASK = NCT6106_DIODE_MASK;
+		data->REG_VIN = NCT6106_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
+		data->REG_TARGET = NCT6106_REG_TARGET;
+		data->REG_FAN = NCT6106_REG_FAN;
+		data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6106_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6106_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6106_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+		data->REG_PWM[0] = NCT6106_REG_PWM;
+		data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
+		data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6106_REG_ALARM;
+		data->ALARM_BITS = NCT6106_ALARM_BITS;
+		data->REG_BEEP = NCT6106_REG_BEEP;
+		data->BEEP_BITS = NCT6106_BEEP_BITS;
+
+		reg_temp = NCT6106_REG_TEMP;
+		num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
+		reg_temp_over = NCT6106_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+		reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+		reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
+		break;
 	case nct6775:
 		data->in_num = 9;
 		data->pwm_num = 3;
@@ -3451,8 +3392,10 @@
 		data->has_fan_div = true;
 		data->temp_fixed_num = 3;
 		data->num_temp_alarms = 3;
+		data->num_temp_beeps = 3;
 
 		data->ALARM_BITS = NCT6775_ALARM_BITS;
+		data->BEEP_BITS = NCT6775_BEEP_BITS;
 
 		data->fan_from_reg = fan_from_reg16;
 		data->fan_from_reg_min = fan_from_reg8;
@@ -3466,6 +3409,7 @@
 		data->REG_CONFIG = NCT6775_REG_CONFIG;
 		data->REG_VBAT = NCT6775_REG_VBAT;
 		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
 		data->REG_VIN = NCT6775_REG_IN;
 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3474,6 +3418,7 @@
 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
 		data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
 		data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
 		data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
 		data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3499,6 +3444,7 @@
 		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
 		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
 		data->REG_ALARM = NCT6775_REG_ALARM;
+		data->REG_BEEP = NCT6775_REG_BEEP;
 
 		reg_temp = NCT6775_REG_TEMP;
 		num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
@@ -3516,8 +3462,10 @@
 		data->has_fan_div = false;
 		data->temp_fixed_num = 3;
 		data->num_temp_alarms = 3;
+		data->num_temp_beeps = 6;
 
 		data->ALARM_BITS = NCT6776_ALARM_BITS;
+		data->BEEP_BITS = NCT6776_BEEP_BITS;
 
 		data->fan_from_reg = fan_from_reg13;
 		data->fan_from_reg_min = fan_from_reg13;
@@ -3531,6 +3479,7 @@
 		data->REG_CONFIG = NCT6775_REG_CONFIG;
 		data->REG_VBAT = NCT6775_REG_VBAT;
 		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
 		data->REG_VIN = NCT6775_REG_IN;
 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3539,6 +3488,7 @@
 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
 		data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
 		data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
 		data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3564,6 +3514,7 @@
 		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
 		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
 		data->REG_ALARM = NCT6775_REG_ALARM;
+		data->REG_BEEP = NCT6776_REG_BEEP;
 
 		reg_temp = NCT6775_REG_TEMP;
 		num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
@@ -3581,8 +3532,10 @@
 		data->has_fan_div = false;
 		data->temp_fixed_num = 6;
 		data->num_temp_alarms = 2;
+		data->num_temp_beeps = 2;
 
 		data->ALARM_BITS = NCT6779_ALARM_BITS;
+		data->BEEP_BITS = NCT6779_BEEP_BITS;
 
 		data->fan_from_reg = fan_from_reg13;
 		data->fan_from_reg_min = fan_from_reg13;
@@ -3596,6 +3549,7 @@
 		data->REG_CONFIG = NCT6775_REG_CONFIG;
 		data->REG_VBAT = NCT6775_REG_VBAT;
 		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
 		data->REG_VIN = NCT6779_REG_IN;
 		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
 		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
@@ -3604,6 +3558,7 @@
 		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
 		data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
 		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
 		data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
 		data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
@@ -3621,6 +3576,10 @@
 		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
 		data->REG_CRITICAL_TEMP_TOLERANCE
 		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
 		data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
 		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
 		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
@@ -3629,6 +3588,81 @@
 		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
 		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
 		data->REG_ALARM = NCT6779_REG_ALARM;
+		data->REG_BEEP = NCT6776_REG_BEEP;
+
+		reg_temp = NCT6779_REG_TEMP;
+		num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+		reg_temp_over = NCT6779_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+		reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+		reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+		break;
+	case nct6791:
+		data->in_num = 15;
+		data->pwm_num = 6;
+		data->auto_pwm_num = 4;
+		data->has_fan_div = false;
+		data->temp_fixed_num = 6;
+		data->num_temp_alarms = 2;
+		data->num_temp_beeps = 2;
+
+		data->ALARM_BITS = NCT6791_ALARM_BITS;
+		data->BEEP_BITS = NCT6779_BEEP_BITS;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+		data->target_temp_mask = 0xff;
+		data->tolerance_mask = 0x07;
+		data->speed_tolerance_limit = 63;
+
+		data->temp_label = nct6779_temp_label;
+		data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
+		data->REG_CONFIG = NCT6775_REG_CONFIG;
+		data->REG_VBAT = NCT6775_REG_VBAT;
+		data->REG_DIODE = NCT6775_REG_DIODE;
+		data->DIODE_MASK = NCT6775_DIODE_MASK;
+		data->REG_VIN = NCT6779_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+		data->REG_TARGET = NCT6775_REG_TARGET;
+		data->REG_FAN = NCT6779_REG_FAN;
+		data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT6775_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+		data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+		data->REG_PWM[0] = NCT6775_REG_PWM;
+		data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6779_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6779_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6779_REG_CRITICAL_PWM;
+		data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6791_REG_ALARM;
+		data->REG_BEEP = NCT6776_REG_BEEP;
 
 		reg_temp = NCT6779_REG_TEMP;
 		num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
@@ -3700,6 +3734,13 @@
 			data->reg_temp[0][src - 1] = reg_temp[i];
 			data->reg_temp[1][src - 1] = reg_temp_over[i];
 			data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+			if (reg_temp_crit_h && reg_temp_crit_h[i])
+				data->reg_temp[3][src - 1] = reg_temp_crit_h[i];
+			else if (reg_temp_crit[src - 1])
+				data->reg_temp[3][src - 1]
+				  = reg_temp_crit[src - 1];
+			if (reg_temp_crit_l && reg_temp_crit_l[i])
+				data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
 			data->reg_temp_config[src - 1] = reg_temp_config[i];
 			data->temp_src[src - 1] = src;
 			continue;
@@ -3714,8 +3755,12 @@
 		data->reg_temp[1][s] = reg_temp_over[i];
 		data->reg_temp[2][s] = reg_temp_hyst[i];
 		data->reg_temp_config[s] = reg_temp_config[i];
-		if (reg_temp_crit[src - 1])
+		if (reg_temp_crit_h && reg_temp_crit_h[i])
+			data->reg_temp[3][s] = reg_temp_crit_h[i];
+		else if (reg_temp_crit[src - 1])
 			data->reg_temp[3][s] = reg_temp_crit[src - 1];
+		if (reg_temp_crit_l && reg_temp_crit_l[i])
+			data->reg_temp[4][s] = reg_temp_crit_l[i];
 
 		data->temp_src[s] = src;
 		s++;
@@ -3767,12 +3812,14 @@
 	cr2a = superio_inb(sio_data->sioreg, 0x2a);
 	switch (data->kind) {
 	case nct6775:
-		have_vid = (cr2a & 0x40);
+		data->have_vid = (cr2a & 0x40);
 		break;
 	case nct6776:
-		have_vid = (cr2a & 0x60) == 0x40;
+		data->have_vid = (cr2a & 0x60) == 0x40;
 		break;
+	case nct6106:
 	case nct6779:
+	case nct6791:
 		break;
 	}
 
@@ -3780,7 +3827,7 @@
 	 * Read VID value
 	 * We can get the VID input values directly at logical device D 0xe3.
 	 */
-	if (have_vid) {
+	if (data->have_vid) {
 		superio_select(sio_data->sioreg, NCT6775_LD_VID);
 		data->vid = superio_inb(sio_data->sioreg, 0xe3);
 		data->vrm = vid_which_vrm();
@@ -3793,6 +3840,9 @@
 		tmp = superio_inb(sio_data->sioreg,
 				  NCT6775_REG_CR_FAN_DEBOUNCE);
 		switch (data->kind) {
+		case nct6106:
+			tmp |= 0xe0;
+			break;
 		case nct6775:
 			tmp |= 0x1e;
 			break;
@@ -3800,6 +3850,9 @@
 		case nct6779:
 			tmp |= 0x3e;
 			break;
+		case nct6791:
+			tmp |= 0x7e;
+			break;
 		}
 		superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
 			     tmp);
@@ -3807,157 +3860,47 @@
 			 data->name);
 	}
 
+	nct6775_check_fan_inputs(data);
+
 	superio_exit(sio_data->sioreg);
 
-	if (have_vid) {
-		err = device_create_file(dev, &dev_attr_cpu0_vid);
-		if (err)
-			return err;
-	}
-
-	err = nct6775_check_fan_inputs(sio_data, data);
-	if (err)
-		goto exit_remove;
-
 	/* Read fan clock dividers immediately */
 	nct6775_init_fan_common(dev, data);
 
 	/* Register sysfs hooks */
-	for (i = 0; i < data->pwm_num; i++) {
-		if (!(data->has_pwm & (1 << i)))
-			continue;
-
-		err = sysfs_create_group(&dev->kobj, &nct6775_group_pwm[i]);
-		if (err)
-			goto exit_remove;
-
-		if (data->REG_PWM[3]) {
-			err = device_create_file(dev,
-					&sda_pwm_max[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (data->REG_PWM[4]) {
-			err = device_create_file(dev,
-					&sda_pwm_step[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (data->REG_PWM[6]) {
-			err = device_create_file(dev,
-					&sda_weight_duty_base[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
+	group = nct6775_create_attr_group(dev, &nct6775_pwm_template_group,
+					  data->pwm_num);
+	if (IS_ERR(group)) {
+		err = PTR_ERR(group);
+		goto exit_remove;
 	}
-	for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++) {
-		struct sensor_device_attribute_2 *attr =
-			&sda_auto_pwm_arrays[i];
+	data->group_pwm = group;
 
-		if (!(data->has_pwm & (1 << attr->nr)))
-			continue;
-		if (attr->index > data->auto_pwm_num)
-			continue;
-		err = device_create_file(dev, &attr->dev_attr);
-		if (err)
-			goto exit_remove;
+	group = nct6775_create_attr_group(dev, &nct6775_in_template_group,
+					  fls(data->have_in));
+	if (IS_ERR(group)) {
+		err = PTR_ERR(group);
+		goto exit_remove;
 	}
+	data->group_in = group;
 
-	for (i = 0; i < data->in_num; i++) {
-		if (!(data->have_in & (1 << i)))
-			continue;
-		err = sysfs_create_group(&dev->kobj, &nct6775_group_in[i]);
-		if (err)
-			goto exit_remove;
+	group = nct6775_create_attr_group(dev, &nct6775_fan_template_group,
+					  fls(data->has_fan));
+	if (IS_ERR(group)) {
+		err = PTR_ERR(group);
+		goto exit_remove;
 	}
+	data->group_fan = group;
 
-	for (i = 0; i < 5; i++) {
-		if (data->has_fan & (1 << i)) {
-			err = device_create_file(dev,
-						 &sda_fan_input[i].dev_attr);
-			if (err)
-				goto exit_remove;
-			if (data->ALARM_BITS[FAN_ALARM_BASE + i] >= 0) {
-				err = device_create_file(dev,
-						&sda_fan_alarm[i].dev_attr);
-				if (err)
-					goto exit_remove;
-			}
-			if (data->kind != nct6776 &&
-			    data->kind != nct6779) {
-				err = device_create_file(dev,
-						&sda_fan_div[i].dev_attr);
-				if (err)
-					goto exit_remove;
-			}
-			if (data->has_fan_min & (1 << i)) {
-				err = device_create_file(dev,
-						&sda_fan_min[i].dev_attr);
-				if (err)
-					goto exit_remove;
-			}
-			err = device_create_file(dev,
-						&sda_fan_pulses[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
+	group = nct6775_create_attr_group(dev, &nct6775_temp_template_group,
+					  fls(data->have_temp));
+	if (IS_ERR(group)) {
+		err = PTR_ERR(group);
+		goto exit_remove;
 	}
+	data->group_temp = group;
 
-	for (i = 0; i < NUM_TEMP; i++) {
-		if (!(data->have_temp & (1 << i)))
-			continue;
-		err = device_create_file(dev, &sda_temp_input[i].dev_attr);
-		if (err)
-			goto exit_remove;
-		if (data->temp_label) {
-			err = device_create_file(dev,
-						 &sda_temp_label[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (data->reg_temp[1][i]) {
-			err = device_create_file(dev,
-						 &sda_temp_max[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (data->reg_temp[2][i]) {
-			err = device_create_file(dev,
-					&sda_temp_max_hyst[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (data->reg_temp[3][i]) {
-			err = device_create_file(dev,
-						 &sda_temp_crit[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (find_temp_source(data, i, data->num_temp_alarms) >= 0) {
-			err = device_create_file(dev,
-						 &sda_temp_alarm[i].dev_attr);
-			if (err)
-				goto exit_remove;
-		}
-		if (!(data->have_temp_fixed & (1 << i)))
-			continue;
-		err = device_create_file(dev, &sda_temp_type[i].dev_attr);
-		if (err)
-			goto exit_remove;
-		err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
-		if (err)
-			goto exit_remove;
-	}
-
-	for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
-		if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
-			continue;
-		err = device_create_file(dev, &sda_caseopen[i].dev_attr);
-		if (err)
-			goto exit_remove;
-	}
-
-	err = device_create_file(dev, &dev_attr_name);
+	err = sysfs_create_group(&dev->kobj, &nct6775_group_other);
 	if (err)
 		goto exit_remove;
 
@@ -3988,11 +3931,10 @@
 static int nct6775_suspend(struct device *dev)
 {
 	struct nct6775_data *data = nct6775_update_device(dev);
-	struct nct6775_sio_data *sio_data = dev->platform_data;
 
 	mutex_lock(&data->update_lock);
 	data->vbat = nct6775_read_value(data, data->REG_VBAT);
-	if (sio_data->kind == nct6775) {
+	if (data->kind == nct6775) {
 		data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
 		data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
 	}
@@ -4004,7 +3946,6 @@
 static int nct6775_resume(struct device *dev)
 {
 	struct nct6775_data *data = dev_get_drvdata(dev);
-	struct nct6775_sio_data *sio_data = dev->platform_data;
 	int i, j;
 
 	mutex_lock(&data->update_lock);
@@ -4041,7 +3982,7 @@
 
 	/* Restore other settings */
 	nct6775_write_value(data, data->REG_VBAT, data->vbat);
-	if (sio_data->kind == nct6775) {
+	if (data->kind == nct6775) {
 		nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
 		nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
 	}
@@ -4056,6 +3997,8 @@
 static const struct dev_pm_ops nct6775_dev_pm_ops = {
 	.suspend = nct6775_suspend,
 	.resume = nct6775_resume,
+	.freeze = nct6775_suspend,
+	.restore = nct6775_resume,
 };
 
 #define NCT6775_DEV_PM_OPS	(&nct6775_dev_pm_ops)
@@ -4074,17 +4017,19 @@
 };
 
 static const char * const nct6775_sio_names[] __initconst = {
+	"NCT6106D",
 	"NCT6775F",
 	"NCT6776D/F",
 	"NCT6779D",
+	"NCT6791D",
 };
 
 /* nct6775_find() looks for a '627 in the Super-I/O config space */
-static int __init nct6775_find(int sioaddr, unsigned short *addr,
-			       struct nct6775_sio_data *sio_data)
+static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
 {
 	u16 val;
 	int err;
+	int addr;
 
 	err = superio_enter(sioaddr);
 	if (err)
@@ -4096,6 +4041,9 @@
 		val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
 		    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
 	switch (val & SIO_ID_MASK) {
+	case SIO_NCT6106_ID:
+		sio_data->kind = nct6106;
+		break;
 	case SIO_NCT6775_ID:
 		sio_data->kind = nct6775;
 		break;
@@ -4105,6 +4053,9 @@
 	case SIO_NCT6779_ID:
 		sio_data->kind = nct6779;
 		break;
+	case SIO_NCT6791_ID:
+		sio_data->kind = nct6791;
+		break;
 	default:
 		if (val != 0xffff)
 			pr_debug("unsupported chip ID: 0x%04x\n", val);
@@ -4116,8 +4067,8 @@
 	superio_select(sioaddr, NCT6775_LD_HWM);
 	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
 	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
-	*addr = val & IOREGION_ALIGNMENT;
-	if (*addr == 0) {
+	addr = val & IOREGION_ALIGNMENT;
+	if (addr == 0) {
 		pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
 		superio_exit(sioaddr);
 		return -ENODEV;
@@ -4129,13 +4080,22 @@
 		pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
 		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
 	}
+	if (sio_data->kind == nct6791) {
+		val = superio_inb(sioaddr, NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE);
+		if (val & 0x10) {
+			pr_info("Enabling hardware monitor logical device mappings.\n");
+			superio_outb(sioaddr,
+				     NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE,
+				     val & ~0x10);
+		}
+	}
 
 	superio_exit(sioaddr);
-	pr_info("Found %s or compatible chip at %#x\n",
-		nct6775_sio_names[sio_data->kind], *addr);
+	pr_info("Found %s or compatible chip at %#x:%#x\n",
+		nct6775_sio_names[sio_data->kind], sioaddr, addr);
 	sio_data->sioreg = sioaddr;
 
-	return 0;
+	return addr;
 }
 
 /*
@@ -4144,14 +4104,20 @@
  * track of the nct6775 driver. But since we platform_device_alloc(), we
  * must keep track of the device
  */
-static struct platform_device *pdev;
+static struct platform_device *pdev[2];
 
 static int __init sensors_nct6775_init(void)
 {
-	int err;
-	unsigned short address;
+	int i, err;
+	bool found = false;
+	int address;
 	struct resource res;
 	struct nct6775_sio_data sio_data;
+	int sioaddr[2] = { 0x2e, 0x4e };
+
+	err = platform_driver_register(&nct6775_driver);
+	if (err)
+		return err;
 
 	/*
 	 * initialize sio_data->kind and sio_data->sioreg.
@@ -4160,64 +4126,71 @@
 	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
 	 * nct6775 hardware monitor, and call probe()
 	 */
-	if (nct6775_find(0x2e, &address, &sio_data) &&
-	    nct6775_find(0x4e, &address, &sio_data))
-		return -ENODEV;
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		address = nct6775_find(sioaddr[i], &sio_data);
+		if (address <= 0)
+			continue;
 
-	err = platform_driver_register(&nct6775_driver);
-	if (err)
-		goto exit;
+		found = true;
 
-	pdev = platform_device_alloc(DRVNAME, address);
-	if (!pdev) {
-		err = -ENOMEM;
-		pr_err("Device allocation failed\n");
+		pdev[i] = platform_device_alloc(DRVNAME, address);
+		if (!pdev[i]) {
+			err = -ENOMEM;
+			goto exit_device_put;
+		}
+
+		err = platform_device_add_data(pdev[i], &sio_data,
+					       sizeof(struct nct6775_sio_data));
+		if (err)
+			goto exit_device_put;
+
+		memset(&res, 0, sizeof(res));
+		res.name = DRVNAME;
+		res.start = address + IOREGION_OFFSET;
+		res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+		res.flags = IORESOURCE_IO;
+
+		err = acpi_check_resource_conflict(&res);
+		if (err) {
+			platform_device_put(pdev[i]);
+			pdev[i] = NULL;
+			continue;
+		}
+
+		err = platform_device_add_resources(pdev[i], &res, 1);
+		if (err)
+			goto exit_device_put;
+
+		/* platform_device_add calls probe() */
+		err = platform_device_add(pdev[i]);
+		if (err)
+			goto exit_device_put;
+	}
+	if (!found) {
+		err = -ENODEV;
 		goto exit_unregister;
 	}
 
-	err = platform_device_add_data(pdev, &sio_data,
-				       sizeof(struct nct6775_sio_data));
-	if (err) {
-		pr_err("Platform data allocation failed\n");
-		goto exit_device_put;
-	}
-
-	memset(&res, 0, sizeof(res));
-	res.name = DRVNAME;
-	res.start = address + IOREGION_OFFSET;
-	res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
-	res.flags = IORESOURCE_IO;
-
-	err = acpi_check_resource_conflict(&res);
-	if (err)
-		goto exit_device_put;
-
-	err = platform_device_add_resources(pdev, &res, 1);
-	if (err) {
-		pr_err("Device resource addition failed (%d)\n", err);
-		goto exit_device_put;
-	}
-
-	/* platform_device_add calls probe() */
-	err = platform_device_add(pdev);
-	if (err) {
-		pr_err("Device addition failed (%d)\n", err);
-		goto exit_device_put;
-	}
-
 	return 0;
 
 exit_device_put:
-	platform_device_put(pdev);
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		if (pdev[i])
+			platform_device_put(pdev[i]);
+	}
 exit_unregister:
 	platform_driver_unregister(&nct6775_driver);
-exit:
 	return err;
 }
 
 static void __exit sensors_nct6775_exit(void)
 {
-	platform_device_unregister(pdev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pdev); i++) {
+		if (pdev[i])
+			platform_device_unregister(pdev[i]);
+	}
 	platform_driver_unregister(&nct6775_driver);
 }
 
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 830a842..8c232039 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -424,7 +424,7 @@
 	if (IS_ERR(pdata))
 		return PTR_ERR(pdata);
 	else if (pdata == NULL)
-		pdata = pdev->dev.platform_data;
+		pdata = dev_get_platdata(&pdev->dev);
 
 	if (!pdata) {
 		dev_err(&pdev->dev, "No platform init data supplied.\n");
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index ea60686..6e6ea44 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -983,7 +983,7 @@
 
 static void pc87427_init_device(struct device *dev)
 {
-	struct pc87427_sio_data *sio_data = dev->platform_data;
+	struct pc87427_sio_data *sio_data = dev_get_platdata(dev);
 	struct pc87427_data *data = dev_get_drvdata(dev);
 	int i;
 	u8 reg;
@@ -1075,7 +1075,7 @@
 
 static int pc87427_probe(struct platform_device *pdev)
 {
-	struct pc87427_sio_data *sio_data = pdev->dev.platform_data;
+	struct pc87427_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	struct pc87427_data *data;
 	int i, err, res_count;
 
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 9add6092..9319fcf 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -1726,7 +1726,7 @@
 		   struct pmbus_driver_info *info)
 {
 	struct device *dev = &client->dev;
-	const struct pmbus_platform_data *pdata = dev->platform_data;
+	const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
 	struct pmbus_data *data;
 	int ret;
 
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index a9f7e80..73bd64e 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -165,7 +165,7 @@
 {
 	struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
 	struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev));
-	struct s3c_hwmon_pdata *pdata = dev->platform_data;
+	struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
 	struct s3c_hwmon_chcfg *cfg;
 	int ret;
 
@@ -194,7 +194,7 @@
 				    char *buf)
 {
 	struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr);
-	struct s3c_hwmon_pdata *pdata = dev->platform_data;
+	struct s3c_hwmon_pdata *pdata = dev_get_platdata(dev);
 	struct s3c_hwmon_chcfg *cfg;
 
 	cfg = pdata->in[sen_attr->index];
@@ -274,7 +274,7 @@
 */
 static int s3c_hwmon_probe(struct platform_device *dev)
 {
-	struct s3c_hwmon_pdata *pdata = dev->dev.platform_data;
+	struct s3c_hwmon_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct s3c_hwmon *hwmon;
 	int ret = 0;
 	int i;
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 2507f90..97cd45a 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -940,11 +940,11 @@
 	data->dev = &pdev->dev;
 	init_waitqueue_head(&data->wait_queue);
 
-	if (pdev->dev.platform_data == NULL) {
+	if (dev_get_platdata(&pdev->dev) == NULL) {
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		return -EINVAL;
 	}
-	data->pdata = pdev->dev.platform_data;
+	data->pdata = dev_get_platdata(&pdev->dev);
 	data->supply_uv = data->pdata->supply_mv * 1000;
 	if (data->pdata->checksum)
 		data->checksumming = true;
@@ -957,7 +957,7 @@
 	 * If a regulator is available,
 	 * query what the supply voltage actually is!
 	 */
-	data->reg = devm_regulator_get(data->dev, "vcc");
+	data->reg = devm_regulator_get_optional(data->dev, "vcc");
 	if (!IS_ERR(data->reg)) {
 		int voltage;
 
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 6d8255c..05cb814 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -668,7 +668,7 @@
 static int __init smsc47m1_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct smsc47m1_sio_data *sio_data = dev->platform_data;
+	struct smsc47m1_sio_data *sio_data = dev_get_platdata(dev);
 	struct smsc47m1_data *data;
 	struct resource *res;
 	int err;
@@ -940,7 +940,7 @@
 static void __exit sm_smsc47m1_exit(void)
 {
 	platform_driver_unregister(&smsc47m1_driver);
-	smsc47m1_restore(pdev->dev.platform_data);
+	smsc47m1_restore(dev_get_platdata(&pdev->dev));
 	platform_device_unregister(pdev);
 }
 
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 004801e..23ff210 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -673,7 +673,7 @@
 static void w83627ehf_write_fan_div_common(struct device *dev,
 					   struct w83627ehf_data *data, int nr)
 {
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
 	if (sio_data->kind == nct6776)
 		; /* no dividers, do nothing */
@@ -724,7 +724,7 @@
 static void w83627ehf_update_fan_div_common(struct device *dev,
 					    struct w83627ehf_data *data)
 {
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
 	if (sio_data->kind == nct6776)
 		; /* no dividers, do nothing */
@@ -781,7 +781,7 @@
 static void w83627ehf_update_pwm_common(struct device *dev,
 					struct w83627ehf_data *data)
 {
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
 		nct6775_update_pwm(data);
@@ -792,7 +792,7 @@
 static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
 	int i;
 
@@ -1392,7 +1392,7 @@
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 	int nr = sensor_attr->index;
 	unsigned long val;
 	int err;
@@ -1448,7 +1448,7 @@
 			const char *buf, size_t count)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	unsigned long val;
@@ -1527,7 +1527,7 @@
 			const char *buf, size_t count)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u16 reg;
@@ -2065,7 +2065,7 @@
 static int w83627ehf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 	struct w83627ehf_data *data;
 	struct resource *res;
 	u8 en_vrm10;
@@ -2618,7 +2618,7 @@
 static int w83627ehf_suspend(struct device *dev)
 {
 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 
 	mutex_lock(&data->update_lock);
 	data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
@@ -2634,7 +2634,7 @@
 static int w83627ehf_resume(struct device *dev)
 {
 	struct w83627ehf_data *data = dev_get_drvdata(dev);
-	struct w83627ehf_sio_data *sio_data = dev->platform_data;
+	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -2694,6 +2694,8 @@
 static const struct dev_pm_ops w83627ehf_dev_pm_ops = {
 	.suspend = w83627ehf_suspend,
 	.resume = w83627ehf_resume,
+	.freeze = w83627ehf_suspend,
+	.restore = w83627ehf_resume,
 };
 
 #define W83627EHF_DEV_PM_OPS	(&w83627ehf_dev_pm_ops)
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 3b9ef2d..cb9cd32 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1415,7 +1415,7 @@
 static int w83627hf_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct w83627hf_sio_data *sio_data = dev->platform_data;
+	struct w83627hf_sio_data *sio_data = dev_get_platdata(dev);
 	struct w83627hf_data *data;
 	struct resource *res;
 	int err, i;
@@ -1636,7 +1636,7 @@
 
 static int w83627thf_read_gpio5(struct platform_device *pdev)
 {
-	struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+	struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	int res = 0xff, sel;
 
 	superio_enter(sio_data);
@@ -1669,7 +1669,7 @@
 
 static int w83687thf_read_vid(struct platform_device *pdev)
 {
-	struct w83627hf_sio_data *sio_data = pdev->dev.platform_data;
+	struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev);
 	int res = 0xff;
 
 	superio_enter(sio_data);
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index f1a6796b..140c8ef5 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -520,11 +520,12 @@
 	ide_port_for_each_present_dev(i, drive, hwif) {
 		if (drive->acpidata->obj_handle)
 			acpi_bus_set_power(drive->acpidata->obj_handle,
-					   on ? ACPI_STATE_D0 : ACPI_STATE_D3);
+				on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
 	}
 
 	if (!on)
-		acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+		acpi_bus_set_power(hwif->acpidata->obj_handle,
+				   ACPI_STATE_D3_COLD);
 }
 
 /**
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 9af763a..cbea327 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -23,15 +23,14 @@
 config IIO_BUFFER_CB
 boolean "IIO callback buffer used for push in-kernel interfaces"
 	help
-	  Should be selected by any drivers that do-inkernel push
+	  Should be selected by any drivers that do in-kernel push
 	  usage.  That is, those where the data is pushed to the consumer.
 
 config IIO_KFIFO_BUF
 	select IIO_TRIGGER
 	tristate "Industrial I/O buffering based on kfifo"
 	help
-	  A simple fifo based on kfifo.  Use this if you want a fifo
-	  rather than a ring buffer. Note that this currently provides
+	  A simple fifo based on kfifo.  Note that this currently provides
 	  no buffer events so it is up to userspace to work out how
 	  often to read from the buffer.
 
@@ -49,7 +48,7 @@
 	help
 	  Provides IIO core support for triggers.  Currently these
 	  are used to initialize capture of samples to push into
-	  ring buffers.  The triggers are effectively a 'capture
+	  buffers.  The triggers are effectively a 'capture
 	  data now' interrupt.
 
 config IIO_CONSUMERS_PER_TRIGGER
@@ -74,5 +73,6 @@
    source "drivers/iio/trigger/Kconfig"
 endif #IIO_TRIGGER
 source "drivers/iio/pressure/Kconfig"
+source "drivers/iio/temperature/Kconfig"
 
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 7a3866c..bcf7e9e 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -21,5 +21,6 @@
 obj-y += imu/
 obj-y += light/
 obj-y += magnetometer/
-obj-y += trigger/
 obj-y += pressure/
+obj-y += temperature/
+obj-y += trigger/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 719d83f..e23e5085 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -1,8 +1,22 @@
 #
 # Accelerometer drivers
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Accelerometers"
 
+config BMA180
+	tristate "Bosch BMA180 3-Axis Accelerometer Driver"
+	depends on I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say Y here if you want to build a driver for the Bosch BMA180
+	  triaxial acceleration sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bma180.
+
 config HID_SENSOR_ACCEL_3D
 	depends on HID_SENSOR_HUB
 	select IIO_BUFFER
@@ -14,13 +28,6 @@
 	  Say yes here to build support for the HID SENSOR
 	  accelerometers 3D.
 
-config KXSD9
-	tristate "Kionix KXSD9 Accelerometer Driver"
-	depends on SPI
-	help
-	  Say yes here to build support for the Kionix KXSD9 accelerometer.
-	  Currently this only supports the device via an SPI interface.
-
 config IIO_ST_ACCEL_3AXIS
 	tristate "STMicroelectronics accelerometers 3-Axis Driver"
 	depends on (I2C || SPI_MASTER) && SYSFS
@@ -33,8 +40,8 @@
 	  LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
 	  LIS331DLH, LSM303DL, LSM303DLM, LSM330.
 
-	  This driver can also be built as a module. If so, will be created
-	  these modules:
+	  This driver can also be built as a module. If so, these modules
+	  will be created:
 	  - st_accel (core functions for the driver [it is mandatory]);
 	  - st_accel_i2c (necessary for the I2C devices [optional*]);
 	  - st_accel_spi (necessary for the SPI devices [optional*]);
@@ -51,4 +58,11 @@
 	depends on IIO_ST_ACCEL_3AXIS
 	depends on IIO_ST_SENSORS_SPI
 
+config KXSD9
+	tristate "Kionix KXSD9 Accelerometer Driver"
+	depends on SPI
+	help
+	  Say yes here to build support for the Kionix KXSD9 accelerometer.
+	  Currently this only supports the device via an SPI interface.
+
 endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 87d8fa2..c48d15f 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -2,7 +2,10 @@
 # Makefile for industrial I/O accelerometer drivers
 #
 
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_BMA180) += bma180.o
 obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
+obj-$(CONFIG_KXSD9)	+= kxsd9.o
 
 obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
 st_accel-y := st_accel_core.o
@@ -10,5 +13,3 @@
 
 obj-$(CONFIG_IIO_ST_ACCEL_I2C_3AXIS) += st_accel_i2c.o
 obj-$(CONFIG_IIO_ST_ACCEL_SPI_3AXIS) += st_accel_spi.o
-
-obj-$(CONFIG_KXSD9)	+= kxsd9.o
diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c
new file mode 100644
index 0000000..12e32e6
--- /dev/null
+++ b/drivers/iio/accel/bma180.c
@@ -0,0 +1,676 @@
+/*
+ * bma180.c - IIO driver for Bosch BMA180 triaxial acceleration sensor
+ *
+ * Copyright 2013 Oleksandr Kravchenko <x0199363@ti.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define BMA180_DRV_NAME "bma180"
+#define BMA180_IRQ_NAME "bma180_event"
+
+/* Register set */
+#define BMA180_CHIP_ID		0x00 /* Need to distinguish BMA180 from other */
+#define BMA180_ACC_X_LSB	0x02 /* First of 6 registers of accel data */
+#define BMA180_CTRL_REG0	0x0d
+#define BMA180_RESET		0x10
+#define BMA180_BW_TCS		0x20
+#define BMA180_CTRL_REG3	0x21
+#define BMA180_TCO_Z		0x30
+#define BMA180_OFFSET_LSB1	0x35
+
+/* BMA180_CTRL_REG0 bits */
+#define BMA180_DIS_WAKE_UP	BIT(0) /* Disable wake up mode */
+#define BMA180_SLEEP		BIT(1) /* 1 - chip will sleep */
+#define BMA180_EE_W		BIT(4) /* Unlock writing to addr from 0x20 */
+#define BMA180_RESET_INT	BIT(6) /* Reset pending interrupts */
+
+/* BMA180_CTRL_REG3 bits */
+#define BMA180_NEW_DATA_INT	BIT(1) /* Intr every new accel data is ready */
+
+/* BMA180_OFFSET_LSB1 skipping mode bit */
+#define BMA180_SMP_SKIP		BIT(0)
+
+/* Bit masks for registers bit fields */
+#define BMA180_RANGE		0x0e /* Range of measured accel values*/
+#define BMA180_BW		0xf0 /* Accel bandwidth */
+#define BMA180_MODE_CONFIG	0x03 /* Config operation modes */
+
+/* We have to write this value in reset register to do soft reset */
+#define BMA180_RESET_VAL	0xb6
+
+#define BMA_180_ID_REG_VAL	0x03
+
+/* Chip power modes */
+#define BMA180_LOW_NOISE	0x00
+#define BMA180_LOW_POWER	0x03
+
+#define BMA180_LOW_NOISE_STR	"low_noise"
+#define BMA180_LOW_POWER_STR	"low_power"
+
+/* Defaults values */
+#define BMA180_DEF_PMODE	0
+#define BMA180_DEF_BW		20
+#define BMA180_DEF_SCALE	250
+
+/* Available values for sysfs */
+#define BMA180_FLP_FREQ_AVAILABLE \
+	"10 20 40 75 150 300"
+#define BMA180_SCALE_AVAILABLE \
+	"0.000130 0.000190 0.000250 0.000380 0.000500 0.000990 0.001980"
+
+struct bma180_data {
+	struct i2c_client *client;
+	struct iio_trigger *trig;
+	struct mutex mutex;
+	int sleep_state;
+	int scale;
+	int bw;
+	int pmode;
+	char *buff;
+};
+
+enum bma180_axis {
+	AXIS_X,
+	AXIS_Y,
+	AXIS_Z,
+};
+
+static int bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
+static int scale_table[] = { 130, 190, 250, 380, 500, 990, 1980 };
+
+static int bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis)
+{
+	u8 reg = BMA180_ACC_X_LSB + axis * 2;
+	int ret;
+
+	if (data->sleep_state)
+		return -EBUSY;
+
+	ret = i2c_smbus_read_word_data(data->client, reg);
+	if (ret < 0)
+		dev_err(&data->client->dev,
+			"failed to read accel_%c registers\n", 'x' + axis);
+
+	return ret;
+}
+
+static int bma180_set_bits(struct bma180_data *data, u8 reg, u8 mask, u8 val)
+{
+	int ret = i2c_smbus_read_byte_data(data->client, reg);
+	u8 reg_val = (ret & ~mask) | (val << (ffs(mask) - 1));
+
+	if (ret < 0)
+		return ret;
+
+	return i2c_smbus_write_byte_data(data->client, reg, reg_val);
+}
+
+static int bma180_reset_intr(struct bma180_data *data)
+{
+	int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_RESET_INT, 1);
+
+	if (ret)
+		dev_err(&data->client->dev, "failed to reset interrupt\n");
+
+	return ret;
+}
+
+static int bma180_set_new_data_intr_state(struct bma180_data *data, int state)
+{
+	u8 reg_val = state ? BMA180_NEW_DATA_INT : 0x00;
+	int ret = i2c_smbus_write_byte_data(data->client, BMA180_CTRL_REG3,
+			reg_val);
+
+	if (ret)
+		goto err;
+	ret = bma180_reset_intr(data);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	dev_err(&data->client->dev,
+		"failed to set new data interrupt state %d\n", state);
+	return ret;
+}
+
+static int bma180_set_sleep_state(struct bma180_data *data, int state)
+{
+	int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_SLEEP, state);
+
+	if (ret) {
+		dev_err(&data->client->dev,
+			"failed to set sleep state %d\n", state);
+		return ret;
+	}
+	data->sleep_state = state;
+
+	return 0;
+}
+
+static int bma180_set_ee_writing_state(struct bma180_data *data, int state)
+{
+	int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_EE_W, state);
+
+	if (ret)
+		dev_err(&data->client->dev,
+			"failed to set ee writing state %d\n", state);
+
+	return ret;
+}
+
+static int bma180_set_bw(struct bma180_data *data, int val)
+{
+	int ret, i;
+
+	if (data->sleep_state)
+		return -EBUSY;
+
+	for (i = 0; i < ARRAY_SIZE(bw_table); ++i) {
+		if (bw_table[i] == val) {
+			ret = bma180_set_bits(data,
+					BMA180_BW_TCS, BMA180_BW, i);
+			if (ret) {
+				dev_err(&data->client->dev,
+					"failed to set bandwidth\n");
+				return ret;
+			}
+			data->bw = val;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int bma180_set_scale(struct bma180_data *data, int val)
+{
+	int ret, i;
+
+	if (data->sleep_state)
+		return -EBUSY;
+
+	for (i = 0; i < ARRAY_SIZE(scale_table); ++i)
+		if (scale_table[i] == val) {
+			ret = bma180_set_bits(data,
+					BMA180_OFFSET_LSB1, BMA180_RANGE, i);
+			if (ret) {
+				dev_err(&data->client->dev,
+					"failed to set scale\n");
+				return ret;
+			}
+			data->scale = val;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static int bma180_set_pmode(struct bma180_data *data, int mode)
+{
+	u8 reg_val = mode ? BMA180_LOW_POWER : BMA180_LOW_NOISE;
+	int ret = bma180_set_bits(data, BMA180_TCO_Z, BMA180_MODE_CONFIG,
+			reg_val);
+
+	if (ret) {
+		dev_err(&data->client->dev, "failed to set power mode\n");
+		return ret;
+	}
+	data->pmode = mode;
+
+	return 0;
+}
+
+static int bma180_soft_reset(struct bma180_data *data)
+{
+	int ret = i2c_smbus_write_byte_data(data->client,
+			BMA180_RESET, BMA180_RESET_VAL);
+
+	if (ret)
+		dev_err(&data->client->dev, "failed to reset the chip\n");
+
+	return ret;
+}
+
+static int bma180_chip_init(struct bma180_data *data)
+{
+	/* Try to read chip_id register. It must return 0x03. */
+	int ret = i2c_smbus_read_byte_data(data->client, BMA180_CHIP_ID);
+
+	if (ret < 0)
+		goto err;
+	if (ret != BMA_180_ID_REG_VAL) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = bma180_soft_reset(data);
+	if (ret)
+		goto err;
+	/*
+	 * No serial transaction should occur within minimum 10 us
+	 * after soft_reset command
+	 */
+	msleep(20);
+
+	ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1);
+	if (ret)
+		goto err;
+	ret = bma180_set_ee_writing_state(data, 1);
+	if (ret)
+		goto err;
+	ret = bma180_set_new_data_intr_state(data, 0);
+	if (ret)
+		goto err;
+	ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_SMP_SKIP, 1);
+	if (ret)
+		goto err;
+	ret = bma180_set_pmode(data, BMA180_DEF_PMODE);
+	if (ret)
+		goto err;
+	ret = bma180_set_bw(data, BMA180_DEF_BW);
+	if (ret)
+		goto err;
+	ret = bma180_set_scale(data, BMA180_DEF_SCALE);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	dev_err(&data->client->dev, "failed to init the chip\n");
+	return ret;
+}
+
+static void bma180_chip_disable(struct bma180_data *data)
+{
+	if (bma180_set_new_data_intr_state(data, 0))
+		goto err;
+	if (bma180_set_ee_writing_state(data, 0))
+		goto err;
+	if (bma180_set_sleep_state(data, 1))
+		goto err;
+
+	return;
+
+err:
+	dev_err(&data->client->dev, "failed to disable the chip\n");
+}
+
+static IIO_CONST_ATTR(in_accel_filter_low_pass_3db_frequency_available,
+		BMA180_FLP_FREQ_AVAILABLE);
+static IIO_CONST_ATTR(in_accel_scale_available, BMA180_SCALE_AVAILABLE);
+
+static struct attribute *bma180_attributes[] = {
+	&iio_const_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group bma180_attrs_group = {
+	.attrs = bma180_attributes,
+};
+
+static int bma180_read_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan, int *val, int *val2,
+		long mask)
+{
+	struct bma180_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->mutex);
+		if (iio_buffer_enabled(indio_dev))
+			ret = -EBUSY;
+		else
+			ret = bma180_get_acc_reg(data, chan->scan_index);
+		mutex_unlock(&data->mutex);
+		if (ret < 0)
+			return ret;
+		*val = (s16)ret >> chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		*val = data->bw;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = data->scale;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int bma180_write_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct bma180_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (val)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = bma180_set_scale(data, val2);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		mutex_lock(&data->mutex);
+		ret = bma180_set_bw(data, val);
+		mutex_unlock(&data->mutex);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int bma180_update_scan_mode(struct iio_dev *indio_dev,
+		const unsigned long *scan_mask)
+{
+	struct bma180_data *data = iio_priv(indio_dev);
+
+	if (data->buff)
+		devm_kfree(&indio_dev->dev, data->buff);
+	data->buff = devm_kzalloc(&indio_dev->dev,
+			indio_dev->scan_bytes, GFP_KERNEL);
+	if (!data->buff)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static const struct iio_info bma180_info = {
+	.attrs			= &bma180_attrs_group,
+	.read_raw		= bma180_read_raw,
+	.write_raw		= bma180_write_raw,
+	.update_scan_mode	= bma180_update_scan_mode,
+	.driver_module		= THIS_MODULE,
+};
+
+static const char * const bma180_power_modes[] = {
+	BMA180_LOW_NOISE_STR,
+	BMA180_LOW_POWER_STR,
+};
+
+static int bma180_get_power_mode(struct iio_dev *indio_dev,
+		const struct iio_chan_spec *chan)
+{
+	struct bma180_data *data = iio_priv(indio_dev);
+
+	return data->pmode;
+}
+
+static int bma180_set_power_mode(struct iio_dev *indio_dev,
+		const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct bma180_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bma180_set_pmode(data, mode);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static const struct iio_enum bma180_power_mode_enum = {
+	.items = bma180_power_modes,
+	.num_items = ARRAY_SIZE(bma180_power_modes),
+	.get = bma180_get_power_mode,
+	.set = bma180_set_power_mode,
+};
+
+static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
+	IIO_ENUM("power_mode", true, &bma180_power_mode_enum),
+	IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum),
+	{ },
+};
+
+#define BMA180_CHANNEL(_index) {					\
+	.type = IIO_ACCEL,						\
+	.indexed = 1,							\
+	.channel = (_index),						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
+		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),	\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
+	.scan_index = (_index),						\
+	.scan_type = IIO_ST('s', 14, 16, 2),				\
+	.ext_info = bma180_ext_info,					\
+}
+
+static const struct iio_chan_spec bma180_channels[] = {
+	BMA180_CHANNEL(AXIS_X),
+	BMA180_CHANNEL(AXIS_Y),
+	BMA180_CHANNEL(AXIS_Z),
+	IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static irqreturn_t bma180_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct bma180_data *data = iio_priv(indio_dev);
+	int bit, ret, i = 0;
+
+	mutex_lock(&data->mutex);
+	if (indio_dev->scan_timestamp) {
+		ret = indio_dev->scan_bytes / sizeof(s64) - 1;
+		((s64 *)data->buff)[ret] = iio_get_time_ns();
+	}
+
+	for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+			 indio_dev->masklength) {
+		ret = bma180_get_acc_reg(data, bit);
+		if (ret < 0) {
+			mutex_unlock(&data->mutex);
+			goto err;
+		}
+		((s16 *)data->buff)[i++] = ret;
+	}
+	mutex_unlock(&data->mutex);
+
+	iio_push_to_buffers(indio_dev, (u8 *)data->buff);
+err:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int bma180_data_rdy_trigger_set_state(struct iio_trigger *trig,
+		bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct bma180_data *data = iio_priv(indio_dev);
+
+	return bma180_set_new_data_intr_state(data, state);
+}
+
+static int bma180_trig_try_reen(struct iio_trigger *trig)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct bma180_data *data = iio_priv(indio_dev);
+
+	return bma180_reset_intr(data);
+}
+
+static const struct iio_trigger_ops bma180_trigger_ops = {
+	.set_trigger_state = bma180_data_rdy_trigger_set_state,
+	.try_reenable = bma180_trig_try_reen,
+	.owner = THIS_MODULE,
+};
+
+static int bma180_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct bma180_data *data;
+	struct iio_dev *indio_dev;
+	struct iio_trigger *trig;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	ret = bma180_chip_init(data);
+	if (ret < 0)
+		goto err_chip_disable;
+
+	mutex_init(&data->mutex);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = bma180_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bma180_channels);
+	indio_dev->name = BMA180_DRV_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &bma180_info;
+
+	trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, indio_dev->id);
+	if (!trig) {
+		ret = -ENOMEM;
+		goto err_chip_disable;
+	}
+
+	ret = devm_request_irq(&client->dev, client->irq,
+			iio_trigger_generic_data_rdy_poll,
+			IRQF_TRIGGER_RISING, BMA180_IRQ_NAME, trig);
+	if (ret) {
+		dev_err(&client->dev, "unable to request IRQ\n");
+		goto err_trigger_free;
+	}
+
+	trig->dev.parent = &client->dev;
+	trig->ops = &bma180_trigger_ops;
+	iio_trigger_set_drvdata(trig, indio_dev);
+	data->trig = trig;
+	indio_dev->trig = trig;
+
+	ret = iio_trigger_register(trig);
+	if (ret)
+		goto err_trigger_free;
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+			bma180_trigger_handler, NULL);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to setup iio triggered buffer\n");
+		goto err_trigger_unregister;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to register iio device\n");
+		goto err_buffer_cleanup;
+	}
+
+	return 0;
+
+err_buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
+err_trigger_unregister:
+	iio_trigger_unregister(trig);
+err_trigger_free:
+	iio_trigger_free(trig);
+err_chip_disable:
+	bma180_chip_disable(data);
+
+	return ret;
+}
+
+static int bma180_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct bma180_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+	iio_trigger_unregister(data->trig);
+	iio_trigger_free(data->trig);
+
+	mutex_lock(&data->mutex);
+	bma180_chip_disable(data);
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bma180_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct bma180_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bma180_set_sleep_state(data, 1);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int bma180_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct bma180_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bma180_set_sleep_state(data, 0);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
+#define BMA180_PM_OPS (&bma180_pm_ops)
+#else
+#define BMA180_PM_OPS NULL
+#endif
+
+static struct i2c_device_id bma180_id[] = {
+	{ BMA180_DRV_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, bma180_id);
+
+static struct i2c_driver bma180_driver = {
+	.driver = {
+		.name	= BMA180_DRV_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= BMA180_PM_OPS,
+	},
+	.probe		= bma180_probe,
+	.remove		= bma180_remove,
+	.id_table	= bma180_id,
+};
+
+module_i2c_driver(bma180_driver);
+
+MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Bosch BMA180 triaxial acceleration sensor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index bbcbd71..46d22f3 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -30,10 +30,6 @@
 #include <linux/iio/triggered_buffer.h>
 #include "../common/hid-sensors/hid-sensor-trigger.h"
 
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Accelerometer-3D: 0x200073*/
-#define DRIVER_NAME "HID-SENSOR-200073"
-
 enum accel_3d_channel {
 	CHANNEL_SCAN_INDEX_X,
 	CHANNEL_SCAN_INDEX_Y,
@@ -179,18 +175,10 @@
 	return ret;
 }
 
-static int accel_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       long mask)
-{
-	return IIO_VAL_INT_PLUS_MICRO;
-}
-
 static const struct iio_info accel_3d_info = {
 	.driver_module = THIS_MODULE,
 	.read_raw = &accel_3d_read_raw,
 	.write_raw = &accel_3d_write_raw,
-	.write_raw_get_fmt = &accel_3d_write_raw_get_fmt,
 };
 
 /* Function to push data to buffer */
@@ -286,11 +274,11 @@
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 	struct iio_chan_spec *channels;
 
-	indio_dev = iio_device_alloc(sizeof(struct accel_3d_state));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					  sizeof(struct accel_3d_state));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
 	platform_set_drvdata(pdev, indio_dev);
 
 	accel_state = iio_priv(indio_dev);
@@ -302,15 +290,14 @@
 					&accel_state->common_attributes);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup common attributes\n");
-		goto error_free_dev;
+		return ret;
 	}
 
 	channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
 			   GFP_KERNEL);
 	if (!channels) {
-		ret = -ENOMEM;
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
-		goto error_free_dev;
+		return -ENOMEM;
 	}
 
 	ret = accel_3d_parse_report(pdev, hsdev, channels,
@@ -367,9 +354,6 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 error_free_dev_mem:
 	kfree(indio_dev->channels);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -384,14 +368,23 @@
 	hid_sensor_remove_trigger(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	kfree(indio_dev->channels);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
 
+static struct platform_device_id hid_accel_3d_ids[] = {
+	{
+		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+		.name = "HID-SENSOR-200073",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
+
 static struct platform_driver hid_accel_3d_platform_driver = {
+	.id_table = hid_accel_3d_ids,
 	.driver = {
-		.name	= DRIVER_NAME,
+		.name	= KBUILD_MODNAME,
 		.owner	= THIS_MODULE,
 	},
 	.probe		= hid_accel_3d_probe,
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index 7229645..709c132 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -224,11 +224,10 @@
 	struct kxsd9_state *st;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
 	st = iio_priv(indio_dev);
 	spi_set_drvdata(spi, indio_dev);
 
@@ -247,20 +246,14 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
 }
 
 static int kxsd9_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index 37949b9..c387763 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -25,7 +25,16 @@
 #define LSM303DLM_ACCEL_DEV_NAME	"lsm303dlm_accel"
 #define LSM330_ACCEL_DEV_NAME		"lsm330_accel"
 
-int st_accel_common_probe(struct iio_dev *indio_dev);
+/**
+* struct st_sensors_platform_data - default accel platform data
+* @drdy_int_pin: default accel DRDY is available on INT1 pin.
+*/
+static const struct st_sensors_platform_data default_accel_pdata = {
+	.drdy_int_pin = 1,
+};
+
+int st_accel_common_probe(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata);
 void st_accel_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 4aec1212..1458343 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -65,7 +65,8 @@
 #define ST_ACCEL_1_BDU_ADDR			0x23
 #define ST_ACCEL_1_BDU_MASK			0x80
 #define ST_ACCEL_1_DRDY_IRQ_ADDR		0x22
-#define ST_ACCEL_1_DRDY_IRQ_MASK		0x10
+#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK		0x10
+#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK		0x08
 #define ST_ACCEL_1_MULTIREAD_BIT		true
 
 /* CUSTOM VALUES FOR SENSOR 2 */
@@ -89,7 +90,8 @@
 #define ST_ACCEL_2_BDU_ADDR			0x23
 #define ST_ACCEL_2_BDU_MASK			0x80
 #define ST_ACCEL_2_DRDY_IRQ_ADDR		0x22
-#define ST_ACCEL_2_DRDY_IRQ_MASK		0x02
+#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK		0x02
+#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK		0x10
 #define ST_ACCEL_2_MULTIREAD_BIT		true
 
 /* CUSTOM VALUES FOR SENSOR 3 */
@@ -121,7 +123,8 @@
 #define ST_ACCEL_3_BDU_ADDR			0x20
 #define ST_ACCEL_3_BDU_MASK			0x08
 #define ST_ACCEL_3_DRDY_IRQ_ADDR		0x23
-#define ST_ACCEL_3_DRDY_IRQ_MASK		0x80
+#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK		0x80
+#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK		0x00
 #define ST_ACCEL_3_IG1_EN_ADDR			0x23
 #define ST_ACCEL_3_IG1_EN_MASK			0x08
 #define ST_ACCEL_3_MULTIREAD_BIT		false
@@ -224,7 +227,8 @@
 		},
 		.drdy_irq = {
 			.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
-			.mask = ST_ACCEL_1_DRDY_IRQ_MASK,
+			.mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
 		},
 		.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
 		.bootime = 2,
@@ -285,7 +289,8 @@
 		},
 		.drdy_irq = {
 			.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
-			.mask = ST_ACCEL_2_DRDY_IRQ_MASK,
+			.mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
 		},
 		.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
 		.bootime = 2,
@@ -358,7 +363,8 @@
 		},
 		.drdy_irq = {
 			.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
-			.mask = ST_ACCEL_3_DRDY_IRQ_MASK,
+			.mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
 			.ig1 = {
 				.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
 				.en_mask = ST_ACCEL_3_IG1_EN_MASK,
@@ -443,7 +449,8 @@
 #define ST_ACCEL_TRIGGER_OPS NULL
 #endif
 
-int st_accel_common_probe(struct iio_dev *indio_dev)
+int st_accel_common_probe(struct iio_dev *indio_dev,
+				struct st_sensors_platform_data *plat_data)
 {
 	int err;
 	struct st_sensor_data *adata = iio_priv(indio_dev);
@@ -465,7 +472,11 @@
 						&adata->sensor->fs.fs_avl[0];
 	adata->odr = adata->sensor->odr.odr_avl[0].hz;
 
-	err = st_sensors_init_sensor(indio_dev);
+	if (!plat_data)
+		plat_data =
+			(struct st_sensors_platform_data *)&default_accel_pdata;
+
+	err = st_sensors_init_sensor(indio_dev, plat_data);
 	if (err < 0)
 		goto st_accel_common_probe_error;
 
@@ -506,7 +517,6 @@
 		st_sensors_deallocate_trigger(indio_dev);
 		st_accel_deallocate_ring(indio_dev);
 	}
-	iio_device_free(indio_dev);
 }
 EXPORT_SYMBOL(st_accel_common_remove);
 
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index ffc9d09..d7bedbd 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -25,27 +25,20 @@
 	struct st_sensor_data *adata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*adata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	adata = iio_priv(indio_dev);
 	adata->dev = &client->dev;
 
 	st_sensors_i2c_configure(indio_dev, client, adata);
 
-	err = st_accel_common_probe(indio_dev);
+	err = st_accel_common_probe(indio_dev, client->dev.platform_data);
 	if (err < 0)
-		goto st_accel_common_probe_error;
+		return err;
 
 	return 0;
-
-st_accel_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_accel_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 22b35bf..1956396 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -24,27 +24,20 @@
 	struct st_sensor_data *adata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*adata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	adata = iio_priv(indio_dev);
 	adata->dev = &spi->dev;
 
 	st_sensors_spi_configure(indio_dev, spi, adata);
 
-	err = st_accel_common_probe(indio_dev);
+	err = st_accel_common_probe(indio_dev, spi->dev.platform_data);
 	if (err < 0)
-		goto st_accel_common_probe_error;
+		return err;
 
 	return 0;
-
-st_accel_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_accel_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 93129ec..09371cb 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1,6 +1,8 @@
 #
 # ADC drivers
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Analog to digital converters"
 
 config AD_SIGMA_DELTA
@@ -30,17 +32,20 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7298.
 
-config AD7923
-	tristate "Analog Devices AD7923 and similar ADCs driver"
+config AD7476
+	tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
 	depends on SPI
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	help
-	  Say yes here to build support for Analog Devices
-	  AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
+	  Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
+	  AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
+	  AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
+
+	  If unsure, say N (but it's safe to say "Y").
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called ad7923.
+	  module will be called ad7476.
 
 config AD7791
 	tristate "Analog Devices AD7791 ADC driver"
@@ -66,21 +71,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called AD7793.
 
-config AD7476
-	tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
-	depends on SPI
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
-	help
-	  Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
-	  AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
-	  AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
-
-	  If unsure, say N (but it's safe to say "Y").
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad7476.
-
 config AD7887
 	tristate "Analog Devices AD7887 ADC driver"
 	depends on SPI
@@ -94,6 +84,18 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7887.
 
+config AD7923
+	tristate "Analog Devices AD7923 and similar ADCs driver"
+	depends on SPI
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for Analog Devices
+	  AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7923.
+
 config AT91_ADC
 	tristate "Atmel AT91 ADC"
 	depends on ARCH_AT91
@@ -143,6 +145,15 @@
 	  This driver can also be built as a module. If so, the module will be
 	  called mcp320x.
 
+config NAU7802
+	tristate "Nuvoton NAU7802 ADC driver"
+	depends on I2C
+	help
+	  Say yes here to build support for Nuvoton NAU7802 ADC.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nau7802.
+
 config TI_ADC081C
 	tristate "Texas Instruments ADC081C021/027"
 	depends on I2C
@@ -154,12 +165,26 @@
 	  called ti-adc081c.
 
 config TI_AM335X_ADC
-	tristate "TI's ADC driver"
+	tristate "TI's AM335X ADC driver"
 	depends on MFD_TI_AM335X_TSCADC
 	help
 	  Say yes here to build support for Texas Instruments ADC
 	  driver which is also a MFD client.
 
+config TWL6030_GPADC
+	tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
+	depends on TWL4030_CORE
+	default n
+	help
+	  Say yes here if you want support for the TWL6030/TWL6032 General
+	  Purpose A/D Converter. This will add support for battery type
+	  detection, battery voltage and temperature measurement, die
+	  temperature measurement, system supply voltage, audio accessory,
+	  USB ID detection.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called twl6030-gpadc.
+
 config VIPERBOARD_ADC
 	tristate "Viperboard ADC support"
 	depends on MFD_VIPERBOARD && USB
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 8f475d31..33656ef 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -2,6 +2,7 @@
 # Makefile for IIO ADC drivers
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
 obj-$(CONFIG_AD7266) += ad7266.o
 obj-$(CONFIG_AD7298) += ad7298.o
@@ -15,6 +16,8 @@
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
+obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
 obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index c2744a7..371731d 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -399,17 +399,17 @@
 	unsigned int i;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
-	st->reg = regulator_get(&spi->dev, "vref");
+	st->reg = devm_regulator_get(&spi->dev, "vref");
 	if (!IS_ERR_OR_NULL(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 
 		ret = regulator_get_voltage(st->reg);
 		if (ret < 0)
@@ -489,11 +489,6 @@
 error_disable_reg:
 	if (!IS_ERR_OR_NULL(st->reg))
 		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR_OR_NULL(st->reg))
-		regulator_put(st->reg);
-
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -507,11 +502,8 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 	if (!st->fixed_addr)
 		gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
-	if (!IS_ERR_OR_NULL(st->reg)) {
+	if (!IS_ERR_OR_NULL(st->reg))
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index 03b7718..85d1481 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -296,9 +296,10 @@
 {
 	struct ad7298_platform_data *pdata = spi->dev.platform_data;
 	struct ad7298_state *st;
-	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+	struct iio_dev *indio_dev;
 	int ret;
 
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -308,14 +309,13 @@
 		st->ext_ref = AD7298_EXTREF;
 
 	if (st->ext_ref) {
-		st->reg = regulator_get(&spi->dev, "vref");
-		if (IS_ERR(st->reg)) {
-			ret = PTR_ERR(st->reg);
-			goto error_free;
-		}
+		st->reg = devm_regulator_get(&spi->dev, "vref");
+		if (IS_ERR(st->reg))
+			return PTR_ERR(st->reg);
+
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 	}
 
 	spi_set_drvdata(spi, indio_dev);
@@ -361,11 +361,6 @@
 error_disable_reg:
 	if (st->ext_ref)
 		regulator_disable(st->reg);
-error_put_reg:
-	if (st->ext_ref)
-		regulator_put(st->reg);
-error_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -377,11 +372,8 @@
 
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
-	if (st->ext_ref) {
+	if (st->ext_ref)
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 2e98bef4..6d2b1d8 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -213,24 +213,21 @@
 	struct iio_dev *indio_dev;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
 	st = iio_priv(indio_dev);
 	st->chip_info =
 		&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-	st->reg = regulator_get(&spi->dev, "vcc");
-	if (IS_ERR(st->reg)) {
-		ret = PTR_ERR(st->reg);
-		goto error_free_dev;
-	}
+	st->reg = devm_regulator_get(&spi->dev, "vcc");
+	if (IS_ERR(st->reg))
+		return PTR_ERR(st->reg);
 
 	ret = regulator_enable(st->reg);
 	if (ret)
-		goto error_put_reg;
+		return ret;
 
 	spi_set_drvdata(spi, indio_dev);
 
@@ -268,12 +265,7 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 error_disable_reg:
 	regulator_disable(st->reg);
-error_put_reg:
-	regulator_put(st->reg);
-error_free_dev:
-	iio_device_free(indio_dev);
 
-error_ret:
 	return ret;
 }
 
@@ -285,8 +277,6 @@
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	regulator_disable(st->reg);
-	regulator_put(st->reg);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c
index 5e8d1da..c202035 100644
--- a/drivers/iio/adc/ad7791.c
+++ b/drivers/iio/adc/ad7791.c
@@ -361,21 +361,19 @@
 		return -ENXIO;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (!indio_dev)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
-	st->reg = regulator_get(&spi->dev, "refin");
-	if (IS_ERR(st->reg)) {
-		ret = PTR_ERR(st->reg);
-		goto err_iio_free;
-	}
+	st->reg = devm_regulator_get(&spi->dev, "refin");
+	if (IS_ERR(st->reg))
+		return PTR_ERR(st->reg);
 
 	ret = regulator_enable(st->reg);
 	if (ret)
-		goto error_put_reg;
+		return ret;
 
 	st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
 	ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
@@ -410,10 +408,6 @@
 	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 error_disable_reg:
 	regulator_disable(st->reg);
-error_put_reg:
-	regulator_put(st->reg);
-err_iio_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -427,9 +421,6 @@
 	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 
 	regulator_disable(st->reg);
-	regulator_put(st->reg);
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index 334e31f..4dddeab 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -757,7 +757,7 @@
 		return -ENODEV;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -766,15 +766,13 @@
 	ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info);
 
 	if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
-		st->reg = regulator_get(&spi->dev, "refin");
-		if (IS_ERR(st->reg)) {
-			ret = PTR_ERR(st->reg);
-			goto error_device_free;
-		}
+		st->reg = devm_regulator_get(&spi->dev, "refin");
+		if (IS_ERR(st->reg))
+			return PTR_ERR(st->reg);
 
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 
 		vref_mv = regulator_get_voltage(st->reg);
 		if (vref_mv < 0) {
@@ -818,11 +816,6 @@
 error_disable_reg:
 	if (pdata->refsel != AD7793_REFSEL_INTERNAL)
 		regulator_disable(st->reg);
-error_put_reg:
-	if (pdata->refsel != AD7793_REFSEL_INTERNAL)
-		regulator_put(st->reg);
-error_device_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -836,12 +829,8 @@
 	iio_device_unregister(indio_dev);
 	ad_sd_cleanup_buffer_and_trigger(indio_dev);
 
-	if (pdata->refsel != AD7793_REFSEL_INTERNAL) {
+	if (pdata->refsel != AD7793_REFSEL_INTERNAL)
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index dd15a5b..9dd077b 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -237,25 +237,24 @@
 {
 	struct ad7887_platform_data *pdata = spi->dev.platform_data;
 	struct ad7887_state *st;
-	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+	struct iio_dev *indio_dev;
 	uint8_t mode;
 	int ret;
 
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
 	if (!pdata || !pdata->use_onchip_ref) {
-		st->reg = regulator_get(&spi->dev, "vref");
-		if (IS_ERR(st->reg)) {
-			ret = PTR_ERR(st->reg);
-			goto error_free;
-		}
+		st->reg = devm_regulator_get(&spi->dev, "vref");
+		if (IS_ERR(st->reg))
+			return PTR_ERR(st->reg);
 
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 	}
 
 	st->chip_info =
@@ -331,11 +330,6 @@
 error_disable_reg:
 	if (st->reg)
 		regulator_disable(st->reg);
-error_put_reg:
-	if (st->reg)
-		regulator_put(st->reg);
-error_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -347,11 +341,8 @@
 
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
-	if (st->reg) {
+	if (st->reg)
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
index 97fa0d3..4108dbb 100644
--- a/drivers/iio/adc/ad7923.c
+++ b/drivers/iio/adc/ad7923.c
@@ -275,10 +275,11 @@
 static int ad7923_probe(struct spi_device *spi)
 {
 	struct ad7923_state *st;
-	struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+	struct iio_dev *indio_dev;
 	const struct ad7923_chip_info *info;
 	int ret;
 
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -311,14 +312,13 @@
 	spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
 	spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
 
-	st->reg = regulator_get(&spi->dev, "refin");
-	if (IS_ERR(st->reg)) {
-		ret = PTR_ERR(st->reg);
-		goto error_free;
-	}
+	st->reg = devm_regulator_get(&spi->dev, "refin");
+	if (IS_ERR(st->reg))
+		return PTR_ERR(st->reg);
+
 	ret = regulator_enable(st->reg);
 	if (ret)
-		goto error_put_reg;
+		return ret;
 
 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
 			&ad7923_trigger_handler, NULL);
@@ -335,10 +335,6 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 error_disable_reg:
 	regulator_disable(st->reg);
-error_put_reg:
-	regulator_put(st->reg);
-error_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -351,8 +347,6 @@
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	regulator_disable(st->reg);
-	regulator_put(st->reg);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index b6db6a0..84be63b 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -39,6 +39,10 @@
 #define at91_adc_writel(st, reg, val) \
 	(writel_relaxed(val, st->reg_base + reg))
 
+struct at91_adc_caps {
+	struct at91_adc_reg_desc registers;
+};
+
 struct at91_adc_state {
 	struct clk		*adc_clk;
 	u16			*buffer;
@@ -62,6 +66,7 @@
 	u32			res;		/* resolution used for convertions */
 	bool			low_res;	/* the resolution corresponds to the lowest one */
 	wait_queue_head_t	wq_data_avail;
+	struct at91_adc_caps	*caps;
 };
 
 static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
@@ -429,6 +434,8 @@
 	return ret;
 }
 
+static const struct of_device_id at91_adc_dt_ids[];
+
 static int at91_adc_probe_dt(struct at91_adc_state *st,
 			     struct platform_device *pdev)
 {
@@ -441,6 +448,9 @@
 	if (!node)
 		return -EINVAL;
 
+	st->caps = (struct at91_adc_caps *)
+		of_match_device(at91_adc_dt_ids, &pdev->dev)->data;
+
 	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
 
 	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
@@ -481,43 +491,7 @@
 	if (ret)
 		goto error_ret;
 
-	st->registers = devm_kzalloc(&idev->dev,
-				     sizeof(struct at91_adc_reg_desc),
-				     GFP_KERNEL);
-	if (!st->registers) {
-		dev_err(&idev->dev, "Could not allocate register memory.\n");
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-
-	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
-		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->channel_base = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
-		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->drdy_mask = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->status_register = prop;
-
-	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
-		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
-		ret = -EINVAL;
-		goto error_ret;
-	}
-	st->registers->trigger_register = prop;
-
+	st->registers = &st->caps->registers;
 	st->trigger_number = of_get_child_count(node);
 	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
 					sizeof(struct at91_adc_trigger),
@@ -589,11 +563,9 @@
 	struct resource *res;
 	u32 reg;
 
-	idev = iio_device_alloc(sizeof(struct at91_adc_state));
-	if (idev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state));
+	if (!idev)
+		return -ENOMEM;
 
 	st = iio_priv(idev);
 
@@ -604,8 +576,7 @@
 
 	if (ret) {
 		dev_err(&pdev->dev, "No platform data available.\n");
-		ret = -EINVAL;
-		goto error_free_device;
+		return -EINVAL;
 	}
 
 	platform_set_drvdata(pdev, idev);
@@ -618,16 +589,14 @@
 	st->irq = platform_get_irq(pdev, 0);
 	if (st->irq < 0) {
 		dev_err(&pdev->dev, "No IRQ ID is designated\n");
-		ret = -ENODEV;
-		goto error_free_device;
+		return -ENODEV;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	st->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(st->reg_base)) {
-		ret = PTR_ERR(st->reg_base);
-		goto error_free_device;
+		return PTR_ERR(st->reg_base);
 	}
 
 	/*
@@ -642,7 +611,7 @@
 			  idev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
-		goto error_free_device;
+		return ret;
 	}
 
 	st->clk = devm_clk_get(&pdev->dev, "adc_clk");
@@ -703,8 +672,8 @@
 	shtim = round_up((st->sample_hold_time * adc_clk /
 			  1000000) - 1, 1);
 
-	reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
-	reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
+	reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask;
+	reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask;
 	if (st->low_res)
 		reg |= AT91_ADC_LOWRES;
 	if (st->sleep_mode)
@@ -752,9 +721,6 @@
 	clk_disable_unprepare(st->clk);
 error_free_irq:
 	free_irq(st->irq, idev);
-error_free_device:
-	iio_device_free(idev);
-error_ret:
 	return ret;
 }
 
@@ -769,14 +735,49 @@
 	clk_disable_unprepare(st->adc_clk);
 	clk_disable_unprepare(st->clk);
 	free_irq(st->irq, idev);
-	iio_device_free(idev);
 
 	return 0;
 }
 
 #ifdef CONFIG_OF
+static struct at91_adc_caps at91sam9260_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9260,
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9260,
+		.mr_startup_mask = AT91_ADC_STARTUP_9260,
+	},
+};
+
+static struct at91_adc_caps at91sam9g45_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CHR(0),
+		.drdy_mask = AT91_ADC_DRDY,
+		.status_register = AT91_ADC_SR,
+		.trigger_register = AT91_ADC_TRGR_9G45,
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+		.mr_startup_mask = AT91_ADC_STARTUP_9G45,
+	},
+};
+
+static struct at91_adc_caps at91sam9x5_caps = {
+	.registers = {
+		.channel_base = AT91_ADC_CDR0_9X5,
+		.drdy_mask = AT91_ADC_SR_DRDY_9X5,
+		.status_register = AT91_ADC_SR_9X5,
+		.trigger_register = AT91_ADC_TRGR_9X5,
+		/* prescal mask is same as 9G45 */
+		.mr_prescal_mask = AT91_ADC_PRESCAL_9G45,
+		.mr_startup_mask = AT91_ADC_STARTUP_9X5,
+	},
+};
+
 static const struct of_device_id at91_adc_dt_ids[] = {
-	{ .compatible = "atmel,at91sam9260-adc" },
+	{ .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps },
+	{ .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps },
+	{ .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps },
 	{},
 };
 MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 9809fc9..d25b262 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -33,6 +33,7 @@
 #include <linux/of_irq.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of_platform.h>
+#include <linux/err.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/machine.h>
@@ -261,7 +262,7 @@
 	if (!np)
 		return ret;
 
-	indio_dev = iio_device_alloc(sizeof(struct exynos_adc));
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
 	if (!indio_dev) {
 		dev_err(&pdev->dev, "failed allocating iio device\n");
 		return -ENOMEM;
@@ -271,23 +272,18 @@
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	info->regs = devm_ioremap_resource(&pdev->dev, mem);
-	if (IS_ERR(info->regs)) {
-		ret = PTR_ERR(info->regs);
-		goto err_iio;
-	}
+	if (IS_ERR(info->regs))
+		return PTR_ERR(info->regs);
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
-	if (IS_ERR(info->enable_reg)) {
-		ret = PTR_ERR(info->enable_reg);
-		goto err_iio;
-	}
+	if (IS_ERR(info->enable_reg))
+		return PTR_ERR(info->enable_reg);
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		dev_err(&pdev->dev, "no irq resource?\n");
-		ret = irq;
-		goto err_iio;
+		return irq;
 	}
 
 	info->irq = irq;
@@ -299,7 +295,7 @@
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
 							info->irq);
-		goto err_iio;
+		return ret;
 	}
 
 	writel(1, info->enable_reg);
@@ -365,8 +361,6 @@
 	iio_device_unregister(indio_dev);
 err_irq:
 	free_irq(info->irq, info);
-err_iio:
-	iio_device_free(indio_dev);
 	return ret;
 }
 
@@ -382,7 +376,6 @@
 	writel(0, info->enable_reg);
 	iio_device_unregister(indio_dev);
 	free_irq(info->irq, info);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
index 62bc39e..5c8c915 100644
--- a/drivers/iio/adc/lp8788_adc.c
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -194,7 +194,7 @@
 	struct lp8788_adc *adc;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*adc));
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -205,7 +205,7 @@
 	indio_dev->dev.of_node = pdev->dev.of_node;
 	ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc);
 	if (ret)
-		goto err_iio_map;
+		return ret;
 
 	mutex_init(&adc->lock);
 
@@ -226,8 +226,6 @@
 
 err_iio_device:
 	iio_map_array_unregister(indio_dev);
-err_iio_map:
-	iio_device_free(indio_dev);
 	return ret;
 }
 
@@ -237,7 +235,6 @@
 
 	iio_device_unregister(indio_dev);
 	iio_map_array_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index f148d00..4fb35d1 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1498,16 +1498,15 @@
 	struct iio_dev *indio_dev;
 	struct regulator *vref;
 
-	indio_dev = iio_device_alloc(sizeof(struct max1363_state));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_out;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev,
+					  sizeof(struct max1363_state));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	indio_dev->dev.of_node = client->dev.of_node;
 	ret = iio_map_array_register(indio_dev, client->dev.platform_data);
 	if (ret < 0)
-		goto error_free_device;
+		return ret;
 
 	st = iio_priv(indio_dev);
 
@@ -1590,9 +1589,6 @@
 	regulator_disable(st->reg);
 error_unregister_map:
 	iio_map_array_unregister(indio_dev);
-error_free_device:
-	iio_device_free(indio_dev);
-error_out:
 	return ret;
 }
 
@@ -1607,7 +1603,6 @@
 		regulator_disable(st->vref);
 	regulator_disable(st->reg);
 	iio_map_array_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index ebc0159..28a086e 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -169,7 +169,7 @@
 	const struct mcp3208_chip_info *chip_info;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*adc));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -193,15 +193,13 @@
 	spi_message_init_with_transfers(&adc->msg, adc->transfer,
 					ARRAY_SIZE(adc->transfer));
 
-	adc->reg = regulator_get(&spi->dev, "vref");
-	if (IS_ERR(adc->reg)) {
-		ret = PTR_ERR(adc->reg);
-		goto iio_free;
-	}
+	adc->reg = devm_regulator_get(&spi->dev, "vref");
+	if (IS_ERR(adc->reg))
+		return PTR_ERR(adc->reg);
 
 	ret = regulator_enable(adc->reg);
 	if (ret < 0)
-		goto reg_free;
+		return ret;
 
 	mutex_init(&adc->lock);
 
@@ -213,10 +211,6 @@
 
 reg_disable:
 	regulator_disable(adc->reg);
-reg_free:
-	regulator_put(adc->reg);
-iio_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -228,8 +222,6 @@
 
 	iio_device_unregister(indio_dev);
 	regulator_disable(adc->reg);
-	regulator_put(adc->reg);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c
new file mode 100644
index 0000000..bdf0346
--- /dev/null
+++ b/drivers/iio/adc/nau7802.c
@@ -0,0 +1,581 @@
+/*
+ * Driver for the Nuvoton NAU7802 ADC
+ *
+ * Copyright 2013 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/log2.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define NAU7802_REG_PUCTRL	0x00
+#define NAU7802_PUCTRL_RR(x)		(x << 0)
+#define NAU7802_PUCTRL_RR_BIT		NAU7802_PUCTRL_RR(1)
+#define NAU7802_PUCTRL_PUD(x)		(x << 1)
+#define NAU7802_PUCTRL_PUD_BIT		NAU7802_PUCTRL_PUD(1)
+#define NAU7802_PUCTRL_PUA(x)		(x << 2)
+#define NAU7802_PUCTRL_PUA_BIT		NAU7802_PUCTRL_PUA(1)
+#define NAU7802_PUCTRL_PUR(x)		(x << 3)
+#define NAU7802_PUCTRL_PUR_BIT		NAU7802_PUCTRL_PUR(1)
+#define NAU7802_PUCTRL_CS(x)		(x << 4)
+#define NAU7802_PUCTRL_CS_BIT		NAU7802_PUCTRL_CS(1)
+#define NAU7802_PUCTRL_CR(x)		(x << 5)
+#define NAU7802_PUCTRL_CR_BIT		NAU7802_PUCTRL_CR(1)
+#define NAU7802_PUCTRL_AVDDS(x)		(x << 7)
+#define NAU7802_PUCTRL_AVDDS_BIT	NAU7802_PUCTRL_AVDDS(1)
+#define NAU7802_REG_CTRL1	0x01
+#define NAU7802_CTRL1_VLDO(x)		(x << 3)
+#define NAU7802_CTRL1_GAINS(x)		(x)
+#define NAU7802_CTRL1_GAINS_BITS	0x07
+#define NAU7802_REG_CTRL2	0x02
+#define NAU7802_CTRL2_CHS(x)		(x << 7)
+#define NAU7802_CTRL2_CRS(x)		(x << 4)
+#define NAU7802_SAMP_FREQ_320	0x07
+#define NAU7802_CTRL2_CHS_BIT		NAU7802_CTRL2_CHS(1)
+#define NAU7802_REG_ADC_B2	0x12
+#define NAU7802_REG_ADC_B1	0x13
+#define NAU7802_REG_ADC_B0	0x14
+#define NAU7802_REG_ADC_CTRL	0x15
+
+#define NAU7802_MIN_CONVERSIONS 6
+
+struct nau7802_state {
+	struct i2c_client	*client;
+	s32			last_value;
+	struct mutex		lock;
+	struct mutex		data_lock;
+	u32			vref_mv;
+	u32			conversion_count;
+	u32			min_conversions;
+	u8			sample_rate;
+	u32			scale_avail[8];
+	struct completion	value_ok;
+};
+
+#define NAU7802_CHANNEL(chan) {					\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.channel = (chan),					\
+	.scan_index = (chan),					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
+				BIT(IIO_CHAN_INFO_SAMP_FREQ)	\
+}
+
+static const struct iio_chan_spec nau7802_chan_array[] = {
+	NAU7802_CHANNEL(0),
+	NAU7802_CHANNEL(1),
+};
+
+static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80,
+						10, 10, 10, 320};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320");
+
+static struct attribute *nau7802_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group nau7802_attribute_group = {
+	.attrs = nau7802_attributes,
+};
+
+static int nau7802_set_gain(struct nau7802_state *st, int gain)
+{
+	int ret;
+
+	mutex_lock(&st->lock);
+	st->conversion_count = 0;
+
+	ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
+	if (ret < 0)
+		goto nau7802_sysfs_set_gain_out;
+	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
+					(ret & (~NAU7802_CTRL1_GAINS_BITS)) |
+					gain);
+
+nau7802_sysfs_set_gain_out:
+	mutex_unlock(&st->lock);
+
+	return ret;
+}
+
+static int nau7802_read_conversion(struct nau7802_state *st)
+{
+	int data;
+
+	mutex_lock(&st->data_lock);
+	data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B2);
+	if (data < 0)
+		goto nau7802_read_conversion_out;
+	st->last_value = data << 16;
+
+	data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B1);
+	if (data < 0)
+		goto nau7802_read_conversion_out;
+	st->last_value |= data << 8;
+
+	data = i2c_smbus_read_byte_data(st->client, NAU7802_REG_ADC_B0);
+	if (data < 0)
+		goto nau7802_read_conversion_out;
+	st->last_value |= data;
+
+	st->last_value = sign_extend32(st->last_value, 23);
+
+nau7802_read_conversion_out:
+	mutex_unlock(&st->data_lock);
+
+	return data;
+}
+
+/*
+ * Conversions are synchronised on the rising edge of NAU7802_PUCTRL_CS_BIT
+ */
+static int nau7802_sync(struct nau7802_state *st)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
+				ret | NAU7802_PUCTRL_CS_BIT);
+
+	return ret;
+}
+
+static irqreturn_t nau7802_eoc_trigger(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct nau7802_state *st = iio_priv(indio_dev);
+	int status;
+
+	status = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+	if (status < 0)
+		return IRQ_HANDLED;
+
+	if (!(status & NAU7802_PUCTRL_CR_BIT))
+		return IRQ_NONE;
+
+	if (nau7802_read_conversion(st) < 0)
+		return IRQ_HANDLED;
+
+	/*
+	 * Because there is actually only one ADC for both channels, we have to
+	 * wait for enough conversions to happen before getting a significant
+	 * value when changing channels and the values are far apart.
+	 */
+	if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
+		st->conversion_count++;
+	if (st->conversion_count >= NAU7802_MIN_CONVERSIONS)
+		complete_all(&st->value_ok);
+
+	return IRQ_HANDLED;
+}
+
+static int nau7802_read_irq(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val)
+{
+	struct nau7802_state *st = iio_priv(indio_dev);
+	int ret;
+
+	INIT_COMPLETION(st->value_ok);
+	enable_irq(st->client->irq);
+
+	nau7802_sync(st);
+
+	/* read registers to ensure we flush everything */
+	ret = nau7802_read_conversion(st);
+	if (ret < 0)
+		goto read_chan_info_failure;
+
+	/* Wait for a conversion to finish */
+	ret = wait_for_completion_interruptible_timeout(&st->value_ok,
+			msecs_to_jiffies(1000));
+	if (ret == 0)
+		ret = -ETIMEDOUT;
+
+	if (ret < 0)
+		goto read_chan_info_failure;
+
+	disable_irq(st->client->irq);
+
+	*val = st->last_value;
+
+	return IIO_VAL_INT;
+
+read_chan_info_failure:
+	disable_irq(st->client->irq);
+
+	return ret;
+}
+
+static int nau7802_read_poll(struct iio_dev *indio_dev,
+			struct iio_chan_spec const *chan,
+			int *val)
+{
+	struct nau7802_state *st = iio_priv(indio_dev);
+	int ret;
+
+	nau7802_sync(st);
+
+	/* read registers to ensure we flush everything */
+	ret = nau7802_read_conversion(st);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Because there is actually only one ADC for both channels, we have to
+	 * wait for enough conversions to happen before getting a significant
+	 * value when changing channels and the values are far appart.
+	 */
+	do {
+		ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+		if (ret < 0)
+			return ret;
+
+		while (!(ret & NAU7802_PUCTRL_CR_BIT)) {
+			if (st->sample_rate != NAU7802_SAMP_FREQ_320)
+				msleep(20);
+			else
+				mdelay(4);
+			ret = i2c_smbus_read_byte_data(st->client,
+							NAU7802_REG_PUCTRL);
+			if (ret < 0)
+				return ret;
+		}
+
+		ret = nau7802_read_conversion(st);
+		if (ret < 0)
+			return ret;
+		if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
+			st->conversion_count++;
+	} while (st->conversion_count < NAU7802_MIN_CONVERSIONS);
+
+	*val = st->last_value;
+
+	return IIO_VAL_INT;
+}
+
+static int nau7802_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct nau7802_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&st->lock);
+		/*
+		 * Select the channel to use
+		 *   - Channel 1 is value 0 in the CHS register
+		 *   - Channel 2 is value 1 in the CHS register
+		 */
+		ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL2);
+		if (ret < 0) {
+			mutex_unlock(&st->lock);
+			return ret;
+		}
+
+		if (((ret & NAU7802_CTRL2_CHS_BIT) && !chan->channel) ||
+				(!(ret & NAU7802_CTRL2_CHS_BIT) &&
+				 chan->channel)) {
+			st->conversion_count = 0;
+			ret = i2c_smbus_write_byte_data(st->client,
+					NAU7802_REG_CTRL2,
+					NAU7802_CTRL2_CHS(chan->channel) |
+					NAU7802_CTRL2_CRS(st->sample_rate));
+
+			if (ret < 0) {
+				mutex_unlock(&st->lock);
+				return ret;
+			}
+		}
+
+		if (st->client->irq)
+			ret = nau7802_read_irq(indio_dev, chan, val);
+		else
+			ret = nau7802_read_poll(indio_dev, chan, val);
+
+		mutex_unlock(&st->lock);
+		return ret;
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_CTRL1);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * We have 24 bits of signed data, that means 23 bits of data
+		 * plus the sign bit
+		 */
+		*val = st->vref_mv;
+		*val2 = 23 + (ret & NAU7802_CTRL1_GAINS_BITS);
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*val =  nau7802_sample_freq_avail[st->sample_rate];
+		*val2 = 0;
+		return IIO_VAL_INT;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int nau7802_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct nau7802_state *st = iio_priv(indio_dev);
+	int i, ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+			if (val2 == st->scale_avail[i])
+				return nau7802_set_gain(st, i);
+
+		break;
+
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		for (i = 0; i < ARRAY_SIZE(nau7802_sample_freq_avail); i++)
+			if (val == nau7802_sample_freq_avail[i]) {
+				mutex_lock(&st->lock);
+				st->sample_rate = i;
+				st->conversion_count = 0;
+				ret = i2c_smbus_write_byte_data(st->client,
+					NAU7802_REG_CTRL2,
+					NAU7802_CTRL2_CRS(st->sample_rate));
+				mutex_unlock(&st->lock);
+				return ret;
+			}
+
+		break;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int nau7802_write_raw_get_fmt(struct iio_dev *indio_dev,
+				     struct iio_chan_spec const *chan,
+				     long mask)
+{
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static const struct iio_info nau7802_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &nau7802_read_raw,
+	.write_raw = &nau7802_write_raw,
+	.write_raw_get_fmt = nau7802_write_raw_get_fmt,
+	.attrs = &nau7802_attribute_group,
+};
+
+static int nau7802_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct nau7802_state *st;
+	struct device_node *np = client->dev.of_node;
+	int i, ret;
+	u8 data;
+	u32 tmp = 0;
+
+	if (!client->dev.of_node) {
+		dev_err(&client->dev, "No device tree node available.\n");
+		return -EINVAL;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	i2c_set_clientdata(client, indio_dev);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &nau7802_info;
+
+	st->client = client;
+
+	/* Reset the device */
+	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
+				  NAU7802_PUCTRL_RR_BIT);
+	if (ret < 0)
+		return ret;
+
+	/* Enter normal operation mode */
+	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL,
+				  NAU7802_PUCTRL_PUD_BIT);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * After about 200 usecs, the device should be ready and then
+	 * the Power Up bit will be set to 1. If not, wait for it.
+	 */
+	udelay(210);
+	ret = i2c_smbus_read_byte_data(st->client, NAU7802_REG_PUCTRL);
+	if (ret < 0)
+		return ret;
+	if (!(ret & NAU7802_PUCTRL_PUR_BIT))
+		return ret;
+
+	of_property_read_u32(np, "nuvoton,vldo", &tmp);
+	st->vref_mv = tmp;
+
+	data = NAU7802_PUCTRL_PUD_BIT | NAU7802_PUCTRL_PUA_BIT |
+		NAU7802_PUCTRL_CS_BIT;
+	if (tmp >= 2400)
+		data |= NAU7802_PUCTRL_AVDDS_BIT;
+
+	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_PUCTRL, data);
+	if (ret < 0)
+		return ret;
+	ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_ADC_CTRL, 0x30);
+	if (ret < 0)
+		return ret;
+
+	if (tmp >= 2400) {
+		data = NAU7802_CTRL1_VLDO((4500 - tmp) / 300);
+		ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL1,
+						data);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Populate available ADC input ranges */
+	for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
+		st->scale_avail[i] = (((u64)st->vref_mv) * 1000000000ULL)
+					   >> (23 + i);
+
+	init_completion(&st->value_ok);
+
+	/*
+	 * The ADC fires continuously and we can't do anything about
+	 * it. So we need to have the IRQ disabled by default, and we
+	 * will enable them back when we will need them..
+	 */
+	if (client->irq) {
+		ret = request_threaded_irq(client->irq,
+				NULL,
+				nau7802_eoc_trigger,
+				IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				client->dev.driver->name,
+				indio_dev);
+		if (ret) {
+			/*
+			 * What may happen here is that our IRQ controller is
+			 * not able to get level interrupt but this is required
+			 * by this ADC as when going over 40 sample per second,
+			 * the interrupt line may stay high between conversions.
+			 * So, we continue no matter what but we switch to
+			 * polling mode.
+			 */
+			dev_info(&client->dev,
+				"Failed to allocate IRQ, using polling mode\n");
+			client->irq = 0;
+		} else
+			disable_irq(client->irq);
+	}
+
+	if (!client->irq) {
+		/*
+		 * We are polling, use the fastest sample rate by
+		 * default
+		 */
+		st->sample_rate = NAU7802_SAMP_FREQ_320;
+		ret = i2c_smbus_write_byte_data(st->client, NAU7802_REG_CTRL2,
+					  NAU7802_CTRL2_CRS(st->sample_rate));
+		if (ret)
+			goto error_free_irq;
+	}
+
+	/* Setup the ADC channels available on the board */
+	indio_dev->num_channels = ARRAY_SIZE(nau7802_chan_array);
+	indio_dev->channels = nau7802_chan_array;
+
+	mutex_init(&st->lock);
+	mutex_init(&st->data_lock);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "Couldn't register the device.\n");
+		goto error_device_register;
+	}
+
+	return 0;
+
+error_device_register:
+	mutex_destroy(&st->lock);
+	mutex_destroy(&st->data_lock);
+error_free_irq:
+	if (client->irq)
+		free_irq(client->irq, indio_dev);
+
+	return ret;
+}
+
+static int nau7802_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct nau7802_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	mutex_destroy(&st->lock);
+	mutex_destroy(&st->data_lock);
+	if (client->irq)
+		free_irq(client->irq, indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id nau7802_i2c_id[] = {
+	{ "nau7802", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, nau7802_i2c_id);
+
+static const struct of_device_id nau7802_dt_ids[] = {
+	{ .compatible = "nuvoton,nau7802" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, nau7802_dt_ids);
+
+static struct i2c_driver nau7802_driver = {
+	.probe = nau7802_probe,
+	.remove = nau7802_remove,
+	.id_table = nau7802_i2c_id,
+	.driver = {
+		   .name = "nau7802",
+		   .of_match_table = of_match_ptr(nau7802_dt_ids),
+	},
+};
+
+module_i2c_driver(nau7802_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Nuvoton NAU7802 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index 2826faa..ee5f72b 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -74,22 +74,20 @@
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
 		return -ENODEV;
 
-	iio = iio_device_alloc(sizeof(*adc));
+	iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
 	if (!iio)
 		return -ENOMEM;
 
 	adc = iio_priv(iio);
 	adc->i2c = client;
 
-	adc->ref = regulator_get(&client->dev, "vref");
-	if (IS_ERR(adc->ref)) {
-		err = PTR_ERR(adc->ref);
-		goto iio_free;
-	}
+	adc->ref = devm_regulator_get(&client->dev, "vref");
+	if (IS_ERR(adc->ref))
+		return PTR_ERR(adc->ref);
 
 	err = regulator_enable(adc->ref);
 	if (err < 0)
-		goto regulator_put;
+		return err;
 
 	iio->dev.parent = &client->dev;
 	iio->name = dev_name(&client->dev);
@@ -109,10 +107,6 @@
 
 regulator_disable:
 	regulator_disable(adc->ref);
-regulator_put:
-	regulator_put(adc->ref);
-iio_free:
-	iio_device_free(iio);
 
 	return err;
 }
@@ -124,8 +118,6 @@
 
 	iio_device_unregister(iio);
 	regulator_disable(adc->ref);
-	regulator_put(adc->ref);
-	iio_device_free(iio);
 
 	return 0;
 }
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 3ceac3e..a952538 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -216,11 +216,11 @@
 		return -EINVAL;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(struct tiadc_device));
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					  sizeof(struct tiadc_device));
 	if (indio_dev == NULL) {
 		dev_err(&pdev->dev, "failed to allocate iio device\n");
-		err = -ENOMEM;
-		goto err_ret;
+		return -ENOMEM;
 	}
 	adc_dev = iio_priv(indio_dev);
 
@@ -241,7 +241,7 @@
 
 	err = tiadc_channel_init(indio_dev, adc_dev->channels);
 	if (err < 0)
-		goto err_free_device;
+		return err;
 
 	err = iio_device_register(indio_dev);
 	if (err)
@@ -253,9 +253,6 @@
 
 err_free_channels:
 	tiadc_channels_remove(indio_dev);
-err_free_device:
-	iio_device_free(indio_dev);
-err_ret:
 	return err;
 }
 
@@ -271,8 +268,6 @@
 	step_en = get_adc_step_mask(adc_dev);
 	am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c
new file mode 100644
index 0000000..0ea96c0
--- /dev/null
+++ b/drivers/iio/adc/twl6030-gpadc.c
@@ -0,0 +1,1013 @@
+/*
+ * TWL6030 GPADC module driver
+ *
+ * Copyright (C) 2009-2013 Texas Instruments Inc.
+ * Nishant Kamat <nskamat@ti.com>
+ * Balaji T K <balajitk@ti.com>
+ * Graeme Gregory <gg@slimlogic.co.uk>
+ * Girish S Ghongdemath <girishsg@ti.com>
+ * Ambresh K <ambresh@ti.com>
+ * Oleksandr Kozaruk <oleksandr.kozaruk@ti.com
+ *
+ * Based on twl4030-madc.c
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.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.  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
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/i2c/twl.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define DRIVER_NAME		"twl6030_gpadc"
+
+/*
+ * twl6030 per TRM has 17 channels, and twl6032 has 19 channels
+ * 2 test network channels are not used,
+ * 2 die temperature channels are not used either, as it is not
+ * defined how to convert ADC value to temperature
+ */
+#define TWL6030_GPADC_USED_CHANNELS		13
+#define TWL6030_GPADC_MAX_CHANNELS		15
+#define TWL6032_GPADC_USED_CHANNELS		15
+#define TWL6032_GPADC_MAX_CHANNELS		19
+#define TWL6030_GPADC_NUM_TRIM_REGS		16
+
+#define TWL6030_GPADC_CTRL_P1			0x05
+
+#define TWL6032_GPADC_GPSELECT_ISB		0x07
+#define TWL6032_GPADC_CTRL_P1			0x08
+
+#define TWL6032_GPADC_GPCH0_LSB			0x0d
+#define TWL6032_GPADC_GPCH0_MSB			0x0e
+
+#define TWL6030_GPADC_CTRL_P1_SP1		BIT(3)
+
+#define TWL6030_GPADC_GPCH0_LSB			(0x29)
+
+#define TWL6030_GPADC_RT_SW1_EOC_MASK		BIT(5)
+
+#define TWL6030_GPADC_TRIM1			0xCD
+
+#define TWL6030_REG_TOGGLE1			0x90
+#define TWL6030_GPADCS				BIT(1)
+#define TWL6030_GPADCR				BIT(0)
+
+/**
+ * struct twl6030_chnl_calib - channel calibration
+ * @gain:		slope coefficient for ideal curve
+ * @gain_error:		gain error
+ * @offset_error:	offset of the real curve
+ */
+struct twl6030_chnl_calib {
+	s32 gain;
+	s32 gain_error;
+	s32 offset_error;
+};
+
+/**
+ * struct twl6030_ideal_code - GPADC calibration parameters
+ * GPADC is calibrated in two points: close to the beginning and
+ * to the and of the measurable input range
+ *
+ * @channel:	channel number
+ * @code1:	ideal code for the input at the beginning
+ * @code2:	ideal code for at the end of the range
+ * @volt1:	voltage input at the beginning(low voltage)
+ * @volt2:	voltage input at the end(high voltage)
+ */
+struct twl6030_ideal_code {
+	int channel;
+	u16 code1;
+	u16 code2;
+	u16 volt1;
+	u16 volt2;
+};
+
+struct twl6030_gpadc_data;
+
+/**
+ * struct twl6030_gpadc_platform_data - platform specific data
+ * @nchannels:		number of GPADC channels
+ * @iio_channels:	iio channels
+ * @twl6030_ideal:	pointer to calibration parameters
+ * @start_conversion:	pointer to ADC start conversion function
+ * @channel_to_reg	pointer to ADC function to convert channel to
+ *			register address for reading conversion result
+ * @calibrate:		pointer to calibration function
+ */
+struct twl6030_gpadc_platform_data {
+	const int nchannels;
+	const struct iio_chan_spec *iio_channels;
+	const struct twl6030_ideal_code *ideal;
+	int (*start_conversion)(int channel);
+	u8 (*channel_to_reg)(int channel);
+	int (*calibrate)(struct twl6030_gpadc_data *gpadc);
+};
+
+/**
+ * struct twl6030_gpadc_data - GPADC data
+ * @dev:		device pointer
+ * @lock:		mutual exclusion lock for the structure
+ * @irq_complete:	completion to signal end of conversion
+ * @twl6030_cal_tbl:	pointer to calibration data for each
+ *			channel with gain error and offset
+ * @pdata:		pointer to device specific data
+ */
+struct twl6030_gpadc_data {
+	struct device	*dev;
+	struct mutex	lock;
+	struct completion	irq_complete;
+	struct twl6030_chnl_calib	*twl6030_cal_tbl;
+	const struct twl6030_gpadc_platform_data *pdata;
+};
+
+/*
+ * channels 11, 12, 13, 15 and 16 have no calibration data
+ * calibration offset is same for channels 1, 3, 4, 5
+ *
+ * The data is taken from GPADC_TRIM registers description.
+ * GPADC_TRIM registers keep difference between the code measured
+ * at volt1 and volt2 input voltages and corresponding code1 and code2
+ */
+static const struct twl6030_ideal_code
+	twl6030_ideal[TWL6030_GPADC_USED_CHANNELS] = {
+	[0] = { /* ch 0, external, battery type, resistor value */
+		.channel = 0,
+		.code1 = 116,
+		.code2 = 745,
+		.volt1 = 141,
+		.volt2 = 910,
+	},
+	[1] = { /* ch 1, external, battery temperature, NTC resistor value */
+		.channel = 1,
+		.code1 = 82,
+		.code2 = 900,
+		.volt1 = 100,
+		.volt2 = 1100,
+	},
+	[2] = { /* ch 2, external, audio accessory/general purpose */
+		.channel = 2,
+		.code1 = 55,
+		.code2 = 818,
+		.volt1 = 101,
+		.volt2 = 1499,
+	},
+	[3] = { /* ch 3, external, general purpose */
+		.channel = 3,
+		.code1 = 82,
+		.code2 = 900,
+		.volt1 = 100,
+		.volt2 = 1100,
+	},
+	[4] = { /* ch 4, external, temperature measurement/general purpose */
+		.channel = 4,
+		.code1 = 82,
+		.code2 = 900,
+		.volt1 = 100,
+		.volt2 = 1100,
+	},
+	[5] = { /* ch 5, external, general purpose */
+		.channel = 5,
+		.code1 = 82,
+		.code2 = 900,
+		.volt1 = 100,
+		.volt2 = 1100,
+	},
+	[6] = { /* ch 6, external, general purpose */
+		.channel = 6,
+		.code1 = 82,
+		.code2 = 900,
+		.volt1 = 100,
+		.volt2 = 1100,
+	},
+	[7] = { /* ch 7, internal, main battery */
+		.channel = 7,
+		.code1 = 614,
+		.code2 = 941,
+		.volt1 = 3001,
+		.volt2 = 4599,
+	},
+	[8] = { /* ch 8, internal, backup battery */
+		.channel = 8,
+		.code1 = 82,
+		.code2 = 688,
+		.volt1 = 501,
+		.volt2 = 4203,
+	},
+	[9] = { /* ch 9, internal, external charger input */
+		.channel = 9,
+		.code1 = 182,
+		.code2 = 818,
+		.volt1 = 2001,
+		.volt2 = 8996,
+	},
+	[10] = { /* ch 10, internal, VBUS */
+		.channel = 10,
+		.code1 = 149,
+		.code2 = 818,
+		.volt1 = 1001,
+		.volt2 = 5497,
+	},
+	[11] = { /* ch 11, internal, VBUS charging current */
+		.channel = 11,
+	},
+		/* ch 12, internal, Die temperature */
+		/* ch 13, internal, Die temperature */
+	[12] = { /* ch 14, internal, USB ID line */
+		.channel = 14,
+		.code1 = 48,
+		.code2 = 714,
+		.volt1 = 323,
+		.volt2 = 4800,
+	},
+};
+
+static const struct twl6030_ideal_code
+			twl6032_ideal[TWL6032_GPADC_USED_CHANNELS] = {
+	[0] = { /* ch 0, external, battery type, resistor value */
+		.channel = 0,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 440,
+		.volt2 = 1000,
+	},
+	[1] = { /* ch 1, external, battery temperature, NTC resistor value */
+		.channel = 1,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 440,
+		.volt2 = 1000,
+	},
+	[2] = { /* ch 2, external, audio accessory/general purpose */
+		.channel = 2,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 660,
+		.volt2 = 1500,
+	},
+	[3] = { /* ch 3, external, temperature with external diode/general
+								purpose */
+		.channel = 3,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 440,
+		.volt2 = 1000,
+	},
+	[4] = { /* ch 4, external, temperature measurement/general purpose */
+		.channel = 4,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 440,
+		.volt2 = 1000,
+	},
+	[5] = { /* ch 5, external, general purpose */
+		.channel = 5,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 440,
+		.volt2 = 1000,
+	},
+	[6] = { /* ch 6, external, general purpose */
+		.channel = 6,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 440,
+		.volt2 = 1000,
+	},
+	[7] = { /* ch7, internal, system supply */
+		.channel = 7,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 2200,
+		.volt2 = 5000,
+	},
+	[8] = { /* ch8, internal, backup battery */
+		.channel = 8,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 2200,
+		.volt2 = 5000,
+	},
+	[9] = { /* ch 9, internal, external charger input */
+		.channel = 9,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 3960,
+		.volt2 = 9000,
+	},
+	[10] = { /* ch10, internal, VBUS */
+		.channel = 10,
+		.code1 = 150,
+		.code2 = 751,
+		.volt1 = 1000,
+		.volt2 = 5000,
+	},
+	[11] = { /* ch 11, internal, VBUS DC-DC output current */
+		.channel = 11,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 660,
+		.volt2 = 1500,
+	},
+		/* ch 12, internal, Die temperature */
+		/* ch 13, internal, Die temperature */
+	[12] = { /* ch 14, internal, USB ID line */
+		.channel = 14,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 2420,
+		.volt2 = 5500,
+	},
+		/* ch 15, internal, test network */
+		/* ch 16, internal, test network */
+	[13] = { /* ch 17, internal, battery charging current */
+		.channel = 17,
+	},
+	[14] = { /* ch 18, internal, battery voltage */
+		.channel = 18,
+		.code1 = 1441,
+		.code2 = 3276,
+		.volt1 = 2200,
+		.volt2 = 5000,
+	},
+};
+
+static inline int twl6030_gpadc_write(u8 reg, u8 val)
+{
+	return twl_i2c_write_u8(TWL6030_MODULE_GPADC, val, reg);
+}
+
+static inline int twl6030_gpadc_read(u8 reg, u8 *val)
+{
+
+	return twl_i2c_read(TWL6030_MODULE_GPADC, val, reg, 2);
+}
+
+static int twl6030_gpadc_enable_irq(u8 mask)
+{
+	int ret;
+
+	ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_LINE_B);
+	if (ret < 0)
+		return ret;
+
+	ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_STS_B);
+
+	return ret;
+}
+
+static void twl6030_gpadc_disable_irq(u8 mask)
+{
+	twl6030_interrupt_mask(mask, REG_INT_MSK_LINE_B);
+	twl6030_interrupt_mask(mask, REG_INT_MSK_STS_B);
+}
+
+static irqreturn_t twl6030_gpadc_irq_handler(int irq, void *indio_dev)
+{
+	struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
+
+	complete(&gpadc->irq_complete);
+
+	return IRQ_HANDLED;
+}
+
+static int twl6030_start_conversion(int channel)
+{
+	return twl6030_gpadc_write(TWL6030_GPADC_CTRL_P1,
+					TWL6030_GPADC_CTRL_P1_SP1);
+}
+
+static int twl6032_start_conversion(int channel)
+{
+	int ret;
+
+	ret = twl6030_gpadc_write(TWL6032_GPADC_GPSELECT_ISB, channel);
+	if (ret)
+		return ret;
+
+	return twl6030_gpadc_write(TWL6032_GPADC_CTRL_P1,
+						TWL6030_GPADC_CTRL_P1_SP1);
+}
+
+static u8 twl6030_channel_to_reg(int channel)
+{
+	return TWL6030_GPADC_GPCH0_LSB + 2 * channel;
+}
+
+static u8 twl6032_channel_to_reg(int channel)
+{
+	/*
+	 * for any prior chosen channel, when the conversion is ready
+	 * the result is avalable in GPCH0_LSB, GPCH0_MSB.
+	 */
+
+	return TWL6032_GPADC_GPCH0_LSB;
+}
+
+static int twl6030_gpadc_lookup(const struct twl6030_ideal_code *ideal,
+		int channel, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		if (ideal[i].channel == channel)
+			break;
+
+	return i;
+}
+
+static int twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data
+		*pdata, int channel)
+{
+	const struct twl6030_ideal_code *ideal = pdata->ideal;
+	int i;
+
+	i = twl6030_gpadc_lookup(ideal, channel, pdata->nchannels);
+	/* not calibrated channels have 0 in all structure members */
+	return pdata->ideal[i].code2;
+}
+
+static int twl6030_gpadc_make_correction(struct twl6030_gpadc_data *gpadc,
+		int channel, int raw_code)
+{
+	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
+	int corrected_code;
+	int i;
+
+	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
+	corrected_code = ((raw_code * 1000) -
+		gpadc->twl6030_cal_tbl[i].offset_error) /
+		gpadc->twl6030_cal_tbl[i].gain_error;
+
+	return corrected_code;
+}
+
+static int twl6030_gpadc_get_raw(struct twl6030_gpadc_data *gpadc,
+		int channel, int *res)
+{
+	u8 reg = gpadc->pdata->channel_to_reg(channel);
+	__le16 val;
+	int raw_code;
+	int ret;
+
+	ret = twl6030_gpadc_read(reg, (u8 *)&val);
+	if (ret) {
+		dev_dbg(gpadc->dev, "unable to read register 0x%X\n", reg);
+		return ret;
+	}
+
+	raw_code = le16_to_cpu(val);
+	dev_dbg(gpadc->dev, "GPADC raw code: %d", raw_code);
+
+	if (twl6030_channel_calibrated(gpadc->pdata, channel))
+		*res = twl6030_gpadc_make_correction(gpadc, channel, raw_code);
+	else
+		*res = raw_code;
+
+	return ret;
+}
+
+static int twl6030_gpadc_get_processed(struct twl6030_gpadc_data *gpadc,
+		int channel, int *val)
+{
+	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
+	int corrected_code;
+	int channel_value;
+	int i;
+	int ret;
+
+	ret = twl6030_gpadc_get_raw(gpadc, channel, &corrected_code);
+	if (ret)
+		return ret;
+
+	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
+	channel_value = corrected_code *
+			gpadc->twl6030_cal_tbl[i].gain;
+
+	/* Shift back into mV range */
+	channel_value /= 1000;
+
+	dev_dbg(gpadc->dev, "GPADC corrected code: %d", corrected_code);
+	dev_dbg(gpadc->dev, "GPADC value: %d", channel_value);
+
+	*val = channel_value;
+
+	return ret;
+}
+
+static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
+			     const struct iio_chan_spec *chan,
+			     int *val, int *val2, long mask)
+{
+	struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
+	int ret;
+	long timeout;
+
+	mutex_lock(&gpadc->lock);
+
+	ret = gpadc->pdata->start_conversion(chan->channel);
+	if (ret) {
+		dev_err(gpadc->dev, "failed to start conversion\n");
+		goto err;
+	}
+	/* wait for conversion to complete */
+	timeout = wait_for_completion_interruptible_timeout(
+				&gpadc->irq_complete, msecs_to_jiffies(5000));
+	if (timeout == 0) {
+		ret = -ETIMEDOUT;
+		goto err;
+	} else if (timeout < 0) {
+		ret = -EINTR;
+		goto err;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val);
+		ret = ret ? -EIO : IIO_VAL_INT;
+		break;
+
+	case IIO_CHAN_INFO_PROCESSED:
+		ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val);
+		ret = ret ? -EIO : IIO_VAL_INT;
+		break;
+
+	default:
+		break;
+	}
+err:
+	mutex_unlock(&gpadc->lock);
+
+	return ret;
+}
+
+/*
+ * The GPADC channels are calibrated using a two point calibration method.
+ * The channels measured with two known values: volt1 and volt2, and
+ * ideal corresponding output codes are known: code1, code2.
+ * The difference(d1, d2) between ideal and measured codes stored in trim
+ * registers.
+ * The goal is to find offset and gain of the real curve for each calibrated
+ * channel.
+ * gain: k = 1 + ((d2 - d1) / (x2 - x1))
+ * offset: b = d1 + (k - 1) * x1
+ */
+static void twl6030_calibrate_channel(struct twl6030_gpadc_data *gpadc,
+		int channel, int d1, int d2)
+{
+	int b, k, gain, x1, x2, i;
+	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
+
+	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
+
+	/* Gain */
+	gain = ((ideal[i].volt2 - ideal[i].volt1) * 1000) /
+		(ideal[i].code2 - ideal[i].code1);
+
+	x1 = ideal[i].code1;
+	x2 = ideal[i].code2;
+
+	/* k - real curve gain */
+	k = 1000 + (((d2 - d1) * 1000) / (x2 - x1));
+
+	/* b - offset of the real curve gain */
+	b = (d1 * 1000) - (k - 1000) * x1;
+
+	gpadc->twl6030_cal_tbl[i].gain = gain;
+	gpadc->twl6030_cal_tbl[i].gain_error = k;
+	gpadc->twl6030_cal_tbl[i].offset_error = b;
+
+	dev_dbg(gpadc->dev, "GPADC d1   for Chn: %d = %d\n", channel, d1);
+	dev_dbg(gpadc->dev, "GPADC d2   for Chn: %d = %d\n", channel, d2);
+	dev_dbg(gpadc->dev, "GPADC x1   for Chn: %d = %d\n", channel, x1);
+	dev_dbg(gpadc->dev, "GPADC x2   for Chn: %d = %d\n", channel, x2);
+	dev_dbg(gpadc->dev, "GPADC Gain for Chn: %d = %d\n", channel, gain);
+	dev_dbg(gpadc->dev, "GPADC k    for Chn: %d = %d\n", channel, k);
+	dev_dbg(gpadc->dev, "GPADC b    for Chn: %d = %d\n", channel, b);
+}
+
+static inline int twl6030_gpadc_get_trim_offset(s8 d)
+{
+	/*
+	 * XXX NOTE!
+	 * bit 0 - sign, bit 7 - reserved, 6..1 - trim value
+	 * though, the documentation states that trim value
+	 * is absolute value, the correct conversion results are
+	 * obtained if the value is interpreted as 2's complement.
+	 */
+	__u32 temp = ((d & 0x7f) >> 1) | ((d & 1) << 6);
+
+	return sign_extend32(temp, 6);
+}
+
+static int twl6030_calibration(struct twl6030_gpadc_data *gpadc)
+{
+	int ret;
+	int chn;
+	u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS];
+	s8 d1, d2;
+
+	/*
+	 * for calibration two measurements have been performed at
+	 * factory, for some channels, during the production test and
+	 * have been stored in registers. This two stored values are
+	 * used to correct the measurements. The values represent
+	 * offsets for the given input from the output on ideal curve.
+	 */
+	ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs,
+			TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS);
+	if (ret < 0) {
+		dev_err(gpadc->dev, "calibration failed\n");
+		return ret;
+	}
+
+	for (chn = 0; chn < TWL6030_GPADC_MAX_CHANNELS; chn++) {
+
+		switch (chn) {
+		case 0:
+			d1 = trim_regs[0];
+			d2 = trim_regs[1];
+			break;
+		case 1:
+		case 3:
+		case 4:
+		case 5:
+		case 6:
+			d1 = trim_regs[4];
+			d2 = trim_regs[5];
+			break;
+		case 2:
+			d1 = trim_regs[12];
+			d2 = trim_regs[13];
+			break;
+		case 7:
+			d1 = trim_regs[6];
+			d2 = trim_regs[7];
+			break;
+		case 8:
+			d1 = trim_regs[2];
+			d2 = trim_regs[3];
+			break;
+		case 9:
+			d1 = trim_regs[8];
+			d2 = trim_regs[9];
+			break;
+		case 10:
+			d1 = trim_regs[10];
+			d2 = trim_regs[11];
+			break;
+		case 14:
+			d1 = trim_regs[14];
+			d2 = trim_regs[15];
+			break;
+		default:
+			continue;
+		}
+
+		d1 = twl6030_gpadc_get_trim_offset(d1);
+		d2 = twl6030_gpadc_get_trim_offset(d2);
+
+		twl6030_calibrate_channel(gpadc, chn, d1, d2);
+	}
+
+	return 0;
+}
+
+static int twl6032_get_trim_value(u8 *trim_regs, unsigned int reg0,
+		unsigned int reg1, unsigned int mask0, unsigned int mask1,
+		unsigned int shift0)
+{
+	int val;
+
+	val = (trim_regs[reg0] & mask0) << shift0;
+	val |= (trim_regs[reg1] & mask1) >> 1;
+	if (trim_regs[reg1] & 0x01)
+		val = -val;
+
+	return val;
+}
+
+static int twl6032_calibration(struct twl6030_gpadc_data *gpadc)
+{
+	int chn, d1 = 0, d2 = 0, temp;
+	u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS];
+	int ret;
+
+	ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs,
+			TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS);
+	if (ret < 0) {
+		dev_err(gpadc->dev, "calibration failed\n");
+		return ret;
+	}
+
+	/*
+	 * Loop to calculate the value needed for returning voltages from
+	 * GPADC not values.
+	 *
+	 * gain is calculated to 3 decimal places fixed point.
+	 */
+	for (chn = 0; chn < TWL6032_GPADC_MAX_CHANNELS; chn++) {
+
+		switch (chn) {
+		case 0:
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+		case 6:
+		case 11:
+		case 14:
+			d1 = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+								0x06, 2);
+			d2 = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
+								0x06, 2);
+			break;
+		case 8:
+			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+								0x06, 2);
+			d1 = temp + twl6032_get_trim_value(trim_regs, 7, 6,
+								0x18, 0x1E, 1);
+
+			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3F,
+								0x06, 2);
+			d2 = temp + twl6032_get_trim_value(trim_regs, 9, 7,
+								0x1F, 0x06, 2);
+			break;
+		case 9:
+			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+								0x06, 2);
+			d1 = temp + twl6032_get_trim_value(trim_regs, 13, 11,
+								0x18, 0x1E, 1);
+
+			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
+								0x06, 2);
+			d2 = temp + twl6032_get_trim_value(trim_regs, 15, 13,
+								0x1F, 0x06, 1);
+			break;
+		case 10:
+			d1 = twl6032_get_trim_value(trim_regs, 10, 8, 0x0f,
+								0x0E, 3);
+			d2 = twl6032_get_trim_value(trim_regs, 14, 12, 0x0f,
+								0x0E, 3);
+			break;
+		case 7:
+		case 18:
+			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
+								0x06, 2);
+
+			d1 = (trim_regs[4] & 0x7E) >> 1;
+			if (trim_regs[4] & 0x01)
+				d1 = -d1;
+			d1 += temp;
+
+			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
+								0x06, 2);
+
+			d2 = (trim_regs[5] & 0xFE) >> 1;
+			if (trim_regs[5] & 0x01)
+				d2 = -d2;
+
+			d2 += temp;
+			break;
+		default:
+			/* No data for other channels */
+			continue;
+		}
+
+		twl6030_calibrate_channel(gpadc, chn, d1, d2);
+	}
+
+	return 0;
+}
+
+#define TWL6030_GPADC_CHAN(chn, _type, chan_info) {	\
+	.type = _type,					\
+	.channel = chn,					\
+	.info_mask_separate = BIT(chan_info),		\
+	.indexed = 1,					\
+}
+
+static const struct iio_chan_spec twl6030_gpadc_iio_channels[] = {
+	TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW),
+	TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW),
+	TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+	TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+};
+
+static const struct iio_chan_spec twl6032_gpadc_iio_channels[] = {
+	TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW),
+	TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW),
+	TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+	TWL6030_GPADC_CHAN(17, IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
+	TWL6030_GPADC_CHAN(18, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+};
+
+static const struct iio_info twl6030_gpadc_iio_info = {
+	.read_raw = &twl6030_gpadc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct twl6030_gpadc_platform_data twl6030_pdata = {
+	.iio_channels = twl6030_gpadc_iio_channels,
+	.nchannels = TWL6030_GPADC_USED_CHANNELS,
+	.ideal = twl6030_ideal,
+	.start_conversion = twl6030_start_conversion,
+	.channel_to_reg = twl6030_channel_to_reg,
+	.calibrate = twl6030_calibration,
+};
+
+static const struct twl6030_gpadc_platform_data twl6032_pdata = {
+	.iio_channels = twl6032_gpadc_iio_channels,
+	.nchannels = TWL6032_GPADC_USED_CHANNELS,
+	.ideal = twl6032_ideal,
+	.start_conversion = twl6032_start_conversion,
+	.channel_to_reg = twl6032_channel_to_reg,
+	.calibrate = twl6032_calibration,
+};
+
+static const struct of_device_id of_twl6030_match_tbl[] = {
+	{
+		.compatible = "ti,twl6030-gpadc",
+		.data = &twl6030_pdata,
+	},
+	{
+		.compatible = "ti,twl6032-gpadc",
+		.data = &twl6032_pdata,
+	},
+	{ /* end */ }
+};
+
+static int twl6030_gpadc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct twl6030_gpadc_data *gpadc;
+	const struct twl6030_gpadc_platform_data *pdata;
+	const struct of_device_id *match;
+	struct iio_dev *indio_dev;
+	int irq;
+	int ret;
+
+	match = of_match_device(of_match_ptr(of_twl6030_match_tbl), dev);
+	if (!match)
+		return -EINVAL;
+
+	pdata = match->data;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	gpadc = iio_priv(indio_dev);
+
+	gpadc->twl6030_cal_tbl = devm_kzalloc(dev,
+					sizeof(*gpadc->twl6030_cal_tbl) *
+					pdata->nchannels, GFP_KERNEL);
+	if (!gpadc->twl6030_cal_tbl)
+		return -ENOMEM;
+
+	gpadc->dev = dev;
+	gpadc->pdata = pdata;
+
+	platform_set_drvdata(pdev, indio_dev);
+	mutex_init(&gpadc->lock);
+	init_completion(&gpadc->irq_complete);
+
+	ret = pdata->calibrate(gpadc);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to read calibration registers\n");
+		return ret;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get irq\n");
+		return irq;
+	}
+
+	ret = devm_request_threaded_irq(dev, irq, NULL,
+				twl6030_gpadc_irq_handler,
+				IRQF_ONESHOT, "twl6030_gpadc", indio_dev);
+
+	ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
+		return ret;
+	}
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
+					TWL6030_REG_TOGGLE1);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable GPADC module\n");
+		return ret;
+	}
+
+	indio_dev->name = DRIVER_NAME;
+	indio_dev->dev.parent = dev;
+	indio_dev->info = &twl6030_gpadc_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = pdata->iio_channels;
+	indio_dev->num_channels = pdata->nchannels;
+
+	ret = iio_device_register(indio_dev);
+
+	return ret;
+}
+
+static int twl6030_gpadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int twl6030_gpadc_suspend(struct device *pdev)
+{
+	int ret;
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR,
+				TWL6030_REG_TOGGLE1);
+	if (ret)
+		dev_err(pdev, "error reseting GPADC (%d)!\n", ret);
+
+	return 0;
+};
+
+static int twl6030_gpadc_resume(struct device *pdev)
+{
+	int ret;
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
+				TWL6030_REG_TOGGLE1);
+	if (ret)
+		dev_err(pdev, "error setting GPADC (%d)!\n", ret);
+
+	return 0;
+};
+#endif
+
+static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
+					twl6030_gpadc_resume);
+
+static struct platform_driver twl6030_gpadc_driver = {
+	.probe		= twl6030_gpadc_probe,
+	.remove		= twl6030_gpadc_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &twl6030_gpadc_pm_ops,
+		.of_match_table = of_twl6030_match_tbl,
+	},
+};
+
+module_platform_driver(twl6030_gpadc_driver);
+
+MODULE_ALIAS("platform: " DRIVER_NAME);
+MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_AUTHOR("Oleksandr Kozaruk <oleksandr.kozaruk@ti.com");
+MODULE_DESCRIPTION("twl6030 ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index 56ac481..09727a7 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -124,7 +124,7 @@
 	int ret;
 
 	/* registering iio */
-	indio_dev = iio_device_alloc(sizeof(*adc));
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
 	if (!indio_dev) {
 		dev_err(&pdev->dev, "failed allocating iio device\n");
 		return -ENOMEM;
@@ -142,16 +142,12 @@
 	ret = iio_device_register(indio_dev);
 	if (ret) {
 		dev_err(&pdev->dev, "could not register iio (adc)");
-		goto error;
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, indio_dev);
 
 	return 0;
-
-error:
-	iio_device_free(indio_dev);
-	return ret;
 }
 
 static int vprbrd_adc_remove(struct platform_device *pdev)
@@ -159,7 +155,6 @@
 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
index 05d707e..e9c5f2c 100644
--- a/drivers/iio/amplifiers/Kconfig
+++ b/drivers/iio/amplifiers/Kconfig
@@ -1,6 +1,8 @@
 #
 # Gain Amplifiers, etc.
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Amplifiers"
 
 config AD8366
diff --git a/drivers/iio/amplifiers/Makefile b/drivers/iio/amplifiers/Makefile
index a6ca366..8da4b78 100644
--- a/drivers/iio/amplifiers/Makefile
+++ b/drivers/iio/amplifiers/Makefile
@@ -2,4 +2,5 @@
 # Makefile iio/amplifiers
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD8366) += ad8366.o
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index d354554..d0a79a4 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -139,17 +139,17 @@
 	struct ad8366_state *st;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
-	st->reg = regulator_get(&spi->dev, "vcc");
+	st->reg = devm_regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 	}
 
 	spi_set_drvdata(spi, indio_dev);
@@ -173,11 +173,6 @@
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -195,8 +190,6 @@
 		regulator_put(reg);
 	}
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index c2352be..3112df0 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -6,5 +6,6 @@
 # instead of duplicating in each module.
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-y += hid-sensors/
 obj-y += st_sensors/
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 865b178..965ee22 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -22,7 +22,7 @@
 
 static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
 {
-	return ((s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8);
+	return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
 }
 
 static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
@@ -118,7 +118,7 @@
 }
 
 static int st_sensors_set_fullscale(struct iio_dev *indio_dev,
-							unsigned int fs)
+								unsigned int fs)
 {
 	int err, i = 0;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
@@ -198,13 +198,39 @@
 }
 EXPORT_SYMBOL(st_sensors_set_axis_enable);
 
-int st_sensors_init_sensor(struct iio_dev *indio_dev)
+int st_sensors_init_sensor(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata)
 {
 	int err;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
 	mutex_init(&sdata->tb.buf_lock);
 
+	switch (pdata->drdy_int_pin) {
+	case 1:
+		if (sdata->sensor->drdy_irq.mask_int1 == 0) {
+			dev_err(&indio_dev->dev,
+					"DRDY on INT1 not available.\n");
+			err = -EINVAL;
+			goto init_error;
+		}
+		sdata->drdy_int_pin = 1;
+		break;
+	case 2:
+		if (sdata->sensor->drdy_irq.mask_int2 == 0) {
+			dev_err(&indio_dev->dev,
+					"DRDY on INT2 not available.\n");
+			err = -EINVAL;
+			goto init_error;
+		}
+		sdata->drdy_int_pin = 2;
+		break;
+	default:
+		dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
+		err = -EINVAL;
+		goto init_error;
+	}
+
 	err = st_sensors_set_enable(indio_dev, false);
 	if (err < 0)
 		goto init_error;
@@ -234,6 +260,7 @@
 int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
 {
 	int err;
+	u8 drdy_mask;
 	struct st_sensor_data *sdata = iio_priv(indio_dev);
 
 	/* Enable/Disable the interrupt generator 1. */
@@ -245,10 +272,14 @@
 			goto st_accel_set_dataready_irq_error;
 	}
 
+	if (sdata->drdy_int_pin == 1)
+		drdy_mask = sdata->sensor->drdy_irq.mask_int1;
+	else
+		drdy_mask = sdata->sensor->drdy_irq.mask_int2;
+
 	/* Enable/Disable the interrupt generator for data ready. */
 	err = st_sensors_write_data_with_mask(indio_dev,
-			sdata->sensor->drdy_irq.addr,
-			sdata->sensor->drdy_irq.mask, (int)enable);
+			sdata->sensor->drdy_irq.addr, drdy_mask, (int)enable);
 
 st_accel_set_dataready_irq_error:
 	return err;
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index c9c33ce..3c6a78a 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -1,6 +1,8 @@
 #
 # DAC drivers
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Digital to analog converters"
 
 config AD5064
@@ -15,7 +17,7 @@
 	  module will be called ad5064.
 
 config AD5360
-	tristate "Analog Devices Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
+	tristate "Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
 	depends on SPI
 	help
 	  Say yes here to build support for Analog Devices AD5360, AD5361,
@@ -48,13 +50,6 @@
 	  To compile this driver as module choose M here: the module will be called
 	  ad5421.
 
-config AD5624R_SPI
-	tristate "Analog Devices AD5624/44/64R DAC spi driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5624R, AD5644R and
-	  AD5664R converters (DAC). This driver uses the common SPI interface.
-
 config AD5446
 	tristate "Analog Devices AD5446 and similar single channel DACs driver"
 	depends on (SPI_MASTER && I2C!=m) || I2C
@@ -68,7 +63,7 @@
 	  module will be called ad5446.
 
 config AD5449
-	tristate "Analog Device AD5449 and similar DACs driver"
+	tristate "Analog Devices AD5449 and similar DACs driver"
 	depends on SPI_MASTER
 	help
 	  Say yes here to build support for Analog Devices AD5415, AD5426, AD5429,
@@ -87,6 +82,24 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5504.
 
+config AD5624R_SPI
+	tristate "Analog Devices AD5624/44/64R DAC spi driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5624R, AD5644R and
+	  AD5664R converters (DAC). This driver uses the common SPI interface.
+
+config AD5686
+	tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5686R, AD5685R,
+	  AD5684R, AD5791 Voltage Output Digital to
+	  Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5686.
+
 config AD5755
 	tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver"
 	depends on SPI_MASTER
@@ -119,19 +132,8 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad5791.
 
-config AD5686
-	tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
-	depends on SPI
-	help
-	  Say yes here to build support for Analog Devices AD5686R, AD5685R,
-	  AD5684R, AD5791 Voltage Output Digital to
-	  Analog Converter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called ad5686.
-
 config AD7303
-	tristate "Analog Devices Analog Devices AD7303 DAC driver"
+	tristate "Analog Devices AD7303 DAC driver"
 	depends on SPI
 	help
 	  Say yes here to build support for Analog Devices AD7303 Digital to Analog
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index c8d7ab6..bb84ad6 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -2,6 +2,7 @@
 # Makefile for industrial I/O DAC drivers
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD5360) += ad5360.o
 obj-$(CONFIG_AD5380) += ad5380.o
 obj-$(CONFIG_AD5421) += ad5421.o
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index aa26d50..a3a52be 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -442,7 +442,7 @@
 	unsigned int i;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return  -ENOMEM;
 
@@ -456,23 +456,23 @@
 	for (i = 0; i < ad5064_num_vref(st); ++i)
 		st->vref_reg[i].supply = ad5064_vref_name(st, i);
 
-	ret = regulator_bulk_get(dev, ad5064_num_vref(st),
+	ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st),
 		st->vref_reg);
 	if (ret) {
 		if (!st->chip_info->internal_vref)
-			goto error_free;
+			return ret;
 		st->use_internal_vref = true;
 		ret = ad5064_write(st, AD5064_CMD_CONFIG, 0,
 			AD5064_CONFIG_INT_VREF_ENABLE, 0);
 		if (ret) {
 			dev_err(dev, "Failed to enable internal vref: %d\n",
 				ret);
-			goto error_free;
+			return ret;
 		}
 	} else {
 		ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
 		if (ret)
-			goto error_free_reg;
+			return ret;
 	}
 
 	indio_dev->dev.parent = dev;
@@ -498,11 +498,6 @@
 error_disable_reg:
 	if (!st->use_internal_vref)
 		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
-error_free_reg:
-	if (!st->use_internal_vref)
-		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
-error_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -514,12 +509,8 @@
 
 	iio_device_unregister(indio_dev);
 
-	if (!st->use_internal_vref) {
+	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_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
index 80923af..d2da71e 100644
--- a/drivers/iio/dac/ad5360.c
+++ b/drivers/iio/dac/ad5360.c
@@ -459,7 +459,7 @@
 	unsigned int i;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return  -ENOMEM;
@@ -480,13 +480,13 @@
 	ret = ad5360_alloc_channels(indio_dev);
 	if (ret) {
 		dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
-		goto error_free;
+		return ret;
 	}
 
 	for (i = 0; i < st->chip_info->num_vrefs; ++i)
 		st->vref_reg[i].supply = ad5360_vref_name[i];
 
-	ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
+	ret = devm_regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
 		st->vref_reg);
 	if (ret) {
 		dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret);
@@ -496,7 +496,7 @@
 	ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg);
 	if (ret) {
 		dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret);
-		goto error_free_reg;
+		goto error_free_channels;
 	}
 
 	ret = iio_device_register(indio_dev);
@@ -509,12 +509,8 @@
 
 error_disable_reg:
 	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
-error_free_reg:
-	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
 error_free_channels:
 	kfree(indio_dev->channels);
-error_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -529,9 +525,6 @@
 	kfree(indio_dev->channels);
 
 	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
-	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index bf2db02..1c44ae3 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -369,11 +369,10 @@
 	unsigned int ctrl = 0;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(dev, "Failed to allocate iio device\n");
-		ret = -ENOMEM;
-		goto error_out;
+		return -ENOMEM;
 	}
 
 	st = iio_priv(indio_dev);
@@ -391,13 +390,13 @@
 	ret = ad5380_alloc_channels(indio_dev);
 	if (ret) {
 		dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
-		goto error_free;
+		return ret;
 	}
 
 	if (st->chip_info->int_vref == 2500000)
 		ctrl |= AD5380_CTRL_INT_VREF_2V5;
 
-	st->vref_reg = regulator_get(dev, "vref");
+	st->vref_reg = devm_regulator_get(dev, "vref");
 	if (!IS_ERR(st->vref_reg)) {
 		ret = regulator_enable(st->vref_reg);
 		if (ret) {
@@ -434,13 +433,7 @@
 	if (!IS_ERR(st->vref_reg))
 		regulator_disable(st->vref_reg);
 error_free_reg:
-	if (!IS_ERR(st->vref_reg))
-		regulator_put(st->vref_reg);
-
 	kfree(indio_dev->channels);
-error_free:
-	iio_device_free(indio_dev);
-error_out:
 
 	return ret;
 }
@@ -456,11 +449,8 @@
 
 	if (!IS_ERR(st->vref_reg)) {
 		regulator_disable(st->vref_reg);
-		regulator_put(st->vref_reg);
 	}
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
index 98f2440..1f78b14 100644
--- a/drivers/iio/dac/ad5421.c
+++ b/drivers/iio/dac/ad5421.c
@@ -451,7 +451,7 @@
 	struct ad5421_state *st;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return  -ENOMEM;
@@ -484,31 +484,23 @@
 	ad5421_update_ctrl(indio_dev, 0, 0);
 
 	if (spi->irq) {
-		ret = request_threaded_irq(spi->irq,
+		ret = devm_request_threaded_irq(&spi->dev, spi->irq,
 					   NULL,
 					   ad5421_fault_handler,
 					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 					   "ad5421 fault",
 					   indio_dev);
 		if (ret)
-			goto error_free;
+			return ret;
 	}
 
 	ret = iio_device_register(indio_dev);
 	if (ret) {
 		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
-		goto error_free_irq;
+		return ret;
 	}
 
 	return 0;
-
-error_free_irq:
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
-error_free:
-	iio_device_free(indio_dev);
-
-	return ret;
 }
 
 static int ad5421_remove(struct spi_device *spi)
@@ -516,9 +508,6 @@
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index cae8f60..96e9ed4 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -220,11 +220,11 @@
 	struct regulator *reg;
 	int ret, voltage_uv = 0;
 
-	reg = regulator_get(dev, "vcc");
+	reg = devm_regulator_get(dev, "vcc");
 	if (!IS_ERR(reg)) {
 		ret = regulator_enable(reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 
 		ret = regulator_get_voltage(reg);
 		if (ret < 0)
@@ -233,7 +233,7 @@
 		voltage_uv = ret;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
 	if (indio_dev == NULL) {
 		ret = -ENOMEM;
 		goto error_disable_reg;
@@ -264,19 +264,13 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_device;
+		goto error_disable_reg;
 
 	return 0;
 
-error_free_device:
-	iio_device_free(indio_dev);
 error_disable_reg:
 	if (!IS_ERR(reg))
 		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
-
 	return ret;
 }
 
@@ -286,11 +280,8 @@
 	struct ad5446_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
+	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c
index ba1c914..fff7d07 100644
--- a/drivers/iio/dac/ad5449.c
+++ b/drivers/iio/dac/ad5449.c
@@ -275,7 +275,7 @@
 	unsigned int i;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -288,14 +288,14 @@
 	for (i = 0; i < st->chip_info->num_channels; ++i)
 		st->vref_reg[i].supply = ad5449_vref_name(st, i);
 
-	ret = regulator_bulk_get(&spi->dev, st->chip_info->num_channels,
+	ret = devm_regulator_bulk_get(&spi->dev, st->chip_info->num_channels,
 				st->vref_reg);
 	if (ret)
-		goto error_free;
+		return ret;
 
 	ret = regulator_bulk_enable(st->chip_info->num_channels, st->vref_reg);
 	if (ret)
-		goto error_free_reg;
+		return ret;
 
 	indio_dev->dev.parent = &spi->dev;
 	indio_dev->name = id->name;
@@ -325,10 +325,6 @@
 
 error_disable_reg:
 	regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
-error_free_reg:
-	regulator_bulk_free(st->chip_info->num_channels, st->vref_reg);
-error_free:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -341,9 +337,6 @@
 	iio_device_unregister(indio_dev);
 
 	regulator_bulk_disable(st->chip_info->num_channels, st->vref_reg);
-	regulator_bulk_free(st->chip_info->num_channels, st->vref_reg);
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 139206e..caffb16 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -281,16 +281,14 @@
 	struct regulator *reg;
 	int ret, voltage_uv = 0;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	reg = regulator_get(&spi->dev, "vcc");
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+	reg = devm_regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(reg)) {
 		ret = regulator_enable(reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 
 		ret = regulator_get_voltage(reg);
 		if (ret < 0)
@@ -321,7 +319,7 @@
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
 	if (spi->irq) {
-		ret = request_threaded_irq(spi->irq,
+		ret = devm_request_threaded_irq(&spi->dev, spi->irq,
 					   NULL,
 					   &ad5504_event_handler,
 					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
@@ -333,22 +331,14 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_irq;
+		goto error_disable_reg;
 
 	return 0;
 
-error_free_irq:
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
 error_disable_reg:
 	if (!IS_ERR(reg))
 		regulator_disable(reg);
-error_put_reg:
-	if (!IS_ERR(reg))
-		regulator_put(reg);
 
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -358,14 +348,9 @@
 	struct ad5504_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	if (spi->irq)
-		free_irq(spi->irq, indio_dev);
 
-	if (!IS_ERR(st->reg)) {
+	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index bb298aa..714af75 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -226,17 +226,15 @@
 	struct iio_dev *indio_dev;
 	int ret, voltage_uv = 0;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
-	st->reg = regulator_get(&spi->dev, "vcc");
+	st->reg = devm_regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 
 		ret = regulator_get_voltage(st->reg);
 		if (ret < 0)
@@ -277,11 +275,6 @@
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-	iio_device_free(indio_dev);
-error_ret:
 
 	return ret;
 }
@@ -292,11 +285,8 @@
 	struct ad5624r_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
+	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 06439b1..57825ea 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -314,18 +314,18 @@
 	struct iio_dev *indio_dev;
 	int ret, regdone = 0, voltage_uv = 0;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return  -ENOMEM;
 
 	st = iio_priv(indio_dev);
 	spi_set_drvdata(spi, indio_dev);
 
-	st->reg = regulator_get(&spi->dev, "vcc");
+	st->reg = devm_regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 
 		ret = regulator_get_voltage(st->reg);
 		if (ret < 0)
@@ -369,12 +369,6 @@
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-
-	iio_device_free(indio_dev);
-
 	return ret;
 }
 
@@ -384,11 +378,8 @@
 	struct ad5686_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg)) {
+	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 12bb315..36a4361 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -565,7 +565,7 @@
 	struct ad5755_state *st;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return  -ENOMEM;
@@ -589,24 +589,19 @@
 
 	ret = ad5755_init_channels(indio_dev, pdata);
 	if (ret)
-		goto error_free;
+		return ret;
 
 	ret = ad5755_setup_pdata(indio_dev, pdata);
 	if (ret)
-		goto error_free;
+		return ret;
 
 	ret = iio_device_register(indio_dev);
 	if (ret) {
 		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
-		goto error_free;
+		return ret;
 	}
 
 	return 0;
-
-error_free:
-	iio_device_free(indio_dev);
-
-	return ret;
 }
 
 static int ad5755_remove(struct spi_device *spi)
@@ -614,7 +609,6 @@
 	struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
index 7a53f7d..df7e028 100644
--- a/drivers/iio/dac/ad5764.c
+++ b/drivers/iio/dac/ad5764.c
@@ -275,7 +275,7 @@
 	struct ad5764_state *st;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL) {
 		dev_err(&spi->dev, "Failed to allocate iio device\n");
 		return -ENOMEM;
@@ -298,12 +298,12 @@
 		st->vref_reg[0].supply = "vrefAB";
 		st->vref_reg[1].supply = "vrefCD";
 
-		ret = regulator_bulk_get(&st->spi->dev,
+		ret = devm_regulator_bulk_get(&st->spi->dev,
 			ARRAY_SIZE(st->vref_reg), st->vref_reg);
 		if (ret) {
 			dev_err(&spi->dev, "Failed to request vref regulators: %d\n",
 				ret);
-			goto error_free;
+			return ret;
 		}
 
 		ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg),
@@ -311,7 +311,7 @@
 		if (ret) {
 			dev_err(&spi->dev, "Failed to enable vref regulators: %d\n",
 				ret);
-			goto error_free_reg;
+			return ret;
 		}
 	}
 
@@ -326,12 +326,6 @@
 error_disable_reg:
 	if (st->chip_info->int_vref == 0)
 		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-error_free_reg:
-	if (st->chip_info->int_vref == 0)
-		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-error_free:
-	iio_device_free(indio_dev);
-
 	return ret;
 }
 
@@ -342,12 +336,8 @@
 
 	iio_device_unregister(indio_dev);
 
-	if (st->chip_info->int_vref == 0) {
+	if (st->chip_info->int_vref == 0)
 		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
-	}
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 97c1e5d..ce74589 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -349,17 +349,15 @@
 	struct ad5791_state *st;
 	int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
-	st->reg_vdd = regulator_get(&spi->dev, "vdd");
+	st->reg_vdd = devm_regulator_get(&spi->dev, "vdd");
 	if (!IS_ERR(st->reg_vdd)) {
 		ret = regulator_enable(st->reg_vdd);
 		if (ret)
-			goto error_put_reg_pos;
+			return ret;
 
 		ret = regulator_get_voltage(st->reg_vdd);
 		if (ret < 0)
@@ -368,11 +366,11 @@
 		pos_voltage_uv = ret;
 	}
 
-	st->reg_vss = regulator_get(&spi->dev, "vss");
+	st->reg_vss = devm_regulator_get(&spi->dev, "vss");
 	if (!IS_ERR(st->reg_vss)) {
 		ret = regulator_enable(st->reg_vss);
 		if (ret)
-			goto error_put_reg_neg;
+			goto error_disable_reg_pos;
 
 		ret = regulator_get_voltage(st->reg_vss);
 		if (ret < 0)
@@ -428,19 +426,9 @@
 error_disable_reg_neg:
 	if (!IS_ERR(st->reg_vss))
 		regulator_disable(st->reg_vss);
-error_put_reg_neg:
-	if (!IS_ERR(st->reg_vss))
-		regulator_put(st->reg_vss);
-
 error_disable_reg_pos:
 	if (!IS_ERR(st->reg_vdd))
 		regulator_disable(st->reg_vdd);
-error_put_reg_pos:
-	if (!IS_ERR(st->reg_vdd))
-		regulator_put(st->reg_vdd);
-	iio_device_free(indio_dev);
-error_ret:
-
 	return ret;
 }
 
@@ -450,16 +438,11 @@
 	struct ad5791_state *st = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	if (!IS_ERR(st->reg_vdd)) {
+	if (!IS_ERR(st->reg_vdd))
 		regulator_disable(st->reg_vdd);
-		regulator_put(st->reg_vdd);
-	}
 
-	if (!IS_ERR(st->reg_vss)) {
+	if (!IS_ERR(st->reg_vss))
 		regulator_disable(st->reg_vss);
-		regulator_put(st->reg_vss);
-	}
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c
index d546f50..ed2d276 100644
--- a/drivers/iio/dac/ad7303.c
+++ b/drivers/iio/dac/ad7303.c
@@ -203,7 +203,7 @@
 	bool ext_ref;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -212,15 +212,13 @@
 
 	st->spi = spi;
 
-	st->vdd_reg = regulator_get(&spi->dev, "Vdd");
-	if (IS_ERR(st->vdd_reg)) {
-		ret = PTR_ERR(st->vdd_reg);
-		goto err_free;
-	}
+	st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd");
+	if (IS_ERR(st->vdd_reg))
+		return PTR_ERR(st->vdd_reg);
 
 	ret = regulator_enable(st->vdd_reg);
 	if (ret)
-		goto err_put_vdd_reg;
+		return ret;
 
 	if (spi->dev.of_node) {
 		ext_ref = of_property_read_bool(spi->dev.of_node,
@@ -234,7 +232,7 @@
 	}
 
 	if (ext_ref) {
-		st->vref_reg = regulator_get(&spi->dev, "REF");
+		st->vref_reg = devm_regulator_get(&spi->dev, "REF");
 		if (IS_ERR(st->vref_reg)) {
 			ret = PTR_ERR(st->vref_reg);
 			goto err_disable_vdd_reg;
@@ -242,7 +240,7 @@
 
 		ret = regulator_enable(st->vref_reg);
 		if (ret)
-			goto err_put_vref_reg;
+			goto err_disable_vdd_reg;
 
 		st->config |= AD7303_CFG_EXTERNAL_VREF;
 	}
@@ -263,16 +261,8 @@
 err_disable_vref_reg:
 	if (st->vref_reg)
 		regulator_disable(st->vref_reg);
-err_put_vref_reg:
-	if (st->vref_reg)
-		regulator_put(st->vref_reg);
 err_disable_vdd_reg:
 	regulator_disable(st->vdd_reg);
-err_put_vdd_reg:
-	regulator_put(st->vdd_reg);
-err_free:
-	iio_device_free(indio_dev);
-
 	return ret;
 }
 
@@ -283,14 +273,9 @@
 
 	iio_device_unregister(indio_dev);
 
-	if (st->vref_reg) {
+	if (st->vref_reg)
 		regulator_disable(st->vref_reg);
-		regulator_put(st->vref_reg);
-	}
 	regulator_disable(st->vdd_reg);
-	regulator_put(st->vdd_reg);
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index ebfaa41..83adcbf 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -164,11 +164,9 @@
 	struct max517_platform_data *platform_data = client->dev.platform_data;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*data));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
 	data = iio_priv(indio_dev);
 	i2c_set_clientdata(client, indio_dev);
 	data->client = client;
@@ -198,23 +196,16 @@
 
 	err = iio_device_register(indio_dev);
 	if (err)
-		goto exit_free_device;
+		return err;
 
 	dev_info(&client->dev, "DAC registered\n");
 
 	return 0;
-
-exit_free_device:
-	iio_device_free(indio_dev);
-exit:
-	return err;
 }
 
 static int max517_remove(struct i2c_client *client)
 {
 	iio_device_unregister(i2c_get_clientdata(client));
-	iio_device_free(i2c_get_clientdata(client));
-
 	return 0;
 }
 
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index a612ec7..1f4a48e 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -12,14 +12,13 @@
  * driver for the Microchip I2C 12-bit digital-to-analog converter (DAC)
  * (7-bit I2C slave address 0x60, the three LSBs can be configured in
  * hardware)
- *
- * writing the DAC value to EEPROM is not supported
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
+#include <linux/delay.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -32,15 +31,19 @@
 	struct i2c_client *client;
 	u16 vref_mv;
 	u16 dac_value;
+	bool powerdown;
+	unsigned powerdown_mode;
 };
 
-#ifdef CONFIG_PM_SLEEP
 static int mcp4725_suspend(struct device *dev)
 {
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct mcp4725_data *data = iio_priv(indio_dev);
 	u8 outbuf[2];
 
-	outbuf[0] = 0x3 << 4; /* power-down bits, 500 kOhm resistor */
+	outbuf[0] = (data->powerdown_mode + 1) << 4;
 	outbuf[1] = 0;
+	data->powerdown = true;
 
 	return i2c_master_send(to_i2c_client(dev), outbuf, 2);
 }
@@ -54,16 +57,150 @@
 	/* restore previous DAC value */
 	outbuf[0] = (data->dac_value >> 8) & 0xf;
 	outbuf[1] = data->dac_value & 0xff;
+	data->powerdown = false;
 
 	return i2c_master_send(to_i2c_client(dev), outbuf, 2);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
 #define MCP4725_PM_OPS (&mcp4725_pm_ops)
 #else
 #define MCP4725_PM_OPS NULL
 #endif
 
+static ssize_t mcp4725_store_eeprom(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct mcp4725_data *data = iio_priv(indio_dev);
+	int tries = 20;
+	u8 inoutbuf[3];
+	bool state;
+	int ret;
+
+	ret = strtobool(buf, &state);
+	if (ret < 0)
+		return ret;
+
+	if (!state)
+		return 0;
+
+	inoutbuf[0] = 0x60; /* write EEPROM */
+	inoutbuf[1] = data->dac_value >> 4;
+	inoutbuf[2] = (data->dac_value & 0xf) << 4;
+
+	ret = i2c_master_send(data->client, inoutbuf, 3);
+	if (ret < 0)
+		return ret;
+	else if (ret != 3)
+		return -EIO;
+
+	/* wait for write complete, takes up to 50ms */
+	while (tries--) {
+		msleep(20);
+		ret = i2c_master_recv(data->client, inoutbuf, 3);
+		if (ret < 0)
+			return ret;
+		else if (ret != 3)
+			return -EIO;
+
+		if (inoutbuf[0] & 0x80)
+			break;
+	}
+
+	if (tries < 0) {
+		dev_err(&data->client->dev,
+			"mcp4725_store_eeprom() failed, incomplete\n");
+		return -EIO;
+	}
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(store_eeprom, S_IWUSR, NULL, mcp4725_store_eeprom, 0);
+
+static struct attribute *mcp4725_attributes[] = {
+	&iio_dev_attr_store_eeprom.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group mcp4725_attribute_group = {
+	.attrs = mcp4725_attributes,
+};
+
+static const char * const mcp4725_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"100kohm_to_gnd",
+	"500kohm_to_gnd"
+};
+
+static int mcp4725_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+
+	return data->powerdown_mode;
+}
+
+static int mcp4725_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned mode)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+
+	data->powerdown_mode = mode;
+
+	return 0;
+}
+
+static ssize_t mcp4725_read_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", data->powerdown);
+}
+
+static ssize_t mcp4725_write_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan,
+	 const char *buf, size_t len)
+{
+	struct mcp4725_data *data = iio_priv(indio_dev);
+	bool state;
+	int ret;
+
+	ret = strtobool(buf, &state);
+	if (ret)
+		return ret;
+
+	if (state)
+		ret = mcp4725_suspend(&data->client->dev);
+	else
+		ret = mcp4725_resume(&data->client->dev);
+	if (ret < 0)
+		return ret;
+
+	return len;
+}
+
+static const struct iio_enum mcp4725_powerdown_mode_enum = {
+	.items = mcp4725_powerdown_modes,
+	.num_items = ARRAY_SIZE(mcp4725_powerdown_modes),
+	.get = mcp4725_get_powerdown_mode,
+	.set = mcp4725_set_powerdown_mode,
+};
+
+static const struct iio_chan_spec_ext_info mcp4725_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = mcp4725_read_powerdown,
+		.write = mcp4725_write_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &mcp4725_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &mcp4725_powerdown_mode_enum),
+	{ },
+};
+
 static const struct iio_chan_spec mcp4725_channel = {
 	.type		= IIO_VOLTAGE,
 	.indexed	= 1,
@@ -72,6 +209,7 @@
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
 	.scan_type	= IIO_ST('u', 12, 16, 0),
+	.ext_info	= mcp4725_ext_info,
 };
 
 static int mcp4725_set_value(struct iio_dev *indio_dev, int val)
@@ -138,6 +276,7 @@
 static const struct iio_info mcp4725_info = {
 	.read_raw = mcp4725_read_raw,
 	.write_raw = mcp4725_write_raw,
+	.attrs = &mcp4725_attribute_group,
 	.driver_module = THIS_MODULE,
 };
 
@@ -148,19 +287,17 @@
 	struct iio_dev *indio_dev;
 	struct mcp4725_platform_data *platform_data = client->dev.platform_data;
 	u8 inbuf[3];
+	u8 pd;
 	int err;
 
 	if (!platform_data || !platform_data->vref_mv) {
 		dev_err(&client->dev, "invalid platform data");
-		err = -EINVAL;
-		goto exit;
+		return -EINVAL;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*data));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (indio_dev == NULL)
+		return -ENOMEM;
 	data = iio_priv(indio_dev);
 	i2c_set_clientdata(client, indio_dev);
 	data->client = client;
@@ -177,31 +314,25 @@
 	err = i2c_master_recv(client, inbuf, 3);
 	if (err < 0) {
 		dev_err(&client->dev, "failed to read DAC value");
-		goto exit_free_device;
+		return err;
 	}
+	pd = (inbuf[0] >> 1) & 0x3;
+	data->powerdown = pd > 0 ? true : false;
+	data->powerdown_mode = pd ? pd-1 : 2; /* 500kohm_to_gnd */
 	data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4);
 
 	err = iio_device_register(indio_dev);
 	if (err)
-		goto exit_free_device;
+		return err;
 
 	dev_info(&client->dev, "MCP4725 DAC registered\n");
 
 	return 0;
-
-exit_free_device:
-	iio_device_free(indio_dev);
-exit:
-	return err;
 }
 
 static int mcp4725_remove(struct i2c_client *client)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
-	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
-
+	iio_device_unregister(i2c_get_clientdata(client));
 	return 0;
 }
 
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index 6aaa33e..dc5e0b7 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -4,6 +4,7 @@
 #	Clock Distribution device drivers
 #	Phase-Locked Loop (PLL) frequency synthesizers
 #
+# When adding new entries keep the list in alphabetical order
 
 menu "Frequency Synthesizers DDS/PLL"
 
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index 00d26e5..2bca03f 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -2,5 +2,6 @@
 # Makefile iio/frequency
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD9523) += ad9523.o
 obj-$(CONFIG_ADF4350) += adf4350.o
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 92276de..7c5245d9 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -961,17 +961,17 @@
 		return -EINVAL;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
-	st->reg = regulator_get(&spi->dev, "vcc");
+	st->reg = devm_regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			return ret;
 	}
 
 	spi_set_drvdata(spi, indio_dev);
@@ -1001,11 +1001,6 @@
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -1017,12 +1012,8 @@
 
 	iio_device_unregister(indio_dev);
 
-	if (!IS_ERR(st->reg)) {
+	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-		regulator_put(st->reg);
-	}
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index a4157cd..a7b30be 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -515,7 +515,7 @@
 	}
 
 	if (!pdata->clkin) {
-		clk = clk_get(&spi->dev, "clkin");
+		clk = devm_clk_get(&spi->dev, "clkin");
 		if (IS_ERR(clk))
 			return -EPROBE_DEFER;
 
@@ -524,17 +524,17 @@
 			return ret;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
-	st->reg = regulator_get(&spi->dev, "vcc");
+	st->reg = devm_regulator_get(&spi->dev, "vcc");
 	if (!IS_ERR(st->reg)) {
 		ret = regulator_enable(st->reg);
 		if (ret)
-			goto error_put_reg;
+			goto error_disable_clk;
 	}
 
 	spi_set_drvdata(spi, indio_dev);
@@ -564,7 +564,8 @@
 	memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
 
 	if (gpio_is_valid(pdata->gpio_lock_detect)) {
-		ret = gpio_request(pdata->gpio_lock_detect, indio_dev->name);
+		ret = devm_gpio_request(&spi->dev, pdata->gpio_lock_detect,
+					indio_dev->name);
 		if (ret) {
 			dev_err(&spi->dev, "fail to request lock detect GPIO-%d",
 				pdata->gpio_lock_detect);
@@ -576,29 +577,21 @@
 	if (pdata->power_up_frequency) {
 		ret = adf4350_set_freq(st, pdata->power_up_frequency);
 		if (ret)
-			goto error_free_gpio;
+			goto error_disable_reg;
 	}
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_gpio;
+		goto error_disable_reg;
 
 	return 0;
 
-error_free_gpio:
-	if (gpio_is_valid(pdata->gpio_lock_detect))
-		gpio_free(pdata->gpio_lock_detect);
-
 error_disable_reg:
 	if (!IS_ERR(st->reg))
 		regulator_disable(st->reg);
-error_put_reg:
-	if (!IS_ERR(st->reg))
-		regulator_put(st->reg);
-
+error_disable_clk:
 	if (clk)
 		clk_disable_unprepare(clk);
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -619,14 +612,8 @@
 
 	if (!IS_ERR(reg)) {
 		regulator_disable(reg);
-		regulator_put(reg);
 	}
 
-	if (gpio_is_valid(st->pdata->gpio_lock_detect))
-		gpio_free(st->pdata->gpio_lock_detect);
-
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index 8498e9d..41c64a4 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -1,6 +1,8 @@
 #
 # IIO Digital Gyroscope Sensor drivers configuration
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Digital gyroscope sensors"
 
 config ADIS16080
@@ -26,6 +28,18 @@
 	  Say yes here to build support for the Analog Devices ADIS16133, ADIS16135,
 	  ADIS16136 gyroscope devices.
 
+config ADIS16260
+	tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"
+	depends on SPI
+	select IIO_ADIS_LIB
+	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
+	help
+	  Say yes here to build support for Analog Devices ADIS16260 ADIS16265
+	  ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called adis16260.
+
 config ADXRS450
 	tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
 	depends on SPI
@@ -58,8 +72,8 @@
 	  Say yes here to build support for STMicroelectronics gyroscopes:
 	  L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
 
-	  This driver can also be built as a module. If so, will be created
-	  these modules:
+	  This driver can also be built as a module. If so, these modules
+	  will be created:
 	  - st_gyro (core functions for the driver [it is mandatory]);
 	  - st_gyro_i2c (necessary for the I2C devices [optional*]);
 	  - st_gyro_spi (necessary for the SPI devices [optional*]);
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index e9dc034..2f2752a 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -2,9 +2,11 @@
 # Makefile for industrial I/O gyroscope sensor drivers
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_ADIS16080) += adis16080.o
 obj-$(CONFIG_ADIS16130) += adis16130.o
 obj-$(CONFIG_ADIS16136) += adis16136.o
+obj-$(CONFIG_ADIS16260) += adis16260.o
 obj-$(CONFIG_ADXRS450) += adxrs450.o
 
 obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c
index e1bb5f9..e9ec022 100644
--- a/drivers/iio/gyro/adis16080.c
+++ b/drivers/iio/gyro/adis16080.c
@@ -192,16 +192,13 @@
 static int adis16080_probe(struct spi_device *spi)
 {
 	const struct spi_device_id *id = spi_get_device_id(spi);
-	int ret;
 	struct adis16080_state *st;
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -217,22 +214,12 @@
 	indio_dev->info = &adis16080_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_dev;
-	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
+	return iio_device_register(indio_dev);
 }
 
 static int adis16080_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_device_free(spi_get_drvdata(spi));
-
 	return 0;
 }
 
diff --git a/drivers/iio/gyro/adis16130.c b/drivers/iio/gyro/adis16130.c
index 129acdf..ac66fc1 100644
--- a/drivers/iio/gyro/adis16130.c
+++ b/drivers/iio/gyro/adis16130.c
@@ -148,16 +148,13 @@
 
 static int adis16130_probe(struct spi_device *spi)
 {
-	int ret;
 	struct adis16130_state *st;
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -170,24 +167,12 @@
 	indio_dev->info = &adis16130_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_free_dev;
-
-	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-
-error_ret:
-	return ret;
+	return iio_device_register(indio_dev);
 }
 
 static int adis16130_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_device_free(spi_get_drvdata(spi));
-
 	return 0;
 }
 
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 058e6d5..591bd55 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -497,7 +497,7 @@
 	struct iio_dev *indio_dev;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*adis16136));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -515,11 +515,11 @@
 
 	ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis16136_initial_setup(indio_dev);
 	if (ret)
@@ -537,8 +537,6 @@
 	adis16136_stop_device(indio_dev);
 error_cleanup_buffer:
 	adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
 	return ret;
 }
 
@@ -552,8 +550,6 @@
 
 	adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev);
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
new file mode 100644
index 0000000..0654116
--- /dev/null
+++ b/drivers/iio/gyro/adis16260.c
@@ -0,0 +1,422 @@
+/*
+ * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/imu/adis.h>
+
+#define ADIS16260_STARTUP_DELAY	220 /* ms */
+
+#define ADIS16260_FLASH_CNT  0x00 /* Flash memory write count */
+#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */
+#define ADIS16260_GYRO_OUT   0x04 /* X-axis gyroscope output */
+#define ADIS16260_AUX_ADC    0x0A /* analog input channel measurement */
+#define ADIS16260_TEMP_OUT   0x0C /* internal temperature measurement */
+#define ADIS16260_ANGL_OUT   0x0E /* angle displacement */
+#define ADIS16260_GYRO_OFF   0x14 /* Calibration, offset/bias adjustment */
+#define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
+#define ADIS16260_ALM_MAG1   0x20 /* Alarm 1 magnitude/polarity setting */
+#define ADIS16260_ALM_MAG2   0x22 /* Alarm 2 magnitude/polarity setting */
+#define ADIS16260_ALM_SMPL1  0x24 /* Alarm 1 dynamic rate of change setting */
+#define ADIS16260_ALM_SMPL2  0x26 /* Alarm 2 dynamic rate of change setting */
+#define ADIS16260_ALM_CTRL   0x28 /* Alarm control */
+#define ADIS16260_AUX_DAC    0x30 /* Auxiliary DAC data */
+#define ADIS16260_GPIO_CTRL  0x32 /* Control, digital I/O line */
+#define ADIS16260_MSC_CTRL   0x34 /* Control, data ready, self-test settings */
+#define ADIS16260_SMPL_PRD   0x36 /* Control, internal sample rate */
+#define ADIS16260_SENS_AVG   0x38 /* Control, dynamic range, filtering */
+#define ADIS16260_SLP_CNT    0x3A /* Control, sleep mode initiation */
+#define ADIS16260_DIAG_STAT  0x3C /* Diagnostic, error flags */
+#define ADIS16260_GLOB_CMD   0x3E /* Control, global commands */
+#define ADIS16260_LOT_ID1    0x52 /* Lot Identification Code 1 */
+#define ADIS16260_LOT_ID2    0x54 /* Lot Identification Code 2 */
+#define ADIS16260_PROD_ID    0x56 /* Product identifier;
+				   * convert to decimal = 16,265/16,260 */
+#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
+
+#define ADIS16260_ERROR_ACTIVE			(1<<14)
+#define ADIS16260_NEW_DATA			(1<<15)
+
+/* MSC_CTRL */
+#define ADIS16260_MSC_CTRL_MEM_TEST		(1<<11)
+/* Internal self-test enable */
+#define ADIS16260_MSC_CTRL_INT_SELF_TEST	(1<<10)
+#define ADIS16260_MSC_CTRL_NEG_SELF_TEST	(1<<9)
+#define ADIS16260_MSC_CTRL_POS_SELF_TEST	(1<<8)
+#define ADIS16260_MSC_CTRL_DATA_RDY_EN		(1<<2)
+#define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH	(1<<1)
+#define ADIS16260_MSC_CTRL_DATA_RDY_DIO2	(1<<0)
+
+/* SMPL_PRD */
+/* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
+#define ADIS16260_SMPL_PRD_TIME_BASE	(1<<7)
+#define ADIS16260_SMPL_PRD_DIV_MASK	0x7F
+
+/* SLP_CNT */
+#define ADIS16260_SLP_CNT_POWER_OFF     0x80
+
+/* DIAG_STAT */
+#define ADIS16260_DIAG_STAT_ALARM2	(1<<9)
+#define ADIS16260_DIAG_STAT_ALARM1	(1<<8)
+#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT	6
+#define ADIS16260_DIAG_STAT_SELF_TEST_BIT	5
+#define ADIS16260_DIAG_STAT_OVERFLOW_BIT	4
+#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT	3
+#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT	2
+#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT	1
+#define ADIS16260_DIAG_STAT_POWER_LOW_BIT	0
+
+/* GLOB_CMD */
+#define ADIS16260_GLOB_CMD_SW_RESET	(1<<7)
+#define ADIS16260_GLOB_CMD_FLASH_UPD	(1<<3)
+#define ADIS16260_GLOB_CMD_DAC_LATCH	(1<<2)
+#define ADIS16260_GLOB_CMD_FAC_CALIB	(1<<1)
+#define ADIS16260_GLOB_CMD_AUTO_NULL	(1<<0)
+
+#define ADIS16260_SPI_SLOW	(u32)(300 * 1000)
+#define ADIS16260_SPI_BURST	(u32)(1000 * 1000)
+#define ADIS16260_SPI_FAST	(u32)(2000 * 1000)
+
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+#define ADIS16260_SCAN_GYRO	0
+#define ADIS16260_SCAN_SUPPLY	1
+#define ADIS16260_SCAN_AUX_ADC	2
+#define ADIS16260_SCAN_TEMP	3
+#define ADIS16260_SCAN_ANGL	4
+
+static ssize_t adis16260_read_frequency(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct adis *adis = iio_priv(indio_dev);
+	int ret, len = 0;
+	u16 t;
+	int sps;
+	ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &t);
+	if (ret)
+		return ret;
+
+	if (spi_get_device_id(adis->spi)->driver_data) /* If an adis16251 */
+		sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
+	else
+		sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
+	sps /= (t & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
+	len = sprintf(buf, "%d\n", sps);
+	return len;
+}
+
+static ssize_t adis16260_write_frequency(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct adis *adis = iio_priv(indio_dev);
+	unsigned int val;
+	int ret;
+	u8 t;
+
+	ret = kstrtouint(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	if (spi_get_device_id(adis->spi)->driver_data)
+		t = 256 / val;
+	else
+		t = 2048 / val;
+
+	if (t > ADIS16260_SMPL_PRD_DIV_MASK)
+		t = ADIS16260_SMPL_PRD_DIV_MASK;
+	else if (t > 0)
+		t--;
+
+	if (t >= 0x0A)
+		adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
+	else
+		adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
+	ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+/* Power down the device */
+static int adis16260_stop_device(struct iio_dev *indio_dev)
+{
+	struct adis *adis = iio_priv(indio_dev);
+	int ret;
+	u16 val = ADIS16260_SLP_CNT_POWER_OFF;
+
+	ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val);
+	if (ret)
+		dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
+
+	return ret;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+		adis16260_read_frequency,
+		adis16260_write_frequency);
+
+static const struct iio_chan_spec adis16260_channels[] = {
+	ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
+		BIT(IIO_CHAN_INFO_CALIBBIAS) |
+		BIT(IIO_CHAN_INFO_CALIBSCALE), 14),
+	ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14),
+	ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12),
+	ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12),
+	ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12),
+	IIO_CHAN_SOFT_TIMESTAMP(5),
+};
+
+static const u8 adis16260_addresses[][2] = {
+	[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
+};
+
+static int adis16260_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2,
+			      long mask)
+{
+	struct adis *adis = iio_priv(indio_dev);
+	int ret;
+	u8 addr;
+	s16 val16;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return adis_single_conversion(indio_dev, chan,
+				ADIS16260_ERROR_ACTIVE, val);
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_ANGL_VEL:
+			*val = 0;
+			if (spi_get_device_id(adis->spi)->driver_data) {
+				/* 0.01832 degree / sec */
+				*val2 = IIO_DEGREE_TO_RAD(18320);
+			} else {
+				/* 0.07326 degree / sec */
+				*val2 = IIO_DEGREE_TO_RAD(73260);
+			}
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_INCLI:
+			*val = 0;
+			*val2 = IIO_DEGREE_TO_RAD(36630);
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_VOLTAGE:
+			if (chan->channel == 0) {
+				*val = 1;
+				*val2 = 831500; /* 1.8315 mV */
+			} else {
+				*val = 0;
+				*val2 = 610500; /* 610.5 uV */
+			}
+			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_TEMP:
+			*val = 145;
+			*val2 = 300000; /* 0.1453 C */
+			return IIO_VAL_INT_PLUS_MICRO;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 250000 / 1453; /* 25 C = 0x00 */
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		addr = adis16260_addresses[chan->scan_index][0];
+		ret = adis_read_reg_16(adis, addr, &val16);
+		if (ret)
+			return ret;
+
+		*val = sign_extend32(val16, 11);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		addr = adis16260_addresses[chan->scan_index][1];
+		ret = adis_read_reg_16(adis, addr, &val16);
+		if (ret)
+			return ret;
+
+		*val = val16;
+		return IIO_VAL_INT;
+	}
+	return -EINVAL;
+}
+
+static int adis16260_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct adis *adis = iio_priv(indio_dev);
+	u8 addr;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_CALIBBIAS:
+		if (val < -2048 || val >= 2048)
+			return -EINVAL;
+
+		addr = adis16260_addresses[chan->scan_index][0];
+		return adis_write_reg_16(adis, addr, val);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val < 0 || val >= 4096)
+			return -EINVAL;
+
+		addr = adis16260_addresses[chan->scan_index][1];
+		return adis_write_reg_16(adis, addr, val);
+	}
+	return -EINVAL;
+}
+
+static struct attribute *adis16260_attributes[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adis16260_attribute_group = {
+	.attrs = adis16260_attributes,
+};
+
+static const struct iio_info adis16260_info = {
+	.attrs = &adis16260_attribute_group,
+	.read_raw = &adis16260_read_raw,
+	.write_raw = &adis16260_write_raw,
+	.update_scan_mode = adis_update_scan_mode,
+	.driver_module = THIS_MODULE,
+};
+
+static const char * const adis1620_status_error_msgs[] = {
+	[ADIS16260_DIAG_STAT_FLASH_CHK_BIT] = "Flash checksum error",
+	[ADIS16260_DIAG_STAT_SELF_TEST_BIT] = "Self test error",
+	[ADIS16260_DIAG_STAT_OVERFLOW_BIT] = "Sensor overrange",
+	[ADIS16260_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
+	[ADIS16260_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
+	[ADIS16260_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 5.25",
+	[ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75",
+};
+
+static const struct adis_data adis16260_data = {
+	.write_delay = 30,
+	.read_delay = 30,
+	.msc_ctrl_reg = ADIS16260_MSC_CTRL,
+	.glob_cmd_reg = ADIS16260_GLOB_CMD,
+	.diag_stat_reg = ADIS16260_DIAG_STAT,
+
+	.self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,
+	.startup_delay = ADIS16260_STARTUP_DELAY,
+
+	.status_error_msgs = adis1620_status_error_msgs,
+	.status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) |
+		BIT(ADIS16260_DIAG_STAT_SELF_TEST_BIT) |
+		BIT(ADIS16260_DIAG_STAT_OVERFLOW_BIT) |
+		BIT(ADIS16260_DIAG_STAT_SPI_FAIL_BIT) |
+		BIT(ADIS16260_DIAG_STAT_FLASH_UPT_BIT) |
+		BIT(ADIS16260_DIAG_STAT_POWER_HIGH_BIT) |
+		BIT(ADIS16260_DIAG_STAT_POWER_LOW_BIT),
+};
+
+static int adis16260_probe(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev;
+	struct adis *adis;
+	int ret;
+
+	/* setup the industrialio driver allocated elements */
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis));
+	if (!indio_dev)
+		return -ENOMEM;
+	adis = iio_priv(indio_dev);
+	/* this is only used for removal purposes */
+	spi_set_drvdata(spi, indio_dev);
+
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->info = &adis16260_info;
+	indio_dev->channels = adis16260_channels;
+	indio_dev->num_channels = ARRAY_SIZE(adis16260_channels);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = adis_init(adis, indio_dev, spi, &adis16260_data);
+	if (ret)
+		return ret;
+
+	ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL);
+	if (ret)
+		return ret;
+
+	/* Get the device into a sane initial state */
+	ret = adis_initial_startup(adis);
+	if (ret)
+		goto error_cleanup_buffer_trigger;
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_cleanup_buffer_trigger;
+
+	return 0;
+
+error_cleanup_buffer_trigger:
+	adis_cleanup_buffer_and_trigger(adis, indio_dev);
+	return ret;
+}
+
+static int adis16260_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct adis *adis = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	adis16260_stop_device(indio_dev);
+	adis_cleanup_buffer_and_trigger(adis, indio_dev);
+
+	return 0;
+}
+
+/*
+ * These parts do not need to be differentiated until someone adds
+ * support for the on chip filtering.
+ */
+static const struct spi_device_id adis16260_id[] = {
+	{"adis16260", 0},
+	{"adis16265", 0},
+	{"adis16250", 0},
+	{"adis16255", 0},
+	{"adis16251", 1},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, adis16260_id);
+
+static struct spi_driver adis16260_driver = {
+	.driver = {
+		.name = "adis16260",
+		.owner = THIS_MODULE,
+	},
+	.probe = adis16260_probe,
+	.remove = adis16260_remove,
+	.id_table = adis16260_id,
+};
+module_spi_driver(adis16260_driver);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c
index 8bd72b4..6dab299 100644
--- a/drivers/iio/gyro/adxrs450.c
+++ b/drivers/iio/gyro/adxrs450.c
@@ -426,11 +426,9 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	st->us = spi;
 	mutex_init(&st->buf_lock);
@@ -447,7 +445,7 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adxrs450_initial_setup(indio_dev);
@@ -456,17 +454,12 @@
 	return 0;
 error_initial:
 	iio_device_unregister(indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-
-error_ret:
 	return ret;
 }
 
 static int adxrs450_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_device_free(spi_get_drvdata(spi));
 
 	return 0;
 }
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index bc943dd..c688d97 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -30,10 +30,6 @@
 #include <linux/iio/triggered_buffer.h>
 #include "../common/hid-sensors/hid-sensor-trigger.h"
 
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Gyro-3D: 0x200076*/
-#define DRIVER_NAME "HID-SENSOR-200076"
-
 enum gyro_3d_channel {
 	CHANNEL_SCAN_INDEX_X,
 	CHANNEL_SCAN_INDEX_Y,
@@ -179,18 +175,10 @@
 	return ret;
 }
 
-static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       long mask)
-{
-	return IIO_VAL_INT_PLUS_MICRO;
-}
-
 static const struct iio_info gyro_3d_info = {
 	.driver_module = THIS_MODULE,
 	.read_raw = &gyro_3d_read_raw,
 	.write_raw = &gyro_3d_write_raw,
-	.write_raw_get_fmt = &gyro_3d_write_raw_get_fmt,
 };
 
 /* Function to push data to buffer */
@@ -286,11 +274,9 @@
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 	struct iio_chan_spec *channels;
 
-	indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));
+	if (!indio_dev)
+		return -ENOMEM;
 	platform_set_drvdata(pdev, indio_dev);
 
 	gyro_state = iio_priv(indio_dev);
@@ -302,15 +288,14 @@
 						&gyro_state->common_attributes);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup common attributes\n");
-		goto error_free_dev;
+		return ret;
 	}
 
 	channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
 			   GFP_KERNEL);
 	if (!channels) {
-		ret = -ENOMEM;
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
-		goto error_free_dev;
+		return -ENOMEM;
 	}
 
 	ret = gyro_3d_parse_report(pdev, hsdev, channels,
@@ -367,9 +352,6 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 error_free_dev_mem:
 	kfree(indio_dev->channels);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -384,14 +366,23 @@
 	hid_sensor_remove_trigger(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	kfree(indio_dev->channels);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
 
+static struct platform_device_id hid_gyro_3d_ids[] = {
+	{
+		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+		.name = "HID-SENSOR-200076",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids);
+
 static struct platform_driver hid_gyro_3d_platform_driver = {
+	.id_table = hid_gyro_3d_ids,
 	.driver = {
-		.name	= DRIVER_NAME,
+		.name	= KBUILD_MODNAME,
 		.owner	= THIS_MODULE,
 	},
 	.probe		= hid_gyro_3d_probe,
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index d66605d2..4d3f3b9 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -309,11 +309,9 @@
 
 	dev_dbg(&client->dev, "probe I2C dev with IRQ %i", client->irq);
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret =  -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 
@@ -330,7 +328,7 @@
 
 	ret = itg3200_buffer_configure(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	if (client->irq) {
 		ret = itg3200_probe_trigger(indio_dev);
@@ -353,9 +351,6 @@
 		itg3200_remove_trigger(indio_dev);
 error_unconfigure_buffer:
 	itg3200_buffer_unconfigure(indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -370,8 +365,6 @@
 
 	itg3200_buffer_unconfigure(indio_dev);
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h
index 3ad9907..f8f2bf8 100644
--- a/drivers/iio/gyro/st_gyro.h
+++ b/drivers/iio/gyro/st_gyro.h
@@ -23,7 +23,16 @@
 #define L3G4IS_GYRO_DEV_NAME		"l3g4is_ui"
 #define LSM330_GYRO_DEV_NAME		"lsm330_gyro"
 
-int st_gyro_common_probe(struct iio_dev *indio_dev);
+/**
+ * struct st_sensors_platform_data - gyro platform data
+ * @drdy_int_pin: DRDY on gyros is available only on INT2 pin.
+ */
+static const struct st_sensors_platform_data gyro_pdata = {
+	.drdy_int_pin = 2,
+};
+
+int st_gyro_common_probe(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata);
 void st_gyro_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index f9ed348..e13c2b0 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -60,7 +60,7 @@
 #define ST_GYRO_1_BDU_ADDR			0x23
 #define ST_GYRO_1_BDU_MASK			0x80
 #define ST_GYRO_1_DRDY_IRQ_ADDR			0x22
-#define ST_GYRO_1_DRDY_IRQ_MASK			0x08
+#define ST_GYRO_1_DRDY_IRQ_INT2_MASK		0x08
 #define ST_GYRO_1_MULTIREAD_BIT			true
 
 /* CUSTOM VALUES FOR SENSOR 2 */
@@ -84,7 +84,7 @@
 #define ST_GYRO_2_BDU_ADDR			0x23
 #define ST_GYRO_2_BDU_MASK			0x80
 #define ST_GYRO_2_DRDY_IRQ_ADDR			0x22
-#define ST_GYRO_2_DRDY_IRQ_MASK			0x08
+#define ST_GYRO_2_DRDY_IRQ_INT2_MASK		0x08
 #define ST_GYRO_2_MULTIREAD_BIT			true
 
 static const struct iio_chan_spec st_gyro_16bit_channels[] = {
@@ -158,7 +158,7 @@
 		},
 		.drdy_irq = {
 			.addr = ST_GYRO_1_DRDY_IRQ_ADDR,
-			.mask = ST_GYRO_1_DRDY_IRQ_MASK,
+			.mask_int2 = ST_GYRO_1_DRDY_IRQ_INT2_MASK,
 		},
 		.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
 		.bootime = 2,
@@ -221,7 +221,7 @@
 		},
 		.drdy_irq = {
 			.addr = ST_GYRO_2_DRDY_IRQ_ADDR,
-			.mask = ST_GYRO_2_DRDY_IRQ_MASK,
+			.mask_int2 = ST_GYRO_2_DRDY_IRQ_INT2_MASK,
 		},
 		.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
 		.bootime = 2,
@@ -302,7 +302,8 @@
 #define ST_GYRO_TRIGGER_OPS NULL
 #endif
 
-int st_gyro_common_probe(struct iio_dev *indio_dev)
+int st_gyro_common_probe(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata)
 {
 	int err;
 	struct st_sensor_data *gdata = iio_priv(indio_dev);
@@ -324,7 +325,7 @@
 						&gdata->sensor->fs.fs_avl[0];
 	gdata->odr = gdata->sensor->odr.odr_avl[0].hz;
 
-	err = st_sensors_init_sensor(indio_dev);
+	err = st_sensors_init_sensor(indio_dev, pdata);
 	if (err < 0)
 		goto st_gyro_common_probe_error;
 
@@ -365,7 +366,6 @@
 		st_sensors_deallocate_trigger(indio_dev);
 		st_gyro_deallocate_ring(indio_dev);
 	}
-	iio_device_free(indio_dev);
 }
 EXPORT_SYMBOL(st_gyro_common_remove);
 
diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c
index 8a31050..16b8b8d 100644
--- a/drivers/iio/gyro/st_gyro_i2c.c
+++ b/drivers/iio/gyro/st_gyro_i2c.c
@@ -25,27 +25,21 @@
 	struct st_sensor_data *gdata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*gdata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*gdata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	gdata = iio_priv(indio_dev);
 	gdata->dev = &client->dev;
 
 	st_sensors_i2c_configure(indio_dev, client, gdata);
 
-	err = st_gyro_common_probe(indio_dev);
+	err = st_gyro_common_probe(indio_dev,
+				(struct st_sensors_platform_data *)&gyro_pdata);
 	if (err < 0)
-		goto st_gyro_common_probe_error;
+		return err;
 
 	return 0;
-
-st_gyro_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_gyro_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c
index f354039..94763e2 100644
--- a/drivers/iio/gyro/st_gyro_spi.c
+++ b/drivers/iio/gyro/st_gyro_spi.c
@@ -24,27 +24,21 @@
 	struct st_sensor_data *gdata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*gdata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*gdata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	gdata = iio_priv(indio_dev);
 	gdata->dev = &spi->dev;
 
 	st_sensors_spi_configure(indio_dev, spi, gdata);
 
-	err = st_gyro_common_probe(indio_dev);
+	err = st_gyro_common_probe(indio_dev,
+				(struct st_sensors_platform_data *)&gyro_pdata);
 	if (err < 0)
-		goto st_gyro_common_probe_error;
+		return err;
 
 	return 0;
-
-st_gyro_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_gyro_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index 6f7c56f..1fdb1e4 100644
--- a/drivers/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
@@ -30,7 +30,7 @@
 static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
 {
 	return 0;
-};
+}
 
 /**
  * iio_device_unregister_trigger_consumer() - reverse the registration process
@@ -38,9 +38,6 @@
  **/
 static void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
 {
-};
+}
 
 #endif /* CONFIG_TRIGGER_CONSUMER */
-
-
-
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 4f40a10..663e88a 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -1,6 +1,8 @@
 #
 # IIO imu drivers configuration
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Inertial measurement units"
 
 config ADIS16400
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index f2f56ce..114d2c1 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -2,6 +2,7 @@
 # Makefile for Inertial Measurement Units
 #
 
+# When adding new entries keep the list in alphabetical order
 adis16400-y             := adis16400_core.o
 adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o
 obj-$(CONFIG_ADIS16400) += adis16400.o
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index f60591f..3fb7757 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -871,7 +871,7 @@
 	struct iio_dev *indio_dev;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -893,12 +893,12 @@
 
 	ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev,
 			adis16400_trigger_handler);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adis16400_initial_setup(indio_dev);
@@ -913,8 +913,6 @@
 
 error_cleanup_buffer:
 	adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
 	return ret;
 }
 
@@ -928,8 +926,6 @@
 
 	adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index b7db383..dd4206c 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -839,7 +839,7 @@
 	struct adis16480 *st;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 	if (indio_dev == NULL)
 		return -ENOMEM;
 
@@ -857,11 +857,11 @@
 
 	ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis16480_initial_setup(indio_dev);
 	if (ret)
@@ -879,8 +879,6 @@
 	adis16480_stop_device(indio_dev);
 error_cleanup_buffer:
 	adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
 	return ret;
 }
 
@@ -894,8 +892,6 @@
 
 	adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index fe4c61e..df7f1e1 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/kfifo.h>
 #include <linux/spinlock.h>
+#include <linux/iio/iio.h>
 #include "inv_mpu_iio.h"
 
 /*
@@ -663,16 +664,13 @@
 	int result;
 
 	if (!i2c_check_functionality(client->adapter,
-					I2C_FUNC_SMBUS_READ_I2C_BLOCK |
-					I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
-		result = -ENOSYS;
-		goto out_no_free;
-	}
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		result =  -ENOMEM;
-		goto out_no_free;
-	}
+		I2C_FUNC_SMBUS_I2C_BLOCK))
+		return -ENOSYS;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
 	st = iio_priv(indio_dev);
 	st->client = client;
 	st->plat_data = *(struct inv_mpu6050_platform_data
@@ -680,13 +678,13 @@
 	/* power is turned on inside check chip type*/
 	result = inv_check_and_setup_chip(st, id);
 	if (result)
-		goto out_free;
+		return result;
 
 	result = inv_mpu6050_init_config(indio_dev);
 	if (result) {
 		dev_err(&client->dev,
 			"Could not initialize device.\n");
-		goto out_free;
+		return result;
 	}
 
 	i2c_set_clientdata(client, indio_dev);
@@ -705,7 +703,7 @@
 	if (result) {
 		dev_err(&st->client->dev, "configure buffer fail %d\n",
 				result);
-		goto out_free;
+		return result;
 	}
 	result = inv_mpu6050_probe_trigger(indio_dev);
 	if (result) {
@@ -727,10 +725,6 @@
 	inv_mpu6050_remove_trigger(st);
 out_unreg_ring:
 	iio_triggered_buffer_cleanup(indio_dev);
-out_free:
-	iio_device_free(indio_dev);
-out_no_free:
-
 	return result;
 }
 
@@ -742,7 +736,6 @@
 	iio_device_unregister(indio_dev);
 	inv_mpu6050_remove_trigger(st);
 	iio_triggered_buffer_cleanup(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index e145931..97f0297 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -383,14 +383,14 @@
 		scale_db = true;
 	case IIO_VAL_INT_PLUS_MICRO:
 		if (val2 < 0)
-			return sprintf(buf, "-%d.%06u%s\n", val, -val2,
+			return sprintf(buf, "-%ld.%06u%s\n", abs(val), -val2,
 				scale_db ? " dB" : "");
 		else
 			return sprintf(buf, "%d.%06u%s\n", val, val2,
 				scale_db ? " dB" : "");
 	case IIO_VAL_INT_PLUS_NANO:
 		if (val2 < 0)
-			return sprintf(buf, "-%d.%09u\n", val, -val2);
+			return sprintf(buf, "-%ld.%09u\n", abs(val), -val2);
 		else
 			return sprintf(buf, "%d.%09u\n", val, val2);
 	case IIO_VAL_FRACTIONAL:
@@ -912,6 +912,53 @@
 }
 EXPORT_SYMBOL(iio_device_free);
 
+static void devm_iio_device_release(struct device *dev, void *res)
+{
+	iio_device_free(*(struct iio_dev **)res);
+}
+
+static int devm_iio_device_match(struct device *dev, void *res, void *data)
+{
+	struct iio_dev **r = res;
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+	return *r == data;
+}
+
+struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
+{
+	struct iio_dev **ptr, *iio_dev;
+
+	ptr = devres_alloc(devm_iio_device_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	/* use raw alloc_dr for kmalloc caller tracing */
+	iio_dev = iio_device_alloc(sizeof_priv);
+	if (iio_dev) {
+		*ptr = iio_dev;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return iio_dev;
+}
+EXPORT_SYMBOL_GPL(devm_iio_device_alloc);
+
+void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev)
+{
+	int rc;
+
+	rc = devres_release(dev, devm_iio_device_release,
+			    devm_iio_device_match, iio_dev);
+	WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_device_free);
+
 /**
  * iio_chrdev_open() - chrdev file open for buffer access and ioctls
  **/
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 0dd9bb8..bf5e70a 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -424,9 +424,8 @@
 	trig->subirqs[d->irq - trig->subirq_base].enabled = true;
 }
 
-struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
+static struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs)
 {
-	va_list vargs;
 	struct iio_trigger *trig;
 	trig = kzalloc(sizeof *trig, GFP_KERNEL);
 	if (trig) {
@@ -444,9 +443,8 @@
 			kfree(trig);
 			return NULL;
 		}
-		va_start(vargs, fmt);
+
 		trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
-		va_end(vargs);
 		if (trig->name == NULL) {
 			irq_free_descs(trig->subirq_base,
 				       CONFIG_IIO_CONSUMERS_PER_TRIGGER);
@@ -467,6 +465,19 @@
 		}
 		get_device(&trig->dev);
 	}
+
+	return trig;
+}
+
+struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
+{
+	struct iio_trigger *trig;
+	va_list vargs;
+
+	va_start(vargs, fmt);
+	trig = viio_trigger_alloc(fmt, vargs);
+	va_end(vargs);
+
 	return trig;
 }
 EXPORT_SYMBOL(iio_trigger_alloc);
@@ -478,6 +489,59 @@
 }
 EXPORT_SYMBOL(iio_trigger_free);
 
+static void devm_iio_trigger_release(struct device *dev, void *res)
+{
+	iio_trigger_free(*(struct iio_trigger **)res);
+}
+
+static int devm_iio_trigger_match(struct device *dev, void *res, void *data)
+{
+	struct iio_trigger **r = res;
+
+	if (!r || !*r) {
+		WARN_ON(!r || !*r);
+		return 0;
+	}
+
+	return *r == data;
+}
+
+struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
+						const char *fmt, ...)
+{
+	struct iio_trigger **ptr, *trig;
+	va_list vargs;
+
+	ptr = devres_alloc(devm_iio_trigger_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return NULL;
+
+	/* use raw alloc_dr for kmalloc caller tracing */
+	va_start(vargs, fmt);
+	trig = viio_trigger_alloc(fmt, vargs);
+	va_end(vargs);
+	if (trig) {
+		*ptr = trig;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return trig;
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc);
+
+void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig)
+{
+	int rc;
+
+	rc = devres_release(dev, devm_iio_trigger_release,
+			    devm_iio_trigger_match, iio_trig);
+	WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_iio_trigger_free);
+
 void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
 {
 	indio_dev->groups[indio_dev->groupcounter++] =
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 5ef1a39..bf9fa0d 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -1,6 +1,8 @@
 #
 # Light sensors
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Light sensors"
 
 config ADJD_S311
@@ -15,6 +17,27 @@
 	 This driver can also be built as a module.  If so, the module
 	 will be called adjd_s311.
 
+config APDS9300
+	tristate "APDS9300 ambient light sensor"
+	depends on I2C
+	help
+	 Say Y here if you want to build a driver for the Avago APDS9300
+	 ambient light sensor.
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called apds9300.
+
+config HID_SENSOR_ALS
+	depends on HID_SENSOR_HUB
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select HID_SENSOR_IIO_COMMON
+	select HID_SENSOR_IIO_TRIGGER
+	tristate "HID ALS"
+	help
+	  Say yes here to build support for the HID SENSOR
+	  Ambient light sensor.
+
 config SENSORS_LM3533
 	tristate "LM3533 ambient light sensor"
 	depends on MFD_LM3533
@@ -52,15 +75,4 @@
 	 To compile this driver as a module, choose M here: the
 	 module will be called vcnl4000.
 
-config HID_SENSOR_ALS
-	depends on HID_SENSOR_HUB
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
-	select HID_SENSOR_IIO_COMMON
-	select HID_SENSOR_IIO_TRIGGER
-	tristate "HID ALS"
-	help
-	  Say yes here to build support for the HID SENSOR
-	  Ambient light sensor.
-
 endmenu
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 040d9c7..354ee9a 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -2,8 +2,10 @@
 # Makefile for IIO Light sensors
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_ADJD_S311)		+= adjd_s311.o
+obj-$(CONFIG_APDS9300)		+= apds9300.o
+obj-$(CONFIG_HID_SENSOR_ALS)	+= hid-sensor-als.o
 obj-$(CONFIG_SENSORS_LM3533)	+= lm3533-als.o
 obj-$(CONFIG_SENSORS_TSL2563)	+= tsl2563.o
 obj-$(CONFIG_VCNL4000)		+= vcnl4000.o
-obj-$(CONFIG_HID_SENSOR_ALS)	+= hid-sensor-als.o
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 5f4749e..23cff79 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -37,22 +37,14 @@
 #define ADJD_S311_CAP_GREEN	0x07
 #define ADJD_S311_CAP_BLUE	0x08
 #define ADJD_S311_CAP_CLEAR	0x09
-#define ADJD_S311_INT_RED_LO	0x0a
-#define ADJD_S311_INT_RED_HI	0x0b
-#define ADJD_S311_INT_GREEN_LO	0x0c
-#define ADJD_S311_INT_GREEN_HI	0x0d
-#define ADJD_S311_INT_BLUE_LO	0x0e
-#define ADJD_S311_INT_BLUE_HI	0x0f
-#define ADJD_S311_INT_CLEAR_LO	0x10
-#define ADJD_S311_INT_CLEAR_HI	0x11
-#define ADJD_S311_DATA_RED_LO	0x40
-#define ADJD_S311_DATA_RED_HI	0x41
-#define ADJD_S311_DATA_GREEN_LO	0x42
-#define ADJD_S311_DATA_GREEN_HI	0x43
-#define ADJD_S311_DATA_BLUE_LO	0x44
-#define ADJD_S311_DATA_BLUE_HI	0x45
-#define ADJD_S311_DATA_CLEAR_LO	0x46
-#define ADJD_S311_DATA_CLEAR_HI	0x47
+#define ADJD_S311_INT_RED	0x0a
+#define ADJD_S311_INT_GREEN	0x0c
+#define ADJD_S311_INT_BLUE	0x0e
+#define ADJD_S311_INT_CLEAR	0x10
+#define ADJD_S311_DATA_RED	0x40
+#define ADJD_S311_DATA_GREEN	0x42
+#define ADJD_S311_DATA_BLUE	0x44
+#define ADJD_S311_DATA_CLEAR	0x46
 #define ADJD_S311_OFFSET_RED	0x48
 #define ADJD_S311_OFFSET_GREEN	0x49
 #define ADJD_S311_OFFSET_BLUE	0x4a
@@ -73,8 +65,8 @@
 	IDX_RED, IDX_GREEN, IDX_BLUE, IDX_CLEAR
 };
 
-#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED_LO + (chan) * 2)
-#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED_LO + (chan) * 2)
+#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED + (chan) * 2)
+#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED + (chan) * 2)
 #define ADJD_S311_CAP_REG(chan) (ADJD_S311_CAP_RED + (chan))
 
 static int adjd_s311_req_data(struct iio_dev *indio_dev)
@@ -232,7 +224,8 @@
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		ret = adjd_s311_read_data(indio_dev, chan->address, val);
+		ret = adjd_s311_read_data(indio_dev,
+			ADJD_S311_DATA_REG(chan->address), val);
 		if (ret < 0)
 			return ret;
 		return IIO_VAL_INT;
@@ -293,11 +286,10 @@
 	struct iio_dev *indio_dev;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*data));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto exit;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
 	data = iio_priv(indio_dev);
 	i2c_set_clientdata(client, indio_dev);
 	data->client = client;
@@ -312,7 +304,7 @@
 	err = iio_triggered_buffer_setup(indio_dev, NULL,
 		adjd_s311_trigger_handler, NULL);
 	if (err < 0)
-		goto exit_free_device;
+		return err;
 
 	err = iio_device_register(indio_dev);
 	if (err)
@@ -324,9 +316,6 @@
 
 exit_unreg_buffer:
 	iio_triggered_buffer_cleanup(indio_dev);
-exit_free_device:
-	iio_device_free(indio_dev);
-exit:
 	return err;
 }
 
@@ -338,7 +327,6 @@
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	kfree(data->buffer);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c
new file mode 100644
index 0000000..66a58bd
--- /dev/null
+++ b/drivers/iio/light/apds9300.c
@@ -0,0 +1,512 @@
+/*
+ * apds9300.c - IIO driver for Avago APDS9300 ambient light sensor
+ *
+ * Copyright 2013 Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+
+#define APDS9300_DRV_NAME "apds9300"
+#define APDS9300_IRQ_NAME "apds9300_event"
+
+/* Command register bits */
+#define APDS9300_CMD	BIT(7) /* Select command register. Must write as 1 */
+#define APDS9300_WORD	BIT(5) /* I2C write/read: if 1 word, if 0 byte */
+#define APDS9300_CLEAR	BIT(6) /* Interrupt clear. Clears pending interrupt */
+
+/* Register set */
+#define APDS9300_CONTROL	0x00 /* Control of basic functions */
+#define APDS9300_THRESHLOWLOW	0x02 /* Low byte of low interrupt threshold */
+#define APDS9300_THRESHHIGHLOW	0x04 /* Low byte of high interrupt threshold */
+#define APDS9300_INTERRUPT	0x06 /* Interrupt control */
+#define APDS9300_DATA0LOW	0x0c /* Low byte of ADC channel 0 */
+#define APDS9300_DATA1LOW	0x0e /* Low byte of ADC channel 1 */
+
+/* Power on/off value for APDS9300_CONTROL register */
+#define APDS9300_POWER_ON	0x03
+#define APDS9300_POWER_OFF	0x00
+
+/* Interrupts */
+#define APDS9300_INTR_ENABLE	0x10
+/* Interrupt Persist Function: Any value outside of threshold range */
+#define APDS9300_THRESH_INTR	0x01
+
+#define APDS9300_THRESH_MAX	0xffff /* Max threshold value */
+
+struct apds9300_data {
+	struct i2c_client *client;
+	struct mutex mutex;
+	int power_state;
+	int thresh_low;
+	int thresh_hi;
+	int intr_en;
+};
+
+/* Lux calculation */
+
+/* Calculated values 1000 * (CH1/CH0)^1.4 for CH1/CH0 from 0 to 0.52 */
+static const u16 apds9300_lux_ratio[] = {
+	0, 2, 4, 7, 11, 15, 19, 24, 29, 34, 40, 45, 51, 57, 64, 70, 77, 84, 91,
+	98, 105, 112, 120, 128, 136, 144, 152, 160, 168, 177, 185, 194, 203,
+	212, 221, 230, 239, 249, 258, 268, 277, 287, 297, 307, 317, 327, 337,
+	347, 358, 368, 379, 390, 400,
+};
+
+static unsigned long apds9300_calculate_lux(u16 ch0, u16 ch1)
+{
+	unsigned long lux, tmp;
+
+	/* avoid division by zero */
+	if (ch0 == 0)
+		return 0;
+
+	tmp = DIV_ROUND_UP(ch1 * 100, ch0);
+	if (tmp <= 52) {
+		lux = 3150 * ch0 - (unsigned long)DIV_ROUND_UP_ULL(ch0
+				* apds9300_lux_ratio[tmp] * 5930ull, 1000);
+	} else if (tmp <= 65) {
+		lux = 2290 * ch0 - 2910 * ch1;
+	} else if (tmp <= 80) {
+		lux = 1570 * ch0 - 1800 * ch1;
+	} else if (tmp <= 130) {
+		lux = 338 * ch0 - 260 * ch1;
+	} else {
+		lux = 0;
+	}
+
+	return lux / 100000;
+}
+
+static int apds9300_get_adc_val(struct apds9300_data *data, int adc_number)
+{
+	int ret;
+	u8 flags = APDS9300_CMD | APDS9300_WORD;
+
+	if (!data->power_state)
+		return -EBUSY;
+
+	/* Select ADC0 or ADC1 data register */
+	flags |= adc_number ? APDS9300_DATA1LOW : APDS9300_DATA0LOW;
+
+	ret = i2c_smbus_read_word_data(data->client, flags);
+	if (ret < 0)
+		dev_err(&data->client->dev,
+			"failed to read ADC%d value\n", adc_number);
+
+	return ret;
+}
+
+static int apds9300_set_thresh_low(struct apds9300_data *data, int value)
+{
+	int ret;
+
+	if (!data->power_state)
+		return -EBUSY;
+
+	if (value > APDS9300_THRESH_MAX)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHLOWLOW
+			| APDS9300_CMD | APDS9300_WORD, value);
+	if (ret) {
+		dev_err(&data->client->dev, "failed to set thresh_low\n");
+		return ret;
+	}
+	data->thresh_low = value;
+
+	return 0;
+}
+
+static int apds9300_set_thresh_hi(struct apds9300_data *data, int value)
+{
+	int ret;
+
+	if (!data->power_state)
+		return -EBUSY;
+
+	if (value > APDS9300_THRESH_MAX)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHHIGHLOW
+			| APDS9300_CMD | APDS9300_WORD, value);
+	if (ret) {
+		dev_err(&data->client->dev, "failed to set thresh_hi\n");
+		return ret;
+	}
+	data->thresh_hi = value;
+
+	return 0;
+}
+
+static int apds9300_set_intr_state(struct apds9300_data *data, int state)
+{
+	int ret;
+	u8 cmd;
+
+	if (!data->power_state)
+		return -EBUSY;
+
+	cmd = state ? APDS9300_INTR_ENABLE | APDS9300_THRESH_INTR : 0x00;
+	ret = i2c_smbus_write_byte_data(data->client,
+			APDS9300_INTERRUPT | APDS9300_CMD, cmd);
+	if (ret) {
+		dev_err(&data->client->dev,
+			"failed to set interrupt state %d\n", state);
+		return ret;
+	}
+	data->intr_en = state;
+
+	return 0;
+}
+
+static int apds9300_set_power_state(struct apds9300_data *data, int state)
+{
+	int ret;
+	u8 cmd;
+
+	cmd = state ? APDS9300_POWER_ON : APDS9300_POWER_OFF;
+	ret = i2c_smbus_write_byte_data(data->client,
+			APDS9300_CONTROL | APDS9300_CMD, cmd);
+	if (ret) {
+		dev_err(&data->client->dev,
+			"failed to set power state %d\n", state);
+		return ret;
+	}
+	data->power_state = state;
+
+	return 0;
+}
+
+static void apds9300_clear_intr(struct apds9300_data *data)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte(data->client, APDS9300_CLEAR | APDS9300_CMD);
+	if (ret < 0)
+		dev_err(&data->client->dev, "failed to clear interrupt\n");
+}
+
+static int apds9300_chip_init(struct apds9300_data *data)
+{
+	int ret;
+
+	/* Need to set power off to ensure that the chip is off */
+	ret = apds9300_set_power_state(data, 0);
+	if (ret < 0)
+		goto err;
+	/*
+	 * Probe the chip. To do so we try to power up the device and then to
+	 * read back the 0x03 code
+	 */
+	ret = apds9300_set_power_state(data, 1);
+	if (ret < 0)
+		goto err;
+	ret = i2c_smbus_read_byte_data(data->client,
+			APDS9300_CONTROL | APDS9300_CMD);
+	if (ret != APDS9300_POWER_ON) {
+		ret = -ENODEV;
+		goto err;
+	}
+	/*
+	 * Disable interrupt to ensure thai it is doesn't enable
+	 * i.e. after device soft reset
+	 */
+	ret = apds9300_set_intr_state(data, 0);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	dev_err(&data->client->dev, "failed to init the chip\n");
+	return ret;
+}
+
+static int apds9300_read_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan, int *val, int *val2,
+		long mask)
+{
+	int ch0, ch1, ret = -EINVAL;
+	struct apds9300_data *data = iio_priv(indio_dev);
+
+	mutex_lock(&data->mutex);
+	switch (chan->type) {
+	case IIO_LIGHT:
+		ch0 = apds9300_get_adc_val(data, 0);
+		if (ch0 < 0) {
+			ret = ch0;
+			break;
+		}
+		ch1 = apds9300_get_adc_val(data, 1);
+		if (ch1 < 0) {
+			ret = ch1;
+			break;
+		}
+		*val = apds9300_calculate_lux(ch0, ch1);
+		ret = IIO_VAL_INT;
+		break;
+	case IIO_INTENSITY:
+		ret = apds9300_get_adc_val(data, chan->channel);
+		if (ret < 0)
+			break;
+		*val = ret;
+		ret = IIO_VAL_INT;
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int apds9300_read_thresh(struct iio_dev *indio_dev, u64 event_code,
+		int *val)
+{
+	struct apds9300_data *data = iio_priv(indio_dev);
+
+	switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+	case IIO_EV_DIR_RISING:
+		*val = data->thresh_hi;
+		break;
+	case IIO_EV_DIR_FALLING:
+		*val = data->thresh_low;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int apds9300_write_thresh(struct iio_dev *indio_dev, u64 event_code,
+		int val)
+{
+	struct apds9300_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING)
+		ret = apds9300_set_thresh_hi(data, val);
+	else
+		ret = apds9300_set_thresh_low(data, val);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,
+		u64 event_code)
+{
+	struct apds9300_data *data = iio_priv(indio_dev);
+
+	return data->intr_en;
+}
+
+static int apds9300_write_interrupt_config(struct iio_dev *indio_dev,
+		u64 event_code, int state)
+{
+	struct apds9300_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = apds9300_set_intr_state(data, state);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static const struct iio_info apds9300_info_no_irq = {
+	.driver_module	= THIS_MODULE,
+	.read_raw	= apds9300_read_raw,
+};
+
+static const struct iio_info apds9300_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= apds9300_read_raw,
+	.read_event_value	= apds9300_read_thresh,
+	.write_event_value	= apds9300_write_thresh,
+	.read_event_config	= apds9300_read_interrupt_config,
+	.write_event_config	= apds9300_write_interrupt_config,
+};
+
+static const struct iio_chan_spec apds9300_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.channel = 0,
+		.indexed = true,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+	}, {
+		.type = IIO_INTENSITY,
+		.channel = 0,
+		.channel2 = IIO_MOD_LIGHT_BOTH,
+		.indexed = true,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
+					  IIO_EV_DIR_RISING) |
+			       IIO_EV_BIT(IIO_EV_TYPE_THRESH,
+					  IIO_EV_DIR_FALLING)),
+	}, {
+		.type = IIO_INTENSITY,
+		.channel = 1,
+		.channel2 = IIO_MOD_LIGHT_IR,
+		.indexed = true,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+	},
+};
+
+static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
+{
+	struct iio_dev *dev_info = private;
+	struct apds9300_data *data = iio_priv(dev_info);
+
+	iio_push_event(dev_info,
+		       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
+					    IIO_EV_TYPE_THRESH,
+					    IIO_EV_DIR_EITHER),
+		       iio_get_time_ns());
+
+	apds9300_clear_intr(data);
+
+	return IRQ_HANDLED;
+}
+
+static int apds9300_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct apds9300_data *data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	ret = apds9300_chip_init(data);
+	if (ret < 0)
+		goto err;
+
+	mutex_init(&data->mutex);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = apds9300_channels;
+	indio_dev->num_channels = ARRAY_SIZE(apds9300_channels);
+	indio_dev->name = APDS9300_DRV_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	if (client->irq)
+		indio_dev->info = &apds9300_info;
+	else
+		indio_dev->info = &apds9300_info_no_irq;
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+				NULL, apds9300_interrupt_handler,
+				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				APDS9300_IRQ_NAME, indio_dev);
+		if (ret) {
+			dev_err(&client->dev, "irq request error %d\n", -ret);
+			goto err;
+		}
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	/* Ensure that power off in case of error */
+	apds9300_set_power_state(data, 0);
+	return ret;
+}
+
+static int apds9300_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct apds9300_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	/* Ensure that power off and interrupts are disabled */
+	apds9300_set_intr_state(data, 0);
+	apds9300_set_power_state(data, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int apds9300_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct apds9300_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = apds9300_set_power_state(data, 0);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int apds9300_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct apds9300_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = apds9300_set_power_state(data, 1);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume);
+#define APDS9300_PM_OPS (&apds9300_pm_ops)
+#else
+#define APDS9300_PM_OPS NULL
+#endif
+
+static struct i2c_device_id apds9300_id[] = {
+	{ APDS9300_DRV_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, apds9300_id);
+
+static struct i2c_driver apds9300_driver = {
+	.driver = {
+		.name	= APDS9300_DRV_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= APDS9300_PM_OPS,
+	},
+	.probe		= apds9300_probe,
+	.remove		= apds9300_remove,
+	.id_table	= apds9300_id,
+};
+
+module_i2c_driver(apds9300_driver);
+
+MODULE_AUTHOR("Kravchenko Oleksandr <o.v.kravchenko@globallogic.com>");
+MODULE_AUTHOR("GlobalLogic inc.");
+MODULE_DESCRIPTION("APDS9300 ambient light photo sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index cdc2cad..e59d00c 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -30,10 +30,6 @@
 #include <linux/iio/triggered_buffer.h>
 #include "../common/hid-sensors/hid-sensor-trigger.h"
 
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Ambiant-Light: 0x200041*/
-#define DRIVER_NAME "HID-SENSOR-200041"
-
 #define CHANNEL_SCAN_INDEX_ILLUM 0
 
 struct als_state {
@@ -158,18 +154,10 @@
 	return ret;
 }
 
-static int als_write_raw_get_fmt(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       long mask)
-{
-	return IIO_VAL_INT_PLUS_MICRO;
-}
-
 static const struct iio_info als_info = {
 	.driver_module = THIS_MODULE,
 	.read_raw = &als_read_raw,
 	.write_raw = &als_write_raw,
-	.write_raw_get_fmt = &als_write_raw_get_fmt,
 };
 
 /* Function to push data to buffer */
@@ -253,11 +241,9 @@
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 	struct iio_chan_spec *channels;
 
-	indio_dev = iio_device_alloc(sizeof(struct als_state));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state));
+	if (!indio_dev)
+		return -ENOMEM;
 	platform_set_drvdata(pdev, indio_dev);
 
 	als_state = iio_priv(indio_dev);
@@ -268,14 +254,13 @@
 					&als_state->common_attributes);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup common attributes\n");
-		goto error_free_dev;
+		return ret;
 	}
 
 	channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
 	if (!channels) {
-		ret = -ENOMEM;
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
-		goto error_free_dev;
+		return -ENOMEM;
 	}
 
 	ret = als_parse_report(pdev, hsdev, channels,
@@ -333,9 +318,6 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 error_free_dev_mem:
 	kfree(indio_dev->channels);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -350,14 +332,23 @@
 	hid_sensor_remove_trigger(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	kfree(indio_dev->channels);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
 
+static struct platform_device_id hid_als_ids[] = {
+	{
+		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+		.name = "HID-SENSOR-200041",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_als_ids);
+
 static struct platform_driver hid_als_platform_driver = {
+	.id_table = hid_als_ids,
 	.driver = {
-		.name	= DRIVER_NAME,
+		.name	= KBUILD_MODNAME,
 		.owner	= THIS_MODULE,
 	},
 	.probe		= hid_als_probe,
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 5fa31a4..c1aadc6 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -847,7 +847,7 @@
 		return -EINVAL;
 	}
 
-	indio_dev = iio_device_alloc(sizeof(*als));
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*als));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -870,7 +870,7 @@
 	if (als->irq) {
 		ret = lm3533_als_setup_irq(als, indio_dev);
 		if (ret)
-			goto err_free_dev;
+			return ret;
 	}
 
 	ret = lm3533_als_setup(als, pdata);
@@ -894,8 +894,6 @@
 err_free_irq:
 	if (als->irq)
 		free_irq(als->irq, indio_dev);
-err_free_dev:
-	iio_device_free(indio_dev);
 
 	return ret;
 }
@@ -910,7 +908,6 @@
 	lm3533_als_disable(als);
 	if (als->irq)
 		free_irq(als->irq, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index 1f529f3..ebb962c 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -702,7 +702,7 @@
 	int err = 0;
 	u8 id = 0;
 
-	indio_dev = iio_device_alloc(sizeof(*chip));
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -714,13 +714,13 @@
 	err = tsl2563_detect(chip);
 	if (err) {
 		dev_err(&client->dev, "detect error %d\n", -err);
-		goto fail1;
+		return err;
 	}
 
 	err = tsl2563_read_id(chip, &id);
 	if (err) {
 		dev_err(&client->dev, "read id error %d\n", -err);
-		goto fail1;
+		return err;
 	}
 
 	mutex_init(&chip->lock);
@@ -751,7 +751,7 @@
 		indio_dev->info = &tsl2563_info_no_irq;
 
 	if (client->irq) {
-		err = request_threaded_irq(client->irq,
+		err = devm_request_threaded_irq(&client->dev, client->irq,
 					   NULL,
 					   &tsl2563_event_handler,
 					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
@@ -759,14 +759,14 @@
 					   indio_dev);
 		if (err) {
 			dev_err(&client->dev, "irq request error %d\n", -err);
-			goto fail1;
+			return err;
 		}
 	}
 
 	err = tsl2563_configure(chip);
 	if (err) {
 		dev_err(&client->dev, "configure error %d\n", -err);
-		goto fail2;
+		return err;
 	}
 
 	INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
@@ -777,19 +777,14 @@
 	err = iio_device_register(indio_dev);
 	if (err) {
 		dev_err(&client->dev, "iio registration error %d\n", -err);
-		goto fail3;
+		goto fail;
 	}
 
 	return 0;
 
-fail3:
+fail:
 	cancel_delayed_work(&chip->poweroff_work);
 	flush_scheduled_work();
-fail2:
-	if (client->irq)
-		free_irq(client->irq, indio_dev);
-fail1:
-	iio_device_free(indio_dev);
 	return err;
 }
 
@@ -807,10 +802,6 @@
 				  chip->intr);
 	flush_scheduled_work();
 	tsl2563_set_power(chip, 0);
-	if (client->irq)
-		free_irq(client->irq, indio_dev);
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 1014943..2bb3042 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -157,7 +157,7 @@
 	struct iio_dev *indio_dev;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*data));
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
 		return -ENOMEM;
 
@@ -167,7 +167,7 @@
 
 	ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
 	if (ret < 0)
-		goto error_free_dev;
+		return ret;
 
 	dev_info(&client->dev, "VCNL4000 Ambient light/proximity sensor, Prod %02x, Rev: %02x\n",
 		ret >> 4, ret & 0xf);
@@ -181,22 +181,14 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret < 0)
-		goto error_free_dev;
+		return ret;
 
 	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-	return ret;
 }
 
 static int vcnl4000_remove(struct i2c_client *client)
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
-	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
-
+	iio_device_unregister(i2c_get_clientdata(client));
 	return 0;
 }
 
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index c332b0a..4fa923f 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -1,6 +1,8 @@
 #
 # Magnetometer sensors
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Magnetometer sensors"
 
 config AK8975
@@ -36,8 +38,8 @@
 	  Say yes here to build support for STMicroelectronics magnetometers:
 	  LSM303DLHC, LSM303DLM, LIS3MDL.
 
-	  This driver can also be built as a module. If so, will be created
-	  these modules:
+	  This driver can also be built as a module. If so, these modules
+	  will be created:
 	  - st_magn (core functions for the driver [it is mandatory]);
 	  - st_magn_i2c (necessary for the I2C devices [optional*]);
 	  - st_magn_spi (necessary for the SPI devices [optional*]);
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index 7f328e3..f91b1b6 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -2,6 +2,7 @@
 # Makefile for industrial I/O Magnetometer sensor drivers
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
 
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 99f4e49..a98460b 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -30,10 +30,6 @@
 #include <linux/iio/triggered_buffer.h>
 #include "../common/hid-sensors/hid-sensor-trigger.h"
 
-/*Format: HID-SENSOR-usage_id_in_hex*/
-/*Usage ID from spec for Magnetometer-3D: 0x200083*/
-#define DRIVER_NAME "HID-SENSOR-200083"
-
 enum magn_3d_channel {
 	CHANNEL_SCAN_INDEX_X,
 	CHANNEL_SCAN_INDEX_Y,
@@ -180,18 +176,10 @@
 	return ret;
 }
 
-static int magn_3d_write_raw_get_fmt(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       long mask)
-{
-	return IIO_VAL_INT_PLUS_MICRO;
-}
-
 static const struct iio_info magn_3d_info = {
 	.driver_module = THIS_MODULE,
 	.read_raw = &magn_3d_read_raw,
 	.write_raw = &magn_3d_write_raw,
-	.write_raw_get_fmt = &magn_3d_write_raw_get_fmt,
 };
 
 /* Function to push data to buffer */
@@ -287,11 +275,11 @@
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 	struct iio_chan_spec *channels;
 
-	indio_dev = iio_device_alloc(sizeof(struct magn_3d_state));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					  sizeof(struct magn_3d_state));
+	if (indio_dev == NULL)
+		return -ENOMEM;
+
 	platform_set_drvdata(pdev, indio_dev);
 
 	magn_state = iio_priv(indio_dev);
@@ -303,15 +291,14 @@
 				&magn_state->common_attributes);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup common attributes\n");
-		goto error_free_dev;
+		return ret;
 	}
 
 	channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
 			   GFP_KERNEL);
 	if (!channels) {
-		ret = -ENOMEM;
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
-		goto error_free_dev;
+		return -ENOMEM;
 	}
 
 	ret = magn_3d_parse_report(pdev, hsdev, channels,
@@ -368,9 +355,6 @@
 	iio_triggered_buffer_cleanup(indio_dev);
 error_free_dev_mem:
 	kfree(indio_dev->channels);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -385,14 +369,23 @@
 	hid_sensor_remove_trigger(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	kfree(indio_dev->channels);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
 
+static struct platform_device_id hid_magn_3d_ids[] = {
+	{
+		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+		.name = "HID-SENSOR-200083",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_magn_3d_ids);
+
 static struct platform_driver hid_magn_3d_platform_driver = {
+	.id_table = hid_magn_3d_ids,
 	.driver = {
-		.name	= DRIVER_NAME,
+		.name	= KBUILD_MODNAME,
 		.owner	= THIS_MODULE,
 	},
 	.probe		= hid_magn_3d_probe,
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 7e81d00..694e33e 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -18,7 +18,8 @@
 #define LSM303DLM_MAGN_DEV_NAME		"lsm303dlm_magn"
 #define LIS3MDL_MAGN_DEV_NAME		"lis3mdl"
 
-int st_magn_common_probe(struct iio_dev *indio_dev);
+int st_magn_common_probe(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata);
 void st_magn_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index ebfe8f1..e8d2849 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -345,7 +345,8 @@
 	.write_raw = &st_magn_write_raw,
 };
 
-int st_magn_common_probe(struct iio_dev *indio_dev)
+int st_magn_common_probe(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata)
 {
 	int err;
 	struct st_sensor_data *mdata = iio_priv(indio_dev);
@@ -367,7 +368,7 @@
 						&mdata->sensor->fs.fs_avl[0];
 	mdata->odr = mdata->sensor->odr.odr_avl[0].hz;
 
-	err = st_sensors_init_sensor(indio_dev);
+	err = st_sensors_init_sensor(indio_dev, pdata);
 	if (err < 0)
 		goto st_magn_common_probe_error;
 
@@ -406,7 +407,6 @@
 		st_sensors_deallocate_trigger(indio_dev);
 		st_magn_deallocate_ring(indio_dev);
 	}
-	iio_device_free(indio_dev);
 }
 EXPORT_SYMBOL(st_magn_common_remove);
 
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index e6adc4a..892e0fe 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -25,27 +25,20 @@
 	struct st_sensor_data *mdata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*mdata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mdata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	mdata = iio_priv(indio_dev);
 	mdata->dev = &client->dev;
 
 	st_sensors_i2c_configure(indio_dev, client, mdata);
 
-	err = st_magn_common_probe(indio_dev);
+	err = st_magn_common_probe(indio_dev, NULL);
 	if (err < 0)
-		goto st_magn_common_probe_error;
+		return err;
 
 	return 0;
-
-st_magn_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_magn_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 51adb79..a6143ea 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -24,27 +24,20 @@
 	struct st_sensor_data *mdata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*mdata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*mdata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	mdata = iio_priv(indio_dev);
 	mdata->dev = &spi->dev;
 
 	st_sensors_spi_configure(indio_dev, spi, mdata);
 
-	err = st_magn_common_probe(indio_dev);
+	err = st_magn_common_probe(indio_dev, NULL);
 	if (err < 0)
-		goto st_magn_common_probe_error;
+		return err;
 
 	return 0;
-
-st_magn_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_magn_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 9427f01..26fdc0b 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -1,21 +1,23 @@
 #
 # Pressure drivers
 #
-menu "Pressure Sensors"
+# When adding new entries keep the list in alphabetical order
+
+menu "Pressure sensors"
 
 config IIO_ST_PRESS
-	tristate "STMicroelectronics pressures Driver"
+	tristate "STMicroelectronics pressure sensor Driver"
 	depends on (I2C || SPI_MASTER) && SYSFS
 	select IIO_ST_SENSORS_CORE
 	select IIO_ST_PRESS_I2C if (I2C)
 	select IIO_ST_PRESS_SPI if (SPI_MASTER)
 	select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
 	help
-	  Say yes here to build support for STMicroelectronics pressures:
-	  LPS331AP.
+	  Say yes here to build support for STMicroelectronics pressure
+	  sensors: LPS331AP.
 
-	  This driver can also be built as a module. If so, will be created
-	  these modules:
+	  This driver can also be built as a module. If so, these modules
+	  will be created:
 	  - st_pressure (core functions for the driver [it is mandatory]);
 	  - st_pressure_i2c (necessary for the I2C devices [optional*]);
 	  - st_pressure_spi (necessary for the SPI devices [optional*]);
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index d4bb33e..be71464 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -2,6 +2,7 @@
 # Makefile for industrial I/O pressure drivers
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
 st_pressure-y := st_pressure_core.o
 st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h
index 414e45a..b0b6306 100644
--- a/drivers/iio/pressure/st_pressure.h
+++ b/drivers/iio/pressure/st_pressure.h
@@ -16,7 +16,16 @@
 
 #define LPS331AP_PRESS_DEV_NAME		"lps331ap"
 
-int st_press_common_probe(struct iio_dev *indio_dev);
+/**
+ * struct st_sensors_platform_data - default press platform data
+ * @drdy_int_pin: default press DRDY is available on INT1 pin.
+ */
+static const struct st_sensors_platform_data default_press_pdata = {
+	.drdy_int_pin = 1,
+};
+
+int st_press_common_probe(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata);
 void st_press_common_remove(struct iio_dev *indio_dev);
 
 #ifdef CONFIG_IIO_BUFFER
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index 3ffbc56..ceebd3c 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -31,6 +31,9 @@
 #define ST_PRESS_LSB_PER_MBAR			4096UL
 #define ST_PRESS_KPASCAL_NANO_SCALE		(100000000UL / \
 						 ST_PRESS_LSB_PER_MBAR)
+#define ST_PRESS_LSB_PER_CELSIUS		480UL
+#define ST_PRESS_CELSIUS_NANO_SCALE		(1000000000UL / \
+						 ST_PRESS_LSB_PER_CELSIUS)
 #define ST_PRESS_NUMBER_DATA_CHANNELS		1
 
 /* DEFAULT VALUE FOR SENSORS */
@@ -53,12 +56,13 @@
 #define ST_PRESS_1_FS_ADDR			0x23
 #define ST_PRESS_1_FS_MASK			0x30
 #define ST_PRESS_1_FS_AVL_1260_VAL		0x00
-#define ST_PRESS_1_FS_AVL_TEMP_GAIN		2083000
 #define ST_PRESS_1_FS_AVL_1260_GAIN		ST_PRESS_KPASCAL_NANO_SCALE
+#define ST_PRESS_1_FS_AVL_TEMP_GAIN		ST_PRESS_CELSIUS_NANO_SCALE
 #define ST_PRESS_1_BDU_ADDR			0x20
 #define ST_PRESS_1_BDU_MASK			0x04
 #define ST_PRESS_1_DRDY_IRQ_ADDR		0x22
-#define ST_PRESS_1_DRDY_IRQ_MASK		0x04
+#define ST_PRESS_1_DRDY_IRQ_INT1_MASK		0x04
+#define ST_PRESS_1_DRDY_IRQ_INT2_MASK		0x20
 #define ST_PRESS_1_MULTIREAD_BIT		true
 #define ST_PRESS_1_TEMP_OFFSET			42500
 
@@ -116,7 +120,8 @@
 		},
 		.drdy_irq = {
 			.addr = ST_PRESS_1_DRDY_IRQ_ADDR,
-			.mask = ST_PRESS_1_DRDY_IRQ_MASK,
+			.mask_int1 = ST_PRESS_1_DRDY_IRQ_INT1_MASK,
+			.mask_int2 = ST_PRESS_1_DRDY_IRQ_INT2_MASK,
 		},
 		.multi_read_bit = ST_PRESS_1_MULTIREAD_BIT,
 		.bootime = 2,
@@ -202,7 +207,8 @@
 #define ST_PRESS_TRIGGER_OPS NULL
 #endif
 
-int st_press_common_probe(struct iio_dev *indio_dev)
+int st_press_common_probe(struct iio_dev *indio_dev,
+				struct st_sensors_platform_data *plat_data)
 {
 	int err;
 	struct st_sensor_data *pdata = iio_priv(indio_dev);
@@ -224,7 +230,11 @@
 						&pdata->sensor->fs.fs_avl[0];
 	pdata->odr = pdata->sensor->odr.odr_avl[0].hz;
 
-	err = st_sensors_init_sensor(indio_dev);
+	if (!plat_data)
+		plat_data =
+			(struct st_sensors_platform_data *)&default_press_pdata;
+
+	err = st_sensors_init_sensor(indio_dev, plat_data);
 	if (err < 0)
 		goto st_press_common_probe_error;
 
@@ -265,7 +275,6 @@
 		st_sensors_deallocate_trigger(indio_dev);
 		st_press_deallocate_ring(indio_dev);
 	}
-	iio_device_free(indio_dev);
 }
 EXPORT_SYMBOL(st_press_common_remove);
 
diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c
index 7cebcc7..08aac5e 100644
--- a/drivers/iio/pressure/st_pressure_i2c.c
+++ b/drivers/iio/pressure/st_pressure_i2c.c
@@ -25,27 +25,20 @@
 	struct st_sensor_data *pdata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*pdata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*pdata));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	pdata = iio_priv(indio_dev);
 	pdata->dev = &client->dev;
 
 	st_sensors_i2c_configure(indio_dev, client, pdata);
 
-	err = st_press_common_probe(indio_dev);
+	err = st_press_common_probe(indio_dev, client->dev.platform_data);
 	if (err < 0)
-		goto st_press_common_probe_error;
+		return err;
 
 	return 0;
-
-st_press_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_press_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c
index 17a1490..399a29b 100644
--- a/drivers/iio/pressure/st_pressure_spi.c
+++ b/drivers/iio/pressure/st_pressure_spi.c
@@ -24,27 +24,20 @@
 	struct st_sensor_data *pdata;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*pdata));
-	if (indio_dev == NULL) {
-		err = -ENOMEM;
-		goto iio_device_alloc_error;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*pdata));
+	if (indio_dev == NULL)
+		return -ENOMEM;
 
 	pdata = iio_priv(indio_dev);
 	pdata->dev = &spi->dev;
 
 	st_sensors_spi_configure(indio_dev, spi, pdata);
 
-	err = st_press_common_probe(indio_dev);
+	err = st_press_common_probe(indio_dev, spi->dev.platform_data);
 	if (err < 0)
-		goto st_press_common_probe_error;
+		return err;
 
 	return 0;
-
-st_press_common_probe_error:
-	iio_device_free(indio_dev);
-iio_device_alloc_error:
-	return err;
 }
 
 static int st_press_spi_remove(struct spi_device *spi)
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
new file mode 100644
index 0000000..372f8fb
--- /dev/null
+++ b/drivers/iio/temperature/Kconfig
@@ -0,0 +1,16 @@
+#
+# Temperature sensor drivers
+#
+menu "Temperature sensors"
+
+config TMP006
+	tristate "TMP006 infrared thermopile sensor"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Texas Instruments
+	  TMP006 infrared thermopile sensor.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called tmp006.
+
+endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
new file mode 100644
index 0000000..24d7b60
--- /dev/null
+++ b/drivers/iio/temperature/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O temperature drivers
+#
+
+obj-$(CONFIG_TMP006) += tmp006.o
diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c
new file mode 100644
index 0000000..64ccde3
--- /dev/null
+++ b/drivers/iio/temperature/tmp006.c
@@ -0,0 +1,291 @@
+/*
+ * tmp006.c - Support for TI TMP006 IR thermopile sensor
+ *
+ * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
+ *
+ * (7-bit I2C slave address 0x40, changeable via ADR pins)
+ *
+ * TODO: data ready irq
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define TMP006_VOBJECT 0x00
+#define TMP006_TAMBIENT 0x01
+#define TMP006_CONFIG 0x02
+#define TMP006_MANUFACTURER_ID 0xfe
+#define TMP006_DEVICE_ID 0xff
+
+#define TMP006_TAMBIENT_SHIFT 2
+
+#define TMP006_CONFIG_RESET BIT(15)
+#define TMP006_CONFIG_DRDY_EN BIT(8)
+#define TMP006_CONFIG_DRDY BIT(7)
+
+#define TMP006_CONFIG_MOD_MASK 0x7000
+
+#define TMP006_CONFIG_CR_MASK 0x0e00
+#define TMP006_CONFIG_CR_SHIFT 9
+
+#define MANUFACTURER_MAGIC 0x5449
+#define DEVICE_MAGIC 0x0067
+
+struct tmp006_data {
+	struct i2c_client *client;
+	u16 config;
+};
+
+static int tmp006_read_measurement(struct tmp006_data *data, u8 reg)
+{
+	s32 ret;
+	int tries = 50;
+
+	while (tries-- > 0) {
+		ret = i2c_smbus_read_word_swapped(data->client,
+			TMP006_CONFIG);
+		if (ret < 0)
+			return ret;
+		if (ret & TMP006_CONFIG_DRDY)
+			break;
+		msleep(100);
+	}
+
+	if (tries < 0)
+		return -EIO;
+
+	return i2c_smbus_read_word_swapped(data->client, reg);
+}
+
+static int tmp006_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *channel, int *val,
+			    int *val2, long mask)
+{
+	struct tmp006_data *data = iio_priv(indio_dev);
+	s32 ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (channel->type == IIO_VOLTAGE) {
+			/* LSB is 156.25 nV */
+			ret = tmp006_read_measurement(data, TMP006_VOBJECT);
+			if (ret < 0)
+				return ret;
+			*val = sign_extend32(ret, 15);
+		} else if (channel->type == IIO_TEMP) {
+			/* LSB is 0.03125 degrees Celsius */
+			ret = tmp006_read_measurement(data, TMP006_TAMBIENT);
+			if (ret < 0)
+				return ret;
+			*val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT;
+		} else {
+			break;
+		}
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (channel->type == IIO_VOLTAGE) {
+			*val = 0;
+			*val2 = 156250;
+		} else if (channel->type == IIO_TEMP) {
+			*val = 31;
+			*val2 = 250000;
+		} else {
+			break;
+		}
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const char * const tmp006_freqs[] = { "4", "2", "1", "0.5", "0.25" };
+
+static ssize_t tmp006_show_freq(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev));
+	int cr = (data->config & TMP006_CONFIG_CR_MASK)
+		>> TMP006_CONFIG_CR_SHIFT;
+	return sprintf(buf, "%s\n", tmp006_freqs[cr]);
+}
+
+static ssize_t tmp006_store_freq(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct tmp006_data *data = iio_priv(indio_dev);
+	int i;
+	bool found = false;
+
+	for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++)
+		if (sysfs_streq(buf, tmp006_freqs[i])) {
+			found = true;
+			break;
+		}
+	if (!found)
+		return -EINVAL;
+
+	data->config &= ~TMP006_CONFIG_CR_MASK;
+	data->config |= i << TMP006_CONFIG_CR_SHIFT;
+
+	return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+		data->config);
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR,
+			tmp006_show_freq, tmp006_store_freq);
+
+static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
+
+static struct attribute *tmp006_attributes[] = {
+	&iio_dev_attr_sampling_frequency.dev_attr.attr,
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group tmp006_attribute_group = {
+	.attrs = tmp006_attributes,
+};
+
+static const struct iio_chan_spec tmp006_channels[] = {
+	{
+		.type = IIO_VOLTAGE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+	},
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+	}
+};
+
+static const struct iio_info tmp006_info = {
+	.read_raw = tmp006_read_raw,
+	.attrs = &tmp006_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static bool tmp006_check_identification(struct i2c_client *client)
+{
+	int mid, did;
+
+	mid = i2c_smbus_read_word_swapped(client, TMP006_MANUFACTURER_ID);
+	if (mid < 0)
+		return false;
+
+	did = i2c_smbus_read_word_swapped(client, TMP006_DEVICE_ID);
+	if (did < 0)
+		return false;
+
+	return mid == MANUFACTURER_MAGIC && did == DEVICE_MAGIC;
+}
+
+static int tmp006_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct tmp006_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -ENODEV;
+
+	if (!tmp006_check_identification(client)) {
+		dev_err(&client->dev, "no TMP006 sensor\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &tmp006_info;
+
+	indio_dev->channels = tmp006_channels;
+	indio_dev->num_channels = ARRAY_SIZE(tmp006_channels);
+
+	ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG);
+	if (ret < 0)
+		return ret;
+	data->config = ret;
+
+	return iio_device_register(indio_dev);
+}
+
+static int tmp006_powerdown(struct tmp006_data *data)
+{
+	return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+		data->config & ~TMP006_CONFIG_MOD_MASK);
+}
+
+static int tmp006_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	tmp006_powerdown(iio_priv(indio_dev));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tmp006_suspend(struct device *dev)
+{
+	return tmp006_powerdown(iio_priv(dev_to_iio_dev(dev)));
+}
+
+static int tmp006_resume(struct device *dev)
+{
+	struct tmp006_data *data = iio_priv(dev_to_iio_dev(dev));
+	return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
+		data->config | TMP006_CONFIG_MOD_MASK);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
+
+static const struct i2c_device_id tmp006_id[] = {
+	{ "tmp006", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tmp006_id);
+
+static struct i2c_driver tmp006_driver = {
+	.driver = {
+		.name	= "tmp006",
+		.pm	= &tmp006_pm_ops,
+		.owner	= THIS_MODULE,
+	},
+	.probe = tmp006_probe,
+	.remove = tmp006_remove,
+	.id_table = tmp006_id,
+};
+module_i2c_driver(tmp006_driver);
+
+MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_DESCRIPTION("TI TMP006 IR thermopile sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
index 360fd50..7999612 100644
--- a/drivers/iio/trigger/Kconfig
+++ b/drivers/iio/trigger/Kconfig
@@ -1,6 +1,8 @@
 #
 # Industrial I/O standalone triggers
 #
+# When adding new entries keep the list in alphabetical order
+
 menu "Triggers - standalone"
 
 config IIO_INTERRUPT_TRIGGER
@@ -17,7 +19,7 @@
 	depends on SYSFS
 	select IRQ_WORK
 	help
-	  Provides support for using SYSFS entry as IIO triggers.
+	  Provides support for using SYSFS entries as IIO triggers.
 	  If unsure, say N (but it's safe to say "Y").
 
 	  To compile this driver as a module, choose M here: the
diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
index ce319a5..0694dae 100644
--- a/drivers/iio/trigger/Makefile
+++ b/drivers/iio/trigger/Makefile
@@ -2,5 +2,6 @@
 # Makefile for triggers not associated with iio-devices
 #
 
+# When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
 obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 7c0f953..6bd197f 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3208,7 +3208,7 @@
 						id_priv->id.port_num, &rec,
 						comp_mask, GFP_KERNEL,
 						cma_ib_mc_handler, mc);
-	return PTR_RET(mc->multicast.ib);
+	return PTR_ERR_OR_ZERO(mc->multicast.ib);
 }
 
 static void iboe_mcast_work_handler(struct work_struct *work)
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 2e84ef8..1ec78bd8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -672,6 +672,7 @@
 		case ISCSI_PARAM_TGT_RESET_TMO:
 		case ISCSI_PARAM_IFACE_NAME:
 		case ISCSI_PARAM_INITIATOR_NAME:
+		case ISCSI_PARAM_DISCOVERY_SESS:
 			return S_IRUGO;
 		default:
 			return 0;
@@ -701,7 +702,7 @@
 static struct iscsi_transport iscsi_iser_transport = {
 	.owner                  = THIS_MODULE,
 	.name                   = "iser",
-	.caps                   = CAP_RECOVERY_L0 | CAP_MULTI_R2T,
+	.caps                   = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_TEXT_NEGO,
 	/* session management */
 	.create_session         = iscsi_iser_session_create,
 	.destroy_session        = iscsi_iser_session_destroy,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index b6d81a8..b31fa1d 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -234,6 +234,7 @@
 static int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req)
 {
 	struct iscsi_iser_conn *iser_conn = conn->dd_data;
+	struct iscsi_session *session = conn->session;
 
 	iser_dbg("req op %x flags %x\n", req->opcode, req->flags);
 	/* check if this is the last login - going to full feature phase */
@@ -248,7 +249,13 @@
 	WARN_ON(iser_conn->ib_conn->post_recv_buf_count != 1);
 	WARN_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
 
-	iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);
+	if (session->discovery_sess) {
+		iser_info("Discovery session, re-using login RX buffer\n");
+		return 0;
+	} else
+		iser_info("Normal session, posting batch of RX %d buffers\n",
+			  ISER_MIN_POSTED_RX);
+
 	/* Initial post receive buffers */
 	if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))
 		return -ENOMEM;
@@ -425,6 +432,8 @@
 	}
 
 	if (task == conn->login_task) {
+		iser_dbg("op %x dsl %lx, posting login rx buffer\n",
+			 task->hdr->opcode, data_seg_len);
 		err = iser_post_recvl(iser_conn->ib_conn);
 		if (err)
 			goto send_control_error;
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index da739d9..922a7fe 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -639,16 +639,18 @@
  * Gameport driver operations
  */
 
-static ssize_t gameport_driver_show_description(struct device_driver *drv, char *buf)
+static ssize_t description_show(struct device_driver *drv, char *buf)
 {
 	struct gameport_driver *driver = to_gameport_driver(drv);
 	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
 }
+static DRIVER_ATTR_RO(description);
 
-static struct driver_attribute gameport_driver_attrs[] = {
-	__ATTR(description, S_IRUGO, gameport_driver_show_description, NULL),
-	__ATTR_NULL
+static struct attribute *gameport_driver_attrs[] = {
+	&driver_attr_description.attr,
+	NULL
 };
+ATTRIBUTE_GROUPS(gameport_driver);
 
 static int gameport_driver_probe(struct device *dev)
 {
@@ -749,7 +751,7 @@
 static struct bus_type gameport_bus = {
 	.name		= "gameport",
 	.dev_attrs	= gameport_device_attrs,
-	.drv_attrs	= gameport_driver_attrs,
+	.drv_groups	= gameport_driver_groups,
 	.match		= gameport_bus_match,
 	.probe		= gameport_driver_probe,
 	.remove		= gameport_driver_remove,
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index fa061d4..75e3b10 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -167,6 +167,7 @@
 	{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
 	{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
 	{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x1689, 0xfd01, "Razer Onza Classic Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 57b2637..8551dca 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -672,6 +672,7 @@
  */
 static int elantech_packet_check_v3(struct psmouse *psmouse)
 {
+	struct elantech_data *etd = psmouse->private;
 	const u8 debounce_packet[] = { 0xc4, 0xff, 0xff, 0x02, 0xff, 0xff };
 	unsigned char *packet = psmouse->packet;
 
@@ -682,19 +683,48 @@
 	if (!memcmp(packet, debounce_packet, sizeof(debounce_packet)))
 		return PACKET_DEBOUNCE;
 
-	if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02)
-		return PACKET_V3_HEAD;
+	/*
+	 * If the hardware flag 'crc_enabled' is set the packets have
+	 * different signatures.
+	 */
+	if (etd->crc_enabled) {
+		if ((packet[3] & 0x09) == 0x08)
+			return PACKET_V3_HEAD;
 
-	if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
-		return PACKET_V3_TAIL;
+		if ((packet[3] & 0x09) == 0x09)
+			return PACKET_V3_TAIL;
+	} else {
+		if ((packet[0] & 0x0c) == 0x04 && (packet[3] & 0xcf) == 0x02)
+			return PACKET_V3_HEAD;
+
+		if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
+			return PACKET_V3_TAIL;
+	}
 
 	return PACKET_UNKNOWN;
 }
 
 static int elantech_packet_check_v4(struct psmouse *psmouse)
 {
+	struct elantech_data *etd = psmouse->private;
 	unsigned char *packet = psmouse->packet;
 	unsigned char packet_type = packet[3] & 0x03;
+	bool sanity_check;
+
+	/*
+	 * Sanity check based on the constant bits of a packet.
+	 * The constant bits change depending on the value of
+	 * the hardware flag 'crc_enabled' but are the same for
+	 * every packet, regardless of the type.
+	 */
+	if (etd->crc_enabled)
+		sanity_check = ((packet[3] & 0x08) == 0x00);
+	else
+		sanity_check = ((packet[0] & 0x0c) == 0x04 &&
+				(packet[3] & 0x1c) == 0x10);
+
+	if (!sanity_check)
+		return PACKET_UNKNOWN;
 
 	switch (packet_type) {
 	case 0:
@@ -1313,6 +1343,12 @@
 			etd->reports_pressure = true;
 	}
 
+	/*
+	 * The signatures of v3 and v4 packets change depending on the
+	 * value of this hardware flag.
+	 */
+	etd->crc_enabled = ((etd->fw_version & 0x4000) == 0x4000);
+
 	return 0;
 }
 
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index 46db3be..036a04a 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -129,6 +129,7 @@
 	bool paritycheck;
 	bool jumpy_cursor;
 	bool reports_pressure;
+	bool crc_enabled;
 	unsigned char hw_version;
 	unsigned int fw_version;
 	unsigned int single_finger_reports;
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 94c17c2..1e691a3 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -22,7 +22,8 @@
 	tristate "i8042 PC Keyboard controller" if EXPERT || !X86
 	default y
 	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
-		   (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390
+		   (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN && !S390 && \
+		   !ARC
 	help
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  mouse are connected to the computer. If you use these devices,
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 25fc597..2b56855 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -732,19 +732,20 @@
  * Serio driver operations
  */
 
-static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf)
+static ssize_t description_show(struct device_driver *drv, char *buf)
 {
 	struct serio_driver *driver = to_serio_driver(drv);
 	return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)");
 }
+static DRIVER_ATTR_RO(description);
 
-static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf)
+static ssize_t bind_mode_show(struct device_driver *drv, char *buf)
 {
 	struct serio_driver *serio_drv = to_serio_driver(drv);
 	return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto");
 }
 
-static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count)
+static ssize_t bind_mode_store(struct device_driver *drv, const char *buf, size_t count)
 {
 	struct serio_driver *serio_drv = to_serio_driver(drv);
 	int retval;
@@ -760,14 +761,14 @@
 
 	return retval;
 }
+static DRIVER_ATTR_RW(bind_mode);
 
-
-static struct driver_attribute serio_driver_attrs[] = {
-	__ATTR(description, S_IRUGO, serio_driver_show_description, NULL),
-	__ATTR(bind_mode, S_IWUSR | S_IRUGO,
-		serio_driver_show_bind_mode, serio_driver_set_bind_mode),
-	__ATTR_NULL
+static struct attribute *serio_driver_attrs[] = {
+	&driver_attr_description.attr,
+	&driver_attr_bind_mode.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(serio_driver);
 
 static int serio_driver_probe(struct device *dev)
 {
@@ -996,7 +997,7 @@
 static struct bus_type serio_bus = {
 	.name		= "serio",
 	.dev_attrs	= serio_device_attrs,
-	.drv_attrs	= serio_driver_attrs,
+	.drv_groups	= serio_driver_groups,
 	.match		= serio_bus_match,
 	.uevent		= serio_uevent,
 	.probe		= serio_driver_probe,
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 384fbcd..f3e91f0 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -2112,7 +2112,7 @@
 	{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN,  14720,  9200, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
 	  .touch_max = 2 };
-static struct wacom_features wacom_features_0xDB =
+static const struct wacom_features wacom_features_0xDB =
 	{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN,  21648, 13700, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
 	  .touch_max = 2 };
@@ -2127,6 +2127,12 @@
         { "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN,    21648, 13700, 1023,
 	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
 	  .touch_max = 16 };
+static const struct wacom_features wacom_features_0x300 =
+	{ "Wacom Bamboo One S",    WACOM_PKGLEN_BBPEN,    14720,  9225, 1023,
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x301 =
+	{ "Wacom Bamboo One M",    WACOM_PKGLEN_BBPEN,    21648, 13530, 1023,
+	  31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x6004 =
 	{ "ISD-V4",               WACOM_PKGLEN_GRAPHIRE,  12800,  8000,  255,
 	  0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2253,6 +2259,8 @@
 	{ USB_DEVICE_WACOM(0x100) },
 	{ USB_DEVICE_WACOM(0x101) },
 	{ USB_DEVICE_WACOM(0x10D) },
+	{ USB_DEVICE_WACOM(0x300) },
+	{ USB_DEVICE_WACOM(0x301) },
 	{ USB_DEVICE_WACOM(0x304) },
 	{ USB_DEVICE_WACOM(0x4001) },
 	{ USB_DEVICE_WACOM(0x47) },
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 69ea44e..4851afa 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -23,7 +23,7 @@
 #define SIRFSOC_INT_RISC_LEVEL1         0x0024
 #define SIRFSOC_INIT_IRQ_ID		0x0038
 
-#define SIRFSOC_NUM_IRQS		128
+#define SIRFSOC_NUM_IRQS		64
 
 static struct irq_domain *sirfsoc_irqdomain;
 
@@ -32,15 +32,18 @@
 {
 	struct irq_chip_generic *gc;
 	struct irq_chip_type *ct;
+	int ret;
+	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
 
-	gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq);
+	ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc",
+		handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+
+	gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start);
+	gc->reg_base = base;
 	ct = gc->chip_types;
-
 	ct->chip.irq_mask = irq_gc_mask_clr_bit;
 	ct->chip.irq_unmask = irq_gc_mask_set_bit;
 	ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
-
-	irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0);
 }
 
 static asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
@@ -60,9 +63,8 @@
 	if (!base)
 		panic("unable to map intc cpu registers\n");
 
-	/* using legacy because irqchip_generic does not work with linear */
-	sirfsoc_irqdomain = irq_domain_add_legacy(np, SIRFSOC_NUM_IRQS, 0, 0,
-				 &irq_domain_simple_ops, base);
+	sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS,
+		&irq_generic_chip_ops, base);
 
 	sirfsoc_alloc_gc(base, 0, 32);
 	sirfsoc_alloc_gc(base + 4, 32, SIRFSOC_NUM_IRQS - 32);
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index da30c5c..faf5054 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -37,8 +37,8 @@
 	/* nothing to do: the device is part of its parent's data structure */
 }
 
-static ssize_t _show_id(struct device *dev,
-			struct device_attribute *attr, char *buf)
+static ssize_t id_show(struct device *dev,
+		       struct device_attribute *attr, char *buf)
 {
 	struct mISDNdevice *mdev = dev_to_mISDN(dev);
 
@@ -46,9 +46,10 @@
 		return -ENODEV;
 	return sprintf(buf, "%d\n", mdev->id);
 }
+static DEVICE_ATTR_RO(id);
 
-static ssize_t _show_nrbchan(struct device *dev,
-			     struct device_attribute *attr, char *buf)
+static ssize_t nrbchan_show(struct device *dev,
+			    struct device_attribute *attr, char *buf)
 {
 	struct mISDNdevice *mdev = dev_to_mISDN(dev);
 
@@ -56,9 +57,10 @@
 		return -ENODEV;
 	return sprintf(buf, "%d\n", mdev->nrbchan);
 }
+static DEVICE_ATTR_RO(nrbchan);
 
-static ssize_t _show_d_protocols(struct device *dev,
-				 struct device_attribute *attr, char *buf)
+static ssize_t d_protocols_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct mISDNdevice *mdev = dev_to_mISDN(dev);
 
@@ -66,9 +68,10 @@
 		return -ENODEV;
 	return sprintf(buf, "%d\n", mdev->Dprotocols);
 }
+static DEVICE_ATTR_RO(d_protocols);
 
-static ssize_t _show_b_protocols(struct device *dev,
-				 struct device_attribute *attr, char *buf)
+static ssize_t b_protocols_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct mISDNdevice *mdev = dev_to_mISDN(dev);
 
@@ -76,9 +79,10 @@
 		return -ENODEV;
 	return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols());
 }
+static DEVICE_ATTR_RO(b_protocols);
 
-static ssize_t _show_protocol(struct device *dev,
-			      struct device_attribute *attr, char *buf)
+static ssize_t protocol_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
 {
 	struct mISDNdevice *mdev = dev_to_mISDN(dev);
 
@@ -86,17 +90,19 @@
 		return -ENODEV;
 	return sprintf(buf, "%d\n", mdev->D.protocol);
 }
+static DEVICE_ATTR_RO(protocol);
 
-static ssize_t _show_name(struct device *dev,
-			  struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev,
+			 struct device_attribute *attr, char *buf)
 {
 	strcpy(buf, dev_name(dev));
 	return strlen(buf);
 }
+static DEVICE_ATTR_RO(name);
 
 #if 0 /* hangs */
-static ssize_t _set_name(struct device *dev, struct device_attribute *attr,
-			 const char *buf, size_t count)
+static ssize_t name_set(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
 {
 	int err = 0;
 	char *out = kmalloc(count + 1, GFP_KERNEL);
@@ -113,10 +119,11 @@
 
 	return (err < 0) ? err : count;
 }
+static DEVICE_ATTR_RW(name);
 #endif
 
-static ssize_t _show_channelmap(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t channelmap_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct mISDNdevice *mdev = dev_to_mISDN(dev);
 	char *bp = buf;
@@ -127,18 +134,19 @@
 
 	return bp - buf;
 }
+static DEVICE_ATTR_RO(channelmap);
 
-static struct device_attribute mISDN_dev_attrs[] = {
-	__ATTR(id,          S_IRUGO,         _show_id,          NULL),
-	__ATTR(d_protocols, S_IRUGO,         _show_d_protocols, NULL),
-	__ATTR(b_protocols, S_IRUGO,         _show_b_protocols, NULL),
-	__ATTR(protocol,    S_IRUGO,         _show_protocol,    NULL),
-	__ATTR(channelmap,  S_IRUGO,         _show_channelmap,  NULL),
-	__ATTR(nrbchan,     S_IRUGO,         _show_nrbchan,     NULL),
-	__ATTR(name,        S_IRUGO,         _show_name,        NULL),
-/*	__ATTR(name,        S_IRUGO | S_IWUSR, _show_name,      _set_name), */
-	{}
+static struct attribute *mISDN_attrs[] = {
+	&dev_attr_id.attr,
+	&dev_attr_d_protocols.attr,
+	&dev_attr_b_protocols.attr,
+	&dev_attr_protocol.attr,
+	&dev_attr_channelmap.attr,
+	&dev_attr_nrbchan.attr,
+	&dev_attr_name.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(mISDN);
 
 static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -162,7 +170,7 @@
 	.name = "mISDN",
 	.owner = THIS_MODULE,
 	.dev_uevent = mISDN_uevent,
-	.dev_attrs = mISDN_dev_attrs,
+	.dev_groups = mISDN_groups,
 	.dev_release = mISDN_dev_release,
 	.class_release = mISDN_class_release,
 };
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 22b720e..77025f5 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -288,8 +288,10 @@
 	u8 *data;
 	int len;
 
-	if (skb->len < sizeof(int))
+	if (skb->len < sizeof(int)) {
 		printk(KERN_ERR "%s: PH_CONTROL message too short\n", __func__);
+		return -EINVAL;
+	}
 	cont = *((int *)skb->data);
 	len = skb->len - sizeof(int);
 	data = skb->data + sizeof(int);
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 4336e37..f37d63c 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -29,7 +29,7 @@
 		led_cdev->brightness = led_cdev->brightness_get(led_cdev);
 }
 
-static ssize_t led_brightness_show(struct device *dev,
+static ssize_t brightness_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -40,7 +40,7 @@
 	return sprintf(buf, "%u\n", led_cdev->brightness);
 }
 
-static ssize_t led_brightness_store(struct device *dev,
+static ssize_t brightness_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t size)
 {
 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -57,6 +57,7 @@
 
 	return size;
 }
+static DEVICE_ATTR_RW(brightness);
 
 static ssize_t led_max_brightness_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -65,14 +66,35 @@
 
 	return sprintf(buf, "%u\n", led_cdev->max_brightness);
 }
+static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL);
 
-static struct device_attribute led_class_attrs[] = {
-	__ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
-	__ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
 #ifdef CONFIG_LEDS_TRIGGERS
-	__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static struct attribute *led_trigger_attrs[] = {
+	&dev_attr_trigger.attr,
+	NULL,
+};
+static const struct attribute_group led_trigger_group = {
+	.attrs = led_trigger_attrs,
+};
 #endif
-	__ATTR_NULL,
+
+static struct attribute *led_class_attrs[] = {
+	&dev_attr_brightness.attr,
+	&dev_attr_max_brightness.attr,
+	NULL,
+};
+
+static const struct attribute_group led_group = {
+	.attrs = led_class_attrs,
+};
+
+static const struct attribute_group *led_groups[] = {
+	&led_group,
+#ifdef CONFIG_LEDS_TRIGGERS
+	&led_trigger_group,
+#endif
+	NULL,
 };
 
 static void led_timer_function(unsigned long data)
@@ -258,7 +280,7 @@
 	if (IS_ERR(leds_class))
 		return PTR_ERR(leds_class);
 	leds_class->pm = &leds_class_dev_pm_ops;
-	leds_class->dev_attrs = led_class_attrs;
+	leds_class->dev_groups = led_groups;
 	return 0;
 }
 
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index dc112a7..4296155 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -959,23 +959,21 @@
 	return r;
 }
 
-static void remove_mapping(struct mq_policy *mq, dm_oblock_t oblock)
+static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock)
 {
-	struct entry *e = hash_lookup(mq, oblock);
+	struct mq_policy *mq = to_mq_policy(p);
+	struct entry *e;
+
+	mutex_lock(&mq->lock);
+
+	e = hash_lookup(mq, oblock);
 
 	BUG_ON(!e || !e->in_cache);
 
 	del(mq, e);
 	e->in_cache = false;
 	push(mq, e);
-}
 
-static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock)
-{
-	struct mq_policy *mq = to_mq_policy(p);
-
-	mutex_lock(&mq->lock);
-	remove_mapping(mq, oblock);
 	mutex_unlock(&mq->lock);
 }
 
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 5adede1..b759a12 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1261,6 +1261,20 @@
 				pg_init_done, pgpath);
 }
 
+static int noretry_error(int error)
+{
+	switch (error) {
+	case -EOPNOTSUPP:
+	case -EREMOTEIO:
+	case -EILSEQ:
+	case -ENODATA:
+		return 1;
+	}
+
+	/* Anything else could be a path failure, so should be retried */
+	return 0;
+}
+
 /*
  * end_io handling
  */
@@ -1284,7 +1298,7 @@
 	if (!error && !clone->errors)
 		return 0;	/* I/O complete */
 
-	if (error == -EOPNOTSUPP || error == -EREMOTEIO || error == -EILSEQ)
+	if (noretry_error(error))
 		return error;
 
 	if (mpio->pgpath)
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index aa4cca3..744e43b 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -359,7 +359,7 @@
 	veu->m2m_ctx = v4l2_m2m_ctx_init(veu->m2m_dev, veu,
 					 sh_veu_queue_init);
 
-	return PTR_RET(veu->m2m_ctx);
+	return PTR_ERR_OR_ZERO(veu->m2m_ctx);
 }
 
 static int sh_veu_querycap(struct file *file, void *priv,
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index c8859d6..b0f49b0 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -38,24 +38,25 @@
  *	sysfs stuff
  */
 
-static ssize_t show_index(struct device *cd,
-			 struct device_attribute *attr, char *buf)
+static ssize_t index_show(struct device *cd,
+			  struct device_attribute *attr, char *buf)
 {
 	struct video_device *vdev = to_video_device(cd);
 
 	return sprintf(buf, "%i\n", vdev->index);
 }
+static DEVICE_ATTR_RO(index);
 
-static ssize_t show_debug(struct device *cd,
-			 struct device_attribute *attr, char *buf)
+static ssize_t debug_show(struct device *cd,
+			  struct device_attribute *attr, char *buf)
 {
 	struct video_device *vdev = to_video_device(cd);
 
 	return sprintf(buf, "%i\n", vdev->debug);
 }
 
-static ssize_t set_debug(struct device *cd, struct device_attribute *attr,
-		   const char *buf, size_t len)
+static ssize_t debug_store(struct device *cd, struct device_attribute *attr,
+			  const char *buf, size_t len)
 {
 	struct video_device *vdev = to_video_device(cd);
 	int res = 0;
@@ -68,21 +69,24 @@
 	vdev->debug = value;
 	return len;
 }
+static DEVICE_ATTR_RW(debug);
 
-static ssize_t show_name(struct device *cd,
+static ssize_t name_show(struct device *cd,
 			 struct device_attribute *attr, char *buf)
 {
 	struct video_device *vdev = to_video_device(cd);
 
 	return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
 }
+static DEVICE_ATTR_RO(name);
 
-static struct device_attribute video_device_attrs[] = {
-	__ATTR(name, S_IRUGO, show_name, NULL),
-	__ATTR(debug, 0644, show_debug, set_debug),
-	__ATTR(index, S_IRUGO, show_index, NULL),
-	__ATTR_NULL
+static struct attribute *video_device_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_debug.attr,
+	&dev_attr_index.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(video_device);
 
 /*
  *	Active devices
@@ -217,7 +221,7 @@
 
 static struct class video_class = {
 	.name = VIDEO_NAME,
-	.dev_attrs = video_device_attrs,
+	.dev_groups = video_device_groups,
 };
 
 struct video_device *video_devdata(struct file *file)
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 3c157fa..0d68eb1 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -3094,6 +3094,10 @@
 		.pdata_size = sizeof(db8500_cpufreq_table),
 	},
 	{
+		.name = "cpuidle-dbx500",
+		.of_compatible = "stericsson,cpuidle-dbx500",
+	},
+	{
 		.name = "db8500-thermal",
 		.num_resources = ARRAY_SIZE(db8500_thsens_resources),
 		.resources = db8500_thsens_resources,
diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c
index fc831dc..164b7fa 100644
--- a/drivers/mfd/rts5227.c
+++ b/drivers/mfd/rts5227.c
@@ -44,7 +44,7 @@
 	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
 	/* Configure LTR */
 	pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap);
-	if (cap & PCI_EXP_LTR_EN)
+	if (cap & PCI_EXP_DEVCTL2_LTR_EN)
 		rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
 	/* Configure OBFF */
 	rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index e068a76..5be80840 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 
 #include <linux/of.h>
-#include <linux/pinctrl/consumer.h>
 
 /* Serialize access to ssc_list and user count */
 static DEFINE_SPINLOCK(user_lock);
@@ -137,13 +136,6 @@
 	struct resource *regs;
 	struct ssc_device *ssc;
 	const struct atmel_ssc_platform_data *plat_dat;
-	struct pinctrl *pinctrl;
-
-	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		dev_err(&pdev->dev, "Failed to request pinctrl\n");
-		return PTR_ERR(pinctrl);
-	}
 
 	ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL);
 	if (!ssc) {
diff --git a/drivers/misc/c2port/core.c b/drivers/misc/c2port/core.c
index f32550a..464419b 100644
--- a/drivers/misc/c2port/core.c
+++ b/drivers/misc/c2port/core.c
@@ -311,6 +311,7 @@
 
 	return sprintf(buf, "%s\n", c2dev->name);
 }
+static DEVICE_ATTR(name, 0444, c2port_show_name, NULL);
 
 static ssize_t c2port_show_flash_blocks_num(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -320,6 +321,7 @@
 
 	return sprintf(buf, "%d\n", ops->blocks_num);
 }
+static DEVICE_ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL);
 
 static ssize_t c2port_show_flash_block_size(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -329,6 +331,7 @@
 
 	return sprintf(buf, "%d\n", ops->block_size);
 }
+static DEVICE_ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL);
 
 static ssize_t c2port_show_flash_size(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -338,18 +341,18 @@
 
 	return sprintf(buf, "%d\n", ops->blocks_num * ops->block_size);
 }
+static DEVICE_ATTR(flash_size, 0444, c2port_show_flash_size, NULL);
 
-static ssize_t c2port_show_access(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t access_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct c2port_device *c2dev = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%d\n", c2dev->access);
 }
 
-static ssize_t c2port_store_access(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf, size_t count)
+static ssize_t access_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct c2port_device *c2dev = dev_get_drvdata(dev);
 	struct c2port_ops *ops = c2dev->ops;
@@ -375,6 +378,7 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(access);
 
 static ssize_t c2port_store_reset(struct device *dev,
 				struct device_attribute *attr,
@@ -395,6 +399,7 @@
 
 	return count;
 }
+static DEVICE_ATTR(reset, 0200, NULL, c2port_store_reset);
 
 static ssize_t __c2port_show_dev_id(struct c2port_device *dev, char *buf)
 {
@@ -431,6 +436,7 @@
 
 	return ret;
 }
+static DEVICE_ATTR(dev_id, 0444, c2port_show_dev_id, NULL);
 
 static ssize_t __c2port_show_rev_id(struct c2port_device *dev, char *buf)
 {
@@ -467,6 +473,7 @@
 
 	return ret;
 }
+static DEVICE_ATTR(rev_id, 0444, c2port_show_rev_id, NULL);
 
 static ssize_t c2port_show_flash_access(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -536,6 +543,8 @@
 
 	return count;
 }
+static DEVICE_ATTR(flash_access, 0644, c2port_show_flash_access,
+		   c2port_store_flash_access);
 
 static ssize_t __c2port_write_flash_erase(struct c2port_device *dev)
 {
@@ -616,6 +625,7 @@
 
 	return count;
 }
+static DEVICE_ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase);
 
 static ssize_t __c2port_read_flash_data(struct c2port_device *dev,
 				char *buffer, loff_t offset, size_t count)
@@ -846,35 +856,40 @@
 
 	return ret;
 }
+/* size is computed at run-time */
+static BIN_ATTR(flash_data, 0644, c2port_read_flash_data,
+		c2port_write_flash_data, 0);
 
 /*
  * Class attributes
  */
-
-static struct device_attribute c2port_attrs[] = {
-	__ATTR(name, 0444, c2port_show_name, NULL),
-	__ATTR(flash_blocks_num, 0444, c2port_show_flash_blocks_num, NULL),
-	__ATTR(flash_block_size, 0444, c2port_show_flash_block_size, NULL),
-	__ATTR(flash_size, 0444, c2port_show_flash_size, NULL),
-	__ATTR(access, 0644, c2port_show_access, c2port_store_access),
-	__ATTR(reset, 0200, NULL, c2port_store_reset),
-	__ATTR(dev_id, 0444, c2port_show_dev_id, NULL),
-	__ATTR(rev_id, 0444, c2port_show_rev_id, NULL),
-
-	__ATTR(flash_access, 0644, c2port_show_flash_access,
-					c2port_store_flash_access),
-	__ATTR(flash_erase, 0200, NULL, c2port_store_flash_erase),
-	__ATTR_NULL,
+static struct attribute *c2port_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_flash_blocks_num.attr,
+	&dev_attr_flash_block_size.attr,
+	&dev_attr_flash_size.attr,
+	&dev_attr_access.attr,
+	&dev_attr_reset.attr,
+	&dev_attr_dev_id.attr,
+	&dev_attr_rev_id.attr,
+	&dev_attr_flash_access.attr,
+	&dev_attr_flash_erase.attr,
+	NULL,
 };
 
-static struct bin_attribute c2port_bin_attrs = {
-	.attr	= {
-		.name	= "flash_data",
-		.mode	= 0644
-	},
-	.read	= c2port_read_flash_data,
-	.write	= c2port_write_flash_data,
-	/* .size is computed at run-time */
+static struct bin_attribute *c2port_bin_attrs[] = {
+	&bin_attr_flash_data,
+	NULL,
+};
+
+static const struct attribute_group c2port_group = {
+	.attrs = c2port_attrs,
+	.bin_attrs = c2port_bin_attrs,
+};
+
+static const struct attribute_group *c2port_groups[] = {
+	&c2port_group,
+	NULL,
 };
 
 /*
@@ -907,6 +922,8 @@
 		goto error_idr_alloc;
 	c2dev->id = ret;
 
+	bin_attr_flash_data.size = ops->blocks_num * ops->block_size;
+
 	c2dev->dev = device_create(c2port_class, NULL, 0, c2dev,
 				   "c2port%d", c2dev->id);
 	if (unlikely(IS_ERR(c2dev->dev))) {
@@ -919,12 +936,6 @@
 	c2dev->ops = ops;
 	mutex_init(&c2dev->mutex);
 
-	/* Create binary file */
-	c2port_bin_attrs.size = ops->blocks_num * ops->block_size;
-	ret = device_create_bin_file(c2dev->dev, &c2port_bin_attrs);
-	if (unlikely(ret))
-		goto error_device_create_bin_file;
-
 	/* By default C2 port access is off */
 	c2dev->access = c2dev->flash_access = 0;
 	ops->access(c2dev, 0);
@@ -937,9 +948,6 @@
 
 	return c2dev;
 
-error_device_create_bin_file:
-	device_destroy(c2port_class, 0);
-
 error_device_create:
 	spin_lock_irq(&c2port_idr_lock);
 	idr_remove(&c2port_idr, c2dev->id);
@@ -959,7 +967,6 @@
 
 	dev_info(c2dev->dev, "C2 port %s removed\n", c2dev->name);
 
-	device_remove_bin_file(c2dev->dev, &c2port_bin_attrs);
 	spin_lock_irq(&c2port_idr_lock);
 	idr_remove(&c2port_idr, c2dev->id);
 	spin_unlock_irq(&c2port_idr_lock);
@@ -984,7 +991,7 @@
 		printk(KERN_ERR "c2port: failed to allocate class\n");
 		return PTR_ERR(c2port_class);
 	}
-	c2port_class->dev_attrs = c2port_attrs;
+	c2port_class->dev_groups = c2port_groups;
 
 	return 0;
 }
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 00e5fcac8..0e8df41 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -239,7 +239,7 @@
 	put_device(dev->parent);
 }
 
-static const struct attribute_group *enclosure_groups[];
+static const struct attribute_group *enclosure_component_groups[];
 
 /**
  * enclosure_component_register - add a particular component to an enclosure
@@ -282,7 +282,7 @@
 		dev_set_name(cdev, "%u", number);
 
 	cdev->release = enclosure_component_release;
-	cdev->groups = enclosure_groups;
+	cdev->groups = enclosure_component_groups;
 
 	err = device_register(cdev);
 	if (err) {
@@ -365,25 +365,26 @@
  * sysfs pieces below
  */
 
-static ssize_t enclosure_show_components(struct device *cdev,
-					 struct device_attribute *attr,
-					 char *buf)
+static ssize_t components_show(struct device *cdev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct enclosure_device *edev = to_enclosure_device(cdev);
 
 	return snprintf(buf, 40, "%d\n", edev->components);
 }
+static DEVICE_ATTR_RO(components);
 
-static struct device_attribute enclosure_attrs[] = {
-	__ATTR(components, S_IRUGO, enclosure_show_components, NULL),
-	__ATTR_NULL
+static struct attribute *enclosure_class_attrs[] = {
+	&dev_attr_components.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(enclosure_class);
 
 static struct class enclosure_class = {
 	.name			= "enclosure",
 	.owner			= THIS_MODULE,
 	.dev_release		= enclosure_release,
-	.dev_attrs		= enclosure_attrs,
+	.dev_groups		= enclosure_class_groups,
 };
 
 static const char *const enclosure_status [] = {
@@ -536,15 +537,7 @@
 	&dev_attr_type.attr,
 	NULL
 };
-
-static struct attribute_group enclosure_group = {
-	.attrs = enclosure_component_attrs,
-};
-
-static const struct attribute_group *enclosure_groups[] = {
-	&enclosure_group,
-	NULL
-};
+ATTRIBUTE_GROUPS(enclosure_component);
 
 static int __init enclosure_init(void)
 {
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index 621c7a3..b83e3ca 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -759,7 +759,7 @@
 
 	/* Ignore subsystem_device = 0x1979 (set by BIOS)  */
 	if (pdev->subsystem_device == 0x1979)
-		goto out;
+		return 0;
 
 	if (max_ccb > MAX_CCB)
 		max_ccb = MAX_CCB;
@@ -899,7 +899,7 @@
 	class_destroy(ilo_class);
 }
 
-MODULE_VERSION("1.4");
+MODULE_VERSION("1.4.1");
 MODULE_ALIAS(ILO_NAME);
 MODULE_DESCRIPTION(ILO_NAME);
 MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c
index 0029536..28f51e0 100644
--- a/drivers/misc/ics932s401.c
+++ b/drivers/misc/ics932s401.c
@@ -2,7 +2,7 @@
  * A driver for the Integrated Circuits ICS932S401
  * Copyright (C) 2008 IBM
  *
- * Author: Darrick J. Wong <djwong@us.ibm.com>
+ * Author: Darrick J. Wong <darrick.wong@oracle.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
@@ -482,7 +482,7 @@
 
 module_i2c_driver(ics932s401_driver);
 
-MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_AUTHOR("Darrick J. Wong <darrick.wong@oracle.com>");
 MODULE_DESCRIPTION("ICS932S401 driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 08aad69..2fc0586 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <scsi/scsi_cmnd.h>
 #include <linux/debugfs.h>
+#include <linux/vmalloc.h>
 
 #ifdef CONFIG_IDE
 #include <linux/ide.h>
@@ -50,6 +51,7 @@
 
 #define DEFAULT_COUNT 10
 #define REC_NUM_DEFAULT 10
+#define EXEC_SIZE 64
 
 enum cname {
 	CN_INVALID,
@@ -68,6 +70,7 @@
 	CT_NONE,
 	CT_PANIC,
 	CT_BUG,
+	CT_WARNING,
 	CT_EXCEPTION,
 	CT_LOOP,
 	CT_OVERFLOW,
@@ -77,7 +80,12 @@
 	CT_WRITE_AFTER_FREE,
 	CT_SOFTLOCKUP,
 	CT_HARDLOCKUP,
+	CT_SPINLOCKUP,
 	CT_HUNG_TASK,
+	CT_EXEC_DATA,
+	CT_EXEC_STACK,
+	CT_EXEC_KMALLOC,
+	CT_EXEC_VMALLOC,
 };
 
 static char* cp_name[] = {
@@ -95,6 +103,7 @@
 static char* cp_type[] = {
 	"PANIC",
 	"BUG",
+	"WARNING",
 	"EXCEPTION",
 	"LOOP",
 	"OVERFLOW",
@@ -104,7 +113,12 @@
 	"WRITE_AFTER_FREE",
 	"SOFTLOCKUP",
 	"HARDLOCKUP",
+	"SPINLOCKUP",
 	"HUNG_TASK",
+	"EXEC_DATA",
+	"EXEC_STACK",
+	"EXEC_KMALLOC",
+	"EXEC_VMALLOC",
 };
 
 static struct jprobe lkdtm;
@@ -121,6 +135,9 @@
 static enum ctype cptype = CT_NONE;
 static int count = DEFAULT_COUNT;
 static DEFINE_SPINLOCK(count_lock);
+static DEFINE_SPINLOCK(lock_me_up);
+
+static u8 data_area[EXEC_SIZE];
 
 module_param(recur_count, int, 0644);
 MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
@@ -275,6 +292,19 @@
         	return recursive_loop(a);
 }
 
+static void do_nothing(void)
+{
+	return;
+}
+
+static void execute_location(void *dst)
+{
+	void (*func)(void) = dst;
+
+	memcpy(dst, do_nothing, EXEC_SIZE);
+	func();
+}
+
 static void lkdtm_do_action(enum ctype which)
 {
 	switch (which) {
@@ -284,6 +314,9 @@
 	case CT_BUG:
 		BUG();
 		break;
+	case CT_WARNING:
+		WARN_ON(1);
+		break;
 	case CT_EXCEPTION:
 		*((int *) 0) = 0;
 		break;
@@ -295,10 +328,10 @@
 		(void) recursive_loop(0);
 		break;
 	case CT_CORRUPT_STACK: {
-		volatile u32 data[8];
-		volatile u32 *p = data;
+		/* Make sure the compiler creates and uses an 8 char array. */
+		volatile char data[8];
 
-		p[12] = 0x12345678;
+		memset((void *)data, 0, 64);
 		break;
 	}
 	case CT_UNALIGNED_LOAD_STORE_WRITE: {
@@ -340,10 +373,34 @@
 		for (;;)
 			cpu_relax();
 		break;
+	case CT_SPINLOCKUP:
+		/* Must be called twice to trigger. */
+		spin_lock(&lock_me_up);
+		break;
 	case CT_HUNG_TASK:
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule();
 		break;
+	case CT_EXEC_DATA:
+		execute_location(data_area);
+		break;
+	case CT_EXEC_STACK: {
+		u8 stack_area[EXEC_SIZE];
+		execute_location(stack_area);
+		break;
+	}
+	case CT_EXEC_KMALLOC: {
+		u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL);
+		execute_location(kmalloc_area);
+		kfree(kmalloc_area);
+		break;
+	}
+	case CT_EXEC_VMALLOC: {
+		u32 *vmalloc_area = vmalloc(EXEC_SIZE);
+		execute_location(vmalloc_area);
+		vfree(vmalloc_area);
+		break;
+	}
 	case CT_NONE:
 	default:
 		break;
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 749452f..d0fdc13 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -418,15 +418,23 @@
 		struct file *file, poll_table *wait)
 {
 	unsigned int mask = 0;
-	mutex_unlock(&dev->device_lock);
+
 	poll_wait(file, &dev->iamthif_cl.wait, wait);
+
 	mutex_lock(&dev->device_lock);
-	if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
-		dev->iamthif_file_object == file) {
+	if (!mei_cl_is_connected(&dev->iamthif_cl)) {
+
+		mask = POLLERR;
+
+	} else if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
+		   dev->iamthif_file_object == file) {
+
 		mask |= (POLLIN | POLLRDNORM);
 		dev_dbg(&dev->pdev->dev, "run next amthif cb\n");
 		mei_amthif_run_next_cmd(dev);
 	}
+	mutex_unlock(&dev->device_lock);
+
 	return mask;
 }
 
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 9ecd49a..6d0282c 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -47,7 +47,7 @@
 	id = driver->id_table;
 
 	while (id->name[0]) {
-		if (!strcmp(dev_name(dev), id->name))
+		if (!strncmp(dev_name(dev), id->name, sizeof(id->name)))
 			return 1;
 
 		id++;
@@ -71,7 +71,7 @@
 
 	dev_dbg(dev, "Device probe\n");
 
-	strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
+	strncpy(id.name, dev_name(dev), sizeof(id.name));
 
 	return driver->probe(device, &id);
 }
@@ -108,11 +108,13 @@
 
 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
+static DEVICE_ATTR_RO(modalias);
 
-static struct device_attribute mei_cl_dev_attrs[] = {
-	__ATTR_RO(modalias),
-	__ATTR_NULL,
+static struct attribute *mei_cl_dev_attrs[] = {
+	&dev_attr_modalias.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(mei_cl_dev);
 
 static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -124,7 +126,7 @@
 
 static struct bus_type mei_cl_bus_type = {
 	.name		= "mei",
-	.dev_attrs	= mei_cl_dev_attrs,
+	.dev_groups	= mei_cl_dev_groups,
 	.match		= mei_cl_device_match,
 	.probe		= mei_cl_device_probe,
 	.remove		= mei_cl_device_remove,
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 21d3f5a..e0684b4 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -635,10 +635,7 @@
 
 	dev = cl->dev;
 
-	if (cl->state != MEI_FILE_CONNECTED)
-		return -ENODEV;
-
-	if (dev->dev_state != MEI_DEV_ENABLED)
+	if (!mei_cl_is_connected(cl))
 		return -ENODEV;
 
 	if (cl->read_cb) {
@@ -892,18 +889,22 @@
 
 
 /**
- * mei_cl_all_read_wakeup  - wake up all readings so they can be interrupted
+ * mei_cl_all_wakeup  - wake up all readers and writers they can be interrupted
  *
  * @dev  - mei device
  */
-void mei_cl_all_read_wakeup(struct mei_device *dev)
+void mei_cl_all_wakeup(struct mei_device *dev)
 {
 	struct mei_cl *cl, *next;
 	list_for_each_entry_safe(cl, next, &dev->file_list, link) {
 		if (waitqueue_active(&cl->rx_wait)) {
-			dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+			dev_dbg(&dev->pdev->dev, "Waking up reading client!\n");
 			wake_up_interruptible(&cl->rx_wait);
 		}
+		if (waitqueue_active(&cl->tx_wait)) {
+			dev_dbg(&dev->pdev->dev, "Waking up writing client!\n");
+			wake_up_interruptible(&cl->tx_wait);
+		}
 	}
 }
 
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 26b157d..9eb031e 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -84,6 +84,13 @@
 /*
  *  MEI input output function prototype
  */
+static inline bool mei_cl_is_connected(struct mei_cl *cl)
+{
+	return (cl->dev &&
+		cl->dev->dev_state == MEI_DEV_ENABLED &&
+		cl->state == MEI_FILE_CONNECTED);
+}
+
 bool mei_cl_is_other_connecting(struct mei_cl *cl);
 int mei_cl_disconnect(struct mei_cl *cl);
 int mei_cl_connect(struct mei_cl *cl, struct file *file);
@@ -99,7 +106,7 @@
 
 
 void mei_cl_all_disconnect(struct mei_device *dev);
-void mei_cl_all_read_wakeup(struct mei_device *dev);
+void mei_cl_all_wakeup(struct mei_device *dev);
 void mei_cl_all_write_clear(struct mei_device *dev);
 
 #endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index b22c7e2..3412adc 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -176,21 +176,18 @@
 	struct mei_me_hw *hw = to_me_hw(dev);
 	u32 hcsr = mei_hcsr_read(hw);
 
-	dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr);
-
-	hcsr |= (H_RST | H_IG);
+	hcsr |= H_RST | H_IG | H_IS;
 
 	if (intr_enable)
 		hcsr |= H_IE;
 	else
-		hcsr |= ~H_IE;
+		hcsr &= ~H_IE;
 
-	mei_hcsr_set(hw, hcsr);
+	mei_me_reg_write(hw, H_CSR, hcsr);
 
 	if (dev->dev_state == MEI_DEV_POWER_DOWN)
 		mei_me_hw_reset_release(dev);
 
-	dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw));
 	return 0;
 }
 
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index e6f16f8..92c7311 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -154,8 +154,14 @@
 		    dev->dev_state != MEI_DEV_POWER_DOWN)
 			dev->dev_state = MEI_DEV_RESETTING;
 
+		/* remove all waiting requests */
+		mei_cl_all_write_clear(dev);
+
 		mei_cl_all_disconnect(dev);
 
+		/* wake up all readings so they can be interrupted */
+		mei_cl_all_wakeup(dev);
+
 		/* remove entry if already in list */
 		dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
 		mei_cl_unlink(&dev->wd_cl);
@@ -196,11 +202,6 @@
 
 	mei_hbm_start_req(dev);
 
-	/* wake up all readings so they can be interrupted */
-	mei_cl_all_read_wakeup(dev);
-
-	/* remove all waiting requests */
-	mei_cl_all_write_clear(dev);
 }
 EXPORT_SYMBOL_GPL(mei_reset);
 
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 5e11b5b..173ff09 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -625,24 +625,32 @@
 	unsigned int mask = 0;
 
 	if (WARN_ON(!cl || !cl->dev))
-		return mask;
+		return POLLERR;
 
 	dev = cl->dev;
 
 	mutex_lock(&dev->device_lock);
 
-	if (dev->dev_state != MEI_DEV_ENABLED)
-		goto out;
-
-
-	if (cl == &dev->iamthif_cl) {
-		mask = mei_amthif_poll(dev, file, wait);
+	if (!mei_cl_is_connected(cl)) {
+		mask = POLLERR;
 		goto out;
 	}
 
 	mutex_unlock(&dev->device_lock);
+
+
+	if (cl == &dev->iamthif_cl)
+		return mei_amthif_poll(dev, file, wait);
+
 	poll_wait(file, &cl->tx_wait, wait);
+
 	mutex_lock(&dev->device_lock);
+
+	if (!mei_cl_is_connected(cl)) {
+		mask = POLLERR;
+		goto out;
+	}
+
 	if (MEI_WRITE_COMPLETE == cl->writing_state)
 		mask |= (POLLIN | POLLRDNORM);
 
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index d87cc91..afe66571 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -68,7 +68,8 @@
 	ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
 				res->start, size, -1);
 	if (ret < 0) {
-		gen_pool_destroy(sram->pool);
+		if (sram->clk)
+			clk_disable_unprepare(sram->clk);
 		return ret;
 	}
 
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 0a14280..8d64b68 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -562,7 +562,9 @@
 			if ((st_gdata->protos_registered != ST_EMPTY) &&
 			    (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
 				pr_err(" KIM failure complete callback ");
+				spin_lock_irqsave(&st_gdata->lock, flags);
 				st_reg_complete(st_gdata, err);
+				spin_unlock_irqrestore(&st_gdata->lock, flags);
 				clear_bit(ST_REG_PENDING, &st_gdata->st_state);
 			}
 			return -EINVAL;
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c
index cb56e27..2421835 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -133,7 +133,7 @@
 #define VMWARE_BALLOON_CMD(cmd, data, result)		\
 ({							\
 	unsigned long __stat, __dummy1, __dummy2;	\
-	__asm__ __volatile__ ("inl (%%dx)" :		\
+	__asm__ __volatile__ ("inl %%dx" :		\
 		"=a"(__stat),				\
 		"=c"(__dummy1),				\
 		"=d"(__dummy2),				\
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index 7b3fce2..3dee7ae 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@
 
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.0.0.0-k");
+MODULE_VERSION("1.1.0.0-k");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_driver.h b/drivers/misc/vmw_vmci/vmci_driver.h
index f69156a..cee9e97 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.h
+++ b/drivers/misc/vmw_vmci/vmci_driver.h
@@ -35,6 +35,13 @@
 	enum vmci_obj_type type;
 };
 
+/*
+ * Needed by other components of this module.  It's okay to have one global
+ * instance of this because there can only ever be one VMCI device.  Our
+ * virtual hardware enforces this.
+ */
+extern struct pci_dev *vmci_pdev;
+
 u32 vmci_get_context_id(void);
 int vmci_send_datagram(struct vmci_datagram *dg);
 
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c
index 60c0199..b3a2b76 100644
--- a/drivers/misc/vmw_vmci/vmci_guest.c
+++ b/drivers/misc/vmw_vmci/vmci_guest.c
@@ -65,9 +65,11 @@
 
 	void *data_buffer;
 	void *notification_bitmap;
+	dma_addr_t notification_base;
 };
 
 /* vmci_dev singleton device and supporting data*/
+struct pci_dev *vmci_pdev;
 static struct vmci_guest_device *vmci_dev_g;
 static DEFINE_SPINLOCK(vmci_dev_spinlock);
 
@@ -528,7 +530,9 @@
 	 * well.
 	 */
 	if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
-		vmci_dev->notification_bitmap = vmalloc(PAGE_SIZE);
+		vmci_dev->notification_bitmap = dma_alloc_coherent(
+			&pdev->dev, PAGE_SIZE, &vmci_dev->notification_base,
+			GFP_KERNEL);
 		if (!vmci_dev->notification_bitmap) {
 			dev_warn(&pdev->dev,
 				 "Unable to allocate notification bitmap\n");
@@ -546,6 +550,7 @@
 	/* Set up global device so that we can start sending datagrams */
 	spin_lock_irq(&vmci_dev_spinlock);
 	vmci_dev_g = vmci_dev;
+	vmci_pdev = pdev;
 	spin_unlock_irq(&vmci_dev_spinlock);
 
 	/*
@@ -553,9 +558,8 @@
 	 * used.
 	 */
 	if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
-		struct page *page =
-			vmalloc_to_page(vmci_dev->notification_bitmap);
-		unsigned long bitmap_ppn = page_to_pfn(page);
+		unsigned long bitmap_ppn =
+			vmci_dev->notification_base >> PAGE_SHIFT;
 		if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) {
 			dev_warn(&pdev->dev,
 				 "VMCI device unable to register notification bitmap with PPN 0x%x\n",
@@ -665,11 +669,14 @@
 	if (vmci_dev->notification_bitmap) {
 		iowrite32(VMCI_CONTROL_RESET,
 			  vmci_dev->iobase + VMCI_CONTROL_ADDR);
-		vfree(vmci_dev->notification_bitmap);
+		dma_free_coherent(&pdev->dev, PAGE_SIZE,
+				  vmci_dev->notification_bitmap,
+				  vmci_dev->notification_base);
 	}
 
 err_remove_vmci_dev_g:
 	spin_lock_irq(&vmci_dev_spinlock);
+	vmci_pdev = NULL;
 	vmci_dev_g = NULL;
 	spin_unlock_irq(&vmci_dev_spinlock);
 
@@ -699,6 +706,7 @@
 
 	spin_lock_irq(&vmci_dev_spinlock);
 	vmci_dev_g = NULL;
+	vmci_pdev = NULL;
 	spin_unlock_irq(&vmci_dev_spinlock);
 
 	dev_dbg(&pdev->dev, "Resetting vmci device\n");
@@ -727,7 +735,9 @@
 		 * device, so we can safely free it here.
 		 */
 
-		vfree(vmci_dev->notification_bitmap);
+		dma_free_coherent(&pdev->dev, PAGE_SIZE,
+				  vmci_dev->notification_bitmap,
+				  vmci_dev->notification_base);
 	}
 
 	vfree(vmci_dev->data_buffer);
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 8ff2e5e..a0515a6 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/pagemap.h>
+#include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/uio.h>
@@ -146,14 +147,20 @@
 
 /* The Kernel specific component of the struct vmci_queue structure. */
 struct vmci_queue_kern_if {
-	struct page **page;
-	struct page **header_page;
-	void *va;
 	struct mutex __mutex;	/* Protects the queue. */
 	struct mutex *mutex;	/* Shared by producer and consumer queues. */
-	bool host;
-	size_t num_pages;
-	bool mapped;
+	size_t num_pages;	/* Number of pages incl. header. */
+	bool host;		/* Host or guest? */
+	union {
+		struct {
+			dma_addr_t *pas;
+			void **vas;
+		} g;		/* Used by the guest. */
+		struct {
+			struct page **page;
+			struct page **header_page;
+		} h;		/* Used by the host. */
+	} u;
 };
 
 /*
@@ -265,76 +272,65 @@
 	struct vmci_queue *queue = q;
 
 	if (queue) {
-		u64 i = DIV_ROUND_UP(size, PAGE_SIZE);
+		u64 i;
 
-		if (queue->kernel_if->mapped) {
-			vunmap(queue->kernel_if->va);
-			queue->kernel_if->va = NULL;
+		/* Given size does not include header, so add in a page here. */
+		for (i = 0; i < DIV_ROUND_UP(size, PAGE_SIZE) + 1; i++) {
+			dma_free_coherent(&vmci_pdev->dev, PAGE_SIZE,
+					  queue->kernel_if->u.g.vas[i],
+					  queue->kernel_if->u.g.pas[i]);
 		}
 
-		while (i)
-			__free_page(queue->kernel_if->page[--i]);
-
-		vfree(queue->q_header);
+		vfree(queue);
 	}
 }
 
 /*
- * Allocates kernel VA space of specified size, plus space for the
- * queue structure/kernel interface and the queue header.  Allocates
- * physical pages for the queue data pages.
- *
- * PAGE m:      struct vmci_queue_header (struct vmci_queue->q_header)
- * PAGE m+1:    struct vmci_queue
- * PAGE m+1+q:  struct vmci_queue_kern_if (struct vmci_queue->kernel_if)
- * PAGE n-size: Data pages (struct vmci_queue->kernel_if->page[])
+ * Allocates kernel queue pages of specified size with IOMMU mappings,
+ * plus space for the queue structure/kernel interface and the queue
+ * header.
  */
 static void *qp_alloc_queue(u64 size, u32 flags)
 {
 	u64 i;
 	struct vmci_queue *queue;
-	struct vmci_queue_header *q_header;
-	const u64 num_data_pages = DIV_ROUND_UP(size, PAGE_SIZE);
-	const uint queue_size =
-	    PAGE_SIZE +
-	    sizeof(*queue) + sizeof(*(queue->kernel_if)) +
-	    num_data_pages * sizeof(*(queue->kernel_if->page));
+	const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+	const size_t pas_size = num_pages * sizeof(*queue->kernel_if->u.g.pas);
+	const size_t vas_size = num_pages * sizeof(*queue->kernel_if->u.g.vas);
+	const size_t queue_size =
+		sizeof(*queue) + sizeof(*queue->kernel_if) +
+		pas_size + vas_size;
 
-	q_header = vmalloc(queue_size);
-	if (!q_header)
+	queue = vmalloc(queue_size);
+	if (!queue)
 		return NULL;
 
-	queue = (void *)q_header + PAGE_SIZE;
-	queue->q_header = q_header;
+	queue->q_header = NULL;
 	queue->saved_header = NULL;
 	queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
-	queue->kernel_if->header_page = NULL;	/* Unused in guest. */
-	queue->kernel_if->page = (struct page **)(queue->kernel_if + 1);
+	queue->kernel_if->mutex = NULL;
+	queue->kernel_if->num_pages = num_pages;
+	queue->kernel_if->u.g.pas = (dma_addr_t *)(queue->kernel_if + 1);
+	queue->kernel_if->u.g.vas =
+		(void **)((u8 *)queue->kernel_if->u.g.pas + pas_size);
 	queue->kernel_if->host = false;
-	queue->kernel_if->va = NULL;
-	queue->kernel_if->mapped = false;
 
-	for (i = 0; i < num_data_pages; i++) {
-		queue->kernel_if->page[i] = alloc_pages(GFP_KERNEL, 0);
-		if (!queue->kernel_if->page[i])
-			goto fail;
+	for (i = 0; i < num_pages; i++) {
+		queue->kernel_if->u.g.vas[i] =
+			dma_alloc_coherent(&vmci_pdev->dev, PAGE_SIZE,
+					   &queue->kernel_if->u.g.pas[i],
+					   GFP_KERNEL);
+		if (!queue->kernel_if->u.g.vas[i]) {
+			/* Size excl. the header. */
+			qp_free_queue(queue, i * PAGE_SIZE);
+			return NULL;
+		}
 	}
 
-	if (vmci_qp_pinned(flags)) {
-		queue->kernel_if->va =
-		    vmap(queue->kernel_if->page, num_data_pages, VM_MAP,
-			 PAGE_KERNEL);
-		if (!queue->kernel_if->va)
-			goto fail;
+	/* Queue header is the first page. */
+	queue->q_header = queue->kernel_if->u.g.vas[0];
 
-		queue->kernel_if->mapped = true;
-	}
-
-	return (void *)queue;
-
- fail:
-	qp_free_queue(queue, i * PAGE_SIZE);
-	return NULL;
+	return queue;
 }
 
 /*
@@ -353,17 +349,18 @@
 	size_t bytes_copied = 0;
 
 	while (bytes_copied < size) {
-		u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
-		size_t page_offset =
+		const u64 page_index =
+			(queue_offset + bytes_copied) / PAGE_SIZE;
+		const size_t page_offset =
 		    (queue_offset + bytes_copied) & (PAGE_SIZE - 1);
 		void *va;
 		size_t to_copy;
 
-		if (!kernel_if->mapped)
-			va = kmap(kernel_if->page[page_index]);
+		if (kernel_if->host)
+			va = kmap(kernel_if->u.h.page[page_index]);
 		else
-			va = (void *)((u8 *)kernel_if->va +
-				      (page_index * PAGE_SIZE));
+			va = kernel_if->u.g.vas[page_index + 1];
+			/* Skip header. */
 
 		if (size - bytes_copied > PAGE_SIZE - page_offset)
 			/* Enough payload to fill up from this page. */
@@ -379,7 +376,8 @@
 			err = memcpy_fromiovec((u8 *)va + page_offset,
 					       iov, to_copy);
 			if (err != 0) {
-				kunmap(kernel_if->page[page_index]);
+				if (kernel_if->host)
+					kunmap(kernel_if->u.h.page[page_index]);
 				return VMCI_ERROR_INVALID_ARGS;
 			}
 		} else {
@@ -388,8 +386,8 @@
 		}
 
 		bytes_copied += to_copy;
-		if (!kernel_if->mapped)
-			kunmap(kernel_if->page[page_index]);
+		if (kernel_if->host)
+			kunmap(kernel_if->u.h.page[page_index]);
 	}
 
 	return VMCI_SUCCESS;
@@ -411,17 +409,18 @@
 	size_t bytes_copied = 0;
 
 	while (bytes_copied < size) {
-		u64 page_index = (queue_offset + bytes_copied) / PAGE_SIZE;
-		size_t page_offset =
+		const u64 page_index =
+			(queue_offset + bytes_copied) / PAGE_SIZE;
+		const size_t page_offset =
 		    (queue_offset + bytes_copied) & (PAGE_SIZE - 1);
 		void *va;
 		size_t to_copy;
 
-		if (!kernel_if->mapped)
-			va = kmap(kernel_if->page[page_index]);
+		if (kernel_if->host)
+			va = kmap(kernel_if->u.h.page[page_index]);
 		else
-			va = (void *)((u8 *)kernel_if->va +
-				      (page_index * PAGE_SIZE));
+			va = kernel_if->u.g.vas[page_index + 1];
+			/* Skip header. */
 
 		if (size - bytes_copied > PAGE_SIZE - page_offset)
 			/* Enough payload to fill up this page. */
@@ -437,7 +436,8 @@
 			err = memcpy_toiovec(iov, (u8 *)va + page_offset,
 					     to_copy);
 			if (err != 0) {
-				kunmap(kernel_if->page[page_index]);
+				if (kernel_if->host)
+					kunmap(kernel_if->u.h.page[page_index]);
 				return VMCI_ERROR_INVALID_ARGS;
 			}
 		} else {
@@ -446,8 +446,8 @@
 		}
 
 		bytes_copied += to_copy;
-		if (!kernel_if->mapped)
-			kunmap(kernel_if->page[page_index]);
+		if (kernel_if->host)
+			kunmap(kernel_if->u.h.page[page_index]);
 	}
 
 	return VMCI_SUCCESS;
@@ -489,12 +489,11 @@
 		return VMCI_ERROR_NO_MEM;
 	}
 
-	produce_ppns[0] = page_to_pfn(vmalloc_to_page(produce_q->q_header));
-	for (i = 1; i < num_produce_pages; i++) {
+	for (i = 0; i < num_produce_pages; i++) {
 		unsigned long pfn;
 
 		produce_ppns[i] =
-		    page_to_pfn(produce_q->kernel_if->page[i - 1]);
+			produce_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
 		pfn = produce_ppns[i];
 
 		/* Fail allocation if PFN isn't supported by hypervisor. */
@@ -503,12 +502,11 @@
 			goto ppn_error;
 	}
 
-	consume_ppns[0] = page_to_pfn(vmalloc_to_page(consume_q->q_header));
-	for (i = 1; i < num_consume_pages; i++) {
+	for (i = 0; i < num_consume_pages; i++) {
 		unsigned long pfn;
 
 		consume_ppns[i] =
-		    page_to_pfn(consume_q->kernel_if->page[i - 1]);
+			consume_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
 		pfn = consume_ppns[i];
 
 		/* Fail allocation if PFN isn't supported by hypervisor. */
@@ -619,23 +617,20 @@
 	const size_t num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
 	const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
 	const size_t queue_page_size =
-	    num_pages * sizeof(*queue->kernel_if->page);
+	    num_pages * sizeof(*queue->kernel_if->u.h.page);
 
 	queue = kzalloc(queue_size + queue_page_size, GFP_KERNEL);
 	if (queue) {
 		queue->q_header = NULL;
 		queue->saved_header = NULL;
-		queue->kernel_if =
-		    (struct vmci_queue_kern_if *)((u8 *)queue +
-						  sizeof(*queue));
+		queue->kernel_if = (struct vmci_queue_kern_if *)(queue + 1);
 		queue->kernel_if->host = true;
 		queue->kernel_if->mutex = NULL;
 		queue->kernel_if->num_pages = num_pages;
-		queue->kernel_if->header_page =
+		queue->kernel_if->u.h.header_page =
 		    (struct page **)((u8 *)queue + queue_size);
-		queue->kernel_if->page = &queue->kernel_if->header_page[1];
-		queue->kernel_if->va = NULL;
-		queue->kernel_if->mapped = false;
+		queue->kernel_if->u.h.page =
+			&queue->kernel_if->u.h.header_page[1];
 	}
 
 	return queue;
@@ -742,11 +737,12 @@
 				current->mm,
 				(uintptr_t) produce_uva,
 				produce_q->kernel_if->num_pages,
-				1, 0, produce_q->kernel_if->header_page, NULL);
+				1, 0,
+				produce_q->kernel_if->u.h.header_page, NULL);
 	if (retval < produce_q->kernel_if->num_pages) {
 		pr_warn("get_user_pages(produce) failed (retval=%d)", retval);
-		qp_release_pages(produce_q->kernel_if->header_page, retval,
-				 false);
+		qp_release_pages(produce_q->kernel_if->u.h.header_page,
+				 retval, false);
 		err = VMCI_ERROR_NO_MEM;
 		goto out;
 	}
@@ -755,12 +751,13 @@
 				current->mm,
 				(uintptr_t) consume_uva,
 				consume_q->kernel_if->num_pages,
-				1, 0, consume_q->kernel_if->header_page, NULL);
+				1, 0,
+				consume_q->kernel_if->u.h.header_page, NULL);
 	if (retval < consume_q->kernel_if->num_pages) {
 		pr_warn("get_user_pages(consume) failed (retval=%d)", retval);
-		qp_release_pages(consume_q->kernel_if->header_page, retval,
-				 false);
-		qp_release_pages(produce_q->kernel_if->header_page,
+		qp_release_pages(consume_q->kernel_if->u.h.header_page,
+				 retval, false);
+		qp_release_pages(produce_q->kernel_if->u.h.header_page,
 				 produce_q->kernel_if->num_pages, false);
 		err = VMCI_ERROR_NO_MEM;
 	}
@@ -803,15 +800,15 @@
 static void qp_host_unregister_user_memory(struct vmci_queue *produce_q,
 					   struct vmci_queue *consume_q)
 {
-	qp_release_pages(produce_q->kernel_if->header_page,
+	qp_release_pages(produce_q->kernel_if->u.h.header_page,
 			 produce_q->kernel_if->num_pages, true);
-	memset(produce_q->kernel_if->header_page, 0,
-	       sizeof(*produce_q->kernel_if->header_page) *
+	memset(produce_q->kernel_if->u.h.header_page, 0,
+	       sizeof(*produce_q->kernel_if->u.h.header_page) *
 	       produce_q->kernel_if->num_pages);
-	qp_release_pages(consume_q->kernel_if->header_page,
+	qp_release_pages(consume_q->kernel_if->u.h.header_page,
 			 consume_q->kernel_if->num_pages, true);
-	memset(consume_q->kernel_if->header_page, 0,
-	       sizeof(*consume_q->kernel_if->header_page) *
+	memset(consume_q->kernel_if->u.h.header_page, 0,
+	       sizeof(*consume_q->kernel_if->u.h.header_page) *
 	       consume_q->kernel_if->num_pages);
 }
 
@@ -834,12 +831,12 @@
 		if (produce_q->q_header != consume_q->q_header)
 			return VMCI_ERROR_QUEUEPAIR_MISMATCH;
 
-		if (produce_q->kernel_if->header_page == NULL ||
-		    *produce_q->kernel_if->header_page == NULL)
+		if (produce_q->kernel_if->u.h.header_page == NULL ||
+		    *produce_q->kernel_if->u.h.header_page == NULL)
 			return VMCI_ERROR_UNAVAILABLE;
 
-		headers[0] = *produce_q->kernel_if->header_page;
-		headers[1] = *consume_q->kernel_if->header_page;
+		headers[0] = *produce_q->kernel_if->u.h.header_page;
+		headers[1] = *consume_q->kernel_if->u.h.header_page;
 
 		produce_q->q_header = vmap(headers, 2, VM_MAP, PAGE_KERNEL);
 		if (produce_q->q_header != NULL) {
@@ -1720,21 +1717,6 @@
 			if (result < VMCI_SUCCESS)
 				return result;
 
-			/*
-			 * Preemptively load in the headers if non-blocking to
-			 * prevent blocking later.
-			 */
-			if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
-				result = qp_host_map_queues(entry->produce_q,
-							    entry->consume_q);
-				if (result < VMCI_SUCCESS) {
-					qp_host_unregister_user_memory(
-						entry->produce_q,
-						entry->consume_q);
-					return result;
-				}
-			}
-
 			entry->state = VMCIQPB_ATTACHED_MEM;
 		} else {
 			entry->state = VMCIQPB_ATTACHED_NO_MEM;
@@ -1749,24 +1731,6 @@
 
 		return VMCI_ERROR_UNAVAILABLE;
 	} else {
-		/*
-		 * For non-blocking queue pairs, we cannot rely on
-		 * enqueue/dequeue to map in the pages on the
-		 * host-side, since it may block, so we make an
-		 * attempt here.
-		 */
-
-		if (flags & VMCI_QPFLAG_NONBLOCK) {
-			result =
-			    qp_host_map_queues(entry->produce_q,
-					       entry->consume_q);
-			if (result < VMCI_SUCCESS)
-				return result;
-
-			entry->qp.flags |= flags &
-			    (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
-		}
-
 		/* The host side has successfully attached to a queue pair. */
 		entry->state = VMCIQPB_ATTACHED_MEM;
 	}
@@ -2543,24 +2507,19 @@
  * Since non-blocking isn't yet implemented on the host personality we
  * have no reason to acquire a spin lock.  So to avoid the use of an
  * unnecessary lock only acquire the mutex if we can block.
- * Note: It is assumed that QPFLAG_PINNED implies QPFLAG_NONBLOCK.  Therefore
- * we can use the same locking function for access to both the queue
- * and the queue headers as it is the same logic.  Assert this behvior.
  */
 static void qp_lock(const struct vmci_qp *qpair)
 {
-	if (vmci_can_block(qpair->flags))
-		qp_acquire_queue_mutex(qpair->produce_q);
+	qp_acquire_queue_mutex(qpair->produce_q);
 }
 
 /*
  * Helper routine that unlocks the queue pair after calling
- * qp_lock.  Respects non-blocking and pinning flags.
+ * qp_lock.
  */
 static void qp_unlock(const struct vmci_qp *qpair)
 {
-	if (vmci_can_block(qpair->flags))
-		qp_release_queue_mutex(qpair->produce_q);
+	qp_release_queue_mutex(qpair->produce_q);
 }
 
 /*
@@ -2568,17 +2527,12 @@
  * currently not mapped, it will be attempted to do so.
  */
 static int qp_map_queue_headers(struct vmci_queue *produce_q,
-				struct vmci_queue *consume_q,
-				bool can_block)
+				struct vmci_queue *consume_q)
 {
 	int result;
 
 	if (NULL == produce_q->q_header || NULL == consume_q->q_header) {
-		if (can_block)
-			result = qp_host_map_queues(produce_q, consume_q);
-		else
-			result = VMCI_ERROR_QUEUEPAIR_NOT_READY;
-
+		result = qp_host_map_queues(produce_q, consume_q);
 		if (result < VMCI_SUCCESS)
 			return (produce_q->saved_header &&
 				consume_q->saved_header) ?
@@ -2601,8 +2555,7 @@
 {
 	int result;
 
-	result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q,
-				      vmci_can_block(qpair->flags));
+	result = qp_map_queue_headers(qpair->produce_q, qpair->consume_q);
 	if (result == VMCI_SUCCESS) {
 		*produce_q_header = qpair->produce_q->q_header;
 		*consume_q_header = qpair->consume_q->q_header;
@@ -2645,9 +2598,6 @@
 {
 	unsigned int generation;
 
-	if (qpair->flags & VMCI_QPFLAG_NONBLOCK)
-		return false;
-
 	qpair->blocked++;
 	generation = qpair->generation;
 	qp_unlock(qpair);
@@ -2674,15 +2624,14 @@
 				 const u64 produce_q_size,
 				 const void *buf,
 				 size_t buf_size,
-				 vmci_memcpy_to_queue_func memcpy_to_queue,
-				 bool can_block)
+				 vmci_memcpy_to_queue_func memcpy_to_queue)
 {
 	s64 free_space;
 	u64 tail;
 	size_t written;
 	ssize_t result;
 
-	result = qp_map_queue_headers(produce_q, consume_q, can_block);
+	result = qp_map_queue_headers(produce_q, consume_q);
 	if (unlikely(result != VMCI_SUCCESS))
 		return result;
 
@@ -2737,15 +2686,14 @@
 				 void *buf,
 				 size_t buf_size,
 				 vmci_memcpy_from_queue_func memcpy_from_queue,
-				 bool update_consumer,
-				 bool can_block)
+				 bool update_consumer)
 {
 	s64 buf_ready;
 	u64 head;
 	size_t read;
 	ssize_t result;
 
-	result = qp_map_queue_headers(produce_q, consume_q, can_block);
+	result = qp_map_queue_headers(produce_q, consume_q);
 	if (unlikely(result != VMCI_SUCCESS))
 		return result;
 
@@ -2842,32 +2790,11 @@
 		route = vmci_guest_code_active() ?
 		    VMCI_ROUTE_AS_GUEST : VMCI_ROUTE_AS_HOST;
 
-	/* If NONBLOCK or PINNED is set, we better be the guest personality. */
-	if ((!vmci_can_block(flags) || vmci_qp_pinned(flags)) &&
-	    VMCI_ROUTE_AS_GUEST != route) {
-		pr_devel("Not guest personality w/ NONBLOCK OR PINNED set");
+	if (flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED)) {
+		pr_devel("NONBLOCK OR PINNED set");
 		return VMCI_ERROR_INVALID_ARGS;
 	}
 
-	/*
-	 * Limit the size of pinned QPs and check sanity.
-	 *
-	 * Pinned pages implies non-blocking mode.  Mutexes aren't acquired
-	 * when the NONBLOCK flag is set in qpair code; and also should not be
-	 * acquired when the PINNED flagged is set.  Since pinning pages
-	 * implies we want speed, it makes no sense not to have NONBLOCK
-	 * set if PINNED is set.  Hence enforce this implication.
-	 */
-	if (vmci_qp_pinned(flags)) {
-		if (vmci_can_block(flags)) {
-			pr_err("Attempted to enable pinning w/o non-blocking");
-			return VMCI_ERROR_INVALID_ARGS;
-		}
-
-		if (produce_qsize + consume_qsize > VMCI_MAX_PINNED_QP_MEMORY)
-			return VMCI_ERROR_NO_RESOURCES;
-	}
-
 	my_qpair = kzalloc(sizeof(*my_qpair), GFP_KERNEL);
 	if (!my_qpair)
 		return VMCI_ERROR_NO_MEM;
@@ -3195,8 +3122,7 @@
 					   qpair->consume_q,
 					   qpair->produce_q_size,
 					   buf, buf_size,
-					   qp_memcpy_to_queue,
-					   vmci_can_block(qpair->flags));
+					   qp_memcpy_to_queue);
 
 		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
 		    !qp_wait_for_ready_queue(qpair))
@@ -3237,8 +3163,7 @@
 					   qpair->consume_q,
 					   qpair->consume_q_size,
 					   buf, buf_size,
-					   qp_memcpy_from_queue, true,
-					   vmci_can_block(qpair->flags));
+					   qp_memcpy_from_queue, true);
 
 		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
 		    !qp_wait_for_ready_queue(qpair))
@@ -3280,8 +3205,7 @@
 					   qpair->consume_q,
 					   qpair->consume_q_size,
 					   buf, buf_size,
-					   qp_memcpy_from_queue, false,
-					   vmci_can_block(qpair->flags));
+					   qp_memcpy_from_queue, false);
 
 		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
 		    !qp_wait_for_ready_queue(qpair))
@@ -3323,8 +3247,7 @@
 					   qpair->consume_q,
 					   qpair->produce_q_size,
 					   iov, iov_size,
-					   qp_memcpy_to_queue_iov,
-					   vmci_can_block(qpair->flags));
+					   qp_memcpy_to_queue_iov);
 
 		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
 		    !qp_wait_for_ready_queue(qpair))
@@ -3367,7 +3290,7 @@
 					   qpair->consume_q_size,
 					   iov, iov_size,
 					   qp_memcpy_from_queue_iov,
-					   true, vmci_can_block(qpair->flags));
+					   true);
 
 		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
 		    !qp_wait_for_ready_queue(qpair))
@@ -3411,7 +3334,7 @@
 					   qpair->consume_q_size,
 					   iov, iov_size,
 					   qp_memcpy_from_queue_iov,
-					   false, vmci_can_block(qpair->flags));
+					   false);
 
 		if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
 		    !qp_wait_for_ready_queue(qpair))
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.h b/drivers/misc/vmw_vmci/vmci_queue_pair.h
index 58c6959..ed177f0 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.h
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.h
@@ -146,24 +146,6 @@
 	return page_store->len >= 2;
 }
 
-/*
- * Helper function to check if the non-blocking flag
- * is set for a given queue pair.
- */
-static inline bool vmci_can_block(u32 flags)
-{
-	return !(flags & VMCI_QPFLAG_NONBLOCK);
-}
-
-/*
- * Helper function to check if the queue pair is pinned
- * into memory.
- */
-static inline bool vmci_qp_pinned(u32 flags)
-{
-	return flags & VMCI_QPFLAG_PINNED;
-}
-
 void vmci_qp_broker_exit(void);
 int vmci_qp_broker_alloc(struct vmci_handle handle, u32 peer,
 			 u32 flags, u32 priv_flags,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 49a5bca..5d08855 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1313,7 +1313,7 @@
 
 	supply = devm_regulator_get(dev, "vmmc");
 	mmc->supply.vmmc = supply;
-	mmc->supply.vqmmc = devm_regulator_get(dev, "vqmmc");
+	mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
 
 	if (IS_ERR(supply))
 		return PTR_ERR(supply);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index ee5f167..5424073 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2231,7 +2231,7 @@
 		}
 	}
 
-	host->vmmc = devm_regulator_get(host->dev, "vmmc");
+	host->vmmc = devm_regulator_get_optional(host->dev, "vmmc");
 	if (IS_ERR(host->vmmc)) {
 		ret = PTR_ERR(host->vmmc);
 		if (ret == -EPROBE_DEFER)
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 2c5a91b..1956a3d 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -83,7 +83,7 @@
 static inline void pxamci_init_ocr(struct pxamci_host *host)
 {
 #ifdef CONFIG_REGULATOR
-	host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
+	host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc");
 
 	if (IS_ERR(host->vcc))
 		host->vcc = NULL;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index a78bd4f..dd2c083 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2966,7 +2966,7 @@
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
 
 	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
-	host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc");
+	host->vqmmc = regulator_get_optional(mmc_dev(mmc), "vqmmc");
 	if (IS_ERR_OR_NULL(host->vqmmc)) {
 		if (PTR_ERR(host->vqmmc) < 0) {
 			pr_info("%s: no vqmmc regulator found\n",
@@ -3042,7 +3042,7 @@
 
 	ocr_avail = 0;
 
-	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+	host->vmmc = regulator_get_optional(mmc_dev(mmc), "vmmc");
 	if (IS_ERR_OR_NULL(host->vmmc)) {
 		if (PTR_ERR(host->vmmc) < 0) {
 			pr_info("%s: no vmmc regulator found\n",
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index cff6f02..7f2a032 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -996,7 +996,7 @@
 		printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
 			cardname);
 	cops_dev = cops_probe(-1);
-	return PTR_RET(cops_dev);
+	return PTR_ERR_OR_ZERO(cops_dev);
 }
 
 static void __exit cops_module_exit(void)
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index b5782cd..01e2ac5 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -1243,7 +1243,7 @@
 		       "ltpc: Autoprobing is not recommended for modules\n");
 
 	dev_ltpc = ltpc_probe();
-	return PTR_RET(dev_ltpc);
+	return PTR_ERR_OR_ZERO(dev_ltpc);
 }
 module_init(ltpc_module_init);
 #endif
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index e8d0ef5..10ceca5 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -1147,7 +1147,7 @@
 static int __init atarilance_module_init(void)
 {
 	atarilance_dev = atarilance_probe(-1);
-	return PTR_RET(atarilance_dev);
+	return PTR_ERR_OR_ZERO(atarilance_dev);
 }
 
 static void __exit atarilance_module_exit(void)
diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c
index a51497c..e108e91 100644
--- a/drivers/net/ethernet/amd/mvme147.c
+++ b/drivers/net/ethernet/amd/mvme147.c
@@ -188,7 +188,7 @@
 int __init init_module(void)
 {
 	dev_mvme147_lance = mvme147lance_probe(-1);
-	return PTR_RET(dev_mvme147_lance);
+	return PTR_ERR_OR_ZERO(dev_mvme147_lance);
 }
 
 void __exit cleanup_module(void)
diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c
index 26fc0ce..1cf33ad 100644
--- a/drivers/net/ethernet/amd/ni65.c
+++ b/drivers/net/ethernet/amd/ni65.c
@@ -1238,7 +1238,7 @@
 int __init init_module(void)
 {
  	dev_ni65 = ni65_probe(-1);
-	return PTR_RET(dev_ni65);
+	return PTR_ERR_OR_ZERO(dev_ni65);
 }
 
 void __exit cleanup_module(void)
diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c
index 4375abe..d6b2029 100644
--- a/drivers/net/ethernet/amd/sun3lance.c
+++ b/drivers/net/ethernet/amd/sun3lance.c
@@ -940,7 +940,7 @@
 int __init init_module(void)
 {
 	sun3lance_dev = sun3lance_probe(-1);
-	return PTR_RET(sun3lance_dev);
+	return PTR_ERR_OR_ZERO(sun3lance_dev);
 }
 
 void __exit cleanup_module(void)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index ce9b387..00b88cb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1333,6 +1333,8 @@
 	BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
 	BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
 	BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+	BNX2X_SP_RTNL_TX_STOP,
+	BNX2X_SP_RTNL_TX_RESUME,
 };
 
 struct bnx2x_prev_path_list {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f2d1ff1..0cc2611 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -53,6 +53,7 @@
 	struct bnx2x_fp_stats *to_fp_stats = &bp->fp_stats[to];
 	int old_max_eth_txqs, new_max_eth_txqs;
 	int old_txdata_index = 0, new_txdata_index = 0;
+	struct bnx2x_agg_info *old_tpa_info = to_fp->tpa_info;
 
 	/* Copy the NAPI object as it has been already initialized */
 	from_fp->napi = to_fp->napi;
@@ -61,6 +62,11 @@
 	memcpy(to_fp, from_fp, sizeof(*to_fp));
 	to_fp->index = to;
 
+	/* Retain the tpa_info of the original `to' version as we don't want
+	 * 2 FPs to contain the same tpa_info pointer.
+	 */
+	to_fp->tpa_info = old_tpa_info;
+
 	/* move sp_objs contents as well, as their indices match fp ones */
 	memcpy(to_sp_objs, from_sp_objs, sizeof(*to_sp_objs));
 
@@ -2956,8 +2962,9 @@
 	if (IS_PF(bp)) {
 		if (CNIC_LOADED(bp))
 			bnx2x_free_mem_cnic(bp);
-		bnx2x_free_mem(bp);
 	}
+	bnx2x_free_mem(bp);
+
 	bp->state = BNX2X_STATE_CLOSED;
 	bp->cnic_loaded = false;
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index f9122f2..fcf2761 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -30,10 +30,8 @@
 #include "bnx2x_dcb.h"
 
 /* forward declarations of dcbx related functions */
-static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
 static void bnx2x_pfc_set_pfc(struct bnx2x *bp);
 static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp);
-static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
 static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
 					  u32 *set_configuration_ets_pg,
 					  u32 *pri_pg_tbl);
@@ -425,30 +423,52 @@
 		bnx2x_pfc_clear(bp);
 }
 
-static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
+int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp)
 {
 	struct bnx2x_func_state_params func_params = {NULL};
+	int rc;
 
 	func_params.f_obj = &bp->func_obj;
 	func_params.cmd = BNX2X_F_CMD_TX_STOP;
 
+	__set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+	__set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
 	DP(BNX2X_MSG_DCB, "STOP TRAFFIC\n");
-	return bnx2x_func_state_change(bp, &func_params);
+
+	rc = bnx2x_func_state_change(bp, &func_params);
+	if (rc) {
+		BNX2X_ERR("Unable to hold traffic for HW configuration\n");
+		bnx2x_panic();
+	}
+
+	return rc;
 }
 
-static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
+int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp)
 {
 	struct bnx2x_func_state_params func_params = {NULL};
 	struct bnx2x_func_tx_start_params *tx_params =
 		&func_params.params.tx_start;
+	int rc;
 
 	func_params.f_obj = &bp->func_obj;
 	func_params.cmd = BNX2X_F_CMD_TX_START;
 
+	__set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+	__set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
 	bnx2x_dcbx_fw_struct(bp, tx_params);
 
 	DP(BNX2X_MSG_DCB, "START TRAFFIC\n");
-	return bnx2x_func_state_change(bp, &func_params);
+
+	rc = bnx2x_func_state_change(bp, &func_params);
+	if (rc) {
+		BNX2X_ERR("Unable to resume traffic after HW configuration\n");
+		bnx2x_panic();
+	}
+
+	return rc;
 }
 
 static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp)
@@ -744,7 +764,9 @@
 			if (IS_MF(bp))
 				bnx2x_link_sync_notify(bp);
 
-			bnx2x_dcbx_stop_hw_tx(bp);
+			set_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state);
+
+			schedule_delayed_work(&bp->sp_rtnl_task, 0);
 
 			return;
 		}
@@ -757,7 +779,9 @@
 		/* ets may affect cmng configuration: reinit it in hw */
 		bnx2x_set_local_cmng(bp);
 
-		bnx2x_dcbx_resume_hw_tx(bp);
+		set_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state);
+
+		schedule_delayed_work(&bp->sp_rtnl_task, 0);
 
 		return;
 	case BNX2X_DCBX_STATE_TX_RELEASED:
@@ -2367,21 +2391,24 @@
 		case DCB_FEATCFG_ATTR_PG:
 			if (bp->dcbx_local_feat.ets.enabled)
 				*flags |= DCB_FEATCFG_ENABLE;
-			if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR)
+			if (bp->dcbx_error & (DCBX_LOCAL_ETS_ERROR |
+					      DCBX_REMOTE_MIB_ERROR))
 				*flags |= DCB_FEATCFG_ERROR;
 			break;
 		case DCB_FEATCFG_ATTR_PFC:
 			if (bp->dcbx_local_feat.pfc.enabled)
 				*flags |= DCB_FEATCFG_ENABLE;
 			if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR |
-			    DCBX_LOCAL_PFC_MISMATCH))
+					      DCBX_LOCAL_PFC_MISMATCH |
+					      DCBX_REMOTE_MIB_ERROR))
 				*flags |= DCB_FEATCFG_ERROR;
 			break;
 		case DCB_FEATCFG_ATTR_APP:
 			if (bp->dcbx_local_feat.app.enabled)
 				*flags |= DCB_FEATCFG_ENABLE;
 			if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR |
-			    DCBX_LOCAL_APP_MISMATCH))
+					      DCBX_LOCAL_APP_MISMATCH |
+					      DCBX_REMOTE_MIB_ERROR))
 				*flags |= DCB_FEATCFG_ERROR;
 			break;
 		default:
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
index 125bd1b..804b8f6 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
@@ -199,4 +199,7 @@
 int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall);
 #endif /* BCM_DCBNL */
 
+int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp);
+int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp);
+
 #endif /* BNX2X_DCB_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 955d6cf..815f2de 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -2261,6 +2261,23 @@
 		bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH;
 }
 
+static void bnx2x_init_dropless_fc(struct bnx2x *bp)
+{
+	u32 pause_enabled = 0;
+
+	if (!CHIP_IS_E1(bp) && bp->dropless_fc && bp->link_vars.link_up) {
+		if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
+			pause_enabled = 1;
+
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+			   USTORM_ETH_PAUSE_ENABLED_OFFSET(BP_PORT(bp)),
+		       pause_enabled);
+	}
+
+	DP(NETIF_MSG_IFUP | NETIF_MSG_LINK, "dropless_fc is %s\n",
+	   pause_enabled ? "enabled" : "disabled");
+}
+
 int bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode)
 {
 	int rc, cfx_idx = bnx2x_get_link_cfg_idx(bp);
@@ -2294,6 +2311,8 @@
 
 		bnx2x_release_phy_lock(bp);
 
+		bnx2x_init_dropless_fc(bp);
+
 		bnx2x_calc_fc_adv(bp);
 
 		if (bp->link_vars.link_up) {
@@ -2315,6 +2334,8 @@
 		bnx2x_phy_init(&bp->link_params, &bp->link_vars);
 		bnx2x_release_phy_lock(bp);
 
+		bnx2x_init_dropless_fc(bp);
+
 		bnx2x_calc_fc_adv(bp);
 	} else
 		BNX2X_ERR("Bootcode is missing - can not set link\n");
@@ -2556,21 +2577,10 @@
 
 	bnx2x_link_update(&bp->link_params, &bp->link_vars);
 
+	bnx2x_init_dropless_fc(bp);
+
 	if (bp->link_vars.link_up) {
 
-		/* dropless flow control */
-		if (!CHIP_IS_E1(bp) && bp->dropless_fc) {
-			int port = BP_PORT(bp);
-			u32 pause_enabled = 0;
-
-			if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
-				pause_enabled = 1;
-
-			REG_WR(bp, BAR_USTRORM_INTMEM +
-			       USTORM_ETH_PAUSE_ENABLED_OFFSET(port),
-			       pause_enabled);
-		}
-
 		if (bp->link_vars.mac_type != MAC_TYPE_EMAC) {
 			struct host_port_stats *pstats;
 
@@ -7845,12 +7855,15 @@
 {
 	int i;
 
-	BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
-		       sizeof(struct host_sp_status_block));
-
 	BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping,
 		       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
 
+	if (IS_VF(bp))
+		return;
+
+	BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
+		       sizeof(struct host_sp_status_block));
+
 	BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
 		       sizeof(struct bnx2x_slowpath));
 
@@ -9645,6 +9658,12 @@
 			       &bp->sp_rtnl_state))
 		bnx2x_pf_set_vfs_vlan(bp);
 
+	if (test_and_clear_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state))
+		bnx2x_dcbx_stop_hw_tx(bp);
+
+	if (test_and_clear_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state))
+		bnx2x_dcbx_resume_hw_tx(bp);
+
 	/* work which needs rtnl lock not-taken (as it takes the lock itself and
 	 * can be called from other contexts as well)
 	 */
@@ -9941,8 +9960,6 @@
 
 static int bnx2x_do_flr(struct bnx2x *bp)
 {
-	int i;
-	u16 status;
 	struct pci_dev *dev = bp->pdev;
 
 	if (CHIP_IS_E1x(bp)) {
@@ -9957,20 +9974,8 @@
 		return -EINVAL;
 	}
 
-	/* Wait for Transaction Pending bit clean */
-	for (i = 0; i < 4; i++) {
-		if (i)
-			msleep((1 << (i - 1)) * 100);
-
-		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
-		if (!(status & PCI_EXP_DEVSTA_TRPND))
-			goto clear;
-	}
-
-	dev_err(&dev->dev,
-		"transaction is not cleared; proceeding with reset anyway\n");
-
-clear:
+	if (!pci_wait_for_pending_transaction(dev))
+		dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
 
 	BNX2X_DEV_INFO("Initiating FLR\n");
 	bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0);
@@ -11147,6 +11152,9 @@
 	int tmp;
 	u32 cfg;
 
+	if (IS_VF(bp))
+		return 0;
+
 	if (IS_MF(bp) && !CHIP_IS_E1x(bp)) {
 		/* Take function: tmp = func */
 		tmp = BP_ABS_FUNC(bp);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 44104fb..e8706e1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -522,23 +522,6 @@
 	return 0;
 }
 
-static int
-bnx2x_vfop_config_vlan0(struct bnx2x *bp,
-			struct bnx2x_vlan_mac_ramrod_params *vlan_mac,
-			bool add)
-{
-	int rc;
-
-	vlan_mac->user_req.cmd = add ? BNX2X_VLAN_MAC_ADD :
-		BNX2X_VLAN_MAC_DEL;
-	vlan_mac->user_req.u.vlan.vlan = 0;
-
-	rc = bnx2x_config_vlan_mac(bp, vlan_mac);
-	if (rc == -EEXIST)
-		rc = 0;
-	return rc;
-}
-
 static int bnx2x_vfop_config_list(struct bnx2x *bp,
 				  struct bnx2x_vfop_filters *filters,
 				  struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
@@ -643,30 +626,14 @@
 
 	case BNX2X_VFOP_VLAN_CONFIG_LIST:
 		/* next state */
-		vfop->state = BNX2X_VFOP_VLAN_CONFIG_LIST_0;
+		vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
 
-		/* remove vlan0 - could be no-op */
-		vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, false);
-		if (vfop->rc)
-			goto op_err;
-
-		/* Do vlan list config. if this operation fails we try to
-		 * restore vlan0 to keep the queue is working order
-		 */
+		/* do list config */
 		vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
 		if (!vfop->rc) {
 			set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
 			vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
 		}
-		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); /* fall-through */
-
-	case BNX2X_VFOP_VLAN_CONFIG_LIST_0:
-		/* next state */
-		vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
-		if (list_empty(&obj->head))
-			/* add vlan0 */
-			vfop->rc = bnx2x_vfop_config_vlan0(bp, vlan_mac, true);
 		bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
 
 	default:
@@ -1747,11 +1714,8 @@
 
 void bnx2x_iov_init_dmae(struct bnx2x *bp)
 {
-	DP(BNX2X_MSG_IOV, "SRIOV is %s\n", IS_SRIOV(bp) ? "ON" : "OFF");
-	if (!IS_SRIOV(bp))
-		return;
-
-	REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
+	if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV))
+		REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0);
 }
 
 static int bnx2x_vf_bus(struct bnx2x *bp, int vfid)
@@ -2822,6 +2786,18 @@
 	return 0;
 }
 
+struct set_vf_state_cookie {
+	struct bnx2x_virtf *vf;
+	u8 state;
+};
+
+void bnx2x_set_vf_state(void *cookie)
+{
+	struct set_vf_state_cookie *p = (struct set_vf_state_cookie *)cookie;
+
+	p->vf->state = p->state;
+}
+
 /* VFOP close (teardown the queues, delete mcasts and close HW) */
 static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
@@ -2872,7 +2848,19 @@
 op_err:
 	BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
 op_done:
-	vf->state = VF_ACQUIRED;
+
+	/* need to make sure there are no outstanding stats ramrods which may
+	 * cause the device to access the VF's stats buffer which it will free
+	 * as soon as we return from the close flow.
+	 */
+	{
+		struct set_vf_state_cookie cookie;
+
+		cookie.vf = vf;
+		cookie.state = VF_ACQUIRED;
+		bnx2x_stats_safe_exec(bp, bnx2x_set_vf_state, &cookie);
+	}
+
 	DP(BNX2X_MSG_IOV, "set state to acquired\n");
 	bnx2x_vfop_end(bp, vf, vfop);
 }
@@ -3084,8 +3072,9 @@
 	pci_disable_sriov(bp->pdev);
 }
 
-static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx,
-			       struct bnx2x_virtf *vf)
+static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx,
+			     struct bnx2x_virtf **vf,
+			     struct pf_vf_bulletin_content **bulletin)
 {
 	if (bp->state != BNX2X_STATE_OPEN) {
 		BNX2X_ERR("vf ndo called though PF is down\n");
@@ -3103,12 +3092,22 @@
 		return -EINVAL;
 	}
 
-	if (!vf) {
+	/* init members */
+	*vf = BP_VF(bp, vfidx);
+	*bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+	if (!*vf) {
 		BNX2X_ERR("vf ndo called but vf was null. vfidx was %d\n",
 			  vfidx);
 		return -EINVAL;
 	}
 
+	if (!*bulletin) {
+		BNX2X_ERR("vf ndo called but Bulletin Board struct is null. vfidx was %d\n",
+			  vfidx);
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -3116,17 +3115,19 @@
 			struct ifla_vf_info *ivi)
 {
 	struct bnx2x *bp = netdev_priv(dev);
-	struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
-	struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
-	struct bnx2x_vlan_mac_obj *vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj);
-	struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+	struct bnx2x_virtf *vf = NULL;
+	struct pf_vf_bulletin_content *bulletin = NULL;
+	struct bnx2x_vlan_mac_obj *mac_obj;
+	struct bnx2x_vlan_mac_obj *vlan_obj;
 	int rc;
 
-	/* sanity */
-	rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+	/* sanity and init */
+	rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
 	if (rc)
 		return rc;
-	if (!mac_obj || !vlan_obj || !bulletin) {
+	mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+	vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj);
+	if (!mac_obj || !vlan_obj) {
 		BNX2X_ERR("VF partially initialized\n");
 		return -EINVAL;
 	}
@@ -3183,11 +3184,11 @@
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	int rc, q_logical_state;
-	struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
-	struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+	struct bnx2x_virtf *vf = NULL;
+	struct pf_vf_bulletin_content *bulletin = NULL;
 
-	/* sanity */
-	rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+	/* sanity and init */
+	rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
 	if (rc)
 		return rc;
 	if (!is_valid_ether_addr(mac)) {
@@ -3249,11 +3250,11 @@
 {
 	struct bnx2x *bp = netdev_priv(dev);
 	int rc, q_logical_state;
-	struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
-	struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+	struct bnx2x_virtf *vf = NULL;
+	struct pf_vf_bulletin_content *bulletin = NULL;
 
-	/* sanity */
-	rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+	/* sanity and init */
+	rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin);
 	if (rc)
 		return rc;
 
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index d63d132..86436c7 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -522,20 +522,16 @@
 /* should be called under stats_sema */
 static void __bnx2x_stats_start(struct bnx2x *bp)
 {
-	/* vfs travel through here as part of the statistics FSM, but no action
-	 * is required
-	 */
-	if (IS_VF(bp))
-		return;
+	if (IS_PF(bp)) {
+		if (bp->port.pmf)
+			bnx2x_port_stats_init(bp);
 
-	if (bp->port.pmf)
-		bnx2x_port_stats_init(bp);
+		else if (bp->func_stx)
+			bnx2x_func_stats_init(bp);
 
-	else if (bp->func_stx)
-		bnx2x_func_stats_init(bp);
-
-	bnx2x_hw_stats_post(bp);
-	bnx2x_storm_stats_post(bp);
+		bnx2x_hw_stats_post(bp);
+		bnx2x_storm_stats_post(bp);
+	}
 
 	bp->stats_started = true;
 }
@@ -1997,3 +1993,14 @@
 		       estats->mac_discard);
 	}
 }
+
+void bnx2x_stats_safe_exec(struct bnx2x *bp,
+			   void (func_to_exec)(void *cookie),
+			   void *cookie){
+	if (down_timeout(&bp->stats_sema, HZ/10))
+		BNX2X_ERR("Unable to acquire stats lock\n");
+	bnx2x_stats_comp(bp);
+	func_to_exec(cookie);
+	__bnx2x_stats_start(bp);
+	up(&bp->stats_sema);
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index 853824d..f358450 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -539,6 +539,9 @@
 void bnx2x_memset_stats(struct bnx2x *bp);
 void bnx2x_stats_init(struct bnx2x *bp);
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
+void bnx2x_stats_safe_exec(struct bnx2x *bp,
+			   void (func_to_exec)(void *cookie),
+			   void *cookie);
 
 /**
  * bnx2x_save_statistics - save statistics when unloading.
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 181edb5..3d91a5e 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2563,8 +2563,8 @@
 	/* Wait for all pending tx completions to arrive so that
 	 * all tx skbs are freed.
 	 */
-	be_tx_compl_clean(adapter);
 	netif_tx_disable(netdev);
+	be_tx_compl_clean(adapter);
 
 	be_rx_qs_destroy(adapter);
 
@@ -4373,6 +4373,10 @@
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
+	status = be_fw_wait_ready(adapter);
+	if (status)
+		return status;
+
 	/* tell fw we're ready to fire cmds */
 	status = be_cmd_fw_init(adapter);
 	if (status)
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 77ea0db..c610a27 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -971,8 +971,7 @@
 						       htons(ETH_P_8021Q),
 						       vlan_tag);
 
-			if (!skb_defer_rx_timestamp(skb))
-				napi_gro_receive(&fep->napi, skb);
+			napi_gro_receive(&fep->napi, skb);
 		}
 
 		bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data,
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 7fbe6ab..23de82a 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -3069,7 +3069,7 @@
 		jwrite32(jme, JME_APMC, apmc);
 	}
 
-	NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, jme->rx_ring_size >> 2)
+	NETIF_NAPI_SET(netdev, &jme->napi, jme_poll, NAPI_POLL_WEIGHT)
 
 	spin_lock_init(&jme->phy_lock);
 	spin_lock_init(&jme->macaddr_lock);
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index 3fe09ab..32675e1 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -1171,7 +1171,6 @@
 
 #define NETXEN_DB_MAPSIZE_BYTES    	0x1000
 
-#define NETXEN_NETDEV_WEIGHT 128
 #define NETXEN_ADAPTER_UP_MAGIC 777
 #define NETXEN_NIC_PEG_TUNE 0
 
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index c401b0b..ec4cf7f 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -197,7 +197,7 @@
 	for (ring = 0; ring < adapter->max_sds_rings; ring++) {
 		sds_ring = &recv_ctx->sds_rings[ring];
 		netif_napi_add(netdev, &sds_ring->napi,
-				netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+				netxen_nic_poll, NAPI_POLL_WEIGHT);
 	}
 
 	return 0;
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index b5eb419..85e5c97 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -7088,7 +7088,7 @@
 
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
 	RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
-	RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+	RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus));
 	if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
 		tp->features |= RTL_FEATURE_WOL;
 	if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index 2a469b2..30d7442 100644
--- a/drivers/net/ethernet/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
@@ -675,7 +675,7 @@
 		BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
 		BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
 			     EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
-		rep_index = spec->type - EFX_FILTER_INDEX_UC_DEF;
+		rep_index = spec->type - EFX_FILTER_UC_DEF;
 		ins_index = rep_index;
 
 		spin_lock_bh(&state->lock);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 03de76c..1c83a44 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -71,14 +71,18 @@
 		plat->force_sf_dma_mode = 1;
 	}
 
-	dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL);
-	if (!dma_cfg)
-		return -ENOMEM;
-
-	plat->dma_cfg = dma_cfg;
-	of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
-	dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
-	dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
+	if (of_find_property(np, "snps,pbl", NULL)) {
+		dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+				       GFP_KERNEL);
+		if (!dma_cfg)
+			return -ENOMEM;
+		plat->dma_cfg = dma_cfg;
+		of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+		dma_cfg->fixed_burst =
+			of_property_read_bool(np, "snps,fixed-burst");
+		dma_cfg->mixed_burst =
+			of_property_read_bool(np, "snps,mixed-burst");
+	}
 
 	return 0;
 }
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index fa32240..52b2adf 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -9478,7 +9478,7 @@
 	if (IS_ERR(plat_dev))
 		return NULL;
 
-	for (i = 0; attr_name(niu_parent_attributes[i]); i++) {
+	for (i = 0; niu_parent_attributes[i].attr.name; i++) {
 		int err = device_create_file(&plat_dev->dev,
 					     &niu_parent_attributes[i]);
 		if (err)
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index ad32af6..9c805e0 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -1466,8 +1466,7 @@
 {
 	netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
 	/* NAPI */
-	netif_napi_add(netdev, napi,
-		       gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+	netif_napi_add(netdev, napi, gelic_net_poll, NAPI_POLL_WEIGHT);
 	netdev->ethtool_ops = &gelic_ether_ethtool_ops;
 	netdev->netdev_ops = &gelic_netdevice_ops;
 }
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
index a93df6a..309abb4 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -37,7 +37,6 @@
 #define GELIC_NET_RXBUF_ALIGN           128
 #define GELIC_CARD_RX_CSUM_DEFAULT      1 /* hw chksum */
 #define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
-#define GELIC_NET_NAPI_WEIGHT           (GELIC_NET_RX_DESCRIPTORS)
 #define GELIC_NET_BROADCAST_ADDR        0xffffffffffffL
 
 #define GELIC_NET_MC_COUNT_MAX          32 /* multicast address list */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
index e90e1f4..64b4639 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
@@ -175,6 +175,7 @@
 		printk(KERN_WARNING "Setting MDIO clock divisor to "
 		       "default %d\n", DEFAULT_CLOCK_DIVISOR);
 		clk_div = DEFAULT_CLOCK_DIVISOR;
+		of_node_put(np1);
 		goto issue;
 	}
 
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 23a0fff..524f713 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -306,7 +306,6 @@
 			       struct ethtool_drvinfo *info)
 {
 	strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
-	strlcpy(info->version, HV_DRV_VERSION, sizeof(info->version));
 	strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 }
 
@@ -529,7 +528,6 @@
 }
 
 MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
 MODULE_DESCRIPTION("Microsoft Hyper-V network driver");
 
 module_init(netvsc_drv_init);
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index a412671..177441a 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -123,14 +123,14 @@
 
 	tty = priv->tty;
 
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	old_termios = tty->termios;
 	cflag = tty->termios.c_cflag;
 	tty_encode_baud_rate(tty, speed, speed);
 	if (tty->ops->set_termios)
 		tty->ops->set_termios(tty, &old_termios);
 	priv->io.speed = speed;
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 
 	return 0;
 }
@@ -280,7 +280,7 @@
 	struct ktermios old_termios;
 	int cflag;
 
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	old_termios = tty->termios;
 	cflag = tty->termios.c_cflag;
 	
@@ -292,7 +292,7 @@
 	tty->termios.c_cflag = cflag;
 	if (tty->ops->set_termios)
 		tty->ops->set_termios(tty, &old_termios);
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 }
 
 /*****************************************************************/
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 51f2bc3..2dcc60f 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -210,8 +210,7 @@
 			pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0));
 			pci_write_config_byte(pcidev,0x5a,0xc0);
 			WriteLPCReg(0x28, 0x70 );
-			if (via_ircc_open(pcidev, &info, 0x3076) == 0)
-				rc=0;
+			rc = via_ircc_open(pcidev, &info, 0x3076);
 		} else
 			rc = -ENODEV; //IR not turn on	 
 	} else { //Not VT1211
@@ -249,8 +248,7 @@
 			info.irq=FirIRQ;
 			info.dma=FirDRQ1;
 			info.dma2=FirDRQ0;
-			if (via_ircc_open(pcidev, &info, 0x3096) == 0)
-				rc=0;
+			rc = via_ircc_open(pcidev, &info, 0x3096);
 		} else
 			rc = -ENODEV; //IR not turn on !!!!!
 	}//Not VT1211
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index b51db2a..ea53abb 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -68,6 +68,8 @@
 #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
 		      NETIF_F_TSO6 | NETIF_F_UFO)
 #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
+#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
+
 /*
  * RCU usage:
  * The macvtap_queue and the macvlan_dev are loosely coupled, the
@@ -278,7 +280,8 @@
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
 	struct macvtap_queue *q = macvtap_get_queue(dev, skb);
-	netdev_features_t features;
+	netdev_features_t features = TAP_FEATURES;
+
 	if (!q)
 		goto drop;
 
@@ -287,9 +290,11 @@
 
 	skb->dev = dev;
 	/* Apply the forward feature mask so that we perform segmentation
-	 * according to users wishes.
+	 * according to users wishes.  This only works if VNET_HDR is
+	 * enabled.
 	 */
-	features = netif_skb_features(skb) & vlan->tap_features;
+	if (q->flags & IFF_VNET_HDR)
+		features |= vlan->tap_features;
 	if (netif_needs_gso(skb, features)) {
 		struct sk_buff *segs = __skb_gso_segment(skb, features, false);
 
@@ -1064,8 +1069,7 @@
 	/* tap_features are the same as features on tun/tap and
 	 * reflect user expectations.
 	 */
-	vlan->tap_features = vlan->dev->features &
-			    (feature_mask | ~TUN_OFFLOADS);
+	vlan->tap_features = feature_mask;
 	vlan->set_features = features;
 	netdev_update_features(vlan->dev);
 
@@ -1161,10 +1165,6 @@
 			    TUN_F_TSO_ECN | TUN_F_UFO))
 			return -EINVAL;
 
-		/* TODO: only accept frames with the features that
-			 got enabled for forwarded frames */
-		if (!(q->flags & IFF_VNET_HDR))
-			return  -EINVAL;
 		rtnl_lock();
 		ret = set_offload(q, arg);
 		rtnl_unlock();
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 8e7af83..138de83 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -23,7 +23,7 @@
 #define RTL821x_INER_INIT	0x6400
 #define RTL821x_INSR		0x13
 
-#define	RTL8211E_INER_LINK_STAT	0x10
+#define	RTL8211E_INER_LINK_STATUS	0x400
 
 MODULE_DESCRIPTION("Realtek PHY driver");
 MODULE_AUTHOR("Johnson Leung");
@@ -57,7 +57,7 @@
 
 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 		err = phy_write(phydev, RTL821x_INER,
-				RTL8211E_INER_LINK_STAT);
+				RTL8211E_INER_LINK_STATUS);
 	else
 		err = phy_write(phydev, RTL821x_INER, 0);
 
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 2bc87e3..4233c05 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1028,12 +1028,20 @@
 	dev->mii.phy_id = 0x03;
 	dev->mii.supports_gmii = 1;
 
+	if (usb_device_no_sg_constraint(dev->udev))
+		dev->can_dma_sg = 1;
+
 	dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
 			      NETIF_F_RXCSUM;
 
 	dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
 				 NETIF_F_RXCSUM;
 
+	if (dev->can_dma_sg) {
+		dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
+		dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
+	}
+
 	/* Enable checksum offload */
 	*tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
 	       AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 8728198..25ba7ec 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -400,6 +400,10 @@
 	{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68a2, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
 	  .driver_info = (unsigned long)&cdc_mbim_info_zlp,
 	},
+	/* HP hs2434 Mobile Broadband Module needs ZLPs */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x3f0, 0x4b1d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+	  .driver_info = (unsigned long)&cdc_mbim_info_zlp,
+	},
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
 	  .driver_info = (unsigned long)&cdc_mbim_info,
 	},
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cba1d46..86292e6 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -2816,13 +2816,16 @@
 static int hso_get_config_data(struct usb_interface *interface)
 {
 	struct usb_device *usbdev = interface_to_usbdev(interface);
-	u8 config_data[17];
+	u8 *config_data = kmalloc(17, GFP_KERNEL);
 	u32 if_num = interface->altsetting->desc.bInterfaceNumber;
 	s32 result;
 
+	if (!config_data)
+		return -ENOMEM;
 	if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
 			    0x86, 0xC0, 0, 0, config_data, 17,
 			    USB_CTRL_SET_TIMEOUT) != 0x11) {
+		kfree(config_data);
 		return -EIO;
 	}
 
@@ -2873,6 +2876,7 @@
 	if (config_data[16] & 0x1)
 		result |= HSO_INFO_CRC_BUG;
 
+	kfree(config_data);
 	return result;
 }
 
@@ -2886,6 +2890,11 @@
 	struct hso_shared_int *shared_int;
 	struct hso_device *tmp_dev = NULL;
 
+	if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
+		dev_err(&interface->dev, "Not our interface\n");
+		return -ENODEV;
+	}
+
 	if_num = interface->altsetting->desc.bInterfaceNumber;
 
 	/* Get the interface/port specification from either driver_info or from
@@ -2895,10 +2904,6 @@
 	else
 		port_spec = hso_get_config_data(interface);
 
-	if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
-		dev_err(&interface->dev, "Not our interface\n");
-		return -ENODEV;
-	}
 	/* Check if we need to switch to alt interfaces prior to port
 	 * configuration */
 	if (interface->num_altsetting > 1)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 06ee82f..27a00b0 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1197,6 +1197,37 @@
 
 /*-------------------------------------------------------------------------*/
 
+static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
+{
+	unsigned num_sgs, total_len = 0;
+	int i, s = 0;
+
+	num_sgs = skb_shinfo(skb)->nr_frags + 1;
+	if (num_sgs == 1)
+		return 0;
+
+	urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist), GFP_ATOMIC);
+	if (!urb->sg)
+		return -ENOMEM;
+
+	urb->num_sgs = num_sgs;
+	sg_init_table(urb->sg, urb->num_sgs);
+
+	sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));
+	total_len += skb_headlen(skb);
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		struct skb_frag_struct *f = &skb_shinfo(skb)->frags[i];
+
+		total_len += skb_frag_size(f);
+		sg_set_page(&urb->sg[i + s], f->page.p, f->size,
+				f->page_offset);
+	}
+	urb->transfer_buffer_length = total_len;
+
+	return 1;
+}
+
 netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
 				     struct net_device *net)
 {
@@ -1223,7 +1254,6 @@
 			goto drop;
 		}
 	}
-	length = skb->len;
 
 	if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) {
 		netif_dbg(dev, tx_err, dev->net, "no urb\n");
@@ -1233,10 +1263,14 @@
 	entry = (struct skb_data *) skb->cb;
 	entry->urb = urb;
 	entry->dev = dev;
-	entry->length = length;
 
 	usb_fill_bulk_urb (urb, dev->udev, dev->out,
 			skb->data, skb->len, tx_complete, skb);
+	if (dev->can_dma_sg) {
+		if (build_dma_sg(skb, urb) < 0)
+			goto drop;
+	}
+	entry->length = length = urb->transfer_buffer_length;
 
 	/* don't assume the hardware handles USB_ZERO_PACKET
 	 * NOTE:  strictly conforming cdc-ether devices should expect
@@ -1305,7 +1339,10 @@
 not_drop:
 		if (skb)
 			dev_kfree_skb_any (skb);
-		usb_free_urb (urb);
+		if (urb) {
+			kfree(urb->sg);
+			usb_free_urb(urb);
+		}
 	} else
 		netif_dbg(dev, tx_queued, dev->net,
 			  "> tx, len %d, type 0x%x\n", length, skb->protocol);
@@ -1356,6 +1393,7 @@
 			rx_process (dev, skb);
 			continue;
 		case tx_done:
+			kfree(entry->urb->sg);
 		case rx_cleanup:
 			usb_free_urb (entry->urb);
 			dev_kfree_skb (skb);
@@ -1689,6 +1727,7 @@
 			retval = usb_submit_urb(res, GFP_ATOMIC);
 			if (retval < 0) {
 				dev_kfree_skb_any(skb);
+				kfree(res->sg);
 				usb_free_urb(res);
 				usb_autopm_put_interface_async(dev->intf);
 			} else {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index e602c95..c028df7 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -448,6 +448,7 @@
 	struct ieee80211_conf *cur_conf = &priv->hw->conf;
 	bool txok;
 	int slot;
+	int hdrlen, padsize;
 
 	slot = strip_drv_header(priv, skb);
 	if (slot < 0) {
@@ -504,6 +505,15 @@
 
 	ath9k_htc_tx_clear_slot(priv, slot);
 
+	/* Remove padding before handing frame back to mac80211 */
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+	padsize = hdrlen & 3;
+	if (padsize && skb->len > hdrlen + padsize) {
+		memmove(skb->data + padsize, skb->data, hdrlen);
+		skb_pull(skb, padsize);
+	}
+
 	/* Send status to mac80211 */
 	ieee80211_tx_status(priv->hw, skb);
 }
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 16f8b20..026a2a0 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -802,7 +802,8 @@
 		IEEE80211_HW_PS_NULLFUNC_STACK |
 		IEEE80211_HW_SPECTRUM_MGMT |
 		IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-		IEEE80211_HW_SUPPORTS_RC_TABLE;
+		IEEE80211_HW_SUPPORTS_RC_TABLE |
+		IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
 
 	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
 		hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1737a3e..cb5a655 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -173,8 +173,7 @@
 {
 	ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
 
-	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) ||
-	    AR_SREV_9550(sc->sc_ah))
+	if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah))
 		ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
 				     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
 
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 4a33c6e..349fa22 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1860,7 +1860,8 @@
 		     IEEE80211_HW_PS_NULLFUNC_STACK |
 		     IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
 		     IEEE80211_HW_SUPPORTS_RC_TABLE |
-		     IEEE80211_HW_SIGNAL_DBM;
+		     IEEE80211_HW_SIGNAL_DBM |
+		     IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
 
 	if (!modparam_noht) {
 		/*
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index c37b9d6..0f9e9057 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -50,7 +50,7 @@
 		return -ENODEV;
 
 	drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
-	return PTR_RET(drvr->dbgfs_dir);
+	return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
 }
 
 void brcmf_debugfs_detach(struct brcmf_pub *drvr)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
index 9761deb..a5d4add 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
@@ -56,7 +56,7 @@
 
 	drvr->dbgfs_dir = debugfs_create_dir(
 		 dev_name(&drvr->wlc->hw->d11core->dev), root_folder);
-	return PTR_RET(drvr->dbgfs_dir);
+	return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
 }
 
 void brcms_debugfs_detach(struct brcms_pub *drvr)
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index ac07473..e509030 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -523,9 +523,9 @@
 
 	data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
 
-	memcpy(extra, &addr, sizeof(struct sockaddr) * data->length);
+	memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
 	data->flags = 1; /* has quality information */
-	memcpy(extra + sizeof(struct sockaddr) * data->length, &qual,
+	memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
 	       sizeof(struct iw_quality) * data->length);
 
 	kfree(addr);
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index f2ed62e..7acf5ee 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4464,9 +4464,9 @@
 			set_bit(S_RFKILL, &il->status);
 		} else {
 			clear_bit(S_RFKILL, &il->status);
-			wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
 			il_force_reset(il, true);
 		}
+		wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
 
 		handled |= CSR_INT_BIT_RF_KILL;
 	}
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 822f1a0..3193872 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -1068,7 +1068,10 @@
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+	if (!test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+		return;
+
+	if (ctx->vif)
 		ieee80211_chswitch_done(ctx->vif, is_success);
 }
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index a70c7b9..ff8cc75 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -97,8 +97,6 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS		(0x00000800)
 
-#define APMG_RTC_INT_STT_RFKILL		(0x10000000)
-
 /* Device system time */
 #define DEVICE_SYSTEM_TIME_REG 0xA0206C
 
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index ad9bbca..7fd6fbf 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -138,6 +138,20 @@
 	schedule_work(&mvm->roc_done_wk);
 }
 
+static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
+					struct ieee80211_vif *vif,
+					const char *errmsg)
+{
+	if (vif->type != NL80211_IFTYPE_STATION)
+		return false;
+	if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
+		return false;
+	if (errmsg)
+		IWL_ERR(mvm, "%s\n", errmsg);
+	ieee80211_connection_loss(vif);
+	return true;
+}
+
 /*
  * Handles a FW notification for an event that is known to the driver.
  *
@@ -163,8 +177,13 @@
 	 * P2P Device discoveribility, while there are other higher priority
 	 * events in the system).
 	 */
-	WARN_ONCE(!le32_to_cpu(notif->status),
-		  "Failed to schedule time event\n");
+	if (WARN_ONCE(!le32_to_cpu(notif->status),
+		      "Failed to schedule time event\n")) {
+		if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) {
+			iwl_mvm_te_clear_data(mvm, te_data);
+			return;
+		}
+	}
 
 	if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) {
 		IWL_DEBUG_TE(mvm,
@@ -180,14 +199,8 @@
 		 * By now, we should have finished association
 		 * and know the dtim period.
 		 */
-		if (te_data->vif->type == NL80211_IFTYPE_STATION &&
-		    (!te_data->vif->bss_conf.assoc ||
-		     !te_data->vif->bss_conf.dtim_period)) {
-			IWL_ERR(mvm,
-				"No assocation and the time event is over already...\n");
-			ieee80211_connection_loss(te_data->vif);
-		}
-
+		iwl_mvm_te_check_disconnect(mvm, te_data->vif,
+			"No assocation and the time event is over already...");
 		iwl_mvm_te_clear_data(mvm, te_data);
 	} else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
 		te_data->running = true;
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index f600e68..fd848cd 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -888,14 +888,6 @@
 
 		iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 		if (hw_rfkill) {
-			/*
-			 * Clear the interrupt in APMG if the NIC is going down.
-			 * Note that when the NIC exits RFkill (else branch), we
-			 * can't access prph and the NIC will be reset in
-			 * start_hw anyway.
-			 */
-			iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
-				       APMG_RTC_INT_STT_RFKILL);
 			set_bit(STATUS_RFKILL, &trans_pcie->status);
 			if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
 					       &trans_pcie->status))
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 96cfcdd..390e2f0 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -1502,16 +1502,16 @@
 	spin_lock_init(&trans_pcie->reg_lock);
 	init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
-	/* W/A - seems to solve weird behavior. We need to remove this if we
-	 * don't want to stay in L1 all the time. This wastes a lot of power */
-	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
-			       PCIE_LINK_STATE_CLKPM);
-
 	if (pci_enable_device(pdev)) {
 		err = -ENODEV;
 		goto out_no_pci;
 	}
 
+	/* W/A - seems to solve weird behavior. We need to remove this if we
+	 * don't want to stay in L1 all the time. This wastes a lot of power */
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
+			       PCIE_LINK_STATE_CLKPM);
+
 	pci_set_master(pdev);
 
 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 1f80ea5..1b41c8e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -6133,7 +6133,8 @@
 	    IEEE80211_HW_SUPPORTS_PS |
 	    IEEE80211_HW_PS_NULLFUNC_STACK |
 	    IEEE80211_HW_AMPDU_AGGREGATION |
-	    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+	    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+	    IEEE80211_HW_SUPPORTS_HT_CCK_RATES;
 
 	/*
 	 * Don't set IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING for USB devices
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4941f20..b8ba1f9 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -98,10 +98,12 @@
 		goto exit;
 
 	err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
-	    USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT);
+	    USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT);
 	if (err < 0)
 		goto exit;
 
+	memcpy(&ret, buf, sizeof(ret));
+
 	if (ret & 0x80) {
 		err = -EIO;
 		goto exit;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 5c54279..e486e41 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -18,6 +18,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 #include <linux/ctype.h>
+#include <linux/cpu.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/spinlock.h>
@@ -32,6 +33,7 @@
 EXPORT_SYMBOL(of_allnodes);
 struct device_node *of_chosen;
 struct device_node *of_aliases;
+static struct device_node *of_stdout;
 
 DEFINE_MUTEX(of_aliases_mutex);
 
@@ -230,6 +232,100 @@
 }
 EXPORT_SYMBOL(of_get_property);
 
+/*
+ * arch_match_cpu_phys_id - Match the given logical CPU and physical id
+ *
+ * @cpu: logical cpu index of a core/thread
+ * @phys_id: physical identifier of a core/thread
+ *
+ * CPU logical to physical index mapping is architecture specific.
+ * However this __weak function provides a default match of physical
+ * id to logical cpu index. phys_id provided here is usually values read
+ * from the device tree which must match the hardware internal registers.
+ *
+ * Returns true if the physical identifier and the logical cpu index
+ * correspond to the same core/thread, false otherwise.
+ */
+bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+	return (u32)phys_id == cpu;
+}
+
+/**
+ * Checks if the given "prop_name" property holds the physical id of the
+ * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not
+ * NULL, local thread number within the core is returned in it.
+ */
+static bool __of_find_n_match_cpu_property(struct device_node *cpun,
+			const char *prop_name, int cpu, unsigned int *thread)
+{
+	const __be32 *cell;
+	int ac, prop_len, tid;
+	u64 hwid;
+
+	ac = of_n_addr_cells(cpun);
+	cell = of_get_property(cpun, prop_name, &prop_len);
+	if (!cell)
+		return false;
+	prop_len /= sizeof(*cell);
+	for (tid = 0; tid < prop_len; tid++) {
+		hwid = of_read_number(cell, ac);
+		if (arch_match_cpu_phys_id(cpu, hwid)) {
+			if (thread)
+				*thread = tid;
+			return true;
+		}
+		cell += ac;
+	}
+	return false;
+}
+
+/**
+ * of_get_cpu_node - Get device node associated with the given logical CPU
+ *
+ * @cpu: CPU number(logical index) for which device node is required
+ * @thread: if not NULL, local thread number within the physical core is
+ *          returned
+ *
+ * The main purpose of this function is to retrieve the device node for the
+ * given logical CPU index. It should be used to initialize the of_node in
+ * cpu device. Once of_node in cpu device is populated, all the further
+ * references can use that instead.
+ *
+ * CPU logical to physical index mapping is architecture specific and is built
+ * before booting secondary cores. This function uses arch_match_cpu_phys_id
+ * which can be overridden by architecture specific implementation.
+ *
+ * Returns a node pointer for the logical cpu if found, else NULL.
+ */
+struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
+{
+	struct device_node *cpun, *cpus;
+
+	cpus = of_find_node_by_path("/cpus");
+	if (!cpus) {
+		pr_warn("Missing cpus node, bailing out\n");
+		return NULL;
+	}
+
+	for_each_child_of_node(cpus, cpun) {
+		if (of_node_cmp(cpun->type, "cpu"))
+			continue;
+		/* Check for non-standard "ibm,ppc-interrupt-server#s" property
+		 * for thread ids on PowerPC. If it doesn't exist fallback to
+		 * standard "reg" property.
+		 */
+		if (IS_ENABLED(CONFIG_PPC) &&
+			__of_find_n_match_cpu_property(cpun,
+				"ibm,ppc-interrupt-server#s", cpu, thread))
+			return cpun;
+		if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))
+			return cpun;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(of_get_cpu_node);
+
 /** Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
@@ -1595,6 +1691,15 @@
 	of_chosen = of_find_node_by_path("/chosen");
 	if (of_chosen == NULL)
 		of_chosen = of_find_node_by_path("/chosen@0");
+
+	if (of_chosen) {
+		const char *name;
+
+		name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+		if (name)
+			of_stdout = of_find_node_by_path(name);
+	}
+
 	of_aliases = of_find_node_by_path("/aliases");
 	if (!of_aliases)
 		return;
@@ -1703,3 +1808,19 @@
 	return curv;
 }
 EXPORT_SYMBOL_GPL(of_prop_next_string);
+
+/**
+ * of_device_is_stdout_path - check if a device node matches the
+ *                            linux,stdout-path property
+ *
+ * Check if this device node matches the linux,stdout-path property
+ * in the chosen node. return true if yes, false otherwise.
+ */
+int of_device_is_stdout_path(struct device_node *dn)
+{
+	if (!of_stdout)
+		return false;
+
+	return of_stdout == dn;
+}
+EXPORT_SYMBOL_GPL(of_device_is_stdout_path);
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 6bb7cf2..b10ba00 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -392,6 +392,8 @@
 	mem = (unsigned long)
 		dt_alloc(size + 4, __alignof__(struct device_node));
 
+	memset((void *)mem, 0, size);
+
 	((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
 
 	pr_debug("  unflattening %lx...\n", mem);
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 19f6f70..37e71ff 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1590,7 +1590,6 @@
 		lba_dump_res(&lba_dev->hba.lmmio_space, 2);
 #endif
 	}
-	pci_enable_bridges(lba_bus);
 
 	/*
 	** Once PCI register ops has walked the bus, access to config
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index dc82ef0..70694ce 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -37,7 +37,7 @@
 	tristate "PC-style hardware"
 	depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && !S390 && \
 		(!M68K || ISA) && !MN10300 && !AVR32 && !BLACKFIN && \
-		!XTENSA && !CRIS
+		!XTENSA && !CRIS && !H8300
 
 	---help---
 	  You should say Y here if you have a PC-style parallel port. All
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 09503b8..26ecdea 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -232,7 +232,6 @@
 	if (port->irq != PARPORT_IRQ_NONE)
 		free_irq(IRQ_AMIGA_CIAA_FLG, port);
 	parport_put_port(port);
-	platform_set_drvdata(pdev, NULL);
 	return 0;
 }
 
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 1cc2366..0857ca9 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -475,37 +475,33 @@
 	return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS;
 }
 
-static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
-{
-	return true;
-}
-
 static inline bool pcie_cap_has_lnkctl(const struct pci_dev *dev)
 {
 	int type = pci_pcie_type(dev);
 
-	return pcie_cap_version(dev) > 1 ||
+	return type == PCI_EXP_TYPE_ENDPOINT ||
+	       type == PCI_EXP_TYPE_LEG_END ||
 	       type == PCI_EXP_TYPE_ROOT_PORT ||
-	       type == PCI_EXP_TYPE_ENDPOINT ||
-	       type == PCI_EXP_TYPE_LEG_END;
+	       type == PCI_EXP_TYPE_UPSTREAM ||
+	       type == PCI_EXP_TYPE_DOWNSTREAM ||
+	       type == PCI_EXP_TYPE_PCI_BRIDGE ||
+	       type == PCI_EXP_TYPE_PCIE_BRIDGE;
 }
 
 static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev)
 {
 	int type = pci_pcie_type(dev);
 
-	return pcie_cap_version(dev) > 1 ||
-	       type == PCI_EXP_TYPE_ROOT_PORT ||
-	       (type == PCI_EXP_TYPE_DOWNSTREAM &&
-		pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT);
+	return (type == PCI_EXP_TYPE_ROOT_PORT ||
+		type == PCI_EXP_TYPE_DOWNSTREAM) &&
+	       pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT;
 }
 
 static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev)
 {
 	int type = pci_pcie_type(dev);
 
-	return pcie_cap_version(dev) > 1 ||
-	       type == PCI_EXP_TYPE_ROOT_PORT ||
+	return type == PCI_EXP_TYPE_ROOT_PORT ||
 	       type == PCI_EXP_TYPE_RC_EC;
 }
 
@@ -520,7 +516,7 @@
 	case PCI_EXP_DEVCAP:
 	case PCI_EXP_DEVCTL:
 	case PCI_EXP_DEVSTA:
-		return pcie_cap_has_devctl(dev);
+		return true;
 	case PCI_EXP_LNKCAP:
 	case PCI_EXP_LNKCTL:
 	case PCI_EXP_LNKSTA:
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index b1ff02a..fc1b740 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -216,24 +216,6 @@
 	}
 }
 
-void pci_enable_bridges(struct pci_bus *bus)
-{
-	struct pci_dev *dev;
-	int retval;
-
-	list_for_each_entry(dev, &bus->devices, bus_list) {
-		if (dev->subordinate) {
-			if (!pci_is_enabled(dev)) {
-				retval = pci_enable_device(dev);
-				if (retval)
-					dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", retval);
-				pci_set_master(dev);
-			}
-			pci_enable_bridges(dev->subordinate);
-		}
-	}
-}
-
 /** pci_walk_bus - walk devices on/under bus, calling callback.
  *  @top      bus whose devices should be walked
  *  @cb       callback to be called for each device found
@@ -301,4 +283,3 @@
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL(pci_bus_add_devices);
-EXPORT_SYMBOL(pci_enable_bridges);
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 1184ff6..e5ba4eb 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -4,6 +4,7 @@
 config PCI_MVEBU
 	bool "Marvell EBU PCIe controller"
 	depends on ARCH_MVEBU || ARCH_KIRKWOOD
+	depends on OF
 
 config PCIE_DW
 	bool
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 086d850..ab79ccb 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -1,2 +1,3 @@
-obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
+obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
new file mode 100644
index 0000000..94e096b
--- /dev/null
+++ b/drivers/pci/host/pci-exynos.c
@@ -0,0 +1,552 @@
+/*
+ * PCIe host controller driver for Samsung EXYNOS SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Jingoo Han <jg1.han@samsung.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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+#define to_exynos_pcie(x)	container_of(x, struct exynos_pcie, pp)
+
+struct exynos_pcie {
+	void __iomem		*elbi_base;
+	void __iomem		*phy_base;
+	void __iomem		*block_base;
+	int			reset_gpio;
+	struct clk		*clk;
+	struct clk		*bus_clk;
+	struct pcie_port	pp;
+};
+
+/* PCIe ELBI registers */
+#define PCIE_IRQ_PULSE			0x000
+#define IRQ_INTA_ASSERT			(0x1 << 0)
+#define IRQ_INTB_ASSERT			(0x1 << 2)
+#define IRQ_INTC_ASSERT			(0x1 << 4)
+#define IRQ_INTD_ASSERT			(0x1 << 6)
+#define PCIE_IRQ_LEVEL			0x004
+#define PCIE_IRQ_SPECIAL		0x008
+#define PCIE_IRQ_EN_PULSE		0x00c
+#define PCIE_IRQ_EN_LEVEL		0x010
+#define PCIE_IRQ_EN_SPECIAL		0x014
+#define PCIE_PWR_RESET			0x018
+#define PCIE_CORE_RESET			0x01c
+#define PCIE_CORE_RESET_ENABLE		(0x1 << 0)
+#define PCIE_STICKY_RESET		0x020
+#define PCIE_NONSTICKY_RESET		0x024
+#define PCIE_APP_INIT_RESET		0x028
+#define PCIE_APP_LTSSM_ENABLE		0x02c
+#define PCIE_ELBI_RDLH_LINKUP		0x064
+#define PCIE_ELBI_LTSSM_ENABLE		0x1
+#define PCIE_ELBI_SLV_AWMISC		0x11c
+#define PCIE_ELBI_SLV_ARMISC		0x120
+#define PCIE_ELBI_SLV_DBI_ENABLE	(0x1 << 21)
+
+/* PCIe Purple registers */
+#define PCIE_PHY_GLOBAL_RESET		0x000
+#define PCIE_PHY_COMMON_RESET		0x004
+#define PCIE_PHY_CMN_REG		0x008
+#define PCIE_PHY_MAC_RESET		0x00c
+#define PCIE_PHY_PLL_LOCKED		0x010
+#define PCIE_PHY_TRSVREG_RESET		0x020
+#define PCIE_PHY_TRSV_RESET		0x024
+
+/* PCIe PHY registers */
+#define PCIE_PHY_IMPEDANCE		0x004
+#define PCIE_PHY_PLL_DIV_0		0x008
+#define PCIE_PHY_PLL_BIAS		0x00c
+#define PCIE_PHY_DCC_FEEDBACK		0x014
+#define PCIE_PHY_PLL_DIV_1		0x05c
+#define PCIE_PHY_TRSV0_EMP_LVL		0x084
+#define PCIE_PHY_TRSV0_DRV_LVL		0x088
+#define PCIE_PHY_TRSV0_RXCDR		0x0ac
+#define PCIE_PHY_TRSV0_LVCC		0x0dc
+#define PCIE_PHY_TRSV1_EMP_LVL		0x144
+#define PCIE_PHY_TRSV1_RXCDR		0x16c
+#define PCIE_PHY_TRSV1_LVCC		0x19c
+#define PCIE_PHY_TRSV2_EMP_LVL		0x204
+#define PCIE_PHY_TRSV2_RXCDR		0x22c
+#define PCIE_PHY_TRSV2_LVCC		0x25c
+#define PCIE_PHY_TRSV3_EMP_LVL		0x2c4
+#define PCIE_PHY_TRSV3_RXCDR		0x2ec
+#define PCIE_PHY_TRSV3_LVCC		0x31c
+
+static inline void exynos_elb_writel(struct exynos_pcie *pcie, u32 val, u32 reg)
+{
+	writel(val, pcie->elbi_base + reg);
+}
+
+static inline u32 exynos_elb_readl(struct exynos_pcie *pcie, u32 reg)
+{
+	return readl(pcie->elbi_base + reg);
+}
+
+static inline void exynos_phy_writel(struct exynos_pcie *pcie, u32 val, u32 reg)
+{
+	writel(val, pcie->phy_base + reg);
+}
+
+static inline u32 exynos_phy_readl(struct exynos_pcie *pcie, u32 reg)
+{
+	return readl(pcie->phy_base + reg);
+}
+
+static inline void exynos_blk_writel(struct exynos_pcie *pcie, u32 val, u32 reg)
+{
+	writel(val, pcie->block_base + reg);
+}
+
+static inline u32 exynos_blk_readl(struct exynos_pcie *pcie, u32 reg)
+{
+	return readl(pcie->block_base + reg);
+}
+
+static void exynos_pcie_sideband_dbi_w_mode(struct pcie_port *pp, bool on)
+{
+	u32 val;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	if (on) {
+		val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_AWMISC);
+		val |= PCIE_ELBI_SLV_DBI_ENABLE;
+		exynos_elb_writel(exynos_pcie, val, PCIE_ELBI_SLV_AWMISC);
+	} else {
+		val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_AWMISC);
+		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+		exynos_elb_writel(exynos_pcie, val, PCIE_ELBI_SLV_AWMISC);
+	}
+}
+
+static void exynos_pcie_sideband_dbi_r_mode(struct pcie_port *pp, bool on)
+{
+	u32 val;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	if (on) {
+		val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_ARMISC);
+		val |= PCIE_ELBI_SLV_DBI_ENABLE;
+		exynos_elb_writel(exynos_pcie, val, PCIE_ELBI_SLV_ARMISC);
+	} else {
+		val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_SLV_ARMISC);
+		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+		exynos_elb_writel(exynos_pcie, val, PCIE_ELBI_SLV_ARMISC);
+	}
+}
+
+static void exynos_pcie_assert_core_reset(struct pcie_port *pp)
+{
+	u32 val;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	val = exynos_elb_readl(exynos_pcie, PCIE_CORE_RESET);
+	val &= ~PCIE_CORE_RESET_ENABLE;
+	exynos_elb_writel(exynos_pcie, val, PCIE_CORE_RESET);
+	exynos_elb_writel(exynos_pcie, 0, PCIE_PWR_RESET);
+	exynos_elb_writel(exynos_pcie, 0, PCIE_STICKY_RESET);
+	exynos_elb_writel(exynos_pcie, 0, PCIE_NONSTICKY_RESET);
+}
+
+static void exynos_pcie_deassert_core_reset(struct pcie_port *pp)
+{
+	u32 val;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	val = exynos_elb_readl(exynos_pcie, PCIE_CORE_RESET);
+	val |= PCIE_CORE_RESET_ENABLE;
+
+	exynos_elb_writel(exynos_pcie, val, PCIE_CORE_RESET);
+	exynos_elb_writel(exynos_pcie, 1, PCIE_STICKY_RESET);
+	exynos_elb_writel(exynos_pcie, 1, PCIE_NONSTICKY_RESET);
+	exynos_elb_writel(exynos_pcie, 1, PCIE_APP_INIT_RESET);
+	exynos_elb_writel(exynos_pcie, 0, PCIE_APP_INIT_RESET);
+	exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_MAC_RESET);
+}
+
+static void exynos_pcie_assert_phy_reset(struct pcie_port *pp)
+{
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_MAC_RESET);
+	exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_GLOBAL_RESET);
+}
+
+static void exynos_pcie_deassert_phy_reset(struct pcie_port *pp)
+{
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_GLOBAL_RESET);
+	exynos_elb_writel(exynos_pcie, 1, PCIE_PWR_RESET);
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_COMMON_RESET);
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_CMN_REG);
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_TRSVREG_RESET);
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_TRSV_RESET);
+}
+
+static void exynos_pcie_init_phy(struct pcie_port *pp)
+{
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	/* DCC feedback control off */
+	exynos_phy_writel(exynos_pcie, 0x29, PCIE_PHY_DCC_FEEDBACK);
+
+	/* set TX/RX impedance */
+	exynos_phy_writel(exynos_pcie, 0xd5, PCIE_PHY_IMPEDANCE);
+
+	/* set 50Mhz PHY clock */
+	exynos_phy_writel(exynos_pcie, 0x14, PCIE_PHY_PLL_DIV_0);
+	exynos_phy_writel(exynos_pcie, 0x12, PCIE_PHY_PLL_DIV_1);
+
+	/* set TX Differential output for lane 0 */
+	exynos_phy_writel(exynos_pcie, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
+
+	/* set TX Pre-emphasis Level Control for lane 0 to minimum */
+	exynos_phy_writel(exynos_pcie, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
+
+	/* set RX clock and data recovery bandwidth */
+	exynos_phy_writel(exynos_pcie, 0xe7, PCIE_PHY_PLL_BIAS);
+	exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV0_RXCDR);
+	exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV1_RXCDR);
+	exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV2_RXCDR);
+	exynos_phy_writel(exynos_pcie, 0x82, PCIE_PHY_TRSV3_RXCDR);
+
+	/* change TX Pre-emphasis Level Control for lanes */
+	exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
+	exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
+	exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
+	exynos_phy_writel(exynos_pcie, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
+
+	/* set LVCC */
+	exynos_phy_writel(exynos_pcie, 0x20, PCIE_PHY_TRSV0_LVCC);
+	exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV1_LVCC);
+	exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV2_LVCC);
+	exynos_phy_writel(exynos_pcie, 0xa0, PCIE_PHY_TRSV3_LVCC);
+}
+
+static void exynos_pcie_assert_reset(struct pcie_port *pp)
+{
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	if (exynos_pcie->reset_gpio >= 0)
+		devm_gpio_request_one(pp->dev, exynos_pcie->reset_gpio,
+				GPIOF_OUT_INIT_HIGH, "RESET");
+	return;
+}
+
+static int exynos_pcie_establish_link(struct pcie_port *pp)
+{
+	u32 val;
+	int count = 0;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	if (dw_pcie_link_up(pp)) {
+		dev_err(pp->dev, "Link already up\n");
+		return 0;
+	}
+
+	/* assert reset signals */
+	exynos_pcie_assert_core_reset(pp);
+	exynos_pcie_assert_phy_reset(pp);
+
+	/* de-assert phy reset */
+	exynos_pcie_deassert_phy_reset(pp);
+
+	/* initialize phy */
+	exynos_pcie_init_phy(pp);
+
+	/* pulse for common reset */
+	exynos_blk_writel(exynos_pcie, 1, PCIE_PHY_COMMON_RESET);
+	udelay(500);
+	exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_COMMON_RESET);
+
+	/* de-assert core reset */
+	exynos_pcie_deassert_core_reset(pp);
+
+	/* setup root complex */
+	dw_pcie_setup_rc(pp);
+
+	/* assert reset signal */
+	exynos_pcie_assert_reset(pp);
+
+	/* assert LTSSM enable */
+	exynos_elb_writel(exynos_pcie, PCIE_ELBI_LTSSM_ENABLE,
+			  PCIE_APP_LTSSM_ENABLE);
+
+	/* check if the link is up or not */
+	while (!dw_pcie_link_up(pp)) {
+		mdelay(100);
+		count++;
+		if (count == 10) {
+			while (exynos_phy_readl(exynos_pcie,
+						PCIE_PHY_PLL_LOCKED) == 0) {
+				val = exynos_blk_readl(exynos_pcie,
+						       PCIE_PHY_PLL_LOCKED);
+				dev_info(pp->dev, "PLL Locked: 0x%x\n", val);
+			}
+			dev_err(pp->dev, "PCIe Link Fail\n");
+			return -EINVAL;
+		}
+	}
+
+	dev_info(pp->dev, "Link up\n");
+
+	return 0;
+}
+
+static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
+{
+	u32 val;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_PULSE);
+	exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_PULSE);
+	return;
+}
+
+static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp)
+{
+	u32 val;
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+
+	/* enable INTX interrupt */
+	val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
+		IRQ_INTC_ASSERT | IRQ_INTD_ASSERT,
+	exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_PULSE);
+	return;
+}
+
+static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
+{
+	struct pcie_port *pp = arg;
+
+	exynos_pcie_clear_irq_pulse(pp);
+	return IRQ_HANDLED;
+}
+
+static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
+{
+	exynos_pcie_enable_irq_pulse(pp);
+	return;
+}
+
+static inline void exynos_pcie_readl_rc(struct pcie_port *pp,
+					void __iomem *dbi_base, u32 *val)
+{
+	exynos_pcie_sideband_dbi_r_mode(pp, true);
+	*val = readl(dbi_base);
+	exynos_pcie_sideband_dbi_r_mode(pp, false);
+	return;
+}
+
+static inline void exynos_pcie_writel_rc(struct pcie_port *pp,
+					u32 val, void __iomem *dbi_base)
+{
+	exynos_pcie_sideband_dbi_w_mode(pp, true);
+	writel(val, dbi_base);
+	exynos_pcie_sideband_dbi_w_mode(pp, false);
+	return;
+}
+
+static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+				u32 *val)
+{
+	int ret;
+
+	exynos_pcie_sideband_dbi_r_mode(pp, true);
+	ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
+	exynos_pcie_sideband_dbi_r_mode(pp, false);
+	return ret;
+}
+
+static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
+				u32 val)
+{
+	int ret;
+
+	exynos_pcie_sideband_dbi_w_mode(pp, true);
+	ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, val);
+	exynos_pcie_sideband_dbi_w_mode(pp, false);
+	return ret;
+}
+
+static int exynos_pcie_link_up(struct pcie_port *pp)
+{
+	struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
+	u32 val = exynos_elb_readl(exynos_pcie, PCIE_ELBI_RDLH_LINKUP);
+
+	if (val == PCIE_ELBI_LTSSM_ENABLE)
+		return 1;
+
+	return 0;
+}
+
+static void exynos_pcie_host_init(struct pcie_port *pp)
+{
+	exynos_pcie_establish_link(pp);
+	exynos_pcie_enable_interrupts(pp);
+}
+
+static struct pcie_host_ops exynos_pcie_host_ops = {
+	.readl_rc = exynos_pcie_readl_rc,
+	.writel_rc = exynos_pcie_writel_rc,
+	.rd_own_conf = exynos_pcie_rd_own_conf,
+	.wr_own_conf = exynos_pcie_wr_own_conf,
+	.link_up = exynos_pcie_link_up,
+	.host_init = exynos_pcie_host_init,
+};
+
+static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
+{
+	int ret;
+
+	pp->irq = platform_get_irq(pdev, 1);
+	if (!pp->irq) {
+		dev_err(&pdev->dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+	ret = devm_request_irq(&pdev->dev, pp->irq, exynos_pcie_irq_handler,
+				IRQF_SHARED, "exynos-pcie", pp);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		return ret;
+	}
+
+	pp->root_bus_nr = -1;
+	pp->ops = &exynos_pcie_host_ops;
+
+	spin_lock_init(&pp->conf_lock);
+	ret = dw_pcie_host_init(pp);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __init exynos_pcie_probe(struct platform_device *pdev)
+{
+	struct exynos_pcie *exynos_pcie;
+	struct pcie_port *pp;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *elbi_base;
+	struct resource *phy_base;
+	struct resource *block_base;
+	int ret;
+
+	exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie),
+				GFP_KERNEL);
+	if (!exynos_pcie) {
+		dev_err(&pdev->dev, "no memory for exynos pcie\n");
+		return -ENOMEM;
+	}
+
+	pp = &exynos_pcie->pp;
+
+	pp->dev = &pdev->dev;
+
+	exynos_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
+
+	exynos_pcie->clk = devm_clk_get(&pdev->dev, "pcie");
+	if (IS_ERR(exynos_pcie->clk)) {
+		dev_err(&pdev->dev, "Failed to get pcie rc clock\n");
+		return PTR_ERR(exynos_pcie->clk);
+	}
+	ret = clk_prepare_enable(exynos_pcie->clk);
+	if (ret)
+		return ret;
+
+	exynos_pcie->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
+	if (IS_ERR(exynos_pcie->bus_clk)) {
+		dev_err(&pdev->dev, "Failed to get pcie bus clock\n");
+		ret = PTR_ERR(exynos_pcie->bus_clk);
+		goto fail_clk;
+	}
+	ret = clk_prepare_enable(exynos_pcie->bus_clk);
+	if (ret)
+		goto fail_clk;
+
+	elbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	exynos_pcie->elbi_base = devm_ioremap_resource(&pdev->dev, elbi_base);
+	if (IS_ERR(exynos_pcie->elbi_base))
+		return PTR_ERR(exynos_pcie->elbi_base);
+
+	phy_base = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	exynos_pcie->phy_base = devm_ioremap_resource(&pdev->dev, phy_base);
+	if (IS_ERR(exynos_pcie->phy_base))
+		return PTR_ERR(exynos_pcie->phy_base);
+
+	block_base = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	exynos_pcie->block_base = devm_ioremap_resource(&pdev->dev, block_base);
+	if (IS_ERR(exynos_pcie->block_base))
+		return PTR_ERR(exynos_pcie->block_base);
+
+	ret = add_pcie_port(pp, pdev);
+	if (ret < 0)
+		goto fail_bus_clk;
+
+	platform_set_drvdata(pdev, exynos_pcie);
+	return 0;
+
+fail_bus_clk:
+	clk_disable_unprepare(exynos_pcie->bus_clk);
+fail_clk:
+	clk_disable_unprepare(exynos_pcie->clk);
+	return ret;
+}
+
+static int __exit exynos_pcie_remove(struct platform_device *pdev)
+{
+	struct exynos_pcie *exynos_pcie = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(exynos_pcie->bus_clk);
+	clk_disable_unprepare(exynos_pcie->clk);
+
+	return 0;
+}
+
+static const struct of_device_id exynos_pcie_of_match[] = {
+	{ .compatible = "samsung,exynos5440-pcie", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
+
+static struct platform_driver exynos_pcie_driver = {
+	.remove		= __exit_p(exynos_pcie_remove),
+	.driver = {
+		.name	= "exynos-pcie",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(exynos_pcie_of_match),
+	},
+};
+
+/* Exynos PCIe driver does not allow module unload */
+
+static int __init pcie_init(void)
+{
+	return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
+}
+subsys_initcall(pcie_init);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("Samsung PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 7bf3926..ce1543a 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -725,9 +725,9 @@
 
 	ret = of_address_to_resource(np, 0, &regs);
 	if (ret)
-		return NULL;
+		return ERR_PTR(ret);
 
-	return devm_request_and_ioremap(&pdev->dev, &regs);
+	return devm_ioremap_resource(&pdev->dev, &regs);
 }
 
 static int __init mvebu_pcie_probe(struct platform_device *pdev)
@@ -817,9 +817,10 @@
 			continue;
 
 		port->base = mvebu_pcie_map_registers(pdev, child, port);
-		if (!port->base) {
+		if (IS_ERR(port->base)) {
 			dev_err(&pdev->dev, "PCIe%d.%d: cannot map registers\n",
 				port->port, port->lane);
+			port->base = NULL;
 			continue;
 		}
 
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 26bdbda..c10e9ac 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -1,5 +1,5 @@
 /*
- * PCIe host controller driver for Samsung EXYNOS SoCs
+ * Synopsys Designware PCIe host controller driver
  *
  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com
@@ -11,74 +11,28 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/list.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_gpio.h>
-#include <linux/of_pci.h>
 #include <linux/pci.h>
 #include <linux/pci_regs.h>
-#include <linux/platform_device.h>
-#include <linux/resource.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
 #include <linux/types.h>
 
-struct pcie_port_info {
-	u32		cfg0_size;
-	u32		cfg1_size;
-	u32		io_size;
-	u32		mem_size;
-	phys_addr_t	io_bus_addr;
-	phys_addr_t	mem_bus_addr;
-};
-
-struct pcie_port {
-	struct device		*dev;
-	u8			controller;
-	u8			root_bus_nr;
-	void __iomem		*dbi_base;
-	void __iomem		*elbi_base;
-	void __iomem		*phy_base;
-	void __iomem		*purple_base;
-	u64			cfg0_base;
-	void __iomem		*va_cfg0_base;
-	u64			cfg1_base;
-	void __iomem		*va_cfg1_base;
-	u64			io_base;
-	u64			mem_base;
-	spinlock_t		conf_lock;
-	struct resource		cfg;
-	struct resource		io;
-	struct resource		mem;
-	struct pcie_port_info	config;
-	struct clk		*clk;
-	struct clk		*bus_clk;
-	int			irq;
-	int			reset_gpio;
-};
-
-/*
- * Exynos PCIe IP consists of Synopsys specific part and Exynos
- * specific part. Only core block is a Synopsys designware part;
- * other parts are Exynos specific.
- */
+#include "pcie-designware.h"
 
 /* Synopsis specific PCIE configuration registers */
 #define PCIE_PORT_LINK_CONTROL		0x710
 #define PORT_LINK_MODE_MASK		(0x3f << 16)
+#define PORT_LINK_MODE_1_LANES		(0x1 << 16)
+#define PORT_LINK_MODE_2_LANES		(0x3 << 16)
 #define PORT_LINK_MODE_4_LANES		(0x7 << 16)
 
 #define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
 #define PORT_LOGIC_SPEED_CHANGE		(0x1 << 17)
 #define PORT_LOGIC_LINK_WIDTH_MASK	(0x1ff << 8)
-#define PORT_LOGIC_LINK_WIDTH_4_LANES	(0x7 << 8)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES	(0x1 << 8)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES	(0x2 << 8)
+#define PORT_LOGIC_LINK_WIDTH_4_LANES	(0x4 << 8)
 
 #define PCIE_MSI_ADDR_LO		0x820
 #define PCIE_MSI_ADDR_HI		0x824
@@ -108,69 +62,16 @@
 #define PCIE_ATU_FUNC(x)		(((x) & 0x7) << 16)
 #define PCIE_ATU_UPPER_TARGET		0x91C
 
-/* Exynos specific PCIE configuration registers */
+static struct hw_pci dw_pci;
 
-/* PCIe ELBI registers */
-#define PCIE_IRQ_PULSE			0x000
-#define IRQ_INTA_ASSERT			(0x1 << 0)
-#define IRQ_INTB_ASSERT			(0x1 << 2)
-#define IRQ_INTC_ASSERT			(0x1 << 4)
-#define IRQ_INTD_ASSERT			(0x1 << 6)
-#define PCIE_IRQ_LEVEL			0x004
-#define PCIE_IRQ_SPECIAL		0x008
-#define PCIE_IRQ_EN_PULSE		0x00c
-#define PCIE_IRQ_EN_LEVEL		0x010
-#define PCIE_IRQ_EN_SPECIAL		0x014
-#define PCIE_PWR_RESET			0x018
-#define PCIE_CORE_RESET			0x01c
-#define PCIE_CORE_RESET_ENABLE		(0x1 << 0)
-#define PCIE_STICKY_RESET		0x020
-#define PCIE_NONSTICKY_RESET		0x024
-#define PCIE_APP_INIT_RESET		0x028
-#define PCIE_APP_LTSSM_ENABLE		0x02c
-#define PCIE_ELBI_RDLH_LINKUP		0x064
-#define PCIE_ELBI_LTSSM_ENABLE		0x1
-#define PCIE_ELBI_SLV_AWMISC		0x11c
-#define PCIE_ELBI_SLV_ARMISC		0x120
-#define PCIE_ELBI_SLV_DBI_ENABLE	(0x1 << 21)
-
-/* PCIe Purple registers */
-#define PCIE_PHY_GLOBAL_RESET		0x000
-#define PCIE_PHY_COMMON_RESET		0x004
-#define PCIE_PHY_CMN_REG		0x008
-#define PCIE_PHY_MAC_RESET		0x00c
-#define PCIE_PHY_PLL_LOCKED		0x010
-#define PCIE_PHY_TRSVREG_RESET		0x020
-#define PCIE_PHY_TRSV_RESET		0x024
-
-/* PCIe PHY registers */
-#define PCIE_PHY_IMPEDANCE		0x004
-#define PCIE_PHY_PLL_DIV_0		0x008
-#define PCIE_PHY_PLL_BIAS		0x00c
-#define PCIE_PHY_DCC_FEEDBACK		0x014
-#define PCIE_PHY_PLL_DIV_1		0x05c
-#define PCIE_PHY_TRSV0_EMP_LVL		0x084
-#define PCIE_PHY_TRSV0_DRV_LVL		0x088
-#define PCIE_PHY_TRSV0_RXCDR		0x0ac
-#define PCIE_PHY_TRSV0_LVCC		0x0dc
-#define PCIE_PHY_TRSV1_EMP_LVL		0x144
-#define PCIE_PHY_TRSV1_RXCDR		0x16c
-#define PCIE_PHY_TRSV1_LVCC		0x19c
-#define PCIE_PHY_TRSV2_EMP_LVL		0x204
-#define PCIE_PHY_TRSV2_RXCDR		0x22c
-#define PCIE_PHY_TRSV2_LVCC		0x25c
-#define PCIE_PHY_TRSV3_EMP_LVL		0x2c4
-#define PCIE_PHY_TRSV3_RXCDR		0x2ec
-#define PCIE_PHY_TRSV3_LVCC		0x31c
-
-static struct hw_pci exynos_pci;
+unsigned long global_io_offset;
 
 static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
 {
 	return sys->private_data;
 }
 
-static inline int cfg_read(void *addr, int where, int size, u32 *val)
+int cfg_read(void __iomem *addr, int where, int size, u32 *val)
 {
 	*val = readl(addr);
 
@@ -184,7 +85,7 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static inline int cfg_write(void *addr, int where, int size, u32 val)
+int cfg_write(void __iomem *addr, int where, int size, u32 val)
 {
 	if (size == 4)
 		writel(val, addr);
@@ -198,708 +99,66 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static void exynos_pcie_sideband_dbi_w_mode(struct pcie_port *pp, bool on)
+static inline void dw_pcie_readl_rc(struct pcie_port *pp, u32 reg, u32 *val)
 {
-	u32 val;
-
-	if (on) {
-		val = readl(pp->elbi_base + PCIE_ELBI_SLV_AWMISC);
-		val |= PCIE_ELBI_SLV_DBI_ENABLE;
-		writel(val, pp->elbi_base + PCIE_ELBI_SLV_AWMISC);
-	} else {
-		val = readl(pp->elbi_base + PCIE_ELBI_SLV_AWMISC);
-		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
-		writel(val, pp->elbi_base + PCIE_ELBI_SLV_AWMISC);
-	}
+	if (pp->ops->readl_rc)
+		pp->ops->readl_rc(pp, pp->dbi_base + reg, val);
+	else
+		*val = readl(pp->dbi_base + reg);
 }
 
-static void exynos_pcie_sideband_dbi_r_mode(struct pcie_port *pp, bool on)
+static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
 {
-	u32 val;
-
-	if (on) {
-		val = readl(pp->elbi_base + PCIE_ELBI_SLV_ARMISC);
-		val |= PCIE_ELBI_SLV_DBI_ENABLE;
-		writel(val, pp->elbi_base + PCIE_ELBI_SLV_ARMISC);
-	} else {
-		val = readl(pp->elbi_base + PCIE_ELBI_SLV_ARMISC);
-		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
-		writel(val, pp->elbi_base + PCIE_ELBI_SLV_ARMISC);
-	}
+	if (pp->ops->writel_rc)
+		pp->ops->writel_rc(pp, val, pp->dbi_base + reg);
+	else
+		writel(val, pp->dbi_base + reg);
 }
 
-static inline void readl_rc(struct pcie_port *pp, void *dbi_base, u32 *val)
-{
-	exynos_pcie_sideband_dbi_r_mode(pp, true);
-	*val = readl(dbi_base);
-	exynos_pcie_sideband_dbi_r_mode(pp, false);
-	return;
-}
-
-static inline void writel_rc(struct pcie_port *pp, u32 val, void *dbi_base)
-{
-	exynos_pcie_sideband_dbi_w_mode(pp, true);
-	writel(val, dbi_base);
-	exynos_pcie_sideband_dbi_w_mode(pp, false);
-	return;
-}
-
-static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
+int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
 				u32 *val)
 {
 	int ret;
 
-	exynos_pcie_sideband_dbi_r_mode(pp, true);
-	ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
-	exynos_pcie_sideband_dbi_r_mode(pp, false);
+	if (pp->ops->rd_own_conf)
+		ret = pp->ops->rd_own_conf(pp, where, size, val);
+	else
+		ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
+
 	return ret;
 }
 
-static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
+int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
 				u32 val)
 {
 	int ret;
 
-	exynos_pcie_sideband_dbi_w_mode(pp, true);
-	ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, val);
-	exynos_pcie_sideband_dbi_w_mode(pp, false);
-	return ret;
-}
-
-static void exynos_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
-{
-	u32 val;
-	void __iomem *dbi_base = pp->dbi_base;
-
-	/* Program viewport 0 : OUTBOUND : CFG0 */
-	val = PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_VIEWPORT);
-	writel_rc(pp, pp->cfg0_base, dbi_base + PCIE_ATU_LOWER_BASE);
-	writel_rc(pp, (pp->cfg0_base >> 32), dbi_base + PCIE_ATU_UPPER_BASE);
-	writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1,
-			dbi_base + PCIE_ATU_LIMIT);
-	writel_rc(pp, busdev, dbi_base + PCIE_ATU_LOWER_TARGET);
-	writel_rc(pp, 0, dbi_base + PCIE_ATU_UPPER_TARGET);
-	writel_rc(pp, PCIE_ATU_TYPE_CFG0, dbi_base + PCIE_ATU_CR1);
-	val = PCIE_ATU_ENABLE;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_CR2);
-}
-
-static void exynos_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
-{
-	u32 val;
-	void __iomem *dbi_base = pp->dbi_base;
-
-	/* Program viewport 1 : OUTBOUND : CFG1 */
-	val = PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_VIEWPORT);
-	writel_rc(pp, PCIE_ATU_TYPE_CFG1, dbi_base + PCIE_ATU_CR1);
-	val = PCIE_ATU_ENABLE;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_CR2);
-	writel_rc(pp, pp->cfg1_base, dbi_base + PCIE_ATU_LOWER_BASE);
-	writel_rc(pp, (pp->cfg1_base >> 32), dbi_base + PCIE_ATU_UPPER_BASE);
-	writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1,
-			dbi_base + PCIE_ATU_LIMIT);
-	writel_rc(pp, busdev, dbi_base + PCIE_ATU_LOWER_TARGET);
-	writel_rc(pp, 0, dbi_base + PCIE_ATU_UPPER_TARGET);
-}
-
-static void exynos_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
-{
-	u32 val;
-	void __iomem *dbi_base = pp->dbi_base;
-
-	/* Program viewport 0 : OUTBOUND : MEM */
-	val = PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_VIEWPORT);
-	writel_rc(pp, PCIE_ATU_TYPE_MEM, dbi_base + PCIE_ATU_CR1);
-	val = PCIE_ATU_ENABLE;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_CR2);
-	writel_rc(pp, pp->mem_base, dbi_base + PCIE_ATU_LOWER_BASE);
-	writel_rc(pp, (pp->mem_base >> 32), dbi_base + PCIE_ATU_UPPER_BASE);
-	writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
-			dbi_base + PCIE_ATU_LIMIT);
-	writel_rc(pp, pp->config.mem_bus_addr,
-			dbi_base + PCIE_ATU_LOWER_TARGET);
-	writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
-			dbi_base + PCIE_ATU_UPPER_TARGET);
-}
-
-static void exynos_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
-{
-	u32 val;
-	void __iomem *dbi_base = pp->dbi_base;
-
-	/* Program viewport 1 : OUTBOUND : IO */
-	val = PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_VIEWPORT);
-	writel_rc(pp, PCIE_ATU_TYPE_IO, dbi_base + PCIE_ATU_CR1);
-	val = PCIE_ATU_ENABLE;
-	writel_rc(pp, val, dbi_base + PCIE_ATU_CR2);
-	writel_rc(pp, pp->io_base, dbi_base + PCIE_ATU_LOWER_BASE);
-	writel_rc(pp, (pp->io_base >> 32), dbi_base + PCIE_ATU_UPPER_BASE);
-	writel_rc(pp, pp->io_base + pp->config.io_size - 1,
-			dbi_base + PCIE_ATU_LIMIT);
-	writel_rc(pp, pp->config.io_bus_addr,
-			dbi_base + PCIE_ATU_LOWER_TARGET);
-	writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
-			dbi_base + PCIE_ATU_UPPER_TARGET);
-}
-
-static int exynos_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-		u32 devfn, int where, int size, u32 *val)
-{
-	int ret = PCIBIOS_SUCCESSFUL;
-	u32 address, busdev;
-
-	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
-		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-	address = where & ~0x3;
-
-	if (bus->parent->number == pp->root_bus_nr) {
-		exynos_pcie_prog_viewport_cfg0(pp, busdev);
-		ret = cfg_read(pp->va_cfg0_base + address, where, size, val);
-		exynos_pcie_prog_viewport_mem_outbound(pp);
-	} else {
-		exynos_pcie_prog_viewport_cfg1(pp, busdev);
-		ret = cfg_read(pp->va_cfg1_base + address, where, size, val);
-		exynos_pcie_prog_viewport_io_outbound(pp);
-	}
-
-	return ret;
-}
-
-static int exynos_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
-		u32 devfn, int where, int size, u32 val)
-{
-	int ret = PCIBIOS_SUCCESSFUL;
-	u32 address, busdev;
-
-	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
-		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
-	address = where & ~0x3;
-
-	if (bus->parent->number == pp->root_bus_nr) {
-		exynos_pcie_prog_viewport_cfg0(pp, busdev);
-		ret = cfg_write(pp->va_cfg0_base + address, where, size, val);
-		exynos_pcie_prog_viewport_mem_outbound(pp);
-	} else {
-		exynos_pcie_prog_viewport_cfg1(pp, busdev);
-		ret = cfg_write(pp->va_cfg1_base + address, where, size, val);
-		exynos_pcie_prog_viewport_io_outbound(pp);
-	}
-
-	return ret;
-}
-
-static unsigned long global_io_offset;
-
-static int exynos_pcie_setup(int nr, struct pci_sys_data *sys)
-{
-	struct pcie_port *pp;
-
-	pp = sys_to_pcie(sys);
-
-	if (!pp)
-		return 0;
-
-	if (global_io_offset < SZ_1M && pp->config.io_size > 0) {
-		sys->io_offset = global_io_offset - pp->config.io_bus_addr;
-		pci_ioremap_io(sys->io_offset, pp->io.start);
-		global_io_offset += SZ_64K;
-		pci_add_resource_offset(&sys->resources, &pp->io,
-					sys->io_offset);
-	}
-
-	sys->mem_offset = pp->mem.start - pp->config.mem_bus_addr;
-	pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset);
-
-	return 1;
-}
-
-static int exynos_pcie_link_up(struct pcie_port *pp)
-{
-	u32 val = readl(pp->elbi_base + PCIE_ELBI_RDLH_LINKUP);
-
-	if (val == PCIE_ELBI_LTSSM_ENABLE)
-		return 1;
-
-	return 0;
-}
-
-static int exynos_pcie_valid_config(struct pcie_port *pp,
-				struct pci_bus *bus, int dev)
-{
-	/* If there is no link, then there is no device */
-	if (bus->number != pp->root_bus_nr) {
-		if (!exynos_pcie_link_up(pp))
-			return 0;
-	}
-
-	/* access only one slot on each root port */
-	if (bus->number == pp->root_bus_nr && dev > 0)
-		return 0;
-
-	/*
-	 * do not read more than one device on the bus directly attached
-	 * to RC's (Virtual Bridge's) DS side.
-	 */
-	if (bus->primary == pp->root_bus_nr && dev > 0)
-		return 0;
-
-	return 1;
-}
-
-static int exynos_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
-			int size, u32 *val)
-{
-	struct pcie_port *pp = sys_to_pcie(bus->sysdata);
-	unsigned long flags;
-	int ret;
-
-	if (!pp) {
-		BUG();
-		return -EINVAL;
-	}
-
-	if (exynos_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
-		*val = 0xffffffff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
-	spin_lock_irqsave(&pp->conf_lock, flags);
-	if (bus->number != pp->root_bus_nr)
-		ret = exynos_pcie_rd_other_conf(pp, bus, devfn,
-						where, size, val);
+	if (pp->ops->wr_own_conf)
+		ret = pp->ops->wr_own_conf(pp, where, size, val);
 	else
-		ret = exynos_pcie_rd_own_conf(pp, where, size, val);
-	spin_unlock_irqrestore(&pp->conf_lock, flags);
+		ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size,
+				val);
 
 	return ret;
 }
 
-static int exynos_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
-			int where, int size, u32 val)
+int dw_pcie_link_up(struct pcie_port *pp)
 {
-	struct pcie_port *pp = sys_to_pcie(bus->sysdata);
-	unsigned long flags;
-	int ret;
-
-	if (!pp) {
-		BUG();
-		return -EINVAL;
-	}
-
-	if (exynos_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	spin_lock_irqsave(&pp->conf_lock, flags);
-	if (bus->number != pp->root_bus_nr)
-		ret = exynos_pcie_wr_other_conf(pp, bus, devfn,
-						where, size, val);
+	if (pp->ops->link_up)
+		return pp->ops->link_up(pp);
 	else
-		ret = exynos_pcie_wr_own_conf(pp, where, size, val);
-	spin_unlock_irqrestore(&pp->conf_lock, flags);
-
-	return ret;
-}
-
-static struct pci_ops exynos_pcie_ops = {
-	.read = exynos_pcie_rd_conf,
-	.write = exynos_pcie_wr_conf,
-};
-
-static struct pci_bus *exynos_pcie_scan_bus(int nr,
-					struct pci_sys_data *sys)
-{
-	struct pci_bus *bus;
-	struct pcie_port *pp = sys_to_pcie(sys);
-
-	if (pp) {
-		pp->root_bus_nr = sys->busnr;
-		bus = pci_scan_root_bus(NULL, sys->busnr, &exynos_pcie_ops,
-					sys, &sys->resources);
-	} else {
-		bus = NULL;
-		BUG();
-	}
-
-	return bus;
-}
-
-static int exynos_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-	struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
-
-	return pp->irq;
-}
-
-static struct hw_pci exynos_pci = {
-	.setup		= exynos_pcie_setup,
-	.scan		= exynos_pcie_scan_bus,
-	.map_irq	= exynos_pcie_map_irq,
-};
-
-static void exynos_pcie_setup_rc(struct pcie_port *pp)
-{
-	struct pcie_port_info *config = &pp->config;
-	void __iomem *dbi_base = pp->dbi_base;
-	u32 val;
-	u32 membase;
-	u32 memlimit;
-
-	/* set the number of lines as 4 */
-	readl_rc(pp, dbi_base + PCIE_PORT_LINK_CONTROL, &val);
-	val &= ~PORT_LINK_MODE_MASK;
-	val |= PORT_LINK_MODE_4_LANES;
-	writel_rc(pp, val, dbi_base + PCIE_PORT_LINK_CONTROL);
-
-	/* set link width speed control register */
-	readl_rc(pp, dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL, &val);
-	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
-	val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
-	writel_rc(pp, val, dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
-
-	/* setup RC BARs */
-	writel_rc(pp, 0x00000004, dbi_base + PCI_BASE_ADDRESS_0);
-	writel_rc(pp, 0x00000004, dbi_base + PCI_BASE_ADDRESS_1);
-
-	/* setup interrupt pins */
-	readl_rc(pp, dbi_base + PCI_INTERRUPT_LINE, &val);
-	val &= 0xffff00ff;
-	val |= 0x00000100;
-	writel_rc(pp, val, dbi_base + PCI_INTERRUPT_LINE);
-
-	/* setup bus numbers */
-	readl_rc(pp, dbi_base + PCI_PRIMARY_BUS, &val);
-	val &= 0xff000000;
-	val |= 0x00010100;
-	writel_rc(pp, val, dbi_base + PCI_PRIMARY_BUS);
-
-	/* setup memory base, memory limit */
-	membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
-	memlimit = (config->mem_size + (u32)pp->mem_base) & 0xfff00000;
-	val = memlimit | membase;
-	writel_rc(pp, val, dbi_base + PCI_MEMORY_BASE);
-
-	/* setup command register */
-	readl_rc(pp, dbi_base + PCI_COMMAND, &val);
-	val &= 0xffff0000;
-	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
-	writel_rc(pp, val, dbi_base + PCI_COMMAND);
-}
-
-static void exynos_pcie_assert_core_reset(struct pcie_port *pp)
-{
-	u32 val;
-	void __iomem *elbi_base = pp->elbi_base;
-
-	val = readl(elbi_base + PCIE_CORE_RESET);
-	val &= ~PCIE_CORE_RESET_ENABLE;
-	writel(val, elbi_base + PCIE_CORE_RESET);
-	writel(0, elbi_base + PCIE_PWR_RESET);
-	writel(0, elbi_base + PCIE_STICKY_RESET);
-	writel(0, elbi_base + PCIE_NONSTICKY_RESET);
-}
-
-static void exynos_pcie_deassert_core_reset(struct pcie_port *pp)
-{
-	u32 val;
-	void __iomem *elbi_base = pp->elbi_base;
-	void __iomem *purple_base = pp->purple_base;
-
-	val = readl(elbi_base + PCIE_CORE_RESET);
-	val |= PCIE_CORE_RESET_ENABLE;
-	writel(val, elbi_base + PCIE_CORE_RESET);
-	writel(1, elbi_base + PCIE_STICKY_RESET);
-	writel(1, elbi_base + PCIE_NONSTICKY_RESET);
-	writel(1, elbi_base + PCIE_APP_INIT_RESET);
-	writel(0, elbi_base + PCIE_APP_INIT_RESET);
-	writel(1, purple_base + PCIE_PHY_MAC_RESET);
-}
-
-static void exynos_pcie_assert_phy_reset(struct pcie_port *pp)
-{
-	void __iomem *purple_base = pp->purple_base;
-
-	writel(0, purple_base + PCIE_PHY_MAC_RESET);
-	writel(1, purple_base + PCIE_PHY_GLOBAL_RESET);
-}
-
-static void exynos_pcie_deassert_phy_reset(struct pcie_port *pp)
-{
-	void __iomem *elbi_base = pp->elbi_base;
-	void __iomem *purple_base = pp->purple_base;
-
-	writel(0, purple_base + PCIE_PHY_GLOBAL_RESET);
-	writel(1, elbi_base + PCIE_PWR_RESET);
-	writel(0, purple_base + PCIE_PHY_COMMON_RESET);
-	writel(0, purple_base + PCIE_PHY_CMN_REG);
-	writel(0, purple_base + PCIE_PHY_TRSVREG_RESET);
-	writel(0, purple_base + PCIE_PHY_TRSV_RESET);
-}
-
-static void exynos_pcie_init_phy(struct pcie_port *pp)
-{
-	void __iomem *phy_base = pp->phy_base;
-
-	/* DCC feedback control off */
-	writel(0x29, phy_base + PCIE_PHY_DCC_FEEDBACK);
-
-	/* set TX/RX impedance */
-	writel(0xd5, phy_base + PCIE_PHY_IMPEDANCE);
-
-	/* set 50Mhz PHY clock */
-	writel(0x14, phy_base + PCIE_PHY_PLL_DIV_0);
-	writel(0x12, phy_base + PCIE_PHY_PLL_DIV_1);
-
-	/* set TX Differential output for lane 0 */
-	writel(0x7f, phy_base + PCIE_PHY_TRSV0_DRV_LVL);
-
-	/* set TX Pre-emphasis Level Control for lane 0 to minimum */
-	writel(0x0, phy_base + PCIE_PHY_TRSV0_EMP_LVL);
-
-	/* set RX clock and data recovery bandwidth */
-	writel(0xe7, phy_base + PCIE_PHY_PLL_BIAS);
-	writel(0x82, phy_base + PCIE_PHY_TRSV0_RXCDR);
-	writel(0x82, phy_base + PCIE_PHY_TRSV1_RXCDR);
-	writel(0x82, phy_base + PCIE_PHY_TRSV2_RXCDR);
-	writel(0x82, phy_base + PCIE_PHY_TRSV3_RXCDR);
-
-	/* change TX Pre-emphasis Level Control for lanes */
-	writel(0x39, phy_base + PCIE_PHY_TRSV0_EMP_LVL);
-	writel(0x39, phy_base + PCIE_PHY_TRSV1_EMP_LVL);
-	writel(0x39, phy_base + PCIE_PHY_TRSV2_EMP_LVL);
-	writel(0x39, phy_base + PCIE_PHY_TRSV3_EMP_LVL);
-
-	/* set LVCC */
-	writel(0x20, phy_base + PCIE_PHY_TRSV0_LVCC);
-	writel(0xa0, phy_base + PCIE_PHY_TRSV1_LVCC);
-	writel(0xa0, phy_base + PCIE_PHY_TRSV2_LVCC);
-	writel(0xa0, phy_base + PCIE_PHY_TRSV3_LVCC);
-}
-
-static void exynos_pcie_assert_reset(struct pcie_port *pp)
-{
-	if (pp->reset_gpio >= 0)
-		devm_gpio_request_one(pp->dev, pp->reset_gpio,
-				GPIOF_OUT_INIT_HIGH, "RESET");
-	return;
-}
-
-static int exynos_pcie_establish_link(struct pcie_port *pp)
-{
-	u32 val;
-	int count = 0;
-	void __iomem *elbi_base = pp->elbi_base;
-	void __iomem *purple_base = pp->purple_base;
-	void __iomem *phy_base = pp->phy_base;
-
-	if (exynos_pcie_link_up(pp)) {
-		dev_err(pp->dev, "Link already up\n");
 		return 0;
-	}
-
-	/* assert reset signals */
-	exynos_pcie_assert_core_reset(pp);
-	exynos_pcie_assert_phy_reset(pp);
-
-	/* de-assert phy reset */
-	exynos_pcie_deassert_phy_reset(pp);
-
-	/* initialize phy */
-	exynos_pcie_init_phy(pp);
-
-	/* pulse for common reset */
-	writel(1, purple_base + PCIE_PHY_COMMON_RESET);
-	udelay(500);
-	writel(0, purple_base + PCIE_PHY_COMMON_RESET);
-
-	/* de-assert core reset */
-	exynos_pcie_deassert_core_reset(pp);
-
-	/* setup root complex */
-	exynos_pcie_setup_rc(pp);
-
-	/* assert reset signal */
-	exynos_pcie_assert_reset(pp);
-
-	/* assert LTSSM enable */
-	writel(PCIE_ELBI_LTSSM_ENABLE, elbi_base + PCIE_APP_LTSSM_ENABLE);
-
-	/* check if the link is up or not */
-	while (!exynos_pcie_link_up(pp)) {
-		mdelay(100);
-		count++;
-		if (count == 10) {
-			while (readl(phy_base + PCIE_PHY_PLL_LOCKED) == 0) {
-				val = readl(purple_base + PCIE_PHY_PLL_LOCKED);
-				dev_info(pp->dev, "PLL Locked: 0x%x\n", val);
-			}
-			dev_err(pp->dev, "PCIe Link Fail\n");
-			return -EINVAL;
-		}
-	}
-
-	dev_info(pp->dev, "Link up\n");
-
-	return 0;
 }
 
-static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
+int __init dw_pcie_host_init(struct pcie_port *pp)
 {
-	u32 val;
-	void __iomem *elbi_base = pp->elbi_base;
-
-	val = readl(elbi_base + PCIE_IRQ_PULSE);
-	writel(val, elbi_base + PCIE_IRQ_PULSE);
-	return;
-}
-
-static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp)
-{
-	u32 val;
-	void __iomem *elbi_base = pp->elbi_base;
-
-	/* enable INTX interrupt */
-	val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
-		IRQ_INTC_ASSERT | IRQ_INTD_ASSERT,
-	writel(val, elbi_base + PCIE_IRQ_EN_PULSE);
-	return;
-}
-
-static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
-{
-	struct pcie_port *pp = arg;
-
-	exynos_pcie_clear_irq_pulse(pp);
-	return IRQ_HANDLED;
-}
-
-static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
-{
-	exynos_pcie_enable_irq_pulse(pp);
-	return;
-}
-
-static void exynos_pcie_host_init(struct pcie_port *pp)
-{
-	struct pcie_port_info *config = &pp->config;
-	u32 val;
-
-	/* Keep first 64K for IO */
-	pp->cfg0_base = pp->cfg.start;
-	pp->cfg1_base = pp->cfg.start + config->cfg0_size;
-	pp->io_base = pp->io.start;
-	pp->mem_base = pp->mem.start;
-
-	/* enable link */
-	exynos_pcie_establish_link(pp);
-
-	exynos_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
-
-	/* program correct class for RC */
-	exynos_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
-
-	exynos_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
-	val |= PORT_LOGIC_SPEED_CHANGE;
-	exynos_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
-
-	exynos_pcie_enable_interrupts(pp);
-}
-
-static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
-{
-	struct resource *elbi_base;
-	struct resource *phy_base;
-	struct resource *purple_base;
-	int ret;
-
-	elbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!elbi_base) {
-		dev_err(&pdev->dev, "couldn't get elbi base resource\n");
-		return -EINVAL;
-	}
-	pp->elbi_base = devm_ioremap_resource(&pdev->dev, elbi_base);
-	if (IS_ERR(pp->elbi_base))
-		return PTR_ERR(pp->elbi_base);
-
-	phy_base = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!phy_base) {
-		dev_err(&pdev->dev, "couldn't get phy base resource\n");
-		return -EINVAL;
-	}
-	pp->phy_base = devm_ioremap_resource(&pdev->dev, phy_base);
-	if (IS_ERR(pp->phy_base))
-		return PTR_ERR(pp->phy_base);
-
-	purple_base = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	if (!purple_base) {
-		dev_err(&pdev->dev, "couldn't get purple base resource\n");
-		return -EINVAL;
-	}
-	pp->purple_base = devm_ioremap_resource(&pdev->dev, purple_base);
-	if (IS_ERR(pp->purple_base))
-		return PTR_ERR(pp->purple_base);
-
-	pp->irq = platform_get_irq(pdev, 1);
-	if (!pp->irq) {
-		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
-	}
-	ret = devm_request_irq(&pdev->dev, pp->irq, exynos_pcie_irq_handler,
-				IRQF_SHARED, "exynos-pcie", pp);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to request irq\n");
-		return ret;
-	}
-
-	pp->dbi_base = devm_ioremap(&pdev->dev, pp->cfg.start,
-				resource_size(&pp->cfg));
-	if (!pp->dbi_base) {
-		dev_err(&pdev->dev, "error with ioremap\n");
-		return -ENOMEM;
-	}
-
-	pp->root_bus_nr = -1;
-
-	spin_lock_init(&pp->conf_lock);
-	exynos_pcie_host_init(pp);
-	pp->va_cfg0_base = devm_ioremap(&pdev->dev, pp->cfg0_base,
-					pp->config.cfg0_size);
-	if (!pp->va_cfg0_base) {
-		dev_err(pp->dev, "error with ioremap in function\n");
-		return -ENOMEM;
-	}
-	pp->va_cfg1_base = devm_ioremap(&pdev->dev, pp->cfg1_base,
-					pp->config.cfg1_size);
-	if (!pp->va_cfg1_base) {
-		dev_err(pp->dev, "error with ioremap\n");
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static int __init exynos_pcie_probe(struct platform_device *pdev)
-{
-	struct pcie_port *pp;
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = pp->dev->of_node;
 	struct of_pci_range range;
 	struct of_pci_range_parser parser;
-	int ret;
-
-	pp = devm_kzalloc(&pdev->dev, sizeof(*pp), GFP_KERNEL);
-	if (!pp) {
-		dev_err(&pdev->dev, "no memory for pcie port\n");
-		return -ENOMEM;
-	}
-
-	pp->dev = &pdev->dev;
+	u32 val;
 
 	if (of_pci_range_parser_init(&parser, np)) {
-		dev_err(&pdev->dev, "missing ranges property\n");
+		dev_err(pp->dev, "missing ranges property\n");
 		return -EINVAL;
 	}
 
@@ -932,126 +191,375 @@
 		}
 	}
 
-	pp->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
-
-	pp->clk = devm_clk_get(&pdev->dev, "pcie");
-	if (IS_ERR(pp->clk)) {
-		dev_err(&pdev->dev, "Failed to get pcie rc clock\n");
-		return PTR_ERR(pp->clk);
+	if (!pp->dbi_base) {
+		pp->dbi_base = devm_ioremap(pp->dev, pp->cfg.start,
+					resource_size(&pp->cfg));
+		if (!pp->dbi_base) {
+			dev_err(pp->dev, "error with ioremap\n");
+			return -ENOMEM;
+		}
 	}
-	ret = clk_prepare_enable(pp->clk);
-	if (ret)
-		return ret;
 
-	pp->bus_clk = devm_clk_get(&pdev->dev, "pcie_bus");
-	if (IS_ERR(pp->bus_clk)) {
-		dev_err(&pdev->dev, "Failed to get pcie bus clock\n");
-		ret = PTR_ERR(pp->bus_clk);
-		goto fail_clk;
+	pp->cfg0_base = pp->cfg.start;
+	pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+	pp->io_base = pp->io.start;
+	pp->mem_base = pp->mem.start;
+
+	pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+					pp->config.cfg0_size);
+	if (!pp->va_cfg0_base) {
+		dev_err(pp->dev, "error with ioremap in function\n");
+		return -ENOMEM;
 	}
-	ret = clk_prepare_enable(pp->bus_clk);
-	if (ret)
-		goto fail_clk;
+	pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+					pp->config.cfg1_size);
+	if (!pp->va_cfg1_base) {
+		dev_err(pp->dev, "error with ioremap\n");
+		return -ENOMEM;
+	}
 
-	ret = add_pcie_port(pp, pdev);
-	if (ret < 0)
-		goto fail_bus_clk;
+	if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
+		dev_err(pp->dev, "Failed to parse the number of lanes\n");
+		return -EINVAL;
+	}
 
-	pp->controller = exynos_pci.nr_controllers;
-	exynos_pci.nr_controllers = 1;
-	exynos_pci.private_data = (void **)&pp;
+	if (pp->ops->host_init)
+		pp->ops->host_init(pp);
 
-	pci_common_init(&exynos_pci);
+	dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
+
+	/* program correct class for RC */
+	dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
+
+	dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
+	val |= PORT_LOGIC_SPEED_CHANGE;
+	dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
+
+	dw_pci.nr_controllers = 1;
+	dw_pci.private_data = (void **)&pp;
+
+	pci_common_init(&dw_pci);
 	pci_assign_unassigned_resources();
 #ifdef CONFIG_PCI_DOMAINS
-	exynos_pci.domain++;
+	dw_pci.domain++;
 #endif
 
-	platform_set_drvdata(pdev, pp);
 	return 0;
+}
 
-fail_bus_clk:
-	clk_disable_unprepare(pp->bus_clk);
-fail_clk:
-	clk_disable_unprepare(pp->clk);
+static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
+{
+	/* Program viewport 0 : OUTBOUND : CFG0 */
+	dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
+			  PCIE_ATU_VIEWPORT);
+	dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE);
+	dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE);
+	dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1,
+			  PCIE_ATU_LIMIT);
+	dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
+	dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
+	dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG0, PCIE_ATU_CR1);
+	dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+}
+
+static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
+{
+	/* Program viewport 1 : OUTBOUND : CFG1 */
+	dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
+			  PCIE_ATU_VIEWPORT);
+	dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
+	dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+	dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE);
+	dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE);
+	dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1,
+			  PCIE_ATU_LIMIT);
+	dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
+	dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
+}
+
+static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
+{
+	/* Program viewport 0 : OUTBOUND : MEM */
+	dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
+			  PCIE_ATU_VIEWPORT);
+	dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
+	dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+	dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE);
+	dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE);
+	dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
+			  PCIE_ATU_LIMIT);
+	dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
+	dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
+			  PCIE_ATU_UPPER_TARGET);
+}
+
+static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
+{
+	/* Program viewport 1 : OUTBOUND : IO */
+	dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
+			  PCIE_ATU_VIEWPORT);
+	dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
+	dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
+	dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE);
+	dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE);
+	dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1,
+			  PCIE_ATU_LIMIT);
+	dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
+	dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
+			  PCIE_ATU_UPPER_TARGET);
+}
+
+static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		u32 devfn, int where, int size, u32 *val)
+{
+	int ret = PCIBIOS_SUCCESSFUL;
+	u32 address, busdev;
+
+	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
+		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
+	address = where & ~0x3;
+
+	if (bus->parent->number == pp->root_bus_nr) {
+		dw_pcie_prog_viewport_cfg0(pp, busdev);
+		ret = cfg_read(pp->va_cfg0_base + address, where, size, val);
+		dw_pcie_prog_viewport_mem_outbound(pp);
+	} else {
+		dw_pcie_prog_viewport_cfg1(pp, busdev);
+		ret = cfg_read(pp->va_cfg1_base + address, where, size, val);
+		dw_pcie_prog_viewport_io_outbound(pp);
+	}
+
 	return ret;
 }
 
-static int __exit exynos_pcie_remove(struct platform_device *pdev)
+static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
+		u32 devfn, int where, int size, u32 val)
 {
-	struct pcie_port *pp = platform_get_drvdata(pdev);
+	int ret = PCIBIOS_SUCCESSFUL;
+	u32 address, busdev;
 
-	clk_disable_unprepare(pp->bus_clk);
-	clk_disable_unprepare(pp->clk);
+	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
+		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
+	address = where & ~0x3;
 
-	return 0;
+	if (bus->parent->number == pp->root_bus_nr) {
+		dw_pcie_prog_viewport_cfg0(pp, busdev);
+		ret = cfg_write(pp->va_cfg0_base + address, where, size, val);
+		dw_pcie_prog_viewport_mem_outbound(pp);
+	} else {
+		dw_pcie_prog_viewport_cfg1(pp, busdev);
+		ret = cfg_write(pp->va_cfg1_base + address, where, size, val);
+		dw_pcie_prog_viewport_io_outbound(pp);
+	}
+
+	return ret;
 }
 
-static const struct of_device_id exynos_pcie_of_match[] = {
-	{ .compatible = "samsung,exynos5440-pcie", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
 
-static struct platform_driver exynos_pcie_driver = {
-	.remove		= __exit_p(exynos_pcie_remove),
-	.driver = {
-		.name	= "exynos-pcie",
-		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(exynos_pcie_of_match),
-	},
-};
-
-static int exynos_pcie_abort(unsigned long addr, unsigned int fsr,
-			struct pt_regs *regs)
+static int dw_pcie_valid_config(struct pcie_port *pp,
+				struct pci_bus *bus, int dev)
 {
-	unsigned long pc = instruction_pointer(regs);
-	unsigned long instr = *(unsigned long *)pc;
+	/* If there is no link, then there is no device */
+	if (bus->number != pp->root_bus_nr) {
+		if (!dw_pcie_link_up(pp))
+			return 0;
+	}
 
-	WARN_ONCE(1, "pcie abort\n");
+	/* access only one slot on each root port */
+	if (bus->number == pp->root_bus_nr && dev > 0)
+		return 0;
 
 	/*
-	 * If the instruction being executed was a read,
-	 * make it look like it read all-ones.
+	 * do not read more than one device on the bus directly attached
+	 * to RC's (Virtual Bridge's) DS side.
 	 */
-	if ((instr & 0x0c100000) == 0x04100000) {
-		int reg = (instr >> 12) & 15;
-		unsigned long val;
-
-		if (instr & 0x00400000)
-			val = 255;
-		else
-			val = -1;
-
-		regs->uregs[reg] = val;
-		regs->ARM_pc += 4;
+	if (bus->primary == pp->root_bus_nr && dev > 0)
 		return 0;
-	}
-
-	if ((instr & 0x0e100090) == 0x00100090) {
-		int reg = (instr >> 12) & 15;
-
-		regs->uregs[reg] = -1;
-		regs->ARM_pc += 4;
-		return 0;
-	}
 
 	return 1;
 }
 
-/* Exynos PCIe driver does not allow module unload */
-
-static int __init pcie_init(void)
+static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+			int size, u32 *val)
 {
-	hook_fault_code(16 + 6, exynos_pcie_abort, SIGBUS, 0,
-			"imprecise external abort");
+	struct pcie_port *pp = sys_to_pcie(bus->sysdata);
+	unsigned long flags;
+	int ret;
 
-	platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
+	if (!pp) {
+		BUG();
+		return -EINVAL;
+	}
 
-	return 0;
+	if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	spin_lock_irqsave(&pp->conf_lock, flags);
+	if (bus->number != pp->root_bus_nr)
+		ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+						where, size, val);
+	else
+		ret = dw_pcie_rd_own_conf(pp, where, size, val);
+	spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+	return ret;
 }
-subsys_initcall(pcie_init);
+
+static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+			int where, int size, u32 val)
+{
+	struct pcie_port *pp = sys_to_pcie(bus->sysdata);
+	unsigned long flags;
+	int ret;
+
+	if (!pp) {
+		BUG();
+		return -EINVAL;
+	}
+
+	if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	spin_lock_irqsave(&pp->conf_lock, flags);
+	if (bus->number != pp->root_bus_nr)
+		ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+						where, size, val);
+	else
+		ret = dw_pcie_wr_own_conf(pp, where, size, val);
+	spin_unlock_irqrestore(&pp->conf_lock, flags);
+
+	return ret;
+}
+
+static struct pci_ops dw_pcie_ops = {
+	.read = dw_pcie_rd_conf,
+	.write = dw_pcie_wr_conf,
+};
+
+int dw_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct pcie_port *pp;
+
+	pp = sys_to_pcie(sys);
+
+	if (!pp)
+		return 0;
+
+	if (global_io_offset < SZ_1M && pp->config.io_size > 0) {
+		sys->io_offset = global_io_offset - pp->config.io_bus_addr;
+		pci_ioremap_io(sys->io_offset, pp->io.start);
+		global_io_offset += SZ_64K;
+		pci_add_resource_offset(&sys->resources, &pp->io,
+					sys->io_offset);
+	}
+
+	sys->mem_offset = pp->mem.start - pp->config.mem_bus_addr;
+	pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset);
+
+	return 1;
+}
+
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
+{
+	struct pci_bus *bus;
+	struct pcie_port *pp = sys_to_pcie(sys);
+
+	if (pp) {
+		pp->root_bus_nr = sys->busnr;
+		bus = pci_scan_root_bus(NULL, sys->busnr, &dw_pcie_ops,
+					sys, &sys->resources);
+	} else {
+		bus = NULL;
+		BUG();
+	}
+
+	return bus;
+}
+
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
+
+	return pp->irq;
+}
+
+static struct hw_pci dw_pci = {
+	.setup		= dw_pcie_setup,
+	.scan		= dw_pcie_scan_bus,
+	.map_irq	= dw_pcie_map_irq,
+};
+
+void dw_pcie_setup_rc(struct pcie_port *pp)
+{
+	struct pcie_port_info *config = &pp->config;
+	u32 val;
+	u32 membase;
+	u32 memlimit;
+
+	/* set the number of lines as 4 */
+	dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val);
+	val &= ~PORT_LINK_MODE_MASK;
+	switch (pp->lanes) {
+	case 1:
+		val |= PORT_LINK_MODE_1_LANES;
+		break;
+	case 2:
+		val |= PORT_LINK_MODE_2_LANES;
+		break;
+	case 4:
+		val |= PORT_LINK_MODE_4_LANES;
+		break;
+	}
+	dw_pcie_writel_rc(pp, val, PCIE_PORT_LINK_CONTROL);
+
+	/* set link width speed control register */
+	dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, &val);
+	val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+	switch (pp->lanes) {
+	case 1:
+		val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+		break;
+	case 2:
+		val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
+		break;
+	case 4:
+		val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
+		break;
+	}
+	dw_pcie_writel_rc(pp, val, PCIE_LINK_WIDTH_SPEED_CONTROL);
+
+	/* setup RC BARs */
+	dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_0);
+	dw_pcie_writel_rc(pp, 0x00000004, PCI_BASE_ADDRESS_1);
+
+	/* setup interrupt pins */
+	dw_pcie_readl_rc(pp, PCI_INTERRUPT_LINE, &val);
+	val &= 0xffff00ff;
+	val |= 0x00000100;
+	dw_pcie_writel_rc(pp, val, PCI_INTERRUPT_LINE);
+
+	/* setup bus numbers */
+	dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS, &val);
+	val &= 0xff000000;
+	val |= 0x00010100;
+	dw_pcie_writel_rc(pp, val, PCI_PRIMARY_BUS);
+
+	/* setup memory base, memory limit */
+	membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
+	memlimit = (config->mem_size + (u32)pp->mem_base) & 0xfff00000;
+	val = memlimit | membase;
+	dw_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);
+
+	/* setup command register */
+	dw_pcie_readl_rc(pp, PCI_COMMAND, &val);
+	val &= 0xffff0000;
+	val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+		PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+	dw_pcie_writel_rc(pp, val, PCI_COMMAND);
+}
 
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
-MODULE_DESCRIPTION("Samsung PCIe host controller driver");
+MODULE_DESCRIPTION("Designware PCIe host controller driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
new file mode 100644
index 0000000..133820f
--- /dev/null
+++ b/drivers/pci/host/pcie-designware.h
@@ -0,0 +1,65 @@
+/*
+ * Synopsys Designware PCIe host controller driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Author: Jingoo Han <jg1.han@samsung.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.
+ */
+
+struct pcie_port_info {
+	u32		cfg0_size;
+	u32		cfg1_size;
+	u32		io_size;
+	u32		mem_size;
+	phys_addr_t	io_bus_addr;
+	phys_addr_t	mem_bus_addr;
+};
+
+struct pcie_port {
+	struct device		*dev;
+	u8			root_bus_nr;
+	void __iomem		*dbi_base;
+	u64			cfg0_base;
+	void __iomem		*va_cfg0_base;
+	u64			cfg1_base;
+	void __iomem		*va_cfg1_base;
+	u64			io_base;
+	u64			mem_base;
+	spinlock_t		conf_lock;
+	struct resource		cfg;
+	struct resource		io;
+	struct resource		mem;
+	struct pcie_port_info	config;
+	int			irq;
+	u32			lanes;
+	struct pcie_host_ops	*ops;
+};
+
+struct pcie_host_ops {
+	void (*readl_rc)(struct pcie_port *pp,
+			void __iomem *dbi_base, u32 *val);
+	void (*writel_rc)(struct pcie_port *pp,
+			u32 val, void __iomem *dbi_base);
+	int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
+	int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+	int (*link_up)(struct pcie_port *pp);
+	void (*host_init)(struct pcie_port *pp);
+};
+
+extern unsigned long global_io_offset;
+
+int cfg_read(void __iomem *addr, int where, int size, u32 *val);
+int cfg_write(void __iomem *addr, int where, int size, u32 val);
+int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val);
+int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val);
+int dw_pcie_link_up(struct pcie_port *pp);
+void dw_pcie_setup_rc(struct pcie_port *pp);
+int dw_pcie_host_init(struct pcie_port *pp);
+int dw_pcie_setup(int nr, struct pci_sys_data *sys);
+struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
+int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index d85009d..0a648af 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -146,7 +146,7 @@
 	  When in doubt, say N.
 
 config HOTPLUG_PCI_S390
-	tristate "System z PCI Hotplug Support"
+	bool "System z PCI Hotplug Support"
 	depends on S390 && 64BIT
 	help
 	  Say Y here if you want to use the System z PCI Hotplug
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 6fdd49c..f4e0289 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -49,6 +49,7 @@
 #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
+struct acpiphp_context;
 struct acpiphp_bridge;
 struct acpiphp_slot;
 
@@ -59,6 +60,7 @@
 	struct hotplug_slot	*hotplug_slot;
 	struct acpiphp_slot	*acpi_slot;
 	struct hotplug_slot_info info;
+	unsigned int sun;	/* ACPI _SUN (Slot User Number) value */
 };
 
 static inline const char *slot_name(struct slot *slot)
@@ -75,15 +77,11 @@
 	struct list_head list;
 	struct list_head slots;
 	struct kref ref;
-	acpi_handle handle;
 
-	/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
-	struct acpiphp_func *func;
+	struct acpiphp_context *context;
 
 	int nr_slots;
 
-	u32 flags;
-
 	/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
 	struct pci_bus *pci_bus;
 
@@ -99,15 +97,13 @@
  */
 struct acpiphp_slot {
 	struct list_head node;
-	struct acpiphp_bridge *bridge;	/* parent */
+	struct pci_bus *bus;
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
 	struct slot *slot;
 	struct mutex crit_sect;
 
 	u8		device;		/* pci device# */
-
-	unsigned long long sun;		/* ACPI _SUN (slot unique number) */
 	u32		flags;		/* see below */
 };
 
@@ -119,16 +115,32 @@
  * typically 8 objects per slot (i.e. for each PCI function)
  */
 struct acpiphp_func {
-	struct acpiphp_slot *slot;	/* parent */
+	struct acpiphp_bridge *parent;
+	struct acpiphp_slot *slot;
 
 	struct list_head sibling;
-	struct notifier_block nb;
-	acpi_handle	handle;
 
 	u8		function;	/* pci function# */
 	u32		flags;		/* see below */
 };
 
+struct acpiphp_context {
+	acpi_handle handle;
+	struct acpiphp_func func;
+	struct acpiphp_bridge *bridge;
+	unsigned int refcount;
+};
+
+static inline struct acpiphp_context *func_to_context(struct acpiphp_func *func)
+{
+	return container_of(func, struct acpiphp_context, func);
+}
+
+static inline acpi_handle func_to_handle(struct acpiphp_func *func)
+{
+	return func_to_context(func)->handle;
+}
+
 /*
  * struct acpiphp_attention_info - device specific attention registration
  *
@@ -142,45 +154,32 @@
 	struct module *owner;
 };
 
-/* PCI bus bridge HID */
-#define ACPI_PCI_HOST_HID		"PNP0A03"
-
 /* ACPI _STA method value (ignore bit 4; battery present) */
 #define ACPI_STA_ALL			(0x0000000f)
 
-/* bridge flags */
-#define BRIDGE_HAS_EJ0		(0x00000001)
-
 /* slot flags */
 
-#define SLOT_POWEREDON		(0x00000001)
-#define SLOT_ENABLED		(0x00000002)
-#define SLOT_MULTIFUNCTION	(0x00000004)
+#define SLOT_ENABLED		(0x00000001)
 
 /* function flags */
 
 #define FUNC_HAS_STA		(0x00000001)
 #define FUNC_HAS_EJ0		(0x00000002)
-#define FUNC_HAS_PS0		(0x00000010)
-#define FUNC_HAS_PS1		(0x00000020)
-#define FUNC_HAS_PS2		(0x00000040)
-#define FUNC_HAS_PS3		(0x00000080)
-#define FUNC_HAS_DCK            (0x00000100)
+#define FUNC_HAS_DCK            (0x00000004)
 
 /* function prototypes */
 
 /* acpiphp_core.c */
 int acpiphp_register_attention(struct acpiphp_attention_info*info);
 int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot, unsigned int sun);
 void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
 
 /* acpiphp_glue.c */
 typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
 
 int acpiphp_enable_slot(struct acpiphp_slot *slot);
-int acpiphp_disable_slot(struct acpiphp_slot *slot);
-int acpiphp_eject_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index ca81279..bf2203e 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -155,15 +155,11 @@
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
 	struct slot *slot = hotplug_slot->private;
-	int retval;
 
 	dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot(slot->acpi_slot);
-	if (!retval)
-		retval = acpiphp_eject_slot(slot->acpi_slot);
-	return retval;
+	return acpiphp_disable_and_eject_slot(slot->acpi_slot);
 }
 
 
@@ -290,7 +286,8 @@
 }
 
 /* callback routine to initialize 'struct slot' for each slot */
-int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
+				  unsigned int sun)
 {
 	struct slot *slot;
 	int retval = -ENOMEM;
@@ -317,12 +314,11 @@
 	slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	acpiphp_slot->slot = slot;
-	snprintf(name, SLOT_NAME_SIZE, "%llu", slot->acpi_slot->sun);
+	slot->sun = sun;
+	snprintf(name, SLOT_NAME_SIZE, "%u", sun);
 
-	retval = pci_hp_register(slot->hotplug_slot,
-					acpiphp_slot->bridge->pci_bus,
-					acpiphp_slot->device,
-					name);
+	retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bus,
+				 acpiphp_slot->device, name);
 	if (retval == -EBUSY)
 		goto error_hpslot;
 	if (retval) {
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 59df857..f6488ad 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -46,6 +46,7 @@
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
 #include <linux/pci-acpi.h>
+#include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
@@ -55,28 +56,82 @@
 
 static LIST_HEAD(bridge_list);
 static DEFINE_MUTEX(bridge_mutex);
+static DEFINE_MUTEX(acpiphp_context_lock);
 
 #define MY_NAME "acpiphp_glue"
 
-static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
 static void acpiphp_sanitize_bus(struct pci_bus *bus);
 static void acpiphp_set_hpp_values(struct pci_bus *bus);
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context);
-static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void hotplug_event(acpi_handle handle, u32 type, void *data);
 static void free_bridge(struct kref *kref);
 
-/* callback routine to check for the existence of a pci dock device */
-static acpi_status
-is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+static void acpiphp_context_handler(acpi_handle handle, void *context)
 {
-	int *count = (int *)context;
+	/* Intentionally empty. */
+}
 
-	if (is_dock_device(handle)) {
-		(*count)++;
-		return AE_CTRL_TERMINATE;
-	} else {
-		return AE_OK;
+/**
+ * acpiphp_init_context - Create hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to create the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static struct acpiphp_context *acpiphp_init_context(acpi_handle handle)
+{
+	struct acpiphp_context *context;
+	acpi_status status;
+
+	context = kzalloc(sizeof(*context), GFP_KERNEL);
+	if (!context)
+		return NULL;
+
+	context->handle = handle;
+	context->refcount = 1;
+	status = acpi_attach_data(handle, acpiphp_context_handler, context);
+	if (ACPI_FAILURE(status)) {
+		kfree(context);
+		return NULL;
 	}
+	return context;
+}
+
+/**
+ * acpiphp_get_context - Get hotplug context and grab a reference to it.
+ * @handle: ACPI object handle to get the context for.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static struct acpiphp_context *acpiphp_get_context(acpi_handle handle)
+{
+	struct acpiphp_context *context = NULL;
+	acpi_status status;
+	void *data;
+
+	status = acpi_get_data(handle, acpiphp_context_handler, &data);
+	if (ACPI_SUCCESS(status)) {
+		context = data;
+		context->refcount++;
+	}
+	return context;
+}
+
+/**
+ * acpiphp_put_context - Drop a reference to ACPI hotplug context.
+ * @handle: ACPI object handle to put the context for.
+ *
+ * The context object is removed if there are no more references to it.
+ *
+ * Call under acpiphp_context_lock.
+ */
+static void acpiphp_put_context(struct acpiphp_context *context)
+{
+	if (--context->refcount)
+		return;
+
+	WARN_ON(context->bridge);
+	acpi_detach_data(context->handle, acpiphp_context_handler);
+	kfree(context);
 }
 
 static inline void get_bridge(struct acpiphp_bridge *bridge)
@@ -91,25 +146,36 @@
 
 static void free_bridge(struct kref *kref)
 {
+	struct acpiphp_context *context;
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot, *next;
 	struct acpiphp_func *func, *tmp;
 
+	mutex_lock(&acpiphp_context_lock);
+
 	bridge = container_of(kref, struct acpiphp_bridge, ref);
 
 	list_for_each_entry_safe(slot, next, &bridge->slots, node) {
-		list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
-			kfree(func);
-		}
+		list_for_each_entry_safe(func, tmp, &slot->funcs, sibling)
+			acpiphp_put_context(func_to_context(func));
+
 		kfree(slot);
 	}
 
-	/* Release reference acquired by acpiphp_bridge_handle_to_function() */
-	if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
-		put_bridge(bridge->func->slot->bridge);
+	context = bridge->context;
+	/* Root bridges will not have hotplug context. */
+	if (context) {
+		/* Release the reference taken by acpiphp_enumerate_slots(). */
+		put_bridge(context->func.parent);
+		context->bridge = NULL;
+		acpiphp_put_context(context);
+	}
+
 	put_device(&bridge->pci_bus->dev);
 	pci_dev_put(bridge->pci_dev);
 	kfree(bridge);
+
+	mutex_unlock(&acpiphp_context_lock);
 }
 
 /*
@@ -119,15 +185,14 @@
  * TBD - figure out a way to only call fixups for
  * systems that require them.
  */
-static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
-	void *v)
+static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
 {
-	struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
-	struct pci_bus *bus = func->slot->bridge->pci_bus;
+	struct acpiphp_context *context = data;
+	struct pci_bus *bus = context->func.slot->bus;
 	u32 buses;
 
 	if (!bus->self)
-		return  NOTIFY_OK;
+		return;
 
 	/* fixup bad _DCK function that rewrites
 	 * secondary bridge on slot
@@ -143,12 +208,12 @@
 			| ((unsigned int)(bus->busn_res.end) << 16);
 		pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
 	}
-	return NOTIFY_OK;
 }
 
 
 static const struct acpi_dock_ops acpiphp_dock_ops = {
-	.handler = hotplug_event_func,
+	.fixup = post_dock_fixups,
+	.handler = hotplug_event,
 };
 
 /* Check whether the PCI device is managed by native PCIe hotplug driver */
@@ -182,129 +247,118 @@
 
 static void acpiphp_dock_init(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
 
-	get_bridge(func->slot->bridge);
+	get_bridge(context->func.parent);
 }
 
 static void acpiphp_dock_release(void *data)
 {
-	struct acpiphp_func *func = data;
+	struct acpiphp_context *context = data;
 
-	put_bridge(func->slot->bridge);
+	put_bridge(context->func.parent);
 }
 
 /* callback routine to register each ACPI PCI slot object */
-static acpi_status
-register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
+				 void **rv)
 {
-	struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
+	struct acpiphp_bridge *bridge = data;
+	struct acpiphp_context *context;
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *newfunc;
-	acpi_handle tmp;
 	acpi_status status = AE_OK;
-	unsigned long long adr, sun;
-	int device, function, retval, found = 0;
+	unsigned long long adr;
+	int device, function;
 	struct pci_bus *pbus = bridge->pci_bus;
-	struct pci_dev *pdev;
+	struct pci_dev *pdev = bridge->pci_dev;
 	u32 val;
 
-	if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
+	if (pdev && device_is_managed_by_native_pciehp(pdev))
 		return AE_OK;
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
 	if (ACPI_FAILURE(status)) {
-		warn("can't evaluate _ADR (%#x)\n", status);
+		acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
 		return AE_OK;
 	}
 
 	device = (adr >> 16) & 0xffff;
 	function = adr & 0xffff;
 
-	pdev = bridge->pci_dev;
-	if (pdev && device_is_managed_by_native_pciehp(pdev))
-		return AE_OK;
-
-	newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL);
-	if (!newfunc)
-		return AE_NO_MEMORY;
-
-	newfunc->handle = handle;
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_init_context(handle);
+	if (!context) {
+		mutex_unlock(&acpiphp_context_lock);
+		acpi_handle_err(handle, "No hotplug context\n");
+		return AE_NOT_EXIST;
+	}
+	newfunc = &context->func;
 	newfunc->function = function;
+	newfunc->parent = bridge;
+	mutex_unlock(&acpiphp_context_lock);
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+	if (acpi_has_method(handle, "_EJ0"))
 		newfunc->flags = FUNC_HAS_EJ0;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
+	if (acpi_has_method(handle, "_STA"))
 		newfunc->flags |= FUNC_HAS_STA;
 
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp)))
-		newfunc->flags |= FUNC_HAS_PS0;
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
-		newfunc->flags |= FUNC_HAS_PS3;
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
+	if (acpi_has_method(handle, "_DCK"))
 		newfunc->flags |= FUNC_HAS_DCK;
 
-	status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
-	if (ACPI_FAILURE(status)) {
-		/*
-		 * use the count of the number of slots we've found
-		 * for the number of the slot
-		 */
-		sun = bridge->nr_slots+1;
-	}
-
 	/* search for objects that share the same slot */
 	list_for_each_entry(slot, &bridge->slots, node)
-		if (slot->device == device) {
-			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!\n");
-			found = 1;
-			break;
-		}
+		if (slot->device == device)
+			goto slot_found;
 
-	if (!found) {
-		slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
-		if (!slot) {
-			kfree(newfunc);
-			return AE_NO_MEMORY;
-		}
+	slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
+	if (!slot) {
+		status = AE_NO_MEMORY;
+		goto err;
+	}
 
-		slot->bridge = bridge;
-		slot->device = device;
-		slot->sun = sun;
-		INIT_LIST_HEAD(&slot->funcs);
-		mutex_init(&slot->crit_sect);
+	slot->bus = bridge->pci_bus;
+	slot->device = device;
+	INIT_LIST_HEAD(&slot->funcs);
+	mutex_init(&slot->crit_sect);
 
-		mutex_lock(&bridge_mutex);
-		list_add_tail(&slot->node, &bridge->slots);
-		mutex_unlock(&bridge_mutex);
+	list_add_tail(&slot->node, &bridge->slots);
+
+	/* Register slots for ejectable funtions only. */
+	if (acpi_pci_check_ejectable(pbus, handle)  || is_dock_device(handle)) {
+		unsigned long long sun;
+		int retval;
+
 		bridge->nr_slots++;
+		status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
+		if (ACPI_FAILURE(status))
+			sun = bridge->nr_slots;
 
 		dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
-		    slot->sun, pci_domain_nr(pbus), pbus->number, device);
-		retval = acpiphp_register_hotplug_slot(slot);
+		    sun, pci_domain_nr(pbus), pbus->number, device);
+
+		retval = acpiphp_register_hotplug_slot(slot, sun);
 		if (retval) {
+			slot->slot = NULL;
+			bridge->nr_slots--;
 			if (retval == -EBUSY)
 				warn("Slot %llu already registered by another "
-					"hotplug driver\n", slot->sun);
+					"hotplug driver\n", sun);
 			else
 				warn("acpiphp_register_hotplug_slot failed "
 					"(err code = 0x%x)\n", retval);
-			goto err_exit;
 		}
+		/* Even if the slot registration fails, we can still use it. */
 	}
 
+ slot_found:
 	newfunc->slot = slot;
-	mutex_lock(&bridge_mutex);
 	list_add_tail(&newfunc->sibling, &slot->funcs);
-	mutex_unlock(&bridge_mutex);
 
 	if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
 				       &val, 60*1000))
-		slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
+		slot->flags |= SLOT_ENABLED;
 
 	if (is_dock_device(handle)) {
 		/* we don't want to call this device's _EJ0
@@ -313,136 +367,46 @@
 		 */
 		newfunc->flags &= ~FUNC_HAS_EJ0;
 		if (register_hotplug_dock_device(handle,
-			&acpiphp_dock_ops, newfunc,
+			&acpiphp_dock_ops, context,
 			acpiphp_dock_init, acpiphp_dock_release))
 			dbg("failed to register dock device\n");
-
-		/* we need to be notified when dock events happen
-		 * outside of the hotplug operation, since we may
-		 * need to do fixups before we can hotplug.
-		 */
-		newfunc->nb.notifier_call = post_dock_fixups;
-		if (register_dock_notifier(&newfunc->nb))
-			dbg("failed to register a dock notifier");
 	}
 
 	/* install notify handler */
 	if (!(newfunc->flags & FUNC_HAS_DCK)) {
-		status = acpi_install_notify_handler(handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event_func,
-					     newfunc);
-
+		status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+						     handle_hotplug_event,
+						     context);
 		if (ACPI_FAILURE(status))
-			err("failed to register interrupt notify handler\n");
-	} else
-		status = AE_OK;
-
-	return status;
-
- err_exit:
-	bridge->nr_slots--;
-	mutex_lock(&bridge_mutex);
-	list_del(&slot->node);
-	mutex_unlock(&bridge_mutex);
-	kfree(slot);
-	kfree(newfunc);
+			acpi_handle_err(handle,
+					"failed to install notify handler\n");
+	}
 
 	return AE_OK;
+
+ err:
+	mutex_lock(&acpiphp_context_lock);
+	acpiphp_put_context(context);
+	mutex_unlock(&acpiphp_context_lock);
+	return status;
 }
 
-
-/* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle handle)
-{
-	int found = acpi_pci_detect_ejectable(handle);
-	if (!found) {
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
-				    is_pci_dock_device, NULL, (void *)&found, NULL);
-	}
-	return found;
-}
-
-/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */
-static void init_bridge_misc(struct acpiphp_bridge *bridge)
-{
-	acpi_status status;
-
-	/* must be added to the list prior to calling register_slot */
-	mutex_lock(&bridge_mutex);
-	list_add(&bridge->list, &bridge_list);
-	mutex_unlock(&bridge_mutex);
-
-	/* register all slot objects under this bridge */
-	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
-				     register_slot, NULL, bridge, NULL);
-	if (ACPI_FAILURE(status)) {
-		mutex_lock(&bridge_mutex);
-		list_del(&bridge->list);
-		mutex_unlock(&bridge_mutex);
-		return;
-	}
-
-	/* install notify handler for P2P bridges */
-	if (!pci_is_root_bus(bridge->pci_bus)) {
-		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-			status = acpi_remove_notify_handler(bridge->func->handle,
-						ACPI_SYSTEM_NOTIFY,
-						handle_hotplug_event_func);
-			if (ACPI_FAILURE(status))
-				err("failed to remove notify handler\n");
-		}
-		status = acpi_install_notify_handler(bridge->handle,
-					     ACPI_SYSTEM_NOTIFY,
-					     handle_hotplug_event_bridge,
-					     bridge);
-
-		if (ACPI_FAILURE(status)) {
-			err("failed to register interrupt notify handler\n");
-		}
-	}
-}
-
-
-/* find acpiphp_func from acpiphp_bridge */
-static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
-{
-	struct acpiphp_bridge *bridge;
-	struct acpiphp_slot *slot;
-	struct acpiphp_func *func = NULL;
-
-	mutex_lock(&bridge_mutex);
-	list_for_each_entry(bridge, &bridge_list, list) {
-		list_for_each_entry(slot, &bridge->slots, node) {
-			list_for_each_entry(func, &slot->funcs, sibling) {
-				if (func->handle == handle) {
-					get_bridge(func->slot->bridge);
-					mutex_unlock(&bridge_mutex);
-					return func;
-				}
-			}
-		}
-	}
-	mutex_unlock(&bridge_mutex);
-
-	return NULL;
-}
-
-
 static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
 {
-	struct acpiphp_bridge *bridge;
+	struct acpiphp_context *context;
+	struct acpiphp_bridge *bridge = NULL;
 
-	mutex_lock(&bridge_mutex);
-	list_for_each_entry(bridge, &bridge_list, list)
-		if (bridge->handle == handle) {
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (context) {
+		bridge = context->bridge;
+		if (bridge)
 			get_bridge(bridge);
-			mutex_unlock(&bridge_mutex);
-			return bridge;
-		}
-	mutex_unlock(&bridge_mutex);
 
-	return NULL;
+		acpiphp_put_context(context);
+	}
+	mutex_unlock(&acpiphp_context_lock);
+	return bridge;
 }
 
 static void cleanup_bridge(struct acpiphp_bridge *bridge)
@@ -450,40 +414,24 @@
 	struct acpiphp_slot *slot;
 	struct acpiphp_func *func;
 	acpi_status status;
-	acpi_handle handle = bridge->handle;
-
-	if (!pci_is_root_bus(bridge->pci_bus)) {
-		status = acpi_remove_notify_handler(handle,
-					    ACPI_SYSTEM_NOTIFY,
-					    handle_hotplug_event_bridge);
-		if (ACPI_FAILURE(status))
-			err("failed to remove notify handler\n");
-	}
-
-	if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-		status = acpi_install_notify_handler(bridge->func->handle,
-						ACPI_SYSTEM_NOTIFY,
-						handle_hotplug_event_func,
-						bridge->func);
-		if (ACPI_FAILURE(status))
-			err("failed to install interrupt notify handler\n");
-	}
 
 	list_for_each_entry(slot, &bridge->slots, node) {
 		list_for_each_entry(func, &slot->funcs, sibling) {
-			if (is_dock_device(func->handle)) {
-				unregister_hotplug_dock_device(func->handle);
-				unregister_dock_notifier(&func->nb);
-			}
+			acpi_handle handle = func_to_handle(func);
+
+			if (is_dock_device(handle))
+				unregister_hotplug_dock_device(handle);
+
 			if (!(func->flags & FUNC_HAS_DCK)) {
-				status = acpi_remove_notify_handler(func->handle,
-						ACPI_SYSTEM_NOTIFY,
-						handle_hotplug_event_func);
+				status = acpi_remove_notify_handler(handle,
+							ACPI_SYSTEM_NOTIFY,
+							handle_hotplug_event);
 				if (ACPI_FAILURE(status))
 					err("failed to remove notify handler\n");
 			}
 		}
-		acpiphp_unregister_hotplug_slot(slot);
+		if (slot->slot)
+			acpiphp_unregister_hotplug_slot(slot);
 	}
 
 	mutex_lock(&bridge_mutex);
@@ -491,71 +439,6 @@
 	mutex_unlock(&bridge_mutex);
 }
 
-static int power_on_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-	int retval = 0;
-
-	/* if already enabled, just skip */
-	if (slot->flags & SLOT_POWEREDON)
-		goto err_exit;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0\n", __func__);
-			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed\n", __func__);
-				retval = -1;
-				goto err_exit;
-			} else
-				break;
-		}
-	}
-
-	/* TBD: evaluate _STA to check if the slot is enabled */
-
-	slot->flags |= SLOT_POWEREDON;
-
- err_exit:
-	return retval;
-}
-
-
-static int power_off_slot(struct acpiphp_slot *slot)
-{
-	acpi_status status;
-	struct acpiphp_func *func;
-
-	int retval = 0;
-
-	/* if already disabled, just skip */
-	if ((slot->flags & SLOT_POWEREDON) == 0)
-		goto err_exit;
-
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		if (func->flags & FUNC_HAS_PS3) {
-			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed\n", __func__);
-				retval = -1;
-				goto err_exit;
-			} else
-				break;
-		}
-	}
-
-	/* TBD: evaluate _STA to check if the slot is disabled */
-
-	slot->flags &= (~SLOT_POWEREDON);
-
- err_exit:
-	return retval;
-}
-
-
-
 /**
  * acpiphp_max_busnr - return the highest reserved bus number under the given bus.
  * @bus: bus to start search with
@@ -583,52 +466,32 @@
 	return max;
 }
 
-
 /**
- * acpiphp_bus_add - add a new bus to acpi subsystem
- * @func: acpiphp_func of the bridge
+ * acpiphp_bus_trim - Trim device objects in an ACPI namespace subtree.
+ * @handle: ACPI device object handle to start from.
  */
-static int acpiphp_bus_add(struct acpiphp_func *func)
+static void acpiphp_bus_trim(acpi_handle handle)
 {
-	struct acpi_device *device;
-	int ret_val;
+	struct acpi_device *adev = NULL;
 
-	if (!acpi_bus_get_device(func->handle, &device)) {
-		dbg("bus exists... trim\n");
-		/* this shouldn't be in here, so remove
-		 * the bus then re-add it...
-		 */
-		acpi_bus_trim(device);
-	}
-
-	ret_val = acpi_bus_scan(func->handle);
-	if (!ret_val)
-		ret_val = acpi_bus_get_device(func->handle, &device);
-
-	if (ret_val)
-		dbg("error adding bus, %x\n", -ret_val);
-
-	return ret_val;
+	acpi_bus_get_device(handle, &adev);
+	if (adev)
+		acpi_bus_trim(adev);
 }
 
-
 /**
- * acpiphp_bus_trim - trim a bus from acpi subsystem
- * @handle: handle to acpi namespace
+ * acpiphp_bus_add - Scan ACPI namespace subtree.
+ * @handle: ACPI object handle to start the scan from.
  */
-static int acpiphp_bus_trim(acpi_handle handle)
+static void acpiphp_bus_add(acpi_handle handle)
 {
-	struct acpi_device *device;
-	int retval;
+	struct acpi_device *adev = NULL;
 
-	retval = acpi_bus_get_device(handle, &device);
-	if (retval) {
-		dbg("acpi_device not found\n");
-		return retval;
-	}
-
-	acpi_bus_trim(device);
-	return 0;
+	acpiphp_bus_trim(handle);
+	acpi_bus_scan(handle);
+	acpi_bus_get_device(handle, &adev);
+	if (adev)
+		acpi_device_set_power(adev, ACPI_STATE_D0);
 }
 
 static void acpiphp_set_acpi_region(struct acpiphp_slot *slot)
@@ -645,7 +508,8 @@
 		params[1].type = ACPI_TYPE_INTEGER;
 		params[1].integer.value = 1;
 		/* _REG is optional, we don't care about if there is failure */
-		acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL);
+		acpi_evaluate_object(func_to_handle(func), "_REG", &arg_list,
+				     NULL);
 	}
 }
 
@@ -653,59 +517,44 @@
 {
 	struct acpiphp_func *func;
 
-	if (!dev->subordinate)
-		return;
-
 	/* quirk, or pcie could set it already */
 	if (dev->is_hotplug_bridge)
 		return;
 
-	if (PCI_SLOT(dev->devfn) != slot->device)
-		return;
-
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (PCI_FUNC(dev->devfn) == func->function) {
-			/* check if this bridge has ejectable slots */
-			if ((detect_ejectable_slots(func->handle) > 0))
-				dev->is_hotplug_bridge = 1;
+			dev->is_hotplug_bridge = 1;
 			break;
 		}
 	}
 }
 
 /**
- * enable_device - enable, configure a slot
+ * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
  *
  * This function should be called per *physical slot*,
  * not per each slot object in ACPI namespace.
  */
-static int __ref enable_device(struct acpiphp_slot *slot)
+static void __ref enable_slot(struct acpiphp_slot *slot)
 {
 	struct pci_dev *dev;
-	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_bus *bus = slot->bus;
 	struct acpiphp_func *func;
-	int num, max, pass;
+	int max, pass;
 	LIST_HEAD(add_list);
 
-	if (slot->flags & SLOT_ENABLED)
-		goto err_exit;
-
 	list_for_each_entry(func, &slot->funcs, sibling)
-		acpiphp_bus_add(func);
+		acpiphp_bus_add(func_to_handle(func));
 
-	num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-	if (num == 0) {
-		/* Maybe only part of funcs are added. */
-		dbg("No new device found\n");
-		goto err_exit;
-	}
+	pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
 
 	max = acpiphp_max_busnr(bus);
 	for (pass = 0; pass < 2; pass++) {
 		list_for_each_entry(dev, &bus->devices, bus_list) {
 			if (PCI_SLOT(dev->devfn) != slot->device)
 				continue;
+
 			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
 			    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
 				max = pci_scan_bridge(bus, dev, max, pass);
@@ -723,7 +572,6 @@
 	acpiphp_sanitize_bus(bus);
 	acpiphp_set_hpp_values(bus);
 	acpiphp_set_acpi_region(slot);
-	pci_enable_bridges(bus);
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		/* Assume that newly added devices are powered on already. */
@@ -744,16 +592,12 @@
 			continue;
 		}
 	}
-
-
- err_exit:
-	return 0;
 }
 
 /* return first device in slot, acquiring a reference on it */
 static struct pci_dev *dev_in_slot(struct acpiphp_slot *slot)
 {
-	struct pci_bus *bus = slot->bridge->pci_bus;
+	struct pci_bus *bus = slot->bus;
 	struct pci_dev *dev;
 	struct pci_dev *ret = NULL;
 
@@ -769,16 +613,16 @@
 }
 
 /**
- * disable_device - disable a slot
+ * disable_slot - disable a slot
  * @slot: ACPI PHP slot
  */
-static int disable_device(struct acpiphp_slot *slot)
+static void disable_slot(struct acpiphp_slot *slot)
 {
 	struct acpiphp_func *func;
 	struct pci_dev *pdev;
 
 	/*
-	 * enable_device() enumerates all functions in this device via
+	 * enable_slot() enumerates all functions in this device via
 	 * pci_scan_slot(), whether they have associated ACPI hotplug
 	 * methods (_EJ0, etc.) or not.  Therefore, we remove all functions
 	 * here.
@@ -788,13 +632,10 @@
 		pci_dev_put(pdev);
 	}
 
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		acpiphp_bus_trim(func->handle);
-	}
+	list_for_each_entry(func, &slot->funcs, sibling)
+		acpiphp_bus_trim(func_to_handle(func));
 
 	slot->flags &= (~SLOT_ENABLED);
-
-	return 0;
 }
 
 
@@ -812,18 +653,21 @@
  */
 static unsigned int get_slot_status(struct acpiphp_slot *slot)
 {
-	acpi_status status;
 	unsigned long long sta = 0;
-	u32 dvid;
 	struct acpiphp_func *func;
 
 	list_for_each_entry(func, &slot->funcs, sibling) {
 		if (func->flags & FUNC_HAS_STA) {
-			status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
+			acpi_status status;
+
+			status = acpi_evaluate_integer(func_to_handle(func),
+						       "_STA", NULL, &sta);
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			pci_bus_read_config_dword(slot->bridge->pci_bus,
+			u32 dvid;
+
+			pci_bus_read_config_dword(slot->bus,
 						  PCI_DEVFN(slot->device,
 							    func->function),
 						  PCI_VENDOR_ID, &dvid);
@@ -838,34 +682,42 @@
 }
 
 /**
- * acpiphp_eject_slot - physically eject the slot
- * @slot: ACPI PHP slot
+ * trim_stale_devices - remove PCI devices that are not responding.
+ * @dev: PCI device to start walking the hierarchy from.
  */
-int acpiphp_eject_slot(struct acpiphp_slot *slot)
+static void trim_stale_devices(struct pci_dev *dev)
 {
-	acpi_status status;
-	struct acpiphp_func *func;
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
+	acpi_handle handle = ACPI_HANDLE(&dev->dev);
+	struct pci_bus *bus = dev->subordinate;
+	bool alive = false;
 
-	list_for_each_entry(func, &slot->funcs, sibling) {
-		/* We don't want to call _EJ0 on non-existing functions. */
-		if ((func->flags & FUNC_HAS_EJ0)) {
-			/* _EJ0 method take one argument */
-			arg_list.count = 1;
-			arg_list.pointer = &arg;
-			arg.type = ACPI_TYPE_INTEGER;
-			arg.integer.value = 1;
+	if (handle) {
+		acpi_status status;
+		unsigned long long sta;
 
-			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
-			if (ACPI_FAILURE(status)) {
-				warn("%s: _EJ0 failed\n", __func__);
-				return -1;
-			} else
-				break;
-		}
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+		alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
 	}
-	return 0;
+	if (!alive) {
+		u32 v;
+
+		/* Check if the device responds. */
+		alive = pci_bus_read_dev_vendor_id(dev->bus, dev->devfn, &v, 0);
+	}
+	if (!alive) {
+		pci_stop_and_remove_bus_device(dev);
+		if (handle)
+			acpiphp_bus_trim(handle);
+	} else if (bus) {
+		struct pci_dev *child, *tmp;
+
+		/* The device is a bridge. so check the bus below it. */
+		pm_runtime_get_sync(&dev->dev);
+		list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
+			trim_stale_devices(child);
+
+		pm_runtime_put(&dev->dev);
+	}
 }
 
 /**
@@ -875,43 +727,30 @@
  * Iterate over all slots under this bridge and make sure that if a
  * card is present they are enabled, and if not they are disabled.
  */
-static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
+static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
 {
 	struct acpiphp_slot *slot;
-	int retval = 0;
-	int enabled, disabled;
-
-	enabled = disabled = 0;
 
 	list_for_each_entry(slot, &bridge->slots, node) {
-		unsigned int status = get_slot_status(slot);
-		if (slot->flags & SLOT_ENABLED) {
-			if (status == ACPI_STA_ALL)
-				continue;
-			retval = acpiphp_disable_slot(slot);
-			if (retval) {
-				err("Error occurred in disabling\n");
-				goto err_exit;
-			} else {
-				acpiphp_eject_slot(slot);
-			}
-			disabled++;
+		struct pci_bus *bus = slot->bus;
+		struct pci_dev *dev, *tmp;
+
+		mutex_lock(&slot->crit_sect);
+		/* wake up all functions */
+		if (get_slot_status(slot) == ACPI_STA_ALL) {
+			/* remove stale devices if any */
+			list_for_each_entry_safe(dev, tmp, &bus->devices,
+						 bus_list)
+				if (PCI_SLOT(dev->devfn) == slot->device)
+					trim_stale_devices(dev);
+
+			/* configure all functions */
+			enable_slot(slot);
 		} else {
-			if (status != ACPI_STA_ALL)
-				continue;
-			retval = acpiphp_enable_slot(slot);
-			if (retval) {
-				err("Error occurred in enabling\n");
-				goto err_exit;
-			}
-			enabled++;
+			disable_slot(slot);
 		}
+		mutex_unlock(&slot->crit_sect);
 	}
-
-	dbg("%s: %d enabled, %d disabled\n", __func__, enabled, disabled);
-
- err_exit:
-	return retval;
 }
 
 static void acpiphp_set_hpp_values(struct pci_bus *bus)
@@ -950,25 +789,6 @@
  * ACPI event handlers
  */
 
-static acpi_status
-check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-	struct acpiphp_bridge *bridge;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
-
-	bridge = acpiphp_handle_to_bridge(handle);
-	if (bridge) {
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-		dbg("%s: re-enumerating slots under %s\n",
-			__func__, objname);
-		acpiphp_check_bridge(bridge);
-		put_bridge(bridge);
-	}
-	return AE_OK ;
-}
-
 void acpiphp_check_host_bridge(acpi_handle handle)
 {
 	struct acpiphp_bridge *bridge;
@@ -978,27 +798,23 @@
 		acpiphp_check_bridge(bridge);
 		put_bridge(bridge);
 	}
-
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-		ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
 }
 
-static void _handle_hotplug_event_bridge(struct work_struct *work)
+static void hotplug_event(acpi_handle handle, u32 type, void *data)
 {
+	struct acpiphp_context *context = data;
+	struct acpiphp_func *func = &context->func;
 	struct acpiphp_bridge *bridge;
 	char objname[64];
 	struct acpi_buffer buffer = { .length = sizeof(objname),
 				      .pointer = objname };
-	struct acpi_hp_work *hp_work;
-	acpi_handle handle;
-	u32 type;
 
-	hp_work = container_of(work, struct acpi_hp_work, work);
-	handle = hp_work->handle;
-	type = hp_work->type;
-	bridge = (struct acpiphp_bridge *)hp_work->context;
+	mutex_lock(&acpiphp_context_lock);
+	bridge = context->bridge;
+	if (bridge)
+		get_bridge(bridge);
 
-	acpi_scan_lock_acquire();
+	mutex_unlock(&acpiphp_context_lock);
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1007,188 +823,129 @@
 		/* bus re-enumerate */
 		dbg("%s: Bus check notify on %s\n", __func__, objname);
 		dbg("%s: re-enumerating slots under %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
-		acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-			ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+		if (bridge) {
+			acpiphp_check_bridge(bridge);
+		} else {
+			struct acpiphp_slot *slot = func->slot;
+
+			mutex_lock(&slot->crit_sect);
+			enable_slot(slot);
+			mutex_unlock(&slot->crit_sect);
+		}
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
 		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(bridge);
-		break;
+		if (bridge)
+			acpiphp_check_bridge(bridge);
+		else
+			acpiphp_check_bridge(func->parent);
 
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
 		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
-			struct acpiphp_slot *slot;
-			slot = bridge->func->slot;
-			if (!acpiphp_disable_slot(slot))
-				acpiphp_eject_slot(slot);
-		}
-		break;
-
-	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
-		printk(KERN_ERR "Device %s cannot be configured due"
-				" to a frequency mismatch\n", objname);
-		break;
-
-	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
-		printk(KERN_ERR "Device %s cannot be configured due"
-				" to a bus mode mismatch\n", objname);
-		break;
-
-	case ACPI_NOTIFY_POWER_FAULT:
-		printk(KERN_ERR "Device %s has suffered a power fault\n",
-				objname);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
+		acpiphp_disable_and_eject_slot(func->slot);
 		break;
 	}
 
-	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
-	put_bridge(bridge);
+	if (bridge)
+		put_bridge(bridge);
 }
 
-/**
- * handle_hotplug_event_bridge - handle ACPI event on bridges
- * @handle: Notify()'ed acpi_handle
- * @type: Notify code
- * @context: pointer to acpiphp_bridge structure
- *
- * Handles ACPI event notification on {host,p2p} bridges.
- */
-static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
-					void *context)
+static void hotplug_event_work(struct work_struct *work)
 {
-	struct acpiphp_bridge *bridge = context;
-
-	/*
-	 * Currently the code adds all hotplug events to the kacpid_wq
-	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
-	 * The proper way to fix this is to reorganize the code so that
-	 * drivers (dock, etc.) do not call acpi_os_execute(), etc.
-	 * For now just re-add this work to the kacpi_hotplug_wq so we
-	 * don't deadlock on hotplug actions.
-	 */
-	get_bridge(bridge);
-	alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
-}
-
-static void hotplug_event_func(acpi_handle handle, u32 type, void *context)
-{
-	struct acpiphp_func *func = context;
-	char objname[64];
-	struct acpi_buffer buffer = { .length = sizeof(objname),
-				      .pointer = objname };
-
-	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-	switch (type) {
-	case ACPI_NOTIFY_BUS_CHECK:
-		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s\n", __func__, objname);
-		acpiphp_enable_slot(func->slot);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_CHECK:
-		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s\n", __func__, objname);
-		acpiphp_check_bridge(func->slot->bridge);
-		break;
-
-	case ACPI_NOTIFY_DEVICE_WAKE:
-		/* wake event */
-		dbg("%s: Device wake notify on %s\n", __func__, objname);
-		break;
-
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		/* request device eject */
-		dbg("%s: Device eject notify on %s\n", __func__, objname);
-		if (!(acpiphp_disable_slot(func->slot)))
-			acpiphp_eject_slot(func->slot);
-		break;
-
-	default:
-		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
-		break;
-	}
-}
-
-static void _handle_hotplug_event_func(struct work_struct *work)
-{
+	struct acpiphp_context *context;
 	struct acpi_hp_work *hp_work;
-	struct acpiphp_func *func;
 
 	hp_work = container_of(work, struct acpi_hp_work, work);
-	func = hp_work->context;
+	context = hp_work->context;
 	acpi_scan_lock_acquire();
 
-	hotplug_event_func(hp_work->handle, hp_work->type, func);
+	hotplug_event(hp_work->handle, hp_work->type, context);
 
 	acpi_scan_lock_release();
-	kfree(hp_work); /* allocated in handle_hotplug_event_func */
-	put_bridge(func->slot->bridge);
+	kfree(hp_work); /* allocated in handle_hotplug_event() */
+	put_bridge(context->func.parent);
 }
 
 /**
- * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
+ * handle_hotplug_event - handle ACPI hotplug event
  * @handle: Notify()'ed acpi_handle
  * @type: Notify code
- * @context: pointer to acpiphp_func structure
+ * @data: pointer to acpiphp_context structure
  *
  * Handles ACPI event notification on slots.
  */
-static void handle_hotplug_event_func(acpi_handle handle, u32 type,
-				      void *context)
+static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
-	struct acpiphp_func *func = context;
+	struct acpiphp_context *context;
 
-	/*
-	 * Currently the code adds all hotplug events to the kacpid_wq
-	 * queue when it should add hotplug events to the kacpi_hotplug_wq.
-	 * The proper way to fix this is to reorganize the code so that
-	 * drivers (dock, etc.) do not call acpi_os_execute(), etc.
-	 * For now just re-add this work to the kacpi_hotplug_wq so we
-	 * don't deadlock on hotplug actions.
-	 */
-	get_bridge(func->slot->bridge);
-	alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
+	switch (type) {
+	case ACPI_NOTIFY_BUS_CHECK:
+	case ACPI_NOTIFY_DEVICE_CHECK:
+	case ACPI_NOTIFY_EJECT_REQUEST:
+		break;
+
+	case ACPI_NOTIFY_DEVICE_WAKE:
+		return;
+
+	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+		acpi_handle_err(handle, "Device cannot be configured due "
+				"to a frequency mismatch\n");
+		return;
+
+	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+		acpi_handle_err(handle, "Device cannot be configured due "
+				"to a bus mode mismatch\n");
+		return;
+
+	case ACPI_NOTIFY_POWER_FAULT:
+		acpi_handle_err(handle, "Device has suffered a power fault\n");
+		return;
+
+	default:
+		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
+		return;
+	}
+
+	mutex_lock(&acpiphp_context_lock);
+	context = acpiphp_get_context(handle);
+	if (context) {
+		get_bridge(context->func.parent);
+		acpiphp_put_context(context);
+		alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
+	}
+	mutex_unlock(&acpiphp_context_lock);
 }
 
 /*
  * Create hotplug slots for the PCI bus.
  * It should always return 0 to avoid skipping following notifiers.
  */
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
+void acpiphp_enumerate_slots(struct pci_bus *bus)
 {
-	acpi_handle dummy_handle;
 	struct acpiphp_bridge *bridge;
+	acpi_handle handle;
+	acpi_status status;
 
 	if (acpiphp_disabled)
 		return;
 
-	if (detect_ejectable_slots(handle) <= 0)
+	handle = ACPI_HANDLE(bus->bridge);
+	if (!handle)
 		return;
 
 	bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
-	if (bridge == NULL) {
-		err("out of memory\n");
+	if (!bridge) {
+		acpi_handle_err(handle, "No memory for bridge object\n");
 		return;
 	}
 
 	INIT_LIST_HEAD(&bridge->slots);
 	kref_init(&bridge->ref);
-	bridge->handle = handle;
 	bridge->pci_dev = pci_dev_get(bus->self);
 	bridge->pci_bus = bus;
 
@@ -1199,31 +956,62 @@
 	 */
 	get_device(&bus->dev);
 
-	if (!pci_is_root_bus(bridge->pci_bus) &&
-	    ACPI_SUCCESS(acpi_get_handle(bridge->handle,
-					"_EJ0", &dummy_handle))) {
-		dbg("found ejectable p2p bridge\n");
-		bridge->flags |= BRIDGE_HAS_EJ0;
-		bridge->func = acpiphp_bridge_handle_to_function(handle);
+	if (!pci_is_root_bus(bridge->pci_bus)) {
+		struct acpiphp_context *context;
+
+		/*
+		 * This bridge should have been registered as a hotplug function
+		 * under its parent, so the context has to be there.  If not, we
+		 * are in deep goo.
+		 */
+		mutex_lock(&acpiphp_context_lock);
+		context = acpiphp_get_context(handle);
+		if (WARN_ON(!context)) {
+			mutex_unlock(&acpiphp_context_lock);
+			put_device(&bus->dev);
+			kfree(bridge);
+			return;
+		}
+		bridge->context = context;
+		context->bridge = bridge;
+		/* Get a reference to the parent bridge. */
+		get_bridge(context->func.parent);
+		mutex_unlock(&acpiphp_context_lock);
 	}
 
-	init_bridge_misc(bridge);
+	/* must be added to the list prior to calling register_slot */
+	mutex_lock(&bridge_mutex);
+	list_add(&bridge->list, &bridge_list);
+	mutex_unlock(&bridge_mutex);
+
+	/* register all slot objects under this bridge */
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+				     register_slot, NULL, bridge, NULL);
+	if (ACPI_FAILURE(status)) {
+		acpi_handle_err(handle, "failed to register slots\n");
+		cleanup_bridge(bridge);
+		put_bridge(bridge);
+	}
 }
 
 /* Destroy hotplug slots associated with the PCI bus */
 void acpiphp_remove_slots(struct pci_bus *bus)
 {
-	struct acpiphp_bridge *bridge, *tmp;
+	struct acpiphp_bridge *bridge;
 
 	if (acpiphp_disabled)
 		return;
 
-	list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+	mutex_lock(&bridge_mutex);
+	list_for_each_entry(bridge, &bridge_list, list)
 		if (bridge->pci_bus == bus) {
+			mutex_unlock(&bridge_mutex);
 			cleanup_bridge(bridge);
 			put_bridge(bridge);
-			break;
+			return;
 		}
+
+	mutex_unlock(&bridge_mutex);
 }
 
 /**
@@ -1232,51 +1020,39 @@
  */
 int acpiphp_enable_slot(struct acpiphp_slot *slot)
 {
-	int retval;
-
 	mutex_lock(&slot->crit_sect);
+	/* configure all functions */
+	if (!(slot->flags & SLOT_ENABLED))
+		enable_slot(slot);
 
-	/* wake up all functions */
-	retval = power_on_slot(slot);
-	if (retval)
-		goto err_exit;
-
-	if (get_slot_status(slot) == ACPI_STA_ALL) {
-		/* configure all functions */
-		retval = enable_device(slot);
-		if (retval)
-			power_off_slot(slot);
-	} else {
-		dbg("%s: Slot status is not ACPI_STA_ALL\n", __func__);
-		power_off_slot(slot);
-	}
-
- err_exit:
 	mutex_unlock(&slot->crit_sect);
-	return retval;
+	return 0;
 }
 
 /**
- * acpiphp_disable_slot - power off slot
+ * acpiphp_disable_and_eject_slot - power off and eject slot
  * @slot: ACPI PHP slot
  */
-int acpiphp_disable_slot(struct acpiphp_slot *slot)
+int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
 {
+	struct acpiphp_func *func;
 	int retval = 0;
 
 	mutex_lock(&slot->crit_sect);
 
 	/* unconfigure all functions */
-	retval = disable_device(slot);
-	if (retval)
-		goto err_exit;
+	disable_slot(slot);
 
-	/* power off all functions */
-	retval = power_off_slot(slot);
-	if (retval)
-		goto err_exit;
+	list_for_each_entry(func, &slot->funcs, sibling)
+		if (func->flags & FUNC_HAS_EJ0) {
+			acpi_handle handle = func_to_handle(func);
 
- err_exit:
+			if (ACPI_FAILURE(acpi_evaluate_ej0(handle)))
+				acpi_handle_err(handle, "_EJ0 failed\n");
+
+			break;
+		}
+
 	mutex_unlock(&slot->crit_sect);
 	return retval;
 }
@@ -1288,7 +1064,7 @@
  */
 u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
 {
-	return (slot->flags & SLOT_POWEREDON);
+	return (slot->flags & SLOT_ENABLED);
 }
 
 
@@ -1298,11 +1074,7 @@
  */
 u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
 {
-	unsigned int sta;
-
-	sta = get_slot_status(slot);
-
-	return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
+	return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
 }
 
 
@@ -1312,9 +1084,5 @@
  */
 u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
 {
-	unsigned int sta;
-
-	sta = get_slot_status(slot);
-
-	return (sta == 0) ? 0 : 1;
+	return !!get_slot_status(slot);
 }
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index c35e8ad..2f5786c 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -66,7 +66,7 @@
 #define IBM_HARDWARE_ID1 "IBM37D0"
 #define IBM_HARDWARE_ID2 "IBM37D4"
 
-#define hpslot_to_sun(A) (((struct slot *)((A)->private))->acpi_slot->sun)
+#define hpslot_to_sun(A) (((struct slot *)((A)->private))->sun)
 
 /* union apci_descriptor - allows access to the
  * various device descriptors that are embedded in the
@@ -270,7 +270,6 @@
 
 	if (subevent == 0x80) {
 		dbg("%s: generationg bus event\n", __func__);
-		acpi_bus_generate_proc_event(note->device, note->event, detail);
 		acpi_bus_generate_netlink_event(note->device->pnp.device_class,
 						  dev_name(&note->device->dev),
 						  note->event, detail);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 7fb3269..541bbe6 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -155,6 +155,7 @@
 void pciehp_green_led_blink(struct slot *slot);
 int pciehp_check_link_status(struct controller *ctrl);
 void pciehp_release_ctrl(struct controller *ctrl);
+int pciehp_reset_slot(struct slot *slot, int probe);
 
 static inline const char *slot_name(struct slot *slot)
 {
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 7d72c5e..f4a18f5 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -69,6 +69,7 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int reset_slot		(struct hotplug_slot *slot, int probe);
 
 /**
  * release_slot - free up the memory used by a slot
@@ -111,6 +112,7 @@
 	ops->disable_slot = disable_slot;
 	ops->get_power_status = get_power_status;
 	ops->get_adapter_status = get_adapter_status;
+	ops->reset_slot = reset_slot;
 	if (MRL_SENS(ctrl))
 		ops->get_latch_status = get_latch_status;
 	if (ATTN_LED(ctrl)) {
@@ -223,6 +225,16 @@
 	return pciehp_get_adapter_status(slot, value);
 }
 
+static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)
+{
+	struct slot *slot = hotplug_slot->private;
+
+	ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
+		 __func__, slot_name(slot));
+
+	return pciehp_reset_slot(slot, probe);
+}
+
 static int pciehp_probe(struct pcie_device *dev)
 {
 	int rc;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b225573..51f56ef 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -749,6 +749,37 @@
 		ctrl_warn(ctrl, "Cannot disable software notification\n");
 }
 
+/*
+ * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
+ * bus reset of the bridge, but if the slot supports surprise removal we need
+ * to disable presence detection around the bus reset and clear any spurious
+ * events after.
+ */
+int pciehp_reset_slot(struct slot *slot, int probe)
+{
+	struct controller *ctrl = slot->ctrl;
+
+	if (probe)
+		return 0;
+
+	if (HP_SUPR_RM(ctrl)) {
+		pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
+		if (pciehp_poll_mode)
+			del_timer_sync(&ctrl->poll_timer);
+	}
+
+	pci_reset_bridge_secondary_bus(ctrl->pcie->port);
+
+	if (HP_SUPR_RM(ctrl)) {
+		pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDC);
+		pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
+		if (pciehp_poll_mode)
+			int_poll_timeout(ctrl->poll_timer.data);
+	}
+
+	return 0;
+}
+
 int pcie_init_notification(struct controller *ctrl)
 {
 	if (pciehp_request_irq(ctrl))
diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c
index fec2d5b..16f9203 100644
--- a/drivers/pci/hotplug/pcihp_slot.c
+++ b/drivers/pci/hotplug/pcihp_slot.c
@@ -160,9 +160,8 @@
 			(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
 		return;
 
-	if (dev->bus && dev->bus->self)
-		pcie_bus_configure_settings(dev->bus,
-					    dev->bus->self->pcie_mpss);
+	if (dev->bus)
+		pcie_bus_configure_settings(dev->bus);
 
 	memset(&hpp, 0, sizeof(hpp));
 	ret = pci_get_hp_params(dev, &hpp);
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index ea3fa90..66e505c 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -79,8 +79,6 @@
 	if (rc)
 		goto out_deconfigure;
 
-	slot->zdev->state = ZPCI_FN_STATE_ONLINE;
-
 	pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
 	pci_bus_add_devices(slot->zdev->bus);
 
@@ -148,7 +146,7 @@
 	.get_adapter_status =	get_adapter_status,
 };
 
-static int init_pci_slot(struct zpci_dev *zdev)
+int zpci_init_slot(struct zpci_dev *zdev)
 {
 	struct hotplug_slot *hotplug_slot;
 	struct hotplug_slot_info *info;
@@ -202,7 +200,7 @@
 	return -ENOMEM;
 }
 
-static void exit_pci_slot(struct zpci_dev *zdev)
+void zpci_exit_slot(struct zpci_dev *zdev)
 {
 	struct list_head *tmp, *n;
 	struct slot *slot;
@@ -215,60 +213,3 @@
 		pci_hp_deregister(slot->hotplug_slot);
 	}
 }
-
-static struct pci_hp_callback_ops hp_ops = {
-	.create_slot = init_pci_slot,
-	.remove_slot = exit_pci_slot,
-};
-
-static void __init init_pci_slots(void)
-{
-	struct zpci_dev *zdev;
-
-	/*
-	 * Create a structure for each slot, and register that slot
-	 * with the pci_hotplug subsystem.
-	 */
-	mutex_lock(&zpci_list_lock);
-	list_for_each_entry(zdev, &zpci_list, entry) {
-		init_pci_slot(zdev);
-	}
-	mutex_unlock(&zpci_list_lock);
-}
-
-static void __exit exit_pci_slots(void)
-{
-	struct list_head *tmp, *n;
-	struct slot *slot;
-
-	/*
-	 * Unregister all of our slots with the pci_hotplug subsystem.
-	 * Memory will be freed in release_slot() callback after slot's
-	 * lifespan is finished.
-	 */
-	list_for_each_safe(tmp, n, &s390_hotplug_slot_list) {
-		slot = list_entry(tmp, struct slot, slot_list);
-		list_del(&slot->slot_list);
-		pci_hp_deregister(slot->hotplug_slot);
-	}
-}
-
-static int __init pci_hotplug_s390_init(void)
-{
-	if (!s390_pci_probe)
-		return -EOPNOTSUPP;
-
-	zpci_register_hp_ops(&hp_ops);
-	init_pci_slots();
-
-	return 0;
-}
-
-static void __exit pci_hotplug_s390_exit(void)
-{
-	exit_pci_slots();
-	zpci_deregister_hp_ops();
-}
-
-module_init(pci_hotplug_s390_init);
-module_exit(pci_hotplug_s390_exit);
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index de8ffac..21a7182 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -286,7 +286,6 @@
 	    (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
 		return -EINVAL;
 
-	pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
 	pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset);
 	pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride);
 	if (!offset || (nr_virtfn > 1 && !stride))
@@ -324,7 +323,7 @@
 
 		if (!pdev->is_physfn) {
 			pci_dev_put(pdev);
-			return -ENODEV;
+			return -ENOSYS;
 		}
 
 		rc = sysfs_create_link(&dev->dev.kobj,
@@ -334,6 +333,7 @@
 			return rc;
 	}
 
+	pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
 	iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
 	pci_cfg_access_lock(dev);
 	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
@@ -368,6 +368,7 @@
 	iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
 	pci_cfg_access_lock(dev);
 	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+	pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 0);
 	ssleep(1);
 	pci_cfg_access_unlock(dev);
 
@@ -401,6 +402,7 @@
 		sysfs_remove_link(&dev->dev.kobj, "dep_link");
 
 	iov->num_VFs = 0;
+	pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 0);
 }
 
 static int sriov_init(struct pci_dev *dev, int pos)
@@ -662,7 +664,7 @@
 	might_sleep();
 
 	if (!dev->is_physfn)
-		return -ENODEV;
+		return -ENOSYS;
 
 	return sriov_enable(dev, nr_virtfn);
 }
@@ -722,7 +724,7 @@
  * @dev: the PCI device
  *
  * Returns number of VFs belonging to this device that are assigned to a guest.
- * If device is not a physical function returns -ENODEV.
+ * If device is not a physical function returns 0.
  */
 int pci_vfs_assigned(struct pci_dev *dev)
 {
@@ -767,12 +769,15 @@
  * device's mutex held.
  *
  * Returns 0 if PF is an SRIOV-capable device and
- * value of numvfs valid. If not a PF with VFS, return -EINVAL;
+ * value of numvfs valid. If not a PF return -ENOSYS;
+ * if numvfs is invalid return -EINVAL;
  * if VFs already enabled, return -EBUSY.
  */
 int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
 {
-	if (!dev->is_physfn || (numvfs > dev->sriov->total_VFs))
+	if (!dev->is_physfn)
+		return -ENOSYS;
+	if (numvfs > dev->sriov->total_VFs)
 		return -EINVAL;
 
 	/* Shouldn't change if VFs already enabled */
@@ -786,17 +791,17 @@
 EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs);
 
 /**
- * pci_sriov_get_totalvfs -- get total VFs supported on this devic3
+ * pci_sriov_get_totalvfs -- get total VFs supported on this device
  * @dev: the PCI PF device
  *
  * For a PCIe device with SRIOV support, return the PCIe
  * SRIOV capability value of TotalVFs or the value of driver_max_VFs
- * if the driver reduced it.  Otherwise, -EINVAL.
+ * if the driver reduced it.  Otherwise 0.
  */
 int pci_sriov_get_totalvfs(struct pci_dev *dev)
 {
 	if (!dev->is_physfn)
-		return -EINVAL;
+		return 0;
 
 	if (dev->sriov->driver_max_VFs)
 		return dev->sriov->driver_max_VFs;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 01e264f..7c29ee4 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -210,7 +210,7 @@
 	}
 
 	if (!error)
-		dev_info(&dev->dev, "power state changed by ACPI to %s\n",
+		dev_dbg(&dev->dev, "power state changed by ACPI to %s\n",
 			 acpi_power_state_string(state_conv[state]));
 
 	return error;
@@ -290,24 +290,16 @@
 
 void acpi_pci_add_bus(struct pci_bus *bus)
 {
-	acpi_handle handle = NULL;
-
-	if (bus->bridge)
-		handle = ACPI_HANDLE(bus->bridge);
-	if (acpi_pci_disabled || handle == NULL)
+	if (acpi_pci_disabled || !bus->bridge)
 		return;
 
-	acpi_pci_slot_enumerate(bus, handle);
-	acpiphp_enumerate_slots(bus, handle);
+	acpi_pci_slot_enumerate(bus);
+	acpiphp_enumerate_slots(bus);
 }
 
 void acpi_pci_remove_bus(struct pci_bus *bus)
 {
-	/*
-	 * bus->bridge->acpi_node.handle has already been reset to NULL
-	 * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
-	 */
-	if (acpi_pci_disabled)
+	if (acpi_pci_disabled || !bus->bridge)
 		return;
 
 	acpiphp_remove_slots(bus);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e6515e2..98f7b9b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -763,6 +763,13 @@
 
 #ifdef CONFIG_HIBERNATE_CALLBACKS
 
+
+/*
+ * pcibios_pm_ops - provide arch-specific hooks when a PCI device is doing
+ * a hibernate transition
+ */
+struct dev_pm_ops __weak pcibios_pm_ops;
+
 static int pci_pm_freeze(struct device *dev)
 {
 	struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -786,6 +793,9 @@
 			return error;
 	}
 
+	if (pcibios_pm_ops.freeze)
+		return pcibios_pm_ops.freeze(dev);
+
 	return 0;
 }
 
@@ -811,6 +821,9 @@
 
 	pci_pm_set_unknown_state(pci_dev);
 
+	if (pcibios_pm_ops.freeze_noirq)
+		return pcibios_pm_ops.freeze_noirq(dev);
+
 	return 0;
 }
 
@@ -820,6 +833,12 @@
 	struct device_driver *drv = dev->driver;
 	int error = 0;
 
+	if (pcibios_pm_ops.thaw_noirq) {
+		error = pcibios_pm_ops.thaw_noirq(dev);
+		if (error)
+			return error;
+	}
+
 	if (pci_has_legacy_pm_support(pci_dev))
 		return pci_legacy_resume_early(dev);
 
@@ -837,6 +856,12 @@
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 	int error = 0;
 
+	if (pcibios_pm_ops.thaw) {
+		error = pcibios_pm_ops.thaw(dev);
+		if (error)
+			return error;
+	}
+
 	if (pci_has_legacy_pm_support(pci_dev))
 		return pci_legacy_resume(dev);
 
@@ -878,6 +903,9 @@
  Fixup:
 	pci_fixup_device(pci_fixup_suspend, pci_dev);
 
+	if (pcibios_pm_ops.poweroff)
+		return pcibios_pm_ops.poweroff(dev);
+
 	return 0;
 }
 
@@ -911,6 +939,9 @@
 	if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
 		pci_write_config_word(pci_dev, PCI_COMMAND, 0);
 
+	if (pcibios_pm_ops.poweroff_noirq)
+		return pcibios_pm_ops.poweroff_noirq(dev);
+
 	return 0;
 }
 
@@ -920,6 +951,12 @@
 	struct device_driver *drv = dev->driver;
 	int error = 0;
 
+	if (pcibios_pm_ops.restore_noirq) {
+		error = pcibios_pm_ops.restore_noirq(dev);
+		if (error)
+			return error;
+	}
+
 	pci_pm_default_resume_early(pci_dev);
 
 	if (pci_has_legacy_pm_support(pci_dev))
@@ -937,6 +974,12 @@
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 	int error = 0;
 
+	if (pcibios_pm_ops.restore) {
+		error = pcibios_pm_ops.restore(dev);
+		if (error)
+			return error;
+	}
+
 	/*
 	 * This is necessary for the hibernation error path in which restore is
 	 * called without restoring the standard config registers of the device.
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index c0dbe1f..7128cfd 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -131,19 +131,19 @@
 	return ret;
 }
 
-static inline ssize_t pci_bus_show_cpumaskaffinity(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
+static ssize_t cpuaffinity_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	return pci_bus_show_cpuaffinity(dev, 0, attr, buf);
 }
+static DEVICE_ATTR_RO(cpuaffinity);
 
-static inline ssize_t pci_bus_show_cpulistaffinity(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
+static ssize_t cpulistaffinity_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
 {
 	return pci_bus_show_cpuaffinity(dev, 1, attr, buf);
 }
+static DEVICE_ATTR_RO(cpulistaffinity);
 
 /* show resources */
 static ssize_t
@@ -379,6 +379,7 @@
 	}
 	return count;
 }
+static DEVICE_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store);
 
 #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
 static ssize_t d3cold_allowed_store(struct device *dev,
@@ -514,11 +515,20 @@
 	__ATTR_NULL,
 };
 
-struct device_attribute pcibus_dev_attrs[] = {
-	__ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
-	__ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL),
-	__ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL),
-	__ATTR_NULL,
+static struct attribute *pcibus_attrs[] = {
+	&dev_attr_rescan.attr,
+	&dev_attr_cpuaffinity.attr,
+	&dev_attr_cpulistaffinity.attr,
+	NULL,
+};
+
+static const struct attribute_group pcibus_group = {
+	.attrs = pcibus_attrs,
+};
+
+const struct attribute_group *pcibus_groups[] = {
+	&pcibus_group,
+	NULL,
 };
 
 static ssize_t
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e37fea6..b821a62 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/pci_hotplug.h>
 #include <asm-generic/pci-bridge.h>
 #include <asm/setup.h>
 #include "pci.h"
@@ -1145,6 +1146,24 @@
 	return 0;
 }
 
+static void pci_enable_bridge(struct pci_dev *dev)
+{
+	int retval;
+
+	if (!dev)
+		return;
+
+	pci_enable_bridge(dev->bus->self);
+
+	if (pci_is_enabled(dev))
+		return;
+	retval = pci_enable_device(dev);
+	if (retval)
+		dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n",
+			retval);
+	pci_set_master(dev);
+}
+
 static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
 {
 	int err;
@@ -1165,6 +1184,8 @@
 	if (atomic_inc_return(&dev->enable_cnt) > 1)
 		return 0;		/* already enabled */
 
+	pci_enable_bridge(dev->bus->self);
+
 	/* only skip sriov related */
 	for (i = 0; i <= PCI_ROM_RESOURCE; i++)
 		if (dev->resource[i].flags & flags)
@@ -1992,7 +2013,7 @@
 }
 
 /**
- * pci_add_save_buffer - allocate buffer for saving given capability registers
+ * pci_add_cap_save_buffer - allocate buffer for saving given capability registers
  * @dev: the PCI device
  * @cap: the capability to allocate the buffer for
  * @size: requested size of the buffer
@@ -2095,9 +2116,9 @@
 	u16 ctrl = 0;
 
 	if (type & PCI_EXP_IDO_REQUEST)
-		ctrl |= PCI_EXP_IDO_REQ_EN;
+		ctrl |= PCI_EXP_DEVCTL2_IDO_REQ_EN;
 	if (type & PCI_EXP_IDO_COMPLETION)
-		ctrl |= PCI_EXP_IDO_CMP_EN;
+		ctrl |= PCI_EXP_DEVCTL2_IDO_CMP_EN;
 	if (ctrl)
 		pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, ctrl);
 }
@@ -2113,9 +2134,9 @@
 	u16 ctrl = 0;
 
 	if (type & PCI_EXP_IDO_REQUEST)
-		ctrl |= PCI_EXP_IDO_REQ_EN;
+		ctrl |= PCI_EXP_DEVCTL2_IDO_REQ_EN;
 	if (type & PCI_EXP_IDO_COMPLETION)
-		ctrl |= PCI_EXP_IDO_CMP_EN;
+		ctrl |= PCI_EXP_DEVCTL2_IDO_CMP_EN;
 	if (ctrl)
 		pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, ctrl);
 }
@@ -2147,7 +2168,7 @@
 	int ret;
 
 	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
-	if (!(cap & PCI_EXP_OBFF_MASK))
+	if (!(cap & PCI_EXP_DEVCAP2_OBFF_MASK))
 		return -ENOTSUPP; /* no OBFF support at all */
 
 	/* Make sure the topology supports OBFF as well */
@@ -2158,17 +2179,17 @@
 	}
 
 	pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &ctrl);
-	if (cap & PCI_EXP_OBFF_WAKE)
-		ctrl |= PCI_EXP_OBFF_WAKE_EN;
+	if (cap & PCI_EXP_DEVCAP2_OBFF_WAKE)
+		ctrl |= PCI_EXP_DEVCTL2_OBFF_WAKE_EN;
 	else {
 		switch (type) {
 		case PCI_EXP_OBFF_SIGNAL_L0:
-			if (!(ctrl & PCI_EXP_OBFF_WAKE_EN))
-				ctrl |= PCI_EXP_OBFF_MSGA_EN;
+			if (!(ctrl & PCI_EXP_DEVCTL2_OBFF_WAKE_EN))
+				ctrl |= PCI_EXP_DEVCTL2_OBFF_MSGA_EN;
 			break;
 		case PCI_EXP_OBFF_SIGNAL_ALWAYS:
-			ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
-			ctrl |= PCI_EXP_OBFF_MSGB_EN;
+			ctrl &= ~PCI_EXP_DEVCTL2_OBFF_WAKE_EN;
+			ctrl |= PCI_EXP_DEVCTL2_OBFF_MSGB_EN;
 			break;
 		default:
 			WARN(1, "bad OBFF signal type\n");
@@ -2189,7 +2210,8 @@
  */
 void pci_disable_obff(struct pci_dev *dev)
 {
-	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_OBFF_WAKE_EN);
+	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
+				   PCI_EXP_DEVCTL2_OBFF_WAKE_EN);
 }
 EXPORT_SYMBOL(pci_disable_obff);
 
@@ -2237,7 +2259,8 @@
 			return ret;
 	}
 
-	return pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_LTR_EN);
+	return pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
+					PCI_EXP_DEVCTL2_LTR_EN);
 }
 EXPORT_SYMBOL(pci_enable_ltr);
 
@@ -2254,7 +2277,8 @@
 	if (!pci_ltr_supported(dev))
 		return;
 
-	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_LTR_EN);
+	pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
+				   PCI_EXP_DEVCTL2_LTR_EN);
 }
 EXPORT_SYMBOL(pci_disable_ltr);
 
@@ -2359,6 +2383,27 @@
 	pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
 }
 
+static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
+{
+	int pos;
+	u16 cap, ctrl;
+
+	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
+	if (!pos)
+		return false;
+
+	/*
+	 * Except for egress control, capabilities are either required
+	 * or only required if controllable.  Features missing from the
+	 * capability field can therefore be assumed as hard-wired enabled.
+	 */
+	pci_read_config_word(pdev, pos + PCI_ACS_CAP, &cap);
+	acs_flags &= (cap | PCI_ACS_EC);
+
+	pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
+	return (ctrl & acs_flags) == acs_flags;
+}
+
 /**
  * pci_acs_enabled - test ACS against required flags for a given device
  * @pdev: device to test
@@ -2366,36 +2411,76 @@
  *
  * Return true if the device supports the provided flags.  Automatically
  * filters out flags that are not implemented on multifunction devices.
+ *
+ * Note that this interface checks the effective ACS capabilities of the
+ * device rather than the actual capabilities.  For instance, most single
+ * function endpoints are not required to support ACS because they have no
+ * opportunity for peer-to-peer access.  We therefore return 'true'
+ * regardless of whether the device exposes an ACS capability.  This makes
+ * it much easier for callers of this function to ignore the actual type
+ * or topology of the device when testing ACS support.
  */
 bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
 {
-	int pos, ret;
-	u16 ctrl;
+	int ret;
 
 	ret = pci_dev_specific_acs_enabled(pdev, acs_flags);
 	if (ret >= 0)
 		return ret > 0;
 
+	/*
+	 * Conventional PCI and PCI-X devices never support ACS, either
+	 * effectively or actually.  The shared bus topology implies that
+	 * any device on the bus can receive or snoop DMA.
+	 */
 	if (!pci_is_pcie(pdev))
 		return false;
 
-	/* Filter out flags not applicable to multifunction */
-	if (pdev->multifunction)
-		acs_flags &= (PCI_ACS_RR | PCI_ACS_CR |
-			      PCI_ACS_EC | PCI_ACS_DT);
+	switch (pci_pcie_type(pdev)) {
+	/*
+	 * PCI/X-to-PCIe bridges are not specifically mentioned by the spec,
+	 * but since their primary inteface is PCI/X, we conservatively
+	 * handle them as we would a non-PCIe device.
+	 */
+	case PCI_EXP_TYPE_PCIE_BRIDGE:
+	/*
+	 * PCIe 3.0, 6.12.1 excludes ACS on these devices.  "ACS is never
+	 * applicable... must never implement an ACS Extended Capability...".
+	 * This seems arbitrary, but we take a conservative interpretation
+	 * of this statement.
+	 */
+	case PCI_EXP_TYPE_PCI_BRIDGE:
+	case PCI_EXP_TYPE_RC_EC:
+		return false;
+	/*
+	 * PCIe 3.0, 6.12.1.1 specifies that downstream and root ports should
+	 * implement ACS in order to indicate their peer-to-peer capabilities,
+	 * regardless of whether they are single- or multi-function devices.
+	 */
+	case PCI_EXP_TYPE_DOWNSTREAM:
+	case PCI_EXP_TYPE_ROOT_PORT:
+		return pci_acs_flags_enabled(pdev, acs_flags);
+	/*
+	 * PCIe 3.0, 6.12.1.2 specifies ACS capabilities that should be
+	 * implemented by the remaining PCIe types to indicate peer-to-peer
+	 * capabilities, but only when they are part of a multifunciton
+	 * device.  The footnote for section 6.12 indicates the specific
+	 * PCIe types included here.
+	 */
+	case PCI_EXP_TYPE_ENDPOINT:
+	case PCI_EXP_TYPE_UPSTREAM:
+	case PCI_EXP_TYPE_LEG_END:
+	case PCI_EXP_TYPE_RC_END:
+		if (!pdev->multifunction)
+			break;
 
-	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM ||
-	    pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
-	    pdev->multifunction) {
-		pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ACS);
-		if (!pos)
-			return false;
-
-		pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl);
-		if ((ctrl & acs_flags) != acs_flags)
-			return false;
+		return pci_acs_flags_enabled(pdev, acs_flags);
 	}
 
+	/*
+	 * PCIe 3.0, 6.12.1.3 specifies no ACS capabilties are applicable
+	 * to single function devices with the exception of downstream ports.
+	 */
 	return true;
 }
 
@@ -3059,18 +3144,23 @@
 EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
 
 /**
- * pci_msi_off - disables any msi or msix capabilities
+ * pci_msi_off - disables any MSI or MSI-X capabilities
  * @dev: the PCI device to operate on
  *
- * If you want to use msi see pci_enable_msi and friends.
- * This is a lower level primitive that allows us to disable
- * msi operation at the device level.
+ * If you want to use MSI, see pci_enable_msi() and friends.
+ * This is a lower-level primitive that allows us to disable
+ * MSI operation at the device level.
  */
 void pci_msi_off(struct pci_dev *dev)
 {
 	int pos;
 	u16 control;
 
+	/*
+	 * This looks like it could go in msi.c, but we need it even when
+	 * CONFIG_PCI_MSI=n.  For the same reason, we can't use
+	 * dev->msi_cap or dev->msix_cap here.
+	 */
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 	if (pos) {
 		pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
@@ -3098,19 +3188,17 @@
 }
 EXPORT_SYMBOL(pci_set_dma_seg_boundary);
 
-static int pcie_flr(struct pci_dev *dev, int probe)
+/**
+ * pci_wait_for_pending_transaction - waits for pending transaction
+ * @dev: the PCI device to operate on
+ *
+ * Return 0 if transaction is pending 1 otherwise.
+ */
+int pci_wait_for_pending_transaction(struct pci_dev *dev)
 {
 	int i;
-	u32 cap;
 	u16 status;
 
-	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
-	if (!(cap & PCI_EXP_DEVCAP_FLR))
-		return -ENOTTY;
-
-	if (probe)
-		return 0;
-
 	/* Wait for Transaction Pending bit clean */
 	for (i = 0; i < 4; i++) {
 		if (i)
@@ -3118,13 +3206,27 @@
 
 		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
 		if (!(status & PCI_EXP_DEVSTA_TRPND))
-			goto clear;
+			return 1;
 	}
 
-	dev_err(&dev->dev, "transaction is not cleared; "
-			"proceeding with reset anyway\n");
+	return 0;
+}
+EXPORT_SYMBOL(pci_wait_for_pending_transaction);
 
-clear:
+static int pcie_flr(struct pci_dev *dev, int probe)
+{
+	u32 cap;
+
+	pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
+	if (!(cap & PCI_EXP_DEVCAP_FLR))
+		return -ENOTTY;
+
+	if (probe)
+		return 0;
+
+	if (!pci_wait_for_pending_transaction(dev))
+		dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
+
 	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 
 	msleep(100);
@@ -3215,9 +3317,42 @@
 	return 0;
 }
 
-static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
+/**
+ * pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge.
+ * @dev: Bridge device
+ *
+ * Use the bridge control register to assert reset on the secondary bus.
+ * Devices on the secondary bus are left in power-on state.
+ */
+void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
 {
 	u16 ctrl;
+
+	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+	ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+	/*
+	 * PCI spec v3.0 7.6.4.2 requires minimum Trst of 1ms.  Double
+	 * this to 2ms to ensure that we meet the minium requirement.
+	 */
+	msleep(2);
+
+	ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+	/*
+	 * Trhfa for conventional PCI is 2^25 clock cycles.
+	 * Assuming a minimum 33MHz clock this results in a 1s
+	 * delay before we can consider subordinate devices to
+	 * be re-initialized.  PCIe has some ways to shorten this,
+	 * but we don't make use of them yet.
+	 */
+	ssleep(1);
+}
+EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
+
+static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
+{
 	struct pci_dev *pdev;
 
 	if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self)
@@ -3230,18 +3365,40 @@
 	if (probe)
 		return 0;
 
-	pci_read_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, &ctrl);
-	ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
-	pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl);
-	msleep(100);
-
-	ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-	pci_write_config_word(dev->bus->self, PCI_BRIDGE_CONTROL, ctrl);
-	msleep(100);
+	pci_reset_bridge_secondary_bus(dev->bus->self);
 
 	return 0;
 }
 
+static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
+{
+	int rc = -ENOTTY;
+
+	if (!hotplug || !try_module_get(hotplug->ops->owner))
+		return rc;
+
+	if (hotplug->ops->reset_slot)
+		rc = hotplug->ops->reset_slot(hotplug, probe);
+
+	module_put(hotplug->ops->owner);
+
+	return rc;
+}
+
+static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
+{
+	struct pci_dev *pdev;
+
+	if (dev->subordinate || !dev->slot)
+		return -ENOTTY;
+
+	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
+		if (pdev != dev && pdev->slot == dev->slot)
+			return -ENOTTY;
+
+	return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
+}
+
 static int __pci_dev_reset(struct pci_dev *dev, int probe)
 {
 	int rc;
@@ -3264,27 +3421,65 @@
 	if (rc != -ENOTTY)
 		goto done;
 
+	rc = pci_dev_reset_slot_function(dev, probe);
+	if (rc != -ENOTTY)
+		goto done;
+
 	rc = pci_parent_bus_reset(dev, probe);
 done:
 	return rc;
 }
 
+static void pci_dev_lock(struct pci_dev *dev)
+{
+	pci_cfg_access_lock(dev);
+	/* block PM suspend, driver probe, etc. */
+	device_lock(&dev->dev);
+}
+
+static void pci_dev_unlock(struct pci_dev *dev)
+{
+	device_unlock(&dev->dev);
+	pci_cfg_access_unlock(dev);
+}
+
+static void pci_dev_save_and_disable(struct pci_dev *dev)
+{
+	/*
+	 * Wake-up device prior to save.  PM registers default to D0 after
+	 * reset and a simple register restore doesn't reliably return
+	 * to a non-D0 state anyway.
+	 */
+	pci_set_power_state(dev, PCI_D0);
+
+	pci_save_state(dev);
+	/*
+	 * Disable the device by clearing the Command register, except for
+	 * INTx-disable which is set.  This not only disables MMIO and I/O port
+	 * BARs, but also prevents the device from being Bus Master, preventing
+	 * DMA from the device including MSI/MSI-X interrupts.  For PCI 2.3
+	 * compliant devices, INTx-disable prevents legacy interrupts.
+	 */
+	pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
+}
+
+static void pci_dev_restore(struct pci_dev *dev)
+{
+	pci_restore_state(dev);
+}
+
 static int pci_dev_reset(struct pci_dev *dev, int probe)
 {
 	int rc;
 
-	if (!probe) {
-		pci_cfg_access_lock(dev);
-		/* block PM suspend, driver probe, etc. */
-		device_lock(&dev->dev);
-	}
+	if (!probe)
+		pci_dev_lock(dev);
 
 	rc = __pci_dev_reset(dev, probe);
 
-	if (!probe) {
-		device_unlock(&dev->dev);
-		pci_cfg_access_unlock(dev);
-	}
+	if (!probe)
+		pci_dev_unlock(dev);
+
 	return rc;
 }
 /**
@@ -3375,22 +3570,249 @@
 	if (rc)
 		return rc;
 
-	pci_save_state(dev);
-
-	/*
-	 * both INTx and MSI are disabled after the Interrupt Disable bit
-	 * is set and the Bus Master bit is cleared.
-	 */
-	pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
+	pci_dev_save_and_disable(dev);
 
 	rc = pci_dev_reset(dev, 0);
 
-	pci_restore_state(dev);
+	pci_dev_restore(dev);
 
 	return rc;
 }
 EXPORT_SYMBOL_GPL(pci_reset_function);
 
+/* Lock devices from the top of the tree down */
+static void pci_bus_lock(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_dev_lock(dev);
+		if (dev->subordinate)
+			pci_bus_lock(dev->subordinate);
+	}
+}
+
+/* Unlock devices from the bottom of the tree up */
+static void pci_bus_unlock(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		if (dev->subordinate)
+			pci_bus_unlock(dev->subordinate);
+		pci_dev_unlock(dev);
+	}
+}
+
+/* Lock devices from the top of the tree down */
+static void pci_slot_lock(struct pci_slot *slot)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+		if (!dev->slot || dev->slot != slot)
+			continue;
+		pci_dev_lock(dev);
+		if (dev->subordinate)
+			pci_bus_lock(dev->subordinate);
+	}
+}
+
+/* Unlock devices from the bottom of the tree up */
+static void pci_slot_unlock(struct pci_slot *slot)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+		if (!dev->slot || dev->slot != slot)
+			continue;
+		if (dev->subordinate)
+			pci_bus_unlock(dev->subordinate);
+		pci_dev_unlock(dev);
+	}
+}
+
+/* Save and disable devices from the top of the tree down */
+static void pci_bus_save_and_disable(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_dev_save_and_disable(dev);
+		if (dev->subordinate)
+			pci_bus_save_and_disable(dev->subordinate);
+	}
+}
+
+/*
+ * Restore devices from top of the tree down - parent bridges need to be
+ * restored before we can get to subordinate devices.
+ */
+static void pci_bus_restore(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		pci_dev_restore(dev);
+		if (dev->subordinate)
+			pci_bus_restore(dev->subordinate);
+	}
+}
+
+/* Save and disable devices from the top of the tree down */
+static void pci_slot_save_and_disable(struct pci_slot *slot)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+		if (!dev->slot || dev->slot != slot)
+			continue;
+		pci_dev_save_and_disable(dev);
+		if (dev->subordinate)
+			pci_bus_save_and_disable(dev->subordinate);
+	}
+}
+
+/*
+ * Restore devices from top of the tree down - parent bridges need to be
+ * restored before we can get to subordinate devices.
+ */
+static void pci_slot_restore(struct pci_slot *slot)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+		if (!dev->slot || dev->slot != slot)
+			continue;
+		pci_dev_restore(dev);
+		if (dev->subordinate)
+			pci_bus_restore(dev->subordinate);
+	}
+}
+
+static int pci_slot_reset(struct pci_slot *slot, int probe)
+{
+	int rc;
+
+	if (!slot)
+		return -ENOTTY;
+
+	if (!probe)
+		pci_slot_lock(slot);
+
+	might_sleep();
+
+	rc = pci_reset_hotplug_slot(slot->hotplug, probe);
+
+	if (!probe)
+		pci_slot_unlock(slot);
+
+	return rc;
+}
+
+/**
+ * pci_probe_reset_slot - probe whether a PCI slot can be reset
+ * @slot: PCI slot to probe
+ *
+ * Return 0 if slot can be reset, negative if a slot reset is not supported.
+ */
+int pci_probe_reset_slot(struct pci_slot *slot)
+{
+	return pci_slot_reset(slot, 1);
+}
+EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
+
+/**
+ * pci_reset_slot - reset a PCI slot
+ * @slot: PCI slot to reset
+ *
+ * A PCI bus may host multiple slots, each slot may support a reset mechanism
+ * independent of other slots.  For instance, some slots may support slot power
+ * control.  In the case of a 1:1 bus to slot architecture, this function may
+ * wrap the bus reset to avoid spurious slot related events such as hotplug.
+ * Generally a slot reset should be attempted before a bus reset.  All of the
+ * function of the slot and any subordinate buses behind the slot are reset
+ * through this function.  PCI config space of all devices in the slot and
+ * behind the slot is saved before and restored after reset.
+ *
+ * Return 0 on success, non-zero on error.
+ */
+int pci_reset_slot(struct pci_slot *slot)
+{
+	int rc;
+
+	rc = pci_slot_reset(slot, 1);
+	if (rc)
+		return rc;
+
+	pci_slot_save_and_disable(slot);
+
+	rc = pci_slot_reset(slot, 0);
+
+	pci_slot_restore(slot);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pci_reset_slot);
+
+static int pci_bus_reset(struct pci_bus *bus, int probe)
+{
+	if (!bus->self)
+		return -ENOTTY;
+
+	if (probe)
+		return 0;
+
+	pci_bus_lock(bus);
+
+	might_sleep();
+
+	pci_reset_bridge_secondary_bus(bus->self);
+
+	pci_bus_unlock(bus);
+
+	return 0;
+}
+
+/**
+ * pci_probe_reset_bus - probe whether a PCI bus can be reset
+ * @bus: PCI bus to probe
+ *
+ * Return 0 if bus can be reset, negative if a bus reset is not supported.
+ */
+int pci_probe_reset_bus(struct pci_bus *bus)
+{
+	return pci_bus_reset(bus, 1);
+}
+EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
+
+/**
+ * pci_reset_bus - reset a PCI bus
+ * @bus: top level PCI bus to reset
+ *
+ * Do a bus reset on the given bus and any subordinate buses, saving
+ * and restoring state of all devices.
+ *
+ * Return 0 on success, non-zero on error.
+ */
+int pci_reset_bus(struct pci_bus *bus)
+{
+	int rc;
+
+	rc = pci_bus_reset(bus, 1);
+	if (rc)
+		return rc;
+
+	pci_bus_save_and_disable(bus);
+
+	rc = pci_bus_reset(bus, 0);
+
+	pci_bus_restore(bus);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(pci_reset_bus);
+
 /**
  * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
  * @dev: PCI device to query
@@ -3525,8 +3947,6 @@
 	if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
 		int mps = pcie_get_mps(dev);
 
-		if (mps < 0)
-			return mps;
 		if (mps < rq)
 			rq = mps;
 	}
@@ -3543,7 +3963,6 @@
  * @dev: PCI device to query
  *
  * Returns maximum payload size in bytes
- *    or appropriate error value.
  */
 int pcie_get_mps(struct pci_dev *dev)
 {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d1182c4..816c297 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -151,7 +151,7 @@
 
 }
 extern struct device_attribute pci_dev_attrs[];
-extern struct device_attribute pcibus_dev_attrs[];
+extern const struct attribute_group *pcibus_groups[];
 extern struct device_type pci_dev_type;
 extern struct bus_attribute pci_bus_attrs[];
 
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 3b94cfc..7958e59 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -2,7 +2,7 @@
 # PCI Express Port Bus Configuration
 #
 config PCIEPORTBUS
-	bool "PCI Express support"
+	bool "PCI Express Port Bus support"
 	depends on PCI
 	help
 	  This automatically enables PCI Express Port Bus support. Users can
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 76ef634..0bf82a2 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -352,7 +352,7 @@
 	reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
 	pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
 
-	aer_do_secondary_bus_reset(dev);
+	pci_reset_bridge_secondary_bus(dev);
 	dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
 
 	/* Clear Root Error Status */
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 90ea3e8..84420b7 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -106,7 +106,6 @@
 }
 
 extern struct bus_type pcie_port_bus_type;
-void aer_do_secondary_bus_reset(struct pci_dev *dev);
 int aer_init(struct pcie_device *dev);
 void aer_isr(struct work_struct *work);
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 8b68ae5..85ca36f 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -367,39 +367,6 @@
 }
 
 /**
- * aer_do_secondary_bus_reset - perform secondary bus reset
- * @dev: pointer to bridge's pci_dev data structure
- *
- * Invoked when performing link reset at Root Port or Downstream Port.
- */
-void aer_do_secondary_bus_reset(struct pci_dev *dev)
-{
-	u16 p2p_ctrl;
-
-	/* Assert Secondary Bus Reset */
-	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
-	p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
-	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
-
-	/*
-	 * we should send hot reset message for 2ms to allow it time to
-	 * propagate to all downstream ports
-	 */
-	msleep(2);
-
-	/* De-assert Secondary Bus Reset */
-	p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
-	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
-
-	/*
-	 * System software must wait for at least 100ms from the end
-	 * of a reset of one or more device before it is permitted
-	 * to issue Configuration Requests to those devices.
-	 */
-	msleep(200);
-}
-
-/**
  * default_reset_link - default reset function
  * @dev: pointer to pci_dev data structure
  *
@@ -408,7 +375,7 @@
  */
 static pci_ers_result_t default_reset_link(struct pci_dev *dev)
 {
-	aer_do_secondary_bus_reset(dev);
+	pci_reset_bridge_secondary_bus(dev);
 	dev_printk(KERN_DEBUG, &dev->dev, "downstream link has been reset\n");
 	return PCI_ERS_RESULT_RECOVERED;
 }
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 46ada5c..eeb50bd 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -96,7 +96,7 @@
 static struct class pcibus_class = {
 	.name		= "pci_bus",
 	.dev_release	= &release_pcibus_dev,
-	.dev_attrs	= pcibus_dev_attrs,
+	.dev_groups	= pcibus_groups,
 };
 
 static int __init pcibus_class_init(void)
@@ -156,6 +156,8 @@
 	return flags;
 }
 
+#define PCI_COMMAND_DECODE_ENABLE	(PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+
 /**
  * pci_read_base - read a PCI BAR
  * @dev: the PCI device
@@ -178,8 +180,10 @@
 	/* No printks while decoding is disabled! */
 	if (!dev->mmio_always_on) {
 		pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
-		pci_write_config_word(dev, PCI_COMMAND,
-			orig_cmd & ~(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
+		if (orig_cmd & PCI_COMMAND_DECODE_ENABLE) {
+			pci_write_config_word(dev, PCI_COMMAND,
+				orig_cmd & ~PCI_COMMAND_DECODE_ENABLE);
+		}
 	}
 
 	res->name = pci_name(dev);
@@ -293,7 +297,8 @@
 fail:
 	res->flags = 0;
 out:
-	if (!dev->mmio_always_on)
+	if (!dev->mmio_always_on &&
+	    (orig_cmd & PCI_COMMAND_DECODE_ENABLE))
 		pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
 
 	if (bar_too_big)
@@ -1491,24 +1496,23 @@
 	if (!pci_is_pcie(dev))
 		return 0;
 
-	/* For PCIE hotplug enabled slots not connected directly to a
-	 * PCI-E root port, there can be problems when hotplugging
-	 * devices.  This is due to the possibility of hotplugging a
-	 * device into the fabric with a smaller MPS that the devices
-	 * currently running have configured.  Modifying the MPS on the
-	 * running devices could cause a fatal bus error due to an
-	 * incoming frame being larger than the newly configured MPS.
-	 * To work around this, the MPS for the entire fabric must be
-	 * set to the minimum size.  Any devices hotplugged into this
-	 * fabric will have the minimum MPS set.  If the PCI hotplug
-	 * slot is directly connected to the root port and there are not
-	 * other devices on the fabric (which seems to be the most
-	 * common case), then this is not an issue and MPS discovery
-	 * will occur as normal.
+	/*
+	 * We don't have a way to change MPS settings on devices that have
+	 * drivers attached.  A hot-added device might support only the minimum
+	 * MPS setting (MPS=128).  Therefore, if the fabric contains a bridge
+	 * where devices may be hot-added, we limit the fabric MPS to 128 so
+	 * hot-added devices will work correctly.
+	 *
+	 * However, if we hot-add a device to a slot directly below a Root
+	 * Port, it's impossible for there to be other existing devices below
+	 * the port.  We don't limit the MPS in this case because we can
+	 * reconfigure MPS on both the Root Port and the hot-added device,
+	 * and there are no other devices involved.
+	 *
+	 * Note that this PCIE_BUS_SAFE path assumes no peer-to-peer DMA.
 	 */
-	if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) ||
-	     (dev->bus->self &&
-	      pci_pcie_type(dev->bus->self) != PCI_EXP_TYPE_ROOT_PORT)))
+	if (dev->is_hotplug_bridge &&
+	    pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT)
 		*smpss = 0;
 
 	if (*smpss > dev->pcie_mpss)
@@ -1583,6 +1587,22 @@
 			"with pci=pcie_bus_safe.\n");
 }
 
+static void pcie_bus_detect_mps(struct pci_dev *dev)
+{
+	struct pci_dev *bridge = dev->bus->self;
+	int mps, p_mps;
+
+	if (!bridge)
+		return;
+
+	mps = pcie_get_mps(dev);
+	p_mps = pcie_get_mps(bridge);
+
+	if (mps != p_mps)
+		dev_warn(&dev->dev, "Max Payload Size %d, but upstream %s set to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n",
+			 mps, pci_name(bridge), p_mps);
+}
+
 static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
 {
 	int mps, orig_mps;
@@ -1590,13 +1610,18 @@
 	if (!pci_is_pcie(dev))
 		return 0;
 
+	if (pcie_bus_config == PCIE_BUS_TUNE_OFF) {
+		pcie_bus_detect_mps(dev);
+		return 0;
+	}
+
 	mps = 128 << *(u8 *)data;
 	orig_mps = pcie_get_mps(dev);
 
 	pcie_write_mps(dev, mps);
 	pcie_write_mrrs(dev);
 
-	dev_info(&dev->dev, "PCI-E Max Payload Size set to %4d/%4d (was %4d), "
+	dev_info(&dev->dev, "Max Payload Size set to %4d/%4d (was %4d), "
 		 "Max Read Rq %4d\n", pcie_get_mps(dev), 128 << dev->pcie_mpss,
 		 orig_mps, pcie_get_readrq(dev));
 
@@ -1607,25 +1632,25 @@
  * parents then children fashion.  If this changes, then this code will not
  * work as designed.
  */
-void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
+void pcie_bus_configure_settings(struct pci_bus *bus)
 {
 	u8 smpss;
 
+	if (!bus->self)
+		return;
+
 	if (!pci_is_pcie(bus->self))
 		return;
 
-	if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
-		return;
-
 	/* FIXME - Peer to peer DMA is possible, though the endpoint would need
-	 * to be aware to the MPS of the destination.  To work around this,
+	 * to be aware of the MPS of the destination.  To work around this,
 	 * simply force the MPS of the entire system to the smallest possible.
 	 */
 	if (pcie_bus_config == PCIE_BUS_PEER2PEER)
 		smpss = 0;
 
 	if (pcie_bus_config == PCIE_BUS_SAFE) {
-		smpss = mpss;
+		smpss = bus->self->pcie_mpss;
 
 		pcie_find_smpss(bus->self, &smpss);
 		pci_walk_bus(bus, pcie_find_smpss, &smpss);
@@ -1979,7 +2004,6 @@
 
 	max = pci_scan_child_bus(bus);
 	pci_assign_unassigned_bus_resources(bus);
-	pci_enable_bridges(bus);
 	pci_bus_add_devices(bus);
 
 	return max;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e85d230..f6c31fa 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3126,9 +3126,6 @@
 
 static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe)
 {
-	int i;
-	u16 status;
-
 	/*
 	 * http://www.intel.com/content/dam/doc/datasheet/82599-10-gbe-controller-datasheet.pdf
 	 *
@@ -3140,20 +3137,9 @@
 	if (probe)
 		return 0;
 
-	/* Wait for Transaction Pending bit clean */
-	for (i = 0; i < 4; i++) {
-		if (i)
-			msleep((1 << (i - 1)) * 100);
+	if (!pci_wait_for_pending_transaction(dev))
+		dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
 
-		pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
-		if (!(status & PCI_EXP_DEVSTA_TRPND))
-			goto clear;
-	}
-
-	dev_err(&dev->dev, "transaction is not cleared; "
-			"proceeding with reset anyway\n");
-
-clear:
 	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
 
 	msleep(100);
@@ -3208,6 +3194,83 @@
 	return 0;
 }
 
+/*
+ * Device-specific reset method for Chelsio T4-based adapters.
+ */
+static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe)
+{
+	u16 old_command;
+	u16 msix_flags;
+
+	/*
+	 * If this isn't a Chelsio T4-based device, return -ENOTTY indicating
+	 * that we have no device-specific reset method.
+	 */
+	if ((dev->device & 0xf000) != 0x4000)
+		return -ENOTTY;
+
+	/*
+	 * If this is the "probe" phase, return 0 indicating that we can
+	 * reset this device.
+	 */
+	if (probe)
+		return 0;
+
+	/*
+	 * T4 can wedge if there are DMAs in flight within the chip and Bus
+	 * Master has been disabled.  We need to have it on till the Function
+	 * Level Reset completes.  (BUS_MASTER is disabled in
+	 * pci_reset_function()).
+	 */
+	pci_read_config_word(dev, PCI_COMMAND, &old_command);
+	pci_write_config_word(dev, PCI_COMMAND,
+			      old_command | PCI_COMMAND_MASTER);
+
+	/*
+	 * Perform the actual device function reset, saving and restoring
+	 * configuration information around the reset.
+	 */
+	pci_save_state(dev);
+
+	/*
+	 * T4 also suffers a Head-Of-Line blocking problem if MSI-X interrupts
+	 * are disabled when an MSI-X interrupt message needs to be delivered.
+	 * So we briefly re-enable MSI-X interrupts for the duration of the
+	 * FLR.  The pci_restore_state() below will restore the original
+	 * MSI-X state.
+	 */
+	pci_read_config_word(dev, dev->msix_cap+PCI_MSIX_FLAGS, &msix_flags);
+	if ((msix_flags & PCI_MSIX_FLAGS_ENABLE) == 0)
+		pci_write_config_word(dev, dev->msix_cap+PCI_MSIX_FLAGS,
+				      msix_flags |
+				      PCI_MSIX_FLAGS_ENABLE |
+				      PCI_MSIX_FLAGS_MASKALL);
+
+	/*
+	 * Start of pcie_flr() code sequence.  This reset code is a copy of
+	 * the guts of pcie_flr() because that's not an exported function.
+	 */
+
+	if (!pci_wait_for_pending_transaction(dev))
+		dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
+
+	pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
+	msleep(100);
+
+	/*
+	 * End of pcie_flr() code sequence.
+	 */
+
+	/*
+	 * Restore the configuration information (BAR values, etc.) including
+	 * the original PCI Configuration Space Command word, and return
+	 * success.
+	 */
+	pci_restore_state(dev);
+	pci_write_config_word(dev, PCI_COMMAND, old_command);
+	return 0;
+}
+
 #define PCI_DEVICE_ID_INTEL_82599_SFP_VF   0x10ed
 #define PCI_DEVICE_ID_INTEL_IVB_M_VGA      0x0156
 #define PCI_DEVICE_ID_INTEL_IVB_M2_VGA     0x0166
@@ -3221,6 +3284,8 @@
 		reset_ivb_igd },
 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
 		reset_intel_generic_dev },
+	{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+		reset_chelsio_generic_dev },
 	{ 0 }
 };
 
@@ -3295,11 +3360,61 @@
 	return pci_dev_get(dev);
 }
 
+/*
+ * AMD has indicated that the devices below do not support peer-to-peer
+ * in any system where they are found in the southbridge with an AMD
+ * IOMMU in the system.  Multifunction devices that do not support
+ * peer-to-peer between functions can claim to support a subset of ACS.
+ * Such devices effectively enable request redirect (RR) and completion
+ * redirect (CR) since all transactions are redirected to the upstream
+ * root complex.
+ *
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94086
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/94102
+ * http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/99402
+ *
+ * 1002:4385 SBx00 SMBus Controller
+ * 1002:439c SB7x0/SB8x0/SB9x0 IDE Controller
+ * 1002:4383 SBx00 Azalia (Intel HDA)
+ * 1002:439d SB7x0/SB8x0/SB9x0 LPC host controller
+ * 1002:4384 SBx00 PCI to PCI Bridge
+ * 1002:4399 SB7x0/SB8x0/SB9x0 USB OHCI2 Controller
+ */
+static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
+{
+#ifdef CONFIG_ACPI
+	struct acpi_table_header *header = NULL;
+	acpi_status status;
+
+	/* Targeting multifunction devices on the SB (appears on root bus) */
+	if (!dev->multifunction || !pci_is_root_bus(dev->bus))
+		return -ENODEV;
+
+	/* The IVRS table describes the AMD IOMMU */
+	status = acpi_get_table("IVRS", 0, &header);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	/* Filter out flags not applicable to multifunction */
+	acs_flags &= (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC | PCI_ACS_DT);
+
+	return acs_flags & ~(PCI_ACS_RR | PCI_ACS_CR) ? 0 : 1;
+#else
+	return -ENODEV;
+#endif
+}
+
 static const struct pci_dev_acs_enabled {
 	u16 vendor;
 	u16 device;
 	int (*acs_enabled)(struct pci_dev *dev, u16 acs_flags);
 } pci_dev_acs_enabled[] = {
+	{ PCI_VENDOR_ID_ATI, 0x4385, pci_quirk_amd_sb_acs },
+	{ PCI_VENDOR_ID_ATI, 0x439c, pci_quirk_amd_sb_acs },
+	{ PCI_VENDOR_ID_ATI, 0x4383, pci_quirk_amd_sb_acs },
+	{ PCI_VENDOR_ID_ATI, 0x439d, pci_quirk_amd_sb_acs },
+	{ PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs },
+	{ PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs },
 	{ 0 }
 };
 
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 64a7de2..bc26d79 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -814,14 +814,14 @@
 {
 	struct pci_dev *dev;
 	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
-	unsigned long size = 0, size0 = 0, size1 = 0;
+	resource_size_t size = 0, size0 = 0, size1 = 0;
 	resource_size_t children_add_size = 0;
-	resource_size_t min_align, io_align, align;
+	resource_size_t min_align, align;
 
 	if (!b_res)
  		return;
 
-	io_align = min_align = window_alignment(bus, IORESOURCE_IO);
+	min_align = window_alignment(bus, IORESOURCE_IO);
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		int i;
 
@@ -848,9 +848,6 @@
 		}
 	}
 
-	if (min_align > io_align)
-		min_align = io_align;
-
 	size0 = calculate_iosize(size, min_size, size1,
 			resource_size(b_res), min_align);
 	if (children_add_size > add_size)
@@ -874,8 +871,9 @@
 		add_to_list(realloc_head, bus->self, b_res, size1-size0,
 			    min_align);
 		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window "
-				 "%pR to %pR add_size %lx\n", b_res,
-				 &bus->busn_res, size1-size0);
+				 "%pR to %pR add_size %llx\n", b_res,
+				 &bus->busn_res,
+				 (unsigned long long)size1-size0);
 	}
 }
 
@@ -905,6 +903,8 @@
  * pbus_size_mem() - size the memory window of a given bus
  *
  * @bus : the bus
+ * @mask: mask the resource flag, then compare it with type
+ * @type: the type of free resource from bridge
  * @min_size : the minimum memory window that must to be allocated
  * @add_size : additional optional memory window
  * @realloc_head : track the additional memory window on this list
@@ -1364,39 +1364,21 @@
 	}
 }
 
-static int __init pci_bus_get_depth(struct pci_bus *bus)
+static int pci_bus_get_depth(struct pci_bus *bus)
 {
 	int depth = 0;
-	struct pci_dev *dev;
+	struct pci_bus *child_bus;
 
-	list_for_each_entry(dev, &bus->devices, bus_list) {
+	list_for_each_entry(child_bus, &bus->children, node){
 		int ret;
-		struct pci_bus *b = dev->subordinate;
-		if (!b)
-			continue;
 
-		ret = pci_bus_get_depth(b);
+		ret = pci_bus_get_depth(child_bus);
 		if (ret + 1 > depth)
 			depth = ret + 1;
 	}
 
 	return depth;
 }
-static int __init pci_get_max_depth(void)
-{
-	int depth = 0;
-	struct pci_bus *bus;
-
-	list_for_each_entry(bus, &pci_root_buses, node) {
-		int ret;
-
-		ret = pci_bus_get_depth(bus);
-		if (ret > depth)
-			depth = ret;
-	}
-
-	return depth;
-}
 
 /*
  * -1: undefined, will auto detect later
@@ -1413,7 +1395,7 @@
 	auto_enabled,
 };
 
-static enum enable_type pci_realloc_enable __initdata = undefined;
+static enum enable_type pci_realloc_enable = undefined;
 void __init pci_realloc_get_opt(char *str)
 {
 	if (!strncmp(str, "off", 3))
@@ -1421,45 +1403,64 @@
 	else if (!strncmp(str, "on", 2))
 		pci_realloc_enable = user_enabled;
 }
-static bool __init pci_realloc_enabled(void)
+static bool pci_realloc_enabled(enum enable_type enable)
 {
-	return pci_realloc_enable >= user_enabled;
+	return enable >= user_enabled;
 }
 
-static void __init pci_realloc_detect(void)
-{
 #if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO)
-	struct pci_dev *dev = NULL;
+static int iov_resources_unassigned(struct pci_dev *dev, void *data)
+{
+	int i;
+	bool *unassigned = data;
 
-	if (pci_realloc_enable != undefined)
-		return;
+	for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
+		struct resource *r = &dev->resource[i];
+		struct pci_bus_region region;
 
-	for_each_pci_dev(dev) {
-		int i;
+		/* Not assigned or rejected by kernel? */
+		if (!r->flags)
+			continue;
 
-		for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
-			struct resource *r = &dev->resource[i];
-
-			/* Not assigned, or rejected by kernel ? */
-			if (r->flags && !r->start) {
-				pci_realloc_enable = auto_enabled;
-
-				return;
-			}
+		pcibios_resource_to_bus(dev, &region, r);
+		if (!region.start) {
+			*unassigned = true;
+			return 1; /* return early from pci_walk_bus() */
 		}
 	}
-#endif
+
+	return 0;
 }
 
+static enum enable_type pci_realloc_detect(struct pci_bus *bus,
+			 enum enable_type enable_local)
+{
+	bool unassigned = false;
+
+	if (enable_local != undefined)
+		return enable_local;
+
+	pci_walk_bus(bus, iov_resources_unassigned, &unassigned);
+	if (unassigned)
+		return auto_enabled;
+
+	return enable_local;
+}
+#else
+static enum enable_type pci_realloc_detect(struct pci_bus *bus,
+			 enum enable_type enable_local)
+{
+	return enable_local;
+}
+#endif
+
 /*
  * first try will not touch pci bridge res
  * second  and later try will clear small leaf bridge res
  * will stop till to the max  deepth if can not find good one
  */
-void __init
-pci_assign_unassigned_resources(void)
+void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
 {
-	struct pci_bus *bus;
 	LIST_HEAD(realloc_head); /* list of resources that
 					want additional resources */
 	struct list_head *add_list = NULL;
@@ -1470,15 +1471,17 @@
 	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
 				  IORESOURCE_PREFETCH;
 	int pci_try_num = 1;
+	enum enable_type enable_local;
 
 	/* don't realloc if asked to do so */
-	pci_realloc_detect();
-	if (pci_realloc_enabled()) {
-		int max_depth = pci_get_max_depth();
+	enable_local = pci_realloc_detect(bus, pci_realloc_enable);
+	if (pci_realloc_enabled(enable_local)) {
+		int max_depth = pci_bus_get_depth(bus);
 
 		pci_try_num = max_depth + 1;
-		printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
-			 max_depth, pci_try_num);
+		dev_printk(KERN_DEBUG, &bus->dev,
+			   "max bus depth: %d pci_try_num: %d\n",
+			   max_depth, pci_try_num);
 	}
 
 again:
@@ -1490,32 +1493,30 @@
 		add_list = &realloc_head;
 	/* Depth first, calculate sizes and alignments of all
 	   subordinate buses. */
-	list_for_each_entry(bus, &pci_root_buses, node)
-		__pci_bus_size_bridges(bus, add_list);
+	__pci_bus_size_bridges(bus, add_list);
 
 	/* Depth last, allocate resources and update the hardware. */
-	list_for_each_entry(bus, &pci_root_buses, node)
-		__pci_bus_assign_resources(bus, add_list, &fail_head);
+	__pci_bus_assign_resources(bus, add_list, &fail_head);
 	if (add_list)
 		BUG_ON(!list_empty(add_list));
 	tried_times++;
 
 	/* any device complain? */
 	if (list_empty(&fail_head))
-		goto enable_and_dump;
+		goto dump;
 
 	if (tried_times >= pci_try_num) {
-		if (pci_realloc_enable == undefined)
-			printk(KERN_INFO "Some PCI device resources are unassigned, try booting with pci=realloc\n");
-		else if (pci_realloc_enable == auto_enabled)
-			printk(KERN_INFO "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
+		if (enable_local == undefined)
+			dev_info(&bus->dev, "Some PCI device resources are unassigned, try booting with pci=realloc\n");
+		else if (enable_local == auto_enabled)
+			dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
 
 		free_list(&fail_head);
-		goto enable_and_dump;
+		goto dump;
 	}
 
-	printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
-			 tried_times + 1);
+	dev_printk(KERN_DEBUG, &bus->dev,
+		   "No. %d try to assign unassigned res\n", tried_times + 1);
 
 	/* third times and later will not check if it is leaf */
 	if ((tried_times + 1) > 2)
@@ -1525,12 +1526,11 @@
 	 * Try to release leaf bridge's resources that doesn't fit resource of
 	 * child device under that bridge
 	 */
-	list_for_each_entry(fail_res, &fail_head, list) {
-		bus = fail_res->dev->bus;
-		pci_bus_release_bridge_resources(bus,
+	list_for_each_entry(fail_res, &fail_head, list)
+		pci_bus_release_bridge_resources(fail_res->dev->bus,
 						 fail_res->flags & type_mask,
 						 rel_type);
-	}
+
 	/* restore size and flags */
 	list_for_each_entry(fail_res, &fail_head, list) {
 		struct resource *res = fail_res->res;
@@ -1545,14 +1545,17 @@
 
 	goto again;
 
-enable_and_dump:
-	/* Depth last, update the hardware. */
-	list_for_each_entry(bus, &pci_root_buses, node)
-		pci_enable_bridges(bus);
-
+dump:
 	/* dump the resource on buses */
-	list_for_each_entry(bus, &pci_root_buses, node)
-		pci_bus_dump_resources(bus);
+	pci_bus_dump_resources(bus);
+}
+
+void __init pci_assign_unassigned_resources(void)
+{
+	struct pci_bus *root_bus;
+
+	list_for_each_entry(root_bus, &pci_root_buses, node)
+		pci_assign_unassigned_root_bus_resources(root_bus);
 }
 
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
@@ -1589,13 +1592,11 @@
 	 * Try to release leaf bridge's resources that doesn't fit resource of
 	 * child device under that bridge
 	 */
-	list_for_each_entry(fail_res, &fail_head, list) {
-		struct pci_bus *bus = fail_res->dev->bus;
-		unsigned long flags = fail_res->flags;
-
-		pci_bus_release_bridge_resources(bus, flags & type_mask,
+	list_for_each_entry(fail_res, &fail_head, list)
+		pci_bus_release_bridge_resources(fail_res->dev->bus,
+						 fail_res->flags & type_mask,
 						 whole_subtree);
-	}
+
 	/* restore size and flags */
 	list_for_each_entry(fail_res, &fail_head, list) {
 		struct resource *res = fail_res->res;
@@ -1615,7 +1616,6 @@
 	if (retval)
 		dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval);
 	pci_set_master(bridge);
-	pci_enable_bridges(parent);
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 9d3ac99..b2a98cd 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -91,7 +91,6 @@
 	if (s->tune_bridge)
 		s->tune_bridge(s, bus);
 
-	pci_enable_bridges(bus);
 	pci_bus_add_devices(bus);
 
 	return 0;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 5a8ad51..b6e864e 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -61,7 +61,7 @@
 config PINCTRL_BAYTRAIL
 	bool "Intel Baytrail GPIO pin control"
 	depends on GPIOLIB && ACPI && X86
-        select IRQ_DOMAIN
+	select IRQ_DOMAIN
 	help
 	  driver for memory mapped GPIO functionality on Intel Baytrail
 	  platforms. Supports 3 banks with 102, 28 and 44 gpios.
@@ -252,7 +252,7 @@
 
 config PINCTRL_EXYNOS
 	bool "Pinctrl driver data for Samsung EXYNOS SoCs other than 5440"
-	depends on OF && GPIOLIB && ARCH_EXYNOS
+	depends on OF && GPIOLIB && (ARCH_EXYNOS || ARCH_S5PV210)
 	select PINCTRL_SAMSUNG
 
 config PINCTRL_EXYNOS5440
@@ -261,6 +261,17 @@
 	select PINMUX
 	select PINCONF
 
+config PINCTRL_PALMAS
+	bool "Pinctrl driver for the PALMAS Series MFD devices"
+	depends on OF && MFD_PALMAS
+	select PINMUX
+	select GENERIC_PINCONF
+	help
+	  Palmas device supports the configuration of pins for different
+	  functionality. This driver supports the pinmux, push-pull and
+	  open drain configuration for the Palmas series devices like
+	  TPS65913, TPS80036 etc.
+
 config PINCTRL_S3C24XX
 	bool "Samsung S3C24XX SoC pinctrl driver"
 	depends on ARCH_S3C24XX
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index d64563bf..496d9bf 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -2,7 +2,7 @@
 
 ccflags-$(CONFIG_DEBUG_PINCTRL)	+= -DDEBUG
 
-obj-$(CONFIG_PINCTRL)		+= core.o
+obj-$(CONFIG_PINCTRL)		+= core.o pinctrl-utils.o
 obj-$(CONFIG_PINMUX)		+= pinmux.o
 obj-$(CONFIG_PINCONF)		+= pinconf.o
 ifeq ($(CONFIG_OF),y)
@@ -32,6 +32,7 @@
 obj-$(CONFIG_PINCTRL_STN8815)	+= pinctrl-nomadik-stn8815.o
 obj-$(CONFIG_PINCTRL_DB8500)	+= pinctrl-nomadik-db8500.o
 obj-$(CONFIG_PINCTRL_DB8540)	+= pinctrl-nomadik-db8540.o
+obj-$(CONFIG_PINCTRL_PALMAS)	+= pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= sirf/
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 2a00239..92f86ab 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -153,9 +153,7 @@
 		pin = pctldev->desc->pins[i].number;
 		desc = pin_desc_get(pctldev, pin);
 		/* Pin space may be sparse */
-		if (desc == NULL)
-			continue;
-		if (desc->name && !strcmp(name, desc->name))
+		if (desc && !strcmp(name, desc->name))
 			return pin;
 	}
 
@@ -357,14 +355,17 @@
 	/* Loop over the pin controllers */
 	list_for_each_entry(pctldev, &pinctrldev_list, node) {
 		/* Loop over the ranges */
+		mutex_lock(&pctldev->mutex);
 		list_for_each_entry(range, &pctldev->gpio_ranges, node) {
 			/* Check if any gpio range overlapped with gpio chip */
 			if (range->base + range->npins - 1 < chip->base ||
 			    range->base > chip->base + chip->ngpio - 1)
 				continue;
+			mutex_unlock(&pctldev->mutex);
 			mutex_unlock(&pinctrldev_list_mutex);
 			return true;
 		}
+		mutex_unlock(&pctldev->mutex);
 	}
 
 	mutex_unlock(&pinctrldev_list_mutex);
@@ -392,6 +393,8 @@
 {
 	struct pinctrl_dev *pctldev = NULL;
 
+	mutex_lock(&pinctrldev_list_mutex);
+
 	/* Loop over the pin controllers */
 	list_for_each_entry(pctldev, &pinctrldev_list, node) {
 		struct pinctrl_gpio_range *range;
@@ -400,10 +403,13 @@
 		if (range != NULL) {
 			*outdev = pctldev;
 			*outrange = range;
+			mutex_unlock(&pinctrldev_list_mutex);
 			return 0;
 		}
 	}
 
+	mutex_unlock(&pinctrldev_list_mutex);
+
 	return -EPROBE_DEFER;
 }
 
@@ -556,11 +562,15 @@
 		return ret;
 	}
 
+	mutex_lock(&pctldev->mutex);
+
 	/* Convert to the pin controllers number space */
 	pin = gpio_to_pin(range, gpio);
 
 	ret = pinmux_request_gpio(pctldev, range, pin, gpio);
 
+	mutex_unlock(&pctldev->mutex);
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@@ -1228,22 +1238,35 @@
 #ifdef CONFIG_PM
 
 /**
+ * pinctrl_pm_select_state() - select pinctrl state for PM
+ * @dev: device to select default state for
+ * @state: state to set
+ */
+static int pinctrl_pm_select_state(struct device *dev,
+				   struct pinctrl_state *state)
+{
+	struct dev_pin_info *pins = dev->pins;
+	int ret;
+
+	if (IS_ERR(state))
+		return 0; /* No such state */
+	ret = pinctrl_select_state(pins->p, state);
+	if (ret)
+		dev_err(dev, "failed to activate pinctrl state %s\n",
+			state->name);
+	return ret;
+}
+
+/**
  * pinctrl_pm_select_default_state() - select default pinctrl state for PM
  * @dev: device to select default state for
  */
 int pinctrl_pm_select_default_state(struct device *dev)
 {
-	struct dev_pin_info *pins = dev->pins;
-	int ret;
-
-	if (!pins)
+	if (!dev->pins)
 		return 0;
-	if (IS_ERR(pins->default_state))
-		return 0; /* No default state */
-	ret = pinctrl_select_state(pins->p, pins->default_state);
-	if (ret)
-		dev_err(dev, "failed to activate default pinctrl state\n");
-	return ret;
+
+	return pinctrl_pm_select_state(dev, dev->pins->default_state);
 }
 EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state);
 
@@ -1253,17 +1276,10 @@
  */
 int pinctrl_pm_select_sleep_state(struct device *dev)
 {
-	struct dev_pin_info *pins = dev->pins;
-	int ret;
-
-	if (!pins)
+	if (!dev->pins)
 		return 0;
-	if (IS_ERR(pins->sleep_state))
-		return 0; /* No sleep state */
-	ret = pinctrl_select_state(pins->p, pins->sleep_state);
-	if (ret)
-		dev_err(dev, "failed to activate pinctrl sleep state\n");
-	return ret;
+
+	return pinctrl_pm_select_state(dev, dev->pins->sleep_state);
 }
 EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state);
 
@@ -1273,17 +1289,10 @@
  */
 int pinctrl_pm_select_idle_state(struct device *dev)
 {
-	struct dev_pin_info *pins = dev->pins;
-	int ret;
-
-	if (!pins)
+	if (!dev->pins)
 		return 0;
-	if (IS_ERR(pins->idle_state))
-		return 0; /* No idle state */
-	ret = pinctrl_select_state(pins->p, pins->idle_state);
-	if (ret)
-		dev_err(dev, "failed to activate pinctrl idle state\n");
-	return ret;
+
+	return pinctrl_pm_select_state(dev, dev->pins->idle_state);
 }
 EXPORT_SYMBOL_GPL(pinctrl_pm_select_idle_state);
 #endif
diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c
index 048ae80..29f7e4f 100644
--- a/drivers/pinctrl/mvebu/pinctrl-dove.c
+++ b/drivers/pinctrl/mvebu/pinctrl-dove.c
@@ -785,7 +785,7 @@
 	clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "Unable to get pdma clock");
-		return PTR_RET(clk);
+		return PTR_ERR(clk);
 	}
 	clk_prepare_enable(clk);
 
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index bb7ddb1..0fd1ad3 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -191,18 +191,27 @@
 }
 
 static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
-				unsigned gid, unsigned long config)
+				unsigned gid, unsigned long *configs,
+				unsigned num_configs)
 {
 	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
 	struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
+	int i, ret;
 
 	if (!grp->ctrl)
 		return -EINVAL;
 
-	if (grp->ctrl->mpp_set)
-		return grp->ctrl->mpp_set(grp->ctrl, config);
+	for (i = 0; i < num_configs; i++) {
+		if (grp->ctrl->mpp_set)
+			ret = grp->ctrl->mpp_set(grp->ctrl, configs[i]);
+		else
+			ret = mvebu_common_mpp_set(pctl, grp, configs[i]);
 
-	return mvebu_common_mpp_set(pctl, grp, config);
+		if (ret)
+			return ret;
+	} /* for each config */
+
+	return 0;
 }
 
 static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
@@ -303,6 +312,7 @@
 	struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
 	struct mvebu_mpp_ctrl_setting *setting;
 	int ret;
+	unsigned long config;
 
 	setting = mvebu_pinctrl_find_setting_by_name(pctl, grp,
 						     func->name);
@@ -313,7 +323,8 @@
 		return -EINVAL;
 	}
 
-	ret = mvebu_pinconf_group_set(pctldev, grp->gid, setting->val);
+	config = setting->val;
+	ret = mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1);
 	if (ret) {
 		dev_err(pctl->dev, "cannot set group %s to %s\n",
 			func->groups[gid], func->name);
@@ -329,6 +340,7 @@
 	struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
 	struct mvebu_pinctrl_group *grp;
 	struct mvebu_mpp_ctrl_setting *setting;
+	unsigned long config;
 
 	grp = mvebu_pinctrl_find_group_by_pid(pctl, offset);
 	if (!grp)
@@ -341,7 +353,9 @@
 	if (!setting)
 		return -ENOTSUPP;
 
-	return mvebu_pinconf_group_set(pctldev, grp->gid, setting->val);
+	config = setting->val;
+
+	return mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1);
 }
 
 static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -430,7 +444,7 @@
 	}
 
 	*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
-	if (map == NULL) {
+	if (*map == NULL) {
 		dev_err(pctl->dev,
 			"cannot allocate pinctrl_map memory for %s\n",
 			np->name);
@@ -579,7 +593,7 @@
 int mvebu_pinctrl_probe(struct platform_device *pdev)
 {
 	struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
-	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
 	struct mvebu_pinctrl *pctl;
 	void __iomem *base;
 	struct pinctrl_pin_desc *pdesc;
@@ -591,11 +605,10 @@
 		return -EINVAL;
 	}
 
-	base = of_iomap(np, 0);
-	if (!base) {
-		dev_err(&pdev->dev, "unable to get base address\n");
-		return -ENODEV;
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
 
 	pctl = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_pinctrl),
 			GFP_KERNEL);
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 8594f03..55a0ebe 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include "core.h"
 #include "pinconf.h"
+#include "pinctrl-utils.h"
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -236,4 +237,99 @@
 	kfree(cfg);
 	return ret;
 }
+
+int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+		struct device_node *np, struct pinctrl_map **map,
+		unsigned *reserved_maps, unsigned *num_maps,
+		enum pinctrl_map_type type)
+{
+	int ret;
+	const char *function;
+	struct device *dev = pctldev->dev;
+	unsigned long *configs = NULL;
+	unsigned num_configs = 0;
+	unsigned reserve;
+	struct property *prop;
+	const char *group;
+
+	ret = of_property_read_string(np, "function", &function);
+	if (ret < 0) {
+		/* EINVAL=missing, which is fine since it's optional */
+		if (ret != -EINVAL)
+			dev_err(dev, "could not parse property function\n");
+		function = NULL;
+	}
+
+	ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+	if (ret < 0) {
+		dev_err(dev, "could not parse node property\n");
+		return ret;
+	}
+
+	reserve = 0;
+	if (function != NULL)
+		reserve++;
+	if (num_configs)
+		reserve++;
+	ret = of_property_count_strings(np, "pins");
+	if (ret < 0) {
+		dev_err(dev, "could not parse property pins\n");
+		goto exit;
+	}
+	reserve *= ret;
+
+	ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
+			num_maps, reserve);
+	if (ret < 0)
+		goto exit;
+
+	of_property_for_each_string(np, "pins", prop, group) {
+		if (function) {
+			ret = pinctrl_utils_add_map_mux(pctldev, map,
+					reserved_maps, num_maps, group,
+					function);
+			if (ret < 0)
+				goto exit;
+		}
+
+		if (num_configs) {
+			ret = pinctrl_utils_add_map_configs(pctldev, map,
+					reserved_maps, num_maps, group, configs,
+					num_configs, type);
+			if (ret < 0)
+				goto exit;
+		}
+	}
+	ret = 0;
+
+exit:
+	kfree(configs);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map);
+
+int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
+		struct device_node *np_config, struct pinctrl_map **map,
+		unsigned *num_maps, enum pinctrl_map_type type)
+{
+	unsigned reserved_maps;
+	struct device_node *np;
+	int ret;
+
+	reserved_maps = 0;
+	*map = NULL;
+	*num_maps = 0;
+
+	for_each_child_of_node(np_config, np) {
+		ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
+					&reserved_maps, num_maps, type);
+		if (ret < 0) {
+			pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
+			return ret;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
+
 #endif
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index e875f21..a138965 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -158,7 +158,7 @@
 {
 	struct pinctrl_dev *pctldev = setting->pctldev;
 	const struct pinconf_ops *ops = pctldev->desc->confops;
-	int i, ret;
+	int ret;
 
 	if (!ops) {
 		dev_err(pctldev->dev, "missing confops\n");
@@ -171,17 +171,15 @@
 			dev_err(pctldev->dev, "missing pin_config_set op\n");
 			return -EINVAL;
 		}
-		for (i = 0; i < setting->data.configs.num_configs; i++) {
-			ret = ops->pin_config_set(pctldev,
-					setting->data.configs.group_or_pin,
-					setting->data.configs.configs[i]);
-			if (ret < 0) {
-				dev_err(pctldev->dev,
-					"pin_config_set op failed for pin %d config %08lx\n",
-					setting->data.configs.group_or_pin,
-					setting->data.configs.configs[i]);
-				return ret;
-			}
+		ret = ops->pin_config_set(pctldev,
+				setting->data.configs.group_or_pin,
+				setting->data.configs.configs,
+				setting->data.configs.num_configs);
+		if (ret < 0) {
+			dev_err(pctldev->dev,
+				"pin_config_set op failed for pin %d\n",
+				setting->data.configs.group_or_pin);
+			return ret;
 		}
 		break;
 	case PIN_MAP_TYPE_CONFIGS_GROUP:
@@ -190,17 +188,15 @@
 				"missing pin_config_group_set op\n");
 			return -EINVAL;
 		}
-		for (i = 0; i < setting->data.configs.num_configs; i++) {
-			ret = ops->pin_config_group_set(pctldev,
-					setting->data.configs.group_or_pin,
-					setting->data.configs.configs[i]);
-			if (ret < 0) {
-				dev_err(pctldev->dev,
-					"pin_config_group_set op failed for group %d config %08lx\n",
-					setting->data.configs.group_or_pin,
-					setting->data.configs.configs[i]);
-				return ret;
-			}
+		ret = ops->pin_config_group_set(pctldev,
+				setting->data.configs.group_or_pin,
+				setting->data.configs.configs,
+				setting->data.configs.num_configs);
+		if (ret < 0) {
+			dev_err(pctldev->dev,
+				"pin_config_group_set op failed for group %d\n",
+				setting->data.configs.group_or_pin);
+			return ret;
 		}
 		break;
 	default:
@@ -428,12 +424,11 @@
 {
 	struct pinctrl_maps *maps_node;
 	const struct pinctrl_map *map;
-	struct pinctrl_dev *pctldev = NULL;
+	const struct pinctrl_map *found = NULL;
+	struct pinctrl_dev *pctldev;
 	const struct pinconf_ops *confops = NULL;
-	const struct pinctrl_map_configs *configs;
 	struct dbg_cfg *dbg = &pinconf_dbg_conf;
 	int i, j;
-	bool found = false;
 	unsigned long config;
 
 	mutex_lock(&pinctrl_maps_mutex);
@@ -450,14 +445,8 @@
 		for (j = 0; j < map->data.configs.num_configs; j++) {
 			if (!strcmp(map->data.configs.group_or_pin,
 					dbg->pin_name)) {
-				/*
-				 * We found the right pin / state, read the
-				 * config and he pctldev for later use
-				 */
-				configs = &map->data.configs;
-				pctldev = get_pinctrl_dev_from_devname
-					(map->ctrl_dev_name);
-				found = true;
+				/* We found the right pin / state */
+				found = map;
 				break;
 			}
 		}
@@ -473,7 +462,8 @@
 		goto exit;
 	}
 
-	config = *(configs->configs);
+	pctldev = get_pinctrl_dev_from_devname(found->ctrl_dev_name);
+	config = *found->data.configs.configs;
 	seq_printf(s, "Dev %s has config of %s in state %s: 0x%08lX\n",
 			dbg->dev_name, dbg->pin_name,
 			dbg->state_name, config);
@@ -505,12 +495,12 @@
 {
 	struct pinctrl_maps *maps_node;
 	const struct pinctrl_map *map;
-	struct pinctrl_dev *pctldev = NULL;
+	const struct pinctrl_map *found = NULL;
+	struct pinctrl_dev *pctldev;
 	const struct pinconf_ops *confops = NULL;
 	struct dbg_cfg *dbg = &pinconf_dbg_conf;
 	const struct pinctrl_map_configs *configs;
 	char config[MAX_NAME_LEN+1];
-	bool found = false;
 	char buf[128];
 	char *b = &buf[0];
 	int buf_size;
@@ -518,7 +508,7 @@
 	int i;
 
 	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf)-1));
+	buf_size = min(count, (size_t)(sizeof(buf)-1));
 	if (copy_from_user(buf, user_buf, buf_size))
 		return -EFAULT;
 	buf[buf_size] = 0;
@@ -588,10 +578,7 @@
 
 		/*  we found the right pin / state, so overwrite config */
 		if (!strcmp(map->data.configs.group_or_pin, dbg->pin_name)) {
-			found = true;
-			pctldev = get_pinctrl_dev_from_devname(
-					map->ctrl_dev_name);
-			configs = &map->data.configs;
+			found = map;
 			break;
 		}
 	}
@@ -601,10 +588,12 @@
 		goto exit;
 	}
 
+	pctldev = get_pinctrl_dev_from_devname(found->ctrl_dev_name);
 	if (pctldev)
 		confops = pctldev->desc->confops;
 
 	if (confops && confops->pin_config_dbg_parse_modify) {
+		configs = &found->data.configs;
 		for (i = 0; i < configs->num_configs; i++) {
 			confops->pin_config_dbg_parse_modify(pctldev,
 						     config,
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
index 1d3f988..4780959 100644
--- a/drivers/pinctrl/pinctrl-abx500.c
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -426,7 +426,7 @@
 				ret = abx500_gpio_set_bits(chip,
 					AB8500_GPIO_ALTFUN_REG,
 					af.alt_bit2,
-					!!(af.alta_val && BIT(1)));
+					!!(af.alta_val & BIT(1)));
 		} else
 			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
 					offset, 1);
@@ -447,7 +447,7 @@
 			ret = abx500_gpio_set_bits(chip,
 					AB8500_GPIO_ALTFUN_REG,
 					af.alt_bit2,
-					!!(af.altb_val && BIT(1)));
+					!!(af.altb_val & BIT(1)));
 		break;
 
 	case ABX500_ALT_C:
@@ -457,7 +457,7 @@
 			goto out;
 
 		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
-				af.alt_bit2, !!(af.altc_val && BIT(0)));
+				af.alt_bit2, !!(af.altc_val & BIT(0)));
 		if (ret < 0)
 			goto out;
 
@@ -1041,98 +1041,115 @@
 
 static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
 			  unsigned pin,
-			  unsigned long config)
+			  unsigned long *configs,
+			  unsigned num_configs)
 {
 	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
 	struct gpio_chip *chip = &pct->chip;
 	unsigned offset;
 	int ret = -EINVAL;
-	enum pin_config_param param = pinconf_to_config_param(config);
-	enum pin_config_param argument = pinconf_to_config_argument(config);
+	int i;
+	enum pin_config_param param;
+	enum pin_config_param argument;
 
-	dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
-		pin, config, (param == PIN_CONFIG_OUTPUT) ? "output " : "input",
-		(param == PIN_CONFIG_OUTPUT) ? (argument ? "high" : "low") :
-		(argument ? "pull up" : "pull down"));
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		argument = pinconf_to_config_argument(configs[i]);
 
-	/* on ABx500, there is no GPIO0, so adjust the offset */
-	offset = pin - 1;
+		dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+			pin, configs[i],
+			(param == PIN_CONFIG_OUTPUT) ? "output " : "input",
+			(param == PIN_CONFIG_OUTPUT) ?
+			(argument ? "high" : "low") :
+			(argument ? "pull up" : "pull down"));
 
-	switch (param) {
-	case PIN_CONFIG_BIAS_DISABLE:
-		ret = abx500_gpio_direction_input(chip, offset);
-		if (ret < 0)
-			goto out;
-		/*
-		 * Some chips only support pull down, while some actually
-		 * support both pull up and pull down. Such chips have
-		 * a "pullud" range specified for the pins that support
-		 * both features. If the pin is not within that range, we
-		 * fall back to the old bit set that only support pull down.
-		 */
-		if (abx500_pullud_supported(chip, pin))
-			ret = abx500_set_pull_updown(pct,
-				pin,
-				ABX500_GPIO_PULL_NONE);
-		else
-			/* Chip only supports pull down */
-			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
-				offset, ABX500_GPIO_PULL_NONE);
-		break;
+		/* on ABx500, there is no GPIO0, so adjust the offset */
+		offset = pin - 1;
 
-	case PIN_CONFIG_BIAS_PULL_DOWN:
-		ret = abx500_gpio_direction_input(chip, offset);
-		if (ret < 0)
-			goto out;
-		/*
-		 * if argument = 1 set the pull down
-		 * else clear the pull down
-		 * Some chips only support pull down, while some actually
-		 * support both pull up and pull down. Such chips have
-		 * a "pullud" range specified for the pins that support
-		 * both features. If the pin is not within that range, we
-		 * fall back to the old bit set that only support pull down.
-		 */
-		if (abx500_pullud_supported(chip, pin))
-			ret = abx500_set_pull_updown(pct,
-				pin,
-				argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
-		else
-			/* Chip only supports pull down */
-			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
-				offset,
-				argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
-		break;
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			ret = abx500_gpio_direction_input(chip, offset);
+			if (ret < 0)
+				goto out;
+			/*
+			 * Some chips only support pull down, while some
+			 * actually support both pull up and pull down. Such
+			 * chips have a "pullud" range specified for the pins
+			 * that support both features. If the pin is not
+			 * within that range, we fall back to the old bit set
+			 * that only support pull down.
+			 */
+			if (abx500_pullud_supported(chip, pin))
+				ret = abx500_set_pull_updown(pct,
+					pin,
+					ABX500_GPIO_PULL_NONE);
+			else
+				/* Chip only supports pull down */
+				ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_PUD1_REG, offset,
+					ABX500_GPIO_PULL_NONE);
+			break;
 
-	case PIN_CONFIG_BIAS_PULL_UP:
-		ret = abx500_gpio_direction_input(chip, offset);
-		if (ret < 0)
-			goto out;
-		/*
-		 * if argument = 1 set the pull up
-		 * else clear the pull up
-		 */
-		ret = abx500_gpio_direction_input(chip, offset);
-		/*
-		 * Some chips only support pull down, while some actually
-		 * support both pull up and pull down. Such chips have
-		 * a "pullud" range specified for the pins that support
-		 * both features. If the pin is not within that range, do
-		 * nothing
-		 */
-		if (abx500_pullud_supported(chip, pin))
-			ret = abx500_set_pull_updown(pct,
-				pin,
-				argument ? ABX500_GPIO_PULL_UP : ABX500_GPIO_PULL_NONE);
-		break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			ret = abx500_gpio_direction_input(chip, offset);
+			if (ret < 0)
+				goto out;
+			/*
+			 * if argument = 1 set the pull down
+			 * else clear the pull down
+			 * Some chips only support pull down, while some
+			 * actually support both pull up and pull down. Such
+			 * chips have a "pullud" range specified for the pins
+			 * that support both features. If the pin is not
+			 * within that range, we fall back to the old bit set
+			 * that only support pull down.
+			 */
+			if (abx500_pullud_supported(chip, pin))
+				ret = abx500_set_pull_updown(pct,
+					pin,
+					argument ? ABX500_GPIO_PULL_DOWN :
+					ABX500_GPIO_PULL_NONE);
+			else
+				/* Chip only supports pull down */
+				ret = abx500_gpio_set_bits(chip,
+				AB8500_GPIO_PUD1_REG,
+					offset,
+					argument ? ABX500_GPIO_PULL_DOWN :
+					ABX500_GPIO_PULL_NONE);
+			break;
 
-	case PIN_CONFIG_OUTPUT:
-		ret = abx500_gpio_direction_output(chip, offset, argument);
-		break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			ret = abx500_gpio_direction_input(chip, offset);
+			if (ret < 0)
+				goto out;
+			/*
+			 * if argument = 1 set the pull up
+			 * else clear the pull up
+			 */
+			ret = abx500_gpio_direction_input(chip, offset);
+			/*
+			 * Some chips only support pull down, while some
+			 * actually support both pull up and pull down. Such
+			 * chips have a "pullud" range specified for the pins
+			 * that support both features. If the pin is not
+			 * within that range, do nothing
+			 */
+			if (abx500_pullud_supported(chip, pin))
+				ret = abx500_set_pull_updown(pct,
+					pin,
+					argument ? ABX500_GPIO_PULL_UP :
+					ABX500_GPIO_PULL_NONE);
+			break;
 
-	default:
-		dev_err(chip->dev, "illegal configuration requested\n");
-	}
+		case PIN_CONFIG_OUTPUT:
+			ret = abx500_gpio_direction_output(chip, offset,
+				argument);
+			break;
+
+		default:
+			dev_err(chip->dev, "illegal configuration requested\n");
+		}
+	} /* for each config */
 out:
 	if (ret < 0)
 		dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index b90a3a0..f350fd2 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -325,7 +325,7 @@
 
 static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
 {
-	return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
+	return !((readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1);
 }
 
 static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
@@ -445,7 +445,7 @@
 
 static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin)
 {
-	return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1;
+	return !((__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1);
 }
 
 static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on)
@@ -736,30 +736,40 @@
 }
 
 static int at91_pinconf_set(struct pinctrl_dev *pctldev,
-			     unsigned pin_id, unsigned long config)
+			     unsigned pin_id, unsigned long *configs,
+			     unsigned num_configs)
 {
 	struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
 	unsigned mask;
 	void __iomem *pio;
+	int i;
+	unsigned long config;
 
-	dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
-	pio = pin_to_controller(info, pin_to_bank(pin_id));
-	mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
+	for (i = 0; i < num_configs; i++) {
+		config = configs[i];
 
-	if (config & PULL_UP && config & PULL_DOWN)
-		return -EINVAL;
+		dev_dbg(info->dev,
+			"%s:%d, pin_id=%d, config=0x%lx",
+			__func__, __LINE__, pin_id, config);
+		pio = pin_to_controller(info, pin_to_bank(pin_id));
+		mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
 
-	at91_mux_set_pullup(pio, mask, config & PULL_UP);
-	at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
-	if (info->ops->set_deglitch)
-		info->ops->set_deglitch(pio, mask, config & DEGLITCH);
-	if (info->ops->set_debounce)
-		info->ops->set_debounce(pio, mask, config & DEBOUNCE,
+		if (config & PULL_UP && config & PULL_DOWN)
+			return -EINVAL;
+
+		at91_mux_set_pullup(pio, mask, config & PULL_UP);
+		at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
+		if (info->ops->set_deglitch)
+			info->ops->set_deglitch(pio, mask, config & DEGLITCH);
+		if (info->ops->set_debounce)
+			info->ops->set_debounce(pio, mask, config & DEBOUNCE,
 				(config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
-	if (info->ops->set_pulldown)
-		info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
-	if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
-		info->ops->disable_schmitt_trig(pio, mask);
+		if (info->ops->set_pulldown)
+			info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
+		if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
+			info->ops->disable_schmitt_trig(pio, mask);
+
+	} /* for each config */
 
 	return 0;
 }
@@ -1241,18 +1251,22 @@
 
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
+		irq_set_handler(d->irq, handle_simple_irq);
 		writel_relaxed(mask, pio + PIO_ESR);
 		writel_relaxed(mask, pio + PIO_REHLSR);
 		break;
 	case IRQ_TYPE_EDGE_FALLING:
+		irq_set_handler(d->irq, handle_simple_irq);
 		writel_relaxed(mask, pio + PIO_ESR);
 		writel_relaxed(mask, pio + PIO_FELLSR);
 		break;
 	case IRQ_TYPE_LEVEL_LOW:
+		irq_set_handler(d->irq, handle_level_irq);
 		writel_relaxed(mask, pio + PIO_LSR);
 		writel_relaxed(mask, pio + PIO_FELLSR);
 		break;
 	case IRQ_TYPE_LEVEL_HIGH:
+		irq_set_handler(d->irq, handle_level_irq);
 		writel_relaxed(mask, pio + PIO_LSR);
 		writel_relaxed(mask, pio + PIO_REHLSR);
 		break;
@@ -1261,6 +1275,7 @@
 		 * disable additional interrupt modes:
 		 * fall back to default behavior
 		 */
+		irq_set_handler(d->irq, handle_simple_irq);
 		writel_relaxed(mask, pio + PIO_AIMDR);
 		return 0;
 	case IRQ_TYPE_NONE:
@@ -1402,6 +1417,8 @@
 							irq_hw_number_t hw)
 {
 	struct at91_gpio_chip	*at91_gpio = h->host_data;
+	void __iomem		*pio = at91_gpio->regbase;
+	u32			mask = 1 << hw;
 
 	irq_set_lockdep_class(virq, &gpio_lock_class);
 
@@ -1409,8 +1426,13 @@
 	 * Can use the "simple" and not "edge" handler since it's
 	 * shorter, and the AIC handles interrupts sanely.
 	 */
-	irq_set_chip_and_handler(virq, &gpio_irqchip,
-				 handle_simple_irq);
+	irq_set_chip(virq, &gpio_irqchip);
+	if ((at91_gpio->ops == &at91sam9x5_ops) &&
+	    (readl_relaxed(pio + PIO_AIMMR) & mask) &&
+	    (readl_relaxed(pio + PIO_ELSR) & mask))
+		irq_set_handler(virq, handle_level_irq);
+	else
+		irq_set_handler(virq, handle_simple_irq);
 	set_irq_flags(virq, IRQF_VALID);
 	irq_set_chip_data(virq, at91_gpio);
 
diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c
index e9d735d..2832576 100644
--- a/drivers/pinctrl/pinctrl-baytrail.c
+++ b/drivers/pinctrl/pinctrl-baytrail.c
@@ -130,25 +130,25 @@
 	struct pinctrl_gpio_range	*range;
 };
 
+#define to_byt_gpio(c)	container_of(c, struct byt_gpio, chip)
+
 static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
 				 int reg)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	u32 reg_offset;
-	void __iomem *ptr;
 
 	if (reg == BYT_INT_STAT_REG)
 		reg_offset = (offset / 32) * 4;
 	else
 		reg_offset = vg->range->pins[offset] * 16;
 
-	ptr = (void __iomem *) (vg->reg_base + reg_offset + reg);
-	return ptr;
+	return vg->reg_base + reg_offset + reg;
 }
 
 static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 
 	pm_runtime_get(&vg->pdev->dev);
 
@@ -157,7 +157,7 @@
 
 static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
 	u32 value;
 
@@ -218,7 +218,7 @@
 
 static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 	unsigned long flags;
 	u32 old_val;
@@ -237,7 +237,7 @@
 
 static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
 	unsigned long flags;
 	u32 value;
@@ -245,7 +245,7 @@
 	spin_lock_irqsave(&vg->lock, flags);
 
 	value = readl(reg) | BYT_DIR_MASK;
-	value = value & (~BYT_INPUT_EN); /* active low */
+	value &= ~BYT_INPUT_EN;		/* active low */
 	writel(value, reg);
 
 	spin_unlock_irqrestore(&vg->lock, flags);
@@ -256,16 +256,20 @@
 static int byt_gpio_direction_output(struct gpio_chip *chip,
 				     unsigned gpio, int value)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
 	unsigned long flags;
 	u32 reg_val;
 
 	spin_lock_irqsave(&vg->lock, flags);
 
-	reg_val = readl(reg) | (BYT_DIR_MASK | !!value);
-	reg_val &= ~(BYT_OUTPUT_EN | !value);
-	writel(reg_val, reg);
+	reg_val = readl(reg) | BYT_DIR_MASK;
+	reg_val &= ~BYT_OUTPUT_EN;
+
+	if (value)
+		writel(reg_val | BYT_LEVEL, reg);
+	else
+		writel(reg_val & ~BYT_LEVEL, reg);
 
 	spin_unlock_irqrestore(&vg->lock, flags);
 
@@ -274,7 +278,7 @@
 
 static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	int i;
 	unsigned long flags;
 	u32 conf0, val, offs;
@@ -294,16 +298,16 @@
 			   val & BYT_LEVEL ? "hi" : "lo",
 			   vg->range->pins[i], offs,
 			   conf0 & 0x7,
-			   conf0 & BYT_TRIG_NEG ? "fall " : "",
-			   conf0 & BYT_TRIG_POS ? "rise " : "",
-			   conf0 & BYT_TRIG_LVL ? "lvl " : "");
+			   conf0 & BYT_TRIG_NEG ? " fall" : "",
+			   conf0 & BYT_TRIG_POS ? " rise" : "",
+			   conf0 & BYT_TRIG_LVL ? " level" : "");
 	}
 	spin_unlock_irqrestore(&vg->lock, flags);
 }
 
 static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
+	struct byt_gpio *vg = to_byt_gpio(chip);
 	return irq_create_mapping(vg->domain, offset);
 }
 
@@ -516,6 +520,7 @@
 {
 	struct byt_gpio *vg = platform_get_drvdata(pdev);
 	int err;
+
 	pm_runtime_disable(&pdev->dev);
 	err = gpiochip_remove(&vg->chip);
 	if (err)
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index a1c88b3..c05c1ef 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -893,28 +893,35 @@
 }
 
 static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
-			unsigned pin, unsigned long config)
+			unsigned pin, unsigned long *configs,
+			unsigned num_configs)
 {
 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
-	enum bcm2835_pinconf_param param = BCM2835_PINCONF_UNPACK_PARAM(config);
-	u16 arg = BCM2835_PINCONF_UNPACK_ARG(config);
+	enum bcm2835_pinconf_param param;
+	u16 arg;
 	u32 off, bit;
+	int i;
 
-	if (param != BCM2835_PINCONF_PARAM_PULL)
-		return -EINVAL;
+	for (i = 0; i < num_configs; i++) {
+		param = BCM2835_PINCONF_UNPACK_PARAM(configs[i]);
+		arg = BCM2835_PINCONF_UNPACK_ARG(configs[i]);
 
-	off = GPIO_REG_OFFSET(pin);
-	bit = GPIO_REG_SHIFT(pin);
+		if (param != BCM2835_PINCONF_PARAM_PULL)
+			return -EINVAL;
 
-	bcm2835_gpio_wr(pc, GPPUD, arg & 3);
-	/*
-	 * Docs say to wait 150 cycles, but not of what. We assume a
-	 * 1 MHz clock here, which is pretty slow...
-	 */
-	udelay(150);
-	bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
-	udelay(150);
-	bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
+		off = GPIO_REG_OFFSET(pin);
+		bit = GPIO_REG_SHIFT(pin);
+
+		bcm2835_gpio_wr(pc, GPPUD, arg & 3);
+		/*
+		 * Docs say to wait 150 cycles, but not of what. We assume a
+		 * 1 MHz clock here, which is pretty slow...
+		 */
+		udelay(150);
+		bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
+		udelay(150);
+		bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
+	} /* for each config */
 
 	return 0;
 }
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index a74b3cb..2689f8d 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -660,6 +660,64 @@
 			exynos_pinctrl_resume_bank(drvdata, bank);
 }
 
+/* pin banks of s5pv210 pin-controller */
+static struct samsung_pin_bank s5pv210_pin_bank[] = {
+	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+	EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+	EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
+	EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
+	EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
+	EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14),
+	EXYNOS_PIN_BANK_EINTG(4, 0x0c0, "gpd1", 0x18),
+	EXYNOS_PIN_BANK_EINTG(5, 0x0e0, "gpe0", 0x1c),
+	EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20),
+	EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpf0", 0x24),
+	EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpf1", 0x28),
+	EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpf2", 0x2c),
+	EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf3", 0x30),
+	EXYNOS_PIN_BANK_EINTG(7, 0x1a0, "gpg0", 0x34),
+	EXYNOS_PIN_BANK_EINTG(7, 0x1c0, "gpg1", 0x38),
+	EXYNOS_PIN_BANK_EINTG(7, 0x1e0, "gpg2", 0x3c),
+	EXYNOS_PIN_BANK_EINTG(7, 0x200, "gpg3", 0x40),
+	EXYNOS_PIN_BANK_EINTN(7, 0x220, "gpi"),
+	EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x44),
+	EXYNOS_PIN_BANK_EINTG(6, 0x260, "gpj1", 0x48),
+	EXYNOS_PIN_BANK_EINTG(8, 0x280, "gpj2", 0x4c),
+	EXYNOS_PIN_BANK_EINTG(8, 0x2a0, "gpj3", 0x50),
+	EXYNOS_PIN_BANK_EINTG(5, 0x2c0, "gpj4", 0x54),
+	EXYNOS_PIN_BANK_EINTN(8, 0x2e0, "mp01"),
+	EXYNOS_PIN_BANK_EINTN(4, 0x300, "mp02"),
+	EXYNOS_PIN_BANK_EINTN(8, 0x320, "mp03"),
+	EXYNOS_PIN_BANK_EINTN(8, 0x340, "mp04"),
+	EXYNOS_PIN_BANK_EINTN(8, 0x360, "mp05"),
+	EXYNOS_PIN_BANK_EINTN(8, 0x380, "mp06"),
+	EXYNOS_PIN_BANK_EINTN(8, 0x3a0, "mp07"),
+	EXYNOS_PIN_BANK_EINTW(8, 0xc00, "gph0", 0x00),
+	EXYNOS_PIN_BANK_EINTW(8, 0xc20, "gph1", 0x04),
+	EXYNOS_PIN_BANK_EINTW(8, 0xc40, "gph2", 0x08),
+	EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c),
+};
+
+struct samsung_pin_ctrl s5pv210_pin_ctrl[] = {
+	{
+		/* pin-controller instance 0 data */
+		.pin_banks	= s5pv210_pin_bank,
+		.nr_banks	= ARRAY_SIZE(s5pv210_pin_bank),
+		.geint_con	= EXYNOS_GPIO_ECON_OFFSET,
+		.geint_mask	= EXYNOS_GPIO_EMASK_OFFSET,
+		.geint_pend	= EXYNOS_GPIO_EPEND_OFFSET,
+		.weint_con	= EXYNOS_WKUP_ECON_OFFSET,
+		.weint_mask	= EXYNOS_WKUP_EMASK_OFFSET,
+		.weint_pend	= EXYNOS_WKUP_EPEND_OFFSET,
+		.svc		= EXYNOS_SVC_OFFSET,
+		.eint_gpio_init = exynos_eint_gpio_init,
+		.eint_wkup_init = exynos_eint_wkup_init,
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+		.label		= "s5pv210-gpio-ctrl0",
+	},
+};
+
 /* pin banks of exynos4210 pin-controller 0 */
 static struct samsung_pin_bank exynos4210_pin_banks0[] = {
 	EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c
index 3b283fd8..544d469 100644
--- a/drivers/pinctrl/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/pinctrl-exynos5440.c
@@ -401,64 +401,71 @@
 
 /* set the pin config settings for a specified pin */
 static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
-				unsigned long config)
+				unsigned long *configs,
+				unsigned num_configs)
 {
 	struct exynos5440_pinctrl_priv_data *priv;
 	void __iomem *base;
-	enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(config);
-	u32 cfg_value = PINCFG_UNPACK_VALUE(config);
+	enum pincfg_type cfg_type;
+	u32 cfg_value;
 	u32 data;
+	int i;
 
 	priv = pinctrl_dev_get_drvdata(pctldev);
 	base = priv->reg_base;
 
-	switch (cfg_type) {
-	case PINCFG_TYPE_PUD:
-		/* first set pull enable/disable bit */
-		data = readl(base + GPIO_PE);
-		data &= ~(1 << pin);
-		if (cfg_value)
-			data |= (1 << pin);
-		writel(data, base + GPIO_PE);
+	for (i = 0; i < num_configs; i++) {
+		cfg_type = PINCFG_UNPACK_TYPE(configs[i]);
+		cfg_value = PINCFG_UNPACK_VALUE(configs[i]);
 
-		/* then set pull up/down bit */
-		data = readl(base + GPIO_PS);
-		data &= ~(1 << pin);
-		if (cfg_value == 2)
-			data |= (1 << pin);
-		writel(data, base + GPIO_PS);
-		break;
+		switch (cfg_type) {
+		case PINCFG_TYPE_PUD:
+			/* first set pull enable/disable bit */
+			data = readl(base + GPIO_PE);
+			data &= ~(1 << pin);
+			if (cfg_value)
+				data |= (1 << pin);
+			writel(data, base + GPIO_PE);
 
-	case PINCFG_TYPE_DRV:
-		/* set the first bit of the drive strength */
-		data = readl(base + GPIO_DS0);
-		data &= ~(1 << pin);
-		data |= ((cfg_value & 1) << pin);
-		writel(data, base + GPIO_DS0);
-		cfg_value >>= 1;
+			/* then set pull up/down bit */
+			data = readl(base + GPIO_PS);
+			data &= ~(1 << pin);
+			if (cfg_value == 2)
+				data |= (1 << pin);
+			writel(data, base + GPIO_PS);
+			break;
 
-		/* set the second bit of the driver strength */
-		data = readl(base + GPIO_DS1);
-		data &= ~(1 << pin);
-		data |= ((cfg_value & 1) << pin);
-		writel(data, base + GPIO_DS1);
-		break;
-	case PINCFG_TYPE_SKEW_RATE:
-		data = readl(base + GPIO_SR);
-		data &= ~(1 << pin);
-		data |= ((cfg_value & 1) << pin);
-		writel(data, base + GPIO_SR);
-		break;
-	case PINCFG_TYPE_INPUT_TYPE:
-		data = readl(base + GPIO_TYPE);
-		data &= ~(1 << pin);
-		data |= ((cfg_value & 1) << pin);
-		writel(data, base + GPIO_TYPE);
-		break;
-	default:
-		WARN_ON(1);
-		return -EINVAL;
-	}
+		case PINCFG_TYPE_DRV:
+			/* set the first bit of the drive strength */
+			data = readl(base + GPIO_DS0);
+			data &= ~(1 << pin);
+			data |= ((cfg_value & 1) << pin);
+			writel(data, base + GPIO_DS0);
+			cfg_value >>= 1;
+
+			/* set the second bit of the driver strength */
+			data = readl(base + GPIO_DS1);
+			data &= ~(1 << pin);
+			data |= ((cfg_value & 1) << pin);
+			writel(data, base + GPIO_DS1);
+			break;
+		case PINCFG_TYPE_SKEW_RATE:
+			data = readl(base + GPIO_SR);
+			data &= ~(1 << pin);
+			data |= ((cfg_value & 1) << pin);
+			writel(data, base + GPIO_SR);
+			break;
+		case PINCFG_TYPE_INPUT_TYPE:
+			data = readl(base + GPIO_TYPE);
+			data &= ~(1 << pin);
+			data |= ((cfg_value & 1) << pin);
+			writel(data, base + GPIO_TYPE);
+			break;
+		default:
+			WARN_ON(1);
+			return -EINVAL;
+		}
+	} /* for each config */
 
 	return 0;
 }
@@ -510,7 +517,8 @@
 
 /* set the pin config settings for a specified pin group */
 static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev,
-			unsigned group, unsigned long config)
+			unsigned group, unsigned long *configs,
+			unsigned num_configs)
 {
 	struct exynos5440_pinctrl_priv_data *priv;
 	const unsigned int *pins;
@@ -520,7 +528,8 @@
 	pins = priv->pin_groups[group].pins;
 
 	for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++)
-		exynos5440_pinconf_set(pctldev, pins[cnt], config);
+		exynos5440_pinconf_set(pctldev, pins[cnt], configs,
+				       num_configs);
 
 	return 0;
 }
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index f9b2a1d..2e62689 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -75,6 +75,7 @@
 	FALCON_MUX_GPIO = 0,
 	FALCON_MUX_RST,
 	FALCON_MUX_NTR,
+	FALCON_MUX_PPS,
 	FALCON_MUX_MDIO,
 	FALCON_MUX_LED,
 	FALCON_MUX_SPI,
@@ -114,7 +115,7 @@
 	MFP_FALCON(GPIO2,	GPIO,	GPIO,   NONE,   NONE),
 	MFP_FALCON(GPIO3,	GPIO,	GPIO,   NONE,   NONE),
 	MFP_FALCON(GPIO4,	NTR,	GPIO,   NONE,   NONE),
-	MFP_FALCON(GPIO5,	NTR,	GPIO,   NONE,   NONE),
+	MFP_FALCON(GPIO5,	NTR,	GPIO,   PPS,    NONE),
 	MFP_FALCON(GPIO6,	RST,	GPIO,   NONE,   NONE),
 	MFP_FALCON(GPIO7,	MDIO,	GPIO,   NONE,   NONE),
 	MFP_FALCON(GPIO8,	MDIO,	GPIO,   NONE,   NONE),
@@ -168,6 +169,7 @@
 static const unsigned pins_por[] = {GPIO0};
 static const unsigned pins_ntr[] = {GPIO4};
 static const unsigned pins_ntr8k[] = {GPIO5};
+static const unsigned pins_pps[] = {GPIO5};
 static const unsigned pins_hrst[] = {GPIO6};
 static const unsigned pins_mdio[] = {GPIO7, GPIO8};
 static const unsigned pins_bled[] = {GPIO9, GPIO10, GPIO11,
@@ -186,6 +188,7 @@
 	GRP_MUX("por", RST, pins_por),
 	GRP_MUX("ntr", NTR, pins_ntr),
 	GRP_MUX("ntr8k", NTR, pins_ntr8k),
+	GRP_MUX("pps", PPS, pins_pps),
 	GRP_MUX("hrst", RST, pins_hrst),
 	GRP_MUX("mdio", MDIO, pins_mdio),
 	GRP_MUX("bootled", LED, pins_bled),
@@ -201,7 +204,7 @@
 };
 
 static const char * const ltq_rst_grps[] = {"por", "hrst"};
-static const char * const ltq_ntr_grps[] = {"ntr", "ntr8k"};
+static const char * const ltq_ntr_grps[] = {"ntr", "ntr8k", "pps"};
 static const char * const ltq_mdio_grps[] = {"mdio"};
 static const char * const ltq_bled_grps[] = {"bootled"};
 static const char * const ltq_asc_grps[] = {"asc0", "asc1"};
@@ -235,7 +238,8 @@
 }
 
 static int falcon_pinconf_group_set(struct pinctrl_dev *pctrldev,
-				unsigned group, unsigned long config)
+				unsigned group, unsigned long *configs,
+				unsigned num_configs)
 {
 	return -ENOTSUPP;
 }
@@ -276,39 +280,47 @@
 }
 
 static int falcon_pinconf_set(struct pinctrl_dev *pctrldev,
-			unsigned pin, unsigned long config)
+			unsigned pin, unsigned long *configs,
+			unsigned num_configs)
 {
-	enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config);
-	int arg = LTQ_PINCONF_UNPACK_ARG(config);
+	enum ltq_pinconf_param param;
+	int arg;
 	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
 	void __iomem *mem = info->membase[PORT(pin)];
 	u32 reg;
+	int i;
 
-	switch (param) {
-	case LTQ_PINCONF_PARAM_DRIVE_CURRENT:
-		reg = LTQ_PADC_DCC;
-		break;
+	for (i = 0; i < num_configs; i++) {
+		param = LTQ_PINCONF_UNPACK_PARAM(configs[i]);
+		arg = LTQ_PINCONF_UNPACK_ARG(configs[i]);
 
-	case LTQ_PINCONF_PARAM_SLEW_RATE:
-		reg = LTQ_PADC_SRC;
-		break;
+		switch (param) {
+		case LTQ_PINCONF_PARAM_DRIVE_CURRENT:
+			reg = LTQ_PADC_DCC;
+			break;
 
-	case LTQ_PINCONF_PARAM_PULL:
-		if (arg == 1)
-			reg = LTQ_PADC_PDEN;
-		else
-			reg = LTQ_PADC_PUEN;
-		break;
+		case LTQ_PINCONF_PARAM_SLEW_RATE:
+			reg = LTQ_PADC_SRC;
+			break;
 
-	default:
-		pr_err("%s: Invalid config param %04x\n",
-		pinctrl_dev_get_name(pctrldev), param);
-		return -ENOTSUPP;
-	}
+		case LTQ_PINCONF_PARAM_PULL:
+			if (arg == 1)
+				reg = LTQ_PADC_PDEN;
+			else
+				reg = LTQ_PADC_PUEN;
+			break;
 
-	pad_w32(mem, BIT(PORT_PIN(pin)), reg);
-	if (!(pad_r32(mem, reg) & BIT(PORT_PIN(pin))))
-		return -ENOTSUPP;
+		default:
+			pr_err("%s: Invalid config param %04x\n",
+			pinctrl_dev_get_name(pctrldev), param);
+			return -ENOTSUPP;
+		}
+
+		pad_w32(mem, BIT(PORT_PIN(pin)), reg);
+		if (!(pad_r32(mem, reg) & BIT(PORT_PIN(pin))))
+			return -ENOTSUPP;
+	} /* for each config */
+
 	return 0;
 }
 
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 57a4eb0..d78dd81 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -27,18 +27,6 @@
 #include "core.h"
 #include "pinctrl-imx.h"
 
-#define IMX_PMX_DUMP(info, p, m, c, n)			\
-{							\
-	int i, j;					\
-	printk(KERN_DEBUG "Format: Pin Mux Config\n");	\
-	for (i = 0; i < n; i++) {			\
-		j = p[i];				\
-		printk(KERN_DEBUG "%s %d 0x%lx\n",	\
-			info->pins[j].name,		\
-			m[i], c[i]);			\
-	}						\
-}
-
 /* The bits in CONFIG cell defined in binding doc*/
 #define IMX_NO_PAD_CTL	0x80000000	/* no pin config need */
 #define IMX_PAD_SION 0x40000000		/* set SION */
@@ -98,7 +86,7 @@
 	if (selector >= info->ngroups)
 		return -EINVAL;
 
-	*pins = info->groups[selector].pins;
+	*pins = info->groups[selector].pin_ids;
 	*npins = info->groups[selector].npins;
 
 	return 0;
@@ -134,7 +122,7 @@
 	}
 
 	for (i = 0; i < grp->npins; i++) {
-		if (!(grp->configs[i] & IMX_NO_PAD_CTL))
+		if (!(grp->pins[i].config & IMX_NO_PAD_CTL))
 			map_num++;
 	}
 
@@ -159,11 +147,11 @@
 	/* create config map */
 	new_map++;
 	for (i = j = 0; i < grp->npins; i++) {
-		if (!(grp->configs[i] & IMX_NO_PAD_CTL)) {
+		if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) {
 			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
 			new_map[j].data.configs.group_or_pin =
-					pin_get_name(pctldev, grp->pins[i]);
-			new_map[j].data.configs.configs = &grp->configs[i];
+					pin_get_name(pctldev, grp->pins[i].pin);
+			new_map[j].data.configs.configs = &grp->pins[i].config;
 			new_map[j].data.configs.num_configs = 1;
 			j++;
 		}
@@ -197,28 +185,23 @@
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct imx_pin_reg *pin_reg;
-	const unsigned *pins, *mux, *input_val;
-	u16 *input_reg;
 	unsigned int npins, pin_id;
 	int i;
+	struct imx_pin_group *grp;
 
 	/*
 	 * Configure the mux mode for each pin in the group for a specific
 	 * function.
 	 */
-	pins = info->groups[group].pins;
-	npins = info->groups[group].npins;
-	mux = info->groups[group].mux_mode;
-	input_val = info->groups[group].input_val;
-	input_reg = info->groups[group].input_reg;
-
-	WARN_ON(!pins || !npins || !mux || !input_val || !input_reg);
+	grp = &info->groups[group];
+	npins = grp->npins;
 
 	dev_dbg(ipctl->dev, "enable function %s group %s\n",
-		info->functions[selector].name, info->groups[group].name);
+		info->functions[selector].name, grp->name);
 
 	for (i = 0; i < npins; i++) {
-		pin_id = pins[i];
+		struct imx_pin *pin = &grp->pins[i];
+		pin_id = pin->pin;
 		pin_reg = &info->pin_regs[pin_id];
 
 		if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->mux_reg) {
@@ -231,20 +214,50 @@
 			u32 reg;
 			reg = readl(ipctl->base + pin_reg->mux_reg);
 			reg &= ~(0x7 << 20);
-			reg |= (mux[i] << 20);
+			reg |= (pin->mux_mode << 20);
 			writel(reg, ipctl->base + pin_reg->mux_reg);
 		} else {
-			writel(mux[i], ipctl->base + pin_reg->mux_reg);
+			writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg);
 		}
 		dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
-			pin_reg->mux_reg, mux[i]);
+			pin_reg->mux_reg, pin->mux_mode);
 
-		/* some pins also need select input setting, set it if found */
-		if (input_reg[i]) {
-			writel(input_val[i], ipctl->base + input_reg[i]);
+		/*
+		 * If the select input value begins with 0xff, it's a quirky
+		 * select input and the value should be interpreted as below.
+		 *     31     23      15      7        0
+		 *     | 0xff | shift | width | select |
+		 * It's used to work around the problem that the select
+		 * input for some pin is not implemented in the select
+		 * input register but in some general purpose register.
+		 * We encode the select input value, width and shift of
+		 * the bit field into input_val cell of pin function ID
+		 * in device tree, and then decode them here for setting
+		 * up the select input bits in general purpose register.
+		 */
+		if (pin->input_val >> 24 == 0xff) {
+			u32 val = pin->input_val;
+			u8 select = val & 0xff;
+			u8 width = (val >> 8) & 0xff;
+			u8 shift = (val >> 16) & 0xff;
+			u32 mask = ((1 << width) - 1) << shift;
+			/*
+			 * The input_reg[i] here is actually some IOMUXC general
+			 * purpose register, not regular select input register.
+			 */
+			val = readl(ipctl->base + pin->input_val);
+			val &= ~mask;
+			val |= select << shift;
+			writel(val, ipctl->base + pin->input_val);
+		} else if (pin->input_val) {
+			/*
+			 * Regular select input register can never be at offset
+			 * 0, and we only print register value for regular case.
+			 */
+			writel(pin->input_val, ipctl->base + pin->input_reg);
 			dev_dbg(ipctl->dev,
 				"==>select_input: offset 0x%x val 0x%x\n",
-				input_reg[i], input_val[i]);
+				pin->input_reg, pin->input_val);
 		}
 	}
 
@@ -310,11 +323,13 @@
 }
 
 static int imx_pinconf_set(struct pinctrl_dev *pctldev,
-			     unsigned pin_id, unsigned long config)
+			     unsigned pin_id, unsigned long *configs,
+			     unsigned num_configs)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+	int i;
 
 	if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) {
 		dev_err(info->dev, "Pin(%s) does not support config function\n",
@@ -325,17 +340,19 @@
 	dev_dbg(ipctl->dev, "pinconf set pin %s\n",
 		info->pins[pin_id].name);
 
-	if (info->flags & SHARE_MUX_CONF_REG) {
-		u32 reg;
-		reg = readl(ipctl->base + pin_reg->conf_reg);
-		reg &= ~0xffff;
-		reg |= config;
-		writel(reg, ipctl->base + pin_reg->conf_reg);
-	} else {
-		writel(config, ipctl->base + pin_reg->conf_reg);
-	}
-	dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
-		pin_reg->conf_reg, config);
+	for (i = 0; i < num_configs; i++) {
+		if (info->flags & SHARE_MUX_CONF_REG) {
+			u32 reg;
+			reg = readl(ipctl->base + pin_reg->conf_reg);
+			reg &= ~0xffff;
+			reg |= configs[i];
+			writel(reg, ipctl->base + pin_reg->conf_reg);
+		} else {
+			writel(configs[i], ipctl->base + pin_reg->conf_reg);
+		}
+		dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
+			pin_reg->conf_reg, configs[i]);
+	} /* for each config */
 
 	return 0;
 }
@@ -373,8 +390,9 @@
 	seq_printf(s, "\n");
 	grp = &info->groups[group];
 	for (i = 0; i < grp->npins; i++) {
-		name = pin_get_name(pctldev, grp->pins[i]);
-		ret = imx_pinconf_get(pctldev, grp->pins[i], &config);
+		struct imx_pin *pin = &grp->pins[i];
+		name = pin_get_name(pctldev, pin->pin);
+		ret = imx_pinconf_get(pctldev, pin->pin, &config);
 		if (ret)
 			return;
 		seq_printf(s, "%s: 0x%lx", name, config);
@@ -426,28 +444,31 @@
 	 * do sanity check and calculate pins number
 	 */
 	list = of_get_property(np, "fsl,pins", &size);
+	if (!list) {
+		dev_err(info->dev, "no fsl,pins property in node %s\n", np->full_name);
+		return -EINVAL;
+	}
+
 	/* we do not check return since it's safe node passed down */
 	if (!size || size % pin_size) {
-		dev_err(info->dev, "Invalid fsl,pins property\n");
+		dev_err(info->dev, "Invalid fsl,pins property in node %s\n", np->full_name);
 		return -EINVAL;
 	}
 
 	grp->npins = size / pin_size;
-	grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+	grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin),
 				GFP_KERNEL);
-	grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+	grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
 				GFP_KERNEL);
-	grp->input_reg = devm_kzalloc(info->dev, grp->npins * sizeof(u16),
-				GFP_KERNEL);
-	grp->input_val = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
-				GFP_KERNEL);
-	grp->configs = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned long),
-				GFP_KERNEL);
+	if (!grp->pins || ! grp->pin_ids)
+		return -ENOMEM;
+
 	for (i = 0; i < grp->npins; i++) {
 		u32 mux_reg = be32_to_cpu(*list++);
 		u32 conf_reg;
 		unsigned int pin_id;
 		struct imx_pin_reg *pin_reg;
+		struct imx_pin *pin = &grp->pins[i];
 
 		if (info->flags & SHARE_MUX_CONF_REG)
 			conf_reg = mux_reg;
@@ -456,23 +477,23 @@
 
 		pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
 		pin_reg = &info->pin_regs[pin_id];
-		grp->pins[i] = pin_id;
+		pin->pin = pin_id;
+		grp->pin_ids[i] = pin_id;
 		pin_reg->mux_reg = mux_reg;
 		pin_reg->conf_reg = conf_reg;
-		grp->input_reg[i] = be32_to_cpu(*list++);
-		grp->mux_mode[i] = be32_to_cpu(*list++);
-		grp->input_val[i] = be32_to_cpu(*list++);
+		pin->input_reg = be32_to_cpu(*list++);
+		pin->mux_mode = be32_to_cpu(*list++);
+		pin->input_val = be32_to_cpu(*list++);
 
 		/* SION bit is in mux register */
 		config = be32_to_cpu(*list++);
 		if (config & IMX_PAD_SION)
-			grp->mux_mode[i] |= IOMUXC_CONFIG_SION;
-		grp->configs[i] = config & ~IMX_PAD_SION;
-	}
+			pin->mux_mode |= IOMUXC_CONFIG_SION;
+		pin->config = config & ~IMX_PAD_SION;
 
-#ifdef DEBUG
-	IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins);
-#endif
+		dev_dbg(info->dev, "%s: %d 0x%08lx", info->pins[i].name,
+				pin->mux_mode, pin->config);
+	}
 
 	return 0;
 }
@@ -484,7 +505,6 @@
 	struct device_node *child;
 	struct imx_pmx_func *func;
 	struct imx_pin_group *grp;
-	int ret;
 	static u32 grp_index;
 	u32 i = 0;
 
@@ -496,7 +516,7 @@
 	func->name = np->name;
 	func->num_groups = of_get_child_count(np);
 	if (func->num_groups <= 0) {
-		dev_err(info->dev, "no groups defined\n");
+		dev_err(info->dev, "no groups defined in %s\n", np->full_name);
 		return -EINVAL;
 	}
 	func->groups = devm_kzalloc(info->dev,
@@ -505,9 +525,7 @@
 	for_each_child_of_node(np, child) {
 		func->groups[i] = child->name;
 		grp = &info->groups[grp_index++];
-		ret = imx_pinctrl_parse_groups(child, grp, info, i++);
-		if (ret)
-			return ret;
+		imx_pinctrl_parse_groups(child, grp, info, i++);
 	}
 
 	return 0;
@@ -518,7 +536,6 @@
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *child;
-	int ret;
 	u32 nfuncs = 0;
 	u32 i = 0;
 
@@ -545,13 +562,8 @@
 	if (!info->groups)
 		return -ENOMEM;
 
-	for_each_child_of_node(np, child) {
-		ret = imx_pinctrl_parse_functions(child, info, i++);
-		if (ret) {
-			dev_err(&pdev->dev, "failed to parse function\n");
-			return ret;
-		}
-	}
+	for_each_child_of_node(np, child)
+		imx_pinctrl_parse_functions(child, info, i++);
 
 	return 0;
 }
@@ -580,9 +592,6 @@
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENOENT;
-
 	ipctl->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(ipctl->base))
 		return PTR_ERR(ipctl->base);
diff --git a/drivers/pinctrl/pinctrl-imx.h b/drivers/pinctrl/pinctrl-imx.h
index bcedd99..db408b0 100644
--- a/drivers/pinctrl/pinctrl-imx.h
+++ b/drivers/pinctrl/pinctrl-imx.h
@@ -18,29 +18,35 @@
 struct platform_device;
 
 /**
+ * struct imx_pin_group - describes a single i.MX pin
+ * @pin: the pin_id of this pin
+ * @mux_mode: the mux mode for this pin.
+ * @input_reg: the select input register offset for this pin if any
+ *	0 if no select input setting needed.
+ * @input_val: the select input value for this pin.
+ * @configs: the config for this pin.
+ */
+struct imx_pin {
+	unsigned int pin;
+	unsigned int mux_mode;
+	u16 input_reg;
+	unsigned int input_val;
+	unsigned long config;
+};
+
+/**
  * struct imx_pin_group - describes an IMX pin group
  * @name: the name of this specific pin group
- * @pins: an array of discrete physical pins used in this group, taken
- *	from the driver-local pin enumeration space
  * @npins: the number of pins in this group array, i.e. the number of
  *	elements in .pins so we can iterate over that array
- * @mux_mode: the mux mode for each pin in this group. The size of this
- *	array is the same as pins.
- * @input_reg: select input register offset for this mux if any
- *	0 if no select input setting needed.
- * @input_val: the select input value for each pin in this group. The size of
- *	this array is the same as pins.
- * @configs: the config for each pin in this group. The size of this
- *	array is the same as pins.
+ * @pin_ids: array of pin_ids. pinctrl forces us to maintain such an array
+ * @pins: array of pins
  */
 struct imx_pin_group {
 	const char *name;
-	unsigned int *pins;
 	unsigned npins;
-	unsigned int *mux_mode;
-	u16 *input_reg;
-	unsigned int *input_val;
-	unsigned long *configs;
+	unsigned int *pin_ids;
+	struct imx_pin *pins;
 };
 
 /**
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c
index f5d5643..40c76f2 100644
--- a/drivers/pinctrl/pinctrl-mxs.c
+++ b/drivers/pinctrl/pinctrl-mxs.c
@@ -233,7 +233,8 @@
 }
 
 static int mxs_pinconf_set(struct pinctrl_dev *pctldev,
-			   unsigned pin, unsigned long config)
+			   unsigned pin, unsigned long *configs,
+			   unsigned num_configs)
 {
 	return -ENOTSUPP;
 }
@@ -249,7 +250,8 @@
 }
 
 static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
-				 unsigned group, unsigned long config)
+				 unsigned group, unsigned long *configs,
+				 unsigned num_configs)
 {
 	struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
 	struct mxs_group *g = &d->soc->groups[group];
@@ -257,49 +259,56 @@
 	u8 ma, vol, pull, bank, shift;
 	u16 pin;
 	u32 i;
+	int n;
+	unsigned long config;
 
-	ma = CONFIG_TO_MA(config);
-	vol = CONFIG_TO_VOL(config);
-	pull = CONFIG_TO_PULL(config);
+	for (n = 0; n < num_configs; n++) {
+		config = configs[n];
 
-	for (i = 0; i < g->npins; i++) {
-		bank = PINID_TO_BANK(g->pins[i]);
-		pin = PINID_TO_PIN(g->pins[i]);
+		ma = CONFIG_TO_MA(config);
+		vol = CONFIG_TO_VOL(config);
+		pull = CONFIG_TO_PULL(config);
 
-		/* drive */
-		reg = d->base + d->soc->regs->drive;
-		reg += bank * 0x40 + pin / 8 * 0x10;
+		for (i = 0; i < g->npins; i++) {
+			bank = PINID_TO_BANK(g->pins[i]);
+			pin = PINID_TO_PIN(g->pins[i]);
 
-		/* mA */
-		if (config & MA_PRESENT) {
-			shift = pin % 8 * 4;
-			writel(0x3 << shift, reg + CLR);
-			writel(ma << shift, reg + SET);
+			/* drive */
+			reg = d->base + d->soc->regs->drive;
+			reg += bank * 0x40 + pin / 8 * 0x10;
+
+			/* mA */
+			if (config & MA_PRESENT) {
+				shift = pin % 8 * 4;
+				writel(0x3 << shift, reg + CLR);
+				writel(ma << shift, reg + SET);
+			}
+
+			/* vol */
+			if (config & VOL_PRESENT) {
+				shift = pin % 8 * 4 + 2;
+				if (vol)
+					writel(1 << shift, reg + SET);
+				else
+					writel(1 << shift, reg + CLR);
+			}
+
+			/* pull */
+			if (config & PULL_PRESENT) {
+				reg = d->base + d->soc->regs->pull;
+				reg += bank * 0x10;
+				shift = pin;
+				if (pull)
+					writel(1 << shift, reg + SET);
+				else
+					writel(1 << shift, reg + CLR);
+			}
 		}
 
-		/* vol */
-		if (config & VOL_PRESENT) {
-			shift = pin % 8 * 4 + 2;
-			if (vol)
-				writel(1 << shift, reg + SET);
-			else
-				writel(1 << shift, reg + CLR);
-		}
+		/* cache the config value for mxs_pinconf_group_get() */
+		g->config = config;
 
-		/* pull */
-		if (config & PULL_PRESENT) {
-			reg = d->base + d->soc->regs->pull;
-			reg += bank * 0x10;
-			shift = pin;
-			if (pull)
-				writel(1 << shift, reg + SET);
-			else
-				writel(1 << shift, reg + CLR);
-		}
-	}
-
-	/* cache the config value for mxs_pinconf_group_get() */
-	g->config = config;
+	} /* for each config */
 
 	return 0;
 }
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 4a1cfdc..d7c3ae3 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -337,97 +337,6 @@
 	nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit));
 }
 
-static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
-			     pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
-{
-	static const char *afnames[] = {
-		[NMK_GPIO_ALT_GPIO]	= "GPIO",
-		[NMK_GPIO_ALT_A]	= "A",
-		[NMK_GPIO_ALT_B]	= "B",
-		[NMK_GPIO_ALT_C]	= "C"
-	};
-	static const char *pullnames[] = {
-		[NMK_GPIO_PULL_NONE]	= "none",
-		[NMK_GPIO_PULL_UP]	= "up",
-		[NMK_GPIO_PULL_DOWN]	= "down",
-		[3] /* illegal */	= "??"
-	};
-	static const char *slpmnames[] = {
-		[NMK_GPIO_SLPM_INPUT]		= "input/wakeup",
-		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change/no-wakeup",
-	};
-
-	int pin = PIN_NUM(cfg);
-	int pull = PIN_PULL(cfg);
-	int af = PIN_ALT(cfg);
-	int slpm = PIN_SLPM(cfg);
-	int output = PIN_DIR(cfg);
-	int val = PIN_VAL(cfg);
-	bool glitch = af == NMK_GPIO_ALT_C;
-
-	dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
-		pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
-		output ? "output " : "input",
-		output ? (val ? "high" : "low") : "");
-
-	if (sleep) {
-		int slpm_pull = PIN_SLPM_PULL(cfg);
-		int slpm_output = PIN_SLPM_DIR(cfg);
-		int slpm_val = PIN_SLPM_VAL(cfg);
-
-		af = NMK_GPIO_ALT_GPIO;
-
-		/*
-		 * The SLPM_* values are normal values + 1 to allow zero to
-		 * mean "same as normal".
-		 */
-		if (slpm_pull)
-			pull = slpm_pull - 1;
-		if (slpm_output)
-			output = slpm_output - 1;
-		if (slpm_val)
-			val = slpm_val - 1;
-
-		dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
-			pin,
-			slpm_pull ? pullnames[pull] : "same",
-			slpm_output ? (output ? "output" : "input") : "same",
-			slpm_val ? (val ? "high" : "low") : "same");
-	}
-
-	if (output)
-		__nmk_gpio_make_output(nmk_chip, offset, val);
-	else {
-		__nmk_gpio_make_input(nmk_chip, offset);
-		__nmk_gpio_set_pull(nmk_chip, offset, pull);
-	}
-
-	__nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg));
-
-	/*
-	 * If the pin is switching to altfunc, and there was an interrupt
-	 * installed on it which has been lazy disabled, actually mask the
-	 * interrupt to prevent spurious interrupts that would occur while the
-	 * pin is under control of the peripheral.  Only SKE does this.
-	 */
-	if (af != NMK_GPIO_ALT_GPIO)
-		nmk_gpio_disable_lazy_irq(nmk_chip, offset);
-
-	/*
-	 * If we've backed up the SLPM registers (glitch workaround), modify
-	 * the backups since they will be restored.
-	 */
-	if (slpmregs) {
-		if (slpm == NMK_GPIO_SLPM_NOCHANGE)
-			slpmregs[nmk_chip->bank] |= BIT(offset);
-		else
-			slpmregs[nmk_chip->bank] &= ~BIT(offset);
-	} else
-		__nmk_gpio_set_slpm(nmk_chip, offset, slpm);
-
-	__nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch);
-}
-
 /*
  * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
  *  - Save SLPM registers
@@ -474,210 +383,6 @@
 	}
 }
 
-static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
-{
-	static unsigned int slpm[NUM_BANKS];
-	unsigned long flags;
-	bool glitch = false;
-	int ret = 0;
-	int i;
-
-	for (i = 0; i < num; i++) {
-		if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) {
-			glitch = true;
-			break;
-		}
-	}
-
-	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-
-	if (glitch) {
-		memset(slpm, 0xff, sizeof(slpm));
-
-		for (i = 0; i < num; i++) {
-			int pin = PIN_NUM(cfgs[i]);
-			int offset = pin % NMK_GPIO_PER_CHIP;
-
-			if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C)
-				slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset);
-		}
-
-		nmk_gpio_glitch_slpm_init(slpm);
-	}
-
-	for (i = 0; i < num; i++) {
-		struct nmk_gpio_chip *nmk_chip;
-		int pin = PIN_NUM(cfgs[i]);
-
-		nmk_chip = nmk_gpio_chips[pin / NMK_GPIO_PER_CHIP];
-		if (!nmk_chip) {
-			ret = -EINVAL;
-			break;
-		}
-
-		clk_enable(nmk_chip->clk);
-		spin_lock(&nmk_chip->lock);
-		__nmk_config_pin(nmk_chip, pin % NMK_GPIO_PER_CHIP,
-				 cfgs[i], sleep, glitch ? slpm : NULL);
-		spin_unlock(&nmk_chip->lock);
-		clk_disable(nmk_chip->clk);
-	}
-
-	if (glitch)
-		nmk_gpio_glitch_slpm_restore(slpm);
-
-	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-
-	return ret;
-}
-
-/**
- * nmk_config_pin - configure a pin's mux attributes
- * @cfg: pin confguration
- * @sleep: Non-zero to apply the sleep mode configuration
- * Configures a pin's mode (alternate function or GPIO), its pull up status,
- * and its sleep mode based on the specified configuration.  The @cfg is
- * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
- * are constructed using, and can be further enhanced with, the macros in
- * <linux/platform_data/pinctrl-nomadik.h>
- *
- * If a pin's mode is set to GPIO, it is configured as an input to avoid
- * side-effects.  The gpio can be manipulated later using standard GPIO API
- * calls.
- */
-int nmk_config_pin(pin_cfg_t cfg, bool sleep)
-{
-	return __nmk_config_pins(&cfg, 1, sleep);
-}
-EXPORT_SYMBOL(nmk_config_pin);
-
-/**
- * nmk_config_pins - configure several pins at once
- * @cfgs: array of pin configurations
- * @num: number of elments in the array
- *
- * Configures several pins using nmk_config_pin().  Refer to that function for
- * further information.
- */
-int nmk_config_pins(pin_cfg_t *cfgs, int num)
-{
-	return __nmk_config_pins(cfgs, num, false);
-}
-EXPORT_SYMBOL(nmk_config_pins);
-
-int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
-{
-	return __nmk_config_pins(cfgs, num, true);
-}
-EXPORT_SYMBOL(nmk_config_pins_sleep);
-
-/**
- * nmk_gpio_set_slpm() - configure the sleep mode of a pin
- * @gpio: pin number
- * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
- *
- * This register is actually in the pinmux layer, not the GPIO block itself.
- * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP
- * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code).
- * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is
- * HIGH, overriding the normal setting defined by GPIO_AFSELx registers.
- * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit),
- * the GPIOs return to the normal setting defined by GPIO_AFSELx registers.
- *
- * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO
- * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is
- * entered) regardless of the altfunction selected. Also wake-up detection is
- * ENABLED.
- *
- * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains
- * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS
- * (for altfunction GPIO) or respective on-chip peripherals (for other
- * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED.
- *
- * Note that enable_irq_wake() will automatically enable wakeup detection.
- */
-int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-
-	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
-	spin_lock(&nmk_chip->lock);
-
-	__nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP, mode);
-
-	spin_unlock(&nmk_chip->lock);
-	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-/**
- * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
- * @gpio: pin number
- * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
- *
- * Enables/disables pull up/down on a specified pin.  This only takes effect if
- * the pin is configured as an input (either explicitly or by the alternate
- * function).
- *
- * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
- * configured as an input.  Otherwise, due to the way the controller registers
- * work, this function will change the value output on the pin.
- */
-int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-
-	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_chip->lock, flags);
-	__nmk_gpio_set_pull(nmk_chip, gpio % NMK_GPIO_PER_CHIP, pull);
-	spin_unlock_irqrestore(&nmk_chip->lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-
-/* Mode functions */
-/**
- * nmk_gpio_set_mode() - set the mux mode of a gpio pin
- * @gpio: pin number
- * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A,
- *	       NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C
- *
- * Sets the mode of the specified pin to one of the alternate functions or
- * plain GPIO.
- */
-int nmk_gpio_set_mode(int gpio, int gpio_mode)
-{
-	struct nmk_gpio_chip *nmk_chip;
-	unsigned long flags;
-
-	nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
-	if (!nmk_chip)
-		return -EINVAL;
-
-	clk_enable(nmk_chip->clk);
-	spin_lock_irqsave(&nmk_chip->lock, flags);
-	__nmk_gpio_set_mode(nmk_chip, gpio % NMK_GPIO_PER_CHIP, gpio_mode);
-	spin_unlock_irqrestore(&nmk_chip->lock, flags);
-	clk_disable(nmk_chip->clk);
-
-	return 0;
-}
-EXPORT_SYMBOL(nmk_gpio_set_mode);
-
 static int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
 {
 	int i;
@@ -1350,10 +1055,6 @@
 		pdata->num_gpio   = NMK_GPIO_PER_CHIP;
 	}
 
-	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENOENT;
-
 	irq = platform_get_irq(dev, 0);
 	if (irq < 0)
 		return irq;
@@ -1362,6 +1063,7 @@
 	if (secondary_irq >= 0 && !pdata->get_secondary_status)
 		return -EINVAL;
 
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(&dev->dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
@@ -1807,7 +1509,7 @@
 	struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
 	const struct nmk_pingroup *g;
 	static unsigned int slpm[NUM_BANKS];
-	unsigned long flags;
+	unsigned long flags = 0;
 	bool glitch;
 	int ret = -EINVAL;
 	int i;
@@ -1993,7 +1695,7 @@
 }
 
 static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
-			      unsigned long config)
+			      unsigned long *configs, unsigned num_configs)
 {
 	static const char *pullnames[] = {
 		[NMK_GPIO_PULL_NONE]	= "none",
@@ -2010,20 +1712,9 @@
 	struct pinctrl_gpio_range *range;
 	struct gpio_chip *chip;
 	unsigned bit;
-
-	/*
-	 * The pin config contains pin number and altfunction fields, here
-	 * we just ignore that part. It's being handled by the framework and
-	 * pinmux callback respectively.
-	 */
-	pin_cfg_t cfg = (pin_cfg_t) config;
-	int pull = PIN_PULL(cfg);
-	int slpm = PIN_SLPM(cfg);
-	int output = PIN_DIR(cfg);
-	int val = PIN_VAL(cfg);
-	bool lowemi = PIN_LOWEMI(cfg);
-	bool gpiomode = PIN_GPIOMODE(cfg);
-	bool sleep = PIN_SLEEPMODE(cfg);
+	pin_cfg_t cfg;
+	int pull, slpm, output, val, i;
+	bool lowemi, gpiomode, sleep;
 
 	range = nmk_match_gpio_range(pctldev, pin);
 	if (!range) {
@@ -2038,54 +1729,74 @@
 	chip = range->gc;
 	nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
 
-	if (sleep) {
-		int slpm_pull = PIN_SLPM_PULL(cfg);
-		int slpm_output = PIN_SLPM_DIR(cfg);
-		int slpm_val = PIN_SLPM_VAL(cfg);
-
-		/* All pins go into GPIO mode at sleep */
-		gpiomode = true;
-
+	for (i = 0; i < num_configs; i++) {
 		/*
-		 * The SLPM_* values are normal values + 1 to allow zero to
-		 * mean "same as normal".
+		 * The pin config contains pin number and altfunction fields,
+		 * here we just ignore that part. It's being handled by the
+		 * framework and pinmux callback respectively.
 		 */
-		if (slpm_pull)
-			pull = slpm_pull - 1;
-		if (slpm_output)
-			output = slpm_output - 1;
-		if (slpm_val)
-			val = slpm_val - 1;
+		cfg = (pin_cfg_t) configs[i];
+		pull = PIN_PULL(cfg);
+		slpm = PIN_SLPM(cfg);
+		output = PIN_DIR(cfg);
+		val = PIN_VAL(cfg);
+		lowemi = PIN_LOWEMI(cfg);
+		gpiomode = PIN_GPIOMODE(cfg);
+		sleep = PIN_SLEEPMODE(cfg);
 
-		dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
-			pin,
-			slpm_pull ? pullnames[pull] : "same",
-			slpm_output ? (output ? "output" : "input") : "same",
-			slpm_val ? (val ? "high" : "low") : "same");
-	}
+		if (sleep) {
+			int slpm_pull = PIN_SLPM_PULL(cfg);
+			int slpm_output = PIN_SLPM_DIR(cfg);
+			int slpm_val = PIN_SLPM_VAL(cfg);
 
-	dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
-		pin, cfg, pullnames[pull], slpmnames[slpm],
-		output ? "output " : "input",
-		output ? (val ? "high" : "low") : "",
-		lowemi ? "on" : "off");
+			/* All pins go into GPIO mode at sleep */
+			gpiomode = true;
 
-	clk_enable(nmk_chip->clk);
-	bit = pin % NMK_GPIO_PER_CHIP;
-	if (gpiomode)
-		/* No glitch when going to GPIO mode */
-		__nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
-	if (output)
-		__nmk_gpio_make_output(nmk_chip, bit, val);
-	else {
-		__nmk_gpio_make_input(nmk_chip, bit);
-		__nmk_gpio_set_pull(nmk_chip, bit, pull);
-	}
-	/* TODO: isn't this only applicable on output pins? */
-	__nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+			/*
+			 * The SLPM_* values are normal values + 1 to allow zero
+			 * to mean "same as normal".
+			 */
+			if (slpm_pull)
+				pull = slpm_pull - 1;
+			if (slpm_output)
+				output = slpm_output - 1;
+			if (slpm_val)
+				val = slpm_val - 1;
 
-	__nmk_gpio_set_slpm(nmk_chip, bit, slpm);
-	clk_disable(nmk_chip->clk);
+			dev_dbg(nmk_chip->chip.dev,
+				"pin %d: sleep pull %s, dir %s, val %s\n",
+				pin,
+				slpm_pull ? pullnames[pull] : "same",
+				slpm_output ? (output ? "output" : "input")
+				: "same",
+				slpm_val ? (val ? "high" : "low") : "same");
+		}
+
+		dev_dbg(nmk_chip->chip.dev,
+			"pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
+			pin, cfg, pullnames[pull], slpmnames[slpm],
+			output ? "output " : "input",
+			output ? (val ? "high" : "low") : "",
+			lowemi ? "on" : "off");
+
+		clk_enable(nmk_chip->clk);
+		bit = pin % NMK_GPIO_PER_CHIP;
+		if (gpiomode)
+			/* No glitch when going to GPIO mode */
+			__nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+		if (output)
+			__nmk_gpio_make_output(nmk_chip, bit, val);
+		else {
+			__nmk_gpio_make_input(nmk_chip, bit);
+			__nmk_gpio_set_pull(nmk_chip, bit, pull);
+		}
+		/* TODO: isn't this only applicable on output pins? */
+		__nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+
+		__nmk_gpio_set_slpm(nmk_chip, bit, slpm);
+		clk_disable(nmk_chip->clk);
+	} /* for each config */
+
 	return 0;
 }
 
diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c
new file mode 100644
index 0000000..82638fa
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-palmas.c
@@ -0,0 +1,1095 @@
+/*
+ * pinctrl-palmas.c -- TI PALMAS series pin control driver.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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/delay.h>
+#include <linux/module.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+#define PALMAS_PIN_GPIO0_ID				0
+#define PALMAS_PIN_GPIO1_VBUS_LED1_PWM1			1
+#define PALMAS_PIN_GPIO2_REGEN_LED2_PWM2		2
+#define PALMAS_PIN_GPIO3_CHRG_DET			3
+#define PALMAS_PIN_GPIO4_SYSEN1				4
+#define PALMAS_PIN_GPIO5_CLK32KGAUDIO_USB_PSEL		5
+#define PALMAS_PIN_GPIO6_SYSEN2				6
+#define PALMAS_PIN_GPIO7_MSECURE_PWRHOLD		7
+#define PALMAS_PIN_GPIO8_SIM1RSTI			8
+#define PALMAS_PIN_GPIO9_LOW_VBAT			9
+#define PALMAS_PIN_GPIO10_WIRELESS_CHRG1		10
+#define PALMAS_PIN_GPIO11_RCM				11
+#define PALMAS_PIN_GPIO12_SIM2RSTO			12
+#define PALMAS_PIN_GPIO13				13
+#define PALMAS_PIN_GPIO14				14
+#define PALMAS_PIN_GPIO15_SIM2RSTI			15
+#define PALMAS_PIN_VAC					16
+#define PALMAS_PIN_POWERGOOD_USB_PSEL			17
+#define PALMAS_PIN_NRESWARM				18
+#define PALMAS_PIN_PWRDOWN				19
+#define PALMAS_PIN_GPADC_START				20
+#define PALMAS_PIN_RESET_IN				21
+#define PALMAS_PIN_NSLEEP				22
+#define PALMAS_PIN_ENABLE1				23
+#define PALMAS_PIN_ENABLE2				24
+#define PALMAS_PIN_INT					25
+#define PALMAS_PIN_NUM					(PALMAS_PIN_INT + 1)
+
+struct palmas_pin_function {
+	const char *name;
+	const char * const *groups;
+	unsigned ngroups;
+};
+
+struct palmas_pctrl_chip_info {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	struct palmas *palmas;
+	int pins_current_opt[PALMAS_PIN_NUM];
+	const struct palmas_pin_function *functions;
+	unsigned num_functions;
+	const struct palmas_pingroup *pin_groups;
+	int num_pin_groups;
+	const struct pinctrl_pin_desc *pins;
+	unsigned num_pins;
+};
+
+static const struct pinctrl_pin_desc palmas_pins_desc[] = {
+	PINCTRL_PIN(PALMAS_PIN_GPIO0_ID, "gpio0"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO1_VBUS_LED1_PWM1, "gpio1"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO2_REGEN_LED2_PWM2, "gpio2"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO3_CHRG_DET, "gpio3"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO4_SYSEN1, "gpio4"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO5_CLK32KGAUDIO_USB_PSEL, "gpio5"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO6_SYSEN2, "gpio6"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO7_MSECURE_PWRHOLD, "gpio7"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO8_SIM1RSTI, "gpio8"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO9_LOW_VBAT, "gpio9"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO10_WIRELESS_CHRG1, "gpio10"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO11_RCM, "gpio11"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO12_SIM2RSTO, "gpio12"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO13, "gpio13"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO14, "gpio14"),
+	PINCTRL_PIN(PALMAS_PIN_GPIO15_SIM2RSTI, "gpio15"),
+	PINCTRL_PIN(PALMAS_PIN_VAC, "vac"),
+	PINCTRL_PIN(PALMAS_PIN_POWERGOOD_USB_PSEL, "powergood"),
+	PINCTRL_PIN(PALMAS_PIN_NRESWARM, "nreswarm"),
+	PINCTRL_PIN(PALMAS_PIN_PWRDOWN, "pwrdown"),
+	PINCTRL_PIN(PALMAS_PIN_GPADC_START, "gpadc_start"),
+	PINCTRL_PIN(PALMAS_PIN_RESET_IN, "reset_in"),
+	PINCTRL_PIN(PALMAS_PIN_NSLEEP, "nsleep"),
+	PINCTRL_PIN(PALMAS_PIN_ENABLE1, "enable1"),
+	PINCTRL_PIN(PALMAS_PIN_ENABLE2, "enable2"),
+	PINCTRL_PIN(PALMAS_PIN_INT, "int"),
+};
+
+static const char * const opt0_groups[] = {
+	"gpio0",
+	"gpio1",
+	"gpio2",
+	"gpio3",
+	"gpio4",
+	"gpio5",
+	"gpio6",
+	"gpio7",
+	"gpio8",
+	"gpio9",
+	"gpio10",
+	"gpio11",
+	"gpio12",
+	"gpio13",
+	"gpio14",
+	"gpio15",
+	"vac",
+	"powergood",
+	"nreswarm",
+	"pwrdown",
+	"gpadc_start",
+	"reset_in",
+	"nsleep",
+	"enable1",
+	"enable2",
+	"int",
+};
+
+static const char * const opt1_groups[] = {
+	"gpio0",
+	"gpio1",
+	"gpio2",
+	"gpio3",
+	"gpio4",
+	"gpio5",
+	"gpio6",
+	"gpio7",
+	"gpio8",
+	"gpio9",
+	"gpio10",
+	"gpio11",
+	"gpio12",
+	"gpio15",
+	"vac",
+	"powergood",
+};
+
+static const char * const opt2_groups[] = {
+	"gpio1",
+	"gpio2",
+	"gpio5",
+	"gpio7",
+};
+
+static const char * const opt3_groups[] = {
+	"gpio1",
+	"gpio2",
+};
+
+static const char * const gpio_groups[] = {
+	"gpio0",
+	"gpio1",
+	"gpio2",
+	"gpio3",
+	"gpio4",
+	"gpio5",
+	"gpio6",
+	"gpio7",
+	"gpio8",
+	"gpio9",
+	"gpio10",
+	"gpio11",
+	"gpio12",
+	"gpio13",
+	"gpio14",
+	"gpio15",
+};
+
+static const char * const led_groups[] = {
+	"gpio1",
+	"gpio2",
+};
+
+static const char * const pwm_groups[] = {
+	"gpio1",
+	"gpio2",
+};
+
+static const char * const regen_groups[] = {
+	"gpio2",
+};
+
+static const char * const sysen_groups[] = {
+	"gpio4",
+	"gpio6",
+};
+
+static const char * const clk32kgaudio_groups[] = {
+	"gpio5",
+};
+
+static const char * const id_groups[] = {
+	"gpio0",
+};
+
+static const char * const vbus_det_groups[] = {
+	"gpio1",
+};
+
+static const char * const chrg_det_groups[] = {
+	"gpio3",
+};
+
+static const char * const vac_groups[] = {
+	"vac",
+};
+
+static const char * const vacok_groups[] = {
+	"vac",
+};
+
+static const char * const powergood_groups[] = {
+	"powergood",
+};
+
+static const char * const usb_psel_groups[] = {
+	"gpio5",
+	"powergood",
+};
+
+static const char * const msecure_groups[] = {
+	"gpio7",
+};
+
+static const char * const pwrhold_groups[] = {
+	"gpio7",
+};
+
+static const char * const int_groups[] = {
+	"int",
+};
+
+static const char * const nreswarm_groups[] = {
+	"nreswarm",
+};
+
+static const char * const simrsto_groups[] = {
+	"gpio12",
+};
+
+static const char * const simrsti_groups[] = {
+	"gpio8",
+	"gpio15",
+};
+
+static const char * const low_vbat_groups[] = {
+	"gpio9",
+};
+
+static const char * const wireless_chrg1_groups[] = {
+	"gpio10",
+};
+
+static const char * const rcm_groups[] = {
+	"gpio11",
+};
+
+static const char * const pwrdown_groups[] = {
+	"pwrdown",
+};
+
+static const char * const gpadc_start_groups[] = {
+	"gpadc_start",
+};
+
+static const char * const reset_in_groups[] = {
+	"reset_in",
+};
+
+static const char * const nsleep_groups[] = {
+	"nsleep",
+};
+
+static const char * const enable_groups[] = {
+	"enable1",
+	"enable2",
+};
+
+#define FUNCTION_GROUPS					\
+	FUNCTION_GROUP(opt0, OPTION0),			\
+	FUNCTION_GROUP(opt1, OPTION1),			\
+	FUNCTION_GROUP(opt2, OPTION2),			\
+	FUNCTION_GROUP(opt3, OPTION3),			\
+	FUNCTION_GROUP(gpio, GPIO),			\
+	FUNCTION_GROUP(led, LED),			\
+	FUNCTION_GROUP(pwm, PWM),			\
+	FUNCTION_GROUP(regen, REGEN),			\
+	FUNCTION_GROUP(sysen, SYSEN),			\
+	FUNCTION_GROUP(clk32kgaudio, CLK32KGAUDIO),	\
+	FUNCTION_GROUP(id, ID),				\
+	FUNCTION_GROUP(vbus_det, VBUS_DET),		\
+	FUNCTION_GROUP(chrg_det, CHRG_DET),		\
+	FUNCTION_GROUP(vac, VAC),			\
+	FUNCTION_GROUP(vacok, VACOK),			\
+	FUNCTION_GROUP(powergood, POWERGOOD),		\
+	FUNCTION_GROUP(usb_psel, USB_PSEL),		\
+	FUNCTION_GROUP(msecure, MSECURE),		\
+	FUNCTION_GROUP(pwrhold, PWRHOLD),		\
+	FUNCTION_GROUP(int, INT),			\
+	FUNCTION_GROUP(nreswarm, NRESWARM),		\
+	FUNCTION_GROUP(simrsto, SIMRSTO),		\
+	FUNCTION_GROUP(simrsti, SIMRSTI),		\
+	FUNCTION_GROUP(low_vbat, LOW_VBAT),		\
+	FUNCTION_GROUP(wireless_chrg1, WIRELESS_CHRG1),	\
+	FUNCTION_GROUP(rcm, RCM),			\
+	FUNCTION_GROUP(pwrdown, PWRDOWN),		\
+	FUNCTION_GROUP(gpadc_start, GPADC_START),	\
+	FUNCTION_GROUP(reset_in, RESET_IN),		\
+	FUNCTION_GROUP(nsleep, NSLEEP),			\
+	FUNCTION_GROUP(enable, ENABLE)
+
+static const struct palmas_pin_function palmas_pin_function[] = {
+#undef FUNCTION_GROUP
+#define FUNCTION_GROUP(fname, mux)			\
+	{						\
+		.name = #fname,				\
+		.groups = fname##_groups,		\
+		.ngroups = ARRAY_SIZE(fname##_groups),	\
+	}
+
+	FUNCTION_GROUPS,
+};
+
+enum palmas_pinmux {
+#undef FUNCTION_GROUP
+#define FUNCTION_GROUP(fname, mux)	PALMAS_PINMUX_##mux
+	FUNCTION_GROUPS,
+	PALMAS_PINMUX_NA = 0xFFFF,
+};
+
+struct palmas_pins_pullup_dn_info {
+	int pullup_dn_reg_base;
+	int pullup_dn_reg_add;
+	int pullup_dn_mask;
+	int normal_val;
+	int pull_up_val;
+	int pull_dn_val;
+};
+
+struct palmas_pins_od_info {
+	int od_reg_base;
+	int od_reg_add;
+	int od_mask;
+	int od_enable;
+	int od_disable;
+};
+
+struct palmas_pin_info {
+	enum palmas_pinmux mux_opt;
+	const struct palmas_pins_pullup_dn_info *pud_info;
+	const struct palmas_pins_od_info *od_info;
+};
+
+struct palmas_pingroup {
+	const char *name;
+	const unsigned pins[1];
+	unsigned npins;
+	unsigned mux_reg_base;
+	unsigned mux_reg_add;
+	unsigned mux_reg_mask;
+	unsigned mux_bit_shift;
+	const struct palmas_pin_info *opt[4];
+};
+
+#define PULL_UP_DN(_name, _rbase, _add, _mask, _nv, _uv, _dv)		\
+static const struct palmas_pins_pullup_dn_info pud_##_name##_info = {	\
+	.pullup_dn_reg_base = PALMAS_##_rbase##_BASE,			\
+	.pullup_dn_reg_add = _add,					\
+	.pullup_dn_mask = _mask,					\
+	.normal_val = _nv,						\
+	.pull_up_val = _uv,						\
+	.pull_dn_val = _dv,						\
+}
+
+PULL_UP_DN(nreswarm,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL1,	0x2,	0x0,	0x2,	-1);
+PULL_UP_DN(pwrdown,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL1,	0x4,	0x0,	-1,	0x4);
+PULL_UP_DN(gpadc_start,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL1,	0x30,	0x0,	0x20,	0x10);
+PULL_UP_DN(reset_in,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL1,	0x40,	0x0,	-1,	0x40);
+PULL_UP_DN(nsleep,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL2,	0x3,	0x0,	0x2,	0x1);
+PULL_UP_DN(enable1,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL2,	0xC,	0x0,	0x8,	0x4);
+PULL_UP_DN(enable2,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL2,	0x30,	0x0,	0x20,	0x10);
+PULL_UP_DN(vacok,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL3,	0x40,	0x0,	-1,	0x40);
+PULL_UP_DN(chrg_det,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL3,	0x10,	0x0,	-1,	0x10);
+PULL_UP_DN(pwrhold,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL3,	0x4,	0x0,	-1,	0x4);
+PULL_UP_DN(msecure,	PU_PD_OD,	PALMAS_PU_PD_INPUT_CTRL3,	0x1,	0x0,	-1,	0x1);
+PULL_UP_DN(id,		USB_OTG,	PALMAS_USB_ID_CTRL_SET,		0x40,	0x0,	0x40,	-1);
+PULL_UP_DN(gpio0,	GPIO,		PALMAS_PU_PD_GPIO_CTRL1,	0x04,	0,	-1,	1);
+PULL_UP_DN(gpio1,	GPIO,		PALMAS_PU_PD_GPIO_CTRL1,	0x0C,	0,	0x8,	0x4);
+PULL_UP_DN(gpio2,	GPIO,		PALMAS_PU_PD_GPIO_CTRL1,	0x30,	0x0,	0x20,	0x10);
+PULL_UP_DN(gpio3,	GPIO,		PALMAS_PU_PD_GPIO_CTRL1,	0x40,	0x0,	-1,	0x40);
+PULL_UP_DN(gpio4,	GPIO,		PALMAS_PU_PD_GPIO_CTRL2,	0x03,	0x0,	0x2,	0x1);
+PULL_UP_DN(gpio5,	GPIO,		PALMAS_PU_PD_GPIO_CTRL2,	0x0c,	0x0,	0x8,	0x4);
+PULL_UP_DN(gpio6,	GPIO,		PALMAS_PU_PD_GPIO_CTRL2,	0x30,	0x0,	0x20,	0x10);
+PULL_UP_DN(gpio7,	GPIO,		PALMAS_PU_PD_GPIO_CTRL2,	0x40,	0x0,	-1,	0x40);
+PULL_UP_DN(gpio9,	GPIO,		PALMAS_PU_PD_GPIO_CTRL3,	0x0C,	0x0,	0x8,	0x4);
+PULL_UP_DN(gpio10,	GPIO,		PALMAS_PU_PD_GPIO_CTRL3,	0x30,	0x0,	0x20,	0x10);
+PULL_UP_DN(gpio11,	GPIO,		PALMAS_PU_PD_GPIO_CTRL3,	0xC0,	0x0,	0x80,	0x40);
+PULL_UP_DN(gpio13,	GPIO,		PALMAS_PU_PD_GPIO_CTRL4,	0x04,	0x0,	-1,	0x04);
+PULL_UP_DN(gpio14,	GPIO,		PALMAS_PU_PD_GPIO_CTRL4,	0x30,	0x0,	0x20,	0x10);
+
+#define OD_INFO(_name, _rbase, _add, _mask, _ev, _dv)		\
+static const struct palmas_pins_od_info od_##_name##_info = {	\
+	.od_reg_base = PALMAS_##_rbase##_BASE,			\
+	.od_reg_add = _add,					\
+	.od_mask = _mask,					\
+	.od_enable = _ev,					\
+	.od_disable = _dv,					\
+}
+
+OD_INFO(gpio1,	GPIO,	PALMAS_OD_OUTPUT_GPIO_CTRL,	0x1,	0x1,	0x0);
+OD_INFO(gpio2,	GPIO,	PALMAS_OD_OUTPUT_GPIO_CTRL,	0x2,	0x2,	0x0);
+OD_INFO(gpio5,	GPIO,	PALMAS_OD_OUTPUT_GPIO_CTRL,	0x20,	0x20,	0x0);
+OD_INFO(gpio10,	GPIO,	PALMAS_OD_OUTPUT_GPIO_CTRL2,	0x04,	0x04,	0x0);
+OD_INFO(gpio13,	GPIO,	PALMAS_OD_OUTPUT_GPIO_CTRL2,	0x20,	0x20,	0x0);
+OD_INFO(int,		PU_PD_OD,	PALMAS_OD_OUTPUT_CTRL,	0x8,	0x8,	0x0);
+OD_INFO(pwm1,		PU_PD_OD,	PALMAS_OD_OUTPUT_CTRL,	0x20,	0x20,	0x0);
+OD_INFO(pwm2,		PU_PD_OD,	PALMAS_OD_OUTPUT_CTRL,	0x80,	0x80,	0x0);
+OD_INFO(vbus_det,	PU_PD_OD,	PALMAS_OD_OUTPUT_CTRL,	0x40,	0x40,	0x0);
+
+#define PIN_INFO(_name, _id, _pud_info, _od_info)		\
+static const struct palmas_pin_info pin_##_name##_info = {	\
+	.mux_opt = PALMAS_PINMUX_##_id,				\
+	.pud_info = _pud_info,					\
+	.od_info = _od_info					\
+}
+
+PIN_INFO(gpio0,		GPIO,		&pud_gpio0_info,	NULL);
+PIN_INFO(gpio1,		GPIO,		&pud_gpio1_info,	&od_gpio1_info);
+PIN_INFO(gpio2,		GPIO,		&pud_gpio2_info,	&od_gpio2_info);
+PIN_INFO(gpio3,		GPIO,		&pud_gpio3_info,	NULL);
+PIN_INFO(gpio4,		GPIO,		&pud_gpio4_info,	NULL);
+PIN_INFO(gpio5,		GPIO,		&pud_gpio5_info,	&od_gpio5_info);
+PIN_INFO(gpio6,		GPIO,		&pud_gpio6_info,	NULL);
+PIN_INFO(gpio7,		GPIO,		&pud_gpio7_info,	NULL);
+PIN_INFO(gpio8,		GPIO,		NULL,			NULL);
+PIN_INFO(gpio9,		GPIO,		&pud_gpio9_info,	NULL);
+PIN_INFO(gpio10,	GPIO,		&pud_gpio10_info,	&od_gpio10_info);
+PIN_INFO(gpio11,	GPIO,		&pud_gpio11_info,	NULL);
+PIN_INFO(gpio12,	GPIO,		NULL,			NULL);
+PIN_INFO(gpio13,	GPIO,		&pud_gpio13_info,	&od_gpio13_info);
+PIN_INFO(gpio14,	GPIO,		&pud_gpio14_info,	NULL);
+PIN_INFO(gpio15,	GPIO,		NULL,			NULL);
+PIN_INFO(id,		ID,		&pud_id_info,		NULL);
+PIN_INFO(led1,		LED,		NULL,			NULL);
+PIN_INFO(led2,		LED,		NULL,			NULL);
+PIN_INFO(regen,		REGEN,		NULL,			NULL);
+PIN_INFO(sysen1,	SYSEN,		NULL,			NULL);
+PIN_INFO(sysen2,	SYSEN,		NULL,			NULL);
+PIN_INFO(int,		INT,		NULL,			&od_int_info);
+PIN_INFO(pwm1,		PWM,		NULL,			&od_pwm1_info);
+PIN_INFO(pwm2,		PWM,		NULL,			&od_pwm2_info);
+PIN_INFO(vacok,		VACOK,		&pud_vacok_info,	NULL);
+PIN_INFO(chrg_det,	CHRG_DET,	&pud_chrg_det_info,	NULL);
+PIN_INFO(pwrhold,	PWRHOLD,	&pud_pwrhold_info,	NULL);
+PIN_INFO(msecure,	MSECURE,	&pud_msecure_info,	NULL);
+PIN_INFO(nreswarm,	NA,		&pud_nreswarm_info,	NULL);
+PIN_INFO(pwrdown,	NA,		&pud_pwrdown_info,	NULL);
+PIN_INFO(gpadc_start,	NA,		&pud_gpadc_start_info,	NULL);
+PIN_INFO(reset_in,	NA,		&pud_reset_in_info,	NULL);
+PIN_INFO(nsleep,	NA,		&pud_nsleep_info,	NULL);
+PIN_INFO(enable1,	NA,		&pud_enable1_info,	NULL);
+PIN_INFO(enable2,	NA,		&pud_enable2_info,	NULL);
+PIN_INFO(clk32kgaudio,	CLK32KGAUDIO,	NULL,			NULL);
+PIN_INFO(usb_psel,	USB_PSEL,	NULL,			NULL);
+PIN_INFO(vac,		VAC,		NULL,			NULL);
+PIN_INFO(powergood,	POWERGOOD,	NULL,			NULL);
+PIN_INFO(vbus_det,	VBUS_DET,	NULL,			&od_vbus_det_info);
+PIN_INFO(sim1rsti,	SIMRSTI,	NULL,			NULL);
+PIN_INFO(low_vbat,	LOW_VBAT,	NULL,			NULL);
+PIN_INFO(rcm,		RCM,		NULL,			NULL);
+PIN_INFO(sim2rsto,	SIMRSTO,	NULL,			NULL);
+PIN_INFO(sim2rsti,	SIMRSTI,	NULL,			NULL);
+PIN_INFO(wireless_chrg1,	WIRELESS_CHRG1,	NULL,		NULL);
+
+#define PALMAS_PRIMARY_SECONDARY_NONE	0
+#define PALMAS_NONE_BASE		0
+#define PALMAS_PRIMARY_SECONDARY_INPUT3 PALMAS_PU_PD_INPUT_CTRL3
+
+#define PALMAS_PINGROUP(pg_name, pin_id, base, reg, _mask, _bshift, o0, o1, o2, o3)  \
+	{								\
+		.name = #pg_name,					\
+		.pins = {PALMAS_PIN_##pin_id},				\
+		.npins = 1,						\
+		.mux_reg_base = PALMAS_##base##_BASE,			\
+		.mux_reg_add = PALMAS_PRIMARY_SECONDARY_##reg,		\
+		.mux_reg_mask = _mask,					\
+		.mux_bit_shift = _bshift,				\
+		.opt = {						\
+			o0,						\
+			o1,						\
+			o2,						\
+			o3,						\
+		},							\
+	}
+
+static const struct palmas_pingroup tps65913_pingroups[] = {
+	PALMAS_PINGROUP(gpio0,	GPIO0_ID,			PU_PD_OD,	PAD1,	0x4,	0x2,	&pin_gpio0_info,	&pin_id_info,		NULL,		NULL),
+	PALMAS_PINGROUP(gpio1,	GPIO1_VBUS_LED1_PWM1,		PU_PD_OD,	PAD1,	0x18,	0x3,	&pin_gpio1_info,	&pin_vbus_det_info,	&pin_led1_info,	&pin_pwm1_info),
+	PALMAS_PINGROUP(gpio2,	GPIO2_REGEN_LED2_PWM2,		PU_PD_OD,	PAD1,	0x60,	0x5,	&pin_gpio2_info,	&pin_regen_info,	&pin_led2_info,	&pin_pwm2_info),
+	PALMAS_PINGROUP(gpio3,	GPIO3_CHRG_DET,			PU_PD_OD,	PAD1,	0x80,	0x7,	&pin_gpio3_info,	&pin_chrg_det_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio4,	GPIO4_SYSEN1,			PU_PD_OD,	PAD1,	0x01,	0x0,	&pin_gpio4_info,	&pin_sysen1_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio5,	GPIO5_CLK32KGAUDIO_USB_PSEL,	PU_PD_OD,	PAD2,	0x6,	0x1,	&pin_gpio5_info,	&pin_clk32kgaudio_info,	&pin_usb_psel_info,	NULL),
+	PALMAS_PINGROUP(gpio6,	GPIO6_SYSEN2,			PU_PD_OD,	PAD2,	0x08,	0x3,	&pin_gpio6_info,	&pin_sysen2_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio7,	GPIO7_MSECURE_PWRHOLD,		PU_PD_OD,	PAD2,	0x30,	0x4,	&pin_gpio7_info,	&pin_msecure_info,	&pin_pwrhold_info,	NULL),
+	PALMAS_PINGROUP(vac,	VAC,				PU_PD_OD,	PAD1,	0x02,	0x1,	&pin_vac_info,		&pin_vacok_info,	NULL,		NULL),
+	PALMAS_PINGROUP(powergood,	POWERGOOD_USB_PSEL,	PU_PD_OD,	PAD1,	0x01,	0x0,	&pin_powergood_info,	&pin_usb_psel_info,	NULL,	NULL),
+	PALMAS_PINGROUP(nreswarm,	NRESWARM,		NONE,		NONE,	0x0,	0x0,	&pin_nreswarm_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(pwrdown,	PWRDOWN,		NONE,		NONE,	0x0,	0x0,	&pin_pwrdown_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(gpadc_start,	GPADC_START,		NONE,		NONE,	0x0,	0x0,	&pin_gpadc_start_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(reset_in,	RESET_IN,		NONE,		NONE,	0x0,	0x0,	&pin_reset_in_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(nsleep,		NSLEEP,			NONE,		NONE,	0x0,	0x0,	&pin_nsleep_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(enable1,	ENABLE1,		NONE,		NONE,	0x0,	0x0,	&pin_enable1_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(enable2,	ENABLE2,		NONE,		NONE,	0x0,	0x0,	&pin_enable2_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(int,		INT,			NONE,		NONE,	0x0,	0x0,	&pin_int_info,		NULL,			NULL,		NULL),
+};
+
+static const struct palmas_pingroup tps80036_pingroups[] = {
+	PALMAS_PINGROUP(gpio0,	GPIO0_ID,			PU_PD_OD,	PAD1,	0x4,	0x2,	&pin_gpio0_info,	&pin_id_info,		NULL,		NULL),
+	PALMAS_PINGROUP(gpio1,	GPIO1_VBUS_LED1_PWM1,		PU_PD_OD,	PAD1,	0x18,	0x3,	&pin_gpio1_info,	&pin_vbus_det_info,	&pin_led1_info,	&pin_pwm1_info),
+	PALMAS_PINGROUP(gpio2,	GPIO2_REGEN_LED2_PWM2,		PU_PD_OD,	PAD1,	0x60,	0x5,	&pin_gpio2_info,	&pin_regen_info,	&pin_led2_info,	&pin_pwm2_info),
+	PALMAS_PINGROUP(gpio3,	GPIO3_CHRG_DET,			PU_PD_OD,	PAD1,	0x80,	0x7,	&pin_gpio3_info,	&pin_chrg_det_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio4,	GPIO4_SYSEN1,			PU_PD_OD,	PAD1,	0x01,	0x0,	&pin_gpio4_info,	&pin_sysen1_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio5,	GPIO5_CLK32KGAUDIO_USB_PSEL,	PU_PD_OD,	PAD2,	0x6,	0x1,	&pin_gpio5_info,	&pin_clk32kgaudio_info,	&pin_usb_psel_info,	NULL),
+	PALMAS_PINGROUP(gpio6,	GPIO6_SYSEN2,			PU_PD_OD,	PAD2,	0x08,	0x3,	&pin_gpio6_info,	&pin_sysen2_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio7,	GPIO7_MSECURE_PWRHOLD,		PU_PD_OD,	PAD2,	0x30,	0x4,	&pin_gpio7_info,	&pin_msecure_info,	&pin_pwrhold_info,	NULL),
+	PALMAS_PINGROUP(gpio8,	GPIO8_SIM1RSTI,			PU_PD_OD,	PAD4,	0x01,	0x0,	&pin_gpio8_info,	&pin_sim1rsti_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio9,	GPIO9_LOW_VBAT,			PU_PD_OD,	PAD4,	0x02,	0x1,	&pin_gpio9_info,	&pin_low_vbat_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio10,	GPIO10_WIRELESS_CHRG1,		PU_PD_OD,	PAD4,	0x04,	0x2,	&pin_gpio10_info,	&pin_wireless_chrg1_info,	NULL,	NULL),
+	PALMAS_PINGROUP(gpio11,	GPIO11_RCM,			PU_PD_OD,	PAD4,	0x08,	0x3,	&pin_gpio11_info,	&pin_rcm_info,		NULL,		NULL),
+	PALMAS_PINGROUP(gpio12,	GPIO12_SIM2RSTO,		PU_PD_OD,	PAD4,	0x10,	0x4,	&pin_gpio12_info,	&pin_sim2rsto_info,	NULL,		NULL),
+	PALMAS_PINGROUP(gpio13,	GPIO13,				NONE,		NONE,	0x00,	0x0,	&pin_gpio13_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(gpio14,	GPIO14,				NONE,		NONE,	0x00,	0x0,	&pin_gpio14_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(gpio15,	GPIO15_SIM2RSTI,		PU_PD_OD,	PAD4,	0x80,	0x7,	&pin_gpio15_info,	&pin_sim2rsti_info,	NULL,		NULL),
+	PALMAS_PINGROUP(vac,	VAC,				PU_PD_OD,	PAD1,	0x02,	0x1,	&pin_vac_info,		&pin_vacok_info,	NULL,		NULL),
+	PALMAS_PINGROUP(powergood,	POWERGOOD_USB_PSEL,	PU_PD_OD,	PAD1,	0x01,	0x0,	&pin_powergood_info,	&pin_usb_psel_info,	NULL,	NULL),
+	PALMAS_PINGROUP(nreswarm,	NRESWARM,		NONE,		NONE,	0x0,	0x0,	&pin_nreswarm_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(pwrdown,	PWRDOWN,		NONE,		NONE,	0x0,	0x0,	&pin_pwrdown_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(gpadc_start,	GPADC_START,		NONE,		NONE,	0x0,	0x0,	&pin_gpadc_start_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(reset_in,	RESET_IN,		NONE,		NONE,	0x0,	0x0,	&pin_reset_in_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(nsleep,		NSLEEP,			NONE,		NONE,	0x0,	0x0,	&pin_nsleep_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(enable1,	ENABLE1,		NONE,		NONE,	0x0,	0x0,	&pin_enable1_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(enable2,	ENABLE2,		NONE,		NONE,	0x0,	0x0,	&pin_enable2_info,	NULL,			NULL,		NULL),
+	PALMAS_PINGROUP(int,		INT,			NONE,		NONE,	0x0,	0x0,	&pin_int_info,		NULL,			NULL,		NULL),
+};
+
+static int palmas_pinctrl_get_pin_mux(struct palmas_pctrl_chip_info *pci)
+{
+	const struct palmas_pingroup *g;
+	unsigned int val;
+	int ret;
+	int i;
+
+	for (i = 0; i < pci->num_pin_groups; ++i) {
+		g = &pci->pin_groups[i];
+		if (g->mux_reg_base == PALMAS_NONE_BASE) {
+			pci->pins_current_opt[i] = 0;
+			continue;
+		}
+		ret = palmas_read(pci->palmas, g->mux_reg_base,
+				g->mux_reg_add, &val);
+		if (ret < 0) {
+			dev_err(pci->dev, "mux_reg 0x%02x read failed: %d\n",
+					g->mux_reg_add, ret);
+			return ret;
+		}
+		val &= g->mux_reg_mask;
+		pci->pins_current_opt[i] = val >> g->mux_bit_shift;
+	}
+	return 0;
+}
+
+static int palmas_pinctrl_set_dvfs1(struct palmas_pctrl_chip_info *pci,
+		bool enable)
+{
+	int ret;
+	int val;
+
+	val = enable ? PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1 : 0;
+	ret = palmas_update_bits(pci->palmas, PALMAS_PU_PD_OD_BASE,
+			PALMAS_PRIMARY_SECONDARY_PAD3,
+			PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1, val);
+	if (ret < 0)
+		dev_err(pci->dev, "SECONDARY_PAD3 update failed %d\n", ret);
+	return ret;
+}
+
+static int palmas_pinctrl_set_dvfs2(struct palmas_pctrl_chip_info *pci,
+		bool enable)
+{
+	int ret;
+	int val;
+
+	val = enable ? PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2 : 0;
+	ret = palmas_update_bits(pci->palmas, PALMAS_PU_PD_OD_BASE,
+			PALMAS_PRIMARY_SECONDARY_PAD3,
+			PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2, val);
+	if (ret < 0)
+		dev_err(pci->dev, "SECONDARY_PAD3 update failed %d\n", ret);
+	return ret;
+}
+
+static int palmas_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+
+	return pci->num_pin_groups;
+}
+
+static const char *palmas_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+		unsigned group)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+
+	return pci->pin_groups[group].name;
+}
+
+static int palmas_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned group, const unsigned **pins, unsigned *num_pins)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = pci->pin_groups[group].pins;
+	*num_pins = pci->pin_groups[group].npins;
+	return 0;
+}
+
+static const struct pinctrl_ops palmas_pinctrl_ops = {
+	.get_groups_count = palmas_pinctrl_get_groups_count,
+	.get_group_name = palmas_pinctrl_get_group_name,
+	.get_group_pins = palmas_pinctrl_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+	.dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int palmas_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+
+	return pci->num_functions;
+}
+
+static const char *palmas_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+			unsigned function)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+
+	return pci->functions[function].name;
+}
+
+static int palmas_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+		unsigned function, const char * const **groups,
+		unsigned * const num_groups)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pci->functions[function].groups;
+	*num_groups = pci->functions[function].ngroups;
+	return 0;
+}
+
+static int palmas_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+		unsigned group)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+	const struct palmas_pingroup *g;
+	int i;
+	int ret;
+
+	g = &pci->pin_groups[group];
+
+	/* If direct option is provided here */
+	if (function <= PALMAS_PINMUX_OPTION3) {
+		if (!g->opt[function]) {
+			dev_err(pci->dev, "Pin %s does not support option %d\n",
+				g->name, function);
+			return -EINVAL;
+		}
+		i = function;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(g->opt); i++) {
+			if (!g->opt[i])
+				continue;
+			if (g->opt[i]->mux_opt == function)
+				break;
+		}
+		if (WARN_ON(i == ARRAY_SIZE(g->opt))) {
+			dev_err(pci->dev, "Pin %s does not support option %d\n",
+				g->name, function);
+			return -EINVAL;
+		}
+	}
+
+	if (g->mux_reg_base == PALMAS_NONE_BASE) {
+		if (WARN_ON(i != 0))
+			return -EINVAL;
+		return 0;
+	}
+
+	dev_dbg(pci->dev, "%s(): Base0x%02x:0x%02x:0x%02x:0x%02x\n",
+			__func__, g->mux_reg_base, g->mux_reg_add,
+			g->mux_reg_mask, i << g->mux_bit_shift);
+
+	ret = palmas_update_bits(pci->palmas, g->mux_reg_base, g->mux_reg_add,
+			g->mux_reg_mask, i << g->mux_bit_shift);
+	if (ret < 0) {
+		dev_err(pci->dev, "Reg 0x%02x update failed: %d\n",
+				g->mux_reg_add, ret);
+		return ret;
+	}
+	pci->pins_current_opt[group] = i;
+	return 0;
+}
+
+static const struct pinmux_ops palmas_pinmux_ops = {
+	.get_functions_count = palmas_pinctrl_get_funcs_count,
+	.get_function_name = palmas_pinctrl_get_func_name,
+	.get_function_groups = palmas_pinctrl_get_func_groups,
+	.enable = palmas_pinctrl_enable,
+};
+
+static int palmas_pinconf_get(struct pinctrl_dev *pctldev,
+			unsigned pin, unsigned long *config)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	const struct palmas_pingroup *g;
+	const struct palmas_pin_info *opt;
+	unsigned int val;
+	int ret;
+	int base, add;
+	int rval;
+	int arg;
+	int group_nr;
+
+	for (group_nr = 0; group_nr < pci->num_pin_groups; ++group_nr) {
+		if (pci->pin_groups[group_nr].pins[0] == pin)
+			break;
+	}
+
+	if (group_nr == pci->num_pin_groups) {
+		dev_err(pci->dev,
+			"Pinconf is not supported for pin-id %d\n", pin);
+		return -ENOTSUPP;
+	}
+
+	g = &pci->pin_groups[group_nr];
+	opt = g->opt[pci->pins_current_opt[group_nr]];
+	if (!opt) {
+		dev_err(pci->dev,
+			"Pinconf is not supported for pin %s\n", g->name);
+		return -ENOTSUPP;
+	}
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+	case PIN_CONFIG_BIAS_PULL_UP:
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!opt->pud_info) {
+			dev_err(pci->dev,
+				"PULL control not supported for pin %s\n",
+				g->name);
+			return -ENOTSUPP;
+		}
+		base = opt->pud_info->pullup_dn_reg_base;
+		add = opt->pud_info->pullup_dn_reg_add;
+		ret = palmas_read(pci->palmas, base, add, &val);
+		if (ret < 0) {
+			dev_err(pci->dev, "Reg 0x%02x read failed: %d\n",
+				add, ret);
+			return ret;
+		}
+
+		rval = val & opt->pud_info->pullup_dn_mask;
+		arg = 0;
+		if ((opt->pud_info->normal_val >= 0) &&
+				(opt->pud_info->normal_val == rval) &&
+				(param == PIN_CONFIG_BIAS_DISABLE))
+			arg = 1;
+		else if ((opt->pud_info->pull_up_val >= 0) &&
+				(opt->pud_info->pull_up_val == rval) &&
+				(param == PIN_CONFIG_BIAS_PULL_UP))
+			arg = 1;
+		else if ((opt->pud_info->pull_dn_val >= 0) &&
+				(opt->pud_info->pull_dn_val == rval) &&
+				(param == PIN_CONFIG_BIAS_PULL_DOWN))
+			arg = 1;
+		break;
+
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		if (!opt->od_info) {
+			dev_err(pci->dev,
+				"OD control not supported for pin %s\n",
+				g->name);
+			return -ENOTSUPP;
+		}
+		base = opt->od_info->od_reg_base;
+		add = opt->od_info->od_reg_add;
+		ret = palmas_read(pci->palmas, base, add, &val);
+		if (ret < 0) {
+			dev_err(pci->dev, "Reg 0x%02x read failed: %d\n",
+				add, ret);
+			return ret;
+		}
+		rval = val & opt->od_info->od_mask;
+		arg = -1;
+		if ((opt->od_info->od_disable >= 0) &&
+				(opt->od_info->od_disable == rval))
+			arg = 0;
+		else if ((opt->od_info->od_enable >= 0) &&
+					(opt->od_info->od_enable == rval))
+			arg = 1;
+		if (arg < 0) {
+			dev_err(pci->dev,
+				"OD control not supported for pin %s\n",
+				g->name);
+			return -ENOTSUPP;
+		}
+		break;
+
+	default:
+		dev_err(pci->dev, "Properties not supported\n");
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, (u16)arg);
+	return 0;
+}
+
+static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
+			unsigned pin, unsigned long *configs,
+			unsigned num_configs)
+{
+	struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param;
+	u16 param_val;
+	const struct palmas_pingroup *g;
+	const struct palmas_pin_info *opt;
+	int ret;
+	int base, add, mask;
+	int rval;
+	int group_nr;
+	int i;
+
+	for (group_nr = 0; group_nr < pci->num_pin_groups; ++group_nr) {
+		if (pci->pin_groups[group_nr].pins[0] == pin)
+			break;
+	}
+
+	if (group_nr == pci->num_pin_groups) {
+		dev_err(pci->dev,
+			"Pinconf is not supported for pin-id %d\n", pin);
+		return -ENOTSUPP;
+	}
+
+	g = &pci->pin_groups[group_nr];
+	opt = g->opt[pci->pins_current_opt[group_nr]];
+	if (!opt) {
+		dev_err(pci->dev,
+			"Pinconf is not supported for pin %s\n", g->name);
+		return -ENOTSUPP;
+	}
+
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		param_val = pinconf_to_config_argument(configs[i]);
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+			return 0;
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!opt->pud_info) {
+				dev_err(pci->dev,
+					"PULL control not supported for pin %s\n",
+					g->name);
+				return -ENOTSUPP;
+			}
+			base = opt->pud_info->pullup_dn_reg_base;
+			add = opt->pud_info->pullup_dn_reg_add;
+			mask = opt->pud_info->pullup_dn_mask;
+
+			if (param == PIN_CONFIG_BIAS_DISABLE)
+				rval = opt->pud_info->normal_val;
+			else if (param == PIN_CONFIG_BIAS_PULL_UP)
+				rval = opt->pud_info->pull_up_val;
+			else
+				rval = opt->pud_info->pull_dn_val;
+
+			if (rval < 0) {
+				dev_err(pci->dev,
+					"PULL control not supported for pin %s\n",
+					g->name);
+				return -ENOTSUPP;
+			}
+			break;
+
+		case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+			if (!opt->od_info) {
+				dev_err(pci->dev,
+					"OD control not supported for pin %s\n",
+					g->name);
+				return -ENOTSUPP;
+			}
+			base = opt->od_info->od_reg_base;
+			add = opt->od_info->od_reg_add;
+			mask = opt->od_info->od_mask;
+			if (param_val == 0)
+				rval = opt->od_info->od_disable;
+			else
+				rval = opt->od_info->od_enable;
+			if (rval < 0) {
+				dev_err(pci->dev,
+					"OD control not supported for pin %s\n",
+					g->name);
+				return -ENOTSUPP;
+			}
+			break;
+		default:
+			dev_err(pci->dev, "Properties not supported\n");
+			return -ENOTSUPP;
+		}
+
+		dev_dbg(pci->dev, "%s(): Add0x%02x:0x%02x:0x%02x:0x%02x\n",
+				__func__, base, add, mask, rval);
+		ret = palmas_update_bits(pci->palmas, base, add, mask, rval);
+		if (ret < 0) {
+			dev_err(pci->dev, "Reg 0x%02x update failed: %d\n",
+				add, ret);
+			return ret;
+		}
+	} /* for each config */
+
+	return 0;
+}
+
+static int palmas_pinconf_group_get(struct pinctrl_dev *pctldev,
+				unsigned group, unsigned long *config)
+{
+	dev_err(pctldev->dev, "palmas_pinconf_group_get op not supported\n");
+	return -ENOTSUPP;
+}
+
+static int palmas_pinconf_group_set(struct pinctrl_dev *pctldev,
+				unsigned group, unsigned long *configs,
+				unsigned num_configs)
+{
+	dev_err(pctldev->dev, "palmas_pinconf_group_set op not supported\n");
+	return -ENOTSUPP;
+}
+
+static const struct pinconf_ops palmas_pinconf_ops = {
+	.pin_config_get = palmas_pinconf_get,
+	.pin_config_set = palmas_pinconf_set,
+	.pin_config_group_get = palmas_pinconf_group_get,
+	.pin_config_group_set = palmas_pinconf_group_set,
+};
+
+static struct pinctrl_desc palmas_pinctrl_desc = {
+	.pctlops = &palmas_pinctrl_ops,
+	.pmxops = &palmas_pinmux_ops,
+	.confops = &palmas_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+struct palmas_pinctrl_data {
+	const struct palmas_pingroup *pin_groups;
+	int num_pin_groups;
+};
+
+static struct palmas_pinctrl_data tps65913_pinctrl_data = {
+	.pin_groups = tps65913_pingroups,
+	.num_pin_groups = ARRAY_SIZE(tps65913_pingroups),
+};
+
+static struct palmas_pinctrl_data tps80036_pinctrl_data = {
+	.pin_groups = tps80036_pingroups,
+	.num_pin_groups = ARRAY_SIZE(tps80036_pingroups),
+};
+
+static struct of_device_id palmas_pinctrl_of_match[] = {
+	{ .compatible = "ti,palmas-pinctrl", .data = &tps65913_pinctrl_data},
+	{ .compatible = "ti,tps65913-pinctrl", .data = &tps65913_pinctrl_data},
+	{ .compatible = "ti,tps80036-pinctrl", .data = &tps80036_pinctrl_data},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, palmas_pinctrl_of_match);
+
+static int palmas_pinctrl_probe(struct platform_device *pdev)
+{
+	struct palmas_pctrl_chip_info *pci;
+	const struct palmas_pinctrl_data *pinctrl_data = &tps65913_pinctrl_data;
+	int ret;
+	bool enable_dvfs1 = false;
+	bool enable_dvfs2 = false;
+
+	if (pdev->dev.of_node) {
+		const struct of_device_id *match;
+		match = of_match_device(palmas_pinctrl_of_match, &pdev->dev);
+		pinctrl_data = match->data;
+		enable_dvfs1 = of_property_read_bool(pdev->dev.of_node,
+					"ti,palmas-enable-dvfs1");
+		enable_dvfs2 = of_property_read_bool(pdev->dev.of_node,
+					"ti,palmas-enable-dvfs2");
+	}
+
+	pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL);
+	if (!pci) {
+		dev_err(&pdev->dev, "Malloc for pci failed\n");
+		return -ENOMEM;
+	}
+
+	pci->dev = &pdev->dev;
+	pci->palmas = dev_get_drvdata(pdev->dev.parent);
+
+	pci->pins = palmas_pins_desc;
+	pci->num_pins = ARRAY_SIZE(palmas_pins_desc);
+	pci->functions = palmas_pin_function;
+	pci->num_functions = ARRAY_SIZE(palmas_pin_function);
+	pci->pin_groups = pinctrl_data->pin_groups;
+	pci->num_pin_groups = pinctrl_data->num_pin_groups;
+
+	platform_set_drvdata(pdev, pci);
+
+	palmas_pinctrl_set_dvfs1(pci, enable_dvfs1);
+	palmas_pinctrl_set_dvfs2(pci, enable_dvfs2);
+	ret = palmas_pinctrl_get_pin_mux(pci);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Reading pinctrol option register failed: %d\n", ret);
+		return ret;
+	}
+
+	palmas_pinctrl_desc.name = dev_name(&pdev->dev);
+	palmas_pinctrl_desc.pins = palmas_pins_desc;
+	palmas_pinctrl_desc.npins = ARRAY_SIZE(palmas_pins_desc);
+	pci->pctl = pinctrl_register(&palmas_pinctrl_desc, &pdev->dev, pci);
+	if (!pci->pctl) {
+		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static int palmas_pinctrl_remove(struct platform_device *pdev)
+{
+	struct palmas_pctrl_chip_info *pci = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(pci->pctl);
+	return 0;
+}
+
+static struct platform_driver palmas_pinctrl_driver = {
+	.driver = {
+		.name = "palmas-pinctrl",
+		.owner = THIS_MODULE,
+		.of_match_table = palmas_pinctrl_of_match,
+	},
+	.probe = palmas_pinctrl_probe,
+	.remove = palmas_pinctrl_remove,
+};
+
+module_platform_driver(palmas_pinctrl_driver);
+
+MODULE_DESCRIPTION("Palmas pin control driver");
+MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");
+MODULE_ALIAS("platform:palmas-pinctrl");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 1eb5a2e..e0718b7 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -36,7 +36,7 @@
 #include <linux/pinctrl/pinmux.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/irqchip/chained_irq.h>
-#include <linux/clk-provider.h>
+#include <linux/clk.h>
 #include <dt-bindings/pinctrl/rockchip.h>
 
 #include "core.h"
@@ -167,18 +167,14 @@
 					const struct rockchip_pinctrl *info,
 					const char *name)
 {
-	const struct rockchip_pin_group *grp = NULL;
 	int i;
 
 	for (i = 0; i < info->ngroups; i++) {
-		if (strcmp(info->groups[i].name, name))
-			continue;
-
-		grp = &info->groups[i];
-		break;
+		if (!strcmp(info->groups[i].name, name))
+			return &info->groups[i];
 	}
 
-	return grp;
+	return NULL;
 }
 
 /*
@@ -190,8 +186,7 @@
 {
 	struct rockchip_pin_bank *b = info->ctrl->pin_banks;
 
-	while ((pin >= b->pin_base) &&
-			((b->pin_base + b->nr_pins - 1) < pin))
+	while (pin >= (b->pin_base + b->nr_pins))
 		b++;
 
 	return b;
@@ -204,17 +199,12 @@
 	struct rockchip_pin_bank *b = info->ctrl->pin_banks;
 	int i;
 
-	for (i = 0; i < info->ctrl->nr_banks; i++) {
+	for (i = 0; i < info->ctrl->nr_banks; i++, b++) {
 		if (b->bank_num == num)
-			break;
-
-		b++;
+			return b;
 	}
 
-	if (b->bank_num != num)
-		return ERR_PTR(-EINVAL);
-
-	return b;
+	return ERR_PTR(-EINVAL);
 }
 
 /*
@@ -584,32 +574,45 @@
 
 /* set the pin config settings for a specified pin */
 static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
-							unsigned long config)
+				unsigned long *configs, unsigned num_configs)
 {
 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
 	struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
-	enum pin_config_param param = pinconf_to_config_param(config);
-	u16 arg = pinconf_to_config_argument(config);
+	enum pin_config_param param;
+	u16 arg;
+	int i;
+	int rc;
 
-	switch (param) {
-	case PIN_CONFIG_BIAS_DISABLE:
-		return rockchip_set_pull(bank, pin - bank->pin_base, param);
-		break;
-	case PIN_CONFIG_BIAS_PULL_UP:
-	case PIN_CONFIG_BIAS_PULL_DOWN:
-	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
-		if (!rockchip_pinconf_pull_valid(info->ctrl, param))
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			rc =  rockchip_set_pull(bank, pin - bank->pin_base,
+				param);
+			if (rc)
+				return rc;
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+		case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+			if (!rockchip_pinconf_pull_valid(info->ctrl, param))
+				return -ENOTSUPP;
+
+			if (!arg)
+				return -EINVAL;
+
+			rc = rockchip_set_pull(bank, pin - bank->pin_base,
+				param);
+			if (rc)
+				return rc;
+			break;
+		default:
 			return -ENOTSUPP;
-
-		if (!arg)
-			return -EINVAL;
-
-		return rockchip_set_pull(bank, pin - bank->pin_base, param);
-		break;
-	default:
-		return -ENOTSUPP;
-		break;
-	}
+			break;
+		}
+	} /* for each config */
 
 	return 0;
 }
@@ -881,6 +884,16 @@
  * GPIO handling
  */
 
+static int rockchip_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void rockchip_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	pinctrl_free_gpio(chip->base + offset);
+}
+
 static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
 {
 	struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
@@ -954,6 +967,8 @@
 }
 
 static const struct gpio_chip rockchip_gpiolib_chip = {
+	.request = rockchip_gpio_request,
+	.free = rockchip_gpio_free,
 	.set = rockchip_gpio_set,
 	.get = rockchip_gpio_get,
 	.direction_input = rockchip_gpio_direction_input,
@@ -1270,11 +1285,6 @@
 	info->dev = dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(dev, "cannot find IO resource\n");
-		return -ENOENT;
-	}
-
 	info->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->reg_base))
 		return PTR_ERR(info->reg_base);
@@ -1379,7 +1389,7 @@
 	.driver = {
 		.name	= "rockchip-pinctrl",
 		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(rockchip_pinctrl_dt_match),
+		.of_match_table = rockchip_pinctrl_dt_match,
 	},
 };
 
diff --git a/drivers/pinctrl/pinctrl-s3c24xx.c b/drivers/pinctrl/pinctrl-s3c24xx.c
index 24446da..ad3eaad 100644
--- a/drivers/pinctrl/pinctrl-s3c24xx.c
+++ b/drivers/pinctrl/pinctrl-s3c24xx.c
@@ -549,7 +549,7 @@
 		irq = bank->eint_offset;
 		mask = bank->eint_mask;
 		for (pin = 0; mask; ++pin, mask >>= 1) {
-			if (irq > NUM_EINT)
+			if (irq >= NUM_EINT)
 				break;
 			if (!(mask & 1))
 				continue;
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index a7fa9e2..92a9d6c 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -442,9 +442,17 @@
 
 /* set the pin config settings for a specified pin */
 static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
-				unsigned long config)
+				unsigned long *configs, unsigned num_configs)
 {
-	return samsung_pinconf_rw(pctldev, pin, &config, true);
+	int i, ret;
+
+	for (i = 0; i < num_configs; i++) {
+		ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
+		if (ret < 0)
+			return ret;
+	} /* for each config */
+
+	return 0;
 }
 
 /* get the pin config settings for a specified pin */
@@ -456,7 +464,8 @@
 
 /* set the pin config settings for a specified pin group */
 static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
-			unsigned group, unsigned long config)
+			unsigned group, unsigned long *configs,
+			unsigned num_configs)
 {
 	struct samsung_pinctrl_drv_data *drvdata;
 	const unsigned int *pins;
@@ -466,7 +475,7 @@
 	pins = drvdata->pin_groups[group].pins;
 
 	for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
-		samsung_pinconf_set(pctldev, pins[cnt], config);
+		samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
 
 	return 0;
 }
@@ -767,6 +776,10 @@
 		}
 	}
 
+	ret = samsung_pinctrl_parse_dt(pdev, drvdata);
+	if (ret)
+		return ret;
+
 	drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata);
 	if (!drvdata->pctl_dev) {
 		dev_err(&pdev->dev, "could not register pinctrl driver\n");
@@ -784,12 +797,6 @@
 		pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange);
 	}
 
-	ret = samsung_pinctrl_parse_dt(pdev, drvdata);
-	if (ret) {
-		pinctrl_unregister(drvdata->pctl_dev);
-		return ret;
-	}
-
 	return 0;
 }
 
@@ -1115,6 +1122,8 @@
 		.data = (void *)exynos5250_pin_ctrl },
 	{ .compatible = "samsung,exynos5420-pinctrl",
 		.data = (void *)exynos5420_pin_ctrl },
+	{ .compatible = "samsung,s5pv210-pinctrl",
+		.data = (void *)s5pv210_pin_ctrl },
 #endif
 #ifdef CONFIG_PINCTRL_S3C64XX
 	{ .compatible = "samsung,s3c64xx-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 11bb75b..30622d9 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -260,5 +260,6 @@
 extern struct samsung_pin_ctrl s3c2416_pin_ctrl[];
 extern struct samsung_pin_ctrl s3c2440_pin_ctrl[];
 extern struct samsung_pin_ctrl s3c2450_pin_ctrl[];
+extern struct samsung_pin_ctrl s5pv210_pin_ctrl[];
 
 #endif /* __PINCTRL_SAMSUNG_H */
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 7323cca..a82ace4 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -209,7 +209,7 @@
 static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
 			   unsigned long *config);
 static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
-			   unsigned long config);
+			   unsigned long *configs, unsigned num_configs);
 
 static enum pin_config_param pcs_bias[] = {
 	PIN_CONFIG_BIAS_PULL_DOWN,
@@ -536,7 +536,7 @@
 	int i;
 	for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
 		config = pinconf_to_config_packed(pcs_bias[i], 0);
-		pcs_pinconf_set(pctldev, pin, config);
+		pcs_pinconf_set(pctldev, pin, &config, 1);
 	}
 }
 
@@ -622,22 +622,28 @@
 }
 
 static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
-				unsigned pin, unsigned long config)
+				unsigned pin, unsigned long *configs,
+				unsigned num_configs)
 {
 	struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
 	struct pcs_function *func;
 	unsigned offset = 0, shift = 0, i, data, ret;
 	u16 arg;
+	int j;
 
 	ret = pcs_get_function(pctldev, pin, &func);
 	if (ret)
 		return ret;
 
-	for (i = 0; i < func->nconfs; i++) {
-		if (pinconf_to_config_param(config) == func->conf[i].param) {
+	for (j = 0; j < num_configs; j++) {
+		for (i = 0; i < func->nconfs; i++) {
+			if (pinconf_to_config_param(configs[j])
+				!= func->conf[i].param)
+				continue;
+
 			offset = pin * (pcs->width / BITS_PER_BYTE);
 			data = pcs->read(pcs->base + offset);
-			arg = pinconf_to_config_argument(config);
+			arg = pinconf_to_config_argument(configs[j]);
 			switch (func->conf[i].param) {
 			/* 2 parameters */
 			case PIN_CONFIG_INPUT_SCHMITT:
@@ -667,10 +673,14 @@
 				return -ENOTSUPP;
 			}
 			pcs->write(data, pcs->base + offset);
-			return 0;
+
+			break;
 		}
-	}
-	return -ENOTSUPP;
+		if (i >= func->nconfs)
+			return -ENOTSUPP;
+	} /* for each config */
+
+	return 0;
 }
 
 static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
@@ -695,7 +705,8 @@
 }
 
 static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
-				unsigned group, unsigned long config)
+				unsigned group, unsigned long *configs,
+				unsigned num_configs)
 {
 	const unsigned *pins;
 	unsigned npins;
@@ -705,7 +716,7 @@
 	if (ret)
 		return ret;
 	for (i = 0; i < npins; i++) {
-		if (pcs_pinconf_set(pctldev, pins[i], config))
+		if (pcs_pinconf_set(pctldev, pins[i], configs, num_configs))
 			return -ENOTSUPP;
 	}
 	return 0;
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 04d4506..9cadc68 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -288,8 +288,8 @@
 
 /* SOC specific data */
 /* STiH415 data */
-unsigned int stih415_input_delays[] = {0, 500, 1000, 1500};
-unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000};
+static unsigned int stih415_input_delays[] = {0, 500, 1000, 1500};
+static unsigned int stih415_output_delays[] = {0, 1000, 2000, 3000};
 
 #define STIH415_PCTRL_COMMON_DATA				\
 	.rt_style	= st_retime_style_packed,		\
@@ -324,7 +324,7 @@
 };
 
 /* STiH416 data */
-unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
+static unsigned int stih416_delays[] = {0, 300, 500, 750, 1000, 1250, 1500,
 			1750, 2000, 2250, 2500, 2750, 3000, 3250 };
 
 static const struct st_pctl_data  stih416_data = {
@@ -811,7 +811,7 @@
 	return info->nfunctions;
 }
 
-const char *st_pmx_get_fname(struct pinctrl_dev *pctldev,
+static const char *st_pmx_get_fname(struct pinctrl_dev *pctldev,
 	unsigned selector)
 {
 	struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
@@ -909,15 +909,18 @@
 							config, pin);
 }
 
-static int st_pinconf_set(struct pinctrl_dev *pctldev,
-			     unsigned pin_id, unsigned long config)
+static int st_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin_id,
+			unsigned long *configs, unsigned num_configs)
 {
 	int pin = st_gpio_pin(pin_id);
 	struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
 	struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id);
+	int i;
 
-	st_pinconf_set_config(pc, pin, config);
-	st_pinconf_set_retime(info, pc, pin, config);
+	for (i = 0; i < num_configs; i++) {
+		st_pinconf_set_config(pc, pin, configs[i]);
+		st_pinconf_set_retime(info, pc, pin, configs[i]);
+	} /* for each config */
 
 	return 0;
 }
@@ -1222,11 +1225,9 @@
 	if (of_address_to_resource(np, 0, &res))
 		return -ENODEV;
 
-	bank->base = devm_request_and_ioremap(dev, &res);
-	if (!bank->base) {
-		dev_err(dev, "Can't get IO memory mapping!\n");
-		return -ENODEV;
-	}
+	bank->base = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(bank->base))
+		return PTR_ERR(bank->base);
 
 	bank->gpio_chip = st_gpio_template;
 	bank->gpio_chip.base = bank_num * ST_GPIO_PINS_PER_BANK;
diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h
index 2eeae0c..2c7446a 100644
--- a/drivers/pinctrl/pinctrl-sunxi-pins.h
+++ b/drivers/pinctrl/pinctrl-sunxi-pins.h
@@ -806,7 +806,7 @@
 		  SUNXI_FUNCTION(0x3, "pata"),		/* ATAD13 */
 		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN7 */
 		  SUNXI_FUNCTION(0x5, "sim"),		/* VCCEN */
-		SUNXI_FUNCTION_IRQ(0x6, 17),		/* EINT17 */
+		  SUNXI_FUNCTION_IRQ(0x6, 17),		/* EINT17 */
 		  SUNXI_FUNCTION(0x7, "csi1")),		/* D17 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -815,7 +815,7 @@
 		  SUNXI_FUNCTION(0x3, "pata"),		/* ATAD14 */
 		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT0 */
 		  SUNXI_FUNCTION(0x5, "sim"),		/* SCK */
-		SUNXI_FUNCTION_IRQ(0x6, 18),		/* EINT18 */
+		  SUNXI_FUNCTION_IRQ(0x6, 18),		/* EINT18 */
 		  SUNXI_FUNCTION(0x7, "csi1")),		/* D18 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -824,7 +824,7 @@
 		  SUNXI_FUNCTION(0x3, "pata"),		/* ATAD15 */
 		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT1 */
 		  SUNXI_FUNCTION(0x5, "sim"),		/* SDA */
-		SUNXI_FUNCTION_IRQ(0x6, 19),		/* EINT19 */
+		  SUNXI_FUNCTION_IRQ(0x6, 19),		/* EINT19 */
 		  SUNXI_FUNCTION(0x7, "csi1")),		/* D19 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -832,7 +832,7 @@
 		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D20 */
 		  SUNXI_FUNCTION(0x3, "pata"),		/* ATAOE */
 		  SUNXI_FUNCTION(0x4, "can"),		/* TX */
-		SUNXI_FUNCTION_IRQ(0x6, 20),		/* EINT20 */
+		  SUNXI_FUNCTION_IRQ(0x6, 20),		/* EINT20 */
 		  SUNXI_FUNCTION(0x7, "csi1")),		/* D20 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -840,7 +840,7 @@
 		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D21 */
 		  SUNXI_FUNCTION(0x3, "pata"),		/* ATADREQ */
 		  SUNXI_FUNCTION(0x4, "can"),		/* RX */
-		SUNXI_FUNCTION_IRQ(0x6, 21),		/* EINT21 */
+		  SUNXI_FUNCTION_IRQ(0x6, 21),		/* EINT21 */
 		  SUNXI_FUNCTION(0x7, "csi1")),		/* D21 */
 	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
 		  SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -2005,6 +2005,1834 @@
 		  SUNXI_FUNCTION_IRQ(0x6, 12)),		/* EINT12 */
 };
 
+static const struct sunxi_desc_pin sun6i_a31_pins[] = {
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD0 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* DTR */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD1 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* DSR */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD2 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* DCD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD3 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* RING */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD4 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D4 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD5 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D5 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD6 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D6 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* RTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXD7 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D7 */
+		  SUNXI_FUNCTION(0x4, "uart1")),	/* CTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXCLK */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D8 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXEN */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D9 */
+		  SUNXI_FUNCTION(0x4, "mmc3"),		/* CMD */
+		  SUNXI_FUNCTION(0x5, "mmc2")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* GTXCLK */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D10 */
+		  SUNXI_FUNCTION(0x4, "mmc3"),		/* CLK */
+		  SUNXI_FUNCTION(0x5, "mmc2")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD0 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D11 */
+		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D0 */
+		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD1 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D12 */
+		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D1 */
+		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD2 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D13 */
+		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D2 */
+		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD3 */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D14 */
+		  SUNXI_FUNCTION(0x4, "mmc3"),		/* D3 */
+		  SUNXI_FUNCTION(0x5, "mmc2")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD4 */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D15 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD5 */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D16 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD6 */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D17 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXD7 */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* D18 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXDV */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D19 */
+		  SUNXI_FUNCTION(0x4, "pwm3")),		/* Positive */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXCLK */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D20 */
+		  SUNXI_FUNCTION(0x4, "pwm3")),		/* Negative */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* TXERR */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D21 */
+		  SUNXI_FUNCTION(0x4, "spi3")),		/* CS0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* RXERR */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D22 */
+		  SUNXI_FUNCTION(0x4, "spi3")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* COL */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* D23 */
+		  SUNXI_FUNCTION(0x4, "spi3")),		/* MOSI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* CRS */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* CLK */
+		  SUNXI_FUNCTION(0x4, "spi3")),		/* MISO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA25,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* CLKIN */
+		  SUNXI_FUNCTION(0x3, "lcd1"),		/* DE */
+		  SUNXI_FUNCTION(0x4, "spi3")),		/* CS1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA26,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* MDC */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* HSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA27,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "gmac"),		/* MDIO */
+		  SUNXI_FUNCTION(0x3, "lcd1")),		/* VSYNC */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* MCLK */
+		  SUNXI_FUNCTION(0x3, "uart3"),		/* CTS */
+		  SUNXI_FUNCTION(0x4, "csi")),		/* MCLK1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0")),		/* BCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0")),		/* LRCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0")),		/* DO0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO1 */
+		  SUNXI_FUNCTION(0x3, "uart3")),	/* RTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO2 */
+		  SUNXI_FUNCTION(0x3, "uart3"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "i2c3")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO3 */
+		  SUNXI_FUNCTION(0x3, "uart3"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "i2c3")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "i2s0")),		/* DI */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* WE */
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* MOSI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* ALE */
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* MISO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* CLE */
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* CE1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* CE0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* RE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* RB0 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* CMD */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* RB1 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* CLK */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ0 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ1 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ2 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ3 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ4 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D4 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ5 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D5 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ6 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D6 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ7 */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* D7 */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* D7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ8 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ9 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ10 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ11 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ12 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ13 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ14 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQ15 */
+		  SUNXI_FUNCTION(0x3, "nand1")),	/* DQ7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* DQS */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* RST */
+		  SUNXI_FUNCTION(0x4, "mmc3")),		/* RST */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC25,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* CE2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC26,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* CE3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC27,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* CS0 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VPC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D8 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D9 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D10 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D11 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D12 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D13 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D14 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D15 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D16 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VPC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D17 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D18 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D19 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* D20 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* D21 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* D22 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* D23 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* DE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* HSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0")),		/* VSYNC */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* PCLK */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* MCLK */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* ERR */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* HSYNC */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* SYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* VSYNC */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* DVLD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "uart5")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "uart5")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "uart5")),	/* RTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "uart5")),	/* CTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D8 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D9 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D10 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D11 */
+		  SUNXI_FUNCTION(0x3, "ts")),		/* D7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi")),		/* MIPI CSI MCLK */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* MS1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* DI1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CLK */
+		  SUNXI_FUNCTION(0x4, "uart0")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CMD */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* DO1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "uart0")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* CK1 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2")),	/* RTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2")),	/* CTS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c3"),		/* SCK */
+		  SUNXI_FUNCTION(0x3, "usb")),		/* DP3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c3"),		/* SDA */
+		  SUNXI_FUNCTION(0x3, "usb")),		/* DM3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS1 */
+		  SUNXI_FUNCTION(0x3, "i2s1")),		/* MCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS0 */
+		  SUNXI_FUNCTION(0x3, "i2s1")),		/* BCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "i2s1")),		/* LRCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* MOSI */
+		  SUNXI_FUNCTION(0x3, "i2s1")),		/* DIN */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* MISO */
+		  SUNXI_FUNCTION(0x3, "i2s1")),		/* DOUT */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart4")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart4")),	/* RX */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* WE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* ALE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* CLE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* CE1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* CE0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* RE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* RB0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* RB1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* DQS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* CS0 */
+		  SUNXI_FUNCTION(0x3, "jtag"),		/* MS0 */
+		  SUNXI_FUNCTION(0x4, "pwm1")),		/* Positive */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "jtag"),		/* CK0 */
+		  SUNXI_FUNCTION(0x4, "pwm1")),		/* Negative */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* MOSI */
+		  SUNXI_FUNCTION(0x3, "jtag"),		/* DO0 */
+		  SUNXI_FUNCTION(0x4, "pwm2")),		/* Positive */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* MISO */
+		  SUNXI_FUNCTION(0x3, "jtag"),		/* DI0 */
+		  SUNXI_FUNCTION(0x4, "pwm2")),		/* Negative */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "pwm0")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c0")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c0")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c1")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c1")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c2")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c2")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart0")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart0")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH28,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH29,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* CE2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH30,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand1")),	/* CE3 */
+};
+
+static const struct sunxi_desc_pin sun7i_a20_pins[] = {
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXD3 */
+		  SUNXI_FUNCTION(0x3, "spi1"),		/* CS0 */
+		  SUNXI_FUNCTION(0x4, "uart2"),		/* RTS */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GRXD3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXD2 */
+		  SUNXI_FUNCTION(0x3, "spi1"),		/* CLK */
+		  SUNXI_FUNCTION(0x4, "uart2"),		/* CTS */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GRXD2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXD1 */
+		  SUNXI_FUNCTION(0x3, "spi1"),		/* MOSI */
+		  SUNXI_FUNCTION(0x4, "uart2"),		/* TX */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GRXD1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXD0 */
+		  SUNXI_FUNCTION(0x3, "spi1"),		/* MISO */
+		  SUNXI_FUNCTION(0x4, "uart2"),		/* RX */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GRXD0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXD3 */
+		  SUNXI_FUNCTION(0x3, "spi1"),		/* CS1 */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GTXD3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXD2 */
+		  SUNXI_FUNCTION(0x3, "spi3"),		/* CS0 */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GTXD2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXD1 */
+		  SUNXI_FUNCTION(0x3, "spi3"),		/* CLK */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GTXD1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXD0 */
+		  SUNXI_FUNCTION(0x3, "spi3"),		/* MOSI */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GTXD0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXCK */
+		  SUNXI_FUNCTION(0x3, "spi3"),		/* MISO */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GRXCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXERR */
+		  SUNXI_FUNCTION(0x3, "spi3"),		/* CS1 */
+		  SUNXI_FUNCTION(0x5, "gmac"),		/* GNULL / ERXERR */
+		  SUNXI_FUNCTION(0x6, "i2s1")),		/* MCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ERXDV */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* TX */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GRXCTL / ERXDV */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* EMDC */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* RX */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* EMDC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* EMDIO */
+		  SUNXI_FUNCTION(0x3, "uart6"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* RTS */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* EMDIO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXEN */
+		  SUNXI_FUNCTION(0x3, "uart6"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* CTS */
+		  SUNXI_FUNCTION(0x5, "gmac")),		/* GTXCTL / ETXEN */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXCK */
+		  SUNXI_FUNCTION(0x3, "uart7"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* DTR */
+		  SUNXI_FUNCTION(0x5, "gmac"),		/* GNULL / ETXCK */
+		  SUNXI_FUNCTION(0x6, "i2s1")),		/* BCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ECRS */
+		  SUNXI_FUNCTION(0x3, "uart7"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* DSR */
+		  SUNXI_FUNCTION(0x5, "gmac"),		/* GTXCK / ECRS */
+		  SUNXI_FUNCTION(0x6, "i2s1")),		/* LRCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ECOL */
+		  SUNXI_FUNCTION(0x3, "can"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* DCD */
+		  SUNXI_FUNCTION(0x5, "gmac"),		/* GCLKIN / ECOL */
+		  SUNXI_FUNCTION(0x6, "i2s1")),		/* DO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "emac"),		/* ETXERR */
+		  SUNXI_FUNCTION(0x3, "can"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "uart1"),		/* RING */
+		  SUNXI_FUNCTION(0x5, "gmac"),		/* GNULL / ETXERR */
+		  SUNXI_FUNCTION(0x6, "i2s1")),		/* LRCK */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c0")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c0")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "pwm")),		/* PWM0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ir0"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "spdif")),	/* MCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ir0")),		/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* MCLK */
+		  SUNXI_FUNCTION(0x3, "ac97")),		/* MCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* BCLK */
+		  SUNXI_FUNCTION(0x3, "ac97")),		/* BCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* LRCK */
+		  SUNXI_FUNCTION(0x3, "ac97")),		/* SYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DO0 */
+		  SUNXI_FUNCTION(0x3, "ac97")),		/* DO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0")),		/* DO1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0")),		/* DO2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0")),		/* DO3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2s0"),		/* DI */
+		  SUNXI_FUNCTION(0x3, "ac97"),		/* DI */
+		  SUNXI_FUNCTION(0x4, "spdif")),	/* DI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* CS1 */
+		  SUNXI_FUNCTION(0x4, "spdif")),	/* DO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* CS0 */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* MS0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* CK0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* MOSI */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* DO0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi2"),		/* MISO */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* DI0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c1")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c1")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c2")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c2")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart0"),		/* TX */
+		  SUNXI_FUNCTION(0x3, "ir1")),		/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart0"),		/* RX */
+		  SUNXI_FUNCTION(0x3, "ir1")),		/* RX */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NWE */
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* MOSI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NALE */
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* MISO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCLE */
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NCE1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NCE0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NRE# */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NRB0 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NRB1 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ0 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ1 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ2 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ3 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NDQ4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NDQ5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NDQ6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NDQ7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NWP */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NCE2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NCE3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCE4 */
+		  SUNXI_FUNCTION(0x3, "spi2"),		/* CS0 */
+		  SUNXI_FUNCTION_IRQ(0x6, 12)),		/* EINT12 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCE5 */
+		  SUNXI_FUNCTION(0x3, "spi2"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ(0x6, 13)),		/* EINT13 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCE6 */
+		  SUNXI_FUNCTION(0x3, "spi2"),		/* MOSI */
+		  SUNXI_FUNCTION_IRQ(0x6, 14)),		/* EINT14 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCE7 */
+		  SUNXI_FUNCTION(0x3, "spi2"),		/* MISO */
+		  SUNXI_FUNCTION_IRQ(0x6, 15)),		/* EINT15 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "spi0")),		/* CS0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NDQS */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VN2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VPC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D8 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VP3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D9 */
+		  SUNXI_FUNCTION(0x3, "lvds0")),	/* VM3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D10 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D11 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D12 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D13 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D14 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D15 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D16 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VPC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D17 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D18 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VP3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D19 */
+		  SUNXI_FUNCTION(0x3, "lvds1")),	/* VN3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D20 */
+		  SUNXI_FUNCTION(0x3, "csi1")),		/* MCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D21 */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* VPPEN */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D22 */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* VPPPP */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D23 */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* DET */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* VCCEN */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* DE */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* RST */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* HSYNC */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* VSYNC */
+		  SUNXI_FUNCTION(0x3, "sim")),		/* SDA */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* PCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* ERR */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* CK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* SYNC */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* HSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* DVLD */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* VSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "csi0"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "sim")),		/* VPPEN */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts0"),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "csi0")),		/* D7 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* MSI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* DI1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CLK */
+		  SUNXI_FUNCTION(0x4, "uart0")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CMD */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* DO1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "uart0")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "jtag")),		/* CK1 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* PCK */
+		  SUNXI_FUNCTION(0x4, "mmc1")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* ERR */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* CK */
+		  SUNXI_FUNCTION(0x4, "mmc1")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* SYNC */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* HSYNC */
+		  SUNXI_FUNCTION(0x4, "mmc1")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* DVLD */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* VSYNC */
+		  SUNXI_FUNCTION(0x4, "mmc1")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "mmc1"),		/* D2 */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D8 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "mmc1"),		/* D3 */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D9 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* TX */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D10 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* RX */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D11 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D4 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* RTS */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D12 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D5 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* CTS */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D13 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D6 */
+		  SUNXI_FUNCTION(0x4, "uart4"),		/* TX */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D14 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ts1"),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "csi1"),		/* D7 */
+		  SUNXI_FUNCTION(0x4, "uart4"),		/* RX */
+		  SUNXI_FUNCTION(0x5, "csi0")),		/* D15 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* TX */
+		  SUNXI_FUNCTION_IRQ(0x6, 0),		/* EINT0 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* RX */
+		  SUNXI_FUNCTION_IRQ(0x6, 1),		/* EINT1 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ(0x6, 2),		/* EINT2 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "uart3"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ(0x6, 3),		/* EINT3 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D4 */
+		  SUNXI_FUNCTION(0x4, "uart4"),		/* TX */
+		  SUNXI_FUNCTION_IRQ(0x6, 4),		/* EINT4 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D5 */
+		  SUNXI_FUNCTION(0x4, "uart4"),		/* RX */
+		  SUNXI_FUNCTION_IRQ(0x6, 5),		/* EINT5 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D6 */
+		  SUNXI_FUNCTION(0x4, "uart5"),		/* TX */
+		  SUNXI_FUNCTION(0x5, "ms"),		/* BS */
+		  SUNXI_FUNCTION_IRQ(0x6, 6),		/* EINT6 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D7 */
+		  SUNXI_FUNCTION(0x4, "uart5"),		/* RX */
+		  SUNXI_FUNCTION(0x5, "ms"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ(0x6, 7),		/* EINT7 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D8 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ERXD3 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN0 */
+		  SUNXI_FUNCTION(0x5, "ms"),		/* D0 */
+		  SUNXI_FUNCTION_IRQ(0x6, 8),		/* EINT8 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D8 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D9 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ERXD2 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN1 */
+		  SUNXI_FUNCTION(0x5, "ms"),		/* D1 */
+		  SUNXI_FUNCTION_IRQ(0x6, 9),		/* EINT9 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D9 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D10 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ERXD1 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN2 */
+		  SUNXI_FUNCTION(0x5, "ms"),		/* D2 */
+		  SUNXI_FUNCTION_IRQ(0x6, 10),		/* EINT10 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D10 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D11 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ERXD0 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN3 */
+		  SUNXI_FUNCTION(0x5, "ms"),		/* D3 */
+		  SUNXI_FUNCTION_IRQ(0x6, 11),		/* EINT11 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D11 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D12 */
+		  SUNXI_FUNCTION(0x4, "ps2"),		/* SCK1 */
+		  SUNXI_FUNCTION_IRQ(0x6, 12),		/* EINT12 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D12 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D13 */
+		  SUNXI_FUNCTION(0x4, "ps2"),		/* SDA1 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* RST */
+		  SUNXI_FUNCTION_IRQ(0x6, 13),		/* EINT13 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D13 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D14 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXD3 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN4 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* VPPEN */
+		  SUNXI_FUNCTION_IRQ(0x6, 14),		/* EINT14 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D14 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D15 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXD3 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN5 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* VPPPP */
+		  SUNXI_FUNCTION_IRQ(0x6, 15),		/* EINT15 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D15 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D16 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXD2 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN6 */
+		  SUNXI_FUNCTION_IRQ(0x6, 16),		/* EINT16 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D16 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D17 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXD1 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* IN7 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* VCCEN */
+		  SUNXI_FUNCTION_IRQ(0x6, 17),		/* EINT17 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D17 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D18 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXD0 */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT0 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* SCK */
+		  SUNXI_FUNCTION_IRQ(0x6, 18),		/* EINT18 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D18 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D19 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ERXERR */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT1 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* SDA */
+		  SUNXI_FUNCTION_IRQ(0x6, 19),		/* EINT19 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D19 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D20 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ERXDV */
+		  SUNXI_FUNCTION(0x4, "can"),		/* TX */
+		  SUNXI_FUNCTION_IRQ(0x6, 20),		/* EINT20 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D20 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D21 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* EMDC */
+		  SUNXI_FUNCTION(0x4, "can"),		/* RX */
+		  SUNXI_FUNCTION_IRQ(0x6, 21),		/* EINT21 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D21 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D22 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* EMDIO */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT2 */
+		  SUNXI_FUNCTION(0x5, "mmc1"),		/* CMD */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D22 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* D23 */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXEN */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT3 */
+		  SUNXI_FUNCTION(0x5, "mmc1"),		/* CLK */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* D23 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXCK */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT4 */
+		  SUNXI_FUNCTION(0x5, "mmc1"),		/* D0 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* PCLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* DE */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ECRS */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT5 */
+		  SUNXI_FUNCTION(0x5, "mmc1"),		/* D1 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* FIELD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* HSYNC */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ECOL */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT6 */
+		  SUNXI_FUNCTION(0x5, "mmc1"),		/* D2 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* HSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd1"),		/* VSYNC */
+		  SUNXI_FUNCTION(0x3, "emac"),		/* ETXERR */
+		  SUNXI_FUNCTION(0x4, "keypad"),	/* OUT7 */
+		  SUNXI_FUNCTION(0x5, "mmc1"),		/* D3 */
+		  SUNXI_FUNCTION(0x7, "csi1")),		/* VSYNC */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "i2c3")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI1,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "i2c3")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI2,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "i2c4")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "pwm"),		/* PWM1 */
+		  SUNXI_FUNCTION(0x3, "i2c4")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc3")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc3")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc3")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc3")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc3")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc3")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi0"),		/* CS0 */
+		  SUNXI_FUNCTION(0x3, "uart5"),		/* TX */
+		  SUNXI_FUNCTION_IRQ(0x5, 22)),		/* EINT22 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi0"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "uart5"),		/* RX */
+		  SUNXI_FUNCTION_IRQ(0x5, 23)),		/* EINT23 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi0"),		/* MOSI */
+		  SUNXI_FUNCTION(0x3, "uart6"),		/* TX */
+		  SUNXI_FUNCTION_IRQ(0x5, 24)),		/* EINT24 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi0"),		/* MISO */
+		  SUNXI_FUNCTION(0x3, "uart6"),		/* RX */
+		  SUNXI_FUNCTION_IRQ(0x5, 25)),		/* EINT25 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi0"),		/* CS1 */
+		  SUNXI_FUNCTION(0x3, "ps2"),		/* SCK1 */
+		  SUNXI_FUNCTION(0x4, "timer4"),	/* TCLKIN0 */
+		  SUNXI_FUNCTION_IRQ(0x5, 26)),		/* EINT26 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS1 */
+		  SUNXI_FUNCTION(0x3, "ps2"),		/* SDA1 */
+		  SUNXI_FUNCTION(0x4, "timer5"),	/* TCLKIN1 */
+		  SUNXI_FUNCTION_IRQ(0x5, 27)),		/* EINT27 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* CS0 */
+		  SUNXI_FUNCTION(0x3, "uart2"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ(0x5, 28)),		/* EINT28 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "uart2"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ(0x5, 29)),		/* EINT29 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* MOSI */
+		  SUNXI_FUNCTION(0x3, "uart2"),		/* TX */
+		  SUNXI_FUNCTION_IRQ(0x5, 30)),		/* EINT30 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spi1"),		/* MISO */
+		  SUNXI_FUNCTION(0x3, "uart2"),		/* RX */
+		  SUNXI_FUNCTION_IRQ(0x5, 31)),		/* EINT31 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ps2"),		/* SCK0 */
+		  SUNXI_FUNCTION(0x3, "uart7"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "hdmi")),		/* HSCL */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "ps2"),		/* SDA0 */
+		  SUNXI_FUNCTION(0x3, "uart7"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "hdmi")),		/* HSDA */
+};
+
 static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
 	.pins = sun4i_a10_pins,
 	.npins = ARRAY_SIZE(sun4i_a10_pins),
@@ -2020,4 +3848,14 @@
 	.npins = ARRAY_SIZE(sun5i_a13_pins),
 };
 
+static const struct sunxi_pinctrl_desc sun6i_a31_pinctrl_data = {
+	.pins = sun6i_a31_pins,
+	.npins = ARRAY_SIZE(sun6i_a31_pins),
+};
+
+static const struct sunxi_pinctrl_desc sun7i_a20_pinctrl_data = {
+	.pins = sun7i_a20_pins,
+	.npins = ARRAY_SIZE(sun7i_a20_pins),
+};
+
 #endif /* __PINCTRL_SUNXI_PINS_H */
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index c47fd1e..119d2dd 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -175,7 +175,7 @@
 	}
 
 	*map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
-	if (!map)
+	if (!*map)
 		return -ENOMEM;
 
 	of_property_for_each_string(node, "allwinner,pins", prop, group) {
@@ -274,50 +274,61 @@
 
 static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
 				 unsigned group,
-				 unsigned long config)
+				 unsigned long *configs,
+				 unsigned num_configs)
 {
 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
 	struct sunxi_pinctrl_group *g = &pctl->groups[group];
+	unsigned long flags;
 	u32 val, mask;
 	u16 strength;
 	u8 dlevel;
+	int i;
 
-	switch (pinconf_to_config_param(config)) {
-	case PIN_CONFIG_DRIVE_STRENGTH:
-		strength = pinconf_to_config_argument(config);
-		if (strength > 40)
-			return -EINVAL;
-		/*
-		 * We convert from mA to what the register expects:
-		 *   0: 10mA
-		 *   1: 20mA
-		 *   2: 30mA
-		 *   3: 40mA
-		 */
-		dlevel = strength / 10 - 1;
-		val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
-	        mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
-		writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
-			pctl->membase + sunxi_dlevel_reg(g->pin));
-		break;
-	case PIN_CONFIG_BIAS_PULL_UP:
-		val = readl(pctl->membase + sunxi_pull_reg(g->pin));
-		mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
-		writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
-			pctl->membase + sunxi_pull_reg(g->pin));
-		break;
-	case PIN_CONFIG_BIAS_PULL_DOWN:
-		val = readl(pctl->membase + sunxi_pull_reg(g->pin));
-		mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
-		writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
-			pctl->membase + sunxi_pull_reg(g->pin));
-		break;
-	default:
-		break;
-	}
+	spin_lock_irqsave(&pctl->lock, flags);
 
-	/* cache the config value */
-	g->config = config;
+	for (i = 0; i < num_configs; i++) {
+		switch (pinconf_to_config_param(configs[i])) {
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			strength = pinconf_to_config_argument(configs[i]);
+			if (strength > 40) {
+				spin_unlock_irqrestore(&pctl->lock, flags);
+				return -EINVAL;
+			}
+			/*
+			 * We convert from mA to what the register expects:
+			 *   0: 10mA
+			 *   1: 20mA
+			 *   2: 30mA
+			 *   3: 40mA
+			 */
+			dlevel = strength / 10 - 1;
+			val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
+			mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
+			writel((val & ~mask)
+				| dlevel << sunxi_dlevel_offset(g->pin),
+				pctl->membase + sunxi_dlevel_reg(g->pin));
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			val = readl(pctl->membase + sunxi_pull_reg(g->pin));
+			mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
+			writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
+				pctl->membase + sunxi_pull_reg(g->pin));
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			val = readl(pctl->membase + sunxi_pull_reg(g->pin));
+			mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
+			writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
+				pctl->membase + sunxi_pull_reg(g->pin));
+			break;
+		default:
+			break;
+		}
+		/* cache the config value */
+		g->config = configs[i];
+	} /* for each config */
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 
 	return 0;
 }
@@ -360,11 +371,17 @@
 				 u8 config)
 {
 	struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+	unsigned long flags;
+	u32 val, mask;
 
-	u32 val = readl(pctl->membase + sunxi_mux_reg(pin));
-	u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	val = readl(pctl->membase + sunxi_mux_reg(pin));
+	mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
 	writel((val & ~mask) | config << sunxi_mux_offset(pin),
 		pctl->membase + sunxi_mux_reg(pin));
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
@@ -464,8 +481,21 @@
 	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
 	u32 reg = sunxi_data_reg(offset);
 	u8 index = sunxi_data_offset(offset);
+	unsigned long flags;
+	u32 regval;
 
-	writel((value & DATA_PINS_MASK) << index, pctl->membase + reg);
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	regval = readl(pctl->membase + reg);
+
+	if (value)
+		regval |= BIT(index);
+	else
+		regval &= ~(BIT(index));
+
+	writel(regval, pctl->membase + reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
@@ -491,7 +521,7 @@
 	struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
 	struct sunxi_desc_function *desc;
 
-	if (offset > chip->ngpio)
+	if (offset >= chip->ngpio)
 		return -ENXIO;
 
 	desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq");
@@ -526,6 +556,8 @@
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
 	u32 reg = sunxi_irq_cfg_reg(d->hwirq);
 	u8 index = sunxi_irq_cfg_offset(d->hwirq);
+	unsigned long flags;
+	u32 regval;
 	u8 mode;
 
 	switch (type) {
@@ -548,7 +580,13 @@
 		return -EINVAL;
 	}
 
-	writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg);
+	spin_lock_irqsave(&pctl->lock, flags);
+
+	regval = readl(pctl->membase + reg);
+	regval &= ~IRQ_CFG_IRQ_MASK;
+	writel(regval | (mode << index), pctl->membase + reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 
 	return 0;
 }
@@ -560,14 +598,19 @@
 	u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
 	u32 status_reg = sunxi_irq_status_reg(d->hwirq);
 	u8 status_idx = sunxi_irq_status_offset(d->hwirq);
+	unsigned long flags;
 	u32 val;
 
+	spin_lock_irqsave(&pctl->lock, flags);
+
 	/* Mask the IRQ */
 	val = readl(pctl->membase + ctrl_reg);
 	writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
 
 	/* Clear the IRQ */
 	writel(1 << status_idx, pctl->membase + status_reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 static void sunxi_pinctrl_irq_mask(struct irq_data *d)
@@ -575,11 +618,16 @@
 	struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
 	u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
+	unsigned long flags;
 	u32 val;
 
+	spin_lock_irqsave(&pctl->lock, flags);
+
 	/* Mask the IRQ */
 	val = readl(pctl->membase + reg);
 	writel(val & ~(1 << idx), pctl->membase + reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
@@ -588,6 +636,7 @@
 	struct sunxi_desc_function *func;
 	u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
 	u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
+	unsigned long flags;
 	u32 val;
 
 	func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
@@ -597,9 +646,13 @@
 	/* Change muxing to INT mode */
 	sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
 
+	spin_lock_irqsave(&pctl->lock, flags);
+
 	/* Unmask the IRQ */
 	val = readl(pctl->membase + reg);
 	writel(val | (1 << idx), pctl->membase + reg);
+
+	spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 static struct irq_chip sunxi_pinctrl_irq_chip = {
@@ -631,6 +684,8 @@
 	{ .compatible = "allwinner,sun4i-a10-pinctrl", .data = (void *)&sun4i_a10_pinctrl_data },
 	{ .compatible = "allwinner,sun5i-a10s-pinctrl", .data = (void *)&sun5i_a10s_pinctrl_data },
 	{ .compatible = "allwinner,sun5i-a13-pinctrl", .data = (void *)&sun5i_a13_pinctrl_data },
+	{ .compatible = "allwinner,sun6i-a31-pinctrl", .data = (void *)&sun6i_a31_pinctrl_data },
+	{ .compatible = "allwinner,sun7i-a20-pinctrl", .data = (void *)&sun7i_a20_pinctrl_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, sunxi_pinctrl_match);
@@ -752,6 +807,8 @@
 		return -ENOMEM;
 	platform_set_drvdata(pdev, pctl);
 
+	spin_lock_init(&pctl->lock);
+
 	pctl->membase = of_iomap(node, 0);
 	if (!pctl->membase)
 		return -ENOMEM;
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
index d68047d..01c494f 100644
--- a/drivers/pinctrl/pinctrl-sunxi.h
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -14,6 +14,7 @@
 #define __PINCTRL_SUNXI_H
 
 #include <linux/kernel.h>
+#include <linux/spinlock.h>
 
 #define PA_BASE	0
 #define PB_BASE	32
@@ -407,6 +408,7 @@
 	unsigned			ngroups;
 	int				irq;
 	int				irq_array[SUNXI_IRQ_NUMBER];
+	spinlock_t			lock;
 	struct pinctrl_dev		*pctl_dev;
 };
 
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 2fa9bc6..a2e93a2 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -32,6 +32,7 @@
 
 #include "core.h"
 #include "pinctrl-tegra.h"
+#include "pinctrl-utils.h"
 
 struct tegra_pmx {
 	struct device *dev;
@@ -90,107 +91,6 @@
 }
 #endif
 
-static int reserve_map(struct device *dev, struct pinctrl_map **map,
-		       unsigned *reserved_maps, unsigned *num_maps,
-		       unsigned reserve)
-{
-	unsigned old_num = *reserved_maps;
-	unsigned new_num = *num_maps + reserve;
-	struct pinctrl_map *new_map;
-
-	if (old_num >= new_num)
-		return 0;
-
-	new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
-	if (!new_map) {
-		dev_err(dev, "krealloc(map) failed\n");
-		return -ENOMEM;
-	}
-
-	memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
-
-	*map = new_map;
-	*reserved_maps = new_num;
-
-	return 0;
-}
-
-static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
-		       unsigned *num_maps, const char *group,
-		       const char *function)
-{
-	if (WARN_ON(*num_maps == *reserved_maps))
-		return -ENOSPC;
-
-	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
-	(*map)[*num_maps].data.mux.group = group;
-	(*map)[*num_maps].data.mux.function = function;
-	(*num_maps)++;
-
-	return 0;
-}
-
-static int add_map_configs(struct device *dev, struct pinctrl_map **map,
-			   unsigned *reserved_maps, unsigned *num_maps,
-			   const char *group, unsigned long *configs,
-			   unsigned num_configs)
-{
-	unsigned long *dup_configs;
-
-	if (WARN_ON(*num_maps == *reserved_maps))
-		return -ENOSPC;
-
-	dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
-			      GFP_KERNEL);
-	if (!dup_configs) {
-		dev_err(dev, "kmemdup(configs) failed\n");
-		return -ENOMEM;
-	}
-
-	(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
-	(*map)[*num_maps].data.configs.group_or_pin = group;
-	(*map)[*num_maps].data.configs.configs = dup_configs;
-	(*map)[*num_maps].data.configs.num_configs = num_configs;
-	(*num_maps)++;
-
-	return 0;
-}
-
-static int add_config(struct device *dev, unsigned long **configs,
-		      unsigned *num_configs, unsigned long config)
-{
-	unsigned old_num = *num_configs;
-	unsigned new_num = old_num + 1;
-	unsigned long *new_configs;
-
-	new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
-			       GFP_KERNEL);
-	if (!new_configs) {
-		dev_err(dev, "krealloc(configs) failed\n");
-		return -ENOMEM;
-	}
-
-	new_configs[old_num] = config;
-
-	*configs = new_configs;
-	*num_configs = new_num;
-
-	return 0;
-}
-
-static void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
-				      struct pinctrl_map *map,
-				      unsigned num_maps)
-{
-	int i;
-
-	for (i = 0; i < num_maps; i++)
-		if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
-			kfree(map[i].data.configs.configs);
-
-	kfree(map);
-}
-
 static const struct cfg_param {
 	const char *property;
 	enum tegra_pinconf_param param;
@@ -212,12 +112,13 @@
 	{"nvidia,drive-type",		TEGRA_PINCONF_PARAM_DRIVE_TYPE},
 };
 
-static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+static int tegra_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
 					   struct device_node *np,
 					   struct pinctrl_map **map,
 					   unsigned *reserved_maps,
 					   unsigned *num_maps)
 {
+	struct device *dev = pctldev->dev;
 	int ret, i;
 	const char *function;
 	u32 val;
@@ -241,7 +142,8 @@
 		ret = of_property_read_u32(np, cfg_params[i].property, &val);
 		if (!ret) {
 			config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
-			ret = add_config(dev, &configs, &num_configs, config);
+			ret = pinctrl_utils_add_config(pctldev, &configs,
+					&num_configs, config);
 			if (ret < 0)
 				goto exit;
 		/* EINVAL=missing, which is fine since it's optional */
@@ -263,22 +165,25 @@
 	}
 	reserve *= ret;
 
-	ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
+	ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps,
+					num_maps, reserve);
 	if (ret < 0)
 		goto exit;
 
 	of_property_for_each_string(np, "nvidia,pins", prop, group) {
 		if (function) {
-			ret = add_map_mux(map, reserved_maps, num_maps,
-					  group, function);
+			ret = pinctrl_utils_add_map_mux(pctldev, map,
+					reserved_maps, num_maps, group,
+					function);
 			if (ret < 0)
 				goto exit;
 		}
 
 		if (num_configs) {
-			ret = add_map_configs(dev, map, reserved_maps,
-					      num_maps, group, configs,
-					      num_configs);
+			ret = pinctrl_utils_add_map_configs(pctldev, map,
+					reserved_maps, num_maps, group,
+					configs, num_configs,
+					PIN_MAP_TYPE_CONFIGS_GROUP);
 			if (ret < 0)
 				goto exit;
 		}
@@ -305,10 +210,11 @@
 	*num_maps = 0;
 
 	for_each_child_of_node(np_config, np) {
-		ret = tegra_pinctrl_dt_subnode_to_map(pctldev->dev, np, map,
+		ret = tegra_pinctrl_dt_subnode_to_map(pctldev, np, map,
 						      &reserved_maps, num_maps);
 		if (ret < 0) {
-			tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
+			pinctrl_utils_dt_free_map(pctldev, *map,
+				*num_maps);
 			return ret;
 		}
 	}
@@ -324,7 +230,7 @@
 	.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
 #endif
 	.dt_node_to_map = tegra_pinctrl_dt_node_to_map,
-	.dt_free_map = tegra_pinctrl_dt_free_map,
+	.dt_free_map = pinctrl_utils_dt_free_map,
 };
 
 static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
@@ -530,7 +436,8 @@
 }
 
 static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
-			     unsigned pin, unsigned long config)
+			     unsigned pin, unsigned long *configs,
+			     unsigned num_configs)
 {
 	dev_err(pctldev->dev, "pin_config_set op not supported\n");
 	return -ENOTSUPP;
@@ -565,51 +472,57 @@
 }
 
 static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
-				   unsigned group, unsigned long config)
+				   unsigned group, unsigned long *configs,
+				   unsigned num_configs)
 {
 	struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-	enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
-	u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
+	enum tegra_pinconf_param param;
+	u16 arg;
 	const struct tegra_pingroup *g;
-	int ret;
+	int ret, i;
 	s8 bank, bit, width;
 	s16 reg;
 	u32 val, mask;
 
 	g = &pmx->soc->groups[group];
 
-	ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
-				&width);
-	if (ret < 0)
-		return ret;
+	for (i = 0; i < num_configs; i++) {
+		param = TEGRA_PINCONF_UNPACK_PARAM(configs[i]);
+		arg = TEGRA_PINCONF_UNPACK_ARG(configs[i]);
 
-	val = pmx_readl(pmx, bank, reg);
+		ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+					&width);
+		if (ret < 0)
+			return ret;
 
-	/* LOCK can't be cleared */
-	if (param == TEGRA_PINCONF_PARAM_LOCK) {
-		if ((val & BIT(bit)) && !arg) {
-			dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
+		val = pmx_readl(pmx, bank, reg);
+
+		/* LOCK can't be cleared */
+		if (param == TEGRA_PINCONF_PARAM_LOCK) {
+			if ((val & BIT(bit)) && !arg) {
+				dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
+				return -EINVAL;
+			}
+		}
+
+		/* Special-case Boolean values; allow any non-zero as true */
+		if (width == 1)
+			arg = !!arg;
+
+		/* Range-check user-supplied value */
+		mask = (1 << width) - 1;
+		if (arg & ~mask) {
+			dev_err(pctldev->dev,
+				"config %lx: %x too big for %d bit register\n",
+				configs[i], arg, width);
 			return -EINVAL;
 		}
-	}
 
-	/* Special-case Boolean values; allow any non-zero as true */
-	if (width == 1)
-		arg = !!arg;
-
-	/* Range-check user-supplied value */
-	mask = (1 << width) - 1;
-	if (arg & ~mask) {
-		dev_err(pctldev->dev,
-			"config %lx: %x too big for %d bit register\n",
-			config, arg, width);
-		return -EINVAL;
-	}
-
-	/* Update register */
-	val &= ~(mask << bit);
-	val |= arg << bit;
-	pmx_writel(pmx, val, bank, reg);
+		/* Update register */
+		val &= ~(mask << bit);
+		val |= arg << bit;
+		pmx_writel(pmx, val, bank, reg);
+	} /* for each config */
 
 	return 0;
 }
@@ -737,25 +650,9 @@
 
 	for (i = 0; i < pmx->nbanks; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res) {
-			dev_err(&pdev->dev, "Missing MEM resource\n");
-			return -ENODEV;
-		}
-
-		if (!devm_request_mem_region(&pdev->dev, res->start,
-					    resource_size(res),
-					    dev_name(&pdev->dev))) {
-			dev_err(&pdev->dev,
-				"Couldn't request MEM resource %d\n", i);
-			return -ENODEV;
-		}
-
-		pmx->regs[i] = devm_ioremap(&pdev->dev, res->start,
-					    resource_size(res));
-		if (!pmx->regs[i]) {
-			dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
-			return -ENODEV;
-		}
+		pmx->regs[i] = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(pmx->regs[i]))
+			return PTR_ERR(pmx->regs[i]);
 	}
 
 	pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);
diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c
index d4f12cc..5bf01c2 100644
--- a/drivers/pinctrl/pinctrl-tz1090-pdc.c
+++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c
@@ -737,39 +737,46 @@
 }
 
 static int tz1090_pdc_pinconf_set(struct pinctrl_dev *pctldev,
-				  unsigned int pin, unsigned long config)
+				  unsigned int pin, unsigned long *configs,
+				  unsigned num_configs)
 {
 	struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-	enum pin_config_param param = pinconf_to_config_param(config);
-	unsigned int arg = pinconf_to_config_argument(config);
+	enum pin_config_param param;
+	unsigned int arg;
 	int ret;
 	u32 reg, width, mask, shift, val, tmp;
 	unsigned long flags;
+	int i;
 
-	dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
-		__func__, tz1090_pdc_pins[pin].name, config);
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
 
-	/* Get register information */
-	ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true,
-				     &reg, &width, &mask, &shift, &val);
-	if (ret < 0)
-		return ret;
+		dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
+			__func__, tz1090_pdc_pins[pin].name, configs[i]);
 
-	/* Unpack argument and range check it */
-	if (arg > 1) {
-		dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
-			__func__, arg);
-		return -EINVAL;
-	}
+		/* Get register information */
+		ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true,
+					     &reg, &width, &mask, &shift, &val);
+		if (ret < 0)
+			return ret;
 
-	/* Write register field */
-	__global_lock2(flags);
-	tmp = pmx_read(pmx, reg);
-	tmp &= ~mask;
-	if (arg)
-		tmp |= val << shift;
-	pmx_write(pmx, tmp, reg);
-	__global_unlock2(flags);
+		/* Unpack argument and range check it */
+		if (arg > 1) {
+			dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
+				__func__, arg);
+			return -EINVAL;
+		}
+
+		/* Write register field */
+		__global_lock2(flags);
+		tmp = pmx_read(pmx, reg);
+		tmp &= ~mask;
+		if (arg)
+			tmp |= val << shift;
+		pmx_write(pmx, tmp, reg);
+		__global_unlock2(flags);
+	} /* for each config */
 
 	return 0;
 }
@@ -860,54 +867,68 @@
 
 static int tz1090_pdc_pinconf_group_set(struct pinctrl_dev *pctldev,
 					unsigned int group,
-					unsigned long config)
+					unsigned long *configs,
+					unsigned num_configs)
 {
 	struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
 	const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group];
-	enum pin_config_param param = pinconf_to_config_param(config);
+	enum pin_config_param param;
 	const unsigned int *pit;
 	unsigned int i;
 	int ret, arg;
 	u32 reg, width, mask, shift, val;
 	unsigned long flags;
 	const int *map;
+	int j;
 
-	dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
-		__func__, g->name, config);
+	for (j = 0; j < num_configs; j++) {
+		param = pinconf_to_config_param(configs[j]);
 
-	/* Get register information */
-	ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true,
-					   &reg, &width, &mask, &shift, &map);
-	if (ret < 0) {
-		/*
-		 * Maybe we're trying to set a per-pin configuration of a group,
-		 * so do the pins one by one. This is mainly as a convenience.
-		 */
-		for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
-			ret = tz1090_pdc_pinconf_set(pctldev, *pit, config);
-			if (ret)
-				return ret;
-		}
-		return 0;
-	}
+		dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
+			__func__, g->name, configs[j]);
 
-	/* Unpack argument and map it to register value */
-	arg = pinconf_to_config_argument(config);
-	for (i = 0; i < BIT(width); ++i) {
-		if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
-			/* Write register field */
-			__global_lock2(flags);
-			val = pmx_read(pmx, reg);
-			val &= ~mask;
-			val |= i << shift;
-			pmx_write(pmx, val, reg);
-			__global_unlock2(flags);
+		/* Get register information */
+		ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true,
+						   &reg, &width, &mask, &shift,
+						   &map);
+		if (ret < 0) {
+			/*
+			 * Maybe we're trying to set a per-pin configuration
+			 * of a group, so do the pins one by one. This is
+			 * mainly as a convenience.
+			 */
+			for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
+				ret = tz1090_pdc_pinconf_set(pctldev, *pit,
+					configs, num_configs);
+				if (ret)
+					return ret;
+			}
 			return 0;
 		}
-	}
 
-	dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
-		__func__, arg);
+		/* Unpack argument and map it to register value */
+		arg = pinconf_to_config_argument(configs[j]);
+		for (i = 0; i < BIT(width); ++i) {
+			if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
+				/* Write register field */
+				__global_lock2(flags);
+				val = pmx_read(pmx, reg);
+				val &= ~mask;
+				val |= i << shift;
+				pmx_write(pmx, val, reg);
+				__global_unlock2(flags);
+				goto next_config;
+			}
+		}
+
+		dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
+			__func__, arg);
+		return 0;
+
+next_config:
+		;
+	} /* for each config */
+
 	return 0;
 }
 
@@ -949,25 +970,9 @@
 	tz1090_pdc_pinctrl_desc.npins = ARRAY_SIZE(tz1090_pdc_pins);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Missing MEM resource\n");
-		return -ENODEV;
-	}
-
-	if (!devm_request_mem_region(&pdev->dev, res->start,
-				     resource_size(res),
-				     dev_name(&pdev->dev))) {
-		dev_err(&pdev->dev,
-			"Couldn't request MEM resource\n");
-		return -ENODEV;
-	}
-
-	pmx->regs = devm_ioremap(&pdev->dev, res->start,
-				 resource_size(res));
-	if (!pmx->regs) {
-		dev_err(&pdev->dev, "Couldn't ioremap regs\n");
-		return -ENODEV;
-	}
+	pmx->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmx->regs))
+		return PTR_ERR(pmx->regs);
 
 	pmx->pctl = pinctrl_register(&tz1090_pdc_pinctrl_desc, &pdev->dev, pmx);
 	if (!pmx->pctl) {
diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c
index 4edae08a..bc9cd7a 100644
--- a/drivers/pinctrl/pinctrl-tz1090.c
+++ b/drivers/pinctrl/pinctrl-tz1090.c
@@ -1762,39 +1762,46 @@
 }
 
 static int tz1090_pinconf_set(struct pinctrl_dev *pctldev,
-			      unsigned int pin, unsigned long config)
+			      unsigned int pin, unsigned long *configs,
+			      unsigned num_configs)
 {
 	struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-	enum pin_config_param param = pinconf_to_config_param(config);
-	unsigned int arg = pinconf_to_config_argument(config);
+	enum pin_config_param param;
+	unsigned int arg;
 	int ret;
 	u32 reg, width, mask, shift, val, tmp;
 	unsigned long flags;
+	int i;
 
-	dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
-		__func__, tz1090_pins[pin].name, config);
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
 
-	/* Get register information */
-	ret = tz1090_pinconf_reg(pctldev, pin, param, true,
-				 &reg, &width, &mask, &shift, &val);
-	if (ret < 0)
-		return ret;
+		dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
+			__func__, tz1090_pins[pin].name, configs[i]);
 
-	/* Unpack argument and range check it */
-	if (arg > 1) {
-		dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
-			__func__, arg);
-		return -EINVAL;
-	}
+		/* Get register information */
+		ret = tz1090_pinconf_reg(pctldev, pin, param, true,
+					 &reg, &width, &mask, &shift, &val);
+		if (ret < 0)
+			return ret;
 
-	/* Write register field */
-	__global_lock2(flags);
-	tmp = pmx_read(pmx, reg);
-	tmp &= ~mask;
-	if (arg)
-		tmp |= val << shift;
-	pmx_write(pmx, tmp, reg);
-	__global_unlock2(flags);
+		/* Unpack argument and range check it */
+		if (arg > 1) {
+			dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
+				__func__, arg);
+			return -EINVAL;
+		}
+
+		/* Write register field */
+		__global_lock2(flags);
+		tmp = pmx_read(pmx, reg);
+		tmp &= ~mask;
+		if (arg)
+			tmp |= val << shift;
+		pmx_write(pmx, tmp, reg);
+		__global_unlock2(flags);
+	} /* for each config */
 
 	return 0;
 }
@@ -1894,68 +1901,81 @@
 }
 
 static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev,
-				    unsigned int group, unsigned long config)
+				    unsigned int group, unsigned long *configs,
+				    unsigned num_configs)
 {
 	struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
 	const struct tz1090_pingroup *g;
-	enum pin_config_param param = pinconf_to_config_param(config);
+	enum pin_config_param param;
 	unsigned int arg, pin, i;
 	const unsigned int *pit;
 	int ret;
 	u32 reg, width, mask, shift, val;
 	unsigned long flags;
 	const int *map;
+	int j;
 
 	if (group >= ARRAY_SIZE(tz1090_groups)) {
 		pin = group - ARRAY_SIZE(tz1090_groups);
-		return tz1090_pinconf_set(pctldev, pin, config);
+		return tz1090_pinconf_set(pctldev, pin, configs, num_configs);
 	}
 
 	g = &tz1090_groups[group];
 	if (g->npins == 1) {
 		pin = g->pins[0];
-		ret = tz1090_pinconf_set(pctldev, pin, config);
+		ret = tz1090_pinconf_set(pctldev, pin, configs, num_configs);
 		if (ret != -ENOTSUPP)
 			return ret;
 	}
 
-	dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
-		__func__, g->name, config);
+	for (j = 0; j < num_configs; j++) {
+		param = pinconf_to_config_param(configs[j]);
 
-	/* Get register information */
-	ret = tz1090_pinconf_group_reg(pctldev, g, param, true,
-				       &reg, &width, &mask, &shift, &map);
-	if (ret < 0) {
-		/*
-		 * Maybe we're trying to set a per-pin configuration of a group,
-		 * so do the pins one by one. This is mainly as a convenience.
-		 */
-		for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
-			ret = tz1090_pinconf_set(pctldev, *pit, config);
-			if (ret)
-				return ret;
-		}
-		return 0;
-	}
+		dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
+			__func__, g->name, configs[j]);
 
-	/* Unpack argument and map it to register value */
-	arg = pinconf_to_config_argument(config);
-	for (i = 0; i < BIT(width); ++i) {
-		if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
-			/* Write register field */
-			__global_lock2(flags);
-			val = pmx_read(pmx, reg);
-			val &= ~mask;
-			val |= i << shift;
-			pmx_write(pmx, val, reg);
-			__global_unlock2(flags);
+		/* Get register information */
+		ret = tz1090_pinconf_group_reg(pctldev, g, param, true, &reg,
+						&width, &mask, &shift, &map);
+		if (ret < 0) {
+			/*
+			 * Maybe we're trying to set a per-pin configuration
+			 * of a group, so do the pins one by one. This is
+			 * mainly as a convenience.
+			 */
+			for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
+				ret = tz1090_pinconf_set(pctldev, *pit, configs,
+					num_configs);
+				if (ret)
+					return ret;
+			}
 			return 0;
 		}
-	}
 
-	dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
-		__func__, arg);
-	return -EINVAL;
+		/* Unpack argument and map it to register value */
+		arg = pinconf_to_config_argument(configs[j]);
+		for (i = 0; i < BIT(width); ++i) {
+			if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
+				/* Write register field */
+				__global_lock2(flags);
+				val = pmx_read(pmx, reg);
+				val &= ~mask;
+				val |= i << shift;
+				pmx_write(pmx, val, reg);
+				__global_unlock2(flags);
+				goto next_config;
+			}
+		}
+
+		dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
+			__func__, arg);
+		return -EINVAL;
+
+next_config:
+		;
+	} /* for each config */
+
+	return 0;
 }
 
 static struct pinconf_ops tz1090_pinconf_ops = {
@@ -1996,25 +2016,9 @@
 	tz1090_pinctrl_desc.npins = ARRAY_SIZE(tz1090_pins);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Missing MEM resource\n");
-		return -ENODEV;
-	}
-
-	if (!devm_request_mem_region(&pdev->dev, res->start,
-				     resource_size(res),
-				     dev_name(&pdev->dev))) {
-		dev_err(&pdev->dev,
-			"Couldn't request MEM resource\n");
-		return -ENODEV;
-	}
-
-	pmx->regs = devm_ioremap(&pdev->dev, res->start,
-				 resource_size(res));
-	if (!pmx->regs) {
-		dev_err(&pdev->dev, "Couldn't ioremap regs\n");
-		return -ENODEV;
-	}
+	pmx->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmx->regs))
+		return PTR_ERR(pmx->regs);
 
 	pmx->pctl = pinctrl_register(&tz1090_pinctrl_desc, &pdev->dev, pmx);
 	if (!pmx->pctl) {
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index 46a152d..209a01b 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -1027,21 +1027,23 @@
 }
 
 static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
-			       unsigned long config)
+			       unsigned long *configs, unsigned num_configs)
 {
 	struct pinctrl_gpio_range *range =
 		pinctrl_find_gpio_range_from_pin(pctldev, pin);
-	int ret;
+	int ret, i;
 
 	if (!range)
 		return -EINVAL;
 
-	/* Note: none of these configurations take any argument */
-	ret = u300_gpio_config_set(range->gc,
-				   (pin - range->pin_base + range->base),
-				   pinconf_to_config_param(config));
-	if (ret)
-		return ret;
+	for (i = 0; i < num_configs; i++) {
+		/* Note: none of these configurations take any argument */
+		ret = u300_gpio_config_set(range->gc,
+			(pin - range->pin_base + range->base),
+			pinconf_to_config_param(configs[i]));
+		if (ret)
+			return ret;
+	} /* for each config */
 
 	return 0;
 }
@@ -1075,9 +1077,6 @@
 	upmx->dev = &pdev->dev;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENOENT;
-
 	upmx->virtbase = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(upmx->virtbase))
 		return PTR_ERR(upmx->virtbase);
diff --git a/drivers/pinctrl/pinctrl-utils.c b/drivers/pinctrl/pinctrl-utils.c
new file mode 100644
index 0000000..d77693f
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-utils.c
@@ -0,0 +1,142 @@
+/*
+ * Utils functions to implement the pincontrol driver.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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/device.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include "core.h"
+#include "pinctrl-utils.h"
+
+int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, unsigned reserve)
+{
+	unsigned old_num = *reserved_maps;
+	unsigned new_num = *num_maps + reserve;
+	struct pinctrl_map *new_map;
+
+	if (old_num >= new_num)
+		return 0;
+
+	new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
+	if (!new_map) {
+		dev_err(pctldev->dev, "krealloc(map) failed\n");
+		return -ENOMEM;
+	}
+
+	memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
+
+	*map = new_map;
+	*reserved_maps = new_num;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map);
+
+int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
+		struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, const char *group,
+		const char *function)
+{
+	if (WARN_ON(*num_maps == *reserved_maps))
+		return -ENOSPC;
+
+	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
+	(*map)[*num_maps].data.mux.group = group;
+	(*map)[*num_maps].data.mux.function = function;
+	(*num_maps)++;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux);
+
+int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
+		struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, const char *group,
+		unsigned long *configs, unsigned num_configs,
+		enum pinctrl_map_type type)
+{
+	unsigned long *dup_configs;
+
+	if (WARN_ON(*num_maps == *reserved_maps))
+		return -ENOSPC;
+
+	dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
+			      GFP_KERNEL);
+	if (!dup_configs) {
+		dev_err(pctldev->dev, "kmemdup(configs) failed\n");
+		return -ENOMEM;
+	}
+
+	(*map)[*num_maps].type = type;
+	(*map)[*num_maps].data.configs.group_or_pin = group;
+	(*map)[*num_maps].data.configs.configs = dup_configs;
+	(*map)[*num_maps].data.configs.num_configs = num_configs;
+	(*num_maps)++;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs);
+
+int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
+		unsigned long **configs, unsigned *num_configs,
+		unsigned long config)
+{
+	unsigned old_num = *num_configs;
+	unsigned new_num = old_num + 1;
+	unsigned long *new_configs;
+
+	new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
+			       GFP_KERNEL);
+	if (!new_configs) {
+		dev_err(pctldev->dev, "krealloc(configs) failed\n");
+		return -ENOMEM;
+	}
+
+	new_configs[old_num] = config;
+
+	*configs = new_configs;
+	*num_configs = new_num;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pinctrl_utils_add_config);
+
+void pinctrl_utils_dt_free_map(struct pinctrl_dev *pctldev,
+	      struct pinctrl_map *map, unsigned num_maps)
+{
+	int i;
+
+	for (i = 0; i < num_maps; i++) {
+		switch (map[i].type) {
+		case PIN_MAP_TYPE_CONFIGS_GROUP:
+		case PIN_MAP_TYPE_CONFIGS_PIN:
+			kfree(map[i].data.configs.configs);
+			break;
+		default:
+			break;
+		}
+	}
+	kfree(map);
+}
+EXPORT_SYMBOL_GPL(pinctrl_utils_dt_free_map);
diff --git a/drivers/pinctrl/pinctrl-utils.h b/drivers/pinctrl/pinctrl-utils.h
new file mode 100644
index 0000000..d0ffe1c
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-utils.h
@@ -0,0 +1,43 @@
+/*
+ * Utils functions to implement the pincontrol driver.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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
+ */
+#ifndef __PINCTRL_UTILS_H__
+#define __PINCTRL_UTILS_H__
+
+int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, unsigned reserve);
+int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
+		struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, const char *group,
+		const char *function);
+int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
+		struct pinctrl_map **map, unsigned *reserved_maps,
+		unsigned *num_maps, const char *group,
+		unsigned long *configs, unsigned num_configs,
+		enum pinctrl_map_type type);
+int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
+		unsigned long **configs, unsigned *num_configs,
+		unsigned long config);
+void pinctrl_utils_dt_free_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map *map, unsigned num_maps);
+
+#endif /* __PINCTRL_UTILS_H__ */
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index e92132c..ed2d1ba 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -102,6 +102,7 @@
 	XWAY_MUX_EPHY,
 	XWAY_MUX_DFE,
 	XWAY_MUX_SDIO,
+	XWAY_MUX_GPHY,
 	XWAY_MUX_NONE = 0xffff,
 };
 
@@ -109,12 +110,12 @@
 	/*       pin    f0	f1	f2	f3   */
 	MFP_XWAY(GPIO0, GPIO,	EXIN,	NONE,	TDM),
 	MFP_XWAY(GPIO1, GPIO,	EXIN,	NONE,	NONE),
-	MFP_XWAY(GPIO2, GPIO,	CGU,	EXIN,	NONE),
+	MFP_XWAY(GPIO2, GPIO,	CGU,	EXIN,	GPHY),
 	MFP_XWAY(GPIO3, GPIO,	CGU,	NONE,	PCI),
 	MFP_XWAY(GPIO4, GPIO,	STP,	NONE,	ASC),
-	MFP_XWAY(GPIO5, GPIO,	STP,	NONE,	NONE),
+	MFP_XWAY(GPIO5, GPIO,	STP,	NONE,	GPHY),
 	MFP_XWAY(GPIO6, GPIO,	STP,	GPT,	ASC),
-	MFP_XWAY(GPIO7, GPIO,	CGU,	PCI,	NONE),
+	MFP_XWAY(GPIO7, GPIO,	CGU,	PCI,	GPHY),
 	MFP_XWAY(GPIO8, GPIO,	CGU,	NMI,	NONE),
 	MFP_XWAY(GPIO9, GPIO,	ASC,	SPI,	EXIN),
 	MFP_XWAY(GPIO10, GPIO,	ASC,	SPI,	NONE),
@@ -151,10 +152,10 @@
 	MFP_XWAY(GPIO41, GPIO,	NONE,	NONE,	NONE),
 	MFP_XWAY(GPIO42, GPIO,	MDIO,	NONE,	NONE),
 	MFP_XWAY(GPIO43, GPIO,	MDIO,	NONE,	NONE),
-	MFP_XWAY(GPIO44, GPIO,	NONE,	NONE,	SIN),
-	MFP_XWAY(GPIO45, GPIO,	NONE,	NONE,	SIN),
+	MFP_XWAY(GPIO44, GPIO,	NONE,	GPHY,	SIN),
+	MFP_XWAY(GPIO45, GPIO,	NONE,	GPHY,	SIN),
 	MFP_XWAY(GPIO46, GPIO,	NONE,	NONE,	EXIN),
-	MFP_XWAY(GPIO47, GPIO,	NONE,	NONE,	SIN),
+	MFP_XWAY(GPIO47, GPIO,	NONE,	GPHY,	SIN),
 	MFP_XWAY(GPIO48, GPIO,	EBU,	NONE,	NONE),
 	MFP_XWAY(GPIO49, GPIO,	EBU,	NONE,	NONE),
 	MFP_XWAY(GPIO50, GPIO,	NONE,	NONE,	NONE),
@@ -208,6 +209,13 @@
 static const unsigned pins_nmi[] = {GPIO8};
 static const unsigned pins_mdio[] = {GPIO42, GPIO43};
 
+static const unsigned pins_gphy0_led0[] = {GPIO5};
+static const unsigned pins_gphy0_led1[] = {GPIO7};
+static const unsigned pins_gphy0_led2[] = {GPIO2};
+static const unsigned pins_gphy1_led0[] = {GPIO44};
+static const unsigned pins_gphy1_led1[] = {GPIO45};
+static const unsigned pins_gphy1_led2[] = {GPIO47};
+
 static const unsigned pins_ebu_a24[] = {GPIO13};
 static const unsigned pins_ebu_clk[] = {GPIO21};
 static const unsigned pins_ebu_cs1[] = {GPIO23};
@@ -322,6 +330,12 @@
 	GRP_MUX("gnt4", PCI, pins_pci_gnt4),
 	GRP_MUX("req4", PCI, pins_pci_gnt4),
 	GRP_MUX("mdio", MDIO, pins_mdio),
+	GRP_MUX("gphy0 led0", GPHY, pins_gphy0_led0),
+	GRP_MUX("gphy0 led1", GPHY, pins_gphy0_led1),
+	GRP_MUX("gphy0 lde2", GPHY, pins_gphy0_led2),
+	GRP_MUX("gphy1 led0", GPHY, pins_gphy1_led0),
+	GRP_MUX("gphy1 led1", GPHY, pins_gphy1_led1),
+	GRP_MUX("gphy1 lde2", GPHY, pins_gphy1_led2),
 };
 
 static const struct ltq_pin_group ase_grps[] = {
@@ -365,6 +379,9 @@
 
 /* ar9/vr9/gr9 */
 static const char * const xrx_mdio_grps[] = {"mdio"};
+static const char * const xrx_gphy_grps[] = {"gphy0 led0", "gphy0 led1",
+						"gphy0 led2", "gphy1 led0",
+						"gphy1 led1", "gphy1 led2"};
 static const char * const xrx_ebu_grps[] = {"ebu a23", "ebu a24",
 						"ebu a25", "ebu cs1",
 						"ebu wait", "ebu clk",
@@ -414,6 +431,7 @@
 	{"pci",		ARRAY_AND_SIZE(xrx_pci_grps)},
 	{"ebu",		ARRAY_AND_SIZE(xrx_ebu_grps)},
 	{"mdio",	ARRAY_AND_SIZE(xrx_mdio_grps)},
+	{"gphy",	ARRAY_AND_SIZE(xrx_gphy_grps)},
 };
 
 static const struct ltq_pmx_func ase_funcs[] = {
@@ -481,74 +499,101 @@
 
 static int xway_pinconf_set(struct pinctrl_dev *pctldev,
 				unsigned pin,
-				unsigned long config)
+				unsigned long *configs,
+				unsigned num_configs)
 {
 	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
-	enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config);
-	int arg = LTQ_PINCONF_UNPACK_ARG(config);
+	enum ltq_pinconf_param param;
+	int arg;
 	int port = PORT(pin);
 	u32 reg;
+	int i;
 
-	switch (param) {
-	case LTQ_PINCONF_PARAM_OPEN_DRAIN:
-		if (port == PORT3)
-			reg = GPIO3_OD;
-		else
-			reg = GPIO_OD(pin);
-		if (arg == 0)
-			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
-		else
-			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
-		break;
+	for (i = 0; i < num_configs; i++) {
+		param = LTQ_PINCONF_UNPACK_PARAM(configs[i]);
+		arg = LTQ_PINCONF_UNPACK_ARG(configs[i]);
 
-	case LTQ_PINCONF_PARAM_PULL:
-		if (port == PORT3)
-			reg = GPIO3_PUDEN;
-		else
-			reg = GPIO_PUDEN(pin);
-		if (arg == 0) {
-			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
+		switch (param) {
+		case LTQ_PINCONF_PARAM_OPEN_DRAIN:
+			if (port == PORT3)
+				reg = GPIO3_OD;
+			else
+				reg = GPIO_OD(pin);
+			if (arg == 0)
+				gpio_setbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
+			else
+				gpio_clearbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
 			break;
+
+		case LTQ_PINCONF_PARAM_PULL:
+			if (port == PORT3)
+				reg = GPIO3_PUDEN;
+			else
+				reg = GPIO_PUDEN(pin);
+			if (arg == 0) {
+				gpio_clearbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
+				break;
+			}
+			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+
+			if (port == PORT3)
+				reg = GPIO3_PUDSEL;
+			else
+				reg = GPIO_PUDSEL(pin);
+			if (arg == 1)
+				gpio_clearbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
+			else if (arg == 2)
+				gpio_setbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
+			else
+				dev_err(pctldev->dev,
+					"Invalid pull value %d\n", arg);
+			break;
+
+		case LTQ_PINCONF_PARAM_OUTPUT:
+			reg = GPIO_DIR(pin);
+			if (arg == 0)
+				gpio_clearbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
+			else
+				gpio_setbit(info->membase[0],
+					reg,
+					PORT_PIN(pin));
+			break;
+
+		default:
+			dev_err(pctldev->dev,
+				"Invalid config param %04x\n", param);
+			return -ENOTSUPP;
 		}
-		gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
+	} /* for each config */
 
-		if (port == PORT3)
-			reg = GPIO3_PUDSEL;
-		else
-			reg = GPIO_PUDSEL(pin);
-		if (arg == 1)
-			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
-		else if (arg == 2)
-			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
-		else
-			dev_err(pctldev->dev, "Invalid pull value %d\n", arg);
-		break;
-
-	case LTQ_PINCONF_PARAM_OUTPUT:
-		reg = GPIO_DIR(pin);
-		if (arg == 0)
-			gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
-		else
-			gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
-		break;
-
-	default:
-		dev_err(pctldev->dev, "Invalid config param %04x\n", param);
-		return -ENOTSUPP;
-	}
 	return 0;
 }
 
 int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
 			unsigned selector,
-			unsigned long config)
+			unsigned long *configs,
+			unsigned num_configs)
 {
 	struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
 	int i, ret = 0;
 
 	for (i = 0; i < info->grps[selector].npins && !ret; i++)
 		ret = xway_pinconf_set(pctldev,
-				info->grps[selector].pins[i], config);
+				info->grps[selector].pins[i],
+				configs,
+				num_configs);
 
 	return ret;
 }
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 88cc509..9d144a2 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -400,10 +400,14 @@
 	ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
 				      &pins, &num_pins);
 	if (ret) {
+		const char *gname;
+
 		/* errors only affect debug data, so just warn */
+		gname = pctlops->get_group_name(pctldev,
+						setting->data.mux.group);
 		dev_warn(pctldev->dev,
-			 "could not get pins for group selector %d\n",
-			 setting->data.mux.group);
+			 "could not get pins for group %s\n",
+			 gname);
 		num_pins = 0;
 	}
 
@@ -411,9 +415,18 @@
 	for (i = 0; i < num_pins; i++) {
 		ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);
 		if (ret) {
+			const char *gname;
+			const char *pname;
+
+			desc = pin_desc_get(pctldev, pins[i]);
+			pname = desc ? desc->name : "non-existing";
+			gname = pctlops->get_group_name(pctldev,
+						setting->data.mux.group);
 			dev_err(pctldev->dev,
-				"could not request pin %d on device %s\n",
-				pins[i], pinctrl_dev_get_name(pctldev));
+				"could not request pin %d (%s) from group %s "
+				" on device %s\n",
+				pins[i], pname, gname,
+				pinctrl_dev_get_name(pctldev));
 			goto err_pin_request;
 		}
 	}
@@ -466,10 +479,14 @@
 	ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
 				      &pins, &num_pins);
 	if (ret) {
+		const char *gname;
+
 		/* errors only affect debug data, so just warn */
+		gname = pctlops->get_group_name(pctldev,
+						setting->data.mux.group);
 		dev_warn(pctldev->dev,
-			 "could not get pins for group selector %d\n",
-			 setting->data.mux.group);
+			 "could not get pins for group %s\n",
+			 gname);
 		num_pins = 0;
 	}
 
@@ -482,12 +499,24 @@
 				 pins[i]);
 			continue;
 		}
-		desc->mux_setting = NULL;
-	}
+		if (desc->mux_setting == &(setting->data.mux)) {
+			desc->mux_setting = NULL;
+			/* And release the pin */
+			pin_free(pctldev, pins[i], NULL);
+		} else {
+			const char *gname;
+			const char *pname;
 
-	/* And release the pins */
-	for (i = 0; i < num_pins; i++)
-		pin_free(pctldev, pins[i], NULL);
+			pname = desc ? desc->name : "non-existing";
+			gname = pctlops->get_group_name(pctldev,
+						setting->data.mux.group);
+			dev_warn(pctldev->dev,
+				 "not freeing pin %d (%s) as part of "
+				 "deactivating group %s - it is already "
+				 "used for some other setting",
+				 pins[i], pname, gname);
+		}
+	}
 
 	if (ops->disable)
 		ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index f3fc66b..738f14f 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -82,24 +82,20 @@
 	unsigned int offset;
 	unsigned int i;
 
-	if (pfc->info->ranges == NULL)
-		return pin;
-
-	for (i = 0, offset = 0; i < pfc->info->nr_ranges; ++i) {
-		const struct pinmux_range *range = &pfc->info->ranges[i];
+	for (i = 0, offset = 0; i < pfc->nr_ranges; ++i) {
+		const struct sh_pfc_pin_range *range = &pfc->ranges[i];
 
 		if (pin <= range->end)
-			return pin >= range->begin
-			     ? offset + pin - range->begin : -1;
+			return pin >= range->start
+			     ? offset + pin - range->start : -1;
 
-		offset += range->end - range->begin + 1;
+		offset += range->end - range->start + 1;
 	}
 
 	return -EINVAL;
 }
 
-static int sh_pfc_enum_in_range(pinmux_enum_t enum_id,
-				const struct pinmux_range *r)
+static int sh_pfc_enum_in_range(u16 enum_id, const struct pinmux_range *r)
 {
 	if (enum_id < r->begin)
 		return 0;
@@ -194,7 +190,7 @@
 	sh_pfc_write_raw_reg(mapped_reg, crp->reg_width, data);
 }
 
-static int sh_pfc_get_config_reg(struct sh_pfc *pfc, pinmux_enum_t enum_id,
+static int sh_pfc_get_config_reg(struct sh_pfc *pfc, u16 enum_id,
 				 const struct pinmux_cfg_reg **crp, int *fieldp,
 				 int *valuep)
 {
@@ -238,10 +234,10 @@
 	return -EINVAL;
 }
 
-static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, pinmux_enum_t mark, int pos,
-			      pinmux_enum_t *enum_idp)
+static int sh_pfc_mark_to_enum(struct sh_pfc *pfc, u16 mark, int pos,
+			      u16 *enum_idp)
 {
-	const pinmux_enum_t *data = pfc->info->gpio_data;
+	const u16 *data = pfc->info->gpio_data;
 	int k;
 
 	if (pos) {
@@ -264,7 +260,7 @@
 int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
 {
 	const struct pinmux_cfg_reg *cr = NULL;
-	pinmux_enum_t enum_id;
+	u16 enum_id;
 	const struct pinmux_range *range;
 	int in_range, pos, field, value;
 	int ret;
@@ -283,14 +279,6 @@
 		range = &pfc->info->input;
 		break;
 
-	case PINMUX_TYPE_INPUT_PULLUP:
-		range = &pfc->info->input_pu;
-		break;
-
-	case PINMUX_TYPE_INPUT_PULLDOWN:
-		range = &pfc->info->input_pd;
-		break;
-
 	default:
 		return -EINVAL;
 	}
@@ -350,6 +338,67 @@
 	return 0;
 }
 
+static int sh_pfc_init_ranges(struct sh_pfc *pfc)
+{
+	struct sh_pfc_pin_range *range;
+	unsigned int nr_ranges;
+	unsigned int i;
+
+	if (pfc->info->pins[0].pin == (u16)-1) {
+		/* Pin number -1 denotes that the SoC doesn't report pin numbers
+		 * in its pin arrays yet. Consider the pin numbers range as
+		 * continuous and allocate a single range.
+		 */
+		pfc->nr_ranges = 1;
+		pfc->ranges = devm_kzalloc(pfc->dev, sizeof(*pfc->ranges),
+					   GFP_KERNEL);
+		if (pfc->ranges == NULL)
+			return -ENOMEM;
+
+		pfc->ranges->start = 0;
+		pfc->ranges->end = pfc->info->nr_pins - 1;
+		pfc->nr_gpio_pins = pfc->info->nr_pins;
+
+		return 0;
+	}
+
+	/* Count, allocate and fill the ranges. The PFC SoC data pins array must
+	 * be sorted by pin numbers, and pins without a GPIO port must come
+	 * last.
+	 */
+	for (i = 1, nr_ranges = 1; i < pfc->info->nr_pins; ++i) {
+		if (pfc->info->pins[i-1].pin != pfc->info->pins[i].pin - 1)
+			nr_ranges++;
+	}
+
+	pfc->nr_ranges = nr_ranges;
+	pfc->ranges = devm_kzalloc(pfc->dev, sizeof(*pfc->ranges) * nr_ranges,
+				   GFP_KERNEL);
+	if (pfc->ranges == NULL)
+		return -ENOMEM;
+
+	range = pfc->ranges;
+	range->start = pfc->info->pins[0].pin;
+
+	for (i = 1; i < pfc->info->nr_pins; ++i) {
+		if (pfc->info->pins[i-1].pin == pfc->info->pins[i].pin - 1)
+			continue;
+
+		range->end = pfc->info->pins[i-1].pin;
+		if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO))
+			pfc->nr_gpio_pins = range->end + 1;
+
+		range++;
+		range->start = pfc->info->pins[i].pin;
+	}
+
+	range->end = pfc->info->pins[i-1].pin;
+	if (!(pfc->info->pins[i-1].configs & SH_PFC_PIN_CFG_NO_GPIO))
+		pfc->nr_gpio_pins = range->end + 1;
+
+	return 0;
+}
+
 #ifdef CONFIG_OF
 static const struct of_device_id sh_pfc_of_table[] = {
 #ifdef CONFIG_PINCTRL_PFC_R8A73A4
@@ -440,6 +489,10 @@
 
 	pinctrl_provide_dummies();
 
+	ret = sh_pfc_init_ranges(pfc);
+	if (ret < 0)
+		return ret;
+
 	/*
 	 * Initialize pinctrl bindings first
 	 */
@@ -486,8 +539,6 @@
 	if (pfc->info->ops && pfc->info->ops->exit)
 		pfc->info->ops->exit(pfc);
 
-	platform_set_drvdata(pdev, NULL);
-
 	return 0;
 }
 
diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
index f02ba1d..a1b2376 100644
--- a/drivers/pinctrl/sh-pfc/core.h
+++ b/drivers/pinctrl/sh-pfc/core.h
@@ -25,6 +25,11 @@
 struct sh_pfc_chip;
 struct sh_pfc_pinctrl;
 
+struct sh_pfc_pin_range {
+	u16 start;
+	u16 end;
+};
+
 struct sh_pfc {
 	struct device *dev;
 	const struct sh_pfc_soc_info *info;
@@ -34,7 +39,10 @@
 	unsigned int num_windows;
 	struct sh_pfc_window *window;
 
-	unsigned int nr_pins;
+	struct sh_pfc_pin_range *ranges;
+	unsigned int nr_ranges;
+
+	unsigned int nr_gpio_pins;
 
 	struct sh_pfc_chip *gpio;
 	struct sh_pfc_chip *func;
diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index d37efa7..04bf52b 100644
--- a/drivers/pinctrl/sh-pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -48,11 +48,11 @@
 	return gpio_to_pfc_chip(gc)->pfc;
 }
 
-static void gpio_get_data_reg(struct sh_pfc_chip *chip, unsigned int gpio,
+static void gpio_get_data_reg(struct sh_pfc_chip *chip, unsigned int offset,
 			      struct sh_pfc_gpio_data_reg **reg,
 			      unsigned int *bit)
 {
-	int idx = sh_pfc_get_pin_index(chip->pfc, gpio);
+	int idx = sh_pfc_get_pin_index(chip->pfc, offset);
 	struct sh_pfc_gpio_pin *gpio_pin = &chip->pins[idx];
 
 	*reg = &chip->regs[gpio_pin->dreg];
@@ -76,11 +76,11 @@
 	sh_pfc_write_raw_reg(mem, dreg->reg_width, value);
 }
 
-static void gpio_setup_data_reg(struct sh_pfc_chip *chip, unsigned gpio)
+static void gpio_setup_data_reg(struct sh_pfc_chip *chip, unsigned idx)
 {
 	struct sh_pfc *pfc = chip->pfc;
-	struct sh_pfc_gpio_pin *gpio_pin = &chip->pins[gpio];
-	const struct sh_pfc_pin *pin = &pfc->info->pins[gpio];
+	struct sh_pfc_gpio_pin *gpio_pin = &chip->pins[idx];
+	const struct sh_pfc_pin *pin = &pfc->info->pins[idx];
 	const struct pinmux_data_reg *dreg;
 	unsigned int bit;
 	unsigned int i;
@@ -224,8 +224,8 @@
 	struct gpio_chip *gc = &chip->gpio_chip;
 	int ret;
 
-	chip->pins = devm_kzalloc(pfc->dev, pfc->nr_pins * sizeof(*chip->pins),
-				  GFP_KERNEL);
+	chip->pins = devm_kzalloc(pfc->dev, pfc->info->nr_pins *
+				  sizeof(*chip->pins), GFP_KERNEL);
 	if (chip->pins == NULL)
 		return -ENOMEM;
 
@@ -245,7 +245,7 @@
 	gc->dev = pfc->dev;
 	gc->owner = THIS_MODULE;
 	gc->base = 0;
-	gc->ngpio = pfc->nr_pins;
+	gc->ngpio = pfc->nr_gpio_pins;
 
 	return 0;
 }
@@ -293,7 +293,7 @@
 
 	gc->label = pfc->info->name;
 	gc->owner = THIS_MODULE;
-	gc->base = pfc->nr_pins;
+	gc->base = pfc->nr_gpio_pins;
 	gc->ngpio = pfc->info->nr_func_gpios;
 
 	return 0;
@@ -334,10 +334,7 @@
 
 int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
 {
-	const struct pinmux_range *ranges;
-	struct pinmux_range def_range;
 	struct sh_pfc_chip *chip;
-	unsigned int nr_ranges;
 	unsigned int i;
 	int ret;
 
@@ -367,24 +364,20 @@
 
 	pfc->gpio = chip;
 
-	/* Register the GPIO to pin mappings. */
-	if (pfc->info->ranges == NULL) {
-		def_range.begin = 0;
-		def_range.end = pfc->info->nr_pins - 1;
-		ranges = &def_range;
-		nr_ranges = 1;
-	} else {
-		ranges = pfc->info->ranges;
-		nr_ranges = pfc->info->nr_ranges;
-	}
+	/* Register the GPIO to pin mappings. As pins with GPIO ports must come
+	 * first in the ranges, skip the pins without GPIO ports by stopping at
+	 * the first range that contains such a pin.
+	 */
+	for (i = 0; i < pfc->nr_ranges; ++i) {
+		const struct sh_pfc_pin_range *range = &pfc->ranges[i];
 
-	for (i = 0; i < nr_ranges; ++i) {
-		const struct pinmux_range *range = &ranges[i];
+		if (range->start >= pfc->nr_gpio_pins)
+			break;
 
 		ret = gpiochip_add_pin_range(&chip->gpio_chip,
 					     dev_name(pfc->dev),
-					     range->begin, range->begin,
-					     range->end - range->begin + 1);
+					     range->start, range->start,
+					     range->end - range->start + 1);
 		if (ret < 0)
 			return ret;
 	}
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
index 82bf6ab..d25fd4e 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a73a4.c
@@ -21,85 +21,84 @@
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <mach/irqs.h>
-#include <mach/r8a73a4.h>
 
 #include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, pfx, sfx)					\
 	/*  Port0 - Port30 */						\
-	PORT_10(fn, pfx, sfx),						\
-	PORT_10(fn, pfx##1, sfx),					\
-	PORT_10(fn, pfx##2, sfx),					\
-	PORT_1(fn,  pfx##30, sfx),					\
+	PORT_10(0, fn, pfx, sfx),					\
+	PORT_10(10, fn, pfx##1, sfx),					\
+	PORT_10(20, fn, pfx##2, sfx),					\
+	PORT_1(30, fn, pfx##30, sfx),					\
 	/* Port32 - Port40 */						\
-	PORT_1(fn,  pfx##32, sfx),	PORT_1(fn,  pfx##33, sfx),	\
-	PORT_1(fn,  pfx##34, sfx),	PORT_1(fn,  pfx##35, sfx),	\
-	PORT_1(fn,  pfx##36, sfx),	PORT_1(fn,  pfx##37, sfx),	\
-	PORT_1(fn,  pfx##38, sfx),	PORT_1(fn,  pfx##39, sfx),	\
-	PORT_1(fn,  pfx##40, sfx),					\
+	PORT_1(32, fn, pfx##32, sfx),	PORT_1(33, fn, pfx##33, sfx),	\
+	PORT_1(34, fn, pfx##34, sfx),	PORT_1(35, fn, pfx##35, sfx),	\
+	PORT_1(36, fn, pfx##36, sfx),	PORT_1(37, fn, pfx##37, sfx),	\
+	PORT_1(38, fn, pfx##38, sfx),	PORT_1(39, fn, pfx##39, sfx),	\
+	PORT_1(40, fn, pfx##40, sfx),					\
 	/* Port64  - Port85 */						\
-	PORT_1(fn, pfx##64, sfx),	PORT_1(fn, pfx##65, sfx),	\
-	PORT_1(fn, pfx##66, sfx),	PORT_1(fn, pfx##67, sfx),	\
-	PORT_1(fn, pfx##68, sfx),	PORT_1(fn, pfx##69, sfx),	\
-	PORT_10(fn, pfx##7, sfx),					\
-	PORT_1(fn, pfx##80, sfx),	PORT_1(fn, pfx##81, sfx),	\
-	PORT_1(fn, pfx##82, sfx),	PORT_1(fn, pfx##83, sfx),	\
-	PORT_1(fn, pfx##84, sfx),	PORT_1(fn, pfx##85, sfx),	\
+	PORT_1(64, fn, pfx##64, sfx),	PORT_1(65, fn, pfx##65, sfx),	\
+	PORT_1(66, fn, pfx##66, sfx),	PORT_1(67, fn, pfx##67, sfx),	\
+	PORT_1(68, fn, pfx##68, sfx),	PORT_1(69, fn, pfx##69, sfx),	\
+	PORT_10(70, fn, pfx##7, sfx),					\
+	PORT_1(80, fn, pfx##80, sfx),	PORT_1(81, fn, pfx##81, sfx),	\
+	PORT_1(82, fn, pfx##82, sfx),	PORT_1(83, fn, pfx##83, sfx),	\
+	PORT_1(84, fn, pfx##84, sfx),	PORT_1(85, fn, pfx##85, sfx),	\
 	/* Port96  - Port126 */						\
-	PORT_1(fn, pfx##96, sfx),	PORT_1(fn, pfx##97, sfx),	\
-	PORT_1(fn, pfx##98, sfx),	PORT_1(fn, pfx##99, sfx),	\
-	PORT_10(fn, pfx##10, sfx),					\
-	PORT_10(fn, pfx##11, sfx),					\
-	PORT_1(fn, pfx##120, sfx),	PORT_1(fn, pfx##121, sfx),	\
-	PORT_1(fn, pfx##122, sfx),	PORT_1(fn, pfx##123, sfx),	\
-	PORT_1(fn, pfx##124, sfx),	PORT_1(fn, pfx##125, sfx),	\
-	PORT_1(fn, pfx##126, sfx),					\
+	PORT_1(96, fn, pfx##96, sfx),	PORT_1(97, fn, pfx##97, sfx),	\
+	PORT_1(98, fn, pfx##98, sfx),	PORT_1(99, fn, pfx##99, sfx),	\
+	PORT_10(100, fn, pfx##10, sfx),					\
+	PORT_10(110, fn, pfx##11, sfx),					\
+	PORT_1(120, fn, pfx##120, sfx),	PORT_1(121, fn, pfx##121, sfx),	\
+	PORT_1(122, fn, pfx##122, sfx),	PORT_1(123, fn, pfx##123, sfx),	\
+	PORT_1(124, fn, pfx##124, sfx),	PORT_1(125, fn, pfx##125, sfx),	\
+	PORT_1(126, fn, pfx##126, sfx),					\
 	/* Port128 - Port134 */						\
-	PORT_1(fn, pfx##128, sfx),	PORT_1(fn, pfx##129, sfx),	\
-	PORT_1(fn, pfx##130, sfx),	PORT_1(fn, pfx##131, sfx),	\
-	PORT_1(fn, pfx##132, sfx),	PORT_1(fn, pfx##133, sfx),	\
-	PORT_1(fn, pfx##134, sfx),					\
+	PORT_1(128, fn, pfx##128, sfx),	PORT_1(129, fn, pfx##129, sfx),	\
+	PORT_1(130, fn, pfx##130, sfx),	PORT_1(131, fn, pfx##131, sfx),	\
+	PORT_1(132, fn, pfx##132, sfx),	PORT_1(133, fn, pfx##133, sfx),	\
+	PORT_1(134, fn, pfx##134, sfx),					\
 	/* Port160 - Port178 */						\
-	PORT_10(fn, pfx##16, sfx),					\
-	PORT_1(fn, pfx##170, sfx),	PORT_1(fn, pfx##171, sfx),	\
-	PORT_1(fn, pfx##172, sfx),	PORT_1(fn, pfx##173, sfx),	\
-	PORT_1(fn, pfx##174, sfx),	PORT_1(fn, pfx##175, sfx),	\
-	PORT_1(fn, pfx##176, sfx),	PORT_1(fn, pfx##177, sfx),	\
-	PORT_1(fn, pfx##178, sfx),					\
+	PORT_10(160, fn, pfx##16, sfx),					\
+	PORT_1(170, fn, pfx##170, sfx),	PORT_1(171, fn, pfx##171, sfx),	\
+	PORT_1(172, fn, pfx##172, sfx),	PORT_1(173, fn, pfx##173, sfx),	\
+	PORT_1(174, fn, pfx##174, sfx),	PORT_1(175, fn, pfx##175, sfx),	\
+	PORT_1(176, fn, pfx##176, sfx),	PORT_1(177, fn, pfx##177, sfx),	\
+	PORT_1(178, fn, pfx##178, sfx),					\
 	/* Port192 - Port222 */						\
-	PORT_1(fn, pfx##192, sfx),	PORT_1(fn, pfx##193, sfx),	\
-	PORT_1(fn, pfx##194, sfx),	PORT_1(fn, pfx##195, sfx),	\
-	PORT_1(fn, pfx##196, sfx),	PORT_1(fn, pfx##197, sfx),	\
-	PORT_1(fn, pfx##198, sfx),	PORT_1(fn, pfx##199, sfx),	\
-	PORT_10(fn, pfx##20, sfx),					\
-	PORT_10(fn, pfx##21, sfx),					\
-	PORT_1(fn, pfx##220, sfx),	PORT_1(fn, pfx##221, sfx),	\
-	PORT_1(fn, pfx##222, sfx),					\
+	PORT_1(192, fn, pfx##192, sfx),	PORT_1(193, fn, pfx##193, sfx),	\
+	PORT_1(194, fn, pfx##194, sfx),	PORT_1(195, fn, pfx##195, sfx),	\
+	PORT_1(196, fn, pfx##196, sfx),	PORT_1(197, fn, pfx##197, sfx),	\
+	PORT_1(198, fn, pfx##198, sfx),	PORT_1(199, fn, pfx##199, sfx),	\
+	PORT_10(200, fn, pfx##20, sfx),					\
+	PORT_10(210, fn, pfx##21, sfx),					\
+	PORT_1(220, fn, pfx##220, sfx),	PORT_1(221, fn, pfx##221, sfx),	\
+	PORT_1(222, fn, pfx##222, sfx),					\
 	/* Port224 - Port250 */						\
-	PORT_1(fn, pfx##224, sfx),	PORT_1(fn, pfx##225, sfx),	\
-	PORT_1(fn, pfx##226, sfx),	PORT_1(fn, pfx##227, sfx),	\
-	PORT_1(fn, pfx##228, sfx),	PORT_1(fn, pfx##229, sfx),	\
-	PORT_10(fn, pfx##23, sfx),					\
-	PORT_10(fn, pfx##24, sfx),					\
-	PORT_1(fn, pfx##250, sfx),					\
+	PORT_1(224, fn, pfx##224, sfx),	PORT_1(225, fn, pfx##225, sfx),	\
+	PORT_1(226, fn, pfx##226, sfx),	PORT_1(227, fn, pfx##227, sfx),	\
+	PORT_1(228, fn, pfx##228, sfx),	PORT_1(229, fn, pfx##229, sfx),	\
+	PORT_10(230, fn, pfx##23, sfx),					\
+	PORT_10(240, fn, pfx##24, sfx),					\
+	PORT_1(250, fn, pfx##250, sfx),					\
 	/* Port256 - Port283 */						\
-	PORT_1(fn, pfx##256, sfx),	PORT_1(fn, pfx##257, sfx),	\
-	PORT_1(fn, pfx##258, sfx),	PORT_1(fn, pfx##259, sfx),	\
-	PORT_10(fn, pfx##26, sfx),					\
-	PORT_10(fn, pfx##27, sfx),					\
-	PORT_1(fn, pfx##280, sfx),	PORT_1(fn, pfx##281, sfx),	\
-	PORT_1(fn, pfx##282, sfx),	PORT_1(fn, pfx##283, sfx),	\
+	PORT_1(256, fn, pfx##256, sfx),	PORT_1(257, fn, pfx##257, sfx),	\
+	PORT_1(258, fn, pfx##258, sfx),	PORT_1(259, fn, pfx##259, sfx),	\
+	PORT_10(260, fn, pfx##26, sfx),					\
+	PORT_10(270, fn, pfx##27, sfx),					\
+	PORT_1(280, fn, pfx##280, sfx),	PORT_1(281, fn, pfx##281, sfx),	\
+	PORT_1(282, fn, pfx##282, sfx),	PORT_1(283, fn, pfx##283, sfx),	\
 	/* Port288 - Port308 */						\
-	PORT_1(fn, pfx##288, sfx),	PORT_1(fn, pfx##289, sfx),	\
-	PORT_10(fn, pfx##29, sfx),					\
-	PORT_1(fn, pfx##300, sfx),	PORT_1(fn, pfx##301, sfx),	\
-	PORT_1(fn, pfx##302, sfx),	PORT_1(fn, pfx##303, sfx),	\
-	PORT_1(fn, pfx##304, sfx),	PORT_1(fn, pfx##305, sfx),	\
-	PORT_1(fn, pfx##306, sfx),	PORT_1(fn, pfx##307, sfx),	\
-	PORT_1(fn, pfx##308, sfx),					\
+	PORT_1(288, fn, pfx##288, sfx),	PORT_1(289, fn, pfx##289, sfx),	\
+	PORT_10(290, fn, pfx##29, sfx),					\
+	PORT_1(300, fn, pfx##300, sfx),	PORT_1(301, fn, pfx##301, sfx),	\
+	PORT_1(302, fn, pfx##302, sfx),	PORT_1(303, fn, pfx##303, sfx),	\
+	PORT_1(304, fn, pfx##304, sfx),	PORT_1(305, fn, pfx##305, sfx),	\
+	PORT_1(306, fn, pfx##306, sfx),	PORT_1(307, fn, pfx##307, sfx),	\
+	PORT_1(308, fn, pfx##308, sfx),					\
 	/* Port320 - Port329 */						\
-	PORT_10(fn, pfx##32, sfx)
+	PORT_10(320, fn, pfx##32, sfx)
 
 
 enum {
@@ -428,10 +427,7 @@
 	PINMUX_MARK_END,
 };
 
-#define _PORT_DATA(pfx, sfx)	PORT_DATA_IO(pfx)
-#define PINMUX_DATA_ALL()    CPU_ALL_PORT(_PORT_DATA, , unused)
-
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* specify valid pin states for each pin in GPIO mode */
 	PINMUX_DATA_ALL(),
 
@@ -1269,19 +1265,12 @@
 	PINMUX_DATA(IRQ57_MARK,			PORT329_FN0),
 };
 
-#define R8A73A4_PIN(pin, cfgs)			\
-	{					\
-		.name = __stringify(PORT##pin),	\
-		.enum_id = PORT##pin##_DATA,	\
-		.configs = cfgs,		\
-	}
-
 #define __O	(SH_PFC_PIN_CFG_OUTPUT)
 #define __IO	(SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
 #define __PUD	(SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
 
-#define R8A73A4_PIN_IO_PU_PD(pin)       R8A73A4_PIN(pin, __IO | __PUD)
-#define R8A73A4_PIN_O(pin)              R8A73A4_PIN(pin, __O)
+#define R8A73A4_PIN_IO_PU_PD(pin)       SH_PFC_PIN_CFG(pin, __IO | __PUD)
+#define R8A73A4_PIN_O(pin)              SH_PFC_PIN_CFG(pin, __O)
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	R8A73A4_PIN_IO_PU_PD(0), R8A73A4_PIN_IO_PU_PD(1),
@@ -1408,20 +1397,6 @@
 	R8A73A4_PIN_IO_PU_PD(328), R8A73A4_PIN_IO_PU_PD(329),
 };
 
-static const struct pinmux_range pinmux_ranges[] = {
-	{.begin = 0, .end = 30,},
-	{.begin = 32, .end = 40,},
-	{.begin = 64, .end = 85,},
-	{.begin = 96, .end = 126,},
-	{.begin = 128, .end = 134,},
-	{.begin = 160, .end = 178,},
-	{.begin = 192, .end = 222,},
-	{.begin = 224, .end = 250,},
-	{.begin = 256, .end = 283,},
-	{.begin = 288, .end = 308,},
-	{.begin = 320, .end = 329,},
-};
-
 /* - IRQC ------------------------------------------------------------------- */
 #define IRQC_PINS_MUX(pin, irq_mark)				\
 static const unsigned int irqc_irq##irq_mark##_pins[] = {	\
@@ -2766,9 +2741,6 @@
 	.pins = pinmux_pins,
 	.nr_pins = ARRAY_SIZE(pinmux_pins),
 
-	.ranges = pinmux_ranges,
-	.nr_ranges = ARRAY_SIZE(pinmux_ranges),
-
 	.groups = pinmux_groups,
 	.nr_groups = ARRAY_SIZE(pinmux_groups),
 	.functions = pinmux_functions,
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index f6ea47c..009174d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -22,24 +22,16 @@
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
-#include <mach/r8a7740.h>
 #include <mach/irqs.h>
 
 #include "core.h"
 #include "sh_pfc.h"
 
 #define CPU_ALL_PORT(fn, pfx, sfx)					\
-	PORT_10(fn, pfx, sfx),		PORT_90(fn, pfx, sfx),		\
-	PORT_10(fn, pfx##10, sfx),	PORT_90(fn, pfx##1, sfx),	\
-	PORT_10(fn, pfx##20, sfx),					\
-	PORT_1(fn, pfx##210, sfx),	PORT_1(fn, pfx##211, sfx)
-
-#undef _GPIO_PORT
-#define _GPIO_PORT(gpio, sfx)						\
-	[gpio] = {							\
-		.name = __stringify(PORT##gpio),			\
-		.enum_id = PORT##gpio##_DATA,				\
-	}
+	PORT_10(0,  fn, pfx, sfx),	PORT_90(0,   fn, pfx, sfx),	\
+	PORT_10(100, fn, pfx##10, sfx),	PORT_90(100, fn, pfx##1, sfx),	\
+	PORT_10(200, fn, pfx##20, sfx),					\
+	PORT_1(210, fn, pfx##210, sfx),	PORT_1(211, fn, pfx##211, sfx)
 
 #define IRQC_PIN_MUX(irq, pin)						\
 static const unsigned int intc_irq##irq##_pins[] = {			\
@@ -590,11 +582,8 @@
 	PINMUX_MARK_END,
 };
 
-#define _PORT_DATA(pfx, sfx)	PORT_DATA_IO(pfx)
-#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_PORT_DATA, , unused)
-
-static const pinmux_enum_t pinmux_data[] = {
-	PINMUX_DATA_GP_ALL(),
+static const u16 pinmux_data[] = {
+	PINMUX_DATA_ALL(),
 
 	/* Port0 */
 	PINMUX_DATA(DBGMDT2_MARK,		PORT0_FN1),
@@ -1537,13 +1526,6 @@
 	PINMUX_DATA(TRACEAUD_FROM_MEMC_MARK,			MSEL5CR_30_1,	MSEL5CR_29_0),
 };
 
-#define R8A7740_PIN(pin, cfgs)						\
-	{								\
-		.name = __stringify(PORT##pin),				\
-		.enum_id = PORT##pin##_DATA,				\
-		.configs = cfgs,					\
-	}
-
 #define __I		(SH_PFC_PIN_CFG_INPUT)
 #define __O		(SH_PFC_PIN_CFG_OUTPUT)
 #define __IO		(SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
@@ -1551,15 +1533,15 @@
 #define __PU		(SH_PFC_PIN_CFG_PULL_UP)
 #define __PUD		(SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
 
-#define R8A7740_PIN_I_PD(pin)		R8A7740_PIN(pin, __I | __PD)
-#define R8A7740_PIN_I_PU(pin)		R8A7740_PIN(pin, __I | __PU)
-#define R8A7740_PIN_I_PU_PD(pin)		R8A7740_PIN(pin, __I | __PUD)
-#define R8A7740_PIN_IO(pin)		R8A7740_PIN(pin, __IO)
-#define R8A7740_PIN_IO_PD(pin)		R8A7740_PIN(pin, __IO | __PD)
-#define R8A7740_PIN_IO_PU(pin)		R8A7740_PIN(pin, __IO | __PU)
-#define R8A7740_PIN_IO_PU_PD(pin)	R8A7740_PIN(pin, __IO | __PUD)
-#define R8A7740_PIN_O(pin)		R8A7740_PIN(pin, __O)
-#define R8A7740_PIN_O_PU_PD(pin)		R8A7740_PIN(pin, __O | __PUD)
+#define R8A7740_PIN_I_PD(pin)		SH_PFC_PIN_CFG(pin, __I | __PD)
+#define R8A7740_PIN_I_PU(pin)		SH_PFC_PIN_CFG(pin, __I | __PU)
+#define R8A7740_PIN_I_PU_PD(pin)	SH_PFC_PIN_CFG(pin, __I | __PUD)
+#define R8A7740_PIN_IO(pin)		SH_PFC_PIN_CFG(pin, __IO)
+#define R8A7740_PIN_IO_PD(pin)		SH_PFC_PIN_CFG(pin, __IO | __PD)
+#define R8A7740_PIN_IO_PU(pin)		SH_PFC_PIN_CFG(pin, __IO | __PU)
+#define R8A7740_PIN_IO_PU_PD(pin)	SH_PFC_PIN_CFG(pin, __IO | __PUD)
+#define R8A7740_PIN_O(pin)		SH_PFC_PIN_CFG(pin, __O)
+#define R8A7740_PIN_O_PU_PD(pin)	SH_PFC_PIN_CFG(pin, __O | __PUD)
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* Table 56-1 (I/O and Pull U/D) */
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
index f903910..428d2a6 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
@@ -23,26 +23,6 @@
 #include <linux/kernel.h>
 #include "sh_pfc.h"
 
-#define PORT_GP_1(bank, pin, fn, sfx) fn(bank, pin, GP_##bank##_##pin, sfx)
-
-#define PORT_GP_32(bank, fn, sfx)					\
-	PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),	\
-	PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),	\
-	PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),	\
-	PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),	\
-	PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),	\
-	PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),	\
-	PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),	\
-	PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),	\
-	PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),	\
-	PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),	\
-	PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),	\
-	PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),	\
-	PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx),	\
-	PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx),	\
-	PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx),	\
-	PORT_GP_1(bank, 30, fn, sfx), PORT_GP_1(bank, 31, fn, sfx)
-
 #define PORT_GP_27(bank, fn, sfx)					\
 	PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),	\
 	PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),	\
@@ -66,26 +46,6 @@
 	PORT_GP_32(3, fn, sfx),		\
 	PORT_GP_27(4, fn, sfx)
 
-#define _GP_PORT_ALL(bank, pin, name, sfx)	name##_##sfx
-
-#define _GP_GPIO(bank, pin, _name, sfx)		\
-	[RCAR_GP_PIN(bank, pin)] = {		\
-		.name = __stringify(_name),	\
-		.enum_id = _name##_DATA,	\
-	}
-
-#define _GP_DATA(bank, pin, name, sfx)		\
-	PINMUX_DATA(name##_DATA, name##_FN)
-
-#define GP_ALL(str)		CPU_ALL_PORT(_GP_PORT_ALL, str)
-#define PINMUX_GPIO_GP_ALL()	CPU_ALL_PORT(_GP_GPIO, unused)
-#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_GP_DATA, unused)
-
-#define PINMUX_IPSR_NOGP(ispr, fn)	PINMUX_DATA(fn##_MARK, FN_##fn)
-#define PINMUX_IPSR_DATA(ipsr, fn)	PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr)
-#define PINMUX_IPSR_MSEL(ipsr, fn, ms)	PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr, FN_##ms)
-#define PINMUX_IPSR_NOGM(ispr, fn, ms)	PINMUX_DATA(fn##_MARK, FN_##fn,            FN_##ms)
-
 enum {
 	PINMUX_RESERVED = 0,
 
@@ -579,7 +539,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
 	PINMUX_DATA(PENC0_MARK,		FN_PENC0),
@@ -1294,16 +1254,21 @@
 	PINMUX_IPSR_MSEL(IP10_24_22,	CAN_CLK_C,	SEL_CANCLK_C),
 };
 
-static struct sh_pfc_pin pinmux_pins[] = {
-	PINMUX_GPIO_GP_ALL(),
-};
-
 /* Pin numbers for pins without a corresponding GPIO port number are computed
  * from the row and column numbers with a 1000 offset to avoid collisions with
  * GPIO port numbers.
  */
 #define PIN_NUMBER(row, col)		(1000+((row)-1)*25+(col)-1)
 
+static struct sh_pfc_pin pinmux_pins[] = {
+	PINMUX_GPIO_GP_ALL(),
+
+	/* Pins not associated with a GPIO port */
+	SH_PFC_PIN_NAMED(3, 20, C20),
+	SH_PFC_PIN_NAMED(20, 1, T1),
+	SH_PFC_PIN_NAMED(25, 2, Y2),
+};
+
 /* - macro */
 #define SH_PFC_PINS(name, args...) \
 	static const unsigned int name ##_pins[] = { args }
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index 8e22ca6..d3e94e3 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -24,51 +24,13 @@
 
 #include "sh_pfc.h"
 
-#define PORT_GP_1(bank, pin, fn, sfx) fn(bank, pin, GP_##bank##_##pin, sfx)
-
-#define PORT_GP_32(bank, fn, sfx)					\
-	PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),	\
-	PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),	\
-	PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),	\
-	PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),	\
-	PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),	\
-	PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),	\
-	PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),	\
-	PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),	\
-	PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),	\
-	PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),	\
-	PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),	\
-	PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),	\
-	PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx),	\
-	PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx),	\
-	PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx),	\
-	PORT_GP_1(bank, 30, fn, sfx), PORT_GP_1(bank, 31, fn, sfx)
-
-#define PORT_GP_32_9(bank, fn, sfx)					\
+#define PORT_GP_9(bank, fn, sfx)					\
 	PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx),	\
 	PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx),	\
 	PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx),	\
 	PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx),	\
 	PORT_GP_1(bank, 8, fn, sfx)
 
-#define PORT_GP_32_REV(bank, fn, sfx)					\
-	PORT_GP_1(bank, 31, fn, sfx), PORT_GP_1(bank, 30, fn, sfx),	\
-	PORT_GP_1(bank, 29, fn, sfx), PORT_GP_1(bank, 28, fn, sfx),	\
-	PORT_GP_1(bank, 27, fn, sfx), PORT_GP_1(bank, 26, fn, sfx),	\
-	PORT_GP_1(bank, 25, fn, sfx), PORT_GP_1(bank, 24, fn, sfx),	\
-	PORT_GP_1(bank, 23, fn, sfx), PORT_GP_1(bank, 22, fn, sfx),	\
-	PORT_GP_1(bank, 21, fn, sfx), PORT_GP_1(bank, 20, fn, sfx),	\
-	PORT_GP_1(bank, 19, fn, sfx), PORT_GP_1(bank, 18, fn, sfx),	\
-	PORT_GP_1(bank, 17, fn, sfx), PORT_GP_1(bank, 16, fn, sfx),	\
-	PORT_GP_1(bank, 15, fn, sfx), PORT_GP_1(bank, 14, fn, sfx),	\
-	PORT_GP_1(bank, 13, fn, sfx), PORT_GP_1(bank, 12, fn, sfx),	\
-	PORT_GP_1(bank, 11, fn, sfx), PORT_GP_1(bank, 10, fn, sfx),	\
-	PORT_GP_1(bank, 9,  fn, sfx), PORT_GP_1(bank, 8,  fn, sfx),	\
-	PORT_GP_1(bank, 7,  fn, sfx), PORT_GP_1(bank, 6,  fn, sfx),	\
-	PORT_GP_1(bank, 5,  fn, sfx), PORT_GP_1(bank, 4,  fn, sfx),	\
-	PORT_GP_1(bank, 3,  fn, sfx), PORT_GP_1(bank, 2,  fn, sfx),	\
-	PORT_GP_1(bank, 1,  fn, sfx), PORT_GP_1(bank, 0,  fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)						\
 	PORT_GP_32(0, fn, sfx),						\
 	PORT_GP_32(1, fn, sfx),						\
@@ -76,26 +38,7 @@
 	PORT_GP_32(3, fn, sfx),						\
 	PORT_GP_32(4, fn, sfx),						\
 	PORT_GP_32(5, fn, sfx),						\
-	PORT_GP_32_9(6, fn, sfx)
-
-#define _GP_PORT_ALL(bank, pin, name, sfx)	name##_##sfx
-
-#define _GP_GPIO(bank, pin, _name, sfx)					\
-	[RCAR_GP_PIN(bank, pin)] = {					\
-		.name = __stringify(_name),				\
-		.enum_id = _name##_DATA,				\
-	}
-
-#define _GP_DATA(bank, pin, name, sfx)					\
-	PINMUX_DATA(name##_DATA, name##_FN)
-
-#define GP_ALL(str)		CPU_ALL_PORT(_GP_PORT_ALL, str)
-#define PINMUX_GPIO_GP_ALL()	CPU_ALL_PORT(_GP_GPIO, unused)
-#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_GP_DATA, unused)
-
-#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
-#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
-							  FN_##ipsr, FN_##fn)
+	PORT_GP_9(6, fn, sfx)
 
 enum {
 	PINMUX_RESERVED = 0,
@@ -664,7 +607,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
 	PINMUX_DATA(AVS1_MARK, FN_AVS1),
@@ -1731,6 +1674,79 @@
 static const unsigned int hspi2_b_mux[] = {
 	HSPI_CLK2_B_MARK, HSPI_CS2_B_MARK, HSPI_RX2_B_MARK, HSPI_TX2_B_MARK,
 };
+/* - I2C1 ------------------------------------------------------------------ */
+static const unsigned int i2c1_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(0, 27), RCAR_GP_PIN(0, 28),
+};
+static const unsigned int i2c1_mux[] = {
+	SCL1_MARK, SDA1_MARK,
+};
+static const unsigned int i2c1_b_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(1, 10), RCAR_GP_PIN(1, 11),
+};
+static const unsigned int i2c1_b_mux[] = {
+	SCL1_B_MARK, SDA1_B_MARK,
+};
+static const unsigned int i2c1_c_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 13),
+};
+static const unsigned int i2c1_c_mux[] = {
+	SCL1_C_MARK, SDA1_C_MARK,
+};
+static const unsigned int i2c1_d_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 27),
+};
+static const unsigned int i2c1_d_mux[] = {
+	SCL1_D_MARK, SDA1_D_MARK,
+};
+/* - I2C2 ------------------------------------------------------------------ */
+static const unsigned int i2c2_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(0, 25), RCAR_GP_PIN(0, 26),
+};
+static const unsigned int i2c2_mux[] = {
+	SCL2_MARK, SDA2_MARK,
+};
+static const unsigned int i2c2_b_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(1, 18), RCAR_GP_PIN(1, 19),
+};
+static const unsigned int i2c2_b_mux[] = {
+	SCL2_B_MARK, SDA2_B_MARK,
+};
+static const unsigned int i2c2_c_pins[] = {
+	/* SCL, SDA */
+	RCAR_GP_PIN(0, 31), RCAR_GP_PIN(0, 30),
+};
+static const unsigned int i2c2_c_mux[] = {
+	SCL2_C_MARK, SDA2_C_MARK,
+};
+static const unsigned int i2c2_d_pins[] = {
+	/* SCL, SDA */
+	RCAR_GP_PIN(1, 24), RCAR_GP_PIN(1, 25),
+};
+static const unsigned int i2c2_d_mux[] = {
+	SCL2_D_MARK, SDA2_D_MARK,
+};
+/* - I2C3 ------------------------------------------------------------------ */
+static const unsigned int i2c3_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(3, 0), RCAR_GP_PIN(2, 30),
+};
+static const unsigned int i2c3_mux[] = {
+	SCL3_MARK, SDA3_MARK,
+};
+static const unsigned int i2c3_b_pins[] = {
+	/* SCL, SDA, */
+	RCAR_GP_PIN(0, 29), RCAR_GP_PIN(0, 30),
+};
+static const unsigned int i2c3_b_mux[] = {
+	SCL3_B_MARK, SDA3_B_MARK,
+};
 /* - INTC ------------------------------------------------------------------- */
 static const unsigned int intc_irq0_pins[] = {
 	/* IRQ */
@@ -2600,6 +2616,16 @@
 	SH_PFC_PIN_GROUP(hspi1_d),
 	SH_PFC_PIN_GROUP(hspi2),
 	SH_PFC_PIN_GROUP(hspi2_b),
+	SH_PFC_PIN_GROUP(i2c1),
+	SH_PFC_PIN_GROUP(i2c1_b),
+	SH_PFC_PIN_GROUP(i2c1_c),
+	SH_PFC_PIN_GROUP(i2c1_d),
+	SH_PFC_PIN_GROUP(i2c2),
+	SH_PFC_PIN_GROUP(i2c2_b),
+	SH_PFC_PIN_GROUP(i2c2_c),
+	SH_PFC_PIN_GROUP(i2c2_d),
+	SH_PFC_PIN_GROUP(i2c3),
+	SH_PFC_PIN_GROUP(i2c3_b),
 	SH_PFC_PIN_GROUP(intc_irq0),
 	SH_PFC_PIN_GROUP(intc_irq0_b),
 	SH_PFC_PIN_GROUP(intc_irq1),
@@ -2760,6 +2786,25 @@
 	"hspi2_b",
 };
 
+static const char * const i2c1_groups[] = {
+	"i2c1",
+	"i2c1_b",
+	"i2c1_c",
+	"i2c1_d",
+};
+
+static const char * const i2c2_groups[] = {
+	"i2c2",
+	"i2c2_b",
+	"i2c2_c",
+	"i2c2_d",
+};
+
+static const char * const i2c3_groups[] = {
+	"i2c3",
+	"i2c3_b",
+};
+
 static const char * const intc_groups[] = {
 	"intc_irq0",
 	"intc_irq0_b",
@@ -2943,6 +2988,9 @@
 	SH_PFC_FUNCTION(hspi0),
 	SH_PFC_FUNCTION(hspi1),
 	SH_PFC_FUNCTION(hspi2),
+	SH_PFC_FUNCTION(i2c1),
+	SH_PFC_FUNCTION(i2c2),
+	SH_PFC_FUNCTION(i2c3),
 	SH_PFC_FUNCTION(intc),
 	SH_PFC_FUNCTION(lbsc),
 	SH_PFC_FUNCTION(mmc0),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index 14f3ec2..64fcc006 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -27,44 +27,6 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define PORT_GP_1(bank, pin, fn, sfx) fn(bank, pin, GP_##bank##_##pin, sfx)
-
-#define PORT_GP_32(bank, fn, sfx)					\
-	PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),	\
-	PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),	\
-	PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),	\
-	PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),	\
-	PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),	\
-	PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),	\
-	PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),	\
-	PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),	\
-	PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),	\
-	PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),	\
-	PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),	\
-	PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),	\
-	PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx),	\
-	PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx),	\
-	PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx),	\
-	PORT_GP_1(bank, 30, fn, sfx), PORT_GP_1(bank, 31, fn, sfx)
-
-#define PORT_GP_32_REV(bank, fn, sfx)					\
-	PORT_GP_1(bank, 31, fn, sfx), PORT_GP_1(bank, 30, fn, sfx),	\
-	PORT_GP_1(bank, 29, fn, sfx), PORT_GP_1(bank, 28, fn, sfx),	\
-	PORT_GP_1(bank, 27, fn, sfx), PORT_GP_1(bank, 26, fn, sfx),	\
-	PORT_GP_1(bank, 25, fn, sfx), PORT_GP_1(bank, 24, fn, sfx),	\
-	PORT_GP_1(bank, 23, fn, sfx), PORT_GP_1(bank, 22, fn, sfx),	\
-	PORT_GP_1(bank, 21, fn, sfx), PORT_GP_1(bank, 20, fn, sfx),	\
-	PORT_GP_1(bank, 19, fn, sfx), PORT_GP_1(bank, 18, fn, sfx),	\
-	PORT_GP_1(bank, 17, fn, sfx), PORT_GP_1(bank, 16, fn, sfx),	\
-	PORT_GP_1(bank, 15, fn, sfx), PORT_GP_1(bank, 14, fn, sfx),	\
-	PORT_GP_1(bank, 13, fn, sfx), PORT_GP_1(bank, 12, fn, sfx),	\
-	PORT_GP_1(bank, 11, fn, sfx), PORT_GP_1(bank, 10, fn, sfx),	\
-	PORT_GP_1(bank, 9,  fn, sfx), PORT_GP_1(bank, 8,  fn, sfx),	\
-	PORT_GP_1(bank, 7,  fn, sfx), PORT_GP_1(bank, 6,  fn, sfx),	\
-	PORT_GP_1(bank, 5,  fn, sfx), PORT_GP_1(bank, 4,  fn, sfx),	\
-	PORT_GP_1(bank, 3,  fn, sfx), PORT_GP_1(bank, 2,  fn, sfx),	\
-	PORT_GP_1(bank, 1,  fn, sfx), PORT_GP_1(bank, 0,  fn, sfx)
-
 #define CPU_ALL_PORT(fn, sfx)						\
 	PORT_GP_32(0, fn, sfx),						\
 	PORT_GP_32(1, fn, sfx),						\
@@ -73,25 +35,6 @@
 	PORT_GP_32(4, fn, sfx),						\
 	PORT_GP_32(5, fn, sfx)
 
-#define _GP_PORT_ALL(bank, pin, name, sfx)	name##_##sfx
-
-#define _GP_GPIO(bank, pin, _name, sfx)					\
-	[(bank * 32) + pin] = {						\
-		.name = __stringify(_name),				\
-		.enum_id = _name##_DATA,				\
-	}
-
-#define _GP_DATA(bank, pin, name, sfx)					\
-	PINMUX_DATA(name##_DATA, name##_FN)
-
-#define GP_ALL(str)		CPU_ALL_PORT(_GP_PORT_ALL, str)
-#define PINMUX_GPIO_GP_ALL()	CPU_ALL_PORT(_GP_GPIO, unused)
-#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_GP_DATA, unused)
-
-#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
-#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
-							  FN_##ipsr, FN_##fn)
-
 enum {
 	PINMUX_RESERVED = 0,
 
@@ -168,18 +111,18 @@
 	FN_VI0_R0, FN_VI0_R0_B, FN_RX0_B, FN_D5,
 	FN_SCIFB1_TXD_F, FN_SCIFB0_TXD_C, FN_VI3_DATA5,
 	FN_VI0_R1, FN_VI0_R1_B, FN_TX0_B, FN_D6,
-	FN_SCL2_C, FN_VI3_DATA6, FN_VI0_R2, FN_VI0_R2_B,
-	FN_SCL2_CIS_C, FN_D7, FN_AD_DI_B, FN_SDA2_C,
-	FN_VI3_DATA7, FN_VI0_R3, FN_VI0_R3_B, FN_SDA2_CIS_C,
-	FN_D8, FN_SCIFA1_SCK_C, FN_AVB_TXD0, FN_MII_TXD0,
+	FN_IIC2_SCL_C, FN_VI3_DATA6, FN_VI0_R2, FN_VI0_R2_B,
+	FN_I2C2_SCL_C, FN_D7, FN_AD_DI_B, FN_IIC2_SDA_C,
+	FN_VI3_DATA7, FN_VI0_R3, FN_VI0_R3_B, FN_I2C2_SDA_C, FN_TCLK1,
+	FN_D8, FN_SCIFA1_SCK_C, FN_AVB_TXD0,
 	FN_VI0_G0, FN_VI0_G0_B, FN_VI2_DATA0_VI2_B0,
 
 	/* IPSR1 */
-	FN_D9, FN_SCIFA1_RXD_C, FN_AVB_TXD1, FN_MII_TXD1,
+	FN_D9, FN_SCIFA1_RXD_C, FN_AVB_TXD1,
 	FN_VI0_G1, FN_VI0_G1_B, FN_VI2_DATA1_VI2_B1, FN_D10,
-	FN_SCIFA1_TXD_C, FN_AVB_TXD2, FN_MII_TXD2,
+	FN_SCIFA1_TXD_C, FN_AVB_TXD2,
 	FN_VI0_G2, FN_VI0_G2_B, FN_VI2_DATA2_VI2_B2, FN_D11,
-	FN_SCIFA1_CTS_N_C, FN_AVB_TXD3, FN_MII_TXD3,
+	FN_SCIFA1_CTS_N_C, FN_AVB_TXD3,
 	FN_VI0_G3, FN_VI0_G3_B, FN_VI2_DATA3_VI2_B3,
 	FN_D12, FN_SCIFA1_RTS_N_C, FN_AVB_TXD4,
 	FN_VI0_HSYNC_N, FN_VI0_HSYNC_N_B, FN_VI2_DATA4_VI2_B4,
@@ -198,9 +141,9 @@
 	FN_A6, FN_SCIFA1_RTS_N_B, FN_TPU0TO2, FN_A7,
 	FN_SCIFA1_SCK_B, FN_AUDIO_CLKOUT_B, FN_TPU0TO3,
 	FN_A8, FN_SCIFA1_RXD_B, FN_SSI_SCK5_B, FN_VI0_R4,
-	FN_VI0_R4_B, FN_SCIFB2_RXD_C, FN_VI2_DATA0_VI2_B0_B,
+	FN_VI0_R4_B, FN_SCIFB2_RXD_C, FN_RX2_B, FN_VI2_DATA0_VI2_B0_B,
 	FN_A9, FN_SCIFA1_CTS_N_B, FN_SSI_WS5_B, FN_VI0_R5,
-	FN_VI0_R5_B, FN_SCIFB2_TXD_C, FN_VI2_DATA1_VI2_B1_B,
+	FN_VI0_R5_B, FN_SCIFB2_TXD_C, FN_TX2_B, FN_VI2_DATA1_VI2_B1_B,
 	FN_A10, FN_SSI_SDATA5_B, FN_MSIOF2_SYNC, FN_VI0_R6,
 	FN_VI0_R6_B, FN_VI2_DATA2_VI2_B2_B,
 
@@ -239,11 +182,11 @@
 	/* IPSR5 */
 	FN_EX_CS3_N, FN_GPS_MAG, FN_VI3_FIELD, FN_VI1_G1, FN_VI1_G1_B,
 	FN_VI2_R3, FN_EX_CS4_N, FN_MSIOF1_SCK_B, FN_VI3_HSYNC_N,
-	FN_VI2_HSYNC_N, FN_SCL1, FN_VI2_HSYNC_N_B,
-	FN_INTC_EN0_N, FN_SCL1_CIS, FN_EX_CS5_N, FN_CAN0_RX,
+	FN_VI2_HSYNC_N, FN_IIC1_SCL, FN_VI2_HSYNC_N_B,
+	FN_INTC_EN0_N, FN_I2C1_SCL, FN_EX_CS5_N, FN_CAN0_RX,
 	FN_MSIOF1_RXD_B, FN_VI3_VSYNC_N, FN_VI1_G2,
-	FN_VI1_G2_B, FN_VI2_R4, FN_SDA1, FN_INTC_EN1_N,
-	FN_SDA1_CIS, FN_BS_N, FN_IETX, FN_HTX1_B,
+	FN_VI1_G2_B, FN_VI2_R4, FN_IIC1_SDA, FN_INTC_EN1_N,
+	FN_I2C1_SDA, FN_BS_N, FN_IETX, FN_HTX1_B,
 	FN_CAN1_TX, FN_DRACK0, FN_IETX_C, FN_RD_N,
 	FN_CAN0_TX, FN_SCIFA0_SCK_B, FN_RD_WR_N, FN_VI1_G3,
 	FN_VI1_G3_B, FN_VI2_R5, FN_SCIFA0_RXD_B,
@@ -266,56 +209,55 @@
 	FN_DREQ2_N, FN_HSCK1_B, FN_HCTS0_N_B,
 	FN_MSIOF0_TXD_B, FN_DACK2, FN_IRQ2, FN_INTC_IRQ2_N,
 	FN_SSI_SDATA6_B, FN_HRTS0_N_B, FN_MSIOF0_RXD_B,
-	FN_ETH_CRS_DV, FN_RMII_CRS_DV, FN_STP_ISCLK_0_B,
-	FN_TS_SDEN0_D, FN_GLO_Q0_C, FN_SCL2_E,
-	FN_SCL2_CIS_E, FN_ETH_RX_ER, FN_RMII_RX_ER,
+	FN_ETH_CRS_DV, FN_STP_ISCLK_0_B,
+	FN_TS_SDEN0_D, FN_GLO_Q0_C, FN_IIC2_SCL_E,
+	FN_I2C2_SCL_E, FN_ETH_RX_ER,
 	FN_STP_ISD_0_B, FN_TS_SPSYNC0_D, FN_GLO_Q1_C,
-	FN_SDA2_E, FN_SDA2_CIS_E, FN_ETH_RXD0, FN_RMII_RXD0,
+	FN_IIC2_SDA_E, FN_I2C2_SDA_E, FN_ETH_RXD0,
 	FN_STP_ISEN_0_B, FN_TS_SDAT0_D, FN_GLO_I0_C,
 	FN_SCIFB1_SCK_G, FN_SCK1_E, FN_ETH_RXD1,
-	FN_RMII_RXD1, FN_HRX0_E, FN_STP_ISSYNC_0_B,
+	FN_HRX0_E, FN_STP_ISSYNC_0_B,
 	FN_TS_SCK0_D, FN_GLO_I1_C, FN_SCIFB1_RXD_G,
-	FN_RX1_E, FN_ETH_LINK, FN_RMII_LINK, FN_HTX0_E,
+	FN_RX1_E, FN_ETH_LINK, FN_HTX0_E,
 	FN_STP_IVCXO27_0_B, FN_SCIFB1_TXD_G, FN_TX1_E,
-	FN_ETH_REF_CLK, FN_RMII_REF_CLK, FN_HCTS0_N_E,
+	FN_ETH_REF_CLK, FN_HCTS0_N_E,
 	FN_STP_IVCXO27_1_B, FN_HRX0_F,
 
 	/* IPSR7 */
-	FN_ETH_MDIO, FN_RMII_MDIO, FN_HRTS0_N_E,
+	FN_ETH_MDIO, FN_HRTS0_N_E,
 	FN_SIM0_D_C, FN_HCTS0_N_F, FN_ETH_TXD1,
-	FN_RMII_TXD1, FN_HTX0_F, FN_BPFCLK_G, FN_RDS_CLK_F,
-	FN_ETH_TX_EN, FN_RMII_TX_EN, FN_SIM0_CLK_C,
-	FN_HRTS0_N_F, FN_ETH_MAGIC, FN_RMII_MAGIC,
-	FN_SIM0_RST_C, FN_ETH_TXD0, FN_RMII_TXD0,
+	FN_HTX0_F, FN_BPFCLK_G,
+	FN_ETH_TX_EN, FN_SIM0_CLK_C,
+	FN_HRTS0_N_F, FN_ETH_MAGIC,
+	FN_SIM0_RST_C, FN_ETH_TXD0,
 	FN_STP_ISCLK_1_B, FN_TS_SDEN1_C, FN_GLO_SCLK_C,
-	FN_ETH_MDC, FN_RMII_MDC, FN_STP_ISD_1_B,
+	FN_ETH_MDC, FN_STP_ISD_1_B,
 	FN_TS_SPSYNC1_C, FN_GLO_SDATA_C, FN_PWM0,
 	FN_SCIFA2_SCK_C, FN_STP_ISEN_1_B, FN_TS_SDAT1_C,
 	FN_GLO_SS_C, FN_PWM1, FN_SCIFA2_TXD_C,
 	FN_STP_ISSYNC_1_B, FN_TS_SCK1_C, FN_GLO_RFON_C,
 	FN_PCMOE_N, FN_PWM2, FN_PWMFSW0, FN_SCIFA2_RXD_C,
-	FN_PCMWE_N, FN_IECLK_C, FN_DU1_DOTCLKIN,
+	FN_PCMWE_N, FN_IECLK_C, FN_DU_DOTCLKIN1,
 	FN_AUDIO_CLKC, FN_AUDIO_CLKOUT_C, FN_VI0_CLK,
-	FN_ATACS00_N, FN_AVB_RXD1, FN_MII_RXD1,
+	FN_ATACS00_N, FN_AVB_RXD1,
 	FN_VI0_DATA0_VI0_B0, FN_ATACS10_N, FN_AVB_RXD2,
-	FN_MII_RXD2,
 
 	/* IPSR8 */
 	FN_VI0_DATA1_VI0_B1, FN_ATARD0_N, FN_AVB_RXD3,
-	FN_MII_RXD3, FN_VI0_DATA2_VI0_B2, FN_ATAWR0_N,
+	FN_VI0_DATA2_VI0_B2, FN_ATAWR0_N,
 	FN_AVB_RXD4, FN_VI0_DATA3_VI0_B3, FN_ATADIR0_N,
 	FN_AVB_RXD5, FN_VI0_DATA4_VI0_B4, FN_ATAG0_N,
 	FN_AVB_RXD6, FN_VI0_DATA5_VI0_B5, FN_EX_WAIT1,
 	FN_AVB_RXD7, FN_VI0_DATA6_VI0_B6, FN_AVB_RX_ER,
-	FN_MII_RX_ER, FN_VI0_DATA7_VI0_B7, FN_AVB_RX_CLK,
-	FN_MII_RX_CLK, FN_VI1_CLK, FN_AVB_RX_DV,
-	FN_MII_RX_DV, FN_VI1_DATA0_VI1_B0, FN_SCIFA1_SCK_D,
-	FN_AVB_CRS, FN_MII_CRS, FN_VI1_DATA1_VI1_B1,
-	FN_SCIFA1_RXD_D, FN_AVB_MDC, FN_MII_MDC,
+	FN_VI0_DATA7_VI0_B7, FN_AVB_RX_CLK,
+	FN_VI1_CLK, FN_AVB_RX_DV,
+	FN_VI1_DATA0_VI1_B0, FN_SCIFA1_SCK_D,
+	FN_AVB_CRS, FN_VI1_DATA1_VI1_B1,
+	FN_SCIFA1_RXD_D, FN_AVB_MDC,
 	FN_VI1_DATA2_VI1_B2, FN_SCIFA1_TXD_D, FN_AVB_MDIO,
-	FN_MII_MDIO, FN_VI1_DATA3_VI1_B3, FN_SCIFA1_CTS_N_D,
+	FN_VI1_DATA3_VI1_B3, FN_SCIFA1_CTS_N_D,
 	FN_AVB_GTX_CLK, FN_VI1_DATA4_VI1_B4, FN_SCIFA1_RTS_N_D,
-	FN_AVB_MAGIC, FN_MII_MAGIC, FN_VI1_DATA5_VI1_B5,
+	FN_AVB_MAGIC, FN_VI1_DATA5_VI1_B5,
 	FN_AVB_PHY_INT, FN_VI1_DATA6_VI1_B6, FN_AVB_GTXREFCLK,
 	FN_SD0_CLK, FN_VI1_DATA0_VI1_B0_B, FN_SD0_CMD,
 	FN_SCIFB1_SCK_B, FN_VI1_DATA1_VI1_B1_B,
@@ -326,26 +268,26 @@
 	FN_SD0_DAT2, FN_SCIFB1_CTS_N_B, FN_VI1_DATA4_VI1_B4_B,
 	FN_SD0_DAT3, FN_SCIFB1_RTS_N_B, FN_VI1_DATA5_VI1_B5_B,
 	FN_SD0_CD, FN_MMC0_D6, FN_TS_SDEN0_B, FN_USB0_EXTP,
-	FN_GLO_SCLK, FN_VI1_DATA6_VI1_B6_B, FN_SCL1_B,
-	FN_SCL1_CIS_B, FN_VI2_DATA6_VI2_B6_B, FN_SD0_WP,
+	FN_GLO_SCLK, FN_VI1_DATA6_VI1_B6_B, FN_IIC1_SCL_B,
+	FN_I2C1_SCL_B, FN_VI2_DATA6_VI2_B6_B, FN_SD0_WP,
 	FN_MMC0_D7, FN_TS_SPSYNC0_B, FN_USB0_IDIN,
-	FN_GLO_SDATA, FN_VI1_DATA7_VI1_B7_B, FN_SDA1_B,
-	FN_SDA1_CIS_B, FN_VI2_DATA7_VI2_B7_B, FN_SD1_CLK,
-	FN_AVB_TX_EN, FN_MII_TX_EN, FN_SD1_CMD,
-	FN_AVB_TX_ER, FN_MII_TX_ER, FN_SCIFB0_SCK_B,
-	FN_SD1_DAT0, FN_AVB_TX_CLK, FN_MII_TX_CLK,
+	FN_GLO_SDATA, FN_VI1_DATA7_VI1_B7_B, FN_IIC1_SDA_B,
+	FN_I2C1_SDA_B, FN_VI2_DATA7_VI2_B7_B, FN_SD1_CLK,
+	FN_AVB_TX_EN, FN_SD1_CMD,
+	FN_AVB_TX_ER, FN_SCIFB0_SCK_B,
+	FN_SD1_DAT0, FN_AVB_TX_CLK,
 	FN_SCIFB0_RXD_B, FN_SD1_DAT1, FN_AVB_LINK,
-	FN_MII_LINK, FN_SCIFB0_TXD_B, FN_SD1_DAT2,
-	FN_AVB_COL, FN_MII_COL, FN_SCIFB0_CTS_N_B,
-	FN_SD1_DAT3, FN_AVB_RXD0, FN_MII_RXD0,
+	FN_SCIFB0_TXD_B, FN_SD1_DAT2,
+	FN_AVB_COL, FN_SCIFB0_CTS_N_B,
+	FN_SD1_DAT3, FN_AVB_RXD0,
 	FN_SCIFB0_RTS_N_B, FN_SD1_CD, FN_MMC1_D6,
 	FN_TS_SDEN1, FN_USB1_EXTP, FN_GLO_SS, FN_VI0_CLK_B,
-	FN_SCL2_D, FN_SCL2_CIS_D, FN_SIM0_CLK_B,
+	FN_IIC2_SCL_D, FN_I2C2_SCL_D, FN_SIM0_CLK_B,
 	FN_VI3_CLK_B,
 
 	/* IPSR10 */
 	FN_SD1_WP, FN_MMC1_D7, FN_TS_SPSYNC1, FN_USB1_IDIN,
-	FN_GLO_RFON, FN_VI1_CLK_B, FN_SDA2_D, FN_SDA2_CIS_D,
+	FN_GLO_RFON, FN_VI1_CLK_B, FN_IIC2_SDA_D, FN_I2C2_SDA_D,
 	FN_SIM0_D_B, FN_SD2_CLK, FN_MMC0_CLK, FN_SIM0_CLK,
 	FN_VI0_DATA0_VI0_B0_B, FN_TS_SDEN0_C, FN_GLO_SCLK_B,
 	FN_VI3_DATA0_B, FN_SD2_CMD, FN_MMC0_CMD, FN_SIM0_D,
@@ -354,10 +296,10 @@
 	FN_SD2_DAT0, FN_MMC0_D0, FN_FMCLK_B,
 	FN_VI0_DATA2_VI0_B2_B, FN_SCIFB1_RXD_E, FN_RX1_D,
 	FN_TS_SDAT0_C, FN_GLO_SS_B, FN_VI3_DATA2_B,
-	FN_SD2_DAT1, FN_MMC0_D1, FN_FMIN_B, FN_RDS_DATA,
+	FN_SD2_DAT1, FN_MMC0_D1, FN_FMIN_B,
 	FN_VI0_DATA3_VI0_B3_B, FN_SCIFB1_TXD_E, FN_TX1_D,
 	FN_TS_SCK0_C, FN_GLO_RFON_B, FN_VI3_DATA3_B,
-	FN_SD2_DAT2, FN_MMC0_D2, FN_BPFCLK_B, FN_RDS_CLK,
+	FN_SD2_DAT2, FN_MMC0_D2, FN_BPFCLK_B,
 	FN_VI0_DATA4_VI0_B4_B, FN_HRX0_D, FN_TS_SDEN1_B,
 	FN_GLO_Q0_B, FN_VI3_DATA4_B, FN_SD2_DAT3,
 	FN_MMC0_D3, FN_SIM0_RST, FN_VI0_DATA5_VI0_B5_B,
@@ -378,12 +320,12 @@
 	FN_SCKZ, FN_SD3_CD, FN_MMC1_D4, FN_TS_SDAT1,
 	FN_VSP, FN_GLO_Q0, FN_SIM0_RST_B, FN_SD3_WP,
 	FN_MMC1_D5, FN_TS_SCK1, FN_GLO_Q1, FN_FMIN_C,
-	FN_RDS_DATA_B, FN_FMIN_E, FN_RDS_DATA_D, FN_FMIN_F,
-	FN_RDS_DATA_E, FN_MLB_CLK, FN_SCL2_B, FN_SCL2_CIS_B,
-	FN_MLB_SIG, FN_SCIFB1_RXD_D, FN_RX1_C, FN_SDA2_B,
-	FN_SDA2_CIS_B, FN_MLB_DAT, FN_SPV_EVEN,
+	FN_FMIN_E, FN_FMIN_F,
+	FN_MLB_CLK, FN_IIC2_SCL_B, FN_I2C2_SCL_B,
+	FN_MLB_SIG, FN_SCIFB1_RXD_D, FN_RX1_C, FN_IIC2_SDA_B,
+	FN_I2C2_SDA_B, FN_MLB_DAT,
 	FN_SCIFB1_TXD_D, FN_TX1_C, FN_BPFCLK_C,
-	FN_RDS_CLK_B, FN_SSI_SCK0129, FN_CAN_CLK_B,
+	FN_SSI_SCK0129, FN_CAN_CLK_B,
 	FN_MOUT0,
 
 	/* IPSR12 */
@@ -410,12 +352,12 @@
 	/* IPSR13 */
 	FN_SSI_SDATA5, FN_SCIFB1_TXD, FN_IETX_B, FN_DU2_DR2,
 	FN_LCDOUT2, FN_CAN_DEBUGOUT5, FN_SSI_SCK6,
-	FN_SCIFB1_CTS_N, FN_BPFCLK_D, FN_RDS_CLK_C,
+	FN_SCIFB1_CTS_N, FN_BPFCLK_D,
 	FN_DU2_DR3, FN_LCDOUT3, FN_CAN_DEBUGOUT6,
-	FN_BPFCLK_F, FN_RDS_CLK_E, FN_SSI_WS6,
+	FN_BPFCLK_F, FN_SSI_WS6,
 	FN_SCIFB1_RTS_N, FN_CAN0_TX_D, FN_DU2_DR4,
 	FN_LCDOUT4, FN_CAN_DEBUGOUT7, FN_SSI_SDATA6,
-	FN_FMIN_D, FN_RDS_DATA_C, FN_DU2_DR5, FN_LCDOUT5,
+	FN_FMIN_D, FN_DU2_DR5, FN_LCDOUT5,
 	FN_CAN_DEBUGOUT8, FN_SSI_SCK78, FN_STP_IVCXO27_1,
 	FN_SCK1, FN_SCIFA1_SCK, FN_DU2_DR6, FN_LCDOUT6,
 	FN_CAN_DEBUGOUT9, FN_SSI_WS78, FN_STP_ISCLK_1,
@@ -423,8 +365,8 @@
 	FN_LCDOUT7, FN_CAN_DEBUGOUT10, FN_SSI_SDATA7,
 	FN_STP_ISD_1, FN_SCIFB2_RXD, FN_SCIFA2_RTS_N,
 	FN_TCLK2, FN_QSTVA_QVS, FN_CAN_DEBUGOUT11,
-	FN_BPFCLK_E, FN_RDS_CLK_D, FN_SSI_SDATA7_B,
-	FN_FMIN_G, FN_RDS_DATA_F, FN_SSI_SDATA8,
+	FN_BPFCLK_E, FN_SSI_SDATA7_B,
+	FN_FMIN_G, FN_SSI_SDATA8,
 	FN_STP_ISEN_1, FN_SCIFB2_TXD, FN_CAN0_TX_C,
 	FN_CAN_DEBUGOUT12, FN_SSI_SDATA8_B, FN_SSI_SDATA9,
 	FN_STP_ISSYNC_1, FN_SCIFB2_CTS_N, FN_SSI_WS1,
@@ -435,29 +377,29 @@
 	FN_AUDIO_CLKB, FN_SCIF_CLK, FN_CAN0_RX_D,
 	FN_DVC_MUTE, FN_CAN0_RX_C, FN_CAN_DEBUGOUT15,
 	FN_REMOCON, FN_SCIFA0_SCK, FN_HSCK1, FN_SCK0,
-	FN_MSIOF3_SS2, FN_DU2_DG2, FN_LCDOUT10, FN_SDA1_C,
-	FN_SDA1_CIS_C, FN_SCIFA0_RXD, FN_HRX1, FN_RX0,
+	FN_MSIOF3_SS2, FN_DU2_DG2, FN_LCDOUT10, FN_IIC1_SDA_C,
+	FN_I2C1_SDA_C, FN_SCIFA0_RXD, FN_HRX1, FN_RX0,
 	FN_DU2_DR0, FN_LCDOUT0, FN_SCIFA0_TXD, FN_HTX1,
 	FN_TX0, FN_DU2_DR1, FN_LCDOUT1, FN_SCIFA0_CTS_N,
 	FN_HCTS1_N, FN_CTS0_N, FN_MSIOF3_SYNC, FN_DU2_DG3,
-	FN_LCDOUT11, FN_PWM0_B, FN_SCL1_C, FN_SCL1_CIS_C,
-	FN_SCIFA0_RTS_N, FN_HRTS1_N, FN_RTS0_N_TANS,
+	FN_LCDOUT11, FN_PWM0_B, FN_IIC1_SCL_C, FN_I2C1_SCL_C,
+	FN_SCIFA0_RTS_N, FN_HRTS1_N, FN_RTS0_N,
 	FN_MSIOF3_SS1, FN_DU2_DG0, FN_LCDOUT8, FN_PWM1_B,
 	FN_SCIFA1_RXD, FN_AD_DI, FN_RX1,
 	FN_DU2_EXODDF_DU2_ODDF_DISP_CDE, FN_QCPV_QDE,
 	FN_SCIFA1_TXD, FN_AD_DO, FN_TX1, FN_DU2_DG1,
 	FN_LCDOUT9, FN_SCIFA1_CTS_N, FN_AD_CLK,
 	FN_CTS1_N, FN_MSIOF3_RXD, FN_DU0_DOTCLKOUT, FN_QCLK,
-	FN_SCIFA1_RTS_N, FN_AD_NCS_N, FN_RTS1_N_TANS,
+	FN_SCIFA1_RTS_N, FN_AD_NCS_N, FN_RTS1_N,
 	FN_MSIOF3_TXD, FN_DU1_DOTCLKOUT, FN_QSTVB_QVE,
 	FN_HRTS0_N_C,
 
 	/* IPSR15 */
-	FN_SCIFA2_SCK, FN_FMCLK, FN_MSIOF3_SCK, FN_DU2_DG7,
+	FN_SCIFA2_SCK, FN_FMCLK, FN_SCK2, FN_MSIOF3_SCK, FN_DU2_DG7,
 	FN_LCDOUT15, FN_SCIF_CLK_B, FN_SCIFA2_RXD, FN_FMIN,
-	FN_DU2_DB0, FN_LCDOUT16, FN_SCL2, FN_SCL2_CIS,
-	FN_SCIFA2_TXD, FN_BPFCLK, FN_DU2_DB1, FN_LCDOUT17,
-	FN_SDA2, FN_SDA2_CIS, FN_HSCK0, FN_TS_SDEN0,
+	FN_TX2, FN_DU2_DB0, FN_LCDOUT16, FN_IIC2_SCL, FN_I2C2_SCL,
+	FN_SCIFA2_TXD, FN_BPFCLK, FN_RX2, FN_DU2_DB1, FN_LCDOUT17,
+	FN_IIC2_SDA, FN_I2C2_SDA, FN_HSCK0, FN_TS_SDEN0,
 	FN_DU2_DG4, FN_LCDOUT12, FN_HCTS0_N_C, FN_HRX0,
 	FN_DU2_DB2, FN_LCDOUT18, FN_HTX0, FN_DU2_DB3,
 	FN_LCDOUT19, FN_HCTS0_N, FN_SSI_SCK9, FN_DU2_DB4,
@@ -465,7 +407,7 @@
 	FN_LCDOUT21, FN_MSIOF0_SCK, FN_TS_SDAT0, FN_ADICLK,
 	FN_DU2_DB6, FN_LCDOUT22, FN_MSIOF0_SYNC, FN_TS_SCK0,
 	FN_SSI_SCK2, FN_ADIDATA, FN_DU2_DB7, FN_LCDOUT23,
-	FN_SCIFA2_RXD_B, FN_MSIOF0_SS1, FN_ADICHS0,
+	FN_HRX0_C, FN_MSIOF0_SS1, FN_ADICHS0,
 	FN_DU2_DG5, FN_LCDOUT13, FN_MSIOF0_TXD, FN_ADICHS1,
 	FN_DU2_DG6, FN_LCDOUT14,
 
@@ -473,7 +415,7 @@
 	FN_MSIOF0_SS2, FN_AUDIO_CLKOUT, FN_ADICHS2,
 	FN_DU2_DISP, FN_QPOLA, FN_HTX0_C, FN_SCIFA2_TXD_B,
 	FN_MSIOF0_RXD, FN_TS_SPSYNC0, FN_SSI_WS2,
-	FN_ADICS_SAMP, FN_DU2_CDE, FN_QPOLB, FN_HRX0_C,
+	FN_ADICS_SAMP, FN_DU2_CDE, FN_QPOLB, FN_SCIFA2_RXD_B,
 	FN_USB1_PWEN, FN_AUDIO_CLKOUT_D, FN_USB1_OVC,
 	FN_TCLK1_B,
 
@@ -508,6 +450,7 @@
 	FN_SEL_CANCLK_0, FN_SEL_CANCLK_1,
 	FN_SEL_SCIFA2_0, FN_SEL_SCIFA2_1, FN_SEL_SCIFA2_2,
 	FN_SEL_CAN1_0, FN_SEL_CAN1_1,
+	FN_SEL_SCIF2_0, FN_SEL_SCIF2_1,
 	FN_SEL_ADI_0, FN_SEL_ADI_1,
 	FN_SEL_SSP_0, FN_SEL_SSP_1,
 	FN_SEL_FM_0, FN_SEL_FM_1, FN_SEL_FM_2, FN_SEL_FM_3,
@@ -515,8 +458,6 @@
 	FN_SEL_HSCIF0_0, FN_SEL_HSCIF0_1, FN_SEL_HSCIF0_2, FN_SEL_HSCIF0_3,
 	FN_SEL_HSCIF0_4, FN_SEL_HSCIF0_5,
 	FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2,
-	FN_SEL_RDS_0, FN_SEL_RDS_1, FN_SEL_RDS_2,
-	FN_SEL_RDS_3, FN_SEL_RDS_4, FN_SEL_RDS_5,
 	FN_SEL_SIM_0, FN_SEL_SIM_1, FN_SEL_SIM_2,
 	FN_SEL_SSI8_0, FN_SEL_SSI8_1, FN_SEL_SSI8_2,
 
@@ -548,17 +489,17 @@
 	VI0_R0_MARK, VI0_R0_B_MARK, RX0_B_MARK, D5_MARK,
 	SCIFB1_TXD_F_MARK, SCIFB0_TXD_C_MARK, VI3_DATA5_MARK,
 	VI0_R1_MARK, VI0_R1_B_MARK, TX0_B_MARK, D6_MARK,
-	SCL2_C_MARK, VI3_DATA6_MARK, VI0_R2_MARK, VI0_R2_B_MARK,
-	SCL2_CIS_C_MARK, D7_MARK, AD_DI_B_MARK, SDA2_C_MARK,
-	VI3_DATA7_MARK, VI0_R3_MARK, VI0_R3_B_MARK, SDA2_CIS_C_MARK,
-	D8_MARK, SCIFA1_SCK_C_MARK, AVB_TXD0_MARK, MII_TXD0_MARK,
+	IIC2_SCL_C_MARK, VI3_DATA6_MARK, VI0_R2_MARK, VI0_R2_B_MARK,
+	I2C2_SCL_C_MARK, D7_MARK, AD_DI_B_MARK, IIC2_SDA_C_MARK,
+	VI3_DATA7_MARK, VI0_R3_MARK, VI0_R3_B_MARK, I2C2_SDA_C_MARK, TCLK1_MARK,
+	D8_MARK, SCIFA1_SCK_C_MARK, AVB_TXD0_MARK,
 	VI0_G0_MARK, VI0_G0_B_MARK, VI2_DATA0_VI2_B0_MARK,
 
-	D9_MARK, SCIFA1_RXD_C_MARK, AVB_TXD1_MARK, MII_TXD1_MARK,
+	D9_MARK, SCIFA1_RXD_C_MARK, AVB_TXD1_MARK,
 	VI0_G1_MARK, VI0_G1_B_MARK, VI2_DATA1_VI2_B1_MARK, D10_MARK,
-	SCIFA1_TXD_C_MARK, AVB_TXD2_MARK, MII_TXD2_MARK,
+	SCIFA1_TXD_C_MARK, AVB_TXD2_MARK,
 	VI0_G2_MARK, VI0_G2_B_MARK, VI2_DATA2_VI2_B2_MARK, D11_MARK,
-	SCIFA1_CTS_N_C_MARK, AVB_TXD3_MARK, MII_TXD3_MARK,
+	SCIFA1_CTS_N_C_MARK, AVB_TXD3_MARK,
 	VI0_G3_MARK, VI0_G3_B_MARK, VI2_DATA3_VI2_B3_MARK,
 	D12_MARK, SCIFA1_RTS_N_C_MARK, AVB_TXD4_MARK,
 	VI0_HSYNC_N_MARK, VI0_HSYNC_N_B_MARK, VI2_DATA4_VI2_B4_MARK,
@@ -576,9 +517,9 @@
 	A6_MARK, SCIFA1_RTS_N_B_MARK, TPU0TO2_MARK, A7_MARK,
 	SCIFA1_SCK_B_MARK, AUDIO_CLKOUT_B_MARK, TPU0TO3_MARK,
 	A8_MARK, SCIFA1_RXD_B_MARK, SSI_SCK5_B_MARK, VI0_R4_MARK,
-	VI0_R4_B_MARK, SCIFB2_RXD_C_MARK, VI2_DATA0_VI2_B0_B_MARK,
+	VI0_R4_B_MARK, SCIFB2_RXD_C_MARK, RX2_B_MARK, VI2_DATA0_VI2_B0_B_MARK,
 	A9_MARK, SCIFA1_CTS_N_B_MARK, SSI_WS5_B_MARK, VI0_R5_MARK,
-	VI0_R5_B_MARK, SCIFB2_TXD_C_MARK, VI2_DATA1_VI2_B1_B_MARK,
+	VI0_R5_B_MARK, SCIFB2_TXD_C_MARK, TX2_B_MARK, VI2_DATA1_VI2_B1_B_MARK,
 	A10_MARK, SSI_SDATA5_B_MARK, MSIOF2_SYNC_MARK, VI0_R6_MARK,
 	VI0_R6_B_MARK, VI2_DATA2_VI2_B2_B_MARK,
 
@@ -615,11 +556,11 @@
 	EX_CS3_N_MARK, GPS_MAG_MARK, VI3_FIELD_MARK,
 	VI1_G1_MARK, VI1_G1_B_MARK, VI2_R3_MARK,
 	EX_CS4_N_MARK, MSIOF1_SCK_B_MARK, VI3_HSYNC_N_MARK,
-	VI2_HSYNC_N_MARK, SCL1_MARK, VI2_HSYNC_N_B_MARK,
-	INTC_EN0_N_MARK, SCL1_CIS_MARK, EX_CS5_N_MARK, CAN0_RX_MARK,
+	VI2_HSYNC_N_MARK, IIC1_SCL_MARK, VI2_HSYNC_N_B_MARK,
+	INTC_EN0_N_MARK, I2C1_SCL_MARK, EX_CS5_N_MARK, CAN0_RX_MARK,
 	MSIOF1_RXD_B_MARK, VI3_VSYNC_N_MARK, VI1_G2_MARK,
-	VI1_G2_B_MARK, VI2_R4_MARK, SDA1_MARK, INTC_EN1_N_MARK,
-	SDA1_CIS_MARK, BS_N_MARK, IETX_MARK, HTX1_B_MARK,
+	VI1_G2_B_MARK, VI2_R4_MARK, IIC1_SDA_MARK, INTC_EN1_N_MARK,
+	I2C1_SDA_MARK, BS_N_MARK, IETX_MARK, HTX1_B_MARK,
 	CAN1_TX_MARK, DRACK0_MARK, IETX_C_MARK, RD_N_MARK,
 	CAN0_TX_MARK, SCIFA0_SCK_B_MARK, RD_WR_N_MARK, VI1_G3_MARK,
 	VI1_G3_B_MARK, VI2_R5_MARK, SCIFA0_RXD_B_MARK,
@@ -641,54 +582,53 @@
 	DREQ2_N_MARK, HSCK1_B_MARK, HCTS0_N_B_MARK,
 	MSIOF0_TXD_B_MARK, DACK2_MARK, IRQ2_MARK, INTC_IRQ2_N_MARK,
 	SSI_SDATA6_B_MARK, HRTS0_N_B_MARK, MSIOF0_RXD_B_MARK,
-	ETH_CRS_DV_MARK, RMII_CRS_DV_MARK, STP_ISCLK_0_B_MARK,
-	TS_SDEN0_D_MARK, GLO_Q0_C_MARK, SCL2_E_MARK,
-	SCL2_CIS_E_MARK, ETH_RX_ER_MARK, RMII_RX_ER_MARK,
+	ETH_CRS_DV_MARK, STP_ISCLK_0_B_MARK,
+	TS_SDEN0_D_MARK, GLO_Q0_C_MARK, IIC2_SCL_E_MARK,
+	I2C2_SCL_E_MARK, ETH_RX_ER_MARK,
 	STP_ISD_0_B_MARK, TS_SPSYNC0_D_MARK, GLO_Q1_C_MARK,
-	SDA2_E_MARK, SDA2_CIS_E_MARK, ETH_RXD0_MARK, RMII_RXD0_MARK,
+	IIC2_SDA_E_MARK, I2C2_SDA_E_MARK, ETH_RXD0_MARK,
 	STP_ISEN_0_B_MARK, TS_SDAT0_D_MARK, GLO_I0_C_MARK,
 	SCIFB1_SCK_G_MARK, SCK1_E_MARK, ETH_RXD1_MARK,
-	RMII_RXD1_MARK, HRX0_E_MARK, STP_ISSYNC_0_B_MARK,
+	HRX0_E_MARK, STP_ISSYNC_0_B_MARK,
 	TS_SCK0_D_MARK, GLO_I1_C_MARK, SCIFB1_RXD_G_MARK,
-	RX1_E_MARK, ETH_LINK_MARK, RMII_LINK_MARK, HTX0_E_MARK,
+	RX1_E_MARK, ETH_LINK_MARK, HTX0_E_MARK,
 	STP_IVCXO27_0_B_MARK, SCIFB1_TXD_G_MARK, TX1_E_MARK,
-	ETH_REF_CLK_MARK, RMII_REF_CLK_MARK, HCTS0_N_E_MARK,
+	ETH_REF_CLK_MARK, HCTS0_N_E_MARK,
 	STP_IVCXO27_1_B_MARK, HRX0_F_MARK,
 
-	ETH_MDIO_MARK, RMII_MDIO_MARK, HRTS0_N_E_MARK,
+	ETH_MDIO_MARK, HRTS0_N_E_MARK,
 	SIM0_D_C_MARK, HCTS0_N_F_MARK, ETH_TXD1_MARK,
-	RMII_TXD1_MARK, HTX0_F_MARK, BPFCLK_G_MARK, RDS_CLK_F_MARK,
-	ETH_TX_EN_MARK, RMII_TX_EN_MARK, SIM0_CLK_C_MARK,
-	HRTS0_N_F_MARK, ETH_MAGIC_MARK, RMII_MAGIC_MARK,
-	SIM0_RST_C_MARK, ETH_TXD0_MARK, RMII_TXD0_MARK,
+	HTX0_F_MARK, BPFCLK_G_MARK,
+	ETH_TX_EN_MARK, SIM0_CLK_C_MARK,
+	HRTS0_N_F_MARK, ETH_MAGIC_MARK,
+	SIM0_RST_C_MARK, ETH_TXD0_MARK,
 	STP_ISCLK_1_B_MARK, TS_SDEN1_C_MARK, GLO_SCLK_C_MARK,
-	ETH_MDC_MARK, RMII_MDC_MARK, STP_ISD_1_B_MARK,
+	ETH_MDC_MARK, STP_ISD_1_B_MARK,
 	TS_SPSYNC1_C_MARK, GLO_SDATA_C_MARK, PWM0_MARK,
 	SCIFA2_SCK_C_MARK, STP_ISEN_1_B_MARK, TS_SDAT1_C_MARK,
 	GLO_SS_C_MARK, PWM1_MARK, SCIFA2_TXD_C_MARK,
 	STP_ISSYNC_1_B_MARK, TS_SCK1_C_MARK, GLO_RFON_C_MARK,
 	PCMOE_N_MARK, PWM2_MARK, PWMFSW0_MARK, SCIFA2_RXD_C_MARK,
-	PCMWE_N_MARK, IECLK_C_MARK, DU1_DOTCLKIN_MARK,
+	PCMWE_N_MARK, IECLK_C_MARK, DU_DOTCLKIN1_MARK,
 	AUDIO_CLKC_MARK, AUDIO_CLKOUT_C_MARK, VI0_CLK_MARK,
-	ATACS00_N_MARK, AVB_RXD1_MARK, MII_RXD1_MARK,
+	ATACS00_N_MARK, AVB_RXD1_MARK,
 	VI0_DATA0_VI0_B0_MARK, ATACS10_N_MARK, AVB_RXD2_MARK,
-	MII_RXD2_MARK,
 
 	VI0_DATA1_VI0_B1_MARK, ATARD0_N_MARK, AVB_RXD3_MARK,
-	MII_RXD3_MARK, VI0_DATA2_VI0_B2_MARK, ATAWR0_N_MARK,
+	VI0_DATA2_VI0_B2_MARK, ATAWR0_N_MARK,
 	AVB_RXD4_MARK, VI0_DATA3_VI0_B3_MARK, ATADIR0_N_MARK,
 	AVB_RXD5_MARK, VI0_DATA4_VI0_B4_MARK, ATAG0_N_MARK,
 	AVB_RXD6_MARK, VI0_DATA5_VI0_B5_MARK, EX_WAIT1_MARK,
 	AVB_RXD7_MARK, VI0_DATA6_VI0_B6_MARK, AVB_RX_ER_MARK,
-	MII_RX_ER_MARK, VI0_DATA7_VI0_B7_MARK, AVB_RX_CLK_MARK,
-	MII_RX_CLK_MARK, VI1_CLK_MARK, AVB_RX_DV_MARK,
-	MII_RX_DV_MARK, VI1_DATA0_VI1_B0_MARK, SCIFA1_SCK_D_MARK,
-	AVB_CRS_MARK, MII_CRS_MARK, VI1_DATA1_VI1_B1_MARK,
-	SCIFA1_RXD_D_MARK, AVB_MDC_MARK, MII_MDC_MARK,
+	VI0_DATA7_VI0_B7_MARK, AVB_RX_CLK_MARK,
+	VI1_CLK_MARK, AVB_RX_DV_MARK,
+	VI1_DATA0_VI1_B0_MARK, SCIFA1_SCK_D_MARK,
+	AVB_CRS_MARK, VI1_DATA1_VI1_B1_MARK,
+	SCIFA1_RXD_D_MARK, AVB_MDC_MARK,
 	VI1_DATA2_VI1_B2_MARK, SCIFA1_TXD_D_MARK, AVB_MDIO_MARK,
-	MII_MDIO_MARK, VI1_DATA3_VI1_B3_MARK, SCIFA1_CTS_N_D_MARK,
+	VI1_DATA3_VI1_B3_MARK, SCIFA1_CTS_N_D_MARK,
 	AVB_GTX_CLK_MARK, VI1_DATA4_VI1_B4_MARK, SCIFA1_RTS_N_D_MARK,
-	AVB_MAGIC_MARK, MII_MAGIC_MARK, VI1_DATA5_VI1_B5_MARK,
+	AVB_MAGIC_MARK, VI1_DATA5_VI1_B5_MARK,
 	AVB_PHY_INT_MARK, VI1_DATA6_VI1_B6_MARK, AVB_GTXREFCLK_MARK,
 	SD0_CLK_MARK, VI1_DATA0_VI1_B0_B_MARK, SD0_CMD_MARK,
 	SCIFB1_SCK_B_MARK, VI1_DATA1_VI1_B1_B_MARK,
@@ -698,25 +638,25 @@
 	SD0_DAT2_MARK, SCIFB1_CTS_N_B_MARK, VI1_DATA4_VI1_B4_B_MARK,
 	SD0_DAT3_MARK, SCIFB1_RTS_N_B_MARK, VI1_DATA5_VI1_B5_B_MARK,
 	SD0_CD_MARK, MMC0_D6_MARK, TS_SDEN0_B_MARK, USB0_EXTP_MARK,
-	GLO_SCLK_MARK, VI1_DATA6_VI1_B6_B_MARK, SCL1_B_MARK,
-	SCL1_CIS_B_MARK, VI2_DATA6_VI2_B6_B_MARK, SD0_WP_MARK,
+	GLO_SCLK_MARK, VI1_DATA6_VI1_B6_B_MARK, IIC1_SCL_B_MARK,
+	I2C1_SCL_B_MARK, VI2_DATA6_VI2_B6_B_MARK, SD0_WP_MARK,
 	MMC0_D7_MARK, TS_SPSYNC0_B_MARK, USB0_IDIN_MARK,
-	GLO_SDATA_MARK, VI1_DATA7_VI1_B7_B_MARK, SDA1_B_MARK,
-	SDA1_CIS_B_MARK, VI2_DATA7_VI2_B7_B_MARK, SD1_CLK_MARK,
-	AVB_TX_EN_MARK, MII_TX_EN_MARK, SD1_CMD_MARK,
-	AVB_TX_ER_MARK, MII_TX_ER_MARK, SCIFB0_SCK_B_MARK,
-	SD1_DAT0_MARK, AVB_TX_CLK_MARK, MII_TX_CLK_MARK,
+	GLO_SDATA_MARK, VI1_DATA7_VI1_B7_B_MARK, IIC1_SDA_B_MARK,
+	I2C1_SDA_B_MARK, VI2_DATA7_VI2_B7_B_MARK, SD1_CLK_MARK,
+	AVB_TX_EN_MARK, SD1_CMD_MARK,
+	AVB_TX_ER_MARK, SCIFB0_SCK_B_MARK,
+	SD1_DAT0_MARK, AVB_TX_CLK_MARK,
 	SCIFB0_RXD_B_MARK, SD1_DAT1_MARK, AVB_LINK_MARK,
-	MII_LINK_MARK, SCIFB0_TXD_B_MARK, SD1_DAT2_MARK,
-	AVB_COL_MARK, MII_COL_MARK, SCIFB0_CTS_N_B_MARK,
-	SD1_DAT3_MARK, AVB_RXD0_MARK, MII_RXD0_MARK,
+	SCIFB0_TXD_B_MARK, SD1_DAT2_MARK,
+	AVB_COL_MARK, SCIFB0_CTS_N_B_MARK,
+	SD1_DAT3_MARK, AVB_RXD0_MARK,
 	SCIFB0_RTS_N_B_MARK, SD1_CD_MARK, MMC1_D6_MARK,
 	TS_SDEN1_MARK, USB1_EXTP_MARK, GLO_SS_MARK, VI0_CLK_B_MARK,
-	SCL2_D_MARK, SCL2_CIS_D_MARK, SIM0_CLK_B_MARK,
+	IIC2_SCL_D_MARK, I2C2_SCL_D_MARK, SIM0_CLK_B_MARK,
 	VI3_CLK_B_MARK,
 
 	SD1_WP_MARK, MMC1_D7_MARK, TS_SPSYNC1_MARK, USB1_IDIN_MARK,
-	GLO_RFON_MARK, VI1_CLK_B_MARK, SDA2_D_MARK, SDA2_CIS_D_MARK,
+	GLO_RFON_MARK, VI1_CLK_B_MARK, IIC2_SDA_D_MARK, I2C2_SDA_D_MARK,
 	SIM0_D_B_MARK, SD2_CLK_MARK, MMC0_CLK_MARK, SIM0_CLK_MARK,
 	VI0_DATA0_VI0_B0_B_MARK, TS_SDEN0_C_MARK, GLO_SCLK_B_MARK,
 	VI3_DATA0_B_MARK, SD2_CMD_MARK, MMC0_CMD_MARK, SIM0_D_MARK,
@@ -725,10 +665,10 @@
 	SD2_DAT0_MARK, MMC0_D0_MARK, FMCLK_B_MARK,
 	VI0_DATA2_VI0_B2_B_MARK, SCIFB1_RXD_E_MARK, RX1_D_MARK,
 	TS_SDAT0_C_MARK, GLO_SS_B_MARK, VI3_DATA2_B_MARK,
-	SD2_DAT1_MARK, MMC0_D1_MARK, FMIN_B_MARK, RDS_DATA_MARK,
+	SD2_DAT1_MARK, MMC0_D1_MARK, FMIN_B_MARK,
 	VI0_DATA3_VI0_B3_B_MARK, SCIFB1_TXD_E_MARK, TX1_D_MARK,
 	TS_SCK0_C_MARK, GLO_RFON_B_MARK, VI3_DATA3_B_MARK,
-	SD2_DAT2_MARK, MMC0_D2_MARK, BPFCLK_B_MARK, RDS_CLK_MARK,
+	SD2_DAT2_MARK, MMC0_D2_MARK, BPFCLK_B_MARK,
 	VI0_DATA4_VI0_B4_B_MARK, HRX0_D_MARK, TS_SDEN1_B_MARK,
 	GLO_Q0_B_MARK, VI3_DATA4_B_MARK, SD2_DAT3_MARK,
 	MMC0_D3_MARK, SIM0_RST_MARK, VI0_DATA5_VI0_B5_B_MARK,
@@ -748,12 +688,12 @@
 	SCKZ_MARK, SD3_CD_MARK, MMC1_D4_MARK, TS_SDAT1_MARK,
 	VSP_MARK, GLO_Q0_MARK, SIM0_RST_B_MARK, SD3_WP_MARK,
 	MMC1_D5_MARK, TS_SCK1_MARK, GLO_Q1_MARK, FMIN_C_MARK,
-	RDS_DATA_B_MARK, FMIN_E_MARK, RDS_DATA_D_MARK, FMIN_F_MARK,
-	RDS_DATA_E_MARK, MLB_CLK_MARK, SCL2_B_MARK, SCL2_CIS_B_MARK,
-	MLB_SIG_MARK, SCIFB1_RXD_D_MARK, RX1_C_MARK, SDA2_B_MARK,
-	SDA2_CIS_B_MARK, MLB_DAT_MARK, SPV_EVEN_MARK,
+	FMIN_E_MARK, FMIN_F_MARK,
+	MLB_CLK_MARK, IIC2_SCL_B_MARK, I2C2_SCL_B_MARK,
+	MLB_SIG_MARK, SCIFB1_RXD_D_MARK, RX1_C_MARK, IIC2_SDA_B_MARK,
+	I2C2_SDA_B_MARK, MLB_DAT_MARK,
 	SCIFB1_TXD_D_MARK, TX1_C_MARK, BPFCLK_C_MARK,
-	RDS_CLK_B_MARK, SSI_SCK0129_MARK, CAN_CLK_B_MARK,
+	SSI_SCK0129_MARK, CAN_CLK_B_MARK,
 	MOUT0_MARK,
 
 	SSI_WS0129_MARK, CAN0_TX_B_MARK, MOUT1_MARK,
@@ -778,12 +718,12 @@
 
 	SSI_SDATA5_MARK, SCIFB1_TXD_MARK, IETX_B_MARK, DU2_DR2_MARK,
 	LCDOUT2_MARK, CAN_DEBUGOUT5_MARK, SSI_SCK6_MARK,
-	SCIFB1_CTS_N_MARK, BPFCLK_D_MARK, RDS_CLK_C_MARK,
+	SCIFB1_CTS_N_MARK, BPFCLK_D_MARK,
 	DU2_DR3_MARK, LCDOUT3_MARK, CAN_DEBUGOUT6_MARK,
-	BPFCLK_F_MARK, RDS_CLK_E_MARK, SSI_WS6_MARK,
+	BPFCLK_F_MARK, SSI_WS6_MARK,
 	SCIFB1_RTS_N_MARK, CAN0_TX_D_MARK, DU2_DR4_MARK,
 	LCDOUT4_MARK, CAN_DEBUGOUT7_MARK, SSI_SDATA6_MARK,
-	FMIN_D_MARK, RDS_DATA_C_MARK, DU2_DR5_MARK, LCDOUT5_MARK,
+	FMIN_D_MARK, DU2_DR5_MARK, LCDOUT5_MARK,
 	CAN_DEBUGOUT8_MARK, SSI_SCK78_MARK, STP_IVCXO27_1_MARK,
 	SCK1_MARK, SCIFA1_SCK_MARK, DU2_DR6_MARK, LCDOUT6_MARK,
 	CAN_DEBUGOUT9_MARK, SSI_WS78_MARK, STP_ISCLK_1_MARK,
@@ -791,8 +731,8 @@
 	LCDOUT7_MARK, CAN_DEBUGOUT10_MARK, SSI_SDATA7_MARK,
 	STP_ISD_1_MARK, SCIFB2_RXD_MARK, SCIFA2_RTS_N_MARK,
 	TCLK2_MARK, QSTVA_QVS_MARK, CAN_DEBUGOUT11_MARK,
-	BPFCLK_E_MARK, RDS_CLK_D_MARK, SSI_SDATA7_B_MARK,
-	FMIN_G_MARK, RDS_DATA_F_MARK, SSI_SDATA8_MARK,
+	BPFCLK_E_MARK, SSI_SDATA7_B_MARK,
+	FMIN_G_MARK, SSI_SDATA8_MARK,
 	STP_ISEN_1_MARK, SCIFB2_TXD_MARK, CAN0_TX_C_MARK,
 	CAN_DEBUGOUT12_MARK, SSI_SDATA8_B_MARK, SSI_SDATA9_MARK,
 	STP_ISSYNC_1_MARK, SCIFB2_CTS_N_MARK, SSI_WS1_MARK,
@@ -802,28 +742,28 @@
 	AUDIO_CLKB_MARK, SCIF_CLK_MARK, CAN0_RX_D_MARK,
 	DVC_MUTE_MARK, CAN0_RX_C_MARK, CAN_DEBUGOUT15_MARK,
 	REMOCON_MARK, SCIFA0_SCK_MARK, HSCK1_MARK, SCK0_MARK,
-	MSIOF3_SS2_MARK, DU2_DG2_MARK, LCDOUT10_MARK, SDA1_C_MARK,
-	SDA1_CIS_C_MARK, SCIFA0_RXD_MARK, HRX1_MARK, RX0_MARK,
+	MSIOF3_SS2_MARK, DU2_DG2_MARK, LCDOUT10_MARK, IIC1_SDA_C_MARK,
+	I2C1_SDA_C_MARK, SCIFA0_RXD_MARK, HRX1_MARK, RX0_MARK,
 	DU2_DR0_MARK, LCDOUT0_MARK, SCIFA0_TXD_MARK, HTX1_MARK,
 	TX0_MARK, DU2_DR1_MARK, LCDOUT1_MARK, SCIFA0_CTS_N_MARK,
 	HCTS1_N_MARK, CTS0_N_MARK, MSIOF3_SYNC_MARK, DU2_DG3_MARK,
-	LCDOUT11_MARK, PWM0_B_MARK, SCL1_C_MARK, SCL1_CIS_C_MARK,
-	SCIFA0_RTS_N_MARK, HRTS1_N_MARK, RTS0_N_TANS_MARK,
+	LCDOUT11_MARK, PWM0_B_MARK, IIC1_SCL_C_MARK, I2C1_SCL_C_MARK,
+	SCIFA0_RTS_N_MARK, HRTS1_N_MARK, RTS0_N_MARK,
 	MSIOF3_SS1_MARK, DU2_DG0_MARK, LCDOUT8_MARK, PWM1_B_MARK,
 	SCIFA1_RXD_MARK, AD_DI_MARK, RX1_MARK,
 	DU2_EXODDF_DU2_ODDF_DISP_CDE_MARK, QCPV_QDE_MARK,
 	SCIFA1_TXD_MARK, AD_DO_MARK, TX1_MARK, DU2_DG1_MARK,
 	LCDOUT9_MARK, SCIFA1_CTS_N_MARK, AD_CLK_MARK,
 	CTS1_N_MARK, MSIOF3_RXD_MARK, DU0_DOTCLKOUT_MARK, QCLK_MARK,
-	SCIFA1_RTS_N_MARK, AD_NCS_N_MARK, RTS1_N_TANS_MARK,
+	SCIFA1_RTS_N_MARK, AD_NCS_N_MARK, RTS1_N_MARK,
 	MSIOF3_TXD_MARK, DU1_DOTCLKOUT_MARK, QSTVB_QVE_MARK,
 	HRTS0_N_C_MARK,
 
-	SCIFA2_SCK_MARK, FMCLK_MARK, MSIOF3_SCK_MARK, DU2_DG7_MARK,
+	SCIFA2_SCK_MARK, FMCLK_MARK, SCK2_MARK, MSIOF3_SCK_MARK, DU2_DG7_MARK,
 	LCDOUT15_MARK, SCIF_CLK_B_MARK, SCIFA2_RXD_MARK, FMIN_MARK,
-	DU2_DB0_MARK, LCDOUT16_MARK, SCL2_MARK, SCL2_CIS_MARK,
-	SCIFA2_TXD_MARK, BPFCLK_MARK, DU2_DB1_MARK, LCDOUT17_MARK,
-	SDA2_MARK, SDA2_CIS_MARK, HSCK0_MARK, TS_SDEN0_MARK,
+	TX2_MARK, DU2_DB0_MARK, LCDOUT16_MARK, IIC2_SCL_MARK, I2C2_SCL_MARK,
+	SCIFA2_TXD_MARK, BPFCLK_MARK, RX2_MARK, DU2_DB1_MARK, LCDOUT17_MARK,
+	IIC2_SDA_MARK, I2C2_SDA_MARK, HSCK0_MARK, TS_SDEN0_MARK,
 	DU2_DG4_MARK, LCDOUT12_MARK, HCTS0_N_C_MARK, HRX0_MARK,
 	DU2_DB2_MARK, LCDOUT18_MARK, HTX0_MARK, DU2_DB3_MARK,
 	LCDOUT19_MARK, HCTS0_N_MARK, SSI_SCK9_MARK, DU2_DB4_MARK,
@@ -831,20 +771,20 @@
 	LCDOUT21_MARK, MSIOF0_SCK_MARK, TS_SDAT0_MARK, ADICLK_MARK,
 	DU2_DB6_MARK, LCDOUT22_MARK, MSIOF0_SYNC_MARK, TS_SCK0_MARK,
 	SSI_SCK2_MARK, ADIDATA_MARK, DU2_DB7_MARK, LCDOUT23_MARK,
-	SCIFA2_RXD_B_MARK, MSIOF0_SS1_MARK, ADICHS0_MARK,
+	HRX0_C_MARK, MSIOF0_SS1_MARK, ADICHS0_MARK,
 	DU2_DG5_MARK, LCDOUT13_MARK, MSIOF0_TXD_MARK, ADICHS1_MARK,
 	DU2_DG6_MARK, LCDOUT14_MARK,
 
 	MSIOF0_SS2_MARK, AUDIO_CLKOUT_MARK, ADICHS2_MARK,
 	DU2_DISP_MARK, QPOLA_MARK, HTX0_C_MARK, SCIFA2_TXD_B_MARK,
 	MSIOF0_RXD_MARK, TS_SPSYNC0_MARK, SSI_WS2_MARK,
-	ADICS_SAMP_MARK, DU2_CDE_MARK, QPOLB_MARK, HRX0_C_MARK,
+	ADICS_SAMP_MARK, DU2_CDE_MARK, QPOLB_MARK, SCIFA2_RXD_B_MARK,
 	USB1_PWEN_MARK, AUDIO_CLKOUT_D_MARK, USB1_OVC_MARK,
 	TCLK1_B_MARK,
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
 	PINMUX_DATA(VI1_DATA7_VI1_B7_MARK, FN_VI1_DATA7_VI1_B7),
@@ -892,22 +832,22 @@
 	PINMUX_IPSR_MODSEL_DATA(IP0_19_16, VI0_R1_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP0_19_16, TX0_B, SEL_SCIF0_1),
 	PINMUX_IPSR_DATA(IP0_22_20, D6),
-	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, SCL2_C, SEL_IIC2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, IIC2_SCL_C, SEL_IIC2_2),
 	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, VI3_DATA6, SEL_VI3_0),
 	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, VI0_R2, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, VI0_R2_B, SEL_VI0_1),
-	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, SCL2_CIS_C, SEL_I2C2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP0_22_20, I2C2_SCL_C, SEL_I2C2_2),
 	PINMUX_IPSR_DATA(IP0_26_23, D7),
 	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, AD_DI_B, SEL_ADI_1),
-	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, SDA2_C, SEL_IIC2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, IIC2_SDA_C, SEL_IIC2_2),
 	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, VI3_DATA7, SEL_VI3_0),
 	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, VI0_R3, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, VI0_R3_B, SEL_VI0_1),
-	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, SDA2_CIS_C, SEL_I2C2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, I2C2_SDA_C, SEL_I2C2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP0_26_23, TCLK1, SEL_TMU1_0),
 	PINMUX_IPSR_DATA(IP0_30_27, D8),
 	PINMUX_IPSR_MODSEL_DATA(IP0_30_27, SCIFA1_SCK_C, SEL_SCIFA1_2),
 	PINMUX_IPSR_DATA(IP0_30_27, AVB_TXD0),
-	PINMUX_IPSR_DATA(IP0_30_27, MII_TXD0),
 	PINMUX_IPSR_MODSEL_DATA(IP0_30_27, VI0_G0, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP0_30_27, VI0_G0_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP0_30_27, VI2_DATA0_VI2_B0, SEL_VI2_0),
@@ -915,21 +855,18 @@
 	PINMUX_IPSR_DATA(IP1_3_0, D9),
 	PINMUX_IPSR_MODSEL_DATA(IP1_3_0, SCIFA1_RXD_C, SEL_SCIFA1_2),
 	PINMUX_IPSR_DATA(IP1_3_0, AVB_TXD1),
-	PINMUX_IPSR_DATA(IP1_3_0, MII_TXD1),
 	PINMUX_IPSR_MODSEL_DATA(IP1_3_0, VI0_G1, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP1_3_0, VI0_G1_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP1_3_0, VI2_DATA1_VI2_B1, SEL_VI2_0),
 	PINMUX_IPSR_DATA(IP1_7_4, D10),
 	PINMUX_IPSR_MODSEL_DATA(IP1_7_4, SCIFA1_TXD_C, SEL_SCIFA1_2),
 	PINMUX_IPSR_DATA(IP1_7_4, AVB_TXD2),
-	PINMUX_IPSR_DATA(IP1_7_4, MII_TXD2),
 	PINMUX_IPSR_MODSEL_DATA(IP1_7_4, VI0_G2, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP1_7_4, VI0_G2_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP1_7_4, VI2_DATA2_VI2_B2, SEL_VI2_0),
 	PINMUX_IPSR_DATA(IP1_11_8, D11),
 	PINMUX_IPSR_MODSEL_DATA(IP1_11_8, SCIFA1_CTS_N_C, SEL_SCIFA1_2),
 	PINMUX_IPSR_DATA(IP1_11_8, AVB_TXD3),
-	PINMUX_IPSR_DATA(IP1_11_8, MII_TXD3),
 	PINMUX_IPSR_MODSEL_DATA(IP1_11_8, VI0_G3, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP1_11_8, VI0_G3_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP1_11_8, VI2_DATA3_VI2_B3, SEL_VI2_0),
@@ -940,7 +877,7 @@
 	PINMUX_IPSR_MODSEL_DATA(IP1_14_12, VI0_HSYNC_N_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP1_14_12, VI2_DATA4_VI2_B4, SEL_VI2_0),
 	PINMUX_IPSR_DATA(IP1_17_15, D13),
-	PINMUX_IPSR_MODSEL_DATA(IP1_17_15, AVB_TXD5, SEL_SCIFA1_2),
+	PINMUX_IPSR_DATA(IP1_17_15, AVB_TXD5),
 	PINMUX_IPSR_MODSEL_DATA(IP1_17_15, VI0_VSYNC_N, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP1_17_15, VI0_VSYNC_N_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP1_17_15, VI2_DATA5_VI2_B5, SEL_VI2_0),
@@ -988,6 +925,7 @@
 	PINMUX_IPSR_MODSEL_DATA(IP2_21_18, VI0_R4, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP2_21_18, VI0_R4_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP2_21_18, SCIFB2_RXD_C, SEL_SCIFB2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP2_21_18, RX2_B, SEL_SCIF2_1),
 	PINMUX_IPSR_MODSEL_DATA(IP2_21_18, VI2_DATA0_VI2_B0_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP2_25_22, A9),
 	PINMUX_IPSR_MODSEL_DATA(IP2_25_22, SCIFA1_CTS_N_B, SEL_SCIFA1_1),
@@ -995,6 +933,7 @@
 	PINMUX_IPSR_MODSEL_DATA(IP2_25_22, VI0_R5, SEL_VI0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP2_25_22, VI0_R5_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP2_25_22, SCIFB2_TXD_C, SEL_SCIFB2_2),
+	PINMUX_IPSR_MODSEL_DATA(IP2_25_22, TX2_B, SEL_SCIF2_1),
 	PINMUX_IPSR_MODSEL_DATA(IP2_25_22, VI2_DATA1_VI2_B1_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP2_28_26, A10),
 	PINMUX_IPSR_MODSEL_DATA(IP2_28_26, SSI_SDATA5_B, SEL_SSI5_1),
@@ -1009,14 +948,14 @@
 	PINMUX_IPSR_MODSEL_DATA(IP3_3_0, VI1_R0, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP3_3_0, VI1_R0_B, SEL_VI1_1),
 	PINMUX_IPSR_DATA(IP3_3_0, VI2_G0),
-	PINMUX_IPSR_DATA(IP3_3_0, VI2_DATA3_VI2_B3_B),
+	PINMUX_IPSR_MODSEL_DATA(IP3_3_0, VI2_DATA3_VI2_B3_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP3_7_4, A12),
 	PINMUX_IPSR_MODSEL_DATA(IP3_7_4, SCIFB2_RXD_B, SEL_SCIFB2_1),
 	PINMUX_IPSR_DATA(IP3_7_4, MSIOF2_TXD),
 	PINMUX_IPSR_MODSEL_DATA(IP3_7_4, VI1_R1, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP3_7_4, VI1_R1_B, SEL_VI1_1),
 	PINMUX_IPSR_DATA(IP3_7_4, VI2_G1),
-	PINMUX_IPSR_DATA(IP3_7_4, VI2_DATA4_VI2_B4_B),
+	PINMUX_IPSR_MODSEL_DATA(IP3_7_4, VI2_DATA4_VI2_B4_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP3_11_8, A13),
 	PINMUX_IPSR_MODSEL_DATA(IP3_11_8, SCIFB2_RTS_N_B, SEL_SCIFB2_1),
 	PINMUX_IPSR_DATA(IP3_11_8, EX_WAIT2),
@@ -1024,7 +963,7 @@
 	PINMUX_IPSR_MODSEL_DATA(IP3_11_8, VI1_R2, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP3_11_8, VI1_R2_B, SEL_VI1_1),
 	PINMUX_IPSR_DATA(IP3_11_8, VI2_G2),
-	PINMUX_IPSR_MODSEL_DATA(IP3_11_8, VI2_DATA5_VI2_B5_B, SEL_VI2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP3_11_8, VI2_DATA5_VI2_B5_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP3_14_12, A14),
 	PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SCIFB2_TXD_B, SEL_SCIFB2_1),
 	PINMUX_IPSR_DATA(IP3_14_12, ATACS11_N),
@@ -1116,14 +1055,14 @@
 	PINMUX_IPSR_MODSEL_DATA(IP5_2_0, VI1_G1, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP5_2_0, VI1_G1_B, SEL_VI1_1),
 	PINMUX_IPSR_DATA(IP5_2_0, VI2_R3),
-	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, EX_CS4_N, SEL_I2C1_0),
+	PINMUX_IPSR_DATA(IP5_5_3, EX_CS4_N),
 	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, MSIOF1_SCK_B, SEL_SOF1_1),
 	PINMUX_IPSR_DATA(IP5_5_3, VI3_HSYNC_N),
 	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, VI2_HSYNC_N, SEL_VI2_0),
-	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SCL1, SEL_IIC1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, IIC1_SCL, SEL_IIC1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, VI2_HSYNC_N_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP5_5_3, INTC_EN0_N),
-	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SCL1_CIS, SEL_I2C1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_5_3, I2C1_SCL, SEL_I2C1_0),
 	PINMUX_IPSR_DATA(IP5_9_6, EX_CS5_N),
 	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, CAN0_RX, SEL_CAN0_0),
 	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, MSIOF1_RXD_B, SEL_SOF1_1),
@@ -1131,9 +1070,9 @@
 	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, VI1_G2, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, VI1_G2_B, SEL_VI1_1),
 	PINMUX_IPSR_DATA(IP5_9_6, VI2_R4),
-	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, SDA1, SEL_IIC1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, IIC1_SDA, SEL_IIC1_0),
 	PINMUX_IPSR_DATA(IP5_9_6, INTC_EN1_N),
-	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, SDA1_CIS, SEL_I2C1_0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_9_6, I2C1_SDA, SEL_I2C1_0),
 	PINMUX_IPSR_DATA(IP5_12_10, BS_N),
 	PINMUX_IPSR_MODSEL_DATA(IP5_12_10, IETX, SEL_IEB_0),
 	PINMUX_IPSR_MODSEL_DATA(IP5_12_10, HTX1_B, SEL_HSCIF1_1),
@@ -1163,7 +1102,7 @@
 	PINMUX_IPSR_DATA(IP5_23_21, VI2_R6),
 	PINMUX_IPSR_MODSEL_DATA(IP5_23_21, SCIFA0_CTS_N_B, SEL_SCFA_1),
 	PINMUX_IPSR_MODSEL_DATA(IP5_23_21, IERX_C, SEL_IEB_2),
-	PINMUX_IPSR_DATA(IP5_26_24, EX_WAIT0),
+	PINMUX_IPSR_MODSEL_DATA(IP5_26_24, EX_WAIT0, SEL_LBS_0),
 	PINMUX_IPSR_DATA(IP5_26_24, IRQ3),
 	PINMUX_IPSR_DATA(IP5_26_24, INTC_IRQ3_N),
 	PINMUX_IPSR_MODSEL_DATA(IP5_26_24, VI3_CLK, SEL_VI3_0),
@@ -1205,28 +1144,24 @@
 	PINMUX_IPSR_MODSEL_DATA(IP6_13_11, HRTS0_N_B, SEL_HSCIF0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_13_11, MSIOF0_RXD_B, SEL_SOF0_1),
 	PINMUX_IPSR_DATA(IP6_16_14, ETH_CRS_DV),
-	PINMUX_IPSR_DATA(IP6_16_14, RMII_CRS_DV),
 	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, STP_ISCLK_0_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, TS_SDEN0_D, SEL_TSIF0_3),
 	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, GLO_Q0_C, SEL_GPS_2),
-	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, SCL2_E, SEL_IIC2_4),
-	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, SCL2_CIS_E, SEL_I2C2_4),
+	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, IIC2_SCL_E, SEL_IIC2_4),
+	PINMUX_IPSR_MODSEL_DATA(IP6_16_14, I2C2_SCL_E, SEL_I2C2_4),
 	PINMUX_IPSR_DATA(IP6_19_17, ETH_RX_ER),
-	PINMUX_IPSR_DATA(IP6_19_17, RMII_RX_ER),
 	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, STP_ISD_0_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, TS_SPSYNC0_D, SEL_TSIF0_3),
 	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, GLO_Q1_C, SEL_GPS_2),
-	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, SDA2_E, SEL_IIC2_4),
-	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, SDA2_CIS_E, SEL_I2C2_4),
+	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, IIC2_SDA_E, SEL_IIC2_4),
+	PINMUX_IPSR_MODSEL_DATA(IP6_19_17, I2C2_SDA_E, SEL_I2C2_4),
 	PINMUX_IPSR_DATA(IP6_22_20, ETH_RXD0),
-	PINMUX_IPSR_DATA(IP6_22_20, RMII_RXD0),
 	PINMUX_IPSR_MODSEL_DATA(IP6_22_20, STP_ISEN_0_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_22_20, TS_SDAT0_D, SEL_TSIF0_3),
 	PINMUX_IPSR_MODSEL_DATA(IP6_22_20, GLO_I0_C, SEL_GPS_2),
 	PINMUX_IPSR_MODSEL_DATA(IP6_22_20, SCIFB1_SCK_G, SEL_SCIFB1_6),
 	PINMUX_IPSR_MODSEL_DATA(IP6_22_20, SCK1_E, SEL_SCIF1_4),
 	PINMUX_IPSR_DATA(IP6_25_23, ETH_RXD1),
-	PINMUX_IPSR_DATA(IP6_25_23, RMII_RXD1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_25_23, HRX0_E, SEL_HSCIF0_4),
 	PINMUX_IPSR_MODSEL_DATA(IP6_25_23, STP_ISSYNC_0_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_25_23, TS_SCK0_D, SEL_TSIF0_3),
@@ -1234,41 +1169,32 @@
 	PINMUX_IPSR_MODSEL_DATA(IP6_25_23, SCIFB1_RXD_G, SEL_SCIFB1_6),
 	PINMUX_IPSR_MODSEL_DATA(IP6_25_23, RX1_E, SEL_SCIF1_4),
 	PINMUX_IPSR_DATA(IP6_28_26, ETH_LINK),
-	PINMUX_IPSR_DATA(IP6_28_26, RMII_LINK),
 	PINMUX_IPSR_MODSEL_DATA(IP6_28_26, HTX0_E, SEL_HSCIF0_4),
 	PINMUX_IPSR_MODSEL_DATA(IP6_28_26, STP_IVCXO27_0_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_28_26, SCIFB1_TXD_G, SEL_SCIFB1_6),
 	PINMUX_IPSR_MODSEL_DATA(IP6_28_26, TX1_E, SEL_SCIF1_4),
 	PINMUX_IPSR_DATA(IP6_31_29, ETH_REF_CLK),
-	PINMUX_IPSR_DATA(IP6_31_29, RMII_REF_CLK),
 	PINMUX_IPSR_MODSEL_DATA(IP6_31_29, HCTS0_N_E, SEL_HSCIF0_4),
 	PINMUX_IPSR_MODSEL_DATA(IP6_31_29, STP_IVCXO27_1_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP6_31_29, HRX0_F, SEL_HSCIF0_5),
 
 	PINMUX_IPSR_DATA(IP7_2_0, ETH_MDIO),
-	PINMUX_IPSR_DATA(IP7_2_0, RMII_MDIO),
 	PINMUX_IPSR_MODSEL_DATA(IP7_2_0, HRTS0_N_E, SEL_HSCIF0_4),
 	PINMUX_IPSR_MODSEL_DATA(IP7_2_0, SIM0_D_C, SEL_SIM_2),
 	PINMUX_IPSR_MODSEL_DATA(IP7_2_0, HCTS0_N_F, SEL_HSCIF0_5),
 	PINMUX_IPSR_DATA(IP7_5_3, ETH_TXD1),
-	PINMUX_IPSR_DATA(IP7_5_3, RMII_TXD1),
-	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, HTX0_F, SEL_HSCIF0_4),
-	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, BPFCLK_G, SEL_SIM_2),
-	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, RDS_CLK_F, SEL_HSCIF0_5),
+	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, HTX0_F, SEL_HSCIF0_5),
+	PINMUX_IPSR_MODSEL_DATA(IP7_5_3, BPFCLK_G, SEL_FM_6),
 	PINMUX_IPSR_DATA(IP7_7_6, ETH_TX_EN),
-	PINMUX_IPSR_DATA(IP7_7_6, RMII_TX_EN),
 	PINMUX_IPSR_MODSEL_DATA(IP7_7_6, SIM0_CLK_C, SEL_SIM_2),
 	PINMUX_IPSR_MODSEL_DATA(IP7_7_6, HRTS0_N_F, SEL_HSCIF0_5),
 	PINMUX_IPSR_DATA(IP7_9_8, ETH_MAGIC),
-	PINMUX_IPSR_DATA(IP7_9_8, RMII_MAGIC),
 	PINMUX_IPSR_MODSEL_DATA(IP7_9_8, SIM0_RST_C, SEL_SIM_2),
 	PINMUX_IPSR_DATA(IP7_12_10, ETH_TXD0),
-	PINMUX_IPSR_DATA(IP7_12_10, RMII_TXD0),
 	PINMUX_IPSR_MODSEL_DATA(IP7_12_10, STP_ISCLK_1_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP7_12_10, TS_SDEN1_C, SEL_TSIF1_2),
 	PINMUX_IPSR_MODSEL_DATA(IP7_12_10, GLO_SCLK_C, SEL_GPS_2),
 	PINMUX_IPSR_DATA(IP7_15_13, ETH_MDC),
-	PINMUX_IPSR_DATA(IP7_15_13, RMII_MDC),
 	PINMUX_IPSR_MODSEL_DATA(IP7_15_13, STP_ISD_1_B, SEL_SSP_1),
 	PINMUX_IPSR_MODSEL_DATA(IP7_15_13, TS_SPSYNC1_C, SEL_TSIF1_2),
 	PINMUX_IPSR_MODSEL_DATA(IP7_15_13, GLO_SDATA_C, SEL_GPS_2),
@@ -1288,22 +1214,19 @@
 	PINMUX_IPSR_MODSEL_DATA(IP7_24_22, SCIFA2_RXD_C, SEL_SCIFA2_2),
 	PINMUX_IPSR_DATA(IP7_24_22, PCMWE_N),
 	PINMUX_IPSR_MODSEL_DATA(IP7_24_22, IECLK_C, SEL_IEB_2),
-	PINMUX_IPSR_DATA(IP7_26_25, DU1_DOTCLKIN),
+	PINMUX_IPSR_DATA(IP7_26_25, DU_DOTCLKIN1),
 	PINMUX_IPSR_DATA(IP7_26_25, AUDIO_CLKC),
 	PINMUX_IPSR_DATA(IP7_26_25, AUDIO_CLKOUT_C),
 	PINMUX_IPSR_MODSEL_DATA(IP7_28_27, VI0_CLK, SEL_VI0_0),
 	PINMUX_IPSR_DATA(IP7_28_27, ATACS00_N),
 	PINMUX_IPSR_DATA(IP7_28_27, AVB_RXD1),
-	PINMUX_IPSR_DATA(IP7_28_27, MII_RXD1),
 	PINMUX_IPSR_MODSEL_DATA(IP7_30_29, VI0_DATA0_VI0_B0, SEL_VI0_0),
 	PINMUX_IPSR_DATA(IP7_30_29, ATACS10_N),
 	PINMUX_IPSR_DATA(IP7_30_29, AVB_RXD2),
-	PINMUX_IPSR_DATA(IP7_30_29, MII_RXD2),
 
 	PINMUX_IPSR_MODSEL_DATA(IP8_1_0, VI0_DATA1_VI0_B1, SEL_VI0_0),
 	PINMUX_IPSR_DATA(IP8_1_0, ATARD0_N),
 	PINMUX_IPSR_DATA(IP8_1_0, AVB_RXD3),
-	PINMUX_IPSR_DATA(IP8_1_0, MII_RXD3),
 	PINMUX_IPSR_MODSEL_DATA(IP8_3_2, VI0_DATA2_VI0_B2, SEL_VI0_0),
 	PINMUX_IPSR_DATA(IP8_3_2, ATAWR0_N),
 	PINMUX_IPSR_DATA(IP8_3_2, AVB_RXD4),
@@ -1318,34 +1241,27 @@
 	PINMUX_IPSR_DATA(IP8_9_8, AVB_RXD7),
 	PINMUX_IPSR_MODSEL_DATA(IP8_11_10, VI0_DATA6_VI0_B6, SEL_VI0_0),
 	PINMUX_IPSR_DATA(IP8_11_10, AVB_RX_ER),
-	PINMUX_IPSR_DATA(IP8_11_10, MII_RX_ER),
 	PINMUX_IPSR_MODSEL_DATA(IP8_13_12, VI0_DATA7_VI0_B7, SEL_VI0_0),
 	PINMUX_IPSR_DATA(IP8_13_12, AVB_RX_CLK),
-	PINMUX_IPSR_DATA(IP8_13_12, MII_RX_CLK),
 	PINMUX_IPSR_MODSEL_DATA(IP8_15_14, VI1_CLK, SEL_VI1_0),
 	PINMUX_IPSR_DATA(IP8_15_14, AVB_RX_DV),
-	PINMUX_IPSR_DATA(IP8_15_14, MII_RX_DV),
 	PINMUX_IPSR_MODSEL_DATA(IP8_17_16, VI1_DATA0_VI1_B0, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP8_17_16, SCIFA1_SCK_D, SEL_SCIFA1_3),
 	PINMUX_IPSR_DATA(IP8_17_16, AVB_CRS),
-	PINMUX_IPSR_DATA(IP8_17_16, MII_CRS),
 	PINMUX_IPSR_MODSEL_DATA(IP8_19_18, VI1_DATA1_VI1_B1, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP8_19_18, SCIFA1_RXD_D, SEL_SCIFA1_3),
 	PINMUX_IPSR_DATA(IP8_19_18, AVB_MDC),
-	PINMUX_IPSR_DATA(IP8_19_18, MII_MDC),
 	PINMUX_IPSR_MODSEL_DATA(IP8_21_20, VI1_DATA2_VI1_B2, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP8_21_20, SCIFA1_TXD_D, SEL_SCIFA1_3),
 	PINMUX_IPSR_DATA(IP8_21_20, AVB_MDIO),
-	PINMUX_IPSR_DATA(IP8_21_20, MII_MDIO),
 	PINMUX_IPSR_MODSEL_DATA(IP8_23_22, VI1_DATA3_VI1_B3, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP8_23_22, SCIFA1_CTS_N_D, SEL_SCIFA1_3),
 	PINMUX_IPSR_DATA(IP8_23_22, AVB_GTX_CLK),
 	PINMUX_IPSR_MODSEL_DATA(IP8_25_24, VI1_DATA4_VI1_B4, SEL_VI1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP8_25_24, SCIFA1_RTS_N_D, SEL_SCIFA1_3),
 	PINMUX_IPSR_DATA(IP8_25_24, AVB_MAGIC),
-	PINMUX_IPSR_DATA(IP8_25_24, MII_MAGIC),
 	PINMUX_IPSR_MODSEL_DATA(IP8_26, VI1_DATA5_VI1_B5, SEL_VI1_0),
-	PINMUX_IPSR_MODSEL_DATA(IP8_26, AVB_PHY_INT, SEL_SCIFA1_3),
+	PINMUX_IPSR_DATA(IP8_26, AVB_PHY_INT),
 	PINMUX_IPSR_MODSEL_DATA(IP8_27, VI1_DATA6_VI1_B6, SEL_VI1_0),
 	PINMUX_IPSR_DATA(IP8_27, AVB_GTXREFCLK),
 	PINMUX_IPSR_DATA(IP8_28, SD0_CLK),
@@ -1372,8 +1288,8 @@
 	PINMUX_IPSR_DATA(IP9_11_8, USB0_EXTP),
 	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, GLO_SCLK, SEL_GPS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, VI1_DATA6_VI1_B6_B, SEL_VI1_1),
-	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, SCL1_B, SEL_IIC1_1),
-	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, SCL1_CIS_B, SEL_I2C1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, IIC1_SCL_B, SEL_IIC1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, I2C1_SCL_B, SEL_I2C1_1),
 	PINMUX_IPSR_MODSEL_DATA(IP9_11_8, VI2_DATA6_VI2_B6_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP9_15_12, SD0_WP),
 	PINMUX_IPSR_DATA(IP9_15_12, MMC0_D7),
@@ -1381,31 +1297,25 @@
 	PINMUX_IPSR_DATA(IP9_15_12, USB0_IDIN),
 	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, GLO_SDATA, SEL_GPS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, VI1_DATA7_VI1_B7_B, SEL_VI1_1),
-	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, SDA1_B, SEL_IIC1_1),
-	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, SDA1_CIS_B, SEL_I2C1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, IIC1_SDA_B, SEL_IIC1_1),
+	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, I2C1_SDA_B, SEL_I2C1_1),
 	PINMUX_IPSR_MODSEL_DATA(IP9_15_12, VI2_DATA7_VI2_B7_B, SEL_VI2_1),
 	PINMUX_IPSR_DATA(IP9_17_16, SD1_CLK),
 	PINMUX_IPSR_DATA(IP9_17_16, AVB_TX_EN),
-	PINMUX_IPSR_DATA(IP9_17_16, MII_TX_EN),
 	PINMUX_IPSR_DATA(IP9_19_18, SD1_CMD),
 	PINMUX_IPSR_DATA(IP9_19_18, AVB_TX_ER),
-	PINMUX_IPSR_DATA(IP9_19_18, MII_TX_ER),
 	PINMUX_IPSR_MODSEL_DATA(IP9_19_18, SCIFB0_SCK_B, SEL_SCIFB_1),
 	PINMUX_IPSR_DATA(IP9_21_20, SD1_DAT0),
 	PINMUX_IPSR_DATA(IP9_21_20, AVB_TX_CLK),
-	PINMUX_IPSR_DATA(IP9_21_20, MII_TX_CLK),
 	PINMUX_IPSR_MODSEL_DATA(IP9_21_20, SCIFB0_RXD_B, SEL_SCIFB_1),
 	PINMUX_IPSR_DATA(IP9_23_22, SD1_DAT1),
 	PINMUX_IPSR_DATA(IP9_23_22, AVB_LINK),
-	PINMUX_IPSR_DATA(IP9_23_22, MII_LINK),
 	PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SCIFB0_TXD_B, SEL_SCIFB_1),
 	PINMUX_IPSR_DATA(IP9_25_24, SD1_DAT2),
 	PINMUX_IPSR_DATA(IP9_25_24, AVB_COL),
-	PINMUX_IPSR_DATA(IP9_25_24, MII_COL),
 	PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SCIFB0_CTS_N_B, SEL_SCIFB_1),
 	PINMUX_IPSR_DATA(IP9_27_26, SD1_DAT3),
 	PINMUX_IPSR_DATA(IP9_27_26, AVB_RXD0),
-	PINMUX_IPSR_DATA(IP9_27_26, MII_RXD0),
 	PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SCIFB0_RTS_N_B, SEL_SCIFB_1),
 	PINMUX_IPSR_DATA(IP9_31_28, SD1_CD),
 	PINMUX_IPSR_DATA(IP9_31_28, MMC1_D6),
@@ -1413,8 +1323,8 @@
 	PINMUX_IPSR_DATA(IP9_31_28, USB1_EXTP),
 	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, GLO_SS, SEL_GPS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, VI0_CLK_B, SEL_VI0_1),
-	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, SCL2_D, SEL_IIC2_3),
-	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, SCL2_CIS_D, SEL_I2C2_3),
+	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, IIC2_SCL_D, SEL_IIC2_3),
+	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, I2C2_SCL_D, SEL_I2C2_3),
 	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, SIM0_CLK_B, SEL_SIM_1),
 	PINMUX_IPSR_MODSEL_DATA(IP9_31_28, VI3_CLK_B, SEL_VI3_1),
 
@@ -1424,8 +1334,8 @@
 	PINMUX_IPSR_DATA(IP10_3_0, USB1_IDIN),
 	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, GLO_RFON, SEL_GPS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, VI1_CLK_B, SEL_VI1_1),
-	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, SDA2_D, SEL_IIC2_3),
-	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, SDA2_CIS_D, SEL_I2C2_3),
+	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, IIC2_SDA_D, SEL_IIC2_3),
+	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, I2C2_SDA_D, SEL_I2C2_3),
 	PINMUX_IPSR_MODSEL_DATA(IP10_3_0, SIM0_D_B, SEL_SIM_1),
 	PINMUX_IPSR_DATA(IP10_6_4, SD2_CLK),
 	PINMUX_IPSR_DATA(IP10_6_4, MMC0_CLK),
@@ -1455,7 +1365,6 @@
 	PINMUX_IPSR_DATA(IP10_18_15, SD2_DAT1),
 	PINMUX_IPSR_DATA(IP10_18_15, MMC0_D1),
 	PINMUX_IPSR_MODSEL_DATA(IP10_18_15, FMIN_B, SEL_FM_1),
-	PINMUX_IPSR_MODSEL_DATA(IP10_18_15, RDS_DATA, SEL_RDS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP10_18_15, VI0_DATA3_VI0_B3_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP10_18_15, SCIFB1_TXD_E, SEL_SCIFB1_4),
 	PINMUX_IPSR_MODSEL_DATA(IP10_18_15, TX1_D, SEL_SCIF1_3),
@@ -1465,7 +1374,6 @@
 	PINMUX_IPSR_DATA(IP10_22_19, SD2_DAT2),
 	PINMUX_IPSR_DATA(IP10_22_19, MMC0_D2),
 	PINMUX_IPSR_MODSEL_DATA(IP10_22_19, BPFCLK_B, SEL_FM_1),
-	PINMUX_IPSR_MODSEL_DATA(IP10_22_19, RDS_CLK, SEL_RDS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP10_22_19, VI0_DATA4_VI0_B4_B, SEL_VI0_1),
 	PINMUX_IPSR_MODSEL_DATA(IP10_22_19, HRX0_D, SEL_HSCIF0_3),
 	PINMUX_IPSR_MODSEL_DATA(IP10_22_19, TS_SDEN1_B, SEL_TSIF1_1),
@@ -1528,25 +1436,20 @@
 	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, TS_SCK1, SEL_TSIF1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, GLO_Q1, SEL_GPS_0),
 	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, FMIN_C, SEL_FM_2),
-	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, RDS_DATA_B, SEL_RDS_1),
 	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, FMIN_E, SEL_FM_4),
-	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, RDS_DATA_D, SEL_RDS_3),
 	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, FMIN_F, SEL_FM_5),
-	PINMUX_IPSR_MODSEL_DATA(IP11_21_18, RDS_DATA_E, SEL_RDS_4),
 	PINMUX_IPSR_DATA(IP11_23_22, MLB_CLK),
-	PINMUX_IPSR_MODSEL_DATA(IP11_23_22, SCL2_B, SEL_IIC2_1),
-	PINMUX_IPSR_MODSEL_DATA(IP11_23_22, SCL2_CIS_B, SEL_I2C2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_23_22, IIC2_SCL_B, SEL_IIC2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_23_22, I2C2_SCL_B, SEL_I2C2_1),
 	PINMUX_IPSR_DATA(IP11_26_24, MLB_SIG),
 	PINMUX_IPSR_MODSEL_DATA(IP11_26_24, SCIFB1_RXD_D, SEL_SCIFB1_3),
 	PINMUX_IPSR_MODSEL_DATA(IP11_26_24, RX1_C, SEL_SCIF1_2),
-	PINMUX_IPSR_MODSEL_DATA(IP11_26_24, SDA2_B, SEL_IIC2_1),
-	PINMUX_IPSR_MODSEL_DATA(IP11_26_24, SDA2_CIS_B, SEL_I2C2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_26_24, IIC2_SDA_B, SEL_IIC2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP11_26_24, I2C2_SDA_B, SEL_I2C2_1),
 	PINMUX_IPSR_DATA(IP11_29_27, MLB_DAT),
-	PINMUX_IPSR_DATA(IP11_29_27, SPV_EVEN),
 	PINMUX_IPSR_MODSEL_DATA(IP11_29_27, SCIFB1_TXD_D, SEL_SCIFB1_3),
 	PINMUX_IPSR_MODSEL_DATA(IP11_29_27, TX1_C, SEL_SCIF1_2),
 	PINMUX_IPSR_MODSEL_DATA(IP11_29_27, BPFCLK_C, SEL_FM_2),
-	PINMUX_IPSR_MODSEL_DATA(IP11_29_27, RDS_CLK_B, SEL_RDS_1),
 	PINMUX_IPSR_DATA(IP11_31_30, SSI_SCK0129),
 	PINMUX_IPSR_MODSEL_DATA(IP11_31_30, CAN_CLK_B, SEL_CANCLK_1),
 	PINMUX_IPSR_DATA(IP11_31_30, MOUT0),
@@ -1562,7 +1465,7 @@
 	PINMUX_IPSR_DATA(IP12_5_4, MOUT5),
 	PINMUX_IPSR_DATA(IP12_7_6, SSI_SDATA2),
 	PINMUX_IPSR_MODSEL_DATA(IP12_7_6, CAN1_RX_B, SEL_CAN1_1),
-	PINMUX_IPSR_MODSEL_DATA(IP12_7_6, CAN1_TX_B, SEL_CAN1_1),
+	PINMUX_IPSR_DATA(IP12_7_6, SSI_SCK1),
 	PINMUX_IPSR_DATA(IP12_7_6, MOUT6),
 	PINMUX_IPSR_DATA(IP12_10_8, SSI_SCK34),
 	PINMUX_IPSR_DATA(IP12_10_8, STP_OPWM_0),
@@ -1617,12 +1520,10 @@
 	PINMUX_IPSR_MODSEL_DATA(IP13_6_3, SSI_SCK6, SEL_SSI6_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_6_3, SCIFB1_CTS_N, SEL_SCIFB1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_6_3, BPFCLK_D, SEL_FM_3),
-	PINMUX_IPSR_MODSEL_DATA(IP13_6_3, RDS_CLK_C, SEL_RDS_2),
 	PINMUX_IPSR_DATA(IP13_6_3, DU2_DR3),
 	PINMUX_IPSR_DATA(IP13_6_3, LCDOUT3),
 	PINMUX_IPSR_DATA(IP13_6_3, CAN_DEBUGOUT6),
 	PINMUX_IPSR_MODSEL_DATA(IP13_6_3, BPFCLK_F, SEL_FM_5),
-	PINMUX_IPSR_MODSEL_DATA(IP13_6_3, RDS_CLK_E, SEL_RDS_4),
 	PINMUX_IPSR_MODSEL_DATA(IP13_9_7, SSI_WS6, SEL_SSI6_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_9_7, SCIFB1_RTS_N, SEL_SCIFB1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_9_7, CAN0_TX_D, SEL_CAN0_3),
@@ -1631,7 +1532,6 @@
 	PINMUX_IPSR_DATA(IP13_9_7, CAN_DEBUGOUT7),
 	PINMUX_IPSR_MODSEL_DATA(IP13_12_10, SSI_SDATA6, SEL_SSI6_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_12_10, FMIN_D, SEL_FM_3),
-	PINMUX_IPSR_MODSEL_DATA(IP13_12_10, RDS_DATA_C, SEL_RDS_2),
 	PINMUX_IPSR_DATA(IP13_12_10, DU2_DR5),
 	PINMUX_IPSR_DATA(IP13_12_10, LCDOUT5),
 	PINMUX_IPSR_DATA(IP13_12_10, CAN_DEBUGOUT8),
@@ -1657,10 +1557,8 @@
 	PINMUX_IPSR_DATA(IP13_22_19, QSTVA_QVS),
 	PINMUX_IPSR_DATA(IP13_22_19, CAN_DEBUGOUT11),
 	PINMUX_IPSR_MODSEL_DATA(IP13_22_19, BPFCLK_E, SEL_FM_4),
-	PINMUX_IPSR_MODSEL_DATA(IP13_22_19, RDS_CLK_D, SEL_RDS_3),
 	PINMUX_IPSR_MODSEL_DATA(IP13_22_19, SSI_SDATA7_B, SEL_SSI7_1),
 	PINMUX_IPSR_MODSEL_DATA(IP13_22_19, FMIN_G, SEL_FM_6),
-	PINMUX_IPSR_MODSEL_DATA(IP13_22_19, RDS_DATA_F, SEL_RDS_5),
 	PINMUX_IPSR_MODSEL_DATA(IP13_25_23, SSI_SDATA8, SEL_SSI8_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_25_23, STP_ISEN_1, SEL_SSP_0),
 	PINMUX_IPSR_MODSEL_DATA(IP13_25_23, SCIFB2_TXD, SEL_SCIFB2_0),
@@ -1690,8 +1588,8 @@
 	PINMUX_IPSR_DATA(IP14_5_3, MSIOF3_SS2),
 	PINMUX_IPSR_DATA(IP14_5_3, DU2_DG2),
 	PINMUX_IPSR_DATA(IP14_5_3, LCDOUT10),
-	PINMUX_IPSR_MODSEL_DATA(IP14_5_3, SDA1_C, SEL_IIC1_2),
-	PINMUX_IPSR_MODSEL_DATA(IP14_5_3, SDA1_CIS_C, SEL_I2C1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP14_5_3, IIC1_SDA_C, SEL_IIC1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP14_5_3, I2C1_SDA_C, SEL_I2C1_2),
 	PINMUX_IPSR_MODSEL_DATA(IP14_8_6, SCIFA0_RXD, SEL_SCFA_0),
 	PINMUX_IPSR_MODSEL_DATA(IP14_8_6, HRX1, SEL_HSCIF1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP14_8_6, RX0, SEL_SCIF0_0),
@@ -1704,16 +1602,16 @@
 	PINMUX_IPSR_DATA(IP14_11_9, LCDOUT1),
 	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, SCIFA0_CTS_N, SEL_SCFA_0),
 	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, HCTS1_N, SEL_HSCIF1_0),
-	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, CTS0_N, SEL_SCIF0_0),
+	PINMUX_IPSR_DATA(IP14_15_12, CTS0_N),
 	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, MSIOF3_SYNC, SEL_SOF3_0),
 	PINMUX_IPSR_DATA(IP14_15_12, DU2_DG3),
-	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, LCDOUT11, SEL_HSCIF1_0),
-	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, PWM0_B, SEL_SCIF0_0),
-	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, SCL1_C, SEL_IIC1_2),
-	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, SCL1_CIS_C, SEL_I2C1_2),
+	PINMUX_IPSR_DATA(IP14_15_12, LCDOUT11),
+	PINMUX_IPSR_DATA(IP14_15_12, PWM0_B),
+	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, IIC1_SCL_C, SEL_IIC1_2),
+	PINMUX_IPSR_MODSEL_DATA(IP14_15_12, I2C1_SCL_C, SEL_I2C1_2),
 	PINMUX_IPSR_MODSEL_DATA(IP14_18_16, SCIFA0_RTS_N, SEL_SCFA_0),
 	PINMUX_IPSR_MODSEL_DATA(IP14_18_16, HRTS1_N, SEL_HSCIF1_0),
-	PINMUX_IPSR_DATA(IP14_18_16, RTS0_N_TANS),
+	PINMUX_IPSR_DATA(IP14_18_16, RTS0_N),
 	PINMUX_IPSR_DATA(IP14_18_16, MSIOF3_SS1),
 	PINMUX_IPSR_DATA(IP14_18_16, DU2_DG0),
 	PINMUX_IPSR_DATA(IP14_18_16, LCDOUT8),
@@ -1736,7 +1634,7 @@
 	PINMUX_IPSR_DATA(IP14_27_25, QCLK),
 	PINMUX_IPSR_MODSEL_DATA(IP14_30_28, SCIFA1_RTS_N, SEL_SCIFA1_0),
 	PINMUX_IPSR_MODSEL_DATA(IP14_30_28, AD_NCS_N, SEL_ADI_0),
-	PINMUX_IPSR_DATA(IP14_30_28, RTS1_N_TANS),
+	PINMUX_IPSR_DATA(IP14_30_28, RTS1_N),
 	PINMUX_IPSR_MODSEL_DATA(IP14_30_28, MSIOF3_TXD, SEL_SOF3_0),
 	PINMUX_IPSR_DATA(IP14_30_28, DU1_DOTCLKOUT),
 	PINMUX_IPSR_DATA(IP14_30_28, QSTVB_QVE),
@@ -1744,28 +1642,30 @@
 
 	PINMUX_IPSR_MODSEL_DATA(IP15_2_0, SCIFA2_SCK, SEL_SCIFA2_0),
 	PINMUX_IPSR_MODSEL_DATA(IP15_2_0, FMCLK, SEL_FM_0),
+	PINMUX_IPSR_DATA(IP15_2_0, SCK2),
 	PINMUX_IPSR_MODSEL_DATA(IP15_2_0, MSIOF3_SCK, SEL_SOF3_0),
 	PINMUX_IPSR_DATA(IP15_2_0, DU2_DG7),
 	PINMUX_IPSR_DATA(IP15_2_0, LCDOUT15),
-	PINMUX_IPSR_MODSEL_DATA(IP15_2_0, SCIF_CLK_B, SEL_SCIFCLK_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_2_0, SCIF_CLK_B, SEL_SCIFCLK_1),
 	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, SCIFA2_RXD, SEL_SCIFA2_0),
 	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, FMIN, SEL_FM_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, TX2, SEL_SCIF2_0),
 	PINMUX_IPSR_DATA(IP15_5_3, DU2_DB0),
 	PINMUX_IPSR_DATA(IP15_5_3, LCDOUT16),
-	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, SCL2, SEL_IIC2_0),
-	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, SCL2_CIS, SEL_I2C2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, IIC2_SCL, SEL_IIC2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_5_3, I2C2_SCL, SEL_I2C2_0),
 	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, SCIFA2_TXD, SEL_SCIFA2_0),
 	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, BPFCLK, SEL_FM_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, RX2, SEL_SCIF2_0),
 	PINMUX_IPSR_DATA(IP15_8_6, DU2_DB1),
 	PINMUX_IPSR_DATA(IP15_8_6, LCDOUT17),
-	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, SDA2, SEL_IIC2_0),
-	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, SDA2_CIS, SEL_I2C2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, IIC2_SDA, SEL_IIC2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_8_6, I2C2_SDA, SEL_I2C2_0),
 	PINMUX_IPSR_DATA(IP15_11_9, HSCK0),
 	PINMUX_IPSR_MODSEL_DATA(IP15_11_9, TS_SDEN0, SEL_TSIF0_0),
 	PINMUX_IPSR_DATA(IP15_11_9, DU2_DG4),
 	PINMUX_IPSR_DATA(IP15_11_9, LCDOUT12),
-	PINMUX_IPSR_MODSEL_DATA(IP15_11_9, HCTS0_N_C, SEL_IIC2_0),
-	PINMUX_IPSR_MODSEL_DATA(IP15_11_9, SDA2_CIS, SEL_I2C2_0),
+	PINMUX_IPSR_MODSEL_DATA(IP15_11_9, HCTS0_N_C, SEL_HSCIF0_2),
 	PINMUX_IPSR_MODSEL_DATA(IP15_13_12, HRX0, SEL_HSCIF0_0),
 	PINMUX_IPSR_DATA(IP15_13_12, DU2_DB2),
 	PINMUX_IPSR_DATA(IP15_13_12, LCDOUT18),
@@ -1791,7 +1691,7 @@
 	PINMUX_IPSR_DATA(IP15_25_23, ADIDATA),
 	PINMUX_IPSR_DATA(IP15_25_23, DU2_DB7),
 	PINMUX_IPSR_DATA(IP15_25_23, LCDOUT23),
-	PINMUX_IPSR_MODSEL_DATA(IP15_25_23, SCIFA2_RXD_B, SEL_SCIFA2_1),
+	PINMUX_IPSR_MODSEL_DATA(IP15_25_23, HRX0_C, SEL_SCIFA2_1),
 	PINMUX_IPSR_MODSEL_DATA(IP15_27_26, MSIOF0_SS1, SEL_SOF0_0),
 	PINMUX_IPSR_DATA(IP15_27_26, ADICHS0),
 	PINMUX_IPSR_DATA(IP15_27_26, DU2_DG5),
@@ -1814,7 +1714,7 @@
 	PINMUX_IPSR_DATA(IP16_5_3, ADICS_SAMP),
 	PINMUX_IPSR_DATA(IP16_5_3, DU2_CDE),
 	PINMUX_IPSR_DATA(IP16_5_3, QPOLB),
-	PINMUX_IPSR_MODSEL_DATA(IP16_5_3, HRX0_C, SEL_HSCIF0_2),
+	PINMUX_IPSR_MODSEL_DATA(IP16_5_3, SCIFA2_RXD_B, SEL_HSCIF0_2),
 	PINMUX_IPSR_DATA(IP16_6, USB1_PWEN),
 	PINMUX_IPSR_DATA(IP16_6, AUDIO_CLKOUT_D),
 	PINMUX_IPSR_DATA(IP16_7, USB1_OVC),
@@ -1825,6 +1725,104 @@
 	PINMUX_GPIO_GP_ALL(),
 };
 
+/* - DU RGB ----------------------------------------------------------------- */
+static const unsigned int du_rgb666_pins[] = {
+	/* R[7:2], G[7:2], B[7:2] */
+	RCAR_GP_PIN(4, 21), RCAR_GP_PIN(4, 20), RCAR_GP_PIN(4, 19),
+	RCAR_GP_PIN(4, 18), RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 16),
+	RCAR_GP_PIN(5, 4),  RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 14),
+	RCAR_GP_PIN(5, 7),  RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 27),
+	RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 11),
+	RCAR_GP_PIN(5, 10), RCAR_GP_PIN(5, 9),  RCAR_GP_PIN(5, 8),
+};
+static const unsigned int du_rgb666_mux[] = {
+	DU2_DR7_MARK, DU2_DR6_MARK, DU2_DR5_MARK, DU2_DR4_MARK,
+	DU2_DR3_MARK, DU2_DR2_MARK,
+	DU2_DG7_MARK, DU2_DG6_MARK, DU2_DG5_MARK, DU2_DG4_MARK,
+	DU2_DG3_MARK, DU2_DG2_MARK,
+	DU2_DB7_MARK, DU2_DB6_MARK, DU2_DB5_MARK, DU2_DB4_MARK,
+	DU2_DB3_MARK, DU2_DB2_MARK,
+};
+static const unsigned int du_rgb888_pins[] = {
+	/* R[7:0], G[7:0], B[7:0] */
+	RCAR_GP_PIN(4, 21), RCAR_GP_PIN(4, 20), RCAR_GP_PIN(4, 19),
+	RCAR_GP_PIN(4, 18), RCAR_GP_PIN(4, 17), RCAR_GP_PIN(4, 16),
+	RCAR_GP_PIN(4, 29), RCAR_GP_PIN(4, 28), RCAR_GP_PIN(5, 4),
+	RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 14), RCAR_GP_PIN(5, 7),
+	RCAR_GP_PIN(4, 30), RCAR_GP_PIN(4, 27), RCAR_GP_PIN(5, 1),
+	RCAR_GP_PIN(4, 31), RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 12),
+	RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 10), RCAR_GP_PIN(5, 9),
+	RCAR_GP_PIN(5, 8),  RCAR_GP_PIN(5, 6),  RCAR_GP_PIN(5, 5),
+};
+static const unsigned int du_rgb888_mux[] = {
+	DU2_DR7_MARK, DU2_DR6_MARK, DU2_DR5_MARK, DU2_DR4_MARK,
+	DU2_DR3_MARK, DU2_DR2_MARK, DU2_DR1_MARK, DU2_DR0_MARK,
+	DU2_DG7_MARK, DU2_DG6_MARK, DU2_DG5_MARK, DU2_DG4_MARK,
+	DU2_DG3_MARK, DU2_DG2_MARK, DU2_DG1_MARK, DU2_DG0_MARK,
+	DU2_DB7_MARK, DU2_DB6_MARK, DU2_DB5_MARK, DU2_DB4_MARK,
+	DU2_DB3_MARK, DU2_DB2_MARK, DU2_DB1_MARK, DU2_DB0_MARK,
+};
+static const unsigned int du_clk_out_0_pins[] = {
+	/* CLKOUT */
+	RCAR_GP_PIN(5, 2),
+};
+static const unsigned int du_clk_out_0_mux[] = {
+	DU0_DOTCLKOUT_MARK
+};
+static const unsigned int du_clk_out_1_pins[] = {
+	/* CLKOUT */
+	RCAR_GP_PIN(5, 3),
+};
+static const unsigned int du_clk_out_1_mux[] = {
+	DU1_DOTCLKOUT_MARK
+};
+static const unsigned int du_sync_0_pins[] = {
+	/* VSYNC, HSYNC, DISP */
+	RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 14), RCAR_GP_PIN(5, 0),
+};
+static const unsigned int du_sync_0_mux[] = {
+	DU2_EXVSYNC_DU2_VSYNC_MARK, DU2_EXHSYNC_DU2_HSYNC_MARK,
+	DU2_EXODDF_DU2_ODDF_DISP_CDE_MARK
+};
+static const unsigned int du_sync_1_pins[] = {
+	/* VSYNC, HSYNC, DISP */
+	RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 14), RCAR_GP_PIN(5, 16),
+};
+static const unsigned int du_sync_1_mux[] = {
+	DU2_EXVSYNC_DU2_VSYNC_MARK, DU2_EXHSYNC_DU2_HSYNC_MARK,
+	DU2_DISP_MARK
+};
+static const unsigned int du_cde_pins[] = {
+	/* CDE */
+	RCAR_GP_PIN(5, 17),
+};
+static const unsigned int du_cde_mux[] = {
+	DU2_CDE_MARK,
+};
+/* - DU0 -------------------------------------------------------------------- */
+static const unsigned int du0_clk_in_pins[] = {
+	/* CLKIN */
+	RCAR_GP_PIN(5, 26),
+};
+static const unsigned int du0_clk_in_mux[] = {
+	DU_DOTCLKIN0_MARK
+};
+/* - DU1 -------------------------------------------------------------------- */
+static const unsigned int du1_clk_in_pins[] = {
+	/* CLKIN */
+	RCAR_GP_PIN(5, 27),
+};
+static const unsigned int du1_clk_in_mux[] = {
+	DU_DOTCLKIN1_MARK,
+};
+/* - DU2 -------------------------------------------------------------------- */
+static const unsigned int du2_clk_in_pins[] = {
+	/* CLKIN */
+	RCAR_GP_PIN(5, 28),
+};
+static const unsigned int du2_clk_in_mux[] = {
+	DU_DOTCLKIN2_MARK,
+};
 /* - ETH -------------------------------------------------------------------- */
 static const unsigned int eth_link_pins[] = {
 	/* LINK */
@@ -1857,128 +1855,6 @@
 	ETH_RXD0_MARK, ETH_RXD1_MARK, ETH_RX_ER_MARK, ETH_CRS_DV_MARK,
 	ETH_TXD0_MARK, ETH_TXD1_MARK, ETH_TX_EN_MARK, ETH_REF_CLK_MARK,
 };
-/* - INTC ------------------------------------------------------------------- */
-static const unsigned int intc_irq0_pins[] = {
-	/* IRQ */
-	RCAR_GP_PIN(1, 25),
-};
-static const unsigned int intc_irq0_mux[] = {
-	IRQ0_MARK,
-};
-static const unsigned int intc_irq1_pins[] = {
-	/* IRQ */
-	RCAR_GP_PIN(1, 27),
-};
-static const unsigned int intc_irq1_mux[] = {
-	IRQ1_MARK,
-};
-static const unsigned int intc_irq2_pins[] = {
-	/* IRQ */
-	RCAR_GP_PIN(1, 29),
-};
-static const unsigned int intc_irq2_mux[] = {
-	IRQ2_MARK,
-};
-static const unsigned int intc_irq3_pins[] = {
-	/* IRQ */
-	RCAR_GP_PIN(1, 23),
-};
-static const unsigned int intc_irq3_mux[] = {
-	IRQ3_MARK,
-};
-/* - SCIF0 ----------------------------------------------------------------- */
-static const unsigned int scif0_data_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 29),
-};
-static const unsigned int scif0_data_mux[] = {
-	RX0_MARK, TX0_MARK,
-};
-static const unsigned int scif0_clk_pins[] = {
-	/* SCK */
-	RCAR_GP_PIN(4, 27),
-};
-static const unsigned int scif0_clk_mux[] = {
-	SCK0_MARK,
-};
-static const unsigned int scif0_ctrl_pins[] = {
-	/* RTS, CTS */
-	RCAR_GP_PIN(4, 31), RCAR_GP_PIN(4, 30),
-};
-static const unsigned int scif0_ctrl_mux[] = {
-	RTS0_N_TANS_MARK, CTS0_N_MARK,
-};
-static const unsigned int scif0_data_b_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
-};
-static const unsigned int scif0_data_b_mux[] = {
-	RX0_B_MARK, TX0_B_MARK,
-};
-/* - SCIF1 ----------------------------------------------------------------- */
-static const unsigned int scif1_data_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 1),
-};
-static const unsigned int scif1_data_mux[] = {
-	RX1_MARK, TX1_MARK,
-};
-static const unsigned int scif1_clk_pins[] = {
-	/* SCK */
-	RCAR_GP_PIN(4, 20),
-};
-static const unsigned int scif1_clk_mux[] = {
-	SCK1_MARK,
-};
-static const unsigned int scif1_ctrl_pins[] = {
-	/* RTS, CTS */
-	RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 2),
-};
-static const unsigned int scif1_ctrl_mux[] = {
-	RTS1_N_TANS_MARK, CTS1_N_MARK,
-};
-static const unsigned int scif1_data_b_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
-};
-static const unsigned int scif1_data_b_mux[] = {
-	RX1_B_MARK, TX1_B_MARK,
-};
-static const unsigned int scif1_data_c_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 2),
-};
-static const unsigned int scif1_data_c_mux[] = {
-	RX1_C_MARK, TX1_C_MARK,
-};
-static const unsigned int scif1_data_d_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
-};
-static const unsigned int scif1_data_d_mux[] = {
-	RX1_D_MARK, TX1_D_MARK,
-};
-static const unsigned int scif1_clk_d_pins[] = {
-	/* SCK */
-	RCAR_GP_PIN(3, 17),
-};
-static const unsigned int scif1_clk_d_mux[] = {
-	SCK1_D_MARK,
-};
-static const unsigned int scif1_data_e_pins[] = {
-	/* RX, TX */
-	RCAR_GP_PIN(2, 21), RCAR_GP_PIN(2, 22),
-};
-static const unsigned int scif1_data_e_mux[] = {
-	RX1_E_MARK, TX1_E_MARK,
-};
-static const unsigned int scif1_clk_e_pins[] = {
-	/* SCK */
-	RCAR_GP_PIN(2, 20),
-};
-static const unsigned int scif1_clk_e_mux[] = {
-	SCK1_E_MARK,
-};
 /* - HSCIF0 ----------------------------------------------------------------- */
 static const unsigned int hscif0_data_pins[] = {
 	/* RX, TX */
@@ -2114,6 +1990,390 @@
 static const unsigned int hscif1_ctrl_b_mux[] = {
 	HRTS1_N_B_MARK, HCTS1_N_B_MARK,
 };
+/* - INTC ------------------------------------------------------------------- */
+static const unsigned int intc_irq0_pins[] = {
+	/* IRQ */
+	RCAR_GP_PIN(1, 25),
+};
+static const unsigned int intc_irq0_mux[] = {
+	IRQ0_MARK,
+};
+static const unsigned int intc_irq1_pins[] = {
+	/* IRQ */
+	RCAR_GP_PIN(1, 27),
+};
+static const unsigned int intc_irq1_mux[] = {
+	IRQ1_MARK,
+};
+static const unsigned int intc_irq2_pins[] = {
+	/* IRQ */
+	RCAR_GP_PIN(1, 29),
+};
+static const unsigned int intc_irq2_mux[] = {
+	IRQ2_MARK,
+};
+static const unsigned int intc_irq3_pins[] = {
+	/* IRQ */
+	RCAR_GP_PIN(1, 23),
+};
+static const unsigned int intc_irq3_mux[] = {
+	IRQ3_MARK,
+};
+/* - MMCIF0 ----------------------------------------------------------------- */
+static const unsigned int mmc0_data1_pins[] = {
+	/* D[0] */
+	RCAR_GP_PIN(3, 18),
+};
+static const unsigned int mmc0_data1_mux[] = {
+	MMC0_D0_MARK,
+};
+static const unsigned int mmc0_data4_pins[] = {
+	/* D[0:3] */
+	RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
+	RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 21),
+};
+static const unsigned int mmc0_data4_mux[] = {
+	MMC0_D0_MARK, MMC0_D1_MARK, MMC0_D2_MARK, MMC0_D3_MARK,
+};
+static const unsigned int mmc0_data8_pins[] = {
+	/* D[0:7] */
+	RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
+	RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 21),
+	RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 23),
+	RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7),
+};
+static const unsigned int mmc0_data8_mux[] = {
+	MMC0_D0_MARK, MMC0_D1_MARK, MMC0_D2_MARK, MMC0_D3_MARK,
+	MMC0_D4_MARK, MMC0_D5_MARK, MMC0_D6_MARK, MMC0_D7_MARK,
+};
+static const unsigned int mmc0_ctrl_pins[] = {
+	/* CLK, CMD */
+	RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 17),
+};
+static const unsigned int mmc0_ctrl_mux[] = {
+	MMC0_CLK_MARK, MMC0_CMD_MARK,
+};
+/* - MMCIF1 ----------------------------------------------------------------- */
+static const unsigned int mmc1_data1_pins[] = {
+	/* D[0] */
+	RCAR_GP_PIN(3, 26),
+};
+static const unsigned int mmc1_data1_mux[] = {
+	MMC1_D0_MARK,
+};
+static const unsigned int mmc1_data4_pins[] = {
+	/* D[0:3] */
+	RCAR_GP_PIN(3, 26), RCAR_GP_PIN(3, 27),
+	RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 29),
+};
+static const unsigned int mmc1_data4_mux[] = {
+	MMC1_D0_MARK, MMC1_D1_MARK, MMC1_D2_MARK, MMC1_D3_MARK,
+};
+static const unsigned int mmc1_data8_pins[] = {
+	/* D[0:7] */
+	RCAR_GP_PIN(3, 26), RCAR_GP_PIN(3, 27),
+	RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 29),
+	RCAR_GP_PIN(3, 30), RCAR_GP_PIN(3, 31),
+	RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15),
+};
+static const unsigned int mmc1_data8_mux[] = {
+	MMC1_D0_MARK, MMC1_D1_MARK, MMC1_D2_MARK, MMC1_D3_MARK,
+	MMC1_D4_MARK, MMC1_D5_MARK, MMC1_D6_MARK, MMC1_D7_MARK,
+};
+static const unsigned int mmc1_ctrl_pins[] = {
+	/* CLK, CMD */
+	RCAR_GP_PIN(3, 24), RCAR_GP_PIN(3, 25),
+};
+static const unsigned int mmc1_ctrl_mux[] = {
+	MMC1_CLK_MARK, MMC1_CMD_MARK,
+};
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(5, 12),
+};
+static const unsigned int msiof0_clk_mux[] = {
+	MSIOF0_SCK_MARK,
+};
+static const unsigned int msiof0_sync_pins[] = {
+	/* SYNC */
+	RCAR_GP_PIN(5, 13),
+};
+static const unsigned int msiof0_sync_mux[] = {
+	MSIOF0_SYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+	/* SS1 */
+	RCAR_GP_PIN(5, 14),
+};
+static const unsigned int msiof0_ss1_mux[] = {
+	MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+	/* SS2 */
+	RCAR_GP_PIN(5, 16),
+};
+static const unsigned int msiof0_ss2_mux[] = {
+	MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_rx_pins[] = {
+	/* RXD */
+	RCAR_GP_PIN(5, 17),
+};
+static const unsigned int msiof0_rx_mux[] = {
+	MSIOF0_RXD_MARK,
+};
+static const unsigned int msiof0_tx_pins[] = {
+	/* TXD */
+	RCAR_GP_PIN(5, 15),
+};
+static const unsigned int msiof0_tx_mux[] = {
+	MSIOF0_TXD_MARK,
+};
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(4, 8),
+};
+static const unsigned int msiof1_clk_mux[] = {
+	MSIOF1_SCK_MARK,
+};
+static const unsigned int msiof1_sync_pins[] = {
+	/* SYNC */
+	RCAR_GP_PIN(4, 9),
+};
+static const unsigned int msiof1_sync_mux[] = {
+	MSIOF1_SYNC_MARK,
+};
+static const unsigned int msiof1_ss1_pins[] = {
+	/* SS1 */
+	RCAR_GP_PIN(4, 10),
+};
+static const unsigned int msiof1_ss1_mux[] = {
+	MSIOF1_SS1_MARK,
+};
+static const unsigned int msiof1_ss2_pins[] = {
+	/* SS2 */
+	RCAR_GP_PIN(4, 11),
+};
+static const unsigned int msiof1_ss2_mux[] = {
+	MSIOF1_SS2_MARK,
+};
+static const unsigned int msiof1_rx_pins[] = {
+	/* RXD */
+	RCAR_GP_PIN(4, 13),
+};
+static const unsigned int msiof1_rx_mux[] = {
+	MSIOF1_RXD_MARK,
+};
+static const unsigned int msiof1_tx_pins[] = {
+	/* TXD */
+	RCAR_GP_PIN(4, 12),
+};
+static const unsigned int msiof1_tx_mux[] = {
+	MSIOF1_TXD_MARK,
+};
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(0, 27),
+};
+static const unsigned int msiof2_clk_mux[] = {
+	MSIOF2_SCK_MARK,
+};
+static const unsigned int msiof2_sync_pins[] = {
+	/* SYNC */
+	RCAR_GP_PIN(0, 26),
+};
+static const unsigned int msiof2_sync_mux[] = {
+	MSIOF2_SYNC_MARK,
+};
+static const unsigned int msiof2_ss1_pins[] = {
+	/* SS1 */
+	RCAR_GP_PIN(0, 30),
+};
+static const unsigned int msiof2_ss1_mux[] = {
+	MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss2_pins[] = {
+	/* SS2 */
+	RCAR_GP_PIN(0, 31),
+};
+static const unsigned int msiof2_ss2_mux[] = {
+	MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_rx_pins[] = {
+	/* RXD */
+	RCAR_GP_PIN(0, 29),
+};
+static const unsigned int msiof2_rx_mux[] = {
+	MSIOF2_RXD_MARK,
+};
+static const unsigned int msiof2_tx_pins[] = {
+	/* TXD */
+	RCAR_GP_PIN(0, 28),
+};
+static const unsigned int msiof2_tx_mux[] = {
+	MSIOF2_TXD_MARK,
+};
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(5, 4),
+};
+static const unsigned int msiof3_clk_mux[] = {
+	MSIOF3_SCK_MARK,
+};
+static const unsigned int msiof3_sync_pins[] = {
+	/* SYNC */
+	RCAR_GP_PIN(4, 30),
+};
+static const unsigned int msiof3_sync_mux[] = {
+	MSIOF3_SYNC_MARK,
+};
+static const unsigned int msiof3_ss1_pins[] = {
+	/* SS1 */
+	RCAR_GP_PIN(4, 31),
+};
+static const unsigned int msiof3_ss1_mux[] = {
+	MSIOF3_SS1_MARK,
+};
+static const unsigned int msiof3_ss2_pins[] = {
+	/* SS2 */
+	RCAR_GP_PIN(4, 27),
+};
+static const unsigned int msiof3_ss2_mux[] = {
+	MSIOF3_SS2_MARK,
+};
+static const unsigned int msiof3_rx_pins[] = {
+	/* RXD */
+	RCAR_GP_PIN(5, 2),
+};
+static const unsigned int msiof3_rx_mux[] = {
+	MSIOF3_RXD_MARK,
+};
+static const unsigned int msiof3_tx_pins[] = {
+	/* TXD */
+	RCAR_GP_PIN(5, 3),
+};
+static const unsigned int msiof3_tx_mux[] = {
+	MSIOF3_TXD_MARK,
+};
+/* - SCIF0 ------------------------------------------------------------------ */
+static const unsigned int scif0_data_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(4, 28), RCAR_GP_PIN(4, 29),
+};
+static const unsigned int scif0_data_mux[] = {
+	RX0_MARK, TX0_MARK,
+};
+static const unsigned int scif0_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(4, 27),
+};
+static const unsigned int scif0_clk_mux[] = {
+	SCK0_MARK,
+};
+static const unsigned int scif0_ctrl_pins[] = {
+	/* RTS, CTS */
+	RCAR_GP_PIN(4, 31), RCAR_GP_PIN(4, 30),
+};
+static const unsigned int scif0_ctrl_mux[] = {
+	RTS0_N_MARK, CTS0_N_MARK,
+};
+static const unsigned int scif0_data_b_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5),
+};
+static const unsigned int scif0_data_b_mux[] = {
+	RX0_B_MARK, TX0_B_MARK,
+};
+/* - SCIF1 ------------------------------------------------------------------ */
+static const unsigned int scif1_data_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 1),
+};
+static const unsigned int scif1_data_mux[] = {
+	RX1_MARK, TX1_MARK,
+};
+static const unsigned int scif1_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(4, 20),
+};
+static const unsigned int scif1_clk_mux[] = {
+	SCK1_MARK,
+};
+static const unsigned int scif1_ctrl_pins[] = {
+	/* RTS, CTS */
+	RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 2),
+};
+static const unsigned int scif1_ctrl_mux[] = {
+	RTS1_N_MARK, CTS1_N_MARK,
+};
+static const unsigned int scif1_data_b_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
+};
+static const unsigned int scif1_data_b_mux[] = {
+	RX1_B_MARK, TX1_B_MARK,
+};
+static const unsigned int scif1_data_c_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 2),
+};
+static const unsigned int scif1_data_c_mux[] = {
+	RX1_C_MARK, TX1_C_MARK,
+};
+static const unsigned int scif1_data_d_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
+};
+static const unsigned int scif1_data_d_mux[] = {
+	RX1_D_MARK, TX1_D_MARK,
+};
+static const unsigned int scif1_clk_d_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(3, 17),
+};
+static const unsigned int scif1_clk_d_mux[] = {
+	SCK1_D_MARK,
+};
+static const unsigned int scif1_data_e_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(2, 21), RCAR_GP_PIN(2, 22),
+};
+static const unsigned int scif1_data_e_mux[] = {
+	RX1_E_MARK, TX1_E_MARK,
+};
+static const unsigned int scif1_clk_e_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(2, 20),
+};
+static const unsigned int scif1_clk_e_mux[] = {
+	SCK1_E_MARK,
+};
+/* - SCIF2 ------------------------------------------------------------------ */
+static const unsigned int scif2_data_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 5),
+};
+static const unsigned int scif2_data_mux[] = {
+	RX2_MARK, TX2_MARK,
+};
+static const unsigned int scif2_clk_pins[] = {
+	/* SCK */
+	RCAR_GP_PIN(5, 4),
+};
+static const unsigned int scif2_clk_mux[] = {
+	SCK2_MARK,
+};
+static const unsigned int scif2_data_b_pins[] = {
+	/* RX, TX */
+	RCAR_GP_PIN(0, 24), RCAR_GP_PIN(0, 25),
+};
+static const unsigned int scif2_data_b_mux[] = {
+	RX2_B_MARK, TX2_B_MARK,
+};
 /* - SCIFA0 ----------------------------------------------------------------- */
 static const unsigned int scifa0_data_pins[] = {
 	/* RXD, TXD */
@@ -2477,103 +2737,6 @@
 static const unsigned int scifb2_data_c_mux[] = {
 	SCIFB2_RXD_C_MARK, SCIFB2_TXD_C_MARK,
 };
-/* - TPU0 ------------------------------------------------------------------- */
-static const unsigned int tpu0_to0_pins[] = {
-	/* TO */
-	RCAR_GP_PIN(0, 20),
-};
-static const unsigned int tpu0_to0_mux[] = {
-	TPU0TO0_MARK,
-};
-static const unsigned int tpu0_to1_pins[] = {
-	/* TO */
-	RCAR_GP_PIN(0, 21),
-};
-static const unsigned int tpu0_to1_mux[] = {
-	TPU0TO1_MARK,
-};
-static const unsigned int tpu0_to2_pins[] = {
-	/* TO */
-	RCAR_GP_PIN(0, 22),
-};
-static const unsigned int tpu0_to2_mux[] = {
-	TPU0TO2_MARK,
-};
-static const unsigned int tpu0_to3_pins[] = {
-	/* TO */
-	RCAR_GP_PIN(0, 23),
-};
-static const unsigned int tpu0_to3_mux[] = {
-	TPU0TO3_MARK,
-};
-/* - MMCIF0 ----------------------------------------------------------------- */
-static const unsigned int mmc0_data1_pins[] = {
-	/* D[0] */
-	RCAR_GP_PIN(3, 18),
-};
-static const unsigned int mmc0_data1_mux[] = {
-	MMC0_D0_MARK,
-};
-static const unsigned int mmc0_data4_pins[] = {
-	/* D[0:3] */
-	RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
-	RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 21),
-};
-static const unsigned int mmc0_data4_mux[] = {
-	MMC0_D0_MARK, MMC0_D1_MARK, MMC0_D2_MARK, MMC0_D3_MARK,
-};
-static const unsigned int mmc0_data8_pins[] = {
-	/* D[0:7] */
-	RCAR_GP_PIN(3, 18), RCAR_GP_PIN(3, 19),
-	RCAR_GP_PIN(3, 20), RCAR_GP_PIN(3, 21),
-	RCAR_GP_PIN(3, 22), RCAR_GP_PIN(3, 23),
-	RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7),
-};
-static const unsigned int mmc0_data8_mux[] = {
-	MMC0_D0_MARK, MMC0_D1_MARK, MMC0_D2_MARK, MMC0_D3_MARK,
-	MMC0_D4_MARK, MMC0_D5_MARK, MMC0_D6_MARK, MMC0_D7_MARK,
-};
-static const unsigned int mmc0_ctrl_pins[] = {
-	/* CLK, CMD */
-	RCAR_GP_PIN(3, 16), RCAR_GP_PIN(3, 17),
-};
-static const unsigned int mmc0_ctrl_mux[] = {
-	MMC0_CLK_MARK, MMC0_CMD_MARK,
-};
-/* - MMCIF1 ----------------------------------------------------------------- */
-static const unsigned int mmc1_data1_pins[] = {
-	/* D[0] */
-	RCAR_GP_PIN(3, 26),
-};
-static const unsigned int mmc1_data1_mux[] = {
-	MMC1_D0_MARK,
-};
-static const unsigned int mmc1_data4_pins[] = {
-	/* D[0:3] */
-	RCAR_GP_PIN(3, 26), RCAR_GP_PIN(3, 27),
-	RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 29),
-};
-static const unsigned int mmc1_data4_mux[] = {
-	MMC1_D0_MARK, MMC1_D1_MARK, MMC1_D2_MARK, MMC1_D3_MARK,
-};
-static const unsigned int mmc1_data8_pins[] = {
-	/* D[0:7] */
-	RCAR_GP_PIN(3, 26), RCAR_GP_PIN(3, 27),
-	RCAR_GP_PIN(3, 28), RCAR_GP_PIN(3, 29),
-	RCAR_GP_PIN(3, 30), RCAR_GP_PIN(3, 31),
-	RCAR_GP_PIN(3, 14), RCAR_GP_PIN(3, 15),
-};
-static const unsigned int mmc1_data8_mux[] = {
-	MMC1_D0_MARK, MMC1_D1_MARK, MMC1_D2_MARK, MMC1_D3_MARK,
-	MMC1_D4_MARK, MMC1_D5_MARK, MMC1_D6_MARK, MMC1_D7_MARK,
-};
-static const unsigned int mmc1_ctrl_pins[] = {
-	/* CLK, CMD */
-	RCAR_GP_PIN(3, 24), RCAR_GP_PIN(3, 25),
-};
-static const unsigned int mmc1_ctrl_mux[] = {
-	MMC1_CLK_MARK, MMC1_CMD_MARK,
-};
 /* - SDHI0 ------------------------------------------------------------------ */
 static const unsigned int sdhi0_data1_pins[] = {
 	/* D0 */
@@ -2718,8 +2881,149 @@
 static const unsigned int sdhi3_wp_mux[] = {
 	SD3_WP_MARK,
 };
+/* - TPU0 ------------------------------------------------------------------- */
+static const unsigned int tpu0_to0_pins[] = {
+	/* TO */
+	RCAR_GP_PIN(0, 20),
+};
+static const unsigned int tpu0_to0_mux[] = {
+	TPU0TO0_MARK,
+};
+static const unsigned int tpu0_to1_pins[] = {
+	/* TO */
+	RCAR_GP_PIN(0, 21),
+};
+static const unsigned int tpu0_to1_mux[] = {
+	TPU0TO1_MARK,
+};
+static const unsigned int tpu0_to2_pins[] = {
+	/* TO */
+	RCAR_GP_PIN(0, 22),
+};
+static const unsigned int tpu0_to2_mux[] = {
+	TPU0TO2_MARK,
+};
+static const unsigned int tpu0_to3_pins[] = {
+	/* TO */
+	RCAR_GP_PIN(0, 23),
+};
+static const unsigned int tpu0_to3_mux[] = {
+	TPU0TO3_MARK,
+};
+/* - USB0 ------------------------------------------------------------------- */
+static const unsigned int usb0_pins[] = {
+	/* PWEN, OVC/VBUS */
+	RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19),
+};
+static const unsigned int usb0_mux[] = {
+	USB0_PWEN_MARK, USB0_OVC_VBUS_MARK,
+};
+/* - USB1 ------------------------------------------------------------------- */
+static const unsigned int usb1_pins[] = {
+	/* PWEN, OVC */
+	RCAR_GP_PIN(5, 20), RCAR_GP_PIN(5, 21),
+};
+static const unsigned int usb1_mux[] = {
+	USB1_PWEN_MARK, USB1_OVC_MARK,
+};
+/* - USB2 ------------------------------------------------------------------- */
+static const unsigned int usb2_pins[] = {
+	/* PWEN, OVC */
+	RCAR_GP_PIN(5, 22), RCAR_GP_PIN(5, 23),
+};
+static const unsigned int usb2_mux[] = {
+	USB2_PWEN_MARK, USB2_OVC_MARK,
+};
+/* - VIN0 ------------------------------------------------------------------- */
+static const unsigned int vin0_data_g_pins[] = {
+	RCAR_GP_PIN(0, 8), RCAR_GP_PIN(0, 9), RCAR_GP_PIN(0, 10),
+	RCAR_GP_PIN(0, 11), RCAR_GP_PIN(0, 0), RCAR_GP_PIN(0, 1),
+	RCAR_GP_PIN(0, 2), RCAR_GP_PIN(0, 3),
+};
+static const unsigned int vin0_data_g_mux[] = {
+	VI0_G0_MARK, VI0_G1_MARK, VI0_G2_MARK,
+	VI0_G3_MARK, VI0_G4_MARK, VI0_G5_MARK,
+	VI0_G6_MARK, VI0_G7_MARK,
+};
+static const unsigned int vin0_data_r_pins[] = {
+	RCAR_GP_PIN(0, 4), RCAR_GP_PIN(0, 5), RCAR_GP_PIN(0, 6),
+	RCAR_GP_PIN(0, 7), RCAR_GP_PIN(0, 24), RCAR_GP_PIN(0, 25),
+	RCAR_GP_PIN(0, 26), RCAR_GP_PIN(1, 11),
+};
+static const unsigned int vin0_data_r_mux[] = {
+	VI0_R0_MARK, VI0_R1_MARK, VI0_R2_MARK,
+	VI0_R3_MARK, VI0_R4_MARK, VI0_R5_MARK,
+	VI0_R6_MARK, VI0_R7_MARK,
+};
+static const unsigned int vin0_data_b_pins[] = {
+	RCAR_GP_PIN(2, 1), RCAR_GP_PIN(2, 2), RCAR_GP_PIN(2, 3),
+	RCAR_GP_PIN(2, 4), RCAR_GP_PIN(2, 5), RCAR_GP_PIN(2, 6),
+	RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+};
+static const unsigned int vin0_data_b_mux[] = {
+	VI0_DATA0_VI0_B0_MARK, VI0_DATA1_VI0_B1_MARK, VI0_DATA2_VI0_B2_MARK,
+	VI0_DATA3_VI0_B3_MARK, VI0_DATA4_VI0_B4_MARK, VI0_DATA5_VI0_B5_MARK,
+	VI0_DATA6_VI0_B6_MARK, VI0_DATA7_VI0_B7_MARK,
+};
+static const unsigned int vin0_hsync_signal_pins[] = {
+	RCAR_GP_PIN(0, 12),
+};
+static const unsigned int vin0_hsync_signal_mux[] = {
+	VI0_HSYNC_N_MARK,
+};
+static const unsigned int vin0_vsync_signal_pins[] = {
+	RCAR_GP_PIN(0, 13),
+};
+static const unsigned int vin0_vsync_signal_mux[] = {
+	VI0_VSYNC_N_MARK,
+};
+static const unsigned int vin0_field_signal_pins[] = {
+	RCAR_GP_PIN(0, 15),
+};
+static const unsigned int vin0_field_signal_mux[] = {
+	VI0_FIELD_MARK,
+};
+static const unsigned int vin0_data_enable_pins[] = {
+	RCAR_GP_PIN(0, 14),
+};
+static const unsigned int vin0_data_enable_mux[] = {
+	VI0_CLKENB_MARK,
+};
+static const unsigned int vin0_clk_pins[] = {
+	RCAR_GP_PIN(2, 0),
+};
+static const unsigned int vin0_clk_mux[] = {
+	VI0_CLK_MARK,
+};
+/* - VIN1 ------------------------------------------------------------------- */
+static const unsigned int vin1_data_pins[] = {
+	RCAR_GP_PIN(2, 10), RCAR_GP_PIN(2, 11), RCAR_GP_PIN(2, 12),
+	RCAR_GP_PIN(2, 13), RCAR_GP_PIN(2, 14), RCAR_GP_PIN(2, 15),
+	RCAR_GP_PIN(2, 16), RCAR_GP_PIN(2, 17),
+};
+static const unsigned int vin1_data_mux[] = {
+	VI1_DATA0_VI1_B0_MARK, VI1_DATA1_VI1_B1_MARK, VI1_DATA2_VI1_B2_MARK,
+	VI1_DATA3_VI1_B3_MARK, VI1_DATA4_VI1_B4_MARK, VI1_DATA5_VI1_B5_MARK,
+	VI1_DATA6_VI1_B6_MARK, VI1_DATA7_VI1_B7_MARK,
+};
+static const unsigned int vin1_clk_pins[] = {
+	RCAR_GP_PIN(2, 9),
+};
+static const unsigned int vin1_clk_mux[] = {
+	VI1_CLK_MARK,
+};
 
 static const struct sh_pfc_pin_group pinmux_groups[] = {
+	SH_PFC_PIN_GROUP(du_rgb666),
+	SH_PFC_PIN_GROUP(du_rgb888),
+	SH_PFC_PIN_GROUP(du_clk_out_0),
+	SH_PFC_PIN_GROUP(du_clk_out_1),
+	SH_PFC_PIN_GROUP(du_sync_0),
+	SH_PFC_PIN_GROUP(du_sync_1),
+	SH_PFC_PIN_GROUP(du_cde),
+	SH_PFC_PIN_GROUP(du0_clk_in),
+	SH_PFC_PIN_GROUP(du1_clk_in),
+	SH_PFC_PIN_GROUP(du2_clk_in),
 	SH_PFC_PIN_GROUP(eth_link),
 	SH_PFC_PIN_GROUP(eth_magic),
 	SH_PFC_PIN_GROUP(eth_mdio),
@@ -2755,6 +3059,30 @@
 	SH_PFC_PIN_GROUP(mmc1_data4),
 	SH_PFC_PIN_GROUP(mmc1_data8),
 	SH_PFC_PIN_GROUP(mmc1_ctrl),
+	SH_PFC_PIN_GROUP(msiof0_clk),
+	SH_PFC_PIN_GROUP(msiof0_sync),
+	SH_PFC_PIN_GROUP(msiof0_ss1),
+	SH_PFC_PIN_GROUP(msiof0_ss2),
+	SH_PFC_PIN_GROUP(msiof0_rx),
+	SH_PFC_PIN_GROUP(msiof0_tx),
+	SH_PFC_PIN_GROUP(msiof1_clk),
+	SH_PFC_PIN_GROUP(msiof1_sync),
+	SH_PFC_PIN_GROUP(msiof1_ss1),
+	SH_PFC_PIN_GROUP(msiof1_ss2),
+	SH_PFC_PIN_GROUP(msiof1_rx),
+	SH_PFC_PIN_GROUP(msiof1_tx),
+	SH_PFC_PIN_GROUP(msiof2_clk),
+	SH_PFC_PIN_GROUP(msiof2_sync),
+	SH_PFC_PIN_GROUP(msiof2_ss1),
+	SH_PFC_PIN_GROUP(msiof2_ss2),
+	SH_PFC_PIN_GROUP(msiof2_rx),
+	SH_PFC_PIN_GROUP(msiof2_tx),
+	SH_PFC_PIN_GROUP(msiof3_clk),
+	SH_PFC_PIN_GROUP(msiof3_sync),
+	SH_PFC_PIN_GROUP(msiof3_ss1),
+	SH_PFC_PIN_GROUP(msiof3_ss2),
+	SH_PFC_PIN_GROUP(msiof3_rx),
+	SH_PFC_PIN_GROUP(msiof3_tx),
 	SH_PFC_PIN_GROUP(scif0_data),
 	SH_PFC_PIN_GROUP(scif0_clk),
 	SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -2768,6 +3096,9 @@
 	SH_PFC_PIN_GROUP(scif1_clk_d),
 	SH_PFC_PIN_GROUP(scif1_data_e),
 	SH_PFC_PIN_GROUP(scif1_clk_e),
+	SH_PFC_PIN_GROUP(scif2_data),
+	SH_PFC_PIN_GROUP(scif2_clk),
+	SH_PFC_PIN_GROUP(scif2_data_b),
 	SH_PFC_PIN_GROUP(scifa0_data),
 	SH_PFC_PIN_GROUP(scifa0_clk),
 	SH_PFC_PIN_GROUP(scifa0_ctrl),
@@ -2843,6 +3174,41 @@
 	SH_PFC_PIN_GROUP(tpu0_to1),
 	SH_PFC_PIN_GROUP(tpu0_to2),
 	SH_PFC_PIN_GROUP(tpu0_to3),
+	SH_PFC_PIN_GROUP(usb0),
+	SH_PFC_PIN_GROUP(usb1),
+	SH_PFC_PIN_GROUP(usb2),
+	SH_PFC_PIN_GROUP(vin0_data_g),
+	SH_PFC_PIN_GROUP(vin0_data_r),
+	SH_PFC_PIN_GROUP(vin0_data_b),
+	SH_PFC_PIN_GROUP(vin0_hsync_signal),
+	SH_PFC_PIN_GROUP(vin0_vsync_signal),
+	SH_PFC_PIN_GROUP(vin0_field_signal),
+	SH_PFC_PIN_GROUP(vin0_data_enable),
+	SH_PFC_PIN_GROUP(vin0_clk),
+	SH_PFC_PIN_GROUP(vin1_data),
+	SH_PFC_PIN_GROUP(vin1_clk),
+};
+
+static const char * const du_groups[] = {
+	"du_rgb666",
+	"du_rgb888",
+	"du_clk_out_0",
+	"du_clk_out_1",
+	"du_sync_0",
+	"du_sync_1",
+	"du_cde",
+};
+
+static const char * const du0_groups[] = {
+	"du0_clk_in",
+};
+
+static const char * const du1_groups[] = {
+	"du1_clk_in",
+};
+
+static const char * const du2_groups[] = {
+	"du2_clk_in",
 };
 
 static const char * const eth_groups[] = {
@@ -2852,32 +3218,6 @@
 	"eth_rmii",
 };
 
-static const char * const intc_groups[] = {
-	"intc_irq0",
-	"intc_irq1",
-	"intc_irq2",
-	"intc_irq3",
-};
-
-static const char * const scif0_groups[] = {
-	"scif0_data",
-	"scif0_clk",
-	"scif0_ctrl",
-	"scif0_data_b",
-};
-
-static const char * const scif1_groups[] = {
-	"scif1_data",
-	"scif1_clk",
-	"scif1_ctrl",
-	"scif1_data_b",
-	"scif1_data_c",
-	"scif1_data_d",
-	"scif1_clk_d",
-	"scif1_data_e",
-	"scif1_clk_e",
-};
-
 static const char * const hscif0_groups[] = {
 	"hscif0_data",
 	"hscif0_clk",
@@ -2903,6 +3243,88 @@
 	"hscif1_ctrl_b",
 };
 
+static const char * const intc_groups[] = {
+	"intc_irq0",
+	"intc_irq1",
+	"intc_irq2",
+	"intc_irq3",
+};
+
+static const char * const mmc0_groups[] = {
+	"mmc0_data1",
+	"mmc0_data4",
+	"mmc0_data8",
+	"mmc0_ctrl",
+};
+
+static const char * const mmc1_groups[] = {
+	"mmc1_data1",
+	"mmc1_data4",
+	"mmc1_data8",
+	"mmc1_ctrl",
+};
+
+static const char * const msiof0_groups[] = {
+	"msiof0_clk",
+	"msiof0_sync",
+	"msiof0_ss1",
+	"msiof0_ss2",
+	"msiof0_rx",
+	"msiof0_tx",
+};
+
+static const char * const msiof1_groups[] = {
+	"msiof1_clk",
+	"msiof1_sync",
+	"msiof1_ss1",
+	"msiof1_ss2",
+	"msiof1_rx",
+	"msiof1_tx",
+};
+
+static const char * const msiof2_groups[] = {
+	"msiof2_clk",
+	"msiof2_sync",
+	"msiof2_ss1",
+	"msiof2_ss2",
+	"msiof2_rx",
+	"msiof2_tx",
+};
+
+static const char * const msiof3_groups[] = {
+	"msiof3_clk",
+	"msiof3_sync",
+	"msiof3_ss1",
+	"msiof3_ss2",
+	"msiof3_rx",
+	"msiof3_tx",
+};
+
+static const char * const scif0_groups[] = {
+	"scif0_data",
+	"scif0_clk",
+	"scif0_ctrl",
+	"scif0_data_b",
+};
+
+static const char * const scif1_groups[] = {
+	"scif1_data",
+	"scif1_clk",
+	"scif1_ctrl",
+	"scif1_data_b",
+	"scif1_data_c",
+	"scif1_data_d",
+	"scif1_clk_d",
+	"scif1_data_e",
+	"scif1_clk_e",
+};
+
+static const char * const scif2_groups[] = {
+	"scif2_data",
+	"scif2_clk",
+	"scif2_data_b",
+};
+
 static const char * const scifa0_groups[] = {
 	"scifa0_data",
 	"scifa0_clk",
@@ -2972,27 +3394,6 @@
 	"scifb2_data_c",
 };
 
-static const char * const tpu0_groups[] = {
-	"tpu0_to0",
-	"tpu0_to1",
-	"tpu0_to2",
-	"tpu0_to3",
-};
-
-static const char * const mmc0_groups[] = {
-	"mmc0_data1",
-	"mmc0_data4",
-	"mmc0_data8",
-	"mmc0_ctrl",
-};
-
-static const char * const mmc1_groups[] = {
-	"mmc1_data1",
-	"mmc1_data4",
-	"mmc1_data8",
-	"mmc1_ctrl",
-};
-
 static const char * const sdhi0_groups[] = {
 	"sdhi0_data1",
 	"sdhi0_data4",
@@ -3025,15 +3426,59 @@
 	"sdhi3_wp",
 };
 
+static const char * const tpu0_groups[] = {
+	"tpu0_to0",
+	"tpu0_to1",
+	"tpu0_to2",
+	"tpu0_to3",
+};
+
+static const char * const usb0_groups[] = {
+	"usb0",
+};
+
+static const char * const usb1_groups[] = {
+	"usb1",
+};
+
+static const char * const usb2_groups[] = {
+	"usb2",
+};
+
+static const char * const vin0_groups[] = {
+	"vin0_data_g",
+	"vin0_data_r",
+	"vin0_data_b",
+	"vin0_hsync_signal",
+	"vin0_vsync_signal",
+	"vin0_field_signal",
+	"vin0_data_enable",
+	"vin0_clk",
+};
+
+static const char * const vin1_groups[] = {
+	"vin1_data",
+	"vin1_clk",
+};
+
 static const struct sh_pfc_function pinmux_functions[] = {
+	SH_PFC_FUNCTION(du),
+	SH_PFC_FUNCTION(du0),
+	SH_PFC_FUNCTION(du1),
+	SH_PFC_FUNCTION(du2),
 	SH_PFC_FUNCTION(eth),
 	SH_PFC_FUNCTION(hscif0),
 	SH_PFC_FUNCTION(hscif1),
 	SH_PFC_FUNCTION(intc),
 	SH_PFC_FUNCTION(mmc0),
 	SH_PFC_FUNCTION(mmc1),
+	SH_PFC_FUNCTION(msiof0),
+	SH_PFC_FUNCTION(msiof1),
+	SH_PFC_FUNCTION(msiof2),
+	SH_PFC_FUNCTION(msiof3),
 	SH_PFC_FUNCTION(scif0),
 	SH_PFC_FUNCTION(scif1),
+	SH_PFC_FUNCTION(scif2),
 	SH_PFC_FUNCTION(scifa0),
 	SH_PFC_FUNCTION(scifa1),
 	SH_PFC_FUNCTION(scifa2),
@@ -3045,6 +3490,11 @@
 	SH_PFC_FUNCTION(sdhi2),
 	SH_PFC_FUNCTION(sdhi3),
 	SH_PFC_FUNCTION(tpu0),
+	SH_PFC_FUNCTION(usb0),
+	SH_PFC_FUNCTION(usb1),
+	SH_PFC_FUNCTION(usb2),
+	SH_PFC_FUNCTION(vin0),
+	SH_PFC_FUNCTION(vin1),
 };
 
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
@@ -3257,16 +3707,16 @@
 		/* IP0_31 [1] */
 		0, 0,
 		/* IP0_30_27 [4] */
-		FN_D8, FN_SCIFA1_SCK_C, FN_AVB_TXD0, FN_MII_TXD0,
+		FN_D8, FN_SCIFA1_SCK_C, FN_AVB_TXD0, 0,
 		FN_VI0_G0, FN_VI0_G0_B, FN_VI2_DATA0_VI2_B0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP0_26_23 [4] */
-		FN_D7, FN_AD_DI_B, FN_SDA2_C,
-		FN_VI3_DATA7, FN_VI0_R3, FN_VI0_R3_B, FN_SDA2_CIS_C,
-		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		FN_D7, FN_AD_DI_B, FN_IIC2_SDA_C,
+		FN_VI3_DATA7, FN_VI0_R3, FN_VI0_R3_B, FN_I2C2_SDA_C,
+		FN_TCLK1, 0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP0_22_20 [3] */
-		FN_D6, FN_SCL2_C, FN_VI3_DATA6, FN_VI0_R2, FN_VI0_R2_B,
-		FN_SCL2_CIS_C, 0, 0,
+		FN_D6, FN_IIC2_SCL_C, FN_VI3_DATA6, FN_VI0_R2, FN_VI0_R2_B,
+		FN_I2C2_SCL_C, 0, 0,
 		/* IP0_19_16 [4] */
 		FN_D5, FN_SCIFB1_TXD_F, FN_SCIFB0_TXD_C, FN_VI3_DATA5,
 		FN_VI0_R1, FN_VI0_R1_B, FN_TX0_B,
@@ -3313,15 +3763,15 @@
 		FN_VI0_HSYNC_N, FN_VI0_HSYNC_N_B, FN_VI2_DATA4_VI2_B4,
 		0, 0,
 		/* IP1_11_8 [4] */
-		FN_D11, FN_SCIFA1_CTS_N_C, FN_AVB_TXD3, FN_MII_TXD3,
+		FN_D11, FN_SCIFA1_CTS_N_C, FN_AVB_TXD3, 0,
 		FN_VI0_G3, FN_VI0_G3_B, FN_VI2_DATA3_VI2_B3,
 		0, 0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP1_7_4 [4] */
-		FN_D10, FN_SCIFA1_TXD_C, FN_AVB_TXD2, FN_MII_TXD2,
+		FN_D10, FN_SCIFA1_TXD_C, FN_AVB_TXD2, 0,
 		FN_VI0_G2, FN_VI0_G2_B, FN_VI2_DATA2_VI2_B2,
 		0, 0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP1_3_0 [4] */
-		FN_D9, FN_SCIFA1_RXD_C, FN_AVB_TXD1, FN_MII_TXD1,
+		FN_D9, FN_SCIFA1_RXD_C, FN_AVB_TXD1, 0,
 		FN_VI0_G1, FN_VI0_G1_B, FN_VI2_DATA1_VI2_B1,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, }
 	},
@@ -3334,11 +3784,11 @@
 		FN_VI0_R6_B, FN_VI2_DATA2_VI2_B2_B, 0, 0,
 		/* IP2_25_22 [4] */
 		FN_A9, FN_SCIFA1_CTS_N_B, FN_SSI_WS5_B, FN_VI0_R5,
-		FN_VI0_R5_B, FN_SCIFB2_TXD_C, 0, FN_VI2_DATA1_VI2_B1_B,
+		FN_VI0_R5_B, FN_SCIFB2_TXD_C, FN_TX2_B, FN_VI2_DATA1_VI2_B1_B,
 		0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP2_21_18 [4] */
 		FN_A8, FN_SCIFA1_RXD_B, FN_SSI_SCK5_B, FN_VI0_R4,
-		FN_VI0_R4_B, FN_SCIFB2_RXD_C, 0, FN_VI2_DATA0_VI2_B0_B,
+		FN_VI0_R4_B, FN_SCIFB2_RXD_C, FN_RX2_B, FN_VI2_DATA0_VI2_B0_B,
 		0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP2_17_15 [3] */
 		FN_A7, FN_SCIFA1_SCK_B, FN_AUDIO_CLKOUT_B, FN_TPU0TO3,
@@ -3448,12 +3898,12 @@
 		0, 0,
 		/* IP5_9_6 [4] */
 		FN_EX_CS5_N, FN_CAN0_RX, FN_MSIOF1_RXD_B, FN_VI3_VSYNC_N,
-		FN_VI1_G2, FN_VI1_G2_B, FN_VI2_R4, FN_SDA1, FN_INTC_EN1_N,
-		FN_SDA1_CIS, 0, 0, 0, 0, 0, 0,
+		FN_VI1_G2, FN_VI1_G2_B, FN_VI2_R4, FN_IIC1_SDA, FN_INTC_EN1_N,
+		FN_I2C1_SDA, 0, 0, 0, 0, 0, 0,
 		/* IP5_5_3 [3] */
 		FN_EX_CS4_N, FN_MSIOF1_SCK_B, FN_VI3_HSYNC_N,
-		FN_VI2_HSYNC_N, FN_SCL1, FN_VI2_HSYNC_N_B,
-		FN_INTC_EN0_N, FN_SCL1_CIS,
+		FN_VI2_HSYNC_N, FN_IIC1_SCL, FN_VI2_HSYNC_N_B,
+		FN_INTC_EN0_N, FN_I2C1_SCL,
 		/* IP5_2_0 [3] */
 		FN_EX_CS3_N, FN_GPS_MAG, FN_VI3_FIELD, FN_VI1_G1, FN_VI1_G1_B,
 		FN_VI2_R3, 0, 0, }
@@ -3461,24 +3911,24 @@
 	{ PINMUX_CFG_REG_VAR("IPSR6", 0xE6060038, 32,
 			     3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3) {
 		/* IP6_31_29 [3] */
-		FN_ETH_REF_CLK, FN_RMII_REF_CLK, FN_HCTS0_N_E,
+		FN_ETH_REF_CLK, 0, FN_HCTS0_N_E,
 		FN_STP_IVCXO27_1_B, FN_HRX0_F, 0, 0, 0,
 		/* IP6_28_26 [3] */
-		FN_ETH_LINK, FN_RMII_LINK, FN_HTX0_E,
+		FN_ETH_LINK, 0, FN_HTX0_E,
 		FN_STP_IVCXO27_0_B, FN_SCIFB1_TXD_G, FN_TX1_E, 0, 0,
 		/* IP6_25_23 [3] */
-		FN_ETH_RXD1, FN_RMII_RXD1, FN_HRX0_E, FN_STP_ISSYNC_0_B,
+		FN_ETH_RXD1, 0, FN_HRX0_E, FN_STP_ISSYNC_0_B,
 		FN_TS_SCK0_D, FN_GLO_I1_C, FN_SCIFB1_RXD_G, FN_RX1_E,
 		/* IP6_22_20 [3] */
-		FN_ETH_RXD0, FN_RMII_RXD0, FN_STP_ISEN_0_B, FN_TS_SDAT0_D,
+		FN_ETH_RXD0, 0, FN_STP_ISEN_0_B, FN_TS_SDAT0_D,
 		FN_GLO_I0_C, FN_SCIFB1_SCK_G, FN_SCK1_E, 0,
 		/* IP6_19_17 [3] */
-		FN_ETH_RX_ER, FN_RMII_RX_ER, FN_STP_ISD_0_B,
-		FN_TS_SPSYNC0_D, FN_GLO_Q1_C, FN_SDA2_E, FN_SDA2_CIS_E, 0,
+		FN_ETH_RX_ER, 0, FN_STP_ISD_0_B,
+		FN_TS_SPSYNC0_D, FN_GLO_Q1_C, FN_IIC2_SDA_E, FN_I2C2_SDA_E, 0,
 		/* IP6_16_14 [3] */
-		FN_ETH_CRS_DV, FN_RMII_CRS_DV, FN_STP_ISCLK_0_B,
-		FN_TS_SDEN0_D, FN_GLO_Q0_C, FN_SCL2_E,
-		FN_SCL2_CIS_E, 0,
+		FN_ETH_CRS_DV, 0, FN_STP_ISCLK_0_B,
+		FN_TS_SDEN0_D, FN_GLO_Q0_C, FN_IIC2_SCL_E,
+		FN_I2C2_SCL_E, 0,
 		/* IP6_13_11 [3] */
 		FN_DACK2, FN_IRQ2, FN_INTC_IRQ2_N,
 		FN_SSI_SDATA6_B, FN_HRTS0_N_B, FN_MSIOF0_RXD_B, 0, 0,
@@ -3499,12 +3949,11 @@
 		/* IP7_31 [1] */
 		0, 0,
 		/* IP7_30_29 [2] */
-		FN_VI0_DATA0_VI0_B0, FN_ATACS10_N, FN_AVB_RXD2,
-		FN_MII_RXD2,
+		FN_VI0_DATA0_VI0_B0, FN_ATACS10_N, FN_AVB_RXD2, 0,
 		/* IP7_28_27 [2] */
-		FN_VI0_CLK, FN_ATACS00_N, FN_AVB_RXD1, FN_MII_RXD1,
+		FN_VI0_CLK, FN_ATACS00_N, FN_AVB_RXD1, 0,
 		/* IP7_26_25 [2] */
-		FN_DU1_DOTCLKIN, FN_AUDIO_CLKC, FN_AUDIO_CLKOUT_C, 0,
+		FN_DU_DOTCLKIN1, FN_AUDIO_CLKC, FN_AUDIO_CLKOUT_C, 0,
 		/* IP7_24_22 [3] */
 		FN_PWM2, FN_PWMFSW0, FN_SCIFA2_RXD_C, FN_PCMWE_N, FN_IECLK_C,
 		0, 0, 0,
@@ -3515,20 +3964,19 @@
 		FN_PWM0, FN_SCIFA2_SCK_C, FN_STP_ISEN_1_B, FN_TS_SDAT1_C,
 		FN_GLO_SS_C, 0, 0, 0,
 		/* IP7_15_13 [3] */
-		FN_ETH_MDC, FN_RMII_MDC, FN_STP_ISD_1_B,
+		FN_ETH_MDC, 0, FN_STP_ISD_1_B,
 		FN_TS_SPSYNC1_C, FN_GLO_SDATA_C, 0, 0, 0,
 		/* IP7_12_10 [3] */
-		FN_ETH_TXD0, FN_RMII_TXD0, FN_STP_ISCLK_1_B, FN_TS_SDEN1_C,
+		FN_ETH_TXD0, 0, FN_STP_ISCLK_1_B, FN_TS_SDEN1_C,
 		FN_GLO_SCLK_C, 0, 0, 0,
 		/* IP7_9_8 [2] */
-		FN_ETH_MAGIC, FN_RMII_MAGIC, FN_SIM0_RST_C, 0,
+		FN_ETH_MAGIC, 0, FN_SIM0_RST_C, 0,
 		/* IP7_7_6 [2] */
-		FN_ETH_TX_EN, FN_RMII_TX_EN, FN_SIM0_CLK_C, FN_HRTS0_N_F,
+		FN_ETH_TX_EN, 0, FN_SIM0_CLK_C, FN_HRTS0_N_F,
 		/* IP7_5_3 [3] */
-		FN_ETH_TXD1, FN_RMII_TXD1, FN_HTX0_F, FN_BPFCLK_G, FN_RDS_CLK_F,
-		0, 0, 0,
+		FN_ETH_TXD1, 0, FN_HTX0_F, FN_BPFCLK_G, 0, 0, 0, 0,
 		/* IP7_2_0 [3] */
-		FN_ETH_MDIO, FN_RMII_MDIO, FN_HRTS0_N_E,
+		FN_ETH_MDIO, 0, FN_HRTS0_N_E,
 		FN_SIM0_D_C, FN_HCTS0_N_F, 0, 0, 0, }
 	},
 	{ PINMUX_CFG_REG_VAR("IPSR8", 0xE6060040, 32,
@@ -3546,22 +3994,21 @@
 		FN_VI1_DATA5_VI1_B5, FN_AVB_PHY_INT,
 		/* IP8_25_24 [2] */
 		FN_VI1_DATA4_VI1_B4, FN_SCIFA1_RTS_N_D,
-		FN_AVB_MAGIC, FN_MII_MAGIC,
+		FN_AVB_MAGIC, 0,
 		/* IP8_23_22 [2] */
 		FN_VI1_DATA3_VI1_B3, FN_SCIFA1_CTS_N_D, FN_AVB_GTX_CLK, 0,
 		/* IP8_21_20 [2] */
-		FN_VI1_DATA2_VI1_B2, FN_SCIFA1_TXD_D, FN_AVB_MDIO,
-		FN_MII_MDIO,
+		FN_VI1_DATA2_VI1_B2, FN_SCIFA1_TXD_D, FN_AVB_MDIO, 0,
 		/* IP8_19_18 [2] */
-		FN_VI1_DATA1_VI1_B1, FN_SCIFA1_RXD_D, FN_AVB_MDC, FN_MII_MDC,
+		FN_VI1_DATA1_VI1_B1, FN_SCIFA1_RXD_D, FN_AVB_MDC, 0,
 		/* IP8_17_16 [2] */
-		FN_VI1_DATA0_VI1_B0, FN_SCIFA1_SCK_D, FN_AVB_CRS, FN_MII_CRS,
+		FN_VI1_DATA0_VI1_B0, FN_SCIFA1_SCK_D, FN_AVB_CRS, 0,
 		/* IP8_15_14 [2] */
-		FN_VI1_CLK, FN_AVB_RX_DV, FN_MII_RX_DV, 0,
+		FN_VI1_CLK, FN_AVB_RX_DV, 0, 0,
 		/* IP8_13_12 [2] */
-		FN_VI0_DATA7_VI0_B7, FN_AVB_RX_CLK, FN_MII_RX_CLK, 0,
+		FN_VI0_DATA7_VI0_B7, FN_AVB_RX_CLK, 0, 0,
 		/* IP8_11_10 [2] */
-		FN_VI0_DATA6_VI0_B6, FN_AVB_RX_ER, FN_MII_RX_ER, 0,
+		FN_VI0_DATA6_VI0_B6, FN_AVB_RX_ER, 0, 0,
 		/* IP8_9_8 [2] */
 		FN_VI0_DATA5_VI0_B5, FN_EX_WAIT1, FN_AVB_RXD7, 0,
 		/* IP8_7_6 [2] */
@@ -3571,34 +4018,34 @@
 		/* IP8_3_2 [2] */
 		FN_VI0_DATA2_VI0_B2, FN_ATAWR0_N, FN_AVB_RXD4, 0,
 		/* IP8_1_0 [2] */
-		FN_VI0_DATA1_VI0_B1, FN_ATARD0_N, FN_AVB_RXD3, FN_MII_RXD3, }
+		FN_VI0_DATA1_VI0_B1, FN_ATARD0_N, FN_AVB_RXD3, 0, }
 	},
 	{ PINMUX_CFG_REG_VAR("IPSR9", 0xE6060044, 32,
 			     4, 2, 2, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2) {
 		/* IP9_31_28 [4] */
 		FN_SD1_CD, FN_MMC1_D6, FN_TS_SDEN1, FN_USB1_EXTP,
-		FN_GLO_SS, FN_VI0_CLK_B, FN_SCL2_D, FN_SCL2_CIS_D,
+		FN_GLO_SS, FN_VI0_CLK_B, FN_IIC2_SCL_D, FN_I2C2_SCL_D,
 		FN_SIM0_CLK_B, FN_VI3_CLK_B, 0, 0, 0, 0, 0, 0,
 		/* IP9_27_26 [2] */
-		FN_SD1_DAT3, FN_AVB_RXD0, FN_MII_RXD0, FN_SCIFB0_RTS_N_B,
+		FN_SD1_DAT3, FN_AVB_RXD0, 0, FN_SCIFB0_RTS_N_B,
 		/* IP9_25_24 [2] */
-		FN_SD1_DAT2, FN_AVB_COL, FN_MII_COL, FN_SCIFB0_CTS_N_B,
+		FN_SD1_DAT2, FN_AVB_COL, 0, FN_SCIFB0_CTS_N_B,
 		/* IP9_23_22 [2] */
-		FN_SD1_DAT1, FN_AVB_LINK, FN_MII_LINK, FN_SCIFB0_TXD_B,
+		FN_SD1_DAT1, FN_AVB_LINK, 0, FN_SCIFB0_TXD_B,
 		/* IP9_21_20 [2] */
-		FN_SD1_DAT0, FN_AVB_TX_CLK, FN_MII_TX_CLK, FN_SCIFB0_RXD_B,
+		FN_SD1_DAT0, FN_AVB_TX_CLK, 0, FN_SCIFB0_RXD_B,
 		/* IP9_19_18 [2] */
-		FN_SD1_CMD, FN_AVB_TX_ER, FN_MII_TX_ER, FN_SCIFB0_SCK_B,
+		FN_SD1_CMD, FN_AVB_TX_ER, 0, FN_SCIFB0_SCK_B,
 		/* IP9_17_16 [2] */
-		FN_SD1_CLK, FN_AVB_TX_EN, FN_MII_TX_EN, 0,
+		FN_SD1_CLK, FN_AVB_TX_EN, 0, 0,
 		/* IP9_15_12 [4] */
 		FN_SD0_WP, FN_MMC0_D7, FN_TS_SPSYNC0_B, FN_USB0_IDIN,
-		FN_GLO_SDATA, FN_VI1_DATA7_VI1_B7_B, FN_SDA1_B,
-		FN_SDA1_CIS_B, FN_VI2_DATA7_VI2_B7_B, 0, 0, 0, 0, 0, 0, 0,
+		FN_GLO_SDATA, FN_VI1_DATA7_VI1_B7_B, FN_IIC1_SDA_B,
+		FN_I2C1_SDA_B, FN_VI2_DATA7_VI2_B7_B, 0, 0, 0, 0, 0, 0, 0,
 		/* IP9_11_8 [4] */
 		FN_SD0_CD, FN_MMC0_D6, FN_TS_SDEN0_B, FN_USB0_EXTP,
-		FN_GLO_SCLK, FN_VI1_DATA6_VI1_B6_B, FN_SCL1_B,
-		FN_SCL1_CIS_B, FN_VI2_DATA6_VI2_B6_B, 0, 0, 0, 0, 0, 0, 0,
+		FN_GLO_SCLK, FN_VI1_DATA6_VI1_B6_B, FN_IIC1_SCL_B,
+		FN_I2C1_SCL_B, FN_VI2_DATA6_VI2_B6_B, 0, 0, 0, 0, 0, 0, 0,
 		/* IP9_7_6 [2] */
 		FN_SD0_DAT3, FN_SCIFB1_RTS_N_B, FN_VI1_DATA5_VI1_B5_B, 0,
 		/* IP9_5_4 [2] */
@@ -3620,11 +4067,11 @@
 		FN_SD2_DAT3, FN_MMC0_D3, FN_SIM0_RST, FN_VI0_DATA5_VI0_B5_B,
 		FN_HTX0_D, FN_TS_SPSYNC1_B, FN_GLO_Q1_B, FN_VI3_DATA5_B,
 		/* IP10_22_19 [4] */
-		FN_SD2_DAT2, FN_MMC0_D2, FN_BPFCLK_B, FN_RDS_CLK,
+		FN_SD2_DAT2, FN_MMC0_D2, FN_BPFCLK_B, 0,
 		FN_VI0_DATA4_VI0_B4_B, FN_HRX0_D, FN_TS_SDEN1_B,
 		FN_GLO_Q0_B, FN_VI3_DATA4_B, 0, 0, 0, 0, 0, 0, 0,
 		/* IP10_18_15 [4] */
-		FN_SD2_DAT1, FN_MMC0_D1, FN_FMIN_B, FN_RDS_DATA,
+		FN_SD2_DAT1, FN_MMC0_D1, FN_FMIN_B, 0,
 		FN_VI0_DATA3_VI0_B3_B, FN_SCIFB1_TXD_E, FN_TX1_D,
 		FN_TS_SCK0_C, FN_GLO_RFON_B, FN_VI3_DATA3_B,
 		0, 0, 0, 0, 0, 0,
@@ -3644,7 +4091,7 @@
 		FN_VI3_DATA0_B, 0,
 		/* IP10_3_0 [4] */
 		FN_SD1_WP, FN_MMC1_D7, FN_TS_SPSYNC1, FN_USB1_IDIN,
-		FN_GLO_RFON, FN_VI1_CLK_B, FN_SDA2_D, FN_SDA2_CIS_D,
+		FN_GLO_RFON, FN_VI1_CLK_B, FN_IIC2_SDA_D, FN_I2C2_SDA_D,
 		FN_SIM0_D_B, 0, 0, 0, 0, 0, 0, 0, }
 	},
 	{ PINMUX_CFG_REG_VAR("IPSR11", 0xE606004C, 32,
@@ -3652,17 +4099,16 @@
 		/* IP11_31_30 [2] */
 		FN_SSI_SCK0129, FN_CAN_CLK_B, FN_MOUT0, 0,
 		/* IP11_29_27 [3] */
-		FN_MLB_DAT, FN_SPV_EVEN, FN_SCIFB1_TXD_D, FN_TX1_C, FN_BPFCLK_C,
-		FN_RDS_CLK_B, 0, 0,
+		FN_MLB_DAT, 0, FN_SCIFB1_TXD_D, FN_TX1_C, FN_BPFCLK_C,
+		0, 0, 0,
 		/* IP11_26_24 [3] */
-		FN_MLB_SIG, FN_SCIFB1_RXD_D, FN_RX1_C, FN_SDA2_B, FN_SDA2_CIS_B,
+		FN_MLB_SIG, FN_SCIFB1_RXD_D, FN_RX1_C, FN_IIC2_SDA_B, FN_I2C2_SDA_B,
 		0, 0, 0,
 		/* IP11_23_22 [2] */
-		FN_MLB_CLK, FN_SCL2_B, FN_SCL2_CIS_B, 0,
+		FN_MLB_CLK, FN_IIC2_SCL_B, FN_I2C2_SCL_B, 0,
 		/* IP11_21_18 [4] */
 		FN_SD3_WP, FN_MMC1_D5, FN_TS_SCK1, FN_GLO_Q1, FN_FMIN_C,
-		FN_RDS_DATA_B, FN_FMIN_E, FN_RDS_DATA_D, FN_FMIN_F,
-		FN_RDS_DATA_E, 0, 0, 0, 0, 0, 0,
+		0, FN_FMIN_E, 0, FN_FMIN_F, 0, 0, 0, 0, 0, 0, 0,
 		/* IP11_17_15 [3] */
 		FN_SD3_CD, FN_MMC1_D4, FN_TS_SDAT1,
 		FN_VSP, FN_GLO_Q0, FN_SIM0_RST_B, 0, 0,
@@ -3737,8 +4183,7 @@
 		/* IP13_22_19 [4] */
 		FN_SSI_SDATA7, FN_STP_ISD_1, FN_SCIFB2_RXD, FN_SCIFA2_RTS_N,
 		FN_TCLK2, FN_QSTVA_QVS, FN_CAN_DEBUGOUT11, FN_BPFCLK_E,
-		FN_RDS_CLK_D, FN_SSI_SDATA7_B, FN_FMIN_G, FN_RDS_DATA_F,
-		0, 0, 0, 0,
+		0, FN_SSI_SDATA7_B, FN_FMIN_G, 0, 0, 0, 0, 0,
 		/* IP13_18_16 [3] */
 		FN_SSI_WS78, FN_STP_ISCLK_1, FN_SCIFB2_SCK, FN_SCIFA2_CTS_N,
 		FN_DU2_DR7, FN_LCDOUT7, FN_CAN_DEBUGOUT10, 0,
@@ -3746,15 +4191,15 @@
 		FN_SSI_SCK78, FN_STP_IVCXO27_1, FN_SCK1, FN_SCIFA1_SCK,
 		FN_DU2_DR6, FN_LCDOUT6, FN_CAN_DEBUGOUT9, 0,
 		/* IP13_12_10 [3] */
-		FN_SSI_SDATA6, FN_FMIN_D, FN_RDS_DATA_C, FN_DU2_DR5, FN_LCDOUT5,
+		FN_SSI_SDATA6, FN_FMIN_D, 0, FN_DU2_DR5, FN_LCDOUT5,
 		FN_CAN_DEBUGOUT8, 0, 0,
 		/* IP13_9_7 [3] */
 		FN_SSI_WS6, FN_SCIFB1_RTS_N, FN_CAN0_TX_D, FN_DU2_DR4,
 		FN_LCDOUT4, FN_CAN_DEBUGOUT7, 0, 0,
 		/* IP13_6_3 [4] */
-		FN_SSI_SCK6, FN_SCIFB1_CTS_N, FN_BPFCLK_D, FN_RDS_CLK_C,
+		FN_SSI_SCK6, FN_SCIFB1_CTS_N, FN_BPFCLK_D, 0,
 		FN_DU2_DR3, FN_LCDOUT3, FN_CAN_DEBUGOUT6,
-		FN_BPFCLK_F, FN_RDS_CLK_E, 0, 0, 0, 0, 0, 0, 0,
+		FN_BPFCLK_F, 0, 0, 0, 0, 0, 0, 0, 0,
 		/* IP13_2_0 [3] */
 		FN_SSI_SDATA5, FN_SCIFB1_TXD, FN_IETX_B, FN_DU2_DR2,
 		FN_LCDOUT2, FN_CAN_DEBUGOUT5, 0, 0, }
@@ -3764,7 +4209,7 @@
 		/* IP14_30 [1] */
 		0, 0,
 		/* IP14_30_28 [3] */
-		FN_SCIFA1_RTS_N, FN_AD_NCS_N, FN_RTS1_N_TANS,
+		FN_SCIFA1_RTS_N, FN_AD_NCS_N, FN_RTS1_N,
 		FN_MSIOF3_TXD, FN_DU1_DOTCLKOUT, FN_QSTVB_QVE,
 		FN_HRTS0_N_C, 0,
 		/* IP14_27_25 [3] */
@@ -3777,11 +4222,11 @@
 		FN_SCIFA1_RXD, FN_AD_DI, FN_RX1,
 		FN_DU2_EXODDF_DU2_ODDF_DISP_CDE, FN_QCPV_QDE, 0, 0, 0,
 		/* IP14_18_16 [3] */
-		FN_SCIFA0_RTS_N, FN_HRTS1_N, FN_RTS0_N_TANS,
+		FN_SCIFA0_RTS_N, FN_HRTS1_N, FN_RTS0_N,
 		FN_MSIOF3_SS1, FN_DU2_DG0, FN_LCDOUT8, FN_PWM1_B, 0,
 		/* IP14_15_12 [4] */
 		FN_SCIFA0_CTS_N, FN_HCTS1_N, FN_CTS0_N, FN_MSIOF3_SYNC,
-		FN_DU2_DG3, FN_LCDOUT11, FN_PWM0_B, FN_SCL1_C, FN_SCL1_CIS_C,
+		FN_DU2_DG3, FN_LCDOUT11, FN_PWM0_B, FN_IIC1_SCL_C, FN_I2C1_SCL_C,
 		0, 0, 0, 0, 0, 0, 0,
 		/* IP14_11_9 [3] */
 		FN_SCIFA0_TXD, FN_HTX1, FN_TX0, FN_DU2_DR1, FN_LCDOUT1,
@@ -3791,7 +4236,7 @@
 		0, 0, 0,
 		/* IP14_5_3 [3] */
 		FN_SCIFA0_SCK, FN_HSCK1, FN_SCK0, FN_MSIOF3_SS2, FN_DU2_DG2,
-		FN_LCDOUT10, FN_SDA1_C, FN_SDA1_CIS_C,
+		FN_LCDOUT10, FN_IIC1_SDA_C, FN_I2C1_SDA_C,
 		/* IP14_2_0 [3] */
 		FN_AUDIO_CLKB, FN_SCIF_CLK, FN_CAN0_RX_D,
 		FN_DVC_MUTE, FN_CAN0_RX_C, FN_CAN_DEBUGOUT15,
@@ -3807,7 +4252,7 @@
 		FN_MSIOF0_SS1, FN_ADICHS0, FN_DU2_DG5, FN_LCDOUT13,
 		/* IP15_25_23 [3] */
 		FN_MSIOF0_SYNC, FN_TS_SCK0, FN_SSI_SCK2, FN_ADIDATA,
-		FN_DU2_DB7, FN_LCDOUT23, FN_SCIFA2_RXD_B, 0,
+		FN_DU2_DB7, FN_LCDOUT23, FN_HRX0_C, 0,
 		/* IP15_22_20 [3] */
 		FN_MSIOF0_SCK, FN_TS_SDAT0, FN_ADICLK,
 		FN_DU2_DB6, FN_LCDOUT22, 0, 0, 0,
@@ -3823,13 +4268,13 @@
 		FN_HSCK0, FN_TS_SDEN0, FN_DU2_DG4, FN_LCDOUT12, FN_HCTS0_N_C,
 		0, 0, 0,
 		/* IP15_8_6 [3] */
-		FN_SCIFA2_TXD, FN_BPFCLK, 0, FN_DU2_DB1, FN_LCDOUT17,
-		FN_SDA2, FN_SDA2_CIS, 0,
+		FN_SCIFA2_TXD, FN_BPFCLK, FN_RX2, FN_DU2_DB1, FN_LCDOUT17,
+		FN_IIC2_SDA, FN_I2C2_SDA, 0,
 		/* IP15_5_3 [3] */
-		FN_SCIFA2_RXD, FN_FMIN, 0, FN_DU2_DB0, FN_LCDOUT16,
-		FN_SCL2, FN_SCL2_CIS, 0,
+		FN_SCIFA2_RXD, FN_FMIN, FN_TX2, FN_DU2_DB0, FN_LCDOUT16,
+		FN_IIC2_SCL, FN_I2C2_SCL, 0,
 		/* IP15_2_0 [3] */
-		FN_SCIFA2_SCK, FN_FMCLK, 0, FN_MSIOF3_SCK, FN_DU2_DG7,
+		FN_SCIFA2_SCK, FN_FMCLK, FN_SCK2, FN_MSIOF3_SCK, FN_DU2_DG7,
 		FN_LCDOUT15, FN_SCIF_CLK_B, 0, }
 	},
 	{ PINMUX_CFG_REG_VAR("IPSR16", 0xE6060160, 32,
@@ -3858,7 +4303,7 @@
 		FN_USB1_PWEN, FN_AUDIO_CLKOUT_D,
 		/* IP16_5_3 [3] */
 		FN_MSIOF0_RXD, FN_TS_SPSYNC0, FN_SSI_WS2,
-		FN_ADICS_SAMP, FN_DU2_CDE, FN_QPOLB, FN_HRX0_C, 0,
+		FN_ADICS_SAMP, FN_DU2_CDE, FN_QPOLB, FN_SCIFA2_RXD_B, 0,
 		/* IP16_2_0 [3] */
 		FN_MSIOF0_SS2, FN_AUDIO_CLKOUT, FN_ADICHS2,
 		FN_DU2_DISP, FN_QPOLA, FN_HTX0_C, FN_SCIFA2_TXD_B, 0, }
@@ -3934,8 +4379,8 @@
 		FN_SEL_CAN1_0, FN_SEL_CAN1_1,
 		/* RESERVED [2] */
 		0, 0, 0, 0,
-		/* RESERVED [1] (actually TX2, RX2 vs. TX2_B, RX2_B of SCIF2) */
-		0, 0,
+		/* SEL_SCIF2 [1] */
+		FN_SEL_SCIF2_0, FN_SEL_SCIF2_1,
 		/* SEL_ADI [1] */
 		FN_SEL_ADI_0, FN_SEL_ADI_1,
 		/* SEL_SSP [1] */
@@ -3948,9 +4393,8 @@
 		FN_SEL_HSCIF0_3, FN_SEL_HSCIF0_4, FN_SEL_HSCIF0_5, 0, 0,
 		/* SEL_GPS [2] */
 		FN_SEL_GPS_0, FN_SEL_GPS_1, FN_SEL_GPS_2, 0,
-		/* SEL_RDS [3] */
-		FN_SEL_RDS_0, FN_SEL_RDS_1, FN_SEL_RDS_2,
-		FN_SEL_RDS_3, FN_SEL_RDS_4, FN_SEL_RDS_5, 0, 0,
+		/* RESERVED [3] */
+		0, 0, 0, 0, 0, 0, 0, 0,
 		/* SEL_SIM [2] */
 		FN_SEL_SIM_0, FN_SEL_SIM_1, FN_SEL_SIM_2, 0,
 		/* SEL_SSI8 [2] */
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7203.c b/drivers/pinctrl/sh-pfc/pfc-sh7203.c
index f63d51d..bf3d8f2 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7203.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7203.c
@@ -272,8 +272,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
-
+static const u16 pinmux_data[] = {
 	/* PA */
 	PINMUX_DATA(PA7_DATA, PA7_IN),
 	PINMUX_DATA(PA6_DATA, PA6_IN),
@@ -704,117 +703,116 @@
 };
 
 static struct sh_pfc_pin pinmux_pins[] = {
-
 	/* PA */
-	PINMUX_GPIO(GPIO_PA7, PA7_DATA),
-	PINMUX_GPIO(GPIO_PA6, PA6_DATA),
-	PINMUX_GPIO(GPIO_PA5, PA5_DATA),
-	PINMUX_GPIO(GPIO_PA4, PA4_DATA),
-	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
-	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
-	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
-	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+	PINMUX_GPIO(PA7),
+	PINMUX_GPIO(PA6),
+	PINMUX_GPIO(PA5),
+	PINMUX_GPIO(PA4),
+	PINMUX_GPIO(PA3),
+	PINMUX_GPIO(PA2),
+	PINMUX_GPIO(PA1),
+	PINMUX_GPIO(PA0),
 
 	/* PB */
-	PINMUX_GPIO(GPIO_PB12, PB12_DATA),
-	PINMUX_GPIO(GPIO_PB11, PB11_DATA),
-	PINMUX_GPIO(GPIO_PB10, PB10_DATA),
-	PINMUX_GPIO(GPIO_PB9, PB9_DATA),
-	PINMUX_GPIO(GPIO_PB8, PB8_DATA),
-	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
-	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
-	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
-	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
-	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
-	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
-	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
-	PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+	PINMUX_GPIO(PB12),
+	PINMUX_GPIO(PB11),
+	PINMUX_GPIO(PB10),
+	PINMUX_GPIO(PB9),
+	PINMUX_GPIO(PB8),
+	PINMUX_GPIO(PB7),
+	PINMUX_GPIO(PB6),
+	PINMUX_GPIO(PB5),
+	PINMUX_GPIO(PB4),
+	PINMUX_GPIO(PB3),
+	PINMUX_GPIO(PB2),
+	PINMUX_GPIO(PB1),
+	PINMUX_GPIO(PB0),
 
 	/* PC */
-	PINMUX_GPIO(GPIO_PC14, PC14_DATA),
-	PINMUX_GPIO(GPIO_PC13, PC13_DATA),
-	PINMUX_GPIO(GPIO_PC12, PC12_DATA),
-	PINMUX_GPIO(GPIO_PC11, PC11_DATA),
-	PINMUX_GPIO(GPIO_PC10, PC10_DATA),
-	PINMUX_GPIO(GPIO_PC9, PC9_DATA),
-	PINMUX_GPIO(GPIO_PC8, PC8_DATA),
-	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
-	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
-	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
-	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
-	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
-	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
-	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
-	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+	PINMUX_GPIO(PC14),
+	PINMUX_GPIO(PC13),
+	PINMUX_GPIO(PC12),
+	PINMUX_GPIO(PC11),
+	PINMUX_GPIO(PC10),
+	PINMUX_GPIO(PC9),
+	PINMUX_GPIO(PC8),
+	PINMUX_GPIO(PC7),
+	PINMUX_GPIO(PC6),
+	PINMUX_GPIO(PC5),
+	PINMUX_GPIO(PC4),
+	PINMUX_GPIO(PC3),
+	PINMUX_GPIO(PC2),
+	PINMUX_GPIO(PC1),
+	PINMUX_GPIO(PC0),
 
 	/* PD */
-	PINMUX_GPIO(GPIO_PD15, PD15_DATA),
-	PINMUX_GPIO(GPIO_PD14, PD14_DATA),
-	PINMUX_GPIO(GPIO_PD13, PD13_DATA),
-	PINMUX_GPIO(GPIO_PD12, PD12_DATA),
-	PINMUX_GPIO(GPIO_PD11, PD11_DATA),
-	PINMUX_GPIO(GPIO_PD10, PD10_DATA),
-	PINMUX_GPIO(GPIO_PD9, PD9_DATA),
-	PINMUX_GPIO(GPIO_PD8, PD8_DATA),
-	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
-	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
-	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
-	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
-	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
-	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
-	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
-	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+	PINMUX_GPIO(PD15),
+	PINMUX_GPIO(PD14),
+	PINMUX_GPIO(PD13),
+	PINMUX_GPIO(PD12),
+	PINMUX_GPIO(PD11),
+	PINMUX_GPIO(PD10),
+	PINMUX_GPIO(PD9),
+	PINMUX_GPIO(PD8),
+	PINMUX_GPIO(PD7),
+	PINMUX_GPIO(PD6),
+	PINMUX_GPIO(PD5),
+	PINMUX_GPIO(PD4),
+	PINMUX_GPIO(PD3),
+	PINMUX_GPIO(PD2),
+	PINMUX_GPIO(PD1),
+	PINMUX_GPIO(PD0),
 
 	/* PE */
-	PINMUX_GPIO(GPIO_PE15, PE15_DATA),
-	PINMUX_GPIO(GPIO_PE14, PE14_DATA),
-	PINMUX_GPIO(GPIO_PE13, PE13_DATA),
-	PINMUX_GPIO(GPIO_PE12, PE12_DATA),
-	PINMUX_GPIO(GPIO_PE11, PE11_DATA),
-	PINMUX_GPIO(GPIO_PE10, PE10_DATA),
-	PINMUX_GPIO(GPIO_PE9, PE9_DATA),
-	PINMUX_GPIO(GPIO_PE8, PE8_DATA),
-	PINMUX_GPIO(GPIO_PE7, PE7_DATA),
-	PINMUX_GPIO(GPIO_PE6, PE6_DATA),
-	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
-	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
-	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
-	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
-	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
-	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+	PINMUX_GPIO(PE15),
+	PINMUX_GPIO(PE14),
+	PINMUX_GPIO(PE13),
+	PINMUX_GPIO(PE12),
+	PINMUX_GPIO(PE11),
+	PINMUX_GPIO(PE10),
+	PINMUX_GPIO(PE9),
+	PINMUX_GPIO(PE8),
+	PINMUX_GPIO(PE7),
+	PINMUX_GPIO(PE6),
+	PINMUX_GPIO(PE5),
+	PINMUX_GPIO(PE4),
+	PINMUX_GPIO(PE3),
+	PINMUX_GPIO(PE2),
+	PINMUX_GPIO(PE1),
+	PINMUX_GPIO(PE0),
 
 	/* PF */
-	PINMUX_GPIO(GPIO_PF30, PF30_DATA),
-	PINMUX_GPIO(GPIO_PF29, PF29_DATA),
-	PINMUX_GPIO(GPIO_PF28, PF28_DATA),
-	PINMUX_GPIO(GPIO_PF27, PF27_DATA),
-	PINMUX_GPIO(GPIO_PF26, PF26_DATA),
-	PINMUX_GPIO(GPIO_PF25, PF25_DATA),
-	PINMUX_GPIO(GPIO_PF24, PF24_DATA),
-	PINMUX_GPIO(GPIO_PF23, PF23_DATA),
-	PINMUX_GPIO(GPIO_PF22, PF22_DATA),
-	PINMUX_GPIO(GPIO_PF21, PF21_DATA),
-	PINMUX_GPIO(GPIO_PF20, PF20_DATA),
-	PINMUX_GPIO(GPIO_PF19, PF19_DATA),
-	PINMUX_GPIO(GPIO_PF18, PF18_DATA),
-	PINMUX_GPIO(GPIO_PF17, PF17_DATA),
-	PINMUX_GPIO(GPIO_PF16, PF16_DATA),
-	PINMUX_GPIO(GPIO_PF15, PF15_DATA),
-	PINMUX_GPIO(GPIO_PF14, PF14_DATA),
-	PINMUX_GPIO(GPIO_PF13, PF13_DATA),
-	PINMUX_GPIO(GPIO_PF12, PF12_DATA),
-	PINMUX_GPIO(GPIO_PF11, PF11_DATA),
-	PINMUX_GPIO(GPIO_PF10, PF10_DATA),
-	PINMUX_GPIO(GPIO_PF9, PF9_DATA),
-	PINMUX_GPIO(GPIO_PF8, PF8_DATA),
-	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
-	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
-	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
-	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
-	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
-	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
-	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
-	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+	PINMUX_GPIO(PF30),
+	PINMUX_GPIO(PF29),
+	PINMUX_GPIO(PF28),
+	PINMUX_GPIO(PF27),
+	PINMUX_GPIO(PF26),
+	PINMUX_GPIO(PF25),
+	PINMUX_GPIO(PF24),
+	PINMUX_GPIO(PF23),
+	PINMUX_GPIO(PF22),
+	PINMUX_GPIO(PF21),
+	PINMUX_GPIO(PF20),
+	PINMUX_GPIO(PF19),
+	PINMUX_GPIO(PF18),
+	PINMUX_GPIO(PF17),
+	PINMUX_GPIO(PF16),
+	PINMUX_GPIO(PF15),
+	PINMUX_GPIO(PF14),
+	PINMUX_GPIO(PF13),
+	PINMUX_GPIO(PF12),
+	PINMUX_GPIO(PF11),
+	PINMUX_GPIO(PF10),
+	PINMUX_GPIO(PF9),
+	PINMUX_GPIO(PF8),
+	PINMUX_GPIO(PF7),
+	PINMUX_GPIO(PF6),
+	PINMUX_GPIO(PF5),
+	PINMUX_GPIO(PF4),
+	PINMUX_GPIO(PF3),
+	PINMUX_GPIO(PF2),
+	PINMUX_GPIO(PF1),
+	PINMUX_GPIO(PF0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7264.c b/drivers/pinctrl/sh-pfc/pfc-sh7264.c
index 2846752..673a595 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7264.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7264.c
@@ -604,8 +604,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
-
+static const u16 pinmux_data[] = {
 	/* Port A */
 	PINMUX_DATA(PA3_DATA, PA3_IN),
 	PINMUX_DATA(PA2_DATA, PA2_IN),
@@ -1073,149 +1072,148 @@
 };
 
 static struct sh_pfc_pin pinmux_pins[] = {
-
 	/* Port A */
-	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
-	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
-	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
-	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+	PINMUX_GPIO(PA3),
+	PINMUX_GPIO(PA2),
+	PINMUX_GPIO(PA1),
+	PINMUX_GPIO(PA0),
 
 	/* Port B */
-	PINMUX_GPIO(GPIO_PB22, PB22_DATA),
-	PINMUX_GPIO(GPIO_PB21, PB21_DATA),
-	PINMUX_GPIO(GPIO_PB20, PB20_DATA),
-	PINMUX_GPIO(GPIO_PB19, PB19_DATA),
-	PINMUX_GPIO(GPIO_PB18, PB18_DATA),
-	PINMUX_GPIO(GPIO_PB17, PB17_DATA),
-	PINMUX_GPIO(GPIO_PB16, PB16_DATA),
-	PINMUX_GPIO(GPIO_PB15, PB15_DATA),
-	PINMUX_GPIO(GPIO_PB14, PB14_DATA),
-	PINMUX_GPIO(GPIO_PB13, PB13_DATA),
-	PINMUX_GPIO(GPIO_PB12, PB12_DATA),
-	PINMUX_GPIO(GPIO_PB11, PB11_DATA),
-	PINMUX_GPIO(GPIO_PB10, PB10_DATA),
-	PINMUX_GPIO(GPIO_PB9, PB9_DATA),
-	PINMUX_GPIO(GPIO_PB8, PB8_DATA),
-	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
-	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
-	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
-	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
-	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
-	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
-	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+	PINMUX_GPIO(PB22),
+	PINMUX_GPIO(PB21),
+	PINMUX_GPIO(PB20),
+	PINMUX_GPIO(PB19),
+	PINMUX_GPIO(PB18),
+	PINMUX_GPIO(PB17),
+	PINMUX_GPIO(PB16),
+	PINMUX_GPIO(PB15),
+	PINMUX_GPIO(PB14),
+	PINMUX_GPIO(PB13),
+	PINMUX_GPIO(PB12),
+	PINMUX_GPIO(PB11),
+	PINMUX_GPIO(PB10),
+	PINMUX_GPIO(PB9),
+	PINMUX_GPIO(PB8),
+	PINMUX_GPIO(PB7),
+	PINMUX_GPIO(PB6),
+	PINMUX_GPIO(PB5),
+	PINMUX_GPIO(PB4),
+	PINMUX_GPIO(PB3),
+	PINMUX_GPIO(PB2),
+	PINMUX_GPIO(PB1),
 
 	/* Port C */
-	PINMUX_GPIO(GPIO_PC10, PC10_DATA),
-	PINMUX_GPIO(GPIO_PC9, PC9_DATA),
-	PINMUX_GPIO(GPIO_PC8, PC8_DATA),
-	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
-	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
-	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
-	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
-	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
-	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
-	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
-	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+	PINMUX_GPIO(PC10),
+	PINMUX_GPIO(PC9),
+	PINMUX_GPIO(PC8),
+	PINMUX_GPIO(PC7),
+	PINMUX_GPIO(PC6),
+	PINMUX_GPIO(PC5),
+	PINMUX_GPIO(PC4),
+	PINMUX_GPIO(PC3),
+	PINMUX_GPIO(PC2),
+	PINMUX_GPIO(PC1),
+	PINMUX_GPIO(PC0),
 
 	/* Port D */
-	PINMUX_GPIO(GPIO_PD15, PD15_DATA),
-	PINMUX_GPIO(GPIO_PD14, PD14_DATA),
-	PINMUX_GPIO(GPIO_PD13, PD13_DATA),
-	PINMUX_GPIO(GPIO_PD12, PD12_DATA),
-	PINMUX_GPIO(GPIO_PD11, PD11_DATA),
-	PINMUX_GPIO(GPIO_PD10, PD10_DATA),
-	PINMUX_GPIO(GPIO_PD9, PD9_DATA),
-	PINMUX_GPIO(GPIO_PD8, PD8_DATA),
-	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
-	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
-	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
-	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
-	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
-	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
-	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
-	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+	PINMUX_GPIO(PD15),
+	PINMUX_GPIO(PD14),
+	PINMUX_GPIO(PD13),
+	PINMUX_GPIO(PD12),
+	PINMUX_GPIO(PD11),
+	PINMUX_GPIO(PD10),
+	PINMUX_GPIO(PD9),
+	PINMUX_GPIO(PD8),
+	PINMUX_GPIO(PD7),
+	PINMUX_GPIO(PD6),
+	PINMUX_GPIO(PD5),
+	PINMUX_GPIO(PD4),
+	PINMUX_GPIO(PD3),
+	PINMUX_GPIO(PD2),
+	PINMUX_GPIO(PD1),
+	PINMUX_GPIO(PD0),
 
 	/* Port E */
-	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
-	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
-	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
-	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
-	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
-	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+	PINMUX_GPIO(PE5),
+	PINMUX_GPIO(PE4),
+	PINMUX_GPIO(PE3),
+	PINMUX_GPIO(PE2),
+	PINMUX_GPIO(PE1),
+	PINMUX_GPIO(PE0),
 
 	/* Port F */
-	PINMUX_GPIO(GPIO_PF12, PF12_DATA),
-	PINMUX_GPIO(GPIO_PF11, PF11_DATA),
-	PINMUX_GPIO(GPIO_PF10, PF10_DATA),
-	PINMUX_GPIO(GPIO_PF9, PF9_DATA),
-	PINMUX_GPIO(GPIO_PF8, PF8_DATA),
-	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
-	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
-	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
-	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
-	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
-	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
-	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
-	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+	PINMUX_GPIO(PF12),
+	PINMUX_GPIO(PF11),
+	PINMUX_GPIO(PF10),
+	PINMUX_GPIO(PF9),
+	PINMUX_GPIO(PF8),
+	PINMUX_GPIO(PF7),
+	PINMUX_GPIO(PF6),
+	PINMUX_GPIO(PF5),
+	PINMUX_GPIO(PF4),
+	PINMUX_GPIO(PF3),
+	PINMUX_GPIO(PF2),
+	PINMUX_GPIO(PF1),
+	PINMUX_GPIO(PF0),
 
 	/* Port G */
-	PINMUX_GPIO(GPIO_PG24, PG24_DATA),
-	PINMUX_GPIO(GPIO_PG23, PG23_DATA),
-	PINMUX_GPIO(GPIO_PG22, PG22_DATA),
-	PINMUX_GPIO(GPIO_PG21, PG21_DATA),
-	PINMUX_GPIO(GPIO_PG20, PG20_DATA),
-	PINMUX_GPIO(GPIO_PG19, PG19_DATA),
-	PINMUX_GPIO(GPIO_PG18, PG18_DATA),
-	PINMUX_GPIO(GPIO_PG17, PG17_DATA),
-	PINMUX_GPIO(GPIO_PG16, PG16_DATA),
-	PINMUX_GPIO(GPIO_PG15, PG15_DATA),
-	PINMUX_GPIO(GPIO_PG14, PG14_DATA),
-	PINMUX_GPIO(GPIO_PG13, PG13_DATA),
-	PINMUX_GPIO(GPIO_PG12, PG12_DATA),
-	PINMUX_GPIO(GPIO_PG11, PG11_DATA),
-	PINMUX_GPIO(GPIO_PG10, PG10_DATA),
-	PINMUX_GPIO(GPIO_PG9, PG9_DATA),
-	PINMUX_GPIO(GPIO_PG8, PG8_DATA),
-	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
-	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
-	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
-	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
-	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
-	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
-	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
-	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+	PINMUX_GPIO(PG24),
+	PINMUX_GPIO(PG23),
+	PINMUX_GPIO(PG22),
+	PINMUX_GPIO(PG21),
+	PINMUX_GPIO(PG20),
+	PINMUX_GPIO(PG19),
+	PINMUX_GPIO(PG18),
+	PINMUX_GPIO(PG17),
+	PINMUX_GPIO(PG16),
+	PINMUX_GPIO(PG15),
+	PINMUX_GPIO(PG14),
+	PINMUX_GPIO(PG13),
+	PINMUX_GPIO(PG12),
+	PINMUX_GPIO(PG11),
+	PINMUX_GPIO(PG10),
+	PINMUX_GPIO(PG9),
+	PINMUX_GPIO(PG8),
+	PINMUX_GPIO(PG7),
+	PINMUX_GPIO(PG6),
+	PINMUX_GPIO(PG5),
+	PINMUX_GPIO(PG4),
+	PINMUX_GPIO(PG3),
+	PINMUX_GPIO(PG2),
+	PINMUX_GPIO(PG1),
+	PINMUX_GPIO(PG0),
 
 	/* Port H - Port H does not have a Data Register */
 
 	/* Port I - not on device */
 
 	/* Port J */
-	PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
-	PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
-	PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
-	PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
-	PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
-	PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
-	PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
-	PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
-	PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
-	PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
-	PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
-	PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+	PINMUX_GPIO(PJ11),
+	PINMUX_GPIO(PJ10),
+	PINMUX_GPIO(PJ9),
+	PINMUX_GPIO(PJ8),
+	PINMUX_GPIO(PJ7),
+	PINMUX_GPIO(PJ6),
+	PINMUX_GPIO(PJ5),
+	PINMUX_GPIO(PJ4),
+	PINMUX_GPIO(PJ3),
+	PINMUX_GPIO(PJ2),
+	PINMUX_GPIO(PJ1),
+	PINMUX_GPIO(PJ0),
 
 	/* Port K */
-	PINMUX_GPIO(GPIO_PK11, PK11_DATA),
-	PINMUX_GPIO(GPIO_PK10, PK10_DATA),
-	PINMUX_GPIO(GPIO_PK9, PK9_DATA),
-	PINMUX_GPIO(GPIO_PK8, PK8_DATA),
-	PINMUX_GPIO(GPIO_PK7, PK7_DATA),
-	PINMUX_GPIO(GPIO_PK6, PK6_DATA),
-	PINMUX_GPIO(GPIO_PK5, PK5_DATA),
-	PINMUX_GPIO(GPIO_PK4, PK4_DATA),
-	PINMUX_GPIO(GPIO_PK3, PK3_DATA),
-	PINMUX_GPIO(GPIO_PK2, PK2_DATA),
-	PINMUX_GPIO(GPIO_PK1, PK1_DATA),
-	PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+	PINMUX_GPIO(PK11),
+	PINMUX_GPIO(PK10),
+	PINMUX_GPIO(PK9),
+	PINMUX_GPIO(PK8),
+	PINMUX_GPIO(PK7),
+	PINMUX_GPIO(PK6),
+	PINMUX_GPIO(PK5),
+	PINMUX_GPIO(PK4),
+	PINMUX_GPIO(PK3),
+	PINMUX_GPIO(PK2),
+	PINMUX_GPIO(PK1),
+	PINMUX_GPIO(PK0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c
index 4c401a7..a19b60f 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7269.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c
@@ -781,8 +781,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
-
+static const u16 pinmux_data[] = {
 	/* Port A */
 	PINMUX_DATA(PA1_DATA, PA1_IN),
 	PINMUX_DATA(PA0_DATA, PA0_IN),
@@ -1454,165 +1453,165 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* Port A */
-	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
-	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+	PINMUX_GPIO(PA1),
+	PINMUX_GPIO(PA0),
 
 	/* Port B */
-	PINMUX_GPIO(GPIO_PB22, PB22_DATA),
-	PINMUX_GPIO(GPIO_PB21, PB21_DATA),
-	PINMUX_GPIO(GPIO_PB20, PB20_DATA),
-	PINMUX_GPIO(GPIO_PB19, PB19_DATA),
-	PINMUX_GPIO(GPIO_PB18, PB18_DATA),
-	PINMUX_GPIO(GPIO_PB17, PB17_DATA),
-	PINMUX_GPIO(GPIO_PB16, PB16_DATA),
-	PINMUX_GPIO(GPIO_PB15, PB15_DATA),
-	PINMUX_GPIO(GPIO_PB14, PB14_DATA),
-	PINMUX_GPIO(GPIO_PB13, PB13_DATA),
-	PINMUX_GPIO(GPIO_PB12, PB12_DATA),
-	PINMUX_GPIO(GPIO_PB11, PB11_DATA),
-	PINMUX_GPIO(GPIO_PB10, PB10_DATA),
-	PINMUX_GPIO(GPIO_PB9, PB9_DATA),
-	PINMUX_GPIO(GPIO_PB8, PB8_DATA),
-	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
-	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
-	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
-	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
-	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
-	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
-	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+	PINMUX_GPIO(PB22),
+	PINMUX_GPIO(PB21),
+	PINMUX_GPIO(PB20),
+	PINMUX_GPIO(PB19),
+	PINMUX_GPIO(PB18),
+	PINMUX_GPIO(PB17),
+	PINMUX_GPIO(PB16),
+	PINMUX_GPIO(PB15),
+	PINMUX_GPIO(PB14),
+	PINMUX_GPIO(PB13),
+	PINMUX_GPIO(PB12),
+	PINMUX_GPIO(PB11),
+	PINMUX_GPIO(PB10),
+	PINMUX_GPIO(PB9),
+	PINMUX_GPIO(PB8),
+	PINMUX_GPIO(PB7),
+	PINMUX_GPIO(PB6),
+	PINMUX_GPIO(PB5),
+	PINMUX_GPIO(PB4),
+	PINMUX_GPIO(PB3),
+	PINMUX_GPIO(PB2),
+	PINMUX_GPIO(PB1),
 
 	/* Port C */
-	PINMUX_GPIO(GPIO_PC8, PC8_DATA),
-	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
-	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
-	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
-	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
-	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
-	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
-	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
-	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+	PINMUX_GPIO(PC8),
+	PINMUX_GPIO(PC7),
+	PINMUX_GPIO(PC6),
+	PINMUX_GPIO(PC5),
+	PINMUX_GPIO(PC4),
+	PINMUX_GPIO(PC3),
+	PINMUX_GPIO(PC2),
+	PINMUX_GPIO(PC1),
+	PINMUX_GPIO(PC0),
 
 	/* Port D */
-	PINMUX_GPIO(GPIO_PD15, PD15_DATA),
-	PINMUX_GPIO(GPIO_PD14, PD14_DATA),
-	PINMUX_GPIO(GPIO_PD13, PD13_DATA),
-	PINMUX_GPIO(GPIO_PD12, PD12_DATA),
-	PINMUX_GPIO(GPIO_PD11, PD11_DATA),
-	PINMUX_GPIO(GPIO_PD10, PD10_DATA),
-	PINMUX_GPIO(GPIO_PD9, PD9_DATA),
-	PINMUX_GPIO(GPIO_PD8, PD8_DATA),
-	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
-	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
-	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
-	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
-	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
-	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
-	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
-	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+	PINMUX_GPIO(PD15),
+	PINMUX_GPIO(PD14),
+	PINMUX_GPIO(PD13),
+	PINMUX_GPIO(PD12),
+	PINMUX_GPIO(PD11),
+	PINMUX_GPIO(PD10),
+	PINMUX_GPIO(PD9),
+	PINMUX_GPIO(PD8),
+	PINMUX_GPIO(PD7),
+	PINMUX_GPIO(PD6),
+	PINMUX_GPIO(PD5),
+	PINMUX_GPIO(PD4),
+	PINMUX_GPIO(PD3),
+	PINMUX_GPIO(PD2),
+	PINMUX_GPIO(PD1),
+	PINMUX_GPIO(PD0),
 
 	/* Port E */
-	PINMUX_GPIO(GPIO_PE7, PE7_DATA),
-	PINMUX_GPIO(GPIO_PE6, PE6_DATA),
-	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
-	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
-	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
-	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
-	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
-	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+	PINMUX_GPIO(PE7),
+	PINMUX_GPIO(PE6),
+	PINMUX_GPIO(PE5),
+	PINMUX_GPIO(PE4),
+	PINMUX_GPIO(PE3),
+	PINMUX_GPIO(PE2),
+	PINMUX_GPIO(PE1),
+	PINMUX_GPIO(PE0),
 
 	/* Port F */
-	PINMUX_GPIO(GPIO_PF23, PF23_DATA),
-	PINMUX_GPIO(GPIO_PF22, PF22_DATA),
-	PINMUX_GPIO(GPIO_PF21, PF21_DATA),
-	PINMUX_GPIO(GPIO_PF20, PF20_DATA),
-	PINMUX_GPIO(GPIO_PF19, PF19_DATA),
-	PINMUX_GPIO(GPIO_PF18, PF18_DATA),
-	PINMUX_GPIO(GPIO_PF17, PF17_DATA),
-	PINMUX_GPIO(GPIO_PF16, PF16_DATA),
-	PINMUX_GPIO(GPIO_PF15, PF15_DATA),
-	PINMUX_GPIO(GPIO_PF14, PF14_DATA),
-	PINMUX_GPIO(GPIO_PF13, PF13_DATA),
-	PINMUX_GPIO(GPIO_PF12, PF12_DATA),
-	PINMUX_GPIO(GPIO_PF11, PF11_DATA),
-	PINMUX_GPIO(GPIO_PF10, PF10_DATA),
-	PINMUX_GPIO(GPIO_PF9, PF9_DATA),
-	PINMUX_GPIO(GPIO_PF8, PF8_DATA),
-	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
-	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
-	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
-	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
-	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
-	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
-	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
-	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+	PINMUX_GPIO(PF23),
+	PINMUX_GPIO(PF22),
+	PINMUX_GPIO(PF21),
+	PINMUX_GPIO(PF20),
+	PINMUX_GPIO(PF19),
+	PINMUX_GPIO(PF18),
+	PINMUX_GPIO(PF17),
+	PINMUX_GPIO(PF16),
+	PINMUX_GPIO(PF15),
+	PINMUX_GPIO(PF14),
+	PINMUX_GPIO(PF13),
+	PINMUX_GPIO(PF12),
+	PINMUX_GPIO(PF11),
+	PINMUX_GPIO(PF10),
+	PINMUX_GPIO(PF9),
+	PINMUX_GPIO(PF8),
+	PINMUX_GPIO(PF7),
+	PINMUX_GPIO(PF6),
+	PINMUX_GPIO(PF5),
+	PINMUX_GPIO(PF4),
+	PINMUX_GPIO(PF3),
+	PINMUX_GPIO(PF2),
+	PINMUX_GPIO(PF1),
+	PINMUX_GPIO(PF0),
 
 	/* Port G */
-	PINMUX_GPIO(GPIO_PG27, PG27_DATA),
-	PINMUX_GPIO(GPIO_PG26, PG26_DATA),
-	PINMUX_GPIO(GPIO_PG25, PG25_DATA),
-	PINMUX_GPIO(GPIO_PG24, PG24_DATA),
-	PINMUX_GPIO(GPIO_PG23, PG23_DATA),
-	PINMUX_GPIO(GPIO_PG22, PG22_DATA),
-	PINMUX_GPIO(GPIO_PG21, PG21_DATA),
-	PINMUX_GPIO(GPIO_PG20, PG20_DATA),
-	PINMUX_GPIO(GPIO_PG19, PG19_DATA),
-	PINMUX_GPIO(GPIO_PG18, PG18_DATA),
-	PINMUX_GPIO(GPIO_PG17, PG17_DATA),
-	PINMUX_GPIO(GPIO_PG16, PG16_DATA),
-	PINMUX_GPIO(GPIO_PG15, PG15_DATA),
-	PINMUX_GPIO(GPIO_PG14, PG14_DATA),
-	PINMUX_GPIO(GPIO_PG13, PG13_DATA),
-	PINMUX_GPIO(GPIO_PG12, PG12_DATA),
-	PINMUX_GPIO(GPIO_PG11, PG11_DATA),
-	PINMUX_GPIO(GPIO_PG10, PG10_DATA),
-	PINMUX_GPIO(GPIO_PG9, PG9_DATA),
-	PINMUX_GPIO(GPIO_PG8, PG8_DATA),
-	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
-	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
-	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
-	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
-	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
-	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
-	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
-	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+	PINMUX_GPIO(PG27),
+	PINMUX_GPIO(PG26),
+	PINMUX_GPIO(PG25),
+	PINMUX_GPIO(PG24),
+	PINMUX_GPIO(PG23),
+	PINMUX_GPIO(PG22),
+	PINMUX_GPIO(PG21),
+	PINMUX_GPIO(PG20),
+	PINMUX_GPIO(PG19),
+	PINMUX_GPIO(PG18),
+	PINMUX_GPIO(PG17),
+	PINMUX_GPIO(PG16),
+	PINMUX_GPIO(PG15),
+	PINMUX_GPIO(PG14),
+	PINMUX_GPIO(PG13),
+	PINMUX_GPIO(PG12),
+	PINMUX_GPIO(PG11),
+	PINMUX_GPIO(PG10),
+	PINMUX_GPIO(PG9),
+	PINMUX_GPIO(PG8),
+	PINMUX_GPIO(PG7),
+	PINMUX_GPIO(PG6),
+	PINMUX_GPIO(PG5),
+	PINMUX_GPIO(PG4),
+	PINMUX_GPIO(PG3),
+	PINMUX_GPIO(PG2),
+	PINMUX_GPIO(PG1),
+	PINMUX_GPIO(PG0),
 
 	/* Port H - Port H does not have a Data Register */
 
 	/* Port I - not on device */
 
 	/* Port J */
-	PINMUX_GPIO(GPIO_PJ31, PJ31_DATA),
-	PINMUX_GPIO(GPIO_PJ30, PJ30_DATA),
-	PINMUX_GPIO(GPIO_PJ29, PJ29_DATA),
-	PINMUX_GPIO(GPIO_PJ28, PJ28_DATA),
-	PINMUX_GPIO(GPIO_PJ27, PJ27_DATA),
-	PINMUX_GPIO(GPIO_PJ26, PJ26_DATA),
-	PINMUX_GPIO(GPIO_PJ25, PJ25_DATA),
-	PINMUX_GPIO(GPIO_PJ24, PJ24_DATA),
-	PINMUX_GPIO(GPIO_PJ23, PJ23_DATA),
-	PINMUX_GPIO(GPIO_PJ22, PJ22_DATA),
-	PINMUX_GPIO(GPIO_PJ21, PJ21_DATA),
-	PINMUX_GPIO(GPIO_PJ20, PJ20_DATA),
-	PINMUX_GPIO(GPIO_PJ19, PJ19_DATA),
-	PINMUX_GPIO(GPIO_PJ18, PJ18_DATA),
-	PINMUX_GPIO(GPIO_PJ17, PJ17_DATA),
-	PINMUX_GPIO(GPIO_PJ16, PJ16_DATA),
-	PINMUX_GPIO(GPIO_PJ15, PJ15_DATA),
-	PINMUX_GPIO(GPIO_PJ14, PJ14_DATA),
-	PINMUX_GPIO(GPIO_PJ13, PJ13_DATA),
-	PINMUX_GPIO(GPIO_PJ12, PJ12_DATA),
-	PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
-	PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
-	PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
-	PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
-	PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
-	PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
-	PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
-	PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
-	PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
-	PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
-	PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
-	PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+	PINMUX_GPIO(PJ31),
+	PINMUX_GPIO(PJ30),
+	PINMUX_GPIO(PJ29),
+	PINMUX_GPIO(PJ28),
+	PINMUX_GPIO(PJ27),
+	PINMUX_GPIO(PJ26),
+	PINMUX_GPIO(PJ25),
+	PINMUX_GPIO(PJ24),
+	PINMUX_GPIO(PJ23),
+	PINMUX_GPIO(PJ22),
+	PINMUX_GPIO(PJ21),
+	PINMUX_GPIO(PJ20),
+	PINMUX_GPIO(PJ19),
+	PINMUX_GPIO(PJ18),
+	PINMUX_GPIO(PJ17),
+	PINMUX_GPIO(PJ16),
+	PINMUX_GPIO(PJ15),
+	PINMUX_GPIO(PJ14),
+	PINMUX_GPIO(PJ13),
+	PINMUX_GPIO(PJ12),
+	PINMUX_GPIO(PJ11),
+	PINMUX_GPIO(PJ10),
+	PINMUX_GPIO(PJ9),
+	PINMUX_GPIO(PJ8),
+	PINMUX_GPIO(PJ7),
+	PINMUX_GPIO(PJ6),
+	PINMUX_GPIO(PJ5),
+	PINMUX_GPIO(PJ4),
+	PINMUX_GPIO(PJ3),
+	PINMUX_GPIO(PJ2),
+	PINMUX_GPIO(PJ1),
+	PINMUX_GPIO(PJ0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7372.c b/drivers/pinctrl/sh-pfc/pfc-sh7372.c
index 6dfb187..70b522d 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7372.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7372.c
@@ -23,27 +23,18 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/pinctrl/pinconf-generic.h>
-
-#include <mach/irqs.h>
-#include <mach/sh7372.h>
+#include <linux/sh_intc.h>
 
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, pfx, sfx) \
-	PORT_10(fn, pfx, sfx),		PORT_90(fn, pfx, sfx), \
-	PORT_10(fn, pfx##10, sfx),	PORT_10(fn, pfx##11, sfx), \
-	PORT_10(fn, pfx##12, sfx),	PORT_10(fn, pfx##13, sfx), \
-	PORT_10(fn, pfx##14, sfx),	PORT_10(fn, pfx##15, sfx), \
-	PORT_10(fn, pfx##16, sfx),	PORT_10(fn, pfx##17, sfx), \
-	PORT_10(fn, pfx##18, sfx),	PORT_1(fn, pfx##190, sfx)
-
-#undef _GPIO_PORT
-#define _GPIO_PORT(gpio, sfx)						\
-	[gpio] = {							\
-		.name = __stringify(PORT##gpio),			\
-		.enum_id = PORT##gpio##_DATA,				\
-	}
+#define CPU_ALL_PORT(fn, pfx, sfx)					\
+	PORT_10(0,  fn, pfx, sfx),	PORT_90(0,  fn, pfx, sfx),	\
+	PORT_10(100, fn, pfx##10, sfx),	PORT_10(110, fn, pfx##11, sfx),	\
+	PORT_10(120, fn, pfx##12, sfx),	PORT_10(130, fn, pfx##13, sfx),	\
+	PORT_10(140, fn, pfx##14, sfx),	PORT_10(150, fn, pfx##15, sfx),	\
+	PORT_10(160, fn, pfx##16, sfx),	PORT_10(170, fn, pfx##17, sfx),	\
+	PORT_10(180, fn, pfx##18, sfx),	PORT_1(190, fn, pfx##190, sfx)
 
 #define IRQC_PIN_MUX(irq, pin)						\
 static const unsigned int intc_irq##irq##_pins[] = {			\
@@ -391,11 +382,8 @@
 	PINMUX_MARK_END,
 };
 
-#define _PORT_DATA(pfx, sfx)	PORT_DATA_IO(pfx)
-#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_PORT_DATA, , unused)
-
-static const pinmux_enum_t pinmux_data[] = {
-	PINMUX_DATA_GP_ALL(),
+static const u16 pinmux_data[] = {
+	PINMUX_DATA_ALL(),
 
 	/* IRQ */
 	PINMUX_DATA(IRQ0_6_MARK,	PORT6_FN0, 	MSEL1CR_0_0),
@@ -839,13 +827,6 @@
 	PINMUX_DATA(MFIv4_MARK,		MSEL4CR_6_1),
 };
 
-#define SH7372_PIN(pin, cfgs)						\
-	{								\
-		.name = __stringify(PORT##pin),				\
-		.enum_id = PORT##pin##_DATA,				\
-		.configs = cfgs,					\
-	}
-
 #define __I		(SH_PFC_PIN_CFG_INPUT)
 #define __O		(SH_PFC_PIN_CFG_OUTPUT)
 #define __IO		(SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
@@ -853,15 +834,15 @@
 #define __PU		(SH_PFC_PIN_CFG_PULL_UP)
 #define __PUD		(SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
 
-#define SH7372_PIN_I_PD(pin)		SH7372_PIN(pin, __I | __PD)
-#define SH7372_PIN_I_PU(pin)		SH7372_PIN(pin, __I | __PU)
-#define SH7372_PIN_I_PU_PD(pin)		SH7372_PIN(pin, __I | __PUD)
-#define SH7372_PIN_IO(pin)		SH7372_PIN(pin, __IO)
-#define SH7372_PIN_IO_PD(pin)		SH7372_PIN(pin, __IO | __PD)
-#define SH7372_PIN_IO_PU(pin)		SH7372_PIN(pin, __IO | __PU)
-#define SH7372_PIN_IO_PU_PD(pin)	SH7372_PIN(pin, __IO | __PUD)
-#define SH7372_PIN_O(pin)		SH7372_PIN(pin, __O)
-#define SH7372_PIN_O_PU_PD(pin)		SH7372_PIN(pin, __O | __PUD)
+#define SH7372_PIN_I_PD(pin)		SH_PFC_PIN_CFG(pin, __I | __PD)
+#define SH7372_PIN_I_PU(pin)		SH_PFC_PIN_CFG(pin, __I | __PU)
+#define SH7372_PIN_I_PU_PD(pin)		SH_PFC_PIN_CFG(pin, __I | __PUD)
+#define SH7372_PIN_IO(pin)		SH_PFC_PIN_CFG(pin, __IO)
+#define SH7372_PIN_IO_PD(pin)		SH_PFC_PIN_CFG(pin, __IO | __PD)
+#define SH7372_PIN_IO_PU(pin)		SH_PFC_PIN_CFG(pin, __IO | __PU)
+#define SH7372_PIN_IO_PU_PD(pin)	SH_PFC_PIN_CFG(pin, __IO | __PUD)
+#define SH7372_PIN_O(pin)		SH_PFC_PIN_CFG(pin, __O)
+#define SH7372_PIN_O_PU_PD(pin)		SH_PFC_PIN_CFG(pin, __O | __PUD)
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* Table 57-1 (I/O and Pull U/D) */
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index 31f7d0e..7e278a9 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -31,32 +31,32 @@
 #include "core.h"
 #include "sh_pfc.h"
 
-#define CPU_ALL_PORT(fn, pfx, sfx)				\
-	PORT_10(fn, pfx,    sfx), PORT_90(fn, pfx, sfx),	\
-	PORT_10(fn, pfx##10, sfx),				\
-	PORT_1(fn, pfx##110, sfx), PORT_1(fn, pfx##111, sfx),	\
-	PORT_1(fn, pfx##112, sfx), PORT_1(fn, pfx##113, sfx),	\
-	PORT_1(fn, pfx##114, sfx), PORT_1(fn, pfx##115, sfx),	\
-	PORT_1(fn, pfx##116, sfx), PORT_1(fn, pfx##117, sfx),	\
-	PORT_1(fn, pfx##118, sfx),				\
-	PORT_1(fn, pfx##128, sfx), PORT_1(fn, pfx##129, sfx),	\
-	PORT_10(fn, pfx##13, sfx), PORT_10(fn, pfx##14, sfx),	\
-	PORT_10(fn, pfx##15, sfx),				\
-	PORT_1(fn, pfx##160, sfx), PORT_1(fn, pfx##161, sfx),	\
-	PORT_1(fn, pfx##162, sfx), PORT_1(fn, pfx##163, sfx),	\
-	PORT_1(fn, pfx##164, sfx),				\
-	PORT_1(fn, pfx##192, sfx), PORT_1(fn, pfx##193, sfx),	\
-	PORT_1(fn, pfx##194, sfx), PORT_1(fn, pfx##195, sfx),	\
-	PORT_1(fn, pfx##196, sfx), PORT_1(fn, pfx##197, sfx),	\
-	PORT_1(fn, pfx##198, sfx), PORT_1(fn, pfx##199, sfx),	\
-	PORT_10(fn, pfx##20, sfx), PORT_10(fn, pfx##21, sfx),	\
-	PORT_10(fn, pfx##22, sfx), PORT_10(fn, pfx##23, sfx),	\
-	PORT_10(fn, pfx##24, sfx), PORT_10(fn, pfx##25, sfx),	\
-	PORT_10(fn, pfx##26, sfx), PORT_10(fn, pfx##27, sfx),	\
-	PORT_1(fn, pfx##280, sfx), PORT_1(fn, pfx##281, sfx),	\
-	PORT_1(fn, pfx##282, sfx),				\
-	PORT_1(fn, pfx##288, sfx), PORT_1(fn, pfx##289, sfx),	\
-	PORT_10(fn, pfx##29, sfx), PORT_10(fn, pfx##30, sfx)
+#define CPU_ALL_PORT(fn, pfx, sfx)					\
+	PORT_10(0,  fn, pfx, sfx), PORT_90(0, fn, pfx, sfx),		\
+	PORT_10(100, fn, pfx##10, sfx),					\
+	PORT_1(110, fn, pfx##110, sfx), PORT_1(111, fn, pfx##111, sfx),	\
+	PORT_1(112, fn, pfx##112, sfx), PORT_1(113, fn, pfx##113, sfx),	\
+	PORT_1(114, fn, pfx##114, sfx), PORT_1(115, fn, pfx##115, sfx),	\
+	PORT_1(116, fn, pfx##116, sfx), PORT_1(117, fn, pfx##117, sfx),	\
+	PORT_1(118, fn, pfx##118, sfx),					\
+	PORT_1(128, fn, pfx##128, sfx), PORT_1(129, fn, pfx##129, sfx),	\
+	PORT_10(130, fn, pfx##13, sfx), PORT_10(140, fn, pfx##14, sfx),	\
+	PORT_10(150, fn, pfx##15, sfx),					\
+	PORT_1(160, fn, pfx##160, sfx), PORT_1(161, fn, pfx##161, sfx),	\
+	PORT_1(162, fn, pfx##162, sfx), PORT_1(163, fn, pfx##163, sfx),	\
+	PORT_1(164, fn, pfx##164, sfx),					\
+	PORT_1(192, fn, pfx##192, sfx), PORT_1(193, fn, pfx##193, sfx),	\
+	PORT_1(194, fn, pfx##194, sfx), PORT_1(195, fn, pfx##195, sfx),	\
+	PORT_1(196, fn, pfx##196, sfx), PORT_1(197, fn, pfx##197, sfx),	\
+	PORT_1(198, fn, pfx##198, sfx), PORT_1(199, fn, pfx##199, sfx),	\
+	PORT_10(200, fn, pfx##20, sfx), PORT_10(210, fn, pfx##21, sfx),	\
+	PORT_10(220, fn, pfx##22, sfx), PORT_10(230, fn, pfx##23, sfx),	\
+	PORT_10(240, fn, pfx##24, sfx), PORT_10(250, fn, pfx##25, sfx),	\
+	PORT_10(260, fn, pfx##26, sfx), PORT_10(270, fn, pfx##27, sfx),	\
+	PORT_1(280, fn, pfx##280, sfx), PORT_1(281, fn, pfx##281, sfx),	\
+	PORT_1(282, fn, pfx##282, sfx),					\
+	PORT_1(288, fn, pfx##288, sfx), PORT_1(289, fn, pfx##289, sfx),	\
+	PORT_10(290, fn, pfx##29, sfx), PORT_10(300, fn, pfx##30, sfx)
 
 enum {
 	PINMUX_RESERVED = 0,
@@ -466,12 +466,9 @@
 	PINMUX_MARK_END,
 };
 
-#define _PORT_DATA(pfx, sfx)	PORT_DATA_IO(pfx)
-#define PINMUX_DATA_GP_ALL()    CPU_ALL_PORT(_PORT_DATA, , unused)
-
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* specify valid pin states for each pin in GPIO mode */
-	PINMUX_DATA_GP_ALL(),
+	PINMUX_DATA_ALL(),
 
 	/* Table 25-1 (Function 0-7) */
 	PINMUX_DATA(VBUS_0_MARK, PORT0_FN1),
@@ -1160,13 +1157,6 @@
 	PINMUX_DATA(EDBGREQ_PU_MARK, MSEL4CR_MSEL1_1),
 };
 
-#define SH73A0_PIN(pin, cfgs)						\
-	{								\
-		.name = __stringify(PORT##pin),				\
-		.enum_id = PORT##pin##_DATA,				\
-		.configs = cfgs,					\
-	}
-
 #define __I		(SH_PFC_PIN_CFG_INPUT)
 #define __O		(SH_PFC_PIN_CFG_OUTPUT)
 #define __IO		(SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
@@ -1174,14 +1164,20 @@
 #define __PU		(SH_PFC_PIN_CFG_PULL_UP)
 #define __PUD		(SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
 
-#define SH73A0_PIN_I_PD(pin)		SH73A0_PIN(pin, __I | __PD)
-#define SH73A0_PIN_I_PU(pin)		SH73A0_PIN(pin, __I | __PU)
-#define SH73A0_PIN_I_PU_PD(pin)		SH73A0_PIN(pin, __I | __PUD)
-#define SH73A0_PIN_IO(pin)		SH73A0_PIN(pin, __IO)
-#define SH73A0_PIN_IO_PD(pin)		SH73A0_PIN(pin, __IO | __PD)
-#define SH73A0_PIN_IO_PU(pin)		SH73A0_PIN(pin, __IO | __PU)
-#define SH73A0_PIN_IO_PU_PD(pin)	SH73A0_PIN(pin, __IO | __PUD)
-#define SH73A0_PIN_O(pin)		SH73A0_PIN(pin, __O)
+#define SH73A0_PIN_I_PD(pin)		SH_PFC_PIN_CFG(pin, __I | __PD)
+#define SH73A0_PIN_I_PU(pin)		SH_PFC_PIN_CFG(pin, __I | __PU)
+#define SH73A0_PIN_I_PU_PD(pin)		SH_PFC_PIN_CFG(pin, __I | __PUD)
+#define SH73A0_PIN_IO(pin)		SH_PFC_PIN_CFG(pin, __IO)
+#define SH73A0_PIN_IO_PD(pin)		SH_PFC_PIN_CFG(pin, __IO | __PD)
+#define SH73A0_PIN_IO_PU(pin)		SH_PFC_PIN_CFG(pin, __IO | __PU)
+#define SH73A0_PIN_IO_PU_PD(pin)	SH_PFC_PIN_CFG(pin, __IO | __PUD)
+#define SH73A0_PIN_O(pin)		SH_PFC_PIN_CFG(pin, __O)
+
+/* Pin numbers for pins without a corresponding GPIO port number are computed
+ * from the row and column numbers with a 1000 offset to avoid collisions with
+ * GPIO port numbers.
+ */
+#define PIN_NUMBER(row, col)		(1000+((row)-1)*34+(col)-1)
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* Table 25-1 (I/O and Pull U/D) */
@@ -1454,21 +1450,11 @@
 	SH73A0_PIN_O(307),
 	SH73A0_PIN_I_PU(308),
 	SH73A0_PIN_O(309),
-};
 
-static const struct pinmux_range pinmux_ranges[] = {
-	{.begin = 0, .end = 118,},
-	{.begin = 128, .end = 164,},
-	{.begin = 192, .end = 282,},
-	{.begin = 288, .end = 309,},
+	/* Pins not associated with a GPIO port */
+	SH_PFC_PIN_NAMED(6, 26, F26),
 };
 
-/* Pin numbers for pins without a corresponding GPIO port number are computed
- * from the row and column numbers with a 1000 offset to avoid collisions with
- * GPIO port numbers.
- */
-#define PIN_NUMBER(row, col)		(1000+((row)-1)*34+(col)-1)
-
 /* - BSC -------------------------------------------------------------------- */
 static const unsigned int bsc_data_0_7_pins[] = {
 	/* D[0:7] */
@@ -3674,43 +3660,39 @@
 	{ },
 };
 
-/* External IRQ pins mapped at IRQPIN_BASE */
-#define EXT_IRQ16L(n) irq_pin(n)
-#define EXT_IRQ16H(n) irq_pin(n)
-
 static const struct pinmux_irq pinmux_irqs[] = {
-	PINMUX_IRQ(EXT_IRQ16H(19), 9),
-	PINMUX_IRQ(EXT_IRQ16L(1), 10),
-	PINMUX_IRQ(EXT_IRQ16L(0), 11),
-	PINMUX_IRQ(EXT_IRQ16H(18), 13),
-	PINMUX_IRQ(EXT_IRQ16H(20), 14),
-	PINMUX_IRQ(EXT_IRQ16H(21), 15),
-	PINMUX_IRQ(EXT_IRQ16H(31), 26),
-	PINMUX_IRQ(EXT_IRQ16H(30), 27),
-	PINMUX_IRQ(EXT_IRQ16H(29), 28),
-	PINMUX_IRQ(EXT_IRQ16H(22), 40),
-	PINMUX_IRQ(EXT_IRQ16H(23), 53),
-	PINMUX_IRQ(EXT_IRQ16L(10), 54),
-	PINMUX_IRQ(EXT_IRQ16L(9), 56),
-	PINMUX_IRQ(EXT_IRQ16H(26), 115),
-	PINMUX_IRQ(EXT_IRQ16H(27), 116),
-	PINMUX_IRQ(EXT_IRQ16H(28), 117),
-	PINMUX_IRQ(EXT_IRQ16H(24), 118),
-	PINMUX_IRQ(EXT_IRQ16L(6), 147),
-	PINMUX_IRQ(EXT_IRQ16L(2), 149),
-	PINMUX_IRQ(EXT_IRQ16L(7), 150),
-	PINMUX_IRQ(EXT_IRQ16L(12), 156),
-	PINMUX_IRQ(EXT_IRQ16L(4), 159),
-	PINMUX_IRQ(EXT_IRQ16H(25), 164),
-	PINMUX_IRQ(EXT_IRQ16L(8), 223),
-	PINMUX_IRQ(EXT_IRQ16L(3), 224),
-	PINMUX_IRQ(EXT_IRQ16L(5), 227),
-	PINMUX_IRQ(EXT_IRQ16H(17), 234),
-	PINMUX_IRQ(EXT_IRQ16L(11), 238),
-	PINMUX_IRQ(EXT_IRQ16L(13), 239),
-	PINMUX_IRQ(EXT_IRQ16H(16), 249),
-	PINMUX_IRQ(EXT_IRQ16L(14), 251),
-	PINMUX_IRQ(EXT_IRQ16L(9), 308),
+	PINMUX_IRQ(irq_pin(19), 9),
+	PINMUX_IRQ(irq_pin(1), 10),
+	PINMUX_IRQ(irq_pin(0), 11),
+	PINMUX_IRQ(irq_pin(18), 13),
+	PINMUX_IRQ(irq_pin(20), 14),
+	PINMUX_IRQ(irq_pin(21), 15),
+	PINMUX_IRQ(irq_pin(31), 26),
+	PINMUX_IRQ(irq_pin(30), 27),
+	PINMUX_IRQ(irq_pin(29), 28),
+	PINMUX_IRQ(irq_pin(22), 40),
+	PINMUX_IRQ(irq_pin(23), 53),
+	PINMUX_IRQ(irq_pin(10), 54),
+	PINMUX_IRQ(irq_pin(9), 56),
+	PINMUX_IRQ(irq_pin(26), 115),
+	PINMUX_IRQ(irq_pin(27), 116),
+	PINMUX_IRQ(irq_pin(28), 117),
+	PINMUX_IRQ(irq_pin(24), 118),
+	PINMUX_IRQ(irq_pin(6), 147),
+	PINMUX_IRQ(irq_pin(2), 149),
+	PINMUX_IRQ(irq_pin(7), 150),
+	PINMUX_IRQ(irq_pin(12), 156),
+	PINMUX_IRQ(irq_pin(4), 159),
+	PINMUX_IRQ(irq_pin(25), 164),
+	PINMUX_IRQ(irq_pin(8), 223),
+	PINMUX_IRQ(irq_pin(3), 224),
+	PINMUX_IRQ(irq_pin(5), 227),
+	PINMUX_IRQ(irq_pin(17), 234),
+	PINMUX_IRQ(irq_pin(11), 238),
+	PINMUX_IRQ(irq_pin(13), 239),
+	PINMUX_IRQ(irq_pin(16), 249),
+	PINMUX_IRQ(irq_pin(14), 251),
+	PINMUX_IRQ(irq_pin(9), 308),
 };
 
 /* -----------------------------------------------------------------------------
@@ -3905,8 +3887,6 @@
 
 	.pins = pinmux_pins,
 	.nr_pins = ARRAY_SIZE(pinmux_pins),
-	.ranges = pinmux_ranges,
-	.nr_ranges = ARRAY_SIZE(pinmux_ranges),
 	.groups = pinmux_groups,
 	.nr_groups = ARRAY_SIZE(pinmux_groups),
 	.functions = pinmux_functions,
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7720.c b/drivers/pinctrl/sh-pfc/pfc-sh7720.c
index 52e9f6b..7a26809 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7720.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7720.c
@@ -81,36 +81,6 @@
 	PTV4_IN, PTV3_IN, PTV2_IN, PTV1_IN, PTV0_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
-	PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
-	PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
-	PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
-	PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
-	PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
-	PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
-	PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
-	PTE4_IN_PU, PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
-	PTF0_IN_PU,
-	PTG6_IN_PU, PTG5_IN_PU, PTG4_IN_PU,
-	PTG3_IN_PU, PTG2_IN_PU, PTG1_IN_PU, PTG0_IN_PU,
-	PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
-	PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
-	PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
-	PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
-	PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
-	PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU, PTL3_IN_PU,
-	PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
-	PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
-	PTP4_IN_PU, PTP3_IN_PU, PTP2_IN_PU, PTP1_IN_PU, PTP0_IN_PU,
-	PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
-	PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
-	PTS4_IN_PU, PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
-	PTT4_IN_PU, PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
-	PTU4_IN_PU, PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
-	PTV4_IN_PU, PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
 	PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
@@ -262,55 +232,55 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* PTA GPIO */
-	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
-	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
-	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
-	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
-	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
-	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
-	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
-	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
+	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
+	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
+	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT),
+	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT),
+	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT),
+	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT),
+	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT),
 
 	/* PTB GPIO */
-	PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
-	PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
-	PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
-	PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
-	PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
-	PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
-	PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
-	PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
+	PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
+	PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
+	PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
+	PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
+	PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
+	PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
+	PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
+	PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
 
 	/* PTC GPIO */
-	PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
-	PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
-	PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
-	PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
-	PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
-	PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
-	PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
-	PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
+	PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT),
+	PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT),
+	PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT),
+	PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
+	PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
+	PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
+	PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT),
+	PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
 
 	/* PTD GPIO */
-	PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
-	PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
-	PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
-	PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
-	PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
-	PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
-	PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
-	PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
+	PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT),
+	PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT),
+	PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT),
+	PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT),
+	PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT),
+	PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT),
+	PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT),
+	PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
 
 	/* PTE GPIO */
 	PINMUX_DATA(PTE6_DATA, PTE6_IN),
 	PINMUX_DATA(PTE5_DATA, PTE5_IN),
-	PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
-	PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
-	PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
-	PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
-	PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
+	PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
+	PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
+	PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT),
+	PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT),
+	PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT),
 
 	/* PTF GPIO */
 	PINMUX_DATA(PTF6_DATA, PTF6_IN),
@@ -319,102 +289,102 @@
 	PINMUX_DATA(PTF3_DATA, PTF3_IN),
 	PINMUX_DATA(PTF2_DATA, PTF2_IN),
 	PINMUX_DATA(PTF1_DATA, PTF1_IN),
-	PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
+	PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT),
 
 	/* PTG GPIO */
-	PINMUX_DATA(PTG6_DATA, PTG6_IN, PTG6_OUT, PTG6_IN_PU),
-	PINMUX_DATA(PTG5_DATA, PTG5_IN, PTG5_OUT, PTG5_IN_PU),
-	PINMUX_DATA(PTG4_DATA, PTG4_IN, PTG4_OUT, PTG4_IN_PU),
-	PINMUX_DATA(PTG3_DATA, PTG3_IN, PTG3_OUT, PTG3_IN_PU),
-	PINMUX_DATA(PTG2_DATA, PTG2_IN, PTG2_OUT, PTG2_IN_PU),
-	PINMUX_DATA(PTG1_DATA, PTG1_IN, PTG1_OUT, PTG1_IN_PU),
-	PINMUX_DATA(PTG0_DATA, PTG0_IN, PTG0_OUT, PTG0_IN_PU),
+	PINMUX_DATA(PTG6_DATA, PTG6_IN, PTG6_OUT),
+	PINMUX_DATA(PTG5_DATA, PTG5_IN, PTG5_OUT),
+	PINMUX_DATA(PTG4_DATA, PTG4_IN, PTG4_OUT),
+	PINMUX_DATA(PTG3_DATA, PTG3_IN, PTG3_OUT),
+	PINMUX_DATA(PTG2_DATA, PTG2_IN, PTG2_OUT),
+	PINMUX_DATA(PTG1_DATA, PTG1_IN, PTG1_OUT),
+	PINMUX_DATA(PTG0_DATA, PTG0_IN, PTG0_OUT),
 
 	/* PTH GPIO */
-	PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
-	PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
-	PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
-	PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
-	PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
-	PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
-	PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
+	PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT),
+	PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT),
+	PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT),
+	PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT),
+	PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT),
+	PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT),
+	PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT),
 
 	/* PTJ GPIO */
-	PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT, PTJ6_IN_PU),
-	PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT, PTJ5_IN_PU),
-	PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT, PTJ4_IN_PU),
-	PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
-	PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
-	PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
-	PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
+	PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
+	PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
+	PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
+	PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT),
+	PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT),
+	PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT),
+	PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT),
 
 	/* PTK GPIO */
-	PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
-	PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
-	PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
-	PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
+	PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT),
+	PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT),
+	PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT),
+	PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
 
 	/* PTL GPIO */
-	PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
-	PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
-	PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
-	PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
-	PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
+	PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
+	PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
+	PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
+	PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
+	PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT),
 
 	/* PTM GPIO */
-	PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
-	PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
-	PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
-	PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
-	PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
-	PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
-	PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
-	PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
+	PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT),
+	PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT),
+	PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT),
+	PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT),
+	PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT),
+	PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT),
+	PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT),
+	PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
 
 	/* PTP GPIO */
-	PINMUX_DATA(PTP4_DATA, PTP4_IN, PTP4_OUT, PTP4_IN_PU),
-	PINMUX_DATA(PTP3_DATA, PTP3_IN, PTP3_OUT, PTP3_IN_PU),
-	PINMUX_DATA(PTP2_DATA, PTP2_IN, PTP2_OUT, PTP2_IN_PU),
-	PINMUX_DATA(PTP1_DATA, PTP1_IN, PTP1_OUT, PTP1_IN_PU),
-	PINMUX_DATA(PTP0_DATA, PTP0_IN, PTP0_OUT, PTP0_IN_PU),
+	PINMUX_DATA(PTP4_DATA, PTP4_IN, PTP4_OUT),
+	PINMUX_DATA(PTP3_DATA, PTP3_IN, PTP3_OUT),
+	PINMUX_DATA(PTP2_DATA, PTP2_IN, PTP2_OUT),
+	PINMUX_DATA(PTP1_DATA, PTP1_IN, PTP1_OUT),
+	PINMUX_DATA(PTP0_DATA, PTP0_IN, PTP0_OUT),
 
 	/* PTR GPIO */
-	PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
-	PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
-	PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
-	PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
-	PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_OUT, PTR3_IN_PU),
-	PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_OUT, PTR2_IN_PU),
-	PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
-	PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
+	PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT),
+	PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT),
+	PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
+	PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
+	PINMUX_DATA(PTR3_DATA, PTR3_IN, PTR3_OUT),
+	PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_OUT),
+	PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
+	PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
 
 	/* PTS GPIO */
-	PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
-	PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
-	PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
-	PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
-	PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
+	PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT),
+	PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT),
+	PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT),
+	PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT),
+	PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
 
 	/* PTT GPIO */
-	PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
-	PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
-	PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
-	PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
-	PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
+	PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
+	PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
+	PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT),
+	PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT),
+	PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT),
 
 	/* PTU GPIO */
-	PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
-	PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
-	PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
-	PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
-	PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
+	PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT),
+	PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT),
+	PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT),
+	PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT),
+	PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT),
 
 	/* PTV GPIO */
-	PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
-	PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
-	PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
-	PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
-	PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
+	PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT),
+	PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT),
+	PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT),
+	PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT),
+	PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT),
 
 	/* PTA FN */
 	PINMUX_DATA(D23_MARK, PTA7_FN),
@@ -608,157 +578,157 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PTA */
-	PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
-	PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
-	PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
-	PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
-	PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
-	PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
-	PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
-	PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+	PINMUX_GPIO(PTA7),
+	PINMUX_GPIO(PTA6),
+	PINMUX_GPIO(PTA5),
+	PINMUX_GPIO(PTA4),
+	PINMUX_GPIO(PTA3),
+	PINMUX_GPIO(PTA2),
+	PINMUX_GPIO(PTA1),
+	PINMUX_GPIO(PTA0),
 
 	/* PTB */
-	PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
-	PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
-	PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
-	PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
-	PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
-	PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
-	PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
-	PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+	PINMUX_GPIO(PTB7),
+	PINMUX_GPIO(PTB6),
+	PINMUX_GPIO(PTB5),
+	PINMUX_GPIO(PTB4),
+	PINMUX_GPIO(PTB3),
+	PINMUX_GPIO(PTB2),
+	PINMUX_GPIO(PTB1),
+	PINMUX_GPIO(PTB0),
 
 	/* PTC */
-	PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
-	PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
-	PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
-	PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
-	PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
-	PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
-	PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
-	PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+	PINMUX_GPIO(PTC7),
+	PINMUX_GPIO(PTC6),
+	PINMUX_GPIO(PTC5),
+	PINMUX_GPIO(PTC4),
+	PINMUX_GPIO(PTC3),
+	PINMUX_GPIO(PTC2),
+	PINMUX_GPIO(PTC1),
+	PINMUX_GPIO(PTC0),
 
 	/* PTD */
-	PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
-	PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
-	PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
-	PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
-	PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
-	PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
-	PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
-	PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+	PINMUX_GPIO(PTD7),
+	PINMUX_GPIO(PTD6),
+	PINMUX_GPIO(PTD5),
+	PINMUX_GPIO(PTD4),
+	PINMUX_GPIO(PTD3),
+	PINMUX_GPIO(PTD2),
+	PINMUX_GPIO(PTD1),
+	PINMUX_GPIO(PTD0),
 
 	/* PTE */
-	PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
-	PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
-	PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
-	PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
-	PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
-	PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
-	PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+	PINMUX_GPIO(PTE6),
+	PINMUX_GPIO(PTE5),
+	PINMUX_GPIO(PTE4),
+	PINMUX_GPIO(PTE3),
+	PINMUX_GPIO(PTE2),
+	PINMUX_GPIO(PTE1),
+	PINMUX_GPIO(PTE0),
 
 	/* PTF */
-	PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
-	PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
-	PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
-	PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
-	PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
-	PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
-	PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+	PINMUX_GPIO(PTF6),
+	PINMUX_GPIO(PTF5),
+	PINMUX_GPIO(PTF4),
+	PINMUX_GPIO(PTF3),
+	PINMUX_GPIO(PTF2),
+	PINMUX_GPIO(PTF1),
+	PINMUX_GPIO(PTF0),
 
 	/* PTG */
-	PINMUX_GPIO(GPIO_PTG6, PTG6_DATA),
-	PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
-	PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
-	PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
-	PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
-	PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
-	PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+	PINMUX_GPIO(PTG6),
+	PINMUX_GPIO(PTG5),
+	PINMUX_GPIO(PTG4),
+	PINMUX_GPIO(PTG3),
+	PINMUX_GPIO(PTG2),
+	PINMUX_GPIO(PTG1),
+	PINMUX_GPIO(PTG0),
 
 	/* PTH */
-	PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
-	PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
-	PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
-	PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
-	PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
-	PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
-	PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+	PINMUX_GPIO(PTH6),
+	PINMUX_GPIO(PTH5),
+	PINMUX_GPIO(PTH4),
+	PINMUX_GPIO(PTH3),
+	PINMUX_GPIO(PTH2),
+	PINMUX_GPIO(PTH1),
+	PINMUX_GPIO(PTH0),
 
 	/* PTJ */
-	PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
-	PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
-	PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
-	PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
-	PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
-	PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
-	PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+	PINMUX_GPIO(PTJ6),
+	PINMUX_GPIO(PTJ5),
+	PINMUX_GPIO(PTJ4),
+	PINMUX_GPIO(PTJ3),
+	PINMUX_GPIO(PTJ2),
+	PINMUX_GPIO(PTJ1),
+	PINMUX_GPIO(PTJ0),
 
 	/* PTK */
-	PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
-	PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
-	PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
-	PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+	PINMUX_GPIO(PTK3),
+	PINMUX_GPIO(PTK2),
+	PINMUX_GPIO(PTK1),
+	PINMUX_GPIO(PTK0),
 
 	/* PTL */
-	PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
-	PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
-	PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
-	PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
-	PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
+	PINMUX_GPIO(PTL7),
+	PINMUX_GPIO(PTL6),
+	PINMUX_GPIO(PTL5),
+	PINMUX_GPIO(PTL4),
+	PINMUX_GPIO(PTL3),
 
 	/* PTM */
-	PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
-	PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
-	PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
-	PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
-	PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
-	PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
-	PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
-	PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+	PINMUX_GPIO(PTM7),
+	PINMUX_GPIO(PTM6),
+	PINMUX_GPIO(PTM5),
+	PINMUX_GPIO(PTM4),
+	PINMUX_GPIO(PTM3),
+	PINMUX_GPIO(PTM2),
+	PINMUX_GPIO(PTM1),
+	PINMUX_GPIO(PTM0),
 
 	/* PTP */
-	PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
-	PINMUX_GPIO(GPIO_PTP3, PTP3_DATA),
-	PINMUX_GPIO(GPIO_PTP2, PTP2_DATA),
-	PINMUX_GPIO(GPIO_PTP1, PTP1_DATA),
-	PINMUX_GPIO(GPIO_PTP0, PTP0_DATA),
+	PINMUX_GPIO(PTP4),
+	PINMUX_GPIO(PTP3),
+	PINMUX_GPIO(PTP2),
+	PINMUX_GPIO(PTP1),
+	PINMUX_GPIO(PTP0),
 
 	/* PTR */
-	PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
-	PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
-	PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
-	PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
-	PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
-	PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
-	PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
-	PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+	PINMUX_GPIO(PTR7),
+	PINMUX_GPIO(PTR6),
+	PINMUX_GPIO(PTR5),
+	PINMUX_GPIO(PTR4),
+	PINMUX_GPIO(PTR3),
+	PINMUX_GPIO(PTR2),
+	PINMUX_GPIO(PTR1),
+	PINMUX_GPIO(PTR0),
 
 	/* PTS */
-	PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
-	PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
-	PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
-	PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
-	PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+	PINMUX_GPIO(PTS4),
+	PINMUX_GPIO(PTS3),
+	PINMUX_GPIO(PTS2),
+	PINMUX_GPIO(PTS1),
+	PINMUX_GPIO(PTS0),
 
 	/* PTT */
-	PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
-	PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
-	PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
-	PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
-	PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+	PINMUX_GPIO(PTT4),
+	PINMUX_GPIO(PTT3),
+	PINMUX_GPIO(PTT2),
+	PINMUX_GPIO(PTT1),
+	PINMUX_GPIO(PTT0),
 
 	/* PTU */
-	PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
-	PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
-	PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
-	PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
-	PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+	PINMUX_GPIO(PTU4),
+	PINMUX_GPIO(PTU3),
+	PINMUX_GPIO(PTU2),
+	PINMUX_GPIO(PTU1),
+	PINMUX_GPIO(PTU0),
 
 	/* PTV */
-	PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
-	PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
-	PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
-	PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
-	PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+	PINMUX_GPIO(PTV4),
+	PINMUX_GPIO(PTV3),
+	PINMUX_GPIO(PTV2),
+	PINMUX_GPIO(PTV1),
+	PINMUX_GPIO(PTV0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -959,54 +929,54 @@
 
 static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
-		PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
-		PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
-		PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
-		PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
-		PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
-		PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
-		PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
-		PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+		PTA7_FN, PTA7_OUT, 0, PTA7_IN,
+		PTA6_FN, PTA6_OUT, 0, PTA6_IN,
+		PTA5_FN, PTA5_OUT, 0, PTA5_IN,
+		PTA4_FN, PTA4_OUT, 0, PTA4_IN,
+		PTA3_FN, PTA3_OUT, 0, PTA3_IN,
+		PTA2_FN, PTA2_OUT, 0, PTA2_IN,
+		PTA1_FN, PTA1_OUT, 0, PTA1_IN,
+		PTA0_FN, PTA0_OUT, 0, PTA0_IN }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
-		PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
-		PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
-		PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
-		PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
-		PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
-		PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
-		PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
-		PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
+		PTB7_FN, PTB7_OUT, 0, PTB7_IN,
+		PTB6_FN, PTB6_OUT, 0, PTB6_IN,
+		PTB5_FN, PTB5_OUT, 0, PTB5_IN,
+		PTB4_FN, PTB4_OUT, 0, PTB4_IN,
+		PTB3_FN, PTB3_OUT, 0, PTB3_IN,
+		PTB2_FN, PTB2_OUT, 0, PTB2_IN,
+		PTB1_FN, PTB1_OUT, 0, PTB1_IN,
+		PTB0_FN, PTB0_OUT, 0, PTB0_IN }
 	},
 	{ PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
-		PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
-		PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
-		PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
-		PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
-		PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
-		PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
-		PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
-		PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
+		PTC7_FN, PTC7_OUT, 0, PTC7_IN,
+		PTC6_FN, PTC6_OUT, 0, PTC6_IN,
+		PTC5_FN, PTC5_OUT, 0, PTC5_IN,
+		PTC4_FN, PTC4_OUT, 0, PTC4_IN,
+		PTC3_FN, PTC3_OUT, 0, PTC3_IN,
+		PTC2_FN, PTC2_OUT, 0, PTC2_IN,
+		PTC1_FN, PTC1_OUT, 0, PTC1_IN,
+		PTC0_FN, PTC0_OUT, 0, PTC0_IN }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
-		PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
-		PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
-		PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
-		PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
-		PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
-		PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
-		PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
-		PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
+		PTD7_FN, PTD7_OUT, 0, PTD7_IN,
+		PTD6_FN, PTD6_OUT, 0, PTD6_IN,
+		PTD5_FN, PTD5_OUT, 0, PTD5_IN,
+		PTD4_FN, PTD4_OUT, 0, PTD4_IN,
+		PTD3_FN, PTD3_OUT, 0, PTD3_IN,
+		PTD2_FN, PTD2_OUT, 0, PTD2_IN,
+		PTD1_FN, PTD1_OUT, 0, PTD1_IN,
+		PTD0_FN, PTD0_OUT, 0, PTD0_IN }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
 		0, 0, 0, 0,
 		PTE6_FN, 0, 0, PTE6_IN,
 		PTE5_FN, 0, 0, PTE5_IN,
-		PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
-		PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
-		PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
-		PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
-		PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
+		PTE4_FN, PTE4_OUT, 0, PTE4_IN,
+		PTE3_FN, PTE3_OUT, 0, PTE3_IN,
+		PTE2_FN, PTE2_OUT, 0, PTE2_IN,
+		PTE1_FN, PTE1_OUT, 0, PTE1_IN,
+		PTE0_FN, PTE0_OUT, 0, PTE0_IN }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
 		0, 0, 0, 0,
@@ -1020,123 +990,123 @@
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
 		0, 0, 0, 0,
-		PTG6_FN, PTG6_OUT, PTG6_IN_PU, PTG6_IN,
-		PTG5_FN, PTG5_OUT, PTG5_IN_PU, PTG5_IN,
-		PTG4_FN, PTG4_OUT, PTG4_IN_PU, PTG4_IN,
-		PTG3_FN, PTG3_OUT, PTG3_IN_PU, PTG3_IN,
-		PTG2_FN, PTG2_OUT, PTG2_IN_PU, PTG2_IN,
-		PTG1_FN, PTG1_OUT, PTG1_IN_PU, PTG1_IN,
-		PTG0_FN, PTG0_OUT, PTG0_IN_PU, PTG0_IN }
+		PTG6_FN, PTG6_OUT, 0, PTG6_IN,
+		PTG5_FN, PTG5_OUT, 0, PTG5_IN,
+		PTG4_FN, PTG4_OUT, 0, PTG4_IN,
+		PTG3_FN, PTG3_OUT, 0, PTG3_IN,
+		PTG2_FN, PTG2_OUT, 0, PTG2_IN,
+		PTG1_FN, PTG1_OUT, 0, PTG1_IN,
+		PTG0_FN, PTG0_OUT, 0, PTG0_IN }
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
 		0, 0, 0, 0,
-		PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
-		PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
-		PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
-		PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
-		PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
-		PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
-		PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
+		PTH6_FN, PTH6_OUT, 0, PTH6_IN,
+		PTH5_FN, PTH5_OUT, 0, PTH5_IN,
+		PTH4_FN, PTH4_OUT, 0, PTH4_IN,
+		PTH3_FN, PTH3_OUT, 0, PTH3_IN,
+		PTH2_FN, PTH2_OUT, 0, PTH2_IN,
+		PTH1_FN, PTH1_OUT, 0, PTH1_IN,
+		PTH0_FN, PTH0_OUT, 0, PTH0_IN }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
 		0, 0, 0, 0,
-		PTJ6_FN, PTJ6_OUT, PTJ6_IN_PU, PTJ6_IN,
-		PTJ5_FN, PTJ5_OUT, PTJ5_IN_PU, PTJ5_IN,
-		PTJ4_FN, PTJ4_OUT, PTJ4_IN_PU, PTJ4_IN,
-		PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
-		PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
-		PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
-		PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+		PTJ6_FN, PTJ6_OUT, 0, PTJ6_IN,
+		PTJ5_FN, PTJ5_OUT, 0, PTJ5_IN,
+		PTJ4_FN, PTJ4_OUT, 0, PTJ4_IN,
+		PTJ3_FN, PTJ3_OUT, 0, PTJ3_IN,
+		PTJ2_FN, PTJ2_OUT, 0, PTJ2_IN,
+		PTJ1_FN, PTJ1_OUT, 0, PTJ1_IN,
+		PTJ0_FN, PTJ0_OUT, 0, PTJ0_IN }
 	},
 	{ PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
-		PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
-		PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
-		PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
+		PTK3_FN, PTK3_OUT, 0, PTK3_IN,
+		PTK2_FN, PTK2_OUT, 0, PTK2_IN,
+		PTK1_FN, PTK1_OUT, 0, PTK1_IN,
+		PTK0_FN, PTK0_OUT, 0, PTK0_IN }
 	},
 	{ PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
-		PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
-		PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
-		PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
-		PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
-		PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
+		PTL7_FN, PTL7_OUT, 0, PTL7_IN,
+		PTL6_FN, PTL6_OUT, 0, PTL6_IN,
+		PTL5_FN, PTL5_OUT, 0, PTL5_IN,
+		PTL4_FN, PTL4_OUT, 0, PTL4_IN,
+		PTL3_FN, PTL3_OUT, 0, PTL3_IN,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
-		PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
-		PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
-		PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
-		PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
-		PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
-		PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
-		PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
-		PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
+		PTM7_FN, PTM7_OUT, 0, PTM7_IN,
+		PTM6_FN, PTM6_OUT, 0, PTM6_IN,
+		PTM5_FN, PTM5_OUT, 0, PTM5_IN,
+		PTM4_FN, PTM4_OUT, 0, PTM4_IN,
+		PTM3_FN, PTM3_OUT, 0, PTM3_IN,
+		PTM2_FN, PTM2_OUT, 0, PTM2_IN,
+		PTM1_FN, PTM1_OUT, 0, PTM1_IN,
+		PTM0_FN, PTM0_OUT, 0, PTM0_IN }
 	},
 	{ PINMUX_CFG_REG("PPCR", 0xa4050118, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PTP4_FN, PTP4_OUT, PTP4_IN_PU, PTP4_IN,
-		PTP3_FN, PTP3_OUT, PTP3_IN_PU, PTP3_IN,
-		PTP2_FN, PTP2_OUT, PTP2_IN_PU, PTP2_IN,
-		PTP1_FN, PTP1_OUT, PTP1_IN_PU, PTP1_IN,
-		PTP0_FN, PTP0_OUT, PTP0_IN_PU, PTP0_IN }
+		PTP4_FN, PTP4_OUT, 0, PTP4_IN,
+		PTP3_FN, PTP3_OUT, 0, PTP3_IN,
+		PTP2_FN, PTP2_OUT, 0, PTP2_IN,
+		PTP1_FN, PTP1_OUT, 0, PTP1_IN,
+		PTP0_FN, PTP0_OUT, 0, PTP0_IN }
 	},
 	{ PINMUX_CFG_REG("PRCR", 0xa405011a, 16, 2) {
-		PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
-		PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
-		PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
-		PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
-		PTR3_FN, PTR3_OUT, PTR3_IN_PU, PTR3_IN,
-		PTR2_FN, PTR2_OUT, PTR2_IN_PU, PTR2_IN,
-		PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
-		PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
+		PTR7_FN, PTR7_OUT, 0, PTR7_IN,
+		PTR6_FN, PTR6_OUT, 0, PTR6_IN,
+		PTR5_FN, PTR5_OUT, 0, PTR5_IN,
+		PTR4_FN, PTR4_OUT, 0, PTR4_IN,
+		PTR3_FN, PTR3_OUT, 0, PTR3_IN,
+		PTR2_FN, PTR2_OUT, 0, PTR2_IN,
+		PTR1_FN, PTR1_OUT, 0, PTR1_IN,
+		PTR0_FN, PTR0_OUT, 0, PTR0_IN }
 	},
 	{ PINMUX_CFG_REG("PSCR", 0xa405011c, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
-		PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
-		PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
-		PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
-		PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
+		PTS4_FN, PTS4_OUT, 0, PTS4_IN,
+		PTS3_FN, PTS3_OUT, 0, PTS3_IN,
+		PTS2_FN, PTS2_OUT, 0, PTS2_IN,
+		PTS1_FN, PTS1_OUT, 0, PTS1_IN,
+		PTS0_FN, PTS0_OUT, 0, PTS0_IN }
 	},
 	{ PINMUX_CFG_REG("PTCR", 0xa405011e, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
-		PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
-		PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
-		PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
-		PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
+		PTT4_FN, PTT4_OUT, 0, PTT4_IN,
+		PTT3_FN, PTT3_OUT, 0, PTT3_IN,
+		PTT2_FN, PTT2_OUT, 0, PTT2_IN,
+		PTT1_FN, PTT1_OUT, 0, PTT1_IN,
+		PTT0_FN, PTT0_OUT, 0, PTT0_IN }
 	},
 	{ PINMUX_CFG_REG("PUCR", 0xa4050120, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
-		PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
-		PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
-		PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
-		PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
+		PTU4_FN, PTU4_OUT, 0, PTU4_IN,
+		PTU3_FN, PTU3_OUT, 0, PTU3_IN,
+		PTU2_FN, PTU2_OUT, 0, PTU2_IN,
+		PTU1_FN, PTU1_OUT, 0, PTU1_IN,
+		PTU0_FN, PTU0_OUT, 0, PTU0_IN }
 	},
 	{ PINMUX_CFG_REG("PVCR", 0xa4050122, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
-		PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
-		PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
-		PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
-		PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
+		PTV4_FN, PTV4_OUT, 0, PTV4_IN,
+		PTV3_FN, PTV3_OUT, 0, PTV3_IN,
+		PTV2_FN, PTV2_OUT, 0, PTV2_IN,
+		PTV1_FN, PTV1_OUT, 0, PTV1_IN,
+		PTV0_FN, PTV0_OUT, 0, PTV0_IN }
 	},
 	{}
 };
@@ -1220,7 +1190,6 @@
 const struct sh_pfc_soc_info sh7720_pinmux_info = {
 	.name = "sh7720_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7722.c b/drivers/pinctrl/sh-pfc/pfc-sh7722.c
index 3203438..add3093 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7722.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7722.c
@@ -77,39 +77,6 @@
 	PTZ5_IN, PTZ4_IN, PTZ3_IN, PTZ2_IN, PTZ1_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLDOWN_BEGIN,
-	PTA7_IN_PD, PTA6_IN_PD, PTA5_IN_PD, PTA4_IN_PD,
-	PTA3_IN_PD, PTA2_IN_PD, PTA1_IN_PD, PTA0_IN_PD,
-	PTE7_IN_PD, PTE6_IN_PD, PTE5_IN_PD, PTE4_IN_PD,	PTE1_IN_PD, PTE0_IN_PD,
-	PTF6_IN_PD, PTF5_IN_PD, PTF4_IN_PD, PTF3_IN_PD, PTF2_IN_PD, PTF1_IN_PD,
-	PTH6_IN_PD, PTH5_IN_PD, PTH1_IN_PD, PTH0_IN_PD,
-	PTK6_IN_PD, PTK5_IN_PD, PTK4_IN_PD, PTK3_IN_PD, PTK2_IN_PD, PTK0_IN_PD,
-	PTL7_IN_PD, PTL6_IN_PD, PTL5_IN_PD, PTL4_IN_PD,
-	PTL3_IN_PD, PTL2_IN_PD, PTL1_IN_PD, PTL0_IN_PD,
-	PTM7_IN_PD, PTM6_IN_PD, PTM5_IN_PD, PTM4_IN_PD,
-	PTM3_IN_PD, PTM2_IN_PD, PTM1_IN_PD, PTM0_IN_PD,
-	PTQ5_IN_PD, PTQ4_IN_PD, PTQ3_IN_PD, PTQ2_IN_PD,
-	PTS4_IN_PD, PTS2_IN_PD, PTS1_IN_PD,
-	PTT4_IN_PD, PTT3_IN_PD, PTT2_IN_PD, PTT1_IN_PD,
-	PTU4_IN_PD, PTU3_IN_PD, PTU2_IN_PD, PTU1_IN_PD, PTU0_IN_PD,
-	PTV4_IN_PD, PTV3_IN_PD, PTV2_IN_PD, PTV1_IN_PD, PTV0_IN_PD,
-	PTW6_IN_PD, PTW4_IN_PD,	PTW3_IN_PD, PTW2_IN_PD, PTW1_IN_PD, PTW0_IN_PD,
-	PTX6_IN_PD, PTX5_IN_PD, PTX4_IN_PD,
-	PTX3_IN_PD, PTX2_IN_PD, PTX1_IN_PD, PTX0_IN_PD,
-	PINMUX_INPUT_PULLDOWN_END,
-
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PTC7_IN_PU, PTC5_IN_PU,
-	PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
-	PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU,
-	PTJ1_IN_PU, PTJ0_IN_PU,
-	PTQ0_IN_PU,
-	PTR2_IN_PU,
-	PTX6_IN_PU,
-	PTY5_IN_PU, PTY4_IN_PU, PTY3_IN_PU, PTY2_IN_PU, PTY0_IN_PU,
-	PTZ5_IN_PU, PTZ4_IN_PU, PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PTA7_OUT, PTA5_OUT,
 	PTB7_OUT, PTB6_OUT, PTB5_OUT, PTB4_OUT,
@@ -296,16 +263,16 @@
 	PINMUX_FUNCTION_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* PTA */
-	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_IN_PD, PTA7_OUT),
-	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_IN_PD),
-	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_IN_PD, PTA5_OUT),
-	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_IN_PD),
-	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_IN_PD),
-	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_IN_PD),
-	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_IN_PD),
-	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_IN_PD),
+	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
+	PINMUX_DATA(PTA6_DATA, PTA6_IN),
+	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
+	PINMUX_DATA(PTA4_DATA, PTA4_IN),
+	PINMUX_DATA(PTA3_DATA, PTA3_IN),
+	PINMUX_DATA(PTA2_DATA, PTA2_IN),
+	PINMUX_DATA(PTA1_DATA, PTA1_IN),
+	PINMUX_DATA(PTA0_DATA, PTA0_IN),
 
 	/* PTB */
 	PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
@@ -318,38 +285,38 @@
 	PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
 
 	/* PTC */
-	PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_IN_PU),
-	PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_IN_PU),
+	PINMUX_DATA(PTC7_DATA, PTC7_IN),
+	PINMUX_DATA(PTC5_DATA, PTC5_IN),
 	PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
 	PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
 	PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
 	PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
 
 	/* PTD */
-	PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_IN_PU),
-	PINMUX_DATA(PTD6_DATA, PTD6_OUT, PTD6_IN, PTD6_IN_PU),
-	PINMUX_DATA(PTD5_DATA, PTD5_OUT, PTD5_IN, PTD5_IN_PU),
-	PINMUX_DATA(PTD4_DATA, PTD4_OUT, PTD4_IN, PTD4_IN_PU),
-	PINMUX_DATA(PTD3_DATA, PTD3_OUT, PTD3_IN, PTD3_IN_PU),
-	PINMUX_DATA(PTD2_DATA, PTD2_OUT, PTD2_IN, PTD2_IN_PU),
-	PINMUX_DATA(PTD1_DATA, PTD1_OUT, PTD1_IN, PTD1_IN_PU),
+	PINMUX_DATA(PTD7_DATA, PTD7_IN),
+	PINMUX_DATA(PTD6_DATA, PTD6_OUT, PTD6_IN),
+	PINMUX_DATA(PTD5_DATA, PTD5_OUT, PTD5_IN),
+	PINMUX_DATA(PTD4_DATA, PTD4_OUT, PTD4_IN),
+	PINMUX_DATA(PTD3_DATA, PTD3_OUT, PTD3_IN),
+	PINMUX_DATA(PTD2_DATA, PTD2_OUT, PTD2_IN),
+	PINMUX_DATA(PTD1_DATA, PTD1_OUT, PTD1_IN),
 	PINMUX_DATA(PTD0_DATA, PTD0_OUT),
 
 	/* PTE */
-	PINMUX_DATA(PTE7_DATA, PTE7_OUT, PTE7_IN, PTE7_IN_PD),
-	PINMUX_DATA(PTE6_DATA, PTE6_OUT, PTE6_IN, PTE6_IN_PD),
-	PINMUX_DATA(PTE5_DATA, PTE5_OUT, PTE5_IN, PTE5_IN_PD),
-	PINMUX_DATA(PTE4_DATA, PTE4_OUT, PTE4_IN, PTE4_IN_PD),
-	PINMUX_DATA(PTE1_DATA, PTE1_OUT, PTE1_IN, PTE1_IN_PD),
-	PINMUX_DATA(PTE0_DATA, PTE0_OUT, PTE0_IN, PTE0_IN_PD),
+	PINMUX_DATA(PTE7_DATA, PTE7_OUT, PTE7_IN),
+	PINMUX_DATA(PTE6_DATA, PTE6_OUT, PTE6_IN),
+	PINMUX_DATA(PTE5_DATA, PTE5_OUT, PTE5_IN),
+	PINMUX_DATA(PTE4_DATA, PTE4_OUT, PTE4_IN),
+	PINMUX_DATA(PTE1_DATA, PTE1_OUT, PTE1_IN),
+	PINMUX_DATA(PTE0_DATA, PTE0_OUT, PTE0_IN),
 
 	/* PTF */
-	PINMUX_DATA(PTF6_DATA, PTF6_OUT, PTF6_IN, PTF6_IN_PD),
-	PINMUX_DATA(PTF5_DATA, PTF5_OUT, PTF5_IN, PTF5_IN_PD),
-	PINMUX_DATA(PTF4_DATA, PTF4_OUT, PTF4_IN, PTF4_IN_PD),
-	PINMUX_DATA(PTF3_DATA, PTF3_OUT, PTF3_IN, PTF3_IN_PD),
-	PINMUX_DATA(PTF2_DATA, PTF2_OUT, PTF2_IN, PTF2_IN_PD),
-	PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_IN_PD),
+	PINMUX_DATA(PTF6_DATA, PTF6_OUT, PTF6_IN),
+	PINMUX_DATA(PTF5_DATA, PTF5_OUT, PTF5_IN),
+	PINMUX_DATA(PTF4_DATA, PTF4_OUT, PTF4_IN),
+	PINMUX_DATA(PTF3_DATA, PTF3_OUT, PTF3_IN),
+	PINMUX_DATA(PTF2_DATA, PTF2_OUT, PTF2_IN),
+	PINMUX_DATA(PTF1_DATA, PTF1_IN),
 	PINMUX_DATA(PTF0_DATA, PTF0_OUT),
 
 	/* PTG */
@@ -361,49 +328,49 @@
 
 	/* PTH */
 	PINMUX_DATA(PTH7_DATA, PTH7_OUT),
-	PINMUX_DATA(PTH6_DATA, PTH6_OUT, PTH6_IN, PTH6_IN_PD),
-	PINMUX_DATA(PTH5_DATA, PTH5_OUT, PTH5_IN, PTH5_IN_PD),
+	PINMUX_DATA(PTH6_DATA, PTH6_OUT, PTH6_IN),
+	PINMUX_DATA(PTH5_DATA, PTH5_OUT, PTH5_IN),
 	PINMUX_DATA(PTH4_DATA, PTH4_OUT),
 	PINMUX_DATA(PTH3_DATA, PTH3_OUT),
 	PINMUX_DATA(PTH2_DATA, PTH2_OUT),
-	PINMUX_DATA(PTH1_DATA, PTH1_OUT, PTH1_IN, PTH1_IN_PD),
-	PINMUX_DATA(PTH0_DATA, PTH0_OUT, PTH0_IN, PTH0_IN_PD),
+	PINMUX_DATA(PTH1_DATA, PTH1_OUT, PTH1_IN),
+	PINMUX_DATA(PTH0_DATA, PTH0_OUT, PTH0_IN),
 
 	/* PTJ */
 	PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
 	PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
 	PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
-	PINMUX_DATA(PTJ1_DATA, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU),
-	PINMUX_DATA(PTJ0_DATA, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU),
+	PINMUX_DATA(PTJ1_DATA, PTJ1_OUT, PTJ1_IN),
+	PINMUX_DATA(PTJ0_DATA, PTJ0_OUT, PTJ0_IN),
 
 	/* PTK */
-	PINMUX_DATA(PTK6_DATA, PTK6_OUT, PTK6_IN, PTK6_IN_PD),
-	PINMUX_DATA(PTK5_DATA, PTK5_OUT, PTK5_IN, PTK5_IN_PD),
-	PINMUX_DATA(PTK4_DATA, PTK4_OUT, PTK4_IN, PTK4_IN_PD),
-	PINMUX_DATA(PTK3_DATA, PTK3_OUT, PTK3_IN, PTK3_IN_PD),
-	PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_IN_PD),
+	PINMUX_DATA(PTK6_DATA, PTK6_OUT, PTK6_IN),
+	PINMUX_DATA(PTK5_DATA, PTK5_OUT, PTK5_IN),
+	PINMUX_DATA(PTK4_DATA, PTK4_OUT, PTK4_IN),
+	PINMUX_DATA(PTK3_DATA, PTK3_OUT, PTK3_IN),
+	PINMUX_DATA(PTK2_DATA, PTK2_IN),
 	PINMUX_DATA(PTK1_DATA, PTK1_OUT),
-	PINMUX_DATA(PTK0_DATA, PTK0_OUT, PTK0_IN, PTK0_IN_PD),
+	PINMUX_DATA(PTK0_DATA, PTK0_OUT, PTK0_IN),
 
 	/* PTL */
-	PINMUX_DATA(PTL7_DATA, PTL7_OUT, PTL7_IN, PTL7_IN_PD),
-	PINMUX_DATA(PTL6_DATA, PTL6_OUT, PTL6_IN, PTL6_IN_PD),
-	PINMUX_DATA(PTL5_DATA, PTL5_OUT, PTL5_IN, PTL5_IN_PD),
-	PINMUX_DATA(PTL4_DATA, PTL4_OUT, PTL4_IN, PTL4_IN_PD),
-	PINMUX_DATA(PTL3_DATA, PTL3_OUT, PTL3_IN, PTL3_IN_PD),
-	PINMUX_DATA(PTL2_DATA, PTL2_OUT, PTL2_IN, PTL2_IN_PD),
-	PINMUX_DATA(PTL1_DATA, PTL1_OUT, PTL1_IN, PTL1_IN_PD),
-	PINMUX_DATA(PTL0_DATA, PTL0_OUT, PTL0_IN, PTL0_IN_PD),
+	PINMUX_DATA(PTL7_DATA, PTL7_OUT, PTL7_IN),
+	PINMUX_DATA(PTL6_DATA, PTL6_OUT, PTL6_IN),
+	PINMUX_DATA(PTL5_DATA, PTL5_OUT, PTL5_IN),
+	PINMUX_DATA(PTL4_DATA, PTL4_OUT, PTL4_IN),
+	PINMUX_DATA(PTL3_DATA, PTL3_OUT, PTL3_IN),
+	PINMUX_DATA(PTL2_DATA, PTL2_OUT, PTL2_IN),
+	PINMUX_DATA(PTL1_DATA, PTL1_OUT, PTL1_IN),
+	PINMUX_DATA(PTL0_DATA, PTL0_OUT, PTL0_IN),
 
 	/* PTM */
-	PINMUX_DATA(PTM7_DATA, PTM7_OUT, PTM7_IN, PTM7_IN_PD),
-	PINMUX_DATA(PTM6_DATA, PTM6_OUT, PTM6_IN, PTM6_IN_PD),
-	PINMUX_DATA(PTM5_DATA, PTM5_OUT, PTM5_IN, PTM5_IN_PD),
-	PINMUX_DATA(PTM4_DATA, PTM4_OUT, PTM4_IN, PTM4_IN_PD),
-	PINMUX_DATA(PTM3_DATA, PTM3_OUT, PTM3_IN, PTM3_IN_PD),
-	PINMUX_DATA(PTM2_DATA, PTM2_OUT, PTM2_IN, PTM2_IN_PD),
-	PINMUX_DATA(PTM1_DATA, PTM1_OUT, PTM1_IN, PTM1_IN_PD),
-	PINMUX_DATA(PTM0_DATA, PTM0_OUT, PTM0_IN, PTM0_IN_PD),
+	PINMUX_DATA(PTM7_DATA, PTM7_OUT, PTM7_IN),
+	PINMUX_DATA(PTM6_DATA, PTM6_OUT, PTM6_IN),
+	PINMUX_DATA(PTM5_DATA, PTM5_OUT, PTM5_IN),
+	PINMUX_DATA(PTM4_DATA, PTM4_OUT, PTM4_IN),
+	PINMUX_DATA(PTM3_DATA, PTM3_OUT, PTM3_IN),
+	PINMUX_DATA(PTM2_DATA, PTM2_OUT, PTM2_IN),
+	PINMUX_DATA(PTM1_DATA, PTM1_OUT, PTM1_IN),
+	PINMUX_DATA(PTM0_DATA, PTM0_OUT, PTM0_IN),
 
 	/* PTN */
 	PINMUX_DATA(PTN7_DATA, PTN7_OUT, PTN7_IN),
@@ -417,80 +384,80 @@
 
 	/* PTQ */
 	PINMUX_DATA(PTQ6_DATA, PTQ6_OUT),
-	PINMUX_DATA(PTQ5_DATA, PTQ5_OUT, PTQ5_IN, PTQ5_IN_PD),
-	PINMUX_DATA(PTQ4_DATA, PTQ4_OUT, PTQ4_IN, PTQ4_IN_PD),
-	PINMUX_DATA(PTQ3_DATA, PTQ3_OUT, PTQ3_IN, PTQ3_IN_PD),
-	PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_IN_PD),
+	PINMUX_DATA(PTQ5_DATA, PTQ5_OUT, PTQ5_IN),
+	PINMUX_DATA(PTQ4_DATA, PTQ4_OUT, PTQ4_IN),
+	PINMUX_DATA(PTQ3_DATA, PTQ3_OUT, PTQ3_IN),
+	PINMUX_DATA(PTQ2_DATA, PTQ2_IN),
 	PINMUX_DATA(PTQ1_DATA, PTQ1_OUT),
-	PINMUX_DATA(PTQ0_DATA, PTQ0_OUT, PTQ0_IN, PTQ0_IN_PU),
+	PINMUX_DATA(PTQ0_DATA, PTQ0_OUT, PTQ0_IN),
 
 	/* PTR */
 	PINMUX_DATA(PTR4_DATA, PTR4_OUT),
 	PINMUX_DATA(PTR3_DATA, PTR3_OUT),
-	PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
+	PINMUX_DATA(PTR2_DATA, PTR2_IN),
 	PINMUX_DATA(PTR1_DATA, PTR1_OUT),
 	PINMUX_DATA(PTR0_DATA, PTR0_OUT),
 
 	/* PTS */
-	PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_IN_PD),
+	PINMUX_DATA(PTS4_DATA, PTS4_IN),
 	PINMUX_DATA(PTS3_DATA, PTS3_OUT),
-	PINMUX_DATA(PTS2_DATA, PTS2_OUT, PTS2_IN, PTS2_IN_PD),
-	PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_IN_PD),
+	PINMUX_DATA(PTS2_DATA, PTS2_OUT, PTS2_IN),
+	PINMUX_DATA(PTS1_DATA, PTS1_IN),
 	PINMUX_DATA(PTS0_DATA, PTS0_OUT),
 
 	/* PTT */
-	PINMUX_DATA(PTT4_DATA, PTT4_OUT, PTT4_IN, PTT4_IN_PD),
-	PINMUX_DATA(PTT3_DATA, PTT3_OUT, PTT3_IN, PTT3_IN_PD),
-	PINMUX_DATA(PTT2_DATA, PTT2_OUT, PTT2_IN, PTT2_IN_PD),
-	PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_IN_PD),
+	PINMUX_DATA(PTT4_DATA, PTT4_OUT, PTT4_IN),
+	PINMUX_DATA(PTT3_DATA, PTT3_OUT, PTT3_IN),
+	PINMUX_DATA(PTT2_DATA, PTT2_OUT, PTT2_IN),
+	PINMUX_DATA(PTT1_DATA, PTT1_IN),
 	PINMUX_DATA(PTT0_DATA, PTT0_OUT),
 
 	/* PTU */
-	PINMUX_DATA(PTU4_DATA, PTU4_OUT, PTU4_IN, PTU4_IN_PD),
-	PINMUX_DATA(PTU3_DATA, PTU3_OUT, PTU3_IN, PTU3_IN_PD),
-	PINMUX_DATA(PTU2_DATA, PTU2_OUT, PTU2_IN, PTU2_IN_PD),
-	PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_IN_PD),
-	PINMUX_DATA(PTU0_DATA, PTU0_OUT, PTU0_IN, PTU0_IN_PD),
+	PINMUX_DATA(PTU4_DATA, PTU4_OUT, PTU4_IN),
+	PINMUX_DATA(PTU3_DATA, PTU3_OUT, PTU3_IN),
+	PINMUX_DATA(PTU2_DATA, PTU2_OUT, PTU2_IN),
+	PINMUX_DATA(PTU1_DATA, PTU1_IN),
+	PINMUX_DATA(PTU0_DATA, PTU0_OUT, PTU0_IN),
 
 	/* PTV */
-	PINMUX_DATA(PTV4_DATA, PTV4_OUT, PTV4_IN, PTV4_IN_PD),
-	PINMUX_DATA(PTV3_DATA, PTV3_OUT, PTV3_IN, PTV3_IN_PD),
-	PINMUX_DATA(PTV2_DATA, PTV2_OUT, PTV2_IN, PTV2_IN_PD),
-	PINMUX_DATA(PTV1_DATA, PTV1_OUT, PTV1_IN, PTV1_IN_PD),
-	PINMUX_DATA(PTV0_DATA, PTV0_OUT, PTV0_IN, PTV0_IN_PD),
+	PINMUX_DATA(PTV4_DATA, PTV4_OUT, PTV4_IN),
+	PINMUX_DATA(PTV3_DATA, PTV3_OUT, PTV3_IN),
+	PINMUX_DATA(PTV2_DATA, PTV2_OUT, PTV2_IN),
+	PINMUX_DATA(PTV1_DATA, PTV1_OUT, PTV1_IN),
+	PINMUX_DATA(PTV0_DATA, PTV0_OUT, PTV0_IN),
 
 	/* PTW */
-	PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_IN_PD),
+	PINMUX_DATA(PTW6_DATA, PTW6_IN),
 	PINMUX_DATA(PTW5_DATA, PTW5_OUT),
-	PINMUX_DATA(PTW4_DATA, PTW4_OUT, PTW4_IN, PTW4_IN_PD),
-	PINMUX_DATA(PTW3_DATA, PTW3_OUT, PTW3_IN, PTW3_IN_PD),
-	PINMUX_DATA(PTW2_DATA, PTW2_OUT, PTW2_IN, PTW2_IN_PD),
-	PINMUX_DATA(PTW1_DATA, PTW1_OUT, PTW1_IN, PTW1_IN_PD),
-	PINMUX_DATA(PTW0_DATA, PTW0_OUT, PTW0_IN, PTW0_IN_PD),
+	PINMUX_DATA(PTW4_DATA, PTW4_OUT, PTW4_IN),
+	PINMUX_DATA(PTW3_DATA, PTW3_OUT, PTW3_IN),
+	PINMUX_DATA(PTW2_DATA, PTW2_OUT, PTW2_IN),
+	PINMUX_DATA(PTW1_DATA, PTW1_OUT, PTW1_IN),
+	PINMUX_DATA(PTW0_DATA, PTW0_OUT, PTW0_IN),
 
 	/* PTX */
-	PINMUX_DATA(PTX6_DATA, PTX6_OUT, PTX6_IN, PTX6_IN_PD),
-	PINMUX_DATA(PTX5_DATA, PTX5_OUT, PTX5_IN, PTX5_IN_PD),
-	PINMUX_DATA(PTX4_DATA, PTX4_OUT, PTX4_IN, PTX4_IN_PD),
-	PINMUX_DATA(PTX3_DATA, PTX3_OUT, PTX3_IN, PTX3_IN_PD),
-	PINMUX_DATA(PTX2_DATA, PTX2_OUT, PTX2_IN, PTX2_IN_PD),
-	PINMUX_DATA(PTX1_DATA, PTX1_OUT, PTX1_IN, PTX1_IN_PD),
-	PINMUX_DATA(PTX0_DATA, PTX0_OUT, PTX0_IN, PTX0_IN_PD),
+	PINMUX_DATA(PTX6_DATA, PTX6_OUT, PTX6_IN),
+	PINMUX_DATA(PTX5_DATA, PTX5_OUT, PTX5_IN),
+	PINMUX_DATA(PTX4_DATA, PTX4_OUT, PTX4_IN),
+	PINMUX_DATA(PTX3_DATA, PTX3_OUT, PTX3_IN),
+	PINMUX_DATA(PTX2_DATA, PTX2_OUT, PTX2_IN),
+	PINMUX_DATA(PTX1_DATA, PTX1_OUT, PTX1_IN),
+	PINMUX_DATA(PTX0_DATA, PTX0_OUT, PTX0_IN),
 
 	/* PTY */
-	PINMUX_DATA(PTY5_DATA, PTY5_OUT, PTY5_IN, PTY5_IN_PU),
-	PINMUX_DATA(PTY4_DATA, PTY4_OUT, PTY4_IN, PTY4_IN_PU),
-	PINMUX_DATA(PTY3_DATA, PTY3_OUT, PTY3_IN, PTY3_IN_PU),
-	PINMUX_DATA(PTY2_DATA, PTY2_OUT, PTY2_IN, PTY2_IN_PU),
+	PINMUX_DATA(PTY5_DATA, PTY5_OUT, PTY5_IN),
+	PINMUX_DATA(PTY4_DATA, PTY4_OUT, PTY4_IN),
+	PINMUX_DATA(PTY3_DATA, PTY3_OUT, PTY3_IN),
+	PINMUX_DATA(PTY2_DATA, PTY2_OUT, PTY2_IN),
 	PINMUX_DATA(PTY1_DATA, PTY1_OUT),
-	PINMUX_DATA(PTY0_DATA, PTY0_OUT, PTY0_IN, PTY0_IN_PU),
+	PINMUX_DATA(PTY0_DATA, PTY0_OUT, PTY0_IN),
 
 	/* PTZ */
-	PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_IN_PU),
-	PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_IN_PU),
-	PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_IN_PU),
-	PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_IN_PU),
-	PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_IN_PU),
+	PINMUX_DATA(PTZ5_DATA, PTZ5_IN),
+	PINMUX_DATA(PTZ4_DATA, PTZ4_IN),
+	PINMUX_DATA(PTZ3_DATA, PTZ3_IN),
+	PINMUX_DATA(PTZ2_DATA, PTZ2_IN),
+	PINMUX_DATA(PTZ1_DATA, PTZ1_IN),
 
 	/* SCIF0 */
 	PINMUX_DATA(SCIF0_TXD_MARK, SCIF0_TXD),
@@ -789,199 +756,199 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PTA */
-	PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
-	PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
-	PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
-	PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
-	PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
-	PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
-	PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
-	PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+	PINMUX_GPIO(PTA7),
+	PINMUX_GPIO(PTA6),
+	PINMUX_GPIO(PTA5),
+	PINMUX_GPIO(PTA4),
+	PINMUX_GPIO(PTA3),
+	PINMUX_GPIO(PTA2),
+	PINMUX_GPIO(PTA1),
+	PINMUX_GPIO(PTA0),
 
 	/* PTB */
-	PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
-	PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
-	PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
-	PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
-	PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
-	PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
-	PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
-	PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+	PINMUX_GPIO(PTB7),
+	PINMUX_GPIO(PTB6),
+	PINMUX_GPIO(PTB5),
+	PINMUX_GPIO(PTB4),
+	PINMUX_GPIO(PTB3),
+	PINMUX_GPIO(PTB2),
+	PINMUX_GPIO(PTB1),
+	PINMUX_GPIO(PTB0),
 
 	/* PTC */
-	PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
-	PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
-	PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
-	PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
-	PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
-	PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+	PINMUX_GPIO(PTC7),
+	PINMUX_GPIO(PTC5),
+	PINMUX_GPIO(PTC4),
+	PINMUX_GPIO(PTC3),
+	PINMUX_GPIO(PTC2),
+	PINMUX_GPIO(PTC0),
 
 	/* PTD */
-	PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
-	PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
-	PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
-	PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
-	PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
-	PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
-	PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
-	PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+	PINMUX_GPIO(PTD7),
+	PINMUX_GPIO(PTD6),
+	PINMUX_GPIO(PTD5),
+	PINMUX_GPIO(PTD4),
+	PINMUX_GPIO(PTD3),
+	PINMUX_GPIO(PTD2),
+	PINMUX_GPIO(PTD1),
+	PINMUX_GPIO(PTD0),
 
 	/* PTE */
-	PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
-	PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
-	PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
-	PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
-	PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
-	PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+	PINMUX_GPIO(PTE7),
+	PINMUX_GPIO(PTE6),
+	PINMUX_GPIO(PTE5),
+	PINMUX_GPIO(PTE4),
+	PINMUX_GPIO(PTE1),
+	PINMUX_GPIO(PTE0),
 
 	/* PTF */
-	PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
-	PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
-	PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
-	PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
-	PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
-	PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
-	PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+	PINMUX_GPIO(PTF6),
+	PINMUX_GPIO(PTF5),
+	PINMUX_GPIO(PTF4),
+	PINMUX_GPIO(PTF3),
+	PINMUX_GPIO(PTF2),
+	PINMUX_GPIO(PTF1),
+	PINMUX_GPIO(PTF0),
 
 	/* PTG */
-	PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
-	PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
-	PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
-	PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
-	PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+	PINMUX_GPIO(PTG4),
+	PINMUX_GPIO(PTG3),
+	PINMUX_GPIO(PTG2),
+	PINMUX_GPIO(PTG1),
+	PINMUX_GPIO(PTG0),
 
 	/* PTH */
-	PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
-	PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
-	PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
-	PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
-	PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
-	PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
-	PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
-	PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+	PINMUX_GPIO(PTH7),
+	PINMUX_GPIO(PTH6),
+	PINMUX_GPIO(PTH5),
+	PINMUX_GPIO(PTH4),
+	PINMUX_GPIO(PTH3),
+	PINMUX_GPIO(PTH2),
+	PINMUX_GPIO(PTH1),
+	PINMUX_GPIO(PTH0),
 
 	/* PTJ */
-	PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
-	PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
-	PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
-	PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
-	PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+	PINMUX_GPIO(PTJ7),
+	PINMUX_GPIO(PTJ6),
+	PINMUX_GPIO(PTJ5),
+	PINMUX_GPIO(PTJ1),
+	PINMUX_GPIO(PTJ0),
 
 	/* PTK */
-	PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
-	PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
-	PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
-	PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
-	PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
-	PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
-	PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+	PINMUX_GPIO(PTK6),
+	PINMUX_GPIO(PTK5),
+	PINMUX_GPIO(PTK4),
+	PINMUX_GPIO(PTK3),
+	PINMUX_GPIO(PTK2),
+	PINMUX_GPIO(PTK1),
+	PINMUX_GPIO(PTK0),
 
 	/* PTL */
-	PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
-	PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
-	PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
-	PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
-	PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
-	PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
-	PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
-	PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+	PINMUX_GPIO(PTL7),
+	PINMUX_GPIO(PTL6),
+	PINMUX_GPIO(PTL5),
+	PINMUX_GPIO(PTL4),
+	PINMUX_GPIO(PTL3),
+	PINMUX_GPIO(PTL2),
+	PINMUX_GPIO(PTL1),
+	PINMUX_GPIO(PTL0),
 
 	/* PTM */
-	PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
-	PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
-	PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
-	PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
-	PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
-	PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
-	PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
-	PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+	PINMUX_GPIO(PTM7),
+	PINMUX_GPIO(PTM6),
+	PINMUX_GPIO(PTM5),
+	PINMUX_GPIO(PTM4),
+	PINMUX_GPIO(PTM3),
+	PINMUX_GPIO(PTM2),
+	PINMUX_GPIO(PTM1),
+	PINMUX_GPIO(PTM0),
 
 	/* PTN */
-	PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
-	PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
-	PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
-	PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
-	PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
-	PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
-	PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
-	PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+	PINMUX_GPIO(PTN7),
+	PINMUX_GPIO(PTN6),
+	PINMUX_GPIO(PTN5),
+	PINMUX_GPIO(PTN4),
+	PINMUX_GPIO(PTN3),
+	PINMUX_GPIO(PTN2),
+	PINMUX_GPIO(PTN1),
+	PINMUX_GPIO(PTN0),
 
 	/* PTQ */
-	PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
-	PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
-	PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
-	PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
-	PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
-	PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
-	PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+	PINMUX_GPIO(PTQ6),
+	PINMUX_GPIO(PTQ5),
+	PINMUX_GPIO(PTQ4),
+	PINMUX_GPIO(PTQ3),
+	PINMUX_GPIO(PTQ2),
+	PINMUX_GPIO(PTQ1),
+	PINMUX_GPIO(PTQ0),
 
 	/* PTR */
-	PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
-	PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
-	PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
-	PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
-	PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+	PINMUX_GPIO(PTR4),
+	PINMUX_GPIO(PTR3),
+	PINMUX_GPIO(PTR2),
+	PINMUX_GPIO(PTR1),
+	PINMUX_GPIO(PTR0),
 
 	/* PTS */
-	PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
-	PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
-	PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
-	PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
-	PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+	PINMUX_GPIO(PTS4),
+	PINMUX_GPIO(PTS3),
+	PINMUX_GPIO(PTS2),
+	PINMUX_GPIO(PTS1),
+	PINMUX_GPIO(PTS0),
 
 	/* PTT */
-	PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
-	PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
-	PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
-	PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
-	PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+	PINMUX_GPIO(PTT4),
+	PINMUX_GPIO(PTT3),
+	PINMUX_GPIO(PTT2),
+	PINMUX_GPIO(PTT1),
+	PINMUX_GPIO(PTT0),
 
 	/* PTU */
-	PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
-	PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
-	PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
-	PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
-	PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+	PINMUX_GPIO(PTU4),
+	PINMUX_GPIO(PTU3),
+	PINMUX_GPIO(PTU2),
+	PINMUX_GPIO(PTU1),
+	PINMUX_GPIO(PTU0),
 
 	/* PTV */
-	PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
-	PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
-	PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
-	PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
-	PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+	PINMUX_GPIO(PTV4),
+	PINMUX_GPIO(PTV3),
+	PINMUX_GPIO(PTV2),
+	PINMUX_GPIO(PTV1),
+	PINMUX_GPIO(PTV0),
 
 	/* PTW */
-	PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
-	PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
-	PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
-	PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
-	PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
-	PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
-	PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+	PINMUX_GPIO(PTW6),
+	PINMUX_GPIO(PTW5),
+	PINMUX_GPIO(PTW4),
+	PINMUX_GPIO(PTW3),
+	PINMUX_GPIO(PTW2),
+	PINMUX_GPIO(PTW1),
+	PINMUX_GPIO(PTW0),
 
 	/* PTX */
-	PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
-	PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
-	PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
-	PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
-	PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
-	PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
-	PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+	PINMUX_GPIO(PTX6),
+	PINMUX_GPIO(PTX5),
+	PINMUX_GPIO(PTX4),
+	PINMUX_GPIO(PTX3),
+	PINMUX_GPIO(PTX2),
+	PINMUX_GPIO(PTX1),
+	PINMUX_GPIO(PTX0),
 
 	/* PTY */
-	PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
-	PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
-	PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
-	PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
-	PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
-	PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+	PINMUX_GPIO(PTY5),
+	PINMUX_GPIO(PTY4),
+	PINMUX_GPIO(PTY3),
+	PINMUX_GPIO(PTY2),
+	PINMUX_GPIO(PTY1),
+	PINMUX_GPIO(PTY0),
 
 	/* PTZ */
-	PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
-	PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
-	PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
-	PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
-	PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
+	PINMUX_GPIO(PTZ5),
+	PINMUX_GPIO(PTZ4),
+	PINMUX_GPIO(PTZ3),
+	PINMUX_GPIO(PTZ2),
+	PINMUX_GPIO(PTZ1),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -1270,14 +1237,14 @@
 
 static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
-		VIO_D7_SCIF1_SCK, PTA7_OUT, PTA7_IN_PD, PTA7_IN,
-		VIO_D6_SCIF1_RXD, 0, PTA6_IN_PD, PTA6_IN,
-		VIO_D5_SCIF1_TXD, PTA5_OUT, PTA5_IN_PD, PTA5_IN,
-		VIO_D4, 0, PTA4_IN_PD, PTA4_IN,
-		VIO_D3, 0, PTA3_IN_PD, PTA3_IN,
-		VIO_D2, 0, PTA2_IN_PD, PTA2_IN,
-		VIO_D1, 0, PTA1_IN_PD, PTA1_IN,
-		VIO_D0_LCDLCLK, 0, PTA0_IN_PD, PTA0_IN }
+		VIO_D7_SCIF1_SCK, PTA7_OUT, 0, PTA7_IN,
+		VIO_D6_SCIF1_RXD, 0, 0, PTA6_IN,
+		VIO_D5_SCIF1_TXD, PTA5_OUT, 0, PTA5_IN,
+		VIO_D4, 0, 0, PTA4_IN,
+		VIO_D3, 0, 0, PTA3_IN,
+		VIO_D2, 0, 0, PTA2_IN,
+		VIO_D1, 0, 0, PTA1_IN,
+		VIO_D0_LCDLCLK, 0, 0, PTA0_IN }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
 		HPD55, PTB7_OUT, 0, PTB7_IN,
@@ -1290,9 +1257,9 @@
 		HPD48, PTB0_OUT, 0, PTB0_IN }
 	},
 	{ PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
-		0, 0, PTC7_IN_PU, PTC7_IN,
+		0, 0, 0, PTC7_IN,
 		0, 0, 0, 0,
-		IOIS16, 0, PTC5_IN_PU, PTC5_IN,
+		IOIS16, 0, 0, PTC5_IN,
 		HPDQM7, PTC4_OUT, 0, PTC4_IN,
 		HPDQM6, PTC3_OUT, 0, PTC3_IN,
 		HPDQM5, PTC2_OUT, 0, PTC2_IN,
@@ -1300,33 +1267,33 @@
 		HPDQM4, PTC0_OUT, 0, PTC0_IN }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
-		SDHICD, 0, PTD7_IN_PU, PTD7_IN,
-		SDHIWP, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
-		SDHID3, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
-		IRQ2_SDHID2, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
-		SDHID1, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
-		SDHID0, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
-		SDHICMD, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
+		SDHICD, 0, 0, PTD7_IN,
+		SDHIWP, PTD6_OUT, 0, PTD6_IN,
+		SDHID3, PTD5_OUT, 0, PTD5_IN,
+		IRQ2_SDHID2, PTD4_OUT, 0, PTD4_IN,
+		SDHID1, PTD3_OUT, 0, PTD3_IN,
+		SDHID0, PTD2_OUT, 0, PTD2_IN,
+		SDHICMD, PTD1_OUT, 0, PTD1_IN,
 		SDHICLK, PTD0_OUT, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
-		A25, PTE7_OUT, PTE7_IN_PD, PTE7_IN,
-		A24, PTE6_OUT, PTE6_IN_PD, PTE6_IN,
-		A23, PTE5_OUT, PTE5_IN_PD, PTE5_IN,
-		A22, PTE4_OUT, PTE4_IN_PD, PTE4_IN,
+		A25, PTE7_OUT, 0, PTE7_IN,
+		A24, PTE6_OUT, 0, PTE6_IN,
+		A23, PTE5_OUT, 0, PTE5_IN,
+		A22, PTE4_OUT, 0, PTE4_IN,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		IRQ5, PTE1_OUT, PTE1_IN_PD, PTE1_IN,
-		IRQ4_BS, PTE0_OUT, PTE0_IN_PD, PTE0_IN }
+		IRQ5, PTE1_OUT, 0, PTE1_IN,
+		IRQ4_BS, PTE0_OUT, 0, PTE0_IN }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
 		0, 0, 0, 0,
-		PTF6, PTF6_OUT, PTF6_IN_PD, PTF6_IN,
-		SIOSCK_SIUBOBT, PTF5_OUT, PTF5_IN_PD, PTF5_IN,
-		SIOSTRB1_SIUBOLR, PTF4_OUT, PTF4_IN_PD, PTF4_IN,
-		SIOSTRB0_SIUBIBT, PTF3_OUT, PTF3_IN_PD, PTF3_IN,
-		SIOD_SIUBILR, PTF2_OUT, PTF2_IN_PD, PTF2_IN,
-		SIORXD_SIUBISLD, 0, PTF1_IN_PD, PTF1_IN,
+		PTF6, PTF6_OUT, 0, PTF6_IN,
+		SIOSCK_SIUBOBT, PTF5_OUT, 0, PTF5_IN,
+		SIOSTRB1_SIUBOLR, PTF4_OUT, 0, PTF4_IN,
+		SIOSTRB0_SIUBIBT, PTF3_OUT, 0, PTF3_IN,
+		SIOD_SIUBILR, PTF2_OUT, 0, PTF2_IN,
+		SIORXD_SIUBISLD, 0, 0, PTF1_IN,
 		SIOTXD_SIUBOSLD, PTF0_OUT, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
@@ -1341,13 +1308,13 @@
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
 		LCDVCPWC_LCDVCPWC2, PTH7_OUT, 0, 0,
-		LCDVSYN2_DACK, PTH6_OUT, PTH6_IN_PD, PTH6_IN,
-		LCDVSYN, PTH5_OUT, PTH5_IN_PD, PTH5_IN,
+		LCDVSYN2_DACK, PTH6_OUT, 0, PTH6_IN,
+		LCDVSYN, PTH5_OUT, 0, PTH5_IN,
 		LCDDISP_LCDRS, PTH4_OUT, 0, 0,
 		LCDHSYN_LCDCS, PTH3_OUT, 0, 0,
 		LCDDON_LCDDON2, PTH2_OUT, 0, 0,
-		LCDD17_DV_HSYNC, PTH1_OUT, PTH1_IN_PD, PTH1_IN,
-		LCDD16_DV_VSYNC, PTH0_OUT, PTH0_IN_PD, PTH0_IN }
+		LCDD17_DV_HSYNC, PTH1_OUT, 0, PTH1_IN,
+		LCDD16_DV_VSYNC, PTH0_OUT, 0, PTH0_IN }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
 		STATUS0, PTJ7_OUT, 0, 0,
@@ -1356,38 +1323,38 @@
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		IRQ1, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
-		IRQ0, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+		IRQ1, PTJ1_OUT, 0, PTJ1_IN,
+		IRQ0, PTJ0_OUT, 0, PTJ0_IN }
 	},
 	{ PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
 		0, 0, 0, 0,
-		SIUAILR_SIOF1_SS2, PTK6_OUT, PTK6_IN_PD, PTK6_IN,
-		SIUAIBT_SIOF1_SS1, PTK5_OUT, PTK5_IN_PD, PTK5_IN,
-		SIUAOLR_SIOF1_SYNC, PTK4_OUT, PTK4_IN_PD, PTK4_IN,
-		SIUAOBT_SIOF1_SCK, PTK3_OUT, PTK3_IN_PD, PTK3_IN,
-		SIUAISLD_SIOF1_RXD, 0, PTK2_IN_PD, PTK2_IN,
+		SIUAILR_SIOF1_SS2, PTK6_OUT, 0, PTK6_IN,
+		SIUAIBT_SIOF1_SS1, PTK5_OUT, 0, PTK5_IN,
+		SIUAOLR_SIOF1_SYNC, PTK4_OUT, 0, PTK4_IN,
+		SIUAOBT_SIOF1_SCK, PTK3_OUT, 0, PTK3_IN,
+		SIUAISLD_SIOF1_RXD, 0, 0, PTK2_IN,
 		SIUAOSLD_SIOF1_TXD, PTK1_OUT, 0, 0,
-		PTK0, PTK0_OUT, PTK0_IN_PD, PTK0_IN }
+		PTK0, PTK0_OUT, 0, PTK0_IN }
 	},
 	{ PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
-		LCDD15_DV_D15, PTL7_OUT, PTL7_IN_PD, PTL7_IN,
-		LCDD14_DV_D14, PTL6_OUT, PTL6_IN_PD, PTL6_IN,
-		LCDD13_DV_D13, PTL5_OUT, PTL5_IN_PD, PTL5_IN,
-		LCDD12_DV_D12, PTL4_OUT, PTL4_IN_PD, PTL4_IN,
-		LCDD11_DV_D11, PTL3_OUT, PTL3_IN_PD, PTL3_IN,
-		LCDD10_DV_D10, PTL2_OUT, PTL2_IN_PD, PTL2_IN,
-		LCDD9_DV_D9, PTL1_OUT, PTL1_IN_PD, PTL1_IN,
-		LCDD8_DV_D8, PTL0_OUT, PTL0_IN_PD, PTL0_IN }
+		LCDD15_DV_D15, PTL7_OUT, 0, PTL7_IN,
+		LCDD14_DV_D14, PTL6_OUT, 0, PTL6_IN,
+		LCDD13_DV_D13, PTL5_OUT, 0, PTL5_IN,
+		LCDD12_DV_D12, PTL4_OUT, 0, PTL4_IN,
+		LCDD11_DV_D11, PTL3_OUT, 0, PTL3_IN,
+		LCDD10_DV_D10, PTL2_OUT, 0, PTL2_IN,
+		LCDD9_DV_D9, PTL1_OUT, 0, PTL1_IN,
+		LCDD8_DV_D8, PTL0_OUT, 0, PTL0_IN }
 	},
 	{ PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
-		LCDD7_DV_D7, PTM7_OUT, PTM7_IN_PD, PTM7_IN,
-		LCDD6_DV_D6, PTM6_OUT, PTM6_IN_PD, PTM6_IN,
-		LCDD5_DV_D5, PTM5_OUT, PTM5_IN_PD, PTM5_IN,
-		LCDD4_DV_D4, PTM4_OUT, PTM4_IN_PD, PTM4_IN,
-		LCDD3_DV_D3, PTM3_OUT, PTM3_IN_PD, PTM3_IN,
-		LCDD2_DV_D2, PTM2_OUT, PTM2_IN_PD, PTM2_IN,
-		LCDD1_DV_D1, PTM1_OUT, PTM1_IN_PD, PTM1_IN,
-		LCDD0_DV_D0, PTM0_OUT, PTM0_IN_PD, PTM0_IN }
+		LCDD7_DV_D7, PTM7_OUT, 0, PTM7_IN,
+		LCDD6_DV_D6, PTM6_OUT, 0, PTM6_IN,
+		LCDD5_DV_D5, PTM5_OUT, 0, PTM5_IN,
+		LCDD4_DV_D4, PTM4_OUT, 0, PTM4_IN,
+		LCDD3_DV_D3, PTM3_OUT, 0, PTM3_IN,
+		LCDD2_DV_D2, PTM2_OUT, 0, PTM2_IN,
+		LCDD1_DV_D1, PTM1_OUT, 0, PTM1_IN,
+		LCDD0_DV_D0, PTM0_OUT, 0, PTM0_IN }
 	},
 	{ PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
 		HPD63, PTN7_OUT, 0, PTN7_IN,
@@ -1402,12 +1369,12 @@
 	{ PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
 		0, 0, 0, 0,
 		SIOF0_SS2_SIM_RST, PTQ6_OUT, 0, 0,
-		SIOF0_SS1_TS_SPSYNC, PTQ5_OUT, PTQ5_IN_PD, PTQ5_IN,
-		SIOF0_SYNC_TS_SDEN, PTQ4_OUT, PTQ4_IN_PD, PTQ4_IN,
-		SIOF0_SCK_TS_SCK, PTQ3_OUT, PTQ3_IN_PD, PTQ3_IN,
-		PTQ2, 0, PTQ2_IN_PD, PTQ2_IN,
+		SIOF0_SS1_TS_SPSYNC, PTQ5_OUT, 0, PTQ5_IN,
+		SIOF0_SYNC_TS_SDEN, PTQ4_OUT, 0, PTQ4_IN,
+		SIOF0_SCK_TS_SCK, PTQ3_OUT, 0, PTQ3_IN,
+		PTQ2, 0, 0, PTQ2_IN,
 		PTQ1, PTQ1_OUT, 0, 0,
-		PTQ0, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
+		PTQ0, PTQ0_OUT, 0, PTQ0_IN }
 	},
 	{ PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
 		0, 0, 0, 0,
@@ -1415,7 +1382,7 @@
 		0, 0, 0, 0,
 		LCDRD, PTR4_OUT, 0, 0,
 		CS6B_CE1B_LCDCS2, PTR3_OUT, 0, 0,
-		WAIT, 0, PTR2_IN_PU, PTR2_IN,
+		WAIT, 0, 0, PTR2_IN,
 		LCDDCK_LCDWR, PTR1_OUT, 0, 0,
 		LCDVEPWC_LCDVEPWC2, PTR0_OUT, 0, 0 }
 	},
@@ -1423,80 +1390,80 @@
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		SCIF0_CTS_SIUAISPD, 0, PTS4_IN_PD, PTS4_IN,
+		SCIF0_CTS_SIUAISPD, 0, 0, PTS4_IN,
 		SCIF0_RTS_SIUAOSPD, PTS3_OUT, 0, 0,
-		SCIF0_SCK_TPUTO, PTS2_OUT, PTS2_IN_PD, PTS2_IN,
-		SCIF0_RXD, 0, PTS1_IN_PD, PTS1_IN,
+		SCIF0_SCK_TPUTO, PTS2_OUT, 0, PTS2_IN,
+		SCIF0_RXD, 0, 0, PTS1_IN,
 		SCIF0_TXD, PTS0_OUT, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		FOE_VIO_VD2, PTT4_OUT, PTT4_IN_PD, PTT4_IN,
-		FWE, PTT3_OUT, PTT3_IN_PD, PTT3_IN,
-		FSC, PTT2_OUT, PTT2_IN_PD, PTT2_IN,
-		DREQ0, 0, PTT1_IN_PD, PTT1_IN,
+		FOE_VIO_VD2, PTT4_OUT, 0, PTT4_IN,
+		FWE, PTT3_OUT, 0, PTT3_IN,
+		FSC, PTT2_OUT, 0, PTT2_IN,
+		DREQ0, 0, 0, PTT1_IN,
 		FCDE, PTT0_OUT, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		NAF2_VIO_D10, PTU4_OUT, PTU4_IN_PD, PTU4_IN,
-		NAF1_VIO_D9, PTU3_OUT, PTU3_IN_PD, PTU3_IN,
-		NAF0_VIO_D8, PTU2_OUT, PTU2_IN_PD, PTU2_IN,
-		FRB_VIO_CLK2, 0, PTU1_IN_PD, PTU1_IN,
-		FCE_VIO_HD2, PTU0_OUT, PTU0_IN_PD, PTU0_IN }
+		NAF2_VIO_D10, PTU4_OUT, 0, PTU4_IN,
+		NAF1_VIO_D9, PTU3_OUT, 0, PTU3_IN,
+		NAF0_VIO_D8, PTU2_OUT, 0, PTU2_IN,
+		FRB_VIO_CLK2, 0, 0, PTU1_IN,
+		FCE_VIO_HD2, PTU0_OUT, 0, PTU0_IN }
 	},
 	{ PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		NAF7_VIO_D15, PTV4_OUT, PTV4_IN_PD, PTV4_IN,
-		NAF6_VIO_D14, PTV3_OUT, PTV3_IN_PD, PTV3_IN,
-		NAF5_VIO_D13, PTV2_OUT, PTV2_IN_PD, PTV2_IN,
-		NAF4_VIO_D12, PTV1_OUT, PTV1_IN_PD, PTV1_IN,
-		NAF3_VIO_D11, PTV0_OUT, PTV0_IN_PD, PTV0_IN }
+		NAF7_VIO_D15, PTV4_OUT, 0, PTV4_IN,
+		NAF6_VIO_D14, PTV3_OUT, 0, PTV3_IN,
+		NAF5_VIO_D13, PTV2_OUT, 0, PTV2_IN,
+		NAF4_VIO_D12, PTV1_OUT, 0, PTV1_IN,
+		NAF3_VIO_D11, PTV0_OUT, 0, PTV0_IN }
 	},
 	{ PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
 		0, 0, 0, 0,
-		VIO_FLD_SCIF2_CTS, 0, PTW6_IN_PD, PTW6_IN,
+		VIO_FLD_SCIF2_CTS, 0, 0, PTW6_IN,
 		VIO_CKO_SCIF2_RTS, PTW5_OUT, 0, 0,
-		VIO_STEX_SCIF2_SCK, PTW4_OUT, PTW4_IN_PD, PTW4_IN,
-		VIO_STEM_SCIF2_TXD, PTW3_OUT, PTW3_IN_PD, PTW3_IN,
-		VIO_HD_SCIF2_RXD, PTW2_OUT, PTW2_IN_PD, PTW2_IN,
-		VIO_VD_SCIF1_CTS, PTW1_OUT, PTW1_IN_PD, PTW1_IN,
-		VIO_CLK_SCIF1_RTS, PTW0_OUT, PTW0_IN_PD, PTW0_IN }
+		VIO_STEX_SCIF2_SCK, PTW4_OUT, 0, PTW4_IN,
+		VIO_STEM_SCIF2_TXD, PTW3_OUT, 0, PTW3_IN,
+		VIO_HD_SCIF2_RXD, PTW2_OUT, 0, PTW2_IN,
+		VIO_VD_SCIF1_CTS, PTW1_OUT, 0, PTW1_IN,
+		VIO_CLK_SCIF1_RTS, PTW0_OUT, 0, PTW0_IN }
 	},
 	{ PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
 		0, 0, 0, 0,
-		CS6A_CE2B, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
-		LCDD23, PTX5_OUT, PTX5_IN_PD, PTX5_IN,
-		LCDD22, PTX4_OUT, PTX4_IN_PD, PTX4_IN,
-		LCDD21, PTX3_OUT, PTX3_IN_PD, PTX3_IN,
-		LCDD20, PTX2_OUT, PTX2_IN_PD, PTX2_IN,
-		LCDD19_DV_CLKI, PTX1_OUT, PTX1_IN_PD, PTX1_IN,
-		LCDD18_DV_CLK, PTX0_OUT, PTX0_IN_PD, PTX0_IN }
+		CS6A_CE2B, PTX6_OUT, 0, PTX6_IN,
+		LCDD23, PTX5_OUT, 0, PTX5_IN,
+		LCDD22, PTX4_OUT, 0, PTX4_IN,
+		LCDD21, PTX3_OUT, 0, PTX3_IN,
+		LCDD20, PTX2_OUT, 0, PTX2_IN,
+		LCDD19_DV_CLKI, PTX1_OUT, 0, PTX1_IN,
+		LCDD18_DV_CLK, PTX0_OUT, 0, PTX0_IN }
 	},
 	{ PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		KEYOUT5_IN5, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
-		KEYOUT4_IN6, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
-		KEYOUT3, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
-		KEYOUT2, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
+		KEYOUT5_IN5, PTY5_OUT, 0, PTY5_IN,
+		KEYOUT4_IN6, PTY4_OUT, 0, PTY4_IN,
+		KEYOUT3, PTY3_OUT, 0, PTY3_IN,
+		KEYOUT2, PTY2_OUT, 0, PTY2_IN,
 		KEYOUT1, PTY1_OUT, 0, 0,
-		KEYOUT0, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
+		KEYOUT0, PTY0_OUT, 0, PTY0_IN }
 	},
 	{ PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		KEYIN4_IRQ7, 0, PTZ5_IN_PU, PTZ5_IN,
-		KEYIN3, 0, PTZ4_IN_PU, PTZ4_IN,
-		KEYIN2, 0, PTZ3_IN_PU, PTZ3_IN,
-		KEYIN1, 0, PTZ2_IN_PU, PTZ2_IN,
-		KEYIN0_IRQ6, 0, PTZ1_IN_PU, PTZ1_IN,
+		KEYIN4_IRQ7, 0, 0, PTZ5_IN,
+		KEYIN3, 0, 0, PTZ4_IN,
+		KEYIN2, 0, 0, PTZ3_IN,
+		KEYIN1, 0, 0, PTZ2_IN,
+		KEYIN0_IRQ6, 0, 0, PTZ1_IN,
 		0, 0, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
@@ -1763,8 +1730,6 @@
 const struct sh_pfc_soc_info sh7722_pinmux_info = {
 	.name = "sh7722_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pd = { PINMUX_INPUT_PULLDOWN_BEGIN, PINMUX_INPUT_PULLDOWN_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7723.c b/drivers/pinctrl/sh-pfc/pfc-sh7723.c
index 07ad1d8..1cecc91 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7723.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7723.c
@@ -102,12 +102,6 @@
 	PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PTA4_IN_PU, PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
-	PTB2_IN_PU, PTB1_IN_PU,
-	PTR2_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
 	PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
@@ -350,16 +344,16 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* PTA GPIO */
 	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
 	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
 	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
-	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
-	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
-	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
-	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
-	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT),
+	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT),
+	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT),
+	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT),
+	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT),
 
 	/* PTB GPIO */
 	PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
@@ -367,8 +361,8 @@
 	PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
 	PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
 	PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
-	PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
-	PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
+	PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
+	PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
 	PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
 
 	/* PTC GPIO */
@@ -487,7 +481,7 @@
 	PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
 	PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
 	PINMUX_DATA(PTR3_DATA, PTR3_IN),
-	PINMUX_DATA(PTR2_DATA, PTR2_IN, PTR2_IN_PU),
+	PINMUX_DATA(PTR2_DATA, PTR2_IN),
 	PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
 	PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
 
@@ -925,220 +919,220 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PTA */
-	PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
-	PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
-	PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
-	PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
-	PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
-	PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
-	PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
-	PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+	PINMUX_GPIO(PTA7),
+	PINMUX_GPIO(PTA6),
+	PINMUX_GPIO(PTA5),
+	PINMUX_GPIO(PTA4),
+	PINMUX_GPIO(PTA3),
+	PINMUX_GPIO(PTA2),
+	PINMUX_GPIO(PTA1),
+	PINMUX_GPIO(PTA0),
 
 	/* PTB */
-	PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
-	PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
-	PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
-	PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
-	PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
-	PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
-	PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
-	PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+	PINMUX_GPIO(PTB7),
+	PINMUX_GPIO(PTB6),
+	PINMUX_GPIO(PTB5),
+	PINMUX_GPIO(PTB4),
+	PINMUX_GPIO(PTB3),
+	PINMUX_GPIO(PTB2),
+	PINMUX_GPIO(PTB1),
+	PINMUX_GPIO(PTB0),
 
 	/* PTC */
-	PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
-	PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
-	PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
-	PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
-	PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
-	PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
-	PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
-	PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+	PINMUX_GPIO(PTC7),
+	PINMUX_GPIO(PTC6),
+	PINMUX_GPIO(PTC5),
+	PINMUX_GPIO(PTC4),
+	PINMUX_GPIO(PTC3),
+	PINMUX_GPIO(PTC2),
+	PINMUX_GPIO(PTC1),
+	PINMUX_GPIO(PTC0),
 
 	/* PTD */
-	PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
-	PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
-	PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
-	PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
-	PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
-	PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
-	PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
-	PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+	PINMUX_GPIO(PTD7),
+	PINMUX_GPIO(PTD6),
+	PINMUX_GPIO(PTD5),
+	PINMUX_GPIO(PTD4),
+	PINMUX_GPIO(PTD3),
+	PINMUX_GPIO(PTD2),
+	PINMUX_GPIO(PTD1),
+	PINMUX_GPIO(PTD0),
 
 	/* PTE */
-	PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
-	PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
-	PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
-	PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
-	PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
-	PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+	PINMUX_GPIO(PTE5),
+	PINMUX_GPIO(PTE4),
+	PINMUX_GPIO(PTE3),
+	PINMUX_GPIO(PTE2),
+	PINMUX_GPIO(PTE1),
+	PINMUX_GPIO(PTE0),
 
 	/* PTF */
-	PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
-	PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
-	PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
-	PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
-	PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
-	PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
-	PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
-	PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+	PINMUX_GPIO(PTF7),
+	PINMUX_GPIO(PTF6),
+	PINMUX_GPIO(PTF5),
+	PINMUX_GPIO(PTF4),
+	PINMUX_GPIO(PTF3),
+	PINMUX_GPIO(PTF2),
+	PINMUX_GPIO(PTF1),
+	PINMUX_GPIO(PTF0),
 
 	/* PTG */
-	PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
-	PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
-	PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
-	PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
-	PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
-	PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+	PINMUX_GPIO(PTG5),
+	PINMUX_GPIO(PTG4),
+	PINMUX_GPIO(PTG3),
+	PINMUX_GPIO(PTG2),
+	PINMUX_GPIO(PTG1),
+	PINMUX_GPIO(PTG0),
 
 	/* PTH */
-	PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
-	PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
-	PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
-	PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
-	PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
-	PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
-	PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
-	PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+	PINMUX_GPIO(PTH7),
+	PINMUX_GPIO(PTH6),
+	PINMUX_GPIO(PTH5),
+	PINMUX_GPIO(PTH4),
+	PINMUX_GPIO(PTH3),
+	PINMUX_GPIO(PTH2),
+	PINMUX_GPIO(PTH1),
+	PINMUX_GPIO(PTH0),
 
 	/* PTJ */
-	PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
-	PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
-	PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
-	PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
-	PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
-	PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+	PINMUX_GPIO(PTJ7),
+	PINMUX_GPIO(PTJ5),
+	PINMUX_GPIO(PTJ3),
+	PINMUX_GPIO(PTJ2),
+	PINMUX_GPIO(PTJ1),
+	PINMUX_GPIO(PTJ0),
 
 	/* PTK */
-	PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
-	PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
-	PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
-	PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
-	PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
-	PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
-	PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
-	PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+	PINMUX_GPIO(PTK7),
+	PINMUX_GPIO(PTK6),
+	PINMUX_GPIO(PTK5),
+	PINMUX_GPIO(PTK4),
+	PINMUX_GPIO(PTK3),
+	PINMUX_GPIO(PTK2),
+	PINMUX_GPIO(PTK1),
+	PINMUX_GPIO(PTK0),
 
 	/* PTL */
-	PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
-	PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
-	PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
-	PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
-	PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
-	PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
-	PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
-	PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+	PINMUX_GPIO(PTL7),
+	PINMUX_GPIO(PTL6),
+	PINMUX_GPIO(PTL5),
+	PINMUX_GPIO(PTL4),
+	PINMUX_GPIO(PTL3),
+	PINMUX_GPIO(PTL2),
+	PINMUX_GPIO(PTL1),
+	PINMUX_GPIO(PTL0),
 
 	/* PTM */
-	PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
-	PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
-	PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
-	PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
-	PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
-	PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
-	PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
-	PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+	PINMUX_GPIO(PTM7),
+	PINMUX_GPIO(PTM6),
+	PINMUX_GPIO(PTM5),
+	PINMUX_GPIO(PTM4),
+	PINMUX_GPIO(PTM3),
+	PINMUX_GPIO(PTM2),
+	PINMUX_GPIO(PTM1),
+	PINMUX_GPIO(PTM0),
 
 	/* PTN */
-	PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
-	PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
-	PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
-	PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
-	PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
-	PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
-	PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
-	PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+	PINMUX_GPIO(PTN7),
+	PINMUX_GPIO(PTN6),
+	PINMUX_GPIO(PTN5),
+	PINMUX_GPIO(PTN4),
+	PINMUX_GPIO(PTN3),
+	PINMUX_GPIO(PTN2),
+	PINMUX_GPIO(PTN1),
+	PINMUX_GPIO(PTN0),
 
 	/* PTQ */
-	PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
-	PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
-	PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
-	PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+	PINMUX_GPIO(PTQ3),
+	PINMUX_GPIO(PTQ2),
+	PINMUX_GPIO(PTQ1),
+	PINMUX_GPIO(PTQ0),
 
 	/* PTR */
-	PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
-	PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
-	PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
-	PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
-	PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
-	PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
-	PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
-	PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+	PINMUX_GPIO(PTR7),
+	PINMUX_GPIO(PTR6),
+	PINMUX_GPIO(PTR5),
+	PINMUX_GPIO(PTR4),
+	PINMUX_GPIO(PTR3),
+	PINMUX_GPIO(PTR2),
+	PINMUX_GPIO(PTR1),
+	PINMUX_GPIO(PTR0),
 
 	/* PTS */
-	PINMUX_GPIO(GPIO_PTS7, PTS7_DATA),
-	PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
-	PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
-	PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
-	PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
-	PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
-	PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
-	PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+	PINMUX_GPIO(PTS7),
+	PINMUX_GPIO(PTS6),
+	PINMUX_GPIO(PTS5),
+	PINMUX_GPIO(PTS4),
+	PINMUX_GPIO(PTS3),
+	PINMUX_GPIO(PTS2),
+	PINMUX_GPIO(PTS1),
+	PINMUX_GPIO(PTS0),
 
 	/* PTT */
-	PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
-	PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
-	PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
-	PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
-	PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
-	PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+	PINMUX_GPIO(PTT5),
+	PINMUX_GPIO(PTT4),
+	PINMUX_GPIO(PTT3),
+	PINMUX_GPIO(PTT2),
+	PINMUX_GPIO(PTT1),
+	PINMUX_GPIO(PTT0),
 
 	/* PTU */
-	PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
-	PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
-	PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
-	PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
-	PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
-	PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+	PINMUX_GPIO(PTU5),
+	PINMUX_GPIO(PTU4),
+	PINMUX_GPIO(PTU3),
+	PINMUX_GPIO(PTU2),
+	PINMUX_GPIO(PTU1),
+	PINMUX_GPIO(PTU0),
 
 	/* PTV */
-	PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
-	PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
-	PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
-	PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
-	PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
-	PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
-	PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
-	PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+	PINMUX_GPIO(PTV7),
+	PINMUX_GPIO(PTV6),
+	PINMUX_GPIO(PTV5),
+	PINMUX_GPIO(PTV4),
+	PINMUX_GPIO(PTV3),
+	PINMUX_GPIO(PTV2),
+	PINMUX_GPIO(PTV1),
+	PINMUX_GPIO(PTV0),
 
 	/* PTW */
-	PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
-	PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
-	PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
-	PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
-	PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
-	PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
-	PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
-	PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+	PINMUX_GPIO(PTW7),
+	PINMUX_GPIO(PTW6),
+	PINMUX_GPIO(PTW5),
+	PINMUX_GPIO(PTW4),
+	PINMUX_GPIO(PTW3),
+	PINMUX_GPIO(PTW2),
+	PINMUX_GPIO(PTW1),
+	PINMUX_GPIO(PTW0),
 
 	/* PTX */
-	PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
-	PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
-	PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
-	PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
-	PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
-	PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
-	PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
-	PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+	PINMUX_GPIO(PTX7),
+	PINMUX_GPIO(PTX6),
+	PINMUX_GPIO(PTX5),
+	PINMUX_GPIO(PTX4),
+	PINMUX_GPIO(PTX3),
+	PINMUX_GPIO(PTX2),
+	PINMUX_GPIO(PTX1),
+	PINMUX_GPIO(PTX0),
 
 	/* PTY */
-	PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
-	PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
-	PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
-	PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
-	PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
-	PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
-	PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
-	PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+	PINMUX_GPIO(PTY7),
+	PINMUX_GPIO(PTY6),
+	PINMUX_GPIO(PTY5),
+	PINMUX_GPIO(PTY4),
+	PINMUX_GPIO(PTY3),
+	PINMUX_GPIO(PTY2),
+	PINMUX_GPIO(PTY1),
+	PINMUX_GPIO(PTY0),
 
 	/* PTZ */
-	PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
-	PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
-	PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
-	PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
-	PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
-	PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
-	PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
-	PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+	PINMUX_GPIO(PTZ7),
+	PINMUX_GPIO(PTZ6),
+	PINMUX_GPIO(PTZ5),
+	PINMUX_GPIO(PTZ4),
+	PINMUX_GPIO(PTZ3),
+	PINMUX_GPIO(PTZ2),
+	PINMUX_GPIO(PTZ1),
+	PINMUX_GPIO(PTZ0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -1520,11 +1514,11 @@
 		PTA7_FN, PTA7_OUT, 0, PTA7_IN,
 		PTA6_FN, PTA6_OUT, 0, PTA6_IN,
 		PTA5_FN, PTA5_OUT, 0, PTA5_IN,
-		PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
-		PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
-		PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
-		PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
-		PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+		PTA4_FN, PTA4_OUT, 0, PTA4_IN,
+		PTA3_FN, PTA3_OUT, 0, PTA3_IN,
+		PTA2_FN, PTA2_OUT, 0, PTA2_IN,
+		PTA1_FN, PTA1_OUT, 0, PTA1_IN,
+		PTA0_FN, PTA0_OUT, 0, PTA0_IN }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
 		PTB7_FN, PTB7_OUT, 0, PTB7_IN,
@@ -1532,8 +1526,8 @@
 		PTB5_FN, PTB5_OUT, 0, PTB5_IN,
 		PTB4_FN, PTB4_OUT, 0, PTB4_IN,
 		PTB3_FN, PTB3_OUT, 0, PTB3_IN,
-		PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
-		PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
+		PTB2_FN, PTB2_OUT, 0, PTB2_IN,
+		PTB1_FN, PTB1_OUT, 0, PTB1_IN,
 		PTB0_FN, PTB0_OUT, 0, PTB0_IN }
 	},
 	{ PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
@@ -1662,7 +1656,7 @@
 		PTR5_FN, PTR5_OUT, 0, PTR5_IN,
 		PTR4_FN, PTR4_OUT, 0, PTR4_IN,
 		PTR3_FN, 0, 0, PTR3_IN,
-		PTR2_FN, 0, PTR2_IN_PU, PTR2_IN,
+		PTR2_FN, 0, 0, PTR2_IN,
 		PTR1_FN, PTR1_OUT, 0, PTR1_IN,
 		PTR0_FN, PTR0_OUT, 0, PTR0_IN }
 	},
@@ -1888,7 +1882,6 @@
 const struct sh_pfc_soc_info sh7723_pinmux_info = {
 	.name = "sh7723_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7724.c b/drivers/pinctrl/sh-pfc/pfc-sh7724.c
index 35e5516..1085ab5 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7724.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7724.c
@@ -117,52 +117,6 @@
 	PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
-	PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
-	PTB7_IN_PU, PTB6_IN_PU, PTB5_IN_PU, PTB4_IN_PU,
-	PTB3_IN_PU, PTB2_IN_PU, PTB1_IN_PU, PTB0_IN_PU,
-	PTC7_IN_PU, PTC6_IN_PU, PTC5_IN_PU, PTC4_IN_PU,
-	PTC3_IN_PU, PTC2_IN_PU, PTC1_IN_PU, PTC0_IN_PU,
-	PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
-	PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
-	PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
-	PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
-	PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
-	PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
-	PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
-	PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
-	PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
-	PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
-	PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
-	PTL7_IN_PU, PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
-	PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
-	PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
-	PTM3_IN_PU, PTM2_IN_PU, PTM1_IN_PU, PTM0_IN_PU,
-	PTN7_IN_PU, PTN6_IN_PU, PTN5_IN_PU, PTN4_IN_PU,
-	PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
-	PTQ7_IN_PU, PTQ6_IN_PU, PTQ5_IN_PU, PTQ4_IN_PU,
-	PTQ3_IN_PU, PTQ2_IN_PU, PTQ1_IN_PU, PTQ0_IN_PU,
-	PTR7_IN_PU, PTR6_IN_PU, PTR5_IN_PU, PTR4_IN_PU,
-	PTR3_IN_PU, PTR2_IN_PU, PTR1_IN_PU, PTR0_IN_PU,
-		    PTS6_IN_PU, PTS5_IN_PU, PTS4_IN_PU,
-	PTS3_IN_PU, PTS2_IN_PU, PTS1_IN_PU, PTS0_IN_PU,
-	PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
-	PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
-	PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
-	PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
-	PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
-	PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
-	PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
-	PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
-	PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
-	PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
-	PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
-	PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
-	PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
-	PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
 	PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
@@ -572,66 +526,66 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* PTA GPIO */
-	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT, PTA7_IN_PU),
-	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT, PTA6_IN_PU),
-	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT, PTA5_IN_PU),
-	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT, PTA4_IN_PU),
-	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT, PTA3_IN_PU),
-	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT, PTA2_IN_PU),
-	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT, PTA1_IN_PU),
-	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT, PTA0_IN_PU),
+	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
+	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
+	PINMUX_DATA(PTA5_DATA, PTA5_IN, PTA5_OUT),
+	PINMUX_DATA(PTA4_DATA, PTA4_IN, PTA4_OUT),
+	PINMUX_DATA(PTA3_DATA, PTA3_IN, PTA3_OUT),
+	PINMUX_DATA(PTA2_DATA, PTA2_IN, PTA2_OUT),
+	PINMUX_DATA(PTA1_DATA, PTA1_IN, PTA1_OUT),
+	PINMUX_DATA(PTA0_DATA, PTA0_IN, PTA0_OUT),
 
 	/* PTB GPIO */
-	PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT, PTB7_IN_PU),
-	PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT, PTB6_IN_PU),
-	PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT, PTB5_IN_PU),
-	PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT, PTB4_IN_PU),
-	PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT, PTB3_IN_PU),
-	PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT, PTB2_IN_PU),
-	PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT, PTB1_IN_PU),
-	PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT, PTB0_IN_PU),
+	PINMUX_DATA(PTB7_DATA, PTB7_IN, PTB7_OUT),
+	PINMUX_DATA(PTB6_DATA, PTB6_IN, PTB6_OUT),
+	PINMUX_DATA(PTB5_DATA, PTB5_IN, PTB5_OUT),
+	PINMUX_DATA(PTB4_DATA, PTB4_IN, PTB4_OUT),
+	PINMUX_DATA(PTB3_DATA, PTB3_IN, PTB3_OUT),
+	PINMUX_DATA(PTB2_DATA, PTB2_IN, PTB2_OUT),
+	PINMUX_DATA(PTB1_DATA, PTB1_IN, PTB1_OUT),
+	PINMUX_DATA(PTB0_DATA, PTB0_IN, PTB0_OUT),
 
 	/* PTC GPIO */
-	PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT, PTC7_IN_PU),
-	PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT, PTC6_IN_PU),
-	PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT, PTC5_IN_PU),
-	PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT, PTC4_IN_PU),
-	PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT, PTC3_IN_PU),
-	PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT, PTC2_IN_PU),
-	PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT, PTC1_IN_PU),
-	PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT, PTC0_IN_PU),
+	PINMUX_DATA(PTC7_DATA, PTC7_IN, PTC7_OUT),
+	PINMUX_DATA(PTC6_DATA, PTC6_IN, PTC6_OUT),
+	PINMUX_DATA(PTC5_DATA, PTC5_IN, PTC5_OUT),
+	PINMUX_DATA(PTC4_DATA, PTC4_IN, PTC4_OUT),
+	PINMUX_DATA(PTC3_DATA, PTC3_IN, PTC3_OUT),
+	PINMUX_DATA(PTC2_DATA, PTC2_IN, PTC2_OUT),
+	PINMUX_DATA(PTC1_DATA, PTC1_IN, PTC1_OUT),
+	PINMUX_DATA(PTC0_DATA, PTC0_IN, PTC0_OUT),
 
 	/* PTD GPIO */
-	PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT, PTD7_IN_PU),
-	PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT, PTD6_IN_PU),
-	PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT, PTD5_IN_PU),
-	PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT, PTD4_IN_PU),
-	PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT, PTD3_IN_PU),
-	PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT, PTD2_IN_PU),
-	PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT, PTD1_IN_PU),
-	PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT, PTD0_IN_PU),
+	PINMUX_DATA(PTD7_DATA, PTD7_IN, PTD7_OUT),
+	PINMUX_DATA(PTD6_DATA, PTD6_IN, PTD6_OUT),
+	PINMUX_DATA(PTD5_DATA, PTD5_IN, PTD5_OUT),
+	PINMUX_DATA(PTD4_DATA, PTD4_IN, PTD4_OUT),
+	PINMUX_DATA(PTD3_DATA, PTD3_IN, PTD3_OUT),
+	PINMUX_DATA(PTD2_DATA, PTD2_IN, PTD2_OUT),
+	PINMUX_DATA(PTD1_DATA, PTD1_IN, PTD1_OUT),
+	PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
 
 	/* PTE GPIO */
-	PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT, PTE7_IN_PU),
-	PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT, PTE6_IN_PU),
-	PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT, PTE5_IN_PU),
-	PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT, PTE4_IN_PU),
-	PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT, PTE3_IN_PU),
-	PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT, PTE2_IN_PU),
-	PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT, PTE1_IN_PU),
-	PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT, PTE0_IN_PU),
+	PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
+	PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
+	PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
+	PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
+	PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
+	PINMUX_DATA(PTE2_DATA, PTE2_IN, PTE2_OUT),
+	PINMUX_DATA(PTE1_DATA, PTE1_IN, PTE1_OUT),
+	PINMUX_DATA(PTE0_DATA, PTE0_IN, PTE0_OUT),
 
 	/* PTF GPIO */
-	PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT, PTF7_IN_PU),
-	PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT, PTF6_IN_PU),
-	PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT, PTF5_IN_PU),
-	PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT, PTF4_IN_PU),
-	PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT, PTF3_IN_PU),
-	PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT, PTF2_IN_PU),
-	PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT, PTF1_IN_PU),
-	PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT, PTF0_IN_PU),
+	PINMUX_DATA(PTF7_DATA, PTF7_IN, PTF7_OUT),
+	PINMUX_DATA(PTF6_DATA, PTF6_IN, PTF6_OUT),
+	PINMUX_DATA(PTF5_DATA, PTF5_IN, PTF5_OUT),
+	PINMUX_DATA(PTF4_DATA, PTF4_IN, PTF4_OUT),
+	PINMUX_DATA(PTF3_DATA, PTF3_IN, PTF3_OUT),
+	PINMUX_DATA(PTF2_DATA, PTF2_IN, PTF2_OUT),
+	PINMUX_DATA(PTF1_DATA, PTF1_IN, PTF1_OUT),
+	PINMUX_DATA(PTF0_DATA, PTF0_IN, PTF0_OUT),
 
 	/* PTG GPIO */
 	PINMUX_DATA(PTG5_DATA, PTG5_OUT),
@@ -642,162 +596,162 @@
 	PINMUX_DATA(PTG0_DATA, PTG0_OUT),
 
 	/* PTH GPIO */
-	PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT, PTH7_IN_PU),
-	PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT, PTH6_IN_PU),
-	PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT, PTH5_IN_PU),
-	PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT, PTH4_IN_PU),
-	PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT, PTH3_IN_PU),
-	PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT, PTH2_IN_PU),
-	PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT, PTH1_IN_PU),
-	PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT, PTH0_IN_PU),
+	PINMUX_DATA(PTH7_DATA, PTH7_IN, PTH7_OUT),
+	PINMUX_DATA(PTH6_DATA, PTH6_IN, PTH6_OUT),
+	PINMUX_DATA(PTH5_DATA, PTH5_IN, PTH5_OUT),
+	PINMUX_DATA(PTH4_DATA, PTH4_IN, PTH4_OUT),
+	PINMUX_DATA(PTH3_DATA, PTH3_IN, PTH3_OUT),
+	PINMUX_DATA(PTH2_DATA, PTH2_IN, PTH2_OUT),
+	PINMUX_DATA(PTH1_DATA, PTH1_IN, PTH1_OUT),
+	PINMUX_DATA(PTH0_DATA, PTH0_IN, PTH0_OUT),
 
 	/* PTJ GPIO */
 	PINMUX_DATA(PTJ7_DATA, PTJ7_OUT),
 	PINMUX_DATA(PTJ6_DATA, PTJ6_OUT),
 	PINMUX_DATA(PTJ5_DATA, PTJ5_OUT),
-	PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT, PTJ3_IN_PU),
-	PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT, PTJ2_IN_PU),
-	PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT, PTJ1_IN_PU),
-	PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT, PTJ0_IN_PU),
+	PINMUX_DATA(PTJ3_DATA, PTJ3_IN, PTJ3_OUT),
+	PINMUX_DATA(PTJ2_DATA, PTJ2_IN, PTJ2_OUT),
+	PINMUX_DATA(PTJ1_DATA, PTJ1_IN, PTJ1_OUT),
+	PINMUX_DATA(PTJ0_DATA, PTJ0_IN, PTJ0_OUT),
 
 	/* PTK GPIO */
-	PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT, PTK7_IN_PU),
-	PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT, PTK6_IN_PU),
-	PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT, PTK5_IN_PU),
-	PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT, PTK4_IN_PU),
-	PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT, PTK3_IN_PU),
-	PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT, PTK2_IN_PU),
-	PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT, PTK1_IN_PU),
-	PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT, PTK0_IN_PU),
+	PINMUX_DATA(PTK7_DATA, PTK7_IN, PTK7_OUT),
+	PINMUX_DATA(PTK6_DATA, PTK6_IN, PTK6_OUT),
+	PINMUX_DATA(PTK5_DATA, PTK5_IN, PTK5_OUT),
+	PINMUX_DATA(PTK4_DATA, PTK4_IN, PTK4_OUT),
+	PINMUX_DATA(PTK3_DATA, PTK3_IN, PTK3_OUT),
+	PINMUX_DATA(PTK2_DATA, PTK2_IN, PTK2_OUT),
+	PINMUX_DATA(PTK1_DATA, PTK1_IN, PTK1_OUT),
+	PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
 
 	/* PTL GPIO */
-	PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT, PTL7_IN_PU),
-	PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT, PTL6_IN_PU),
-	PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT, PTL5_IN_PU),
-	PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT, PTL4_IN_PU),
-	PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT, PTL3_IN_PU),
-	PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT, PTL2_IN_PU),
-	PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT, PTL1_IN_PU),
-	PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT, PTL0_IN_PU),
+	PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
+	PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
+	PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
+	PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
+	PINMUX_DATA(PTL3_DATA, PTL3_IN, PTL3_OUT),
+	PINMUX_DATA(PTL2_DATA, PTL2_IN, PTL2_OUT),
+	PINMUX_DATA(PTL1_DATA, PTL1_IN, PTL1_OUT),
+	PINMUX_DATA(PTL0_DATA, PTL0_IN, PTL0_OUT),
 
 	/* PTM GPIO */
-	PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT, PTM7_IN_PU),
-	PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT, PTM6_IN_PU),
-	PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT, PTM5_IN_PU),
-	PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT, PTM4_IN_PU),
-	PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT, PTM3_IN_PU),
-	PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT, PTM2_IN_PU),
-	PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT, PTM1_IN_PU),
-	PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT, PTM0_IN_PU),
+	PINMUX_DATA(PTM7_DATA, PTM7_IN, PTM7_OUT),
+	PINMUX_DATA(PTM6_DATA, PTM6_IN, PTM6_OUT),
+	PINMUX_DATA(PTM5_DATA, PTM5_IN, PTM5_OUT),
+	PINMUX_DATA(PTM4_DATA, PTM4_IN, PTM4_OUT),
+	PINMUX_DATA(PTM3_DATA, PTM3_IN, PTM3_OUT),
+	PINMUX_DATA(PTM2_DATA, PTM2_IN, PTM2_OUT),
+	PINMUX_DATA(PTM1_DATA, PTM1_IN, PTM1_OUT),
+	PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
 
 	/* PTN GPIO */
-	PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT, PTN7_IN_PU),
-	PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT, PTN6_IN_PU),
-	PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT, PTN5_IN_PU),
-	PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT, PTN4_IN_PU),
-	PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT, PTN3_IN_PU),
-	PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT, PTN2_IN_PU),
-	PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT, PTN1_IN_PU),
-	PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT, PTN0_IN_PU),
+	PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
+	PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
+	PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
+	PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
+	PINMUX_DATA(PTN3_DATA, PTN3_IN, PTN3_OUT),
+	PINMUX_DATA(PTN2_DATA, PTN2_IN, PTN2_OUT),
+	PINMUX_DATA(PTN1_DATA, PTN1_IN, PTN1_OUT),
+	PINMUX_DATA(PTN0_DATA, PTN0_IN, PTN0_OUT),
 
 	/* PTQ GPIO */
-	PINMUX_DATA(PTQ7_DATA, PTQ7_IN, PTQ7_OUT, PTQ7_IN_PU),
-	PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT, PTQ6_IN_PU),
-	PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT, PTQ5_IN_PU),
-	PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT, PTQ4_IN_PU),
-	PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT, PTQ3_IN_PU),
-	PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT, PTQ2_IN_PU),
-	PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT, PTQ1_IN_PU),
-	PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT, PTQ0_IN_PU),
+	PINMUX_DATA(PTQ7_DATA, PTQ7_IN, PTQ7_OUT),
+	PINMUX_DATA(PTQ6_DATA, PTQ6_IN, PTQ6_OUT),
+	PINMUX_DATA(PTQ5_DATA, PTQ5_IN, PTQ5_OUT),
+	PINMUX_DATA(PTQ4_DATA, PTQ4_IN, PTQ4_OUT),
+	PINMUX_DATA(PTQ3_DATA, PTQ3_IN, PTQ3_OUT),
+	PINMUX_DATA(PTQ2_DATA, PTQ2_IN, PTQ2_OUT),
+	PINMUX_DATA(PTQ1_DATA, PTQ1_IN, PTQ1_OUT),
+	PINMUX_DATA(PTQ0_DATA, PTQ0_IN, PTQ0_OUT),
 
 	/* PTR GPIO */
-	PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT, PTR7_IN_PU),
-	PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT, PTR6_IN_PU),
-	PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT, PTR5_IN_PU),
-	PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT, PTR4_IN_PU),
-	PINMUX_DATA(PTR3_DATA, PTR3_IN,           PTR3_IN_PU),
-	PINMUX_DATA(PTR2_DATA, PTR2_IN,           PTR2_IN_PU),
-	PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT, PTR1_IN_PU),
-	PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT, PTR0_IN_PU),
+	PINMUX_DATA(PTR7_DATA, PTR7_IN, PTR7_OUT),
+	PINMUX_DATA(PTR6_DATA, PTR6_IN, PTR6_OUT),
+	PINMUX_DATA(PTR5_DATA, PTR5_IN, PTR5_OUT),
+	PINMUX_DATA(PTR4_DATA, PTR4_IN, PTR4_OUT),
+	PINMUX_DATA(PTR3_DATA, PTR3_IN),
+	PINMUX_DATA(PTR2_DATA, PTR2_IN),
+	PINMUX_DATA(PTR1_DATA, PTR1_IN, PTR1_OUT),
+	PINMUX_DATA(PTR0_DATA, PTR0_IN, PTR0_OUT),
 
 	/* PTS GPIO */
-	PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT, PTS6_IN_PU),
-	PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT, PTS5_IN_PU),
-	PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT, PTS4_IN_PU),
-	PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT, PTS3_IN_PU),
-	PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT, PTS2_IN_PU),
-	PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT, PTS1_IN_PU),
-	PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT, PTS0_IN_PU),
+	PINMUX_DATA(PTS6_DATA, PTS6_IN, PTS6_OUT),
+	PINMUX_DATA(PTS5_DATA, PTS5_IN, PTS5_OUT),
+	PINMUX_DATA(PTS4_DATA, PTS4_IN, PTS4_OUT),
+	PINMUX_DATA(PTS3_DATA, PTS3_IN, PTS3_OUT),
+	PINMUX_DATA(PTS2_DATA, PTS2_IN, PTS2_OUT),
+	PINMUX_DATA(PTS1_DATA, PTS1_IN, PTS1_OUT),
+	PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
 
 	/* PTT GPIO */
-	PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT, PTT7_IN_PU),
-	PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT, PTT6_IN_PU),
-	PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT, PTT5_IN_PU),
-	PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT, PTT4_IN_PU),
-	PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT, PTT3_IN_PU),
-	PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT, PTT2_IN_PU),
-	PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT, PTT1_IN_PU),
-	PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT, PTT0_IN_PU),
+	PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
+	PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
+	PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
+	PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
+	PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
+	PINMUX_DATA(PTT2_DATA, PTT2_IN, PTT2_OUT),
+	PINMUX_DATA(PTT1_DATA, PTT1_IN, PTT1_OUT),
+	PINMUX_DATA(PTT0_DATA, PTT0_IN, PTT0_OUT),
 
 	/* PTU GPIO */
-	PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT, PTU7_IN_PU),
-	PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT, PTU6_IN_PU),
-	PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT, PTU5_IN_PU),
-	PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT, PTU4_IN_PU),
-	PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT, PTU3_IN_PU),
-	PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT, PTU2_IN_PU),
-	PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT, PTU1_IN_PU),
-	PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT, PTU0_IN_PU),
+	PINMUX_DATA(PTU7_DATA, PTU7_IN, PTU7_OUT),
+	PINMUX_DATA(PTU6_DATA, PTU6_IN, PTU6_OUT),
+	PINMUX_DATA(PTU5_DATA, PTU5_IN, PTU5_OUT),
+	PINMUX_DATA(PTU4_DATA, PTU4_IN, PTU4_OUT),
+	PINMUX_DATA(PTU3_DATA, PTU3_IN, PTU3_OUT),
+	PINMUX_DATA(PTU2_DATA, PTU2_IN, PTU2_OUT),
+	PINMUX_DATA(PTU1_DATA, PTU1_IN, PTU1_OUT),
+	PINMUX_DATA(PTU0_DATA, PTU0_IN, PTU0_OUT),
 
 	/* PTV GPIO */
-	PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT, PTV7_IN_PU),
-	PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT, PTV6_IN_PU),
-	PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT, PTV5_IN_PU),
-	PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT, PTV4_IN_PU),
-	PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT, PTV3_IN_PU),
-	PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT, PTV2_IN_PU),
-	PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT, PTV1_IN_PU),
-	PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT, PTV0_IN_PU),
+	PINMUX_DATA(PTV7_DATA, PTV7_IN, PTV7_OUT),
+	PINMUX_DATA(PTV6_DATA, PTV6_IN, PTV6_OUT),
+	PINMUX_DATA(PTV5_DATA, PTV5_IN, PTV5_OUT),
+	PINMUX_DATA(PTV4_DATA, PTV4_IN, PTV4_OUT),
+	PINMUX_DATA(PTV3_DATA, PTV3_IN, PTV3_OUT),
+	PINMUX_DATA(PTV2_DATA, PTV2_IN, PTV2_OUT),
+	PINMUX_DATA(PTV1_DATA, PTV1_IN, PTV1_OUT),
+	PINMUX_DATA(PTV0_DATA, PTV0_IN, PTV0_OUT),
 
 	/* PTW GPIO */
-	PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT, PTW7_IN_PU),
-	PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT, PTW6_IN_PU),
-	PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT, PTW5_IN_PU),
-	PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT, PTW4_IN_PU),
-	PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT, PTW3_IN_PU),
-	PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT, PTW2_IN_PU),
-	PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT, PTW1_IN_PU),
-	PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT, PTW0_IN_PU),
+	PINMUX_DATA(PTW7_DATA, PTW7_IN, PTW7_OUT),
+	PINMUX_DATA(PTW6_DATA, PTW6_IN, PTW6_OUT),
+	PINMUX_DATA(PTW5_DATA, PTW5_IN, PTW5_OUT),
+	PINMUX_DATA(PTW4_DATA, PTW4_IN, PTW4_OUT),
+	PINMUX_DATA(PTW3_DATA, PTW3_IN, PTW3_OUT),
+	PINMUX_DATA(PTW2_DATA, PTW2_IN, PTW2_OUT),
+	PINMUX_DATA(PTW1_DATA, PTW1_IN, PTW1_OUT),
+	PINMUX_DATA(PTW0_DATA, PTW0_IN, PTW0_OUT),
 
 	/* PTX GPIO */
-	PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT, PTX7_IN_PU),
-	PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT, PTX6_IN_PU),
-	PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT, PTX5_IN_PU),
-	PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT, PTX4_IN_PU),
-	PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT, PTX3_IN_PU),
-	PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT, PTX2_IN_PU),
-	PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT, PTX1_IN_PU),
-	PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT, PTX0_IN_PU),
+	PINMUX_DATA(PTX7_DATA, PTX7_IN, PTX7_OUT),
+	PINMUX_DATA(PTX6_DATA, PTX6_IN, PTX6_OUT),
+	PINMUX_DATA(PTX5_DATA, PTX5_IN, PTX5_OUT),
+	PINMUX_DATA(PTX4_DATA, PTX4_IN, PTX4_OUT),
+	PINMUX_DATA(PTX3_DATA, PTX3_IN, PTX3_OUT),
+	PINMUX_DATA(PTX2_DATA, PTX2_IN, PTX2_OUT),
+	PINMUX_DATA(PTX1_DATA, PTX1_IN, PTX1_OUT),
+	PINMUX_DATA(PTX0_DATA, PTX0_IN, PTX0_OUT),
 
 	/* PTY GPIO */
-	PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT, PTY7_IN_PU),
-	PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT, PTY6_IN_PU),
-	PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT, PTY5_IN_PU),
-	PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT, PTY4_IN_PU),
-	PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT, PTY3_IN_PU),
-	PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT, PTY2_IN_PU),
-	PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT, PTY1_IN_PU),
-	PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT, PTY0_IN_PU),
+	PINMUX_DATA(PTY7_DATA, PTY7_IN, PTY7_OUT),
+	PINMUX_DATA(PTY6_DATA, PTY6_IN, PTY6_OUT),
+	PINMUX_DATA(PTY5_DATA, PTY5_IN, PTY5_OUT),
+	PINMUX_DATA(PTY4_DATA, PTY4_IN, PTY4_OUT),
+	PINMUX_DATA(PTY3_DATA, PTY3_IN, PTY3_OUT),
+	PINMUX_DATA(PTY2_DATA, PTY2_IN, PTY2_OUT),
+	PINMUX_DATA(PTY1_DATA, PTY1_IN, PTY1_OUT),
+	PINMUX_DATA(PTY0_DATA, PTY0_IN, PTY0_OUT),
 
 	/* PTZ GPIO */
-	PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT, PTZ7_IN_PU),
-	PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT, PTZ6_IN_PU),
-	PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT, PTZ5_IN_PU),
-	PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT, PTZ4_IN_PU),
-	PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT, PTZ3_IN_PU),
-	PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT, PTZ2_IN_PU),
-	PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT, PTZ1_IN_PU),
-	PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT, PTZ0_IN_PU),
+	PINMUX_DATA(PTZ7_DATA, PTZ7_IN, PTZ7_OUT),
+	PINMUX_DATA(PTZ6_DATA, PTZ6_IN, PTZ6_OUT),
+	PINMUX_DATA(PTZ5_DATA, PTZ5_IN, PTZ5_OUT),
+	PINMUX_DATA(PTZ4_DATA, PTZ4_IN, PTZ4_OUT),
+	PINMUX_DATA(PTZ3_DATA, PTZ3_IN, PTZ3_OUT),
+	PINMUX_DATA(PTZ2_DATA, PTZ2_IN, PTZ2_OUT),
+	PINMUX_DATA(PTZ1_DATA, PTZ1_IN, PTZ1_OUT),
+	PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
 
 	/* PTA FN */
 	PINMUX_DATA(D23_MARK,	PSA15_0, PSA14_0, PTA7_FN),
@@ -1194,230 +1148,230 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PTA */
-	PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
-	PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
-	PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
-	PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
-	PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
-	PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
-	PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
-	PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+	PINMUX_GPIO(PTA7),
+	PINMUX_GPIO(PTA6),
+	PINMUX_GPIO(PTA5),
+	PINMUX_GPIO(PTA4),
+	PINMUX_GPIO(PTA3),
+	PINMUX_GPIO(PTA2),
+	PINMUX_GPIO(PTA1),
+	PINMUX_GPIO(PTA0),
 
 	/* PTB */
-	PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
-	PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
-	PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
-	PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
-	PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
-	PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
-	PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
-	PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+	PINMUX_GPIO(PTB7),
+	PINMUX_GPIO(PTB6),
+	PINMUX_GPIO(PTB5),
+	PINMUX_GPIO(PTB4),
+	PINMUX_GPIO(PTB3),
+	PINMUX_GPIO(PTB2),
+	PINMUX_GPIO(PTB1),
+	PINMUX_GPIO(PTB0),
 
 	/* PTC */
-	PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
-	PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
-	PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
-	PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
-	PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
-	PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
-	PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
-	PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+	PINMUX_GPIO(PTC7),
+	PINMUX_GPIO(PTC6),
+	PINMUX_GPIO(PTC5),
+	PINMUX_GPIO(PTC4),
+	PINMUX_GPIO(PTC3),
+	PINMUX_GPIO(PTC2),
+	PINMUX_GPIO(PTC1),
+	PINMUX_GPIO(PTC0),
 
 	/* PTD */
-	PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
-	PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
-	PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
-	PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
-	PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
-	PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
-	PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
-	PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+	PINMUX_GPIO(PTD7),
+	PINMUX_GPIO(PTD6),
+	PINMUX_GPIO(PTD5),
+	PINMUX_GPIO(PTD4),
+	PINMUX_GPIO(PTD3),
+	PINMUX_GPIO(PTD2),
+	PINMUX_GPIO(PTD1),
+	PINMUX_GPIO(PTD0),
 
 	/* PTE */
-	PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
-	PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
-	PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
-	PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
-	PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
-	PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
-	PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
-	PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+	PINMUX_GPIO(PTE7),
+	PINMUX_GPIO(PTE6),
+	PINMUX_GPIO(PTE5),
+	PINMUX_GPIO(PTE4),
+	PINMUX_GPIO(PTE3),
+	PINMUX_GPIO(PTE2),
+	PINMUX_GPIO(PTE1),
+	PINMUX_GPIO(PTE0),
 
 	/* PTF */
-	PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
-	PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
-	PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
-	PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
-	PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
-	PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
-	PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
-	PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+	PINMUX_GPIO(PTF7),
+	PINMUX_GPIO(PTF6),
+	PINMUX_GPIO(PTF5),
+	PINMUX_GPIO(PTF4),
+	PINMUX_GPIO(PTF3),
+	PINMUX_GPIO(PTF2),
+	PINMUX_GPIO(PTF1),
+	PINMUX_GPIO(PTF0),
 
 	/* PTG */
-	PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
-	PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
-	PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
-	PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
-	PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
-	PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+	PINMUX_GPIO(PTG5),
+	PINMUX_GPIO(PTG4),
+	PINMUX_GPIO(PTG3),
+	PINMUX_GPIO(PTG2),
+	PINMUX_GPIO(PTG1),
+	PINMUX_GPIO(PTG0),
 
 	/* PTH */
-	PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
-	PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
-	PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
-	PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
-	PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
-	PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
-	PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
-	PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+	PINMUX_GPIO(PTH7),
+	PINMUX_GPIO(PTH6),
+	PINMUX_GPIO(PTH5),
+	PINMUX_GPIO(PTH4),
+	PINMUX_GPIO(PTH3),
+	PINMUX_GPIO(PTH2),
+	PINMUX_GPIO(PTH1),
+	PINMUX_GPIO(PTH0),
 
 	/* PTJ */
-	PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
-	PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
-	PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
-	PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
-	PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
-	PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
-	PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+	PINMUX_GPIO(PTJ7),
+	PINMUX_GPIO(PTJ6),
+	PINMUX_GPIO(PTJ5),
+	PINMUX_GPIO(PTJ3),
+	PINMUX_GPIO(PTJ2),
+	PINMUX_GPIO(PTJ1),
+	PINMUX_GPIO(PTJ0),
 
 	/* PTK */
-	PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
-	PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
-	PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
-	PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
-	PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
-	PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
-	PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
-	PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+	PINMUX_GPIO(PTK7),
+	PINMUX_GPIO(PTK6),
+	PINMUX_GPIO(PTK5),
+	PINMUX_GPIO(PTK4),
+	PINMUX_GPIO(PTK3),
+	PINMUX_GPIO(PTK2),
+	PINMUX_GPIO(PTK1),
+	PINMUX_GPIO(PTK0),
 
 	/* PTL */
-	PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
-	PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
-	PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
-	PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
-	PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
-	PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
-	PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
-	PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+	PINMUX_GPIO(PTL7),
+	PINMUX_GPIO(PTL6),
+	PINMUX_GPIO(PTL5),
+	PINMUX_GPIO(PTL4),
+	PINMUX_GPIO(PTL3),
+	PINMUX_GPIO(PTL2),
+	PINMUX_GPIO(PTL1),
+	PINMUX_GPIO(PTL0),
 
 	/* PTM */
-	PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
-	PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
-	PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
-	PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
-	PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
-	PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
-	PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
-	PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+	PINMUX_GPIO(PTM7),
+	PINMUX_GPIO(PTM6),
+	PINMUX_GPIO(PTM5),
+	PINMUX_GPIO(PTM4),
+	PINMUX_GPIO(PTM3),
+	PINMUX_GPIO(PTM2),
+	PINMUX_GPIO(PTM1),
+	PINMUX_GPIO(PTM0),
 
 	/* PTN */
-	PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
-	PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
-	PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
-	PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
-	PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
-	PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
-	PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
-	PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+	PINMUX_GPIO(PTN7),
+	PINMUX_GPIO(PTN6),
+	PINMUX_GPIO(PTN5),
+	PINMUX_GPIO(PTN4),
+	PINMUX_GPIO(PTN3),
+	PINMUX_GPIO(PTN2),
+	PINMUX_GPIO(PTN1),
+	PINMUX_GPIO(PTN0),
 
 	/* PTQ */
-	PINMUX_GPIO(GPIO_PTQ7, PTQ7_DATA),
-	PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
-	PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
-	PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
-	PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
-	PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
-	PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
-	PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+	PINMUX_GPIO(PTQ7),
+	PINMUX_GPIO(PTQ6),
+	PINMUX_GPIO(PTQ5),
+	PINMUX_GPIO(PTQ4),
+	PINMUX_GPIO(PTQ3),
+	PINMUX_GPIO(PTQ2),
+	PINMUX_GPIO(PTQ1),
+	PINMUX_GPIO(PTQ0),
 
 	/* PTR */
-	PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
-	PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
-	PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
-	PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
-	PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
-	PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
-	PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
-	PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+	PINMUX_GPIO(PTR7),
+	PINMUX_GPIO(PTR6),
+	PINMUX_GPIO(PTR5),
+	PINMUX_GPIO(PTR4),
+	PINMUX_GPIO(PTR3),
+	PINMUX_GPIO(PTR2),
+	PINMUX_GPIO(PTR1),
+	PINMUX_GPIO(PTR0),
 
 	/* PTS */
-	PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
-	PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
-	PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
-	PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
-	PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
-	PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
-	PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+	PINMUX_GPIO(PTS6),
+	PINMUX_GPIO(PTS5),
+	PINMUX_GPIO(PTS4),
+	PINMUX_GPIO(PTS3),
+	PINMUX_GPIO(PTS2),
+	PINMUX_GPIO(PTS1),
+	PINMUX_GPIO(PTS0),
 
 	/* PTT */
-	PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
-	PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
-	PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
-	PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
-	PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
-	PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
-	PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
-	PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+	PINMUX_GPIO(PTT7),
+	PINMUX_GPIO(PTT6),
+	PINMUX_GPIO(PTT5),
+	PINMUX_GPIO(PTT4),
+	PINMUX_GPIO(PTT3),
+	PINMUX_GPIO(PTT2),
+	PINMUX_GPIO(PTT1),
+	PINMUX_GPIO(PTT0),
 
 	/* PTU */
-	PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
-	PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
-	PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
-	PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
-	PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
-	PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
-	PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
-	PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+	PINMUX_GPIO(PTU7),
+	PINMUX_GPIO(PTU6),
+	PINMUX_GPIO(PTU5),
+	PINMUX_GPIO(PTU4),
+	PINMUX_GPIO(PTU3),
+	PINMUX_GPIO(PTU2),
+	PINMUX_GPIO(PTU1),
+	PINMUX_GPIO(PTU0),
 
 	/* PTV */
-	PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
-	PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
-	PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
-	PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
-	PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
-	PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
-	PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
-	PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+	PINMUX_GPIO(PTV7),
+	PINMUX_GPIO(PTV6),
+	PINMUX_GPIO(PTV5),
+	PINMUX_GPIO(PTV4),
+	PINMUX_GPIO(PTV3),
+	PINMUX_GPIO(PTV2),
+	PINMUX_GPIO(PTV1),
+	PINMUX_GPIO(PTV0),
 
 	/* PTW */
-	PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
-	PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
-	PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
-	PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
-	PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
-	PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
-	PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
-	PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+	PINMUX_GPIO(PTW7),
+	PINMUX_GPIO(PTW6),
+	PINMUX_GPIO(PTW5),
+	PINMUX_GPIO(PTW4),
+	PINMUX_GPIO(PTW3),
+	PINMUX_GPIO(PTW2),
+	PINMUX_GPIO(PTW1),
+	PINMUX_GPIO(PTW0),
 
 	/* PTX */
-	PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
-	PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
-	PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
-	PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
-	PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
-	PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
-	PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
-	PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+	PINMUX_GPIO(PTX7),
+	PINMUX_GPIO(PTX6),
+	PINMUX_GPIO(PTX5),
+	PINMUX_GPIO(PTX4),
+	PINMUX_GPIO(PTX3),
+	PINMUX_GPIO(PTX2),
+	PINMUX_GPIO(PTX1),
+	PINMUX_GPIO(PTX0),
 
 	/* PTY */
-	PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
-	PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
-	PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
-	PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
-	PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
-	PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
-	PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
-	PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+	PINMUX_GPIO(PTY7),
+	PINMUX_GPIO(PTY6),
+	PINMUX_GPIO(PTY5),
+	PINMUX_GPIO(PTY4),
+	PINMUX_GPIO(PTY3),
+	PINMUX_GPIO(PTY2),
+	PINMUX_GPIO(PTY1),
+	PINMUX_GPIO(PTY0),
 
 	/* PTZ */
-	PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
-	PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
-	PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
-	PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
-	PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
-	PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
-	PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
-	PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+	PINMUX_GPIO(PTZ7),
+	PINMUX_GPIO(PTZ6),
+	PINMUX_GPIO(PTZ5),
+	PINMUX_GPIO(PTZ4),
+	PINMUX_GPIO(PTZ3),
+	PINMUX_GPIO(PTZ2),
+	PINMUX_GPIO(PTZ1),
+	PINMUX_GPIO(PTZ0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -1789,64 +1743,64 @@
 
 static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xa4050100, 16, 2) {
-		PTA7_FN, PTA7_OUT, PTA7_IN_PU, PTA7_IN,
-		PTA6_FN, PTA6_OUT, PTA6_IN_PU, PTA6_IN,
-		PTA5_FN, PTA5_OUT, PTA5_IN_PU, PTA5_IN,
-		PTA4_FN, PTA4_OUT, PTA4_IN_PU, PTA4_IN,
-		PTA3_FN, PTA3_OUT, PTA3_IN_PU, PTA3_IN,
-		PTA2_FN, PTA2_OUT, PTA2_IN_PU, PTA2_IN,
-		PTA1_FN, PTA1_OUT, PTA1_IN_PU, PTA1_IN,
-		PTA0_FN, PTA0_OUT, PTA0_IN_PU, PTA0_IN }
+		PTA7_FN, PTA7_OUT, 0, PTA7_IN,
+		PTA6_FN, PTA6_OUT, 0, PTA6_IN,
+		PTA5_FN, PTA5_OUT, 0, PTA5_IN,
+		PTA4_FN, PTA4_OUT, 0, PTA4_IN,
+		PTA3_FN, PTA3_OUT, 0, PTA3_IN,
+		PTA2_FN, PTA2_OUT, 0, PTA2_IN,
+		PTA1_FN, PTA1_OUT, 0, PTA1_IN,
+		PTA0_FN, PTA0_OUT, 0, PTA0_IN }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xa4050102, 16, 2) {
-		PTB7_FN, PTB7_OUT, PTB7_IN_PU, PTB7_IN,
-		PTB6_FN, PTB6_OUT, PTB6_IN_PU, PTB6_IN,
-		PTB5_FN, PTB5_OUT, PTB5_IN_PU, PTB5_IN,
-		PTB4_FN, PTB4_OUT, PTB4_IN_PU, PTB4_IN,
-		PTB3_FN, PTB3_OUT, PTB3_IN_PU, PTB3_IN,
-		PTB2_FN, PTB2_OUT, PTB2_IN_PU, PTB2_IN,
-		PTB1_FN, PTB1_OUT, PTB1_IN_PU, PTB1_IN,
-		PTB0_FN, PTB0_OUT, PTB0_IN_PU, PTB0_IN }
+		PTB7_FN, PTB7_OUT, 0, PTB7_IN,
+		PTB6_FN, PTB6_OUT, 0, PTB6_IN,
+		PTB5_FN, PTB5_OUT, 0, PTB5_IN,
+		PTB4_FN, PTB4_OUT, 0, PTB4_IN,
+		PTB3_FN, PTB3_OUT, 0, PTB3_IN,
+		PTB2_FN, PTB2_OUT, 0, PTB2_IN,
+		PTB1_FN, PTB1_OUT, 0, PTB1_IN,
+		PTB0_FN, PTB0_OUT, 0, PTB0_IN }
 	},
 	{ PINMUX_CFG_REG("PCCR", 0xa4050104, 16, 2) {
-		PTC7_FN, PTC7_OUT, PTC7_IN_PU, PTC7_IN,
-		PTC6_FN, PTC6_OUT, PTC6_IN_PU, PTC6_IN,
-		PTC5_FN, PTC5_OUT, PTC5_IN_PU, PTC5_IN,
-		PTC4_FN, PTC4_OUT, PTC4_IN_PU, PTC4_IN,
-		PTC3_FN, PTC3_OUT, PTC3_IN_PU, PTC3_IN,
-		PTC2_FN, PTC2_OUT, PTC2_IN_PU, PTC2_IN,
-		PTC1_FN, PTC1_OUT, PTC1_IN_PU, PTC1_IN,
-		PTC0_FN, PTC0_OUT, PTC0_IN_PU, PTC0_IN }
+		PTC7_FN, PTC7_OUT, 0, PTC7_IN,
+		PTC6_FN, PTC6_OUT, 0, PTC6_IN,
+		PTC5_FN, PTC5_OUT, 0, PTC5_IN,
+		PTC4_FN, PTC4_OUT, 0, PTC4_IN,
+		PTC3_FN, PTC3_OUT, 0, PTC3_IN,
+		PTC2_FN, PTC2_OUT, 0, PTC2_IN,
+		PTC1_FN, PTC1_OUT, 0, PTC1_IN,
+		PTC0_FN, PTC0_OUT, 0, PTC0_IN }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xa4050106, 16, 2) {
-		PTD7_FN, PTD7_OUT, PTD7_IN_PU, PTD7_IN,
-		PTD6_FN, PTD6_OUT, PTD6_IN_PU, PTD6_IN,
-		PTD5_FN, PTD5_OUT, PTD5_IN_PU, PTD5_IN,
-		PTD4_FN, PTD4_OUT, PTD4_IN_PU, PTD4_IN,
-		PTD3_FN, PTD3_OUT, PTD3_IN_PU, PTD3_IN,
-		PTD2_FN, PTD2_OUT, PTD2_IN_PU, PTD2_IN,
-		PTD1_FN, PTD1_OUT, PTD1_IN_PU, PTD1_IN,
-		PTD0_FN, PTD0_OUT, PTD0_IN_PU, PTD0_IN }
+		PTD7_FN, PTD7_OUT, 0, PTD7_IN,
+		PTD6_FN, PTD6_OUT, 0, PTD6_IN,
+		PTD5_FN, PTD5_OUT, 0, PTD5_IN,
+		PTD4_FN, PTD4_OUT, 0, PTD4_IN,
+		PTD3_FN, PTD3_OUT, 0, PTD3_IN,
+		PTD2_FN, PTD2_OUT, 0, PTD2_IN,
+		PTD1_FN, PTD1_OUT, 0, PTD1_IN,
+		PTD0_FN, PTD0_OUT, 0, PTD0_IN }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xa4050108, 16, 2) {
-		PTE7_FN, PTE7_OUT, PTE7_IN_PU, PTE7_IN,
-		PTE6_FN, PTE6_OUT, PTE6_IN_PU, PTE6_IN,
-		PTE5_FN, PTE5_OUT, PTE5_IN_PU, PTE5_IN,
-		PTE4_FN, PTE4_OUT, PTE4_IN_PU, PTE4_IN,
-		PTE3_FN, PTE3_OUT, PTE3_IN_PU, PTE3_IN,
-		PTE2_FN, PTE2_OUT, PTE2_IN_PU, PTE2_IN,
-		PTE1_FN, PTE1_OUT, PTE1_IN_PU, PTE1_IN,
-		PTE0_FN, PTE0_OUT, PTE0_IN_PU, PTE0_IN }
+		PTE7_FN, PTE7_OUT, 0, PTE7_IN,
+		PTE6_FN, PTE6_OUT, 0, PTE6_IN,
+		PTE5_FN, PTE5_OUT, 0, PTE5_IN,
+		PTE4_FN, PTE4_OUT, 0, PTE4_IN,
+		PTE3_FN, PTE3_OUT, 0, PTE3_IN,
+		PTE2_FN, PTE2_OUT, 0, PTE2_IN,
+		PTE1_FN, PTE1_OUT, 0, PTE1_IN,
+		PTE0_FN, PTE0_OUT, 0, PTE0_IN }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xa405010a, 16, 2) {
-		PTF7_FN, PTF7_OUT, PTF7_IN_PU, PTF7_IN,
-		PTF6_FN, PTF6_OUT, PTF6_IN_PU, PTF6_IN,
-		PTF5_FN, PTF5_OUT, PTF5_IN_PU, PTF5_IN,
-		PTF4_FN, PTF4_OUT, PTF4_IN_PU, PTF4_IN,
-		PTF3_FN, PTF3_OUT, PTF3_IN_PU, PTF3_IN,
-		PTF2_FN, PTF2_OUT, PTF2_IN_PU, PTF2_IN,
-		PTF1_FN, PTF1_OUT, PTF1_IN_PU, PTF1_IN,
-		PTF0_FN, PTF0_OUT, PTF0_IN_PU, PTF0_IN }
+		PTF7_FN, PTF7_OUT, 0, PTF7_IN,
+		PTF6_FN, PTF6_OUT, 0, PTF6_IN,
+		PTF5_FN, PTF5_OUT, 0, PTF5_IN,
+		PTF4_FN, PTF4_OUT, 0, PTF4_IN,
+		PTF3_FN, PTF3_OUT, 0, PTF3_IN,
+		PTF2_FN, PTF2_OUT, 0, PTF2_IN,
+		PTF1_FN, PTF1_OUT, 0, PTF1_IN,
+		PTF0_FN, PTF0_OUT, 0, PTF0_IN }
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xa405010c, 16, 2) {
 		0, 0, 0, 0,
@@ -1859,164 +1813,164 @@
 		PTG0_FN, PTG0_OUT, 0, 0 }
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xa405010e, 16, 2) {
-		PTH7_FN, PTH7_OUT, PTH7_IN_PU, PTH7_IN,
-		PTH6_FN, PTH6_OUT, PTH6_IN_PU, PTH6_IN,
-		PTH5_FN, PTH5_OUT, PTH5_IN_PU, PTH5_IN,
-		PTH4_FN, PTH4_OUT, PTH4_IN_PU, PTH4_IN,
-		PTH3_FN, PTH3_OUT, PTH3_IN_PU, PTH3_IN,
-		PTH2_FN, PTH2_OUT, PTH2_IN_PU, PTH2_IN,
-		PTH1_FN, PTH1_OUT, PTH1_IN_PU, PTH1_IN,
-		PTH0_FN, PTH0_OUT, PTH0_IN_PU, PTH0_IN }
+		PTH7_FN, PTH7_OUT, 0, PTH7_IN,
+		PTH6_FN, PTH6_OUT, 0, PTH6_IN,
+		PTH5_FN, PTH5_OUT, 0, PTH5_IN,
+		PTH4_FN, PTH4_OUT, 0, PTH4_IN,
+		PTH3_FN, PTH3_OUT, 0, PTH3_IN,
+		PTH2_FN, PTH2_OUT, 0, PTH2_IN,
+		PTH1_FN, PTH1_OUT, 0, PTH1_IN,
+		PTH0_FN, PTH0_OUT, 0, PTH0_IN }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xa4050110, 16, 2) {
 		PTJ7_FN, PTJ7_OUT, 0, 0,
 		PTJ6_FN, PTJ6_OUT, 0, 0,
 		PTJ5_FN, PTJ5_OUT, 0, 0,
 		0, 0, 0, 0,
-		PTJ3_FN, PTJ3_OUT, PTJ3_IN_PU, PTJ3_IN,
-		PTJ2_FN, PTJ2_OUT, PTJ2_IN_PU, PTJ2_IN,
-		PTJ1_FN, PTJ1_OUT, PTJ1_IN_PU, PTJ1_IN,
-		PTJ0_FN, PTJ0_OUT, PTJ0_IN_PU, PTJ0_IN }
+		PTJ3_FN, PTJ3_OUT, 0, PTJ3_IN,
+		PTJ2_FN, PTJ2_OUT, 0, PTJ2_IN,
+		PTJ1_FN, PTJ1_OUT, 0, PTJ1_IN,
+		PTJ0_FN, PTJ0_OUT, 0, PTJ0_IN }
 	},
 	{ PINMUX_CFG_REG("PKCR", 0xa4050112, 16, 2) {
-		PTK7_FN, PTK7_OUT, PTK7_IN_PU, PTK7_IN,
-		PTK6_FN, PTK6_OUT, PTK6_IN_PU, PTK6_IN,
-		PTK5_FN, PTK5_OUT, PTK5_IN_PU, PTK5_IN,
-		PTK4_FN, PTK4_OUT, PTK4_IN_PU, PTK4_IN,
-		PTK3_FN, PTK3_OUT, PTK3_IN_PU, PTK3_IN,
-		PTK2_FN, PTK2_OUT, PTK2_IN_PU, PTK2_IN,
-		PTK1_FN, PTK1_OUT, PTK1_IN_PU, PTK1_IN,
-		PTK0_FN, PTK0_OUT, PTK0_IN_PU, PTK0_IN }
+		PTK7_FN, PTK7_OUT, 0, PTK7_IN,
+		PTK6_FN, PTK6_OUT, 0, PTK6_IN,
+		PTK5_FN, PTK5_OUT, 0, PTK5_IN,
+		PTK4_FN, PTK4_OUT, 0, PTK4_IN,
+		PTK3_FN, PTK3_OUT, 0, PTK3_IN,
+		PTK2_FN, PTK2_OUT, 0, PTK2_IN,
+		PTK1_FN, PTK1_OUT, 0, PTK1_IN,
+		PTK0_FN, PTK0_OUT, 0, PTK0_IN }
 	},
 	{ PINMUX_CFG_REG("PLCR", 0xa4050114, 16, 2) {
-		PTL7_FN, PTL7_OUT, PTL7_IN_PU, PTL7_IN,
-		PTL6_FN, PTL6_OUT, PTL6_IN_PU, PTL6_IN,
-		PTL5_FN, PTL5_OUT, PTL5_IN_PU, PTL5_IN,
-		PTL4_FN, PTL4_OUT, PTL4_IN_PU, PTL4_IN,
-		PTL3_FN, PTL3_OUT, PTL3_IN_PU, PTL3_IN,
-		PTL2_FN, PTL2_OUT, PTL2_IN_PU, PTL2_IN,
-		PTL1_FN, PTL1_OUT, PTL1_IN_PU, PTL1_IN,
-		PTL0_FN, PTL0_OUT, PTL0_IN_PU, PTL0_IN }
+		PTL7_FN, PTL7_OUT, 0, PTL7_IN,
+		PTL6_FN, PTL6_OUT, 0, PTL6_IN,
+		PTL5_FN, PTL5_OUT, 0, PTL5_IN,
+		PTL4_FN, PTL4_OUT, 0, PTL4_IN,
+		PTL3_FN, PTL3_OUT, 0, PTL3_IN,
+		PTL2_FN, PTL2_OUT, 0, PTL2_IN,
+		PTL1_FN, PTL1_OUT, 0, PTL1_IN,
+		PTL0_FN, PTL0_OUT, 0, PTL0_IN }
 	},
 	{ PINMUX_CFG_REG("PMCR", 0xa4050116, 16, 2) {
-		PTM7_FN, PTM7_OUT, PTM7_IN_PU, PTM7_IN,
-		PTM6_FN, PTM6_OUT, PTM6_IN_PU, PTM6_IN,
-		PTM5_FN, PTM5_OUT, PTM5_IN_PU, PTM5_IN,
-		PTM4_FN, PTM4_OUT, PTM4_IN_PU, PTM4_IN,
-		PTM3_FN, PTM3_OUT, PTM3_IN_PU, PTM3_IN,
-		PTM2_FN, PTM2_OUT, PTM2_IN_PU, PTM2_IN,
-		PTM1_FN, PTM1_OUT, PTM1_IN_PU, PTM1_IN,
-		PTM0_FN, PTM0_OUT, PTM0_IN_PU, PTM0_IN }
+		PTM7_FN, PTM7_OUT, 0, PTM7_IN,
+		PTM6_FN, PTM6_OUT, 0, PTM6_IN,
+		PTM5_FN, PTM5_OUT, 0, PTM5_IN,
+		PTM4_FN, PTM4_OUT, 0, PTM4_IN,
+		PTM3_FN, PTM3_OUT, 0, PTM3_IN,
+		PTM2_FN, PTM2_OUT, 0, PTM2_IN,
+		PTM1_FN, PTM1_OUT, 0, PTM1_IN,
+		PTM0_FN, PTM0_OUT, 0, PTM0_IN }
 	},
 	{ PINMUX_CFG_REG("PNCR", 0xa4050118, 16, 2) {
-		PTN7_FN, PTN7_OUT, PTN7_IN_PU, PTN7_IN,
-		PTN6_FN, PTN6_OUT, PTN6_IN_PU, PTN6_IN,
-		PTN5_FN, PTN5_OUT, PTN5_IN_PU, PTN5_IN,
-		PTN4_FN, PTN4_OUT, PTN4_IN_PU, PTN4_IN,
-		PTN3_FN, PTN3_OUT, PTN3_IN_PU, PTN3_IN,
-		PTN2_FN, PTN2_OUT, PTN2_IN_PU, PTN2_IN,
-		PTN1_FN, PTN1_OUT, PTN1_IN_PU, PTN1_IN,
-		PTN0_FN, PTN0_OUT, PTN0_IN_PU, PTN0_IN }
+		PTN7_FN, PTN7_OUT, 0, PTN7_IN,
+		PTN6_FN, PTN6_OUT, 0, PTN6_IN,
+		PTN5_FN, PTN5_OUT, 0, PTN5_IN,
+		PTN4_FN, PTN4_OUT, 0, PTN4_IN,
+		PTN3_FN, PTN3_OUT, 0, PTN3_IN,
+		PTN2_FN, PTN2_OUT, 0, PTN2_IN,
+		PTN1_FN, PTN1_OUT, 0, PTN1_IN,
+		PTN0_FN, PTN0_OUT, 0, PTN0_IN }
 	},
 	{ PINMUX_CFG_REG("PQCR", 0xa405011a, 16, 2) {
-		PTQ7_FN, PTQ7_OUT, PTQ7_IN_PU, PTQ7_IN,
-		PTQ6_FN, PTQ6_OUT, PTQ6_IN_PU, PTQ6_IN,
-		PTQ5_FN, PTQ5_OUT, PTQ5_IN_PU, PTQ5_IN,
-		PTQ4_FN, PTQ4_OUT, PTQ4_IN_PU, PTQ4_IN,
-		PTQ3_FN, PTQ3_OUT, PTQ3_IN_PU, PTQ3_IN,
-		PTQ2_FN, PTQ2_OUT, PTQ2_IN_PU, PTQ2_IN,
-		PTQ1_FN, PTQ1_OUT, PTQ1_IN_PU, PTQ1_IN,
-		PTQ0_FN, PTQ0_OUT, PTQ0_IN_PU, PTQ0_IN }
+		PTQ7_FN, PTQ7_OUT, 0, PTQ7_IN,
+		PTQ6_FN, PTQ6_OUT, 0, PTQ6_IN,
+		PTQ5_FN, PTQ5_OUT, 0, PTQ5_IN,
+		PTQ4_FN, PTQ4_OUT, 0, PTQ4_IN,
+		PTQ3_FN, PTQ3_OUT, 0, PTQ3_IN,
+		PTQ2_FN, PTQ2_OUT, 0, PTQ2_IN,
+		PTQ1_FN, PTQ1_OUT, 0, PTQ1_IN,
+		PTQ0_FN, PTQ0_OUT, 0, PTQ0_IN }
 	},
 	{ PINMUX_CFG_REG("PRCR", 0xa405011c, 16, 2) {
-		PTR7_FN, PTR7_OUT, PTR7_IN_PU, PTR7_IN,
-		PTR6_FN, PTR6_OUT, PTR6_IN_PU, PTR6_IN,
-		PTR5_FN, PTR5_OUT, PTR5_IN_PU, PTR5_IN,
-		PTR4_FN, PTR4_OUT, PTR4_IN_PU, PTR4_IN,
-		PTR3_FN, 0,        PTR3_IN_PU, PTR3_IN,
-		PTR2_FN, 0,        PTR2_IN_PU, PTR2_IN,
-		PTR1_FN, PTR1_OUT, PTR1_IN_PU, PTR1_IN,
-		PTR0_FN, PTR0_OUT, PTR0_IN_PU, PTR0_IN }
+		PTR7_FN, PTR7_OUT, 0, PTR7_IN,
+		PTR6_FN, PTR6_OUT, 0, PTR6_IN,
+		PTR5_FN, PTR5_OUT, 0, PTR5_IN,
+		PTR4_FN, PTR4_OUT, 0, PTR4_IN,
+		PTR3_FN, 0,        0, PTR3_IN,
+		PTR2_FN, 0,        0, PTR2_IN,
+		PTR1_FN, PTR1_OUT, 0, PTR1_IN,
+		PTR0_FN, PTR0_OUT, 0, PTR0_IN }
 	},
 	{ PINMUX_CFG_REG("PSCR", 0xa405011e, 16, 2) {
 		0, 0, 0, 0,
-		PTS6_FN, PTS6_OUT, PTS6_IN_PU, PTS6_IN,
-		PTS5_FN, PTS5_OUT, PTS5_IN_PU, PTS5_IN,
-		PTS4_FN, PTS4_OUT, PTS4_IN_PU, PTS4_IN,
-		PTS3_FN, PTS3_OUT, PTS3_IN_PU, PTS3_IN,
-		PTS2_FN, PTS2_OUT, PTS2_IN_PU, PTS2_IN,
-		PTS1_FN, PTS1_OUT, PTS1_IN_PU, PTS1_IN,
-		PTS0_FN, PTS0_OUT, PTS0_IN_PU, PTS0_IN }
+		PTS6_FN, PTS6_OUT, 0, PTS6_IN,
+		PTS5_FN, PTS5_OUT, 0, PTS5_IN,
+		PTS4_FN, PTS4_OUT, 0, PTS4_IN,
+		PTS3_FN, PTS3_OUT, 0, PTS3_IN,
+		PTS2_FN, PTS2_OUT, 0, PTS2_IN,
+		PTS1_FN, PTS1_OUT, 0, PTS1_IN,
+		PTS0_FN, PTS0_OUT, 0, PTS0_IN }
 	},
 	{ PINMUX_CFG_REG("PTCR", 0xa4050140, 16, 2) {
-		PTT7_FN, PTT7_OUT, PTT7_IN_PU, PTT7_IN,
-		PTT6_FN, PTT6_OUT, PTT6_IN_PU, PTT6_IN,
-		PTT5_FN, PTT5_OUT, PTT5_IN_PU, PTT5_IN,
-		PTT4_FN, PTT4_OUT, PTT4_IN_PU, PTT4_IN,
-		PTT3_FN, PTT3_OUT, PTT3_IN_PU, PTT3_IN,
-		PTT2_FN, PTT2_OUT, PTT2_IN_PU, PTT2_IN,
-		PTT1_FN, PTT1_OUT, PTT1_IN_PU, PTT1_IN,
-		PTT0_FN, PTT0_OUT, PTT0_IN_PU, PTT0_IN }
+		PTT7_FN, PTT7_OUT, 0, PTT7_IN,
+		PTT6_FN, PTT6_OUT, 0, PTT6_IN,
+		PTT5_FN, PTT5_OUT, 0, PTT5_IN,
+		PTT4_FN, PTT4_OUT, 0, PTT4_IN,
+		PTT3_FN, PTT3_OUT, 0, PTT3_IN,
+		PTT2_FN, PTT2_OUT, 0, PTT2_IN,
+		PTT1_FN, PTT1_OUT, 0, PTT1_IN,
+		PTT0_FN, PTT0_OUT, 0, PTT0_IN }
 	},
 	{ PINMUX_CFG_REG("PUCR", 0xa4050142, 16, 2) {
-		PTU7_FN, PTU7_OUT, PTU7_IN_PU, PTU7_IN,
-		PTU6_FN, PTU6_OUT, PTU6_IN_PU, PTU6_IN,
-		PTU5_FN, PTU5_OUT, PTU5_IN_PU, PTU5_IN,
-		PTU4_FN, PTU4_OUT, PTU4_IN_PU, PTU4_IN,
-		PTU3_FN, PTU3_OUT, PTU3_IN_PU, PTU3_IN,
-		PTU2_FN, PTU2_OUT, PTU2_IN_PU, PTU2_IN,
-		PTU1_FN, PTU1_OUT, PTU1_IN_PU, PTU1_IN,
-		PTU0_FN, PTU0_OUT, PTU0_IN_PU, PTU0_IN }
+		PTU7_FN, PTU7_OUT, 0, PTU7_IN,
+		PTU6_FN, PTU6_OUT, 0, PTU6_IN,
+		PTU5_FN, PTU5_OUT, 0, PTU5_IN,
+		PTU4_FN, PTU4_OUT, 0, PTU4_IN,
+		PTU3_FN, PTU3_OUT, 0, PTU3_IN,
+		PTU2_FN, PTU2_OUT, 0, PTU2_IN,
+		PTU1_FN, PTU1_OUT, 0, PTU1_IN,
+		PTU0_FN, PTU0_OUT, 0, PTU0_IN }
 	},
 	{ PINMUX_CFG_REG("PVCR", 0xa4050144, 16, 2) {
-		PTV7_FN, PTV7_OUT, PTV7_IN_PU, PTV7_IN,
-		PTV6_FN, PTV6_OUT, PTV6_IN_PU, PTV6_IN,
-		PTV5_FN, PTV5_OUT, PTV5_IN_PU, PTV5_IN,
-		PTV4_FN, PTV4_OUT, PTV4_IN_PU, PTV4_IN,
-		PTV3_FN, PTV3_OUT, PTV3_IN_PU, PTV3_IN,
-		PTV2_FN, PTV2_OUT, PTV2_IN_PU, PTV2_IN,
-		PTV1_FN, PTV1_OUT, PTV1_IN_PU, PTV1_IN,
-		PTV0_FN, PTV0_OUT, PTV0_IN_PU, PTV0_IN }
+		PTV7_FN, PTV7_OUT, 0, PTV7_IN,
+		PTV6_FN, PTV6_OUT, 0, PTV6_IN,
+		PTV5_FN, PTV5_OUT, 0, PTV5_IN,
+		PTV4_FN, PTV4_OUT, 0, PTV4_IN,
+		PTV3_FN, PTV3_OUT, 0, PTV3_IN,
+		PTV2_FN, PTV2_OUT, 0, PTV2_IN,
+		PTV1_FN, PTV1_OUT, 0, PTV1_IN,
+		PTV0_FN, PTV0_OUT, 0, PTV0_IN }
 	},
 	{ PINMUX_CFG_REG("PWCR", 0xa4050146, 16, 2) {
-		PTW7_FN, PTW7_OUT, PTW7_IN_PU, PTW7_IN,
-		PTW6_FN, PTW6_OUT, PTW6_IN_PU, PTW6_IN,
-		PTW5_FN, PTW5_OUT, PTW5_IN_PU, PTW5_IN,
-		PTW4_FN, PTW4_OUT, PTW4_IN_PU, PTW4_IN,
-		PTW3_FN, PTW3_OUT, PTW3_IN_PU, PTW3_IN,
-		PTW2_FN, PTW2_OUT, PTW2_IN_PU, PTW2_IN,
-		PTW1_FN, PTW1_OUT, PTW1_IN_PU, PTW1_IN,
-		PTW0_FN, PTW0_OUT, PTW0_IN_PU, PTW0_IN }
+		PTW7_FN, PTW7_OUT, 0, PTW7_IN,
+		PTW6_FN, PTW6_OUT, 0, PTW6_IN,
+		PTW5_FN, PTW5_OUT, 0, PTW5_IN,
+		PTW4_FN, PTW4_OUT, 0, PTW4_IN,
+		PTW3_FN, PTW3_OUT, 0, PTW3_IN,
+		PTW2_FN, PTW2_OUT, 0, PTW2_IN,
+		PTW1_FN, PTW1_OUT, 0, PTW1_IN,
+		PTW0_FN, PTW0_OUT, 0, PTW0_IN }
 	},
 	{ PINMUX_CFG_REG("PXCR", 0xa4050148, 16, 2) {
-		PTX7_FN, PTX7_OUT, PTX7_IN_PU, PTX7_IN,
-		PTX6_FN, PTX6_OUT, PTX6_IN_PU, PTX6_IN,
-		PTX5_FN, PTX5_OUT, PTX5_IN_PU, PTX5_IN,
-		PTX4_FN, PTX4_OUT, PTX4_IN_PU, PTX4_IN,
-		PTX3_FN, PTX3_OUT, PTX3_IN_PU, PTX3_IN,
-		PTX2_FN, PTX2_OUT, PTX2_IN_PU, PTX2_IN,
-		PTX1_FN, PTX1_OUT, PTX1_IN_PU, PTX1_IN,
-		PTX0_FN, PTX0_OUT, PTX0_IN_PU, PTX0_IN }
+		PTX7_FN, PTX7_OUT, 0, PTX7_IN,
+		PTX6_FN, PTX6_OUT, 0, PTX6_IN,
+		PTX5_FN, PTX5_OUT, 0, PTX5_IN,
+		PTX4_FN, PTX4_OUT, 0, PTX4_IN,
+		PTX3_FN, PTX3_OUT, 0, PTX3_IN,
+		PTX2_FN, PTX2_OUT, 0, PTX2_IN,
+		PTX1_FN, PTX1_OUT, 0, PTX1_IN,
+		PTX0_FN, PTX0_OUT, 0, PTX0_IN }
 	},
 	{ PINMUX_CFG_REG("PYCR", 0xa405014a, 16, 2) {
-		PTY7_FN, PTY7_OUT, PTY7_IN_PU, PTY7_IN,
-		PTY6_FN, PTY6_OUT, PTY6_IN_PU, PTY6_IN,
-		PTY5_FN, PTY5_OUT, PTY5_IN_PU, PTY5_IN,
-		PTY4_FN, PTY4_OUT, PTY4_IN_PU, PTY4_IN,
-		PTY3_FN, PTY3_OUT, PTY3_IN_PU, PTY3_IN,
-		PTY2_FN, PTY2_OUT, PTY2_IN_PU, PTY2_IN,
-		PTY1_FN, PTY1_OUT, PTY1_IN_PU, PTY1_IN,
-		PTY0_FN, PTY0_OUT, PTY0_IN_PU, PTY0_IN }
+		PTY7_FN, PTY7_OUT, 0, PTY7_IN,
+		PTY6_FN, PTY6_OUT, 0, PTY6_IN,
+		PTY5_FN, PTY5_OUT, 0, PTY5_IN,
+		PTY4_FN, PTY4_OUT, 0, PTY4_IN,
+		PTY3_FN, PTY3_OUT, 0, PTY3_IN,
+		PTY2_FN, PTY2_OUT, 0, PTY2_IN,
+		PTY1_FN, PTY1_OUT, 0, PTY1_IN,
+		PTY0_FN, PTY0_OUT, 0, PTY0_IN }
 	},
 	{ PINMUX_CFG_REG("PZCR", 0xa405014c, 16, 2) {
-		PTZ7_FN, PTZ7_OUT, PTZ7_IN_PU, PTZ7_IN,
-		PTZ6_FN, PTZ6_OUT, PTZ6_IN_PU, PTZ6_IN,
-		PTZ5_FN, PTZ5_OUT, PTZ5_IN_PU, PTZ5_IN,
-		PTZ4_FN, PTZ4_OUT, PTZ4_IN_PU, PTZ4_IN,
-		PTZ3_FN, PTZ3_OUT, PTZ3_IN_PU, PTZ3_IN,
-		PTZ2_FN, PTZ2_OUT, PTZ2_IN_PU, PTZ2_IN,
-		PTZ1_FN, PTZ1_OUT, PTZ1_IN_PU, PTZ1_IN,
-		PTZ0_FN, PTZ0_OUT, PTZ0_IN_PU, PTZ0_IN }
+		PTZ7_FN, PTZ7_OUT, 0, PTZ7_IN,
+		PTZ6_FN, PTZ6_OUT, 0, PTZ6_IN,
+		PTZ5_FN, PTZ5_OUT, 0, PTZ5_IN,
+		PTZ4_FN, PTZ4_OUT, 0, PTZ4_IN,
+		PTZ3_FN, PTZ3_OUT, 0, PTZ3_IN,
+		PTZ2_FN, PTZ2_OUT, 0, PTZ2_IN,
+		PTZ1_FN, PTZ1_OUT, 0, PTZ1_IN,
+		PTZ0_FN, PTZ0_OUT, 0, PTZ0_IN }
 	},
 	{ PINMUX_CFG_REG("PSELA", 0xa405014e, 16, 1) {
 		PSA15_0, PSA15_1,
@@ -2210,7 +2164,6 @@
 const struct sh_pfc_soc_info sh7724_pinmux_info = {
 	.name = "sh7724_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
index 2fd5b7d..ec0c47c 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -14,40 +14,30 @@
 
 #include "sh_pfc.h"
 
-#define CPU_32_PORT5(fn, pfx, sfx)				\
-	PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx),	\
-	PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx),	\
-	PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx),	\
-	PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx),	\
-	PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx),	\
-	PORT_1(fn, pfx##10, sfx), PORT_1(fn, pfx##11, sfx)
+#define PORT_GP_12(bank, fn, sfx)					\
+	PORT_GP_1(bank, 0, fn, sfx),  PORT_GP_1(bank, 1, fn, sfx),	\
+	PORT_GP_1(bank, 2, fn, sfx),  PORT_GP_1(bank, 3, fn, sfx),	\
+	PORT_GP_1(bank, 4, fn, sfx),  PORT_GP_1(bank, 5, fn, sfx),	\
+	PORT_GP_1(bank, 6, fn, sfx),  PORT_GP_1(bank, 7, fn, sfx),	\
+	PORT_GP_1(bank, 8, fn, sfx),  PORT_GP_1(bank, 9, fn, sfx),	\
+	PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx)
 
-/* GPSR0 - GPSR5 */
-#define CPU_ALL_PORT(fn, pfx, sfx)				\
-	PORT_32(fn, pfx##_0_, sfx),			\
-	PORT_32(fn, pfx##_1_, sfx),				\
-	PORT_32(fn, pfx##_2_, sfx),				\
-	PORT_32(fn, pfx##_3_, sfx),				\
-	PORT_32(fn, pfx##_4_, sfx),				\
-	CPU_32_PORT5(fn, pfx##_5_, sfx)
+#define CPU_ALL_PORT(fn, sfx)						\
+	PORT_GP_32(0, fn, sfx),						\
+	PORT_GP_32(1, fn, sfx),						\
+	PORT_GP_32(2, fn, sfx),						\
+	PORT_GP_32(3, fn, sfx),						\
+	PORT_GP_32(4, fn, sfx),						\
+	PORT_GP_12(5, fn, sfx)
 
-#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
-#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN,	\
-				       GP##pfx##_IN, GP##pfx##_OUT)
+#undef _GP_DATA
+#define _GP_DATA(bank, pin, name, sfx)					\
+	PINMUX_DATA(name##_DATA, name##_FN, name##_IN, name##_OUT)
 
-#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
-#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
-
-#define GP_ALL(str)	CPU_ALL_PORT(_PORT_ALL, GP, str)
-#define PINMUX_GPIO_GP_ALL()	CPU_ALL_PORT(_GP_GPIO, , unused)
-#define PINMUX_DATA_GP_ALL()	CPU_ALL_PORT(_GP_DATA, , unused)
-
-#define GP_INOUTSEL(bank) PORT_32_REV(_GP_INOUTSEL, _##bank##_, unused)
-#define GP_INDT(bank) PORT_32_REV(_GP_INDT, _##bank##_, unused)
-
-#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
-#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
-							  FN_##ipsr, FN_##fn)
+#define _GP_INOUTSEL(bank, pin, name, sfx)	name##_IN, name##_OUT
+#define _GP_INDT(bank, pin, name, sfx)		name##_DATA
+#define GP_INOUTSEL(bank)	PORT_GP_32_REV(bank, _GP_INOUTSEL, unused)
+#define GP_INDT(bank)		PORT_GP_32_REV(bank, _GP_INDT, unused)
 
 enum {
 	PINMUX_RESERVED = 0,
@@ -592,7 +582,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
 
 	PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7757.c b/drivers/pinctrl/sh-pfc/pfc-sh7757.c
index e074230..33d75e5 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7757.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7757.c
@@ -132,46 +132,6 @@
 	PTZ3_IN, PTZ2_IN, PTZ1_IN, PTZ0_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
-	PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
-	PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
-	PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
-	PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
-	PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
-	PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
-	PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
-	PTG7_IN_PU, PTG6_IN_PU,		    PTG4_IN_PU,
-	PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
-	PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
-	PTI7_IN_PU, PTI6_IN_PU,		    PTI4_IN_PU,
-	PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
-		    PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
-	PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
-	PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
-	PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
-		    PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
-	PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
-	PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
-					    PTN4_IN_PU,
-	PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
-	PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
-	PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
-	PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
-	PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
-	PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
-	PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
-	PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
-	PTV3_IN_PU, PTV2_IN_PU,
-				PTW1_IN_PU, PTW0_IN_PU,
-	PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
-	PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
-	PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
-	PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
-	PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
-	PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PTA7_OUT, PTA6_OUT, PTA5_OUT, PTA4_OUT,
 	PTA3_OUT, PTA2_OUT, PTA1_OUT, PTA0_OUT,
@@ -526,7 +486,7 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
+static const u16 pinmux_data[] = {
 	/* PTA GPIO */
 	PINMUX_DATA(PTA7_DATA, PTA7_IN, PTA7_OUT),
 	PINMUX_DATA(PTA6_DATA, PTA6_IN, PTA6_OUT),
@@ -1116,260 +1076,260 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PTA */
-	PINMUX_GPIO(GPIO_PTA7, PTA7_DATA),
-	PINMUX_GPIO(GPIO_PTA6, PTA6_DATA),
-	PINMUX_GPIO(GPIO_PTA5, PTA5_DATA),
-	PINMUX_GPIO(GPIO_PTA4, PTA4_DATA),
-	PINMUX_GPIO(GPIO_PTA3, PTA3_DATA),
-	PINMUX_GPIO(GPIO_PTA2, PTA2_DATA),
-	PINMUX_GPIO(GPIO_PTA1, PTA1_DATA),
-	PINMUX_GPIO(GPIO_PTA0, PTA0_DATA),
+	PINMUX_GPIO(PTA7),
+	PINMUX_GPIO(PTA6),
+	PINMUX_GPIO(PTA5),
+	PINMUX_GPIO(PTA4),
+	PINMUX_GPIO(PTA3),
+	PINMUX_GPIO(PTA2),
+	PINMUX_GPIO(PTA1),
+	PINMUX_GPIO(PTA0),
 
 	/* PTB */
-	PINMUX_GPIO(GPIO_PTB7, PTB7_DATA),
-	PINMUX_GPIO(GPIO_PTB6, PTB6_DATA),
-	PINMUX_GPIO(GPIO_PTB5, PTB5_DATA),
-	PINMUX_GPIO(GPIO_PTB4, PTB4_DATA),
-	PINMUX_GPIO(GPIO_PTB3, PTB3_DATA),
-	PINMUX_GPIO(GPIO_PTB2, PTB2_DATA),
-	PINMUX_GPIO(GPIO_PTB1, PTB1_DATA),
-	PINMUX_GPIO(GPIO_PTB0, PTB0_DATA),
+	PINMUX_GPIO(PTB7),
+	PINMUX_GPIO(PTB6),
+	PINMUX_GPIO(PTB5),
+	PINMUX_GPIO(PTB4),
+	PINMUX_GPIO(PTB3),
+	PINMUX_GPIO(PTB2),
+	PINMUX_GPIO(PTB1),
+	PINMUX_GPIO(PTB0),
 
 	/* PTC */
-	PINMUX_GPIO(GPIO_PTC7, PTC7_DATA),
-	PINMUX_GPIO(GPIO_PTC6, PTC6_DATA),
-	PINMUX_GPIO(GPIO_PTC5, PTC5_DATA),
-	PINMUX_GPIO(GPIO_PTC4, PTC4_DATA),
-	PINMUX_GPIO(GPIO_PTC3, PTC3_DATA),
-	PINMUX_GPIO(GPIO_PTC2, PTC2_DATA),
-	PINMUX_GPIO(GPIO_PTC1, PTC1_DATA),
-	PINMUX_GPIO(GPIO_PTC0, PTC0_DATA),
+	PINMUX_GPIO(PTC7),
+	PINMUX_GPIO(PTC6),
+	PINMUX_GPIO(PTC5),
+	PINMUX_GPIO(PTC4),
+	PINMUX_GPIO(PTC3),
+	PINMUX_GPIO(PTC2),
+	PINMUX_GPIO(PTC1),
+	PINMUX_GPIO(PTC0),
 
 	/* PTD */
-	PINMUX_GPIO(GPIO_PTD7, PTD7_DATA),
-	PINMUX_GPIO(GPIO_PTD6, PTD6_DATA),
-	PINMUX_GPIO(GPIO_PTD5, PTD5_DATA),
-	PINMUX_GPIO(GPIO_PTD4, PTD4_DATA),
-	PINMUX_GPIO(GPIO_PTD3, PTD3_DATA),
-	PINMUX_GPIO(GPIO_PTD2, PTD2_DATA),
-	PINMUX_GPIO(GPIO_PTD1, PTD1_DATA),
-	PINMUX_GPIO(GPIO_PTD0, PTD0_DATA),
+	PINMUX_GPIO(PTD7),
+	PINMUX_GPIO(PTD6),
+	PINMUX_GPIO(PTD5),
+	PINMUX_GPIO(PTD4),
+	PINMUX_GPIO(PTD3),
+	PINMUX_GPIO(PTD2),
+	PINMUX_GPIO(PTD1),
+	PINMUX_GPIO(PTD0),
 
 	/* PTE */
-	PINMUX_GPIO(GPIO_PTE7, PTE7_DATA),
-	PINMUX_GPIO(GPIO_PTE6, PTE6_DATA),
-	PINMUX_GPIO(GPIO_PTE5, PTE5_DATA),
-	PINMUX_GPIO(GPIO_PTE4, PTE4_DATA),
-	PINMUX_GPIO(GPIO_PTE3, PTE3_DATA),
-	PINMUX_GPIO(GPIO_PTE2, PTE2_DATA),
-	PINMUX_GPIO(GPIO_PTE1, PTE1_DATA),
-	PINMUX_GPIO(GPIO_PTE0, PTE0_DATA),
+	PINMUX_GPIO(PTE7),
+	PINMUX_GPIO(PTE6),
+	PINMUX_GPIO(PTE5),
+	PINMUX_GPIO(PTE4),
+	PINMUX_GPIO(PTE3),
+	PINMUX_GPIO(PTE2),
+	PINMUX_GPIO(PTE1),
+	PINMUX_GPIO(PTE0),
 
 	/* PTF */
-	PINMUX_GPIO(GPIO_PTF7, PTF7_DATA),
-	PINMUX_GPIO(GPIO_PTF6, PTF6_DATA),
-	PINMUX_GPIO(GPIO_PTF5, PTF5_DATA),
-	PINMUX_GPIO(GPIO_PTF4, PTF4_DATA),
-	PINMUX_GPIO(GPIO_PTF3, PTF3_DATA),
-	PINMUX_GPIO(GPIO_PTF2, PTF2_DATA),
-	PINMUX_GPIO(GPIO_PTF1, PTF1_DATA),
-	PINMUX_GPIO(GPIO_PTF0, PTF0_DATA),
+	PINMUX_GPIO(PTF7),
+	PINMUX_GPIO(PTF6),
+	PINMUX_GPIO(PTF5),
+	PINMUX_GPIO(PTF4),
+	PINMUX_GPIO(PTF3),
+	PINMUX_GPIO(PTF2),
+	PINMUX_GPIO(PTF1),
+	PINMUX_GPIO(PTF0),
 
 	/* PTG */
-	PINMUX_GPIO(GPIO_PTG7, PTG7_DATA),
-	PINMUX_GPIO(GPIO_PTG6, PTG6_DATA),
-	PINMUX_GPIO(GPIO_PTG5, PTG5_DATA),
-	PINMUX_GPIO(GPIO_PTG4, PTG4_DATA),
-	PINMUX_GPIO(GPIO_PTG3, PTG3_DATA),
-	PINMUX_GPIO(GPIO_PTG2, PTG2_DATA),
-	PINMUX_GPIO(GPIO_PTG1, PTG1_DATA),
-	PINMUX_GPIO(GPIO_PTG0, PTG0_DATA),
+	PINMUX_GPIO(PTG7),
+	PINMUX_GPIO(PTG6),
+	PINMUX_GPIO(PTG5),
+	PINMUX_GPIO(PTG4),
+	PINMUX_GPIO(PTG3),
+	PINMUX_GPIO(PTG2),
+	PINMUX_GPIO(PTG1),
+	PINMUX_GPIO(PTG0),
 
 	/* PTH */
-	PINMUX_GPIO(GPIO_PTH7, PTH7_DATA),
-	PINMUX_GPIO(GPIO_PTH6, PTH6_DATA),
-	PINMUX_GPIO(GPIO_PTH5, PTH5_DATA),
-	PINMUX_GPIO(GPIO_PTH4, PTH4_DATA),
-	PINMUX_GPIO(GPIO_PTH3, PTH3_DATA),
-	PINMUX_GPIO(GPIO_PTH2, PTH2_DATA),
-	PINMUX_GPIO(GPIO_PTH1, PTH1_DATA),
-	PINMUX_GPIO(GPIO_PTH0, PTH0_DATA),
+	PINMUX_GPIO(PTH7),
+	PINMUX_GPIO(PTH6),
+	PINMUX_GPIO(PTH5),
+	PINMUX_GPIO(PTH4),
+	PINMUX_GPIO(PTH3),
+	PINMUX_GPIO(PTH2),
+	PINMUX_GPIO(PTH1),
+	PINMUX_GPIO(PTH0),
 
 	/* PTI */
-	PINMUX_GPIO(GPIO_PTI7, PTI7_DATA),
-	PINMUX_GPIO(GPIO_PTI6, PTI6_DATA),
-	PINMUX_GPIO(GPIO_PTI5, PTI5_DATA),
-	PINMUX_GPIO(GPIO_PTI4, PTI4_DATA),
-	PINMUX_GPIO(GPIO_PTI3, PTI3_DATA),
-	PINMUX_GPIO(GPIO_PTI2, PTI2_DATA),
-	PINMUX_GPIO(GPIO_PTI1, PTI1_DATA),
-	PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
+	PINMUX_GPIO(PTI7),
+	PINMUX_GPIO(PTI6),
+	PINMUX_GPIO(PTI5),
+	PINMUX_GPIO(PTI4),
+	PINMUX_GPIO(PTI3),
+	PINMUX_GPIO(PTI2),
+	PINMUX_GPIO(PTI1),
+	PINMUX_GPIO(PTI0),
 
 	/* PTJ */
-	PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
-	PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
-	PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
-	PINMUX_GPIO(GPIO_PTJ3, PTJ3_DATA),
-	PINMUX_GPIO(GPIO_PTJ2, PTJ2_DATA),
-	PINMUX_GPIO(GPIO_PTJ1, PTJ1_DATA),
-	PINMUX_GPIO(GPIO_PTJ0, PTJ0_DATA),
+	PINMUX_GPIO(PTJ6),
+	PINMUX_GPIO(PTJ5),
+	PINMUX_GPIO(PTJ4),
+	PINMUX_GPIO(PTJ3),
+	PINMUX_GPIO(PTJ2),
+	PINMUX_GPIO(PTJ1),
+	PINMUX_GPIO(PTJ0),
 
 	/* PTK */
-	PINMUX_GPIO(GPIO_PTK7, PTK7_DATA),
-	PINMUX_GPIO(GPIO_PTK6, PTK6_DATA),
-	PINMUX_GPIO(GPIO_PTK5, PTK5_DATA),
-	PINMUX_GPIO(GPIO_PTK4, PTK4_DATA),
-	PINMUX_GPIO(GPIO_PTK3, PTK3_DATA),
-	PINMUX_GPIO(GPIO_PTK2, PTK2_DATA),
-	PINMUX_GPIO(GPIO_PTK1, PTK1_DATA),
-	PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
+	PINMUX_GPIO(PTK7),
+	PINMUX_GPIO(PTK6),
+	PINMUX_GPIO(PTK5),
+	PINMUX_GPIO(PTK4),
+	PINMUX_GPIO(PTK3),
+	PINMUX_GPIO(PTK2),
+	PINMUX_GPIO(PTK1),
+	PINMUX_GPIO(PTK0),
 
 	/* PTL */
-	PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
-	PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
-	PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
-	PINMUX_GPIO(GPIO_PTL3, PTL3_DATA),
-	PINMUX_GPIO(GPIO_PTL2, PTL2_DATA),
-	PINMUX_GPIO(GPIO_PTL1, PTL1_DATA),
-	PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
+	PINMUX_GPIO(PTL6),
+	PINMUX_GPIO(PTL5),
+	PINMUX_GPIO(PTL4),
+	PINMUX_GPIO(PTL3),
+	PINMUX_GPIO(PTL2),
+	PINMUX_GPIO(PTL1),
+	PINMUX_GPIO(PTL0),
 
 	/* PTM */
-	PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
-	PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
-	PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
-	PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
-	PINMUX_GPIO(GPIO_PTM3, PTM3_DATA),
-	PINMUX_GPIO(GPIO_PTM2, PTM2_DATA),
-	PINMUX_GPIO(GPIO_PTM1, PTM1_DATA),
-	PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
+	PINMUX_GPIO(PTM7),
+	PINMUX_GPIO(PTM6),
+	PINMUX_GPIO(PTM5),
+	PINMUX_GPIO(PTM4),
+	PINMUX_GPIO(PTM3),
+	PINMUX_GPIO(PTM2),
+	PINMUX_GPIO(PTM1),
+	PINMUX_GPIO(PTM0),
 
 	/* PTN */
-	PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
-	PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
-	PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
-	PINMUX_GPIO(GPIO_PTN3, PTN3_DATA),
-	PINMUX_GPIO(GPIO_PTN2, PTN2_DATA),
-	PINMUX_GPIO(GPIO_PTN1, PTN1_DATA),
-	PINMUX_GPIO(GPIO_PTN0, PTN0_DATA),
+	PINMUX_GPIO(PTN6),
+	PINMUX_GPIO(PTN5),
+	PINMUX_GPIO(PTN4),
+	PINMUX_GPIO(PTN3),
+	PINMUX_GPIO(PTN2),
+	PINMUX_GPIO(PTN1),
+	PINMUX_GPIO(PTN0),
 
 	/* PTO */
-	PINMUX_GPIO(GPIO_PTO7, PTO7_DATA),
-	PINMUX_GPIO(GPIO_PTO6, PTO6_DATA),
-	PINMUX_GPIO(GPIO_PTO5, PTO5_DATA),
-	PINMUX_GPIO(GPIO_PTO4, PTO4_DATA),
-	PINMUX_GPIO(GPIO_PTO3, PTO3_DATA),
-	PINMUX_GPIO(GPIO_PTO2, PTO2_DATA),
-	PINMUX_GPIO(GPIO_PTO1, PTO1_DATA),
-	PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
+	PINMUX_GPIO(PTO7),
+	PINMUX_GPIO(PTO6),
+	PINMUX_GPIO(PTO5),
+	PINMUX_GPIO(PTO4),
+	PINMUX_GPIO(PTO3),
+	PINMUX_GPIO(PTO2),
+	PINMUX_GPIO(PTO1),
+	PINMUX_GPIO(PTO0),
 
 	/* PTP */
-	PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
-	PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
-	PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
-	PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
-	PINMUX_GPIO(GPIO_PTP3, PTP3_DATA),
-	PINMUX_GPIO(GPIO_PTP2, PTP2_DATA),
-	PINMUX_GPIO(GPIO_PTP1, PTP1_DATA),
-	PINMUX_GPIO(GPIO_PTP0, PTP0_DATA),
+	PINMUX_GPIO(PTP7),
+	PINMUX_GPIO(PTP6),
+	PINMUX_GPIO(PTP5),
+	PINMUX_GPIO(PTP4),
+	PINMUX_GPIO(PTP3),
+	PINMUX_GPIO(PTP2),
+	PINMUX_GPIO(PTP1),
+	PINMUX_GPIO(PTP0),
 
 	/* PTQ */
-	PINMUX_GPIO(GPIO_PTQ6, PTQ6_DATA),
-	PINMUX_GPIO(GPIO_PTQ5, PTQ5_DATA),
-	PINMUX_GPIO(GPIO_PTQ4, PTQ4_DATA),
-	PINMUX_GPIO(GPIO_PTQ3, PTQ3_DATA),
-	PINMUX_GPIO(GPIO_PTQ2, PTQ2_DATA),
-	PINMUX_GPIO(GPIO_PTQ1, PTQ1_DATA),
-	PINMUX_GPIO(GPIO_PTQ0, PTQ0_DATA),
+	PINMUX_GPIO(PTQ6),
+	PINMUX_GPIO(PTQ5),
+	PINMUX_GPIO(PTQ4),
+	PINMUX_GPIO(PTQ3),
+	PINMUX_GPIO(PTQ2),
+	PINMUX_GPIO(PTQ1),
+	PINMUX_GPIO(PTQ0),
 
 	/* PTR */
-	PINMUX_GPIO(GPIO_PTR7, PTR7_DATA),
-	PINMUX_GPIO(GPIO_PTR6, PTR6_DATA),
-	PINMUX_GPIO(GPIO_PTR5, PTR5_DATA),
-	PINMUX_GPIO(GPIO_PTR4, PTR4_DATA),
-	PINMUX_GPIO(GPIO_PTR3, PTR3_DATA),
-	PINMUX_GPIO(GPIO_PTR2, PTR2_DATA),
-	PINMUX_GPIO(GPIO_PTR1, PTR1_DATA),
-	PINMUX_GPIO(GPIO_PTR0, PTR0_DATA),
+	PINMUX_GPIO(PTR7),
+	PINMUX_GPIO(PTR6),
+	PINMUX_GPIO(PTR5),
+	PINMUX_GPIO(PTR4),
+	PINMUX_GPIO(PTR3),
+	PINMUX_GPIO(PTR2),
+	PINMUX_GPIO(PTR1),
+	PINMUX_GPIO(PTR0),
 
 	/* PTS */
-	PINMUX_GPIO(GPIO_PTS7, PTS7_DATA),
-	PINMUX_GPIO(GPIO_PTS6, PTS6_DATA),
-	PINMUX_GPIO(GPIO_PTS5, PTS5_DATA),
-	PINMUX_GPIO(GPIO_PTS4, PTS4_DATA),
-	PINMUX_GPIO(GPIO_PTS3, PTS3_DATA),
-	PINMUX_GPIO(GPIO_PTS2, PTS2_DATA),
-	PINMUX_GPIO(GPIO_PTS1, PTS1_DATA),
-	PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
+	PINMUX_GPIO(PTS7),
+	PINMUX_GPIO(PTS6),
+	PINMUX_GPIO(PTS5),
+	PINMUX_GPIO(PTS4),
+	PINMUX_GPIO(PTS3),
+	PINMUX_GPIO(PTS2),
+	PINMUX_GPIO(PTS1),
+	PINMUX_GPIO(PTS0),
 
 	/* PTT */
-	PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
-	PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
-	PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
-	PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
-	PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
-	PINMUX_GPIO(GPIO_PTT2, PTT2_DATA),
-	PINMUX_GPIO(GPIO_PTT1, PTT1_DATA),
-	PINMUX_GPIO(GPIO_PTT0, PTT0_DATA),
+	PINMUX_GPIO(PTT7),
+	PINMUX_GPIO(PTT6),
+	PINMUX_GPIO(PTT5),
+	PINMUX_GPIO(PTT4),
+	PINMUX_GPIO(PTT3),
+	PINMUX_GPIO(PTT2),
+	PINMUX_GPIO(PTT1),
+	PINMUX_GPIO(PTT0),
 
 	/* PTU */
-	PINMUX_GPIO(GPIO_PTU7, PTU7_DATA),
-	PINMUX_GPIO(GPIO_PTU6, PTU6_DATA),
-	PINMUX_GPIO(GPIO_PTU5, PTU5_DATA),
-	PINMUX_GPIO(GPIO_PTU4, PTU4_DATA),
-	PINMUX_GPIO(GPIO_PTU3, PTU3_DATA),
-	PINMUX_GPIO(GPIO_PTU2, PTU2_DATA),
-	PINMUX_GPIO(GPIO_PTU1, PTU1_DATA),
-	PINMUX_GPIO(GPIO_PTU0, PTU0_DATA),
+	PINMUX_GPIO(PTU7),
+	PINMUX_GPIO(PTU6),
+	PINMUX_GPIO(PTU5),
+	PINMUX_GPIO(PTU4),
+	PINMUX_GPIO(PTU3),
+	PINMUX_GPIO(PTU2),
+	PINMUX_GPIO(PTU1),
+	PINMUX_GPIO(PTU0),
 
 	/* PTV */
-	PINMUX_GPIO(GPIO_PTV7, PTV7_DATA),
-	PINMUX_GPIO(GPIO_PTV6, PTV6_DATA),
-	PINMUX_GPIO(GPIO_PTV5, PTV5_DATA),
-	PINMUX_GPIO(GPIO_PTV4, PTV4_DATA),
-	PINMUX_GPIO(GPIO_PTV3, PTV3_DATA),
-	PINMUX_GPIO(GPIO_PTV2, PTV2_DATA),
-	PINMUX_GPIO(GPIO_PTV1, PTV1_DATA),
-	PINMUX_GPIO(GPIO_PTV0, PTV0_DATA),
+	PINMUX_GPIO(PTV7),
+	PINMUX_GPIO(PTV6),
+	PINMUX_GPIO(PTV5),
+	PINMUX_GPIO(PTV4),
+	PINMUX_GPIO(PTV3),
+	PINMUX_GPIO(PTV2),
+	PINMUX_GPIO(PTV1),
+	PINMUX_GPIO(PTV0),
 
 	/* PTW */
-	PINMUX_GPIO(GPIO_PTW7, PTW7_DATA),
-	PINMUX_GPIO(GPIO_PTW6, PTW6_DATA),
-	PINMUX_GPIO(GPIO_PTW5, PTW5_DATA),
-	PINMUX_GPIO(GPIO_PTW4, PTW4_DATA),
-	PINMUX_GPIO(GPIO_PTW3, PTW3_DATA),
-	PINMUX_GPIO(GPIO_PTW2, PTW2_DATA),
-	PINMUX_GPIO(GPIO_PTW1, PTW1_DATA),
-	PINMUX_GPIO(GPIO_PTW0, PTW0_DATA),
+	PINMUX_GPIO(PTW7),
+	PINMUX_GPIO(PTW6),
+	PINMUX_GPIO(PTW5),
+	PINMUX_GPIO(PTW4),
+	PINMUX_GPIO(PTW3),
+	PINMUX_GPIO(PTW2),
+	PINMUX_GPIO(PTW1),
+	PINMUX_GPIO(PTW0),
 
 	/* PTX */
-	PINMUX_GPIO(GPIO_PTX7, PTX7_DATA),
-	PINMUX_GPIO(GPIO_PTX6, PTX6_DATA),
-	PINMUX_GPIO(GPIO_PTX5, PTX5_DATA),
-	PINMUX_GPIO(GPIO_PTX4, PTX4_DATA),
-	PINMUX_GPIO(GPIO_PTX3, PTX3_DATA),
-	PINMUX_GPIO(GPIO_PTX2, PTX2_DATA),
-	PINMUX_GPIO(GPIO_PTX1, PTX1_DATA),
-	PINMUX_GPIO(GPIO_PTX0, PTX0_DATA),
+	PINMUX_GPIO(PTX7),
+	PINMUX_GPIO(PTX6),
+	PINMUX_GPIO(PTX5),
+	PINMUX_GPIO(PTX4),
+	PINMUX_GPIO(PTX3),
+	PINMUX_GPIO(PTX2),
+	PINMUX_GPIO(PTX1),
+	PINMUX_GPIO(PTX0),
 
 	/* PTY */
-	PINMUX_GPIO(GPIO_PTY7, PTY7_DATA),
-	PINMUX_GPIO(GPIO_PTY6, PTY6_DATA),
-	PINMUX_GPIO(GPIO_PTY5, PTY5_DATA),
-	PINMUX_GPIO(GPIO_PTY4, PTY4_DATA),
-	PINMUX_GPIO(GPIO_PTY3, PTY3_DATA),
-	PINMUX_GPIO(GPIO_PTY2, PTY2_DATA),
-	PINMUX_GPIO(GPIO_PTY1, PTY1_DATA),
-	PINMUX_GPIO(GPIO_PTY0, PTY0_DATA),
+	PINMUX_GPIO(PTY7),
+	PINMUX_GPIO(PTY6),
+	PINMUX_GPIO(PTY5),
+	PINMUX_GPIO(PTY4),
+	PINMUX_GPIO(PTY3),
+	PINMUX_GPIO(PTY2),
+	PINMUX_GPIO(PTY1),
+	PINMUX_GPIO(PTY0),
 
 	/* PTZ */
-	PINMUX_GPIO(GPIO_PTZ7, PTZ7_DATA),
-	PINMUX_GPIO(GPIO_PTZ6, PTZ6_DATA),
-	PINMUX_GPIO(GPIO_PTZ5, PTZ5_DATA),
-	PINMUX_GPIO(GPIO_PTZ4, PTZ4_DATA),
-	PINMUX_GPIO(GPIO_PTZ3, PTZ3_DATA),
-	PINMUX_GPIO(GPIO_PTZ2, PTZ2_DATA),
-	PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
-	PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
+	PINMUX_GPIO(PTZ7),
+	PINMUX_GPIO(PTZ6),
+	PINMUX_GPIO(PTZ5),
+	PINMUX_GPIO(PTZ4),
+	PINMUX_GPIO(PTZ3),
+	PINMUX_GPIO(PTZ2),
+	PINMUX_GPIO(PTZ1),
+	PINMUX_GPIO(PTZ0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -1728,14 +1688,14 @@
 
 static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
-		PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
-		PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
-		PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
-		PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
-		PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
-		PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
-		PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
-		PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
+		PTA7_FN, PTA7_OUT, PTA7_IN, 0,
+		PTA6_FN, PTA6_OUT, PTA6_IN, 0,
+		PTA5_FN, PTA5_OUT, PTA5_IN, 0,
+		PTA4_FN, PTA4_OUT, PTA4_IN, 0,
+		PTA3_FN, PTA3_OUT, PTA3_IN, 0,
+		PTA2_FN, PTA2_OUT, PTA2_IN, 0,
+		PTA1_FN, PTA1_OUT, PTA1_IN, 0,
+		PTA0_FN, PTA0_OUT, PTA0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
 		PTB7_FN, PTB7_OUT, PTB7_IN, 0,
@@ -1758,100 +1718,100 @@
 		PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
-		PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
-		PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
-		PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
-		PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
-		PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
-		PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
-		PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
-		PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
+		PTD7_FN, PTD7_OUT, PTD7_IN, 0,
+		PTD6_FN, PTD6_OUT, PTD6_IN, 0,
+		PTD5_FN, PTD5_OUT, PTD5_IN, 0,
+		PTD4_FN, PTD4_OUT, PTD4_IN, 0,
+		PTD3_FN, PTD3_OUT, PTD3_IN, 0,
+		PTD2_FN, PTD2_OUT, PTD2_IN, 0,
+		PTD1_FN, PTD1_OUT, PTD1_IN, 0,
+		PTD0_FN, PTD0_OUT, PTD0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
-		PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
-		PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
-		PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
-		PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
-		PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
-		PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
-		PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
-		PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
+		PTE7_FN, PTE7_OUT, PTE7_IN, 0,
+		PTE6_FN, PTE6_OUT, PTE6_IN, 0,
+		PTE5_FN, PTE5_OUT, PTE5_IN, 0,
+		PTE4_FN, PTE4_OUT, PTE4_IN, 0,
+		PTE3_FN, PTE3_OUT, PTE3_IN, 0,
+		PTE2_FN, PTE2_OUT, PTE2_IN, 0,
+		PTE1_FN, PTE1_OUT, PTE1_IN, 0,
+		PTE0_FN, PTE0_OUT, PTE0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
-		PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
-		PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
-		PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
-		PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
-		PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
-		PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
-		PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
-		PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
+		PTF7_FN, PTF7_OUT, PTF7_IN, 0,
+		PTF6_FN, PTF6_OUT, PTF6_IN, 0,
+		PTF5_FN, PTF5_OUT, PTF5_IN, 0,
+		PTF4_FN, PTF4_OUT, PTF4_IN, 0,
+		PTF3_FN, PTF3_OUT, PTF3_IN, 0,
+		PTF2_FN, PTF2_OUT, PTF2_IN, 0,
+		PTF1_FN, PTF1_OUT, PTF1_IN, 0,
+		PTF0_FN, PTF0_OUT, PTF0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
-		PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
-		PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
+		PTG7_FN, PTG7_OUT, PTG7_IN, 0,
+		PTG6_FN, PTG6_OUT, PTG6_IN, 0,
 		PTG5_FN, PTG5_OUT, PTG5_IN, 0,
-		PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
+		PTG4_FN, PTG4_OUT, PTG4_IN, 0,
 		PTG3_FN, PTG3_OUT, PTG3_IN, 0,
 		PTG2_FN, PTG2_OUT, PTG2_IN, 0,
 		PTG1_FN, PTG1_OUT, PTG1_IN, 0,
 		PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
-		PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
-		PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
-		PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
-		PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
-		PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
-		PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
-		PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
-		PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
+		PTH7_FN, PTH7_OUT, PTH7_IN, 0,
+		PTH6_FN, PTH6_OUT, PTH6_IN, 0,
+		PTH5_FN, PTH5_OUT, PTH5_IN, 0,
+		PTH4_FN, PTH4_OUT, PTH4_IN, 0,
+		PTH3_FN, PTH3_OUT, PTH3_IN, 0,
+		PTH2_FN, PTH2_OUT, PTH2_IN, 0,
+		PTH1_FN, PTH1_OUT, PTH1_IN, 0,
+		PTH0_FN, PTH0_OUT, PTH0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
-		PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
-		PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
+		PTI7_FN, PTI7_OUT, PTI7_IN, 0,
+		PTI6_FN, PTI6_OUT, PTI6_IN, 0,
 		PTI5_FN, PTI5_OUT, PTI5_IN, 0,
-		PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
-		PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
-		PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
-		PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
-		PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
+		PTI4_FN, PTI4_OUT, PTI4_IN, 0,
+		PTI3_FN, PTI3_OUT, PTI3_IN, 0,
+		PTI2_FN, PTI2_OUT, PTI2_IN, 0,
+		PTI1_FN, PTI1_OUT, PTI1_IN, 0,
+		PTI0_FN, PTI0_OUT, PTI0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
 		0, 0, 0, 0,	/* reserved: always set 1 */
-		PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
-		PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
-		PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
-		PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
-		PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
-		PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
-		PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
+		PTJ6_FN, PTJ6_OUT, PTJ6_IN, 0,
+		PTJ5_FN, PTJ5_OUT, PTJ5_IN, 0,
+		PTJ4_FN, PTJ4_OUT, PTJ4_IN, 0,
+		PTJ3_FN, PTJ3_OUT, PTJ3_IN, 0,
+		PTJ2_FN, PTJ2_OUT, PTJ2_IN, 0,
+		PTJ1_FN, PTJ1_OUT, PTJ1_IN, 0,
+		PTJ0_FN, PTJ0_OUT, PTJ0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
-		PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
-		PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
-		PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
-		PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
-		PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
-		PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
-		PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
-		PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
+		PTK7_FN, PTK7_OUT, PTK7_IN, 0,
+		PTK6_FN, PTK6_OUT, PTK6_IN, 0,
+		PTK5_FN, PTK5_OUT, PTK5_IN, 0,
+		PTK4_FN, PTK4_OUT, PTK4_IN, 0,
+		PTK3_FN, PTK3_OUT, PTK3_IN, 0,
+		PTK2_FN, PTK2_OUT, PTK2_IN, 0,
+		PTK1_FN, PTK1_OUT, PTK1_IN, 0,
+		PTK0_FN, PTK0_OUT, PTK0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
 		0, 0, 0, 0,	/* reserved: always set 1 */
-		PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
-		PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
-		PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
-		PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
-		PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
-		PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
-		PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
+		PTL6_FN, PTL6_OUT, PTL6_IN, 0,
+		PTL5_FN, PTL5_OUT, PTL5_IN, 0,
+		PTL4_FN, PTL4_OUT, PTL4_IN, 0,
+		PTL3_FN, PTL3_OUT, PTL3_IN, 0,
+		PTL2_FN, PTL2_OUT, PTL2_IN, 0,
+		PTL1_FN, PTL1_OUT, PTL1_IN, 0,
+		PTL0_FN, PTL0_OUT, PTL0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
-		PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
-		PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
-		PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
-		PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
+		PTM7_FN, PTM7_OUT, PTM7_IN, 0,
+		PTM6_FN, PTM6_OUT, PTM6_IN, 0,
+		PTM5_FN, PTM5_OUT, PTM5_IN, 0,
+		PTM4_FN, PTM4_OUT, PTM4_IN, 0,
 		PTM3_FN, PTM3_OUT, PTM3_IN, 0,
 		PTM2_FN, PTM2_OUT, PTM2_IN, 0,
 		PTM1_FN, PTM1_OUT, PTM1_IN, 0,
@@ -1861,21 +1821,21 @@
 		0, 0, 0, 0,	/* reserved: always set 1 */
 		PTN6_FN, PTN6_OUT, PTN6_IN, 0,
 		PTN5_FN, PTN5_OUT, PTN5_IN, 0,
-		PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
-		PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
-		PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
-		PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
-		PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
+		PTN4_FN, PTN4_OUT, PTN4_IN, 0,
+		PTN3_FN, PTN3_OUT, PTN3_IN, 0,
+		PTN2_FN, PTN2_OUT, PTN2_IN, 0,
+		PTN1_FN, PTN1_OUT, PTN1_IN, 0,
+		PTN0_FN, PTN0_OUT, PTN0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
-		PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
-		PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
-		PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
-		PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
-		PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
-		PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
-		PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
-		PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
+		PTO7_FN, PTO7_OUT, PTO7_IN, 0,
+		PTO6_FN, PTO6_OUT, PTO6_IN, 0,
+		PTO5_FN, PTO5_OUT, PTO5_IN, 0,
+		PTO4_FN, PTO4_OUT, PTO4_IN, 0,
+		PTO3_FN, PTO3_OUT, PTO3_IN, 0,
+		PTO2_FN, PTO2_OUT, PTO2_IN, 0,
+		PTO1_FN, PTO1_OUT, PTO1_IN, 0,
+		PTO0_FN, PTO0_OUT, PTO0_IN, 0 }
 	},
 #if 0	/* FIXME: Remove it? */
 	{ PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
@@ -1920,32 +1880,32 @@
 		PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
-		PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
-		PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
-		PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
-		PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
-		PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
-		PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
-		PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
-		PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
+		PTT7_FN, PTT7_OUT, PTT7_IN, 0,
+		PTT6_FN, PTT6_OUT, PTT6_IN, 0,
+		PTT5_FN, PTT5_OUT, PTT5_IN, 0,
+		PTT4_FN, PTT4_OUT, PTT4_IN, 0,
+		PTT3_FN, PTT3_OUT, PTT3_IN, 0,
+		PTT2_FN, PTT2_OUT, PTT2_IN, 0,
+		PTT1_FN, PTT1_OUT, PTT1_IN, 0,
+		PTT0_FN, PTT0_OUT, PTT0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
-		PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
-		PTU6_FN, PTU6_OUT, PTU6_IN, PTU6_IN_PU,
-		PTU5_FN, PTU5_OUT, PTU5_IN, PTU5_IN_PU,
-		PTU4_FN, PTU4_OUT, PTU4_IN, PTU4_IN_PU,
-		PTU3_FN, PTU3_OUT, PTU3_IN, PTU3_IN_PU,
-		PTU2_FN, PTU2_OUT, PTU2_IN, PTU2_IN_PU,
-		PTU1_FN, PTU1_OUT, PTU1_IN, PTU1_IN_PU,
-		PTU0_FN, PTU0_OUT, PTU0_IN, PTU0_IN_PU }
+		PTU7_FN, PTU7_OUT, PTU7_IN, 0,
+		PTU6_FN, PTU6_OUT, PTU6_IN, 0,
+		PTU5_FN, PTU5_OUT, PTU5_IN, 0,
+		PTU4_FN, PTU4_OUT, PTU4_IN, 0,
+		PTU3_FN, PTU3_OUT, PTU3_IN, 0,
+		PTU2_FN, PTU2_OUT, PTU2_IN, 0,
+		PTU1_FN, PTU1_OUT, PTU1_IN, 0,
+		PTU0_FN, PTU0_OUT, PTU0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PVCR", 0xffec002a, 16, 2) {
-		PTV7_FN, PTV7_OUT, PTV7_IN, PTV7_IN_PU,
-		PTV6_FN, PTV6_OUT, PTV6_IN, PTV6_IN_PU,
-		PTV5_FN, PTV5_OUT, PTV5_IN, PTV5_IN_PU,
-		PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
-		PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
-		PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
+		PTV7_FN, PTV7_OUT, PTV7_IN, 0,
+		PTV6_FN, PTV6_OUT, PTV6_IN, 0,
+		PTV5_FN, PTV5_OUT, PTV5_IN, 0,
+		PTV4_FN, PTV4_OUT, PTV4_IN, 0,
+		PTV3_FN, PTV3_OUT, PTV3_IN, 0,
+		PTV2_FN, PTV2_OUT, PTV2_IN, 0,
 		PTV1_FN, PTV1_OUT, PTV1_IN, 0,
 		PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
 	},
@@ -1956,28 +1916,28 @@
 		PTW4_FN, PTW4_OUT, PTW4_IN, 0,
 		PTW3_FN, PTW3_OUT, PTW3_IN, 0,
 		PTW2_FN, PTW2_OUT, PTW2_IN, 0,
-		PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
-		PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
+		PTW1_FN, PTW1_OUT, PTW1_IN, 0,
+		PTW0_FN, PTW0_OUT, PTW0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PXCR", 0xffec002e, 16, 2) {
-		PTX7_FN, PTX7_OUT, PTX7_IN, PTX7_IN_PU,
-		PTX6_FN, PTX6_OUT, PTX6_IN, PTX6_IN_PU,
-		PTX5_FN, PTX5_OUT, PTX5_IN, PTX5_IN_PU,
-		PTX4_FN, PTX4_OUT, PTX4_IN, PTX4_IN_PU,
-		PTX3_FN, PTX3_OUT, PTX3_IN, PTX3_IN_PU,
-		PTX2_FN, PTX2_OUT, PTX2_IN, PTX2_IN_PU,
-		PTX1_FN, PTX1_OUT, PTX1_IN, PTX1_IN_PU,
-		PTX0_FN, PTX0_OUT, PTX0_IN, PTX0_IN_PU }
+		PTX7_FN, PTX7_OUT, PTX7_IN, 0,
+		PTX6_FN, PTX6_OUT, PTX6_IN, 0,
+		PTX5_FN, PTX5_OUT, PTX5_IN, 0,
+		PTX4_FN, PTX4_OUT, PTX4_IN, 0,
+		PTX3_FN, PTX3_OUT, PTX3_IN, 0,
+		PTX2_FN, PTX2_OUT, PTX2_IN, 0,
+		PTX1_FN, PTX1_OUT, PTX1_IN, 0,
+		PTX0_FN, PTX0_OUT, PTX0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PYCR", 0xffec0030, 16, 2) {
-		PTY7_FN, PTY7_OUT, PTY7_IN, PTY7_IN_PU,
-		PTY6_FN, PTY6_OUT, PTY6_IN, PTY6_IN_PU,
-		PTY5_FN, PTY5_OUT, PTY5_IN, PTY5_IN_PU,
-		PTY4_FN, PTY4_OUT, PTY4_IN, PTY4_IN_PU,
-		PTY3_FN, PTY3_OUT, PTY3_IN, PTY3_IN_PU,
-		PTY2_FN, PTY2_OUT, PTY2_IN, PTY2_IN_PU,
-		PTY1_FN, PTY1_OUT, PTY1_IN, PTY1_IN_PU,
-		PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
+		PTY7_FN, PTY7_OUT, PTY7_IN, 0,
+		PTY6_FN, PTY6_OUT, PTY6_IN, 0,
+		PTY5_FN, PTY5_OUT, PTY5_IN, 0,
+		PTY4_FN, PTY4_OUT, PTY4_IN, 0,
+		PTY3_FN, PTY3_OUT, PTY3_IN, 0,
+		PTY2_FN, PTY2_OUT, PTY2_IN, 0,
+		PTY1_FN, PTY1_OUT, PTY1_IN, 0,
+		PTY0_FN, PTY0_OUT, PTY0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
 		PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
@@ -2267,7 +2227,6 @@
 const struct sh_pfc_soc_info sh7757_pinmux_info = {
 	.name = "sh7757_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7785.c b/drivers/pinctrl/sh-pfc/pfc-sh7785.c
index c176b79..517eb49 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7785.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7785.c
@@ -77,36 +77,6 @@
 	PR3_IN, PR2_IN, PR1_IN, PR0_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
-	PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
-	PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
-	PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
-	PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
-	PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
-	PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
-	PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
-	PE5_IN_PU, PE4_IN_PU, PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
-	PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
-	PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
-	PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
-	PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
-	PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
-	PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
-	PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
-	PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU, PJ0_IN_PU,
-	PK7_IN_PU, PK6_IN_PU, PK5_IN_PU, PK4_IN_PU,
-	PK3_IN_PU, PK2_IN_PU, PK1_IN_PU, PK0_IN_PU,
-	PL7_IN_PU, PL6_IN_PU, PL5_IN_PU, PL4_IN_PU,
-	PL3_IN_PU, PL2_IN_PU, PL1_IN_PU, PL0_IN_PU,
-	PM1_IN_PU, PM0_IN_PU,
-	PN7_IN_PU, PN6_IN_PU, PN5_IN_PU, PN4_IN_PU,
-	PN3_IN_PU, PN2_IN_PU, PN1_IN_PU, PN0_IN_PU,
-	PP5_IN_PU, PP4_IN_PU, PP3_IN_PU, PP2_IN_PU, PP1_IN_PU, PP0_IN_PU,
-	PQ4_IN_PU, PQ3_IN_PU, PQ2_IN_PU, PQ1_IN_PU, PQ0_IN_PU,
-	PR3_IN_PU, PR2_IN_PU, PR1_IN_PU, PR0_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
 	PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
@@ -355,150 +325,149 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
-
+static const u16 pinmux_data[] = {
 	/* PA GPIO */
-	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
-	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
-	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
-	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
-	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
-	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
-	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
-	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT),
+	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT),
+	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT),
+	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT),
+	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT),
+	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT),
+	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT),
+	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT),
 
 	/* PB GPIO */
-	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
-	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
-	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
-	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
-	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
-	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
-	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
-	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT),
+	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT),
+	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT),
+	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT),
+	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT),
+	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT),
+	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT),
+	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT),
 
 	/* PC GPIO */
-	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
-	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
-	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
-	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
-	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
-	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
-	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
-	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT),
+	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT),
+	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT),
+	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT),
+	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT),
+	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT),
+	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT),
+	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT),
 
 	/* PD GPIO */
-	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
-	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
-	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
-	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
-	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
-	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
-	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
-	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT),
+	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT),
+	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT),
+	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT),
+	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT),
+	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT),
+	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT),
+	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT),
 
 	/* PE GPIO */
-	PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
-	PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
-	PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
-	PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
-	PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
-	PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+	PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT),
+	PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT),
+	PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT),
+	PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT),
+	PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT),
+	PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT),
 
 	/* PF GPIO */
-	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
-	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
-	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
-	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
-	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
-	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
-	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
-	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT),
+	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT),
+	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT),
+	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT),
+	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT),
+	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT),
+	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT),
+	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT),
 
 	/* PG GPIO */
-	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
-	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
-	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
-	PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
-	PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
-	PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
-	PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
-	PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT),
+	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT),
+	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT),
+	PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT),
+	PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT),
+	PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT),
+	PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT),
+	PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT),
 
 	/* PH GPIO */
-	PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
-	PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
-	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
-	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
-	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
-	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
-	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
-	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+	PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT),
+	PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT),
+	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT),
+	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT),
+	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT),
+	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT),
+	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT),
+	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT),
 
 	/* PJ GPIO */
-	PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
-	PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
-	PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
-	PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
-	PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
-	PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
-	PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
-	PINMUX_DATA(PJ0_DATA, PJ0_IN, PJ0_OUT, PJ0_IN_PU),
+	PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT),
+	PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT),
+	PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT),
+	PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT),
+	PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT),
+	PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT),
+	PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT),
+	PINMUX_DATA(PJ0_DATA, PJ0_IN, PJ0_OUT),
 
 	/* PK GPIO */
-	PINMUX_DATA(PK7_DATA, PK7_IN, PK7_OUT, PK7_IN_PU),
-	PINMUX_DATA(PK6_DATA, PK6_IN, PK6_OUT, PK6_IN_PU),
-	PINMUX_DATA(PK5_DATA, PK5_IN, PK5_OUT, PK5_IN_PU),
-	PINMUX_DATA(PK4_DATA, PK4_IN, PK4_OUT, PK4_IN_PU),
-	PINMUX_DATA(PK3_DATA, PK3_IN, PK3_OUT, PK3_IN_PU),
-	PINMUX_DATA(PK2_DATA, PK2_IN, PK2_OUT, PK2_IN_PU),
-	PINMUX_DATA(PK1_DATA, PK1_IN, PK1_OUT, PK1_IN_PU),
-	PINMUX_DATA(PK0_DATA, PK0_IN, PK0_OUT, PK0_IN_PU),
+	PINMUX_DATA(PK7_DATA, PK7_IN, PK7_OUT),
+	PINMUX_DATA(PK6_DATA, PK6_IN, PK6_OUT),
+	PINMUX_DATA(PK5_DATA, PK5_IN, PK5_OUT),
+	PINMUX_DATA(PK4_DATA, PK4_IN, PK4_OUT),
+	PINMUX_DATA(PK3_DATA, PK3_IN, PK3_OUT),
+	PINMUX_DATA(PK2_DATA, PK2_IN, PK2_OUT),
+	PINMUX_DATA(PK1_DATA, PK1_IN, PK1_OUT),
+	PINMUX_DATA(PK0_DATA, PK0_IN, PK0_OUT),
 
 	/* PL GPIO */
-	PINMUX_DATA(PL7_DATA, PL7_IN, PL7_OUT, PL7_IN_PU),
-	PINMUX_DATA(PL6_DATA, PL6_IN, PL6_OUT, PL6_IN_PU),
-	PINMUX_DATA(PL5_DATA, PL5_IN, PL5_OUT, PL5_IN_PU),
-	PINMUX_DATA(PL4_DATA, PL4_IN, PL4_OUT, PL4_IN_PU),
-	PINMUX_DATA(PL3_DATA, PL3_IN, PL3_OUT, PL3_IN_PU),
-	PINMUX_DATA(PL2_DATA, PL2_IN, PL2_OUT, PL2_IN_PU),
-	PINMUX_DATA(PL1_DATA, PL1_IN, PL1_OUT, PL1_IN_PU),
-	PINMUX_DATA(PL0_DATA, PL0_IN, PL0_OUT, PL0_IN_PU),
+	PINMUX_DATA(PL7_DATA, PL7_IN, PL7_OUT),
+	PINMUX_DATA(PL6_DATA, PL6_IN, PL6_OUT),
+	PINMUX_DATA(PL5_DATA, PL5_IN, PL5_OUT),
+	PINMUX_DATA(PL4_DATA, PL4_IN, PL4_OUT),
+	PINMUX_DATA(PL3_DATA, PL3_IN, PL3_OUT),
+	PINMUX_DATA(PL2_DATA, PL2_IN, PL2_OUT),
+	PINMUX_DATA(PL1_DATA, PL1_IN, PL1_OUT),
+	PINMUX_DATA(PL0_DATA, PL0_IN, PL0_OUT),
 
 	/* PM GPIO */
-	PINMUX_DATA(PM1_DATA, PM1_IN, PM1_OUT, PM1_IN_PU),
-	PINMUX_DATA(PM0_DATA, PM0_IN, PM0_OUT, PM0_IN_PU),
+	PINMUX_DATA(PM1_DATA, PM1_IN, PM1_OUT),
+	PINMUX_DATA(PM0_DATA, PM0_IN, PM0_OUT),
 
 	/* PN GPIO */
-	PINMUX_DATA(PN7_DATA, PN7_IN, PN7_OUT, PN7_IN_PU),
-	PINMUX_DATA(PN6_DATA, PN6_IN, PN6_OUT, PN6_IN_PU),
-	PINMUX_DATA(PN5_DATA, PN5_IN, PN5_OUT, PN5_IN_PU),
-	PINMUX_DATA(PN4_DATA, PN4_IN, PN4_OUT, PN4_IN_PU),
-	PINMUX_DATA(PN3_DATA, PN3_IN, PN3_OUT, PN3_IN_PU),
-	PINMUX_DATA(PN2_DATA, PN2_IN, PN2_OUT, PN2_IN_PU),
-	PINMUX_DATA(PN1_DATA, PN1_IN, PN1_OUT, PN1_IN_PU),
-	PINMUX_DATA(PN0_DATA, PN0_IN, PN0_OUT, PN0_IN_PU),
+	PINMUX_DATA(PN7_DATA, PN7_IN, PN7_OUT),
+	PINMUX_DATA(PN6_DATA, PN6_IN, PN6_OUT),
+	PINMUX_DATA(PN5_DATA, PN5_IN, PN5_OUT),
+	PINMUX_DATA(PN4_DATA, PN4_IN, PN4_OUT),
+	PINMUX_DATA(PN3_DATA, PN3_IN, PN3_OUT),
+	PINMUX_DATA(PN2_DATA, PN2_IN, PN2_OUT),
+	PINMUX_DATA(PN1_DATA, PN1_IN, PN1_OUT),
+	PINMUX_DATA(PN0_DATA, PN0_IN, PN0_OUT),
 
 	/* PP GPIO */
-	PINMUX_DATA(PP5_DATA, PP5_IN, PP5_OUT, PP5_IN_PU),
-	PINMUX_DATA(PP4_DATA, PP4_IN, PP4_OUT, PP4_IN_PU),
-	PINMUX_DATA(PP3_DATA, PP3_IN, PP3_OUT, PP3_IN_PU),
-	PINMUX_DATA(PP2_DATA, PP2_IN, PP2_OUT, PP2_IN_PU),
-	PINMUX_DATA(PP1_DATA, PP1_IN, PP1_OUT, PP1_IN_PU),
-	PINMUX_DATA(PP0_DATA, PP0_IN, PP0_OUT, PP0_IN_PU),
+	PINMUX_DATA(PP5_DATA, PP5_IN, PP5_OUT),
+	PINMUX_DATA(PP4_DATA, PP4_IN, PP4_OUT),
+	PINMUX_DATA(PP3_DATA, PP3_IN, PP3_OUT),
+	PINMUX_DATA(PP2_DATA, PP2_IN, PP2_OUT),
+	PINMUX_DATA(PP1_DATA, PP1_IN, PP1_OUT),
+	PINMUX_DATA(PP0_DATA, PP0_IN, PP0_OUT),
 
 	/* PQ GPIO */
-	PINMUX_DATA(PQ4_DATA, PQ4_IN, PQ4_OUT, PQ4_IN_PU),
-	PINMUX_DATA(PQ3_DATA, PQ3_IN, PQ3_OUT, PQ3_IN_PU),
-	PINMUX_DATA(PQ2_DATA, PQ2_IN, PQ2_OUT, PQ2_IN_PU),
-	PINMUX_DATA(PQ1_DATA, PQ1_IN, PQ1_OUT, PQ1_IN_PU),
-	PINMUX_DATA(PQ0_DATA, PQ0_IN, PQ0_OUT, PQ0_IN_PU),
+	PINMUX_DATA(PQ4_DATA, PQ4_IN, PQ4_OUT),
+	PINMUX_DATA(PQ3_DATA, PQ3_IN, PQ3_OUT),
+	PINMUX_DATA(PQ2_DATA, PQ2_IN, PQ2_OUT),
+	PINMUX_DATA(PQ1_DATA, PQ1_IN, PQ1_OUT),
+	PINMUX_DATA(PQ0_DATA, PQ0_IN, PQ0_OUT),
 
 	/* PR GPIO */
-	PINMUX_DATA(PR3_DATA, PR3_IN, PR3_OUT, PR3_IN_PU),
-	PINMUX_DATA(PR2_DATA, PR2_IN, PR2_OUT, PR2_IN_PU),
-	PINMUX_DATA(PR1_DATA, PR1_IN, PR1_OUT, PR1_IN_PU),
-	PINMUX_DATA(PR0_DATA, PR0_IN, PR0_OUT, PR0_IN_PU),
+	PINMUX_DATA(PR3_DATA, PR3_IN, PR3_OUT),
+	PINMUX_DATA(PR2_DATA, PR2_IN, PR2_OUT),
+	PINMUX_DATA(PR1_DATA, PR1_IN, PR1_OUT),
+	PINMUX_DATA(PR0_DATA, PR0_IN, PR0_OUT),
 
 	/* PA FN */
 	PINMUX_DATA(D63_AD31_MARK, PA7_FN),
@@ -704,147 +673,147 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PA */
-	PINMUX_GPIO(GPIO_PA7, PA7_DATA),
-	PINMUX_GPIO(GPIO_PA6, PA6_DATA),
-	PINMUX_GPIO(GPIO_PA5, PA5_DATA),
-	PINMUX_GPIO(GPIO_PA4, PA4_DATA),
-	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
-	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
-	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
-	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+	PINMUX_GPIO(PA7),
+	PINMUX_GPIO(PA6),
+	PINMUX_GPIO(PA5),
+	PINMUX_GPIO(PA4),
+	PINMUX_GPIO(PA3),
+	PINMUX_GPIO(PA2),
+	PINMUX_GPIO(PA1),
+	PINMUX_GPIO(PA0),
 
 	/* PB */
-	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
-	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
-	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
-	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
-	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
-	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
-	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
-	PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+	PINMUX_GPIO(PB7),
+	PINMUX_GPIO(PB6),
+	PINMUX_GPIO(PB5),
+	PINMUX_GPIO(PB4),
+	PINMUX_GPIO(PB3),
+	PINMUX_GPIO(PB2),
+	PINMUX_GPIO(PB1),
+	PINMUX_GPIO(PB0),
 
 	/* PC */
-	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
-	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
-	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
-	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
-	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
-	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
-	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
-	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+	PINMUX_GPIO(PC7),
+	PINMUX_GPIO(PC6),
+	PINMUX_GPIO(PC5),
+	PINMUX_GPIO(PC4),
+	PINMUX_GPIO(PC3),
+	PINMUX_GPIO(PC2),
+	PINMUX_GPIO(PC1),
+	PINMUX_GPIO(PC0),
 
 	/* PD */
-	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
-	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
-	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
-	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
-	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
-	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
-	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
-	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+	PINMUX_GPIO(PD7),
+	PINMUX_GPIO(PD6),
+	PINMUX_GPIO(PD5),
+	PINMUX_GPIO(PD4),
+	PINMUX_GPIO(PD3),
+	PINMUX_GPIO(PD2),
+	PINMUX_GPIO(PD1),
+	PINMUX_GPIO(PD0),
 
 	/* PE */
-	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
-	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
-	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
-	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
-	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
-	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+	PINMUX_GPIO(PE5),
+	PINMUX_GPIO(PE4),
+	PINMUX_GPIO(PE3),
+	PINMUX_GPIO(PE2),
+	PINMUX_GPIO(PE1),
+	PINMUX_GPIO(PE0),
 
 	/* PF */
-	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
-	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
-	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
-	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
-	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
-	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
-	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
-	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+	PINMUX_GPIO(PF7),
+	PINMUX_GPIO(PF6),
+	PINMUX_GPIO(PF5),
+	PINMUX_GPIO(PF4),
+	PINMUX_GPIO(PF3),
+	PINMUX_GPIO(PF2),
+	PINMUX_GPIO(PF1),
+	PINMUX_GPIO(PF0),
 
 	/* PG */
-	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
-	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
-	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
-	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
-	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
-	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
-	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
-	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+	PINMUX_GPIO(PG7),
+	PINMUX_GPIO(PG6),
+	PINMUX_GPIO(PG5),
+	PINMUX_GPIO(PG4),
+	PINMUX_GPIO(PG3),
+	PINMUX_GPIO(PG2),
+	PINMUX_GPIO(PG1),
+	PINMUX_GPIO(PG0),
 
 	/* PH */
-	PINMUX_GPIO(GPIO_PH7, PH7_DATA),
-	PINMUX_GPIO(GPIO_PH6, PH6_DATA),
-	PINMUX_GPIO(GPIO_PH5, PH5_DATA),
-	PINMUX_GPIO(GPIO_PH4, PH4_DATA),
-	PINMUX_GPIO(GPIO_PH3, PH3_DATA),
-	PINMUX_GPIO(GPIO_PH2, PH2_DATA),
-	PINMUX_GPIO(GPIO_PH1, PH1_DATA),
-	PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+	PINMUX_GPIO(PH7),
+	PINMUX_GPIO(PH6),
+	PINMUX_GPIO(PH5),
+	PINMUX_GPIO(PH4),
+	PINMUX_GPIO(PH3),
+	PINMUX_GPIO(PH2),
+	PINMUX_GPIO(PH1),
+	PINMUX_GPIO(PH0),
 
 	/* PJ */
-	PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
-	PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
-	PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
-	PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
-	PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
-	PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
-	PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
-	PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+	PINMUX_GPIO(PJ7),
+	PINMUX_GPIO(PJ6),
+	PINMUX_GPIO(PJ5),
+	PINMUX_GPIO(PJ4),
+	PINMUX_GPIO(PJ3),
+	PINMUX_GPIO(PJ2),
+	PINMUX_GPIO(PJ1),
+	PINMUX_GPIO(PJ0),
 
 	/* PK */
-	PINMUX_GPIO(GPIO_PK7, PK7_DATA),
-	PINMUX_GPIO(GPIO_PK6, PK6_DATA),
-	PINMUX_GPIO(GPIO_PK5, PK5_DATA),
-	PINMUX_GPIO(GPIO_PK4, PK4_DATA),
-	PINMUX_GPIO(GPIO_PK3, PK3_DATA),
-	PINMUX_GPIO(GPIO_PK2, PK2_DATA),
-	PINMUX_GPIO(GPIO_PK1, PK1_DATA),
-	PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+	PINMUX_GPIO(PK7),
+	PINMUX_GPIO(PK6),
+	PINMUX_GPIO(PK5),
+	PINMUX_GPIO(PK4),
+	PINMUX_GPIO(PK3),
+	PINMUX_GPIO(PK2),
+	PINMUX_GPIO(PK1),
+	PINMUX_GPIO(PK0),
 
 	/* PL */
-	PINMUX_GPIO(GPIO_PL7, PL7_DATA),
-	PINMUX_GPIO(GPIO_PL6, PL6_DATA),
-	PINMUX_GPIO(GPIO_PL5, PL5_DATA),
-	PINMUX_GPIO(GPIO_PL4, PL4_DATA),
-	PINMUX_GPIO(GPIO_PL3, PL3_DATA),
-	PINMUX_GPIO(GPIO_PL2, PL2_DATA),
-	PINMUX_GPIO(GPIO_PL1, PL1_DATA),
-	PINMUX_GPIO(GPIO_PL0, PL0_DATA),
+	PINMUX_GPIO(PL7),
+	PINMUX_GPIO(PL6),
+	PINMUX_GPIO(PL5),
+	PINMUX_GPIO(PL4),
+	PINMUX_GPIO(PL3),
+	PINMUX_GPIO(PL2),
+	PINMUX_GPIO(PL1),
+	PINMUX_GPIO(PL0),
 
 	/* PM */
-	PINMUX_GPIO(GPIO_PM1, PM1_DATA),
-	PINMUX_GPIO(GPIO_PM0, PM0_DATA),
+	PINMUX_GPIO(PM1),
+	PINMUX_GPIO(PM0),
 
 	/* PN */
-	PINMUX_GPIO(GPIO_PN7, PN7_DATA),
-	PINMUX_GPIO(GPIO_PN6, PN6_DATA),
-	PINMUX_GPIO(GPIO_PN5, PN5_DATA),
-	PINMUX_GPIO(GPIO_PN4, PN4_DATA),
-	PINMUX_GPIO(GPIO_PN3, PN3_DATA),
-	PINMUX_GPIO(GPIO_PN2, PN2_DATA),
-	PINMUX_GPIO(GPIO_PN1, PN1_DATA),
-	PINMUX_GPIO(GPIO_PN0, PN0_DATA),
+	PINMUX_GPIO(PN7),
+	PINMUX_GPIO(PN6),
+	PINMUX_GPIO(PN5),
+	PINMUX_GPIO(PN4),
+	PINMUX_GPIO(PN3),
+	PINMUX_GPIO(PN2),
+	PINMUX_GPIO(PN1),
+	PINMUX_GPIO(PN0),
 
 	/* PP */
-	PINMUX_GPIO(GPIO_PP5, PP5_DATA),
-	PINMUX_GPIO(GPIO_PP4, PP4_DATA),
-	PINMUX_GPIO(GPIO_PP3, PP3_DATA),
-	PINMUX_GPIO(GPIO_PP2, PP2_DATA),
-	PINMUX_GPIO(GPIO_PP1, PP1_DATA),
-	PINMUX_GPIO(GPIO_PP0, PP0_DATA),
+	PINMUX_GPIO(PP5),
+	PINMUX_GPIO(PP4),
+	PINMUX_GPIO(PP3),
+	PINMUX_GPIO(PP2),
+	PINMUX_GPIO(PP1),
+	PINMUX_GPIO(PP0),
 
 	/* PQ */
-	PINMUX_GPIO(GPIO_PQ4, PQ4_DATA),
-	PINMUX_GPIO(GPIO_PQ3, PQ3_DATA),
-	PINMUX_GPIO(GPIO_PQ2, PQ2_DATA),
-	PINMUX_GPIO(GPIO_PQ1, PQ1_DATA),
-	PINMUX_GPIO(GPIO_PQ0, PQ0_DATA),
+	PINMUX_GPIO(PQ4),
+	PINMUX_GPIO(PQ3),
+	PINMUX_GPIO(PQ2),
+	PINMUX_GPIO(PQ1),
+	PINMUX_GPIO(PQ0),
 
 	/* PR */
-	PINMUX_GPIO(GPIO_PR3, PR3_DATA),
-	PINMUX_GPIO(GPIO_PR2, PR2_DATA),
-	PINMUX_GPIO(GPIO_PR1, PR1_DATA),
-	PINMUX_GPIO(GPIO_PR0, PR0_DATA),
+	PINMUX_GPIO(PR3),
+	PINMUX_GPIO(PR2),
+	PINMUX_GPIO(PR1),
+	PINMUX_GPIO(PR0),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -1020,114 +989,114 @@
 
 static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xffe70000, 16, 2) {
-		PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
-		PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
-		PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
-		PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
-		PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
-		PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
-		PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
-		PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
+		PA7_FN, PA7_OUT, PA7_IN, 0,
+		PA6_FN, PA6_OUT, PA6_IN, 0,
+		PA5_FN, PA5_OUT, PA5_IN, 0,
+		PA4_FN, PA4_OUT, PA4_IN, 0,
+		PA3_FN, PA3_OUT, PA3_IN, 0,
+		PA2_FN, PA2_OUT, PA2_IN, 0,
+		PA1_FN, PA1_OUT, PA1_IN, 0,
+		PA0_FN, PA0_OUT, PA0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xffe70002, 16, 2) {
-		PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
-		PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
-		PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
-		PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
-		PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
-		PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
-		PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
-		PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
+		PB7_FN, PB7_OUT, PB7_IN, 0,
+		PB6_FN, PB6_OUT, PB6_IN, 0,
+		PB5_FN, PB5_OUT, PB5_IN, 0,
+		PB4_FN, PB4_OUT, PB4_IN, 0,
+		PB3_FN, PB3_OUT, PB3_IN, 0,
+		PB2_FN, PB2_OUT, PB2_IN, 0,
+		PB1_FN, PB1_OUT, PB1_IN, 0,
+		PB0_FN, PB0_OUT, PB0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PCCR", 0xffe70004, 16, 2) {
-		PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
-		PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
-		PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
-		PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
-		PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
-		PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
-		PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
-		PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
+		PC7_FN, PC7_OUT, PC7_IN, 0,
+		PC6_FN, PC6_OUT, PC6_IN, 0,
+		PC5_FN, PC5_OUT, PC5_IN, 0,
+		PC4_FN, PC4_OUT, PC4_IN, 0,
+		PC3_FN, PC3_OUT, PC3_IN, 0,
+		PC2_FN, PC2_OUT, PC2_IN, 0,
+		PC1_FN, PC1_OUT, PC1_IN, 0,
+		PC0_FN, PC0_OUT, PC0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xffe70006, 16, 2) {
-		PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
-		PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
-		PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
-		PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
-		PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
-		PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
-		PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
-		PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
+		PD7_FN, PD7_OUT, PD7_IN, 0,
+		PD6_FN, PD6_OUT, PD6_IN, 0,
+		PD5_FN, PD5_OUT, PD5_IN, 0,
+		PD4_FN, PD4_OUT, PD4_IN, 0,
+		PD3_FN, PD3_OUT, PD3_IN, 0,
+		PD2_FN, PD2_OUT, PD2_IN, 0,
+		PD1_FN, PD1_OUT, PD1_IN, 0,
+		PD0_FN, PD0_OUT, PD0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xffe70008, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
-		PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
-		PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
-		PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
-		PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
-		PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU }
+		PE5_FN, PE5_OUT, PE5_IN, 0,
+		PE4_FN, PE4_OUT, PE4_IN, 0,
+		PE3_FN, PE3_OUT, PE3_IN, 0,
+		PE2_FN, PE2_OUT, PE2_IN, 0,
+		PE1_FN, PE1_OUT, PE1_IN, 0,
+		PE0_FN, PE0_OUT, PE0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xffe7000a, 16, 2) {
-		PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
-		PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
-		PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
-		PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
-		PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
-		PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
-		PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
-		PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
+		PF7_FN, PF7_OUT, PF7_IN, 0,
+		PF6_FN, PF6_OUT, PF6_IN, 0,
+		PF5_FN, PF5_OUT, PF5_IN, 0,
+		PF4_FN, PF4_OUT, PF4_IN, 0,
+		PF3_FN, PF3_OUT, PF3_IN, 0,
+		PF2_FN, PF2_OUT, PF2_IN, 0,
+		PF1_FN, PF1_OUT, PF1_IN, 0,
+		PF0_FN, PF0_OUT, PF0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xffe7000c, 16, 2) {
-		PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
-		PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
-		PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
-		PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
-		PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
-		PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
-		PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
-		PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU }
+		PG7_FN, PG7_OUT, PG7_IN, 0,
+		PG6_FN, PG6_OUT, PG6_IN, 0,
+		PG5_FN, PG5_OUT, PG5_IN, 0,
+		PG4_FN, PG4_OUT, PG4_IN, 0,
+		PG3_FN, PG3_OUT, PG3_IN, 0,
+		PG2_FN, PG2_OUT, PG2_IN, 0,
+		PG1_FN, PG1_OUT, PG1_IN, 0,
+		PG0_FN, PG0_OUT, PG0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xffe7000e, 16, 2) {
-		PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
-		PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
-		PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
-		PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
-		PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
-		PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
-		PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
-		PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
+		PH7_FN, PH7_OUT, PH7_IN, 0,
+		PH6_FN, PH6_OUT, PH6_IN, 0,
+		PH5_FN, PH5_OUT, PH5_IN, 0,
+		PH4_FN, PH4_OUT, PH4_IN, 0,
+		PH3_FN, PH3_OUT, PH3_IN, 0,
+		PH2_FN, PH2_OUT, PH2_IN, 0,
+		PH1_FN, PH1_OUT, PH1_IN, 0,
+		PH0_FN, PH0_OUT, PH0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xffe70010, 16, 2) {
-		PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
-		PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
-		PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
-		PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
-		PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
-		PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
-		PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
-		PJ0_FN, PJ0_OUT, PJ0_IN, PJ0_IN_PU }
+		PJ7_FN, PJ7_OUT, PJ7_IN, 0,
+		PJ6_FN, PJ6_OUT, PJ6_IN, 0,
+		PJ5_FN, PJ5_OUT, PJ5_IN, 0,
+		PJ4_FN, PJ4_OUT, PJ4_IN, 0,
+		PJ3_FN, PJ3_OUT, PJ3_IN, 0,
+		PJ2_FN, PJ2_OUT, PJ2_IN, 0,
+		PJ1_FN, PJ1_OUT, PJ1_IN, 0,
+		PJ0_FN, PJ0_OUT, PJ0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PKCR", 0xffe70012, 16, 2) {
-		PK7_FN, PK7_OUT, PK7_IN, PK7_IN_PU,
-		PK6_FN, PK6_OUT, PK6_IN, PK6_IN_PU,
-		PK5_FN, PK5_OUT, PK5_IN, PK5_IN_PU,
-		PK4_FN, PK4_OUT, PK4_IN, PK4_IN_PU,
-		PK3_FN, PK3_OUT, PK3_IN, PK3_IN_PU,
-		PK2_FN, PK2_OUT, PK2_IN, PK2_IN_PU,
-		PK1_FN, PK1_OUT, PK1_IN, PK1_IN_PU,
-		PK0_FN, PK0_OUT, PK0_IN, PK0_IN_PU }
+		PK7_FN, PK7_OUT, PK7_IN, 0,
+		PK6_FN, PK6_OUT, PK6_IN, 0,
+		PK5_FN, PK5_OUT, PK5_IN, 0,
+		PK4_FN, PK4_OUT, PK4_IN, 0,
+		PK3_FN, PK3_OUT, PK3_IN, 0,
+		PK2_FN, PK2_OUT, PK2_IN, 0,
+		PK1_FN, PK1_OUT, PK1_IN, 0,
+		PK0_FN, PK0_OUT, PK0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PLCR", 0xffe70014, 16, 2) {
-		PL7_FN, PL7_OUT, PL7_IN, PL7_IN_PU,
-		PL6_FN, PL6_OUT, PL6_IN, PL6_IN_PU,
-		PL5_FN, PL5_OUT, PL5_IN, PL5_IN_PU,
-		PL4_FN, PL4_OUT, PL4_IN, PL4_IN_PU,
-		PL3_FN, PL3_OUT, PL3_IN, PL3_IN_PU,
-		PL2_FN, PL2_OUT, PL2_IN, PL2_IN_PU,
-		PL1_FN, PL1_OUT, PL1_IN, PL1_IN_PU,
-		PL0_FN, PL0_OUT, PL0_IN, PL0_IN_PU }
+		PL7_FN, PL7_OUT, PL7_IN, 0,
+		PL6_FN, PL6_OUT, PL6_IN, 0,
+		PL5_FN, PL5_OUT, PL5_IN, 0,
+		PL4_FN, PL4_OUT, PL4_IN, 0,
+		PL3_FN, PL3_OUT, PL3_IN, 0,
+		PL2_FN, PL2_OUT, PL2_IN, 0,
+		PL1_FN, PL1_OUT, PL1_IN, 0,
+		PL0_FN, PL0_OUT, PL0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PMCR", 0xffe70016, 16, 2) {
 		0, 0, 0, 0,
@@ -1136,48 +1105,48 @@
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PM1_FN, PM1_OUT, PM1_IN, PM1_IN_PU,
-		PM0_FN, PM0_OUT, PM0_IN, PM0_IN_PU }
+		PM1_FN, PM1_OUT, PM1_IN, 0,
+		PM0_FN, PM0_OUT, PM0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PNCR", 0xffe70018, 16, 2) {
-		PN7_FN, PN7_OUT, PN7_IN, PN7_IN_PU,
-		PN6_FN, PN6_OUT, PN6_IN, PN6_IN_PU,
-		PN5_FN, PN5_OUT, PN5_IN, PN5_IN_PU,
-		PN4_FN, PN4_OUT, PN4_IN, PN4_IN_PU,
-		PN3_FN, PN3_OUT, PN3_IN, PN3_IN_PU,
-		PN2_FN, PN2_OUT, PN2_IN, PN2_IN_PU,
-		PN1_FN, PN1_OUT, PN1_IN, PN1_IN_PU,
-		PN0_FN, PN0_OUT, PN0_IN, PN0_IN_PU }
+		PN7_FN, PN7_OUT, PN7_IN, 0,
+		PN6_FN, PN6_OUT, PN6_IN, 0,
+		PN5_FN, PN5_OUT, PN5_IN, 0,
+		PN4_FN, PN4_OUT, PN4_IN, 0,
+		PN3_FN, PN3_OUT, PN3_IN, 0,
+		PN2_FN, PN2_OUT, PN2_IN, 0,
+		PN1_FN, PN1_OUT, PN1_IN, 0,
+		PN0_FN, PN0_OUT, PN0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PPCR", 0xffe7001a, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PP5_FN, PP5_OUT, PP5_IN, PP5_IN_PU,
-		PP4_FN, PP4_OUT, PP4_IN, PP4_IN_PU,
-		PP3_FN, PP3_OUT, PP3_IN, PP3_IN_PU,
-		PP2_FN, PP2_OUT, PP2_IN, PP2_IN_PU,
-		PP1_FN, PP1_OUT, PP1_IN, PP1_IN_PU,
-		PP0_FN, PP0_OUT, PP0_IN, PP0_IN_PU }
+		PP5_FN, PP5_OUT, PP5_IN, 0,
+		PP4_FN, PP4_OUT, PP4_IN, 0,
+		PP3_FN, PP3_OUT, PP3_IN, 0,
+		PP2_FN, PP2_OUT, PP2_IN, 0,
+		PP1_FN, PP1_OUT, PP1_IN, 0,
+		PP0_FN, PP0_OUT, PP0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PQCR", 0xffe7001c, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PQ4_FN, PQ4_OUT, PQ4_IN, PQ4_IN_PU,
-		PQ3_FN, PQ3_OUT, PQ3_IN, PQ3_IN_PU,
-		PQ2_FN, PQ2_OUT, PQ2_IN, PQ2_IN_PU,
-		PQ1_FN, PQ1_OUT, PQ1_IN, PQ1_IN_PU,
-		PQ0_FN, PQ0_OUT, PQ0_IN, PQ0_IN_PU }
+		PQ4_FN, PQ4_OUT, PQ4_IN, 0,
+		PQ3_FN, PQ3_OUT, PQ3_IN, 0,
+		PQ2_FN, PQ2_OUT, PQ2_IN, 0,
+		PQ1_FN, PQ1_OUT, PQ1_IN, 0,
+		PQ0_FN, PQ0_OUT, PQ0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PRCR", 0xffe7001e, 16, 2) {
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PR3_FN, PR3_OUT, PR3_IN, PR3_IN_PU,
-		PR2_FN, PR2_OUT, PR2_IN, PR2_IN_PU,
-		PR1_FN, PR1_OUT, PR1_IN, PR1_IN_PU,
-		PR0_FN, PR0_OUT, PR0_IN, PR0_IN_PU }
+		PR3_FN, PR3_OUT, PR3_IN, 0,
+		PR2_FN, PR2_OUT, PR2_IN, 0,
+		PR1_FN, PR1_OUT, PR1_IN, 0,
+		PR0_FN, PR0_OUT, PR0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("P1MSELR", 0xffe70080, 16, 1) {
 		P1MSEL15_0, P1MSEL15_1,
@@ -1289,7 +1258,6 @@
 const struct sh_pfc_soc_info sh7785_pinmux_info = {
 	.name = "sh7785_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7786.c b/drivers/pinctrl/sh-pfc/pfc-sh7786.c
index 8ae0e32..623345f 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7786.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7786.c
@@ -60,25 +60,6 @@
 	PJ3_IN, PJ2_IN, PJ1_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
-	PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
-	PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
-	PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
-	PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
-	PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
-	PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
-	PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
-	PE7_IN_PU, PE6_IN_PU,
-	PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
-	PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
-	PG7_IN_PU, PG6_IN_PU, PG5_IN_PU,
-	PH7_IN_PU, PH6_IN_PU, PH5_IN_PU, PH4_IN_PU,
-	PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
-	PJ7_IN_PU, PJ6_IN_PU, PJ5_IN_PU, PJ4_IN_PU,
-	PJ3_IN_PU, PJ2_IN_PU, PJ1_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
 	PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
@@ -191,85 +172,84 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t pinmux_data[] = {
-
+static const u16 pinmux_data[] = {
 	/* PA GPIO */
-	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
-	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
-	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
-	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
-	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
-	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
-	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
-	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT),
+	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT),
+	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT),
+	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT),
+	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT),
+	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT),
+	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT),
+	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT),
 
 	/* PB GPIO */
-	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
-	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
-	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
-	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
-	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
-	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
-	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
-	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT),
+	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT),
+	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT),
+	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT),
+	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT),
+	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT),
+	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT),
+	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT),
 
 	/* PC GPIO */
-	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
-	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
-	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
-	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
-	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
-	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
-	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
-	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT),
+	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT),
+	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT),
+	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT),
+	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT),
+	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT),
+	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT),
+	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT),
 
 	/* PD GPIO */
-	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
-	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
-	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
-	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
-	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
-	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
-	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
-	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT),
+	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT),
+	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT),
+	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT),
+	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT),
+	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT),
+	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT),
+	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT),
 
 	/* PE GPIO */
-	PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
-	PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+	PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT),
+	PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT),
 
 	/* PF GPIO */
-	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
-	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
-	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
-	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
-	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
-	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
-	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
-	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT),
+	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT),
+	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT),
+	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT),
+	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT),
+	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT),
+	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT),
+	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT),
 
 	/* PG GPIO */
-	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
-	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
-	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT),
+	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT),
+	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT),
 
 	/* PH GPIO */
-	PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT, PH7_IN_PU),
-	PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT, PH6_IN_PU),
-	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
-	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
-	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
-	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
-	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
-	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+	PINMUX_DATA(PH7_DATA, PH7_IN, PH7_OUT),
+	PINMUX_DATA(PH6_DATA, PH6_IN, PH6_OUT),
+	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT),
+	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT),
+	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT),
+	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT),
+	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT),
+	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT),
 
 	/* PJ GPIO */
-	PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT, PJ7_IN_PU),
-	PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT, PJ6_IN_PU),
-	PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT, PJ5_IN_PU),
-	PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT, PJ4_IN_PU),
-	PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT, PJ3_IN_PU),
-	PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT, PJ2_IN_PU),
-	PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT, PJ1_IN_PU),
+	PINMUX_DATA(PJ7_DATA, PJ7_IN, PJ7_OUT),
+	PINMUX_DATA(PJ6_DATA, PJ6_IN, PJ6_OUT),
+	PINMUX_DATA(PJ5_DATA, PJ5_IN, PJ5_OUT),
+	PINMUX_DATA(PJ4_DATA, PJ4_IN, PJ4_OUT),
+	PINMUX_DATA(PJ3_DATA, PJ3_IN, PJ3_OUT),
+	PINMUX_DATA(PJ2_DATA, PJ2_IN, PJ2_OUT),
+	PINMUX_DATA(PJ1_DATA, PJ1_IN, PJ1_OUT),
 
 	/* PA FN */
 	PINMUX_DATA(CDE_MARK,		P1MSEL2_0, PA7_FN),
@@ -429,82 +409,82 @@
 
 static struct sh_pfc_pin pinmux_pins[] = {
 	/* PA */
-	PINMUX_GPIO(GPIO_PA7, PA7_DATA),
-	PINMUX_GPIO(GPIO_PA6, PA6_DATA),
-	PINMUX_GPIO(GPIO_PA5, PA5_DATA),
-	PINMUX_GPIO(GPIO_PA4, PA4_DATA),
-	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
-	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
-	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
-	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+	PINMUX_GPIO(PA7),
+	PINMUX_GPIO(PA6),
+	PINMUX_GPIO(PA5),
+	PINMUX_GPIO(PA4),
+	PINMUX_GPIO(PA3),
+	PINMUX_GPIO(PA2),
+	PINMUX_GPIO(PA1),
+	PINMUX_GPIO(PA0),
 
 	/* PB */
-	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
-	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
-	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
-	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
-	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
-	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
-	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
-	PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+	PINMUX_GPIO(PB7),
+	PINMUX_GPIO(PB6),
+	PINMUX_GPIO(PB5),
+	PINMUX_GPIO(PB4),
+	PINMUX_GPIO(PB3),
+	PINMUX_GPIO(PB2),
+	PINMUX_GPIO(PB1),
+	PINMUX_GPIO(PB0),
 
 	/* PC */
-	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
-	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
-	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
-	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
-	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
-	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
-	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
-	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+	PINMUX_GPIO(PC7),
+	PINMUX_GPIO(PC6),
+	PINMUX_GPIO(PC5),
+	PINMUX_GPIO(PC4),
+	PINMUX_GPIO(PC3),
+	PINMUX_GPIO(PC2),
+	PINMUX_GPIO(PC1),
+	PINMUX_GPIO(PC0),
 
 	/* PD */
-	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
-	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
-	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
-	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
-	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
-	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
-	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
-	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+	PINMUX_GPIO(PD7),
+	PINMUX_GPIO(PD6),
+	PINMUX_GPIO(PD5),
+	PINMUX_GPIO(PD4),
+	PINMUX_GPIO(PD3),
+	PINMUX_GPIO(PD2),
+	PINMUX_GPIO(PD1),
+	PINMUX_GPIO(PD0),
 
 	/* PE */
-	PINMUX_GPIO(GPIO_PE7, PE7_DATA),
-	PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+	PINMUX_GPIO(PE7),
+	PINMUX_GPIO(PE6),
 
 	/* PF */
-	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
-	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
-	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
-	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
-	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
-	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
-	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
-	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+	PINMUX_GPIO(PF7),
+	PINMUX_GPIO(PF6),
+	PINMUX_GPIO(PF5),
+	PINMUX_GPIO(PF4),
+	PINMUX_GPIO(PF3),
+	PINMUX_GPIO(PF2),
+	PINMUX_GPIO(PF1),
+	PINMUX_GPIO(PF0),
 
 	/* PG */
-	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
-	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
-	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+	PINMUX_GPIO(PG7),
+	PINMUX_GPIO(PG6),
+	PINMUX_GPIO(PG5),
 
 	/* PH */
-	PINMUX_GPIO(GPIO_PH7, PH7_DATA),
-	PINMUX_GPIO(GPIO_PH6, PH6_DATA),
-	PINMUX_GPIO(GPIO_PH5, PH5_DATA),
-	PINMUX_GPIO(GPIO_PH4, PH4_DATA),
-	PINMUX_GPIO(GPIO_PH3, PH3_DATA),
-	PINMUX_GPIO(GPIO_PH2, PH2_DATA),
-	PINMUX_GPIO(GPIO_PH1, PH1_DATA),
-	PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+	PINMUX_GPIO(PH7),
+	PINMUX_GPIO(PH6),
+	PINMUX_GPIO(PH5),
+	PINMUX_GPIO(PH4),
+	PINMUX_GPIO(PH3),
+	PINMUX_GPIO(PH2),
+	PINMUX_GPIO(PH1),
+	PINMUX_GPIO(PH0),
 
 	/* PJ */
-	PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
-	PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
-	PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
-	PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
-	PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
-	PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
-	PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+	PINMUX_GPIO(PJ7),
+	PINMUX_GPIO(PJ6),
+	PINMUX_GPIO(PJ5),
+	PINMUX_GPIO(PJ4),
+	PINMUX_GPIO(PJ3),
+	PINMUX_GPIO(PJ2),
+	PINMUX_GPIO(PJ1),
 };
 
 #define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
@@ -651,48 +631,48 @@
 
 static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xffcc0000, 16, 2) {
-		PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
-		PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
-		PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
-		PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
-		PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
-		PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
-		PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
-		PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU }
+		PA7_FN, PA7_OUT, PA7_IN, 0,
+		PA6_FN, PA6_OUT, PA6_IN, 0,
+		PA5_FN, PA5_OUT, PA5_IN, 0,
+		PA4_FN, PA4_OUT, PA4_IN, 0,
+		PA3_FN, PA3_OUT, PA3_IN, 0,
+		PA2_FN, PA2_OUT, PA2_IN, 0,
+		PA1_FN, PA1_OUT, PA1_IN, 0,
+		PA0_FN, PA0_OUT, PA0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xffcc0002, 16, 2) {
-		PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
-		PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
-		PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
-		PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
-		PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
-		PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
-		PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
-		PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU }
+		PB7_FN, PB7_OUT, PB7_IN, 0,
+		PB6_FN, PB6_OUT, PB6_IN, 0,
+		PB5_FN, PB5_OUT, PB5_IN, 0,
+		PB4_FN, PB4_OUT, PB4_IN, 0,
+		PB3_FN, PB3_OUT, PB3_IN, 0,
+		PB2_FN, PB2_OUT, PB2_IN, 0,
+		PB1_FN, PB1_OUT, PB1_IN, 0,
+		PB0_FN, PB0_OUT, PB0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PCCR", 0xffcc0004, 16, 2) {
-		PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
-		PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
-		PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
-		PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
-		PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
-		PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
-		PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
-		PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU }
+		PC7_FN, PC7_OUT, PC7_IN, 0,
+		PC6_FN, PC6_OUT, PC6_IN, 0,
+		PC5_FN, PC5_OUT, PC5_IN, 0,
+		PC4_FN, PC4_OUT, PC4_IN, 0,
+		PC3_FN, PC3_OUT, PC3_IN, 0,
+		PC2_FN, PC2_OUT, PC2_IN, 0,
+		PC1_FN, PC1_OUT, PC1_IN, 0,
+		PC0_FN, PC0_OUT, PC0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xffcc0006, 16, 2) {
-		PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
-		PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
-		PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
-		PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
-		PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
-		PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
-		PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
-		PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU }
+		PD7_FN, PD7_OUT, PD7_IN, 0,
+		PD6_FN, PD6_OUT, PD6_IN, 0,
+		PD5_FN, PD5_OUT, PD5_IN, 0,
+		PD4_FN, PD4_OUT, PD4_IN, 0,
+		PD3_FN, PD3_OUT, PD3_IN, 0,
+		PD2_FN, PD2_OUT, PD2_IN, 0,
+		PD1_FN, PD1_OUT, PD1_IN, 0,
+		PD0_FN, PD0_OUT, PD0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xffcc0008, 16, 2) {
-		PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
-		PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+		PE7_FN, PE7_OUT, PE7_IN, 0,
+		PE6_FN, PE6_OUT, PE6_IN, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
@@ -701,19 +681,19 @@
 		0, 0, 0, 0, }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xffcc000a, 16, 2) {
-		PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
-		PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
-		PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
-		PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
-		PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
-		PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
-		PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
-		PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU }
+		PF7_FN, PF7_OUT, PF7_IN, 0,
+		PF6_FN, PF6_OUT, PF6_IN, 0,
+		PF5_FN, PF5_OUT, PF5_IN, 0,
+		PF4_FN, PF4_OUT, PF4_IN, 0,
+		PF3_FN, PF3_OUT, PF3_IN, 0,
+		PF2_FN, PF2_OUT, PF2_IN, 0,
+		PF1_FN, PF1_OUT, PF1_IN, 0,
+		PF0_FN, PF0_OUT, PF0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xffcc000c, 16, 2) {
-		PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
-		PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
-		PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+		PG7_FN, PG7_OUT, PG7_IN, 0,
+		PG6_FN, PG6_OUT, PG6_IN, 0,
+		PG5_FN, PG5_OUT, PG5_IN, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
@@ -721,23 +701,23 @@
 		0, 0, 0, 0, }
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xffcc000e, 16, 2) {
-		PH7_FN, PH7_OUT, PH7_IN, PH7_IN_PU,
-		PH6_FN, PH6_OUT, PH6_IN, PH6_IN_PU,
-		PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
-		PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
-		PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
-		PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
-		PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
-		PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU }
+		PH7_FN, PH7_OUT, PH7_IN, 0,
+		PH6_FN, PH6_OUT, PH6_IN, 0,
+		PH5_FN, PH5_OUT, PH5_IN, 0,
+		PH4_FN, PH4_OUT, PH4_IN, 0,
+		PH3_FN, PH3_OUT, PH3_IN, 0,
+		PH2_FN, PH2_OUT, PH2_IN, 0,
+		PH1_FN, PH1_OUT, PH1_IN, 0,
+		PH0_FN, PH0_OUT, PH0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xffcc0010, 16, 2) {
-		PJ7_FN, PJ7_OUT, PJ7_IN, PJ7_IN_PU,
-		PJ6_FN, PJ6_OUT, PJ6_IN, PJ6_IN_PU,
-		PJ5_FN, PJ5_OUT, PJ5_IN, PJ5_IN_PU,
-		PJ4_FN, PJ4_OUT, PJ4_IN, PJ4_IN_PU,
-		PJ3_FN, PJ3_OUT, PJ3_IN, PJ3_IN_PU,
-		PJ2_FN, PJ2_OUT, PJ2_IN, PJ2_IN_PU,
-		PJ1_FN, PJ1_OUT, PJ1_IN, PJ1_IN_PU,
+		PJ7_FN, PJ7_OUT, PJ7_IN, 0,
+		PJ6_FN, PJ6_OUT, PJ6_IN, 0,
+		PJ5_FN, PJ5_OUT, PJ5_IN, 0,
+		PJ4_FN, PJ4_OUT, PJ4_IN, 0,
+		PJ3_FN, PJ3_OUT, PJ3_IN, 0,
+		PJ2_FN, PJ2_OUT, PJ2_IN, 0,
+		PJ1_FN, PJ1_OUT, PJ1_IN, 0,
 		0, 0, 0, 0, }
 	},
 	{ PINMUX_CFG_REG("P1MSELR", 0xffcc0080, 16, 1) {
@@ -822,7 +802,6 @@
 const struct sh_pfc_soc_info sh7786_pinmux_info = {
 	.name = "sh7786_pfc",
 	.input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
-	.input_pu = { PINMUX_INPUT_PULLUP_BEGIN, PINMUX_INPUT_PULLUP_END },
 	.output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
diff --git a/drivers/pinctrl/sh-pfc/pfc-shx3.c b/drivers/pinctrl/sh-pfc/pfc-shx3.c
index 6594c8c..55262bd 100644
--- a/drivers/pinctrl/sh-pfc/pfc-shx3.c
+++ b/drivers/pinctrl/sh-pfc/pfc-shx3.c
@@ -56,26 +56,6 @@
 	PH3_IN, PH2_IN, PH1_IN, PH0_IN,
 	PINMUX_INPUT_END,
 
-	PINMUX_INPUT_PULLUP_BEGIN,
-	PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
-	PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
-	PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
-	PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
-	PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
-	PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
-	PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
-	PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
-	PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
-	PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
-	PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
-	PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
-	PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
-	PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
-
-	PH5_IN_PU, PH4_IN_PU,
-	PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
-	PINMUX_INPUT_PULLUP_END,
-
 	PINMUX_OUTPUT_BEGIN,
 	PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
 	PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
@@ -147,85 +127,84 @@
 	PINMUX_MARK_END,
 };
 
-static const pinmux_enum_t shx3_pinmux_data[] = {
-
+static const u16 pinmux_data[] = {
 	/* PA GPIO */
-	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
-	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
-	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
-	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
-	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
-	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
-	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
-	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT),
+	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT),
+	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT),
+	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT),
+	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT),
+	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT),
+	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT),
+	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT),
 
 	/* PB GPIO */
-	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
-	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
-	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
-	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
-	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
-	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
-	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
-	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT),
+	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT),
+	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT),
+	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT),
+	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT),
+	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT),
+	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT),
+	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT),
 
 	/* PC GPIO */
-	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
-	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
-	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
-	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
-	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
-	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
-	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
-	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT),
+	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT),
+	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT),
+	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT),
+	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT),
+	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT),
+	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT),
+	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT),
 
 	/* PD GPIO */
-	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
-	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
-	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
-	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
-	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
-	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
-	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
-	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT),
+	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT),
+	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT),
+	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT),
+	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT),
+	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT),
+	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT),
+	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT),
 
 	/* PE GPIO */
-	PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
-	PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
-	PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
-	PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
-	PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
-	PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
-	PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
-	PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+	PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT),
+	PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT),
+	PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT),
+	PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT),
+	PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT),
+	PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT),
+	PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT),
+	PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT),
 
 	/* PF GPIO */
-	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
-	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
-	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
-	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
-	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
-	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
-	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
-	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT),
+	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT),
+	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT),
+	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT),
+	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT),
+	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT),
+	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT),
+	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT),
 
 	/* PG GPIO */
-	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
-	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
-	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
-	PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
-	PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
-	PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
-	PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
-	PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT),
+	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT),
+	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT),
+	PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT),
+	PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT),
+	PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT),
+	PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT),
+	PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT),
 
 	/* PH GPIO */
-	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
-	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
-	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
-	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
-	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
-	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT),
+	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT),
+	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT),
+	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT),
+	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT),
+	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT),
 
 	/* PA FN */
 	PINMUX_DATA(D31_MARK, PA7_FN),
@@ -306,89 +285,89 @@
 	PINMUX_DATA(IRQOUT_MARK,	PH0_FN),
 };
 
-static struct sh_pfc_pin shx3_pinmux_pins[] = {
+static struct sh_pfc_pin pinmux_pins[] = {
 	/* PA */
-	PINMUX_GPIO(GPIO_PA7, PA7_DATA),
-	PINMUX_GPIO(GPIO_PA6, PA6_DATA),
-	PINMUX_GPIO(GPIO_PA5, PA5_DATA),
-	PINMUX_GPIO(GPIO_PA4, PA4_DATA),
-	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
-	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
-	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
-	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+	PINMUX_GPIO(PA7),
+	PINMUX_GPIO(PA6),
+	PINMUX_GPIO(PA5),
+	PINMUX_GPIO(PA4),
+	PINMUX_GPIO(PA3),
+	PINMUX_GPIO(PA2),
+	PINMUX_GPIO(PA1),
+	PINMUX_GPIO(PA0),
 
 	/* PB */
-	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
-	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
-	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
-	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
-	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
-	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
-	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
-	PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+	PINMUX_GPIO(PB7),
+	PINMUX_GPIO(PB6),
+	PINMUX_GPIO(PB5),
+	PINMUX_GPIO(PB4),
+	PINMUX_GPIO(PB3),
+	PINMUX_GPIO(PB2),
+	PINMUX_GPIO(PB1),
+	PINMUX_GPIO(PB0),
 
 	/* PC */
-	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
-	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
-	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
-	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
-	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
-	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
-	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
-	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+	PINMUX_GPIO(PC7),
+	PINMUX_GPIO(PC6),
+	PINMUX_GPIO(PC5),
+	PINMUX_GPIO(PC4),
+	PINMUX_GPIO(PC3),
+	PINMUX_GPIO(PC2),
+	PINMUX_GPIO(PC1),
+	PINMUX_GPIO(PC0),
 
 	/* PD */
-	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
-	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
-	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
-	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
-	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
-	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
-	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
-	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+	PINMUX_GPIO(PD7),
+	PINMUX_GPIO(PD6),
+	PINMUX_GPIO(PD5),
+	PINMUX_GPIO(PD4),
+	PINMUX_GPIO(PD3),
+	PINMUX_GPIO(PD2),
+	PINMUX_GPIO(PD1),
+	PINMUX_GPIO(PD0),
 
 	/* PE */
-	PINMUX_GPIO(GPIO_PE7, PE7_DATA),
-	PINMUX_GPIO(GPIO_PE6, PE6_DATA),
-	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
-	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
-	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
-	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
-	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
-	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+	PINMUX_GPIO(PE7),
+	PINMUX_GPIO(PE6),
+	PINMUX_GPIO(PE5),
+	PINMUX_GPIO(PE4),
+	PINMUX_GPIO(PE3),
+	PINMUX_GPIO(PE2),
+	PINMUX_GPIO(PE1),
+	PINMUX_GPIO(PE0),
 
 	/* PF */
-	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
-	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
-	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
-	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
-	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
-	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
-	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
-	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+	PINMUX_GPIO(PF7),
+	PINMUX_GPIO(PF6),
+	PINMUX_GPIO(PF5),
+	PINMUX_GPIO(PF4),
+	PINMUX_GPIO(PF3),
+	PINMUX_GPIO(PF2),
+	PINMUX_GPIO(PF1),
+	PINMUX_GPIO(PF0),
 
 	/* PG */
-	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
-	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
-	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
-	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
-	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
-	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
-	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
-	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+	PINMUX_GPIO(PG7),
+	PINMUX_GPIO(PG6),
+	PINMUX_GPIO(PG5),
+	PINMUX_GPIO(PG4),
+	PINMUX_GPIO(PG3),
+	PINMUX_GPIO(PG2),
+	PINMUX_GPIO(PG1),
+	PINMUX_GPIO(PG0),
 
 	/* PH */
-	PINMUX_GPIO(GPIO_PH5, PH5_DATA),
-	PINMUX_GPIO(GPIO_PH4, PH4_DATA),
-	PINMUX_GPIO(GPIO_PH3, PH3_DATA),
-	PINMUX_GPIO(GPIO_PH2, PH2_DATA),
-	PINMUX_GPIO(GPIO_PH1, PH1_DATA),
-	PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+	PINMUX_GPIO(PH5),
+	PINMUX_GPIO(PH4),
+	PINMUX_GPIO(PH3),
+	PINMUX_GPIO(PH2),
+	PINMUX_GPIO(PH1),
+	PINMUX_GPIO(PH0),
 };
 
-#define PINMUX_FN_BASE	ARRAY_SIZE(shx3_pinmux_pins)
+#define PINMUX_FN_BASE	ARRAY_SIZE(pinmux_pins)
 
-static const struct pinmux_func shx3_pinmux_func_gpios[] = {
+static const struct pinmux_func pinmux_func_gpios[] = {
 	/* FN */
 	GPIO_FN(D31),
 	GPIO_FN(D30),
@@ -454,83 +433,83 @@
 	GPIO_FN(IRQOUT),
 };
 
-static const struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
+static const struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
-		PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
-		PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
-		PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
-		PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
-		PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
-		PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
-		PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
-		PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
-		PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
-		PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
-		PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
-		PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
-		PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
-		PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
-		PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
-		PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
+		PA7_FN, PA7_OUT, PA7_IN, 0,
+		PA6_FN, PA6_OUT, PA6_IN, 0,
+		PA5_FN, PA5_OUT, PA5_IN, 0,
+		PA4_FN, PA4_OUT, PA4_IN, 0,
+		PA3_FN, PA3_OUT, PA3_IN, 0,
+		PA2_FN, PA2_OUT, PA2_IN, 0,
+		PA1_FN, PA1_OUT, PA1_IN, 0,
+		PA0_FN, PA0_OUT, PA0_IN, 0,
+		PB7_FN, PB7_OUT, PB7_IN, 0,
+		PB6_FN, PB6_OUT, PB6_IN, 0,
+		PB5_FN, PB5_OUT, PB5_IN, 0,
+		PB4_FN, PB4_OUT, PB4_IN, 0,
+		PB3_FN, PB3_OUT, PB3_IN, 0,
+		PB2_FN, PB2_OUT, PB2_IN, 0,
+		PB1_FN, PB1_OUT, PB1_IN, 0,
+		PB0_FN, PB0_OUT, PB0_IN, 0, },
 	},
 	{ PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
-		PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
-		PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
-		PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
-		PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
-		PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
-		PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
-		PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
-		PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
-		PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
-		PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
-		PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
-		PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
-		PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
-		PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
-		PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
-		PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
+		PC7_FN, PC7_OUT, PC7_IN, 0,
+		PC6_FN, PC6_OUT, PC6_IN, 0,
+		PC5_FN, PC5_OUT, PC5_IN, 0,
+		PC4_FN, PC4_OUT, PC4_IN, 0,
+		PC3_FN, PC3_OUT, PC3_IN, 0,
+		PC2_FN, PC2_OUT, PC2_IN, 0,
+		PC1_FN, PC1_OUT, PC1_IN, 0,
+		PC0_FN, PC0_OUT, PC0_IN, 0,
+		PD7_FN, PD7_OUT, PD7_IN, 0,
+		PD6_FN, PD6_OUT, PD6_IN, 0,
+		PD5_FN, PD5_OUT, PD5_IN, 0,
+		PD4_FN, PD4_OUT, PD4_IN, 0,
+		PD3_FN, PD3_OUT, PD3_IN, 0,
+		PD2_FN, PD2_OUT, PD2_IN, 0,
+		PD1_FN, PD1_OUT, PD1_IN, 0,
+		PD0_FN, PD0_OUT, PD0_IN, 0, },
 	},
 	{ PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
-		PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
-		PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
-		PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
-		PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
-		PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
-		PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
-		PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
-		PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
-		PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
-		PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
-		PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
-		PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
-		PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
-		PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
-		PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
-		PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
+		PE7_FN, PE7_OUT, PE7_IN, 0,
+		PE6_FN, PE6_OUT, PE6_IN, 0,
+		PE5_FN, PE5_OUT, PE5_IN, 0,
+		PE4_FN, PE4_OUT, PE4_IN, 0,
+		PE3_FN, PE3_OUT, PE3_IN, 0,
+		PE2_FN, PE2_OUT, PE2_IN, 0,
+		PE1_FN, PE1_OUT, PE1_IN, 0,
+		PE0_FN, PE0_OUT, PE0_IN, 0,
+		PF7_FN, PF7_OUT, PF7_IN, 0,
+		PF6_FN, PF6_OUT, PF6_IN, 0,
+		PF5_FN, PF5_OUT, PF5_IN, 0,
+		PF4_FN, PF4_OUT, PF4_IN, 0,
+		PF3_FN, PF3_OUT, PF3_IN, 0,
+		PF2_FN, PF2_OUT, PF2_IN, 0,
+		PF1_FN, PF1_OUT, PF1_IN, 0,
+		PF0_FN, PF0_OUT, PF0_IN, 0, },
 	},
 	{ PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
-		PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
-		PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
-		PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
-		PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
-		PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
-		PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
-		PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
-		PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
+		PG7_FN, PG7_OUT, PG7_IN, 0,
+		PG6_FN, PG6_OUT, PG6_IN, 0,
+		PG5_FN, PG5_OUT, PG5_IN, 0,
+		PG4_FN, PG4_OUT, PG4_IN, 0,
+		PG3_FN, PG3_OUT, PG3_IN, 0,
+		PG2_FN, PG2_OUT, PG2_IN, 0,
+		PG1_FN, PG1_OUT, PG1_IN, 0,
+		PG0_FN, PG0_OUT, PG0_IN, 0,
 		0, 0, 0, 0,
 		0, 0, 0, 0,
-		PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
-		PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
-		PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
-		PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
-		PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
-		PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
+		PH5_FN, PH5_OUT, PH5_IN, 0,
+		PH4_FN, PH4_OUT, PH4_IN, 0,
+		PH3_FN, PH3_OUT, PH3_IN, 0,
+		PH2_FN, PH2_OUT, PH2_IN, 0,
+		PH1_FN, PH1_OUT, PH1_IN, 0,
+		PH0_FN, PH0_OUT, PH0_IN, 0, },
 	},
 	{ },
 };
 
-static const struct pinmux_data_reg shx3_pinmux_data_regs[] = {
+static const struct pinmux_data_reg pinmux_data_regs[] = {
 	{ PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
 		0, 0, 0, 0, 0, 0, 0, 0,
 		PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
@@ -569,16 +548,14 @@
 const struct sh_pfc_soc_info shx3_pinmux_info = {
 	.name		= "shx3_pfc",
 	.input		= { PINMUX_INPUT_BEGIN,	   PINMUX_INPUT_END },
-	.input_pu	= { PINMUX_INPUT_PULLUP_BEGIN,
-			    PINMUX_INPUT_PULLUP_END },
 	.output		= { PINMUX_OUTPUT_BEGIN,   PINMUX_OUTPUT_END },
 	.function	= { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-	.pins		= shx3_pinmux_pins,
-	.nr_pins	= ARRAY_SIZE(shx3_pinmux_pins),
-	.func_gpios	= shx3_pinmux_func_gpios,
-	.nr_func_gpios	= ARRAY_SIZE(shx3_pinmux_func_gpios),
-	.gpio_data	= shx3_pinmux_data,
-	.gpio_data_size	= ARRAY_SIZE(shx3_pinmux_data),
-	.cfg_regs	= shx3_pinmux_config_regs,
-	.data_regs	= shx3_pinmux_data_regs,
+	.pins		= pinmux_pins,
+	.nr_pins	= ARRAY_SIZE(pinmux_pins),
+	.func_gpios	= pinmux_func_gpios,
+	.nr_func_gpios	= ARRAY_SIZE(pinmux_func_gpios),
+	.gpio_data	= pinmux_data,
+	.gpio_data_size	= ARRAY_SIZE(pinmux_data),
+	.cfg_regs	= pinmux_config_regs,
+	.data_regs	= pinmux_data_regs,
 };
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index bc8b028..e758af9 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -529,38 +529,44 @@
 }
 
 static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin,
-			      unsigned long config)
+			      unsigned long *configs, unsigned num_configs)
 {
 	struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
 	struct sh_pfc *pfc = pmx->pfc;
-	enum pin_config_param param = pinconf_to_config_param(config);
+	enum pin_config_param param;
 	unsigned long flags;
+	unsigned int i;
 
-	if (!sh_pfc_pinconf_validate(pfc, _pin, param))
-		return -ENOTSUPP;
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
 
-	switch (param) {
-	case PIN_CONFIG_BIAS_PULL_UP:
-	case PIN_CONFIG_BIAS_PULL_DOWN:
-	case PIN_CONFIG_BIAS_DISABLE:
-		if (!pfc->info->ops || !pfc->info->ops->set_bias)
+		if (!sh_pfc_pinconf_validate(pfc, _pin, param))
 			return -ENOTSUPP;
 
-		spin_lock_irqsave(&pfc->lock, flags);
-		pfc->info->ops->set_bias(pfc, _pin, param);
-		spin_unlock_irqrestore(&pfc->lock, flags);
+		switch (param) {
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+		case PIN_CONFIG_BIAS_DISABLE:
+			if (!pfc->info->ops || !pfc->info->ops->set_bias)
+				return -ENOTSUPP;
 
-		break;
+			spin_lock_irqsave(&pfc->lock, flags);
+			pfc->info->ops->set_bias(pfc, _pin, param);
+			spin_unlock_irqrestore(&pfc->lock, flags);
 
-	default:
-		return -ENOTSUPP;
-	}
+			break;
+
+		default:
+			return -ENOTSUPP;
+		}
+	} /* for each config */
 
 	return 0;
 }
 
 static int sh_pfc_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
-				    unsigned long config)
+				    unsigned long *configs,
+				    unsigned num_configs)
 {
 	struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
 	const unsigned int *pins;
@@ -571,7 +577,7 @@
 	num_pins = pmx->pfc->info->groups[group].nr_pins;
 
 	for (i = 0; i < num_pins; ++i)
-		sh_pfc_pinconf_set(pctldev, pins[i], config);
+		sh_pfc_pinconf_set(pctldev, pins[i], configs, num_configs);
 
 	return 0;
 }
@@ -587,22 +593,9 @@
 /* PFC ranges -> pinctrl pin descs */
 static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
 {
-	const struct pinmux_range *ranges;
-	struct pinmux_range def_range;
-	unsigned int nr_ranges;
-	unsigned int nr_pins;
 	unsigned int i;
 
-	if (pfc->info->ranges == NULL) {
-		def_range.begin = 0;
-		def_range.end = pfc->info->nr_pins - 1;
-		ranges = &def_range;
-		nr_ranges = 1;
-	} else {
-		ranges = pfc->info->ranges;
-		nr_ranges = pfc->info->nr_ranges;
-	}
-
+	/* Allocate and initialize the pins and configs arrays. */
 	pmx->pins = devm_kzalloc(pfc->dev,
 				 sizeof(*pmx->pins) * pfc->info->nr_pins,
 				 GFP_KERNEL);
@@ -615,32 +608,24 @@
 	if (unlikely(!pmx->configs))
 		return -ENOMEM;
 
-	for (i = 0, nr_pins = 0; i < nr_ranges; ++i) {
-		const struct pinmux_range *range = &ranges[i];
-		unsigned int number;
+	for (i = 0; i < pfc->info->nr_pins; ++i) {
+		const struct sh_pfc_pin *info = &pfc->info->pins[i];
+		struct sh_pfc_pin_config *cfg = &pmx->configs[i];
+		struct pinctrl_pin_desc *pin = &pmx->pins[i];
 
-		for (number = range->begin; number <= range->end;
-		     number++, nr_pins++) {
-			struct sh_pfc_pin_config *cfg = &pmx->configs[nr_pins];
-			struct pinctrl_pin_desc *pin = &pmx->pins[nr_pins];
-			const struct sh_pfc_pin *info =
-				&pfc->info->pins[nr_pins];
-
-			pin->number = number;
-			pin->name = info->name;
-			cfg->type = PINMUX_TYPE_NONE;
-		}
+		/* If the pin number is equal to -1 all pins are considered */
+		pin->number = info->pin != (u16)-1 ? info->pin : i;
+		pin->name = info->name;
+		cfg->type = PINMUX_TYPE_NONE;
 	}
 
-	pfc->nr_pins = ranges[nr_ranges-1].end + 1;
-
-	return nr_ranges;
+	return 0;
 }
 
 int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
 {
 	struct sh_pfc_pinctrl *pmx;
-	int nr_ranges;
+	int ret;
 
 	pmx = devm_kzalloc(pfc->dev, sizeof(*pmx), GFP_KERNEL);
 	if (unlikely(!pmx))
@@ -649,9 +634,9 @@
 	pmx->pfc = pfc;
 	pfc->pinctrl = pmx;
 
-	nr_ranges = sh_pfc_map_pins(pfc, pmx);
-	if (unlikely(nr_ranges < 0))
-		return nr_ranges;
+	ret = sh_pfc_map_pins(pfc, pmx);
+	if (ret < 0)
+		return ret;
 
 	pmx->pctl_desc.name = DRV_NAME;
 	pmx->pctl_desc.owner = THIS_MODULE;
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 830ae1f..11bd0d9 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -14,30 +14,23 @@
 #include <linux/bug.h>
 #include <linux/stringify.h>
 
-typedef unsigned short pinmux_enum_t;
-
-#define SH_PFC_MARK_INVALID	((pinmux_enum_t)-1)
-
 enum {
 	PINMUX_TYPE_NONE,
-
 	PINMUX_TYPE_FUNCTION,
 	PINMUX_TYPE_GPIO,
 	PINMUX_TYPE_OUTPUT,
 	PINMUX_TYPE_INPUT,
-	PINMUX_TYPE_INPUT_PULLUP,
-	PINMUX_TYPE_INPUT_PULLDOWN,
-
-	PINMUX_FLAG_TYPE,	/* must be last */
 };
 
 #define SH_PFC_PIN_CFG_INPUT		(1 << 0)
 #define SH_PFC_PIN_CFG_OUTPUT		(1 << 1)
 #define SH_PFC_PIN_CFG_PULL_UP		(1 << 2)
 #define SH_PFC_PIN_CFG_PULL_DOWN	(1 << 3)
+#define SH_PFC_PIN_CFG_NO_GPIO		(1 << 31)
 
 struct sh_pfc_pin {
-	const pinmux_enum_t enum_id;
+	u16 pin;
+	u16 enum_id;
 	const char *name;
 	unsigned int configs;
 };
@@ -71,46 +64,33 @@
 };
 
 struct pinmux_func {
-	const pinmux_enum_t enum_id;
+	u16 enum_id;
 	const char *name;
 };
 
-#define PINMUX_GPIO(gpio, data_or_mark)			\
-	[gpio] = {					\
-		.name = __stringify(gpio),		\
-		.enum_id = data_or_mark,		\
-	}
-#define PINMUX_GPIO_FN(gpio, base, data_or_mark)	\
-	[gpio - (base)] = {				\
-		.name = __stringify(gpio),		\
-		.enum_id = data_or_mark,		\
-	}
-
-#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
-
 struct pinmux_cfg_reg {
 	unsigned long reg, reg_width, field_width;
-	const pinmux_enum_t *enum_ids;
+	const u16 *enum_ids;
 	const unsigned long *var_field_width;
 };
 
 #define PINMUX_CFG_REG(name, r, r_width, f_width) \
 	.reg = r, .reg_width = r_width, .field_width = f_width,		\
-	.enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)])
+	.enum_ids = (u16 [(r_width / f_width) * (1 << f_width)])
 
 #define PINMUX_CFG_REG_VAR(name, r, r_width, var_fw0, var_fwn...) \
 	.reg = r, .reg_width = r_width,	\
 	.var_field_width = (unsigned long [r_width]) { var_fw0, var_fwn, 0 }, \
-	.enum_ids = (pinmux_enum_t [])
+	.enum_ids = (u16 [])
 
 struct pinmux_data_reg {
 	unsigned long reg, reg_width;
-	const pinmux_enum_t *enum_ids;
+	const u16 *enum_ids;
 };
 
 #define PINMUX_DATA_REG(name, r, r_width) \
 	.reg = r, .reg_width = r_width,	\
-	.enum_ids = (pinmux_enum_t [r_width]) \
+	.enum_ids = (u16 [r_width]) \
 
 struct pinmux_irq {
 	int irq;
@@ -121,9 +101,9 @@
 	{ .irq = irq_nr, .gpios = (unsigned short []) { ids, 0 } }	\
 
 struct pinmux_range {
-	pinmux_enum_t begin;
-	pinmux_enum_t end;
-	pinmux_enum_t force;
+	u16 begin;
+	u16 end;
+	u16 force;
 };
 
 struct sh_pfc;
@@ -141,15 +121,11 @@
 	const struct sh_pfc_soc_operations *ops;
 
 	struct pinmux_range input;
-	struct pinmux_range input_pd;
-	struct pinmux_range input_pu;
 	struct pinmux_range output;
 	struct pinmux_range function;
 
 	const struct sh_pfc_pin *pins;
 	unsigned int nr_pins;
-	const struct pinmux_range *ranges;
-	unsigned int nr_ranges;
 	const struct sh_pfc_pin_group *groups;
 	unsigned int nr_groups;
 	const struct sh_pfc_function *functions;
@@ -161,7 +137,7 @@
 	const struct pinmux_cfg_reg *cfg_regs;
 	const struct pinmux_data_reg *data_regs;
 
-	const pinmux_enum_t *gpio_data;
+	const u16 *gpio_data;
 	unsigned int gpio_data_size;
 
 	const struct pinmux_irq *gpio_irq;
@@ -170,84 +146,155 @@
 	unsigned long unlock_reg;
 };
 
-enum { GPIO_CFG_REQ, GPIO_CFG_FREE };
+/* -----------------------------------------------------------------------------
+ * Helper macros to create pin and port lists
+ */
 
-/* helper macro for port */
-#define PORT_1(fn, pfx, sfx) fn(pfx, sfx)
+/*
+ * sh_pfc_soc_info gpio_data array macros
+ */
 
-#define PORT_10(fn, pfx, sfx) \
-	PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx),	\
-	PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx),	\
-	PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx),	\
-	PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx),	\
-	PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx)
+#define PINMUX_DATA(data_or_mark, ids...)	data_or_mark, ids, 0
 
-#define PORT_10_REV(fn, pfx, sfx)	\
-	PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx),	\
-	PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx),	\
-	PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx),	\
-	PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx),	\
-	PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
+#define PINMUX_IPSR_NOGP(ispr, fn)					\
+	PINMUX_DATA(fn##_MARK, FN_##fn)
+#define PINMUX_IPSR_DATA(ipsr, fn)					\
+	PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr)
+#define PINMUX_IPSR_NOGM(ispr, fn, ms)					\
+	PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ms)
+#define PINMUX_IPSR_MSEL(ipsr, fn, ms)					\
+	PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr, FN_##ms)
+#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms)				\
+	PINMUX_DATA(fn##_MARK, FN_##ms, FN_##ipsr, FN_##fn)
 
-#define PORT_32(fn, pfx, sfx)					\
-	PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx),	\
-	PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx),	\
-	PORT_1(fn, pfx##31, sfx)
+/*
+ * GP port style (32 ports banks)
+ */
 
-#define PORT_32_REV(fn, pfx, sfx)					\
-	PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx),		\
-	PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx),	\
-	PORT_10_REV(fn, pfx, sfx)
+#define PORT_GP_1(bank, pin, fn, sfx) fn(bank, pin, GP_##bank##_##pin, sfx)
 
-#define PORT_90(fn, pfx, sfx) \
-	PORT_10(fn, pfx##1, sfx), PORT_10(fn, pfx##2, sfx),	\
-	PORT_10(fn, pfx##3, sfx), PORT_10(fn, pfx##4, sfx),	\
-	PORT_10(fn, pfx##5, sfx), PORT_10(fn, pfx##6, sfx),	\
-	PORT_10(fn, pfx##7, sfx), PORT_10(fn, pfx##8, sfx),	\
-	PORT_10(fn, pfx##9, sfx)
+#define PORT_GP_32(bank, fn, sfx)					\
+	PORT_GP_1(bank, 0,  fn, sfx), PORT_GP_1(bank, 1,  fn, sfx),	\
+	PORT_GP_1(bank, 2,  fn, sfx), PORT_GP_1(bank, 3,  fn, sfx),	\
+	PORT_GP_1(bank, 4,  fn, sfx), PORT_GP_1(bank, 5,  fn, sfx),	\
+	PORT_GP_1(bank, 6,  fn, sfx), PORT_GP_1(bank, 7,  fn, sfx),	\
+	PORT_GP_1(bank, 8,  fn, sfx), PORT_GP_1(bank, 9,  fn, sfx),	\
+	PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx),	\
+	PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx),	\
+	PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx),	\
+	PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx),	\
+	PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx),	\
+	PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx),	\
+	PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx),	\
+	PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx),	\
+	PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx),	\
+	PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx),	\
+	PORT_GP_1(bank, 30, fn, sfx), PORT_GP_1(bank, 31, fn, sfx)
 
-#define _PORT_ALL(pfx, sfx) pfx##_##sfx
-#define _GPIO_PORT(pfx, sfx) PINMUX_GPIO(GPIO_PORT##pfx, PORT##pfx##_DATA)
-#define PORT_ALL(str)	CPU_ALL_PORT(_PORT_ALL, PORT, str)
-#define GPIO_PORT_ALL()	CPU_ALL_PORT(_GPIO_PORT, , unused)
-#define GPIO_FN(str) PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK)
+#define PORT_GP_32_REV(bank, fn, sfx)					\
+	PORT_GP_1(bank, 31, fn, sfx), PORT_GP_1(bank, 30, fn, sfx),	\
+	PORT_GP_1(bank, 29, fn, sfx), PORT_GP_1(bank, 28, fn, sfx),	\
+	PORT_GP_1(bank, 27, fn, sfx), PORT_GP_1(bank, 26, fn, sfx),	\
+	PORT_GP_1(bank, 25, fn, sfx), PORT_GP_1(bank, 24, fn, sfx),	\
+	PORT_GP_1(bank, 23, fn, sfx), PORT_GP_1(bank, 22, fn, sfx),	\
+	PORT_GP_1(bank, 21, fn, sfx), PORT_GP_1(bank, 20, fn, sfx),	\
+	PORT_GP_1(bank, 19, fn, sfx), PORT_GP_1(bank, 18, fn, sfx),	\
+	PORT_GP_1(bank, 17, fn, sfx), PORT_GP_1(bank, 16, fn, sfx),	\
+	PORT_GP_1(bank, 15, fn, sfx), PORT_GP_1(bank, 14, fn, sfx),	\
+	PORT_GP_1(bank, 13, fn, sfx), PORT_GP_1(bank, 12, fn, sfx),	\
+	PORT_GP_1(bank, 11, fn, sfx), PORT_GP_1(bank, 10, fn, sfx),	\
+	PORT_GP_1(bank, 9,  fn, sfx), PORT_GP_1(bank, 8,  fn, sfx),	\
+	PORT_GP_1(bank, 7,  fn, sfx), PORT_GP_1(bank, 6,  fn, sfx),	\
+	PORT_GP_1(bank, 5,  fn, sfx), PORT_GP_1(bank, 4,  fn, sfx),	\
+	PORT_GP_1(bank, 3,  fn, sfx), PORT_GP_1(bank, 2,  fn, sfx),	\
+	PORT_GP_1(bank, 1,  fn, sfx), PORT_GP_1(bank, 0,  fn, sfx)
 
-/* helper macro for pinmux_enum_t */
-#define PORT_DATA_I(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_IN)
+/* GP_ALL(suffix) - Expand to a list of GP_#_#_suffix */
+#define _GP_ALL(bank, pin, name, sfx)	name##_##sfx
+#define GP_ALL(str)			CPU_ALL_PORT(_GP_ALL, str)
 
-#define PORT_DATA_I_PD(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,	\
-		    PORT##nr##_IN, PORT##nr##_IN_PD)
+/* PINMUX_GPIO_GP_ALL - Expand to a list of sh_pfc_pin entries */
+#define _GP_GPIO(bank, _pin, _name, sfx)				\
+	[(bank * 32) + _pin] = {					\
+		.pin = (bank * 32) + _pin,				\
+		.name = __stringify(_name),				\
+		.enum_id = _name##_DATA,				\
+	}
+#define PINMUX_GPIO_GP_ALL()		CPU_ALL_PORT(_GP_GPIO, unused)
 
-#define PORT_DATA_I_PU(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,	\
-		    PORT##nr##_IN, PORT##nr##_IN_PU)
+/* PINMUX_DATA_GP_ALL -  Expand to a list of name_DATA, name_FN marks */
+#define _GP_DATA(bank, pin, name, sfx)	PINMUX_DATA(name##_DATA, name##_FN)
+#define PINMUX_DATA_GP_ALL()		CPU_ALL_PORT(_GP_DATA, unused)
 
-#define PORT_DATA_I_PU_PD(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0,			\
-		    PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
+/*
+ * PORT style (linear pin space)
+ */
 
-#define PORT_DATA_O(nr)		\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT)
+#define PORT_1(pn, fn, pfx, sfx) fn(pn, pfx, sfx)
 
-#define PORT_DATA_IO(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,	\
-		    PORT##nr##_IN)
+#define PORT_10(pn, fn, pfx, sfx)					  \
+	PORT_1(pn,   fn, pfx##0, sfx), PORT_1(pn+1, fn, pfx##1, sfx),	  \
+	PORT_1(pn+2, fn, pfx##2, sfx), PORT_1(pn+3, fn, pfx##3, sfx),	  \
+	PORT_1(pn+4, fn, pfx##4, sfx), PORT_1(pn+5, fn, pfx##5, sfx),	  \
+	PORT_1(pn+6, fn, pfx##6, sfx), PORT_1(pn+7, fn, pfx##7, sfx),	  \
+	PORT_1(pn+8, fn, pfx##8, sfx), PORT_1(pn+9, fn, pfx##9, sfx)
 
-#define PORT_DATA_IO_PD(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,	\
-		    PORT##nr##_IN, PORT##nr##_IN_PD)
+#define PORT_90(pn, fn, pfx, sfx)					  \
+	PORT_10(pn+10, fn, pfx##1, sfx), PORT_10(pn+20, fn, pfx##2, sfx), \
+	PORT_10(pn+30, fn, pfx##3, sfx), PORT_10(pn+40, fn, pfx##4, sfx), \
+	PORT_10(pn+50, fn, pfx##5, sfx), PORT_10(pn+60, fn, pfx##6, sfx), \
+	PORT_10(pn+70, fn, pfx##7, sfx), PORT_10(pn+80, fn, pfx##8, sfx), \
+	PORT_10(pn+90, fn, pfx##9, sfx)
 
-#define PORT_DATA_IO_PU(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,	\
-		    PORT##nr##_IN, PORT##nr##_IN_PU)
+/* PORT_ALL(suffix) - Expand to a list of PORT_#_suffix */
+#define _PORT_ALL(pn, pfx, sfx)		pfx##_##sfx
+#define PORT_ALL(str)			CPU_ALL_PORT(_PORT_ALL, PORT, str)
 
-#define PORT_DATA_IO_PU_PD(nr)	\
-	PINMUX_DATA(PORT##nr##_DATA, PORT##nr##_FN0, PORT##nr##_OUT,	\
-		    PORT##nr##_IN, PORT##nr##_IN_PD, PORT##nr##_IN_PU)
+/* PINMUX_GPIO - Expand to a sh_pfc_pin entry */
+#define PINMUX_GPIO(_pin)						\
+	[GPIO_##_pin] = {						\
+		.pin = (u16)-1,						\
+		.name = __stringify(name),				\
+		.enum_id = _pin##_DATA,					\
+	}
 
-/* helper macro for top 4 bits in PORTnCR */
+/* SH_PFC_PIN_CFG - Expand to a sh_pfc_pin entry (named PORT#) with config */
+#define SH_PFC_PIN_CFG(_pin, cfgs)					\
+	{								\
+		.pin = _pin,						\
+		.name = __stringify(PORT##_pin),			\
+		.enum_id = PORT##_pin##_DATA,				\
+		.configs = cfgs,					\
+	}
+
+/* SH_PFC_PIN_NAMED - Expand to a sh_pfc_pin entry with the given name */
+#define SH_PFC_PIN_NAMED(row, col, _name)				\
+	{								\
+		.pin = PIN_NUMBER(row, col),				\
+		.name = __stringify(PIN_##_name),			\
+		.configs = SH_PFC_PIN_CFG_NO_GPIO,			\
+	}
+
+/* PINMUX_DATA_ALL - Expand to a list of PORT_name_DATA, PORT_name_FN0,
+ *		     PORT_name_OUT, PORT_name_IN marks
+ */
+#define _PORT_DATA(pn, pfx, sfx)					\
+	PINMUX_DATA(PORT##pfx##_DATA, PORT##pfx##_FN0,			\
+		    PORT##pfx##_OUT, PORT##pfx##_IN)
+#define PINMUX_DATA_ALL()		CPU_ALL_PORT(_PORT_DATA, , unused)
+
+/* GPIO_FN(name) - Expand to a sh_pfc_pin entry for a function GPIO */
+#define PINMUX_GPIO_FN(gpio, base, data_or_mark)			\
+	[gpio - (base)] = {						\
+		.name = __stringify(gpio),				\
+		.enum_id = data_or_mark,				\
+	}
+#define GPIO_FN(str)							\
+	PINMUX_GPIO_FN(GPIO_FN_##str, PINMUX_FN_BASE, str##_MARK)
+
+/*
+ * PORTnCR macro
+ */
 #define _PCRH(in, in_pd, in_pu, out)	\
 	0, (out), (in), 0,		\
 	0, 0, 0, 0,			\
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas6.c b/drivers/pinctrl/sirf/pinctrl-atlas6.c
index 867c968..edf45a6 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas6.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas6.c
@@ -831,6 +831,7 @@
 	SIRFSOC_PIN_GROUP("lcd_24bitsgrp", lcd_24bits_pins),
 	SIRFSOC_PIN_GROUP("lcdrom_grp", lcdrom_pins),
 	SIRFSOC_PIN_GROUP("uart0grp", uart0_pins),
+	SIRFSOC_PIN_GROUP("uart0_nostreamctrlgrp", uart0_nostreamctrl_pins),
 	SIRFSOC_PIN_GROUP("uart1grp", uart1_pins),
 	SIRFSOC_PIN_GROUP("uart2grp", uart2_pins),
 	SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins),
@@ -874,6 +875,7 @@
 static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" };
 static const char * const lcdromgrp[] = { "lcdromgrp" };
 static const char * const uart0grp[] = { "uart0grp" };
+static const char * const uart0_nostreamctrlgrp[] = { "uart0_nostreamctrlgrp" };
 static const char * const uart1grp[] = { "uart1grp" };
 static const char * const uart2grp[] = { "uart2grp" };
 static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
@@ -917,6 +919,8 @@
 	SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux),
 	SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux),
 	SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux),
+	SIRFSOC_PMX_FUNCTION("uart0_nostreamctrl", uart0_nostreamctrlgrp,
+						uart0_nostreamctrl_padmux),
 	SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux),
 	SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux),
 	SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux),
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index 0677e19..26f946a 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -306,13 +306,13 @@
        u32 *flags)
 {
        if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
-               return -EINVAL;
+		return -EINVAL;
 
        if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
-               return -EINVAL;
+		return -EINVAL;
 
        if (flags)
-               *flags = gpiospec->args[1];
+		*flags = gpiospec->args[1];
 
        return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
 }
@@ -440,6 +440,8 @@
 static const struct dev_pm_ops sirfsoc_pinmux_pm_ops = {
 	.suspend_noirq = sirfsoc_pinmux_suspend_noirq,
 	.resume_noirq = sirfsoc_pinmux_resume_noirq,
+	.freeze_noirq = sirfsoc_pinmux_suspend_noirq,
+	.restore_noirq = sirfsoc_pinmux_resume_noirq,
 };
 #endif
 
@@ -831,7 +833,7 @@
 {
 	int i, err = 0;
 	struct sirfsoc_gpio_bank *bank;
-	void *regs;
+	void __iomem *regs;
 	struct platform_device *pdev;
 	bool is_marco = false;
 
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index 116da04..58bf686 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -367,21 +367,16 @@
 	if (!machdata)
 		return -ENODEV;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
 	if (!pmx) {
 		dev_err(&pdev->dev, "Can't alloc spear_pmx\n");
 		return -ENOMEM;
 	}
 
-	pmx->vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-	if (!pmx->vbase) {
-		dev_err(&pdev->dev, "Couldn't ioremap at index 0\n");
-		return -ENODEV;
-	}
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	pmx->vbase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pmx->vbase))
+		return PTR_ERR(pmx->vbase);
 
 	pmx->dev = &pdev->dev;
 	pmx->machdata = machdata;
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
index 06c7e6f..ed1d360 100644
--- a/drivers/pinctrl/spear/pinctrl-spear310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -430,4 +430,4 @@
 MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
 MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
 MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, SPEAr310_pinctrl_of_match);
+MODULE_DEVICE_TABLE(of, spear310_pinctrl_of_match);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index 0cc4335..39aec08 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -424,15 +424,16 @@
 }
 
 static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
-			   unsigned long config)
+			   unsigned long *configs, unsigned num_configs)
 {
 	struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
-	enum pin_config_param param = pinconf_to_config_param(config);
-	u16 arg = pinconf_to_config_argument(config);
+	enum pin_config_param param;
+	u16 arg;
 	u32 bank = WMT_BANK_FROM_PIN(pin);
 	u32 bit = WMT_BIT_FROM_PIN(pin);
 	u32 reg_pull_en = data->banks[bank].reg_pull_en;
 	u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg;
+	int i;
 
 	if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) {
 		dev_err(data->dev, "bias functions not supported on pin %d\n",
@@ -440,28 +441,33 @@
 		return -EINVAL;
 	}
 
-	if ((param == PIN_CONFIG_BIAS_PULL_DOWN) ||
-	    (param == PIN_CONFIG_BIAS_PULL_UP)) {
-		if (arg == 0)
-			param = PIN_CONFIG_BIAS_DISABLE;
-	}
+	for (i = 0; i < num_configs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
 
-	switch (param) {
-	case PIN_CONFIG_BIAS_DISABLE:
-		wmt_clearbits(data, reg_pull_en, BIT(bit));
-		break;
-	case PIN_CONFIG_BIAS_PULL_DOWN:
-		wmt_clearbits(data, reg_pull_cfg, BIT(bit));
-		wmt_setbits(data, reg_pull_en, BIT(bit));
-		break;
-	case PIN_CONFIG_BIAS_PULL_UP:
-		wmt_setbits(data, reg_pull_cfg, BIT(bit));
-		wmt_setbits(data, reg_pull_en, BIT(bit));
-		break;
-	default:
-		dev_err(data->dev, "unknown pinconf param\n");
-		return -EINVAL;
-	}
+		if ((param == PIN_CONFIG_BIAS_PULL_DOWN) ||
+		    (param == PIN_CONFIG_BIAS_PULL_UP)) {
+			if (arg == 0)
+				param = PIN_CONFIG_BIAS_DISABLE;
+		}
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			wmt_clearbits(data, reg_pull_en, BIT(bit));
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			wmt_clearbits(data, reg_pull_cfg, BIT(bit));
+			wmt_setbits(data, reg_pull_en, BIT(bit));
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			wmt_setbits(data, reg_pull_cfg, BIT(bit));
+			wmt_setbits(data, reg_pull_en, BIT(bit));
+			break;
+		default:
+			dev_err(data->dev, "unknown pinconf param\n");
+			return -EINVAL;
+		}
+	} /* for each config */
 
 	return 0;
 }
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 0f9f859..f911952 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -330,7 +330,7 @@
 	return platform_driver_register(&olpc_ec_plat_driver);
 }
 
-module_init(olpc_ec_init_module);
+arch_initcall(olpc_ec_init_module);
 
 MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 8e268da..0e9c169 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -1543,7 +1543,6 @@
 
 	/* TODO Find a better way to handle events count. */
 	count = asus->event_count[event % 128]++;
-	acpi_bus_generate_proc_event(asus->device, event, count);
 	acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
 					dev_name(&asus->device->dev), event,
 					count);
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 5d26e70..a6afd41 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1269,7 +1269,6 @@
 	if (event > ACPI_MAX_SYS_NOTIFY)
 		return;
 	count = eeepc->event_count[event % 128]++;
-	acpi_bus_generate_proc_event(device, event, count);
 	acpi_bus_generate_netlink_event(device->pnp.device_class,
 					dev_name(&device->dev), event,
 					count);
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 1c9386e..52b8a97 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -773,8 +773,6 @@
 				else
 					set_lcd_level(newb);
 			}
-			acpi_bus_generate_proc_event(fujitsu->dev,
-				ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
 			keycode = KEY_BRIGHTNESSUP;
 		} else if (oldb > newb) {
 			if (disable_brightness_adjust != 1) {
@@ -783,8 +781,6 @@
 				else
 					set_lcd_level(newb);
 			}
-			acpi_bus_generate_proc_event(fujitsu->dev,
-				ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
 			keycode = KEY_BRIGHTNESSDOWN;
 		}
 		break;
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 97bb05e..d6970f4 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -53,7 +53,6 @@
 #define HPWMI_ALS_QUERY 0x3
 #define HPWMI_HARDWARE_QUERY 0x4
 #define HPWMI_WIRELESS_QUERY 0x5
-#define HPWMI_BIOS_QUERY 0x9
 #define HPWMI_HOTKEY_QUERY 0xc
 #define HPWMI_WIRELESS2_QUERY 0x1b
 #define HPWMI_POSTCODEERROR_QUERY 0x2a
@@ -293,19 +292,6 @@
 	return (state & 0x4) ? 1 : 0;
 }
 
-static int hp_wmi_enable_hotkeys(void)
-{
-	int ret;
-	int query = 0x6e;
-
-	ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query),
-				   0);
-
-	if (ret)
-		return -EINVAL;
-	return 0;
-}
-
 static int hp_wmi_set_block(void *data, bool blocked)
 {
 	enum hp_wmi_radio r = (enum hp_wmi_radio) data;
@@ -1009,8 +995,6 @@
 		err = hp_wmi_input_setup();
 		if (err)
 			return err;
-
-		hp_wmi_enable_hotkeys();
 	}
 
 	if (bios_capable) {
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 4add9a3..984253d 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -464,9 +464,6 @@
 				 "error getting hotkey status\n"));
 		return;
 	}
-
-	acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
-
 	if (!sparse_keymap_report_event(hotk_input_dev,
 					result & 0xf, result & 0x80, false))
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c
index 1a90b62..4430b8c 100644
--- a/drivers/platform/x86/samsung-q10.c
+++ b/drivers/platform/x86/samsung-q10.c
@@ -176,7 +176,7 @@
 						   samsungq10_probe,
 						   NULL, 0, NULL, 0);
 
-	return PTR_RET(samsungq10_device);
+	return PTR_ERR_OR_ZERO(samsungq10_device);
 }
 
 static void __exit samsungq10_exit(void)
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 2ac045f..d3fd520 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1275,9 +1275,6 @@
 		ev_type = HOTKEY;
 		sony_laptop_report_input_event(real_ev);
 	}
-
-	acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev);
-
 	acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
 			dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
 }
@@ -2440,7 +2437,10 @@
 	if (pos < 0)
 		return pos;
 
-	return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina");
+	return snprintf(buffer, PAGE_SIZE, "%s\n",
+					pos == SPEED ? "speed" :
+					pos == STAMINA ? "stamina" :
+					pos == AUTO ? "auto" : "unknown");
 }
 
 static int sony_nc_gfx_switch_setup(struct platform_device *pd,
@@ -4243,7 +4243,6 @@
 
 found:
 	sony_laptop_report_input_event(device_event);
-	acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
 	sonypi_compat_report_event(device_event);
 	return IRQ_HANDLED;
 }
@@ -4320,7 +4319,8 @@
 		goto err_free_resources;
 	}
 
-	if (sonypi_compat_init())
+	result = sonypi_compat_init();
+	if (result)
 		goto err_remove_input;
 
 	/* request io port */
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 54d31c0..be67e5e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2022,8 +2022,6 @@
 static u32 hotkey_user_mask;		/* events visible to userspace */
 static u32 hotkey_acpi_mask;		/* events enabled in firmware */
 
-static unsigned int hotkey_report_mode;
-
 static u16 *hotkey_keycode_map;
 
 static struct attribute_set *hotkey_dev_attributes;
@@ -2282,10 +2280,6 @@
 static void tpacpi_hotkey_send_key(unsigned int scancode)
 {
 	tpacpi_input_send_key_masked(scancode);
-	if (hotkey_report_mode < 2) {
-		acpi_bus_generate_proc_event(ibm_hotkey_acpidriver.device,
-				0x80, TP_HKEY_EV_HOTKEY_BASE + scancode);
-	}
 }
 
 static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m)
@@ -2882,18 +2876,6 @@
 			     "hotkey_tablet_mode");
 }
 
-/* sysfs hotkey report_mode -------------------------------------------- */
-static ssize_t hotkey_report_mode_show(struct device *dev,
-			   struct device_attribute *attr,
-			   char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-		(hotkey_report_mode != 0) ? hotkey_report_mode : 1);
-}
-
-static struct device_attribute dev_attr_hotkey_report_mode =
-	__ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
-
 /* sysfs wakeup reason (pollable) -------------------------------------- */
 static ssize_t hotkey_wakeup_reason_show(struct device *dev,
 			   struct device_attribute *attr,
@@ -2935,7 +2917,6 @@
 	&dev_attr_hotkey_enable.attr,
 	&dev_attr_hotkey_bios_enabled.attr,
 	&dev_attr_hotkey_bios_mask.attr,
-	&dev_attr_hotkey_report_mode.attr,
 	&dev_attr_hotkey_wakeup_reason.attr,
 	&dev_attr_hotkey_wakeup_hotunplug_complete.attr,
 	&dev_attr_hotkey_mask.attr,
@@ -3439,11 +3420,6 @@
 		"initial masks: user=0x%08x, fw=0x%08x, poll=0x%08x\n",
 		hotkey_user_mask, hotkey_acpi_mask, hotkey_source_mask);
 
-	dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY,
-			"legacy ibm/hotkey event reporting over procfs %s\n",
-			(hotkey_report_mode < 2) ?
-				"enabled" : "disabled");
-
 	tpacpi_inputdev->open = &hotkey_inputdev_open;
 	tpacpi_inputdev->close = &hotkey_inputdev_close;
 
@@ -3737,13 +3713,6 @@
 				  "event happened to %s\n", TPACPI_MAIL);
 		}
 
-		/* Legacy events */
-		if (!ignore_acpi_ev &&
-		    (send_acpi_ev || hotkey_report_mode < 2)) {
-			acpi_bus_generate_proc_event(ibm->acpi->device,
-						     event, hkey);
-		}
-
 		/* netlink events */
 		if (!ignore_acpi_ev && send_acpi_ev) {
 			acpi_bus_generate_netlink_event(
@@ -8840,11 +8809,6 @@
 MODULE_PARM_DESC(brightness_enable,
 		 "Enables backlight control when 1, disables when 0");
 
-module_param(hotkey_report_mode, uint, 0444);
-MODULE_PARM_DESC(hotkey_report_mode,
-		 "used for backwards compatibility with userspace, "
-		 "see documentation");
-
 #ifdef CONFIG_THINKPAD_ACPI_ALSA_SUPPORT
 module_param_named(volume_mode, volume_mode, uint, 0444);
 MODULE_PARM_DESC(volume_mode,
@@ -8975,10 +8939,6 @@
 
 	tpacpi_lifecycle = TPACPI_LIFE_INIT;
 
-	/* Parameter checking */
-	if (hotkey_report_mode > 2)
-		return -EINVAL;
-
 	/* Driver-level probe */
 
 	ret = get_thinkpad_model_data(&thinkpad_id);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index b13344c..6e02c95 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -693,11 +693,13 @@
 
 	return sprintf(buf, "wmi:%s\n", guid_string);
 }
+static DEVICE_ATTR_RO(modalias);
 
-static struct device_attribute wmi_dev_attrs[] = {
-	__ATTR_RO(modalias),
-	__ATTR_NULL
+static struct attribute *wmi_attrs[] = {
+	&dev_attr_modalias.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(wmi);
 
 static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -732,7 +734,7 @@
 	.name = "wmi",
 	.dev_release = wmi_dev_free,
 	.dev_uevent = wmi_dev_uevent,
-	.dev_attrs = wmi_dev_attrs,
+	.dev_groups = wmi_groups,
 };
 
 static int wmi_create_device(const struct guid_block *gblock,
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 00e9403..12adb43 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -154,7 +154,7 @@
 	return 1;
 }
 
-static int pnp_bus_suspend(struct device *dev, pm_message_t state)
+static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
 {
 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
 	struct pnp_driver *pnp_drv = pnp_dev->driver;
@@ -180,6 +180,16 @@
 	return 0;
 }
 
+static int pnp_bus_suspend(struct device *dev)
+{
+	return __pnp_bus_suspend(dev, PMSG_SUSPEND);
+}
+
+static int pnp_bus_freeze(struct device *dev)
+{
+	return __pnp_bus_suspend(dev, PMSG_FREEZE);
+}
+
 static int pnp_bus_resume(struct device *dev)
 {
 	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
@@ -210,14 +220,19 @@
 	return 0;
 }
 
+static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
+	.suspend = pnp_bus_suspend,
+	.freeze = pnp_bus_freeze,
+	.resume = pnp_bus_resume,
+};
+
 struct bus_type pnp_bus_type = {
 	.name    = "pnp",
 	.match   = pnp_bus_match,
 	.probe   = pnp_device_probe,
 	.remove  = pnp_device_remove,
 	.shutdown = pnp_device_shutdown,
-	.suspend = pnp_bus_suspend,
-	.resume  = pnp_bus_resume,
+	.pm	 = &pnp_bus_dev_pm_ops,
 	.dev_attrs = pnp_interface_attrs,
 };
 
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 55cd459..34049b0 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -131,7 +131,7 @@
 	/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
 	ret = 0;
 	if (acpi_bus_power_manageable(handle))
-		acpi_bus_set_power(handle, ACPI_STATE_D3);
+		acpi_bus_set_power(handle, ACPI_STATE_D3_COLD);
 		/* continue even if acpi_bus_set_power() fails */
 	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DIS", NULL, NULL)))
 		ret = -ENODEV;
@@ -174,10 +174,10 @@
 
 	if (acpi_bus_power_manageable(handle)) {
 		int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
-							     ACPI_STATE_D3);
+							ACPI_STATE_D3_COLD);
 		if (power_state < 0)
 			power_state = (state.event == PM_EVENT_ON) ?
-					ACPI_STATE_D0 : ACPI_STATE_D3;
+					ACPI_STATE_D0 : ACPI_STATE_D3_COLD;
 
 		/*
 		 * acpi_bus_set_power() often fails (keyboard port can't be
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 7173e3a..2f07cd6 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -406,7 +406,7 @@
 		pr_err("failed to allocate class\n");
 		return PTR_ERR(pps_class);
 	}
-	pps_class->dev_attrs = pps_attrs;
+	pps_class->dev_groups = pps_groups;
 
 	err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
 	if (err < 0) {
diff --git a/drivers/pps/sysfs.c b/drivers/pps/sysfs.c
index ef0978c..aefb75d 100644
--- a/drivers/pps/sysfs.c
+++ b/drivers/pps/sysfs.c
@@ -29,8 +29,8 @@
  * Attribute functions
  */
 
-static ssize_t pps_show_assert(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t assert_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct pps_device *pps = dev_get_drvdata(dev);
 
@@ -41,9 +41,10 @@
 			(long long) pps->assert_tu.sec, pps->assert_tu.nsec,
 			pps->assert_sequence);
 }
+static DEVICE_ATTR_RO(assert);
 
-static ssize_t pps_show_clear(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t clear_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct pps_device *pps = dev_get_drvdata(dev);
 
@@ -54,45 +55,59 @@
 			(long long) pps->clear_tu.sec, pps->clear_tu.nsec,
 			pps->clear_sequence);
 }
+static DEVICE_ATTR_RO(clear);
 
-static ssize_t pps_show_mode(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct pps_device *pps = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%4x\n", pps->info.mode);
 }
+static DEVICE_ATTR_RO(mode);
 
-static ssize_t pps_show_echo(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t echo_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct pps_device *pps = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%d\n", !!pps->info.echo);
 }
+static DEVICE_ATTR_RO(echo);
 
-static ssize_t pps_show_name(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct pps_device *pps = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%s\n", pps->info.name);
 }
+static DEVICE_ATTR_RO(name);
 
-static ssize_t pps_show_path(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t path_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct pps_device *pps = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%s\n", pps->info.path);
 }
+static DEVICE_ATTR_RO(path);
 
-struct device_attribute pps_attrs[] = {
-	__ATTR(assert, S_IRUGO, pps_show_assert, NULL),
-	__ATTR(clear, S_IRUGO, pps_show_clear, NULL),
-	__ATTR(mode, S_IRUGO, pps_show_mode, NULL),
-	__ATTR(echo, S_IRUGO, pps_show_echo, NULL),
-	__ATTR(name, S_IRUGO, pps_show_name, NULL),
-	__ATTR(path, S_IRUGO, pps_show_path, NULL),
-	__ATTR_NULL,
+static struct attribute *pps_attrs[] = {
+	&dev_attr_assert.attr,
+	&dev_attr_clear.attr,
+	&dev_attr_mode.attr,
+	&dev_attr_echo.attr,
+	&dev_attr_name.attr,
+	&dev_attr_path.attr,
+	NULL,
+};
+
+static const struct attribute_group pps_group = {
+	.attrs = pps_attrs,
+};
+
+const struct attribute_group *pps_groups[] = {
+	&pps_group,
+	NULL,
 };
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 4a8c388..a8319b2 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -330,7 +330,7 @@
 		goto no_region;
 	}
 
-	ptp_class->dev_attrs = ptp_dev_attrs;
+	ptp_class->dev_groups = ptp_groups;
 	pr_info("PTP clock support registered\n");
 	return 0;
 
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index 69d3207..df03f2e 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -84,7 +84,7 @@
  * see ptp_sysfs.c
  */
 
-extern struct device_attribute ptp_dev_attrs[];
+extern const struct attribute_group *ptp_groups[];
 
 int ptp_cleanup_sysfs(struct ptp_clock *ptp);
 
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 2f93926..13ec531 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -27,36 +27,43 @@
 	struct ptp_clock *ptp = dev_get_drvdata(dev);
 	return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
 }
+static DEVICE_ATTR(clock_name, 0444, clock_name_show, NULL);
 
-#define PTP_SHOW_INT(name)						\
-static ssize_t name##_show(struct device *dev,				\
+#define PTP_SHOW_INT(name, var)						\
+static ssize_t var##_show(struct device *dev,				\
 			   struct device_attribute *attr, char *page)	\
 {									\
 	struct ptp_clock *ptp = dev_get_drvdata(dev);			\
-	return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->name);	\
-}
+	return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var);	\
+}									\
+static DEVICE_ATTR(name, 0444, var##_show, NULL);
 
-PTP_SHOW_INT(max_adj);
-PTP_SHOW_INT(n_alarm);
-PTP_SHOW_INT(n_ext_ts);
-PTP_SHOW_INT(n_per_out);
-PTP_SHOW_INT(pps);
+PTP_SHOW_INT(max_adjustment, max_adj);
+PTP_SHOW_INT(n_alarms, n_alarm);
+PTP_SHOW_INT(n_external_timestamps, n_ext_ts);
+PTP_SHOW_INT(n_periodic_outputs, n_per_out);
+PTP_SHOW_INT(pps_available, pps);
 
-#define PTP_RO_ATTR(_var, _name) {				\
-	.attr	= { .name = __stringify(_name), .mode = 0444 },	\
-	.show	= _var##_show,					\
-}
-
-struct device_attribute ptp_dev_attrs[] = {
-	PTP_RO_ATTR(clock_name,	clock_name),
-	PTP_RO_ATTR(max_adj,	max_adjustment),
-	PTP_RO_ATTR(n_alarm,	n_alarms),
-	PTP_RO_ATTR(n_ext_ts,	n_external_timestamps),
-	PTP_RO_ATTR(n_per_out,	n_periodic_outputs),
-	PTP_RO_ATTR(pps,	pps_available),
-	__ATTR_NULL,
+static struct attribute *ptp_attrs[] = {
+	&dev_attr_clock_name.attr,
+	&dev_attr_max_adjustment.attr,
+	&dev_attr_n_alarms.attr,
+	&dev_attr_n_external_timestamps.attr,
+	&dev_attr_n_periodic_outputs.attr,
+	&dev_attr_pps_available.attr,
+	NULL,
 };
 
+static const struct attribute_group ptp_group = {
+	.attrs = ptp_attrs,
+};
+
+const struct attribute_group *ptp_groups[] = {
+	&ptp_group,
+	NULL,
+};
+
+
 static ssize_t extts_enable_store(struct device *dev,
 				  struct device_attribute *attr,
 				  const char *buf, size_t count)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index dfbfbc5..2ca9504 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -30,10 +30,9 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 
-#define MAX_PWMS 1024
+#include <dt-bindings/pwm/pwm.h>
 
-/* flags in the third cell of the DT PWM specifier */
-#define PWM_SPEC_POLARITY	(1 << 0)
+#define MAX_PWMS 1024
 
 static DEFINE_MUTEX(pwm_lookup_lock);
 static LIST_HEAD(pwm_lookup_list);
@@ -149,7 +148,7 @@
 
 	pwm_set_period(pwm, args->args[1]);
 
-	if (args->args[2] & PWM_SPEC_POLARITY)
+	if (args->args[2] & PWM_POLARITY_INVERTED)
 		pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
 	else
 		pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
index efb6c7b..efac99e0 100644
--- a/drivers/pwm/pwm-lpc32xx.c
+++ b/drivers/pwm/pwm-lpc32xx.c
@@ -124,9 +124,6 @@
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -EINVAL;
-
 	lpc32xx->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(lpc32xx->base))
 		return PTR_ERR(lpc32xx->base);
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 2c77b81..c2c5a4f 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -161,9 +161,15 @@
 
 	platform_set_drvdata(pdev, mxs);
 
-	stmp_reset_block(mxs->base);
+	ret = stmp_reset_block(mxs->base);
+	if (ret)
+		goto pwm_remove;
 
 	return 0;
+
+pwm_remove:
+	pwmchip_remove(&mxs->chip);
+	return ret;
 }
 
 static int mxs_pwm_remove(struct platform_device *pdev)
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index dc97175..a4d2164 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -182,16 +182,6 @@
 	.id_table	= pwm_id_table,
 };
 
-static int __init pwm_init(void)
-{
-	return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-	platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
+module_platform_driver(pwm_driver);
 
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index 2600892..aff6ba9 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -20,6 +20,7 @@
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 #include <linux/platform_data/pwm-renesas-tpu.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -86,7 +87,7 @@
 
 struct tpu_device {
 	struct platform_device *pdev;
-	struct tpu_pwm_platform_data *pdata;
+	enum pwm_polarity polarities[TPU_CHANNEL_MAX];
 	struct pwm_chip chip;
 	spinlock_t lock;
 
@@ -228,8 +229,7 @@
 
 	pwm->tpu = tpu;
 	pwm->channel = _pwm->hwpwm;
-	pwm->polarity = tpu->pdata ? tpu->pdata->channels[pwm->channel].polarity
-		      : PWM_POLARITY_NORMAL;
+	pwm->polarity = tpu->polarities[pwm->channel];
 	pwm->prescaler = 0;
 	pwm->period = 0;
 	pwm->duty = 0;
@@ -388,6 +388,16 @@
  * Probe and remove
  */
 
+static void tpu_parse_pdata(struct tpu_device *tpu)
+{
+	struct tpu_pwm_platform_data *pdata = tpu->pdev->dev.platform_data;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tpu->polarities); ++i)
+		tpu->polarities[i] = pdata ? pdata->channels[i].polarity
+				   : PWM_POLARITY_NORMAL;
+}
+
 static int tpu_probe(struct platform_device *pdev)
 {
 	struct tpu_device *tpu;
@@ -400,15 +410,14 @@
 		return -ENOMEM;
 	}
 
-	tpu->pdata = pdev->dev.platform_data;
+	spin_lock_init(&tpu->lock);
+	tpu->pdev = pdev;
+
+	/* Initialize device configuration from platform data. */
+	tpu_parse_pdata(tpu);
 
 	/* Map memory, get clock and pin control. */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to get I/O memory\n");
-		return -ENXIO;
-	}
-
 	tpu->base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(tpu->base))
 		return PTR_ERR(tpu->base);
@@ -422,11 +431,10 @@
 	/* Initialize and register the device. */
 	platform_set_drvdata(pdev, tpu);
 
-	spin_lock_init(&tpu->lock);
-	tpu->pdev = pdev;
-
 	tpu->chip.dev = &pdev->dev;
 	tpu->chip.ops = &tpu_pwm_ops;
+	tpu->chip.of_xlate = of_pwm_xlate_with_flags;
+	tpu->chip.of_pwm_n_cells = 3;
 	tpu->chip.base = -1;
 	tpu->chip.npwm = TPU_CHANNEL_MAX;
 
@@ -457,12 +465,26 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id tpu_of_table[] = {
+	{ .compatible = "renesas,tpu-r8a73a4", },
+	{ .compatible = "renesas,tpu-r8a7740", },
+	{ .compatible = "renesas,tpu-r8a7790", },
+	{ .compatible = "renesas,tpu-sh7372", },
+	{ .compatible = "renesas,tpu", },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, tpu_of_table);
+#endif
+
 static struct platform_driver tpu_driver = {
 	.probe		= tpu_probe,
 	.remove		= tpu_remove,
 	.driver		= {
 		.name	= "renesas-tpu-pwm",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(tpu_of_table),
 	}
 };
 
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
index a54d214..8ad26b8 100644
--- a/drivers/pwm/pwm-spear.c
+++ b/drivers/pwm/pwm-spear.c
@@ -178,18 +178,13 @@
 	int ret;
 	u32 val;
 
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		dev_err(&pdev->dev, "no memory resources defined\n");
-		return -ENODEV;
-	}
-
 	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
 	if (!pc) {
 		dev_err(&pdev->dev, "failed to allocate memory\n");
 		return -ENOMEM;
 	}
 
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
 	if (IS_ERR(pc->mmio_base))
 		return PTR_ERR(pc->mmio_base);
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 72ca42d..c2e2e58 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -290,6 +290,7 @@
 	return pwmchip_remove(&pc->chip);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
 {
 	pm_runtime_get_sync(pc->chip.dev);
@@ -306,7 +307,6 @@
 	writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2);
 }
 
-#ifdef CONFIG_PM_SLEEP
 static int ecap_pwm_suspend(struct device *dev)
 {
 	struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index aa4c558..084f552 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -139,17 +139,17 @@
 	return container_of(chip, struct ehrpwm_pwm_chip, chip);
 }
 
-static u16 ehrpwm_read(void *base, int offset)
+static u16 ehrpwm_read(void __iomem *base, int offset)
 {
 	return readw(base + offset);
 }
 
-static void ehrpwm_write(void *base, int offset, unsigned int val)
+static void ehrpwm_write(void __iomem *base, int offset, unsigned int val)
 {
 	writew(val & 0xFFFF, base + offset);
 }
 
-static void ehrpwm_modify(void *base, int offset,
+static void ehrpwm_modify(void __iomem *base, int offset,
 		unsigned short mask, unsigned short val)
 {
 	unsigned short regval;
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 8ca5de3..8c20332 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -268,6 +268,7 @@
 
 	return ret ? : len;
 }
+static DEVICE_ATTR(export, 0200, NULL, pwm_export_store);
 
 static ssize_t pwm_unexport_store(struct device *parent,
 				  struct device_attribute *attr,
@@ -288,27 +289,29 @@
 
 	return ret ? : len;
 }
+static DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store);
 
-static ssize_t pwm_npwm_show(struct device *parent,
-			     struct device_attribute *attr,
-			     char *buf)
+static ssize_t npwm_show(struct device *parent, struct device_attribute *attr,
+			 char *buf)
 {
 	const struct pwm_chip *chip = dev_get_drvdata(parent);
 
 	return sprintf(buf, "%u\n", chip->npwm);
 }
+static DEVICE_ATTR_RO(npwm);
 
-static struct device_attribute pwm_chip_attrs[] = {
-	__ATTR(export, 0200, NULL, pwm_export_store),
-	__ATTR(unexport, 0200, NULL, pwm_unexport_store),
-	__ATTR(npwm, 0444, pwm_npwm_show, NULL),
-	__ATTR_NULL,
+static struct attribute *pwm_chip_attrs[] = {
+	&dev_attr_export.attr,
+	&dev_attr_unexport.attr,
+	&dev_attr_npwm.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(pwm_chip);
 
 static struct class pwm_class = {
 	.name		= "pwm",
 	.owner		= THIS_MODULE,
-	.dev_attrs	= pwm_chip_attrs,
+	.dev_groups	= pwm_chip_groups,
 };
 
 static int pwmchip_sysfs_match(struct device *parent, const void *data)
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c
new file mode 100644
index 0000000..3459f60
--- /dev/null
+++ b/drivers/regulator/88pm800.c
@@ -0,0 +1,383 @@
+/*
+ * Regulators driver for Marvell 88PM800
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ * Joseph(Yossi) Hanin <yhanin@marvell.com>
+ * Yi Zhang <yizhang@marvell.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
+
+/* LDO1 with DVC[0..3] */
+#define PM800_LDO1_VOUT		(0x08) /* VOUT1 */
+#define PM800_LDO1_VOUT_2	(0x09)
+#define PM800_LDO1_VOUT_3	(0x0A)
+#define PM800_LDO2_VOUT		(0x0B)
+#define PM800_LDO3_VOUT		(0x0C)
+#define PM800_LDO4_VOUT		(0x0D)
+#define PM800_LDO5_VOUT		(0x0E)
+#define PM800_LDO6_VOUT		(0x0F)
+#define PM800_LDO7_VOUT		(0x10)
+#define PM800_LDO8_VOUT		(0x11)
+#define PM800_LDO9_VOUT		(0x12)
+#define PM800_LDO10_VOUT	(0x13)
+#define PM800_LDO11_VOUT	(0x14)
+#define PM800_LDO12_VOUT	(0x15)
+#define PM800_LDO13_VOUT	(0x16)
+#define PM800_LDO14_VOUT	(0x17)
+#define PM800_LDO15_VOUT	(0x18)
+#define PM800_LDO16_VOUT	(0x19)
+#define PM800_LDO17_VOUT	(0x1A)
+#define PM800_LDO18_VOUT	(0x1B)
+#define PM800_LDO19_VOUT	(0x1C)
+
+/* BUCK1 with DVC[0..3] */
+#define PM800_BUCK1		(0x3C)
+#define PM800_BUCK1_1		(0x3D)
+#define PM800_BUCK1_2		(0x3E)
+#define PM800_BUCK1_3		(0x3F)
+#define PM800_BUCK2		(0x40)
+#define PM800_BUCK3		(0x41)
+#define PM800_BUCK3		(0x41)
+#define PM800_BUCK4		(0x42)
+#define PM800_BUCK4_1		(0x43)
+#define PM800_BUCK4_2		(0x44)
+#define PM800_BUCK4_3		(0x45)
+#define PM800_BUCK5		(0x46)
+
+#define PM800_BUCK_ENA		(0x50)
+#define PM800_LDO_ENA1_1	(0x51)
+#define PM800_LDO_ENA1_2	(0x52)
+#define PM800_LDO_ENA1_3	(0x53)
+
+#define PM800_LDO_ENA2_1	(0x56)
+#define PM800_LDO_ENA2_2	(0x57)
+#define PM800_LDO_ENA2_3	(0x58)
+
+#define PM800_BUCK1_MISC1	(0x78)
+#define PM800_BUCK3_MISC1	(0x7E)
+#define PM800_BUCK4_MISC1	(0x81)
+#define PM800_BUCK5_MISC1	(0x84)
+
+struct pm800_regulator_info {
+	struct regulator_desc desc;
+	int max_ua;
+};
+
+struct pm800_regulators {
+	struct regulator_dev *regulators[PM800_ID_RG_MAX];
+	struct pm80x_chip *chip;
+	struct regmap *map;
+};
+
+/*
+ * vreg - the buck regs string.
+ * ereg - the string for the enable register.
+ * ebit - the bit number in the enable register.
+ * amax - the current
+ * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges,
+ * not the constant voltage table.
+ * n_volt - Number of available selectors
+ */
+#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt)		\
+{									\
+	.desc	= {							\
+		.name	= #vreg,					\
+		.ops	= &pm800_volt_range_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= PM800_ID_##vreg,				\
+		.owner	= THIS_MODULE,					\
+		.n_voltages		= n_volt,			\
+		.linear_ranges		= volt_ranges,			\
+		.n_linear_ranges	= ARRAY_SIZE(volt_ranges),	\
+		.vsel_reg		= PM800_##vreg,			\
+		.vsel_mask		= 0x7f,				\
+		.enable_reg		= PM800_##ereg,			\
+		.enable_mask		= 1 << (ebit),			\
+	},								\
+	.max_ua		= (amax),					\
+}
+
+/*
+ * vreg - the LDO regs string
+ * ereg -  the string for the enable register.
+ * ebit - the bit number in the enable register.
+ * amax - the current
+ * volt_table - the LDO voltage table
+ * For all the LDOes, there are too many ranges. Using volt_table will be
+ * simpler and faster.
+ */
+#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table)		\
+{									\
+	.desc	= {							\
+		.name	= #vreg,					\
+		.ops	= &pm800_volt_table_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= PM800_ID_##vreg,				\
+		.owner	= THIS_MODULE,					\
+		.n_voltages = ARRAY_SIZE(ldo_volt_table),		\
+		.vsel_reg	= PM800_##vreg##_VOUT,			\
+		.vsel_mask	= 0x1f,					\
+		.enable_reg	= PM800_##ereg,				\
+		.enable_mask	= 1 << (ebit),				\
+		.volt_table	= ldo_volt_table,			\
+	},								\
+	.max_ua		= (amax),					\
+}
+
+/* Ranges are sorted in ascending order. */
+static const struct regulator_linear_range buck1_volt_range[] = {
+	{ .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f,
+	  .uV_step = 12500 },
+	{ .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50,
+	  .max_sel = 0x54, .uV_step = 50000 },
+};
+
+/* BUCK 2~5 have same ranges. */
+static const struct regulator_linear_range buck2_5_volt_range[] = {
+	{ .min_uV = 600000, .max_uV = 1587500,	.min_sel = 0, .max_sel = 0x4f,
+	  .uV_step = 12500 },
+	{ .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50,
+	  .max_sel = 0x72, .uV_step = 50000 },
+};
+
+static const unsigned int ldo1_volt_table[] = {
+	600000,  650000,  700000,  750000,  800000,  850000,  900000,  950000,
+	1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000,
+};
+
+static const unsigned int ldo2_volt_table[] = {
+	1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000,
+};
+
+/* LDO 3~17 have same voltage table. */
+static const unsigned int ldo3_17_volt_table[] = {
+	1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000,
+	2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
+};
+
+/* LDO 18~19 have same voltage table. */
+static const unsigned int ldo18_19_volt_table[] = {
+	1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000,
+};
+
+static int pm800_get_current_limit(struct regulator_dev *rdev)
+{
+	struct pm800_regulator_info *info = rdev_get_drvdata(rdev);
+
+	return info->max_ua;
+}
+
+static struct regulator_ops pm800_volt_range_ops = {
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_current_limit = pm800_get_current_limit,
+};
+
+static struct regulator_ops pm800_volt_table_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_iterate,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.get_current_limit = pm800_get_current_limit,
+};
+
+/* The array is indexed by id(PM800_ID_XXX) */
+static struct pm800_regulator_info pm800_regulator_info[] = {
+	PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55),
+	PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73),
+	PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73),
+	PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73),
+	PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73),
+
+	PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table),
+	PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table),
+	PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table),
+	PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table),
+	PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table),
+};
+
+#define PM800_REGULATOR_OF_MATCH(_name, _id)				\
+	[PM800_ID_##_id] = {						\
+		.name = #_name,						\
+		.driver_data = &pm800_regulator_info[PM800_ID_##_id],	\
+	}
+
+static struct of_regulator_match pm800_regulator_matches[] = {
+	PM800_REGULATOR_OF_MATCH(buck1, BUCK1),
+	PM800_REGULATOR_OF_MATCH(buck2, BUCK2),
+	PM800_REGULATOR_OF_MATCH(buck3, BUCK3),
+	PM800_REGULATOR_OF_MATCH(buck4, BUCK4),
+	PM800_REGULATOR_OF_MATCH(buck5, BUCK5),
+	PM800_REGULATOR_OF_MATCH(ldo1, LDO1),
+	PM800_REGULATOR_OF_MATCH(ldo2, LDO2),
+	PM800_REGULATOR_OF_MATCH(ldo3, LDO3),
+	PM800_REGULATOR_OF_MATCH(ldo4, LDO4),
+	PM800_REGULATOR_OF_MATCH(ldo5, LDO5),
+	PM800_REGULATOR_OF_MATCH(ldo6, LDO6),
+	PM800_REGULATOR_OF_MATCH(ldo7, LDO7),
+	PM800_REGULATOR_OF_MATCH(ldo8, LDO8),
+	PM800_REGULATOR_OF_MATCH(ldo9, LDO9),
+	PM800_REGULATOR_OF_MATCH(ldo10, LDO10),
+	PM800_REGULATOR_OF_MATCH(ldo11, LDO11),
+	PM800_REGULATOR_OF_MATCH(ldo12, LDO12),
+	PM800_REGULATOR_OF_MATCH(ldo13, LDO13),
+	PM800_REGULATOR_OF_MATCH(ldo14, LDO14),
+	PM800_REGULATOR_OF_MATCH(ldo15, LDO15),
+	PM800_REGULATOR_OF_MATCH(ldo16, LDO16),
+	PM800_REGULATOR_OF_MATCH(ldo17, LDO17),
+	PM800_REGULATOR_OF_MATCH(ldo18, LDO18),
+	PM800_REGULATOR_OF_MATCH(ldo19, LDO19),
+};
+
+static int pm800_regulator_dt_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	ret = of_regulator_match(&pdev->dev, np,
+				 pm800_regulator_matches,
+				 ARRAY_SIZE(pm800_regulator_matches));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int pm800_regulator_probe(struct platform_device *pdev)
+{
+	struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm80x_platform_data *pdata = dev_get_platdata(pdev->dev.parent);
+	struct pm800_regulators *pm800_data;
+	struct pm800_regulator_info *info;
+	struct regulator_config config = { };
+	struct regulator_init_data *init_data;
+	int i, ret;
+
+	if (!pdata || pdata->num_regulators == 0) {
+		if (IS_ENABLED(CONFIG_OF)) {
+			ret = pm800_regulator_dt_init(pdev);
+			if (ret)
+				return ret;
+		} else {
+			return -ENODEV;
+		}
+	} else if (pdata->num_regulators) {
+		unsigned int count = 0;
+
+		/* Check whether num_regulator is valid. */
+		for (i = 0; i < ARRAY_SIZE(pdata->regulators); i++) {
+			if (pdata->regulators[i])
+				count++;
+		}
+		if (count != pdata->num_regulators)
+			return -EINVAL;
+	} else {
+		return -EINVAL;
+	}
+
+	pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
+					GFP_KERNEL);
+	if (!pm800_data) {
+		dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
+		return -ENOMEM;
+	}
+
+	pm800_data->map = chip->subchip->regmap_power;
+	pm800_data->chip = chip;
+
+	platform_set_drvdata(pdev, pm800_data);
+
+	for (i = 0; i < PM800_ID_RG_MAX; i++) {
+		if (!pdata || pdata->num_regulators == 0)
+			init_data = pm800_regulator_matches[i].init_data;
+		else
+			init_data = pdata->regulators[i];
+		if (!init_data)
+			continue;
+		info = pm800_regulator_matches[i].driver_data;
+		config.dev = &pdev->dev;
+		config.init_data = init_data;
+		config.driver_data = info;
+		config.regmap = pm800_data->map;
+		config.of_node = pm800_regulator_matches[i].of_node;
+
+		pm800_data->regulators[i] =
+				regulator_register(&info->desc, &config);
+		if (IS_ERR(pm800_data->regulators[i])) {
+			ret = PTR_ERR(pm800_data->regulators[i]);
+			dev_err(&pdev->dev, "Failed to register %s\n",
+				info->desc.name);
+
+			while (--i >= 0)
+				regulator_unregister(pm800_data->regulators[i]);
+
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int pm800_regulator_remove(struct platform_device *pdev)
+{
+	struct pm800_regulators *pm800_data = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < PM800_ID_RG_MAX; i++)
+		regulator_unregister(pm800_data->regulators[i]);
+
+	return 0;
+}
+
+static struct platform_driver pm800_regulator_driver = {
+	.driver		= {
+		.name	= "88pm80x-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pm800_regulator_probe,
+	.remove		= pm800_regulator_remove,
+};
+
+module_platform_driver(pm800_regulator_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Joseph(Yossi) Hanin <yhanin@marvell.com>");
+MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM800 PMIC");
+MODULE_ALIAS("platform:88pm800-regulator");
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 8a7cb1f..7023097 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -346,7 +346,7 @@
 {
 	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
 	struct pm8607_regulator_info *info = NULL;
-	struct regulator_init_data *pdata = pdev->dev.platform_data;
+	struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
 	struct regulator_config config = { };
 	struct resource *res;
 	int i;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index f1e6ad9..dfe5809 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -64,15 +64,21 @@
 
 	  If unsure, say no.
 
-config REGULATOR_GPIO
-	tristate "GPIO regulator support"
-	depends on GPIOLIB
+config REGULATOR_88PM800
+	tristate "Marvell 88PM800 Power regulators"
+	depends on MFD_88PM800
 	help
-	  This driver provides support for regulators that can be
-	  controlled via gpios.
-	  It is capable of supporting current and voltage regulators
-	  and the platform has to provide a mapping of GPIO-states
-	  to target volts/amps.
+	  This driver supports Marvell 88PM800 voltage regulator chips.
+	  It delivers digitally programmable output,
+	  the voltage is programmed via I2C interface.
+	  It's suitable to support PXA988 chips to control VCC_MAIN and
+	  various voltages.
+
+config REGULATOR_88PM8607
+	tristate "Marvell 88PM8607 Power regulators"
+	depends on MFD_88PM860X=y
+	help
+	  This driver supports 88PM8607 voltage regulator chips.
 
 config REGULATOR_AD5398
 	tristate "Analog Devices AD5398/AD5821 regulators"
@@ -81,6 +87,14 @@
 	  This driver supports AD5398 and AD5821 current regulator chips.
 	  If building into module, its name is ad5398.ko.
 
+config REGULATOR_ANATOP
+	tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+	depends on MFD_SYSCON
+	help
+	  Say y here to support Freescale i.MX on-chip ANATOP LDOs
+	  regulators. It is recommended that this option be
+	  enabled on i.MX6 platform.
+
 config REGULATOR_AAT2870
 	tristate "AnalogicTech AAT2870 Regulators"
 	depends on MFD_AAT2870_CORE
@@ -88,6 +102,22 @@
 	  If you have a AnalogicTech AAT2870 say Y to enable the
 	  regulator driver.
 
+config REGULATOR_AB3100
+	tristate "ST-Ericsson AB3100 Regulator functions"
+	depends on AB3100_CORE
+	default y if AB3100_CORE
+	help
+	 These regulators correspond to functionality in the
+	 AB3100 analog baseband dealing with power regulators
+	 for the system.
+
+config REGULATOR_AB8500
+	bool "ST-Ericsson AB8500 Power Regulators"
+	depends on AB8500_CORE
+	help
+	  This driver supports the regulators found on the ST-Ericsson mixed
+	  signal AB8500 PMIC
+
 config REGULATOR_ARIZONA
 	tristate "Wolfson Arizona class devices"
 	depends on MFD_ARIZONA
@@ -96,6 +126,13 @@
 	  Support for the regulators found on Wolfson Arizona class
 	  devices.
 
+config REGULATOR_AS3711
+	tristate "AS3711 PMIC"
+	depends on MFD_AS3711
+	help
+	  This driver provides support for the voltage regulators on the
+	  AS3711 PMIC
+
 config REGULATOR_DA903X
 	tristate "Dialog Semiconductor DA9030/DA9034 regulators"
 	depends on PMIC_DA903X
@@ -120,6 +157,37 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called da9055-regulator.
 
+config REGULATOR_DA9063
+	tristate "Dialog Semiconductor DA9063 regulators"
+	depends on MFD_DA9063
+	help
+	  Say y here to support the BUCKs and LDOs regulators found on
+	  DA9063 PMICs.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called da9063-regulator.
+
+config REGULATOR_DA9210
+	tristate "Dialog Semiconductor DA9210 regulator"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Say y here to support for the Dialog Semiconductor DA9210.
+	  The DA9210 is a multi-phase synchronous step down
+	  converter 12A DC-DC Buck controlled through an I2C
+	  interface.
+
+config REGULATOR_DBX500_PRCMU
+	bool
+
+config REGULATOR_DB8500_PRCMU
+	bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+	depends on MFD_DB8500_PRCMU
+	select REGULATOR_DBX500_PRCMU
+	help
+	  This driver supports the voltage domain regulators controlled by the
+	  DB8500 PRCMU
+
 config REGULATOR_FAN53555
 	tristate "Fairchild FAN53555 Regulator"
 	depends on I2C
@@ -131,32 +199,15 @@
 	  input voltage supply of 2.5V to 5.5V. The output voltage is
 	  programmed through an I2C interface.
 
-config REGULATOR_ANATOP
-	tristate "Freescale i.MX on-chip ANATOP LDO regulators"
-	depends on MFD_SYSCON
+config REGULATOR_GPIO
+	tristate "GPIO regulator support"
+	depends on GPIOLIB
 	help
-	  Say y here to support Freescale i.MX on-chip ANATOP LDOs
-	  regulators. It is recommended that this option be
-	  enabled on i.MX6 platform.
-
-config REGULATOR_MC13XXX_CORE
-	tristate
-
-config REGULATOR_MC13783
-	tristate "Freescale MC13783 regulator driver"
-	depends on MFD_MC13783
-	select REGULATOR_MC13XXX_CORE
-	help
-	  Say y here to support the regulators found on the Freescale MC13783
-	  PMIC.
-
-config REGULATOR_MC13892
-	tristate "Freescale MC13892 regulator driver"
-	depends on MFD_MC13XXX
-	select REGULATOR_MC13XXX_CORE
-	help
-	  Say y here to support the regulators found on the Freescale MC13892
-	  PMIC.
+	  This driver provides support for regulators that can be
+	  controlled via gpios.
+	  It is capable of supporting current and voltage regulators
+	  and the platform has to provide a mapping of GPIO-states
+	  to target volts/amps.
 
 config REGULATOR_ISL6271A
 	tristate "Intersil ISL6271A Power regulator"
@@ -164,11 +215,41 @@
 	help
 	  This driver supports ISL6271A voltage regulator chip.
 
-config REGULATOR_88PM8607
-	bool "Marvell 88PM8607 Power regulators"
-	depends on MFD_88PM860X=y
+config REGULATOR_LP3971
+	tristate "National Semiconductors LP3971 PMIC regulator driver"
+	depends on I2C
 	help
-	  This driver supports 88PM8607 voltage regulator chips.
+	 Say Y here to support the voltage regulators and convertors
+	 on National Semiconductors LP3971 PMIC
+
+config REGULATOR_LP3972
+	tristate "National Semiconductors LP3972 PMIC regulator driver"
+	depends on I2C
+	help
+	 Say Y here to support the voltage regulators and convertors
+	 on National Semiconductors LP3972 PMIC
+
+config REGULATOR_LP872X
+	tristate "TI/National Semiconductor LP8720/LP8725 voltage regulators"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports LP8720/LP8725 PMIC
+
+config REGULATOR_LP8755
+	tristate "TI LP8755 High Performance PMU driver"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This driver supports LP8755 High Performance PMU driver. This
+	  chip contains six step-down DC/DC converters which can support
+	  9 mode multiphase configuration.
+
+config REGULATOR_LP8788
+	tristate "TI LP8788 Power Regulators"
+	depends on MFD_LP8788
+	help
+	  This driver supports LP8788 voltage regulator chip.
 
 config REGULATOR_MAX1586
 	tristate "Maxim 1586/1587 voltage regulator"
@@ -259,6 +340,37 @@
 	  and one current regulator 'CHARGER'. This is suitable for
 	  Exynos-4x12 chips.
 
+config REGULATOR_MC13XXX_CORE
+	tristate
+
+config REGULATOR_MC13783
+	tristate "Freescale MC13783 regulator driver"
+	depends on MFD_MC13783
+	select REGULATOR_MC13XXX_CORE
+	help
+	  Say y here to support the regulators found on the Freescale MC13783
+	  PMIC.
+
+config REGULATOR_MC13892
+	tristate "Freescale MC13892 regulator driver"
+	depends on MFD_MC13XXX
+	select REGULATOR_MC13XXX_CORE
+	help
+	  Say y here to support the regulators found on the Freescale MC13892
+	  PMIC.
+
+config REGULATOR_PALMAS
+	tristate "TI Palmas PMIC Regulators"
+	depends on MFD_PALMAS
+	help
+	  If you wish to control the regulators on the Palmas series of
+	  chips say Y here. This will enable support for all the software
+	  controllable SMPS/LDO regulators.
+
+	  The regulators available on Palmas series chips vary depending
+	  on the muxing. This is handled automatically in the driver by
+	  reading the mux info from OTP.
+
 config REGULATOR_PCAP
 	tristate "Motorola PCAP2 regulator driver"
 	depends on EZX_PCAP
@@ -266,42 +378,6 @@
 	 This driver provides support for the voltage regulators of the
 	 PCAP2 PMIC.
 
-config REGULATOR_LP3971
-	tristate "National Semiconductors LP3971 PMIC regulator driver"
-	depends on I2C
-	help
-	 Say Y here to support the voltage regulators and convertors
-	 on National Semiconductors LP3971 PMIC
-
-config REGULATOR_LP3972
-	tristate "National Semiconductors LP3972 PMIC regulator driver"
-	depends on I2C
-	help
-	 Say Y here to support the voltage regulators and convertors
-	 on National Semiconductors LP3972 PMIC
-
-config REGULATOR_LP872X
-	bool "TI/National Semiconductor LP8720/LP8725 voltage regulators"
-	depends on I2C=y
-	select REGMAP_I2C
-	help
-	  This driver supports LP8720/LP8725 PMIC
-
-config REGULATOR_LP8755
-	tristate "TI LP8755 High Performance PMU driver"
-	depends on I2C
-	select REGMAP_I2C
-	help
-	  This driver supports LP8755 High Performance PMU driver. This
-	  chip contains six step-down DC/DC converters which can support
-	  9 mode multiphase configuration.
-
-config REGULATOR_LP8788
-	bool "TI LP8788 Power Regulators"
-	depends on MFD_LP8788
-	help
-	  This driver supports LP8788 voltage regulator chip.
-
 config REGULATOR_PCF50633
 	tristate "NXP PCF50633 regulator driver"
 	depends on MFD_PCF50633
@@ -309,6 +385,14 @@
 	 Say Y here to support the voltage regulators and convertors
 	 on PCF50633
 
+config REGULATOR_PFUZE100
+	tristate "Support regulators on Freescale PFUZE100 PMIC"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  Say y here to support the regulators found on the Freescale PFUZE100
+	  PMIC.
+
 config REGULATOR_RC5T583
 	tristate "RICOH RC5T583 Power regulators"
 	depends on MFD_RC5T583
@@ -335,44 +419,15 @@
 	 via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and
 	 supports DVS mode with 8bits of output voltage control.
 
-config REGULATOR_AB3100
-	tristate "ST-Ericsson AB3100 Regulator functions"
-	depends on AB3100_CORE
-	default y if AB3100_CORE
+config REGULATOR_TI_ABB
+	tristate "TI Adaptive Body Bias on-chip LDO"
+	depends on ARCH_OMAP
 	help
-	 These regulators correspond to functionality in the
-	 AB3100 analog baseband dealing with power regulators
-	 for the system.
-
-config REGULATOR_AB8500
-	bool "ST-Ericsson AB8500 Power Regulators"
-	depends on AB8500_CORE
-	help
-	  This driver supports the regulators found on the ST-Ericsson mixed
-	  signal AB8500 PMIC
-
-config REGULATOR_DBX500_PRCMU
-	bool
-
-config REGULATOR_DB8500_PRCMU
-	bool "ST-Ericsson DB8500 Voltage Domain Regulators"
-	depends on MFD_DB8500_PRCMU
-	select REGULATOR_DBX500_PRCMU
-	help
-	  This driver supports the voltage domain regulators controlled by the
-	  DB8500 PRCMU
-
-config REGULATOR_PALMAS
-	tristate "TI Palmas PMIC Regulators"
-	depends on MFD_PALMAS
-	help
-	  If you wish to control the regulators on the Palmas series of
-	  chips say Y here. This will enable support for all the software
-	  controllable SMPS/LDO regulators.
-
-	  The regulators available on Palmas series chips vary depending
-	  on the muxing. This is handled automatically in the driver by
-	  reading the mux info from OTP.
+	  Select this option to support Texas Instruments' on-chip Adaptive Body
+	  Bias (ABB) LDO regulators. It is recommended that this option be
+	  enabled on required TI SoC. Certain Operating Performance Points
+	  on TI SoCs may be unstable without enabling this as it provides
+	  device specific optimized bias to allow/optimize functionality.
 
 config REGULATOR_TPS51632
 	tristate "TI TPS51632 Power Regulator"
@@ -475,22 +530,12 @@
 	  output to control regulators.
 
 config REGULATOR_TWL4030
-	bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
+	tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
 	depends on TWL4030_CORE
 	help
 	  This driver supports the voltage regulators provided by
 	  this family of companion chips.
 
-config REGULATOR_TI_ABB
-	bool "TI Adaptive Body Bias on-chip LDO"
-	depends on ARCH_OMAP
-	help
-	  Select this option to support Texas Instruments' on-chip Adaptive Body
-	  Bias (ABB) LDO regulators. It is recommended that this option be
-	  enabled on required TI SoC. Certain Operating Performance Points
-	  on TI SoCs may be unstable without enabling this as it provides
-	  device specific optimized bias to allow/optimize functionality.
-
 config REGULATOR_VEXPRESS
 	tristate "Versatile Express regulators"
 	depends on VEXPRESS_CONFIG
@@ -526,12 +571,5 @@
 	  This driver provides support for the voltage regulators on the
 	  WM8994 CODEC.
 
-config REGULATOR_AS3711
-	tristate "AS3711 PMIC"
-	depends on MFD_AS3711
-	help
-	  This driver provides support for the voltage regulators on the
-	  AS3711 PMIC
-
 endif
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ba4a3cf..185cce2 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -3,12 +3,13 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
 
+obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
@@ -20,6 +21,8 @@
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DA9055)	+= da9055-regulator.o
+obj-$(CONFIG_REGULATOR_DA9063)	+= da9063-regulator.o
+obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o
 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
 obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
@@ -46,12 +49,14 @@
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
+obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
@@ -64,7 +69,6 @@
 obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
-obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c
index 8b58763..881159d 100644
--- a/drivers/regulator/aat2870-regulator.c
+++ b/drivers/regulator/aat2870-regulator.c
@@ -174,7 +174,7 @@
 
 	config.dev = &pdev->dev;
 	config.driver_data = ri;
-	config.init_data = pdev->dev.platform_data;
+	config.init_data = dev_get_platdata(&pdev->dev);
 
 	rdev = regulator_register(&ri->desc, &config);
 	if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 3be9e46..7d5eaa8 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -660,7 +660,7 @@
 
 static int ab3100_regulators_probe(struct platform_device *pdev)
 {
-	struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
+	struct ab3100_platform_data *plfdata = dev_get_platdata(&pdev->dev);
 	struct device_node *np = pdev->dev.of_node;
 	int err = 0;
 	u8 data;
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
index 6b981b5..b2b203c 100644
--- a/drivers/regulator/ad5398.c
+++ b/drivers/regulator/ad5398.c
@@ -214,7 +214,7 @@
 static int ad5398_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
-	struct regulator_init_data *init_data = client->dev.platform_data;
+	struct regulator_init_data *init_data = dev_get_platdata(&client->dev);
 	struct regulator_config config = { };
 	struct ad5398_chip_info *chip;
 	const struct ad5398_current_data_format *df =
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index 3da6bd6..8406cd7 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -30,102 +30,6 @@
 	struct regulator_dev *rdev;
 };
 
-static int as3711_list_voltage_sd(struct regulator_dev *rdev,
-				  unsigned int selector)
-{
-	if (selector >= rdev->desc->n_voltages)
-		return -EINVAL;
-
-	if (!selector)
-		return 0;
-	if (selector < 0x41)
-		return 600000 + selector * 12500;
-	if (selector < 0x71)
-		return 1400000 + (selector - 0x40) * 25000;
-	return 2600000 + (selector - 0x70) * 50000;
-}
-
-static int as3711_list_voltage_aldo(struct regulator_dev *rdev,
-				    unsigned int selector)
-{
-	if (selector >= rdev->desc->n_voltages)
-		return -EINVAL;
-
-	if (selector < 0x10)
-		return 1200000 + selector * 50000;
-	return 1800000 + (selector - 0x10) * 100000;
-}
-
-static int as3711_list_voltage_dldo(struct regulator_dev *rdev,
-				    unsigned int selector)
-{
-	if (selector >= rdev->desc->n_voltages ||
-	    (selector > 0x10 && selector < 0x20))
-		return -EINVAL;
-
-	if (selector < 0x11)
-		return 900000 + selector * 50000;
-	return 1750000 + (selector - 0x20) * 50000;
-}
-
-static int as3711_bound_check(struct regulator_dev *rdev,
-			      int *min_uV, int *max_uV)
-{
-	struct as3711_regulator *reg = rdev_get_drvdata(rdev);
-	struct as3711_regulator_info *info = reg->reg_info;
-
-	dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__,
-		*min_uV, rdev->desc->min_uV, info->max_uV);
-
-	if (*max_uV < *min_uV ||
-	    *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV)
-		return -EINVAL;
-
-	if (rdev->desc->n_voltages == 1)
-		return 0;
-
-	if (*max_uV > info->max_uV)
-		*max_uV = info->max_uV;
-
-	if (*min_uV < rdev->desc->min_uV)
-		*min_uV = rdev->desc->min_uV;
-
-	return *min_uV;
-}
-
-static int as3711_sel_check(int min, int max, int bottom, int step)
-{
-	int sel, voltage;
-
-	/* Round up min, when dividing: keeps us within the range */
-	sel = DIV_ROUND_UP(min - bottom, step);
-	voltage = sel * step + bottom;
-	pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__,
-	       min, max, bottom, step, sel);
-	if (voltage > max)
-		return -EINVAL;
-
-	return sel;
-}
-
-static int as3711_map_voltage_sd(struct regulator_dev *rdev,
-				 int min_uV, int max_uV)
-{
-	int ret;
-
-	ret = as3711_bound_check(rdev, &min_uV, &max_uV);
-	if (ret <= 0)
-		return ret;
-
-	if (min_uV <= 1400000)
-		return as3711_sel_check(min_uV, max_uV, 600000, 12500);
-
-	if (min_uV <= 2600000)
-		return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40;
-
-	return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70;
-}
-
 /*
  * The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and
  * STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes:
@@ -180,44 +84,14 @@
 	return -EINVAL;
 }
 
-static int as3711_map_voltage_aldo(struct regulator_dev *rdev,
-				  int min_uV, int max_uV)
-{
-	int ret;
-
-	ret = as3711_bound_check(rdev, &min_uV, &max_uV);
-	if (ret <= 0)
-		return ret;
-
-	if (min_uV <= 1800000)
-		return as3711_sel_check(min_uV, max_uV, 1200000, 50000);
-
-	return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10;
-}
-
-static int as3711_map_voltage_dldo(struct regulator_dev *rdev,
-				  int min_uV, int max_uV)
-{
-	int ret;
-
-	ret = as3711_bound_check(rdev, &min_uV, &max_uV);
-	if (ret <= 0)
-		return ret;
-
-	if (min_uV <= 1700000)
-		return as3711_sel_check(min_uV, max_uV, 900000, 50000);
-
-	return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20;
-}
-
 static struct regulator_ops as3711_sd_ops = {
 	.is_enabled		= regulator_is_enabled_regmap,
 	.enable			= regulator_enable_regmap,
 	.disable		= regulator_disable_regmap,
 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
-	.list_voltage		= as3711_list_voltage_sd,
-	.map_voltage		= as3711_map_voltage_sd,
+	.list_voltage		= regulator_list_voltage_linear_range,
+	.map_voltage		= regulator_map_voltage_linear_range,
 	.get_mode		= as3711_get_mode_sd,
 	.set_mode		= as3711_set_mode_sd,
 };
@@ -228,8 +102,8 @@
 	.disable		= regulator_disable_regmap,
 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
-	.list_voltage		= as3711_list_voltage_aldo,
-	.map_voltage		= as3711_map_voltage_aldo,
+	.list_voltage		= regulator_list_voltage_linear_range,
+	.map_voltage		= regulator_map_voltage_linear_range,
 };
 
 static struct regulator_ops as3711_dldo_ops = {
@@ -238,8 +112,31 @@
 	.disable		= regulator_disable_regmap,
 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
-	.list_voltage		= as3711_list_voltage_dldo,
-	.map_voltage		= as3711_map_voltage_dldo,
+	.list_voltage		= regulator_list_voltage_linear_range,
+	.map_voltage		= regulator_map_voltage_linear_range,
+};
+
+static const struct regulator_linear_range as3711_sd_ranges[] = {
+	{ .min_uV = 612500, .max_uV = 1400000,
+	  .min_sel = 0x1, .max_sel = 0x40, .uV_step = 12500 },
+	{ .min_uV = 1425000, .max_uV = 2600000,
+	  .min_sel = 0x41, .max_sel = 0x70, .uV_step = 25000 },
+	{ .min_uV = 2650000, .max_uV = 3350000,
+	  .min_sel = 0x71, .max_sel = 0x7f, .uV_step = 50000 },
+};
+
+static const struct regulator_linear_range as3711_aldo_ranges[] = {
+	{ .min_uV = 1200000, .max_uV = 1950000,
+	  .min_sel = 0, .max_sel = 0xf, .uV_step = 50000 },
+	{ .min_uV = 1800000, .max_uV = 3300000,
+	  .min_sel = 0x10, .max_sel = 0x1f, .uV_step = 100000 },
+};
+
+static const struct regulator_linear_range as3711_dldo_ranges[] = {
+	{ .min_uV = 900000, .max_uV = 1700000,
+	  .min_sel = 0, .max_sel = 0x10, .uV_step = 50000 },
+	{ .min_uV = 1750000, .max_uV = 3300000,
+	  .min_sel = 0x20, .max_sel = 0x3f, .uV_step = 50000 },
 };
 
 #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx)	\
@@ -256,6 +153,8 @@
 		.enable_reg = AS3711_ ## _en_reg,					\
 		.enable_mask = BIT(_en_bit),						\
 		.min_uV	= _min_uV,							\
+		.linear_ranges = as3711_ ## _sfx ## _ranges,				\
+		.n_linear_ranges = ARRAY_SIZE(as3711_ ## _sfx ## _ranges),		\
 	},										\
 	.max_uV = _max_uV,								\
 }
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 288c75a..a01b8b3 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -323,13 +323,14 @@
 }
 static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
 
-static ssize_t regulator_name_show(struct device *dev,
-			     struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
 	return sprintf(buf, "%s\n", rdev_get_name(rdev));
 }
+static DEVICE_ATTR_RO(name);
 
 static ssize_t regulator_print_opmode(char *buf, int mode)
 {
@@ -489,15 +490,16 @@
 }
 static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
 
-static ssize_t regulator_num_users_show(struct device *dev,
-				      struct device_attribute *attr, char *buf)
+static ssize_t num_users_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
 {
 	struct regulator_dev *rdev = dev_get_drvdata(dev);
 	return sprintf(buf, "%d\n", rdev->use_count);
 }
+static DEVICE_ATTR_RO(num_users);
 
-static ssize_t regulator_type_show(struct device *dev,
-				  struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct regulator_dev *rdev = dev_get_drvdata(dev);
 
@@ -509,6 +511,7 @@
 	}
 	return sprintf(buf, "unknown\n");
 }
+static DEVICE_ATTR_RO(type);
 
 static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -632,12 +635,13 @@
  * These are the only attributes are present for all regulators.
  * Other attributes are a function of regulator functionality.
  */
-static struct device_attribute regulator_dev_attrs[] = {
-	__ATTR(name, 0444, regulator_name_show, NULL),
-	__ATTR(num_users, 0444, regulator_num_users_show, NULL),
-	__ATTR(type, 0444, regulator_type_show, NULL),
-	__ATTR_NULL,
+static struct attribute *regulator_dev_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_num_users.attr,
+	&dev_attr_type.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(regulator_dev);
 
 static void regulator_dev_release(struct device *dev)
 {
@@ -648,7 +652,7 @@
 static struct class regulator_class = {
 	.name = "regulator",
 	.dev_release = regulator_dev_release,
-	.dev_attrs = regulator_dev_attrs,
+	.dev_groups = regulator_dev_groups,
 };
 
 /* Calculate the new optimum regulator operating mode based on the new total
@@ -984,7 +988,8 @@
 		}
 	}
 
-	if (rdev->constraints->ramp_delay && ops->set_ramp_delay) {
+	if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable)
+		&& ops->set_ramp_delay) {
 		ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay);
 		if (ret < 0) {
 			rdev_err(rdev, "failed to set ramp_delay\n");
@@ -1238,7 +1243,7 @@
 
 /* Internal regulator request function */
 static struct regulator *_regulator_get(struct device *dev, const char *id,
-					int exclusive)
+					bool exclusive)
 {
 	struct regulator_dev *rdev;
 	struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
@@ -1344,7 +1349,7 @@
  */
 struct regulator *regulator_get(struct device *dev, const char *id)
 {
-	return _regulator_get(dev, id, 0);
+	return _regulator_get(dev, id, false);
 }
 EXPORT_SYMBOL_GPL(regulator_get);
 
@@ -1405,10 +1410,69 @@
  */
 struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
 {
-	return _regulator_get(dev, id, 1);
+	return _regulator_get(dev, id, true);
 }
 EXPORT_SYMBOL_GPL(regulator_get_exclusive);
 
+/**
+ * regulator_get_optional - obtain optional access to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.  Other consumers will be
+ * unable to obtain this reference is held and the use count for the
+ * regulator will be initialised to reflect the current state of the
+ * regulator.
+ *
+ * This is intended for use by consumers for devices which can have
+ * some supplies unconnected in normal use, such as some MMC devices.
+ * It can allow the regulator core to provide stub supplies for other
+ * supplies requested using normal regulator_get() calls without
+ * disrupting the operation of drivers that can handle absent
+ * supplies.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged.  It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get_optional(struct device *dev, const char *id)
+{
+	return _regulator_get(dev, id, 0);
+}
+EXPORT_SYMBOL_GPL(regulator_get_optional);
+
+/**
+ * devm_regulator_get_optional - Resource managed regulator_get_optional()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get_optional(). Regulators returned from this
+ * function are automatically regulator_put() on driver detach. See
+ * regulator_get_optional() for more information.
+ */
+struct regulator *devm_regulator_get_optional(struct device *dev,
+					      const char *id)
+{
+	struct regulator **ptr, *regulator;
+
+	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	regulator = regulator_get_optional(dev, id);
+	if (!IS_ERR(regulator)) {
+		*ptr = regulator;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
+
 /* Locks held by regulator_put() */
 static void _regulator_put(struct regulator *regulator)
 {
@@ -1435,6 +1499,36 @@
 }
 
 /**
+ * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive()
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Managed regulator_get_exclusive(). Regulators returned from this function
+ * are automatically regulator_put() on driver detach. See regulator_get() for
+ * more information.
+ */
+struct regulator *devm_regulator_get_exclusive(struct device *dev,
+					       const char *id)
+{
+	struct regulator **ptr, *regulator;
+
+	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	regulator = _regulator_get(dev, id, 1);
+	if (!IS_ERR(regulator)) {
+		*ptr = regulator;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return regulator;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive);
+
+/**
  * regulator_put - "free" the regulator source
  * @regulator: regulator source
  *
@@ -1890,8 +1984,9 @@
 	rdev->deferred_disables++;
 	mutex_unlock(&rdev->mutex);
 
-	ret = schedule_delayed_work(&rdev->disable_work,
-				    msecs_to_jiffies(ms));
+	ret = queue_delayed_work(system_power_efficient_wq,
+				 &rdev->disable_work,
+				 msecs_to_jiffies(ms));
 	if (ret < 0)
 		return ret;
 	else
@@ -1899,77 +1994,6 @@
 }
 EXPORT_SYMBOL_GPL(regulator_disable_deferred);
 
-/**
- * regulator_is_enabled_regmap - standard is_enabled() for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * enable_reg and enable_mask fields in their descriptor and then use
- * this as their is_enabled operation, saving some code.
- */
-int regulator_is_enabled_regmap(struct regulator_dev *rdev)
-{
-	unsigned int val;
-	int ret;
-
-	ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
-	if (ret != 0)
-		return ret;
-
-	if (rdev->desc->enable_is_inverted)
-		return (val & rdev->desc->enable_mask) == 0;
-	else
-		return (val & rdev->desc->enable_mask) != 0;
-}
-EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
-
-/**
- * regulator_enable_regmap - standard enable() for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * enable_reg and enable_mask fields in their descriptor and then use
- * this as their enable() operation, saving some code.
- */
-int regulator_enable_regmap(struct regulator_dev *rdev)
-{
-	unsigned int val;
-
-	if (rdev->desc->enable_is_inverted)
-		val = 0;
-	else
-		val = rdev->desc->enable_mask;
-
-	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
-				  rdev->desc->enable_mask, val);
-}
-EXPORT_SYMBOL_GPL(regulator_enable_regmap);
-
-/**
- * regulator_disable_regmap - standard disable() for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * enable_reg and enable_mask fields in their descriptor and then use
- * this as their disable() operation, saving some code.
- */
-int regulator_disable_regmap(struct regulator_dev *rdev)
-{
-	unsigned int val;
-
-	if (rdev->desc->enable_is_inverted)
-		val = rdev->desc->enable_mask;
-	else
-		val = 0;
-
-	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
-				  rdev->desc->enable_mask, val);
-}
-EXPORT_SYMBOL_GPL(regulator_disable_regmap);
-
 static int _regulator_is_enabled(struct regulator_dev *rdev)
 {
 	/* A GPIO control always takes precedence */
@@ -2055,55 +2079,6 @@
 EXPORT_SYMBOL_GPL(regulator_count_voltages);
 
 /**
- * regulator_list_voltage_linear - List voltages with simple calculation
- *
- * @rdev: Regulator device
- * @selector: Selector to convert into a voltage
- *
- * Regulators with a simple linear mapping between voltages and
- * selectors can set min_uV and uV_step in the regulator descriptor
- * and then use this function as their list_voltage() operation,
- */
-int regulator_list_voltage_linear(struct regulator_dev *rdev,
-				  unsigned int selector)
-{
-	if (selector >= rdev->desc->n_voltages)
-		return -EINVAL;
-	if (selector < rdev->desc->linear_min_sel)
-		return 0;
-
-	selector -= rdev->desc->linear_min_sel;
-
-	return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
-}
-EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
-
-/**
- * regulator_list_voltage_table - List voltages with table based mapping
- *
- * @rdev: Regulator device
- * @selector: Selector to convert into a voltage
- *
- * Regulators with table based mapping between voltages and
- * selectors can set volt_table in the regulator descriptor
- * and then use this function as their list_voltage() operation.
- */
-int regulator_list_voltage_table(struct regulator_dev *rdev,
-				 unsigned int selector)
-{
-	if (!rdev->desc->volt_table) {
-		BUG_ON(!rdev->desc->volt_table);
-		return -EINVAL;
-	}
-
-	if (selector >= rdev->desc->n_voltages)
-		return -EINVAL;
-
-	return rdev->desc->volt_table[selector];
-}
-EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
-
-/**
  * regulator_list_voltage - enumerate supported voltages
  * @regulator: regulator source
  * @selector: identify voltage to list
@@ -2197,177 +2172,6 @@
 }
 EXPORT_SYMBOL_GPL(regulator_is_supported_voltage);
 
-/**
- * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
- *
- * @rdev: regulator to operate on
- *
- * Regulators that use regmap for their register I/O can set the
- * vsel_reg and vsel_mask fields in their descriptor and then use this
- * as their get_voltage_vsel operation, saving some code.
- */
-int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev)
-{
-	unsigned int val;
-	int ret;
-
-	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
-	if (ret != 0)
-		return ret;
-
-	val &= rdev->desc->vsel_mask;
-	val >>= ffs(rdev->desc->vsel_mask) - 1;
-
-	return val;
-}
-EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
-
-/**
- * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
- *
- * @rdev: regulator to operate on
- * @sel: Selector to set
- *
- * Regulators that use regmap for their register I/O can set the
- * vsel_reg and vsel_mask fields in their descriptor and then use this
- * as their set_voltage_vsel operation, saving some code.
- */
-int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
-{
-	int ret;
-
-	sel <<= ffs(rdev->desc->vsel_mask) - 1;
-
-	ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
-				  rdev->desc->vsel_mask, sel);
-	if (ret)
-		return ret;
-
-	if (rdev->desc->apply_bit)
-		ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
-					 rdev->desc->apply_bit,
-					 rdev->desc->apply_bit);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
-
-/**
- * regulator_map_voltage_iterate - map_voltage() based on list_voltage()
- *
- * @rdev: Regulator to operate on
- * @min_uV: Lower bound for voltage
- * @max_uV: Upper bound for voltage
- *
- * Drivers implementing set_voltage_sel() and list_voltage() can use
- * this as their map_voltage() operation.  It will find a suitable
- * voltage by calling list_voltage() until it gets something in bounds
- * for the requested voltages.
- */
-int regulator_map_voltage_iterate(struct regulator_dev *rdev,
-				  int min_uV, int max_uV)
-{
-	int best_val = INT_MAX;
-	int selector = 0;
-	int i, ret;
-
-	/* Find the smallest voltage that falls within the specified
-	 * range.
-	 */
-	for (i = 0; i < rdev->desc->n_voltages; i++) {
-		ret = rdev->desc->ops->list_voltage(rdev, i);
-		if (ret < 0)
-			continue;
-
-		if (ret < best_val && ret >= min_uV && ret <= max_uV) {
-			best_val = ret;
-			selector = i;
-		}
-	}
-
-	if (best_val != INT_MAX)
-		return selector;
-	else
-		return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
-
-/**
- * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list
- *
- * @rdev: Regulator to operate on
- * @min_uV: Lower bound for voltage
- * @max_uV: Upper bound for voltage
- *
- * Drivers that have ascendant voltage list can use this as their
- * map_voltage() operation.
- */
-int regulator_map_voltage_ascend(struct regulator_dev *rdev,
-				 int min_uV, int max_uV)
-{
-	int i, ret;
-
-	for (i = 0; i < rdev->desc->n_voltages; i++) {
-		ret = rdev->desc->ops->list_voltage(rdev, i);
-		if (ret < 0)
-			continue;
-
-		if (ret > max_uV)
-			break;
-
-		if (ret >= min_uV && ret <= max_uV)
-			return i;
-	}
-
-	return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend);
-
-/**
- * regulator_map_voltage_linear - map_voltage() for simple linear mappings
- *
- * @rdev: Regulator to operate on
- * @min_uV: Lower bound for voltage
- * @max_uV: Upper bound for voltage
- *
- * Drivers providing min_uV and uV_step in their regulator_desc can
- * use this as their map_voltage() operation.
- */
-int regulator_map_voltage_linear(struct regulator_dev *rdev,
-				 int min_uV, int max_uV)
-{
-	int ret, voltage;
-
-	/* Allow uV_step to be 0 for fixed voltage */
-	if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
-		if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
-			return 0;
-		else
-			return -EINVAL;
-	}
-
-	if (!rdev->desc->uV_step) {
-		BUG_ON(!rdev->desc->uV_step);
-		return -EINVAL;
-	}
-
-	if (min_uV < rdev->desc->min_uV)
-		min_uV = rdev->desc->min_uV;
-
-	ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
-	if (ret < 0)
-		return ret;
-
-	ret += rdev->desc->linear_min_sel;
-
-	/* Map back into a voltage to verify we're still in bounds */
-	voltage = rdev->desc->ops->list_voltage(rdev, ret);
-	if (voltage < min_uV || voltage > max_uV)
-		return -EINVAL;
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
-
 static int _regulator_do_set_voltage(struct regulator_dev *rdev,
 				     int min_uV, int max_uV)
 {
@@ -2438,8 +2242,8 @@
 	}
 
 	/* Call set_voltage_time_sel if successfully obtained old_selector */
-	if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 &&
-	    old_selector != selector && rdev->desc->ops->set_voltage_time_sel) {
+	if (ret == 0 && !rdev->constraints->ramp_disable && old_selector >= 0
+		&& old_selector != selector) {
 
 		delay = rdev->desc->ops->set_voltage_time_sel(rdev,
 						old_selector, selector);
@@ -2971,47 +2775,6 @@
 EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
 
 /**
- * regulator_set_bypass_regmap - Default set_bypass() using regmap
- *
- * @rdev: device to operate on.
- * @enable: state to set.
- */
-int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
-{
-	unsigned int val;
-
-	if (enable)
-		val = rdev->desc->bypass_mask;
-	else
-		val = 0;
-
-	return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
-				  rdev->desc->bypass_mask, val);
-}
-EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
-
-/**
- * regulator_get_bypass_regmap - Default get_bypass() using regmap
- *
- * @rdev: device to operate on.
- * @enable: current state.
- */
-int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
-{
-	unsigned int val;
-	int ret;
-
-	ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
-	if (ret != 0)
-		return ret;
-
-	*enable = val & rdev->desc->bypass_mask;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
-
-/**
  * regulator_allow_bypass - allow the regulator to go into bypass mode
  *
  * @regulator: Regulator to configure
@@ -3740,8 +3503,11 @@
 	if (rdev == NULL)
 		return;
 
-	if (rdev->supply)
+	if (rdev->supply) {
+		while (rdev->use_count--)
+			regulator_disable(rdev->supply);
 		regulator_put(rdev->supply);
+	}
 	mutex_lock(&regulator_list_mutex);
 	debugfs_remove_recursive(rdev->debugfs);
 	flush_work(&rdev->disable_work.work);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 2afa573..f06854c 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -252,39 +252,12 @@
 	return ret;
 }
 
-static int da9034_map_ldo12_voltage(struct regulator_dev *rdev,
-				    int min_uV, int max_uV)
-{
-	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
-	int sel;
-
-	if (check_range(info, min_uV, max_uV)) {
-		pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	sel = DIV_ROUND_UP(min_uV - info->desc.min_uV, info->desc.uV_step);
-	sel = (sel >= 20) ? sel - 12 : ((sel > 7) ? 8 : sel);
-
-	return sel;
-}
-
-static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
-				     unsigned selector)
-{
-	struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
-	int volt;
-
-	if (selector >= 8)
-		volt = 2700000 + rdev->desc->uV_step * (selector - 8);
-	else
-		volt = rdev->desc->min_uV + rdev->desc->uV_step * selector;
-
-	if (volt > info->max_uV)
-		return -EINVAL;
-
-	return volt;
-}
+static const struct regulator_linear_range da9034_ldo12_ranges[] = {
+	{ .min_uV = 1700000, .max_uV = 2050000, .min_sel =  0, .max_sel = 7,
+	  .uV_step =  50000 },
+	{ .min_uV = 2700000, .max_uV = 3050000, .min_sel =  8, .max_sel = 15,
+	  .uV_step =  50000 },
+};
 
 static struct regulator_ops da903x_regulator_ldo_ops = {
 	.set_voltage_sel = da903x_set_voltage_sel,
@@ -332,8 +305,8 @@
 static struct regulator_ops da9034_regulator_ldo12_ops = {
 	.set_voltage_sel = da903x_set_voltage_sel,
 	.get_voltage_sel = da903x_get_voltage_sel,
-	.list_voltage	= da9034_list_ldo12_voltage,
-	.map_voltage	= da9034_map_ldo12_voltage,
+	.list_voltage	= regulator_list_voltage_linear_range,
+	.map_voltage	= regulator_map_voltage_linear_range,
 	.enable		= da903x_enable,
 	.disable	= da903x_disable,
 	.is_enabled	= da903x_is_enabled,
@@ -476,6 +449,8 @@
 	if (ri->desc.id == DA9034_ID_LDO12) {
 		ri->desc.ops = &da9034_regulator_ldo12_ops;
 		ri->desc.n_voltages = 16;
+		ri->desc.linear_ranges = da9034_ldo12_ranges;
+		ri->desc.n_linear_ranges = ARRAY_SIZE(da9034_ldo12_ranges);
 	}
 
 	if (ri->desc.id == DA9030_ID_LDO14)
@@ -485,7 +460,7 @@
 		ri->desc.ops = &da9030_regulator_ldo1_15_ops;
 
 	config.dev = &pdev->dev;
-	config.init_data = pdev->dev.platform_data;
+	config.init_data = dev_get_platdata(&pdev->dev);
 	config.driver_data = ri;
 
 	rdev = regulator_register(&ri->desc, &config);
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 96b569a..1e4d483 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -349,7 +349,7 @@
 		return -ENOMEM;
 
 	da9052 = dev_get_drvdata(pdev->dev.parent);
-	pdata = da9052->dev->platform_data;
+	pdata = dev_get_platdata(da9052->dev);
 	regulator->da9052 = da9052;
 
 	regulator->info = find_regulator_info(regulator->da9052->chip_id,
diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c
index 3022109..77b53e5 100644
--- a/drivers/regulator/da9055-regulator.c
+++ b/drivers/regulator/da9055-regulator.c
@@ -535,7 +535,7 @@
 	struct regulator_config config = { };
 	struct da9055_regulator *regulator;
 	struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
-	struct da9055_pdata *pdata = da9055->dev->platform_data;
+	struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
 	int ret, irq;
 
 	if (pdata == NULL || pdata->regulators[pdev->id] == NULL)
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
new file mode 100644
index 0000000..1a78163
--- /dev/null
+++ b/drivers/regulator/da9063-regulator.c
@@ -0,0 +1,934 @@
+/*
+ * Regulator driver for DA9063 PMIC series
+ *
+ * Copyright 2012 Dialog Semiconductors Ltd.
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+#include <linux/mfd/da9063/registers.h>
+
+
+/* Definition for registering regmap bit fields using a mask */
+#define BFIELD(_reg, _mask) \
+	REG_FIELD(_reg, __builtin_ffs((int)_mask) - 1, \
+		sizeof(unsigned int) * 8 - __builtin_clz((_mask)) - 1)
+
+/* Regulator capabilities and registers description */
+struct da9063_regulator_info {
+	struct regulator_desc desc;
+
+	/* Current limiting */
+	unsigned	n_current_limits;
+	const int	*current_limits;
+
+	/* DA9063 main register fields */
+	struct reg_field mode;		/* buck mode of operation */
+	struct reg_field suspend;
+	struct reg_field sleep;
+	struct reg_field suspend_sleep;
+	unsigned int suspend_vsel_reg;
+	struct reg_field ilimit;
+
+	/* DA9063 event detection bit */
+	struct reg_field oc_event;
+};
+
+/* Macros for LDO */
+#define DA9063_LDO(chip, regl_name, min_mV, step_mV, max_mV) \
+	.desc.id = chip##_ID_##regl_name, \
+	.desc.name = __stringify(chip##_##regl_name), \
+	.desc.ops = &da9063_ldo_ops, \
+	.desc.min_uV = (min_mV) * 1000, \
+	.desc.uV_step = (step_mV) * 1000, \
+	.desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \
+	.desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
+	.desc.enable_mask = DA9063_LDO_EN, \
+	.desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
+	.desc.vsel_mask = DA9063_V##regl_name##_MASK, \
+	.desc.linear_min_sel = DA9063_V##regl_name##_BIAS, \
+	.sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_LDO_SL), \
+	.suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_LDO_SL), \
+	.suspend_vsel_reg = DA9063_REG_V##regl_name##_B
+
+/* Macros for voltage DC/DC converters (BUCKs) */
+#define DA9063_BUCK(chip, regl_name, min_mV, step_mV, max_mV, limits_array) \
+	.desc.id = chip##_ID_##regl_name, \
+	.desc.name = __stringify(chip##_##regl_name), \
+	.desc.ops = &da9063_buck_ops, \
+	.desc.min_uV = (min_mV) * 1000, \
+	.desc.uV_step = (step_mV) * 1000, \
+	.desc.n_voltages = ((max_mV) - (min_mV))/(step_mV) + 1, \
+	.current_limits = limits_array, \
+	.n_current_limits = ARRAY_SIZE(limits_array)
+
+#define DA9063_BUCK_COMMON_FIELDS(regl_name) \
+	.desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
+	.desc.enable_mask = DA9063_BUCK_EN, \
+	.desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
+	.desc.vsel_mask = DA9063_VBUCK_MASK, \
+	.desc.linear_min_sel = DA9063_VBUCK_BIAS, \
+	.sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_BUCK_SL), \
+	.suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_BUCK_SL), \
+	.suspend_vsel_reg = DA9063_REG_V##regl_name##_B, \
+	.mode = BFIELD(DA9063_REG_##regl_name##_CFG, DA9063_BUCK_MODE_MASK)
+
+/* Defines asignment of regulators info table to chip model */
+struct da9063_dev_model {
+	const struct da9063_regulator_info	*regulator_info;
+	unsigned				n_regulators;
+	unsigned				dev_model;
+};
+
+/* Single regulator settings */
+struct da9063_regulator {
+	struct regulator_desc			desc;
+	struct regulator_dev			*rdev;
+	struct da9063				*hw;
+	const struct da9063_regulator_info	*info;
+
+	struct regmap_field			*mode;
+	struct regmap_field			*suspend;
+	struct regmap_field			*sleep;
+	struct regmap_field			*suspend_sleep;
+	struct regmap_field			*ilimit;
+};
+
+/* Encapsulates all information for the regulators driver */
+struct da9063_regulators {
+	int					irq_ldo_lim;
+	int					irq_uvov;
+
+	unsigned				n_regulators;
+	/* Array size to be defined during init. Keep at end. */
+	struct da9063_regulator			regulator[0];
+};
+
+/* BUCK modes for DA9063 */
+enum {
+	BUCK_MODE_MANUAL,	/* 0 */
+	BUCK_MODE_SLEEP,	/* 1 */
+	BUCK_MODE_SYNC,		/* 2 */
+	BUCK_MODE_AUTO		/* 3 */
+};
+
+/* Regulator operations */
+
+/* Current limits array (in uA) for BCORE1, BCORE2, BPRO.
+   Entry indexes corresponds to register values. */
+static const int da9063_buck_a_limits[] = {
+	 500000,  600000,  700000,  800000,  900000, 1000000, 1100000, 1200000,
+	1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000
+};
+
+/* Current limits array (in uA) for BMEM, BIO, BPERI.
+   Entry indexes corresponds to register values. */
+static const int da9063_buck_b_limits[] = {
+	1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000,
+	2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000
+};
+
+/* Current limits array (in uA) for merged BCORE1 and BCORE2.
+   Entry indexes corresponds to register values. */
+static const int da9063_bcores_merged_limits[] = {
+	1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2200000, 2400000,
+	2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000
+};
+
+/* Current limits array (in uA) for merged BMEM and BIO.
+   Entry indexes corresponds to register values. */
+static const int da9063_bmem_bio_merged_limits[] = {
+	3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000,
+	4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000
+};
+
+static int da9063_set_current_limit(struct regulator_dev *rdev,
+							int min_uA, int max_uA)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	const struct da9063_regulator_info *rinfo = regl->info;
+	int n, tval;
+
+	for (n = 0; n < rinfo->n_current_limits; n++) {
+		tval = rinfo->current_limits[n];
+		if (tval >= min_uA && tval <= max_uA)
+			return regmap_field_write(regl->ilimit, n);
+	}
+
+	return -EINVAL;
+}
+
+static int da9063_get_current_limit(struct regulator_dev *rdev)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	const struct da9063_regulator_info *rinfo = regl->info;
+	unsigned int sel;
+	int ret;
+
+	ret = regmap_field_read(regl->ilimit, &sel);
+	if (ret < 0)
+		return ret;
+
+	if (sel >= rinfo->n_current_limits)
+		sel = rinfo->n_current_limits - 1;
+
+	return rinfo->current_limits[sel];
+}
+
+static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	unsigned val;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		val = BUCK_MODE_SYNC;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = BUCK_MODE_AUTO;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val = BUCK_MODE_SLEEP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_field_write(regl->mode, val);
+}
+
+/*
+ * Bucks use single mode register field for normal operation
+ * and suspend state.
+ * There are 3 modes to map to: FAST, NORMAL, and STANDBY.
+ */
+
+static unsigned da9063_buck_get_mode(struct regulator_dev *rdev)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	struct regmap_field *field;
+	unsigned int val, mode = 0;
+	int ret;
+
+	ret = regmap_field_read(regl->mode, &val);
+	if (ret < 0)
+		return ret;
+
+	switch (val) {
+	default:
+	case BUCK_MODE_MANUAL:
+		mode = REGULATOR_MODE_FAST | REGULATOR_MODE_STANDBY;
+		/* Sleep flag bit decides the mode */
+		break;
+	case BUCK_MODE_SLEEP:
+		return REGULATOR_MODE_STANDBY;
+	case BUCK_MODE_SYNC:
+		return REGULATOR_MODE_FAST;
+	case BUCK_MODE_AUTO:
+		return REGULATOR_MODE_NORMAL;
+	}
+
+	/* Detect current regulator state */
+	ret = regmap_field_read(regl->suspend, &val);
+	if (ret < 0)
+		return 0;
+
+	/* Read regulator mode from proper register, depending on state */
+	if (val)
+		field = regl->suspend_sleep;
+	else
+		field = regl->sleep;
+
+	ret = regmap_field_read(field, &val);
+	if (ret < 0)
+		return 0;
+
+	if (val)
+		mode &= REGULATOR_MODE_STANDBY;
+	else
+		mode &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST;
+
+	return mode;
+}
+
+/*
+ * LDOs use sleep flags - one for normal and one for suspend state.
+ * There are 2 modes to map to: NORMAL and STANDBY (sleep) for each state.
+ */
+
+static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	unsigned val;
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_field_write(regl->sleep, val);
+}
+
+static unsigned da9063_ldo_get_mode(struct regulator_dev *rdev)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	struct regmap_field *field;
+	int ret, val;
+
+	/* Detect current regulator state */
+	ret = regmap_field_read(regl->suspend, &val);
+	if (ret < 0)
+		return 0;
+
+	/* Read regulator mode from proper register, depending on state */
+	if (val)
+		field = regl->suspend_sleep;
+	else
+		field = regl->sleep;
+
+	ret = regmap_field_read(field, &val);
+	if (ret < 0)
+		return 0;
+
+	if (val)
+		return REGULATOR_MODE_STANDBY;
+	else
+		return REGULATOR_MODE_NORMAL;
+}
+
+static int da9063_buck_get_status(struct regulator_dev *rdev)
+{
+	int ret = regulator_is_enabled_regmap(rdev);
+
+	if (ret == 0) {
+		ret = REGULATOR_STATUS_OFF;
+	} else if (ret > 0) {
+		ret = da9063_buck_get_mode(rdev);
+		if (ret > 0)
+			ret = regulator_mode_to_status(ret);
+		else if (ret == 0)
+			ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int da9063_ldo_get_status(struct regulator_dev *rdev)
+{
+	int ret = regulator_is_enabled_regmap(rdev);
+
+	if (ret == 0) {
+		ret = REGULATOR_STATUS_OFF;
+	} else if (ret > 0) {
+		ret = da9063_ldo_get_mode(rdev);
+		if (ret > 0)
+			ret = regulator_mode_to_status(ret);
+		else if (ret == 0)
+			ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int da9063_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	const struct da9063_regulator_info *rinfo = regl->info;
+	int ret, sel;
+
+	sel = regulator_map_voltage_linear(rdev, uV, uV);
+	if (sel < 0)
+		return -EINVAL;
+
+	sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+	ret = regmap_update_bits(regl->hw->regmap, rinfo->suspend_vsel_reg,
+				 rdev->desc->vsel_mask, sel);
+
+	return ret;
+}
+
+static int da9063_suspend_enable(struct regulator_dev *rdev)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+
+	return regmap_field_write(regl->suspend, 1);
+}
+
+static int da9063_suspend_disable(struct regulator_dev *rdev)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+
+	return regmap_field_write(regl->suspend, 0);
+}
+
+static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	int val;
+
+	switch (mode) {
+	case REGULATOR_MODE_FAST:
+		val = BUCK_MODE_SYNC;
+		break;
+	case REGULATOR_MODE_NORMAL:
+		val = BUCK_MODE_AUTO;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val = BUCK_MODE_SLEEP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_field_write(regl->mode, val);
+}
+
+static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode)
+{
+	struct da9063_regulator *regl = rdev_get_drvdata(rdev);
+	unsigned val;
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		val = 0;
+		break;
+	case REGULATOR_MODE_STANDBY:
+		val = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_field_write(regl->suspend_sleep, val);
+}
+
+static struct regulator_ops da9063_buck_ops = {
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.list_voltage		= regulator_list_voltage_linear,
+	.set_current_limit	= da9063_set_current_limit,
+	.get_current_limit	= da9063_get_current_limit,
+	.set_mode		= da9063_buck_set_mode,
+	.get_mode		= da9063_buck_get_mode,
+	.get_status		= da9063_buck_get_status,
+	.set_suspend_voltage	= da9063_set_suspend_voltage,
+	.set_suspend_enable	= da9063_suspend_enable,
+	.set_suspend_disable	= da9063_suspend_disable,
+	.set_suspend_mode	= da9063_buck_set_suspend_mode,
+};
+
+static struct regulator_ops da9063_ldo_ops = {
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
+	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
+	.list_voltage		= regulator_list_voltage_linear,
+	.set_mode		= da9063_ldo_set_mode,
+	.get_mode		= da9063_ldo_get_mode,
+	.get_status		= da9063_ldo_get_status,
+	.set_suspend_voltage	= da9063_set_suspend_voltage,
+	.set_suspend_enable	= da9063_suspend_enable,
+	.set_suspend_disable	= da9063_suspend_disable,
+	.set_suspend_mode	= da9063_ldo_set_suspend_mode,
+};
+
+/* Info of regulators for DA9063 */
+static const struct da9063_regulator_info da9063_regulator_info[] = {
+	{
+		DA9063_BUCK(DA9063, BCORE1, 300, 10, 1570,
+			    da9063_buck_a_limits),
+		DA9063_BUCK_COMMON_FIELDS(BCORE1),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C,
+				 DA9063_BCORE1_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BCORE2, 300, 10, 1570,
+			    da9063_buck_a_limits),
+		DA9063_BUCK_COMMON_FIELDS(BCORE2),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE2_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C,
+				 DA9063_BCORE2_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BPRO, 530, 10, 1800,
+			    da9063_buck_a_limits),
+		DA9063_BUCK_COMMON_FIELDS(BPRO),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPRO_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_B,
+				 DA9063_BPRO_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BMEM, 800, 20, 3340,
+			    da9063_buck_b_limits),
+		DA9063_BUCK_COMMON_FIELDS(BMEM),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A,
+				 DA9063_BMEM_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BIO, 800, 20, 3340,
+			    da9063_buck_b_limits),
+		DA9063_BUCK_COMMON_FIELDS(BIO),
+		.suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VBIO_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A,
+				 DA9063_BIO_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BPERI, 800, 20, 3340,
+			    da9063_buck_b_limits),
+		DA9063_BUCK_COMMON_FIELDS(BPERI),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPERI_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_B,
+				 DA9063_BPERI_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BCORES_MERGED, 300, 10, 1570,
+			    da9063_bcores_merged_limits),
+		/* BCORES_MERGED uses the same register fields as BCORE1 */
+		DA9063_BUCK_COMMON_FIELDS(BCORE1),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_C,
+				 DA9063_BCORE1_ILIM_MASK),
+	},
+	{
+		DA9063_BUCK(DA9063, BMEM_BIO_MERGED, 800, 20, 3340,
+			    da9063_bmem_bio_merged_limits),
+		/* BMEM_BIO_MERGED uses the same register fields as BMEM */
+		DA9063_BUCK_COMMON_FIELDS(BMEM),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL),
+		.ilimit = BFIELD(DA9063_REG_BUCK_ILIM_A,
+				 DA9063_BMEM_ILIM_MASK),
+	},
+	{
+		DA9063_LDO(DA9063, LDO1, 600, 20, 1860),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO1_SEL),
+	},
+	{
+		DA9063_LDO(DA9063, LDO2, 600, 20, 1860),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO2_SEL),
+	},
+	{
+		DA9063_LDO(DA9063, LDO3, 900, 20, 3440),
+		.suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO3_SEL),
+		.oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO3_LIM),
+	},
+	{
+		DA9063_LDO(DA9063, LDO4, 900, 20, 3440),
+		.suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VLDO4_SEL),
+		.oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO4_LIM),
+	},
+	{
+		DA9063_LDO(DA9063, LDO5, 900, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO5_CONT, DA9063_VLDO5_SEL),
+	},
+	{
+		DA9063_LDO(DA9063, LDO6, 900, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO6_CONT, DA9063_VLDO6_SEL),
+	},
+	{
+		DA9063_LDO(DA9063, LDO7, 900, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO7_CONT, DA9063_VLDO7_SEL),
+		.oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO7_LIM),
+	},
+	{
+		DA9063_LDO(DA9063, LDO8, 900, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO8_CONT, DA9063_VLDO8_SEL),
+		.oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO8_LIM),
+	},
+	{
+		DA9063_LDO(DA9063, LDO9, 950, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO9_CONT, DA9063_VLDO9_SEL),
+	},
+	{
+		DA9063_LDO(DA9063, LDO10, 900, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO10_CONT, DA9063_VLDO10_SEL),
+	},
+	{
+		DA9063_LDO(DA9063, LDO11, 900, 50, 3600),
+		.suspend = BFIELD(DA9063_REG_LDO11_CONT, DA9063_VLDO11_SEL),
+		.oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO11_LIM),
+	},
+};
+
+/* Link chip model with regulators info table */
+static struct da9063_dev_model regulators_models[] = {
+	{
+		.regulator_info = da9063_regulator_info,
+		.n_regulators = ARRAY_SIZE(da9063_regulator_info),
+		.dev_model = PMIC_DA9063,
+	},
+	{ }
+};
+
+/* Regulator interrupt handlers */
+static irqreturn_t da9063_ldo_lim_event(int irq, void *data)
+{
+	struct da9063_regulators *regulators = data;
+	struct da9063 *hw = regulators->regulator[0].hw;
+	struct da9063_regulator *regl;
+	int bits, i , ret;
+
+	ret = regmap_read(hw->regmap, DA9063_REG_STATUS_D, &bits);
+	if (ret < 0)
+		return IRQ_NONE;
+
+	for (i = regulators->n_regulators - 1; i >= 0; i--) {
+		regl = &regulators->regulator[i];
+		if (regl->info->oc_event.reg != DA9063_REG_STATUS_D)
+			continue;
+
+		if (BIT(regl->info->oc_event.lsb) & bits)
+			regulator_notifier_call_chain(regl->rdev,
+					REGULATOR_EVENT_OVER_CURRENT, NULL);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Probing and Initialisation functions
+ */
+static const struct regulator_init_data *da9063_get_regulator_initdata(
+		const struct da9063_regulators_pdata *regl_pdata, int id)
+{
+	int i;
+
+	for (i = 0; i < regl_pdata->n_regulators; i++) {
+		if (id == regl_pdata->regulator_data[i].id)
+			return regl_pdata->regulator_data[i].initdata;
+	}
+
+	return NULL;
+}
+
+#ifdef CONFIG_OF
+static struct of_regulator_match da9063_matches[] = {
+	[DA9063_ID_BCORE1]           = { .name = "bcore1"           },
+	[DA9063_ID_BCORE2]           = { .name = "bcore2"           },
+	[DA9063_ID_BPRO]             = { .name = "bpro",            },
+	[DA9063_ID_BMEM]             = { .name = "bmem",            },
+	[DA9063_ID_BIO]              = { .name = "bio",             },
+	[DA9063_ID_BPERI]            = { .name = "bperi",           },
+	[DA9063_ID_BCORES_MERGED]    = { .name = "bcores-merged"    },
+	[DA9063_ID_BMEM_BIO_MERGED]  = { .name = "bmem-bio-merged", },
+	[DA9063_ID_LDO1]             = { .name = "ldo1",            },
+	[DA9063_ID_LDO2]             = { .name = "ldo2",            },
+	[DA9063_ID_LDO3]             = { .name = "ldo3",            },
+	[DA9063_ID_LDO4]             = { .name = "ldo4",            },
+	[DA9063_ID_LDO5]             = { .name = "ldo5",            },
+	[DA9063_ID_LDO6]             = { .name = "ldo6",            },
+	[DA9063_ID_LDO7]             = { .name = "ldo7",            },
+	[DA9063_ID_LDO8]             = { .name = "ldo8",            },
+	[DA9063_ID_LDO9]             = { .name = "ldo9",            },
+	[DA9063_ID_LDO10]            = { .name = "ldo10",           },
+	[DA9063_ID_LDO11]            = { .name = "ldo11",           },
+};
+
+static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
+		struct platform_device *pdev,
+		struct of_regulator_match **da9063_reg_matches)
+{
+	struct da9063_regulators_pdata *pdata;
+	struct da9063_regulator_data *rdata;
+	struct device_node *node;
+	int i, n, num;
+
+	node = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
+	if (!node) {
+		dev_err(&pdev->dev, "Regulators device node not found\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	num = of_regulator_match(&pdev->dev, node, da9063_matches,
+				 ARRAY_SIZE(da9063_matches));
+	if (num < 0) {
+		dev_err(&pdev->dev, "Failed to match regulators\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->regulator_data = devm_kzalloc(&pdev->dev,
+					num * sizeof(*pdata->regulator_data),
+					GFP_KERNEL);
+	if (!pdata->regulator_data)
+		return ERR_PTR(-ENOMEM);
+	pdata->n_regulators = num;
+
+	n = 0;
+	for (i = 0; i < ARRAY_SIZE(da9063_matches); i++) {
+		if (!da9063_matches[i].init_data)
+			continue;
+
+		rdata = &pdata->regulator_data[n];
+		rdata->id = i;
+		rdata->initdata = da9063_matches[i].init_data;
+
+		n++;
+	};
+
+	*da9063_reg_matches = da9063_matches;
+	return pdata;
+}
+#else
+static struct da9063_regulators_pdata *da9063_parse_regulators_dt(
+		struct platform_device *pdev,
+		struct of_regulator_match **da9063_reg_matches)
+{
+	da9063_reg_matches = NULL;
+	return PTR_ERR(-ENODEV);
+}
+#endif
+
+static int da9063_regulator_probe(struct platform_device *pdev)
+{
+	struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
+	struct da9063_pdata *da9063_pdata = dev_get_platdata(da9063->dev);
+	struct of_regulator_match *da9063_reg_matches;
+	struct da9063_regulators_pdata *regl_pdata;
+	const struct da9063_dev_model *model;
+	struct da9063_regulators *regulators;
+	struct da9063_regulator *regl;
+	struct regulator_config config;
+	bool bcores_merged, bmem_bio_merged;
+	int id, irq, n, n_regulators, ret, val;
+	size_t size;
+
+	regl_pdata = da9063_pdata ? da9063_pdata->regulators_pdata : NULL;
+
+	if (!regl_pdata)
+		regl_pdata = da9063_parse_regulators_dt(pdev,
+							&da9063_reg_matches);
+
+	if (IS_ERR(regl_pdata) || regl_pdata->n_regulators == 0) {
+		dev_err(&pdev->dev,
+			"No regulators defined for the platform\n");
+		return PTR_ERR(regl_pdata);
+	}
+
+	/* Find regulators set for particular device model */
+	for (model = regulators_models; model->regulator_info; model++) {
+		if (model->dev_model == da9063->model)
+			break;
+	}
+	if (!model->regulator_info) {
+		dev_err(&pdev->dev, "Chip model not recognised (%u)\n",
+			da9063->model);
+		return -ENODEV;
+	}
+
+	ret = regmap_read(da9063->regmap, DA9063_REG_CONFIG_H, &val);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"Error while reading BUCKs configuration\n");
+		return -EIO;
+	}
+	bcores_merged = val & DA9063_BCORE_MERGE;
+	bmem_bio_merged = val & DA9063_BUCK_MERGE;
+
+	n_regulators = model->n_regulators;
+	if (bcores_merged)
+		n_regulators -= 2; /* remove BCORE1, BCORE2 */
+	else
+		n_regulators--;    /* remove BCORES_MERGED */
+	if (bmem_bio_merged)
+		n_regulators -= 2; /* remove BMEM, BIO */
+	else
+		n_regulators--;    /* remove BMEM_BIO_MERGED */
+
+	/* Allocate memory required by usable regulators */
+	size = sizeof(struct da9063_regulators) +
+		n_regulators * sizeof(struct da9063_regulator);
+	regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+	if (!regulators) {
+		dev_err(&pdev->dev, "No memory for regulators\n");
+		return -ENOMEM;
+	}
+
+	regulators->n_regulators = n_regulators;
+	platform_set_drvdata(pdev, regulators);
+
+	/* Register all regulators declared in platform information */
+	n = 0;
+	id = 0;
+	while (n < regulators->n_regulators) {
+		/* Skip regulator IDs depending on merge mode configuration */
+		switch (id) {
+		case DA9063_ID_BCORE1:
+		case DA9063_ID_BCORE2:
+			if (bcores_merged) {
+				id++;
+				continue;
+			}
+			break;
+		case DA9063_ID_BMEM:
+		case DA9063_ID_BIO:
+			if (bmem_bio_merged) {
+				id++;
+				continue;
+			}
+			break;
+		case DA9063_ID_BCORES_MERGED:
+			if (!bcores_merged) {
+				id++;
+				continue;
+			}
+			break;
+		case DA9063_ID_BMEM_BIO_MERGED:
+			if (!bmem_bio_merged) {
+				id++;
+				continue;
+			}
+			break;
+		}
+
+		/* Initialise regulator structure */
+		regl = &regulators->regulator[n];
+		regl->hw = da9063;
+		regl->info = &model->regulator_info[id];
+		regl->desc = regl->info->desc;
+		regl->desc.type = REGULATOR_VOLTAGE;
+		regl->desc.owner = THIS_MODULE;
+
+		if (regl->info->mode.reg)
+			regl->mode = devm_regmap_field_alloc(&pdev->dev,
+					da9063->regmap, regl->info->mode);
+		if (regl->info->suspend.reg)
+			regl->suspend = devm_regmap_field_alloc(&pdev->dev,
+					da9063->regmap, regl->info->suspend);
+		if (regl->info->sleep.reg)
+			regl->sleep = devm_regmap_field_alloc(&pdev->dev,
+					da9063->regmap, regl->info->sleep);
+		if (regl->info->suspend_sleep.reg)
+			regl->suspend_sleep = devm_regmap_field_alloc(&pdev->dev,
+					da9063->regmap, regl->info->suspend_sleep);
+		if (regl->info->ilimit.reg)
+			regl->ilimit = devm_regmap_field_alloc(&pdev->dev,
+					da9063->regmap, regl->info->ilimit);
+
+		/* Register regulator */
+		memset(&config, 0, sizeof(config));
+		config.dev = &pdev->dev;
+		config.init_data = da9063_get_regulator_initdata(regl_pdata, id);
+		config.driver_data = regl;
+		if (da9063_reg_matches)
+			config.of_node = da9063_reg_matches[id].of_node;
+		config.regmap = da9063->regmap;
+		regl->rdev = regulator_register(&regl->desc, &config);
+		if (IS_ERR(regl->rdev)) {
+			dev_err(&pdev->dev,
+				"Failed to register %s regulator\n",
+				regl->desc.name);
+			ret = PTR_ERR(regl->rdev);
+			goto err;
+		}
+		id++;
+		n++;
+	}
+
+	/* LDOs overcurrent event support */
+	irq = platform_get_irq_byname(pdev, "LDO_LIM");
+	if (irq < 0) {
+		ret = irq;
+		dev_err(&pdev->dev, "Failed to get IRQ.\n");
+		goto err;
+	}
+
+	regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq);
+	if (regulators->irq_ldo_lim >= 0) {
+		ret = request_threaded_irq(regulators->irq_ldo_lim,
+					   NULL, da9063_ldo_lim_event,
+					   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					   "LDO_LIM", regulators);
+		if (ret) {
+			dev_err(&pdev->dev,
+					"Failed to request LDO_LIM IRQ.\n");
+			regulators->irq_ldo_lim = -ENXIO;
+		}
+	}
+
+	return 0;
+
+err:
+	/* Wind back regulators registeration */
+	while (--n >= 0)
+		regulator_unregister(regulators->regulator[n].rdev);
+
+	return ret;
+}
+
+static int da9063_regulator_remove(struct platform_device *pdev)
+{
+	struct da9063_regulators *regulators = platform_get_drvdata(pdev);
+	struct da9063_regulator *regl;
+
+	free_irq(regulators->irq_ldo_lim, regulators);
+	free_irq(regulators->irq_uvov, regulators);
+
+	for (regl = &regulators->regulator[regulators->n_regulators - 1];
+	     regl >= &regulators->regulator[0]; regl--)
+		regulator_unregister(regl->rdev);
+
+	return 0;
+}
+
+static struct platform_driver da9063_regulator_driver = {
+	.driver = {
+		.name = DA9063_DRVNAME_REGULATORS,
+		.owner = THIS_MODULE,
+	},
+	.probe = da9063_regulator_probe,
+	.remove = da9063_regulator_remove,
+};
+
+static int __init da9063_regulator_init(void)
+{
+	return platform_driver_register(&da9063_regulator_driver);
+}
+subsys_initcall(da9063_regulator_init);
+
+static void __exit da9063_regulator_cleanup(void)
+{
+	platform_driver_unregister(&da9063_regulator_driver);
+}
+module_exit(da9063_regulator_cleanup);
+
+
+/* Module information */
+MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>");
+MODULE_DESCRIPTION("DA9063 regulators driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("paltform:" DA9063_DRVNAME_REGULATORS);
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
new file mode 100644
index 0000000..f0fe54b
--- /dev/null
+++ b/drivers/regulator/da9210-regulator.c
@@ -0,0 +1,196 @@
+/*
+ * da9210-regulator.c - Regulator device driver for DA9210
+ * Copyright (C) 2013  Dialog Semiconductor Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regmap.h>
+
+#include "da9210-regulator.h"
+
+struct da9210 {
+	struct regulator_dev *rdev;
+	struct regmap *regmap;
+};
+
+static const struct regmap_config da9210_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
+				    int max_uA);
+static int da9210_get_current_limit(struct regulator_dev *rdev);
+
+static struct regulator_ops da9210_buck_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+	.set_current_limit = da9210_set_current_limit,
+	.get_current_limit = da9210_get_current_limit,
+};
+
+/* Default limits measured in millivolts and milliamps */
+#define DA9210_MIN_MV		300
+#define DA9210_MAX_MV		1570
+#define DA9210_STEP_MV		10
+
+/* Current limits for buck (uA) indices corresponds with register values */
+static const int da9210_buck_limits[] = {
+	1600000, 1800000, 2000000, 2200000, 2400000, 2600000, 2800000, 3000000,
+	3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000
+};
+
+static const struct regulator_desc da9210_reg = {
+	.name = "DA9210",
+	.id = 0,
+	.ops = &da9210_buck_ops,
+	.type = REGULATOR_VOLTAGE,
+	.n_voltages = ((DA9210_MAX_MV - DA9210_MIN_MV) / DA9210_STEP_MV) + 1,
+	.min_uV = (DA9210_MIN_MV * 1000),
+	.uV_step = (DA9210_STEP_MV * 1000),
+	.vsel_reg = DA9210_REG_VBUCK_A,
+	.vsel_mask = DA9210_VBUCK_MASK,
+	.enable_reg = DA9210_REG_BUCK_CONT,
+	.enable_mask = DA9210_BUCK_EN,
+	.owner = THIS_MODULE,
+};
+
+static int da9210_set_current_limit(struct regulator_dev *rdev, int min_uA,
+				    int max_uA)
+{
+	struct da9210 *chip = rdev_get_drvdata(rdev);
+	unsigned int sel;
+	int i;
+
+	/* search for closest to maximum */
+	for (i = ARRAY_SIZE(da9210_buck_limits)-1; i >= 0; i--) {
+		if (min_uA <= da9210_buck_limits[i] &&
+		    max_uA >= da9210_buck_limits[i]) {
+			sel = i;
+			sel = sel << DA9210_BUCK_ILIM_SHIFT;
+			return regmap_update_bits(chip->regmap,
+						  DA9210_REG_BUCK_ILIM,
+						  DA9210_BUCK_ILIM_MASK, sel);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int da9210_get_current_limit(struct regulator_dev *rdev)
+{
+	struct da9210 *chip = rdev_get_drvdata(rdev);
+	unsigned int data;
+	unsigned int sel;
+	int ret;
+
+	ret = regmap_read(chip->regmap, DA9210_REG_BUCK_ILIM, &data);
+	if (ret < 0)
+		return ret;
+
+	/* select one of 16 values: 0000 (1600mA) to 1111 (4600mA) */
+	sel = (data & DA9210_BUCK_ILIM_MASK) >> DA9210_BUCK_ILIM_SHIFT;
+
+	return da9210_buck_limits[sel];
+}
+
+/*
+ * I2C driver interface functions
+ */
+static int da9210_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct da9210 *chip;
+	struct da9210_pdata *pdata = i2c->dev.platform_data;
+	struct regulator_dev *rdev = NULL;
+	struct regulator_config config = { };
+	int error;
+
+	chip = devm_kzalloc(&i2c->dev, sizeof(struct da9210), GFP_KERNEL);
+	if (NULL == chip) {
+		dev_err(&i2c->dev,
+			"Cannot kzalloc memory for regulator structure\n");
+		return -ENOMEM;
+	}
+
+	chip->regmap = devm_regmap_init_i2c(i2c, &da9210_regmap_config);
+	if (IS_ERR(chip->regmap)) {
+		error = PTR_ERR(chip->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			error);
+		return error;
+	}
+
+	config.dev = &i2c->dev;
+	if (pdata)
+		config.init_data = &pdata->da9210_constraints;
+	config.driver_data = chip;
+	config.regmap = chip->regmap;
+
+	rdev = regulator_register(&da9210_reg, &config);
+	if (IS_ERR(rdev)) {
+		dev_err(&i2c->dev, "Failed to register DA9210 regulator\n");
+		return PTR_ERR(rdev);
+	}
+
+	chip->rdev = rdev;
+
+	i2c_set_clientdata(i2c, chip);
+
+	return 0;
+}
+
+static int da9210_i2c_remove(struct i2c_client *i2c)
+{
+	struct da9210 *chip = i2c_get_clientdata(i2c);
+	regulator_unregister(chip->rdev);
+	return 0;
+}
+
+static const struct i2c_device_id da9210_i2c_id[] = {
+	{"da9210", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, da9210_i2c_id);
+
+static struct i2c_driver da9210_regulator_driver = {
+	.driver = {
+		.name = "da9210",
+		.owner = THIS_MODULE,
+	},
+	.probe = da9210_i2c_probe,
+	.remove = da9210_i2c_remove,
+	.id_table = da9210_i2c_id,
+};
+
+module_i2c_driver(da9210_regulator_driver);
+
+MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Regulator device driver for Dialog DA9210");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/da9210-regulator.h b/drivers/regulator/da9210-regulator.h
new file mode 100644
index 0000000..749c550
--- /dev/null
+++ b/drivers/regulator/da9210-regulator.h
@@ -0,0 +1,288 @@
+
+/*
+ * da9210-regulator.h - Regulator definitions for DA9210
+ * Copyright (C) 2013  Dialog Semiconductor Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __DA9210_REGISTERS_H__
+#define __DA9210_REGISTERS_H__
+
+struct da9210_pdata {
+	struct regulator_init_data da9210_constraints;
+};
+
+/* Page selection */
+#define	DA9210_REG_PAGE_CON			0x00
+
+/* System Control and Event Registers */
+#define	DA9210_REG_STATUS_A			0x50
+#define	DA9210_REG_STATUS_B			0x51
+#define	DA9210_REG_EVENT_A			0x52
+#define	DA9210_REG_EVENT_B			0x53
+#define	DA9210_REG_MASK_A			0x54
+#define	DA9210_REG_MASK_B			0x55
+#define	DA9210_REG_CONTROL_A			0x56
+
+/* GPIO Control Registers */
+#define	DA9210_REG_GPIO_0_1			0x58
+#define	DA9210_REG_GPIO_2_3			0x59
+#define	DA9210_REG_GPIO_4_5			0x5A
+#define	DA9210_REG_GPIO_6			0x5B
+
+/* Regulator Registers */
+#define	DA9210_REG_BUCK_CONT			0x5D
+#define	DA9210_REG_BUCK_ILIM			0xD0
+#define	DA9210_REG_BUCK_CONF1			0xD1
+#define	DA9210_REG_BUCK_CONF2			0xD2
+#define DA9210_REG_VBACK_AUTO			0xD4
+#define DA9210_REG_VBACK_BASE			0xD5
+#define DA9210_REG_VBACK_MAX_DVC_IF		0xD6
+#define DA9210_REG_VBACK_DVC			0xD7
+#define	DA9210_REG_VBUCK_A			0xD8
+#define	DA9210_REG_VBUCK_B			0xD9
+
+/* I2C Interface Settings */
+#define DA9210_REG_INTERFACE			0x105
+
+/* OTP */
+#define	DA9210_REG_OPT_COUNT			0x140
+#define	DA9210_REG_OPT_ADDR			0x141
+#define	DA9210_REG_OPT_DATA			0x142
+
+/* Customer Trim and Configuration */
+#define	DA9210_REG_CONFIG_A			0x143
+#define	DA9210_REG_CONFIG_B			0x144
+#define	DA9210_REG_CONFIG_C			0x145
+#define	DA9210_REG_CONFIG_D			0x146
+#define	DA9210_REG_CONFIG_E			0x147
+
+
+/*
+ * Registers bits
+ */
+/* DA9210_REG_PAGE_CON (addr=0x00) */
+#define	DA9210_PEG_PAGE_SHIFT			0
+#define	DA9210_REG_PAGE_MASK			0x0F
+/* On I2C registers 0x00 - 0xFF */
+#define	DA9210_REG_PAGE0			0
+/* On I2C registers 0x100 - 0x1FF */
+#define	DA9210_REG_PAGE2			2
+#define	DA9210_PAGE_WRITE_MODE			0x00
+#define	DA9210_REPEAT_WRITE_MODE		0x40
+#define	DA9210_PAGE_REVERT			0x80
+
+/* DA9210_REG_STATUS_A (addr=0x50) */
+#define	DA9210_GPI0				0x01
+#define	DA9210_GPI1				0x02
+#define	DA9210_GPI2				0x04
+#define	DA9210_GPI3				0x08
+#define	DA9210_GPI4				0x10
+#define	DA9210_GPI5				0x20
+#define	DA9210_GPI6				0x40
+
+/* DA9210_REG_EVENT_A (addr=0x52) */
+#define	DA9210_E_GPI0				0x01
+#define	DA9210_E_GPI1				0x02
+#define	DA9210_E_GPI2				0x04
+#define	DA9210_E_GPI3				0x08
+#define	DA9210_E_GPI4				0x10
+#define	DA9210_E_GPI5				0x20
+#define	DA9210_E_GPI6				0x40
+
+/* DA9210_REG_EVENT_B (addr=0x53) */
+#define	DA9210_E_OVCURR				0x01
+#define	DA9210_E_NPWRGOOD			0x02
+#define	DA9210_E_TEMP_WARN			0x04
+#define	DA9210_E_TEMP_CRIT			0x08
+#define	DA9210_E_VMAX				0x10
+
+/* DA9210_REG_MASK_A (addr=0x54) */
+#define	DA9210_M_GPI0				0x01
+#define	DA9210_M_GPI1				0x02
+#define	DA9210_M_GPI2				0x04
+#define	DA9210_M_GPI3				0x08
+#define	DA9210_M_GPI4				0x10
+#define	DA9210_M_GPI5				0x20
+#define	DA9210_M_GPI6				0x40
+
+/* DA9210_REG_MASK_B (addr=0x55) */
+#define	DA9210_M_OVCURR				0x01
+#define	DA9210_M_NPWRGOOD			0x02
+#define	DA9210_M_TEMP_WARN			0x04
+#define	DA9210_M_TEMP_CRIT			0x08
+#define	DA9210_M_VMAX				0x10
+
+/* DA9210_REG_CONTROL_A (addr=0x56) */
+#define	DA9210_DEBOUNCING_SHIFT			0
+#define	DA9210_DEBOUNCING_MASK			0x07
+#define	DA9210_SLEW_RATE_SHIFT			3
+#define	DA9210_SLEW_RATE_MASK			0x18
+#define	DA9210_V_LOCK				0x20
+
+/* DA9210_REG_GPIO_0_1 (addr=0x58) */
+#define	DA9210_GPIO0_PIN_SHIFT			0
+#define	DA9210_GPIO0_PIN_MASK			0x03
+#define		DA9210_GPIO0_PIN_GPI		0x00
+#define		DA9210_GPIO0_PIN_GPO_OD		0x02
+#define		DA9210_GPIO0_PIN_GPO		0x03
+#define	DA9210_GPIO0_TYPE			0x04
+#define		DA9210_GPIO0_TYPE_GPI		0x00
+#define		DA9210_GPIO0_TYPE_GPO		0x04
+#define	DA9210_GPIO0_MODE			0x08
+#define	DA9210_GPIO1_PIN_SHIFT			4
+#define	DA9210_GPIO1_PIN_MASK			0x30
+#define		DA9210_GPIO1_PIN_GPI		0x00
+#define		DA9210_GPIO1_PIN_VERROR		0x10
+#define		DA9210_GPIO1_PIN_GPO_OD		0x20
+#define		DA9210_GPIO1_PIN_GPO		0x30
+#define	DA9210_GPIO1_TYPE_SHIFT			0x40
+#define		DA9210_GPIO1_TYPE_GPI		0x00
+#define		DA9210_GPIO1_TYPE_GPO		0x40
+#define	DA9210_GPIO1_MODE			0x80
+
+/* DA9210_REG_GPIO_2_3 (addr=0x59) */
+#define	DA9210_GPIO2_PIN_SHIFT			0
+#define	DA9210_GPIO2_PIN_MASK			0x03
+#define		DA9210_GPIO2_PIN_GPI		0x00
+#define		DA9210_GPIO5_PIN_BUCK_CLK	0x10
+#define		DA9210_GPIO2_PIN_GPO_OD		0x02
+#define		DA9210_GPIO2_PIN_GPO		0x03
+#define	DA9210_GPIO2_TYPE			0x04
+#define		DA9210_GPIO2_TYPE_GPI		0x00
+#define		DA9210_GPIO2_TYPE_GPO		0x04
+#define	DA9210_GPIO2_MODE			0x08
+#define	DA9210_GPIO3_PIN_SHIFT			4
+#define	DA9210_GPIO3_PIN_MASK			0x30
+#define		DA9210_GPIO3_PIN_GPI		0x00
+#define		DA9210_GPIO3_PIN_IERROR		0x10
+#define		DA9210_GPIO3_PIN_GPO_OD		0x20
+#define		DA9210_GPIO3_PIN_GPO		0x30
+#define	DA9210_GPIO3_TYPE_SHIFT			0x40
+#define		DA9210_GPIO3_TYPE_GPI		0x00
+#define		DA9210_GPIO3_TYPE_GPO		0x40
+#define	DA9210_GPIO3_MODE			0x80
+
+/* DA9210_REG_GPIO_4_5 (addr=0x5A) */
+#define	DA9210_GPIO4_PIN_SHIFT			0
+#define	DA9210_GPIO4_PIN_MASK			0x03
+#define		DA9210_GPIO4_PIN_GPI		0x00
+#define		DA9210_GPIO4_PIN_GPO_OD		0x02
+#define		DA9210_GPIO4_PIN_GPO		0x03
+#define	DA9210_GPIO4_TYPE			0x04
+#define		DA9210_GPIO4_TYPE_GPI		0x00
+#define		DA9210_GPIO4_TYPE_GPO		0x04
+#define	DA9210_GPIO4_MODE			0x08
+#define	DA9210_GPIO5_PIN_SHIFT			4
+#define	DA9210_GPIO5_PIN_MASK			0x30
+#define		DA9210_GPIO5_PIN_GPI		0x00
+#define		DA9210_GPIO5_PIN_INTERFACE	0x01
+#define		DA9210_GPIO5_PIN_GPO_OD		0x20
+#define		DA9210_GPIO5_PIN_GPO		0x30
+#define	DA9210_GPIO5_TYPE_SHIFT			0x40
+#define		DA9210_GPIO5_TYPE_GPI		0x00
+#define		DA9210_GPIO5_TYPE_GPO		0x40
+#define	DA9210_GPIO5_MODE			0x80
+
+/* DA9210_REG_GPIO_6 (addr=0x5B) */
+#define	DA9210_GPIO6_PIN_SHIFT			0
+#define	DA9210_GPIO6_PIN_MASK			0x03
+#define		DA9210_GPIO6_PIN_GPI		0x00
+#define		DA9210_GPIO6_PIN_INTERFACE	0x01
+#define		DA9210_GPIO6_PIN_GPO_OD		0x02
+#define		DA9210_GPIO6_PIN_GPO		0x03
+#define	DA9210_GPIO6_TYPE			0x04
+#define		DA9210_GPIO6_TYPE_GPI		0x00
+#define		DA9210_GPIO6_TYPE_GPO		0x04
+#define	DA9210_GPIO6_MODE			0x08
+
+/* DA9210_REG_BUCK_CONT (addr=0x5D) */
+#define	DA9210_BUCK_EN				0x01
+#define	DA9210_BUCK_GPI_SHIFT			1
+#define DA9210_BUCK_GPI_MASK			0x06
+#define		DA9210_BUCK_GPI_OFF		0x00
+#define		DA9210_BUCK_GPI_GPIO0		0x02
+#define		DA9210_BUCK_GPI_GPIO3		0x04
+#define		DA9210_BUCK_GPI_GPIO4		0x06
+#define	DA9210_BUCK_PD_DIS			0x08
+#define	DA9210_VBUCK_SEL			0x10
+#define		DA9210_VBUCK_SEL_A		0x00
+#define		DA9210_VBUCK_SEL_B		0x10
+#define	DA9210_VBUCK_GPI_SHIFT			5
+#define	DA9210_VBUCK_GPI_MASK			0x60
+#define		DA9210_VBUCK_GPI_OFF		0x00
+#define		DA9210_VBUCK_GPI_GPIO0		0x20
+#define		DA9210_VBUCK_GPI_GPIO3		0x40
+#define		DA9210_VBUCK_GPI_GPIO4		0x60
+#define	DA9210_DVC_CTRL_EN			0x80
+
+/* DA9210_REG_BUCK_ILIM (addr=0xD0) */
+#define DA9210_BUCK_ILIM_SHIFT			0
+#define DA9210_BUCK_ILIM_MASK			0x0F
+#define DA9210_BUCK_IALARM			0x10
+
+/* DA9210_REG_BUCK_CONF1 (addr=0xD1) */
+#define DA9210_BUCK_MODE_SHIFT			0
+#define DA9210_BUCK_MODE_MASK			0x03
+#define		DA9210_BUCK_MODE_MANUAL		0x00
+#define		DA9210_BUCK_MODE_SLEEP		0x01
+#define		DA9210_BUCK_MODE_SYNC		0x02
+#define		DA9210_BUCK_MODE_AUTO		0x03
+#define DA9210_STARTUP_CTRL_SHIFT		2
+#define DA9210_STARTUP_CTRL_MASK		0x1C
+#define DA9210_PWR_DOWN_CTRL_SHIFT		5
+#define DA9210_PWR_DOWN_CTRL_MASK		0xE0
+
+/* DA9210_REG_BUCK_CONF2 (addr=0xD2) */
+#define DA9210_PHASE_SEL_SHIFT			0
+#define DA9210_PHASE_SEL_MASK			0x03
+#define DA9210_FREQ_SEL				0x40
+
+/* DA9210_REG_BUCK_AUTO (addr=0xD4) */
+#define DA9210_VBUCK_AUTO_SHIFT			0
+#define DA9210_VBUCK_AUTO_MASK			0x7F
+
+/* DA9210_REG_BUCK_BASE (addr=0xD5) */
+#define DA9210_VBUCK_BASE_SHIFT			0
+#define DA9210_VBUCK_BASE_MASK			0x7F
+
+/* DA9210_REG_VBUCK_MAX_DVC_IF (addr=0xD6) */
+#define DA9210_VBUCK_MAX_SHIFT			0
+#define DA9210_VBUCK_MAX_MASK			0x7F
+#define DA9210_DVC_STEP_SIZE			0x80
+#define		DA9210_DVC_STEP_SIZE_10MV	0x00
+#define		DA9210_DVC_STEP_SIZE_20MV	0x80
+
+/* DA9210_REG_VBUCK_DVC (addr=0xD7) */
+#define DA9210_VBUCK_DVC_SHIFT			0
+#define DA9210_VBUCK_DVC_MASK			0x7F
+
+/* DA9210_REG_VBUCK_A/B (addr=0xD8/0xD9) */
+#define DA9210_VBUCK_SHIFT			0
+#define DA9210_VBUCK_MASK			0x7F
+#define DA9210_VBUCK_BIAS			0
+#define DA9210_BUCK_SL				0x80
+
+/* DA9210_REG_INTERFACE (addr=0x105) */
+#define DA9210_IF_BASE_ADDR_SHIFT		4
+#define DA9210_IF_BASE_ADDR_MASK		0xF0
+
+/* DA9210_REG_CONFIG_E (addr=0x147) */
+#define DA9210_STAND_ALONE			0x01
+
+#endif	/* __DA9210_REGISTERS_H__ */
+
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index f0e1ae5..70b7220 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -219,7 +219,7 @@
 	rdesc->owner = THIS_MODULE;
 
 	di->rdev = regulator_register(&di->desc, config);
-	return PTR_RET(di->rdev);
+	return PTR_ERR_OR_ZERO(di->rdev);
 
 }
 
@@ -237,7 +237,7 @@
 	unsigned int val;
 	int ret;
 
-	pdata = client->dev.platform_data;
+	pdata = dev_get_platdata(&client->dev);
 	if (!pdata || !pdata->regulator) {
 		dev_err(&client->dev, "Platform data not found!\n");
 		return -ENODEV;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index e5c03b5..7610920 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -146,7 +146,7 @@
 		if (IS_ERR(config))
 			return PTR_ERR(config);
 	} else {
-		config = pdev->dev.platform_data;
+		config = dev_get_platdata(&pdev->dev);
 	}
 
 	if (!config)
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index 9d39eb4..98a98ff 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -219,7 +219,7 @@
 
 static int gpio_regulator_probe(struct platform_device *pdev)
 {
-	struct gpio_regulator_config *config = pdev->dev.platform_data;
+	struct gpio_regulator_config *config = dev_get_platdata(&pdev->dev);
 	struct device_node *np = pdev->dev.of_node;
 	struct gpio_regulator_data *drvdata;
 	struct regulator_config cfg = { };
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
new file mode 100644
index 0000000..6e30df1
--- /dev/null
+++ b/drivers/regulator/helpers.c
@@ -0,0 +1,447 @@
+/*
+ * helpers.c  --  Voltage/Current Regulator framework helper functions.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
+ *
+ *  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/kernel.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/module.h>
+
+/**
+ * regulator_is_enabled_regmap - standard is_enabled() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their is_enabled operation, saving some code.
+ */
+int regulator_is_enabled_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+	if (ret != 0)
+		return ret;
+
+	if (rdev->desc->enable_is_inverted)
+		return (val & rdev->desc->enable_mask) == 0;
+	else
+		return (val & rdev->desc->enable_mask) != 0;
+}
+EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
+
+/**
+ * regulator_enable_regmap - standard enable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their enable() operation, saving some code.
+ */
+int regulator_enable_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+
+	if (rdev->desc->enable_is_inverted)
+		val = 0;
+	else
+		val = rdev->desc->enable_mask;
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_enable_regmap);
+
+/**
+ * regulator_disable_regmap - standard disable() for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * enable_reg and enable_mask fields in their descriptor and then use
+ * this as their disable() operation, saving some code.
+ */
+int regulator_disable_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+
+	if (rdev->desc->enable_is_inverted)
+		val = rdev->desc->enable_mask;
+	else
+		val = 0;
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+				  rdev->desc->enable_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_disable_regmap);
+
+/**
+ * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their get_voltage_vsel operation, saving some code.
+ */
+int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+	if (ret != 0)
+		return ret;
+
+	val &= rdev->desc->vsel_mask;
+	val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap);
+
+/**
+ * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users
+ *
+ * @rdev: regulator to operate on
+ * @sel: Selector to set
+ *
+ * Regulators that use regmap for their register I/O can set the
+ * vsel_reg and vsel_mask fields in their descriptor and then use this
+ * as their set_voltage_vsel operation, saving some code.
+ */
+int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel)
+{
+	int ret;
+
+	sel <<= ffs(rdev->desc->vsel_mask) - 1;
+
+	ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+				  rdev->desc->vsel_mask, sel);
+	if (ret)
+		return ret;
+
+	if (rdev->desc->apply_bit)
+		ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg,
+					 rdev->desc->apply_bit,
+					 rdev->desc->apply_bit);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap);
+
+/**
+ * regulator_map_voltage_iterate - map_voltage() based on list_voltage()
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers implementing set_voltage_sel() and list_voltage() can use
+ * this as their map_voltage() operation.  It will find a suitable
+ * voltage by calling list_voltage() until it gets something in bounds
+ * for the requested voltages.
+ */
+int regulator_map_voltage_iterate(struct regulator_dev *rdev,
+				  int min_uV, int max_uV)
+{
+	int best_val = INT_MAX;
+	int selector = 0;
+	int i, ret;
+
+	/* Find the smallest voltage that falls within the specified
+	 * range.
+	 */
+	for (i = 0; i < rdev->desc->n_voltages; i++) {
+		ret = rdev->desc->ops->list_voltage(rdev, i);
+		if (ret < 0)
+			continue;
+
+		if (ret < best_val && ret >= min_uV && ret <= max_uV) {
+			best_val = ret;
+			selector = i;
+		}
+	}
+
+	if (best_val != INT_MAX)
+		return selector;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
+
+/**
+ * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers that have ascendant voltage list can use this as their
+ * map_voltage() operation.
+ */
+int regulator_map_voltage_ascend(struct regulator_dev *rdev,
+				 int min_uV, int max_uV)
+{
+	int i, ret;
+
+	for (i = 0; i < rdev->desc->n_voltages; i++) {
+		ret = rdev->desc->ops->list_voltage(rdev, i);
+		if (ret < 0)
+			continue;
+
+		if (ret > max_uV)
+			break;
+
+		if (ret >= min_uV && ret <= max_uV)
+			return i;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for simple linear mappings
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing min_uV and uV_step in their regulator_desc can
+ * use this as their map_voltage() operation.
+ */
+int regulator_map_voltage_linear(struct regulator_dev *rdev,
+				 int min_uV, int max_uV)
+{
+	int ret, voltage;
+
+	/* Allow uV_step to be 0 for fixed voltage */
+	if (rdev->desc->n_voltages == 1 && rdev->desc->uV_step == 0) {
+		if (min_uV <= rdev->desc->min_uV && rdev->desc->min_uV <= max_uV)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
+	if (!rdev->desc->uV_step) {
+		BUG_ON(!rdev->desc->uV_step);
+		return -EINVAL;
+	}
+
+	if (min_uV < rdev->desc->min_uV)
+		min_uV = rdev->desc->min_uV;
+
+	ret = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step);
+	if (ret < 0)
+		return ret;
+
+	ret += rdev->desc->linear_min_sel;
+
+	/* Map back into a voltage to verify we're still in bounds */
+	voltage = rdev->desc->ops->list_voltage(rdev, ret);
+	if (voltage < min_uV || voltage > max_uV)
+		return -EINVAL;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear);
+
+/**
+ * regulator_map_voltage_linear - map_voltage() for multiple linear ranges
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers providing linear_ranges in their descriptor can use this as
+ * their map_voltage() callback.
+ */
+int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
+				       int min_uV, int max_uV)
+{
+	const struct regulator_linear_range *range;
+	int ret = -EINVAL;
+	int voltage, i;
+
+	if (!rdev->desc->n_linear_ranges) {
+		BUG_ON(!rdev->desc->n_linear_ranges);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+		range = &rdev->desc->linear_ranges[i];
+
+		if (!(min_uV <= range->max_uV && max_uV >= range->min_uV))
+			continue;
+
+		if (min_uV <= range->min_uV)
+			min_uV = range->min_uV;
+
+		/* range->uV_step == 0 means fixed voltage range */
+		if (range->uV_step == 0) {
+			ret = 0;
+		} else {
+			ret = DIV_ROUND_UP(min_uV - range->min_uV,
+					   range->uV_step);
+			if (ret < 0)
+				return ret;
+		}
+
+		ret += range->min_sel;
+
+		break;
+	}
+
+	if (i == rdev->desc->n_linear_ranges)
+		return -EINVAL;
+
+	/* Map back into a voltage to verify we're still in bounds */
+	voltage = rdev->desc->ops->list_voltage(rdev, ret);
+	if (voltage < min_uV || voltage > max_uV)
+		return -EINVAL;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_linear_range);
+
+/**
+ * regulator_list_voltage_linear - List voltages with simple calculation
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear(struct regulator_dev *rdev,
+				  unsigned int selector)
+{
+	if (selector >= rdev->desc->n_voltages)
+		return -EINVAL;
+	if (selector < rdev->desc->linear_min_sel)
+		return 0;
+
+	selector -= rdev->desc->linear_min_sel;
+
+	return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
+
+/**
+ * regulator_list_voltage_linear_range - List voltages for linear ranges
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a series of simple linear mappings between voltages
+ * and selectors can set linear_ranges in the regulator descriptor and
+ * then use this function as their list_voltage() operation,
+ */
+int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
+					unsigned int selector)
+{
+	const struct regulator_linear_range *range;
+	int i;
+
+	if (!rdev->desc->n_linear_ranges) {
+		BUG_ON(!rdev->desc->n_linear_ranges);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < rdev->desc->n_linear_ranges; i++) {
+		range = &rdev->desc->linear_ranges[i];
+
+		if (!(selector >= range->min_sel &&
+		      selector <= range->max_sel))
+			continue;
+
+		selector -= range->min_sel;
+
+		return range->min_uV + (range->uV_step * selector);
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_linear_range);
+
+/**
+ * regulator_list_voltage_table - List voltages with table based mapping
+ *
+ * @rdev: Regulator device
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with table based mapping between voltages and
+ * selectors can set volt_table in the regulator descriptor
+ * and then use this function as their list_voltage() operation.
+ */
+int regulator_list_voltage_table(struct regulator_dev *rdev,
+				 unsigned int selector)
+{
+	if (!rdev->desc->volt_table) {
+		BUG_ON(!rdev->desc->volt_table);
+		return -EINVAL;
+	}
+
+	if (selector >= rdev->desc->n_voltages)
+		return -EINVAL;
+
+	return rdev->desc->volt_table[selector];
+}
+EXPORT_SYMBOL_GPL(regulator_list_voltage_table);
+
+/**
+ * regulator_set_bypass_regmap - Default set_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: state to set.
+ */
+int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
+{
+	unsigned int val;
+
+	if (enable)
+		val = rdev->desc->bypass_mask;
+	else
+		val = 0;
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
+				  rdev->desc->bypass_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
+
+/**
+ * regulator_get_bypass_regmap - Default get_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: current state.
+ */
+int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
+	if (ret != 0)
+		return ret;
+
+	*enable = val & rdev->desc->bypass_mask;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
index b99c49b..88c1a3a 100644
--- a/drivers/regulator/isl6271a-regulator.c
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -110,7 +110,7 @@
 				     const struct i2c_device_id *id)
 {
 	struct regulator_config config = { };
-	struct regulator_init_data *init_data	= i2c->dev.platform_data;
+	struct regulator_init_data *init_data	= dev_get_platdata(&i2c->dev);
 	struct isl_pmic *pmic;
 	int err, i;
 
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 3809b43..5a4604e 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -425,7 +425,7 @@
 			    const struct i2c_device_id *id)
 {
 	struct lp3971 *lp3971;
-	struct lp3971_platform_data *pdata = i2c->dev.platform_data;
+	struct lp3971_platform_data *pdata = dev_get_platdata(&i2c->dev);
 	int ret;
 	u16 val;
 
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 5730240..093e6f4 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -519,7 +519,7 @@
 			    const struct i2c_device_id *id)
 {
 	struct lp3972 *lp3972;
-	struct lp3972_platform_data *pdata = i2c->dev.platform_data;
+	struct lp3972_platform_data *pdata = dev_get_platdata(&i2c->dev);
 	int ret;
 	u16 val;
 
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index b16336b..2b84b72 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -373,7 +373,7 @@
 		return -EINVAL;
 	}
 
-	for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) {
+	for (i = ARRAY_SIZE(lp8725_buck_uA) - 1; i >= 0; i--) {
 		if (lp8725_buck_uA[i] >= min_uA &&
 			lp8725_buck_uA[i] <= max_uA)
 			return lp872x_update_bits(lp, addr,
@@ -787,7 +787,7 @@
 	struct regulator_dev *rdev;
 	int i, ret;
 
-	for (i = 0 ; i < lp->num_regulators ; i++) {
+	for (i = 0; i < lp->num_regulators; i++) {
 		desc = (lp->chipid == LP8720) ? &lp8720_regulator_desc[i] :
 						&lp8725_regulator_desc[i];
 
@@ -820,7 +820,7 @@
 	struct regulator_dev *rdev;
 	int i;
 
-	for (i = 0 ; i < lp->num_regulators ; i++) {
+	for (i = 0; i < lp->num_regulators; i++) {
 		rdev = *(lp->regulators + i);
 		regulator_unregister(rdev);
 	}
@@ -907,7 +907,8 @@
 		goto out;
 
 	for (i = 0; i < num_matches; i++) {
-		pdata->regulator_data[i].id = (int)match[i].driver_data;
+		pdata->regulator_data[i].id =
+				(enum lp872x_regulator_id)match[i].driver_data;
 		pdata->regulator_data[i].init_data = match[i].init_data;
 
 		/* Operation mode configuration for buck/buck1/buck2 */
@@ -961,7 +962,7 @@
 	}
 
 	lp->dev = &cl->dev;
-	lp->pdata = cl->dev.platform_data;
+	lp->pdata = dev_get_platdata(&cl->dev);
 	lp->chipid = id->driver_data;
 	lp->num_regulators = num_regulators;
 	i2c_set_clientdata(cl, lp);
diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c
index d9e38b4..785a25e 100644
--- a/drivers/regulator/lp8755.c
+++ b/drivers/regulator/lp8755.c
@@ -228,6 +228,7 @@
 }
 
 static struct regulator_ops lp8755_buck_ops = {
+	.map_voltage = regulator_map_voltage_linear,
 	.list_voltage = regulator_list_voltage_linear,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -449,7 +450,7 @@
 {
 	int ret, icnt;
 	struct lp8755_chip *pchip;
-	struct lp8755_platform_data *pdata = client->dev.platform_data;
+	struct lp8755_platform_data *pdata = dev_get_platdata(&client->dev);
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		dev_err(&client->dev, "i2c functionality check fail.\n");
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 54af610..3a599ee 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -163,7 +163,7 @@
 					const struct i2c_device_id *i2c_id)
 {
 	struct regulator_dev **rdev;
-	struct max1586_platform_data *pdata = client->dev.platform_data;
+	struct max1586_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct regulator_config config = { };
 	struct max1586_data *max1586;
 	int i, id, ret = -ENOMEM;
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index db6c9be..19c6f08 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -152,7 +152,7 @@
 static int max8649_regulator_probe(struct i2c_client *client,
 					     const struct i2c_device_id *id)
 {
-	struct max8649_platform_data *pdata = client->dev.platform_data;
+	struct max8649_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct max8649_regulator_info *info = NULL;
 	struct regulator_config config = { };
 	unsigned int val;
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index d428ef9..144bcac 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -44,6 +44,9 @@
 #include <linux/regulator/driver.h>
 #include <linux/slab.h>
 #include <linux/regulator/max8660.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
 
 #define MAX8660_DCDC_MIN_UV	 725000
 #define MAX8660_DCDC_MAX_UV	1800000
@@ -305,21 +308,105 @@
 	},
 };
 
+enum {
+	MAX8660 = 0,
+	MAX8661 = 1,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id max8660_dt_ids[] = {
+	{ .compatible = "maxim,max8660", .data = (void *) MAX8660 },
+	{ .compatible = "maxim,max8661", .data = (void *) MAX8661 },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, max8660_dt_ids);
+
+static int max8660_pdata_from_dt(struct device *dev,
+				 struct device_node **of_node,
+				 struct max8660_platform_data *pdata)
+{
+	int matched, i;
+	struct device_node *np;
+	struct max8660_subdev_data *sub;
+	struct of_regulator_match rmatch[ARRAY_SIZE(max8660_reg)];
+
+	np = of_find_node_by_name(dev->of_node, "regulators");
+	if (!np) {
+		dev_err(dev, "missing 'regulators' subnode in DT\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rmatch); i++)
+		rmatch[i].name = max8660_reg[i].name;
+
+	matched = of_regulator_match(dev, np, rmatch, ARRAY_SIZE(rmatch));
+	if (matched <= 0)
+		return matched;
+
+	pdata->subdevs = devm_kzalloc(dev, sizeof(struct max8660_subdev_data) *
+						matched, GFP_KERNEL);
+	if (!pdata->subdevs)
+		return -ENOMEM;
+
+	pdata->num_subdevs = matched;
+	sub = pdata->subdevs;
+
+	for (i = 0; i < matched; i++) {
+		sub->id = i;
+		sub->name = rmatch[i].name;
+		sub->platform_data = rmatch[i].init_data;
+		of_node[i] = rmatch[i].of_node;
+		sub++;
+	}
+
+	return 0;
+}
+#else
+static inline int max8660_pdata_from_dt(struct device *dev,
+					struct device_node **of_node,
+					struct max8660_platform_data *pdata)
+{
+	return 0;
+}
+#endif
+
 static int max8660_probe(struct i2c_client *client,
 				   const struct i2c_device_id *i2c_id)
 {
 	struct regulator_dev **rdev;
-	struct max8660_platform_data *pdata = client->dev.platform_data;
+	struct device *dev = &client->dev;
+	struct max8660_platform_data *pdata = dev_get_platdata(dev);
 	struct regulator_config config = { };
 	struct max8660 *max8660;
 	int boot_on, i, id, ret = -EINVAL;
+	struct device_node *of_node[MAX8660_V_END];
+	unsigned long type;
+
+	if (dev->of_node && !pdata) {
+		const struct of_device_id *id;
+		struct max8660_platform_data pdata_of;
+
+		id = of_match_device(of_match_ptr(max8660_dt_ids), dev);
+		if (!id)
+			return -ENODEV;
+
+		ret = max8660_pdata_from_dt(dev, of_node, &pdata_of);
+		if (ret < 0)
+			return ret;
+
+		pdata = &pdata_of;
+		type = (unsigned long) id->data;
+	} else {
+		type = i2c_id->driver_data;
+		memset(of_node, 0, sizeof(of_node));
+	}
 
 	if (pdata->num_subdevs > MAX8660_V_END) {
-		dev_err(&client->dev, "Too many regulators found!\n");
+		dev_err(dev, "Too many regulators found!\n");
 		return -EINVAL;
 	}
 
-	max8660 = devm_kzalloc(&client->dev, sizeof(struct max8660) +
+	max8660 = devm_kzalloc(dev, sizeof(struct max8660) +
 			sizeof(struct regulator_dev *) * MAX8660_V_END,
 			GFP_KERNEL);
 	if (!max8660)
@@ -376,8 +463,8 @@
 			break;
 
 		case MAX8660_V7:
-			if (!strcmp(i2c_id->name, "max8661")) {
-				dev_err(&client->dev, "Regulator not on this chip!\n");
+			if (type == MAX8661) {
+				dev_err(dev, "Regulator not on this chip!\n");
 				goto err_out;
 			}
 
@@ -386,7 +473,7 @@
 			break;
 
 		default:
-			dev_err(&client->dev, "invalid regulator %s\n",
+			dev_err(dev, "invalid regulator %s\n",
 				 pdata->subdevs[i].name);
 			goto err_out;
 		}
@@ -397,14 +484,15 @@
 
 		id = pdata->subdevs[i].id;
 
-		config.dev = &client->dev;
+		config.dev = dev;
 		config.init_data = pdata->subdevs[i].platform_data;
+		config.of_node = of_node[i];
 		config.driver_data = max8660;
 
 		rdev[i] = regulator_register(&max8660_reg[id], &config);
 		if (IS_ERR(rdev[i])) {
 			ret = PTR_ERR(rdev[i]);
-			dev_err(&client->dev, "failed to register %s\n",
+			dev_err(dev, "failed to register %s\n",
 				max8660_reg[id].name);
 			goto err_unregister;
 		}
@@ -431,8 +519,8 @@
 }
 
 static const struct i2c_device_id max8660_id[] = {
-	{ "max8660", 0 },
-	{ "max8661", 0 },
+	{ .name = "max8660", .driver_data = MAX8660 },
+	{ .name = "max8661", .driver_data = MAX8661 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, max8660_id);
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index e6d54a5..d80b5fa 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -277,7 +277,7 @@
 static int max8925_regulator_probe(struct platform_device *pdev)
 {
 	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
-	struct regulator_init_data *pdata = pdev->dev.platform_data;
+	struct regulator_init_data *pdata = dev_get_platdata(&pdev->dev);
 	struct regulator_config config = { };
 	struct max8925_regulator_info *ri;
 	struct resource *res;
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index 5259c2f..788e5ae 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -196,7 +196,7 @@
 		const struct i2c_device_id *i2c_id)
 {
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-	struct max8952_platform_data *pdata = client->dev.platform_data;
+	struct max8952_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct regulator_config config = { };
 	struct max8952_data *max8952;
 
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 0c5195a..5b77ab7 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -371,7 +371,7 @@
 	struct max8973_chip *max;
 	int ret;
 
-	pdata = client->dev.platform_data;
+	pdata = dev_get_platdata(&client->dev);
 
 	if (!pdata && !client->dev.of_node) {
 		dev_err(&client->dev, "No Platform data");
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index f3c8f8f..7827384 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -21,6 +21,7 @@
 {
 	const __be32 *min_uV, *max_uV, *uV_offset;
 	const __be32 *min_uA, *max_uA, *ramp_delay;
+	struct property *prop;
 	struct regulation_constraints *constraints = &(*init_data)->constraints;
 
 	constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -64,9 +65,14 @@
 	if (of_property_read_bool(np, "regulator-allow-bypass"))
 		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
 
-	ramp_delay = of_get_property(np, "regulator-ramp-delay", NULL);
-	if (ramp_delay)
-		constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+	prop = of_find_property(np, "regulator-ramp-delay", NULL);
+	if (prop && prop->value) {
+		ramp_delay = prop->value;
+		if (*ramp_delay)
+			constraints->ramp_delay = be32_to_cpu(*ramp_delay);
+		else
+			constraints->ramp_disable = true;
+	}
 }
 
 /**
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index d0c8785..488dfe7 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -97,11 +97,16 @@
 		.ctrl_addr	= PALMAS_SMPS9_CTRL,
 	},
 	{
-		.name		= "SMPS10",
+		.name		= "SMPS10_OUT2",
 		.sname		= "smps10-in",
 		.ctrl_addr	= PALMAS_SMPS10_CTRL,
 	},
 	{
+		.name		= "SMPS10_OUT1",
+		.sname		= "smps10-out2",
+		.ctrl_addr	= PALMAS_SMPS10_CTRL,
+	},
+	{
 		.name		= "LDO1",
 		.sname		= "ldo1-in",
 		.vsel_addr	= PALMAS_LDO1_VOLTAGE,
@@ -487,6 +492,8 @@
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
 	.list_voltage		= regulator_list_voltage_linear,
 	.map_voltage		= regulator_map_voltage_linear,
+	.set_bypass		= regulator_set_bypass_regmap,
+	.get_bypass		= regulator_get_bypass_regmap,
 };
 
 static int palmas_is_enabled_ldo(struct regulator_dev *dev)
@@ -538,7 +545,8 @@
 		return ret;
 
 	switch (id) {
-	case PALMAS_REG_SMPS10:
+	case PALMAS_REG_SMPS10_OUT1:
+	case PALMAS_REG_SMPS10_OUT2:
 		reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
 		if (reg_init->mode_sleep)
 			reg |= reg_init->mode_sleep <<
@@ -681,7 +689,8 @@
 	{ .name = "smps7", },
 	{ .name = "smps8", },
 	{ .name = "smps9", },
-	{ .name = "smps10", },
+	{ .name = "smps10_out2", },
+	{ .name = "smps10_out1", },
 	{ .name = "ldo1", },
 	{ .name = "ldo2", },
 	{ .name = "ldo3", },
@@ -765,7 +774,7 @@
 static int palmas_regulators_probe(struct platform_device *pdev)
 {
 	struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
-	struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
+	struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *node = pdev->dev.of_node;
 	struct regulator_dev *rdev;
 	struct regulator_config config = { };
@@ -838,7 +847,8 @@
 				continue;
 			ramp_delay_support = true;
 			break;
-		case PALMAS_REG_SMPS10:
+		case PALMAS_REG_SMPS10_OUT1:
+		case PALMAS_REG_SMPS10_OUT2:
 			if (!PALMAS_PMIC_HAS(palmas, SMPS10_BOOST))
 				continue;
 		}
@@ -872,7 +882,8 @@
 		pmic->desc[id].id = id;
 
 		switch (id) {
-		case PALMAS_REG_SMPS10:
+		case PALMAS_REG_SMPS10_OUT1:
+		case PALMAS_REG_SMPS10_OUT2:
 			pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
 			pmic->desc[id].ops = &palmas_ops_smps10;
 			pmic->desc[id].vsel_reg =
@@ -882,7 +893,14 @@
 			pmic->desc[id].enable_reg =
 					PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
 							PALMAS_SMPS10_CTRL);
-			pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+			if (id == PALMAS_REG_SMPS10_OUT1)
+				pmic->desc[id].enable_mask = SMPS10_SWITCH_EN;
+			else
+				pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
+			pmic->desc[id].bypass_reg =
+					PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
+							PALMAS_SMPS10_CTRL);
+			pmic->desc[id].bypass_mask = SMPS10_BYPASS_EN;
 			pmic->desc[id].min_uV = 3750000;
 			pmic->desc[id].uV_step = 1250000;
 			break;
diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c
index 1a73a29..b49eaee 100644
--- a/drivers/regulator/pcap-regulator.c
+++ b/drivers/regulator/pcap-regulator.c
@@ -243,7 +243,7 @@
 	struct regulator_config config = { };
 
 	config.dev = &pdev->dev;
-	config.init_data = pdev->dev.platform_data;
+	config.init_data = dev_get_platdata(&pdev->dev);
 	config.driver_data = pcap;
 
 	rdev = regulator_register(&pcap_regulators[pdev->id], &config);
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
index 54df9f7..0f3576d 100644
--- a/drivers/regulator/pcf50633-regulator.c
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -86,7 +86,7 @@
 	pcf = dev_to_pcf50633(pdev->dev.parent);
 
 	config.dev = &pdev->dev;
-	config.init_data = pdev->dev.platform_data;
+	config.init_data = dev_get_platdata(&pdev->dev);
 	config.driver_data = pcf;
 	config.regmap = pcf->regmap;
 
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
new file mode 100644
index 0000000..ba67b2c
--- /dev/null
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 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  02111-1307 USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/pfuze100.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+
+#define PFUZE_NUMREGS		128
+#define PFUZE100_VOL_OFFSET	0
+#define PFUZE100_STANDBY_OFFSET	1
+#define PFUZE100_MODE_OFFSET	3
+#define PFUZE100_CONF_OFFSET	4
+
+#define PFUZE100_DEVICEID	0x0
+#define PFUZE100_REVID		0x3
+#define PFUZE100_FABID		0x3
+
+#define PFUZE100_SW1ABVOL	0x20
+#define PFUZE100_SW1CVOL	0x2e
+#define PFUZE100_SW2VOL		0x35
+#define PFUZE100_SW3AVOL	0x3c
+#define PFUZE100_SW3BVOL	0x43
+#define PFUZE100_SW4VOL		0x4a
+#define PFUZE100_SWBSTCON1	0x66
+#define PFUZE100_VREFDDRCON	0x6a
+#define PFUZE100_VSNVSVOL	0x6b
+#define PFUZE100_VGEN1VOL	0x6c
+#define PFUZE100_VGEN2VOL	0x6d
+#define PFUZE100_VGEN3VOL	0x6e
+#define PFUZE100_VGEN4VOL	0x6f
+#define PFUZE100_VGEN5VOL	0x70
+#define PFUZE100_VGEN6VOL	0x71
+
+struct pfuze_regulator {
+	struct regulator_desc desc;
+	unsigned char stby_reg;
+	unsigned char stby_mask;
+};
+
+struct pfuze_chip {
+	struct regmap *regmap;
+	struct device *dev;
+	struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
+	struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
+};
+
+static const int pfuze100_swbst[] = {
+	5000000, 5050000, 5100000, 5150000,
+};
+
+static const int pfuze100_vsnvs[] = {
+	1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
+};
+
+static const struct i2c_device_id pfuze_device_id[] = {
+	{.name = "pfuze100"},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
+
+static const struct of_device_id pfuze_dt_ids[] = {
+	{ .compatible = "fsl,pfuze100" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
+
+static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+	struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
+	int id = rdev->desc->id;
+	unsigned int ramp_bits;
+	int ret;
+
+	if (id < PFUZE100_SWBST) {
+		ramp_delay = 12500 / ramp_delay;
+		ramp_bits = (ramp_delay >> 1) - (ramp_delay >> 3);
+		ret = regmap_update_bits(pfuze100->regmap,
+					 rdev->desc->vsel_reg + 4,
+					 0xc0, ramp_bits << 6);
+		if (ret < 0)
+			dev_err(pfuze100->dev, "ramp failed, err %d\n", ret);
+	} else
+		ret = -EACCES;
+
+	return ret;
+}
+
+static struct regulator_ops pfuze100_ldo_regulator_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops pfuze100_fixed_regulator_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops pfuze100_sw_regulator_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_voltage_time_sel = regulator_set_voltage_time_sel,
+	.set_ramp_delay = pfuze100_set_ramp_delay,
+};
+
+static struct regulator_ops pfuze100_swb_regulator_ops = {
+	.list_voltage = regulator_list_voltage_table,
+	.map_voltage = regulator_map_voltage_ascend,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+
+};
+
+#define PFUZE100_FIXED_REG(_name, base, voltage)	\
+	[PFUZE100_ ## _name] = {	\
+		.desc = {	\
+			.name = #_name,	\
+			.n_voltages = 1,	\
+			.ops = &pfuze100_fixed_regulator_ops,	\
+			.type = REGULATOR_VOLTAGE,	\
+			.id = PFUZE100_ ## _name,	\
+			.owner = THIS_MODULE,	\
+			.min_uV = (voltage),	\
+			.enable_reg = (base),	\
+			.enable_mask = 0x10,	\
+		},	\
+	}
+
+#define PFUZE100_SW_REG(_name, base, min, max, step)	\
+	[PFUZE100_ ## _name] = {	\
+		.desc = {	\
+			.name = #_name,\
+			.n_voltages = ((max) - (min)) / (step) + 1,	\
+			.ops = &pfuze100_sw_regulator_ops,	\
+			.type = REGULATOR_VOLTAGE,	\
+			.id = PFUZE100_ ## _name,	\
+			.owner = THIS_MODULE,	\
+			.min_uV = (min),	\
+			.uV_step = (step),	\
+			.vsel_reg = (base) + PFUZE100_VOL_OFFSET,	\
+			.vsel_mask = 0x3f,	\
+		},	\
+		.stby_reg = (base) + PFUZE100_STANDBY_OFFSET,	\
+		.stby_mask = 0x3f,	\
+	}
+
+#define PFUZE100_SWB_REG(_name, base, mask, voltages)	\
+	[PFUZE100_ ## _name] = {	\
+		.desc = {	\
+			.name = #_name,	\
+			.n_voltages = ARRAY_SIZE(voltages),	\
+			.ops = &pfuze100_swb_regulator_ops,	\
+			.type = REGULATOR_VOLTAGE,	\
+			.id = PFUZE100_ ## _name,	\
+			.owner = THIS_MODULE,	\
+			.volt_table = voltages,	\
+			.vsel_reg = (base),	\
+			.vsel_mask = (mask),	\
+		},	\
+	}
+
+#define PFUZE100_VGEN_REG(_name, base, min, max, step)	\
+	[PFUZE100_ ## _name] = {	\
+		.desc = {	\
+			.name = #_name,	\
+			.n_voltages = ((max) - (min)) / (step) + 1,	\
+			.ops = &pfuze100_ldo_regulator_ops,	\
+			.type = REGULATOR_VOLTAGE,	\
+			.id = PFUZE100_ ## _name,	\
+			.owner = THIS_MODULE,	\
+			.min_uV = (min),	\
+			.uV_step = (step),	\
+			.vsel_reg = (base),	\
+			.vsel_mask = 0xf,	\
+			.enable_reg = (base),	\
+			.enable_mask = 0x10,	\
+		},	\
+		.stby_reg = (base),	\
+		.stby_mask = 0x20,	\
+	}
+
+static struct pfuze_regulator pfuze100_regulators[] = {
+	PFUZE100_SW_REG(SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
+	PFUZE100_SW_REG(SW1C, PFUZE100_SW1CVOL, 300000, 1875000, 25000),
+	PFUZE100_SW_REG(SW2, PFUZE100_SW2VOL, 400000, 1975000, 25000),
+	PFUZE100_SW_REG(SW3A, PFUZE100_SW3AVOL, 400000, 1975000, 25000),
+	PFUZE100_SW_REG(SW3B, PFUZE100_SW3BVOL, 400000, 1975000, 25000),
+	PFUZE100_SW_REG(SW4, PFUZE100_SW4VOL, 400000, 1975000, 25000),
+	PFUZE100_SWB_REG(SWBST, PFUZE100_SWBSTCON1, 0x3 , pfuze100_swbst),
+	PFUZE100_SWB_REG(VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+	PFUZE100_FIXED_REG(VREFDDR, PFUZE100_VREFDDRCON, 750000),
+	PFUZE100_VGEN_REG(VGEN1, PFUZE100_VGEN1VOL, 800000, 1550000, 50000),
+	PFUZE100_VGEN_REG(VGEN2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+	PFUZE100_VGEN_REG(VGEN3, PFUZE100_VGEN3VOL, 1800000, 3300000, 100000),
+	PFUZE100_VGEN_REG(VGEN4, PFUZE100_VGEN4VOL, 1800000, 3300000, 100000),
+	PFUZE100_VGEN_REG(VGEN5, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+	PFUZE100_VGEN_REG(VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
+#ifdef CONFIG_OF
+static struct of_regulator_match pfuze100_matches[] = {
+	{ .name = "sw1ab",	},
+	{ .name = "sw1c",	},
+	{ .name = "sw2",	},
+	{ .name = "sw3a",	},
+	{ .name = "sw3b",	},
+	{ .name = "sw4",	},
+	{ .name = "swbst",	},
+	{ .name = "vsnvs",	},
+	{ .name = "vrefddr",	},
+	{ .name = "vgen1",	},
+	{ .name = "vgen2",	},
+	{ .name = "vgen3",	},
+	{ .name = "vgen4",	},
+	{ .name = "vgen5",	},
+	{ .name = "vgen6",	},
+};
+
+static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
+{
+	struct device *dev = chip->dev;
+	struct device_node *np, *parent;
+	int ret;
+
+	np = of_node_get(dev->parent->of_node);
+	if (!np)
+		return 0;
+
+	parent = of_find_node_by_name(np, "regulators");
+	if (!parent) {
+		dev_err(dev, "regulators node not found\n");
+		return -EINVAL;
+	}
+
+	ret = of_regulator_match(dev, parent, pfuze100_matches,
+				 ARRAY_SIZE(pfuze100_matches));
+
+	of_node_put(parent);
+	if (ret < 0) {
+		dev_err(dev, "Error parsing regulator init data: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+	return pfuze100_matches[index].init_data;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+	return pfuze100_matches[index].of_node;
+}
+#else
+static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
+{
+	return 0;
+}
+
+static inline struct regulator_init_data *match_init_data(int index)
+{
+	return NULL;
+}
+
+static inline struct device_node *match_of_node(int index)
+{
+	return NULL;
+}
+#endif
+
+static int pfuze_identify(struct pfuze_chip *pfuze_chip)
+{
+	unsigned int value;
+	int ret;
+
+	ret = regmap_read(pfuze_chip->regmap, PFUZE100_DEVICEID, &value);
+	if (ret)
+		return ret;
+
+	if (value & 0x0f) {
+		dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
+		return -ENODEV;
+	}
+
+	ret = regmap_read(pfuze_chip->regmap, PFUZE100_REVID, &value);
+	if (ret)
+		return ret;
+	dev_info(pfuze_chip->dev,
+		 "Full lay: %x, Metal lay: %x\n",
+		 (value & 0xf0) >> 4, value & 0x0f);
+
+	ret = regmap_read(pfuze_chip->regmap, PFUZE100_FABID, &value);
+	if (ret)
+		return ret;
+	dev_info(pfuze_chip->dev, "FAB: %x, FIN: %x\n",
+		 (value & 0xc) >> 2, value & 0x3);
+
+	return 0;
+}
+
+static const struct regmap_config pfuze_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = PFUZE_NUMREGS - 1,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int pfuze100_regulator_probe(struct i2c_client *client,
+				    const struct i2c_device_id *id)
+{
+	struct pfuze_chip *pfuze_chip;
+	struct pfuze_regulator_platform_data *pdata =
+	    dev_get_platdata(&client->dev);
+	struct regulator_config config = { };
+	int i, ret;
+
+	pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
+			GFP_KERNEL);
+	if (!pfuze_chip)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, pfuze_chip);
+
+	memcpy(pfuze_chip->regulator_descs, pfuze100_regulators,
+		sizeof(pfuze_chip->regulator_descs));
+
+	pfuze_chip->dev = &client->dev;
+
+	pfuze_chip->regmap = devm_regmap_init_i2c(client, &pfuze_regmap_config);
+	if (IS_ERR(pfuze_chip->regmap)) {
+		ret = PTR_ERR(pfuze_chip->regmap);
+		dev_err(&client->dev,
+			"regmap allocation failed with err %d\n", ret);
+		return ret;
+	}
+
+	ret = pfuze_identify(pfuze_chip);
+	if (ret) {
+		dev_err(&client->dev, "unrecognized pfuze chip ID!\n");
+		return ret;
+	}
+
+	ret = pfuze_parse_regulators_dt(pfuze_chip);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < PFUZE100_MAX_REGULATOR; i++) {
+		struct regulator_init_data *init_data;
+		struct regulator_desc *desc;
+		int val;
+
+		desc = &pfuze_chip->regulator_descs[i].desc;
+
+		if (pdata)
+			init_data = pdata->init_data[i];
+		else
+			init_data = match_init_data(i);
+
+		/* SW2~SW4 high bit check and modify the voltage value table */
+		if (i > PFUZE100_SW1C && i < PFUZE100_SWBST) {
+			regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
+			if (val & 0x40) {
+				desc->min_uV = 800000;
+				desc->uV_step = 50000;
+				desc->n_voltages = 51;
+			}
+		}
+
+		config.dev = &client->dev;
+		config.init_data = init_data;
+		config.driver_data = pfuze_chip;
+		config.of_node = match_of_node(i);
+
+		pfuze_chip->regulators[i] = regulator_register(desc, &config);
+		if (IS_ERR(pfuze_chip->regulators[i])) {
+			dev_err(&client->dev, "register regulator%s failed\n",
+				pfuze100_regulators[i].desc.name);
+			ret = PTR_ERR(pfuze_chip->regulators[i]);
+			while (--i >= 0)
+				regulator_unregister(pfuze_chip->regulators[i]);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+	int i;
+	struct pfuze_chip *pfuze_chip = i2c_get_clientdata(client);
+
+	for (i = 0; i < PFUZE100_MAX_REGULATOR; i++)
+		regulator_unregister(pfuze_chip->regulators[i]);
+
+	return 0;
+}
+
+static struct i2c_driver pfuze_driver = {
+	.id_table = pfuze_device_id,
+	.driver = {
+		.name = "pfuze100-regulator",
+		.owner = THIS_MODULE,
+		.of_match_table = pfuze_dt_ids,
+	},
+	.probe = pfuze100_regulator_probe,
+	.remove = pfuze100_regulator_remove,
+};
+module_i2c_driver(pfuze_driver);
+
+MODULE_AUTHOR("Robin Gong <b38343@freescale.com>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100 PMIC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("i2c:pfuze100-regulator");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index 2f62564..5eba2ff 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -16,12 +16,17 @@
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/s2mps11.h>
 
+#define S2MPS11_REGULATOR_CNT ARRAY_SIZE(regulators)
+
 struct s2mps11_info {
 	struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
 
@@ -31,11 +36,6 @@
 	int ramp_delay16;
 	int ramp_delay7810;
 	int ramp_delay9;
-
-	bool buck6_ramp;
-	bool buck2_ramp;
-	bool buck3_ramp;
-	bool buck4_ramp;
 };
 
 static int get_ramp_delay(int ramp_delay)
@@ -50,9 +50,171 @@
 			break;
 		cnt++;
 	}
+
+	if (cnt > 3)
+		cnt = 3;
+
 	return cnt;
 }
 
+static int s2mps11_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
+				   unsigned int old_selector,
+				   unsigned int new_selector)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	unsigned int ramp_delay = 0;
+	int old_volt, new_volt;
+
+	switch (rdev->desc->id) {
+	case S2MPS11_BUCK2:
+		ramp_delay = s2mps11->ramp_delay2;
+		break;
+	case S2MPS11_BUCK3:
+		ramp_delay = s2mps11->ramp_delay34;
+		break;
+	case S2MPS11_BUCK4:
+		ramp_delay = s2mps11->ramp_delay34;
+		break;
+	case S2MPS11_BUCK5:
+		ramp_delay = s2mps11->ramp_delay5;
+		break;
+	case S2MPS11_BUCK6:
+	case S2MPS11_BUCK1:
+		ramp_delay = s2mps11->ramp_delay16;
+		break;
+	case S2MPS11_BUCK7:
+	case S2MPS11_BUCK8:
+	case S2MPS11_BUCK10:
+		ramp_delay = s2mps11->ramp_delay7810;
+		break;
+	case S2MPS11_BUCK9:
+		ramp_delay = s2mps11->ramp_delay9;
+	}
+
+	if (ramp_delay == 0)
+		ramp_delay = rdev->desc->ramp_delay;
+
+	old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);
+	new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);
+
+	return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);
+}
+
+static int s2mps11_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+	struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
+	unsigned int ramp_val, ramp_shift, ramp_reg = S2MPS11_REG_RAMP_BUCK;
+	unsigned int ramp_enable = 1, enable_shift = 0;
+	int ret;
+
+	switch (rdev->desc->id) {
+	case S2MPS11_BUCK1:
+		if (ramp_delay > s2mps11->ramp_delay16)
+			s2mps11->ramp_delay16 = ramp_delay;
+		else
+			ramp_delay = s2mps11->ramp_delay16;
+
+		ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT;
+		break;
+	case S2MPS11_BUCK2:
+		enable_shift = S2MPS11_BUCK2_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		s2mps11->ramp_delay2 = ramp_delay;
+		ramp_shift = S2MPS11_BUCK2_RAMP_SHIFT;
+		ramp_reg = S2MPS11_REG_RAMP;
+		break;
+	case S2MPS11_BUCK3:
+		enable_shift = S2MPS11_BUCK3_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		if (ramp_delay > s2mps11->ramp_delay34)
+			s2mps11->ramp_delay34 = ramp_delay;
+		else
+			ramp_delay = s2mps11->ramp_delay34;
+
+		ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT;
+		ramp_reg = S2MPS11_REG_RAMP;
+		break;
+	case S2MPS11_BUCK4:
+		enable_shift = S2MPS11_BUCK4_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		if (ramp_delay > s2mps11->ramp_delay34)
+			s2mps11->ramp_delay34 = ramp_delay;
+		else
+			ramp_delay = s2mps11->ramp_delay34;
+
+		ramp_shift = S2MPS11_BUCK34_RAMP_SHIFT;
+		ramp_reg = S2MPS11_REG_RAMP;
+		break;
+	case S2MPS11_BUCK5:
+		s2mps11->ramp_delay5 = ramp_delay;
+		ramp_shift = S2MPS11_BUCK5_RAMP_SHIFT;
+		break;
+	case S2MPS11_BUCK6:
+		enable_shift = S2MPS11_BUCK6_RAMP_EN_SHIFT;
+		if (!ramp_delay) {
+			ramp_enable = 0;
+			break;
+		}
+
+		if (ramp_delay > s2mps11->ramp_delay16)
+			s2mps11->ramp_delay16 = ramp_delay;
+		else
+			ramp_delay = s2mps11->ramp_delay16;
+
+		ramp_shift = S2MPS11_BUCK16_RAMP_SHIFT;
+		break;
+	case S2MPS11_BUCK7:
+	case S2MPS11_BUCK8:
+	case S2MPS11_BUCK10:
+		if (ramp_delay > s2mps11->ramp_delay7810)
+			s2mps11->ramp_delay7810 = ramp_delay;
+		else
+			ramp_delay = s2mps11->ramp_delay7810;
+
+		ramp_shift = S2MPS11_BUCK7810_RAMP_SHIFT;
+		break;
+	case S2MPS11_BUCK9:
+		s2mps11->ramp_delay9 = ramp_delay;
+		ramp_shift = S2MPS11_BUCK9_RAMP_SHIFT;
+		break;
+	default:
+		return 0;
+	}
+
+	if (!ramp_enable)
+		goto ramp_disable;
+
+	if (enable_shift) {
+		ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+					1 << enable_shift, 1 << enable_shift);
+		if (ret) {
+			dev_err(&rdev->dev, "failed to enable ramp rate\n");
+			return ret;
+		}
+	}
+
+	ramp_val = get_ramp_delay(ramp_delay);
+
+	return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,
+				  ramp_val << ramp_shift);
+
+ramp_disable:
+	return regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+				  1 << enable_shift, 0);
+}
+
 static struct regulator_ops s2mps11_ldo_ops = {
 	.list_voltage		= regulator_list_voltage_linear,
 	.map_voltage		= regulator_map_voltage_linear,
@@ -72,7 +234,8 @@
 	.disable		= regulator_disable_regmap,
 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
-	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
+	.set_voltage_time_sel	= s2mps11_regulator_set_voltage_time_sel,
+	.set_ramp_delay		= s2mps11_set_ramp_delay,
 };
 
 #define regulator_desc_ldo1(num)	{		\
@@ -239,59 +402,51 @@
 {
 	struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
 	struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct of_regulator_match rdata[S2MPS11_REGULATOR_MAX];
+	struct device_node *reg_np = NULL;
 	struct regulator_config config = { };
 	struct s2mps11_info *s2mps11;
 	int i, ret;
-	unsigned char ramp_enable, ramp_reg = 0;
-
-	if (!pdata) {
-		dev_err(pdev->dev.parent, "Platform data not supplied\n");
-		return -ENODEV;
-	}
 
 	s2mps11 = devm_kzalloc(&pdev->dev, sizeof(struct s2mps11_info),
 				GFP_KERNEL);
 	if (!s2mps11)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, s2mps11);
-
-	s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
-	s2mps11->ramp_delay34 = pdata->buck34_ramp_delay;
-	s2mps11->ramp_delay5 = pdata->buck5_ramp_delay;
-	s2mps11->ramp_delay16 = pdata->buck16_ramp_delay;
-	s2mps11->ramp_delay7810 = pdata->buck7810_ramp_delay;
-	s2mps11->ramp_delay9 = pdata->buck9_ramp_delay;
-
-	s2mps11->buck6_ramp = pdata->buck6_ramp_enable;
-	s2mps11->buck2_ramp = pdata->buck2_ramp_enable;
-	s2mps11->buck3_ramp = pdata->buck3_ramp_enable;
-	s2mps11->buck4_ramp = pdata->buck4_ramp_enable;
-
-	ramp_enable = (s2mps11->buck2_ramp << 3) | (s2mps11->buck3_ramp << 2) |
-		(s2mps11->buck4_ramp << 1) | s2mps11->buck6_ramp ;
-
-	if (ramp_enable) {
-		if (s2mps11->buck2_ramp)
-			ramp_reg |= get_ramp_delay(s2mps11->ramp_delay2) << 6;
-		if (s2mps11->buck3_ramp || s2mps11->buck4_ramp)
-			ramp_reg |= get_ramp_delay(s2mps11->ramp_delay34) << 4;
-		sec_reg_write(iodev, S2MPS11_REG_RAMP, ramp_reg | ramp_enable);
+	if (!iodev->dev->of_node) {
+		if (pdata) {
+			goto common_reg;
+		} else {
+			dev_err(pdev->dev.parent,
+				"Platform data or DT node not supplied\n");
+			return -ENODEV;
+		}
 	}
 
-	ramp_reg &= 0x00;
-	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay5) << 6;
-	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay16) << 4;
-	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay7810) << 2;
-	ramp_reg |= get_ramp_delay(s2mps11->ramp_delay9);
-	sec_reg_write(iodev, S2MPS11_REG_RAMP_BUCK, ramp_reg);
+	for (i = 0; i < S2MPS11_REGULATOR_CNT; i++)
+		rdata[i].name = regulators[i].name;
 
+	reg_np = of_find_node_by_name(iodev->dev->of_node, "regulators");
+	if (!reg_np) {
+		dev_err(&pdev->dev, "could not find regulators sub-node\n");
+		return -EINVAL;
+	}
+
+	of_regulator_match(&pdev->dev, reg_np, rdata, S2MPS11_REGULATOR_MAX);
+
+common_reg:
+	platform_set_drvdata(pdev, s2mps11);
+
+	config.dev = &pdev->dev;
+	config.regmap = iodev->regmap;
+	config.driver_data = s2mps11;
 	for (i = 0; i < S2MPS11_REGULATOR_MAX; i++) {
-
-		config.dev = &pdev->dev;
-		config.regmap = iodev->regmap;
-		config.init_data = pdata->regulators[i].initdata;
-		config.driver_data = s2mps11;
+		if (!reg_np) {
+			config.init_data = pdata->regulators[i].initdata;
+		} else {
+			config.init_data = rdata[i].init_data;
+			config.of_node = rdata[i].of_node;
+		}
 
 		s2mps11->rdev[i] = regulator_register(&regulators[i], &config);
 		if (IS_ERR(s2mps11->rdev[i])) {
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c
index 3753ed0..d8e3e12 100644
--- a/drivers/regulator/ti-abb-regulator.c
+++ b/drivers/regulator/ti-abb-regulator.c
@@ -717,11 +717,6 @@
 	/* Map ABB resources */
 	pname = "base-address";
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
-	if (!res) {
-		dev_err(dev, "Missing '%s' IO resource\n", pname);
-		ret = -ENODEV;
-		goto err;
-	}
 	abb->base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(abb->base)) {
 		ret = PTR_ERR(abb->base);
@@ -770,11 +765,6 @@
 
 	pname = "ldo-address";
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname);
-	if (!res) {
-		dev_dbg(dev, "Missing '%s' IO resource\n", pname);
-		ret = -ENODEV;
-		goto skip_opt;
-	}
 	abb->ldo_base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(abb->ldo_base)) {
 		ret = PTR_ERR(abb->ldo_base);
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index 6e67be7..9392a7c 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -275,7 +275,7 @@
 		}
 	}
 
-	pdata = client->dev.platform_data;
+	pdata = dev_get_platdata(&client->dev);
 	if (!pdata && client->dev.of_node)
 		pdata = of_get_tps51632_platform_data(&client->dev);
 	if (!pdata) {
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index a490d5b..0b7ebb1 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -350,7 +350,7 @@
 	int i;
 	int chip_id;
 
-	pdata = client->dev.platform_data;
+	pdata = dev_get_platdata(&client->dev);
 
 	if (client->dev.of_node) {
 		const struct of_device_id *match;
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 9d053e2..a15263d 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -218,7 +218,7 @@
 	 * init_data points to array of regulator_init structures
 	 * coming from the board-evm file.
 	 */
-	init_data = client->dev.platform_data;
+	init_data = dev_get_platdata(&client->dev);
 	if (!init_data)
 		return -EIO;
 
diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c
index 2df4616..90861d6 100644
--- a/drivers/regulator/tps65217-regulator.c
+++ b/drivers/regulator/tps65217-regulator.c
@@ -27,7 +27,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps65217.h>
 
-#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t) \
+#define TPS65217_REGULATOR(_name, _id, _ops, _n, _vr, _vm, _em, _t, _lr, _nlr) \
 	{						\
 		.name		= _name,		\
 		.id		= _id,			\
@@ -40,17 +40,10 @@
 		.enable_reg	= TPS65217_REG_ENABLE,	\
 		.enable_mask	= _em,			\
 		.volt_table	= _t,			\
+		.linear_ranges	= _lr,			\
+		.n_linear_ranges = _nlr,		\
 	}						\
 
-#define TPS65217_INFO(_nm, _min, _max, _f1, _f2)	\
-	{						\
-		.name		= _nm,			\
-		.min_uV		= _min,			\
-		.max_uV		= _max,			\
-		.vsel_to_uv	= _f1,			\
-		.uv_to_vsel	= _f2,			\
-	}
-
 static const unsigned int LDO1_VSEL_table[] = {
 	1000000, 1100000, 1200000, 1250000,
 	1300000, 1350000, 1400000, 1500000,
@@ -58,88 +51,26 @@
 	2800000, 3000000, 3100000, 3300000,
 };
 
-static int tps65217_vsel_to_uv1(unsigned int vsel)
-{
-	int uV = 0;
+static const struct regulator_linear_range tps65217_uv1_ranges[] = {
+	{ .min_uV = 900000, .max_uV = 1500000, .min_sel =  0, .max_sel = 24,
+	  .uV_step = 25000 },
+	{ .min_uV = 1550000, .max_uV = 1800000, .min_sel = 25, .max_sel = 30,
+	  .uV_step = 50000 },
+	{ .min_uV = 1850000, .max_uV = 2900000, .min_sel = 31, .max_sel = 52,
+	  .uV_step = 50000 },
+	{ .min_uV = 3000000, .max_uV = 3200000, .min_sel = 53, .max_sel = 55,
+	  .uV_step = 100000 },
+	{ .min_uV = 3300000, .max_uV = 3300000, .min_sel = 56, .max_sel = 62,
+	  .uV_step = 0 },
+};
 
-	if (vsel > 63)
-		return -EINVAL;
-
-	if (vsel <= 24)
-		uV = vsel * 25000 + 900000;
-	else if (vsel <= 52)
-		uV = (vsel - 24) * 50000 + 1500000;
-	else if (vsel < 56)
-		uV = (vsel - 52) * 100000 + 2900000;
-	else
-		uV = 3300000;
-
-	return uV;
-}
-
-static int tps65217_uv_to_vsel1(int uV, unsigned int *vsel)
-{
-	if (uV < 0 || uV > 3300000)
-		return -EINVAL;
-
-	if (uV <= 1500000)
-		*vsel = DIV_ROUND_UP(uV - 900000, 25000);
-	else if (uV <= 2900000)
-		*vsel = 24 + DIV_ROUND_UP(uV - 1500000, 50000);
-	else if (uV < 3300000)
-		*vsel = 52 + DIV_ROUND_UP(uV - 2900000, 100000);
-	else
-		*vsel = 56;
-
-	return 0;
-}
-
-static int tps65217_vsel_to_uv2(unsigned int vsel)
-{
-	int uV = 0;
-
-	if (vsel > 31)
-		return -EINVAL;
-
-	if (vsel <= 8)
-		uV = vsel * 50000 + 1500000;
-	else if (vsel <= 13)
-		uV = (vsel - 8) * 100000 + 1900000;
-	else
-		uV = (vsel - 13) * 50000 + 2400000;
-
-	return uV;
-}
-
-static int tps65217_uv_to_vsel2(int uV, unsigned int *vsel)
-{
-	if (uV < 0 || uV > 3300000)
-		return -EINVAL;
-
-	if (uV <= 1900000)
-		*vsel = DIV_ROUND_UP(uV - 1500000, 50000);
-	else if (uV <= 2400000)
-		*vsel = 8 + DIV_ROUND_UP(uV - 1900000, 100000);
-	else
-		*vsel = 13 + DIV_ROUND_UP(uV - 2400000, 50000);
-
-	return 0;
-}
-
-static struct tps_info tps65217_pmic_regs[] = {
-	TPS65217_INFO("DCDC1", 900000, 1800000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1),
-	TPS65217_INFO("DCDC2", 900000, 3300000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1),
-	TPS65217_INFO("DCDC3", 900000, 1500000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1),
-	TPS65217_INFO("LDO1", 1000000, 3300000, NULL, NULL),
-	TPS65217_INFO("LDO2", 900000, 3300000, tps65217_vsel_to_uv1,
-			tps65217_uv_to_vsel1),
-	TPS65217_INFO("LDO3", 1800000, 3300000, tps65217_vsel_to_uv2,
-			tps65217_uv_to_vsel2),
-	TPS65217_INFO("LDO4", 1800000, 3300000, tps65217_vsel_to_uv2,
-			tps65217_uv_to_vsel2),
+static const struct regulator_linear_range tps65217_uv2_ranges[] = {
+	{ .min_uV = 1500000, .max_uV = 1900000, .min_sel =  0, .max_sel = 8,
+	  .uV_step = 50000 },
+	{ .min_uV = 2000000, .max_uV = 2400000, .min_sel = 9, .max_sel = 13,
+	  .uV_step = 100000 },
+	{ .min_uV = 2450000, .max_uV = 3300000, .min_sel = 14, .max_sel = 31,
+	  .uV_step = 50000 },
 };
 
 static int tps65217_pmic_enable(struct regulator_dev *dev)
@@ -192,49 +123,6 @@
 	return ret;
 }
 
-static int tps65217_pmic_map_voltage(struct regulator_dev *dev,
-				     int min_uV, int max_uV)
-{
-
-	struct tps65217 *tps = rdev_get_drvdata(dev);
-	unsigned int sel, rid = rdev_get_id(dev);
-	int ret;
-
-	/* LDO1 uses regulator_map_voltage_iterate() */
-	if (rid == TPS65217_LDO_1)
-		return -EINVAL;
-
-	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
-		return -EINVAL;
-
-	if (min_uV < tps->info[rid]->min_uV)
-		min_uV = tps->info[rid]->min_uV;
-
-	if (max_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
-		return -EINVAL;
-
-	ret = tps->info[rid]->uv_to_vsel(min_uV, &sel);
-	if (ret)
-		return ret;
-
-	return sel;
-}
-
-static int tps65217_pmic_list_voltage(struct regulator_dev *dev,
-					unsigned selector)
-{
-	struct tps65217 *tps = rdev_get_drvdata(dev);
-	unsigned int rid = rdev_get_id(dev);
-
-	if (rid < TPS65217_DCDC_1 || rid > TPS65217_LDO_4)
-		return -EINVAL;
-
-	if (selector >= dev->desc->n_voltages)
-		return -EINVAL;
-
-	return tps->info[rid]->vsel_to_uv(selector);
-}
-
 /* Operations permitted on DCDCx, LDO2, LDO3 and LDO4 */
 static struct regulator_ops tps65217_pmic_ops = {
 	.is_enabled		= regulator_is_enabled_regmap,
@@ -242,8 +130,8 @@
 	.disable		= tps65217_pmic_disable,
 	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
 	.set_voltage_sel	= tps65217_pmic_set_voltage_sel,
-	.list_voltage		= tps65217_pmic_list_voltage,
-	.map_voltage		= tps65217_pmic_map_voltage,
+	.list_voltage		= regulator_list_voltage_linear_range,
+	.map_voltage		= regulator_map_voltage_linear_range,
 };
 
 /* Operations permitted on LDO1 */
@@ -259,27 +147,33 @@
 static const struct regulator_desc regulators[] = {
 	TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, tps65217_pmic_ops, 64,
 			   TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK,
-			   TPS65217_ENABLE_DC1_EN, NULL),
+			   TPS65217_ENABLE_DC1_EN, NULL, tps65217_uv1_ranges,
+			   2),	/* DCDC1 voltage range: 900000 ~ 1800000 */
 	TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, tps65217_pmic_ops, 64,
 			   TPS65217_REG_DEFDCDC2, TPS65217_DEFDCDCX_DCDC_MASK,
-			   TPS65217_ENABLE_DC2_EN, NULL),
+			   TPS65217_ENABLE_DC2_EN, NULL, tps65217_uv1_ranges,
+			   ARRAY_SIZE(tps65217_uv1_ranges)),
 	TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, tps65217_pmic_ops, 64,
 			   TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK,
-			   TPS65217_ENABLE_DC3_EN, NULL),
+			   TPS65217_ENABLE_DC3_EN, NULL, tps65217_uv1_ranges,
+			   1),	/* DCDC3 voltage range: 900000 ~ 1500000 */
 	TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, tps65217_pmic_ldo1_ops, 16,
 			   TPS65217_REG_DEFLDO1, TPS65217_DEFLDO1_LDO1_MASK,
-			   TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table),
+			   TPS65217_ENABLE_LDO1_EN, LDO1_VSEL_table, NULL, 0),
 	TPS65217_REGULATOR("LDO2", TPS65217_LDO_2, tps65217_pmic_ops, 64,
 			   TPS65217_REG_DEFLDO2, TPS65217_DEFLDO2_LDO2_MASK,
-			   TPS65217_ENABLE_LDO2_EN, NULL),
+			   TPS65217_ENABLE_LDO2_EN, NULL, tps65217_uv1_ranges,
+			   ARRAY_SIZE(tps65217_uv1_ranges)),
 	TPS65217_REGULATOR("LDO3", TPS65217_LDO_3, tps65217_pmic_ops, 32,
 			   TPS65217_REG_DEFLS1, TPS65217_DEFLDO3_LDO3_MASK,
 			   TPS65217_ENABLE_LS1_EN | TPS65217_DEFLDO3_LDO3_EN,
-			   NULL),
+			   NULL, tps65217_uv2_ranges,
+			   ARRAY_SIZE(tps65217_uv2_ranges)),
 	TPS65217_REGULATOR("LDO4", TPS65217_LDO_4, tps65217_pmic_ops, 32,
 			   TPS65217_REG_DEFLS2, TPS65217_DEFLDO4_LDO4_MASK,
 			   TPS65217_ENABLE_LS2_EN | TPS65217_DEFLDO4_LDO4_EN,
-			   NULL),
+			   NULL, tps65217_uv2_ranges,
+			   ARRAY_SIZE(tps65217_uv2_ranges)),
 };
 
 #ifdef CONFIG_OF
@@ -368,8 +262,6 @@
 			continue;
 
 		/* Register the regulators */
-		tps->info[i] = &tps65217_pmic_regs[i];
-
 		config.dev = tps->dev;
 		config.init_data = reg_data;
 		config.driver_data = tps;
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 1094393..62e8d28 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -601,7 +601,7 @@
 	struct regulator_config config = { };
 	int ret = 0, i;
 
-	init_data = dev->platform_data;
+	init_data = dev_get_platdata(dev);
 	if (!init_data) {
 		dev_err(dev, "could not find regulator platform data\n");
 		return -EINVAL;
diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c
index 17e994e..281e52a 100644
--- a/drivers/regulator/tps65912-regulator.c
+++ b/drivers/regulator/tps65912-regulator.c
@@ -118,6 +118,15 @@
 	int eco_reg;
 };
 
+static const struct regulator_linear_range tps65912_ldo_ranges[] = {
+	{ .min_uV = 800000, .max_uV = 1600000, .min_sel =  0, .max_sel = 32,
+	  .uV_step = 25000 },
+	{ .min_uV = 1650000, .max_uV = 3000000, .min_sel = 33, .max_sel = 60,
+	  .uV_step = 50000 },
+	{ .min_uV = 3100000, .max_uV = 3300000, .min_sel = 61, .max_sel = 63,
+	  .uV_step = 100000 },
+};
+
 static int tps65912_get_range(struct tps65912_reg *pmic, int id)
 {
 	struct tps65912 *mfd = pmic->mfd;
@@ -184,20 +193,6 @@
 	return uv;
 }
 
-static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel)
-{
-	unsigned long uv = 0;
-
-	if (vsel <= 32)
-		uv = ((vsel * 25000) + 800000);
-	else if (vsel > 32 && vsel <= 60)
-		uv = (((vsel - 32) * 50000) + 1600000);
-	else if (vsel > 60)
-		uv = (((vsel - 60) * 100000) + 3000000);
-
-	return uv;
-}
-
 static int tps65912_get_ctrl_register(int id)
 {
 	if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4)
@@ -376,9 +371,6 @@
 	struct tps65912_reg *pmic = rdev_get_drvdata(dev);
 	int range, voltage = 0, id = rdev_get_id(dev);
 
-	if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10)
-		return tps65912_vsel_to_uv_ldo(selector);
-
 	if (id > TPS65912_REG_DCDC4)
 		return -EINVAL;
 
@@ -456,7 +448,8 @@
 	.disable = tps65912_reg_disable,
 	.get_voltage_sel = tps65912_get_voltage_sel,
 	.set_voltage_sel = tps65912_set_voltage_sel,
-	.list_voltage = tps65912_list_voltage,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
 };
 
 static int tps65912_probe(struct platform_device *pdev)
@@ -495,8 +488,14 @@
 		pmic->desc[i].name = info->name;
 		pmic->desc[i].id = i;
 		pmic->desc[i].n_voltages = 64;
-		pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ?
-			&tps65912_ops_ldo : &tps65912_ops_dcdc);
+		if (i > TPS65912_REG_DCDC4) {
+			pmic->desc[i].ops = &tps65912_ops_ldo;
+			pmic->desc[i].linear_ranges = tps65912_ldo_ranges;
+			pmic->desc[i].n_linear_ranges =
+					ARRAY_SIZE(tps65912_ldo_ranges);
+		} else {
+			pmic->desc[i].ops = &tps65912_ops_dcdc;
+		}
 		pmic->desc[i].type = REGULATOR_VOLTAGE;
 		pmic->desc[i].owner = THIS_MODULE;
 		range = tps65912_get_range(pmic, i);
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 93bc4f4..78aae4c 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -1108,7 +1108,7 @@
 		drvdata = NULL;
 	} else {
 		id = pdev->id;
-		initdata = pdev->dev.platform_data;
+		initdata = dev_get_platdata(&pdev->dev);
 		for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
 			template = twl_of_match[i].data;
 			if (template && template->desc.id == id)
diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c
index a7c8deb..765acc1 100644
--- a/drivers/regulator/userspace-consumer.c
+++ b/drivers/regulator/userspace-consumer.c
@@ -111,7 +111,7 @@
 	struct userspace_consumer_data *drvdata;
 	int ret;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata)
 		return -EINVAL;
 
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index a9d4284..f53e78b 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -287,7 +287,7 @@
 
 static int regulator_virtual_probe(struct platform_device *pdev)
 {
-	char *reg_id = pdev->dev.platform_data;
+	char *reg_id = dev_get_platdata(&pdev->dev);
 	struct virtual_consumer_data *drvdata;
 	int ret;
 
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index 46938cf..11861cb 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -451,7 +451,7 @@
 static int wm831x_buckv_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id;
 	struct wm831x_dcdc *dcdc;
@@ -624,7 +624,7 @@
 static int wm831x_buckp_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id;
 	struct wm831x_dcdc *dcdc;
@@ -770,7 +770,7 @@
 static int wm831x_boostp_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
 	struct wm831x_dcdc *dcdc;
@@ -880,7 +880,7 @@
 static int wm831x_epe_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id = pdev->id % ARRAY_SIZE(pdata->epe);
 	struct wm831x_dcdc *dcdc;
diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c
index 16ebdf9..4eb373d 100644
--- a/drivers/regulator/wm831x-isink.c
+++ b/drivers/regulator/wm831x-isink.c
@@ -151,7 +151,7 @@
 static int wm831x_isink_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct wm831x_isink *isink;
 	int id = pdev->id % ARRAY_SIZE(pdata->isink);
 	struct regulator_config config = { };
diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c
index 9ff883f..1432b26 100644
--- a/drivers/regulator/wm831x-ldo.c
+++ b/drivers/regulator/wm831x-ldo.c
@@ -62,41 +62,12 @@
  * General purpose LDOs
  */
 
-#define WM831X_GP_LDO_SELECTOR_LOW 0xe
-#define WM831X_GP_LDO_MAX_SELECTOR 0x1f
-
-static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
-				      unsigned int selector)
-{
-	/* 0.9-1.6V in 50mV steps */
-	if (selector <= WM831X_GP_LDO_SELECTOR_LOW)
-		return 900000 + (selector * 50000);
-	/* 1.7-3.3V in 100mV steps */
-	if (selector <= WM831X_GP_LDO_MAX_SELECTOR)
-		return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW)
-				  * 100000);
-	return -EINVAL;
-}
-
-static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
-				     int min_uV, int max_uV)
-{
-	int volt, vsel;
-
-	if (min_uV < 900000)
-		vsel = 0;
-	else if (min_uV < 1700000)
-		vsel = ((min_uV - 900000) / 50000);
-	else
-		vsel = ((min_uV - 1700000) / 100000)
-			+ WM831X_GP_LDO_SELECTOR_LOW + 1;
-
-	volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
-	if (volt < min_uV || volt > max_uV)
-		return -EINVAL;
-
-	return vsel;
-}
+static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
+	{ .min_uV =  900000, .max_uV = 1650000, .min_sel =  0, .max_sel = 14,
+	  .uV_step =  50000 },
+	{ .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
+	  .uV_step = 100000 },
+};
 
 static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
 					     int uV)
@@ -105,7 +76,7 @@
 	struct wm831x *wm831x = ldo->wm831x;
 	int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
 
-	sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
+	sel = regulator_map_voltage_linear_range(rdev, uV, uV);
 	if (sel < 0)
 		return sel;
 
@@ -230,8 +201,8 @@
 
 
 static struct regulator_ops wm831x_gp_ldo_ops = {
-	.list_voltage = wm831x_gp_ldo_list_voltage,
-	.map_voltage = wm831x_gp_ldo_map_voltage,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
@@ -250,7 +221,7 @@
 static int wm831x_gp_ldo_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id;
 	struct wm831x_ldo *ldo;
@@ -290,7 +261,7 @@
 
 	ldo->desc.id = id;
 	ldo->desc.type = REGULATOR_VOLTAGE;
-	ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
+	ldo->desc.n_voltages = 32;
 	ldo->desc.ops = &wm831x_gp_ldo_ops;
 	ldo->desc.owner = THIS_MODULE;
 	ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
@@ -299,6 +270,8 @@
 	ldo->desc.enable_mask = 1 << id;
 	ldo->desc.bypass_reg = ldo->base;
 	ldo->desc.bypass_mask = WM831X_LDO1_SWI;
+	ldo->desc.linear_ranges = wm831x_gp_ldo_ranges;
+	ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges);
 
 	config.dev = pdev->dev.parent;
 	if (pdata)
@@ -358,43 +331,12 @@
  * Analogue LDOs
  */
 
-
-#define WM831X_ALDO_SELECTOR_LOW 0xc
-#define WM831X_ALDO_MAX_SELECTOR 0x1f
-
-static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
-				      unsigned int selector)
-{
-	/* 1-1.6V in 50mV steps */
-	if (selector <= WM831X_ALDO_SELECTOR_LOW)
-		return 1000000 + (selector * 50000);
-	/* 1.7-3.5V in 100mV steps */
-	if (selector <= WM831X_ALDO_MAX_SELECTOR)
-		return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
-				  * 100000);
-	return -EINVAL;
-}
-
-static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
-				   int min_uV, int max_uV)
-{
-	int volt, vsel;
-
-	if (min_uV < 1000000)
-		vsel = 0;
-	else if (min_uV < 1700000)
-		vsel = ((min_uV - 1000000) / 50000);
-	else
-		vsel = ((min_uV - 1700000) / 100000)
-			+ WM831X_ALDO_SELECTOR_LOW + 1;
-
-	volt = wm831x_aldo_list_voltage(rdev, vsel);
-	if (volt < min_uV || volt > max_uV)
-		return -EINVAL;
-
-	return vsel;
-
-}
+static const struct regulator_linear_range wm831x_aldo_ranges[] = {
+	{ .min_uV = 1000000, .max_uV = 1650000, .min_sel =  0, .max_sel = 12,
+	  .uV_step =  50000 },
+	{ .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31,
+	  .uV_step = 100000 },
+};
 
 static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
 					     int uV)
@@ -403,7 +345,7 @@
 	struct wm831x *wm831x = ldo->wm831x;
 	int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
 
-	sel = wm831x_aldo_map_voltage(rdev, uV, uV);
+	sel = regulator_map_voltage_linear_range(rdev, uV, uV);
 	if (sel < 0)
 		return sel;
 
@@ -486,8 +428,8 @@
 }
 
 static struct regulator_ops wm831x_aldo_ops = {
-	.list_voltage = wm831x_aldo_list_voltage,
-	.map_voltage = wm831x_aldo_map_voltage,
+	.list_voltage = regulator_list_voltage_linear_range,
+	.map_voltage = regulator_map_voltage_linear_range,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
@@ -505,7 +447,7 @@
 static int wm831x_aldo_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id;
 	struct wm831x_ldo *ldo;
@@ -545,7 +487,9 @@
 
 	ldo->desc.id = id;
 	ldo->desc.type = REGULATOR_VOLTAGE;
-	ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
+	ldo->desc.n_voltages = 32;
+	ldo->desc.linear_ranges = wm831x_aldo_ranges;
+	ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges);
 	ldo->desc.ops = &wm831x_aldo_ops;
 	ldo->desc.owner = THIS_MODULE;
 	ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
@@ -661,7 +605,7 @@
 static int wm831x_alive_ldo_probe(struct platform_device *pdev)
 {
 	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
-	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+	struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
 	struct regulator_config config = { };
 	int id;
 	struct wm831x_ldo *ldo;
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 7f0fa22..835b5f0 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -542,41 +542,12 @@
 	return 0;
 }
 
-static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	if (selector > WM8350_LDO1_VSEL_MASK)
-		return -EINVAL;
-
-	if (selector < 16)
-		return (selector * 50000) + 900000;
-	else
-		return ((selector - 16) * 100000) + 1800000;
-}
-
-static int wm8350_ldo_map_voltage(struct regulator_dev *rdev, int min_uV,
-				  int max_uV)
-{
-	int volt, sel;
-	int min_mV = min_uV / 1000;
-	int max_mV = max_uV / 1000;
-
-	if (min_mV < 900 || min_mV > 3300)
-		return -EINVAL;
-	if (max_mV < 900 || max_mV > 3300)
-		return -EINVAL;
-
-	if (min_mV < 1800) /* step size is 50mV < 1800mV */
-		sel = DIV_ROUND_UP(min_uV - 900, 50);
-	else /* step size is 100mV > 1800mV */
-		sel = DIV_ROUND_UP(min_uV - 1800, 100) + 16;
-
-	volt = wm8350_ldo_list_voltage(rdev, sel);
-	if (volt < min_uV || volt > max_uV)
-		return -EINVAL;
-
-	return sel;
-}
+static const struct regulator_linear_range wm8350_ldo_ranges[] = {
+	{ .min_uV =  900000, .max_uV = 1750000, .min_sel =  0, .max_sel = 15,
+	  .uV_step =  50000 },
+	{ .min_uV = 1800000, .max_uV = 3300000, .min_sel = 16, .max_sel = 31,
+	  .uV_step = 100000 },
+};
 
 static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
 {
@@ -603,7 +574,7 @@
 		return -EINVAL;
 	}
 
-	sel = wm8350_ldo_map_voltage(rdev, uV, uV);
+	sel = regulator_map_voltage_linear_range(rdev, uV, uV);
 	if (sel < 0)
 		return -EINVAL;
 
@@ -998,10 +969,10 @@
 };
 
 static struct regulator_ops wm8350_ldo_ops = {
-	.map_voltage = wm8350_ldo_map_voltage,
+	.map_voltage = regulator_map_voltage_linear_range,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.list_voltage = wm8350_ldo_list_voltage,
+	.list_voltage = regulator_list_voltage_linear_range,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
 	.is_enabled = regulator_is_enabled_regmap,
@@ -1108,6 +1079,8 @@
 		.irq = WM8350_IRQ_UV_LDO1,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
+		.linear_ranges = wm8350_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
 		.vsel_reg = WM8350_LDO1_CONTROL,
 		.vsel_mask = WM8350_LDO1_VSEL_MASK,
 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1121,6 +1094,8 @@
 		.irq = WM8350_IRQ_UV_LDO2,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
+		.linear_ranges = wm8350_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
 		.vsel_reg = WM8350_LDO2_CONTROL,
 		.vsel_mask = WM8350_LDO2_VSEL_MASK,
 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1134,6 +1109,8 @@
 		.irq = WM8350_IRQ_UV_LDO3,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
+		.linear_ranges = wm8350_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
 		.vsel_reg = WM8350_LDO3_CONTROL,
 		.vsel_mask = WM8350_LDO3_VSEL_MASK,
 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1147,6 +1124,8 @@
 		.irq = WM8350_IRQ_UV_LDO4,
 		.type = REGULATOR_VOLTAGE,
 		.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
+		.linear_ranges = wm8350_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8350_ldo_ranges),
 		.vsel_reg = WM8350_LDO4_CONTROL,
 		.vsel_mask = WM8350_LDO4_VSEL_MASK,
 		.enable_reg = WM8350_DCDC_LDO_REQUESTED,
@@ -1222,7 +1201,7 @@
 	}
 
 	config.dev = &pdev->dev;
-	config.init_data = pdev->dev.platform_data;
+	config.init_data = dev_get_platdata(&pdev->dev);
 	config.driver_data = dev_get_drvdata(&pdev->dev);
 	config.regmap = wm8350->regmap;
 
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index a09f03e..58f51be 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -19,47 +19,21 @@
 #include <linux/regulator/driver.h>
 #include <linux/mfd/wm8400-private.h>
 
-static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
-				   unsigned selector)
-{
-	if (selector > WM8400_LDO1_VSEL_MASK)
-		return -EINVAL;
-
-	if (selector < 15)
-		return 900000 + (selector * 50000);
-	else
-		return 1700000 + ((selector - 15) * 100000);
-}
-
-static int wm8400_ldo_map_voltage(struct regulator_dev *dev,
-				  int min_uV, int max_uV)
-{
-	u16 val;
-	int volt;
-
-	if (min_uV < 900000 || min_uV > 3300000)
-		return -EINVAL;
-
-	if (min_uV < 1700000) /* Steps of 50mV from 900mV;  */
-		val = DIV_ROUND_UP(min_uV - 900000, 50000);
-	else /* Steps of 100mV from 1700mV */
-		val = DIV_ROUND_UP(min_uV - 1700000, 100000) + 15;
-
-	volt = wm8400_ldo_list_voltage(dev, val);
-	if (volt < min_uV || volt > max_uV)
-		return -EINVAL;
-
-	return val;
-}
+static const struct regulator_linear_range wm8400_ldo_ranges[] = {
+	{ .min_uV =  900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14,
+	  .uV_step =  50000 },
+	{ .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
+	  .uV_step = 100000 },
+};
 
 static struct regulator_ops wm8400_ldo_ops = {
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
 	.disable = regulator_disable_regmap,
-	.list_voltage = wm8400_ldo_list_voltage,
+	.list_voltage = regulator_list_voltage_linear_range,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
-	.map_voltage = wm8400_ldo_map_voltage,
+	.map_voltage = regulator_map_voltage_linear_range,
 };
 
 static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
@@ -155,6 +129,8 @@
 		.enable_reg = WM8400_LDO1_CONTROL,
 		.enable_mask = WM8400_LDO1_ENA,
 		.n_voltages = WM8400_LDO1_VSEL_MASK + 1,
+		.linear_ranges = wm8400_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
 		.vsel_reg = WM8400_LDO1_CONTROL,
 		.vsel_mask = WM8400_LDO1_VSEL_MASK,
 		.type = REGULATOR_VOLTAGE,
@@ -167,6 +143,8 @@
 		.enable_reg = WM8400_LDO2_CONTROL,
 		.enable_mask = WM8400_LDO2_ENA,
 		.n_voltages = WM8400_LDO2_VSEL_MASK + 1,
+		.linear_ranges = wm8400_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
 		.type = REGULATOR_VOLTAGE,
 		.vsel_reg = WM8400_LDO2_CONTROL,
 		.vsel_mask = WM8400_LDO2_VSEL_MASK,
@@ -179,6 +157,8 @@
 		.enable_reg = WM8400_LDO3_CONTROL,
 		.enable_mask = WM8400_LDO3_ENA,
 		.n_voltages = WM8400_LDO3_VSEL_MASK + 1,
+		.linear_ranges = wm8400_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
 		.vsel_reg = WM8400_LDO3_CONTROL,
 		.vsel_mask = WM8400_LDO3_VSEL_MASK,
 		.type = REGULATOR_VOLTAGE,
@@ -191,6 +171,8 @@
 		.enable_reg = WM8400_LDO4_CONTROL,
 		.enable_mask = WM8400_LDO4_ENA,
 		.n_voltages = WM8400_LDO4_VSEL_MASK + 1,
+		.linear_ranges = wm8400_ldo_ranges,
+		.n_linear_ranges = ARRAY_SIZE(wm8400_ldo_ranges),
 		.vsel_reg = WM8400_LDO4_CONTROL,
 		.vsel_mask = WM8400_LDO4_VSEL_MASK,
 		.type = REGULATOR_VOLTAGE,
@@ -233,7 +215,7 @@
 	struct regulator_dev *rdev;
 
 	config.dev = &pdev->dev;
-	config.init_data = pdev->dev.platform_data;
+	config.init_data = dev_get_platdata(&pdev->dev);
 	config.driver_data = wm8400;
 	config.regmap = wm8400->regmap;
 
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 8f2a8a7..5ee2a20 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -125,7 +125,7 @@
 static int wm8994_ldo_probe(struct platform_device *pdev)
 {
 	struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
-	struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+	struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
 	int id = pdev->id % ARRAY_SIZE(pdata->ldo);
 	struct regulator_config config = { };
 	struct wm8994_ldo *ldo;
diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
index 9b2e60a..129f7b9 100644
--- a/drivers/remoteproc/da8xx_remoteproc.c
+++ b/drivers/remoteproc/da8xx_remoteproc.c
@@ -165,7 +165,7 @@
 	dsp_clk = clk_get(dev, NULL);
 	if (IS_ERR(dsp_clk)) {
 		dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk));
-		return PTR_RET(dsp_clk);
+		return PTR_ERR(dsp_clk);
 	}
 
 	davinci_clk_reset_assert(dsp_clk);
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
index 9c8c194..4385ca4 100644
--- a/drivers/rtc/rtc-da9052.c
+++ b/drivers/rtc/rtc-da9052.c
@@ -250,7 +250,7 @@
 
 	rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
 				       &da9052_rtc_ops, THIS_MODULE);
-	return PTR_RET(rtc->rtc);
+	return PTR_ERR_OR_ZERO(rtc->rtc);
 }
 
 static struct platform_driver da9052_rtc_driver = {
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 5dbdc44..03b8911 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -268,7 +268,7 @@
 	isl12022->rtc = devm_rtc_device_register(&client->dev,
 					isl12022_driver.driver.name,
 					&isl12022_rtc_ops, THIS_MODULE);
-	return PTR_RET(isl12022->rtc);
+	return PTR_ERR_OR_ZERO(isl12022->rtc);
 }
 
 static const struct i2c_device_id isl12022_id[] = {
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index 23c3779..411adb3 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -175,7 +175,7 @@
 
 	priv->rtc = devm_rtc_device_register(&pdev->dev, "m48t35",
 				  &m48t35_ops, THIS_MODULE);
-	return PTR_RET(priv->rtc);
+	return PTR_ERR_OR_ZERO(priv->rtc);
 }
 
 static struct platform_driver m48t35_platform_driver = {
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 710c3a5..63b558c 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -264,7 +264,7 @@
 				pcf8563_driver.driver.name,
 				&pcf8563_rtc_ops, THIS_MODULE);
 
-	return PTR_RET(pcf8563->rtc);
+	return PTR_ERR_OR_ZERO(pcf8563->rtc);
 }
 
 static const struct i2c_device_id pcf8563_id[] = {
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 843a745..c263984 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -285,7 +285,7 @@
 				pcf8583_driver.driver.name,
 				&pcf8583_rtc_ops, THIS_MODULE);
 
-	return PTR_RET(pcf8583->rtc);
+	return PTR_ERR_OR_ZERO(pcf8583->rtc);
 }
 
 static const struct i2c_device_id pcf8583_id[] = {
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 4b26f86..babd43b 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -25,15 +25,14 @@
  */
 
 static ssize_t
-rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
-		char *buf)
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
 }
+static DEVICE_ATTR_RO(name);
 
 static ssize_t
-rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
-		char *buf)
+date_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	ssize_t retval;
 	struct rtc_time tm;
@@ -46,10 +45,10 @@
 
 	return retval;
 }
+static DEVICE_ATTR_RO(date);
 
 static ssize_t
-rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
-		char *buf)
+time_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	ssize_t retval;
 	struct rtc_time tm;
@@ -62,10 +61,10 @@
 
 	return retval;
 }
+static DEVICE_ATTR_RO(time);
 
 static ssize_t
-rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
-		char *buf)
+since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	ssize_t retval;
 	struct rtc_time tm;
@@ -79,16 +78,16 @@
 
 	return retval;
 }
+static DEVICE_ATTR_RO(since_epoch);
 
 static ssize_t
-rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
-		char *buf)
+max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
 }
 
 static ssize_t
-rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
+max_user_freq_store(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t n)
 {
 	struct rtc_device *rtc = to_rtc_device(dev);
@@ -101,6 +100,7 @@
 
 	return n;
 }
+static DEVICE_ATTR_RW(max_user_freq);
 
 /**
  * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time
@@ -109,8 +109,7 @@
  * boot or resume event.
  */
 static ssize_t
-rtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
-		char *buf)
+hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 #ifdef CONFIG_RTC_HCTOSYS_DEVICE
 	if (rtc_hctosys_ret == 0 &&
@@ -121,17 +120,18 @@
 #endif
 		return sprintf(buf, "0\n");
 }
+static DEVICE_ATTR_RO(hctosys);
 
-static struct device_attribute rtc_attrs[] = {
-	__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
-	__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
-	__ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
-	__ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
-	__ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
-			rtc_sysfs_set_max_user_freq),
-	__ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
-	{ },
+static struct attribute *rtc_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_date.attr,
+	&dev_attr_time.attr,
+	&dev_attr_since_epoch.attr,
+	&dev_attr_max_user_freq.attr,
+	&dev_attr_hctosys.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(rtc);
 
 static ssize_t
 rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
@@ -261,5 +261,5 @@
 
 void __init rtc_sysfs_init(struct class *rtc_class)
 {
-	rtc_class->dev_attrs = rtc_attrs;
+	rtc_class->dev_groups = rtc_groups;
 }
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 58bc6eb..2ead7e7 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -930,7 +930,7 @@
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 
-	if ((strict_strtoul(buf, 10, &val) != 0) || val > 1)
+	if ((kstrtoul(buf, 10, &val) != 0) || val > 1)
 		return -EINVAL;
 
 	spin_lock(&dasd_devmap_lock);
@@ -1225,7 +1225,7 @@
 	if (IS_ERR(device))
 		return -ENODEV;
 
-	if ((strict_strtoul(buf, 10, &val) != 0) ||
+	if ((kstrtoul(buf, 10, &val) != 0) ||
 	    (val > DASD_EXPIRES_MAX) || val == 0) {
 		dasd_put_device(device);
 		return -EINVAL;
@@ -1265,7 +1265,7 @@
 	if (IS_ERR(device))
 		return -ENODEV;
 
-	if ((strict_strtoul(buf, 10, &val) != 0) ||
+	if ((kstrtoul(buf, 10, &val) != 0) ||
 	    (val > DASD_RETRIES_MAX)) {
 		dasd_put_device(device);
 		return -EINVAL;
@@ -1307,7 +1307,7 @@
 	if (IS_ERR(device) || !device->block)
 		return -ENODEV;
 
-	if ((strict_strtoul(buf, 10, &val) != 0) ||
+	if ((kstrtoul(buf, 10, &val) != 0) ||
 	    val > UINT_MAX / HZ) {
 		dasd_put_device(device);
 		return -EINVAL;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index e61a6de..5adb204 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -85,6 +85,8 @@
 
 static struct ccw_driver dasd_eckd_driver; /* see below */
 
+static void *rawpadpage;
+
 #define INIT_CQR_OK 0
 #define INIT_CQR_UNFORMATTED 1
 #define INIT_CQR_ERROR 2
@@ -3237,18 +3239,26 @@
 	unsigned int seg_len, len_to_track_end;
 	unsigned int first_offs;
 	unsigned int cidaw, cplength, datasize;
-	sector_t first_trk, last_trk;
+	sector_t first_trk, last_trk, sectors;
+	sector_t start_padding_sectors, end_sector_offset, end_padding_sectors;
 	unsigned int pfx_datasize;
 
 	/*
 	 * raw track access needs to be mutiple of 64k and on 64k boundary
+	 * For read requests we can fix an incorrect alignment by padding
+	 * the request with dummy pages.
 	 */
-	if ((blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK) != 0) {
-		cqr = ERR_PTR(-EINVAL);
-		goto out;
-	}
-	if (((blk_rq_pos(req) + blk_rq_sectors(req)) %
-	     DASD_RAW_SECTORS_PER_TRACK) != 0) {
+	start_padding_sectors = blk_rq_pos(req) % DASD_RAW_SECTORS_PER_TRACK;
+	end_sector_offset = (blk_rq_pos(req) + blk_rq_sectors(req)) %
+		DASD_RAW_SECTORS_PER_TRACK;
+	end_padding_sectors = (DASD_RAW_SECTORS_PER_TRACK - end_sector_offset) %
+		DASD_RAW_SECTORS_PER_TRACK;
+	basedev = block->base;
+	if ((start_padding_sectors || end_padding_sectors) &&
+	    (rq_data_dir(req) == WRITE)) {
+		DBF_DEV_EVENT(DBF_ERR, basedev,
+			      "raw write not track aligned (%lu,%lu) req %p",
+			      start_padding_sectors, end_padding_sectors, req);
 		cqr = ERR_PTR(-EINVAL);
 		goto out;
 	}
@@ -3258,7 +3268,6 @@
 		DASD_RAW_SECTORS_PER_TRACK;
 	trkcount = last_trk - first_trk + 1;
 	first_offs = 0;
-	basedev = block->base;
 
 	if (rq_data_dir(req) == READ)
 		cmd = DASD_ECKD_CCW_READ_TRACK;
@@ -3307,12 +3316,26 @@
 	}
 
 	idaws = (unsigned long *)(cqr->data + pfx_datasize);
-
 	len_to_track_end = 0;
-
+	if (start_padding_sectors) {
+		ccw[-1].flags |= CCW_FLAG_CC;
+		ccw->cmd_code = cmd;
+		/* maximum 3390 track size */
+		ccw->count = 57326;
+		/* 64k map to one track */
+		len_to_track_end = 65536 - start_padding_sectors * 512;
+		ccw->cda = (__u32)(addr_t)idaws;
+		ccw->flags |= CCW_FLAG_IDA;
+		ccw->flags |= CCW_FLAG_SLI;
+		ccw++;
+		for (sectors = 0; sectors < start_padding_sectors; sectors += 8)
+			idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE);
+	}
 	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
 		seg_len = bv->bv_len;
+		if (cmd == DASD_ECKD_CCW_READ_TRACK)
+			memset(dst, 0, seg_len);
 		if (!len_to_track_end) {
 			ccw[-1].flags |= CCW_FLAG_CC;
 			ccw->cmd_code = cmd;
@@ -3328,7 +3351,8 @@
 		len_to_track_end -= seg_len;
 		idaws = idal_create_words(idaws, dst, seg_len);
 	}
-
+	for (sectors = 0; sectors < end_padding_sectors; sectors += 8)
+		idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE);
 	if (blk_noretry_request(req) ||
 	    block->base->features & DASD_FEATURE_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
@@ -4479,12 +4503,19 @@
 		kfree(dasd_reserve_req);
 		return -ENOMEM;
 	}
+	rawpadpage = (void *)__get_free_page(GFP_KERNEL);
+	if (!rawpadpage) {
+		kfree(path_verification_worker);
+		kfree(dasd_reserve_req);
+		return -ENOMEM;
+	}
 	ret = ccw_driver_register(&dasd_eckd_driver);
 	if (!ret)
 		wait_for_device_probe();
 	else {
 		kfree(path_verification_worker);
 		kfree(dasd_reserve_req);
+		free_page((unsigned long)rawpadpage);
 	}
 	return ret;
 }
@@ -4495,6 +4526,7 @@
 	ccw_driver_unregister(&dasd_eckd_driver);
 	kfree(path_verification_worker);
 	kfree(dasd_reserve_req);
+	free_page((unsigned long)rawpadpage);
 }
 
 module_init(dasd_eckd_init);
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 8d11f77..e1e8848 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -124,10 +124,15 @@
 struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
 {
 	int success;
+	unsigned long long startclk, stopclk;
+	struct dasd_device *startdev;
 
 	BUG_ON(cqr->refers == NULL || cqr->function == NULL);
 
 	success = cqr->status == DASD_CQR_DONE;
+	startclk = cqr->startclk;
+	stopclk = cqr->stopclk;
+	startdev = cqr->startdev;
 
 	/* free all ERPs - but NOT the original cqr */
 	while (cqr->refers != NULL) {
@@ -142,6 +147,9 @@
 	}
 
 	/* set corresponding status to original cqr */
+	cqr->startclk = startclk;
+	cqr->stopclk = stopclk;
+	cqr->startdev = startdev;
 	if (success)
 		cqr->status = DASD_CQR_DONE;
 	else {
@@ -160,11 +168,13 @@
 
 	device = cqr->startdev;
 	if (cqr->intrc == -ETIMEDOUT) {
-		dev_err(&device->cdev->dev, "cqr %p timeout error", cqr);
+		dev_err(&device->cdev->dev,
+			"A timeout error occurred for cqr %p", cqr);
 		return;
 	}
 	if (cqr->intrc == -ENOLINK) {
-		dev_err(&device->cdev->dev, "cqr %p transport error", cqr);
+		dev_err(&device->cdev->dev,
+			"A transport error occurred for cqr %p", cqr);
 		return;
 	}
 	/* dump sense data */
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 444d361..9441562 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -32,7 +32,7 @@
 	struct device *dev;
 
 	s390_adjust_jiffies();
-	pr_warning("cpu capability changed.\n");
+	pr_info("CPU capability may have changed\n");
 	get_online_cpus();
 	for_each_online_cpu(cpu) {
 		dev = get_cpu_device(cpu);
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 91edbd7..d028fd8 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -81,15 +81,185 @@
 }
 EXPORT_SYMBOL(unregister_adapter_interrupt);
 
-void do_adapter_IO(u8 isc)
+static irqreturn_t do_airq_interrupt(int irq, void *dummy)
 {
+	struct tpi_info *tpi_info;
 	struct airq_struct *airq;
 	struct hlist_head *head;
 
-	head = &airq_lists[isc];
+	__this_cpu_write(s390_idle.nohz_delay, 1);
+	tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+	head = &airq_lists[tpi_info->isc];
 	rcu_read_lock();
 	hlist_for_each_entry_rcu(airq, head, list)
 		if ((*airq->lsi_ptr & airq->lsi_mask) != 0)
 			airq->handler(airq);
 	rcu_read_unlock();
+
+	return IRQ_HANDLED;
 }
+
+static struct irqaction airq_interrupt = {
+	.name	 = "AIO",
+	.handler = do_airq_interrupt,
+};
+
+void __init init_airq_interrupts(void)
+{
+	irq_set_chip_and_handler(THIN_INTERRUPT,
+				 &dummy_irq_chip, handle_percpu_irq);
+	setup_irq(THIN_INTERRUPT, &airq_interrupt);
+}
+
+/**
+ * airq_iv_create - create an interrupt vector
+ * @bits: number of bits in the interrupt vector
+ * @flags: allocation flags
+ *
+ * Returns a pointer to an interrupt vector structure
+ */
+struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags)
+{
+	struct airq_iv *iv;
+	unsigned long size;
+
+	iv = kzalloc(sizeof(*iv), GFP_KERNEL);
+	if (!iv)
+		goto out;
+	iv->bits = bits;
+	size = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+	iv->vector = kzalloc(size, GFP_KERNEL);
+	if (!iv->vector)
+		goto out_free;
+	if (flags & AIRQ_IV_ALLOC) {
+		iv->avail = kmalloc(size, GFP_KERNEL);
+		if (!iv->avail)
+			goto out_free;
+		memset(iv->avail, 0xff, size);
+		iv->end = 0;
+	} else
+		iv->end = bits;
+	if (flags & AIRQ_IV_BITLOCK) {
+		iv->bitlock = kzalloc(size, GFP_KERNEL);
+		if (!iv->bitlock)
+			goto out_free;
+	}
+	if (flags & AIRQ_IV_PTR) {
+		size = bits * sizeof(unsigned long);
+		iv->ptr = kzalloc(size, GFP_KERNEL);
+		if (!iv->ptr)
+			goto out_free;
+	}
+	if (flags & AIRQ_IV_DATA) {
+		size = bits * sizeof(unsigned int);
+		iv->data = kzalloc(size, GFP_KERNEL);
+		if (!iv->data)
+			goto out_free;
+	}
+	spin_lock_init(&iv->lock);
+	return iv;
+
+out_free:
+	kfree(iv->ptr);
+	kfree(iv->bitlock);
+	kfree(iv->avail);
+	kfree(iv->vector);
+	kfree(iv);
+out:
+	return NULL;
+}
+EXPORT_SYMBOL(airq_iv_create);
+
+/**
+ * airq_iv_release - release an interrupt vector
+ * @iv: pointer to interrupt vector structure
+ */
+void airq_iv_release(struct airq_iv *iv)
+{
+	kfree(iv->data);
+	kfree(iv->ptr);
+	kfree(iv->bitlock);
+	kfree(iv->vector);
+	kfree(iv->avail);
+	kfree(iv);
+}
+EXPORT_SYMBOL(airq_iv_release);
+
+/**
+ * airq_iv_alloc_bit - allocate an irq bit from an interrupt vector
+ * @iv: pointer to an interrupt vector structure
+ *
+ * Returns the bit number of the allocated irq, or -1UL if no bit
+ * is available or the AIRQ_IV_ALLOC flag has not been specified
+ */
+unsigned long airq_iv_alloc_bit(struct airq_iv *iv)
+{
+	const unsigned long be_to_le = BITS_PER_LONG - 1;
+	unsigned long bit;
+
+	if (!iv->avail)
+		return -1UL;
+	spin_lock(&iv->lock);
+	bit = find_first_bit_left(iv->avail, iv->bits);
+	if (bit < iv->bits) {
+		clear_bit(bit ^ be_to_le, iv->avail);
+		if (bit >= iv->end)
+			iv->end = bit + 1;
+	} else
+		bit = -1UL;
+	spin_unlock(&iv->lock);
+	return bit;
+
+}
+EXPORT_SYMBOL(airq_iv_alloc_bit);
+
+/**
+ * airq_iv_free_bit - free an irq bit of an interrupt vector
+ * @iv: pointer to interrupt vector structure
+ * @bit: number of the irq bit to free
+ */
+void airq_iv_free_bit(struct airq_iv *iv, unsigned long bit)
+{
+	const unsigned long be_to_le = BITS_PER_LONG - 1;
+
+	if (!iv->avail)
+		return;
+	spin_lock(&iv->lock);
+	/* Clear (possibly left over) interrupt bit */
+	clear_bit(bit ^ be_to_le, iv->vector);
+	/* Make the bit position available again */
+	set_bit(bit ^ be_to_le, iv->avail);
+	if (bit == iv->end - 1) {
+		/* Find new end of bit-field */
+		while (--iv->end > 0)
+			if (!test_bit((iv->end - 1) ^ be_to_le, iv->avail))
+				break;
+	}
+	spin_unlock(&iv->lock);
+}
+EXPORT_SYMBOL(airq_iv_free_bit);
+
+/**
+ * airq_iv_scan - scan interrupt vector for non-zero bits
+ * @iv: pointer to interrupt vector structure
+ * @start: bit number to start the search
+ * @end: bit number to end the search
+ *
+ * Returns the bit number of the next non-zero interrupt bit, or
+ * -1UL if the scan completed without finding any more any non-zero bits.
+ */
+unsigned long airq_iv_scan(struct airq_iv *iv, unsigned long start,
+			   unsigned long end)
+{
+	const unsigned long be_to_le = BITS_PER_LONG - 1;
+	unsigned long bit;
+
+	/* Find non-zero bit starting from 'ivs->next'. */
+	bit = find_next_bit_left(iv->vector, end, start);
+	if (bit >= end)
+		return -1UL;
+	/* Clear interrupt bit (find left uses big-endian bit numbers) */
+	clear_bit(bit ^ be_to_le, iv->vector);
+	return bit;
+}
+EXPORT_SYMBOL(airq_iv_scan);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 84846c2..959135a 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -137,7 +137,7 @@
 	if (!try_module_get(gdrv->driver.owner))
 		return -EINVAL;
 
-	ret = strict_strtoul(buf, 0, &value);
+	ret = kstrtoul(buf, 0, &value);
 	if (ret)
 		goto out;
 
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 4eeb4a6..d7da67a 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -561,37 +561,23 @@
 }
 
 /*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- *	    SMP cross-CPU interrupts have their own specific
- *	    handlers).
- *
+ * do_cio_interrupt() handles all normal I/O device IRQ's
  */
-void __irq_entry do_IRQ(struct pt_regs *regs)
+static irqreturn_t do_cio_interrupt(int irq, void *dummy)
 {
-	struct tpi_info *tpi_info = (struct tpi_info *) &regs->int_code;
+	struct tpi_info *tpi_info;
 	struct subchannel *sch;
 	struct irb *irb;
-	struct pt_regs *old_regs;
 
-	old_regs = set_irq_regs(regs);
-	irq_enter();
 	__this_cpu_write(s390_idle.nohz_delay, 1);
-	if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
-		/* Serve timer interrupts first. */
-		clock_comparator_work();
-
-	kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+	tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
 	irb = (struct irb *) &S390_lowcore.irb;
-	if (tpi_info->adapter_IO) {
-		do_adapter_IO(tpi_info->isc);
-		goto out;
-	}
 	sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
 	if (!sch) {
 		/* Clear pending interrupt condition. */
 		inc_irq_stat(IRQIO_CIO);
 		tsch(tpi_info->schid, irb);
-		goto out;
+		return IRQ_HANDLED;
 	}
 	spin_lock(sch->lock);
 	/* Store interrupt response block to lowcore. */
@@ -606,9 +592,23 @@
 	} else
 		inc_irq_stat(IRQIO_CIO);
 	spin_unlock(sch->lock);
-out:
-	irq_exit();
-	set_irq_regs(old_regs);
+
+	return IRQ_HANDLED;
+}
+
+static struct irq_desc *irq_desc_io;
+
+static struct irqaction io_interrupt = {
+	.name	 = "IO",
+	.handler = do_cio_interrupt,
+};
+
+void __init init_cio_interrupts(void)
+{
+	irq_set_chip_and_handler(IO_INTERRUPT,
+				 &dummy_irq_chip, handle_percpu_irq);
+	setup_irq(IO_INTERRUPT, &io_interrupt);
+	irq_desc_io = irq_to_desc(IO_INTERRUPT);
 }
 
 #ifdef CONFIG_CCW_CONSOLE
@@ -635,7 +635,7 @@
 		local_bh_disable();
 		irq_enter();
 	}
-	kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
+	kstat_incr_irqs_this_cpu(IO_INTERRUPT, irq_desc_io);
 	if (sch->driver && sch->driver->irq)
 		sch->driver->irq(sch);
 	else
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index d62f5e7..d42f674 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -121,9 +121,6 @@
 int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
 int cio_tm_intrg(struct subchannel *sch);
 
-void do_adapter_IO(u8 isc);
-void do_IRQ(struct pt_regs *);
-
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
 extern struct subchannel *cio_probe_console(void);
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 4495e06..23054f8 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1182,7 +1182,7 @@
 	int ret;
 	unsigned long val;
 
-	ret = strict_strtoul(buf, 16, &val);
+	ret = kstrtoul(buf, 16, &val);
 	if (ret)
 		return ret;
 
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 1ebe5d3..8c2cb87 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -546,7 +546,9 @@
 		case -ENOMEM:
 		case -EIO:
 			/* These should abort looping */
+			spin_lock_irq(&slow_subchannel_lock);
 			idset_sch_del_subseq(slow_subchannel_set, schid);
+			spin_unlock_irq(&slow_subchannel_lock);
 			break;
 		default:
 			rc = 0;
@@ -740,7 +742,7 @@
 	int ret;
 	unsigned long val;
 
-	ret = strict_strtoul(buf, 16, &val);
+	ret = kstrtoul(buf, 16, &val);
 	if (ret)
 		return ret;
 	mutex_lock(&css->mutex);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index b1de603..2935132 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -130,8 +130,6 @@
 
 extern struct channel_subsystem *channel_subsystems[];
 
-void channel_subsystem_reinit(void);
-
 /* Helper functions to build lists for the slow path. */
 void css_schedule_eval(struct subchannel_id schid);
 void css_schedule_eval_all(void);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 1ab5f6c..e4a7ab2 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -564,7 +564,7 @@
 		ret = 0;
 	} else {
 		force = 0;
-		ret = strict_strtoul(buf, 16, &i);
+		ret = kstrtoul(buf, 16, &i);
 	}
 	if (ret)
 		goto out;
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index d1c8025..adef5f5 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -208,7 +208,7 @@
 		goto out;
 	}
 
-	rc = strict_strtoul(buf, 16, &i);
+	rc = kstrtoul(buf, 16, &i);
 	if (rc) {
 		rc = -EINVAL;
 		goto out;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 1b9e4ae..8004b07 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -104,11 +104,11 @@
 	strncpy(busid, token, ZFCP_BUS_ID_SIZE);
 
 	token = strsep(&str, ",");
-	if (!token || strict_strtoull(token, 0, (unsigned long long *) &wwpn))
+	if (!token || kstrtoull(token, 0, (unsigned long long *) &wwpn))
 		goto err_out;
 
 	token = strsep(&str, ",");
-	if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun))
+	if (!token || kstrtoull(token, 0, (unsigned long long *) &lun))
 		goto err_out;
 
 	kfree(str_saved);
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 1d4c8fe..c82fe65 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -102,10 +102,13 @@
 
 	if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE)
 		zfcp_erp_action_dismiss(&port->erp_action);
-	else
-		shost_for_each_device(sdev, port->adapter->scsi_host)
+	else {
+		spin_lock(port->adapter->scsi_host->host_lock);
+		__shost_for_each_device(sdev, port->adapter->scsi_host)
 			if (sdev_to_zfcp(sdev)->port == port)
 				zfcp_erp_action_dismiss_lun(sdev);
+		spin_unlock(port->adapter->scsi_host->host_lock);
+	}
 }
 
 static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
@@ -592,9 +595,11 @@
 {
 	struct scsi_device *sdev;
 
-	shost_for_each_device(sdev, port->adapter->scsi_host)
+	spin_lock(port->adapter->scsi_host->host_lock);
+	__shost_for_each_device(sdev, port->adapter->scsi_host)
 		if (sdev_to_zfcp(sdev)->port == port)
 			_zfcp_erp_lun_reopen(sdev, clear, id, 0);
+	spin_unlock(port->adapter->scsi_host->host_lock);
 }
 
 static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act)
@@ -1434,8 +1439,10 @@
 		atomic_set_mask(common_mask, &port->status);
 	read_unlock_irqrestore(&adapter->port_list_lock, flags);
 
-	shost_for_each_device(sdev, adapter->scsi_host)
+	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+	__shost_for_each_device(sdev, adapter->scsi_host)
 		atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status);
+	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
 }
 
 /**
@@ -1469,11 +1476,13 @@
 	}
 	read_unlock_irqrestore(&adapter->port_list_lock, flags);
 
-	shost_for_each_device(sdev, adapter->scsi_host) {
+	spin_lock_irqsave(adapter->scsi_host->host_lock, flags);
+	__shost_for_each_device(sdev, adapter->scsi_host) {
 		atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status);
 		if (clear_counter)
 			atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
 	}
+	spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags);
 }
 
 /**
@@ -1487,16 +1496,19 @@
 {
 	struct scsi_device *sdev;
 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
+	unsigned long flags;
 
 	atomic_set_mask(mask, &port->status);
 
 	if (!common_mask)
 		return;
 
-	shost_for_each_device(sdev, port->adapter->scsi_host)
+	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
+	__shost_for_each_device(sdev, port->adapter->scsi_host)
 		if (sdev_to_zfcp(sdev)->port == port)
 			atomic_set_mask(common_mask,
 					&sdev_to_zfcp(sdev)->status);
+	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
 }
 
 /**
@@ -1511,6 +1523,7 @@
 	struct scsi_device *sdev;
 	u32 common_mask = mask & ZFCP_COMMON_FLAGS;
 	u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED;
+	unsigned long flags;
 
 	atomic_clear_mask(mask, &port->status);
 
@@ -1520,13 +1533,15 @@
 	if (clear_counter)
 		atomic_set(&port->erp_counter, 0);
 
-	shost_for_each_device(sdev, port->adapter->scsi_host)
+	spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags);
+	__shost_for_each_device(sdev, port->adapter->scsi_host)
 		if (sdev_to_zfcp(sdev)->port == port) {
 			atomic_clear_mask(common_mask,
 					  &sdev_to_zfcp(sdev)->status);
 			if (clear_counter)
 				atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0);
 		}
+	spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags);
 }
 
 /**
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 83e3f14..a9c570a 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -126,8 +126,6 @@
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);
 extern void zfcp_qdio_siosl(struct zfcp_adapter *);
-extern struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *,
-					     struct qdio_buffer *);
 
 /* zfcp_scsi.c */
 extern struct scsi_transport_template *zfcp_scsi_transport_template;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 510e9b0..0fe8d5d 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -770,7 +770,8 @@
 	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
-	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,
+	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
+				  SBAL_SFLAGS0_TYPE_STATUS,
 				  adapter->pool.status_read_req);
 	if (IS_ERR(req)) {
 		retval = PTR_ERR(req);
@@ -2387,12 +2388,3 @@
 			break;
 	}
 }
-
-struct zfcp_fsf_req *zfcp_fsf_get_req(struct zfcp_qdio *qdio,
-				      struct qdio_buffer *sbal)
-{
-	struct qdio_buffer_element *sbale = &sbal->element[0];
-	u64 req_id = (unsigned long) sbale->addr;
-
-	return zfcp_reqlist_find(qdio->adapter->req_list, req_id);
-}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 665e3cf..06025cd 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -16,9 +16,9 @@
 
 #define QBUFF_PER_PAGE		(PAGE_SIZE / sizeof(struct qdio_buffer))
 
-static bool enable_multibuffer;
+static bool enable_multibuffer = 1;
 module_param_named(datarouter, enable_multibuffer, bool, 0400);
-MODULE_PARM_DESC(datarouter, "Enable hardware data router support");
+MODULE_PARM_DESC(datarouter, "Enable hardware data router support (default on)");
 
 static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
 {
@@ -224,11 +224,9 @@
 
 static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
 {
-	spin_lock_irq(&qdio->req_q_lock);
 	if (atomic_read(&qdio->req_q_free) ||
 	    !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
 		return 1;
-	spin_unlock_irq(&qdio->req_q_lock);
 	return 0;
 }
 
@@ -246,9 +244,8 @@
 {
 	long ret;
 
-	spin_unlock_irq(&qdio->req_q_lock);
-	ret = wait_event_interruptible_timeout(qdio->req_q_wq,
-			       zfcp_qdio_sbal_check(qdio), 5 * HZ);
+	ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq,
+		       zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ);
 
 	if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
 		return -EIO;
@@ -262,7 +259,6 @@
 		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1");
 	}
 
-	spin_lock_irq(&qdio->req_q_lock);
 	return -EIO;
 }
 
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 3f01bbf..672b572 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -27,6 +27,16 @@
 static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO,				       \
 		     zfcp_sysfs_##_feat##_##_name##_show, NULL);
 
+#define ZFCP_DEFINE_ATTR_CONST(_feat, _name, _format, _value)		       \
+static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev,	       \
+						   struct device_attribute *at,\
+						   char *buf)		       \
+{									       \
+	return sprintf(buf, _format, _value);				       \
+}									       \
+static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO,				       \
+		     zfcp_sysfs_##_feat##_##_name##_show, NULL);
+
 #define ZFCP_DEFINE_A_ATTR(_name, _format, _value)			     \
 static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev,	     \
 						 struct device_attribute *at,\
@@ -75,6 +85,8 @@
 ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n",
 		 (zfcp_unit_sdev_status(unit) &
 		  ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
+ZFCP_DEFINE_ATTR_CONST(unit, access_shared, "%d\n", 0);
+ZFCP_DEFINE_ATTR_CONST(unit, access_readonly, "%d\n", 0);
 
 static ssize_t zfcp_sysfs_port_failed_show(struct device *dev,
 					   struct device_attribute *attr,
@@ -95,7 +107,7 @@
 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
 	unsigned long val;
 
-	if (strict_strtoul(buf, 0, &val) || val != 0)
+	if (kstrtoul(buf, 0, &val) || val != 0)
 		return -EINVAL;
 
 	zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_RUNNING);
@@ -134,7 +146,7 @@
 	unsigned long val;
 	struct scsi_device *sdev;
 
-	if (strict_strtoul(buf, 0, &val) || val != 0)
+	if (kstrtoul(buf, 0, &val) || val != 0)
 		return -EINVAL;
 
 	sdev = zfcp_unit_sdev(unit);
@@ -184,7 +196,7 @@
 	if (!adapter)
 		return -ENODEV;
 
-	if (strict_strtoul(buf, 0, &val) || val != 0) {
+	if (kstrtoul(buf, 0, &val) || val != 0) {
 		retval = -EINVAL;
 		goto out;
 	}
@@ -236,7 +248,7 @@
 	if (!adapter)
 		return -ENODEV;
 
-	if (strict_strtoull(buf, 0, (unsigned long long *) &wwpn))
+	if (kstrtoull(buf, 0, (unsigned long long *) &wwpn))
 		goto out;
 
 	port = zfcp_get_port_by_wwpn(adapter, wwpn);
@@ -297,7 +309,7 @@
 	u64 fcp_lun;
 	int retval;
 
-	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
+	if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
 		return -EINVAL;
 
 	retval = zfcp_unit_add(port, fcp_lun);
@@ -315,7 +327,7 @@
 	struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
 	u64 fcp_lun;
 
-	if (strict_strtoull(buf, 0, (unsigned long long *) &fcp_lun))
+	if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
 		return -EINVAL;
 
 	if (zfcp_unit_remove(port, fcp_lun))
@@ -347,6 +359,8 @@
 	&dev_attr_unit_in_recovery.attr,
 	&dev_attr_unit_status.attr,
 	&dev_attr_unit_access_denied.attr,
+	&dev_attr_unit_access_shared.attr,
+	&dev_attr_unit_access_readonly.attr,
 	NULL
 };
 static struct attribute_group zfcp_unit_attr_group = {
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 48b2918..fe25677 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -601,6 +601,7 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called arcmsr (modprobe arcmsr).
 
+source "drivers/scsi/esas2r/Kconfig"
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 source "drivers/scsi/mpt2sas/Kconfig"
 source "drivers/scsi/mpt3sas/Kconfig"
@@ -1353,7 +1354,6 @@
 	tristate "Emulex LightPulse Fibre Channel Support"
 	depends on PCI && SCSI
 	select SCSI_FC_ATTRS
-	select GENERIC_CSUM
 	select CRC_T10DIF
 	help
           This lpfc driver supports the Emulex LightPulse
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index b607ba4..149bb6b 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -141,6 +141,7 @@
 obj-$(CONFIG_SCSI_CXGB4_ISCSI)	+= libiscsi.o libiscsi_tcp.o cxgbi/
 obj-$(CONFIG_SCSI_BNX2_ISCSI)	+= libiscsi.o bnx2i/
 obj-$(CONFIG_BE2ISCSI)		+= libiscsi.o be2iscsi/
+obj-$(CONFIG_SCSI_ESAS2R)	+= esas2r/
 obj-$(CONFIG_SCSI_PMCRAID)	+= pmcraid.o
 obj-$(CONFIG_SCSI_VIRTIO)	+= virtio_scsi.o
 obj-$(CONFIG_VMWARE_PVSCSI)	+= vmw_pvscsi.o
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 9611195..f8ca7be 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -63,9 +63,9 @@
 u32	bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
 u32	*bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
 
-#define BFAD_FW_FILE_CB		"cbfw-3.2.1.0.bin"
-#define BFAD_FW_FILE_CT		"ctfw-3.2.1.0.bin"
-#define BFAD_FW_FILE_CT2	"ct2fw-3.2.1.0.bin"
+#define BFAD_FW_FILE_CB		"cbfw-3.2.1.1.bin"
+#define BFAD_FW_FILE_CT		"ctfw-3.2.1.1.bin"
+#define BFAD_FW_FILE_CT2	"ct2fw-3.2.1.1.bin"
 
 static u32 *bfad_load_fwimg(struct pci_dev *pdev);
 static void bfad_free_fwimg(void);
diff --git a/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
index 25093a0..3d33767 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_constants.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_constants.h
@@ -1,6 +1,6 @@
 /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
  *
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
  *
  * 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/scsi/bnx2i/57xx_iscsi_hsi.h b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
index f2db5fe..37049e4 100644
--- a/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
+++ b/drivers/scsi/bnx2i/57xx_iscsi_hsi.h
@@ -1,6 +1,6 @@
 /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
  *
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
  *
  * 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/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index f109e3b..6940f09 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -1,6 +1,6 @@
 /* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
  *
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
  * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
  * Copyright (c) 2007, 2008 Mike Christie
  *
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index a28b03e..af3e675 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1,6 +1,6 @@
 /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
  *
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
  * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
  * Copyright (c) 2007, 2008 Mike Christie
  *
diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c
index 50fef69..b6f6f43 100644
--- a/drivers/scsi/bnx2i/bnx2i_init.c
+++ b/drivers/scsi/bnx2i/bnx2i_init.c
@@ -1,6 +1,6 @@
 /* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
  *
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
  * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
  * Copyright (c) 2007, 2008 Mike Christie
  *
@@ -18,8 +18,8 @@
 static u32 adapter_count;
 
 #define DRV_MODULE_NAME		"bnx2i"
-#define DRV_MODULE_VERSION	"2.7.2.2"
-#define DRV_MODULE_RELDATE	"Apr 25, 2012"
+#define DRV_MODULE_VERSION	"2.7.6.2"
+#define DRV_MODULE_RELDATE	"Jun 06, 2013"
 
 static char version[] =
 		"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 0056e47..fabeb88 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1,7 +1,7 @@
 /*
  * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver.
  *
- * Copyright (c) 2006 - 2012 Broadcom Corporation
+ * Copyright (c) 2006 - 2013 Broadcom Corporation
  * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
  * Copyright (c) 2007, 2008 Mike Christie
  *
diff --git a/drivers/scsi/bnx2i/bnx2i_sysfs.c b/drivers/scsi/bnx2i/bnx2i_sysfs.c
index c61cf7a..a0a3d9f 100644
--- a/drivers/scsi/bnx2i/bnx2i_sysfs.c
+++ b/drivers/scsi/bnx2i/bnx2i_sysfs.c
@@ -1,6 +1,6 @@
 /* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver.
  *
- * Copyright (c) 2004 - 2012 Broadcom Corporation
+ * Copyright (c) 2004 - 2013 Broadcom Corporation
  *
  * 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/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 356def4..1663173 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -919,7 +919,7 @@
 	find_pio_EISA(&gc);
 	find_pio_ISA(&gc);
 
-	for (i = 0; i <= MAXIRQ; i++)
+	for (i = 0; i < MAXIRQ; i++)
 		if (reg_IRQ[i])
 			request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
 
diff --git a/drivers/scsi/esas2r/Kconfig b/drivers/scsi/esas2r/Kconfig
new file mode 100644
index 0000000..78fdbfd
--- /dev/null
+++ b/drivers/scsi/esas2r/Kconfig
@@ -0,0 +1,5 @@
+config SCSI_ESAS2R
+	tristate "ATTO Technology's ExpressSAS RAID adapter driver"
+	depends on PCI && SCSI
+	---help---
+	  This driver supports the ATTO ExpressSAS R6xx SAS/SATA RAID controllers.
diff --git a/drivers/scsi/esas2r/Makefile b/drivers/scsi/esas2r/Makefile
new file mode 100644
index 0000000..c77160b
--- /dev/null
+++ b/drivers/scsi/esas2r/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SCSI_ESAS2R)	+= esas2r.o
+
+esas2r-objs := esas2r_log.o esas2r_disc.o esas2r_flash.o esas2r_init.o \
+	 esas2r_int.o esas2r_io.o esas2r_ioctl.o esas2r_targdb.o   \
+	 esas2r_vda.o esas2r_main.o
diff --git a/drivers/scsi/esas2r/atioctl.h b/drivers/scsi/esas2r/atioctl.h
new file mode 100644
index 0000000..4aca3d5
--- /dev/null
+++ b/drivers/scsi/esas2r/atioctl.h
@@ -0,0 +1,1254 @@
+/*  linux/drivers/scsi/esas2r/atioctl.h
+ *      ATTO IOCTL Handling
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.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; 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.
+ *
+ *  NO WARRANTY
+ *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ *  solely responsible for determining the appropriateness of using and
+ *  distributing the Program and assumes all risks associated with its
+ *  exercise of rights under this Agreement, including but not limited to
+ *  the risks and costs of program errors, damage to or loss of data,
+ *  programs or equipment, and unavailability or interruption of operations.
+ *
+ *  DISCLAIMER OF LIABILITY
+ *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ *  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 "atvda.h"
+
+#ifndef ATIOCTL_H
+#define ATIOCTL_H
+
+#define EXPRESS_IOCTL_SIGNATURE        "Express"
+#define EXPRESS_IOCTL_SIGNATURE_SIZE   8
+
+/* structure definitions for IOCTls */
+
+struct __packed atto_express_ioctl_header {
+	u8 signature[EXPRESS_IOCTL_SIGNATURE_SIZE];
+	u8 return_code;
+
+#define IOCTL_SUCCESS               0
+#define IOCTL_ERR_INVCMD          101
+#define IOCTL_INIT_FAILED         102
+#define IOCTL_NOT_IMPLEMENTED     103
+#define IOCTL_BAD_CHANNEL         104
+#define IOCTL_TARGET_OVERRUN      105
+#define IOCTL_TARGET_NOT_ENABLED  106
+#define IOCTL_BAD_FLASH_IMGTYPE   107
+#define IOCTL_OUT_OF_RESOURCES    108
+#define IOCTL_GENERAL_ERROR       109
+#define IOCTL_INVALID_PARAM       110
+
+	u8 channel;
+	u8 retries;
+	u8 pad[5];
+};
+
+/*
+ * NOTE - if channel == 0xFF, the request is
+ * handled on the adapter it came in on.
+ */
+#define MAX_NODE_NAMES  256
+
+struct __packed atto_firmware_rw_request {
+	u8 function;
+	#define FUNC_FW_DOWNLOAD        0x09
+	#define FUNC_FW_UPLOAD          0x12
+
+	u8 img_type;
+	#define FW_IMG_FW               0x01
+	#define FW_IMG_BIOS             0x02
+	#define FW_IMG_NVR              0x03
+	#define FW_IMG_RAW              0x04
+	#define FW_IMG_FM_API           0x05
+	#define FW_IMG_FS_API           0x06
+
+	u8 pad[2];
+	u32 img_offset;
+	u32 img_size;
+	u8 image[0x80000];
+};
+
+struct __packed atto_param_rw_request {
+	u16 code;
+	char data_buffer[512];
+};
+
+#define MAX_CHANNEL 256
+
+struct __packed atto_channel_list {
+	u32 num_channels;
+	u8 channel[MAX_CHANNEL];
+};
+
+struct __packed atto_channel_info {
+	u8 major_rev;
+	u8 minor_rev;
+	u8 IRQ;
+	u8 revision_id;
+	u8 pci_bus;
+	u8 pci_dev_func;
+	u8 core_rev;
+	u8 host_no;
+	u16 device_id;
+	u16 vendor_id;
+	u16 ven_dev_id;
+	u8 pad[3];
+	u32 hbaapi_rev;
+};
+
+/*
+ * CSMI control codes
+ * class independent
+ */
+#define CSMI_CC_GET_DRVR_INFO        1
+#define CSMI_CC_GET_CNTLR_CFG        2
+#define CSMI_CC_GET_CNTLR_STS        3
+#define CSMI_CC_FW_DOWNLOAD          4
+
+/* RAID class */
+#define CSMI_CC_GET_RAID_INFO        10
+#define CSMI_CC_GET_RAID_CFG         11
+
+/* HBA class */
+#define CSMI_CC_GET_PHY_INFO         20
+#define CSMI_CC_SET_PHY_INFO         21
+#define CSMI_CC_GET_LINK_ERRORS      22
+#define CSMI_CC_SMP_PASSTHRU         23
+#define CSMI_CC_SSP_PASSTHRU         24
+#define CSMI_CC_STP_PASSTHRU         25
+#define CSMI_CC_GET_SATA_SIG         26
+#define CSMI_CC_GET_SCSI_ADDR        27
+#define CSMI_CC_GET_DEV_ADDR         28
+#define CSMI_CC_TASK_MGT             29
+#define CSMI_CC_GET_CONN_INFO        30
+
+/* PHY class */
+#define CSMI_CC_PHY_CTRL             60
+
+/*
+ * CSMI status codes
+ * class independent
+ */
+#define CSMI_STS_SUCCESS             0
+#define CSMI_STS_FAILED              1
+#define CSMI_STS_BAD_CTRL_CODE       2
+#define CSMI_STS_INV_PARAM           3
+#define CSMI_STS_WRITE_ATTEMPTED     4
+
+/* RAID class */
+#define CSMI_STS_INV_RAID_SET        1000
+
+/* HBA class */
+#define CSMI_STS_PHY_CHANGED         CSMI_STS_SUCCESS
+#define CSMI_STS_PHY_UNCHANGEABLE    2000
+#define CSMI_STS_INV_LINK_RATE       2001
+#define CSMI_STS_INV_PHY             2002
+#define CSMI_STS_INV_PHY_FOR_PORT    2003
+#define CSMI_STS_PHY_UNSELECTABLE    2004
+#define CSMI_STS_SELECT_PHY_OR_PORT  2005
+#define CSMI_STS_INV_PORT            2006
+#define CSMI_STS_PORT_UNSELECTABLE   2007
+#define CSMI_STS_CONNECTION_FAILED   2008
+#define CSMI_STS_NO_SATA_DEV         2009
+#define CSMI_STS_NO_SATA_SIGNATURE   2010
+#define CSMI_STS_SCSI_EMULATION      2011
+#define CSMI_STS_NOT_AN_END_DEV      2012
+#define CSMI_STS_NO_SCSI_ADDR        2013
+#define CSMI_STS_NO_DEV_ADDR         2014
+
+/* CSMI class independent structures */
+struct atto_csmi_get_driver_info {
+	char name[81];
+	char description[81];
+	u16 major_rev;
+	u16 minor_rev;
+	u16 build_rev;
+	u16 release_rev;
+	u16 csmi_major_rev;
+	u16 csmi_minor_rev;
+	#define CSMI_MAJOR_REV_0_81      0
+	#define CSMI_MINOR_REV_0_81      81
+
+	#define CSMI_MAJOR_REV           CSMI_MAJOR_REV_0_81
+	#define CSMI_MINOR_REV           CSMI_MINOR_REV_0_81
+};
+
+struct atto_csmi_get_pci_bus_addr {
+	u8 bus_num;
+	u8 device_num;
+	u8 function_num;
+	u8 reserved;
+};
+
+struct atto_csmi_get_cntlr_cfg {
+	u32 base_io_addr;
+
+	struct {
+		u32 base_memaddr_lo;
+		u32 base_memaddr_hi;
+	};
+
+	u32 board_id;
+	u16 slot_num;
+	#define CSMI_SLOT_NUM_UNKNOWN    0xFFFF
+
+	u8 cntlr_class;
+	#define CSMI_CNTLR_CLASS_HBA     5
+
+	u8 io_bus_type;
+	#define CSMI_BUS_TYPE_PCI        3
+	#define CSMI_BUS_TYPE_PCMCIA     4
+
+	union {
+		struct atto_csmi_get_pci_bus_addr pci_addr;
+		u8 reserved[32];
+	};
+
+	char serial_num[81];
+	u16 major_rev;
+	u16 minor_rev;
+	u16 build_rev;
+	u16 release_rev;
+	u16 bios_major_rev;
+	u16 bios_minor_rev;
+	u16 bios_build_rev;
+	u16 bios_release_rev;
+	u32 cntlr_flags;
+	#define CSMI_CNTLRF_SAS_HBA      0x00000001
+	#define CSMI_CNTLRF_SAS_RAID     0x00000002
+	#define CSMI_CNTLRF_SATA_HBA     0x00000004
+	#define CSMI_CNTLRF_SATA_RAID    0x00000008
+	#define CSMI_CNTLRF_FWD_SUPPORT  0x00010000
+	#define CSMI_CNTLRF_FWD_ONLINE   0x00020000
+	#define CSMI_CNTLRF_FWD_SRESET   0x00040000
+	#define CSMI_CNTLRF_FWD_HRESET   0x00080000
+	#define CSMI_CNTLRF_FWD_RROM     0x00100000
+
+	u16 rrom_major_rev;
+	u16 rrom_minor_rev;
+	u16 rrom_build_rev;
+	u16 rrom_release_rev;
+	u16 rrom_biosmajor_rev;
+	u16 rrom_biosminor_rev;
+	u16 rrom_biosbuild_rev;
+	u16 rrom_biosrelease_rev;
+	u8 reserved2[7];
+};
+
+struct atto_csmi_get_cntlr_sts {
+	u32 status;
+	#define CSMI_CNTLR_STS_GOOD          1
+	#define CSMI_CNTLR_STS_FAILED        2
+	#define CSMI_CNTLR_STS_OFFLINE       3
+	#define CSMI_CNTLR_STS_POWEROFF      4
+
+	u32 offline_reason;
+	#define CSMI_OFFLINE_NO_REASON       0
+	#define CSMI_OFFLINE_INITIALIZING    1
+	#define CSMI_OFFLINE_BUS_DEGRADED    2
+	#define CSMI_OFFLINE_BUS_FAILURE     3
+
+	u8 reserved[28];
+};
+
+struct atto_csmi_fw_download {
+	u32 buffer_len;
+	u32 download_flags;
+	#define CSMI_FWDF_VALIDATE       0x00000001
+	#define CSMI_FWDF_SOFT_RESET     0x00000002
+	#define CSMI_FWDF_HARD_RESET     0x00000004
+
+	u8 reserved[32];
+	u16 status;
+	#define CSMI_FWD_STS_SUCCESS     0
+	#define CSMI_FWD_STS_FAILED      1
+	#define CSMI_FWD_STS_USING_RROM  2
+	#define CSMI_FWD_STS_REJECT      3
+	#define CSMI_FWD_STS_DOWNREV     4
+
+	u16 severity;
+	#define CSMI_FWD_SEV_INFO        0
+	#define CSMI_FWD_SEV_WARNING     1
+	#define CSMI_FWD_SEV_ERROR       2
+	#define CSMI_FWD_SEV_FATAL       3
+
+};
+
+/* CSMI RAID class structures */
+struct atto_csmi_get_raid_info {
+	u32 num_raid_sets;
+	u32 max_drivesper_set;
+	u8 reserved[92];
+};
+
+struct atto_csmi_raid_drives {
+	char model[40];
+	char firmware[8];
+	char serial_num[40];
+	u8 sas_addr[8];
+	u8 lun[8];
+	u8 drive_sts;
+	#define CSMI_DRV_STS_OK          0
+	#define CSMI_DRV_STS_REBUILDING  1
+	#define CSMI_DRV_STS_FAILED      2
+	#define CSMI_DRV_STS_DEGRADED    3
+
+	u8 drive_usage;
+	#define CSMI_DRV_USE_NOT_USED    0
+	#define CSMI_DRV_USE_MEMBER      1
+	#define CSMI_DRV_USE_SPARE       2
+
+	u8 reserved[30]; /* spec says 22 */
+};
+
+struct atto_csmi_get_raid_cfg {
+	u32 raid_set_index;
+	u32 capacity;
+	u32 stripe_size;
+	u8 raid_type;
+	u8 status;
+	u8 information;
+	u8 drive_cnt;
+	u8 reserved[20];
+
+	struct atto_csmi_raid_drives drives[1];
+};
+
+/* CSMI HBA class structures */
+struct atto_csmi_phy_entity {
+	u8 ident_frame[0x1C];
+	u8 port_id;
+	u8 neg_link_rate;
+	u8 min_link_rate;
+	u8 max_link_rate;
+	u8 phy_change_cnt;
+	u8 auto_discover;
+	#define CSMI_DISC_NOT_SUPPORTED  0x00
+	#define CSMI_DISC_NOT_STARTED    0x01
+	#define CSMI_DISC_IN_PROGRESS    0x02
+	#define CSMI_DISC_COMPLETE       0x03
+	#define CSMI_DISC_ERROR          0x04
+
+	u8 reserved[2];
+	u8 attach_ident_frame[0x1C];
+};
+
+struct atto_csmi_get_phy_info {
+	u8 number_of_phys;
+	u8 reserved[3];
+	struct atto_csmi_phy_entity
+		phy[32];
+};
+
+struct atto_csmi_set_phy_info {
+	u8 phy_id;
+	u8 neg_link_rate;
+	#define CSMI_NEG_RATE_NEGOTIATE  0x00
+	#define CSMI_NEG_RATE_PHY_DIS    0x01
+
+	u8 prog_minlink_rate;
+	u8 prog_maxlink_rate;
+	u8 signal_class;
+	#define CSMI_SIG_CLASS_UNKNOWN   0x00
+	#define CSMI_SIG_CLASS_DIRECT    0x01
+	#define CSMI_SIG_CLASS_SERVER    0x02
+	#define CSMI_SIG_CLASS_ENCLOSURE 0x03
+
+	u8 reserved[3];
+};
+
+struct atto_csmi_get_link_errors {
+	u8 phy_id;
+	u8 reset_cnts;
+	#define CSMI_RESET_CNTS_NO       0x00
+	#define CSMI_RESET_CNTS_YES      0x01
+
+	u8 reserved[2];
+	u32 inv_dw_cnt;
+	u32 disp_err_cnt;
+	u32 loss_ofdw_sync_cnt;
+	u32 phy_reseterr_cnt;
+
+	/*
+	 * The following field has been added by ATTO for ease of
+	 * implementation of additional statistics.  Drivers must validate
+	 * the length of the IOCTL payload prior to filling them in so CSMI
+	 * complaint applications function correctly.
+	 */
+
+	u32 crc_err_cnt;
+};
+
+struct atto_csmi_smp_passthru {
+	u8 phy_id;
+	u8 port_id;
+	u8 conn_rate;
+	u8 reserved;
+	u8 dest_sas_addr[8];
+	u32 req_len;
+	u8 smp_req[1020];
+	u8 conn_sts;
+	u8 reserved2[3];
+	u32 rsp_len;
+	u8 smp_rsp[1020];
+};
+
+struct atto_csmi_ssp_passthru_sts {
+	u8 conn_sts;
+	u8 reserved[3];
+	u8 data_present;
+	u8 status;
+	u16 rsp_length;
+	u8 rsp[256];
+	u32 data_bytes;
+};
+
+struct atto_csmi_ssp_passthru {
+	u8 phy_id;
+	u8 port_id;
+	u8 conn_rate;
+	u8 reserved;
+	u8 dest_sas_addr[8];
+	u8 lun[8];
+	u8 cdb_len;
+	u8 add_cdb_len;
+	u8 reserved2[2];
+	u8 cdb[16];
+	u32 flags;
+	#define CSMI_SSPF_DD_READ        0x00000001
+	#define CSMI_SSPF_DD_WRITE       0x00000002
+	#define CSMI_SSPF_DD_UNSPECIFIED 0x00000004
+	#define CSMI_SSPF_TA_SIMPLE      0x00000000
+	#define CSMI_SSPF_TA_HEAD_OF_Q   0x00000010
+	#define CSMI_SSPF_TA_ORDERED     0x00000020
+	#define CSMI_SSPF_TA_ACA         0x00000040
+
+	u8 add_cdb[24];
+	u32 data_len;
+
+	struct atto_csmi_ssp_passthru_sts sts;
+};
+
+struct atto_csmi_stp_passthru_sts {
+	u8 conn_sts;
+	u8 reserved[3];
+	u8 sts_fis[20];
+	u32 scr[16];
+	u32 data_bytes;
+};
+
+struct atto_csmi_stp_passthru {
+	u8 phy_id;
+	u8 port_id;
+	u8 conn_rate;
+	u8 reserved;
+	u8 dest_sas_addr[8];
+	u8 reserved2[4];
+	u8 command_fis[20];
+	u32 flags;
+	#define CSMI_STPF_DD_READ        0x00000001
+	#define CSMI_STPF_DD_WRITE       0x00000002
+	#define CSMI_STPF_DD_UNSPECIFIED 0x00000004
+	#define CSMI_STPF_PIO            0x00000010
+	#define CSMI_STPF_DMA            0x00000020
+	#define CSMI_STPF_PACKET         0x00000040
+	#define CSMI_STPF_DMA_QUEUED     0x00000080
+	#define CSMI_STPF_EXECUTE_DIAG   0x00000100
+	#define CSMI_STPF_RESET_DEVICE   0x00000200
+
+	u32 data_len;
+
+	struct atto_csmi_stp_passthru_sts sts;
+};
+
+struct atto_csmi_get_sata_sig {
+	u8 phy_id;
+	u8 reserved[3];
+	u8 reg_dth_fis[20];
+};
+
+struct atto_csmi_get_scsi_addr {
+	u8 sas_addr[8];
+	u8 sas_lun[8];
+	u8 host_index;
+	u8 path_id;
+	u8 target_id;
+	u8 lun;
+};
+
+struct atto_csmi_get_dev_addr {
+	u8 host_index;
+	u8 path_id;
+	u8 target_id;
+	u8 lun;
+	u8 sas_addr[8];
+	u8 sas_lun[8];
+};
+
+struct atto_csmi_task_mgmt {
+	u8 host_index;
+	u8 path_id;
+	u8 target_id;
+	u8 lun;
+	u32 flags;
+	#define CSMI_TMF_TASK_IU         0x00000001
+	#define CSMI_TMF_HARD_RST        0x00000002
+	#define CSMI_TMF_SUPPRESS_RSLT   0x00000004
+
+	u32 queue_tag;
+	u32 reserved;
+	u8 task_mgt_func;
+	u8 reserved2[7];
+	u32 information;
+	#define CSMI_TM_INFO_TEST        1
+	#define CSMI_TM_INFO_EXCEEDED    2
+	#define CSMI_TM_INFO_DEMAND      3
+	#define CSMI_TM_INFO_TRIGGER     4
+
+	struct atto_csmi_ssp_passthru_sts sts;
+
+};
+
+struct atto_csmi_get_conn_info {
+	u32 pinout;
+	#define CSMI_CON_UNKNOWN         0x00000001
+	#define CSMI_CON_SFF_8482        0x00000002
+	#define CSMI_CON_SFF_8470_LANE_1 0x00000100
+	#define CSMI_CON_SFF_8470_LANE_2 0x00000200
+	#define CSMI_CON_SFF_8470_LANE_3 0x00000400
+	#define CSMI_CON_SFF_8470_LANE_4 0x00000800
+	#define CSMI_CON_SFF_8484_LANE_1 0x00010000
+	#define CSMI_CON_SFF_8484_LANE_2 0x00020000
+	#define CSMI_CON_SFF_8484_LANE_3 0x00040000
+	#define CSMI_CON_SFF_8484_LANE_4 0x00080000
+
+	u8 connector[16];
+	u8 location;
+	#define CSMI_CON_INTERNAL        0x02
+	#define CSMI_CON_EXTERNAL        0x04
+	#define CSMI_CON_SWITCHABLE      0x08
+	#define CSMI_CON_AUTO            0x10
+
+	u8 reserved[15];
+};
+
+/* CSMI PHY class structures */
+struct atto_csmi_character {
+	u8 type_flags;
+	#define CSMI_CTF_POS_DISP        0x01
+	#define CSMI_CTF_NEG_DISP        0x02
+	#define CSMI_CTF_CTRL_CHAR       0x04
+
+	u8 value;
+};
+
+struct atto_csmi_pc_ctrl {
+	u8 type;
+	#define CSMI_PC_TYPE_UNDEFINED   0x00
+	#define CSMI_PC_TYPE_SATA        0x01
+	#define CSMI_PC_TYPE_SAS         0x02
+	u8 rate;
+	u8 reserved[6];
+	u32 vendor_unique[8];
+	u32 tx_flags;
+	#define CSMI_PC_TXF_PREEMP_DIS   0x00000001
+
+	signed char tx_amplitude;
+	signed char tx_preemphasis;
+	signed char tx_slew_rate;
+	signed char tx_reserved[13];
+	u8 tx_vendor_unique[64];
+	u32 rx_flags;
+	#define CSMI_PC_RXF_EQ_DIS       0x00000001
+
+	signed char rx_threshold;
+	signed char rx_equalization_gain;
+	signed char rx_reserved[14];
+	u8 rx_vendor_unique[64];
+	u32 pattern_flags;
+	#define CSMI_PC_PATF_FIXED       0x00000001
+	#define CSMI_PC_PATF_DIS_SCR     0x00000002
+	#define CSMI_PC_PATF_DIS_ALIGN   0x00000004
+	#define CSMI_PC_PATF_DIS_SSC     0x00000008
+
+	u8 fixed_pattern;
+	#define CSMI_PC_FP_CJPAT         0x00000001
+	#define CSMI_PC_FP_ALIGN         0x00000002
+
+	u8 user_pattern_len;
+	u8 pattern_reserved[6];
+
+	struct atto_csmi_character user_pattern_buffer[16];
+};
+
+struct atto_csmi_phy_ctrl {
+	u32 function;
+	#define CSMI_PC_FUNC_GET_SETUP   0x00000100
+
+	u8 phy_id;
+	u16 len_of_cntl;
+	u8 num_of_cntls;
+	u8 reserved[4];
+	u32 link_flags;
+	#define CSMI_PHY_ACTIVATE_CTRL   0x00000001
+	#define CSMI_PHY_UPD_SPINUP_RATE 0x00000002
+	#define CSMI_PHY_AUTO_COMWAKE    0x00000004
+
+	u8 spinup_rate;
+	u8 link_reserved[7];
+	u32 vendor_unique[8];
+
+	struct atto_csmi_pc_ctrl control[1];
+};
+
+union atto_ioctl_csmi {
+	struct atto_csmi_get_driver_info drvr_info;
+	struct atto_csmi_get_cntlr_cfg cntlr_cfg;
+	struct atto_csmi_get_cntlr_sts cntlr_sts;
+	struct atto_csmi_fw_download fw_dwnld;
+	struct atto_csmi_get_raid_info raid_info;
+	struct atto_csmi_get_raid_cfg raid_cfg;
+	struct atto_csmi_get_phy_info get_phy_info;
+	struct atto_csmi_set_phy_info set_phy_info;
+	struct atto_csmi_get_link_errors link_errs;
+	struct atto_csmi_smp_passthru smp_pass_thru;
+	struct atto_csmi_ssp_passthru ssp_pass_thru;
+	struct atto_csmi_stp_passthru stp_pass_thru;
+	struct atto_csmi_task_mgmt tsk_mgt;
+	struct atto_csmi_get_sata_sig sata_sig;
+	struct atto_csmi_get_scsi_addr scsi_addr;
+	struct atto_csmi_get_dev_addr dev_addr;
+	struct atto_csmi_get_conn_info conn_info[32];
+	struct atto_csmi_phy_ctrl phy_ctrl;
+};
+
+struct atto_csmi {
+	u32 control_code;
+	u32 status;
+	union atto_ioctl_csmi data;
+};
+
+struct atto_module_info {
+	void *adapter;
+	void *pci_dev;
+	void *scsi_host;
+	unsigned short host_no;
+	union {
+		struct {
+			u64 node_name;
+			u64 port_name;
+		};
+		u64 sas_addr;
+	};
+};
+
+#define ATTO_FUNC_GET_ADAP_INFO      0x00
+#define ATTO_VER_GET_ADAP_INFO0      0
+#define ATTO_VER_GET_ADAP_INFO       ATTO_VER_GET_ADAP_INFO0
+
+struct __packed atto_hba_get_adapter_info {
+
+	struct {
+		u16 vendor_id;
+		u16 device_id;
+		u16 ss_vendor_id;
+		u16 ss_device_id;
+		u8 class_code[3];
+		u8 rev_id;
+		u8 bus_num;
+		u8 dev_num;
+		u8 func_num;
+		u8 link_width_max;
+		u8 link_width_curr;
+	    #define ATTO_GAI_PCILW_UNKNOWN   0x00
+
+		u8 link_speed_max;
+		u8 link_speed_curr;
+	    #define ATTO_GAI_PCILS_UNKNOWN   0x00
+	    #define ATTO_GAI_PCILS_GEN1      0x01
+	    #define ATTO_GAI_PCILS_GEN2      0x02
+	    #define ATTO_GAI_PCILS_GEN3      0x03
+
+		u8 interrupt_mode;
+	    #define ATTO_GAI_PCIIM_UNKNOWN   0x00
+	    #define ATTO_GAI_PCIIM_LEGACY    0x01
+	    #define ATTO_GAI_PCIIM_MSI       0x02
+	    #define ATTO_GAI_PCIIM_MSIX      0x03
+
+		u8 msi_vector_cnt;
+		u8 reserved[19];
+	} pci;
+
+	u8 adap_type;
+	#define ATTO_GAI_AT_EPCIU320     0x00
+	#define ATTO_GAI_AT_ESASRAID     0x01
+	#define ATTO_GAI_AT_ESASRAID2    0x02
+	#define ATTO_GAI_AT_ESASHBA      0x03
+	#define ATTO_GAI_AT_ESASHBA2     0x04
+	#define ATTO_GAI_AT_CELERITY     0x05
+	#define ATTO_GAI_AT_CELERITY8    0x06
+	#define ATTO_GAI_AT_FASTFRAME    0x07
+	#define ATTO_GAI_AT_ESASHBA3     0x08
+	#define ATTO_GAI_AT_CELERITY16   0x09
+	#define ATTO_GAI_AT_TLSASHBA     0x0A
+	#define ATTO_GAI_AT_ESASHBA4     0x0B
+
+	u8 adap_flags;
+	#define ATTO_GAI_AF_DEGRADED     0x01
+	#define ATTO_GAI_AF_SPT_SUPP     0x02
+	#define ATTO_GAI_AF_DEVADDR_SUPP 0x04
+	#define ATTO_GAI_AF_PHYCTRL_SUPP 0x08
+	#define ATTO_GAI_AF_TEST_SUPP    0x10
+	#define ATTO_GAI_AF_DIAG_SUPP    0x20
+	#define ATTO_GAI_AF_VIRT_SES     0x40
+	#define ATTO_GAI_AF_CONN_CTRL    0x80
+
+	u8 num_ports;
+	u8 num_phys;
+	u8 drvr_rev_major;
+	u8 drvr_rev_minor;
+	u8 drvr_revsub_minor;
+	u8 drvr_rev_build;
+	char drvr_rev_ascii[16];
+	char drvr_name[32];
+	char firmware_rev[16];
+	char flash_rev[16];
+	char model_name_short[16];
+	char model_name[32];
+	u32 num_targets;
+	u32 num_targsper_bus;
+	u32 num_lunsper_targ;
+	u8 num_busses;
+	u8 num_connectors;
+	u8 adap_flags2;
+	#define ATTO_GAI_AF2_FCOE_SUPP       0x01
+	#define ATTO_GAI_AF2_NIC_SUPP        0x02
+	#define ATTO_GAI_AF2_LOCATE_SUPP     0x04
+	#define ATTO_GAI_AF2_ADAP_CTRL_SUPP  0x08
+	#define ATTO_GAI_AF2_DEV_INFO_SUPP   0x10
+	#define ATTO_GAI_AF2_NPIV_SUPP       0x20
+	#define ATTO_GAI_AF2_MP_SUPP         0x40
+
+	u8 num_temp_sensors;
+	u32 num_targets_backend;
+	u32 tunnel_flags;
+	#define ATTO_GAI_TF_MEM_RW           0x00000001
+	#define ATTO_GAI_TF_TRACE            0x00000002
+	#define ATTO_GAI_TF_SCSI_PASS_THRU   0x00000004
+	#define ATTO_GAI_TF_GET_DEV_ADDR     0x00000008
+	#define ATTO_GAI_TF_PHY_CTRL         0x00000010
+	#define ATTO_GAI_TF_CONN_CTRL        0x00000020
+	#define ATTO_GAI_TF_GET_DEV_INFO     0x00000040
+
+	u8 reserved3[0x138];
+};
+
+#define ATTO_FUNC_GET_ADAP_ADDR      0x01
+#define ATTO_VER_GET_ADAP_ADDR0      0
+#define ATTO_VER_GET_ADAP_ADDR       ATTO_VER_GET_ADAP_ADDR0
+
+struct __packed atto_hba_get_adapter_address {
+
+	u8 addr_type;
+	#define ATTO_GAA_AT_PORT         0x00
+	#define ATTO_GAA_AT_NODE         0x01
+	#define ATTO_GAA_AT_CURR_MAC     0x02
+	#define ATTO_GAA_AT_PERM_MAC     0x03
+	#define ATTO_GAA_AT_VNIC         0x04
+
+	u8 port_id;
+	u16 addr_len;
+	u8 address[256];
+};
+
+#define ATTO_FUNC_MEM_RW             0x02
+#define ATTO_VER_MEM_RW0             0
+#define ATTO_VER_MEM_RW              ATTO_VER_MEM_RW0
+
+struct __packed atto_hba_memory_read_write {
+	u8 mem_func;
+	u8 mem_type;
+	union {
+		u8 pci_index;
+		u8 i2c_dev;
+	};
+	u8 i2c_status;
+	u32 length;
+	u64 address;
+	u8 reserved[48];
+
+};
+
+#define ATTO_FUNC_TRACE              0x03
+#define ATTO_VER_TRACE0              0
+#define ATTO_VER_TRACE1              1
+#define ATTO_VER_TRACE               ATTO_VER_TRACE1
+
+struct __packed atto_hba_trace {
+	u8 trace_func;
+	#define ATTO_TRC_TF_GET_INFO     0x00
+	#define ATTO_TRC_TF_ENABLE       0x01
+	#define ATTO_TRC_TF_DISABLE      0x02
+	#define ATTO_TRC_TF_SET_MASK     0x03
+	#define ATTO_TRC_TF_UPLOAD       0x04
+	#define ATTO_TRC_TF_RESET        0x05
+
+	u8 trace_type;
+	#define ATTO_TRC_TT_DRIVER       0x00
+	#define ATTO_TRC_TT_FWCOREDUMP   0x01
+
+	u8 reserved[2];
+	u32 current_offset;
+	u32 total_length;
+	u32 trace_mask;
+	u8 reserved2[48];
+};
+
+#define ATTO_FUNC_SCSI_PASS_THRU     0x04
+#define ATTO_VER_SCSI_PASS_THRU0     0
+#define ATTO_VER_SCSI_PASS_THRU      ATTO_VER_SCSI_PASS_THRU0
+
+struct __packed atto_hba_scsi_pass_thru {
+	u8 cdb[32];
+	u8 cdb_length;
+	u8 req_status;
+	#define ATTO_SPT_RS_SUCCESS      0x00
+	#define ATTO_SPT_RS_FAILED       0x01
+	#define ATTO_SPT_RS_OVERRUN      0x02
+	#define ATTO_SPT_RS_UNDERRUN     0x03
+	#define ATTO_SPT_RS_NO_DEVICE    0x04
+	#define ATTO_SPT_RS_NO_LUN       0x05
+	#define ATTO_SPT_RS_TIMEOUT      0x06
+	#define ATTO_SPT_RS_BUS_RESET    0x07
+	#define ATTO_SPT_RS_ABORTED      0x08
+	#define ATTO_SPT_RS_BUSY         0x09
+	#define ATTO_SPT_RS_DEGRADED     0x0A
+
+	u8 scsi_status;
+	u8 sense_length;
+	u32 flags;
+	#define ATTO_SPTF_DATA_IN    0x00000001
+	#define ATTO_SPTF_DATA_OUT   0x00000002
+	#define ATTO_SPTF_SIMPLE_Q   0x00000004
+	#define ATTO_SPTF_HEAD_OF_Q  0x00000008
+	#define ATTO_SPTF_ORDERED_Q  0x00000010
+
+	u32 timeout;
+	u32 target_id;
+	u8 lun[8];
+	u32 residual_length;
+	u8 sense_data[0xFC];
+	u8 reserved[0x28];
+};
+
+#define ATTO_FUNC_GET_DEV_ADDR       0x05
+#define ATTO_VER_GET_DEV_ADDR0       0
+#define ATTO_VER_GET_DEV_ADDR        ATTO_VER_GET_DEV_ADDR0
+
+struct __packed atto_hba_get_device_address {
+	u8 addr_type;
+	#define ATTO_GDA_AT_PORT         0x00
+	#define ATTO_GDA_AT_NODE         0x01
+	#define ATTO_GDA_AT_MAC          0x02
+	#define ATTO_GDA_AT_PORTID       0x03
+	#define ATTO_GDA_AT_UNIQUE       0x04
+
+	u8 reserved;
+	u16 addr_len;
+	u32 target_id;
+	u8 address[256];
+};
+
+/* The following functions are supported by firmware but do not have any
+ * associated driver structures
+ */
+#define ATTO_FUNC_PHY_CTRL           0x06
+#define ATTO_FUNC_CONN_CTRL          0x0C
+#define ATTO_FUNC_ADAP_CTRL          0x0E
+#define ATTO_VER_ADAP_CTRL0          0
+#define ATTO_VER_ADAP_CTRL           ATTO_VER_ADAP_CTRL0
+
+struct __packed atto_hba_adap_ctrl {
+	u8 adap_func;
+	#define ATTO_AC_AF_HARD_RST      0x00
+	#define ATTO_AC_AF_GET_STATE     0x01
+	#define ATTO_AC_AF_GET_TEMP      0x02
+
+	u8 adap_state;
+	#define ATTO_AC_AS_UNKNOWN       0x00
+	#define ATTO_AC_AS_OK            0x01
+	#define ATTO_AC_AS_RST_SCHED     0x02
+	#define ATTO_AC_AS_RST_IN_PROG   0x03
+	#define ATTO_AC_AS_RST_DISC      0x04
+	#define ATTO_AC_AS_DEGRADED      0x05
+	#define ATTO_AC_AS_DISABLED      0x06
+	#define ATTO_AC_AS_TEMP          0x07
+
+	u8 reserved[2];
+
+	union {
+		struct {
+			u8 temp_sensor;
+			u8 temp_state;
+
+	#define ATTO_AC_TS_UNSUPP        0x00
+	#define ATTO_AC_TS_UNKNOWN       0x01
+	#define ATTO_AC_TS_INIT_FAILED   0x02
+	#define ATTO_AC_TS_NORMAL        0x03
+	#define ATTO_AC_TS_OUT_OF_RANGE  0x04
+	#define ATTO_AC_TS_FAULT         0x05
+
+			signed short temp_value;
+			signed short temp_lower_lim;
+			signed short temp_upper_lim;
+			char temp_desc[32];
+			u8 reserved2[20];
+		};
+	};
+};
+
+#define ATTO_FUNC_GET_DEV_INFO       0x0F
+#define ATTO_VER_GET_DEV_INFO0       0
+#define ATTO_VER_GET_DEV_INFO        ATTO_VER_GET_DEV_INFO0
+
+struct __packed atto_hba_sas_device_info {
+
+    #define ATTO_SDI_MAX_PHYS_WIDE_PORT  16
+
+	u8 phy_id[ATTO_SDI_MAX_PHYS_WIDE_PORT]; /* IDs of parent exp/adapt */
+	#define ATTO_SDI_PHY_ID_INV      ATTO_SAS_PHY_ID_INV
+	u32 exp_target_id;
+	u32 sas_port_mask;
+	u8 sas_level;
+	#define ATTO_SDI_SAS_LVL_INV     0xFF
+
+	u8 slot_num;
+	#define ATTO_SDI_SLOT_NUM_INV    ATTO_SLOT_NUM_INV
+
+	u8 dev_type;
+	#define ATTO_SDI_DT_END_DEVICE   0
+	#define ATTO_SDI_DT_EXPANDER     1
+	#define ATTO_SDI_DT_PORT_MULT    2
+
+	u8 ini_flags;
+	u8 tgt_flags;
+	u8 link_rate; /* SMP_RATE_XXX */
+	u8 loc_flags;
+	#define ATTO_SDI_LF_DIRECT       0x01
+	#define ATTO_SDI_LF_EXPANDER     0x02
+	#define ATTO_SDI_LF_PORT_MULT    0x04
+	u8 pm_port;
+	u8 reserved[0x60];
+};
+
+union atto_hba_device_info {
+	struct atto_hba_sas_device_info sas_dev_info;
+};
+
+struct __packed atto_hba_get_device_info {
+	u32 target_id;
+	u8 info_type;
+	#define ATTO_GDI_IT_UNKNOWN      0x00
+	#define ATTO_GDI_IT_SAS          0x01
+	#define ATTO_GDI_IT_FC           0x02
+	#define ATTO_GDI_IT_FCOE         0x03
+
+	u8 reserved[11];
+	union atto_hba_device_info dev_info;
+};
+
+struct atto_ioctl {
+	u8 version;
+	u8 function; /* ATTO_FUNC_XXX */
+	u8 status;
+#define ATTO_STS_SUCCESS         0x00
+#define ATTO_STS_FAILED          0x01
+#define ATTO_STS_INV_VERSION     0x02
+#define ATTO_STS_OUT_OF_RSRC     0x03
+#define ATTO_STS_INV_FUNC        0x04
+#define ATTO_STS_UNSUPPORTED     0x05
+#define ATTO_STS_INV_ADAPTER     0x06
+#define ATTO_STS_INV_DRVR_VER    0x07
+#define ATTO_STS_INV_PARAM       0x08
+#define ATTO_STS_TIMEOUT         0x09
+#define ATTO_STS_NOT_APPL        0x0A
+#define ATTO_STS_DEGRADED        0x0B
+
+	u8 flags;
+	#define HBAF_TUNNEL      0x01
+
+	u32 data_length;
+	u8 reserved2[56];
+
+	union {
+		u8 byte[1];
+		struct atto_hba_get_adapter_info get_adap_info;
+		struct atto_hba_get_adapter_address get_adap_addr;
+		struct atto_hba_scsi_pass_thru scsi_pass_thru;
+		struct atto_hba_get_device_address get_dev_addr;
+		struct atto_hba_adap_ctrl adap_ctrl;
+		struct atto_hba_get_device_info get_dev_info;
+		struct atto_hba_trace trace;
+	} data;
+
+};
+
+struct __packed atto_ioctl_vda_scsi_cmd {
+
+    #define ATTO_VDA_SCSI_VER0   0
+    #define ATTO_VDA_SCSI_VER    ATTO_VDA_SCSI_VER0
+
+	u8 cdb[16];
+	u32 flags;
+	u32 data_length;
+	u32 residual_length;
+	u16 target_id;
+	u8 sense_len;
+	u8 scsi_stat;
+	u8 reserved[8];
+	u8 sense_data[80];
+};
+
+struct __packed atto_ioctl_vda_flash_cmd {
+
+    #define ATTO_VDA_FLASH_VER0  0
+    #define ATTO_VDA_FLASH_VER   ATTO_VDA_FLASH_VER0
+
+	u32 flash_addr;
+	u32 data_length;
+	u8 sub_func;
+	u8 reserved[15];
+
+	union {
+		struct {
+			u32 flash_size;
+			u32 page_size;
+			u8 prod_info[32];
+		} info;
+
+		struct {
+			char file_name[16]; /* 8.3 fname, NULL term, wc=* */
+			u32 file_size;
+		} file;
+	} data;
+
+};
+
+struct __packed atto_ioctl_vda_diag_cmd {
+
+    #define ATTO_VDA_DIAG_VER0   0
+    #define ATTO_VDA_DIAG_VER    ATTO_VDA_DIAG_VER0
+
+	u64 local_addr;
+	u32 data_length;
+	u8 sub_func;
+	u8 flags;
+	u8 reserved[3];
+};
+
+struct __packed atto_ioctl_vda_cli_cmd {
+
+    #define ATTO_VDA_CLI_VER0    0
+    #define ATTO_VDA_CLI_VER     ATTO_VDA_CLI_VER0
+
+	u32 cmd_rsp_len;
+};
+
+struct __packed atto_ioctl_vda_smp_cmd {
+
+    #define ATTO_VDA_SMP_VER0    0
+    #define ATTO_VDA_SMP_VER     ATTO_VDA_SMP_VER0
+
+	u64 dest;
+	u32 cmd_rsp_len;
+};
+
+struct __packed atto_ioctl_vda_cfg_cmd {
+
+    #define ATTO_VDA_CFG_VER0    0
+    #define ATTO_VDA_CFG_VER     ATTO_VDA_CFG_VER0
+
+	u32 data_length;
+	u8 cfg_func;
+	u8 reserved[11];
+
+	union {
+		u8 bytes[112];
+		struct atto_vda_cfg_init init;
+	} data;
+
+};
+
+struct __packed atto_ioctl_vda_mgt_cmd {
+
+    #define ATTO_VDA_MGT_VER0    0
+    #define ATTO_VDA_MGT_VER     ATTO_VDA_MGT_VER0
+
+	u8 mgt_func;
+	u8 scan_generation;
+	u16 dev_index;
+	u32 data_length;
+	u8 reserved[8];
+	union {
+		u8 bytes[112];
+		struct atto_vda_devinfo dev_info;
+		struct atto_vda_grp_info grp_info;
+		struct atto_vdapart_info part_info;
+		struct atto_vda_dh_info dh_info;
+		struct atto_vda_metrics_info metrics_info;
+		struct atto_vda_schedule_info sched_info;
+		struct atto_vda_n_vcache_info nvcache_info;
+		struct atto_vda_buzzer_info buzzer_info;
+		struct atto_vda_adapter_info adapter_info;
+		struct atto_vda_temp_info temp_info;
+		struct atto_vda_fan_info fan_info;
+	} data;
+};
+
+struct __packed atto_ioctl_vda_gsv_cmd {
+
+    #define ATTO_VDA_GSV_VER0    0
+    #define ATTO_VDA_GSV_VER     ATTO_VDA_GSV_VER0
+
+	u8 rsp_len;
+	u8 reserved[7];
+	u8 version_info[1];
+	#define ATTO_VDA_VER_UNSUPPORTED 0xFF
+
+};
+
+struct __packed atto_ioctl_vda {
+	u8 version;
+	u8 function;    /* VDA_FUNC_XXXX */
+	u8 status;      /* ATTO_STS_XXX */
+	u8 vda_status;  /* RS_XXX (if status == ATTO_STS_SUCCESS) */
+	u32 data_length;
+	u8 reserved[8];
+
+	union {
+		struct atto_ioctl_vda_scsi_cmd scsi;
+		struct atto_ioctl_vda_flash_cmd flash;
+		struct atto_ioctl_vda_diag_cmd diag;
+		struct atto_ioctl_vda_cli_cmd cli;
+		struct atto_ioctl_vda_smp_cmd smp;
+		struct atto_ioctl_vda_cfg_cmd cfg;
+		struct atto_ioctl_vda_mgt_cmd mgt;
+		struct atto_ioctl_vda_gsv_cmd gsv;
+		u8 cmd_info[256];
+	} cmd;
+
+	union {
+		u8 data[1];
+		struct atto_vda_devinfo2 dev_info2;
+	} data;
+
+};
+
+struct __packed atto_ioctl_smp {
+	u8 version;
+	#define ATTO_SMP_VERSION0        0
+	#define ATTO_SMP_VERSION1        1
+	#define ATTO_SMP_VERSION2        2
+	#define ATTO_SMP_VERSION         ATTO_SMP_VERSION2
+
+	u8 function;
+#define ATTO_SMP_FUNC_DISC_SMP           0x00
+#define ATTO_SMP_FUNC_DISC_TARG          0x01
+#define ATTO_SMP_FUNC_SEND_CMD           0x02
+#define ATTO_SMP_FUNC_DISC_TARG_DIRECT   0x03
+#define ATTO_SMP_FUNC_SEND_CMD_DIRECT    0x04
+#define ATTO_SMP_FUNC_DISC_SMP_DIRECT    0x05
+
+	u8 status;      /* ATTO_STS_XXX */
+	u8 smp_status;  /* if status == ATTO_STS_SUCCESS */
+	#define ATTO_SMP_STS_SUCCESS     0x00
+	#define ATTO_SMP_STS_FAILURE     0x01
+	#define ATTO_SMP_STS_RESCAN      0x02
+	#define ATTO_SMP_STS_NOT_FOUND   0x03
+
+	u16 target_id;
+	u8 phy_id;
+	u8 dev_index;
+	u64 smp_sas_addr;
+	u64 targ_sas_addr;
+	u32 req_length;
+	u32 rsp_length;
+	u8 flags;
+	#define ATTO_SMPF_ROOT_EXP       0x01 /* expander direct attached */
+
+	u8 reserved[31];
+
+	union {
+		u8 byte[1];
+		u32 dword[1];
+	} data;
+
+};
+
+struct __packed atto_express_ioctl {
+	struct atto_express_ioctl_header header;
+
+	union {
+		struct atto_firmware_rw_request fwrw;
+		struct atto_param_rw_request prw;
+		struct atto_channel_list chanlist;
+		struct atto_channel_info chaninfo;
+		struct atto_ioctl ioctl_hba;
+		struct atto_module_info modinfo;
+		struct atto_ioctl_vda ioctl_vda;
+		struct atto_ioctl_smp ioctl_smp;
+		struct atto_csmi csmi;
+
+	} data;
+};
+
+/* The struct associated with the code is listed after the definition */
+#define EXPRESS_IOCTL_MIN             0x4500
+#define EXPRESS_IOCTL_RW_FIRMWARE     0x4500            /* FIRMWARERW    */
+#define EXPRESS_IOCTL_READ_PARAMS     0x4501            /* PARAMRW       */
+#define EXPRESS_IOCTL_WRITE_PARAMS    0x4502            /* PARAMRW       */
+#define EXPRESS_IOCTL_FC_API          0x4503            /* internal      */
+#define EXPRESS_IOCTL_GET_CHANNELS    0x4504            /* CHANNELLIST   */
+#define EXPRESS_IOCTL_CHAN_INFO       0x4505            /* CHANNELINFO   */
+#define EXPRESS_IOCTL_DEFAULT_PARAMS  0x4506            /* PARAMRW       */
+#define EXPRESS_ADDR_MEMORY           0x4507            /* MEMADDR       */
+#define EXPRESS_RW_MEMORY             0x4508            /* MEMRW         */
+#define EXPRESS_TSDK_DUMP             0x4509            /* TSDKDUMP      */
+#define EXPRESS_IOCTL_SMP             0x450A            /* IOCTL_SMP     */
+#define EXPRESS_CSMI                  0x450B            /* CSMI          */
+#define EXPRESS_IOCTL_HBA             0x450C            /* IOCTL_HBA     */
+#define EXPRESS_IOCTL_VDA             0x450D            /* IOCTL_VDA     */
+#define EXPRESS_IOCTL_GET_ID          0x450E            /* GET_ID        */
+#define EXPRESS_IOCTL_GET_MOD_INFO    0x450F            /* MODULE_INFO   */
+#define EXPRESS_IOCTL_MAX             0x450F
+
+#endif
diff --git a/drivers/scsi/esas2r/atvda.h b/drivers/scsi/esas2r/atvda.h
new file mode 100644
index 0000000..5fc1f99
--- /dev/null
+++ b/drivers/scsi/esas2r/atvda.h
@@ -0,0 +1,1319 @@
+/*  linux/drivers/scsi/esas2r/atvda.h
+ *       ATTO VDA interface definitions
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.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; 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.
+ *
+ *  NO WARRANTY
+ *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ *  solely responsible for determining the appropriateness of using and
+ *  distributing the Program and assumes all risks associated with its
+ *  exercise of rights under this Agreement, including but not limited to
+ *  the risks and costs of program errors, damage to or loss of data,
+ *  programs or equipment, and unavailability or interruption of operations.
+ *
+ *  DISCLAIMER OF LIABILITY
+ *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ *  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
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+
+#ifndef ATVDA_H
+#define ATVDA_H
+
+struct __packed atto_dev_addr {
+	u64 dev_port;
+	u64 hba_port;
+	u8 lun;
+	u8 flags;
+	   #define VDA_DEVADDRF_SATA   0x01
+	   #define VDA_DEVADDRF_SSD    0x02
+	u8 link_speed; /* VDALINKSPEED_xxx */
+	u8 pad[1];
+};
+
+/* dev_addr2 was added for 64-bit alignment */
+
+struct __packed atto_dev_addr2 {
+	u64 dev_port;
+	u64 hba_port;
+	u8 lun;
+	u8 flags;
+	u8 link_speed;
+	u8 pad[5];
+};
+
+struct __packed atto_vda_sge {
+	u32 length;
+	u64 address;
+};
+
+
+/* VDA request function codes */
+
+#define VDA_FUNC_SCSI     0x00
+#define VDA_FUNC_FLASH    0x01
+#define VDA_FUNC_DIAG     0x02
+#define VDA_FUNC_AE       0x03
+#define VDA_FUNC_CLI      0x04
+#define VDA_FUNC_IOCTL    0x05
+#define VDA_FUNC_CFG      0x06
+#define VDA_FUNC_MGT      0x07
+#define VDA_FUNC_GSV      0x08
+
+
+/* VDA request status values.  for host driver considerations, values for
+ * SCSI requests start at zero.  other requests may use these values as well. */
+
+#define RS_SUCCESS          0x00        /*! successful completion            */
+#define RS_INV_FUNC         0x01        /*! invalid command function         */
+#define RS_BUSY             0x02        /*! insufficient resources           */
+#define RS_SEL              0x03        /*! no target at target_id           */
+#define RS_NO_LUN           0x04        /*! invalid LUN                      */
+#define RS_TIMEOUT          0x05        /*! request timeout                  */
+#define RS_OVERRUN          0x06        /*! data overrun                     */
+#define RS_UNDERRUN         0x07        /*! data underrun                    */
+#define RS_SCSI_ERROR       0x08        /*! SCSI error occurred              */
+#define RS_ABORTED          0x0A        /*! command aborted                  */
+#define RS_RESID_MISM       0x0B        /*! residual length incorrect        */
+#define RS_TM_FAILED        0x0C        /*! task management failed           */
+#define RS_RESET            0x0D        /*! aborted due to bus reset         */
+#define RS_ERR_DMA_SG       0x0E        /*! error reading SG list            */
+#define RS_ERR_DMA_DATA     0x0F        /*! error transferring data          */
+#define RS_UNSUPPORTED      0x10        /*! unsupported request              */
+#define RS_SEL2             0x70        /*! internal generated RS_SEL        */
+#define RS_VDA_BASE         0x80        /*! base of VDA-specific errors      */
+#define RS_MGT_BASE         0x80        /*! base of VDA management errors    */
+#define RS_SCAN_FAIL        (RS_MGT_BASE + 0x00)
+#define RS_DEV_INVALID      (RS_MGT_BASE + 0x01)
+#define RS_DEV_ASSIGNED     (RS_MGT_BASE + 0x02)
+#define RS_DEV_REMOVE       (RS_MGT_BASE + 0x03)
+#define RS_DEV_LOST         (RS_MGT_BASE + 0x04)
+#define RS_SCAN_GEN         (RS_MGT_BASE + 0x05)
+#define RS_GRP_INVALID      (RS_MGT_BASE + 0x08)
+#define RS_GRP_EXISTS       (RS_MGT_BASE + 0x09)
+#define RS_GRP_LIMIT        (RS_MGT_BASE + 0x0A)
+#define RS_GRP_INTLV        (RS_MGT_BASE + 0x0B)
+#define RS_GRP_SPAN         (RS_MGT_BASE + 0x0C)
+#define RS_GRP_TYPE         (RS_MGT_BASE + 0x0D)
+#define RS_GRP_MEMBERS      (RS_MGT_BASE + 0x0E)
+#define RS_GRP_COMMIT       (RS_MGT_BASE + 0x0F)
+#define RS_GRP_REBUILD      (RS_MGT_BASE + 0x10)
+#define RS_GRP_REBUILD_TYPE (RS_MGT_BASE + 0x11)
+#define RS_GRP_BLOCK_SIZE   (RS_MGT_BASE + 0x12)
+#define RS_CFG_SAVE         (RS_MGT_BASE + 0x14)
+#define RS_PART_LAST        (RS_MGT_BASE + 0x18)
+#define RS_ELEM_INVALID     (RS_MGT_BASE + 0x19)
+#define RS_PART_MAPPED      (RS_MGT_BASE + 0x1A)
+#define RS_PART_TARGET      (RS_MGT_BASE + 0x1B)
+#define RS_PART_LUN         (RS_MGT_BASE + 0x1C)
+#define RS_PART_DUP         (RS_MGT_BASE + 0x1D)
+#define RS_PART_NOMAP       (RS_MGT_BASE + 0x1E)
+#define RS_PART_MAX         (RS_MGT_BASE + 0x1F)
+#define RS_PART_CAP         (RS_MGT_BASE + 0x20)
+#define RS_PART_STATE       (RS_MGT_BASE + 0x21)
+#define RS_TEST_IN_PROG     (RS_MGT_BASE + 0x22)
+#define RS_METRICS_ERROR    (RS_MGT_BASE + 0x23)
+#define RS_HS_ERROR         (RS_MGT_BASE + 0x24)
+#define RS_NO_METRICS_TEST  (RS_MGT_BASE + 0x25)
+#define RS_BAD_PARAM        (RS_MGT_BASE + 0x26)
+#define RS_GRP_MEMBER_SIZE  (RS_MGT_BASE + 0x27)
+#define RS_FLS_BASE         0xB0        /*! base of VDA errors               */
+#define RS_FLS_ERR_AREA     (RS_FLS_BASE + 0x00)
+#define RS_FLS_ERR_BUSY     (RS_FLS_BASE + 0x01)
+#define RS_FLS_ERR_RANGE    (RS_FLS_BASE + 0x02)
+#define RS_FLS_ERR_BEGIN    (RS_FLS_BASE + 0x03)
+#define RS_FLS_ERR_CHECK    (RS_FLS_BASE + 0x04)
+#define RS_FLS_ERR_FAIL     (RS_FLS_BASE + 0x05)
+#define RS_FLS_ERR_RSRC     (RS_FLS_BASE + 0x06)
+#define RS_FLS_ERR_NOFILE   (RS_FLS_BASE + 0x07)
+#define RS_FLS_ERR_FSIZE    (RS_FLS_BASE + 0x08)
+#define RS_CFG_BASE         0xC0        /*! base of VDA configuration errors */
+#define RS_CFG_ERR_BUSY     (RS_CFG_BASE + 0)
+#define RS_CFG_ERR_SGE      (RS_CFG_BASE + 1)
+#define RS_CFG_ERR_DATE     (RS_CFG_BASE + 2)
+#define RS_CFG_ERR_TIME     (RS_CFG_BASE + 3)
+#define RS_DEGRADED         0xFB        /*! degraded mode                    */
+#define RS_CLI_INTERNAL     0xFC        /*! VDA CLI internal error           */
+#define RS_VDA_INTERNAL     0xFD        /*! catch-all                        */
+#define RS_PENDING          0xFE        /*! pending, not started             */
+#define RS_STARTED          0xFF        /*! started                          */
+
+
+/* flash request subfunctions.  these are used in both the IOCTL and the
+ * driver-firmware interface (VDA_FUNC_FLASH). */
+
+#define VDA_FLASH_BEGINW  0x00
+#define VDA_FLASH_READ    0x01
+#define VDA_FLASH_WRITE   0x02
+#define VDA_FLASH_COMMIT  0x03
+#define VDA_FLASH_CANCEL  0x04
+#define VDA_FLASH_INFO    0x05
+#define VDA_FLASH_FREAD   0x06
+#define VDA_FLASH_FWRITE  0x07
+#define VDA_FLASH_FINFO   0x08
+
+
+/* IOCTL request subfunctions.  these identify the payload type for
+ * VDA_FUNC_IOCTL.
+ */
+
+#define VDA_IOCTL_HBA     0x00
+#define VDA_IOCTL_CSMI    0x01
+#define VDA_IOCTL_SMP     0x02
+
+struct __packed atto_vda_devinfo {
+	struct atto_dev_addr dev_addr;
+	u8 vendor_id[8];
+	u8 product_id[16];
+	u8 revision[4];
+	u64 capacity;
+	u32 block_size;
+	u8 dev_type;
+
+	union {
+		u8 dev_status;
+	    #define VDADEVSTAT_INVALID   0x00
+	    #define VDADEVSTAT_CORRUPT   VDADEVSTAT_INVALID
+	    #define VDADEVSTAT_ASSIGNED  0x01
+	    #define VDADEVSTAT_SPARE     0x02
+	    #define VDADEVSTAT_UNAVAIL   0x03
+	    #define VDADEVSTAT_PT_MAINT  0x04
+	    #define VDADEVSTAT_LCLSPARE  0x05
+	    #define VDADEVSTAT_UNUSEABLE 0x06
+	    #define VDADEVSTAT_AVAIL     0xFF
+
+		u8 op_ctrl;
+	    #define VDA_DEV_OP_CTRL_START   0x01
+	    #define VDA_DEV_OP_CTRL_HALT    0x02
+	    #define VDA_DEV_OP_CTRL_RESUME  0x03
+	    #define VDA_DEV_OP_CTRL_CANCEL  0x04
+	};
+
+	u8 member_state;
+	#define VDAMBRSTATE_ONLINE   0x00
+	#define VDAMBRSTATE_DEGRADED 0x01
+	#define VDAMBRSTATE_UNAVAIL  0x02
+	#define VDAMBRSTATE_FAULTED  0x03
+	#define VDAMBRSTATE_MISREAD  0x04
+	#define VDAMBRSTATE_INCOMPAT 0x05
+
+	u8 operation;
+	#define VDAOP_NONE           0x00
+	#define VDAOP_REBUILD        0x01
+	#define VDAOP_ERASE          0x02
+	#define VDAOP_PATTERN        0x03
+	#define VDAOP_CONVERSION     0x04
+	#define VDAOP_FULL_INIT      0x05
+	#define VDAOP_QUICK_INIT     0x06
+	#define VDAOP_SECT_SCAN      0x07
+	#define VDAOP_SECT_SCAN_PARITY      0x08
+	#define VDAOP_SECT_SCAN_PARITY_FIX  0x09
+	#define VDAOP_RECOV_REBUILD  0x0A
+
+	u8 op_status;
+	#define VDAOPSTAT_OK         0x00
+	#define VDAOPSTAT_FAULTED    0x01
+	#define VDAOPSTAT_HALTED     0x02
+	#define VDAOPSTAT_INT        0x03
+
+	u8 progress; /* 0 - 100% */
+	u16 ses_dev_index;
+	#define VDASESDI_INVALID     0xFFFF
+
+	u8 serial_no[32];
+
+	union {
+		u16 target_id;
+	#define VDATGTID_INVALID     0xFFFF
+
+		u16 features_mask;
+	};
+
+	u16 lun;
+	u16 features;
+	#define VDADEVFEAT_ENC_SERV  0x0001
+	#define VDADEVFEAT_IDENT     0x0002
+	#define VDADEVFEAT_DH_SUPP   0x0004
+	#define VDADEVFEAT_PHYS_ID   0x0008
+
+	u8 ses_element_id;
+	u8 link_speed;
+	#define VDALINKSPEED_UNKNOWN 0x00
+	#define VDALINKSPEED_1GB     0x01
+	#define VDALINKSPEED_1_5GB   0x02
+	#define VDALINKSPEED_2GB     0x03
+	#define VDALINKSPEED_3GB     0x04
+	#define VDALINKSPEED_4GB     0x05
+	#define VDALINKSPEED_6GB     0x06
+	#define VDALINKSPEED_8GB     0x07
+
+	u16 phys_target_id;
+	u8 reserved[2];
+};
+
+
+/*! struct atto_vda_devinfo2 is a replacement for atto_vda_devinfo.  it
+ * extends beyond the 0x70 bytes allowed in atto_vda_mgmt_req; therefore,
+ * the entire structure is DMaed between the firmware and host buffer and
+ * the data will always be in little endian format.
+ */
+
+struct __packed atto_vda_devinfo2 {
+	struct atto_dev_addr dev_addr;
+	u8 vendor_id[8];
+	u8 product_id[16];
+	u8 revision[4];
+	u64 capacity;
+	u32 block_size;
+	u8 dev_type;
+	u8 dev_status;
+	u8 member_state;
+	u8 operation;
+	u8 op_status;
+	u8 progress;
+	u16 ses_dev_index;
+	u8 serial_no[32];
+	union {
+		u16 target_id;
+		u16 features_mask;
+	};
+
+	u16 lun;
+	u16 features;
+	u8 ses_element_id;
+	u8 link_speed;
+	u16 phys_target_id;
+	u8 reserved[2];
+
+/* This is where fields specific to struct atto_vda_devinfo2 begin.  Note
+ * that the structure version started at one so applications that unionize this
+ * structure with atto_vda_dev_info can differentiate them if desired.
+ */
+
+	u8 version;
+	#define VDADEVINFO_VERSION0         0x00
+	#define VDADEVINFO_VERSION1         0x01
+	#define VDADEVINFO_VERSION2         0x02
+	#define VDADEVINFO_VERSION3         0x03
+	#define VDADEVINFO_VERSION          VDADEVINFO_VERSION3
+
+	u8 reserved2[3];
+
+	/* sector scanning fields */
+
+	u32 ss_curr_errors;
+	u64 ss_curr_scanned;
+	u32 ss_curr_recvrd;
+	u32 ss_scan_length;
+	u32 ss_total_errors;
+	u32 ss_total_recvrd;
+	u32 ss_num_scans;
+
+	/* grp_name was added in version 2 of this structure. */
+
+	char grp_name[15];
+	u8 reserved3[4];
+
+	/* dev_addr_list was added in version 3 of this structure. */
+
+	u8 num_dev_addr;
+	struct atto_dev_addr2 dev_addr_list[8];
+};
+
+
+struct __packed atto_vda_grp_info {
+	u8 grp_index;
+	#define VDA_MAX_RAID_GROUPS         32
+
+	char grp_name[15];
+	u64 capacity;
+	u32 block_size;
+	u32 interleave;
+	u8 type;
+	#define VDA_GRP_TYPE_RAID0          0
+	#define VDA_GRP_TYPE_RAID1          1
+	#define VDA_GRP_TYPE_RAID4          4
+	#define VDA_GRP_TYPE_RAID5          5
+	#define VDA_GRP_TYPE_RAID6          6
+	#define VDA_GRP_TYPE_RAID10         10
+	#define VDA_GRP_TYPE_RAID40         40
+	#define VDA_GRP_TYPE_RAID50         50
+	#define VDA_GRP_TYPE_RAID60         60
+	#define VDA_GRP_TYPE_DVRAID_HS      252
+	#define VDA_GRP_TYPE_DVRAID_NOHS    253
+	#define VDA_GRP_TYPE_JBOD           254
+	#define VDA_GRP_TYPE_SPARE          255
+
+	union {
+		u8 status;
+	    #define VDA_GRP_STAT_INVALID  0x00
+	    #define VDA_GRP_STAT_NEW      0x01
+	    #define VDA_GRP_STAT_WAITING  0x02
+	    #define VDA_GRP_STAT_ONLINE   0x03
+	    #define VDA_GRP_STAT_DEGRADED 0x04
+	    #define VDA_GRP_STAT_OFFLINE  0x05
+	    #define VDA_GRP_STAT_DELETED  0x06
+	    #define VDA_GRP_STAT_RECOV_BASIC    0x07
+	    #define VDA_GRP_STAT_RECOV_EXTREME  0x08
+
+		u8 op_ctrl;
+	    #define VDA_GRP_OP_CTRL_START   0x01
+	    #define VDA_GRP_OP_CTRL_HALT    0x02
+	    #define VDA_GRP_OP_CTRL_RESUME  0x03
+	    #define VDA_GRP_OP_CTRL_CANCEL  0x04
+	};
+
+	u8 rebuild_state;
+	#define VDA_RBLD_NONE      0x00
+	#define VDA_RBLD_REBUILD   0x01
+	#define VDA_RBLD_ERASE     0x02
+	#define VDA_RBLD_PATTERN   0x03
+	#define VDA_RBLD_CONV      0x04
+	#define VDA_RBLD_FULL_INIT 0x05
+	#define VDA_RBLD_QUICK_INIT 0x06
+	#define VDA_RBLD_SECT_SCAN 0x07
+	#define VDA_RBLD_SECT_SCAN_PARITY     0x08
+	#define VDA_RBLD_SECT_SCAN_PARITY_FIX 0x09
+	#define VDA_RBLD_RECOV_REBUILD 0x0A
+	#define VDA_RBLD_RECOV_BASIC   0x0B
+	#define VDA_RBLD_RECOV_EXTREME 0x0C
+
+	u8 span_depth;
+	u8 progress;
+	u8 mirror_width;
+	u8 stripe_width;
+	u8 member_cnt;
+
+	union {
+		u16 members[32];
+	#define VDA_MEMBER_MISSING  0xFFFF
+	#define VDA_MEMBER_NEW      0xFFFE
+		u16 features_mask;
+	};
+
+	u16 features;
+	#define VDA_GRP_FEAT_HOTSWAP    0x0001
+	#define VDA_GRP_FEAT_SPDRD_MASK 0x0006
+	#define VDA_GRP_FEAT_SPDRD_DIS  0x0000
+	#define VDA_GRP_FEAT_SPDRD_ENB  0x0002
+	#define VDA_GRP_FEAT_SPDRD_AUTO 0x0004
+	#define VDA_GRP_FEAT_IDENT      0x0008
+	#define VDA_GRP_FEAT_RBLDPRI_MASK 0x0030
+	#define VDA_GRP_FEAT_RBLDPRI_LOW  0x0010
+	#define VDA_GRP_FEAT_RBLDPRI_SAME 0x0020
+	#define VDA_GRP_FEAT_RBLDPRI_HIGH 0x0030
+	#define VDA_GRP_FEAT_WRITE_CACHE  0x0040
+	#define VDA_GRP_FEAT_RBLD_RESUME  0x0080
+	#define VDA_GRP_FEAT_SECT_RESUME  0x0100
+	#define VDA_GRP_FEAT_INIT_RESUME  0x0200
+	#define VDA_GRP_FEAT_SSD          0x0400
+	#define VDA_GRP_FEAT_BOOT_DEV     0x0800
+
+	/*
+	 * for backward compatibility, a prefetch value of zero means the
+	 * setting is ignored/unsupported.  therefore, the firmware supported
+	 * 0-6 values are incremented to 1-7.
+	 */
+
+	u8 prefetch;
+	u8 op_status;
+	#define VDAGRPOPSTAT_MASK       0x0F
+	#define VDAGRPOPSTAT_INVALID    0x00
+	#define VDAGRPOPSTAT_OK         0x01
+	#define VDAGRPOPSTAT_FAULTED    0x02
+	#define VDAGRPOPSTAT_HALTED     0x03
+	#define VDAGRPOPSTAT_INT        0x04
+	#define VDAGRPOPPROC_MASK       0xF0
+	#define VDAGRPOPPROC_STARTABLE  0x10
+	#define VDAGRPOPPROC_CANCELABLE 0x20
+	#define VDAGRPOPPROC_RESUMABLE  0x40
+	#define VDAGRPOPPROC_HALTABLE   0x80
+	u8 over_provision;
+	u8 reserved[3];
+
+};
+
+
+struct __packed atto_vdapart_info {
+	u8 part_no;
+	#define VDA_MAX_PARTITIONS   128
+
+	char grp_name[15];
+	u64 part_size;
+	u64 start_lba;
+	u32 block_size;
+	u16 target_id;
+	u8 LUN;
+	char serial_no[41];
+	u8 features;
+	#define VDAPI_FEAT_WRITE_CACHE   0x01
+
+	u8 reserved[7];
+};
+
+
+struct __packed atto_vda_dh_info {
+	u8 req_type;
+	#define VDADH_RQTYPE_CACHE      0x01
+	#define VDADH_RQTYPE_FETCH      0x02
+	#define VDADH_RQTYPE_SET_STAT   0x03
+	#define VDADH_RQTYPE_GET_STAT   0x04
+
+	u8 req_qual;
+	#define VDADH_RQQUAL_SMART      0x01
+	#define VDADH_RQQUAL_MEDDEF     0x02
+	#define VDADH_RQQUAL_INFOEXC    0x04
+
+	u8 num_smart_attribs;
+	u8 status;
+	#define VDADH_STAT_DISABLE      0x00
+	#define VDADH_STAT_ENABLE       0x01
+
+	u32 med_defect_cnt;
+	u32 info_exc_cnt;
+	u8 smart_status;
+	#define VDADH_SMARTSTAT_OK      0x00
+	#define VDADH_SMARTSTAT_ERR     0x01
+
+	u8 reserved[35];
+	struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_dh_smart {
+	u8 attrib_id;
+	u8 current_val;
+	u8 worst;
+	u8 threshold;
+	u8 raw_data[6];
+	u8 raw_attrib_status;
+	#define VDADHSM_RAWSTAT_PREFAIL_WARRANTY        0x01
+	#define VDADHSM_RAWSTAT_ONLINE_COLLECTION       0x02
+	#define VDADHSM_RAWSTAT_PERFORMANCE_ATTR        0x04
+	#define VDADHSM_RAWSTAT_ERROR_RATE_ATTR         0x08
+	#define VDADHSM_RAWSTAT_EVENT_COUNT_ATTR        0x10
+	#define VDADHSM_RAWSTAT_SELF_PRESERVING_ATTR    0x20
+
+	u8 calc_attrib_status;
+	#define VDADHSM_CALCSTAT_UNKNOWN                0x00
+	#define VDADHSM_CALCSTAT_GOOD                   0x01
+	#define VDADHSM_CALCSTAT_PREFAIL                0x02
+	#define VDADHSM_CALCSTAT_OLDAGE                 0x03
+
+	u8 reserved[4];
+};
+
+
+struct __packed atto_vda_metrics_info {
+	u8 data_version;
+	#define VDAMET_VERSION0         0x00
+	#define VDAMET_VERSION          VDAMET_VERSION0
+
+	u8 metrics_action;
+	#define VDAMET_METACT_NONE      0x00
+	#define VDAMET_METACT_START     0x01
+	#define VDAMET_METACT_STOP      0x02
+	#define VDAMET_METACT_RETRIEVE  0x03
+	#define VDAMET_METACT_CLEAR     0x04
+
+	u8 test_action;
+	#define VDAMET_TSTACT_NONE              0x00
+	#define VDAMET_TSTACT_STRT_INIT         0x01
+	#define VDAMET_TSTACT_STRT_READ         0x02
+	#define VDAMET_TSTACT_STRT_VERIFY       0x03
+	#define VDAMET_TSTACT_STRT_INIT_VERIFY  0x04
+	#define VDAMET_TSTACT_STOP              0x05
+
+	u8 num_dev_indexes;
+	#define VDAMET_ALL_DEVICES      0xFF
+
+	u16 dev_indexes[32];
+	u8 reserved[12];
+	struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_metrics_data {
+	u16 dev_index;
+	u16 length;
+	#define VDAMD_LEN_LAST          0x8000
+	#define VDAMD_LEN_MASK          0x0FFF
+
+	u32 flags;
+	#define VDAMDF_RUN          0x00000007
+	#define VDAMDF_RUN_READ     0x00000001
+	#define VDAMDF_RUN_WRITE    0x00000002
+	#define VDAMDF_RUN_ALL      0x00000004
+	#define VDAMDF_READ         0x00000010
+	#define VDAMDF_WRITE        0x00000020
+	#define VDAMDF_ALL          0x00000040
+	#define VDAMDF_DRIVETEST    0x40000000
+	#define VDAMDF_NEW          0x80000000
+
+	u64 total_read_data;
+	u64 total_write_data;
+	u64 total_read_io;
+	u64 total_write_io;
+	u64 read_start_time;
+	u64 read_stop_time;
+	u64 write_start_time;
+	u64 write_stop_time;
+	u64 read_maxio_time;
+	u64 wpvdadmetricsdatarite_maxio_time;
+	u64 read_totalio_time;
+	u64 write_totalio_time;
+	u64 read_total_errs;
+	u64 write_total_errs;
+	u64 read_recvrd_errs;
+	u64 write_recvrd_errs;
+	u64 miscompares;
+};
+
+
+struct __packed atto_vda_schedule_info {
+	u8 schedule_type;
+	#define VDASI_SCHTYPE_ONETIME   0x01
+	#define VDASI_SCHTYPE_DAILY     0x02
+	#define VDASI_SCHTYPE_WEEKLY    0x03
+
+	u8 operation;
+	#define VDASI_OP_NONE           0x00
+	#define VDASI_OP_CREATE         0x01
+	#define VDASI_OP_CANCEL         0x02
+
+	u8 hour;
+	u8 minute;
+	u8 day;
+	#define VDASI_DAY_NONE          0x00
+
+	u8 progress;
+	#define VDASI_PROG_NONE         0xFF
+
+	u8 event_type;
+	#define VDASI_EVTTYPE_SECT_SCAN             0x01
+	#define VDASI_EVTTYPE_SECT_SCAN_PARITY      0x02
+	#define VDASI_EVTTYPE_SECT_SCAN_PARITY_FIX  0x03
+
+	u8 recurrences;
+	#define VDASI_RECUR_FOREVER     0x00
+
+	u32 id;
+	#define VDASI_ID_NONE           0x00
+
+	char grp_name[15];
+	u8 reserved[85];
+};
+
+
+struct __packed atto_vda_n_vcache_info {
+	u8 super_cap_status;
+	#define VDANVCI_SUPERCAP_NOT_PRESENT       0x00
+	#define VDANVCI_SUPERCAP_FULLY_CHARGED     0x01
+	#define VDANVCI_SUPERCAP_NOT_CHARGED       0x02
+
+	u8 nvcache_module_status;
+	#define VDANVCI_NVCACHEMODULE_NOT_PRESENT  0x00
+	#define VDANVCI_NVCACHEMODULE_PRESENT      0x01
+
+	u8 protection_mode;
+	#define VDANVCI_PROTMODE_HI_PROTECT        0x00
+	#define VDANVCI_PROTMODE_HI_PERFORM        0x01
+
+	u8 reserved[109];
+};
+
+
+struct __packed atto_vda_buzzer_info {
+	u8 status;
+	#define VDABUZZI_BUZZER_OFF           0x00
+	#define VDABUZZI_BUZZER_ON            0x01
+	#define VDABUZZI_BUZZER_LAST          0x02
+
+	u8 reserved[3];
+	u32 duration;
+	#define VDABUZZI_DURATION_INDEFINITE  0xffffffff
+
+	u8 reserved2[104];
+};
+
+
+struct  __packed atto_vda_adapter_info {
+	u8 version;
+	#define VDAADAPINFO_VERSION0         0x00
+	#define VDAADAPINFO_VERSION          VDAADAPINFO_VERSION0
+
+	u8 reserved;
+	signed short utc_offset;
+	u32 utc_time;
+	u32 features;
+	#define VDA_ADAP_FEAT_IDENT     0x0001
+	#define VDA_ADAP_FEAT_BUZZ_ERR  0x0002
+	#define VDA_ADAP_FEAT_UTC_TIME  0x0004
+
+	u32 valid_features;
+	char active_config[33];
+	u8 temp_count;
+	u8 fan_count;
+	u8 reserved3[61];
+};
+
+
+struct __packed atto_vda_temp_info {
+	u8 temp_index;
+	u8 max_op_temp;
+	u8 min_op_temp;
+	u8 op_temp_warn;
+	u8 temperature;
+	u8 type;
+	#define VDA_TEMP_TYPE_CPU  1
+
+	u8 reserved[106];
+};
+
+
+struct __packed atto_vda_fan_info {
+	u8 fan_index;
+	u8 status;
+	#define VDA_FAN_STAT_UNKNOWN 0
+	#define VDA_FAN_STAT_NORMAL  1
+	#define VDA_FAN_STAT_FAIL    2
+
+	u16 crit_pvdafaninfothreshold;
+	u16 warn_threshold;
+	u16 speed;
+	u8 reserved[104];
+};
+
+
+/* VDA management commands */
+
+#define VDAMGT_DEV_SCAN         0x00
+#define VDAMGT_DEV_INFO         0x01
+#define VDAMGT_DEV_CLEAN        0x02
+#define VDAMGT_DEV_IDENTIFY     0x03
+#define VDAMGT_DEV_IDENTSTOP    0x04
+#define VDAMGT_DEV_PT_INFO      0x05
+#define VDAMGT_DEV_FEATURES     0x06
+#define VDAMGT_DEV_PT_FEATURES  0x07
+#define VDAMGT_DEV_HEALTH_REQ   0x08
+#define VDAMGT_DEV_METRICS      0x09
+#define VDAMGT_DEV_INFO2        0x0A
+#define VDAMGT_DEV_OPERATION    0x0B
+#define VDAMGT_DEV_INFO2_BYADDR 0x0C
+#define VDAMGT_GRP_INFO         0x10
+#define VDAMGT_GRP_CREATE       0x11
+#define VDAMGT_GRP_DELETE       0x12
+#define VDAMGT_ADD_STORAGE      0x13
+#define VDAMGT_MEMBER_ADD       0x14
+#define VDAMGT_GRP_COMMIT       0x15
+#define VDAMGT_GRP_REBUILD      0x16
+#define VDAMGT_GRP_COMMIT_INIT  0x17
+#define VDAMGT_QUICK_RAID       0x18
+#define VDAMGT_GRP_FEATURES     0x19
+#define VDAMGT_GRP_COMMIT_INIT_AUTOMAP  0x1A
+#define VDAMGT_QUICK_RAID_INIT_AUTOMAP  0x1B
+#define VDAMGT_GRP_OPERATION    0x1C
+#define VDAMGT_CFG_SAVE         0x20
+#define VDAMGT_LAST_ERROR       0x21
+#define VDAMGT_ADAP_INFO        0x22
+#define VDAMGT_ADAP_FEATURES    0x23
+#define VDAMGT_TEMP_INFO        0x24
+#define VDAMGT_FAN_INFO         0x25
+#define VDAMGT_PART_INFO        0x30
+#define VDAMGT_PART_MAP         0x31
+#define VDAMGT_PART_UNMAP       0x32
+#define VDAMGT_PART_AUTOMAP     0x33
+#define VDAMGT_PART_SPLIT       0x34
+#define VDAMGT_PART_MERGE       0x35
+#define VDAMGT_SPARE_LIST       0x40
+#define VDAMGT_SPARE_ADD        0x41
+#define VDAMGT_SPARE_REMOVE     0x42
+#define VDAMGT_LOCAL_SPARE_ADD  0x43
+#define VDAMGT_SCHEDULE_EVENT   0x50
+#define VDAMGT_SCHEDULE_INFO    0x51
+#define VDAMGT_NVCACHE_INFO     0x60
+#define VDAMGT_NVCACHE_SET      0x61
+#define VDAMGT_BUZZER_INFO      0x70
+#define VDAMGT_BUZZER_SET       0x71
+
+
+struct __packed atto_vda_ae_hdr {
+	u8 bylength;
+	u8 byflags;
+	#define VDAAE_HDRF_EVENT_ACK    0x01
+
+	u8 byversion;
+	#define VDAAE_HDR_VER_0         0
+
+	u8 bytype;
+	#define VDAAE_HDR_TYPE_RAID     1
+	#define VDAAE_HDR_TYPE_LU       2
+	#define VDAAE_HDR_TYPE_DISK     3
+	#define VDAAE_HDR_TYPE_RESET    4
+	#define VDAAE_HDR_TYPE_LOG_INFO 5
+	#define VDAAE_HDR_TYPE_LOG_WARN 6
+	#define VDAAE_HDR_TYPE_LOG_CRIT 7
+	#define VDAAE_HDR_TYPE_LOG_FAIL 8
+	#define VDAAE_HDR_TYPE_NVC      9
+	#define VDAAE_HDR_TYPE_TLG_INFO 10
+	#define VDAAE_HDR_TYPE_TLG_WARN 11
+	#define VDAAE_HDR_TYPE_TLG_CRIT 12
+	#define VDAAE_HDR_TYPE_PWRMGT   13
+	#define VDAAE_HDR_TYPE_MUTE     14
+	#define VDAAE_HDR_TYPE_DEV      15
+};
+
+
+struct  __packed atto_vda_ae_raid {
+	struct atto_vda_ae_hdr hdr;
+	u32 dwflags;
+	#define VDAAE_GROUP_STATE   0x00000001
+	#define VDAAE_RBLD_STATE    0x00000002
+	#define VDAAE_RBLD_PROG     0x00000004
+	#define VDAAE_MEMBER_CHG    0x00000008
+	#define VDAAE_PART_CHG      0x00000010
+	#define VDAAE_MEM_STATE_CHG 0x00000020
+
+	u8 bygroup_state;
+	#define VDAAE_RAID_INVALID  0
+	#define VDAAE_RAID_NEW      1
+	#define VDAAE_RAID_WAITING  2
+	#define VDAAE_RAID_ONLINE   3
+	#define VDAAE_RAID_DEGRADED 4
+	#define VDAAE_RAID_OFFLINE  5
+	#define VDAAE_RAID_DELETED  6
+	#define VDAAE_RAID_BASIC    7
+	#define VDAAE_RAID_EXTREME  8
+	#define VDAAE_RAID_UNKNOWN  9
+
+	u8 byrebuild_state;
+	#define VDAAE_RBLD_NONE       0
+	#define VDAAE_RBLD_REBUILD    1
+	#define VDAAE_RBLD_ERASE      2
+	#define VDAAE_RBLD_PATTERN    3
+	#define VDAAE_RBLD_CONV       4
+	#define VDAAE_RBLD_FULL_INIT  5
+	#define VDAAE_RBLD_QUICK_INIT 6
+	#define VDAAE_RBLD_SECT_SCAN  7
+	#define VDAAE_RBLD_SECT_SCAN_PARITY     8
+	#define VDAAE_RBLD_SECT_SCAN_PARITY_FIX 9
+	#define VDAAE_RBLD_RECOV_REBUILD 10
+	#define VDAAE_RBLD_UNKNOWN    11
+
+	u8 byrebuild_progress;
+	u8 op_status;
+	#define VDAAE_GRPOPSTAT_MASK       0x0F
+	#define VDAAE_GRPOPSTAT_INVALID    0x00
+	#define VDAAE_GRPOPSTAT_OK         0x01
+	#define VDAAE_GRPOPSTAT_FAULTED    0x02
+	#define VDAAE_GRPOPSTAT_HALTED     0x03
+	#define VDAAE_GRPOPSTAT_INT        0x04
+	#define VDAAE_GRPOPPROC_MASK       0xF0
+	#define VDAAE_GRPOPPROC_STARTABLE  0x10
+	#define VDAAE_GRPOPPROC_CANCELABLE 0x20
+	#define VDAAE_GRPOPPROC_RESUMABLE  0x40
+	#define VDAAE_GRPOPPROC_HALTABLE   0x80
+	char acname[15];
+	u8 byreserved;
+	u8 byreserved2[0x80 - 0x1C];
+};
+
+
+struct __packed atto_vda_ae_lu_tgt_lun {
+	u16 wtarget_id;
+	u8 bylun;
+	u8 byreserved;
+};
+
+
+struct __packed atto_vda_ae_lu_tgt_lun_raid {
+	u16 wtarget_id;
+	u8 bylun;
+	u8 byreserved;
+	u32 dwinterleave;
+	u32 dwblock_size;
+};
+
+
+struct __packed atto_vda_ae_lu {
+	struct atto_vda_ae_hdr hdr;
+	u32 dwevent;
+	#define VDAAE_LU_DISC        0x00000001
+	#define VDAAE_LU_LOST        0x00000002
+	#define VDAAE_LU_STATE       0x00000004
+	#define VDAAE_LU_PASSTHROUGH 0x10000000
+	#define VDAAE_LU_PHYS_ID     0x20000000
+
+	u8 bystate;
+	#define VDAAE_LU_UNDEFINED        0
+	#define VDAAE_LU_NOT_PRESENT      1
+	#define VDAAE_LU_OFFLINE          2
+	#define VDAAE_LU_ONLINE           3
+	#define VDAAE_LU_DEGRADED         4
+	#define VDAAE_LU_FACTORY_DISABLED 5
+	#define VDAAE_LU_DELETED          6
+	#define VDAAE_LU_BUSSCAN          7
+	#define VDAAE_LU_UNKNOWN          8
+
+	u8 byreserved;
+	u16 wphys_target_id;
+
+	union {
+		struct atto_vda_ae_lu_tgt_lun tgtlun;
+		struct atto_vda_ae_lu_tgt_lun_raid tgtlun_raid;
+	} id;
+};
+
+
+struct __packed atto_vda_ae_disk {
+	struct atto_vda_ae_hdr hdr;
+};
+
+
+#define VDAAE_LOG_STRSZ 64
+
+struct __packed atto_vda_ae_log {
+	struct atto_vda_ae_hdr hdr;
+	char aclog_ascii[VDAAE_LOG_STRSZ];
+};
+
+
+#define VDAAE_TLG_STRSZ 56
+
+struct __packed atto_vda_ae_timestamp_log {
+	struct atto_vda_ae_hdr hdr;
+	u32 dwtimestamp;
+	char aclog_ascii[VDAAE_TLG_STRSZ];
+};
+
+
+struct __packed atto_vda_ae_nvc {
+	struct atto_vda_ae_hdr hdr;
+};
+
+
+struct __packed atto_vda_ae_dev {
+	struct atto_vda_ae_hdr hdr;
+	struct atto_dev_addr devaddr;
+};
+
+
+union atto_vda_ae {
+	struct atto_vda_ae_hdr hdr;
+	struct atto_vda_ae_disk disk;
+	struct atto_vda_ae_lu lu;
+	struct atto_vda_ae_raid raid;
+	struct atto_vda_ae_log log;
+	struct atto_vda_ae_timestamp_log tslog;
+	struct atto_vda_ae_nvc nvcache;
+	struct atto_vda_ae_dev dev;
+};
+
+
+struct __packed atto_vda_date_and_time {
+	u8 flags;
+	#define VDA_DT_DAY_MASK   0x07
+	#define VDA_DT_DAY_NONE   0x00
+	#define VDA_DT_DAY_SUN    0x01
+	#define VDA_DT_DAY_MON    0x02
+	#define VDA_DT_DAY_TUE    0x03
+	#define VDA_DT_DAY_WED    0x04
+	#define VDA_DT_DAY_THU    0x05
+	#define VDA_DT_DAY_FRI    0x06
+	#define VDA_DT_DAY_SAT    0x07
+	#define VDA_DT_PM         0x40
+	#define VDA_DT_MILITARY   0x80
+
+	u8 seconds;
+	u8 minutes;
+	u8 hours;
+	u8 day;
+	u8 month;
+	u16 year;
+};
+
+#define SGE_LEN_LIMIT   0x003FFFFF      /*! mask of segment length            */
+#define SGE_LEN_MAX     0x003FF000      /*! maximum segment length            */
+#define SGE_LAST        0x01000000      /*! last entry                        */
+#define SGE_ADDR_64     0x04000000      /*! 64-bit addressing flag            */
+#define SGE_CHAIN       0x80000000      /*! chain descriptor flag             */
+#define SGE_CHAIN_LEN   0x0000FFFF      /*! mask of length in chain entries   */
+#define SGE_CHAIN_SZ    0x00FF0000      /*! mask of size of chained buffer    */
+
+
+struct __packed atto_vda_cfg_init {
+	struct atto_vda_date_and_time date_time;
+	u32 sgl_page_size;
+	u32 vda_version;
+	u32 fw_version;
+	u32 fw_build;
+	u32 fw_release;
+	u32 epoch_time;
+	u32 ioctl_tunnel;
+	#define VDA_ITF_MEM_RW           0x00000001
+	#define VDA_ITF_TRACE            0x00000002
+	#define VDA_ITF_SCSI_PASS_THRU   0x00000004
+	#define VDA_ITF_GET_DEV_ADDR     0x00000008
+	#define VDA_ITF_PHY_CTRL         0x00000010
+	#define VDA_ITF_CONN_CTRL        0x00000020
+	#define VDA_ITF_GET_DEV_INFO     0x00000040
+
+	u32 num_targets_backend;
+	u8 reserved[0x48];
+};
+
+
+/* configuration commands */
+
+#define VDA_CFG_INIT          0x00
+#define VDA_CFG_GET_INIT      0x01
+#define VDA_CFG_GET_INIT2     0x02
+
+
+/*! physical region descriptor (PRD) aka scatter/gather entry */
+
+struct __packed atto_physical_region_description {
+	u64 address;
+	u32 ctl_len;
+	#define PRD_LEN_LIMIT       0x003FFFFF
+	#define PRD_LEN_MAX         0x003FF000
+	#define PRD_NXT_PRD_CNT     0x0000007F
+	#define PRD_CHAIN           0x01000000
+	#define PRD_DATA            0x00000000
+	#define PRD_INT_SEL         0xF0000000
+	  #define PRD_INT_SEL_F0    0x00000000
+	  #define PRD_INT_SEL_F1    0x40000000
+	  #define PRD_INT_SEL_F2    0x80000000
+	  #define PRD_INT_SEL_F3    0xc0000000
+	  #define PRD_INT_SEL_SRAM  0x10000000
+	  #define PRD_INT_SEL_PBSR  0x20000000
+
+};
+
+/* Request types. NOTE that ALL requests have the same layout for the first
+ * few bytes.
+ */
+struct __packed atto_vda_req_header {
+	u32 length;
+	u8 function;
+	u8 variable1;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+};
+
+
+#define FCP_CDB_SIZE    16
+
+struct __packed atto_vda_scsi_req {
+	u32 length;
+	u8 function;  /* VDA_FUNC_SCSI */
+	u8 sense_len;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+	u32 flags;
+     #define FCP_CMND_LUN_MASK    0x000000FF
+     #define FCP_CMND_TA_MASK     0x00000700
+      #define FCP_CMND_TA_SIMPL_Q 0x00000000
+      #define FCP_CMND_TA_HEAD_Q  0x00000100
+      #define FCP_CMND_TA_ORDRD_Q 0x00000200
+      #define FCP_CMND_TA_ACA     0x00000400
+     #define FCP_CMND_PRI_MASK    0x00007800
+     #define FCP_CMND_TM_MASK     0x00FF0000
+      #define FCP_CMND_ATS        0x00020000
+      #define FCP_CMND_CTS        0x00040000
+      #define FCP_CMND_LRS        0x00100000
+      #define FCP_CMND_TRS        0x00200000
+      #define FCP_CMND_CLA        0x00400000
+      #define FCP_CMND_TRM        0x00800000
+     #define FCP_CMND_DATA_DIR    0x03000000
+      #define FCP_CMND_WRD        0x01000000
+      #define FCP_CMND_RDD        0x02000000
+
+	u8 cdb[FCP_CDB_SIZE];
+	union {
+		struct __packed {
+			u64 ppsense_buf;
+			u16 target_id;
+			u8 iblk_cnt_prd;
+			u8 reserved;
+		};
+
+		struct atto_physical_region_description sense_buff_prd;
+	};
+
+	union {
+		struct atto_vda_sge sge[1];
+
+		u32 abort_handle;
+		u32 dwords[245];
+		struct atto_physical_region_description prd[1];
+	} u;
+};
+
+
+struct __packed atto_vda_flash_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_FLASH */
+	u8 sub_func;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+	u32 flash_addr;
+	u8 checksum;
+	u8 rsvd[3];
+
+	union {
+		struct {
+			char file_name[16]; /* 8.3 fname, NULL term, wc=* */
+			struct atto_vda_sge sge[1];
+		} file;
+
+		struct atto_vda_sge sge[1];
+		struct atto_physical_region_description prde[2];
+	} data;
+};
+
+
+struct __packed atto_vda_diag_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_DIAG */
+	u8 sub_func;
+	#define VDA_DIAG_STATUS   0x00
+	#define VDA_DIAG_RESET    0x01
+	#define VDA_DIAG_PAUSE    0x02
+	#define VDA_DIAG_RESUME   0x03
+	#define VDA_DIAG_READ     0x04
+	#define VDA_DIAG_WRITE    0x05
+
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+	u32 rsvd;
+	u64 local_addr;
+	struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_ae_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_AE */
+	u8 reserved1;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+
+	union {
+		struct atto_vda_sge sge[1];
+		struct atto_physical_region_description prde[1];
+	};
+};
+
+
+struct __packed atto_vda_cli_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_CLI */
+	u8 reserved1;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+	u32 cmd_rsp_len;
+	struct atto_vda_sge sge[1];
+};
+
+
+struct __packed atto_vda_ioctl_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_IOCTL */
+	u8 sub_func;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+
+	union {
+		struct atto_vda_sge reserved_sge;
+		struct atto_physical_region_description reserved_prde;
+	};
+
+	union {
+		struct {
+			u32 ctrl_code;
+			u16 target_id;
+			u8 lun;
+			u8 reserved;
+		} csmi;
+	};
+
+	union {
+		struct atto_vda_sge sge[1];
+		struct atto_physical_region_description prde[1];
+	};
+};
+
+
+struct __packed atto_vda_cfg_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_CFG */
+	u8 sub_func;
+	u8 rsvd1;
+	u8 sg_list_offset;
+	u32 handle;
+
+	union {
+		u8 bytes[116];
+		struct atto_vda_cfg_init init;
+		struct atto_vda_sge sge;
+		struct atto_physical_region_description prde;
+	} data;
+};
+
+
+struct __packed atto_vda_mgmt_req {
+	u32 length;
+	u8 function; /* VDA_FUNC_MGT */
+	u8 mgt_func;
+	u8 chain_offset;
+	u8 sg_list_offset;
+	u32 handle;
+	u8 scan_generation;
+	u8 payld_sglst_offset;
+	u16 dev_index;
+	u32 payld_length;
+	u32 pad;
+	union {
+		struct atto_vda_sge sge[2];
+		struct atto_physical_region_description prde[2];
+	};
+	struct atto_vda_sge payld_sge[1];
+};
+
+
+union atto_vda_req {
+	struct atto_vda_scsi_req scsi;
+	struct atto_vda_flash_req flash;
+	struct atto_vda_diag_req diag;
+	struct atto_vda_ae_req ae;
+	struct atto_vda_cli_req cli;
+	struct atto_vda_ioctl_req ioctl;
+	struct atto_vda_cfg_req cfg;
+	struct atto_vda_mgmt_req mgt;
+	u8 bytes[1024];
+};
+
+/* Outbound response structures */
+
+struct __packed atto_vda_scsi_rsp {
+	u8 scsi_stat;
+	u8 sense_len;
+	u8 rsvd[2];
+	u32 residual_length;
+};
+
+struct __packed atto_vda_flash_rsp {
+	u32 file_size;
+};
+
+struct __packed atto_vda_ae_rsp {
+	u32 length;
+};
+
+struct __packed atto_vda_cli_rsp {
+	u32 cmd_rsp_len;
+};
+
+struct __packed atto_vda_ioctl_rsp {
+	union {
+		struct {
+			u32 csmi_status;
+			u16 target_id;
+			u8 lun;
+			u8 reserved;
+		} csmi;
+	};
+};
+
+struct __packed atto_vda_cfg_rsp {
+	u16 vda_version;
+	u16 fw_release;
+	u32 fw_build;
+};
+
+struct __packed atto_vda_mgmt_rsp {
+	u32 length;
+	u16 dev_index;
+	u8 scan_generation;
+};
+
+union atto_vda_func_rsp {
+	struct atto_vda_scsi_rsp scsi_rsp;
+	struct atto_vda_flash_rsp flash_rsp;
+	struct atto_vda_ae_rsp ae_rsp;
+	struct atto_vda_cli_rsp cli_rsp;
+	struct atto_vda_ioctl_rsp ioctl_rsp;
+	struct atto_vda_cfg_rsp cfg_rsp;
+	struct atto_vda_mgmt_rsp mgt_rsp;
+	u32 dwords[2];
+};
+
+struct __packed atto_vda_ob_rsp {
+	u32 handle;
+	u8 req_stat;
+	u8 rsvd[3];
+
+	union atto_vda_func_rsp
+		func_rsp;
+};
+
+struct __packed atto_vda_ae_data {
+	u8 event_data[256];
+};
+
+struct __packed atto_vda_mgmt_data {
+	union {
+		u8 bytes[112];
+		struct atto_vda_devinfo dev_info;
+		struct atto_vda_grp_info grp_info;
+		struct atto_vdapart_info part_info;
+		struct atto_vda_dh_info dev_health_info;
+		struct atto_vda_metrics_info metrics_info;
+		struct atto_vda_schedule_info sched_info;
+		struct atto_vda_n_vcache_info nvcache_info;
+		struct atto_vda_buzzer_info buzzer_info;
+	} data;
+};
+
+union atto_vda_rsp_data {
+	struct atto_vda_ae_data ae_data;
+	struct atto_vda_mgmt_data mgt_data;
+	u8 sense_data[252];
+	#define SENSE_DATA_SZ   252;
+	u8 bytes[256];
+};
+
+#endif
diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h
new file mode 100644
index 0000000..0838e26
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r.h
@@ -0,0 +1,1441 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r.h
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+
+#include "esas2r_log.h"
+#include "atioctl.h"
+#include "atvda.h"
+
+#ifndef ESAS2R_H
+#define ESAS2R_H
+
+/* Global Variables */
+extern struct esas2r_adapter *esas2r_adapters[];
+extern u8 *esas2r_buffered_ioctl;
+extern dma_addr_t esas2r_buffered_ioctl_addr;
+extern u32 esas2r_buffered_ioctl_size;
+extern struct pci_dev *esas2r_buffered_ioctl_pcid;
+#define SGL_PG_SZ_MIN   64
+#define SGL_PG_SZ_MAX   1024
+extern int sgl_page_size;
+#define NUM_SGL_MIN     8
+#define NUM_SGL_MAX     2048
+extern int num_sg_lists;
+#define NUM_REQ_MIN     4
+#define NUM_REQ_MAX     256
+extern int num_requests;
+#define NUM_AE_MIN      2
+#define NUM_AE_MAX      8
+extern int num_ae_requests;
+extern int cmd_per_lun;
+extern int can_queue;
+extern int esas2r_max_sectors;
+extern int sg_tablesize;
+extern int interrupt_mode;
+extern int num_io_requests;
+
+/* Macro defintions */
+#define ESAS2R_MAX_ID        255
+#define MAX_ADAPTERS         32
+#define ESAS2R_DRVR_NAME     "esas2r"
+#define ESAS2R_LONGNAME      "ATTO ExpressSAS 6GB RAID Adapter"
+#define ESAS2R_MAX_DEVICES     32
+#define ATTONODE_NAME         "ATTONode"
+#define ESAS2R_MAJOR_REV       1
+#define ESAS2R_MINOR_REV       00
+#define ESAS2R_VERSION_STR     DEFINED_NUM_TO_STR(ESAS2R_MAJOR_REV) "." \
+	DEFINED_NUM_TO_STR(ESAS2R_MINOR_REV)
+#define ESAS2R_COPYRIGHT_YEARS "2001-2013"
+#define ESAS2R_DEFAULT_SGL_PAGE_SIZE 384
+#define ESAS2R_DEFAULT_CMD_PER_LUN   64
+#define ESAS2R_DEFAULT_NUM_SG_LISTS 1024
+#define DEFINED_NUM_TO_STR(num) NUM_TO_STR(num)
+#define NUM_TO_STR(num) #num
+
+#define ESAS2R_SGL_ALIGN    16
+#define ESAS2R_LIST_ALIGN   16
+#define ESAS2R_LIST_EXTRA   ESAS2R_NUM_EXTRA
+#define ESAS2R_DATA_BUF_LEN         256
+#define ESAS2R_DEFAULT_TMO          5000
+#define ESAS2R_DISC_BUF_LEN         512
+#define ESAS2R_FWCOREDUMP_SZ        0x80000
+#define ESAS2R_NUM_PHYS             8
+#define ESAS2R_TARG_ID_INV          0xFFFF
+#define ESAS2R_INT_STS_MASK         MU_INTSTAT_MASK
+#define ESAS2R_INT_ENB_MASK         MU_INTSTAT_MASK
+#define ESAS2R_INT_DIS_MASK         0
+#define ESAS2R_MAX_TARGETS          256
+#define ESAS2R_KOBJ_NAME_LEN        20
+
+/* u16 (WORD) component macros */
+#define LOBYTE(w) ((u8)(u16)(w))
+#define HIBYTE(w) ((u8)(((u16)(w)) >> 8))
+#define MAKEWORD(lo, hi) ((u16)((u8)(lo) | ((u16)(u8)(hi) << 8)))
+
+/* u32 (DWORD) component macros */
+#define LOWORD(d) ((u16)(u32)(d))
+#define HIWORD(d) ((u16)(((u32)(d)) >> 16))
+#define MAKEDWORD(lo, hi) ((u32)((u16)(lo) | ((u32)(u16)(hi) << 16)))
+
+/* macro to get the lowest nonzero bit of a value */
+#define LOBIT(x) ((x) & (0 - (x)))
+
+/* These functions are provided to access the chip's control registers.
+ * The register is specified by its byte offset from the register base
+ * for the adapter.
+ */
+#define esas2r_read_register_dword(a, reg)                             \
+	readl((void __iomem *)a->regs + (reg) + MW_REG_OFFSET_HWREG)
+
+#define esas2r_write_register_dword(a, reg, data)                      \
+	writel(data, (void __iomem *)(a->regs + (reg) + MW_REG_OFFSET_HWREG))
+
+#define esas2r_flush_register_dword(a, r) esas2r_read_register_dword(a, r)
+
+/* This function is provided to access the chip's data window.   The
+ * register is specified by its byte offset from the window base
+ * for the adapter.
+ */
+#define esas2r_read_data_byte(a, reg)                                  \
+	readb((void __iomem *)a->data_window + (reg))
+
+/* ATTO vendor and device Ids */
+#define ATTO_VENDOR_ID          0x117C
+#define ATTO_DID_INTEL_IOP348   0x002C
+#define ATTO_DID_MV_88RC9580    0x0049
+#define ATTO_DID_MV_88RC9580TS  0x0066
+#define ATTO_DID_MV_88RC9580TSE 0x0067
+#define ATTO_DID_MV_88RC9580TL  0x0068
+
+/* ATTO subsystem device Ids */
+#define ATTO_SSDID_TBT      0x4000
+#define ATTO_TSSC_3808      0x4066
+#define ATTO_TSSC_3808E     0x4067
+#define ATTO_TLSH_1068      0x4068
+#define ATTO_ESAS_R680      0x0049
+#define ATTO_ESAS_R608      0x004A
+#define ATTO_ESAS_R60F      0x004B
+#define ATTO_ESAS_R6F0      0x004C
+#define ATTO_ESAS_R644      0x004D
+#define ATTO_ESAS_R648      0x004E
+
+/*
+ * flash definitions & structures
+ * define the code types
+ */
+#define FBT_CPYR        0xAA00
+#define FBT_SETUP       0xAA02
+#define FBT_FLASH_VER   0xAA04
+
+/* offsets to various locations in flash */
+#define FLS_OFFSET_BOOT (u32)(0x00700000)
+#define FLS_OFFSET_NVR  (u32)(0x007C0000)
+#define FLS_OFFSET_CPYR FLS_OFFSET_NVR
+#define FLS_LENGTH_BOOT (FLS_OFFSET_CPYR - FLS_OFFSET_BOOT)
+#define FLS_BLOCK_SIZE  (u32)(0x00020000)
+#define FI_NVR_2KB  0x0800
+#define FI_NVR_8KB  0x2000
+#define FM_BUF_SZ   0x800
+
+/*
+ * marvell frey (88R9580) register definitions
+ * chip revision identifiers
+ */
+#define MVR_FREY_B2     0xB2
+
+/*
+ * memory window definitions.  window 0 is the data window with definitions
+ * of MW_DATA_XXX.  window 1 is the register window with definitions of
+ * MW_REG_XXX.
+ */
+#define MW_REG_WINDOW_SIZE      (u32)(0x00040000)
+#define MW_REG_OFFSET_HWREG     (u32)(0x00000000)
+#define MW_REG_OFFSET_PCI       (u32)(0x00008000)
+#define MW_REG_PCI_HWREG_DELTA  (MW_REG_OFFSET_PCI - MW_REG_OFFSET_HWREG)
+#define MW_DATA_WINDOW_SIZE     (u32)(0x00020000)
+#define MW_DATA_ADDR_SER_FLASH  (u32)(0xEC000000)
+#define MW_DATA_ADDR_SRAM       (u32)(0xF4000000)
+#define MW_DATA_ADDR_PAR_FLASH  (u32)(0xFC000000)
+
+/*
+ * the following registers are for the communication
+ * list interface (AKA message unit (MU))
+ */
+#define MU_IN_LIST_ADDR_LO      (u32)(0x00004000)
+#define MU_IN_LIST_ADDR_HI      (u32)(0x00004004)
+
+#define MU_IN_LIST_WRITE        (u32)(0x00004018)
+    #define MU_ILW_TOGGLE       (u32)(0x00004000)
+
+#define MU_IN_LIST_READ         (u32)(0x0000401C)
+    #define MU_ILR_TOGGLE       (u32)(0x00004000)
+    #define MU_ILIC_LIST        (u32)(0x0000000F)
+    #define MU_ILIC_LIST_F0     (u32)(0x00000000)
+    #define MU_ILIC_DEST        (u32)(0x00000F00)
+    #define MU_ILIC_DEST_DDR    (u32)(0x00000200)
+#define MU_IN_LIST_IFC_CONFIG   (u32)(0x00004028)
+
+#define MU_IN_LIST_CONFIG       (u32)(0x0000402C)
+    #define MU_ILC_ENABLE       (u32)(0x00000001)
+    #define MU_ILC_ENTRY_MASK   (u32)(0x000000F0)
+    #define MU_ILC_ENTRY_4_DW   (u32)(0x00000020)
+    #define MU_ILC_DYNAMIC_SRC  (u32)(0x00008000)
+    #define MU_ILC_NUMBER_MASK  (u32)(0x7FFF0000)
+    #define MU_ILC_NUMBER_SHIFT            16
+
+#define MU_OUT_LIST_ADDR_LO     (u32)(0x00004050)
+#define MU_OUT_LIST_ADDR_HI     (u32)(0x00004054)
+
+#define MU_OUT_LIST_COPY_PTR_LO (u32)(0x00004058)
+#define MU_OUT_LIST_COPY_PTR_HI (u32)(0x0000405C)
+
+#define MU_OUT_LIST_WRITE       (u32)(0x00004068)
+    #define MU_OLW_TOGGLE       (u32)(0x00004000)
+
+#define MU_OUT_LIST_COPY        (u32)(0x0000406C)
+    #define MU_OLC_TOGGLE       (u32)(0x00004000)
+    #define MU_OLC_WRT_PTR      (u32)(0x00003FFF)
+
+#define MU_OUT_LIST_IFC_CONFIG  (u32)(0x00004078)
+    #define MU_OLIC_LIST        (u32)(0x0000000F)
+    #define MU_OLIC_LIST_F0     (u32)(0x00000000)
+    #define MU_OLIC_SOURCE      (u32)(0x00000F00)
+    #define MU_OLIC_SOURCE_DDR  (u32)(0x00000200)
+
+#define MU_OUT_LIST_CONFIG      (u32)(0x0000407C)
+    #define MU_OLC_ENABLE       (u32)(0x00000001)
+    #define MU_OLC_ENTRY_MASK   (u32)(0x000000F0)
+    #define MU_OLC_ENTRY_4_DW   (u32)(0x00000020)
+    #define MU_OLC_NUMBER_MASK  (u32)(0x7FFF0000)
+    #define MU_OLC_NUMBER_SHIFT            16
+
+#define MU_OUT_LIST_INT_STAT    (u32)(0x00004088)
+    #define MU_OLIS_INT         (u32)(0x00000001)
+
+#define MU_OUT_LIST_INT_MASK    (u32)(0x0000408C)
+    #define MU_OLIS_MASK        (u32)(0x00000001)
+
+/*
+ * the maximum size of the communication lists is two greater than the
+ * maximum amount of VDA requests.  the extra are to prevent queue overflow.
+ */
+#define ESAS2R_MAX_NUM_REQS         256
+#define ESAS2R_NUM_EXTRA            2
+#define ESAS2R_MAX_COMM_LIST_SIZE   (ESAS2R_MAX_NUM_REQS + ESAS2R_NUM_EXTRA)
+
+/*
+ * the following registers are for the CPU interface
+ */
+#define MU_CTL_STATUS_IN        (u32)(0x00010108)
+    #define MU_CTL_IN_FULL_RST  (u32)(0x00000020)
+#define MU_CTL_STATUS_IN_B2     (u32)(0x00010130)
+    #define MU_CTL_IN_FULL_RST2 (u32)(0x80000000)
+#define MU_DOORBELL_IN          (u32)(0x00010460)
+    #define DRBL_RESET_BUS      (u32)(0x00000002)
+    #define DRBL_PAUSE_AE       (u32)(0x00000004)
+    #define DRBL_RESUME_AE      (u32)(0x00000008)
+    #define DRBL_MSG_IFC_DOWN   (u32)(0x00000010)
+    #define DRBL_FLASH_REQ      (u32)(0x00000020)
+    #define DRBL_FLASH_DONE     (u32)(0x00000040)
+    #define DRBL_FORCE_INT      (u32)(0x00000080)
+    #define DRBL_MSG_IFC_INIT   (u32)(0x00000100)
+    #define DRBL_POWER_DOWN     (u32)(0x00000200)
+    #define DRBL_DRV_VER_1      (u32)(0x00010000)
+    #define DRBL_DRV_VER        DRBL_DRV_VER_1
+#define MU_DOORBELL_IN_ENB      (u32)(0x00010464)
+#define MU_DOORBELL_OUT         (u32)(0x00010480)
+ #define DRBL_PANIC_REASON_MASK (u32)(0x00F00000)
+    #define DRBL_UNUSED_HANDLER (u32)(0x00100000)
+    #define DRBL_UNDEF_INSTR    (u32)(0x00200000)
+    #define DRBL_PREFETCH_ABORT (u32)(0x00300000)
+    #define DRBL_DATA_ABORT     (u32)(0x00400000)
+    #define DRBL_JUMP_TO_ZERO   (u32)(0x00500000)
+  #define DRBL_FW_RESET         (u32)(0x00080000)
+  #define DRBL_FW_VER_MSK       (u32)(0x00070000)
+  #define DRBL_FW_VER_0         (u32)(0x00000000)
+  #define DRBL_FW_VER_1         (u32)(0x00010000)
+  #define DRBL_FW_VER           DRBL_FW_VER_1
+#define MU_DOORBELL_OUT_ENB     (u32)(0x00010484)
+    #define DRBL_ENB_MASK       (u32)(0x00F803FF)
+#define MU_INT_STATUS_OUT       (u32)(0x00010200)
+    #define MU_INTSTAT_POST_OUT (u32)(0x00000010)
+    #define MU_INTSTAT_DRBL_IN  (u32)(0x00000100)
+    #define MU_INTSTAT_DRBL     (u32)(0x00001000)
+    #define MU_INTSTAT_MASK     (u32)(0x00001010)
+#define MU_INT_MASK_OUT         (u32)(0x0001020C)
+
+/* PCI express registers accessed via window 1 */
+#define MVR_PCI_WIN1_REMAP      (u32)(0x00008438)
+    #define MVRPW1R_ENABLE      (u32)(0x00000001)
+
+
+/* structures */
+
+/* inbound list dynamic source entry */
+struct esas2r_inbound_list_source_entry {
+	u64 address;
+	u32 length;
+	#define HWILSE_INTERFACE_F0  0x00000000
+	u32 reserved;
+};
+
+/* PCI data structure in expansion ROM images */
+struct __packed esas2r_boot_header {
+	char signature[4];
+	u16 vendor_id;
+	u16 device_id;
+	u16 VPD;
+	u16 struct_length;
+	u8 struct_revision;
+	u8 class_code[3];
+	u16 image_length;
+	u16 code_revision;
+	u8 code_type;
+	#define CODE_TYPE_PC    0
+	#define CODE_TYPE_OPEN  1
+	#define CODE_TYPE_EFI   3
+	u8 indicator;
+	#define INDICATOR_LAST  0x80
+	u8 reserved[2];
+};
+
+struct __packed esas2r_boot_image {
+	u16 signature;
+	u8 reserved[22];
+	u16 header_offset;
+	u16 pnp_offset;
+};
+
+struct __packed esas2r_pc_image {
+	u16 signature;
+	u8 length;
+	u8 entry_point[3];
+	u8 checksum;
+	u16 image_end;
+	u16 min_size;
+	u8 rom_flags;
+	u8 reserved[12];
+	u16 header_offset;
+	u16 pnp_offset;
+	struct esas2r_boot_header boot_image;
+};
+
+struct __packed esas2r_efi_image {
+	u16 signature;
+	u16 length;
+	u32 efi_signature;
+	#define EFI_ROM_SIG     0x00000EF1
+	u16 image_type;
+	#define EFI_IMAGE_APP   10
+	#define EFI_IMAGE_BSD   11
+	#define EFI_IMAGE_RTD   12
+	u16 machine_type;
+	#define EFI_MACHINE_IA32 0x014c
+	#define EFI_MACHINE_IA64 0x0200
+	#define EFI_MACHINE_X64  0x8664
+	#define EFI_MACHINE_EBC  0x0EBC
+	u16 compression;
+	#define EFI_UNCOMPRESSED 0x0000
+	#define EFI_COMPRESSED   0x0001
+	u8 reserved[8];
+	u16 efi_offset;
+	u16 header_offset;
+	u16 reserved2;
+	struct esas2r_boot_header boot_image;
+};
+
+struct esas2r_adapter;
+struct esas2r_sg_context;
+struct esas2r_request;
+
+typedef void (*RQCALLBK)     (struct esas2r_adapter *a,
+			      struct esas2r_request *rq);
+typedef bool (*RQBUILDSGL)   (struct esas2r_adapter *a,
+			      struct esas2r_sg_context *sgc);
+
+struct esas2r_component_header {
+	u8 img_type;
+	#define CH_IT_FW    0x00
+	#define CH_IT_NVR   0x01
+	#define CH_IT_BIOS  0x02
+	#define CH_IT_MAC   0x03
+	#define CH_IT_CFG   0x04
+	#define CH_IT_EFI   0x05
+	u8 status;
+	#define CH_STAT_PENDING 0xff
+	#define CH_STAT_FAILED  0x00
+	#define CH_STAT_SUCCESS 0x01
+	#define CH_STAT_RETRY   0x02
+	#define CH_STAT_INVALID 0x03
+	u8 pad[2];
+	u32 version;
+	u32 length;
+	u32 image_offset;
+};
+
+#define FI_REL_VER_SZ   16
+
+struct esas2r_flash_img_v0 {
+	u8 fi_version;
+	#define FI_VERSION_0    00
+	u8 status;
+	u8 adap_typ;
+	u8 action;
+	u32 length;
+	u16 checksum;
+	u16 driver_error;
+	u16 flags;
+	u16 num_comps;
+	#define FI_NUM_COMPS_V0 5
+	u8 rel_version[FI_REL_VER_SZ];
+	struct esas2r_component_header cmp_hdr[FI_NUM_COMPS_V0];
+	u8 scratch_buf[FM_BUF_SZ];
+};
+
+struct esas2r_flash_img {
+	u8 fi_version;
+	#define FI_VERSION_1    01
+	u8 status;
+	#define FI_STAT_SUCCESS  0x00
+	#define FI_STAT_FAILED   0x01
+	#define FI_STAT_REBOOT   0x02
+	#define FI_STAT_ADAPTYP  0x03
+	#define FI_STAT_INVALID  0x04
+	#define FI_STAT_CHKSUM   0x05
+	#define FI_STAT_LENGTH   0x06
+	#define FI_STAT_UNKNOWN  0x07
+	#define FI_STAT_IMG_VER  0x08
+	#define FI_STAT_BUSY     0x09
+	#define FI_STAT_DUAL     0x0A
+	#define FI_STAT_MISSING  0x0B
+	#define FI_STAT_UNSUPP   0x0C
+	#define FI_STAT_ERASE    0x0D
+	#define FI_STAT_FLASH    0x0E
+	#define FI_STAT_DEGRADED 0x0F
+	u8 adap_typ;
+	#define FI_AT_UNKNWN    0xFF
+	#define FI_AT_SUN_LAKE  0x0B
+	#define FI_AT_MV_9580   0x0F
+	u8 action;
+	#define FI_ACT_DOWN     0x00
+	#define FI_ACT_UP       0x01
+	#define FI_ACT_UPSZ     0x02
+	#define FI_ACT_MAX      0x02
+	#define FI_ACT_DOWN1    0x80
+	u32 length;
+	u16 checksum;
+	u16 driver_error;
+	u16 flags;
+	#define FI_FLG_NVR_DEF  0x0001
+	u16 num_comps;
+	#define FI_NUM_COMPS_V1 6
+	u8 rel_version[FI_REL_VER_SZ];
+	struct esas2r_component_header cmp_hdr[FI_NUM_COMPS_V1];
+	u8 scratch_buf[FM_BUF_SZ];
+};
+
+/* definitions for flash script (FS) commands */
+struct esas2r_ioctlfs_command {
+	u8 command;
+	#define ESAS2R_FS_CMD_ERASE    0
+	#define ESAS2R_FS_CMD_READ     1
+	#define ESAS2R_FS_CMD_BEGINW   2
+	#define ESAS2R_FS_CMD_WRITE    3
+	#define ESAS2R_FS_CMD_COMMIT   4
+	#define ESAS2R_FS_CMD_CANCEL   5
+	u8 checksum;
+	u8 reserved[2];
+	u32 flash_addr;
+	u32 length;
+	u32 image_offset;
+};
+
+struct esas2r_ioctl_fs {
+	u8 version;
+	#define ESAS2R_FS_VER      0
+	u8 status;
+	u8 driver_error;
+	u8 adap_type;
+	#define ESAS2R_FS_AT_ESASRAID2     3
+	#define ESAS2R_FS_AT_TSSASRAID2    4
+	#define ESAS2R_FS_AT_TSSASRAID2E   5
+	#define ESAS2R_FS_AT_TLSASHBA      6
+	u8 driver_ver;
+	u8 reserved[11];
+	struct esas2r_ioctlfs_command command;
+	u8 data[1];
+};
+
+struct esas2r_sas_nvram {
+	u8 signature[4];
+	u8 version;
+	#define SASNVR_VERSION_0    0x00
+	#define SASNVR_VERSION      SASNVR_VERSION_0
+	u8 checksum;
+	#define SASNVR_CKSUM_SEED   0x5A
+	u8 max_lun_for_target;
+	u8 pci_latency;
+	#define SASNVR_PCILAT_DIS   0x00
+	#define SASNVR_PCILAT_MIN   0x10
+	#define SASNVR_PCILAT_MAX   0xF8
+	u8 options1;
+	#define SASNVR1_BOOT_DRVR   0x01
+	#define SASNVR1_BOOT_SCAN   0x02
+	#define SASNVR1_DIS_PCI_MWI 0x04
+	#define SASNVR1_FORCE_ORD_Q 0x08
+	#define SASNVR1_CACHELINE_0 0x10
+	#define SASNVR1_DIS_DEVSORT 0x20
+	#define SASNVR1_PWR_MGT_EN  0x40
+	#define SASNVR1_WIDEPORT    0x80
+	u8 options2;
+	#define SASNVR2_SINGLE_BUS  0x01
+	#define SASNVR2_SLOT_BIND   0x02
+	#define SASNVR2_EXP_PROG    0x04
+	#define SASNVR2_CMDTHR_LUN  0x08
+	#define SASNVR2_HEARTBEAT   0x10
+	#define SASNVR2_INT_CONNECT 0x20
+	#define SASNVR2_SW_MUX_CTRL 0x40
+	#define SASNVR2_DISABLE_NCQ 0x80
+	u8 int_coalescing;
+	#define SASNVR_COAL_DIS     0x00
+	#define SASNVR_COAL_LOW     0x01
+	#define SASNVR_COAL_MED     0x02
+	#define SASNVR_COAL_HI      0x03
+	u8 cmd_throttle;
+	#define SASNVR_CMDTHR_NONE  0x00
+	u8 dev_wait_time;
+	u8 dev_wait_count;
+	u8 spin_up_delay;
+	#define SASNVR_SPINUP_MAX   0x14
+	u8 ssp_align_rate;
+	u8 sas_addr[8];
+	u8 phy_speed[16];
+	#define SASNVR_SPEED_AUTO   0x00
+	#define SASNVR_SPEED_1_5GB  0x01
+	#define SASNVR_SPEED_3GB    0x02
+	#define SASNVR_SPEED_6GB    0x03
+	#define SASNVR_SPEED_12GB   0x04
+	u8 phy_mux[16];
+	#define SASNVR_MUX_DISABLED 0x00
+	#define SASNVR_MUX_1_5GB    0x01
+	#define SASNVR_MUX_3GB      0x02
+	#define SASNVR_MUX_6GB      0x03
+	u8 phy_flags[16];
+	#define SASNVR_PHF_DISABLED 0x01
+	#define SASNVR_PHF_RD_ONLY  0x02
+	u8 sort_type;
+	#define SASNVR_SORT_SAS_ADDR    0x00
+	#define SASNVR_SORT_H308_CONN   0x01
+	#define SASNVR_SORT_PHY_ID      0x02
+	#define SASNVR_SORT_SLOT_ID     0x03
+	u8 dpm_reqcmd_lmt;
+	u8 dpm_stndby_time;
+	u8 dpm_active_time;
+	u8 phy_target_id[16];
+	#define SASNVR_PTI_DISABLED     0xFF
+	u8 virt_ses_mode;
+	#define SASNVR_VSMH_DISABLED    0x00
+	u8 read_write_mode;
+	#define SASNVR_RWM_DEFAULT      0x00
+	u8 link_down_to;
+	u8 reserved[0xA1];
+};
+
+typedef u32 (*PGETPHYSADDR) (struct esas2r_sg_context *sgc, u64 *addr);
+
+struct esas2r_sg_context {
+	struct esas2r_adapter *adapter;
+	struct esas2r_request *first_req;
+	u32 length;
+	u8 *cur_offset;
+	PGETPHYSADDR get_phys_addr;
+	union {
+		struct {
+			struct atto_vda_sge *curr;
+			struct atto_vda_sge *last;
+			struct atto_vda_sge *limit;
+			struct atto_vda_sge *chain;
+		} a64;
+		struct {
+			struct atto_physical_region_description *curr;
+			struct atto_physical_region_description *chain;
+			u32 sgl_max_cnt;
+			u32 sge_cnt;
+		} prd;
+	} sge;
+	struct scatterlist *cur_sgel;
+	u8 *exp_offset;
+	int num_sgel;
+	int sgel_count;
+};
+
+struct esas2r_target {
+	u8 flags;
+	#define TF_PASS_THRU    0x01
+	#define TF_USED         0x02
+	u8 new_target_state;
+	u8 target_state;
+	u8 buffered_target_state;
+#define TS_NOT_PRESENT      0x00
+#define TS_PRESENT          0x05
+#define TS_LUN_CHANGE       0x06
+#define TS_INVALID          0xFF
+	u32 block_size;
+	u32 inter_block;
+	u32 inter_byte;
+	u16 virt_targ_id;
+	u16 phys_targ_id;
+	u8 identifier_len;
+	u64 sas_addr;
+	u8 identifier[60];
+	struct atto_vda_ae_lu lu_event;
+};
+
+struct esas2r_request {
+	struct list_head comp_list;
+	struct list_head req_list;
+	union atto_vda_req *vrq;
+	struct esas2r_mem_desc *vrq_md;
+	union {
+		void *data_buf;
+		union atto_vda_rsp_data *vda_rsp_data;
+	};
+	u8 *sense_buf;
+	struct list_head sg_table_head;
+	struct esas2r_mem_desc *sg_table;
+	u32 timeout;
+	#define RQ_TIMEOUT_S1     0xFFFFFFFF
+	#define RQ_TIMEOUT_S2     0xFFFFFFFE
+	#define RQ_MAX_TIMEOUT    0xFFFFFFFD
+	u16 target_id;
+	u8 req_type;
+	#define RT_INI_REQ          0x01
+	#define RT_DISC_REQ         0x02
+	u8 sense_len;
+	union atto_vda_func_rsp func_rsp;
+	RQCALLBK comp_cb;
+	RQCALLBK interrupt_cb;
+	void *interrupt_cx;
+	u8 flags;
+	#define RF_1ST_IBLK_BASE    0x04
+	#define RF_FAILURE_OK       0x08
+	u8 req_stat;
+	u16 vda_req_sz;
+	#define RQ_SIZE_DEFAULT   0
+	u64 lba;
+	RQCALLBK aux_req_cb;
+	void *aux_req_cx;
+	u32 blk_len;
+	u32 max_blk_len;
+	union {
+		struct scsi_cmnd *cmd;
+		u8 *task_management_status_ptr;
+	};
+};
+
+struct esas2r_flash_context {
+	struct esas2r_flash_img *fi;
+	RQCALLBK interrupt_cb;
+	u8 *sgc_offset;
+	u8 *scratch;
+	u32 fi_hdr_len;
+	u8 task;
+	#define     FMTSK_ERASE_BOOT    0
+	#define     FMTSK_WRTBIOS       1
+	#define     FMTSK_READBIOS      2
+	#define     FMTSK_WRTMAC        3
+	#define     FMTSK_READMAC       4
+	#define     FMTSK_WRTEFI        5
+	#define     FMTSK_READEFI       6
+	#define     FMTSK_WRTCFG        7
+	#define     FMTSK_READCFG       8
+	u8 func;
+	u16 num_comps;
+	u32 cmp_len;
+	u32 flsh_addr;
+	u32 curr_len;
+	u8 comp_typ;
+	struct esas2r_sg_context sgc;
+};
+
+struct esas2r_disc_context {
+	u8 disc_evt;
+	#define DCDE_DEV_CHANGE     0x01
+	#define DCDE_DEV_SCAN       0x02
+	u8 state;
+	#define DCS_DEV_RMV         0x00
+	#define DCS_DEV_ADD         0x01
+	#define DCS_BLOCK_DEV_SCAN  0x02
+	#define DCS_RAID_GRP_INFO   0x03
+	#define DCS_PART_INFO       0x04
+	#define DCS_PT_DEV_INFO     0x05
+	#define DCS_PT_DEV_ADDR     0x06
+	#define DCS_DISC_DONE       0xFF
+	u16 flags;
+	#define DCF_DEV_CHANGE      0x0001
+	#define DCF_DEV_SCAN        0x0002
+	#define DCF_POLLED          0x8000
+	u32 interleave;
+	u32 block_size;
+	u16 dev_ix;
+	u8 part_num;
+	u8 raid_grp_ix;
+	char raid_grp_name[16];
+	struct esas2r_target *curr_targ;
+	u16 curr_virt_id;
+	u16 curr_phys_id;
+	u8 scan_gen;
+	u8 dev_addr_type;
+	u64 sas_addr;
+};
+
+struct esas2r_mem_desc {
+	struct list_head next_desc;
+	void *virt_addr;
+	u64 phys_addr;
+	void *pad;
+	void *esas2r_data;
+	u32 esas2r_param;
+	u32 size;
+};
+
+enum fw_event_type {
+	fw_event_null,
+	fw_event_lun_change,
+	fw_event_present,
+	fw_event_not_present,
+	fw_event_vda_ae
+};
+
+struct esas2r_vda_ae {
+	u32 signature;
+#define ESAS2R_VDA_EVENT_SIG  0x4154544F
+	u8 bus_number;
+	u8 devfn;
+	u8 pad[2];
+	union atto_vda_ae vda_ae;
+};
+
+struct esas2r_fw_event_work {
+	struct list_head list;
+	struct delayed_work work;
+	struct esas2r_adapter *a;
+	enum fw_event_type type;
+	u8 data[sizeof(struct esas2r_vda_ae)];
+};
+
+enum state {
+	FW_INVALID_ST,
+	FW_STATUS_ST,
+	FW_COMMAND_ST
+};
+
+struct esas2r_firmware {
+	enum state state;
+	struct esas2r_flash_img header;
+	u8 *data;
+	u64 phys;
+	int orig_len;
+	void *header_buff;
+	u64 header_buff_phys;
+};
+
+struct esas2r_adapter {
+	struct esas2r_target targetdb[ESAS2R_MAX_TARGETS];
+	struct esas2r_target *targetdb_end;
+	unsigned char *regs;
+	unsigned char *data_window;
+	u32 volatile flags;
+	#define AF_PORT_CHANGE      (u32)(0x00000001)
+	#define AF_CHPRST_NEEDED    (u32)(0x00000004)
+	#define AF_CHPRST_PENDING   (u32)(0x00000008)
+	#define AF_CHPRST_DETECTED  (u32)(0x00000010)
+	#define AF_BUSRST_NEEDED    (u32)(0x00000020)
+	#define AF_BUSRST_PENDING   (u32)(0x00000040)
+	#define AF_BUSRST_DETECTED  (u32)(0x00000080)
+	#define AF_DISABLED         (u32)(0x00000100)
+	#define AF_FLASH_LOCK       (u32)(0x00000200)
+	#define AF_OS_RESET         (u32)(0x00002000)
+	#define AF_FLASHING         (u32)(0x00004000)
+	#define AF_POWER_MGT        (u32)(0x00008000)
+	#define AF_NVR_VALID        (u32)(0x00010000)
+	#define AF_DEGRADED_MODE    (u32)(0x00020000)
+	#define AF_DISC_PENDING     (u32)(0x00040000)
+	#define AF_TASKLET_SCHEDULED    (u32)(0x00080000)
+	#define AF_HEARTBEAT        (u32)(0x00200000)
+	#define AF_HEARTBEAT_ENB    (u32)(0x00400000)
+	#define AF_NOT_PRESENT      (u32)(0x00800000)
+	#define AF_CHPRST_STARTED   (u32)(0x01000000)
+	#define AF_FIRST_INIT       (u32)(0x02000000)
+	#define AF_POWER_DOWN       (u32)(0x04000000)
+	#define AF_DISC_IN_PROG     (u32)(0x08000000)
+	#define AF_COMM_LIST_TOGGLE (u32)(0x10000000)
+	#define AF_LEGACY_SGE_MODE  (u32)(0x20000000)
+	#define AF_DISC_POLLED      (u32)(0x40000000)
+	u32 volatile flags2;
+	#define AF2_SERIAL_FLASH    (u32)(0x00000001)
+	#define AF2_DEV_SCAN        (u32)(0x00000002)
+	#define AF2_DEV_CNT_OK      (u32)(0x00000004)
+	#define AF2_COREDUMP_AVAIL  (u32)(0x00000008)
+	#define AF2_COREDUMP_SAVED  (u32)(0x00000010)
+	#define AF2_VDA_POWER_DOWN  (u32)(0x00000100)
+	#define AF2_THUNDERLINK     (u32)(0x00000200)
+	#define AF2_THUNDERBOLT     (u32)(0x00000400)
+	#define AF2_INIT_DONE       (u32)(0x00000800)
+	#define AF2_INT_PENDING     (u32)(0x00001000)
+	#define AF2_TIMER_TICK      (u32)(0x00002000)
+	#define AF2_IRQ_CLAIMED     (u32)(0x00004000)
+	#define AF2_MSI_ENABLED     (u32)(0x00008000)
+	atomic_t disable_cnt;
+	atomic_t dis_ints_cnt;
+	u32 int_stat;
+	u32 int_mask;
+	u32 volatile *outbound_copy;
+	struct list_head avail_request;
+	spinlock_t request_lock;
+	spinlock_t sg_list_lock;
+	spinlock_t queue_lock;
+	spinlock_t mem_lock;
+	struct list_head free_sg_list_head;
+	struct esas2r_mem_desc *sg_list_mds;
+	struct list_head active_list;
+	struct list_head defer_list;
+	struct esas2r_request **req_table;
+	union {
+		u16 prev_dev_cnt;
+		u32 heartbeat_time;
+	#define ESAS2R_HEARTBEAT_TIME       (3000)
+	};
+	u32 chip_uptime;
+	#define ESAS2R_CHP_UPTIME_MAX       (60000)
+	#define ESAS2R_CHP_UPTIME_CNT       (20000)
+	u64 uncached_phys;
+	u8 *uncached;
+	struct esas2r_sas_nvram *nvram;
+	struct esas2r_request general_req;
+	u8 init_msg;
+	#define ESAS2R_INIT_MSG_START       1
+	#define ESAS2R_INIT_MSG_INIT        2
+	#define ESAS2R_INIT_MSG_GET_INIT    3
+	#define ESAS2R_INIT_MSG_REINIT      4
+	u16 cmd_ref_no;
+	u32 fw_version;
+	u32 fw_build;
+	u32 chip_init_time;
+	#define ESAS2R_CHPRST_TIME         (180000)
+	#define ESAS2R_CHPRST_WAIT_TIME    (2000)
+	u32 last_tick_time;
+	u32 window_base;
+	RQBUILDSGL build_sgl;
+	struct esas2r_request *first_ae_req;
+	u32 list_size;
+	u32 last_write;
+	u32 last_read;
+	u16 max_vdareq_size;
+	u16 disc_wait_cnt;
+	struct esas2r_mem_desc inbound_list_md;
+	struct esas2r_mem_desc outbound_list_md;
+	struct esas2r_disc_context disc_ctx;
+	u8 *disc_buffer;
+	u32 disc_start_time;
+	u32 disc_wait_time;
+	u32 flash_ver;
+	char flash_rev[16];
+	char fw_rev[16];
+	char image_type[16];
+	struct esas2r_flash_context flash_context;
+	u32 num_targets_backend;
+	u32 ioctl_tunnel;
+	struct tasklet_struct tasklet;
+	struct pci_dev *pcid;
+	struct Scsi_Host *host;
+	unsigned int index;
+	char name[32];
+	struct timer_list timer;
+	struct esas2r_firmware firmware;
+	wait_queue_head_t nvram_waiter;
+	int nvram_command_done;
+	wait_queue_head_t fm_api_waiter;
+	int fm_api_command_done;
+	wait_queue_head_t vda_waiter;
+	int vda_command_done;
+	u8 *vda_buffer;
+	u64 ppvda_buffer;
+#define VDA_BUFFER_HEADER_SZ (offsetof(struct atto_ioctl_vda, data))
+#define VDA_MAX_BUFFER_SIZE  (0x40000 + VDA_BUFFER_HEADER_SZ)
+	wait_queue_head_t fs_api_waiter;
+	int fs_api_command_done;
+	u64 ppfs_api_buffer;
+	u8 *fs_api_buffer;
+	u32 fs_api_buffer_size;
+	wait_queue_head_t buffered_ioctl_waiter;
+	int buffered_ioctl_done;
+	int uncached_size;
+	struct workqueue_struct *fw_event_q;
+	struct list_head fw_event_list;
+	spinlock_t fw_event_lock;
+	u8 fw_events_off;                       /* if '1', then ignore events */
+	char fw_event_q_name[ESAS2R_KOBJ_NAME_LEN];
+	/*
+	 * intr_mode stores the interrupt mode currently being used by this
+	 * adapter. it is based on the interrupt_mode module parameter, but
+	 * can be changed based on the ability (or not) to utilize the
+	 * mode requested by the parameter.
+	 */
+	int intr_mode;
+#define INTR_MODE_LEGACY 0
+#define INTR_MODE_MSI    1
+#define INTR_MODE_MSIX   2
+	struct esas2r_sg_context fm_api_sgc;
+	u8 *save_offset;
+	struct list_head vrq_mds_head;
+	struct esas2r_mem_desc *vrq_mds;
+	int num_vrqs;
+	struct semaphore fm_api_semaphore;
+	struct semaphore fs_api_semaphore;
+	struct semaphore nvram_semaphore;
+	struct atto_ioctl *local_atto_ioctl;
+	u8 fw_coredump_buff[ESAS2R_FWCOREDUMP_SZ];
+	unsigned int sysfs_fw_created:1;
+	unsigned int sysfs_fs_created:1;
+	unsigned int sysfs_vda_created:1;
+	unsigned int sysfs_hw_created:1;
+	unsigned int sysfs_live_nvram_created:1;
+	unsigned int sysfs_default_nvram_created:1;
+};
+
+/*
+ * Function Declarations
+ * SCSI functions
+ */
+int esas2r_release(struct Scsi_Host *);
+const char *esas2r_info(struct Scsi_Host *);
+int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq,
+			struct esas2r_sas_nvram *data);
+int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg);
+int esas2r_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
+u8 handle_hba_ioctl(struct esas2r_adapter *a,
+		    struct atto_ioctl *ioctl_hba);
+int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd);
+int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh);
+int esas2r_slave_alloc(struct scsi_device *dev);
+int esas2r_slave_configure(struct scsi_device *dev);
+void esas2r_slave_destroy(struct scsi_device *dev);
+int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason);
+int esas2r_change_queue_type(struct scsi_device *dev, int type);
+long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
+
+/* SCSI error handler (eh) functions */
+int esas2r_eh_abort(struct scsi_cmnd *cmd);
+int esas2r_device_reset(struct scsi_cmnd *cmd);
+int esas2r_host_reset(struct scsi_cmnd *cmd);
+int esas2r_bus_reset(struct scsi_cmnd *cmd);
+int esas2r_target_reset(struct scsi_cmnd *cmd);
+
+/* Internal functions */
+int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
+			int index);
+int esas2r_cleanup(struct Scsi_Host *host);
+int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count);
+int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off,
+		    int count);
+int esas2r_read_vda(struct esas2r_adapter *a, char *buf, long off, int count);
+int esas2r_write_vda(struct esas2r_adapter *a, const char *buf, long off,
+		     int count);
+int esas2r_read_fs(struct esas2r_adapter *a, char *buf, long off, int count);
+int esas2r_write_fs(struct esas2r_adapter *a, const char *buf, long off,
+		    int count);
+void esas2r_adapter_tasklet(unsigned long context);
+irqreturn_t esas2r_interrupt(int irq, void *dev_id);
+irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id);
+void esas2r_kickoff_timer(struct esas2r_adapter *a);
+int esas2r_suspend(struct pci_dev *pcid, pm_message_t state);
+int esas2r_resume(struct pci_dev *pcid);
+void esas2r_fw_event_off(struct esas2r_adapter *a);
+void esas2r_fw_event_on(struct esas2r_adapter *a);
+bool esas2r_nvram_write(struct esas2r_adapter *a, struct esas2r_request *rq,
+			struct esas2r_sas_nvram *nvram);
+void esas2r_nvram_get_defaults(struct esas2r_adapter *a,
+			       struct esas2r_sas_nvram *nvram);
+void esas2r_complete_request_cb(struct esas2r_adapter *a,
+				struct esas2r_request *rq);
+void esas2r_reset_detected(struct esas2r_adapter *a);
+void esas2r_target_state_changed(struct esas2r_adapter *ha, u16 targ_id,
+				 u8 state);
+int esas2r_req_status_to_error(u8 req_stat);
+void esas2r_kill_adapter(int i);
+void esas2r_free_request(struct esas2r_adapter *a, struct esas2r_request *rq);
+struct esas2r_request *esas2r_alloc_request(struct esas2r_adapter *a);
+u32 esas2r_get_uncached_size(struct esas2r_adapter *a);
+bool esas2r_init_adapter_struct(struct esas2r_adapter *a,
+				void **uncached_area);
+bool esas2r_check_adapter(struct esas2r_adapter *a);
+bool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll);
+void esas2r_start_request(struct esas2r_adapter *a, struct esas2r_request *rq);
+bool esas2r_send_task_mgmt(struct esas2r_adapter *a,
+			   struct esas2r_request *rqaux, u8 task_mgt_func);
+void esas2r_do_tasklet_tasks(struct esas2r_adapter *a);
+void esas2r_adapter_interrupt(struct esas2r_adapter *a);
+void esas2r_do_deferred_processes(struct esas2r_adapter *a);
+void esas2r_reset_bus(struct esas2r_adapter *a);
+void esas2r_reset_adapter(struct esas2r_adapter *a);
+void esas2r_timer_tick(struct esas2r_adapter *a);
+const char *esas2r_get_model_name(struct esas2r_adapter *a);
+const char *esas2r_get_model_name_short(struct esas2r_adapter *a);
+u32 esas2r_stall_execution(struct esas2r_adapter *a, u32 start_time,
+			   u32 *delay);
+void esas2r_build_flash_req(struct esas2r_adapter *a,
+			    struct esas2r_request *rq,
+			    u8 sub_func,
+			    u8 cksum,
+			    u32 addr,
+			    u32 length);
+void esas2r_build_mgt_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq,
+			  u8 sub_func,
+			  u8 scan_gen,
+			  u16 dev_index,
+			  u32 length,
+			  void *data);
+void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq);
+void esas2r_build_cli_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq,
+			  u32 length,
+			  u32 cmd_rsp_len);
+void esas2r_build_ioctl_req(struct esas2r_adapter *a,
+			    struct esas2r_request *rq,
+			    u32 length,
+			    u8 sub_func);
+void esas2r_build_cfg_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq,
+			  u8 sub_func,
+			  u32 length,
+			  void *data);
+void esas2r_power_down(struct esas2r_adapter *a);
+bool esas2r_power_up(struct esas2r_adapter *a, bool init_poll);
+void esas2r_wait_request(struct esas2r_adapter *a, struct esas2r_request *rq);
+u32 esas2r_map_data_window(struct esas2r_adapter *a, u32 addr_lo);
+bool esas2r_process_fs_ioctl(struct esas2r_adapter *a,
+			     struct esas2r_ioctl_fs *fs,
+			     struct esas2r_request *rq,
+			     struct esas2r_sg_context *sgc);
+bool esas2r_read_flash_block(struct esas2r_adapter *a, void *to, u32 from,
+			     u32 size);
+bool esas2r_read_mem_block(struct esas2r_adapter *a, void *to, u32 from,
+			   u32 size);
+bool esas2r_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi,
+		   struct esas2r_request *rq, struct esas2r_sg_context *sgc);
+void esas2r_force_interrupt(struct esas2r_adapter *a);
+void esas2r_local_start_request(struct esas2r_adapter *a,
+				struct esas2r_request *rq);
+void esas2r_process_adapter_reset(struct esas2r_adapter *a);
+void esas2r_complete_request(struct esas2r_adapter *a,
+			     struct esas2r_request *rq);
+void esas2r_dummy_complete(struct esas2r_adapter *a,
+			   struct esas2r_request *rq);
+void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq);
+void esas2r_start_vda_request(struct esas2r_adapter *a,
+			      struct esas2r_request *rq);
+bool esas2r_read_flash_rev(struct esas2r_adapter *a);
+bool esas2r_read_image_type(struct esas2r_adapter *a);
+bool esas2r_nvram_read_direct(struct esas2r_adapter *a);
+bool esas2r_nvram_validate(struct esas2r_adapter *a);
+void esas2r_nvram_set_defaults(struct esas2r_adapter *a);
+bool esas2r_print_flash_rev(struct esas2r_adapter *a);
+void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt);
+bool esas2r_init_msgs(struct esas2r_adapter *a);
+bool esas2r_is_adapter_present(struct esas2r_adapter *a);
+void esas2r_nuxi_mgt_data(u8 function, void *data);
+void esas2r_nuxi_cfg_data(u8 function, void *data);
+void esas2r_nuxi_ae_data(union atto_vda_ae *ae);
+void esas2r_reset_chip(struct esas2r_adapter *a);
+void esas2r_log_request_failure(struct esas2r_adapter *a,
+				struct esas2r_request *rq);
+void esas2r_polled_interrupt(struct esas2r_adapter *a);
+bool esas2r_ioreq_aborted(struct esas2r_adapter *a, struct esas2r_request *rq,
+			  u8 status);
+bool esas2r_build_sg_list_sge(struct esas2r_adapter *a,
+			      struct esas2r_sg_context *sgc);
+bool esas2r_build_sg_list_prd(struct esas2r_adapter *a,
+			      struct esas2r_sg_context *sgc);
+void esas2r_targ_db_initialize(struct esas2r_adapter *a);
+void esas2r_targ_db_remove_all(struct esas2r_adapter *a, bool notify);
+void esas2r_targ_db_report_changes(struct esas2r_adapter *a);
+struct esas2r_target *esas2r_targ_db_add_raid(struct esas2r_adapter *a,
+					      struct esas2r_disc_context *dc);
+struct esas2r_target *esas2r_targ_db_add_pthru(struct esas2r_adapter *a,
+					       struct esas2r_disc_context *dc,
+					       u8 *ident,
+					       u8 ident_len);
+void esas2r_targ_db_remove(struct esas2r_adapter *a, struct esas2r_target *t);
+struct esas2r_target *esas2r_targ_db_find_by_sas_addr(struct esas2r_adapter *a,
+						      u64 *sas_addr);
+struct esas2r_target *esas2r_targ_db_find_by_ident(struct esas2r_adapter *a,
+						   void *identifier,
+						   u8 ident_len);
+u16 esas2r_targ_db_find_next_present(struct esas2r_adapter *a, u16 target_id);
+struct esas2r_target *esas2r_targ_db_find_by_virt_id(struct esas2r_adapter *a,
+						     u16 virt_id);
+u16 esas2r_targ_db_get_tgt_cnt(struct esas2r_adapter *a);
+void esas2r_disc_initialize(struct esas2r_adapter *a);
+void esas2r_disc_start_waiting(struct esas2r_adapter *a);
+void esas2r_disc_check_for_work(struct esas2r_adapter *a);
+void esas2r_disc_check_complete(struct esas2r_adapter *a);
+void esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt);
+bool esas2r_disc_start_port(struct esas2r_adapter *a);
+void esas2r_disc_local_start_request(struct esas2r_adapter *a,
+				     struct esas2r_request *rq);
+bool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str);
+bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
+			      struct atto_ioctl_vda *vi,
+			      struct esas2r_request *rq,
+			      struct esas2r_sg_context *sgc);
+void esas2r_queue_fw_event(struct esas2r_adapter *a,
+			   enum fw_event_type type,
+			   void *data,
+			   int data_sz);
+
+/* Inline functions */
+static inline u32 esas2r_lock_set_flags(volatile u32 *flags, u32 bits)
+{
+	return test_and_set_bit(ilog2(bits), (volatile unsigned long *)flags);
+}
+
+static inline u32 esas2r_lock_clear_flags(volatile u32 *flags, u32 bits)
+{
+	return test_and_clear_bit(ilog2(bits),
+				  (volatile unsigned long *)flags);
+}
+
+/* Allocate a chip scatter/gather list entry */
+static inline struct esas2r_mem_desc *esas2r_alloc_sgl(struct esas2r_adapter *a)
+{
+	unsigned long flags;
+	struct list_head *sgl;
+	struct esas2r_mem_desc *result = NULL;
+
+	spin_lock_irqsave(&a->sg_list_lock, flags);
+	if (likely(!list_empty(&a->free_sg_list_head))) {
+		sgl = a->free_sg_list_head.next;
+		result = list_entry(sgl, struct esas2r_mem_desc, next_desc);
+		list_del_init(sgl);
+	}
+	spin_unlock_irqrestore(&a->sg_list_lock, flags);
+
+	return result;
+}
+
+/* Initialize a scatter/gather context */
+static inline void esas2r_sgc_init(struct esas2r_sg_context *sgc,
+				   struct esas2r_adapter *a,
+				   struct esas2r_request *rq,
+				   struct atto_vda_sge *first)
+{
+	sgc->adapter = a;
+	sgc->first_req = rq;
+
+	/*
+	 * set the limit pointer such that an SGE pointer above this value
+	 * would be the first one to overflow the SGL.
+	 */
+	sgc->sge.a64.limit = (struct atto_vda_sge *)((u8 *)rq->vrq
+						     + (sizeof(union
+							       atto_vda_req) /
+							8)
+						     - sizeof(struct
+							      atto_vda_sge));
+	if (first) {
+		sgc->sge.a64.last =
+			sgc->sge.a64.curr = first;
+		rq->vrq->scsi.sg_list_offset = (u8)
+					       ((u8 *)first -
+						(u8 *)rq->vrq);
+	} else {
+		sgc->sge.a64.last =
+			sgc->sge.a64.curr = &rq->vrq->scsi.u.sge[0];
+		rq->vrq->scsi.sg_list_offset =
+			(u8)offsetof(struct atto_vda_scsi_req, u.sge);
+	}
+	sgc->sge.a64.chain = NULL;
+}
+
+static inline void esas2r_rq_init_request(struct esas2r_request *rq,
+					  struct esas2r_adapter *a)
+{
+	union atto_vda_req *vrq = rq->vrq;
+	u32 handle;
+
+	INIT_LIST_HEAD(&rq->sg_table_head);
+	rq->data_buf = (void *)(vrq + 1);
+	rq->interrupt_cb = NULL;
+	rq->comp_cb = esas2r_complete_request_cb;
+	rq->flags = 0;
+	rq->timeout = 0;
+	rq->req_stat = RS_PENDING;
+	rq->req_type = RT_INI_REQ;
+
+	/* clear the outbound response */
+	rq->func_rsp.dwords[0] = 0;
+	rq->func_rsp.dwords[1] = 0;
+
+	/*
+	 * clear the size of the VDA request.  esas2r_build_sg_list() will
+	 * only allow the size of the request to grow.  there are some
+	 * management requests that go through there twice and the second
+	 * time through sets a smaller request size.  if this is not modified
+	 * at all we'll set it to the size of the entire VDA request.
+	 */
+	rq->vda_req_sz = RQ_SIZE_DEFAULT;
+
+	/* req_table entry should be NULL at this point - if not, halt */
+
+	if (a->req_table[LOWORD(vrq->scsi.handle)])
+		esas2r_bugon();
+
+	/* fill in the table for this handle so we can get back to the
+	 * request.
+	 */
+	a->req_table[LOWORD(vrq->scsi.handle)] = rq;
+
+	/*
+	 * add a reference number to the handle to make it unique (until it
+	 * wraps of course) while preserving the upper word
+	 */
+
+	handle = be32_to_cpu(vrq->scsi.handle) & 0xFFFF0000;
+	vrq->scsi.handle = cpu_to_be32(handle + a->cmd_ref_no++);
+
+	/*
+	 * the following formats a SCSI request.  the caller can override as
+	 * necessary.  clear_vda_request can be called to clear the VDA
+	 * request for another type of request.
+	 */
+	vrq->scsi.function = VDA_FUNC_SCSI;
+	vrq->scsi.sense_len = SENSE_DATA_SZ;
+
+	/* clear out sg_list_offset and chain_offset */
+	vrq->scsi.sg_list_offset = 0;
+	vrq->scsi.chain_offset = 0;
+	vrq->scsi.flags = 0;
+	vrq->scsi.reserved = 0;
+
+	/* set the sense buffer to be the data payload buffer */
+	vrq->scsi.ppsense_buf
+		= cpu_to_le64(rq->vrq_md->phys_addr +
+			      sizeof(union atto_vda_req));
+}
+
+static inline void esas2r_rq_free_sg_lists(struct esas2r_request *rq,
+					   struct esas2r_adapter *a)
+{
+	unsigned long flags;
+
+	if (list_empty(&rq->sg_table_head))
+		return;
+
+	spin_lock_irqsave(&a->sg_list_lock, flags);
+	list_splice_tail_init(&rq->sg_table_head, &a->free_sg_list_head);
+	spin_unlock_irqrestore(&a->sg_list_lock, flags);
+}
+
+static inline void esas2r_rq_destroy_request(struct esas2r_request *rq,
+					     struct esas2r_adapter *a)
+
+{
+	esas2r_rq_free_sg_lists(rq, a);
+	a->req_table[LOWORD(rq->vrq->scsi.handle)] = NULL;
+	rq->data_buf = NULL;
+}
+
+static inline bool esas2r_is_tasklet_pending(struct esas2r_adapter *a)
+{
+	return (a->flags & (AF_BUSRST_NEEDED | AF_BUSRST_DETECTED
+			    | AF_CHPRST_NEEDED | AF_CHPRST_DETECTED
+			    | AF_PORT_CHANGE))
+	       ? true : false;
+}
+
+/*
+ * Build the scatter/gather list for an I/O request according to the
+ * specifications placed in the esas2r_sg_context.  The caller must initialize
+ * struct esas2r_sg_context prior to the initial call by calling
+ * esas2r_sgc_init()
+ */
+static inline bool esas2r_build_sg_list(struct esas2r_adapter *a,
+					struct esas2r_request *rq,
+					struct esas2r_sg_context *sgc)
+{
+	if (unlikely(le32_to_cpu(rq->vrq->scsi.length) == 0))
+		return true;
+
+	return (*a->build_sgl)(a, sgc);
+}
+
+static inline void esas2r_disable_chip_interrupts(struct esas2r_adapter *a)
+{
+	if (atomic_inc_return(&a->dis_ints_cnt) == 1)
+		esas2r_write_register_dword(a, MU_INT_MASK_OUT,
+					    ESAS2R_INT_DIS_MASK);
+}
+
+static inline void esas2r_enable_chip_interrupts(struct esas2r_adapter *a)
+{
+	if (atomic_dec_return(&a->dis_ints_cnt) == 0)
+		esas2r_write_register_dword(a, MU_INT_MASK_OUT,
+					    ESAS2R_INT_ENB_MASK);
+}
+
+/* Schedule a TASKLET to perform non-interrupt tasks that may require delays
+ * or long completion times.
+ */
+static inline void esas2r_schedule_tasklet(struct esas2r_adapter *a)
+{
+	/* make sure we don't schedule twice */
+	if (!(esas2r_lock_set_flags(&a->flags, AF_TASKLET_SCHEDULED) &
+	      ilog2(AF_TASKLET_SCHEDULED)))
+		tasklet_hi_schedule(&a->tasklet);
+}
+
+static inline void esas2r_enable_heartbeat(struct esas2r_adapter *a)
+{
+	if (!(a->flags & (AF_DEGRADED_MODE | AF_CHPRST_PENDING))
+	    && (a->nvram->options2 & SASNVR2_HEARTBEAT))
+		esas2r_lock_set_flags(&a->flags, AF_HEARTBEAT_ENB);
+	else
+		esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT_ENB);
+}
+
+static inline void esas2r_disable_heartbeat(struct esas2r_adapter *a)
+{
+	esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT_ENB);
+	esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT);
+}
+
+/* Set the initial state for resetting the adapter on the next pass through
+ * esas2r_do_deferred.
+ */
+static inline void esas2r_local_reset_adapter(struct esas2r_adapter *a)
+{
+	esas2r_disable_heartbeat(a);
+
+	esas2r_lock_set_flags(&a->flags, AF_CHPRST_NEEDED);
+	esas2r_lock_set_flags(&a->flags, AF_CHPRST_PENDING);
+	esas2r_lock_set_flags(&a->flags, AF_DISC_PENDING);
+}
+
+/* See if an interrupt is pending on the adapter. */
+static inline bool esas2r_adapter_interrupt_pending(struct esas2r_adapter *a)
+{
+	u32 intstat;
+
+	if (a->int_mask == 0)
+		return false;
+
+	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+	if ((intstat & a->int_mask) == 0)
+		return false;
+
+	esas2r_disable_chip_interrupts(a);
+
+	a->int_stat = intstat;
+	a->int_mask = 0;
+
+	return true;
+}
+
+static inline u16 esas2r_targ_get_id(struct esas2r_target *t,
+				     struct esas2r_adapter *a)
+{
+	return (u16)(uintptr_t)(t - a->targetdb);
+}
+
+/*  Build and start an asynchronous event request */
+static inline void esas2r_start_ae_request(struct esas2r_adapter *a,
+					   struct esas2r_request *rq)
+{
+	unsigned long flags;
+
+	esas2r_build_ae_req(a, rq);
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+	esas2r_start_vda_request(a, rq);
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+}
+
+static inline void esas2r_comp_list_drain(struct esas2r_adapter *a,
+					  struct list_head *comp_list)
+{
+	struct esas2r_request *rq;
+	struct list_head *element, *next;
+
+	list_for_each_safe(element, next, comp_list) {
+		rq = list_entry(element, struct esas2r_request, comp_list);
+		list_del_init(element);
+		esas2r_complete_request(a, rq);
+	}
+}
+
+/* sysfs handlers */
+extern struct bin_attribute bin_attr_fw;
+extern struct bin_attribute bin_attr_fs;
+extern struct bin_attribute bin_attr_vda;
+extern struct bin_attribute bin_attr_hw;
+extern struct bin_attribute bin_attr_live_nvram;
+extern struct bin_attribute bin_attr_default_nvram;
+
+#endif /* ESAS2R_H */
diff --git a/drivers/scsi/esas2r/esas2r_disc.c b/drivers/scsi/esas2r/esas2r_disc.c
new file mode 100644
index 0000000..dec6c33
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_disc.c
@@ -0,0 +1,1189 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_disc.c
+ *      esas2r device discovery routines
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.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; 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.
+ *
+ *  NO WARRANTY
+ *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ *  solely responsible for determining the appropriateness of using and
+ *  distributing the Program and assumes all risks associated with its
+ *  exercise of rights under this Agreement, including but not limited to
+ *  the risks and costs of program errors, damage to or loss of data,
+ *  programs or equipment, and unavailability or interruption of operations.
+ *
+ *  DISCLAIMER OF LIABILITY
+ *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ *  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 "esas2r.h"
+
+/* Miscellaneous internal discovery routines */
+static void esas2r_disc_abort(struct esas2r_adapter *a,
+			      struct esas2r_request *rq);
+static bool esas2r_disc_continue(struct esas2r_adapter *a,
+				 struct esas2r_request *rq);
+static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a);
+static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr);
+static bool esas2r_disc_start_request(struct esas2r_adapter *a,
+				      struct esas2r_request *rq);
+
+/* Internal discovery routines that process the states */
+static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,
+				       struct esas2r_request *rq);
+static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,
+					  struct esas2r_request *rq);
+static bool esas2r_disc_dev_add(struct esas2r_adapter *a,
+				struct esas2r_request *rq);
+static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,
+				   struct esas2r_request *rq);
+static bool esas2r_disc_part_info(struct esas2r_adapter *a,
+				  struct esas2r_request *rq);
+static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,
+				     struct esas2r_request *rq);
+static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,
+					  struct esas2r_request *rq);
+static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,
+					     struct esas2r_request *rq);
+static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,
+					  struct esas2r_request *rq);
+static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,
+					     struct esas2r_request *rq);
+static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,
+				      struct esas2r_request *rq);
+static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,
+					 struct esas2r_request *rq);
+
+void esas2r_disc_initialize(struct esas2r_adapter *a)
+{
+	struct esas2r_sas_nvram *nvr = a->nvram;
+
+	esas2r_trace_enter();
+
+	esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
+	esas2r_lock_clear_flags(&a->flags2, AF2_DEV_SCAN);
+	esas2r_lock_clear_flags(&a->flags2, AF2_DEV_CNT_OK);
+
+	a->disc_start_time = jiffies_to_msecs(jiffies);
+	a->disc_wait_time = nvr->dev_wait_time * 1000;
+	a->disc_wait_cnt = nvr->dev_wait_count;
+
+	if (a->disc_wait_cnt > ESAS2R_MAX_TARGETS)
+		a->disc_wait_cnt = ESAS2R_MAX_TARGETS;
+
+	/*
+	 * If we are doing chip reset or power management processing, always
+	 * wait for devices.  use the NVRAM device count if it is greater than
+	 * previously discovered devices.
+	 */
+
+	esas2r_hdebug("starting discovery...");
+
+	a->general_req.interrupt_cx = NULL;
+
+	if (a->flags & (AF_CHPRST_DETECTED | AF_POWER_MGT)) {
+		if (a->prev_dev_cnt == 0) {
+			/* Don't bother waiting if there is nothing to wait
+			 * for.
+			 */
+			a->disc_wait_time = 0;
+		} else {
+			/*
+			 * Set the device wait count to what was previously
+			 * found.  We don't care if the user only configured
+			 * a time because we know the exact count to wait for.
+			 * There is no need to honor the user's wishes to
+			 * always wait the full time.
+			 */
+			a->disc_wait_cnt = a->prev_dev_cnt;
+
+			/*
+			 * bump the minimum wait time to 15 seconds since the
+			 * default is 3 (system boot or the boot driver usually
+			 * buys us more time).
+			 */
+			if (a->disc_wait_time < 15000)
+				a->disc_wait_time = 15000;
+		}
+	}
+
+	esas2r_trace("disc wait count: %d", a->disc_wait_cnt);
+	esas2r_trace("disc wait time: %d", a->disc_wait_time);
+
+	if (a->disc_wait_time == 0)
+		esas2r_disc_check_complete(a);
+
+	esas2r_trace_exit();
+}
+
+void esas2r_disc_start_waiting(struct esas2r_adapter *a)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	if (a->disc_ctx.disc_evt)
+		esas2r_disc_start_port(a);
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+}
+
+void esas2r_disc_check_for_work(struct esas2r_adapter *a)
+{
+	struct esas2r_request *rq = &a->general_req;
+
+	/* service any pending interrupts first */
+
+	esas2r_polled_interrupt(a);
+
+	/*
+	 * now, interrupt processing may have queued up a discovery event.  go
+	 * see if we have one to start.  we couldn't start it in the ISR since
+	 * polled discovery would cause a deadlock.
+	 */
+
+	esas2r_disc_start_waiting(a);
+
+	if (rq->interrupt_cx == NULL)
+		return;
+
+	if (rq->req_stat == RS_STARTED
+	    && rq->timeout <= RQ_MAX_TIMEOUT) {
+		/* wait for the current discovery request to complete. */
+		esas2r_wait_request(a, rq);
+
+		if (rq->req_stat == RS_TIMEOUT) {
+			esas2r_disc_abort(a, rq);
+			esas2r_local_reset_adapter(a);
+			return;
+		}
+	}
+
+	if (rq->req_stat == RS_PENDING
+	    || rq->req_stat == RS_STARTED)
+		return;
+
+	esas2r_disc_continue(a, rq);
+}
+
+void esas2r_disc_check_complete(struct esas2r_adapter *a)
+{
+	unsigned long flags;
+
+	esas2r_trace_enter();
+
+	/* check to see if we should be waiting for devices */
+	if (a->disc_wait_time) {
+		u32 currtime = jiffies_to_msecs(jiffies);
+		u32 time = currtime - a->disc_start_time;
+
+		/*
+		 * Wait until the device wait time is exhausted or the device
+		 * wait count is satisfied.
+		 */
+		if (time < a->disc_wait_time
+		    && (esas2r_targ_db_get_tgt_cnt(a) < a->disc_wait_cnt
+			|| a->disc_wait_cnt == 0)) {
+			/* After three seconds of waiting, schedule a scan. */
+			if (time >= 3000
+			    && !(esas2r_lock_set_flags(&a->flags2,
+						       AF2_DEV_SCAN) &
+				 ilog2(AF2_DEV_SCAN))) {
+				spin_lock_irqsave(&a->mem_lock, flags);
+				esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
+				spin_unlock_irqrestore(&a->mem_lock, flags);
+			}
+
+			esas2r_trace_exit();
+			return;
+		}
+
+		/*
+		 * We are done waiting...we think.  Adjust the wait time to
+		 * consume events after the count is met.
+		 */
+		if (!(esas2r_lock_set_flags(&a->flags2, AF2_DEV_CNT_OK)
+		      & ilog2(AF2_DEV_CNT_OK)))
+			a->disc_wait_time = time + 3000;
+
+		/* If we haven't done a full scan yet, do it now. */
+		if (!(esas2r_lock_set_flags(&a->flags2,
+					    AF2_DEV_SCAN) &
+		      ilog2(AF2_DEV_SCAN))) {
+			spin_lock_irqsave(&a->mem_lock, flags);
+			esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
+			spin_unlock_irqrestore(&a->mem_lock, flags);
+
+			esas2r_trace_exit();
+			return;
+		}
+
+		/*
+		 * Now, if there is still time left to consume events, continue
+		 * waiting.
+		 */
+		if (time < a->disc_wait_time) {
+			esas2r_trace_exit();
+			return;
+		}
+	} else {
+		if (!(esas2r_lock_set_flags(&a->flags2,
+					    AF2_DEV_SCAN) &
+		      ilog2(AF2_DEV_SCAN))) {
+			spin_lock_irqsave(&a->mem_lock, flags);
+			esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
+			spin_unlock_irqrestore(&a->mem_lock, flags);
+		}
+	}
+
+	/* We want to stop waiting for devices. */
+	a->disc_wait_time = 0;
+
+	if ((a->flags & AF_DISC_POLLED)
+	    && (a->flags & AF_DISC_IN_PROG)) {
+		/*
+		 * Polled discovery is still pending so continue the active
+		 * discovery until it is done.  At that point, we will stop
+		 * polled discovery and transition to interrupt driven
+		 * discovery.
+		 */
+	} else {
+		/*
+		 * Done waiting for devices.  Note that we get here immediately
+		 * after deferred waiting completes because that is interrupt
+		 * driven; i.e. There is no transition.
+		 */
+		esas2r_disc_fix_curr_requests(a);
+		esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
+
+		/*
+		 * We have deferred target state changes until now because we
+		 * don't want to report any removals (due to the first arrival)
+		 * until the device wait time expires.
+		 */
+		esas2r_lock_set_flags(&a->flags, AF_PORT_CHANGE);
+	}
+
+	esas2r_trace_exit();
+}
+
+void esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt)
+{
+	struct esas2r_disc_context *dc = &a->disc_ctx;
+
+	esas2r_trace_enter();
+
+	esas2r_trace("disc_event: %d", disc_evt);
+
+	/* Initialize the discovery context */
+	dc->disc_evt |= disc_evt;
+
+	/*
+	 * Don't start discovery before or during polled discovery.  if we did,
+	 * we would have a deadlock if we are in the ISR already.
+	 */
+	if (!(a->flags & (AF_CHPRST_PENDING | AF_DISC_POLLED)))
+		esas2r_disc_start_port(a);
+
+	esas2r_trace_exit();
+}
+
+bool esas2r_disc_start_port(struct esas2r_adapter *a)
+{
+	struct esas2r_request *rq = &a->general_req;
+	struct esas2r_disc_context *dc = &a->disc_ctx;
+	bool ret;
+
+	esas2r_trace_enter();
+
+	if (a->flags & AF_DISC_IN_PROG) {
+		esas2r_trace_exit();
+
+		return false;
+	}
+
+	/* If there is a discovery waiting, process it. */
+	if (dc->disc_evt) {
+		if ((a->flags & AF_DISC_POLLED)
+		    && a->disc_wait_time == 0) {
+			/*
+			 * We are doing polled discovery, but we no longer want
+			 * to wait for devices.  Stop polled discovery and
+			 * transition to interrupt driven discovery.
+			 */
+
+			esas2r_trace_exit();
+
+			return false;
+		}
+	} else {
+		/* Discovery is complete. */
+
+		esas2r_hdebug("disc done");
+
+		esas2r_lock_set_flags(&a->flags, AF_PORT_CHANGE);
+
+		esas2r_trace_exit();
+
+		return false;
+	}
+
+	/* Handle the discovery context */
+	esas2r_trace("disc_evt: %d", dc->disc_evt);
+	esas2r_lock_set_flags(&a->flags, AF_DISC_IN_PROG);
+	dc->flags = 0;
+
+	if (a->flags & AF_DISC_POLLED)
+		dc->flags |= DCF_POLLED;
+
+	rq->interrupt_cx = dc;
+	rq->req_stat = RS_SUCCESS;
+
+	/* Decode the event code */
+	if (dc->disc_evt & DCDE_DEV_SCAN) {
+		dc->disc_evt &= ~DCDE_DEV_SCAN;
+
+		dc->flags |= DCF_DEV_SCAN;
+		dc->state = DCS_BLOCK_DEV_SCAN;
+	} else if (dc->disc_evt & DCDE_DEV_CHANGE) {
+		dc->disc_evt &= ~DCDE_DEV_CHANGE;
+
+		dc->flags |= DCF_DEV_CHANGE;
+		dc->state = DCS_DEV_RMV;
+	}
+
+	/* Continue interrupt driven discovery */
+	if (!(a->flags & AF_DISC_POLLED))
+		ret = esas2r_disc_continue(a, rq);
+	else
+		ret = true;
+
+	esas2r_trace_exit();
+
+	return ret;
+}
+
+static bool esas2r_disc_continue(struct esas2r_adapter *a,
+				 struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	bool rslt;
+
+	/* Device discovery/removal */
+	while (dc->flags & (DCF_DEV_CHANGE | DCF_DEV_SCAN)) {
+		rslt = false;
+
+		switch (dc->state) {
+		case DCS_DEV_RMV:
+
+			rslt = esas2r_disc_dev_remove(a, rq);
+			break;
+
+		case DCS_DEV_ADD:
+
+			rslt = esas2r_disc_dev_add(a, rq);
+			break;
+
+		case DCS_BLOCK_DEV_SCAN:
+
+			rslt = esas2r_disc_block_dev_scan(a, rq);
+			break;
+
+		case DCS_RAID_GRP_INFO:
+
+			rslt = esas2r_disc_raid_grp_info(a, rq);
+			break;
+
+		case DCS_PART_INFO:
+
+			rslt = esas2r_disc_part_info(a, rq);
+			break;
+
+		case DCS_PT_DEV_INFO:
+
+			rslt = esas2r_disc_passthru_dev_info(a, rq);
+			break;
+		case DCS_PT_DEV_ADDR:
+
+			rslt = esas2r_disc_passthru_dev_addr(a, rq);
+			break;
+		case DCS_DISC_DONE:
+
+			dc->flags &= ~(DCF_DEV_CHANGE | DCF_DEV_SCAN);
+			break;
+
+		default:
+
+			esas2r_bugon();
+			dc->state = DCS_DISC_DONE;
+			break;
+		}
+
+		if (rslt)
+			return true;
+	}
+
+	/* Discovery is done...for now. */
+	rq->interrupt_cx = NULL;
+
+	if (!(a->flags & AF_DISC_PENDING))
+		esas2r_disc_fix_curr_requests(a);
+
+	esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
+
+	/* Start the next discovery. */
+	return esas2r_disc_start_port(a);
+}
+
+static bool esas2r_disc_start_request(struct esas2r_adapter *a,
+				      struct esas2r_request *rq)
+{
+	unsigned long flags;
+
+	/* Set the timeout to a minimum value. */
+	if (rq->timeout < ESAS2R_DEFAULT_TMO)
+		rq->timeout = ESAS2R_DEFAULT_TMO;
+
+	/*
+	 * Override the request type to distinguish discovery requests.  If we
+	 * end up deferring the request, esas2r_disc_local_start_request()
+	 * will be called to restart it.
+	 */
+	rq->req_type = RT_DISC_REQ;
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	if (!(a->flags & (AF_CHPRST_PENDING | AF_FLASHING)))
+		esas2r_disc_local_start_request(a, rq);
+	else
+		list_add_tail(&rq->req_list, &a->defer_list);
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+
+	return true;
+}
+
+void esas2r_disc_local_start_request(struct esas2r_adapter *a,
+				     struct esas2r_request *rq)
+{
+	esas2r_trace_enter();
+
+	list_add_tail(&rq->req_list, &a->active_list);
+
+	esas2r_start_vda_request(a, rq);
+
+	esas2r_trace_exit();
+
+	return;
+}
+
+static void esas2r_disc_abort(struct esas2r_adapter *a,
+			      struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+
+	esas2r_trace_enter();
+
+	/* abort the current discovery */
+
+	dc->state = DCS_DISC_DONE;
+
+	esas2r_trace_exit();
+}
+
+static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,
+				       struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	bool rslt;
+
+	esas2r_trace_enter();
+
+	esas2r_rq_init_request(rq, a);
+
+	esas2r_build_mgt_req(a,
+			     rq,
+			     VDAMGT_DEV_SCAN,
+			     0,
+			     0,
+			     0,
+			     NULL);
+
+	rq->comp_cb = esas2r_disc_block_dev_scan_cb;
+
+	rq->timeout = 30000;
+	rq->interrupt_cx = dc;
+
+	rslt = esas2r_disc_start_request(a, rq);
+
+	esas2r_trace_exit();
+
+	return rslt;
+}
+
+static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,
+					  struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	unsigned long flags;
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	if (rq->req_stat == RS_SUCCESS)
+		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+
+	dc->state = DCS_RAID_GRP_INFO;
+	dc->raid_grp_ix = 0;
+
+	esas2r_rq_destroy_request(rq, a);
+
+	/* continue discovery if it's interrupt driven */
+
+	if (!(dc->flags & DCF_POLLED))
+		esas2r_disc_continue(a, rq);
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+
+	esas2r_trace_exit();
+}
+
+static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,
+				      struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	bool rslt;
+	struct atto_vda_grp_info *grpinfo;
+
+	esas2r_trace_enter();
+
+	esas2r_trace("raid_group_idx: %d", dc->raid_grp_ix);
+
+	if (dc->raid_grp_ix >= VDA_MAX_RAID_GROUPS) {
+		dc->state = DCS_DISC_DONE;
+
+		esas2r_trace_exit();
+
+		return false;
+	}
+
+	esas2r_rq_init_request(rq, a);
+
+	grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;
+
+	memset(grpinfo, 0, sizeof(struct atto_vda_grp_info));
+
+	esas2r_build_mgt_req(a,
+			     rq,
+			     VDAMGT_GRP_INFO,
+			     dc->scan_gen,
+			     0,
+			     sizeof(struct atto_vda_grp_info),
+			     NULL);
+
+	grpinfo->grp_index = dc->raid_grp_ix;
+
+	rq->comp_cb = esas2r_disc_raid_grp_info_cb;
+
+	rq->interrupt_cx = dc;
+
+	rslt = esas2r_disc_start_request(a, rq);
+
+	esas2r_trace_exit();
+
+	return rslt;
+}
+
+static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,
+					 struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	unsigned long flags;
+	struct atto_vda_grp_info *grpinfo;
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	if (rq->req_stat == RS_SCAN_GEN) {
+		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+		dc->raid_grp_ix = 0;
+		goto done;
+	}
+
+	if (rq->req_stat == RS_SUCCESS) {
+		grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;
+
+		if (grpinfo->status != VDA_GRP_STAT_ONLINE
+		    && grpinfo->status != VDA_GRP_STAT_DEGRADED) {
+			/* go to the next group. */
+
+			dc->raid_grp_ix++;
+		} else {
+			memcpy(&dc->raid_grp_name[0],
+			       &grpinfo->grp_name[0],
+			       sizeof(grpinfo->grp_name));
+
+			dc->interleave = le32_to_cpu(grpinfo->interleave);
+			dc->block_size = le32_to_cpu(grpinfo->block_size);
+
+			dc->state = DCS_PART_INFO;
+			dc->part_num = 0;
+		}
+	} else {
+		if (!(rq->req_stat == RS_GRP_INVALID)) {
+			esas2r_log(ESAS2R_LOG_WARN,
+				   "A request for RAID group info failed - "
+				   "returned with %x",
+				   rq->req_stat);
+		}
+
+		dc->dev_ix = 0;
+		dc->state = DCS_PT_DEV_INFO;
+	}
+
+done:
+
+	esas2r_rq_destroy_request(rq, a);
+
+	/* continue discovery if it's interrupt driven */
+
+	if (!(dc->flags & DCF_POLLED))
+		esas2r_disc_continue(a, rq);
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+
+	esas2r_trace_exit();
+}
+
+static bool esas2r_disc_part_info(struct esas2r_adapter *a,
+				  struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	bool rslt;
+	struct atto_vdapart_info *partinfo;
+
+	esas2r_trace_enter();
+
+	esas2r_trace("part_num: %d", dc->part_num);
+
+	if (dc->part_num >= VDA_MAX_PARTITIONS) {
+		dc->state = DCS_RAID_GRP_INFO;
+		dc->raid_grp_ix++;
+
+		esas2r_trace_exit();
+
+		return false;
+	}
+
+	esas2r_rq_init_request(rq, a);
+
+	partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;
+
+	memset(partinfo, 0, sizeof(struct atto_vdapart_info));
+
+	esas2r_build_mgt_req(a,
+			     rq,
+			     VDAMGT_PART_INFO,
+			     dc->scan_gen,
+			     0,
+			     sizeof(struct atto_vdapart_info),
+			     NULL);
+
+	partinfo->part_no = dc->part_num;
+
+	memcpy(&partinfo->grp_name[0],
+	       &dc->raid_grp_name[0],
+	       sizeof(partinfo->grp_name));
+
+	rq->comp_cb = esas2r_disc_part_info_cb;
+
+	rq->interrupt_cx = dc;
+
+	rslt = esas2r_disc_start_request(a, rq);
+
+	esas2r_trace_exit();
+
+	return rslt;
+}
+
+static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,
+				     struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	unsigned long flags;
+	struct atto_vdapart_info *partinfo;
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	if (rq->req_stat == RS_SCAN_GEN) {
+		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+		dc->raid_grp_ix = 0;
+		dc->state = DCS_RAID_GRP_INFO;
+	} else if (rq->req_stat == RS_SUCCESS) {
+		partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;
+
+		dc->part_num = partinfo->part_no;
+
+		dc->curr_virt_id = le16_to_cpu(partinfo->target_id);
+
+		esas2r_targ_db_add_raid(a, dc);
+
+		dc->part_num++;
+	} else {
+		if (!(rq->req_stat == RS_PART_LAST)) {
+			esas2r_log(ESAS2R_LOG_WARN,
+				   "A request for RAID group partition info "
+				   "failed - status:%d", rq->req_stat);
+		}
+
+		dc->state = DCS_RAID_GRP_INFO;
+		dc->raid_grp_ix++;
+	}
+
+	esas2r_rq_destroy_request(rq, a);
+
+	/* continue discovery if it's interrupt driven */
+
+	if (!(dc->flags & DCF_POLLED))
+		esas2r_disc_continue(a, rq);
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+
+	esas2r_trace_exit();
+}
+
+static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,
+					  struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	bool rslt;
+	struct atto_vda_devinfo *devinfo;
+
+	esas2r_trace_enter();
+
+	esas2r_trace("dev_ix: %d", dc->dev_ix);
+
+	esas2r_rq_init_request(rq, a);
+
+	devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;
+
+	memset(devinfo, 0, sizeof(struct atto_vda_devinfo));
+
+	esas2r_build_mgt_req(a,
+			     rq,
+			     VDAMGT_DEV_PT_INFO,
+			     dc->scan_gen,
+			     dc->dev_ix,
+			     sizeof(struct atto_vda_devinfo),
+			     NULL);
+
+	rq->comp_cb = esas2r_disc_passthru_dev_info_cb;
+
+	rq->interrupt_cx = dc;
+
+	rslt = esas2r_disc_start_request(a, rq);
+
+	esas2r_trace_exit();
+
+	return rslt;
+}
+
+static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,
+					     struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	unsigned long flags;
+	struct atto_vda_devinfo *devinfo;
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	if (rq->req_stat == RS_SCAN_GEN) {
+		dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
+		dc->dev_ix = 0;
+		dc->state = DCS_PT_DEV_INFO;
+	} else if (rq->req_stat == RS_SUCCESS) {
+		devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;
+
+		dc->dev_ix = le16_to_cpu(rq->func_rsp.mgt_rsp.dev_index);
+
+		dc->curr_virt_id = le16_to_cpu(devinfo->target_id);
+
+		if (le16_to_cpu(devinfo->features) & VDADEVFEAT_PHYS_ID) {
+			dc->curr_phys_id =
+				le16_to_cpu(devinfo->phys_target_id);
+			dc->dev_addr_type = ATTO_GDA_AT_PORT;
+			dc->state = DCS_PT_DEV_ADDR;
+
+			esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);
+			esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);
+		} else {
+			dc->dev_ix++;
+		}
+	} else {
+		if (!(rq->req_stat == RS_DEV_INVALID)) {
+			esas2r_log(ESAS2R_LOG_WARN,
+				   "A request for device information failed - "
+				   "status:%d", rq->req_stat);
+		}
+
+		dc->state = DCS_DISC_DONE;
+	}
+
+	esas2r_rq_destroy_request(rq, a);
+
+	/* continue discovery if it's interrupt driven */
+
+	if (!(dc->flags & DCF_POLLED))
+		esas2r_disc_continue(a, rq);
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+
+	esas2r_trace_exit();
+}
+
+static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,
+					  struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	bool rslt;
+	struct atto_ioctl *hi;
+	struct esas2r_sg_context sgc;
+
+	esas2r_trace_enter();
+
+	esas2r_rq_init_request(rq, a);
+
+	/* format the request. */
+
+	sgc.cur_offset = NULL;
+	sgc.get_phys_addr = (PGETPHYSADDR)esas2r_disc_get_phys_addr;
+	sgc.length = offsetof(struct atto_ioctl, data)
+		     + sizeof(struct atto_hba_get_device_address);
+
+	esas2r_sgc_init(&sgc, a, rq, rq->vrq->ioctl.sge);
+
+	esas2r_build_ioctl_req(a, rq, sgc.length, VDA_IOCTL_HBA);
+
+	if (!esas2r_build_sg_list(a, rq, &sgc)) {
+		esas2r_rq_destroy_request(rq, a);
+
+		esas2r_trace_exit();
+
+		return false;
+	}
+
+	rq->comp_cb = esas2r_disc_passthru_dev_addr_cb;
+
+	rq->interrupt_cx = dc;
+
+	/* format the IOCTL data. */
+
+	hi = (struct atto_ioctl *)a->disc_buffer;
+
+	memset(a->disc_buffer, 0, ESAS2R_DISC_BUF_LEN);
+
+	hi->version = ATTO_VER_GET_DEV_ADDR0;
+	hi->function = ATTO_FUNC_GET_DEV_ADDR;
+	hi->flags = HBAF_TUNNEL;
+
+	hi->data.get_dev_addr.target_id = le32_to_cpu(dc->curr_phys_id);
+	hi->data.get_dev_addr.addr_type = dc->dev_addr_type;
+
+	/* start it up. */
+
+	rslt = esas2r_disc_start_request(a, rq);
+
+	esas2r_trace_exit();
+
+	return rslt;
+}
+
+static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,
+					     struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	struct esas2r_target *t = NULL;
+	unsigned long flags;
+	struct atto_ioctl *hi;
+	u16 addrlen;
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	hi = (struct atto_ioctl *)a->disc_buffer;
+
+	if (rq->req_stat == RS_SUCCESS
+	    && hi->status == ATTO_STS_SUCCESS) {
+		addrlen = le16_to_cpu(hi->data.get_dev_addr.addr_len);
+
+		if (dc->dev_addr_type == ATTO_GDA_AT_PORT) {
+			if (addrlen == sizeof(u64))
+				memcpy(&dc->sas_addr,
+				       &hi->data.get_dev_addr.address[0],
+				       addrlen);
+			else
+				memset(&dc->sas_addr, 0, sizeof(dc->sas_addr));
+
+			/* Get the unique identifier. */
+			dc->dev_addr_type = ATTO_GDA_AT_UNIQUE;
+
+			goto next_dev_addr;
+		} else {
+			/* Add the pass through target. */
+			if (HIBYTE(addrlen) == 0) {
+				t = esas2r_targ_db_add_pthru(a,
+							     dc,
+							     &hi->data.
+							     get_dev_addr.
+							     address[0],
+							     (u8)hi->data.
+							     get_dev_addr.
+							     addr_len);
+
+				if (t)
+					memcpy(&t->sas_addr, &dc->sas_addr,
+					       sizeof(t->sas_addr));
+			} else {
+				/* getting the back end data failed */
+
+				esas2r_log(ESAS2R_LOG_WARN,
+					   "an error occurred retrieving the "
+					   "back end data (%s:%d)",
+					   __func__,
+					   __LINE__);
+			}
+		}
+	} else {
+		/* getting the back end data failed */
+
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "an error occurred retrieving the back end data - "
+			   "rq->req_stat:%d hi->status:%d",
+			   rq->req_stat, hi->status);
+	}
+
+	/* proceed to the next device. */
+
+	if (dc->flags & DCF_DEV_SCAN) {
+		dc->dev_ix++;
+		dc->state = DCS_PT_DEV_INFO;
+	} else if (dc->flags & DCF_DEV_CHANGE) {
+		dc->curr_targ++;
+		dc->state = DCS_DEV_ADD;
+	} else {
+		esas2r_bugon();
+	}
+
+next_dev_addr:
+	esas2r_rq_destroy_request(rq, a);
+
+	/* continue discovery if it's interrupt driven */
+
+	if (!(dc->flags & DCF_POLLED))
+		esas2r_disc_continue(a, rq);
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+
+	esas2r_trace_exit();
+}
+
+static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr)
+{
+	struct esas2r_adapter *a = sgc->adapter;
+
+	if (sgc->length > ESAS2R_DISC_BUF_LEN)
+		esas2r_bugon();
+
+	*addr = a->uncached_phys
+		+ (u64)((u8 *)a->disc_buffer - a->uncached);
+
+	return sgc->length;
+}
+
+static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,
+				   struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	struct esas2r_target *t;
+	struct esas2r_target *t2;
+
+	esas2r_trace_enter();
+
+	/* process removals. */
+
+	for (t = a->targetdb; t < a->targetdb_end; t++) {
+		if (t->new_target_state != TS_NOT_PRESENT)
+			continue;
+
+		t->new_target_state = TS_INVALID;
+
+		/* remove the right target! */
+
+		t2 =
+			esas2r_targ_db_find_by_virt_id(a,
+						       esas2r_targ_get_id(t,
+									  a));
+
+		if (t2)
+			esas2r_targ_db_remove(a, t2);
+	}
+
+	/* removals complete.  process arrivals. */
+
+	dc->state = DCS_DEV_ADD;
+	dc->curr_targ = a->targetdb;
+
+	esas2r_trace_exit();
+
+	return false;
+}
+
+static bool esas2r_disc_dev_add(struct esas2r_adapter *a,
+				struct esas2r_request *rq)
+{
+	struct esas2r_disc_context *dc =
+		(struct esas2r_disc_context *)rq->interrupt_cx;
+	struct esas2r_target *t = dc->curr_targ;
+
+	if (t >= a->targetdb_end) {
+		/* done processing state changes. */
+
+		dc->state = DCS_DISC_DONE;
+	} else if (t->new_target_state == TS_PRESENT) {
+		struct atto_vda_ae_lu *luevt = &t->lu_event;
+
+		esas2r_trace_enter();
+
+		/* clear this now in case more events come in. */
+
+		t->new_target_state = TS_INVALID;
+
+		/* setup the discovery context for adding this device. */
+
+		dc->curr_virt_id = esas2r_targ_get_id(t, a);
+
+		if ((luevt->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id)
+		     + sizeof(struct atto_vda_ae_lu_tgt_lun_raid))
+		    && !(luevt->dwevent & VDAAE_LU_PASSTHROUGH)) {
+			dc->block_size = luevt->id.tgtlun_raid.dwblock_size;
+			dc->interleave = luevt->id.tgtlun_raid.dwinterleave;
+		} else {
+			dc->block_size = 0;
+			dc->interleave = 0;
+		}
+
+		/* determine the device type being added. */
+
+		if (luevt->dwevent & VDAAE_LU_PASSTHROUGH) {
+			if (luevt->dwevent & VDAAE_LU_PHYS_ID) {
+				dc->state = DCS_PT_DEV_ADDR;
+				dc->dev_addr_type = ATTO_GDA_AT_PORT;
+				dc->curr_phys_id = luevt->wphys_target_id;
+			} else {
+				esas2r_log(ESAS2R_LOG_WARN,
+					   "luevt->dwevent does not have the "
+					   "VDAAE_LU_PHYS_ID bit set (%s:%d)",
+					   __func__, __LINE__);
+			}
+		} else {
+			dc->raid_grp_name[0] = 0;
+
+			esas2r_targ_db_add_raid(a, dc);
+		}
+
+		esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);
+		esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);
+		esas2r_trace("dwevent: %d", luevt->dwevent);
+
+		esas2r_trace_exit();
+	}
+
+	if (dc->state == DCS_DEV_ADD) {
+		/* go to the next device. */
+
+		dc->curr_targ++;
+	}
+
+	return false;
+}
+
+/*
+ * When discovery is done, find all requests on defer queue and
+ * test if they need to be modified. If a target is no longer present
+ * then complete the request with RS_SEL. Otherwise, update the
+ * target_id since after a hibernate it can be a different value.
+ * VDA does not make passthrough target IDs persistent.
+ */
+static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a)
+{
+	unsigned long flags;
+	struct esas2r_target *t;
+	struct esas2r_request *rq;
+	struct list_head *element;
+
+	/* update virt_targ_id in any outstanding esas2r_requests  */
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	list_for_each(element, &a->defer_list) {
+		rq = list_entry(element, struct esas2r_request, req_list);
+		if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
+			t = a->targetdb + rq->target_id;
+
+			if (t->target_state == TS_PRESENT)
+				rq->vrq->scsi.target_id = le16_to_cpu(
+					t->virt_targ_id);
+			else
+				rq->req_stat = RS_SEL;
+		}
+
+	}
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+}
diff --git a/drivers/scsi/esas2r/esas2r_flash.c b/drivers/scsi/esas2r/esas2r_flash.c
new file mode 100644
index 0000000..8582929
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_flash.c
@@ -0,0 +1,1512 @@
+
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_flash.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+/* local macro defs */
+#define esas2r_nvramcalc_cksum(n)     \
+	(esas2r_calc_byte_cksum((u8 *)(n), sizeof(struct esas2r_sas_nvram), \
+				SASNVR_CKSUM_SEED))
+#define esas2r_nvramcalc_xor_cksum(n)  \
+	(esas2r_calc_byte_xor_cksum((u8 *)(n), \
+				    sizeof(struct esas2r_sas_nvram), 0))
+
+#define ESAS2R_FS_DRVR_VER 2
+
+static struct esas2r_sas_nvram default_sas_nvram = {
+	{ 'E',	'S',  'A',  'S'			     }, /* signature          */
+	SASNVR_VERSION,                                 /* version            */
+	0,                                              /* checksum           */
+	31,                                             /* max_lun_for_target */
+	SASNVR_PCILAT_MAX,                              /* pci_latency        */
+	SASNVR1_BOOT_DRVR,                              /* options1           */
+	SASNVR2_HEARTBEAT   | SASNVR2_SINGLE_BUS        /* options2           */
+	| SASNVR2_SW_MUX_CTRL,
+	SASNVR_COAL_DIS,                                /* int_coalescing     */
+	SASNVR_CMDTHR_NONE,                             /* cmd_throttle       */
+	3,                                              /* dev_wait_time      */
+	1,                                              /* dev_wait_count     */
+	0,                                              /* spin_up_delay      */
+	0,                                              /* ssp_align_rate     */
+	{ 0x50, 0x01, 0x08, 0x60,                       /* sas_addr           */
+	  0x00, 0x00, 0x00, 0x00 },
+	{ SASNVR_SPEED_AUTO },                          /* phy_speed          */
+	{ SASNVR_MUX_DISABLED },                        /* SAS multiplexing   */
+	{ 0 },                                          /* phy_flags          */
+	SASNVR_SORT_SAS_ADDR,                           /* sort_type          */
+	3,                                              /* dpm_reqcmd_lmt     */
+	3,                                              /* dpm_stndby_time    */
+	0,                                              /* dpm_active_time    */
+	{ 0 },                                          /* phy_target_id      */
+	SASNVR_VSMH_DISABLED,                           /* virt_ses_mode      */
+	SASNVR_RWM_DEFAULT,                             /* read_write_mode    */
+	0,                                              /* link down timeout  */
+	{ 0 }                                           /* reserved           */
+};
+
+static u8 cmd_to_fls_func[] = {
+	0xFF,
+	VDA_FLASH_READ,
+	VDA_FLASH_BEGINW,
+	VDA_FLASH_WRITE,
+	VDA_FLASH_COMMIT,
+	VDA_FLASH_CANCEL
+};
+
+static u8 esas2r_calc_byte_xor_cksum(u8 *addr, u32 len, u8 seed)
+{
+	u32 cksum = seed;
+	u8 *p = (u8 *)&cksum;
+
+	while (len) {
+		if (((uintptr_t)addr & 3) == 0)
+			break;
+
+		cksum = cksum ^ *addr;
+		addr++;
+		len--;
+	}
+	while (len >= sizeof(u32)) {
+		cksum = cksum ^ *(u32 *)addr;
+		addr += 4;
+		len -= 4;
+	}
+	while (len--) {
+		cksum = cksum ^ *addr;
+		addr++;
+	}
+	return p[0] ^ p[1] ^ p[2] ^ p[3];
+}
+
+static u8 esas2r_calc_byte_cksum(void *addr, u32 len, u8 seed)
+{
+	u8 *p = (u8 *)addr;
+	u8 cksum = seed;
+
+	while (len--)
+		cksum = cksum + p[len];
+	return cksum;
+}
+
+/* Interrupt callback to process FM API write requests. */
+static void esas2r_fmapi_callback(struct esas2r_adapter *a,
+				  struct esas2r_request *rq)
+{
+	struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+	struct esas2r_flash_context *fc =
+		(struct esas2r_flash_context *)rq->interrupt_cx;
+
+	if (rq->req_stat == RS_SUCCESS) {
+		/* Last request was successful.  See what to do now. */
+		switch (vrq->sub_func) {
+		case VDA_FLASH_BEGINW:
+			if (fc->sgc.cur_offset == NULL)
+				goto commit;
+
+			vrq->sub_func = VDA_FLASH_WRITE;
+			rq->req_stat = RS_PENDING;
+			break;
+
+		case VDA_FLASH_WRITE:
+commit:
+			vrq->sub_func = VDA_FLASH_COMMIT;
+			rq->req_stat = RS_PENDING;
+			rq->interrupt_cb = fc->interrupt_cb;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (rq->req_stat != RS_PENDING)
+		/*
+		 * All done. call the real callback to complete the FM API
+		 * request.  We should only get here if a BEGINW or WRITE
+		 * operation failed.
+		 */
+		(*fc->interrupt_cb)(a, rq);
+}
+
+/*
+ * Build a flash request based on the flash context.  The request status
+ * is filled in on an error.
+ */
+static void build_flash_msg(struct esas2r_adapter *a,
+			    struct esas2r_request *rq)
+{
+	struct esas2r_flash_context *fc =
+		(struct esas2r_flash_context *)rq->interrupt_cx;
+	struct esas2r_sg_context *sgc = &fc->sgc;
+	u8 cksum = 0;
+
+	/* calculate the checksum */
+	if (fc->func == VDA_FLASH_BEGINW) {
+		if (sgc->cur_offset)
+			cksum = esas2r_calc_byte_xor_cksum(sgc->cur_offset,
+							   sgc->length,
+							   0);
+		rq->interrupt_cb = esas2r_fmapi_callback;
+	} else {
+		rq->interrupt_cb = fc->interrupt_cb;
+	}
+	esas2r_build_flash_req(a,
+			       rq,
+			       fc->func,
+			       cksum,
+			       fc->flsh_addr,
+			       sgc->length);
+
+	esas2r_rq_free_sg_lists(rq, a);
+
+	/*
+	 * remember the length we asked for.  we have to keep track of
+	 * the current amount done so we know how much to compare when
+	 * doing the verification phase.
+	 */
+	fc->curr_len = fc->sgc.length;
+
+	if (sgc->cur_offset) {
+		/* setup the S/G context to build the S/G table  */
+		esas2r_sgc_init(sgc, a, rq, &rq->vrq->flash.data.sge[0]);
+
+		if (!esas2r_build_sg_list(a, rq, sgc)) {
+			rq->req_stat = RS_BUSY;
+			return;
+		}
+	} else {
+		fc->sgc.length = 0;
+	}
+
+	/* update the flsh_addr to the next one to write to  */
+	fc->flsh_addr += fc->curr_len;
+}
+
+/* determine the method to process the flash request */
+static bool load_image(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+	/*
+	 * assume we have more to do.  if we return with the status set to
+	 * RS_PENDING, FM API tasks will continue.
+	 */
+	rq->req_stat = RS_PENDING;
+	if (a->flags & AF_DEGRADED_MODE)
+		/* not suppported for now */;
+	else
+		build_flash_msg(a, rq);
+
+	return rq->req_stat == RS_PENDING;
+}
+
+/*  boot image fixer uppers called before downloading the image. */
+static void fix_bios(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
+{
+	struct esas2r_component_header *ch = &fi->cmp_hdr[CH_IT_BIOS];
+	struct esas2r_pc_image *pi;
+	struct esas2r_boot_header *bh;
+
+	pi = (struct esas2r_pc_image *)((u8 *)fi + ch->image_offset);
+	bh =
+		(struct esas2r_boot_header *)((u8 *)pi +
+					      le16_to_cpu(pi->header_offset));
+	bh->device_id = cpu_to_le16(a->pcid->device);
+
+	/* Recalculate the checksum in the PNP header if there  */
+	if (pi->pnp_offset) {
+		u8 *pnp_header_bytes =
+			((u8 *)pi + le16_to_cpu(pi->pnp_offset));
+
+		/* Identifier - dword that starts at byte 10 */
+		*((u32 *)&pnp_header_bytes[10]) =
+			cpu_to_le32(MAKEDWORD(a->pcid->subsystem_vendor,
+					      a->pcid->subsystem_device));
+
+		/* Checksum - byte 9 */
+		pnp_header_bytes[9] -= esas2r_calc_byte_cksum(pnp_header_bytes,
+							      32, 0);
+	}
+
+	/* Recalculate the checksum needed by the PC */
+	pi->checksum = pi->checksum -
+		       esas2r_calc_byte_cksum((u8 *)pi, ch->length, 0);
+}
+
+static void fix_efi(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
+{
+	struct esas2r_component_header *ch = &fi->cmp_hdr[CH_IT_EFI];
+	u32 len = ch->length;
+	u32 offset = ch->image_offset;
+	struct esas2r_efi_image *ei;
+	struct esas2r_boot_header *bh;
+
+	while (len) {
+		u32 thislen;
+
+		ei = (struct esas2r_efi_image *)((u8 *)fi + offset);
+		bh = (struct esas2r_boot_header *)((u8 *)ei +
+						   le16_to_cpu(
+							   ei->header_offset));
+		bh->device_id = cpu_to_le16(a->pcid->device);
+		thislen = (u32)le16_to_cpu(bh->image_length) * 512;
+
+		if (thislen > len)
+			break;
+
+		len -= thislen;
+		offset += thislen;
+	}
+}
+
+/* Complete a FM API request with the specified status. */
+static bool complete_fmapi_req(struct esas2r_adapter *a,
+			       struct esas2r_request *rq, u8 fi_stat)
+{
+	struct esas2r_flash_context *fc =
+		(struct esas2r_flash_context *)rq->interrupt_cx;
+	struct esas2r_flash_img *fi = fc->fi;
+
+	fi->status = fi_stat;
+	fi->driver_error = rq->req_stat;
+	rq->interrupt_cb = NULL;
+	rq->req_stat = RS_SUCCESS;
+
+	if (fi_stat != FI_STAT_IMG_VER)
+		memset(fc->scratch, 0, FM_BUF_SZ);
+
+	esas2r_enable_heartbeat(a);
+	esas2r_lock_clear_flags(&a->flags, AF_FLASH_LOCK);
+	return false;
+}
+
+/* Process each phase of the flash download process. */
+static void fw_download_proc(struct esas2r_adapter *a,
+			     struct esas2r_request *rq)
+{
+	struct esas2r_flash_context *fc =
+		(struct esas2r_flash_context *)rq->interrupt_cx;
+	struct esas2r_flash_img *fi = fc->fi;
+	struct esas2r_component_header *ch;
+	u32 len;
+	u8 *p, *q;
+
+	/* If the previous operation failed, just return. */
+	if (rq->req_stat != RS_SUCCESS)
+		goto error;
+
+	/*
+	 * If an upload just completed and the compare length is non-zero,
+	 * then we just read back part of the image we just wrote.  verify the
+	 * section and continue reading until the entire image is verified.
+	 */
+	if (fc->func == VDA_FLASH_READ
+	    && fc->cmp_len) {
+		ch = &fi->cmp_hdr[fc->comp_typ];
+
+		p = fc->scratch;
+		q = (u8 *)fi                    /* start of the whole gob     */
+		    + ch->image_offset          /* start of the current image */
+		    + ch->length                /* end of the current image   */
+		    - fc->cmp_len;              /* where we are now           */
+
+		/*
+		 * NOTE - curr_len is the exact count of bytes for the read
+		 *        even when the end is read and its not a full buffer
+		 */
+		for (len = fc->curr_len; len; len--)
+			if (*p++ != *q++)
+				goto error;
+
+		fc->cmp_len -= fc->curr_len; /* # left to compare    */
+
+		/* Update fc and determine the length for the next upload */
+		if (fc->cmp_len > FM_BUF_SZ)
+			fc->sgc.length = FM_BUF_SZ;
+		else
+			fc->sgc.length = fc->cmp_len;
+
+		fc->sgc.cur_offset = fc->sgc_offset +
+				     ((u8 *)fc->scratch - (u8 *)fi);
+	}
+
+	/*
+	 * This code uses a 'while' statement since the next component may
+	 * have a length = zero.  This can happen since some components are
+	 * not required.  At the end of this 'while' we set up the length
+	 * for the next request and therefore sgc.length can be = 0.
+	 */
+	while (fc->sgc.length == 0) {
+		ch = &fi->cmp_hdr[fc->comp_typ];
+
+		switch (fc->task) {
+		case FMTSK_ERASE_BOOT:
+			/* the BIOS image is written next */
+			ch = &fi->cmp_hdr[CH_IT_BIOS];
+			if (ch->length == 0)
+				goto no_bios;
+
+			fc->task = FMTSK_WRTBIOS;
+			fc->func = VDA_FLASH_BEGINW;
+			fc->comp_typ = CH_IT_BIOS;
+			fc->flsh_addr = FLS_OFFSET_BOOT;
+			fc->sgc.length = ch->length;
+			fc->sgc.cur_offset = fc->sgc_offset +
+					     ch->image_offset;
+			break;
+
+		case FMTSK_WRTBIOS:
+			/*
+			 * The BIOS image has been written - read it and
+			 * verify it
+			 */
+			fc->task = FMTSK_READBIOS;
+			fc->func = VDA_FLASH_READ;
+			fc->flsh_addr = FLS_OFFSET_BOOT;
+			fc->cmp_len = ch->length;
+			fc->sgc.length = FM_BUF_SZ;
+			fc->sgc.cur_offset = fc->sgc_offset
+					     + ((u8 *)fc->scratch -
+						(u8 *)fi);
+			break;
+
+		case FMTSK_READBIOS:
+no_bios:
+			/*
+			 * Mark the component header status for the image
+			 * completed
+			 */
+			ch->status = CH_STAT_SUCCESS;
+
+			/* The MAC image is written next */
+			ch = &fi->cmp_hdr[CH_IT_MAC];
+			if (ch->length == 0)
+				goto no_mac;
+
+			fc->task = FMTSK_WRTMAC;
+			fc->func = VDA_FLASH_BEGINW;
+			fc->comp_typ = CH_IT_MAC;
+			fc->flsh_addr = FLS_OFFSET_BOOT
+					+ fi->cmp_hdr[CH_IT_BIOS].length;
+			fc->sgc.length = ch->length;
+			fc->sgc.cur_offset = fc->sgc_offset +
+					     ch->image_offset;
+			break;
+
+		case FMTSK_WRTMAC:
+			/* The MAC image has been written - read and verify */
+			fc->task = FMTSK_READMAC;
+			fc->func = VDA_FLASH_READ;
+			fc->flsh_addr -= ch->length;
+			fc->cmp_len = ch->length;
+			fc->sgc.length = FM_BUF_SZ;
+			fc->sgc.cur_offset = fc->sgc_offset
+					     + ((u8 *)fc->scratch -
+						(u8 *)fi);
+			break;
+
+		case FMTSK_READMAC:
+no_mac:
+			/*
+			 * Mark the component header status for the image
+			 * completed
+			 */
+			ch->status = CH_STAT_SUCCESS;
+
+			/* The EFI image is written next */
+			ch = &fi->cmp_hdr[CH_IT_EFI];
+			if (ch->length == 0)
+				goto no_efi;
+
+			fc->task = FMTSK_WRTEFI;
+			fc->func = VDA_FLASH_BEGINW;
+			fc->comp_typ = CH_IT_EFI;
+			fc->flsh_addr = FLS_OFFSET_BOOT
+					+ fi->cmp_hdr[CH_IT_BIOS].length
+					+ fi->cmp_hdr[CH_IT_MAC].length;
+			fc->sgc.length = ch->length;
+			fc->sgc.cur_offset = fc->sgc_offset +
+					     ch->image_offset;
+			break;
+
+		case FMTSK_WRTEFI:
+			/* The EFI image has been written - read and verify */
+			fc->task = FMTSK_READEFI;
+			fc->func = VDA_FLASH_READ;
+			fc->flsh_addr -= ch->length;
+			fc->cmp_len = ch->length;
+			fc->sgc.length = FM_BUF_SZ;
+			fc->sgc.cur_offset = fc->sgc_offset
+					     + ((u8 *)fc->scratch -
+						(u8 *)fi);
+			break;
+
+		case FMTSK_READEFI:
+no_efi:
+			/*
+			 * Mark the component header status for the image
+			 * completed
+			 */
+			ch->status = CH_STAT_SUCCESS;
+
+			/* The CFG image is written next */
+			ch = &fi->cmp_hdr[CH_IT_CFG];
+
+			if (ch->length == 0)
+				goto no_cfg;
+			fc->task = FMTSK_WRTCFG;
+			fc->func = VDA_FLASH_BEGINW;
+			fc->comp_typ = CH_IT_CFG;
+			fc->flsh_addr = FLS_OFFSET_CPYR - ch->length;
+			fc->sgc.length = ch->length;
+			fc->sgc.cur_offset = fc->sgc_offset +
+					     ch->image_offset;
+			break;
+
+		case FMTSK_WRTCFG:
+			/* The CFG image has been written - read and verify */
+			fc->task = FMTSK_READCFG;
+			fc->func = VDA_FLASH_READ;
+			fc->flsh_addr = FLS_OFFSET_CPYR - ch->length;
+			fc->cmp_len = ch->length;
+			fc->sgc.length = FM_BUF_SZ;
+			fc->sgc.cur_offset = fc->sgc_offset
+					     + ((u8 *)fc->scratch -
+						(u8 *)fi);
+			break;
+
+		case FMTSK_READCFG:
+no_cfg:
+			/*
+			 * Mark the component header status for the image
+			 * completed
+			 */
+			ch->status = CH_STAT_SUCCESS;
+
+			/*
+			 * The download is complete.  If in degraded mode,
+			 * attempt a chip reset.
+			 */
+			if (a->flags & AF_DEGRADED_MODE)
+				esas2r_local_reset_adapter(a);
+
+			a->flash_ver = fi->cmp_hdr[CH_IT_BIOS].version;
+			esas2r_print_flash_rev(a);
+
+			/* Update the type of boot image on the card */
+			memcpy(a->image_type, fi->rel_version,
+			       sizeof(fi->rel_version));
+			complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
+			return;
+		}
+
+		/* If verifying, don't try reading more than what's there */
+		if (fc->func == VDA_FLASH_READ
+		    && fc->sgc.length > fc->cmp_len)
+			fc->sgc.length = fc->cmp_len;
+	}
+
+	/* Build the request to perform the next action */
+	if (!load_image(a, rq)) {
+error:
+		if (fc->comp_typ < fi->num_comps) {
+			ch = &fi->cmp_hdr[fc->comp_typ];
+			ch->status = CH_STAT_FAILED;
+		}
+
+		complete_fmapi_req(a, rq, FI_STAT_FAILED);
+	}
+}
+
+/* Determine the flash image adaptyp for this adapter */
+static u8 get_fi_adap_type(struct esas2r_adapter *a)
+{
+	u8 type;
+
+	/* use the device ID to get the correct adap_typ for this HBA */
+	switch (a->pcid->device) {
+	case ATTO_DID_INTEL_IOP348:
+		type = FI_AT_SUN_LAKE;
+		break;
+
+	case ATTO_DID_MV_88RC9580:
+	case ATTO_DID_MV_88RC9580TS:
+	case ATTO_DID_MV_88RC9580TSE:
+	case ATTO_DID_MV_88RC9580TL:
+		type = FI_AT_MV_9580;
+		break;
+
+	default:
+		type = FI_AT_UNKNWN;
+		break;
+	}
+
+	return type;
+}
+
+/* Size of config + copyright + flash_ver images, 0 for failure. */
+static u32 chk_cfg(u8 *cfg, u32 length, u32 *flash_ver)
+{
+	u16 *pw = (u16 *)cfg - 1;
+	u32 sz = 0;
+	u32 len = length;
+
+	if (len == 0)
+		len = FM_BUF_SZ;
+
+	if (flash_ver)
+		*flash_ver = 0;
+
+	while (true) {
+		u16 type;
+		u16 size;
+
+		type = le16_to_cpu(*pw--);
+		size = le16_to_cpu(*pw--);
+
+		if (type != FBT_CPYR
+		    && type != FBT_SETUP
+		    && type != FBT_FLASH_VER)
+			break;
+
+		if (type == FBT_FLASH_VER
+		    && flash_ver)
+			*flash_ver = le32_to_cpu(*(u32 *)(pw - 1));
+
+		sz += size + (2 * sizeof(u16));
+		pw -= size / sizeof(u16);
+
+		if (sz > len - (2 * sizeof(u16)))
+			break;
+	}
+
+	/* See if we are comparing the size to the specified length */
+	if (length && sz != length)
+		return 0;
+
+	return sz;
+}
+
+/* Verify that the boot image is valid */
+static u8 chk_boot(u8 *boot_img, u32 length)
+{
+	struct esas2r_boot_image *bi = (struct esas2r_boot_image *)boot_img;
+	u16 hdroffset = le16_to_cpu(bi->header_offset);
+	struct esas2r_boot_header *bh;
+
+	if (bi->signature != le16_to_cpu(0xaa55)
+	    || (long)hdroffset >
+	    (long)(65536L - sizeof(struct esas2r_boot_header))
+	    || (hdroffset & 3)
+	    || (hdroffset < sizeof(struct esas2r_boot_image))
+	    || ((u32)hdroffset + sizeof(struct esas2r_boot_header) > length))
+		return 0xff;
+
+	bh = (struct esas2r_boot_header *)((char *)bi + hdroffset);
+
+	if (bh->signature[0] != 'P'
+	    || bh->signature[1] != 'C'
+	    || bh->signature[2] != 'I'
+	    || bh->signature[3] != 'R'
+	    || le16_to_cpu(bh->struct_length) <
+	    (u16)sizeof(struct esas2r_boot_header)
+	    || bh->class_code[2] != 0x01
+	    || bh->class_code[1] != 0x04
+	    || bh->class_code[0] != 0x00
+	    || (bh->code_type != CODE_TYPE_PC
+		&& bh->code_type != CODE_TYPE_OPEN
+		&& bh->code_type != CODE_TYPE_EFI))
+		return 0xff;
+
+	return bh->code_type;
+}
+
+/* The sum of all the WORDS of the image */
+static u16 calc_fi_checksum(struct esas2r_flash_context *fc)
+{
+	struct esas2r_flash_img *fi = fc->fi;
+	u16 cksum;
+	u32 len;
+	u16 *pw;
+
+	for (len = (fi->length - fc->fi_hdr_len) / 2,
+	     pw = (u16 *)((u8 *)fi + fc->fi_hdr_len),
+	     cksum = 0;
+	     len;
+	     len--, pw++)
+		cksum = cksum + le16_to_cpu(*pw);
+
+	return cksum;
+}
+
+/*
+ * Verify the flash image structure.  The following verifications will
+ * be performed:
+ *              1)  verify the fi_version is correct
+ *              2)  verify the checksum of the entire image.
+ *              3)  validate the adap_typ, action and length fields.
+ *              4)  valdiate each component header. check the img_type and
+ *                  length fields
+ *              5)  valdiate each component image.  validate signatures and
+ *                  local checksums
+ */
+static bool verify_fi(struct esas2r_adapter *a,
+		      struct esas2r_flash_context *fc)
+{
+	struct esas2r_flash_img *fi = fc->fi;
+	u8 type;
+	bool imgerr;
+	u16 i;
+	u32 len;
+	struct esas2r_component_header *ch;
+
+	/* Verify the length - length must even since we do a word checksum */
+	len = fi->length;
+
+	if ((len & 1)
+	    || len < fc->fi_hdr_len) {
+		fi->status = FI_STAT_LENGTH;
+		return false;
+	}
+
+	/* Get adapter type and verify type in flash image */
+	type = get_fi_adap_type(a);
+	if ((type == FI_AT_UNKNWN) || (fi->adap_typ != type)) {
+		fi->status = FI_STAT_ADAPTYP;
+		return false;
+	}
+
+	/*
+	 * Loop through each component and verify the img_type and length
+	 * fields.  Keep a running count of the sizes sooze we can verify total
+	 * size to additive size.
+	 */
+	imgerr = false;
+
+	for (i = 0, len = 0, ch = fi->cmp_hdr;
+	     i < fi->num_comps;
+	     i++, ch++) {
+		bool cmperr = false;
+
+		/*
+		 * Verify that the component header has the same index as the
+		 * image type.  The headers must be ordered correctly
+		 */
+		if (i != ch->img_type) {
+			imgerr = true;
+			ch->status = CH_STAT_INVALID;
+			continue;
+		}
+
+		switch (ch->img_type) {
+		case CH_IT_BIOS:
+			type = CODE_TYPE_PC;
+			break;
+
+		case CH_IT_MAC:
+			type = CODE_TYPE_OPEN;
+			break;
+
+		case CH_IT_EFI:
+			type = CODE_TYPE_EFI;
+			break;
+		}
+
+		switch (ch->img_type) {
+		case CH_IT_FW:
+		case CH_IT_NVR:
+			break;
+
+		case CH_IT_BIOS:
+		case CH_IT_MAC:
+		case CH_IT_EFI:
+			if (ch->length & 0x1ff)
+				cmperr = true;
+
+			/* Test if component image is present  */
+			if (ch->length == 0)
+				break;
+
+			/* Image is present - verify the image */
+			if (chk_boot((u8 *)fi + ch->image_offset, ch->length)
+			    != type)
+				cmperr = true;
+
+			break;
+
+		case CH_IT_CFG:
+
+			/* Test if component image is present */
+			if (ch->length == 0) {
+				cmperr = true;
+				break;
+			}
+
+			/* Image is present - verify the image */
+			if (!chk_cfg((u8 *)fi + ch->image_offset + ch->length,
+				     ch->length, NULL))
+				cmperr = true;
+
+			break;
+
+		default:
+
+			fi->status = FI_STAT_UNKNOWN;
+			return false;
+		}
+
+		if (cmperr) {
+			imgerr = true;
+			ch->status = CH_STAT_INVALID;
+		} else {
+			ch->status = CH_STAT_PENDING;
+			len += ch->length;
+		}
+	}
+
+	if (imgerr) {
+		fi->status = FI_STAT_MISSING;
+		return false;
+	}
+
+	/* Compare fi->length to the sum of ch->length fields */
+	if (len != fi->length - fc->fi_hdr_len) {
+		fi->status = FI_STAT_LENGTH;
+		return false;
+	}
+
+	/* Compute the checksum - it should come out zero */
+	if (fi->checksum != calc_fi_checksum(fc)) {
+		fi->status = FI_STAT_CHKSUM;
+		return false;
+	}
+
+	return true;
+}
+
+/* Fill in the FS IOCTL response data from a completed request. */
+static void esas2r_complete_fs_ioctl(struct esas2r_adapter *a,
+				     struct esas2r_request *rq)
+{
+	struct esas2r_ioctl_fs *fs =
+		(struct esas2r_ioctl_fs *)rq->interrupt_cx;
+
+	if (rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
+		esas2r_enable_heartbeat(a);
+
+	fs->driver_error = rq->req_stat;
+
+	if (fs->driver_error == RS_SUCCESS)
+		fs->status = ATTO_STS_SUCCESS;
+	else
+		fs->status = ATTO_STS_FAILED;
+}
+
+/* Prepare an FS IOCTL request to be sent to the firmware. */
+bool esas2r_process_fs_ioctl(struct esas2r_adapter *a,
+			     struct esas2r_ioctl_fs *fs,
+			     struct esas2r_request *rq,
+			     struct esas2r_sg_context *sgc)
+{
+	u8 cmdcnt = (u8)ARRAY_SIZE(cmd_to_fls_func);
+	struct esas2r_ioctlfs_command *fsc = &fs->command;
+	u8 func = 0;
+	u32 datalen;
+
+	fs->status = ATTO_STS_FAILED;
+	fs->driver_error = RS_PENDING;
+
+	if (fs->version > ESAS2R_FS_VER) {
+		fs->status = ATTO_STS_INV_VERSION;
+		return false;
+	}
+
+	func = cmd_to_fls_func[fsc->command];
+	if (fsc->command >= cmdcnt || func == 0xFF) {
+		fs->status = ATTO_STS_INV_FUNC;
+		return false;
+	}
+
+	if (fsc->command != ESAS2R_FS_CMD_CANCEL) {
+		if ((a->pcid->device != ATTO_DID_MV_88RC9580
+		     || fs->adap_type != ESAS2R_FS_AT_ESASRAID2)
+		    && (a->pcid->device != ATTO_DID_MV_88RC9580TS
+			|| fs->adap_type != ESAS2R_FS_AT_TSSASRAID2)
+		    && (a->pcid->device != ATTO_DID_MV_88RC9580TSE
+			|| fs->adap_type != ESAS2R_FS_AT_TSSASRAID2E)
+		    && (a->pcid->device != ATTO_DID_MV_88RC9580TL
+			|| fs->adap_type != ESAS2R_FS_AT_TLSASHBA)) {
+			fs->status = ATTO_STS_INV_ADAPTER;
+			return false;
+		}
+
+		if (fs->driver_ver > ESAS2R_FS_DRVR_VER) {
+			fs->status = ATTO_STS_INV_DRVR_VER;
+			return false;
+		}
+	}
+
+	if (a->flags & AF_DEGRADED_MODE) {
+		fs->status = ATTO_STS_DEGRADED;
+		return false;
+	}
+
+	rq->interrupt_cb = esas2r_complete_fs_ioctl;
+	rq->interrupt_cx = fs;
+	datalen = le32_to_cpu(fsc->length);
+	esas2r_build_flash_req(a,
+			       rq,
+			       func,
+			       fsc->checksum,
+			       le32_to_cpu(fsc->flash_addr),
+			       datalen);
+
+	if (func == VDA_FLASH_WRITE
+	    || func == VDA_FLASH_READ) {
+		if (datalen == 0) {
+			fs->status = ATTO_STS_INV_FUNC;
+			return false;
+		}
+
+		esas2r_sgc_init(sgc, a, rq, rq->vrq->flash.data.sge);
+		sgc->length = datalen;
+
+		if (!esas2r_build_sg_list(a, rq, sgc)) {
+			fs->status = ATTO_STS_OUT_OF_RSRC;
+			return false;
+		}
+	}
+
+	if (func == VDA_FLASH_COMMIT)
+		esas2r_disable_heartbeat(a);
+
+	esas2r_start_request(a, rq);
+
+	return true;
+}
+
+static bool esas2r_flash_access(struct esas2r_adapter *a, u32 function)
+{
+	u32 starttime;
+	u32 timeout;
+	u32 intstat;
+	u32 doorbell;
+
+	/* Disable chip interrupts awhile */
+	if (function == DRBL_FLASH_REQ)
+		esas2r_disable_chip_interrupts(a);
+
+	/* Issue the request to the firmware */
+	esas2r_write_register_dword(a, MU_DOORBELL_IN, function);
+
+	/* Now wait for the firmware to process it */
+	starttime = jiffies_to_msecs(jiffies);
+	timeout = a->flags &
+		  (AF_CHPRST_PENDING | AF_DISC_PENDING) ? 40000 : 5000;
+
+	while (true) {
+		intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+		if (intstat & MU_INTSTAT_DRBL) {
+			/* Got a doorbell interrupt.  Check for the function */
+			doorbell =
+				esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+						    doorbell);
+			if (doorbell & function)
+				break;
+		}
+
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+		if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
+			/*
+			 * Iimeout.  If we were requesting flash access,
+			 * indicate we are done so the firmware knows we gave
+			 * up.  If this was a REQ, we also need to re-enable
+			 * chip interrupts.
+			 */
+			if (function == DRBL_FLASH_REQ) {
+				esas2r_hdebug("flash access timeout");
+				esas2r_write_register_dword(a, MU_DOORBELL_IN,
+							    DRBL_FLASH_DONE);
+				esas2r_enable_chip_interrupts(a);
+			} else {
+				esas2r_hdebug("flash release timeout");
+			}
+
+			return false;
+		}
+	}
+
+	/* if we're done, re-enable chip interrupts */
+	if (function == DRBL_FLASH_DONE)
+		esas2r_enable_chip_interrupts(a);
+
+	return true;
+}
+
+#define WINDOW_SIZE ((signed int)MW_DATA_WINDOW_SIZE)
+
+bool esas2r_read_flash_block(struct esas2r_adapter *a,
+			     void *to,
+			     u32 from,
+			     u32 size)
+{
+	u8 *end = (u8 *)to;
+
+	/* Try to acquire access to the flash */
+	if (!esas2r_flash_access(a, DRBL_FLASH_REQ))
+		return false;
+
+	while (size) {
+		u32 len;
+		u32 offset;
+		u32 iatvr;
+
+		if (a->flags2 & AF2_SERIAL_FLASH)
+			iatvr = MW_DATA_ADDR_SER_FLASH + (from & -WINDOW_SIZE);
+		else
+			iatvr = MW_DATA_ADDR_PAR_FLASH + (from & -WINDOW_SIZE);
+
+		esas2r_map_data_window(a, iatvr);
+		offset = from & (WINDOW_SIZE - 1);
+		len = size;
+
+		if (len > WINDOW_SIZE - offset)
+			len = WINDOW_SIZE - offset;
+
+		from += len;
+		size -= len;
+
+		while (len--) {
+			*end++ = esas2r_read_data_byte(a, offset);
+			offset++;
+		}
+	}
+
+	/* Release flash access */
+	esas2r_flash_access(a, DRBL_FLASH_DONE);
+	return true;
+}
+
+bool esas2r_read_flash_rev(struct esas2r_adapter *a)
+{
+	u8 bytes[256];
+	u16 *pw;
+	u16 *pwstart;
+	u16 type;
+	u16 size;
+	u32 sz;
+
+	sz = sizeof(bytes);
+	pw = (u16 *)(bytes + sz);
+	pwstart = (u16 *)bytes + 2;
+
+	if (!esas2r_read_flash_block(a, bytes, FLS_OFFSET_CPYR - sz, sz))
+		goto invalid_rev;
+
+	while (pw >= pwstart) {
+		pw--;
+		type = le16_to_cpu(*pw);
+		pw--;
+		size = le16_to_cpu(*pw);
+		pw -= size / 2;
+
+		if (type == FBT_CPYR
+		    || type == FBT_SETUP
+		    || pw < pwstart)
+			continue;
+
+		if (type == FBT_FLASH_VER)
+			a->flash_ver = le32_to_cpu(*(u32 *)pw);
+
+		break;
+	}
+
+invalid_rev:
+	return esas2r_print_flash_rev(a);
+}
+
+bool esas2r_print_flash_rev(struct esas2r_adapter *a)
+{
+	u16 year = LOWORD(a->flash_ver);
+	u8 day = LOBYTE(HIWORD(a->flash_ver));
+	u8 month = HIBYTE(HIWORD(a->flash_ver));
+
+	if (day == 0
+	    || month == 0
+	    || day > 31
+	    || month > 12
+	    || year < 2006
+	    || year > 9999) {
+		strcpy(a->flash_rev, "not found");
+		a->flash_ver = 0;
+		return false;
+	}
+
+	sprintf(a->flash_rev, "%02d/%02d/%04d", month, day, year);
+	esas2r_hdebug("flash version: %s", a->flash_rev);
+	return true;
+}
+
+/*
+ * Find the type of boot image type that is currently in the flash.
+ * The chip only has a 64 KB PCI-e expansion ROM
+ * size so only one image can be flashed at a time.
+ */
+bool esas2r_read_image_type(struct esas2r_adapter *a)
+{
+	u8 bytes[256];
+	struct esas2r_boot_image *bi;
+	struct esas2r_boot_header *bh;
+	u32 sz;
+	u32 len;
+	u32 offset;
+
+	/* Start at the base of the boot images and look for a valid image */
+	sz = sizeof(bytes);
+	len = FLS_LENGTH_BOOT;
+	offset = 0;
+
+	while (true) {
+		if (!esas2r_read_flash_block(a, bytes, FLS_OFFSET_BOOT +
+					     offset,
+					     sz))
+			goto invalid_rev;
+
+		bi = (struct esas2r_boot_image *)bytes;
+		bh = (struct esas2r_boot_header *)((u8 *)bi +
+						   le16_to_cpu(
+							   bi->header_offset));
+		if (bi->signature != cpu_to_le16(0xAA55))
+			goto invalid_rev;
+
+		if (bh->code_type == CODE_TYPE_PC) {
+			strcpy(a->image_type, "BIOS");
+
+			return true;
+		} else if (bh->code_type == CODE_TYPE_EFI) {
+			struct esas2r_efi_image *ei;
+
+			/*
+			 * So we have an EFI image.  There are several types
+			 * so see which architecture we have.
+			 */
+			ei = (struct esas2r_efi_image *)bytes;
+
+			switch (le16_to_cpu(ei->machine_type)) {
+			case EFI_MACHINE_IA32:
+				strcpy(a->image_type, "EFI 32-bit");
+				return true;
+
+			case EFI_MACHINE_IA64:
+				strcpy(a->image_type, "EFI itanium");
+				return true;
+
+			case EFI_MACHINE_X64:
+				strcpy(a->image_type, "EFI 64-bit");
+				return true;
+
+			case EFI_MACHINE_EBC:
+				strcpy(a->image_type, "EFI EBC");
+				return true;
+
+			default:
+				goto invalid_rev;
+			}
+		} else {
+			u32 thislen;
+
+			/* jump to the next image */
+			thislen = (u32)le16_to_cpu(bh->image_length) * 512;
+			if (thislen == 0
+			    || thislen + offset > len
+			    || bh->indicator == INDICATOR_LAST)
+				break;
+
+			offset += thislen;
+		}
+	}
+
+invalid_rev:
+	strcpy(a->image_type, "no boot images");
+	return false;
+}
+
+/*
+ *  Read and validate current NVRAM parameters by accessing
+ *  physical NVRAM directly.  if currently stored parameters are
+ *  invalid, use the defaults.
+ */
+bool esas2r_nvram_read_direct(struct esas2r_adapter *a)
+{
+	bool result;
+
+	if (down_interruptible(&a->nvram_semaphore))
+		return false;
+
+	if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR,
+				     sizeof(struct esas2r_sas_nvram))) {
+		esas2r_hdebug("NVRAM read failed, using defaults");
+		return false;
+	}
+
+	result = esas2r_nvram_validate(a);
+
+	up(&a->nvram_semaphore);
+
+	return result;
+}
+
+/* Interrupt callback to process NVRAM completions. */
+static void esas2r_nvram_callback(struct esas2r_adapter *a,
+				  struct esas2r_request *rq)
+{
+	struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+
+	if (rq->req_stat == RS_SUCCESS) {
+		/* last request was successful.  see what to do now. */
+
+		switch (vrq->sub_func) {
+		case VDA_FLASH_BEGINW:
+			vrq->sub_func = VDA_FLASH_WRITE;
+			rq->req_stat = RS_PENDING;
+			break;
+
+		case VDA_FLASH_WRITE:
+			vrq->sub_func = VDA_FLASH_COMMIT;
+			rq->req_stat = RS_PENDING;
+			break;
+
+		case VDA_FLASH_READ:
+			esas2r_nvram_validate(a);
+			break;
+
+		case VDA_FLASH_COMMIT:
+		default:
+			break;
+		}
+	}
+
+	if (rq->req_stat != RS_PENDING) {
+		/* update the NVRAM state */
+		if (rq->req_stat == RS_SUCCESS)
+			esas2r_lock_set_flags(&a->flags, AF_NVR_VALID);
+		else
+			esas2r_lock_clear_flags(&a->flags, AF_NVR_VALID);
+
+		esas2r_enable_heartbeat(a);
+
+		up(&a->nvram_semaphore);
+	}
+}
+
+/*
+ * Write the contents of nvram to the adapter's physical NVRAM.
+ * The cached copy of the NVRAM is also updated.
+ */
+bool esas2r_nvram_write(struct esas2r_adapter *a, struct esas2r_request *rq,
+			struct esas2r_sas_nvram *nvram)
+{
+	struct esas2r_sas_nvram *n = nvram;
+	u8 sas_address_bytes[8];
+	u32 *sas_address_dwords = (u32 *)&sas_address_bytes[0];
+	struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return false;
+
+	if (down_interruptible(&a->nvram_semaphore))
+		return false;
+
+	if (n == NULL)
+		n = a->nvram;
+
+	/* check the validity of the settings */
+	if (n->version > SASNVR_VERSION) {
+		up(&a->nvram_semaphore);
+		return false;
+	}
+
+	memcpy(&sas_address_bytes[0], n->sas_addr, 8);
+
+	if (sas_address_bytes[0] != 0x50
+	    || sas_address_bytes[1] != 0x01
+	    || sas_address_bytes[2] != 0x08
+	    || (sas_address_bytes[3] & 0xF0) != 0x60
+	    || ((sas_address_bytes[3] & 0x0F) | sas_address_dwords[1]) == 0) {
+		up(&a->nvram_semaphore);
+		return false;
+	}
+
+	if (n->spin_up_delay > SASNVR_SPINUP_MAX)
+		n->spin_up_delay = SASNVR_SPINUP_MAX;
+
+	n->version = SASNVR_VERSION;
+	n->checksum = n->checksum - esas2r_nvramcalc_cksum(n);
+	memcpy(a->nvram, n, sizeof(struct esas2r_sas_nvram));
+
+	/* write the NVRAM */
+	n = a->nvram;
+	esas2r_disable_heartbeat(a);
+
+	esas2r_build_flash_req(a,
+			       rq,
+			       VDA_FLASH_BEGINW,
+			       esas2r_nvramcalc_xor_cksum(n),
+			       FLS_OFFSET_NVR,
+			       sizeof(struct esas2r_sas_nvram));
+
+	if (a->flags & AF_LEGACY_SGE_MODE) {
+
+		vrq->data.sge[0].length =
+			cpu_to_le32(SGE_LAST |
+				    sizeof(struct esas2r_sas_nvram));
+		vrq->data.sge[0].address = cpu_to_le64(
+			a->uncached_phys + (u64)((u8 *)n - a->uncached));
+	} else {
+		vrq->data.prde[0].ctl_len =
+			cpu_to_le32(sizeof(struct esas2r_sas_nvram));
+		vrq->data.prde[0].address = cpu_to_le64(
+			a->uncached_phys
+			+ (u64)((u8 *)n - a->uncached));
+	}
+	rq->interrupt_cb = esas2r_nvram_callback;
+	esas2r_start_request(a, rq);
+	return true;
+}
+
+/* Validate the cached NVRAM.  if the NVRAM is invalid, load the defaults. */
+bool esas2r_nvram_validate(struct esas2r_adapter *a)
+{
+	struct esas2r_sas_nvram *n = a->nvram;
+	bool rslt = false;
+
+	if (n->signature[0] != 'E'
+	    || n->signature[1] != 'S'
+	    || n->signature[2] != 'A'
+	    || n->signature[3] != 'S') {
+		esas2r_hdebug("invalid NVRAM signature");
+	} else if (esas2r_nvramcalc_cksum(n)) {
+		esas2r_hdebug("invalid NVRAM checksum");
+	} else if (n->version > SASNVR_VERSION) {
+		esas2r_hdebug("invalid NVRAM version");
+	} else {
+		esas2r_lock_set_flags(&a->flags, AF_NVR_VALID);
+		rslt = true;
+	}
+
+	if (rslt == false) {
+		esas2r_hdebug("using defaults");
+		esas2r_nvram_set_defaults(a);
+	}
+
+	return rslt;
+}
+
+/*
+ * Set the cached NVRAM to defaults.  note that this function sets the default
+ * NVRAM when it has been determined that the physical NVRAM is invalid.
+ * In this case, the SAS address is fabricated.
+ */
+void esas2r_nvram_set_defaults(struct esas2r_adapter *a)
+{
+	struct esas2r_sas_nvram *n = a->nvram;
+	u32 time = jiffies_to_msecs(jiffies);
+
+	esas2r_lock_clear_flags(&a->flags, AF_NVR_VALID);
+	memcpy(n, &default_sas_nvram, sizeof(struct esas2r_sas_nvram));
+	n->sas_addr[3] |= 0x0F;
+	n->sas_addr[4] = HIBYTE(LOWORD(time));
+	n->sas_addr[5] = LOBYTE(LOWORD(time));
+	n->sas_addr[6] = a->pcid->bus->number;
+	n->sas_addr[7] = a->pcid->devfn;
+}
+
+void esas2r_nvram_get_defaults(struct esas2r_adapter *a,
+			       struct esas2r_sas_nvram *nvram)
+{
+	u8 sas_addr[8];
+
+	/*
+	 * in case we are copying the defaults into the adapter, copy the SAS
+	 * address out first.
+	 */
+	memcpy(&sas_addr[0], a->nvram->sas_addr, 8);
+	memcpy(nvram, &default_sas_nvram, sizeof(struct esas2r_sas_nvram));
+	memcpy(&nvram->sas_addr[0], &sas_addr[0], 8);
+}
+
+bool esas2r_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi,
+		   struct esas2r_request *rq, struct esas2r_sg_context *sgc)
+{
+	struct esas2r_flash_context *fc = &a->flash_context;
+	u8 j;
+	struct esas2r_component_header *ch;
+
+	if (esas2r_lock_set_flags(&a->flags, AF_FLASH_LOCK) & AF_FLASH_LOCK) {
+		/* flag was already set */
+		fi->status = FI_STAT_BUSY;
+		return false;
+	}
+
+	memcpy(&fc->sgc, sgc, sizeof(struct esas2r_sg_context));
+	sgc = &fc->sgc;
+	fc->fi = fi;
+	fc->sgc_offset = sgc->cur_offset;
+	rq->req_stat = RS_SUCCESS;
+	rq->interrupt_cx = fc;
+
+	switch (fi->fi_version) {
+	case FI_VERSION_1:
+		fc->scratch = ((struct esas2r_flash_img *)fi)->scratch_buf;
+		fc->num_comps = FI_NUM_COMPS_V1;
+		fc->fi_hdr_len = sizeof(struct esas2r_flash_img);
+		break;
+
+	default:
+		return complete_fmapi_req(a, rq, FI_STAT_IMG_VER);
+	}
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return complete_fmapi_req(a, rq, FI_STAT_DEGRADED);
+
+	switch (fi->action) {
+	case FI_ACT_DOWN: /* Download the components */
+		/* Verify the format of the flash image */
+		if (!verify_fi(a, fc))
+			return complete_fmapi_req(a, rq, fi->status);
+
+		/* Adjust the BIOS fields that are dependent on the HBA */
+		ch = &fi->cmp_hdr[CH_IT_BIOS];
+
+		if (ch->length)
+			fix_bios(a, fi);
+
+		/* Adjust the EFI fields that are dependent on the HBA */
+		ch = &fi->cmp_hdr[CH_IT_EFI];
+
+		if (ch->length)
+			fix_efi(a, fi);
+
+		/*
+		 * Since the image was just modified, compute the checksum on
+		 * the modified image.  First update the CRC for the composite
+		 * expansion ROM image.
+		 */
+		fi->checksum = calc_fi_checksum(fc);
+
+		/* Disable the heartbeat */
+		esas2r_disable_heartbeat(a);
+
+		/* Now start up the download sequence */
+		fc->task = FMTSK_ERASE_BOOT;
+		fc->func = VDA_FLASH_BEGINW;
+		fc->comp_typ = CH_IT_CFG;
+		fc->flsh_addr = FLS_OFFSET_BOOT;
+		fc->sgc.length = FLS_LENGTH_BOOT;
+		fc->sgc.cur_offset = NULL;
+
+		/* Setup the callback address */
+		fc->interrupt_cb = fw_download_proc;
+		break;
+
+	case FI_ACT_UPSZ: /* Get upload sizes */
+		fi->adap_typ = get_fi_adap_type(a);
+		fi->flags = 0;
+		fi->num_comps = fc->num_comps;
+		fi->length = fc->fi_hdr_len;
+
+		/* Report the type of boot image in the rel_version string */
+		memcpy(fi->rel_version, a->image_type,
+		       sizeof(fi->rel_version));
+
+		/* Build the component headers */
+		for (j = 0, ch = fi->cmp_hdr;
+		     j < fi->num_comps;
+		     j++, ch++) {
+			ch->img_type = j;
+			ch->status = CH_STAT_PENDING;
+			ch->length = 0;
+			ch->version = 0xffffffff;
+			ch->image_offset = 0;
+			ch->pad[0] = 0;
+			ch->pad[1] = 0;
+		}
+
+		if (a->flash_ver != 0) {
+			fi->cmp_hdr[CH_IT_BIOS].version =
+				fi->cmp_hdr[CH_IT_MAC].version =
+					fi->cmp_hdr[CH_IT_EFI].version =
+						fi->cmp_hdr[CH_IT_CFG].version
+							= a->flash_ver;
+
+			fi->cmp_hdr[CH_IT_BIOS].status =
+				fi->cmp_hdr[CH_IT_MAC].status =
+					fi->cmp_hdr[CH_IT_EFI].status =
+						fi->cmp_hdr[CH_IT_CFG].status =
+							CH_STAT_SUCCESS;
+
+			return complete_fmapi_req(a, rq, FI_STAT_SUCCESS);
+		}
+
+	/* fall through */
+
+	case FI_ACT_UP: /* Upload the components */
+	default:
+		return complete_fmapi_req(a, rq, FI_STAT_INVALID);
+	}
+
+	/*
+	 * If we make it here, fc has been setup to do the first task.  Call
+	 * load_image to format the request, start it, and get out.  The
+	 * interrupt code will call the callback when the first message is
+	 * complete.
+	 */
+	if (!load_image(a, rq))
+		return complete_fmapi_req(a, rq, FI_STAT_FAILED);
+
+	esas2r_start_request(a, rq);
+
+	return true;
+}
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
new file mode 100644
index 0000000..3a798e7
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -0,0 +1,1773 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_init.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag.
+ *
+ * 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.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+static bool esas2r_initmem_alloc(struct esas2r_adapter *a,
+				 struct esas2r_mem_desc *mem_desc,
+				 u32 align)
+{
+	mem_desc->esas2r_param = mem_desc->size + align;
+	mem_desc->virt_addr = NULL;
+	mem_desc->phys_addr = 0;
+	mem_desc->esas2r_data = dma_alloc_coherent(&a->pcid->dev,
+						   (size_t)mem_desc->
+						   esas2r_param,
+						   (dma_addr_t *)&mem_desc->
+						   phys_addr,
+						   GFP_KERNEL);
+
+	if (mem_desc->esas2r_data == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "failed to allocate %lu bytes of consistent memory!",
+			   (long
+			    unsigned
+			    int)mem_desc->esas2r_param);
+		return false;
+	}
+
+	mem_desc->virt_addr = PTR_ALIGN(mem_desc->esas2r_data, align);
+	mem_desc->phys_addr = ALIGN(mem_desc->phys_addr, align);
+	memset(mem_desc->virt_addr, 0, mem_desc->size);
+	return true;
+}
+
+static void esas2r_initmem_free(struct esas2r_adapter *a,
+				struct esas2r_mem_desc *mem_desc)
+{
+	if (mem_desc->virt_addr == NULL)
+		return;
+
+	/*
+	 * Careful!  phys_addr and virt_addr may have been adjusted from the
+	 * original allocation in order to return the desired alignment.  That
+	 * means we have to use the original address (in esas2r_data) and size
+	 * (esas2r_param) and calculate the original physical address based on
+	 * the difference between the requested and actual allocation size.
+	 */
+	if (mem_desc->phys_addr) {
+		int unalign = ((u8 *)mem_desc->virt_addr) -
+			      ((u8 *)mem_desc->esas2r_data);
+
+		dma_free_coherent(&a->pcid->dev,
+				  (size_t)mem_desc->esas2r_param,
+				  mem_desc->esas2r_data,
+				  (dma_addr_t)(mem_desc->phys_addr - unalign));
+	} else {
+		kfree(mem_desc->esas2r_data);
+	}
+
+	mem_desc->virt_addr = NULL;
+}
+
+static bool alloc_vda_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq)
+{
+	struct esas2r_mem_desc *memdesc = kzalloc(
+		sizeof(struct esas2r_mem_desc), GFP_KERNEL);
+
+	if (memdesc == NULL) {
+		esas2r_hdebug("could not alloc mem for vda request memdesc\n");
+		return false;
+	}
+
+	memdesc->size = sizeof(union atto_vda_req) +
+			ESAS2R_DATA_BUF_LEN;
+
+	if (!esas2r_initmem_alloc(a, memdesc, 256)) {
+		esas2r_hdebug("could not alloc mem for vda request\n");
+		kfree(memdesc);
+		return false;
+	}
+
+	a->num_vrqs++;
+	list_add(&memdesc->next_desc, &a->vrq_mds_head);
+
+	rq->vrq_md = memdesc;
+	rq->vrq = (union atto_vda_req *)memdesc->virt_addr;
+	rq->vrq->scsi.handle = a->num_vrqs;
+
+	return true;
+}
+
+static void esas2r_unmap_regions(struct esas2r_adapter *a)
+{
+	if (a->regs)
+		iounmap((void __iomem *)a->regs);
+
+	a->regs = NULL;
+
+	pci_release_region(a->pcid, 2);
+
+	if (a->data_window)
+		iounmap((void __iomem *)a->data_window);
+
+	a->data_window = NULL;
+
+	pci_release_region(a->pcid, 0);
+}
+
+static int esas2r_map_regions(struct esas2r_adapter *a)
+{
+	int error;
+
+	a->regs = NULL;
+	a->data_window = NULL;
+
+	error = pci_request_region(a->pcid, 2, a->name);
+	if (error != 0) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "pci_request_region(2) failed, error %d",
+			   error);
+
+		return error;
+	}
+
+	a->regs = (void __force *)ioremap(pci_resource_start(a->pcid, 2),
+					  pci_resource_len(a->pcid, 2));
+	if (a->regs == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "ioremap failed for regs mem region\n");
+		pci_release_region(a->pcid, 2);
+		return -EFAULT;
+	}
+
+	error = pci_request_region(a->pcid, 0, a->name);
+	if (error != 0) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "pci_request_region(2) failed, error %d",
+			   error);
+		esas2r_unmap_regions(a);
+		return error;
+	}
+
+	a->data_window = (void __force *)ioremap(pci_resource_start(a->pcid,
+								    0),
+						 pci_resource_len(a->pcid, 0));
+	if (a->data_window == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "ioremap failed for data_window mem region\n");
+		esas2r_unmap_regions(a);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static void esas2r_setup_interrupts(struct esas2r_adapter *a, int intr_mode)
+{
+	int i;
+
+	/* Set up interrupt mode based on the requested value */
+	switch (intr_mode) {
+	case INTR_MODE_LEGACY:
+use_legacy_interrupts:
+		a->intr_mode = INTR_MODE_LEGACY;
+		break;
+
+	case INTR_MODE_MSI:
+		i = pci_enable_msi(a->pcid);
+		if (i != 0) {
+			esas2r_log(ESAS2R_LOG_WARN,
+				   "failed to enable MSI for adapter %d, "
+				   "falling back to legacy interrupts "
+				   "(err=%d)", a->index,
+				   i);
+			goto use_legacy_interrupts;
+		}
+		a->intr_mode = INTR_MODE_MSI;
+		esas2r_lock_set_flags(&a->flags2, AF2_MSI_ENABLED);
+		break;
+
+
+	default:
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "unknown interrupt_mode %d requested, "
+			   "falling back to legacy interrupt",
+			   interrupt_mode);
+		goto use_legacy_interrupts;
+	}
+}
+
+static void esas2r_claim_interrupts(struct esas2r_adapter *a)
+{
+	unsigned long flags = IRQF_DISABLED;
+
+	if (a->intr_mode == INTR_MODE_LEGACY)
+		flags |= IRQF_SHARED;
+
+	esas2r_log(ESAS2R_LOG_INFO,
+		   "esas2r_claim_interrupts irq=%d (%p, %s, %x)",
+		   a->pcid->irq, a, a->name, flags);
+
+	if (request_irq(a->pcid->irq,
+			(a->intr_mode ==
+			 INTR_MODE_LEGACY) ? esas2r_interrupt :
+			esas2r_msi_interrupt,
+			flags,
+			a->name,
+			a)) {
+		esas2r_log(ESAS2R_LOG_CRIT, "unable to request IRQ %02X",
+			   a->pcid->irq);
+		return;
+	}
+
+	esas2r_lock_set_flags(&a->flags2, AF2_IRQ_CLAIMED);
+	esas2r_log(ESAS2R_LOG_INFO,
+		   "claimed IRQ %d flags: 0x%lx",
+		   a->pcid->irq, flags);
+}
+
+int esas2r_init_adapter(struct Scsi_Host *host, struct pci_dev *pcid,
+			int index)
+{
+	struct esas2r_adapter *a;
+	u64 bus_addr = 0;
+	int i;
+	void *next_uncached;
+	struct esas2r_request *first_request, *last_request;
+
+	if (index >= MAX_ADAPTERS) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "tried to init invalid adapter index %u!",
+			   index);
+		return 0;
+	}
+
+	if (esas2r_adapters[index]) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "tried to init existing adapter index %u!",
+			   index);
+		return 0;
+	}
+
+	a = (struct esas2r_adapter *)host->hostdata;
+	memset(a, 0, sizeof(struct esas2r_adapter));
+	a->pcid = pcid;
+	a->host = host;
+
+	if (sizeof(dma_addr_t) > 4) {
+		const uint64_t required_mask = dma_get_required_mask
+						       (&pcid->dev);
+		if (required_mask > DMA_BIT_MASK(32)
+		    && !pci_set_dma_mask(pcid, DMA_BIT_MASK(64))
+		    && !pci_set_consistent_dma_mask(pcid,
+						    DMA_BIT_MASK(64))) {
+			esas2r_log_dev(ESAS2R_LOG_INFO,
+				       &(a->pcid->dev),
+				       "64-bit PCI addressing enabled\n");
+		} else if (!pci_set_dma_mask(pcid, DMA_BIT_MASK(32))
+			   && !pci_set_consistent_dma_mask(pcid,
+							   DMA_BIT_MASK(32))) {
+			esas2r_log_dev(ESAS2R_LOG_INFO,
+				       &(a->pcid->dev),
+				       "32-bit PCI addressing enabled\n");
+		} else {
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "failed to set DMA mask");
+			esas2r_kill_adapter(index);
+			return 0;
+		}
+	} else {
+		if (!pci_set_dma_mask(pcid, DMA_BIT_MASK(32))
+		    && !pci_set_consistent_dma_mask(pcid,
+						    DMA_BIT_MASK(32))) {
+			esas2r_log_dev(ESAS2R_LOG_INFO,
+				       &(a->pcid->dev),
+				       "32-bit PCI addressing enabled\n");
+		} else {
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "failed to set DMA mask");
+			esas2r_kill_adapter(index);
+			return 0;
+		}
+	}
+	esas2r_adapters[index] = a;
+	sprintf(a->name, ESAS2R_DRVR_NAME "_%02d", index);
+	esas2r_debug("new adapter %p, name %s", a, a->name);
+	spin_lock_init(&a->request_lock);
+	spin_lock_init(&a->fw_event_lock);
+	sema_init(&a->fm_api_semaphore, 1);
+	sema_init(&a->fs_api_semaphore, 1);
+	sema_init(&a->nvram_semaphore, 1);
+
+	esas2r_fw_event_off(a);
+	snprintf(a->fw_event_q_name, ESAS2R_KOBJ_NAME_LEN, "esas2r/%d",
+		 a->index);
+	a->fw_event_q = create_singlethread_workqueue(a->fw_event_q_name);
+
+	init_waitqueue_head(&a->buffered_ioctl_waiter);
+	init_waitqueue_head(&a->nvram_waiter);
+	init_waitqueue_head(&a->fm_api_waiter);
+	init_waitqueue_head(&a->fs_api_waiter);
+	init_waitqueue_head(&a->vda_waiter);
+
+	INIT_LIST_HEAD(&a->general_req.req_list);
+	INIT_LIST_HEAD(&a->active_list);
+	INIT_LIST_HEAD(&a->defer_list);
+	INIT_LIST_HEAD(&a->free_sg_list_head);
+	INIT_LIST_HEAD(&a->avail_request);
+	INIT_LIST_HEAD(&a->vrq_mds_head);
+	INIT_LIST_HEAD(&a->fw_event_list);
+
+	first_request = (struct esas2r_request *)((u8 *)(a + 1));
+
+	for (last_request = first_request, i = 1; i < num_requests;
+	     last_request++, i++) {
+		INIT_LIST_HEAD(&last_request->req_list);
+		list_add_tail(&last_request->comp_list, &a->avail_request);
+		if (!alloc_vda_req(a, last_request)) {
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "failed to allocate a VDA request!");
+			esas2r_kill_adapter(index);
+			return 0;
+		}
+	}
+
+	esas2r_debug("requests: %p to %p (%d, %d)", first_request,
+		     last_request,
+		     sizeof(*first_request),
+		     num_requests);
+
+	if (esas2r_map_regions(a) != 0) {
+		esas2r_log(ESAS2R_LOG_CRIT, "could not map PCI regions!");
+		esas2r_kill_adapter(index);
+		return 0;
+	}
+
+	a->index = index;
+
+	/* interrupts will be disabled until we are done with init */
+	atomic_inc(&a->dis_ints_cnt);
+	atomic_inc(&a->disable_cnt);
+	a->flags |= AF_CHPRST_PENDING
+		    | AF_DISC_PENDING
+		    | AF_FIRST_INIT
+		    | AF_LEGACY_SGE_MODE;
+
+	a->init_msg = ESAS2R_INIT_MSG_START;
+	a->max_vdareq_size = 128;
+	a->build_sgl = esas2r_build_sg_list_sge;
+
+	esas2r_setup_interrupts(a, interrupt_mode);
+
+	a->uncached_size = esas2r_get_uncached_size(a);
+	a->uncached = dma_alloc_coherent(&pcid->dev,
+					 (size_t)a->uncached_size,
+					 (dma_addr_t *)&bus_addr,
+					 GFP_KERNEL);
+	if (a->uncached == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "failed to allocate %d bytes of consistent memory!",
+			   a->uncached_size);
+		esas2r_kill_adapter(index);
+		return 0;
+	}
+
+	a->uncached_phys = bus_addr;
+
+	esas2r_debug("%d bytes uncached memory allocated @ %p (%x:%x)",
+		     a->uncached_size,
+		     a->uncached,
+		     upper_32_bits(bus_addr),
+		     lower_32_bits(bus_addr));
+	memset(a->uncached, 0, a->uncached_size);
+	next_uncached = a->uncached;
+
+	if (!esas2r_init_adapter_struct(a,
+					&next_uncached)) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "failed to initialize adapter structure (2)!");
+		esas2r_kill_adapter(index);
+		return 0;
+	}
+
+	tasklet_init(&a->tasklet,
+		     esas2r_adapter_tasklet,
+		     (unsigned long)a);
+
+	/*
+	 * Disable chip interrupts to prevent spurious interrupts
+	 * until we claim the IRQ.
+	 */
+	esas2r_disable_chip_interrupts(a);
+	esas2r_check_adapter(a);
+
+	if (!esas2r_init_adapter_hw(a, true))
+		esas2r_log(ESAS2R_LOG_CRIT, "failed to initialize hardware!");
+	else
+		esas2r_debug("esas2r_init_adapter ok");
+
+	esas2r_claim_interrupts(a);
+
+	if (a->flags2 & AF2_IRQ_CLAIMED)
+		esas2r_enable_chip_interrupts(a);
+
+	esas2r_lock_set_flags(&a->flags2, AF2_INIT_DONE);
+	if (!(a->flags & AF_DEGRADED_MODE))
+		esas2r_kickoff_timer(a);
+	esas2r_debug("esas2r_init_adapter done for %p (%d)",
+		     a, a->disable_cnt);
+
+	return 1;
+}
+
+static void esas2r_adapter_power_down(struct esas2r_adapter *a,
+				      int power_management)
+{
+	struct esas2r_mem_desc *memdesc, *next;
+
+	if ((a->flags2 & AF2_INIT_DONE)
+	    &&  (!(a->flags & AF_DEGRADED_MODE))) {
+		if (!power_management) {
+			del_timer_sync(&a->timer);
+			tasklet_kill(&a->tasklet);
+		}
+		esas2r_power_down(a);
+
+		/*
+		 * There are versions of firmware that do not handle the sync
+		 * cache command correctly.  Stall here to ensure that the
+		 * cache is lazily flushed.
+		 */
+		mdelay(500);
+		esas2r_debug("chip halted");
+	}
+
+	/* Remove sysfs binary files */
+	if (a->sysfs_fw_created) {
+		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fw);
+		a->sysfs_fw_created = 0;
+	}
+
+	if (a->sysfs_fs_created) {
+		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_fs);
+		a->sysfs_fs_created = 0;
+	}
+
+	if (a->sysfs_vda_created) {
+		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_vda);
+		a->sysfs_vda_created = 0;
+	}
+
+	if (a->sysfs_hw_created) {
+		sysfs_remove_bin_file(&a->host->shost_dev.kobj, &bin_attr_hw);
+		a->sysfs_hw_created = 0;
+	}
+
+	if (a->sysfs_live_nvram_created) {
+		sysfs_remove_bin_file(&a->host->shost_dev.kobj,
+				      &bin_attr_live_nvram);
+		a->sysfs_live_nvram_created = 0;
+	}
+
+	if (a->sysfs_default_nvram_created) {
+		sysfs_remove_bin_file(&a->host->shost_dev.kobj,
+				      &bin_attr_default_nvram);
+		a->sysfs_default_nvram_created = 0;
+	}
+
+	/* Clean up interrupts */
+	if (a->flags2 & AF2_IRQ_CLAIMED) {
+		esas2r_log_dev(ESAS2R_LOG_INFO,
+			       &(a->pcid->dev),
+			       "free_irq(%d) called", a->pcid->irq);
+
+		free_irq(a->pcid->irq, a);
+		esas2r_debug("IRQ released");
+		esas2r_lock_clear_flags(&a->flags2, AF2_IRQ_CLAIMED);
+	}
+
+	if (a->flags2 & AF2_MSI_ENABLED) {
+		pci_disable_msi(a->pcid);
+		esas2r_lock_clear_flags(&a->flags2, AF2_MSI_ENABLED);
+		esas2r_debug("MSI disabled");
+	}
+
+	if (a->inbound_list_md.virt_addr)
+		esas2r_initmem_free(a, &a->inbound_list_md);
+
+	if (a->outbound_list_md.virt_addr)
+		esas2r_initmem_free(a, &a->outbound_list_md);
+
+	list_for_each_entry_safe(memdesc, next, &a->free_sg_list_head,
+				 next_desc) {
+		esas2r_initmem_free(a, memdesc);
+	}
+
+	/* Following frees everything allocated via alloc_vda_req */
+	list_for_each_entry_safe(memdesc, next, &a->vrq_mds_head, next_desc) {
+		esas2r_initmem_free(a, memdesc);
+		list_del(&memdesc->next_desc);
+		kfree(memdesc);
+	}
+
+	kfree(a->first_ae_req);
+	a->first_ae_req = NULL;
+
+	kfree(a->sg_list_mds);
+	a->sg_list_mds = NULL;
+
+	kfree(a->req_table);
+	a->req_table = NULL;
+
+	if (a->regs) {
+		esas2r_unmap_regions(a);
+		a->regs = NULL;
+		a->data_window = NULL;
+		esas2r_debug("regions unmapped");
+	}
+}
+
+/* Release/free allocated resources for specified adapters. */
+void esas2r_kill_adapter(int i)
+{
+	struct esas2r_adapter *a = esas2r_adapters[i];
+
+	if (a) {
+		unsigned long flags;
+		struct workqueue_struct *wq;
+		esas2r_debug("killing adapter %p [%d] ", a, i);
+		esas2r_fw_event_off(a);
+		esas2r_adapter_power_down(a, 0);
+		if (esas2r_buffered_ioctl &&
+		    (a->pcid == esas2r_buffered_ioctl_pcid)) {
+			dma_free_coherent(&a->pcid->dev,
+					  (size_t)esas2r_buffered_ioctl_size,
+					  esas2r_buffered_ioctl,
+					  esas2r_buffered_ioctl_addr);
+			esas2r_buffered_ioctl = NULL;
+		}
+
+		if (a->vda_buffer) {
+			dma_free_coherent(&a->pcid->dev,
+					  (size_t)VDA_MAX_BUFFER_SIZE,
+					  a->vda_buffer,
+					  (dma_addr_t)a->ppvda_buffer);
+			a->vda_buffer = NULL;
+		}
+		if (a->fs_api_buffer) {
+			dma_free_coherent(&a->pcid->dev,
+					  (size_t)a->fs_api_buffer_size,
+					  a->fs_api_buffer,
+					  (dma_addr_t)a->ppfs_api_buffer);
+			a->fs_api_buffer = NULL;
+		}
+
+		kfree(a->local_atto_ioctl);
+		a->local_atto_ioctl = NULL;
+
+		spin_lock_irqsave(&a->fw_event_lock, flags);
+		wq = a->fw_event_q;
+		a->fw_event_q = NULL;
+		spin_unlock_irqrestore(&a->fw_event_lock, flags);
+		if (wq)
+			destroy_workqueue(wq);
+
+		if (a->uncached) {
+			dma_free_coherent(&a->pcid->dev,
+					  (size_t)a->uncached_size,
+					  a->uncached,
+					  (dma_addr_t)a->uncached_phys);
+			a->uncached = NULL;
+			esas2r_debug("uncached area freed");
+		}
+
+		esas2r_log_dev(ESAS2R_LOG_INFO,
+			       &(a->pcid->dev),
+			       "pci_disable_device() called.  msix_enabled: %d "
+			       "msi_enabled: %d irq: %d pin: %d",
+			       a->pcid->msix_enabled,
+			       a->pcid->msi_enabled,
+			       a->pcid->irq,
+			       a->pcid->pin);
+
+		esas2r_log_dev(ESAS2R_LOG_INFO,
+			       &(a->pcid->dev),
+			       "before pci_disable_device() enable_cnt: %d",
+			       a->pcid->enable_cnt.counter);
+
+		pci_disable_device(a->pcid);
+		esas2r_log_dev(ESAS2R_LOG_INFO,
+			       &(a->pcid->dev),
+			       "after pci_disable_device() enable_cnt: %d",
+			       a->pcid->enable_cnt.counter);
+
+		esas2r_log_dev(ESAS2R_LOG_INFO,
+			       &(a->pcid->dev),
+			       "pci_set_drv_data(%p, NULL) called",
+			       a->pcid);
+
+		pci_set_drvdata(a->pcid, NULL);
+		esas2r_adapters[i] = NULL;
+
+		if (a->flags2 & AF2_INIT_DONE) {
+			esas2r_lock_clear_flags(&a->flags2,
+						AF2_INIT_DONE);
+
+			esas2r_lock_set_flags(&a->flags,
+					      AF_DEGRADED_MODE);
+
+			esas2r_log_dev(ESAS2R_LOG_INFO,
+				       &(a->host->shost_gendev),
+				       "scsi_remove_host() called");
+
+			scsi_remove_host(a->host);
+
+			esas2r_log_dev(ESAS2R_LOG_INFO,
+				       &(a->host->shost_gendev),
+				       "scsi_host_put() called");
+
+			scsi_host_put(a->host);
+		}
+	}
+}
+
+int esas2r_cleanup(struct Scsi_Host *host)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+	int index;
+
+	if (host == NULL) {
+		int i;
+
+		esas2r_debug("esas2r_cleanup everything");
+		for (i = 0; i < MAX_ADAPTERS; i++)
+			esas2r_kill_adapter(i);
+		return -1;
+	}
+
+	esas2r_debug("esas2r_cleanup called for host %p", host);
+	index = a->index;
+	esas2r_kill_adapter(index);
+	return index;
+}
+
+int esas2r_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	u32 device_state;
+	struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "suspending adapter()");
+	if (!a)
+		return -ENODEV;
+
+	esas2r_adapter_power_down(a, 1);
+	device_state = pci_choose_state(pdev, state);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_save_state() called");
+	pci_save_state(pdev);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_disable_device() called");
+	pci_disable_device(pdev);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_set_power_state() called");
+	pci_set_power_state(pdev, device_state);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "esas2r_suspend(): 0");
+	return 0;
+}
+
+int esas2r_resume(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+	int rez;
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev), "resuming adapter()");
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_set_power_state(PCI_D0) "
+		       "called");
+	pci_set_power_state(pdev, PCI_D0);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_enable_wake(PCI_D0, 0) "
+		       "called");
+	pci_enable_wake(pdev, PCI_D0, 0);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_restore_state() called");
+	pci_restore_state(pdev);
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "pci_enable_device() called");
+	rez = pci_enable_device(pdev);
+	pci_set_master(pdev);
+
+	if (!a) {
+		rez = -ENODEV;
+		goto error_exit;
+	}
+
+	if (esas2r_map_regions(a) != 0) {
+		esas2r_log(ESAS2R_LOG_CRIT, "could not re-map PCI regions!");
+		rez = -ENOMEM;
+		goto error_exit;
+	}
+
+	/* Set up interupt mode */
+	esas2r_setup_interrupts(a, a->intr_mode);
+
+	/*
+	 * Disable chip interrupts to prevent spurious interrupts until we
+	 * claim the IRQ.
+	 */
+	esas2r_disable_chip_interrupts(a);
+	if (!esas2r_power_up(a, true)) {
+		esas2r_debug("yikes, esas2r_power_up failed");
+		rez = -ENOMEM;
+		goto error_exit;
+	}
+
+	esas2r_claim_interrupts(a);
+
+	if (a->flags2 & AF2_IRQ_CLAIMED) {
+		/*
+		 * Now that system interrupt(s) are claimed, we can enable
+		 * chip interrupts.
+		 */
+		esas2r_enable_chip_interrupts(a);
+		esas2r_kickoff_timer(a);
+	} else {
+		esas2r_debug("yikes, unable to claim IRQ");
+		esas2r_log(ESAS2R_LOG_CRIT, "could not re-claim IRQ!");
+		rez = -ENOMEM;
+		goto error_exit;
+	}
+
+error_exit:
+	esas2r_log_dev(ESAS2R_LOG_CRIT, &(pdev->dev), "esas2r_resume(): %d",
+		       rez);
+	return rez;
+}
+
+bool esas2r_set_degraded_mode(struct esas2r_adapter *a, char *error_str)
+{
+	esas2r_lock_set_flags(&a->flags, AF_DEGRADED_MODE);
+	esas2r_log(ESAS2R_LOG_CRIT,
+		   "setting adapter to degraded mode: %s\n", error_str);
+	return false;
+}
+
+u32 esas2r_get_uncached_size(struct esas2r_adapter *a)
+{
+	return sizeof(struct esas2r_sas_nvram)
+	       + ALIGN(ESAS2R_DISC_BUF_LEN, 8)
+	       + ALIGN(sizeof(u32), 8) /* outbound list copy pointer */
+	       + 8
+	       + (num_sg_lists * (u16)sgl_page_size)
+	       + ALIGN((num_requests + num_ae_requests + 1 +
+			ESAS2R_LIST_EXTRA) *
+		       sizeof(struct esas2r_inbound_list_source_entry),
+		       8)
+	       + ALIGN((num_requests + num_ae_requests + 1 +
+			ESAS2R_LIST_EXTRA) *
+		       sizeof(struct atto_vda_ob_rsp), 8)
+	       + 256; /* VDA request and buffer align */
+}
+
+static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a)
+{
+	int pcie_cap_reg;
+
+	pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP);
+	if (0xffff && pcie_cap_reg) {
+		u16 devcontrol;
+
+		pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL,
+				     &devcontrol);
+
+		if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > 0x2000) {
+			esas2r_log(ESAS2R_LOG_INFO,
+				   "max read request size > 512B");
+
+			devcontrol &= ~PCI_EXP_DEVCTL_READRQ;
+			devcontrol |= 0x2000;
+			pci_write_config_word(a->pcid,
+					      pcie_cap_reg + PCI_EXP_DEVCTL,
+					      devcontrol);
+		}
+	}
+}
+
+/*
+ * Determine the organization of the uncached data area and
+ * finish initializing the adapter structure
+ */
+bool esas2r_init_adapter_struct(struct esas2r_adapter *a,
+				void **uncached_area)
+{
+	u32 i;
+	u8 *high;
+	struct esas2r_inbound_list_source_entry *element;
+	struct esas2r_request *rq;
+	struct esas2r_mem_desc *sgl;
+
+	spin_lock_init(&a->sg_list_lock);
+	spin_lock_init(&a->mem_lock);
+	spin_lock_init(&a->queue_lock);
+
+	a->targetdb_end = &a->targetdb[ESAS2R_MAX_TARGETS];
+
+	if (!alloc_vda_req(a, &a->general_req)) {
+		esas2r_hdebug(
+			"failed to allocate a VDA request for the general req!");
+		return false;
+	}
+
+	/* allocate requests for asynchronous events */
+	a->first_ae_req =
+		kzalloc(num_ae_requests * sizeof(struct esas2r_request),
+			GFP_KERNEL);
+
+	if (a->first_ae_req == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "failed to allocate memory for asynchronous events");
+		return false;
+	}
+
+	/* allocate the S/G list memory descriptors */
+	a->sg_list_mds = kzalloc(
+		num_sg_lists * sizeof(struct esas2r_mem_desc), GFP_KERNEL);
+
+	if (a->sg_list_mds == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "failed to allocate memory for s/g list descriptors");
+		return false;
+	}
+
+	/* allocate the request table */
+	a->req_table =
+		kzalloc((num_requests + num_ae_requests +
+			 1) * sizeof(struct esas2r_request *), GFP_KERNEL);
+
+	if (a->req_table == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "failed to allocate memory for the request table");
+		return false;
+	}
+
+	/* initialize PCI configuration space */
+	esas2r_init_pci_cfg_space(a);
+
+	/*
+	 * the thunder_stream boards all have a serial flash part that has a
+	 * different base address on the AHB bus.
+	 */
+	if ((a->pcid->subsystem_vendor == ATTO_VENDOR_ID)
+	    && (a->pcid->subsystem_device & ATTO_SSDID_TBT))
+		a->flags2 |= AF2_THUNDERBOLT;
+
+	if (a->flags2 & AF2_THUNDERBOLT)
+		a->flags2 |= AF2_SERIAL_FLASH;
+
+	if (a->pcid->subsystem_device == ATTO_TLSH_1068)
+		a->flags2 |= AF2_THUNDERLINK;
+
+	/* Uncached Area */
+	high = (u8 *)*uncached_area;
+
+	/* initialize the scatter/gather table pages */
+
+	for (i = 0, sgl = a->sg_list_mds; i < num_sg_lists; i++, sgl++) {
+		sgl->size = sgl_page_size;
+
+		list_add_tail(&sgl->next_desc, &a->free_sg_list_head);
+
+		if (!esas2r_initmem_alloc(a, sgl, ESAS2R_SGL_ALIGN)) {
+			/* Allow the driver to load if the minimum count met. */
+			if (i < NUM_SGL_MIN)
+				return false;
+			break;
+		}
+	}
+
+	/* compute the size of the lists */
+	a->list_size = num_requests + ESAS2R_LIST_EXTRA;
+
+	/* allocate the inbound list */
+	a->inbound_list_md.size = a->list_size *
+				  sizeof(struct
+					 esas2r_inbound_list_source_entry);
+
+	if (!esas2r_initmem_alloc(a, &a->inbound_list_md, ESAS2R_LIST_ALIGN)) {
+		esas2r_hdebug("failed to allocate IB list");
+		return false;
+	}
+
+	/* allocate the outbound list */
+	a->outbound_list_md.size = a->list_size *
+				   sizeof(struct atto_vda_ob_rsp);
+
+	if (!esas2r_initmem_alloc(a, &a->outbound_list_md,
+				  ESAS2R_LIST_ALIGN)) {
+		esas2r_hdebug("failed to allocate IB list");
+		return false;
+	}
+
+	/* allocate the NVRAM structure */
+	a->nvram = (struct esas2r_sas_nvram *)high;
+	high += sizeof(struct esas2r_sas_nvram);
+
+	/* allocate the discovery buffer */
+	a->disc_buffer = high;
+	high += ESAS2R_DISC_BUF_LEN;
+	high = PTR_ALIGN(high, 8);
+
+	/* allocate the outbound list copy pointer */
+	a->outbound_copy = (u32 volatile *)high;
+	high += sizeof(u32);
+
+	if (!(a->flags & AF_NVR_VALID))
+		esas2r_nvram_set_defaults(a);
+
+	/* update the caller's uncached memory area pointer */
+	*uncached_area = (void *)high;
+
+	/* initialize the allocated memory */
+	if (a->flags & AF_FIRST_INIT) {
+		memset(a->req_table, 0,
+		       (num_requests + num_ae_requests +
+			1) * sizeof(struct esas2r_request *));
+
+		esas2r_targ_db_initialize(a);
+
+		/* prime parts of the inbound list */
+		element =
+			(struct esas2r_inbound_list_source_entry *)a->
+			inbound_list_md.
+			virt_addr;
+
+		for (i = 0; i < a->list_size; i++) {
+			element->address = 0;
+			element->reserved = 0;
+			element->length = cpu_to_le32(HWILSE_INTERFACE_F0
+						      | (sizeof(union
+								atto_vda_req)
+							 /
+							 sizeof(u32)));
+			element++;
+		}
+
+		/* init the AE requests */
+		for (rq = a->first_ae_req, i = 0; i < num_ae_requests; rq++,
+		     i++) {
+			INIT_LIST_HEAD(&rq->req_list);
+			if (!alloc_vda_req(a, rq)) {
+				esas2r_hdebug(
+					"failed to allocate a VDA request!");
+				return false;
+			}
+
+			esas2r_rq_init_request(rq, a);
+
+			/* override the completion function */
+			rq->comp_cb = esas2r_ae_complete;
+		}
+	}
+
+	return true;
+}
+
+/* This code will verify that the chip is operational. */
+bool esas2r_check_adapter(struct esas2r_adapter *a)
+{
+	u32 starttime;
+	u32 doorbell;
+	u64 ppaddr;
+	u32 dw;
+
+	/*
+	 * if the chip reset detected flag is set, we can bypass a bunch of
+	 * stuff.
+	 */
+	if (a->flags & AF_CHPRST_DETECTED)
+		goto skip_chip_reset;
+
+	/*
+	 * BEFORE WE DO ANYTHING, disable the chip interrupts!  the boot driver
+	 * may have left them enabled or we may be recovering from a fault.
+	 */
+	esas2r_write_register_dword(a, MU_INT_MASK_OUT, ESAS2R_INT_DIS_MASK);
+	esas2r_flush_register_dword(a, MU_INT_MASK_OUT);
+
+	/*
+	 * wait for the firmware to become ready by forcing an interrupt and
+	 * waiting for a response.
+	 */
+	starttime = jiffies_to_msecs(jiffies);
+
+	while (true) {
+		esas2r_force_interrupt(a);
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell == 0xFFFFFFFF) {
+			/*
+			 * Give the firmware up to two seconds to enable
+			 * register access after a reset.
+			 */
+			if ((jiffies_to_msecs(jiffies) - starttime) > 2000)
+				return esas2r_set_degraded_mode(a,
+								"unable to access registers");
+		} else if (doorbell & DRBL_FORCE_INT) {
+			u32 ver = (doorbell & DRBL_FW_VER_MSK);
+
+			/*
+			 * This driver supports version 0 and version 1 of
+			 * the API
+			 */
+			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+						    doorbell);
+
+			if (ver == DRBL_FW_VER_0) {
+				esas2r_lock_set_flags(&a->flags,
+						      AF_LEGACY_SGE_MODE);
+
+				a->max_vdareq_size = 128;
+				a->build_sgl = esas2r_build_sg_list_sge;
+			} else if (ver == DRBL_FW_VER_1) {
+				esas2r_lock_clear_flags(&a->flags,
+							AF_LEGACY_SGE_MODE);
+
+				a->max_vdareq_size = 1024;
+				a->build_sgl = esas2r_build_sg_list_prd;
+			} else {
+				return esas2r_set_degraded_mode(a,
+								"unknown firmware version");
+			}
+			break;
+		}
+
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+		if ((jiffies_to_msecs(jiffies) - starttime) > 180000) {
+			esas2r_hdebug("FW ready TMO");
+			esas2r_bugon();
+
+			return esas2r_set_degraded_mode(a,
+							"firmware start has timed out");
+		}
+	}
+
+	/* purge any asynchronous events since we will repost them later */
+	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_DOWN);
+	starttime = jiffies_to_msecs(jiffies);
+
+	while (true) {
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell & DRBL_MSG_IFC_DOWN) {
+			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+						    doorbell);
+			break;
+		}
+
+		schedule_timeout_interruptible(msecs_to_jiffies(50));
+
+		if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
+			esas2r_hdebug("timeout waiting for interface down");
+			break;
+		}
+	}
+skip_chip_reset:
+	/*
+	 * first things first, before we go changing any of these registers
+	 * disable the communication lists.
+	 */
+	dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG);
+	dw &= ~MU_ILC_ENABLE;
+	esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw);
+	dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG);
+	dw &= ~MU_OLC_ENABLE;
+	esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw);
+
+	/* configure the communication list addresses */
+	ppaddr = a->inbound_list_md.phys_addr;
+	esas2r_write_register_dword(a, MU_IN_LIST_ADDR_LO,
+				    lower_32_bits(ppaddr));
+	esas2r_write_register_dword(a, MU_IN_LIST_ADDR_HI,
+				    upper_32_bits(ppaddr));
+	ppaddr = a->outbound_list_md.phys_addr;
+	esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_LO,
+				    lower_32_bits(ppaddr));
+	esas2r_write_register_dword(a, MU_OUT_LIST_ADDR_HI,
+				    upper_32_bits(ppaddr));
+	ppaddr = a->uncached_phys +
+		 ((u8 *)a->outbound_copy - a->uncached);
+	esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_LO,
+				    lower_32_bits(ppaddr));
+	esas2r_write_register_dword(a, MU_OUT_LIST_COPY_PTR_HI,
+				    upper_32_bits(ppaddr));
+
+	/* reset the read and write pointers */
+	*a->outbound_copy =
+		a->last_write =
+			a->last_read = a->list_size - 1;
+	esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
+	esas2r_write_register_dword(a, MU_IN_LIST_WRITE, MU_ILW_TOGGLE |
+				    a->last_write);
+	esas2r_write_register_dword(a, MU_OUT_LIST_COPY, MU_OLC_TOGGLE |
+				    a->last_write);
+	esas2r_write_register_dword(a, MU_IN_LIST_READ, MU_ILR_TOGGLE |
+				    a->last_write);
+	esas2r_write_register_dword(a, MU_OUT_LIST_WRITE,
+				    MU_OLW_TOGGLE | a->last_write);
+
+	/* configure the interface select fields */
+	dw = esas2r_read_register_dword(a, MU_IN_LIST_IFC_CONFIG);
+	dw &= ~(MU_ILIC_LIST | MU_ILIC_DEST);
+	esas2r_write_register_dword(a, MU_IN_LIST_IFC_CONFIG,
+				    (dw | MU_ILIC_LIST_F0 | MU_ILIC_DEST_DDR));
+	dw = esas2r_read_register_dword(a, MU_OUT_LIST_IFC_CONFIG);
+	dw &= ~(MU_OLIC_LIST | MU_OLIC_SOURCE);
+	esas2r_write_register_dword(a, MU_OUT_LIST_IFC_CONFIG,
+				    (dw | MU_OLIC_LIST_F0 |
+				     MU_OLIC_SOURCE_DDR));
+
+	/* finish configuring the communication lists */
+	dw = esas2r_read_register_dword(a, MU_IN_LIST_CONFIG);
+	dw &= ~(MU_ILC_ENTRY_MASK | MU_ILC_NUMBER_MASK);
+	dw |= MU_ILC_ENTRY_4_DW | MU_ILC_DYNAMIC_SRC
+	      | (a->list_size << MU_ILC_NUMBER_SHIFT);
+	esas2r_write_register_dword(a, MU_IN_LIST_CONFIG, dw);
+	dw = esas2r_read_register_dword(a, MU_OUT_LIST_CONFIG);
+	dw &= ~(MU_OLC_ENTRY_MASK | MU_OLC_NUMBER_MASK);
+	dw |= MU_OLC_ENTRY_4_DW | (a->list_size << MU_OLC_NUMBER_SHIFT);
+	esas2r_write_register_dword(a, MU_OUT_LIST_CONFIG, dw);
+
+	/*
+	 * notify the firmware that we're done setting up the communication
+	 * list registers.  wait here until the firmware is done configuring
+	 * its lists.  it will signal that it is done by enabling the lists.
+	 */
+	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_MSG_IFC_INIT);
+	starttime = jiffies_to_msecs(jiffies);
+
+	while (true) {
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell & DRBL_MSG_IFC_INIT) {
+			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+						    doorbell);
+			break;
+		}
+
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+		if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
+			esas2r_hdebug(
+				"timeout waiting for communication list init");
+			esas2r_bugon();
+			return esas2r_set_degraded_mode(a,
+							"timeout waiting for communication list init");
+		}
+	}
+
+	/*
+	 * flag whether the firmware supports the power down doorbell.  we
+	 * determine this by reading the inbound doorbell enable mask.
+	 */
+	doorbell = esas2r_read_register_dword(a, MU_DOORBELL_IN_ENB);
+	if (doorbell & DRBL_POWER_DOWN)
+		esas2r_lock_set_flags(&a->flags2, AF2_VDA_POWER_DOWN);
+	else
+		esas2r_lock_clear_flags(&a->flags2, AF2_VDA_POWER_DOWN);
+
+	/*
+	 * enable assertion of outbound queue and doorbell interrupts in the
+	 * main interrupt cause register.
+	 */
+	esas2r_write_register_dword(a, MU_OUT_LIST_INT_MASK, MU_OLIS_MASK);
+	esas2r_write_register_dword(a, MU_DOORBELL_OUT_ENB, DRBL_ENB_MASK);
+	return true;
+}
+
+/* Process the initialization message just completed and format the next one. */
+static bool esas2r_format_init_msg(struct esas2r_adapter *a,
+				   struct esas2r_request *rq)
+{
+	u32 msg = a->init_msg;
+	struct atto_vda_cfg_init *ci;
+
+	a->init_msg = 0;
+
+	switch (msg) {
+	case ESAS2R_INIT_MSG_START:
+	case ESAS2R_INIT_MSG_REINIT:
+	{
+		struct timeval now;
+		do_gettimeofday(&now);
+		esas2r_hdebug("CFG init");
+		esas2r_build_cfg_req(a,
+				     rq,
+				     VDA_CFG_INIT,
+				     0,
+				     NULL);
+		ci = (struct atto_vda_cfg_init *)&rq->vrq->cfg.data.init;
+		ci->sgl_page_size = sgl_page_size;
+		ci->epoch_time = now.tv_sec;
+		rq->flags |= RF_FAILURE_OK;
+		a->init_msg = ESAS2R_INIT_MSG_INIT;
+		break;
+	}
+
+	case ESAS2R_INIT_MSG_INIT:
+		if (rq->req_stat == RS_SUCCESS) {
+			u32 major;
+			u32 minor;
+
+			a->fw_version = le16_to_cpu(
+				rq->func_rsp.cfg_rsp.vda_version);
+			a->fw_build = rq->func_rsp.cfg_rsp.fw_build;
+			major = LOBYTE(rq->func_rsp.cfg_rsp.fw_release);
+			minor = HIBYTE(rq->func_rsp.cfg_rsp.fw_release);
+			a->fw_version += (major << 16) + (minor << 24);
+		} else {
+			esas2r_hdebug("FAILED");
+		}
+
+		/*
+		 * the 2.71 and earlier releases of R6xx firmware did not error
+		 * unsupported config requests correctly.
+		 */
+
+		if ((a->flags2 & AF2_THUNDERBOLT)
+		    || (be32_to_cpu(a->fw_version) >
+			be32_to_cpu(0x47020052))) {
+			esas2r_hdebug("CFG get init");
+			esas2r_build_cfg_req(a,
+					     rq,
+					     VDA_CFG_GET_INIT2,
+					     sizeof(struct atto_vda_cfg_init),
+					     NULL);
+
+			rq->vrq->cfg.sg_list_offset = offsetof(
+				struct atto_vda_cfg_req,
+				data.sge);
+			rq->vrq->cfg.data.prde.ctl_len =
+				cpu_to_le32(sizeof(struct atto_vda_cfg_init));
+			rq->vrq->cfg.data.prde.address = cpu_to_le64(
+				rq->vrq_md->phys_addr +
+				sizeof(union atto_vda_req));
+			rq->flags |= RF_FAILURE_OK;
+			a->init_msg = ESAS2R_INIT_MSG_GET_INIT;
+			break;
+		}
+
+	case ESAS2R_INIT_MSG_GET_INIT:
+		if (msg == ESAS2R_INIT_MSG_GET_INIT) {
+			ci = (struct atto_vda_cfg_init *)rq->data_buf;
+			if (rq->req_stat == RS_SUCCESS) {
+				a->num_targets_backend =
+					le32_to_cpu(ci->num_targets_backend);
+				a->ioctl_tunnel =
+					le32_to_cpu(ci->ioctl_tunnel);
+			} else {
+				esas2r_hdebug("FAILED");
+			}
+		}
+	/* fall through */
+
+	default:
+		rq->req_stat = RS_SUCCESS;
+		return false;
+	}
+	return true;
+}
+
+/*
+ * Perform initialization messages via the request queue.  Messages are
+ * performed with interrupts disabled.
+ */
+bool esas2r_init_msgs(struct esas2r_adapter *a)
+{
+	bool success = true;
+	struct esas2r_request *rq = &a->general_req;
+
+	esas2r_rq_init_request(rq, a);
+	rq->comp_cb = esas2r_dummy_complete;
+
+	if (a->init_msg == 0)
+		a->init_msg = ESAS2R_INIT_MSG_REINIT;
+
+	while (a->init_msg) {
+		if (esas2r_format_init_msg(a, rq)) {
+			unsigned long flags;
+			while (true) {
+				spin_lock_irqsave(&a->queue_lock, flags);
+				esas2r_start_vda_request(a, rq);
+				spin_unlock_irqrestore(&a->queue_lock, flags);
+				esas2r_wait_request(a, rq);
+				if (rq->req_stat != RS_PENDING)
+					break;
+			}
+		}
+
+		if (rq->req_stat == RS_SUCCESS
+		    || ((rq->flags & RF_FAILURE_OK)
+			&& rq->req_stat != RS_TIMEOUT))
+			continue;
+
+		esas2r_log(ESAS2R_LOG_CRIT, "init message %x failed (%x, %x)",
+			   a->init_msg, rq->req_stat, rq->flags);
+		a->init_msg = ESAS2R_INIT_MSG_START;
+		success = false;
+		break;
+	}
+
+	esas2r_rq_destroy_request(rq, a);
+	return success;
+}
+
+/* Initialize the adapter chip */
+bool esas2r_init_adapter_hw(struct esas2r_adapter *a, bool init_poll)
+{
+	bool rslt = false;
+	struct esas2r_request *rq;
+	u32 i;
+
+	if (a->flags & AF_DEGRADED_MODE)
+		goto exit;
+
+	if (!(a->flags & AF_NVR_VALID)) {
+		if (!esas2r_nvram_read_direct(a))
+			esas2r_log(ESAS2R_LOG_WARN,
+				   "invalid/missing NVRAM parameters");
+	}
+
+	if (!esas2r_init_msgs(a)) {
+		esas2r_set_degraded_mode(a, "init messages failed");
+		goto exit;
+	}
+
+	/* The firmware is ready. */
+	esas2r_lock_clear_flags(&a->flags, AF_DEGRADED_MODE);
+	esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+
+	/* Post all the async event requests */
+	for (i = 0, rq = a->first_ae_req; i < num_ae_requests; i++, rq++)
+		esas2r_start_ae_request(a, rq);
+
+	if (!a->flash_rev[0])
+		esas2r_read_flash_rev(a);
+
+	if (!a->image_type[0])
+		esas2r_read_image_type(a);
+
+	if (a->fw_version == 0)
+		a->fw_rev[0] = 0;
+	else
+		sprintf(a->fw_rev, "%1d.%02d",
+			(int)LOBYTE(HIWORD(a->fw_version)),
+			(int)HIBYTE(HIWORD(a->fw_version)));
+
+	esas2r_hdebug("firmware revision: %s", a->fw_rev);
+
+	if ((a->flags & AF_CHPRST_DETECTED)
+	    && (a->flags & AF_FIRST_INIT)) {
+		esas2r_enable_chip_interrupts(a);
+		return true;
+	}
+
+	/* initialize discovery */
+	esas2r_disc_initialize(a);
+
+	/*
+	 * wait for the device wait time to expire here if requested.  this is
+	 * usually requested during initial driver load and possibly when
+	 * resuming from a low power state.  deferred device waiting will use
+	 * interrupts.  chip reset recovery always defers device waiting to
+	 * avoid being in a TASKLET too long.
+	 */
+	if (init_poll) {
+		u32 currtime = a->disc_start_time;
+		u32 nexttick = 100;
+		u32 deltatime;
+
+		/*
+		 * Block Tasklets from getting scheduled and indicate this is
+		 * polled discovery.
+		 */
+		esas2r_lock_set_flags(&a->flags, AF_TASKLET_SCHEDULED);
+		esas2r_lock_set_flags(&a->flags, AF_DISC_POLLED);
+
+		/*
+		 * Temporarily bring the disable count to zero to enable
+		 * deferred processing.  Note that the count is already zero
+		 * after the first initialization.
+		 */
+		if (a->flags & AF_FIRST_INIT)
+			atomic_dec(&a->disable_cnt);
+
+		while (a->flags & AF_DISC_PENDING) {
+			schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+			/*
+			 * Determine the need for a timer tick based on the
+			 * delta time between this and the last iteration of
+			 * this loop.  We don't use the absolute time because
+			 * then we would have to worry about when nexttick
+			 * wraps and currtime hasn't yet.
+			 */
+			deltatime = jiffies_to_msecs(jiffies) - currtime;
+			currtime += deltatime;
+
+			/*
+			 * Process any waiting discovery as long as the chip is
+			 * up.  If a chip reset happens during initial polling,
+			 * we have to make sure the timer tick processes the
+			 * doorbell indicating the firmware is ready.
+			 */
+			if (!(a->flags & AF_CHPRST_PENDING))
+				esas2r_disc_check_for_work(a);
+
+			/* Simulate a timer tick. */
+			if (nexttick <= deltatime) {
+
+				/* Time for a timer tick */
+				nexttick += 100;
+				esas2r_timer_tick(a);
+			}
+
+			if (nexttick > deltatime)
+				nexttick -= deltatime;
+
+			/* Do any deferred processing */
+			if (esas2r_is_tasklet_pending(a))
+				esas2r_do_tasklet_tasks(a);
+
+		}
+
+		if (a->flags & AF_FIRST_INIT)
+			atomic_inc(&a->disable_cnt);
+
+		esas2r_lock_clear_flags(&a->flags, AF_DISC_POLLED);
+		esas2r_lock_clear_flags(&a->flags, AF_TASKLET_SCHEDULED);
+	}
+
+
+	esas2r_targ_db_report_changes(a);
+
+	/*
+	 * For cases where (a) the initialization messages processing may
+	 * handle an interrupt for a port event and a discovery is waiting, but
+	 * we are not waiting for devices, or (b) the device wait time has been
+	 * exhausted but there is still discovery pending, start any leftover
+	 * discovery in interrupt driven mode.
+	 */
+	esas2r_disc_start_waiting(a);
+
+	/* Enable chip interrupts */
+	a->int_mask = ESAS2R_INT_STS_MASK;
+	esas2r_enable_chip_interrupts(a);
+	esas2r_enable_heartbeat(a);
+	rslt = true;
+
+exit:
+	/*
+	 * Regardless of whether initialization was successful, certain things
+	 * need to get done before we exit.
+	 */
+
+	if ((a->flags & AF_CHPRST_DETECTED)
+	    && (a->flags & AF_FIRST_INIT)) {
+		/*
+		 * Reinitialization was performed during the first
+		 * initialization.  Only clear the chip reset flag so the
+		 * original device polling is not cancelled.
+		 */
+		if (!rslt)
+			esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+	} else {
+		/* First initialization or a subsequent re-init is complete. */
+		if (!rslt) {
+			esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+			esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
+		}
+
+
+		/* Enable deferred processing after the first initialization. */
+		if (a->flags & AF_FIRST_INIT) {
+			esas2r_lock_clear_flags(&a->flags, AF_FIRST_INIT);
+
+			if (atomic_dec_return(&a->disable_cnt) == 0)
+				esas2r_do_deferred_processes(a);
+		}
+	}
+
+	return rslt;
+}
+
+void esas2r_reset_adapter(struct esas2r_adapter *a)
+{
+	esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
+	esas2r_local_reset_adapter(a);
+	esas2r_schedule_tasklet(a);
+}
+
+void esas2r_reset_chip(struct esas2r_adapter *a)
+{
+	if (!esas2r_is_adapter_present(a))
+		return;
+
+	/*
+	 * Before we reset the chip, save off the VDA core dump.  The VDA core
+	 * dump is located in the upper 512KB of the onchip SRAM.  Make sure
+	 * to not overwrite a previous crash that was saved.
+	 */
+	if ((a->flags2 & AF2_COREDUMP_AVAIL)
+	    && !(a->flags2 & AF2_COREDUMP_SAVED)
+	    && a->fw_coredump_buff) {
+		esas2r_read_mem_block(a,
+				      a->fw_coredump_buff,
+				      MW_DATA_ADDR_SRAM + 0x80000,
+				      ESAS2R_FWCOREDUMP_SZ);
+
+		esas2r_lock_set_flags(&a->flags2, AF2_COREDUMP_SAVED);
+	}
+
+	esas2r_lock_clear_flags(&a->flags2, AF2_COREDUMP_AVAIL);
+
+	/* Reset the chip */
+	if (a->pcid->revision == MVR_FREY_B2)
+		esas2r_write_register_dword(a, MU_CTL_STATUS_IN_B2,
+					    MU_CTL_IN_FULL_RST2);
+	else
+		esas2r_write_register_dword(a, MU_CTL_STATUS_IN,
+					    MU_CTL_IN_FULL_RST);
+
+
+	/* Stall a little while to let the reset condition clear */
+	mdelay(10);
+}
+
+static void esas2r_power_down_notify_firmware(struct esas2r_adapter *a)
+{
+	u32 starttime;
+	u32 doorbell;
+
+	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_POWER_DOWN);
+	starttime = jiffies_to_msecs(jiffies);
+
+	while (true) {
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell & DRBL_POWER_DOWN) {
+			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+						    doorbell);
+			break;
+		}
+
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+		if ((jiffies_to_msecs(jiffies) - starttime) > 30000) {
+			esas2r_hdebug("Timeout waiting for power down");
+			break;
+		}
+	}
+}
+
+/*
+ * Perform power management processing including managing device states, adapter
+ * states, interrupts, and I/O.
+ */
+void esas2r_power_down(struct esas2r_adapter *a)
+{
+	esas2r_lock_set_flags(&a->flags, AF_POWER_MGT);
+	esas2r_lock_set_flags(&a->flags, AF_POWER_DOWN);
+
+	if (!(a->flags & AF_DEGRADED_MODE)) {
+		u32 starttime;
+		u32 doorbell;
+
+		/*
+		 * We are currently running OK and will be reinitializing later.
+		 * increment the disable count to coordinate with
+		 * esas2r_init_adapter.  We don't have to do this in degraded
+		 * mode since we never enabled interrupts in the first place.
+		 */
+		esas2r_disable_chip_interrupts(a);
+		esas2r_disable_heartbeat(a);
+
+		/* wait for any VDA activity to clear before continuing */
+		esas2r_write_register_dword(a, MU_DOORBELL_IN,
+					    DRBL_MSG_IFC_DOWN);
+		starttime = jiffies_to_msecs(jiffies);
+
+		while (true) {
+			doorbell =
+				esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+			if (doorbell & DRBL_MSG_IFC_DOWN) {
+				esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+							    doorbell);
+				break;
+			}
+
+			schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+			if ((jiffies_to_msecs(jiffies) - starttime) > 3000) {
+				esas2r_hdebug(
+					"timeout waiting for interface down");
+				break;
+			}
+		}
+
+		/*
+		 * For versions of firmware that support it tell them the driver
+		 * is powering down.
+		 */
+		if (a->flags2 & AF2_VDA_POWER_DOWN)
+			esas2r_power_down_notify_firmware(a);
+	}
+
+	/* Suspend I/O processing. */
+	esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
+	esas2r_lock_set_flags(&a->flags, AF_DISC_PENDING);
+	esas2r_lock_set_flags(&a->flags, AF_CHPRST_PENDING);
+
+	esas2r_process_adapter_reset(a);
+
+	/* Remove devices now that I/O is cleaned up. */
+	a->prev_dev_cnt = esas2r_targ_db_get_tgt_cnt(a);
+	esas2r_targ_db_remove_all(a, false);
+}
+
+/*
+ * Perform power management processing including managing device states, adapter
+ * states, interrupts, and I/O.
+ */
+bool esas2r_power_up(struct esas2r_adapter *a, bool init_poll)
+{
+	bool ret;
+
+	esas2r_lock_clear_flags(&a->flags, AF_POWER_DOWN);
+	esas2r_init_pci_cfg_space(a);
+	esas2r_lock_set_flags(&a->flags, AF_FIRST_INIT);
+	atomic_inc(&a->disable_cnt);
+
+	/* reinitialize the adapter */
+	ret = esas2r_check_adapter(a);
+	if (!esas2r_init_adapter_hw(a, init_poll))
+		ret = false;
+
+	/* send the reset asynchronous event */
+	esas2r_send_reset_ae(a, true);
+
+	/* clear this flag after initialization. */
+	esas2r_lock_clear_flags(&a->flags, AF_POWER_MGT);
+	return ret;
+}
+
+bool esas2r_is_adapter_present(struct esas2r_adapter *a)
+{
+	if (a->flags & AF_NOT_PRESENT)
+		return false;
+
+	if (esas2r_read_register_dword(a, MU_DOORBELL_OUT) == 0xFFFFFFFF) {
+		esas2r_lock_set_flags(&a->flags, AF_NOT_PRESENT);
+
+		return false;
+	}
+	return true;
+}
+
+const char *esas2r_get_model_name(struct esas2r_adapter *a)
+{
+	switch (a->pcid->subsystem_device) {
+	case ATTO_ESAS_R680:
+		return "ATTO ExpressSAS R680";
+
+	case ATTO_ESAS_R608:
+		return "ATTO ExpressSAS R608";
+
+	case ATTO_ESAS_R60F:
+		return "ATTO ExpressSAS R60F";
+
+	case ATTO_ESAS_R6F0:
+		return "ATTO ExpressSAS R6F0";
+
+	case ATTO_ESAS_R644:
+		return "ATTO ExpressSAS R644";
+
+	case ATTO_ESAS_R648:
+		return "ATTO ExpressSAS R648";
+
+	case ATTO_TSSC_3808:
+		return "ATTO ThunderStream SC 3808D";
+
+	case ATTO_TSSC_3808E:
+		return "ATTO ThunderStream SC 3808E";
+
+	case ATTO_TLSH_1068:
+		return "ATTO ThunderLink SH 1068";
+	}
+
+	return "ATTO SAS Controller";
+}
+
+const char *esas2r_get_model_name_short(struct esas2r_adapter *a)
+{
+	switch (a->pcid->subsystem_device) {
+	case ATTO_ESAS_R680:
+		return "R680";
+
+	case ATTO_ESAS_R608:
+		return "R608";
+
+	case ATTO_ESAS_R60F:
+		return "R60F";
+
+	case ATTO_ESAS_R6F0:
+		return "R6F0";
+
+	case ATTO_ESAS_R644:
+		return "R644";
+
+	case ATTO_ESAS_R648:
+		return "R648";
+
+	case ATTO_TSSC_3808:
+		return "SC 3808D";
+
+	case ATTO_TSSC_3808E:
+		return "SC 3808E";
+
+	case ATTO_TLSH_1068:
+		return "SH 1068";
+	}
+
+	return "unknown";
+}
diff --git a/drivers/scsi/esas2r/esas2r_int.c b/drivers/scsi/esas2r/esas2r_int.c
new file mode 100644
index 0000000..c2d4ff5
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_int.c
@@ -0,0 +1,941 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_int.c
+ *      esas2r interrupt handling
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.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; 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.
+ *
+ *  NO WARRANTY
+ *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ *  solely responsible for determining the appropriateness of using and
+ *  distributing the Program and assumes all risks associated with its
+ *  exercise of rights under this Agreement, including but not limited to
+ *  the risks and costs of program errors, damage to or loss of data,
+ *  programs or equipment, and unavailability or interruption of operations.
+ *
+ *  DISCLAIMER OF LIABILITY
+ *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ *  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 "esas2r.h"
+
+/* Local function prototypes */
+static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell);
+static void esas2r_get_outbound_responses(struct esas2r_adapter *a);
+static void esas2r_process_bus_reset(struct esas2r_adapter *a);
+
+/*
+ * Poll the adapter for interrupts and service them.
+ * This function handles both legacy interrupts and MSI.
+ */
+void esas2r_polled_interrupt(struct esas2r_adapter *a)
+{
+	u32 intstat;
+	u32 doorbell;
+
+	esas2r_disable_chip_interrupts(a);
+
+	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+	if (intstat & MU_INTSTAT_POST_OUT) {
+		/* clear the interrupt */
+
+		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
+					    MU_OLIS_INT);
+		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
+
+		esas2r_get_outbound_responses(a);
+	}
+
+	if (intstat & MU_INTSTAT_DRBL) {
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell != 0)
+			esas2r_doorbell_interrupt(a, doorbell);
+	}
+
+	esas2r_enable_chip_interrupts(a);
+
+	if (atomic_read(&a->disable_cnt) == 0)
+		esas2r_do_deferred_processes(a);
+}
+
+/*
+ * Legacy and MSI interrupt handlers.  Note that the legacy interrupt handler
+ * schedules a TASKLET to process events, whereas the MSI handler just
+ * processes interrupt events directly.
+ */
+irqreturn_t esas2r_interrupt(int irq, void *dev_id)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
+
+	if (!esas2r_adapter_interrupt_pending(a))
+		return IRQ_NONE;
+
+	esas2r_lock_set_flags(&a->flags2, AF2_INT_PENDING);
+	esas2r_schedule_tasklet(a);
+
+	return IRQ_HANDLED;
+}
+
+void esas2r_adapter_interrupt(struct esas2r_adapter *a)
+{
+	u32 doorbell;
+
+	if (likely(a->int_stat & MU_INTSTAT_POST_OUT)) {
+		/* clear the interrupt */
+		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
+					    MU_OLIS_INT);
+		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
+		esas2r_get_outbound_responses(a);
+	}
+
+	if (unlikely(a->int_stat & MU_INTSTAT_DRBL)) {
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell != 0)
+			esas2r_doorbell_interrupt(a, doorbell);
+	}
+
+	a->int_mask = ESAS2R_INT_STS_MASK;
+
+	esas2r_enable_chip_interrupts(a);
+
+	if (likely(atomic_read(&a->disable_cnt) == 0))
+		esas2r_do_deferred_processes(a);
+}
+
+irqreturn_t esas2r_msi_interrupt(int irq, void *dev_id)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)dev_id;
+	u32 intstat;
+	u32 doorbell;
+
+	intstat = esas2r_read_register_dword(a, MU_INT_STATUS_OUT);
+
+	if (likely(intstat & MU_INTSTAT_POST_OUT)) {
+		/* clear the interrupt */
+
+		esas2r_write_register_dword(a, MU_OUT_LIST_INT_STAT,
+					    MU_OLIS_INT);
+		esas2r_flush_register_dword(a, MU_OUT_LIST_INT_STAT);
+
+		esas2r_get_outbound_responses(a);
+	}
+
+	if (unlikely(intstat & MU_INTSTAT_DRBL)) {
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell != 0)
+			esas2r_doorbell_interrupt(a, doorbell);
+	}
+
+	/*
+	 * Work around a chip bug and force a new MSI to be sent if one is
+	 * still pending.
+	 */
+	esas2r_disable_chip_interrupts(a);
+	esas2r_enable_chip_interrupts(a);
+
+	if (likely(atomic_read(&a->disable_cnt) == 0))
+		esas2r_do_deferred_processes(a);
+
+	esas2r_do_tasklet_tasks(a);
+
+	return 1;
+}
+
+
+
+static void esas2r_handle_outbound_rsp_err(struct esas2r_adapter *a,
+					   struct esas2r_request *rq,
+					   struct atto_vda_ob_rsp *rsp)
+{
+
+	/*
+	 * For I/O requests, only copy the response if an error
+	 * occurred and setup a callback to do error processing.
+	 */
+	if (unlikely(rq->req_stat != RS_SUCCESS)) {
+		memcpy(&rq->func_rsp, &rsp->func_rsp, sizeof(rsp->func_rsp));
+
+		if (rq->req_stat == RS_ABORTED) {
+			if (rq->timeout > RQ_MAX_TIMEOUT)
+				rq->req_stat = RS_TIMEOUT;
+		} else if (rq->req_stat == RS_SCSI_ERROR) {
+			u8 scsistatus = rq->func_rsp.scsi_rsp.scsi_stat;
+
+			esas2r_trace("scsistatus: %x", scsistatus);
+
+			/* Any of these are a good result. */
+			if (scsistatus == SAM_STAT_GOOD || scsistatus ==
+			    SAM_STAT_CONDITION_MET || scsistatus ==
+			    SAM_STAT_INTERMEDIATE || scsistatus ==
+			    SAM_STAT_INTERMEDIATE_CONDITION_MET) {
+				rq->req_stat = RS_SUCCESS;
+				rq->func_rsp.scsi_rsp.scsi_stat =
+					SAM_STAT_GOOD;
+			}
+		}
+	}
+}
+
+static void esas2r_get_outbound_responses(struct esas2r_adapter *a)
+{
+	struct atto_vda_ob_rsp *rsp;
+	u32 rspput_ptr;
+	u32 rspget_ptr;
+	struct esas2r_request *rq;
+	u32 handle;
+	unsigned long flags;
+
+	LIST_HEAD(comp_list);
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	/* Get the outbound limit and pointers */
+	rspput_ptr = le32_to_cpu(*a->outbound_copy) & MU_OLC_WRT_PTR;
+	rspget_ptr = a->last_read;
+
+	esas2r_trace("rspput_ptr: %x, rspget_ptr: %x", rspput_ptr, rspget_ptr);
+
+	/* If we don't have anything to process, get out */
+	if (unlikely(rspget_ptr == rspput_ptr)) {
+		spin_unlock_irqrestore(&a->queue_lock, flags);
+		esas2r_trace_exit();
+		return;
+	}
+
+	/* Make sure the firmware is healthy */
+	if (unlikely(rspput_ptr >= a->list_size)) {
+		spin_unlock_irqrestore(&a->queue_lock, flags);
+		esas2r_bugon();
+		esas2r_local_reset_adapter(a);
+		esas2r_trace_exit();
+		return;
+	}
+
+	do {
+		rspget_ptr++;
+
+		if (rspget_ptr >= a->list_size)
+			rspget_ptr = 0;
+
+		rsp = (struct atto_vda_ob_rsp *)a->outbound_list_md.virt_addr
+		      + rspget_ptr;
+
+		handle = rsp->handle;
+
+		/* Verify the handle range */
+		if (unlikely(LOWORD(handle) == 0
+			     || LOWORD(handle) > num_requests +
+			     num_ae_requests + 1)) {
+			esas2r_bugon();
+			continue;
+		}
+
+		/* Get the request for this handle */
+		rq = a->req_table[LOWORD(handle)];
+
+		if (unlikely(rq == NULL || rq->vrq->scsi.handle != handle)) {
+			esas2r_bugon();
+			continue;
+		}
+
+		list_del(&rq->req_list);
+
+		/* Get the completion status */
+		rq->req_stat = rsp->req_stat;
+
+		esas2r_trace("handle: %x", handle);
+		esas2r_trace("rq: %p", rq);
+		esas2r_trace("req_status: %x", rq->req_stat);
+
+		if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
+			esas2r_handle_outbound_rsp_err(a, rq, rsp);
+		} else {
+			/*
+			 * Copy the outbound completion struct for non-I/O
+			 * requests.
+			 */
+			memcpy(&rq->func_rsp, &rsp->func_rsp,
+			       sizeof(rsp->func_rsp));
+		}
+
+		/* Queue the request for completion. */
+		list_add_tail(&rq->comp_list, &comp_list);
+
+	} while (rspget_ptr != rspput_ptr);
+
+	a->last_read = rspget_ptr;
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+
+	esas2r_comp_list_drain(a, &comp_list);
+	esas2r_trace_exit();
+}
+
+/*
+ * Perform all deferred processes for the adapter.  Deferred
+ * processes can only be done while the current interrupt
+ * disable_cnt for the adapter is zero.
+ */
+void esas2r_do_deferred_processes(struct esas2r_adapter *a)
+{
+	int startreqs = 2;
+	struct esas2r_request *rq;
+	unsigned long flags;
+
+	/*
+	 * startreqs is used to control starting requests
+	 * that are on the deferred queue
+	 *  = 0 - do not start any requests
+	 *  = 1 - can start discovery requests
+	 *  = 2 - can start any request
+	 */
+
+	if (a->flags & (AF_CHPRST_PENDING | AF_FLASHING))
+		startreqs = 0;
+	else if (a->flags & AF_DISC_PENDING)
+		startreqs = 1;
+
+	atomic_inc(&a->disable_cnt);
+
+	/* Clear off the completed list to be processed later. */
+
+	if (esas2r_is_tasklet_pending(a)) {
+		esas2r_schedule_tasklet(a);
+
+		startreqs = 0;
+	}
+
+	/*
+	 * If we can start requests then traverse the defer queue
+	 * looking for requests to start or complete
+	 */
+	if (startreqs && !list_empty(&a->defer_list)) {
+		LIST_HEAD(comp_list);
+		struct list_head *element, *next;
+
+		spin_lock_irqsave(&a->queue_lock, flags);
+
+		list_for_each_safe(element, next, &a->defer_list) {
+			rq = list_entry(element, struct esas2r_request,
+					req_list);
+
+			if (rq->req_stat != RS_PENDING) {
+				list_del(element);
+				list_add_tail(&rq->comp_list, &comp_list);
+			}
+			/*
+			 * Process discovery and OS requests separately.  We
+			 * can't hold up discovery requests when discovery is
+			 * pending.  In general, there may be different sets of
+			 * conditions for starting different types of requests.
+			 */
+			else if (rq->req_type == RT_DISC_REQ) {
+				list_del(element);
+				esas2r_disc_local_start_request(a, rq);
+			} else if (startreqs == 2) {
+				list_del(element);
+				esas2r_local_start_request(a, rq);
+
+				/*
+				 * Flashing could have been set by last local
+				 * start
+				 */
+				if (a->flags & AF_FLASHING)
+					break;
+			}
+		}
+
+		spin_unlock_irqrestore(&a->queue_lock, flags);
+		esas2r_comp_list_drain(a, &comp_list);
+	}
+
+	atomic_dec(&a->disable_cnt);
+}
+
+/*
+ * Process an adapter reset (or one that is about to happen)
+ * by making sure all outstanding requests are completed that
+ * haven't been already.
+ */
+void esas2r_process_adapter_reset(struct esas2r_adapter *a)
+{
+	struct esas2r_request *rq = &a->general_req;
+	unsigned long flags;
+	struct esas2r_disc_context *dc;
+
+	LIST_HEAD(comp_list);
+	struct list_head *element;
+
+	esas2r_trace_enter();
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	/* abort the active discovery, if any.   */
+
+	if (rq->interrupt_cx) {
+		dc = (struct esas2r_disc_context *)rq->interrupt_cx;
+
+		dc->disc_evt = 0;
+
+		esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
+	}
+
+	/*
+	 * just clear the interrupt callback for now.  it will be dequeued if
+	 * and when we find it on the active queue and we don't want the
+	 * callback called.  also set the dummy completion callback in case we
+	 * were doing an I/O request.
+	 */
+
+	rq->interrupt_cx = NULL;
+	rq->interrupt_cb = NULL;
+
+	rq->comp_cb = esas2r_dummy_complete;
+
+	/* Reset the read and write pointers */
+
+	*a->outbound_copy =
+		a->last_write =
+			a->last_read = a->list_size - 1;
+
+	esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
+
+	/* Kill all the requests on the active list */
+	list_for_each(element, &a->defer_list) {
+		rq = list_entry(element, struct esas2r_request, req_list);
+
+		if (rq->req_stat == RS_STARTED)
+			if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
+				list_add_tail(&rq->comp_list, &comp_list);
+	}
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+	esas2r_comp_list_drain(a, &comp_list);
+	esas2r_process_bus_reset(a);
+	esas2r_trace_exit();
+}
+
+static void esas2r_process_bus_reset(struct esas2r_adapter *a)
+{
+	struct esas2r_request *rq;
+	struct list_head *element;
+	unsigned long flags;
+
+	LIST_HEAD(comp_list);
+
+	esas2r_trace_enter();
+
+	esas2r_hdebug("reset detected");
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	/* kill all the requests on the deferred queue */
+	list_for_each(element, &a->defer_list) {
+		rq = list_entry(element, struct esas2r_request, req_list);
+		if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
+			list_add_tail(&rq->comp_list, &comp_list);
+	}
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+
+	esas2r_comp_list_drain(a, &comp_list);
+
+	if (atomic_read(&a->disable_cnt) == 0)
+		esas2r_do_deferred_processes(a);
+
+	esas2r_lock_clear_flags(&a->flags, AF_OS_RESET);
+
+	esas2r_trace_exit();
+}
+
+static void esas2r_chip_rst_needed_during_tasklet(struct esas2r_adapter *a)
+{
+
+	esas2r_lock_clear_flags(&a->flags, AF_CHPRST_NEEDED);
+	esas2r_lock_clear_flags(&a->flags, AF_BUSRST_NEEDED);
+	esas2r_lock_clear_flags(&a->flags, AF_BUSRST_DETECTED);
+	esas2r_lock_clear_flags(&a->flags, AF_BUSRST_PENDING);
+	/*
+	 * Make sure we don't get attempt more than 3 resets
+	 * when the uptime between resets does not exceed one
+	 * minute.  This will stop any situation where there is
+	 * really something wrong with the hardware.  The way
+	 * this works is that we start with uptime ticks at 0.
+	 * Each time we do a reset, we add 20 seconds worth to
+	 * the count.  Each time a timer tick occurs, as long
+	 * as a chip reset is not pending, we decrement the
+	 * tick count.  If the uptime ticks ever gets to 60
+	 * seconds worth, we disable the adapter from that
+	 * point forward.  Three strikes, you're out.
+	 */
+	if (!esas2r_is_adapter_present(a) || (a->chip_uptime >=
+					      ESAS2R_CHP_UPTIME_MAX)) {
+		esas2r_hdebug("*** adapter disabled ***");
+
+		/*
+		 * Ok, some kind of hard failure.  Make sure we
+		 * exit this loop with chip interrupts
+		 * permanently disabled so we don't lock up the
+		 * entire system.  Also flag degraded mode to
+		 * prevent the heartbeat from trying to recover.
+		 */
+
+		esas2r_lock_set_flags(&a->flags, AF_DEGRADED_MODE);
+		esas2r_lock_set_flags(&a->flags, AF_DISABLED);
+		esas2r_lock_clear_flags(&a->flags, AF_CHPRST_PENDING);
+		esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
+
+		esas2r_disable_chip_interrupts(a);
+		a->int_mask = 0;
+		esas2r_process_adapter_reset(a);
+
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "Adapter disabled because of hardware failure");
+	} else {
+		u32 flags =
+			esas2r_lock_set_flags(&a->flags, AF_CHPRST_STARTED);
+
+		if (!(flags & AF_CHPRST_STARTED))
+			/*
+			 * Only disable interrupts if this is
+			 * the first reset attempt.
+			 */
+			esas2r_disable_chip_interrupts(a);
+
+		if ((a->flags & AF_POWER_MGT) && !(a->flags & AF_FIRST_INIT) &&
+		    !(flags & AF_CHPRST_STARTED)) {
+			/*
+			 * Don't reset the chip on the first
+			 * deferred power up attempt.
+			 */
+		} else {
+			esas2r_hdebug("*** resetting chip ***");
+			esas2r_reset_chip(a);
+		}
+
+		/* Kick off the reinitialization */
+		a->chip_uptime += ESAS2R_CHP_UPTIME_CNT;
+		a->chip_init_time = jiffies_to_msecs(jiffies);
+		if (!(a->flags & AF_POWER_MGT)) {
+			esas2r_process_adapter_reset(a);
+
+			if (!(flags & AF_CHPRST_STARTED)) {
+				/* Remove devices now that I/O is cleaned up. */
+				a->prev_dev_cnt =
+					esas2r_targ_db_get_tgt_cnt(a);
+				esas2r_targ_db_remove_all(a, false);
+			}
+		}
+
+		a->int_mask = 0;
+	}
+}
+
+static void esas2r_handle_chip_rst_during_tasklet(struct esas2r_adapter *a)
+{
+	while (a->flags & AF_CHPRST_DETECTED) {
+		/*
+		 * Balance the enable in esas2r_initadapter_hw.
+		 * Esas2r_power_down already took care of it for power
+		 * management.
+		 */
+		if (!(a->flags & AF_DEGRADED_MODE) && !(a->flags &
+							AF_POWER_MGT))
+			esas2r_disable_chip_interrupts(a);
+
+		/* Reinitialize the chip. */
+		esas2r_check_adapter(a);
+		esas2r_init_adapter_hw(a, 0);
+
+		if (a->flags & AF_CHPRST_NEEDED)
+			break;
+
+		if (a->flags & AF_POWER_MGT) {
+			/* Recovery from power management. */
+			if (a->flags & AF_FIRST_INIT) {
+				/* Chip reset during normal power up */
+				esas2r_log(ESAS2R_LOG_CRIT,
+					   "The firmware was reset during a normal power-up sequence");
+			} else {
+				/* Deferred power up complete. */
+				esas2r_lock_clear_flags(&a->flags,
+							AF_POWER_MGT);
+				esas2r_send_reset_ae(a, true);
+			}
+		} else {
+			/* Recovery from online chip reset. */
+			if (a->flags & AF_FIRST_INIT) {
+				/* Chip reset during driver load */
+			} else {
+				/* Chip reset after driver load */
+				esas2r_send_reset_ae(a, false);
+			}
+
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "Recovering from a chip reset while the chip was online");
+		}
+
+		esas2r_lock_clear_flags(&a->flags, AF_CHPRST_STARTED);
+		esas2r_enable_chip_interrupts(a);
+
+		/*
+		 * Clear this flag last!  this indicates that the chip has been
+		 * reset already during initialization.
+		 */
+		esas2r_lock_clear_flags(&a->flags, AF_CHPRST_DETECTED);
+	}
+}
+
+
+/* Perform deferred tasks when chip interrupts are disabled */
+void esas2r_do_tasklet_tasks(struct esas2r_adapter *a)
+{
+	if (a->flags & (AF_CHPRST_NEEDED | AF_CHPRST_DETECTED)) {
+		if (a->flags & AF_CHPRST_NEEDED)
+			esas2r_chip_rst_needed_during_tasklet(a);
+
+		esas2r_handle_chip_rst_during_tasklet(a);
+	}
+
+	if (a->flags & AF_BUSRST_NEEDED) {
+		esas2r_hdebug("hard resetting bus");
+
+		esas2r_lock_clear_flags(&a->flags, AF_BUSRST_NEEDED);
+
+		if (a->flags & AF_FLASHING)
+			esas2r_lock_set_flags(&a->flags, AF_BUSRST_DETECTED);
+		else
+			esas2r_write_register_dword(a, MU_DOORBELL_IN,
+						    DRBL_RESET_BUS);
+	}
+
+	if (a->flags & AF_BUSRST_DETECTED) {
+		esas2r_process_bus_reset(a);
+
+		esas2r_log_dev(ESAS2R_LOG_WARN,
+			       &(a->host->shost_gendev),
+			       "scsi_report_bus_reset() called");
+
+		scsi_report_bus_reset(a->host, 0);
+
+		esas2r_lock_clear_flags(&a->flags, AF_BUSRST_DETECTED);
+		esas2r_lock_clear_flags(&a->flags, AF_BUSRST_PENDING);
+
+		esas2r_log(ESAS2R_LOG_WARN, "Bus reset complete");
+	}
+
+	if (a->flags & AF_PORT_CHANGE) {
+		esas2r_lock_clear_flags(&a->flags, AF_PORT_CHANGE);
+
+		esas2r_targ_db_report_changes(a);
+	}
+
+	if (atomic_read(&a->disable_cnt) == 0)
+		esas2r_do_deferred_processes(a);
+}
+
+static void esas2r_doorbell_interrupt(struct esas2r_adapter *a, u32 doorbell)
+{
+	if (!(doorbell & DRBL_FORCE_INT)) {
+		esas2r_trace_enter();
+		esas2r_trace("doorbell: %x", doorbell);
+	}
+
+	/* First clear the doorbell bits */
+	esas2r_write_register_dword(a, MU_DOORBELL_OUT, doorbell);
+
+	if (doorbell & DRBL_RESET_BUS)
+		esas2r_lock_set_flags(&a->flags, AF_BUSRST_DETECTED);
+
+	if (doorbell & DRBL_FORCE_INT)
+		esas2r_lock_clear_flags(&a->flags, AF_HEARTBEAT);
+
+	if (doorbell & DRBL_PANIC_REASON_MASK) {
+		esas2r_hdebug("*** Firmware Panic ***");
+		esas2r_log(ESAS2R_LOG_CRIT, "The firmware has panicked");
+	}
+
+	if (doorbell & DRBL_FW_RESET) {
+		esas2r_lock_set_flags(&a->flags2, AF2_COREDUMP_AVAIL);
+		esas2r_local_reset_adapter(a);
+	}
+
+	if (!(doorbell & DRBL_FORCE_INT))
+		esas2r_trace_exit();
+}
+
+void esas2r_force_interrupt(struct esas2r_adapter *a)
+{
+	esas2r_write_register_dword(a, MU_DOORBELL_IN, DRBL_FORCE_INT |
+				    DRBL_DRV_VER);
+}
+
+
+static void esas2r_lun_event(struct esas2r_adapter *a, union atto_vda_ae *ae,
+			     u16 target, u32 length)
+{
+	struct esas2r_target *t = a->targetdb + target;
+	u32 cplen = length;
+	unsigned long flags;
+
+	if (cplen > sizeof(t->lu_event))
+		cplen = sizeof(t->lu_event);
+
+	esas2r_trace("ae->lu.dwevent: %x", ae->lu.dwevent);
+	esas2r_trace("ae->lu.bystate: %x", ae->lu.bystate);
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+
+	t->new_target_state = TS_INVALID;
+
+	if (ae->lu.dwevent  & VDAAE_LU_LOST) {
+		t->new_target_state = TS_NOT_PRESENT;
+	} else {
+		switch (ae->lu.bystate) {
+		case VDAAE_LU_NOT_PRESENT:
+		case VDAAE_LU_OFFLINE:
+		case VDAAE_LU_DELETED:
+		case VDAAE_LU_FACTORY_DISABLED:
+			t->new_target_state = TS_NOT_PRESENT;
+			break;
+
+		case VDAAE_LU_ONLINE:
+		case VDAAE_LU_DEGRADED:
+			t->new_target_state = TS_PRESENT;
+			break;
+		}
+	}
+
+	if (t->new_target_state != TS_INVALID) {
+		memcpy(&t->lu_event, &ae->lu, cplen);
+
+		esas2r_disc_queue_event(a, DCDE_DEV_CHANGE);
+	}
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+}
+
+
+
+void esas2r_ae_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+	union atto_vda_ae *ae =
+		(union atto_vda_ae *)rq->vda_rsp_data->ae_data.event_data;
+	u32 length = le32_to_cpu(rq->func_rsp.ae_rsp.length);
+	union atto_vda_ae *last =
+		(union atto_vda_ae *)(rq->vda_rsp_data->ae_data.event_data
+				      + length);
+
+	esas2r_trace_enter();
+	esas2r_trace("length: %d", length);
+
+	if (length > sizeof(struct atto_vda_ae_data)
+	    || (length & 3) != 0
+	    || length == 0) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "The AE request response length (%p) is too long: %d",
+			   rq, length);
+
+		esas2r_hdebug("aereq->length (0x%x) too long", length);
+		esas2r_bugon();
+
+		last = ae;
+	}
+
+	while (ae < last) {
+		u16 target;
+
+		esas2r_trace("ae: %p", ae);
+		esas2r_trace("ae->hdr: %p", &(ae->hdr));
+
+		length = ae->hdr.bylength;
+
+		if (length > (u32)((u8 *)last - (u8 *)ae)
+		    || (length & 3) != 0
+		    || length == 0) {
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "the async event length is invalid (%p): %d",
+				   ae, length);
+
+			esas2r_hdebug("ae->hdr.length (0x%x) invalid", length);
+			esas2r_bugon();
+
+			break;
+		}
+
+		esas2r_nuxi_ae_data(ae);
+
+		esas2r_queue_fw_event(a, fw_event_vda_ae, ae,
+				      sizeof(union atto_vda_ae));
+
+		switch (ae->hdr.bytype) {
+		case VDAAE_HDR_TYPE_RAID:
+
+			if (ae->raid.dwflags & (VDAAE_GROUP_STATE
+						| VDAAE_RBLD_STATE
+						| VDAAE_MEMBER_CHG
+						| VDAAE_PART_CHG)) {
+				esas2r_log(ESAS2R_LOG_INFO,
+					   "RAID event received - name:%s rebuild_state:%d group_state:%d",
+					   ae->raid.acname,
+					   ae->raid.byrebuild_state,
+					   ae->raid.bygroup_state);
+			}
+
+			break;
+
+		case VDAAE_HDR_TYPE_LU:
+			esas2r_log(ESAS2R_LOG_INFO,
+				   "LUN event received: event:%d target_id:%d LUN:%d state:%d",
+				   ae->lu.dwevent,
+				   ae->lu.id.tgtlun.wtarget_id,
+				   ae->lu.id.tgtlun.bylun,
+				   ae->lu.bystate);
+
+			target = ae->lu.id.tgtlun.wtarget_id;
+
+			if (target < ESAS2R_MAX_TARGETS)
+				esas2r_lun_event(a, ae, target, length);
+
+			break;
+
+		case VDAAE_HDR_TYPE_DISK:
+			esas2r_log(ESAS2R_LOG_INFO, "Disk event received");
+			break;
+
+		default:
+
+			/* Silently ignore the rest and let the apps deal with
+			 * them.
+			 */
+
+			break;
+		}
+
+		ae = (union atto_vda_ae *)((u8 *)ae + length);
+	}
+
+	/* Now requeue it. */
+	esas2r_start_ae_request(a, rq);
+	esas2r_trace_exit();
+}
+
+/* Send an asynchronous event for a chip reset or power management. */
+void esas2r_send_reset_ae(struct esas2r_adapter *a, bool pwr_mgt)
+{
+	struct atto_vda_ae_hdr ae;
+
+	if (pwr_mgt)
+		ae.bytype = VDAAE_HDR_TYPE_PWRMGT;
+	else
+		ae.bytype = VDAAE_HDR_TYPE_RESET;
+
+	ae.byversion = VDAAE_HDR_VER_0;
+	ae.byflags = 0;
+	ae.bylength = (u8)sizeof(struct atto_vda_ae_hdr);
+
+	if (pwr_mgt)
+		esas2r_hdebug("*** sending power management AE ***");
+	else
+		esas2r_hdebug("*** sending reset AE ***");
+
+	esas2r_queue_fw_event(a, fw_event_vda_ae, &ae,
+			      sizeof(union atto_vda_ae));
+}
+
+void esas2r_dummy_complete(struct esas2r_adapter *a, struct esas2r_request *rq)
+{}
+
+static void esas2r_check_req_rsp_sense(struct esas2r_adapter *a,
+				       struct esas2r_request *rq)
+{
+	u8 snslen, snslen2;
+
+	snslen = snslen2 = rq->func_rsp.scsi_rsp.sense_len;
+
+	if (snslen > rq->sense_len)
+		snslen = rq->sense_len;
+
+	if (snslen) {
+		if (rq->sense_buf)
+			memcpy(rq->sense_buf, rq->data_buf, snslen);
+		else
+			rq->sense_buf = (u8 *)rq->data_buf;
+
+		/* See about possible sense data */
+		if (snslen2 > 0x0c) {
+			u8 *s = (u8 *)rq->data_buf;
+
+			esas2r_trace_enter();
+
+			/* Report LUNS data has changed */
+			if (s[0x0c] == 0x3f && s[0x0d] == 0x0E) {
+				esas2r_trace("rq->target_id: %d",
+					     rq->target_id);
+				esas2r_target_state_changed(a, rq->target_id,
+							    TS_LUN_CHANGE);
+			}
+
+			esas2r_trace("add_sense_key=%x", s[0x0c]);
+			esas2r_trace("add_sense_qual=%x", s[0x0d]);
+			esas2r_trace_exit();
+		}
+	}
+
+	rq->sense_len = snslen;
+}
+
+
+void esas2r_complete_request(struct esas2r_adapter *a,
+			     struct esas2r_request *rq)
+{
+	if (rq->vrq->scsi.function == VDA_FUNC_FLASH
+	    && rq->vrq->flash.sub_func == VDA_FLASH_COMMIT)
+		esas2r_lock_clear_flags(&a->flags, AF_FLASHING);
+
+	/* See if we setup a callback to do special processing */
+
+	if (rq->interrupt_cb) {
+		(*rq->interrupt_cb)(a, rq);
+
+		if (rq->req_stat == RS_PENDING) {
+			esas2r_start_request(a, rq);
+			return;
+		}
+	}
+
+	if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)
+	    && unlikely(rq->req_stat != RS_SUCCESS)) {
+		esas2r_check_req_rsp_sense(a, rq);
+		esas2r_log_request_failure(a, rq);
+	}
+
+	(*rq->comp_cb)(a, rq);
+}
diff --git a/drivers/scsi/esas2r/esas2r_io.c b/drivers/scsi/esas2r/esas2r_io.c
new file mode 100644
index 0000000..324e262
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_io.c
@@ -0,0 +1,880 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_io.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)mpt3sas/mpt3sas_trigger_diag.
+ *
+ * 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.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+void esas2r_start_request(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+	struct esas2r_target *t = NULL;
+	struct esas2r_request *startrq = rq;
+	unsigned long flags;
+
+	if (unlikely(a->flags & (AF_DEGRADED_MODE | AF_POWER_DOWN))) {
+		if (rq->vrq->scsi.function == VDA_FUNC_SCSI)
+			rq->req_stat = RS_SEL2;
+		else
+			rq->req_stat = RS_DEGRADED;
+	} else if (likely(rq->vrq->scsi.function == VDA_FUNC_SCSI)) {
+		t = a->targetdb + rq->target_id;
+
+		if (unlikely(t >= a->targetdb_end
+			     || !(t->flags & TF_USED))) {
+			rq->req_stat = RS_SEL;
+		} else {
+			/* copy in the target ID. */
+			rq->vrq->scsi.target_id = cpu_to_le16(t->virt_targ_id);
+
+			/*
+			 * Test if we want to report RS_SEL for missing target.
+			 * Note that if AF_DISC_PENDING is set than this will
+			 * go on the defer queue.
+			 */
+			if (unlikely(t->target_state != TS_PRESENT
+				     && !(a->flags & AF_DISC_PENDING)))
+				rq->req_stat = RS_SEL;
+		}
+	}
+
+	if (unlikely(rq->req_stat != RS_PENDING)) {
+		esas2r_complete_request(a, rq);
+		return;
+	}
+
+	esas2r_trace("rq=%p", rq);
+	esas2r_trace("rq->vrq->scsi.handle=%x", rq->vrq->scsi.handle);
+
+	if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
+		esas2r_trace("rq->target_id=%d", rq->target_id);
+		esas2r_trace("rq->vrq->scsi.flags=%x", rq->vrq->scsi.flags);
+	}
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	if (likely(list_empty(&a->defer_list) &&
+		   !(a->flags &
+		     (AF_CHPRST_PENDING | AF_FLASHING | AF_DISC_PENDING))))
+		esas2r_local_start_request(a, startrq);
+	else
+		list_add_tail(&startrq->req_list, &a->defer_list);
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+}
+
+/*
+ * Starts the specified request.  all requests have RS_PENDING set when this
+ * routine is called.  The caller is usually esas2r_start_request, but
+ * esas2r_do_deferred_processes will start request that are deferred.
+ *
+ * The caller must ensure that requests can be started.
+ *
+ * esas2r_start_request will defer a request if there are already requests
+ * waiting or there is a chip reset pending.  once the reset condition clears,
+ * esas2r_do_deferred_processes will call this function to start the request.
+ *
+ * When a request is started, it is placed on the active list and queued to
+ * the controller.
+ */
+void esas2r_local_start_request(struct esas2r_adapter *a,
+				struct esas2r_request *rq)
+{
+	esas2r_trace_enter();
+	esas2r_trace("rq=%p", rq);
+	esas2r_trace("rq->vrq:%p", rq->vrq);
+	esas2r_trace("rq->vrq_md->phys_addr:%x", rq->vrq_md->phys_addr);
+
+	if (unlikely(rq->vrq->scsi.function == VDA_FUNC_FLASH
+		     && rq->vrq->flash.sub_func == VDA_FLASH_COMMIT))
+		esas2r_lock_set_flags(&a->flags, AF_FLASHING);
+
+	list_add_tail(&rq->req_list, &a->active_list);
+	esas2r_start_vda_request(a, rq);
+	esas2r_trace_exit();
+	return;
+}
+
+void esas2r_start_vda_request(struct esas2r_adapter *a,
+			      struct esas2r_request *rq)
+{
+	struct esas2r_inbound_list_source_entry *element;
+	u32 dw;
+
+	rq->req_stat = RS_STARTED;
+	/*
+	 * Calculate the inbound list entry location and the current state of
+	 * toggle bit.
+	 */
+	a->last_write++;
+	if (a->last_write >= a->list_size) {
+		a->last_write = 0;
+		/* update the toggle bit */
+		if (a->flags & AF_COMM_LIST_TOGGLE)
+			esas2r_lock_clear_flags(&a->flags,
+						AF_COMM_LIST_TOGGLE);
+		else
+			esas2r_lock_set_flags(&a->flags, AF_COMM_LIST_TOGGLE);
+	}
+
+	element =
+		(struct esas2r_inbound_list_source_entry *)a->inbound_list_md.
+		virt_addr
+		+ a->last_write;
+
+	/* Set the VDA request size if it was never modified */
+	if (rq->vda_req_sz == RQ_SIZE_DEFAULT)
+		rq->vda_req_sz = (u16)(a->max_vdareq_size / sizeof(u32));
+
+	element->address = cpu_to_le64(rq->vrq_md->phys_addr);
+	element->length = cpu_to_le32(rq->vda_req_sz);
+
+	/* Update the write pointer */
+	dw = a->last_write;
+
+	if (a->flags & AF_COMM_LIST_TOGGLE)
+		dw |= MU_ILW_TOGGLE;
+
+	esas2r_trace("rq->vrq->scsi.handle:%x", rq->vrq->scsi.handle);
+	esas2r_trace("dw:%x", dw);
+	esas2r_trace("rq->vda_req_sz:%x", rq->vda_req_sz);
+	esas2r_write_register_dword(a, MU_IN_LIST_WRITE, dw);
+}
+
+/*
+ * Build the scatter/gather list for an I/O request according to the
+ * specifications placed in the s/g context.  The caller must initialize
+ * context prior to the initial call by calling esas2r_sgc_init().
+ */
+bool esas2r_build_sg_list_sge(struct esas2r_adapter *a,
+			      struct esas2r_sg_context *sgc)
+{
+	struct esas2r_request *rq = sgc->first_req;
+	union atto_vda_req *vrq = rq->vrq;
+
+	while (sgc->length) {
+		u32 rem = 0;
+		u64 addr;
+		u32 len;
+
+		len = (*sgc->get_phys_addr)(sgc, &addr);
+
+		if (unlikely(len == 0))
+			return false;
+
+		/* if current length is more than what's left, stop there */
+		if (unlikely(len > sgc->length))
+			len = sgc->length;
+
+another_entry:
+		/* limit to a round number less than the maximum length */
+		if (len > SGE_LEN_MAX) {
+			/*
+			 * Save the remainder of the split.  Whenever we limit
+			 * an entry we come back around to build entries out
+			 * of the leftover.  We do this to prevent multiple
+			 * calls to the get_phys_addr() function for an SGE
+			 * that is too large.
+			 */
+			rem = len - SGE_LEN_MAX;
+			len = SGE_LEN_MAX;
+		}
+
+		/* See if we need to allocate a new SGL */
+		if (unlikely(sgc->sge.a64.curr > sgc->sge.a64.limit)) {
+			u8 sgelen;
+			struct esas2r_mem_desc *sgl;
+
+			/*
+			 * If no SGls are available, return failure.  The
+			 * caller can call us later with the current context
+			 * to pick up here.
+			 */
+			sgl = esas2r_alloc_sgl(a);
+
+			if (unlikely(sgl == NULL))
+				return false;
+
+			/* Calculate the length of the last SGE filled in */
+			sgelen = (u8)((u8 *)sgc->sge.a64.curr
+				      - (u8 *)sgc->sge.a64.last);
+
+			/*
+			 * Copy the last SGE filled in to the first entry of
+			 * the new SGL to make room for the chain entry.
+			 */
+			memcpy(sgl->virt_addr, sgc->sge.a64.last, sgelen);
+
+			/* Figure out the new curr pointer in the new segment */
+			sgc->sge.a64.curr =
+				(struct atto_vda_sge *)((u8 *)sgl->virt_addr +
+							sgelen);
+
+			/* Set the limit pointer and build the chain entry */
+			sgc->sge.a64.limit =
+				(struct atto_vda_sge *)((u8 *)sgl->virt_addr
+							+ sgl_page_size
+							- sizeof(struct
+								 atto_vda_sge));
+			sgc->sge.a64.last->length = cpu_to_le32(
+				SGE_CHAIN | SGE_ADDR_64);
+			sgc->sge.a64.last->address =
+				cpu_to_le64(sgl->phys_addr);
+
+			/*
+			 * Now, if there was a previous chain entry, then
+			 * update it to contain the length of this segment
+			 * and size of this chain.  otherwise this is the
+			 * first SGL, so set the chain_offset in the request.
+			 */
+			if (sgc->sge.a64.chain) {
+				sgc->sge.a64.chain->length |=
+					cpu_to_le32(
+						((u8 *)(sgc->sge.a64.
+							last + 1)
+						 - (u8 *)rq->sg_table->
+						 virt_addr)
+						+ sizeof(struct atto_vda_sge) *
+						LOBIT(SGE_CHAIN_SZ));
+			} else {
+				vrq->scsi.chain_offset = (u8)
+							 ((u8 *)sgc->
+							  sge.a64.last -
+							  (u8 *)vrq);
+
+				/*
+				 * This is the first SGL, so set the
+				 * chain_offset and the VDA request size in
+				 * the request.
+				 */
+				rq->vda_req_sz =
+					(vrq->scsi.chain_offset +
+					 sizeof(struct atto_vda_sge) +
+					 3)
+					/ sizeof(u32);
+			}
+
+			/*
+			 * Remember this so when we get a new SGL filled in we
+			 * can update the length of this chain entry.
+			 */
+			sgc->sge.a64.chain = sgc->sge.a64.last;
+
+			/* Now link the new SGL onto the primary request. */
+			list_add(&sgl->next_desc, &rq->sg_table_head);
+		}
+
+		/* Update last one filled in */
+		sgc->sge.a64.last = sgc->sge.a64.curr;
+
+		/* Build the new SGE and update the S/G context */
+		sgc->sge.a64.curr->length = cpu_to_le32(SGE_ADDR_64 | len);
+		sgc->sge.a64.curr->address = cpu_to_le32(addr);
+		sgc->sge.a64.curr++;
+		sgc->cur_offset += len;
+		sgc->length -= len;
+
+		/*
+		 * Check if we previously split an entry.  If so we have to
+		 * pick up where we left off.
+		 */
+		if (rem) {
+			addr += len;
+			len = rem;
+			rem = 0;
+			goto another_entry;
+		}
+	}
+
+	/* Mark the end of the SGL */
+	sgc->sge.a64.last->length |= cpu_to_le32(SGE_LAST);
+
+	/*
+	 * If there was a previous chain entry, update the length to indicate
+	 * the length of this last segment.
+	 */
+	if (sgc->sge.a64.chain) {
+		sgc->sge.a64.chain->length |= cpu_to_le32(
+			((u8 *)(sgc->sge.a64.curr) -
+			 (u8 *)rq->sg_table->virt_addr));
+	} else {
+		u16 reqsize;
+
+		/*
+		 * The entire VDA request was not used so lets
+		 * set the size of the VDA request to be DMA'd
+		 */
+		reqsize =
+			((u16)((u8 *)sgc->sge.a64.last - (u8 *)vrq)
+			 + sizeof(struct atto_vda_sge) + 3) / sizeof(u32);
+
+		/*
+		 * Only update the request size if it is bigger than what is
+		 * already there.  We can come in here twice for some management
+		 * commands.
+		 */
+		if (reqsize > rq->vda_req_sz)
+			rq->vda_req_sz = reqsize;
+	}
+	return true;
+}
+
+
+/*
+ * Create PRD list for each I-block consumed by the command. This routine
+ * determines how much data is required from each I-block being consumed
+ * by the command. The first and last I-blocks can be partials and all of
+ * the I-blocks in between are for a full I-block of data.
+ *
+ * The interleave size is used to determine the number of bytes in the 1st
+ * I-block and the remaining I-blocks are what remeains.
+ */
+static bool esas2r_build_prd_iblk(struct esas2r_adapter *a,
+				  struct esas2r_sg_context *sgc)
+{
+	struct esas2r_request *rq = sgc->first_req;
+	u64 addr;
+	u32 len;
+	struct esas2r_mem_desc *sgl;
+	u32 numchain = 1;
+	u32 rem = 0;
+
+	while (sgc->length) {
+		/* Get the next address/length pair */
+
+		len = (*sgc->get_phys_addr)(sgc, &addr);
+
+		if (unlikely(len == 0))
+			return false;
+
+		/* If current length is more than what's left, stop there */
+
+		if (unlikely(len > sgc->length))
+			len = sgc->length;
+
+another_entry:
+		/* Limit to a round number less than the maximum length */
+
+		if (len > PRD_LEN_MAX) {
+			/*
+			 * Save the remainder of the split.  whenever we limit
+			 * an entry we come back around to build entries out
+			 * of the leftover.  We do this to prevent multiple
+			 * calls to the get_phys_addr() function for an SGE
+			 * that is too large.
+			 */
+			rem = len - PRD_LEN_MAX;
+			len = PRD_LEN_MAX;
+		}
+
+		/* See if we need to allocate a new SGL */
+		if (sgc->sge.prd.sge_cnt == 0) {
+			if (len == sgc->length) {
+				/*
+				 * We only have 1 PRD entry left.
+				 * It can be placed where the chain
+				 * entry would have gone
+				 */
+
+				/* Build the simple SGE */
+				sgc->sge.prd.curr->ctl_len = cpu_to_le32(
+					PRD_DATA | len);
+				sgc->sge.prd.curr->address = cpu_to_le64(addr);
+
+				/* Adjust length related fields */
+				sgc->cur_offset += len;
+				sgc->length -= len;
+
+				/* We use the reserved chain entry for data */
+				numchain = 0;
+
+				break;
+			}
+
+			if (sgc->sge.prd.chain) {
+				/*
+				 * Fill # of entries of current SGL in previous
+				 * chain the length of this current SGL may not
+				 * full.
+				 */
+
+				sgc->sge.prd.chain->ctl_len |= cpu_to_le32(
+					sgc->sge.prd.sgl_max_cnt);
+			}
+
+			/*
+			 * If no SGls are available, return failure.  The
+			 * caller can call us later with the current context
+			 * to pick up here.
+			 */
+
+			sgl = esas2r_alloc_sgl(a);
+
+			if (unlikely(sgl == NULL))
+				return false;
+
+			/*
+			 * Link the new SGL onto the chain
+			 * They are in reverse order
+			 */
+			list_add(&sgl->next_desc, &rq->sg_table_head);
+
+			/*
+			 * An SGL was just filled in and we are starting
+			 * a new SGL. Prime the chain of the ending SGL with
+			 * info that points to the new SGL. The length gets
+			 * filled in when the new SGL is filled or ended
+			 */
+
+			sgc->sge.prd.chain = sgc->sge.prd.curr;
+
+			sgc->sge.prd.chain->ctl_len = cpu_to_le32(PRD_CHAIN);
+			sgc->sge.prd.chain->address =
+				cpu_to_le64(sgl->phys_addr);
+
+			/*
+			 * Start a new segment.
+			 * Take one away and save for chain SGE
+			 */
+
+			sgc->sge.prd.curr =
+				(struct atto_physical_region_description *)sgl
+				->
+				virt_addr;
+			sgc->sge.prd.sge_cnt = sgc->sge.prd.sgl_max_cnt - 1;
+		}
+
+		sgc->sge.prd.sge_cnt--;
+		/* Build the simple SGE */
+		sgc->sge.prd.curr->ctl_len = cpu_to_le32(PRD_DATA | len);
+		sgc->sge.prd.curr->address = cpu_to_le64(addr);
+
+		/* Used another element.  Point to the next one */
+
+		sgc->sge.prd.curr++;
+
+		/* Adjust length related fields */
+
+		sgc->cur_offset += len;
+		sgc->length -= len;
+
+		/*
+		 * Check if we previously split an entry.  If so we have to
+		 * pick up where we left off.
+		 */
+
+		if (rem) {
+			addr += len;
+			len = rem;
+			rem = 0;
+			goto another_entry;
+		}
+	}
+
+	if (!list_empty(&rq->sg_table_head)) {
+		if (sgc->sge.prd.chain) {
+			sgc->sge.prd.chain->ctl_len |=
+				cpu_to_le32(sgc->sge.prd.sgl_max_cnt
+					    - sgc->sge.prd.sge_cnt
+					    - numchain);
+		}
+	}
+
+	return true;
+}
+
+bool esas2r_build_sg_list_prd(struct esas2r_adapter *a,
+			      struct esas2r_sg_context *sgc)
+{
+	struct esas2r_request *rq = sgc->first_req;
+	u32 len = sgc->length;
+	struct esas2r_target *t = a->targetdb + rq->target_id;
+	u8 is_i_o = 0;
+	u16 reqsize;
+	struct atto_physical_region_description *curr_iblk_chn;
+	u8 *cdb = (u8 *)&rq->vrq->scsi.cdb[0];
+
+	/*
+	 * extract LBA from command so we can determine
+	 * the I-Block boundary
+	 */
+
+	if (rq->vrq->scsi.function == VDA_FUNC_SCSI
+	    && t->target_state == TS_PRESENT
+	    && !(t->flags & TF_PASS_THRU)) {
+		u32 lbalo = 0;
+
+		switch (rq->vrq->scsi.cdb[0]) {
+		case    READ_16:
+		case    WRITE_16:
+		{
+			lbalo =
+				MAKEDWORD(MAKEWORD(cdb[9],
+						   cdb[8]),
+					  MAKEWORD(cdb[7],
+						   cdb[6]));
+			is_i_o = 1;
+			break;
+		}
+
+		case    READ_12:
+		case    WRITE_12:
+		case    READ_10:
+		case    WRITE_10:
+		{
+			lbalo =
+				MAKEDWORD(MAKEWORD(cdb[5],
+						   cdb[4]),
+					  MAKEWORD(cdb[3],
+						   cdb[2]));
+			is_i_o = 1;
+			break;
+		}
+
+		case    READ_6:
+		case    WRITE_6:
+		{
+			lbalo =
+				MAKEDWORD(MAKEWORD(cdb[3],
+						   cdb[2]),
+					  MAKEWORD(cdb[1] & 0x1F,
+						   0));
+			is_i_o = 1;
+			break;
+		}
+
+		default:
+			break;
+		}
+
+		if (is_i_o) {
+			u32 startlba;
+
+			rq->vrq->scsi.iblk_cnt_prd = 0;
+
+			/* Determine size of 1st I-block PRD list       */
+			startlba = t->inter_block - (lbalo & (t->inter_block -
+							      1));
+			sgc->length = startlba * t->block_size;
+
+			/* Chk if the 1st iblk chain starts at base of Iblock */
+			if ((lbalo & (t->inter_block - 1)) == 0)
+				rq->flags |= RF_1ST_IBLK_BASE;
+
+			if (sgc->length > len)
+				sgc->length = len;
+		} else {
+			sgc->length = len;
+		}
+	} else {
+		sgc->length = len;
+	}
+
+	/* get our starting chain address   */
+
+	curr_iblk_chn =
+		(struct atto_physical_region_description *)sgc->sge.a64.curr;
+
+	sgc->sge.prd.sgl_max_cnt = sgl_page_size /
+				   sizeof(struct
+					  atto_physical_region_description);
+
+	/* create all of the I-block PRD lists          */
+
+	while (len) {
+		sgc->sge.prd.sge_cnt = 0;
+		sgc->sge.prd.chain = NULL;
+		sgc->sge.prd.curr = curr_iblk_chn;
+
+		/* increment to next I-Block    */
+
+		len -= sgc->length;
+
+		/* go build the next I-Block PRD list   */
+
+		if (unlikely(!esas2r_build_prd_iblk(a, sgc)))
+			return false;
+
+		curr_iblk_chn++;
+
+		if (is_i_o) {
+			rq->vrq->scsi.iblk_cnt_prd++;
+
+			if (len > t->inter_byte)
+				sgc->length = t->inter_byte;
+			else
+				sgc->length = len;
+		}
+	}
+
+	/* figure out the size used of the VDA request */
+
+	reqsize = ((u16)((u8 *)curr_iblk_chn - (u8 *)rq->vrq))
+		  / sizeof(u32);
+
+	/*
+	 * only update the request size if it is bigger than what is
+	 * already there.  we can come in here twice for some management
+	 * commands.
+	 */
+
+	if (reqsize > rq->vda_req_sz)
+		rq->vda_req_sz = reqsize;
+
+	return true;
+}
+
+static void esas2r_handle_pending_reset(struct esas2r_adapter *a, u32 currtime)
+{
+	u32 delta = currtime - a->chip_init_time;
+
+	if (delta <= ESAS2R_CHPRST_WAIT_TIME) {
+		/* Wait before accessing registers */
+	} else if (delta >= ESAS2R_CHPRST_TIME) {
+		/*
+		 * The last reset failed so try again. Reset
+		 * processing will give up after three tries.
+		 */
+		esas2r_local_reset_adapter(a);
+	} else {
+		/* We can now see if the firmware is ready */
+		u32 doorbell;
+
+		doorbell = esas2r_read_register_dword(a, MU_DOORBELL_OUT);
+		if (doorbell == 0xFFFFFFFF || !(doorbell & DRBL_FORCE_INT)) {
+			esas2r_force_interrupt(a);
+		} else {
+			u32 ver = (doorbell & DRBL_FW_VER_MSK);
+
+			/* Driver supports API version 0 and 1 */
+			esas2r_write_register_dword(a, MU_DOORBELL_OUT,
+						    doorbell);
+			if (ver == DRBL_FW_VER_0) {
+				esas2r_lock_set_flags(&a->flags,
+						      AF_CHPRST_DETECTED);
+				esas2r_lock_set_flags(&a->flags,
+						      AF_LEGACY_SGE_MODE);
+
+				a->max_vdareq_size = 128;
+				a->build_sgl = esas2r_build_sg_list_sge;
+			} else if (ver == DRBL_FW_VER_1) {
+				esas2r_lock_set_flags(&a->flags,
+						      AF_CHPRST_DETECTED);
+				esas2r_lock_clear_flags(&a->flags,
+							AF_LEGACY_SGE_MODE);
+
+				a->max_vdareq_size = 1024;
+				a->build_sgl = esas2r_build_sg_list_prd;
+			} else {
+				esas2r_local_reset_adapter(a);
+			}
+		}
+	}
+}
+
+
+/* This function must be called once per timer tick */
+void esas2r_timer_tick(struct esas2r_adapter *a)
+{
+	u32 currtime = jiffies_to_msecs(jiffies);
+	u32 deltatime = currtime - a->last_tick_time;
+
+	a->last_tick_time = currtime;
+
+	/* count down the uptime */
+	if (a->chip_uptime
+	    && !(a->flags & (AF_CHPRST_PENDING | AF_DISC_PENDING))) {
+		if (deltatime >= a->chip_uptime)
+			a->chip_uptime = 0;
+		else
+			a->chip_uptime -= deltatime;
+	}
+
+	if (a->flags & AF_CHPRST_PENDING) {
+		if (!(a->flags & AF_CHPRST_NEEDED)
+		    && !(a->flags & AF_CHPRST_DETECTED))
+			esas2r_handle_pending_reset(a, currtime);
+	} else {
+		if (a->flags & AF_DISC_PENDING)
+			esas2r_disc_check_complete(a);
+
+		if (a->flags & AF_HEARTBEAT_ENB) {
+			if (a->flags & AF_HEARTBEAT) {
+				if ((currtime - a->heartbeat_time) >=
+				    ESAS2R_HEARTBEAT_TIME) {
+					esas2r_lock_clear_flags(&a->flags,
+								AF_HEARTBEAT);
+					esas2r_hdebug("heartbeat failed");
+					esas2r_log(ESAS2R_LOG_CRIT,
+						   "heartbeat failed");
+					esas2r_bugon();
+					esas2r_local_reset_adapter(a);
+				}
+			} else {
+				esas2r_lock_set_flags(&a->flags, AF_HEARTBEAT);
+				a->heartbeat_time = currtime;
+				esas2r_force_interrupt(a);
+			}
+		}
+	}
+
+	if (atomic_read(&a->disable_cnt) == 0)
+		esas2r_do_deferred_processes(a);
+}
+
+/*
+ * Send the specified task management function to the target and LUN
+ * specified in rqaux.  in addition, immediately abort any commands that
+ * are queued but not sent to the device according to the rules specified
+ * by the task management function.
+ */
+bool esas2r_send_task_mgmt(struct esas2r_adapter *a,
+			   struct esas2r_request *rqaux, u8 task_mgt_func)
+{
+	u16 targetid = rqaux->target_id;
+	u8 lun = (u8)le32_to_cpu(rqaux->vrq->scsi.flags);
+	bool ret = false;
+	struct esas2r_request *rq;
+	struct list_head *next, *element;
+	unsigned long flags;
+
+	LIST_HEAD(comp_list);
+
+	esas2r_trace_enter();
+	esas2r_trace("rqaux:%p", rqaux);
+	esas2r_trace("task_mgt_func:%x", task_mgt_func);
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	/* search the defer queue looking for requests for the device */
+	list_for_each_safe(element, next, &a->defer_list) {
+		rq = list_entry(element, struct esas2r_request, req_list);
+
+		if (rq->vrq->scsi.function == VDA_FUNC_SCSI
+		    && rq->target_id == targetid
+		    && (((u8)le32_to_cpu(rq->vrq->scsi.flags)) == lun
+			|| task_mgt_func == 0x20)) { /* target reset */
+			/* Found a request affected by the task management */
+			if (rq->req_stat == RS_PENDING) {
+				/*
+				 * The request is pending or waiting.  We can
+				 * safelycomplete the request now.
+				 */
+				if (esas2r_ioreq_aborted(a, rq, RS_ABORTED))
+					list_add_tail(&rq->comp_list,
+						      &comp_list);
+			}
+		}
+	}
+
+	/* Send the task management request to the firmware */
+	rqaux->sense_len = 0;
+	rqaux->vrq->scsi.length = 0;
+	rqaux->target_id = targetid;
+	rqaux->vrq->scsi.flags |= cpu_to_le32(lun);
+	memset(rqaux->vrq->scsi.cdb, 0, sizeof(rqaux->vrq->scsi.cdb));
+	rqaux->vrq->scsi.flags |=
+		cpu_to_le16(task_mgt_func * LOBIT(FCP_CMND_TM_MASK));
+
+	if (a->flags & AF_FLASHING) {
+		/* Assume success.  if there are active requests, return busy */
+		rqaux->req_stat = RS_SUCCESS;
+
+		list_for_each_safe(element, next, &a->active_list) {
+			rq = list_entry(element, struct esas2r_request,
+					req_list);
+			if (rq->vrq->scsi.function == VDA_FUNC_SCSI
+			    && rq->target_id == targetid
+			    && (((u8)le32_to_cpu(rq->vrq->scsi.flags)) == lun
+				|| task_mgt_func == 0x20))  /* target reset */
+				rqaux->req_stat = RS_BUSY;
+		}
+
+		ret = true;
+	}
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+
+	if (!(a->flags & AF_FLASHING))
+		esas2r_start_request(a, rqaux);
+
+	esas2r_comp_list_drain(a, &comp_list);
+
+	if (atomic_read(&a->disable_cnt) == 0)
+		esas2r_do_deferred_processes(a);
+
+	esas2r_trace_exit();
+
+	return ret;
+}
+
+void esas2r_reset_bus(struct esas2r_adapter *a)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "performing a bus reset");
+
+	if (!(a->flags & AF_DEGRADED_MODE)
+	    && !(a->flags & (AF_CHPRST_PENDING | AF_DISC_PENDING))) {
+		esas2r_lock_set_flags(&a->flags, AF_BUSRST_NEEDED);
+		esas2r_lock_set_flags(&a->flags, AF_BUSRST_PENDING);
+		esas2r_lock_set_flags(&a->flags, AF_OS_RESET);
+
+		esas2r_schedule_tasklet(a);
+	}
+}
+
+bool esas2r_ioreq_aborted(struct esas2r_adapter *a, struct esas2r_request *rq,
+			  u8 status)
+{
+	esas2r_trace_enter();
+	esas2r_trace("rq:%p", rq);
+	list_del_init(&rq->req_list);
+	if (rq->timeout > RQ_MAX_TIMEOUT) {
+		/*
+		 * The request timed out, but we could not abort it because a
+		 * chip reset occurred.  Return busy status.
+		 */
+		rq->req_stat = RS_BUSY;
+		esas2r_trace_exit();
+		return true;
+	}
+
+	rq->req_stat = status;
+	esas2r_trace_exit();
+	return true;
+}
diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c
new file mode 100644
index 0000000..f3d0cb8
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_ioctl.c
@@ -0,0 +1,2110 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_ioctl.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+/*
+ * Buffered ioctl handlers.  A buffered ioctl is one which requires that we
+ * allocate a DMA-able memory area to communicate with the firmware.  In
+ * order to prevent continually allocating and freeing consistent memory,
+ * we will allocate a global buffer the first time we need it and re-use
+ * it for subsequent ioctl calls that require it.
+ */
+
+u8 *esas2r_buffered_ioctl;
+dma_addr_t esas2r_buffered_ioctl_addr;
+u32 esas2r_buffered_ioctl_size;
+struct pci_dev *esas2r_buffered_ioctl_pcid;
+
+static DEFINE_SEMAPHORE(buffered_ioctl_semaphore);
+typedef int (*BUFFERED_IOCTL_CALLBACK)(struct esas2r_adapter *,
+				       struct esas2r_request *,
+				       struct esas2r_sg_context *,
+				       void *);
+typedef void (*BUFFERED_IOCTL_DONE_CALLBACK)(struct esas2r_adapter *,
+					     struct esas2r_request *, void *);
+
+struct esas2r_buffered_ioctl {
+	struct esas2r_adapter *a;
+	void *ioctl;
+	u32 length;
+	u32 control_code;
+	u32 offset;
+	BUFFERED_IOCTL_CALLBACK
+		callback;
+	void *context;
+	BUFFERED_IOCTL_DONE_CALLBACK
+		done_callback;
+	void *done_context;
+
+};
+
+static void complete_fm_api_req(struct esas2r_adapter *a,
+				struct esas2r_request *rq)
+{
+	a->fm_api_command_done = 1;
+	wake_up_interruptible(&a->fm_api_waiter);
+}
+
+/* Callbacks for building scatter/gather lists for FM API requests */
+static u32 get_physaddr_fm_api(struct esas2r_sg_context *sgc, u64 *addr)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+	int offset = sgc->cur_offset - a->save_offset;
+
+	(*addr) = a->firmware.phys + offset;
+	return a->firmware.orig_len - offset;
+}
+
+static u32 get_physaddr_fm_api_header(struct esas2r_sg_context *sgc, u64 *addr)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+	int offset = sgc->cur_offset - a->save_offset;
+
+	(*addr) = a->firmware.header_buff_phys + offset;
+	return sizeof(struct esas2r_flash_img) - offset;
+}
+
+/* Handle EXPRESS_IOCTL_RW_FIRMWARE ioctl with img_type = FW_IMG_FM_API. */
+static void do_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
+{
+	struct esas2r_request *rq;
+
+	if (down_interruptible(&a->fm_api_semaphore)) {
+		fi->status = FI_STAT_BUSY;
+		return;
+	}
+
+	rq = esas2r_alloc_request(a);
+	if (rq == NULL) {
+		up(&a->fm_api_semaphore);
+		fi->status = FI_STAT_BUSY;
+		return;
+	}
+
+	if (fi == &a->firmware.header) {
+		a->firmware.header_buff = dma_alloc_coherent(&a->pcid->dev,
+							     (size_t)sizeof(
+								     struct
+								     esas2r_flash_img),
+							     (dma_addr_t *)&a->
+							     firmware.
+							     header_buff_phys,
+							     GFP_KERNEL);
+
+		if (a->firmware.header_buff == NULL) {
+			esas2r_debug("failed to allocate header buffer!");
+			fi->status = FI_STAT_BUSY;
+			return;
+		}
+
+		memcpy(a->firmware.header_buff, fi,
+		       sizeof(struct esas2r_flash_img));
+		a->save_offset = a->firmware.header_buff;
+		a->fm_api_sgc.get_phys_addr =
+			(PGETPHYSADDR)get_physaddr_fm_api_header;
+	} else {
+		a->save_offset = (u8 *)fi;
+		a->fm_api_sgc.get_phys_addr =
+			(PGETPHYSADDR)get_physaddr_fm_api;
+	}
+
+	rq->comp_cb = complete_fm_api_req;
+	a->fm_api_command_done = 0;
+	a->fm_api_sgc.cur_offset = a->save_offset;
+
+	if (!esas2r_fm_api(a, (struct esas2r_flash_img *)a->save_offset, rq,
+			   &a->fm_api_sgc))
+		goto all_done;
+
+	/* Now wait around for it to complete. */
+	while (!a->fm_api_command_done)
+		wait_event_interruptible(a->fm_api_waiter,
+					 a->fm_api_command_done);
+all_done:
+	if (fi == &a->firmware.header) {
+		memcpy(fi, a->firmware.header_buff,
+		       sizeof(struct esas2r_flash_img));
+
+		dma_free_coherent(&a->pcid->dev,
+				  (size_t)sizeof(struct esas2r_flash_img),
+				  a->firmware.header_buff,
+				  (dma_addr_t)a->firmware.header_buff_phys);
+	}
+
+	up(&a->fm_api_semaphore);
+	esas2r_free_request(a, (struct esas2r_request *)rq);
+	return;
+
+}
+
+static void complete_nvr_req(struct esas2r_adapter *a,
+			     struct esas2r_request *rq)
+{
+	a->nvram_command_done = 1;
+	wake_up_interruptible(&a->nvram_waiter);
+}
+
+/* Callback for building scatter/gather lists for buffered ioctls */
+static u32 get_physaddr_buffered_ioctl(struct esas2r_sg_context *sgc,
+				       u64 *addr)
+{
+	int offset = (u8 *)sgc->cur_offset - esas2r_buffered_ioctl;
+
+	(*addr) = esas2r_buffered_ioctl_addr + offset;
+	return esas2r_buffered_ioctl_size - offset;
+}
+
+static void complete_buffered_ioctl_req(struct esas2r_adapter *a,
+					struct esas2r_request *rq)
+{
+	a->buffered_ioctl_done = 1;
+	wake_up_interruptible(&a->buffered_ioctl_waiter);
+}
+
+static u8 handle_buffered_ioctl(struct esas2r_buffered_ioctl *bi)
+{
+	struct esas2r_adapter *a = bi->a;
+	struct esas2r_request *rq;
+	struct esas2r_sg_context sgc;
+	u8 result = IOCTL_SUCCESS;
+
+	if (down_interruptible(&buffered_ioctl_semaphore))
+		return IOCTL_OUT_OF_RESOURCES;
+
+	/* allocate a buffer or use the existing buffer. */
+	if (esas2r_buffered_ioctl) {
+		if (esas2r_buffered_ioctl_size < bi->length) {
+			/* free the too-small buffer and get a new one */
+			dma_free_coherent(&a->pcid->dev,
+					  (size_t)esas2r_buffered_ioctl_size,
+					  esas2r_buffered_ioctl,
+					  esas2r_buffered_ioctl_addr);
+
+			goto allocate_buffer;
+		}
+	} else {
+allocate_buffer:
+		esas2r_buffered_ioctl_size = bi->length;
+		esas2r_buffered_ioctl_pcid = a->pcid;
+		esas2r_buffered_ioctl = dma_alloc_coherent(&a->pcid->dev,
+							   (size_t)
+							   esas2r_buffered_ioctl_size,
+							   &
+							   esas2r_buffered_ioctl_addr,
+							   GFP_KERNEL);
+	}
+
+	if (!esas2r_buffered_ioctl) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "could not allocate %d bytes of consistent memory "
+			   "for a buffered ioctl!",
+			   bi->length);
+
+		esas2r_debug("buffered ioctl alloc failure");
+		result = IOCTL_OUT_OF_RESOURCES;
+		goto exit_cleanly;
+	}
+
+	memcpy(esas2r_buffered_ioctl, bi->ioctl, bi->length);
+
+	rq = esas2r_alloc_request(a);
+	if (rq == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "could not allocate an internal request");
+
+		result = IOCTL_OUT_OF_RESOURCES;
+		esas2r_debug("buffered ioctl - no requests");
+		goto exit_cleanly;
+	}
+
+	a->buffered_ioctl_done = 0;
+	rq->comp_cb = complete_buffered_ioctl_req;
+	sgc.cur_offset = esas2r_buffered_ioctl + bi->offset;
+	sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_buffered_ioctl;
+	sgc.length = esas2r_buffered_ioctl_size;
+
+	if (!(*bi->callback)(a, rq, &sgc, bi->context)) {
+		/* completed immediately, no need to wait */
+		a->buffered_ioctl_done = 0;
+		goto free_andexit_cleanly;
+	}
+
+	/* now wait around for it to complete. */
+	while (!a->buffered_ioctl_done)
+		wait_event_interruptible(a->buffered_ioctl_waiter,
+					 a->buffered_ioctl_done);
+
+free_andexit_cleanly:
+	if (result == IOCTL_SUCCESS && bi->done_callback)
+		(*bi->done_callback)(a, rq, bi->done_context);
+
+	esas2r_free_request(a, rq);
+
+exit_cleanly:
+	if (result == IOCTL_SUCCESS)
+		memcpy(bi->ioctl, esas2r_buffered_ioctl, bi->length);
+
+	up(&buffered_ioctl_semaphore);
+	return result;
+}
+
+/* SMP ioctl support */
+static int smp_ioctl_callback(struct esas2r_adapter *a,
+			      struct esas2r_request *rq,
+			      struct esas2r_sg_context *sgc, void *context)
+{
+	struct atto_ioctl_smp *si =
+		(struct atto_ioctl_smp *)esas2r_buffered_ioctl;
+
+	esas2r_sgc_init(sgc, a, rq, rq->vrq->ioctl.sge);
+	esas2r_build_ioctl_req(a, rq, sgc->length, VDA_IOCTL_SMP);
+
+	if (!esas2r_build_sg_list(a, rq, sgc)) {
+		si->status = ATTO_STS_OUT_OF_RSRC;
+		return false;
+	}
+
+	esas2r_start_request(a, rq);
+	return true;
+}
+
+static u8 handle_smp_ioctl(struct esas2r_adapter *a, struct atto_ioctl_smp *si)
+{
+	struct esas2r_buffered_ioctl bi;
+
+	memset(&bi, 0, sizeof(bi));
+
+	bi.a = a;
+	bi.ioctl = si;
+	bi.length = sizeof(struct atto_ioctl_smp)
+		    + le32_to_cpu(si->req_length)
+		    + le32_to_cpu(si->rsp_length);
+	bi.offset = 0;
+	bi.callback = smp_ioctl_callback;
+	return handle_buffered_ioctl(&bi);
+}
+
+
+/* CSMI ioctl support */
+static void esas2r_csmi_ioctl_tunnel_comp_cb(struct esas2r_adapter *a,
+					     struct esas2r_request *rq)
+{
+	rq->target_id = le16_to_cpu(rq->func_rsp.ioctl_rsp.csmi.target_id);
+	rq->vrq->scsi.flags |= cpu_to_le32(rq->func_rsp.ioctl_rsp.csmi.lun);
+
+	/* Now call the original completion callback. */
+	(*rq->aux_req_cb)(a, rq);
+}
+
+/* Tunnel a CSMI IOCTL to the back end driver for processing. */
+static bool csmi_ioctl_tunnel(struct esas2r_adapter *a,
+			      union atto_ioctl_csmi *ci,
+			      struct esas2r_request *rq,
+			      struct esas2r_sg_context *sgc,
+			      u32 ctrl_code,
+			      u16 target_id)
+{
+	struct atto_vda_ioctl_req *ioctl = &rq->vrq->ioctl;
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return false;
+
+	esas2r_sgc_init(sgc, a, rq, rq->vrq->ioctl.sge);
+	esas2r_build_ioctl_req(a, rq, sgc->length, VDA_IOCTL_CSMI);
+	ioctl->csmi.ctrl_code = cpu_to_le32(ctrl_code);
+	ioctl->csmi.target_id = cpu_to_le16(target_id);
+	ioctl->csmi.lun = (u8)le32_to_cpu(rq->vrq->scsi.flags);
+
+	/*
+	 * Always usurp the completion callback since the interrupt callback
+	 * mechanism may be used.
+	 */
+	rq->aux_req_cx = ci;
+	rq->aux_req_cb = rq->comp_cb;
+	rq->comp_cb = esas2r_csmi_ioctl_tunnel_comp_cb;
+
+	if (!esas2r_build_sg_list(a, rq, sgc))
+		return false;
+
+	esas2r_start_request(a, rq);
+	return true;
+}
+
+static bool check_lun(struct scsi_lun lun)
+{
+	bool result;
+
+	result = ((lun.scsi_lun[7] == 0) &&
+		  (lun.scsi_lun[6] == 0) &&
+		  (lun.scsi_lun[5] == 0) &&
+		  (lun.scsi_lun[4] == 0) &&
+		  (lun.scsi_lun[3] == 0) &&
+		  (lun.scsi_lun[2] == 0) &&
+/* Byte 1 is intentionally skipped */
+		  (lun.scsi_lun[0] == 0));
+
+	return result;
+}
+
+static int csmi_ioctl_callback(struct esas2r_adapter *a,
+			       struct esas2r_request *rq,
+			       struct esas2r_sg_context *sgc, void *context)
+{
+	struct atto_csmi *ci = (struct atto_csmi *)context;
+	union atto_ioctl_csmi *ioctl_csmi =
+		(union atto_ioctl_csmi *)esas2r_buffered_ioctl;
+	u8 path = 0;
+	u8 tid = 0;
+	u8 lun = 0;
+	u32 sts = CSMI_STS_SUCCESS;
+	struct esas2r_target *t;
+	unsigned long flags;
+
+	if (ci->control_code == CSMI_CC_GET_DEV_ADDR) {
+		struct atto_csmi_get_dev_addr *gda = &ci->data.dev_addr;
+
+		path = gda->path_id;
+		tid = gda->target_id;
+		lun = gda->lun;
+	} else if (ci->control_code == CSMI_CC_TASK_MGT) {
+		struct atto_csmi_task_mgmt *tm = &ci->data.tsk_mgt;
+
+		path = tm->path_id;
+		tid = tm->target_id;
+		lun = tm->lun;
+	}
+
+	if (path > 0 || tid > ESAS2R_MAX_ID) {
+		rq->func_rsp.ioctl_rsp.csmi.csmi_status = cpu_to_le32(
+			CSMI_STS_INV_PARAM);
+		return false;
+	}
+
+	rq->target_id = tid;
+	rq->vrq->scsi.flags |= cpu_to_le32(lun);
+
+	switch (ci->control_code) {
+	case CSMI_CC_GET_DRVR_INFO:
+	{
+		struct atto_csmi_get_driver_info *gdi = &ioctl_csmi->drvr_info;
+
+		strcpy(gdi->description, esas2r_get_model_name(a));
+		gdi->csmi_major_rev = CSMI_MAJOR_REV;
+		gdi->csmi_minor_rev = CSMI_MINOR_REV;
+		break;
+	}
+
+	case CSMI_CC_GET_CNTLR_CFG:
+	{
+		struct atto_csmi_get_cntlr_cfg *gcc = &ioctl_csmi->cntlr_cfg;
+
+		gcc->base_io_addr = 0;
+		pci_read_config_dword(a->pcid, PCI_BASE_ADDRESS_2,
+				      &gcc->base_memaddr_lo);
+		pci_read_config_dword(a->pcid, PCI_BASE_ADDRESS_3,
+				      &gcc->base_memaddr_hi);
+		gcc->board_id = MAKEDWORD(a->pcid->subsystem_device,
+					  a->pcid->subsystem_vendor);
+		gcc->slot_num = CSMI_SLOT_NUM_UNKNOWN;
+		gcc->cntlr_class = CSMI_CNTLR_CLASS_HBA;
+		gcc->io_bus_type = CSMI_BUS_TYPE_PCI;
+		gcc->pci_addr.bus_num = a->pcid->bus->number;
+		gcc->pci_addr.device_num = PCI_SLOT(a->pcid->devfn);
+		gcc->pci_addr.function_num = PCI_FUNC(a->pcid->devfn);
+
+		memset(gcc->serial_num, 0, sizeof(gcc->serial_num));
+
+		gcc->major_rev = LOBYTE(LOWORD(a->fw_version));
+		gcc->minor_rev = HIBYTE(LOWORD(a->fw_version));
+		gcc->build_rev = LOBYTE(HIWORD(a->fw_version));
+		gcc->release_rev = HIBYTE(HIWORD(a->fw_version));
+		gcc->bios_major_rev = HIBYTE(HIWORD(a->flash_ver));
+		gcc->bios_minor_rev = LOBYTE(HIWORD(a->flash_ver));
+		gcc->bios_build_rev = LOWORD(a->flash_ver);
+
+		if (a->flags2 & AF2_THUNDERLINK)
+			gcc->cntlr_flags = CSMI_CNTLRF_SAS_HBA
+					   | CSMI_CNTLRF_SATA_HBA;
+		else
+			gcc->cntlr_flags = CSMI_CNTLRF_SAS_RAID
+					   | CSMI_CNTLRF_SATA_RAID;
+
+		gcc->rrom_major_rev = 0;
+		gcc->rrom_minor_rev = 0;
+		gcc->rrom_build_rev = 0;
+		gcc->rrom_release_rev = 0;
+		gcc->rrom_biosmajor_rev = 0;
+		gcc->rrom_biosminor_rev = 0;
+		gcc->rrom_biosbuild_rev = 0;
+		gcc->rrom_biosrelease_rev = 0;
+		break;
+	}
+
+	case CSMI_CC_GET_CNTLR_STS:
+	{
+		struct atto_csmi_get_cntlr_sts *gcs = &ioctl_csmi->cntlr_sts;
+
+		if (a->flags & AF_DEGRADED_MODE)
+			gcs->status = CSMI_CNTLR_STS_FAILED;
+		else
+			gcs->status = CSMI_CNTLR_STS_GOOD;
+
+		gcs->offline_reason = CSMI_OFFLINE_NO_REASON;
+		break;
+	}
+
+	case CSMI_CC_FW_DOWNLOAD:
+	case CSMI_CC_GET_RAID_INFO:
+	case CSMI_CC_GET_RAID_CFG:
+
+		sts = CSMI_STS_BAD_CTRL_CODE;
+		break;
+
+	case CSMI_CC_SMP_PASSTHRU:
+	case CSMI_CC_SSP_PASSTHRU:
+	case CSMI_CC_STP_PASSTHRU:
+	case CSMI_CC_GET_PHY_INFO:
+	case CSMI_CC_SET_PHY_INFO:
+	case CSMI_CC_GET_LINK_ERRORS:
+	case CSMI_CC_GET_SATA_SIG:
+	case CSMI_CC_GET_CONN_INFO:
+	case CSMI_CC_PHY_CTRL:
+
+		if (!csmi_ioctl_tunnel(a, ioctl_csmi, rq, sgc,
+				       ci->control_code,
+				       ESAS2R_TARG_ID_INV)) {
+			sts = CSMI_STS_FAILED;
+			break;
+		}
+
+		return true;
+
+	case CSMI_CC_GET_SCSI_ADDR:
+	{
+		struct atto_csmi_get_scsi_addr *gsa = &ioctl_csmi->scsi_addr;
+
+		struct scsi_lun lun;
+
+		memcpy(&lun, gsa->sas_lun, sizeof(struct scsi_lun));
+
+		if (!check_lun(lun)) {
+			sts = CSMI_STS_NO_SCSI_ADDR;
+			break;
+		}
+
+		/* make sure the device is present */
+		spin_lock_irqsave(&a->mem_lock, flags);
+		t = esas2r_targ_db_find_by_sas_addr(a, (u64 *)gsa->sas_addr);
+		spin_unlock_irqrestore(&a->mem_lock, flags);
+
+		if (t == NULL) {
+			sts = CSMI_STS_NO_SCSI_ADDR;
+			break;
+		}
+
+		gsa->host_index = 0xFF;
+		gsa->lun = gsa->sas_lun[1];
+		rq->target_id = esas2r_targ_get_id(t, a);
+		break;
+	}
+
+	case CSMI_CC_GET_DEV_ADDR:
+	{
+		struct atto_csmi_get_dev_addr *gda = &ioctl_csmi->dev_addr;
+
+		/* make sure the target is present */
+		t = a->targetdb + rq->target_id;
+
+		if (t >= a->targetdb_end
+		    || t->target_state != TS_PRESENT
+		    || t->sas_addr == 0) {
+			sts = CSMI_STS_NO_DEV_ADDR;
+			break;
+		}
+
+		/* fill in the result */
+		*(u64 *)gda->sas_addr = t->sas_addr;
+		memset(gda->sas_lun, 0, sizeof(gda->sas_lun));
+		gda->sas_lun[1] = (u8)le32_to_cpu(rq->vrq->scsi.flags);
+		break;
+	}
+
+	case CSMI_CC_TASK_MGT:
+
+		/* make sure the target is present */
+		t = a->targetdb + rq->target_id;
+
+		if (t >= a->targetdb_end
+		    || t->target_state != TS_PRESENT
+		    || !(t->flags & TF_PASS_THRU)) {
+			sts = CSMI_STS_NO_DEV_ADDR;
+			break;
+		}
+
+		if (!csmi_ioctl_tunnel(a, ioctl_csmi, rq, sgc,
+				       ci->control_code,
+				       t->phys_targ_id)) {
+			sts = CSMI_STS_FAILED;
+			break;
+		}
+
+		return true;
+
+	default:
+
+		sts = CSMI_STS_BAD_CTRL_CODE;
+		break;
+	}
+
+	rq->func_rsp.ioctl_rsp.csmi.csmi_status = cpu_to_le32(sts);
+
+	return false;
+}
+
+
+static void csmi_ioctl_done_callback(struct esas2r_adapter *a,
+				     struct esas2r_request *rq, void *context)
+{
+	struct atto_csmi *ci = (struct atto_csmi *)context;
+	union atto_ioctl_csmi *ioctl_csmi =
+		(union atto_ioctl_csmi *)esas2r_buffered_ioctl;
+
+	switch (ci->control_code) {
+	case CSMI_CC_GET_DRVR_INFO:
+	{
+		struct atto_csmi_get_driver_info *gdi =
+			&ioctl_csmi->drvr_info;
+
+		strcpy(gdi->name, ESAS2R_VERSION_STR);
+
+		gdi->major_rev = ESAS2R_MAJOR_REV;
+		gdi->minor_rev = ESAS2R_MINOR_REV;
+		gdi->build_rev = 0;
+		gdi->release_rev = 0;
+		break;
+	}
+
+	case CSMI_CC_GET_SCSI_ADDR:
+	{
+		struct atto_csmi_get_scsi_addr *gsa = &ioctl_csmi->scsi_addr;
+
+		if (le32_to_cpu(rq->func_rsp.ioctl_rsp.csmi.csmi_status) ==
+		    CSMI_STS_SUCCESS) {
+			gsa->target_id = rq->target_id;
+			gsa->path_id = 0;
+		}
+
+		break;
+	}
+	}
+
+	ci->status = le32_to_cpu(rq->func_rsp.ioctl_rsp.csmi.csmi_status);
+}
+
+
+static u8 handle_csmi_ioctl(struct esas2r_adapter *a, struct atto_csmi *ci)
+{
+	struct esas2r_buffered_ioctl bi;
+
+	memset(&bi, 0, sizeof(bi));
+
+	bi.a = a;
+	bi.ioctl = &ci->data;
+	bi.length = sizeof(union atto_ioctl_csmi);
+	bi.offset = 0;
+	bi.callback = csmi_ioctl_callback;
+	bi.context = ci;
+	bi.done_callback = csmi_ioctl_done_callback;
+	bi.done_context = ci;
+
+	return handle_buffered_ioctl(&bi);
+}
+
+/* ATTO HBA ioctl support */
+
+/* Tunnel an ATTO HBA IOCTL to the back end driver for processing. */
+static bool hba_ioctl_tunnel(struct esas2r_adapter *a,
+			     struct atto_ioctl *hi,
+			     struct esas2r_request *rq,
+			     struct esas2r_sg_context *sgc)
+{
+	esas2r_sgc_init(sgc, a, rq, rq->vrq->ioctl.sge);
+
+	esas2r_build_ioctl_req(a, rq, sgc->length, VDA_IOCTL_HBA);
+
+	if (!esas2r_build_sg_list(a, rq, sgc)) {
+		hi->status = ATTO_STS_OUT_OF_RSRC;
+
+		return false;
+	}
+
+	esas2r_start_request(a, rq);
+
+	return true;
+}
+
+static void scsi_passthru_comp_cb(struct esas2r_adapter *a,
+				  struct esas2r_request *rq)
+{
+	struct atto_ioctl *hi = (struct atto_ioctl *)rq->aux_req_cx;
+	struct atto_hba_scsi_pass_thru *spt = &hi->data.scsi_pass_thru;
+	u8 sts = ATTO_SPT_RS_FAILED;
+
+	spt->scsi_status = rq->func_rsp.scsi_rsp.scsi_stat;
+	spt->sense_length = rq->sense_len;
+	spt->residual_length =
+		le32_to_cpu(rq->func_rsp.scsi_rsp.residual_length);
+
+	switch (rq->req_stat) {
+	case RS_SUCCESS:
+	case RS_SCSI_ERROR:
+		sts = ATTO_SPT_RS_SUCCESS;
+		break;
+	case RS_UNDERRUN:
+		sts = ATTO_SPT_RS_UNDERRUN;
+		break;
+	case RS_OVERRUN:
+		sts = ATTO_SPT_RS_OVERRUN;
+		break;
+	case RS_SEL:
+	case RS_SEL2:
+		sts = ATTO_SPT_RS_NO_DEVICE;
+		break;
+	case RS_NO_LUN:
+		sts = ATTO_SPT_RS_NO_LUN;
+		break;
+	case RS_TIMEOUT:
+		sts = ATTO_SPT_RS_TIMEOUT;
+		break;
+	case RS_DEGRADED:
+		sts = ATTO_SPT_RS_DEGRADED;
+		break;
+	case RS_BUSY:
+		sts = ATTO_SPT_RS_BUSY;
+		break;
+	case RS_ABORTED:
+		sts = ATTO_SPT_RS_ABORTED;
+		break;
+	case RS_RESET:
+		sts = ATTO_SPT_RS_BUS_RESET;
+		break;
+	}
+
+	spt->req_status = sts;
+
+	/* Update the target ID to the next one present. */
+	spt->target_id =
+		esas2r_targ_db_find_next_present(a, (u16)spt->target_id);
+
+	/* Done, call the completion callback. */
+	(*rq->aux_req_cb)(a, rq);
+}
+
+static int hba_ioctl_callback(struct esas2r_adapter *a,
+			      struct esas2r_request *rq,
+			      struct esas2r_sg_context *sgc,
+			      void *context)
+{
+	struct atto_ioctl *hi = (struct atto_ioctl *)esas2r_buffered_ioctl;
+
+	hi->status = ATTO_STS_SUCCESS;
+
+	switch (hi->function) {
+	case ATTO_FUNC_GET_ADAP_INFO:
+	{
+		u8 *class_code = (u8 *)&a->pcid->class;
+
+		struct atto_hba_get_adapter_info *gai =
+			&hi->data.get_adap_info;
+		int pcie_cap_reg;
+
+		if (hi->flags & HBAF_TUNNEL) {
+			hi->status = ATTO_STS_UNSUPPORTED;
+			break;
+		}
+
+		if (hi->version > ATTO_VER_GET_ADAP_INFO0) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_GET_ADAP_INFO0;
+			break;
+		}
+
+		memset(gai, 0, sizeof(*gai));
+
+		gai->pci.vendor_id = a->pcid->vendor;
+		gai->pci.device_id = a->pcid->device;
+		gai->pci.ss_vendor_id = a->pcid->subsystem_vendor;
+		gai->pci.ss_device_id = a->pcid->subsystem_device;
+		gai->pci.class_code[0] = class_code[0];
+		gai->pci.class_code[1] = class_code[1];
+		gai->pci.class_code[2] = class_code[2];
+		gai->pci.rev_id = a->pcid->revision;
+		gai->pci.bus_num = a->pcid->bus->number;
+		gai->pci.dev_num = PCI_SLOT(a->pcid->devfn);
+		gai->pci.func_num = PCI_FUNC(a->pcid->devfn);
+
+		pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP);
+		if (pcie_cap_reg) {
+			u16 stat;
+			u32 caps;
+
+			pci_read_config_word(a->pcid,
+					     pcie_cap_reg + PCI_EXP_LNKSTA,
+					     &stat);
+			pci_read_config_dword(a->pcid,
+					      pcie_cap_reg + PCI_EXP_LNKCAP,
+					      &caps);
+
+			gai->pci.link_speed_curr =
+				(u8)(stat & PCI_EXP_LNKSTA_CLS);
+			gai->pci.link_speed_max =
+				(u8)(caps & PCI_EXP_LNKCAP_SLS);
+			gai->pci.link_width_curr =
+				(u8)((stat & PCI_EXP_LNKSTA_NLW)
+				     >> PCI_EXP_LNKSTA_NLW_SHIFT);
+			gai->pci.link_width_max =
+				(u8)((caps & PCI_EXP_LNKCAP_MLW)
+				     >> 4);
+		}
+
+		gai->pci.msi_vector_cnt = 1;
+
+		if (a->pcid->msix_enabled)
+			gai->pci.interrupt_mode = ATTO_GAI_PCIIM_MSIX;
+		else if (a->pcid->msi_enabled)
+			gai->pci.interrupt_mode = ATTO_GAI_PCIIM_MSI;
+		else
+			gai->pci.interrupt_mode = ATTO_GAI_PCIIM_LEGACY;
+
+		gai->adap_type = ATTO_GAI_AT_ESASRAID2;
+
+		if (a->flags2 & AF2_THUNDERLINK)
+			gai->adap_type = ATTO_GAI_AT_TLSASHBA;
+
+		if (a->flags & AF_DEGRADED_MODE)
+			gai->adap_flags |= ATTO_GAI_AF_DEGRADED;
+
+		gai->adap_flags |= ATTO_GAI_AF_SPT_SUPP |
+				   ATTO_GAI_AF_DEVADDR_SUPP;
+
+		if (a->pcid->subsystem_device == ATTO_ESAS_R60F
+		    || a->pcid->subsystem_device == ATTO_ESAS_R608
+		    || a->pcid->subsystem_device == ATTO_ESAS_R644
+		    || a->pcid->subsystem_device == ATTO_TSSC_3808E)
+			gai->adap_flags |= ATTO_GAI_AF_VIRT_SES;
+
+		gai->num_ports = ESAS2R_NUM_PHYS;
+		gai->num_phys = ESAS2R_NUM_PHYS;
+
+		strcpy(gai->firmware_rev, a->fw_rev);
+		strcpy(gai->flash_rev, a->flash_rev);
+		strcpy(gai->model_name_short, esas2r_get_model_name_short(a));
+		strcpy(gai->model_name, esas2r_get_model_name(a));
+
+		gai->num_targets = ESAS2R_MAX_TARGETS;
+
+		gai->num_busses = 1;
+		gai->num_targsper_bus = gai->num_targets;
+		gai->num_lunsper_targ = 256;
+
+		if (a->pcid->subsystem_device == ATTO_ESAS_R6F0
+		    || a->pcid->subsystem_device == ATTO_ESAS_R60F)
+			gai->num_connectors = 4;
+		else
+			gai->num_connectors = 2;
+
+		gai->adap_flags2 |= ATTO_GAI_AF2_ADAP_CTRL_SUPP;
+
+		gai->num_targets_backend = a->num_targets_backend;
+
+		gai->tunnel_flags = a->ioctl_tunnel
+				    & (ATTO_GAI_TF_MEM_RW
+				       | ATTO_GAI_TF_TRACE
+				       | ATTO_GAI_TF_SCSI_PASS_THRU
+				       | ATTO_GAI_TF_GET_DEV_ADDR
+				       | ATTO_GAI_TF_PHY_CTRL
+				       | ATTO_GAI_TF_CONN_CTRL
+				       | ATTO_GAI_TF_GET_DEV_INFO);
+		break;
+	}
+
+	case ATTO_FUNC_GET_ADAP_ADDR:
+	{
+		struct atto_hba_get_adapter_address *gaa =
+			&hi->data.get_adap_addr;
+
+		if (hi->flags & HBAF_TUNNEL) {
+			hi->status = ATTO_STS_UNSUPPORTED;
+			break;
+		}
+
+		if (hi->version > ATTO_VER_GET_ADAP_ADDR0) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_GET_ADAP_ADDR0;
+		} else if (gaa->addr_type == ATTO_GAA_AT_PORT
+			   || gaa->addr_type == ATTO_GAA_AT_NODE) {
+			if (gaa->addr_type == ATTO_GAA_AT_PORT
+			    && gaa->port_id >= ESAS2R_NUM_PHYS) {
+				hi->status = ATTO_STS_NOT_APPL;
+			} else {
+				memcpy((u64 *)gaa->address,
+				       &a->nvram->sas_addr[0], sizeof(u64));
+				gaa->addr_len = sizeof(u64);
+			}
+		} else {
+			hi->status = ATTO_STS_INV_PARAM;
+		}
+
+		break;
+	}
+
+	case ATTO_FUNC_MEM_RW:
+	{
+		if (hi->flags & HBAF_TUNNEL) {
+			if (hba_ioctl_tunnel(a, hi, rq, sgc))
+				return true;
+
+			break;
+		}
+
+		hi->status = ATTO_STS_UNSUPPORTED;
+
+		break;
+	}
+
+	case ATTO_FUNC_TRACE:
+	{
+		struct atto_hba_trace *trc = &hi->data.trace;
+
+		if (hi->flags & HBAF_TUNNEL) {
+			if (hba_ioctl_tunnel(a, hi, rq, sgc))
+				return true;
+
+			break;
+		}
+
+		if (hi->version > ATTO_VER_TRACE1) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_TRACE1;
+			break;
+		}
+
+		if (trc->trace_type == ATTO_TRC_TT_FWCOREDUMP
+		    && hi->version >= ATTO_VER_TRACE1) {
+			if (trc->trace_func == ATTO_TRC_TF_UPLOAD) {
+				u32 len = hi->data_length;
+				u32 offset = trc->current_offset;
+				u32 total_len = ESAS2R_FWCOREDUMP_SZ;
+
+				/* Size is zero if a core dump isn't present */
+				if (!(a->flags2 & AF2_COREDUMP_SAVED))
+					total_len = 0;
+
+				if (len > total_len)
+					len = total_len;
+
+				if (offset >= total_len
+				    || offset + len > total_len
+				    || len == 0) {
+					hi->status = ATTO_STS_INV_PARAM;
+					break;
+				}
+
+				memcpy(trc + 1,
+				       a->fw_coredump_buff + offset,
+				       len);
+
+				hi->data_length = len;
+			} else if (trc->trace_func == ATTO_TRC_TF_RESET) {
+				memset(a->fw_coredump_buff, 0,
+				       ESAS2R_FWCOREDUMP_SZ);
+
+				esas2r_lock_clear_flags(&a->flags2,
+							AF2_COREDUMP_SAVED);
+			} else if (trc->trace_func != ATTO_TRC_TF_GET_INFO) {
+				hi->status = ATTO_STS_UNSUPPORTED;
+				break;
+			}
+
+			/* Always return all the info we can. */
+			trc->trace_mask = 0;
+			trc->current_offset = 0;
+			trc->total_length = ESAS2R_FWCOREDUMP_SZ;
+
+			/* Return zero length buffer if core dump not present */
+			if (!(a->flags2 & AF2_COREDUMP_SAVED))
+				trc->total_length = 0;
+		} else {
+			hi->status = ATTO_STS_UNSUPPORTED;
+		}
+
+		break;
+	}
+
+	case ATTO_FUNC_SCSI_PASS_THRU:
+	{
+		struct atto_hba_scsi_pass_thru *spt = &hi->data.scsi_pass_thru;
+		struct scsi_lun lun;
+
+		memcpy(&lun, spt->lun, sizeof(struct scsi_lun));
+
+		if (hi->flags & HBAF_TUNNEL) {
+			if (hba_ioctl_tunnel(a, hi, rq, sgc))
+				return true;
+
+			break;
+		}
+
+		if (hi->version > ATTO_VER_SCSI_PASS_THRU0) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_SCSI_PASS_THRU0;
+			break;
+		}
+
+		if (spt->target_id >= ESAS2R_MAX_TARGETS || !check_lun(lun)) {
+			hi->status = ATTO_STS_INV_PARAM;
+			break;
+		}
+
+		esas2r_sgc_init(sgc, a, rq, NULL);
+
+		sgc->length = hi->data_length;
+		sgc->cur_offset += offsetof(struct atto_ioctl, data.byte)
+				   + sizeof(struct atto_hba_scsi_pass_thru);
+
+		/* Finish request initialization */
+		rq->target_id = (u16)spt->target_id;
+		rq->vrq->scsi.flags |= cpu_to_le32(spt->lun[1]);
+		memcpy(rq->vrq->scsi.cdb, spt->cdb, 16);
+		rq->vrq->scsi.length = cpu_to_le32(hi->data_length);
+		rq->sense_len = spt->sense_length;
+		rq->sense_buf = (u8 *)spt->sense_data;
+		/* NOTE: we ignore spt->timeout */
+
+		/*
+		 * always usurp the completion callback since the interrupt
+		 * callback mechanism may be used.
+		 */
+
+		rq->aux_req_cx = hi;
+		rq->aux_req_cb = rq->comp_cb;
+		rq->comp_cb = scsi_passthru_comp_cb;
+
+		if (spt->flags & ATTO_SPTF_DATA_IN) {
+			rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_RDD);
+		} else if (spt->flags & ATTO_SPTF_DATA_OUT) {
+			rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_WRD);
+		} else {
+			if (sgc->length) {
+				hi->status = ATTO_STS_INV_PARAM;
+				break;
+			}
+		}
+
+		if (spt->flags & ATTO_SPTF_ORDERED_Q)
+			rq->vrq->scsi.flags |=
+				cpu_to_le32(FCP_CMND_TA_ORDRD_Q);
+		else if (spt->flags & ATTO_SPTF_HEAD_OF_Q)
+			rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_TA_HEAD_Q);
+
+		if (!esas2r_build_sg_list(a, rq, sgc)) {
+			hi->status = ATTO_STS_OUT_OF_RSRC;
+			break;
+		}
+
+		esas2r_start_request(a, rq);
+
+		return true;
+	}
+
+	case ATTO_FUNC_GET_DEV_ADDR:
+	{
+		struct atto_hba_get_device_address *gda =
+			&hi->data.get_dev_addr;
+		struct esas2r_target *t;
+
+		if (hi->flags & HBAF_TUNNEL) {
+			if (hba_ioctl_tunnel(a, hi, rq, sgc))
+				return true;
+
+			break;
+		}
+
+		if (hi->version > ATTO_VER_GET_DEV_ADDR0) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_GET_DEV_ADDR0;
+			break;
+		}
+
+		if (gda->target_id >= ESAS2R_MAX_TARGETS) {
+			hi->status = ATTO_STS_INV_PARAM;
+			break;
+		}
+
+		t = a->targetdb + (u16)gda->target_id;
+
+		if (t->target_state != TS_PRESENT) {
+			hi->status = ATTO_STS_FAILED;
+		} else if (gda->addr_type == ATTO_GDA_AT_PORT) {
+			if (t->sas_addr == 0) {
+				hi->status = ATTO_STS_UNSUPPORTED;
+			} else {
+				*(u64 *)gda->address = t->sas_addr;
+
+				gda->addr_len = sizeof(u64);
+			}
+		} else if (gda->addr_type == ATTO_GDA_AT_NODE) {
+			hi->status = ATTO_STS_NOT_APPL;
+		} else {
+			hi->status = ATTO_STS_INV_PARAM;
+		}
+
+		/* update the target ID to the next one present. */
+
+		gda->target_id =
+			esas2r_targ_db_find_next_present(a,
+							 (u16)gda->target_id);
+		break;
+	}
+
+	case ATTO_FUNC_PHY_CTRL:
+	case ATTO_FUNC_CONN_CTRL:
+	{
+		if (hba_ioctl_tunnel(a, hi, rq, sgc))
+			return true;
+
+		break;
+	}
+
+	case ATTO_FUNC_ADAP_CTRL:
+	{
+		struct atto_hba_adap_ctrl *ac = &hi->data.adap_ctrl;
+
+		if (hi->flags & HBAF_TUNNEL) {
+			hi->status = ATTO_STS_UNSUPPORTED;
+			break;
+		}
+
+		if (hi->version > ATTO_VER_ADAP_CTRL0) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_ADAP_CTRL0;
+			break;
+		}
+
+		if (ac->adap_func == ATTO_AC_AF_HARD_RST) {
+			esas2r_reset_adapter(a);
+		} else if (ac->adap_func != ATTO_AC_AF_GET_STATE) {
+			hi->status = ATTO_STS_UNSUPPORTED;
+			break;
+		}
+
+		if (a->flags & AF_CHPRST_NEEDED)
+			ac->adap_state = ATTO_AC_AS_RST_SCHED;
+		else if (a->flags & AF_CHPRST_PENDING)
+			ac->adap_state = ATTO_AC_AS_RST_IN_PROG;
+		else if (a->flags & AF_DISC_PENDING)
+			ac->adap_state = ATTO_AC_AS_RST_DISC;
+		else if (a->flags & AF_DISABLED)
+			ac->adap_state = ATTO_AC_AS_DISABLED;
+		else if (a->flags & AF_DEGRADED_MODE)
+			ac->adap_state = ATTO_AC_AS_DEGRADED;
+		else
+			ac->adap_state = ATTO_AC_AS_OK;
+
+		break;
+	}
+
+	case ATTO_FUNC_GET_DEV_INFO:
+	{
+		struct atto_hba_get_device_info *gdi = &hi->data.get_dev_info;
+		struct esas2r_target *t;
+
+		if (hi->flags & HBAF_TUNNEL) {
+			if (hba_ioctl_tunnel(a, hi, rq, sgc))
+				return true;
+
+			break;
+		}
+
+		if (hi->version > ATTO_VER_GET_DEV_INFO0) {
+			hi->status = ATTO_STS_INV_VERSION;
+			hi->version = ATTO_VER_GET_DEV_INFO0;
+			break;
+		}
+
+		if (gdi->target_id >= ESAS2R_MAX_TARGETS) {
+			hi->status = ATTO_STS_INV_PARAM;
+			break;
+		}
+
+		t = a->targetdb + (u16)gdi->target_id;
+
+		/* update the target ID to the next one present. */
+
+		gdi->target_id =
+			esas2r_targ_db_find_next_present(a,
+							 (u16)gdi->target_id);
+
+		if (t->target_state != TS_PRESENT) {
+			hi->status = ATTO_STS_FAILED;
+			break;
+		}
+
+		hi->status = ATTO_STS_UNSUPPORTED;
+		break;
+	}
+
+	default:
+
+		hi->status = ATTO_STS_INV_FUNC;
+		break;
+	}
+
+	return false;
+}
+
+static void hba_ioctl_done_callback(struct esas2r_adapter *a,
+				    struct esas2r_request *rq, void *context)
+{
+	struct atto_ioctl *ioctl_hba =
+		(struct atto_ioctl *)esas2r_buffered_ioctl;
+
+	esas2r_debug("hba_ioctl_done_callback %d", a->index);
+
+	if (ioctl_hba->function == ATTO_FUNC_GET_ADAP_INFO) {
+		struct atto_hba_get_adapter_info *gai =
+			&ioctl_hba->data.get_adap_info;
+
+		esas2r_debug("ATTO_FUNC_GET_ADAP_INFO");
+
+		gai->drvr_rev_major = ESAS2R_MAJOR_REV;
+		gai->drvr_rev_minor = ESAS2R_MINOR_REV;
+
+		strcpy(gai->drvr_rev_ascii, ESAS2R_VERSION_STR);
+		strcpy(gai->drvr_name, ESAS2R_DRVR_NAME);
+
+		gai->num_busses = 1;
+		gai->num_targsper_bus = ESAS2R_MAX_ID + 1;
+		gai->num_lunsper_targ = 1;
+	}
+}
+
+u8 handle_hba_ioctl(struct esas2r_adapter *a,
+		    struct atto_ioctl *ioctl_hba)
+{
+	struct esas2r_buffered_ioctl bi;
+
+	memset(&bi, 0, sizeof(bi));
+
+	bi.a = a;
+	bi.ioctl = ioctl_hba;
+	bi.length = sizeof(struct atto_ioctl) + ioctl_hba->data_length;
+	bi.callback = hba_ioctl_callback;
+	bi.context = NULL;
+	bi.done_callback = hba_ioctl_done_callback;
+	bi.done_context = NULL;
+	bi.offset = 0;
+
+	return handle_buffered_ioctl(&bi);
+}
+
+
+int esas2r_write_params(struct esas2r_adapter *a, struct esas2r_request *rq,
+			struct esas2r_sas_nvram *data)
+{
+	int result = 0;
+
+	a->nvram_command_done = 0;
+	rq->comp_cb = complete_nvr_req;
+
+	if (esas2r_nvram_write(a, rq, data)) {
+		/* now wait around for it to complete. */
+		while (!a->nvram_command_done)
+			wait_event_interruptible(a->nvram_waiter,
+						 a->nvram_command_done);
+		;
+
+		/* done, check the status. */
+		if (rq->req_stat == RS_SUCCESS)
+			result = 1;
+	}
+	return result;
+}
+
+
+/* This function only cares about ATTO-specific ioctls (atto_express_ioctl) */
+int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
+{
+	struct atto_express_ioctl *ioctl = NULL;
+	struct esas2r_adapter *a;
+	struct esas2r_request *rq;
+	u16 code;
+	int err;
+
+	esas2r_log(ESAS2R_LOG_DEBG, "ioctl (%p, %x, %p)", hostdata, cmd, arg);
+
+	if ((arg == NULL)
+	    || (cmd < EXPRESS_IOCTL_MIN)
+	    || (cmd > EXPRESS_IOCTL_MAX))
+		return -ENOTSUPP;
+
+	if (!access_ok(VERIFY_WRITE, arg, sizeof(struct atto_express_ioctl))) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "ioctl_handler access_ok failed for cmd %d, "
+			   "address %p", cmd,
+			   arg);
+		return -EFAULT;
+	}
+
+	/* allocate a kernel memory buffer for the IOCTL data */
+	ioctl = kzalloc(sizeof(struct atto_express_ioctl), GFP_KERNEL);
+	if (ioctl == NULL) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "ioctl_handler kzalloc failed for %d bytes",
+			   sizeof(struct atto_express_ioctl));
+		return -ENOMEM;
+	}
+
+	err = __copy_from_user(ioctl, arg, sizeof(struct atto_express_ioctl));
+	if (err != 0) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "copy_from_user didn't copy everything (err %d, cmd %d)",
+			   err,
+			   cmd);
+		kfree(ioctl);
+
+		return -EFAULT;
+	}
+
+	/* verify the signature */
+
+	if (memcmp(ioctl->header.signature,
+		   EXPRESS_IOCTL_SIGNATURE,
+		   EXPRESS_IOCTL_SIGNATURE_SIZE) != 0) {
+		esas2r_log(ESAS2R_LOG_WARN, "invalid signature");
+		kfree(ioctl);
+
+		return -ENOTSUPP;
+	}
+
+	/* assume success */
+
+	ioctl->header.return_code = IOCTL_SUCCESS;
+	err = 0;
+
+	/*
+	 * handle EXPRESS_IOCTL_GET_CHANNELS
+	 * without paying attention to channel
+	 */
+
+	if (cmd == EXPRESS_IOCTL_GET_CHANNELS) {
+		int i = 0, k = 0;
+
+		ioctl->data.chanlist.num_channels = 0;
+
+		while (i < MAX_ADAPTERS) {
+			if (esas2r_adapters[i]) {
+				ioctl->data.chanlist.num_channels++;
+				ioctl->data.chanlist.channel[k] = i;
+				k++;
+			}
+			i++;
+		}
+
+		goto ioctl_done;
+	}
+
+	/* get the channel */
+
+	if (ioctl->header.channel == 0xFF) {
+		a = (struct esas2r_adapter *)hostdata;
+	} else {
+		a = esas2r_adapters[ioctl->header.channel];
+		if (ioctl->header.channel >= MAX_ADAPTERS || (a == NULL)) {
+			ioctl->header.return_code = IOCTL_BAD_CHANNEL;
+			esas2r_log(ESAS2R_LOG_WARN, "bad channel value");
+			kfree(ioctl);
+
+			return -ENOTSUPP;
+		}
+	}
+
+	switch (cmd) {
+	case EXPRESS_IOCTL_RW_FIRMWARE:
+
+		if (ioctl->data.fwrw.img_type == FW_IMG_FM_API) {
+			err = esas2r_write_fw(a,
+					      (char *)ioctl->data.fwrw.image,
+					      0,
+					      sizeof(struct
+						     atto_express_ioctl));
+
+			if (err >= 0) {
+				err = esas2r_read_fw(a,
+						     (char *)ioctl->data.fwrw.
+						     image,
+						     0,
+						     sizeof(struct
+							    atto_express_ioctl));
+			}
+		} else if (ioctl->data.fwrw.img_type == FW_IMG_FS_API) {
+			err = esas2r_write_fs(a,
+					      (char *)ioctl->data.fwrw.image,
+					      0,
+					      sizeof(struct
+						     atto_express_ioctl));
+
+			if (err >= 0) {
+				err = esas2r_read_fs(a,
+						     (char *)ioctl->data.fwrw.
+						     image,
+						     0,
+						     sizeof(struct
+							    atto_express_ioctl));
+			}
+		} else {
+			ioctl->header.return_code = IOCTL_BAD_FLASH_IMGTYPE;
+		}
+
+		break;
+
+	case EXPRESS_IOCTL_READ_PARAMS:
+
+		memcpy(ioctl->data.prw.data_buffer, a->nvram,
+		       sizeof(struct esas2r_sas_nvram));
+		ioctl->data.prw.code = 1;
+		break;
+
+	case EXPRESS_IOCTL_WRITE_PARAMS:
+
+		rq = esas2r_alloc_request(a);
+		if (rq == NULL) {
+			up(&a->nvram_semaphore);
+			ioctl->data.prw.code = 0;
+			break;
+		}
+
+		code = esas2r_write_params(a, rq,
+					   (struct esas2r_sas_nvram *)ioctl->data.prw.data_buffer);
+		ioctl->data.prw.code = code;
+
+		esas2r_free_request(a, rq);
+
+		break;
+
+	case EXPRESS_IOCTL_DEFAULT_PARAMS:
+
+		esas2r_nvram_get_defaults(a,
+					  (struct esas2r_sas_nvram *)ioctl->data.prw.data_buffer);
+		ioctl->data.prw.code = 1;
+		break;
+
+	case EXPRESS_IOCTL_CHAN_INFO:
+
+		ioctl->data.chaninfo.major_rev = ESAS2R_MAJOR_REV;
+		ioctl->data.chaninfo.minor_rev = ESAS2R_MINOR_REV;
+		ioctl->data.chaninfo.IRQ = a->pcid->irq;
+		ioctl->data.chaninfo.device_id = a->pcid->device;
+		ioctl->data.chaninfo.vendor_id = a->pcid->vendor;
+		ioctl->data.chaninfo.ven_dev_id = a->pcid->subsystem_device;
+		ioctl->data.chaninfo.revision_id = a->pcid->revision;
+		ioctl->data.chaninfo.pci_bus = a->pcid->bus->number;
+		ioctl->data.chaninfo.pci_dev_func = a->pcid->devfn;
+		ioctl->data.chaninfo.core_rev = 0;
+		ioctl->data.chaninfo.host_no = a->host->host_no;
+		ioctl->data.chaninfo.hbaapi_rev = 0;
+		break;
+
+	case EXPRESS_IOCTL_SMP:
+		ioctl->header.return_code = handle_smp_ioctl(a,
+							     &ioctl->data.
+							     ioctl_smp);
+		break;
+
+	case EXPRESS_CSMI:
+		ioctl->header.return_code =
+			handle_csmi_ioctl(a, &ioctl->data.csmi);
+		break;
+
+	case EXPRESS_IOCTL_HBA:
+		ioctl->header.return_code = handle_hba_ioctl(a,
+							     &ioctl->data.
+							     ioctl_hba);
+		break;
+
+	case EXPRESS_IOCTL_VDA:
+		err = esas2r_write_vda(a,
+				       (char *)&ioctl->data.ioctl_vda,
+				       0,
+				       sizeof(struct atto_ioctl_vda) +
+				       ioctl->data.ioctl_vda.data_length);
+
+		if (err >= 0) {
+			err = esas2r_read_vda(a,
+					      (char *)&ioctl->data.ioctl_vda,
+					      0,
+					      sizeof(struct atto_ioctl_vda) +
+					      ioctl->data.ioctl_vda.data_length);
+		}
+
+
+
+
+		break;
+
+	case EXPRESS_IOCTL_GET_MOD_INFO:
+
+		ioctl->data.modinfo.adapter = a;
+		ioctl->data.modinfo.pci_dev = a->pcid;
+		ioctl->data.modinfo.scsi_host = a->host;
+		ioctl->data.modinfo.host_no = a->host->host_no;
+
+		break;
+
+	default:
+		esas2r_debug("esas2r_ioctl invalid cmd %p!", cmd);
+		ioctl->header.return_code = IOCTL_ERR_INVCMD;
+	}
+
+ioctl_done:
+
+	if (err < 0) {
+		esas2r_log(ESAS2R_LOG_WARN, "err %d on ioctl cmd %d", err,
+			   cmd);
+
+		switch (err) {
+		case -ENOMEM:
+		case -EBUSY:
+			ioctl->header.return_code = IOCTL_OUT_OF_RESOURCES;
+			break;
+
+		case -ENOSYS:
+		case -EINVAL:
+			ioctl->header.return_code = IOCTL_INVALID_PARAM;
+			break;
+		}
+
+		ioctl->header.return_code = IOCTL_GENERAL_ERROR;
+	}
+
+	/* Always copy the buffer back, if only to pick up the status */
+	err = __copy_to_user(arg, ioctl, sizeof(struct atto_express_ioctl));
+	if (err != 0) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "ioctl_handler copy_to_user didn't copy "
+			   "everything (err %d, cmd %d)", err,
+			   cmd);
+		kfree(ioctl);
+
+		return -EFAULT;
+	}
+
+	kfree(ioctl);
+
+	return 0;
+}
+
+int esas2r_ioctl(struct scsi_device *sd, int cmd, void __user *arg)
+{
+	return esas2r_ioctl_handler(sd->host->hostdata, cmd, arg);
+}
+
+static void free_fw_buffers(struct esas2r_adapter *a)
+{
+	if (a->firmware.data) {
+		dma_free_coherent(&a->pcid->dev,
+				  (size_t)a->firmware.orig_len,
+				  a->firmware.data,
+				  (dma_addr_t)a->firmware.phys);
+
+		a->firmware.data = NULL;
+	}
+}
+
+static int allocate_fw_buffers(struct esas2r_adapter *a, u32 length)
+{
+	free_fw_buffers(a);
+
+	a->firmware.orig_len = length;
+
+	a->firmware.data = (u8 *)dma_alloc_coherent(&a->pcid->dev,
+						    (size_t)length,
+						    (dma_addr_t *)&a->firmware.
+						    phys,
+						    GFP_KERNEL);
+
+	if (!a->firmware.data) {
+		esas2r_debug("buffer alloc failed!");
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Handle a call to read firmware. */
+int esas2r_read_fw(struct esas2r_adapter *a, char *buf, long off, int count)
+{
+	esas2r_trace_enter();
+	/* if the cached header is a status, simply copy it over and return. */
+	if (a->firmware.state == FW_STATUS_ST) {
+		int size = min_t(int, count, sizeof(a->firmware.header));
+		esas2r_trace_exit();
+		memcpy(buf, &a->firmware.header, size);
+		esas2r_debug("esas2r_read_fw: STATUS size %d", size);
+		return size;
+	}
+
+	/*
+	 * if the cached header is a command, do it if at
+	 * offset 0, otherwise copy the pieces.
+	 */
+
+	if (a->firmware.state == FW_COMMAND_ST) {
+		u32 length = a->firmware.header.length;
+		esas2r_trace_exit();
+
+		esas2r_debug("esas2r_read_fw: COMMAND length %d off %d",
+			     length,
+			     off);
+
+		if (off == 0) {
+			if (a->firmware.header.action == FI_ACT_UP) {
+				if (!allocate_fw_buffers(a, length))
+					return -ENOMEM;
+
+
+				/* copy header over */
+
+				memcpy(a->firmware.data,
+				       &a->firmware.header,
+				       sizeof(a->firmware.header));
+
+				do_fm_api(a,
+					  (struct esas2r_flash_img *)a->firmware.data);
+			} else if (a->firmware.header.action == FI_ACT_UPSZ) {
+				int size =
+					min((int)count,
+					    (int)sizeof(a->firmware.header));
+				do_fm_api(a, &a->firmware.header);
+				memcpy(buf, &a->firmware.header, size);
+				esas2r_debug("FI_ACT_UPSZ size %d", size);
+				return size;
+			} else {
+				esas2r_debug("invalid action %d",
+					     a->firmware.header.action);
+				return -ENOSYS;
+			}
+		}
+
+		if (count + off > length)
+			count = length - off;
+
+		if (count < 0)
+			return 0;
+
+		if (!a->firmware.data) {
+			esas2r_debug(
+				"read: nonzero offset but no buffer available!");
+			return -ENOMEM;
+		}
+
+		esas2r_debug("esas2r_read_fw: off %d count %d length %d ", off,
+			     count,
+			     length);
+
+		memcpy(buf, &a->firmware.data[off], count);
+
+		/* when done, release the buffer */
+
+		if (length <= off + count) {
+			esas2r_debug("esas2r_read_fw: freeing buffer!");
+
+			free_fw_buffers(a);
+		}
+
+		return count;
+	}
+
+	esas2r_trace_exit();
+	esas2r_debug("esas2r_read_fw: invalid firmware state %d",
+		     a->firmware.state);
+
+	return -EINVAL;
+}
+
+/* Handle a call to write firmware. */
+int esas2r_write_fw(struct esas2r_adapter *a, const char *buf, long off,
+		    int count)
+{
+	u32 length;
+
+	if (off == 0) {
+		struct esas2r_flash_img *header =
+			(struct esas2r_flash_img *)buf;
+
+		/* assume version 0 flash image */
+
+		int min_size = sizeof(struct esas2r_flash_img_v0);
+
+		a->firmware.state = FW_INVALID_ST;
+
+		/* validate the version field first */
+
+		if (count < 4
+		    ||  header->fi_version > FI_VERSION_1) {
+			esas2r_debug(
+				"esas2r_write_fw: short header or invalid version");
+			return -EINVAL;
+		}
+
+		/* See if its a version 1 flash image */
+
+		if (header->fi_version == FI_VERSION_1)
+			min_size = sizeof(struct esas2r_flash_img);
+
+		/* If this is the start, the header must be full and valid. */
+		if (count < min_size) {
+			esas2r_debug("esas2r_write_fw: short header, aborting");
+			return -EINVAL;
+		}
+
+		/* Make sure the size is reasonable. */
+		length = header->length;
+
+		if (length > 1024 * 1024) {
+			esas2r_debug(
+				"esas2r_write_fw: hosed, length %d  fi_version %d",
+				length, header->fi_version);
+			return -EINVAL;
+		}
+
+		/*
+		 * If this is a write command, allocate memory because
+		 * we have to cache everything. otherwise, just cache
+		 * the header, because the read op will do the command.
+		 */
+
+		if (header->action == FI_ACT_DOWN) {
+			if (!allocate_fw_buffers(a, length))
+				return -ENOMEM;
+
+			/*
+			 * Store the command, so there is context on subsequent
+			 * calls.
+			 */
+			memcpy(&a->firmware.header,
+			       buf,
+			       sizeof(*header));
+		} else if (header->action == FI_ACT_UP
+			   ||  header->action == FI_ACT_UPSZ) {
+			/* Save the command, result will be picked up on read */
+			memcpy(&a->firmware.header,
+			       buf,
+			       sizeof(*header));
+
+			a->firmware.state = FW_COMMAND_ST;
+
+			esas2r_debug(
+				"esas2r_write_fw: COMMAND, count %d, action %d ",
+				count, header->action);
+
+			/*
+			 * Pretend we took the whole buffer,
+			 * so we don't get bothered again.
+			 */
+
+			return count;
+		} else {
+			esas2r_debug("esas2r_write_fw: invalid action %d ",
+				     a->firmware.header.action);
+			return -ENOSYS;
+		}
+	} else {
+		length = a->firmware.header.length;
+	}
+
+	/*
+	 * We only get here on a download command, regardless of offset.
+	 * the chunks written by the system need to be cached, and when
+	 * the final one arrives, issue the fmapi command.
+	 */
+
+	if (off + count > length)
+		count = length - off;
+
+	if (count > 0) {
+		esas2r_debug("esas2r_write_fw: off %d count %d length %d", off,
+			     count,
+			     length);
+
+		/*
+		 * On a full upload, the system tries sending the whole buffer.
+		 * there's nothing to do with it, so just drop it here, before
+		 * trying to copy over into unallocated memory!
+		 */
+		if (a->firmware.header.action == FI_ACT_UP)
+			return count;
+
+		if (!a->firmware.data) {
+			esas2r_debug(
+				"write: nonzero offset but no buffer available!");
+			return -ENOMEM;
+		}
+
+		memcpy(&a->firmware.data[off], buf, count);
+
+		if (length == off + count) {
+			do_fm_api(a,
+				  (struct esas2r_flash_img *)a->firmware.data);
+
+			/*
+			 * Now copy the header result to be picked up by the
+			 * next read
+			 */
+			memcpy(&a->firmware.header,
+			       a->firmware.data,
+			       sizeof(a->firmware.header));
+
+			a->firmware.state = FW_STATUS_ST;
+
+			esas2r_debug("write completed");
+
+			/*
+			 * Since the system has the data buffered, the only way
+			 * this can leak is if a root user writes a program
+			 * that writes a shorter buffer than it claims, and the
+			 * copyin fails.
+			 */
+			free_fw_buffers(a);
+		}
+	}
+
+	return count;
+}
+
+/* Callback for the completion of a VDA request. */
+static void vda_complete_req(struct esas2r_adapter *a,
+			     struct esas2r_request *rq)
+{
+	a->vda_command_done = 1;
+	wake_up_interruptible(&a->vda_waiter);
+}
+
+/* Scatter/gather callback for VDA requests */
+static u32 get_physaddr_vda(struct esas2r_sg_context *sgc, u64 *addr)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+	int offset = (u8 *)sgc->cur_offset - (u8 *)a->vda_buffer;
+
+	(*addr) = a->ppvda_buffer + offset;
+	return VDA_MAX_BUFFER_SIZE - offset;
+}
+
+/* Handle a call to read a VDA command. */
+int esas2r_read_vda(struct esas2r_adapter *a, char *buf, long off, int count)
+{
+	if (!a->vda_buffer)
+		return -ENOMEM;
+
+	if (off == 0) {
+		struct esas2r_request *rq;
+		struct atto_ioctl_vda *vi =
+			(struct atto_ioctl_vda *)a->vda_buffer;
+		struct esas2r_sg_context sgc;
+		bool wait_for_completion;
+
+		/*
+		 * Presumeably, someone has already written to the vda_buffer,
+		 * and now they are reading the node the response, so now we
+		 * will actually issue the request to the chip and reply.
+		 */
+
+		/* allocate a request */
+		rq = esas2r_alloc_request(a);
+		if (rq == NULL) {
+			esas2r_debug("esas2r_read_vda: out of requestss");
+			return -EBUSY;
+		}
+
+		rq->comp_cb = vda_complete_req;
+
+		sgc.first_req = rq;
+		sgc.adapter = a;
+		sgc.cur_offset = a->vda_buffer + VDA_BUFFER_HEADER_SZ;
+		sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_vda;
+
+		a->vda_command_done = 0;
+
+		wait_for_completion =
+			esas2r_process_vda_ioctl(a, vi, rq, &sgc);
+
+		if (wait_for_completion) {
+			/* now wait around for it to complete. */
+
+			while (!a->vda_command_done)
+				wait_event_interruptible(a->vda_waiter,
+							 a->vda_command_done);
+		}
+
+		esas2r_free_request(a, (struct esas2r_request *)rq);
+	}
+
+	if (off > VDA_MAX_BUFFER_SIZE)
+		return 0;
+
+	if (count + off > VDA_MAX_BUFFER_SIZE)
+		count = VDA_MAX_BUFFER_SIZE - off;
+
+	if (count < 0)
+		return 0;
+
+	memcpy(buf, a->vda_buffer + off, count);
+
+	return count;
+}
+
+/* Handle a call to write a VDA command. */
+int esas2r_write_vda(struct esas2r_adapter *a, const char *buf, long off,
+		     int count)
+{
+	/*
+	 * allocate memory for it, if not already done.  once allocated,
+	 * we will keep it around until the driver is unloaded.
+	 */
+
+	if (!a->vda_buffer) {
+		dma_addr_t dma_addr;
+		a->vda_buffer = (u8 *)dma_alloc_coherent(&a->pcid->dev,
+							 (size_t)
+							 VDA_MAX_BUFFER_SIZE,
+							 &dma_addr,
+							 GFP_KERNEL);
+
+		a->ppvda_buffer = dma_addr;
+	}
+
+	if (!a->vda_buffer)
+		return -ENOMEM;
+
+	if (off > VDA_MAX_BUFFER_SIZE)
+		return 0;
+
+	if (count + off > VDA_MAX_BUFFER_SIZE)
+		count = VDA_MAX_BUFFER_SIZE - off;
+
+	if (count < 1)
+		return 0;
+
+	memcpy(a->vda_buffer + off, buf, count);
+
+	return count;
+}
+
+/* Callback for the completion of an FS_API request.*/
+static void fs_api_complete_req(struct esas2r_adapter *a,
+				struct esas2r_request *rq)
+{
+	a->fs_api_command_done = 1;
+
+	wake_up_interruptible(&a->fs_api_waiter);
+}
+
+/* Scatter/gather callback for VDA requests */
+static u32 get_physaddr_fs_api(struct esas2r_sg_context *sgc, u64 *addr)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)sgc->adapter;
+	struct esas2r_ioctl_fs *fs =
+		(struct esas2r_ioctl_fs *)a->fs_api_buffer;
+	u32 offset = (u8 *)sgc->cur_offset - (u8 *)fs;
+
+	(*addr) = a->ppfs_api_buffer + offset;
+
+	return a->fs_api_buffer_size - offset;
+}
+
+/* Handle a call to read firmware via FS_API. */
+int esas2r_read_fs(struct esas2r_adapter *a, char *buf, long off, int count)
+{
+	if (!a->fs_api_buffer)
+		return -ENOMEM;
+
+	if (off == 0) {
+		struct esas2r_request *rq;
+		struct esas2r_sg_context sgc;
+		struct esas2r_ioctl_fs *fs =
+			(struct esas2r_ioctl_fs *)a->fs_api_buffer;
+
+		/* If another flash request is already in progress, return. */
+		if (down_interruptible(&a->fs_api_semaphore)) {
+busy:
+			fs->status = ATTO_STS_OUT_OF_RSRC;
+			return -EBUSY;
+		}
+
+		/*
+		 * Presumeably, someone has already written to the
+		 * fs_api_buffer, and now they are reading the node the
+		 * response, so now we will actually issue the request to the
+		 * chip and reply. Allocate a request
+		 */
+
+		rq = esas2r_alloc_request(a);
+		if (rq == NULL) {
+			esas2r_debug("esas2r_read_fs: out of requests");
+			up(&a->fs_api_semaphore);
+			goto busy;
+		}
+
+		rq->comp_cb = fs_api_complete_req;
+
+		/* Set up the SGCONTEXT for to build the s/g table */
+
+		sgc.cur_offset = fs->data;
+		sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_fs_api;
+
+		a->fs_api_command_done = 0;
+
+		if (!esas2r_process_fs_ioctl(a, fs, rq, &sgc)) {
+			if (fs->status == ATTO_STS_OUT_OF_RSRC)
+				count = -EBUSY;
+
+			goto dont_wait;
+		}
+
+		/* Now wait around for it to complete. */
+
+		while (!a->fs_api_command_done)
+			wait_event_interruptible(a->fs_api_waiter,
+						 a->fs_api_command_done);
+		;
+dont_wait:
+		/* Free the request and keep going */
+		up(&a->fs_api_semaphore);
+		esas2r_free_request(a, (struct esas2r_request *)rq);
+
+		/* Pick up possible error code from above */
+		if (count < 0)
+			return count;
+	}
+
+	if (off > a->fs_api_buffer_size)
+		return 0;
+
+	if (count + off > a->fs_api_buffer_size)
+		count = a->fs_api_buffer_size - off;
+
+	if (count < 0)
+		return 0;
+
+	memcpy(buf, a->fs_api_buffer + off, count);
+
+	return count;
+}
+
+/* Handle a call to write firmware via FS_API. */
+int esas2r_write_fs(struct esas2r_adapter *a, const char *buf, long off,
+		    int count)
+{
+	if (off == 0) {
+		struct esas2r_ioctl_fs *fs = (struct esas2r_ioctl_fs *)buf;
+		u32 length = fs->command.length + offsetof(
+			struct esas2r_ioctl_fs,
+			data);
+
+		/*
+		 * Special case, for BEGIN commands, the length field
+		 * is lying to us, so just get enough for the header.
+		 */
+
+		if (fs->command.command == ESAS2R_FS_CMD_BEGINW)
+			length = offsetof(struct esas2r_ioctl_fs, data);
+
+		/*
+		 * Beginning a command.  We assume we'll get at least
+		 * enough in the first write so we can look at the
+		 * header and see how much we need to alloc.
+		 */
+
+		if (count < offsetof(struct esas2r_ioctl_fs, data))
+			return -EINVAL;
+
+		/* Allocate a buffer or use the existing buffer. */
+		if (a->fs_api_buffer) {
+			if (a->fs_api_buffer_size < length) {
+				/* Free too-small buffer and get a new one */
+				dma_free_coherent(&a->pcid->dev,
+						  (size_t)a->fs_api_buffer_size,
+						  a->fs_api_buffer,
+						  (dma_addr_t)a->ppfs_api_buffer);
+
+				goto re_allocate_buffer;
+			}
+		} else {
+re_allocate_buffer:
+			a->fs_api_buffer_size = length;
+
+			a->fs_api_buffer = (u8 *)dma_alloc_coherent(
+				&a->pcid->dev,
+				(size_t)a->fs_api_buffer_size,
+				(dma_addr_t *)&a->ppfs_api_buffer,
+				GFP_KERNEL);
+		}
+	}
+
+	if (!a->fs_api_buffer)
+		return -ENOMEM;
+
+	if (off > a->fs_api_buffer_size)
+		return 0;
+
+	if (count + off > a->fs_api_buffer_size)
+		count = a->fs_api_buffer_size - off;
+
+	if (count < 1)
+		return 0;
+
+	memcpy(a->fs_api_buffer + off, buf, count);
+
+	return count;
+}
diff --git a/drivers/scsi/esas2r/esas2r_log.c b/drivers/scsi/esas2r/esas2r_log.c
new file mode 100644
index 0000000..9bf285d
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_log.c
@@ -0,0 +1,254 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_log.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+/*
+ * this module within the driver is tasked with providing logging functionality.
+ * the event_log_level module parameter controls the level of messages that are
+ * written to the system log.  the default level of messages that are written
+ * are critical and warning messages.  if other types of messages are desired,
+ * one simply needs to load the module with the correct value for the
+ * event_log_level module parameter.  for example:
+ *
+ * insmod <module> event_log_level=1
+ *
+ * will load the module and only critical events will be written by this module
+ * to the system log.  if critical, warning, and information-level messages are
+ * desired, the correct value for the event_log_level module parameter
+ * would be as follows:
+ *
+ * insmod <module> event_log_level=3
+ */
+
+#define EVENT_LOG_BUFF_SIZE 1024
+
+static long event_log_level = ESAS2R_LOG_DFLT;
+
+module_param(event_log_level, long, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(event_log_level,
+		 "Specifies the level of events to report to the system log.  Critical and warning level events are logged by default.");
+
+/* A shared buffer to use for formatting messages. */
+static char event_buffer[EVENT_LOG_BUFF_SIZE];
+
+/* A lock to protect the shared buffer used for formatting messages. */
+static DEFINE_SPINLOCK(event_buffer_lock);
+
+/**
+ * translates an esas2r-defined logging event level to a kernel logging level.
+ *
+ * @param [in] level the esas2r-defined logging event level to translate
+ *
+ * @return the corresponding kernel logging level.
+ */
+static const char *translate_esas2r_event_level_to_kernel(const long level)
+{
+	switch (level) {
+	case ESAS2R_LOG_CRIT:
+		return KERN_CRIT;
+
+	case ESAS2R_LOG_WARN:
+		return KERN_WARNING;
+
+	case ESAS2R_LOG_INFO:
+		return KERN_INFO;
+
+	case ESAS2R_LOG_DEBG:
+	case ESAS2R_LOG_TRCE:
+	default:
+		return KERN_DEBUG;
+	}
+}
+
+/**
+ * the master logging function.  this function will format the message as
+ * outlined by the formatting string, the input device information and the
+ * substitution arguments and output the resulting string to the system log.
+ *
+ * @param [in] level  the event log level of the message
+ * @param [in] dev    the device information
+ * @param [in] format the formatting string for the message
+ * @param [in] args   the substition arguments to the formatting string
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+static int esas2r_log_master(const long level,
+			     const struct device *dev,
+			     const char *format,
+			     va_list args)
+{
+	if (level <= event_log_level) {
+		unsigned long flags = 0;
+		int retval = 0;
+		char *buffer = event_buffer;
+		size_t buflen = EVENT_LOG_BUFF_SIZE;
+		const char *fmt_nodev = "%s%s: ";
+		const char *fmt_dev = "%s%s [%s, %s, %s]";
+		const char *slevel =
+			translate_esas2r_event_level_to_kernel(level);
+
+		spin_lock_irqsave(&event_buffer_lock, flags);
+
+		if (buffer == NULL) {
+			spin_unlock_irqrestore(&event_buffer_lock, flags);
+			return -1;
+		}
+
+		memset(buffer, 0, buflen);
+
+		/*
+		 * format the level onto the beginning of the string and do
+		 * some pointer arithmetic to move the pointer to the point
+		 * where the actual message can be inserted.
+		 */
+
+		if (dev == NULL) {
+			snprintf(buffer, buflen, fmt_nodev, slevel,
+				 ESAS2R_DRVR_NAME);
+		} else {
+			snprintf(buffer, buflen, fmt_dev, slevel,
+				 ESAS2R_DRVR_NAME,
+				 (dev->driver ? dev->driver->name : "unknown"),
+				 (dev->bus ? dev->bus->name : "unknown"),
+				 dev_name(dev));
+		}
+
+		buffer += strlen(event_buffer);
+		buflen -= strlen(event_buffer);
+
+		retval = vsnprintf(buffer, buflen, format, args);
+		if (retval < 0) {
+			spin_unlock_irqrestore(&event_buffer_lock, flags);
+			return -1;
+		}
+
+		/*
+		 * Put a line break at the end of the formatted string so that
+		 * we don't wind up with run-on messages.  only append if there
+		 * is enough space in the buffer.
+		 */
+		if (strlen(event_buffer) < buflen)
+			strcat(buffer, "\n");
+
+		printk(event_buffer);
+
+		spin_unlock_irqrestore(&event_buffer_lock, flags);
+	}
+
+	return 0;
+}
+
+/**
+ * formats and logs a message to the system log.
+ *
+ * @param [in] level  the event level of the message
+ * @param [in] format the formating string for the message
+ * @param [in] ...    the substitution arguments to the formatting string
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+int esas2r_log(const long level, const char *format, ...)
+{
+	int retval = 0;
+	va_list args;
+
+	va_start(args, format);
+
+	retval = esas2r_log_master(level, NULL, format, args);
+
+	va_end(args);
+
+	return retval;
+}
+
+/**
+ * formats and logs a message to the system log.  this message will include
+ * device information.
+ *
+ * @param [in] level   the event level of the message
+ * @param [in] dev     the device information
+ * @param [in] format  the formatting string for the message
+ * @param [in] ...     the substitution arguments to the formatting string
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+int esas2r_log_dev(const long level,
+		   const struct device *dev,
+		   const char *format,
+		   ...)
+{
+	int retval = 0;
+	va_list args;
+
+	va_start(args, format);
+
+	retval = esas2r_log_master(level, dev, format, args);
+
+	va_end(args);
+
+	return retval;
+}
+
+/**
+ * formats and logs a message to the system log.  this message will include
+ * device information.
+ *
+ * @param [in] level   the event level of the message
+ * @param [in] buf
+ * @param [in] len
+ *
+ * @return 0 on success, or -1 if an error occurred.
+ */
+int esas2r_log_hexdump(const long level,
+		       const void *buf,
+		       size_t len)
+{
+	if (level <= event_log_level) {
+		print_hex_dump(translate_esas2r_event_level_to_kernel(level),
+			       "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+			       len, true);
+	}
+
+	return 1;
+}
diff --git a/drivers/scsi/esas2r/esas2r_log.h b/drivers/scsi/esas2r/esas2r_log.h
new file mode 100644
index 0000000..7b6397b
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_log.h
@@ -0,0 +1,118 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_log.h
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#ifndef __esas2r_log_h__
+#define __esas2r_log_h__
+
+struct device;
+
+enum {
+	ESAS2R_LOG_NONE = 0,    /* no events logged */
+	ESAS2R_LOG_CRIT = 1,    /* critical events  */
+	ESAS2R_LOG_WARN = 2,    /* warning events   */
+	ESAS2R_LOG_INFO = 3,    /* info events      */
+	ESAS2R_LOG_DEBG = 4,    /* debugging events */
+	ESAS2R_LOG_TRCE = 5,    /* tracing events   */
+
+#ifdef ESAS2R_TRACE
+	ESAS2R_LOG_DFLT = ESAS2R_LOG_TRCE
+#else
+	ESAS2R_LOG_DFLT = ESAS2R_LOG_WARN
+#endif
+};
+
+int esas2r_log(const long level, const char *format, ...);
+int esas2r_log_dev(const long level,
+		   const struct device *dev,
+		   const char *format,
+		   ...);
+int esas2r_log_hexdump(const long level,
+		       const void *buf,
+		       size_t len);
+
+/*
+ * the following macros are provided specifically for debugging and tracing
+ * messages.  esas2r_debug() is provided for generic non-hardware layer
+ * debugging and tracing events.  esas2r_hdebug is provided specifically for
+ * hardware layer debugging and tracing events.
+ */
+
+#ifdef ESAS2R_DEBUG
+#define esas2r_debug(f, args ...) esas2r_log(ESAS2R_LOG_DEBG, f, ## args)
+#define esas2r_hdebug(f, args ...) esas2r_log(ESAS2R_LOG_DEBG, f, ## args)
+#else
+#define esas2r_debug(f, args ...)
+#define esas2r_hdebug(f, args ...)
+#endif  /* ESAS2R_DEBUG */
+
+/*
+ * the following macros are provided in order to trace the driver and catch
+ * some more serious bugs.  be warned, enabling these macros may *severely*
+ * impact performance.
+ */
+
+#ifdef ESAS2R_TRACE
+#define esas2r_bugon() \
+	do { \
+		esas2r_log(ESAS2R_LOG_TRCE, "esas2r_bugon() called in %s:%d" \
+			   " - dumping stack and stopping kernel", __func__, \
+			   __LINE__); \
+		dump_stack(); \
+		BUG(); \
+	} while (0)
+
+#define esas2r_trace_enter() esas2r_log(ESAS2R_LOG_TRCE, "entered %s (%s:%d)", \
+					__func__, __FILE__, __LINE__)
+#define esas2r_trace_exit() esas2r_log(ESAS2R_LOG_TRCE, "exited %s (%s:%d)", \
+				       __func__, __FILE__, __LINE__)
+#define esas2r_trace(f, args ...) esas2r_log(ESAS2R_LOG_TRCE, "(%s:%s:%d): " \
+					     f, __func__, __FILE__, __LINE__, \
+					     ## args)
+#else
+#define esas2r_bugon()
+#define esas2r_trace_enter()
+#define esas2r_trace_exit()
+#define esas2r_trace(f, args ...)
+#endif  /* ESAS2R_TRACE */
+
+#endif  /* __esas2r_log_h__ */
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
new file mode 100644
index 0000000..4abf127
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -0,0 +1,2032 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_main.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+MODULE_DESCRIPTION(ESAS2R_DRVR_NAME ": " ESAS2R_LONGNAME " driver");
+MODULE_AUTHOR("ATTO Technology, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ESAS2R_VERSION_STR);
+
+/* global definitions */
+
+static int found_adapters;
+struct esas2r_adapter *esas2r_adapters[MAX_ADAPTERS];
+
+#define ESAS2R_VDA_EVENT_PORT1       54414
+#define ESAS2R_VDA_EVENT_PORT2       54415
+#define ESAS2R_VDA_EVENT_SOCK_COUNT  2
+
+static struct esas2r_adapter *esas2r_adapter_from_kobj(struct kobject *kobj)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct Scsi_Host *host = class_to_shost(dev);
+
+	return (struct esas2r_adapter *)host->hostdata;
+}
+
+static ssize_t read_fw(struct file *file, struct kobject *kobj,
+		       struct bin_attribute *attr,
+		       char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+	return esas2r_read_fw(a, buf, off, count);
+}
+
+static ssize_t write_fw(struct file *file, struct kobject *kobj,
+			struct bin_attribute *attr,
+			char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+	return esas2r_write_fw(a, buf, off, count);
+}
+
+static ssize_t read_fs(struct file *file, struct kobject *kobj,
+		       struct bin_attribute *attr,
+		       char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+	return esas2r_read_fs(a, buf, off, count);
+}
+
+static ssize_t write_fs(struct file *file, struct kobject *kobj,
+			struct bin_attribute *attr,
+			char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+	int length = min(sizeof(struct esas2r_ioctl_fs), count);
+	int result = 0;
+
+	result = esas2r_write_fs(a, buf, off, count);
+
+	if (result < 0)
+		result = 0;
+
+	return length;
+}
+
+static ssize_t read_vda(struct file *file, struct kobject *kobj,
+			struct bin_attribute *attr,
+			char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+	return esas2r_read_vda(a, buf, off, count);
+}
+
+static ssize_t write_vda(struct file *file, struct kobject *kobj,
+			 struct bin_attribute *attr,
+			 char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+	return esas2r_write_vda(a, buf, off, count);
+}
+
+static ssize_t read_live_nvram(struct file *file, struct kobject *kobj,
+			       struct bin_attribute *attr,
+			       char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+	int length = min_t(size_t, sizeof(struct esas2r_sas_nvram), PAGE_SIZE);
+
+	memcpy(buf, a->nvram, length);
+	return length;
+}
+
+static ssize_t write_live_nvram(struct file *file, struct kobject *kobj,
+				struct bin_attribute *attr,
+				char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+	struct esas2r_request *rq;
+	int result = -EFAULT;
+
+	rq = esas2r_alloc_request(a);
+	if (rq == NULL)
+		return -ENOMEM;
+
+	if (esas2r_write_params(a, rq, (struct esas2r_sas_nvram *)buf))
+		result = count;
+
+	esas2r_free_request(a, rq);
+
+	return result;
+}
+
+static ssize_t read_default_nvram(struct file *file, struct kobject *kobj,
+				  struct bin_attribute *attr,
+				  char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+
+	esas2r_nvram_get_defaults(a, (struct esas2r_sas_nvram *)buf);
+
+	return sizeof(struct esas2r_sas_nvram);
+}
+
+static ssize_t read_hw(struct file *file, struct kobject *kobj,
+		       struct bin_attribute *attr,
+		       char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+	int length = min_t(size_t, sizeof(struct atto_ioctl), PAGE_SIZE);
+
+	if (!a->local_atto_ioctl)
+		return -ENOMEM;
+
+	if (handle_hba_ioctl(a, a->local_atto_ioctl) != IOCTL_SUCCESS)
+		return -ENOMEM;
+
+	memcpy(buf, a->local_atto_ioctl, length);
+
+	return length;
+}
+
+static ssize_t write_hw(struct file *file, struct kobject *kobj,
+			struct bin_attribute *attr,
+			char *buf, loff_t off, size_t count)
+{
+	struct esas2r_adapter *a = esas2r_adapter_from_kobj(kobj);
+	int length = min(sizeof(struct atto_ioctl), count);
+
+	if (!a->local_atto_ioctl) {
+		a->local_atto_ioctl = kzalloc(sizeof(struct atto_ioctl),
+					      GFP_KERNEL);
+		if (a->local_atto_ioctl == NULL) {
+			esas2r_log(ESAS2R_LOG_WARN,
+				   "write_hw kzalloc failed for %d bytes",
+				   sizeof(struct atto_ioctl));
+			return -ENOMEM;
+		}
+	}
+
+	memset(a->local_atto_ioctl, 0, sizeof(struct atto_ioctl));
+	memcpy(a->local_atto_ioctl, buf, length);
+
+	return length;
+}
+
+#define ESAS2R_RW_BIN_ATTR(_name) \
+	struct bin_attribute bin_attr_ ## _name = { \
+		.attr	= \
+		{ .name = __stringify(_name), .mode  = S_IRUSR | S_IWUSR }, \
+		.size	= 0, \
+		.read	= read_ ## _name, \
+		.write	= write_ ## _name }
+
+ESAS2R_RW_BIN_ATTR(fw);
+ESAS2R_RW_BIN_ATTR(fs);
+ESAS2R_RW_BIN_ATTR(vda);
+ESAS2R_RW_BIN_ATTR(hw);
+ESAS2R_RW_BIN_ATTR(live_nvram);
+
+struct bin_attribute bin_attr_default_nvram = {
+	.attr	= { .name = "default_nvram", .mode = S_IRUGO },
+	.size	= 0,
+	.read	= read_default_nvram,
+	.write	= NULL
+};
+
+static struct scsi_host_template driver_template = {
+	.module				= THIS_MODULE,
+	.show_info			= esas2r_show_info,
+	.name				= ESAS2R_LONGNAME,
+	.release			= esas2r_release,
+	.info				= esas2r_info,
+	.ioctl				= esas2r_ioctl,
+	.queuecommand			= esas2r_queuecommand,
+	.eh_abort_handler		= esas2r_eh_abort,
+	.eh_device_reset_handler	= esas2r_device_reset,
+	.eh_bus_reset_handler		= esas2r_bus_reset,
+	.eh_host_reset_handler		= esas2r_host_reset,
+	.eh_target_reset_handler	= esas2r_target_reset,
+	.can_queue			= 128,
+	.this_id			= -1,
+	.sg_tablesize			= SCSI_MAX_SG_SEGMENTS,
+	.cmd_per_lun			=
+		ESAS2R_DEFAULT_CMD_PER_LUN,
+	.present			= 0,
+	.unchecked_isa_dma		= 0,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.emulated			= 0,
+	.proc_name			= ESAS2R_DRVR_NAME,
+	.slave_configure		= esas2r_slave_configure,
+	.slave_alloc			= esas2r_slave_alloc,
+	.slave_destroy			= esas2r_slave_destroy,
+	.change_queue_depth		= esas2r_change_queue_depth,
+	.change_queue_type		= esas2r_change_queue_type,
+	.max_sectors			= 0xFFFF,
+};
+
+int sgl_page_size = 512;
+module_param(sgl_page_size, int, 0);
+MODULE_PARM_DESC(sgl_page_size,
+		 "Scatter/gather list (SGL) page size in number of S/G "
+		 "entries.  If your application is doing a lot of very large "
+		 "transfers, you may want to increase the SGL page size.  "
+		 "Default 512.");
+
+int num_sg_lists = 1024;
+module_param(num_sg_lists, int, 0);
+MODULE_PARM_DESC(num_sg_lists,
+		 "Number of scatter/gather lists.  Default 1024.");
+
+int sg_tablesize = SCSI_MAX_SG_SEGMENTS;
+module_param(sg_tablesize, int, 0);
+MODULE_PARM_DESC(sg_tablesize,
+		 "Maximum number of entries in a scatter/gather table.");
+
+int num_requests = 256;
+module_param(num_requests, int, 0);
+MODULE_PARM_DESC(num_requests,
+		 "Number of requests.  Default 256.");
+
+int num_ae_requests = 4;
+module_param(num_ae_requests, int, 0);
+MODULE_PARM_DESC(num_ae_requests,
+		 "Number of VDA asynchromous event requests.  Default 4.");
+
+int cmd_per_lun = ESAS2R_DEFAULT_CMD_PER_LUN;
+module_param(cmd_per_lun, int, 0);
+MODULE_PARM_DESC(cmd_per_lun,
+		 "Maximum number of commands per LUN.  Default "
+		 DEFINED_NUM_TO_STR(ESAS2R_DEFAULT_CMD_PER_LUN) ".");
+
+int can_queue = 128;
+module_param(can_queue, int, 0);
+MODULE_PARM_DESC(can_queue,
+		 "Maximum number of commands per adapter.  Default 128.");
+
+int esas2r_max_sectors = 0xFFFF;
+module_param(esas2r_max_sectors, int, 0);
+MODULE_PARM_DESC(esas2r_max_sectors,
+		 "Maximum number of disk sectors in a single data transfer.  "
+		 "Default 65535 (largest possible setting).");
+
+int interrupt_mode = 1;
+module_param(interrupt_mode, int, 0);
+MODULE_PARM_DESC(interrupt_mode,
+		 "Defines the interrupt mode to use.  0 for legacy"
+		 ", 1 for MSI.  Default is MSI (1).");
+
+static struct pci_device_id
+	esas2r_pci_table[] = {
+	{ ATTO_VENDOR_ID, 0x0049,	  ATTO_VENDOR_ID, 0x0049,
+	  0,
+	  0, 0 },
+	{ ATTO_VENDOR_ID, 0x0049,	  ATTO_VENDOR_ID, 0x004A,
+	  0,
+	  0, 0 },
+	{ ATTO_VENDOR_ID, 0x0049,	  ATTO_VENDOR_ID, 0x004B,
+	  0,
+	  0, 0 },
+	{ ATTO_VENDOR_ID, 0x0049,	  ATTO_VENDOR_ID, 0x004C,
+	  0,
+	  0, 0 },
+	{ ATTO_VENDOR_ID, 0x0049,	  ATTO_VENDOR_ID, 0x004D,
+	  0,
+	  0, 0 },
+	{ ATTO_VENDOR_ID, 0x0049,	  ATTO_VENDOR_ID, 0x004E,
+	  0,
+	  0, 0 },
+	{ 0,		  0,		  0,		  0,
+	  0,
+	  0, 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, esas2r_pci_table);
+
+static int
+esas2r_probe(struct pci_dev *pcid, const struct pci_device_id *id);
+
+static void
+esas2r_remove(struct pci_dev *pcid);
+
+static struct pci_driver
+	esas2r_pci_driver = {
+	.name		= ESAS2R_DRVR_NAME,
+	.id_table	= esas2r_pci_table,
+	.probe		= esas2r_probe,
+	.remove		= esas2r_remove,
+	.suspend	= esas2r_suspend,
+	.resume		= esas2r_resume,
+};
+
+static int esas2r_probe(struct pci_dev *pcid,
+			const struct pci_device_id *id)
+{
+	struct Scsi_Host *host = NULL;
+	struct esas2r_adapter *a;
+	int err;
+
+	size_t host_alloc_size = sizeof(struct esas2r_adapter)
+				 + ((num_requests) +
+				    1) * sizeof(struct esas2r_request);
+
+	esas2r_log_dev(ESAS2R_LOG_DEBG, &(pcid->dev),
+		       "esas2r_probe() 0x%02x 0x%02x 0x%02x 0x%02x",
+		       pcid->vendor,
+		       pcid->device,
+		       pcid->subsystem_vendor,
+		       pcid->subsystem_device);
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pcid->dev),
+		       "before pci_enable_device() "
+		       "enable_cnt: %d",
+		       pcid->enable_cnt.counter);
+
+	err = pci_enable_device(pcid);
+	if (err != 0) {
+		esas2r_log_dev(ESAS2R_LOG_CRIT, &(pcid->dev),
+			       "pci_enable_device() FAIL (%d)",
+			       err);
+		return -ENODEV;
+	}
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pcid->dev),
+		       "pci_enable_device() OK");
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pcid->dev),
+		       "after pci_device_enable() enable_cnt: %d",
+		       pcid->enable_cnt.counter);
+
+	host = scsi_host_alloc(&driver_template, host_alloc_size);
+	if (host == NULL) {
+		esas2r_log(ESAS2R_LOG_CRIT, "scsi_host_alloc() FAIL");
+		return -ENODEV;
+	}
+
+	memset(host->hostdata, 0, host_alloc_size);
+
+	a = (struct esas2r_adapter *)host->hostdata;
+
+	esas2r_log(ESAS2R_LOG_INFO, "scsi_host_alloc() OK host: %p", host);
+
+	/* override max LUN and max target id */
+
+	host->max_id = ESAS2R_MAX_ID + 1;
+	host->max_lun = 255;
+
+	/* we can handle 16-byte CDbs */
+
+	host->max_cmd_len = 16;
+
+	host->can_queue = can_queue;
+	host->cmd_per_lun = cmd_per_lun;
+	host->this_id = host->max_id + 1;
+	host->max_channel = 0;
+	host->unique_id = found_adapters;
+	host->sg_tablesize = sg_tablesize;
+	host->max_sectors = esas2r_max_sectors;
+
+	/* set to bus master for BIOses that don't do it for us */
+
+	esas2r_log(ESAS2R_LOG_INFO, "pci_set_master() called");
+
+	pci_set_master(pcid);
+
+	if (!esas2r_init_adapter(host, pcid, found_adapters)) {
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "unable to initialize device at PCI bus %x:%x",
+			   pcid->bus->number,
+			   pcid->devfn);
+
+		esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+			       "scsi_host_put() called");
+
+		scsi_host_put(host);
+
+		return 0;
+
+	}
+
+	esas2r_log(ESAS2R_LOG_INFO, "pci_set_drvdata(%p, %p) called", pcid,
+		   host->hostdata);
+
+	pci_set_drvdata(pcid, host);
+
+	esas2r_log(ESAS2R_LOG_INFO, "scsi_add_host() called");
+
+	err = scsi_add_host(host, &pcid->dev);
+
+	if (err) {
+		esas2r_log(ESAS2R_LOG_CRIT, "scsi_add_host returned %d", err);
+		esas2r_log_dev(ESAS2R_LOG_CRIT, &(host->shost_gendev),
+			       "scsi_add_host() FAIL");
+
+		esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+			       "scsi_host_put() called");
+
+		scsi_host_put(host);
+
+		esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+			       "pci_set_drvdata(%p, NULL) called",
+			       pcid);
+
+		pci_set_drvdata(pcid, NULL);
+
+		return -ENODEV;
+	}
+
+
+	esas2r_fw_event_on(a);
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(host->shost_gendev),
+		       "scsi_scan_host() called");
+
+	scsi_scan_host(host);
+
+	/* Add sysfs binary files */
+	if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_fw))
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+			       "Failed to create sysfs binary file: fw");
+	else
+		a->sysfs_fw_created = 1;
+
+	if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_fs))
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+			       "Failed to create sysfs binary file: fs");
+	else
+		a->sysfs_fs_created = 1;
+
+	if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_vda))
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+			       "Failed to create sysfs binary file: vda");
+	else
+		a->sysfs_vda_created = 1;
+
+	if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_hw))
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+			       "Failed to create sysfs binary file: hw");
+	else
+		a->sysfs_hw_created = 1;
+
+	if (sysfs_create_bin_file(&host->shost_dev.kobj, &bin_attr_live_nvram))
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+			       "Failed to create sysfs binary file: live_nvram");
+	else
+		a->sysfs_live_nvram_created = 1;
+
+	if (sysfs_create_bin_file(&host->shost_dev.kobj,
+				  &bin_attr_default_nvram))
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(host->shost_gendev),
+			       "Failed to create sysfs binary file: default_nvram");
+	else
+		a->sysfs_default_nvram_created = 1;
+
+	found_adapters++;
+
+	return 0;
+}
+
+static void esas2r_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host;
+	int index;
+
+	if (pdev == NULL) {
+		esas2r_log(ESAS2R_LOG_WARN, "esas2r_remove pdev==NULL");
+		return;
+	}
+
+	host = pci_get_drvdata(pdev);
+
+	if (host == NULL) {
+		/*
+		 * this can happen if pci_set_drvdata was already called
+		 * to clear the host pointer.  if this is the case, we
+		 * are okay; this channel has already been cleaned up.
+		 */
+
+		return;
+	}
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(pdev->dev),
+		       "esas2r_remove(%p) called; "
+		       "host:%p", pdev,
+		       host);
+
+	index = esas2r_cleanup(host);
+
+	if (index < 0)
+		esas2r_log_dev(ESAS2R_LOG_WARN, &(pdev->dev),
+			       "unknown host in %s",
+			       __func__);
+
+	found_adapters--;
+
+	/* if this was the last adapter, clean up the rest of the driver */
+
+	if (found_adapters == 0)
+		esas2r_cleanup(NULL);
+}
+
+static int __init esas2r_init(void)
+{
+	int i;
+
+	esas2r_log(ESAS2R_LOG_INFO, "%s called", __func__);
+
+	/* verify valid parameters */
+
+	if (can_queue < 1) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: can_queue must be at least 1, value "
+			   "forced.");
+		can_queue = 1;
+	} else if (can_queue > 2048) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: can_queue must be no larger than 2048, "
+			   "value forced.");
+		can_queue = 2048;
+	}
+
+	if (cmd_per_lun < 1) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: cmd_per_lun must be at least 1, value "
+			   "forced.");
+		cmd_per_lun = 1;
+	} else if (cmd_per_lun > 2048) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: cmd_per_lun must be no larger than "
+			   "2048, value forced.");
+		cmd_per_lun = 2048;
+	}
+
+	if (sg_tablesize < 32) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: sg_tablesize must be at least 32, "
+			   "value forced.");
+		sg_tablesize = 32;
+	}
+
+	if (esas2r_max_sectors < 1) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: esas2r_max_sectors must be at least "
+			   "1, value forced.");
+		esas2r_max_sectors = 1;
+	} else if (esas2r_max_sectors > 0xffff) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "warning: esas2r_max_sectors must be no larger "
+			   "than 0xffff, value forced.");
+		esas2r_max_sectors = 0xffff;
+	}
+
+	sgl_page_size &= ~(ESAS2R_SGL_ALIGN - 1);
+
+	if (sgl_page_size < SGL_PG_SZ_MIN)
+		sgl_page_size = SGL_PG_SZ_MIN;
+	else if (sgl_page_size > SGL_PG_SZ_MAX)
+		sgl_page_size = SGL_PG_SZ_MAX;
+
+	if (num_sg_lists < NUM_SGL_MIN)
+		num_sg_lists = NUM_SGL_MIN;
+	else if (num_sg_lists > NUM_SGL_MAX)
+		num_sg_lists = NUM_SGL_MAX;
+
+	if (num_requests < NUM_REQ_MIN)
+		num_requests = NUM_REQ_MIN;
+	else if (num_requests > NUM_REQ_MAX)
+		num_requests = NUM_REQ_MAX;
+
+	if (num_ae_requests < NUM_AE_MIN)
+		num_ae_requests = NUM_AE_MIN;
+	else if (num_ae_requests > NUM_AE_MAX)
+		num_ae_requests = NUM_AE_MAX;
+
+	/* set up other globals */
+
+	for (i = 0; i < MAX_ADAPTERS; i++)
+		esas2r_adapters[i] = NULL;
+
+	/* initialize */
+
+	driver_template.module = THIS_MODULE;
+
+	if (pci_register_driver(&esas2r_pci_driver) != 0)
+		esas2r_log(ESAS2R_LOG_CRIT, "pci_register_driver FAILED");
+	else
+		esas2r_log(ESAS2R_LOG_INFO, "pci_register_driver() OK");
+
+	if (!found_adapters) {
+		pci_unregister_driver(&esas2r_pci_driver);
+		esas2r_cleanup(NULL);
+
+		esas2r_log(ESAS2R_LOG_CRIT,
+			   "driver will not be loaded because no ATTO "
+			   "%s devices were found",
+			   ESAS2R_DRVR_NAME);
+		return -1;
+	} else {
+		esas2r_log(ESAS2R_LOG_INFO, "found %d adapters",
+			   found_adapters);
+	}
+
+	return 0;
+}
+
+/* Handle ioctl calls to "/proc/scsi/esas2r/ATTOnode" */
+static const struct file_operations esas2r_proc_fops = {
+	.compat_ioctl	= esas2r_proc_ioctl,
+	.unlocked_ioctl = esas2r_proc_ioctl,
+};
+
+static struct Scsi_Host *esas2r_proc_host;
+static int esas2r_proc_major;
+
+long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	return esas2r_ioctl_handler(esas2r_proc_host->hostdata,
+				    (int)cmd, (void __user *)arg);
+}
+
+static void __exit esas2r_exit(void)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "%s called", __func__);
+
+	if (esas2r_proc_major > 0) {
+		esas2r_log(ESAS2R_LOG_INFO, "unregister proc");
+
+		remove_proc_entry(ATTONODE_NAME,
+				  esas2r_proc_host->hostt->proc_dir);
+		unregister_chrdev(esas2r_proc_major, ESAS2R_DRVR_NAME);
+
+		esas2r_proc_major = 0;
+	}
+
+	esas2r_log(ESAS2R_LOG_INFO, "pci_unregister_driver() called");
+
+	pci_unregister_driver(&esas2r_pci_driver);
+}
+
+int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata;
+
+	struct esas2r_target *t;
+	int dev_count = 0;
+
+	esas2r_log(ESAS2R_LOG_DEBG, "esas2r_show_info (%p,%d)", m, sh->host_no);
+
+	seq_printf(m, ESAS2R_LONGNAME "\n"
+		   "Driver version: "ESAS2R_VERSION_STR "\n"
+		   "Flash version: %s\n"
+		   "Firmware version: %s\n"
+		   "Copyright "ESAS2R_COPYRIGHT_YEARS "\n"
+		   "http://www.attotech.com\n"
+		   "\n",
+		   a->flash_rev,
+		   a->fw_rev[0] ? a->fw_rev : "(none)");
+
+
+	seq_printf(m, "Adapter information:\n"
+		   "--------------------\n"
+		   "Model: %s\n"
+		   "SAS address: %02X%02X%02X%02X:%02X%02X%02X%02X\n",
+		   esas2r_get_model_name(a),
+		   a->nvram->sas_addr[0],
+		   a->nvram->sas_addr[1],
+		   a->nvram->sas_addr[2],
+		   a->nvram->sas_addr[3],
+		   a->nvram->sas_addr[4],
+		   a->nvram->sas_addr[5],
+		   a->nvram->sas_addr[6],
+		   a->nvram->sas_addr[7]);
+
+	seq_puts(m, "\n"
+		   "Discovered devices:\n"
+		   "\n"
+		   "   #  Target ID\n"
+		   "---------------\n");
+
+	for (t = a->targetdb; t < a->targetdb_end; t++)
+		if (t->buffered_target_state == TS_PRESENT) {
+			seq_printf(m, " %3d   %3d\n",
+				   ++dev_count,
+				   (u16)(uintptr_t)(t - a->targetdb));
+		}
+
+	if (dev_count == 0)
+		seq_puts(m, "none\n");
+
+	seq_puts(m, "\n");
+	return 0;
+
+}
+
+int esas2r_release(struct Scsi_Host *sh)
+{
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(sh->shost_gendev),
+		       "esas2r_release() called");
+
+	esas2r_cleanup(sh);
+	if (sh->irq)
+		free_irq(sh->irq, NULL);
+	scsi_unregister(sh);
+	return 0;
+}
+
+const char *esas2r_info(struct Scsi_Host *sh)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)sh->hostdata;
+	static char esas2r_info_str[512];
+
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(sh->shost_gendev),
+		       "esas2r_info() called");
+
+	/*
+	 * if we haven't done so already, register as a char driver
+	 * and stick a node under "/proc/scsi/esas2r/ATTOnode"
+	 */
+
+	if (esas2r_proc_major <= 0) {
+		esas2r_proc_host = sh;
+
+		esas2r_proc_major = register_chrdev(0, ESAS2R_DRVR_NAME,
+						    &esas2r_proc_fops);
+
+		esas2r_log_dev(ESAS2R_LOG_DEBG, &(sh->shost_gendev),
+			       "register_chrdev (major %d)",
+			       esas2r_proc_major);
+
+		if (esas2r_proc_major > 0) {
+			struct proc_dir_entry *pde;
+
+			pde = proc_create(ATTONODE_NAME, 0,
+					  sh->hostt->proc_dir,
+					  &esas2r_proc_fops);
+
+			if (!pde) {
+				esas2r_log_dev(ESAS2R_LOG_WARN,
+					       &(sh->shost_gendev),
+					       "failed to create_proc_entry");
+				esas2r_proc_major = -1;
+			}
+		}
+	}
+
+	sprintf(esas2r_info_str,
+		ESAS2R_LONGNAME " (bus 0x%02X, device 0x%02X, IRQ 0x%02X)"
+		" driver version: "ESAS2R_VERSION_STR "  firmware version: "
+		"%s\n",
+		a->pcid->bus->number, a->pcid->devfn, a->pcid->irq,
+		a->fw_rev[0] ? a->fw_rev : "(none)");
+
+	return esas2r_info_str;
+}
+
+/* Callback for building a request scatter/gather list */
+static u32 get_physaddr_from_sgc(struct esas2r_sg_context *sgc, u64 *addr)
+{
+	u32 len;
+
+	if (likely(sgc->cur_offset == sgc->exp_offset)) {
+		/*
+		 * the normal case: caller used all bytes from previous call, so
+		 * expected offset is the same as the current offset.
+		 */
+
+		if (sgc->sgel_count < sgc->num_sgel) {
+			/* retrieve next segment, except for first time */
+			if (sgc->exp_offset > (u8 *)0) {
+				/* advance current segment */
+				sgc->cur_sgel = sg_next(sgc->cur_sgel);
+				++(sgc->sgel_count);
+			}
+
+
+			len = sg_dma_len(sgc->cur_sgel);
+			(*addr) = sg_dma_address(sgc->cur_sgel);
+
+			/* save the total # bytes returned to caller so far */
+			sgc->exp_offset += len;
+
+		} else {
+			len = 0;
+		}
+	} else if (sgc->cur_offset < sgc->exp_offset) {
+		/*
+		 * caller did not use all bytes from previous call. need to
+		 * compute the address based on current segment.
+		 */
+
+		len = sg_dma_len(sgc->cur_sgel);
+		(*addr) = sg_dma_address(sgc->cur_sgel);
+
+		sgc->exp_offset -= len;
+
+		/* calculate PA based on prev segment address and offsets */
+		*addr = *addr +
+			(sgc->cur_offset - sgc->exp_offset);
+
+		sgc->exp_offset += len;
+
+		/* re-calculate length based on offset */
+		len = lower_32_bits(
+			sgc->exp_offset - sgc->cur_offset);
+	} else {   /* if ( sgc->cur_offset > sgc->exp_offset ) */
+		   /*
+		    * we don't expect the caller to skip ahead.
+		    * cur_offset will never exceed the len we return
+		    */
+		len = 0;
+	}
+
+	return len;
+}
+
+int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+	struct esas2r_adapter *a =
+		(struct esas2r_adapter *)cmd->device->host->hostdata;
+	struct esas2r_request *rq;
+	struct esas2r_sg_context sgc;
+	unsigned bufflen;
+
+	/* Assume success, if it fails we will fix the result later. */
+	cmd->result = DID_OK << 16;
+
+	if (unlikely(a->flags & AF_DEGRADED_MODE)) {
+		cmd->result = DID_NO_CONNECT << 16;
+		cmd->scsi_done(cmd);
+		return 0;
+	}
+
+	rq = esas2r_alloc_request(a);
+	if (unlikely(rq == NULL)) {
+		esas2r_debug("esas2r_alloc_request failed");
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	rq->cmd = cmd;
+	bufflen = scsi_bufflen(cmd);
+
+	if (likely(bufflen != 0)) {
+		if (cmd->sc_data_direction == DMA_TO_DEVICE)
+			rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_WRD);
+		else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+			rq->vrq->scsi.flags |= cpu_to_le32(FCP_CMND_RDD);
+	}
+
+	memcpy(rq->vrq->scsi.cdb, cmd->cmnd, cmd->cmd_len);
+	rq->vrq->scsi.length = cpu_to_le32(bufflen);
+	rq->target_id = cmd->device->id;
+	rq->vrq->scsi.flags |= cpu_to_le32(cmd->device->lun);
+	rq->sense_buf = cmd->sense_buffer;
+	rq->sense_len = SCSI_SENSE_BUFFERSIZE;
+
+	esas2r_sgc_init(&sgc, a, rq, NULL);
+
+	sgc.length = bufflen;
+	sgc.cur_offset = NULL;
+
+	sgc.cur_sgel = scsi_sglist(cmd);
+	sgc.exp_offset = NULL;
+	sgc.num_sgel = scsi_dma_map(cmd);
+	sgc.sgel_count = 0;
+
+	if (unlikely(sgc.num_sgel < 0)) {
+		esas2r_free_request(a, rq);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	sgc.get_phys_addr = (PGETPHYSADDR)get_physaddr_from_sgc;
+
+	if (unlikely(!esas2r_build_sg_list(a, rq, &sgc))) {
+		scsi_dma_unmap(cmd);
+		esas2r_free_request(a, rq);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	esas2r_debug("start request %p to %d:%d\n", rq, (int)cmd->device->id,
+		     (int)cmd->device->lun);
+
+	esas2r_start_request(a, rq);
+
+	return 0;
+}
+
+static void complete_task_management_request(struct esas2r_adapter *a,
+					     struct esas2r_request *rq)
+{
+	(*rq->task_management_status_ptr) = rq->req_stat;
+	esas2r_free_request(a, rq);
+}
+
+/**
+ * Searches the specified queue for the specified queue for the command
+ * to abort.
+ *
+ * @param [in] a
+ * @param [in] abort_request
+ * @param [in] cmd
+ * t
+ * @return 0 on failure, 1 if command was not found, 2 if command was found
+ */
+static int esas2r_check_active_queue(struct esas2r_adapter *a,
+				     struct esas2r_request **abort_request,
+				     struct scsi_cmnd *cmd,
+				     struct list_head *queue)
+{
+	bool found = false;
+	struct esas2r_request *ar = *abort_request;
+	struct esas2r_request *rq;
+	struct list_head *element, *next;
+
+	list_for_each_safe(element, next, queue) {
+
+		rq = list_entry(element, struct esas2r_request, req_list);
+
+		if (rq->cmd == cmd) {
+
+			/* Found the request.  See what to do with it. */
+			if (queue == &a->active_list) {
+				/*
+				 * We are searching the active queue, which
+				 * means that we need to send an abort request
+				 * to the firmware.
+				 */
+				ar = esas2r_alloc_request(a);
+				if (ar == NULL) {
+					esas2r_log_dev(ESAS2R_LOG_WARN,
+						       &(a->host->shost_gendev),
+						       "unable to allocate an abort request for cmd %p",
+						       cmd);
+					return 0; /* Failure */
+				}
+
+				/*
+				 * Task management request must be formatted
+				 * with a lock held.
+				 */
+				ar->sense_len = 0;
+				ar->vrq->scsi.length = 0;
+				ar->target_id = rq->target_id;
+				ar->vrq->scsi.flags |= cpu_to_le32(
+					(u8)le32_to_cpu(rq->vrq->scsi.flags));
+
+				memset(ar->vrq->scsi.cdb, 0,
+				       sizeof(ar->vrq->scsi.cdb));
+
+				ar->vrq->scsi.flags |= cpu_to_le32(
+					FCP_CMND_TRM);
+				ar->vrq->scsi.u.abort_handle =
+					rq->vrq->scsi.handle;
+			} else {
+				/*
+				 * The request is pending but not active on
+				 * the firmware.  Just free it now and we'll
+				 * report the successful abort below.
+				 */
+				list_del_init(&rq->req_list);
+				esas2r_free_request(a, rq);
+			}
+
+			found = true;
+			break;
+		}
+
+	}
+
+	if (!found)
+		return 1;       /* Not found */
+
+	return 2;               /* found */
+
+
+}
+
+int esas2r_eh_abort(struct scsi_cmnd *cmd)
+{
+	struct esas2r_adapter *a =
+		(struct esas2r_adapter *)cmd->device->host->hostdata;
+	struct esas2r_request *abort_request = NULL;
+	unsigned long flags;
+	struct list_head *queue;
+	int result;
+
+	esas2r_log(ESAS2R_LOG_INFO, "eh_abort (%p)", cmd);
+
+	if (a->flags & AF_DEGRADED_MODE) {
+		cmd->result = DID_ABORT << 16;
+
+		scsi_set_resid(cmd, 0);
+
+		cmd->scsi_done(cmd);
+
+		return 0;
+	}
+
+	spin_lock_irqsave(&a->queue_lock, flags);
+
+	/*
+	 * Run through the defer and active queues looking for the request
+	 * to abort.
+	 */
+
+	queue = &a->defer_list;
+
+check_active_queue:
+
+	result = esas2r_check_active_queue(a, &abort_request, cmd, queue);
+
+	if (!result) {
+		spin_unlock_irqrestore(&a->queue_lock, flags);
+		return FAILED;
+	} else if (result == 2 && (queue == &a->defer_list)) {
+		queue = &a->active_list;
+		goto check_active_queue;
+	}
+
+	spin_unlock_irqrestore(&a->queue_lock, flags);
+
+	if (abort_request) {
+		u8 task_management_status = RS_PENDING;
+
+		/*
+		 * the request is already active, so we need to tell
+		 * the firmware to abort it and wait for the response.
+		 */
+
+		abort_request->comp_cb = complete_task_management_request;
+		abort_request->task_management_status_ptr =
+			&task_management_status;
+
+		esas2r_start_request(a, abort_request);
+
+		if (atomic_read(&a->disable_cnt) == 0)
+			esas2r_do_deferred_processes(a);
+
+		while (task_management_status == RS_PENDING)
+			msleep(10);
+
+		/*
+		 * Once we get here, the original request will have been
+		 * completed by the firmware and the abort request will have
+		 * been cleaned up.  we're done!
+		 */
+
+		return SUCCESS;
+	}
+
+	/*
+	 * If we get here, either we found the inactive request and
+	 * freed it, or we didn't find it at all.  Either way, success!
+	 */
+
+	cmd->result = DID_ABORT << 16;
+
+	scsi_set_resid(cmd, 0);
+
+	cmd->scsi_done(cmd);
+
+	return SUCCESS;
+}
+
+static int esas2r_host_bus_reset(struct scsi_cmnd *cmd, bool host_reset)
+{
+	struct esas2r_adapter *a =
+		(struct esas2r_adapter *)cmd->device->host->hostdata;
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return FAILED;
+
+	if (host_reset)
+		esas2r_reset_adapter(a);
+	else
+		esas2r_reset_bus(a);
+
+	/* above call sets the AF_OS_RESET flag.  wait for it to clear. */
+
+	while (a->flags & AF_OS_RESET) {
+		msleep(10);
+
+		if (a->flags & AF_DEGRADED_MODE)
+			return FAILED;
+	}
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return FAILED;
+
+	return SUCCESS;
+}
+
+int esas2r_host_reset(struct scsi_cmnd *cmd)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "host_reset (%p)", cmd);
+
+	return esas2r_host_bus_reset(cmd, true);
+}
+
+int esas2r_bus_reset(struct scsi_cmnd *cmd)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "bus_reset (%p)", cmd);
+
+	return esas2r_host_bus_reset(cmd, false);
+}
+
+static int esas2r_dev_targ_reset(struct scsi_cmnd *cmd, bool target_reset)
+{
+	struct esas2r_adapter *a =
+		(struct esas2r_adapter *)cmd->device->host->hostdata;
+	struct esas2r_request *rq;
+	u8 task_management_status = RS_PENDING;
+	bool completed;
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return FAILED;
+
+retry:
+	rq = esas2r_alloc_request(a);
+	if (rq == NULL) {
+		if (target_reset) {
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "unable to allocate a request for a "
+				   "target reset (%d)!",
+				   cmd->device->id);
+		} else {
+			esas2r_log(ESAS2R_LOG_CRIT,
+				   "unable to allocate a request for a "
+				   "device reset (%d:%d)!",
+				   cmd->device->id,
+				   cmd->device->lun);
+		}
+
+
+		return FAILED;
+	}
+
+	rq->target_id = cmd->device->id;
+	rq->vrq->scsi.flags |= cpu_to_le32(cmd->device->lun);
+	rq->req_stat = RS_PENDING;
+
+	rq->comp_cb = complete_task_management_request;
+	rq->task_management_status_ptr = &task_management_status;
+
+	if (target_reset) {
+		esas2r_debug("issuing target reset (%p) to id %d", rq,
+			     cmd->device->id);
+		completed = esas2r_send_task_mgmt(a, rq, 0x20);
+	} else {
+		esas2r_debug("issuing device reset (%p) to id %d lun %d", rq,
+			     cmd->device->id, cmd->device->lun);
+		completed = esas2r_send_task_mgmt(a, rq, 0x10);
+	}
+
+	if (completed) {
+		/* Task management cmd completed right away, need to free it. */
+
+		esas2r_free_request(a, rq);
+	} else {
+		/*
+		 * Wait for firmware to complete the request.  Completion
+		 * callback will free it.
+		 */
+		while (task_management_status == RS_PENDING)
+			msleep(10);
+	}
+
+	if (a->flags & AF_DEGRADED_MODE)
+		return FAILED;
+
+	if (task_management_status == RS_BUSY) {
+		/*
+		 * Busy, probably because we are flashing.  Wait a bit and
+		 * try again.
+		 */
+		msleep(100);
+		goto retry;
+	}
+
+	return SUCCESS;
+}
+
+int esas2r_device_reset(struct scsi_cmnd *cmd)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "device_reset (%p)", cmd);
+
+	return esas2r_dev_targ_reset(cmd, false);
+
+}
+
+int esas2r_target_reset(struct scsi_cmnd *cmd)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "target_reset (%p)", cmd);
+
+	return esas2r_dev_targ_reset(cmd, true);
+}
+
+int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "change_queue_depth %p, %d", dev, depth);
+
+	scsi_adjust_queue_depth(dev, scsi_get_tag_type(dev), depth);
+
+	return dev->queue_depth;
+}
+
+int esas2r_change_queue_type(struct scsi_device *dev, int type)
+{
+	esas2r_log(ESAS2R_LOG_INFO, "change_queue_type %p, %d", dev, type);
+
+	if (dev->tagged_supported) {
+		scsi_set_tag_type(dev, type);
+
+		if (type)
+			scsi_activate_tcq(dev, dev->queue_depth);
+		else
+			scsi_deactivate_tcq(dev, dev->queue_depth);
+	} else {
+		type = 0;
+	}
+
+	return type;
+}
+
+int esas2r_slave_alloc(struct scsi_device *dev)
+{
+	return 0;
+}
+
+int esas2r_slave_configure(struct scsi_device *dev)
+{
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
+		       "esas2r_slave_configure()");
+
+	if (dev->tagged_supported) {
+		scsi_set_tag_type(dev, MSG_SIMPLE_TAG);
+		scsi_activate_tcq(dev, cmd_per_lun);
+	} else {
+		scsi_set_tag_type(dev, 0);
+		scsi_deactivate_tcq(dev, cmd_per_lun);
+	}
+
+	return 0;
+}
+
+void esas2r_slave_destroy(struct scsi_device *dev)
+{
+	esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
+		       "esas2r_slave_destroy()");
+}
+
+void esas2r_log_request_failure(struct esas2r_adapter *a,
+				struct esas2r_request *rq)
+{
+	u8 reqstatus = rq->req_stat;
+
+	if (reqstatus == RS_SUCCESS)
+		return;
+
+	if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
+		if (reqstatus == RS_SCSI_ERROR) {
+			if (rq->func_rsp.scsi_rsp.sense_len >= 13) {
+				esas2r_log(ESAS2R_LOG_WARN,
+					   "request failure - SCSI error %x ASC:%x ASCQ:%x CDB:%x",
+					   rq->sense_buf[2], rq->sense_buf[12],
+					   rq->sense_buf[13],
+					   rq->vrq->scsi.cdb[0]);
+			} else {
+				esas2r_log(ESAS2R_LOG_WARN,
+					   "request failure - SCSI error CDB:%x\n",
+					   rq->vrq->scsi.cdb[0]);
+			}
+		} else if ((rq->vrq->scsi.cdb[0] != INQUIRY
+			    && rq->vrq->scsi.cdb[0] != REPORT_LUNS)
+			   || (reqstatus != RS_SEL
+			       && reqstatus != RS_SEL2)) {
+			if ((reqstatus == RS_UNDERRUN) &&
+			    (rq->vrq->scsi.cdb[0] == INQUIRY)) {
+				/* Don't log inquiry underruns */
+			} else {
+				esas2r_log(ESAS2R_LOG_WARN,
+					   "request failure - cdb:%x reqstatus:%d target:%d",
+					   rq->vrq->scsi.cdb[0], reqstatus,
+					   rq->target_id);
+			}
+		}
+	}
+}
+
+void esas2r_wait_request(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+	u32 starttime;
+	u32 timeout;
+
+	starttime = jiffies_to_msecs(jiffies);
+	timeout = rq->timeout ? rq->timeout : 5000;
+
+	while (true) {
+		esas2r_polled_interrupt(a);
+
+		if (rq->req_stat != RS_STARTED)
+			break;
+
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
+
+		if ((jiffies_to_msecs(jiffies) - starttime) > timeout) {
+			esas2r_hdebug("request TMO");
+			esas2r_bugon();
+
+			rq->req_stat = RS_TIMEOUT;
+
+			esas2r_local_reset_adapter(a);
+			return;
+		}
+	}
+}
+
+u32 esas2r_map_data_window(struct esas2r_adapter *a, u32 addr_lo)
+{
+	u32 offset = addr_lo & (MW_DATA_WINDOW_SIZE - 1);
+	u32 base = addr_lo & -(signed int)MW_DATA_WINDOW_SIZE;
+
+	if (a->window_base != base) {
+		esas2r_write_register_dword(a, MVR_PCI_WIN1_REMAP,
+					    base | MVRPW1R_ENABLE);
+		esas2r_flush_register_dword(a, MVR_PCI_WIN1_REMAP);
+		a->window_base = base;
+	}
+
+	return offset;
+}
+
+/* Read a block of data from chip memory */
+bool esas2r_read_mem_block(struct esas2r_adapter *a,
+			   void *to,
+			   u32 from,
+			   u32 size)
+{
+	u8 *end = (u8 *)to;
+
+	while (size) {
+		u32 len;
+		u32 offset;
+		u32 iatvr;
+
+		iatvr = (from & -(signed int)MW_DATA_WINDOW_SIZE);
+
+		esas2r_map_data_window(a, iatvr);
+
+		offset = from & (MW_DATA_WINDOW_SIZE - 1);
+		len = size;
+
+		if (len > MW_DATA_WINDOW_SIZE - offset)
+			len = MW_DATA_WINDOW_SIZE - offset;
+
+		from += len;
+		size -= len;
+
+		while (len--) {
+			*end++ = esas2r_read_data_byte(a, offset);
+			offset++;
+		}
+	}
+
+	return true;
+}
+
+void esas2r_nuxi_mgt_data(u8 function, void *data)
+{
+	struct atto_vda_grp_info *g;
+	struct atto_vda_devinfo *d;
+	struct atto_vdapart_info *p;
+	struct atto_vda_dh_info *h;
+	struct atto_vda_metrics_info *m;
+	struct atto_vda_schedule_info *s;
+	struct atto_vda_buzzer_info *b;
+	u8 i;
+
+	switch (function) {
+	case VDAMGT_BUZZER_INFO:
+	case VDAMGT_BUZZER_SET:
+
+		b = (struct atto_vda_buzzer_info *)data;
+
+		b->duration = le32_to_cpu(b->duration);
+		break;
+
+	case VDAMGT_SCHEDULE_INFO:
+	case VDAMGT_SCHEDULE_EVENT:
+
+		s = (struct atto_vda_schedule_info *)data;
+
+		s->id = le32_to_cpu(s->id);
+
+		break;
+
+	case VDAMGT_DEV_INFO:
+	case VDAMGT_DEV_CLEAN:
+	case VDAMGT_DEV_PT_INFO:
+	case VDAMGT_DEV_FEATURES:
+	case VDAMGT_DEV_PT_FEATURES:
+	case VDAMGT_DEV_OPERATION:
+
+		d = (struct atto_vda_devinfo *)data;
+
+		d->capacity = le64_to_cpu(d->capacity);
+		d->block_size = le32_to_cpu(d->block_size);
+		d->ses_dev_index = le16_to_cpu(d->ses_dev_index);
+		d->target_id = le16_to_cpu(d->target_id);
+		d->lun = le16_to_cpu(d->lun);
+		d->features = le16_to_cpu(d->features);
+		break;
+
+	case VDAMGT_GRP_INFO:
+	case VDAMGT_GRP_CREATE:
+	case VDAMGT_GRP_DELETE:
+	case VDAMGT_ADD_STORAGE:
+	case VDAMGT_MEMBER_ADD:
+	case VDAMGT_GRP_COMMIT:
+	case VDAMGT_GRP_REBUILD:
+	case VDAMGT_GRP_COMMIT_INIT:
+	case VDAMGT_QUICK_RAID:
+	case VDAMGT_GRP_FEATURES:
+	case VDAMGT_GRP_COMMIT_INIT_AUTOMAP:
+	case VDAMGT_QUICK_RAID_INIT_AUTOMAP:
+	case VDAMGT_SPARE_LIST:
+	case VDAMGT_SPARE_ADD:
+	case VDAMGT_SPARE_REMOVE:
+	case VDAMGT_LOCAL_SPARE_ADD:
+	case VDAMGT_GRP_OPERATION:
+
+		g = (struct atto_vda_grp_info *)data;
+
+		g->capacity = le64_to_cpu(g->capacity);
+		g->block_size = le32_to_cpu(g->block_size);
+		g->interleave = le32_to_cpu(g->interleave);
+		g->features = le16_to_cpu(g->features);
+
+		for (i = 0; i < 32; i++)
+			g->members[i] = le16_to_cpu(g->members[i]);
+
+		break;
+
+	case VDAMGT_PART_INFO:
+	case VDAMGT_PART_MAP:
+	case VDAMGT_PART_UNMAP:
+	case VDAMGT_PART_AUTOMAP:
+	case VDAMGT_PART_SPLIT:
+	case VDAMGT_PART_MERGE:
+
+		p = (struct atto_vdapart_info *)data;
+
+		p->part_size = le64_to_cpu(p->part_size);
+		p->start_lba = le32_to_cpu(p->start_lba);
+		p->block_size = le32_to_cpu(p->block_size);
+		p->target_id = le16_to_cpu(p->target_id);
+		break;
+
+	case VDAMGT_DEV_HEALTH_REQ:
+
+		h = (struct atto_vda_dh_info *)data;
+
+		h->med_defect_cnt = le32_to_cpu(h->med_defect_cnt);
+		h->info_exc_cnt = le32_to_cpu(h->info_exc_cnt);
+		break;
+
+	case VDAMGT_DEV_METRICS:
+
+		m = (struct atto_vda_metrics_info *)data;
+
+		for (i = 0; i < 32; i++)
+			m->dev_indexes[i] = le16_to_cpu(m->dev_indexes[i]);
+
+		break;
+
+	default:
+		break;
+	}
+}
+
+void esas2r_nuxi_cfg_data(u8 function, void *data)
+{
+	struct atto_vda_cfg_init *ci;
+
+	switch (function) {
+	case VDA_CFG_INIT:
+	case VDA_CFG_GET_INIT:
+	case VDA_CFG_GET_INIT2:
+
+		ci = (struct atto_vda_cfg_init *)data;
+
+		ci->date_time.year = le16_to_cpu(ci->date_time.year);
+		ci->sgl_page_size = le32_to_cpu(ci->sgl_page_size);
+		ci->vda_version = le32_to_cpu(ci->vda_version);
+		ci->epoch_time = le32_to_cpu(ci->epoch_time);
+		ci->ioctl_tunnel = le32_to_cpu(ci->ioctl_tunnel);
+		ci->num_targets_backend = le32_to_cpu(ci->num_targets_backend);
+		break;
+
+	default:
+		break;
+	}
+}
+
+void esas2r_nuxi_ae_data(union atto_vda_ae *ae)
+{
+	struct atto_vda_ae_raid *r = &ae->raid;
+	struct atto_vda_ae_lu *l = &ae->lu;
+
+	switch (ae->hdr.bytype) {
+	case VDAAE_HDR_TYPE_RAID:
+
+		r->dwflags = le32_to_cpu(r->dwflags);
+		break;
+
+	case VDAAE_HDR_TYPE_LU:
+
+		l->dwevent = le32_to_cpu(l->dwevent);
+		l->wphys_target_id = le16_to_cpu(l->wphys_target_id);
+		l->id.tgtlun.wtarget_id = le16_to_cpu(l->id.tgtlun.wtarget_id);
+
+		if (l->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id)
+		    + sizeof(struct atto_vda_ae_lu_tgt_lun_raid)) {
+			l->id.tgtlun_raid.dwinterleave
+				= le32_to_cpu(l->id.tgtlun_raid.dwinterleave);
+			l->id.tgtlun_raid.dwblock_size
+				= le32_to_cpu(l->id.tgtlun_raid.dwblock_size);
+		}
+
+		break;
+
+	case VDAAE_HDR_TYPE_DISK:
+	default:
+		break;
+	}
+}
+
+void esas2r_free_request(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+	unsigned long flags;
+
+	esas2r_rq_destroy_request(rq, a);
+	spin_lock_irqsave(&a->request_lock, flags);
+	list_add(&rq->comp_list, &a->avail_request);
+	spin_unlock_irqrestore(&a->request_lock, flags);
+}
+
+struct esas2r_request *esas2r_alloc_request(struct esas2r_adapter *a)
+{
+	struct esas2r_request *rq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&a->request_lock, flags);
+
+	if (unlikely(list_empty(&a->avail_request))) {
+		spin_unlock_irqrestore(&a->request_lock, flags);
+		return NULL;
+	}
+
+	rq = list_first_entry(&a->avail_request, struct esas2r_request,
+			      comp_list);
+	list_del(&rq->comp_list);
+	spin_unlock_irqrestore(&a->request_lock, flags);
+	esas2r_rq_init_request(rq, a);
+
+	return rq;
+
+}
+
+void esas2r_complete_request_cb(struct esas2r_adapter *a,
+				struct esas2r_request *rq)
+{
+	esas2r_debug("completing request %p\n", rq);
+
+	scsi_dma_unmap(rq->cmd);
+
+	if (unlikely(rq->req_stat != RS_SUCCESS)) {
+		esas2r_debug("[%x STATUS %x:%x (%x)]", rq->target_id,
+			     rq->req_stat,
+			     rq->func_rsp.scsi_rsp.scsi_stat,
+			     rq->cmd);
+
+		rq->cmd->result =
+			((esas2r_req_status_to_error(rq->req_stat) << 16)
+			 | (rq->func_rsp.scsi_rsp.scsi_stat & STATUS_MASK));
+
+		if (rq->req_stat == RS_UNDERRUN)
+			scsi_set_resid(rq->cmd,
+				       le32_to_cpu(rq->func_rsp.scsi_rsp.
+						   residual_length));
+		else
+			scsi_set_resid(rq->cmd, 0);
+	}
+
+	rq->cmd->scsi_done(rq->cmd);
+
+	esas2r_free_request(a, rq);
+}
+
+/* Run tasklet to handle stuff outside of interrupt context. */
+void esas2r_adapter_tasklet(unsigned long context)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)context;
+
+	if (unlikely(a->flags2 & AF2_TIMER_TICK)) {
+		esas2r_lock_clear_flags(&a->flags2, AF2_TIMER_TICK);
+		esas2r_timer_tick(a);
+	}
+
+	if (likely(a->flags2 & AF2_INT_PENDING)) {
+		esas2r_lock_clear_flags(&a->flags2, AF2_INT_PENDING);
+		esas2r_adapter_interrupt(a);
+	}
+
+	if (esas2r_is_tasklet_pending(a))
+		esas2r_do_tasklet_tasks(a);
+
+	if (esas2r_is_tasklet_pending(a)
+	    || (a->flags2 & AF2_INT_PENDING)
+	    || (a->flags2 & AF2_TIMER_TICK)) {
+		esas2r_lock_clear_flags(&a->flags, AF_TASKLET_SCHEDULED);
+		esas2r_schedule_tasklet(a);
+	} else {
+		esas2r_lock_clear_flags(&a->flags, AF_TASKLET_SCHEDULED);
+	}
+}
+
+static void esas2r_timer_callback(unsigned long context);
+
+void esas2r_kickoff_timer(struct esas2r_adapter *a)
+{
+	init_timer(&a->timer);
+
+	a->timer.function = esas2r_timer_callback;
+	a->timer.data = (unsigned long)a;
+	a->timer.expires = jiffies +
+			   msecs_to_jiffies(100);
+
+	add_timer(&a->timer);
+}
+
+static void esas2r_timer_callback(unsigned long context)
+{
+	struct esas2r_adapter *a = (struct esas2r_adapter *)context;
+
+	esas2r_lock_set_flags(&a->flags2, AF2_TIMER_TICK);
+
+	esas2r_schedule_tasklet(a);
+
+	esas2r_kickoff_timer(a);
+}
+
+/*
+ * Firmware events need to be handled outside of interrupt context
+ * so we schedule a delayed_work to handle them.
+ */
+
+static void
+esas2r_free_fw_event(struct esas2r_fw_event_work *fw_event)
+{
+	unsigned long flags;
+	struct esas2r_adapter *a = fw_event->a;
+
+	spin_lock_irqsave(&a->fw_event_lock, flags);
+	list_del(&fw_event->list);
+	kfree(fw_event);
+	spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+void
+esas2r_fw_event_off(struct esas2r_adapter *a)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&a->fw_event_lock, flags);
+	a->fw_events_off = 1;
+	spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+void
+esas2r_fw_event_on(struct esas2r_adapter *a)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&a->fw_event_lock, flags);
+	a->fw_events_off = 0;
+	spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+static void esas2r_add_device(struct esas2r_adapter *a, u16 target_id)
+{
+	int ret;
+	struct scsi_device *scsi_dev;
+
+	scsi_dev = scsi_device_lookup(a->host, 0, target_id, 0);
+
+	if (scsi_dev) {
+		esas2r_log_dev(
+			ESAS2R_LOG_WARN,
+			&(scsi_dev->
+			  sdev_gendev),
+			"scsi device already exists at id %d", target_id);
+
+		scsi_device_put(scsi_dev);
+	} else {
+		esas2r_log_dev(
+			ESAS2R_LOG_INFO,
+			&(a->host->
+			  shost_gendev),
+			"scsi_add_device() called for 0:%d:0",
+			target_id);
+
+		ret = scsi_add_device(a->host, 0, target_id, 0);
+		if (ret) {
+			esas2r_log_dev(
+				ESAS2R_LOG_CRIT,
+				&(a->host->
+				  shost_gendev),
+				"scsi_add_device failed with %d for id %d",
+				ret, target_id);
+		}
+	}
+}
+
+static void esas2r_remove_device(struct esas2r_adapter *a, u16 target_id)
+{
+	struct scsi_device *scsi_dev;
+
+	scsi_dev = scsi_device_lookup(a->host, 0, target_id, 0);
+
+	if (scsi_dev) {
+		scsi_device_set_state(scsi_dev, SDEV_OFFLINE);
+
+		esas2r_log_dev(
+			ESAS2R_LOG_INFO,
+			&(scsi_dev->
+			  sdev_gendev),
+			"scsi_remove_device() called for 0:%d:0",
+			target_id);
+
+		scsi_remove_device(scsi_dev);
+
+		esas2r_log_dev(
+			ESAS2R_LOG_INFO,
+			&(scsi_dev->
+			  sdev_gendev),
+			"scsi_device_put() called");
+
+		scsi_device_put(scsi_dev);
+	} else {
+		esas2r_log_dev(
+			ESAS2R_LOG_WARN,
+			&(a->host->shost_gendev),
+			"no target found at id %d",
+			target_id);
+	}
+}
+
+/*
+ * Sends a firmware asynchronous event to anyone who happens to be
+ * listening on the defined ATTO VDA event ports.
+ */
+static void esas2r_send_ae_event(struct esas2r_fw_event_work *fw_event)
+{
+	struct esas2r_vda_ae *ae = (struct esas2r_vda_ae *)fw_event->data;
+	char *type;
+
+	switch (ae->vda_ae.hdr.bytype) {
+	case VDAAE_HDR_TYPE_RAID:
+		type = "RAID group state change";
+		break;
+
+	case VDAAE_HDR_TYPE_LU:
+		type = "Mapped destination LU change";
+		break;
+
+	case VDAAE_HDR_TYPE_DISK:
+		type = "Physical disk inventory change";
+		break;
+
+	case VDAAE_HDR_TYPE_RESET:
+		type = "Firmware reset";
+		break;
+
+	case VDAAE_HDR_TYPE_LOG_INFO:
+		type = "Event Log message (INFO level)";
+		break;
+
+	case VDAAE_HDR_TYPE_LOG_WARN:
+		type = "Event Log message (WARN level)";
+		break;
+
+	case VDAAE_HDR_TYPE_LOG_CRIT:
+		type = "Event Log message (CRIT level)";
+		break;
+
+	case VDAAE_HDR_TYPE_LOG_FAIL:
+		type = "Event Log message (FAIL level)";
+		break;
+
+	case VDAAE_HDR_TYPE_NVC:
+		type = "NVCache change";
+		break;
+
+	case VDAAE_HDR_TYPE_TLG_INFO:
+		type = "Time stamped log message (INFO level)";
+		break;
+
+	case VDAAE_HDR_TYPE_TLG_WARN:
+		type = "Time stamped log message (WARN level)";
+		break;
+
+	case VDAAE_HDR_TYPE_TLG_CRIT:
+		type = "Time stamped log message (CRIT level)";
+		break;
+
+	case VDAAE_HDR_TYPE_PWRMGT:
+		type = "Power management";
+		break;
+
+	case VDAAE_HDR_TYPE_MUTE:
+		type = "Mute button pressed";
+		break;
+
+	case VDAAE_HDR_TYPE_DEV:
+		type = "Device attribute change";
+		break;
+
+	default:
+		type = "Unknown";
+		break;
+	}
+
+	esas2r_log(ESAS2R_LOG_WARN,
+		   "An async event of type \"%s\" was received from the firmware.  The event contents are:",
+		   type);
+	esas2r_log_hexdump(ESAS2R_LOG_WARN, &ae->vda_ae,
+			   ae->vda_ae.hdr.bylength);
+
+}
+
+static void
+esas2r_firmware_event_work(struct work_struct *work)
+{
+	struct esas2r_fw_event_work *fw_event =
+		container_of(work, struct esas2r_fw_event_work, work.work);
+
+	struct esas2r_adapter *a = fw_event->a;
+
+	u16 target_id = *(u16 *)&fw_event->data[0];
+
+	if (a->fw_events_off)
+		goto done;
+
+	switch (fw_event->type) {
+	case fw_event_null:
+		break; /* do nothing */
+
+	case fw_event_lun_change:
+		esas2r_remove_device(a, target_id);
+		esas2r_add_device(a, target_id);
+		break;
+
+	case fw_event_present:
+		esas2r_add_device(a, target_id);
+		break;
+
+	case fw_event_not_present:
+		esas2r_remove_device(a, target_id);
+		break;
+
+	case fw_event_vda_ae:
+		esas2r_send_ae_event(fw_event);
+		break;
+	}
+
+done:
+	esas2r_free_fw_event(fw_event);
+}
+
+void esas2r_queue_fw_event(struct esas2r_adapter *a,
+			   enum fw_event_type type,
+			   void *data,
+			   int data_sz)
+{
+	struct esas2r_fw_event_work *fw_event;
+	unsigned long flags;
+
+	fw_event = kzalloc(sizeof(struct esas2r_fw_event_work), GFP_ATOMIC);
+	if (!fw_event) {
+		esas2r_log(ESAS2R_LOG_WARN,
+			   "esas2r_queue_fw_event failed to alloc");
+		return;
+	}
+
+	if (type == fw_event_vda_ae) {
+		struct esas2r_vda_ae *ae =
+			(struct esas2r_vda_ae *)fw_event->data;
+
+		ae->signature = ESAS2R_VDA_EVENT_SIG;
+		ae->bus_number = a->pcid->bus->number;
+		ae->devfn = a->pcid->devfn;
+		memcpy(&ae->vda_ae, data, sizeof(ae->vda_ae));
+	} else {
+		memcpy(fw_event->data, data, data_sz);
+	}
+
+	fw_event->type = type;
+	fw_event->a = a;
+
+	spin_lock_irqsave(&a->fw_event_lock, flags);
+	list_add_tail(&fw_event->list, &a->fw_event_list);
+	INIT_DELAYED_WORK(&fw_event->work, esas2r_firmware_event_work);
+	queue_delayed_work_on(
+		smp_processor_id(), a->fw_event_q, &fw_event->work,
+		msecs_to_jiffies(1));
+	spin_unlock_irqrestore(&a->fw_event_lock, flags);
+}
+
+void esas2r_target_state_changed(struct esas2r_adapter *a, u16 targ_id,
+				 u8 state)
+{
+	if (state == TS_LUN_CHANGE)
+		esas2r_queue_fw_event(a, fw_event_lun_change, &targ_id,
+				      sizeof(targ_id));
+	else if (state == TS_PRESENT)
+		esas2r_queue_fw_event(a, fw_event_present, &targ_id,
+				      sizeof(targ_id));
+	else if (state == TS_NOT_PRESENT)
+		esas2r_queue_fw_event(a, fw_event_not_present, &targ_id,
+				      sizeof(targ_id));
+}
+
+/* Translate status to a Linux SCSI mid-layer error code */
+int esas2r_req_status_to_error(u8 req_stat)
+{
+	switch (req_stat) {
+	case RS_OVERRUN:
+	case RS_UNDERRUN:
+	case RS_SUCCESS:
+	/*
+	 * NOTE: SCSI mid-layer wants a good status for a SCSI error, because
+	 *       it will check the scsi_stat value in the completion anyway.
+	 */
+	case RS_SCSI_ERROR:
+		return DID_OK;
+
+	case RS_SEL:
+	case RS_SEL2:
+		return DID_NO_CONNECT;
+
+	case RS_RESET:
+		return DID_RESET;
+
+	case RS_ABORTED:
+		return DID_ABORT;
+
+	case RS_BUSY:
+		return DID_BUS_BUSY;
+	}
+
+	/* everything else is just an error. */
+
+	return DID_ERROR;
+}
+
+module_init(esas2r_init);
+module_exit(esas2r_exit);
diff --git a/drivers/scsi/esas2r/esas2r_targdb.c b/drivers/scsi/esas2r/esas2r_targdb.c
new file mode 100644
index 0000000..e540a2f
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_targdb.c
@@ -0,0 +1,306 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_targdb.c
+ *      For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+ *
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ * 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-1301,
+ * USA.
+ */
+
+#include "esas2r.h"
+
+void esas2r_targ_db_initialize(struct esas2r_adapter *a)
+{
+	struct esas2r_target *t;
+
+	for (t = a->targetdb; t < a->targetdb_end; t++) {
+		memset(t, 0, sizeof(struct esas2r_target));
+
+		t->target_state = TS_NOT_PRESENT;
+		t->buffered_target_state = TS_NOT_PRESENT;
+		t->new_target_state = TS_INVALID;
+	}
+}
+
+void esas2r_targ_db_remove_all(struct esas2r_adapter *a, bool notify)
+{
+	struct esas2r_target *t;
+	unsigned long flags;
+
+	for (t = a->targetdb; t < a->targetdb_end; t++) {
+		if (t->target_state != TS_PRESENT)
+			continue;
+
+		spin_lock_irqsave(&a->mem_lock, flags);
+		esas2r_targ_db_remove(a, t);
+		spin_unlock_irqrestore(&a->mem_lock, flags);
+
+		if (notify) {
+			esas2r_trace("remove id:%d", esas2r_targ_get_id(t,
+									a));
+			esas2r_target_state_changed(a, esas2r_targ_get_id(t,
+									  a),
+						    TS_NOT_PRESENT);
+		}
+	}
+}
+
+void esas2r_targ_db_report_changes(struct esas2r_adapter *a)
+{
+	struct esas2r_target *t;
+	unsigned long flags;
+
+	esas2r_trace_enter();
+
+	if (a->flags & AF_DISC_PENDING) {
+		esas2r_trace_exit();
+		return;
+	}
+
+	for (t = a->targetdb; t < a->targetdb_end; t++) {
+		u8 state = TS_INVALID;
+
+		spin_lock_irqsave(&a->mem_lock, flags);
+		if (t->buffered_target_state != t->target_state)
+			state = t->buffered_target_state = t->target_state;
+
+		spin_unlock_irqrestore(&a->mem_lock, flags);
+		if (state != TS_INVALID) {
+			esas2r_trace("targ_db_report_changes:%d",
+				     esas2r_targ_get_id(
+					     t,
+					     a));
+			esas2r_trace("state:%d", state);
+
+			esas2r_target_state_changed(a,
+						    esas2r_targ_get_id(t,
+								       a),
+						    state);
+		}
+	}
+
+	esas2r_trace_exit();
+}
+
+struct esas2r_target *esas2r_targ_db_add_raid(struct esas2r_adapter *a,
+					      struct esas2r_disc_context *
+					      dc)
+{
+	struct esas2r_target *t;
+
+	esas2r_trace_enter();
+
+	if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) {
+		esas2r_bugon();
+		esas2r_trace_exit();
+		return NULL;
+	}
+
+	t = a->targetdb + dc->curr_virt_id;
+
+	if (t->target_state == TS_PRESENT) {
+		esas2r_trace_exit();
+		return NULL;
+	}
+
+	esas2r_hdebug("add RAID %s, T:%d", dc->raid_grp_name,
+		      esas2r_targ_get_id(
+			      t,
+			      a));
+
+	if (dc->interleave == 0
+	    || dc->block_size  == 0) {
+		/* these are invalid values, don't create the target entry. */
+
+		esas2r_hdebug("invalid RAID group dimensions");
+
+		esas2r_trace_exit();
+
+		return NULL;
+	}
+
+	t->block_size = dc->block_size;
+	t->inter_byte = dc->interleave;
+	t->inter_block = dc->interleave / dc->block_size;
+	t->virt_targ_id = dc->curr_virt_id;
+	t->phys_targ_id = ESAS2R_TARG_ID_INV;
+
+	t->flags &= ~TF_PASS_THRU;
+	t->flags |= TF_USED;
+
+	t->identifier_len = 0;
+
+	t->target_state = TS_PRESENT;
+
+	return t;
+}
+
+struct esas2r_target *esas2r_targ_db_add_pthru(struct esas2r_adapter *a,
+					       struct esas2r_disc_context *dc,
+					       u8 *ident,
+					       u8 ident_len)
+{
+	struct esas2r_target *t;
+
+	esas2r_trace_enter();
+
+	if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) {
+		esas2r_bugon();
+		esas2r_trace_exit();
+		return NULL;
+	}
+
+	/* see if we found this device before. */
+
+	t = esas2r_targ_db_find_by_ident(a, ident, ident_len);
+
+	if (t == NULL) {
+		t = a->targetdb + dc->curr_virt_id;
+
+		if (ident_len > sizeof(t->identifier)
+		    || t->target_state == TS_PRESENT) {
+			esas2r_trace_exit();
+			return NULL;
+		}
+	}
+
+	esas2r_hdebug("add PT; T:%d, V:%d, P:%d", esas2r_targ_get_id(t, a),
+		      dc->curr_virt_id,
+		      dc->curr_phys_id);
+
+	t->block_size = 0;
+	t->inter_byte = 0;
+	t->inter_block = 0;
+	t->virt_targ_id = dc->curr_virt_id;
+	t->phys_targ_id = dc->curr_phys_id;
+	t->identifier_len = ident_len;
+
+	memcpy(t->identifier, ident, ident_len);
+
+	t->flags |= TF_PASS_THRU | TF_USED;
+
+	t->target_state = TS_PRESENT;
+
+	return t;
+}
+
+void esas2r_targ_db_remove(struct esas2r_adapter *a, struct esas2r_target *t)
+{
+	esas2r_trace_enter();
+
+	t->target_state = TS_NOT_PRESENT;
+
+	esas2r_trace("remove id:%d", esas2r_targ_get_id(t, a));
+
+	esas2r_trace_exit();
+}
+
+struct esas2r_target *esas2r_targ_db_find_by_sas_addr(struct esas2r_adapter *a,
+						      u64 *sas_addr)
+{
+	struct esas2r_target *t;
+
+	for (t = a->targetdb; t < a->targetdb_end; t++)
+		if (t->sas_addr == *sas_addr)
+			return t;
+
+	return NULL;
+}
+
+struct esas2r_target *esas2r_targ_db_find_by_ident(struct esas2r_adapter *a,
+						   void *identifier,
+						   u8 ident_len)
+{
+	struct esas2r_target *t;
+
+	for (t = a->targetdb; t < a->targetdb_end; t++) {
+		if (ident_len == t->identifier_len
+		    && memcmp(&t->identifier[0], identifier,
+			      ident_len) == 0)
+			return t;
+	}
+
+	return NULL;
+}
+
+u16 esas2r_targ_db_find_next_present(struct esas2r_adapter *a, u16 target_id)
+{
+	u16 id = target_id + 1;
+
+	while (id < ESAS2R_MAX_TARGETS) {
+		struct esas2r_target *t = a->targetdb + id;
+
+		if (t->target_state == TS_PRESENT)
+			break;
+
+		id++;
+	}
+
+	return id;
+}
+
+struct esas2r_target *esas2r_targ_db_find_by_virt_id(struct esas2r_adapter *a,
+						     u16 virt_id)
+{
+	struct esas2r_target *t;
+
+	for (t = a->targetdb; t < a->targetdb_end; t++) {
+		if (t->target_state != TS_PRESENT)
+			continue;
+
+		if (t->virt_targ_id == virt_id)
+			return t;
+	}
+
+	return NULL;
+}
+
+u16 esas2r_targ_db_get_tgt_cnt(struct esas2r_adapter *a)
+{
+	u16 devcnt = 0;
+	struct esas2r_target *t;
+	unsigned long flags;
+
+	spin_lock_irqsave(&a->mem_lock, flags);
+	for (t = a->targetdb; t < a->targetdb_end; t++)
+		if (t->target_state == TS_PRESENT)
+			devcnt++;
+
+	spin_unlock_irqrestore(&a->mem_lock, flags);
+
+	return devcnt;
+}
diff --git a/drivers/scsi/esas2r/esas2r_vda.c b/drivers/scsi/esas2r/esas2r_vda.c
new file mode 100644
index 0000000..f8ec6d6
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_vda.c
@@ -0,0 +1,521 @@
+/*
+ *  linux/drivers/scsi/esas2r/esas2r_vda.c
+ *      esas2r driver VDA firmware interface functions
+ *
+ *  Copyright (c) 2001-2013 ATTO Technology, Inc.
+ *  (mailto:linuxdrivers@attotech.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; 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.
+ *
+ *  NO WARRANTY
+ *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ *  solely responsible for determining the appropriateness of using and
+ *  distributing the Program and assumes all risks associated with its
+ *  exercise of rights under this Agreement, including but not limited to
+ *  the risks and costs of program errors, damage to or loss of data,
+ *  programs or equipment, and unavailability or interruption of operations.
+ *
+ *  DISCLAIMER OF LIABILITY
+ *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+ *
+ *  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 "esas2r.h"
+
+static u8 esas2r_vdaioctl_versions[] = {
+	ATTO_VDA_VER_UNSUPPORTED,
+	ATTO_VDA_FLASH_VER,
+	ATTO_VDA_VER_UNSUPPORTED,
+	ATTO_VDA_VER_UNSUPPORTED,
+	ATTO_VDA_CLI_VER,
+	ATTO_VDA_VER_UNSUPPORTED,
+	ATTO_VDA_CFG_VER,
+	ATTO_VDA_MGT_VER,
+	ATTO_VDA_GSV_VER
+};
+
+static void clear_vda_request(struct esas2r_request *rq);
+
+static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
+				      struct esas2r_request *rq);
+
+/* Prepare a VDA IOCTL request to be sent to the firmware. */
+bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
+			      struct atto_ioctl_vda *vi,
+			      struct esas2r_request *rq,
+			      struct esas2r_sg_context *sgc)
+{
+	u32 datalen = 0;
+	struct atto_vda_sge *firstsg = NULL;
+	u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
+
+	vi->status = ATTO_STS_SUCCESS;
+	vi->vda_status = RS_PENDING;
+
+	if (vi->function >= vercnt) {
+		vi->status = ATTO_STS_INV_FUNC;
+		return false;
+	}
+
+	if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
+		vi->status = ATTO_STS_INV_VERSION;
+		return false;
+	}
+
+	if (a->flags & AF_DEGRADED_MODE) {
+		vi->status = ATTO_STS_DEGRADED;
+		return false;
+	}
+
+	if (vi->function != VDA_FUNC_SCSI)
+		clear_vda_request(rq);
+
+	rq->vrq->scsi.function = vi->function;
+	rq->interrupt_cb = esas2r_complete_vda_ioctl;
+	rq->interrupt_cx = vi;
+
+	switch (vi->function) {
+	case VDA_FUNC_FLASH:
+
+		if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
+		    && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
+		    && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
+			vi->status = ATTO_STS_INV_FUNC;
+			return false;
+		}
+
+		if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
+			datalen = vi->data_length;
+
+		rq->vrq->flash.length = cpu_to_le32(datalen);
+		rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
+
+		memcpy(rq->vrq->flash.data.file.file_name,
+		       vi->cmd.flash.data.file.file_name,
+		       sizeof(vi->cmd.flash.data.file.file_name));
+
+		firstsg = rq->vrq->flash.data.file.sge;
+		break;
+
+	case VDA_FUNC_CLI:
+
+		datalen = vi->data_length;
+
+		rq->vrq->cli.cmd_rsp_len =
+			cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
+		rq->vrq->cli.length = cpu_to_le32(datalen);
+
+		firstsg = rq->vrq->cli.sge;
+		break;
+
+	case VDA_FUNC_MGT:
+	{
+		u8 *cmdcurr_offset = sgc->cur_offset
+				     - offsetof(struct atto_ioctl_vda, data)
+				     + offsetof(struct atto_ioctl_vda, cmd)
+				     + offsetof(struct atto_ioctl_vda_mgt_cmd,
+						data);
+		/*
+		 * build the data payload SGL here first since
+		 * esas2r_sgc_init() will modify the S/G list offset for the
+		 * management SGL (which is built below where the data SGL is
+		 * usually built).
+		 */
+
+		if (vi->data_length) {
+			u32 payldlen = 0;
+
+			if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
+			    || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
+				rq->vrq->mgt.payld_sglst_offset =
+					(u8)offsetof(struct atto_vda_mgmt_req,
+						     payld_sge);
+
+				payldlen = vi->data_length;
+				datalen = vi->cmd.mgt.data_length;
+			} else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
+				   || vi->cmd.mgt.mgt_func ==
+				   VDAMGT_DEV_INFO2_BYADDR) {
+				datalen = vi->data_length;
+				cmdcurr_offset = sgc->cur_offset;
+			} else {
+				vi->status = ATTO_STS_INV_PARAM;
+				return false;
+			}
+
+			/* Setup the length so building the payload SGL works */
+			rq->vrq->mgt.length = cpu_to_le32(datalen);
+
+			if (payldlen) {
+				rq->vrq->mgt.payld_length =
+					cpu_to_le32(payldlen);
+
+				esas2r_sgc_init(sgc, a, rq,
+						rq->vrq->mgt.payld_sge);
+				sgc->length = payldlen;
+
+				if (!esas2r_build_sg_list(a, rq, sgc)) {
+					vi->status = ATTO_STS_OUT_OF_RSRC;
+					return false;
+				}
+			}
+		} else {
+			datalen = vi->cmd.mgt.data_length;
+
+			rq->vrq->mgt.length = cpu_to_le32(datalen);
+		}
+
+		/*
+		 * Now that the payload SGL is built, if any, setup to build
+		 * the management SGL.
+		 */
+		firstsg = rq->vrq->mgt.sge;
+		sgc->cur_offset = cmdcurr_offset;
+
+		/* Finish initializing the management request. */
+		rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
+		rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
+		rq->vrq->mgt.dev_index =
+			cpu_to_le32(vi->cmd.mgt.dev_index);
+
+		esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
+		break;
+	}
+
+	case VDA_FUNC_CFG:
+
+		if (vi->data_length
+		    || vi->cmd.cfg.data_length == 0) {
+			vi->status = ATTO_STS_INV_PARAM;
+			return false;
+		}
+
+		if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
+			vi->status = ATTO_STS_INV_FUNC;
+			return false;
+		}
+
+		rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
+		rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
+
+		if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
+			memcpy(&rq->vrq->cfg.data,
+			       &vi->cmd.cfg.data,
+			       vi->cmd.cfg.data_length);
+
+			esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
+					     &rq->vrq->cfg.data);
+		} else {
+			vi->status = ATTO_STS_INV_FUNC;
+
+			return false;
+		}
+
+		break;
+
+	case VDA_FUNC_GSV:
+
+		vi->cmd.gsv.rsp_len = vercnt;
+
+		memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
+		       vercnt);
+
+		vi->vda_status = RS_SUCCESS;
+		break;
+
+	default:
+
+		vi->status = ATTO_STS_INV_FUNC;
+		return false;
+	}
+
+	if (datalen) {
+		esas2r_sgc_init(sgc, a, rq, firstsg);
+		sgc->length = datalen;
+
+		if (!esas2r_build_sg_list(a, rq, sgc)) {
+			vi->status = ATTO_STS_OUT_OF_RSRC;
+			return false;
+		}
+	}
+
+	esas2r_start_request(a, rq);
+
+	return true;
+}
+
+static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
+				      struct esas2r_request *rq)
+{
+	struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
+
+	vi->vda_status = rq->req_stat;
+
+	switch (vi->function) {
+	case VDA_FUNC_FLASH:
+
+		if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
+		    || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
+			vi->cmd.flash.data.file.file_size =
+				le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
+
+		break;
+
+	case VDA_FUNC_MGT:
+
+		vi->cmd.mgt.scan_generation =
+			rq->func_rsp.mgt_rsp.scan_generation;
+		vi->cmd.mgt.dev_index = le16_to_cpu(
+			rq->func_rsp.mgt_rsp.dev_index);
+
+		if (vi->data_length == 0)
+			vi->cmd.mgt.data_length =
+				le32_to_cpu(rq->func_rsp.mgt_rsp.length);
+
+		esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
+		break;
+
+	case VDA_FUNC_CFG:
+
+		if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
+			struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
+			struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
+
+			cfg->data_length =
+				cpu_to_le32(sizeof(struct atto_vda_cfg_init));
+			cfg->data.init.vda_version =
+				le32_to_cpu(rsp->vda_version);
+			cfg->data.init.fw_build = rsp->fw_build;
+
+			sprintf((char *)&cfg->data.init.fw_release,
+				"%1d.%02d",
+				(int)LOBYTE(le16_to_cpu(rsp->fw_release)),
+				(int)HIBYTE(le16_to_cpu(rsp->fw_release)));
+
+			if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
+				cfg->data.init.fw_version =
+					cfg->data.init.fw_build;
+			else
+				cfg->data.init.fw_version =
+					cfg->data.init.fw_release;
+		} else {
+			esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
+					     &vi->cmd.cfg.data);
+		}
+
+		break;
+
+	case VDA_FUNC_CLI:
+
+		vi->cmd.cli.cmd_rsp_len =
+			le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
+		break;
+
+	default:
+
+		break;
+	}
+}
+
+/* Build a flash VDA request. */
+void esas2r_build_flash_req(struct esas2r_adapter *a,
+			    struct esas2r_request *rq,
+			    u8 sub_func,
+			    u8 cksum,
+			    u32 addr,
+			    u32 length)
+{
+	struct atto_vda_flash_req *vrq = &rq->vrq->flash;
+
+	clear_vda_request(rq);
+
+	rq->vrq->scsi.function = VDA_FUNC_FLASH;
+
+	if (sub_func == VDA_FLASH_BEGINW
+	    || sub_func == VDA_FLASH_WRITE
+	    || sub_func == VDA_FLASH_READ)
+		vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
+						   data.sge);
+
+	vrq->length = cpu_to_le32(length);
+	vrq->flash_addr = cpu_to_le32(addr);
+	vrq->checksum = cksum;
+	vrq->sub_func = sub_func;
+}
+
+/* Build a VDA management request. */
+void esas2r_build_mgt_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq,
+			  u8 sub_func,
+			  u8 scan_gen,
+			  u16 dev_index,
+			  u32 length,
+			  void *data)
+{
+	struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
+
+	clear_vda_request(rq);
+
+	rq->vrq->scsi.function = VDA_FUNC_MGT;
+
+	vrq->mgt_func = sub_func;
+	vrq->scan_generation = scan_gen;
+	vrq->dev_index = cpu_to_le16(dev_index);
+	vrq->length = cpu_to_le32(length);
+
+	if (vrq->length) {
+		if (a->flags & AF_LEGACY_SGE_MODE) {
+			vrq->sg_list_offset = (u8)offsetof(
+				struct atto_vda_mgmt_req, sge);
+
+			vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
+			vrq->sge[0].address = cpu_to_le64(
+				rq->vrq_md->phys_addr +
+				sizeof(union atto_vda_req));
+		} else {
+			vrq->sg_list_offset = (u8)offsetof(
+				struct atto_vda_mgmt_req, prde);
+
+			vrq->prde[0].ctl_len = cpu_to_le32(length);
+			vrq->prde[0].address = cpu_to_le64(
+				rq->vrq_md->phys_addr +
+				sizeof(union atto_vda_req));
+		}
+	}
+
+	if (data) {
+		esas2r_nuxi_mgt_data(sub_func, data);
+
+		memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
+		       length);
+	}
+}
+
+/* Build a VDA asyncronous event (AE) request. */
+void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
+{
+	struct atto_vda_ae_req *vrq = &rq->vrq->ae;
+
+	clear_vda_request(rq);
+
+	rq->vrq->scsi.function = VDA_FUNC_AE;
+
+	vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
+
+	if (a->flags & AF_LEGACY_SGE_MODE) {
+		vrq->sg_list_offset =
+			(u8)offsetof(struct atto_vda_ae_req, sge);
+		vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
+		vrq->sge[0].address = cpu_to_le64(
+			rq->vrq_md->phys_addr +
+			sizeof(union atto_vda_req));
+	} else {
+		vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
+						   prde);
+		vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
+		vrq->prde[0].address = cpu_to_le64(
+			rq->vrq_md->phys_addr +
+			sizeof(union atto_vda_req));
+	}
+}
+
+/* Build a VDA CLI request. */
+void esas2r_build_cli_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq,
+			  u32 length,
+			  u32 cmd_rsp_len)
+{
+	struct atto_vda_cli_req *vrq = &rq->vrq->cli;
+
+	clear_vda_request(rq);
+
+	rq->vrq->scsi.function = VDA_FUNC_CLI;
+
+	vrq->length = cpu_to_le32(length);
+	vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
+	vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
+}
+
+/* Build a VDA IOCTL request. */
+void esas2r_build_ioctl_req(struct esas2r_adapter *a,
+			    struct esas2r_request *rq,
+			    u32 length,
+			    u8 sub_func)
+{
+	struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
+
+	clear_vda_request(rq);
+
+	rq->vrq->scsi.function = VDA_FUNC_IOCTL;
+
+	vrq->length = cpu_to_le32(length);
+	vrq->sub_func = sub_func;
+	vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
+}
+
+/* Build a VDA configuration request. */
+void esas2r_build_cfg_req(struct esas2r_adapter *a,
+			  struct esas2r_request *rq,
+			  u8 sub_func,
+			  u32 length,
+			  void *data)
+{
+	struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
+
+	clear_vda_request(rq);
+
+	rq->vrq->scsi.function = VDA_FUNC_CFG;
+
+	vrq->sub_func = sub_func;
+	vrq->length = cpu_to_le32(length);
+
+	if (data) {
+		esas2r_nuxi_cfg_data(sub_func, data);
+
+		memcpy(&vrq->data, data, length);
+	}
+}
+
+static void clear_vda_request(struct esas2r_request *rq)
+{
+	u32 handle = rq->vrq->scsi.handle;
+
+	memset(rq->vrq, 0, sizeof(*rq->vrq));
+
+	rq->vrq->scsi.handle = handle;
+
+	rq->req_stat = RS_PENDING;
+
+	/* since the data buffer is separate clear that too */
+
+	memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
+
+	/*
+	 * Setup next and prev pointer in case the request is not going through
+	 * esas2r_start_request().
+	 */
+
+	INIT_LIST_HEAD(&rq->req_list);
+}
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 7f4f790..b766f5a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -583,7 +583,7 @@
 		c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
 		if (likely(h->msix_vector))
 			c->Header.ReplyQueue =
-				smp_processor_id() % h->nreply_queues;
+				raw_smp_processor_id() % h->nreply_queues;
 	}
 }
 
@@ -1205,8 +1205,8 @@
 	scsi_set_resid(cmd, ei->ResidualCnt);
 
 	if (ei->CommandStatus == 0) {
-		cmd->scsi_done(cmd);
 		cmd_free(h, cp);
+		cmd->scsi_done(cmd);
 		return;
 	}
 
@@ -1379,8 +1379,8 @@
 		dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
 				cp, ei->CommandStatus);
 	}
-	cmd->scsi_done(cmd);
 	cmd_free(h, cp);
+	cmd->scsi_done(cmd);
 }
 
 static void hpsa_pci_unmap(struct pci_dev *pdev,
@@ -2721,7 +2721,6 @@
 	} while (test_and_set_bit
 		 (i & (BITS_PER_LONG - 1),
 		  h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
-	h->nr_allocs++;
 	spin_unlock_irqrestore(&h->lock, flags);
 
 	c = h->cmd_pool + i;
@@ -2793,7 +2792,6 @@
 	spin_lock_irqsave(&h->lock, flags);
 	clear_bit(i & (BITS_PER_LONG - 1),
 		  h->cmd_pool_bits + (i / BITS_PER_LONG));
-	h->nr_frees++;
 	spin_unlock_irqrestore(&h->lock, flags);
 }
 
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 9816479..bc85e72 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -98,8 +98,6 @@
 	struct ErrorInfo 	*errinfo_pool;
 	dma_addr_t		errinfo_pool_dhandle;
 	unsigned long  		*cmd_pool_bits;
-	int			nr_allocs;
-	int			nr_frees;
 	int			scan_finished;
 	spinlock_t		scan_lock;
 	wait_queue_head_t	scan_wait_queue;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 6601e03..36ac1c3 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -9990,6 +9990,20 @@
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D7, 0, 0, 0 },
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
 		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D8, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57D9, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EB, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EC, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57ED, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EE, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57EF, 0, 0, 0 },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57F0, 0, 0, 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, ipr_pci_table);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 07a85ce..cad1483 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -100,6 +100,13 @@
 #define IPR_SUBS_DEV_ID_57D6    0x03FC
 #define IPR_SUBS_DEV_ID_57D7    0x03FF
 #define IPR_SUBS_DEV_ID_57D8    0x03FE
+#define IPR_SUBS_DEV_ID_57D9    0x046D
+#define IPR_SUBS_DEV_ID_57EB    0x0474
+#define IPR_SUBS_DEV_ID_57EC    0x0475
+#define IPR_SUBS_DEV_ID_57ED    0x0499
+#define IPR_SUBS_DEV_ID_57EE    0x049A
+#define IPR_SUBS_DEV_ID_57EF    0x049B
+#define IPR_SUBS_DEV_ID_57F0    0x049C
 #define IPR_NAME				"ipr"
 
 /*
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index cd962da..85c77f6 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -311,9 +311,9 @@
 					      &ihost->phys[phy_index]);
 
 			assigned_phy_mask |= (1 << phy_index);
+			phy_index++;
 		}
 
-		phy_index++;
 	}
 
 	return sci_port_configuration_agent_validate_ports(ihost, port_agent);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index ae69dfc..e399561 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2812,6 +2812,8 @@
 	kfree(session->boot_nic);
 	kfree(session->boot_target);
 	kfree(session->ifacename);
+	kfree(session->portal_type);
+	kfree(session->discovery_parent_type);
 
 	iscsi_destroy_session(cls_session);
 	iscsi_host_dec_session_cnt(shost);
@@ -3168,6 +3170,7 @@
 {
 	struct iscsi_conn *conn = cls_conn->dd_data;
 	struct iscsi_session *session = conn->session;
+	int val;
 
 	switch(param) {
 	case ISCSI_PARAM_FAST_ABORT:
@@ -3257,6 +3260,15 @@
 		return iscsi_switch_str_param(&session->boot_nic, buf);
 	case ISCSI_PARAM_BOOT_TARGET:
 		return iscsi_switch_str_param(&session->boot_target, buf);
+	case ISCSI_PARAM_PORTAL_TYPE:
+		return iscsi_switch_str_param(&session->portal_type, buf);
+	case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
+		return iscsi_switch_str_param(&session->discovery_parent_type,
+					      buf);
+	case ISCSI_PARAM_DISCOVERY_SESS:
+		sscanf(buf, "%d", &val);
+		session->discovery_sess = !!val;
+		break;
 	default:
 		return -ENOSYS;
 	}
@@ -3305,6 +3317,9 @@
 	case ISCSI_PARAM_DATASEQ_INORDER_EN:
 		len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
 		break;
+	case ISCSI_PARAM_DEF_TASKMGMT_TMO:
+		len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo);
+		break;
 	case ISCSI_PARAM_ERL:
 		len = sprintf(buf, "%d\n", session->erl);
 		break;
@@ -3344,6 +3359,52 @@
 	case ISCSI_PARAM_BOOT_TARGET:
 		len = sprintf(buf, "%s\n", session->boot_target);
 		break;
+	case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
+		len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable);
+		break;
+	case ISCSI_PARAM_DISCOVERY_SESS:
+		len = sprintf(buf, "%u\n", session->discovery_sess);
+		break;
+	case ISCSI_PARAM_PORTAL_TYPE:
+		len = sprintf(buf, "%s\n", session->portal_type);
+		break;
+	case ISCSI_PARAM_CHAP_AUTH_EN:
+		len = sprintf(buf, "%u\n", session->chap_auth_en);
+		break;
+	case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
+		len = sprintf(buf, "%u\n", session->discovery_logout_en);
+		break;
+	case ISCSI_PARAM_BIDI_CHAP_EN:
+		len = sprintf(buf, "%u\n", session->bidi_chap_en);
+		break;
+	case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
+		len = sprintf(buf, "%u\n", session->discovery_auth_optional);
+		break;
+	case ISCSI_PARAM_DEF_TIME2WAIT:
+		len = sprintf(buf, "%d\n", session->time2wait);
+		break;
+	case ISCSI_PARAM_DEF_TIME2RETAIN:
+		len = sprintf(buf, "%d\n", session->time2retain);
+		break;
+	case ISCSI_PARAM_TSID:
+		len = sprintf(buf, "%u\n", session->tsid);
+		break;
+	case ISCSI_PARAM_ISID:
+		len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
+			      session->isid[0], session->isid[1],
+			      session->isid[2], session->isid[3],
+			      session->isid[4], session->isid[5]);
+		break;
+	case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
+		len = sprintf(buf, "%u\n", session->discovery_parent_idx);
+		break;
+	case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
+		if (session->discovery_parent_type)
+			len = sprintf(buf, "%s\n",
+				      session->discovery_parent_type);
+		else
+			len = sprintf(buf, "\n");
+		break;
 	default:
 		return -ENOSYS;
 	}
@@ -3433,6 +3494,54 @@
 	case ISCSI_PARAM_PERSISTENT_ADDRESS:
 		len = sprintf(buf, "%s\n", conn->persistent_address);
 		break;
+	case ISCSI_PARAM_STATSN:
+		len = sprintf(buf, "%u\n", conn->statsn);
+		break;
+	case ISCSI_PARAM_MAX_SEGMENT_SIZE:
+		len = sprintf(buf, "%u\n", conn->max_segment_size);
+		break;
+	case ISCSI_PARAM_KEEPALIVE_TMO:
+		len = sprintf(buf, "%u\n", conn->keepalive_tmo);
+		break;
+	case ISCSI_PARAM_LOCAL_PORT:
+		len = sprintf(buf, "%u\n", conn->local_port);
+		break;
+	case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
+		len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat);
+		break;
+	case ISCSI_PARAM_TCP_NAGLE_DISABLE:
+		len = sprintf(buf, "%u\n", conn->tcp_nagle_disable);
+		break;
+	case ISCSI_PARAM_TCP_WSF_DISABLE:
+		len = sprintf(buf, "%u\n", conn->tcp_wsf_disable);
+		break;
+	case ISCSI_PARAM_TCP_TIMER_SCALE:
+		len = sprintf(buf, "%u\n", conn->tcp_timer_scale);
+		break;
+	case ISCSI_PARAM_TCP_TIMESTAMP_EN:
+		len = sprintf(buf, "%u\n", conn->tcp_timestamp_en);
+		break;
+	case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
+		len = sprintf(buf, "%u\n", conn->fragment_disable);
+		break;
+	case ISCSI_PARAM_IPV4_TOS:
+		len = sprintf(buf, "%u\n", conn->ipv4_tos);
+		break;
+	case ISCSI_PARAM_IPV6_TC:
+		len = sprintf(buf, "%u\n", conn->ipv6_traffic_class);
+		break;
+	case ISCSI_PARAM_IPV6_FLOW_LABEL:
+		len = sprintf(buf, "%u\n", conn->ipv6_flow_label);
+		break;
+	case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
+		len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6);
+		break;
+	case ISCSI_PARAM_TCP_XMIT_WSF:
+		len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf);
+		break;
+	case ISCSI_PARAM_TCP_RECV_WSF:
+		len = sprintf(buf, "%u\n", conn->tcp_recv_wsf);
+		break;
 	default:
 		return -ENOSYS;
 	}
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 93f222d..df43bfe 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -421,6 +421,7 @@
 	uint32_t cfg_enable_da_id;
 	uint32_t cfg_max_scsicmpl_time;
 	uint32_t cfg_tgt_queue_depth;
+	uint32_t cfg_first_burst_size;
 
 	uint32_t dev_loss_tmo_changed;
 
@@ -710,8 +711,6 @@
 	uint32_t cfg_use_msi;
 	uint32_t cfg_fcp_imax;
 	uint32_t cfg_fcp_cpu_map;
-	uint32_t cfg_fcp_wq_count;
-	uint32_t cfg_fcp_eq_count;
 	uint32_t cfg_fcp_io_channel;
 	uint32_t cfg_total_seg_cnt;
 	uint32_t cfg_sg_seg_cnt;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5cb08ae..22f42f8 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -674,9 +674,6 @@
 	int i;
 	int rc;
 
-	if (phba->pport->fc_flag & FC_OFFLINE_MODE)
-		return 0;
-
 	init_completion(&online_compl);
 	rc = lpfc_workq_post_event(phba, &status, &online_compl,
 			      LPFC_EVT_OFFLINE_PREP);
@@ -744,14 +741,15 @@
 	int status = 0;
 	int rc;
 
-	if ((!phba->cfg_enable_hba_reset) ||
-	    (phba->pport->fc_flag & FC_OFFLINE_MODE))
+	if (!phba->cfg_enable_hba_reset)
 		return -EACCES;
 
-	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
+	if (!(phba->pport->fc_flag & FC_OFFLINE_MODE)) {
+		status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
-	if (status != 0)
-		return status;
+		if (status != 0)
+			return status;
+	}
 
 	init_completion(&online_compl);
 	rc = lpfc_workq_post_event(phba, &status, &online_compl,
@@ -2591,9 +2589,12 @@
 
 /*
 # lun_queue_depth:  This parameter is used to limit the number of outstanding
-# commands per FCP LUN. Value range is [1,128]. Default value is 30.
+# commands per FCP LUN. Value range is [1,512]. Default value is 30.
+# If this parameter value is greater than 1/8th the maximum number of exchanges
+# supported by the HBA port, then the lun queue depth will be reduced to
+# 1/8th the maximum number of exchanges.
 */
-LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
+LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 512,
 		  "Max number of FCP commands we can queue to a specific LUN");
 
 /*
@@ -2601,7 +2602,7 @@
 # commands per target port. Value range is [10,65535]. Default value is 65535.
 */
 LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535,
-	"Max number of FCP commands we can queue to a specific target port");
+		  "Max number of FCP commands we can queue to a specific target port");
 
 /*
 # hba_queue_depth:  This parameter is used to limit the number of outstanding
@@ -3949,6 +3950,14 @@
 		   "Use ADISC on rediscovery to authenticate FCP devices");
 
 /*
+# lpfc_first_burst_size: First burst size to use on the NPorts
+# that support first burst.
+# Value range is [0,65536]. Default value is 0.
+*/
+LPFC_VPORT_ATTR_RW(first_burst_size, 0, 0, 65536,
+		   "First burst size for Targets that support first burst");
+
+/*
 # lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue
 # depth. Default value is 0. When the value of this parameter is zero the
 # SCSI command completion time is not used for controlling I/O queue depth. When
@@ -4112,25 +4121,6 @@
 	    "MSI-X (2), if possible");
 
 /*
-# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues
-# This parameter is ignored and will eventually be depricated
-#
-# Value range is [1,7]. Default value is 4.
-*/
-LPFC_ATTR_R(fcp_wq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
-	    LPFC_FCP_IO_CHAN_MAX,
-	    "Set the number of fast-path FCP work queues, if possible");
-
-/*
-# lpfc_fcp_eq_count: Set the number of FCP EQ/CQ/WQ IO channels
-#
-# Value range is [1,7]. Default value is 4.
-*/
-LPFC_ATTR_R(fcp_eq_count, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
-	    LPFC_FCP_IO_CHAN_MAX,
-	    "Set the number of fast-path FCP event queues, if possible");
-
-/*
 # lpfc_fcp_io_channel: Set the number of FCP EQ/CQ/WQ IO channels
 #
 # Value range is [1,7]. Default value is 4.
@@ -4276,6 +4266,7 @@
 	&dev_attr_lpfc_devloss_tmo,
 	&dev_attr_lpfc_fcp_class,
 	&dev_attr_lpfc_use_adisc,
+	&dev_attr_lpfc_first_burst_size,
 	&dev_attr_lpfc_ack0,
 	&dev_attr_lpfc_topology,
 	&dev_attr_lpfc_scan_down,
@@ -4307,8 +4298,6 @@
 	&dev_attr_lpfc_use_msi,
 	&dev_attr_lpfc_fcp_imax,
 	&dev_attr_lpfc_fcp_cpu_map,
-	&dev_attr_lpfc_fcp_wq_count,
-	&dev_attr_lpfc_fcp_eq_count,
 	&dev_attr_lpfc_fcp_io_channel,
 	&dev_attr_lpfc_enable_bg,
 	&dev_attr_lpfc_soft_wwnn,
@@ -4352,6 +4341,7 @@
 	&dev_attr_lpfc_restrict_login,
 	&dev_attr_lpfc_fcp_class,
 	&dev_attr_lpfc_use_adisc,
+	&dev_attr_lpfc_first_burst_size,
 	&dev_attr_lpfc_fdmi_on,
 	&dev_attr_lpfc_max_luns,
 	&dev_attr_nport_evt_cnt,
@@ -5290,8 +5280,6 @@
 	lpfc_use_msi_init(phba, lpfc_use_msi);
 	lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
 	lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
-	lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count);
-	lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count);
 	lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
 	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
 	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
@@ -5331,6 +5319,7 @@
 	lpfc_restrict_login_init(vport, lpfc_restrict_login);
 	lpfc_fcp_class_init(vport, lpfc_fcp_class);
 	lpfc_use_adisc_init(vport, lpfc_use_adisc);
+	lpfc_first_burst_size_init(vport, lpfc_first_burst_size);
 	lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
 	lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
 	lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 6630520..bc27063 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -2498,7 +2498,7 @@
 	struct lpfc_sli_ct_request *ctreq = NULL;
 	int ret_val = 0;
 	int time_left;
-	int iocb_stat = 0;
+	int iocb_stat = IOCB_SUCCESS;
 	unsigned long flags;
 
 	*txxri = 0;
@@ -2574,6 +2574,7 @@
 
 	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
 	cmdiocbq->vport = phba->pport;
+	cmdiocbq->iocb_cmpl = NULL;
 
 	iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
 				rspiocbq,
@@ -2963,7 +2964,7 @@
 	uint8_t *ptr = NULL, *rx_databuf = NULL;
 	int rc = 0;
 	int time_left;
-	int iocb_stat;
+	int iocb_stat = IOCB_SUCCESS;
 	unsigned long flags;
 	void *dataout = NULL;
 	uint32_t total_mem;
@@ -3149,6 +3150,7 @@
 	}
 	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
 	cmdiocbq->vport = phba->pport;
+	cmdiocbq->iocb_cmpl = NULL;
 	iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
 					     rspiocbq, (phba->fc_ratov * 2) +
 					     LPFC_DRVR_TIMEOUT);
@@ -3209,7 +3211,7 @@
 	lpfc_bsg_event_unref(evt); /* delete */
 	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
-	if (cmdiocbq != NULL)
+	if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT))
 		lpfc_sli_release_iocbq(phba, cmdiocbq);
 
 	if (rspiocbq != NULL)
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 6839117..02e8cd9 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -895,7 +895,7 @@
 
 	if (irsp->ulpStatus) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
-				 "0268 NS cmd %x Error (%d %d)\n",
+				 "0268 NS cmd x%x Error (x%x x%x)\n",
 				 cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
 
 		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index af49fb0..e409ba5 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2013 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -154,6 +154,7 @@
 #define NLP_NODEV_REMOVE   0x08000000	/* Defer removal till discovery ends */
 #define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
 #define NLP_SC_REQ         0x20000000	/* Target requires authentication */
+#define NLP_FIRSTBURST     0x40000000	/* Target supports FirstBurst */
 #define NLP_RPI_REGISTERED 0x80000000	/* nlp_rpi is valid */
 
 /* ndlp usage management macros */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 6b8ee74..110445f 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -2122,6 +2122,8 @@
 	}
 	npr->estabImagePair = 1;
 	npr->readXferRdyDis = 1;
+	 if (vport->cfg_first_burst_size)
+		npr->writeXferRdyDis = 1;
 
 	/* For FCP support */
 	npr->prliType = PRLI_FCP_TYPE;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 4ec3d7c..086c3f2 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -234,6 +234,9 @@
 	uint32_t addrHigh;
 };
 
+/* Maximun size of immediate data that can fit into a 128 byte WQE */
+#define LPFC_MAX_BDE_IMM_SIZE	64
+
 struct lpfc_sli4_flags {
 	uint32_t word0;
 #define lpfc_idx_rsrc_rdy_SHIFT		0
@@ -2585,6 +2588,9 @@
 #define cfg_mqv_WORD				word6
 	uint32_t word7;
 	uint32_t word8;
+#define cfg_wqsize_SHIFT			8
+#define cfg_wqsize_MASK				0x0000000f
+#define cfg_wqsize_WORD				word8
 #define cfg_wqv_SHIFT				14
 #define cfg_wqv_MASK				0x00000003
 #define cfg_wqv_WORD				word8
@@ -3622,6 +3628,13 @@
 	struct gen_req64_wqe gen_req;
 };
 
+union lpfc_wqe128 {
+	uint32_t words[32];
+	struct lpfc_wqe_generic generic;
+	struct xmit_seq64_wqe xmit_sequence;
+	struct gen_req64_wqe gen_req;
+};
+
 #define LPFC_GROUP_OJECT_MAGIC_NUM		0xfeaa0001
 #define LPFC_FILE_TYPE_GROUP			0xf7
 #define LPFC_FILE_ID_GROUP			0xa2
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index e0b20fa..501147c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -472,10 +472,22 @@
 	lpfc_sli_read_link_ste(phba);
 
 	/* Reset the DFT_HBA_Q_DEPTH to the max xri  */
-	if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1))
-		phba->cfg_hba_queue_depth =
-			(mb->un.varRdConfig.max_xri + 1) -
-					lpfc_sli4_get_els_iocb_cnt(phba);
+	i = (mb->un.varRdConfig.max_xri + 1);
+	if (phba->cfg_hba_queue_depth > i) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"3359 HBA queue depth changed from %d to %d\n",
+				phba->cfg_hba_queue_depth, i);
+		phba->cfg_hba_queue_depth = i;
+	}
+
+	/* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3)  */
+	i = (mb->un.varRdConfig.max_xri >> 3);
+	if (phba->pport->cfg_lun_queue_depth > i) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"3360 LUN queue depth changed from %d to %d\n",
+				phba->pport->cfg_lun_queue_depth, i);
+		phba->pport->cfg_lun_queue_depth = i;
+	}
 
 	phba->lmt = mb->un.varRdConfig.lmt;
 
@@ -4901,9 +4913,6 @@
 	lpfc_get_cfgparam(phba);
 	phba->max_vpi = LPFC_MAX_VPI;
 
-	/* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */
-	phba->cfg_fcp_io_channel = phba->cfg_fcp_eq_count;
-
 	/* This will be set to correct value after the read_config mbox */
 	phba->max_vports = 0;
 
@@ -6664,12 +6673,14 @@
 		goto read_cfg_out;
 
 	/* Reset the DFT_HBA_Q_DEPTH to the max xri  */
-	if (phba->cfg_hba_queue_depth >
-		(phba->sli4_hba.max_cfg_param.max_xri -
-			lpfc_sli4_get_els_iocb_cnt(phba)))
-		phba->cfg_hba_queue_depth =
-			phba->sli4_hba.max_cfg_param.max_xri -
-				lpfc_sli4_get_els_iocb_cnt(phba);
+	length = phba->sli4_hba.max_cfg_param.max_xri -
+			lpfc_sli4_get_els_iocb_cnt(phba);
+	if (phba->cfg_hba_queue_depth > length) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"3361 HBA queue depth changed from %d to %d\n",
+				phba->cfg_hba_queue_depth, length);
+		phba->cfg_hba_queue_depth = length;
+	}
 
 	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
 	    LPFC_SLI_INTF_IF_TYPE_2)
@@ -6859,11 +6870,7 @@
 		cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq;
 	}
 
-	/* Eventually cfg_fcp_eq_count / cfg_fcp_wq_count will be depricated */
-
 	/* The actual number of FCP event queues adopted */
-	phba->cfg_fcp_eq_count = cfg_fcp_io_channel;
-	phba->cfg_fcp_wq_count = cfg_fcp_io_channel;
 	phba->cfg_fcp_io_channel = cfg_fcp_io_channel;
 
 	/* Get EQ depth from module parameter, fake the default for now */
@@ -9154,6 +9161,7 @@
 	sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);
 	sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters);
 	sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters);
+	sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters);
 	sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt,
 					    mbx_sli4_parameters);
 	sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align,
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index b1c510f..1f292e2 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -178,7 +178,8 @@
 	mb->mbxOwner = OWN_HOST;
 	mb->un.varDmp.cv = 1;
 	mb->un.varDmp.type = DMP_NV_PARAMS;
-	mb->un.varDmp.entry_index = 0;
+	if (phba->sli_rev < LPFC_SLI_REV4)
+		mb->un.varDmp.entry_index = 0;
 	mb->un.varDmp.region_id = WAKE_UP_PARMS_REGION_ID;
 	mb->un.varDmp.word_cnt = WAKE_UP_PARMS_WORD_SIZE;
 	mb->un.varDmp.co = 0;
@@ -361,7 +362,7 @@
 	/* NEW_FEATURE
 	 * SLI-2, Coalescing Response Feature.
 	 */
-	if (phba->cfg_cr_delay) {
+	if (phba->cfg_cr_delay && (phba->sli_rev < LPFC_SLI_REV4)) {
 		mb->un.varCfgLnk.cr = 1;
 		mb->un.varCfgLnk.ci = 1;
 		mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay;
@@ -377,7 +378,7 @@
 	mb->un.varCfgLnk.crtov = phba->fc_crtov;
 	mb->un.varCfgLnk.citov = phba->fc_citov;
 
-	if (phba->cfg_ack0)
+	if (phba->cfg_ack0 && (phba->sli_rev < LPFC_SLI_REV4))
 		mb->un.varCfgLnk.ack0_enable = 1;
 
 	mb->mbxCommand = MBX_CONFIG_LINK;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 6aaf39a..abc3612 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -690,11 +690,15 @@
 
 	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
 	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+	ndlp->nlp_flag &= ~NLP_FIRSTBURST;
 	if (npr->prliType == PRLI_FCP_TYPE) {
 		if (npr->initiatorFunc)
 			ndlp->nlp_type |= NLP_FCP_INITIATOR;
-		if (npr->targetFunc)
+		if (npr->targetFunc) {
 			ndlp->nlp_type |= NLP_FCP_TARGET;
+			if (npr->writeXferRdyDis)
+				ndlp->nlp_flag |= NLP_FIRSTBURST;
+		}
 		if (npr->Retry)
 			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
 	}
@@ -1676,12 +1680,16 @@
 	/* Check out PRLI rsp */
 	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
 	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
+	ndlp->nlp_flag &= ~NLP_FIRSTBURST;
 	if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
 	    (npr->prliType == PRLI_FCP_TYPE)) {
 		if (npr->initiatorFunc)
 			ndlp->nlp_type |= NLP_FCP_INITIATOR;
-		if (npr->targetFunc)
+		if (npr->targetFunc) {
 			ndlp->nlp_type |= NLP_FCP_TARGET;
+			if (npr->writeXferRdyDis)
+				ndlp->nlp_flag |= NLP_FIRSTBURST;
+		}
 		if (npr->Retry)
 			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
 	}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 243de1d..1242b6c 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -4386,11 +4386,11 @@
 	if (scsi_sg_count(scsi_cmnd)) {
 		if (datadir == DMA_TO_DEVICE) {
 			iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
-			if (sli4)
-				iocb_cmd->ulpPU = PARM_READ_CHECK;
-			else {
-				iocb_cmd->un.fcpi.fcpi_parm = 0;
-				iocb_cmd->ulpPU = 0;
+			iocb_cmd->ulpPU = PARM_READ_CHECK;
+			if (vport->cfg_first_burst_size &&
+			    (pnode->nlp_flag & NLP_FIRSTBURST)) {
+				piocbq->iocb.un.fcpi.fcpi_XRdy =
+					vport->cfg_first_burst_size;
 			}
 			fcp_cmnd->fcpCntl3 = WRITE_DATA;
 			phba->fc4OutputRequests++;
@@ -5022,6 +5022,7 @@
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 		return FAILED;
 	}
+	iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
 
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
 			 "0702 Issue %s to TGT %d LUN %d "
@@ -5034,7 +5035,6 @@
 					  iocbq, iocbqrsp, lpfc_cmd->timeout);
 	if (status != IOCB_SUCCESS) {
 		if (status == IOCB_TIMEDOUT) {
-			iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
 			ret = TIMEOUT_ERROR;
 		} else
 			ret = FAILED;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 43440ca..0392e11 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -6163,6 +6163,7 @@
 		kfree(vpd);
 		goto out_free_mbox;
 	}
+
 	mqe = &mboxq->u.mqe;
 	phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev);
 	if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev))
@@ -6249,6 +6250,16 @@
 			phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow,
 			phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow);
 
+	/* Reset the DFT_LUN_Q_DEPTH to (max xri >> 3)  */
+	rc = (phba->sli4_hba.max_cfg_param.max_xri >> 3);
+	if (phba->pport->cfg_lun_queue_depth > rc) {
+		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
+				"3362 LUN queue depth changed from %d to %d\n",
+				phba->pport->cfg_lun_queue_depth, rc);
+		phba->pport->cfg_lun_queue_depth = rc;
+	}
+
+
 	/*
 	 * Discover the port's supported feature set and match it against the
 	 * hosts requests.
@@ -9889,6 +9900,24 @@
 	struct lpfc_scsi_buf *lpfc_cmd;
 
 	spin_lock_irqsave(&phba->hbalock, iflags);
+	if (cmdiocbq->iocb_flag & LPFC_IO_WAKE_TMO) {
+
+		/*
+		 * A time out has occurred for the iocb.  If a time out
+		 * completion handler has been supplied, call it.  Otherwise,
+		 * just free the iocbq.
+		 */
+
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		cmdiocbq->iocb_cmpl = cmdiocbq->wait_iocb_cmpl;
+		cmdiocbq->wait_iocb_cmpl = NULL;
+		if (cmdiocbq->iocb_cmpl)
+			(cmdiocbq->iocb_cmpl)(phba, cmdiocbq, NULL);
+		else
+			lpfc_sli_release_iocbq(phba, cmdiocbq);
+		return;
+	}
+
 	cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
 	if (cmdiocbq->context2 && rspiocbq)
 		memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
@@ -9944,10 +9973,16 @@
  * @timeout: Timeout in number of seconds.
  *
  * This function issues the iocb to firmware and waits for the
- * iocb to complete. If the iocb command is not
- * completed within timeout seconds, it returns IOCB_TIMEDOUT.
- * Caller should not free the iocb resources if this function
- * returns IOCB_TIMEDOUT.
+ * iocb to complete. The iocb_cmpl field of the shall be used
+ * to handle iocbs which time out. If the field is NULL, the
+ * function shall free the iocbq structure.  If more clean up is
+ * needed, the caller is expected to provide a completion function
+ * that will provide the needed clean up.  If the iocb command is
+ * not completed within timeout seconds, the function will either
+ * free the iocbq structure (if iocb_cmpl == NULL) or execute the
+ * completion function set in the iocb_cmpl field and then return
+ * a status of IOCB_TIMEDOUT.  The caller should not free the iocb
+ * resources if this function returns IOCB_TIMEDOUT.
  * The function waits for the iocb completion using an
  * non-interruptible wait.
  * This function will sleep while waiting for iocb completion.
@@ -9980,6 +10015,9 @@
 	int txq_cnt = 0;
 	int txcmplq_cnt = 0;
 	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+	unsigned long iflags;
+	bool iocb_completed = true;
+
 	/*
 	 * If the caller has provided a response iocbq buffer, then context2
 	 * is NULL or its an error.
@@ -9990,9 +10028,10 @@
 		piocb->context2 = prspiocbq;
 	}
 
+	piocb->wait_iocb_cmpl = piocb->iocb_cmpl;
 	piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait;
 	piocb->context_un.wait_queue = &done_q;
-	piocb->iocb_flag &= ~LPFC_IO_WAKE;
+	piocb->iocb_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO);
 
 	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
 		if (lpfc_readl(phba->HCregaddr, &creg_val))
@@ -10009,8 +10048,19 @@
 		timeleft = wait_event_timeout(done_q,
 				lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
 				timeout_req);
+		spin_lock_irqsave(&phba->hbalock, iflags);
+		if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
 
-		if (piocb->iocb_flag & LPFC_IO_WAKE) {
+			/*
+			 * IOCB timed out.  Inform the wake iocb wait
+			 * completion function and set local status
+			 */
+
+			iocb_completed = false;
+			piocb->iocb_flag |= LPFC_IO_WAKE_TMO;
+		}
+		spin_unlock_irqrestore(&phba->hbalock, iflags);
+		if (iocb_completed) {
 			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
 					"0331 IOCB wake signaled\n");
 		} else if (timeleft == 0) {
@@ -10122,7 +10172,6 @@
 		 */
 		if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
 			retval = MBX_SUCCESS;
-			lpfc_sli4_swap_str(phba, pmboxq);
 		} else {
 			retval = MBX_TIMEOUT;
 			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -12820,10 +12869,44 @@
 		    wq->page_count);
 	bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
 		    cq->queue_id);
+
+	/* wqv is the earliest version supported, NOT the latest */
 	bf_set(lpfc_mbox_hdr_version, &shdr->request,
 	       phba->sli4_hba.pc_sli4_params.wqv);
 
-	if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) {
+	switch (phba->sli4_hba.pc_sli4_params.wqv) {
+	case LPFC_Q_CREATE_VERSION_0:
+		switch (wq->entry_size) {
+		default:
+		case 64:
+			/* Nothing to do, version 0 ONLY supports 64 byte */
+			page = wq_create->u.request.page;
+			break;
+		case 128:
+			if (!(phba->sli4_hba.pc_sli4_params.wqsize &
+			    LPFC_WQ_SZ128_SUPPORT)) {
+				status = -ERANGE;
+				goto out;
+			}
+			/* If we get here the HBA MUST also support V1 and
+			 * we MUST use it
+			 */
+			bf_set(lpfc_mbox_hdr_version, &shdr->request,
+			       LPFC_Q_CREATE_VERSION_1);
+
+			bf_set(lpfc_mbx_wq_create_wqe_count,
+			       &wq_create->u.request_1, wq->entry_count);
+			bf_set(lpfc_mbx_wq_create_wqe_size,
+			       &wq_create->u.request_1,
+			       LPFC_WQ_WQE_SIZE_128);
+			bf_set(lpfc_mbx_wq_create_page_size,
+			       &wq_create->u.request_1,
+			       (PAGE_SIZE/SLI4_PAGE_SIZE));
+			page = wq_create->u.request_1.page;
+			break;
+		}
+		break;
+	case LPFC_Q_CREATE_VERSION_1:
 		bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1,
 		       wq->entry_count);
 		switch (wq->entry_size) {
@@ -12834,6 +12917,11 @@
 			       LPFC_WQ_WQE_SIZE_64);
 			break;
 		case 128:
+			if (!(phba->sli4_hba.pc_sli4_params.wqsize &
+				LPFC_WQ_SZ128_SUPPORT)) {
+				status = -ERANGE;
+				goto out;
+			}
 			bf_set(lpfc_mbx_wq_create_wqe_size,
 			       &wq_create->u.request_1,
 			       LPFC_WQ_WQE_SIZE_128);
@@ -12842,9 +12930,12 @@
 		bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1,
 		       (PAGE_SIZE/SLI4_PAGE_SIZE));
 		page = wq_create->u.request_1.page;
-	} else {
-		page = wq_create->u.request.page;
+		break;
+	default:
+		status = -ERANGE;
+		goto out;
 	}
+
 	list_for_each_entry(dmabuf, &wq->page_list, list) {
 		memset(dmabuf->virt, 0, hw_page_size);
 		page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys);
@@ -14665,14 +14756,20 @@
 		first_iocbq->iocb.unsli3.rcvsli3.vpi =
 			vport->phba->vpi_ids[vport->vpi];
 		/* put the first buffer into the first IOCBq */
+		tot_len = bf_get(lpfc_rcqe_length,
+				       &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
 		first_iocbq->context2 = &seq_dmabuf->dbuf;
 		first_iocbq->context3 = NULL;
 		first_iocbq->iocb.ulpBdeCount = 1;
-		first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+		if (tot_len > LPFC_DATA_BUF_SIZE)
+			first_iocbq->iocb.un.cont64[0].tus.f.bdeSize =
 							LPFC_DATA_BUF_SIZE;
+		else
+			first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = tot_len;
+
 		first_iocbq->iocb.un.rcvels.remoteID = sid;
-		tot_len = bf_get(lpfc_rcqe_length,
-				       &seq_dmabuf->cq_event.cqe.rcqe_cmpl);
+
 		first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
 	}
 	iocbq = first_iocbq;
@@ -14688,14 +14785,17 @@
 		if (!iocbq->context3) {
 			iocbq->context3 = d_buf;
 			iocbq->iocb.ulpBdeCount++;
-			pbde = (struct ulp_bde64 *)
-					&iocbq->iocb.unsli3.sli3Words[4];
-			pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
-
 			/* We need to get the size out of the right CQE */
 			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 			len = bf_get(lpfc_rcqe_length,
 				       &hbq_buf->cq_event.cqe.rcqe_cmpl);
+			pbde = (struct ulp_bde64 *)
+					&iocbq->iocb.unsli3.sli3Words[4];
+			if (len > LPFC_DATA_BUF_SIZE)
+				pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE;
+			else
+				pbde->tus.f.bdeSize = len;
+
 			iocbq->iocb.unsli3.rcvsli3.acc_len += len;
 			tot_len += len;
 		} else {
@@ -14710,16 +14810,19 @@
 				lpfc_in_buf_free(vport->phba, d_buf);
 				continue;
 			}
-			iocbq->context2 = d_buf;
-			iocbq->context3 = NULL;
-			iocbq->iocb.ulpBdeCount = 1;
-			iocbq->iocb.un.cont64[0].tus.f.bdeSize =
-							LPFC_DATA_BUF_SIZE;
-
 			/* We need to get the size out of the right CQE */
 			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 			len = bf_get(lpfc_rcqe_length,
 				       &hbq_buf->cq_event.cqe.rcqe_cmpl);
+			iocbq->context2 = d_buf;
+			iocbq->context3 = NULL;
+			iocbq->iocb.ulpBdeCount = 1;
+			if (len > LPFC_DATA_BUF_SIZE)
+				iocbq->iocb.un.cont64[0].tus.f.bdeSize =
+							LPFC_DATA_BUF_SIZE;
+			else
+				iocbq->iocb.un.cont64[0].tus.f.bdeSize = len;
+
 			tot_len += len;
 			iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len;
 
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 9d2e0c6..9761799 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2013 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -60,7 +60,8 @@
 	uint8_t retry;		/* retry counter for IOCB cmd - if needed */
 	uint16_t iocb_flag;
 #define LPFC_IO_LIBDFC		1	/* libdfc iocb */
-#define LPFC_IO_WAKE		2	/* High Priority Queue signal flag */
+#define LPFC_IO_WAKE		2	/* Synchronous I/O completed */
+#define LPFC_IO_WAKE_TMO	LPFC_IO_WAKE /* Synchronous I/O timed out */
 #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
 #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
 #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
@@ -93,6 +94,8 @@
 
 	void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
 			   struct lpfc_iocbq *);
+	void (*wait_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+			   struct lpfc_iocbq *);
 	void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
 			   struct lpfc_iocbq *);
 };
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index d710b87..5bcc382 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -117,6 +117,7 @@
 	struct lpfc_rcqe_complete *rcqe_complete;
 	struct lpfc_mqe *mqe;
 	union  lpfc_wqe *wqe;
+	union  lpfc_wqe128 *wqe128;
 	struct lpfc_rqe *rqe;
 };
 
@@ -325,12 +326,14 @@
 #define LPFC_EQE_SIZE_16B	16
 #define LPFC_CQE_SIZE		16
 #define LPFC_WQE_SIZE		64
+#define LPFC_WQE128_SIZE	128
 #define LPFC_MQE_SIZE		256
 #define LPFC_RQE_SIZE		8
 
 #define LPFC_EQE_DEF_COUNT	1024
 #define LPFC_CQE_DEF_COUNT      1024
 #define LPFC_WQE_DEF_COUNT      256
+#define LPFC_WQE128_DEF_COUNT   128
 #define LPFC_MQE_DEF_COUNT      16
 #define LPFC_RQE_DEF_COUNT	512
 
@@ -416,6 +419,9 @@
 	uint8_t mqv;
 	uint8_t wqv;
 	uint8_t rqv;
+	uint8_t wqsize;
+#define LPFC_WQ_SZ64_SUPPORT	1
+#define LPFC_WQ_SZ128_SUPPORT	2
 };
 
 struct lpfc_iov {
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index c6c32ee..21859d2 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.40"
+#define LPFC_DRIVER_VERSION "8.3.41"
 #define LPFC_DRIVER_NAME		"lpfc"
 
 /* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index e28e431..a87ee33 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2013 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -387,6 +387,9 @@
 	/* Create binary sysfs attribute for vport */
 	lpfc_alloc_sysfs_attr(vport);
 
+	/* Set the DFT_LUN_Q_DEPTH accordingly */
+	vport->cfg_lun_queue_depth  = phba->pport->cfg_lun_queue_depth;
+
 	*(struct lpfc_vport **)fc_vport->dd_data = vport;
 	vport->fc_vport = fc_vport;
 
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 31b5b15..7b14a01 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2.h
@@ -8,7 +8,7 @@
  *                  scatter/gather formats.
  *  Creation Date:  June 21, 2006
  *
- *  mpi2.h Version:  02.00.27
+ *  mpi2.h Version:  02.00.28
  *
  *  Version History
  *  ---------------
@@ -77,6 +77,7 @@
  *                      Added Hard Reset delay timings.
  *  07-10-12  02.00.26  Bumped MPI2_HEADER_VERSION_UNIT.
  *  07-26-12  02.00.27  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  11-27-12  02.00.28  Bumped MPI2_HEADER_VERSION_UNIT.
  *  --------------------------------------------------------------------------
  */
 
@@ -102,7 +103,7 @@
 #define MPI2_VERSION_02_00                  (0x0200)
 
 /* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT            (0x1B)
+#define MPI2_HEADER_VERSION_UNIT            (0x1C)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 737fa8c..88cb7f8 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2011 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_cnfg.h
  *          Title:  MPI Configuration messages and pages
  *  Creation Date:  November 10, 2006
  *
- *    mpi2_cnfg.h Version:  02.00.22
+ *    mpi2_cnfg.h Version:  02.00.23
  *
  *  Version History
  *  ---------------
@@ -149,6 +149,8 @@
  *  11-18-11  02.00.22  Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
  *                      Added UEFIVersion field to BIOS Page 1 and defined new
  *                      BiosOptions bits.
+ *  11-27-12  02.00.23  Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
+ *			 Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
  *  --------------------------------------------------------------------------
  */
 
@@ -698,6 +700,7 @@
 #define MPI2_MANUFACTURING7_PAGEVERSION                 (0x01)
 
 /* defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER       (0x00000002)
 #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO                (0x00000001)
 
 
@@ -1224,6 +1227,9 @@
 #define MPI2_BIOSPAGE1_PAGEVERSION                      (0x05)
 
 /* values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID                  (0x000000F0)
+#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID                   (0x00000000)
+
 #define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION   (0x00000006)
 #define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII              (0x00000000)
 #define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII             (0x00000002)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index 963761f..9d284da 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_init.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index e93f8f5..d159c5f 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_ioc.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
index 255b0ca..0d202a2 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_raid.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
index fdffde1..50b39cc 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2010 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_sas.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 67c387f..11b2ac4 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2012 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_tool.h
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h
index cfde017..0b128b6 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_type.h
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2007 LSI Corporation.
+ *  Copyright (c) 2000-2013 LSI Corporation.
  *
  *
  *           Name:  mpi2_type.h
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index ccd6d5a..3901edc 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -768,10 +768,9 @@
  * @msix_index: MSIX table index supplied by the OS
  * @reply: reply message frame(lower 32bit addr)
  *
- * Return 1 meaning mf should be freed from _base_interrupt
- *        0 means the mf is freed from this function.
+ * Returns void.
  */
-static u8
+static void
 _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
 {
 	Mpi2EventNotificationReply_t *mpi_reply;
@@ -780,9 +779,9 @@
 
 	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
 	if (!mpi_reply)
-		return 1;
+		return;
 	if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
-		return 1;
+		return;
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
 	_base_display_event_data(ioc, mpi_reply);
 #endif
@@ -812,7 +811,7 @@
 	/* ctl callback handler */
 	mpt2sas_ctl_event_callback(ioc, msix_index, reply);
 
-	return 1;
+	return;
 }
 
 /**
@@ -1409,8 +1408,6 @@
 	int i;
 	u8 try_msix = 0;
 
-	INIT_LIST_HEAD(&ioc->reply_queue_list);
-
 	if (msix_disable == -1 || msix_disable == 0)
 		try_msix = 1;
 
@@ -1489,6 +1486,7 @@
 	if (pci_enable_device_mem(pdev)) {
 		printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
 		    "failed\n", ioc->name);
+		ioc->bars = 0;
 		return -ENODEV;
 	}
 
@@ -1497,6 +1495,7 @@
 	    MPT2SAS_DRIVER_NAME)) {
 		printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
 		    "failed\n", ioc->name);
+		ioc->bars = 0;
 		r = -ENODEV;
 		goto out_fail;
 	}
@@ -4229,18 +4228,25 @@
 	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
 
-	_base_mask_interrupts(ioc);
-	ioc->shost_recovery = 1;
-	_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
-	ioc->shost_recovery = 0;
+	if (ioc->chip_phys && ioc->chip) {
+		_base_mask_interrupts(ioc);
+		ioc->shost_recovery = 1;
+		_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+		ioc->shost_recovery = 0;
+	}
+
 	_base_free_irq(ioc);
 	_base_disable_msix(ioc);
-	if (ioc->chip_phys)
+
+	if (ioc->chip_phys && ioc->chip)
 		iounmap(ioc->chip);
 	ioc->chip_phys = 0;
-	pci_release_selected_regions(ioc->pdev, ioc->bars);
-	pci_disable_pcie_error_reporting(pdev);
-	pci_disable_device(pdev);
+
+	if (pci_is_enabled(pdev)) {
+		pci_release_selected_regions(ioc->pdev, ioc->bars);
+		pci_disable_pcie_error_reporting(pdev);
+		pci_disable_device(pdev);
+	}
 	return;
 }
 
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 6fbd084..1f2ac3a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -69,8 +69,8 @@
 #define MPT2SAS_DRIVER_NAME		"mpt2sas"
 #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION		"15.100.00.00"
-#define MPT2SAS_MAJOR_VERSION		15
+#define MPT2SAS_DRIVER_VERSION		"16.100.00.00"
+#define MPT2SAS_MAJOR_VERSION		16
 #define MPT2SAS_MINOR_VERSION		100
 #define MPT2SAS_BUILD_VERSION		00
 #define MPT2SAS_RELEASE_VERSION		00
@@ -1061,7 +1061,7 @@
 int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc);
 
 /* scsih shared API */
-u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
     u32 reply);
 int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
 	uint channel, uint id, uint lun, u8 type, u16 smid_task,
@@ -1144,7 +1144,7 @@
 u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
     u32 reply);
 void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
     u32 reply);
 void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
     Mpi2EventNotificationReply_t *mpi_reply);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index 8637780..0c47425 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -2,7 +2,7 @@
  * This module provides common API for accessing firmware configuration pages
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index eec052c..b7f887c 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -397,18 +397,22 @@
  * This function merely adds a new work task into ioc->firmware_event_thread.
  * The tasks are worked from _firmware_event_work in user context.
  *
- * Return 1 meaning mf should be freed from _base_interrupt
- *        0 means the mf is freed from this function.
+ * Returns void.
  */
-u8
+void
 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
 	u32 reply)
 {
 	Mpi2EventNotificationReply_t *mpi_reply;
 
 	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+	if (unlikely(!mpi_reply)) {
+		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
+		    ioc->name, __FILE__, __LINE__, __func__);
+		return;
+	}
 	mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
-	return 1;
+	return;
 }
 
 /**
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
index b5eb0d1..8b2ac18 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
index 69cc7d0..a9021cbd 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h
@@ -2,7 +2,7 @@
  * Logging Support for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 5100476..7f0af4f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -2,7 +2,7 @@
  * Scsi Host Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -628,11 +628,12 @@
 		 * devices while scanning is turned on due to an oops in
 		 * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
 		 */
-		if (!ioc->is_driver_loading)
+		if (!ioc->is_driver_loading) {
 			mpt2sas_transport_port_remove(ioc,
 			sas_device->sas_address,
 			sas_device->sas_address_parent);
-		_scsih_sas_device_remove(ioc, sas_device);
+			_scsih_sas_device_remove(ioc, sas_device);
+		}
 	}
 }
 
@@ -1402,6 +1403,7 @@
 	struct MPT2SAS_DEVICE *sas_device_priv_data;
 	struct scsi_target *starget;
 	struct _raid_device *raid_device;
+	struct _sas_device *sas_device;
 	unsigned long flags;
 
 	sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
@@ -1430,6 +1432,19 @@
 		spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 	}
 
+	if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
+		spin_lock_irqsave(&ioc->sas_device_lock, flags);
+		sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+				sas_target_priv_data->sas_address);
+		if (sas_device && (sas_device->starget == NULL)) {
+			sdev_printk(KERN_INFO, sdev,
+			     "%s : sas_device->starget set to starget @ %d\n",
+			     __func__, __LINE__);
+			sas_device->starget = starget;
+		}
+		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+	}
+
 	return 0;
 }
 
@@ -6753,7 +6768,7 @@
 	    handle))) {
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
 			break;
 		handle = le16_to_cpu(sas_device_pg0.DevHandle);
 		device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
@@ -6862,7 +6877,7 @@
 	    &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
 			break;
 		handle = le16_to_cpu(volume_pg1.DevHandle);
 
@@ -6887,7 +6902,7 @@
 		    phys_disk_num))) {
 			ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 			    MPI2_IOCSTATUS_MASK;
-			if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+			if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
 				break;
 			phys_disk_num = pd_pg0.PhysDiskNum;
 			handle = le16_to_cpu(pd_pg0.DevHandle);
@@ -6967,7 +6982,7 @@
 
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+		if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
 			break;
 
 		handle = le16_to_cpu(expander_pg0.DevHandle);
@@ -7109,8 +7124,6 @@
 	    MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-			break;
 		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 			printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: "
 				"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7153,8 +7166,6 @@
 	    phys_disk_num))) {
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-			break;
 		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 			printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:"
 				"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7219,8 +7230,6 @@
 	    &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-			break;
 		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 			printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
 				"ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7278,8 +7287,6 @@
 	    handle))) {
 		ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 		    MPI2_IOCSTATUS_MASK;
-		if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
-			break;
 		if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 			printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:"
 				" ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -7471,10 +7478,9 @@
  * This function merely adds a new work task into ioc->firmware_event_thread.
  * The tasks are worked from _firmware_event_work in user context.
  *
- * Return 1 meaning mf should be freed from _base_interrupt
- *        0 means the mf is freed from this function.
+ * Returns void.
  */
-u8
+void
 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
 	u32 reply)
 {
@@ -7485,14 +7491,14 @@
 
 	/* events turned off due to host reset or driver unloading */
 	if (ioc->remove_host || ioc->pci_error_recovery)
-		return 1;
+		return;
 
 	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
 
 	if (unlikely(!mpi_reply)) {
 		printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
-		return 1;
+		return;
 	}
 
 	event = le16_to_cpu(mpi_reply->Event);
@@ -7507,11 +7513,11 @@
 
 		if (baen_data->Primitive !=
 		    MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
-			return 1;
+			return;
 
 		if (ioc->broadcast_aen_busy) {
 			ioc->broadcast_aen_pending++;
-			return 1;
+			return;
 		} else
 			ioc->broadcast_aen_busy = 1;
 		break;
@@ -7587,14 +7593,14 @@
 		break;
 
 	default: /* ignore the rest */
-		return 1;
+		return;
 	}
 
 	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
 	if (!fw_event) {
 		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
-		return 1;
+		return;
 	}
 	sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
 	fw_event->event_data = kzalloc(sz, GFP_ATOMIC);
@@ -7602,7 +7608,7 @@
 		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 		    ioc->name, __FILE__, __LINE__, __func__);
 		kfree(fw_event);
-		return 1;
+		return;
 	}
 
 	memcpy(fw_event->event_data, mpi_reply->EventData,
@@ -7612,7 +7618,7 @@
 	fw_event->VP_ID = mpi_reply->VP_ID;
 	fw_event->event = event;
 	_scsih_fw_event_add(ioc, fw_event);
-	return 1;
+	return;
 }
 
 /* shost template */
@@ -7711,10 +7717,6 @@
 	if (!ioc->ir_firmware)
 		return;
 
-	/* are there any volumes ? */
-	if (list_empty(&ioc->raid_device_list))
-		return;
-
 	mutex_lock(&ioc->scsih_cmds.mutex);
 
 	if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
@@ -7929,10 +7931,12 @@
 		    sas_device->sas_address_parent)) {
 			_scsih_sas_device_remove(ioc, sas_device);
 		} else if (!sas_device->starget) {
-			if (!ioc->is_driver_loading)
-				mpt2sas_transport_port_remove(ioc, sas_address,
+			if (!ioc->is_driver_loading) {
+				mpt2sas_transport_port_remove(ioc,
+					sas_address,
 					sas_address_parent);
-			_scsih_sas_device_remove(ioc, sas_device);
+				_scsih_sas_device_remove(ioc, sas_device);
+			}
 		}
 	}
 }
@@ -7985,14 +7989,14 @@
 			kfree(sas_device);
 			continue;
 		} else if (!sas_device->starget) {
-			if (!ioc->is_driver_loading)
+			if (!ioc->is_driver_loading) {
 				mpt2sas_transport_port_remove(ioc,
 					sas_device->sas_address,
 					sas_device->sas_address_parent);
-			list_del(&sas_device->list);
-			kfree(sas_device);
-			continue;
-
+				list_del(&sas_device->list);
+				kfree(sas_device);
+				continue;
+			}
 		}
 		spin_lock_irqsave(&ioc->sas_device_lock, flags);
 		list_move_tail(&sas_device->list, &ioc->sas_device_list);
@@ -8175,6 +8179,7 @@
 	INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
+	INIT_LIST_HEAD(&ioc->reply_queue_list);
 
 	/* init shost parameters */
 	shost->max_cmd_len = 32;
@@ -8280,6 +8285,7 @@
 
 	mpt2sas_base_stop_watchdog(ioc);
 	scsi_block_requests(shost);
+	_scsih_ir_shutdown(ioc);
 	device_state = pci_choose_state(pdev, state);
 	printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
 	    "operating state [D%d]\n", ioc->name, pdev,
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 193e7ae..9d26637 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -2,7 +2,7 @@
  * SAS Transport Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2012  LSI Corporation
+ * Copyright (C) 2007-2013  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -1006,9 +1006,12 @@
 		    &mpt2sas_phy->remote_identify);
 		_transport_add_phy_to_an_existing_port(ioc, sas_node,
 		    mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
-	} else
+	} else {
 		memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
 		    sas_identify));
+		_transport_del_phy_from_an_existing_port(ioc, sas_node,
+		    mpt2sas_phy);
+	}
 
 	if (mpt2sas_phy->phy)
 		mpt2sas_phy->phy->negotiated_linkrate =
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 5dc280c..fa78506 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -82,6 +82,10 @@
 module_param(msix_disable, int, 0);
 MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
 
+static int max_msix_vectors = 8;
+module_param(max_msix_vectors, int, 0);
+MODULE_PARM_DESC(max_msix_vectors,
+	" max msix vectors - (default=8)");
 
 static int mpt3sas_fwfault_debug;
 MODULE_PARM_DESC(mpt3sas_fwfault_debug,
@@ -1709,8 +1713,6 @@
 	int i;
 	u8 try_msix = 0;
 
-	INIT_LIST_HEAD(&ioc->reply_queue_list);
-
 	if (msix_disable == -1 || msix_disable == 0)
 		try_msix = 1;
 
@@ -1723,6 +1725,16 @@
 	ioc->reply_queue_count = min_t(int, ioc->cpu_count,
 	    ioc->msix_vector_count);
 
+	printk(MPT3SAS_FMT "MSI-X vectors supported: %d, no of cores"
+	  ": %d, max_msix_vectors: %d\n", ioc->name, ioc->msix_vector_count,
+	  ioc->cpu_count, max_msix_vectors);
+
+	if (max_msix_vectors > 0) {
+		ioc->reply_queue_count = min_t(int, max_msix_vectors,
+			ioc->reply_queue_count);
+		ioc->msix_vector_count = ioc->reply_queue_count;
+	}
+
 	entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
 	    GFP_KERNEL);
 	if (!entries) {
@@ -1790,6 +1802,7 @@
 	if (pci_enable_device_mem(pdev)) {
 		pr_warn(MPT3SAS_FMT "pci_enable_device_mem: failed\n",
 			ioc->name);
+		ioc->bars = 0;
 		return -ENODEV;
 	}
 
@@ -1798,6 +1811,7 @@
 	    MPT3SAS_DRIVER_NAME)) {
 		pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
 			ioc->name);
+		ioc->bars = 0;
 		r = -ENODEV;
 		goto out_fail;
 	}
@@ -4393,18 +4407,25 @@
 	dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
 	    __func__));
 
-	_base_mask_interrupts(ioc);
-	ioc->shost_recovery = 1;
-	_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
-	ioc->shost_recovery = 0;
+	if (ioc->chip_phys && ioc->chip) {
+		_base_mask_interrupts(ioc);
+		ioc->shost_recovery = 1;
+		_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+		ioc->shost_recovery = 0;
+	}
+
 	_base_free_irq(ioc);
 	_base_disable_msix(ioc);
-	if (ioc->chip_phys)
+
+	if (ioc->chip_phys && ioc->chip)
 		iounmap(ioc->chip);
 	ioc->chip_phys = 0;
-	pci_release_selected_regions(ioc->pdev, ioc->bars);
-	pci_disable_pcie_error_reporting(pdev);
-	pci_disable_device(pdev);
+
+	if (pci_is_enabled(pdev)) {
+		pci_release_selected_regions(ioc->pdev, ioc->bars);
+		pci_disable_pcie_error_reporting(pdev);
+		pci_disable_device(pdev);
+	}
 	return;
 }
 
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 8cbe8fd..a961fe1 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -7779,6 +7779,7 @@
 	INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_list);
 	INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
+	INIT_LIST_HEAD(&ioc->reply_queue_list);
 
 	/* init shost parameters */
 	shost->max_cmd_len = 32;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index dcadd56..e771a88 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -1003,9 +1003,12 @@
 		    &mpt3sas_phy->remote_identify);
 		_transport_add_phy_to_an_existing_port(ioc, sas_node,
 		    mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address);
-	} else
+	} else {
 		memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct
 		    sas_identify));
+		_transport_del_phy_from_an_existing_port(ioc, sas_node,
+		    mpt3sas_phy);
+	}
 
 	if (mpt3sas_phy->phy)
 		mpt3sas_phy->phy->negotiated_linkrate =
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 9d86947..e1d9a4c 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -107,6 +107,7 @@
 						   class_dev);
 	return sprintf(buf, "%s\n", ould->odi.osdname);
 }
+static DEVICE_ATTR_RO(osdname);
 
 static ssize_t systemid_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
@@ -117,17 +118,19 @@
 	memcpy(buf, ould->odi.systemid, ould->odi.systemid_len);
 	return ould->odi.systemid_len;
 }
+static DEVICE_ATTR_RO(systemid);
 
-static struct device_attribute osd_uld_attrs[] = {
-	__ATTR(osdname, S_IRUGO, osdname_show, NULL),
-	__ATTR(systemid, S_IRUGO, systemid_show, NULL),
-	__ATTR_NULL,
+static struct attribute *osd_uld_attrs[] = {
+	&dev_attr_osdname.attr,
+	&dev_attr_systemid.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(osd_uld);
 
 static struct class osd_uld_class = {
 	.owner		= THIS_MODULE,
 	.name		= "scsi_osd",
-	.dev_attrs	= osd_uld_attrs,
+	.dev_groups	= osd_uld_groups,
 };
 
 /*
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 5456f5c..4a21957 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -221,7 +221,7 @@
 	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_interrupt		= 0x01;
 	for (i = 0; i < PM8001_MAX_INB_NUM; i++) {
 		pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt	=
-			PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30);
+			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
 		pm8001_ha->inbnd_q_tbl[i].upper_base_addr	=
 			pm8001_ha->memoryMap.region[IB + i].phys_addr_hi;
 		pm8001_ha->inbnd_q_tbl[i].lower_base_addr	=
@@ -247,7 +247,7 @@
 	}
 	for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) {
 		pm8001_ha->outbnd_q_tbl[i].element_size_cnt	=
-			PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30);
+			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
 		pm8001_ha->outbnd_q_tbl[i].upper_base_addr	=
 			pm8001_ha->memoryMap.region[OB + i].phys_addr_hi;
 		pm8001_ha->outbnd_q_tbl[i].lower_base_addr	=
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 3861aa1f..f7c1896 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -424,7 +424,8 @@
 			PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
 				"base addr %llx virt_addr=%llx len=%d\n",
 				(u64)pm8001_ha->io_mem[logicalBar].membase,
-				(u64)pm8001_ha->io_mem[logicalBar].memvirtaddr,
+				(u64)(unsigned long)
+				pm8001_ha->io_mem[logicalBar].memvirtaddr,
 				pm8001_ha->io_mem[logicalBar].memsize));
 		} else {
 			pm8001_ha->io_mem[logicalBar].membase	= 0;
@@ -734,7 +735,7 @@
 	pdev = pm8001_ha->pdev;
 
 #ifdef PM8001_USE_MSIX
-	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
+	if (pdev->msix_cap)
 		return pm8001_setup_msix(pm8001_ha);
 	else {
 		PM8001_INIT_DBG(pm8001_ha,
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 7f77210..9f91030 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -275,7 +275,7 @@
 
 	for (i = 0; i < PM8001_MAX_SPCV_INB_NUM; i++) {
 		pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt	=
-			PM8001_MPI_QUEUE | (64 << 16) | (0x00<<30);
+			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
 		pm8001_ha->inbnd_q_tbl[i].upper_base_addr	=
 			pm8001_ha->memoryMap.region[IB + i].phys_addr_hi;
 		pm8001_ha->inbnd_q_tbl[i].lower_base_addr	=
@@ -301,7 +301,7 @@
 	}
 	for (i = 0; i < PM8001_MAX_SPCV_OUTB_NUM; i++) {
 		pm8001_ha->outbnd_q_tbl[i].element_size_cnt	=
-			PM8001_MPI_QUEUE | (64 << 16) | (0x01<<30);
+			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
 		pm8001_ha->outbnd_q_tbl[i].upper_base_addr	=
 			pm8001_ha->memoryMap.region[OB + i].phys_addr_hi;
 		pm8001_ha->outbnd_q_tbl[i].lower_base_addr	=
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index c37b244..ff0fc7c 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,6 +1,6 @@
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
 		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
-        qla_nx.o qla_mr.o qla_target.o
+        qla_nx.o qla_mr.o qla_nx2.o qla_target.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
 obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index d7a99ae..5f174b8 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -29,7 +29,7 @@
 	if (!(ha->fw_dump_reading || ha->mctp_dump_reading))
 		return 0;
 
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		if (off < ha->md_template_size) {
 			rval = memory_read_from_buffer(buf, count,
 			    &off, ha->md_tmplt_hdr, ha->md_template_size);
@@ -71,7 +71,7 @@
 		ql_log(ql_log_info, vha, 0x705d,
 		    "Firmware dump cleared on (%ld).\n", vha->host_no);
 
-		if (IS_QLA82XX(vha->hw)) {
+		if (IS_P3P_TYPE(ha)) {
 			qla82xx_md_free(vha);
 			qla82xx_md_prep(vha);
 		}
@@ -95,11 +95,15 @@
 			qla82xx_idc_lock(ha);
 			qla82xx_set_reset_owner(vha);
 			qla82xx_idc_unlock(ha);
+		} else if (IS_QLA8044(ha)) {
+			qla8044_idc_lock(ha);
+			qla82xx_set_reset_owner(vha);
+			qla8044_idc_unlock(ha);
 		} else
 			qla2x00_system_error(vha);
 		break;
 	case 4:
-		if (IS_QLA82XX(ha)) {
+		if (IS_P3P_TYPE(ha)) {
 			if (ha->md_tmplt_hdr)
 				ql_dbg(ql_dbg_user, vha, 0x705b,
 				    "MiniDump supported with this firmware.\n");
@@ -109,7 +113,7 @@
 		}
 		break;
 	case 5:
-		if (IS_QLA82XX(ha))
+		if (IS_P3P_TYPE(ha))
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 		break;
 	case 6:
@@ -586,7 +590,7 @@
 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
 	int type;
 	uint32_t idc_control;
-
+	uint8_t *tmp_data = NULL;
 	if (off != 0)
 		return -EINVAL;
 
@@ -597,14 +601,23 @@
 		    "Issuing ISP reset.\n");
 
 		scsi_block_requests(vha->host);
-		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
 		if (IS_QLA82XX(ha)) {
 			ha->flags.isp82xx_no_md_cap = 1;
 			qla82xx_idc_lock(ha);
 			qla82xx_set_reset_owner(vha);
 			qla82xx_idc_unlock(ha);
+		} else if (IS_QLA8044(ha)) {
+			qla8044_idc_lock(ha);
+			idc_control = qla8044_rd_reg(ha,
+			    QLA8044_IDC_DRV_CTRL);
+			qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
+			    (idc_control | GRACEFUL_RESET_BIT1));
+			qla82xx_set_reset_owner(vha);
+			qla8044_idc_unlock(ha);
+		} else {
+			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+			qla2xxx_wake_dpc(vha);
 		}
-		qla2xxx_wake_dpc(vha);
 		qla2x00_wait_for_chip_reset(vha);
 		scsi_unblock_requests(vha->host);
 		break;
@@ -640,7 +653,7 @@
 			break;
 		}
 	case 0x2025e:
-		if (!IS_QLA82XX(ha) || vha != base_vha) {
+		if (!IS_P3P_TYPE(ha) || vha != base_vha) {
 			ql_log(ql_log_info, vha, 0x7071,
 			    "FCoE ctx reset no supported.\n");
 			return -EPERM;
@@ -674,7 +687,19 @@
 		__qla83xx_set_idc_control(vha, idc_control);
 		qla83xx_idc_unlock(vha, 0);
 		break;
+	case 0x20261:
+		ql_dbg(ql_dbg_user, vha, 0x70e0,
+		    "Updating cache versions without reset ");
 
+		tmp_data = vmalloc(256);
+		if (!tmp_data) {
+			ql_log(ql_log_warn, vha, 0x70e1,
+			    "Unable to allocate memory for VPD information update.\n");
+			return -ENOMEM;
+		}
+		ha->isp_ops->get_flash_version(vha, tmp_data);
+		vfree(tmp_data);
+		break;
 	}
 	return count;
 }
@@ -1212,7 +1237,7 @@
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
 	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
@@ -1265,10 +1290,7 @@
 	if (!IS_CNA_CAPABLE(vha->hw))
 		return snprintf(buf, PAGE_SIZE, "\n");
 
-	return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
-	    vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4],
-	    vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2],
-	    vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]);
+	return snprintf(buf, PAGE_SIZE, "%pMR\n", vha->fcoe_vn_port_mac);
 }
 
 static ssize_t
@@ -1287,12 +1309,6 @@
 	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
 	uint16_t temp = 0;
 
-	if (!vha->hw->thermal_support) {
-		ql_log(ql_log_warn, vha, 0x70db,
-		    "Thermal not supported by this card.\n");
-		goto done;
-	}
-
 	if (qla2x00_reset_active(vha)) {
 		ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n");
 		goto done;
@@ -1725,11 +1741,21 @@
 		pfc_host_stat->lip_count = stats->lip_cnt;
 		pfc_host_stat->tx_frames = stats->tx_frames;
 		pfc_host_stat->rx_frames = stats->rx_frames;
-		pfc_host_stat->dumped_frames = stats->dumped_frames;
+		pfc_host_stat->dumped_frames = stats->discarded_frames;
 		pfc_host_stat->nos_count = stats->nos_rcvd;
+		pfc_host_stat->error_frames =
+			stats->dropped_frames + stats->discarded_frames;
+		pfc_host_stat->rx_words = vha->qla_stats.input_bytes;
+		pfc_host_stat->tx_words = vha->qla_stats.output_bytes;
 	}
+	pfc_host_stat->fcp_control_requests = vha->qla_stats.control_requests;
+	pfc_host_stat->fcp_input_requests = vha->qla_stats.input_requests;
+	pfc_host_stat->fcp_output_requests = vha->qla_stats.output_requests;
 	pfc_host_stat->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20;
 	pfc_host_stat->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20;
+	pfc_host_stat->seconds_since_last_reset =
+		get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset;
+	do_div(pfc_host_stat->seconds_since_last_reset, HZ);
 
 done_free:
         dma_pool_free(ha->s_dma_pool, stats, stats_dma);
@@ -1738,6 +1764,16 @@
 }
 
 static void
+qla2x00_reset_host_stats(struct Scsi_Host *shost)
+{
+	scsi_qla_host_t *vha = shost_priv(shost);
+
+	memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
+
+	vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
+}
+
+static void
 qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
 {
 	scsi_qla_host_t *vha = shost_priv(shost);
@@ -2043,6 +2079,7 @@
 	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
 	.terminate_rport_io = qla2x00_terminate_rport_io,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
+	.reset_fc_host_stats = qla2x00_reset_host_stats,
 
 	.vport_create = qla24xx_vport_create,
 	.vport_disable = qla24xx_vport_disable,
@@ -2089,6 +2126,8 @@
 	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
 	.terminate_rport_io = qla2x00_terminate_rport_io,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
+	.reset_fc_host_stats = qla2x00_reset_host_stats,
+
 	.bsg_request = qla24xx_bsg_request,
 	.bsg_timeout = qla24xx_bsg_timeout,
 };
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 417eaad..b989add 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -125,7 +125,7 @@
 	uint32_t len;
 	uint32_t oper;
 
-	if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) {
+	if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_P3P_TYPE(ha))) {
 		ret = -EINVAL;
 		goto exit_fcp_prio_cfg;
 	}
@@ -559,7 +559,7 @@
 	uint16_t new_config[4];
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
 		goto done_reset_internal;
 
 	memset(new_config, 0 , sizeof(new_config));
@@ -627,9 +627,10 @@
 {
 	int ret = 0;
 	int rval = 0;
+	unsigned long rem_tmo = 0, current_tmo = 0;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha))
 		goto done_set_internal;
 
 	if (mode == INTERNAL_LOOPBACK)
@@ -652,8 +653,19 @@
 	}
 
 	/* Wait for DCBX complete event */
-	if (!wait_for_completion_timeout(&ha->dcbx_comp,
-	    (DCBX_COMP_TIMEOUT * HZ))) {
+	current_tmo = DCBX_COMP_TIMEOUT * HZ;
+	while (1) {
+		rem_tmo = wait_for_completion_timeout(&ha->dcbx_comp,
+		    current_tmo);
+		if (!ha->idc_extend_tmo || rem_tmo) {
+			ha->idc_extend_tmo = 0;
+			break;
+		}
+		current_tmo = ha->idc_extend_tmo * HZ;
+		ha->idc_extend_tmo = 0;
+	}
+
+	if (!rem_tmo) {
 		ql_dbg(ql_dbg_user, vha, 0x7022,
 		    "DCBX completion not received.\n");
 		ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);
@@ -678,6 +690,7 @@
 	}
 
 	ha->notify_dcbx_comp = 0;
+	ha->idc_extend_tmo = 0;
 
 done_set_internal:
 	return rval;
@@ -773,7 +786,7 @@
 
 	if (atomic_read(&vha->loop_state) == LOOP_READY &&
 	    (ha->current_topology == ISP_CFG_F ||
-	    ((IS_QLA81XX(ha) || IS_QLA8031(ha)) &&
+	    ((IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) &&
 	    le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
 	    && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
 		elreq.options == EXTERNAL_LOOPBACK) {
@@ -783,7 +796,7 @@
 		command_sent = INT_DEF_LB_ECHO_CMD;
 		rval = qla2x00_echo_test(vha, &elreq, response);
 	} else {
-		if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
+		if (IS_QLA81XX(ha) || IS_QLA8031(ha) || IS_QLA8044(ha)) {
 			memset(config, 0, sizeof(config));
 			memset(new_config, 0, sizeof(new_config));
 
@@ -806,7 +819,7 @@
 			    "elreq.options=%04x\n", elreq.options);
 
 			if (elreq.options == EXTERNAL_LOOPBACK)
-				if (IS_QLA8031(ha))
+				if (IS_QLA8031(ha) || IS_QLA8044(ha))
 					rval = qla81xx_set_loopback_mode(vha,
 					    config, new_config, elreq.options);
 				else
@@ -1266,6 +1279,7 @@
 	int rval = 0;
 	struct qla_port_param *port_param = NULL;
 	fc_port_t *fcport = NULL;
+	int found = 0;
 	uint16_t mb[MAILBOX_REGISTER_COUNT];
 	uint8_t *rsp_ptr = NULL;
 
@@ -1288,10 +1302,12 @@
 		if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn,
 			fcport->port_name, sizeof(fcport->port_name)))
 			continue;
+
+		found = 1;
 		break;
 	}
 
-	if (!fcport) {
+	if (!found) {
 		ql_log(ql_log_warn, vha, 0x7049,
 		    "Failed to find port.\n");
 		return -EINVAL;
@@ -1318,12 +1334,9 @@
 
 	if (rval) {
 		ql_log(ql_log_warn, vha, 0x704c,
-		    "iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- "
-		    "%04x %x %04x %04x.\n", fcport->port_name[0],
-		    fcport->port_name[1], fcport->port_name[2],
-		    fcport->port_name[3], fcport->port_name[4],
-		    fcport->port_name[5], fcport->port_name[6],
-		    fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]);
+		    "iIDMA cmd failed for %8phN -- "
+		    "%04x %x %04x %04x.\n", fcport->port_name,
+		    rval, fcport->fp_speed, mb[0], mb[1]);
 		rval = (DID_ERROR << 16);
 	} else {
 		if (!port_param->mode) {
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index df132fe..2ef497e 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,9 +11,12 @@
  * ----------------------------------------------------------------------
  * |             Level            |   Last Value Used  |     Holes	|
  * ----------------------------------------------------------------------
- * | Module Init and Probe        |       0x014f       | 0x4b,0xba,0xfa |
- * | Mailbox commands             |       0x117a       | 0x111a-0x111b  |
+ * | Module Init and Probe        |       0x0159       | 0x4b,0xba,0xfa |
+ * | Mailbox commands             |       0x1181       | 0x111a-0x111b  |
  * |                              |                    | 0x1155-0x1158  |
+ * |                              |                    | 0x1018-0x1019  |
+ * |                              |                    | 0x1115-0x1116  |
+ * |                              |                    | 0x10ca		|
  * | Device Discovery             |       0x2095       | 0x2020-0x2022, |
  * |                              |                    | 0x2011-0x2012, |
  * |                              |                    | 0x2016         |
@@ -24,11 +27,12 @@
  * |                              |                    | 0x3036,0x3038  |
  * |                              |                    | 0x303a		|
  * | DPC Thread                   |       0x4022       | 0x4002,0x4013  |
- * | Async Events                 |       0x5081       | 0x502b-0x502f  |
+ * | Async Events                 |       0x5087       | 0x502b-0x502f  |
  * |                              |                    | 0x5047,0x5052  |
- * |                              |                    | 0x5040,0x5075  |
- * | Timer Routines               |       0x6011       |                |
- * | User Space Interactions      |       0x70dd       | 0x7018,0x702e, |
+ * |                              |                    | 0x5084,0x5075	|
+ * |                              |                    | 0x503d,0x5044  |
+ * | Timer Routines               |       0x6012       |                |
+ * | User Space Interactions      |       0x70e1       | 0x7018,0x702e, |
  * |                              |                    | 0x7020,0x7024, |
  * |                              |                    | 0x7039,0x7045, |
  * |                              |                    | 0x7073-0x7075, |
@@ -36,17 +40,28 @@
  * |                              |                    | 0x70a5,0x70a6, |
  * |                              |                    | 0x70a8,0x70ab, |
  * |                              |                    | 0x70ad-0x70ae, |
- * |                              |                    | 0x70d1-0x70da, |
+ * |                              |                    | 0x70d1-0x70db, |
  * |                              |                    | 0x7047,0x703b	|
- * | Task Management              |       0x803c       | 0x8025-0x8026  |
+ * |                              |                    | 0x70de-0x70df, |
+ * | Task Management              |       0x803d       | 0x8025-0x8026  |
  * |                              |                    | 0x800b,0x8039  |
  * | AER/EEH                      |       0x9011       |		|
  * | Virtual Port                 |       0xa007       |		|
- * | ISP82XX Specific             |       0xb086       | 0xb002,0xb024  |
+ * | ISP82XX Specific             |       0xb14c       | 0xb002,0xb024  |
+ * |                              |                    | 0xb09e,0xb0ae  |
+ * |                              |                    | 0xb0e0-0xb0ef  |
+ * |                              |                    | 0xb085,0xb0dc  |
+ * |                              |                    | 0xb107,0xb108  |
+ * |                              |                    | 0xb111,0xb11e  |
+ * |                              |                    | 0xb12c,0xb12d  |
+ * |                              |                    | 0xb13a,0xb142  |
+ * |                              |                    | 0xb13c-0xb140  |
+ * |                              |                    | 0xb149		|
  * | MultiQ                       |       0xc00c       |		|
  * | Misc                         |       0xd010       |		|
- * | Target Mode		  |	  0xe070       |		|
- * | Target Mode Management	  |	  0xf072       |		|
+ * | Target Mode		  |	  0xe070       | 0xe021		|
+ * | Target Mode Management	  |	  0xf072       | 0xf002-0xf003	|
+ * |                              |                    | 0xf046-0xf049  |
  * | Target Mode Task Management  |	  0x1000b      |		|
  * ----------------------------------------------------------------------
  */
@@ -519,7 +534,7 @@
 	uint32_t cnt, que_idx;
 	uint8_t que_cnt;
 	struct qla2xxx_mq_chain *mq = ptr;
-	struct device_reg_25xxmq __iomem *reg;
+	device_reg_t __iomem *reg;
 
 	if (!ha->mqenable || IS_QLA83XX(ha))
 		return ptr;
@@ -533,13 +548,16 @@
 		ha->max_req_queues : ha->max_rsp_queues;
 	mq->count = htonl(que_cnt);
 	for (cnt = 0; cnt < que_cnt; cnt++) {
-		reg = (struct device_reg_25xxmq __iomem *)
-			(ha->mqiobase + cnt * QLA_QUE_PAGE);
+		reg = ISP_QUE_REG(ha, cnt);
 		que_idx = cnt * 4;
-		mq->qregs[que_idx] = htonl(RD_REG_DWORD(&reg->req_q_in));
-		mq->qregs[que_idx+1] = htonl(RD_REG_DWORD(&reg->req_q_out));
-		mq->qregs[que_idx+2] = htonl(RD_REG_DWORD(&reg->rsp_q_in));
-		mq->qregs[que_idx+3] = htonl(RD_REG_DWORD(&reg->rsp_q_out));
+		mq->qregs[que_idx] =
+		    htonl(RD_REG_DWORD(&reg->isp25mq.req_q_in));
+		mq->qregs[que_idx+1] =
+		    htonl(RD_REG_DWORD(&reg->isp25mq.req_q_out));
+		mq->qregs[que_idx+2] =
+		    htonl(RD_REG_DWORD(&reg->isp25mq.rsp_q_in));
+		mq->qregs[que_idx+3] =
+		    htonl(RD_REG_DWORD(&reg->isp25mq.rsp_q_out));
 	}
 
 	return ptr + sizeof(struct qla2xxx_mq_chain);
@@ -941,7 +959,7 @@
 	uint32_t	*last_chain = NULL;
 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return;
 
 	risc_address = ext_mem_cnt = 0;
@@ -2530,7 +2548,7 @@
 	if (!ql_mask_match(level))
 		return;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		mbx_reg = &reg82->mailbox_in[0];
 	else if (IS_FWI2_CAPABLE(ha))
 		mbx_reg = &reg24->mailbox0;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 95ca32a..93db74e 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -35,6 +35,7 @@
 
 #include "qla_bsg.h"
 #include "qla_nx.h"
+#include "qla_nx2.h"
 #define QLA2XXX_DRIVER_NAME	"qla2xxx"
 #define QLA2XXX_APIDEV		"ql2xapidev"
 #define QLA2XXX_MANUFACTURER	"QLogic Corporation"
@@ -642,6 +643,7 @@
 	uint32_t initval6;		/* C8 */
 	uint32_t initval7;		/* CC */
 	uint32_t fwheartbeat;		/* D0 */
+	uint32_t pseudoaen;		/* D4 */
 };
 
 
@@ -805,6 +807,7 @@
 #define MBA_MIRROR_LUN_CHANGE	0x8402	/* Mirror LUN State Change
 					   Notification */
 #define MBA_FW_POLL_STATE	0x8600  /* Firmware in poll diagnostic state */
+#define MBA_FW_RESET_FCT	0x8502	/* Firmware reset factory defaults */
 
 /* 83XX FCoE specific */
 #define MBA_IDC_AEN		0x8200  /* FCoE: NIC Core state change AEN */
@@ -997,6 +1000,7 @@
 #define	MBX_1		BIT_1
 #define	MBX_0		BIT_0
 
+#define RNID_TYPE_SET_VERSION	0x9
 #define RNID_TYPE_ASIC_TEMP	0xC
 
 /*
@@ -1233,8 +1237,9 @@
 	uint32_t unused1[0x1a];
 	uint32_t tx_frames;
 	uint32_t rx_frames;
-	uint32_t dumped_frames;
-	uint32_t unused2[2];
+	uint32_t discarded_frames;
+	uint32_t dropped_frames;
+	uint32_t unused2[1];
 	uint32_t nos_rcvd;
 };
 
@@ -2656,6 +2661,11 @@
 	uint32_t total_isp_aborts;
 	uint64_t input_bytes;
 	uint64_t output_bytes;
+	uint64_t input_requests;
+	uint64_t output_requests;
+	uint32_t control_requests;
+
+	uint64_t jiffies_at_last_reset;
 };
 
 struct bidi_statistics {
@@ -2670,9 +2680,8 @@
 #define QLA_MAX_QUEUES 256
 #define ISP_QUE_REG(ha, id) \
 	((ha->mqenable || IS_QLA83XX(ha)) ? \
-	((device_reg_t __iomem *)(ha->mqiobase) +\
-	(QLA_QUE_PAGE * id)) :\
-	((device_reg_t __iomem *)(ha->iobase)))
+	 ((void __iomem *)ha->mqiobase + (QLA_QUE_PAGE * id)) :\
+	 ((void __iomem *)ha->iobase))
 #define QLA_REQ_QUE_ID(tag) \
 	((tag < QLA_MAX_QUEUES && tag > 0) ? tag : 0)
 #define QLA_DEFAULT_QUE_QOS 5
@@ -2935,7 +2944,8 @@
 #define DT_ISP2031			BIT_15
 #define DT_ISP8031			BIT_16
 #define DT_ISPFX00			BIT_17
-#define DT_ISP_LAST			(DT_ISPFX00 << 1)
+#define DT_ISP8044			BIT_18
+#define DT_ISP_LAST			(DT_ISP8044 << 1)
 
 #define DT_T10_PI                       BIT_25
 #define DT_IIDMA                        BIT_26
@@ -2961,6 +2971,7 @@
 #define IS_QLA8001(ha)	(DT_MASK(ha) & DT_ISP8001)
 #define IS_QLA81XX(ha)	(IS_QLA8001(ha))
 #define IS_QLA82XX(ha)	(DT_MASK(ha) & DT_ISP8021)
+#define IS_QLA8044(ha)  (DT_MASK(ha) & DT_ISP8044)
 #define IS_QLA2031(ha)	(DT_MASK(ha) & DT_ISP2031)
 #define IS_QLA8031(ha)	(DT_MASK(ha) & DT_ISP8031)
 #define IS_QLAFX00(ha)	(DT_MASK(ha) & DT_ISPFX00)
@@ -2975,10 +2986,12 @@
 #define IS_QLA24XX_TYPE(ha)     (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
 				IS_QLA84XX(ha))
 #define IS_CNA_CAPABLE(ha)	(IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
-				IS_QLA8031(ha))
+				IS_QLA8031(ha) || IS_QLA8044(ha))
+#define IS_P3P_TYPE(ha)		(IS_QLA82XX(ha) || IS_QLA8044(ha))
 #define IS_QLA2XXX_MIDTYPE(ha)	(IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
 				IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
-				IS_QLA82XX(ha) || IS_QLA83XX(ha))
+				IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
+				IS_QLA8044(ha))
 #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
 #define IS_NOPOLLING_TYPE(ha)	((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
 			IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
@@ -3187,10 +3200,12 @@
 	uint32_t	nvram_data_off;
 
 	uint32_t	fdt_wrt_disable;
+	uint32_t	fdt_wrt_enable;
 	uint32_t	fdt_erase_cmd;
 	uint32_t	fdt_block_size;
 	uint32_t	fdt_unprotect_sec_cmd;
 	uint32_t	fdt_protect_sec_cmd;
+	uint32_t	fdt_wrt_sts_reg_cmd;
 
 	uint32_t        flt_region_flt;
 	uint32_t        flt_region_fdt;
@@ -3277,6 +3292,7 @@
 
 	/* QLA83XX IDC specific fields */
 	uint32_t	idc_audit_ts;
+	uint32_t	idc_extend_tmo;
 
 	/* DPC low-priority workqueue */
 	struct workqueue_struct *dpc_lp_wq;
@@ -3296,9 +3312,6 @@
 	struct mr_data_fx00 mr;
 
 	struct qlt_hw_data tgt;
-	uint16_t	thermal_support;
-#define THERMAL_SUPPORT_I2C BIT_0
-#define THERMAL_SUPPORT_ISP BIT_1
 };
 
 /*
@@ -3364,6 +3377,7 @@
 #define PORT_UPDATE_NEEDED	24
 #define FX00_RESET_RECOVERY	25
 #define FX00_TARGET_SCAN	26
+#define FX00_CRITEMP_RECOVERY	27
 
 	uint32_t	device_flags;
 #define SWITCH_FOUND		BIT_0
@@ -3402,7 +3416,7 @@
 	uint16_t	fcoe_fcf_idx;
 	uint8_t		fcoe_vn_port_mac[6];
 
-	uint32_t   	vp_abort_cnt;
+	uint32_t	vp_abort_cnt;
 
 	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
 	uint16_t        vp_idx;		/* vport ID */
@@ -3435,6 +3449,7 @@
 	struct bidi_statistics bidi_stats;
 
 	atomic_t	vref_count;
+	struct qla8044_reset_template reset_tmplt;
 } scsi_qla_host_t;
 
 #define SET_VP_IDX	1
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 1ac2b0e..610d3aa9 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1387,6 +1387,8 @@
 #define FLT_REG_GOLD_FW		0x2f
 #define FLT_REG_FCP_PRIO_0	0x87
 #define FLT_REG_FCP_PRIO_1	0x88
+#define FLT_REG_CNA_FW		0x97
+#define FLT_REG_BOOT_CODE_8044	0xA2
 #define FLT_REG_FCOE_FW		0xA4
 #define FLT_REG_FCOE_NVRAM_0	0xAA
 #define FLT_REG_FCOE_NVRAM_1	0xAC
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 2d98232..4446bf5 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -357,6 +357,12 @@
 qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
 
 extern int
+qla82xx_set_driver_version(scsi_qla_host_t *, char *);
+
+extern int
+qla25xx_set_driver_version(scsi_qla_host_t *, char *);
+
+extern int
 qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *,
 	uint16_t, uint16_t, uint16_t, uint16_t);
 
@@ -435,19 +441,19 @@
  */
 extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
 extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
-    uint32_t, uint32_t);
+					 uint32_t, uint32_t);
 extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-    uint32_t);
+					uint32_t);
 extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-    uint32_t);
+					uint32_t);
 extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-    uint32_t);
+				    uint32_t);
 extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-    uint32_t);
+				    uint32_t);
 extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-    uint32_t);
+					uint32_t);
 extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
-    uint32_t);
+				    uint32_t);
 extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t);
 
 extern int qla2x00_beacon_on(struct scsi_qla_host *);
@@ -463,21 +469,25 @@
 extern int qla83xx_rd_reg(scsi_qla_host_t *, uint32_t, uint32_t *);
 extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *);
 extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t,
-    uint32_t, uint16_t *);
+				  uint32_t, uint16_t *);
 
 extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+					 uint32_t, uint32_t);
 extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+				     uint32_t, uint32_t);
 extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+					 uint32_t, uint32_t);
 extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+				     uint32_t, uint32_t);
 extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+					 uint32_t, uint32_t);
+extern uint8_t *qla8044_read_optrom_data(struct scsi_qla_host *,
+					 uint8_t *, uint32_t, uint32_t);
+extern void qla8044_watchdog(struct scsi_qla_host *vha);
 
 extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
 extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
+extern int qla82xx_get_flash_version(scsi_qla_host_t *, void *);
 
 extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
 extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
@@ -498,7 +508,7 @@
 extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t);
 extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t);
 extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t,
-	uint8_t *, uint32_t);
+			   uint8_t *, uint32_t);
 extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int);
 
 /*
@@ -584,6 +594,7 @@
 extern int qlafx00_abort_isp(scsi_qla_host_t *);
 extern int qlafx00_iospace_config(struct qla_hw_data *);
 extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
+extern int qlafx00_driver_shutdown(scsi_qla_host_t *, int);
 extern int qlafx00_fw_ready(scsi_qla_host_t *);
 extern int qlafx00_configure_devices(scsi_qla_host_t *);
 extern int qlafx00_reset_initialize(scsi_qla_host_t *);
@@ -601,6 +612,7 @@
 extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
 extern void qlafx00_timer_routine(scsi_qla_host_t *);
 extern int qlafx00_rescan_isp(scsi_qla_host_t *);
+extern int qlafx00_loop_reset(scsi_qla_host_t *vha);
 
 /* qla82xx related functions */
 
@@ -619,9 +631,9 @@
 /* Firmware and flash related functions */
 extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *);
 extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+					 uint32_t, uint32_t);
 extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
-    uint32_t, uint32_t);
+				     uint32_t, uint32_t);
 
 /* Mailbox related functions */
 extern int qla82xx_abort_isp(scsi_qla_host_t *);
@@ -662,7 +674,7 @@
 extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
 
 extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
-    size_t, char *);
+				   size_t, char *);
 extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *);
 extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *);
 extern void qla82xx_start_iocbs(scsi_qla_host_t *);
@@ -674,6 +686,8 @@
 extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int);
 extern char *qdev_state(uint32_t);
 extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *);
+extern int qla82xx_read_temperature(scsi_qla_host_t *);
+extern int qla8044_read_temperature(scsi_qla_host_t *);
 
 /* BSG related functions */
 extern int qla24xx_bsg_request(struct fc_bsg_job *);
@@ -695,5 +709,31 @@
 extern int qla82xx_md_collect(scsi_qla_host_t *);
 extern void qla82xx_md_prep(scsi_qla_host_t *);
 extern void qla82xx_set_reset_owner(scsi_qla_host_t *);
+extern int qla82xx_validate_template_chksum(scsi_qla_host_t *vha);
+
+/* Function declarations for ISP8044 */
+extern int qla8044_idc_lock(struct qla_hw_data *ha);
+extern void qla8044_idc_unlock(struct qla_hw_data *ha);
+extern uint32_t qla8044_rd_reg(struct qla_hw_data *ha, ulong addr);
+extern void qla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val);
+extern void qla8044_read_reset_template(struct scsi_qla_host *ha);
+extern void qla8044_set_idc_dontreset(struct scsi_qla_host *ha);
+extern int qla8044_rd_direct(struct scsi_qla_host *vha, const uint32_t crb_reg);
+extern void qla8044_wr_direct(struct scsi_qla_host *vha,
+			      const uint32_t crb_reg, const uint32_t value);
+extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha);
+extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha);
+extern int qla8044_device_state_handler(struct scsi_qla_host *vha);
+extern void qla8044_clear_qsnt_ready(struct scsi_qla_host *vha);
+extern void qla8044_clear_drv_active(struct scsi_qla_host *vha);
+void qla8044_get_minidump(struct scsi_qla_host *vha);
+int qla8044_collect_md_data(struct scsi_qla_host *vha);
+extern int qla8044_md_get_template(scsi_qla_host_t *);
+extern int qla8044_write_optrom_data(struct scsi_qla_host *, uint8_t *,
+				     uint32_t, uint32_t);
+extern irqreturn_t qla8044_intr_handler(int, void *);
+extern void qla82xx_mbx_completion(scsi_qla_host_t *, uint16_t);
+extern int qla8044_abort_isp(scsi_qla_host_t *);
+extern int qla8044_check_fw_alive(struct scsi_qla_host *);
 
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 0926451..cd47f1b 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -49,6 +49,8 @@
 	ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
 	ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
 
+	vha->qla_stats.control_requests++;
+
 	return (ms_pkt);
 }
 
@@ -87,6 +89,8 @@
 	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
 	ct_pkt->vp_index = vha->vp_idx;
 
+	vha->qla_stats.control_requests++;
+
 	return (ct_pkt);
 }
 
@@ -226,17 +230,9 @@
 			fcport->d_id.b.domain = 0xf0;
 
 		ql_dbg(ql_dbg_disc, vha, 0x2063,
-		    "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
-		    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+		    "GA_NXT entry - nn %8phN pn %8phN "
 		    "port_id=%02x%02x%02x.\n",
-		    fcport->node_name[0], fcport->node_name[1],
-		    fcport->node_name[2], fcport->node_name[3],
-		    fcport->node_name[4], fcport->node_name[5],
-		    fcport->node_name[6], fcport->node_name[7],
-		    fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7],
+		    fcport->node_name, fcport->port_name,
 		    fcport->d_id.b.domain, fcport->d_id.b.area,
 		    fcport->d_id.b.al_pa);
 	}
@@ -447,17 +443,9 @@
 			    ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
 
 			ql_dbg(ql_dbg_disc, vha, 0x2058,
-			    "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x "
-			    "pn %02x%02x%02x%02x%02x%02x%02X%02x "
+			    "GID_PT entry - nn %8phN pn %8phN "
 			    "portid=%02x%02x%02x.\n",
-			    list[i].node_name[0], list[i].node_name[1],
-			    list[i].node_name[2], list[i].node_name[3],
-			    list[i].node_name[4], list[i].node_name[5],
-			    list[i].node_name[6], list[i].node_name[7],
-			    list[i].port_name[0], list[i].port_name[1],
-			    list[i].port_name[2], list[i].port_name[3],
-			    list[i].port_name[4], list[i].port_name[5],
-			    list[i].port_name[6], list[i].port_name[7],
+			    list[i].node_name, list[i].port_name,
 			    list[i].d_id.b.domain, list[i].d_id.b.area,
 			    list[i].d_id.b.al_pa);
 		}
@@ -739,6 +727,8 @@
 	wc = (data_size - 16) / 4;		/* Size in 32bit words. */
 	sns_cmd->p.cmd.size = cpu_to_le16(wc);
 
+	vha->qla_stats.control_requests++;
+
 	return (sns_cmd);
 }
 
@@ -796,17 +786,9 @@
 			fcport->d_id.b.domain = 0xf0;
 
 		ql_dbg(ql_dbg_disc, vha, 0x2061,
-		    "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
-		    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+		    "GA_NXT entry - nn %8phN pn %8phN "
 		    "port_id=%02x%02x%02x.\n",
-		    fcport->node_name[0], fcport->node_name[1],
-		    fcport->node_name[2], fcport->node_name[3],
-		    fcport->node_name[4], fcport->node_name[5],
-		    fcport->node_name[6], fcport->node_name[7],
-		    fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7],
+		    fcport->node_name, fcport->port_name,
 		    fcport->d_id.b.domain, fcport->d_id.b.area,
 		    fcport->d_id.b.al_pa);
 	}
@@ -991,17 +973,9 @@
 			    WWN_SIZE);
 
 			ql_dbg(ql_dbg_disc, vha, 0x206e,
-			    "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
-			    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+			    "GID_PT entry - nn %8phN pn %8phN "
 			    "port_id=%02x%02x%02x.\n",
-			    list[i].node_name[0], list[i].node_name[1],
-			    list[i].node_name[2], list[i].node_name[3],
-			    list[i].node_name[4], list[i].node_name[5],
-			    list[i].node_name[6], list[i].node_name[7],
-			    list[i].port_name[0], list[i].port_name[1],
-			    list[i].port_name[2], list[i].port_name[3],
-			    list[i].port_name[4], list[i].port_name[5],
-			    list[i].port_name[6], list[i].port_name[7],
+			    list[i].node_name, list[i].port_name,
 			    list[i].d_id.b.domain, list[i].d_id.b.area,
 			    list[i].d_id.b.al_pa);
 		}
@@ -1321,11 +1295,7 @@
 	size += 4 + WWN_SIZE;
 
 	ql_dbg(ql_dbg_disc, vha, 0x2025,
-	    "NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
-	    eiter->a.node_name[0], eiter->a.node_name[1],
-	    eiter->a.node_name[2], eiter->a.node_name[3],
-	    eiter->a.node_name[4], eiter->a.node_name[5],
-	    eiter->a.node_name[6], eiter->a.node_name[7]);
+	    "NodeName = %8phN.\n", eiter->a.node_name);
 
 	/* Manufacturer. */
 	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
@@ -1428,16 +1398,8 @@
 	qla2x00_update_ms_fdmi_iocb(vha, size + 16);
 
 	ql_dbg(ql_dbg_disc, vha, 0x202e,
-	    "RHBA identifier = "
-	    "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n",
-	    ct_req->req.rhba.hba_identifier[0],
-	    ct_req->req.rhba.hba_identifier[1],
-	    ct_req->req.rhba.hba_identifier[2],
-	    ct_req->req.rhba.hba_identifier[3],
-	    ct_req->req.rhba.hba_identifier[4],
-	    ct_req->req.rhba.hba_identifier[5],
-	    ct_req->req.rhba.hba_identifier[6],
-	    ct_req->req.rhba.hba_identifier[7], size);
+	    "RHBA identifier = %8phN size=%d.\n",
+	    ct_req->req.rhba.hba_identifier, size);
 	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076,
 	    entries, size);
 
@@ -1494,11 +1456,7 @@
 	memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE);
 
 	ql_dbg(ql_dbg_disc, vha, 0x2036,
-	    "DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
-	    ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
-	    ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
-	    ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
-	    ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]);
+	    "DHBA portname = %8phN.\n", ct_req->req.dhba.port_name);
 
 	/* Execute MS IOCB */
 	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
@@ -1678,12 +1636,7 @@
 	qla2x00_update_ms_fdmi_iocb(vha, size + 16);
 
 	ql_dbg(ql_dbg_disc, vha, 0x203e,
-	    "RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n",
-	    ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1],
-	    ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3],
-	    ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5],
-	    ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7],
-	    size);
+	    "RPA portname= %8phN size=%d.\n", ct_req->req.rpa.port_name, size);
 	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079,
 	    entries, size);
 
@@ -1940,16 +1893,8 @@
 
 			ql_dbg(ql_dbg_disc, vha, 0x205b,
 			    "GPSC ext entry - fpn "
-			    "%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
-			    "speed=%04x.\n",
-			    list[i].fabric_port_name[0],
-			    list[i].fabric_port_name[1],
-			    list[i].fabric_port_name[2],
-			    list[i].fabric_port_name[3],
-			    list[i].fabric_port_name[4],
-			    list[i].fabric_port_name[5],
-			    list[i].fabric_port_name[6],
-			    list[i].fabric_port_name[7],
+			    "%8phN speeds=%04x speed=%04x.\n",
+			    list[i].fabric_port_name,
 			    be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
 			    be16_to_cpu(ct_rsp->rsp.gpsc.speed));
 		}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index f2216ed..03f715e 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -524,7 +524,7 @@
 	vha->flags.reset_active = 0;
 	ha->flags.pci_channel_io_perm_failure = 0;
 	ha->flags.eeh_busy = 0;
-	ha->thermal_support = THERMAL_SUPPORT_I2C|THERMAL_SUPPORT_ISP;
+	vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
 	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
 	atomic_set(&vha->loop_state, LOOP_DOWN);
 	vha->device_flags = DFLG_NO_CABLE;
@@ -552,7 +552,18 @@
 	if (rval) {
 		ql_log(ql_log_fatal, vha, 0x004f,
 		    "Unable to validate FLASH data.\n");
-		return (rval);
+		return rval;
+	}
+
+	if (IS_QLA8044(ha)) {
+		qla8044_read_reset_template(vha);
+
+		/* NOTE: If ql2xdontresethba==1, set IDC_CTRL DONTRESET_BIT0.
+		 * If DONRESET_BIT0 is set, drivers should not set dev_state
+		 * to NEED_RESET. But if NEED_RESET is set, drivers should
+		 * should honor the reset. */
+		if (ql2xdontresethba == 1)
+			qla8044_set_idc_dontreset(vha);
 	}
 
 	ha->isp_ops->get_flash_version(vha, req->ring);
@@ -564,12 +575,7 @@
 	if (ha->flags.disable_serdes) {
 		/* Mask HBA via NVRAM settings? */
 		ql_log(ql_log_info, vha, 0x0077,
-		    "Masking HBA WWPN "
-		    "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
-		    vha->port_name[0], vha->port_name[1],
-		    vha->port_name[2], vha->port_name[3],
-		    vha->port_name[4], vha->port_name[5],
-		    vha->port_name[6], vha->port_name[7]);
+		    "Masking HBA WWPN %8phN (via NVRAM).\n", vha->port_name);
 		return QLA_FUNCTION_FAILED;
 	}
 
@@ -620,6 +626,11 @@
 	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
 		qla24xx_read_fcp_prio_cfg(vha);
 
+	if (IS_P3P_TYPE(ha))
+		qla82xx_set_driver_version(vha, QLA2XXX_VERSION);
+	else
+		qla25xx_set_driver_version(vha, QLA2XXX_VERSION);
+
 	return (rval);
 }
 
@@ -1332,7 +1343,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return QLA_SUCCESS;
 
 	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
@@ -1615,7 +1626,7 @@
 	unsigned long flags;
 	uint16_t fw_major_version;
 
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		rval = ha->isp_ops->load_risc(vha, &srisc_address);
 		if (rval == QLA_SUCCESS) {
 			qla2x00_stop_firmware(vha);
@@ -1651,7 +1662,7 @@
 			if (rval == QLA_SUCCESS) {
 enable_82xx_npiv:
 				fw_major_version = ha->fw_major_version;
-				if (IS_QLA82XX(ha))
+				if (IS_P3P_TYPE(ha))
 					qla82xx_check_md_needed(vha);
 				else
 					rval = qla2x00_get_fw_version(vha);
@@ -1681,7 +1692,7 @@
 					goto failed;
 
 				if (!fw_major_version && ql2xallocfwdump
-				    && !IS_QLA82XX(ha))
+				    && !(IS_P3P_TYPE(ha)))
 					qla2x00_alloc_fw_dump(vha);
 			}
 		} else {
@@ -1849,7 +1860,7 @@
 	int rval;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return;
 
 	/* Update Serial Link options. */
@@ -3061,22 +3072,13 @@
 	    mb);
 	if (rval != QLA_SUCCESS) {
 		ql_dbg(ql_dbg_disc, vha, 0x2004,
-		    "Unable to adjust iIDMA "
-		    "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x "
-		    "%04x.\n", fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7], rval,
-		    fcport->fp_speed, mb[0], mb[1]);
+		    "Unable to adjust iIDMA %8phN -- %04x %x %04x %04x.\n",
+		    fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]);
 	} else {
 		ql_dbg(ql_dbg_disc, vha, 0x2005,
-		    "iIDMA adjusted to %s GB/s "
-		    "on %02x%02x%02x%02x%02x%02x%02x%02x.\n",
+		    "iIDMA adjusted to %s GB/s on %8phN.\n",
 		    qla2x00_get_link_speed_str(ha, fcport->fp_speed),
-		    fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7]);
+		    fcport->port_name);
 	}
 }
 
@@ -4007,10 +4009,18 @@
 	uint32_t class_type_mask = 0x3;
 	uint16_t fcoe_other_function = 0xffff, i;
 
-	qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
-
-	qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
-	qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
+	if (IS_QLA8044(ha)) {
+		drv_presence = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_ACTIVE_INDEX);
+		dev_part_info1 = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DEV_PART_INFO_INDEX);
+		dev_part_info2 = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DEV_PART_INFO2);
+	} else {
+		qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
+		qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
+		qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
+	}
 	for (i = 0; i < 8; i++) {
 		class_type = ((dev_part_info1 >> (i * 4)) & class_type_mask);
 		if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
@@ -4347,7 +4357,7 @@
 	/* For ISP82XX, driver waits for completion of the commands.
 	 * online flag should be set.
 	 */
-	if (!IS_QLA82XX(ha))
+	if (!(IS_P3P_TYPE(ha)))
 		vha->flags.online = 0;
 	ha->flags.chip_reset_done = 0;
 	clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -4360,7 +4370,7 @@
 	 * Driver waits for the completion of the commands.
 	 * the interrupts need to be enabled.
 	 */
-	if (!IS_QLA82XX(ha))
+	if (!(IS_P3P_TYPE(ha)))
 		ha->isp_ops->reset_chip(vha);
 
 	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -4403,7 +4413,7 @@
 
 	if (!ha->flags.eeh_busy) {
 		/* Make sure for ISP 82XX IO DMA is complete */
-		if (IS_QLA82XX(ha)) {
+		if (IS_P3P_TYPE(ha)) {
 			qla82xx_chip_reset_cleanup(vha);
 			ql_log(ql_log_info, vha, 0x00b4,
 			    "Done chip reset cleanup.\n");
@@ -4723,7 +4733,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return;
 
 	vha->flags.online = 0;
@@ -4789,8 +4799,6 @@
 	}
 	ha->nvram_size = sizeof(struct nvram_24xx);
 	ha->vpd_size = FA_NVRAM_VPD_SIZE;
-	if (IS_QLA82XX(ha))
-		ha->vpd_size = FA_VPD_SIZE_82XX;
 
 	/* Get VPD data into cache */
 	ha->vpd = ha->nvram + VPD_OFFSET;
@@ -5552,6 +5560,8 @@
 	/* Determine NVRAM starting address. */
 	ha->nvram_size = sizeof(struct nvram_81xx);
 	ha->vpd_size = FA_NVRAM_VPD_SIZE;
+	if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
+		ha->vpd_size = FA_VPD_SIZE_82XX;
 
 	/* Get VPD data into cache */
 	ha->vpd = ha->nvram + VPD_OFFSET;
@@ -5734,7 +5744,7 @@
 
 	/* Link Down Timeout = 0:
 	 *
-	 * 	When Port Down timer expires we will start returning
+	 *	When Port Down timer expires we will start returning
 	 *	I/O's to OS with "DID_NO_CONNECT".
 	 *
 	 * Link Down Timeout != 0:
@@ -6061,7 +6071,7 @@
 	if (priority < 0)
 		return QLA_FUNCTION_FAILED;
 
-	if (IS_QLA82XX(vha->hw)) {
+	if (IS_P3P_TYPE(vha->hw)) {
 		fcport->fcp_prio = priority & 0xf;
 		return QLA_SUCCESS;
 	}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 28c38b4..957088b 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -59,7 +59,7 @@
 	unsigned long flags;
 	struct qla_hw_data *ha = rsp->hw;
 	local_irq_save(flags);
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		qla82xx_poll(0, rsp);
 	else
 		ha->isp_ops->intr_handler(0, rsp);
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index ef0a548..46b9307 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -32,9 +32,11 @@
 	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
 		cflags = CF_WRITE;
 		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.output_requests++;
 	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cflags = CF_READ;
 		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.input_requests++;
 	}
 	return (cflags);
 }
@@ -474,7 +476,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
 
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		qla82xx_start_iocbs(vha);
 	} else {
 		/* Adjust ring index. */
@@ -642,10 +644,12 @@
 		cmd_pkt->control_flags =
 		    __constant_cpu_to_le16(CF_WRITE_DATA);
 		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.output_requests++;
 	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cmd_pkt->control_flags =
 		    __constant_cpu_to_le16(CF_READ_DATA);
 		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.input_requests++;
 	}
 
 	cur_seg = scsi_sglist(cmd);
@@ -758,10 +762,12 @@
 		cmd_pkt->task_mgmt_flags =
 		    __constant_cpu_to_le16(TMF_WRITE_DATA);
 		vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.output_requests++;
 	} else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		cmd_pkt->task_mgmt_flags =
 		    __constant_cpu_to_le16(TMF_READ_DATA);
 		vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+		vha->qla_stats.input_requests++;
 	}
 
 	/* One DSD is available in the Command Type 3 IOCB */
@@ -1844,7 +1850,7 @@
 	if (req->cnt < req_cnt) {
 		if (ha->mqenable || IS_QLA83XX(ha))
 			cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
-		else if (IS_QLA82XX(ha))
+		else if (IS_P3P_TYPE(ha))
 			cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
 		else if (IS_FWI2_CAPABLE(ha))
 			cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
@@ -2056,6 +2062,8 @@
             (bsg_job->reply_payload.sg_list)));
         els_iocb->rx_len = cpu_to_le32(sg_dma_len
             (bsg_job->reply_payload.sg_list));
+
+	sp->fcport->vha->qla_stats.control_requests++;
 }
 
 static void
@@ -2133,6 +2141,8 @@
 		avail_dsds--;
 	}
 	ct_iocb->entry_count = entry_count;
+
+	sp->fcport->vha->qla_stats.control_requests++;
 }
 
 static void
@@ -2685,6 +2695,9 @@
 	vha->bidi_stats.transfer_bytes += req_data_len;
 	vha->bidi_stats.io_count++;
 
+	vha->qla_stats.output_bytes += req_data_len;
+	vha->qla_stats.output_requests++;
+
 	/* Only one dsd is available for bidirectional IOCB, remaining dsds
 	 * are bundled in continuation iocb
 	 */
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 2d8e7b8..df1b30b 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -282,25 +282,38 @@
 	    "%04x %04x %04x %04x %04x %04x %04x.\n",
 	    event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
 	    mb[4], mb[5], mb[6]);
-	if ((aen == MBA_IDC_COMPLETE && mb[1] >> 15)) {
-		vha->hw->flags.idc_compl_status = 1;
-		if (vha->hw->notify_dcbx_comp)
-			complete(&vha->hw->dcbx_comp);
+	switch (aen) {
+	/* Handle IDC Error completion case. */
+	case MBA_IDC_COMPLETE:
+		if (mb[1] >> 15) {
+			vha->hw->flags.idc_compl_status = 1;
+			if (vha->hw->notify_dcbx_comp)
+				complete(&vha->hw->dcbx_comp);
+		}
+		break;
+
+	case MBA_IDC_NOTIFY:
+		/* Acknowledgement needed? [Notify && non-zero timeout]. */
+		timeout = (descr >> 8) & 0xf;
+		ql_dbg(ql_dbg_async, vha, 0x5022,
+		    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
+		    vha->host_no, event[aen & 0xff], timeout);
+
+		if (!timeout)
+			return;
+		rval = qla2x00_post_idc_ack_work(vha, mb);
+		if (rval != QLA_SUCCESS)
+			ql_log(ql_log_warn, vha, 0x5023,
+			    "IDC failed to post ACK.\n");
+		break;
+	case MBA_IDC_TIME_EXT:
+		vha->hw->idc_extend_tmo = descr;
+		ql_dbg(ql_dbg_async, vha, 0x5087,
+		    "%lu Inter-Driver Communication %s -- "
+		    "Extend timeout by=%d.\n",
+		    vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
+		break;
 	}
-
-	/* Acknowledgement needed? [Notify && non-zero timeout]. */
-	timeout = (descr >> 8) & 0xf;
-	if (aen != MBA_IDC_NOTIFY || !timeout)
-		return;
-
-	ql_dbg(ql_dbg_async, vha, 0x5022,
-	    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
-	    vha->host_no, event[aen & 0xff], timeout);
-
-	rval = qla2x00_post_idc_ack_work(vha, mb);
-	if (rval != QLA_SUCCESS)
-		ql_log(ql_log_warn, vha, 0x5023,
-		    "IDC failed to post ACK.\n");
 }
 
 #define LS_UNKNOWN	2
@@ -691,7 +704,8 @@
 	case MBA_LOOP_DOWN:		/* Loop Down Event */
 		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
 			? RD_REG_WORD(&reg24->mailbox4) : 0;
-		mbx = IS_QLA82XX(ha) ? RD_REG_WORD(&reg82->mailbox_out[4]) : mbx;
+		mbx = (IS_P3P_TYPE(ha)) ? RD_REG_WORD(&reg82->mailbox_out[4])
+			: mbx;
 		ql_dbg(ql_dbg_async, vha, 0x500b,
 		    "LOOP DOWN detected (%x %x %x %x).\n",
 		    mb[1], mb[2], mb[3], mbx);
@@ -740,7 +754,7 @@
 		if (IS_QLA2100(ha))
 			break;
 
-		if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA8031(ha)) {
+		if (IS_CNA_CAPABLE(ha)) {
 			ql_dbg(ql_dbg_async, vha, 0x500d,
 			    "DCBX Completed -- %04x %04x %04x.\n",
 			    mb[1], mb[2], mb[3]);
@@ -1002,7 +1016,7 @@
 		    mb[1], mb[2], mb[3]);
 		break;
 	case MBA_IDC_NOTIFY:
-		if (IS_QLA8031(vha->hw)) {
+		if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
 			mb[4] = RD_REG_WORD(&reg24->mailbox4);
 			if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
 			    (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
@@ -1022,7 +1036,8 @@
 			complete(&ha->lb_portup_comp);
 		/* Fallthru */
 	case MBA_IDC_TIME_EXT:
-		if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw))
+		if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
+		    IS_QLA8044(ha))
 			qla81xx_idc_event(vha, mb[0], mb[1]);
 		break;
 
@@ -1063,7 +1078,7 @@
 		ql_log(ql_log_warn, vha, 0x3014,
 		    "Invalid SCSI command index (%x).\n", index);
 
-		if (IS_QLA82XX(ha))
+		if (IS_P3P_TYPE(ha))
 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
 		else
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -1080,7 +1095,7 @@
 	} else {
 		ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
 
-		if (IS_QLA82XX(ha))
+		if (IS_P3P_TYPE(ha))
 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
 		else
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -1100,7 +1115,7 @@
 	if (index >= req->num_outstanding_cmds) {
 		ql_log(ql_log_warn, vha, 0x5031,
 		    "Invalid command index (%x).\n", index);
-		if (IS_QLA82XX(ha))
+		if (IS_P3P_TYPE(ha))
 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
 		else
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -1805,6 +1820,9 @@
 		if (scsi_status == 0) {
 			bsg_job->reply->reply_payload_rcv_len =
 					bsg_job->reply_payload.payload_len;
+			vha->qla_stats.input_bytes +=
+				bsg_job->reply->reply_payload_rcv_len;
+			vha->qla_stats.input_requests++;
 			rval = EXT_STATUS_OK;
 		}
 		goto done;
@@ -1949,7 +1967,7 @@
 		ql_dbg(ql_dbg_io, vha, 0x3017,
 		    "Invalid status handle (0x%x).\n", sts->handle);
 
-		if (IS_QLA82XX(ha))
+		if (IS_P3P_TYPE(ha))
 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
 		else
 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -2176,8 +2194,10 @@
 		}
 
 		ql_dbg(ql_dbg_io, fcport->vha, 0x3021,
-		    "Port down status: port-state=0x%x.\n",
-		    atomic_read(&fcport->state));
+		    "Port to be marked lost on fcport=%02x%02x%02x, current "
+		    "port state= %s.\n", fcport->d_id.b.domain,
+		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
+		    port_state_str[atomic_read(&fcport->state)]);
 
 		if (atomic_read(&fcport->state) == FCS_ONLINE)
 			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
@@ -2212,16 +2232,13 @@
 out:
 	if (logit)
 		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
-		    "FCP command status: 0x%x-0x%x (0x%x) "
-		    "nexus=%ld:%d:%d portid=%02x%02x%02x oxid=0x%x "
-		    "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
+		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%d "
+		    "portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
 		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
 		    comp_status, scsi_status, res, vha->host_no,
 		    cp->device->id, cp->device->lun, fcport->d_id.b.domain,
 		    fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
-		    cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
-		    cp->cmnd[4], cp->cmnd[5], cp->cmnd[6], cp->cmnd[7],
-		    cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len,
+		    cp->cmnd, scsi_bufflen(cp), rsp_info_len,
 		    resid_len, fw_resid_len);
 
 	if (!res)
@@ -2324,7 +2341,7 @@
 	ql_log(ql_log_warn, vha, 0x5030,
 	    "Error entry - invalid handle/queue.\n");
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
 	else
 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
@@ -2452,7 +2469,7 @@
 	}
 
 	/* Adjust ring index */
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
 		WRT_REG_DWORD(&reg->rsp_q_out[0], rsp->ring_index);
 	} else
@@ -2865,7 +2882,7 @@
 			ret = request_irq(qentry->vector,
 				qla83xx_msix_entries[i].handler,
 				0, qla83xx_msix_entries[i].name, rsp);
-		} else if (IS_QLA82XX(ha)) {
+		} else if (IS_P3P_TYPE(ha)) {
 			ret = request_irq(qentry->vector,
 				qla82xx_msix_entries[i].handler,
 				0, qla82xx_msix_entries[i].name, rsp);
@@ -2950,7 +2967,7 @@
 skip_msix:
 
 	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
-	    !IS_QLA8001(ha) && !IS_QLA82XX(ha) && !IS_QLAFX00(ha))
+	    !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha))
 		goto skip_msi;
 
 	ret = pci_enable_msi(ha->pdev);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 7257c3c..a9aae50 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -75,7 +75,7 @@
 		return QLA_FUNCTION_TIMEOUT;
 	}
 
-	if (IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung) {
+	if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
 		/* Setting Link-Down error */
 		mcp->mb[0] = MBS_LINK_DOWN_ERROR;
 		ql_log(ql_log_warn, vha, 0x1004,
@@ -106,9 +106,9 @@
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
 	/* Load mailbox registers. */
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		optr = (uint16_t __iomem *)&reg->isp82.mailbox_in[0];
-	else if (IS_FWI2_CAPABLE(ha) && !IS_QLA82XX(ha))
+	else if (IS_FWI2_CAPABLE(ha) && !(IS_P3P_TYPE(ha)))
 		optr = (uint16_t __iomem *)&reg->isp24.mailbox0;
 	else
 		optr = (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 0);
@@ -117,33 +117,25 @@
 	command = mcp->mb[0];
 	mboxes = mcp->out_mb;
 
+	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111,
+	    "Mailbox registers (OUT):\n");
 	for (cnt = 0; cnt < ha->mbx_count; cnt++) {
 		if (IS_QLA2200(ha) && cnt == 8)
 			optr =
 			    (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 8);
-		if (mboxes & BIT_0)
+		if (mboxes & BIT_0) {
+			ql_dbg(ql_dbg_mbx, vha, 0x1112,
+			    "mbox[%d]<-0x%04x\n", cnt, *iptr);
 			WRT_REG_WORD(optr, *iptr);
+		}
 
 		mboxes >>= 1;
 		optr++;
 		iptr++;
 	}
 
-	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111,
-	    "Loaded MBX registers (displayed in bytes) =.\n");
-	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1112,
-	    (uint8_t *)mcp->mb, 16);
-	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1113,
-	    ".\n");
-	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1114,
-	    ((uint8_t *)mcp->mb + 0x10), 16);
-	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1115,
-	    ".\n");
-	ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1116,
-	    ((uint8_t *)mcp->mb + 0x20), 8);
 	ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1117,
 	    "I/O Address = %p.\n", optr);
-	ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x100e);
 
 	/* Issue set host interrupt command to send cmd out. */
 	ha->flags.mbox_int = 0;
@@ -159,7 +151,7 @@
 	if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
 		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
-		if (IS_QLA82XX(ha)) {
+		if (IS_P3P_TYPE(ha)) {
 			if (RD_REG_DWORD(&reg->isp82.hint) &
 				HINT_MBX_INT_PENDING) {
 				spin_unlock_irqrestore(&ha->hardware_lock,
@@ -189,7 +181,7 @@
 		ql_dbg(ql_dbg_mbx, vha, 0x1011,
 		    "Cmd=%x Polling Mode.\n", command);
 
-		if (IS_QLA82XX(ha)) {
+		if (IS_P3P_TYPE(ha)) {
 			if (RD_REG_DWORD(&reg->isp82.hint) &
 				HINT_MBX_INT_PENDING) {
 				spin_unlock_irqrestore(&ha->hardware_lock,
@@ -236,7 +228,7 @@
 		ha->flags.mbox_int = 0;
 		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
 
-		if ((IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung)) {
+		if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) {
 			ha->flags.mbox_busy = 0;
 			/* Setting Link-Down error */
 			mcp->mb[0] = MBS_LINK_DOWN_ERROR;
@@ -254,9 +246,15 @@
 		iptr2 = mcp->mb;
 		iptr = (uint16_t *)&ha->mailbox_out[0];
 		mboxes = mcp->in_mb;
+
+		ql_dbg(ql_dbg_mbx, vha, 0x1113,
+		    "Mailbox registers (IN):\n");
 		for (cnt = 0; cnt < ha->mbx_count; cnt++) {
-			if (mboxes & BIT_0)
+			if (mboxes & BIT_0) {
 				*iptr2 = *iptr;
+				ql_dbg(ql_dbg_mbx, vha, 0x1114,
+				    "mbox[%d]->0x%04x\n", cnt, *iptr2);
+			}
 
 			mboxes >>= 1;
 			iptr2++;
@@ -537,7 +535,7 @@
 	mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
 	mcp->out_mb = MBX_0;
 	mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-	if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha))
+	if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha) || IS_QLA8044(ha))
 		mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
 	if (IS_FWI2_CAPABLE(ha))
 		mcp->in_mb |= MBX_17|MBX_16|MBX_15;
@@ -556,7 +554,7 @@
 		ha->fw_memory_size = 0x1FFFF;		/* Defaults to 128KB. */
 	else
 		ha->fw_memory_size = (mcp->mb[5] << 16) | mcp->mb[4];
-	if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) {
+	if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
 		ha->mpi_version[0] = mcp->mb[10] & 0xff;
 		ha->mpi_version[1] = mcp->mb[11] >> 8;
 		ha->mpi_version[2] = mcp->mb[11] & 0xff;
@@ -1201,7 +1199,7 @@
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104c,
 	    "Entered %s.\n", __func__);
 
-	if (IS_QLA82XX(ha) && ql2xdbwr)
+	if (IS_P3P_TYPE(ha) && ql2xdbwr)
 		qla82xx_wr_32(ha, ha->nxdb_wr_ptr,
 			(0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16)));
 
@@ -1667,7 +1665,11 @@
 		return QLA_FUNCTION_FAILED;
 
 	mcp->mb[0] = MBC_LINK_INITIALIZATION;
-	mcp->mb[1] = BIT_6|BIT_4;
+	mcp->mb[1] = BIT_4;
+	if (vha->hw->operating_mode == LOOP)
+		mcp->mb[1] |= BIT_6;
+	else
+		mcp->mb[1] |= BIT_5;
 	mcp->mb[2] = 0;
 	mcp->mb[3] = 0;
 	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -3574,7 +3576,6 @@
 	unsigned long flags;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
-	struct device_reg_25xxmq __iomem *reg;
 	struct qla_hw_data *ha = vha->hw;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d3,
@@ -3595,9 +3596,6 @@
 	if (IS_QLA83XX(ha))
 		mcp->mb[15] = 0;
 
-	reg = (struct device_reg_25xxmq __iomem *)((ha->mqiobase) +
-		QLA_QUE_PAGE * req->id);
-
 	mcp->mb[4] = req->id;
 	/* que in ptr index */
 	mcp->mb[8] = 0;
@@ -3619,12 +3617,10 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (!(req->options & BIT_0)) {
-		WRT_REG_DWORD(&reg->req_q_in, 0);
+		WRT_REG_DWORD(req->req_q_in, 0);
 		if (!IS_QLA83XX(ha))
-			WRT_REG_DWORD(&reg->req_q_out, 0);
+			WRT_REG_DWORD(req->req_q_out, 0);
 	}
-	req->req_q_in = &reg->req_q_in;
-	req->req_q_out = &reg->req_q_out;
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	rval = qla2x00_mailbox_command(vha, mcp);
@@ -3646,7 +3642,6 @@
 	unsigned long flags;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
-	struct device_reg_25xxmq __iomem *reg;
 	struct qla_hw_data *ha = vha->hw;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d6,
@@ -3664,9 +3659,6 @@
 	if (IS_QLA83XX(ha))
 		mcp->mb[15] = 0;
 
-	reg = (struct device_reg_25xxmq __iomem *)((ha->mqiobase) +
-		QLA_QUE_PAGE * rsp->id);
-
 	mcp->mb[4] = rsp->id;
 	/* que in ptr index */
 	mcp->mb[8] = 0;
@@ -3690,9 +3682,9 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	if (!(rsp->options & BIT_0)) {
-		WRT_REG_DWORD(&reg->rsp_q_out, 0);
+		WRT_REG_DWORD(rsp->rsp_q_out, 0);
 		if (!IS_QLA83XX(ha))
-			WRT_REG_DWORD(&reg->rsp_q_in, 0);
+			WRT_REG_DWORD(rsp->rsp_q_in, 0);
 	}
 
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -3872,6 +3864,112 @@
 	return rval;
 }
 
+int
+qla82xx_set_driver_version(scsi_qla_host_t *vha, char *version)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	int i;
+	int len;
+	uint16_t *str;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!IS_P3P_TYPE(ha))
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117b,
+	    "Entered %s.\n", __func__);
+
+	str = (void *)version;
+	len = strlen(version);
+
+	mcp->mb[0] = MBC_SET_RNID_PARAMS;
+	mcp->mb[1] = RNID_TYPE_SET_VERSION << 8;
+	mcp->out_mb = MBX_1|MBX_0;
+	for (i = 4; i < 16 && len; i++, str++, len -= 2) {
+		mcp->mb[i] = cpu_to_le16p(str);
+		mcp->out_mb |= 1<<i;
+	}
+	for (; i < 16; i++) {
+		mcp->mb[i] = 0;
+		mcp->out_mb |= 1<<i;
+	}
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x117c,
+		    "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
+	} else {
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117d,
+		    "Done %s.\n", __func__);
+	}
+
+	return rval;
+}
+
+int
+qla25xx_set_driver_version(scsi_qla_host_t *vha, char *version)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	int len;
+	uint16_t dwlen;
+	uint8_t *str;
+	dma_addr_t str_dma;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!IS_FWI2_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA81XX(ha) ||
+	    IS_P3P_TYPE(ha))
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x117e,
+	    "Entered %s.\n", __func__);
+
+	str = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &str_dma);
+	if (!str) {
+		ql_log(ql_log_warn, vha, 0x117f,
+		    "Failed to allocate driver version param.\n");
+		return QLA_MEMORY_ALLOC_FAILED;
+	}
+
+	memcpy(str, "\x7\x3\x11\x0", 4);
+	dwlen = str[0];
+	len = dwlen * 4 - 4;
+	memset(str + 4, 0, len);
+	if (len > strlen(version))
+		len = strlen(version);
+	memcpy(str + 4, version, len);
+
+	mcp->mb[0] = MBC_SET_RNID_PARAMS;
+	mcp->mb[1] = RNID_TYPE_SET_VERSION << 8 | dwlen;
+	mcp->mb[2] = MSW(LSD(str_dma));
+	mcp->mb[3] = LSW(LSD(str_dma));
+	mcp->mb[6] = MSW(MSD(str_dma));
+	mcp->mb[7] = LSW(MSD(str_dma));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(vha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1180,
+		    "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
+	} else {
+		ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1181,
+		    "Done %s.\n", __func__);
+	}
+
+	dma_pool_free(ha->s_dma_pool, str, str_dma);
+
+	return rval;
+}
+
 static int
 qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp)
 {
@@ -4407,7 +4505,7 @@
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1109,
 	    "Entered %s.\n", __func__);
 
-	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
+	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) && !IS_QLA8044(ha))
 		return QLA_FUNCTION_FAILED;
 	mcp->mb[0] = MBC_GET_PORT_CONFIG;
 	mcp->out_mb = MBX_0;
@@ -4512,40 +4610,43 @@
 	struct qla_hw_data *ha = vha->hw;
 	uint8_t byte;
 
-	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ca,
-	    "Entered %s.\n", __func__);
-
-	if (ha->thermal_support & THERMAL_SUPPORT_I2C) {
-		rval = qla2x00_read_sfp(vha, 0, &byte,
-		    0x98, 0x1, 1, BIT_13|BIT_12|BIT_0);
-		*temp = byte;
-		if (rval == QLA_SUCCESS)
-			goto done;
-
-		ql_log(ql_log_warn, vha, 0x10c9,
-		    "Thermal not supported through I2C bus, trying alternate "
-		    "method (ISP access).\n");
-		ha->thermal_support &= ~THERMAL_SUPPORT_I2C;
+	if (!IS_FWI2_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA81XX(ha)) {
+		ql_dbg(ql_dbg_mbx, vha, 0x1150,
+		    "Thermal not supported by this card.\n");
+		return rval;
 	}
 
-	if (ha->thermal_support & THERMAL_SUPPORT_ISP) {
-		rval = qla2x00_read_asic_temperature(vha, temp);
-		if (rval == QLA_SUCCESS)
-			goto done;
-
-		ql_log(ql_log_warn, vha, 0x1019,
-		    "Thermal not supported through ISP.\n");
-		ha->thermal_support &= ~THERMAL_SUPPORT_ISP;
+	if (IS_QLA25XX(ha)) {
+		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+		    ha->pdev->subsystem_device == 0x0175) {
+			rval = qla2x00_read_sfp(vha, 0, &byte,
+			    0x98, 0x1, 1, BIT_13|BIT_0);
+			*temp = byte;
+			return rval;
+		}
+		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
+		    ha->pdev->subsystem_device == 0x338e) {
+			rval = qla2x00_read_sfp(vha, 0, &byte,
+			    0x98, 0x1, 1, BIT_15|BIT_14|BIT_0);
+			*temp = byte;
+			return rval;
+		}
+		ql_dbg(ql_dbg_mbx, vha, 0x10c9,
+		    "Thermal not supported by this card.\n");
+		return rval;
 	}
 
-	ql_log(ql_log_warn, vha, 0x1150,
-	    "Thermal not supported by this card "
-	    "(ignoring further requests).\n");
-	return  rval;
+	if (IS_QLA82XX(ha)) {
+		*temp = qla82xx_read_temperature(vha);
+		rval = QLA_SUCCESS;
+		return rval;
+	} else if (IS_QLA8044(ha)) {
+		*temp = qla8044_read_temperature(vha);
+		rval = QLA_SUCCESS;
+		return rval;
+	}
 
-done:
-	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1018,
-	    "Done %s.\n", __func__);
+	rval = qla2x00_read_asic_temperature(vha, temp);
 	return rval;
 }
 
@@ -4595,7 +4696,7 @@
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x100d,
 	    "Entered %s.\n", __func__);
 
-	if (!IS_QLA82XX(ha))
+	if (!IS_P3P_TYPE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	memset(mcp, 0, sizeof(mbx_cmd_t));
@@ -4713,6 +4814,60 @@
 }
 
 int
+qla8044_md_get_template(scsi_qla_host_t *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	int rval = QLA_FUNCTION_FAILED;
+	int offset = 0, size = MINIDUMP_SIZE_36K;
+	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11f,
+	    "Entered %s.\n", __func__);
+
+	ha->md_tmplt_hdr = dma_alloc_coherent(&ha->pdev->dev,
+	   ha->md_template_size, &ha->md_tmplt_hdr_dma, GFP_KERNEL);
+	if (!ha->md_tmplt_hdr) {
+		ql_log(ql_log_warn, vha, 0xb11b,
+		    "Unable to allocate memory for Minidump template.\n");
+		return rval;
+	}
+
+	memset(mcp->mb, 0 , sizeof(mcp->mb));
+	while (offset < ha->md_template_size) {
+		mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE);
+		mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE);
+		mcp->mb[2] = LSW(RQST_TMPLT);
+		mcp->mb[3] = MSW(RQST_TMPLT);
+		mcp->mb[4] = LSW(LSD(ha->md_tmplt_hdr_dma + offset));
+		mcp->mb[5] = MSW(LSD(ha->md_tmplt_hdr_dma + offset));
+		mcp->mb[6] = LSW(MSD(ha->md_tmplt_hdr_dma + offset));
+		mcp->mb[7] = MSW(MSD(ha->md_tmplt_hdr_dma + offset));
+		mcp->mb[8] = LSW(size);
+		mcp->mb[9] = MSW(size);
+		mcp->mb[10] = offset & 0x0000FFFF;
+		mcp->mb[11] = offset & 0xFFFF0000;
+		mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD;
+		mcp->tov = MBX_TOV_SECONDS;
+		mcp->out_mb = MBX_11|MBX_10|MBX_9|MBX_8|
+			MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+		mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+		rval = qla2x00_mailbox_command(vha, mcp);
+
+		if (rval != QLA_SUCCESS) {
+			ql_dbg(ql_dbg_mbx, vha, 0xb11c,
+				"mailbox command FAILED=0x%x, subcode=%x.\n",
+				((mcp->mb[1] << 16) | mcp->mb[0]),
+				((mcp->mb[3] << 16) | mcp->mb[2]));
+			return rval;
+		} else
+			ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xb11d,
+				"Done %s.\n", __func__);
+		offset = offset + size;
+	}
+	return rval;
+}
+
+int
 qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg)
 {
 	int rval;
@@ -4808,7 +4963,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA82XX(ha))
+	if (!IS_P3P_TYPE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1127,
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index f868a9f..a72df70 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -699,6 +699,8 @@
 	req->cnt = req->length;
 	req->id = que_id;
 	reg = ISP_QUE_REG(ha, que_id);
+	req->req_q_in = &reg->isp25mq.req_q_in;
+	req->req_q_out = &reg->isp25mq.req_q_out;
 	req->max_q_depth = ha->req_q_map[0]->max_q_depth;
 	mutex_unlock(&ha->vport_lock);
 	ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index d799379..2482975 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -294,7 +294,7 @@
  * Context:
  *	Kernel context.
  */
-static int
+int
 qlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
 {
 	int rval;
@@ -776,6 +776,29 @@
 }
 
 int
+qlafx00_loop_reset(scsi_qla_host_t *vha)
+{
+	int ret;
+	struct fc_port *fcport;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (ql2xtargetreset) {
+		list_for_each_entry(fcport, &vha->vp_fcports, list) {
+			if (fcport->port_type != FCT_TARGET)
+				continue;
+
+			ret = ha->isp_ops->target_reset(fcport, 0, 0);
+			if (ret != QLA_SUCCESS) {
+				ql_dbg(ql_dbg_taskm, vha, 0x803d,
+				    "Bus Reset failed: Reset=%d "
+				    "d_id=%x.\n", ret, fcport->d_id.b24);
+			}
+		}
+	}
+	return QLA_SUCCESS;
+}
+
+int
 qlafx00_iospace_config(struct qla_hw_data *ha)
 {
 	if (pci_request_selected_regions(ha->pdev, ha->bars,
@@ -918,12 +941,23 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
 	uint32_t aenmbx, aenmbx7 = 0;
+	uint32_t pseudo_aen;
 	uint32_t state[5];
 	bool done = false;
 
 	/* 30 seconds wait - Adjust if required */
 	wait_time = 30;
 
+	pseudo_aen = RD_REG_DWORD(&reg->pseudoaen);
+	if (pseudo_aen == 1) {
+		aenmbx7 = RD_REG_DWORD(&reg->initval7);
+		ha->mbx_intr_code = MSW(aenmbx7);
+		ha->rqstq_intr_code = LSW(aenmbx7);
+		rval = qlafx00_driver_shutdown(vha, 10);
+		if (rval != QLA_SUCCESS)
+			qlafx00_soft_reset(vha);
+	}
+
 	/* wait time before firmware ready */
 	wtime = jiffies + (wait_time * HZ);
 	do {
@@ -1349,21 +1383,22 @@
 }
 
 static void
-qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
+qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha, bool critemp)
 {
 	struct qla_hw_data *ha = vha->hw;
 	fc_port_t *fcport;
 
 	vha->flags.online = 0;
-	ha->flags.chip_reset_done = 0;
 	ha->mr.fw_hbt_en = 0;
-	clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-	vha->qla_stats.total_isp_aborts++;
 
-	ql_log(ql_log_info, vha, 0x013f,
-	    "Performing ISP error recovery - ha = %p.\n", ha);
-
-	ha->isp_ops->reset_chip(vha);
+	if (!critemp) {
+		ha->flags.chip_reset_done = 0;
+		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+		vha->qla_stats.total_isp_aborts++;
+		ql_log(ql_log_info, vha, 0x013f,
+		    "Performing ISP error recovery - ha = %p.\n", ha);
+		ha->isp_ops->reset_chip(vha);
+	}
 
 	if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
 		atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1383,12 +1418,19 @@
 	}
 
 	if (!ha->flags.eeh_busy) {
-		/* Requeue all commands in outstanding command list. */
-		qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+		if (critemp) {
+			qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
+		} else {
+			/* Requeue all commands in outstanding command list. */
+			qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+		}
 	}
 
 	qla2x00_free_irqs(vha);
-	set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+	if (critemp)
+		set_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags);
+	else
+		set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
 
 	/* Clear the Interrupts */
 	QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
@@ -1475,6 +1517,7 @@
 	uint32_t fw_heart_beat;
 	uint32_t aenmbx0;
 	struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+	uint32_t tempc;
 
 	/* Check firmware health */
 	if (ha->mr.fw_hbt_cnt)
@@ -1539,10 +1582,36 @@
 		} else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
 			ha->mr.fw_reset_timer_tick =
 			    QLAFX00_MAX_RESET_INTERVAL;
+		} else if (aenmbx0 == MBA_FW_RESET_FCT) {
+			ha->mr.fw_reset_timer_tick =
+			    QLAFX00_MAX_RESET_INTERVAL;
 		}
 		ha->mr.old_aenmbx0_state = aenmbx0;
 		ha->mr.fw_reset_timer_tick--;
 	}
+	if (test_bit(FX00_CRITEMP_RECOVERY, &vha->dpc_flags)) {
+		/*
+		 * Critical temperature recovery to be
+		 * performed in timer routine
+		 */
+		if (ha->mr.fw_critemp_timer_tick == 0) {
+			tempc = QLAFX00_GET_TEMPERATURE(ha);
+			ql_dbg(ql_dbg_timer, vha, 0x6012,
+			    "ISPFx00(%s): Critical temp timer, "
+			    "current SOC temperature: %d\n",
+			    __func__, tempc);
+			if (tempc < ha->mr.critical_temperature) {
+				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+				clear_bit(FX00_CRITEMP_RECOVERY,
+				    &vha->dpc_flags);
+				qla2xxx_wake_dpc(vha);
+			}
+			ha->mr.fw_critemp_timer_tick =
+			    QLAFX00_CRITEMP_INTERVAL;
+		} else {
+			ha->mr.fw_critemp_timer_tick--;
+		}
+	}
 }
 
 /*
@@ -1570,7 +1639,7 @@
 
 	if (vha->flags.online) {
 		scsi_block_requests(vha->host);
-		qlafx00_abort_isp_cleanup(vha);
+		qlafx00_abort_isp_cleanup(vha, false);
 	}
 
 	ql_log(ql_log_info, vha, 0x0143,
@@ -1602,7 +1671,15 @@
 		}
 
 		scsi_block_requests(vha->host);
-		qlafx00_abort_isp_cleanup(vha);
+		qlafx00_abort_isp_cleanup(vha, false);
+	} else {
+		scsi_block_requests(vha->host);
+		clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+		vha->qla_stats.total_isp_aborts++;
+		ha->isp_ops->reset_chip(vha);
+		set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+		/* Clear the Interrupts */
+		QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
 	}
 
 	ql_log(ql_log_info, vha, 0x0145,
@@ -1688,6 +1765,15 @@
 		aen_code = FCH_EVT_LINKDOWN;
 		aen_data = 0;
 		break;
+	case QLAFX00_MBA_TEMP_CRIT:	/* Critical temperature event */
+		ql_log(ql_log_info, vha, 0x5082,
+		    "Process critical temperature event "
+		    "aenmb[0]: %x\n",
+		    evt->u.aenfx.evtcode);
+		scsi_block_requests(vha->host);
+		qlafx00_abort_isp_cleanup(vha, true);
+		scsi_unblock_requests(vha->host);
+		break;
 	}
 
 	fc_host_post_event(vha->host, fc_get_event_number(),
@@ -1879,6 +1965,11 @@
 		    sizeof(vha->hw->mr.uboot_version));
 		memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
 		    sizeof(vha->hw->mr.fru_serial_num));
+		vha->hw->mr.critical_temperature =
+		    (pinfo->nominal_temp_value) ?
+		    pinfo->nominal_temp_value : QLAFX00_CRITEMP_THRSHLD;
+		ha->mr.extended_io_enabled = (pinfo->enabled_capabilities &
+		    QLAFX00_EXTENDED_IO_EN_MASK) != 0;
 	} else if (fx_type == FXDISC_GET_PORT_INFO) {
 		struct port_info_data *pinfo =
 		    (struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
@@ -2021,6 +2112,7 @@
 {
 	int	rval;
 	struct qla_hw_data *ha = vha->hw;
+	uint32_t tempc;
 
 	/* Clear adapter flags. */
 	vha->flags.online = 0;
@@ -2028,7 +2120,6 @@
 	vha->flags.reset_active = 0;
 	ha->flags.pci_channel_io_perm_failure = 0;
 	ha->flags.eeh_busy = 0;
-	ha->thermal_support = 0;
 	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
 	atomic_set(&vha->loop_state, LOOP_DOWN);
 	vha->device_flags = DFLG_NO_CABLE;
@@ -2072,6 +2163,11 @@
 	rval = qla2x00_init_rings(vha);
 	ha->flags.chip_reset_done = 1;
 
+	tempc = QLAFX00_GET_TEMPERATURE(ha);
+	ql_dbg(ql_dbg_init, vha, 0x0152,
+	    "ISPFx00(%s): Critical temp timer, current SOC temperature: 0x%x\n",
+	    __func__, tempc);
+
 	return rval;
 }
 
@@ -2526,16 +2622,13 @@
 
 	if (logit)
 		ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
-		    "FCP command status: 0x%x-0x%x (0x%x) "
-		    "nexus=%ld:%d:%d tgt_id: 0x%x lscsi_status: 0x%x"
-		    "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
-		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x "
-		    "sense_len=0x%x, par_sense_len=0x%x, rsp_info_len=0x%x\n",
+		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%d "
+		    "tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x "
+		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x sense_len=0x%x, "
+		    "par_sense_len=0x%x, rsp_info_len=0x%x\n",
 		    comp_status, scsi_status, res, vha->host_no,
 		    cp->device->id, cp->device->lun, fcport->tgt_id,
-		    lscsi_status, cp->cmnd[0], cp->cmnd[1], cp->cmnd[2],
-		    cp->cmnd[3], cp->cmnd[4], cp->cmnd[5], cp->cmnd[6],
-		    cp->cmnd[7], cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp),
+		    lscsi_status, cp->cmnd, scsi_bufflen(cp),
 		    rsp_info_len, resid_len, fw_resid_len, sense_len,
 		    par_sense_len, rsp_info_len);
 
@@ -2720,9 +2813,6 @@
 	struct sts_entry_fx00 *pkt;
 	response_t *lptr;
 
-	if (!vha->flags.online)
-		return;
-
 	while (RD_REG_DWORD((void __iomem *)&(rsp->ring_ptr->signature)) !=
 	    RESPONSE_PROCESSED) {
 		lptr = rsp->ring_ptr;
@@ -2824,6 +2914,28 @@
 		    ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
 		data_size = 4;
 		break;
+
+	case QLAFX00_MBA_TEMP_OVER:	/* Over temperature event */
+		ql_log(ql_log_info, vha, 0x5085,
+		    "Asynchronous over temperature event received "
+		    "aenmb[0]: %x\n",
+		    ha->aenmb[0]);
+		break;
+
+	case QLAFX00_MBA_TEMP_NORM:	/* Normal temperature event */
+		ql_log(ql_log_info, vha, 0x5086,
+		    "Asynchronous normal temperature event received "
+		    "aenmb[0]: %x\n",
+		    ha->aenmb[0]);
+		break;
+
+	case QLAFX00_MBA_TEMP_CRIT:	/* Critical temperature event */
+		ql_log(ql_log_info, vha, 0x5083,
+		    "Asynchronous critical temperature event received "
+		    "aenmb[0]: %x\n",
+		ha->aenmb[0]);
+		break;
+
 	default:
 		ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
 		ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
index 1a092af..79a93c5 100644
--- a/drivers/scsi/qla2xxx/qla_mr.h
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -329,11 +329,13 @@
 	uint64_t	adapter_id;
 
 	uint32_t	cluster_key_len;
-	uint8_t		cluster_key[10];
+	uint8_t		cluster_key[16];
 
 	uint64_t	cluster_master_id;
 	uint64_t	cluster_slave_id;
 	uint8_t		cluster_flags;
+	uint32_t	enabled_capabilities;
+	uint32_t	nominal_temp_value;
 } __packed;
 
 #define FXDISC_GET_CONFIG_INFO		0x01
@@ -342,10 +344,11 @@
 #define FXDISC_GET_TGT_NODE_LIST	0x81
 #define FXDISC_REG_HOST_INFO		0x99
 
-#define QLAFX00_HBA_ICNTRL_REG		0x21B08
+#define QLAFX00_HBA_ICNTRL_REG		0x20B08
 #define QLAFX00_ICR_ENB_MASK            0x80000000
 #define QLAFX00_ICR_DIS_MASK            0x7fffffff
 #define QLAFX00_HST_RST_REG		0x18264
+#define QLAFX00_SOC_TEMP_REG		0x184C4
 #define QLAFX00_HST_TO_HBA_REG		0x20A04
 #define QLAFX00_HBA_TO_HOST_REG		0x21B70
 #define QLAFX00_HST_INT_STS_BITS	0x7
@@ -361,6 +364,9 @@
 #define QLAFX00_INTR_ALL_CMPLT		0x7
 
 #define QLAFX00_MBA_SYSTEM_ERR		0x8002
+#define QLAFX00_MBA_TEMP_OVER		0x8005
+#define QLAFX00_MBA_TEMP_NORM		0x8006
+#define	QLAFX00_MBA_TEMP_CRIT		0x8007
 #define QLAFX00_MBA_LINK_UP		0x8011
 #define QLAFX00_MBA_LINK_DOWN		0x8012
 #define QLAFX00_MBA_PORT_UPDATE		0x8014
@@ -434,9 +440,11 @@
 
 	__le32 dataword_extra;
 
-	__le32 req_len;
+	__le16 req_len;
+	__le16 reserved_2;
 
-	__le32 rsp_len;
+	__le16 rsp_len;
+	__le16 reserved_3;
 };
 
 struct qla_mt_iocb_rsp_fx00 {
@@ -499,12 +507,37 @@
 	uint32_t old_fw_hbt_cnt;
 	uint16_t fw_reset_timer_tick;
 	uint8_t fw_reset_timer_exp;
+	uint16_t fw_critemp_timer_tick;
 	uint32_t old_aenmbx0_state;
+	uint32_t critical_temperature;
+	bool extended_io_enabled;
 };
 
+#define QLAFX00_EXTENDED_IO_EN_MASK    0x20
+
+/*
+ * SoC Junction Temperature is stored in
+ * bits 9:1 of SoC Junction Temperature Register
+ * in a firmware specific format format.
+ * To get the temperature in Celsius degrees
+ * the value from this bitfiled should be converted
+ * using this formula:
+ * Temperature (degrees C) = ((3,153,000 - (10,000 * X)) / 13,825)
+ * where X is the bit field value
+ * this macro reads the register, extracts the bitfield value,
+ * performs the calcualtions and returns temperature in Celsius
+ */
+#define QLAFX00_GET_TEMPERATURE(ha) ((3153000 - (10000 * \
+	((QLAFX00_RD_REG(ha, QLAFX00_SOC_TEMP_REG) & 0x3FE) >> 1))) / 13825)
+
+
 #define QLAFX00_LOOP_DOWN_TIME		615     /* 600 */
 #define QLAFX00_HEARTBEAT_INTERVAL	6	/* number of seconds */
 #define QLAFX00_HEARTBEAT_MISS_CNT	3	/* number of miss */
 #define QLAFX00_RESET_INTERVAL		120	/* number of seconds */
 #define QLAFX00_MAX_RESET_INTERVAL	600	/* number of seconds */
+#define QLAFX00_CRITEMP_INTERVAL	60	/* number of seconds */
+
+#define QLAFX00_CRITEMP_THRSHLD		80	/* Celsius degrees */
+
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index cce0cd0..11ce53d 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -848,7 +848,6 @@
 {
 	int done = 0, timeout = 0;
 	uint32_t lock_owner = 0;
-	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 
 	while (!done) {
 		/* acquire semaphore2 from PCI HW block */
@@ -857,9 +856,6 @@
 			break;
 		if (timeout >= qla82xx_rom_lock_timeout) {
 			lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
-			ql_dbg(ql_dbg_p3p, vha, 0xb085,
-			    "Failed to acquire rom lock, acquired by %d.\n",
-			    lock_owner);
 			return -1;
 		}
 		timeout++;
@@ -1666,8 +1662,14 @@
 	}
 
 	/* Mapping of IO base pointer */
-	ha->iobase = (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
-	    0xbc000 + (ha->pdev->devfn << 11));
+	if (IS_QLA8044(ha)) {
+		ha->iobase =
+		    (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase);
+	} else if (IS_QLA82XX(ha)) {
+		ha->iobase =
+		    (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase +
+			0xbc000 + (ha->pdev->devfn << 11));
+	}
 
 	if (!ql2xdbwr) {
 		ha->nxdb_wr_ptr =
@@ -1967,7 +1969,7 @@
  * @ha: SCSI driver HA context
  * @mb0: Mailbox0 register
  */
-static void
+void
 qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
 {
 	uint16_t	cnt;
@@ -2075,13 +2077,6 @@
 		WRT_REG_DWORD(&reg->host_int, 0);
 	}
 
-#ifdef QL_DEBUG_LEVEL_17
-	if (!irq && ha->flags.eeh_busy)
-		ql_log(ql_log_warn, vha, 0x503d,
-		    "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
-		    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
-#endif
-
 	qla2x00_handle_mbx_completion(ha, status);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -2147,13 +2142,6 @@
 		WRT_REG_DWORD(&reg->host_int, 0);
 	} while (0);
 
-#ifdef QL_DEBUG_LEVEL_17
-	if (!irq && ha->flags.eeh_busy)
-		ql_log(ql_log_warn, vha, 0x5044,
-		    "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n",
-		    status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat);
-#endif
-
 	qla2x00_handle_mbx_completion(ha, status);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
@@ -2247,7 +2235,10 @@
 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 	qla82xx_mbx_intr_enable(vha);
 	spin_lock_irq(&ha->hardware_lock);
-	qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
+	if (IS_QLA8044(ha))
+		qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 0);
+	else
+		qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
 	spin_unlock_irq(&ha->hardware_lock);
 	ha->interrupts_on = 1;
 }
@@ -2258,7 +2249,10 @@
 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
 	qla82xx_mbx_intr_disable(vha);
 	spin_lock_irq(&ha->hardware_lock);
-	qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
+	if (IS_QLA8044(ha))
+		qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 1);
+	else
+		qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
 	spin_unlock_irq(&ha->hardware_lock);
 	ha->interrupts_on = 0;
 }
@@ -3008,6 +3002,9 @@
 	if (IS_QLA82XX(ha)) {
 		qla82xx_clear_drv_active(ha);
 		qla82xx_idc_unlock(ha);
+	} else if (IS_QLA8044(ha)) {
+		qla8044_clear_drv_active(vha);
+		qla8044_idc_unlock(ha);
 	}
 
 	/* Set DEV_FAILED flag to disable timer */
@@ -3134,7 +3131,7 @@
 			if (fw_major_version != ha->fw_major_version ||
 			    fw_minor_version != ha->fw_minor_version ||
 			    fw_subminor_version != ha->fw_subminor_version) {
-				ql_log(ql_log_info, vha, 0xb02d,
+				ql_dbg(ql_dbg_p3p, vha, 0xb02d,
 				    "Firmware version differs "
 				    "Previous version: %d:%d:%d - "
 				    "New version: %d:%d:%d\n",
@@ -3330,6 +3327,14 @@
 	return 0;
 }
 
+int qla82xx_read_temperature(scsi_qla_host_t *vha)
+{
+	uint32_t temp;
+
+	temp = qla82xx_rd_32(vha->hw, CRB_TEMP_STATE);
+	return qla82xx_get_temp_val(temp);
+}
+
 void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha)
 {
 	struct qla_hw_data *ha = vha->hw;
@@ -3423,8 +3428,18 @@
 
 int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
 {
-	int rval;
-	rval = qla82xx_device_state_handler(vha);
+	int rval = -1;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (IS_QLA82XX(ha))
+		rval = qla82xx_device_state_handler(vha);
+	else if (IS_QLA8044(ha)) {
+		qla8044_idc_lock(ha);
+		/* Decide the reset ownership */
+		qla83xx_reset_ownership(vha);
+		qla8044_idc_unlock(ha);
+		rval = qla8044_device_state_handler(vha);
+	}
 	return rval;
 }
 
@@ -3432,17 +3447,25 @@
 qla82xx_set_reset_owner(scsi_qla_host_t *vha)
 {
 	struct qla_hw_data *ha = vha->hw;
-	uint32_t dev_state;
+	uint32_t dev_state = 0;
 
-	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+	if (IS_QLA82XX(ha))
+		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
+	else if (IS_QLA8044(ha))
+		dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
 	if (dev_state == QLA8XXX_DEV_READY) {
 		ql_log(ql_log_info, vha, 0xb02f,
 		    "HW State: NEED RESET\n");
-		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-			QLA8XXX_DEV_NEED_RESET);
-		ha->flags.nic_core_reset_owner = 1;
-		ql_dbg(ql_dbg_p3p, vha, 0xb030,
-		    "reset_owner is 0x%x\n", ha->portnum);
+		if (IS_QLA82XX(ha)) {
+			qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+			    QLA8XXX_DEV_NEED_RESET);
+			ha->flags.nic_core_reset_owner = 1;
+			ql_dbg(ql_dbg_p3p, vha, 0xb030,
+			    "reset_owner is 0x%x\n", ha->portnum);
+		} else if (IS_QLA8044(ha))
+			qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+			    QLA8XXX_DEV_NEED_RESET);
 	} else
 		ql_log(ql_log_info, vha, 0xb031,
 		    "Device state is 0x%x = %s.\n",
@@ -3463,7 +3486,7 @@
 int
 qla82xx_abort_isp(scsi_qla_host_t *vha)
 {
-	int rval;
+	int rval = -1;
 	struct qla_hw_data *ha = vha->hw;
 
 	if (vha->device_flags & DFLG_DEV_FAILED) {
@@ -3477,7 +3500,15 @@
 	qla82xx_set_reset_owner(vha);
 	qla82xx_idc_unlock(ha);
 
-	rval = qla82xx_device_state_handler(vha);
+	if (IS_QLA82XX(ha))
+		rval = qla82xx_device_state_handler(vha);
+	else if (IS_QLA8044(ha)) {
+		qla8044_idc_lock(ha);
+		/* Decide the reset ownership */
+		qla83xx_reset_ownership(vha);
+		qla8044_idc_unlock(ha);
+		rval = qla8044_device_state_handler(vha);
+	}
 
 	qla82xx_idc_lock(ha);
 	qla82xx_clear_rst_ready(ha);
@@ -3597,7 +3628,7 @@
 void
 qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
 {
-	int i;
+	int i, fw_state = 0;
 	unsigned long flags;
 	struct qla_hw_data *ha = vha->hw;
 
@@ -3608,7 +3639,11 @@
 	if (!ha->flags.isp82xx_fw_hung) {
 		for (i = 0; i < 2; i++) {
 			msleep(1000);
-			if (qla82xx_check_fw_alive(vha)) {
+			if (IS_QLA82XX(ha))
+				fw_state = qla82xx_check_fw_alive(vha);
+			else if (IS_QLA8044(ha))
+				fw_state = qla8044_check_fw_alive(vha);
+			if (fw_state) {
 				ha->flags.isp82xx_fw_hung = 1;
 				qla82xx_clear_pending_mbx(vha);
 				break;
@@ -4072,7 +4107,7 @@
 	return QLA_SUCCESS;
 }
 
-static int
+int
 qla82xx_validate_template_chksum(scsi_qla_host_t *vha)
 {
 	struct qla_hw_data *ha = vha->hw;
@@ -4384,7 +4419,11 @@
 		    ha->md_template_size / 1024);
 
 		/* Get Minidump template */
-		rval = qla82xx_md_get_template(vha);
+		if (IS_QLA8044(ha))
+			rval = qla8044_md_get_template(vha);
+		else
+			rval = qla82xx_md_get_template(vha);
+
 		if (rval == QLA_SUCCESS) {
 			ql_dbg(ql_dbg_p3p, vha, 0xb04b,
 			    "MiniDump Template obtained\n");
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index d268e84..1bb93db 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -589,6 +589,7 @@
  * The PCI VendorID and DeviceID for our board.
  */
 #define PCI_DEVICE_ID_QLOGIC_ISP8021		0x8021
+#define PCI_DEVICE_ID_QLOGIC_ISP8044		0x8044
 
 #define QLA82XX_MSIX_TBL_SPACE			8192
 #define QLA82XX_PCI_REG_MSIX_TBL		0x44
@@ -954,6 +955,11 @@
 #define QLA82XX_CNTRL                  98
 #define QLA82XX_TLHDR                  99
 #define QLA82XX_RDEND                  255
+#define QLA8044_POLLRD			35
+#define QLA8044_RDMUX2			36
+#define QLA8044_L1DTG			8
+#define QLA8044_L1ITG			9
+#define QLA8044_POLLRDMWR		37
 
 /*
  * Opcodes for Control Entries.
@@ -1191,4 +1197,8 @@
 	QLA82XX_TEMP_WARN,	   /* Sound alert, temperature getting high */
 	QLA82XX_TEMP_PANIC	   /* Fatal error, hardware has shut down. */
 };
+
+#define LEG_INTR_PTR_OFFSET	0x38C0
+#define LEG_INTR_TRIG_OFFSET	0x38C4
+#define LEG_INTR_MASK_OFFSET	0x38C8
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
new file mode 100644
index 0000000..8164cc9
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -0,0 +1,3716 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+
+#include <linux/vmalloc.h>
+
+#include "qla_def.h"
+#include "qla_gbl.h"
+
+#include <linux/delay.h>
+
+/* 8044 Flash Read/Write functions */
+uint32_t
+qla8044_rd_reg(struct qla_hw_data *ha, ulong addr)
+{
+	return readl((void __iomem *) (ha->nx_pcibase + addr));
+}
+
+void
+qla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val)
+{
+	writel(val, (void __iomem *)((ha)->nx_pcibase + addr));
+}
+
+int
+qla8044_rd_direct(struct scsi_qla_host *vha,
+	const uint32_t crb_reg)
+{
+	struct qla_hw_data *ha = vha->hw;
+
+	if (crb_reg < CRB_REG_INDEX_MAX)
+		return qla8044_rd_reg(ha, qla8044_reg_tbl[crb_reg]);
+	else
+		return QLA_FUNCTION_FAILED;
+}
+
+void
+qla8044_wr_direct(struct scsi_qla_host *vha,
+	const uint32_t crb_reg,
+	const uint32_t value)
+{
+	struct qla_hw_data *ha = vha->hw;
+
+	if (crb_reg < CRB_REG_INDEX_MAX)
+		qla8044_wr_reg(ha, qla8044_reg_tbl[crb_reg], value);
+}
+
+static int
+qla8044_set_win_base(scsi_qla_host_t *vha, uint32_t addr)
+{
+	uint32_t val;
+	int ret_val = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	qla8044_wr_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum), addr);
+	val = qla8044_rd_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum));
+
+	if (val != addr) {
+		ql_log(ql_log_warn, vha, 0xb087,
+		    "%s: Failed to set register window : "
+		    "addr written 0x%x, read 0x%x!\n",
+		    __func__, addr, val);
+		ret_val = QLA_FUNCTION_FAILED;
+	}
+	return ret_val;
+}
+
+static int
+qla8044_rd_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data)
+{
+	int ret_val = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	ret_val = qla8044_set_win_base(vha, addr);
+	if (!ret_val)
+		*data = qla8044_rd_reg(ha, QLA8044_WILDCARD);
+	else
+		ql_log(ql_log_warn, vha, 0xb088,
+		    "%s: failed read of addr 0x%x!\n", __func__, addr);
+	return ret_val;
+}
+
+static int
+qla8044_wr_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t data)
+{
+	int ret_val = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	ret_val = qla8044_set_win_base(vha, addr);
+	if (!ret_val)
+		qla8044_wr_reg(ha, QLA8044_WILDCARD, data);
+	else
+		ql_log(ql_log_warn, vha, 0xb089,
+		    "%s: failed wrt to addr 0x%x, data 0x%x\n",
+		    __func__, addr, data);
+	return ret_val;
+}
+
+/*
+ * qla8044_read_write_crb_reg - Read from raddr and write value to waddr.
+ *
+ * @ha : Pointer to adapter structure
+ * @raddr : CRB address to read from
+ * @waddr : CRB address to write to
+ *
+ */
+static void
+qla8044_read_write_crb_reg(struct scsi_qla_host *vha,
+	uint32_t raddr, uint32_t waddr)
+{
+	uint32_t value;
+
+	qla8044_rd_reg_indirect(vha, raddr, &value);
+	qla8044_wr_reg_indirect(vha, waddr, value);
+}
+
+/*
+ * qla8044_rmw_crb_reg - Read value from raddr, AND with test_mask,
+ * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
+ *
+ * @vha : Pointer to adapter structure
+ * @raddr : CRB address to read from
+ * @waddr : CRB address to write to
+ * @p_rmw_hdr : header with shift/or/xor values.
+ *
+ */
+static void
+qla8044_rmw_crb_reg(struct scsi_qla_host *vha,
+	uint32_t raddr, uint32_t waddr,	struct qla8044_rmw *p_rmw_hdr)
+{
+	uint32_t value;
+
+	if (p_rmw_hdr->index_a)
+		value = vha->reset_tmplt.array[p_rmw_hdr->index_a];
+	else
+		qla8044_rd_reg_indirect(vha, raddr, &value);
+	value &= p_rmw_hdr->test_mask;
+	value <<= p_rmw_hdr->shl;
+	value >>= p_rmw_hdr->shr;
+	value |= p_rmw_hdr->or_value;
+	value ^= p_rmw_hdr->xor_value;
+	qla8044_wr_reg_indirect(vha, waddr, value);
+	return;
+}
+
+inline void
+qla8044_set_qsnt_ready(struct scsi_qla_host *vha)
+{
+	uint32_t qsnt_state;
+	struct qla_hw_data *ha = vha->hw;
+
+	qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+	qsnt_state |= (1 << ha->portnum);
+	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state);
+	ql_log(ql_log_info, vha, 0xb08e, "%s(%ld): qsnt_state: 0x%08x\n",
+	     __func__, vha->host_no, qsnt_state);
+}
+
+void
+qla8044_clear_qsnt_ready(struct scsi_qla_host *vha)
+{
+	uint32_t qsnt_state;
+	struct qla_hw_data *ha = vha->hw;
+
+	qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+	qsnt_state &= ~(1 << ha->portnum);
+	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state);
+	ql_log(ql_log_info, vha, 0xb08f, "%s(%ld): qsnt_state: 0x%08x\n",
+	    __func__, vha->host_no, qsnt_state);
+}
+
+/**
+ *
+ * qla8044_lock_recovery - Recovers the idc_lock.
+ * @ha : Pointer to adapter structure
+ *
+ * Lock Recovery Register
+ * 5-2	Lock recovery owner: Function ID of driver doing lock recovery,
+ *	valid if bits 1..0 are set by driver doing lock recovery.
+ * 1-0  1 - Driver intends to force unlock the IDC lock.
+ *	2 - Driver is moving forward to unlock the IDC lock. Driver clears
+ *	    this field after force unlocking the IDC lock.
+ *
+ * Lock Recovery process
+ * a. Read the IDC_LOCK_RECOVERY register. If the value in bits 1..0 is
+ *    greater than 0, then wait for the other driver to unlock otherwise
+ *    move to the next step.
+ * b. Indicate intent to force-unlock by writing 1h to the IDC_LOCK_RECOVERY
+ *    register bits 1..0 and also set the function# in bits 5..2.
+ * c. Read the IDC_LOCK_RECOVERY register again after a delay of 200ms.
+ *    Wait for the other driver to perform lock recovery if the function
+ *    number in bits 5..2 has changed, otherwise move to the next step.
+ * d. Write a value of 2h to the IDC_LOCK_RECOVERY register bits 1..0
+ *    leaving your function# in bits 5..2.
+ * e. Force unlock using the DRIVER_UNLOCK register and immediately clear
+ *    the IDC_LOCK_RECOVERY bits 5..0 by writing 0.
+ **/
+static int
+qla8044_lock_recovery(struct scsi_qla_host *vha)
+{
+	uint32_t lock = 0, lockid;
+	struct qla_hw_data *ha = vha->hw;
+
+	lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY);
+
+	/* Check for other Recovery in progress, go wait */
+	if ((lockid & IDC_LOCK_RECOVERY_STATE_MASK) != 0)
+		return QLA_FUNCTION_FAILED;
+
+	/* Intent to Recover */
+	qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY,
+	    (ha->portnum <<
+	     IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) | INTENT_TO_RECOVER);
+	msleep(200);
+
+	/* Check Intent to Recover is advertised */
+	lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY);
+	if ((lockid & IDC_LOCK_RECOVERY_OWNER_MASK) != (ha->portnum <<
+	    IDC_LOCK_RECOVERY_STATE_SHIFT_BITS))
+		return QLA_FUNCTION_FAILED;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb08B, "%s:%d: IDC Lock recovery initiated\n"
+	    , __func__, ha->portnum);
+
+	/* Proceed to Recover */
+	qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY,
+	    (ha->portnum << IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) |
+	    PROCEED_TO_RECOVER);
+
+	/* Force Unlock() */
+	qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, 0xFF);
+	qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK);
+
+	/* Clear bits 0-5 in IDC_RECOVERY register*/
+	qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY, 0);
+
+	/* Get lock() */
+	lock = qla8044_rd_reg(ha, QLA8044_DRV_LOCK);
+	if (lock) {
+		lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+		lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->portnum;
+		qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lockid);
+		return QLA_SUCCESS;
+	} else
+		return QLA_FUNCTION_FAILED;
+}
+
+int
+qla8044_idc_lock(struct qla_hw_data *ha)
+{
+	uint32_t ret_val = QLA_SUCCESS, timeout = 0, status = 0;
+	uint32_t lock_id, lock_cnt, func_num, tmo_owner = 0, first_owner = 0;
+	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
+	while (status == 0) {
+		/* acquire semaphore5 from PCI HW block */
+		status = qla8044_rd_reg(ha, QLA8044_DRV_LOCK);
+
+		if (status) {
+			/* Increment Counter (8-31) and update func_num (0-7) on
+			 * getting a successful lock  */
+			lock_id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+			lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->portnum;
+			qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lock_id);
+			break;
+		}
+
+		if (timeout == 0)
+			first_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+
+		if (++timeout >=
+		    (QLA8044_DRV_LOCK_TIMEOUT / QLA8044_DRV_LOCK_MSLEEP)) {
+			tmo_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+			func_num = tmo_owner & 0xFF;
+			lock_cnt = tmo_owner >> 8;
+			ql_log(ql_log_warn, vha, 0xb114,
+			    "%s: Lock by func %d failed after 2s, lock held "
+			    "by func %d, lock count %d, first_owner %d\n",
+			    __func__, ha->portnum, func_num, lock_cnt,
+			    (first_owner & 0xFF));
+			if (first_owner != tmo_owner) {
+				/* Some other driver got lock,
+				 * OR same driver got lock again (counter
+				 * value changed), when we were waiting for
+				 * lock. Retry for another 2 sec */
+				ql_dbg(ql_dbg_p3p, vha, 0xb115,
+				    "%s: %d: IDC lock failed\n",
+				    __func__, ha->portnum);
+				timeout = 0;
+			} else {
+				/* Same driver holding lock > 2sec.
+				 * Force Recovery */
+				if (qla8044_lock_recovery(vha) == QLA_SUCCESS) {
+					/* Recovered and got lock */
+					ret_val = QLA_SUCCESS;
+					ql_dbg(ql_dbg_p3p, vha, 0xb116,
+					    "%s:IDC lock Recovery by %d"
+					    "successful...\n", __func__,
+					     ha->portnum);
+				}
+				/* Recovery Failed, some other function
+				 * has the lock, wait for 2secs
+				 * and retry
+				 */
+				 ql_dbg(ql_dbg_p3p, vha, 0xb08a,
+				     "%s: IDC lock Recovery by %d "
+				     "failed, Retrying timout\n", __func__,
+				     ha->portnum);
+				 timeout = 0;
+			}
+		}
+		msleep(QLA8044_DRV_LOCK_MSLEEP);
+	}
+	return ret_val;
+}
+
+void
+qla8044_idc_unlock(struct qla_hw_data *ha)
+{
+	int id;
+	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+
+	id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
+
+	if ((id & 0xFF) != ha->portnum) {
+		ql_log(ql_log_warn, vha, 0xb118,
+		    "%s: IDC Unlock by %d failed, lock owner is %d!\n",
+		    __func__, ha->portnum, (id & 0xFF));
+		return;
+	}
+
+	/* Keep lock counter value, update the ha->func_num to 0xFF */
+	qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, (id | 0xFF));
+	qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK);
+}
+
+/* 8044 Flash Lock/Unlock functions */
+static int
+qla8044_flash_lock(scsi_qla_host_t *vha)
+{
+	int lock_owner;
+	int timeout = 0;
+	uint32_t lock_status = 0;
+	int ret_val = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	while (lock_status == 0) {
+		lock_status = qla8044_rd_reg(ha, QLA8044_FLASH_LOCK);
+		if (lock_status)
+			break;
+
+		if (++timeout >= QLA8044_FLASH_LOCK_TIMEOUT / 20) {
+			lock_owner = qla8044_rd_reg(ha,
+			    QLA8044_FLASH_LOCK_ID);
+			ql_log(ql_log_warn, vha, 0xb113,
+			    "%s: flash lock by %d failed, held by %d\n",
+				__func__, ha->portnum, lock_owner);
+			ret_val = QLA_FUNCTION_FAILED;
+			break;
+		}
+		msleep(20);
+	}
+	qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, ha->portnum);
+	return ret_val;
+}
+
+static void
+qla8044_flash_unlock(scsi_qla_host_t *vha)
+{
+	int ret_val;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Reading FLASH_UNLOCK register unlocks the Flash */
+	qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, 0xFF);
+	ret_val = qla8044_rd_reg(ha, QLA8044_FLASH_UNLOCK);
+}
+
+
+static
+void qla8044_flash_lock_recovery(struct scsi_qla_host *vha)
+{
+
+	if (qla8044_flash_lock(vha)) {
+		/* Someone else is holding the lock. */
+		ql_log(ql_log_warn, vha, 0xb120, "Resetting flash_lock\n");
+	}
+
+	/*
+	 * Either we got the lock, or someone
+	 * else died while holding it.
+	 * In either case, unlock.
+	 */
+	qla8044_flash_unlock(vha);
+}
+
+/*
+ * Address and length are byte address
+ */
+static int
+qla8044_read_flash_data(scsi_qla_host_t *vha,  uint8_t *p_data,
+	uint32_t flash_addr, int u32_word_count)
+{
+	int i, ret_val = QLA_SUCCESS;
+	uint32_t u32_word;
+
+	if (qla8044_flash_lock(vha) != QLA_SUCCESS) {
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_lock_error;
+	}
+
+	if (flash_addr & 0x03) {
+		ql_log(ql_log_warn, vha, 0xb117,
+		    "%s: Illegal addr = 0x%x\n", __func__, flash_addr);
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_flash_read;
+	}
+
+	for (i = 0; i < u32_word_count; i++) {
+		if (qla8044_wr_reg_indirect(vha, QLA8044_FLASH_DIRECT_WINDOW,
+		    (flash_addr & 0xFFFF0000))) {
+			ql_log(ql_log_warn, vha, 0xb119,
+			    "%s: failed to write addr 0x%x to "
+			    "FLASH_DIRECT_WINDOW\n! ",
+			    __func__, flash_addr);
+			ret_val = QLA_FUNCTION_FAILED;
+			goto exit_flash_read;
+		}
+
+		ret_val = qla8044_rd_reg_indirect(vha,
+		    QLA8044_FLASH_DIRECT_DATA(flash_addr),
+		    &u32_word);
+		if (ret_val != QLA_SUCCESS) {
+			ql_log(ql_log_warn, vha, 0xb08c,
+			    "%s: failed to read addr 0x%x!\n",
+			    __func__, flash_addr);
+			goto exit_flash_read;
+		}
+
+		*(uint32_t *)p_data = u32_word;
+		p_data = p_data + 4;
+		flash_addr = flash_addr + 4;
+	}
+
+exit_flash_read:
+	qla8044_flash_unlock(vha);
+
+exit_lock_error:
+	return ret_val;
+}
+
+/*
+ * Address and length are byte address
+ */
+uint8_t *
+qla8044_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+	uint32_t offset, uint32_t length)
+{
+	scsi_block_requests(vha->host);
+	if (qla8044_read_flash_data(vha, (uint8_t *)buf, offset, length / 4)
+	    != QLA_SUCCESS) {
+		ql_log(ql_log_warn, vha,  0xb08d,
+		    "%s: Failed to read from flash\n",
+		    __func__);
+	}
+	scsi_unblock_requests(vha->host);
+	return buf;
+}
+
+inline int
+qla8044_need_reset(struct scsi_qla_host *vha)
+{
+	uint32_t drv_state, drv_active;
+	int rval;
+	struct qla_hw_data *ha = vha->hw;
+
+	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+
+	rval = drv_state & (1 << ha->portnum);
+
+	if (ha->flags.eeh_busy && drv_active)
+		rval = 1;
+	return rval;
+}
+
+/*
+ * qla8044_write_list - Write the value (p_entry->arg2) to address specified
+ * by p_entry->arg1 for all entries in header with delay of p_hdr->delay between
+ * entries.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : reset_entry header for WRITE_LIST opcode.
+ *
+ */
+static void
+qla8044_write_list(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	struct qla8044_entry *p_entry;
+	uint32_t i;
+
+	p_entry = (struct qla8044_entry *)((char *)p_hdr +
+	    sizeof(struct qla8044_reset_entry_hdr));
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla8044_wr_reg_indirect(vha, p_entry->arg1, p_entry->arg2);
+		if (p_hdr->delay)
+			udelay((uint32_t)(p_hdr->delay));
+	}
+}
+
+/*
+ * qla8044_read_write_list - Read from address specified by p_entry->arg1,
+ * write value read to address specified by p_entry->arg2, for all entries in
+ * header with delay of p_hdr->delay between entries.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : reset_entry header for READ_WRITE_LIST opcode.
+ *
+ */
+static void
+qla8044_read_write_list(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	struct qla8044_entry *p_entry;
+	uint32_t i;
+
+	p_entry = (struct qla8044_entry *)((char *)p_hdr +
+	    sizeof(struct qla8044_reset_entry_hdr));
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla8044_read_write_crb_reg(vha, p_entry->arg1,
+		    p_entry->arg2);
+		if (p_hdr->delay)
+			udelay((uint32_t)(p_hdr->delay));
+	}
+}
+
+/*
+ * qla8044_poll_reg - Poll the given CRB addr for duration msecs till
+ * value read ANDed with test_mask is equal to test_result.
+ *
+ * @ha : Pointer to adapter structure
+ * @addr : CRB register address
+ * @duration : Poll for total of "duration" msecs
+ * @test_mask : Mask value read with "test_mask"
+ * @test_result : Compare (value&test_mask) with test_result.
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_poll_reg(struct scsi_qla_host *vha, uint32_t addr,
+	int duration, uint32_t test_mask, uint32_t test_result)
+{
+	uint32_t value;
+	int timeout_error;
+	uint8_t retries;
+	int ret_val = QLA_SUCCESS;
+
+	ret_val = qla8044_rd_reg_indirect(vha, addr, &value);
+	if (ret_val == QLA_FUNCTION_FAILED) {
+		timeout_error = 1;
+		goto exit_poll_reg;
+	}
+
+	/* poll every 1/10 of the total duration */
+	retries = duration/10;
+
+	do {
+		if ((value & test_mask) != test_result) {
+			timeout_error = 1;
+			msleep(duration/10);
+			ret_val = qla8044_rd_reg_indirect(vha, addr, &value);
+			if (ret_val == QLA_FUNCTION_FAILED) {
+				timeout_error = 1;
+				goto exit_poll_reg;
+			}
+		} else {
+			timeout_error = 0;
+			break;
+		}
+	} while (retries--);
+
+exit_poll_reg:
+	if (timeout_error) {
+		vha->reset_tmplt.seq_error++;
+		ql_log(ql_log_fatal, vha, 0xb090,
+		    "%s: Poll Failed: 0x%08x 0x%08x 0x%08x\n",
+		    __func__, value, test_mask, test_result);
+	}
+
+	return timeout_error;
+}
+
+/*
+ * qla8044_poll_list - For all entries in the POLL_LIST header, poll read CRB
+ * register specified by p_entry->arg1 and compare (value AND test_mask) with
+ * test_result to validate it. Wait for p_hdr->delay between processing entries.
+ *
+ * @ha : Pointer to adapter structure
+ * @p_hdr : reset_entry header for POLL_LIST opcode.
+ *
+ */
+static void
+qla8044_poll_list(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	long delay;
+	struct qla8044_entry *p_entry;
+	struct qla8044_poll *p_poll;
+	uint32_t i;
+	uint32_t value;
+
+	p_poll = (struct qla8044_poll *)
+		((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr));
+
+	/* Entries start after 8 byte qla8044_poll, poll header contains
+	 * the test_mask, test_value.
+	 */
+	p_entry = (struct qla8044_entry *)((char *)p_poll +
+	    sizeof(struct qla8044_poll));
+
+	delay = (long)p_hdr->delay;
+
+	if (!delay) {
+		for (i = 0; i < p_hdr->count; i++, p_entry++)
+			qla8044_poll_reg(vha, p_entry->arg1,
+			    delay, p_poll->test_mask, p_poll->test_value);
+	} else {
+		for (i = 0; i < p_hdr->count; i++, p_entry++) {
+			if (delay) {
+				if (qla8044_poll_reg(vha,
+				    p_entry->arg1, delay,
+				    p_poll->test_mask,
+				    p_poll->test_value)) {
+					/*If
+					* (data_read&test_mask != test_value)
+					* read TIMEOUT_ADDR (arg1) and
+					* ADDR (arg2) registers
+					*/
+					qla8044_rd_reg_indirect(vha,
+					    p_entry->arg1, &value);
+					qla8044_rd_reg_indirect(vha,
+					    p_entry->arg2, &value);
+				}
+			}
+		}
+	}
+}
+
+/*
+ * qla8044_poll_write_list - Write dr_value, ar_value to dr_addr/ar_addr,
+ * read ar_addr, if (value& test_mask != test_mask) re-read till timeout
+ * expires.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : reset entry header for POLL_WRITE_LIST opcode.
+ *
+ */
+static void
+qla8044_poll_write_list(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	long delay;
+	struct qla8044_quad_entry *p_entry;
+	struct qla8044_poll *p_poll;
+	uint32_t i;
+
+	p_poll = (struct qla8044_poll *)((char *)p_hdr +
+	    sizeof(struct qla8044_reset_entry_hdr));
+
+	p_entry = (struct qla8044_quad_entry *)((char *)p_poll +
+	    sizeof(struct qla8044_poll));
+
+	delay = (long)p_hdr->delay;
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla8044_wr_reg_indirect(vha,
+		    p_entry->dr_addr, p_entry->dr_value);
+		qla8044_wr_reg_indirect(vha,
+		    p_entry->ar_addr, p_entry->ar_value);
+		if (delay) {
+			if (qla8044_poll_reg(vha,
+			    p_entry->ar_addr, delay,
+			    p_poll->test_mask,
+			    p_poll->test_value)) {
+				ql_dbg(ql_dbg_p3p, vha, 0xb091,
+				    "%s: Timeout Error: poll list, ",
+				    __func__);
+				ql_dbg(ql_dbg_p3p, vha, 0xb092,
+				    "item_num %d, entry_num %d\n", i,
+				    vha->reset_tmplt.seq_index);
+			}
+		}
+	}
+}
+
+/*
+ * qla8044_read_modify_write - Read value from p_entry->arg1, modify the
+ * value, write value to p_entry->arg2. Process entries with p_hdr->delay
+ * between entries.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : header with shift/or/xor values.
+ *
+ */
+static void
+qla8044_read_modify_write(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	struct qla8044_entry *p_entry;
+	struct qla8044_rmw *p_rmw_hdr;
+	uint32_t i;
+
+	p_rmw_hdr = (struct qla8044_rmw *)((char *)p_hdr +
+	    sizeof(struct qla8044_reset_entry_hdr));
+
+	p_entry = (struct qla8044_entry *)((char *)p_rmw_hdr +
+	    sizeof(struct qla8044_rmw));
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla8044_rmw_crb_reg(vha, p_entry->arg1,
+		    p_entry->arg2, p_rmw_hdr);
+		if (p_hdr->delay)
+			udelay((uint32_t)(p_hdr->delay));
+	}
+}
+
+/*
+ * qla8044_pause - Wait for p_hdr->delay msecs, called between processing
+ * two entries of a sequence.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : Common reset entry header.
+ *
+ */
+static
+void qla8044_pause(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	if (p_hdr->delay)
+		mdelay((uint32_t)((long)p_hdr->delay));
+}
+
+/*
+ * qla8044_template_end - Indicates end of reset sequence processing.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : Common reset entry header.
+ *
+ */
+static void
+qla8044_template_end(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	vha->reset_tmplt.template_end = 1;
+
+	if (vha->reset_tmplt.seq_error == 0) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb093,
+		    "%s: Reset sequence completed SUCCESSFULLY.\n", __func__);
+	} else {
+		ql_log(ql_log_fatal, vha, 0xb094,
+		    "%s: Reset sequence completed with some timeout "
+		    "errors.\n", __func__);
+	}
+}
+
+/*
+ * qla8044_poll_read_list - Write ar_value to ar_addr register, read ar_addr,
+ * if (value & test_mask != test_value) re-read till timeout value expires,
+ * read dr_addr register and assign to reset_tmplt.array.
+ *
+ * @vha : Pointer to adapter structure
+ * @p_hdr : Common reset entry header.
+ *
+ */
+static void
+qla8044_poll_read_list(struct scsi_qla_host *vha,
+	struct qla8044_reset_entry_hdr *p_hdr)
+{
+	long delay;
+	int index;
+	struct qla8044_quad_entry *p_entry;
+	struct qla8044_poll *p_poll;
+	uint32_t i;
+	uint32_t value;
+
+	p_poll = (struct qla8044_poll *)
+		((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr));
+
+	p_entry = (struct qla8044_quad_entry *)
+		((char *)p_poll + sizeof(struct qla8044_poll));
+
+	delay = (long)p_hdr->delay;
+
+	for (i = 0; i < p_hdr->count; i++, p_entry++) {
+		qla8044_wr_reg_indirect(vha, p_entry->ar_addr,
+		    p_entry->ar_value);
+		if (delay) {
+			if (qla8044_poll_reg(vha, p_entry->ar_addr, delay,
+			    p_poll->test_mask, p_poll->test_value)) {
+				ql_dbg(ql_dbg_p3p, vha, 0xb095,
+				    "%s: Timeout Error: poll "
+				    "list, ", __func__);
+				ql_dbg(ql_dbg_p3p, vha, 0xb096,
+				    "Item_num %d, "
+				    "entry_num %d\n", i,
+				    vha->reset_tmplt.seq_index);
+			} else {
+				index = vha->reset_tmplt.array_index;
+				qla8044_rd_reg_indirect(vha,
+				    p_entry->dr_addr, &value);
+				vha->reset_tmplt.array[index++] = value;
+				if (index == QLA8044_MAX_RESET_SEQ_ENTRIES)
+					vha->reset_tmplt.array_index = 1;
+			}
+		}
+	}
+}
+
+/*
+ * qla8031_process_reset_template - Process all entries in reset template
+ * till entry with SEQ_END opcode, which indicates end of the reset template
+ * processing. Each entry has a Reset Entry header, entry opcode/command, with
+ * size of the entry, number of entries in sub-sequence and delay in microsecs
+ * or timeout in millisecs.
+ *
+ * @ha : Pointer to adapter structure
+ * @p_buff : Common reset entry header.
+ *
+ */
+static void
+qla8044_process_reset_template(struct scsi_qla_host *vha,
+	char *p_buff)
+{
+	int index, entries;
+	struct qla8044_reset_entry_hdr *p_hdr;
+	char *p_entry = p_buff;
+
+	vha->reset_tmplt.seq_end = 0;
+	vha->reset_tmplt.template_end = 0;
+	entries = vha->reset_tmplt.hdr->entries;
+	index = vha->reset_tmplt.seq_index;
+
+	for (; (!vha->reset_tmplt.seq_end) && (index  < entries); index++) {
+		p_hdr = (struct qla8044_reset_entry_hdr *)p_entry;
+		switch (p_hdr->cmd) {
+		case OPCODE_NOP:
+			break;
+		case OPCODE_WRITE_LIST:
+			qla8044_write_list(vha, p_hdr);
+			break;
+		case OPCODE_READ_WRITE_LIST:
+			qla8044_read_write_list(vha, p_hdr);
+			break;
+		case OPCODE_POLL_LIST:
+			qla8044_poll_list(vha, p_hdr);
+			break;
+		case OPCODE_POLL_WRITE_LIST:
+			qla8044_poll_write_list(vha, p_hdr);
+			break;
+		case OPCODE_READ_MODIFY_WRITE:
+			qla8044_read_modify_write(vha, p_hdr);
+			break;
+		case OPCODE_SEQ_PAUSE:
+			qla8044_pause(vha, p_hdr);
+			break;
+		case OPCODE_SEQ_END:
+			vha->reset_tmplt.seq_end = 1;
+			break;
+		case OPCODE_TMPL_END:
+			qla8044_template_end(vha, p_hdr);
+			break;
+		case OPCODE_POLL_READ_LIST:
+			qla8044_poll_read_list(vha, p_hdr);
+			break;
+		default:
+			ql_log(ql_log_fatal, vha, 0xb097,
+			    "%s: Unknown command ==> 0x%04x on "
+			    "entry = %d\n", __func__, p_hdr->cmd, index);
+			break;
+		}
+		/*
+		 *Set pointer to next entry in the sequence.
+		*/
+		p_entry += p_hdr->size;
+	}
+	vha->reset_tmplt.seq_index = index;
+}
+
+static void
+qla8044_process_init_seq(struct scsi_qla_host *vha)
+{
+	qla8044_process_reset_template(vha,
+	    vha->reset_tmplt.init_offset);
+	if (vha->reset_tmplt.seq_end != 1)
+		ql_log(ql_log_fatal, vha, 0xb098,
+		    "%s: Abrupt INIT Sub-Sequence end.\n",
+		    __func__);
+}
+
+static void
+qla8044_process_stop_seq(struct scsi_qla_host *vha)
+{
+	vha->reset_tmplt.seq_index = 0;
+	qla8044_process_reset_template(vha, vha->reset_tmplt.stop_offset);
+	if (vha->reset_tmplt.seq_end != 1)
+		ql_log(ql_log_fatal, vha, 0xb099,
+		    "%s: Abrupt STOP Sub-Sequence end.\n", __func__);
+}
+
+static void
+qla8044_process_start_seq(struct scsi_qla_host *vha)
+{
+	qla8044_process_reset_template(vha, vha->reset_tmplt.start_offset);
+	if (vha->reset_tmplt.template_end != 1)
+		ql_log(ql_log_fatal, vha, 0xb09a,
+		    "%s: Abrupt START Sub-Sequence end.\n",
+		    __func__);
+}
+
+static int
+qla8044_lockless_flash_read_u32(struct scsi_qla_host *vha,
+	uint32_t flash_addr, uint8_t *p_data, int u32_word_count)
+{
+	uint32_t i;
+	uint32_t u32_word;
+	uint32_t flash_offset;
+	uint32_t addr = flash_addr;
+	int ret_val = QLA_SUCCESS;
+
+	flash_offset = addr & (QLA8044_FLASH_SECTOR_SIZE - 1);
+
+	if (addr & 0x3) {
+		ql_log(ql_log_fatal, vha, 0xb09b, "%s: Illegal addr = 0x%x\n",
+		    __func__, addr);
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_lockless_read;
+	}
+
+	ret_val = qla8044_wr_reg_indirect(vha,
+	    QLA8044_FLASH_DIRECT_WINDOW, (addr));
+
+	if (ret_val != QLA_SUCCESS) {
+		ql_log(ql_log_fatal, vha, 0xb09c,
+		    "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
+		    __func__, addr);
+		goto exit_lockless_read;
+	}
+
+	/* Check if data is spread across multiple sectors  */
+	if ((flash_offset + (u32_word_count * sizeof(uint32_t))) >
+	    (QLA8044_FLASH_SECTOR_SIZE - 1)) {
+		/* Multi sector read */
+		for (i = 0; i < u32_word_count; i++) {
+			ret_val = qla8044_rd_reg_indirect(vha,
+			    QLA8044_FLASH_DIRECT_DATA(addr), &u32_word);
+			if (ret_val != QLA_SUCCESS) {
+				ql_log(ql_log_fatal, vha, 0xb09d,
+				    "%s: failed to read addr 0x%x!\n",
+				    __func__, addr);
+				goto exit_lockless_read;
+			}
+			*(uint32_t *)p_data  = u32_word;
+			p_data = p_data + 4;
+			addr = addr + 4;
+			flash_offset = flash_offset + 4;
+			if (flash_offset > (QLA8044_FLASH_SECTOR_SIZE - 1)) {
+				/* This write is needed once for each sector */
+				ret_val = qla8044_wr_reg_indirect(vha,
+				    QLA8044_FLASH_DIRECT_WINDOW, (addr));
+				if (ret_val != QLA_SUCCESS) {
+					ql_log(ql_log_fatal, vha, 0xb09f,
+					    "%s: failed to write addr "
+					    "0x%x to FLASH_DIRECT_WINDOW!\n",
+					    __func__, addr);
+					goto exit_lockless_read;
+				}
+				flash_offset = 0;
+			}
+		}
+	} else {
+		/* Single sector read */
+		for (i = 0; i < u32_word_count; i++) {
+			ret_val = qla8044_rd_reg_indirect(vha,
+			    QLA8044_FLASH_DIRECT_DATA(addr), &u32_word);
+			if (ret_val != QLA_SUCCESS) {
+				ql_log(ql_log_fatal, vha, 0xb0a0,
+				    "%s: failed to read addr 0x%x!\n",
+				    __func__, addr);
+				goto exit_lockless_read;
+			}
+			*(uint32_t *)p_data = u32_word;
+			p_data = p_data + 4;
+			addr = addr + 4;
+		}
+	}
+
+exit_lockless_read:
+	return ret_val;
+}
+
+/*
+ * qla8044_ms_mem_write_128b - Writes data to MS/off-chip memory
+ *
+ * @vha : Pointer to adapter structure
+ * addr : Flash address to write to
+ * data : Data to be written
+ * count : word_count to be written
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_ms_mem_write_128b(struct scsi_qla_host *vha,
+	uint64_t addr, uint32_t *data, uint32_t count)
+{
+	int i, j, ret_val = QLA_SUCCESS;
+	uint32_t agt_ctrl;
+	unsigned long flags;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* Only 128-bit aligned access */
+	if (addr & 0xF) {
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_ms_mem_write;
+	}
+	write_lock_irqsave(&ha->hw_lock, flags);
+
+	/* Write address */
+	ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, 0);
+	if (ret_val == QLA_FUNCTION_FAILED) {
+		ql_log(ql_log_fatal, vha, 0xb0a1,
+		    "%s: write to AGT_ADDR_HI failed!\n", __func__);
+		goto exit_ms_mem_write_unlock;
+	}
+
+	for (i = 0; i < count; i++, addr += 16) {
+		if (!((QLA8044_ADDR_IN_RANGE(addr, QLA8044_ADDR_QDR_NET,
+		    QLA8044_ADDR_QDR_NET_MAX)) ||
+		    (QLA8044_ADDR_IN_RANGE(addr, QLA8044_ADDR_DDR_NET,
+			QLA8044_ADDR_DDR_NET_MAX)))) {
+			ret_val = QLA_FUNCTION_FAILED;
+			goto exit_ms_mem_write_unlock;
+		}
+
+		ret_val = qla8044_wr_reg_indirect(vha,
+		    MD_MIU_TEST_AGT_ADDR_LO, addr);
+
+		/* Write data */
+		ret_val += qla8044_wr_reg_indirect(vha,
+		    MD_MIU_TEST_AGT_WRDATA_LO, *data++);
+		ret_val += qla8044_wr_reg_indirect(vha,
+		    MD_MIU_TEST_AGT_WRDATA_HI, *data++);
+		ret_val += qla8044_wr_reg_indirect(vha,
+		    MD_MIU_TEST_AGT_WRDATA_ULO, *data++);
+		ret_val += qla8044_wr_reg_indirect(vha,
+		    MD_MIU_TEST_AGT_WRDATA_UHI, *data++);
+		if (ret_val == QLA_FUNCTION_FAILED) {
+			ql_log(ql_log_fatal, vha, 0xb0a2,
+			    "%s: write to AGT_WRDATA failed!\n",
+			    __func__);
+			goto exit_ms_mem_write_unlock;
+		}
+
+		/* Check write status */
+		ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
+		    MIU_TA_CTL_WRITE_ENABLE);
+		ret_val += qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
+		    MIU_TA_CTL_WRITE_START);
+		if (ret_val == QLA_FUNCTION_FAILED) {
+			ql_log(ql_log_fatal, vha, 0xb0a3,
+			    "%s: write to AGT_CTRL failed!\n", __func__);
+			goto exit_ms_mem_write_unlock;
+		}
+
+		for (j = 0; j < MAX_CTL_CHECK; j++) {
+			ret_val = qla8044_rd_reg_indirect(vha,
+			    MD_MIU_TEST_AGT_CTRL, &agt_ctrl);
+			if (ret_val == QLA_FUNCTION_FAILED) {
+				ql_log(ql_log_fatal, vha, 0xb0a4,
+				    "%s: failed to read "
+				    "MD_MIU_TEST_AGT_CTRL!\n", __func__);
+				goto exit_ms_mem_write_unlock;
+			}
+			if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0)
+				break;
+		}
+
+		/* Status check failed */
+		if (j >= MAX_CTL_CHECK) {
+			ql_log(ql_log_fatal, vha, 0xb0a5,
+			    "%s: MS memory write failed!\n",
+			   __func__);
+			ret_val = QLA_FUNCTION_FAILED;
+			goto exit_ms_mem_write_unlock;
+		}
+	}
+
+exit_ms_mem_write_unlock:
+	write_unlock_irqrestore(&ha->hw_lock, flags);
+
+exit_ms_mem_write:
+	return ret_val;
+}
+
+static int
+qla8044_copy_bootloader(struct scsi_qla_host *vha)
+{
+	uint8_t *p_cache;
+	uint32_t src, count, size;
+	uint64_t dest;
+	int ret_val = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	src = QLA8044_BOOTLOADER_FLASH_ADDR;
+	dest = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_ADDR);
+	size = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_SIZE);
+
+	/* 128 bit alignment check */
+	if (size & 0xF)
+		size = (size + 16) & ~0xF;
+
+	/* 16 byte count */
+	count = size/16;
+
+	p_cache = vmalloc(size);
+	if (p_cache == NULL) {
+		ql_log(ql_log_fatal, vha, 0xb0a6,
+		    "%s: Failed to allocate memory for "
+		    "boot loader cache\n", __func__);
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_copy_bootloader;
+	}
+
+	ret_val = qla8044_lockless_flash_read_u32(vha, src,
+	    p_cache, size/sizeof(uint32_t));
+	if (ret_val == QLA_FUNCTION_FAILED) {
+		ql_log(ql_log_fatal, vha, 0xb0a7,
+		    "%s: Error reading F/W from flash!!!\n", __func__);
+		goto exit_copy_error;
+	}
+	ql_dbg(ql_dbg_p3p, vha, 0xb0a8, "%s: Read F/W from flash!\n",
+	    __func__);
+
+	/* 128 bit/16 byte write to MS memory */
+	ret_val = qla8044_ms_mem_write_128b(vha, dest,
+	    (uint32_t *)p_cache, count);
+	if (ret_val == QLA_FUNCTION_FAILED) {
+		ql_log(ql_log_fatal, vha, 0xb0a9,
+		    "%s: Error writing F/W to MS !!!\n", __func__);
+		goto exit_copy_error;
+	}
+	ql_dbg(ql_dbg_p3p, vha, 0xb0aa,
+	    "%s: Wrote F/W (size %d) to MS !!!\n",
+	    __func__, size);
+
+exit_copy_error:
+	vfree(p_cache);
+
+exit_copy_bootloader:
+	return ret_val;
+}
+
+static int
+qla8044_restart(struct scsi_qla_host *vha)
+{
+	int ret_val = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	qla8044_process_stop_seq(vha);
+
+	/* Collect minidump */
+	if (ql2xmdenable)
+		qla8044_get_minidump(vha);
+	else
+		ql_log(ql_log_fatal, vha, 0xb14c,
+		    "Minidump disabled.\n");
+
+	qla8044_process_init_seq(vha);
+
+	if (qla8044_copy_bootloader(vha)) {
+		ql_log(ql_log_fatal, vha, 0xb0ab,
+		    "%s: Copy bootloader, firmware restart failed!\n",
+		    __func__);
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_restart;
+	}
+
+	/*
+	 *  Loads F/W from flash
+	 */
+	qla8044_wr_reg(ha, QLA8044_FW_IMAGE_VALID, QLA8044_BOOT_FROM_FLASH);
+
+	qla8044_process_start_seq(vha);
+
+exit_restart:
+	return ret_val;
+}
+
+/*
+ * qla8044_check_cmd_peg_status - Check peg status to see if Peg is
+ * initialized.
+ *
+ * @ha : Pointer to adapter structure
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_check_cmd_peg_status(struct scsi_qla_host *vha)
+{
+	uint32_t val, ret_val = QLA_FUNCTION_FAILED;
+	int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
+	struct qla_hw_data *ha = vha->hw;
+
+	do {
+		val = qla8044_rd_reg(ha, QLA8044_CMDPEG_STATE);
+		if (val == PHAN_INITIALIZE_COMPLETE) {
+			ql_dbg(ql_dbg_p3p, vha, 0xb0ac,
+			    "%s: Command Peg initialization "
+			    "complete! state=0x%x\n", __func__, val);
+			ret_val = QLA_SUCCESS;
+			break;
+		}
+		msleep(CRB_CMDPEG_CHECK_DELAY);
+	} while (--retries);
+
+	return ret_val;
+}
+
+static int
+qla8044_start_firmware(struct scsi_qla_host *vha)
+{
+	int ret_val = QLA_SUCCESS;
+
+	if (qla8044_restart(vha)) {
+		ql_log(ql_log_fatal, vha, 0xb0ad,
+		    "%s: Restart Error!!!, Need Reset!!!\n",
+		    __func__);
+		ret_val = QLA_FUNCTION_FAILED;
+		goto exit_start_fw;
+	} else
+		ql_dbg(ql_dbg_p3p, vha, 0xb0af,
+		    "%s: Restart done!\n", __func__);
+
+	ret_val = qla8044_check_cmd_peg_status(vha);
+	if (ret_val) {
+		ql_log(ql_log_fatal, vha, 0xb0b0,
+		    "%s: Peg not initialized!\n", __func__);
+		ret_val = QLA_FUNCTION_FAILED;
+	}
+
+exit_start_fw:
+	return ret_val;
+}
+
+void
+qla8044_clear_drv_active(struct scsi_qla_host *vha)
+{
+	uint32_t drv_active;
+	struct qla_hw_data *ha = vha->hw;
+
+	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+	drv_active &= ~(1 << (ha->portnum));
+
+	ql_log(ql_log_info, vha, 0xb0b1,
+	    "%s(%ld): drv_active: 0x%08x\n",
+	    __func__, vha->host_no, drv_active);
+
+	qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active);
+}
+
+/*
+ * qla8044_device_bootstrap - Initialize device, set DEV_READY, start fw
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static int
+qla8044_device_bootstrap(struct scsi_qla_host *vha)
+{
+	int rval = QLA_FUNCTION_FAILED;
+	int i;
+	uint32_t old_count = 0, count = 0;
+	int need_reset = 0;
+	uint32_t idc_ctrl;
+	struct qla_hw_data *ha = vha->hw;
+
+	need_reset = qla8044_need_reset(vha);
+
+	if (!need_reset) {
+		old_count = qla8044_rd_direct(vha,
+		    QLA8044_PEG_ALIVE_COUNTER_INDEX);
+
+		for (i = 0; i < 10; i++) {
+			msleep(200);
+
+			count = qla8044_rd_direct(vha,
+			    QLA8044_PEG_ALIVE_COUNTER_INDEX);
+			if (count != old_count) {
+				rval = QLA_SUCCESS;
+				goto dev_ready;
+			}
+		}
+		qla8044_flash_lock_recovery(vha);
+	} else {
+		/* We are trying to perform a recovery here. */
+		if (ha->flags.isp82xx_fw_hung)
+			qla8044_flash_lock_recovery(vha);
+	}
+
+	/* set to DEV_INITIALIZING */
+	ql_log(ql_log_info, vha, 0xb0b2,
+	    "%s: HW State: INITIALIZING\n", __func__);
+	qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+	    QLA8XXX_DEV_INITIALIZING);
+
+	qla8044_idc_unlock(ha);
+	rval = qla8044_start_firmware(vha);
+	qla8044_idc_lock(ha);
+
+	if (rval != QLA_SUCCESS) {
+		ql_log(ql_log_info, vha, 0xb0b3,
+		     "%s: HW State: FAILED\n", __func__);
+		qla8044_clear_drv_active(vha);
+		qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+		    QLA8XXX_DEV_FAILED);
+		return rval;
+	}
+
+	/* For ISP8044, If IDC_CTRL GRACEFUL_RESET_BIT1 is set , reset it after
+	 * device goes to INIT state. */
+	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+	if (idc_ctrl & GRACEFUL_RESET_BIT1) {
+		qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
+		    (idc_ctrl & ~GRACEFUL_RESET_BIT1));
+		ha->fw_dumped = 0;
+	}
+
+dev_ready:
+	ql_log(ql_log_info, vha, 0xb0b4,
+	    "%s: HW State: READY\n", __func__);
+	qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, QLA8XXX_DEV_READY);
+
+	return rval;
+}
+
+/*-------------------------Reset Sequence Functions-----------------------*/
+static void
+qla8044_dump_reset_seq_hdr(struct scsi_qla_host *vha)
+{
+	u8 *phdr;
+
+	if (!vha->reset_tmplt.buff) {
+		ql_log(ql_log_fatal, vha, 0xb0b5,
+		    "%s: Error Invalid reset_seq_template\n", __func__);
+		return;
+	}
+
+	phdr = vha->reset_tmplt.buff;
+	ql_dbg(ql_dbg_p3p, vha, 0xb0b6,
+	    "Reset Template :\n\t0x%X 0x%X 0x%X 0x%X"
+	    "0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n"
+	    "\t0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n\n",
+	    *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
+	    *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
+	    *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
+	    *(phdr+13), *(phdr+14), *(phdr+15));
+}
+
+/*
+ * qla8044_reset_seq_checksum_test - Validate Reset Sequence template.
+ *
+ * @ha : Pointer to adapter structure
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ */
+static int
+qla8044_reset_seq_checksum_test(struct scsi_qla_host *vha)
+{
+	uint32_t sum =  0;
+	uint16_t *buff = (uint16_t *)vha->reset_tmplt.buff;
+	int u16_count =  vha->reset_tmplt.hdr->size / sizeof(uint16_t);
+
+	while (u16_count-- > 0)
+		sum += *buff++;
+
+	while (sum >> 16)
+		sum = (sum & 0xFFFF) +  (sum >> 16);
+
+	/* checksum of 0 indicates a valid template */
+	if (~sum) {
+		return QLA_SUCCESS;
+	} else {
+		ql_log(ql_log_fatal, vha, 0xb0b7,
+		    "%s: Reset seq checksum failed\n", __func__);
+		return QLA_FUNCTION_FAILED;
+	}
+}
+
+/*
+ * qla8044_read_reset_template - Read Reset Template from Flash, validate
+ * the template and store offsets of stop/start/init offsets in ha->reset_tmplt.
+ *
+ * @ha : Pointer to adapter structure
+ */
+void
+qla8044_read_reset_template(struct scsi_qla_host *vha)
+{
+	uint8_t *p_buff;
+	uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
+
+	vha->reset_tmplt.seq_error = 0;
+	vha->reset_tmplt.buff = vmalloc(QLA8044_RESTART_TEMPLATE_SIZE);
+	if (vha->reset_tmplt.buff == NULL) {
+		ql_log(ql_log_fatal, vha, 0xb0b8,
+		    "%s: Failed to allocate reset template resources\n",
+		    __func__);
+		goto exit_read_reset_template;
+	}
+
+	p_buff = vha->reset_tmplt.buff;
+	addr = QLA8044_RESET_TEMPLATE_ADDR;
+
+	tmplt_hdr_def_size =
+	    sizeof(struct qla8044_reset_template_hdr) / sizeof(uint32_t);
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0b9,
+	    "%s: Read template hdr size %d from Flash\n",
+	    __func__, tmplt_hdr_def_size);
+
+	/* Copy template header from flash */
+	if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) {
+		ql_log(ql_log_fatal, vha, 0xb0ba,
+		    "%s: Failed to read reset template\n", __func__);
+		goto exit_read_template_error;
+	}
+
+	vha->reset_tmplt.hdr =
+	 (struct qla8044_reset_template_hdr *) vha->reset_tmplt.buff;
+
+	/* Validate the template header size and signature */
+	tmplt_hdr_size = vha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
+	if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
+	    (vha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
+		ql_log(ql_log_fatal, vha, 0xb0bb,
+		    "%s: Template Header size invalid %d "
+		    "tmplt_hdr_def_size %d!!!\n", __func__,
+		    tmplt_hdr_size, tmplt_hdr_def_size);
+		goto exit_read_template_error;
+	}
+
+	addr = QLA8044_RESET_TEMPLATE_ADDR + vha->reset_tmplt.hdr->hdr_size;
+	p_buff = vha->reset_tmplt.buff + vha->reset_tmplt.hdr->hdr_size;
+	tmplt_hdr_def_size = (vha->reset_tmplt.hdr->size -
+	    vha->reset_tmplt.hdr->hdr_size)/sizeof(uint32_t);
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0bc,
+	    "%s: Read rest of the template size %d\n",
+	    __func__, vha->reset_tmplt.hdr->size);
+
+	/* Copy rest of the template */
+	if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) {
+		ql_log(ql_log_fatal, vha, 0xb0bd,
+		    "%s: Failed to read reset tempelate\n", __func__);
+		goto exit_read_template_error;
+	}
+
+	/* Integrity check */
+	if (qla8044_reset_seq_checksum_test(vha)) {
+		ql_log(ql_log_fatal, vha, 0xb0be,
+		    "%s: Reset Seq checksum failed!\n", __func__);
+		goto exit_read_template_error;
+	}
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0bf,
+	    "%s: Reset Seq checksum passed! Get stop, "
+	    "start and init seq offsets\n", __func__);
+
+	/* Get STOP, START, INIT sequence offsets */
+	vha->reset_tmplt.init_offset = vha->reset_tmplt.buff +
+	    vha->reset_tmplt.hdr->init_seq_offset;
+
+	vha->reset_tmplt.start_offset = vha->reset_tmplt.buff +
+	    vha->reset_tmplt.hdr->start_seq_offset;
+
+	vha->reset_tmplt.stop_offset = vha->reset_tmplt.buff +
+	    vha->reset_tmplt.hdr->hdr_size;
+
+	qla8044_dump_reset_seq_hdr(vha);
+
+	goto exit_read_reset_template;
+
+exit_read_template_error:
+	vfree(vha->reset_tmplt.buff);
+
+exit_read_reset_template:
+	return;
+}
+
+void
+qla8044_set_idc_dontreset(struct scsi_qla_host *vha)
+{
+	uint32_t idc_ctrl;
+	struct qla_hw_data *ha = vha->hw;
+
+	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+	idc_ctrl |= DONTRESET_BIT0;
+	ql_dbg(ql_dbg_p3p, vha, 0xb0c0,
+	    "%s: idc_ctrl = %d\n", __func__, idc_ctrl);
+	qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl);
+}
+
+inline void
+qla8044_set_rst_ready(struct scsi_qla_host *vha)
+{
+	uint32_t drv_state;
+	struct qla_hw_data *ha = vha->hw;
+
+	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+
+	/* For ISP8044, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.*/
+	drv_state |= (1 << ha->portnum);
+
+	ql_log(ql_log_info, vha, 0xb0c1,
+	    "%s(%ld): drv_state: 0x%08x\n",
+	    __func__, vha->host_no, drv_state);
+	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state);
+}
+
+/**
+ * qla8044_need_reset_handler - Code to start reset sequence
+ * @ha: pointer to adapter structure
+ *
+ * Note: IDC lock must be held upon entry
+ **/
+static void
+qla8044_need_reset_handler(struct scsi_qla_host *vha)
+{
+	uint32_t dev_state = 0, drv_state, drv_active;
+	unsigned long reset_timeout, dev_init_timeout;
+	struct qla_hw_data *ha = vha->hw;
+
+	ql_log(ql_log_fatal, vha, 0xb0c2,
+	    "%s: Performing ISP error recovery\n", __func__);
+
+	if (vha->flags.online) {
+		qla8044_idc_unlock(ha);
+		qla2x00_abort_isp_cleanup(vha);
+		ha->isp_ops->get_flash_version(vha, vha->req->ring);
+		ha->isp_ops->nvram_config(vha);
+		qla8044_idc_lock(ha);
+	}
+
+	if (!ha->flags.nic_core_reset_owner) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb0c3,
+		    "%s(%ld): reset acknowledged\n",
+		    __func__, vha->host_no);
+		qla8044_set_rst_ready(vha);
+
+		/* Non-reset owners ACK Reset and wait for device INIT state
+		 * as part of Reset Recovery by Reset Owner
+		 */
+		dev_init_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
+
+		do {
+			if (time_after_eq(jiffies, dev_init_timeout)) {
+				ql_log(ql_log_info, vha, 0xb0c4,
+				    "%s: Non Reset owner DEV INIT "
+				    "TIMEOUT!\n", __func__);
+				break;
+			}
+
+			qla8044_idc_unlock(ha);
+			msleep(1000);
+			qla8044_idc_lock(ha);
+
+			dev_state = qla8044_rd_direct(vha,
+					QLA8044_CRB_DEV_STATE_INDEX);
+		} while (dev_state == QLA8XXX_DEV_NEED_RESET);
+	} else {
+		qla8044_set_rst_ready(vha);
+
+		/* wait for 10 seconds for reset ack from all functions */
+		reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
+
+		drv_state = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_STATE_INDEX);
+		drv_active = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+		ql_log(ql_log_info, vha, 0xb0c5,
+		    "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
+		    __func__, vha->host_no, drv_state, drv_active);
+
+		while (drv_state != drv_active) {
+			if (time_after_eq(jiffies, reset_timeout)) {
+				ql_log(ql_log_info, vha, 0xb0c6,
+				    "%s: RESET TIMEOUT!"
+				    "drv_state: 0x%08x, drv_active: 0x%08x\n",
+				    QLA2XXX_DRIVER_NAME, drv_state, drv_active);
+				break;
+			}
+
+			qla8044_idc_unlock(ha);
+			msleep(1000);
+			qla8044_idc_lock(ha);
+
+			drv_state = qla8044_rd_direct(vha,
+			    QLA8044_CRB_DRV_STATE_INDEX);
+			drv_active = qla8044_rd_direct(vha,
+			    QLA8044_CRB_DRV_ACTIVE_INDEX);
+		}
+
+		if (drv_state != drv_active) {
+			ql_log(ql_log_info, vha, 0xb0c7,
+			    "%s(%ld): Reset_owner turning off drv_active "
+			    "of non-acking function 0x%x\n", __func__,
+			    vha->host_no, (drv_active ^ drv_state));
+			drv_active = drv_active & drv_state;
+			qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX,
+			    drv_active);
+		}
+
+		/*
+		* Clear RESET OWNER, will be set at next reset
+		* by next RST_OWNER
+		*/
+		ha->flags.nic_core_reset_owner = 0;
+
+		/* Start Reset Recovery */
+		qla8044_device_bootstrap(vha);
+	}
+}
+
+static void
+qla8044_set_drv_active(struct scsi_qla_host *vha)
+{
+	uint32_t drv_active;
+	struct qla_hw_data *ha = vha->hw;
+
+	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+	/* For ISP8044, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.*/
+	drv_active |= (1 << ha->portnum);
+
+	ql_log(ql_log_info, vha, 0xb0c8,
+	    "%s(%ld): drv_active: 0x%08x\n",
+	    __func__, vha->host_no, drv_active);
+	qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active);
+}
+
+static void
+qla8044_clear_idc_dontreset(struct scsi_qla_host *vha)
+{
+	uint32_t idc_ctrl;
+	struct qla_hw_data *ha = vha->hw;
+
+	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+	idc_ctrl &= ~DONTRESET_BIT0;
+	ql_log(ql_log_info, vha, 0xb0c9,
+	    "%s: idc_ctrl = %d\n", __func__,
+	    idc_ctrl);
+	qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl);
+}
+
+static int
+qla8044_set_idc_ver(struct scsi_qla_host *vha)
+{
+	int idc_ver;
+	uint32_t drv_active;
+	int rval = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+	if (drv_active == (1 << ha->portnum)) {
+		idc_ver = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_IDC_VERSION_INDEX);
+		idc_ver &= (~0xFF);
+		idc_ver |= QLA8044_IDC_VER_MAJ_VALUE;
+		qla8044_wr_direct(vha, QLA8044_CRB_DRV_IDC_VERSION_INDEX,
+		    idc_ver);
+		ql_log(ql_log_info, vha, 0xb0ca,
+		    "%s: IDC version updated to %d\n",
+		    __func__, idc_ver);
+	} else {
+		idc_ver = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_IDC_VERSION_INDEX);
+		idc_ver &= 0xFF;
+		if (QLA8044_IDC_VER_MAJ_VALUE != idc_ver) {
+			ql_log(ql_log_info, vha, 0xb0cb,
+			    "%s: qla4xxx driver IDC version %d "
+			    "is not compatible with IDC version %d "
+			    "of other drivers!\n",
+			    __func__, QLA8044_IDC_VER_MAJ_VALUE,
+			    idc_ver);
+			rval = QLA_FUNCTION_FAILED;
+			goto exit_set_idc_ver;
+		}
+	}
+
+	/* Update IDC_MINOR_VERSION */
+	idc_ver = qla8044_rd_reg(ha, QLA8044_CRB_IDC_VER_MINOR);
+	idc_ver &= ~(0x03 << (ha->portnum * 2));
+	idc_ver |= (QLA8044_IDC_VER_MIN_VALUE << (ha->portnum * 2));
+	qla8044_wr_reg(ha, QLA8044_CRB_IDC_VER_MINOR, idc_ver);
+
+exit_set_idc_ver:
+	return rval;
+}
+
+static int
+qla8044_update_idc_reg(struct scsi_qla_host *vha)
+{
+	uint32_t drv_active;
+	int rval = QLA_SUCCESS;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (vha->flags.init_done)
+		goto exit_update_idc_reg;
+
+	qla8044_idc_lock(ha);
+	qla8044_set_drv_active(vha);
+
+	drv_active = qla8044_rd_direct(vha,
+	    QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+	/* If we are the first driver to load and
+	 * ql2xdontresethba is not set, clear IDC_CTRL BIT0. */
+	if ((drv_active == (1 << ha->portnum)) && !ql2xdontresethba)
+		qla8044_clear_idc_dontreset(vha);
+
+	rval = qla8044_set_idc_ver(vha);
+	if (rval == QLA_FUNCTION_FAILED)
+		qla8044_clear_drv_active(vha);
+	qla8044_idc_unlock(ha);
+
+exit_update_idc_reg:
+	return rval;
+}
+
+/**
+ * qla8044_need_qsnt_handler - Code to start qsnt
+ * @ha: pointer to adapter structure
+ **/
+static void
+qla8044_need_qsnt_handler(struct scsi_qla_host *vha)
+{
+	unsigned long qsnt_timeout;
+	uint32_t drv_state, drv_active, dev_state;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (vha->flags.online)
+		qla2x00_quiesce_io(vha);
+	else
+		return;
+
+	qla8044_set_qsnt_ready(vha);
+
+	/* Wait for 30 secs for all functions to ack qsnt mode */
+	qsnt_timeout = jiffies + (QSNT_ACK_TOV * HZ);
+	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
+
+	/* Shift drv_active by 1 to match drv_state. As quiescent ready bit
+	   position is at bit 1 and drv active is at bit 0 */
+	drv_active = drv_active << 1;
+
+	while (drv_state != drv_active) {
+		if (time_after_eq(jiffies, qsnt_timeout)) {
+			/* Other functions did not ack, changing state to
+			 * DEV_READY
+			 */
+			clear_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
+			qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+					    QLA8XXX_DEV_READY);
+			qla8044_clear_qsnt_ready(vha);
+			ql_log(ql_log_info, vha, 0xb0cc,
+			    "Timeout waiting for quiescent ack!!!\n");
+			return;
+		}
+		qla8044_idc_unlock(ha);
+		msleep(1000);
+		qla8044_idc_lock(ha);
+
+		drv_state = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_STATE_INDEX);
+		drv_active = qla8044_rd_direct(vha,
+		    QLA8044_CRB_DRV_ACTIVE_INDEX);
+		drv_active = drv_active << 1;
+	}
+
+	/* All functions have Acked. Set quiescent state */
+	dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
+	if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
+		qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+		    QLA8XXX_DEV_QUIESCENT);
+		ql_log(ql_log_info, vha, 0xb0cd,
+		    "%s: HW State: QUIESCENT\n", __func__);
+	}
+}
+
+/*
+ * qla8044_device_state_handler - Adapter state machine
+ * @ha: pointer to host adapter structure.
+ *
+ * Note: IDC lock must be UNLOCKED upon entry
+ **/
+int
+qla8044_device_state_handler(struct scsi_qla_host *vha)
+{
+	uint32_t dev_state;
+	int rval = QLA_SUCCESS;
+	unsigned long dev_init_timeout;
+	struct qla_hw_data *ha = vha->hw;
+
+	rval = qla8044_update_idc_reg(vha);
+	if (rval == QLA_FUNCTION_FAILED)
+		goto exit_error;
+
+	dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+	ql_dbg(ql_dbg_p3p, vha, 0xb0ce,
+	    "Device state is 0x%x = %s\n",
+	    dev_state, dev_state < MAX_STATES ?
+	    qdev_state(dev_state) : "Unknown");
+
+	/* wait for 30 seconds for device to go ready */
+	dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
+
+	qla8044_idc_lock(ha);
+
+	while (1) {
+		if (time_after_eq(jiffies, dev_init_timeout)) {
+			ql_log(ql_log_warn, vha, 0xb0cf,
+			    "%s: Device Init Failed 0x%x = %s\n",
+			    QLA2XXX_DRIVER_NAME, dev_state,
+			    dev_state < MAX_STATES ?
+			    qdev_state(dev_state) : "Unknown");
+
+			qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+			    QLA8XXX_DEV_FAILED);
+		}
+
+		dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+		ql_log(ql_log_info, vha, 0xb0d0,
+		    "Device state is 0x%x = %s\n",
+		    dev_state, dev_state < MAX_STATES ?
+		    qdev_state(dev_state) : "Unknown");
+
+		/* NOTE: Make sure idc unlocked upon exit of switch statement */
+		switch (dev_state) {
+		case QLA8XXX_DEV_READY:
+			ha->flags.nic_core_reset_owner = 0;
+			goto exit;
+		case QLA8XXX_DEV_COLD:
+			rval = qla8044_device_bootstrap(vha);
+			goto exit;
+		case QLA8XXX_DEV_INITIALIZING:
+			qla8044_idc_unlock(ha);
+			msleep(1000);
+			qla8044_idc_lock(ha);
+			break;
+		case QLA8XXX_DEV_NEED_RESET:
+			/* For ISP8044, if NEED_RESET is set by any driver,
+			 * it should be honored, irrespective of IDC_CTRL
+			 * DONTRESET_BIT0 */
+			qla8044_need_reset_handler(vha);
+			break;
+		case QLA8XXX_DEV_NEED_QUIESCENT:
+			/* idc locked/unlocked in handler */
+			qla8044_need_qsnt_handler(vha);
+
+			/* Reset the init timeout after qsnt handler */
+			dev_init_timeout = jiffies +
+			    (ha->fcoe_reset_timeout * HZ);
+			break;
+		case QLA8XXX_DEV_QUIESCENT:
+			ql_log(ql_log_info, vha, 0xb0d1,
+			    "HW State: QUIESCENT\n");
+
+			qla8044_idc_unlock(ha);
+			msleep(1000);
+			qla8044_idc_lock(ha);
+
+			/* Reset the init timeout after qsnt handler */
+			dev_init_timeout = jiffies +
+			    (ha->fcoe_reset_timeout * HZ);
+			break;
+		case QLA8XXX_DEV_FAILED:
+			ha->flags.nic_core_reset_owner = 0;
+			qla8044_idc_unlock(ha);
+			qla8xxx_dev_failed_handler(vha);
+			rval = QLA_FUNCTION_FAILED;
+			qla8044_idc_lock(ha);
+			goto exit;
+		default:
+			qla8044_idc_unlock(ha);
+			qla8xxx_dev_failed_handler(vha);
+			rval = QLA_FUNCTION_FAILED;
+			qla8044_idc_lock(ha);
+			goto exit;
+		}
+	}
+exit:
+	qla8044_idc_unlock(ha);
+
+exit_error:
+	return rval;
+}
+
+/**
+ * qla4_8xxx_check_temp - Check the ISP82XX temperature.
+ * @ha: adapter block pointer.
+ *
+ * Note: The caller should not hold the idc lock.
+ **/
+static int
+qla8044_check_temp(struct scsi_qla_host *vha)
+{
+	uint32_t temp, temp_state, temp_val;
+	int status = QLA_SUCCESS;
+
+	temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX);
+	temp_state = qla82xx_get_temp_state(temp);
+	temp_val = qla82xx_get_temp_val(temp);
+
+	if (temp_state == QLA82XX_TEMP_PANIC) {
+		ql_log(ql_log_warn, vha, 0xb0d2,
+		    "Device temperature %d degrees C"
+		    " exceeds maximum allowed. Hardware has been shut"
+		    " down\n", temp_val);
+		status = QLA_FUNCTION_FAILED;
+		return status;
+	} else if (temp_state == QLA82XX_TEMP_WARN) {
+		ql_log(ql_log_warn, vha, 0xb0d3,
+		    "Device temperature %d"
+		    " degrees C exceeds operating range."
+		    " Immediate action needed.\n", temp_val);
+	}
+	return 0;
+}
+
+int qla8044_read_temperature(scsi_qla_host_t *vha)
+{
+	uint32_t temp;
+
+	temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX);
+	return qla82xx_get_temp_val(temp);
+}
+
+/**
+ * qla8044_check_fw_alive  - Check firmware health
+ * @ha: Pointer to host adapter structure.
+ *
+ * Context: Interrupt
+ **/
+int
+qla8044_check_fw_alive(struct scsi_qla_host *vha)
+{
+	uint32_t fw_heartbeat_counter;
+	uint32_t halt_status1, halt_status2;
+	int status = QLA_SUCCESS;
+
+	fw_heartbeat_counter = qla8044_rd_direct(vha,
+	    QLA8044_PEG_ALIVE_COUNTER_INDEX);
+
+	/* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
+	if (fw_heartbeat_counter == 0xffffffff) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb0d4,
+		    "scsi%ld: %s: Device in frozen "
+		    "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
+		    vha->host_no, __func__);
+		return status;
+	}
+
+	if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
+		vha->seconds_since_last_heartbeat++;
+		/* FW not alive after 2 seconds */
+		if (vha->seconds_since_last_heartbeat == 2) {
+			vha->seconds_since_last_heartbeat = 0;
+			halt_status1 = qla8044_rd_direct(vha,
+			    QLA8044_PEG_HALT_STATUS1_INDEX);
+			halt_status2 = qla8044_rd_direct(vha,
+			    QLA8044_PEG_HALT_STATUS2_INDEX);
+
+			ql_log(ql_log_info, vha, 0xb0d5,
+			    "scsi(%ld): %s, ISP8044 "
+			    "Dumping hw/fw registers:\n"
+			    " PEG_HALT_STATUS1: 0x%x, "
+			    "PEG_HALT_STATUS2: 0x%x,\n",
+			    vha->host_no, __func__, halt_status1,
+			    halt_status2);
+			status = QLA_FUNCTION_FAILED;
+		}
+	} else
+		vha->seconds_since_last_heartbeat = 0;
+
+	vha->fw_heartbeat_counter = fw_heartbeat_counter;
+	return status;
+}
+
+void
+qla8044_watchdog(struct scsi_qla_host *vha)
+{
+	uint32_t dev_state, halt_status;
+	int halt_status_unrecoverable = 0;
+	struct qla_hw_data *ha = vha->hw;
+
+	/* don't poll if reset is going on or FW hang in quiescent state */
+	if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
+	    test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
+	    test_bit(ISP_ABORT_RETRY, &vha->dpc_flags) ||
+	    test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) {
+		dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
+		if (qla8044_check_temp(vha)) {
+			set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
+			ha->flags.isp82xx_fw_hung = 1;
+			qla2xxx_wake_dpc(vha);
+		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
+			   !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
+			ql_log(ql_log_info, vha, 0xb0d6,
+			    "%s: HW State: NEED RESET!\n",
+			    __func__);
+			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+			qla2xxx_wake_dpc(vha);
+		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
+		    !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
+			ql_log(ql_log_info, vha, 0xb0d7,
+			    "%s: HW State: NEED QUIES detected!\n",
+			    __func__);
+			set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
+			qla2xxx_wake_dpc(vha);
+		} else  {
+			/* Check firmware health */
+			if (qla8044_check_fw_alive(vha)) {
+				halt_status = qla8044_rd_direct(vha,
+					QLA8044_PEG_HALT_STATUS1_INDEX);
+				if (halt_status &
+				    QLA8044_HALT_STATUS_FW_RESET) {
+					ql_log(ql_log_fatal, vha,
+					    0xb0d8, "%s: Firmware "
+					    "error detected device "
+					    "is being reset\n",
+					    __func__);
+				} else if (halt_status &
+					    QLA8044_HALT_STATUS_UNRECOVERABLE) {
+						halt_status_unrecoverable = 1;
+				}
+
+				/* Since we cannot change dev_state in interrupt
+				 * context, set appropriate DPC flag then wakeup
+				 *  DPC */
+				if (halt_status_unrecoverable) {
+					set_bit(ISP_UNRECOVERABLE,
+					    &vha->dpc_flags);
+				} else {
+					if (dev_state ==
+					    QLA8XXX_DEV_QUIESCENT) {
+						set_bit(FCOE_CTX_RESET_NEEDED,
+						    &vha->dpc_flags);
+						ql_log(ql_log_info, vha, 0xb0d9,
+						    "%s: FW CONTEXT Reset "
+						    "needed!\n", __func__);
+					} else {
+						ql_log(ql_log_info, vha,
+						    0xb0da, "%s: "
+						    "detect abort needed\n",
+						    __func__);
+						set_bit(ISP_ABORT_NEEDED,
+						    &vha->dpc_flags);
+						qla82xx_clear_pending_mbx(vha);
+					}
+				}
+				ha->flags.isp82xx_fw_hung = 1;
+				ql_log(ql_log_warn, vha, 0xb10a,
+				    "Firmware hung.\n");
+				qla2xxx_wake_dpc(vha);
+			}
+		}
+
+	}
+}
+
+static int
+qla8044_minidump_process_control(struct scsi_qla_host *vha,
+				 struct qla8044_minidump_entry_hdr *entry_hdr)
+{
+	struct qla8044_minidump_entry_crb *crb_entry;
+	uint32_t read_value, opcode, poll_time, addr, index;
+	uint32_t crb_addr, rval = QLA_SUCCESS;
+	unsigned long wtime;
+	struct qla8044_minidump_template_hdr *tmplt_hdr;
+	int i;
+	struct qla_hw_data *ha = vha->hw;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0dd, "Entering fn: %s\n", __func__);
+	tmplt_hdr = (struct qla8044_minidump_template_hdr *)
+		ha->md_tmplt_hdr;
+	crb_entry = (struct qla8044_minidump_entry_crb *)entry_hdr;
+
+	crb_addr = crb_entry->addr;
+	for (i = 0; i < crb_entry->op_count; i++) {
+		opcode = crb_entry->crb_ctrl.opcode;
+
+		if (opcode & QLA82XX_DBG_OPCODE_WR) {
+			qla8044_wr_reg_indirect(vha, crb_addr,
+			    crb_entry->value_1);
+			opcode &= ~QLA82XX_DBG_OPCODE_WR;
+		}
+
+		if (opcode & QLA82XX_DBG_OPCODE_RW) {
+			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+			qla8044_wr_reg_indirect(vha, crb_addr, read_value);
+			opcode &= ~QLA82XX_DBG_OPCODE_RW;
+		}
+
+		if (opcode & QLA82XX_DBG_OPCODE_AND) {
+			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+			read_value &= crb_entry->value_2;
+			opcode &= ~QLA82XX_DBG_OPCODE_AND;
+			if (opcode & QLA82XX_DBG_OPCODE_OR) {
+				read_value |= crb_entry->value_3;
+				opcode &= ~QLA82XX_DBG_OPCODE_OR;
+			}
+			qla8044_wr_reg_indirect(vha, crb_addr, read_value);
+		}
+		if (opcode & QLA82XX_DBG_OPCODE_OR) {
+			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+			read_value |= crb_entry->value_3;
+			qla8044_wr_reg_indirect(vha, crb_addr, read_value);
+			opcode &= ~QLA82XX_DBG_OPCODE_OR;
+		}
+		if (opcode & QLA82XX_DBG_OPCODE_POLL) {
+			poll_time = crb_entry->crb_strd.poll_timeout;
+			wtime = jiffies + poll_time;
+			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
+
+			do {
+				if ((read_value & crb_entry->value_2) ==
+				    crb_entry->value_1) {
+					break;
+				} else if (time_after_eq(jiffies, wtime)) {
+					/* capturing dump failed */
+					rval = QLA_FUNCTION_FAILED;
+					break;
+				} else {
+					qla8044_rd_reg_indirect(vha,
+					    crb_addr, &read_value);
+				}
+			} while (1);
+			opcode &= ~QLA82XX_DBG_OPCODE_POLL;
+		}
+
+		if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) {
+			if (crb_entry->crb_strd.state_index_a) {
+				index = crb_entry->crb_strd.state_index_a;
+				addr = tmplt_hdr->saved_state_array[index];
+			} else {
+				addr = crb_addr;
+			}
+
+			qla8044_rd_reg_indirect(vha, addr, &read_value);
+			index = crb_entry->crb_ctrl.state_index_v;
+			tmplt_hdr->saved_state_array[index] = read_value;
+			opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE;
+		}
+
+		if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) {
+			if (crb_entry->crb_strd.state_index_a) {
+				index = crb_entry->crb_strd.state_index_a;
+				addr = tmplt_hdr->saved_state_array[index];
+			} else {
+				addr = crb_addr;
+			}
+
+			if (crb_entry->crb_ctrl.state_index_v) {
+				index = crb_entry->crb_ctrl.state_index_v;
+				read_value =
+				    tmplt_hdr->saved_state_array[index];
+			} else {
+				read_value = crb_entry->value_1;
+			}
+
+			qla8044_wr_reg_indirect(vha, addr, read_value);
+			opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE;
+		}
+
+		if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) {
+			index = crb_entry->crb_ctrl.state_index_v;
+			read_value = tmplt_hdr->saved_state_array[index];
+			read_value <<= crb_entry->crb_ctrl.shl;
+			read_value >>= crb_entry->crb_ctrl.shr;
+			if (crb_entry->value_2)
+				read_value &= crb_entry->value_2;
+			read_value |= crb_entry->value_3;
+			read_value += crb_entry->value_1;
+			tmplt_hdr->saved_state_array[index] = read_value;
+			opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE;
+		}
+		crb_addr += crb_entry->crb_strd.addr_stride;
+	}
+	return rval;
+}
+
+static void
+qla8044_minidump_process_rdcrb(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
+	struct qla8044_minidump_entry_crb *crb_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0de, "Entering fn: %s\n", __func__);
+	crb_hdr = (struct qla8044_minidump_entry_crb *)entry_hdr;
+	r_addr = crb_hdr->addr;
+	r_stride = crb_hdr->crb_strd.addr_stride;
+	loop_cnt = crb_hdr->op_count;
+
+	for (i = 0; i < loop_cnt; i++) {
+		qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+		*data_ptr++ = r_addr;
+		*data_ptr++ = r_value;
+		r_addr += r_stride;
+	}
+	*d_ptr = data_ptr;
+}
+
+static int
+qla8044_minidump_process_rdmem(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	uint32_t r_addr, r_value, r_data;
+	uint32_t i, j, loop_cnt;
+	struct qla8044_minidump_entry_rdmem *m_hdr;
+	unsigned long flags;
+	uint32_t *data_ptr = *d_ptr;
+	struct qla_hw_data *ha = vha->hw;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0df, "Entering fn: %s\n", __func__);
+	m_hdr = (struct qla8044_minidump_entry_rdmem *)entry_hdr;
+	r_addr = m_hdr->read_addr;
+	loop_cnt = m_hdr->read_data_size/16;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0f0,
+	    "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n",
+	    __func__, r_addr, m_hdr->read_data_size);
+
+	if (r_addr & 0xf) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb0f1,
+		    "[%s]: Read addr 0x%x not 16 bytes alligned\n",
+		    __func__, r_addr);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	if (m_hdr->read_data_size % 16) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb0f2,
+		    "[%s]: Read data[0x%x] not multiple of 16 bytes\n",
+		    __func__, m_hdr->read_data_size);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0f3,
+	    "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n",
+	    __func__, r_addr, m_hdr->read_data_size, loop_cnt);
+
+	write_lock_irqsave(&ha->hw_lock, flags);
+	for (i = 0; i < loop_cnt; i++) {
+		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_LO, r_addr);
+		r_value = 0;
+		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, r_value);
+		r_value = MIU_TA_CTL_ENABLE;
+		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value);
+		r_value = MIU_TA_CTL_START_ENABLE;
+		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value);
+
+		for (j = 0; j < MAX_CTL_CHECK; j++) {
+			qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
+			    &r_value);
+			if ((r_value & MIU_TA_CTL_BUSY) == 0)
+				break;
+		}
+
+		if (j >= MAX_CTL_CHECK) {
+			printk_ratelimited(KERN_ERR
+			    "%s: failed to read through agent\n", __func__);
+			write_unlock_irqrestore(&ha->hw_lock, flags);
+			return QLA_SUCCESS;
+		}
+
+		for (j = 0; j < 4; j++) {
+			qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_RDDATA[j],
+			    &r_data);
+			*data_ptr++ = r_data;
+		}
+
+		r_addr += 16;
+	}
+	write_unlock_irqrestore(&ha->hw_lock, flags);
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0f4,
+	    "Leaving fn: %s datacount: 0x%x\n",
+	     __func__, (loop_cnt * 16));
+
+	*d_ptr = data_ptr;
+	return QLA_SUCCESS;
+}
+
+/* ISP83xx flash read for _RDROM _BOARD */
+static uint32_t
+qla8044_minidump_process_rdrom(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	uint32_t fl_addr, u32_count, rval;
+	struct qla8044_minidump_entry_rdrom *rom_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	rom_hdr = (struct qla8044_minidump_entry_rdrom *)entry_hdr;
+	fl_addr = rom_hdr->read_addr;
+	u32_count = (rom_hdr->read_data_size)/sizeof(uint32_t);
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0f5, "[%s]: fl_addr: 0x%x, count: 0x%x\n",
+	    __func__, fl_addr, u32_count);
+
+	rval = qla8044_lockless_flash_read_u32(vha, fl_addr,
+	    (u8 *)(data_ptr), u32_count);
+
+	if (rval != QLA_SUCCESS) {
+		ql_log(ql_log_fatal, vha, 0xb0f6,
+		    "%s: Flash Read Error,Count=%d\n", __func__, u32_count);
+		return QLA_FUNCTION_FAILED;
+	} else {
+		data_ptr += u32_count;
+		*d_ptr = data_ptr;
+		return QLA_SUCCESS;
+	}
+}
+
+static void
+qla8044_mark_entry_skipped(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, int index)
+{
+	entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG;
+
+	ql_log(ql_log_info, vha, 0xb0f7,
+	    "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n",
+	    vha->host_no, index, entry_hdr->entry_type,
+	    entry_hdr->d_ctrl.entry_capture_mask);
+}
+
+static int
+qla8044_minidump_process_l2tag(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr,
+				 uint32_t **d_ptr)
+{
+	uint32_t addr, r_addr, c_addr, t_r_addr;
+	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
+	unsigned long p_wait, w_time, p_mask;
+	uint32_t c_value_w, c_value_r;
+	struct qla8044_minidump_entry_cache *cache_hdr;
+	int rval = QLA_FUNCTION_FAILED;
+	uint32_t *data_ptr = *d_ptr;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0f8, "Entering fn: %s\n", __func__);
+	cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr;
+
+	loop_count = cache_hdr->op_count;
+	r_addr = cache_hdr->read_addr;
+	c_addr = cache_hdr->control_addr;
+	c_value_w = cache_hdr->cache_ctrl.write_value;
+
+	t_r_addr = cache_hdr->tag_reg_addr;
+	t_value = cache_hdr->addr_ctrl.init_tag_value;
+	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
+	p_wait = cache_hdr->cache_ctrl.poll_wait;
+	p_mask = cache_hdr->cache_ctrl.poll_mask;
+
+	for (i = 0; i < loop_count; i++) {
+		qla8044_wr_reg_indirect(vha, t_r_addr, t_value);
+		if (c_value_w)
+			qla8044_wr_reg_indirect(vha, c_addr, c_value_w);
+
+		if (p_mask) {
+			w_time = jiffies + p_wait;
+			do {
+				qla8044_rd_reg_indirect(vha, c_addr,
+				    &c_value_r);
+				if ((c_value_r & p_mask) == 0) {
+					break;
+				} else if (time_after_eq(jiffies, w_time)) {
+					/* capturing dump failed */
+					return rval;
+				}
+			} while (1);
+		}
+
+		addr = r_addr;
+		for (k = 0; k < r_cnt; k++) {
+			qla8044_rd_reg_indirect(vha, addr, &r_value);
+			*data_ptr++ = r_value;
+			addr += cache_hdr->read_ctrl.read_addr_stride;
+		}
+		t_value += cache_hdr->addr_ctrl.tag_value_stride;
+	}
+	*d_ptr = data_ptr;
+	return QLA_SUCCESS;
+}
+
+static void
+qla8044_minidump_process_l1cache(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	uint32_t addr, r_addr, c_addr, t_r_addr;
+	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
+	uint32_t c_value_w;
+	struct qla8044_minidump_entry_cache *cache_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr;
+	loop_count = cache_hdr->op_count;
+	r_addr = cache_hdr->read_addr;
+	c_addr = cache_hdr->control_addr;
+	c_value_w = cache_hdr->cache_ctrl.write_value;
+
+	t_r_addr = cache_hdr->tag_reg_addr;
+	t_value = cache_hdr->addr_ctrl.init_tag_value;
+	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
+
+	for (i = 0; i < loop_count; i++) {
+		qla8044_wr_reg_indirect(vha, t_r_addr, t_value);
+		qla8044_wr_reg_indirect(vha, c_addr, c_value_w);
+		addr = r_addr;
+		for (k = 0; k < r_cnt; k++) {
+			qla8044_rd_reg_indirect(vha, addr, &r_value);
+			*data_ptr++ = r_value;
+			addr += cache_hdr->read_ctrl.read_addr_stride;
+		}
+		t_value += cache_hdr->addr_ctrl.tag_value_stride;
+	}
+	*d_ptr = data_ptr;
+}
+
+static void
+qla8044_minidump_process_rdocm(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
+	struct qla8044_minidump_entry_rdocm *ocm_hdr;
+	uint32_t *data_ptr = *d_ptr;
+	struct qla_hw_data *ha = vha->hw;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0f9, "Entering fn: %s\n", __func__);
+
+	ocm_hdr = (struct qla8044_minidump_entry_rdocm *)entry_hdr;
+	r_addr = ocm_hdr->read_addr;
+	r_stride = ocm_hdr->read_addr_stride;
+	loop_cnt = ocm_hdr->op_count;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0fa,
+	    "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n",
+	    __func__, r_addr, r_stride, loop_cnt);
+
+	for (i = 0; i < loop_cnt; i++) {
+		r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase));
+		*data_ptr++ = r_value;
+		r_addr += r_stride;
+	}
+	ql_dbg(ql_dbg_p3p, vha, 0xb0fb, "Leaving fn: %s datacount: 0x%lx\n",
+	    __func__, (long unsigned int) (loop_cnt * sizeof(uint32_t)));
+
+	*d_ptr = data_ptr;
+}
+
+static void
+qla8044_minidump_process_rdmux(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr,
+	uint32_t **d_ptr)
+{
+	uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value;
+	struct qla8044_minidump_entry_mux *mux_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0fc, "Entering fn: %s\n", __func__);
+
+	mux_hdr = (struct qla8044_minidump_entry_mux *)entry_hdr;
+	r_addr = mux_hdr->read_addr;
+	s_addr = mux_hdr->select_addr;
+	s_stride = mux_hdr->select_value_stride;
+	s_value = mux_hdr->select_value;
+	loop_cnt = mux_hdr->op_count;
+
+	for (i = 0; i < loop_cnt; i++) {
+		qla8044_wr_reg_indirect(vha, s_addr, s_value);
+		qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+		*data_ptr++ = s_value;
+		*data_ptr++ = r_value;
+		s_value += s_stride;
+	}
+	*d_ptr = data_ptr;
+}
+
+static void
+qla8044_minidump_process_queue(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr,
+	uint32_t **d_ptr)
+{
+	uint32_t s_addr, r_addr;
+	uint32_t r_stride, r_value, r_cnt, qid = 0;
+	uint32_t i, k, loop_cnt;
+	struct qla8044_minidump_entry_queue *q_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb0fd, "Entering fn: %s\n", __func__);
+	q_hdr = (struct qla8044_minidump_entry_queue *)entry_hdr;
+	s_addr = q_hdr->select_addr;
+	r_cnt = q_hdr->rd_strd.read_addr_cnt;
+	r_stride = q_hdr->rd_strd.read_addr_stride;
+	loop_cnt = q_hdr->op_count;
+
+	for (i = 0; i < loop_cnt; i++) {
+		qla8044_wr_reg_indirect(vha, s_addr, qid);
+		r_addr = q_hdr->read_addr;
+		for (k = 0; k < r_cnt; k++) {
+			qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+			*data_ptr++ = r_value;
+			r_addr += r_stride;
+		}
+		qid += q_hdr->q_strd.queue_id_stride;
+	}
+	*d_ptr = data_ptr;
+}
+
+/* ISP83xx functions to process new minidump entries... */
+static uint32_t
+qla8044_minidump_process_pollrd(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr,
+	uint32_t **d_ptr)
+{
+	uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask;
+	uint16_t s_stride, i;
+	struct qla8044_minidump_entry_pollrd *pollrd_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	pollrd_hdr = (struct qla8044_minidump_entry_pollrd *) entry_hdr;
+	s_addr = pollrd_hdr->select_addr;
+	r_addr = pollrd_hdr->read_addr;
+	s_value = pollrd_hdr->select_value;
+	s_stride = pollrd_hdr->select_value_stride;
+
+	poll_wait = pollrd_hdr->poll_wait;
+	poll_mask = pollrd_hdr->poll_mask;
+
+	for (i = 0; i < pollrd_hdr->op_count; i++) {
+		qla8044_wr_reg_indirect(vha, s_addr, s_value);
+		poll_wait = pollrd_hdr->poll_wait;
+		while (1) {
+			qla8044_rd_reg_indirect(vha, s_addr, &r_value);
+			if ((r_value & poll_mask) != 0) {
+				break;
+			} else {
+				usleep_range(1000, 1100);
+				if (--poll_wait == 0) {
+					ql_log(ql_log_fatal, vha, 0xb0fe,
+					    "%s: TIMEOUT\n", __func__);
+					goto error;
+				}
+			}
+		}
+		qla8044_rd_reg_indirect(vha, r_addr, &r_value);
+		*data_ptr++ = s_value;
+		*data_ptr++ = r_value;
+
+		s_value += s_stride;
+	}
+	*d_ptr = data_ptr;
+	return QLA_SUCCESS;
+
+error:
+	return QLA_FUNCTION_FAILED;
+}
+
+static void
+qla8044_minidump_process_rdmux2(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	uint32_t sel_val1, sel_val2, t_sel_val, data, i;
+	uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr;
+	struct qla8044_minidump_entry_rdmux2 *rdmux2_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	rdmux2_hdr = (struct qla8044_minidump_entry_rdmux2 *) entry_hdr;
+	sel_val1 = rdmux2_hdr->select_value_1;
+	sel_val2 = rdmux2_hdr->select_value_2;
+	sel_addr1 = rdmux2_hdr->select_addr_1;
+	sel_addr2 = rdmux2_hdr->select_addr_2;
+	sel_val_mask = rdmux2_hdr->select_value_mask;
+	read_addr = rdmux2_hdr->read_addr;
+
+	for (i = 0; i < rdmux2_hdr->op_count; i++) {
+		qla8044_wr_reg_indirect(vha, sel_addr1, sel_val1);
+		t_sel_val = sel_val1 & sel_val_mask;
+		*data_ptr++ = t_sel_val;
+
+		qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val);
+		qla8044_rd_reg_indirect(vha, read_addr, &data);
+
+		*data_ptr++ = data;
+
+		qla8044_wr_reg_indirect(vha, sel_addr1, sel_val2);
+		t_sel_val = sel_val2 & sel_val_mask;
+		*data_ptr++ = t_sel_val;
+
+		qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val);
+		qla8044_rd_reg_indirect(vha, read_addr, &data);
+
+		*data_ptr++ = data;
+
+		sel_val1 += rdmux2_hdr->select_value_stride;
+		sel_val2 += rdmux2_hdr->select_value_stride;
+	}
+
+	*d_ptr = data_ptr;
+}
+
+static uint32_t
+qla8044_minidump_process_pollrdmwr(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr,
+	uint32_t **d_ptr)
+{
+	uint32_t poll_wait, poll_mask, r_value, data;
+	uint32_t addr_1, addr_2, value_1, value_2;
+	struct qla8044_minidump_entry_pollrdmwr *poll_hdr;
+	uint32_t *data_ptr = *d_ptr;
+
+	poll_hdr = (struct qla8044_minidump_entry_pollrdmwr *) entry_hdr;
+	addr_1 = poll_hdr->addr_1;
+	addr_2 = poll_hdr->addr_2;
+	value_1 = poll_hdr->value_1;
+	value_2 = poll_hdr->value_2;
+	poll_mask = poll_hdr->poll_mask;
+
+	qla8044_wr_reg_indirect(vha, addr_1, value_1);
+
+	poll_wait = poll_hdr->poll_wait;
+	while (1) {
+		qla8044_rd_reg_indirect(vha, addr_1, &r_value);
+
+		if ((r_value & poll_mask) != 0) {
+			break;
+		} else {
+			usleep_range(1000, 1100);
+			if (--poll_wait == 0) {
+				ql_log(ql_log_fatal, vha, 0xb0ff,
+				    "%s: TIMEOUT\n", __func__);
+				goto error;
+			}
+		}
+	}
+
+	qla8044_rd_reg_indirect(vha, addr_2, &data);
+	data &= poll_hdr->modify_mask;
+	qla8044_wr_reg_indirect(vha, addr_2, data);
+	qla8044_wr_reg_indirect(vha, addr_1, value_2);
+
+	poll_wait = poll_hdr->poll_wait;
+	while (1) {
+		qla8044_rd_reg_indirect(vha, addr_1, &r_value);
+
+		if ((r_value & poll_mask) != 0) {
+			break;
+		} else {
+			usleep_range(1000, 1100);
+			if (--poll_wait == 0) {
+				ql_log(ql_log_fatal, vha, 0xb100,
+				    "%s: TIMEOUT2\n", __func__);
+				goto error;
+			}
+		}
+	}
+
+	*data_ptr++ = addr_2;
+	*data_ptr++ = data;
+
+	*d_ptr = data_ptr;
+
+	return QLA_SUCCESS;
+
+error:
+	return QLA_FUNCTION_FAILED;
+}
+
+#define ISP8044_PEX_DMA_ENGINE_INDEX		8
+#define ISP8044_PEX_DMA_BASE_ADDRESS		0x77320000
+#define ISP8044_PEX_DMA_NUM_OFFSET		0x10000
+#define ISP8044_PEX_DMA_CMD_ADDR_LOW		0x0
+#define ISP8044_PEX_DMA_CMD_ADDR_HIGH		0x04
+#define ISP8044_PEX_DMA_CMD_STS_AND_CNTRL	0x08
+
+#define ISP8044_PEX_DMA_READ_SIZE	(16 * 1024)
+#define ISP8044_PEX_DMA_MAX_WAIT	(100 * 100) /* Max wait of 100 msecs */
+
+static int
+qla8044_check_dma_engine_state(struct scsi_qla_host *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+	int rval = QLA_SUCCESS;
+	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+	uint64_t dma_base_addr = 0;
+	struct qla8044_minidump_template_hdr *tmplt_hdr = NULL;
+
+	tmplt_hdr = ha->md_tmplt_hdr;
+	dma_eng_num =
+	    tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX];
+	dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS +
+		(dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET);
+
+	/* Read the pex-dma's command-status-and-control register. */
+	rval = qla8044_rd_reg_indirect(vha,
+	    (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL),
+	    &cmd_sts_and_cntrl);
+	if (rval)
+		return QLA_FUNCTION_FAILED;
+
+	/* Check if requested pex-dma engine is available. */
+	if (cmd_sts_and_cntrl & BIT_31)
+		return QLA_SUCCESS;
+
+	return QLA_FUNCTION_FAILED;
+}
+
+static int
+qla8044_start_pex_dma(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr)
+{
+	struct qla_hw_data *ha = vha->hw;
+	int rval = QLA_SUCCESS, wait = 0;
+	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+	uint64_t dma_base_addr = 0;
+	struct qla8044_minidump_template_hdr *tmplt_hdr = NULL;
+
+	tmplt_hdr = ha->md_tmplt_hdr;
+	dma_eng_num =
+	    tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX];
+	dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS +
+		(dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET);
+
+	rval = qla8044_wr_reg_indirect(vha,
+	    dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_LOW,
+	    m_hdr->desc_card_addr);
+	if (rval)
+		goto error_exit;
+
+	rval = qla8044_wr_reg_indirect(vha,
+	    dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_HIGH, 0);
+	if (rval)
+		goto error_exit;
+
+	rval = qla8044_wr_reg_indirect(vha,
+	    dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL,
+	    m_hdr->start_dma_cmd);
+	if (rval)
+		goto error_exit;
+
+	/* Wait for dma operation to complete. */
+	for (wait = 0; wait < ISP8044_PEX_DMA_MAX_WAIT; wait++) {
+		rval = qla8044_rd_reg_indirect(vha,
+		    (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL),
+		    &cmd_sts_and_cntrl);
+		if (rval)
+			goto error_exit;
+
+		if ((cmd_sts_and_cntrl & BIT_1) == 0)
+			break;
+
+		udelay(10);
+	}
+
+	/* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
+	if (wait >= ISP8044_PEX_DMA_MAX_WAIT) {
+		rval = QLA_FUNCTION_FAILED;
+		goto error_exit;
+	}
+
+error_exit:
+	return rval;
+}
+
+static int
+qla8044_minidump_pex_dma_read(struct scsi_qla_host *vha,
+	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
+{
+	struct qla_hw_data *ha = vha->hw;
+	int rval = QLA_SUCCESS;
+	struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
+	uint32_t chunk_size, read_size;
+	uint8_t *data_ptr = (uint8_t *)*d_ptr;
+	void *rdmem_buffer = NULL;
+	dma_addr_t rdmem_dma;
+	struct qla8044_pex_dma_descriptor dma_desc;
+
+	rval = qla8044_check_dma_engine_state(vha);
+	if (rval != QLA_SUCCESS) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb147,
+		    "DMA engine not available. Fallback to rdmem-read.\n");
+		return QLA_FUNCTION_FAILED;
+	}
+
+	m_hdr = (void *)entry_hdr;
+
+	rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
+	    ISP8044_PEX_DMA_READ_SIZE, &rdmem_dma, GFP_KERNEL);
+	if (!rdmem_buffer) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb148,
+		    "Unable to allocate rdmem dma buffer\n");
+		return QLA_FUNCTION_FAILED;
+	}
+
+	/* Prepare pex-dma descriptor to be written to MS memory. */
+	/* dma-desc-cmd layout:
+	 *		0-3: dma-desc-cmd 0-3
+	 *		4-7: pcid function number
+	 *		8-15: dma-desc-cmd 8-15
+	 * dma_bus_addr: dma buffer address
+	 * cmd.read_data_size: amount of data-chunk to be read.
+	 */
+	dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
+	dma_desc.cmd.dma_desc_cmd |=
+	    ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
+
+	dma_desc.dma_bus_addr = rdmem_dma;
+	dma_desc.cmd.read_data_size = chunk_size = ISP8044_PEX_DMA_READ_SIZE;
+	read_size = 0;
+
+	/*
+	 * Perform rdmem operation using pex-dma.
+	 * Prepare dma in chunks of ISP8044_PEX_DMA_READ_SIZE.
+	 */
+	while (read_size < m_hdr->read_data_size) {
+		if (m_hdr->read_data_size - read_size <
+		    ISP8044_PEX_DMA_READ_SIZE) {
+			chunk_size = (m_hdr->read_data_size - read_size);
+			dma_desc.cmd.read_data_size = chunk_size;
+		}
+
+		dma_desc.src_addr = m_hdr->read_addr + read_size;
+
+		/* Prepare: Write pex-dma descriptor to MS memory. */
+		rval = qla8044_ms_mem_write_128b(vha,
+		    m_hdr->desc_card_addr, (void *)&dma_desc,
+		    (sizeof(struct qla8044_pex_dma_descriptor)/16));
+		if (rval) {
+			ql_log(ql_log_warn, vha, 0xb14a,
+			    "%s: Error writing rdmem-dma-init to MS !!!\n",
+			    __func__);
+			goto error_exit;
+		}
+		ql_dbg(ql_dbg_p3p, vha, 0xb14b,
+		    "%s: Dma-descriptor: Instruct for rdmem dma "
+		    "(chunk_size 0x%x).\n", __func__, chunk_size);
+
+		/* Execute: Start pex-dma operation. */
+		rval = qla8044_start_pex_dma(vha, m_hdr);
+		if (rval)
+			goto error_exit;
+
+		memcpy(data_ptr, rdmem_buffer, chunk_size);
+		data_ptr += chunk_size;
+		read_size += chunk_size;
+	}
+
+	*d_ptr = (void *)data_ptr;
+
+error_exit:
+	if (rdmem_buffer)
+		dma_free_coherent(&ha->pdev->dev, ISP8044_PEX_DMA_READ_SIZE,
+		    rdmem_buffer, rdmem_dma);
+
+	return rval;
+}
+
+/*
+ *
+ * qla8044_collect_md_data - Retrieve firmware minidump data.
+ * @ha: pointer to adapter structure
+ **/
+int
+qla8044_collect_md_data(struct scsi_qla_host *vha)
+{
+	int num_entry_hdr = 0;
+	struct qla8044_minidump_entry_hdr *entry_hdr;
+	struct qla8044_minidump_template_hdr *tmplt_hdr;
+	uint32_t *data_ptr;
+	uint32_t data_collected = 0, f_capture_mask;
+	int i, rval = QLA_FUNCTION_FAILED;
+	uint64_t now;
+	uint32_t timestamp, idc_control;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!ha->md_dump) {
+		ql_log(ql_log_info, vha, 0xb101,
+		    "%s(%ld) No buffer to dump\n",
+		    __func__, vha->host_no);
+		return rval;
+	}
+
+	if (ha->fw_dumped) {
+		ql_log(ql_log_warn, vha, 0xb10d,
+		    "Firmware has been previously dumped (%p) "
+		    "-- ignoring request.\n", ha->fw_dump);
+		goto md_failed;
+	}
+
+	ha->fw_dumped = 0;
+
+	if (!ha->md_tmplt_hdr || !ha->md_dump) {
+		ql_log(ql_log_warn, vha, 0xb10e,
+		    "Memory not allocated for minidump capture\n");
+		goto md_failed;
+	}
+
+	qla8044_idc_lock(ha);
+	idc_control = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+	if (idc_control & GRACEFUL_RESET_BIT1) {
+		ql_log(ql_log_warn, vha, 0xb112,
+		    "Forced reset from application, "
+		    "ignore minidump capture\n");
+		qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
+		    (idc_control & ~GRACEFUL_RESET_BIT1));
+		qla8044_idc_unlock(ha);
+
+		goto md_failed;
+	}
+	qla8044_idc_unlock(ha);
+
+	if (qla82xx_validate_template_chksum(vha)) {
+		ql_log(ql_log_info, vha, 0xb109,
+		    "Template checksum validation error\n");
+		goto md_failed;
+	}
+
+	tmplt_hdr = (struct qla8044_minidump_template_hdr *)
+		ha->md_tmplt_hdr;
+	data_ptr = (uint32_t *)((uint8_t *)ha->md_dump);
+	num_entry_hdr = tmplt_hdr->num_of_entries;
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb11a,
+	    "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level);
+
+	f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF;
+
+	/* Validate whether required debug level is set */
+	if ((f_capture_mask & 0x3) != 0x3) {
+		ql_log(ql_log_warn, vha, 0xb10f,
+		    "Minimum required capture mask[0x%x] level not set\n",
+		    f_capture_mask);
+
+	}
+	tmplt_hdr->driver_capture_mask = ql2xmdcapmask;
+	ql_log(ql_log_info, vha, 0xb102,
+	    "[%s]: starting data ptr: %p\n",
+	   __func__, data_ptr);
+	ql_log(ql_log_info, vha, 0xb10b,
+	   "[%s]: no of entry headers in Template: 0x%x\n",
+	   __func__, num_entry_hdr);
+	ql_log(ql_log_info, vha, 0xb10c,
+	    "[%s]: Total_data_size 0x%x, %d obtained\n",
+	   __func__, ha->md_dump_size, ha->md_dump_size);
+
+	/* Update current timestamp before taking dump */
+	now = get_jiffies_64();
+	timestamp = (u32)(jiffies_to_msecs(now) / 1000);
+	tmplt_hdr->driver_timestamp = timestamp;
+
+	entry_hdr = (struct qla8044_minidump_entry_hdr *)
+		(((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset);
+	tmplt_hdr->saved_state_array[QLA8044_SS_OCM_WNDREG_INDEX] =
+	    tmplt_hdr->ocm_window_reg[ha->portnum];
+
+	/* Walk through the entry headers - validate/perform required action */
+	for (i = 0; i < num_entry_hdr; i++) {
+		if (data_collected > ha->md_dump_size) {
+			ql_log(ql_log_info, vha, 0xb103,
+			    "Data collected: [0x%x], "
+			    "Total Dump size: [0x%x]\n",
+			    data_collected, ha->md_dump_size);
+			return rval;
+		}
+
+		if (!(entry_hdr->d_ctrl.entry_capture_mask &
+		      ql2xmdcapmask)) {
+			entry_hdr->d_ctrl.driver_flags |=
+			    QLA82XX_DBG_SKIPPED_FLAG;
+			goto skip_nxt_entry;
+		}
+
+		ql_dbg(ql_dbg_p3p, vha, 0xb104,
+		    "Data collected: [0x%x], Dump size left:[0x%x]\n",
+		    data_collected,
+		    (ha->md_dump_size - data_collected));
+
+		/* Decode the entry type and take required action to capture
+		 * debug data
+		 */
+		switch (entry_hdr->entry_type) {
+		case QLA82XX_RDEND:
+			qla8044_mark_entry_skipped(vha, entry_hdr, i);
+			break;
+		case QLA82XX_CNTRL:
+			rval = qla8044_minidump_process_control(vha,
+			    entry_hdr);
+			if (rval != QLA_SUCCESS) {
+				qla8044_mark_entry_skipped(vha, entry_hdr, i);
+				goto md_failed;
+			}
+			break;
+		case QLA82XX_RDCRB:
+			qla8044_minidump_process_rdcrb(vha,
+			    entry_hdr, &data_ptr);
+			break;
+		case QLA82XX_RDMEM:
+			rval = qla8044_minidump_pex_dma_read(vha,
+			    entry_hdr, &data_ptr);
+			if (rval != QLA_SUCCESS) {
+				rval = qla8044_minidump_process_rdmem(vha,
+				    entry_hdr, &data_ptr);
+				if (rval != QLA_SUCCESS) {
+					qla8044_mark_entry_skipped(vha,
+					    entry_hdr, i);
+					goto md_failed;
+				}
+			}
+			break;
+		case QLA82XX_BOARD:
+		case QLA82XX_RDROM:
+			rval = qla8044_minidump_process_rdrom(vha,
+			    entry_hdr, &data_ptr);
+			if (rval != QLA_SUCCESS) {
+				qla8044_mark_entry_skipped(vha,
+				    entry_hdr, i);
+			}
+			break;
+		case QLA82XX_L2DTG:
+		case QLA82XX_L2ITG:
+		case QLA82XX_L2DAT:
+		case QLA82XX_L2INS:
+			rval = qla8044_minidump_process_l2tag(vha,
+			    entry_hdr, &data_ptr);
+			if (rval != QLA_SUCCESS) {
+				qla8044_mark_entry_skipped(vha, entry_hdr, i);
+				goto md_failed;
+			}
+			break;
+		case QLA8044_L1DTG:
+		case QLA8044_L1ITG:
+		case QLA82XX_L1DAT:
+		case QLA82XX_L1INS:
+			qla8044_minidump_process_l1cache(vha,
+			    entry_hdr, &data_ptr);
+			break;
+		case QLA82XX_RDOCM:
+			qla8044_minidump_process_rdocm(vha,
+			    entry_hdr, &data_ptr);
+			break;
+		case QLA82XX_RDMUX:
+			qla8044_minidump_process_rdmux(vha,
+			    entry_hdr, &data_ptr);
+			break;
+		case QLA82XX_QUEUE:
+			qla8044_minidump_process_queue(vha,
+			    entry_hdr, &data_ptr);
+			break;
+		case QLA8044_POLLRD:
+			rval = qla8044_minidump_process_pollrd(vha,
+			    entry_hdr, &data_ptr);
+			if (rval != QLA_SUCCESS)
+				qla8044_mark_entry_skipped(vha, entry_hdr, i);
+			break;
+		case QLA8044_RDMUX2:
+			qla8044_minidump_process_rdmux2(vha,
+			    entry_hdr, &data_ptr);
+			break;
+		case QLA8044_POLLRDMWR:
+			rval = qla8044_minidump_process_pollrdmwr(vha,
+			    entry_hdr, &data_ptr);
+			if (rval != QLA_SUCCESS)
+				qla8044_mark_entry_skipped(vha, entry_hdr, i);
+			break;
+		case QLA82XX_RDNOP:
+		default:
+			qla8044_mark_entry_skipped(vha, entry_hdr, i);
+			break;
+		}
+
+		data_collected = (uint8_t *)data_ptr -
+		    (uint8_t *)((uint8_t *)ha->md_dump);
+skip_nxt_entry:
+		/*
+		 * next entry in the template
+		 */
+		entry_hdr = (struct qla8044_minidump_entry_hdr *)
+		    (((uint8_t *)entry_hdr) + entry_hdr->entry_size);
+	}
+
+	if (data_collected != ha->md_dump_size) {
+		ql_log(ql_log_info, vha, 0xb105,
+		    "Dump data mismatch: Data collected: "
+		    "[0x%x], total_data_size:[0x%x]\n",
+		    data_collected, ha->md_dump_size);
+		goto md_failed;
+	}
+
+	ql_log(ql_log_info, vha, 0xb110,
+	    "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n",
+	    vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump);
+	ha->fw_dumped = 1;
+	qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
+
+
+	ql_log(ql_log_info, vha, 0xb106,
+	    "Leaving fn: %s Last entry: 0x%x\n",
+	    __func__, i);
+md_failed:
+	return rval;
+}
+
+void
+qla8044_get_minidump(struct scsi_qla_host *vha)
+{
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!qla8044_collect_md_data(vha)) {
+		ha->fw_dumped = 1;
+	} else {
+		ql_log(ql_log_fatal, vha, 0xb0db,
+		    "%s: Unable to collect minidump\n",
+		    __func__);
+	}
+}
+
+static int
+qla8044_poll_flash_status_reg(struct scsi_qla_host *vha)
+{
+	uint32_t flash_status;
+	int retries = QLA8044_FLASH_READ_RETRY_COUNT;
+	int ret_val = QLA_SUCCESS;
+
+	while (retries--) {
+		ret_val = qla8044_rd_reg_indirect(vha, QLA8044_FLASH_STATUS,
+		    &flash_status);
+		if (ret_val) {
+			ql_log(ql_log_warn, vha, 0xb13c,
+			    "%s: Failed to read FLASH_STATUS reg.\n",
+			    __func__);
+			break;
+		}
+		if ((flash_status & QLA8044_FLASH_STATUS_READY) ==
+		    QLA8044_FLASH_STATUS_READY)
+			break;
+		msleep(QLA8044_FLASH_STATUS_REG_POLL_DELAY);
+	}
+
+	if (!retries)
+		ret_val = QLA_FUNCTION_FAILED;
+
+	return ret_val;
+}
+
+static int
+qla8044_write_flash_status_reg(struct scsi_qla_host *vha,
+			       uint32_t data)
+{
+	int ret_val = QLA_SUCCESS;
+	uint32_t cmd;
+
+	cmd = vha->hw->fdt_wrt_sts_reg_cmd;
+
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+	    QLA8044_FLASH_STATUS_WRITE_DEF_SIG | cmd);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb125,
+		    "%s: Failed to write to FLASH_ADDR.\n", __func__);
+		goto exit_func;
+	}
+
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, data);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb126,
+		    "%s: Failed to write to FLASH_WRDATA.\n", __func__);
+		goto exit_func;
+	}
+
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+	    QLA8044_FLASH_SECOND_ERASE_MS_VAL);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb127,
+		    "%s: Failed to write to FLASH_CONTROL.\n", __func__);
+		goto exit_func;
+	}
+
+	ret_val = qla8044_poll_flash_status_reg(vha);
+	if (ret_val)
+		ql_log(ql_log_warn, vha, 0xb128,
+		    "%s: Error polling flash status reg.\n", __func__);
+
+exit_func:
+	return ret_val;
+}
+
+/*
+ * This function assumes that the flash lock is held.
+ */
+static int
+qla8044_unprotect_flash(scsi_qla_host_t *vha)
+{
+	int ret_val;
+	struct qla_hw_data *ha = vha->hw;
+
+	ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_enable);
+	if (ret_val)
+		ql_log(ql_log_warn, vha, 0xb139,
+		    "%s: Write flash status failed.\n", __func__);
+
+	return ret_val;
+}
+
+/*
+ * This function assumes that the flash lock is held.
+ */
+static int
+qla8044_protect_flash(scsi_qla_host_t *vha)
+{
+	int ret_val;
+	struct qla_hw_data *ha = vha->hw;
+
+	ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_disable);
+	if (ret_val)
+		ql_log(ql_log_warn, vha, 0xb13b,
+		    "%s: Write flash status failed.\n", __func__);
+
+	return ret_val;
+}
+
+
+static int
+qla8044_erase_flash_sector(struct scsi_qla_host *vha,
+			   uint32_t sector_start_addr)
+{
+	uint32_t reversed_addr;
+	int ret_val = QLA_SUCCESS;
+
+	ret_val = qla8044_poll_flash_status_reg(vha);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb12e,
+		    "%s: Poll flash status after erase failed..\n", __func__);
+	}
+
+	reversed_addr = (((sector_start_addr & 0xFF) << 16) |
+	    (sector_start_addr & 0xFF00) |
+	    ((sector_start_addr & 0xFF0000) >> 16));
+
+	ret_val = qla8044_wr_reg_indirect(vha,
+	    QLA8044_FLASH_WRDATA, reversed_addr);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb12f,
+		    "%s: Failed to write to FLASH_WRDATA.\n", __func__);
+	}
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+	   QLA8044_FLASH_ERASE_SIG | vha->hw->fdt_erase_cmd);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb130,
+		    "%s: Failed to write to FLASH_ADDR.\n", __func__);
+	}
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+	    QLA8044_FLASH_LAST_ERASE_MS_VAL);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb131,
+		    "%s: Failed write to FLASH_CONTROL.\n", __func__);
+	}
+	ret_val = qla8044_poll_flash_status_reg(vha);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb132,
+		    "%s: Poll flash status failed.\n", __func__);
+	}
+
+
+	return ret_val;
+}
+
+/*
+ * qla8044_flash_write_u32 - Write data to flash
+ *
+ * @ha : Pointer to adapter structure
+ * addr : Flash address to write to
+ * p_data : Data to be written
+ *
+ * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
+ *
+ * NOTE: Lock should be held on entry
+ */
+static int
+qla8044_flash_write_u32(struct scsi_qla_host *vha, uint32_t addr,
+			uint32_t *p_data)
+{
+	int ret_val = QLA_SUCCESS;
+
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+	    0x00800000 | (addr >> 2));
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb134,
+		    "%s: Failed write to FLASH_ADDR.\n", __func__);
+		goto exit_func;
+	}
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *p_data);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb135,
+		    "%s: Failed write to FLASH_WRDATA.\n", __func__);
+		goto exit_func;
+	}
+	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 0x3D);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb136,
+		    "%s: Failed write to FLASH_CONTROL.\n", __func__);
+		goto exit_func;
+	}
+	ret_val = qla8044_poll_flash_status_reg(vha);
+	if (ret_val) {
+		ql_log(ql_log_warn, vha, 0xb137,
+		    "%s: Poll flash status failed.\n", __func__);
+	}
+
+exit_func:
+	return ret_val;
+}
+
+static int
+qla8044_write_flash_buffer_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
+				uint32_t faddr, uint32_t dwords)
+{
+	int ret = QLA_FUNCTION_FAILED;
+	uint32_t spi_val;
+
+	if (dwords < QLA8044_MIN_OPTROM_BURST_DWORDS ||
+	    dwords > QLA8044_MAX_OPTROM_BURST_DWORDS) {
+		ql_dbg(ql_dbg_user, vha, 0xb123,
+		    "Got unsupported dwords = 0x%x.\n",
+		    dwords);
+		return QLA_FUNCTION_FAILED;
+	}
+
+	qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, &spi_val);
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
+	    spi_val | QLA8044_FLASH_SPI_CTL);
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+	    QLA8044_FLASH_FIRST_TEMP_VAL);
+
+	/* First DWORD write to FLASH_WRDATA */
+	ret = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA,
+	    *dwptr++);
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+	    QLA8044_FLASH_FIRST_MS_PATTERN);
+
+	ret = qla8044_poll_flash_status_reg(vha);
+	if (ret) {
+		ql_log(ql_log_warn, vha, 0xb124,
+		    "%s: Failed.\n", __func__);
+		goto exit_func;
+	}
+
+	dwords--;
+
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+	    QLA8044_FLASH_SECOND_TEMP_VAL);
+
+
+	/* Second to N-1 DWORDS writes */
+	while (dwords != 1) {
+		qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++);
+		qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+		    QLA8044_FLASH_SECOND_MS_PATTERN);
+		ret = qla8044_poll_flash_status_reg(vha);
+		if (ret) {
+			ql_log(ql_log_warn, vha, 0xb129,
+			    "%s: Failed.\n", __func__);
+			goto exit_func;
+		}
+		dwords--;
+	}
+
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
+	    QLA8044_FLASH_FIRST_TEMP_VAL | (faddr >> 2));
+
+	/* Last DWORD write */
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++);
+	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
+	    QLA8044_FLASH_LAST_MS_PATTERN);
+	ret = qla8044_poll_flash_status_reg(vha);
+	if (ret) {
+		ql_log(ql_log_warn, vha, 0xb12a,
+		    "%s: Failed.\n", __func__);
+		goto exit_func;
+	}
+	qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_STATUS, &spi_val);
+
+	if ((spi_val & QLA8044_FLASH_SPI_CTL) == QLA8044_FLASH_SPI_CTL) {
+		ql_log(ql_log_warn, vha, 0xb12b,
+		    "%s: Failed.\n", __func__);
+		spi_val = 0;
+		/* Operation failed, clear error bit. */
+		qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
+		    &spi_val);
+		qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
+		    spi_val | QLA8044_FLASH_SPI_CTL);
+	}
+exit_func:
+	return ret;
+}
+
+static int
+qla8044_write_flash_dword_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
+			       uint32_t faddr, uint32_t dwords)
+{
+	int ret = QLA_FUNCTION_FAILED;
+	uint32_t liter;
+
+	for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) {
+		ret = qla8044_flash_write_u32(vha, faddr, dwptr);
+		if (ret) {
+			ql_dbg(ql_dbg_p3p, vha, 0xb141,
+			    "%s: flash address=%x data=%x.\n", __func__,
+			     faddr, *dwptr);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+int
+qla8044_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
+			  uint32_t offset, uint32_t length)
+{
+	int rval = QLA_FUNCTION_FAILED, i, burst_iter_count;
+	int dword_count, erase_sec_count;
+	uint32_t erase_offset;
+	uint8_t *p_cache, *p_src;
+
+	erase_offset = offset;
+
+	p_cache = kcalloc(length, sizeof(uint8_t), GFP_KERNEL);
+	if (!p_cache)
+		return QLA_FUNCTION_FAILED;
+
+	memcpy(p_cache, buf, length);
+	p_src = p_cache;
+	dword_count = length / sizeof(uint32_t);
+	/* Since the offset and legth are sector aligned, it will be always
+	 * multiple of burst_iter_count (64)
+	 */
+	burst_iter_count = dword_count / QLA8044_MAX_OPTROM_BURST_DWORDS;
+	erase_sec_count = length / QLA8044_SECTOR_SIZE;
+
+	/* Suspend HBA. */
+	scsi_block_requests(vha->host);
+	/* Lock and enable write for whole operation. */
+	qla8044_flash_lock(vha);
+	qla8044_unprotect_flash(vha);
+
+	/* Erasing the sectors */
+	for (i = 0; i < erase_sec_count; i++) {
+		rval = qla8044_erase_flash_sector(vha, erase_offset);
+		ql_dbg(ql_dbg_user, vha, 0xb138,
+		    "Done erase of sector=0x%x.\n",
+		    erase_offset);
+		if (rval) {
+			ql_log(ql_log_warn, vha, 0xb121,
+			    "Failed to erase the sector having address: "
+			    "0x%x.\n", erase_offset);
+			goto out;
+		}
+		erase_offset += QLA8044_SECTOR_SIZE;
+	}
+	ql_dbg(ql_dbg_user, vha, 0xb13f,
+	    "Got write for addr = 0x%x length=0x%x.\n",
+	    offset, length);
+
+	for (i = 0; i < burst_iter_count; i++) {
+
+		/* Go with write. */
+		rval = qla8044_write_flash_buffer_mode(vha, (uint32_t *)p_src,
+		    offset, QLA8044_MAX_OPTROM_BURST_DWORDS);
+		if (rval) {
+			/* Buffer Mode failed skip to dword mode */
+			ql_log(ql_log_warn, vha, 0xb122,
+			    "Failed to write flash in buffer mode, "
+			    "Reverting to slow-write.\n");
+			rval = qla8044_write_flash_dword_mode(vha,
+			    (uint32_t *)p_src, offset,
+			    QLA8044_MAX_OPTROM_BURST_DWORDS);
+		}
+		p_src +=  sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS;
+		offset += sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS;
+	}
+	ql_dbg(ql_dbg_user, vha, 0xb133,
+	    "Done writing.\n");
+
+out:
+	qla8044_protect_flash(vha);
+	qla8044_flash_unlock(vha);
+	scsi_unblock_requests(vha->host);
+	kfree(p_cache);
+
+	return rval;
+}
+
+#define LEG_INT_PTR_B31		(1 << 31)
+#define LEG_INT_PTR_B30		(1 << 30)
+#define PF_BITS_MASK		(0xF << 16)
+/**
+ * qla8044_intr_handler() - Process interrupts for the ISP8044
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qla8044_intr_handler(int irq, void *dev_id)
+{
+	scsi_qla_host_t	*vha;
+	struct qla_hw_data *ha;
+	struct rsp_que *rsp;
+	struct device_reg_82xx __iomem *reg;
+	int		status = 0;
+	unsigned long	flags;
+	unsigned long	iter;
+	uint32_t	stat;
+	uint16_t	mb[4];
+	uint32_t leg_int_ptr = 0, pf_bit;
+
+	rsp = (struct rsp_que *) dev_id;
+	if (!rsp) {
+		ql_log(ql_log_info, NULL, 0xb143,
+		    "%s(): NULL response queue pointer\n", __func__);
+		return IRQ_NONE;
+	}
+	ha = rsp->hw;
+	vha = pci_get_drvdata(ha->pdev);
+
+	if (unlikely(pci_channel_offline(ha->pdev)))
+		return IRQ_HANDLED;
+
+	leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET);
+
+	/* Legacy interrupt is valid if bit31 of leg_int_ptr is set */
+	if (!(leg_int_ptr & (LEG_INT_PTR_B31))) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb144,
+		    "%s: Legacy Interrupt Bit 31 not set, "
+		    "spurious interrupt!\n", __func__);
+		return IRQ_NONE;
+	}
+
+	pf_bit = ha->portnum << 16;
+	/* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */
+	if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit) {
+		ql_dbg(ql_dbg_p3p, vha, 0xb145,
+		    "%s: Incorrect function ID 0x%x in "
+		    "legacy interrupt register, "
+		    "ha->pf_bit = 0x%x\n", __func__,
+		    (leg_int_ptr & (PF_BITS_MASK)), pf_bit);
+		return IRQ_NONE;
+	}
+
+	/* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger
+	 * Control register and poll till Legacy Interrupt Pointer register
+	 * bit32 is 0.
+	 */
+	qla8044_wr_reg(ha, LEG_INTR_TRIG_OFFSET, 0);
+	do {
+		leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET);
+		if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit)
+			break;
+	} while (leg_int_ptr & (LEG_INT_PTR_B30));
+
+	reg = &ha->iobase->isp82;
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	for (iter = 1; iter--; ) {
+
+		if (RD_REG_DWORD(&reg->host_int)) {
+			stat = RD_REG_DWORD(&reg->host_status);
+			if ((stat & HSRX_RISC_INT) == 0)
+				break;
+
+			switch (stat & 0xff) {
+			case 0x1:
+			case 0x2:
+			case 0x10:
+			case 0x11:
+				qla82xx_mbx_completion(vha, MSW(stat));
+				status |= MBX_INTERRUPT;
+				break;
+			case 0x12:
+				mb[0] = MSW(stat);
+				mb[1] = RD_REG_WORD(&reg->mailbox_out[1]);
+				mb[2] = RD_REG_WORD(&reg->mailbox_out[2]);
+				mb[3] = RD_REG_WORD(&reg->mailbox_out[3]);
+				qla2x00_async_event(vha, rsp, mb);
+				break;
+			case 0x13:
+				qla24xx_process_response_queue(vha, rsp);
+				break;
+			default:
+				ql_dbg(ql_dbg_p3p, vha, 0xb146,
+				    "Unrecognized interrupt type "
+				    "(%d).\n", stat & 0xff);
+				break;
+			}
+		}
+		WRT_REG_DWORD(&reg->host_int, 0);
+	}
+
+	qla2x00_handle_mbx_completion(ha, status);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int
+qla8044_idc_dontreset(struct qla_hw_data *ha)
+{
+	uint32_t idc_ctrl;
+
+	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
+	return idc_ctrl & DONTRESET_BIT0;
+}
+
+static void
+qla8044_clear_rst_ready(scsi_qla_host_t *vha)
+{
+	uint32_t drv_state;
+
+	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
+
+	/*
+	 * For ISP8044, drv_active register has 1 bit per function,
+	 * shift 1 by func_num to set a bit for the function.
+	 * For ISP82xx, drv_active has 4 bits per function
+	 */
+	drv_state &= ~(1 << vha->hw->portnum);
+
+	ql_dbg(ql_dbg_p3p, vha, 0xb13d,
+	    "drv_state: 0x%08x\n", drv_state);
+	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state);
+}
+
+int
+qla8044_abort_isp(scsi_qla_host_t *vha)
+{
+	int rval;
+	uint32_t dev_state;
+	struct qla_hw_data *ha = vha->hw;
+
+	qla8044_idc_lock(ha);
+	dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
+
+	if (ql2xdontresethba)
+		qla8044_set_idc_dontreset(vha);
+
+	/* If device_state is NEED_RESET, go ahead with
+	 * Reset,irrespective of ql2xdontresethba. This is to allow a
+	 * non-reset-owner to force a reset. Non-reset-owner sets
+	 * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
+	 * and then forces a Reset by setting device_state to
+	 * NEED_RESET. */
+	if (dev_state == QLA8XXX_DEV_READY) {
+		/* If IDC_CTRL DONTRESETHBA_BIT0 is set don't do reset
+		 * recovery */
+		if (qla8044_idc_dontreset(ha) == DONTRESET_BIT0) {
+			ql_dbg(ql_dbg_p3p, vha, 0xb13e,
+			    "Reset recovery disabled\n");
+			rval = QLA_FUNCTION_FAILED;
+			goto exit_isp_reset;
+		}
+
+		ql_dbg(ql_dbg_p3p, vha, 0xb140,
+		    "HW State: NEED RESET\n");
+		qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
+		    QLA8XXX_DEV_NEED_RESET);
+	}
+
+	/* For ISP8044, Reset owner is NIC, iSCSI or FCOE based on priority
+	 * and which drivers are present. Unlike ISP82XX, the function setting
+	 * NEED_RESET, may not be the Reset owner. */
+	qla83xx_reset_ownership(vha);
+
+	qla8044_idc_unlock(ha);
+	rval = qla8044_device_state_handler(vha);
+	qla8044_idc_lock(ha);
+	qla8044_clear_rst_ready(vha);
+
+exit_isp_reset:
+	qla8044_idc_unlock(ha);
+	if (rval == QLA_SUCCESS) {
+		ha->flags.isp82xx_fw_hung = 0;
+		ha->flags.nic_core_reset_hdlr_active = 0;
+		rval = qla82xx_restart_isp(vha);
+	}
+
+	return rval;
+}
+
diff --git a/drivers/scsi/qla2xxx/qla_nx2.h b/drivers/scsi/qla2xxx/qla_nx2.h
new file mode 100644
index 0000000..2ab2eab
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_nx2.h
@@ -0,0 +1,551 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+
+#ifndef __QLA_NX2_H
+#define __QLA_NX2_H
+
+#define QSNT_ACK_TOV				30
+#define INTENT_TO_RECOVER			0x01
+#define PROCEED_TO_RECOVER			0x02
+#define IDC_LOCK_RECOVERY_OWNER_MASK		0x3C
+#define IDC_LOCK_RECOVERY_STATE_MASK		0x3
+#define IDC_LOCK_RECOVERY_STATE_SHIFT_BITS	2
+
+#define QLA8044_DRV_LOCK_MSLEEP		200
+#define QLA8044_ADDR_DDR_NET		(0x0000000000000000ULL)
+#define QLA8044_ADDR_DDR_NET_MAX	(0x000000000fffffffULL)
+
+#define MD_MIU_TEST_AGT_WRDATA_LO		0x410000A0
+#define MD_MIU_TEST_AGT_WRDATA_HI		0x410000A4
+#define MD_MIU_TEST_AGT_WRDATA_ULO		0x410000B0
+#define MD_MIU_TEST_AGT_WRDATA_UHI		0x410000B4
+#define MD_MIU_TEST_AGT_RDDATA_LO		0x410000A8
+#define MD_MIU_TEST_AGT_RDDATA_HI		0x410000AC
+#define MD_MIU_TEST_AGT_RDDATA_ULO		0x410000B8
+#define MD_MIU_TEST_AGT_RDDATA_UHI		0x410000BC
+
+/* MIU_TEST_AGT_CTRL flags. work for SIU as well */
+#define MIU_TA_CTL_WRITE_ENABLE	(MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE)
+#define MIU_TA_CTL_WRITE_START	(MIU_TA_CTL_WRITE | MIU_TA_CTL_ENABLE |	\
+				 MIU_TA_CTL_START)
+#define MIU_TA_CTL_START_ENABLE	(MIU_TA_CTL_START | MIU_TA_CTL_ENABLE)
+
+/* Imbus address bit used to indicate a host address. This bit is
+ * eliminated by the pcie bar and bar select before presentation
+ * over pcie. */
+/* host memory via IMBUS */
+#define QLA8044_P2_ADDR_PCIE	(0x0000000800000000ULL)
+#define QLA8044_P3_ADDR_PCIE	(0x0000008000000000ULL)
+#define QLA8044_ADDR_PCIE_MAX	(0x0000000FFFFFFFFFULL)
+#define QLA8044_ADDR_OCM0	(0x0000000200000000ULL)
+#define QLA8044_ADDR_OCM0_MAX	(0x00000002000fffffULL)
+#define QLA8044_ADDR_OCM1	(0x0000000200400000ULL)
+#define QLA8044_ADDR_OCM1_MAX	(0x00000002004fffffULL)
+#define QLA8044_ADDR_QDR_NET	(0x0000000300000000ULL)
+#define QLA8044_P2_ADDR_QDR_NET_MAX	(0x00000003001fffffULL)
+#define QLA8044_P3_ADDR_QDR_NET_MAX	(0x0000000303ffffffULL)
+#define QLA8044_ADDR_QDR_NET_MAX	(0x0000000307ffffffULL)
+#define QLA8044_PCI_CRBSPACE		((unsigned long)0x06000000)
+#define QLA8044_PCI_DIRECT_CRB		((unsigned long)0x04400000)
+#define QLA8044_PCI_CAMQM		((unsigned long)0x04800000)
+#define QLA8044_PCI_CAMQM_MAX		((unsigned long)0x04ffffff)
+#define QLA8044_PCI_DDR_NET		((unsigned long)0x00000000)
+#define QLA8044_PCI_QDR_NET		((unsigned long)0x04000000)
+#define QLA8044_PCI_QDR_NET_MAX		((unsigned long)0x043fffff)
+
+/*  PCI Windowing for DDR regions.  */
+#define QLA8044_ADDR_IN_RANGE(addr, low, high)		\
+	(((addr) <= (high)) && ((addr) >= (low)))
+
+/* Indirectly Mapped Registers */
+#define QLA8044_FLASH_SPI_STATUS	0x2808E010
+#define QLA8044_FLASH_SPI_CONTROL	0x2808E014
+#define QLA8044_FLASH_STATUS		0x42100004
+#define QLA8044_FLASH_CONTROL		0x42110004
+#define QLA8044_FLASH_ADDR		0x42110008
+#define QLA8044_FLASH_WRDATA		0x4211000C
+#define QLA8044_FLASH_RDDATA		0x42110018
+#define QLA8044_FLASH_DIRECT_WINDOW	0x42110030
+#define QLA8044_FLASH_DIRECT_DATA(DATA) (0x42150000 | (0x0000FFFF&DATA))
+
+/* Flash access regs */
+#define QLA8044_FLASH_LOCK		0x3850
+#define QLA8044_FLASH_UNLOCK		0x3854
+#define QLA8044_FLASH_LOCK_ID		0x3500
+
+/* Driver Lock regs */
+#define QLA8044_DRV_LOCK		0x3868
+#define QLA8044_DRV_UNLOCK		0x386C
+#define QLA8044_DRV_LOCK_ID		0x3504
+#define QLA8044_DRV_LOCKRECOVERY	0x379C
+
+/* IDC version */
+#define QLA8044_IDC_VER_MAJ_VALUE       0x1
+#define QLA8044_IDC_VER_MIN_VALUE       0x0
+
+/* IDC Registers : Driver Coexistence Defines */
+#define QLA8044_CRB_IDC_VER_MAJOR	0x3780
+#define QLA8044_CRB_IDC_VER_MINOR	0x3798
+#define QLA8044_IDC_DRV_AUDIT		0x3794
+#define QLA8044_SRE_SHIM_CONTROL	0x0D200284
+#define QLA8044_PORT0_RXB_PAUSE_THRS	0x0B2003A4
+#define QLA8044_PORT1_RXB_PAUSE_THRS	0x0B2013A4
+#define QLA8044_PORT0_RXB_TC_MAX_CELL	0x0B200388
+#define QLA8044_PORT1_RXB_TC_MAX_CELL	0x0B201388
+#define QLA8044_PORT0_RXB_TC_STATS	0x0B20039C
+#define QLA8044_PORT1_RXB_TC_STATS	0x0B20139C
+#define QLA8044_PORT2_IFB_PAUSE_THRS	0x0B200704
+#define QLA8044_PORT3_IFB_PAUSE_THRS	0x0B201704
+
+/* set value to pause threshold value */
+#define QLA8044_SET_PAUSE_VAL		0x0
+#define QLA8044_SET_TC_MAX_CELL_VAL	0x03FF03FF
+#define QLA8044_PEG_HALT_STATUS1	0x34A8
+#define QLA8044_PEG_HALT_STATUS2	0x34AC
+#define QLA8044_PEG_ALIVE_COUNTER	0x34B0 /* FW_HEARTBEAT */
+#define QLA8044_FW_CAPABILITIES		0x3528
+#define QLA8044_CRB_DRV_ACTIVE		0x3788 /* IDC_DRV_PRESENCE */
+#define QLA8044_CRB_DEV_STATE		0x3784 /* IDC_DEV_STATE */
+#define QLA8044_CRB_DRV_STATE		0x378C /* IDC_DRV_ACK */
+#define QLA8044_CRB_DRV_SCRATCH		0x3548
+#define QLA8044_CRB_DEV_PART_INFO1	0x37E0
+#define QLA8044_CRB_DEV_PART_INFO2	0x37E4
+#define QLA8044_FW_VER_MAJOR		0x3550
+#define QLA8044_FW_VER_MINOR		0x3554
+#define QLA8044_FW_VER_SUB		0x3558
+#define QLA8044_NPAR_STATE		0x359C
+#define QLA8044_FW_IMAGE_VALID		0x35FC
+#define QLA8044_CMDPEG_STATE		0x3650
+#define QLA8044_ASIC_TEMP		0x37B4
+#define QLA8044_FW_API			0x356C
+#define QLA8044_DRV_OP_MODE		0x3570
+#define QLA8044_CRB_WIN_BASE		0x3800
+#define QLA8044_CRB_WIN_FUNC(f)		(QLA8044_CRB_WIN_BASE+((f)*4))
+#define QLA8044_SEM_LOCK_BASE		0x3840
+#define QLA8044_SEM_UNLOCK_BASE		0x3844
+#define QLA8044_SEM_LOCK_FUNC(f)	(QLA8044_SEM_LOCK_BASE+((f)*8))
+#define QLA8044_SEM_UNLOCK_FUNC(f)	(QLA8044_SEM_UNLOCK_BASE+((f)*8))
+#define QLA8044_LINK_STATE(f)		(0x3698+((f) > 7 ? 4 : 0))
+#define QLA8044_LINK_SPEED(f)		(0x36E0+(((f) >> 2) * 4))
+#define QLA8044_MAX_LINK_SPEED(f)       (0x36F0+(((f) / 4) * 4))
+#define QLA8044_LINK_SPEED_FACTOR	10
+
+/* FLASH API Defines */
+#define QLA8044_FLASH_MAX_WAIT_USEC	100
+#define QLA8044_FLASH_LOCK_TIMEOUT	10000
+#define QLA8044_FLASH_SECTOR_SIZE	65536
+#define QLA8044_DRV_LOCK_TIMEOUT	2000
+#define QLA8044_FLASH_SECTOR_ERASE_CMD	0xdeadbeef
+#define QLA8044_FLASH_WRITE_CMD		0xdacdacda
+#define QLA8044_FLASH_BUFFER_WRITE_CMD	0xcadcadca
+#define QLA8044_FLASH_READ_RETRY_COUNT	2000
+#define QLA8044_FLASH_STATUS_READY	0x6
+#define QLA8044_FLASH_BUFFER_WRITE_MIN	2
+#define QLA8044_FLASH_BUFFER_WRITE_MAX	64
+#define QLA8044_FLASH_STATUS_REG_POLL_DELAY 1
+#define QLA8044_ERASE_MODE		1
+#define QLA8044_WRITE_MODE		2
+#define QLA8044_DWORD_WRITE_MODE	3
+#define QLA8044_GLOBAL_RESET		0x38CC
+#define QLA8044_WILDCARD		0x38F0
+#define QLA8044_INFORMANT		0x38FC
+#define QLA8044_HOST_MBX_CTRL		0x3038
+#define QLA8044_FW_MBX_CTRL		0x303C
+#define QLA8044_BOOTLOADER_ADDR		0x355C
+#define QLA8044_BOOTLOADER_SIZE		0x3560
+#define QLA8044_FW_IMAGE_ADDR		0x3564
+#define QLA8044_MBX_INTR_ENABLE		0x1000
+#define QLA8044_MBX_INTR_MASK		0x1200
+
+/* IDC Control Register bit defines */
+#define DONTRESET_BIT0		0x1
+#define GRACEFUL_RESET_BIT1	0x2
+
+/* ISP8044 PEG_HALT_STATUS1 bits */
+#define QLA8044_HALT_STATUS_INFORMATIONAL (0x1 << 29)
+#define QLA8044_HALT_STATUS_FW_RESET	  (0x2 << 29)
+#define QLA8044_HALT_STATUS_UNRECOVERABLE (0x4 << 29)
+
+/* Firmware image definitions */
+#define QLA8044_BOOTLOADER_FLASH_ADDR	0x10000
+#define QLA8044_BOOT_FROM_FLASH		0
+#define QLA8044_IDC_PARAM_ADDR		0x3e8020
+
+/* FLASH related definitions */
+#define QLA8044_OPTROM_BURST_SIZE		0x100
+#define QLA8044_MAX_OPTROM_BURST_DWORDS		(QLA8044_OPTROM_BURST_SIZE / 4)
+#define QLA8044_MIN_OPTROM_BURST_DWORDS		2
+#define QLA8044_SECTOR_SIZE			(64 * 1024)
+
+#define QLA8044_FLASH_SPI_CTL			0x4
+#define QLA8044_FLASH_FIRST_TEMP_VAL		0x00800000
+#define QLA8044_FLASH_SECOND_TEMP_VAL		0x00800001
+#define QLA8044_FLASH_FIRST_MS_PATTERN		0x43
+#define QLA8044_FLASH_SECOND_MS_PATTERN		0x7F
+#define QLA8044_FLASH_LAST_MS_PATTERN		0x7D
+#define QLA8044_FLASH_STATUS_WRITE_DEF_SIG	0xFD0100
+#define QLA8044_FLASH_SECOND_ERASE_MS_VAL	0x5
+#define QLA8044_FLASH_ERASE_SIG			0xFD0300
+#define QLA8044_FLASH_LAST_ERASE_MS_VAL		0x3D
+
+/* Reset template definitions */
+#define QLA8044_MAX_RESET_SEQ_ENTRIES	16
+#define QLA8044_RESTART_TEMPLATE_SIZE	0x2000
+#define QLA8044_RESET_TEMPLATE_ADDR	0x4F0000
+#define QLA8044_RESET_SEQ_VERSION	0x0101
+
+/* Reset template entry opcodes */
+#define OPCODE_NOP			0x0000
+#define OPCODE_WRITE_LIST		0x0001
+#define OPCODE_READ_WRITE_LIST		0x0002
+#define OPCODE_POLL_LIST		0x0004
+#define OPCODE_POLL_WRITE_LIST		0x0008
+#define OPCODE_READ_MODIFY_WRITE	0x0010
+#define OPCODE_SEQ_PAUSE		0x0020
+#define OPCODE_SEQ_END			0x0040
+#define OPCODE_TMPL_END			0x0080
+#define OPCODE_POLL_READ_LIST		0x0100
+
+/* Template Header */
+#define RESET_TMPLT_HDR_SIGNATURE	0xCAFE
+#define QLA8044_IDC_DRV_CTRL            0x3790
+#define AF_8044_NO_FW_DUMP              27 /* 0x08000000 */
+
+#define MINIDUMP_SIZE_36K		36864
+
+struct qla8044_reset_template_hdr {
+	uint16_t	version;
+	uint16_t	signature;
+	uint16_t	size;
+	uint16_t	entries;
+	uint16_t	hdr_size;
+	uint16_t	checksum;
+	uint16_t	init_seq_offset;
+	uint16_t	start_seq_offset;
+} __packed;
+
+/* Common Entry Header. */
+struct qla8044_reset_entry_hdr {
+	uint16_t cmd;
+	uint16_t size;
+	uint16_t count;
+	uint16_t delay;
+} __packed;
+
+/* Generic poll entry type. */
+struct qla8044_poll {
+	uint32_t  test_mask;
+	uint32_t  test_value;
+} __packed;
+
+/* Read modify write entry type. */
+struct qla8044_rmw {
+	uint32_t test_mask;
+	uint32_t xor_value;
+	uint32_t  or_value;
+	uint8_t shl;
+	uint8_t shr;
+	uint8_t index_a;
+	uint8_t rsvd;
+} __packed;
+
+/* Generic Entry Item with 2 DWords. */
+struct qla8044_entry {
+	uint32_t arg1;
+	uint32_t arg2;
+} __packed;
+
+/* Generic Entry Item with 4 DWords.*/
+struct qla8044_quad_entry {
+	uint32_t dr_addr;
+	uint32_t dr_value;
+	uint32_t ar_addr;
+	uint32_t ar_value;
+} __packed;
+
+struct qla8044_reset_template {
+	int seq_index;
+	int seq_error;
+	int array_index;
+	uint32_t array[QLA8044_MAX_RESET_SEQ_ENTRIES];
+	uint8_t *buff;
+	uint8_t *stop_offset;
+	uint8_t *start_offset;
+	uint8_t *init_offset;
+	struct qla8044_reset_template_hdr *hdr;
+	uint8_t seq_end;
+	uint8_t template_end;
+};
+
+/* Driver_code is for driver to write some info about the entry
+ * currently not used.
+ */
+struct qla8044_minidump_entry_hdr {
+	uint32_t entry_type;
+	uint32_t entry_size;
+	uint32_t entry_capture_size;
+	struct {
+		uint8_t entry_capture_mask;
+		uint8_t entry_code;
+		uint8_t driver_code;
+		uint8_t driver_flags;
+	} d_ctrl;
+} __packed;
+
+/*  Read CRB entry header */
+struct qla8044_minidump_entry_crb {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t addr;
+	struct {
+		uint8_t addr_stride;
+		uint8_t state_index_a;
+		uint16_t poll_timeout;
+	} crb_strd;
+	uint32_t data_size;
+	uint32_t op_count;
+
+	struct {
+		uint8_t opcode;
+		uint8_t state_index_v;
+		uint8_t shl;
+		uint8_t shr;
+	} crb_ctrl;
+
+	uint32_t value_1;
+	uint32_t value_2;
+	uint32_t value_3;
+} __packed;
+
+struct qla8044_minidump_entry_cache {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t tag_reg_addr;
+	struct {
+		uint16_t tag_value_stride;
+		uint16_t init_tag_value;
+	} addr_ctrl;
+	uint32_t data_size;
+	uint32_t op_count;
+	uint32_t control_addr;
+	struct {
+		uint16_t write_value;
+		uint8_t poll_mask;
+		uint8_t poll_wait;
+	} cache_ctrl;
+	uint32_t read_addr;
+	struct {
+		uint8_t read_addr_stride;
+		uint8_t read_addr_cnt;
+		uint16_t rsvd_1;
+	} read_ctrl;
+} __packed;
+
+/* Read OCM */
+struct qla8044_minidump_entry_rdocm {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t rsvd_0;
+	uint32_t rsvd_1;
+	uint32_t data_size;
+	uint32_t op_count;
+	uint32_t rsvd_2;
+	uint32_t rsvd_3;
+	uint32_t read_addr;
+	uint32_t read_addr_stride;
+} __packed;
+
+/* Read Memory */
+struct qla8044_minidump_entry_rdmem {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t rsvd[6];
+	uint32_t read_addr;
+	uint32_t read_data_size;
+};
+
+/* Read Memory: For Pex-DMA */
+struct qla8044_minidump_entry_rdmem_pex_dma {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t desc_card_addr;
+	uint16_t dma_desc_cmd;
+	uint8_t rsvd[2];
+	uint32_t start_dma_cmd;
+	uint8_t rsvd2[12];
+	uint32_t read_addr;
+	uint32_t read_data_size;
+} __packed;
+
+/* Read ROM */
+struct qla8044_minidump_entry_rdrom {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t rsvd[6];
+	uint32_t read_addr;
+	uint32_t read_data_size;
+} __packed;
+
+/* Mux entry */
+struct qla8044_minidump_entry_mux {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t select_addr;
+	uint32_t rsvd_0;
+	uint32_t data_size;
+	uint32_t op_count;
+	uint32_t select_value;
+	uint32_t select_value_stride;
+	uint32_t read_addr;
+	uint32_t rsvd_1;
+} __packed;
+
+/* Queue entry */
+struct qla8044_minidump_entry_queue {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t select_addr;
+	struct {
+		uint16_t queue_id_stride;
+		uint16_t rsvd_0;
+	} q_strd;
+	uint32_t data_size;
+	uint32_t op_count;
+	uint32_t rsvd_1;
+	uint32_t rsvd_2;
+	uint32_t read_addr;
+	struct {
+		uint8_t read_addr_stride;
+		uint8_t read_addr_cnt;
+		uint16_t rsvd_3;
+	} rd_strd;
+} __packed;
+
+/* POLLRD Entry */
+struct qla8044_minidump_entry_pollrd {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t select_addr;
+	uint32_t read_addr;
+	uint32_t select_value;
+	uint16_t select_value_stride;
+	uint16_t op_count;
+	uint32_t poll_wait;
+	uint32_t poll_mask;
+	uint32_t data_size;
+	uint32_t rsvd_1;
+} __packed;
+
+/* RDMUX2 Entry */
+struct qla8044_minidump_entry_rdmux2 {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t select_addr_1;
+	uint32_t select_addr_2;
+	uint32_t select_value_1;
+	uint32_t select_value_2;
+	uint32_t op_count;
+	uint32_t select_value_mask;
+	uint32_t read_addr;
+	uint8_t select_value_stride;
+	uint8_t data_size;
+	uint8_t rsvd[2];
+} __packed;
+
+/* POLLRDMWR Entry */
+struct qla8044_minidump_entry_pollrdmwr {
+	struct qla8044_minidump_entry_hdr h;
+	uint32_t addr_1;
+	uint32_t addr_2;
+	uint32_t value_1;
+	uint32_t value_2;
+	uint32_t poll_wait;
+	uint32_t poll_mask;
+	uint32_t modify_mask;
+	uint32_t data_size;
+} __packed;
+
+/* IDC additional information */
+struct qla8044_idc_information {
+	uint32_t request_desc;  /* IDC request descriptor */
+	uint32_t info1; /* IDC additional info */
+	uint32_t info2; /* IDC additional info */
+	uint32_t info3; /* IDC additional info */
+} __packed;
+
+enum qla_regs {
+	QLA8044_PEG_HALT_STATUS1_INDEX = 0,
+	QLA8044_PEG_HALT_STATUS2_INDEX,
+	QLA8044_PEG_ALIVE_COUNTER_INDEX,
+	QLA8044_CRB_DRV_ACTIVE_INDEX,
+	QLA8044_CRB_DEV_STATE_INDEX,
+	QLA8044_CRB_DRV_STATE_INDEX,
+	QLA8044_CRB_DRV_SCRATCH_INDEX,
+	QLA8044_CRB_DEV_PART_INFO_INDEX,
+	QLA8044_CRB_DRV_IDC_VERSION_INDEX,
+	QLA8044_FW_VERSION_MAJOR_INDEX,
+	QLA8044_FW_VERSION_MINOR_INDEX,
+	QLA8044_FW_VERSION_SUB_INDEX,
+	QLA8044_CRB_CMDPEG_STATE_INDEX,
+	QLA8044_CRB_TEMP_STATE_INDEX,
+} __packed;
+
+#define CRB_REG_INDEX_MAX	14
+#define CRB_CMDPEG_CHECK_RETRY_COUNT    60
+#define CRB_CMDPEG_CHECK_DELAY          500
+
+static const uint32_t qla8044_reg_tbl[] = {
+	QLA8044_PEG_HALT_STATUS1,
+	QLA8044_PEG_HALT_STATUS2,
+	QLA8044_PEG_ALIVE_COUNTER,
+	QLA8044_CRB_DRV_ACTIVE,
+	QLA8044_CRB_DEV_STATE,
+	QLA8044_CRB_DRV_STATE,
+	QLA8044_CRB_DRV_SCRATCH,
+	QLA8044_CRB_DEV_PART_INFO1,
+	QLA8044_CRB_IDC_VER_MAJOR,
+	QLA8044_FW_VER_MAJOR,
+	QLA8044_FW_VER_MINOR,
+	QLA8044_FW_VER_SUB,
+	QLA8044_CMDPEG_STATE,
+	QLA8044_ASIC_TEMP,
+};
+
+/* MiniDump Structures */
+
+/* Driver_code is for driver to write some info about the entry
+ * currently not used.
+ */
+#define QLA8044_SS_OCM_WNDREG_INDEX             3
+#define QLA8044_DBG_STATE_ARRAY_LEN             16
+#define QLA8044_DBG_CAP_SIZE_ARRAY_LEN          8
+#define QLA8044_DBG_RSVD_ARRAY_LEN              8
+#define QLA8044_DBG_OCM_WNDREG_ARRAY_LEN        16
+#define QLA8044_SS_PCI_INDEX                    0
+
+struct qla8044_minidump_template_hdr {
+	uint32_t entry_type;
+	uint32_t first_entry_offset;
+	uint32_t size_of_template;
+	uint32_t capture_debug_level;
+	uint32_t num_of_entries;
+	uint32_t version;
+	uint32_t driver_timestamp;
+	uint32_t checksum;
+
+	uint32_t driver_capture_mask;
+	uint32_t driver_info_word2;
+	uint32_t driver_info_word3;
+	uint32_t driver_info_word4;
+
+	uint32_t saved_state_array[QLA8044_DBG_STATE_ARRAY_LEN];
+	uint32_t capture_size_array[QLA8044_DBG_CAP_SIZE_ARRAY_LEN];
+	uint32_t ocm_window_reg[QLA8044_DBG_OCM_WNDREG_ARRAY_LEN];
+};
+
+struct qla8044_pex_dma_descriptor {
+	struct {
+		uint32_t read_data_size; /* 0-23: size, 24-31: rsvd */
+		uint8_t rsvd[2];
+		uint16_t dma_desc_cmd;
+	} cmd;
+	uint64_t src_addr;
+	uint64_t dma_bus_addr; /*0-3: desc-cmd, 4-7: pci-func, 8-15: desc-cmd*/
+	uint8_t rsvd[24];
+} __packed;
+
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 3e21e9f..9f01bbb 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1247,7 +1247,7 @@
 		if (qla2x00_vp_abort_isp(vha))
 			goto eh_host_reset_lock;
 	} else {
-		if (IS_QLA82XX(vha->hw)) {
+		if (IS_P3P_TYPE(vha->hw)) {
 			if (!qla82xx_fcoe_ctx_reset(vha)) {
 				/* Ctx reset success */
 				ret = SUCCESS;
@@ -1303,6 +1303,10 @@
 	struct fc_port *fcport;
 	struct qla_hw_data *ha = vha->hw;
 
+	if (IS_QLAFX00(ha)) {
+		return qlafx00_loop_reset(vha);
+	}
+
 	if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {
 		list_for_each_entry(fcport, &vha->vp_fcports, list) {
 			if (fcport->port_type != FCT_TARGET)
@@ -1311,14 +1315,12 @@
 			ret = ha->isp_ops->target_reset(fcport, 0, 0);
 			if (ret != QLA_SUCCESS) {
 				ql_dbg(ql_dbg_taskm, vha, 0x802c,
-				    "Bus Reset failed: Target Reset=%d "
+				    "Bus Reset failed: Reset=%d "
 				    "d_id=%x.\n", ret, fcport->d_id.b24);
 			}
 		}
 	}
 
-	if (IS_QLAFX00(ha))
-		return QLA_SUCCESS;
 
 	if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
 		atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -1506,7 +1508,7 @@
 			if (sdev->queue_depth > shost->cmd_per_lun) {
 				if (sdev->queue_depth < ha->cfg_lun_q_depth)
 					continue;
-				ql_log(ql_log_warn, vp, 0x3031,
+				ql_dbg(ql_dbg_io, vp, 0x3031,
 				    "%ld:%d:%d: Ramping down queue depth to %d",
 				    vp->host_no, sdev->id, sdev->lun,
 				    ha->cfg_lun_q_depth);
@@ -1911,7 +1913,7 @@
 	.get_flash_version	= qla2x00_get_flash_version,
 	.start_scsi		= qla2x00_start_scsi,
 	.abort_isp		= qla2x00_abort_isp,
-	.iospace_config     	= qla2x00_iospace_config,
+	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
@@ -1949,7 +1951,7 @@
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi		= qla24xx_start_scsi,
 	.abort_isp		= qla2x00_abort_isp,
-	.iospace_config     	= qla2x00_iospace_config,
+	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
@@ -1987,7 +1989,7 @@
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi		= qla24xx_dif_start_scsi,
 	.abort_isp		= qla2x00_abort_isp,
-	.iospace_config     	= qla2x00_iospace_config,
+	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
@@ -2025,7 +2027,7 @@
 	.get_flash_version	= qla24xx_get_flash_version,
 	.start_scsi		= qla24xx_dif_start_scsi,
 	.abort_isp		= qla2x00_abort_isp,
-	.iospace_config     	= qla2x00_iospace_config,
+	.iospace_config		= qla2x00_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
@@ -2060,13 +2062,51 @@
 	.beacon_blink		= NULL,
 	.read_optrom		= qla82xx_read_optrom_data,
 	.write_optrom		= qla82xx_write_optrom_data,
-	.get_flash_version	= qla24xx_get_flash_version,
+	.get_flash_version	= qla82xx_get_flash_version,
 	.start_scsi             = qla82xx_start_scsi,
 	.abort_isp		= qla82xx_abort_isp,
 	.iospace_config     	= qla82xx_iospace_config,
 	.initialize_adapter	= qla2x00_initialize_adapter,
 };
 
+static struct isp_operations qla8044_isp_ops = {
+	.pci_config		= qla82xx_pci_config,
+	.reset_chip		= qla82xx_reset_chip,
+	.chip_diag		= qla24xx_chip_diag,
+	.config_rings		= qla82xx_config_rings,
+	.reset_adapter		= qla24xx_reset_adapter,
+	.nvram_config		= qla81xx_nvram_config,
+	.update_fw_options	= qla24xx_update_fw_options,
+	.load_risc		= qla82xx_load_risc,
+	.pci_info_str		= qla24xx_pci_info_str,
+	.fw_version_str		= qla24xx_fw_version_str,
+	.intr_handler		= qla8044_intr_handler,
+	.enable_intrs		= qla82xx_enable_intrs,
+	.disable_intrs		= qla82xx_disable_intrs,
+	.abort_command		= qla24xx_abort_command,
+	.target_reset		= qla24xx_abort_target,
+	.lun_reset		= qla24xx_lun_reset,
+	.fabric_login		= qla24xx_login_fabric,
+	.fabric_logout		= qla24xx_fabric_logout,
+	.calc_req_entries	= NULL,
+	.build_iocbs		= NULL,
+	.prep_ms_iocb		= qla24xx_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla24xx_prep_ms_fdmi_iocb,
+	.read_nvram		= NULL,
+	.write_nvram		= NULL,
+	.fw_dump		= qla24xx_fw_dump,
+	.beacon_on		= qla82xx_beacon_on,
+	.beacon_off		= qla82xx_beacon_off,
+	.beacon_blink		= NULL,
+	.read_optrom		= qla82xx_read_optrom_data,
+	.write_optrom		= qla8044_write_optrom_data,
+	.get_flash_version	= qla82xx_get_flash_version,
+	.start_scsi             = qla82xx_start_scsi,
+	.abort_isp		= qla8044_abort_isp,
+	.iospace_config		= qla82xx_iospace_config,
+	.initialize_adapter	= qla2x00_initialize_adapter,
+};
+
 static struct isp_operations qla83xx_isp_ops = {
 	.pci_config		= qla25xx_pci_config,
 	.reset_chip		= qla24xx_reset_chip,
@@ -2237,6 +2277,14 @@
 		/* Initialize 82XX ISP flags */
 		qla82xx_init_flags(ha);
 		break;
+	 case PCI_DEVICE_ID_QLOGIC_ISP8044:
+		ha->device_type |= DT_ISP8044;
+		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+		/* Initialize 82XX ISP flags */
+		qla82xx_init_flags(ha);
+		break;
 	case PCI_DEVICE_ID_QLOGIC_ISP2031:
 		ha->device_type |= DT_ISP2031;
 		ha->device_type |= DT_ZIO_SUPPORTED;
@@ -2317,7 +2365,6 @@
 	uint16_t req_length = 0, rsp_length = 0;
 	struct req_que *req = NULL;
 	struct rsp_que *rsp = NULL;
-
 	bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
 	sht = &qla2xxx_driver_template;
 	if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
@@ -2330,7 +2377,8 @@
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031 ||
-	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001) {
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044) {
 		bars = pci_select_bars(pdev, IORESOURCE_MEM);
 		mem_only = 1;
 		ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2484,6 +2532,21 @@
 		ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
 		ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
 		ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
+	} else if (IS_QLA8044(ha)) {
+		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		req_length = REQUEST_ENTRY_CNT_82XX;
+		rsp_length = RESPONSE_ENTRY_CNT_82XX;
+		ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+		ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+		ha->gid_list_info_size = 8;
+		ha->optrom_size = OPTROM_SIZE_83XX;
+		ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
+		ha->isp_ops = &qla8044_isp_ops;
+		ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+		ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
+		ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
+		ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
 	} else if (IS_QLA83XX(ha)) {
 		ha->portnum = PCI_FUNC(ha->pdev->devfn);
 		ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
@@ -2512,6 +2575,7 @@
 		ha->port_down_retry_count = 30; /* default value */
 		ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
 		ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+		ha->mr.fw_critemp_timer_tick = QLAFX00_CRITEMP_INTERVAL;
 		ha->mr.fw_hbt_en = 1;
 	}
 
@@ -2676,7 +2740,7 @@
 		rsp->rsp_q_out = &ha->iobase->ispfx00.rsp_q_out;
 	}
 
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		req->req_q_out = &ha->iobase->isp82.req_q_out[0];
 		rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0];
 		rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0];
@@ -2709,6 +2773,14 @@
 			qla82xx_idc_unlock(ha);
 			ql_log(ql_log_fatal, base_vha, 0x00d7,
 			    "HW State: FAILED.\n");
+		} else if (IS_QLA8044(ha)) {
+			qla8044_idc_lock(ha);
+			qla8044_wr_direct(base_vha,
+				QLA8044_CRB_DEV_STATE_INDEX,
+				QLA8XXX_DEV_FAILED);
+			qla8044_idc_unlock(ha);
+			ql_log(ql_log_fatal, base_vha, 0x0150,
+			    "HW State: FAILED.\n");
 		}
 
 		ret = -ENODEV;
@@ -2804,6 +2876,13 @@
 
 	ha->isp_ops->enable_intrs(ha);
 
+	if (IS_QLAFX00(ha)) {
+		ret = qlafx00_fx_disc(base_vha,
+			&base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO);
+		host->sg_tablesize = (ha->mr.extended_io_enabled) ?
+		    QLA_SG_ALL : 128;
+	}
+
 	ret = scsi_add_host(host, &pdev->dev);
 	if (ret)
 		goto probe_failed;
@@ -2824,9 +2903,6 @@
 
 	if (IS_QLAFX00(ha)) {
 		ret = qlafx00_fx_disc(base_vha,
-			&base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO);
-
-		ret = qlafx00_fx_disc(base_vha,
 			&base_vha->hw->mr.fcport, FXDISC_GET_PORT_INFO);
 
 		/* Register system information */
@@ -2881,8 +2957,13 @@
 		qla82xx_clear_drv_active(ha);
 		qla82xx_idc_unlock(ha);
 	}
+	if (IS_QLA8044(ha)) {
+		qla8044_idc_lock(ha);
+		qla8044_clear_drv_active(base_vha);
+		qla8044_idc_unlock(ha);
+	}
 iospace_config_failed:
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		if (!ha->nx_pcibase)
 			iounmap((device_reg_t __iomem *)ha->nx_pcibase);
 		if (!ql2xdbwr)
@@ -2930,6 +3011,10 @@
 	vha = pci_get_drvdata(pdev);
 	ha = vha->hw;
 
+	/* Notify ISPFX00 firmware */
+	if (IS_QLAFX00(ha))
+		qlafx00_driver_shutdown(vha, 20);
+
 	/* Turn-off FCE trace */
 	if (ha->flags.fce_enabled) {
 		qla2x00_disable_fce_trace(vha, NULL, NULL);
@@ -2977,6 +3062,9 @@
 	ha->flags.host_shutting_down = 1;
 
 	set_bit(UNLOADING, &base_vha->dpc_flags);
+	if (IS_QLAFX00(ha))
+		qlafx00_driver_shutdown(base_vha, 20);
+
 	mutex_lock(&ha->vport_lock);
 	while (ha->cur_vport_count) {
 		spin_lock_irqsave(&ha->vport_slock, flags);
@@ -3061,6 +3149,11 @@
 
 	scsi_host_put(base_vha->host);
 
+	if (IS_QLA8044(ha)) {
+		qla8044_idc_lock(ha);
+		qla8044_clear_drv_active(base_vha);
+		qla8044_idc_unlock(ha);
+	}
 	if (IS_QLA82XX(ha)) {
 		qla82xx_idc_lock(ha);
 		qla82xx_clear_drv_active(ha);
@@ -3210,14 +3303,8 @@
 		set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
 
 		ql_dbg(ql_dbg_disc, vha, 0x2067,
-		    "Port login retry "
-		    "%02x%02x%02x%02x%02x%02x%02x%02x, "
-		    "id = 0x%04x retry cnt=%d.\n",
-		    fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7],
-		    fcport->loop_id, fcport->login_retry);
+		    "Port login retry %8phN, id = 0x%04x retry cnt=%d.\n",
+		    fcport->port_name, fcport->loop_id, fcport->login_retry);
 	}
 }
 
@@ -3290,7 +3377,7 @@
 	if (!ha->srb_mempool)
 		goto fail_free_gid_list;
 
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		/* Allocate cache for CT6 Ctx. */
 		if (!ctx_cachep) {
 			ctx_cachep = kmem_cache_create("qla2xxx_ctx",
@@ -3324,7 +3411,7 @@
 	    "init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n",
 	    ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool);
 
-	if (IS_QLA82XX(ha) || ql2xenabledif) {
+	if (IS_P3P_TYPE(ha) || ql2xenabledif) {
 		ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
 			DSD_LIST_DMA_POOL_SIZE, 8, 0);
 		if (!ha->dl_dma_pool) {
@@ -3532,7 +3619,7 @@
 *	Frees fw dump stuff.
 *
 * Input:
-*	ha = adapter block pointer.
+*	ha = adapter block pointer
 */
 static void
 qla2x00_free_fw_dump(struct qla_hw_data *ha)
@@ -4699,17 +4786,33 @@
 
 		qla2x00_do_work(base_vha);
 
-		if (IS_QLA82XX(ha)) {
-			if (test_and_clear_bit(ISP_UNRECOVERABLE,
-				&base_vha->dpc_flags)) {
-				qla82xx_idc_lock(ha);
-				qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
-					QLA8XXX_DEV_FAILED);
-				qla82xx_idc_unlock(ha);
-				ql_log(ql_log_info, base_vha, 0x4004,
-				    "HW State: FAILED.\n");
-				qla82xx_device_state_handler(base_vha);
-				continue;
+		if (IS_P3P_TYPE(ha)) {
+			if (IS_QLA8044(ha)) {
+				if (test_and_clear_bit(ISP_UNRECOVERABLE,
+					&base_vha->dpc_flags)) {
+					qla8044_idc_lock(ha);
+					qla8044_wr_direct(base_vha,
+						QLA8044_CRB_DEV_STATE_INDEX,
+						QLA8XXX_DEV_FAILED);
+					qla8044_idc_unlock(ha);
+					ql_log(ql_log_info, base_vha, 0x4004,
+						"HW State: FAILED.\n");
+					qla8044_device_state_handler(base_vha);
+					continue;
+				}
+
+			} else {
+				if (test_and_clear_bit(ISP_UNRECOVERABLE,
+					&base_vha->dpc_flags)) {
+					qla82xx_idc_lock(ha);
+					qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
+						QLA8XXX_DEV_FAILED);
+					qla82xx_idc_unlock(ha);
+					ql_log(ql_log_info, base_vha, 0x0151,
+						"HW State: FAILED.\n");
+					qla82xx_device_state_handler(base_vha);
+					continue;
+				}
 			}
 
 			if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED,
@@ -4809,16 +4912,26 @@
 		if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
 			ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
 			    "Quiescence mode scheduled.\n");
-			if (IS_QLA82XX(ha)) {
-				qla82xx_device_state_handler(base_vha);
+			if (IS_P3P_TYPE(ha)) {
+				if (IS_QLA82XX(ha))
+					qla82xx_device_state_handler(base_vha);
+				if (IS_QLA8044(ha))
+					qla8044_device_state_handler(base_vha);
 				clear_bit(ISP_QUIESCE_NEEDED,
 				    &base_vha->dpc_flags);
 				if (!ha->flags.quiesce_owner) {
 					qla2x00_perform_loop_resync(base_vha);
-
-					qla82xx_idc_lock(ha);
-					qla82xx_clear_qsnt_ready(base_vha);
-					qla82xx_idc_unlock(ha);
+					if (IS_QLA82XX(ha)) {
+						qla82xx_idc_lock(ha);
+						qla82xx_clear_qsnt_ready(
+						    base_vha);
+						qla82xx_idc_unlock(ha);
+					} else if (IS_QLA8044(ha)) {
+						qla8044_idc_lock(ha);
+						qla8044_clear_qsnt_ready(
+						    base_vha);
+						qla8044_idc_unlock(ha);
+					}
 				}
 			} else {
 				clear_bit(ISP_QUIESCE_NEEDED,
@@ -4992,10 +5105,13 @@
 		pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
 
 	/* Make sure qla82xx_watchdog is run only for physical port */
-	if (!vha->vp_idx && IS_QLA82XX(ha)) {
+	if (!vha->vp_idx && IS_P3P_TYPE(ha)) {
 		if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags))
 			start_dpc++;
-		qla82xx_watchdog(vha);
+		if (IS_QLA82XX(ha))
+			qla82xx_watchdog(vha);
+		else if (IS_QLA8044(ha))
+			qla8044_watchdog(vha);
 	}
 
 	if (!vha->vp_idx && IS_QLAFX00(ha))
@@ -5075,7 +5191,7 @@
 	/* Check if beacon LED needs to be blinked for physical host only */
 	if (!vha->vp_idx && (ha->beacon_blink_led == 1)) {
 		/* There is no beacon_blink function for ISP82xx */
-		if (!IS_QLA82XX(ha)) {
+		if (!IS_P3P_TYPE(ha)) {
 			set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags);
 			start_dpc++;
 		}
@@ -5519,6 +5635,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8031) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISPF001) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8044) },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 3bef673..bd56cde 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -565,7 +565,7 @@
 		*start = FA_FLASH_LAYOUT_ADDR;
 	else if (IS_QLA81XX(ha))
 		*start = FA_FLASH_LAYOUT_ADDR_81;
-	else if (IS_QLA82XX(ha)) {
+	else if (IS_P3P_TYPE(ha)) {
 		*start = FA_FLASH_LAYOUT_ADDR_82;
 		goto end;
 	} else if (IS_QLA83XX(ha)) {
@@ -719,7 +719,7 @@
 		start = le32_to_cpu(region->start) >> 2;
 		ql_dbg(ql_dbg_init, vha, 0x0049,
 		    "FLT[%02x]: start=0x%x "
-		    "end=0x%x size=0x%x.\n", le32_to_cpu(region->code),
+		    "end=0x%x size=0x%x.\n", le32_to_cpu(region->code) & 0xff,
 		    start, le32_to_cpu(region->end) >> 2,
 		    le32_to_cpu(region->size));
 
@@ -741,13 +741,13 @@
 			if (IS_QLA8031(ha))
 				break;
 			ha->flt_region_vpd_nvram = start;
-			if (IS_QLA82XX(ha))
+			if (IS_P3P_TYPE(ha))
 				break;
 			if (ha->flags.port0)
 				ha->flt_region_vpd = start;
 			break;
 		case FLT_REG_VPD_1:
-			if (IS_QLA82XX(ha) || IS_QLA8031(ha))
+			if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
 				break;
 			if (!ha->flags.port0)
 				ha->flt_region_vpd = start;
@@ -789,9 +789,17 @@
 		case FLT_REG_BOOT_CODE_82XX:
 			ha->flt_region_boot = start;
 			break;
+		case FLT_REG_BOOT_CODE_8044:
+			if (IS_QLA8044(ha))
+				ha->flt_region_boot = start;
+			break;
 		case FLT_REG_FW_82XX:
 			ha->flt_region_fw = start;
 			break;
+		case FLT_REG_CNA_FW:
+			if (IS_CNA_CAPABLE(ha))
+				ha->flt_region_fw = start;
+			break;
 		case FLT_REG_GOLD_FW_82XX:
 			ha->flt_region_gold_fw = start;
 			break;
@@ -803,13 +811,13 @@
 				ha->flt_region_vpd = start;
 			break;
 		case FLT_REG_FCOE_NVRAM_0:
-			if (!IS_QLA8031(ha))
+			if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
 				break;
 			if (ha->flags.port0)
 				ha->flt_region_nvram = start;
 			break;
 		case FLT_REG_FCOE_NVRAM_1:
-			if (!IS_QLA8031(ha))
+			if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
 				break;
 			if (!ha->flags.port0)
 				ha->flt_region_nvram = start;
@@ -883,7 +891,13 @@
 	mid = le16_to_cpu(fdt->man_id);
 	fid = le16_to_cpu(fdt->id);
 	ha->fdt_wrt_disable = fdt->wrt_disable_bits;
-	ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0300 | fdt->erase_cmd);
+	ha->fdt_wrt_enable = fdt->wrt_enable_bits;
+	ha->fdt_wrt_sts_reg_cmd = fdt->wrt_sts_reg_cmd;
+	if (IS_QLA8044(ha))
+		ha->fdt_erase_cmd = fdt->erase_cmd;
+	else
+		ha->fdt_erase_cmd =
+		    flash_conf_addr(ha, 0x0300 | fdt->erase_cmd);
 	ha->fdt_block_size = le32_to_cpu(fdt->block_size);
 	if (fdt->unprotect_sec_cmd) {
 		ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 |
@@ -895,7 +909,7 @@
 	goto done;
 no_flash_data:
 	loc = locations[0];
-	if (IS_QLA82XX(ha)) {
+	if (IS_P3P_TYPE(ha)) {
 		ha->fdt_block_size = FLASH_BLK_SIZE_64K;
 		goto done;
 	}
@@ -946,7 +960,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct req_que *req = ha->req_q_map[0];
 
-	if (!IS_QLA82XX(ha))
+	if (!(IS_P3P_TYPE(ha)))
 		return;
 
 	wptr = (uint32_t *)req->ring;
@@ -1008,6 +1022,9 @@
 	if (ha->flags.nic_core_reset_hdlr_active)
 		return;
 
+	if (IS_QLA8044(ha))
+		return;
+
 	ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
 	    ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header));
 	if (hdr.version == __constant_cpu_to_le16(0xffff))
@@ -1302,7 +1319,7 @@
 	uint32_t *dwptr;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return  buf;
 
 	/* Dword reads to flash. */
@@ -1360,7 +1377,7 @@
 
 	ret = QLA_SUCCESS;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return ret;
 
 	/* Enable flash write. */
@@ -1474,7 +1491,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1752,7 +1769,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return QLA_SUCCESS;
 
 	if (IS_QLA8031(ha) || IS_QLA81XX(ha))
@@ -1804,7 +1821,7 @@
 	struct qla_hw_data *ha = vha->hw;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return QLA_SUCCESS;
 
 	ha->beacon_blink_led = 0;
@@ -2822,6 +2839,121 @@
 }
 
 int
+qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
+{
+	int ret = QLA_SUCCESS;
+	uint32_t pcihdr, pcids;
+	uint32_t *dcode;
+	uint8_t *bcode;
+	uint8_t code_type, last_image;
+	struct qla_hw_data *ha = vha->hw;
+
+	if (!mbuf)
+		return QLA_FUNCTION_FAILED;
+
+	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
+	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
+	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+
+	dcode = mbuf;
+
+	/* Begin with first PCI expansion ROM header. */
+	pcihdr = ha->flt_region_boot << 2;
+	last_image = 1;
+	do {
+		/* Verify PCI expansion ROM header. */
+		ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcihdr,
+		    0x20 * 4);
+		bcode = mbuf + (pcihdr % 4);
+		if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
+			/* No signature */
+			ql_log(ql_log_fatal, vha, 0x0154,
+			    "No matching ROM signature.\n");
+			ret = QLA_FUNCTION_FAILED;
+			break;
+		}
+
+		/* Locate PCI data structure. */
+		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
+
+		ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, pcids,
+		    0x20 * 4);
+		bcode = mbuf + (pcihdr % 4);
+
+		/* Validate signature of PCI data structure. */
+		if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
+		    bcode[0x2] != 'I' || bcode[0x3] != 'R') {
+			/* Incorrect header. */
+			ql_log(ql_log_fatal, vha, 0x0155,
+			    "PCI data struct not found pcir_adr=%x.\n", pcids);
+			ret = QLA_FUNCTION_FAILED;
+			break;
+		}
+
+		/* Read version */
+		code_type = bcode[0x14];
+		switch (code_type) {
+		case ROM_CODE_TYPE_BIOS:
+			/* Intel x86, PC-AT compatible. */
+			ha->bios_revision[0] = bcode[0x12];
+			ha->bios_revision[1] = bcode[0x13];
+			ql_dbg(ql_dbg_init, vha, 0x0156,
+			    "Read BIOS %d.%d.\n",
+			    ha->bios_revision[1], ha->bios_revision[0]);
+			break;
+		case ROM_CODE_TYPE_FCODE:
+			/* Open Firmware standard for PCI (FCode). */
+			ha->fcode_revision[0] = bcode[0x12];
+			ha->fcode_revision[1] = bcode[0x13];
+			ql_dbg(ql_dbg_init, vha, 0x0157,
+			    "Read FCODE %d.%d.\n",
+			    ha->fcode_revision[1], ha->fcode_revision[0]);
+			break;
+		case ROM_CODE_TYPE_EFI:
+			/* Extensible Firmware Interface (EFI). */
+			ha->efi_revision[0] = bcode[0x12];
+			ha->efi_revision[1] = bcode[0x13];
+			ql_dbg(ql_dbg_init, vha, 0x0158,
+			    "Read EFI %d.%d.\n",
+			    ha->efi_revision[1], ha->efi_revision[0]);
+			break;
+		default:
+			ql_log(ql_log_warn, vha, 0x0159,
+			    "Unrecognized code type %x at pcids %x.\n",
+			    code_type, pcids);
+			break;
+		}
+
+		last_image = bcode[0x15] & BIT_7;
+
+		/* Locate next PCI expansion ROM. */
+		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
+	} while (!last_image);
+
+	/* Read firmware image information. */
+	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+	dcode = mbuf;
+	ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, ha->flt_region_fw << 2,
+	    0x20);
+	bcode = mbuf + (pcihdr % 4);
+
+	/* Validate signature of PCI data structure. */
+	if (bcode[0x0] == 0x3 && bcode[0x1] == 0x0 &&
+	    bcode[0x2] == 0x40 && bcode[0x3] == 0x40) {
+		ha->fw_revision[0] = bcode[0x4];
+		ha->fw_revision[1] = bcode[0x5];
+		ha->fw_revision[2] = bcode[0x6];
+		ql_dbg(ql_dbg_init, vha, 0x0153,
+		    "Firmware revision %d.%d.%d\n",
+		    ha->fw_revision[0], ha->fw_revision[1],
+		    ha->fw_revision[2]);
+	}
+
+	return ret;
+}
+
+int
 qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
 {
 	int ret = QLA_SUCCESS;
@@ -2832,7 +2964,7 @@
 	int i;
 	struct qla_hw_data *ha = vha->hw;
 
-	if (IS_QLA82XX(ha))
+	if (IS_P3P_TYPE(ha))
 		return ret;
 
 	if (!mbuf)
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 83a8f7a..ff12d46 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -430,13 +430,8 @@
 	}
 
 	ql_dbg(ql_dbg_tgt, vha, 0xe047,
-	    "scsi(%ld): resetting (session %p from port "
-	    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, "
-	    "mcmd %x, loop_id %d)\n", vha->host_no, sess,
-	    sess->port_name[0], sess->port_name[1],
-	    sess->port_name[2], sess->port_name[3],
-	    sess->port_name[4], sess->port_name[5],
-	    sess->port_name[6], sess->port_name[7],
+	    "scsi(%ld): resetting (session %p from port %8phC mcmd %x, "
+	    "loop_id %d)\n", vha->host_no, sess, sess->port_name,
 	    mcmd, loop_id);
 
 	lun = a->u.isp24.fcp_cmnd.lun;
@@ -467,15 +462,10 @@
 	sess->expires = jiffies + dev_loss_tmo * HZ;
 
 	ql_dbg(ql_dbg_tgt, sess->vha, 0xe048,
-	    "qla_target(%d): session for port %02x:%02x:%02x:"
-	    "%02x:%02x:%02x:%02x:%02x (loop ID %d) scheduled for "
+	    "qla_target(%d): session for port %8phC (loop ID %d) scheduled for "
 	    "deletion in %u secs (expires: %lu) immed: %d\n",
-	    sess->vha->vp_idx,
-	    sess->port_name[0], sess->port_name[1],
-	    sess->port_name[2], sess->port_name[3],
-	    sess->port_name[4], sess->port_name[5],
-	    sess->port_name[6], sess->port_name[7],
-	    sess->loop_id, dev_loss_tmo, sess->expires, immediate);
+	    sess->vha->vp_idx, sess->port_name, sess->loop_id, dev_loss_tmo,
+	    sess->expires, immediate);
 
 	if (immediate)
 		schedule_delayed_work(&tgt->sess_del_work, 0);
@@ -630,13 +620,9 @@
 	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
 	if (!sess) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04a,
-		    "qla_target(%u): session allocation failed, "
-		    "all commands from port %02x:%02x:%02x:%02x:"
-		    "%02x:%02x:%02x:%02x will be refused", vha->vp_idx,
-		    fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7]);
+		    "qla_target(%u): session allocation failed, all commands "
+		    "from port %8phC will be refused", vha->vp_idx,
+		    fcport->port_name);
 
 		return NULL;
 	}
@@ -680,15 +666,11 @@
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
-	    "qla_target(%d): %ssession for wwn %02x:%02x:%02x:%02x:"
-	    "%02x:%02x:%02x:%02x (loop_id %d, s_id %x:%x:%x, confirmed"
-	    " completion %ssupported) added\n",
-	    vha->vp_idx, local ?  "local " : "", fcport->port_name[0],
-	    fcport->port_name[1], fcport->port_name[2], fcport->port_name[3],
-	    fcport->port_name[4], fcport->port_name[5], fcport->port_name[6],
-	    fcport->port_name[7], fcport->loop_id, sess->s_id.b.domain,
-	    sess->s_id.b.area, sess->s_id.b.al_pa, sess->conf_compl_supported ?
-	    "" : "not ");
+	    "qla_target(%d): %ssession for wwn %8phC (loop_id %d, "
+	    "s_id %x:%x:%x, confirmed completion %ssupported) added\n",
+	    vha->vp_idx, local ?  "local " : "", fcport->port_name,
+	    fcport->loop_id, sess->s_id.b.domain, sess->s_id.b.area,
+	    sess->s_id.b.al_pa, sess->conf_compl_supported ?  "" : "not ");
 
 	return sess;
 }
@@ -730,13 +712,9 @@
 			qlt_undelete_sess(sess);
 
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04c,
-			    "qla_target(%u): %ssession for port %02x:"
-			    "%02x:%02x:%02x:%02x:%02x:%02x:%02x (loop ID %d) "
-			    "reappeared\n", vha->vp_idx, sess->local ? "local "
-			    : "", sess->port_name[0], sess->port_name[1],
-			    sess->port_name[2], sess->port_name[3],
-			    sess->port_name[4], sess->port_name[5],
-			    sess->port_name[6], sess->port_name[7],
+			    "qla_target(%u): %ssession for port %8phC "
+			    "(loop ID %d) reappeared\n", vha->vp_idx,
+			    sess->local ? "local " : "", sess->port_name,
 			    sess->loop_id);
 
 			ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007,
@@ -749,13 +727,8 @@
 	if (sess && sess->local) {
 		ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04d,
 		    "qla_target(%u): local session for "
-		    "port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
-		    "(loop ID %d) became global\n", vha->vp_idx,
-		    fcport->port_name[0], fcport->port_name[1],
-		    fcport->port_name[2], fcport->port_name[3],
-		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7],
-		    sess->loop_id);
+		    "port %8phC (loop ID %d) became global\n", vha->vp_idx,
+		    fcport->port_name, sess->loop_id);
 		sess->local = 0;
 	}
 	ha->tgt.tgt_ops->put_sess(sess);
@@ -2840,10 +2813,8 @@
 	int res = 0;
 
 	ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026,
-	    "qla_target(%d): Port ID: 0x%02x:%02x:%02x"
-	    " ELS opcode: 0x%02x\n", vha->vp_idx, iocb->u.isp24.port_id[0],
-	    iocb->u.isp24.port_id[1], iocb->u.isp24.port_id[2],
-	    iocb->u.isp24.status_subcode);
+	    "qla_target(%d): Port ID: 0x%3phC ELS opcode: 0x%02x\n",
+	    vha->vp_idx, iocb->u.isp24.port_id, iocb->u.isp24.status_subcode);
 
 	switch (iocb->u.isp24.status_subcode) {
 	case ELS_PLOGI:
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 6c66d22..a808e29 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.05.00.03-k"
+#define QLA2XXX_VERSION      "8.06.00.08-k"
 
 #define QLA_DRIVER_MAJOR_VER	8
-#define QLA_DRIVER_MINOR_VER	5
+#define QLA_DRIVER_MINOR_VER	6
 #define QLA_DRIVER_PATCH_VER	0
 #define QLA_DRIVER_BETA_VER	0
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index a318092..a6da313 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1474,15 +1474,11 @@
 
 
 	if (sess->loop_id != loop_id || sess->s_id.b24 != s_id.b24)
-		pr_info("Updating session %p from port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n",
-			sess,
-			sess->port_name[0], sess->port_name[1],
-			sess->port_name[2], sess->port_name[3],
-			sess->port_name[4], sess->port_name[5],
-			sess->port_name[6], sess->port_name[7],
-			sess->loop_id, loop_id,
-			sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
-			s_id.b.domain, s_id.b.area, s_id.b.al_pa);
+		pr_info("Updating session %p from port %8phC loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n",
+		    sess, sess->port_name,
+		    sess->loop_id, loop_id, sess->s_id.b.domain,
+		    sess->s_id.b.area, sess->s_id.b.al_pa, s_id.b.domain,
+		    s_id.b.area, s_id.b.al_pa);
 
 	if (sess->loop_id != loop_id) {
 		/*
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index d607eb8..8196c2f 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)   2003-2012 QLogic Corporation
+ * Copyright (c)   2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -259,8 +259,8 @@
  * Return: On success return QLA_SUCCESS
  *	   On error return QLA_ERROR
  **/
-static int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
-				       uint32_t *data, uint32_t count)
+int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
+				uint32_t *data, uint32_t count)
 {
 	int i, j;
 	uint32_t agt_ctrl;
@@ -1473,9 +1473,9 @@
 				  __func__));
 	}
 
-	/* For ISP8324, Reset owner is NIC, iSCSI or FCOE based on priority
-	 * and which drivers are present. Unlike ISP8022, the function setting
-	 * NEED_RESET, may not be the Reset owner. */
+	/* For ISP8324 and ISP8042, Reset owner is NIC, iSCSI or FCOE based on
+	 * priority and which drivers are present. Unlike ISP8022, the function
+	 * setting NEED_RESET, may not be the Reset owner. */
 	if (qla4_83xx_can_perform_reset(ha))
 		set_bit(AF_8XXX_RST_OWNER, &ha->flags);
 
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h
index fab237f..a0de6e2 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.h
+++ b/drivers/scsi/qla4xxx/ql4_83xx.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -290,4 +290,38 @@
 	uint32_t info3; /* IDC additional info */
 };
 
+#define QLA83XX_PEX_DMA_ENGINE_INDEX		8
+#define QLA83XX_PEX_DMA_BASE_ADDRESS		0x77320000
+#define QLA83XX_PEX_DMA_NUM_OFFSET		0x10000
+#define QLA83XX_PEX_DMA_CMD_ADDR_LOW		0x0
+#define QLA83XX_PEX_DMA_CMD_ADDR_HIGH		0x04
+#define QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL	0x08
+
+#define QLA83XX_PEX_DMA_READ_SIZE	(16 * 1024)
+#define QLA83XX_PEX_DMA_MAX_WAIT	(100 * 100) /* Max wait of 100 msecs */
+
+/* Read Memory: For Pex-DMA */
+struct qla4_83xx_minidump_entry_rdmem_pex_dma {
+	struct qla8xxx_minidump_entry_hdr h;
+	uint32_t desc_card_addr;
+	uint16_t dma_desc_cmd;
+	uint8_t rsvd[2];
+	uint32_t start_dma_cmd;
+	uint8_t rsvd2[12];
+	uint32_t read_addr;
+	uint32_t read_data_size;
+};
+
+struct qla4_83xx_pex_dma_descriptor {
+	struct {
+		uint32_t read_data_size; /* 0-23: size, 24-31: rsvd */
+		uint8_t rsvd[2];
+		uint16_t dma_desc_cmd;
+	} cmd;
+	uint64_t src_addr;
+	uint64_t dma_bus_addr; /* 0-3: desc-cmd, 4-7: pci-func,
+				* 8-15: desc-cmd */
+	uint8_t rsvd[24];
+} __packed;
+
 #endif
diff --git a/drivers/scsi/qla4xxx/ql4_attr.c b/drivers/scsi/qla4xxx/ql4_attr.c
index 19ee55a..463239c 100644
--- a/drivers/scsi/qla4xxx/ql4_attr.c
+++ b/drivers/scsi/qla4xxx/ql4_attr.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2011 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -83,7 +83,7 @@
 			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
 					    QLA8XXX_DEV_NEED_RESET);
 			if (is_qla8022(ha) ||
-			    (is_qla8032(ha) &&
+			    ((is_qla8032(ha) || is_qla8042(ha)) &&
 			     qla4_83xx_can_perform_reset(ha))) {
 				set_bit(AF_8XXX_RST_OWNER, &ha->flags);
 				set_bit(AF_FW_RECOVERY, &ha->flags);
@@ -158,14 +158,12 @@
 
 	if (is_qla80XX(ha))
 		return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
-				ha->firmware_version[0],
-				ha->firmware_version[1],
-				ha->patch_number, ha->build_number);
+				ha->fw_info.fw_major, ha->fw_info.fw_minor,
+				ha->fw_info.fw_patch, ha->fw_info.fw_build);
 	else
 		return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n",
-				ha->firmware_version[0],
-				ha->firmware_version[1],
-				ha->patch_number, ha->build_number);
+				ha->fw_info.fw_major, ha->fw_info.fw_minor,
+				ha->fw_info.fw_patch, ha->fw_info.fw_build);
 }
 
 static ssize_t
@@ -181,8 +179,8 @@
 			   char *buf)
 {
 	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
-	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->iscsi_major,
-			ha->iscsi_minor);
+	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fw_info.iscsi_major,
+			ha->fw_info.iscsi_minor);
 }
 
 static ssize_t
@@ -191,8 +189,8 @@
 {
 	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
 	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n",
-			ha->bootload_major, ha->bootload_minor,
-			ha->bootload_patch, ha->bootload_build);
+			ha->fw_info.bootload_major, ha->fw_info.bootload_minor,
+			ha->fw_info.bootload_patch, ha->fw_info.bootload_build);
 }
 
 static ssize_t
@@ -259,6 +257,63 @@
 	return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_name);
 }
 
+static ssize_t
+qla4xxx_fw_timestamp_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+	return snprintf(buf, PAGE_SIZE, "%s %s\n", ha->fw_info.fw_build_date,
+			ha->fw_info.fw_build_time);
+}
+
+static ssize_t
+qla4xxx_fw_build_user_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+	return snprintf(buf, PAGE_SIZE, "%s\n", ha->fw_info.fw_build_user);
+}
+
+static ssize_t
+qla4xxx_fw_ext_timestamp_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+	return snprintf(buf, PAGE_SIZE, "%s\n", ha->fw_info.extended_timestamp);
+}
+
+static ssize_t
+qla4xxx_fw_load_src_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+	char *load_src = NULL;
+
+	switch (ha->fw_info.fw_load_source) {
+	case 1:
+		load_src = "Flash Primary";
+		break;
+	case 2:
+		load_src = "Flash Secondary";
+		break;
+	case 3:
+		load_src = "Host Download";
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", load_src);
+}
+
+static ssize_t
+qla4xxx_fw_uptime_show(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev));
+	qla4xxx_about_firmware(ha);
+	return snprintf(buf, PAGE_SIZE, "%u.%u secs\n", ha->fw_uptime_secs,
+			ha->fw_uptime_msecs);
+}
+
 static DEVICE_ATTR(fw_version, S_IRUGO, qla4xxx_fw_version_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla4xxx_serial_num_show, NULL);
 static DEVICE_ATTR(iscsi_version, S_IRUGO, qla4xxx_iscsi_version_show, NULL);
@@ -269,6 +324,12 @@
 static DEVICE_ATTR(phy_port_num, S_IRUGO, qla4xxx_phy_port_num_show, NULL);
 static DEVICE_ATTR(iscsi_func_cnt, S_IRUGO, qla4xxx_iscsi_func_cnt_show, NULL);
 static DEVICE_ATTR(hba_model, S_IRUGO, qla4xxx_hba_model_show, NULL);
+static DEVICE_ATTR(fw_timestamp, S_IRUGO, qla4xxx_fw_timestamp_show, NULL);
+static DEVICE_ATTR(fw_build_user, S_IRUGO, qla4xxx_fw_build_user_show, NULL);
+static DEVICE_ATTR(fw_ext_timestamp, S_IRUGO, qla4xxx_fw_ext_timestamp_show,
+		   NULL);
+static DEVICE_ATTR(fw_load_src, S_IRUGO, qla4xxx_fw_load_src_show, NULL);
+static DEVICE_ATTR(fw_uptime, S_IRUGO, qla4xxx_fw_uptime_show, NULL);
 
 struct device_attribute *qla4xxx_host_attrs[] = {
 	&dev_attr_fw_version,
@@ -281,5 +342,10 @@
 	&dev_attr_phy_port_num,
 	&dev_attr_iscsi_func_cnt,
 	&dev_attr_hba_model,
+	&dev_attr_fw_timestamp,
+	&dev_attr_fw_build_user,
+	&dev_attr_fw_ext_timestamp,
+	&dev_attr_fw_load_src,
+	&dev_attr_fw_uptime,
 	NULL,
 };
diff --git a/drivers/scsi/qla4xxx/ql4_bsg.c b/drivers/scsi/qla4xxx/ql4_bsg.c
index 8acdc58..cf8fdf1 100644
--- a/drivers/scsi/qla4xxx/ql4_bsg.c
+++ b/drivers/scsi/qla4xxx/ql4_bsg.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c) 2011 QLogic Corporation
+ * Copyright (c) 2011-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index 77b7c59..5649e9e 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -141,21 +141,22 @@
 
 	if (is_qla8022(ha)) {
 		ql4_printk(KERN_INFO, ha,
-			   "scsi(%ld): %s, ISP8022 Dumping hw/fw registers:\n"
+			   "scsi(%ld): %s, ISP%04x Dumping hw/fw registers:\n"
 			   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n"
 			   " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,\n"
 			   " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
-			   " PEG_NET_4_PC: 0x%x\n", ha->host_no,
-			   __func__, halt_status1, halt_status2,
+			   " PEG_NET_4_PC: 0x%x\n", ha->host_no, __func__,
+			   ha->pdev->device, halt_status1, halt_status2,
 			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c),
 			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c),
 			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c),
 			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c),
 			   qla4_82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c));
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		ql4_printk(KERN_INFO, ha,
-			   "scsi(%ld): %s, ISP8324 Dumping hw/fw registers:\n"
+			   "scsi(%ld): %s, ISP%04x Dumping hw/fw registers:\n"
 			   " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,\n",
-			   ha->host_no, __func__, halt_status1, halt_status2);
+			   ha->host_no, __func__, ha->pdev->device,
+			   halt_status1, halt_status2);
 	}
 }
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index ddf16a8..41327d4 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -64,6 +64,10 @@
 #define PCI_DEVICE_ID_QLOGIC_ISP8324	0x8032
 #endif
 
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP8042
+#define PCI_DEVICE_ID_QLOGIC_ISP8042	0x8042
+#endif
+
 #define ISP4XXX_PCI_FN_1	0x1
 #define ISP4XXX_PCI_FN_2	0x3
 
@@ -201,6 +205,7 @@
 
 #define MAX_RESET_HA_RETRIES		2
 #define FW_ALIVE_WAIT_TOV		3
+#define IDC_EXTEND_TOV			8
 
 #define CMD_SP(Cmnd)			((Cmnd)->SCp.ptr)
 
@@ -335,6 +340,7 @@
 #define DF_BOOT_TGT		1	/* Boot target entry */
 #define DF_ISNS_DISCOVERED	2	/* Device was discovered via iSNS */
 #define DF_FO_MASKED		3
+#define DF_DISABLE_RELOGIN		4	/* Disable relogin to device */
 
 enum qla4_work_type {
 	QLA4_EVENT_AEN,
@@ -557,6 +563,7 @@
 #define DPC_HA_UNRECOVERABLE		21 /* 0x00080000 ISP-82xx only*/
 #define DPC_HA_NEED_QUIESCENT		22 /* 0x00100000 ISP-82xx only*/
 #define DPC_POST_IDC_ACK		23 /* 0x00200000 */
+#define DPC_RESTORE_ACB			24 /* 0x01000000 */
 
 	struct Scsi_Host *host; /* pointer to host data */
 	uint32_t tot_ddbs;
@@ -734,12 +741,9 @@
 	struct iscsi_iface *iface_ipv6_1;
 
 	/* --- From About Firmware --- */
-	uint16_t iscsi_major;
-	uint16_t iscsi_minor;
-	uint16_t bootload_major;
-	uint16_t bootload_minor;
-	uint16_t bootload_patch;
-	uint16_t bootload_build;
+	struct about_fw_info fw_info;
+	uint32_t fw_uptime_secs;  /* seconds elapsed since fw bootup */
+	uint32_t fw_uptime_msecs; /* milliseconds beyond elapsed seconds */
 	uint16_t def_timeout; /* Default login timeout */
 
 	uint32_t flash_state;
@@ -780,9 +784,11 @@
 	uint32_t *reg_tbl;
 	struct qla4_83xx_reset_template reset_tmplt;
 	struct device_reg_83xx  __iomem *qla4_83xx_reg; /* Base I/O address
-							   for ISP8324 */
+							   for ISP8324 and
+							   and ISP8042 */
 	uint32_t pf_bit;
 	struct qla4_83xx_idc_information idc_info;
+	struct addr_ctrl_blk *saved_acb;
 };
 
 struct ql4_task_data {
@@ -850,9 +856,14 @@
 	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8324;
 }
 
+static inline int is_qla8042(struct scsi_qla_host *ha)
+{
+	return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8042;
+}
+
 static inline int is_qla80XX(struct scsi_qla_host *ha)
 {
-	return is_qla8022(ha) || is_qla8032(ha);
+	return is_qla8022(ha) || is_qla8032(ha) || is_qla8042(ha);
 }
 
 static inline int is_aer_supported(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index c7b8892..51d1a70 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -458,6 +458,7 @@
 #define MBOX_CMD_GET_CONN_EVENT_LOG		0x0077
 
 #define MBOX_CMD_IDC_ACK			0x0101
+#define MBOX_CMD_IDC_TIME_EXTEND		0x0102
 #define MBOX_CMD_PORT_RESET			0x0120
 #define MBOX_CMD_SET_PORT_CONFIG		0x0122
 
@@ -502,6 +503,7 @@
 #define MBOX_ASTS_SYSTEM_WARNING_EVENT		0x8036
 #define MBOX_ASTS_IDC_COMPLETE			0x8100
 #define MBOX_ASTS_IDC_REQUEST_NOTIFICATION	0x8101
+#define MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION	0x8102
 #define MBOX_ASTS_DCBX_CONF_CHANGE		0x8110
 #define MBOX_ASTS_TXSCVR_INSERTED		0x8130
 #define MBOX_ASTS_TXSCVR_REMOVED		0x8131
@@ -512,6 +514,10 @@
 #define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR	0x8022
 #define MBOX_ASTS_SUBNET_STATE_CHANGE		0x8027
 
+/* ACB Configuration Defines */
+#define ACB_CONFIG_DISABLE		0x00
+#define ACB_CONFIG_SET			0x01
+
 /* ACB State Defines */
 #define ACB_STATE_UNCONFIGURED	0x00
 #define ACB_STATE_INVALID	0x01
@@ -955,7 +961,7 @@
 	uint16_t bootload_minor;	/* 46 - 47 */
 	uint16_t bootload_patch;	/* 48 - 49 */
 	uint16_t bootload_build;	/* 4A - 4B */
-	uint8_t reserved2[180];		/* 4C - FF */
+	uint8_t extended_timestamp[180];/* 4C - FF */
 };
 
 struct crash_record {
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 4a42800..e6f2a26 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -266,6 +266,14 @@
 			    dma_addr_t dma_addr);
 int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
 				  char *password, uint16_t chap_index);
+int qla4xxx_disable_acb(struct scsi_qla_host *ha);
+int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
+		    uint32_t *mbox_sts, dma_addr_t acb_dma);
+int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma,
+		    uint32_t acb_type, uint32_t len);
+int qla4_84xx_config_acb(struct scsi_qla_host *ha, int acb_config);
+int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha,
+				uint64_t addr, uint32_t *data, uint32_t count);
 
 extern int ql4xextended_error_logging;
 extern int ql4xdontresethba;
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 8fc8548..7456eeb 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -107,7 +107,7 @@
 		    (unsigned long  __iomem *)&ha->qla4_82xx_reg->rsp_q_in);
 		writel(0,
 		    (unsigned long  __iomem *)&ha->qla4_82xx_reg->rsp_q_out);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		writel(0,
 		       (unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in);
 		writel(0,
@@ -940,7 +940,7 @@
 	 * while switching from polling to interrupt mode. IOCB interrupts are
 	 * enabled via isp_ops->enable_intrs.
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		qla4_83xx_enable_mbox_intrs(ha);
 
 	if (qla4xxx_about_firmware(ha) == QLA_ERROR)
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
index 6f4decd..8503ad6 100644
--- a/drivers/scsi/qla4xxx/ql4_inline.h
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index fad71ed..e5697ab 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 482287f..7dff09f 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -588,7 +588,7 @@
 {
 	int rval = 1;
 
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		if ((ha->idc_info.info2 & ENABLE_INTERNAL_LOOPBACK) ||
 		    (ha->idc_info.info2 & ENABLE_EXTERNAL_LOOPBACK)) {
 			DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -621,7 +621,7 @@
 	uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
 	__le32 __iomem *mailbox_out;
 
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0];
 	else if (is_qla8022(ha))
 		mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0];
@@ -665,7 +665,8 @@
 			qla4xxx_dump_registers(ha);
 
 			if ((is_qla8022(ha) && ql4xdontresethba) ||
-			    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+			    ((is_qla8032(ha) || is_qla8042(ha)) &&
+			     qla4_83xx_idc_dontreset(ha))) {
 				DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
 				    ha->host_no, __func__));
 			} else {
@@ -744,17 +745,23 @@
 			 * mbox_sts[3] = new ACB state */
 			if ((mbox_sts[3] == ACB_STATE_VALID) &&
 			    ((mbox_sts[2] == ACB_STATE_TENTATIVE) ||
-			    (mbox_sts[2] == ACB_STATE_ACQUIRING)))
+			    (mbox_sts[2] == ACB_STATE_ACQUIRING))) {
 				set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
-			else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
-				 (mbox_sts[2] == ACB_STATE_VALID)) {
+			} else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) &&
+				   (mbox_sts[2] == ACB_STATE_VALID)) {
 				if (is_qla80XX(ha))
 					set_bit(DPC_RESET_HA_FW_CONTEXT,
 						&ha->dpc_flags);
 				else
 					set_bit(DPC_RESET_HA, &ha->dpc_flags);
-			} else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED))
+			} else if (mbox_sts[3] == ACB_STATE_DISABLING) {
+				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB in disabling state\n",
+					   ha->host_no, __func__);
+			} else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED)) {
 				complete(&ha->disable_acb_comp);
+				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB state unconfigured\n",
+					   ha->host_no, __func__);
+			}
 			break;
 
 		case MBOX_ASTS_MAC_ADDRESS_CHANGED:
@@ -836,7 +843,7 @@
 		case MBOX_ASTS_IDC_REQUEST_NOTIFICATION:
 		{
 			uint32_t opcode;
-			if (is_qla8032(ha)) {
+			if (is_qla8032(ha) || is_qla8042(ha)) {
 				DEBUG2(ql4_printk(KERN_INFO, ha,
 						  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",
 						  ha->host_no, mbox_sts[0],
@@ -858,7 +865,7 @@
 		}
 
 		case MBOX_ASTS_IDC_COMPLETE:
-			if (is_qla8032(ha)) {
+			if (is_qla8032(ha) || is_qla8042(ha)) {
 				DEBUG2(ql4_printk(KERN_INFO, ha,
 						  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",
 						  ha->host_no, mbox_sts[0],
@@ -868,10 +875,15 @@
 						  "scsi:%ld: AEN %04x IDC Complete notification\n",
 						  ha->host_no, mbox_sts[0]));
 
-				if (qla4_83xx_loopback_in_progress(ha))
+				if (qla4_83xx_loopback_in_progress(ha)) {
 					set_bit(AF_LOOPBACK, &ha->flags);
-				else
+				} else {
 					clear_bit(AF_LOOPBACK, &ha->flags);
+					if (ha->saved_acb)
+						set_bit(DPC_RESTORE_ACB,
+							&ha->dpc_flags);
+				}
+				qla4xxx_wake_dpc(ha);
 			}
 			break;
 
@@ -886,6 +898,17 @@
 					  ha->host_no, mbox_sts[0]));
 			break;
 
+		case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION:
+			DEBUG2(ql4_printk(KERN_INFO, ha,
+					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+					  ha->host_no, mbox_sts[0], mbox_sts[1],
+					  mbox_sts[2], mbox_sts[3], mbox_sts[4],
+					  mbox_sts[5]));
+			DEBUG2(ql4_printk(KERN_INFO, ha,
+					  "scsi%ld: AEN %04x Received IDC Extend Timeout notification\n",
+					  ha->host_no, mbox_sts[0]));
+			break;
+
 		case MBOX_ASTS_INITIALIZATION_FAILED:
 			DEBUG2(ql4_printk(KERN_INFO, ha,
 					  "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n",
@@ -1297,7 +1320,7 @@
 	uint32_t intr_status;
 	uint8_t reqs_count = 0;
 
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		qla4_83xx_mailbox_intr_handler(irq, dev_id);
 	} else {
 		spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1334,7 +1357,7 @@
 	uint32_t ival = 0;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		ival = readl(&ha->qla4_83xx_reg->iocb_int_mask);
 		if (ival == 0) {
 			ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n",
@@ -1425,10 +1448,10 @@
 		goto try_intx;
 
 	if (ql4xenablemsix == 2) {
-		/* Note: MSI Interrupts not supported for ISP8324 */
-		if (is_qla8032(ha)) {
-			ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP8324, Falling back-to INTx mode\n",
-				   __func__);
+		/* Note: MSI Interrupts not supported for ISP8324 and ISP8042 */
+		if (is_qla8032(ha) || is_qla8042(ha)) {
+			ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP%04x, Falling back-to INTx mode\n",
+				   __func__, ha->pdev->device);
 			goto try_intx;
 		}
 		goto try_msi;
@@ -1444,9 +1467,9 @@
 		    "MSI-X: Enabled (0x%X).\n", ha->revision_id));
 		goto irq_attached;
 	} else {
-		if (is_qla8032(ha)) {
-			ql4_printk(KERN_INFO, ha, "%s: ISP8324: MSI-X: Falling back-to INTx mode. ret = %d\n",
-				   __func__, ret);
+		if (is_qla8032(ha) || is_qla8042(ha)) {
+			ql4_printk(KERN_INFO, ha, "%s: ISP%04x: MSI-X: Falling back-to INTx mode. ret = %d\n",
+				   __func__, ha->pdev->device, ret);
 			goto try_intx;
 		}
 	}
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index a501bea..62d4208 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -1,10 +1,11 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
+#include <linux/ctype.h>
 #include "ql4_def.h"
 #include "ql4_glbl.h"
 #include "ql4_dbg.h"
@@ -52,7 +53,7 @@
 {
 	int rval = 1;
 
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
 		    test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags))
 			rval = 0;
@@ -223,7 +224,7 @@
 			qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
 					CRB_NIU_XG_PAUSE_CTL_P0 |
 					CRB_NIU_XG_PAUSE_CTL_P1);
-		} else if (is_qla8032(ha)) {
+		} else if (is_qla8032(ha) || is_qla8042(ha)) {
 			ql4_printk(KERN_INFO, ha, " %s: disabling pause transmit on port 0 & 1.\n",
 				   __func__);
 			qla4_83xx_disable_pause(ha);
@@ -1270,16 +1271,28 @@
 	}
 
 	/* Save version information. */
-	ha->firmware_version[0] = le16_to_cpu(about_fw->fw_major);
-	ha->firmware_version[1] = le16_to_cpu(about_fw->fw_minor);
-	ha->patch_number = le16_to_cpu(about_fw->fw_patch);
-	ha->build_number = le16_to_cpu(about_fw->fw_build);
-	ha->iscsi_major = le16_to_cpu(about_fw->iscsi_major);
-	ha->iscsi_minor = le16_to_cpu(about_fw->iscsi_minor);
-	ha->bootload_major = le16_to_cpu(about_fw->bootload_major);
-	ha->bootload_minor = le16_to_cpu(about_fw->bootload_minor);
-	ha->bootload_patch = le16_to_cpu(about_fw->bootload_patch);
-	ha->bootload_build = le16_to_cpu(about_fw->bootload_build);
+	ha->fw_info.fw_major = le16_to_cpu(about_fw->fw_major);
+	ha->fw_info.fw_minor = le16_to_cpu(about_fw->fw_minor);
+	ha->fw_info.fw_patch = le16_to_cpu(about_fw->fw_patch);
+	ha->fw_info.fw_build = le16_to_cpu(about_fw->fw_build);
+	memcpy(ha->fw_info.fw_build_date, about_fw->fw_build_date,
+	       sizeof(about_fw->fw_build_date));
+	memcpy(ha->fw_info.fw_build_time, about_fw->fw_build_time,
+	       sizeof(about_fw->fw_build_time));
+	strcpy((char *)ha->fw_info.fw_build_user,
+	       skip_spaces((char *)about_fw->fw_build_user));
+	ha->fw_info.fw_load_source = le16_to_cpu(about_fw->fw_load_source);
+	ha->fw_info.iscsi_major = le16_to_cpu(about_fw->iscsi_major);
+	ha->fw_info.iscsi_minor = le16_to_cpu(about_fw->iscsi_minor);
+	ha->fw_info.bootload_major = le16_to_cpu(about_fw->bootload_major);
+	ha->fw_info.bootload_minor = le16_to_cpu(about_fw->bootload_minor);
+	ha->fw_info.bootload_patch = le16_to_cpu(about_fw->bootload_patch);
+	ha->fw_info.bootload_build = le16_to_cpu(about_fw->bootload_build);
+	strcpy((char *)ha->fw_info.extended_timestamp,
+	       skip_spaces((char *)about_fw->extended_timestamp));
+
+	ha->fw_uptime_secs = le32_to_cpu(mbox_sts[5]);
+	ha->fw_uptime_msecs = le32_to_cpu(mbox_sts[6]);
 	status = QLA_SUCCESS;
 
 exit_about_fw:
@@ -1723,6 +1736,45 @@
 	return status;
 }
 
+/**
+ * qla4_84xx_extend_idc_tmo - Extend IDC Timeout.
+ * @ha: Pointer to host adapter structure.
+ * @ext_tmo: idc timeout value
+ *
+ * Requests firmware to extend the idc timeout value.
+ **/
+static int qla4_84xx_extend_idc_tmo(struct scsi_qla_host *ha, uint32_t ext_tmo)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+	int status;
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+	ext_tmo &= 0xf;
+
+	mbox_cmd[0] = MBOX_CMD_IDC_TIME_EXTEND;
+	mbox_cmd[1] = ((ha->idc_info.request_desc & 0xfffff0ff) |
+		       (ext_tmo << 8));		/* new timeout */
+	mbox_cmd[2] = ha->idc_info.info1;
+	mbox_cmd[3] = ha->idc_info.info2;
+	mbox_cmd[4] = ha->idc_info.info3;
+
+	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
+					 mbox_cmd, mbox_sts);
+	if (status != QLA_SUCCESS) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "scsi%ld: %s: failed status %04X\n",
+				  ha->host_no, __func__, mbox_sts[0]));
+		return QLA_ERROR;
+	} else {
+		ql4_printk(KERN_INFO, ha, "%s: IDC timeout extended by %d secs\n",
+			   __func__, ext_tmo);
+	}
+
+	return QLA_SUCCESS;
+}
+
 int qla4xxx_disable_acb(struct scsi_qla_host *ha)
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
@@ -1739,6 +1791,23 @@
 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_DISABLE_ACB "
 				  "failed w/ status %04X %04X %04X", __func__,
 				  mbox_sts[0], mbox_sts[1], mbox_sts[2]));
+	} else {
+		if (is_qla8042(ha) &&
+		    (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE)) {
+			/*
+			 * Disable ACB mailbox command takes time to complete
+			 * based on the total number of targets connected.
+			 * For 512 targets, it took approximately 5 secs to
+			 * complete. Setting the timeout value to 8, with the 3
+			 * secs buffer.
+			 */
+			qla4_84xx_extend_idc_tmo(ha, IDC_EXTEND_TOV);
+			if (!wait_for_completion_timeout(&ha->disable_acb_comp,
+							 IDC_EXTEND_TOV * HZ)) {
+				ql4_printk(KERN_WARNING, ha, "%s: Disable ACB Completion not received\n",
+					   __func__);
+			}
+		}
 	}
 	return status;
 }
@@ -2145,8 +2214,80 @@
 		ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", __func__,
 			   mbox_sts[0]);
 	else
-	       DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IDC ACK posted\n",
-				 __func__));
+	       ql4_printk(KERN_INFO, ha, "%s: IDC ACK posted\n", __func__);
 
 	return status;
 }
+
+int qla4_84xx_config_acb(struct scsi_qla_host *ha, int acb_config)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+	struct addr_ctrl_blk *acb = NULL;
+	uint32_t acb_len = sizeof(struct addr_ctrl_blk);
+	int rval = QLA_SUCCESS;
+	dma_addr_t acb_dma;
+
+	acb = dma_alloc_coherent(&ha->pdev->dev,
+				 sizeof(struct addr_ctrl_blk),
+				 &acb_dma, GFP_KERNEL);
+	if (!acb) {
+		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", __func__);
+		rval = QLA_ERROR;
+		goto exit_config_acb;
+	}
+	memset(acb, 0, acb_len);
+
+	switch (acb_config) {
+	case ACB_CONFIG_DISABLE:
+		rval = qla4xxx_get_acb(ha, acb_dma, 0, acb_len);
+		if (rval != QLA_SUCCESS)
+			goto exit_free_acb;
+
+		rval = qla4xxx_disable_acb(ha);
+		if (rval != QLA_SUCCESS)
+			goto exit_free_acb;
+
+		if (!ha->saved_acb)
+			ha->saved_acb = kzalloc(acb_len, GFP_KERNEL);
+
+		if (!ha->saved_acb) {
+			ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
+				   __func__);
+			rval = QLA_ERROR;
+			goto exit_config_acb;
+		}
+		memcpy(ha->saved_acb, acb, acb_len);
+		break;
+	case ACB_CONFIG_SET:
+
+		if (!ha->saved_acb) {
+			ql4_printk(KERN_ERR, ha, "%s: Can't set ACB, Saved ACB not available\n",
+				   __func__);
+			rval = QLA_ERROR;
+			goto exit_free_acb;
+		}
+
+		memcpy(acb, ha->saved_acb, acb_len);
+		kfree(ha->saved_acb);
+		ha->saved_acb = NULL;
+
+		rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
+		if (rval != QLA_SUCCESS)
+			goto exit_free_acb;
+
+		break;
+	default:
+		ql4_printk(KERN_ERR, ha, "%s: Invalid ACB Configuration\n",
+			   __func__);
+	}
+
+exit_free_acb:
+	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), acb,
+			  acb_dma);
+exit_config_acb:
+	DEBUG2(ql4_printk(KERN_INFO, ha,
+			  "%s %s\n", __func__,
+			  rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
+	return rval;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index 325db1f..3bf418f 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
index dba0514..e97d79f 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.h
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index eaf00c1..d001202 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -1514,11 +1514,11 @@
 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
 
 	/*
-	 * For ISP8324, drv_active register has 1 bit per function,
+	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
 	 * shift 1 by func_num to set a bit for the function.
 	 * For ISP8022, drv_active has 4 bits per function
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		drv_active |= (1 << ha->func_num);
 	else
 		drv_active |= (1 << (ha->func_num * 4));
@@ -1536,11 +1536,11 @@
 	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
 
 	/*
-	 * For ISP8324, drv_active register has 1 bit per function,
+	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
 	 * shift 1 by func_num to set a bit for the function.
 	 * For ISP8022, drv_active has 4 bits per function
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		drv_active &= ~(1 << (ha->func_num));
 	else
 		drv_active &= ~(1 << (ha->func_num * 4));
@@ -1559,11 +1559,11 @@
 	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
 
 	/*
-	 * For ISP8324, drv_active register has 1 bit per function,
+	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
 	 * shift 1 by func_num to set a bit for the function.
 	 * For ISP8022, drv_active has 4 bits per function
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		rval = drv_state & (1 << ha->func_num);
 	else
 		rval = drv_state & (1 << (ha->func_num * 4));
@@ -1581,11 +1581,11 @@
 	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
 
 	/*
-	 * For ISP8324, drv_active register has 1 bit per function,
+	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
 	 * shift 1 by func_num to set a bit for the function.
 	 * For ISP8022, drv_active has 4 bits per function
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		drv_state |= (1 << ha->func_num);
 	else
 		drv_state |= (1 << (ha->func_num * 4));
@@ -1602,11 +1602,11 @@
 	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
 
 	/*
-	 * For ISP8324, drv_active register has 1 bit per function,
+	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
 	 * shift 1 by func_num to set a bit for the function.
 	 * For ISP8022, drv_active has 4 bits per function
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		drv_state &= ~(1 << ha->func_num);
 	else
 		drv_state &= ~(1 << (ha->func_num * 4));
@@ -1624,11 +1624,11 @@
 	qsnt_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
 
 	/*
-	 * For ISP8324, drv_active register has 1 bit per function,
+	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
 	 * shift 1 by func_num to set a bit for the function.
 	 * For ISP8022, drv_active has 4 bits per function.
 	 */
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		qsnt_state |= (1 << ha->func_num);
 	else
 		qsnt_state |= (2 << (ha->func_num * 4));
@@ -1737,6 +1737,208 @@
 	*d_ptr = data_ptr;
 }
 
+static int qla4_83xx_check_dma_engine_state(struct scsi_qla_host *ha)
+{
+	int rval = QLA_SUCCESS;
+	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+	uint64_t dma_base_addr = 0;
+	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;
+
+	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
+							ha->fw_dump_tmplt_hdr;
+	dma_eng_num =
+		tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
+	dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
+				(dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);
+
+	/* Read the pex-dma's command-status-and-control register. */
+	rval = ha->isp_ops->rd_reg_indirect(ha,
+			(dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
+			&cmd_sts_and_cntrl);
+
+	if (rval)
+		return QLA_ERROR;
+
+	/* Check if requested pex-dma engine is available. */
+	if (cmd_sts_and_cntrl & BIT_31)
+		return QLA_SUCCESS;
+	else
+		return QLA_ERROR;
+}
+
+static int qla4_83xx_start_pex_dma(struct scsi_qla_host *ha,
+			   struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr)
+{
+	int rval = QLA_SUCCESS, wait = 0;
+	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
+	uint64_t dma_base_addr = 0;
+	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;
+
+	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
+							ha->fw_dump_tmplt_hdr;
+	dma_eng_num =
+		tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
+	dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
+				(dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);
+
+	rval = ha->isp_ops->wr_reg_indirect(ha,
+				dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_LOW,
+				m_hdr->desc_card_addr);
+	if (rval)
+		goto error_exit;
+
+	rval = ha->isp_ops->wr_reg_indirect(ha,
+			      dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_HIGH, 0);
+	if (rval)
+		goto error_exit;
+
+	rval = ha->isp_ops->wr_reg_indirect(ha,
+			      dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL,
+			      m_hdr->start_dma_cmd);
+	if (rval)
+		goto error_exit;
+
+	/* Wait for dma operation to complete. */
+	for (wait = 0; wait < QLA83XX_PEX_DMA_MAX_WAIT; wait++) {
+		rval = ha->isp_ops->rd_reg_indirect(ha,
+			    (dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
+			    &cmd_sts_and_cntrl);
+		if (rval)
+			goto error_exit;
+
+		if ((cmd_sts_and_cntrl & BIT_1) == 0)
+			break;
+		else
+			udelay(10);
+	}
+
+	/* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
+	if (wait >= QLA83XX_PEX_DMA_MAX_WAIT) {
+		rval = QLA_ERROR;
+		goto error_exit;
+	}
+
+error_exit:
+	return rval;
+}
+
+static int qla4_83xx_minidump_pex_dma_read(struct scsi_qla_host *ha,
+				struct qla8xxx_minidump_entry_hdr *entry_hdr,
+				uint32_t **d_ptr)
+{
+	int rval = QLA_SUCCESS;
+	struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
+	uint32_t size, read_size;
+	uint8_t *data_ptr = (uint8_t *)*d_ptr;
+	void *rdmem_buffer = NULL;
+	dma_addr_t rdmem_dma;
+	struct qla4_83xx_pex_dma_descriptor dma_desc;
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
+
+	rval = qla4_83xx_check_dma_engine_state(ha);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "%s: DMA engine not available. Fallback to rdmem-read.\n",
+				  __func__));
+		return QLA_ERROR;
+	}
+
+	m_hdr = (struct qla4_83xx_minidump_entry_rdmem_pex_dma *)entry_hdr;
+	rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
+					  QLA83XX_PEX_DMA_READ_SIZE,
+					  &rdmem_dma, GFP_KERNEL);
+	if (!rdmem_buffer) {
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "%s: Unable to allocate rdmem dma buffer\n",
+				  __func__));
+		return QLA_ERROR;
+	}
+
+	/* Prepare pex-dma descriptor to be written to MS memory. */
+	/* dma-desc-cmd layout:
+	 *              0-3: dma-desc-cmd 0-3
+	 *              4-7: pcid function number
+	 *              8-15: dma-desc-cmd 8-15
+	 */
+	dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
+	dma_desc.cmd.dma_desc_cmd |= ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
+	dma_desc.dma_bus_addr = rdmem_dma;
+
+	size = 0;
+	read_size = 0;
+	/*
+	 * Perform rdmem operation using pex-dma.
+	 * Prepare dma in chunks of QLA83XX_PEX_DMA_READ_SIZE.
+	 */
+	while (read_size < m_hdr->read_data_size) {
+		if (m_hdr->read_data_size - read_size >=
+		    QLA83XX_PEX_DMA_READ_SIZE)
+			size = QLA83XX_PEX_DMA_READ_SIZE;
+		else {
+			size = (m_hdr->read_data_size - read_size);
+
+			if (rdmem_buffer)
+				dma_free_coherent(&ha->pdev->dev,
+						  QLA83XX_PEX_DMA_READ_SIZE,
+						  rdmem_buffer, rdmem_dma);
+
+			rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev, size,
+							  &rdmem_dma,
+							  GFP_KERNEL);
+			if (!rdmem_buffer) {
+				DEBUG2(ql4_printk(KERN_INFO, ha,
+						  "%s: Unable to allocate rdmem dma buffer\n",
+						  __func__));
+				return QLA_ERROR;
+			}
+			dma_desc.dma_bus_addr = rdmem_dma;
+		}
+
+		dma_desc.src_addr = m_hdr->read_addr + read_size;
+		dma_desc.cmd.read_data_size = size;
+
+		/* Prepare: Write pex-dma descriptor to MS memory. */
+		rval = qla4_83xx_ms_mem_write_128b(ha,
+			      (uint64_t)m_hdr->desc_card_addr,
+			      (uint32_t *)&dma_desc,
+			      (sizeof(struct qla4_83xx_pex_dma_descriptor)/16));
+		if (rval == -1) {
+			ql4_printk(KERN_INFO, ha,
+				   "%s: Error writing rdmem-dma-init to MS !!!\n",
+				   __func__);
+			goto error_exit;
+		}
+
+		DEBUG2(ql4_printk(KERN_INFO, ha,
+				  "%s: Dma-desc: Instruct for rdmem dma (size 0x%x).\n",
+				  __func__, size));
+		/* Execute: Start pex-dma operation. */
+		rval = qla4_83xx_start_pex_dma(ha, m_hdr);
+		if (rval != QLA_SUCCESS) {
+			DEBUG2(ql4_printk(KERN_INFO, ha,
+					  "scsi(%ld): start-pex-dma failed rval=0x%x\n",
+					  ha->host_no, rval));
+			goto error_exit;
+		}
+
+		memcpy(data_ptr, rdmem_buffer, size);
+		data_ptr += size;
+		read_size += size;
+	}
+
+	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__));
+
+	*d_ptr = (uint32_t *)data_ptr;
+
+error_exit:
+	if (rdmem_buffer)
+		dma_free_coherent(&ha->pdev->dev, size, rdmem_buffer,
+				  rdmem_dma);
+
+	return rval;
+}
+
 static int qla4_8xxx_minidump_process_l2tag(struct scsi_qla_host *ha,
 				 struct qla8xxx_minidump_entry_hdr *entry_hdr,
 				 uint32_t **d_ptr)
@@ -2068,7 +2270,7 @@
 #define MD_MIU_TEST_AGT_ADDR_LO		0x41000094
 #define MD_MIU_TEST_AGT_ADDR_HI		0x41000098
 
-static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
+static int __qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
 				struct qla8xxx_minidump_entry_hdr *entry_hdr,
 				uint32_t **d_ptr)
 {
@@ -2150,6 +2352,28 @@
 	return QLA_SUCCESS;
 }
 
+static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
+				struct qla8xxx_minidump_entry_hdr *entry_hdr,
+				uint32_t **d_ptr)
+{
+	uint32_t *data_ptr = *d_ptr;
+	int rval = QLA_SUCCESS;
+
+	if (is_qla8032(ha) || is_qla8042(ha)) {
+		rval = qla4_83xx_minidump_pex_dma_read(ha, entry_hdr,
+						       &data_ptr);
+		if (rval != QLA_SUCCESS) {
+			rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
+								  &data_ptr);
+		}
+	} else {
+		rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
+							  &data_ptr);
+	}
+	*d_ptr = data_ptr;
+	return rval;
+}
+
 static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
 				struct qla8xxx_minidump_entry_hdr *entry_hdr,
 				int index)
@@ -2398,13 +2622,13 @@
 					(((uint8_t *)ha->fw_dump_tmplt_hdr) +
 					 tmplt_hdr->first_entry_offset);
 
-	if (is_qla8032(ha))
+	if (is_qla8032(ha) || is_qla8042(ha))
 		tmplt_hdr->saved_state_array[QLA83XX_SS_OCM_WNDREG_INDEX] =
 					tmplt_hdr->ocm_window_reg[ha->func_num];
 
 	/* Walk through the entry headers - validate/perform required action */
 	for (i = 0; i < num_entry_hdr; i++) {
-		if (data_collected >= ha->fw_dump_size) {
+		if (data_collected > ha->fw_dump_size) {
 			ql4_printk(KERN_INFO, ha,
 				   "Data collected: [0x%x], Total Dump size: [0x%x]\n",
 				   data_collected, ha->fw_dump_size);
@@ -2455,7 +2679,7 @@
 			if (is_qla8022(ha)) {
 				qla4_82xx_minidump_process_rdrom(ha, entry_hdr,
 								 &data_ptr);
-			} else if (is_qla8032(ha)) {
+			} else if (is_qla8032(ha) || is_qla8042(ha)) {
 				rval = qla4_83xx_minidump_process_rdrom(ha,
 								    entry_hdr,
 								    &data_ptr);
@@ -2496,7 +2720,7 @@
 							 &data_ptr);
 			break;
 		case QLA83XX_POLLRD:
-			if (!is_qla8032(ha)) {
+			if (is_qla8022(ha)) {
 				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
 				break;
 			}
@@ -2506,7 +2730,7 @@
 				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
 			break;
 		case QLA83XX_RDMUX2:
-			if (!is_qla8032(ha)) {
+			if (is_qla8022(ha)) {
 				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
 				break;
 			}
@@ -2514,7 +2738,7 @@
 							&data_ptr);
 			break;
 		case QLA83XX_POLLRDMWR:
-			if (!is_qla8032(ha)) {
+			if (is_qla8022(ha)) {
 				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
 				break;
 			}
@@ -2529,9 +2753,7 @@
 			break;
 		}
 
-		data_collected = (uint8_t *)data_ptr -
-				 ((uint8_t *)((uint8_t *)ha->fw_dump +
-						ha->fw_dump_tmplt_size));
+		data_collected = (uint8_t *)data_ptr - (uint8_t *)ha->fw_dump;
 skip_nxt_entry:
 		/*  next entry in the template */
 		entry_hdr = (struct qla8xxx_minidump_entry_hdr *)
@@ -2539,10 +2761,11 @@
 				 entry_hdr->entry_size);
 	}
 
-	if ((data_collected + ha->fw_dump_tmplt_size) != ha->fw_dump_size) {
+	if (data_collected != ha->fw_dump_size) {
 		ql4_printk(KERN_INFO, ha,
 			   "Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x]\n",
 			   data_collected, ha->fw_dump_size);
+		rval = QLA_ERROR;
 		goto md_failed;
 	}
 
@@ -2642,10 +2865,10 @@
 			    QLA8XXX_DEV_INITIALIZING);
 
 	/*
-	 * For ISP8324, if IDC_CTRL GRACEFUL_RESET_BIT1 is set, reset it after
-	 * device goes to INIT state.
+	 * For ISP8324 and ISP8042, if IDC_CTRL GRACEFUL_RESET_BIT1 is set,
+	 * reset it after device goes to INIT state.
 	 */
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
 		if (idc_ctrl & GRACEFUL_RESET_BIT1) {
 			qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
@@ -2846,7 +3069,7 @@
 	 * If we are the first driver to load and
 	 * ql4xdontresethba is not set, clear IDC_CTRL BIT0.
 	 */
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
 		if ((drv_active == (1 << ha->func_num)) && !ql4xdontresethba)
 			qla4_83xx_clear_idc_dontreset(ha);
@@ -2854,7 +3077,7 @@
 
 	if (is_qla8022(ha)) {
 		qla4_82xx_set_idc_ver(ha);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		rval = qla4_83xx_set_idc_ver(ha);
 		if (rval == QLA_ERROR)
 			qla4_8xxx_clear_drv_active(ha);
@@ -2922,11 +3145,11 @@
 			break;
 		case QLA8XXX_DEV_NEED_RESET:
 			/*
-			 * For ISP8324, if NEED_RESET is set by any driver,
-			 * it should be honored, irrespective of IDC_CTRL
-			 * DONTRESET_BIT0
+			 * For ISP8324 and ISP8042, if NEED_RESET is set by any
+			 * driver, it should be honored, irrespective of
+			 * IDC_CTRL DONTRESET_BIT0
 			 */
-			if (is_qla8032(ha)) {
+			if (is_qla8032(ha) || is_qla8042(ha)) {
 				qla4_83xx_need_reset_handler(ha);
 			} else if (is_qla8022(ha)) {
 				if (!ql4xdontresethba) {
@@ -2976,7 +3199,7 @@
 	int retval;
 
 	/* clear the interrupt */
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		writel(0, &ha->qla4_83xx_reg->risc_intr);
 		readl(&ha->qla4_83xx_reg->risc_intr);
 	} else if (is_qla8022(ha)) {
@@ -3094,7 +3317,7 @@
 	if (is_qla8022(ha)) {
 		qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
 					   flt_addr << 2, OPTROM_BURST_SIZE);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		status = qla4_83xx_flash_read_u32(ha, flt_addr << 2,
 						  (uint8_t *)ha->request_ring,
 						  0x400);
@@ -3326,7 +3549,7 @@
 	if (is_qla8022(ha)) {
 		qla4_82xx_get_fdt_info(ha);
 		qla4_82xx_get_idc_param(ha);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		qla4_83xx_get_idc_param(ha);
 	}
 
@@ -3436,7 +3659,7 @@
 	}
 
 	/* Make sure we receive the minimum required data to cache internally */
-	if ((is_qla8032(ha) ? mbox_sts[3] : mbox_sts[4]) <
+	if (((is_qla8032(ha) || is_qla8042(ha)) ? mbox_sts[3] : mbox_sts[4]) <
 	    offsetof(struct mbx_sys_info, reserved)) {
 		DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive"
 		    " error (%x)\n", ha->host_no, __func__, mbox_sts[4]));
diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h
index 9dc0bbf..14500a0 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.h
+++ b/drivers/scsi/qla4xxx/ql4_nx.h
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index b246b3c..f8a0a26 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1,6 +1,6 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
@@ -378,6 +378,44 @@
 		case ISCSI_PARAM_PASSWORD:
 		case ISCSI_PARAM_USERNAME_IN:
 		case ISCSI_PARAM_PASSWORD_IN:
+		case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
+		case ISCSI_PARAM_DISCOVERY_SESS:
+		case ISCSI_PARAM_PORTAL_TYPE:
+		case ISCSI_PARAM_CHAP_AUTH_EN:
+		case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
+		case ISCSI_PARAM_BIDI_CHAP_EN:
+		case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
+		case ISCSI_PARAM_DEF_TIME2WAIT:
+		case ISCSI_PARAM_DEF_TIME2RETAIN:
+		case ISCSI_PARAM_HDRDGST_EN:
+		case ISCSI_PARAM_DATADGST_EN:
+		case ISCSI_PARAM_INITIAL_R2T_EN:
+		case ISCSI_PARAM_IMM_DATA_EN:
+		case ISCSI_PARAM_PDU_INORDER_EN:
+		case ISCSI_PARAM_DATASEQ_INORDER_EN:
+		case ISCSI_PARAM_MAX_SEGMENT_SIZE:
+		case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
+		case ISCSI_PARAM_TCP_WSF_DISABLE:
+		case ISCSI_PARAM_TCP_NAGLE_DISABLE:
+		case ISCSI_PARAM_TCP_TIMER_SCALE:
+		case ISCSI_PARAM_TCP_TIMESTAMP_EN:
+		case ISCSI_PARAM_TCP_XMIT_WSF:
+		case ISCSI_PARAM_TCP_RECV_WSF:
+		case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
+		case ISCSI_PARAM_IPV4_TOS:
+		case ISCSI_PARAM_IPV6_TC:
+		case ISCSI_PARAM_IPV6_FLOW_LABEL:
+		case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
+		case ISCSI_PARAM_KEEPALIVE_TMO:
+		case ISCSI_PARAM_LOCAL_PORT:
+		case ISCSI_PARAM_ISID:
+		case ISCSI_PARAM_TSID:
+		case ISCSI_PARAM_DEF_TASKMGMT_TMO:
+		case ISCSI_PARAM_ERL:
+		case ISCSI_PARAM_STATSN:
+		case ISCSI_PARAM_EXP_STATSN:
+		case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
+		case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
 			return S_IRUGO;
 		default:
 			return 0;
@@ -2218,19 +2256,23 @@
 	fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
 	fw_ddb_entry->tcp_xmt_wsf = (uint8_t) cpu_to_le32(conn->tcp_xmit_wsf);
 	fw_ddb_entry->tcp_rcv_wsf = (uint8_t) cpu_to_le32(conn->tcp_recv_wsf);
-	fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
 	fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
 	fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
 	fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
 	fw_ddb_entry->stat_sn = cpu_to_le32(conn->statsn);
 	fw_ddb_entry->exp_stat_sn = cpu_to_le32(conn->exp_statsn);
-	fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_type);
+	fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_idx);
 	fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
 	fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
 	fw_ddb_entry->port = cpu_to_le16(conn->port);
 	fw_ddb_entry->def_timeout =
 				cpu_to_le16(sess->default_taskmgmt_timeout);
 
+	if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
+		fw_ddb_entry->ipv4_tos = conn->ipv6_traffic_class;
+	else
+		fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
+
 	if (conn->ipaddress)
 		memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
 		       sizeof(fw_ddb_entry->ip_addr));
@@ -2257,6 +2299,101 @@
 	return rc;
 }
 
+static void qla4xxx_copy_to_sess_conn_params(struct iscsi_conn *conn,
+					     struct iscsi_session *sess,
+					     struct dev_db_entry *fw_ddb_entry)
+{
+	unsigned long options = 0;
+	uint16_t ddb_link;
+	uint16_t disc_parent;
+
+	options = le16_to_cpu(fw_ddb_entry->options);
+	conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
+	sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
+					      &options);
+	sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
+
+	options = le16_to_cpu(fw_ddb_entry->iscsi_options);
+	conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
+	conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
+	sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
+	sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
+	sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
+					    &options);
+	sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
+	sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
+	sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
+					     &options);
+	sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
+	sess->discovery_auth_optional =
+			test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
+	if (test_bit(ISCSIOPT_ERL1, &options))
+		sess->erl |= BIT_1;
+	if (test_bit(ISCSIOPT_ERL0, &options))
+		sess->erl |= BIT_0;
+
+	options = le16_to_cpu(fw_ddb_entry->tcp_options);
+	conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
+	conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
+	conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
+	if (test_bit(TCPOPT_TIMER_SCALE3, &options))
+		conn->tcp_timer_scale |= BIT_3;
+	if (test_bit(TCPOPT_TIMER_SCALE2, &options))
+		conn->tcp_timer_scale |= BIT_2;
+	if (test_bit(TCPOPT_TIMER_SCALE1, &options))
+		conn->tcp_timer_scale |= BIT_1;
+
+	conn->tcp_timer_scale >>= 1;
+	conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
+
+	options = le16_to_cpu(fw_ddb_entry->ip_options);
+	conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
+
+	conn->max_recv_dlength = BYTE_UNITS *
+			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
+	conn->max_xmit_dlength = BYTE_UNITS *
+			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
+	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
+	sess->first_burst = BYTE_UNITS *
+			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
+	sess->max_burst = BYTE_UNITS *
+				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
+	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
+	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
+	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+	conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
+	conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
+	conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
+	conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
+	conn->keepalive_tmo = le16_to_cpu(fw_ddb_entry->ka_timeout);
+	conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
+	conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
+	conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
+	sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
+	COPY_ISID(sess->isid, fw_ddb_entry->isid);
+
+	ddb_link = le16_to_cpu(fw_ddb_entry->ddb_link);
+	if (ddb_link < MAX_DDB_ENTRIES)
+		sess->discovery_parent_idx = ddb_link;
+	else
+		sess->discovery_parent_idx = DDB_NO_LINK;
+
+	if (ddb_link == DDB_ISNS)
+		disc_parent = ISCSI_DISC_PARENT_ISNS;
+	else if (ddb_link == DDB_NO_LINK)
+		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
+	else if (ddb_link < MAX_DDB_ENTRIES)
+		disc_parent = ISCSI_DISC_PARENT_SENDTGT;
+	else
+		disc_parent = ISCSI_DISC_PARENT_UNKNOWN;
+
+	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
+			iscsi_get_discovery_parent_name(disc_parent), 0);
+
+	iscsi_set_param(conn->cls_conn, ISCSI_PARAM_TARGET_ALIAS,
+			(char *)fw_ddb_entry->iscsi_alias, 0);
+}
+
 static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
 				     struct dev_db_entry *fw_ddb_entry,
 				     struct iscsi_cls_session *cls_sess,
@@ -2275,47 +2412,29 @@
 
 	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
 
-	conn->max_recv_dlength = BYTE_UNITS *
-			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
+	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
 
-	conn->max_xmit_dlength = BYTE_UNITS *
-			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
-
-	sess->initial_r2t_en =
-			    (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
-	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
-
-	sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
-	sess->first_burst = BYTE_UNITS *
-			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
-
-	sess->max_burst = BYTE_UNITS *
-				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
-
-	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
-
-	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
-
+	sess->def_taskmgmt_tmo = le16_to_cpu(fw_ddb_entry->def_timeout);
 	conn->persistent_port = le16_to_cpu(fw_ddb_entry->port);
 
-	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
-
+	memset(ip_addr, 0, sizeof(ip_addr));
 	options = le16_to_cpu(fw_ddb_entry->options);
-	if (options & DDB_OPT_IPV6_DEVICE)
-		sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
-	else
-		sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
+	if (options & DDB_OPT_IPV6_DEVICE) {
+		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv6", 4);
 
+		memset(ip_addr, 0, sizeof(ip_addr));
+		sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr);
+	} else {
+		iscsi_set_param(cls_conn, ISCSI_PARAM_PORTAL_TYPE, "ipv4", 4);
+		sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr);
+	}
+
+	iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
+			(char *)ip_addr, buflen);
 	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME,
 			(char *)fw_ddb_entry->iscsi_name, buflen);
 	iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME,
 			(char *)ha->name_string, buflen);
-	iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS,
-			(char *)ip_addr, buflen);
-	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS,
-			(char *)fw_ddb_entry->iscsi_alias, buflen);
 }
 
 void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha,
@@ -2403,37 +2522,11 @@
 
 	/* Update params */
 	ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
-	conn->max_recv_dlength = BYTE_UNITS *
-			  le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
-
-	conn->max_xmit_dlength = BYTE_UNITS *
-			  le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
-
-	sess->initial_r2t_en =
-			    (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
-	sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
-
-	sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options));
-
-	sess->first_burst = BYTE_UNITS *
-			       le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
-
-	sess->max_burst = BYTE_UNITS *
-				 le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
-
-	sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
-
-	sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
-
-	sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+	qla4xxx_copy_to_sess_conn_params(conn, sess, fw_ddb_entry);
 
 	memcpy(sess->initiatorname, ha->name_string,
 	       min(sizeof(ha->name_string), sizeof(sess->initiatorname)));
 
-	iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS,
-			(char *)fw_ddb_entry->iscsi_alias, 0);
-
 exit_session_conn_param:
 	if (fw_ddb_entry)
 		dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
@@ -2578,6 +2671,8 @@
 	    !test_bit(AF_ONLINE, &ha->flags) ||
 	    !test_bit(AF_LINK_UP, &ha->flags) ||
 	    test_bit(AF_LOOPBACK, &ha->flags) ||
+	    test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) ||
+	    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags) ||
 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))
 		goto qc_host_busy;
 
@@ -2652,7 +2747,7 @@
 		if (ha->nx_pcibase)
 			iounmap(
 			    (struct device_reg_82xx __iomem *)ha->nx_pcibase);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		if (ha->nx_pcibase)
 			iounmap(
 			    (struct device_reg_83xx __iomem *)ha->nx_pcibase);
@@ -2846,7 +2941,7 @@
 				   __func__);
 		if (halt_status & HALT_STATUS_UNRECOVERABLE)
 			halt_status_unrecoverable = 1;
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		if (halt_status & QLA83XX_HALT_STATUS_FW_RESET)
 			ql4_printk(KERN_ERR, ha, "%s: Firmware error detected device is being reset\n",
 				   __func__);
@@ -2901,7 +2996,7 @@
 			ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
 				   __func__);
 
-			if (is_qla8032(ha)) {
+			if (is_qla8032(ha) || is_qla8042(ha)) {
 				idc_ctrl = qla4_83xx_rd_reg(ha,
 							QLA83XX_IDC_DRV_CTRL);
 				if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
@@ -2912,7 +3007,7 @@
 				}
 			}
 
-			if (is_qla8032(ha) ||
+			if ((is_qla8032(ha) || is_qla8042(ha)) ||
 			    (is_qla8022(ha) && !ql4xdontresethba)) {
 				set_bit(DPC_RESET_HA, &ha->dpc_flags);
 				qla4xxx_wake_dpc(ha);
@@ -3296,7 +3391,7 @@
 
 	set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags);
 
-	if (is_qla8032(ha) &&
+	if ((is_qla8032(ha) || is_qla8042(ha)) &&
 	    !test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) {
 		ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
 			   __func__);
@@ -3494,7 +3589,9 @@
 		} else {
 			/* Trigger relogin */
 			if (ddb_entry->ddb_type == FLASH_DDB) {
-				if (!test_bit(DF_RELOGIN, &ddb_entry->flags))
+				if (!(test_bit(DF_RELOGIN, &ddb_entry->flags) ||
+				      test_bit(DF_DISABLE_RELOGIN,
+					       &ddb_entry->flags)))
 					qla4xxx_arm_relogin_timer(ddb_entry);
 			} else
 				iscsi_session_failure(cls_session->dd_data,
@@ -3597,6 +3694,9 @@
 	if (!(ddb_entry->ddb_type == FLASH_DDB))
 		return;
 
+	if (test_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
+		return;
+
 	if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
 	    !iscsi_is_session_online(cls_sess)) {
 		DEBUG2(ql4_printk(KERN_INFO, ha,
@@ -3750,7 +3850,7 @@
 
 	if (is_qla80XX(ha)) {
 		if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
-			if (is_qla8032(ha)) {
+			if (is_qla8032(ha) || is_qla8042(ha)) {
 				ql4_printk(KERN_INFO, ha, "%s: disabling pause transmit on port 0 & 1.\n",
 					   __func__);
 				/* disable pause frame for ISP83xx */
@@ -3765,8 +3865,35 @@
 			qla4_8xxx_device_state_handler(ha);
 		}
 
-		if (test_and_clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags))
+		if (test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags)) {
+			if (is_qla8042(ha)) {
+				if (ha->idc_info.info2 &
+				    ENABLE_INTERNAL_LOOPBACK) {
+					ql4_printk(KERN_INFO, ha, "%s: Disabling ACB\n",
+						   __func__);
+					status = qla4_84xx_config_acb(ha,
+							    ACB_CONFIG_DISABLE);
+					if (status != QLA_SUCCESS) {
+						ql4_printk(KERN_INFO, ha, "%s: ACB config failed\n",
+							   __func__);
+					}
+				}
+			}
 			qla4_83xx_post_idc_ack(ha);
+			clear_bit(DPC_POST_IDC_ACK, &ha->dpc_flags);
+		}
+
+		if (is_qla8042(ha) &&
+		    test_bit(DPC_RESTORE_ACB, &ha->dpc_flags)) {
+			ql4_printk(KERN_INFO, ha, "%s: Restoring ACB\n",
+				   __func__);
+			if (qla4_84xx_config_acb(ha, ACB_CONFIG_SET) !=
+			    QLA_SUCCESS) {
+				ql4_printk(KERN_INFO, ha, "%s: ACB config failed ",
+					   __func__);
+			}
+			clear_bit(DPC_RESTORE_ACB, &ha->dpc_flags);
+		}
 
 		if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) {
 			qla4_8xxx_need_qsnt_handler(ha);
@@ -3778,7 +3905,8 @@
 	    test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
 	    test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) {
 		if ((is_qla8022(ha) && ql4xdontresethba) ||
-		    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+		    ((is_qla8032(ha) || is_qla8042(ha)) &&
+		     qla4_83xx_idc_dontreset(ha))) {
 			DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
 			    ha->host_no, __func__));
 			clear_bit(DPC_RESET_HA, &ha->dpc_flags);
@@ -3870,7 +3998,7 @@
 	} else if (is_qla8022(ha)) {
 		writel(0, &ha->qla4_82xx_reg->host_int);
 		readl(&ha->qla4_82xx_reg->host_int);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		writel(0, &ha->qla4_83xx_reg->risc_intr);
 		readl(&ha->qla4_83xx_reg->risc_intr);
 	}
@@ -3945,7 +4073,7 @@
 				     (ha->pdev->devfn << 11));
 		ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 :
 				    QLA82XX_CAM_RAM_DB2);
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		ha->qla4_83xx_reg = (struct device_reg_83xx __iomem *)
 				    ((uint8_t *)ha->nx_pcibase);
 	}
@@ -5609,7 +5737,8 @@
 		goto exit_ddb_add;
 	}
 
-	for (idx = 0; idx < max_ddbs; idx++) {
+	/* Index 0 and 1 are reserved for boot target entries */
+	for (idx = 2; idx < max_ddbs; idx++) {
 		if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
 					     fw_ddb_entry_dma, idx))
 			break;
@@ -5925,13 +6054,6 @@
 		goto exit_ddb_logout;
 	}
 
-	options = LOGOUT_OPTION_CLOSE_SESSION;
-	if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
-		ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
-		ret = -EIO;
-		goto exit_ddb_logout;
-	}
-
 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
 					  &fw_ddb_entry_dma, GFP_KERNEL);
 	if (!fw_ddb_entry) {
@@ -5941,6 +6063,38 @@
 		goto exit_ddb_logout;
 	}
 
+	if (test_and_set_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags))
+		goto ddb_logout_init;
+
+	ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
+				      fw_ddb_entry, fw_ddb_entry_dma,
+				      NULL, NULL, &ddb_state, NULL,
+				      NULL, NULL);
+	if (ret == QLA_ERROR)
+		goto ddb_logout_init;
+
+	if (ddb_state == DDB_DS_SESSION_ACTIVE)
+		goto ddb_logout_init;
+
+	/* wait until next relogin is triggered using DF_RELOGIN and
+	 * clear DF_RELOGIN to avoid invocation of further relogin
+	 */
+	wtime = jiffies + (HZ * RELOGIN_TOV);
+	do {
+		if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags))
+			goto ddb_logout_init;
+
+		schedule_timeout_uninterruptible(HZ);
+	} while ((time_after(wtime, jiffies)));
+
+ddb_logout_init:
+	atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
+	atomic_set(&ddb_entry->relogin_timer, 0);
+
+	options = LOGOUT_OPTION_CLOSE_SESSION;
+	qla4xxx_session_logout_ddb(ha, ddb_entry, options);
+
+	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
 	wtime = jiffies + (HZ * LOGOUT_TOV);
 	do {
 		ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
@@ -5970,10 +6124,12 @@
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	qla4xxx_free_ddb(ha, ddb_entry);
+	clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	iscsi_session_teardown(ddb_entry->sess);
 
+	clear_bit(DF_DISABLE_RELOGIN, &ddb_entry->flags);
 	ret = QLA_SUCCESS;
 
 exit_ddb_logout:
@@ -6110,7 +6266,7 @@
 	struct iscsi_bus_flash_conn *fnode_conn;
 	struct ql4_chap_table chap_tbl;
 	struct device *dev;
-	int parent_type, parent_index = 0xffff;
+	int parent_type;
 	int rc = 0;
 
 	dev = iscsi_find_flashnode_conn(fnode_sess);
@@ -6276,10 +6432,7 @@
 			rc = sprintf(buf, "\n");
 		break;
 	case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
-		if (fnode_sess->discovery_parent_idx < MAX_DDB_ENTRIES)
-			parent_index = fnode_sess->discovery_parent_idx;
-
-		rc = sprintf(buf, "%u\n", parent_index);
+		rc = sprintf(buf, "%u\n", fnode_sess->discovery_parent_idx);
 		break;
 	case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
 		if (fnode_sess->discovery_parent_type == DDB_ISNS)
@@ -6533,8 +6686,8 @@
 			memcpy(fnode_conn->link_local_ipv6_addr,
 			       fnode_param->value, IPv6_ADDR_LEN);
 			break;
-		case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
-			fnode_sess->discovery_parent_type =
+		case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
+			fnode_sess->discovery_parent_idx =
 						*(uint16_t *)fnode_param->value;
 			break;
 		case ISCSI_FLASHNODE_TCP_XMIT_WSF:
@@ -6910,7 +7063,7 @@
 			nx_legacy_intr->tgt_status_reg;
 		ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
 		ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
-	} else if (is_qla8032(ha)) {
+	} else if (is_qla8032(ha) || is_qla8042(ha)) {
 		ha->isp_ops = &qla4_83xx_isp_ops;
 		ha->reg_tbl = (uint32_t *)qla4_83xx_reg_tbl;
 	} else {
@@ -6981,7 +7134,7 @@
 	if (is_qla80XX(ha))
 		qla4_8xxx_get_flash_info(ha);
 
-	if (is_qla8032(ha)) {
+	if (is_qla8032(ha) || is_qla8042(ha)) {
 		qla4_83xx_read_reset_template(ha);
 		/*
 		 * NOTE: If ql4dontresethba==1, set IDC_CTRL DONTRESET_BIT0.
@@ -7036,7 +7189,8 @@
 		ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n");
 
 		if ((is_qla8022(ha) && ql4xdontresethba) ||
-		    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+		    ((is_qla8032(ha) || is_qla8042(ha)) &&
+		     qla4_83xx_idc_dontreset(ha))) {
 			/* Put the device in failed state. */
 			DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n"));
 			ha->isp_ops->idc_lock(ha);
@@ -7097,8 +7251,8 @@
 	       " QLogic iSCSI HBA Driver version: %s\n"
 	       "  QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
 	       qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
-	       ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
-	       ha->patch_number, ha->build_number);
+	       ha->host_no, ha->fw_info.fw_major, ha->fw_info.fw_minor,
+	       ha->fw_info.fw_patch, ha->fw_info.fw_build);
 
 	/* Set the driver version */
 	if (is_qla80XX(ha))
@@ -7645,16 +7799,16 @@
 
 	ha = to_qla_host(cmd->device->host);
 
-	if (is_qla8032(ha) && ql4xdontresethba)
+	if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
 		qla4_83xx_set_idc_dontreset(ha);
 
 	/*
-	 * For ISP8324, if IDC_CTRL DONTRESET_BIT0 is set by other
-	 * protocol drivers, we should not set device_state to
-	 * NEED_RESET
+	 * For ISP8324 and ISP8042, if IDC_CTRL DONTRESET_BIT0 is set by other
+	 * protocol drivers, we should not set device_state to NEED_RESET
 	 */
 	if (ql4xdontresethba ||
-	    (is_qla8032(ha) && qla4_83xx_idc_dontreset(ha))) {
+	    ((is_qla8032(ha) || is_qla8042(ha)) &&
+	     qla4_83xx_idc_dontreset(ha))) {
 		DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n",
 		     ha->host_no, __func__));
 
@@ -7779,9 +7933,10 @@
 	}
 
 recover_adapter:
-	/* For ISP83XX set graceful reset bit in IDC_DRV_CTRL if
+	/* For ISP8324 and ISP8042 set graceful reset bit in IDC_DRV_CTRL if
 	 * reset is issued by application */
-	if (is_qla8032(ha) && test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+	if ((is_qla8032(ha) || is_qla8042(ha)) &&
+	    test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
 		idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
 		qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
 				 (idc_ctrl | GRACEFUL_RESET_BIT1));
@@ -8078,6 +8233,12 @@
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
 	},
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP8042,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
 	{0, 0},
 };
 MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index fe873cf..f4fef72 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -1,8 +1,8 @@
 /*
  * QLogic iSCSI HBA Driver
- * Copyright (c)  2003-2012 QLogic Corporation
+ * Copyright (c)  2003-2013 QLogic Corporation
  *
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
-#define QLA4XXX_DRIVER_VERSION	"5.03.00-k9"
+#define QLA4XXX_DRIVER_VERSION	"5.04.00-k1"
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index cb4fefa..01c0ffa 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1997,8 +1997,14 @@
 
 static sector_t map_index_to_lba(unsigned long index)
 {
-	return index * scsi_debug_unmap_granularity -
-		scsi_debug_unmap_alignment;
+	sector_t lba = index * scsi_debug_unmap_granularity;
+
+	if (scsi_debug_unmap_alignment) {
+		lba -= scsi_debug_unmap_granularity -
+			scsi_debug_unmap_alignment;
+	}
+
+	return lba;
 }
 
 static unsigned int map_state(sector_t lba, unsigned int *num)
@@ -2659,8 +2665,8 @@
 			       / sdebug_sectors_per;
 		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
 
-		pp->start_sect = start_sec;
-		pp->nr_sects = end_sec - start_sec + 1;
+		pp->start_sect = cpu_to_le32(start_sec);
+		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
 		pp->sys_ind = 0x83;	/* plain Linux partition */
 	}
 }
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 2150596..83e591b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -223,12 +223,80 @@
 }
 #endif
 
+ /**
+ * scsi_report_lun_change - Set flag on all *other* devices on the same target
+ *                          to indicate that a UNIT ATTENTION is expected.
+ * @sdev:	Device reporting the UNIT ATTENTION
+ */
+static void scsi_report_lun_change(struct scsi_device *sdev)
+{
+	sdev->sdev_target->expecting_lun_change = 1;
+}
+
+/**
+ * scsi_report_sense - Examine scsi sense information and log messages for
+ *		       certain conditions, also issue uevents for some of them.
+ * @sdev:	Device reporting the sense code
+ * @sshdr:	sshdr to be examined
+ */
+static void scsi_report_sense(struct scsi_device *sdev,
+			      struct scsi_sense_hdr *sshdr)
+{
+	enum scsi_device_event evt_type = SDEV_EVT_MAXBITS;	/* i.e. none */
+
+	if (sshdr->sense_key == UNIT_ATTENTION) {
+		if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) {
+			evt_type = SDEV_EVT_INQUIRY_CHANGE_REPORTED;
+			sdev_printk(KERN_WARNING, sdev,
+				    "Inquiry data has changed");
+		} else if (sshdr->asc == 0x3f && sshdr->ascq == 0x0e) {
+			evt_type = SDEV_EVT_LUN_CHANGE_REPORTED;
+			scsi_report_lun_change(sdev);
+			sdev_printk(KERN_WARNING, sdev,
+				    "Warning! Received an indication that the "
+				    "LUN assignments on this target have "
+				    "changed. The Linux SCSI layer does not "
+				    "automatically remap LUN assignments.\n");
+		} else if (sshdr->asc == 0x3f)
+			sdev_printk(KERN_WARNING, sdev,
+				    "Warning! Received an indication that the "
+				    "operating parameters on this target have "
+				    "changed. The Linux SCSI layer does not "
+				    "automatically adjust these parameters.\n");
+
+		if (sshdr->asc == 0x38 && sshdr->ascq == 0x07) {
+			evt_type = SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED;
+			sdev_printk(KERN_WARNING, sdev,
+				    "Warning! Received an indication that the "
+				    "LUN reached a thin provisioning soft "
+				    "threshold.\n");
+		}
+
+		if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) {
+			evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;
+			sdev_printk(KERN_WARNING, sdev,
+				    "Mode parameters changed");
+		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {
+			evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;
+			sdev_printk(KERN_WARNING, sdev,
+				    "Capacity data has changed");
+		} else if (sshdr->asc == 0x2a)
+			sdev_printk(KERN_WARNING, sdev,
+				    "Parameters changed");
+	}
+
+	if (evt_type != SDEV_EVT_MAXBITS) {
+		set_bit(evt_type, sdev->pending_events);
+		schedule_work(&sdev->event_work);
+	}
+}
+
 /**
  * scsi_check_sense - Examine scsi cmd sense
  * @scmd:	Cmd to have sense checked.
  *
  * Return value:
- *	SUCCESS or FAILED or NEEDS_RETRY or TARGET_ERROR
+ *	SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
  *
  * Notes:
  *	When a deferred error is detected the current command has
@@ -250,6 +318,8 @@
 		 */
 		return SUCCESS;
 
+	scsi_report_sense(sdev, &sshdr);
+
 	if (scsi_sense_is_deferred(&sshdr))
 		return NEEDS_RETRY;
 
@@ -315,6 +385,14 @@
 			}
 		}
 		/*
+		 * we might also expect a cc/ua if another LUN on the target
+		 * reported a UA with an ASC/ASCQ of 3F 0E -
+		 * REPORTED LUNS DATA HAS CHANGED.
+		 */
+		if (scmd->device->sdev_target->expecting_lun_change &&
+		    sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
+			return NEEDS_RETRY;
+		/*
 		 * if the device is in the process of becoming ready, we
 		 * should retry.
 		 */
@@ -327,26 +405,6 @@
 		if (scmd->device->allow_restart &&
 		    (sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
 			return FAILED;
-
-		if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
-			scmd_printk(KERN_WARNING, scmd,
-				    "Warning! Received an indication that the "
-				    "LUN assignments on this target have "
-				    "changed. The Linux SCSI layer does not "
-				    "automatically remap LUN assignments.\n");
-		else if (sshdr.asc == 0x3f)
-			scmd_printk(KERN_WARNING, scmd,
-				    "Warning! Received an indication that the "
-				    "operating parameters on this target have "
-				    "changed. The Linux SCSI layer does not "
-				    "automatically adjust these parameters.\n");
-
-		if (sshdr.asc == 0x38 && sshdr.ascq == 0x07)
-			scmd_printk(KERN_WARNING, scmd,
-				    "Warning! Received an indication that the "
-				    "LUN reached a thin provisioning soft "
-				    "threshold.\n");
-
 		/*
 		 * Pass the UA upwards for a determination in the completion
 		 * functions.
@@ -354,18 +412,25 @@
 		return SUCCESS;
 
 		/* these are not supported */
+	case DATA_PROTECT:
+		if (sshdr.asc == 0x27 && sshdr.ascq == 0x07) {
+			/* Thin provisioning hard threshold reached */
+			set_host_byte(scmd, DID_ALLOC_FAILURE);
+			return SUCCESS;
+		}
 	case COPY_ABORTED:
 	case VOLUME_OVERFLOW:
 	case MISCOMPARE:
 	case BLANK_CHECK:
-	case DATA_PROTECT:
-		return TARGET_ERROR;
+		set_host_byte(scmd, DID_TARGET_FAILURE);
+		return SUCCESS;
 
 	case MEDIUM_ERROR:
 		if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
 		    sshdr.asc == 0x13 || /* AMNF DATA FIELD */
 		    sshdr.asc == 0x14) { /* RECORD NOT FOUND */
-			return TARGET_ERROR;
+			set_host_byte(scmd, DID_MEDIUM_ERROR);
+			return SUCCESS;
 		}
 		return NEEDS_RETRY;
 
@@ -373,14 +438,14 @@
 		if (scmd->device->retry_hwerror)
 			return ADD_TO_MLQUEUE;
 		else
-			return TARGET_ERROR;
+			set_host_byte(scmd, DID_TARGET_FAILURE);
 
 	case ILLEGAL_REQUEST:
 		if (sshdr.asc == 0x20 || /* Invalid command operation code */
 		    sshdr.asc == 0x21 || /* Logical block address out of range */
 		    sshdr.asc == 0x24 || /* Invalid field in cdb */
 		    sshdr.asc == 0x26) { /* Parameter value invalid */
-			return TARGET_ERROR;
+			set_host_byte(scmd, DID_TARGET_FAILURE);
 		}
 		return SUCCESS;
 
@@ -843,7 +908,6 @@
 		case SUCCESS:
 		case NEEDS_RETRY:
 		case FAILED:
-		case TARGET_ERROR:
 			break;
 		case ADD_TO_MLQUEUE:
 			rtn = NEEDS_RETRY;
@@ -1568,6 +1632,8 @@
 		 */
 		return ADD_TO_MLQUEUE;
 	case GOOD:
+		if (scmd->cmnd[0] == REPORT_LUNS)
+			scmd->device->sdev_target->expecting_lun_change = 0;
 		scsi_handle_queue_ramp_up(scmd->device);
 	case COMMAND_TERMINATED:
 		return SUCCESS;
@@ -1577,14 +1643,6 @@
 		rtn = scsi_check_sense(scmd);
 		if (rtn == NEEDS_RETRY)
 			goto maybe_retry;
-		else if (rtn == TARGET_ERROR) {
-			/*
-			 * Need to modify host byte to signal a
-			 * permanent target failure
-			 */
-			set_host_byte(scmd, DID_TARGET_FAILURE);
-			rtn = SUCCESS;
-		}
 		/* if rtn == FAILED, we have no sense information;
 		 * returning FAILED will wake the error handler thread
 		 * to collect the sense and redo the decide
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 124392f..d1549b7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -68,28 +68,6 @@
 
 struct kmem_cache *scsi_sdb_cache;
 
-#ifdef CONFIG_ACPI
-#include <acpi/acpi_bus.h>
-
-static bool acpi_scsi_bus_match(struct device *dev)
-{
-	return dev->bus == &scsi_bus_type;
-}
-
-int scsi_register_acpi_bus_type(struct acpi_bus_type *bus)
-{
-        bus->match = acpi_scsi_bus_match;
-        return register_acpi_bus_type(bus);
-}
-EXPORT_SYMBOL_GPL(scsi_register_acpi_bus_type);
-
-void scsi_unregister_acpi_bus_type(struct acpi_bus_type *bus)
-{
-	unregister_acpi_bus_type(bus);
-}
-EXPORT_SYMBOL_GPL(scsi_unregister_acpi_bus_type);
-#endif
-
 /*
  * When to reinvoke queueing after a resource shortage. It's 3 msecs to
  * not change behaviour from the previous unplug mechanism, experimentation
@@ -716,6 +694,20 @@
 }
 EXPORT_SYMBOL(scsi_release_buffers);
 
+/**
+ * __scsi_error_from_host_byte - translate SCSI error code into errno
+ * @cmd:	SCSI command (unused)
+ * @result:	scsi error code
+ *
+ * Translate SCSI error code into standard UNIX errno.
+ * Return values:
+ * -ENOLINK	temporary transport failure
+ * -EREMOTEIO	permanent target failure, do not retry
+ * -EBADE	permanent nexus failure, retry on other path
+ * -ENOSPC	No write space available
+ * -ENODATA	Medium error
+ * -EIO		unspecified I/O error
+ */
 static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result)
 {
 	int error = 0;
@@ -732,6 +724,14 @@
 		set_host_byte(cmd, DID_OK);
 		error = -EBADE;
 		break;
+	case DID_ALLOC_FAILURE:
+		set_host_byte(cmd, DID_OK);
+		error = -ENOSPC;
+		break;
+	case DID_MEDIUM_ERROR:
+		set_host_byte(cmd, DID_OK);
+		error = -ENODATA;
+		break;
 	default:
 		error = -EIO;
 		break;
@@ -2231,7 +2231,21 @@
 	case SDEV_EVT_MEDIA_CHANGE:
 		envp[idx++] = "SDEV_MEDIA_CHANGE=1";
 		break;
-
+	case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+		envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
+		break;
+	case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
+		envp[idx++] = "SDEV_UA=CAPACITY_DATA_HAS_CHANGED";
+		break;
+	case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED:
+	       envp[idx++] = "SDEV_UA=THIN_PROVISIONING_SOFT_THRESHOLD_REACHED";
+		break;
+	case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED:
+		envp[idx++] = "SDEV_UA=MODE_PARAMETERS_CHANGED";
+		break;
+	case SDEV_EVT_LUN_CHANGE_REPORTED:
+		envp[idx++] = "SDEV_UA=REPORTED_LUNS_DATA_HAS_CHANGED";
+		break;
 	default:
 		/* do nothing */
 		break;
@@ -2252,10 +2266,15 @@
 void scsi_evt_thread(struct work_struct *work)
 {
 	struct scsi_device *sdev;
+	enum scsi_device_event evt_type;
 	LIST_HEAD(event_list);
 
 	sdev = container_of(work, struct scsi_device, event_work);
 
+	for (evt_type = SDEV_EVT_FIRST; evt_type <= SDEV_EVT_LAST; evt_type++)
+		if (test_and_clear_bit(evt_type, sdev->pending_events))
+			sdev_evt_send_simple(sdev, evt_type, GFP_KERNEL);
+
 	while (1) {
 		struct scsi_event *evt;
 		struct list_head *this, *tmp;
@@ -2325,6 +2344,11 @@
 	/* evt_type-specific initialization, if any */
 	switch (evt_type) {
 	case SDEV_EVT_MEDIA_CHANGE:
+	case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
+	case SDEV_EVT_CAPACITY_CHANGE_REPORTED:
+	case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED:
+	case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED:
+	case SDEV_EVT_LUN_CHANGE_REPORTED:
 	default:
 		/* do nothing */
 		break;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 7e50061..40c6394 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -739,6 +739,11 @@
 #define REF_EVT(name) &dev_attr_evt_##name.attr
 
 DECLARE_EVT(media_change, MEDIA_CHANGE)
+DECLARE_EVT(inquiry_change_reported, INQUIRY_CHANGE_REPORTED)
+DECLARE_EVT(capacity_change_reported, CAPACITY_CHANGE_REPORTED)
+DECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED)
+DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED)
+DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED)
 
 /* Default template for device attributes.  May NOT be modified */
 static struct attribute *scsi_sdev_attrs[] = {
@@ -759,6 +764,11 @@
 	&dev_attr_ioerr_cnt.attr,
 	&dev_attr_modalias.attr,
 	REF_EVT(media_change),
+	REF_EVT(inquiry_change_reported),
+	REF_EVT(capacity_change_reported),
+	REF_EVT(soft_threshold_reached),
+	REF_EVT(mode_parameter_change_reported),
+	REF_EVT(lun_change_reported),
 	NULL
 };
 
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index abf7c40..e4a989f 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/bsg-lib.h>
 #include <linux/idr.h>
-#include <linux/list.h>
 #include <net/tcp.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -3327,6 +3326,23 @@
 iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
 iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
 iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
+iscsi_conn_attr(local_port, ISCSI_PARAM_LOCAL_PORT);
+iscsi_conn_attr(statsn, ISCSI_PARAM_STATSN);
+iscsi_conn_attr(keepalive_tmo, ISCSI_PARAM_KEEPALIVE_TMO);
+iscsi_conn_attr(max_segment_size, ISCSI_PARAM_MAX_SEGMENT_SIZE);
+iscsi_conn_attr(tcp_timestamp_stat, ISCSI_PARAM_TCP_TIMESTAMP_STAT);
+iscsi_conn_attr(tcp_wsf_disable, ISCSI_PARAM_TCP_WSF_DISABLE);
+iscsi_conn_attr(tcp_nagle_disable, ISCSI_PARAM_TCP_NAGLE_DISABLE);
+iscsi_conn_attr(tcp_timer_scale, ISCSI_PARAM_TCP_TIMER_SCALE);
+iscsi_conn_attr(tcp_timestamp_enable, ISCSI_PARAM_TCP_TIMESTAMP_EN);
+iscsi_conn_attr(fragment_disable, ISCSI_PARAM_IP_FRAGMENT_DISABLE);
+iscsi_conn_attr(ipv4_tos, ISCSI_PARAM_IPV4_TOS);
+iscsi_conn_attr(ipv6_traffic_class, ISCSI_PARAM_IPV6_TC);
+iscsi_conn_attr(ipv6_flow_label, ISCSI_PARAM_IPV6_FLOW_LABEL);
+iscsi_conn_attr(is_fw_assigned_ipv6, ISCSI_PARAM_IS_FW_ASSIGNED_IPV6);
+iscsi_conn_attr(tcp_xmit_wsf, ISCSI_PARAM_TCP_XMIT_WSF);
+iscsi_conn_attr(tcp_recv_wsf, ISCSI_PARAM_TCP_RECV_WSF);
+
 
 #define iscsi_conn_ep_attr_show(param)					\
 static ssize_t show_conn_ep_param_##param(struct device *dev,		\
@@ -3379,6 +3395,22 @@
 	&dev_attr_conn_persistent_port.attr,
 	&dev_attr_conn_ping_tmo.attr,
 	&dev_attr_conn_recv_tmo.attr,
+	&dev_attr_conn_local_port.attr,
+	&dev_attr_conn_statsn.attr,
+	&dev_attr_conn_keepalive_tmo.attr,
+	&dev_attr_conn_max_segment_size.attr,
+	&dev_attr_conn_tcp_timestamp_stat.attr,
+	&dev_attr_conn_tcp_wsf_disable.attr,
+	&dev_attr_conn_tcp_nagle_disable.attr,
+	&dev_attr_conn_tcp_timer_scale.attr,
+	&dev_attr_conn_tcp_timestamp_enable.attr,
+	&dev_attr_conn_fragment_disable.attr,
+	&dev_attr_conn_ipv4_tos.attr,
+	&dev_attr_conn_ipv6_traffic_class.attr,
+	&dev_attr_conn_ipv6_flow_label.attr,
+	&dev_attr_conn_is_fw_assigned_ipv6.attr,
+	&dev_attr_conn_tcp_xmit_wsf.attr,
+	&dev_attr_conn_tcp_recv_wsf.attr,
 	NULL,
 };
 
@@ -3416,6 +3448,38 @@
 		param = ISCSI_PARAM_PING_TMO;
 	else if (attr == &dev_attr_conn_recv_tmo.attr)
 		param = ISCSI_PARAM_RECV_TMO;
+	else if (attr == &dev_attr_conn_local_port.attr)
+		param = ISCSI_PARAM_LOCAL_PORT;
+	else if (attr == &dev_attr_conn_statsn.attr)
+		param = ISCSI_PARAM_STATSN;
+	else if (attr == &dev_attr_conn_keepalive_tmo.attr)
+		param = ISCSI_PARAM_KEEPALIVE_TMO;
+	else if (attr == &dev_attr_conn_max_segment_size.attr)
+		param = ISCSI_PARAM_MAX_SEGMENT_SIZE;
+	else if (attr == &dev_attr_conn_tcp_timestamp_stat.attr)
+		param = ISCSI_PARAM_TCP_TIMESTAMP_STAT;
+	else if (attr == &dev_attr_conn_tcp_wsf_disable.attr)
+		param = ISCSI_PARAM_TCP_WSF_DISABLE;
+	else if (attr == &dev_attr_conn_tcp_nagle_disable.attr)
+		param = ISCSI_PARAM_TCP_NAGLE_DISABLE;
+	else if (attr == &dev_attr_conn_tcp_timer_scale.attr)
+		param = ISCSI_PARAM_TCP_TIMER_SCALE;
+	else if (attr == &dev_attr_conn_tcp_timestamp_enable.attr)
+		param = ISCSI_PARAM_TCP_TIMESTAMP_EN;
+	else if (attr == &dev_attr_conn_fragment_disable.attr)
+		param = ISCSI_PARAM_IP_FRAGMENT_DISABLE;
+	else if (attr == &dev_attr_conn_ipv4_tos.attr)
+		param = ISCSI_PARAM_IPV4_TOS;
+	else if (attr == &dev_attr_conn_ipv6_traffic_class.attr)
+		param = ISCSI_PARAM_IPV6_TC;
+	else if (attr == &dev_attr_conn_ipv6_flow_label.attr)
+		param = ISCSI_PARAM_IPV6_FLOW_LABEL;
+	else if (attr == &dev_attr_conn_is_fw_assigned_ipv6.attr)
+		param = ISCSI_PARAM_IS_FW_ASSIGNED_IPV6;
+	else if (attr == &dev_attr_conn_tcp_xmit_wsf.attr)
+		param = ISCSI_PARAM_TCP_XMIT_WSF;
+	else if (attr == &dev_attr_conn_tcp_recv_wsf.attr)
+		param = ISCSI_PARAM_TCP_RECV_WSF;
 	else {
 		WARN_ONCE(1, "Invalid conn attr");
 		return 0;
@@ -3476,6 +3540,21 @@
 iscsi_session_attr(boot_root, ISCSI_PARAM_BOOT_ROOT, 0);
 iscsi_session_attr(boot_nic, ISCSI_PARAM_BOOT_NIC, 0);
 iscsi_session_attr(boot_target, ISCSI_PARAM_BOOT_TARGET, 0);
+iscsi_session_attr(auto_snd_tgt_disable, ISCSI_PARAM_AUTO_SND_TGT_DISABLE, 0);
+iscsi_session_attr(discovery_session, ISCSI_PARAM_DISCOVERY_SESS, 0);
+iscsi_session_attr(portal_type, ISCSI_PARAM_PORTAL_TYPE, 0);
+iscsi_session_attr(chap_auth, ISCSI_PARAM_CHAP_AUTH_EN, 0);
+iscsi_session_attr(discovery_logout, ISCSI_PARAM_DISCOVERY_LOGOUT_EN, 0);
+iscsi_session_attr(bidi_chap, ISCSI_PARAM_BIDI_CHAP_EN, 0);
+iscsi_session_attr(discovery_auth_optional,
+		   ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL, 0);
+iscsi_session_attr(def_time2wait, ISCSI_PARAM_DEF_TIME2WAIT, 0);
+iscsi_session_attr(def_time2retain, ISCSI_PARAM_DEF_TIME2RETAIN, 0);
+iscsi_session_attr(isid, ISCSI_PARAM_ISID, 0);
+iscsi_session_attr(tsid, ISCSI_PARAM_TSID, 0);
+iscsi_session_attr(def_taskmgmt_tmo, ISCSI_PARAM_DEF_TASKMGMT_TMO, 0);
+iscsi_session_attr(discovery_parent_idx, ISCSI_PARAM_DISCOVERY_PARENT_IDX, 0);
+iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);
 
 static ssize_t
 show_priv_session_state(struct device *dev, struct device_attribute *attr,
@@ -3580,6 +3659,20 @@
 	&dev_attr_sess_chap_out_idx.attr,
 	&dev_attr_sess_chap_in_idx.attr,
 	&dev_attr_priv_sess_target_id.attr,
+	&dev_attr_sess_auto_snd_tgt_disable.attr,
+	&dev_attr_sess_discovery_session.attr,
+	&dev_attr_sess_portal_type.attr,
+	&dev_attr_sess_chap_auth.attr,
+	&dev_attr_sess_discovery_logout.attr,
+	&dev_attr_sess_bidi_chap.attr,
+	&dev_attr_sess_discovery_auth_optional.attr,
+	&dev_attr_sess_def_time2wait.attr,
+	&dev_attr_sess_def_time2retain.attr,
+	&dev_attr_sess_isid.attr,
+	&dev_attr_sess_tsid.attr,
+	&dev_attr_sess_def_taskmgmt_tmo.attr,
+	&dev_attr_sess_discovery_parent_idx.attr,
+	&dev_attr_sess_discovery_parent_type.attr,
 	NULL,
 };
 
@@ -3643,6 +3736,34 @@
 		param = ISCSI_PARAM_BOOT_NIC;
 	else if (attr == &dev_attr_sess_boot_target.attr)
 		param = ISCSI_PARAM_BOOT_TARGET;
+	else if (attr == &dev_attr_sess_auto_snd_tgt_disable.attr)
+		param = ISCSI_PARAM_AUTO_SND_TGT_DISABLE;
+	else if (attr == &dev_attr_sess_discovery_session.attr)
+		param = ISCSI_PARAM_DISCOVERY_SESS;
+	else if (attr == &dev_attr_sess_portal_type.attr)
+		param = ISCSI_PARAM_PORTAL_TYPE;
+	else if (attr == &dev_attr_sess_chap_auth.attr)
+		param = ISCSI_PARAM_CHAP_AUTH_EN;
+	else if (attr == &dev_attr_sess_discovery_logout.attr)
+		param = ISCSI_PARAM_DISCOVERY_LOGOUT_EN;
+	else if (attr == &dev_attr_sess_bidi_chap.attr)
+		param = ISCSI_PARAM_BIDI_CHAP_EN;
+	else if (attr == &dev_attr_sess_discovery_auth_optional.attr)
+		param = ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL;
+	else if (attr == &dev_attr_sess_def_time2wait.attr)
+		param = ISCSI_PARAM_DEF_TIME2WAIT;
+	else if (attr == &dev_attr_sess_def_time2retain.attr)
+		param = ISCSI_PARAM_DEF_TIME2RETAIN;
+	else if (attr == &dev_attr_sess_isid.attr)
+		param = ISCSI_PARAM_ISID;
+	else if (attr == &dev_attr_sess_tsid.attr)
+		param = ISCSI_PARAM_TSID;
+	else if (attr == &dev_attr_sess_def_taskmgmt_tmo.attr)
+		param = ISCSI_PARAM_DEF_TASKMGMT_TMO;
+	else if (attr == &dev_attr_sess_discovery_parent_idx.attr)
+		param = ISCSI_PARAM_DISCOVERY_PARENT_IDX;
+	else if (attr == &dev_attr_sess_discovery_parent_type.attr)
+		param = ISCSI_PARAM_DISCOVERY_PARENT_TYPE;
 	else if (attr == &dev_attr_priv_sess_recovery_tmo.attr)
 		return S_IRUGO | S_IWUSR;
 	else if (attr == &dev_attr_priv_sess_state.attr)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 86fcf2c..b58e8f8 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -132,8 +132,8 @@
 };
 
 static ssize_t
-sd_store_cache_type(struct device *dev, struct device_attribute *attr,
-		    const char *buf, size_t count)
+cache_type_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
 {
 	int i, ct = -1, rcd, wce, sp;
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -199,8 +199,18 @@
 }
 
 static ssize_t
-sd_store_manage_start_stop(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
+manage_start_stop_show(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+	struct scsi_device *sdp = sdkp->device;
+
+	return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
+}
+
+static ssize_t
+manage_start_stop_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
@@ -212,10 +222,19 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(manage_start_stop);
 
 static ssize_t
-sd_store_allow_restart(struct device *dev, struct device_attribute *attr,
-		       const char *buf, size_t count)
+allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+	return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
+}
+
+static ssize_t
+allow_restart_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
@@ -230,47 +249,30 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(allow_restart);
 
 static ssize_t
-sd_show_cache_type(struct device *dev, struct device_attribute *attr,
-		   char *buf)
+cache_type_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	int ct = sdkp->RCD + 2*sdkp->WCE;
 
 	return snprintf(buf, 40, "%s\n", sd_cache_types[ct]);
 }
+static DEVICE_ATTR_RW(cache_type);
 
 static ssize_t
-sd_show_fua(struct device *dev, struct device_attribute *attr, char *buf)
+FUA_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
 	return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
 }
+static DEVICE_ATTR_RO(FUA);
 
 static ssize_t
-sd_show_manage_start_stop(struct device *dev, struct device_attribute *attr,
-			  char *buf)
-{
-	struct scsi_disk *sdkp = to_scsi_disk(dev);
-	struct scsi_device *sdp = sdkp->device;
-
-	return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
-}
-
-static ssize_t
-sd_show_allow_restart(struct device *dev, struct device_attribute *attr,
-		      char *buf)
-{
-	struct scsi_disk *sdkp = to_scsi_disk(dev);
-
-	return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
-}
-
-static ssize_t
-sd_show_protection_type(struct device *dev, struct device_attribute *attr,
-			char *buf)
+protection_type_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
@@ -278,8 +280,8 @@
 }
 
 static ssize_t
-sd_store_protection_type(struct device *dev, struct device_attribute *attr,
-			 const char *buf, size_t count)
+protection_type_store(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	unsigned int val;
@@ -298,10 +300,11 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(protection_type);
 
 static ssize_t
-sd_show_protection_mode(struct device *dev, struct device_attribute *attr,
-			char *buf)
+protection_mode_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
@@ -320,24 +323,26 @@
 
 	return snprintf(buf, 20, "%s%u\n", dix ? "dix" : "dif", dif);
 }
+static DEVICE_ATTR_RO(protection_mode);
 
 static ssize_t
-sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
-		    char *buf)
+app_tag_own_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
 	return snprintf(buf, 20, "%u\n", sdkp->ATO);
 }
+static DEVICE_ATTR_RO(app_tag_own);
 
 static ssize_t
-sd_show_thin_provisioning(struct device *dev, struct device_attribute *attr,
-			  char *buf)
+thin_provisioning_show(struct device *dev, struct device_attribute *attr,
+		       char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
 	return snprintf(buf, 20, "%u\n", sdkp->lbpme);
 }
+static DEVICE_ATTR_RO(thin_provisioning);
 
 static const char *lbp_mode[] = {
 	[SD_LBP_FULL]		= "full",
@@ -349,8 +354,8 @@
 };
 
 static ssize_t
-sd_show_provisioning_mode(struct device *dev, struct device_attribute *attr,
-			  char *buf)
+provisioning_mode_show(struct device *dev, struct device_attribute *attr,
+		       char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
@@ -358,8 +363,8 @@
 }
 
 static ssize_t
-sd_store_provisioning_mode(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
+provisioning_mode_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
@@ -385,10 +390,11 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(provisioning_mode);
 
 static ssize_t
-sd_show_max_medium_access_timeouts(struct device *dev,
-				   struct device_attribute *attr, char *buf)
+max_medium_access_timeouts_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
@@ -396,9 +402,9 @@
 }
 
 static ssize_t
-sd_store_max_medium_access_timeouts(struct device *dev,
-				    struct device_attribute *attr,
-				    const char *buf, size_t count)
+max_medium_access_timeouts_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	int err;
@@ -410,10 +416,11 @@
 
 	return err ? err : count;
 }
+static DEVICE_ATTR_RW(max_medium_access_timeouts);
 
 static ssize_t
-sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr,
-			  char *buf)
+max_write_same_blocks_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 
@@ -421,8 +428,8 @@
 }
 
 static ssize_t
-sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
+max_write_same_blocks_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
 	struct scsi_device *sdp = sdkp->device;
@@ -451,35 +458,29 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(max_write_same_blocks);
 
-static struct device_attribute sd_disk_attrs[] = {
-	__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
-	       sd_store_cache_type),
-	__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
-	__ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
-	       sd_store_allow_restart),
-	__ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
-	       sd_store_manage_start_stop),
-	__ATTR(protection_type, S_IRUGO|S_IWUSR, sd_show_protection_type,
-	       sd_store_protection_type),
-	__ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL),
-	__ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL),
-	__ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
-	__ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode,
-	       sd_store_provisioning_mode),
-	__ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR,
-	       sd_show_write_same_blocks, sd_store_write_same_blocks),
-	__ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR,
-	       sd_show_max_medium_access_timeouts,
-	       sd_store_max_medium_access_timeouts),
-	__ATTR_NULL,
+static struct attribute *sd_disk_attrs[] = {
+	&dev_attr_cache_type.attr,
+	&dev_attr_FUA.attr,
+	&dev_attr_allow_restart.attr,
+	&dev_attr_manage_start_stop.attr,
+	&dev_attr_protection_type.attr,
+	&dev_attr_protection_mode.attr,
+	&dev_attr_app_tag_own.attr,
+	&dev_attr_thin_provisioning.attr,
+	&dev_attr_provisioning_mode.attr,
+	&dev_attr_max_write_same_blocks.attr,
+	&dev_attr_max_medium_access_timeouts.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(sd_disk);
 
 static struct class sd_disk_class = {
 	.name		= "scsi_disk",
 	.owner		= THIS_MODULE,
 	.dev_release	= scsi_disk_release,
-	.dev_attrs	= sd_disk_attrs,
+	.dev_groups	= sd_disk_groups,
 };
 
 static const struct dev_pm_ops sd_pm_ops = {
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index df5e961..5cbc4bb 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -105,11 +105,8 @@
 static int sg_add(struct device *, struct class_interface *);
 static void sg_remove(struct device *, struct class_interface *);
 
-static DEFINE_SPINLOCK(sg_open_exclusive_lock);
-
 static DEFINE_IDR(sg_index_idr);
-static DEFINE_RWLOCK(sg_index_lock);	/* Also used to lock
-							   file descriptor list for device */
+static DEFINE_RWLOCK(sg_index_lock);
 
 static struct class_interface sg_interface = {
 	.add_dev	= sg_add,
@@ -146,8 +143,7 @@
 } Sg_request;
 
 typedef struct sg_fd {		/* holds the state of a file descriptor */
-	/* sfd_siblings is protected by sg_index_lock */
-	struct list_head sfd_siblings;
+	struct list_head sfd_siblings; /* protected by sfd_lock of device */
 	struct sg_device *parentdp;	/* owning device */
 	wait_queue_head_t read_wait;	/* queue read until command done */
 	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
@@ -170,13 +166,12 @@
 
 typedef struct sg_device { /* holds the state of each scsi generic device */
 	struct scsi_device *device;
-	wait_queue_head_t o_excl_wait;	/* queue open() when O_EXCL in use */
 	int sg_tablesize;	/* adapter's max scatter-gather table size */
 	u32 index;		/* device index number */
-	/* sfds is protected by sg_index_lock */
+	spinlock_t sfd_lock;	/* protect file descriptor list for device */
 	struct list_head sfds;
+	struct rw_semaphore o_sem;	/* exclude open should hold this rwsem */
 	volatile char detached;	/* 0->attached, 1->detached pending removal */
-	/* exclude protected by sg_open_exclusive_lock */
 	char exclude;		/* opened for exclusive access */
 	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
 	struct gendisk *disk;
@@ -225,35 +220,14 @@
 	return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
 }
 
-static int get_exclude(Sg_device *sdp)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&sg_open_exclusive_lock, flags);
-	ret = sdp->exclude;
-	spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
-	return ret;
-}
-
-static int set_exclude(Sg_device *sdp, char val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&sg_open_exclusive_lock, flags);
-	sdp->exclude = val;
-	spin_unlock_irqrestore(&sg_open_exclusive_lock, flags);
-	return val;
-}
-
 static int sfds_list_empty(Sg_device *sdp)
 {
 	unsigned long flags;
 	int ret;
 
-	read_lock_irqsave(&sg_index_lock, flags);
+	spin_lock_irqsave(&sdp->sfd_lock, flags);
 	ret = list_empty(&sdp->sfds);
-	read_unlock_irqrestore(&sg_index_lock, flags);
+	spin_unlock_irqrestore(&sdp->sfd_lock, flags);
 	return ret;
 }
 
@@ -265,7 +239,6 @@
 	struct request_queue *q;
 	Sg_device *sdp;
 	Sg_fd *sfp;
-	int res;
 	int retval;
 
 	nonseekable_open(inode, filp);
@@ -294,54 +267,52 @@
 		goto error_out;
 	}
 
-	if (flags & O_EXCL) {
-		if (O_RDONLY == (flags & O_ACCMODE)) {
-			retval = -EPERM; /* Can't lock it with read only access */
-			goto error_out;
-		}
-		if (!sfds_list_empty(sdp) && (flags & O_NONBLOCK)) {
-			retval = -EBUSY;
-			goto error_out;
-		}
-		res = wait_event_interruptible(sdp->o_excl_wait,
-					   ((!sfds_list_empty(sdp) || get_exclude(sdp)) ? 0 : set_exclude(sdp, 1)));
-		if (res) {
-			retval = res;	/* -ERESTARTSYS because signal hit process */
-			goto error_out;
-		}
-	} else if (get_exclude(sdp)) {	/* some other fd has an exclusive lock on dev */
-		if (flags & O_NONBLOCK) {
-			retval = -EBUSY;
-			goto error_out;
-		}
-		res = wait_event_interruptible(sdp->o_excl_wait, !get_exclude(sdp));
-		if (res) {
-			retval = res;	/* -ERESTARTSYS because signal hit process */
-			goto error_out;
-		}
-	}
-	if (sdp->detached) {
-		retval = -ENODEV;
+	if ((flags & O_EXCL) && (O_RDONLY == (flags & O_ACCMODE))) {
+		retval = -EPERM; /* Can't lock it with read only access */
 		goto error_out;
 	}
+	if (flags & O_NONBLOCK) {
+		if (flags & O_EXCL) {
+			if (!down_write_trylock(&sdp->o_sem)) {
+				retval = -EBUSY;
+				goto error_out;
+			}
+		} else {
+			if (!down_read_trylock(&sdp->o_sem)) {
+				retval = -EBUSY;
+				goto error_out;
+			}
+		}
+	} else {
+		if (flags & O_EXCL)
+			down_write(&sdp->o_sem);
+		else
+			down_read(&sdp->o_sem);
+	}
+	/* Since write lock is held, no need to check sfd_list */
+	if (flags & O_EXCL)
+		sdp->exclude = 1;	/* used by release lock */
+
 	if (sfds_list_empty(sdp)) {	/* no existing opens on this device */
 		sdp->sgdebug = 0;
 		q = sdp->device->request_queue;
 		sdp->sg_tablesize = queue_max_segments(q);
 	}
-	if ((sfp = sg_add_sfp(sdp, dev)))
+	sfp = sg_add_sfp(sdp, dev);
+	if (!IS_ERR(sfp))
 		filp->private_data = sfp;
+		/* retval is already provably zero at this point because of the
+		 * check after retval = scsi_autopm_get_device(sdp->device))
+		 */
 	else {
+		retval = PTR_ERR(sfp);
+
 		if (flags & O_EXCL) {
-			set_exclude(sdp, 0);	/* undo if error */
-			wake_up_interruptible(&sdp->o_excl_wait);
-		}
-		retval = -ENOMEM;
-		goto error_out;
-	}
-	retval = 0;
+			sdp->exclude = 0;	/* undo if error */
+			up_write(&sdp->o_sem);
+		} else
+			up_read(&sdp->o_sem);
 error_out:
-	if (retval) {
 		scsi_autopm_put_device(sdp->device);
 sdp_put:
 		scsi_device_put(sdp->device);
@@ -358,13 +329,18 @@
 {
 	Sg_device *sdp;
 	Sg_fd *sfp;
+	int excl;
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
 
-	set_exclude(sdp, 0);
-	wake_up_interruptible(&sdp->o_excl_wait);
+	excl = sdp->exclude;
+	sdp->exclude = 0;
+	if (excl)
+		up_write(&sdp->o_sem);
+	else
+		up_read(&sdp->o_sem);
 
 	scsi_autopm_put_device(sdp->device);
 	kref_put(&sfp->f_ref, sg_remove_sfp);
@@ -1415,8 +1391,9 @@
 	disk->first_minor = k;
 	sdp->disk = disk;
 	sdp->device = scsidp;
+	spin_lock_init(&sdp->sfd_lock);
 	INIT_LIST_HEAD(&sdp->sfds);
-	init_waitqueue_head(&sdp->o_excl_wait);
+	init_rwsem(&sdp->o_sem);
 	sdp->sg_tablesize = queue_max_segments(q);
 	sdp->index = k;
 	kref_init(&sdp->d_ref);
@@ -1549,11 +1526,13 @@
 
 	/* Need a write lock to set sdp->detached. */
 	write_lock_irqsave(&sg_index_lock, iflags);
+	spin_lock(&sdp->sfd_lock);
 	sdp->detached = 1;
 	list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
 		wake_up_interruptible(&sfp->read_wait);
 		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
 	}
+	spin_unlock(&sdp->sfd_lock);
 	write_unlock_irqrestore(&sg_index_lock, iflags);
 
 	sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
@@ -2064,7 +2043,7 @@
 
 	sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
 	if (!sfp)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	init_waitqueue_head(&sfp->read_wait);
 	rwlock_init(&sfp->rq_list_lock);
@@ -2078,9 +2057,13 @@
 	sfp->cmd_q = SG_DEF_COMMAND_Q;
 	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
 	sfp->parentdp = sdp;
-	write_lock_irqsave(&sg_index_lock, iflags);
+	spin_lock_irqsave(&sdp->sfd_lock, iflags);
+	if (sdp->detached) {
+		spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
+		return ERR_PTR(-ENODEV);
+	}
 	list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
-	write_unlock_irqrestore(&sg_index_lock, iflags);
+	spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
 	SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
 	if (unlikely(sg_big_buff != def_reserved_size))
 		sg_big_buff = def_reserved_size;
@@ -2130,10 +2113,9 @@
 	struct sg_device *sdp = sfp->parentdp;
 	unsigned long iflags;
 
-	write_lock_irqsave(&sg_index_lock, iflags);
+	spin_lock_irqsave(&sdp->sfd_lock, iflags);
 	list_del(&sfp->sfd_siblings);
-	write_unlock_irqrestore(&sg_index_lock, iflags);
-	wake_up_interruptible(&sdp->o_excl_wait);
+	spin_unlock_irqrestore(&sdp->sfd_lock, iflags);
 
 	INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext);
 	schedule_work(&sfp->ew.work);
@@ -2520,7 +2502,7 @@
 	return 0;
 }
 
-/* must be called while holding sg_index_lock */
+/* must be called while holding sg_index_lock and sfd_lock */
 static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
 {
 	int k, m, new_interface, blen, usg;
@@ -2605,22 +2587,26 @@
 
 	read_lock_irqsave(&sg_index_lock, iflags);
 	sdp = it ? sg_lookup_dev(it->index) : NULL;
-	if (sdp && !list_empty(&sdp->sfds)) {
-		struct scsi_device *scsidp = sdp->device;
+	if (sdp) {
+		spin_lock(&sdp->sfd_lock);
+		if (!list_empty(&sdp->sfds)) {
+			struct scsi_device *scsidp = sdp->device;
 
-		seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
-		if (sdp->detached)
-			seq_printf(s, "detached pending close ");
-		else
-			seq_printf
-			    (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
-			     scsidp->host->host_no,
-			     scsidp->channel, scsidp->id,
-			     scsidp->lun,
-			     scsidp->host->hostt->emulated);
-		seq_printf(s, " sg_tablesize=%d excl=%d\n",
-			   sdp->sg_tablesize, get_exclude(sdp));
-		sg_proc_debug_helper(s, sdp);
+			seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
+			if (sdp->detached)
+				seq_printf(s, "detached pending close ");
+			else
+				seq_printf
+				    (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
+				     scsidp->host->host_no,
+				     scsidp->channel, scsidp->id,
+				     scsidp->lun,
+				     scsidp->host->hostt->emulated);
+			seq_printf(s, " sg_tablesize=%d excl=%d\n",
+				   sdp->sg_tablesize, sdp->exclude);
+			sg_proc_debug_helper(s, sdp);
+		}
+		spin_unlock(&sdp->sfd_lock);
 	}
 	read_unlock_irqrestore(&sg_index_lock, iflags);
 	return 0;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 2a32036..ff44b3c 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -82,7 +82,7 @@
 static int try_wdio = 1;
 
 static struct class st_sysfs_class;
-static struct device_attribute st_dev_attrs[];
+static const struct attribute_group *st_dev_groups[];
 
 MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI tape (st) driver");
@@ -4274,7 +4274,7 @@
 
 static struct class st_sysfs_class = {
 	.name = "scsi_tape",
-	.dev_attrs = st_dev_attrs,
+	.dev_groups = st_dev_groups,
 };
 
 static int __init init_st(void)
@@ -4408,6 +4408,7 @@
 	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
 	return l;
 }
+static DEVICE_ATTR_RO(defined);
 
 static ssize_t
 default_blksize_show(struct device *dev, struct device_attribute *attr,
@@ -4419,7 +4420,7 @@
 	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
 	return l;
 }
-
+static DEVICE_ATTR_RO(default_blksize);
 
 static ssize_t
 default_density_show(struct device *dev, struct device_attribute *attr,
@@ -4433,6 +4434,7 @@
 	l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density);
 	return l;
 }
+static DEVICE_ATTR_RO(default_density);
 
 static ssize_t
 default_compression_show(struct device *dev, struct device_attribute *attr,
@@ -4444,6 +4446,7 @@
 	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
 	return l;
 }
+static DEVICE_ATTR_RO(default_compression);
 
 static ssize_t
 options_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -4472,15 +4475,17 @@
 	l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options);
 	return l;
 }
+static DEVICE_ATTR_RO(options);
 
-static struct device_attribute st_dev_attrs[] = {
-	__ATTR_RO(defined),
-	__ATTR_RO(default_blksize),
-	__ATTR_RO(default_density),
-	__ATTR_RO(default_compression),
-	__ATTR_RO(options),
-	__ATTR_NULL,
+static struct attribute *st_dev_attrs[] = {
+	&dev_attr_defined.attr,
+	&dev_attr_default_blksize.attr,
+	&dev_attr_default_density.attr,
+	&dev_attr_default_compression.attr,
+	&dev_attr_options.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(st_dev);
 
 /* The following functions may be useful for a larger audience. */
 static int sgl_map_user_pages(struct st_buffer *STbp,
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 83ec1aa..1a28f56 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1879,7 +1879,6 @@
 }
 
 MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
 MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver");
 module_init(storvsc_drv_init);
 module_exit(storvsc_drv_exit);
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..bce09a6 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,10 +36,17 @@
 #ifndef _UFS_H
 #define _UFS_H
 
+#include <linux/mutex.h>
+#include <linux/types.h>
+
 #define MAX_CDB_SIZE	16
+#define GENERAL_UPIU_REQUEST_SIZE 32
+#define QUERY_DESC_MAX_SIZE       256
+#define QUERY_OSF_SIZE            (GENERAL_UPIU_REQUEST_SIZE - \
+					(sizeof(struct utp_upiu_header)))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
-			((byte3 << 24) | (byte2 << 16) |\
+			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
 			 (byte1 << 8) | (byte0))
 
 /*
@@ -62,7 +69,7 @@
 	UPIU_TRANSACTION_COMMAND	= 0x01,
 	UPIU_TRANSACTION_DATA_OUT	= 0x02,
 	UPIU_TRANSACTION_TASK_REQ	= 0x04,
-	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
 };
 
 /* UTP UPIU Transaction Codes Target to Initiator */
@@ -73,6 +80,7 @@
 	UPIU_TRANSACTION_TASK_RSP	= 0x24,
 	UPIU_TRANSACTION_READY_XFER	= 0x31,
 	UPIU_TRANSACTION_QUERY_RSP	= 0x36,
+	UPIU_TRANSACTION_REJECT_UPIU	= 0x3F,
 };
 
 /* UPIU Read/Write flags */
@@ -90,8 +98,41 @@
 	UPIU_TASK_ATTR_ACA	= 0x03,
 };
 
-/* UTP QUERY Transaction Specific Fields OpCode */
+/* UPIU Query request function */
 enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST           = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST          = 0x81,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+	QUERY_FLAG_IDN_FDEVICEINIT      = 0x01,
+	QUERY_FLAG_IDN_BKOPS_EN         = 0x04,
+};
+
+/* Attribute idn for Query requests */
+enum attr_idn {
+	QUERY_ATTR_IDN_BKOPS_STATUS	= 0x05,
+	QUERY_ATTR_IDN_EE_CONTROL	= 0x0D,
+	QUERY_ATTR_IDN_EE_STATUS	= 0x0E,
+};
+
+/* Exception event mask values */
+enum {
+	MASK_EE_STATUS		= 0xFFFF,
+	MASK_EE_URGENT_BKOPS	= (1 << 2),
+};
+
+/* Background operation status */
+enum {
+	BKOPS_STATUS_NO_OP               = 0x0,
+	BKOPS_STATUS_NON_CRITICAL        = 0x1,
+	BKOPS_STATUS_PERF_IMPACT         = 0x2,
+	BKOPS_STATUS_CRITICAL            = 0x3,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
 	UPIU_QUERY_OPCODE_NOP		= 0x0,
 	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
 	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
@@ -103,6 +144,21 @@
 	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
 };
 
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS                    = 0x00,
+	QUERY_RESULT_NOT_READABLE               = 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE              = 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN            = 0xF8,
+	QUERY_RESULT_INVALID_LENGTH             = 0xF9,
+	QUERY_RESULT_INVALID_VALUE              = 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR           = 0xFB,
+	QUERY_RESULT_INVALID_INDEX              = 0xFC,
+	QUERY_RESULT_INVALID_IDN                = 0xFD,
+	QUERY_RESULT_INVALID_OPCODE             = 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE            = 0xFF,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
 	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
@@ -110,10 +166,18 @@
 	UPIU_COMMAND_SET_TYPE_QUERY	= 0x2,
 };
 
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET	28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET		8
+
 enum {
-	MASK_SCSI_STATUS	= 0xFF,
-	MASK_TASK_RESPONSE	= 0xFF00,
-	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+	MASK_SCSI_STATUS		= 0xFF,
+	MASK_TASK_RESPONSE              = 0xFF00,
+	MASK_RSP_UPIU_RESULT            = 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN         = 0xFFFF,
+	MASK_RSP_EXCEPTION_EVENT        = 0x10000,
 };
 
 /* Task management service response */
@@ -138,26 +202,59 @@
 
 /**
  * struct utp_upiu_cmd - Command UPIU structure
- * @header: UPIU header structure DW-0 to DW-2
  * @data_transfer_len: Data Transfer Length DW-3
  * @cdb: Command Descriptor Block CDB DW-4 to DW-7
  */
 struct utp_upiu_cmd {
-	struct utp_upiu_header header;
 	u32 exp_data_transfer_len;
 	u8 cdb[MAX_CDB_SIZE];
 };
 
 /**
- * struct utp_upiu_rsp - Response UPIU structure
- * @header: UPIU header DW-0 to DW-2
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-5
+ * @reserved: spec reserved DW-6,7
+ */
+struct utp_upiu_query {
+	u8 opcode;
+	u8 idn;
+	u8 index;
+	u8 selector;
+	u16 reserved_osf;
+	u16 length;
+	u32 value;
+	u32 reserved[2];
+};
+
+/**
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command DW-3 to DW-7
+ * @qr: fields structure for query request DW-3 to DW-7
+ */
+struct utp_upiu_req {
+	struct utp_upiu_header header;
+	union {
+		struct utp_upiu_cmd sc;
+		struct utp_upiu_query qr;
+	};
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
  * @residual_transfer_count: Residual transfer count DW-3
  * @reserved: Reserved double words DW-4 to DW-7
  * @sense_data_len: Sense data length DW-8 U16
  * @sense_data: Sense data field DW-8 to DW-12
  */
-struct utp_upiu_rsp {
-	struct utp_upiu_header header;
+struct utp_cmd_rsp {
 	u32 residual_transfer_count;
 	u32 reserved[4];
 	u16 sense_data_len;
@@ -165,6 +262,20 @@
 };
 
 /**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sr: fields structure for scsi command DW-3 to DW-12
+ * @qr: fields structure for query request DW-3 to DW-7
+ */
+struct utp_upiu_rsp {
+	struct utp_upiu_header header;
+	union {
+		struct utp_cmd_rsp sr;
+		struct utp_upiu_query qr;
+	};
+};
+
+/**
  * struct utp_upiu_task_req - Task request UPIU structure
  * @header - UPIU header structure DW0 to DW-2
  * @input_param1: Input parameter 1 DW-3
@@ -194,4 +305,24 @@
 	u32 reserved[3];
 };
 
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index 48be39a..a823cf4 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -35,6 +35,7 @@
 
 #include "ufshcd.h"
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 
 #ifdef CONFIG_PM
 /**
@@ -44,7 +45,7 @@
  *
  * Returns -ENOSYS
  */
-static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int ufshcd_pci_suspend(struct device *dev)
 {
 	/*
 	 * TODO:
@@ -61,7 +62,7 @@
  *
  * Returns -ENOSYS
  */
-static int ufshcd_pci_resume(struct pci_dev *pdev)
+static int ufshcd_pci_resume(struct device *dev)
 {
 	/*
 	 * TODO:
@@ -71,8 +72,45 @@
 
 	return -ENOSYS;
 }
+#else
+#define ufshcd_pci_suspend	NULL
+#define ufshcd_pci_resume	NULL
 #endif /* CONFIG_PM */
 
+#ifdef CONFIG_PM_RUNTIME
+static int ufshcd_pci_runtime_suspend(struct device *dev)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+
+	if (!hba)
+		return 0;
+
+	return ufshcd_runtime_suspend(hba);
+}
+static int ufshcd_pci_runtime_resume(struct device *dev)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+
+	if (!hba)
+		return 0;
+
+	return ufshcd_runtime_resume(hba);
+}
+static int ufshcd_pci_runtime_idle(struct device *dev)
+{
+	struct ufs_hba *hba = dev_get_drvdata(dev);
+
+	if (!hba)
+		return 0;
+
+	return ufshcd_runtime_idle(hba);
+}
+#else /* !CONFIG_PM_RUNTIME */
+#define ufshcd_pci_runtime_suspend	NULL
+#define ufshcd_pci_runtime_resume	NULL
+#define ufshcd_pci_runtime_idle	NULL
+#endif /* CONFIG_PM_RUNTIME */
+
 /**
  * ufshcd_pci_shutdown - main function to put the controller in reset state
  * @pdev: pointer to PCI device handle
@@ -91,12 +129,10 @@
 {
 	struct ufs_hba *hba = pci_get_drvdata(pdev);
 
-	disable_irq(pdev->irq);
+	pm_runtime_forbid(&pdev->dev);
+	pm_runtime_get_noresume(&pdev->dev);
 	ufshcd_remove(hba);
-	pci_release_regions(pdev);
 	pci_set_drvdata(pdev, NULL);
-	pci_clear_master(pdev);
-	pci_disable_device(pdev);
 }
 
 /**
@@ -133,55 +169,49 @@
 	void __iomem *mmio_base;
 	int err;
 
-	err = pci_enable_device(pdev);
+	err = pcim_enable_device(pdev);
 	if (err) {
-		dev_err(&pdev->dev, "pci_enable_device failed\n");
-		goto out_error;
+		dev_err(&pdev->dev, "pcim_enable_device failed\n");
+		return err;
 	}
 
 	pci_set_master(pdev);
 
-
-	err = pci_request_regions(pdev, UFSHCD);
+	err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD);
 	if (err < 0) {
-		dev_err(&pdev->dev, "request regions failed\n");
-		goto out_disable;
+		dev_err(&pdev->dev, "request and iomap failed\n");
+		return err;
 	}
 
-	mmio_base = pci_ioremap_bar(pdev, 0);
-	if (!mmio_base) {
-		dev_err(&pdev->dev, "memory map failed\n");
-		err = -ENOMEM;
-		goto out_release_regions;
-	}
+	mmio_base = pcim_iomap_table(pdev)[0];
 
 	err = ufshcd_set_dma_mask(pdev);
 	if (err) {
 		dev_err(&pdev->dev, "set dma mask failed\n");
-		goto out_iounmap;
+		return err;
 	}
 
 	err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq);
 	if (err) {
 		dev_err(&pdev->dev, "Initialization failed\n");
-		goto out_iounmap;
+		return err;
 	}
 
 	pci_set_drvdata(pdev, hba);
+	pm_runtime_put_noidle(&pdev->dev);
+	pm_runtime_allow(&pdev->dev);
 
 	return 0;
-
-out_iounmap:
-	iounmap(mmio_base);
-out_release_regions:
-	pci_release_regions(pdev);
-out_disable:
-	pci_clear_master(pdev);
-	pci_disable_device(pdev);
-out_error:
-	return err;
 }
 
+static const struct dev_pm_ops ufshcd_pci_pm_ops = {
+	.suspend	= ufshcd_pci_suspend,
+	.resume		= ufshcd_pci_resume,
+	.runtime_suspend = ufshcd_pci_runtime_suspend,
+	.runtime_resume  = ufshcd_pci_runtime_resume,
+	.runtime_idle    = ufshcd_pci_runtime_idle,
+};
+
 static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = {
 	{ PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	{ }	/* terminate list */
@@ -195,10 +225,9 @@
 	.probe = ufshcd_pci_probe,
 	.remove = ufshcd_pci_remove,
 	.shutdown = ufshcd_pci_shutdown,
-#ifdef CONFIG_PM
-	.suspend = ufshcd_pci_suspend,
-	.resume = ufshcd_pci_resume,
-#endif
+	.driver = {
+		.pm = &ufshcd_pci_pm_ops
+	},
 };
 
 module_pci_driver(ufshcd_pci_driver);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index c42db40..5e46232 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -34,6 +34,7 @@
  */
 
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include "ufshcd.h"
 
@@ -87,6 +88,40 @@
 #define ufshcd_pltfrm_resume	NULL
 #endif
 
+#ifdef CONFIG_PM_RUNTIME
+static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
+{
+	struct ufs_hba *hba =  dev_get_drvdata(dev);
+
+	if (!hba)
+		return 0;
+
+	return ufshcd_runtime_suspend(hba);
+}
+static int ufshcd_pltfrm_runtime_resume(struct device *dev)
+{
+	struct ufs_hba *hba =  dev_get_drvdata(dev);
+
+	if (!hba)
+		return 0;
+
+	return ufshcd_runtime_resume(hba);
+}
+static int ufshcd_pltfrm_runtime_idle(struct device *dev)
+{
+	struct ufs_hba *hba =  dev_get_drvdata(dev);
+
+	if (!hba)
+		return 0;
+
+	return ufshcd_runtime_idle(hba);
+}
+#else /* !CONFIG_PM_RUNTIME */
+#define ufshcd_pltfrm_runtime_suspend	NULL
+#define ufshcd_pltfrm_runtime_resume	NULL
+#define ufshcd_pltfrm_runtime_idle	NULL
+#endif /* CONFIG_PM_RUNTIME */
+
 /**
  * ufshcd_pltfrm_probe - probe routine of the driver
  * @pdev: pointer to Platform device handle
@@ -102,15 +137,8 @@
 	struct device *dev = &pdev->dev;
 
 	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res) {
-		dev_err(dev, "Memory resource not available\n");
-		err = -ENODEV;
-		goto out;
-	}
-
 	mmio_base = devm_ioremap_resource(dev, mem_res);
 	if (IS_ERR(mmio_base)) {
-		dev_err(dev, "memory map failed\n");
 		err = PTR_ERR(mmio_base);
 		goto out;
 	}
@@ -122,14 +150,22 @@
 		goto out;
 	}
 
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	err = ufshcd_init(dev, &hba, mmio_base, irq);
 	if (err) {
 		dev_err(dev, "Intialization failed\n");
-		goto out;
+		goto out_disable_rpm;
 	}
 
 	platform_set_drvdata(pdev, hba);
 
+	return 0;
+
+out_disable_rpm:
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_set_suspended(&pdev->dev);
 out:
 	return err;
 }
@@ -144,7 +180,7 @@
 {
 	struct ufs_hba *hba =  platform_get_drvdata(pdev);
 
-	disable_irq(hba->irq);
+	pm_runtime_get_sync(&(pdev)->dev);
 	ufshcd_remove(hba);
 	return 0;
 }
@@ -157,6 +193,9 @@
 static const struct dev_pm_ops ufshcd_dev_pm_ops = {
 	.suspend	= ufshcd_pltfrm_suspend,
 	.resume		= ufshcd_pltfrm_resume,
+	.runtime_suspend = ufshcd_pltfrm_runtime_suspend,
+	.runtime_resume  = ufshcd_pltfrm_runtime_resume,
+	.runtime_idle    = ufshcd_pltfrm_runtime_idle,
 };
 
 static struct platform_driver ufshcd_pltfrm_driver = {
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b743bd6..b36ca9a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -43,6 +43,19 @@
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT	500
 
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES    10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT    30 /* msecs */
+
+/* Query request retries */
+#define QUERY_REQ_RETRIES 10
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 30 /* msec */
+
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -71,6 +84,40 @@
 	INT_AGGR_CONFIG,
 };
 
+/*
+ * ufshcd_wait_for_register - wait for register value to change
+ * @hba - per-adapter interface
+ * @reg - mmio register offset
+ * @mask - mask to apply to read register value
+ * @val - wait condition
+ * @interval_us - polling interval in microsecs
+ * @timeout_ms - timeout in millisecs
+ *
+ * Returns -ETIMEDOUT on error, zero on success
+ */
+static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+		u32 val, unsigned long interval_us, unsigned long timeout_ms)
+{
+	int err = 0;
+	unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+	/* ignore bits that we don't intend to wait on */
+	val = val & mask;
+
+	while ((ufshcd_readl(hba, reg) & mask) != val) {
+		/* wakeup within 50us of expiry */
+		usleep_range(interval_us, interval_us + 50);
+
+		if (time_after(jiffies, timeout)) {
+			if ((ufshcd_readl(hba, reg) & mask) != val)
+				err = -ETIMEDOUT;
+			break;
+		}
+	}
+
+	return err;
+}
+
 /**
  * ufshcd_get_intr_mask - Get the interrupt bit mask
  * @hba - Pointer to adapter instance
@@ -191,18 +238,13 @@
 }
 
 /**
- * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * ufshcd_get_req_rsp - returns the TR response transaction type
  * @ucd_rsp_ptr: pointer to response UPIU
- *
- * This function checks the response UPIU for valid transaction type in
- * response field
- * Returns 0 on success, non-zero on failure
  */
 static inline int
-ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
 {
-	return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
-		 UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
 }
 
 /**
@@ -219,6 +261,21 @@
 }
 
 /**
+ * ufshcd_is_exception_event - Check if the device raised an exception event
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * The function checks if the device raised an exception event indicated in
+ * the Device Information field of response UPIU.
+ *
+ * Returns true if exception is raised, false otherwise.
+ */
+static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
+			MASK_RSP_EXCEPTION_EVENT ? true : false;
+}
+
+/**
  * ufshcd_config_int_aggr - Configure interrupt aggregation values.
  *		Currently there is no use case where we want to configure
  *		interrupt aggregation dynamically. So to configure interrupt
@@ -299,14 +356,68 @@
 {
 	int len;
 	if (lrbp->sense_buffer) {
-		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
 		memcpy(lrbp->sense_buffer,
-			lrbp->ucd_rsp_ptr->sense_data,
+			lrbp->ucd_rsp_ptr->sr.sense_data,
 			min_t(int, len, SCSI_SENSE_BUFFERSIZE));
 	}
 }
 
 /**
+ * ufshcd_query_to_cpu() - formats the buffer to native cpu endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+	response->length = be16_to_cpu(response->length);
+	response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer to big endian
+ * @request: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+	request->length = cpu_to_be16(request->length);
+	request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ * @hba: per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	struct ufs_query_res *query_res = &hba->dev_cmd.query.response;
+
+	/* Get the UPIU response */
+	query_res->response = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr) >>
+			UPIU_RSP_CODE_OFFSET;
+
+	memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, QUERY_OSF_SIZE);
+	ufshcd_query_to_cpu(&query_res->upiu_res);
+
+
+	/* Get the descriptor */
+	if (lrbp->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 len;
+
+		/* data segment length */
+		len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+
+		memcpy(hba->dev_cmd.query.descriptor, descp,
+				min_t(u16, len, QUERY_DESC_MAX_SIZE));
+	}
+}
+
+/**
  * ufshcd_hba_capabilities - Read controller capabilities
  * @hba: per adapter instance
  */
@@ -519,76 +630,170 @@
 }
 
 /**
+ * ufshcd_prepare_req_desc_hdr() - Fills the requests header
+ * descriptor according to request
+ * @lrbp: pointer to local reference block
+ * @upiu_flags: flags required in the header
+ * @cmd_dir: requests data direction
+ */
+static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
+		u32 *upiu_flags, enum dma_data_direction cmd_dir)
+{
+	struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
+	u32 data_direction;
+	u32 dword_0;
+
+	if (cmd_dir == DMA_FROM_DEVICE) {
+		data_direction = UTP_DEVICE_TO_HOST;
+		*upiu_flags = UPIU_CMD_FLAGS_READ;
+	} else if (cmd_dir == DMA_TO_DEVICE) {
+		data_direction = UTP_HOST_TO_DEVICE;
+		*upiu_flags = UPIU_CMD_FLAGS_WRITE;
+	} else {
+		data_direction = UTP_NO_DATA_TRANSFER;
+		*upiu_flags = UPIU_CMD_FLAGS_NONE;
+	}
+
+	dword_0 = data_direction | (lrbp->command_type
+				<< UPIU_COMMAND_TYPE_OFFSET);
+	if (lrbp->intr_cmd)
+		dword_0 |= UTP_REQ_DESC_INT_CMD;
+
+	/* Transfer request descriptor header fields */
+	req_desc->header.dword_0 = cpu_to_le32(dword_0);
+
+	/*
+	 * assigning invalid value for command status. Controller
+	 * updates OCS on command completion, with the command
+	 * status
+	 */
+	req_desc->header.dword_2 =
+		cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+}
+
+/**
+ * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
+ * for scsi commands
+ * @lrbp - local reference block pointer
+ * @upiu_flags - flags
+ */
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+				UPIU_TRANSACTION_COMMAND, upiu_flags,
+				lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+				UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+	/* Total EHS length and Data segment length will be zero */
+	ucd_req_ptr->header.dword_2 = 0;
+
+	ucd_req_ptr->sc.exp_data_transfer_len =
+		cpu_to_be32(lrbp->cmd->sdb.length);
+
+	memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
+		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+}
+
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+				struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+	struct ufs_query *query = &hba->dev_cmd.query;
+	u16 len = query->request.upiu_req.length;
+	u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+			lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+			0, query->request.query_func, 0, 0);
+
+	/* Data segment length */
+	ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+			0, 0, len >> 8, (u8)len);
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&ucd_req_ptr->qr, &query->request.upiu_req,
+			QUERY_OSF_SIZE);
+	ufshcd_query_to_be(&ucd_req_ptr->qr);
+
+	/* Copy the Descriptor */
+	if ((len > 0) && (query->request.upiu_req.opcode ==
+					UPIU_QUERY_OPCODE_WRITE_DESC)) {
+		memcpy(descp, query->descriptor,
+				min_t(u16, len, QUERY_DESC_MAX_SIZE));
+	}
+}
+
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 =
+		UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+}
+
+/**
  * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @hba - per adapter instance
  * @lrb - pointer to local reference block
  */
-static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 {
-	struct utp_transfer_req_desc *req_desc;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
-	u32 data_direction;
 	u32 upiu_flags;
-
-	ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
-	req_desc = lrbp->utr_descriptor_ptr;
+	int ret = 0;
 
 	switch (lrbp->command_type) {
 	case UTP_CMD_TYPE_SCSI:
-		if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
-			data_direction = UTP_DEVICE_TO_HOST;
-			upiu_flags = UPIU_CMD_FLAGS_READ;
-		} else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
-			data_direction = UTP_HOST_TO_DEVICE;
-			upiu_flags = UPIU_CMD_FLAGS_WRITE;
+		if (likely(lrbp->cmd)) {
+			ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags,
+					lrbp->cmd->sc_data_direction);
+			ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
 		} else {
-			data_direction = UTP_NO_DATA_TRANSFER;
-			upiu_flags = UPIU_CMD_FLAGS_NONE;
+			ret = -EINVAL;
 		}
-
-		/* Transfer request descriptor header fields */
-		req_desc->header.dword_0 =
-			cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
-
-		/*
-		 * assigning invalid value for command status. Controller
-		 * updates OCS on command completion, with the command
-		 * status
-		 */
-		req_desc->header.dword_2 =
-			cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
-		/* command descriptor fields */
-		ucd_cmd_ptr->header.dword_0 =
-			cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
-						      upiu_flags,
-						      lrbp->lun,
-						      lrbp->task_tag));
-		ucd_cmd_ptr->header.dword_1 =
-			cpu_to_be32(
-				UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
-						  0,
-						  0,
-						  0));
-
-		/* Total EHS length and Data segment length will be zero */
-		ucd_cmd_ptr->header.dword_2 = 0;
-
-		ucd_cmd_ptr->exp_data_transfer_len =
-			cpu_to_be32(lrbp->cmd->sdb.length);
-
-		memcpy(ucd_cmd_ptr->cdb,
-		       lrbp->cmd->cmnd,
-		       (min_t(unsigned short,
-			      lrbp->cmd->cmd_len,
-			      MAX_CDB_SIZE)));
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
-		/* For query function implementation */
+		ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE);
+		if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY)
+			ufshcd_prepare_utp_query_req_upiu(
+					hba, lrbp, upiu_flags);
+		else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP)
+			ufshcd_prepare_utp_nop_upiu(lrbp);
+		else
+			ret = -EINVAL;
 		break;
 	case UTP_CMD_TYPE_UFS:
 		/* For UFS native command implementation */
+		ret = -ENOTSUPP;
+		dev_err(hba->dev, "%s: UFS native command are not supported\n",
+			__func__);
+		break;
+	default:
+		ret = -ENOTSUPP;
+		dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
+				__func__, lrbp->command_type);
 		break;
 	} /* end of switch */
+
+	return ret;
 }
 
 /**
@@ -615,21 +820,37 @@
 		goto out;
 	}
 
+	/* acquire the tag to make sure device cmds don't use it */
+	if (test_and_set_bit_lock(tag, &hba->lrb_in_use)) {
+		/*
+		 * Dev manage command in progress, requeue the command.
+		 * Requeuing the command helps in cases where the request *may*
+		 * find different tag instead of waiting for dev manage command
+		 * completion.
+		 */
+		err = SCSI_MLQUEUE_HOST_BUSY;
+		goto out;
+	}
+
 	lrbp = &hba->lrb[tag];
 
+	WARN_ON(lrbp->cmd);
 	lrbp->cmd = cmd;
 	lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE;
 	lrbp->sense_buffer = cmd->sense_buffer;
 	lrbp->task_tag = tag;
 	lrbp->lun = cmd->device->lun;
-
+	lrbp->intr_cmd = false;
 	lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
 	/* form UPIU before issuing the command */
-	ufshcd_compose_upiu(lrbp);
+	ufshcd_compose_upiu(hba, lrbp);
 	err = ufshcd_map_sg(lrbp);
-	if (err)
+	if (err) {
+		lrbp->cmd = NULL;
+		clear_bit_unlock(tag, &hba->lrb_in_use);
 		goto out;
+	}
 
 	/* issue command to the controller */
 	spin_lock_irqsave(hba->host->host_lock, flags);
@@ -639,6 +860,338 @@
 	return err;
 }
 
+static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
+		struct ufshcd_lrb *lrbp, enum dev_cmd_type cmd_type, int tag)
+{
+	lrbp->cmd = NULL;
+	lrbp->sense_bufflen = 0;
+	lrbp->sense_buffer = NULL;
+	lrbp->task_tag = tag;
+	lrbp->lun = 0; /* device management cmd is not specific to any LUN */
+	lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+	lrbp->intr_cmd = true; /* No interrupt aggregation */
+	hba->dev_cmd.type = cmd_type;
+
+	return ufshcd_compose_upiu(hba, lrbp);
+}
+
+static int
+ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
+{
+	int err = 0;
+	unsigned long flags;
+	u32 mask = 1 << tag;
+
+	/* clear outstanding transaction before retry */
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_utrl_clear(hba, tag);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	/*
+	 * wait for for h/w to clear corresponding bit in door-bell.
+	 * max. wait is 1 sec.
+	 */
+	err = ufshcd_wait_for_register(hba,
+			REG_UTP_TRANSFER_REQ_DOOR_BELL,
+			mask, ~mask, 1000, 1000);
+
+	return err;
+}
+
+/**
+ * ufshcd_dev_cmd_completion() - handles device management command responses
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ */
+static int
+ufshcd_dev_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	int resp;
+	int err = 0;
+
+	resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+	switch (resp) {
+	case UPIU_TRANSACTION_NOP_IN:
+		if (hba->dev_cmd.type != DEV_CMD_TYPE_NOP) {
+			err = -EINVAL;
+			dev_err(hba->dev, "%s: unexpected response %x\n",
+					__func__, resp);
+		}
+		break;
+	case UPIU_TRANSACTION_QUERY_RSP:
+		ufshcd_copy_query_response(hba, lrbp);
+		break;
+	case UPIU_TRANSACTION_REJECT_UPIU:
+		/* TODO: handle Reject UPIU Response */
+		err = -EPERM;
+		dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n",
+				__func__);
+		break;
+	default:
+		err = -EINVAL;
+		dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n",
+				__func__, resp);
+		break;
+	}
+
+	return err;
+}
+
+static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba,
+		struct ufshcd_lrb *lrbp, int max_timeout)
+{
+	int err = 0;
+	unsigned long time_left;
+	unsigned long flags;
+
+	time_left = wait_for_completion_timeout(hba->dev_cmd.complete,
+			msecs_to_jiffies(max_timeout));
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	hba->dev_cmd.complete = NULL;
+	if (likely(time_left)) {
+		err = ufshcd_get_tr_ocs(lrbp);
+		if (!err)
+			err = ufshcd_dev_cmd_completion(hba, lrbp);
+	}
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	if (!time_left) {
+		err = -ETIMEDOUT;
+		if (!ufshcd_clear_cmd(hba, lrbp->task_tag))
+			/* sucessfully cleared the command, retry if needed */
+			err = -EAGAIN;
+	}
+
+	return err;
+}
+
+/**
+ * ufshcd_get_dev_cmd_tag - Get device management command tag
+ * @hba: per-adapter instance
+ * @tag: pointer to variable with available slot value
+ *
+ * Get a free slot and lock it until device management command
+ * completes.
+ *
+ * Returns false if free slot is unavailable for locking, else
+ * return true with tag value in @tag.
+ */
+static bool ufshcd_get_dev_cmd_tag(struct ufs_hba *hba, int *tag_out)
+{
+	int tag;
+	bool ret = false;
+	unsigned long tmp;
+
+	if (!tag_out)
+		goto out;
+
+	do {
+		tmp = ~hba->lrb_in_use;
+		tag = find_last_bit(&tmp, hba->nutrs);
+		if (tag >= hba->nutrs)
+			goto out;
+	} while (test_and_set_bit_lock(tag, &hba->lrb_in_use));
+
+	*tag_out = tag;
+	ret = true;
+out:
+	return ret;
+}
+
+static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag)
+{
+	clear_bit_unlock(tag, &hba->lrb_in_use);
+}
+
+/**
+ * ufshcd_exec_dev_cmd - API for sending device management requests
+ * @hba - UFS hba
+ * @cmd_type - specifies the type (NOP, Query...)
+ * @timeout - time in seconds
+ *
+ * NOTE: Since there is only one available tag for device management commands,
+ * it is expected you hold the hba->dev_cmd.lock mutex.
+ */
+static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
+		enum dev_cmd_type cmd_type, int timeout)
+{
+	struct ufshcd_lrb *lrbp;
+	int err;
+	int tag;
+	struct completion wait;
+	unsigned long flags;
+
+	/*
+	 * Get free slot, sleep if slots are unavailable.
+	 * Even though we use wait_event() which sleeps indefinitely,
+	 * the maximum wait time is bounded by SCSI request timeout.
+	 */
+	wait_event(hba->dev_cmd.tag_wq, ufshcd_get_dev_cmd_tag(hba, &tag));
+
+	init_completion(&wait);
+	lrbp = &hba->lrb[tag];
+	WARN_ON(lrbp->cmd);
+	err = ufshcd_compose_dev_cmd(hba, lrbp, cmd_type, tag);
+	if (unlikely(err))
+		goto out_put_tag;
+
+	hba->dev_cmd.complete = &wait;
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_send_command(hba, tag);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	err = ufshcd_wait_for_dev_cmd(hba, lrbp, timeout);
+
+out_put_tag:
+	ufshcd_put_dev_cmd_tag(hba, tag);
+	wake_up(&hba->dev_cmd.tag_wq);
+	return err;
+}
+
+/**
+ * ufshcd_query_flag() - API function for sending flag query requests
+ * hba: per-adapter instance
+ * query_opcode: flag query to perform
+ * idn: flag idn to access
+ * flag_res: the flag value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+			enum flag_idn idn, bool *flag_res)
+{
+	struct ufs_query_req *request;
+	struct ufs_query_res *response;
+	int err;
+
+	BUG_ON(!hba);
+
+	mutex_lock(&hba->dev_cmd.lock);
+	request = &hba->dev_cmd.query.request;
+	response = &hba->dev_cmd.query.response;
+	memset(request, 0, sizeof(struct ufs_query_req));
+	memset(response, 0, sizeof(struct ufs_query_res));
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_SET_FLAG:
+	case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+	case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_FLAG:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		if (!flag_res) {
+			/* No dummy reads */
+			dev_err(hba->dev, "%s: Invalid argument for read request\n",
+					__func__);
+			err = -EINVAL;
+			goto out_unlock;
+		}
+		break;
+	default:
+		dev_err(hba->dev,
+			"%s: Expected query flag opcode but got = %d\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out_unlock;
+	}
+	request->upiu_req.opcode = opcode;
+	request->upiu_req.idn = idn;
+
+	/* Send query request */
+	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY,
+			QUERY_REQ_TIMEOUT);
+
+	if (err) {
+		dev_err(hba->dev,
+			"%s: Sending flag query for idn %d failed, err = %d\n",
+			__func__, idn, err);
+		goto out_unlock;
+	}
+
+	if (flag_res)
+		*flag_res = (response->upiu_res.value &
+				MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out_unlock:
+	mutex_unlock(&hba->dev_cmd.lock);
+	return err;
+}
+
+/**
+ * ufshcd_query_attr - API function for sending attribute requests
+ * hba: per-adapter instance
+ * opcode: attribute opcode
+ * idn: attribute idn to access
+ * index: index field
+ * selector: selector field
+ * attr_val: the attribute value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+*/
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+			enum attr_idn idn, u8 index, u8 selector, u32 *attr_val)
+{
+	struct ufs_query_req *request;
+	struct ufs_query_res *response;
+	int err;
+
+	BUG_ON(!hba);
+
+	if (!attr_val) {
+		dev_err(hba->dev, "%s: attribute value required for opcode 0x%x\n",
+				__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+
+	mutex_lock(&hba->dev_cmd.lock);
+	request = &hba->dev_cmd.query.request;
+	response = &hba->dev_cmd.query.response;
+	memset(request, 0, sizeof(struct ufs_query_req));
+	memset(response, 0, sizeof(struct ufs_query_res));
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_WRITE_ATTR:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		request->upiu_req.value = *attr_val;
+		break;
+	case UPIU_QUERY_OPCODE_READ_ATTR:
+		request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		break;
+	default:
+		dev_err(hba->dev, "%s: Expected query attr opcode but got = 0x%.2x\n",
+				__func__, opcode);
+		err = -EINVAL;
+		goto out_unlock;
+	}
+
+	request->upiu_req.opcode = opcode;
+	request->upiu_req.idn = idn;
+	request->upiu_req.index = index;
+	request->upiu_req.selector = selector;
+
+	/* Send query request */
+	err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY,
+						QUERY_REQ_TIMEOUT);
+
+	if (err) {
+		dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, err = %d\n",
+				__func__, opcode, idn, err);
+		goto out_unlock;
+	}
+
+	*attr_val = response->upiu_res.value;
+
+out_unlock:
+	mutex_unlock(&hba->dev_cmd.lock);
+out:
+	return err;
+}
+
 /**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
@@ -774,8 +1327,8 @@
 				cpu_to_le16(ALIGNED_UPIU_SIZE >> 2);
 
 		hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
-		hba->lrb[i].ucd_cmd_ptr =
-			(struct utp_upiu_cmd *)(cmd_descp + i);
+		hba->lrb[i].ucd_req_ptr =
+			(struct utp_upiu_req *)(cmd_descp + i);
 		hba->lrb[i].ucd_rsp_ptr =
 			(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
 		hba->lrb[i].ucd_prdt_ptr =
@@ -809,6 +1362,57 @@
 }
 
 /**
+ * ufshcd_complete_dev_init() - checks device readiness
+ * hba: per-adapter instance
+ *
+ * Set fDeviceInit flag and poll until device toggles it.
+ */
+static int ufshcd_complete_dev_init(struct ufs_hba *hba)
+{
+	int i, retries, err = 0;
+	bool flag_res = 1;
+
+	for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+		/* Set the fDeviceInit flag */
+		err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, NULL);
+		if (!err || err == -ETIMEDOUT)
+			break;
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+	if (err) {
+		dev_err(hba->dev,
+			"%s setting fDeviceInit flag failed with error %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/* poll for max. 100 iterations for fDeviceInit flag to clear */
+	for (i = 0; i < 100 && !err && flag_res; i++) {
+		for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+			err = ufshcd_query_flag(hba,
+					UPIU_QUERY_OPCODE_READ_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+			if (!err || err == -ETIMEDOUT)
+				break;
+			dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
+					err);
+		}
+	}
+	if (err)
+		dev_err(hba->dev,
+			"%s reading fDeviceInit flag failed with error %d\n",
+			__func__, err);
+	else if (flag_res)
+		dev_err(hba->dev,
+			"%s fDeviceInit was not cleared by the device\n",
+			__func__);
+
+out:
+	return err;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -961,6 +1565,38 @@
 }
 
 /**
+ * ufshcd_verify_dev_init() - Verify device initialization
+ * @hba: per-adapter instance
+ *
+ * Send NOP OUT UPIU and wait for NOP IN response to check whether the
+ * device Transport Protocol (UTP) layer is ready after a reset.
+ * If the UTP layer at the device side is not initialized, it may
+ * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
+ * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
+ */
+static int ufshcd_verify_dev_init(struct ufs_hba *hba)
+{
+	int err = 0;
+	int retries;
+
+	mutex_lock(&hba->dev_cmd.lock);
+	for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
+		err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP,
+					       NOP_OUT_TIMEOUT);
+
+		if (!err || err == -ETIMEDOUT)
+			break;
+
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+	mutex_unlock(&hba->dev_cmd.lock);
+
+	if (err)
+		dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+	return err;
+}
+
+/**
  * ufshcd_do_reset - reset the host controller
  * @hba: per adapter instance
  *
@@ -986,13 +1622,20 @@
 	for (tag = 0; tag < hba->nutrs; tag++) {
 		if (test_bit(tag, &hba->outstanding_reqs)) {
 			lrbp = &hba->lrb[tag];
-			scsi_dma_unmap(lrbp->cmd);
-			lrbp->cmd->result = DID_RESET << 16;
-			lrbp->cmd->scsi_done(lrbp->cmd);
-			lrbp->cmd = NULL;
+			if (lrbp->cmd) {
+				scsi_dma_unmap(lrbp->cmd);
+				lrbp->cmd->result = DID_RESET << 16;
+				lrbp->cmd->scsi_done(lrbp->cmd);
+				lrbp->cmd = NULL;
+				clear_bit_unlock(tag, &hba->lrb_in_use);
+			}
 		}
 	}
 
+	/* complete device management command */
+	if (hba->dev_cmd.complete)
+		complete(hba->dev_cmd.complete);
+
 	/* clear outstanding request/task bit maps */
 	hba->outstanding_reqs = 0;
 	hba->outstanding_tasks = 0;
@@ -1199,27 +1842,39 @@
 
 	switch (ocs) {
 	case OCS_SUCCESS:
+		result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
 
-		/* check if the returned transfer response is valid */
-		result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
-		if (result) {
+		switch (result) {
+		case UPIU_TRANSACTION_RESPONSE:
+			/*
+			 * get the response UPIU result to extract
+			 * the SCSI command status
+			 */
+			result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+			/*
+			 * get the result based on SCSI status response
+			 * to notify the SCSI midlayer of the command status
+			 */
+			scsi_status = result & MASK_SCSI_STATUS;
+			result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
+
+			if (ufshcd_is_exception_event(lrbp->ucd_rsp_ptr))
+				schedule_work(&hba->eeh_work);
+			break;
+		case UPIU_TRANSACTION_REJECT_UPIU:
+			/* TODO: handle Reject UPIU Response */
+			result = DID_ERROR << 16;
 			dev_err(hba->dev,
-				"Invalid response = %x\n", result);
+				"Reject UPIU not fully implemented\n");
+			break;
+		default:
+			result = DID_ERROR << 16;
+			dev_err(hba->dev,
+				"Unexpected request response code = %x\n",
+				result);
 			break;
 		}
-
-		/*
-		 * get the response UPIU result to extract
-		 * the SCSI command status
-		 */
-		result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
-		/*
-		 * get the result based on SCSI status response
-		 * to notify the SCSI midlayer of the command status
-		 */
-		scsi_status = result & MASK_SCSI_STATUS;
-		result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
 		break;
 	case OCS_ABORTED:
 		result |= DID_ABORT << 16;
@@ -1259,28 +1914,40 @@
  */
 static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
-	struct ufshcd_lrb *lrb;
+	struct ufshcd_lrb *lrbp;
+	struct scsi_cmnd *cmd;
 	unsigned long completed_reqs;
 	u32 tr_doorbell;
 	int result;
 	int index;
+	bool int_aggr_reset = false;
 
-	lrb = hba->lrb;
 	tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 	completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
 	for (index = 0; index < hba->nutrs; index++) {
 		if (test_bit(index, &completed_reqs)) {
+			lrbp = &hba->lrb[index];
+			cmd = lrbp->cmd;
+			/*
+			 * Don't skip resetting interrupt aggregation counters
+			 * if a regular command is present.
+			 */
+			int_aggr_reset |= !lrbp->intr_cmd;
 
-			result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
-
-			if (lrb[index].cmd) {
-				scsi_dma_unmap(lrb[index].cmd);
-				lrb[index].cmd->result = result;
-				lrb[index].cmd->scsi_done(lrb[index].cmd);
-
+			if (cmd) {
+				result = ufshcd_transfer_rsp_status(hba, lrbp);
+				scsi_dma_unmap(cmd);
+				cmd->result = result;
 				/* Mark completed command as NULL in LRB */
-				lrb[index].cmd = NULL;
+				lrbp->cmd = NULL;
+				clear_bit_unlock(index, &hba->lrb_in_use);
+				/* Do not touch lrbp after scsi done */
+				cmd->scsi_done(cmd);
+			} else if (lrbp->command_type ==
+					UTP_CMD_TYPE_DEV_MANAGE) {
+				if (hba->dev_cmd.complete)
+					complete(hba->dev_cmd.complete);
 			}
 		} /* end of if */
 	} /* end of for */
@@ -1288,8 +1955,238 @@
 	/* clear corresponding bits of completed commands */
 	hba->outstanding_reqs ^= completed_reqs;
 
+	/* we might have free'd some tags above */
+	wake_up(&hba->dev_cmd.tag_wq);
+
 	/* Reset interrupt aggregation counters */
-	ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+	if (int_aggr_reset)
+		ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+}
+
+/**
+ * ufshcd_disable_ee - disable exception event
+ * @hba: per-adapter instance
+ * @mask: exception event to disable
+ *
+ * Disables exception event in the device so that the EVENT_ALERT
+ * bit is not set.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask)
+{
+	int err = 0;
+	u32 val;
+
+	if (!(hba->ee_ctrl_mask & mask))
+		goto out;
+
+	val = hba->ee_ctrl_mask & ~mask;
+	val &= 0xFFFF; /* 2 bytes */
+	err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+			QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
+	if (!err)
+		hba->ee_ctrl_mask &= ~mask;
+out:
+	return err;
+}
+
+/**
+ * ufshcd_enable_ee - enable exception event
+ * @hba: per-adapter instance
+ * @mask: exception event to enable
+ *
+ * Enable corresponding exception event in the device to allow
+ * device to alert host in critical scenarios.
+ *
+ * Returns zero on success, non-zero error value on failure.
+ */
+static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask)
+{
+	int err = 0;
+	u32 val;
+
+	if (hba->ee_ctrl_mask & mask)
+		goto out;
+
+	val = hba->ee_ctrl_mask | mask;
+	val &= 0xFFFF; /* 2 bytes */
+	err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+			QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val);
+	if (!err)
+		hba->ee_ctrl_mask |= mask;
+out:
+	return err;
+}
+
+/**
+ * ufshcd_enable_auto_bkops - Allow device managed BKOPS
+ * @hba: per-adapter instance
+ *
+ * Allow device to manage background operations on its own. Enabling
+ * this might lead to inconsistent latencies during normal data transfers
+ * as the device is allowed to manage its own way of handling background
+ * operations.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+static int ufshcd_enable_auto_bkops(struct ufs_hba *hba)
+{
+	int err = 0;
+
+	if (hba->auto_bkops_enabled)
+		goto out;
+
+	err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+			QUERY_FLAG_IDN_BKOPS_EN, NULL);
+	if (err) {
+		dev_err(hba->dev, "%s: failed to enable bkops %d\n",
+				__func__, err);
+		goto out;
+	}
+
+	hba->auto_bkops_enabled = true;
+
+	/* No need of URGENT_BKOPS exception from the device */
+	err = ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS);
+	if (err)
+		dev_err(hba->dev, "%s: failed to disable exception event %d\n",
+				__func__, err);
+out:
+	return err;
+}
+
+/**
+ * ufshcd_disable_auto_bkops - block device in doing background operations
+ * @hba: per-adapter instance
+ *
+ * Disabling background operations improves command response latency but
+ * has drawback of device moving into critical state where the device is
+ * not-operable. Make sure to call ufshcd_enable_auto_bkops() whenever the
+ * host is idle so that BKOPS are managed effectively without any negative
+ * impacts.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+static int ufshcd_disable_auto_bkops(struct ufs_hba *hba)
+{
+	int err = 0;
+
+	if (!hba->auto_bkops_enabled)
+		goto out;
+
+	/*
+	 * If host assisted BKOPs is to be enabled, make sure
+	 * urgent bkops exception is allowed.
+	 */
+	err = ufshcd_enable_ee(hba, MASK_EE_URGENT_BKOPS);
+	if (err) {
+		dev_err(hba->dev, "%s: failed to enable exception event %d\n",
+				__func__, err);
+		goto out;
+	}
+
+	err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
+			QUERY_FLAG_IDN_BKOPS_EN, NULL);
+	if (err) {
+		dev_err(hba->dev, "%s: failed to disable bkops %d\n",
+				__func__, err);
+		ufshcd_disable_ee(hba, MASK_EE_URGENT_BKOPS);
+		goto out;
+	}
+
+	hba->auto_bkops_enabled = false;
+out:
+	return err;
+}
+
+/**
+ * ufshcd_force_reset_auto_bkops - force enable of auto bkops
+ * @hba: per adapter instance
+ *
+ * After a device reset the device may toggle the BKOPS_EN flag
+ * to default value. The s/w tracking variables should be updated
+ * as well. Do this by forcing enable of auto bkops.
+ */
+static void  ufshcd_force_reset_auto_bkops(struct ufs_hba *hba)
+{
+	hba->auto_bkops_enabled = false;
+	hba->ee_ctrl_mask |= MASK_EE_URGENT_BKOPS;
+	ufshcd_enable_auto_bkops(hba);
+}
+
+static inline int ufshcd_get_bkops_status(struct ufs_hba *hba, u32 *status)
+{
+	return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+			QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, status);
+}
+
+/**
+ * ufshcd_urgent_bkops - handle urgent bkops exception event
+ * @hba: per-adapter instance
+ *
+ * Enable fBackgroundOpsEn flag in the device to permit background
+ * operations.
+ */
+static int ufshcd_urgent_bkops(struct ufs_hba *hba)
+{
+	int err;
+	u32 status = 0;
+
+	err = ufshcd_get_bkops_status(hba, &status);
+	if (err) {
+		dev_err(hba->dev, "%s: failed to get BKOPS status %d\n",
+				__func__, err);
+		goto out;
+	}
+
+	status = status & 0xF;
+
+	/* handle only if status indicates performance impact or critical */
+	if (status >= BKOPS_STATUS_PERF_IMPACT)
+		err = ufshcd_enable_auto_bkops(hba);
+out:
+	return err;
+}
+
+static inline int ufshcd_get_ee_status(struct ufs_hba *hba, u32 *status)
+{
+	return ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+			QUERY_ATTR_IDN_EE_STATUS, 0, 0, status);
+}
+
+/**
+ * ufshcd_exception_event_handler - handle exceptions raised by device
+ * @work: pointer to work data
+ *
+ * Read bExceptionEventStatus attribute from the device and handle the
+ * exception event accordingly.
+ */
+static void ufshcd_exception_event_handler(struct work_struct *work)
+{
+	struct ufs_hba *hba;
+	int err;
+	u32 status = 0;
+	hba = container_of(work, struct ufs_hba, eeh_work);
+
+	pm_runtime_get_sync(hba->dev);
+	err = ufshcd_get_ee_status(hba, &status);
+	if (err) {
+		dev_err(hba->dev, "%s: failed to get exception status %d\n",
+				__func__, err);
+		goto out;
+	}
+
+	status &= hba->ee_ctrl_mask;
+	if (status & MASK_EE_URGENT_BKOPS) {
+		err = ufshcd_urgent_bkops(hba);
+		if (err)
+			dev_err(hba->dev, "%s: failed to handle urgent bkops %d\n",
+					__func__, err);
+	}
+out:
+	pm_runtime_put_sync(hba->dev);
+	return;
 }
 
 /**
@@ -1301,9 +2198,11 @@
 	struct ufs_hba *hba;
 	hba = container_of(work, struct ufs_hba, feh_workq);
 
+	pm_runtime_get_sync(hba->dev);
 	/* check if reset is already in progress */
 	if (hba->ufshcd_state != UFSHCD_STATE_RESET)
 		ufshcd_do_reset(hba);
+	pm_runtime_put_sync(hba->dev);
 }
 
 /**
@@ -1432,10 +2331,10 @@
 	task_req_upiup =
 		(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
 	task_req_upiup->header.dword_0 =
-		cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
-					      lrbp->lun, lrbp->task_tag));
+		UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+					      lrbp->lun, lrbp->task_tag);
 	task_req_upiup->header.dword_1 =
-	cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+		UPIU_HEADER_DWORD(0, tm_function, 0, 0);
 
 	task_req_upiup->input_param1 = lrbp->lun;
 	task_req_upiup->input_param1 =
@@ -1502,9 +2401,11 @@
 			if (hba->lrb[pos].cmd) {
 				scsi_dma_unmap(hba->lrb[pos].cmd);
 				hba->lrb[pos].cmd->result =
-						DID_ABORT << 16;
+					DID_ABORT << 16;
 				hba->lrb[pos].cmd->scsi_done(cmd);
 				hba->lrb[pos].cmd = NULL;
+				clear_bit_unlock(pos, &hba->lrb_in_use);
+				wake_up(&hba->dev_cmd.tag_wq);
 			}
 		}
 	} /* end of for */
@@ -1572,6 +2473,9 @@
 	__clear_bit(tag, &hba->outstanding_reqs);
 	hba->lrb[tag].cmd = NULL;
 	spin_unlock_irqrestore(host->host_lock, flags);
+
+	clear_bit_unlock(tag, &hba->lrb_in_use);
+	wake_up(&hba->dev_cmd.tag_wq);
 out:
 	return err;
 }
@@ -1587,8 +2491,22 @@
 	int ret;
 
 	ret = ufshcd_link_startup(hba);
-	if (!ret)
-		scsi_scan_host(hba->host);
+	if (ret)
+		goto out;
+
+	ret = ufshcd_verify_dev_init(hba);
+	if (ret)
+		goto out;
+
+	ret = ufshcd_complete_dev_init(hba);
+	if (ret)
+		goto out;
+
+	ufshcd_force_reset_auto_bkops(hba);
+	scsi_scan_host(hba->host);
+	pm_runtime_put_sync(hba->dev);
+out:
+	return;
 }
 
 static struct scsi_host_template ufshcd_driver_template = {
@@ -1650,6 +2568,34 @@
 }
 EXPORT_SYMBOL_GPL(ufshcd_resume);
 
+int ufshcd_runtime_suspend(struct ufs_hba *hba)
+{
+	if (!hba)
+		return 0;
+
+	/*
+	 * The device is idle with no requests in the queue,
+	 * allow background operations.
+	 */
+	return ufshcd_enable_auto_bkops(hba);
+}
+EXPORT_SYMBOL(ufshcd_runtime_suspend);
+
+int ufshcd_runtime_resume(struct ufs_hba *hba)
+{
+	if (!hba)
+		return 0;
+
+	return ufshcd_disable_auto_bkops(hba);
+}
+EXPORT_SYMBOL(ufshcd_runtime_resume);
+
+int ufshcd_runtime_idle(struct ufs_hba *hba)
+{
+	return 0;
+}
+EXPORT_SYMBOL(ufshcd_runtime_idle);
+
 /**
  * ufshcd_remove - de-allocate SCSI host and host memory space
  *		data structure memory
@@ -1657,11 +2603,11 @@
  */
 void ufshcd_remove(struct ufs_hba *hba)
 {
+	scsi_remove_host(hba->host);
 	/* disable interrupts */
 	ufshcd_disable_intr(hba, hba->intr_mask);
 	ufshcd_hba_stop(hba);
 
-	scsi_remove_host(hba->host);
 	scsi_host_put(hba->host);
 }
 EXPORT_SYMBOL_GPL(ufshcd_remove);
@@ -1740,10 +2686,17 @@
 
 	/* Initialize work queues */
 	INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler);
+	INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
 
 	/* Initialize UIC command mutex */
 	mutex_init(&hba->uic_cmd_mutex);
 
+	/* Initialize mutex for device management commands */
+	mutex_init(&hba->dev_cmd.lock);
+
+	/* Initialize device management tag acquire wait queue */
+	init_waitqueue_head(&hba->dev_cmd.tag_wq);
+
 	/* IRQ registration */
 	err = devm_request_irq(dev, irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
 	if (err) {
@@ -1773,6 +2726,9 @@
 
 	*hba_handle = hba;
 
+	/* Hold auto suspend until async scan completes */
+	pm_runtime_get_sync(dev);
+
 	async_schedule(ufshcd_async_scan, hba);
 
 	return 0;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 49590ee..59c9c48 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -68,6 +68,11 @@
 #define UFSHCD "ufshcd"
 #define UFSHCD_DRIVER_VERSION "0.2"
 
+enum dev_cmd_type {
+	DEV_CMD_TYPE_NOP		= 0x0,
+	DEV_CMD_TYPE_QUERY		= 0x1,
+};
+
 /**
  * struct uic_command - UIC command structure
  * @command: UIC command
@@ -91,7 +96,7 @@
 /**
  * struct ufshcd_lrb - local reference block
  * @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_req_ptr: UCD address of the command
  * @ucd_rsp_ptr: Response UPIU address for this command
  * @ucd_prdt_ptr: PRDT address of the command
  * @cmd: pointer to SCSI command
@@ -101,10 +106,11 @@
  * @command_type: SCSI, UFS, Query.
  * @task_tag: Task tag of the command
  * @lun: LUN of the command
+ * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
  */
 struct ufshcd_lrb {
 	struct utp_transfer_req_desc *utr_descriptor_ptr;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
+	struct utp_upiu_req *ucd_req_ptr;
 	struct utp_upiu_rsp *ucd_rsp_ptr;
 	struct ufshcd_sg_entry *ucd_prdt_ptr;
 
@@ -116,8 +122,35 @@
 	int command_type;
 	int task_tag;
 	unsigned int lun;
+	bool intr_cmd;
 };
 
+/**
+ * struct ufs_query - holds relevent data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+	struct ufs_query_req request;
+	u8 *descriptor;
+	struct ufs_query_res response;
+};
+
+/**
+ * struct ufs_dev_cmd - all assosiated fields with device management commands
+ * @type: device management command type - Query, NOP OUT
+ * @lock: lock to allow one command at a time
+ * @complete: internal commands completion
+ * @tag_wq: wait queue until free command slot is available
+ */
+struct ufs_dev_cmd {
+	enum dev_cmd_type type;
+	struct mutex lock;
+	struct completion *complete;
+	wait_queue_head_t tag_wq;
+	struct ufs_query query;
+};
 
 /**
  * struct ufs_hba - per adapter private structure
@@ -131,6 +164,7 @@
  * @host: Scsi_Host instance of the driver
  * @dev: device handle
  * @lrb: local reference block
+ * @lrb_in_use: lrb in use
  * @outstanding_tasks: Bits representing outstanding task requests
  * @outstanding_reqs: Bits representing outstanding transfer requests
  * @capabilities: UFS Controller Capabilities
@@ -144,8 +178,12 @@
  * @tm_condition: condition variable for task management
  * @ufshcd_state: UFSHCD states
  * @intr_mask: Interrupt Mask Bits
+ * @ee_ctrl_mask: Exception event control mask
  * @feh_workq: Work queue for fatal controller error handling
+ * @eeh_work: Worker to handle exception events
  * @errors: HBA errors
+ * @dev_cmd: ufs device management command information
+ * @auto_bkops_enabled: to track whether bkops is enabled in device
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -164,6 +202,7 @@
 	struct device *dev;
 
 	struct ufshcd_lrb *lrb;
+	unsigned long lrb_in_use;
 
 	unsigned long outstanding_tasks;
 	unsigned long outstanding_reqs;
@@ -182,12 +221,19 @@
 
 	u32 ufshcd_state;
 	u32 intr_mask;
+	u16 ee_ctrl_mask;
 
 	/* Work Queues */
 	struct work_struct feh_workq;
+	struct work_struct eeh_work;
 
 	/* HBA Errors */
 	u32 errors;
+
+	/* Device management request data */
+	struct ufs_dev_cmd dev_cmd;
+
+	bool auto_bkops_enabled;
 };
 
 #define ufshcd_writel(hba, val, reg)	\
@@ -208,4 +254,13 @@
 	ufshcd_writel(hba, CONTROLLER_DISABLE,  REG_CONTROLLER_ENABLE);
 }
 
+static inline void check_upiu_size(void)
+{
+	BUILD_BUG_ON(ALIGNED_UPIU_SIZE <
+		GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
+}
+
+extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
+extern int ufshcd_runtime_resume(struct ufs_hba *hba);
+extern int ufshcd_runtime_idle(struct ufs_hba *hba);
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
-	ALIGNED_UPIU_SIZE		= 128,
+	ALIGNED_UPIU_SIZE		= 512,
 };
 
 /* UFSHCI Registers */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 89cbbab..0170d4c 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -70,14 +70,14 @@
 
 config SPI_ATMEL
 	tristate "Atmel SPI Controller"
-	depends on (ARCH_AT91 || AVR32)
+	depends on (ARCH_AT91 || AVR32 || COMPILE_TEST)
 	help
 	  This selects a driver for the Atmel SPI Controller, present on
 	  many AT32 (AVR32) and AT91 (ARM) chips.
 
 config SPI_BCM2835
 	tristate "BCM2835 SPI controller"
-	depends on ARCH_BCM2835
+	depends on ARCH_BCM2835 || COMPILE_TEST
 	help
 	  This selects a driver for the Broadcom BCM2835 SPI master.
 
@@ -88,10 +88,17 @@
 
 config SPI_BFIN5XX
 	tristate "SPI controller driver for ADI Blackfin5xx"
-	depends on BLACKFIN
+	depends on BLACKFIN && !BF60x
 	help
 	  This is the SPI controller master driver for Blackfin 5xx processor.
 
+config SPI_BFIN_V3
+	tristate "SPI controller v3 for Blackfin"
+	depends on BF60x
+	help
+	  This is the SPI controller v3 master driver
+	  found on Blackfin 60x processor.
+
 config SPI_BFIN_SPORT
 	tristate "SPI bus via Blackfin SPORT"
 	depends on BLACKFIN
@@ -151,15 +158,22 @@
 
 config SPI_DAVINCI
 	tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
-	depends on ARCH_DAVINCI
+	depends on ARCH_DAVINCI || ARCH_KEYSTONE
 	select SPI_BITBANG
 	select TI_EDMA
 	help
 	  SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
 
+config SPI_EFM32
+	tristate "EFM32 SPI controller"
+	depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
+	select SPI_BITBANG
+	help
+	  Driver for the spi controller found on Energy Micro's EFM32 SoCs.
+
 config SPI_EP93XX
 	tristate "Cirrus Logic EP93xx SPI controller"
-	depends on ARCH_EP93XX
+	depends on ARCH_EP93XX || COMPILE_TEST
 	help
 	  This enables using the Cirrus EP93xx SPI controller in master
 	  mode.
@@ -191,7 +205,7 @@
 
 config SPI_IMX
 	tristate "Freescale i.MX SPI controllers"
-	depends on ARCH_MXC
+	depends on ARCH_MXC || COMPILE_TEST
 	select SPI_BITBANG
 	default m if IMX_HAVE_PLATFORM_SPI_IMX
 	help
@@ -248,6 +262,13 @@
 	  This also enables using the Aeroflex Gaisler GRLIB SPI controller in
 	  master mode.
 
+config SPI_FSL_DSPI
+	tristate "Freescale DSPI controller"
+	select SPI_BITBANG
+	help
+	  This enables support for the Freescale DSPI controller in master
+	  mode. VF610 platform uses the controller.
+
 config SPI_FSL_ESPI
 	bool "Freescale eSPI controller"
 	depends on FSL_SOC
@@ -280,20 +301,28 @@
 
 config SPI_OMAP24XX
 	tristate "McSPI driver for OMAP"
-	depends on ARCH_OMAP2PLUS
+	depends on ARCH_OMAP2PLUS || COMPILE_TEST
 	help
 	  SPI master controller for OMAP24XX and later Multichannel SPI
 	  (McSPI) modules.
 
+config SPI_TI_QSPI
+	tristate "DRA7xxx QSPI controller support"
+	depends on ARCH_OMAP2PLUS || COMPILE_TEST
+	help
+	  QSPI master controller for DRA7xxx used for flash devices.
+	  This device supports single, dual and quad read support, while
+	  it only supports single write mode.
+
 config SPI_OMAP_100K
 	tristate "OMAP SPI 100K"
-	depends on ARCH_OMAP850 || ARCH_OMAP730
+	depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST
 	help
 	  OMAP SPI 100K master controller for omap7xx boards.
 
 config SPI_ORION
 	tristate "Orion SPI master"
-	depends on PLAT_ORION
+	depends on PLAT_ORION || COMPILE_TEST
 	help
 	  This enables using the SPI master controller on the Orion chips.
 
@@ -341,7 +370,7 @@
 
 config SPI_RSPI
 	tristate "Renesas RSPI controller"
-	depends on SUPERH
+	depends on SUPERH && SH_DMAE_BASE
 	help
 	  SPI driver for Renesas RSPI blocks.
 
@@ -385,7 +414,7 @@
 
 config SPI_SH
 	tristate "SuperH SPI controller"
-	depends on SUPERH
+	depends on SUPERH || COMPILE_TEST
 	help
 	  SPI driver for SuperH SPI blocks.
 
@@ -398,13 +427,13 @@
 
 config SPI_SH_HSPI
 	tristate "SuperH HSPI controller"
-	depends on ARCH_SHMOBILE
+	depends on ARCH_SHMOBILE || COMPILE_TEST
 	help
 	  SPI driver for SuperH HSPI blocks.
 
 config SPI_SIRF
 	tristate "CSR SiRFprimaII SPI controller"
-	depends on ARCH_SIRF
+	depends on SIRF_DMA
 	select SPI_BITBANG
 	help
 	  SPI driver for CSR SiRFprimaII SoCs
@@ -418,7 +447,7 @@
 
 config SPI_TEGRA114
 	tristate "NVIDIA Tegra114 SPI Controller"
-	depends on ARCH_TEGRA && TEGRA20_APB_DMA
+	depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
 	help
 	  SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
 	  is different than the older SoCs SPI controller and also register interface
@@ -426,7 +455,7 @@
 
 config SPI_TEGRA20_SFLASH
 	tristate "Nvidia Tegra20 Serial flash Controller"
-	depends on ARCH_TEGRA
+	depends on ARCH_TEGRA || COMPILE_TEST
 	help
 	  SPI driver for Nvidia Tegra20 Serial flash Controller interface.
 	  The main usecase of this controller is to use spi flash as boot
@@ -434,7 +463,7 @@
 
 config SPI_TEGRA20_SLINK
 	tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
-	depends on ARCH_TEGRA && TEGRA20_APB_DMA
+	depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
 	help
 	  SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
 
@@ -457,7 +486,7 @@
 
 config SPI_TXX9
 	tristate "Toshiba TXx9 SPI controller"
-	depends on GPIOLIB && CPU_TX49XX
+	depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST)
 	help
 	  SPI driver for Toshiba TXx9 MIPS SoCs
 
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 33f9c09..ab8d864 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_SPI_BCM2835)		+= spi-bcm2835.o
 obj-$(CONFIG_SPI_BCM63XX)		+= spi-bcm63xx.o
 obj-$(CONFIG_SPI_BFIN5XX)		+= spi-bfin5xx.o
+obj-$(CONFIG_SPI_BFIN_V3)               += spi-bfin-v3.o
 obj-$(CONFIG_SPI_BFIN_SPORT)		+= spi-bfin-sport.o
 obj-$(CONFIG_SPI_BITBANG)		+= spi-bitbang.o
 obj-$(CONFIG_SPI_BUTTERFLY)		+= spi-butterfly.o
@@ -27,9 +28,11 @@
 obj-$(CONFIG_SPI_DW_MMIO)		+= spi-dw-mmio.o
 obj-$(CONFIG_SPI_DW_PCI)		+= spi-dw-midpci.o
 spi-dw-midpci-objs			:= spi-dw-pci.o spi-dw-mid.o
+obj-$(CONFIG_SPI_EFM32)			+= spi-efm32.o
 obj-$(CONFIG_SPI_EP93XX)		+= spi-ep93xx.o
 obj-$(CONFIG_SPI_FALCON)		+= spi-falcon.o
 obj-$(CONFIG_SPI_FSL_CPM)		+= spi-fsl-cpm.o
+obj-$(CONFIG_SPI_FSL_DSPI)		+= spi-fsl-dspi.o
 obj-$(CONFIG_SPI_FSL_LIB)		+= spi-fsl-lib.o
 obj-$(CONFIG_SPI_FSL_ESPI)		+= spi-fsl-espi.o
 obj-$(CONFIG_SPI_FSL_SPI)		+= spi-fsl-spi.o
@@ -46,6 +49,7 @@
 obj-$(CONFIG_SPI_OMAP_UWIRE)		+= spi-omap-uwire.o
 obj-$(CONFIG_SPI_OMAP_100K)		+= spi-omap-100k.o
 obj-$(CONFIG_SPI_OMAP24XX)		+= spi-omap2-mcspi.o
+obj-$(CONFIG_SPI_TI_QSPI)		+= spi-ti-qspi.o
 obj-$(CONFIG_SPI_ORION)			+= spi-orion.o
 obj-$(CONFIG_SPI_PL022)			+= spi-pl022.o
 obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c
index 81b9adb..f38855f 100644
--- a/drivers/spi/spi-altera.c
+++ b/drivers/spi/spi-altera.c
@@ -103,16 +103,6 @@
 	}
 }
 
-static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
-{
-	return 0;
-}
-
-static int altera_spi_setup(struct spi_device *spi)
-{
-	return 0;
-}
-
 static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
 {
 	if (hw->tx) {
@@ -134,7 +124,7 @@
 	hw->tx = t->tx_buf;
 	hw->rx = t->rx_buf;
 	hw->count = 0;
-	hw->bytes_per_word = t->bits_per_word / 8;
+	hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
 	hw->len = t->len / hw->bytes_per_word;
 
 	if (hw->irq >= 0) {
@@ -150,12 +140,12 @@
 		hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
 		writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
 	} else {
-		/* send the first byte */
-		writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
-
-		while (1) {
+		while (hw->count < hw->len) {
 			unsigned int rxd;
 
+			writel(hw_txbyte(hw, hw->count),
+			       hw->base + ALTERA_SPI_TXDATA);
+
 			while (!(readl(hw->base + ALTERA_SPI_STATUS) &
 				 ALTERA_SPI_STATUS_RRDY_MSK))
 				cpu_relax();
@@ -174,14 +164,7 @@
 			}
 
 			hw->count++;
-
-			if (hw->count < hw->len)
-				writel(hw_txbyte(hw, hw->count),
-				       hw->base + ALTERA_SPI_TXDATA);
-			else
-				break;
 		}
-
 	}
 
 	return hw->count * hw->bytes_per_word;
@@ -217,7 +200,7 @@
 
 static int altera_spi_probe(struct platform_device *pdev)
 {
-	struct altera_spi_platform_data *platp = pdev->dev.platform_data;
+	struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
 	struct altera_spi *hw;
 	struct spi_master *master;
 	struct resource *res;
@@ -231,7 +214,6 @@
 	master->bus_num = pdev->id;
 	master->num_chipselect = 16;
 	master->mode_bits = SPI_CS_HIGH;
-	master->setup = altera_spi_setup;
 
 	hw = spi_master_get_devdata(master);
 	platform_set_drvdata(pdev, hw);
@@ -240,21 +222,16 @@
 	hw->bitbang.master = spi_master_get(master);
 	if (!hw->bitbang.master)
 		return err;
-	hw->bitbang.setup_transfer = altera_spi_setupxfer;
 	hw->bitbang.chipselect = altera_spi_chipsel;
 	hw->bitbang.txrx_bufs = altera_spi_txrx;
 
 	/* find and map our resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto exit_busy;
-	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-				     pdev->name))
-		goto exit_busy;
-	hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
-					resource_size(res));
-	if (!hw->base)
-		goto exit_busy;
+	hw->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hw->base)) {
+		err = PTR_ERR(hw->base);
+		goto exit;
+	}
 	/* program defaults into the registers */
 	hw->imr = 0;		/* disable spi interrupts */
 	writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
@@ -281,9 +258,6 @@
 	dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
 
 	return 0;
-
-exit_busy:
-	err = -EBUSY;
 exit:
 	spi_master_put(master);
 	return err;
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index 0e06407..37bad95 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -221,7 +221,7 @@
 	sp = spi_master_get_devdata(master);
 	platform_set_drvdata(pdev, sp);
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
 	master->setup = ath79_spi_setup;
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index ea1ec00..fd7cc56 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -360,12 +360,12 @@
 		gpio_set_value(asd->npcs_pin, !active);
 }
 
-static void atmel_spi_lock(struct atmel_spi *as)
+static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
 {
 	spin_lock_irqsave(&as->lock, as->flags);
 }
 
-static void atmel_spi_unlock(struct atmel_spi *as)
+static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock)
 {
 	spin_unlock_irqrestore(&as->lock, as->flags);
 }
@@ -629,9 +629,9 @@
 		goto err_dma;
 
 	dev_dbg(master->dev.parent,
-		"  start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n",
-		xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-		xfer->rx_buf, xfer->rx_dma);
+		"  start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
+		xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma,
+		xfer->rx_buf, (unsigned long long)xfer->rx_dma);
 
 	/* Enable relevant interrupts */
 	spi_writel(as, IER, SPI_BIT(OVRES));
@@ -732,9 +732,10 @@
 		spi_writel(as, TCR, len);
 
 		dev_dbg(&msg->spi->dev,
-			"  start xfer %p: len %u tx %p/%08x rx %p/%08x\n",
-			xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-			xfer->rx_buf, xfer->rx_dma);
+			"  start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
+			xfer, xfer->len, xfer->tx_buf,
+			(unsigned long long)xfer->tx_dma, xfer->rx_buf,
+			(unsigned long long)xfer->rx_dma);
 	} else {
 		xfer = as->next_transfer;
 		remaining = as->next_remaining_bytes;
@@ -771,9 +772,10 @@
 		spi_writel(as, TNCR, len);
 
 		dev_dbg(&msg->spi->dev,
-			"  next xfer %p: len %u tx %p/%08x rx %p/%08x\n",
-			xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
-			xfer->rx_buf, xfer->rx_dma);
+			"  next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
+			xfer, xfer->len, xfer->tx_buf,
+			(unsigned long long)xfer->tx_dma, xfer->rx_buf,
+			(unsigned long long)xfer->rx_dma);
 		ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES);
 	} else {
 		spi_writel(as, RNCR, 0);
@@ -1579,7 +1581,9 @@
 		goto out_unmap_regs;
 
 	/* Initialize the hardware */
-	clk_enable(clk);
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		goto out_unmap_regs;
 	spi_writel(as, CR, SPI_BIT(SWRST));
 	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
 	if (as->caps.has_wdrbt) {
@@ -1609,7 +1613,7 @@
 
 	spi_writel(as, CR, SPI_BIT(SWRST));
 	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
-	clk_disable(clk);
+	clk_disable_unprepare(clk);
 	free_irq(irq, master);
 out_unmap_regs:
 	iounmap(as->regs);
@@ -1661,7 +1665,7 @@
 	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
 			as->buffer_dma);
 
-	clk_disable(as->clk);
+	clk_disable_unprepare(as->clk);
 	clk_put(as->clk);
 	free_irq(as->irq, master);
 	iounmap(as->regs);
@@ -1678,7 +1682,7 @@
 	struct spi_master	*master = platform_get_drvdata(pdev);
 	struct atmel_spi	*as = spi_master_get_devdata(master);
 
-	clk_disable(as->clk);
+	clk_disable_unprepare(as->clk);
 	return 0;
 }
 
@@ -1687,7 +1691,7 @@
 	struct spi_master	*master = platform_get_drvdata(pdev);
 	struct atmel_spi	*as = spi_master_get_devdata(master);
 
-	clk_enable(as->clk);
+	return clk_prepare_enable(as->clk);
 	return 0;
 }
 
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index e196555..1d00d9b3 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -776,7 +776,7 @@
 	hw = spi_master_get_devdata(master);
 
 	hw->master = spi_master_get(master);
-	hw->pdata = pdev->dev.platform_data;
+	hw->pdata = dev_get_platdata(&pdev->dev);
 	hw->dev = &pdev->dev;
 
 	if (hw->pdata == NULL) {
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index a4185e4..52c8148 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -314,7 +314,7 @@
 	platform_set_drvdata(pdev, master);
 
 	master->mode_bits = BCM2835_SPI_MODE_BITS;
-	master->bits_per_word_mask = BIT(8 - 1);
+	master->bits_per_word_mask = SPI_BPW_MASK(8);
 	master->bus_num = -1;
 	master->num_chipselect = 3;
 	master->transfer_one_message = bcm2835_spi_transfer_one;
@@ -325,12 +325,6 @@
 	init_completion(&bs->done);
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "could not get memory resource\n");
-		err = -ENODEV;
-		goto out_master_put;
-	}
-
 	bs->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(bs->regs)) {
 		err = PTR_ERR(bs->regs);
@@ -383,7 +377,7 @@
 
 static int bcm2835_spi_remove(struct platform_device *pdev)
 {
-	struct spi_master *master = platform_get_drvdata(pdev);
+	struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
 	struct bcm2835_spi *bs = spi_master_get_devdata(master);
 
 	free_irq(bs->irq, master);
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 9fd7a39..536b0e3 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -231,24 +231,6 @@
 	return 0;
 }
 
-static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
-{
-	struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-
-	pm_runtime_get_sync(&bs->pdev->dev);
-
-	return 0;
-}
-
-static int bcm63xx_spi_unprepare_transfer(struct spi_master *master)
-{
-	struct bcm63xx_spi *bs = spi_master_get_devdata(master);
-
-	pm_runtime_put(&bs->pdev->dev);
-
-	return 0;
-}
-
 static int bcm63xx_spi_transfer_one(struct spi_master *master,
 					struct spi_message *m)
 {
@@ -353,20 +335,13 @@
 {
 	struct resource *r;
 	struct device *dev = &pdev->dev;
-	struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data;
+	struct bcm63xx_spi_pdata *pdata = dev_get_platdata(&pdev->dev);
 	int irq;
 	struct spi_master *master;
 	struct clk *clk;
 	struct bcm63xx_spi *bs;
 	int ret;
 
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		dev_err(dev, "no iomem\n");
-		ret = -ENXIO;
-		goto out;
-	}
-
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
 		dev_err(dev, "no irq\n");
@@ -393,6 +368,7 @@
 	platform_set_drvdata(pdev, master);
 	bs->pdev = pdev;
 
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	bs->regs = devm_ioremap_resource(&pdev->dev, r);
 	if (IS_ERR(bs->regs)) {
 		ret = PTR_ERR(bs->regs);
@@ -412,11 +388,10 @@
 
 	master->bus_num = pdata->bus_num;
 	master->num_chipselect = pdata->num_chipselect;
-	master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
-	master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
 	master->transfer_one_message = bcm63xx_spi_transfer_one;
 	master->mode_bits = MODEBITS;
 	master->bits_per_word_mask = SPI_BPW_MASK(8);
+	master->auto_runtime_pm = true;
 	bs->msg_type_shift = pdata->msg_type_shift;
 	bs->msg_ctl_width = pdata->msg_ctl_width;
 	bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
@@ -480,8 +455,7 @@
 #ifdef CONFIG_PM
 static int bcm63xx_spi_suspend(struct device *dev)
 {
-	struct spi_master *master =
-			platform_get_drvdata(to_platform_device(dev));
+	struct spi_master *master = dev_get_drvdata(dev);
 	struct bcm63xx_spi *bs = spi_master_get_devdata(master);
 
 	spi_master_suspend(master);
@@ -493,8 +467,7 @@
 
 static int bcm63xx_spi_resume(struct device *dev)
 {
-	struct spi_master *master =
-			platform_get_drvdata(to_platform_device(dev));
+	struct spi_master *master = dev_get_drvdata(dev);
 	struct bcm63xx_spi *bs = spi_master_get_devdata(master);
 
 	clk_prepare_enable(bs->clk);
diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c
index 07ec597..91921b5 100644
--- a/drivers/spi/spi-bfin-sport.c
+++ b/drivers/spi/spi-bfin-sport.c
@@ -756,7 +756,7 @@
 	struct bfin_sport_spi_master_data *drv_data;
 	int status;
 
-	platform_info = dev->platform_data;
+	platform_info = dev_get_platdata(dev);
 
 	/* Allocate master with space for drv_data */
 	master = spi_alloc_master(dev, sizeof(*master) + 16);
diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c
new file mode 100644
index 0000000..f4bf813
--- /dev/null
+++ b/drivers/spi/spi-bfin-v3.c
@@ -0,0 +1,965 @@
+/*
+ * Analog Devices SPI3 controller driver
+ *
+ * Copyright (c) 2013 Analog Devices 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.
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+#include <asm/bfin_spi3.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+enum bfin_spi_state {
+	START_STATE,
+	RUNNING_STATE,
+	DONE_STATE,
+	ERROR_STATE
+};
+
+struct bfin_spi_master;
+
+struct bfin_spi_transfer_ops {
+	void (*write) (struct bfin_spi_master *);
+	void (*read) (struct bfin_spi_master *);
+	void (*duplex) (struct bfin_spi_master *);
+};
+
+/* runtime info for spi master */
+struct bfin_spi_master {
+	/* SPI framework hookup */
+	struct spi_master *master;
+
+	/* Regs base of SPI controller */
+	struct bfin_spi_regs __iomem *regs;
+
+	/* Pin request list */
+	u16 *pin_req;
+
+	/* Message Transfer pump */
+	struct tasklet_struct pump_transfers;
+
+	/* Current message transfer state info */
+	struct spi_message *cur_msg;
+	struct spi_transfer *cur_transfer;
+	struct bfin_spi_device *cur_chip;
+	unsigned transfer_len;
+
+	/* transfer buffer */
+	void *tx;
+	void *tx_end;
+	void *rx;
+	void *rx_end;
+
+	/* dma info */
+	unsigned int tx_dma;
+	unsigned int rx_dma;
+	dma_addr_t tx_dma_addr;
+	dma_addr_t rx_dma_addr;
+	unsigned long dummy_buffer; /* used in unidirectional transfer */
+	unsigned long tx_dma_size;
+	unsigned long rx_dma_size;
+	int tx_num;
+	int rx_num;
+
+	/* store register value for suspend/resume */
+	u32 control;
+	u32 ssel;
+
+	unsigned long sclk;
+	enum bfin_spi_state state;
+
+	const struct bfin_spi_transfer_ops *ops;
+};
+
+struct bfin_spi_device {
+	u32 control;
+	u32 clock;
+	u32 ssel;
+
+	u8 cs;
+	u16 cs_chg_udelay; /* Some devices require > 255usec delay */
+	u32 cs_gpio;
+	u32 tx_dummy_val; /* tx value for rx only transfer */
+	bool enable_dma;
+	const struct bfin_spi_transfer_ops *ops;
+};
+
+static void bfin_spi_enable(struct bfin_spi_master *drv_data)
+{
+	bfin_write_or(&drv_data->regs->control, SPI_CTL_EN);
+}
+
+static void bfin_spi_disable(struct bfin_spi_master *drv_data)
+{
+	bfin_write_and(&drv_data->regs->control, ~SPI_CTL_EN);
+}
+
+/* Caculate the SPI_CLOCK register value based on input HZ */
+static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz)
+{
+	u32 spi_clock = sclk / speed_hz;
+
+	if (spi_clock)
+		spi_clock--;
+	return spi_clock;
+}
+
+static int bfin_spi_flush(struct bfin_spi_master *drv_data)
+{
+	unsigned long limit = loops_per_jiffy << 1;
+
+	/* wait for stop and clear stat */
+	while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit)
+		cpu_relax();
+
+	bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+
+	return limit;
+}
+
+/* Chip select operation functions for cs_change flag */
+static void bfin_spi_cs_active(struct bfin_spi_master *drv_data, struct bfin_spi_device *chip)
+{
+	if (likely(chip->cs < MAX_CTRL_CS))
+		bfin_write_and(&drv_data->regs->ssel, ~chip->ssel);
+	else
+		gpio_set_value(chip->cs_gpio, 0);
+}
+
+static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data,
+				struct bfin_spi_device *chip)
+{
+	if (likely(chip->cs < MAX_CTRL_CS))
+		bfin_write_or(&drv_data->regs->ssel, chip->ssel);
+	else
+		gpio_set_value(chip->cs_gpio, 1);
+
+	/* Move delay here for consistency */
+	if (chip->cs_chg_udelay)
+		udelay(chip->cs_chg_udelay);
+}
+
+/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
+static inline void bfin_spi_cs_enable(struct bfin_spi_master *drv_data,
+					struct bfin_spi_device *chip)
+{
+	if (chip->cs < MAX_CTRL_CS)
+		bfin_write_or(&drv_data->regs->ssel, chip->ssel >> 8);
+}
+
+static inline void bfin_spi_cs_disable(struct bfin_spi_master *drv_data,
+					struct bfin_spi_device *chip)
+{
+	if (chip->cs < MAX_CTRL_CS)
+		bfin_write_and(&drv_data->regs->ssel, ~(chip->ssel >> 8));
+}
+
+/* stop controller and re-config current chip*/
+static void bfin_spi_restore_state(struct bfin_spi_master *drv_data)
+{
+	struct bfin_spi_device *chip = drv_data->cur_chip;
+
+	/* Clear status and disable clock */
+	bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+	bfin_write(&drv_data->regs->rx_control, 0x0);
+	bfin_write(&drv_data->regs->tx_control, 0x0);
+	bfin_spi_disable(drv_data);
+
+	SSYNC();
+
+	/* Load the registers */
+	bfin_write(&drv_data->regs->control, chip->control);
+	bfin_write(&drv_data->regs->clock, chip->clock);
+
+	bfin_spi_enable(drv_data);
+	drv_data->tx_num = drv_data->rx_num = 0;
+	/* we always choose tx transfer initiate */
+	bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN);
+	bfin_write(&drv_data->regs->tx_control,
+			SPI_TXCTL_TEN | SPI_TXCTL_TTI);
+	bfin_spi_cs_active(drv_data, chip);
+}
+
+/* discard invalid rx data and empty rfifo */
+static inline void dummy_read(struct bfin_spi_master *drv_data)
+{
+	while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_RFE))
+		bfin_read(&drv_data->regs->rfifo);
+}
+
+static void bfin_spi_u8_write(struct bfin_spi_master *drv_data)
+{
+	dummy_read(drv_data);
+	while (drv_data->tx < drv_data->tx_end) {
+		bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++)));
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		bfin_read(&drv_data->regs->rfifo);
+	}
+}
+
+static void bfin_spi_u8_read(struct bfin_spi_master *drv_data)
+{
+	u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+	dummy_read(drv_data);
+	while (drv_data->rx < drv_data->rx_end) {
+		bfin_write(&drv_data->regs->tfifo, tx_val);
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		*(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo);
+	}
+}
+
+static void bfin_spi_u8_duplex(struct bfin_spi_master *drv_data)
+{
+	dummy_read(drv_data);
+	while (drv_data->rx < drv_data->rx_end) {
+		bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++)));
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		*(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo);
+	}
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = {
+	.write  = bfin_spi_u8_write,
+	.read   = bfin_spi_u8_read,
+	.duplex = bfin_spi_u8_duplex,
+};
+
+static void bfin_spi_u16_write(struct bfin_spi_master *drv_data)
+{
+	dummy_read(drv_data);
+	while (drv_data->tx < drv_data->tx_end) {
+		bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx));
+		drv_data->tx += 2;
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		bfin_read(&drv_data->regs->rfifo);
+	}
+}
+
+static void bfin_spi_u16_read(struct bfin_spi_master *drv_data)
+{
+	u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+	dummy_read(drv_data);
+	while (drv_data->rx < drv_data->rx_end) {
+		bfin_write(&drv_data->regs->tfifo, tx_val);
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		*(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+		drv_data->rx += 2;
+	}
+}
+
+static void bfin_spi_u16_duplex(struct bfin_spi_master *drv_data)
+{
+	dummy_read(drv_data);
+	while (drv_data->rx < drv_data->rx_end) {
+		bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx));
+		drv_data->tx += 2;
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		*(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+		drv_data->rx += 2;
+	}
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = {
+	.write  = bfin_spi_u16_write,
+	.read   = bfin_spi_u16_read,
+	.duplex = bfin_spi_u16_duplex,
+};
+
+static void bfin_spi_u32_write(struct bfin_spi_master *drv_data)
+{
+	dummy_read(drv_data);
+	while (drv_data->tx < drv_data->tx_end) {
+		bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx));
+		drv_data->tx += 4;
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		bfin_read(&drv_data->regs->rfifo);
+	}
+}
+
+static void bfin_spi_u32_read(struct bfin_spi_master *drv_data)
+{
+	u32 tx_val = drv_data->cur_chip->tx_dummy_val;
+
+	dummy_read(drv_data);
+	while (drv_data->rx < drv_data->rx_end) {
+		bfin_write(&drv_data->regs->tfifo, tx_val);
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		*(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+		drv_data->rx += 4;
+	}
+}
+
+static void bfin_spi_u32_duplex(struct bfin_spi_master *drv_data)
+{
+	dummy_read(drv_data);
+	while (drv_data->rx < drv_data->rx_end) {
+		bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx));
+		drv_data->tx += 4;
+		while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)
+			cpu_relax();
+		*(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo);
+		drv_data->rx += 4;
+	}
+}
+
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u32 = {
+	.write  = bfin_spi_u32_write,
+	.read   = bfin_spi_u32_read,
+	.duplex = bfin_spi_u32_duplex,
+};
+
+
+/* test if there is more transfer to be done */
+static void bfin_spi_next_transfer(struct bfin_spi_master *drv)
+{
+	struct spi_message *msg = drv->cur_msg;
+	struct spi_transfer *t = drv->cur_transfer;
+
+	/* Move to next transfer */
+	if (t->transfer_list.next != &msg->transfers) {
+		drv->cur_transfer = list_entry(t->transfer_list.next,
+			       struct spi_transfer, transfer_list);
+		drv->state = RUNNING_STATE;
+	} else {
+		drv->state = DONE_STATE;
+		drv->cur_transfer = NULL;
+	}
+}
+
+static void bfin_spi_giveback(struct bfin_spi_master *drv_data)
+{
+	struct bfin_spi_device *chip = drv_data->cur_chip;
+
+	bfin_spi_cs_deactive(drv_data, chip);
+	spi_finalize_current_message(drv_data->master);
+}
+
+static int bfin_spi_setup_transfer(struct bfin_spi_master *drv)
+{
+	struct spi_transfer *t = drv->cur_transfer;
+	u32 cr, cr_width;
+
+	if (t->tx_buf) {
+		drv->tx = (void *)t->tx_buf;
+		drv->tx_end = drv->tx + t->len;
+	} else {
+		drv->tx = NULL;
+	}
+
+	if (t->rx_buf) {
+		drv->rx = t->rx_buf;
+		drv->rx_end = drv->rx + t->len;
+	} else {
+		drv->rx = NULL;
+	}
+
+	drv->transfer_len = t->len;
+
+	/* bits per word setup */
+	switch (t->bits_per_word) {
+	case 8:
+		cr_width = SPI_CTL_SIZE08;
+		drv->ops = &bfin_bfin_spi_transfer_ops_u8;
+		break;
+	case 16:
+		cr_width = SPI_CTL_SIZE16;
+		drv->ops = &bfin_bfin_spi_transfer_ops_u16;
+		break;
+	case 32:
+		cr_width = SPI_CTL_SIZE32;
+		drv->ops = &bfin_bfin_spi_transfer_ops_u32;
+		break;
+	default:
+		return -EINVAL;
+	}
+	cr = bfin_read(&drv->regs->control) & ~SPI_CTL_SIZE;
+	cr |= cr_width;
+	bfin_write(&drv->regs->control, cr);
+
+	/* speed setup */
+	bfin_write(&drv->regs->clock,
+			hz_to_spi_clock(drv->sclk, t->speed_hz));
+	return 0;
+}
+
+static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data)
+{
+	struct spi_transfer *t = drv_data->cur_transfer;
+	struct spi_message *msg = drv_data->cur_msg;
+	struct bfin_spi_device *chip = drv_data->cur_chip;
+	u32 dma_config;
+	unsigned long word_count, word_size;
+	void *tx_buf, *rx_buf;
+
+	switch (t->bits_per_word) {
+	case 8:
+		dma_config = WDSIZE_8 | PSIZE_8;
+		word_count = drv_data->transfer_len;
+		word_size = 1;
+		break;
+	case 16:
+		dma_config = WDSIZE_16 | PSIZE_16;
+		word_count = drv_data->transfer_len / 2;
+		word_size = 2;
+		break;
+	default:
+		dma_config = WDSIZE_32 | PSIZE_32;
+		word_count = drv_data->transfer_len / 4;
+		word_size = 4;
+		break;
+	}
+
+	if (!drv_data->rx) {
+		tx_buf = drv_data->tx;
+		rx_buf = &drv_data->dummy_buffer;
+		drv_data->tx_dma_size = drv_data->transfer_len;
+		drv_data->rx_dma_size = sizeof(drv_data->dummy_buffer);
+		set_dma_x_modify(drv_data->tx_dma, word_size);
+		set_dma_x_modify(drv_data->rx_dma, 0);
+	} else if (!drv_data->tx) {
+		drv_data->dummy_buffer = chip->tx_dummy_val;
+		tx_buf = &drv_data->dummy_buffer;
+		rx_buf = drv_data->rx;
+		drv_data->tx_dma_size = sizeof(drv_data->dummy_buffer);
+		drv_data->rx_dma_size = drv_data->transfer_len;
+		set_dma_x_modify(drv_data->tx_dma, 0);
+		set_dma_x_modify(drv_data->rx_dma, word_size);
+	} else {
+		tx_buf = drv_data->tx;
+		rx_buf = drv_data->rx;
+		drv_data->tx_dma_size = drv_data->rx_dma_size
+					= drv_data->transfer_len;
+		set_dma_x_modify(drv_data->tx_dma, word_size);
+		set_dma_x_modify(drv_data->rx_dma, word_size);
+	}
+
+	drv_data->tx_dma_addr = dma_map_single(&msg->spi->dev,
+				(void *)tx_buf,
+				drv_data->tx_dma_size,
+				DMA_TO_DEVICE);
+	if (dma_mapping_error(&msg->spi->dev,
+				drv_data->tx_dma_addr))
+		return -ENOMEM;
+
+	drv_data->rx_dma_addr = dma_map_single(&msg->spi->dev,
+				(void *)rx_buf,
+				drv_data->rx_dma_size,
+				DMA_FROM_DEVICE);
+	if (dma_mapping_error(&msg->spi->dev,
+				drv_data->rx_dma_addr)) {
+		dma_unmap_single(&msg->spi->dev,
+				drv_data->tx_dma_addr,
+				drv_data->tx_dma_size,
+				DMA_TO_DEVICE);
+		return -ENOMEM;
+	}
+
+	dummy_read(drv_data);
+	set_dma_x_count(drv_data->tx_dma, word_count);
+	set_dma_x_count(drv_data->rx_dma, word_count);
+	set_dma_start_addr(drv_data->tx_dma, drv_data->tx_dma_addr);
+	set_dma_start_addr(drv_data->rx_dma, drv_data->rx_dma_addr);
+	dma_config |= DMAFLOW_STOP | RESTART | DI_EN;
+	set_dma_config(drv_data->tx_dma, dma_config);
+	set_dma_config(drv_data->rx_dma, dma_config | WNR);
+	enable_dma(drv_data->tx_dma);
+	enable_dma(drv_data->rx_dma);
+	SSYNC();
+
+	bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN | SPI_RXCTL_RDR_NE);
+	SSYNC();
+	bfin_write(&drv_data->regs->tx_control,
+			SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF);
+
+	return 0;
+}
+
+static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data)
+{
+	struct spi_message *msg = drv_data->cur_msg;
+
+	if (!drv_data->rx) {
+		/* write only half duplex */
+		drv_data->ops->write(drv_data);
+		if (drv_data->tx != drv_data->tx_end)
+			return -EIO;
+	} else if (!drv_data->tx) {
+		/* read only half duplex */
+		drv_data->ops->read(drv_data);
+		if (drv_data->rx != drv_data->rx_end)
+			return -EIO;
+	} else {
+		/* full duplex mode */
+		drv_data->ops->duplex(drv_data);
+		if (drv_data->tx != drv_data->tx_end)
+			return -EIO;
+	}
+
+	if (!bfin_spi_flush(drv_data))
+		return -EIO;
+	msg->actual_length += drv_data->transfer_len;
+	tasklet_schedule(&drv_data->pump_transfers);
+	return 0;
+}
+
+static void bfin_spi_pump_transfers(unsigned long data)
+{
+	struct bfin_spi_master *drv_data = (struct bfin_spi_master *)data;
+	struct spi_message *msg = NULL;
+	struct spi_transfer *t = NULL;
+	struct bfin_spi_device *chip = NULL;
+	int ret;
+
+	/* Get current state information */
+	msg = drv_data->cur_msg;
+	t = drv_data->cur_transfer;
+	chip = drv_data->cur_chip;
+
+	/* Handle for abort */
+	if (drv_data->state == ERROR_STATE) {
+		msg->status = -EIO;
+		bfin_spi_giveback(drv_data);
+		return;
+	}
+
+	if (drv_data->state == RUNNING_STATE) {
+		if (t->delay_usecs)
+			udelay(t->delay_usecs);
+		if (t->cs_change)
+			bfin_spi_cs_deactive(drv_data, chip);
+		bfin_spi_next_transfer(drv_data);
+		t = drv_data->cur_transfer;
+	}
+	/* Handle end of message */
+	if (drv_data->state == DONE_STATE) {
+		msg->status = 0;
+		bfin_spi_giveback(drv_data);
+		return;
+	}
+
+	if ((t->len == 0) || (t->tx_buf == NULL && t->rx_buf == NULL)) {
+		/* Schedule next transfer tasklet */
+		tasklet_schedule(&drv_data->pump_transfers);
+		return;
+	}
+
+	ret = bfin_spi_setup_transfer(drv_data);
+	if (ret) {
+		msg->status = ret;
+		bfin_spi_giveback(drv_data);
+	}
+
+	bfin_write(&drv_data->regs->status, 0xFFFFFFFF);
+	bfin_spi_cs_active(drv_data, chip);
+	drv_data->state = RUNNING_STATE;
+
+	if (chip->enable_dma)
+		ret = bfin_spi_dma_xfer(drv_data);
+	else
+		ret = bfin_spi_pio_xfer(drv_data);
+	if (ret) {
+		msg->status = ret;
+		bfin_spi_giveback(drv_data);
+	}
+}
+
+static int bfin_spi_transfer_one_message(struct spi_master *master,
+					struct spi_message *m)
+{
+	struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+	drv_data->cur_msg = m;
+	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+	bfin_spi_restore_state(drv_data);
+
+	drv_data->state = START_STATE;
+	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+					    struct spi_transfer, transfer_list);
+
+	tasklet_schedule(&drv_data->pump_transfers);
+	return 0;
+}
+
+#define MAX_SPI_SSEL	7
+
+static const u16 ssel[][MAX_SPI_SSEL] = {
+	{P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
+	P_SPI0_SSEL4, P_SPI0_SSEL5,
+	P_SPI0_SSEL6, P_SPI0_SSEL7},
+
+	{P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3,
+	P_SPI1_SSEL4, P_SPI1_SSEL5,
+	P_SPI1_SSEL6, P_SPI1_SSEL7},
+
+	{P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3,
+	P_SPI2_SSEL4, P_SPI2_SSEL5,
+	P_SPI2_SSEL6, P_SPI2_SSEL7},
+};
+
+static int bfin_spi_setup(struct spi_device *spi)
+{
+	struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master);
+	struct bfin_spi_device *chip = spi_get_ctldata(spi);
+	u32 bfin_ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE;
+	int ret = -EINVAL;
+
+	if (!chip) {
+		struct bfin_spi3_chip *chip_info = spi->controller_data;
+
+		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+		if (!chip) {
+			dev_err(&spi->dev, "can not allocate chip data\n");
+			return -ENOMEM;
+		}
+		if (chip_info) {
+			if (chip_info->control & ~bfin_ctl_reg) {
+				dev_err(&spi->dev,
+					"do not set bits that the SPI framework manages\n");
+				goto error;
+			}
+			chip->control = chip_info->control;
+			chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+			chip->tx_dummy_val = chip_info->tx_dummy_val;
+			chip->enable_dma = chip_info->enable_dma;
+		}
+		chip->cs = spi->chip_select;
+		if (chip->cs < MAX_CTRL_CS) {
+			chip->ssel = (1 << chip->cs) << 8;
+			ret = peripheral_request(ssel[spi->master->bus_num]
+					[chip->cs-1], dev_name(&spi->dev));
+			if (ret) {
+				dev_err(&spi->dev, "peripheral_request() error\n");
+				goto error;
+			}
+		} else {
+			chip->cs_gpio = chip->cs - MAX_CTRL_CS;
+			ret = gpio_request_one(chip->cs_gpio, GPIOF_OUT_INIT_HIGH,
+						dev_name(&spi->dev));
+			if (ret) {
+				dev_err(&spi->dev, "gpio_request_one() error\n");
+				goto error;
+			}
+		}
+		spi_set_ctldata(spi, chip);
+	}
+
+	/* force a default base state */
+	chip->control &= bfin_ctl_reg;
+
+	if (spi->mode & SPI_CPOL)
+		chip->control |= SPI_CTL_CPOL;
+	if (spi->mode & SPI_CPHA)
+		chip->control |= SPI_CTL_CPHA;
+	if (spi->mode & SPI_LSB_FIRST)
+		chip->control |= SPI_CTL_LSBF;
+	chip->control |= SPI_CTL_MSTR;
+	/* we choose software to controll cs */
+	chip->control &= ~SPI_CTL_ASSEL;
+
+	chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz);
+
+	bfin_spi_cs_enable(drv_data, chip);
+	bfin_spi_cs_deactive(drv_data, chip);
+
+	return 0;
+error:
+	if (chip) {
+		kfree(chip);
+		spi_set_ctldata(spi, NULL);
+	}
+
+	return ret;
+}
+
+static void bfin_spi_cleanup(struct spi_device *spi)
+{
+	struct bfin_spi_device *chip = spi_get_ctldata(spi);
+	struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master);
+
+	if (!chip)
+		return;
+
+	if (chip->cs < MAX_CTRL_CS) {
+		peripheral_free(ssel[spi->master->bus_num]
+					[chip->cs-1]);
+		bfin_spi_cs_disable(drv_data, chip);
+	} else {
+		gpio_free(chip->cs_gpio);
+	}
+
+	kfree(chip);
+	spi_set_ctldata(spi, NULL);
+}
+
+static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id)
+{
+	struct bfin_spi_master *drv_data = dev_id;
+	u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma);
+
+	clear_dma_irqstat(drv_data->tx_dma);
+	if (dma_stat & DMA_DONE) {
+		drv_data->tx_num++;
+	} else {
+		dev_err(&drv_data->master->dev,
+				"spi tx dma error: %d\n", dma_stat);
+		if (drv_data->tx)
+			drv_data->state = ERROR_STATE;
+	}
+	bfin_write_and(&drv_data->regs->tx_control, ~SPI_TXCTL_TDR_NF);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id)
+{
+	struct bfin_spi_master *drv_data = dev_id;
+	struct spi_message *msg = drv_data->cur_msg;
+	u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma);
+
+	clear_dma_irqstat(drv_data->rx_dma);
+	if (dma_stat & DMA_DONE) {
+		drv_data->rx_num++;
+		/* we may fail on tx dma */
+		if (drv_data->state != ERROR_STATE)
+			msg->actual_length += drv_data->transfer_len;
+	} else {
+		drv_data->state = ERROR_STATE;
+		dev_err(&drv_data->master->dev,
+				"spi rx dma error: %d\n", dma_stat);
+	}
+	bfin_write(&drv_data->regs->tx_control, 0);
+	bfin_write(&drv_data->regs->rx_control, 0);
+	if (drv_data->rx_num != drv_data->tx_num)
+		dev_dbg(&drv_data->master->dev,
+				"dma interrupt missing: tx=%d,rx=%d\n",
+				drv_data->tx_num, drv_data->rx_num);
+	tasklet_schedule(&drv_data->pump_transfers);
+	return IRQ_HANDLED;
+}
+
+static int bfin_spi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bfin_spi3_master *info = dev_get_platdata(dev);
+	struct spi_master *master;
+	struct bfin_spi_master *drv_data;
+	struct resource *mem, *res;
+	unsigned int tx_dma, rx_dma;
+	unsigned long sclk;
+	int ret;
+
+	if (!info) {
+		dev_err(dev, "platform data missing!\n");
+		return -ENODEV;
+	}
+
+	sclk = get_sclk1();
+	if (!sclk) {
+		dev_err(dev, "can not get sclk1\n");
+		return -ENXIO;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		dev_err(dev, "can not get tx dma resource\n");
+		return -ENXIO;
+	}
+	tx_dma = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res) {
+		dev_err(dev, "can not get rx dma resource\n");
+		return -ENXIO;
+	}
+	rx_dma = res->start;
+
+	/* allocate master with space for drv_data */
+	master = spi_alloc_master(dev, sizeof(*drv_data));
+	if (!master) {
+		dev_err(dev, "can not alloc spi_master\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, master);
+
+	/* the mode bits supported by this driver */
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+
+	master->bus_num = pdev->id;
+	master->num_chipselect = info->num_chipselect;
+	master->cleanup = bfin_spi_cleanup;
+	master->setup = bfin_spi_setup;
+	master->transfer_one_message = bfin_spi_transfer_one_message;
+	master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+
+	drv_data = spi_master_get_devdata(master);
+	drv_data->master = master;
+	drv_data->tx_dma = tx_dma;
+	drv_data->rx_dma = rx_dma;
+	drv_data->pin_req = info->pin_req;
+	drv_data->sclk = sclk;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv_data->regs = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(drv_data->regs)) {
+		ret = PTR_ERR(drv_data->regs);
+		goto err_put_master;
+	}
+
+	/* request tx and rx dma */
+	ret = request_dma(tx_dma, "SPI_TX_DMA");
+	if (ret) {
+		dev_err(dev, "can not request SPI TX DMA channel\n");
+		goto err_put_master;
+	}
+	set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data);
+
+	ret = request_dma(rx_dma, "SPI_RX_DMA");
+	if (ret) {
+		dev_err(dev, "can not request SPI RX DMA channel\n");
+		goto err_free_tx_dma;
+	}
+	set_dma_callback(drv_data->rx_dma, bfin_spi_rx_dma_isr, drv_data);
+
+	/* request CLK, MOSI and MISO */
+	ret = peripheral_request_list(drv_data->pin_req, "bfin-spi3");
+	if (ret < 0) {
+		dev_err(dev, "can not request spi pins\n");
+		goto err_free_rx_dma;
+	}
+
+	bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA);
+	bfin_write(&drv_data->regs->ssel, 0x0000FE00);
+	bfin_write(&drv_data->regs->delay, 0x0);
+
+	tasklet_init(&drv_data->pump_transfers,
+			bfin_spi_pump_transfers, (unsigned long)drv_data);
+	/* register with the SPI framework */
+	ret = spi_register_master(master);
+	if (ret) {
+		dev_err(dev, "can not  register spi master\n");
+		goto err_free_peripheral;
+	}
+
+	return ret;
+
+err_free_peripheral:
+	peripheral_free_list(drv_data->pin_req);
+err_free_rx_dma:
+	free_dma(rx_dma);
+err_free_tx_dma:
+	free_dma(tx_dma);
+err_put_master:
+	spi_master_put(master);
+
+	return ret;
+}
+
+static int bfin_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+	bfin_spi_disable(drv_data);
+
+	peripheral_free_list(drv_data->pin_req);
+	free_dma(drv_data->rx_dma);
+	free_dma(drv_data->tx_dma);
+
+	spi_unregister_master(drv_data->master);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_spi_suspend(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+
+	spi_master_suspend(master);
+
+	drv_data->control = bfin_read(&drv_data->regs->control);
+	drv_data->ssel = bfin_read(&drv_data->regs->ssel);
+
+	bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA);
+	bfin_write(&drv_data->regs->ssel, 0x0000FE00);
+	dma_disable_irq(drv_data->rx_dma);
+	dma_disable_irq(drv_data->tx_dma);
+
+	return 0;
+}
+
+static int bfin_spi_resume(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct bfin_spi_master *drv_data = spi_master_get_devdata(master);
+	int ret = 0;
+
+	/* bootrom may modify spi and dma status when resume in spi boot mode */
+	disable_dma(drv_data->rx_dma);
+
+	dma_enable_irq(drv_data->rx_dma);
+	dma_enable_irq(drv_data->tx_dma);
+	bfin_write(&drv_data->regs->control, drv_data->control);
+	bfin_write(&drv_data->regs->ssel, drv_data->ssel);
+
+	ret = spi_master_resume(master);
+	if (ret) {
+		free_dma(drv_data->rx_dma);
+		free_dma(drv_data->tx_dma);
+	}
+
+	return ret;
+}
+#endif
+static const struct dev_pm_ops bfin_spi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(bfin_spi_suspend, bfin_spi_resume)
+};
+
+MODULE_ALIAS("platform:bfin-spi3");
+static struct platform_driver bfin_spi_driver = {
+	.driver	= {
+		.name	= "bfin-spi3",
+		.owner	= THIS_MODULE,
+		.pm     = &bfin_spi_pm_ops,
+	},
+	.remove		= bfin_spi_remove,
+};
+
+module_platform_driver_probe(bfin_spi_driver, bfin_spi_probe);
+
+MODULE_DESCRIPTION("Analog Devices SPI3 controller driver");
+MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c
index 59a7342..45bdf73 100644
--- a/drivers/spi/spi-bfin5xx.c
+++ b/drivers/spi/spi-bfin5xx.c
@@ -1271,7 +1271,7 @@
 	struct resource *res;
 	int status = 0;
 
-	platform_info = dev->platform_data;
+	platform_info = dev_get_platdata(dev);
 
 	/* Allocate master with space for drv_data */
 	master = spi_alloc_master(dev, sizeof(*drv_data));
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index a63d7da..e3946e4 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -255,150 +255,140 @@
  * Drivers can provide word-at-a-time i/o primitives, or provide
  * transfer-at-a-time ones to leverage dma or fifo hardware.
  */
-static void bitbang_work(struct work_struct *work)
+
+static int spi_bitbang_prepare_hardware(struct spi_master *spi)
 {
-	struct spi_bitbang	*bitbang =
-		container_of(work, struct spi_bitbang, work);
+	struct spi_bitbang 	*bitbang;
 	unsigned long		flags;
-	struct spi_message	*m, *_m;
+
+	bitbang = spi_master_get_devdata(spi);
 
 	spin_lock_irqsave(&bitbang->lock, flags);
 	bitbang->busy = 1;
-	list_for_each_entry_safe(m, _m, &bitbang->queue, queue) {
-		struct spi_device	*spi;
-		unsigned		nsecs;
-		struct spi_transfer	*t = NULL;
-		unsigned		tmp;
-		unsigned		cs_change;
-		int			status;
-		int			do_setup = -1;
+	spin_unlock_irqrestore(&bitbang->lock, flags);
 
-		list_del(&m->queue);
-		spin_unlock_irqrestore(&bitbang->lock, flags);
+	return 0;
+}
 
-		/* FIXME this is made-up ... the correct value is known to
-		 * word-at-a-time bitbang code, and presumably chipselect()
-		 * should enforce these requirements too?
-		 */
-		nsecs = 100;
+static int spi_bitbang_transfer_one(struct spi_master *master,
+				    struct spi_message *m)
+{
+	struct spi_bitbang 	*bitbang;
+	unsigned		nsecs;
+	struct spi_transfer	*t = NULL;
+	unsigned		cs_change;
+	int			status;
+	int			do_setup = -1;
+	struct spi_device	*spi = m->spi;
 
-		spi = m->spi;
-		tmp = 0;
-		cs_change = 1;
-		status = 0;
+	bitbang = spi_master_get_devdata(master);
 
-		list_for_each_entry (t, &m->transfers, transfer_list) {
+	/* FIXME this is made-up ... the correct value is known to
+	 * word-at-a-time bitbang code, and presumably chipselect()
+	 * should enforce these requirements too?
+	 */
+	nsecs = 100;
 
-			/* override speed or wordsize? */
-			if (t->speed_hz || t->bits_per_word)
-				do_setup = 1;
+	cs_change = 1;
+	status = 0;
 
-			/* init (-1) or override (1) transfer params */
-			if (do_setup != 0) {
-				status = bitbang->setup_transfer(spi, t);
-				if (status < 0)
-					break;
-				if (do_setup == -1)
-					do_setup = 0;
-			}
+	list_for_each_entry (t, &m->transfers, transfer_list) {
 
-			/* set up default clock polarity, and activate chip;
-			 * this implicitly updates clock and spi modes as
-			 * previously recorded for this device via setup().
-			 * (and also deselects any other chip that might be
-			 * selected ...)
-			 */
-			if (cs_change) {
-				bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
-				ndelay(nsecs);
-			}
-			cs_change = t->cs_change;
-			if (!t->tx_buf && !t->rx_buf && t->len) {
-				status = -EINVAL;
+		/* override speed or wordsize? */
+		if (t->speed_hz || t->bits_per_word)
+			do_setup = 1;
+
+		/* init (-1) or override (1) transfer params */
+		if (do_setup != 0) {
+			status = bitbang->setup_transfer(spi, t);
+			if (status < 0)
 				break;
-			}
-
-			/* transfer data.  the lower level code handles any
-			 * new dma mappings it needs. our caller always gave
-			 * us dma-safe buffers.
-			 */
-			if (t->len) {
-				/* REVISIT dma API still needs a designated
-				 * DMA_ADDR_INVALID; ~0 might be better.
-				 */
-				if (!m->is_dma_mapped)
-					t->rx_dma = t->tx_dma = 0;
-				status = bitbang->txrx_bufs(spi, t);
-			}
-			if (status > 0)
-				m->actual_length += status;
-			if (status != t->len) {
-				/* always report some kind of error */
-				if (status >= 0)
-					status = -EREMOTEIO;
-				break;
-			}
-			status = 0;
-
-			/* protocol tweaks before next transfer */
-			if (t->delay_usecs)
-				udelay(t->delay_usecs);
-
-			if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
-				/* sometimes a short mid-message deselect of the chip
-				 * may be needed to terminate a mode or command
-				 */
-				ndelay(nsecs);
-				bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-				ndelay(nsecs);
-			}
+			if (do_setup == -1)
+				do_setup = 0;
 		}
 
-		m->status = status;
-		m->complete(m->context);
-
-		/* normally deactivate chipselect ... unless no error and
-		 * cs_change has hinted that the next message will probably
-		 * be for this chip too.
+		/* set up default clock polarity, and activate chip;
+		 * this implicitly updates clock and spi modes as
+		 * previously recorded for this device via setup().
+		 * (and also deselects any other chip that might be
+		 * selected ...)
 		 */
-		if (!(status == 0 && cs_change)) {
+		if (cs_change) {
+			bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+			ndelay(nsecs);
+		}
+		cs_change = t->cs_change;
+		if (!t->tx_buf && !t->rx_buf && t->len) {
+			status = -EINVAL;
+			break;
+		}
+
+		/* transfer data.  the lower level code handles any
+		 * new dma mappings it needs. our caller always gave
+		 * us dma-safe buffers.
+		 */
+		if (t->len) {
+			/* REVISIT dma API still needs a designated
+			 * DMA_ADDR_INVALID; ~0 might be better.
+			 */
+			if (!m->is_dma_mapped)
+				t->rx_dma = t->tx_dma = 0;
+			status = bitbang->txrx_bufs(spi, t);
+		}
+		if (status > 0)
+			m->actual_length += status;
+		if (status != t->len) {
+			/* always report some kind of error */
+			if (status >= 0)
+				status = -EREMOTEIO;
+			break;
+		}
+		status = 0;
+
+		/* protocol tweaks before next transfer */
+		if (t->delay_usecs)
+			udelay(t->delay_usecs);
+
+		if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
+			/* sometimes a short mid-message deselect of the chip
+			 * may be needed to terminate a mode or command
+			 */
 			ndelay(nsecs);
 			bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
 			ndelay(nsecs);
 		}
-
-		spin_lock_irqsave(&bitbang->lock, flags);
 	}
-	bitbang->busy = 0;
-	spin_unlock_irqrestore(&bitbang->lock, flags);
-}
 
-/**
- * spi_bitbang_transfer - default submit to transfer queue
- */
-int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
-{
-	struct spi_bitbang	*bitbang;
-	unsigned long		flags;
-	int			status = 0;
+	m->status = status;
 
-	m->actual_length = 0;
-	m->status = -EINPROGRESS;
-
-	bitbang = spi_master_get_devdata(spi->master);
-
-	spin_lock_irqsave(&bitbang->lock, flags);
-	if (!spi->max_speed_hz)
-		status = -ENETDOWN;
-	else {
-		list_add_tail(&m->queue, &bitbang->queue);
-		queue_work(bitbang->workqueue, &bitbang->work);
+	/* normally deactivate chipselect ... unless no error and
+	 * cs_change has hinted that the next message will probably
+	 * be for this chip too.
+	 */
+	if (!(status == 0 && cs_change)) {
+		ndelay(nsecs);
+		bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+		ndelay(nsecs);
 	}
-	spin_unlock_irqrestore(&bitbang->lock, flags);
+
+	spi_finalize_current_message(master);
 
 	return status;
 }
-EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
+
+static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
+{
+	struct spi_bitbang 	*bitbang;
+	unsigned long		flags;
+
+	bitbang = spi_master_get_devdata(spi);
+
+	spin_lock_irqsave(&bitbang->lock, flags);
+	bitbang->busy = 0;
+	spin_unlock_irqrestore(&bitbang->lock, flags);
+
+	return 0;
+}
 
 /*----------------------------------------------------------------------*/
 
@@ -428,20 +418,22 @@
 int spi_bitbang_start(struct spi_bitbang *bitbang)
 {
 	struct spi_master *master = bitbang->master;
-	int status;
 
 	if (!master || !bitbang->chipselect)
 		return -EINVAL;
 
-	INIT_WORK(&bitbang->work, bitbang_work);
 	spin_lock_init(&bitbang->lock);
-	INIT_LIST_HEAD(&bitbang->queue);
 
 	if (!master->mode_bits)
 		master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
 
-	if (!master->transfer)
-		master->transfer = spi_bitbang_transfer;
+	if (master->transfer || master->transfer_one_message)
+		return -EINVAL;
+
+	master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
+	master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
+	master->transfer_one_message = spi_bitbang_transfer_one;
+
 	if (!bitbang->txrx_bufs) {
 		bitbang->use_dma = 0;
 		bitbang->txrx_bufs = spi_bitbang_bufs;
@@ -452,34 +444,12 @@
 			master->setup = spi_bitbang_setup;
 			master->cleanup = spi_bitbang_cleanup;
 		}
-	} else if (!master->setup)
-		return -EINVAL;
-	if (master->transfer == spi_bitbang_transfer &&
-			!bitbang->setup_transfer)
-		return -EINVAL;
-
-	/* this task is the only thing to touch the SPI bits */
-	bitbang->busy = 0;
-	bitbang->workqueue = create_singlethread_workqueue(
-			dev_name(master->dev.parent));
-	if (bitbang->workqueue == NULL) {
-		status = -EBUSY;
-		goto err1;
 	}
 
 	/* driver may get busy before register() returns, especially
 	 * if someone registered boardinfo for devices
 	 */
-	status = spi_register_master(master);
-	if (status < 0)
-		goto err2;
-
-	return status;
-
-err2:
-	destroy_workqueue(bitbang->workqueue);
-err1:
-	return status;
+	return spi_register_master(master);
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_start);
 
@@ -490,10 +460,6 @@
 {
 	spi_unregister_master(bitbang->master);
 
-	WARN_ON(!list_empty(&bitbang->queue));
-
-	destroy_workqueue(bitbang->workqueue);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(spi_bitbang_stop);
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index 17965fe..5655acf 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -239,11 +239,8 @@
 	}
 
 	dev_err(&pdev->dev, "Failed to register master\n");
-	devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
 
 clk_out:
-	devm_clk_put(&pdev->dev, hw->spi_clk);
-
 err_out:
 	while (--i >= 0)
 		if (gpio_is_valid(hw->chipselect[i]))
@@ -261,13 +258,10 @@
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct spi_clps711x_data *hw = spi_master_get_devdata(master);
 
-	devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
-
 	for (i = 0; i < master->num_chipselect; i++)
 		if (gpio_is_valid(hw->chipselect[i]))
 			gpio_free(hw->chipselect[i]);
 
-	devm_clk_put(&pdev->dev, hw->spi_clk);
 	spi_unregister_master(master);
 	kfree(master);
 
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 0631b9d..cc5b75d 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -354,24 +354,6 @@
 
 }
 
-static int mcfqspi_prepare_transfer_hw(struct spi_master *master)
-{
-	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-
-	pm_runtime_get_sync(mcfqspi->dev);
-
-	return 0;
-}
-
-static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
-{
-	struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
-
-	pm_runtime_put_sync(mcfqspi->dev);
-
-	return 0;
-}
-
 static int mcfqspi_setup(struct spi_device *spi)
 {
 	if (spi->chip_select >= spi->master->num_chipselect) {
@@ -400,7 +382,7 @@
 	struct mcfqspi_platform_data *pdata;
 	int status;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata) {
 		dev_dbg(&pdev->dev, "platform data is missing\n");
 		return -ENOENT;
@@ -473,8 +455,7 @@
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
 	master->setup = mcfqspi_setup;
 	master->transfer_one_message = mcfqspi_transfer_one_message;
-	master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
-	master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw;
+	master->auto_runtime_pm = true;
 
 	platform_set_drvdata(pdev, master);
 
@@ -558,7 +539,7 @@
 #ifdef CONFIG_PM_RUNTIME
 static int mcfqspi_runtime_suspend(struct device *dev)
 {
-	struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+	struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
 
 	clk_disable(mcfqspi->clk);
 
@@ -567,7 +548,7 @@
 
 static int mcfqspi_runtime_resume(struct device *dev)
 {
-	struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+	struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
 
 	clk_enable(mcfqspi->clk);
 
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 707966b..8fbfe24 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -872,8 +872,8 @@
 		goto free_master;
 	}
 
-	if (pdev->dev.platform_data) {
-		pdata = pdev->dev.platform_data;
+	if (dev_get_platdata(&pdev->dev)) {
+		pdata = dev_get_platdata(&pdev->dev);
 		dspi->pdata = *pdata;
 	} else {
 		/* update dspi pdata with that from the DT */
diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c
new file mode 100644
index 0000000..7d84418
--- /dev/null
+++ b/drivers/spi/spi-efm32.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix
+ *
+ * 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/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_data/efm32-spi.h>
+
+#define DRIVER_NAME "efm32-spi"
+
+#define MASK_VAL(mask, val)		((val << __ffs(mask)) & mask)
+
+#define REG_CTRL		0x00
+#define REG_CTRL_SYNC			0x0001
+#define REG_CTRL_CLKPOL			0x0100
+#define REG_CTRL_CLKPHA			0x0200
+#define REG_CTRL_MSBF			0x0400
+#define REG_CTRL_TXBIL			0x1000
+
+#define REG_FRAME		0x04
+#define REG_FRAME_DATABITS__MASK	0x000f
+#define REG_FRAME_DATABITS(n)		((n) - 3)
+
+#define REG_CMD			0x0c
+#define REG_CMD_RXEN			0x0001
+#define REG_CMD_RXDIS			0x0002
+#define REG_CMD_TXEN			0x0004
+#define REG_CMD_TXDIS			0x0008
+#define REG_CMD_MASTEREN		0x0010
+
+#define REG_STATUS		0x10
+#define REG_STATUS_TXENS		0x0002
+#define REG_STATUS_TXC			0x0020
+#define REG_STATUS_TXBL			0x0040
+#define REG_STATUS_RXDATAV		0x0080
+
+#define REG_CLKDIV		0x14
+
+#define REG_RXDATAX		0x18
+#define REG_RXDATAX_RXDATA__MASK	0x01ff
+#define REG_RXDATAX_PERR		0x4000
+#define REG_RXDATAX_FERR		0x8000
+
+#define REG_TXDATA		0x34
+
+#define REG_IF		0x40
+#define REG_IF_TXBL			0x0002
+#define REG_IF_RXDATAV			0x0004
+
+#define REG_IFS		0x44
+#define REG_IFC		0x48
+#define REG_IEN		0x4c
+
+#define REG_ROUTE		0x54
+#define REG_ROUTE_RXPEN			0x0001
+#define REG_ROUTE_TXPEN			0x0002
+#define REG_ROUTE_CLKPEN		0x0008
+#define REG_ROUTE_LOCATION__MASK	0x0700
+#define REG_ROUTE_LOCATION(n)		MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
+
+struct efm32_spi_ddata {
+	struct spi_bitbang bitbang;
+
+	spinlock_t lock;
+
+	struct clk *clk;
+	void __iomem *base;
+	unsigned int rxirq, txirq;
+	struct efm32_spi_pdata pdata;
+
+	/* irq data */
+	struct completion done;
+	const u8 *tx_buf;
+	u8 *rx_buf;
+	unsigned tx_len, rx_len;
+
+	/* chip selects */
+	unsigned csgpio[];
+};
+
+#define ddata_to_dev(ddata)	(&(ddata->bitbang.master->dev))
+#define efm32_spi_vdbg(ddata, format, arg...)	\
+	dev_vdbg(ddata_to_dev(ddata), format, ##arg)
+
+static void efm32_spi_write32(struct efm32_spi_ddata *ddata,
+		u32 value, unsigned offset)
+{
+	writel_relaxed(value, ddata->base + offset);
+}
+
+static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset)
+{
+	return readl_relaxed(ddata->base + offset);
+}
+
+static void efm32_spi_chipselect(struct spi_device *spi, int is_on)
+{
+	struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
+	int value = !(spi->mode & SPI_CS_HIGH) == !(is_on == BITBANG_CS_ACTIVE);
+
+	gpio_set_value(ddata->csgpio[spi->chip_select], value);
+}
+
+static int efm32_spi_setup_transfer(struct spi_device *spi,
+		struct spi_transfer *t)
+{
+	struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
+
+	unsigned bpw = t->bits_per_word ?: spi->bits_per_word;
+	unsigned speed = t->speed_hz ?: spi->max_speed_hz;
+	unsigned long clkfreq = clk_get_rate(ddata->clk);
+	u32 clkdiv;
+
+	efm32_spi_write32(ddata, REG_CTRL_SYNC | REG_CTRL_MSBF |
+			(spi->mode & SPI_CPHA ? REG_CTRL_CLKPHA : 0) |
+			(spi->mode & SPI_CPOL ? REG_CTRL_CLKPOL : 0), REG_CTRL);
+
+	efm32_spi_write32(ddata,
+			REG_FRAME_DATABITS(bpw), REG_FRAME);
+
+	if (2 * speed >= clkfreq)
+		clkdiv = 0;
+	else
+		clkdiv = 64 * (DIV_ROUND_UP(2 * clkfreq, speed) - 4);
+
+	if (clkdiv > (1U << 21))
+		return -EINVAL;
+
+	efm32_spi_write32(ddata, clkdiv, REG_CLKDIV);
+	efm32_spi_write32(ddata, REG_CMD_MASTEREN, REG_CMD);
+	efm32_spi_write32(ddata, REG_CMD_RXEN | REG_CMD_TXEN, REG_CMD);
+
+	return 0;
+}
+
+static void efm32_spi_tx_u8(struct efm32_spi_ddata *ddata)
+{
+	u8 val = 0;
+
+	if (ddata->tx_buf) {
+		val = *ddata->tx_buf;
+		ddata->tx_buf++;
+	}
+
+	ddata->tx_len--;
+	efm32_spi_write32(ddata, val, REG_TXDATA);
+	efm32_spi_vdbg(ddata, "%s: tx 0x%x\n", __func__, val);
+}
+
+static void efm32_spi_rx_u8(struct efm32_spi_ddata *ddata)
+{
+	u32 rxdata = efm32_spi_read32(ddata, REG_RXDATAX);
+	efm32_spi_vdbg(ddata, "%s: rx 0x%x\n", __func__, rxdata);
+
+	if (ddata->rx_buf) {
+		*ddata->rx_buf = rxdata;
+		ddata->rx_buf++;
+	}
+
+	ddata->rx_len--;
+}
+
+static void efm32_spi_filltx(struct efm32_spi_ddata *ddata)
+{
+	while (ddata->tx_len &&
+			ddata->tx_len + 2 > ddata->rx_len &&
+			efm32_spi_read32(ddata, REG_STATUS) & REG_STATUS_TXBL) {
+		efm32_spi_tx_u8(ddata);
+	}
+}
+
+static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
+	int ret = -EBUSY;
+
+	spin_lock_irq(&ddata->lock);
+
+	if (ddata->tx_buf || ddata->rx_buf)
+		goto out_unlock;
+
+	ddata->tx_buf = t->tx_buf;
+	ddata->rx_buf = t->rx_buf;
+	ddata->tx_len = ddata->rx_len =
+		t->len * DIV_ROUND_UP(t->bits_per_word, 8);
+
+	efm32_spi_filltx(ddata);
+
+	init_completion(&ddata->done);
+
+	efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
+
+	spin_unlock_irq(&ddata->lock);
+
+	wait_for_completion(&ddata->done);
+
+	spin_lock_irq(&ddata->lock);
+
+	ret = t->len - max(ddata->tx_len, ddata->rx_len);
+
+	efm32_spi_write32(ddata, 0, REG_IEN);
+	ddata->tx_buf = ddata->rx_buf = NULL;
+
+out_unlock:
+	spin_unlock_irq(&ddata->lock);
+
+	return ret;
+}
+
+static irqreturn_t efm32_spi_rxirq(int irq, void *data)
+{
+	struct efm32_spi_ddata *ddata = data;
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock(&ddata->lock);
+
+	while (ddata->rx_len > 0 &&
+			efm32_spi_read32(ddata, REG_STATUS) &
+			REG_STATUS_RXDATAV) {
+		efm32_spi_rx_u8(ddata);
+
+		ret = IRQ_HANDLED;
+	}
+
+	if (!ddata->rx_len) {
+		u32 ien = efm32_spi_read32(ddata, REG_IEN);
+
+		ien &= ~REG_IF_RXDATAV;
+
+		efm32_spi_write32(ddata, ien, REG_IEN);
+
+		complete(&ddata->done);
+	}
+
+	spin_unlock(&ddata->lock);
+
+	return ret;
+}
+
+static irqreturn_t efm32_spi_txirq(int irq, void *data)
+{
+	struct efm32_spi_ddata *ddata = data;
+
+	efm32_spi_vdbg(ddata,
+			"%s: txlen = %u, rxlen = %u, if=0x%08x, stat=0x%08x\n",
+			__func__, ddata->tx_len, ddata->rx_len,
+			efm32_spi_read32(ddata, REG_IF),
+			efm32_spi_read32(ddata, REG_STATUS));
+
+	spin_lock(&ddata->lock);
+
+	efm32_spi_filltx(ddata);
+
+	efm32_spi_vdbg(ddata, "%s: txlen = %u, rxlen = %u\n",
+			__func__, ddata->tx_len, ddata->rx_len);
+
+	if (!ddata->tx_len) {
+		u32 ien = efm32_spi_read32(ddata, REG_IEN);
+
+		ien &= ~REG_IF_TXBL;
+
+		efm32_spi_write32(ddata, ien, REG_IEN);
+		efm32_spi_vdbg(ddata, "disable TXBL\n");
+	}
+
+	spin_unlock(&ddata->lock);
+
+	return IRQ_HANDLED;
+}
+
+static const struct efm32_spi_pdata efm32_spi_pdata_default = {
+	.location = 1,
+};
+
+static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
+{
+	u32 reg = efm32_spi_read32(ddata, REG_ROUTE);
+
+	return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
+}
+
+static int efm32_spi_probe_dt(struct platform_device *pdev,
+		struct spi_master *master, struct efm32_spi_ddata *ddata)
+{
+	struct device_node *np = pdev->dev.of_node;
+	u32 location;
+	int ret;
+
+	if (!np)
+		return 1;
+
+	ret = of_property_read_u32(np, "location", &location);
+	if (!ret) {
+		dev_dbg(&pdev->dev, "using location %u\n", location);
+	} else {
+		/* default to location configured in hardware */
+		location = efm32_spi_get_configured_location(ddata);
+
+		dev_info(&pdev->dev, "fall back to location %u\n", location);
+	}
+
+	ddata->pdata.location = location;
+
+	/* spi core takes care about the bus number using an alias */
+	master->bus_num = -1;
+
+	return 0;
+}
+
+static int efm32_spi_probe(struct platform_device *pdev)
+{
+	struct efm32_spi_ddata *ddata;
+	struct resource *res;
+	int ret;
+	struct spi_master *master;
+	struct device_node *np = pdev->dev.of_node;
+	unsigned int num_cs, i;
+
+	num_cs = of_gpio_named_count(np, "cs-gpios");
+
+	master = spi_alloc_master(&pdev->dev,
+			sizeof(*ddata) + num_cs * sizeof(unsigned));
+	if (!master) {
+		dev_dbg(&pdev->dev,
+				"failed to allocate spi master controller\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, master);
+
+	master->dev.of_node = pdev->dev.of_node;
+
+	master->num_chipselect = num_cs;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+
+	ddata = spi_master_get_devdata(master);
+
+	ddata->bitbang.master = spi_master_get(master);
+	ddata->bitbang.chipselect = efm32_spi_chipselect;
+	ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
+	ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
+
+	spin_lock_init(&ddata->lock);
+
+	ddata->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(ddata->clk)) {
+		ret = PTR_ERR(ddata->clk);
+		dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+		goto err;
+	}
+
+	for (i = 0; i < num_cs; ++i) {
+		ret = of_get_named_gpio(np, "cs-gpios", i);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n",
+					i, ret);
+			goto err;
+		}
+		ddata->csgpio[i] = ret;
+		dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, ddata->csgpio[i]);
+		ret = devm_gpio_request_one(&pdev->dev, ddata->csgpio[i],
+				GPIOF_OUT_INIT_LOW, DRIVER_NAME);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+					"failed to configure csgpio#%u (%d)\n",
+					i, ret);
+			goto err;
+		}
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		dev_err(&pdev->dev, "failed to determine base address\n");
+		goto err;
+	}
+
+	if (resource_size(res) < 60) {
+		ret = -EINVAL;
+		dev_err(&pdev->dev, "memory resource too small\n");
+		goto err;
+	}
+
+	ddata->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ddata->base)) {
+		ret = PTR_ERR(ddata->base);
+		goto err;
+	}
+
+	ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "failed to get rx irq (%d)\n", ret);
+		goto err;
+	}
+
+	ddata->rxirq = ret;
+
+	ret = platform_get_irq(pdev, 1);
+	if (ret <= 0)
+		ret = ddata->rxirq + 1;
+
+	ddata->txirq = ret;
+
+	ret = clk_prepare_enable(ddata->clk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
+		goto err;
+	}
+
+	ret = efm32_spi_probe_dt(pdev, master, ddata);
+	if (ret > 0) {
+		/* not created by device tree */
+		const struct efm32_spi_pdata *pdata =
+			dev_get_platdata(&pdev->dev);
+
+		if (pdata)
+			ddata->pdata = *pdata;
+		else
+			ddata->pdata.location =
+				efm32_spi_get_configured_location(ddata);
+
+		master->bus_num = pdev->id;
+
+	} else if (ret < 0) {
+		goto err_disable_clk;
+	}
+
+	efm32_spi_write32(ddata, 0, REG_IEN);
+	efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
+			REG_ROUTE_CLKPEN |
+			REG_ROUTE_LOCATION(ddata->pdata.location), REG_ROUTE);
+
+	ret = request_irq(ddata->rxirq, efm32_spi_rxirq,
+			0, DRIVER_NAME " rx", ddata);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register rxirq (%d)\n", ret);
+		goto err_disable_clk;
+	}
+
+	ret = request_irq(ddata->txirq, efm32_spi_txirq,
+			0, DRIVER_NAME " tx", ddata);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register txirq (%d)\n", ret);
+		goto err_free_rx_irq;
+	}
+
+	ret = spi_bitbang_start(&ddata->bitbang);
+	if (ret) {
+		dev_err(&pdev->dev, "spi_bitbang_start failed (%d)\n", ret);
+
+		free_irq(ddata->txirq, ddata);
+err_free_rx_irq:
+		free_irq(ddata->rxirq, ddata);
+err_disable_clk:
+		clk_disable_unprepare(ddata->clk);
+err:
+		spi_master_put(master);
+		kfree(master);
+	}
+
+	return ret;
+}
+
+static int efm32_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct efm32_spi_ddata *ddata = spi_master_get_devdata(master);
+
+	efm32_spi_write32(ddata, 0, REG_IEN);
+
+	free_irq(ddata->txirq, ddata);
+	free_irq(ddata->rxirq, ddata);
+	clk_disable_unprepare(ddata->clk);
+	spi_master_put(master);
+	kfree(master);
+
+	return 0;
+}
+
+static const struct of_device_id efm32_spi_dt_ids[] = {
+	{
+		.compatible = "efm32,spi",
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, efm32_spi_dt_ids);
+
+static struct platform_driver efm32_spi_driver = {
+	.probe = efm32_spi_probe,
+	.remove = efm32_spi_remove,
+
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = efm32_spi_dt_ids,
+	},
+};
+module_platform_driver(efm32_spi_driver);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 SPI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index cad30b8..d22c00a 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/scatterlist.h>
 #include <linux/spi/spi.h>
@@ -70,19 +69,13 @@
 
 /**
  * struct ep93xx_spi - EP93xx SPI controller structure
- * @lock: spinlock that protects concurrent accesses to fields @running,
- *        @current_msg and @msg_queue
  * @pdev: pointer to platform device
  * @clk: clock for the controller
  * @regs_base: pointer to ioremap()'d registers
  * @sspdr_phys: physical address of the SSPDR register
  * @min_rate: minimum clock rate (in Hz) supported by the controller
  * @max_rate: maximum clock rate (in Hz) supported by the controller
- * @running: is the queue running
- * @wq: workqueue used by the driver
- * @msg_work: work that is queued for the driver
  * @wait: wait here until given transfer is completed
- * @msg_queue: queue for the messages
  * @current_msg: message that is currently processed (or %NULL if none)
  * @tx: current byte in transfer to transmit
  * @rx: current byte in transfer to receive
@@ -96,30 +89,15 @@
  * @tx_sgt: sg table for TX transfers
  * @zeropage: dummy page used as RX buffer when only TX buffer is passed in by
  *            the client
- *
- * This structure holds EP93xx SPI controller specific information. When
- * @running is %true, driver accepts transfer requests from protocol drivers.
- * @current_msg is used to hold pointer to the message that is currently
- * processed. If @current_msg is %NULL, it means that no processing is going
- * on.
- *
- * Most of the fields are only written once and they can be accessed without
- * taking the @lock. Fields that are accessed concurrently are: @current_msg,
- * @running, and @msg_queue.
  */
 struct ep93xx_spi {
-	spinlock_t			lock;
 	const struct platform_device	*pdev;
 	struct clk			*clk;
 	void __iomem			*regs_base;
 	unsigned long			sspdr_phys;
 	unsigned long			min_rate;
 	unsigned long			max_rate;
-	bool				running;
-	struct workqueue_struct		*wq;
-	struct work_struct		msg_work;
 	struct completion		wait;
-	struct list_head		msg_queue;
 	struct spi_message		*current_msg;
 	size_t				tx;
 	size_t				rx;
@@ -136,50 +114,36 @@
 /**
  * struct ep93xx_spi_chip - SPI device hardware settings
  * @spi: back pointer to the SPI device
- * @rate: max rate in hz this chip supports
- * @div_cpsr: cpsr (pre-scaler) divider
- * @div_scr: scr divider
- * @dss: bits per word (4 - 16 bits)
  * @ops: private chip operations
- *
- * This structure is used to store hardware register specific settings for each
- * SPI device. Settings are written to hardware by function
- * ep93xx_spi_chip_setup().
  */
 struct ep93xx_spi_chip {
 	const struct spi_device		*spi;
-	unsigned long			rate;
-	u8				div_cpsr;
-	u8				div_scr;
-	u8				dss;
 	struct ep93xx_spi_chip_ops	*ops;
 };
 
 /* converts bits per word to CR0.DSS value */
 #define bits_per_word_to_dss(bpw)	((bpw) - 1)
 
-static inline void
-ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi,
+				u16 reg, u8 value)
 {
-	__raw_writeb(value, espi->regs_base + reg);
+	writeb(value, espi->regs_base + reg);
 }
 
-static inline u8
-ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
 {
-	return __raw_readb(spi->regs_base + reg);
+	return readb(spi->regs_base + reg);
 }
 
-static inline void
-ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi,
+				 u16 reg, u16 value)
 {
-	__raw_writew(value, espi->regs_base + reg);
+	writew(value, espi->regs_base + reg);
 }
 
-static inline u16
-ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
 {
-	return __raw_readw(spi->regs_base + reg);
+	return readw(spi->regs_base + reg);
 }
 
 static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
@@ -230,17 +194,13 @@
 /**
  * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
  * @espi: ep93xx SPI controller struct
- * @chip: divisors are calculated for this chip
  * @rate: desired SPI output clock rate
- *
- * Function calculates cpsr (clock pre-scaler) and scr divisors based on
- * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
- * for some reason, divisors cannot be calculated nothing is stored and
- * %-EINVAL is returned.
+ * @div_cpsr: pointer to return the cpsr (pre-scaler) divider
+ * @div_scr: pointer to return the scr divider
  */
 static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
-				    struct ep93xx_spi_chip *chip,
-				    unsigned long rate)
+				    unsigned long rate,
+				    u8 *div_cpsr, u8 *div_scr)
 {
 	unsigned long spi_clk_rate = clk_get_rate(espi->clk);
 	int cpsr, scr;
@@ -248,7 +208,7 @@
 	/*
 	 * Make sure that max value is between values supported by the
 	 * controller. Note that minimum value is already checked in
-	 * ep93xx_spi_transfer().
+	 * ep93xx_spi_transfer_one_message().
 	 */
 	rate = clamp(rate, espi->min_rate, espi->max_rate);
 
@@ -263,8 +223,8 @@
 	for (cpsr = 2; cpsr <= 254; cpsr += 2) {
 		for (scr = 0; scr <= 255; scr++) {
 			if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
-				chip->div_scr = (u8)scr;
-				chip->div_cpsr = (u8)cpsr;
+				*div_scr = (u8)scr;
+				*div_cpsr = (u8)cpsr;
 				return 0;
 			}
 		}
@@ -319,73 +279,11 @@
 		spi_set_ctldata(spi, chip);
 	}
 
-	if (spi->max_speed_hz != chip->rate) {
-		int err;
-
-		err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
-		if (err != 0) {
-			spi_set_ctldata(spi, NULL);
-			kfree(chip);
-			return err;
-		}
-		chip->rate = spi->max_speed_hz;
-	}
-
-	chip->dss = bits_per_word_to_dss(spi->bits_per_word);
-
 	ep93xx_spi_cs_control(spi, false);
 	return 0;
 }
 
 /**
- * ep93xx_spi_transfer() - queue message to be transferred
- * @spi: target SPI device
- * @msg: message to be transferred
- *
- * This function is called by SPI device drivers when they are going to transfer
- * a new message. It simply puts the message in the queue and schedules
- * workqueue to perform the actual transfer later on.
- *
- * Returns %0 on success and negative error in case of failure.
- */
-static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
-{
-	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
-	struct spi_transfer *t;
-	unsigned long flags;
-
-	if (!msg || !msg->complete)
-		return -EINVAL;
-
-	/* first validate each transfer */
-	list_for_each_entry(t, &msg->transfers, transfer_list) {
-		if (t->speed_hz && t->speed_hz < espi->min_rate)
-				return -EINVAL;
-	}
-
-	/*
-	 * Now that we own the message, let's initialize it so that it is
-	 * suitable for us. We use @msg->status to signal whether there was
-	 * error in transfer and @msg->state is used to hold pointer to the
-	 * current transfer (or %NULL if no active current transfer).
-	 */
-	msg->state = NULL;
-	msg->status = 0;
-	msg->actual_length = 0;
-
-	spin_lock_irqsave(&espi->lock, flags);
-	if (!espi->running) {
-		spin_unlock_irqrestore(&espi->lock, flags);
-		return -ESHUTDOWN;
-	}
-	list_add_tail(&msg->queue, &espi->msg_queue);
-	queue_work(espi->wq, &espi->msg_work);
-	spin_unlock_irqrestore(&espi->lock, flags);
-
-	return 0;
-}
-
-/**
  * ep93xx_spi_cleanup() - cleans up master controller specific state
  * @spi: SPI device to cleanup
  *
@@ -409,39 +307,40 @@
  * ep93xx_spi_chip_setup() - configures hardware according to given @chip
  * @espi: ep93xx SPI controller struct
  * @chip: chip specific settings
- *
- * This function sets up the actual hardware registers with settings given in
- * @chip. Note that no validation is done so make sure that callers validate
- * settings before calling this.
+ * @speed_hz: transfer speed
+ * @bits_per_word: transfer bits_per_word
  */
-static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
-				  const struct ep93xx_spi_chip *chip)
+static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+				 const struct ep93xx_spi_chip *chip,
+				 u32 speed_hz, u8 bits_per_word)
 {
+	u8 dss = bits_per_word_to_dss(bits_per_word);
+	u8 div_cpsr = 0;
+	u8 div_scr = 0;
 	u16 cr0;
+	int err;
 
-	cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+	err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr);
+	if (err)
+		return err;
+
+	cr0 = div_scr << SSPCR0_SCR_SHIFT;
 	cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
-	cr0 |= chip->dss;
+	cr0 |= dss;
 
 	dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
-		chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+		chip->spi->mode, div_cpsr, div_scr, dss);
 	dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
 
-	ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+	ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr);
 	ep93xx_spi_write_u16(espi, SSPCR0, cr0);
-}
 
-static inline int bits_per_word(const struct ep93xx_spi *espi)
-{
-	struct spi_message *msg = espi->current_msg;
-	struct spi_transfer *t = msg->state;
-
-	return t->bits_per_word;
+	return 0;
 }
 
 static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
 {
-	if (bits_per_word(espi) > 8) {
+	if (t->bits_per_word > 8) {
 		u16 tx_val = 0;
 
 		if (t->tx_buf)
@@ -460,7 +359,7 @@
 
 static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
 {
-	if (bits_per_word(espi) > 8) {
+	if (t->bits_per_word > 8) {
 		u16 rx_val;
 
 		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
@@ -546,7 +445,7 @@
 	size_t len = t->len;
 	int i, ret, nents;
 
-	if (bits_per_word(espi) > 8)
+	if (t->bits_per_word > 8)
 		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
 	else
 		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
@@ -610,7 +509,7 @@
 	}
 
 	if (WARN_ON(len)) {
-		dev_warn(&espi->pdev->dev, "len = %d expected 0!", len);
+		dev_warn(&espi->pdev->dev, "len = %zu expected 0!", len);
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -708,37 +607,16 @@
 					struct spi_transfer *t)
 {
 	struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+	int err;
 
 	msg->state = t;
 
-	/*
-	 * Handle any transfer specific settings if needed. We use
-	 * temporary chip settings here and restore original later when
-	 * the transfer is finished.
-	 */
-	if (t->speed_hz || t->bits_per_word) {
-		struct ep93xx_spi_chip tmp_chip = *chip;
-
-		if (t->speed_hz) {
-			int err;
-
-			err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
-						       t->speed_hz);
-			if (err) {
-				dev_err(&espi->pdev->dev,
-					"failed to adjust speed\n");
-				msg->status = err;
-				return;
-			}
-		}
-
-		if (t->bits_per_word)
-			tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
-
-		/*
-		 * Set up temporary new hw settings for this transfer.
-		 */
-		ep93xx_spi_chip_setup(espi, &tmp_chip);
+	err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word);
+	if (err) {
+		dev_err(&espi->pdev->dev,
+			"failed to setup chip for transfer\n");
+		msg->status = err;
+		return;
 	}
 
 	espi->rx = 0;
@@ -783,9 +661,6 @@
 			ep93xx_spi_cs_control(msg->spi, true);
 		}
 	}
-
-	if (t->speed_hz || t->bits_per_word)
-		ep93xx_spi_chip_setup(espi, chip);
 }
 
 /*
@@ -838,10 +713,8 @@
 	espi->fifo_level = 0;
 
 	/*
-	 * Update SPI controller registers according to spi device and assert
-	 * the chipselect.
+	 * Assert the chipselect.
 	 */
-	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
 	ep93xx_spi_cs_control(msg->spi, true);
 
 	list_for_each_entry(t, &msg->transfers, transfer_list) {
@@ -858,50 +731,29 @@
 	ep93xx_spi_disable(espi);
 }
 
-#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
-
-/**
- * ep93xx_spi_work() - EP93xx SPI workqueue worker function
- * @work: work struct
- *
- * Workqueue worker function. This function is called when there are new
- * SPI messages to be processed. Message is taken out from the queue and then
- * passed to ep93xx_spi_process_message().
- *
- * After message is transferred, protocol driver is notified by calling
- * @msg->complete(). In case of error, @msg->status is set to negative error
- * number, otherwise it contains zero (and @msg->actual_length is updated).
- */
-static void ep93xx_spi_work(struct work_struct *work)
+static int ep93xx_spi_transfer_one_message(struct spi_master *master,
+					   struct spi_message *msg)
 {
-	struct ep93xx_spi *espi = work_to_espi(work);
-	struct spi_message *msg;
+	struct ep93xx_spi *espi = spi_master_get_devdata(master);
+	struct spi_transfer *t;
 
-	spin_lock_irq(&espi->lock);
-	if (!espi->running || espi->current_msg ||
-		list_empty(&espi->msg_queue)) {
-		spin_unlock_irq(&espi->lock);
-		return;
+	/* first validate each transfer */
+	list_for_each_entry(t, &msg->transfers, transfer_list) {
+		if (t->speed_hz < espi->min_rate)
+			return -EINVAL;
 	}
-	msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
-	list_del_init(&msg->queue);
+
+	msg->state = NULL;
+	msg->status = 0;
+	msg->actual_length = 0;
+
 	espi->current_msg = msg;
-	spin_unlock_irq(&espi->lock);
-
 	ep93xx_spi_process_message(espi, msg);
-
-	/*
-	 * Update the current message and re-schedule ourselves if there are
-	 * more messages in the queue.
-	 */
-	spin_lock_irq(&espi->lock);
 	espi->current_msg = NULL;
-	if (espi->running && !list_empty(&espi->msg_queue))
-		queue_work(espi->wq, &espi->msg_work);
-	spin_unlock_irq(&espi->lock);
 
-	/* notify the protocol driver that we are done with this message */
-	msg->complete(msg->context);
+	spi_finalize_current_message(master);
+
+	return 0;
 }
 
 static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
@@ -1022,16 +874,26 @@
 	int irq;
 	int error;
 
-	info = pdev->dev.platform_data;
+	info = dev_get_platdata(&pdev->dev);
 
-	master = spi_alloc_master(&pdev->dev, sizeof(*espi));
-	if (!master) {
-		dev_err(&pdev->dev, "failed to allocate spi master\n");
-		return -ENOMEM;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "failed to get irq resources\n");
+		return -EBUSY;
 	}
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "unable to get iomem resource\n");
+		return -ENODEV;
+	}
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*espi));
+	if (!master)
+		return -ENOMEM;
+
 	master->setup = ep93xx_spi_setup;
-	master->transfer = ep93xx_spi_transfer;
+	master->transfer_one_message = ep93xx_spi_transfer_one_message;
 	master->cleanup = ep93xx_spi_cleanup;
 	master->bus_num = pdev->id;
 	master->num_chipselect = info->num_chipselect;
@@ -1042,14 +904,13 @@
 
 	espi = spi_master_get_devdata(master);
 
-	espi->clk = clk_get(&pdev->dev, NULL);
+	espi->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(espi->clk)) {
 		dev_err(&pdev->dev, "unable to get spi clock\n");
 		error = PTR_ERR(espi->clk);
 		goto fail_release_master;
 	}
 
-	spin_lock_init(&espi->lock);
 	init_completion(&espi->wait);
 
 	/*
@@ -1060,55 +921,31 @@
 	espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
 	espi->pdev = pdev;
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		error = -EBUSY;
-		dev_err(&pdev->dev, "failed to get irq resources\n");
-		goto fail_put_clock;
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "unable to get iomem resource\n");
-		error = -ENODEV;
-		goto fail_put_clock;
-	}
-
 	espi->sspdr_phys = res->start + SSPDR;
 
 	espi->regs_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(espi->regs_base)) {
 		error = PTR_ERR(espi->regs_base);
-		goto fail_put_clock;
+		goto fail_release_master;
 	}
 
 	error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
 				0, "ep93xx-spi", espi);
 	if (error) {
 		dev_err(&pdev->dev, "failed to request irq\n");
-		goto fail_put_clock;
+		goto fail_release_master;
 	}
 
 	if (info->use_dma && ep93xx_spi_setup_dma(espi))
 		dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
 
-	espi->wq = create_singlethread_workqueue("ep93xx_spid");
-	if (!espi->wq) {
-		dev_err(&pdev->dev, "unable to create workqueue\n");
-		error = -ENOMEM;
-		goto fail_free_dma;
-	}
-	INIT_WORK(&espi->msg_work, ep93xx_spi_work);
-	INIT_LIST_HEAD(&espi->msg_queue);
-	espi->running = true;
-
 	/* make sure that the hardware is disabled */
 	ep93xx_spi_write_u8(espi, SSPCR1, 0);
 
 	error = spi_register_master(master);
 	if (error) {
 		dev_err(&pdev->dev, "failed to register SPI master\n");
-		goto fail_free_queue;
+		goto fail_free_dma;
 	}
 
 	dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
@@ -1116,12 +953,8 @@
 
 	return 0;
 
-fail_free_queue:
-	destroy_workqueue(espi->wq);
 fail_free_dma:
 	ep93xx_spi_release_dma(espi);
-fail_put_clock:
-	clk_put(espi->clk);
 fail_release_master:
 	spi_master_put(master);
 
@@ -1133,31 +966,7 @@
 	struct spi_master *master = platform_get_drvdata(pdev);
 	struct ep93xx_spi *espi = spi_master_get_devdata(master);
 
-	spin_lock_irq(&espi->lock);
-	espi->running = false;
-	spin_unlock_irq(&espi->lock);
-
-	destroy_workqueue(espi->wq);
-
-	/*
-	 * Complete remaining messages with %-ESHUTDOWN status.
-	 */
-	spin_lock_irq(&espi->lock);
-	while (!list_empty(&espi->msg_queue)) {
-		struct spi_message *msg;
-
-		msg = list_first_entry(&espi->msg_queue,
-				       struct spi_message, queue);
-		list_del_init(&msg->queue);
-		msg->status = -ESHUTDOWN;
-		spin_unlock_irq(&espi->lock);
-		msg->complete(msg->context);
-		spin_lock_irq(&espi->lock);
-	}
-	spin_unlock_irq(&espi->lock);
-
 	ep93xx_spi_release_dma(espi);
-	clk_put(espi->clk);
 
 	spi_unregister_master(master);
 	return 0;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
new file mode 100644
index 0000000..6cd07d1
--- /dev/null
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -0,0 +1,557 @@
+/*
+ * drivers/spi/spi-fsl-dspi.c
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Freescale DSPI driver
+ * This file contains a driver for the Freescale DSPI
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#define DRIVER_NAME "fsl-dspi"
+
+#define TRAN_STATE_RX_VOID		0x01
+#define TRAN_STATE_TX_VOID		0x02
+#define TRAN_STATE_WORD_ODD_NUM	0x04
+
+#define DSPI_FIFO_SIZE			4
+
+#define SPI_MCR		0x00
+#define SPI_MCR_MASTER		(1 << 31)
+#define SPI_MCR_PCSIS		(0x3F << 16)
+#define SPI_MCR_CLR_TXF	(1 << 11)
+#define SPI_MCR_CLR_RXF	(1 << 10)
+
+#define SPI_TCR			0x08
+
+#define SPI_CTAR(x)		(0x0c + (x * 4))
+#define SPI_CTAR_FMSZ(x)	(((x) & 0x0000000f) << 27)
+#define SPI_CTAR_CPOL(x)	((x) << 26)
+#define SPI_CTAR_CPHA(x)	((x) << 25)
+#define SPI_CTAR_LSBFE(x)	((x) << 24)
+#define SPI_CTAR_PCSSCR(x)	(((x) & 0x00000003) << 22)
+#define SPI_CTAR_PASC(x)	(((x) & 0x00000003) << 20)
+#define SPI_CTAR_PDT(x)	(((x) & 0x00000003) << 18)
+#define SPI_CTAR_PBR(x)	(((x) & 0x00000003) << 16)
+#define SPI_CTAR_CSSCK(x)	(((x) & 0x0000000f) << 12)
+#define SPI_CTAR_ASC(x)	(((x) & 0x0000000f) << 8)
+#define SPI_CTAR_DT(x)		(((x) & 0x0000000f) << 4)
+#define SPI_CTAR_BR(x)		((x) & 0x0000000f)
+
+#define SPI_CTAR0_SLAVE	0x0c
+
+#define SPI_SR			0x2c
+#define SPI_SR_EOQF		0x10000000
+
+#define SPI_RSER		0x30
+#define SPI_RSER_EOQFE		0x10000000
+
+#define SPI_PUSHR		0x34
+#define SPI_PUSHR_CONT		(1 << 31)
+#define SPI_PUSHR_CTAS(x)	(((x) & 0x00000007) << 28)
+#define SPI_PUSHR_EOQ		(1 << 27)
+#define SPI_PUSHR_CTCNT	(1 << 26)
+#define SPI_PUSHR_PCS(x)	(((1 << x) & 0x0000003f) << 16)
+#define SPI_PUSHR_TXDATA(x)	((x) & 0x0000ffff)
+
+#define SPI_PUSHR_SLAVE	0x34
+
+#define SPI_POPR		0x38
+#define SPI_POPR_RXDATA(x)	((x) & 0x0000ffff)
+
+#define SPI_TXFR0		0x3c
+#define SPI_TXFR1		0x40
+#define SPI_TXFR2		0x44
+#define SPI_TXFR3		0x48
+#define SPI_RXFR0		0x7c
+#define SPI_RXFR1		0x80
+#define SPI_RXFR2		0x84
+#define SPI_RXFR3		0x88
+
+#define SPI_FRAME_BITS(bits)	SPI_CTAR_FMSZ((bits) - 1)
+#define SPI_FRAME_BITS_MASK	SPI_CTAR_FMSZ(0xf)
+#define SPI_FRAME_BITS_16	SPI_CTAR_FMSZ(0xf)
+#define SPI_FRAME_BITS_8	SPI_CTAR_FMSZ(0x7)
+
+#define SPI_CS_INIT		0x01
+#define SPI_CS_ASSERT		0x02
+#define SPI_CS_DROP		0x04
+
+struct chip_data {
+	u32 mcr_val;
+	u32 ctar_val;
+	u16 void_write_data;
+};
+
+struct fsl_dspi {
+	struct spi_bitbang	bitbang;
+	struct platform_device	*pdev;
+
+	void			*base;
+	int			irq;
+	struct clk 		*clk;
+
+	struct spi_transfer 	*cur_transfer;
+	struct chip_data	*cur_chip;
+	size_t			len;
+	void			*tx;
+	void			*tx_end;
+	void			*rx;
+	void			*rx_end;
+	char			dataflags;
+	u8			cs;
+	u16			void_write_data;
+
+	wait_queue_head_t 	waitq;
+	u32 			waitflags;
+};
+
+static inline int is_double_byte_mode(struct fsl_dspi *dspi)
+{
+	return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
+			== SPI_FRAME_BITS(8)) ? 0 : 1;
+}
+
+static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
+{
+	u32 temp;
+
+	temp = readl(dspi->base + SPI_CTAR(dspi->cs));
+	temp &= ~SPI_FRAME_BITS_MASK;
+	temp |= SPI_FRAME_BITS(bits);
+	writel(temp, dspi->base + SPI_CTAR(dspi->cs));
+}
+
+static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
+		unsigned long clkrate)
+{
+	/* Valid baud rate pre-scaler values */
+	int pbr_tbl[4] = {2, 3, 5, 7};
+	int brs[16] = {	2,	4,	6,	8,
+		16,	32,	64,	128,
+		256,	512,	1024,	2048,
+		4096,	8192,	16384,	32768 };
+	int temp, i = 0, j = 0;
+
+	temp = clkrate / 2 / speed_hz;
+
+	for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
+		for (j = 0; j < ARRAY_SIZE(brs); j++) {
+			if (pbr_tbl[i] * brs[j] >= temp) {
+				*pbr = i;
+				*br = j;
+				return;
+			}
+		}
+
+	pr_warn("Can not find valid buad rate,speed_hz is %d,clkrate is %ld\
+		,we use the max prescaler value.\n", speed_hz, clkrate);
+	*pbr = ARRAY_SIZE(pbr_tbl) - 1;
+	*br =  ARRAY_SIZE(brs) - 1;
+}
+
+static int dspi_transfer_write(struct fsl_dspi *dspi)
+{
+	int tx_count = 0;
+	int tx_word;
+	u16 d16;
+	u8  d8;
+	u32 dspi_pushr = 0;
+	int first = 1;
+
+	tx_word = is_double_byte_mode(dspi);
+
+	/* If we are in word mode, but only have a single byte to transfer
+	 * then switch to byte mode temporarily.  Will switch back at the
+	 * end of the transfer.
+	 */
+	if (tx_word && (dspi->len == 1)) {
+		dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
+		set_bit_mode(dspi, 8);
+		tx_word = 0;
+	}
+
+	while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) {
+		if (tx_word) {
+			if (dspi->len == 1)
+				break;
+
+			if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) {
+				d16 = *(u16 *)dspi->tx;
+				dspi->tx += 2;
+			} else {
+				d16 = dspi->void_write_data;
+			}
+
+			dspi_pushr = SPI_PUSHR_TXDATA(d16) |
+				SPI_PUSHR_PCS(dspi->cs) |
+				SPI_PUSHR_CTAS(dspi->cs) |
+				SPI_PUSHR_CONT;
+
+			dspi->len -= 2;
+		} else {
+			if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) {
+
+				d8 = *(u8 *)dspi->tx;
+				dspi->tx++;
+			} else {
+				d8 = (u8)dspi->void_write_data;
+			}
+
+			dspi_pushr = SPI_PUSHR_TXDATA(d8) |
+				SPI_PUSHR_PCS(dspi->cs) |
+				SPI_PUSHR_CTAS(dspi->cs) |
+				SPI_PUSHR_CONT;
+
+			dspi->len--;
+		}
+
+		if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
+			/* last transfer in the transfer */
+			dspi_pushr |= SPI_PUSHR_EOQ;
+		} else if (tx_word && (dspi->len == 1))
+			dspi_pushr |= SPI_PUSHR_EOQ;
+
+		if (first) {
+			first = 0;
+			dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
+		}
+
+		writel(dspi_pushr, dspi->base + SPI_PUSHR);
+		tx_count++;
+	}
+
+	return tx_count * (tx_word + 1);
+}
+
+static int dspi_transfer_read(struct fsl_dspi *dspi)
+{
+	int rx_count = 0;
+	int rx_word = is_double_byte_mode(dspi);
+	u16 d;
+	while ((dspi->rx < dspi->rx_end)
+			&& (rx_count < DSPI_FIFO_SIZE)) {
+		if (rx_word) {
+			if ((dspi->rx_end - dspi->rx) == 1)
+				break;
+
+			d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+
+			if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
+				*(u16 *)dspi->rx = d;
+			dspi->rx += 2;
+
+		} else {
+			d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
+			if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
+				*(u8 *)dspi->rx = d;
+			dspi->rx++;
+		}
+		rx_count++;
+	}
+
+	return rx_count;
+}
+
+static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+	dspi->cur_transfer = t;
+	dspi->cur_chip = spi_get_ctldata(spi);
+	dspi->cs = spi->chip_select;
+	dspi->void_write_data = dspi->cur_chip->void_write_data;
+
+	dspi->dataflags = 0;
+	dspi->tx = (void *)t->tx_buf;
+	dspi->tx_end = dspi->tx + t->len;
+	dspi->rx = t->rx_buf;
+	dspi->rx_end = dspi->rx + t->len;
+	dspi->len = t->len;
+
+	if (!dspi->rx)
+		dspi->dataflags |= TRAN_STATE_RX_VOID;
+
+	if (!dspi->tx)
+		dspi->dataflags |= TRAN_STATE_TX_VOID;
+
+	writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
+	writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
+	writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
+
+	if (t->speed_hz)
+		writel(dspi->cur_chip->ctar_val,
+				dspi->base + SPI_CTAR(dspi->cs));
+
+	dspi_transfer_write(dspi);
+
+	if (wait_event_interruptible(dspi->waitq, dspi->waitflags))
+		dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n");
+	dspi->waitflags = 0;
+
+	return t->len - dspi->len;
+}
+
+static void dspi_chipselect(struct spi_device *spi, int value)
+{
+	struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+	u32 pushr = readl(dspi->base + SPI_PUSHR);
+
+	switch (value) {
+	case BITBANG_CS_ACTIVE:
+		pushr |= SPI_PUSHR_CONT;
+	case BITBANG_CS_INACTIVE:
+		pushr &= ~SPI_PUSHR_CONT;
+	}
+
+	writel(pushr, dspi->base + SPI_PUSHR);
+}
+
+static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct chip_data *chip;
+	struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
+	unsigned char br = 0, pbr = 0, fmsz = 0;
+
+	/* Only alloc on first setup */
+	chip = spi_get_ctldata(spi);
+	if (chip == NULL) {
+		chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+	}
+
+	chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
+		SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
+	if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
+		fmsz = spi->bits_per_word - 1;
+	} else {
+		pr_err("Invalid wordsize\n");
+		kfree(chip);
+		return -ENODEV;
+	}
+
+	chip->void_write_data = 0;
+
+	hz_to_spi_baud(&pbr, &br,
+			spi->max_speed_hz, clk_get_rate(dspi->clk));
+
+	chip->ctar_val =  SPI_CTAR_FMSZ(fmsz)
+		| SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
+		| SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
+		| SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
+		| SPI_CTAR_PBR(pbr)
+		| SPI_CTAR_BR(br);
+
+	spi_set_ctldata(spi, chip);
+
+	return 0;
+}
+
+static int dspi_setup(struct spi_device *spi)
+{
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	if (!spi->bits_per_word)
+		spi->bits_per_word = 8;
+
+	return dspi_setup_transfer(spi, NULL);
+}
+
+static irqreturn_t dspi_interrupt(int irq, void *dev_id)
+{
+	struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
+
+	writel(SPI_SR_EOQF, dspi->base + SPI_SR);
+
+	dspi_transfer_read(dspi);
+
+	if (!dspi->len) {
+		if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
+			set_bit_mode(dspi, 16);
+		dspi->waitflags = 1;
+		wake_up_interruptible(&dspi->waitq);
+	} else {
+		dspi_transfer_write(dspi);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct of_device_id fsl_dspi_dt_ids[] = {
+	{ .compatible = "fsl,vf610-dspi", .data = NULL, },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
+
+#ifdef CONFIG_PM_SLEEP
+static int dspi_suspend(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct fsl_dspi *dspi = spi_master_get_devdata(master);
+
+	spi_master_suspend(master);
+	clk_disable_unprepare(dspi->clk);
+
+	return 0;
+}
+
+static int dspi_resume(struct device *dev)
+{
+
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct fsl_dspi *dspi = spi_master_get_devdata(master);
+
+	clk_prepare_enable(dspi->clk);
+	spi_master_resume(master);
+
+	return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dspi_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
+};
+
+static int dspi_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct spi_master *master;
+	struct fsl_dspi *dspi;
+	struct resource *res;
+	int ret = 0, cs_num, bus_num;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
+	if (!master)
+		return -ENOMEM;
+
+	dspi = spi_master_get_devdata(master);
+	dspi->pdev = pdev;
+	dspi->bitbang.master = spi_master_get(master);
+	dspi->bitbang.chipselect = dspi_chipselect;
+	dspi->bitbang.setup_transfer = dspi_setup_transfer;
+	dspi->bitbang.txrx_bufs = dspi_txrx_transfer;
+	dspi->bitbang.master->setup = dspi_setup;
+	dspi->bitbang.master->dev.of_node = pdev->dev.of_node;
+
+	master->mode_bits = SPI_CPOL | SPI_CPHA;
+	master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
+					SPI_BPW_MASK(16);
+
+	ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "can't get spi-num-chipselects\n");
+		goto out_master_put;
+	}
+	master->num_chipselect = cs_num;
+
+	ret = of_property_read_u32(np, "bus-num", &bus_num);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "can't get bus-num\n");
+		goto out_master_put;
+	}
+	master->bus_num = bus_num;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "can't get platform resource\n");
+		ret = -EINVAL;
+		goto out_master_put;
+	}
+
+	dspi->base = devm_ioremap_resource(&pdev->dev, res);
+	if (!dspi->base) {
+		ret = -EINVAL;
+		goto out_master_put;
+	}
+
+	dspi->irq = platform_get_irq(pdev, 0);
+	if (dspi->irq < 0) {
+		dev_err(&pdev->dev, "can't get platform irq\n");
+		ret = dspi->irq;
+		goto out_master_put;
+	}
+
+	ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0,
+			pdev->name, dspi);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n");
+		goto out_master_put;
+	}
+
+	dspi->clk = devm_clk_get(&pdev->dev, "dspi");
+	if (IS_ERR(dspi->clk)) {
+		ret = PTR_ERR(dspi->clk);
+		dev_err(&pdev->dev, "unable to get clock\n");
+		goto out_master_put;
+	}
+	clk_prepare_enable(dspi->clk);
+
+	init_waitqueue_head(&dspi->waitq);
+	platform_set_drvdata(pdev, dspi);
+
+	ret = spi_bitbang_start(&dspi->bitbang);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Problem registering DSPI master\n");
+		goto out_clk_put;
+	}
+
+	pr_info(KERN_INFO "Freescale DSPI master initialized\n");
+	return ret;
+
+out_clk_put:
+	clk_disable_unprepare(dspi->clk);
+out_master_put:
+	spi_master_put(master);
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int dspi_remove(struct platform_device *pdev)
+{
+	struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+
+	/* Disconnect from the SPI framework */
+	spi_bitbang_stop(&dspi->bitbang);
+	spi_master_put(dspi->bitbang.master);
+
+	return 0;
+}
+
+static struct platform_driver fsl_dspi_driver = {
+	.driver.name    = DRIVER_NAME,
+	.driver.of_match_table = fsl_dspi_dt_ids,
+	.driver.owner   = THIS_MODULE,
+	.driver.pm = &dspi_pm,
+	.probe          = dspi_probe,
+	.remove		= dspi_remove,
+};
+module_platform_driver(fsl_dspi_driver);
+
+MODULE_DESCRIPTION("Freescale DSPI Controller Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 6a74d78..b8f1103 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -584,7 +584,7 @@
 static struct spi_master * fsl_espi_probe(struct device *dev,
 		struct resource *mem, unsigned int irq)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct spi_master *master;
 	struct mpc8xxx_spi *mpc8xxx_spi;
 	struct fsl_espi_reg *reg_base;
@@ -665,7 +665,7 @@
 static int of_fsl_espi_get_chipselects(struct device *dev)
 {
 	struct device_node *np = dev->of_node;
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	const u32 *prop;
 	int len;
 
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index e947f2d..0b75f26 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -122,7 +122,7 @@
 int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
 			unsigned int irq)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct spi_master *master;
 	struct mpc8xxx_spi *mpc8xxx_spi;
 	int ret = 0;
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 41e89c3..2129fcd 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -574,7 +574,7 @@
 
 static void fsl_spi_grlib_probe(struct device *dev)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct spi_master *master = dev_get_drvdata(dev);
 	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
 	struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
@@ -600,7 +600,7 @@
 static struct spi_master * fsl_spi_probe(struct device *dev,
 		struct resource *mem, unsigned int irq)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct spi_master *master;
 	struct mpc8xxx_spi *mpc8xxx_spi;
 	struct fsl_spi_reg *reg_base;
@@ -700,7 +700,8 @@
 static void fsl_spi_cs_control(struct spi_device *spi, bool on)
 {
 	struct device *dev = spi->dev.parent->parent;
-	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
+	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
 	u16 cs = spi->chip_select;
 	int gpio = pinfo->gpios[cs];
 	bool alow = pinfo->alow_flags[cs];
@@ -711,7 +712,7 @@
 static int of_fsl_spi_get_chipselects(struct device *dev)
 {
 	struct device_node *np = dev->of_node;
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
 	int ngpios;
 	int i = 0;
@@ -790,7 +791,7 @@
 
 static int of_fsl_spi_free_chipselects(struct device *dev)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
 	int i;
 
@@ -889,7 +890,7 @@
 	int irq;
 	struct spi_master *master;
 
-	if (!pdev->dev.platform_data)
+	if (!dev_get_platdata(&pdev->dev))
 		return -EINVAL;
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -901,7 +902,7 @@
 		return -EINVAL;
 
 	master = fsl_spi_probe(&pdev->dev, mem, irq);
-	return PTR_RET(master);
+	return PTR_ERR_OR_ZERO(master);
 }
 
 static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index a54524c..68b69fe 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -420,7 +420,7 @@
 	if (status > 0)
 		use_of = 1;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 #ifdef GENERIC_BITBANG
 	if (!pdata || !pdata->num_chipselect)
 		return -ENODEV;
@@ -506,7 +506,7 @@
 	int				status;
 
 	spi_gpio = platform_get_drvdata(pdev);
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 
 	/* stop() unregisters child devices too */
 	status = spi_bitbang_stop(&spi_gpio->bitbang);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 7db4f43..15323d8 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -619,6 +619,7 @@
 	{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
 	{ /* sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
 
 static void spi_imx_chipselect(struct spi_device *spi, int is_active)
 {
@@ -796,10 +797,11 @@
 		if (!gpio_is_valid(cs_gpio))
 			continue;
 
-		ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
+		ret = devm_gpio_request(&pdev->dev, spi_imx->chipselect[i],
+					DRIVER_NAME);
 		if (ret) {
 			dev_err(&pdev->dev, "can't get cs gpios\n");
-			goto out_gpio_free;
+			goto out_master_put;
 		}
 	}
 
@@ -816,50 +818,44 @@
 		(struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "can't get platform resource\n");
-		ret = -ENOMEM;
-		goto out_gpio_free;
-	}
-
-	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
-		dev_err(&pdev->dev, "request_mem_region failed\n");
-		ret = -EBUSY;
-		goto out_gpio_free;
-	}
-
-	spi_imx->base = ioremap(res->start, resource_size(res));
-	if (!spi_imx->base) {
-		ret = -EINVAL;
-		goto out_release_mem;
+	spi_imx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(spi_imx->base)) {
+		ret = PTR_ERR(spi_imx->base);
+		goto out_master_put;
 	}
 
 	spi_imx->irq = platform_get_irq(pdev, 0);
 	if (spi_imx->irq < 0) {
 		ret = -EINVAL;
-		goto out_iounmap;
+		goto out_master_put;
 	}
 
-	ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
+	ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
+			       DRIVER_NAME, spi_imx);
 	if (ret) {
 		dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
-		goto out_iounmap;
+		goto out_master_put;
 	}
 
 	spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(spi_imx->clk_ipg)) {
 		ret = PTR_ERR(spi_imx->clk_ipg);
-		goto out_free_irq;
+		goto out_master_put;
 	}
 
 	spi_imx->clk_per = devm_clk_get(&pdev->dev, "per");
 	if (IS_ERR(spi_imx->clk_per)) {
 		ret = PTR_ERR(spi_imx->clk_per);
-		goto out_free_irq;
+		goto out_master_put;
 	}
 
-	clk_prepare_enable(spi_imx->clk_per);
-	clk_prepare_enable(spi_imx->clk_ipg);
+	ret = clk_prepare_enable(spi_imx->clk_per);
+	if (ret)
+		goto out_master_put;
+
+	ret = clk_prepare_enable(spi_imx->clk_ipg);
+	if (ret)
+		goto out_put_per;
 
 	spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
 
@@ -879,47 +875,27 @@
 	return ret;
 
 out_clk_put:
-	clk_disable_unprepare(spi_imx->clk_per);
 	clk_disable_unprepare(spi_imx->clk_ipg);
-out_free_irq:
-	free_irq(spi_imx->irq, spi_imx);
-out_iounmap:
-	iounmap(spi_imx->base);
-out_release_mem:
-	release_mem_region(res->start, resource_size(res));
-out_gpio_free:
-	while (--i >= 0) {
-		if (gpio_is_valid(spi_imx->chipselect[i]))
-			gpio_free(spi_imx->chipselect[i]);
-	}
+out_put_per:
+	clk_disable_unprepare(spi_imx->clk_per);
+out_master_put:
 	spi_master_put(master);
-	kfree(master);
+
 	return ret;
 }
 
 static int spi_imx_remove(struct platform_device *pdev)
 {
 	struct spi_master *master = platform_get_drvdata(pdev);
-	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
-	int i;
 
 	spi_bitbang_stop(&spi_imx->bitbang);
 
 	writel(0, spi_imx->base + MXC_CSPICTRL);
-	clk_disable_unprepare(spi_imx->clk_per);
 	clk_disable_unprepare(spi_imx->clk_ipg);
-	free_irq(spi_imx->irq, spi_imx);
-	iounmap(spi_imx->base);
-
-	for (i = 0; i < master->num_chipselect; i++)
-		if (gpio_is_valid(spi_imx->chipselect[i]))
-			gpio_free(spi_imx->chipselect[i]);
-
+	clk_disable_unprepare(spi_imx->clk_per);
 	spi_master_put(master);
 
-	release_mem_region(res->start, resource_size(res));
-
 	return 0;
 }
 
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 29fce6a..dbc5e99 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -38,7 +38,8 @@
 	struct mpc512x_psc_fifo __iomem *fifo;
 	unsigned int irq;
 	u8 bits_per_word;
-	u32 mclk;
+	struct clk *clk_mclk;
+	u32 mclk_rate;
 
 	struct completion txisrdone;
 };
@@ -72,6 +73,7 @@
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
 	sicr = in_be32(&psc->sicr);
@@ -95,10 +97,10 @@
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	if (cs->speed_hz)
-		bclkdiv = (mps->mclk / cs->speed_hz) - 1;
-	else
-		bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = cs->speed_hz;
+	if (!speed)
+		speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
@@ -386,19 +388,11 @@
 {
 	struct mpc52xx_psc __iomem *psc = mps->psc;
 	struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
-	struct clk *spiclk;
-	int ret = 0;
-	char name[32];
 	u32 sicr;
 	u32 ccr;
+	int speed;
 	u16 bclkdiv;
 
-	sprintf(name, "psc%d_mclk", master->bus_num);
-	spiclk = clk_get(&master->dev, name);
-	clk_enable(spiclk);
-	mps->mclk = clk_get_rate(spiclk);
-	clk_put(spiclk);
-
 	/* Reset the PSC into a known state */
 	out_8(&psc->command, MPC52xx_PSC_RST_RX);
 	out_8(&psc->command, MPC52xx_PSC_RST_TX);
@@ -425,7 +419,8 @@
 
 	ccr = in_be32(&psc->ccr);
 	ccr &= 0xFF000000;
-	bclkdiv = (mps->mclk / 1000000) - 1;	/* default 1MHz */
+	speed = 1000000;	/* default 1MHz */
+	bclkdiv = (mps->mclk_rate / speed) - 1;
 	ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
 	out_be32(&psc->ccr, ccr);
 
@@ -445,7 +440,7 @@
 
 	mps->bits_per_word = 8;
 
-	return ret;
+	return 0;
 }
 
 static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
@@ -474,11 +469,14 @@
 					      u32 size, unsigned int irq,
 					      s16 bus_num)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct mpc512x_psc_spi *mps;
 	struct spi_master *master;
 	int ret;
 	void *tempp;
+	int psc_num;
+	char clk_name[16];
+	struct clk *clk;
 
 	master = spi_alloc_master(dev, sizeof *mps);
 	if (master == NULL)
@@ -521,16 +519,29 @@
 		goto free_master;
 	init_completion(&mps->txisrdone);
 
+	psc_num = master->bus_num;
+	snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
+	clk = devm_clk_get(dev, clk_name);
+	if (IS_ERR(clk))
+		goto free_irq;
+	ret = clk_prepare_enable(clk);
+	if (ret)
+		goto free_irq;
+	mps->clk_mclk = clk;
+	mps->mclk_rate = clk_get_rate(clk);
+
 	ret = mpc512x_psc_spi_port_config(master, mps);
 	if (ret < 0)
-		goto free_irq;
+		goto free_clock;
 
 	ret = spi_register_master(master);
 	if (ret < 0)
-		goto free_irq;
+		goto free_clock;
 
 	return ret;
 
+free_clock:
+	clk_disable_unprepare(mps->clk_mclk);
 free_irq:
 	free_irq(mps->irq, mps);
 free_master:
@@ -547,6 +558,7 @@
 	struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
 
 	spi_unregister_master(master);
+	clk_disable_unprepare(mps->clk_mclk);
 	free_irq(mps->irq, mps);
 	if (mps->psc)
 		iounmap(mps->psc);
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index fed0571..6e925dc 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -366,7 +366,7 @@
 static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
 				u32 size, unsigned int irq, s16 bus_num)
 {
-	struct fsl_spi_platform_data *pdata = dev->platform_data;
+	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
 	struct mpc52xx_psc_spi *mps;
 	struct spi_master *master;
 	int ret;
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 424d38e..de7b114 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -67,13 +67,8 @@
 {
 	struct mxs_spi *spi = spi_master_get_devdata(dev->master);
 	struct mxs_ssp *ssp = &spi->ssp;
-	uint8_t bits_per_word;
 	uint32_t hz = 0;
 
-	bits_per_word = dev->bits_per_word;
-	if (t && t->bits_per_word)
-		bits_per_word = t->bits_per_word;
-
 	hz = dev->max_speed_hz;
 	if (t && t->speed_hz)
 		hz = min(hz, t->speed_hz);
@@ -513,7 +508,7 @@
 
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	irq_err = platform_get_irq(pdev, 0);
-	if (!iores || irq_err < 0)
+	if (irq_err < 0)
 		return -EINVAL;
 
 	base = devm_ioremap_resource(&pdev->dev, iores);
@@ -563,25 +558,31 @@
 		goto out_master_free;
 	}
 
-	clk_prepare_enable(ssp->clk);
+	ret = clk_prepare_enable(ssp->clk);
+	if (ret)
+		goto out_dma_release;
+
 	clk_set_rate(ssp->clk, clk_freq);
 	ssp->clk_rate = clk_get_rate(ssp->clk) / 1000;
 
-	stmp_reset_block(ssp->base);
+	ret = stmp_reset_block(ssp->base);
+	if (ret)
+		goto out_disable_clk;
 
 	platform_set_drvdata(pdev, master);
 
 	ret = spi_register_master(master);
 	if (ret) {
 		dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
-		goto out_free_dma;
+		goto out_disable_clk;
 	}
 
 	return 0;
 
-out_free_dma:
-	dma_release_channel(ssp->dmach);
+out_disable_clk:
 	clk_disable_unprepare(ssp->clk);
+out_dma_release:
+	dma_release_channel(ssp->dmach);
 out_master_free:
 	spi_master_put(master);
 	return ret;
@@ -598,11 +599,8 @@
 	ssp = &spi->ssp;
 
 	spi_unregister_master(master);
-
-	dma_release_channel(ssp->dmach);
-
 	clk_disable_unprepare(ssp->clk);
-
+	dma_release_channel(ssp->dmach);
 	spi_master_put(master);
 
 	return 0;
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
index 150d854..47a68b4 100644
--- a/drivers/spi/spi-nuc900.c
+++ b/drivers/spi/spi-nuc900.c
@@ -174,17 +174,6 @@
 	spin_unlock_irqrestore(&hw->lock, flags);
 }
 
-static int nuc900_spi_setupxfer(struct spi_device *spi,
-				 struct spi_transfer *t)
-{
-	return 0;
-}
-
-static int nuc900_spi_setup(struct spi_device *spi)
-{
-	return 0;
-}
-
 static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
 {
 	return hw->tx ? hw->tx[count] : 0;
@@ -361,7 +350,7 @@
 
 	hw = spi_master_get_devdata(master);
 	hw->master = spi_master_get(master);
-	hw->pdata  = pdev->dev.platform_data;
+	hw->pdata  = dev_get_platdata(&pdev->dev);
 	hw->dev = &pdev->dev;
 
 	if (hw->pdata == NULL) {
@@ -373,14 +362,12 @@
 	platform_set_drvdata(pdev, hw);
 	init_completion(&hw->done);
 
-	master->mode_bits          = SPI_MODE_0;
+	master->mode_bits          = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 	master->num_chipselect     = hw->pdata->num_cs;
 	master->bus_num            = hw->pdata->bus_num;
 	hw->bitbang.master         = hw->master;
-	hw->bitbang.setup_transfer = nuc900_spi_setupxfer;
 	hw->bitbang.chipselect     = nuc900_spi_chipsel;
 	hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
-	hw->bitbang.master->setup  = nuc900_spi_setup;
 
 	hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (hw->res == NULL) {
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 58deb79..333cb1b 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -285,7 +285,7 @@
 
 static int tiny_spi_probe(struct platform_device *pdev)
 {
-	struct tiny_spi_platform_data *platp = pdev->dev.platform_data;
+	struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
 	struct tiny_spi *hw;
 	struct spi_master *master;
 	struct resource *res;
@@ -315,15 +315,11 @@
 
 	/* find and map our resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		goto exit_busy;
-	if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-				     pdev->name))
-		goto exit_busy;
-	hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
-					resource_size(res));
-	if (!hw->base)
-		goto exit_busy;
+	hw->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hw->base)) {
+		err = PTR_ERR(hw->base);
+		goto exit;
+	}
 	/* irq is optional */
 	hw->irq = platform_get_irq(pdev, 0);
 	if (hw->irq >= 0) {
@@ -337,8 +333,10 @@
 	if (platp) {
 		hw->gpio_cs_count = platp->gpio_cs_count;
 		hw->gpio_cs = platp->gpio_cs;
-		if (platp->gpio_cs_count && !platp->gpio_cs)
-			goto exit_busy;
+		if (platp->gpio_cs_count && !platp->gpio_cs) {
+			err = -EBUSY;
+			goto exit;
+		}
 		hw->freq = platp->freq;
 		hw->baudwidth = platp->baudwidth;
 	} else {
@@ -365,8 +363,6 @@
 exit_gpio:
 	while (i-- > 0)
 		gpio_free(hw->gpio_cs[i]);
-exit_busy:
-	err = -EBUSY;
 exit:
 	spi_master_put(master);
 	return err;
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c
index 24daf96..5f28ddb 100644
--- a/drivers/spi/spi-octeon.c
+++ b/drivers/spi/spi-octeon.c
@@ -28,7 +28,6 @@
 #define OCTEON_SPI_MAX_CLOCK_HZ 16000000
 
 struct octeon_spi {
-	struct spi_master *my_master;
 	u64 register_base;
 	u64 last_cfg;
 	u64 cs_enax;
@@ -64,7 +63,6 @@
 	unsigned int speed_hz;
 	int mode;
 	bool cpha, cpol;
-	int bits_per_word;
 	const u8 *tx_buf;
 	u8 *rx_buf;
 	int len;
@@ -76,12 +74,9 @@
 	mode = msg_setup->mode;
 	cpha = mode & SPI_CPHA;
 	cpol = mode & SPI_CPOL;
-	bits_per_word = msg_setup->bits_per_word;
 
 	if (xfer->speed_hz)
 		speed_hz = xfer->speed_hz;
-	if (xfer->bits_per_word)
-		bits_per_word = xfer->bits_per_word;
 
 	if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
 		speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
@@ -166,19 +161,6 @@
 	return xfer->len;
 }
 
-static int octeon_spi_validate_bpw(struct spi_device *spi, u32 speed)
-{
-	switch (speed) {
-	case 8:
-		break;
-	default:
-		dev_err(&spi->dev, "Error: %d bits per word not supported\n",
-			speed);
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static int octeon_spi_transfer_one_message(struct spi_master *master,
 					   struct spi_message *msg)
 {
@@ -197,15 +179,6 @@
 	}
 
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-		if (xfer->bits_per_word) {
-			status = octeon_spi_validate_bpw(msg->spi,
-							 xfer->bits_per_word);
-			if (status)
-				goto err;
-		}
-	}
-
-	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 		bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
 		int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
 		if (r < 0) {
@@ -236,14 +209,9 @@
 
 static int octeon_spi_setup(struct spi_device *spi)
 {
-	int r;
 	struct octeon_spi_setup *new_setup;
 	struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
 
-	r = octeon_spi_validate_bpw(spi, spi->bits_per_word);
-	if (r)
-		return r;
-
 	new_setup = octeon_spi_new_setup(spi);
 	if (!new_setup)
 		return -ENOMEM;
@@ -261,14 +229,8 @@
 	kfree(old_setup);
 }
 
-static int octeon_spi_nop_transfer_hardware(struct spi_master *master)
-{
-	return 0;
-}
-
 static int octeon_spi_probe(struct platform_device *pdev)
 {
-
 	struct resource *res_mem;
 	struct spi_master *master;
 	struct octeon_spi *p;
@@ -278,8 +240,7 @@
 	if (!master)
 		return -ENOMEM;
 	p = spi_master_get_devdata(master);
-	platform_set_drvdata(pdev, p);
-	p->my_master = master;
+	platform_set_drvdata(pdev, master);
 
 	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -307,9 +268,8 @@
 
 	master->setup = octeon_spi_setup;
 	master->cleanup = octeon_spi_cleanup;
-	master->prepare_transfer_hardware = octeon_spi_nop_transfer_hardware;
 	master->transfer_one_message = octeon_spi_transfer_one_message;
-	master->unprepare_transfer_hardware = octeon_spi_nop_transfer_hardware;
+	master->bits_per_word_mask = SPI_BPW_MASK(8);
 
 	master->dev.of_node = pdev->dev.of_node;
 	err = spi_register_master(master);
@@ -328,10 +288,11 @@
 
 static int octeon_spi_remove(struct platform_device *pdev)
 {
-	struct octeon_spi *p = platform_get_drvdata(pdev);
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct octeon_spi *p = spi_master_get_devdata(master);
 	u64 register_base = p->register_base;
 
-	spi_unregister_master(p->my_master);
+	spi_unregister_master(master);
 
 	/* Clear the CSENA* and put everything in a known state. */
 	cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index ee25670..69ecf05 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -83,11 +83,6 @@
 #define SPI_SHUTDOWN	1
 
 struct omap1_spi100k {
-	struct work_struct      work;
-
-	/* lock protects queue and registers */
-	spinlock_t              lock;
-	struct list_head        msg_queue;
 	struct spi_master       *master;
 	struct clk              *ick;
 	struct clk              *fck;
@@ -104,8 +99,6 @@
 	int                     word_len;
 };
 
-static struct workqueue_struct *omap1_spi100k_wq;
-
 #define MOD_REG_BIT(val, mask, set) do { \
 	if (set) \
 		val |= mask; \
@@ -310,170 +303,102 @@
 
 	spi100k_open(spi->master);
 
-	clk_enable(spi100k->ick);
-	clk_enable(spi100k->fck);
+	clk_prepare_enable(spi100k->ick);
+	clk_prepare_enable(spi100k->fck);
 
 	ret = omap1_spi100k_setup_transfer(spi, NULL);
 
-	clk_disable(spi100k->ick);
-	clk_disable(spi100k->fck);
+	clk_disable_unprepare(spi100k->ick);
+	clk_disable_unprepare(spi100k->fck);
 
 	return ret;
 }
 
-static void omap1_spi100k_work(struct work_struct *work)
+static int omap1_spi100k_prepare_hardware(struct spi_master *master)
 {
-	struct omap1_spi100k    *spi100k;
-	int status = 0;
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
 
-	spi100k = container_of(work, struct omap1_spi100k, work);
-	spin_lock_irq(&spi100k->lock);
-
-	clk_enable(spi100k->ick);
-	clk_enable(spi100k->fck);
-
-	/* We only enable one channel at a time -- the one whose message is
-	 * at the head of the queue -- although this controller would gladly
-	 * arbitrate among multiple channels.  This corresponds to "single
-	 * channel" master mode.  As a side effect, we need to manage the
-	 * chipselect with the FORCE bit ... CS != channel enable.
-	 */
-	 while (!list_empty(&spi100k->msg_queue)) {
-		struct spi_message              *m;
-		struct spi_device               *spi;
-		struct spi_transfer             *t = NULL;
-		int                             cs_active = 0;
-		struct omap1_spi100k_cs         *cs;
-		int                             par_override = 0;
-
-		m = container_of(spi100k->msg_queue.next, struct spi_message,
-				 queue);
-
-		list_del_init(&m->queue);
-		spin_unlock_irq(&spi100k->lock);
-
-		spi = m->spi;
-		cs = spi->controller_state;
-
-		list_for_each_entry(t, &m->transfers, transfer_list) {
-			if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-				status = -EINVAL;
-				break;
-			}
-			if (par_override || t->speed_hz || t->bits_per_word) {
-				par_override = 1;
-				status = omap1_spi100k_setup_transfer(spi, t);
-				if (status < 0)
-					break;
-				if (!t->speed_hz && !t->bits_per_word)
-					par_override = 0;
-			}
-
-			if (!cs_active) {
-				omap1_spi100k_force_cs(spi100k, 1);
-				cs_active = 1;
-			}
-
-			if (t->len) {
-				unsigned count;
-
-				count = omap1_spi100k_txrx_pio(spi, t);
-				m->actual_length += count;
-
-				if (count != t->len) {
-					status = -EIO;
-					break;
-				}
-			}
-
-			if (t->delay_usecs)
-				udelay(t->delay_usecs);
-
-			/* ignore the "leave it on after last xfer" hint */
-
-			if (t->cs_change) {
-				omap1_spi100k_force_cs(spi100k, 0);
-				cs_active = 0;
-			}
-		}
-
-		/* Restore defaults if they were overriden */
-		if (par_override) {
-			par_override = 0;
-			status = omap1_spi100k_setup_transfer(spi, NULL);
-		}
-
-		if (cs_active)
-			omap1_spi100k_force_cs(spi100k, 0);
-
-		m->status = status;
-		m->complete(m->context);
-
-		spin_lock_irq(&spi100k->lock);
-	}
-
-	clk_disable(spi100k->ick);
-	clk_disable(spi100k->fck);
-	spin_unlock_irq(&spi100k->lock);
-
-	if (status < 0)
-		printk(KERN_WARNING "spi transfer failed with %d\n", status);
-}
-
-static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
-{
-	struct omap1_spi100k    *spi100k;
-	unsigned long           flags;
-	struct spi_transfer     *t;
-
-	m->actual_length = 0;
-	m->status = -EINPROGRESS;
-
-	spi100k = spi_master_get_devdata(spi->master);
-
-	/* Don't accept new work if we're shutting down */
-	if (spi100k->state == SPI_SHUTDOWN)
-		return -ESHUTDOWN;
-
-	/* reject invalid messages and transfers */
-	if (list_empty(&m->transfers) || !m->complete)
-		return -EINVAL;
-
-	list_for_each_entry(t, &m->transfers, transfer_list) {
-		const void      *tx_buf = t->tx_buf;
-		void            *rx_buf = t->rx_buf;
-		unsigned        len = t->len;
-
-		if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
-				|| (len && !(rx_buf || tx_buf))) {
-			dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
-					t->speed_hz,
-					len,
-					tx_buf ? "tx" : "",
-					rx_buf ? "rx" : "",
-					t->bits_per_word);
-			return -EINVAL;
-		}
-
-		if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) {
-			dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
-					t->speed_hz,
-					OMAP1_SPI100K_MAX_FREQ/(1<<16));
-			return -EINVAL;
-		}
-
-	}
-
-	spin_lock_irqsave(&spi100k->lock, flags);
-	list_add_tail(&m->queue, &spi100k->msg_queue);
-	queue_work(omap1_spi100k_wq, &spi100k->work);
-	spin_unlock_irqrestore(&spi100k->lock, flags);
+	clk_prepare_enable(spi100k->ick);
+	clk_prepare_enable(spi100k->fck);
 
 	return 0;
 }
 
-static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
+static int omap1_spi100k_transfer_one_message(struct spi_master *master,
+					      struct spi_message *m)
 {
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+	struct spi_device *spi = m->spi;
+	struct spi_transfer *t = NULL;
+	int cs_active = 0;
+	int par_override = 0;
+	int status = 0;
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+			status = -EINVAL;
+			break;
+		}
+		if (par_override || t->speed_hz || t->bits_per_word) {
+			par_override = 1;
+			status = omap1_spi100k_setup_transfer(spi, t);
+			if (status < 0)
+				break;
+			if (!t->speed_hz && !t->bits_per_word)
+				par_override = 0;
+		}
+
+		if (!cs_active) {
+			omap1_spi100k_force_cs(spi100k, 1);
+			cs_active = 1;
+		}
+
+		if (t->len) {
+			unsigned count;
+
+			count = omap1_spi100k_txrx_pio(spi, t);
+			m->actual_length += count;
+
+			if (count != t->len) {
+				status = -EIO;
+				break;
+			}
+		}
+
+		if (t->delay_usecs)
+			udelay(t->delay_usecs);
+
+		/* ignore the "leave it on after last xfer" hint */
+
+		if (t->cs_change) {
+			omap1_spi100k_force_cs(spi100k, 0);
+			cs_active = 0;
+		}
+	}
+
+	/* Restore defaults if they were overriden */
+	if (par_override) {
+		par_override = 0;
+		status = omap1_spi100k_setup_transfer(spi, NULL);
+	}
+
+	if (cs_active)
+		omap1_spi100k_force_cs(spi100k, 0);
+
+	m->status = status;
+
+	spi_finalize_current_message(master);
+
+	return status;
+}
+
+static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
+{
+	struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
+
+	clk_disable_unprepare(spi100k->ick);
+	clk_disable_unprepare(spi100k->fck);
+
 	return 0;
 }
 
@@ -496,11 +421,15 @@
 	       master->bus_num = pdev->id;
 
 	master->setup = omap1_spi100k_setup;
-	master->transfer = omap1_spi100k_transfer;
+	master->transfer_one_message = omap1_spi100k_transfer_one_message;
+	master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
+	master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
 	master->cleanup = NULL;
 	master->num_chipselect = 2;
 	master->mode_bits = MODEBITS;
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+	master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
+	master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
 
 	platform_set_drvdata(pdev, master);
 
@@ -512,42 +441,31 @@
 	 * You should allocate this with ioremap() before initializing
 	 * the SPI.
 	 */
-	spi100k->base = (void __iomem *) pdev->dev.platform_data;
+	spi100k->base = (void __iomem *)dev_get_platdata(&pdev->dev);
 
-	INIT_WORK(&spi100k->work, omap1_spi100k_work);
-
-	spin_lock_init(&spi100k->lock);
-	INIT_LIST_HEAD(&spi100k->msg_queue);
-	spi100k->ick = clk_get(&pdev->dev, "ick");
+	spi100k->ick = devm_clk_get(&pdev->dev, "ick");
 	if (IS_ERR(spi100k->ick)) {
 		dev_dbg(&pdev->dev, "can't get spi100k_ick\n");
 		status = PTR_ERR(spi100k->ick);
-		goto err1;
+		goto err;
 	}
 
-	spi100k->fck = clk_get(&pdev->dev, "fck");
+	spi100k->fck = devm_clk_get(&pdev->dev, "fck");
 	if (IS_ERR(spi100k->fck)) {
 		dev_dbg(&pdev->dev, "can't get spi100k_fck\n");
 		status = PTR_ERR(spi100k->fck);
-		goto err2;
+		goto err;
 	}
 
-	if (omap1_spi100k_reset(spi100k) < 0)
-		goto err3;
-
 	status = spi_register_master(master);
 	if (status < 0)
-		goto err3;
+		goto err;
 
 	spi100k->state = SPI_RUNNING;
 
 	return status;
 
-err3:
-	clk_put(spi100k->fck);
-err2:
-	clk_put(spi100k->ick);
-err1:
+err:
 	spi_master_put(master);
 	return status;
 }
@@ -557,33 +475,14 @@
 	struct spi_master       *master;
 	struct omap1_spi100k    *spi100k;
 	struct resource         *r;
-	unsigned		limit = 500;
-	unsigned long		flags;
 	int			status = 0;
 
 	master = platform_get_drvdata(pdev);
 	spi100k = spi_master_get_devdata(master);
 
-	spin_lock_irqsave(&spi100k->lock, flags);
-
-	spi100k->state = SPI_SHUTDOWN;
-	while (!list_empty(&spi100k->msg_queue) && limit--) {
-		spin_unlock_irqrestore(&spi100k->lock, flags);
-		msleep(10);
-		spin_lock_irqsave(&spi100k->lock, flags);
-	}
-
-	if (!list_empty(&spi100k->msg_queue))
-		status = -EBUSY;
-
-	spin_unlock_irqrestore(&spi100k->lock, flags);
-
 	if (status != 0)
 		return status;
 
-	clk_put(spi100k->fck);
-	clk_put(spi100k->ick);
-
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	spi_unregister_master(master);
@@ -596,30 +495,11 @@
 		.name		= "omap1_spi100k",
 		.owner		= THIS_MODULE,
 	},
+	.probe		= omap1_spi100k_probe,
 	.remove		= omap1_spi100k_remove,
 };
 
-
-static int __init omap1_spi100k_init(void)
-{
-	omap1_spi100k_wq = create_singlethread_workqueue(
-			omap1_spi100k_driver.driver.name);
-
-	if (omap1_spi100k_wq == NULL)
-		return -1;
-
-	return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe);
-}
-
-static void __exit omap1_spi100k_exit(void)
-{
-	platform_driver_unregister(&omap1_spi100k_driver);
-
-	destroy_workqueue(omap1_spi100k_wq);
-}
-
-module_init(omap1_spi100k_init);
-module_exit(omap1_spi100k_exit);
+module_platform_driver(omap1_spi100k_driver);
 
 MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver");
 MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>");
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 5994039..ed4af47 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -335,23 +335,6 @@
 		__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
 }
 
-static int omap2_prepare_transfer(struct spi_master *master)
-{
-	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
-
-	pm_runtime_get_sync(mcspi->dev);
-	return 0;
-}
-
-static int omap2_unprepare_transfer(struct spi_master *master)
-{
-	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
-
-	pm_runtime_mark_last_busy(mcspi->dev);
-	pm_runtime_put_autosuspend(mcspi->dev);
-	return 0;
-}
-
 static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
 {
 	unsigned long timeout;
@@ -1318,8 +1301,7 @@
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
 	master->setup = omap2_mcspi_setup;
-	master->prepare_transfer_hardware = omap2_prepare_transfer;
-	master->unprepare_transfer_hardware = omap2_unprepare_transfer;
+	master->auto_runtime_pm = true;
 	master->transfer_one_message = omap2_mcspi_transfer_one_message;
 	master->cleanup = omap2_mcspi_cleanup;
 	master->dev.of_node = node;
@@ -1340,7 +1322,7 @@
 		if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
 			mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
 	} else {
-		pdata = pdev->dev.platform_data;
+		pdata = dev_get_platdata(&pdev->dev);
 		master->num_chipselect = pdata->num_cs;
 		if (pdev->id != -1)
 			master->bus_num = pdev->id;
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 5d90beb..1d1d321 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <linux/sizes.h>
 #include <asm/unaligned.h>
 
 #define DRIVER_NAME			"orion_spi"
@@ -446,30 +447,22 @@
 	spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (r == NULL) {
-		status = -ENODEV;
+	spi->base = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(spi->base)) {
+		status = PTR_ERR(spi->base);
 		goto out_rel_clk;
 	}
 
-	if (!request_mem_region(r->start, resource_size(r),
-				dev_name(&pdev->dev))) {
-		status = -EBUSY;
-		goto out_rel_clk;
-	}
-	spi->base = ioremap(r->start, SZ_1K);
-
 	if (orion_spi_reset(spi) < 0)
-		goto out_rel_mem;
+		goto out_rel_clk;
 
 	master->dev.of_node = pdev->dev.of_node;
 	status = spi_register_master(master);
 	if (status < 0)
-		goto out_rel_mem;
+		goto out_rel_clk;
 
 	return status;
 
-out_rel_mem:
-	release_mem_region(r->start, resource_size(r));
 out_rel_clk:
 	clk_disable_unprepare(spi->clk);
 	clk_put(spi->clk);
@@ -482,7 +475,6 @@
 static int orion_spi_remove(struct platform_device *pdev)
 {
 	struct spi_master *master;
-	struct resource *r;
 	struct orion_spi *spi;
 
 	master = platform_get_drvdata(pdev);
@@ -491,9 +483,6 @@
 	clk_disable_unprepare(spi->clk);
 	clk_put(spi->clk);
 
-	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(r->start, resource_size(r));
-
 	spi_unregister_master(master);
 
 	return 0;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index abef061..9c511a9 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1555,18 +1555,6 @@
 	return 0;
 }
 
-static int pl022_prepare_transfer_hardware(struct spi_master *master)
-{
-	struct pl022 *pl022 = spi_master_get_devdata(master);
-
-	/*
-	 * Just make sure we have all we need to run the transfer by syncing
-	 * with the runtime PM framework.
-	 */
-	pm_runtime_get_sync(&pl022->adev->dev);
-	return 0;
-}
-
 static int pl022_unprepare_transfer_hardware(struct spi_master *master)
 {
 	struct pl022 *pl022 = spi_master_get_devdata(master);
@@ -1575,13 +1563,6 @@
 	writew((readw(SSP_CR1(pl022->virtbase)) &
 		(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
 
-	if (pl022->master_info->autosuspend_delay > 0) {
-		pm_runtime_mark_last_busy(&pl022->adev->dev);
-		pm_runtime_put_autosuspend(&pl022->adev->dev);
-	} else {
-		pm_runtime_put(&pl022->adev->dev);
-	}
-
 	return 0;
 }
 
@@ -2091,7 +2072,8 @@
 static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
 {
 	struct device *dev = &adev->dev;
-	struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
+	struct pl022_ssp_controller *platform_info =
+			dev_get_platdata(&adev->dev);
 	struct spi_master *master;
 	struct pl022 *pl022 = NULL;	/*Data for this driver */
 	struct device_node *np = adev->dev.of_node;
@@ -2139,7 +2121,7 @@
 	master->num_chipselect = num_cs;
 	master->cleanup = pl022_cleanup;
 	master->setup = pl022_setup;
-	master->prepare_transfer_hardware = pl022_prepare_transfer_hardware;
+	master->auto_runtime_pm = true;
 	master->transfer_one_message = pl022_transfer_one_message;
 	master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
 	master->rt = platform_info->rt;
@@ -2193,8 +2175,8 @@
 		status = -ENOMEM;
 		goto err_no_ioremap;
 	}
-	printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
-	       adev->res.start, pl022->virtbase);
+	printk(KERN_INFO "pl022: mapped registers from %pa to %p\n",
+	       &adev->res.start, pl022->virtbase);
 
 	pl022->clk = devm_clk_get(&adev->dev, NULL);
 	if (IS_ERR(pl022->clk)) {
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index f440dce..2eb06ee 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -69,6 +69,8 @@
 #define LPSS_TX_HITHRESH_DFLT	224
 
 /* Offset from drv_data->lpss_base */
+#define GENERAL_REG		0x08
+#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
 #define SSP_REG			0x0c
 #define SPI_CS_CONTROL		0x18
 #define SPI_CS_CONTROL_SW_MODE	BIT(0)
@@ -142,8 +144,13 @@
 	__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
 
 	/* Enable multiblock DMA transfers */
-	if (drv_data->master_info->enable_dma)
+	if (drv_data->master_info->enable_dma) {
 		__lpss_ssp_write_priv(drv_data, SSP_REG, 1);
+
+		value = __lpss_ssp_read_priv(drv_data, GENERAL_REG);
+		value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
+		__lpss_ssp_write_priv(drv_data, GENERAL_REG, value);
+	}
 }
 
 static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
@@ -804,14 +811,6 @@
 	return 0;
 }
 
-static int pxa2xx_spi_prepare_transfer(struct spi_master *master)
-{
-	struct driver_data *drv_data = spi_master_get_devdata(master);
-
-	pm_runtime_get_sync(&drv_data->pdev->dev);
-	return 0;
-}
-
 static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
 {
 	struct driver_data *drv_data = spi_master_get_devdata(master);
@@ -820,8 +819,6 @@
 	write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
 		    drv_data->ioaddr);
 
-	pm_runtime_mark_last_busy(&drv_data->pdev->dev);
-	pm_runtime_put_autosuspend(&drv_data->pdev->dev);
 	return 0;
 }
 
@@ -1134,8 +1131,8 @@
 	master->cleanup = cleanup;
 	master->setup = setup;
 	master->transfer_one_message = pxa2xx_spi_transfer_one_message;
-	master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer;
 	master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
+	master->auto_runtime_pm = true;
 
 	drv_data->ssp_type = ssp->type;
 	drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index b44a6ac..8719206 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -564,8 +564,12 @@
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&rspi->lock, flags);
-	while (!list_empty(&rspi->queue)) {
+	while (1) {
+		spin_lock_irqsave(&rspi->lock, flags);
+		if (list_empty(&rspi->queue)) {
+			spin_unlock_irqrestore(&rspi->lock, flags);
+			break;
+		}
 		mesg = list_entry(rspi->queue.next, struct spi_message, queue);
 		list_del_init(&mesg->queue);
 		spin_unlock_irqrestore(&rspi->lock, flags);
@@ -595,8 +599,6 @@
 
 		mesg->status = 0;
 		mesg->complete(mesg->context);
-
-		spin_lock_irqsave(&rspi->lock, flags);
 	}
 
 	return;
@@ -664,12 +666,13 @@
 static int rspi_request_dma(struct rspi_data *rspi,
 				      struct platform_device *pdev)
 {
-	struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
+	struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	dma_cap_mask_t mask;
 	struct dma_slave_config cfg;
 	int ret;
 
-	if (!rspi_pd)
+	if (!res || !rspi_pd)
 		return 0;	/* The driver assumes no error. */
 
 	rspi->dma_width_16bit = rspi_pd->dma_width_16bit;
@@ -683,6 +686,8 @@
 		if (rspi->chan_rx) {
 			cfg.slave_id = rspi_pd->dma_rx_id;
 			cfg.direction = DMA_DEV_TO_MEM;
+			cfg.dst_addr = 0;
+			cfg.src_addr = res->start + RSPI_SPDR;
 			ret = dmaengine_slave_config(rspi->chan_rx, &cfg);
 			if (!ret)
 				dev_info(&pdev->dev, "Use DMA when rx.\n");
@@ -698,6 +703,8 @@
 		if (rspi->chan_tx) {
 			cfg.slave_id = rspi_pd->dma_tx_id;
 			cfg.direction = DMA_MEM_TO_DEV;
+			cfg.dst_addr = res->start + RSPI_SPDR;
+			cfg.src_addr = 0;
 			ret = dmaengine_slave_config(rspi->chan_tx, &cfg);
 			if (!ret)
 				dev_info(&pdev->dev, "Use DMA when tx\n");
@@ -719,7 +726,7 @@
 
 static int rspi_remove(struct platform_device *pdev)
 {
-	struct rspi_data *rspi = platform_get_drvdata(pdev);
+	struct rspi_data *rspi = spi_master_get(platform_get_drvdata(pdev));
 
 	spi_unregister_master(rspi->master);
 	rspi_release_dma(rspi);
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 68910b3..ce318d9 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -525,7 +525,7 @@
 	memset(hw, 0, sizeof(struct s3c24xx_spi));
 
 	hw->master = spi_master_get(master);
-	hw->pdata = pdata = pdev->dev.platform_data;
+	hw->pdata = pdata = dev_get_platdata(&pdev->dev);
 	hw->dev = &pdev->dev;
 
 	if (pdata == NULL) {
@@ -690,7 +690,7 @@
 
 static int s3c24xx_spi_suspend(struct device *dev)
 {
-	struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
+	struct s3c24xx_spi *hw = dev_get_drvdata(dev);
 
 	if (hw->pdata && hw->pdata->gpio_setup)
 		hw->pdata->gpio_setup(hw->pdata, 0);
@@ -701,7 +701,7 @@
 
 static int s3c24xx_spi_resume(struct device *dev)
 {
-	struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
+	struct s3c24xx_spi *hw = dev_get_drvdata(dev);
 
 	s3c24xx_spi_initialsetup(hw);
 	return 0;
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 63e2070..512b8893 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -172,7 +172,6 @@
  * @master: Pointer to the SPI Protocol master.
  * @cntrlr_info: Platform specific data for the controller this driver manages.
  * @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
- * @queue: To log SPI xfer requests.
  * @lock: Controller specific lock.
  * @state: Set of FLAGS to indicate status.
  * @rx_dmach: Controller's DMA channel for Rx.
@@ -193,7 +192,6 @@
 	struct spi_master               *master;
 	struct s3c64xx_spi_info  *cntrlr_info;
 	struct spi_device               *tgl_spi;
-	struct list_head                queue;
 	spinlock_t                      lock;
 	unsigned long                   sfr_start;
 	struct completion               xfer_completion;
@@ -338,8 +336,10 @@
 	req.cap = DMA_SLAVE;
 	req.client = &s3c64xx_spi_dma_client;
 
-	sdd->rx_dma.ch = (void *)sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
-	sdd->tx_dma.ch = (void *)sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
+	sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
+					sdd->rx_dma.dmach, &req, dev, "rx");
+	sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
+					sdd->tx_dma.dmach, &req, dev, "tx");
 
 	return 1;
 }
@@ -356,8 +356,6 @@
 	while (!is_polling(sdd) && !acquire_dma(sdd))
 		usleep_range(10000, 11000);
 
-	pm_runtime_get_sync(&sdd->pdev->dev);
-
 	return 0;
 }
 
@@ -372,7 +370,6 @@
 		sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
 					&s3c64xx_spi_dma_client);
 	}
-	pm_runtime_put(&sdd->pdev->dev);
 
 	return 0;
 }
@@ -389,9 +386,10 @@
 {
 	struct s3c64xx_spi_driver_data *sdd;
 	struct dma_slave_config config;
-	struct scatterlist sg;
 	struct dma_async_tx_descriptor *desc;
 
+	memset(&config, 0, sizeof(config));
+
 	if (dma->direction == DMA_DEV_TO_MEM) {
 		sdd = container_of((void *)dma,
 			struct s3c64xx_spi_driver_data, rx_dma);
@@ -410,14 +408,8 @@
 		dmaengine_slave_config(dma->ch, &config);
 	}
 
-	sg_init_table(&sg, 1);
-	sg_dma_len(&sg) = len;
-	sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
-		    len, offset_in_page(buf));
-	sg_dma_address(&sg) = buf;
-
-	desc = dmaengine_prep_slave_sg(dma->ch,
-		&sg, 1, dma->direction, DMA_PREP_INTERRUPT);
+	desc = dmaengine_prep_slave_single(dma->ch, buf, len,
+					dma->direction, DMA_PREP_INTERRUPT);
 
 	desc->callback = s3c64xx_spi_dmacb;
 	desc->callback_param = dma;
@@ -434,27 +426,26 @@
 	dma_cap_mask_t mask;
 	int ret;
 
-	if (is_polling(sdd))
-		return 0;
+	if (!is_polling(sdd)) {
+		dma_cap_zero(mask);
+		dma_cap_set(DMA_SLAVE, mask);
 
-	dma_cap_zero(mask);
-	dma_cap_set(DMA_SLAVE, mask);
+		/* Acquire DMA channels */
+		sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+				   (void *)sdd->rx_dma.dmach, dev, "rx");
+		if (!sdd->rx_dma.ch) {
+			dev_err(dev, "Failed to get RX DMA channel\n");
+			ret = -EBUSY;
+			goto out;
+		}
 
-	/* Acquire DMA channels */
-	sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
-				(void*)sdd->rx_dma.dmach, dev, "rx");
-	if (!sdd->rx_dma.ch) {
-		dev_err(dev, "Failed to get RX DMA channel\n");
-		ret = -EBUSY;
-		goto out;
-	}
-
-	sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
-				(void*)sdd->tx_dma.dmach, dev, "tx");
-	if (!sdd->tx_dma.ch) {
-		dev_err(dev, "Failed to get TX DMA channel\n");
-		ret = -EBUSY;
-		goto out_rx;
+		sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+				   (void *)sdd->tx_dma.dmach, dev, "tx");
+		if (!sdd->tx_dma.ch) {
+			dev_err(dev, "Failed to get TX DMA channel\n");
+			ret = -EBUSY;
+			goto out_rx;
+		}
 	}
 
 	ret = pm_runtime_get_sync(&sdd->pdev->dev);
@@ -1056,8 +1047,6 @@
 	struct s3c64xx_spi_csinfo *cs = spi->controller_data;
 	struct s3c64xx_spi_driver_data *sdd;
 	struct s3c64xx_spi_info *sci;
-	struct spi_message *msg;
-	unsigned long flags;
 	int err;
 
 	sdd = spi_master_get_devdata(spi->master);
@@ -1071,38 +1060,24 @@
 		return -ENODEV;
 	}
 
-	/* Request gpio only if cs line is asserted by gpio pins */
-	if (sdd->cs_gpio) {
-		err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
-				       dev_name(&spi->dev));
-		if (err) {
-			dev_err(&spi->dev,
-				"Failed to get /CS gpio [%d]: %d\n",
-				cs->line, err);
-			goto err_gpio_req;
+	if (!spi_get_ctldata(spi)) {
+		/* Request gpio only if cs line is asserted by gpio pins */
+		if (sdd->cs_gpio) {
+			err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
+					dev_name(&spi->dev));
+			if (err) {
+				dev_err(&spi->dev,
+					"Failed to get /CS gpio [%d]: %d\n",
+					cs->line, err);
+				goto err_gpio_req;
+			}
 		}
-	}
 
-	if (!spi_get_ctldata(spi))
 		spi_set_ctldata(spi, cs);
+	}
 
 	sci = sdd->cntrlr_info;
 
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	list_for_each_entry(msg, &sdd->queue, queue) {
-		/* Is some mssg is already queued for this device */
-		if (msg->spi == spi) {
-			dev_err(&spi->dev,
-				"setup: attempt while mssg in queue!\n");
-			spin_unlock_irqrestore(&sdd->lock, flags);
-			err = -EBUSY;
-			goto err_msgq;
-		}
-	}
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-
 	pm_runtime_get_sync(&sdd->pdev->dev);
 
 	/* Check if we can provide the requested rate */
@@ -1149,7 +1124,6 @@
 	/* setup() returns with device de-selected */
 	disable_cs(sdd, spi);
 
-err_msgq:
 	gpio_free(cs->line);
 	spi_set_ctldata(spi, NULL);
 
@@ -1275,7 +1249,7 @@
 #else
 static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
 {
-	return dev->platform_data;
+	return dev_get_platdata(dev);
 }
 #endif
 
@@ -1300,7 +1274,7 @@
 	struct resource	*mem_res;
 	struct resource	*res;
 	struct s3c64xx_spi_driver_data *sdd;
-	struct s3c64xx_spi_info *sci = pdev->dev.platform_data;
+	struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev);
 	struct spi_master *master;
 	int ret, irq;
 	char clk_name[16];
@@ -1364,16 +1338,14 @@
 	if (!sdd->pdev->dev.of_node) {
 		res = platform_get_resource(pdev, IORESOURCE_DMA,  0);
 		if (!res) {
-			dev_warn(&pdev->dev, "Unable to get SPI tx dma "
-					"resource. Switching to poll mode\n");
+			dev_warn(&pdev->dev, "Unable to get SPI tx dma resource. Switching to poll mode\n");
 			sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
 		} else
 			sdd->tx_dma.dmach = res->start;
 
 		res = platform_get_resource(pdev, IORESOURCE_DMA,  1);
 		if (!res) {
-			dev_warn(&pdev->dev, "Unable to get SPI rx dma "
-					"resource. Switching to poll mode\n");
+			dev_warn(&pdev->dev, "Unable to get SPI rx dma resource. Switching to poll mode\n");
 			sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
 		} else
 			sdd->rx_dma.dmach = res->start;
@@ -1395,6 +1367,7 @@
 					SPI_BPW_MASK(8);
 	/* the spi->mode bits understood by this driver: */
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+	master->auto_runtime_pm = true;
 
 	sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
 	if (IS_ERR(sdd->regs)) {
@@ -1442,7 +1415,6 @@
 
 	spin_lock_init(&sdd->lock);
 	init_completion(&sdd->xfer_completion);
-	INIT_LIST_HEAD(&sdd->queue);
 
 	ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
 				"spi-s3c64xx", sdd);
@@ -1464,8 +1436,8 @@
 
 	dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
 					sdd->port_id, master->num_chipselect);
-	dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
-					mem_res->end, mem_res->start,
+	dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tDMA=[Rx-%d, Tx-%d]\n",
+					mem_res,
 					sdd->rx_dma.dmach, sdd->tx_dma.dmach);
 
 	pm_runtime_enable(&pdev->dev);
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 716edf9..0b68cb5 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -99,21 +99,6 @@
 /*
  *		spi master function
  */
-static int hspi_prepare_transfer(struct spi_master *master)
-{
-	struct hspi_priv *hspi = spi_master_get_devdata(master);
-
-	pm_runtime_get_sync(hspi->dev);
-	return 0;
-}
-
-static int hspi_unprepare_transfer(struct spi_master *master)
-{
-	struct hspi_priv *hspi = spi_master_get_devdata(master);
-
-	pm_runtime_put_sync(hspi->dev);
-	return 0;
-}
 
 #define hspi_hw_cs_enable(hspi)		hspi_hw_cs_ctrl(hspi, 0)
 #define hspi_hw_cs_disable(hspi)	hspi_hw_cs_ctrl(hspi, 1)
@@ -316,9 +301,8 @@
 	master->setup		= hspi_setup;
 	master->cleanup		= hspi_cleanup;
 	master->mode_bits	= SPI_CPOL | SPI_CPHA;
-	master->prepare_transfer_hardware	= hspi_prepare_transfer;
+	master->auto_runtime_pm = true;
 	master->transfer_one_message		= hspi_transfer_one_message;
-	master->unprepare_transfer_hardware	= hspi_unprepare_transfer;
 	ret = spi_register_master(master);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "spi_register_master error.\n");
@@ -327,8 +311,6 @@
 
 	pm_runtime_enable(&pdev->dev);
 
-	dev_info(&pdev->dev, "probed\n");
-
 	return 0;
 
  error1:
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 2bc5a6b..2a95435 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -645,7 +645,7 @@
 	if (pdev->dev.of_node)
 		p->info = sh_msiof_spi_parse_dt(&pdev->dev);
 	else
-		p->info = pdev->dev.platform_data;
+		p->info = dev_get_platdata(&pdev->dev);
 
 	if (!p->info) {
 		dev_err(&pdev->dev, "failed to obtain device info\n");
@@ -745,18 +745,6 @@
 	return ret;
 }
 
-static int sh_msiof_spi_runtime_nop(struct device *dev)
-{
-	/* Runtime PM callback shared between ->runtime_suspend()
-	 * and ->runtime_resume(). Simply returns success.
-	 *
-	 * This driver re-initializes all registers after
-	 * pm_runtime_get_sync() anyway so there is no need
-	 * to save and restore registers here.
-	 */
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id sh_msiof_match[] = {
 	{ .compatible = "renesas,sh-msiof", },
@@ -766,18 +754,12 @@
 MODULE_DEVICE_TABLE(of, sh_msiof_match);
 #endif
 
-static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
-	.runtime_suspend = sh_msiof_spi_runtime_nop,
-	.runtime_resume = sh_msiof_spi_runtime_nop,
-};
-
 static struct platform_driver sh_msiof_spi_drv = {
 	.probe		= sh_msiof_spi_probe,
 	.remove		= sh_msiof_spi_remove,
 	.driver		= {
 		.name		= "spi_sh_msiof",
 		.owner		= THIS_MODULE,
-		.pm		= &sh_msiof_spi_dev_pm_ops,
 		.of_match_table = of_match_ptr(sh_msiof_match),
 	},
 };
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 097e5060..8eefeb6 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -130,7 +130,7 @@
 	sp = spi_master_get_devdata(master);
 
 	platform_set_drvdata(dev, sp);
-	sp->info = dev->dev.platform_data;
+	sp->info = dev_get_platdata(&dev->dev);
 
 	/* setup spi bitbang adaptor */
 	sp->bitbang.master = spi_master_get(master);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index fc20bcf..a1f21b7 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -19,6 +19,10 @@
 #include <linux/of_gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/sirfsoc_dma.h>
 
 #define DRIVER_NAME "sirfsoc_spi"
 
@@ -119,9 +123,19 @@
 #define SIRFSOC_SPI_FIFO_HC(x)		(((x) & 0x3F) << 20)
 #define SIRFSOC_SPI_FIFO_THD(x)		(((x) & 0xFF) << 2)
 
+/*
+ * only if the rx/tx buffer and transfer size are 4-bytes aligned, we use dma
+ * due to the limitation of dma controller
+ */
+
+#define ALIGNED(x) (!((u32)x & 0x3))
+#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
+	ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
+
 struct sirfsoc_spi {
 	struct spi_bitbang bitbang;
-	struct completion done;
+	struct completion rx_done;
+	struct completion tx_done;
 
 	void __iomem *base;
 	u32 ctrl_freq;  /* SPI controller clock speed */
@@ -137,8 +151,16 @@
 	void (*tx_word) (struct sirfsoc_spi *);
 
 	/* number of words left to be tranmitted/received */
-	unsigned int left_tx_cnt;
-	unsigned int left_rx_cnt;
+	unsigned int left_tx_word;
+	unsigned int left_rx_word;
+
+	/* rx & tx DMA channels */
+	struct dma_chan *rx_chan;
+	struct dma_chan *tx_chan;
+	dma_addr_t src_start;
+	dma_addr_t dst_start;
+	void *dummypage;
+	int word_width; /* in bytes */
 
 	int chipselect[0];
 };
@@ -155,7 +177,7 @@
 		sspi->rx = rx;
 	}
 
-	sspi->left_rx_cnt--;
+	sspi->left_rx_word--;
 }
 
 static void spi_sirfsoc_tx_word_u8(struct sirfsoc_spi *sspi)
@@ -169,7 +191,7 @@
 	}
 
 	writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA);
-	sspi->left_tx_cnt--;
+	sspi->left_tx_word--;
 }
 
 static void spi_sirfsoc_rx_word_u16(struct sirfsoc_spi *sspi)
@@ -184,7 +206,7 @@
 		sspi->rx = rx;
 	}
 
-	sspi->left_rx_cnt--;
+	sspi->left_rx_word--;
 }
 
 static void spi_sirfsoc_tx_word_u16(struct sirfsoc_spi *sspi)
@@ -198,7 +220,7 @@
 	}
 
 	writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA);
-	sspi->left_tx_cnt--;
+	sspi->left_tx_word--;
 }
 
 static void spi_sirfsoc_rx_word_u32(struct sirfsoc_spi *sspi)
@@ -213,7 +235,7 @@
 		sspi->rx = rx;
 	}
 
-	sspi->left_rx_cnt--;
+	sspi->left_rx_word--;
 
 }
 
@@ -228,7 +250,7 @@
 	}
 
 	writel(data, sspi->base + SIRFSOC_SPI_TXFIFO_DATA);
-	sspi->left_tx_cnt--;
+	sspi->left_tx_word--;
 }
 
 static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
@@ -241,7 +263,7 @@
 	/* Error Conditions */
 	if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
 			spi_stat & SIRFSOC_SPI_TX_UFLOW) {
-		complete(&sspi->done);
+		complete(&sspi->rx_done);
 		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
 	}
 
@@ -249,50 +271,61 @@
 			| SIRFSOC_SPI_RXFIFO_THD_REACH))
 		while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
 				& SIRFSOC_SPI_FIFO_EMPTY)) &&
-				sspi->left_rx_cnt)
+				sspi->left_rx_word)
 			sspi->rx_word(sspi);
 
 	if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY
 			| SIRFSOC_SPI_TXFIFO_THD_REACH))
 		while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
 				& SIRFSOC_SPI_FIFO_FULL)) &&
-				sspi->left_tx_cnt)
+				sspi->left_tx_word)
 			sspi->tx_word(sspi);
 
 	/* Received all words */
-	if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
-		complete(&sspi->done);
+	if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) {
+		complete(&sspi->rx_done);
 		writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
 	}
 	return IRQ_HANDLED;
 }
 
+static void spi_sirfsoc_dma_fini_callback(void *data)
+{
+	struct completion *dma_complete = data;
+
+	complete(dma_complete);
+}
+
 static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
 {
 	struct sirfsoc_spi *sspi;
 	int timeout = t->len * 10;
 	sspi = spi_master_get_devdata(spi->master);
 
-	sspi->tx = t->tx_buf;
-	sspi->rx = t->rx_buf;
-	sspi->left_tx_cnt = sspi->left_rx_cnt = t->len;
-	INIT_COMPLETION(sspi->done);
+	sspi->tx = t->tx_buf ? t->tx_buf : sspi->dummypage;
+	sspi->rx = t->rx_buf ? t->rx_buf : sspi->dummypage;
+	sspi->left_tx_word = sspi->left_rx_word = t->len / sspi->word_width;
+	INIT_COMPLETION(sspi->rx_done);
+	INIT_COMPLETION(sspi->tx_done);
 
 	writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
 
-	if (t->len == 1) {
+	if (sspi->left_tx_word == 1) {
 		writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
 			SIRFSOC_SPI_ENA_AUTO_CLR,
 			sspi->base + SIRFSOC_SPI_CTRL);
 		writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
 		writel(0, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
-	} else if ((t->len > 1) && (t->len < SIRFSOC_SPI_DAT_FRM_LEN_MAX)) {
+	} else if ((sspi->left_tx_word > 1) && (sspi->left_tx_word <
+				SIRFSOC_SPI_DAT_FRM_LEN_MAX)) {
 		writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
 				SIRFSOC_SPI_MUL_DAT_MODE |
 				SIRFSOC_SPI_ENA_AUTO_CLR,
 			sspi->base + SIRFSOC_SPI_CTRL);
-		writel(t->len - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
-		writel(t->len - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
+		writel(sspi->left_tx_word - 1,
+				sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
+		writel(sspi->left_tx_word - 1,
+				sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
 	} else {
 		writel(readl(sspi->base + SIRFSOC_SPI_CTRL),
 			sspi->base + SIRFSOC_SPI_CTRL);
@@ -305,17 +338,64 @@
 	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
 	writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
 
-	/* Send the first word to trigger the whole tx/rx process */
-	sspi->tx_word(sspi);
+	if (IS_DMA_VALID(t)) {
+		struct dma_async_tx_descriptor *rx_desc, *tx_desc;
 
-	writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
-		SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN |
-		SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN |
-		SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN);
+		sspi->dst_start = dma_map_single(&spi->dev, sspi->rx, t->len, DMA_FROM_DEVICE);
+		rx_desc = dmaengine_prep_slave_single(sspi->rx_chan,
+			sspi->dst_start, t->len, DMA_DEV_TO_MEM,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		rx_desc->callback = spi_sirfsoc_dma_fini_callback;
+		rx_desc->callback_param = &sspi->rx_done;
+
+		sspi->src_start = dma_map_single(&spi->dev, (void *)sspi->tx, t->len, DMA_TO_DEVICE);
+		tx_desc = dmaengine_prep_slave_single(sspi->tx_chan,
+			sspi->src_start, t->len, DMA_MEM_TO_DEV,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		tx_desc->callback = spi_sirfsoc_dma_fini_callback;
+		tx_desc->callback_param = &sspi->tx_done;
+
+		dmaengine_submit(tx_desc);
+		dmaengine_submit(rx_desc);
+		dma_async_issue_pending(sspi->tx_chan);
+		dma_async_issue_pending(sspi->rx_chan);
+	} else {
+		/* Send the first word to trigger the whole tx/rx process */
+		sspi->tx_word(sspi);
+
+		writel(SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
+			SIRFSOC_SPI_RXFIFO_THD_INT_EN | SIRFSOC_SPI_TXFIFO_THD_INT_EN |
+			SIRFSOC_SPI_FRM_END_INT_EN | SIRFSOC_SPI_RXFIFO_FULL_INT_EN |
+			SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN, sspi->base + SIRFSOC_SPI_INT_EN);
+	}
+
 	writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN, sspi->base + SIRFSOC_SPI_TX_RX_EN);
 
-	if (wait_for_completion_timeout(&sspi->done, timeout) == 0)
+	if (!IS_DMA_VALID(t)) { /* for PIO */
+		if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0)
+			dev_err(&spi->dev, "transfer timeout\n");
+	} else if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0) {
 		dev_err(&spi->dev, "transfer timeout\n");
+		dmaengine_terminate_all(sspi->rx_chan);
+	} else
+		sspi->left_rx_word = 0;
+
+	/*
+	 * we only wait tx-done event if transferring by DMA. for PIO,
+	 * we get rx data by writing tx data, so if rx is done, tx has
+	 * done earlier
+	 */
+	if (IS_DMA_VALID(t)) {
+		if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
+			dev_err(&spi->dev, "transfer timeout\n");
+			dmaengine_terminate_all(sspi->tx_chan);
+		}
+	}
+
+	if (IS_DMA_VALID(t)) {
+		dma_unmap_single(&spi->dev, sspi->src_start, t->len, DMA_TO_DEVICE);
+		dma_unmap_single(&spi->dev, sspi->dst_start, t->len, DMA_FROM_DEVICE);
+	}
 
 	/* TX, RX FIFO stop */
 	writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
@@ -323,7 +403,7 @@
 	writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN);
 	writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
 
-	return t->len - sspi->left_rx_cnt;
+	return t->len - sspi->left_rx_word * sspi->word_width;
 }
 
 static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
@@ -332,7 +412,6 @@
 
 	if (sspi->chipselect[spi->chip_select] == 0) {
 		u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL);
-		regval |= SIRFSOC_SPI_CS_IO_OUT;
 		switch (value) {
 		case BITBANG_CS_ACTIVE:
 			if (spi->mode & SPI_CS_HIGH)
@@ -369,11 +448,7 @@
 	bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
 	hz = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz;
 
-	/* Enable IO mode for RX, TX */
-	writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL);
-	writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);
 	regval = (sspi->ctrl_freq / (2 * hz)) - 1;
-
 	if (regval > 0xFFFF || regval < 0) {
 		dev_err(&spi->dev, "Speed %d not supported\n", hz);
 		return -EINVAL;
@@ -388,6 +463,7 @@
 					SIRFSOC_SPI_FIFO_WIDTH_BYTE;
 		rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
 					SIRFSOC_SPI_FIFO_WIDTH_BYTE;
+		sspi->word_width = 1;
 		break;
 	case 12:
 	case 16:
@@ -399,6 +475,7 @@
 					SIRFSOC_SPI_FIFO_WIDTH_WORD;
 		rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
 					SIRFSOC_SPI_FIFO_WIDTH_WORD;
+		sspi->word_width = 2;
 		break;
 	case 32:
 		regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
@@ -408,6 +485,7 @@
 					SIRFSOC_SPI_FIFO_WIDTH_DWORD;
 		rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
 					SIRFSOC_SPI_FIFO_WIDTH_DWORD;
+		sspi->word_width = 4;
 		break;
 	default:
 		BUG();
@@ -442,6 +520,17 @@
 	writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
 
 	writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
+
+	if (IS_DMA_VALID(t)) {
+		/* Enable DMA mode for RX, TX */
+		writel(0, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL);
+		writel(SIRFSOC_SPI_RX_DMA_FLUSH, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);
+	} else {
+		/* Enable IO mode for RX, TX */
+		writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_TX_DMA_IO_CTRL);
+		writel(SIRFSOC_SPI_IO_MODE_SEL, sspi->base + SIRFSOC_SPI_RX_DMA_IO_CTRL);
+	}
+
 	return 0;
 }
 
@@ -466,6 +555,8 @@
 	struct spi_master *master;
 	struct resource *mem_res;
 	int num_cs, cs_gpio, irq;
+	u32 rx_dma_ch, tx_dma_ch;
+	dma_cap_mask_t dma_cap_mask;
 	int i;
 	int ret;
 
@@ -476,6 +567,20 @@
 		goto err_cs;
 	}
 
+	ret = of_property_read_u32(pdev->dev.of_node,
+			"sirf,spi-dma-rx-channel", &rx_dma_ch);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to get rx dma channel\n");
+		goto err_cs;
+	}
+
+	ret = of_property_read_u32(pdev->dev.of_node,
+			"sirf,spi-dma-tx-channel", &tx_dma_ch);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to get tx dma channel\n");
+		goto err_cs;
+	}
+
 	master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
 	if (!master) {
 		dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -484,12 +589,6 @@
 	platform_set_drvdata(pdev, master);
 	sspi = spi_master_get_devdata(master);
 
-	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res) {
-		dev_err(&pdev->dev, "Unable to get IO resource\n");
-		ret = -ENODEV;
-		goto free_master;
-	}
 	master->num_chipselect = num_cs;
 
 	for (i = 0; i < master->num_chipselect; i++) {
@@ -516,6 +615,7 @@
 		}
 	}
 
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
 	if (IS_ERR(sspi->base)) {
 		ret = PTR_ERR(sspi->base);
@@ -538,19 +638,40 @@
 	sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
 	sspi->bitbang.master->setup = spi_sirfsoc_setup;
 	master->bus_num = pdev->id;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
 	master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
 					SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
 	sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
 
+	/* request DMA channels */
+	dma_cap_zero(dma_cap_mask);
+	dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
+
+	sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
+		(void *)rx_dma_ch);
+	if (!sspi->rx_chan) {
+		dev_err(&pdev->dev, "can not allocate rx dma channel\n");
+		ret = -ENODEV;
+		goto free_master;
+	}
+	sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
+		(void *)tx_dma_ch);
+	if (!sspi->tx_chan) {
+		dev_err(&pdev->dev, "can not allocate tx dma channel\n");
+		ret = -ENODEV;
+		goto free_rx_dma;
+	}
+
 	sspi->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(sspi->clk)) {
-		ret = -EINVAL;
-		goto free_master;
+		ret = PTR_ERR(sspi->clk);
+		goto free_tx_dma;
 	}
 	clk_prepare_enable(sspi->clk);
 	sspi->ctrl_freq = clk_get_rate(sspi->clk);
 
-	init_completion(&sspi->done);
+	init_completion(&sspi->rx_done);
+	init_completion(&sspi->tx_done);
 
 	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
 	writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
@@ -559,17 +680,28 @@
 	/* We are not using dummy delay between command and data */
 	writel(0, sspi->base + SIRFSOC_SPI_DUMMY_DELAY_CTL);
 
+	sspi->dummypage = kmalloc(2 * PAGE_SIZE, GFP_KERNEL);
+	if (!sspi->dummypage) {
+		ret = -ENOMEM;
+		goto free_clk;
+	}
+
 	ret = spi_bitbang_start(&sspi->bitbang);
 	if (ret)
-		goto free_clk;
+		goto free_dummypage;
 
 	dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
 
 	return 0;
-
+free_dummypage:
+	kfree(sspi->dummypage);
 free_clk:
 	clk_disable_unprepare(sspi->clk);
 	clk_put(sspi->clk);
+free_tx_dma:
+	dma_release_channel(sspi->tx_chan);
+free_rx_dma:
+	dma_release_channel(sspi->rx_chan);
 free_master:
 	spi_master_put(master);
 err_cs:
@@ -590,8 +722,11 @@
 		if (sspi->chipselect[i] > 0)
 			gpio_free(sspi->chipselect[i]);
 	}
+	kfree(sspi->dummypage);
 	clk_disable_unprepare(sspi->clk);
 	clk_put(sspi->clk);
+	dma_release_channel(sspi->rx_chan);
+	dma_release_channel(sspi->tx_chan);
 	spi_master_put(master);
 	return 0;
 }
@@ -599,8 +734,7 @@
 #ifdef CONFIG_PM
 static int spi_sirfsoc_suspend(struct device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct spi_master *master = platform_get_drvdata(pdev);
+	struct spi_master *master = dev_get_drvdata(dev);
 	struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
 
 	clk_disable(sspi->clk);
@@ -609,8 +743,7 @@
 
 static int spi_sirfsoc_resume(struct device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct spi_master *master = platform_get_drvdata(pdev);
+	struct spi_master *master = dev_get_drvdata(dev);
 	struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
 
 	clk_enable(sspi->clk);
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index e8f542a..145dd43 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -816,14 +816,6 @@
 	msg->status = 0;
 	msg->actual_length = 0;
 
-	ret = pm_runtime_get_sync(tspi->dev);
-	if (ret < 0) {
-		dev_err(tspi->dev, "runtime PM get failed: %d\n", ret);
-		msg->status = ret;
-		spi_finalize_current_message(master);
-		return ret;
-	}
-
 	single_xfer = list_is_singular(&msg->transfers);
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 		INIT_COMPLETION(tspi->xfer_completion);
@@ -859,7 +851,6 @@
 	ret = 0;
 exit:
 	tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
-	pm_runtime_put(tspi->dev);
 	msg->status = ret;
 	spi_finalize_current_message(master);
 	return ret;
@@ -1053,24 +1044,19 @@
 	master->transfer_one_message = tegra_spi_transfer_one_message;
 	master->num_chipselect = MAX_CHIP_SELECT;
 	master->bus_num = -1;
+	master->auto_runtime_pm = true;
 
 	tspi->master = master;
 	tspi->dev = &pdev->dev;
 	spin_lock_init(&tspi->lock);
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r) {
-		dev_err(&pdev->dev, "No IO memory resource\n");
-		ret = -ENODEV;
-		goto exit_free_master;
-	}
-	tspi->phys = r->start;
 	tspi->base = devm_ioremap_resource(&pdev->dev, r);
 	if (IS_ERR(tspi->base)) {
 		ret = PTR_ERR(tspi->base);
-		dev_err(&pdev->dev, "ioremap failed: err = %d\n", ret);
 		goto exit_free_master;
 	}
+	tspi->phys = r->start;
 
 	spi_irq = platform_get_irq(pdev, 0);
 	tspi->irq = spi_irq;
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index c1d5d95..1d814dc 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -335,12 +335,6 @@
 	struct spi_device *spi = msg->spi;
 	int ret;
 
-	ret = pm_runtime_get_sync(tsd->dev);
-	if (ret < 0) {
-		dev_err(tsd->dev, "pm_runtime_get() failed, err = %d\n", ret);
-		return ret;
-	}
-
 	msg->status = 0;
 	msg->actual_length = 0;
 	single_xfer = list_is_singular(&msg->transfers);
@@ -380,7 +374,6 @@
 	tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
 	msg->status = ret;
 	spi_finalize_current_message(master);
-	pm_runtime_put(tsd->dev);
 	return ret;
 }
 
@@ -477,6 +470,7 @@
 	master->mode_bits = SPI_CPOL | SPI_CPHA;
 	master->setup = tegra_sflash_setup;
 	master->transfer_one_message = tegra_sflash_transfer_one_message;
+	master->auto_runtime_pm = true;
 	master->num_chipselect = MAX_CHIP_SELECT;
 	master->bus_num = -1;
 
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index 80490cc..c703536 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -836,11 +836,6 @@
 
 	msg->status = 0;
 	msg->actual_length = 0;
-	ret = pm_runtime_get_sync(tspi->dev);
-	if (ret < 0) {
-		dev_err(tspi->dev, "runtime get failed: %d\n", ret);
-		goto done;
-	}
 
 	single_xfer = list_is_singular(&msg->transfers);
 	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
@@ -878,8 +873,6 @@
 exit:
 	tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
 	tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
-	pm_runtime_put(tspi->dev);
-done:
 	msg->status = ret;
 	spi_finalize_current_message(master);
 	return ret;
@@ -1086,6 +1079,7 @@
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 	master->setup = tegra_slink_setup;
 	master->transfer_one_message = tegra_slink_transfer_one_message;
+	master->auto_runtime_pm = true;
 	master->num_chipselect = MAX_CHIP_SELECT;
 	master->bus_num = -1;
 
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
new file mode 100644
index 0000000..e12d962
--- /dev/null
+++ b/drivers/spi/spi-ti-qspi.c
@@ -0,0 +1,574 @@
+/*
+ * TI QSPI driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Sourav Poddar <sourav.poddar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GPLv2.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/spi/spi.h>
+
+struct ti_qspi_regs {
+	u32 clkctrl;
+};
+
+struct ti_qspi {
+	struct completion       transfer_complete;
+
+	/* IRQ synchronization */
+	spinlock_t              lock;
+
+	/* list synchronization */
+	struct mutex            list_lock;
+
+	struct spi_master	*master;
+	void __iomem            *base;
+	struct clk		*fclk;
+	struct device           *dev;
+
+	struct ti_qspi_regs     ctx_reg;
+
+	u32 spi_max_frequency;
+	u32 cmd;
+	u32 dc;
+	u32 stat;
+};
+
+#define QSPI_PID			(0x0)
+#define QSPI_SYSCONFIG			(0x10)
+#define QSPI_INTR_STATUS_RAW_SET	(0x20)
+#define QSPI_INTR_STATUS_ENABLED_CLEAR	(0x24)
+#define QSPI_INTR_ENABLE_SET_REG	(0x28)
+#define QSPI_INTR_ENABLE_CLEAR_REG	(0x2c)
+#define QSPI_SPI_CLOCK_CNTRL_REG	(0x40)
+#define QSPI_SPI_DC_REG			(0x44)
+#define QSPI_SPI_CMD_REG		(0x48)
+#define QSPI_SPI_STATUS_REG		(0x4c)
+#define QSPI_SPI_DATA_REG		(0x50)
+#define QSPI_SPI_SETUP0_REG		(0x54)
+#define QSPI_SPI_SWITCH_REG		(0x64)
+#define QSPI_SPI_SETUP1_REG		(0x58)
+#define QSPI_SPI_SETUP2_REG		(0x5c)
+#define QSPI_SPI_SETUP3_REG		(0x60)
+#define QSPI_SPI_DATA_REG_1		(0x68)
+#define QSPI_SPI_DATA_REG_2		(0x6c)
+#define QSPI_SPI_DATA_REG_3		(0x70)
+
+#define QSPI_COMPLETION_TIMEOUT		msecs_to_jiffies(2000)
+
+#define QSPI_FCLK			192000000
+
+/* Clock Control */
+#define QSPI_CLK_EN			(1 << 31)
+#define QSPI_CLK_DIV_MAX		0xffff
+
+/* Command */
+#define QSPI_EN_CS(n)			(n << 28)
+#define QSPI_WLEN(n)			((n - 1) << 19)
+#define QSPI_3_PIN			(1 << 18)
+#define QSPI_RD_SNGL			(1 << 16)
+#define QSPI_WR_SNGL			(2 << 16)
+#define QSPI_RD_DUAL			(3 << 16)
+#define QSPI_RD_QUAD			(7 << 16)
+#define QSPI_INVAL			(4 << 16)
+#define QSPI_WC_CMD_INT_EN			(1 << 14)
+#define QSPI_FLEN(n)			((n - 1) << 0)
+
+/* STATUS REGISTER */
+#define WC				0x02
+
+/* INTERRUPT REGISTER */
+#define QSPI_WC_INT_EN				(1 << 1)
+#define QSPI_WC_INT_DISABLE			(1 << 1)
+
+/* Device Control */
+#define QSPI_DD(m, n)			(m << (3 + n * 8))
+#define QSPI_CKPHA(n)			(1 << (2 + n * 8))
+#define QSPI_CSPOL(n)			(1 << (1 + n * 8))
+#define QSPI_CKPOL(n)			(1 << (n * 8))
+
+#define	QSPI_FRAME			4096
+
+#define QSPI_AUTOSUSPEND_TIMEOUT         2000
+
+static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
+		unsigned long reg)
+{
+	return readl(qspi->base + reg);
+}
+
+static inline void ti_qspi_write(struct ti_qspi *qspi,
+		unsigned long val, unsigned long reg)
+{
+	writel(val, qspi->base + reg);
+}
+
+static int ti_qspi_setup(struct spi_device *spi)
+{
+	struct ti_qspi	*qspi = spi_master_get_devdata(spi->master);
+	struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
+	int clk_div = 0, ret;
+	u32 clk_ctrl_reg, clk_rate, clk_mask;
+
+	if (spi->master->busy) {
+		dev_dbg(qspi->dev, "master busy doing other trasnfers\n");
+		return -EBUSY;
+	}
+
+	if (!qspi->spi_max_frequency) {
+		dev_err(qspi->dev, "spi max frequency not defined\n");
+		return -EINVAL;
+	}
+
+	clk_rate = clk_get_rate(qspi->fclk);
+
+	clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1;
+
+	if (clk_div < 0) {
+		dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n");
+		return -EINVAL;
+	}
+
+	if (clk_div > QSPI_CLK_DIV_MAX) {
+		dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n",
+				QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
+		return -EINVAL;
+	}
+
+	dev_dbg(qspi->dev, "hz: %d, clock divider %d\n",
+			qspi->spi_max_frequency, clk_div);
+
+	ret = pm_runtime_get_sync(qspi->dev);
+	if (ret) {
+		dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
+		return ret;
+	}
+
+	clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
+
+	clk_ctrl_reg &= ~QSPI_CLK_EN;
+
+	/* disable SCLK */
+	ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
+
+	/* enable SCLK */
+	clk_mask = QSPI_CLK_EN | clk_div;
+	ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG);
+	ctx_reg->clkctrl = clk_mask;
+
+	pm_runtime_mark_last_busy(qspi->dev);
+	ret = pm_runtime_put_autosuspend(qspi->dev);
+	if (ret < 0) {
+		dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
+{
+	struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
+
+	ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
+}
+
+static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+{
+	int wlen, count, ret;
+	unsigned int cmd;
+	const u8 *txbuf;
+
+	txbuf = t->tx_buf;
+	cmd = qspi->cmd | QSPI_WR_SNGL;
+	count = t->len;
+	wlen = t->bits_per_word;
+
+	while (count) {
+		switch (wlen) {
+		case 8:
+			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
+					cmd, qspi->dc, *txbuf);
+			writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
+			ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+			ret = wait_for_completion_timeout(&qspi->transfer_complete,
+					QSPI_COMPLETION_TIMEOUT);
+			if (ret == 0) {
+				dev_err(qspi->dev, "write timed out\n");
+				return -ETIMEDOUT;
+			}
+			txbuf += 1;
+			count -= 1;
+			break;
+		case 16:
+			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
+					cmd, qspi->dc, *txbuf);
+			writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
+			ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+			ret = wait_for_completion_timeout(&qspi->transfer_complete,
+				QSPI_COMPLETION_TIMEOUT);
+			if (ret == 0) {
+				dev_err(qspi->dev, "write timed out\n");
+				return -ETIMEDOUT;
+			}
+			txbuf += 2;
+			count -= 2;
+			break;
+		case 32:
+			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n",
+					cmd, qspi->dc, *txbuf);
+			writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
+			ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+			ret = wait_for_completion_timeout(&qspi->transfer_complete,
+				QSPI_COMPLETION_TIMEOUT);
+			if (ret == 0) {
+				dev_err(qspi->dev, "write timed out\n");
+				return -ETIMEDOUT;
+			}
+			txbuf += 4;
+			count -= 4;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+{
+	int wlen, count, ret;
+	unsigned int cmd;
+	u8 *rxbuf;
+
+	rxbuf = t->rx_buf;
+	cmd = qspi->cmd;
+	switch (t->rx_nbits) {
+	case SPI_NBITS_DUAL:
+		cmd |= QSPI_RD_DUAL;
+		break;
+	case SPI_NBITS_QUAD:
+		cmd |= QSPI_RD_QUAD;
+		break;
+	default:
+		cmd |= QSPI_RD_SNGL;
+		break;
+	}
+	count = t->len;
+	wlen = t->bits_per_word;
+
+	while (count) {
+		dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
+		ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
+		ret = wait_for_completion_timeout(&qspi->transfer_complete,
+				QSPI_COMPLETION_TIMEOUT);
+		if (ret == 0) {
+			dev_err(qspi->dev, "read timed out\n");
+			return -ETIMEDOUT;
+		}
+		switch (wlen) {
+		case 8:
+			*rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG);
+			rxbuf += 1;
+			count -= 1;
+			break;
+		case 16:
+			*((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG);
+			rxbuf += 2;
+			count -= 2;
+			break;
+		case 32:
+			*((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG);
+			rxbuf += 4;
+			count -= 4;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t)
+{
+	int ret;
+
+	if (t->tx_buf) {
+		ret = qspi_write_msg(qspi, t);
+		if (ret) {
+			dev_dbg(qspi->dev, "Error while writing\n");
+			return ret;
+		}
+	}
+
+	if (t->rx_buf) {
+		ret = qspi_read_msg(qspi, t);
+		if (ret) {
+			dev_dbg(qspi->dev, "Error while reading\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int ti_qspi_start_transfer_one(struct spi_master *master,
+		struct spi_message *m)
+{
+	struct ti_qspi *qspi = spi_master_get_devdata(master);
+	struct spi_device *spi = m->spi;
+	struct spi_transfer *t;
+	int status = 0, ret;
+	int frame_length;
+
+	/* setup device control reg */
+	qspi->dc = 0;
+
+	if (spi->mode & SPI_CPHA)
+		qspi->dc |= QSPI_CKPHA(spi->chip_select);
+	if (spi->mode & SPI_CPOL)
+		qspi->dc |= QSPI_CKPOL(spi->chip_select);
+	if (spi->mode & SPI_CS_HIGH)
+		qspi->dc |= QSPI_CSPOL(spi->chip_select);
+
+	frame_length = (m->frame_length << 3) / spi->bits_per_word;
+
+	frame_length = clamp(frame_length, 0, QSPI_FRAME);
+
+	/* setup command reg */
+	qspi->cmd = 0;
+	qspi->cmd |= QSPI_EN_CS(spi->chip_select);
+	qspi->cmd |= QSPI_FLEN(frame_length);
+	qspi->cmd |= QSPI_WC_CMD_INT_EN;
+
+	ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG);
+	ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG);
+
+	mutex_lock(&qspi->list_lock);
+
+	list_for_each_entry(t, &m->transfers, transfer_list) {
+		qspi->cmd |= QSPI_WLEN(t->bits_per_word);
+
+		ret = qspi_transfer_msg(qspi, t);
+		if (ret) {
+			dev_dbg(qspi->dev, "transfer message failed\n");
+			mutex_unlock(&qspi->list_lock);
+			return -EINVAL;
+		}
+
+		m->actual_length += t->len;
+	}
+
+	mutex_unlock(&qspi->list_lock);
+
+	m->status = status;
+	spi_finalize_current_message(master);
+
+	ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
+
+	return status;
+}
+
+static irqreturn_t ti_qspi_isr(int irq, void *dev_id)
+{
+	struct ti_qspi *qspi = dev_id;
+	u16 int_stat;
+
+	irqreturn_t ret = IRQ_HANDLED;
+
+	spin_lock(&qspi->lock);
+
+	int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR);
+	qspi->stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
+
+	if (!int_stat) {
+		dev_dbg(qspi->dev, "No IRQ triggered\n");
+		ret = IRQ_NONE;
+		goto out;
+	}
+
+	ret = IRQ_WAKE_THREAD;
+
+	ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG);
+	ti_qspi_write(qspi, QSPI_WC_INT_DISABLE,
+				QSPI_INTR_STATUS_ENABLED_CLEAR);
+
+out:
+	spin_unlock(&qspi->lock);
+
+	return ret;
+}
+
+static irqreturn_t ti_qspi_threaded_isr(int this_irq, void *dev_id)
+{
+	struct ti_qspi *qspi = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qspi->lock, flags);
+
+	if (qspi->stat & WC)
+		complete(&qspi->transfer_complete);
+
+	spin_unlock_irqrestore(&qspi->lock, flags);
+
+	ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG);
+
+	return IRQ_HANDLED;
+}
+
+static int ti_qspi_runtime_resume(struct device *dev)
+{
+	struct ti_qspi      *qspi;
+	struct spi_master       *master;
+
+	master = dev_get_drvdata(dev);
+	qspi = spi_master_get_devdata(master);
+	ti_qspi_restore_ctx(qspi);
+
+	return 0;
+}
+
+static const struct of_device_id ti_qspi_match[] = {
+	{.compatible = "ti,dra7xxx-qspi" },
+	{.compatible = "ti,am4372-qspi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ti_qspi_match);
+
+static int ti_qspi_probe(struct platform_device *pdev)
+{
+	struct  ti_qspi *qspi;
+	struct spi_master *master;
+	struct resource         *r;
+	struct device_node *np = pdev->dev.of_node;
+	u32 max_freq;
+	int ret = 0, num_cs, irq;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
+	if (!master)
+		return -ENOMEM;
+
+	master->mode_bits = SPI_CPOL | SPI_CPHA;
+
+	master->bus_num = -1;
+	master->flags = SPI_MASTER_HALF_DUPLEX;
+	master->setup = ti_qspi_setup;
+	master->auto_runtime_pm = true;
+	master->transfer_one_message = ti_qspi_start_transfer_one;
+	master->dev.of_node = pdev->dev.of_node;
+	master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
+
+	if (!of_property_read_u32(np, "num-cs", &num_cs))
+		master->num_chipselect = num_cs;
+
+	platform_set_drvdata(pdev, master);
+
+	qspi = spi_master_get_devdata(master);
+	qspi->master = master;
+	qspi->dev = &pdev->dev;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		return irq;
+	}
+
+	spin_lock_init(&qspi->lock);
+	mutex_init(&qspi->list_lock);
+
+	qspi->base = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(qspi->base)) {
+		ret = PTR_ERR(qspi->base);
+		goto free_master;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, ti_qspi_isr,
+			ti_qspi_threaded_isr, 0,
+			dev_name(&pdev->dev), qspi);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
+				irq);
+		goto free_master;
+	}
+
+	qspi->fclk = devm_clk_get(&pdev->dev, "fck");
+	if (IS_ERR(qspi->fclk)) {
+		ret = PTR_ERR(qspi->fclk);
+		dev_err(&pdev->dev, "could not get clk: %d\n", ret);
+	}
+
+	init_completion(&qspi->transfer_complete);
+
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT);
+	pm_runtime_enable(&pdev->dev);
+
+	if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
+		qspi->spi_max_frequency = max_freq;
+
+	ret = spi_register_master(master);
+	if (ret)
+		goto free_master;
+
+	return 0;
+
+free_master:
+	spi_master_put(master);
+	return ret;
+}
+
+static int ti_qspi_remove(struct platform_device *pdev)
+{
+	struct	ti_qspi *qspi = platform_get_drvdata(pdev);
+
+	spi_unregister_master(qspi->master);
+
+	return 0;
+}
+
+static const struct dev_pm_ops ti_qspi_pm_ops = {
+	.runtime_resume = ti_qspi_runtime_resume,
+};
+
+static struct platform_driver ti_qspi_driver = {
+	.probe	= ti_qspi_probe,
+	.remove	= ti_qspi_remove,
+	.driver = {
+		.name	= "ti,dra7xxx-qspi",
+		.owner	= THIS_MODULE,
+		.pm =   &ti_qspi_pm_ops,
+		.of_match_table = ti_qspi_match,
+	}
+};
+
+module_platform_driver(ti_qspi_driver);
+
+MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI QSPI controller driver");
diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c
index 10606fc..7d20e12 100644
--- a/drivers/spi/spi-ti-ssp.c
+++ b/drivers/spi/spi-ti-ssp.c
@@ -283,7 +283,7 @@
 	struct device *dev = &pdev->dev;
 	int error = 0;
 
-	pdata = dev->platform_data;
+	pdata = dev_get_platdata(dev);
 	if (!pdata) {
 		dev_err(dev, "platform data not found\n");
 		return -EINVAL;
diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c
index 6b0874d..2d4010d 100644
--- a/drivers/spi/spi-tle62x0.c
+++ b/drivers/spi/spi-tle62x0.c
@@ -52,8 +52,7 @@
 		buff[1] = gpio_state;
 	}
 
-	dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n",
-		buff[0], buff[1], buff[2]);
+	dev_dbg(&st->us->dev, "buff %3ph\n", buff);
 
 	return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
 }
@@ -247,7 +246,7 @@
 	int ptr;
 	int ret;
 
-	pdata = spi->dev.platform_data;
+	pdata = dev_get_platdata(&spi->dev);
 	if (pdata == NULL) {
 		dev_err(&spi->dev, "no device data specified\n");
 		return -EINVAL;
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index dd55707..eaeeed5 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1797,3 +1797,5 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor ML7xxx IOH SPI Driver");
+MODULE_DEVICE_TABLE(pci, pch_spi_pcidev_id);
+
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index e9b7681..7c6d157 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -26,7 +26,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
 
 
 #define SPI_FIFO_SIZE 4
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 09a9428..0bf1b2c 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -80,10 +80,9 @@
 	/* bitbang has to be first */
 	struct spi_bitbang bitbang;
 	struct completion done;
-	struct resource mem; /* phys mem */
 	void __iomem	*regs;	/* virt. address of the control registers */
 
-	u32		irq;
+	int		irq;
 
 	u8 *rx_ptr;		/* pointer in the Tx buffer */
 	const u8 *tx_ptr;	/* pointer in the Rx buffer */
@@ -233,21 +232,6 @@
 	return 0;
 }
 
-static int xilinx_spi_setup(struct spi_device *spi)
-{
-	/* always return 0, we can not check the number of bits.
-	 * There are cases when SPI setup is called before any driver is
-	 * there, in that case the SPI core defaults to 8 bits, which we
-	 * do not support in some cases. But if we return an error, the
-	 * SPI device would not be registered and no driver can get hold of it
-	 * When the driver is there, it will call SPI setup again with the
-	 * correct number of bits per transfer.
-	 * If a driver setups with the wrong bit number, it will fail when
-	 * it tries to do a transfer
-	 */
-	return 0;
-}
-
 static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
 {
 	u8 sr;
@@ -355,17 +339,34 @@
 };
 MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
 
-struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
-	u32 irq, s16 bus_num, int num_cs, int bits_per_word)
+static int xilinx_spi_probe(struct platform_device *pdev)
 {
-	struct spi_master *master;
 	struct xilinx_spi *xspi;
-	int ret;
+	struct xspi_platform_data *pdata;
+	struct resource *res;
+	int ret, num_cs = 0, bits_per_word = 8;
+	struct spi_master *master;
 	u32 tmp;
+	u8 i;
 
-	master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
+	pdata = dev_get_platdata(&pdev->dev);
+	if (pdata) {
+		num_cs = pdata->num_chipselect;
+		bits_per_word = pdata->bits_per_word;
+	} else {
+		of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
+					  &num_cs);
+	}
+
+	if (!num_cs) {
+		dev_err(&pdev->dev,
+			"Missing slave select configuration data\n");
+		return -EINVAL;
+	}
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
 	if (!master)
-		return NULL;
+		return -ENODEV;
 
 	/* the spi->mode bits understood by this driver: */
 	master->mode_bits = SPI_CPOL | SPI_CPHA;
@@ -375,25 +376,18 @@
 	xspi->bitbang.chipselect = xilinx_spi_chipselect;
 	xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
 	xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
-	xspi->bitbang.master->setup = xilinx_spi_setup;
 	init_completion(&xspi->done);
 
-	if (!request_mem_region(mem->start, resource_size(mem),
-		XILINX_SPI_NAME))
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	xspi->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(xspi->regs)) {
+		ret = PTR_ERR(xspi->regs);
 		goto put_master;
-
-	xspi->regs = ioremap(mem->start, resource_size(mem));
-	if (xspi->regs == NULL) {
-		dev_warn(dev, "ioremap failure\n");
-		goto map_failed;
 	}
 
-	master->bus_num = bus_num;
+	master->bus_num = pdev->dev.id;
 	master->num_chipselect = num_cs;
-	master->dev.of_node = dev->of_node;
-
-	xspi->mem = *mem;
-	xspi->irq = irq;
+	master->dev.of_node = pdev->dev.of_node;
 
 	/*
 	 * Detect endianess on the IP via loop bit in CR. Detection
@@ -423,113 +417,63 @@
 	} else if (xspi->bits_per_word == 32) {
 		xspi->tx_fn = xspi_tx32;
 		xspi->rx_fn = xspi_rx32;
-	} else
-		goto unmap_io;
-
+	} else {
+		ret = -EINVAL;
+		goto put_master;
+	}
 
 	/* SPI controller initializations */
 	xspi_init_hw(xspi);
 
+	xspi->irq = platform_get_irq(pdev, 0);
+	if (xspi->irq < 0) {
+		ret = xspi->irq;
+		goto put_master;
+	}
+
 	/* Register for SPI Interrupt */
-	ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+	ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
+			       dev_name(&pdev->dev), xspi);
 	if (ret)
-		goto unmap_io;
+		goto put_master;
 
 	ret = spi_bitbang_start(&xspi->bitbang);
 	if (ret) {
-		dev_err(dev, "spi_bitbang_start FAILED\n");
-		goto free_irq;
+		dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
+		goto put_master;
 	}
 
-	dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
-		(unsigned long long)mem->start, xspi->regs, xspi->irq);
-	return master;
-
-free_irq:
-	free_irq(xspi->irq, xspi);
-unmap_io:
-	iounmap(xspi->regs);
-map_failed:
-	release_mem_region(mem->start, resource_size(mem));
-put_master:
-	spi_master_put(master);
-	return NULL;
-}
-EXPORT_SYMBOL(xilinx_spi_init);
-
-void xilinx_spi_deinit(struct spi_master *master)
-{
-	struct xilinx_spi *xspi;
-
-	xspi = spi_master_get_devdata(master);
-
-	spi_bitbang_stop(&xspi->bitbang);
-	free_irq(xspi->irq, xspi);
-	iounmap(xspi->regs);
-
-	release_mem_region(xspi->mem.start, resource_size(&xspi->mem));
-	spi_master_put(xspi->bitbang.master);
-}
-EXPORT_SYMBOL(xilinx_spi_deinit);
-
-static int xilinx_spi_probe(struct platform_device *dev)
-{
-	struct xspi_platform_data *pdata;
-	struct resource *r;
-	int irq, num_cs = 0, bits_per_word = 8;
-	struct spi_master *master;
-	u8 i;
-
-	pdata = dev->dev.platform_data;
-	if (pdata) {
-		num_cs = pdata->num_chipselect;
-		bits_per_word = pdata->bits_per_word;
-	}
-
-#ifdef CONFIG_OF
-	if (dev->dev.of_node) {
-		const __be32 *prop;
-		int len;
-
-		/* number of slave select bits is required */
-		prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
-				       &len);
-		if (prop && len >= sizeof(*prop))
-			num_cs = __be32_to_cpup(prop);
-	}
-#endif
-
-	if (!num_cs) {
-		dev_err(&dev->dev, "Missing slave select configuration data\n");
-		return -EINVAL;
-	}
-
-
-	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
-	if (!r)
-		return -ENODEV;
-
-	irq = platform_get_irq(dev, 0);
-	if (irq < 0)
-		return -ENXIO;
-
-	master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
-				 bits_per_word);
-	if (!master)
-		return -ENODEV;
+	dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
+		(unsigned long long)res->start, xspi->regs, xspi->irq);
 
 	if (pdata) {
 		for (i = 0; i < pdata->num_devices; i++)
 			spi_new_device(master, pdata->devices + i);
 	}
 
-	platform_set_drvdata(dev, master);
+	platform_set_drvdata(pdev, master);
 	return 0;
+
+put_master:
+	spi_master_put(master);
+
+	return ret;
 }
 
-static int xilinx_spi_remove(struct platform_device *dev)
+static int xilinx_spi_remove(struct platform_device *pdev)
 {
-	xilinx_spi_deinit(platform_get_drvdata(dev));
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct xilinx_spi *xspi = spi_master_get_devdata(master);
+	void __iomem *regs_base = xspi->regs;
+
+	spi_bitbang_stop(&xspi->bitbang);
+
+	/* Disable all the interrupts just in case */
+	xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
+	/* Disable the global IPIF interrupt */
+	xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
+
+	spi_master_put(xspi->bitbang.master);
 
 	return 0;
 }
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 978dda2..9e039c6 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -553,6 +553,10 @@
 		    master->unprepare_transfer_hardware(master))
 			dev_err(&master->dev,
 				"failed to unprepare transfer hardware\n");
+		if (master->auto_runtime_pm) {
+			pm_runtime_mark_last_busy(master->dev.parent);
+			pm_runtime_put_autosuspend(master->dev.parent);
+		}
 		return;
 	}
 
@@ -572,11 +576,23 @@
 		master->busy = true;
 	spin_unlock_irqrestore(&master->queue_lock, flags);
 
+	if (!was_busy && master->auto_runtime_pm) {
+		ret = pm_runtime_get_sync(master->dev.parent);
+		if (ret < 0) {
+			dev_err(&master->dev, "Failed to power device: %d\n",
+				ret);
+			return;
+		}
+	}
+
 	if (!was_busy && master->prepare_transfer_hardware) {
 		ret = master->prepare_transfer_hardware(master);
 		if (ret) {
 			dev_err(&master->dev,
 				"failed to prepare transfer hardware\n");
+
+			if (master->auto_runtime_pm)
+				pm_runtime_put(master->dev.parent);
 			return;
 		}
 	}
@@ -774,7 +790,7 @@
 	msg->status = -EINPROGRESS;
 
 	list_add_tail(&msg->queue, &master->queue);
-	if (master->running && !master->busy)
+	if (!master->busy)
 		queue_kthread_work(&master->kworker, &master->pump_messages);
 
 	spin_unlock_irqrestore(&master->queue_lock, flags);
@@ -869,6 +885,47 @@
 		if (of_find_property(nc, "spi-3wire", NULL))
 			spi->mode |= SPI_3WIRE;
 
+		/* Device DUAL/QUAD mode */
+		prop = of_get_property(nc, "spi-tx-bus-width", &len);
+		if (prop && len == sizeof(*prop)) {
+			switch (be32_to_cpup(prop)) {
+			case SPI_NBITS_SINGLE:
+				break;
+			case SPI_NBITS_DUAL:
+				spi->mode |= SPI_TX_DUAL;
+				break;
+			case SPI_NBITS_QUAD:
+				spi->mode |= SPI_TX_QUAD;
+				break;
+			default:
+				dev_err(&master->dev,
+					"spi-tx-bus-width %d not supported\n",
+					be32_to_cpup(prop));
+				spi_dev_put(spi);
+				continue;
+			}
+		}
+
+		prop = of_get_property(nc, "spi-rx-bus-width", &len);
+		if (prop && len == sizeof(*prop)) {
+			switch (be32_to_cpup(prop)) {
+			case SPI_NBITS_SINGLE:
+				break;
+			case SPI_NBITS_DUAL:
+				spi->mode |= SPI_RX_DUAL;
+				break;
+			case SPI_NBITS_QUAD:
+				spi->mode |= SPI_RX_QUAD;
+				break;
+			default:
+				dev_err(&master->dev,
+					"spi-rx-bus-width %d not supported\n",
+					be32_to_cpup(prop));
+				spi_dev_put(spi);
+				continue;
+			}
+		}
+
 		/* Device speed */
 		prop = of_get_property(nc, "spi-max-frequency", &len);
 		if (!prop || len < sizeof(*prop)) {
@@ -1169,7 +1226,7 @@
 	else {
 		status = spi_master_initialize_queue(master);
 		if (status) {
-			device_unregister(&master->dev);
+			device_del(&master->dev);
 			goto done;
 		}
 	}
@@ -1316,6 +1373,19 @@
 	unsigned	bad_bits;
 	int		status = 0;
 
+	/* check mode to prevent that DUAL and QUAD set at the same time
+	 */
+	if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) ||
+		((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) {
+		dev_err(&spi->dev,
+		"setup: can not select dual and quad at the same time\n");
+		return -EINVAL;
+	}
+	/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
+	 */
+	if ((spi->mode & SPI_3WIRE) && (spi->mode &
+		(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))
+		return -EINVAL;
 	/* help drivers fail *cleanly* when they need options
 	 * that aren't supported with their current master
 	 */
@@ -1351,6 +1421,11 @@
 	struct spi_master *master = spi->master;
 	struct spi_transfer *xfer;
 
+	if (list_empty(&message->transfers))
+		return -EINVAL;
+	if (!message->complete)
+		return -EINVAL;
+
 	/* Half-duplex links include original MicroWire, and ones with
 	 * only one data pin like SPI_3WIRE (switches direction) or where
 	 * either MOSI or MISO is missing.  They can also be caused by
@@ -1373,12 +1448,20 @@
 	/**
 	 * Set transfer bits_per_word and max speed as spi device default if
 	 * it is not set for this transfer.
+	 * Set transfer tx_nbits and rx_nbits as single transfer default
+	 * (SPI_NBITS_SINGLE) if it is not set for this transfer.
 	 */
 	list_for_each_entry(xfer, &message->transfers, transfer_list) {
+		message->frame_length += xfer->len;
 		if (!xfer->bits_per_word)
 			xfer->bits_per_word = spi->bits_per_word;
-		if (!xfer->speed_hz)
+		if (!xfer->speed_hz) {
 			xfer->speed_hz = spi->max_speed_hz;
+			if (master->max_speed_hz &&
+			    xfer->speed_hz > master->max_speed_hz)
+				xfer->speed_hz = master->max_speed_hz;
+		}
+
 		if (master->bits_per_word_mask) {
 			/* Only 32 bits fit in the mask */
 			if (xfer->bits_per_word > 32)
@@ -1387,6 +1470,54 @@
 					BIT(xfer->bits_per_word - 1)))
 				return -EINVAL;
 		}
+
+		if (xfer->speed_hz && master->min_speed_hz &&
+		    xfer->speed_hz < master->min_speed_hz)
+			return -EINVAL;
+		if (xfer->speed_hz && master->max_speed_hz &&
+		    xfer->speed_hz > master->max_speed_hz)
+			return -EINVAL;
+
+		if (xfer->tx_buf && !xfer->tx_nbits)
+			xfer->tx_nbits = SPI_NBITS_SINGLE;
+		if (xfer->rx_buf && !xfer->rx_nbits)
+			xfer->rx_nbits = SPI_NBITS_SINGLE;
+		/* check transfer tx/rx_nbits:
+		 * 1. keep the value is not out of single, dual and quad
+		 * 2. keep tx/rx_nbits is contained by mode in spi_device
+		 * 3. if SPI_3WIRE, tx/rx_nbits should be in single
+		 */
+		if (xfer->tx_buf) {
+			if (xfer->tx_nbits != SPI_NBITS_SINGLE &&
+				xfer->tx_nbits != SPI_NBITS_DUAL &&
+				xfer->tx_nbits != SPI_NBITS_QUAD)
+				return -EINVAL;
+			if ((xfer->tx_nbits == SPI_NBITS_DUAL) &&
+				!(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
+				return -EINVAL;
+			if ((xfer->tx_nbits == SPI_NBITS_QUAD) &&
+				!(spi->mode & SPI_TX_QUAD))
+				return -EINVAL;
+			if ((spi->mode & SPI_3WIRE) &&
+				(xfer->tx_nbits != SPI_NBITS_SINGLE))
+				return -EINVAL;
+		}
+		/* check transfer rx_nbits */
+		if (xfer->rx_buf) {
+			if (xfer->rx_nbits != SPI_NBITS_SINGLE &&
+				xfer->rx_nbits != SPI_NBITS_DUAL &&
+				xfer->rx_nbits != SPI_NBITS_QUAD)
+				return -EINVAL;
+			if ((xfer->rx_nbits == SPI_NBITS_DUAL) &&
+				!(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
+				return -EINVAL;
+			if ((xfer->rx_nbits == SPI_NBITS_QUAD) &&
+				!(spi->mode & SPI_RX_QUAD))
+				return -EINVAL;
+			if ((spi->mode & SPI_3WIRE) &&
+				(xfer->rx_nbits != SPI_NBITS_SINGLE))
+				return -EINVAL;
+		}
 	}
 
 	message->spi = spi;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 911e9e0..ca5bcfe 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -603,7 +603,7 @@
 		dev = device_create(spidev_class, &spi->dev, spidev->devt,
 				    spidev, "spidev%d.%d",
 				    spi->master->bus_num, spi->chip_select);
-		status = PTR_RET(dev);
+		status = PTR_ERR_OR_ZERO(dev);
 	} else {
 		dev_dbg(&spi->dev, "no minor number available!\n");
 		status = -ENODEV;
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 57d8b34..3626dbc8 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -40,8 +40,6 @@
 
 source "drivers/staging/olpc_dcon/Kconfig"
 
-source "drivers/staging/asus_oled/Kconfig"
-
 source "drivers/staging/panel/Kconfig"
 
 source "drivers/staging/rtl8187se/Kconfig"
@@ -52,6 +50,8 @@
 
 source "drivers/staging/rtl8712/Kconfig"
 
+source "drivers/staging/rtl8188eu/Kconfig"
+
 source "drivers/staging/rts5139/Kconfig"
 
 source "drivers/staging/frontier/Kconfig"
@@ -118,6 +118,8 @@
 
 source "drivers/staging/gdm72xx/Kconfig"
 
+source "drivers/staging/gdm724x/Kconfig"
+
 source "drivers/staging/silicom/Kconfig"
 
 source "drivers/staging/ced1401/Kconfig"
@@ -130,8 +132,6 @@
 
 source "drivers/staging/fwserial/Kconfig"
 
-source "drivers/staging/zcache/Kconfig"
-
 source "drivers/staging/goldfish/Kconfig"
 
 source "drivers/staging/netlogic/Kconfig"
@@ -142,4 +142,10 @@
 
 source "drivers/staging/btmtk_usb/Kconfig"
 
+source "drivers/staging/xillybus/Kconfig"
+
+source "drivers/staging/dgnc/Kconfig"
+
+source "drivers/staging/dgap/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 429321f..d1b4b80 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -12,12 +12,12 @@
 obj-$(CONFIG_ECHO)		+= echo/
 obj-$(CONFIG_COMEDI)		+= comedi/
 obj-$(CONFIG_FB_OLPC_DCON)	+= olpc_dcon/
-obj-$(CONFIG_ASUS_OLED)		+= asus_oled/
 obj-$(CONFIG_PANEL)		+= panel/
 obj-$(CONFIG_R8187SE)		+= rtl8187se/
 obj-$(CONFIG_RTL8192U)		+= rtl8192u/
 obj-$(CONFIG_RTL8192E)		+= rtl8192e/
 obj-$(CONFIG_R8712U)		+= rtl8712/
+obj-$(CONFIG_R8188EU)		+= rtl8188eu/
 obj-$(CONFIG_RTS5139)		+= rts5139/
 obj-$(CONFIG_TRANZPORT)		+= frontier/
 obj-$(CONFIG_IDE_PHISON)	+= phison/
@@ -52,14 +52,17 @@
 obj-$(CONFIG_ANDROID)		+= android/
 obj-$(CONFIG_USB_WPAN_HCD)	+= ozwpan/
 obj-$(CONFIG_WIMAX_GDM72XX)	+= gdm72xx/
+obj-$(CONFIG_LTE_GDM724X)	+= gdm724x/
 obj-$(CONFIG_NET_VENDOR_SILICOM)	+= silicom/
 obj-$(CONFIG_CED1401)		+= ced1401/
 obj-$(CONFIG_DRM_IMX)		+= imx-drm/
 obj-$(CONFIG_DGRP)		+= dgrp/
 obj-$(CONFIG_SB105X)		+= sb105x/
 obj-$(CONFIG_FIREWIRE_SERIAL)	+= fwserial/
-obj-$(CONFIG_ZCACHE)		+= zcache/
 obj-$(CONFIG_GOLDFISH)		+= goldfish/
 obj-$(CONFIG_USB_DWC2)		+= dwc2/
 obj-$(CONFIG_LUSTRE_FS)		+= lustre/
 obj-$(CONFIG_USB_BTMTK)		+= btmtk_usb/
+obj-$(CONFIG_XILLYBUS)		+= xillybus/
+obj-$(CONFIG_DGNC)			+= dgnc/
+obj-$(CONFIG_DGAP)			+= dgap/
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 119d486..98ac020 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -1248,7 +1248,7 @@
 		struct flat_binder_object *fp;
 		if (*offp > buffer->data_size - sizeof(*fp) ||
 		    buffer->data_size < sizeof(*fp) ||
-		    !IS_ALIGNED(*offp, sizeof(void *))) {
+		    !IS_ALIGNED(*offp, sizeof(u32))) {
 			pr_err("transaction release %d bad offset %zd, size %zd\n",
 			 debug_id, *offp, buffer->data_size);
 			continue;
@@ -1272,7 +1272,7 @@
 		case BINDER_TYPE_WEAK_HANDLE: {
 			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
 			if (ref == NULL) {
-				pr_err("transaction release %d bad handle %ld\n",
+				pr_err("transaction release %d bad handle %d\n",
 				 debug_id, fp->handle);
 				break;
 			}
@@ -1284,13 +1284,13 @@
 
 		case BINDER_TYPE_FD:
 			binder_debug(BINDER_DEBUG_TRANSACTION,
-				     "        fd %ld\n", fp->handle);
+				     "        fd %d\n", fp->handle);
 			if (failed_at)
 				task_close_fd(proc, fp->handle);
 			break;
 
 		default:
-			pr_err("transaction release %d bad object type %lx\n",
+			pr_err("transaction release %d bad object type %x\n",
 				debug_id, fp->type);
 			break;
 		}
@@ -1497,7 +1497,7 @@
 		struct flat_binder_object *fp;
 		if (*offp > t->buffer->data_size - sizeof(*fp) ||
 		    t->buffer->data_size < sizeof(*fp) ||
-		    !IS_ALIGNED(*offp, sizeof(void *))) {
+		    !IS_ALIGNED(*offp, sizeof(u32))) {
 			binder_user_error("%d:%d got transaction with invalid offset, %zd\n",
 					proc->pid, thread->pid, *offp);
 			return_error = BR_FAILED_REPLY;
@@ -1548,7 +1548,7 @@
 		case BINDER_TYPE_WEAK_HANDLE: {
 			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
 			if (ref == NULL) {
-				binder_user_error("%d:%d got transaction with invalid handle, %ld\n",
+				binder_user_error("%d:%d got transaction with invalid handle, %d\n",
 						proc->pid,
 						thread->pid, fp->handle);
 				return_error = BR_FAILED_REPLY;
@@ -1591,13 +1591,13 @@
 
 			if (reply) {
 				if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
-					binder_user_error("%d:%d got reply with fd, %ld, but target does not allow fds\n",
+					binder_user_error("%d:%d got reply with fd, %d, but target does not allow fds\n",
 						proc->pid, thread->pid, fp->handle);
 					return_error = BR_FAILED_REPLY;
 					goto err_fd_not_allowed;
 				}
 			} else if (!target_node->accept_fds) {
-				binder_user_error("%d:%d got transaction with fd, %ld, but target does not allow fds\n",
+				binder_user_error("%d:%d got transaction with fd, %d, but target does not allow fds\n",
 					proc->pid, thread->pid, fp->handle);
 				return_error = BR_FAILED_REPLY;
 				goto err_fd_not_allowed;
@@ -1605,7 +1605,7 @@
 
 			file = fget(fp->handle);
 			if (file == NULL) {
-				binder_user_error("%d:%d got transaction with invalid fd, %ld\n",
+				binder_user_error("%d:%d got transaction with invalid fd, %d\n",
 					proc->pid, thread->pid, fp->handle);
 				return_error = BR_FAILED_REPLY;
 				goto err_fget_failed;
@@ -1619,13 +1619,13 @@
 			task_fd_install(target_proc, target_fd, file);
 			trace_binder_transaction_fd(t, fp->handle, target_fd);
 			binder_debug(BINDER_DEBUG_TRANSACTION,
-				     "        fd %ld -> %d\n", fp->handle, target_fd);
+				     "        fd %d -> %d\n", fp->handle, target_fd);
 			/* TODO: fput? */
 			fp->handle = target_fd;
 		} break;
 
 		default:
-			binder_user_error("%d:%d got transaction with invalid object type, %lx\n",
+			binder_user_error("%d:%d got transaction with invalid object type, %x\n",
 				proc->pid, thread->pid, fp->type);
 			return_error = BR_FAILED_REPLY;
 			goto err_bad_object_type;
@@ -1701,7 +1701,7 @@
 }
 
 int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
-			void __user *buffer, int size, signed long *consumed)
+			void __user *buffer, size_t size, size_t *consumed)
 {
 	uint32_t cmd;
 	void __user *ptr = buffer + *consumed;
@@ -2081,8 +2081,8 @@
 
 static int binder_thread_read(struct binder_proc *proc,
 			      struct binder_thread *thread,
-			      void  __user *buffer, int size,
-			      signed long *consumed, int non_block)
+			      void  __user *buffer, size_t size,
+			      size_t *consumed, int non_block)
 {
 	void __user *ptr = buffer + *consumed;
 	void __user *end = buffer + size;
@@ -2579,7 +2579,7 @@
 			goto err;
 		}
 		binder_debug(BINDER_DEBUG_READ_WRITE,
-			     "%d:%d write %ld at %08lx, read %ld at %08lx\n",
+			     "%d:%d write %zd at %016lx, read %zd at %016lx\n",
 			     proc->pid, thread->pid, bwr.write_size,
 			     bwr.write_buffer, bwr.read_size, bwr.read_buffer);
 
@@ -2605,7 +2605,7 @@
 			}
 		}
 		binder_debug(BINDER_DEBUG_READ_WRITE,
-			     "%d:%d wrote %ld of %ld, read return %ld of %ld\n",
+			     "%d:%d wrote %zd of %zd, read return %zd of %zd\n",
 			     proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
 			     bwr.read_consumed, bwr.read_size);
 		if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index dbe81ce..cbe3451 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -48,13 +48,13 @@
  */
 struct flat_binder_object {
 	/* 8 bytes for large_flat_header. */
-	unsigned long		type;
-	unsigned long		flags;
+	__u32		type;
+	__u32		flags;
 
 	/* 8 bytes of data. */
 	union {
 		void __user	*binder;	/* local object */
-		signed long	handle;		/* remote object */
+		__u32	    handle;		/* remote object */
 	};
 
 	/* extra data associated with local object */
@@ -67,18 +67,18 @@
  */
 
 struct binder_write_read {
-	signed long	write_size;	/* bytes to write */
-	signed long	write_consumed;	/* bytes consumed by driver */
+	size_t write_size;	/* bytes to write */
+	size_t write_consumed;	/* bytes consumed by driver */
 	unsigned long	write_buffer;
-	signed long	read_size;	/* bytes to read */
-	signed long	read_consumed;	/* bytes consumed by driver */
+	size_t read_size;	/* bytes to read */
+	size_t read_consumed;	/* bytes consumed by driver */
 	unsigned long	read_buffer;
 };
 
 /* Use with BINDER_VERSION, driver fills in fields. */
 struct binder_version {
 	/* driver protocol version -- increment with incompatible change */
-	signed long	protocol_version;
+	__s32       protocol_version;
 };
 
 /* This is the current protocol version. */
@@ -86,7 +86,7 @@
 
 #define BINDER_WRITE_READ		_IOWR('b', 1, struct binder_write_read)
 #define	BINDER_SET_IDLE_TIMEOUT		_IOW('b', 3, __s64)
-#define	BINDER_SET_MAX_THREADS		_IOW('b', 5, size_t)
+#define	BINDER_SET_MAX_THREADS		_IOW('b', 5, __u32)
 #define	BINDER_SET_IDLE_PRIORITY	_IOW('b', 6, __s32)
 #define	BINDER_SET_CONTEXT_MGR		_IOW('b', 7, __s32)
 #define	BINDER_THREAD_EXIT		_IOW('b', 8, __s32)
@@ -119,14 +119,14 @@
 	 * identifying the target and contents of the transaction.
 	 */
 	union {
-		size_t	handle;	/* target descriptor of command transaction */
+		__u32	handle;	/* target descriptor of command transaction */
 		void	*ptr;	/* target descriptor of return transaction */
 	} target;
 	void		*cookie;	/* target object cookie */
-	unsigned int	code;		/* transaction command */
+	__u32		code;		/* transaction command */
 
 	/* General information about the transaction. */
-	unsigned int	flags;
+	__u32	        flags;
 	pid_t		sender_pid;
 	uid_t		sender_euid;
 	size_t		data_size;	/* number of bytes of data */
@@ -143,7 +143,7 @@
 			/* offsets from buffer to flat_binder_object structs */
 			const void __user	*offsets;
 		} ptr;
-		uint8_t	buf[8];
+		__u8	buf[8];
 	} data;
 };
 
@@ -153,18 +153,18 @@
 };
 
 struct binder_pri_desc {
-	int priority;
-	int desc;
+	__s32 priority;
+	__u32 desc;
 };
 
 struct binder_pri_ptr_cookie {
-	int priority;
+	__s32 priority;
 	void *ptr;
 	void *cookie;
 };
 
 enum binder_driver_return_protocol {
-	BR_ERROR = _IOR('r', 0, int),
+	BR_ERROR = _IOR('r', 0, __s32),
 	/*
 	 * int: error code
 	 */
@@ -178,7 +178,7 @@
 	 * binder_transaction_data: the received command.
 	 */
 
-	BR_ACQUIRE_RESULT = _IOR('r', 4, int),
+	BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
 	/*
 	 * not currently supported
 	 * int: 0 if the last bcATTEMPT_ACQUIRE was not successful.
@@ -258,22 +258,22 @@
 	 * binder_transaction_data: the sent command.
 	 */
 
-	BC_ACQUIRE_RESULT = _IOW('c', 2, int),
+	BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
 	/*
 	 * not currently supported
 	 * int:  0 if the last BR_ATTEMPT_ACQUIRE was not successful.
 	 * Else you have acquired a primary reference on the object.
 	 */
 
-	BC_FREE_BUFFER = _IOW('c', 3, int),
+	BC_FREE_BUFFER = _IOW('c', 3, void *),
 	/*
 	 * void *: ptr to transaction data received on a read
 	 */
 
-	BC_INCREFS = _IOW('c', 4, int),
-	BC_ACQUIRE = _IOW('c', 5, int),
-	BC_RELEASE = _IOW('c', 6, int),
-	BC_DECREFS = _IOW('c', 7, int),
+	BC_INCREFS = _IOW('c', 4, __u32),
+	BC_ACQUIRE = _IOW('c', 5, __u32),
+	BC_RELEASE = _IOW('c', 6, __u32),
+	BC_DECREFS = _IOW('c', 7, __u32),
 	/*
 	 * int:	descriptor
 	 */
diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c
index 765c757..f24493a 100644
--- a/drivers/staging/android/sw_sync.c
+++ b/drivers/staging/android/sw_sync.c
@@ -163,7 +163,7 @@
 static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj,
 				       unsigned long arg)
 {
-	int fd = get_unused_fd();
+	int fd = get_unused_fd_flags(O_CLOEXEC);
 	int err;
 	struct sync_pt *pt;
 	struct sync_fence *fence;
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
index 2996077..38e5d3b 100644
--- a/drivers/staging/android/sync.c
+++ b/drivers/staging/android/sync.c
@@ -697,7 +697,7 @@
 
 static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg)
 {
-	int fd = get_unused_fd();
+	int fd = get_unused_fd_flags(O_CLOEXEC);
 	int err;
 	struct sync_fence *fence2, *fence3;
 	struct sync_merge_data data;
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index ee3a57f..2c61783 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -28,7 +28,7 @@
 static atomic_t device_count;
 
 static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
+			   char *buf)
 {
 	struct timed_output_dev *tdev = dev_get_drvdata(dev);
 	int remaining = tdev->get_time(tdev);
@@ -36,9 +36,8 @@
 	return sprintf(buf, "%d\n", remaining);
 }
 
-static ssize_t enable_store(
-		struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t size)
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t size)
 {
 	struct timed_output_dev *tdev = dev_get_drvdata(dev);
 	int value;
@@ -50,8 +49,13 @@
 
 	return size;
 }
+static DEVICE_ATTR_RW(enable);
 
-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static struct attribute *timed_output_attrs[] = {
+	&dev_attr_enable.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(timed_output);
 
 static int create_timed_output_class(void)
 {
@@ -60,6 +64,7 @@
 		if (IS_ERR(timed_output_class))
 			return PTR_ERR(timed_output_class);
 		atomic_set(&device_count, 0);
+		timed_output_class->dev_groups = timed_output_groups;
 	}
 
 	return 0;
@@ -82,27 +87,15 @@
 	if (IS_ERR(tdev->dev))
 		return PTR_ERR(tdev->dev);
 
-	ret = device_create_file(tdev->dev, &dev_attr_enable);
-	if (ret < 0)
-		goto err_create_file;
-
 	dev_set_drvdata(tdev->dev, tdev);
 	tdev->state = 0;
 	return 0;
-
-err_create_file:
-	device_destroy(timed_output_class, MKDEV(0, tdev->index));
-	pr_err("failed to register driver %s\n",
-			tdev->name);
-
-	return ret;
 }
 EXPORT_SYMBOL_GPL(timed_output_dev_register);
 
 void timed_output_dev_unregister(struct timed_output_dev *tdev)
 {
 	tdev->enable(tdev, 0);
-	device_remove_file(tdev->dev, &dev_attr_enable);
 	device_destroy(timed_output_class, MKDEV(0, tdev->index));
 	dev_set_drvdata(tdev->dev, NULL);
 }
diff --git a/drivers/staging/asus_oled/Kconfig b/drivers/staging/asus_oled/Kconfig
deleted file mode 100644
index e56dbb2..0000000
--- a/drivers/staging/asus_oled/Kconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-config ASUS_OLED
-	tristate "Asus OLED driver"
-	depends on USB
-	default N
-	---help---
-	  Enable support for the OLED display present in some Asus laptops.
diff --git a/drivers/staging/asus_oled/Makefile b/drivers/staging/asus_oled/Makefile
deleted file mode 100644
index e71f9aa..0000000
--- a/drivers/staging/asus_oled/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_ASUS_OLED)		+= asus_oled.o
diff --git a/drivers/staging/asus_oled/README b/drivers/staging/asus_oled/README
deleted file mode 100644
index 2d72123..0000000
--- a/drivers/staging/asus_oled/README
+++ /dev/null
@@ -1,156 +0,0 @@
-
-    Driver for Asus OLED display present in some Asus laptops.
-
-    The code of this driver is based on 'asusoled' program taken from
-    <http://lapsus.berlios.de/asus_oled.html>. I just wanted to have a simple
-    kernel driver for controlling this device, but I didn't know how
-    to do that. Now I know ;) Also, that program can not be used
-    with usbhid loaded, which means no USB mouse/keyboard while
-    controlling OLED display :(
-
-    It has been tested on Asus G1 and didn't cause any problems,
-    but I don't guarantee that it won't do anything wrong :)
-
-    It can (and probably does) have errors. It is usable
-    in my case, and I hope others will find it useful too!
-
-*******
-
-Building the module
-
-   To build the module you need kernel 2.6 include files and some C compiler.
-
-   Just run:
-   make
-   make install (as a root)
-
-   It will build (hopefully) the module and install it in
-   /lib/modules/'uname -r'/extra/asus_oled.ko.
-
-   To load it just use:
-   modprobe asus_oled
-
-   You can check if it has detected your OLED display by looking into dmesg output.
-   There should be something like this:
-   asus-oled 2-7:1.0: Attached Asus OLED device
-
-   If it doesn't find your display, you can try removing usbhid module.
-   If you add asus_oled into the list of modules loaded during system boot
-   before usbhid, it will work even when usbhid is present.
-
-   If it still doesn't detect your hardware, check lsusb output.
-   There should be similar line:
-   Bus 002 Device 005: ID 0b05:1726 ASUSTek Computer, Inc.
-
-   If you don't see any lines with '0b05:1726' it means that you have different
-   type of hardware that is not detected (it may or may not work, but the driver
-   knows only '0b05:1726' device).
-
-*******
-
-Configuration
-
-   There is only one option: start_off.
-   You can use it by: 'modprobe asus_oled start_off=1', or by adding this
-   line to /etc/modprobe.d/asus_oled.conf:
-   options asus_oled start_off=1
-
-   With this option provided, asus_oled driver will switch off the display
-   when it is detected and attached. It is nice feature to just switch off the 'ASUS'
-   logo. If you don't use the display, it is probably the good idea to switch it off,
-   to protect OLEDs from "wearing off".
-
-*******
-
-Usage
-
-   This module can be controlled with two special files:
-   /sys/class/asus_oled/oled_N/enabled
-   /sys/class/asus_oled/oled_N/picture
-
-   (N is the device number, the first, and probably the only, has number 1,
-    so it is /sys/class/asus_oled/oled_1/enabled
-    and /sys/class/asus_oled/oled_1/picture)
-
-   'enabled' files is for reading and writing, 'picture' is writeable only.
-
-   You can write 0 or 1 to 'enabled' file, which will switch
-   on and off the display. Reading from this file will tell you the last
-   status set, either 0 or 1. By default it is 1, so if the device was set to 'off',
-   and the computer was rebooted without power-off, this file will contain wrong
-   value - because the device is off, but hasn't been disabled this time and is
-   assumed to be on...
-
-   To 'picture' file you write pictures to be displayed by the OLED device.
-   The format of the file:
-   <M:WxH>
-   00001110010111000
-   00010101010101010
-   ....
-
-   First line is a configuration parameter. Meaning of fields in <M:WxH>:
-   M - picture mode. It can be either 's' for static pictures,
-       'r' for rolling pictures, and 'f' for flashing pictures.
-   W - width of the picture. May be between 1 and 1792
-   H - height of the picture. May be between 1 and 32
-
-   For example <s:128x32> means static picture, 128 pixels long and 32 pixels high.
-
-   The physical size of the display is 128x32 pixels. Static and flashing pictures
-   can't be larger than that (actually they can, but only part of them will be displayed ;) )
-
-   If the picture is smaller than 128x32 it will be centered. Rolling pictures wider than
-   128 pixels will be centered too, unless their width = n*128. Vertically they will be
-   centered just like static pictures, if their height is smaller than 32.
-
-   Flashing pictures will be centered horizontally if their width < 128, but they were
-   centered vertically in a different way. If their height < 16, they will be centered
-   in the upper half of the display (rows 0-15). This is because only the first half
-   of flashing pictures is used for flashing. When the picture with heigh = 32 is
-   displayed in flashing mode, its upper 16 rows will be flashing in the upper half
-   of the display, and the lower half will be empty. After few seconds upper part will
-   stop flashing (but that part of the picture will remain there), and the lower
-   half of the display will start displayin the lower half of the picture
-   in rolling mode, unless it is empty, or the picture was small enough to fit in
-   upper part. It is not mine idea, this is just the way Asus' display work ;)
-   So if you need just flashing, use at most 128x16 picture. If you need flashing and
-   rolling, use whole size of the display.
-
-   Lines following the first, configuration, line are picture data. Each '1' means
-   that the pixel is lit, and '0' means that it is not. You can also use '#' as ON,
-   and ' ' (space) as OFF. Empty lines and all other characters are ignored.
-
-   It is possible to write everything in one line <M:WxH>01010101010101010...,
-   and W*H characters will be used. If there is not enough characters, nothing will be
-   displayed. However, the 'line mode' is easier to read (and write), and it also
-   lets to omit parts of data. Whenever End-Of-Line character is found, but
-   the line is not W characters long, it is assumed that all missing characters
-   are equal to the last character in the line.
-
-   Following line represents '0', '1' and a lots of '0's, dependng on the width of the picture
-   provided in configuration data:
-   010
-
-   So if you need empty line, it is sufficient to write line with only one '0' in it.
-   The same works with '1' (or ' ' and '#').
-
-   If there are too many data in the file, they will be ignored. If you are not sure
-   how many characters you are missing, you can add few lines with one zero in each of them.
-
-   There are some example pictures in .txt format, that can be used as follows:
-   cat foo.txt > /sys/class/asus_oled/oled_1/picture
-
-   If the display is switched off you also need to run:
-   echo 1 > /sys/class/asus_oled/oled_1/enabled
-   To switch it off, just use:
-   echo 0 > /sys/class/asus_oled/oled_1/enabled
-
-
-*******
-
-   For any additional info please have a look at http://lapsus.berlios.de/asus_oled.html
-
-
-
-   Jakub Schmidtke (sjakub@gmail.com)
-
diff --git a/drivers/staging/asus_oled/TODO b/drivers/staging/asus_oled/TODO
deleted file mode 100644
index 2514131..0000000
--- a/drivers/staging/asus_oled/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
-	- checkpatch.pl cleanups
-	- sparse fixes
-	- audit the userspace interface
-		- sysfs vs. char?
-	- Documentation/ABI/ needs to be added
-	- put the sample .txt files and README file somewhere.
-
-Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
-Cc: Jakub Schmidtke <sjakub@gmail.com>
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
deleted file mode 100644
index 3654dc3..0000000
--- a/drivers/staging/asus_oled/asus_oled.c
+++ /dev/null
@@ -1,847 +0,0 @@
-/*
- *  Asus OLED USB driver
- *
- *  Copyright (C) 2007,2008 Jakub Schmidtke (sjakub@gmail.com)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *
- *
- *  This module is based on usbled and asus-laptop modules.
- *
- *
- *  Asus OLED support is based on asusoled program taken from
- *  <http://lapsus.berlios.de/asus_oled.html>.
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/platform_device.h>
-#include <linux/ctype.h>
-
-#define ASUS_OLED_VERSION		"0.04-dev"
-#define ASUS_OLED_NAME			"asus-oled"
-#define ASUS_OLED_UNDERSCORE_NAME	"asus_oled"
-
-#define ASUS_OLED_STATIC		's'
-#define ASUS_OLED_ROLL			'r'
-#define ASUS_OLED_FLASH			'f'
-
-#define ASUS_OLED_MAX_WIDTH		1792
-#define ASUS_OLED_DISP_HEIGHT		32
-#define ASUS_OLED_PACKET_BUF_SIZE	256
-
-#define USB_VENDOR_ID_ASUS		0x0b05
-#define USB_DEVICE_ID_ASUS_LCM		0x1726
-#define USB_DEVICE_ID_ASUS_LCM2		0x175b
-
-MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
-MODULE_DESCRIPTION("Asus OLED Driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(ASUS_OLED_VERSION);
-
-static struct class *oled_class;
-static int oled_num;
-
-static uint start_off;
-
-module_param(start_off, uint, 0644);
-
-MODULE_PARM_DESC(start_off,
-		 "Set to 1 to switch off OLED display after it is attached");
-
-enum oled_pack_mode {
-	PACK_MODE_G1,
-	PACK_MODE_G50,
-	PACK_MODE_LAST
-};
-
-struct oled_dev_desc_str {
-	uint16_t		idVendor;
-	uint16_t		idProduct;
-	/* width of display */
-	uint16_t		devWidth;
-	/* formula to be used while packing the picture */
-	enum oled_pack_mode	packMode;
-	const char		*devDesc;
-};
-
-/* table of devices that work with this driver */
-static const struct usb_device_id id_table[] = {
-	/* Asus G1/G2 (and variants)*/
-	{ USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM) },
-	/* Asus G50V (and possibly others - G70? G71?)*/
-	{ USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2) },
-	{ },
-};
-
-/* parameters of specific devices */
-static struct oled_dev_desc_str oled_dev_desc_table[] = {
-	{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, 128, PACK_MODE_G1,
-		"G1/G2" },
-	{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2, 256, PACK_MODE_G50,
-		"G50" },
-	{ },
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct asus_oled_header {
-	uint8_t		magic1;
-	uint8_t		magic2;
-	uint8_t		flags;
-	uint8_t		value3;
-	uint8_t		buffer1;
-	uint8_t		buffer2;
-	uint8_t		value6;
-	uint8_t		value7;
-	uint8_t		value8;
-	uint8_t		padding2[7];
-} __attribute((packed));
-
-struct asus_oled_packet {
-	struct asus_oled_header		header;
-	uint8_t				bitmap[ASUS_OLED_PACKET_BUF_SIZE];
-} __attribute((packed));
-
-struct asus_oled_dev {
-	struct usb_device       *udev;
-	uint8_t			pic_mode;
-	uint16_t		dev_width;
-	enum oled_pack_mode	pack_mode;
-	size_t			height;
-	size_t			width;
-	size_t			x_shift;
-	size_t			y_shift;
-	size_t			buf_offs;
-	uint8_t			last_val;
-	size_t			buf_size;
-	char			*buf;
-	uint8_t			enabled;
-	uint8_t			enabled_post_resume;
-	struct device		*dev;
-};
-
-static void setup_packet_header(struct asus_oled_packet *packet, char flags,
-			 char value3, char buffer1, char buffer2, char value6,
-			 char value7, char value8)
-{
-	memset(packet, 0, sizeof(struct asus_oled_header));
-	packet->header.magic1 = 0x55;
-	packet->header.magic2 = 0xaa;
-	packet->header.flags = flags;
-	packet->header.value3 = value3;
-	packet->header.buffer1 = buffer1;
-	packet->header.buffer2 = buffer2;
-	packet->header.value6 = value6;
-	packet->header.value7 = value7;
-	packet->header.value8 = value8;
-}
-
-static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
-{
-	int retval;
-	int act_len;
-	struct asus_oled_packet *packet;
-
-	packet = kzalloc(sizeof(struct asus_oled_packet), GFP_KERNEL);
-	if (!packet)
-		return;
-
-	setup_packet_header(packet, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00);
-
-	if (enabl)
-		packet->bitmap[0] = 0xaf;
-	else
-		packet->bitmap[0] = 0xae;
-
-	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);
-
-	odev->enabled = enabl;
-
-	kfree(packet);
-}
-
-static ssize_t set_enabled(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
-{
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct asus_oled_dev *odev = usb_get_intfdata(intf);
-	unsigned long value;
-	if (kstrtoul(buf, 10, &value))
-		return -EINVAL;
-
-	enable_oled(odev, value);
-
-	return count;
-}
-
-static ssize_t class_set_enabled(struct device *device,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	struct asus_oled_dev *odev =
-		(struct asus_oled_dev *) dev_get_drvdata(device);
-	unsigned long value;
-
-	if (kstrtoul(buf, 10, &value))
-		return -EINVAL;
-
-	enable_oled(odev, value);
-
-	return count;
-}
-
-static ssize_t get_enabled(struct device *dev, struct device_attribute *attr,
-			   char *buf)
-{
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct asus_oled_dev *odev = usb_get_intfdata(intf);
-
-	return sprintf(buf, "%d\n", odev->enabled);
-}
-
-static ssize_t class_get_enabled(struct device *device,
-				 struct device_attribute *attr, char *buf)
-{
-	struct asus_oled_dev *odev =
-		(struct asus_oled_dev *) dev_get_drvdata(device);
-
-	return sprintf(buf, "%d\n", odev->enabled);
-}
-
-static void send_packets(struct usb_device *udev,
-			 struct asus_oled_packet *packet,
-			 char *buf, uint8_t p_type, size_t p_num)
-{
-	size_t i;
-	int act_len;
-
-	for (i = 0; i < p_num; i++) {
-		int retval;
-
-		switch (p_type) {
-		case ASUS_OLED_ROLL:
-			setup_packet_header(packet, 0x40, 0x80, p_num,
-					    i + 1, 0x00, 0x01, 0xff);
-			break;
-		case ASUS_OLED_STATIC:
-			setup_packet_header(packet, 0x10 + i, 0x80, 0x01,
-					    0x01, 0x00, 0x01, 0x00);
-			break;
-		case ASUS_OLED_FLASH:
-			setup_packet_header(packet, 0x10 + i, 0x80, 0x01,
-					    0x01, 0x00, 0x00, 0xff);
-			break;
-		}
-
-		memcpy(packet->bitmap, buf + (ASUS_OLED_PACKET_BUF_SIZE*i),
-		       ASUS_OLED_PACKET_BUF_SIZE);
-
-		retval = usb_bulk_msg(udev, usb_sndctrlpipe(udev, 2),
-				      packet, sizeof(struct asus_oled_packet),
-				      &act_len, -1);
-
-		if (retval)
-			dev_dbg(&udev->dev, "retval = %d\n", retval);
-	}
-}
-
-static void send_packet(struct usb_device *udev,
-			struct asus_oled_packet *packet,
-			size_t offset, size_t len, char *buf, uint8_t b1,
-			uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
-			uint8_t b6) {
-	int retval;
-	int act_len;
-
-	setup_packet_header(packet, b1, b2, b3, b4, b5, b6, 0x00);
-	memcpy(packet->bitmap, buf + offset, len);
-
-	retval = usb_bulk_msg(udev,
-			      usb_sndctrlpipe(udev, 2),
-			      packet,
-			      sizeof(struct asus_oled_packet),
-			      &act_len,
-			      -1);
-
-	if (retval)
-		dev_dbg(&udev->dev, "retval = %d\n", retval);
-}
-
-
-static void send_packets_g50(struct usb_device *udev,
-			     struct asus_oled_packet *packet, char *buf)
-{
-	send_packet(udev, packet,     0, 0x100, buf,
-		    0x10, 0x00, 0x02, 0x01, 0x00, 0x01);
-	send_packet(udev, packet, 0x100, 0x080, buf,
-		    0x10, 0x00, 0x02, 0x02, 0x80, 0x00);
-
-	send_packet(udev, packet, 0x180, 0x100, buf,
-		    0x11, 0x00, 0x03, 0x01, 0x00, 0x01);
-	send_packet(udev, packet, 0x280, 0x100, buf,
-		    0x11, 0x00, 0x03, 0x02, 0x00, 0x01);
-	send_packet(udev, packet, 0x380, 0x080, buf,
-		    0x11, 0x00, 0x03, 0x03, 0x80, 0x00);
-}
-
-
-static void send_data(struct asus_oled_dev *odev)
-{
-	size_t packet_num = odev->buf_size / ASUS_OLED_PACKET_BUF_SIZE;
-	struct asus_oled_packet *packet;
-
-	packet = kzalloc(sizeof(struct asus_oled_packet), GFP_KERNEL);
-	if (!packet)
-		return;
-
-	if (odev->pack_mode == PACK_MODE_G1) {
-		/*
-		 * When sending roll-mode data the display updated only
-		 * first packet.  I have no idea why, but when static picture
-		 * is sent just before rolling picture everything works fine.
-		 */
-		if (odev->pic_mode == ASUS_OLED_ROLL)
-			send_packets(odev->udev, packet, odev->buf,
-				     ASUS_OLED_STATIC, 2);
-
-		/* Only ROLL mode can use more than 2 packets.*/
-		if (odev->pic_mode != ASUS_OLED_ROLL && packet_num > 2)
-			packet_num = 2;
-
-		send_packets(odev->udev, packet, odev->buf,
-			     odev->pic_mode, packet_num);
-	} else if (odev->pack_mode == PACK_MODE_G50) {
-		send_packets_g50(odev->udev, packet, odev->buf);
-	}
-
-	kfree(packet);
-}
-
-static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count)
-{
-	odev->last_val = val;
-
-	if (val == 0) {
-		odev->buf_offs += count;
-		return 0;
-	}
-
-	while (count-- > 0) {
-		size_t x = odev->buf_offs % odev->width;
-		size_t y = odev->buf_offs / odev->width;
-		size_t i;
-
-		x += odev->x_shift;
-		y += odev->y_shift;
-
-		switch (odev->pack_mode) {
-		case PACK_MODE_G1:
-			/*
-			 * i = (x/128)*640 + 127 - x + (y/8)*128;
-			 * This one for 128 is the same, but might be better
-			 * for different widths?
-			 */
-			i = (x/odev->dev_width)*640 +
-				odev->dev_width - 1 - x +
-				(y/8)*odev->dev_width;
-			break;
-
-		case PACK_MODE_G50:
-			i =  (odev->dev_width - 1 - x)/8 + y*odev->dev_width/8;
-			break;
-
-		default:
-			i = 0;
-			dev_err(odev->dev, "Unknown OLED Pack Mode: %d!\n",
-			       odev->pack_mode);
-			break;
-		}
-
-		if (i >= odev->buf_size) {
-			dev_err(odev->dev, "Buffer overflow! Report a bug: offs: %zu >= %zu i: %zu (x: %zu y: %zu)\n",
-			       odev->buf_offs, odev->buf_size, i, x, y);
-			return -EIO;
-		}
-
-		switch (odev->pack_mode) {
-		case PACK_MODE_G1:
-			odev->buf[i] &= ~(1<<(y%8));
-			break;
-
-		case PACK_MODE_G50:
-			odev->buf[i] &= ~(1<<(x%8));
-			break;
-
-		default:
-			/* cannot get here; stops gcc complaining*/
-			break;
-		}
-
-		odev->buf_offs++;
-	}
-
-	return 0;
-}
-
-static ssize_t odev_set_picture(struct asus_oled_dev *odev,
-				const char *buf, size_t count)
-{
-	size_t offs = 0, max_offs;
-
-	if (count < 1)
-		return 0;
-
-	if (tolower(buf[0]) == 'b') {
-		/* binary mode, set the entire memory*/
-
-		size_t i;
-
-		odev->buf_size = (odev->dev_width * ASUS_OLED_DISP_HEIGHT) / 8;
-
-		kfree(odev->buf);
-		odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
-		if (odev->buf == NULL) {
-			odev->buf_size = 0;
-			dev_err(odev->dev, "Out of memory!\n");
-			return -ENOMEM;
-		}
-
-		memset(odev->buf, 0xff, odev->buf_size);
-
-		for (i = 1; i < count && i <= 32 * 32; i++) {
-			odev->buf[i-1] = buf[i];
-			odev->buf_offs = i-1;
-		}
-
-		odev->width = odev->dev_width / 8;
-		odev->height = ASUS_OLED_DISP_HEIGHT;
-		odev->x_shift = 0;
-		odev->y_shift = 0;
-		odev->last_val =  0;
-
-		send_data(odev);
-
-		return count;
-	}
-
-	if (buf[0] == '<') {
-		size_t i;
-		size_t w = 0, h = 0;
-		size_t w_mem, h_mem;
-
-		if (count < 10 || buf[2] != ':')
-			goto error_header;
-
-
-		switch (tolower(buf[1])) {
-		case ASUS_OLED_STATIC:
-		case ASUS_OLED_ROLL:
-		case ASUS_OLED_FLASH:
-			odev->pic_mode = buf[1];
-			break;
-		default:
-			dev_err(odev->dev, "Wrong picture mode: '%c'.\n",
-			       buf[1]);
-			return -EIO;
-			break;
-		}
-
-		for (i = 3; i < count; ++i) {
-			if (buf[i] >= '0' && buf[i] <= '9') {
-				w = 10*w + (buf[i] - '0');
-
-				if (w > ASUS_OLED_MAX_WIDTH)
-					goto error_width;
-			} else if (tolower(buf[i]) == 'x') {
-				break;
-			} else {
-				goto error_width;
-			}
-		}
-
-		for (++i; i < count; ++i) {
-			if (buf[i] >= '0' && buf[i] <= '9') {
-				h = 10*h + (buf[i] - '0');
-
-				if (h > ASUS_OLED_DISP_HEIGHT)
-					goto error_height;
-			} else if (tolower(buf[i]) == '>') {
-				break;
-			} else {
-				goto error_height;
-			}
-		}
-
-		if (w < 1 || w > ASUS_OLED_MAX_WIDTH)
-			goto error_width;
-
-		if (h < 1 || h > ASUS_OLED_DISP_HEIGHT)
-			goto error_height;
-
-		if (i >= count || buf[i] != '>')
-			goto error_header;
-
-		offs = i+1;
-
-		if (w % (odev->dev_width) != 0)
-			w_mem = (w/(odev->dev_width) + 1)*(odev->dev_width);
-		else
-			w_mem = w;
-
-		if (h < ASUS_OLED_DISP_HEIGHT)
-			h_mem = ASUS_OLED_DISP_HEIGHT;
-		else
-			h_mem = h;
-
-		odev->buf_size = w_mem * h_mem / 8;
-
-		kfree(odev->buf);
-		odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
-
-		if (odev->buf == NULL) {
-			odev->buf_size = 0;
-			dev_err(odev->dev, "Out of memory!\n");
-			return -ENOMEM;
-		}
-
-		memset(odev->buf, 0xff, odev->buf_size);
-
-		odev->buf_offs = 0;
-		odev->width = w;
-		odev->height = h;
-		odev->x_shift = 0;
-		odev->y_shift = 0;
-		odev->last_val = 0;
-
-		if (odev->pic_mode == ASUS_OLED_FLASH) {
-			if (h < ASUS_OLED_DISP_HEIGHT/2)
-				odev->y_shift = (ASUS_OLED_DISP_HEIGHT/2 - h)/2;
-		} else {
-			if (h < ASUS_OLED_DISP_HEIGHT)
-				odev->y_shift = (ASUS_OLED_DISP_HEIGHT - h)/2;
-		}
-
-		if (w < (odev->dev_width))
-			odev->x_shift = ((odev->dev_width) - w)/2;
-	}
-
-	max_offs = odev->width * odev->height;
-
-	while (offs < count && odev->buf_offs < max_offs) {
-		int ret = 0;
-
-		if (buf[offs] == '1' || buf[offs] == '#') {
-			ret = append_values(odev, 1, 1);
-			if (ret < 0)
-				return ret;
-		} else if (buf[offs] == '0' || buf[offs] == ' ') {
-			ret = append_values(odev, 0, 1);
-			if (ret < 0)
-				return ret;
-		} else if (buf[offs] == '\n') {
-			/*
-			 * New line detected. Lets assume, that all characters
-			 * till the end of the line were equal to the last
-			 * character in this line.
-			 */
-			if (odev->buf_offs % odev->width != 0)
-				ret = append_values(odev, odev->last_val,
-						    odev->width -
-						    (odev->buf_offs %
-						     odev->width));
-			if (ret < 0)
-				return ret;
-		}
-
-		offs++;
-	}
-
-	if (odev->buf_offs >= max_offs)
-		send_data(odev);
-
-	return count;
-
-error_width:
-	dev_err(odev->dev, "Wrong picture width specified.\n");
-	return -EIO;
-
-error_height:
-	dev_err(odev->dev, "Wrong picture height specified.\n");
-	return -EIO;
-
-error_header:
-	dev_err(odev->dev, "Wrong picture header.\n");
-	return -EIO;
-}
-
-static ssize_t set_picture(struct device *dev, struct device_attribute *attr,
-			   const char *buf, size_t count)
-{
-	struct usb_interface *intf = to_usb_interface(dev);
-
-	return odev_set_picture(usb_get_intfdata(intf), buf, count);
-}
-
-static ssize_t class_set_picture(struct device *device,
-				 struct device_attribute *attr,
-				 const char *buf, size_t count)
-{
-	return odev_set_picture((struct asus_oled_dev *)
-				dev_get_drvdata(device), buf, count);
-}
-
-#define ASUS_OLED_DEVICE_ATTR(_file)		dev_attr_asus_oled_##_file
-
-static DEVICE_ATTR(asus_oled_enabled, S_IWUSR | S_IRUGO,
-		   get_enabled, set_enabled);
-static DEVICE_ATTR(asus_oled_picture, S_IWUSR , NULL, set_picture);
-
-static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO,
-		   class_get_enabled, class_set_enabled);
-static DEVICE_ATTR(picture, S_IWUSR, NULL, class_set_picture);
-
-static int asus_oled_probe(struct usb_interface *interface,
-			   const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(interface);
-	struct asus_oled_dev *odev = NULL;
-	int retval = -ENOMEM;
-	uint16_t dev_width = 0;
-	enum oled_pack_mode pack_mode = PACK_MODE_LAST;
-	const struct oled_dev_desc_str *dev_desc = oled_dev_desc_table;
-	const char *desc = NULL;
-
-	if (!id) {
-		/* Even possible? Just to make sure...*/
-		dev_err(&interface->dev, "No usb_device_id provided!\n");
-		return -ENODEV;
-	}
-
-	for (; dev_desc->idVendor; dev_desc++) {
-		if (dev_desc->idVendor == id->idVendor
-		    && dev_desc->idProduct == id->idProduct) {
-			dev_width = dev_desc->devWidth;
-			desc = dev_desc->devDesc;
-			pack_mode = dev_desc->packMode;
-			break;
-		}
-	}
-
-	if (!desc || dev_width < 1 || pack_mode == PACK_MODE_LAST) {
-		dev_err(&interface->dev,
-			"Missing or incomplete device description!\n");
-		return -ENODEV;
-	}
-
-	odev = kzalloc(sizeof(struct asus_oled_dev), GFP_KERNEL);
-	if (odev == NULL)
-		return -ENOMEM;
-
-	odev->udev = usb_get_dev(udev);
-	odev->pic_mode = ASUS_OLED_STATIC;
-	odev->dev_width = dev_width;
-	odev->pack_mode = pack_mode;
-	odev->height = 0;
-	odev->width = 0;
-	odev->x_shift = 0;
-	odev->y_shift = 0;
-	odev->buf_offs = 0;
-	odev->buf_size = 0;
-	odev->last_val = 0;
-	odev->buf = NULL;
-	odev->enabled = 1;
-	odev->dev = NULL;
-
-	usb_set_intfdata(interface, odev);
-
-	retval = device_create_file(&interface->dev,
-				    &ASUS_OLED_DEVICE_ATTR(enabled));
-	if (retval)
-		goto err_files;
-
-	retval = device_create_file(&interface->dev,
-				    &ASUS_OLED_DEVICE_ATTR(picture));
-	if (retval)
-		goto err_files;
-
-	odev->dev = device_create(oled_class, &interface->dev, MKDEV(0, 0),
-				  NULL, "oled_%d", ++oled_num);
-
-	if (IS_ERR(odev->dev)) {
-		retval = PTR_ERR(odev->dev);
-		goto err_files;
-	}
-
-	dev_set_drvdata(odev->dev, odev);
-
-	retval = device_create_file(odev->dev, &dev_attr_enabled);
-	if (retval)
-		goto err_class_enabled;
-
-	retval = device_create_file(odev->dev, &dev_attr_picture);
-	if (retval)
-		goto err_class_picture;
-
-	dev_info(&interface->dev,
-		 "Attached Asus OLED device: %s [width %u, pack_mode %d]\n",
-		 desc, odev->dev_width, odev->pack_mode);
-
-	if (start_off)
-		enable_oled(odev, 0);
-
-	return 0;
-
-err_class_picture:
-	device_remove_file(odev->dev, &dev_attr_picture);
-
-err_class_enabled:
-	device_remove_file(odev->dev, &dev_attr_enabled);
-	device_unregister(odev->dev);
-
-err_files:
-	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
-	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
-
-	usb_set_intfdata(interface, NULL);
-	usb_put_dev(odev->udev);
-	kfree(odev);
-
-	return retval;
-}
-
-static void asus_oled_disconnect(struct usb_interface *interface)
-{
-	struct asus_oled_dev *odev;
-
-	odev = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
-
-	device_remove_file(odev->dev, &dev_attr_picture);
-	device_remove_file(odev->dev, &dev_attr_enabled);
-	device_unregister(odev->dev);
-
-	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(picture));
-	device_remove_file(&interface->dev, &ASUS_OLED_DEVICE_ATTR(enabled));
-
-	usb_put_dev(odev->udev);
-
-	kfree(odev->buf);
-
-	kfree(odev);
-
-	dev_info(&interface->dev, "Disconnected Asus OLED device\n");
-}
-
-#ifdef CONFIG_PM
-static int asus_oled_suspend(struct usb_interface *intf, pm_message_t message)
-{
-	struct asus_oled_dev *odev;
-
-	odev = usb_get_intfdata(intf);
-	if (!odev)
-		return -ENODEV;
-
-	odev->enabled_post_resume = odev->enabled;
-	enable_oled(odev, 0);
-
-	return 0;
-}
-
-static int asus_oled_resume(struct usb_interface *intf)
-{
-	struct asus_oled_dev *odev;
-
-	odev = usb_get_intfdata(intf);
-	if (!odev)
-		return -ENODEV;
-
-	enable_oled(odev, odev->enabled_post_resume);
-
-	return 0;
-}
-#else
-#define asus_oled_suspend NULL
-#define asus_oled_resume NULL
-#endif
-
-static struct usb_driver oled_driver = {
-	.name =		ASUS_OLED_NAME,
-	.probe =	asus_oled_probe,
-	.disconnect =	asus_oled_disconnect,
-	.id_table =	id_table,
-	.suspend =	asus_oled_suspend,
-	.resume =	asus_oled_resume,
-};
-
-static CLASS_ATTR_STRING(version, S_IRUGO,
-			ASUS_OLED_UNDERSCORE_NAME " " ASUS_OLED_VERSION);
-
-static int __init asus_oled_init(void)
-{
-	int retval = 0;
-	oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME);
-
-	if (IS_ERR(oled_class)) {
-		pr_err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class\n");
-		return PTR_ERR(oled_class);
-	}
-
-	retval = class_create_file(oled_class, &class_attr_version.attr);
-	if (retval) {
-		pr_err("Error creating class version file\n");
-		goto error;
-	}
-
-	retval = usb_register(&oled_driver);
-
-	if (retval) {
-		pr_err("usb_register failed. Error number %d\n", retval);
-		goto error;
-	}
-
-	return retval;
-
-error:
-	class_destroy(oled_class);
-	return retval;
-}
-
-static void __exit asus_oled_exit(void)
-{
-	usb_deregister(&oled_driver);
-	class_remove_file(oled_class, &class_attr_version.attr);
-	class_destroy(oled_class);
-}
-
-module_init(asus_oled_init);
-module_exit(asus_oled_exit);
-
diff --git a/drivers/staging/asus_oled/linux.txt b/drivers/staging/asus_oled/linux.txt
deleted file mode 100644
index dc758b0..0000000
--- a/drivers/staging/asus_oled/linux.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<s:74x32>
-0
-0
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-01111111111000000000000000000000000000000000000000000000000000000000000000
-00011111100000000000000111000000000000000000000000000000000000000000000000
-00001111000000000000000111000000000000000000000000000000000000000000000000
-00001111000000000000000111000000000000000000000000000000000000000000000000
-00001111000000000000000000000000000000000000000000000000000000000000000000
-00001111000000000000000000000000000000000000000000000000000000000000000000
-00001111000000000000011100001111111111100000111110011111100011111101111000
-00001111000000000000111110000011111000111000111110000111100001111000110000
-00001111000000000001101110000011111000111000001111000111100000111100100000
-00001111000000000001001110000011110000111100001111000111100000111101100000
-00001111000000000100001110000011110000111100001111000111100000011111000000
-00001111000000000100011110000011110000111100001111000111100000001111000000
-00001111000000000100011110000011110000111100001111000111100000001111000000
-00001111000000000100011100100011110000111100001111000111100000001111100000
-00001111000000001100111100100011110000111100001111000111100000001111110000
-00001111000000001100111101100011110000111100001111000111100000011011110000
-00001111000000011100111101000011110000111100001111000111100000010001111000
-00011111000001111100111011000011110000111100001111001111100000110000111100
-11111111111111111100011110001111111011111110000111110111111011111011111110
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000
-0
-0
-0
-0
diff --git a/drivers/staging/asus_oled/linux_f.txt b/drivers/staging/asus_oled/linux_f.txt
deleted file mode 100644
index b4bb85c..0000000
--- a/drivers/staging/asus_oled/linux_f.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-<f:128x16>
-00000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011000111111111100001111001111100111110111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000111100001111000110001111000111100011100010000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000001011100001111000111000111100111100001110110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011100001110000111000111100111100001111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100111001001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111011001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111010001110000111000111100111100000100111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000111100110110001110000111000111100111100001000011100000000000000000000000000000000000
-00000000000000000000000000000000001111111111111100111100111111011111100011110111110111101111110000000000000000000000000000000000
-
diff --git a/drivers/staging/asus_oled/linux_fr.txt b/drivers/staging/asus_oled/linux_fr.txt
deleted file mode 100644
index f88e2b3..0000000
--- a/drivers/staging/asus_oled/linux_fr.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<f:128x32>
-00000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000001110000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011000111111111100001111001111100111110111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000111100001111000110001111000111100011100010000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000001011100001111000111000111100111100001110110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000000011100001110000111000111100111100001111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100011100001110000111000111100111100000111100000000000000000000000000000000000000
-00000000000000000000000000000000000011110000000100111001001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111011001110000111000111100111100000111110000000000000000000000000000000000000
-00000000000000000000000000000000000011110000001100111010001110000111000111100111100000100111000000000000000000000000000000000000
-00000000000000000000000000000000000011110000111100110110001110000111000111100111100001000011100000000000000000000000000000000000
-00000000000000000000000000000000001111111111111100111100111111011111100011110111110111101111110000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
-00000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000
-00000000000000000000000000011111100000000000000000000000000000000000000000000000000000000000011111100000000000000000000000000000
-00000000000000000000000000011111100000000000000000000000000000000000000000000000000000000000011111100000000000000000000000000000
-00000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000
-00000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/drivers/staging/asus_oled/tux.txt b/drivers/staging/asus_oled/tux.txt
deleted file mode 100644
index 9d20528..0000000
--- a/drivers/staging/asus_oled/tux.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<s:32x32>
-00000000000001111111000000000000
-0000000000001       100000000000
-000000000001         10000000000
-000000000001         10000000000
-000000000001         10000000000
-000000000001 1  111  10000000000
-000000000001    1 1   1000000000
-000000000001  111     1000000000
-000000000001 111111   1000000000
-000000000001 111111   1000000000
-000000000001    1 1    100000000
-00000000001      11    100000000
-00000000001 11111111    10000000
-0000000001  11111111     1000000
-000000001   111111111    1000000
-000000001  1111111111     100000
-00000001   11111111111    100000
-00000001  111111111111     10000
-0000001   111111111111     10000
-0000001   111111111111     10000
-0000001   111111111111     10000
-0000001   111111111111     10000
-000000011 11111111111      10000
-000011 11  11111111111    100000
-0001  1111  111111111111111 1000
-001 1111111  11111111111111 1000
-001 1111111  1111111  111111 100
-001 11111111 111111   1111111 10
-001 11111111          11111  100
-001  1111111          111  11100
-000111   111   11111  11  100000
-000000111   111111111    1000000
diff --git a/drivers/staging/asus_oled/tux_r.txt b/drivers/staging/asus_oled/tux_r.txt
deleted file mode 100644
index fd81a3e..0000000
--- a/drivers/staging/asus_oled/tux_r.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<r:32x32>
-00000000000001111111000000000000
-0000000000001       100000000000
-000000000001         10000000000
-000000000001         10000000000
-000000000001         10000000000
-000000000001 1  111  10000000000
-000000000001    1 1   1000000000
-000000000001  111     1000000000
-000000000001 111111   1000000000
-000000000001 111111   1000000000
-000000000001    1 1    100000000
-00000000001      11    100000000
-00000000001 11111111    10000000
-0000000001  11111111     1000000
-000000001   111111111    1000000
-000000001  1111111111     100000
-00000001   11111111111    100000
-00000001  111111111111     10000
-0000001   111111111111     10000
-0000001   111111111111     10000
-0000001   111111111111     10000
-0000001   111111111111     10000
-000000011 11111111111      10000
-000011 11  11111111111    100000
-0001  1111  111111111111111 1000
-001 1111111  11111111111111 1000
-001 1111111  1111111  111111 100
-001 11111111 111111   1111111 10
-001 11111111          11111  100
-001  1111111          111  11100
-000111   111   11111  11  100000
-000000111   111111111    1000000
diff --git a/drivers/staging/asus_oled/tux_r2.txt b/drivers/staging/asus_oled/tux_r2.txt
deleted file mode 100644
index e94d84e..0000000
--- a/drivers/staging/asus_oled/tux_r2.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<r:256x32>
-000000000000000000000000000000000000000000000000000000000000011111110000000000000000000000000000000000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000000000001       1000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001         1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001         1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001         1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 1  111  1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001    1 1   100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001  111     100000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111100000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 111111   100000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001 111111   100000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000111000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000001    1 1    10000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000001      11    10000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000000001 11111111    1000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000011100001111111111100000111110011111100011111101111000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000000001  11111111     100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000111110000011111000111000111110000111100001111000110000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000001   111111111    100000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000001101110000011111000111000001111000111100000111100100000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000001  1111111111     10000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000001001110000011110000111100001111000111100000111101100000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000001   11111111111    10000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100001110000011110000111100001111000111100000011111000000000000000000000000000000000
-00000000000000000000000000000000000000000000000000000001  111111111111     10000000000000000000000000000000000000000000000000000000000000000000000000000000000011110000000001000111100000111100001111000011110001111000000011110000000
-0000000000000000000000000000000000000000000000000000001   111111111111     1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100011110000011110000111100001111000111100000001111000000
-0000000000000000000000000000000000000000000000000000001   111111111111     1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000100011100100011110000111100001111000111100000001111100000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000001   111111111111     1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000001100111100100011110000111100001111000111100000001111110000000000000000000000000000000
-0000000000000000000000000000000000000000000000000000001   111111111111     1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000001100111101100011110000111100001111000111100000011011110000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000011 11111111111      1000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000011100111101000011110000111100001111000111100000010001111000000000000000000000000000000
-000000000000000000000000000000000000000000000000000011 11  11111111111    10000000000000000000000000000000000000000000000000000000000000000000000000000000000011111000001111100111011000011110000111100001111001111100000110000111100000000000000000000000000000
-0000000000000000000000000000000000000000000000000001  1111  111111111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111100011110001111111011111110000111110111111011111011111110000000000000000000000000000
-000000000000000000000000000000000000000000000000001 1111111  11111111111111 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 1111111  1111111  111111 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 11111111 111111   1111111 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001 11111111          11111  1000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000001  1111111          111  111000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000111   111   11111  11  10
-000000000000000000000000000000000000000000000000000000111   111111111    10
diff --git a/drivers/staging/asus_oled/zig.txt b/drivers/staging/asus_oled/zig.txt
deleted file mode 100644
index 31573d8..0000000
--- a/drivers/staging/asus_oled/zig.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-<r:128x32>
-10000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000001
-01000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000000000010
-00100000000000000000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000100
-00010000000000000000000000000000000000000000000000000000000010000001000000000000000000000000000000000000000000000000000000001000
-00001000000000000000000000000000000000000000000000000000000100000000100000000000000000000000000000000000000000000000000000010000
-00000100000000000000000000000000000000000000000000000000001000000000010000000000000000000000000000000000000000000000000000100000
-00000010000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000001000000
-00000001000000000000000000000000000000000000000000000000100000000000000100000000000000000000000000000000000000000000000010000000
-00000000100000000000000000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000100000000
-00000000010000000000000000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000001000000000
-00000000001000000000000000000000000000000000000000000100000000000000000000100000000000000000000000000000000000000000010000000000
-00000000000100000000000000000000000000000000000000001000000000000000000000010000000000000000000000000000000000000000100000000000
-00000000000010000000000000000000000000000000000000010000000000000000000000001000000000000000000000000000000000000001000000000000
-00000000000001000000000000000000000000000000000000100000000000000000000000000100000000000000000000000000000000000010000000000000
-00000000000000100000000000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000100000000000000
-00000000000000010000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000001000000000000000
-00000000000000001000000000000000000000000000000100000000000000000000000000000000100000000000000000000000000000010000000000000000
-00000000000000000100000000000000000000000000001000000000000000000000000000000000010000000000000000000000000000100000000000000000
-00000000000000000010000000000000000000000000010000000000000000000000000000000000001000000000000000000000000001000000000000000000
-00000000000000000001000000000000000000000000100000000000000000000000000000000000000100000000000000000000000010000000000000000000
-00000000000000000000100000000000000000000001000000000000000000000000000000000000000010000000000000000000000100000000000000000000
-00000000000000000000010000000000000000000010000000000000000000000000000000000000000001000000000000000000001000000000000000000000
-00000000000000000000001000000000000000000100000000000000000000000000000000000000000000100000000000000000010000000000000000000000
-00000000000000000000000100000000000000001000000000000000000000000000000000000000000000010000000000000000100000000000000000000000
-00000000000000000000000010000000000000010000000000000000000000000000000000000000000000001000000000000001000000000000000000000000
-00000000000000000000000001000000000000100000000000000000000000000000000000000000000000000100000000000010000000000000000000000000
-00000000000000000000000000100000000001000000000000000000000000000000000000000000000000000010000000000100000000000000000000000000
-00000000000000000000000000010000000010000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000
-00000000000000000000000000001000000100000000000000000000000000000000000000000000000000000000100000010000000000000000000000000000
-00000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000010000100000000000000000000000000000
-00000000000000000000000000000010010000000000000000000000000000000000000000000000000000000000001001000000000000000000000000000000
-00000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index f67a225..f91bc1f 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -1004,9 +1004,9 @@
 		if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer)))
 			return -EFAULT;
 
-		len = min_t(ulong, IoBuffer.OutputLength, strlen(VER_FILEVERSION_STR) + 1);
+		len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1);
 
-		if (copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, len))
+		if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len))
 			return -EFAULT;
 		Status = STATUS_SUCCESS;
 		break;
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 8c696b6..f5eda96 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -828,13 +828,13 @@
 		{
 				retval= rdmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
 				if(retval < 0) {
-					BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+					BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 					return retval;
 				}
 				uiResetValue |= 0x44;
 				retval = wrmalt(Adapter,(UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
 				if(retval < 0) {
-					BCM_DEBUG_PRINT(Adapter,CMHOST, WRM, DBG_LVL_ALL, "%s:%d WRM failed\n", __FUNCTION__, __LINE__);
+					BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 					return retval;
 				}
 		}
@@ -972,7 +972,7 @@
 		}
 		retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value, sizeof(value));
 		if(STATUS_SUCCESS != retval) {
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
 			break;
 		}
 
@@ -992,25 +992,25 @@
 			uiResetValue = 0x01010001;
 			retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x00040020;
 			retval = wrmalt(Adapter, (UINT)0x0F007094, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x01020101;
 			retval = wrmalt(Adapter, (UINT)0x0F00701c, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x01010000;
 			retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 		}
@@ -1026,34 +1026,34 @@
 		{
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x1322a8;
 			retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x132296;
 			retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 		}
@@ -1062,34 +1062,34 @@
 
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x6003229a;
 			retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			retval = rdmalt(Adapter,(UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 			uiResetValue = 0x1322a8;
 			retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue));
 			if(retval < 0) {
-				BCM_DEBUG_PRINT(Adapter,CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __FUNCTION__, __LINE__);
+				BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
 				return retval;
 			}
 		}
@@ -1235,28 +1235,28 @@
 	retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
 	if(retval)
 	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
 
 		return retval;
 	}
-	ul_ddr_setting_load_addr+=sizeof(ULONG);
+	ul_ddr_setting_load_addr += sizeof(ULONG);
 	/*signature */
 	value =(0x1d1e0dd0);
 	retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
 	if(retval)
 	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
 		return retval;
 	}
 
-	ul_ddr_setting_load_addr+=sizeof(ULONG);
+	ul_ddr_setting_load_addr += sizeof(ULONG);
 	RegCount*=(sizeof(struct bcm_ddr_setting)/sizeof(ULONG));
 
 	while(RegCount && !retval)
 	{
 		value = psDDRSetting->ulRegAddress ;
 		retval = wrmalt( Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
-		ul_ddr_setting_load_addr+=sizeof(ULONG);
+		ul_ddr_setting_load_addr += sizeof(ULONG);
 		if(!retval)
 		{
 			if(bOverrideSelfRefresh && (psDDRSetting->ulRegAddress == 0x0F007018))
@@ -1264,7 +1264,7 @@
 				value = (psDDRSetting->ulRegValue |(1<<8));
 				if(STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr,
 						&value, sizeof(value))){
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
 					break;
 				}
 			}
@@ -1274,12 +1274,12 @@
 
 				if(STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr ,
 							&value, sizeof(value))){
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%s:%d\n", __FUNCTION__, __LINE__);
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
 					break;
 				}
 			}
 		}
-		ul_ddr_setting_load_addr+=sizeof(ULONG);
+		ul_ddr_setting_load_addr += sizeof(ULONG);
 		RegCount--;
 		psDDRSetting++;
 	}
diff --git a/drivers/staging/bcm/Ioctl.h b/drivers/staging/bcm/Ioctl.h
index e253c08..797f862 100644
--- a/drivers/staging/bcm/Ioctl.h
+++ b/drivers/staging/bcm/Ioctl.h
@@ -175,7 +175,7 @@
 
 /*
  * This section provide the complete bitmap of the Flash.
- * using this map lib/APP will isssue read/write command.
+ * using this map lib/APP will issue read/write command.
  * Fields are defined as :
  * Bit [0] = section is present  //1:present, 0: Not present
  * Bit [1] = section is valid  //1: valid, 0: not valid
diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c
index 877cf0b..bc48616 100644
--- a/drivers/staging/bcm/LeakyBucket.c
+++ b/drivers/staging/bcm/LeakyBucket.c
@@ -17,47 +17,42 @@
 
 static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter)
 {
-	ULONG 	liCurrentTime;
-	INT 	i = 0;
+	ULONG liCurrentTime;
+	INT i = 0;
 	struct timeval tv;
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL,
 			"=====>\n");
-	if(NULL == Adapter)
-	{
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, 
+	if (NULL == Adapter) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS,
 				DBG_LVL_ALL, "Adapter found NULL!\n");
 		return;
 	}
 
 	do_gettimeofday(&tv);
-	for(i = 0; i < NO_OF_QUEUES; i++)
-	{
-		if(TRUE == Adapter->PackInfo[i].bValid &&
-			(1 == Adapter->PackInfo[i].ucDirection))
-		{
+	for (i = 0; i < NO_OF_QUEUES; i++) {
+		if (TRUE == Adapter->PackInfo[i].bValid &&
+		    (1 == Adapter->PackInfo[i].ucDirection)) {
 			liCurrentTime = ((tv.tv_sec-
 				Adapter->PackInfo[i].stLastUpdateTokenAt.tv_sec)*1000 +
 				(tv.tv_usec-Adapter->PackInfo[i].stLastUpdateTokenAt.tv_usec)/
 				1000);
-			if(0!=liCurrentTime)
-			{
+			if (0 != liCurrentTime) {
 				Adapter->PackInfo[i].uiCurrentTokenCount += (ULONG)
 					((Adapter->PackInfo[i].uiMaxAllowedRate) *
 					((ULONG)((liCurrentTime)))/1000);
 				memcpy(&Adapter->PackInfo[i].stLastUpdateTokenAt,
 					&tv, sizeof(struct timeval));
 				Adapter->PackInfo[i].liLastUpdateTokenAt = liCurrentTime;
-				if((Adapter->PackInfo[i].uiCurrentTokenCount) >=
-				Adapter->PackInfo[i].uiMaxBucketSize)
-				{
+				if (Adapter->PackInfo[i].uiCurrentTokenCount >=
+				    Adapter->PackInfo[i].uiMaxBucketSize) {
 					Adapter->PackInfo[i].uiCurrentTokenCount =
 						Adapter->PackInfo[i].uiMaxBucketSize;
 				}
 			}
 		}
 	}
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n");
 	return;
 
 }
@@ -79,33 +74,26 @@
 ***********************************************************************/
 static ULONG GetSFTokenCount(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF)
 {
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
 	/* Validate the parameters */
-	if(NULL == Adapter || (psSF < Adapter->PackInfo &&
-		(uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority]))
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo));
+	if (NULL == Adapter || (psSF < Adapter->PackInfo &&
+	    (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority])) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo));
 		return 0;
 	}
 
-	if(FALSE != psSF->bValid && psSF->ucDirection)
-	{
-		if(0 != psSF->uiCurrentTokenCount)
-		{
+	if (FALSE != psSF->bValid && psSF->ucDirection) {
+		if (0 != psSF->uiCurrentTokenCount) {
 				return psSF->uiCurrentTokenCount;
-		}
-		else
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n",
+		} else {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n",
 				psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount);
 			psSF->uiPendedLast = 1;
 		}
+	} else {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo);
 	}
-	else
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo);
-	}
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <===");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <===");
 	return 0;
 }
 
@@ -116,33 +104,29 @@
 */
 static INT SendPacketFromQueue(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/
 			struct bcm_packet_info *psSF, /**<Queue identifier*/
-			       struct sk_buff*  Packet)	/**<Pointer to the packet to be sent*/
+			       struct sk_buff *Packet)	/**<Pointer to the packet to be sent*/
 {
-	INT  	Status=STATUS_FAILURE;
-	UINT uiIndex =0,PktLen = 0;
+	INT Status = STATUS_FAILURE;
+	UINT uiIndex = 0, PktLen = 0;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "=====>");
-	if(!Adapter || !Packet || !psSF)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "Got NULL Adapter or Packet");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "=====>");
+	if (!Adapter || !Packet || !psSF) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "Got NULL Adapter or Packet");
 		return -EINVAL;
 	}
 
-	if(psSF->liDrainCalculated==0)
-	{
+	if (psSF->liDrainCalculated == 0)
 		psSF->liDrainCalculated = jiffies;
-	}
-	///send the packet to the fifo..
+	/* send the packet to the fifo.. */
 	PktLen = Packet->len;
 	Status = SetupNextSend(Adapter, Packet, psSF->usVCID_Value);
-	if(Status == 0)
-	{
-		for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++)
-		{	if((PktLen <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (PktLen > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
+	if (Status == 0) {
+		for (uiIndex = 0; uiIndex < MIBS_MAX_HIST_ENTRIES; uiIndex++) {
+			if ((PktLen <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (PktLen > MIBS_PKTSIZEHIST_RANGE*(uiIndex)))
 				Adapter->aTxPktSizeHist[uiIndex]++;
 		}
 	}
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "<=====");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "<=====");
 	return Status;
 }
 
@@ -160,107 +144,93 @@
 ****************************************************************************/
 static VOID CheckAndSendPacketFromIndex(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF)
 {
-	struct sk_buff	*QueuePacket=NULL;
-	char 			*pControlPacket = NULL;
-	INT				Status=0;
-	int				iPacketLen=0;
+	struct sk_buff *QueuePacket = NULL;
+	char *pControlPacket = NULL;
+	INT Status = 0;
+	int iPacketLen = 0;
 
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo));
-	if((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount))//Get data packet
-  	{
-		if(!psSF->ucDirection )
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo));
+	if ((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount)) { /* Get data packet */
+		if (!psSF->ucDirection)
 			return;
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount ");
-		if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount ");
+		if (Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
 			return;	/* in idle mode */
 
-		// Check for Free Descriptors
-		if(atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..",atomic_read(&Adapter->CurrNumFreeTxDesc));
-			return ;
+		/* Check for Free Descriptors */
+		if (atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..", atomic_read(&Adapter->CurrNumFreeTxDesc));
+			return;
 		}
 
 		spin_lock_bh(&psSF->SFQueueLock);
-		QueuePacket=psSF->FirstTxQueue;
+		QueuePacket = psSF->FirstTxQueue;
 
-		if(QueuePacket)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet");
+		if (QueuePacket) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet");
 
-			if(psSF->bEthCSSupport)
+			if (psSF->bEthCSSupport)
 				iPacketLen = QueuePacket->len;
 			else
 				iPacketLen = QueuePacket->len-ETH_HLEN;
 
-			iPacketLen<<=3;
-			if(iPacketLen <= GetSFTokenCount(Adapter, psSF))
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d",
+			iPacketLen <<= 3;
+			if (iPacketLen <= GetSFTokenCount(Adapter, psSF)) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d",
 					(iPacketLen >> 3));
 
-				DEQUEUEPACKET(psSF->FirstTxQueue,psSF->LastTxQueue);
+				DEQUEUEPACKET(psSF->FirstTxQueue, psSF->LastTxQueue);
 				psSF->uiCurrentBytesOnHost -= (QueuePacket->len);
 				psSF->uiCurrentPacketsOnHost--;
 				atomic_dec(&Adapter->TotalPacketCount);
 				spin_unlock_bh(&psSF->SFQueueLock);
 
-			   	Status = SendPacketFromQueue(Adapter, psSF, QueuePacket);
+				Status = SendPacketFromQueue(Adapter, psSF, QueuePacket);
 				psSF->uiPendedLast = FALSE;
-			}
-			else
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo);
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n",
+			} else {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n",
 					psSF->uiCurrentTokenCount, iPacketLen);
-				//this part indicates that because of non-availability of the tokens
-				//pkt has not been send out hence setting the pending flag indicating the host to send it out
-				//first next iteration  .
+				/*
+				this part indicates that because of non-availability of the tokens
+				pkt has not been send out hence setting the pending flag indicating the host to send it out
+				first next iteration.
+				*/
 				psSF->uiPendedLast = TRUE;
 				spin_unlock_bh(&psSF->SFQueueLock);
 			}
-		}
-		else
-		{
+		} else {
 			spin_unlock_bh(&psSF->SFQueueLock);
 		}
-	}
-	else
-	{
+	} else {
 
-		if((atomic_read(&Adapter->CurrNumFreeTxDesc) > 0 ) &&
-			(atomic_read(&Adapter->index_rd_txcntrlpkt) !=
-			 atomic_read(&Adapter->index_wr_txcntrlpkt))
-			)
-		{
+		if ((atomic_read(&Adapter->CurrNumFreeTxDesc) > 0) &&
+		    (atomic_read(&Adapter->index_rd_txcntrlpkt) !=
+		     atomic_read(&Adapter->index_wr_txcntrlpkt))) {
 			pControlPacket = Adapter->txctlpacket
 			[(atomic_read(&Adapter->index_rd_txcntrlpkt)%MAX_CNTRL_PKTS)];
-			if(pControlPacket)
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet");
+			if (pControlPacket) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet");
 				Status = SendControlPacket(Adapter, pControlPacket);
-				if(STATUS_SUCCESS==Status)
-				{
+				if (STATUS_SUCCESS == Status) {
 					spin_lock_bh(&psSF->SFQueueLock);
 					psSF->NumOfPacketsSent++;
-					psSF->uiSentBytes+=((struct bcm_leader *)pControlPacket)->PLength;
+					psSF->uiSentBytes += ((struct bcm_leader *)pControlPacket)->PLength;
 					psSF->uiSentPackets++;
 					atomic_dec(&Adapter->TotalPacketCount);
 					psSF->uiCurrentBytesOnHost -= ((struct bcm_leader *)pControlPacket)->PLength;
 					psSF->uiCurrentPacketsOnHost--;
 					atomic_inc(&Adapter->index_rd_txcntrlpkt);
 					spin_unlock_bh(&psSF->SFQueueLock);
+				} else {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n");
 				}
-				else
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n");
+			} else {
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong....");
 			}
-			else
-			{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong....");
-			}
-	   	}
+		}
 	}
 }
 
@@ -277,79 +247,71 @@
 ********************************************************************/
 VOID transmit_packets(struct bcm_mini_adapter *Adapter)
 {
-	UINT 	uiPrevTotalCount = 0;
+	UINT uiPrevTotalCount = 0;
 	int iIndex = 0;
 
-	BOOLEAN exit_flag = TRUE ;
+	BOOLEAN exit_flag = TRUE;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "=====>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "=====>");
 
-	if(NULL == Adapter)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX,TX_PACKETS, DBG_LVL_ALL, "Got NULL Adapter");
+	if (NULL == Adapter) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Got NULL Adapter");
 		return;
 	}
-	if(Adapter->device_removed == TRUE)
-	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device removed");
+	if (Adapter->device_removed == TRUE) {
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device removed");
 		return;
 	}
 
-    BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nUpdateTokenCount ====>\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nUpdateTokenCount ====>\n");
 
 	UpdateTokenCount(Adapter);
 
-    BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nPruneQueueAllSF ====>\n");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nPruneQueueAllSF ====>\n");
 
 	PruneQueueAllSF(Adapter);
 
 	uiPrevTotalCount = atomic_read(&Adapter->TotalPacketCount);
 
-	for(iIndex=HiPriority;iIndex>=0;iIndex--)
-	{
-		if(	!uiPrevTotalCount || (TRUE == Adapter->device_removed))
+	for (iIndex = HiPriority; iIndex >= 0; iIndex--) {
+		if (!uiPrevTotalCount || (TRUE == Adapter->device_removed))
 				break;
 
-		if(Adapter->PackInfo[iIndex].bValid &&
-			Adapter->PackInfo[iIndex].uiPendedLast &&
-			Adapter->PackInfo[iIndex].uiCurrentBytesOnHost)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
+		if (Adapter->PackInfo[iIndex].bValid &&
+		    Adapter->PackInfo[iIndex].uiPendedLast &&
+		    Adapter->PackInfo[iIndex].uiCurrentBytesOnHost) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
 			CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]);
 			uiPrevTotalCount--;
 		}
 	}
 
-	while(uiPrevTotalCount > 0 && !Adapter->device_removed)
-	{
-		exit_flag = TRUE ;
-			//second iteration to parse non-pending queues
-		for(iIndex=HiPriority;iIndex>=0;iIndex--)
-		{
-			if( !uiPrevTotalCount || (TRUE == Adapter->device_removed))
-					break;
+	while (uiPrevTotalCount > 0 && !Adapter->device_removed) {
+		exit_flag = TRUE;
+		/* second iteration to parse non-pending queues */
+		for (iIndex = HiPriority; iIndex >= 0; iIndex--) {
+			if (!uiPrevTotalCount || (TRUE == Adapter->device_removed))
+				break;
 
-			if(Adapter->PackInfo[iIndex].bValid &&
-				Adapter->PackInfo[iIndex].uiCurrentBytesOnHost &&
-				!Adapter->PackInfo[iIndex].uiPendedLast )
-			{
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
+			if (Adapter->PackInfo[iIndex].bValid &&
+			    Adapter->PackInfo[iIndex].uiCurrentBytesOnHost &&
+			    !Adapter->PackInfo[iIndex].uiPendedLast) {
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex..");
 				CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]);
 				uiPrevTotalCount--;
 				exit_flag = FALSE;
 			}
 		}
 
-		if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
-		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "In Idle Mode\n");
+		if (Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) {
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "In Idle Mode\n");
 			break;
 		}
-		if(exit_flag == TRUE )
-		    break ;
-	}/* end of inner while loop */
+		if (exit_flag == TRUE)
+			break;
+	} /* end of inner while loop */
 
-	update_per_cid_rx  (Adapter);
+	update_per_cid_rx(Adapter);
 	Adapter->txtransmit_running = 0;
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======");
 }
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index d23eeeb..4cfc2c3 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -210,7 +210,7 @@
  * @ingroup ctrl_pkt_functions
  * This function copies the contents of given buffer
  * to the control packet and queues it for transmission.
- * @note Do not acquire the spinock, as it it already acquired.
+ * @note Do not acquire the spinlock, as it it already acquired.
  * @return  SUCCESS/FAILURE.
  * Arguments:
  * Logical Adapter
diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c
index 8d142a5..2d4a77c 100644
--- a/drivers/staging/bcm/Qos.c
+++ b/drivers/staging/bcm/Qos.c
@@ -4,11 +4,11 @@
 */
 #include "headers.h"
 
-static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload, struct bcm_eth_packet_info *pstEthCsPktInfo);
-static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo,struct bcm_classifier_rule *pstClassifierRule, B_UINT8 EthCSCupport);
+static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload, struct bcm_eth_packet_info *pstEthCsPktInfo);
+static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo, struct bcm_classifier_rule *pstClassifierRule, B_UINT8 EthCSCupport);
 
 static USHORT	IpVersion4(struct bcm_mini_adapter *Adapter, struct iphdr *iphd,
-			   struct bcm_classifier_rule *pstClassifierRule );
+			   struct bcm_classifier_rule *pstClassifierRule);
 
 static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex);
 
@@ -20,30 +20,30 @@
 *				matches with that of Queue.
 *
 * Parameters  - pstClassifierRule: Pointer to the packet info structure.
-* 			  - ulSrcIP	    : Source IP address from the packet.
+*		- ulSrcIP	    : Source IP address from the packet.
 *
 * Returns     - TRUE(If address matches) else FAIL .
 *********************************************************************/
-BOOLEAN MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ulSrcIP)
+BOOLEAN MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULONG ulSrcIP)
 {
-    UCHAR 	ucLoopIndex=0;
+	UCHAR ucLoopIndex = 0;
 
-    struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-    ulSrcIP=ntohl(ulSrcIP);
-    if(0 == pstClassifierRule->ucIPSourceAddressLength)
-       	return TRUE;
-    for(ucLoopIndex=0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength);ucLoopIndex++)
-    {
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]);
-		if((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP)==
-				(pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] ))
-       	{
-       		return TRUE;
-       	}
-    }
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched");
-   	return FALSE;
+	ulSrcIP = ntohl(ulSrcIP);
+	if (0 == pstClassifierRule->ucIPSourceAddressLength)
+		return TRUE;
+	for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++)
+	{
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]);
+		if ((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP) ==
+				(pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex]))
+		{
+			return TRUE;
+		}
+	}
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched");
+	return FALSE;
 }
 
 
@@ -54,30 +54,30 @@
 *				matches with that of Queue.
 *
 * Parameters  - pstClassifierRule: Pointer to the packet info structure.
-* 			  - ulDestIP    : Destination IP address from the packet.
+*		- ulDestIP    : Destination IP address from the packet.
 *
 * Returns     - TRUE(If address matches) else FAIL .
 *********************************************************************/
-BOOLEAN MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule,ULONG ulDestIP)
+BOOLEAN MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULONG ulDestIP)
 {
-	UCHAR 	ucLoopIndex=0;
+	UCHAR ucLoopIndex = 0;
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-	ulDestIP=ntohl(ulDestIP);
-    if(0 == pstClassifierRule->ucIPDestinationAddressLength)
-       	return TRUE;
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x  ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]);
+	ulDestIP = ntohl(ulDestIP);
+	if (0 == pstClassifierRule->ucIPDestinationAddressLength)
+		return TRUE;
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x  ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]);
 
-    for(ucLoopIndex=0;ucLoopIndex<(pstClassifierRule->ucIPDestinationAddressLength);ucLoopIndex++)
-    {
-		if((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP)==
-					(pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex]))
-       	{
-       		return TRUE;
-       	}
-    }
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched");
-    return FALSE;
+	for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++)
+	{
+		if ((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP) ==
+				(pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex]))
+		{
+			return TRUE;
+		}
+	}
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched");
+	return FALSE;
 }
 
 
@@ -87,23 +87,23 @@
 * Description - Checks the TOS from the packet matches with that of queue.
 *
 * Parameters  - pstClassifierRule   : Pointer to the packet info structure.
-* 			  - ucTypeOfService: TOS from the packet.
+*		- ucTypeOfService: TOS from the packet.
 *
 * Returns     - TRUE(If address matches) else FAIL.
 **************************************************************************/
-BOOLEAN MatchTos(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucTypeOfService)
+BOOLEAN MatchTos(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucTypeOfService)
 {
 
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
-    if( 3 != pstClassifierRule->ucIPTypeOfServiceLength )
-       	return TRUE;
+	if (3 != pstClassifierRule->ucIPTypeOfServiceLength)
+		return TRUE;
 
-    if(((pstClassifierRule->ucTosMask & ucTypeOfService)<=pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService)>=pstClassifierRule->ucTosLow))
-    {
-       	return TRUE;
-    }
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched");
-    return FALSE;
+	if (((pstClassifierRule->ucTosMask & ucTypeOfService) <= pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService) >= pstClassifierRule->ucTosLow))
+	{
+		return TRUE;
+	}
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched");
+	return FALSE;
 }
 
 
@@ -113,26 +113,26 @@
 * Description - Checks the protocol from the packet matches with that of queue.
 *
 * Parameters  - pstClassifierRule: Pointer to the packet info structure.
-* 			  - ucProtocol	: Protocol from the packet.
+*		- ucProtocol	: Protocol from the packet.
 *
 * Returns     - TRUE(If address matches) else FAIL.
 ****************************************************************************/
-bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtocol)
+bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucProtocol)
 {
-   	UCHAR 	ucLoopIndex=0;
+	UCHAR ucLoopIndex = 0;
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	if(0 == pstClassifierRule->ucProtocolLength)
-      	return TRUE;
-	for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucProtocolLength;ucLoopIndex++)
-    {
-       	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X",ucProtocol,pstClassifierRule->ucProtocol[ucLoopIndex]);
-       	if(pstClassifierRule->ucProtocol[ucLoopIndex]==ucProtocol)
-       	{
-       		return TRUE;
-       	}
-    }
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched");
-   	return FALSE;
+	if (0 == pstClassifierRule->ucProtocolLength)
+		return TRUE;
+	for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++)
+	{
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X", ucProtocol, pstClassifierRule->ucProtocol[ucLoopIndex]);
+		if (pstClassifierRule->ucProtocol[ucLoopIndex] == ucProtocol)
+		{
+			return TRUE;
+		}
+	}
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched");
+	return FALSE;
 }
 
 
@@ -142,29 +142,29 @@
 * Description - Checks, Source port from the packet matches with that of queue.
 *
 * Parameters  - pstClassifierRule: Pointer to the packet info structure.
-* 			  - ushSrcPort	: Source port from the packet.
+*		- ushSrcPort	: Source port from the packet.
 *
 * Returns     - TRUE(If address matches) else FAIL.
 ***************************************************************************/
-bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort)
+bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushSrcPort)
 {
-    	UCHAR 	ucLoopIndex=0;
+	UCHAR ucLoopIndex = 0;
 
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
 
-    	if(0 == pstClassifierRule->ucSrcPortRangeLength)
-        	return TRUE;
-    	for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucSrcPortRangeLength;ucLoopIndex++)
-    	{
-        	if(ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] &&
-		    ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex])
-	    	{
-		    	return TRUE;
-	    	}
-    	}
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ",ushSrcPort);
-    	return FALSE;
+	if (0 == pstClassifierRule->ucSrcPortRangeLength)
+		return TRUE;
+	for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++)
+	{
+		if (ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] &&
+			ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex])
+		{
+			return TRUE;
+		}
+	}
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ", ushSrcPort);
+	return FALSE;
 }
 
 
@@ -174,30 +174,30 @@
 * Description - Checks, Destination port from packet matches with that of queue.
 *
 * Parameters  - pstClassifierRule: Pointer to the packet info structure.
-* 			  - ushDestPort	: Destination port from the packet.
+*		- ushDestPort	: Destination port from the packet.
 *
 * Returns     - TRUE(If address matches) else FAIL.
 ***************************************************************************/
-bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushDestPort)
+bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushDestPort)
 {
-    	UCHAR 	ucLoopIndex=0;
+	UCHAR ucLoopIndex = 0;
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-    	if(0 == pstClassifierRule->ucDestPortRangeLength)
-        	return TRUE;
+	if (0 == pstClassifierRule->ucDestPortRangeLength)
+		return TRUE;
 
-    	for(ucLoopIndex=0;ucLoopIndex<pstClassifierRule->ucDestPortRangeLength;ucLoopIndex++)
-    	{
-        	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X   0x%X  0x%X",ushDestPort,pstClassifierRule->usDestPortRangeLo[ucLoopIndex],pstClassifierRule->usDestPortRangeHi[ucLoopIndex]);
+	for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++)
+	{
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X   0x%X  0x%X", ushDestPort, pstClassifierRule->usDestPortRangeLo[ucLoopIndex], pstClassifierRule->usDestPortRangeHi[ucLoopIndex]);
 
- 		if(ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] &&
-		    ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex])
-	    	{
-		    return TRUE;
-	    	}
-    	}
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched",ushDestPort);
-    	return FALSE;
+		if (ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] &&
+			ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex])
+		{
+			return TRUE;
+		}
+	}
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched", ushDestPort);
+	return FALSE;
 }
 /**
 @ingroup tx_functions
@@ -209,95 +209,95 @@
 			   struct bcm_classifier_rule *pstClassifierRule)
 {
 	struct bcm_transport_header *xprt_hdr = NULL;
-	BOOLEAN	bClassificationSucceed=FALSE;
+	BOOLEAN	bClassificationSucceed = FALSE;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "========>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "========>");
 
-	xprt_hdr=(struct bcm_transport_header *)((PUCHAR)iphd + sizeof(struct iphdr));
+	xprt_hdr = (struct bcm_transport_header *)((PUCHAR)iphd + sizeof(struct iphdr));
 
 	do {
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to see Direction = %d %d",
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to see Direction = %d %d",
 			pstClassifierRule->ucDirection,
 			pstClassifierRule->usVCID_Value);
 
 		//Checking classifier validity
-		if(!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR)
+		if (!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR)
 		{
 			bClassificationSucceed = FALSE;
 			break;
 		}
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!");
-		if(pstClassifierRule->bIpv6Protocol)
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!");
+		if (pstClassifierRule->bIpv6Protocol)
 			break;
 
 		//**************Checking IP header parameter**************************//
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address");
-		if(FALSE == (bClassificationSucceed =
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address");
+		if (FALSE == (bClassificationSucceed =
 			MatchSrcIpAddress(pstClassifierRule, iphd->saddr)))
 			break;
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched");
 
-		if(FALSE == (bClassificationSucceed =
+		if (FALSE == (bClassificationSucceed =
 			MatchDestIpAddress(pstClassifierRule, iphd->daddr)))
 			break;
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched");
 
-		if(FALSE == (bClassificationSucceed =
+		if (FALSE == (bClassificationSucceed =
 			MatchTos(pstClassifierRule, iphd->tos)))
 		{
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n");
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n");
 			break;
 		}
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched");
 
-		if(FALSE == (bClassificationSucceed =
-			MatchProtocol(pstClassifierRule,iphd->protocol)))
+		if (FALSE == (bClassificationSucceed =
+			MatchProtocol(pstClassifierRule, iphd->protocol)))
 			break;
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched");
 
 		//if protocol is not TCP or UDP then no need of comparing source port and destination port
-		if(iphd->protocol!=TCP && iphd->protocol!=UDP)
+		if (iphd->protocol != TCP && iphd->protocol != UDP)
 			break;
 		//******************Checking Transport Layer Header field if present *****************//
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
-			(iphd->protocol==UDP)?xprt_hdr->uhdr.source:xprt_hdr->thdr.source);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
+			(iphd->protocol == UDP) ? xprt_hdr->uhdr.source : xprt_hdr->thdr.source);
 
-		if(FALSE == (bClassificationSucceed =
+		if (FALSE == (bClassificationSucceed =
 			MatchSrcPort(pstClassifierRule,
-				ntohs((iphd->protocol == UDP)?
-				xprt_hdr->uhdr.source:xprt_hdr->thdr.source))))
+				ntohs((iphd->protocol == UDP) ?
+				xprt_hdr->uhdr.source : xprt_hdr->thdr.source))))
 			break;
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched");
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x",
-			(iphd->protocol==UDP)?xprt_hdr->uhdr.dest:
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x",
+			(iphd->protocol == UDP) ? xprt_hdr->uhdr.dest :
 			xprt_hdr->thdr.dest);
-		if(FALSE == (bClassificationSucceed =
+		if (FALSE == (bClassificationSucceed =
 			MatchDestPort(pstClassifierRule,
-			ntohs((iphd->protocol == UDP)?
-			xprt_hdr->uhdr.dest:xprt_hdr->thdr.dest))))
+			ntohs((iphd->protocol == UDP) ?
+			xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest))))
 			break;
-	} while(0);
+	} while (0);
 
-	if(TRUE==bClassificationSucceed)
+	if (TRUE == bClassificationSucceed)
 	{
 		INT iMatchedSFQueueIndex = 0;
-		iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
-		if(iMatchedSFQueueIndex >= NO_OF_QUEUES)
+		iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
+		if (iMatchedSFQueueIndex >= NO_OF_QUEUES)
 		{
 			bClassificationSucceed = FALSE;
 		}
 		else
 		{
-			if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
+			if (FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
 			{
 				bClassificationSucceed = FALSE;
 			}
 		}
 	}
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <==========");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <==========");
 
 	return bClassificationSucceed;
 }
@@ -306,9 +306,9 @@
 {
 	UINT iIndex = 0;
 
-	for(iIndex = 0; iIndex < HiPriority; iIndex++)
+	for (iIndex = 0; iIndex < HiPriority; iIndex++)
 	{
-		if(!Adapter->PackInfo[iIndex].bValid)
+		if (!Adapter->PackInfo[iIndex].bValid)
 			continue;
 
 		PruneQueue(Adapter, iIndex);
@@ -325,15 +325,15 @@
 */
 static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex)
 {
-	struct sk_buff* PacketToDrop=NULL;
+	struct sk_buff* PacketToDrop = NULL;
 	struct net_device_stats *netstats;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d",iIndex);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d", iIndex);
 
-   	if(iIndex == HiPriority)
+	if (iIndex == HiPriority)
 		return;
 
-	if(!Adapter || (iIndex < 0) || (iIndex > HiPriority))
+	if (!Adapter || (iIndex < 0) || (iIndex > HiPriority))
 		return;
 
 	/* To Store the netdevice statistic */
@@ -341,26 +341,26 @@
 
 	spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
 
-	while(1)
+	while (1)
 //	while((UINT)Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost >
 //		SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
 	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x",
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x",
 		Adapter->PackInfo[iIndex].uiCurrentBytesOnHost,
 		Adapter->PackInfo[iIndex].uiMaxBucketSize);
 
 		PacketToDrop = Adapter->PackInfo[iIndex].FirstTxQueue;
 
-		if(PacketToDrop == NULL)
+		if (PacketToDrop == NULL)
 			break;
-		if((Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost < SF_MAX_ALLOWED_PACKETS_TO_BACKUP) &&
+		if ((Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost < SF_MAX_ALLOWED_PACKETS_TO_BACKUP) &&
 			((1000*(jiffies - *((B_UINT32 *)(PacketToDrop->cb)+SKB_CB_LATENCY_OFFSET))/HZ) <= Adapter->PackInfo[iIndex].uiMaxLatency))
 			break;
 
-		if(PacketToDrop)
+		if (PacketToDrop)
 		{
 			if (netif_msg_tx_err(Adapter))
-				pr_info(PFX "%s: tx queue %d overlimit\n", 
+				pr_info(PFX "%s: tx queue %d overlimit\n",
 					Adapter->dev->name, iIndex);
 
 			netstats->tx_dropped++;
@@ -378,7 +378,7 @@
 
 		}
 
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
 			Adapter->PackInfo[iIndex].uiDroppedCountBytes,
 			Adapter->PackInfo[iIndex].uiDroppedCountPackets);
 
@@ -387,29 +387,29 @@
 
 	spin_unlock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "TotalPacketCount:%x",
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "TotalPacketCount:%x",
 		atomic_read(&Adapter->TotalPacketCount));
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "<=====");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "<=====");
 }
 
 VOID flush_all_queues(struct bcm_mini_adapter *Adapter)
 {
 	INT		iQIndex;
 	UINT	uiTotalPacketLength;
-	struct sk_buff*			PacketToDrop=NULL;
+	struct sk_buff*			PacketToDrop = NULL;
 
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
 
 //	down(&Adapter->data_packet_queue_lock);
-	for(iQIndex=LowPriority; iQIndex<HiPriority; iQIndex++)
+	for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++)
 	{
 		struct net_device_stats *netstats = &Adapter->dev->stats;
 
 		spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
-		while(Adapter->PackInfo[iQIndex].FirstTxQueue)
+		while (Adapter->PackInfo[iQIndex].FirstTxQueue)
 		{
 			PacketToDrop = Adapter->PackInfo[iQIndex].FirstTxQueue;
-			if(PacketToDrop)
+			if (PacketToDrop)
 			{
 				uiTotalPacketLength = PacketToDrop->len;
 				netstats->tx_dropped++;
@@ -431,7 +431,7 @@
 			Adapter->PackInfo[iQIndex].uiDroppedCountBytes += uiTotalPacketLength;
 			Adapter->PackInfo[iQIndex].uiDroppedCountPackets++;
 
-			BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x",
 					Adapter->PackInfo[iQIndex].uiDroppedCountBytes,
 					Adapter->PackInfo[iQIndex].uiDroppedCountPackets);
 			atomic_dec(&Adapter->TotalPacketCount);
@@ -439,30 +439,30 @@
 		spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
 	}
 //	up(&Adapter->data_packet_queue_lock);
-	BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "<=====");
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "<=====");
 }
 
-USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb)
+USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb)
 {
-	INT			uiLoopIndex=0;
+	INT			uiLoopIndex = 0;
 	struct bcm_classifier_rule *pstClassifierRule = NULL;
 	struct bcm_eth_packet_info stEthCsPktInfo;
 	PVOID pvEThPayload = NULL;
-	struct iphdr 		*pIpHeader = NULL;
-	INT	  uiSfIndex=0;
-	USHORT	usIndex=Adapter->usBestEffortQueueIndex;
-	BOOLEAN	bFragmentedPkt=FALSE,bClassificationSucceed=FALSE;
-	USHORT	usCurrFragment =0;
+	struct iphdr *pIpHeader = NULL;
+	INT	  uiSfIndex = 0;
+	USHORT	usIndex = Adapter->usBestEffortQueueIndex;
+	BOOLEAN	bFragmentedPkt = FALSE, bClassificationSucceed = FALSE;
+	USHORT	usCurrFragment = 0;
 
 	struct bcm_tcp_header *pTcpHeader;
 	UCHAR IpHeaderLength;
 	UCHAR TcpHeaderLength;
 
 	pvEThPayload = skb->data;
-	*((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET ) = 0;
-	EThCSGetPktInfo(Adapter,pvEThPayload,&stEthCsPktInfo);
+	*((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET) = 0;
+	EThCSGetPktInfo(Adapter, pvEThPayload, &stEthCsPktInfo);
 
-	switch(stEthCsPktInfo.eNwpktEthFrameType)
+	switch (stEthCsPktInfo.eNwpktEthFrameType)
 	{
 		case eEth802LLCFrame:
 		{
@@ -497,75 +497,75 @@
 		}
 	}
 
-	if(stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
+	if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
 	{
 		usCurrFragment = (ntohs(pIpHeader->frag_off) & IP_OFFSET);
-		if((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment)
+		if ((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment)
 			bFragmentedPkt = TRUE;
 
-		if(bFragmentedPkt)
+		if (bFragmentedPkt)
 		{
 				//Fragmented  Packet. Get Frag Classifier Entry.
-			pstClassifierRule = GetFragIPClsEntry(Adapter,pIpHeader->id, pIpHeader->saddr);
-			if(pstClassifierRule)
+			pstClassifierRule = GetFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr);
+			if (pstClassifierRule)
 			{
-					BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"It is next Fragmented pkt");
-					bClassificationSucceed=TRUE;
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "It is next Fragmented pkt");
+					bClassificationSucceed = TRUE;
 			}
-			if(!(ntohs(pIpHeader->frag_off) & IP_MF))
+			if (!(ntohs(pIpHeader->frag_off) & IP_MF))
 			{
 				//Fragmented Last packet . Remove Frag Classifier Entry
-				BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"This is the last fragmented Pkt");
-				DelFragIPClsEntry(Adapter,pIpHeader->id, pIpHeader->saddr);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "This is the last fragmented Pkt");
+				DelFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr);
 			}
 		}
 	}
 
-	for(uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
+	for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
 	{
-		if(bClassificationSucceed)
+		if (bClassificationSucceed)
 			break;
 		//Iterate through all classifiers which are already in order of priority
 		//to classify the packet until match found
 		do
 		{
-			if(FALSE==Adapter->astClassifierTable[uiLoopIndex].bUsed)
+			if (FALSE == Adapter->astClassifierTable[uiLoopIndex].bUsed)
 			{
-				bClassificationSucceed=FALSE;
+				bClassificationSucceed = FALSE;
 				break;
 			}
-			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Adapter->PackInfo[%d].bvalid=True\n",uiLoopIndex);
+			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Adapter->PackInfo[%d].bvalid=True\n", uiLoopIndex);
 
-			if(0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection)
+			if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection)
 			{
-				bClassificationSucceed=FALSE;//cannot be processed for classification.
+				bClassificationSucceed = FALSE;//cannot be processed for classification.
 				break;						// it is a down link connection
 			}
 
 			pstClassifierRule = &Adapter->astClassifierTable[uiLoopIndex];
 
-			uiSfIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
+			uiSfIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
 			if (uiSfIndex >= NO_OF_QUEUES) {
 				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Queue Not Valid. SearchSfid for this classifier Failed\n");
 				break;
 			}
 
-			if(Adapter->PackInfo[uiSfIndex].bEthCSSupport)
+			if (Adapter->PackInfo[uiSfIndex].bEthCSSupport)
 			{
 
-				if(eEthUnsupportedFrame==stEthCsPktInfo.eNwpktEthFrameType)
+				if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType)
 				{
-					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame \n");
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame\n");
 					bClassificationSucceed = FALSE;
 					break;
 				}
 
 
 
-				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n",pstClassifierRule->uiClassifierRuleIndex,Adapter->PackInfo[uiSfIndex].ulSFID);
-				bClassificationSucceed = EThCSClassifyPkt(Adapter,skb,&stEthCsPktInfo,pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n", pstClassifierRule->uiClassifierRuleIndex, Adapter->PackInfo[uiSfIndex].ulSFID);
+				bClassificationSucceed = EThCSClassifyPkt(Adapter, skb, &stEthCsPktInfo, pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport);
 
-				if(!bClassificationSucceed)
+				if (!bClassificationSucceed)
 				{
 					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ClassifyPacket : Ethernet CS Classification Failed\n");
 					break;
@@ -574,9 +574,9 @@
 
 			else // No ETH Supported on this SF
 			{
-				if(eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType)
+				if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType)
 				{
-					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF \n");
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF\n");
 					bClassificationSucceed = FALSE;
 					break;
 				}
@@ -584,51 +584,51 @@
 
 			BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Proceeding to IP CS Clasification");
 
-			if(Adapter->PackInfo[uiSfIndex].bIPCSSupport)
+			if (Adapter->PackInfo[uiSfIndex].bIPCSSupport)
 			{
 
-				if(stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket)
+				if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket)
 				{
-					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  " ClassifyPacket : Packet is Not an IP Packet \n");
+					BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet is Not an IP Packet\n");
 					bClassificationSucceed = FALSE;
 					break;
 				}
-				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "Dump IP Header : \n");
-				DumpFullPacket((PUCHAR)pIpHeader,20);
+				BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dump IP Header :\n");
+				DumpFullPacket((PUCHAR)pIpHeader, 20);
 
-				if(stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
-					bClassificationSucceed = IpVersion4(Adapter,pIpHeader,pstClassifierRule);
-				else if(stEthCsPktInfo.eNwpktIPFrameType == eIPv6Packet)
-					bClassificationSucceed = IpVersion6(Adapter,pIpHeader,pstClassifierRule);
+				if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet)
+					bClassificationSucceed = IpVersion4(Adapter, pIpHeader, pstClassifierRule);
+				else if (stEthCsPktInfo.eNwpktIPFrameType == eIPv6Packet)
+					bClassificationSucceed = IpVersion6(Adapter, pIpHeader, pstClassifierRule);
 			}
 
-		}while(0);
+		} while (0);
 	}
 
-	if(bClassificationSucceed == TRUE)
+	if (bClassificationSucceed == TRUE)
 	{
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu",pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu", pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID);
 
 		//Store The matched Classifier in SKB
 		*((UINT32*)(skb->cb)+SKB_CB_CLASSIFICATION_OFFSET) = pstClassifierRule->uiClassifierRuleIndex;
-		if((TCP == pIpHeader->protocol ) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len) )
+		if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len))
 		{
 			 IpHeaderLength   = pIpHeader->ihl;
 			 pTcpHeader = (struct bcm_tcp_header *)(((PUCHAR)pIpHeader)+(IpHeaderLength*4));
 			 TcpHeaderLength  = GET_TCP_HEADER_LEN(pTcpHeader->HeaderLength);
 
-			if((pTcpHeader->ucFlags & TCP_ACK) &&
+			if ((pTcpHeader->ucFlags & TCP_ACK) &&
 			   (ntohs(pIpHeader->tot_len) == (IpHeaderLength*4)+(TcpHeaderLength*4)))
 			{
-    			*((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET ) = TCP_ACK;
+				*((UINT32*) (skb->cb) + SKB_CB_TCPACK_OFFSET) = TCP_ACK;
 			}
 		}
 
 		usIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
-		BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is	=%d", usIndex);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is	=%d", usIndex);
 
 		//If this is the first fragment of a Fragmented pkt, add this CF. Only This CF should be used for all other fragment of this Pkt.
-		if(bFragmentedPkt && (usCurrFragment == 0))
+		if (bFragmentedPkt && (usCurrFragment == 0))
 		{
 			//First Fragment of Fragmented Packet. Create Frag CLS Entry
 			struct bcm_fragmented_packet_info stFragPktInfo;
@@ -637,77 +637,77 @@
 			stFragPktInfo.usIpIdentification = pIpHeader->id;
 			stFragPktInfo.pstMatchedClassifierEntry = pstClassifierRule;
 			stFragPktInfo.bOutOfOrderFragment = FALSE;
-			AddFragIPClsEntry(Adapter,&stFragPktInfo);
+			AddFragIPClsEntry(Adapter, &stFragPktInfo);
 		}
 
 
 	}
 
-	if(bClassificationSucceed)
+	if (bClassificationSucceed)
 		return usIndex;
 	else
 		return INVALID_QUEUE_INDEX;
 }
 
-static BOOLEAN EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRule,PUCHAR Mac)
+static BOOLEAN EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRule, PUCHAR Mac)
 {
-	UINT i=0;
+	UINT i = 0;
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	if(pstClassifierRule->ucEthCSSrcMACLen==0)
+	if (pstClassifierRule->ucEthCSSrcMACLen == 0)
 		return TRUE;
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s \n",__FUNCTION__);
-	for(i=0;i<MAC_ADDRESS_SIZE;i++)
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s\n", __FUNCTION__);
+	for (i = 0; i < MAC_ADDRESS_SIZE; i++)
 	{
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n",i,Mac[i],pstClassifierRule->au8EThCSSrcMAC[i],pstClassifierRule->au8EThCSSrcMACMask[i]);
-		if((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i])!=
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSSrcMAC[i], pstClassifierRule->au8EThCSSrcMACMask[i]);
+		if ((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i]) !=
 			(Mac[i] & pstClassifierRule->au8EThCSSrcMACMask[i]))
 			return FALSE;
 	}
 	return TRUE;
 }
 
-static BOOLEAN EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRule,PUCHAR Mac)
+static BOOLEAN EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRule, PUCHAR Mac)
 {
-	UINT i=0;
+	UINT i = 0;
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	if(pstClassifierRule->ucEthCSDestMACLen==0)
+	if (pstClassifierRule->ucEthCSDestMACLen == 0)
 		return TRUE;
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s \n",__FUNCTION__);
-	for(i=0;i<MAC_ADDRESS_SIZE;i++)
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __FUNCTION__);
+	for (i = 0; i < MAC_ADDRESS_SIZE; i++)
 	{
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n",i,Mac[i],pstClassifierRule->au8EThCSDestMAC[i],pstClassifierRule->au8EThCSDestMACMask[i]);
-		if((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i])!=
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSDestMAC[i], pstClassifierRule->au8EThCSDestMACMask[i]);
+		if ((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i]) !=
 			(Mac[i] & pstClassifierRule->au8EThCSDestMACMask[i]))
 			return FALSE;
 	}
 	return TRUE;
 }
 
-static BOOLEAN EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule,struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
+static BOOLEAN EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
 {
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
-	if((pstClassifierRule->ucEtherTypeLen==0)||
+	if ((pstClassifierRule->ucEtherTypeLen == 0) ||
 		(pstClassifierRule->au8EthCSEtherType[0] == 0))
 		return TRUE;
 
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s SrcEtherType:%x CLS EtherType[0]:%x\n",__FUNCTION__,pstEthCsPktInfo->usEtherType,pstClassifierRule->au8EthCSEtherType[0]);
-	if(pstClassifierRule->au8EthCSEtherType[0] == 1)
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s SrcEtherType:%x CLS EtherType[0]:%x\n", __FUNCTION__, pstEthCsPktInfo->usEtherType, pstClassifierRule->au8EthCSEtherType[0]);
+	if (pstClassifierRule->au8EthCSEtherType[0] == 1)
 	{
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  CLS EtherType[1]:%x EtherType[2]:%x\n",__FUNCTION__,pstClassifierRule->au8EthCSEtherType[1],pstClassifierRule->au8EthCSEtherType[2]);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  CLS EtherType[1]:%x EtherType[2]:%x\n", __FUNCTION__, pstClassifierRule->au8EthCSEtherType[1], pstClassifierRule->au8EthCSEtherType[2]);
 
-		if(memcmp(&pstEthCsPktInfo->usEtherType,&pstClassifierRule->au8EthCSEtherType[1],2)==0)
+		if (memcmp(&pstEthCsPktInfo->usEtherType, &pstClassifierRule->au8EthCSEtherType[1], 2) == 0)
 			return TRUE;
 		else
 			return FALSE;
 	}
 
-	if(pstClassifierRule->au8EthCSEtherType[0] == 2)
+	if (pstClassifierRule->au8EthCSEtherType[0] == 2)
 	{
-		if(eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType)
+		if (eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType)
 			return FALSE;
 
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  EthCS DSAP:%x EtherType[2]:%x\n",__FUNCTION__,pstEthCsPktInfo->ucDSAP,pstClassifierRule->au8EthCSEtherType[2]);
-		if(pstEthCsPktInfo->ucDSAP == pstClassifierRule->au8EthCSEtherType[2])
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  EthCS DSAP:%x EtherType[2]:%x\n", __FUNCTION__, pstEthCsPktInfo->ucDSAP, pstClassifierRule->au8EthCSEtherType[2]);
+		if (pstEthCsPktInfo->ucDSAP == pstClassifierRule->au8EthCSEtherType[2])
 			return TRUE;
 		else
 			return FALSE;
@@ -718,27 +718,27 @@
 
 }
 
-static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule,struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
+static BOOLEAN EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo)
 {
 	BOOLEAN bClassificationSucceed = FALSE;
 	USHORT usVLANID;
 	B_UINT8 uPriority = 0;
 	struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
 
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  CLS UserPrio:%x CLS VLANID:%x\n",__FUNCTION__,ntohs(*((USHORT *)pstClassifierRule->usUserPriority)),pstClassifierRule->usVLANID);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  CLS UserPrio:%x CLS VLANID:%x\n", __FUNCTION__, ntohs(*((USHORT *)pstClassifierRule->usUserPriority)), pstClassifierRule->usVLANID);
 
 	/* In case FW didn't receive the TLV, the priority field should be ignored */
-	if(pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID))
+	if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID))
 	{
-		if(pstEthCsPktInfo->eNwpktEthFrameType!=eEth802QVLANFrame)
+		if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame)
 				return FALSE;
 
 		uPriority = (ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xF000) >> 13;
 
-		if((uPriority >= pstClassifierRule->usUserPriority[0]) && (uPriority <= pstClassifierRule->usUserPriority[1]))
+		if ((uPriority >= pstClassifierRule->usUserPriority[0]) && (uPriority <= pstClassifierRule->usUserPriority[1]))
 				bClassificationSucceed = TRUE;
 
-		if(!bClassificationSucceed)
+		if (!bClassificationSucceed)
 			return FALSE;
 	}
 
@@ -746,19 +746,19 @@
 
 	bClassificationSucceed = FALSE;
 
-	if(pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID))
+	if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID))
 	{
-		if(pstEthCsPktInfo->eNwpktEthFrameType!=eEth802QVLANFrame)
+		if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame)
 				return FALSE;
 
 		usVLANID = ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xFFF;
 
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  Pkt VLANID %x Priority: %d\n",__FUNCTION__,usVLANID, uPriority);
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "%s  Pkt VLANID %x Priority: %d\n", __FUNCTION__, usVLANID, uPriority);
 
-		if(usVLANID == ((pstClassifierRule->usVLANID & 0xFFF0) >> 4))
+		if (usVLANID == ((pstClassifierRule->usVLANID & 0xFFF0) >> 4))
 			bClassificationSucceed = TRUE;
 
-		if(!bClassificationSucceed)
+		if (!bClassificationSucceed)
 			return FALSE;
 	}
 
@@ -768,50 +768,50 @@
 }
 
 
-static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter,struct sk_buff* skb,
+static BOOLEAN EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, struct sk_buff* skb,
 				struct bcm_eth_packet_info *pstEthCsPktInfo,
 				struct bcm_classifier_rule *pstClassifierRule,
 				B_UINT8 EthCSCupport)
 {
 	BOOLEAN bClassificationSucceed = FALSE;
-	bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule,((struct bcm_eth_header *)(skb->data))->au8SourceAddress);
-	if(!bClassificationSucceed)
+	bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule, ((struct bcm_eth_header *)(skb->data))->au8SourceAddress);
+	if (!bClassificationSucceed)
 		return FALSE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ETH CS SrcMAC Matched\n");
 
-	bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule,((struct bcm_eth_header *)(skb->data))->au8DestinationAddress);
-	if(!bClassificationSucceed)
+	bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule, ((struct bcm_eth_header *)(skb->data))->au8DestinationAddress);
+	if (!bClassificationSucceed)
 		return FALSE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ETH CS DestMAC Matched\n");
 
 	//classify on ETHType/802.2SAP TLV
-	bClassificationSucceed = EthCSMatchEThTypeSAP(pstClassifierRule,skb,pstEthCsPktInfo);
-	if(!bClassificationSucceed)
+	bClassificationSucceed = EthCSMatchEThTypeSAP(pstClassifierRule, skb, pstEthCsPktInfo);
+	if (!bClassificationSucceed)
 		return FALSE;
 
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ETH CS EthType/802.2SAP Matched\n");
 
 	//classify on 802.1VLAN Header Parameters
 
-	bClassificationSucceed = EthCSMatchVLANRules(pstClassifierRule,skb,pstEthCsPktInfo);
-	if(!bClassificationSucceed)
+	bClassificationSucceed = EthCSMatchVLANRules(pstClassifierRule, skb, pstEthCsPktInfo);
+	if (!bClassificationSucceed)
 		return FALSE;
 	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "ETH CS 802.1 VLAN Rules Matched\n");
 
 	return bClassificationSucceed;
 }
 
-static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter,PVOID pvEthPayload,
+static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload,
 			    struct bcm_eth_packet_info *pstEthCsPktInfo)
 {
 	USHORT u16Etype = ntohs(((struct bcm_eth_header *)pvEthPayload)->u16Etype);
 
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCSGetPktInfo : Eth Hdr Type : %X\n",u16Etype);
-	if(u16Etype > 0x5dc)
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCSGetPktInfo : Eth Hdr Type : %X\n", u16Etype);
+	if (u16Etype > 0x5dc)
 	{
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCSGetPktInfo : ETH2 Frame \n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : ETH2 Frame\n");
 		//ETH2 Frame
-		if(u16Etype == ETHERNET_FRAMETYPE_802QVLAN)
+		if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN)
 		{
 			//802.1Q VLAN Header
 			pstEthCsPktInfo->eNwpktEthFrameType = eEth802QVLANFrame;
@@ -828,27 +828,27 @@
 	else
 	{
 		//802.2 LLC
-		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "802.2 LLC Frame \n");
+		BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "802.2 LLC Frame\n");
 		pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCFrame;
 		pstEthCsPktInfo->ucDSAP = ((struct bcm_eth_llc_frame *)pvEthPayload)->DSAP;
-		if(pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA)
+		if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA)
 		{
 			//SNAP Frame
 			pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCSNAPFrame;
 			u16Etype = ((struct bcm_eth_llc_snap_frame *)pvEthPayload)->usEtherType;
 		}
 	}
-	if(u16Etype == ETHERNET_FRAMETYPE_IPV4)
+	if (u16Etype == ETHERNET_FRAMETYPE_IPV4)
 		pstEthCsPktInfo->eNwpktIPFrameType = eIPv4Packet;
-	else if(u16Etype == ETHERNET_FRAMETYPE_IPV6)
+	else if (u16Etype == ETHERNET_FRAMETYPE_IPV6)
 		pstEthCsPktInfo->eNwpktIPFrameType = eIPv6Packet;
 	else
 		pstEthCsPktInfo->eNwpktIPFrameType = eNonIPPacket;
 
 	pstEthCsPktInfo->usEtherType = ((struct bcm_eth_header *)pvEthPayload)->u16Etype;
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->eNwpktIPFrameType : %x\n",pstEthCsPktInfo->eNwpktIPFrameType);
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->eNwpktEthFrameType : %x\n",pstEthCsPktInfo->eNwpktEthFrameType);
-	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->usEtherType : %x\n",pstEthCsPktInfo->usEtherType);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->eNwpktIPFrameType : %x\n", pstEthCsPktInfo->eNwpktIPFrameType);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->eNwpktEthFrameType : %x\n", pstEthCsPktInfo->eNwpktEthFrameType);
+	BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCsPktInfo->usEtherType : %x\n", pstEthCsPktInfo->usEtherType);
 }
 
 
diff --git a/drivers/staging/bcm/Version.h b/drivers/staging/bcm/Version.h
deleted file mode 100644
index f1cb9de..0000000
--- a/drivers/staging/bcm/Version.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*Copyright (c) 2005 Beceem Communications Inc.
-
-Module Name:
-
-  Version.h
-
-Abstract:
-
-
---*/
-
-#ifndef VERSION_H
-#define VERSION_H
-
-
-#define VER_FILETYPE                VFT_DRV
-#define VER_FILESUBTYPE             VFT2_DRV_NETWORK
-
-#define VER_FILEVERSION             5.2.45
-#define VER_FILEVERSION_STR         "5.2.45"
-
-#undef VER_PRODUCTVERSION
-#define VER_PRODUCTVERSION          VER_FILEVERSION
-
-#undef VER_PRODUCTVERSION_STR
-#define VER_PRODUCTVERSION_STR      VER_FILEVERSION_STR
-
-
-#endif /* VERSION_H */
diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h
index da47db8..7fd21c6 100644
--- a/drivers/staging/bcm/headers.h
+++ b/drivers/staging/bcm/headers.h
@@ -38,7 +38,6 @@
 #include <net/ip.h>
 
 #include "Typedefs.h"
-#include "Version.h"
 #include "Macros.h"
 #include "HostMIBSInterface.h"
 #include "cntrl_SignalingInterface.h"
@@ -71,7 +70,7 @@
 #define DEV_NAME	"tarang"
 #define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver"
 #define DRV_COPYRIGHT	"Copyright 2010. Beceem Communications Inc"
-#define DRV_VERSION	VER_FILEVERSION_STR
+#define DRV_VERSION	"5.2.45"
 #define PFX		DRV_NAME " "
 
 extern struct class *bcm_class;
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index bea1330..91a5715 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -2966,7 +2966,7 @@
  * @Adapter :-Drivers private Data Structure
  *
  * Return Value:-
- * Return STATUS_SUCESS if get success in setting the right DSD else negaive error code
+ * Return STATUS_SUCESS if get success in setting the right DSD else negative error code
  *
  */
 
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 8c8a551..a84aab4 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -100,7 +100,6 @@
 
 menuconfig COMEDI_ISA_DRIVERS
 	bool "Comedi ISA and PC/104 drivers"
-	depends on ISA
 	---help---
 	  Enable comedi ISA and PC/104 drivers to be built
 
@@ -122,8 +121,18 @@
 	tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
 	select COMEDI_8255
 	---help---
-	  Enable support for Advantech PCL-724, PCL-722, PCL-731 and
-	  ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards
+	  Enable support for ISA and PC/104 based 8255 digital i/o boards. This
+	  driver provides a legacy comedi driver wrapper for the generic 8255
+	  support driver.
+
+	  Supported boards include:
+	    Advantech PCL-724    24 channels
+	    Advantech PCL-722    144 (or 96) channels
+	    Advantech PCL-731    48 channels
+	    ADlink ACL-7122      144 (or 96) channels
+	    ADlink ACL-7124      24 channels
+	    ADlink PET-48DIO     48 channels
+	    WinSystems PCM-IO48  48 channels (PC/104)
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called pcl724.
@@ -403,6 +412,15 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called aio_iiro_16.
 
+config COMEDI_II_PCI20KC
+	tristate "Intelligent Instruments PCI-20001C carrier support"
+	---help---
+	  Enable support for Intelligent Instruments PCI-20001C carrier
+	  PCI-20001, PCI-20006 and PCI-20341
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called ii_pci20kc.
+
 config COMEDI_C6XDIGIO
 	tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support"
 	---help---
@@ -448,7 +466,6 @@
 
 config COMEDI_NI_ATMIO
 	tristate "NI AT-MIO E series ISA-PNP card support"
-	depends on ISAPNP
 	select COMEDI_8255
 	select COMEDI_NI_TIO
 	---help---
@@ -461,11 +478,10 @@
 	  called ni_atmio.
 
 config COMEDI_NI_ATMIO16D
-	tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
-	depends on ISAPNP
+	tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support"
 	select COMEDI_8255
 	---help---
-	  Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
+	  Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards.
 
 	  To compile this driver as a module, choose M here: the module will be
 	  called ni_atmio16d.
@@ -473,7 +489,7 @@
 config COMEDI_NI_LABPC_ISA
 	tristate "NI Lab-PC and compatibles ISA support"
 	select COMEDI_NI_LABPC
-	depends on VIRT_TO_BUS
+	select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API && VIRT_TO_BUS
 	---help---
 	  Enable support for National Instruments Lab-PC and compatibles
 	  Lab-PC-1200, Lab-PC-1200AI, Lab-PC+.
@@ -866,15 +882,6 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called icp_multi.
 
-config COMEDI_II_PCI20KC
-	tristate "Intelligent Instruments PCI-20001C carrier support"
-	---help---
-	  Enable support for Intelligent Instruments PCI-20001C carrier
-	  PCI-20001, PCI-20006 and PCI-20341
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called ii_pci20kc.
-
 config COMEDI_DAQBOARD2000
 	tristate "IOtech DAQboard/2000 support"
 	select COMEDI_8255
@@ -1262,6 +1269,9 @@
 	select COMEDI_8255
 	select COMEDI_FC
 
+config COMEDI_NI_LABPC_ISADMA
+	tristate
+
 config COMEDI_NI_TIO
 	tristate
 
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index b4c001b..94b2385f 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -15,6 +15,8 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/vmalloc.h>
+
 #include "comedidev.h"
 #include "comedi_internal.h"
 
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f4a197b..1636c7c 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -26,7 +26,6 @@
 #include <linux/sched.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
-#include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -262,7 +261,7 @@
 
 /* sysfs attribute files */
 
-static ssize_t show_max_read_buffer_kb(struct device *csdev,
+static ssize_t max_read_buffer_kb_show(struct device *csdev,
 				       struct device_attribute *attr, char *buf)
 {
 	unsigned int minor = MINOR(csdev->devt);
@@ -283,7 +282,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
-static ssize_t store_max_read_buffer_kb(struct device *csdev,
+static ssize_t max_read_buffer_kb_store(struct device *csdev,
 					struct device_attribute *attr,
 					const char *buf, size_t count)
 {
@@ -314,8 +313,9 @@
 
 	return err ? err : count;
 }
+static DEVICE_ATTR_RW(max_read_buffer_kb);
 
-static ssize_t show_read_buffer_kb(struct device *csdev,
+static ssize_t read_buffer_kb_show(struct device *csdev,
 				   struct device_attribute *attr, char *buf)
 {
 	unsigned int minor = MINOR(csdev->devt);
@@ -336,7 +336,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
-static ssize_t store_read_buffer_kb(struct device *csdev,
+static ssize_t read_buffer_kb_store(struct device *csdev,
 				    struct device_attribute *attr,
 				    const char *buf, size_t count)
 {
@@ -367,8 +367,9 @@
 
 	return err ? err : count;
 }
+static DEVICE_ATTR_RW(read_buffer_kb);
 
-static ssize_t show_max_write_buffer_kb(struct device *csdev,
+static ssize_t max_write_buffer_kb_show(struct device *csdev,
 					struct device_attribute *attr,
 					char *buf)
 {
@@ -390,7 +391,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
-static ssize_t store_max_write_buffer_kb(struct device *csdev,
+static ssize_t max_write_buffer_kb_store(struct device *csdev,
 					 struct device_attribute *attr,
 					 const char *buf, size_t count)
 {
@@ -421,8 +422,9 @@
 
 	return err ? err : count;
 }
+static DEVICE_ATTR_RW(max_write_buffer_kb);
 
-static ssize_t show_write_buffer_kb(struct device *csdev,
+static ssize_t write_buffer_kb_show(struct device *csdev,
 				    struct device_attribute *attr, char *buf)
 {
 	unsigned int minor = MINOR(csdev->devt);
@@ -443,7 +445,7 @@
 	return snprintf(buf, PAGE_SIZE, "%i\n", size);
 }
 
-static ssize_t store_write_buffer_kb(struct device *csdev,
+static ssize_t write_buffer_kb_store(struct device *csdev,
 				     struct device_attribute *attr,
 				     const char *buf, size_t count)
 {
@@ -474,18 +476,16 @@
 
 	return err ? err : count;
 }
+static DEVICE_ATTR_RW(write_buffer_kb);
 
-static struct device_attribute comedi_dev_attrs[] = {
-	__ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
-		show_max_read_buffer_kb, store_max_read_buffer_kb),
-	__ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
-		show_read_buffer_kb, store_read_buffer_kb),
-	__ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
-		show_max_write_buffer_kb, store_max_write_buffer_kb),
-	__ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
-		show_write_buffer_kb, store_write_buffer_kb),
-	__ATTR_NULL
+static struct attribute *comedi_dev_attrs[] = {
+	&dev_attr_max_read_buffer_kb.attr,
+	&dev_attr_read_buffer_kb.attr,
+	&dev_attr_max_write_buffer_kb.attr,
+	&dev_attr_write_buffer_kb.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(comedi_dev);
 
 static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
 					  unsigned mask, unsigned bits)
@@ -2564,7 +2564,7 @@
 		return PTR_ERR(comedi_class);
 	}
 
-	comedi_class->dev_attrs = comedi_dev_attrs;
+	comedi_class->dev_groups = comedi_dev_groups;
 
 	/* XXX requires /proc interface */
 	comedi_proc_init();
diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h
index d5e03e5..fda1a7b 100644
--- a/drivers/staging/comedi/comedi_internal.h
+++ b/drivers/staging/comedi/comedi_internal.h
@@ -24,6 +24,7 @@
 /* drivers.c */
 
 extern struct comedi_driver *comedi_drivers;
+extern struct mutex comedi_drivers_list_lock;
 
 int insn_inval(struct comedi_device *, struct comedi_subdevice *,
 	       struct comedi_insn *, unsigned int *);
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index b75915f..2e19f65 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -19,22 +19,7 @@
 #ifndef _COMEDIDEV_H
 #define _COMEDIDEV_H
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kdev_t.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
 #include <linux/dma-mapping.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/timer.h>
 
 #include "comedi.h"
 
@@ -357,6 +342,11 @@
 
 /* drivers.c - general comedi driver functions */
 
+int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
+			   struct comedi_insn *, unsigned int *data,
+			   unsigned int mask);
+
+void *comedi_alloc_devpriv(struct comedi_device *, size_t);
 int comedi_alloc_subdevices(struct comedi_device *, int);
 
 int comedi_load_firmware(struct comedi_device *, struct device *,
@@ -377,7 +367,7 @@
 void comedi_auto_unconfig(struct device *);
 
 int comedi_driver_register(struct comedi_driver *);
-int comedi_driver_unregister(struct comedi_driver *);
+void comedi_driver_unregister(struct comedi_driver *);
 
 /**
  * module_comedi_driver() - Helper macro for registering a comedi driver
@@ -400,7 +390,6 @@
  */
 #define PCI_VENDOR_ID_KOLTER		0x1001
 #define PCI_VENDOR_ID_ICP		0x104c
-#define PCI_VENDOR_ID_AMCC		0x10e8
 #define PCI_VENDOR_ID_DT		0x1116
 #define PCI_VENDOR_ID_IOTECH		0x1616
 #define PCI_VENDOR_ID_CONTEC		0x1221
diff --git a/drivers/staging/comedi/comedilib.h b/drivers/staging/comedi/comedilib.h
index 1a78b15..56baf85 100644
--- a/drivers/staging/comedi/comedilib.h
+++ b/drivers/staging/comedi/comedilib.h
@@ -21,10 +21,13 @@
 
 struct comedi_device *comedi_open(const char *path);
 int comedi_close(struct comedi_device *dev);
+int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
+			  unsigned int chan, unsigned int *io);
 int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
 		      unsigned int chan, unsigned int io);
-int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
-			unsigned int mask, unsigned int *bits);
+int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
+			 unsigned int mask, unsigned int *bits,
+			 unsigned int base_channel);
 int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
 				  unsigned int subd);
 int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice);
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index e25eba5..317a821 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -23,7 +23,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fcntl.h>
-#include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
@@ -39,6 +38,7 @@
 #include "comedi_internal.h"
 
 struct comedi_driver *comedi_drivers;
+DEFINE_MUTEX(comedi_drivers_list_lock);
 
 int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
 {
@@ -57,6 +57,18 @@
 	dev->hw_dev = NULL;
 }
 
+/**
+ * comedi_alloc_devpriv() - Allocate memory for the device private data.
+ * @dev: comedi_device struct
+ * @size: size of the memory to allocate
+ */
+void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size)
+{
+	dev->private = kzalloc(size, GFP_KERNEL);
+	return dev->private;
+}
+EXPORT_SYMBOL_GPL(comedi_alloc_devpriv);
+
 int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
 {
 	struct comedi_subdevice *s;
@@ -138,6 +150,46 @@
 	return -EINVAL;
 }
 
+/**
+ * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices.
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct
+ * @insn: comedi_insn struct
+ * @data: parameters for the @insn
+ * @mask: io_bits mask for grouped channels
+ */
+int comedi_dio_insn_config(struct comedi_device *dev,
+			   struct comedi_subdevice *s,
+			   struct comedi_insn *insn,
+			   unsigned int *data,
+			   unsigned int mask)
+{
+	unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
+
+	if (!mask)
+		mask = chan_mask;
+
+	switch (data[0]) {
+	case INSN_CONFIG_DIO_INPUT:
+		s->io_bits &= ~mask;
+		break;
+
+	case INSN_CONFIG_DIO_OUTPUT:
+		s->io_bits |= mask;
+		break;
+
+	case INSN_CONFIG_DIO_QUERY:
+		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
+		return insn->n;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_dio_insn_config);
+
 static int insn_rw_emulate_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
 				struct comedi_insn *insn, unsigned int *data)
@@ -442,6 +494,7 @@
 	if (dev->attached)
 		return -EBUSY;
 
+	mutex_lock(&comedi_drivers_list_lock);
 	for (driv = comedi_drivers; driv; driv = driv->next) {
 		if (!try_module_get(driv->module))
 			continue;
@@ -462,7 +515,8 @@
 			comedi_report_boards(driv);
 			module_put(driv->module);
 		}
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 	if (driv->attach == NULL) {
 		/* driver does not support manual configuration */
@@ -470,7 +524,8 @@
 			 "driver '%s' does not support attach using comedi_config\n",
 			 driv->driver_name);
 		module_put(driv->module);
-		return -ENOSYS;
+		ret = -ENOSYS;
+		goto out;
 	}
 	/* initialize dev->driver here so
 	 * comedi_error() can be called from attach */
@@ -482,9 +537,11 @@
 		ret = comedi_device_postconfig(dev);
 	if (ret < 0) {
 		comedi_device_detach(dev);
-		module_put(dev->driver->module);
+		module_put(driv->module);
 	}
 	/* On success, the driver module count has been incremented. */
+out:
+	mutex_unlock(&comedi_drivers_list_lock);
 	return ret;
 }
 
@@ -541,18 +598,34 @@
 
 int comedi_driver_register(struct comedi_driver *driver)
 {
+	mutex_lock(&comedi_drivers_list_lock);
 	driver->next = comedi_drivers;
 	comedi_drivers = driver;
+	mutex_unlock(&comedi_drivers_list_lock);
 
 	return 0;
 }
 EXPORT_SYMBOL_GPL(comedi_driver_register);
 
-int comedi_driver_unregister(struct comedi_driver *driver)
+void comedi_driver_unregister(struct comedi_driver *driver)
 {
 	struct comedi_driver *prev;
 	int i;
 
+	/* unlink the driver */
+	mutex_lock(&comedi_drivers_list_lock);
+	if (comedi_drivers == driver) {
+		comedi_drivers = driver->next;
+	} else {
+		for (prev = comedi_drivers; prev->next; prev = prev->next) {
+			if (prev->next == driver) {
+				prev->next = driver->next;
+				break;
+			}
+		}
+	}
+	mutex_unlock(&comedi_drivers_list_lock);
+
 	/* check for devices using this driver */
 	for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) {
 		struct comedi_device *dev = comedi_dev_from_minor(i);
@@ -570,18 +643,5 @@
 		}
 		mutex_unlock(&dev->mutex);
 	}
-
-	if (comedi_drivers == driver) {
-		comedi_drivers = driver->next;
-		return 0;
-	}
-
-	for (prev = comedi_drivers; prev->next; prev = prev->next) {
-		if (prev->next == driver) {
-			prev->next = driver->next;
-			return 0;
-		}
-	}
-	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(comedi_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 94e1750..2f070fd 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -73,10 +73,9 @@
    will copy the latched value to a Comedi buffer.
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #include "comedi_fc.h"
 #include "8255.h"
 
@@ -185,39 +184,29 @@
 
 static int subdev_8255_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn, unsigned int *data)
+				   struct comedi_insn *insn,
+				   unsigned int *data)
 {
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	unsigned int mask;
-	unsigned int bits;
+	int ret;
 
-	mask = 1 << CR_CHAN(insn->chanspec);
-	if (mask & 0x0000ff)
-		bits = 0x0000ff;
-	else if (mask & 0x00ff00)
-		bits = 0x00ff00;
-	else if (mask & 0x0f0000)
-		bits = 0x0f0000;
+	if (chan < 8)
+		mask = 0x0000ff;
+	else if (chan < 16)
+		mask = 0x00ff00;
+	else if (chan < 20)
+		mask = 0x0f0000;
 	else
-		bits = 0xf00000;
+		mask = 0xf00000;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	subdev_8255_do_config(dev, s);
 
-	return 1;
+	return insn->n;
 }
 
 static int subdev_8255_cmdtest(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 3d3547c..432e3f9 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -50,6 +50,7 @@
 Configuration Options: not applicable, uses PCI auto config
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -186,10 +187,9 @@
 	dev->board_ptr = board;
 	dev->board_name = board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index dbb93e3..94cbd26 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -39,6 +39,7 @@
 obj-$(CONFIG_COMEDI_FL512)		+= fl512.o
 obj-$(CONFIG_COMEDI_AIO_AIO12_8)	+= aio_aio12_8.o
 obj-$(CONFIG_COMEDI_AIO_IIRO_16)	+= aio_iiro_16.o
+obj-$(CONFIG_COMEDI_II_PCI20KC)		+= ii_pci20kc.o
 obj-$(CONFIG_COMEDI_C6XDIGIO)		+= c6xdigio.o
 obj-$(CONFIG_COMEDI_MPC624)		+= mpc624.o
 obj-$(CONFIG_COMEDI_ADQ12B)		+= adq12b.o
@@ -89,7 +90,6 @@
 obj-$(CONFIG_COMEDI_UNIOXX5)		+= unioxx5.o
 obj-$(CONFIG_COMEDI_GSC_HPDI)		+= gsc_hpdi.o
 obj-$(CONFIG_COMEDI_ICP_MULTI)		+= icp_multi.o
-obj-$(CONFIG_COMEDI_II_PCI20KC)		+= ii_pci20kc.o
 obj-$(CONFIG_COMEDI_DAQBOARD2000)	+= daqboard2000.o
 obj-$(CONFIG_COMEDI_JR3_PCI)		+= jr3_pci.o
 obj-$(CONFIG_COMEDI_KE_COUNTER)		+= ke_counter.o
@@ -132,6 +132,7 @@
 obj-$(CONFIG_COMEDI_NI_TIO)		+= ni_tio.o
 obj-$(CONFIG_COMEDI_NI_TIOCMD)		+= ni_tiocmd.o
 obj-$(CONFIG_COMEDI_NI_LABPC)		+= ni_labpc.o
+obj-$(CONFIG_COMEDI_NI_LABPC_ISADMA)	+= ni_labpc_isadma.o
 
 obj-$(CONFIG_COMEDI_8255)		+= 8255.o
 obj-$(CONFIG_COMEDI_AMPLC_DIO200)	+= amplc_dio200_common.o
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c
deleted file mode 100644
index d070208..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c
+++ /dev/null
@@ -1,1068 +0,0 @@
-/*
- *  Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
- *
- *	ADDI-DATA GmbH
- *	Dieselstrasse 3
- *	D-77833 Ottersweier
- *	Tel: +19(0)7223/9493-0
- *	Fax: +49(0)7223/9493-92
- *	http://www.addi-data.com
- *	info@addi-data.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.
- */
-/*
-  | Description :   APCI-1710 82X54 timer module                          |
-*/
-
-#define APCI1710_PCI_BUS_CLOCK			0
-#define APCI1710_FRONT_CONNECTOR_INPUT		1
-#define APCI1710_TIMER_READVALUE		0
-#define APCI1710_TIMER_GETOUTPUTLEVEL		1
-#define APCI1710_TIMER_GETPROGRESSSTATUS	2
-#define APCI1710_TIMER_WRITEVALUE		3
-
-#define APCI1710_TIMER_READINTERRUPT		1
-#define APCI1710_TIMER_READALLTIMER		2
-
-#ifndef APCI1710_10MHZ
-#define APCI1710_10MHZ				10
-#endif
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_InitTimer                         |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char_   b_TimerNbr,                         |
-|                                unsigned char_   b_TimerMode,                        |
-|                                ULONG_ ul_ReloadValue,                      |
-|                                unsigned char_   b_InputClockSelection,              |
-|                                unsigned char_   b_InputClockLevel,                  |
-|                                unsigned char_   b_OutputLevel,                      |
-|                                unsigned char_   b_HardwareGateLevel)
-int i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s,
-	struct comedi_insn *insn,unsigned int *data)
-|
-+----------------------------------------------------------------------------+
-| Task              : Configure the Timer (b_TimerNbr) operating mode        |
-|                     (b_TimerMode) from selected module (b_ModulNbr).       |
-|                     You must calling this function be for you call any     |
-|                     other function witch access of the timer.              |
-|                                                                            |
-|                                                                            |
-|                       Timer mode description table                         |
-|                                                                            |
-|+--------+-----------------------------+--------------+--------------------+|
-||Selected+      Mode description       +u_ReloadValue | Hardware gate input||
-||  mode  |                             |  description |      action        ||
-|+--------+-----------------------------+--------------+--------------------+|
-||        |Mode 0 is typically used     |              |                    ||
-||        |for event counting. After    |              |                    ||
-||        |the initialisation, OUT      |              |                    ||
-||        |is initially low, and        |              |                    ||
-||   0    |will remain low until the    |Start counting|   Hardware gate    ||
-||        |counter reaches zero.        |   value      |                    ||
-||        |OUT then goes high and       |              |                    ||
-||        |remains high until a new     |              |                    ||
-||        |count is written. See        |              |                    ||
-||        |"i_APCI1710_WriteTimerValue" |              |                    ||
-||        |function.                    |              |                    ||
-|+--------+-----------------------------+--------------+--------------------+|
-||        |Mode 1 is similar to mode 0  |              |                    ||
-||        |except for the gate input    |              |                    ||
-||   1    |action. The gate input is not|Start counting|  Hardware trigger  ||
-||        |used for enabled or disabled |   value      |                    ||
-||        |the timer.                   |              |                    ||
-||        |The gate input is used for   |              |                    ||
-||        |triggered the timer.         |              |                    ||
-|+--------+-----------------------------+--------------+--------------------+|
-||        |This mode functions like a   |              |                    ||
-||        |divide-by-ul_ReloadValue     |              |                    ||
-||        |counter. It is typically used|              |                    ||
-||        |to generate a real time clock|              |                    ||
-||        |interrupt. OUT will initially|              |                    ||
-||   2    |be high after the            |   Division   |  Hardware gate     ||
-||        |initialisation. When the     |    factor    |                    ||
-||        |initial count has decremented|              |                    ||
-||        |to 1, OUT goes low for one   |              |                    ||
-||        |CLK pule. OUT then goes high |              |                    ||
-||        |again, the counter reloads   |              |                    ||
-||        |the initial count            |              |                    ||
-||        |(ul_ReloadValue) and the     |              |                    ||
-||        |process is repeated.         |              |                    ||
-||        |This action can generated a  |              |                    ||
-||        |interrupt. See function      |              |                    ||
-||        |"i_APCI1710_SetBoardInt-     |              |                    ||
-||        |RoutineX"                    |              |                    ||
-||        |and "i_APCI1710_EnableTimer" |              |                    ||
-|+--------+-----------------------------+--------------+--------------------+|
-||        |Mode 3 is typically used for |              |                    ||
-||        |baud rate generation. This   |              |                    ||
-||        |mode is similar to mode 2    |              |                    ||
-||        |except for the duty cycle of |              |                    ||
-||   3    |OUT. OUT will initially be   |  Division    |   Hardware gate    ||
-||        |high after the initialisation|   factor     |                    ||
-||        |When half the initial count  |              |                    ||
-||        |(ul_ReloadValue) has expired,|              |                    ||
-||        |OUT goes low for the         |              |                    ||
-||        |remainder of the count. The  |              |                    ||
-||        |mode is periodic; the        |              |                    ||
-||        |sequence above is repeated   |              |                    ||
-||        |indefinitely.                |              |                    ||
-|+--------+-----------------------------+--------------+--------------------+|
-||        |OUT will be initially high   |              |                    ||
-||        |after the initialisation.    |              |                    ||
-||        |When the initial count       |              |                    ||
-||   4    |expires OUT will go low for  |Start counting|  Hardware gate     ||
-||        |one CLK pulse and then go    |    value     |                    ||
-||        |high again.                  |              |                    ||
-||        |The counting sequences is    |              |                    ||
-||        |triggered by writing a new   |              |                    ||
-||        |value. See                   |              |                    ||
-||        |"i_APCI1710_WriteTimerValue" |              |                    ||
-||        |function. If a new count is  |              |                    ||
-||        |written during counting,     |              |                    ||
-||        |it will be loaded on the     |              |                    ||
-||        |next CLK pulse               |              |                    ||
-|+--------+-----------------------------+--------------+--------------------+|
-||        |Mode 5 is similar to mode 4  |              |                    ||
-||        |except for the gate input    |              |                    ||
-||        |action. The gate input is not|              |                    ||
-||   5    |used for enabled or disabled |Start counting|  Hardware trigger  ||
-||        |the timer. The gate input is |    value     |                    ||
-||        |used for triggered the timer.|              |                    ||
-|+--------+-----------------------------+--------------+--------------------+|
-|                                                                            |
-|                                                                            |
-|                                                                            |
-|                      Input clock selection table                           |
-|                                                                            |
-|  +--------------------------------+------------------------------------+   |
-|  |       b_InputClockSelection    |           Description              |   |
-|  |           parameter            |                                    |   |
-|  +--------------------------------+------------------------------------+   |
-|  |    APCI1710_PCI_BUS_CLOCK      | For the timer input clock, the PCI |   |
-|  |                                | bus clock / 4 is used. This PCI bus|   |
-|  |                                | clock can be 30MHz or 33MHz. For   |   |
-|  |                                | Timer 0 only this selection are    |   |
-|  |                                | available.                         |   |
-|  +--------------------------------+------------------------------------+   |
-|  | APCI1710_ FRONT_CONNECTOR_INPUT| Of the front connector you have the|   |
-|  |                                | possibility to inject a input clock|   |
-|  |                                | for Timer 1 or Timer 2. The source |   |
-|  |                                | from this clock can eat the output |   |
-|  |                                | clock from Timer 0 or any other    |   |
-|  |                                | clock source.                      |   |
-|  +--------------------------------+------------------------------------+   |
-|                                                                            |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle        : Handle of board         |
-|                                                    APCI-1710               |
-|                     unsigned char_   b_ModulNbr           : Module number to        |
-|                                                    configure (0 to 3)      |
-|                     unsigned char_   b_TimerNbr           : Timer number to         |
-|                                                    configure (0 to 2)      |
-|                     unsigned char_   b_TimerMode          : Timer mode selection    |
-|                                                    (0 to 5)                |
-|                                                    0: Interrupt on terminal|
-|                                                       count                |
-|                                                    1: Hardware             |
-|                                                       retriggerable one-   |
-|                                                       shot                 |
-|                                                    2: Rate generator       |
-|                                                    3: Square wave mode     |
-|                                                    4: Software triggered   |
-|                                                       strobe               |
-|                                                    5: Hardware triggered   |
-|                                                       strobe               |
-|                                                       See timer mode       |
-|                                                       description table.   |
-|                     ULONG_ ul_ReloadValue         : Start counting value   |
-|                                                     or division factor     |
-|                                                     See timer mode         |
-|                                                     description table.     |
-|                     unsigned char_   b_InputClockSelection : Selection from input   |
-|                                                     timer clock.           |
-|                                                     See input clock        |
-|                                                     selection table.       |
-|                     unsigned char_   b_InputClockLevel     : Selection from input   |
-|                                                     clock level.           |
-|                                                     0 : Low active         |
-|                                                         (Input inverted)   |
-|                                                     1 : High active        |
-|                     unsigned char_   b_OutputLevel,        : Selection from output  |
-|                                                     clock level.           |
-|                                                     0 : Low active         |
-|                                                     1 : High active        |
-|                                                         (Output inverted)  |
-|                     unsigned char_   b_HardwareGateLevel   : Selection from         |
-|                                                     hardware gate level.   |
-|                                                     0 : Low active         |
-|                                                         (Input inverted)   |
-|                                                     1 : High active        |
-|                                                     If you will not used   |
-|                                                     the hardware gate set  |
-|                                                     this value to 0.
-|b_ModulNbr        = (unsigned char) CR_AREF(insn->chanspec);
-	b_TimerNbr		  = (unsigned char) CR_CHAN(insn->chanspec);
-	b_TimerMode		  = (unsigned char) data[0];
-	ul_ReloadValue	  = (unsigned int) data[1];
-	b_InputClockSelection	=(unsigned char) data[2];
-	b_InputClockLevel		=(unsigned char) data[3];
-	b_OutputLevel			=(unsigned char) data[4];
-	b_HardwareGateLevel		=(unsigned char) data[5];
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: Timer selection wrong                               |
-|                    -4: The module is not a TIMER module                    |
-|                    -5: Timer mode selection is wrong                       |
-|                    -6: Input timer clock selection is wrong                |
-|                    -7: Selection from input clock level is wrong           |
-|                    -8: Selection from output clock level is wrong          |
-|                    -9: Selection from hardware gate level is wrong         |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev,
-					  struct comedi_subdevice *s,
-					  struct comedi_insn *insn,
-					  unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_ModulNbr;
-	unsigned char b_TimerNbr;
-	unsigned char b_TimerMode;
-	unsigned int ul_ReloadValue;
-	unsigned char b_InputClockSelection;
-	unsigned char b_InputClockLevel;
-	unsigned char b_OutputLevel;
-	unsigned char b_HardwareGateLevel;
-
-	/* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
-	unsigned int dw_Test = 0;
-	/* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec);
-	b_TimerMode = (unsigned char) data[0];
-	ul_ReloadValue = (unsigned int) data[1];
-	b_InputClockSelection = (unsigned char) data[2];
-	b_InputClockLevel = (unsigned char) data[3];
-	b_OutputLevel = (unsigned char) data[4];
-	b_HardwareGateLevel = (unsigned char) data[5];
-
-	/* Test the module number */
-	if (b_ModulNbr < 4) {
-		/* Test if 82X54 timer */
-		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-			/* Test the timer number */
-
-			if (b_TimerNbr <= 2) {
-				/* Test the timer mode */
-				if (b_TimerMode <= 5) {
-					/* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
-					/* Test te imput clock selection */
-					/*
-					   if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) ||
-					   ((b_TimerNbr != 0) && ((b_InputClockSelection == 0) || (b_InputClockSelection == 1))))
-					 */
-
-					if (((b_TimerNbr == 0) &&
-					     (b_InputClockSelection == APCI1710_PCI_BUS_CLOCK)) ||
-					    ((b_TimerNbr == 0) &&
-					     (b_InputClockSelection == APCI1710_10MHZ)) ||
-					    ((b_TimerNbr != 0) &&
-					     ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) ||
-					      (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) ||
-					      (b_InputClockSelection == APCI1710_10MHZ)))) {
-						/* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
-						if (((b_InputClockSelection == APCI1710_10MHZ) &&
-						     ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) ||
-						     (b_InputClockSelection != APCI1710_10MHZ)) {
-							/* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */
-							/* Test the input clock level selection */
-
-							if ((b_InputClockLevel == 0) ||
-							    (b_InputClockLevel == 1)) {
-								/* Test the output clock level selection */
-								if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) {
-									/* Test the hardware gate level selection */
-									if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) {
-										/* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
-										/* Test if version > 1.1 and clock selection = 10MHz */
-										if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) {
-											/* Test if 40MHz quartz on board */
-											dw_Test = inl(devpriv->s_BoardInfos.ui_Address + (16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)));
-
-											dw_Test = (dw_Test >> 16) & 1;
-										} else {
-											dw_Test = 1;
-										}
-
-										/* Test if detection OK */
-										if (dw_Test == 1) {
-											/* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
-											/* Initialisation OK */
-											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1;
-
-											/* Save the input clock selection */
-											devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockSelection = b_InputClockSelection;
-
-											/* Save the input clock level */
-											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockLevel = ~b_InputClockLevel & 1;
-
-											/* Save the output level */
-											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel = ~b_OutputLevel & 1;
-
-											/* Save the gate level */
-											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel;
-
-											/* Set the configuration word and disable the timer */
-											/* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
-											/*
-											   devpriv->s_ModuleInfo [b_ModulNbr].
-											   s_82X54ModuleInfo.
-											   s_82X54TimerInfo  [b_TimerNbr].
-											   dw_ConfigurationWord = (unsigned int) (((b_HardwareGateLevel         << 0) & 0x1) |
-											   ((b_InputClockLevel           << 1) & 0x2) |
-											   (((~b_OutputLevel       & 1)  << 2) & 0x4) |
-											   ((b_InputClockSelection       << 4) & 0x10));
-											 */
-											/* Test if 10MHz selected */
-											if (b_InputClockSelection == APCI1710_10MHZ) {
-												b_InputClockSelection = 2;
-											}
-
-											devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (unsigned int)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30));
-											/* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
-											outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-											/* Initialise the 82X54 Timer */
-											outl((unsigned int) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-											/* Write the reload value */
-											outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-											/* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
-										}	/*  if (dw_Test == 1) */
-										else {
-											/* Input timer clock selection is wrong */
-											i_ReturnValue = -6;
-										}	/*  if (dw_Test == 1) */
-										/* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */
-									}	/*  if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */
-									else {
-										/* Selection from hardware gate level is wrong */
-										DPRINTK("Selection from hardware gate level is wrong\n");
-										i_ReturnValue = -9;
-									}	/*  if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */
-								}	/*  if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */
-								else {
-									/* Selection from output clock level is wrong */
-									DPRINTK("Selection from output clock level is wrong\n");
-									i_ReturnValue = -8;
-								}	/*  if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */
-							}	/*  if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */
-							else {
-								/* Selection from input clock level is wrong */
-								DPRINTK("Selection from input clock level is wrong\n");
-								i_ReturnValue = -7;
-							}	/*  if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */
-						} else {
-							/* Input timer clock selection is wrong */
-							DPRINTK("Input timer clock selection is wrong\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-						/* Input timer clock selection is wrong */
-						DPRINTK("Input timer clock selection is wrong\n");
-						i_ReturnValue = -6;
-					}
-				}	/*  if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */
-				else {
-					/* Timer mode selection is wrong */
-					DPRINTK("Timer mode selection is wrong\n");
-					i_ReturnValue = -5;
-				}	/*  if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-			else {
-				/* Timer selection wrong */
-				DPRINTK("Timer selection wrong\n");
-				i_ReturnValue = -3;
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-		} else {
-			/* The module is not a TIMER module */
-			DPRINTK("The module is not a TIMER module\n");
-			i_ReturnValue = -4;
-		}
-	} else {
-		/* Module number error */
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_EnableTimer                       |
-|                               (unsigned char_ b_BoardHandle,                        |
-|                                unsigned char_ b_ModulNbr,                           |
-|                                unsigned char_ b_TimerNbr,                           |
-|                                unsigned char_ b_InterruptEnable)
-int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s,
-	struct comedi_insn *insn,unsigned int *data)                |
-+----------------------------------------------------------------------------+
-| Task              : Enable OR Disable the Timer (b_TimerNbr) from selected module     |
-|                     (b_ModulNbr). You must calling the                     |
-|                     "i_APCI1710_InitTimer" function be for you call this   |
-|                     function. If you enable the timer interrupt, the timer |
-|                     generate a interrupt after the timer value reach       |
-|                     the zero. See function "i_APCI1710_SetBoardIntRoutineX"|
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle     : Handle of board            |
-|                                                 APCI-1710                  |
-|                     unsigned char_   b_ModulNbr        : Selected module number     |
-|                                                 (0 to 3)                   |
-|                     unsigned char_   b_TimerNbr        : Timer number to enable     |
-|                                                 (0 to 2)                   |
-|                     unsigned char_   b_InterruptEnable : Enable or disable the      |
-|                                                 timer interrupt.           |
-|                                                 APCI1710_ENABLE :          |
-|                                                 Enable the timer interrupt |
-|                                                 APCI1710_DISABLE :         |
-|                                                 Disable the timer interrupt|
-i_ReturnValue=insn->n;
-	b_ModulNbr        = (unsigned char) CR_AREF(insn->chanspec);
-	b_TimerNbr		  = (unsigned char) CR_CHAN(insn->chanspec);
-	b_ActionType      = (unsigned char) data[0]; /*  enable disable */
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: Timer selection wrong                               |
-|                    -4: The module is not a TIMER module                    |
-|                    -5: Timer not initialised see function                  |
-|                        "i_APCI1710_InitTimer"                              |
-|                    -6: Interrupt parameter is wrong                        |
-|                    -7: Interrupt function not initialised.                 |
-|                        See function "i_APCI1710_SetBoardIntRoutineX"       |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,
-						 struct comedi_subdevice *s,
-						 struct comedi_insn *insn,
-						 unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_DummyRead;
-	unsigned char b_ModulNbr;
-	unsigned char b_TimerNbr;
-	unsigned char b_ActionType;
-	unsigned char b_InterruptEnable;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec);
-	b_ActionType = (unsigned char) data[0];	/*  enable disable */
-
-	/* Test the module number */
-	if (b_ModulNbr < 4) {
-		/* Test if 82X54 timer */
-		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-			/* Test the timer number */
-			if (b_TimerNbr <= 2) {
-				/* Test if timer initialised */
-				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
-
-					switch (b_ActionType) {
-					case APCI1710_ENABLE:
-						b_InterruptEnable = (unsigned char) data[1];
-						/* Test the interrupt selection */
-						if ((b_InterruptEnable == APCI1710_ENABLE) ||
-						    (b_InterruptEnable == APCI1710_DISABLE)) {
-							if (b_InterruptEnable == APCI1710_ENABLE) {
-
-								dw_DummyRead = inl(devpriv->s_BoardInfos.ui_Address + 12 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-								/* Enable the interrupt */
-								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8;
-
-								outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-								devpriv->tsk_Current = current;	/*  Save the current process task structure */
-
-							}	/*  if (b_InterruptEnable == APCI1710_ENABLE) */
-							else {
-								/* Disable the interrupt */
-								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
-
-								outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-								/* Save the interrupt flag */
-								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
-							}	/*  if (b_InterruptEnable == APCI1710_ENABLE) */
-
-							/* Test if error occur */
-							if (i_ReturnValue >= 0) {
-								/* Save the interrupt flag */
-								devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask | ((1 & b_InterruptEnable) << b_TimerNbr);
-
-								/* Enable the timer */
-								outl(1, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-							}
-						} else {
-							/* Interrupt parameter is wrong */
-							DPRINTK("\n");
-							i_ReturnValue = -6;
-						}
-						break;
-					case APCI1710_DISABLE:
-						/* Test the interrupt flag */
-						if (((devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask >> b_TimerNbr) & 1) == 1) {
-							/* Disable the interrupt */
-
-							devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr]. dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7;
-
-							outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-							/* Save the interrupt flag */
-							devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr));
-						}
-
-						/* Disable the timer */
-						outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-						break;
-					}	/*  Switch end */
-				} else {
-					/* Timer not initialised see function */
-					DPRINTK ("Timer not initialised see function\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-				/* Timer selection wrong */
-				DPRINTK("Timer selection wrong\n");
-				i_ReturnValue = -3;
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-		} else {
-			/* The module is not a TIMER module */
-			DPRINTK("The module is not a TIMER module\n");
-			i_ReturnValue = -4;
-		}
-	} else {
-		/* Module number error */
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_ReadAllTimerValue                 |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        PULONG_ pul_TimerValueArray)
-int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s,
-	struct comedi_insn *insn,unsigned int *data)        |
-+----------------------------------------------------------------------------+
-| Task              : Return the all timer values from selected timer        |
-|                     module (b_ModulNbr).                                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle     : Handle of board            |
-|                                                 APCI-1710                  |
-|                     unsigned char_   b_ModulNbr        : Selected module number     |
-|                                                 (0 to 3)                   |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_TimerValueArray : Timer value array.       |
-|                           Element 0 contain the timer 0 value.             |
-|                           Element 1 contain the timer 1 value.             |
-|                           Element 2 contain the timer 2 value.             |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: The module is not a TIMER module                    |
-|                    -4: Timer 0 not initialised see function                |
-|                        "i_APCI1710_InitTimer"                              |
-|                    -5: Timer 1 not initialised see function                |
-|                        "i_APCI1710_InitTimer"                              |
-|                    -6: Timer 2 not initialised see function                |
-|                        "i_APCI1710_InitTimer"                              |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,
-					    struct comedi_subdevice *s,
-					    struct comedi_insn *insn,
-					    unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_ModulNbr, b_ReadType;
-	unsigned int *pul_TimerValueArray;
-
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_ReadType = CR_CHAN(insn->chanspec);
-	pul_TimerValueArray = (unsigned int *) data;
-	i_ReturnValue = insn->n;
-
-	switch (b_ReadType) {
-	case APCI1710_TIMER_READINTERRUPT:
-
-		data[0] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].b_OldModuleMask;
-		data[1] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldInterruptMask;
-		data[2] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
-		/* Increment the read FIFO */
-		devpriv->s_InterruptParameters.ui_Read = (devpriv->s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
-		break;
-
-	case APCI1710_TIMER_READALLTIMER:
-		/* Test the module number */
-		if (b_ModulNbr < 4) {
-			/* Test if 82X54 timer */
-			if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-				/* Test if timer 0 iniutialised */
-				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[0].b_82X54Init == 1) {
-					/* Test if timer 1 iniutialised */
-					if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[1].b_82X54Init == 1) {
-						/* Test if timer 2 iniutialised */
-						if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[2].b_82X54Init == 1) {
-							/* Latch all counter */
-							outl(0x17, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
-							/* Read the timer 0 value */
-							pul_TimerValueArray[0] = inl(devpriv->s_BoardInfos.ui_Address + 0 + (64 * b_ModulNbr));
-
-							/* Read the timer 1 value */
-							pul_TimerValueArray[1] = inl(devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
-
-							/* Read the timer 2 value */
-							pul_TimerValueArray[2] = inl(devpriv->s_BoardInfos.ui_Address + 8 + (64 * b_ModulNbr));
-						} else {
-							/* Timer 2 not initialised see function */
-							DPRINTK("Timer 2 not initialised see function\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-						/* Timer 1 not initialised see function */
-						DPRINTK("Timer 1 not initialised see function\n");
-						i_ReturnValue = -5;
-					}
-				} else {
-					/* Timer 0 not initialised see function */
-					DPRINTK("Timer 0 not initialised see function\n");
-					i_ReturnValue = -4;
-				}
-			} else {
-				/* The module is not a TIMER module */
-				DPRINTK("The module is not a TIMER module\n");
-				i_ReturnValue = -3;
-			}
-		} else {
-			/* Module number error */
-			DPRINTK("Module number error\n");
-			i_ReturnValue = -2;
-		}
-
-	}			/*  End of Switch */
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_ReadTimerValue                    |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_TimerNbr,               |
-|                                        PULONG_ pul_TimerValue)             |
-+----------------------------------------------------------------------------+
-| Task              : Return the timer value from selected digital timer     |
-|                     (b_TimerNbr) from selected timer  module (b_ModulNbr). |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle     : Handle of board            |
-|                                                 APCI-1710                  |
-|                     unsigned char_   b_ModulNbr        : Selected module number     |
-|                                                 (0 to 3)                   |
-|                     unsigned char_   b_TimerNbr        : Timer number to read       |
-|                                                 (0 to 2)                   |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_TimerValue    : Timer value                |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: Timer selection wrong                               |
-|                    -4: The module is not a TIMER module                    |
-|                    -5: Timer not initialised see function                  |
-|                        "i_APCI1710_InitTimer"                              |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadTimerValue(struct comedi_device *dev,
-				     unsigned char b_ModulNbr,
-				     unsigned char b_TimerNbr,
-				     unsigned int *pul_TimerValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/* Test the module number */
-	if (b_ModulNbr < 4) {
-		/* Test if 82X54 timer */
-		if ((devpriv->s_BoardInfos.
-		     dw_MolduleConfiguration[b_ModulNbr] &
-		     0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-			/* Test the timer number */
-			if (b_TimerNbr <= 2) {
-				/* Test if timer initialised */
-				if (devpriv->
-				    s_ModuleInfo[b_ModulNbr].
-				    s_82X54ModuleInfo.
-				    s_82X54TimerInfo[b_TimerNbr].
-				    b_82X54Init == 1) {
-					/* Latch the timer value */
-					outl((2 << b_TimerNbr) | 0xD0,
-					     devpriv->s_BoardInfos.
-					     ui_Address + 12 +
-					     (64 * b_ModulNbr));
-
-					/* Read the counter value */
-					*pul_TimerValue =
-					    inl(devpriv->s_BoardInfos.
-						ui_Address + (b_TimerNbr * 4) +
-						(64 * b_ModulNbr));
-				} else {
-					/* Timer not initialised see function */
-					DPRINTK("Timer not initialised see function\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-				/* Timer selection wrong */
-				DPRINTK("Timer selection wrong\n");
-				i_ReturnValue = -3;
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-		} else {
-			/* The module is not a TIMER module */
-			DPRINTK("The module is not a TIMER module\n");
-			i_ReturnValue = -4;
-		}
-	} else {
-		/* Module number error */
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-	/*
-	   +----------------------------------------------------------------------------+
-	   | Function Name     : _INT_     i_APCI1710_GetTimerOutputLevel               |
-	   |                                       (unsigned char_     b_BoardHandle,            |
-	   |                                        unsigned char_     b_ModulNbr,               |
-	   |                                        unsigned char_     b_TimerNbr,               |
-	   |                                        unsigned char *_   pb_OutputLevel)            |
-	   +----------------------------------------------------------------------------+
-	   | Task              : Return the output signal level (pb_OutputLevel) from   |
-	   |                     selected digital timer (b_TimerNbr) from selected timer|
-	   |                     module (b_ModulNbr).                                   |
-	   +----------------------------------------------------------------------------+
-	   | Input Parameters  : unsigned char_   b_BoardHandle     : Handle of board            |
-	   |                                                 APCI-1710                  |
-	   |                     unsigned char_   b_ModulNbr        : Selected module number     |
-	   |                                                 (0 to 3)                   |
-	   |                     unsigned char_   b_TimerNbr        : Timer number to test       |
-	   |                                                 (0 to 2)                   |
-	   +----------------------------------------------------------------------------+
-	   | Output Parameters : unsigned char *_ pb_OutputLevel     : Output signal level        |
-	   |                                                 0 : The output is low      |
-	   |                                                 1 : The output is high     |
-	   +----------------------------------------------------------------------------+
-	   | Return Value      : 0: No error                                            |
-	   |                    -1: The handle parameter of the board is wrong          |
-	   |                    -2: Module selection wrong                              |
-	   |                    -3: Timer selection wrong                               |
-	   |                    -4: The module is not a TIMER module                    |
-	   |                    -5: Timer not initialised see function                  |
-	   |                        "i_APCI1710_InitTimer"                              |
-	   +----------------------------------------------------------------------------+
-	 */
-static int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev,
-					  unsigned char b_ModulNbr,
-					  unsigned char b_TimerNbr,
-					  unsigned char *pb_OutputLevel)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_TimerStatus;
-
-	/* Test the module number */
-	if (b_ModulNbr < 4) {
-		/* Test if 82X54 timer */
-		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-			/* Test the timer number */
-			if (b_TimerNbr <= 2) {
-				/* Test if timer initialised */
-				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
-					/* Latch the timer value */
-					outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
-					/* Read the timer status */
-					dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-					*pb_OutputLevel = (unsigned char) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel);
-				} else {
-					/* Timer not initialised see function */
-					DPRINTK("Timer not initialised see function\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-				/* Timer selection wrong */
-				DPRINTK("Timer selection wrong\n");
-				i_ReturnValue = -3;
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-		} else {
-			/* The module is not a TIMER module */
-			DPRINTK("The module is not a TIMER module\n");
-			i_ReturnValue = -4;
-		}
-	} else {
-		/* Module number error */
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_GetTimerProgressStatus            |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_TimerNbr,               |
-|                                        unsigned char *_   pb_TimerStatus)            |
-+----------------------------------------------------------------------------+
-| Task              : Return the progress status (pb_TimerStatus) from       |
-|                     selected digital timer (b_TimerNbr) from selected timer|
-|                     module (b_ModulNbr).                                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle     : Handle of board            |
-|                                                 APCI-1710                  |
-|                     unsigned char_   b_ModulNbr        : Selected module number     |
-|                                                 (0 to 3)                   |
-|                     unsigned char_   b_TimerNbr        : Timer number to test       |
-|                                                 (0 to 2)                   |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TimerStatus     : Output signal level        |
-|                                                 0 : Timer not in progress  |
-|                                                 1 : Timer in progress      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: Timer selection wrong                               |
-|                    -4: The module is not a TIMER module                    |
-|                    -5: Timer not initialised see function                  |
-|                        "i_APCI1710_InitTimer"                              |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev,
-					     unsigned char b_ModulNbr,
-					     unsigned char b_TimerNbr,
-					     unsigned char *pb_TimerStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_TimerStatus;
-
-	/* Test the module number */
-	if (b_ModulNbr < 4) {
-		/* Test if 82X54 timer */
-
-		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-			/* Test the timer number */
-			if (b_TimerNbr <= 2) {
-				/* Test if timer initialised */
-				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
-					/* Latch the timer value */
-					outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
-					/* Read the timer status */
-					dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-
-					*pb_TimerStatus = (unsigned char) ((dw_TimerStatus) >> 8) & 1;
-					printk("ProgressStatus : %d", *pb_TimerStatus);
-				} else {
-					/* Timer not initialised see function */
-					i_ReturnValue = -5;
-				}
-			} else {
-				/* Timer selection wrong */
-				i_ReturnValue = -3;
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-		} else {
-			/* The module is not a TIMER module */
-
-			i_ReturnValue = -4;
-		}
-	} else {
-		/* Module number error */
-
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_WriteTimerValue                   |
-|                                       (unsigned char_   b_BoardHandle,              |
-|                                        unsigned char_   b_ModulNbr,                 |
-|                                        unsigned char_   b_TimerNbr,                 |
-|                                        ULONG_ ul_WriteValue)               |
-+----------------------------------------------------------------------------+
-| Task              : Write the value (ul_WriteValue) into the selected timer|
-|                     (b_TimerNbr) from selected timer module (b_ModulNbr).  |
-|                     The action in depend of the time mode selection.       |
-|                     See timer mode description table.                      |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle     : Handle of board            |
-|                                                 APCI-1710                  |
-|                     unsigned char_   b_ModulNbr        : Selected module number     |
-|                                                 (0 to 3)                   |
-|                     unsigned char_   b_TimerNbr        : Timer number to write      |
-|                                                 (0 to 2)                   |
-|                     ULONG_ ul_WriteValue      : Value to write             |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: Timer selection wrong                               |
-|                    -4: The module is not a TIMER module                    |
-|                    -5: Timer not initialised see function                  |
-|                        "i_APCI1710_InitTimer"                              |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_WriteTimerValue(struct comedi_device *dev,
-				      unsigned char b_ModulNbr,
-				      unsigned char b_TimerNbr,
-				      unsigned int ul_WriteValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/* Test the module number */
-	if (b_ModulNbr < 4) {
-		/* Test if 82X54 timer */
-		if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-			/* Test the timer number */
-			if (b_TimerNbr <= 2) {
-				/* Test if timer initialised */
-				if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) {
-					/* Write the value */
-					outl(ul_WriteValue, devpriv->s_BoardInfos.ui_Address + (b_TimerNbr * 4) + (64 * b_ModulNbr));
-				} else {
-					/* Timer not initialised see function */
-					DPRINTK("Timer not initialised see function\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-				/* Timer selection wrong */
-				DPRINTK("Timer selection wrong\n");
-				i_ReturnValue = -3;
-			}	/*  if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */
-		} else {
-			/* The module is not a TIMER module */
-			DPRINTK("The module is not a TIMER module\n");
-			i_ReturnValue = -4;
-		}
-	} else {
-		/* Module number error */
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     :INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev,
-struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)                   |
-+----------------------------------------------------------------------------+
-| Task              : Read write functions for Timer                                          |
-+----------------------------------------------------------------------------+
-| Input Parameters  :
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnBitsTimer(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
-{
-	unsigned char b_BitsType;
-	int i_ReturnValue = 0;
-	b_BitsType = data[0];
-
-	printk("\n82X54");
-
-	switch (b_BitsType) {
-	case APCI1710_TIMER_READVALUE:
-		i_ReturnValue = i_APCI1710_ReadTimerValue(dev,
-							  (unsigned char)CR_AREF(insn->chanspec),
-							  (unsigned char)CR_CHAN(insn->chanspec),
-							  (unsigned int *) &data[0]);
-		break;
-
-	case APCI1710_TIMER_GETOUTPUTLEVEL:
-		i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev,
-							       (unsigned char)CR_AREF(insn->chanspec),
-							       (unsigned char)CR_CHAN(insn->chanspec),
-							       (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_TIMER_GETPROGRESSSTATUS:
-		i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev,
-								  (unsigned char)CR_AREF(insn->chanspec),
-								  (unsigned char)CR_CHAN(insn->chanspec),
-								  (unsigned char *)&data[0]);
-		break;
-
-	case APCI1710_TIMER_WRITEVALUE:
-		i_ReturnValue = i_APCI1710_WriteTimerValue(dev,
-							   (unsigned char)CR_AREF(insn->chanspec),
-							   (unsigned char)CR_CHAN(insn->chanspec),
-							   (unsigned int)data[1]);
-
-		break;
-
-	default:
-		printk("Bits Config Parameter Wrong\n");
-		i_ReturnValue = -1;
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
deleted file mode 100644
index d91f586..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c
+++ /dev/null
@@ -1,2050 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : CHRONO.C        | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 chronometer module                          |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  | 29/06/98 | S. Weber  | Digital input / output implementation          |
-  |----------|-----------|------------------------------------------------|
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-  |          |           |                                                |
-  |          |           |                                                |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ			30
-#define APCI1710_33MHZ			33
-#define APCI1710_40MHZ			40
-
-#define APCI1710_SINGLE			0
-#define APCI1710_CONTINUOUS		1
-
-#define APCI1710_CHRONO_PROGRESS_STATUS	0
-#define APCI1710_CHRONO_READVALUE	1
-#define APCI1710_CHRONO_CONVERTVALUE	2
-#define APCI1710_CHRONO_READINTERRUPT	3
-
-#define APCI1710_CHRONO_SET_CHANNELON	0
-#define APCI1710_CHRONO_SET_CHANNELOFF	1
-#define APCI1710_CHRONO_READ_CHANNEL	2
-#define APCI1710_CHRONO_READ_PORT	3
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_InitChrono                        |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_ChronoMode,             |
-|                                        unsigned char_     b_PCIInputClock,          |
-|                                        unsigned char_     b_TimingUnit,             |
-|                                        ULONG_   ul_TimingInterval,         |
-|                                        PULONG_ pul_RealTimingInterval)
-
-+----------------------------------------------------------------------------+
-| Task              : Configure the chronometer operating mode (b_ChronoMode)|
-|                     from selected module (b_ModulNbr).                     |
-|                     The ul_TimingInterval and ul_TimingUnit determine the  |
-|                     timing base for the measurement.                       |
-|                     The pul_RealTimingInterval return the real timing      |
-|                     value. You must calling this function be for you call  |
-|                     any other function witch access of the chronometer.    |
-|                                                                            |
-|                     Witch this functionality from the APCI-1710 you have   |
-|                     the possibility to measure the timing witch two event. |
-|                                                                            |
-|                     The mode 0 and 1 is appropriate for period measurement.|
-|                     The mode 2 and 3 is appropriate for frequent           |
-|                     measurement.                                           |
-|                     The mode 4 to 7 is appropriate for measuring the timing|
-|                     between  two event.                                    |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle    : Handle of board APCI-1710   |
-| unsigned char_   b_ModulNbr  CR_AREF(insn->chanspec)  : Module number to configure  |
-|                                                (0 to 3)                    |
-| unsigned char_   b_ChronoMode				data[0]    : Chronometer action mode     |
-|                                                (0 to 7).                   |
-| unsigned char_   b_PCIInputClock			data[1] : Selection from PCI bus clock|
-|                                                - APCI1710_30MHZ :          |
-|                                                  The PC have a PCI bus     |
-|                                                  clock from 30 MHz         |
-|                                                - APCI1710_33MHZ :          |
-|                                                  The PC have a PCI bus     |
-|                                                  clock from 33 MHz         |
-|                                                - APCI1710_40MHZ            |
-|                                                  The APCI-1710 have a      |
-|                                                  integrated 40Mhz          |
-|                                                  quartz.                   |
-|               unsigned char_   b_TimingUnit	data[2]    : Base timing unity (0 to 4) |
-|                                                 0 : ns                     |
-|                                                 1 : µs                     |
-|                                                 2 : ms                     |
-|                                                 3 : s                      |
-|                                                 4 : mn                     |
-|         ULONG_ ul_TimingInterval : data[3]	 Base timing value.          |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pul_RealTimingInterval : Real  base timing    |
-|                                                       value.
-|                     data[0]
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: Chronometer mode selection is wrong                |
-|                     -5: The selected PCI input clock is wrong              |
-|                     -6: Timing unity selection is wrong                    |
-|                     -7: Base timing selection is wrong                     |
-|                     -8: You can not used the 40MHz clock selection with    |
-|                         this board                                         |
-|                     -9: You can not used the 40MHz clock selection with    |
-|                         this CHRONOS version                               |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ul_TimerValue = 0;
-	unsigned int ul_TimingInterval = 0;
-	unsigned int ul_RealTimingInterval = 0;
-	double d_RealTimingInterval = 0;
-	unsigned int dw_ModeArray[8] =
-		{ 0x01, 0x05, 0x00, 0x04, 0x02, 0x0E, 0x0A, 0x06 };
-	unsigned char b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit;
-
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_ChronoMode = (unsigned char) data[0];
-	b_PCIInputClock = (unsigned char) data[1];
-	b_TimingUnit = (unsigned char) data[2];
-	ul_TimingInterval = (unsigned int) data[3];
-	i_ReturnValue = insn->n;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if chronometer */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-	      /*****************************/
-			/* Test the chronometer mode */
-	      /*****************************/
-
-			if (b_ChronoMode <= 7) {
-		 /**************************/
-				/* Test the PCI bus clock */
-		 /**************************/
-
-				if ((b_PCIInputClock == APCI1710_30MHZ) ||
-					(b_PCIInputClock == APCI1710_33MHZ) ||
-					(b_PCIInputClock == APCI1710_40MHZ)) {
-		    /*************************/
-					/* Test the timing unity */
-		    /*************************/
-
-					if (b_TimingUnit <= 4) {
-		       /**********************************/
-						/* Test the base timing selection */
-		       /**********************************/
-
-						if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 66) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165576UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 60) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150240UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 50) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374182UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 1UL))) {
-			  /**************************/
-							/* Test the board version */
-			  /**************************/
-
-							if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) {
-			     /************************/
-								/* Test the TOR version */
-			     /************************/
-
-								if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || (b_PCIInputClock != APCI1710_40MHZ)) {
-									fpu_begin
-										();
-
-				/****************************************/
-									/* Calculate the timer 0 division fator */
-				/****************************************/
-
-									switch (b_TimingUnit) {
-				   /******/
-										/* ns */
-				   /******/
-
-									case 0:
-
-					   /******************/
-										/* Timer 0 factor */
-					   /******************/
-
-										ul_TimerValue
-											=
-											(unsigned int)
-											(ul_TimingInterval
-											*
-											(0.001 * b_PCIInputClock));
-
-					   /*******************/
-										/* Round the value */
-					   /*******************/
-
-										if ((double)((double)ul_TimingInterval * (0.001 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-											ul_TimerValue
-												=
-												ul_TimerValue
-												+
-												1;
-										}
-
-					   /*****************************/
-										/* Calculate the real timing */
-					   /*****************************/
-
-										ul_RealTimingInterval
-											=
-											(unsigned int)
-											(ul_TimerValue
-											/
-											(0.001 * (double)b_PCIInputClock));
-										d_RealTimingInterval
-											=
-											(double)
-											ul_TimerValue
-											/
-											(0.001
-											*
-											(double)
-											b_PCIInputClock);
-
-										if ((double)((double)ul_TimerValue / (0.001 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-											ul_RealTimingInterval
-												=
-												ul_RealTimingInterval
-												+
-												1;
-										}
-
-										ul_TimingInterval
-											=
-											ul_TimingInterval
-											-
-											1;
-										ul_TimerValue
-											=
-											ul_TimerValue
-											-
-											2;
-										if (b_PCIInputClock != APCI1710_40MHZ) {
-											ul_TimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_TimerValue)
-												*
-												0.99392);
-										}
-
-										break;
-
-				   /******/
-										/* æs */
-				   /******/
-
-									case 1:
-
-					   /******************/
-										/* Timer 0 factor */
-					   /******************/
-
-										ul_TimerValue
-											=
-											(unsigned int)
-											(ul_TimingInterval
-											*
-											(1.0 * b_PCIInputClock));
-
-					   /*******************/
-										/* Round the value */
-					   /*******************/
-
-										if ((double)((double)ul_TimingInterval * (1.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-											ul_TimerValue
-												=
-												ul_TimerValue
-												+
-												1;
-										}
-
-					   /*****************************/
-										/* Calculate the real timing */
-					   /*****************************/
-
-										ul_RealTimingInterval
-											=
-											(unsigned int)
-											(ul_TimerValue
-											/
-											(1.0 * (double)b_PCIInputClock));
-										d_RealTimingInterval
-											=
-											(double)
-											ul_TimerValue
-											/
-											(
-											(double)
-											1.0
-											*
-											(double)
-											b_PCIInputClock);
-
-										if ((double)((double)ul_TimerValue / (1.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-											ul_RealTimingInterval
-												=
-												ul_RealTimingInterval
-												+
-												1;
-										}
-
-										ul_TimingInterval
-											=
-											ul_TimingInterval
-											-
-											1;
-										ul_TimerValue
-											=
-											ul_TimerValue
-											-
-											2;
-										if (b_PCIInputClock != APCI1710_40MHZ) {
-											ul_TimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_TimerValue)
-												*
-												0.99392);
-										}
-
-										break;
-
-				   /******/
-										/* ms */
-				   /******/
-
-									case 2:
-
-					   /******************/
-										/* Timer 0 factor */
-					   /******************/
-
-										ul_TimerValue
-											=
-											ul_TimingInterval
-											*
-											(1000
-											*
-											b_PCIInputClock);
-
-					   /*******************/
-										/* Round the value */
-					   /*******************/
-
-										if ((double)((double)ul_TimingInterval * (1000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-											ul_TimerValue
-												=
-												ul_TimerValue
-												+
-												1;
-										}
-
-					   /*****************************/
-										/* Calculate the real timing */
-					   /*****************************/
-
-										ul_RealTimingInterval
-											=
-											(unsigned int)
-											(ul_TimerValue
-											/
-											(1000.0 * (double)b_PCIInputClock));
-										d_RealTimingInterval
-											=
-											(double)
-											ul_TimerValue
-											/
-											(1000.0
-											*
-											(double)
-											b_PCIInputClock);
-
-										if ((double)((double)ul_TimerValue / (1000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-											ul_RealTimingInterval
-												=
-												ul_RealTimingInterval
-												+
-												1;
-										}
-
-										ul_TimingInterval
-											=
-											ul_TimingInterval
-											-
-											1;
-										ul_TimerValue
-											=
-											ul_TimerValue
-											-
-											2;
-										if (b_PCIInputClock != APCI1710_40MHZ) {
-											ul_TimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_TimerValue)
-												*
-												0.99392);
-										}
-
-										break;
-
-				   /*****/
-										/* s */
-				   /*****/
-
-									case 3:
-
-					   /******************/
-										/* Timer 0 factor */
-					   /******************/
-
-										ul_TimerValue
-											=
-											(unsigned int)
-											(ul_TimingInterval
-											*
-											(1000000.0
-												*
-												b_PCIInputClock));
-
-					   /*******************/
-										/* Round the value */
-					   /*******************/
-
-										if ((double)((double)ul_TimingInterval * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-											ul_TimerValue
-												=
-												ul_TimerValue
-												+
-												1;
-										}
-
-					   /*****************************/
-										/* Calculate the real timing */
-					   /*****************************/
-
-										ul_RealTimingInterval
-											=
-											(unsigned int)
-											(ul_TimerValue
-											/
-											(1000000.0
-												*
-												(double)
-												b_PCIInputClock));
-										d_RealTimingInterval
-											=
-											(double)
-											ul_TimerValue
-											/
-											(1000000.0
-											*
-											(double)
-											b_PCIInputClock);
-
-										if ((double)((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-											ul_RealTimingInterval
-												=
-												ul_RealTimingInterval
-												+
-												1;
-										}
-
-										ul_TimingInterval
-											=
-											ul_TimingInterval
-											-
-											1;
-										ul_TimerValue
-											=
-											ul_TimerValue
-											-
-											2;
-										if (b_PCIInputClock != APCI1710_40MHZ) {
-											ul_TimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_TimerValue)
-												*
-												0.99392);
-										}
-
-										break;
-
-				   /******/
-										/* mn */
-				   /******/
-
-									case 4:
-
-					   /******************/
-										/* Timer 0 factor */
-					   /******************/
-
-										ul_TimerValue
-											=
-											(unsigned int)
-											(
-											(ul_TimingInterval
-												*
-												60)
-											*
-											(1000000.0
-												*
-												b_PCIInputClock));
-
-					   /*******************/
-										/* Round the value */
-					   /*******************/
-
-										if ((double)((double)(ul_TimingInterval * 60.0) * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-											ul_TimerValue
-												=
-												ul_TimerValue
-												+
-												1;
-										}
-
-					   /*****************************/
-										/* Calculate the real timing */
-					   /*****************************/
-
-										ul_RealTimingInterval
-											=
-											(unsigned int)
-											(ul_TimerValue
-											/
-											(1000000.0
-												*
-												(double)
-												b_PCIInputClock))
-											/
-											60;
-										d_RealTimingInterval
-											=
-											(
-											(double)
-											ul_TimerValue
-											/
-											(0.001 * (double)b_PCIInputClock)) / 60.0;
-
-										if ((double)(((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-											ul_RealTimingInterval
-												=
-												ul_RealTimingInterval
-												+
-												1;
-										}
-
-										ul_TimingInterval
-											=
-											ul_TimingInterval
-											-
-											1;
-										ul_TimerValue
-											=
-											ul_TimerValue
-											-
-											2;
-										if (b_PCIInputClock != APCI1710_40MHZ) {
-											ul_TimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_TimerValue)
-												*
-												0.99392);
-										}
-
-										break;
-									}
-
-									fpu_end();
-
-				/****************************/
-									/* Save the PCI input clock */
-				/****************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_ChronoModuleInfo.
-										b_PCIInputClock
-										=
-										b_PCIInputClock;
-
-				/*************************/
-									/* Save the timing unity */
-				/*************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_ChronoModuleInfo.
-										b_TimingUnit
-										=
-										b_TimingUnit;
-
-				/************************/
-									/* Save the base timing */
-				/************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_ChronoModuleInfo.
-										d_TimingInterval
-										=
-										d_RealTimingInterval;
-
-				/****************************/
-									/* Set the chronometer mode */
-				/****************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_ChronoModuleInfo.
-										dw_ConfigReg
-										=
-										dw_ModeArray
-										[b_ChronoMode];
-
-				/***********************/
-									/* Test if 40 MHz used */
-				/***********************/
-
-									if (b_PCIInputClock == APCI1710_40MHZ) {
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_ChronoModuleInfo.
-											dw_ConfigReg
-											=
-											devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_ChronoModuleInfo.
-											dw_ConfigReg
-											|
-											0x80;
-									}
-
-									outl(devpriv->s_ModuleInfo[b_ModulNbr].s_ChronoModuleInfo.dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr));
-
-				/***********************/
-									/* Write timer 0 value */
-				/***********************/
-
-									outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
-
-				/*********************/
-									/* Chronometer init. */
-				/*********************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_ChronoModuleInfo.
-										b_ChronoInit
-										=
-										1;
-								} else {
-				/***********************************************/
-									/* TOR version error for 40MHz clock selection */
-				/***********************************************/
-
-									DPRINTK("TOR version error for 40MHz clock selection\n");
-									i_ReturnValue
-										=
-										-9;
-								}
-							} else {
-			     /**************************************************************/
-								/* You can not use the 40MHz clock selection with this board */
-			     /**************************************************************/
-
-								DPRINTK("You can not used the 40MHz clock selection with this board\n");
-								i_ReturnValue =
-									-8;
-							}
-						} else {
-			  /**********************************/
-							/* Base timing selection is wrong */
-			  /**********************************/
-
-							DPRINTK("Base timing selection is wrong\n");
-							i_ReturnValue = -7;
-						}
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-					else {
-		       /***********************************/
-						/* Timing unity selection is wrong */
-		       /***********************************/
-
-						DPRINTK("Timing unity selection is wrong\n");
-						i_ReturnValue = -6;
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-				}	/*  if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
-				else {
-		    /*****************************************/
-					/* The selected PCI input clock is wrong */
-		    /*****************************************/
-
-					DPRINTK("The selected PCI input clock is wrong\n");
-					i_ReturnValue = -5;
-				}	/*  if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
-			}	/*  if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */
-			else {
-		 /***************************************/
-				/* Chronometer mode selection is wrong */
-		 /***************************************/
-
-				DPRINTK("Chronometer mode selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */
-		} else {
-	      /******************************************/
-			/* The module is not a Chronometer module */
-	      /******************************************/
-
-			DPRINTK("The module is not a Chronometer module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-	data[0] = ul_RealTimingInterval;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_EnableChrono                          |
-|                                               (unsigned char_ b_BoardHandle,        |
-|                                                unsigned char_ b_ModulNbr,           |
-|                                                unsigned char_ b_CycleMode,          |
-|                                                unsigned char_ b_InterruptEnable)
-int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev,
-struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)						 |
-+----------------------------------------------------------------------------+
-| Task              : Enable the chronometer from selected module            |
-|                     (b_ModulNbr). You must calling the                     |
-|                     "i_APCI1710_InitChrono" function be for you call this  |
-|                     function.                                              |
-|                     If you enable the chronometer interrupt, the           |
-|                     chronometer generate a interrupt after the stop signal.|
-|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
-|                     Interrupt mask description chapter from this manual.   |
-|                     The b_CycleMode parameter determine if you will        |
-|                     measured a single or more cycle.
-
-|					  Disable the chronometer from selected module           |
-|                     (b_ModulNbr). If you disable the chronometer after a   |
-|                     start signal occur and you restart the chronometer     |
-|                     witch the " i_APCI1710_EnableChrono" function, if no   |
-|                     stop signal occur this start signal is ignored.
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr   CR_AREF(chanspec)  : Selected module number (0 to 3) |
-                                  data[0]  ENABle/Disable chrono
-|                     unsigned char_ b_CycleMode    : Selected the chronometer        |
-|                                  data[1]           acquisition mode                |
-|                     unsigned char_ b_InterruptEnable : Enable or disable the        |
-|                                   data[2]            chronometer interrupt.       |
-|                                               APCI1710_ENABLE:             |
-|                                               Enable the chronometer       |
-|                                               interrupt                    |
-|                                               APCI1710_DISABLE:            |
-|                                               Disable the chronometer      |
-|                                               interrupt                    |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-|                     -5: Chronometer acquisition mode cycle is wrong        |
-|                     -6: Interrupt parameter is wrong                       |
-|                     -7: Interrupt function not initialised.                |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"
-                      -8: data[0] wrong input    |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev,
-						   struct comedi_subdevice *s,
-						   struct comedi_insn *insn,
-						   unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action;
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_Action = (unsigned char) data[0];
-	b_CycleMode = (unsigned char) data[1];
-	b_InterruptEnable = (unsigned char) data[2];
-	i_ReturnValue = insn->n;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if chronometer */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-	      /***********************************/
-			/* Test if chronometer initialised */
-	      /***********************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_ChronoModuleInfo.b_ChronoInit == 1) {
-
-				switch (b_Action) {
-
-				case APCI1710_ENABLE:
-
-		 /*********************************/
-					/* Test the cycle mode parameter */
-		 /*********************************/
-
-					if ((b_CycleMode == APCI1710_SINGLE)
-						|| (b_CycleMode ==
-							APCI1710_CONTINUOUS)) {
-		    /***************************/
-						/* Test the interrupt flag */
-		    /***************************/
-
-						if ((b_InterruptEnable ==
-								APCI1710_ENABLE)
-							|| (b_InterruptEnable ==
-								APCI1710_DISABLE))
-						{
-
-			  /***************************/
-							/* Save the interrupt flag */
-			  /***************************/
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_ChronoModuleInfo.
-								b_InterruptMask
-								=
-								b_InterruptEnable;
-
-			  /***********************/
-							/* Save the cycle mode */
-			  /***********************/
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_ChronoModuleInfo.
-								b_CycleMode =
-								b_CycleMode;
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_ChronoModuleInfo.
-								dw_ConfigReg =
-								(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_ChronoModuleInfo.
-								dw_ConfigReg &
-								0x8F) | ((1 &
-									b_InterruptEnable)
-								<< 5) | ((1 &
-									b_CycleMode)
-								<< 6) | 0x10;
-
-			  /*****************************/
-							/* Test if interrupt enabled */
-			  /*****************************/
-
-							if (b_InterruptEnable ==
-								APCI1710_ENABLE)
-							{
-			     /****************************/
-								/* Clear the interrupt flag */
-			     /****************************/
-
-								outl(devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_ChronoModuleInfo.
-									dw_ConfigReg,
-									devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 32 +
-									(64 * b_ModulNbr));
-								devpriv->tsk_Current = current;	/*  Save the current process task structure */
-							}
-
-			  /***********************************/
-							/* Enable or disable the interrupt */
-							/* Enable the chronometer          */
-			  /***********************************/
-
-							outl(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_ChronoModuleInfo.
-								dw_ConfigReg,
-								devpriv->
-								s_BoardInfos.
-								ui_Address +
-								16 +
-								(64 * b_ModulNbr));
-
-			  /*************************/
-							/* Clear status register */
-			  /*************************/
-
-							outl(0, devpriv->
-								s_BoardInfos.
-								ui_Address +
-								36 +
-								(64 * b_ModulNbr));
-
-						}	/*  if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
-						else {
-		       /********************************/
-							/* Interrupt parameter is wrong */
-		       /********************************/
-
-							DPRINTK("Interrupt parameter is wrong\n");
-							i_ReturnValue = -6;
-						}	/*  if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
-					}	/*  if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
-					else {
-		    /***********************************************/
-						/* Chronometer acquisition mode cycle is wrong */
-		    /***********************************************/
-
-						DPRINTK("Chronometer acquisition mode cycle is wrong\n");
-						i_ReturnValue = -5;
-					}	/*  if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
-					break;
-
-				case APCI1710_DISABLE:
-
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_ChronoModuleInfo.
-						b_InterruptMask = 0;
-
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_ChronoModuleInfo.
-						dw_ConfigReg =
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_ChronoModuleInfo.
-						dw_ConfigReg & 0x2F;
-
-		 /***************************/
-					/* Disable the interrupt   */
-					/* Disable the chronometer */
-		 /***************************/
-
-					outl(devpriv->s_ModuleInfo[b_ModulNbr].
-						s_ChronoModuleInfo.dw_ConfigReg,
-						devpriv->s_BoardInfos.
-						ui_Address + 16 +
-						(64 * b_ModulNbr));
-
-		 /***************************/
-					/* Test if continuous mode */
-		 /***************************/
-
-					if (devpriv->s_ModuleInfo[b_ModulNbr].
-						s_ChronoModuleInfo.
-						b_CycleMode ==
-						APCI1710_CONTINUOUS) {
-		    /*************************/
-						/* Clear status register */
-		    /*************************/
-
-						outl(0, devpriv->s_BoardInfos.
-							ui_Address + 36 +
-							(64 * b_ModulNbr));
-					}
-					break;
-
-				default:
-					DPRINTK("Inputs wrong! Enable or Disable chrono\n");
-					i_ReturnValue = -8;
-				}	/*  switch ENABLE/DISABLE */
-			} else {
-		 /*******************************/
-				/* Chronometer not initialised */
-		 /*******************************/
-
-				DPRINTK("Chronometer not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a Chronometer module */
-	      /******************************************/
-
-			DPRINTK("The module is not a Chronometer module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetChronoProgressStatus               |
-|                               (unsigned char_    b_BoardHandle,                     |
-|                                unsigned char_    b_ModulNbr,                        |
-|                                unsigned char *_  pb_ChronoStatus)                    |
-+----------------------------------------------------------------------------+
-| Task              : Return the chronometer status (pb_ChronoStatus) from   |
-|                     selected chronometer module (b_ModulNbr).              |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr     : Selected module number (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pb_ChronoStatus : Return the chronometer      |
-|                                                status.                     |
-|                                                0 : Measurement not started.|
-|                                                    No start signal occur.  |
-|                                                1 : Measurement started.    |
-|                                                    A start signal occur.   |
-|                                                2 : Measurement stopped.    |
-|                                                    A stop signal occur.    |
-|                                                    The measurement is      |
-|                                                    terminate.              |
-|                                                3: A overflow occur. You    |
-|                                                   must change the base     |
-|                                                   timing witch the         |
-|                                                   function                 |
-|                                                   "i_APCI1710_InitChrono"  |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev,
-					      unsigned char b_ModulNbr,
-					      unsigned char *pb_ChronoStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if chronometer */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-	      /***********************************/
-			/* Test if chronometer initialised */
-	      /***********************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_ChronoModuleInfo.b_ChronoInit == 1) {
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 8 + (64 * b_ModulNbr));
-
-		 /********************/
-				/* Test if overflow */
-		 /********************/
-
-				if ((dw_Status & 8) == 8) {
-		    /******************/
-					/* Overflow occur */
-		    /******************/
-
-					*pb_ChronoStatus = 3;
-				}	/*  if ((dw_Status & 8) == 8) */
-				else {
-		    /*******************************/
-					/* Test if measurement stopped */
-		    /*******************************/
-
-					if ((dw_Status & 2) == 2) {
-		       /***********************/
-						/* A stop signal occur */
-		       /***********************/
-
-						*pb_ChronoStatus = 2;
-					}	/*  if ((dw_Status & 2) == 2) */
-					else {
-		       /*******************************/
-						/* Test if measurement started */
-		       /*******************************/
-
-						if ((dw_Status & 1) == 1) {
-			  /************************/
-							/* A start signal occur */
-			  /************************/
-
-							*pb_ChronoStatus = 1;
-						}	/*  if ((dw_Status & 1) == 1) */
-						else {
-			  /***************************/
-							/* Measurement not started */
-			  /***************************/
-
-							*pb_ChronoStatus = 0;
-						}	/*  if ((dw_Status & 1) == 1) */
-					}	/*  if ((dw_Status & 2) == 2) */
-				}	/*  if ((dw_Status & 8) == 8) */
-			} else {
-		 /*******************************/
-				/* Chronometer not initialised */
-		 /*******************************/
-				DPRINTK("Chronometer not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a Chronometer module */
-	      /******************************************/
-			DPRINTK("The module is not a Chronometer module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadChronoValue                       |
-|                               (unsigned char_     b_BoardHandle,                    |
-|                                unsigned char_     b_ModulNbr,                       |
-|                                unsigned int_    ui_TimeOut,                        |
-|                                unsigned char *_   pb_ChronoStatus,                   |
-|                                PULONG_ pul_ChronoValue)                    |
-+----------------------------------------------------------------------------+
-| Task              : Return the chronometer status (pb_ChronoStatus) and the|
-|                     timing value (pul_ChronoValue) after a stop signal     |
-|                     occur from selected chronometer module (b_ModulNbr).   |
-|                     This function are only avaible if you have disabled    |
-|                     the interrupt functionality. See function              |
-|                     "i_APCI1710_EnableChrono" and the Interrupt mask       |
-|                     description chapter.                                   |
-|                     You can test the chronometer status witch the          |
-|                     "i_APCI1710_GetChronoProgressStatus" function.         |
-|                                                                            |
-|                     The returned value from pul_ChronoValue parameter is   |
-|                     not real measured timing.                              |
-|                     You must used the "i_APCI1710_ConvertChronoValue"      |
-|                     function or make this operation for calculate the      |
-|                     timing:                                                |
-|                                                                            |
-|                     Timing = pul_ChronoValue * pul_RealTimingInterval.     |
-|                                                                            |
-|                     pul_RealTimingInterval is the returned parameter from  |
-|                     "i_APCI1710_InitChrono" function and the time unity is |
-|                     the b_TimingUnit from "i_APCI1710_InitChrono" function|
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr     : Selected module number (0 to 3) |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pb_ChronoStatus : Return the chronometer      |
-|                                                status.                     |
-|                                                0 : Measurement not started.|
-|                                                    No start signal occur.  |
-|                                                1 : Measurement started.    |
-|                                                    A start signal occur.   |
-|                                                2 : Measurement stopped.    |
-|                                                    A stop signal occur.    |
-|                                                    The measurement is      |
-|                                                    terminate.              |
-|                                                3: A overflow occur. You    |
-|                                                   must change the base     |
-|                                                   timing witch the         |
-|                                                   function                 |
-|                                                   "i_APCI1710_InitChrono"  |
-|                     unsigned int *  pul_ChronoValue  : Chronometer timing value.   |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-|                     -5: Timeout parameter is wrong (0 to 65535)            |
-|                     -6: Interrupt routine installed. You can not read      |
-|                         directly the chronometer measured timing.          |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadChronoValue(struct comedi_device *dev,
-				      unsigned char b_ModulNbr,
-				      unsigned int ui_TimeOut,
-				      unsigned char *pb_ChronoStatus,
-				      unsigned int *pul_ChronoValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned int dw_TimeOut = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if chronometer */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-	      /***********************************/
-			/* Test if chronometer initialised */
-	      /***********************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_ChronoModuleInfo.b_ChronoInit == 1) {
-		 /*****************************/
-				/* Test the timout parameter */
-		 /*****************************/
-
-				if (ui_TimeOut <= 65535UL) {
-
-					for (;;) {
-			  /*******************/
-						/* Read the status */
-			  /*******************/
-
-						dw_Status =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 8 +
-							(64 * b_ModulNbr));
-
-			  /********************/
-						/* Test if overflow */
-			  /********************/
-
-						if ((dw_Status & 8) == 8) {
-			     /******************/
-							/* Overflow occur */
-			     /******************/
-
-							*pb_ChronoStatus = 3;
-
-			     /***************************/
-							/* Test if continuous mode */
-			     /***************************/
-
-							if (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_ChronoModuleInfo.
-								b_CycleMode ==
-								APCI1710_CONTINUOUS)
-							{
-				/*************************/
-								/* Clear status register */
-				/*************************/
-
-								outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr));
-							}
-
-							break;
-						}	/*  if ((dw_Status & 8) == 8) */
-						else {
-			     /*******************************/
-							/* Test if measurement stopped */
-			     /*******************************/
-
-							if ((dw_Status & 2) ==
-								2) {
-				/***********************/
-								/* A stop signal occur */
-				/***********************/
-
-								*pb_ChronoStatus
-									= 2;
-
-				/***************************/
-								/* Test if continnous mode */
-				/***************************/
-
-								if (devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_ChronoModuleInfo.
-									b_CycleMode
-									==
-									APCI1710_CONTINUOUS)
-								{
-				   /*************************/
-									/* Clear status register */
-				   /*************************/
-
-									outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr));
-								}
-								break;
-							}	/*  if ((dw_Status & 2) == 2) */
-							else {
-				/*******************************/
-								/* Test if measurement started */
-				/*******************************/
-
-								if ((dw_Status & 1) == 1) {
-				   /************************/
-									/* A start signal occur */
-				   /************************/
-
-									*pb_ChronoStatus
-										=
-										1;
-								}	/*  if ((dw_Status & 1) == 1) */
-								else {
-				   /***************************/
-									/* Measurement not started */
-				   /***************************/
-
-									*pb_ChronoStatus
-										=
-										0;
-								}	/*  if ((dw_Status & 1) == 1) */
-							}	/*  if ((dw_Status & 2) == 2) */
-						}	/*  if ((dw_Status & 8) == 8) */
-
-						if (dw_TimeOut == ui_TimeOut) {
-			     /*****************/
-							/* Timeout occur */
-			     /*****************/
-
-							break;
-						} else {
-			     /*************************/
-							/* Increment the timeout */
-			     /*************************/
-
-							dw_TimeOut =
-								dw_TimeOut + 1;
-							mdelay(1000);
-
-						}
-					}	/*  for (;;) */
-
-		       /*****************************/
-					/* Test if stop signal occur */
-		       /*****************************/
-
-					if (*pb_ChronoStatus == 2) {
-			  /**********************************/
-						/* Read the measured timing value */
-			  /**********************************/
-
-						*pul_ChronoValue =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 4 +
-							(64 * b_ModulNbr));
-
-						if (*pul_ChronoValue != 0) {
-							*pul_ChronoValue =
-								*pul_ChronoValue
-								- 1;
-						}
-					} else {
-			  /*************************/
-						/* Test if timeout occur */
-			  /*************************/
-
-						if ((*pb_ChronoStatus != 3)
-							&& (dw_TimeOut ==
-								ui_TimeOut)
-							&& (ui_TimeOut != 0)) {
-			     /*****************/
-							/* Timeout occur */
-			     /*****************/
-
-							*pb_ChronoStatus = 4;
-						}
-					}
-
-				} else {
-		    /******************************/
-					/* Timeout parameter is wrong */
-		    /******************************/
-					DPRINTK("Timeout parameter is wrong\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /*******************************/
-				/* Chronometer not initialised */
-		 /*******************************/
-				DPRINTK("Chronometer not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a Chronometer module */
-	      /******************************************/
-			DPRINTK("The module is not a Chronometer module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ConvertChronoValue                    |
-|                               (unsigned char_     b_BoardHandle,                    |
-|                                unsigned char_     b_ModulNbr,                       |
-|                                ULONG_   ul_ChronoValue,                    |
-|                                PULONG_ pul_Hour,                           |
-|                                unsigned char *_   pb_Minute,                         |
-|                                unsigned char *_   pb_Second,                         |
-|                                unsigned int *_  pui_MilliSecond,                    |
-|                                unsigned int *_  pui_MicroSecond,                    |
-|                                unsigned int *_  pui_NanoSecond)                     |
-+----------------------------------------------------------------------------+
-| Task              : Convert the chronometer measured timing                |
-|                     (ul_ChronoValue) in to h, mn, s, ms, µs, ns.           |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle : Handle of board APCI-1710      |
-|                     unsigned char_   b_ModulNbr    : Selected module number (0 to 3)|
-|                     ULONG_ ul_ChronoValue : Measured chronometer timing    |
-|                                             value.                         |
-|                                             See"i_APCI1710_ReadChronoValue"|
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_   pul_Hour        : Chronometer timing hour    |
-|                     unsigned char *_     pb_Minute      : Chronometer timing minute  |
-|                     unsigned char *_     pb_Second      : Chronometer timing second  |
-|                     unsigned int *_    pui_MilliSecond  : Chronometer timing mini   |
-|                                                 second                     |
-|                     unsigned int *_    pui_MicroSecond : Chronometer timing micro   |
-|                                                 second                     |
-|                     unsigned int *_    pui_NanoSecond  : Chronometer timing nano    |
-|                                                 second                     |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ConvertChronoValue(struct comedi_device *dev,
-					 unsigned char b_ModulNbr,
-					 unsigned int ul_ChronoValue,
-					 unsigned int *pul_Hour,
-					 unsigned char *pb_Minute,
-					 unsigned char *pb_Second,
-					 unsigned int *pui_MilliSecond,
-					 unsigned int *pui_MicroSecond,
-					 unsigned int *pui_NanoSecond)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	double d_Hour;
-	double d_Minute;
-	double d_Second;
-	double d_MilliSecond;
-	double d_MicroSecond;
-	double d_NanoSecond;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if chronometer */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-	      /***********************************/
-			/* Test if chronometer initialised */
-	      /***********************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_ChronoModuleInfo.b_ChronoInit == 1) {
-				fpu_begin();
-
-				d_Hour = (double)ul_ChronoValue *(double)
-					devpriv->s_ModuleInfo[b_ModulNbr].
-					s_ChronoModuleInfo.d_TimingInterval;
-
-				switch (devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_ChronoModuleInfo.b_TimingUnit) {
-				case 0:
-					d_Hour = d_Hour / (double)1000.0;
-
-				case 1:
-					d_Hour = d_Hour / (double)1000.0;
-
-				case 2:
-					d_Hour = d_Hour / (double)1000.0;
-
-				case 3:
-					d_Hour = d_Hour / (double)60.0;
-
-				case 4:
-			    /**********************/
-					/* Calculate the hour */
-			    /**********************/
-
-					d_Hour = d_Hour / (double)60.0;
-					*pul_Hour = (unsigned int) d_Hour;
-
-			    /************************/
-					/* Calculate the minute */
-			    /************************/
-
-					d_Minute = d_Hour - *pul_Hour;
-					d_Minute = d_Minute * 60;
-					*pb_Minute = (unsigned char) d_Minute;
-
-			    /************************/
-					/* Calculate the second */
-			    /************************/
-
-					d_Second = d_Minute - *pb_Minute;
-					d_Second = d_Second * 60;
-					*pb_Second = (unsigned char) d_Second;
-
-			    /*****************************/
-					/* Calculate the mini second */
-			    /*****************************/
-
-					d_MilliSecond = d_Second - *pb_Second;
-					d_MilliSecond = d_MilliSecond * 1000;
-					*pui_MilliSecond = (unsigned int) d_MilliSecond;
-
-			    /******************************/
-					/* Calculate the micro second */
-			    /******************************/
-
-					d_MicroSecond =
-						d_MilliSecond -
-						*pui_MilliSecond;
-					d_MicroSecond = d_MicroSecond * 1000;
-					*pui_MicroSecond = (unsigned int) d_MicroSecond;
-
-			    /******************************/
-					/* Calculate the micro second */
-			    /******************************/
-
-					d_NanoSecond =
-						d_MicroSecond -
-						*pui_MicroSecond;
-					d_NanoSecond = d_NanoSecond * 1000;
-					*pui_NanoSecond = (unsigned int) d_NanoSecond;
-					break;
-				}
-
-				fpu_end();
-			} else {
-		 /*******************************/
-				/* Chronometer not initialised */
-		 /*******************************/
-				DPRINTK("Chronometer not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a Chronometer module */
-	      /******************************************/
-			DPRINTK("The module is not a Chronometer module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     :INT	i_APCI1710_InsnReadChrono(struct comedi_device *dev,struct comedi_subdevice *s,
-struct comedi_insn *insn,unsigned int *data)                   |
-+----------------------------------------------------------------------------+
-| Task              : Read  functions for Timer                                     |
-+----------------------------------------------------------------------------+
-| Input Parameters  :
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnReadChrono(struct comedi_device *dev,
-				     struct comedi_subdevice *s,
-				     struct comedi_insn *insn,
-				     unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned char b_ReadType;
-	int i_ReturnValue = insn->n;
-
-	b_ReadType = CR_CHAN(insn->chanspec);
-
-	switch (b_ReadType) {
-	case APCI1710_CHRONO_PROGRESS_STATUS:
-		i_ReturnValue = i_APCI1710_GetChronoProgressStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_CHRONO_READVALUE:
-		i_ReturnValue = i_APCI1710_ReadChronoValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned int) insn->unused[0],
-			(unsigned char *) &data[0], (unsigned int *) &data[1]);
-		break;
-
-	case APCI1710_CHRONO_CONVERTVALUE:
-		i_ReturnValue = i_APCI1710_ConvertChronoValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned int) insn->unused[0],
-			(unsigned int *) &data[0],
-			(unsigned char *) &data[1],
-			(unsigned char *) &data[2],
-			(unsigned int *) &data[3],
-			(unsigned int *) &data[4], (unsigned int *) &data[5]);
-		break;
-
-	case APCI1710_CHRONO_READINTERRUPT:
-		printk("In Chrono Read Interrupt\n");
-
-		data[0] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].b_OldModuleMask;
-		data[1] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].ul_OldInterruptMask;
-		data[2] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
-			     /**************************/
-		/* Increment the read FIFO */
-			     /***************************/
-
-		devpriv->
-			s_InterruptParameters.
-			ui_Read = (devpriv->
-			s_InterruptParameters.
-			ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-		break;
-
-	default:
-		printk("ReadType Parameter wrong\n");
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s,
-	struct comedi_insn *insn,unsigned int *data)                    |
-+----------------------------------------------------------------------------+
-| Task              : Sets the output witch has been passed with the         |
-|                     parameter b_Channel. Setting an output means setting an|
-|                     output high.                                           |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle   : Handle of board APCI-1710      |
-|                     unsigned char_ b_ModulNbr      : Selected module number (0 to 3)|
-|                     unsigned char_ b_OutputChannel : Selection from digital output  |
-|                           CR_CHAN()                  channel (0 to 2)               |
-|                                              0 : Channel H                 |
-|                                              1 : Channel A                 |
-|                                              2 : Channel B                 |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: The selected digital output is wrong               |
-|                     -5: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_SetChronoChlOff                       |
-|                               (unsigned char_  b_BoardHandle,                       |
-|                                unsigned char_  b_ModulNbr,                          |
-|                                unsigned char_  b_OutputChannel)                     |
-+----------------------------------------------------------------------------+
-| Task              : Resets the output witch has been passed with the       |
-|                     parameter b_Channel. Resetting an output means setting |
-|                     an output low.                                         |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle   : Handle of board APCI-1710
-                        data[0] : Chl ON, Chl OFF , Chl Read , Port Read
-
-|                     unsigned char_ b_ModulNbr  CR_AREF    : Selected module number (0 to 3)|
-|                     unsigned char_ b_OutputChannel CR_CHAN : Selection from digital output  |
-|                                             channel (0 to 2)               |
-|                                              0 : Channel H                 |
-|                                              1 : Channel A                 |
-|                                              2 : Channel B                 |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: The selected digital output is wrong               |
-|                     -5: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadChronoChlValue                    |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char_   b_InputChannel,                     |
-|                                unsigned char *_ pb_ChannelStatus)                    |
-+----------------------------------------------------------------------------+
-| Task              : Return the status from selected digital input          |
-|                     (b_InputChannel) from selected chronometer             |
-|                     module (b_ModulNbr).                                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle   : Handle of board APCI-1710      |
-|                     unsigned char_ b_ModulNbr      : Selected module number (0 to 3)|
-|                     unsigned char_ b_InputChannel  : Selection from digital input   |
-|                                             channel (0 to 2)               |
-|                                   CR_CHAN()             0 : Channel E               |
-|                                                1 : Channel F               |
-|                                                2 : Channel G               |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel status.|
-|                                data[0]                0 : Channel is not active   |
-|                                                1 : Channel is active       |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: The selected digital input is wrong                |
-|                     -5: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadChronoPortValue                   |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char *_ pb_PortValue)                        |
-+----------------------------------------------------------------------------+
-| Task              : Return the status from digital inputs port from        |
-|                     selected  (b_ModulNbr) chronometer module.             |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle   : Handle of board APCI-1710      |
-|                     unsigned char_ b_ModulNbr      : Selected module number (0 to 3)|
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_PortValue   : Digital inputs port status.
-|                     data[0]
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a Chronometer module             |
-|                     -4: Chronometer not initialised see function           |
-|                         "i_APCI1710_InitChrono"                            |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,
-					      struct comedi_subdevice *s,
-					      struct comedi_insn *insn,
-					      unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType;
-	unsigned int dw_Status;
-	unsigned char *pb_ChannelStatus;
-	unsigned char *pb_PortValue;
-
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	i_ReturnValue = insn->n;
-	b_IOType = (unsigned char) data[0];
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if chronometer */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-	      /***********************************/
-			/* Test if chronometer initialised */
-	      /***********************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_ChronoModuleInfo.b_ChronoInit == 1) {
-		 /***********************************/
-				/* Test the digital output channel */
-		 /***********************************/
-				switch (b_IOType) {
-
-				case APCI1710_CHRONO_SET_CHANNELOFF:
-
-					b_OutputChannel =
-						(unsigned char) CR_CHAN(insn->chanspec);
-					if (b_OutputChannel <= 2) {
-
-						outl(0, devpriv->s_BoardInfos.
-							ui_Address + 20 +
-							(b_OutputChannel * 4) +
-							(64 * b_ModulNbr));
-					}	/*  if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
-					else {
-		    /****************************************/
-						/* The selected digital output is wrong */
-		    /****************************************/
-
-						DPRINTK("The selected digital output is wrong\n");
-						i_ReturnValue = -4;
-
-					}	/*  if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
-
-					break;
-
-				case APCI1710_CHRONO_SET_CHANNELON:
-
-					b_OutputChannel =
-						(unsigned char) CR_CHAN(insn->chanspec);
-					if (b_OutputChannel <= 2) {
-
-						outl(1, devpriv->s_BoardInfos.
-							ui_Address + 20 +
-							(b_OutputChannel * 4) +
-							(64 * b_ModulNbr));
-					}	/*  if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
-					else {
-		    /****************************************/
-						/* The selected digital output is wrong */
-		    /****************************************/
-
-						DPRINTK("The selected digital output is wrong\n");
-						i_ReturnValue = -4;
-
-					}	/*  if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */
-
-					break;
-
-				case APCI1710_CHRONO_READ_CHANNEL:
-		 /**********************************/
-					/* Test the digital input channel */
-		 /**********************************/
-					pb_ChannelStatus = (unsigned char *) &data[0];
-					b_InputChannel =
-						(unsigned char) CR_CHAN(insn->chanspec);
-
-					if (b_InputChannel <= 2) {
-
-						dw_Status =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 12 +
-							(64 * b_ModulNbr));
-
-						*pb_ChannelStatus =
-							(unsigned char) (((dw_Status >>
-									b_InputChannel)
-								& 1) ^ 1);
-					}	/*  if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */
-					else {
-		    /***************************************/
-						/* The selected digital input is wrong */
-		    /***************************************/
-
-						DPRINTK("The selected digital input is wrong\n");
-						i_ReturnValue = -4;
-					}	/*  if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */
-
-					break;
-
-				case APCI1710_CHRONO_READ_PORT:
-
-					pb_PortValue = (unsigned char *) &data[0];
-
-					dw_Status =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 12 +
-						(64 * b_ModulNbr));
-
-					*pb_PortValue =
-						(unsigned char) ((dw_Status & 0x7) ^ 7);
-					break;
-				}
-			} else {
-		 /*******************************/
-				/* Chronometer not initialised */
-		 /*******************************/
-
-				DPRINTK("Chronometer not initialised\n");
-				i_ReturnValue = -5;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a Chronometer module */
-	      /******************************************/
-
-			DPRINTK("The module is not a Chronometer module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
deleted file mode 100644
index 27de18e..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c
+++ /dev/null
@@ -1,1037 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : DIG_IO.C        | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 digital I/O module                          |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  | 16/06/98 | S. Weber  | Digital input / output implementation          |
-  |----------|-----------|------------------------------------------------|
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-  |          |           |                                                |
-  |          |           |                                                |
-  +-----------------------------------------------------------------------+
-*/
-
-/* Digital Output ON or OFF */
-#define APCI1710_ON			1
-#define APCI1710_OFF			0
-
-/* Digital I/O */
-#define APCI1710_INPUT			0
-#define APCI1710_OUTPUT			1
-
-#define APCI1710_DIGIO_MEMORYONOFF	0x10
-#define APCI1710_DIGIO_INIT		0x11
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, |
-|						struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)|
-+----------------------------------------------------------------------------+
-| Task              : Configure the digital I/O operating mode from selected |
-|                     module  (b_ModulNbr). You must calling this function be|
-|                     for you call any other function witch access of digital|
-|                     I/O.                                                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  :													     |
-|                  unsigned char_ b_ModulNbr      data[0]: Module number to               |
-|                                             configure (0 to 3)             |
-|                     unsigned char_ b_ChannelAMode data[1]  : Channel A mode selection       |
-|                                             0 : Channel used for digital   |
-|                                                 input                      |
-|                                             1 : Channel used for digital   |
-|                                                 output                     |
-|                     unsigned char_ b_ChannelBMode data[2] : Channel B mode selection       |
-|                                             0 : Channel used for digital   |
-|                                                 input                      |
-|                                             1 : Channel used for digital   |
-|                                                 output					 |
-						data[0]	  memory on/off
-Activates and deactivates the digital output memory.
-						After having      |
-|                 called up this function with memory on,the output you have previously|
-|                     activated with the function are not reset
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a digital I/O module              |
-|                    -4: Bi-directional channel A configuration error        |
-|                    -5: Bi-directional channel B configuration error        |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev,
-					  struct comedi_subdevice *s,
-					  struct comedi_insn *insn,
-					  unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned char b_ModulNbr, b_ChannelAMode, b_ChannelBMode;
-	unsigned char b_MemoryOnOff, b_ConfigType;
-	int i_ReturnValue = 0;
-	unsigned int dw_WriteConfig = 0;
-
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_ConfigType = (unsigned char) data[0];	/*  Memory or  Init */
-	b_ChannelAMode = (unsigned char) data[1];
-	b_ChannelBMode = (unsigned char) data[2];
-	b_MemoryOnOff = (unsigned char) data[1];	/*  if memory operation */
-	i_ReturnValue = insn->n;
-
-		/**************************/
-	/* Test the module number */
-		/**************************/
-
-	if (b_ModulNbr >= 4) {
-		DPRINTK("Module Number invalid\n");
-		i_ReturnValue = -2;
-		return i_ReturnValue;
-	}
-	switch (b_ConfigType) {
-	case APCI1710_DIGIO_MEMORYONOFF:
-
-		if (b_MemoryOnOff)	/*  If Memory ON */
-		{
-		 /****************************/
-			/* Set the output memory on */
-		 /****************************/
-
-			devpriv->s_ModuleInfo[b_ModulNbr].
-				s_DigitalIOInfo.b_OutputMemoryEnabled = 1;
-
-		 /***************************/
-			/* Clear the output memory */
-		 /***************************/
-			devpriv->s_ModuleInfo[b_ModulNbr].
-				s_DigitalIOInfo.dw_OutputMemory = 0;
-		} else		/*  If memory off */
-		{
-		 /*****************************/
-			/* Set the output memory off */
-		 /*****************************/
-
-			devpriv->s_ModuleInfo[b_ModulNbr].
-				s_DigitalIOInfo.b_OutputMemoryEnabled = 0;
-		}
-		break;
-
-	case APCI1710_DIGIO_INIT:
-
-	/*******************************/
-		/* Test if digital I/O counter */
-	/*******************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
-
-	/***************************************************/
-			/* Test the bi-directional channel A configuration */
-	/***************************************************/
-
-			if ((b_ChannelAMode == 0) || (b_ChannelAMode == 1)) {
-	/***************************************************/
-				/* Test the bi-directional channel B configuration */
-	/***************************************************/
-
-				if ((b_ChannelBMode == 0)
-					|| (b_ChannelBMode == 1)) {
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_DigitalIOInfo.b_DigitalInit =
-						1;
-
-	/********************************/
-					/* Save channel A configuration */
-	/********************************/
-
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_DigitalIOInfo.
-						b_ChannelAMode = b_ChannelAMode;
-
-	/********************************/
-					/* Save channel B configuration */
-	/********************************/
-
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_DigitalIOInfo.
-						b_ChannelBMode = b_ChannelBMode;
-
-	/*****************************************/
-					/* Set the channel A and B configuration */
-	/*****************************************/
-
-					dw_WriteConfig =
-						(unsigned int) (b_ChannelAMode |
-						(b_ChannelBMode * 2));
-
-	/***************************/
-					/* Write the configuration */
-	/***************************/
-
-					outl(dw_WriteConfig,
-						devpriv->s_BoardInfos.
-						ui_Address + 4 +
-						(64 * b_ModulNbr));
-
-				} else {
-	/************************************************/
-					/* Bi-directional channel B configuration error */
-	/************************************************/
-					DPRINTK("Bi-directional channel B configuration error\n");
-					i_ReturnValue = -5;
-				}
-
-			} else {
-	/************************************************/
-				/* Bi-directional channel A configuration error */
-	/************************************************/
-				DPRINTK("Bi-directional channel A configuration error\n");
-				i_ReturnValue = -4;
-
-			}
-
-		} else {
-	/******************************************/
-			/* The module is not a digital I/O module */
-	/******************************************/
-			DPRINTK("The module is not a digital I/O module\n");
-			i_ReturnValue = -3;
-		}
-	}			/*  end of Switch */
-	printk("Return Value %d\n", i_ReturnValue);
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-|                            INPUT FUNCTIONS                                 |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-
-|INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,comedi_subdevice
-*s,	struct comedi_insn *insn,unsigned int *data)
-
-+----------------------------------------------------------------------------+
-| Task              : Read the status from selected digital I/O digital input|
-|                     (b_InputChannel)                                       |
-+----------------------------------------------------------------------------|
-
-
-|
-|  unsigned char_ b_ModulNbr  CR_AREF(chanspec)          : Selected module number   |
-|                                                   (0 to 3)                 |
-|  unsigned char_ b_InputChannel CR_CHAN(chanspec)        : Selection from digital   |
-|                                                   input ( 0 to 6)          |
-|                                                      0 : Channel C         |
-|                                                      1 : Channel D         |
-|                                                      2 : Channel E         |
-|                                                      3 : Channel F         |
-|                                                      4 : Channel G         |
-|                                                      5 : Channel A         |
-|                                                      6 : Channel B
-
-
-	|
-+----------------------------------------------------------------------------+
-| Output Parameters :					 data[0]   : Digital input channel    |
-|                                                   status                   |
-|                                                   0 : Channle is not active|
-|                                                   1 : Channle is active    |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a digital I/O module              |
-|                    -4: The selected digital I/O digital input is wrong     |
-|                    -5: Digital I/O not initialised                         |
-|                    -6: The digital channel A is used for output            |
-|                    -7: The digital channel B is used for output            |
-+----------------------------------------------------------------------------+
-*/
-
-/* _INT_   i_APCI1710_ReadDigitalIOChlValue      (unsigned char_    b_BoardHandle, */
-/*
-* unsigned char_ b_ModulNbr, unsigned char_ b_InputChannel,
-* unsigned char *_ pb_ChannelStatus)
-*/
-static int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,
-						struct comedi_subdevice *s,
-						struct comedi_insn *insn,
-						unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg;
-	unsigned char b_ModulNbr, b_InputChannel;
-	unsigned char *pb_ChannelStatus;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec);
-	data[0] = 0;
-	pb_ChannelStatus = (unsigned char *) &data[0];
-	i_ReturnValue = insn->n;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if digital I/O counter */
-	   /*******************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
-	      /******************************************/
-			/* Test the digital imnput channel number */
-	      /******************************************/
-
-			if (b_InputChannel <= 6) {
-		 /**********************************************/
-				/* Test if the digital I/O module initialised */
-		 /**********************************************/
-
-				if (devpriv->s_ModuleInfo[b_ModulNbr].
-					s_DigitalIOInfo.b_DigitalInit == 1) {
-		    /**********************************/
-					/* Test if channel A or channel B */
-		    /**********************************/
-
-					if (b_InputChannel > 4) {
-		       /*********************/
-						/* Test if channel A */
-		       /*********************/
-
-						if (b_InputChannel == 5) {
-			  /***************************/
-							/* Test the channel A mode */
-			  /***************************/
-
-							if (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								b_ChannelAMode
-								!= 0) {
-			     /********************************************/
-								/* The digital channel A is used for output */
-			     /********************************************/
-
-								i_ReturnValue =
-									-6;
-							}
-						}	/*  if (b_InputChannel == 5) */
-						else {
-			  /***************************/
-							/* Test the channel B mode */
-			  /***************************/
-
-							if (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								b_ChannelBMode
-								!= 0) {
-			     /********************************************/
-								/* The digital channel B is used for output */
-			     /********************************************/
-
-								i_ReturnValue =
-									-7;
-							}
-						}	/*  if (b_InputChannel == 5) */
-					}	/*  if (b_InputChannel > 4) */
-
-		    /***********************/
-					/* Test if error occur */
-		    /***********************/
-
-					if (i_ReturnValue >= 0) {
-		       /**************************/
-						/* Read all digital input */
-		       /**************************/
-
-/*
-* INPDW (ps_APCI1710Variable-> s_Board [b_BoardHandle].
-* s_BoardInfos. ui_Address + (64 * b_ModulNbr), &dw_StatusReg);
-*/
-
-						dw_StatusReg =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address +
-							(64 * b_ModulNbr));
-
-						*pb_ChannelStatus =
-							(unsigned char) ((dw_StatusReg ^
-								0x1C) >>
-							b_InputChannel) & 1;
-
-					}	/*  if (i_ReturnValue == 0) */
-				} else {
-		    /*******************************/
-					/* Digital I/O not initialised */
-		    /*******************************/
-					DPRINTK("Digital I/O not initialised\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /********************************/
-				/* Selected digital input error */
-		 /********************************/
-				DPRINTK("Selected digital input error\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a digital I/O module */
-	      /******************************************/
-			DPRINTK("The module is not a digital I/O module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-|                            OUTPUT FUNCTIONS                                |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : int i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device
-|*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)
-
-+----------------------------------------------------------------------------+
-| Task              : Sets or resets the output witch has been passed with the         |
-|                     parameter b_Channel. Setting an output means setting   |
-|                     an ouput high.                                         |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle   : Handle of board APCI-1710      |
-|                     unsigned char_ b_ModulNbr (aref )    : Selected module number (0 to 3)|
-|                     unsigned char_ b_OutputChannel (CR_CHAN) : Selection from digital output  |
-|                                             channel (0 to 2)               |
-|                                                0 : Channel H               |
-|                                                1 : Channel A               |
-|                                                2 : Channel B               |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a digital I/O module              |
-|                    -4: The selected digital output is wrong                |
-|                    -5: digital I/O not initialised see function            |
-|                        " i_APCI1710_InitDigitalIO"                         |
-|                    -6: The digital channel A is used for input             |
-|                    -7: The digital channel B is used for input
-					 -8: Digital Output Memory OFF.                          |
-|                        Use previously the function                         |
-|                        "i_APCI1710_SetDigitalIOMemoryOn".            |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-* _INT_ i_APCI1710_SetDigitalIOChlOn (unsigned char_ b_BoardHandle,
-* unsigned char_ b_ModulNbr, unsigned char_ b_OutputChannel)
-*/
-static int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev,
-						 struct comedi_subdevice *s,
-						 struct comedi_insn *insn,
-						 unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_WriteValue = 0;
-	unsigned char b_ModulNbr, b_OutputChannel;
-	i_ReturnValue = insn->n;
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_OutputChannel = CR_CHAN(insn->chanspec);
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if digital I/O counter */
-	   /*******************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
-	      /**********************************************/
-			/* Test if the digital I/O module initialised */
-	      /**********************************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_DigitalIOInfo.b_DigitalInit == 1) {
-		 /******************************************/
-				/* Test the digital output channel number */
-		 /******************************************/
-
-				switch (b_OutputChannel) {
-		    /*************/
-					/* Channel H */
-		    /*************/
-
-				case 0:
-					break;
-
-		    /*************/
-					/* Channel A */
-		    /*************/
-
-				case 1:
-					if (devpriv->s_ModuleInfo[b_ModulNbr].
-						s_DigitalIOInfo.
-						b_ChannelAMode != 1) {
-			    /*******************************************/
-						/* The digital channel A is used for input */
-			    /*******************************************/
-
-						i_ReturnValue = -6;
-					}
-					break;
-
-		    /*************/
-					/* Channel B */
-		    /*************/
-
-				case 2:
-					if (devpriv->s_ModuleInfo[b_ModulNbr].
-						s_DigitalIOInfo.
-						b_ChannelBMode != 1) {
-			    /*******************************************/
-						/* The digital channel B is used for input */
-			    /*******************************************/
-
-						i_ReturnValue = -7;
-					}
-					break;
-
-				default:
-			 /****************************************/
-					/* The selected digital output is wrong */
-			 /****************************************/
-
-					i_ReturnValue = -4;
-					break;
-				}
-
-		 /***********************/
-				/* Test if error occur */
-		 /***********************/
-
-				if (i_ReturnValue >= 0) {
-
-			/*********************************/
-					/* Test if set channel ON        */
-		    /*********************************/
-					if (data[0]) {
-		    /*********************************/
-						/* Test if output memory enabled */
-		    /*********************************/
-
-						if (devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_DigitalIOInfo.
-							b_OutputMemoryEnabled ==
-							1) {
-							dw_WriteValue =
-								devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								dw_OutputMemory
-								| (1 <<
-								b_OutputChannel);
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								dw_OutputMemory
-								= dw_WriteValue;
-						} else {
-							dw_WriteValue =
-								1 <<
-								b_OutputChannel;
-						}
-					}	/*  set channel off */
-					else {
-						if (devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_DigitalIOInfo.
-							b_OutputMemoryEnabled ==
-							1) {
-							dw_WriteValue =
-								devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								dw_OutputMemory
-								& (0xFFFFFFFFUL
-								-
-								(1 << b_OutputChannel));
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								dw_OutputMemory
-								= dw_WriteValue;
-						} else {
-							/*****************************/
-							/* Digital Output Memory OFF */
-							/*****************************/
-							/*  +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn" */
-							i_ReturnValue = -8;
-						}
-
-					}
-					/*******************/
-					/* Write the value */
-					/*******************/
-
-					/* OUTPDW (ps_APCI1710Variable->
-					 * s_Board [b_BoardHandle].
-					 * s_BoardInfos. ui_Address + (64 * b_ModulNbr),
-					 * dw_WriteValue);
-					 */
-*/
-					outl(dw_WriteValue,
-						devpriv->s_BoardInfos.
-						ui_Address + (64 * b_ModulNbr));
-				}
-			} else {
-		 /*******************************/
-				/* Digital I/O not initialised */
-		 /*******************************/
-
-				i_ReturnValue = -5;
-			}
-		} else {
-	      /******************************************/
-			/* The module is not a digital I/O module */
-	      /******************************************/
-
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-
-|INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,comedi_subdevice
-	*s,	struct comedi_insn *insn,unsigned int *data)
-+----------------------------------------------------------------------------+
-| Task              : write:
-					  Sets or resets one or several outputs from port.                 |
-|                     Setting an output means setting an output high.        |
-|                     If you have switched OFF the digital output memory     |
-|                     (OFF), all the other output are set to "0".
-
-|                      read:
-					  Read the status from digital input port                |
-|                     from selected digital I/O module (b_ModulNbr)
-+----------------------------------------------------------------------------+
-| Input Parameters  :
-	unsigned char_ b_BoardHandle   : Handle of board APCI-1710      |
-|   unsigned char_ b_ModulNbr  CR_AREF(aref)    : Selected module number (0 to 3)|
-|   unsigned char_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 )
-|                       data[0]           read or write port
-|                       data[1]            if write then indicate ON or OFF
-
-|                       if read : data[1] will return port status.
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :
-
-|                INPUT :
-
-					  0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a digital I/O module              |
-|                    -4: Digital I/O not initialised
-
-				OUTPUT:	  0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a digital I/O module              |
-|                    -4: Output value wrong                                  |
-|                    -5: digital I/O not initialised see function            |
-|                        " i_APCI1710_InitDigitalIO"                         |
-|                    -6: The digital channel A is used for input             |
-|                    -7: The digital channel B is used for input
-					-8: Digital Output Memory OFF.                          |
-|                        Use previously the function                         |
-|                        "i_APCI1710_SetDigitalIOMemoryOn".               |
-+----------------------------------------------------------------------------+
-*/
-
-/*
- * _INT_ i_APCI1710_SetDigitalIOPortOn (unsigned char_
- * b_BoardHandle, unsigned char_ b_ModulNbr, unsigned char_
- * b_PortValue)
-*/
-static int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,
-						 struct comedi_subdevice *s,
-						 struct comedi_insn *insn,
-						 unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_WriteValue = 0;
-	unsigned int dw_StatusReg;
-	unsigned char b_ModulNbr, b_PortValue;
-	unsigned char b_PortOperation, b_PortOnOFF;
-
-	unsigned char *pb_PortValue;
-
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_PortOperation = (unsigned char) data[0];	/*  Input or output */
-	b_PortOnOFF = (unsigned char) data[1];	/*  if output then On or Off */
-	b_PortValue = (unsigned char) data[2];	/*  if out put then Value */
-	i_ReturnValue = insn->n;
-	pb_PortValue = (unsigned char *) &data[0];
-/* if input then read value */
-
-	switch (b_PortOperation) {
-	case APCI1710_INPUT:
-		/**************************/
-		/* Test the module number */
-		/**************************/
-
-		if (b_ModulNbr < 4) {
-			/*******************************/
-			/* Test if digital I/O counter */
-			/*******************************/
-
-			if ((devpriv->s_BoardInfos.
-					dw_MolduleConfiguration[b_ModulNbr] &
-					0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
-				/**********************************************/
-				/* Test if the digital I/O module initialised */
-				/**********************************************/
-
-				if (devpriv->s_ModuleInfo[b_ModulNbr].
-					s_DigitalIOInfo.b_DigitalInit == 1) {
-					/**************************/
-					/* Read all digital input */
-					/**************************/
-
-					/* INPDW (ps_APCI1710Variable->
-					 * s_Board [b_BoardHandle].
-					 * s_BoardInfos.
-					 * ui_Address + (64 * b_ModulNbr),
-					 * &dw_StatusReg);
-					 */
-
-					dw_StatusReg =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + (64 * b_ModulNbr));
-					*pb_PortValue =
-						(unsigned char) (dw_StatusReg ^ 0x1C);
-
-				} else {
-					/*******************************/
-					/* Digital I/O not initialised */
-					/*******************************/
-
-					i_ReturnValue = -4;
-				}
-			} else {
-				/******************************************/
-				/* The module is not a digital I/O module */
-				/******************************************/
-
-				i_ReturnValue = -3;
-			}
-		} else {
-	   /***********************/
-			/* Module number error */
-	   /***********************/
-
-			i_ReturnValue = -2;
-		}
-
-		break;
-
-	case APCI1710_OUTPUT:
-	/**************************/
-		/* Test the module number */
-	/**************************/
-
-		if (b_ModulNbr < 4) {
-	   /*******************************/
-			/* Test if digital I/O counter */
-	   /*******************************/
-
-			if ((devpriv->s_BoardInfos.
-					dw_MolduleConfiguration[b_ModulNbr] &
-					0xFFFF0000UL) == APCI1710_DIGITAL_IO) {
-	      /**********************************************/
-				/* Test if the digital I/O module initialised */
-	      /**********************************************/
-
-				if (devpriv->s_ModuleInfo[b_ModulNbr].
-					s_DigitalIOInfo.b_DigitalInit == 1) {
-		 /***********************/
-					/* Test the port value */
-		 /***********************/
-
-					if (b_PortValue <= 7) {
-		    /***********************************/
-						/* Test the digital output channel */
-		    /***********************************/
-
-		    /**************************/
-						/* Test if channel A used */
-		    /**************************/
-
-						if ((b_PortValue & 2) == 2) {
-							if (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								b_ChannelAMode
-								!= 1) {
-			  /*******************************************/
-								/* The digital channel A is used for input */
-			  /*******************************************/
-
-								i_ReturnValue =
-									-6;
-							}
-						}	/*  if ((b_PortValue & 2) == 2) */
-
-						/**************************/
-						/* Test if channel B used */
-						/**************************/
-
-						if ((b_PortValue & 4) == 4) {
-							if (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_DigitalIOInfo.
-								b_ChannelBMode
-								!= 1) {
-								/*******************************************/
-								/* The digital channel B is used for input */
-								/*******************************************/
-
-								i_ReturnValue =
-									-7;
-							}
-						}	/*  if ((b_PortValue & 4) == 4) */
-
-						/***********************/
-						/* Test if error occur */
-						/***********************/
-
-						if (i_ReturnValue >= 0) {
-
-							/* if(data[1]) { */
-
-							switch (b_PortOnOFF) {
-								/*********************************/
-								/* Test if set Port ON                   */
-								/*********************************/
-
-							case APCI1710_ON:
-
-								/*********************************/
-								/* Test if output memory enabled */
-								/*********************************/
-
-								if (devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_DigitalIOInfo.
-									b_OutputMemoryEnabled
-									== 1) {
-									dw_WriteValue
-										=
-										devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_DigitalIOInfo.
-										dw_OutputMemory
-										|
-										b_PortValue;
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_DigitalIOInfo.
-										dw_OutputMemory
-										=
-										dw_WriteValue;
-								} else {
-									dw_WriteValue
-										=
-										b_PortValue;
-								}
-								break;
-
-								/*  If Set PORT  OFF */
-							case APCI1710_OFF:
-
-			   /*********************************/
-								/* Test if output memory enabled */
-		       /*********************************/
-
-								if (devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_DigitalIOInfo.
-									b_OutputMemoryEnabled
-									== 1) {
-									dw_WriteValue
-										=
-										devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_DigitalIOInfo.
-										dw_OutputMemory
-										&
-										(0xFFFFFFFFUL
-										-
-										b_PortValue);
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_DigitalIOInfo.
-										dw_OutputMemory
-										=
-										dw_WriteValue;
-								} else {
-									/*****************************/
-									/* Digital Output Memory OFF */
-									/*****************************/
-
-									i_ReturnValue
-										=
-										-8;
-								}
-							}	/*  switch */
-
-							/*******************/
-							/* Write the value */
-							/*******************/
-
-							/* OUTPDW (ps_APCI1710Variable->
-							 * s_Board [b_BoardHandle].
-							 * s_BoardInfos.
-							 * ui_Address + (64 * b_ModulNbr),
-							 * dw_WriteValue); */
-
-							outl(dw_WriteValue,
-								devpriv->
-								s_BoardInfos.
-								ui_Address +
-								(64 * b_ModulNbr));
-						}
-					} else {
-						/**********************/
-						/* Output value wrong */
-						/**********************/
-
-						i_ReturnValue = -4;
-					}
-				} else {
-					/*******************************/
-					/* Digital I/O not initialised */
-					/*******************************/
-
-					i_ReturnValue = -5;
-				}
-			} else {
-	      /******************************************/
-				/* The module is not a digital I/O module */
-	      /******************************************/
-
-				i_ReturnValue = -3;
-			}
-		} else {
-	   /***********************/
-			/* Module number error */
-	   /***********************/
-
-			i_ReturnValue = -2;
-		}
-		break;
-
-	default:
-		i_ReturnValue = -9;
-		DPRINTK("NO INPUT/OUTPUT specified\n");
-	}			/* switch INPUT / OUTPUT */
-	return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
deleted file mode 100644
index c9db601..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c
+++ /dev/null
@@ -1,5461 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : INC_CPT.C       | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 incremental counter module                  |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  |          |           |                                                |
-  |----------|-----------|------------------------------------------------|
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-  | 29/06/01 | Guinot C. | - 1100/0231 -> 0701/0232                       |
-  |          |           | See i_APCI1710_DisableFrequencyMeasurement     |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_16BIT_COUNTER			0x10
-#define APCI1710_32BIT_COUNTER			0x0
-#define APCI1710_QUADRUPLE_MODE			0x0
-#define APCI1710_DOUBLE_MODE			0x3
-#define APCI1710_SIMPLE_MODE			0xF
-#define APCI1710_DIRECT_MODE			0x80
-#define APCI1710_HYSTERESIS_ON			0x60
-#define APCI1710_HYSTERESIS_OFF			0x0
-#define APCI1710_INCREMENT			0x60
-#define APCI1710_DECREMENT			0x0
-#define APCI1710_LATCH_COUNTER			0x1
-#define APCI1710_CLEAR_COUNTER			0x0
-#define APCI1710_LOW				0x0
-#define APCI1710_HIGH				0x1
-
-/*********************/
-/* Version 0600-0229 */
-/*********************/
-#define APCI1710_HIGH_EDGE_CLEAR_COUNTER		0x0
-#define APCI1710_HIGH_EDGE_LATCH_COUNTER		0x1
-#define APCI1710_LOW_EDGE_CLEAR_COUNTER			0x2
-#define APCI1710_LOW_EDGE_LATCH_COUNTER			0x3
-#define APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER	0x4
-#define APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER	0x5
-#define APCI1710_SOURCE_0				0x0
-#define APCI1710_SOURCE_1				0x1
-
-#define APCI1710_30MHZ				30
-#define APCI1710_33MHZ				33
-#define APCI1710_40MHZ				40
-
-#define APCI1710_ENABLE_LATCH_INT    		0x80
-#define APCI1710_DISABLE_LATCH_INT   		(~APCI1710_ENABLE_LATCH_INT)
-
-#define APCI1710_INDEX_LATCH_COUNTER		0x10
-#define APCI1710_INDEX_AUTO_MODE		0x8
-#define APCI1710_ENABLE_INDEX			0x4
-#define APCI1710_DISABLE_INDEX			(~APCI1710_ENABLE_INDEX)
-#define APCI1710_ENABLE_LATCH_AND_CLEAR		0x8
-#define APCI1710_DISABLE_LATCH_AND_CLEAR	(~APCI1710_ENABLE_LATCH_AND_CLEAR)
-#define APCI1710_SET_LOW_INDEX_LEVEL		0x4
-#define APCI1710_SET_HIGH_INDEX_LEVEL		(~APCI1710_SET_LOW_INDEX_LEVEL)
-#define APCI1710_INVERT_INDEX_RFERENCE		0x2
-#define APCI1710_DEFAULT_INDEX_RFERENCE         (~APCI1710_INVERT_INDEX_RFERENCE)
-
-#define APCI1710_ENABLE_INDEX_INT		0x1
-#define APCI1710_DISABLE_INDEX_INT		(~APCI1710_ENABLE_INDEX_INT)
-
-#define APCI1710_ENABLE_FREQUENCY		0x4
-#define APCI1710_DISABLE_FREQUENCY		(~APCI1710_ENABLE_FREQUENCY)
-
-#define APCI1710_ENABLE_FREQUENCY_INT		0x8
-#define APCI1710_DISABLE_FREQUENCY_INT		(~APCI1710_ENABLE_FREQUENCY_INT)
-
-#define APCI1710_ENABLE_40MHZ_FREQUENCY		0x40
-#define APCI1710_DISABLE_40MHZ_FREQUENCY	(~APCI1710_ENABLE_40MHZ_FREQUENCY)
-
-#define APCI1710_ENABLE_40MHZ_FILTER		0x80
-#define APCI1710_DISABLE_40MHZ_FILTER		(~APCI1710_ENABLE_40MHZ_FILTER)
-
-#define APCI1710_ENABLE_COMPARE_INT		0x2
-#define APCI1710_DISABLE_COMPARE_INT		(~APCI1710_ENABLE_COMPARE_INT)
-
-#define APCI1710_ENABLE_INDEX_ACTION		0x20
-#define APCI1710_DISABLE_INDEX_ACTION		(~APCI1710_ENABLE_INDEX_ACTION)
-#define APCI1710_REFERENCE_HIGH			0x40
-#define APCI1710_REFERENCE_LOW			(~APCI1710_REFERENCE_HIGH)
-
-#define APCI1710_TOR_GATE_LOW			0x40
-#define APCI1710_TOR_GATE_HIGH			(~APCI1710_TOR_GATE_LOW)
-
-/* INSN CONFIG */
-#define	APCI1710_INCCPT_INITCOUNTER			100
-#define APCI1710_INCCPT_COUNTERAUTOTEST			101
-#define APCI1710_INCCPT_INITINDEX			102
-#define APCI1710_INCCPT_INITREFERENCE			103
-#define APCI1710_INCCPT_INITEXTERNALSTROBE		104
-#define APCI1710_INCCPT_INITCOMPARELOGIC		105
-#define APCI1710_INCCPT_INITFREQUENCYMEASUREMENT	106
-
-/* INSN READ */
-#define APCI1710_INCCPT_READLATCHREGISTERSTATUS		200
-#define APCI1710_INCCPT_READLATCHREGISTERVALUE		201
-#define APCI1710_INCCPT_READ16BITCOUNTERVALUE		202
-#define APCI1710_INCCPT_READ32BITCOUNTERVALUE		203
-#define APCI1710_INCCPT_GETINDEXSTATUS			204
-#define APCI1710_INCCPT_GETREFERENCESTATUS		205
-#define APCI1710_INCCPT_GETUASSTATUS			206
-#define APCI1710_INCCPT_GETCBSTATUS			207
-#define APCI1710_INCCPT_GET16BITCBSTATUS		208
-#define APCI1710_INCCPT_GETUDSTATUS			209
-#define APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS	210
-#define APCI1710_INCCPT_READFREQUENCYMEASUREMENT	211
-#define APCI1710_INCCPT_READINTERRUPT			212
-
-/* INSN BITS */
-#define APCI1710_INCCPT_CLEARCOUNTERVALUE		300
-#define APCI1710_INCCPT_CLEARALLCOUNTERVALUE		301
-#define APCI1710_INCCPT_SETINPUTFILTER			302
-#define APCI1710_INCCPT_LATCHCOUNTER			303
-#define APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE	304
-#define APCI1710_INCCPT_SETDIGITALCHLON			305
-#define APCI1710_INCCPT_SETDIGITALCHLOFF		306
-
-/* INSN WRITE */
-#define APCI1710_INCCPT_ENABLELATCHINTERRUPT		400
-#define APCI1710_INCCPT_DISABLELATCHINTERRUPT		401
-#define APCI1710_INCCPT_WRITE16BITCOUNTERVALUE		402
-#define APCI1710_INCCPT_WRITE32BITCOUNTERVALUE		403
-#define APCI1710_INCCPT_ENABLEINDEX			404
-#define APCI1710_INCCPT_DISABLEINDEX			405
-#define APCI1710_INCCPT_ENABLECOMPARELOGIC		406
-#define APCI1710_INCCPT_DISABLECOMPARELOGIC		407
-#define APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT	408
-#define APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT	409
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitCounter                           |
-|                               (unsigned char_          b_BoardHandle,               |
-|                                unsigned char_          b_ModulNbr,                  |
-|                                unsigned char_          b_CounterRange,              |
-|                                unsigned char_          b_FirstCounterModus,         |
-|                                unsigned char_          b_FirstCounterOption,        |
-|                                unsigned char_          b_SecondCounterModus,        |
-|                                unsigned char_          b_SecondCounterOption)       |
-+----------------------------------------------------------------------------+
-| Task              : Configure the counter operating mode from selected     |
-|                     module (b_ModulNbr). You must calling this function be |
-|                     for you call any other function witch access of        |
-|                     counters.                                              |
-|                                                                            |
-|                          Counter range                                     |
-|                          -------------                                     |
-| +------------------------------------+-----------------------------------+ |
-| | Parameter       Passed value       |        Description                | |
-| |------------------------------------+-----------------------------------| |
-| |b_ModulNbr   APCI1710_16BIT_COUNTER |  The module is configured for     | |
-| |                                    |  two 16-bit counter.              | |
-| |                                    |  - b_FirstCounterModus and        | |
-| |                                    |    b_FirstCounterOption           | |
-| |                                    |    configure the first 16 bit     | |
-| |                                    |    counter.                       | |
-| |                                    |  - b_SecondCounterModus and       | |
-| |                                    |    b_SecondCounterOption          | |
-| |                                    |    configure the second 16 bit    | |
-| |                                    |    counter.                       | |
-| |------------------------------------+-----------------------------------| |
-| |b_ModulNbr   APCI1710_32BIT_COUNTER |  The module is configured for one | |
-| |                                    |  32-bit counter.                  | |
-| |                                    |  - b_FirstCounterModus and        | |
-| |                                    |    b_FirstCounterOption           | |
-| |                                    |    configure the 32 bit counter.  | |
-| |                                    |  - b_SecondCounterModus and       | |
-| |                                    |    b_SecondCounterOption          | |
-| |                                    |    are not used and have no       | |
-| |                                    |    importance.                    | |
-| +------------------------------------+-----------------------------------+ |
-|                                                                            |
-|                      Counter operating mode                                |
-|                      ----------------------                                |
-|                                                                            |
-| +--------------------+-------------------------+-------------------------+ |
-| |    Parameter       |     Passed value        |    Description          | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus | APCI1710_QUADRUPLE_MODE | In the quadruple mode,  | |
-| |       or           |                         | the edge analysis       | |
-| |b_SecondCounterModus|                         | circuit generates a     | |
-| |                    |                         | counting pulse from     | |
-| |                    |                         | each edge of 2 signals  | |
-| |                    |                         | which are phase shifted | |
-| |                    |                         | in relation to each     | |
-| |                    |                         | other.                  | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus |   APCI1710_DOUBLE_MODE  | Functions in the same   | |
-| |       or           |                         | way as the quadruple    | |
-| |b_SecondCounterModus|                         | mode, except that only  | |
-| |                    |                         | two of the four edges   | |
-| |                    |                         | are analysed per        | |
-| |                    |                         | period                  | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus |   APCI1710_SIMPLE_MODE  | Functions in the same   | |
-| |       or           |                         | way as the quadruple    | |
-| |b_SecondCounterModus|                         | mode, except that only  | |
-| |                    |                         | one of the four edges   | |
-| |                    |                         | is analysed per         | |
-| |                    |                         | period.                 | |
-| |--------------------+-------------------------+-------------------------| |
-| |b_FirstCounterModus |   APCI1710_DIRECT_MODE  | In the direct mode the  | |
-| |       or           |                         | both edge analysis      | |
-| |b_SecondCounterModus|                         | circuits are inactive.  | |
-| |                    |                         | The inputs A, B in the  | |
-| |                    |                         | 32-bit mode or A, B and | |
-| |                    |                         | C, D in the 16-bit mode | |
-| |                    |                         | represent, each, one    | |
-| |                    |                         | clock pulse gate circuit| |
-| |                    |                         | There by frequency and  | |
-| |                    |                         | pulse duration          | |
-| |                    |                         | measurements can be     | |
-| |                    |                         | performed.              | |
-| +--------------------+-------------------------+-------------------------+ |
-|                                                                            |
-|                                                                            |
-|       IMPORTANT!                                                           |
-|       If you have configured the module for two 16-bit counter, a mixed    |
-|       mode with a counter in quadruple/double/single mode                  |
-|       and the other counter in direct mode is not possible!                |
-|                                                                            |
-|                                                                            |
-|         Counter operating option for quadruple/double/simple mode          |
-|         ---------------------------------------------------------          |
-|                                                                            |
-| +----------------------+-------------------------+------------------------+|
-| |       Parameter      |     Passed value        |  Description           ||
-| |----------------------+-------------------------+------------------------||
-| |b_FirstCounterOption  | APCI1710_HYSTERESIS_ON  | In both edge analysis  ||
-| |        or            |                         | circuits is available  ||
-| |b_SecondCounterOption |                         | one hysteresis circuit.||
-| |                      |                         | It suppresses each     ||
-| |                      |                         | time the first counting||
-| |                      |                         | pulse after a change   ||
-| |                      |                         | of rotation.           ||
-| |----------------------+-------------------------+------------------------||
-| |b_FirstCounterOption  | APCI1710_HYSTERESIS_OFF | The first counting     ||
-| |       or             |                         | pulse is not suppress  ||
-| |b_SecondCounterOption |                         | after a change of      ||
-| |                      |                         | rotation.              ||
-| +----------------------+-------------------------+------------------------+|
-|                                                                            |
-|                                                                            |
-|       IMPORTANT!                                                           |
-|       This option are only avaible if you have selected the direct mode.   |
-|                                                                            |
-|                                                                            |
-|               Counter operating option for direct mode                     |
-|               ----------------------------------------                     |
-|                                                                            |
-| +----------------------+--------------------+----------------------------+ |
-| |      Parameter       |     Passed value   |       Description          | |
-| |----------------------+--------------------+----------------------------| |
-| |b_FirstCounterOption  | APCI1710_INCREMENT | The counter increment for  | |
-| |       or             |                    | each counting pulse        | |
-| |b_SecondCounterOption |                    |                            | |
-| |----------------------+--------------------+----------------------------| |
-| |b_FirstCounterOption  | APCI1710_DECREMENT | The counter decrement for  | |
-| |       or             |                    | each counting pulse        | |
-| |b_SecondCounterOption |                    |                            | |
-| +----------------------+--------------------+----------------------------+ |
-|                                                                            |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 3)       |
-|                     unsigned char_ b_CounterRange        : Selection form counter   |
-|                                                   range.                   |
-|                     unsigned char_ b_FirstCounterModus   : First counter operating  |
-|                                                   mode.                    |
-|                     unsigned char_ b_FirstCounterOption  : First counter  option.   |
-|                     unsigned char_ b_SecondCounterModus  : Second counter operating |
-|                                                   mode.                    |
-|                     unsigned char_ b_SecondCounterOption : Second counter  option.  |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module is not a counter module                  |
-|                    -3: The selected counter range is wrong.                |
-|                    -4: The selected first counter operating mode is wrong. |
-|                    -5: The selected first counter operating option is wrong|
-|                    -6: The selected second counter operating mode is wrong.|
-|                    -7: The selected second counter operating option is     |
-|                        wrong.                                              |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitCounter(struct comedi_device *dev,
-				  unsigned char b_ModulNbr,
-				  unsigned char b_CounterRange,
-				  unsigned char b_FirstCounterModus,
-				  unsigned char b_FirstCounterOption,
-				  unsigned char b_SecondCounterModus,
-				  unsigned char b_SecondCounterOption)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/*******************************/
-	/* Test if incremental counter */
-	/*******************************/
-
-	if ((devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER) {
-	   /**************************/
-		/* Test the counter range */
-	   /**************************/
-
-		if (b_CounterRange == APCI1710_16BIT_COUNTER
-			|| b_CounterRange == APCI1710_32BIT_COUNTER) {
-	      /********************************/
-			/* Test the first counter modus */
-	      /********************************/
-
-			if (b_FirstCounterModus == APCI1710_QUADRUPLE_MODE ||
-				b_FirstCounterModus == APCI1710_DOUBLE_MODE ||
-				b_FirstCounterModus == APCI1710_SIMPLE_MODE ||
-				b_FirstCounterModus == APCI1710_DIRECT_MODE) {
-		 /*********************************/
-				/* Test the first counter option */
-		 /*********************************/
-
-				if ((b_FirstCounterModus == APCI1710_DIRECT_MODE
-						&& (b_FirstCounterOption ==
-							APCI1710_INCREMENT
-							|| b_FirstCounterOption
-							== APCI1710_DECREMENT))
-					|| (b_FirstCounterModus !=
-						APCI1710_DIRECT_MODE
-						&& (b_FirstCounterOption ==
-							APCI1710_HYSTERESIS_ON
-							|| b_FirstCounterOption
-							==
-							APCI1710_HYSTERESIS_OFF)))
-				{
-		    /**************************/
-					/* Test if 16-bit counter */
-		    /**************************/
-
-					if (b_CounterRange ==
-						APCI1710_16BIT_COUNTER) {
-		       /*********************************/
-						/* Test the second counter modus */
-		       /*********************************/
-
-						if ((b_FirstCounterModus !=
-								APCI1710_DIRECT_MODE
-								&&
-								(b_SecondCounterModus
-									==
-									APCI1710_QUADRUPLE_MODE
-									||
-									b_SecondCounterModus
-									==
-									APCI1710_DOUBLE_MODE
-									||
-									b_SecondCounterModus
-									==
-									APCI1710_SIMPLE_MODE))
-							|| (b_FirstCounterModus
-								==
-								APCI1710_DIRECT_MODE
-								&&
-								b_SecondCounterModus
-								==
-								APCI1710_DIRECT_MODE))
-						{
-			  /**********************************/
-							/* Test the second counter option */
-			  /**********************************/
-
-							if ((b_SecondCounterModus == APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_INCREMENT || b_SecondCounterOption == APCI1710_DECREMENT)) || (b_SecondCounterModus != APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_HYSTERESIS_ON || b_SecondCounterOption == APCI1710_HYSTERESIS_OFF))) {
-								i_ReturnValue =
-									0;
-							} else {
-			     /*********************************************************/
-								/* The selected second counter operating option is wrong */
-			     /*********************************************************/
-
-								DPRINTK("The selected second counter operating option is wrong\n");
-								i_ReturnValue =
-									-7;
-							}
-						} else {
-			  /*******************************************************/
-							/* The selected second counter operating mode is wrong */
-			  /*******************************************************/
-
-							DPRINTK("The selected second counter operating mode is wrong\n");
-							i_ReturnValue = -6;
-						}
-					}
-				} else {
-		    /********************************************************/
-					/* The selected first counter operating option is wrong */
-		    /********************************************************/
-
-					DPRINTK("The selected first counter operating option is wrong\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /******************************************************/
-				/* The selected first counter operating mode is wrong */
-		 /******************************************************/
-				DPRINTK("The selected first counter operating mode is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /***************************************/
-			/* The selected counter range is wrong */
-	      /***************************************/
-
-			DPRINTK("The selected counter range is wrong\n");
-			i_ReturnValue = -3;
-		}
-
-	   /*************************/
-		/* Test if a error occur */
-	   /*************************/
-
-		if (i_ReturnValue == 0) {
-	      /**************************/
-			/* Test if 16-Bit counter */
-	      /**************************/
-
-			if (b_CounterRange == APCI1710_32BIT_COUNTER) {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister1 = b_CounterRange |
-					b_FirstCounterModus |
-					b_FirstCounterOption;
-			} else {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister1 = b_CounterRange |
-					(b_FirstCounterModus & 0x5) |
-					(b_FirstCounterOption & 0x20) |
-					(b_SecondCounterModus & 0xA) |
-					(b_SecondCounterOption & 0x40);
-
-		 /***********************/
-				/* Test if direct mode */
-		 /***********************/
-
-				if (b_FirstCounterModus == APCI1710_DIRECT_MODE) {
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister1 = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister1 |
-						APCI1710_DIRECT_MODE;
-				}
-			}
-
-	      /***************************/
-			/* Write the configuration */
-	      /***************************/
-
-			outl(devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				dw_ModeRegister1_2_3_4,
-				devpriv->s_BoardInfos.
-				ui_Address + 20 + (64 * b_ModulNbr));
-
-			devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_CounterInit = 1;
-		}
-	} else {
-	   /**************************************/
-		/* The module is not a counter module */
-	   /**************************************/
-
-		DPRINTK("The module is not a counter module\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_CounterAutoTest                       |
-|                                               (unsigned char_     b_BoardHandle,    |
-|                                                unsigned char *_   pb_TestStatus)     |
-+----------------------------------------------------------------------------+
-| Task              : A test mode is intended for testing the component and  |
-|                     the connected periphery. All the 8-bit counter chains  |
-|                     are operated internally as down counters.              |
-|                     Independently from the external signals,               |
-|                     all the four 8-bit counter chains are decremented in   |
-|                     parallel by each negative clock pulse edge of CLKX.    |
-|                                                                            |
-|                       Counter auto test conclusion                         |
-|                       ----------------------------                         |
-|              +-----------------+-----------------------------+             |
-|              | pb_TestStatus   |    Error description        |             |
-|              |     mask        |                             |             |
-|              |-----------------+-----------------------------|             |
-|              |    0000         |     No error detected       |             |
-|              |-----------------|-----------------------------|             |
-|              |    0001         | Error detected of counter 0 |             |
-|              |-----------------|-----------------------------|             |
-|              |    0010         | Error detected of counter 1 |             |
-|              |-----------------|-----------------------------|             |
-|              |    0100         | Error detected of counter 2 |             |
-|              |-----------------|-----------------------------|             |
-|              |    1000         | Error detected of counter 3 |             |
-|              +-----------------+-----------------------------+             |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle : Handle of board APCI-1710      |  |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_TestStatus  : Auto test conclusion. See table|
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_CounterAutoTest(struct comedi_device *dev,
-				      unsigned char *pb_TestStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned char b_ModulCpt = 0;
-	int i_ReturnValue = 0;
-	unsigned int dw_LathchValue;
-
-	*pb_TestStatus = 0;
-
-	/********************************/
-	/* Test if counter module found */
-	/********************************/
-
-	if ((devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[0] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER
-		|| (devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[1] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER
-		|| (devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[2] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER
-		|| (devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[3] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER) {
-		for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) {
-	      /*******************************/
-			/* Test if incremental counter */
-	      /*******************************/
-
-			if ((devpriv->s_BoardInfos.
-					dw_MolduleConfiguration[b_ModulCpt] &
-					0xFFFF0000UL) ==
-				APCI1710_INCREMENTAL_COUNTER) {
-		 /******************/
-				/* Start the test */
-		 /******************/
-
-				outl(3, devpriv->s_BoardInfos.
-					ui_Address + 16 + (64 * b_ModulCpt));
-
-		 /*********************/
-				/* Tatch the counter */
-		 /*********************/
-
-				outl(1, devpriv->s_BoardInfos.
-					ui_Address + (64 * b_ModulCpt));
-
-		 /************************/
-				/* Read the latch value */
-		 /************************/
-
-				dw_LathchValue = inl(devpriv->s_BoardInfos.
-					ui_Address + 4 + (64 * b_ModulCpt));
-
-				if ((dw_LathchValue & 0xFF) !=
-					((dw_LathchValue >> 8) & 0xFF)
-					&& (dw_LathchValue & 0xFF) !=
-					((dw_LathchValue >> 16) & 0xFF)
-					&& (dw_LathchValue & 0xFF) !=
-					((dw_LathchValue >> 24) & 0xFF)) {
-					*pb_TestStatus =
-						*pb_TestStatus | (1 <<
-						b_ModulCpt);
-				}
-
-		 /*****************/
-				/* Stop the test */
-		 /*****************/
-
-				outl(0, devpriv->s_BoardInfos.
-					ui_Address + 16 + (64 * b_ModulCpt));
-			}
-		}
-	} else {
-	   /***************************/
-		/* No counter module found */
-	   /***************************/
-
-		DPRINTK("No counter module found\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitIndex (unsigned char_ b_BoardHandle,       |
-|                                                 unsigned char_ b_ModulNbr,          |
-|                                                 unsigned char_ b_ReferenceAction,   |
-|                                                 unsigned char_ b_IndexOperation,    |
-|                                                 unsigned char_ b_AutoMode,          |
-|                                                 unsigned char_ b_InterruptEnable)   |
-+----------------------------------------------------------------------------+
-| Task              : Initialise the index corresponding to the selected     |
-|                     module (b_ModulNbr). If a INDEX flag occur, you have   |
-|                     the possibility to clear the 32-Bit counter or to latch|
-|                     the current 32-Bit value in to the first latch         |
-|                     register. The b_IndexOperation parameter give the      |
-|                     possibility to choice the INDEX action.                |
-|                     If you have enabled the automatic mode, each INDEX     |
-|                     action is cleared automatically, else you must read    |
-|                     the index status ("i_APCI1710_ReadIndexStatus")        |
-|                     after each INDEX action.                               |
-|                                                                            |
-|                                                                            |
-|                               Index action                                 |
-|                               ------------                                 |
-|                                                                            |
-|           +------------------------+------------------------------------+  |
-|           |   b_IndexOperation     |         Operation                  |  |
-|           |------------------------+------------------------------------|  |
-|           |APCI1710_LATCH_COUNTER  | After a index signal, the counter  |  |
-|           |                        | value (32-Bit) is latched in to    |  |
-|           |                        | the first latch register           |  |
-|           |------------------------|------------------------------------|  |
-|           |APCI1710_CLEAR_COUNTER  | After a index signal, the counter  |  |
-|           |                        | value is cleared (32-Bit)          |  |
-|           +------------------------+------------------------------------+  |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-|                     unsigned char_ b_ReferenceAction : Determine if the reference   |
-|                                               must set or no for the       |
-|                                               acceptance from index        |
-|                                               APCI1710_ENABLE :            |
-|                                                  Reference must be set for |
-|                                                  accepted the index        |
-|                                               APCI1710_DISABLE :           |
-|                                                  Reference have not        |
-|                                                  importance                |
-|                     unsigned char_ b_IndexOperation  : Index operating mode.        |
-|                                               See table.                   |
-|                     unsigned char_ b_AutoMode        : Enable or disable the        |
-|                                               automatic index reset.       |
-|                                               APCI1710_ENABLE :            |
-|                                                 Enable the automatic mode  |
-|                                               APCI1710_DISABLE :           |
-|                                                 Disable the automatic mode |
-|                     unsigned char_ b_InterruptEnable : Enable or disable the        |
-|                                               interrupt.                   |
-|                                               APCI1710_ENABLE :            |
-|                                               Enable the interrupt         |
-|                                               APCI1710_DISABLE :           |
-|                                               Disable the interrupt        |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4  The reference action parameter is wrong            |
-|                     -5: The index operating mode parameter is wrong        |
-|                     -6: The auto mode parameter is wrong                   |
-|                     -7: Interrupt parameter is wrong                       |
-|                     -8: Interrupt function not initialised.                |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitIndex(struct comedi_device *dev,
-				unsigned char b_ModulNbr,
-				unsigned char b_ReferenceAction,
-				unsigned char b_IndexOperation,
-				unsigned char b_AutoMode,
-				unsigned char b_InterruptEnable)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /********************************/
-			/* Test the reference parameter */
-	      /********************************/
-
-			if (b_ReferenceAction == APCI1710_ENABLE ||
-				b_ReferenceAction == APCI1710_DISABLE) {
-		 /****************************/
-				/* Test the index parameter */
-		 /****************************/
-
-				if (b_IndexOperation ==
-					APCI1710_HIGH_EDGE_LATCH_COUNTER
-					|| b_IndexOperation ==
-					APCI1710_LOW_EDGE_LATCH_COUNTER
-					|| b_IndexOperation ==
-					APCI1710_HIGH_EDGE_CLEAR_COUNTER
-					|| b_IndexOperation ==
-					APCI1710_LOW_EDGE_CLEAR_COUNTER
-					|| b_IndexOperation ==
-					APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER
-					|| b_IndexOperation ==
-					APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
-				{
-		    /********************************/
-					/* Test the auto mode parameter */
-		    /********************************/
-
-					if (b_AutoMode == APCI1710_ENABLE ||
-						b_AutoMode == APCI1710_DISABLE)
-					{
-		       /***************************/
-						/* Test the interrupt mode */
-		       /***************************/
-
-						if (b_InterruptEnable ==
-							APCI1710_ENABLE
-							|| b_InterruptEnable ==
-							APCI1710_DISABLE) {
-
-			     /************************************/
-							/* Makte the configuration commando */
-			     /************************************/
-
-							if (b_ReferenceAction ==
-								APCI1710_ENABLE)
-							{
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									|
-									APCI1710_ENABLE_INDEX_ACTION;
-							} else {
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									&
-									APCI1710_DISABLE_INDEX_ACTION;
-							}
-
-			     /****************************************/
-							/* Test if low level latch or/and clear */
-			     /****************************************/
-
-							if (b_IndexOperation ==
-								APCI1710_LOW_EDGE_LATCH_COUNTER
-								||
-								b_IndexOperation
-								==
-								APCI1710_LOW_EDGE_CLEAR_COUNTER
-								||
-								b_IndexOperation
-								==
-								APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
-							{
-				/*************************************/
-								/* Set the index level to low (DQ26) */
-				/*************************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									|
-									APCI1710_SET_LOW_INDEX_LEVEL;
-							} else {
-				/**************************************/
-								/* Set the index level to high (DQ26) */
-				/**************************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									&
-									APCI1710_SET_HIGH_INDEX_LEVEL;
-							}
-
-			     /***********************************/
-							/* Test if latch and clear counter */
-			     /***********************************/
-
-							if (b_IndexOperation ==
-								APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER
-								||
-								b_IndexOperation
-								==
-								APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER)
-							{
-				/***************************************/
-								/* Set the latch and clear flag (DQ27) */
-				/***************************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									|
-									APCI1710_ENABLE_LATCH_AND_CLEAR;
-							}	/*  if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */
-							else {
-				/*****************************************/
-								/* Clear the latch and clear flag (DQ27) */
-				/*****************************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									&
-									APCI1710_DISABLE_LATCH_AND_CLEAR;
-
-				/*************************/
-								/* Test if latch counter */
-				/*************************/
-
-								if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_COUNTER) {
-				   /*********************************/
-									/* Enable the latch from counter */
-				   /*********************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister2
-										=
-										devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister2
-										|
-										APCI1710_INDEX_LATCH_COUNTER;
-								} else {
-				   /*********************************/
-									/* Enable the clear from counter */
-				   /*********************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister2
-										=
-										devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister2
-										&
-										(~APCI1710_INDEX_LATCH_COUNTER);
-								}
-							}	/*  // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */
-
-							if (b_AutoMode ==
-								APCI1710_DISABLE)
-							{
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									|
-									APCI1710_INDEX_AUTO_MODE;
-							} else {
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister2
-									&
-									(~APCI1710_INDEX_AUTO_MODE);
-							}
-
-							if (b_InterruptEnable ==
-								APCI1710_ENABLE)
-							{
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister3
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister3
-									|
-									APCI1710_ENABLE_INDEX_INT;
-							} else {
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister3
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister3
-									&
-									APCI1710_DISABLE_INDEX_INT;
-							}
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_SiemensCounterInfo.
-								s_InitFlag.
-								b_IndexInit = 1;
-
-						} else {
-			  /********************************/
-							/* Interrupt parameter is wrong */
-			  /********************************/
-							DPRINTK("Interrupt parameter is wrong\n");
-							i_ReturnValue = -7;
-						}
-					} else {
-		       /************************************/
-						/* The auto mode parameter is wrong */
-		       /************************************/
-
-						DPRINTK("The auto mode parameter is wrong\n");
-						i_ReturnValue = -6;
-					}
-				} else {
-		    /***********************************************/
-					/* The index operating mode parameter is wrong */
-		    /***********************************************/
-
-					DPRINTK("The index operating mode parameter is wrong\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /*******************************************/
-				/* The reference action parameter is wrong */
-		 /*******************************************/
-
-				DPRINTK("The reference action parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitReference                         |
-|                                                (unsigned char_ b_BoardHandle,       |
-|                                                 unsigned char_ b_ModulNbr,          |
-|                                                 unsigned char_ b_ReferenceLevel)    |
-+----------------------------------------------------------------------------+
-| Task              : Initialise the reference corresponding to the selected |
-|                     module (b_ModulNbr).                                   |
-|                                                                            |
-|                               Reference level                              |
-|                               ---------------                              |
-|             +--------------------+-------------------------+               |
-|             | b_ReferenceLevel   |         Operation       |               |
-|             +--------------------+-------------------------+               |
-|             |   APCI1710_LOW     |  Reference occur if "0" |               |
-|             |--------------------|-------------------------|               |
-|             |   APCI1710_HIGH    |  Reference occur if "1" |               |
-|             +--------------------+-------------------------+               |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-|                     unsigned char_ b_ReferenceLevel  : Reference level.             |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number parameter is wrong      |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Reference level parameter is wrong                 |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitReference(struct comedi_device *dev,
-				    unsigned char b_ModulNbr,
-				    unsigned char b_ReferenceLevel)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /**************************************/
-			/* Test the reference level parameter */
-	      /**************************************/
-
-			if (b_ReferenceLevel == 0 || b_ReferenceLevel == 1) {
-				if (b_ReferenceLevel == 1) {
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister2 = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister2 |
-						APCI1710_REFERENCE_HIGH;
-				} else {
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister2 = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister2 &
-						APCI1710_REFERENCE_LOW;
-				}
-
-				outl(devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					dw_ModeRegister1_2_3_4,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_InitFlag.b_ReferenceInit = 1;
-			} else {
-		 /**************************************/
-				/* Reference level parameter is wrong */
-		 /**************************************/
-
-				DPRINTK("Reference level parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_	i_APCI1710_InitExternalStrobe                |
-|					(unsigned char_ b_BoardHandle,                |
-|					 unsigned char_ b_ModulNbr,                   |
-|					 unsigned char_ b_ExternalStrobe,             |
-|					 unsigned char_ b_ExternalStrobeLevel)        |
-+----------------------------------------------------------------------------+
-| Task              : Initialises the external strobe level corresponding to |
-|		      the selected module (b_ModulNbr).                      |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-|		      unsigned char_ b_ExternalStrobe  : External strobe selection    |
-|						0 : External strobe A        |
-|						1 : External strobe B        |
-|		      unsigned char_ b_ExternalStrobeLevel : External strobe level    |
-|						APCI1710_LOW :               |
-|						External latch occurs if "0" |
-|						APCI1710_HIGH :              |
-|						External latch occurs if "1" |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number is wrong                |
-|                     -3: Counter not initialised.                           |
-|			  See function "i_APCI1710_InitCounter"              |
-|                     -4: External strobe selection is wrong                 |
-|                     -5: External strobe level parameter is wrong           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitExternalStrobe(struct comedi_device *dev,
-					 unsigned char b_ModulNbr,
-					 unsigned char b_ExternalStrobe,
-					 unsigned char b_ExternalStrobeLevel)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /**************************************/
-			/* Test the external strobe selection */
-	      /**************************************/
-
-			if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) {
-		 /******************/
-				/* Test the level */
-		 /******************/
-
-				if ((b_ExternalStrobeLevel == APCI1710_HIGH) ||
-					((b_ExternalStrobeLevel == APCI1710_LOW
-							&& (devpriv->
-								s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) >=
-							0x3135))) {
-		    /*****************/
-					/* Set the level */
-		    /*****************/
-
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister4 = (devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister4 & (0xFF -
-							(0x10 << b_ExternalStrobe))) | ((b_ExternalStrobeLevel ^ 1) << (4 + b_ExternalStrobe));
-				} else {
-		    /********************************************/
-					/* External strobe level parameter is wrong */
-		    /********************************************/
-
-					DPRINTK("External strobe level parameter is wrong\n");
-					i_ReturnValue = -5;
-				}
-			}	/*  if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */
-			else {
-		 /**************************************/
-				/* External strobe selection is wrong */
-		 /**************************************/
-
-				DPRINTK("External strobe selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-	/*
-	   +----------------------------------------------------------------------------+
-	   | Function Name     : _INT_ i_APCI1710_InitCompareLogic                      |
-	   |                               (unsigned char_   b_BoardHandle,                      |
-	   |                                unsigned char_   b_ModulNbr,                         |
-	   |                                unsigned int_  ui_CompareValue)                     |
-	   +----------------------------------------------------------------------------+
-	   | Task              : Set the 32-Bit compare value. At that moment that the  |
-	   |                     incremental counter arrive to the compare value        |
-	   |                     (ui_CompareValue) a interrupt is generated.            |
-	   +----------------------------------------------------------------------------+
-	   | Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-	   |                     unsigned char_  b_ModulNbr       : Module number to configure   |
-	   |                                               (0 to 3)                     |
-	   |                     unsigned int_ ui_CompareValue   : 32-Bit compare value         |
-	   +----------------------------------------------------------------------------+
-	   | Output Parameters : -
-	   +----------------------------------------------------------------------------+
-	   | Return Value      :  0: No error                                           |
-	   |                     -1: The handle parameter of the board is wrong         |
-	   |                     -2: No counter module found                            |
-	   |                     -3: Counter not initialised see function               |
-	   |                         "i_APCI1710_InitCounter"                           |
-	   +----------------------------------------------------------------------------+
-	 */
-static int i_APCI1710_InitCompareLogic(struct comedi_device *dev,
-				       unsigned char b_ModulNbr,
-				       unsigned int ui_CompareValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-
-			outl(ui_CompareValue, devpriv->s_BoardInfos.
-				ui_Address + 28 + (64 * b_ModulNbr));
-
-			devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_CompareLogicInit = 1;
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitFrequencyMeasurement              |
-|				(unsigned char_		 b_BoardHandle,              |
-|				 unsigned char_		 b_ModulNbr,                 |
-|				 unsigned char_		 b_PCIInputClock,            |
-|				 unsigned char_		 b_TimingUnity,              |
-|				 ULONG_ 	ul_TimingInterval,           |
-|				 PULONG_       pul_RealTimingInterval)       |
-+----------------------------------------------------------------------------+
-| Task              : Sets the time for the frequency measurement.           |
-|		      Configures the selected TOR incremental counter of the |
-|		      selected module (b_ModulNbr). The ul_TimingInterval and|
-|		      ul_TimingUnity determine the time base for the         |
-|		      measurement. The pul_RealTimingInterval returns the    |
-|		      real time value. You must call up this function before |
-|		      you call up any other function which gives access to   |
-|		      the frequency measurement.                             |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-|		      unsigned char_  b_ModulNbr	      :	Number of the module to be   |
-|						configured (0 to 3)          |
-|		      unsigned char_  b_PCIInputClock  :	Selection of the PCI bus     |
-|						clock                        |
-|						- APCI1710_30MHZ :           |
-|						  The PC has a PCI bus clock |
-|						  of 30 MHz                  |
-|						- APCI1710_33MHZ :           |
-|						  The PC has a PCI bus clock |
-|						  of 33 MHz                  |
-|		      unsigned char_  b_TimingUnity    : Base time unit (0 to 2)      |
-|						  0 : ns                     |
-|						  1 : æs                     |
-|						  2 : ms                     |
-|		      ULONG_ ul_TimingInterval: Base time value.             |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_RealTimingInterval : Real base time value. |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number is wrong                |
-|                     -3: Counter not initialised see function               |
-|			  "i_APCI1710_InitCounter"                           |
-|                     -4: The selected PCI input clock is wrong              |
-|                     -5: Timing unity selection is wrong                    |
-|                     -6: Base timing selection is wrong                     |
-|		      -7: 40MHz quartz not on board                          |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev,
-					       unsigned char b_ModulNbr,
-					       unsigned char b_PCIInputClock,
-					       unsigned char b_TimingUnity,
-					       unsigned int ul_TimingInterval,
-					       unsigned int *pul_RealTimingInterval)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ul_TimerValue = 0;
-	double d_RealTimingInterval;
-	unsigned int dw_Status = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /**************************/
-			/* Test the PCI bus clock */
-	      /**************************/
-
-			if ((b_PCIInputClock == APCI1710_30MHZ) ||
-				(b_PCIInputClock == APCI1710_33MHZ) ||
-				(b_PCIInputClock == APCI1710_40MHZ)) {
-		 /************************/
-				/* Test the timing unit */
-		 /************************/
-
-				if (b_TimingUnity <= 2) {
-		    /**********************************/
-					/* Test the base timing selection */
-		    /**********************************/
-
-					if (((b_PCIInputClock == APCI1710_30MHZ)
-							&& (b_TimingUnity == 0)
-							&& (ul_TimingInterval >=
-								266)
-							&& (ul_TimingInterval <=
-								8738133UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_30MHZ)
-							&& (b_TimingUnity == 1)
-							&& (ul_TimingInterval >=
-								1)
-							&& (ul_TimingInterval <=
-								8738UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_30MHZ)
-							&& (b_TimingUnity == 2)
-							&& (ul_TimingInterval >=
-								1)
-							&& (ul_TimingInterval <=
-								8UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_33MHZ)
-							&& (b_TimingUnity == 0)
-							&& (ul_TimingInterval >=
-								242)
-							&& (ul_TimingInterval <=
-								7943757UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_33MHZ)
-							&& (b_TimingUnity == 1)
-							&& (ul_TimingInterval >=
-								1)
-							&& (ul_TimingInterval <=
-								7943UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_33MHZ)
-							&& (b_TimingUnity == 2)
-							&& (ul_TimingInterval >=
-								1)
-							&& (ul_TimingInterval <=
-								7UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_40MHZ)
-							&& (b_TimingUnity == 0)
-							&& (ul_TimingInterval >=
-								200)
-							&& (ul_TimingInterval <=
-								6553500UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_40MHZ)
-							&& (b_TimingUnity == 1)
-							&& (ul_TimingInterval >=
-								1)
-							&& (ul_TimingInterval <=
-								6553UL))
-						|| ((b_PCIInputClock ==
-								APCI1710_40MHZ)
-							&& (b_TimingUnity == 2)
-							&& (ul_TimingInterval >=
-								1)
-							&& (ul_TimingInterval <=
-								6UL))) {
-		       /**********************/
-						/* Test if 40MHz used */
-		       /**********************/
-
-						if (b_PCIInputClock ==
-							APCI1710_40MHZ) {
-			  /******************************/
-							/* Test if firmware >= Rev1.5 */
-			  /******************************/
-
-							if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3135) {
-			     /*********************************/
-								/* Test if 40MHz quartz on board */
-			     /*********************************/
-
-								/*INPDW (ps_APCI1710Variable->
-								   s_Board [b_BoardHandle].
-								   s_BoardInfos.
-								   ui_Address + 36 + (64 * b_ModulNbr), &dw_Status); */
-								dw_Status =
-									inl
-									(devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 36 +
-									(64 * b_ModulNbr));
-
-			     /******************************/
-								/* Test the quartz flag (DQ0) */
-			     /******************************/
-
-								if ((dw_Status & 1) != 1) {
-				/*****************************/
-									/* 40MHz quartz not on board */
-				/*****************************/
-
-									DPRINTK("40MHz quartz not on board\n");
-									i_ReturnValue
-										=
-										-7;
-								}
-							} else {
-			     /*****************************/
-								/* 40MHz quartz not on board */
-			     /*****************************/
-								DPRINTK("40MHz quartz not on board\n");
-								i_ReturnValue =
-									-7;
-							}
-						}	/*  if (b_PCIInputClock == APCI1710_40MHZ) */
-
-		       /***************************/
-						/* Test if not error occur */
-		       /***************************/
-
-						if (i_ReturnValue == 0) {
-			  /****************************/
-							/* Test the INC_CPT version */
-			  /****************************/
-
-							if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131) {
-
-				/**********************/
-								/* Test if 40MHz used */
-				/**********************/
-
-								if (b_PCIInputClock == APCI1710_40MHZ) {
-				   /*********************************/
-									/* Enable the 40MHz quarz (DQ30) */
-				   /*********************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister4
-										=
-										devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister4
-										|
-										APCI1710_ENABLE_40MHZ_FREQUENCY;
-								}	/*  if (b_PCIInputClock == APCI1710_40MHZ) */
-								else {
-				   /**********************************/
-									/* Disable the 40MHz quarz (DQ30) */
-				   /**********************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister4
-										=
-										devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_SiemensCounterInfo.
-										s_ModeRegister.
-										s_ByteModeRegister.
-										b_ModeRegister4
-										&
-										APCI1710_DISABLE_40MHZ_FREQUENCY;
-
-								}	/*  if (b_PCIInputClock == APCI1710_40MHZ) */
-
-			     /********************************/
-								/* Calculate the division fator */
-			     /********************************/
-
-								fpu_begin();
-								switch (b_TimingUnity) {
-				/******/
-									/* ns */
-				/******/
-
-								case 0:
-
-					/******************/
-									/* Timer 0 factor */
-					/******************/
-
-									ul_TimerValue
-										=
-										(unsigned int)
-										(ul_TimingInterval
-										*
-										(0.00025 * b_PCIInputClock));
-
-					/*******************/
-									/* Round the value */
-					/*******************/
-
-									if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-										ul_TimerValue
-											=
-											ul_TimerValue
-											+
-											1;
-									}
-
-					/*****************************/
-									/* Calculate the real timing */
-					/*****************************/
-
-									*pul_RealTimingInterval
-										=
-										(unsigned int)
-										(ul_TimerValue
-										/
-										(0.00025 * (double)b_PCIInputClock));
-									d_RealTimingInterval
-										=
-										(double)
-										ul_TimerValue
-										/
-										(0.00025
-										*
-										(double)
-										b_PCIInputClock);
-
-									if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
-										*pul_RealTimingInterval
-											=
-											*pul_RealTimingInterval
-											+
-											1;
-									}
-
-									ul_TimingInterval
-										=
-										ul_TimingInterval
-										-
-										1;
-									ul_TimerValue
-										=
-										ul_TimerValue
-										-
-										2;
-
-									break;
-
-				/******/
-									/* æs */
-				/******/
-
-								case 1:
-
-					/******************/
-									/* Timer 0 factor */
-					/******************/
-
-									ul_TimerValue
-										=
-										(unsigned int)
-										(ul_TimingInterval
-										*
-										(0.25 * b_PCIInputClock));
-
-					/*******************/
-									/* Round the value */
-					/*******************/
-
-									if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-										ul_TimerValue
-											=
-											ul_TimerValue
-											+
-											1;
-									}
-
-					/*****************************/
-									/* Calculate the real timing */
-					/*****************************/
-
-									*pul_RealTimingInterval
-										=
-										(unsigned int)
-										(ul_TimerValue
-										/
-										(0.25 * (double)b_PCIInputClock));
-									d_RealTimingInterval
-										=
-										(double)
-										ul_TimerValue
-										/
-										(
-										(double)
-										0.25
-										*
-										(double)
-										b_PCIInputClock);
-
-									if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
-										*pul_RealTimingInterval
-											=
-											*pul_RealTimingInterval
-											+
-											1;
-									}
-
-									ul_TimingInterval
-										=
-										ul_TimingInterval
-										-
-										1;
-									ul_TimerValue
-										=
-										ul_TimerValue
-										-
-										2;
-
-									break;
-
-				/******/
-									/* ms */
-				/******/
-
-								case 2:
-
-					/******************/
-									/* Timer 0 factor */
-					/******************/
-
-									ul_TimerValue
-										=
-										ul_TimingInterval
-										*
-										(250.0
-										*
-										b_PCIInputClock);
-
-					/*******************/
-									/* Round the value */
-					/*******************/
-
-									if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-										ul_TimerValue
-											=
-											ul_TimerValue
-											+
-											1;
-									}
-
-					/*****************************/
-									/* Calculate the real timing */
-					/*****************************/
-
-									*pul_RealTimingInterval
-										=
-										(unsigned int)
-										(ul_TimerValue
-										/
-										(250.0 * (double)b_PCIInputClock));
-									d_RealTimingInterval
-										=
-										(double)
-										ul_TimerValue
-										/
-										(250.0
-										*
-										(double)
-										b_PCIInputClock);
-
-									if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) {
-										*pul_RealTimingInterval
-											=
-											*pul_RealTimingInterval
-											+
-											1;
-									}
-
-									ul_TimingInterval
-										=
-										ul_TimingInterval
-										-
-										1;
-									ul_TimerValue
-										=
-										ul_TimerValue
-										-
-										2;
-
-									break;
-								}
-
-								fpu_end();
-			     /*************************/
-								/* Write the timer value */
-			     /*************************/
-
-								outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 32 + (64 * b_ModulNbr));
-
-			     /*******************************/
-								/* Set the initialisation flag */
-			     /*******************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_InitFlag.
-									b_FrequencyMeasurementInit
-									= 1;
-							} else {
-			     /***************************/
-								/* Counter not initialised */
-			     /***************************/
-
-								DPRINTK("Counter not initialised\n");
-								i_ReturnValue =
-									-3;
-							}
-						}	/*  if (i_ReturnValue == 0) */
-					} else {
-		       /**********************************/
-						/* Base timing selection is wrong */
-		       /**********************************/
-
-						DPRINTK("Base timing selection is wrong\n");
-						i_ReturnValue = -6;
-					}
-				} else {
-		    /***********************************/
-					/* Timing unity selection is wrong */
-		    /***********************************/
-
-					DPRINTK("Timing unity selection is wrong\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /*****************************************/
-				/* The selected PCI input clock is wrong */
-		 /*****************************************/
-
-				DPRINTK("The selected PCI input clock is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
- * Configuration function for INC_CPT
- */
-static int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev,
-				       struct comedi_subdevice *s,
-				       struct comedi_insn *insn,
-				       unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned int ui_ConfigType;
-	int i_ReturnValue = 0;
-
-	ui_ConfigType = CR_CHAN(insn->chanspec);
-
-	printk("\nINC_CPT");
-
-	devpriv->tsk_Current = current;	/*  Save the current process task structure */
-	switch (ui_ConfigType) {
-	case APCI1710_INCCPT_INITCOUNTER:
-		i_ReturnValue = i_APCI1710_InitCounter(dev,
-			CR_AREF(insn->chanspec),
-			(unsigned char) data[0],
-			(unsigned char) data[1],
-			(unsigned char) data[2], (unsigned char) data[3], (unsigned char) data[4]);
-		break;
-
-	case APCI1710_INCCPT_COUNTERAUTOTEST:
-		i_ReturnValue = i_APCI1710_CounterAutoTest(dev,
-			(unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_INITINDEX:
-		i_ReturnValue = i_APCI1710_InitIndex(dev,
-			CR_AREF(insn->chanspec),
-			(unsigned char) data[0],
-			(unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]);
-		break;
-
-	case APCI1710_INCCPT_INITREFERENCE:
-		i_ReturnValue = i_APCI1710_InitReference(dev,
-			CR_AREF(insn->chanspec), (unsigned char) data[0]);
-		break;
-
-	case APCI1710_INCCPT_INITEXTERNALSTROBE:
-		i_ReturnValue = i_APCI1710_InitExternalStrobe(dev,
-			CR_AREF(insn->chanspec),
-			(unsigned char) data[0], (unsigned char) data[1]);
-		break;
-
-	case APCI1710_INCCPT_INITCOMPARELOGIC:
-		i_ReturnValue = i_APCI1710_InitCompareLogic(dev,
-			CR_AREF(insn->chanspec), (unsigned int) data[0]);
-		break;
-
-	case APCI1710_INCCPT_INITFREQUENCYMEASUREMENT:
-		i_ReturnValue = i_APCI1710_InitFrequencyMeasurement(dev,
-			CR_AREF(insn->chanspec),
-			(unsigned char) data[0],
-			(unsigned char) data[1], (unsigned int) data[2], (unsigned int *) &data[0]);
-		break;
-
-	default:
-		printk("Insn Config : Config Parameter Wrong\n");
-
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ClearCounterValue                     |
-|                               (unsigned char_      b_BoardHandle,                   |
-|                                unsigned char_       b_ModulNbr)                     |
-+----------------------------------------------------------------------------+
-| Task              : Clear the counter value from selected module           |
-|                     (b_ModulNbr).                                          |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Module number to configure       |
-|                                           (0 to 3)                         |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number parameter is wrong      |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ClearCounterValue(struct comedi_device *dev,
-					unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*********************/
-			/* Clear the counter */
-	      /*********************/
-
-			outl(1, devpriv->s_BoardInfos.
-				ui_Address + 16 + (64 * b_ModulNbr));
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ClearAllCounterValue                  |
-|                               (unsigned char_      b_BoardHandle)                   |
-+----------------------------------------------------------------------------+
-| Task              : Clear all counter value.                               |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned char b_ModulCpt = 0;
-	int i_ReturnValue = 0;
-
-	/********************************/
-	/* Test if counter module found */
-	/********************************/
-
-	if ((devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[0] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER
-		|| (devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[1] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER
-		|| (devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[2] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER
-		|| (devpriv->s_BoardInfos.
-			dw_MolduleConfiguration[3] & 0xFFFF0000UL) ==
-		APCI1710_INCREMENTAL_COUNTER) {
-		for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) {
-	      /*******************************/
-			/* Test if incremental counter */
-	      /*******************************/
-
-			if ((devpriv->s_BoardInfos.
-					dw_MolduleConfiguration[b_ModulCpt] &
-					0xFFFF0000UL) ==
-				APCI1710_INCREMENTAL_COUNTER) {
-		 /*********************/
-				/* Clear the counter */
-		 /*********************/
-
-				outl(1, devpriv->s_BoardInfos.
-					ui_Address + 16 + (64 * b_ModulCpt));
-			}
-		}
-	} else {
-	   /***************************/
-		/* No counter module found */
-	   /***************************/
-
-		DPRINTK("No counter module found\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_SetInputFilter                        |
-|					(unsigned char_ b_BoardHandle,                |
-|					 unsigned char_ b_Module,                     |
-|					 unsigned char_ b_PCIInputClock,              |
-|					 unsigned char_ b_Filter)     		     |
-+----------------------------------------------------------------------------+
-| Task              : Disable or enable the software filter from selected    |
-|		      module (b_ModulNbr). b_Filter determine the filter time|
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-|		      unsigned char_  b_ModulNbr	      :	Number of the module to be   |
-|						configured (0 to 3)          |
-|		      unsigned char_  b_PCIInputClock  :	Selection of the PCI bus     |
-|						clock                        |
-|						- APCI1710_30MHZ :           |
-|						  The PC has a PCI bus clock |
-|						  of 30 MHz                  |
-|						- APCI1710_33MHZ :           |
-|						  The PC has a PCI bus clock |
-|						  of 33 MHz                  |
-|						- APCI1710_40MHZ :           |
-|						  The APCI1710 has a 40MHz    |
-|						  quartz		     |
-|		      unsigned char_  b_Filter	      : Filter selection             |
-|                                                                            |
-|				30 MHz                                       |
-|				------                                       |
-|					0:  Software filter not used         |
-|					1:  Filter from 266ns  (3.750000MHz) |
-|					2:  Filter from 400ns  (2.500000MHz) |
-|					3:  Filter from 533ns  (1.876170MHz) |
-|					4:  Filter from 666ns  (1.501501MHz) |
-|					5:  Filter from 800ns  (1.250000MHz) |
-|					6:  Filter from 933ns  (1.071800MHz) |
-|					7:  Filter from 1066ns (0.938080MHz) |
-|					8:  Filter from 1200ns (0.833333MHz) |
-|					9:  Filter from 1333ns (0.750000MHz) |
-|					10: Filter from 1466ns (0.682100MHz) |
-|					11: Filter from 1600ns (0.625000MHz) |
-|					12: Filter from 1733ns (0.577777MHz) |
-|					13: Filter from 1866ns (0.535900MHz) |
-|					14: Filter from 2000ns (0.500000MHz) |
-|					15: Filter from 2133ns (0.468800MHz) |
-|									     |
-|				33 MHz                                       |
-|				------                                       |
-|					0:  Software filter not used         |
-|					1:  Filter from 242ns  (4.125000MHz) |
-|					2:  Filter from 363ns  (2.754820MHz) |
-|					3:  Filter from 484ns  (2.066115MHz) |
-|					4:  Filter from 605ns  (1.652892MHz) |
-|					5:  Filter from 726ns  (1.357741MHz) |
-|					6:  Filter from 847ns  (1.180637MHz) |
-|					7:  Filter from 968ns  (1.033055MHz) |
-|					8:  Filter from 1089ns (0.918273MHz) |
-|					9:  Filter from 1210ns (0.826446MHz) |
-|					10: Filter from 1331ns (0.751314MHz) |
-|					11: Filter from 1452ns (0.688705MHz) |
-|					12: Filter from 1573ns (0.635727MHz) |
-|					13: Filter from 1694ns (0.590318MHz) |
-|					14: Filter from 1815ns (0.550964MHz) |
-|					15: Filter from 1936ns (0.516528MHz) |
-|									     |
-|				40 MHz                                       |
-|				------                                       |
-|					0:  Software filter not used         |
-|					1:  Filter from 200ns  (5.000000MHz) |
-|					2:  Filter from 300ns  (3.333333MHz) |
-|					3:  Filter from 400ns  (2.500000MHz) |
-|					4:  Filter from 500ns  (2.000000MHz) |
-|					5:  Filter from 600ns  (1.666666MHz) |
-|					6:  Filter from 700ns  (1.428500MHz) |
-|					7:  Filter from 800ns  (1.250000MHz) |
-|					8:  Filter from 900ns  (1.111111MHz) |
-|					9:  Filter from 1000ns (1.000000MHz) |
-|					10: Filter from 1100ns (0.909090MHz) |
-|					11: Filter from 1200ns (0.833333MHz) |
-|					12: Filter from 1300ns (0.769200MHz) |
-|					13: Filter from 1400ns (0.714200MHz) |
-|					14: Filter from 1500ns (0.666666MHz) |
-|					15: Filter from 1600ns (0.625000MHz) |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number is wrong                |
-|                     -3: The module is not a counter module                 |
-|					  -4: The selected PCI input clock is wrong              |
-|					  -5: The selected filter value is wrong                 |
-|					  -6: 40MHz quartz not on board                          |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetInputFilter(struct comedi_device *dev,
-				     unsigned char b_ModulNbr,
-				     unsigned char b_PCIInputClock,
-				     unsigned char b_Filter)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if incremental counter */
-	   /*******************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
-	      /******************************/
-			/* Test if firmware >= Rev1.5 */
-	      /******************************/
-
-			if ((devpriv->s_BoardInfos.
-					dw_MolduleConfiguration[b_ModulNbr] &
-					0xFFFF) >= 0x3135) {
-		 /**************************/
-				/* Test the PCI bus clock */
-		 /**************************/
-
-				if ((b_PCIInputClock == APCI1710_30MHZ) ||
-					(b_PCIInputClock == APCI1710_33MHZ) ||
-					(b_PCIInputClock == APCI1710_40MHZ)) {
-		    /*************************/
-					/* Test the filter value */
-		    /*************************/
-
-					if (b_Filter < 16) {
-		       /**********************/
-						/* Test if 40MHz used */
-		       /**********************/
-
-						if (b_PCIInputClock ==
-							APCI1710_40MHZ) {
-			  /*********************************/
-							/* Test if 40MHz quartz on board */
-			  /*********************************/
-
-							dw_Status =
-								inl(devpriv->
-								s_BoardInfos.
-								ui_Address +
-								36 +
-								(64 * b_ModulNbr));
-
-			  /******************************/
-							/* Test the quartz flag (DQ0) */
-			  /******************************/
-
-							if ((dw_Status & 1) !=
-								1) {
-			     /*****************************/
-								/* 40MHz quartz not on board */
-			     /*****************************/
-
-								DPRINTK("40MHz quartz not on board\n");
-								i_ReturnValue =
-									-6;
-							}
-						}	/*  if (b_PCIInputClock == APCI1710_40MHZ) */
-
-		       /***************************/
-						/* Test if error not occur */
-		       /***************************/
-
-						if (i_ReturnValue == 0) {
-			  /**********************/
-							/* Test if 40MHz used */
-			  /**********************/
-
-							if (b_PCIInputClock ==
-								APCI1710_40MHZ)
-							{
-			     /*********************************/
-								/* Enable the 40MHz quarz (DQ31) */
-			     /*********************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									|
-									APCI1710_ENABLE_40MHZ_FILTER;
-
-							}	/*  if (b_PCIInputClock == APCI1710_40MHZ) */
-							else {
-			     /**********************************/
-								/* Disable the 40MHz quarz (DQ31) */
-			     /**********************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_SiemensCounterInfo.
-									s_ModeRegister.
-									s_ByteModeRegister.
-									b_ModeRegister4
-									&
-									APCI1710_DISABLE_40MHZ_FILTER;
-
-							}	/*  if (b_PCIInputClock == APCI1710_40MHZ) */
-
-			  /************************/
-							/* Set the filter value */
-			  /************************/
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_SiemensCounterInfo.
-								s_ModeRegister.
-								s_ByteModeRegister.
-								b_ModeRegister3
-								=
-								(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_SiemensCounterInfo.
-								s_ModeRegister.
-								s_ByteModeRegister.
-								b_ModeRegister3
-								& 0x1F) |
-								((b_Filter &
-									0x7) <<
-								5);
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_SiemensCounterInfo.
-								s_ModeRegister.
-								s_ByteModeRegister.
-								b_ModeRegister4
-								=
-								(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_SiemensCounterInfo.
-								s_ModeRegister.
-								s_ByteModeRegister.
-								b_ModeRegister4
-								& 0xFE) |
-								((b_Filter &
-									0x8) >>
-								3);
-
-			  /***************************/
-							/* Write the configuration */
-			  /***************************/
-
-							outl(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_SiemensCounterInfo.
-								s_ModeRegister.
-								dw_ModeRegister1_2_3_4,
-								devpriv->
-								s_BoardInfos.
-								ui_Address +
-								20 +
-								(64 * b_ModulNbr));
-						}	/*  if (i_ReturnValue == 0) */
-					}	/*  if (b_Filter < 16) */
-					else {
-		       /**************************************/
-						/* The selected filter value is wrong */
-		       /**************************************/
-
-						DPRINTK("The selected filter value is wrong\n");
-						i_ReturnValue = -5;
-					}	/*  if (b_Filter < 16) */
-				}	/*  if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */
-				else {
-		    /*****************************************/
-					/* The selected PCI input clock is wrong */
-		    /*****************************************/
-
-					DPRINTK("The selected PCI input clock is wrong\n");
-					i_ReturnValue = 4;
-				}	/*  if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */
-			} else {
-		 /**************************************/
-				/* The module is not a counter module */
-		 /**************************************/
-
-				DPRINTK("The module is not a counter module\n");
-				i_ReturnValue = -3;
-			}
-		} else {
-	      /**************************************/
-			/* The module is not a counter module */
-	      /**************************************/
-
-			DPRINTK("The module is not a counter module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_LatchCounter (unsigned char_ b_BoardHandle,    |
-|                                                    unsigned char_ b_ModulNbr,       |
-|                                                    unsigned char_ b_LatchReg)       |
-+----------------------------------------------------------------------------+
-| Task              : Latch the courant value from selected module           |
-|                     (b_ModulNbr) in to the selected latch register         |
-|                     (b_LatchReg).                                          |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Module number to configure       |
-|                                           (0 to 3)                         |
-|                     unsigned char_ b_LatchReg    : Selected latch register          |
-|                               0 : for the first latch register             |
-|                               1 : for the second latch register            |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: The selected latch register parameter is wrong     |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_LatchCounter(struct comedi_device *dev,
-				   unsigned char b_ModulNbr,
-				   unsigned char b_LatchReg)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*************************************/
-			/* Test the latch register parameter */
-	      /*************************************/
-
-			if (b_LatchReg < 2) {
-		 /*********************/
-				/* Tatch the counter */
-		 /*********************/
-
-				outl(1 << (b_LatchReg * 4),
-					devpriv->s_BoardInfos.ui_Address +
-					(64 * b_ModulNbr));
-			} else {
-		 /**************************************************/
-				/* The selected latch register parameter is wrong */
-		 /**************************************************/
-
-				DPRINTK("The selected latch register parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_	i_APCI1710_SetIndexAndReferenceSource        |
-|					(unsigned char_ b_BoardHandle,                |
-|					 unsigned char_ b_ModulNbr,                   |
-|					 unsigned char_ b_SourceSelection)            |
-+----------------------------------------------------------------------------+
-| Task              : Determine the hardware source for the index and the    |
-|		      reference logic. Per default the index logic is        |
-|		      connected to the difference input C and the reference  |
-|		      logic is connected to the 24V input E                  |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-|		      unsigned char_ b_SourceSelection : APCI1710_SOURCE_0 :          |
-|						The index logic is connected |
-|						to the difference input C and|
-|						the reference logic is       |
-|						connected to the 24V input E.|
-|						This is the default          |
-|						configuration.               |
-|						APCI1710_SOURCE_1 :          |
-|						The reference logic is       |
-|						connected to the difference  |
-|						input C and the index logic  |
-|						is connected to the 24V      |
-|						input E                      |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|		      -2: The selected module number is wrong                |
-|		      -3: The module is not a counter module.                |
-|		      -4: The source selection is wrong                      |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev,
-						 unsigned char b_ModulNbr,
-						 unsigned char b_SourceSelection)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if incremental counter */
-	   /*******************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
-	      /******************************/
-			/* Test if firmware >= Rev1.5 */
-	      /******************************/
-
-			if ((devpriv->s_BoardInfos.
-					dw_MolduleConfiguration[b_ModulNbr] &
-					0xFFFF) >= 0x3135) {
-		 /*****************************/
-				/* Test the source selection */
-		 /*****************************/
-
-				if (b_SourceSelection == APCI1710_SOURCE_0 ||
-					b_SourceSelection == APCI1710_SOURCE_1)
-				{
-		    /******************************************/
-					/* Test if invert the index and reference */
-		    /******************************************/
-
-					if (b_SourceSelection ==
-						APCI1710_SOURCE_1) {
-		       /********************************************/
-						/* Invert index and reference source (DQ25) */
-		       /********************************************/
-
-						devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SiemensCounterInfo.
-							s_ModeRegister.
-							s_ByteModeRegister.
-							b_ModeRegister4 =
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SiemensCounterInfo.
-							s_ModeRegister.
-							s_ByteModeRegister.
-							b_ModeRegister4 |
-							APCI1710_INVERT_INDEX_RFERENCE;
-					} else {
-		       /****************************************/
-						/* Set the default configuration (DQ25) */
-		       /****************************************/
-
-						devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SiemensCounterInfo.
-							s_ModeRegister.
-							s_ByteModeRegister.
-							b_ModeRegister4 =
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SiemensCounterInfo.
-							s_ModeRegister.
-							s_ByteModeRegister.
-							b_ModeRegister4 &
-							APCI1710_DEFAULT_INDEX_RFERENCE;
-					}
-				}	/*  if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */
-				else {
-		    /*********************************/
-					/* The source selection is wrong */
-		    /*********************************/
-
-					DPRINTK("The source selection is wrong\n");
-					i_ReturnValue = -4;
-				}	/*  if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */
-			} else {
-		 /**************************************/
-				/* The module is not a counter module */
-		 /**************************************/
-
-				DPRINTK("The module is not a counter module\n");
-				i_ReturnValue = -3;
-			}
-		} else {
-	      /**************************************/
-			/* The module is not a counter module */
-	      /**************************************/
-
-			DPRINTK("The module is not a counter module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***************************************/
-		/* The selected module number is wrong */
-	   /***************************************/
-
-		DPRINTK("The selected module number is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_	i_APCI1710_SetDigitalChlOn                   |
-|				   (unsigned char_  b_BoardHandle,                    |
-|				    unsigned char_  b_ModulNbr)                       |
-+----------------------------------------------------------------------------+
-| Task              : Sets the digital output H Setting an output means      |
-|		      setting an ouput high.                                 |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-|		      unsigned char_  b_ModulNbr	      :	Number of the module to be   |
-|						configured (0 to 3)          |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number is wrong                |
-|                     -3: Counter not initialised see function               |
-|			  "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev,
-				      unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-			devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.
-				b_ModeRegister3 = devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.b_ModeRegister3 | 0x10;
-
-	      /*********************/
-			/* Set the output On */
-	      /*********************/
-
-			outl(devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
-				ui_Address + 20 + (64 * b_ModulNbr));
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_	i_APCI1710_SetDigitalChlOff                  |
-|				   (unsigned char_  b_BoardHandle,                    |
-|				    unsigned char_  b_ModulNbr)                       |
-+----------------------------------------------------------------------------+
-| Task              : Resets the digital output H. Resetting an output means |
-|		      setting an ouput low.                                  |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-|		      unsigned char_  b_ModulNbr	      :	Number of the module to be   |
-|						configured (0 to 3)          |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: The selected module number is wrong                |
-|                     -3: Counter not initialised see function               |
-|			  "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev,
-				       unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-			devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.
-				b_ModeRegister3 = devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.b_ModeRegister3 & 0xEF;
-
-	      /**********************/
-			/* Set the output Off */
-	      /**********************/
-
-			outl(devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
-				ui_Address + 20 + (64 * b_ModulNbr));
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
- * Set & Clear Functions for INC_CPT
- */
-static int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev,
-				     struct comedi_subdevice *s,
-				     struct comedi_insn *insn,
-				     unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned int ui_BitsType;
-	int i_ReturnValue = 0;
-
-	ui_BitsType = CR_CHAN(insn->chanspec);
-	devpriv->tsk_Current = current;	/*  Save the current process task structure */
-
-	switch (ui_BitsType) {
-	case APCI1710_INCCPT_CLEARCOUNTERVALUE:
-		i_ReturnValue = i_APCI1710_ClearCounterValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_CLEARALLCOUNTERVALUE:
-		i_ReturnValue = i_APCI1710_ClearAllCounterValue(dev);
-		break;
-
-	case APCI1710_INCCPT_SETINPUTFILTER:
-		i_ReturnValue = i_APCI1710_SetInputFilter(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) data[0], (unsigned char) data[1]);
-		break;
-
-	case APCI1710_INCCPT_LATCHCOUNTER:
-		i_ReturnValue = i_APCI1710_LatchCounter(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
-		break;
-
-	case APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE:
-		i_ReturnValue = i_APCI1710_SetIndexAndReferenceSource(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
-		break;
-
-	case APCI1710_INCCPT_SETDIGITALCHLON:
-		i_ReturnValue = i_APCI1710_SetDigitalChlOn(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_SETDIGITALCHLOFF:
-		i_ReturnValue = i_APCI1710_SetDigitalChlOff(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	default:
-		printk("Bits Config Parameter Wrong\n");
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_EnableLatchInterrupt                  |
-|                               (unsigned char_ b_BoardHandle,                        |
-|                                unsigned char_ b_ModulNbr)                           |
-+----------------------------------------------------------------------------+
-| Task              : Enable the latch interrupt from selected module        |
-|                     (b_ModulNbr). Each software or hardware latch occur a  |
-|                     interrupt.                                             |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Module number to configure       |
-|                                           (0 to 3)                         |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Interrupt routine not installed see function       |
-|                         "i_APCI1710_SetBoardIntRoutine"                    |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev,
-					   unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-
-		 /********************/
-			/* Enable interrupt */
-		 /********************/
-
-			devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.
-				b_ModeRegister2 = devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.
-				b_ModeRegister2 | APCI1710_ENABLE_LATCH_INT;
-
-		 /***************************/
-			/* Write the configuration */
-		 /***************************/
-
-			outl(devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos.
-				ui_Address + 20 + (64 * b_ModulNbr));
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_DisableLatchInterrupt                 |
-|                               (unsigned char_ b_BoardHandle,                        |
-|                                unsigned char_ b_ModulNbr)                           |
-+----------------------------------------------------------------------------+
-| Task              : Disable the latch interrupt from selected module       |
-|                     (b_ModulNbr).                                          |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Module number to configure       |
-|                                           (0 to 3)                         |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Interrupt routine not installed see function       |
-|                         "i_APCI1710_SetBoardIntRoutine"                    |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev,
-					    unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-
-		 /***************************/
-			/* Write the configuration */
-		 /***************************/
-
-			outl(devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				dw_ModeRegister1_2_3_4 &
-				((APCI1710_DISABLE_LATCH_INT << 8) | 0xFF),
-				devpriv->s_BoardInfos.ui_Address + 20 +
-				(64 * b_ModulNbr));
-
-			mdelay(1000);
-
-		 /*********************/
-			/* Disable interrupt */
-		 /*********************/
-
-			devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.
-				b_ModeRegister2 = devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_ModeRegister.
-				s_ByteModeRegister.
-				b_ModeRegister2 & APCI1710_DISABLE_LATCH_INT;
-
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_Write16BitCounterValue                |
-|                                               (unsigned char_  b_BoardHandle        |
-|                                                unsigned char_  b_ModulNbr,          |
-|                                                unsigned char_  b_SelectedCounter,   |
-|                                                unsigned int_ ui_WriteValue)        |
-+----------------------------------------------------------------------------+
-| Task              : Write a 16-Bit value (ui_WriteValue) in to the selected|
-|                     16-Bit counter (b_SelectedCounter) from selected module|
-|                     (b_ModulNbr).                                          |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                              (0 to 3)                      |
-|                     unsigned char_ b_SelectedCounter : Selected 16-Bit counter      |
-|                                               (0 or 1)                     |
-|                     unsigned int_ ui_WriteValue     : 16-Bit write value           |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: The selected 16-Bit counter parameter is wrong     |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev,
-					     unsigned char b_ModulNbr,
-					     unsigned char b_SelectedCounter,
-					     unsigned int ui_WriteValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /******************************/
-			/* Test the counter selection */
-	      /******************************/
-
-			if (b_SelectedCounter < 2) {
-		 /*******************/
-				/* Write the value */
-		 /*******************/
-
-				outl((unsigned int) ((unsigned int) (ui_WriteValue) << (16 *
-							b_SelectedCounter)),
-					devpriv->s_BoardInfos.ui_Address + 8 +
-					(b_SelectedCounter * 4) +
-					(64 * b_ModulNbr));
-			} else {
-		 /**************************************************/
-				/* The selected 16-Bit counter parameter is wrong */
-		 /**************************************************/
-
-				DPRINTK("The selected 16-Bit counter parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_Write32BitCounterValue                |
-|                                               (unsigned char_   b_BoardHandle       |
-|                                                unsigned char_   b_ModulNbr,         |
-|                                                ULONG_ ul_WriteValue)       |
-+----------------------------------------------------------------------------+
-| Task              : Write a 32-Bit value (ui_WriteValue) in to the selected|
-|                     module (b_ModulNbr).                                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                              (0 to 3)                      |
-|                     ULONG_ ul_WriteValue    : 32-Bit write value           |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev,
-					     unsigned char b_ModulNbr,
-					     unsigned int ul_WriteValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*******************/
-			/* Write the value */
-	      /*******************/
-
-			outl(ul_WriteValue, devpriv->s_BoardInfos.
-				ui_Address + 4 + (64 * b_ModulNbr));
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_EnableIndex (unsigned char_  b_BoardHandle,    |
-|                                                   unsigned char_  b_ModulNbr)       |
-+----------------------------------------------------------------------------+
-| Task              : Enable the INDEX actions                               |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Index not initialised see function                 |
-|                         "i_APCI1710_InitIndex"                             |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnableIndex(struct comedi_device *dev,
-				  unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ul_InterruptLatchReg;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*****************************/
-			/* Test if index initialised */
-	      /*****************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister2 = devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister2 | APCI1710_ENABLE_INDEX;
-
-				ul_InterruptLatchReg =
-					inl(devpriv->s_BoardInfos.ui_Address +
-					24 + (64 * b_ModulNbr));
-
-				outl(devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					dw_ModeRegister1_2_3_4,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-			} else {
-		 /*************************************************************/
-				/* Index not initialised see function "i_APCI1710_InitIndex" */
-		 /*************************************************************/
-
-				DPRINTK("Index not initialised \n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_DisableIndex (unsigned char_  b_BoardHandle,   |
-|                                                    unsigned char_  b_ModulNbr)      |
-+----------------------------------------------------------------------------+
-| Task              : Disable the INDEX actions                              |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Index not initialised see function                 |
-|                         "i_APCI1710_InitIndex"                             |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisableIndex(struct comedi_device *dev,
-				   unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*****************************/
-			/* Test if index initialised */
-	      /*****************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister2 = devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister2 &
-					APCI1710_DISABLE_INDEX;
-
-				outl(devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					dw_ModeRegister1_2_3_4,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-			} else {
-		 /*************************************************************/
-				/* Index not initialised see function "i_APCI1710_InitIndex" */
-		 /*************************************************************/
-
-				DPRINTK("Index not initialised  \n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_EnableCompareLogic                    |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr)                         |
-+----------------------------------------------------------------------------+
-| Task              : Enable the 32-Bit compare logic. At that moment that   |
-|                     the incremental counter arrive to the compare value a  |
-|                     interrupt is generated.                                |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-|                     unsigned char_  b_ModulNbr       : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : -
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Compare logic not initialised.                     |
-|                         See function "i_APCI1710_InitCompareLogic"         |
-|                     -5: Interrupt function not initialised.                |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnableCompareLogic(struct comedi_device *dev,
-					 unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*************************************/
-			/* Test if compare logic initialised */
-	      /*************************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_CompareLogicInit == 1) {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister3 = devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister3 |
-					APCI1710_ENABLE_COMPARE_INT;
-
-		    /***************************/
-				/* Write the configuration */
-		    /***************************/
-
-				outl(devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					dw_ModeRegister1_2_3_4,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-			} else {
-		 /*********************************/
-				/* Compare logic not initialised */
-		 /*********************************/
-
-				DPRINTK("Compare logic not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_DisableCompareLogic                   |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr)                         |
-+----------------------------------------------------------------------------+
-| Task              : Disable the 32-Bit compare logic.
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-|                     unsigned char_  b_ModulNbr       : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : -
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Compare logic not initialised.                     |
-|                         See function "i_APCI1710_InitCompareLogic"         |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisableCompareLogic(struct comedi_device *dev,
-					  unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*************************************/
-			/* Test if compare logic initialised */
-	      /*************************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_CompareLogicInit == 1) {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister3 = devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister3 &
-					APCI1710_DISABLE_COMPARE_INT;
-
-		 /***************************/
-				/* Write the configuration */
-		 /***************************/
-
-				outl(devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					dw_ModeRegister1_2_3_4,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-			} else {
-		 /*********************************/
-				/* Compare logic not initialised */
-		 /*********************************/
-
-				DPRINTK("Compare logic not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-	/*
-	   +----------------------------------------------------------------------------+
-	   | Function Name     : _INT_ i_APCI1710_EnableFrequencyMeasurement            |
-	   |                            (unsigned char_   b_BoardHandle,                      |
-	   |                             unsigned char_   b_ModulNbr,                         |
-	   |                             unsigned char_   b_InterruptEnable)                  |
-	   +----------------------------------------------------------------------------+
-	   | Task              : Enables the frequency measurement function             |
-	   +----------------------------------------------------------------------------+
-	   | Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-	   |                  unsigned char_  b_ModulNbr       : Number of the module to be   |
-	   |                                            configured (0 to 3)          |
-	   |                  unsigned char_  b_InterruptEnable: Enable or disable the        |
-	   |                                            interrupt.                   |
-	   |                                            APCI1710_ENABLE:             |
-	   |                                            Enable the interrupt         |
-	   |                                            APCI1710_DISABLE:            |
-	   |                                            Disable the interrupt        |
-	   +----------------------------------------------------------------------------+
-	   | Output Parameters : -                                                      |
-	   +----------------------------------------------------------------------------+
-	   | Return Value      :  0: No error                                           |
-	   |                     -1: The handle parameter of the board is wrong         |
-	   |                     -2: The selected module number is wrong                |
-	   |                     -3: Counter not initialised see function               |
-	   |                      "i_APCI1710_InitCounter"                           |
-	   |                     -4: Frequency measurement logic not initialised.       |
-	   |                      See function "i_APCI1710_InitFrequencyMeasurement" |
-	   |                     -5: Interrupt parameter is wrong                       |
-	   |                     -6: Interrupt function not initialised.                |
-	   +----------------------------------------------------------------------------+
-	 */
-static int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev,
-						 unsigned char b_ModulNbr,
-						 unsigned char b_InterruptEnable)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /********************************************/
-			/* Test if frequency measurement initialised */
-	      /********************************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_FrequencyMeasurementInit == 1) {
-		 /***************************/
-				/* Test the interrupt mode */
-		 /***************************/
-
-				if ((b_InterruptEnable == APCI1710_DISABLE) ||
-					(b_InterruptEnable == APCI1710_ENABLE))
-				{
-
-		       /************************************/
-					/* Enable the frequency measurement */
-		       /************************************/
-
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister3 = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister3 |
-						APCI1710_ENABLE_FREQUENCY;
-
-		       /*********************************************/
-					/* Disable or enable the frequency interrupt */
-		       /*********************************************/
-
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister3 = (devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister3 &
-						APCI1710_DISABLE_FREQUENCY_INT)
-						| (b_InterruptEnable << 3);
-
-		       /***************************/
-					/* Write the configuration */
-		       /***************************/
-
-					outl(devpriv->s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						dw_ModeRegister1_2_3_4,
-						devpriv->s_BoardInfos.
-						ui_Address + 20 +
-						(64 * b_ModulNbr));
-
-					devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SiemensCounterInfo.
-						s_InitFlag.
-						b_FrequencyMeasurementEnable =
-						1;
-				} else {
-		    /********************************/
-					/* Interrupt parameter is wrong */
-		    /********************************/
-
-					DPRINTK("Interrupt parameter is wrong\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /***********************************************/
-				/* Frequency measurement logic not initialised */
-		 /***********************************************/
-
-				DPRINTK("Frequency measurement logic not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-	/*
-	   +----------------------------------------------------------------------------+
-	   | Function Name     : _INT_ i_APCI1710_DisableFrequencyMeasurement           |
-	   |                            (unsigned char_   b_BoardHandle,                      |
-	   |                             unsigned char_   b_ModulNbr)                         |
-	   +----------------------------------------------------------------------------+
-	   | Task              : Disables the frequency measurement function             |
-	   +----------------------------------------------------------------------------+
-	   | Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-	   |                  unsigned char_  b_ModulNbr       : Number of the module to be   |
-	   |                                            configured (0 to 3)          |
-	   +----------------------------------------------------------------------------+
-	   | Output Parameters : -                                                      |
-	   +----------------------------------------------------------------------------+
-	   | Return Value      :  0: No error                                           |
-	   |                     -1: The handle parameter of the board is wrong         |
-	   |                     -2: The selected module number is wrong                |
-	   |                     -3: Counter not initialised see function               |
-	   |                      "i_APCI1710_InitCounter"                           |
-	   |                     -4: Frequency measurement logic not initialised.       |
-	   |                      See function "i_APCI1710_InitFrequencyMeasurement" |
-	   +----------------------------------------------------------------------------+
-	 */
-static int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev,
-						  unsigned char b_ModulNbr)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /********************************************/
-			/* Test if frequency measurement initialised */
-	      /********************************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_FrequencyMeasurementInit == 1) {
-		 /*************************************/
-				/* Disable the frequency measurement */
-		 /*************************************/
-
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister3 = devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister3 &
-					APCI1710_DISABLE_FREQUENCY
-					/*  Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */
-					& APCI1710_DISABLE_FREQUENCY_INT;
-				/*  End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */
-
-		 /***************************/
-				/* Write the configuration */
-		 /***************************/
-
-				outl(devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					dw_ModeRegister1_2_3_4,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-
-		 /*************************************/
-				/* Disable the frequency measurement */
-		 /*************************************/
-
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_InitFlag.
-					b_FrequencyMeasurementEnable = 0;
-			} else {
-		 /***********************************************/
-				/* Frequency measurement logic not initialised */
-		 /***********************************************/
-
-				DPRINTK("Frequency measurement logic not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
- * Enable Disable functions for INC_CPT
- */
-static int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev,
-				      struct comedi_subdevice *s,
-				      struct comedi_insn *insn,
-				      unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned int ui_WriteType;
-	int i_ReturnValue = 0;
-
-	ui_WriteType = CR_CHAN(insn->chanspec);
-	devpriv->tsk_Current = current;	/*  Save the current process task structure */
-
-	switch (ui_WriteType) {
-	case APCI1710_INCCPT_ENABLELATCHINTERRUPT:
-		i_ReturnValue = i_APCI1710_EnableLatchInterrupt(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_DISABLELATCHINTERRUPT:
-		i_ReturnValue = i_APCI1710_DisableLatchInterrupt(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_WRITE16BITCOUNTERVALUE:
-		i_ReturnValue = i_APCI1710_Write16BitCounterValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) data[0], (unsigned int) data[1]);
-		break;
-
-	case APCI1710_INCCPT_WRITE32BITCOUNTERVALUE:
-		i_ReturnValue = i_APCI1710_Write32BitCounterValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned int) data[0]);
-
-		break;
-
-	case APCI1710_INCCPT_ENABLEINDEX:
-		i_APCI1710_EnableIndex(dev, (unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_DISABLEINDEX:
-		i_ReturnValue = i_APCI1710_DisableIndex(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_ENABLECOMPARELOGIC:
-		i_ReturnValue = i_APCI1710_EnableCompareLogic(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_DISABLECOMPARELOGIC:
-		i_ReturnValue = i_APCI1710_DisableCompareLogic(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	case APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT:
-		i_ReturnValue = i_APCI1710_EnableFrequencyMeasurement(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
-		break;
-
-	case APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT:
-		i_ReturnValue = i_APCI1710_DisableFrequencyMeasurement(dev,
-			(unsigned char) CR_AREF(insn->chanspec));
-		break;
-
-	default:
-		printk("Write Config Parameter Wrong\n");
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadLatchRegisterStatus               |
-|                                                   (unsigned char_   b_BoardHandle,  |
-|                                                    unsigned char_   b_ModulNbr,     |
-|                                                    unsigned char_   b_LatchReg,     |
-|                                                    unsigned char *_ pb_LatchStatus)  |
-+----------------------------------------------------------------------------+
-| Task              : Read the latch register status from selected module    |
-|                     (b_ModulNbr) and selected latch register (b_LatchReg). |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Module number to configure       |
-|                                           (0 to 3)                         |
-|                     unsigned char_ b_LatchReg    : Selected latch register          |
-|                               0 : for the first latch register             |
-|                               1 : for the second latch register            |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_LatchStatus :   Latch register status.       |
-|                                               0 : No latch occur           |
-|                                               1 : A software latch occur   |
-|                                               2 : A hardware latch occur   |
-|                                               3 : A software and hardware  |
-|                                                   latch occur              |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: The selected latch register parameter is wrong     |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev,
-					      unsigned char b_ModulNbr,
-					      unsigned char b_LatchReg,
-					      unsigned char *pb_LatchStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_LatchReg;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*************************************/
-			/* Test the latch register parameter */
-	      /*************************************/
-
-			if (b_LatchReg < 2) {
-				dw_LatchReg = inl(devpriv->s_BoardInfos.
-					ui_Address + (64 * b_ModulNbr));
-
-				*pb_LatchStatus =
-					(unsigned char) ((dw_LatchReg >> (b_LatchReg *
-							4)) & 0x3);
-			} else {
-		 /**************************************************/
-				/* The selected latch register parameter is wrong */
-		 /**************************************************/
-
-				DPRINTK("The selected latch register parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadLatchRegisterValue                |
-|                                                   (unsigned char_     b_BoardHandle,|
-|                                                    unsigned char_     b_ModulNbr,   |
-|                                                    unsigned char_     b_LatchReg,   |
-|                                                    PULONG_ pul_LatchValue) |
-+----------------------------------------------------------------------------+
-| Task              : Read the latch register value from selected module     |
-|                     (b_ModulNbr) and selected latch register (b_LatchReg). |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Module number to configure       |
-|                                           (0 to 3)                         |
-|                     unsigned char_ b_LatchReg    : Selected latch register          |
-|                               0 : for the first latch register             |
-|                               1 : for the second latch register            |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_ pul_LatchValue : Latch register value          |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: The selected latch register parameter is wrong     |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev,
-					     unsigned char b_ModulNbr,
-					     unsigned char b_LatchReg,
-					     unsigned int *pul_LatchValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*************************************/
-			/* Test the latch register parameter */
-	      /*************************************/
-
-			if (b_LatchReg < 2) {
-				*pul_LatchValue = inl(devpriv->s_BoardInfos.
-					ui_Address + ((b_LatchReg + 1) * 4) +
-					(64 * b_ModulNbr));
-
-			} else {
-		 /**************************************************/
-				/* The selected latch register parameter is wrong */
-		 /**************************************************/
-
-				DPRINTK("The selected latch register parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_Read16BitCounterValue                 |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_SelectedCounter,        |
-|                                        unsigned int *_   pui_CounterValue)          |
-+----------------------------------------------------------------------------+
-| Task              : Latch the selected 16-Bit counter (b_SelectedCounter)  |
-|                     from selected module (b_ModulNbr) in to the first      |
-|                     latch register and return the latched value.           |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                              (0 to 3)                      |
-|                     unsigned char_ b_SelectedCounter : Selected 16-Bit counter      |
-|                                               (0 or 1)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned int *_ pui_CounterValue : 16-Bit counter value         |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: The selected 16-Bit counter parameter is wrong     |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev,
-					    unsigned char b_ModulNbr,
-					    unsigned char b_SelectedCounter,
-					    unsigned int *pui_CounterValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_LathchValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /******************************/
-			/* Test the counter selection */
-	      /******************************/
-
-			if (b_SelectedCounter < 2) {
-		 /*********************/
-				/* Latch the counter */
-		 /*********************/
-
-				outl(1, devpriv->s_BoardInfos.
-					ui_Address + (64 * b_ModulNbr));
-
-		 /************************/
-				/* Read the latch value */
-		 /************************/
-
-				dw_LathchValue = inl(devpriv->s_BoardInfos.
-					ui_Address + 4 + (64 * b_ModulNbr));
-
-				*pui_CounterValue =
-					(unsigned int) ((dw_LathchValue >> (16 *
-							b_SelectedCounter)) &
-					0xFFFFU);
-			} else {
-		 /**************************************************/
-				/* The selected 16-Bit counter parameter is wrong */
-		 /**************************************************/
-
-				DPRINTK("The selected 16-Bit counter parameter is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_Read32BitCounterValue                 |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        PULONG_ pul_CounterValue)           |
-+----------------------------------------------------------------------------+
-| Task              : Latch the 32-Bit counter from selected module          |
-|                     (b_ModulNbr) in to the first latch register and return |
-|                     the latched value.                                     |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                              (0 to 3)                      |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pul_CounterValue : 32-Bit counter value       |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev,
-					    unsigned char b_ModulNbr,
-					    unsigned int *pul_CounterValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*********************/
-			/* Tatch the counter */
-	      /*********************/
-
-			outl(1, devpriv->s_BoardInfos.
-				ui_Address + (64 * b_ModulNbr));
-
-	      /************************/
-			/* Read the latch value */
-	      /************************/
-
-			*pul_CounterValue = inl(devpriv->s_BoardInfos.
-				ui_Address + 4 + (64 * b_ModulNbr));
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetIndexStatus (unsigned char_   b_BoardHandle,|
-|                                                      unsigned char_   b_ModulNbr,   |
-|                                                      unsigned char *_ pb_IndexStatus)|
-+----------------------------------------------------------------------------+
-| Task              : Return the index status                                |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_IndexStatus   : 0 : No INDEX occur           |
-|                                               1 : A INDEX occur            |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Index not initialised see function                 |
-|                         "i_APCI1710_InitIndex"                             |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetIndexStatus(struct comedi_device *dev,
-				     unsigned char b_ModulNbr,
-				     unsigned char *pb_IndexStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*****************************/
-			/* Test if index initialised */
-	      /*****************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.s_InitFlag.b_IndexInit) {
-				dw_StatusReg = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (64 * b_ModulNbr));
-
-				*pb_IndexStatus = (unsigned char) (dw_StatusReg & 1);
-			} else {
-		 /*************************************************************/
-				/* Index not initialised see function "i_APCI1710_InitIndex" */
-		 /*************************************************************/
-
-				DPRINTK("Index not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetReferenceStatus                    |
-|                                                (unsigned char_   b_BoardHandle,     |
-|                                                 unsigned char_   b_ModulNbr,        |
-|                                                 unsigned char *_ pb_ReferenceStatus) |
-+----------------------------------------------------------------------------+
-| Task              : Return the reference status                            |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_ReferenceStatus   : 0 : No REFERENCE occur   |
-|                                                   1 : A REFERENCE occur    |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Reference not initialised see function             |
-|                         "i_APCI1710_InitReference"                         |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetReferenceStatus(struct comedi_device *dev,
-					 unsigned char b_ModulNbr,
-					 unsigned char *pb_ReferenceStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*********************************/
-			/* Test if reference initialised */
-	      /*********************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_ReferenceInit) {
-				dw_StatusReg = inl(devpriv->s_BoardInfos.
-					ui_Address + 24 + (64 * b_ModulNbr));
-
-				*pb_ReferenceStatus =
-					(unsigned char) (~dw_StatusReg & 1);
-			} else {
-		 /*********************************************************************/
-				/* Reference not initialised see function "i_APCI1710_InitReference" */
-		 /*********************************************************************/
-
-				DPRINTK("Reference not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetUASStatus                          |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char *_ pb_UASStatus)                        |
-+----------------------------------------------------------------------------+
-| Task              : Return the error signal (UAS) status                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_UASStatus      : 0 : UAS is low "0"          |
-|                                                1 : UAS is high "1"         |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetUASStatus(struct comedi_device *dev,
-				   unsigned char b_ModulNbr,
-				   unsigned char *pb_UASStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-			dw_StatusReg = inl(devpriv->s_BoardInfos.
-				ui_Address + 24 + (64 * b_ModulNbr));
-
-			*pb_UASStatus = (unsigned char) ((dw_StatusReg >> 1) & 1);
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetCBStatus                           |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char *_ pb_CBStatus)                         |
-+----------------------------------------------------------------------------+
-| Task              : Return the counter overflow status                     |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_CBStatus      : 0 : Counter no overflow      |
-|                                               1 : Counter overflow         |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetCBStatus(struct comedi_device *dev,
-				  unsigned char b_ModulNbr,
-				  unsigned char *pb_CBStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-			dw_StatusReg = inl(devpriv->s_BoardInfos.
-				ui_Address + 16 + (64 * b_ModulNbr));
-
-			*pb_CBStatus = (unsigned char) (dw_StatusReg & 1);
-
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_Get16BitCBStatus                      |
-|					(unsigned char_     b_BoardHandle,            |
-|					 unsigned char_     b_ModulNbr,               |
-|					 unsigned char *_ pb_CBStatusCounter0,         |
-|					 unsigned char *_ pb_CBStatusCounter1)         |
-+----------------------------------------------------------------------------+
-| Task              : Returns the counter overflow (counter initialised to   |
-|		      2*16-bit) status from selected incremental counter     |
-|		      module                                                 |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_CBStatusCounter0 : 0 : No overflow occur for |
-|						       the first 16-bit      |
-|						       counter               |
-|						   1 : Overflow occur for the|
-|						       first 16-bit counter  |
-|		      unsigned char *_ pb_CBStatusCounter1 : 0 : No overflow occur for |
-|						       the second 16-bit     |
-|						       counter               |
-|						   1 : Overflow occur for the|
-|						       second 16-bit counter |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Counter not initialised to 2*16-bit mode.          |
-|			  See function "i_APCI1710_InitCounter"              |
-|                     -5: Firmware revision error                            |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev,
-				       unsigned char b_ModulNbr,
-				       unsigned char *pb_CBStatusCounter0,
-				       unsigned char *pb_CBStatusCounter1)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /*************************/
-			/* Test if 2*16-Bit mode */
-	      /*************************/
-
-			if ((devpriv->s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister1 & 0x10) == 0x10) {
-		 /*****************************/
-				/* Test the Firmware version */
-		 /*****************************/
-
-				if ((devpriv->s_BoardInfos.
-						dw_MolduleConfiguration
-						[b_ModulNbr] & 0xFFFF) >=
-					0x3136) {
-					dw_StatusReg =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 16 +
-						(64 * b_ModulNbr));
-
-					*pb_CBStatusCounter1 =
-						(unsigned char) ((dw_StatusReg >> 0) &
-						1);
-					*pb_CBStatusCounter0 =
-						(unsigned char) ((dw_StatusReg >> 1) &
-						1);
-				}	/*  if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */
-				else {
-		    /****************************/
-					/* Firmware revision error  */
-		    /****************************/
-
-					i_ReturnValue = -5;
-				}	/*  if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */
-			}	/*  if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */
-			else {
-		 /********************************************/
-				/* Counter not initialised to 2*16-bit mode */
-				/* "i_APCI1710_InitCounter"                 */
-		 /********************************************/
-
-				DPRINTK("Counter not initialised\n");
-				i_ReturnValue = -4;
-			}	/*  if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */
-		}		/*  if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */
-		else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}		/*  if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */
-	}			/*  if (b_ModulNbr < 4) */
-	else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}			/*  if (b_ModulNbr < 4) */
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetUDStatus                           |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char *_ pb_UDStatus)                         |
-+----------------------------------------------------------------------------+
-| Task              : Return the counter progress status                     |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_UDStatus      : 0 : Counter progress in the  |
-|                                                   selected mode down       |
-|                                               1 : Counter progress in the  |
-|                                                   selected mode up         |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetUDStatus(struct comedi_device *dev,
-				  unsigned char b_ModulNbr,
-				  unsigned char *pb_UDStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-			dw_StatusReg = inl(devpriv->s_BoardInfos.
-				ui_Address + 24 + (64 * b_ModulNbr));
-
-			*pb_UDStatus = (unsigned char) ((dw_StatusReg >> 2) & 1);
-
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetInterruptUDLatchedStatus           |
-|                               (unsigned char_   b_BoardHandle,                      |
-|                                unsigned char_   b_ModulNbr,                         |
-|                                unsigned char *_ pb_UDStatus)                         |
-+----------------------------------------------------------------------------+
-| Task              : Return the counter progress latched status after a     |
-|                     index interrupt occur.                                 |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Module number to configure   |
-|                                               (0 to 3)                     |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_UDStatus      : 0 : Counter progress in the  |
-|                                                   selected mode down       |
-|                                               1 : Counter progress in the  |
-|                                                   selected mode up         |
-|                                               2 : No index interrupt occur |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: No counter module found                            |
-|                     -3: Counter not initialised see function               |
-|                         "i_APCI1710_InitCounter"                           |
-|                     -4: Interrupt function not initialised.                |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev,
-						  unsigned char b_ModulNbr,
-						  unsigned char *pb_UDStatus)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-		 /*********************************/
-			/* Test if index interrupt occur */
-		 /*********************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_IndexInterruptOccur == 1) {
-				devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_InitFlag.b_IndexInterruptOccur = 0;
-
-				dw_StatusReg = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (64 * b_ModulNbr));
-
-				*pb_UDStatus = (unsigned char) ((dw_StatusReg >> 1) & 1);
-			} else {
-		    /****************************/
-				/* No index interrupt occur */
-		    /****************************/
-
-				*pb_UDStatus = 2;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-	/*
-	   +----------------------------------------------------------------------------+
-	   | Function Name     : _INT_ i_APCI1710_ReadFrequencyMeasurement              |
-	   |                            (unsigned char_            b_BoardHandle,             |
-	   |                             unsigned char_            b_ModulNbr,                |
-	   |                             unsigned char *_          pb_Status,                  |
-	   |                             PULONG_        pul_ReadValue)               |
-	   +----------------------------------------------------------------------------+
-	   | Task              : Returns the status (pb_Status) and the number of       |
-	   |                  increments in the set time.                            |
-	   |                  See function " i_APCI1710_InitFrequencyMeasurement "   |
-	   +----------------------------------------------------------------------------+
-	   | Input Parameters  : unsigned char_  b_BoardHandle    : Handle of board APCI-1710    |
-	   |                  unsigned char_  b_ModulNbr       : Number of the module to be   |
-	   |                                            configured (0 to 3)          |
-	   +----------------------------------------------------------------------------+
-	   | Output Parameters : unsigned char *_ pb_Status     : Returns the frequency        |
-	   |                                            measurement status           |
-	   |                                            0 : Counting cycle not       |
-	   |                                                started.                 |
-	   |                                            1 : Counting cycle started.  |
-	   |                                            2 : Counting cycle stopped.  |
-	   |                                                The measurement cycle is |
-	   |                                                completed.               |
-	   |                  unsigned char *_ pb_UDStatus      : 0 : Counter progress in the  |
-	   |                                                   selected mode down       |
-	   |                                               1 : Counter progress in the  |
-	   |                                                   selected mode up         |
-	   |                  PULONG_ pul_ReadValue   : Return the number of         |
-	   |                                            increments in the defined    |
-	   |                                            time base.                   |
-	   +----------------------------------------------------------------------------+
-	   | Return Value      :  0: No error                                           |
-	   |                     -1: The handle parameter of the board is wrong         |
-	   |                     -2: The selected module number is wrong                |
-	   |                     -3: Counter not initialised see function               |
-	   |                      "i_APCI1710_InitCounter"                           |
-	   |                     -4: Frequency measurement logic not initialised.       |
-	   |                      See function "i_APCI1710_InitFrequencyMeasurement" |
-	   +----------------------------------------------------------------------------+
-	 */
-static int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev,
-					       unsigned char b_ModulNbr,
-					       unsigned char *pb_Status,
-					       unsigned char *pb_UDStatus,
-					       unsigned int *pul_ReadValue)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ui_16BitValue;
-	unsigned int dw_StatusReg;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /*******************************/
-		/* Test if counter initialised */
-	   /*******************************/
-
-		if (devpriv->
-			s_ModuleInfo[b_ModulNbr].
-			s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) {
-	      /********************************************/
-			/* Test if frequency measurement initialised */
-	      /********************************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_SiemensCounterInfo.
-				s_InitFlag.b_FrequencyMeasurementInit == 1) {
-		 /******************/
-				/* Test if enable */
-		 /******************/
-
-				if (devpriv->
-					s_ModuleInfo[b_ModulNbr].
-					s_SiemensCounterInfo.
-					s_InitFlag.
-					b_FrequencyMeasurementEnable == 1) {
-		    /*******************/
-					/* Read the status */
-		    /*******************/
-
-					dw_StatusReg =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 32 +
-						(64 * b_ModulNbr));
-
-		    /**************************/
-					/* Test if frequency stop */
-		    /**************************/
-
-					if (dw_StatusReg & 1) {
-						*pb_Status = 2;
-						*pb_UDStatus =
-							(unsigned char) ((dw_StatusReg >>
-								1) & 3);
-
-		       /******************/
-						/* Read the value */
-		       /******************/
-
-						*pul_ReadValue =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 28 +
-							(64 * b_ModulNbr));
-
-						if (*pb_UDStatus == 0) {
-			  /*************************/
-							/* Test the counter mode */
-			  /*************************/
-
-							if ((devpriv->s_ModuleInfo[b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & APCI1710_16BIT_COUNTER) == APCI1710_16BIT_COUNTER) {
-			     /****************************************/
-								/* Test if 16-bit counter 1 pulse occur */
-			     /****************************************/
-
-								if ((*pul_ReadValue & 0xFFFFU) != 0) {
-									ui_16BitValue
-										=
-										(unsigned int)
-										*
-										pul_ReadValue
-										&
-										0xFFFFU;
-									*pul_ReadValue
-										=
-										(*pul_ReadValue
-										&
-										0xFFFF0000UL)
-										|
-										(0xFFFFU
-										-
-										ui_16BitValue);
-								}
-
-			     /****************************************/
-								/* Test if 16-bit counter 2 pulse occur */
-			     /****************************************/
-
-								if ((*pul_ReadValue & 0xFFFF0000UL) != 0) {
-									ui_16BitValue
-										=
-										(unsigned int)
-										(
-										(*pul_ReadValue
-											>>
-											16)
-										&
-										0xFFFFU);
-									*pul_ReadValue
-										=
-										(*pul_ReadValue
-										&
-										0xFFFFUL)
-										|
-										(
-										(0xFFFFU - ui_16BitValue) << 16);
-								}
-							} else {
-								if (*pul_ReadValue != 0) {
-									*pul_ReadValue
-										=
-										0xFFFFFFFFUL
-										-
-										*pul_ReadValue;
-								}
-							}
-						} else {
-							if (*pb_UDStatus == 1) {
-			     /****************************************/
-								/* Test if 16-bit counter 2 pulse occur */
-			     /****************************************/
-
-								if ((*pul_ReadValue & 0xFFFF0000UL) != 0) {
-									ui_16BitValue
-										=
-										(unsigned int)
-										(
-										(*pul_ReadValue
-											>>
-											16)
-										&
-										0xFFFFU);
-									*pul_ReadValue
-										=
-										(*pul_ReadValue
-										&
-										0xFFFFUL)
-										|
-										(
-										(0xFFFFU - ui_16BitValue) << 16);
-								}
-							} else {
-								if (*pb_UDStatus
-									== 2) {
-				/****************************************/
-									/* Test if 16-bit counter 1 pulse occur */
-				/****************************************/
-
-									if ((*pul_ReadValue & 0xFFFFU) != 0) {
-										ui_16BitValue
-											=
-											(unsigned int)
-											*
-											pul_ReadValue
-											&
-											0xFFFFU;
-										*pul_ReadValue
-											=
-											(*pul_ReadValue
-											&
-											0xFFFF0000UL)
-											|
-											(0xFFFFU
-											-
-											ui_16BitValue);
-									}
-								}
-							}
-						}
-					} else {
-						*pb_Status = 1;
-						*pb_UDStatus = 0;
-					}
-				} else {
-					*pb_Status = 0;
-					*pb_UDStatus = 0;
-				}
-			} else {
-		 /***********************************************/
-				/* Frequency measurement logic not initialised */
-		 /***********************************************/
-
-				DPRINTK("Frequency measurement logic not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /****************************************/
-			/* Counter not initialised see function */
-			/* "i_APCI1710_InitCounter"             */
-	      /****************************************/
-
-			DPRINTK("Counter not initialised\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*************************************************/
-		/* The selected module number parameter is wrong */
-	   /*************************************************/
-
-		DPRINTK("The selected module number parameter is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-/*
- * Read and Get functions for INC_CPT
- */
-static int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev,
-				     struct comedi_subdevice *s,
-				     struct comedi_insn *insn,
-				     unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned int ui_ReadType;
-	int i_ReturnValue = 0;
-
-	ui_ReadType = CR_CHAN(insn->chanspec);
-
-	devpriv->tsk_Current = current;	/*  Save the current process task structure */
-	switch (ui_ReadType) {
-	case APCI1710_INCCPT_READLATCHREGISTERSTATUS:
-		i_ReturnValue = i_APCI1710_ReadLatchRegisterStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) CR_RANGE(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_READLATCHREGISTERVALUE:
-		i_ReturnValue = i_APCI1710_ReadLatchRegisterValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]);
-		printk("Latch Register Value %d\n", data[0]);
-		break;
-
-	case APCI1710_INCCPT_READ16BITCOUNTERVALUE:
-		i_ReturnValue = i_APCI1710_Read16BitCounterValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_READ32BITCOUNTERVALUE:
-		i_ReturnValue = i_APCI1710_Read32BitCounterValue(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned int *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_GETINDEXSTATUS:
-		i_ReturnValue = i_APCI1710_GetIndexStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_GETREFERENCESTATUS:
-		i_ReturnValue = i_APCI1710_GetReferenceStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_GETUASSTATUS:
-		i_ReturnValue = i_APCI1710_GetUASStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_GETCBSTATUS:
-		i_ReturnValue = i_APCI1710_GetCBStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_GET16BITCBSTATUS:
-		i_ReturnValue = i_APCI1710_Get16BitCBStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char *) &data[0], (unsigned char *) &data[1]);
-		break;
-
-	case APCI1710_INCCPT_GETUDSTATUS:
-		i_ReturnValue = i_APCI1710_GetUDStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-
-		break;
-
-	case APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS:
-		i_ReturnValue = i_APCI1710_GetInterruptUDLatchedStatus(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]);
-		break;
-
-	case APCI1710_INCCPT_READFREQUENCYMEASUREMENT:
-		i_ReturnValue = i_APCI1710_ReadFrequencyMeasurement(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char *) &data[0],
-			(unsigned char *) &data[1], (unsigned int *) &data[2]);
-		break;
-
-	case APCI1710_INCCPT_READINTERRUPT:
-		data[0] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].b_OldModuleMask;
-		data[1] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].ul_OldInterruptMask;
-		data[2] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
-		/**************************/
-		/* Increment the read FIFO */
-		/***************************/
-
-		devpriv->
-			s_InterruptParameters.
-			ui_Read = (devpriv->s_InterruptParameters.
-			ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
-		break;
-
-	default:
-		printk("ReadType Parameter wrong\n");
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
deleted file mode 100644
index 6bbcb06..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c
+++ /dev/null
@@ -1,866 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : Inp_CPT.C       | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 pulse encoder module                        |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  |          |           |                                                |
-  |----------|-----------|------------------------------------------------|
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_SINGLE			0
-#define APCI1710_CONTINUOUS		1
-
-#define APCI1710_PULSEENCODER_READ	0
-#define APCI1710_PULSEENCODER_WRITE	1
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitPulseEncoder                      |
-|                               (unsigned char_          b_BoardHandle,               |
-|                                unsigned char_          b_ModulNbr,                  |
-|                                unsigned char_          b_PulseEncoderNbr,           |
-|                                unsigned char_          b_InputLevelSelection,       |
-|                                unsigned char_          b_TriggerOutputAction,       |
-|                                ULONG_        ul_StartValue)                |
-+----------------------------------------------------------------------------+
-| Task              : Configure the pulse encoder operating mode selected via|
-|                     b_ModulNbr and b_PulseEncoderNbr. The pulse encoder    |
-|                     after each pulse decrement the counter value from 1.   |
-|                                                                            |
-|                     You must calling this function be for you call any     |
-|                     other function witch access of pulse encoders.         |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 3)       |
-|                     unsigned char_ b_PulseEncoderNbr     : Pulse encoder selection  |
-|                                                   (0 to 3)                 |
-|                     unsigned char_ b_InputLevelSelection : Input level selection    |
-|                                                   (0 or 1)                 |
-|                                                       0 : Set pulse encoder|
-|                                                           count the the low|
-|                                                           level pulse.     |
-|                                                       1 : Set pulse encoder|
-|                                                           count the the    |
-|                                                           high level pulse.|
-|                     unsigned char_ b_TriggerOutputAction : Digital TRIGGER output   |
-|                                                   action                   |
-|                                                       0 : No action        |
-|                                                       1 : Set the trigger  |
-|                                                           output to "1"    |
-|                                                           (high) after the |
-|                                                           passage from 1 to|
-|                                                           0 from pulse     |
-|                                                           encoder.         |
-|                                                       2 : Set the trigger  |
-|                                                           output to "0"    |
-|                                                           (low) after the  |
-|                                                           passage from 1 to|
-|                                                           0 from pulse     |
-|                                                           encoder          |
-|                     ULONG_ ul_StartValue        : Pulse encoder start value|
-|                                                   (1 to 4294967295)
-	b_ModulNbr				=(unsigned char) CR_AREF(insn->chanspec);
-	b_PulseEncoderNbr		=(unsigned char) data[0];
-	b_InputLevelSelection	=(unsigned char) data[1];
-	b_TriggerOutputAction	=(unsigned char) data[2];
-	ul_StartValue			=(unsigned int) data[3];
-       |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module is not a pulse encoder module            |
-|                    -3: Pulse encoder selection is wrong                    |
-|                    -4: Input level selection is wrong                      |
-|                    -5: Digital TRIGGER output action selection is wrong    |
-|                    -6: Pulse encoder start value is wrong                  |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev,
-						 struct comedi_subdevice *s,
-						 struct comedi_insn *insn,
-						 unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_IntRegister;
-	unsigned char b_ModulNbr;
-	unsigned char b_PulseEncoderNbr;
-	unsigned char b_InputLevelSelection;
-	unsigned char b_TriggerOutputAction;
-	unsigned int ul_StartValue;
-
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_PulseEncoderNbr = (unsigned char) data[0];
-	b_InputLevelSelection = (unsigned char) data[1];
-	b_TriggerOutputAction = (unsigned char) data[2];
-	ul_StartValue = (unsigned int) data[3];
-
-	i_ReturnValue = insn->n;
-
-	/***********************************/
-	/* Test the selected module number */
-	/***********************************/
-
-	if (b_ModulNbr <= 3) {
-	   /*************************/
-		/* Test if pulse encoder */
-	   /*************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				APCI1710_PULSE_ENCODER) ==
-			APCI1710_PULSE_ENCODER) {
-	      /******************************************/
-			/* Test the selected pulse encoder number */
-	      /******************************************/
-
-			if (b_PulseEncoderNbr <= 3) {
-		 /************************/
-				/* Test the input level */
-		 /************************/
-
-				if ((b_InputLevelSelection == 0)
-					|| (b_InputLevelSelection == 1)) {
-		    /*******************************************/
-					/* Test the ouput TRIGGER action selection */
-		    /*******************************************/
-
-					if ((b_TriggerOutputAction <= 2)
-						|| (b_PulseEncoderNbr > 0)) {
-						if (ul_StartValue > 1) {
-
-							dw_IntRegister =
-								inl(devpriv->
-								s_BoardInfos.
-								ui_Address +
-								20 +
-								(64 * b_ModulNbr));
-
-			  /***********************/
-							/* Set the start value */
-			  /***********************/
-
-							outl(ul_StartValue,
-								devpriv->
-								s_BoardInfos.
-								ui_Address +
-								(b_PulseEncoderNbr
-									* 4) +
-								(64 * b_ModulNbr));
-
-			  /***********************/
-							/* Set the input level */
-			  /***********************/
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_PulseEncoderModuleInfo.
-								dw_SetRegister =
-								(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_PulseEncoderModuleInfo.
-								dw_SetRegister &
-								(0xFFFFFFFFUL -
-									(1UL << (8 + b_PulseEncoderNbr)))) | ((1UL & (~b_InputLevelSelection)) << (8 + b_PulseEncoderNbr));
-
-			  /*******************************/
-							/* Test if output trigger used */
-			  /*******************************/
-
-							if ((b_TriggerOutputAction > 0) && (b_PulseEncoderNbr > 1)) {
-			     /****************************/
-								/* Enable the output action */
-			     /****************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									| (1UL
-									<< (4 + b_PulseEncoderNbr));
-
-			     /*********************************/
-								/* Set the output TRIGGER action */
-			     /*********************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									=
-									(devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									&
-									(0xFFFFFFFFUL
-										-
-										(1UL << (12 + b_PulseEncoderNbr)))) | ((1UL & (b_TriggerOutputAction - 1)) << (12 + b_PulseEncoderNbr));
-							} else {
-			     /*****************************/
-								/* Disable the output action */
-			     /*****************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									&
-									(0xFFFFFFFFUL
-									-
-									(1UL << (4 + b_PulseEncoderNbr)));
-							}
-
-			  /*************************/
-							/* Set the configuration */
-			  /*************************/
-
-							outl(devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_PulseEncoderModuleInfo.
-								dw_SetRegister,
-								devpriv->
-								s_BoardInfos.
-								ui_Address +
-								20 +
-								(64 * b_ModulNbr));
-
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_PulseEncoderModuleInfo.
-								s_PulseEncoderInfo
-								[b_PulseEncoderNbr].
-								b_PulseEncoderInit
-								= 1;
-						} else {
-			  /**************************************/
-							/* Pulse encoder start value is wrong */
-			  /**************************************/
-
-							DPRINTK("Pulse encoder start value is wrong\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-		       /****************************************************/
-						/* Digital TRIGGER output action selection is wrong */
-		       /****************************************************/
-
-						DPRINTK("Digital TRIGGER output action selection is wrong\n");
-						i_ReturnValue = -5;
-					}
-				} else {
-		    /**********************************/
-					/* Input level selection is wrong */
-		    /**********************************/
-
-					DPRINTK("Input level selection is wrong\n");
-					i_ReturnValue = -4;
-				}
-			} else {
-		 /************************************/
-				/* Pulse encoder selection is wrong */
-		 /************************************/
-
-				DPRINTK("Pulse encoder selection is wrong\n");
-				i_ReturnValue = -3;
-			}
-		} else {
-	      /********************************************/
-			/* The module is not a pulse encoder module */
-	      /********************************************/
-
-			DPRINTK("The module is not a pulse encoder module\n");
-			i_ReturnValue = -2;
-		}
-	} else {
-	   /********************************************/
-		/* The module is not a pulse encoder module */
-	   /********************************************/
-
-		DPRINTK("The module is not a pulse encoder module\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_EnablePulseEncoder                    |
-|                                       (unsigned char_  b_BoardHandle,               |
-|                                        unsigned char_  b_ModulNbr,                  |
-|                                        unsigned char_  b_PulseEncoderNbr,           |
-|                                        unsigned char_  b_CycleSelection,            |
-|                                        unsigned char_  b_InterruptHandling)         |
-+----------------------------------------------------------------------------+
-| Task              : Enableor disable  the selected pulse encoder (b_PulseEncoderNbr)  |
-|                     from selected module (b_ModulNbr). Each input pulse    |
-|                     decrement the pulse encoder counter value from 1.      |
-|                     If you enabled the interrupt (b_InterruptHandling), a  |
-|                     interrupt is generated when the pulse encoder has run  |
-|                     down.                                                  |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_   b_BoardHandle       : Handle of board APCI-1710|
-|                     unsigned char_   b_ModulNbr          : Module number to         |
-|                                                   configure (0 to 3)       |
-|                     unsigned char_   b_PulseEncoderNbr   : Pulse encoder selection  |
-|                                                   (0 to 3)                 |
-|                     unsigned char_   b_CycleSelection    : APCI1710_CONTINUOUS:     |
-|                                                       Each time the        |
-|                                                       counting value is set|
-|                                                       on "0", the pulse    |
-|                                                       encoder load the     |
-|                                                       start value after    |
-|                                                       the next pulse.      |
-|                                                   APCI1710_SINGLE:         |
-|                                                       If the counter is set|
-|                                                       on "0", the pulse    |
-|                                                       encoder is stopped.  |
-|                     unsigned char_   b_InterruptHandling : Interrupts can be        |
-|                                                   generated, when the pulse|
-|                                                   encoder has run down.    |
-|                                                   With this parameter the  |
-|                                                   user decides if          |
-|                                                   interrupts are used or   |
-|                                                   not.                     |
-|                                                     APCI1710_ENABLE:       |
-|                                                     Interrupts are enabled |
-|                                                     APCI1710_DISABLE:      |
-|                                                     Interrupts are disabled
-
-	b_ModulNbr			=(unsigned char) CR_AREF(insn->chanspec);
-	b_Action			=(unsigned char) data[0];
-	b_PulseEncoderNbr	=(unsigned char) data[1];
-	b_CycleSelection	=(unsigned char) data[2];
-	b_InterruptHandling	=(unsigned char) data[3];|
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection is wrong                          |
-|                     -3: Pulse encoder selection is wrong                   |
-|                     -4: Pulse encoder not initialised.                     |
-|                         See function "i_APCI1710_InitPulseEncoder"         |
-|                     -5: Cycle selection mode is wrong                      |
-|                     -6: Interrupt handling mode is wrong                   |
-|                     -7: Interrupt routine not installed.                   |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev,
-							 struct comedi_subdevice *s,
-							 struct comedi_insn *insn,
-							 unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_ModulNbr;
-	unsigned char b_PulseEncoderNbr;
-	unsigned char b_CycleSelection;
-	unsigned char b_InterruptHandling;
-	unsigned char b_Action;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_Action = (unsigned char) data[0];
-	b_PulseEncoderNbr = (unsigned char) data[1];
-	b_CycleSelection = (unsigned char) data[2];
-	b_InterruptHandling = (unsigned char) data[3];
-
-	/***********************************/
-	/* Test the selected module number */
-	/***********************************/
-
-	if (b_ModulNbr <= 3) {
-	   /******************************************/
-		/* Test the selected pulse encoder number */
-	   /******************************************/
-
-		if (b_PulseEncoderNbr <= 3) {
-	      /*************************************/
-			/* Test if pulse encoder initialised */
-	      /*************************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_PulseEncoderModuleInfo.
-				s_PulseEncoderInfo[b_PulseEncoderNbr].
-				b_PulseEncoderInit == 1) {
-				switch (b_Action) {
-
-				case APCI1710_ENABLE:
-		 /****************************/
-					/* Test the cycle selection */
-		 /****************************/
-
-					if (b_CycleSelection ==
-						APCI1710_CONTINUOUS
-						|| b_CycleSelection ==
-						APCI1710_SINGLE) {
-		    /*******************************/
-						/* Test the interrupt handling */
-		    /*******************************/
-
-						if (b_InterruptHandling ==
-							APCI1710_ENABLE
-							|| b_InterruptHandling
-							== APCI1710_DISABLE) {
-		       /******************************/
-							/* Test if interrupt not used */
-		       /******************************/
-
-							if (b_InterruptHandling
-								==
-								APCI1710_DISABLE)
-							{
-			  /*************************/
-								/* Disable the interrupt */
-			  /*************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									&
-									(0xFFFFFFFFUL
-									-
-									(1UL << b_PulseEncoderNbr));
-							} else {
-
-			     /************************/
-								/* Enable the interrupt */
-			     /************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister
-									| (1UL
-									<<
-									b_PulseEncoderNbr);
-								devpriv->tsk_Current = current;	/*  Save the current process task structure */
-
-							}
-
-							if (i_ReturnValue >= 0) {
-			  /***********************************/
-								/* Enable or disable the interrupt */
-			  /***********************************/
-
-								outl(devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_SetRegister,
-									devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 20 +
-									(64 * b_ModulNbr));
-
-			  /****************************/
-								/* Enable the pulse encoder */
-			  /****************************/
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_ControlRegister
-									=
-									devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_ControlRegister
-									| (1UL
-									<<
-									b_PulseEncoderNbr);
-
-			  /**********************/
-								/* Set the cycle mode */
-			  /**********************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_ControlRegister
-									=
-									(devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_ControlRegister
-									&
-									(0xFFFFFFFFUL
-										-
-										(1 << (b_PulseEncoderNbr + 4)))) | ((b_CycleSelection & 1UL) << (4 + b_PulseEncoderNbr));
-
-			  /****************************/
-								/* Enable the pulse encoder */
-			  /****************************/
-
-								outl(devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PulseEncoderModuleInfo.
-									dw_ControlRegister,
-									devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 16 +
-									(64 * b_ModulNbr));
-							}
-						} else {
-		       /************************************/
-							/* Interrupt handling mode is wrong */
-		       /************************************/
-
-							DPRINTK("Interrupt handling mode is wrong\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-		    /*********************************/
-						/* Cycle selection mode is wrong */
-		    /*********************************/
-
-						DPRINTK("Cycle selection mode is wrong\n");
-						i_ReturnValue = -5;
-					}
-					break;
-
-				case APCI1710_DISABLE:
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_ControlRegister =
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_ControlRegister &
-						(0xFFFFFFFFUL -
-						(1UL << b_PulseEncoderNbr));
-
-		 /*****************************/
-					/* Disable the pulse encoder */
-		 /*****************************/
-
-					outl(devpriv->s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_ControlRegister,
-						devpriv->s_BoardInfos.
-						ui_Address + 16 +
-						(64 * b_ModulNbr));
-
-					break;
-				}	/*  switch End */
-
-			} else {
-		 /*********************************/
-				/* Pulse encoder not initialised */
-		 /*********************************/
-
-				DPRINTK("Pulse encoder not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /************************************/
-			/* Pulse encoder selection is wrong */
-	      /************************************/
-
-			DPRINTK("Pulse encoder selection is wrong\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*****************************/
-		/* Module selection is wrong */
-	   /*****************************/
-
-		DPRINTK("Module selection is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadPulseEncoderStatus                |
-|                                       (unsigned char_  b_BoardHandle,               |
-|                                        unsigned char_  b_ModulNbr,                  |
-|                                        unsigned char_  b_PulseEncoderNbr,           |
-|                                        unsigned char *_ pb_Status)                   |
-+----------------------------------------------------------------------------+
-| Task    APCI1710_PULSEENCODER_READ          : Reads the pulse encoder status
-											and valuefrom selected pulse     |
-|                     encoder (b_PulseEncoderNbr) from selected module       |
-|                     (b_ModulNbr).                                          |
-+----------------------------------------------------------------------------+
-	unsigned char   b_Type; data[0]
-   APCI1710_PULSEENCODER_WRITE
- Writes a 32-bit value (ul_WriteValue) into the selected|
-|                     pulse encoder (b_PulseEncoderNbr) from selected module |
-|                     (b_ModulNbr). This operation set the new start pulse   |
-|                     encoder value.
- APCI1710_PULSEENCODER_READ
-| Input Parameters  : unsigned char_   b_BoardHandle       : Handle of board APCI-1710|
-|            CRAREF()         unsigned char_   b_ModulNbr          : Module number to         |
-|                                                   configure (0 to 3)       |
-|              data[1]       unsigned char_   b_PulseEncoderNbr   : Pulse encoder selection  |
-|                                                   (0 to 3)
-   APCI1710_PULSEENCODER_WRITE
-				data[2]		ULONG_ ul_WriteValue        : 32-bit value to be       |
-|                                                   written             |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_ pb_Status            : Pulse encoder status.    |
-|                                                       0 : No overflow occur|
-|                                                       1 : Overflow occur
-						PULONG_ pul_ReadValue       : Pulse encoder value      |  |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection is wrong                          |
-|                     -3: Pulse encoder selection is wrong                   |
-|                     -4: Pulse encoder not initialised.                     |
-|                         See function "i_APCI1710_InitPulseEncoder"         |
-+----------------------------------------------------------------------------+
-*/
-
-/*_INT_   i_APCI1710_ReadPulseEncoderStatus       (unsigned char_   b_BoardHandle,
-						 unsigned char_   b_ModulNbr,
-						 unsigned char_   b_PulseEncoderNbr,
-
-						 unsigned char *_ pb_Status)
-						 */
-static int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev,
-						    struct comedi_subdevice *s,
-						    struct comedi_insn *insn,
-						    unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusRegister;
-	unsigned char b_ModulNbr;
-	unsigned char b_PulseEncoderNbr;
-	unsigned char *pb_Status;
-	unsigned char b_Type;
-	unsigned int *pul_ReadValue;
-	unsigned int ul_WriteValue;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_Type = (unsigned char) data[0];
-	b_PulseEncoderNbr = (unsigned char) data[1];
-	pb_Status = (unsigned char *) &data[0];
-	pul_ReadValue = (unsigned int *) &data[1];
-
-	/***********************************/
-	/* Test the selected module number */
-	/***********************************/
-
-	if (b_ModulNbr <= 3) {
-	   /******************************************/
-		/* Test the selected pulse encoder number */
-	   /******************************************/
-
-		if (b_PulseEncoderNbr <= 3) {
-	      /*************************************/
-			/* Test if pulse encoder initialised */
-	      /*************************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_PulseEncoderModuleInfo.
-				s_PulseEncoderInfo[b_PulseEncoderNbr].
-				b_PulseEncoderInit == 1) {
-
-				switch (b_Type) {
-				case APCI1710_PULSEENCODER_READ:
-		 /****************************/
-					/* Read the status register */
-		 /****************************/
-
-					dw_StatusRegister =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 16 +
-						(64 * b_ModulNbr));
-
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_StatusRegister = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_StatusRegister |
-						dw_StatusRegister;
-
-					*pb_Status =
-						(unsigned char) (devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_StatusRegister >> (1 +
-							b_PulseEncoderNbr)) & 1;
-
-					devpriv->s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_StatusRegister =
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_PulseEncoderModuleInfo.
-						dw_StatusRegister &
-						(0xFFFFFFFFUL - (1 << (1 +
-								b_PulseEncoderNbr)));
-
-		 /******************/
-					/* Read the value */
-		 /******************/
-
-					*pul_ReadValue =
-						inl(devpriv->s_BoardInfos.
-						ui_Address +
-						(4 * b_PulseEncoderNbr) +
-						(64 * b_ModulNbr));
-					break;
-
-				case APCI1710_PULSEENCODER_WRITE:
-					ul_WriteValue = (unsigned int) data[2];
-			/*******************/
-					/* Write the value */
-			/*******************/
-
-					outl(ul_WriteValue,
-						devpriv->s_BoardInfos.
-						ui_Address +
-						(4 * b_PulseEncoderNbr) +
-						(64 * b_ModulNbr));
-
-				}	/* end of switch */
-			} else {
-		 /*********************************/
-				/* Pulse encoder not initialised */
-		 /*********************************/
-
-				DPRINTK("Pulse encoder not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /************************************/
-			/* Pulse encoder selection is wrong */
-	      /************************************/
-
-			DPRINTK("Pulse encoder selection is wrong\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /*****************************/
-		/* Module selection is wrong */
-	   /*****************************/
-
-		DPRINTK("Module selection is wrong\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-static int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev,
-						    struct comedi_subdevice *s,
-						    struct comedi_insn *insn,
-						    unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-
-	data[0] = devpriv->s_InterruptParameters.
-		s_FIFOInterruptParameters[devpriv->
-		s_InterruptParameters.ui_Read].b_OldModuleMask;
-	data[1] = devpriv->s_InterruptParameters.
-		s_FIFOInterruptParameters[devpriv->
-		s_InterruptParameters.ui_Read].ul_OldInterruptMask;
-	data[2] = devpriv->s_InterruptParameters.
-		s_FIFOInterruptParameters[devpriv->
-		s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
-	/***************************/
-	/* Increment the read FIFO */
-	/***************************/
-
-	devpriv->s_InterruptParameters.
-		ui_Read = (devpriv->
-		s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
-	return insn->n;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
deleted file mode 100644
index 5c83033..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c
+++ /dev/null
@@ -1,3582 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : PWM.C           | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 Wulse wide modulation module                |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +-----------------------------------------------------------------------+
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ			30
-#define APCI1710_33MHZ			33
-#define APCI1710_40MHZ			40
-
-#define APCI1710_PWM_INIT		0
-#define APCI1710_PWM_GETINITDATA	1
-
-#define APCI1710_PWM_DISABLE		0
-#define APCI1710_PWM_ENABLE		1
-#define APCI1710_PWM_NEWTIMING		2
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitPWM                               |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_PWM,                    |
-|                                        unsigned char_     b_ClockSelection,         |
-|                                        unsigned char_     b_TimingUnit,             |
-|                                        ULONG_   ul_LowTiming,              |
-|                                        ULONG_   ul_HighTiming,             |
-|                                        PULONG_ pul_RealLowTiming,          |
-|                                        PULONG_ pul_RealHighTiming)         |
-+----------------------------------------------------------------------------+
-| Task              : Configure the selected PWM (b_PWM) from selected module|
-|                     (b_ModulNbr). The ul_LowTiming, ul_HighTiming and      |
-|                     ul_TimingUnit determine the low/high timing base for   |
-|                     the period. pul_RealLowTiming, pul_RealHighTiming      |
-|                     return the real timing value.                          |
-|                     You must calling this function be for you call any     |
-|                     other function witch access of the PWM.                |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_     b_BoardHandle    : Handle of board APCI-1710 |
-|                     unsigned char_     b_ModulNbr       : Module number to configure|
-|                                                  (0 to 3)                  |
-|                     unsigned char_     b_PWM            : Selected PWM (0 or 1).    |
-|                     unsigned char_     b_ClockSelection : Selection from PCI bus    |
-|                                                  clock                     |
-|                                                   - APCI1710_30MHZ :       |
-|                                                     The PC have a 30 MHz   |
-|                                                     PCI bus clock          |
-|                                                   - APCI1710_33MHZ :       |
-|                                                     The PC have a 33 MHz   |
-|                                                     PCI bus clock          |
-|                                                   - APCI1710_40MHZ         |
-|                                                     The APCI-1710 have a   |
-|                                                     integrated 40Mhz       |
-|                                                     quartz.                |
-|                     unsigned char_     b_TimingUnit     : Base timing Unit (0 to 4) |
-|                                                       0 : ns               |
-|                                                       1 : æs               |
-|                                                       2 : ms               |
-|                                                       3 : s                |
-|                                                       4 : mn               |
-|                     ULONG_    ul_LowTiming     : Low base timing value.    |
-|                     ULONG_    ul_HighTiming    : High base timing value.   |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pul_RealLowTiming  : Real low base timing     |
-|                                                   value.                   |
-|                     PULONG_  pul_RealHighTiming : Real high base timing    |
-|                                                   value.                   |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: The module is not a PWM module                      |
-|                    -4: PWM selection is wrong                              |
-|                    -5: The selected input clock is wrong                   |
-|                    -6: Timing Unit selection is wrong                      |
-|                    -7: Low base timing selection is wrong                  |
-|                    -8: High base timing selection is wrong                 |
-|                    -9: You can not used the 40MHz clock selection with     |
-|                        this board                                          |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InitPWM(struct comedi_device *dev,
-			      unsigned char b_ModulNbr,
-			      unsigned char b_PWM,
-			      unsigned char b_ClockSelection,
-			      unsigned char b_TimingUnit,
-			      unsigned int ul_LowTiming,
-			      unsigned int ul_HighTiming,
-			      unsigned int *pul_RealLowTiming,
-			      unsigned int *pul_RealHighTiming)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ul_LowTimerValue = 0;
-	unsigned int ul_HighTimerValue = 0;
-	unsigned int dw_Command;
-	double d_RealLowTiming = 0;
-	double d_RealHighTiming = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***************/
-		/* Test if PWM */
-		/***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			/**************************/
-			/* Test the PWM selection */
-			/**************************/
-
-			if (b_PWM <= 1) {
-				/******************/
-				/* Test the clock */
-				/******************/
-
-				if ((b_ClockSelection == APCI1710_30MHZ) ||
-					(b_ClockSelection == APCI1710_33MHZ) ||
-					(b_ClockSelection == APCI1710_40MHZ)) {
-					/************************/
-					/* Test the timing unit */
-					/************************/
-
-					if (b_TimingUnit <= 4) {
-						/*********************************/
-						/* Test the low timing selection */
-						/*********************************/
-
-						if (((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 0)
-								&& (ul_LowTiming
-									>= 266)
-								&& (ul_LowTiming
-									<=
-									0xFFFFFFFFUL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 1)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									571230650UL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 2)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									571230UL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 3)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									571UL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 4)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<= 9UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 0)
-								&& (ul_LowTiming
-									>= 242)
-								&& (ul_LowTiming
-									<=
-									0xFFFFFFFFUL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 1)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									519691043UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 2)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									519691UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 3)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									520UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 4)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<= 8UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 0)
-								&& (ul_LowTiming
-									>= 200)
-								&& (ul_LowTiming
-									<=
-									0xFFFFFFFFUL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 1)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									429496729UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 2)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									429496UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 3)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									429UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 4)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									7UL))) {
-							/**********************************/
-							/* Test the High timing selection */
-							/**********************************/
-
-							if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) {
-								/**************************/
-								/* Test the board version */
-								/**************************/
-
-								if (((b_ClockSelection == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_ClockSelection != APCI1710_40MHZ)) {
-
-									/************************************/
-									/* Calculate the low division fator */
-									/************************************/
-
-									fpu_begin
-										();
-
-									switch (b_TimingUnit) {
-										/******/
-										/* ns */
-										/******/
-
-									case 0:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(ul_LowTiming
-											*
-											(0.00025 * b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-											ul_LowTimerValue
-												=
-												ul_LowTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealLowTiming
-											=
-											(unsigned int)
-											(ul_LowTimerValue
-											/
-											(0.00025 * (double)b_ClockSelection));
-										d_RealLowTiming
-											=
-											(double)
-											ul_LowTimerValue
-											/
-											(0.00025
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
-											*pul_RealLowTiming
-												=
-												*pul_RealLowTiming
-												+
-												1;
-										}
-
-										ul_LowTiming
-											=
-											ul_LowTiming
-											-
-											1;
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_LowTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_LowTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/******/
-										/* æs */
-										/******/
-
-									case 1:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(ul_LowTiming
-											*
-											(0.25 * b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-											ul_LowTimerValue
-												=
-												ul_LowTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealLowTiming
-											=
-											(unsigned int)
-											(ul_LowTimerValue
-											/
-											(0.25 * (double)b_ClockSelection));
-										d_RealLowTiming
-											=
-											(double)
-											ul_LowTimerValue
-											/
-											(
-											(double)
-											0.25
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
-											*pul_RealLowTiming
-												=
-												*pul_RealLowTiming
-												+
-												1;
-										}
-
-										ul_LowTiming
-											=
-											ul_LowTiming
-											-
-											1;
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_LowTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_LowTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/******/
-										/* ms */
-										/******/
-
-									case 2:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_LowTimerValue
-											=
-											ul_LowTiming
-											*
-											(250.0
-											*
-											b_ClockSelection);
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-											ul_LowTimerValue
-												=
-												ul_LowTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealLowTiming
-											=
-											(unsigned int)
-											(ul_LowTimerValue
-											/
-											(250.0 * (double)b_ClockSelection));
-										d_RealLowTiming
-											=
-											(double)
-											ul_LowTimerValue
-											/
-											(250.0
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
-											*pul_RealLowTiming
-												=
-												*pul_RealLowTiming
-												+
-												1;
-										}
-
-										ul_LowTiming
-											=
-											ul_LowTiming
-											-
-											1;
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_LowTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_LowTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/*****/
-										/* s */
-										/*****/
-
-									case 3:
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(ul_LowTiming
-											*
-											(250000.0
-												*
-												b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-											ul_LowTimerValue
-												=
-												ul_LowTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealLowTiming
-											=
-											(unsigned int)
-											(ul_LowTimerValue
-											/
-											(250000.0
-												*
-												(double)
-												b_ClockSelection));
-										d_RealLowTiming
-											=
-											(double)
-											ul_LowTimerValue
-											/
-											(250000.0
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) {
-											*pul_RealLowTiming
-												=
-												*pul_RealLowTiming
-												+
-												1;
-										}
-
-										ul_LowTiming
-											=
-											ul_LowTiming
-											-
-											1;
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_LowTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_LowTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/******/
-										/* mn */
-										/******/
-
-									case 4:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(
-											(ul_LowTiming
-												*
-												60)
-											*
-											(250000.0
-												*
-												b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-											ul_LowTimerValue
-												=
-												ul_LowTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealLowTiming
-											=
-											(unsigned int)
-											(ul_LowTimerValue
-											/
-											(250000.0
-												*
-												(double)
-												b_ClockSelection))
-											/
-											60;
-										d_RealLowTiming
-											=
-											(
-											(double)
-											ul_LowTimerValue
-											/
-											(250000.0
-												*
-												(double)
-												b_ClockSelection))
-											/
-											60.0;
-
-										if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealLowTiming + 0.5)) {
-											*pul_RealLowTiming
-												=
-												*pul_RealLowTiming
-												+
-												1;
-										}
-
-										ul_LowTiming
-											=
-											ul_LowTiming
-											-
-											1;
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_LowTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_LowTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-									}
-
-									/*************************************/
-									/* Calculate the high division fator */
-									/*************************************/
-
-									switch (b_TimingUnit) {
-										/******/
-										/* ns */
-										/******/
-
-									case 0:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(ul_HighTiming
-											*
-											(0.00025 * b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-											ul_HighTimerValue
-												=
-												ul_HighTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealHighTiming
-											=
-											(unsigned int)
-											(ul_HighTimerValue
-											/
-											(0.00025 * (double)b_ClockSelection));
-										d_RealHighTiming
-											=
-											(double)
-											ul_HighTimerValue
-											/
-											(0.00025
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
-											*pul_RealHighTiming
-												=
-												*pul_RealHighTiming
-												+
-												1;
-										}
-
-										ul_HighTiming
-											=
-											ul_HighTiming
-											-
-											1;
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_HighTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_HighTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/******/
-										/* æs */
-										/******/
-
-									case 1:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(ul_HighTiming
-											*
-											(0.25 * b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-											ul_HighTimerValue
-												=
-												ul_HighTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealHighTiming
-											=
-											(unsigned int)
-											(ul_HighTimerValue
-											/
-											(0.25 * (double)b_ClockSelection));
-										d_RealHighTiming
-											=
-											(double)
-											ul_HighTimerValue
-											/
-											(
-											(double)
-											0.25
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
-											*pul_RealHighTiming
-												=
-												*pul_RealHighTiming
-												+
-												1;
-										}
-
-										ul_HighTiming
-											=
-											ul_HighTiming
-											-
-											1;
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_HighTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_HighTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/******/
-										/* ms */
-										/******/
-
-									case 2:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_HighTimerValue
-											=
-											ul_HighTiming
-											*
-											(250.0
-											*
-											b_ClockSelection);
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-											ul_HighTimerValue
-												=
-												ul_HighTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealHighTiming
-											=
-											(unsigned int)
-											(ul_HighTimerValue
-											/
-											(250.0 * (double)b_ClockSelection));
-										d_RealHighTiming
-											=
-											(double)
-											ul_HighTimerValue
-											/
-											(250.0
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
-											*pul_RealHighTiming
-												=
-												*pul_RealHighTiming
-												+
-												1;
-										}
-
-										ul_HighTiming
-											=
-											ul_HighTiming
-											-
-											1;
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_HighTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_HighTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/*****/
-										/* s */
-										/*****/
-
-									case 3:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(ul_HighTiming
-											*
-											(250000.0
-												*
-												b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-											ul_HighTimerValue
-												=
-												ul_HighTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealHighTiming
-											=
-											(unsigned int)
-											(ul_HighTimerValue
-											/
-											(250000.0
-												*
-												(double)
-												b_ClockSelection));
-										d_RealHighTiming
-											=
-											(double)
-											ul_HighTimerValue
-											/
-											(250000.0
-											*
-											(double)
-											b_ClockSelection);
-
-										if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) {
-											*pul_RealHighTiming
-												=
-												*pul_RealHighTiming
-												+
-												1;
-										}
-
-										ul_HighTiming
-											=
-											ul_HighTiming
-											-
-											1;
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_HighTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_HighTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-
-										/******/
-										/* mn */
-										/******/
-
-									case 4:
-
-										/******************/
-										/* Timer 0 factor */
-										/******************/
-
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(
-											(ul_HighTiming
-												*
-												60)
-											*
-											(250000.0
-												*
-												b_ClockSelection));
-
-										/*******************/
-										/* Round the value */
-										/*******************/
-
-										if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-											ul_HighTimerValue
-												=
-												ul_HighTimerValue
-												+
-												1;
-										}
-
-										/*****************************/
-										/* Calculate the real timing */
-										/*****************************/
-
-										*pul_RealHighTiming
-											=
-											(unsigned int)
-											(ul_HighTimerValue
-											/
-											(250000.0
-												*
-												(double)
-												b_ClockSelection))
-											/
-											60;
-										d_RealHighTiming
-											=
-											(
-											(double)
-											ul_HighTimerValue
-											/
-											(250000.0
-												*
-												(double)
-												b_ClockSelection))
-											/
-											60.0;
-
-										if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealHighTiming + 0.5)) {
-											*pul_RealHighTiming
-												=
-												*pul_RealHighTiming
-												+
-												1;
-										}
-
-										ul_HighTiming
-											=
-											ul_HighTiming
-											-
-											1;
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											-
-											2;
-
-										if (b_ClockSelection != APCI1710_40MHZ) {
-											ul_HighTimerValue
-												=
-												(unsigned int)
-												(
-												(double)
-												(ul_HighTimerValue)
-												*
-												1.007752288);
-										}
-
-										break;
-									}
-
-									fpu_end();
-									/****************************/
-									/* Save the clock selection */
-									/****************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										b_ClockSelection
-										=
-										b_ClockSelection;
-
-									/************************/
-									/* Save the timing unit */
-									/************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										s_PWMInfo
-										[b_PWM].
-										b_TimingUnit
-										=
-										b_TimingUnit;
-
-									/****************************/
-									/* Save the low base timing */
-									/****************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										s_PWMInfo
-										[b_PWM].
-										d_LowTiming
-										=
-										d_RealLowTiming;
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										s_PWMInfo
-										[b_PWM].
-										ul_RealLowTiming
-										=
-										*pul_RealLowTiming;
-
-									/****************************/
-									/* Save the high base timing */
-									/****************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										s_PWMInfo
-										[b_PWM].
-										d_HighTiming
-										=
-										d_RealHighTiming;
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										s_PWMInfo
-										[b_PWM].
-										ul_RealHighTiming
-										=
-										*pul_RealHighTiming;
-
-									/************************/
-									/* Write the low timing */
-									/************************/
-
-									outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr));
-
-									/*************************/
-									/* Write the high timing */
-									/*************************/
-
-									outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr));
-
-									/***************************/
-									/* Set the clock selection */
-									/***************************/
-
-									dw_Command
-										=
-										inl
-										(devpriv->
-										s_BoardInfos.
-										ui_Address
-										+
-										8
-										+
-										(20 * b_PWM) + (64 * b_ModulNbr));
-
-									dw_Command
-										=
-										dw_Command
-										&
-										0x7F;
-
-									if (b_ClockSelection == APCI1710_40MHZ) {
-										dw_Command
-											=
-											dw_Command
-											|
-											0x80;
-									}
-
-									/***************************/
-									/* Set the clock selection */
-									/***************************/
-
-									outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr));
-
-									/*************/
-									/* PWM init. */
-									/*************/
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_PWMModuleInfo.
-										s_PWMInfo
-										[b_PWM].
-										b_PWMInit
-										=
-										1;
-								} else {
-									/***************************************************/
-									/* You can not used the 40MHz clock selection with */
-									/* this board                                      */
-									/***************************************************/
-									DPRINTK("You can not used the 40MHz clock selection with this board\n");
-									i_ReturnValue
-										=
-										-9;
-								}
-							} else {
-								/***************************************/
-								/* High base timing selection is wrong */
-								/***************************************/
-								DPRINTK("High base timing selection is wrong\n");
-								i_ReturnValue =
-									-8;
-							}
-						} else {
-							/**************************************/
-							/* Low base timing selection is wrong */
-							/**************************************/
-							DPRINTK("Low base timing selection is wrong\n");
-							i_ReturnValue = -7;
-						}
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-					else {
-						/**********************************/
-						/* Timing unit selection is wrong */
-						/**********************************/
-						DPRINTK("Timing unit selection is wrong\n");
-						i_ReturnValue = -6;
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-				}	/*  if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */
-				else {
-					/*******************************/
-					/* The selected clock is wrong */
-					/*******************************/
-					DPRINTK("The selected clock is wrong\n");
-					i_ReturnValue = -5;
-				}	/*  if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-			else {
-				/******************************/
-				/* Tor PWM selection is wrong */
-				/******************************/
-				DPRINTK("Tor PWM selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-		} else {
-			/**********************************/
-			/* The module is not a PWM module */
-			/**********************************/
-			DPRINTK("The module is not a PWM module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-		/***********************/
-		/* Module number error */
-		/***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetPWMInitialisation                  |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_PWM,                    |
-|                                        unsigned char *_   pb_TimingUnit,             |
-|                                        PULONG_ pul_LowTiming,              |
-|                                        PULONG_ pul_HighTiming,             |
-|                                        unsigned char *_   pb_StartLevel,             |
-|                                        unsigned char *_   pb_StopMode,               |
-|                                        unsigned char *_   pb_StopLevel,              |
-|                                        unsigned char *_   pb_ExternGate,             |
-|                                        unsigned char *_   pb_InterruptEnable,        |
-|                                        unsigned char *_   pb_Enable)                 |
-+----------------------------------------------------------------------------+
-| Task              : Return the PWM (b_PWM) initialisation from selected    |
-|                     module (b_ModulNbr). You must calling the              |
-|                     "i_APCI1710_InitPWM" function be for you call this     |
-|                     function.                                              |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle : Handle of board APCI-1710        |
-|                     unsigned char_ b_ModulNbr    : Selected module number (0 to 3)  |
-|                     unsigned char_ b_PWM         : Selected PWM (0 or 1)            |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_  pb_TimingUnit      : Base timing Unit (0 to 4) |
-|                                                       0 : ns               |
-|                                                       1 : æs               |
-|                                                       2 : ms               |
-|                                                       3 : s                |
-|                                                       4 : mn               |
-|                     PULONG_ pul_LowTiming      : Low base timing value.    |
-|                     PULONG_ pul_HighTiming     : High base timing value.   |
-|                     unsigned char *_  pb_StartLevel      : Start period level        |
-|                                                  selection                 |
-|                                                       0 : The period start |
-|                                                           with a low level |
-|                                                       1 : The period start |
-|                                                           with a high level|
-|                     unsigned char *_  pb_StopMode        : Stop mode selection       |
-|                                                  0 : The PWM is stopped    |
-|                                                      directly after the    |
-|                                                     "i_APCI1710_DisablePWM"|
-|                                                      function and break the|
-|                                                      last period           |
-|                                                  1 : After the             |
-|                                                     "i_APCI1710_DisablePWM"|
-|                                                      function the PWM is   |
-|                                                      stopped at the end    |
-|                                                      from last period cycle|
-|                     unsigned char *_  pb_StopLevel        : Stop PWM level selection |
-|                                                    0 : The output signal   |
-|                                                        keep the level after|
-|                                                        the                 |
-|                                                     "i_APCI1710_DisablePWM"|
-|                                                        function            |
-|                                                    1 : The output signal is|
-|                                                        set to low after the|
-|                                                     "i_APCI1710_DisablePWM"|
-|                                                        function            |
-|                                                    2 : The output signal is|
-|                                                        set to high after   |
-|                                                        the                 |
-|                                                     "i_APCI1710_DisablePWM"|
-|                                                        function            |
-|                     unsigned char *_  pb_ExternGate      : Extern gate action        |
-|                                                  selection                 |
-|                                                   0 : Extern gate signal   |
-|                                                       not used.            |
-|                                                   1 : Extern gate signal   |
-|                                                       used.                |
-|                     unsigned char *_  pb_InterruptEnable : Enable or disable the PWM |
-|                                                  interrupt.                |
-|                                                  - APCI1710_ENABLE :       |
-|                                                    Enable the PWM interrupt|
-|                                                    A interrupt occur after |
-|                                                    each period             |
-|                                                  - APCI1710_DISABLE :      |
-|                                                    Disable the PWM         |
-|                                                    interrupt               |
-|                     unsigned char *_  pb_Enable          : Indicate if the PWM is    |
-|                                                  enabled or no             |
-|                                                       0 : PWM not enabled  |
-|                                                       1 : PWM enabled      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a PWM module                     |
-|                     -4: PWM selection is wrong                             |
-|                     -5: PWM not initialised see function                   |
-|                         "i_APCI1710_InitPWM"                               |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev,
-					   unsigned char b_ModulNbr,
-					   unsigned char b_PWM,
-					   unsigned char *pb_TimingUnit,
-					   unsigned int *pul_LowTiming,
-					   unsigned int *pul_HighTiming,
-					   unsigned char *pb_StartLevel,
-					   unsigned char *pb_StopMode,
-					   unsigned char *pb_StopLevel,
-					   unsigned char *pb_ExternGate,
-					   unsigned char *pb_InterruptEnable,
-					   unsigned char *pb_Enable)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned int dw_Command;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***************/
-		/* Test if PWM */
-		/***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			/**************************/
-			/* Test the PWM selection */
-			/**************************/
-
-			if (b_PWM <= 1) {
-				/***************************/
-				/* Test if PWM initialised */
-				/***************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (20 * b_PWM) +
-					(64 * b_ModulNbr));
-
-				if (dw_Status & 0x10) {
-					/***********************/
-					/* Read the low timing */
-					/***********************/
-
-					*pul_LowTiming =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 0 + (20 * b_PWM) +
-						(64 * b_ModulNbr));
-
-					/************************/
-					/* Read the high timing */
-					/************************/
-
-					*pul_HighTiming =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 4 + (20 * b_PWM) +
-						(64 * b_ModulNbr));
-
-					/********************/
-					/* Read the command */
-					/********************/
-
-					dw_Command = inl(devpriv->s_BoardInfos.
-						ui_Address + 8 + (20 * b_PWM) +
-						(64 * b_ModulNbr));
-
-					*pb_StartLevel =
-						(unsigned char) ((dw_Command >> 5) & 1);
-					*pb_StopMode =
-						(unsigned char) ((dw_Command >> 0) & 1);
-					*pb_StopLevel =
-						(unsigned char) ((dw_Command >> 1) & 1);
-					*pb_ExternGate =
-						(unsigned char) ((dw_Command >> 4) & 1);
-					*pb_InterruptEnable =
-						(unsigned char) ((dw_Command >> 3) & 1);
-
-					if (*pb_StopLevel) {
-						*pb_StopLevel =
-							*pb_StopLevel +
-							(unsigned char) ((dw_Command >>
-								2) & 1);
-					}
-
-					/********************/
-					/* Read the command */
-					/********************/
-
-					dw_Command = inl(devpriv->s_BoardInfos.
-						ui_Address + 8 + (20 * b_PWM) +
-						(64 * b_ModulNbr));
-
-					*pb_Enable =
-						(unsigned char) ((dw_Command >> 0) & 1);
-
-					*pb_TimingUnit = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_PWMModuleInfo.
-						s_PWMInfo[b_PWM].b_TimingUnit;
-				}	/*  if (dw_Status & 0x10) */
-				else {
-					/***********************/
-					/* PWM not initialised */
-					/***********************/
-					DPRINTK("PWM not initialised\n");
-					i_ReturnValue = -5;
-				}	/*  if (dw_Status & 0x10) */
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-			else {
-				/******************************/
-				/* Tor PWM selection is wrong */
-				/******************************/
-				DPRINTK("Tor PWM selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-		} else {
-			/**********************************/
-			/* The module is not a PWM module */
-			/**********************************/
-			DPRINTK("The module is not a PWM module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-		/***********************/
-		/* Module number error */
-		/***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
- * Pwm Init and Get Pwm Initialisation
- */
-static int i_APCI1710_InsnConfigPWM(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
-{
-	unsigned char b_ConfigType;
-	int i_ReturnValue = 0;
-	b_ConfigType = CR_CHAN(insn->chanspec);
-
-	switch (b_ConfigType) {
-	case APCI1710_PWM_INIT:
-		i_ReturnValue = i_APCI1710_InitPWM(dev, (unsigned char) CR_AREF(insn->chanspec),	/*   b_ModulNbr */
-			(unsigned char) data[0],	/* b_PWM */
-			(unsigned char) data[1],	/*  b_ClockSelection */
-			(unsigned char) data[2],	/*  b_TimingUnit */
-			(unsigned int) data[3],	/* ul_LowTiming */
-			(unsigned int) data[4],	/* ul_HighTiming */
-			(unsigned int *) &data[0],	/* pul_RealLowTiming */
-			(unsigned int *) &data[1]	/* pul_RealHighTiming */
-			);
-		break;
-
-	case APCI1710_PWM_GETINITDATA:
-		i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (unsigned char) CR_AREF(insn->chanspec),	/*  b_ModulNbr */
-			(unsigned char) data[0],	/* b_PWM */
-			(unsigned char *) &data[0],	/* pb_TimingUnit */
-			(unsigned int *) &data[1],	/* pul_LowTiming */
-			(unsigned int *) &data[2],	/* pul_HighTiming */
-			(unsigned char *) &data[3],	/*  pb_StartLevel */
-			(unsigned char *) &data[4],	/*  pb_StopMode */
-			(unsigned char *) &data[5],	/*  pb_StopLevel */
-			(unsigned char *) &data[6],	/*  pb_ExternGate */
-			(unsigned char *) &data[7],	/*  pb_InterruptEnable */
-			(unsigned char *) &data[8]	/*  pb_Enable */
-			);
-		break;
-
-	default:
-		printk(" Config Parameter Wrong\n");
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_EnablePWM                         |
-|                                       (unsigned char_  b_BoardHandle,               |
-|                                        unsigned char_  b_ModulNbr,                  |
-|                                        unsigned char_  b_PWM,                       |
-|                                        unsigned char_  b_StartLevel,                |
-|                                        unsigned char_  b_StopMode,                  |
-|                                        unsigned char_  b_StopLevel,                 |
-|                                        unsigned char_  b_ExternGate,                |
-|                                        unsigned char_  b_InterruptEnable)           |
-+----------------------------------------------------------------------------+
-| Task              : Enable the selected PWM (b_PWM) from selected module   |
-|                     (b_ModulNbr). You must calling the "i_APCI1710_InitPWM"|
-|                     function be for you call this function.                |
-|                     If you enable the PWM interrupt, the PWM generate a    |
-|                     interrupt after each period.                           |
-|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
-|                     Interrupt mask description chapter.                    |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle     : Handle of board APCI-1710    |
-|                     unsigned char_ b_ModulNbr        : Selected module number       |
-|                                               (0 to 3)                     |
-|                     unsigned char_ b_PWM             : Selected PWM (0 or 1)        |
-|                     unsigned char_ b_StartLevel      : Start period level selection |
-|                                                0 : The period start with a |
-|                                                    low level               |
-|                                                1 : The period start with a |
-|                                                    high level              |
-|                     unsigned char_ b_StopMode        : Stop mode selection          |
-|                                                0 : The PWM is stopped      |
-|                                                    directly after the      |
-|                                                    "i_APCI1710_DisablePWM" |
-|                                                    function and break the  |
-|                                                    last period             |
-|                                                1 : After the               |
-|                                                    "i_APCI1710_DisablePWM" |
-|                                                     function the PWM is    |
-|                                                     stopped at the end from|
-|                                                     last period cycle.     |
-|                     unsigned char_ b_StopLevel       : Stop PWM level selection     |
-|                                                0 : The output signal keep  |
-|                                                    the level after the     |
-|                                                    "i_APCI1710_DisablePWM" |
-|                                                    function                |
-|                                                1 : The output signal is set|
-|                                                    to low after the        |
-|                                                    "i_APCI1710_DisablePWM" |
-|                                                    function                |
-|                                                2 : The output signal is set|
-|                                                    to high after the       |
-|                                                    "i_APCI1710_DisablePWM" |
-|                                                    function                |
-|                     unsigned char_ b_ExternGate      : Extern gate action selection |
-|                                                0 : Extern gate signal not  |
-|                                                    used.                   |
-|                                                1 : Extern gate signal used.|
-|                     unsigned char_ b_InterruptEnable : Enable or disable the PWM    |
-|                                               interrupt.                   |
-|                                               - APCI1710_ENABLE :          |
-|                                                 Enable the PWM interrupt   |
-|                                                 A interrupt occur after    |
-|                                                 each period                |
-|                                               - APCI1710_DISABLE :         |
-|                                                 Disable the PWM interrupt  |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0:  No error                                           |
-|                    -1:  The handle parameter of the board is wrong         |
-|                    -2:  Module selection wrong                             |
-|                    -3:  The module is not a PWM module                     |
-|                    -4:  PWM selection is wrong                             |
-|                    -5:  PWM not initialised see function                   |
-|                         "i_APCI1710_InitPWM"                               |
-|                    -6:  PWM start level selection is wrong                 |
-|                    -7:  PWM stop mode selection is wrong                   |
-|                    -8:  PWM stop level selection is wrong                  |
-|                    -9:  Extern gate signal selection is wrong              |
-|                    -10: Interrupt parameter is wrong                       |
-|                    -11: Interrupt function not initialised.                |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_EnablePWM(struct comedi_device *dev,
-				unsigned char b_ModulNbr,
-				unsigned char b_PWM,
-				unsigned char b_StartLevel,
-				unsigned char b_StopMode,
-				unsigned char b_StopLevel,
-				unsigned char b_ExternGate,
-				unsigned char b_InterruptEnable)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned int dw_Command;
-
-	devpriv->tsk_Current = current;	/*  Save the current process task structure */
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***************/
-		/* Test if PWM */
-		/***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			/**************************/
-			/* Test the PWM selection */
-			/**************************/
-
-			if (b_PWM <= 1) {
-				/***************************/
-				/* Test if PWM initialised */
-				/***************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (20 * b_PWM) +
-					(64 * b_ModulNbr));
-
-				if (dw_Status & 0x10) {
-					/**********************************/
-					/* Test the start level selection */
-					/**********************************/
-
-					if (b_StartLevel <= 1) {
-						/**********************/
-						/* Test the stop mode */
-						/**********************/
-
-						if (b_StopMode <= 1) {
-							/***********************/
-							/* Test the stop level */
-							/***********************/
-
-							if (b_StopLevel <= 2) {
-								/*****************************/
-								/* Test the extern gate mode */
-								/*****************************/
-
-								if (b_ExternGate
-									<= 1) {
-									/*****************************/
-									/* Test the interrupt action */
-									/*****************************/
-
-									if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) {
-										/******************************************/
-										/* Test if interrupt function initialised */
-										/******************************************/
-
-										/********************/
-										/* Read the command */
-										/********************/
-
-										dw_Command
-											=
-											inl
-											(devpriv->
-											s_BoardInfos.
-											ui_Address
-											+
-											8
-											+
-											(20 * b_PWM) + (64 * b_ModulNbr));
-
-										dw_Command
-											=
-											dw_Command
-											&
-											0x80;
-
-										/********************/
-										/* Make the command */
-										/********************/
-
-										dw_Command
-											=
-											dw_Command
-											|
-											b_StopMode
-											|
-											(b_InterruptEnable
-											<<
-											3)
-											|
-											(b_ExternGate
-											<<
-											4)
-											|
-											(b_StartLevel
-											<<
-											5);
-
-										if (b_StopLevel & 3) {
-											dw_Command
-												=
-												dw_Command
-												|
-												2;
-
-											if (b_StopLevel & 2) {
-												dw_Command
-													=
-													dw_Command
-													|
-													4;
-											}
-										}
-
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_PWMModuleInfo.
-											s_PWMInfo
-											[b_PWM].
-											b_InterruptEnable
-											=
-											b_InterruptEnable;
-
-										/*******************/
-										/* Set the command */
-										/*******************/
-
-										outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr));
-
-										/******************/
-										/* Enable the PWM */
-										/******************/
-										outl(1, devpriv->s_BoardInfos.ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr));
-									}	/*  if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */
-									else {
-										/********************************/
-										/* Interrupt parameter is wrong */
-										/********************************/
-										DPRINTK("Interrupt parameter is wrong\n");
-										i_ReturnValue
-											=
-											-10;
-									}	/*  if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */
-								}	/*  if (b_ExternGate >= 0 && b_ExternGate <= 1) */
-								else {
-									/*****************************************/
-									/* Extern gate signal selection is wrong */
-									/*****************************************/
-									DPRINTK("Extern gate signal selection is wrong\n");
-									i_ReturnValue
-										=
-										-9;
-								}	/*  if (b_ExternGate >= 0 && b_ExternGate <= 1) */
-							}	/*  if (b_StopLevel >= 0 && b_StopLevel <= 2) */
-							else {
-								/*************************************/
-								/* PWM stop level selection is wrong */
-								/*************************************/
-								DPRINTK("PWM stop level selection is wrong\n");
-								i_ReturnValue =
-									-8;
-							}	/*  if (b_StopLevel >= 0 && b_StopLevel <= 2) */
-						}	/*  if (b_StopMode >= 0 && b_StopMode <= 1) */
-						else {
-							/************************************/
-							/* PWM stop mode selection is wrong */
-							/************************************/
-							DPRINTK("PWM stop mode selection is wrong\n");
-							i_ReturnValue = -7;
-						}	/*  if (b_StopMode >= 0 && b_StopMode <= 1) */
-					}	/*  if (b_StartLevel >= 0 && b_StartLevel <= 1) */
-					else {
-						/**************************************/
-						/* PWM start level selection is wrong */
-						/**************************************/
-						DPRINTK("PWM start level selection is wrong\n");
-						i_ReturnValue = -6;
-					}	/*  if (b_StartLevel >= 0 && b_StartLevel <= 1) */
-				}	/*  if (dw_Status & 0x10) */
-				else {
-					/***********************/
-					/* PWM not initialised */
-					/***********************/
-					DPRINTK("PWM not initialised\n");
-					i_ReturnValue = -5;
-				}	/*  if (dw_Status & 0x10) */
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-			else {
-				/******************************/
-				/* Tor PWM selection is wrong */
-				/******************************/
-				DPRINTK("Tor PWM selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-		} else {
-			/**********************************/
-			/* The module is not a PWM module */
-			/**********************************/
-			DPRINTK("The module is not a PWM module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-		/***********************/
-		/* Module number error */
-		/***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_DisablePWM (unsigned char_  b_BoardHandle,     |
-|                                                  unsigned char_  b_ModulNbr,        |
-|                                                  unsigned char_  b_PWM)             |
-+----------------------------------------------------------------------------+
-| Task              : Disable the selected PWM (b_PWM) from selected module  |
-|                     (b_ModulNbr). The output signal level depend of the    |
-|                     initialisation by the "i_APCI1710_EnablePWM".          |
-|                     See the b_StartLevel, b_StopMode and b_StopLevel       |
-|                     parameters from this function.                         |
-+----------------------------------------------------------------------------+
-| Input Parameters  :BYTE_ b_BoardHandle : Handle of board APCI-1710         |
-|                    unsigned char_ b_ModulNbr    : Selected module number (0 to 3)   |
-|                    unsigned char_ b_PWM         : Selected PWM (0 or 1)             |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a PWM module                     |
-|                     -4: PWM selection is wrong                             |
-|                     -5: PWM not initialised see function                   |
-|                         "i_APCI1710_InitPWM"                               |
-|                     -6: PWM not enabled see function                       |
-|                         "i_APCI1710_EnablePWM"                             |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_DisablePWM(struct comedi_device *dev,
-				 unsigned char b_ModulNbr,
-				 unsigned char b_PWM)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***************/
-		/* Test if PWM */
-		/***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			/**************************/
-			/* Test the PWM selection */
-			/**************************/
-
-			if (b_PWM <= 1) {
-				/***************************/
-				/* Test if PWM initialised */
-				/***************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (20 * b_PWM) +
-					(64 * b_ModulNbr));
-
-				if (dw_Status & 0x10) {
-					/***********************/
-					/* Test if PWM enabled */
-					/***********************/
-
-					if (dw_Status & 0x1) {
-						/*******************/
-						/* Disable the PWM */
-						/*******************/
-						outl(0, devpriv->s_BoardInfos.
-							ui_Address + 12 +
-							(20 * b_PWM) +
-							(64 * b_ModulNbr));
-					}	/*  if (dw_Status & 0x1) */
-					else {
-						/*******************/
-						/* PWM not enabled */
-						/*******************/
-						DPRINTK("PWM not enabled\n");
-						i_ReturnValue = -6;
-					}	/*  if (dw_Status & 0x1) */
-				}	/*  if (dw_Status & 0x10) */
-				else {
-					/***********************/
-					/* PWM not initialised */
-					/***********************/
-					DPRINTK(" PWM not initialised\n");
-					i_ReturnValue = -5;
-				}	/*  if (dw_Status & 0x10) */
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-			else {
-				/******************************/
-				/* Tor PWM selection is wrong */
-				/******************************/
-				DPRINTK("Tor PWM selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-		} else {
-			/**********************************/
-			/* The module is not a PWM module */
-			/**********************************/
-			DPRINTK("The module is not a PWM module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-		/***********************/
-		/* Module number error */
-		/***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_SetNewPWMTiming                       |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_PWM,                    |
-|                                        unsigned char_     b_ClockSelection,         |
-|                                        unsigned char_     b_TimingUnit,             |
-|                                        ULONG_   ul_LowTiming,              |
-|                                        ULONG_   ul_HighTiming)             |
-+----------------------------------------------------------------------------+
-| Task              : Set a new timing. The ul_LowTiming, ul_HighTiming and  |
-|                     ul_TimingUnit determine the low/high timing base for   |
-|                     the period.                                            |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_     b_BoardHandle    : Handle of board APCI-1710 |
-|                     unsigned char_     b_ModulNbr       : Module number to configure|
-|                                                  (0 to 3)                  |
-|                     unsigned char_     b_PWM            : Selected PWM (0 or 1).    |
-|                     unsigned char_     b_TimingUnit     : Base timing Unit (0 to 4) |
-|                                                       0 : ns               |
-|                                                       1 : æs               |
-|                                                       2 : ms               |
-|                                                       3 : s                |
-|                                                       4 : mn               |
-|                     ULONG_    ul_LowTiming     : Low base timing value.    |
-|                     ULONG_    ul_HighTiming    : High base timing value.   |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: Module selection wrong                              |
-|                    -3: The module is not a PWM module                      |
-|                    -4: PWM selection is wrong                              |
-|                    -5: PWM not initialised                                 |
-|                    -6: Timing Unit selection is wrong                      |
-|                    -7: Low base timing selection is wrong                  |
-|                    -8: High base timing selection is wrong                 |
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev,
-				      unsigned char b_ModulNbr,
-				      unsigned char b_PWM,
-				      unsigned char b_TimingUnit,
-				      unsigned int ul_LowTiming,
-				      unsigned int ul_HighTiming)
-{
-	struct addi_private *devpriv = dev->private;
-	unsigned char b_ClockSelection;
-	int i_ReturnValue = 0;
-	unsigned int ul_LowTimerValue = 0;
-	unsigned int ul_HighTimerValue = 0;
-	unsigned int ul_RealLowTiming = 0;
-	unsigned int ul_RealHighTiming = 0;
-	unsigned int dw_Status;
-	unsigned int dw_Command;
-	double d_RealLowTiming = 0;
-	double d_RealHighTiming = 0;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***************/
-		/* Test if PWM */
-		/***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			/**************************/
-			/* Test the PWM selection */
-			/**************************/
-
-			if (b_PWM <= 1) {
-				/***************************/
-				/* Test if PWM initialised */
-				/***************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (20 * b_PWM) +
-					(64 * b_ModulNbr));
-
-				if (dw_Status & 0x10) {
-					b_ClockSelection = devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_PWMModuleInfo.
-						b_ClockSelection;
-
-					/************************/
-					/* Test the timing unit */
-					/************************/
-
-					if (b_TimingUnit <= 4) {
-						/*********************************/
-						/* Test the low timing selection */
-						/*********************************/
-
-						if (((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 0)
-								&& (ul_LowTiming
-									>= 266)
-								&& (ul_LowTiming
-									<=
-									0xFFFFFFFFUL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 1)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									571230650UL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 2)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									571230UL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 3)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									571UL))
-							|| ((b_ClockSelection ==
-									APCI1710_30MHZ)
-								&& (b_TimingUnit
-									== 4)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<= 9UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 0)
-								&& (ul_LowTiming
-									>= 242)
-								&& (ul_LowTiming
-									<=
-									0xFFFFFFFFUL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 1)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									519691043UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 2)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									519691UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 3)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									520UL))
-							|| ((b_ClockSelection ==
-									APCI1710_33MHZ)
-								&& (b_TimingUnit
-									== 4)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<= 8UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 0)
-								&& (ul_LowTiming
-									>= 200)
-								&& (ul_LowTiming
-									<=
-									0xFFFFFFFFUL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 1)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									429496729UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 2)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									429496UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 3)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									429UL))
-							|| ((b_ClockSelection ==
-									APCI1710_40MHZ)
-								&& (b_TimingUnit
-									== 4)
-								&& (ul_LowTiming
-									>= 1)
-								&& (ul_LowTiming
-									<=
-									7UL))) {
-							/**********************************/
-							/* Test the High timing selection */
-							/**********************************/
-
-							if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) {
-								/************************************/
-								/* Calculate the low division fator */
-								/************************************/
-
-								fpu_begin();
-								switch (b_TimingUnit) {
-									/******/
-									/* ns */
-									/******/
-
-								case 0:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_LowTimerValue
-										=
-										(unsigned int)
-										(ul_LowTiming
-										*
-										(0.00025 * b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealLowTiming
-										=
-										(unsigned int)
-										(ul_LowTimerValue
-										/
-										(0.00025 * (double)b_ClockSelection));
-									d_RealLowTiming
-										=
-										(double)
-										ul_LowTimerValue
-										/
-										(0.00025
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
-										ul_RealLowTiming
-											=
-											ul_RealLowTiming
-											+
-											1;
-									}
-
-									ul_LowTiming
-										=
-										ul_LowTiming
-										-
-										1;
-									ul_LowTimerValue
-										=
-										ul_LowTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_LowTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/******/
-									/* æs */
-									/******/
-
-								case 1:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_LowTimerValue
-										=
-										(unsigned int)
-										(ul_LowTiming
-										*
-										(0.25 * b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealLowTiming
-										=
-										(unsigned int)
-										(ul_LowTimerValue
-										/
-										(0.25 * (double)b_ClockSelection));
-									d_RealLowTiming
-										=
-										(double)
-										ul_LowTimerValue
-										/
-										(
-										(double)
-										0.25
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
-										ul_RealLowTiming
-											=
-											ul_RealLowTiming
-											+
-											1;
-									}
-
-									ul_LowTiming
-										=
-										ul_LowTiming
-										-
-										1;
-									ul_LowTimerValue
-										=
-										ul_LowTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_LowTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/******/
-									/* ms */
-									/******/
-
-								case 2:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_LowTimerValue
-										=
-										ul_LowTiming
-										*
-										(250.0
-										*
-										b_ClockSelection);
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealLowTiming
-										=
-										(unsigned int)
-										(ul_LowTimerValue
-										/
-										(250.0 * (double)b_ClockSelection));
-									d_RealLowTiming
-										=
-										(double)
-										ul_LowTimerValue
-										/
-										(250.0
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
-										ul_RealLowTiming
-											=
-											ul_RealLowTiming
-											+
-											1;
-									}
-
-									ul_LowTiming
-										=
-										ul_LowTiming
-										-
-										1;
-									ul_LowTimerValue
-										=
-										ul_LowTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_LowTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/*****/
-									/* s */
-									/*****/
-
-								case 3:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_LowTimerValue
-										=
-										(unsigned int)
-										(ul_LowTiming
-										*
-										(250000.0
-											*
-											b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealLowTiming
-										=
-										(unsigned int)
-										(ul_LowTimerValue
-										/
-										(250000.0
-											*
-											(double)
-											b_ClockSelection));
-									d_RealLowTiming
-										=
-										(double)
-										ul_LowTimerValue
-										/
-										(250000.0
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) {
-										ul_RealLowTiming
-											=
-											ul_RealLowTiming
-											+
-											1;
-									}
-
-									ul_LowTiming
-										=
-										ul_LowTiming
-										-
-										1;
-									ul_LowTimerValue
-										=
-										ul_LowTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_LowTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/******/
-									/* mn */
-									/******/
-
-								case 4:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_LowTimerValue
-										=
-										(unsigned int)
-										(
-										(ul_LowTiming
-											*
-											60)
-										*
-										(250000.0
-											*
-											b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) {
-										ul_LowTimerValue
-											=
-											ul_LowTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealLowTiming
-										=
-										(unsigned int)
-										(ul_LowTimerValue
-										/
-										(250000.0
-											*
-											(double)
-											b_ClockSelection))
-										/
-										60;
-									d_RealLowTiming
-										=
-										(
-										(double)
-										ul_LowTimerValue
-										/
-										(250000.0
-											*
-											(double)
-											b_ClockSelection))
-										/
-										60.0;
-
-									if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealLowTiming + 0.5)) {
-										ul_RealLowTiming
-											=
-											ul_RealLowTiming
-											+
-											1;
-									}
-
-									ul_LowTiming
-										=
-										ul_LowTiming
-										-
-										1;
-									ul_LowTimerValue
-										=
-										ul_LowTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_LowTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_LowTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-								}
-
-								/*************************************/
-								/* Calculate the high division fator */
-								/*************************************/
-
-								switch (b_TimingUnit) {
-									/******/
-									/* ns */
-									/******/
-
-								case 0:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_HighTimerValue
-										=
-										(unsigned int)
-										(ul_HighTiming
-										*
-										(0.00025 * b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealHighTiming
-										=
-										(unsigned int)
-										(ul_HighTimerValue
-										/
-										(0.00025 * (double)b_ClockSelection));
-									d_RealHighTiming
-										=
-										(double)
-										ul_HighTimerValue
-										/
-										(0.00025
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
-										ul_RealHighTiming
-											=
-											ul_RealHighTiming
-											+
-											1;
-									}
-
-									ul_HighTiming
-										=
-										ul_HighTiming
-										-
-										1;
-									ul_HighTimerValue
-										=
-										ul_HighTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_HighTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/******/
-									/* æs */
-									/******/
-
-								case 1:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_HighTimerValue
-										=
-										(unsigned int)
-										(ul_HighTiming
-										*
-										(0.25 * b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealHighTiming
-										=
-										(unsigned int)
-										(ul_HighTimerValue
-										/
-										(0.25 * (double)b_ClockSelection));
-									d_RealHighTiming
-										=
-										(double)
-										ul_HighTimerValue
-										/
-										(
-										(double)
-										0.25
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
-										ul_RealHighTiming
-											=
-											ul_RealHighTiming
-											+
-											1;
-									}
-
-									ul_HighTiming
-										=
-										ul_HighTiming
-										-
-										1;
-									ul_HighTimerValue
-										=
-										ul_HighTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_HighTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/******/
-									/* ms */
-									/******/
-
-								case 2:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_HighTimerValue
-										=
-										ul_HighTiming
-										*
-										(250.0
-										*
-										b_ClockSelection);
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealHighTiming
-										=
-										(unsigned int)
-										(ul_HighTimerValue
-										/
-										(250.0 * (double)b_ClockSelection));
-									d_RealHighTiming
-										=
-										(double)
-										ul_HighTimerValue
-										/
-										(250.0
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
-										ul_RealHighTiming
-											=
-											ul_RealHighTiming
-											+
-											1;
-									}
-
-									ul_HighTiming
-										=
-										ul_HighTiming
-										-
-										1;
-									ul_HighTimerValue
-										=
-										ul_HighTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_HighTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/*****/
-									/* s */
-									/*****/
-
-								case 3:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_HighTimerValue
-										=
-										(unsigned int)
-										(ul_HighTiming
-										*
-										(250000.0
-											*
-											b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealHighTiming
-										=
-										(unsigned int)
-										(ul_HighTimerValue
-										/
-										(250000.0
-											*
-											(double)
-											b_ClockSelection));
-									d_RealHighTiming
-										=
-										(double)
-										ul_HighTimerValue
-										/
-										(250000.0
-										*
-										(double)
-										b_ClockSelection);
-
-									if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) {
-										ul_RealHighTiming
-											=
-											ul_RealHighTiming
-											+
-											1;
-									}
-
-									ul_HighTiming
-										=
-										ul_HighTiming
-										-
-										1;
-									ul_HighTimerValue
-										=
-										ul_HighTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_HighTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-
-									/******/
-									/* mn */
-									/******/
-
-								case 4:
-
-									/******************/
-									/* Timer 0 factor */
-									/******************/
-
-									ul_HighTimerValue
-										=
-										(unsigned int)
-										(
-										(ul_HighTiming
-											*
-											60)
-										*
-										(250000.0
-											*
-											b_ClockSelection));
-
-									/*******************/
-									/* Round the value */
-									/*******************/
-
-									if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) {
-										ul_HighTimerValue
-											=
-											ul_HighTimerValue
-											+
-											1;
-									}
-
-									/*****************************/
-									/* Calculate the real timing */
-									/*****************************/
-
-									ul_RealHighTiming
-										=
-										(unsigned int)
-										(ul_HighTimerValue
-										/
-										(250000.0
-											*
-											(double)
-											b_ClockSelection))
-										/
-										60;
-									d_RealHighTiming
-										=
-										(
-										(double)
-										ul_HighTimerValue
-										/
-										(250000.0
-											*
-											(double)
-											b_ClockSelection))
-										/
-										60.0;
-
-									if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealHighTiming + 0.5)) {
-										ul_RealHighTiming
-											=
-											ul_RealHighTiming
-											+
-											1;
-									}
-
-									ul_HighTiming
-										=
-										ul_HighTiming
-										-
-										1;
-									ul_HighTimerValue
-										=
-										ul_HighTimerValue
-										-
-										2;
-
-									if (b_ClockSelection != APCI1710_40MHZ) {
-										ul_HighTimerValue
-											=
-											(unsigned int)
-											(
-											(double)
-											(ul_HighTimerValue)
-											*
-											1.007752288);
-									}
-
-									break;
-								}
-
-								fpu_end();
-
-								/************************/
-								/* Save the timing unit */
-								/************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PWMModuleInfo.
-									s_PWMInfo
-									[b_PWM].
-									b_TimingUnit
-									=
-									b_TimingUnit;
-
-								/****************************/
-								/* Save the low base timing */
-								/****************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PWMModuleInfo.
-									s_PWMInfo
-									[b_PWM].
-									d_LowTiming
-									=
-									d_RealLowTiming;
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PWMModuleInfo.
-									s_PWMInfo
-									[b_PWM].
-									ul_RealLowTiming
-									=
-									ul_RealLowTiming;
-
-								/****************************/
-								/* Save the high base timing */
-								/****************************/
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PWMModuleInfo.
-									s_PWMInfo
-									[b_PWM].
-									d_HighTiming
-									=
-									d_RealHighTiming;
-
-								devpriv->
-									s_ModuleInfo
-									[b_ModulNbr].
-									s_PWMModuleInfo.
-									s_PWMInfo
-									[b_PWM].
-									ul_RealHighTiming
-									=
-									ul_RealHighTiming;
-
-								/************************/
-								/* Write the low timing */
-								/************************/
-
-								outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr));
-
-								/*************************/
-								/* Write the high timing */
-								/*************************/
-
-								outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr));
-
-								/***************************/
-								/* Set the clock selection */
-								/***************************/
-
-								dw_Command =
-									inl
-									(devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 8 +
-									(20 * b_PWM) + (64 * b_ModulNbr));
-
-								dw_Command =
-									dw_Command
-									& 0x7F;
-
-								if (b_ClockSelection == APCI1710_40MHZ) {
-									dw_Command
-										=
-										dw_Command
-										|
-										0x80;
-								}
-
-								/***************************/
-								/* Set the clock selection */
-								/***************************/
-
-								outl(dw_Command,
-									devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 8 +
-									(20 * b_PWM) + (64 * b_ModulNbr));
-							} else {
-								/***************************************/
-								/* High base timing selection is wrong */
-								/***************************************/
-								DPRINTK("High base timing selection is wrong\n");
-								i_ReturnValue =
-									-8;
-							}
-						} else {
-							/**************************************/
-							/* Low base timing selection is wrong */
-							/**************************************/
-							DPRINTK("Low base timing selection is wrong\n");
-							i_ReturnValue = -7;
-						}
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-					else {
-						/**********************************/
-						/* Timing unit selection is wrong */
-						/**********************************/
-						DPRINTK("Timing unit selection is wrong\n");
-						i_ReturnValue = -6;
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-				}	/*  if (dw_Status & 0x10) */
-				else {
-					/***********************/
-					/* PWM not initialised */
-					/***********************/
-					DPRINTK("PWM not initialised\n");
-					i_ReturnValue = -5;
-				}	/*  if (dw_Status & 0x10) */
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-			else {
-				/******************************/
-				/* Tor PWM selection is wrong */
-				/******************************/
-				DPRINTK("Tor PWM selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-		} else {
-			/**********************************/
-			/* The module is not a PWM module */
-			/**********************************/
-			DPRINTK("The module is not a PWM module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-		/***********************/
-		/* Module number error */
-		/***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
- * Pwm Enable Disable and Set New Timing
- */
-static int i_APCI1710_InsnWritePWM(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn,
-				   unsigned int *data)
-{
-	unsigned char b_WriteType;
-	int i_ReturnValue = 0;
-	b_WriteType = CR_CHAN(insn->chanspec);
-
-	switch (b_WriteType) {
-	case APCI1710_PWM_ENABLE:
-		i_ReturnValue = i_APCI1710_EnablePWM(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) data[0],
-			(unsigned char) data[1],
-			(unsigned char) data[2],
-			(unsigned char) data[3], (unsigned char) data[4], (unsigned char) data[5]);
-		break;
-
-	case APCI1710_PWM_DISABLE:
-		i_ReturnValue = i_APCI1710_DisablePWM(dev,
-			(unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]);
-		break;
-
-	case APCI1710_PWM_NEWTIMING:
-		i_ReturnValue = i_APCI1710_SetNewPWMTiming(dev,
-			(unsigned char) CR_AREF(insn->chanspec),
-			(unsigned char) data[0],
-			(unsigned char) data[1], (unsigned int) data[2], (unsigned int) data[3]);
-		break;
-
-	default:
-		printk("Write Config Parameter Wrong\n");
-	}
-
-	if (i_ReturnValue >= 0)
-		i_ReturnValue = insn->n;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetPWMStatus                          |
-|                               (unsigned char_    b_BoardHandle,                     |
-|                                unsigned char_    b_ModulNbr,                        |
-|                                unsigned char_    b_PWM,                             |
-|                                unsigned char *_  pb_PWMOutputStatus,                 |
-|                                unsigned char *_  pb_ExternGateStatus)                |
-+----------------------------------------------------------------------------+
-| Task              : Return the status from selected PWM (b_PWM) from       |
-|                     selected module (b_ModulNbr).                          |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_  b_BoardHandle : Handle of board APCI-1710       |
-|                     unsigned char_  b_PWM         : Selected PWM (0 or 1)           |
-|                     unsigned char_  b_ModulNbr    : Selected module number (0 to 3)
-	b_ModulNbr			=(unsigned char)  CR_AREF(insn->chanspec);
-	b_PWM				=(unsigned char)  data[0];
-
- |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_  pb_PWMOutputStatus  : Return the PWM output    |
-|                                                   level status.            |
-|                                                    0 : The PWM output level|
-|                                                        is low.             |
-|                                                    1 : The PWM output level|
-|                                                        is high.            |
-|                     unsigned char *_  pb_ExternGateStatus : Return the extern gate   |
-|                                                   level status.            |
-|                                                    0 : The extern gate is  |
-|                                                        low.                |
-|                                                    1 : The extern gate is  |
-|                                                        high.
-    pb_PWMOutputStatus	=(unsigned char *) data[0];
-	pb_ExternGateStatus =(unsigned char *) data[1];             |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a PWM module                     |
-|                     -4: PWM selection is wrong                             |
-|                     -5: PWM not initialised see function                   |
-|                         "i_APCI1710_InitPWM"                               |
-|                     -6: PWM not enabled see function "i_APCI1710_EnablePWM"|
-+----------------------------------------------------------------------------+
-*/
-static int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned char b_ModulNbr;
-	unsigned char b_PWM;
-	unsigned char *pb_PWMOutputStatus;
-	unsigned char *pb_ExternGateStatus;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_PWM = (unsigned char) CR_CHAN(insn->chanspec);
-	pb_PWMOutputStatus = (unsigned char *) &data[0];
-	pb_ExternGateStatus = (unsigned char *) &data[1];
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***************/
-		/* Test if PWM */
-		/***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			/**************************/
-			/* Test the PWM selection */
-			/**************************/
-
-			if (b_PWM <= 1) {
-				/***************************/
-				/* Test if PWM initialised */
-				/***************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 12 + (20 * b_PWM) +
-					(64 * b_ModulNbr));
-
-				if (dw_Status & 0x10) {
-					/***********************/
-					/* Test if PWM enabled */
-					/***********************/
-
-					if (dw_Status & 0x1) {
-						*pb_PWMOutputStatus =
-							(unsigned char) ((dw_Status >> 7)
-							& 1);
-						*pb_ExternGateStatus =
-							(unsigned char) ((dw_Status >> 6)
-							& 1);
-					}	/*  if (dw_Status & 0x1) */
-					else {
-						/*******************/
-						/* PWM not enabled */
-						/*******************/
-
-						DPRINTK("PWM not enabled \n");
-						i_ReturnValue = -6;
-					}	/*  if (dw_Status & 0x1) */
-				}	/*  if (dw_Status & 0x10) */
-				else {
-					/***********************/
-					/* PWM not initialised */
-					/***********************/
-
-					DPRINTK("PWM not initialised\n");
-					i_ReturnValue = -5;
-				}	/*  if (dw_Status & 0x10) */
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-			else {
-				/******************************/
-				/* Tor PWM selection is wrong */
-				/******************************/
-
-				DPRINTK("Tor PWM selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_PWM >= 0 && b_PWM <= 1) */
-		} else {
-			/**********************************/
-			/* The module is not a PWM module */
-			/**********************************/
-
-			DPRINTK("The module is not a PWM module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-		/***********************/
-		/* Module number error */
-		/***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-static int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev,
-					       struct comedi_subdevice *s,
-					       struct comedi_insn *insn,
-					       unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-
-	data[0] = devpriv->s_InterruptParameters.
-		s_FIFOInterruptParameters[devpriv->
-		s_InterruptParameters.ui_Read].b_OldModuleMask;
-	data[1] = devpriv->s_InterruptParameters.
-		s_FIFOInterruptParameters[devpriv->
-		s_InterruptParameters.ui_Read].ul_OldInterruptMask;
-	data[2] = devpriv->s_InterruptParameters.
-		s_FIFOInterruptParameters[devpriv->
-		s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
-	/**************************/
-	/* Increment the read FIFO */
-	/***************************/
-
-	devpriv->
-		s_InterruptParameters.
-		ui_Read = (devpriv->
-		s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
-	return insn->n;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
deleted file mode 100644
index 6ef1d6a..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
+++ /dev/null
@@ -1,845 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : SSI.C           | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 SSI counter module                          |
-  +-----------------------------------------------------------------------+
-  | several changes done by S. Weber in 1998 and C. Guinot in 2000        |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ			30
-#define APCI1710_33MHZ			33
-#define APCI1710_40MHZ			40
-
-#define APCI1710_BINARY_MODE		0x1
-#define APCI1710_GRAY_MODE		0x0
-
-#define APCI1710_SSI_READ1VALUE		1
-#define APCI1710_SSI_READALLVALUE	2
-
-#define APCI1710_SSI_SET_CHANNELON	0
-#define APCI1710_SSI_SET_CHANNELOFF	1
-#define APCI1710_SSI_READ_1CHANNEL	2
-#define APCI1710_SSI_READ_ALLCHANNEL	3
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitSSI                               |
-|                               (unsigned char_    b_BoardHandle,                     |
-|                                unsigned char_    b_ModulNbr,                        |
-|                                unsigned char_    b_SSIProfile,                      |
-|                                unsigned char_    b_PositionTurnLength,              |
-|                                unsigned char_    b_TurnCptLength,                   |
-|                                unsigned char_    b_PCIInputClock,                   |
-|                                ULONG_  ul_SSIOutputClock,                  |
-|                                unsigned char_    b_SSICountingMode)                 |
-+----------------------------------------------------------------------------+
-| Task              : Configure the SSI operating mode from selected module  |
-|                     (b_ModulNbr). You must calling this function be for you|
-|                     call any other function witch access of SSI.           |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 3)       |
-|                     unsigned char_  b_SSIProfile         : Selection from SSI       |
-|                                                   profile length (2 to 32).|
-|                     unsigned char_  b_PositionTurnLength : Selection from SSI       |
-|                                                   position data length     |
-|                                                   (1 to 31).               |
-|                     unsigned char_  b_TurnCptLength      : Selection from SSI turn  |
-|                                                   counter data length      |
-|                                                   (1 to 31).               |
-|                     unsigned char   b_PCIInputClock      : Selection from PCI bus   |
-|                                                   clock                    |
-|                                                 - APCI1710_30MHZ :         |
-|                                                   The PC have a PCI bus    |
-|                                                   clock from 30 MHz        |
-|                                                 - APCI1710_33MHZ :         |
-|                                                   The PC have a PCI bus    |
-|                                                   clock from 33 MHz        |
-|                     ULONG_ ul_SSIOutputClock    : Selection from SSI output|
-|                                                   clock.                   |
-|                                                   From  229 to 5 000 000 Hz|
-|                                                   for 30 MHz selection.    |
-|                                                   From  252 to 5 000 000 Hz|
-|                                                   for 33 MHz selection.    |
-|                     unsigned char   b_SSICountingMode    : SSI counting mode        |
-|                                                   selection                |
-|                                                 - APCI1710_BINARY_MODE :   |
-|                                                    Binary counting mode.   |
-|                                                 - APCI1710_GRAY_MODE :     |
-|                                                    Gray counting mode.
-
-	b_ModulNbr			= CR_AREF(insn->chanspec);
-	b_SSIProfile		= (unsigned char) data[0];
-	b_PositionTurnLength= (unsigned char) data[1];
-	b_TurnCptLength		= (unsigned char) data[2];
-	b_PCIInputClock		= (unsigned char) data[3];
-	ul_SSIOutputClock	= (unsigned int) data[4];
-	b_SSICountingMode	= (unsigned char)  data[5];     |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a SSI module                      |
-|                    -4: The selected SSI profile length is wrong            |
-|                    -5: The selected SSI position data length is wrong      |
-|                    -6: The selected SSI turn counter data length is wrong  |
-|                    -7: The selected PCI input clock is wrong               |
-|                    -8: The selected SSI output clock is wrong              |
-|                    -9: The selected SSI counting mode parameter is wrong   |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev,
-					struct comedi_subdevice *s,
-					struct comedi_insn *insn,
-					unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ui_TimerValue;
-	unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength,
-		b_PCIInputClock, b_SSICountingMode;
-	unsigned int ul_SSIOutputClock;
-
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_SSIProfile = (unsigned char) data[0];
-	b_PositionTurnLength = (unsigned char) data[1];
-	b_TurnCptLength = (unsigned char) data[2];
-	b_PCIInputClock = (unsigned char) data[3];
-	ul_SSIOutputClock = (unsigned int) data[4];
-	b_SSICountingMode = (unsigned char) data[5];
-
-	i_ReturnValue = insn->n;
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if SSI counter */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
-	      /*******************************/
-			/* Test the SSI profile length */
-	      /*******************************/
-
-			/*  CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */
-			if (b_SSIProfile >= 2 && b_SSIProfile < 33) {
-		 /*************************************/
-				/* Test the SSI position data length */
-		 /*************************************/
-
-				if (b_PositionTurnLength > 0
-					&& b_PositionTurnLength < 32) {
-		    /*****************************************/
-					/* Test the SSI turn counter data length */
-		    /*****************************************/
-
-					if (b_TurnCptLength > 0
-						&& b_TurnCptLength < 32) {
-		       /***************************/
-						/* Test the profile length */
-		       /***************************/
-
-						if ((b_TurnCptLength +
-								b_PositionTurnLength)
-							<= b_SSIProfile) {
-			  /****************************/
-							/* Test the PCI input clock */
-			  /****************************/
-
-							if (b_PCIInputClock ==
-								APCI1710_30MHZ
-								||
-								b_PCIInputClock
-								==
-								APCI1710_33MHZ)
-							{
-			     /*************************/
-								/* Test the output clock */
-			     /*************************/
-
-								if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) {
-									if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) {
-				   /**********************/
-										/* Save configuration */
-				   /**********************/
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_SSICounterInfo.
-											b_SSIProfile
-											=
-											b_SSIProfile;
-
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_SSICounterInfo.
-											b_PositionTurnLength
-											=
-											b_PositionTurnLength;
-
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_SSICounterInfo.
-											b_TurnCptLength
-											=
-											b_TurnCptLength;
-
-				   /*********************************/
-										/* Initialise the profile length */
-				   /*********************************/
-
-										if (b_SSICountingMode == APCI1710_BINARY_MODE) {
-
-											outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
-										} else {
-
-											outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr));
-										}
-
-				   /******************************/
-										/* Calculate the output clock */
-				   /******************************/
-
-										ui_TimerValue
-											=
-											(unsigned int)
-											(
-											((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock);
-
-				   /************************/
-										/* Initialise the timer */
-				   /************************/
-
-										outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr));
-
-				   /********************************/
-										/* Initialise the counting mode */
-				   /********************************/
-
-										outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr));
-
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_SSICounterInfo.
-											b_SSIInit
-											=
-											1;
-									} else {
-				   /*****************************************************/
-										/* The selected SSI counting mode parameter is wrong */
-				   /*****************************************************/
-
-										DPRINTK("The selected SSI counting mode parameter is wrong\n");
-										i_ReturnValue
-											=
-											-9;
-									}
-								} else {
-				/******************************************/
-									/* The selected SSI output clock is wrong */
-				/******************************************/
-
-									DPRINTK("The selected SSI output clock is wrong\n");
-									i_ReturnValue
-										=
-										-8;
-								}
-							} else {
-			     /*****************************************/
-								/* The selected PCI input clock is wrong */
-			     /*****************************************/
-
-								DPRINTK("The selected PCI input clock is wrong\n");
-								i_ReturnValue =
-									-7;
-							}
-						} else {
-			  /********************************************/
-							/* The selected SSI profile length is wrong */
-			  /********************************************/
-
-							DPRINTK("The selected SSI profile length is wrong\n");
-							i_ReturnValue = -4;
-						}
-					} else {
-		       /******************************************************/
-						/* The selected SSI turn counter data length is wrong */
-		       /******************************************************/
-
-						DPRINTK("The selected SSI turn counter data length is wrong\n");
-						i_ReturnValue = -6;
-					}
-				} else {
-		    /**************************************************/
-					/* The selected SSI position data length is wrong */
-		    /**************************************************/
-
-					DPRINTK("The selected SSI position data length is wrong\n");
-					i_ReturnValue = -5;
-				}
-			} else {
-		 /********************************************/
-				/* The selected SSI profile length is wrong */
-		 /********************************************/
-
-				DPRINTK("The selected SSI profile length is wrong\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /**********************************/
-			/* The module is not a SSI module */
-	      /**********************************/
-
-			DPRINTK("The module is not a SSI module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_  i_APCI1710_Read1SSIValue                        |
-|                               (unsigned char_     b_BoardHandle,                    |
-|                                unsigned char_     b_ModulNbr,                       |
-|                                unsigned char_     b_SelectedSSI,                    |
-|                                PULONG_ pul_Position,                       |
-|                                PULONG_ pul_TurnCpt)
- int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s,
-	struct comedi_insn *insn,unsigned int *data)                       |
-+----------------------------------------------------------------------------+
-| Task              :
-
-
-						Read the selected SSI counter (b_SelectedSSI) from     |
-|                     selected module (b_ModulNbr).
-						or Read all SSI counter (b_SelectedSSI) from              |
-|                     selected module (b_ModulNbr).                            |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 3)       |
-|                     unsigned char_ b_SelectedSSI         : Selection from SSI       |
-|                                                   counter (0 to 2)
-
-    b_ModulNbr		=   (unsigned char) CR_AREF(insn->chanspec);
-	b_SelectedSSI	=	(unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi)
-	b_ReadType		=	(unsigned char) CR_RANGE(insn->chanspec);
-|
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pul_Position       : SSI position in the turn |
-|                     PULONG_  pul_TurnCpt        : Number of turns
-
-pul_Position	=	(unsigned int *) &data[0];
-	pul_TurnCpt		=	(unsigned int *) &data[1];         |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a SSI module                      |
-|                    -4: SSI not initialised see function                    |
-|                        "i_APCI1710_InitSSI"                                |
-|                    -5: The selected SSI is wrong                           |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev,
-				       struct comedi_subdevice *s,
-				       struct comedi_insn *insn,
-				       unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_Cpt;
-	unsigned char b_Length;
-	unsigned char b_Schift;
-	unsigned char b_SSICpt;
-	unsigned int dw_And;
-	unsigned int dw_And1;
-	unsigned int dw_And2;
-	unsigned int dw_StatusReg;
-	unsigned int dw_CounterValue;
-	unsigned char b_ModulNbr;
-	unsigned char b_SelectedSSI;
-	unsigned char b_ReadType;
-	unsigned int *pul_Position;
-	unsigned int *pul_TurnCpt;
-	unsigned int *pul_Position1;
-	unsigned int *pul_TurnCpt1;
-
-	i_ReturnValue = insn->n;
-	pul_Position1 = (unsigned int *) &data[0];
-/* For Read1 */
-	pul_TurnCpt1 = (unsigned int *) &data[1];
-/* For Read all */
-	pul_Position = (unsigned int *) &data[0];	/* 0-2 */
-	pul_TurnCpt = (unsigned int *) &data[3];	/* 3-5 */
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec);
-	b_ReadType = (unsigned char) CR_RANGE(insn->chanspec);
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if SSI counter */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
-	      /***************************/
-			/* Test if SSI initialised */
-	      /***************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_SSICounterInfo.b_SSIInit == 1) {
-
-				switch (b_ReadType) {
-
-				case APCI1710_SSI_READ1VALUE:
-		 /****************************************/
-					/* Test the selected SSI counter number */
-		 /****************************************/
-
-					if (b_SelectedSSI < 3) {
-		    /************************/
-						/* Start the conversion */
-		    /************************/
-
-						outl(0, devpriv->s_BoardInfos.
-							ui_Address + 8 +
-							(64 * b_ModulNbr));
-
-						do {
-		       /*******************/
-							/* Read the status */
-		       /*******************/
-
-							dw_StatusReg =
-								inl(devpriv->
-								s_BoardInfos.
-								ui_Address +
-								(64 * b_ModulNbr));
-						} while ((dw_StatusReg & 0x1)
-							 != 0);
-
-		    /******************************/
-						/* Read the SSI counter value */
-		    /******************************/
-
-						dw_CounterValue =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 4 +
-							(b_SelectedSSI * 4) +
-							(64 * b_ModulNbr));
-
-						b_Length =
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_SSIProfile / 2;
-
-						if ((b_Length * 2) !=
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_SSIProfile) {
-							b_Length++;
-						}
-
-						b_Schift =
-							b_Length -
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_PositionTurnLength;
-
-						*pul_Position1 =
-							dw_CounterValue >>
-							b_Schift;
-
-						dw_And = 1;
-
-						for (b_Cpt = 0;
-							b_Cpt <
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_PositionTurnLength;
-							b_Cpt++) {
-							dw_And = dw_And * 2;
-						}
-
-						*pul_Position1 =
-							*pul_Position1 &
-							((dw_And) - 1);
-
-						*pul_TurnCpt1 =
-							dw_CounterValue >>
-							b_Length;
-
-						dw_And = 1;
-
-						for (b_Cpt = 0;
-							b_Cpt <
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_TurnCptLength;
-							b_Cpt++) {
-							dw_And = dw_And * 2;
-						}
-
-						*pul_TurnCpt1 =
-							*pul_TurnCpt1 &
-							((dw_And) - 1);
-					} else {
-		    /*****************************/
-						/* The selected SSI is wrong */
-		    /*****************************/
-
-						DPRINTK("The selected SSI is wrong\n");
-						i_ReturnValue = -5;
-					}
-					break;
-
-				case APCI1710_SSI_READALLVALUE:
-					dw_And1 = 1;
-
-					for (b_Cpt = 0;
-						b_Cpt <
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SSICounterInfo.
-						b_PositionTurnLength; b_Cpt++) {
-						dw_And1 = dw_And1 * 2;
-					}
-
-					dw_And2 = 1;
-
-					for (b_Cpt = 0;
-						b_Cpt <
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_SSICounterInfo.
-						b_TurnCptLength; b_Cpt++) {
-						dw_And2 = dw_And2 * 2;
-					}
-
-		 /************************/
-					/* Start the conversion */
-		 /************************/
-
-					outl(0, devpriv->s_BoardInfos.
-						ui_Address + 8 +
-						(64 * b_ModulNbr));
-
-					do {
-		    /*******************/
-						/* Read the status */
-		    /*******************/
-
-						dw_StatusReg =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address +
-							(64 * b_ModulNbr));
-					} while ((dw_StatusReg & 0x1) != 0);
-
-					for (b_SSICpt = 0; b_SSICpt < 3;
-						b_SSICpt++) {
-		    /******************************/
-						/* Read the SSI counter value */
-		    /******************************/
-
-						dw_CounterValue =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 4 +
-							(b_SSICpt * 4) +
-							(64 * b_ModulNbr));
-
-						b_Length =
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_SSIProfile / 2;
-
-						if ((b_Length * 2) !=
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_SSIProfile) {
-							b_Length++;
-						}
-
-						b_Schift =
-							b_Length -
-							devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_SSICounterInfo.
-							b_PositionTurnLength;
-
-						pul_Position[b_SSICpt] =
-							dw_CounterValue >>
-							b_Schift;
-						pul_Position[b_SSICpt] =
-							pul_Position[b_SSICpt] &
-							((dw_And1) - 1);
-
-						pul_TurnCpt[b_SSICpt] =
-							dw_CounterValue >>
-							b_Length;
-						pul_TurnCpt[b_SSICpt] =
-							pul_TurnCpt[b_SSICpt] &
-							((dw_And2) - 1);
-					}
-					break;
-
-				default:
-					printk("Read Type Inputs Wrong\n");
-
-				}	/*  switch  ending */
-
-			} else {
-		 /***********************/
-				/* SSI not initialised */
-		 /***********************/
-
-				DPRINTK("SSI not initialised\n");
-				i_ReturnValue = -4;
-			}
-		} else {
-	      /**********************************/
-			/* The module is not a SSI module */
-	      /**********************************/
-
-			DPRINTK("The module is not a SSI module\n");
-			i_ReturnValue = -3;
-
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_   i_APCI1710_ReadSSI1DigitalInput                |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_InputChannel,           |
-|                                        unsigned char *_   pb_ChannelStatus)          |
-+----------------------------------------------------------------------------+
-| Task              :
-					(0) Set the digital output from selected SSI module         |
-|                     (b_ModuleNbr) ON
-                    (1) Set the digital output from selected SSI module         |
-|                     (b_ModuleNbr) OFF
-					(2)Read the status from selected SSI digital input        |
-|                     (b_InputChannel)
-                    (3)Read the status from all SSI digital inputs from       |
-|                     selected SSI module (b_ModulNbr)                   |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr    CR_AREF        : Module number to         |
-|                                                   configure (0 to 3)       |
-|                     unsigned char_ b_InputChannel CR_CHAN       : Selection from digital   |
-|                        data[0] which IOTYPE                           input ( 0 to 2)          |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_  pb_ChannelStatus    : Digital input channel    |
-|                                 data[0]                  status                   |
-|                                                   0 : Channle is not active|
-|                                                   1 : Channle is active    |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a SSI module                      |
-|                    -4: The selected SSI digital input is wrong             |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev,
-					   struct comedi_subdevice *s,
-					   struct comedi_insn *insn,
-					   unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg;
-	unsigned char b_ModulNbr;
-	unsigned char b_InputChannel;
-	unsigned char *pb_ChannelStatus;
-	unsigned char *pb_InputStatus;
-	unsigned char b_IOType;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_IOType = (unsigned char) data[0];
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if SSI counter */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_SSI_COUNTER) {
-			switch (b_IOType) {
-			case APCI1710_SSI_SET_CHANNELON:
-					/*****************************/
-				/* Set the digital output ON */
-					/*****************************/
-
-				outl(1, devpriv->s_BoardInfos.ui_Address + 16 +
-					(64 * b_ModulNbr));
-				break;
-
-			case APCI1710_SSI_SET_CHANNELOFF:
-					/******************************/
-				/* Set the digital output OFF */
-					/******************************/
-
-				outl(0, devpriv->s_BoardInfos.ui_Address + 16 +
-					(64 * b_ModulNbr));
-				break;
-
-			case APCI1710_SSI_READ_1CHANNEL:
-				   /******************************************/
-				/* Test the digital imnput channel number */
-				   /******************************************/
-
-				b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec);
-				pb_ChannelStatus = (unsigned char *) &data[0];
-
-				if (b_InputChannel <= 2) {
-					/**************************/
-					/* Read all digital input */
-					/**************************/
-
-					dw_StatusReg =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + (64 * b_ModulNbr));
-					*pb_ChannelStatus =
-						(unsigned char) (((~dw_StatusReg) >> (4 +
-								b_InputChannel))
-						& 1);
-				} else {
-					/********************************/
-					/* Selected digital input error */
-					/********************************/
-
-					DPRINTK("Selected digital input error\n");
-					i_ReturnValue = -4;
-				}
-				break;
-
-			case APCI1710_SSI_READ_ALLCHANNEL:
-					/**************************/
-				/* Read all digital input */
-					/**************************/
-				pb_InputStatus = (unsigned char *) &data[0];
-
-				dw_StatusReg =
-					inl(devpriv->s_BoardInfos.ui_Address +
-					(64 * b_ModulNbr));
-				*pb_InputStatus =
-					(unsigned char) (((~dw_StatusReg) >> 4) & 7);
-				break;
-
-			default:
-				printk("IO type wrong\n");
-
-			}	/* switch end */
-		} else {
-	      /**********************************/
-			/* The module is not a SSI module */
-	      /**********************************/
-
-			DPRINTK("The module is not a SSI module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
deleted file mode 100644
index 0b79531..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c
+++ /dev/null
@@ -1,2065 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : TOR.C           | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 tor counter module                          |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  | 27/01/99 | S. Weber  | 40 MHz implementation                          |
-  +-----------------------------------------------------------------------+
-  | 28/04/00 | S. Weber  | Simple,double and quadruple mode implementation|
-  |          |           | Extern clock implementation                    |
-  +-----------------------------------------------------------------------+
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_30MHZ			30
-#define APCI1710_33MHZ			33
-#define APCI1710_40MHZ			40
-
-#define APCI1710_GATE_INPUT		10
-
-#define APCI1710_TOR_SIMPLE_MODE	2
-#define APCI1710_TOR_DOUBLE_MODE	3
-#define APCI1710_TOR_QUADRUPLE_MODE	4
-
-#define APCI1710_SINGLE			0
-#define APCI1710_CONTINUOUS		1
-
-#define APCI1710_TOR_GETPROGRESSSTATUS	0
-#define APCI1710_TOR_GETCOUNTERVALUE	1
-#define APCI1710_TOR_READINTERRUPT	2
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_     i_APCI1710_InitTorCounter                    |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_TorCounter,             |
-|                                        unsigned char_     b_PCIInputClock,          |
-|                                        unsigned char_     b_TimingUnit,             |
-|                                        ULONG_   ul_TimingInterval,         |
-|                                        PULONG_ pul_RealTimingInterval)     |
-+----------------------------------------------------------------------------+
-| Task              : Configure the selected tor counter (b_TorCounter)      |
-|                     from selected module (b_ModulNbr).                     |
-|                     The ul_TimingInterval and ul_TimingUnit determine the  |
-|                     timing base for the measurement.                       |
-|                     The pul_RealTimingInterval return the real timing      |
-|                     value. You must calling this function be for you call  |
-|                     any other function witch access of the tor counter.    |
-|                                                                            |
-+----------------------------------------------------------------------------+
-| Input Parameters  :    |
-|
-		CR_AREF	unsigned char_   b_ModulNbr       : Module number to configure  |
-|                                                (0 to 3)                    |
-|           data[0] unsigned char_   b_TorCounter     : Tor counter selection       |
-|                                                (0 or 1).                   |
-|           data[1] unsigned char_   b_PCIInputClock  : Selection from PCI bus clock|
-|                                                - APCI1710_30MHZ :          |
-|                                                  The PC have a PCI bus     |
-|                                                  clock from 30 MHz         |
-|                                                - APCI1710_33MHZ :          |
-|                                                  The PC have a PCI bus     |
-|                                                  clock from 33 MHz         |
-|                                                - APCI1710_40MHZ            |
-|                                                  The APCI-1710 have a      |
-|                                                  integrated 40Mhz          |
-|                                                  quartz.                   |
-|                                                - APCI1710_GATE_INPUT       |
-|                                                  Used the gate input for   |
-|						   the base clock. If you    |
-|						   have selected this option,|
-|						   than it is not possibl to |
-|						   used the gate input for   |
-|						   enabled the acquisition   |
-|           data[2] unsigned char_   b_TimingUnit    : Base timing unit (0 to 4)    |
-|                                                 0 : ns                     |
-|                                                 1 : µs                     |
-|                                                 2 : ms                     |
-|                                                 3 : s                      |
-|                                                 4 : mn                     |
-|           data[3]          ULONG_ ul_TimingInterval : Base timing value.          |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pul_RealTimingInterval : Real  base timing    |
-|                     data[0]                                  value.               |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a tor counter module             |
-|                     -4: Tor counter selection is wrong                     |
-|                     -5: The selected PCI input clock is wrong              |
-|                     -6: Timing unit selection is wrong                     |
-|                     -7: Base timing selection is wrong                     |
-|                     -8: You can not used the 40MHz clock selection wich    |
-|                         this board                                         |
-|                     -9: You can not used the 40MHz clock selection wich    |
-|                         this TOR version                                   |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev,
-					       struct comedi_subdevice *s,
-					       struct comedi_insn *insn,
-					       unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int ul_TimerValue = 0;
-	unsigned int dw_Command;
-	double d_RealTimingInterval = 0;
-	unsigned char b_ModulNbr;
-	unsigned char b_TorCounter;
-	unsigned char b_PCIInputClock;
-	unsigned char b_TimingUnit;
-	unsigned int ul_TimingInterval;
-	unsigned int ul_RealTimingInterval = 0;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-
-	b_TorCounter = (unsigned char) data[0];
-	b_PCIInputClock = (unsigned char) data[1];
-	b_TimingUnit = (unsigned char) data[2];
-	ul_TimingInterval = (unsigned int) data[3];
-	printk("INPUT clock %d\n", b_PCIInputClock);
-
-		/**************************/
-	/* Test the module number */
-		/**************************/
-
-	if (b_ModulNbr < 4) {
-		/***********************/
-		/* Test if tor counter */
-		/***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
-	      /**********************************/
-			/* Test the tor counter selection */
-	      /**********************************/
-
-			if (b_TorCounter <= 1) {
-		 /**************************/
-				/* Test the PCI bus clock */
-		 /**************************/
-
-				if ((b_PCIInputClock == APCI1710_30MHZ) ||
-					(b_PCIInputClock == APCI1710_33MHZ) ||
-					(b_PCIInputClock == APCI1710_40MHZ) ||
-					(b_PCIInputClock ==
-						APCI1710_GATE_INPUT)) {
-		    /************************/
-					/* Test the timing unit */
-		    /************************/
-
-					if ((b_TimingUnit <= 4)
-						|| (b_PCIInputClock ==
-							APCI1710_GATE_INPUT)) {
-		       /**********************************/
-						/* Test the base timing selection */
-		       /**********************************/
-
-						if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 133) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230650UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 9UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 121) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691043UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 520UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 8UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 100) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496729UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 7UL)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && (ul_TimingInterval >= 2))) {
-				/**************************/
-							/* Test the board version */
-				/**************************/
-
-							if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) {
-			     /************************/
-								/* Test the TOR version */
-			     /************************/
-
-								if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3132)) || (b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) {
-				/*********************************/
-									/* Test if not extern clock used */
-				/*********************************/
-
-									if (b_PCIInputClock != APCI1710_GATE_INPUT) {
-										fpu_begin
-											();
-				   /****************************************/
-										/* Calculate the timer 0 division fator */
-				   /****************************************/
-
-										switch (b_TimingUnit) {
-				      /******/
-											/* ns */
-				      /******/
-
-										case 0:
-
-					      /******************/
-											/* Timer 0 factor */
-					      /******************/
-
-											ul_TimerValue
-												=
-												(unsigned int)
-												(ul_TimingInterval
-												*
-												(0.00025 * b_PCIInputClock));
-
-					      /*******************/
-											/* Round the value */
-					      /*******************/
-
-											if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-												ul_TimerValue
-													=
-													ul_TimerValue
-													+
-													1;
-											}
-
-					      /*****************************/
-											/* Calculate the real timing */
-					      /*****************************/
-
-											ul_RealTimingInterval
-												=
-												(unsigned int)
-												(ul_TimerValue
-												/
-												(0.00025 * (double)b_PCIInputClock));
-											d_RealTimingInterval
-												=
-												(double)
-												ul_TimerValue
-												/
-												(0.00025
-												*
-												(double)
-												b_PCIInputClock);
-
-											if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-												ul_RealTimingInterval
-													=
-													ul_RealTimingInterval
-													+
-													1;
-											}
-
-											ul_TimingInterval
-												=
-												ul_TimingInterval
-												-
-												1;
-											ul_TimerValue
-												=
-												ul_TimerValue
-												-
-												2;
-
-											if (b_PCIInputClock != APCI1710_40MHZ) {
-												ul_TimerValue
-													=
-													(unsigned int)
-													(
-													(double)
-													(ul_TimerValue)
-													*
-													1.007752288);
-											}
-
-											break;
-
-				      /******/
-											/* æs */
-				      /******/
-
-										case 1:
-
-					      /******************/
-											/* Timer 0 factor */
-					      /******************/
-
-											ul_TimerValue
-												=
-												(unsigned int)
-												(ul_TimingInterval
-												*
-												(0.25 * b_PCIInputClock));
-
-					      /*******************/
-											/* Round the value */
-					      /*******************/
-
-											if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-												ul_TimerValue
-													=
-													ul_TimerValue
-													+
-													1;
-											}
-
-					      /*****************************/
-											/* Calculate the real timing */
-					      /*****************************/
-
-											ul_RealTimingInterval
-												=
-												(unsigned int)
-												(ul_TimerValue
-												/
-												(0.25 * (double)b_PCIInputClock));
-											d_RealTimingInterval
-												=
-												(double)
-												ul_TimerValue
-												/
-												(
-												(double)
-												0.25
-												*
-												(double)
-												b_PCIInputClock);
-
-											if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-												ul_RealTimingInterval
-													=
-													ul_RealTimingInterval
-													+
-													1;
-											}
-
-											ul_TimingInterval
-												=
-												ul_TimingInterval
-												-
-												1;
-											ul_TimerValue
-												=
-												ul_TimerValue
-												-
-												2;
-
-											if (b_PCIInputClock != APCI1710_40MHZ) {
-												ul_TimerValue
-													=
-													(unsigned int)
-													(
-													(double)
-													(ul_TimerValue)
-													*
-													1.007752288);
-											}
-
-											break;
-
-				      /******/
-											/* ms */
-				      /******/
-
-										case 2:
-
-					      /******************/
-											/* Timer 0 factor */
-					      /******************/
-
-											ul_TimerValue
-												=
-												ul_TimingInterval
-												*
-												(250.0
-												*
-												b_PCIInputClock);
-
-					      /*******************/
-											/* Round the value */
-					      /*******************/
-
-											if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-												ul_TimerValue
-													=
-													ul_TimerValue
-													+
-													1;
-											}
-
-					      /*****************************/
-											/* Calculate the real timing */
-					      /*****************************/
-
-											ul_RealTimingInterval
-												=
-												(unsigned int)
-												(ul_TimerValue
-												/
-												(250.0 * (double)b_PCIInputClock));
-											d_RealTimingInterval
-												=
-												(double)
-												ul_TimerValue
-												/
-												(250.0
-												*
-												(double)
-												b_PCIInputClock);
-
-											if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-												ul_RealTimingInterval
-													=
-													ul_RealTimingInterval
-													+
-													1;
-											}
-
-											ul_TimingInterval
-												=
-												ul_TimingInterval
-												-
-												1;
-											ul_TimerValue
-												=
-												ul_TimerValue
-												-
-												2;
-
-											if (b_PCIInputClock != APCI1710_40MHZ) {
-												ul_TimerValue
-													=
-													(unsigned int)
-													(
-													(double)
-													(ul_TimerValue)
-													*
-													1.007752288);
-											}
-
-											break;
-
-				      /*****/
-											/* s */
-				      /*****/
-
-										case 3:
-
-					      /******************/
-											/* Timer 0 factor */
-					      /******************/
-
-											ul_TimerValue
-												=
-												(unsigned int)
-												(ul_TimingInterval
-												*
-												(250000.0
-													*
-													b_PCIInputClock));
-
-					      /*******************/
-											/* Round the value */
-					      /*******************/
-
-											if ((double)((double)ul_TimingInterval * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-												ul_TimerValue
-													=
-													ul_TimerValue
-													+
-													1;
-											}
-
-					      /*****************************/
-											/* Calculate the real timing */
-					      /*****************************/
-
-											ul_RealTimingInterval
-												=
-												(unsigned int)
-												(ul_TimerValue
-												/
-												(250000.0
-													*
-													(double)
-													b_PCIInputClock));
-											d_RealTimingInterval
-												=
-												(double)
-												ul_TimerValue
-												/
-												(250000.0
-												*
-												(double)
-												b_PCIInputClock);
-
-											if ((double)((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-												ul_RealTimingInterval
-													=
-													ul_RealTimingInterval
-													+
-													1;
-											}
-
-											ul_TimingInterval
-												=
-												ul_TimingInterval
-												-
-												1;
-											ul_TimerValue
-												=
-												ul_TimerValue
-												-
-												2;
-
-											if (b_PCIInputClock != APCI1710_40MHZ) {
-												ul_TimerValue
-													=
-													(unsigned int)
-													(
-													(double)
-													(ul_TimerValue)
-													*
-													1.007752288);
-											}
-
-											break;
-
-				      /******/
-											/* mn */
-				      /******/
-
-										case 4:
-
-					      /******************/
-											/* Timer 0 factor */
-					      /******************/
-
-											ul_TimerValue
-												=
-												(unsigned int)
-												(
-												(ul_TimingInterval
-													*
-													60)
-												*
-												(250000.0
-													*
-													b_PCIInputClock));
-
-					      /*******************/
-											/* Round the value */
-					      /*******************/
-
-											if ((double)((double)(ul_TimingInterval * 60.0) * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) {
-												ul_TimerValue
-													=
-													ul_TimerValue
-													+
-													1;
-											}
-
-					      /*****************************/
-											/* Calculate the real timing */
-					      /*****************************/
-
-											ul_RealTimingInterval
-												=
-												(unsigned int)
-												(ul_TimerValue
-												/
-												(250000.0
-													*
-													(double)
-													b_PCIInputClock))
-												/
-												60;
-											d_RealTimingInterval
-												=
-												(
-												(double)
-												ul_TimerValue
-												/
-												(250000.0
-													*
-													(double)
-													b_PCIInputClock))
-												/
-												60.0;
-
-											if ((double)(((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) {
-												ul_RealTimingInterval
-													=
-													ul_RealTimingInterval
-													+
-													1;
-											}
-
-											ul_TimingInterval
-												=
-												ul_TimingInterval
-												-
-												1;
-											ul_TimerValue
-												=
-												ul_TimerValue
-												-
-												2;
-
-											if (b_PCIInputClock != APCI1710_40MHZ) {
-												ul_TimerValue
-													=
-													(unsigned int)
-													(
-													(double)
-													(ul_TimerValue)
-													*
-													1.007752288);
-											}
-
-											break;
-										}
-
-										fpu_end();
-									}	/*  if (b_PCIInputClock != APCI1710_GATE_INPUT) */
-									else {
-				   /*************************************************************/
-										/* 2 Clock used for the overflow and the reload from counter */
-				   /*************************************************************/
-
-										ul_TimerValue
-											=
-											ul_TimingInterval
-											-
-											2;
-									}	/*  if (b_PCIInputClock != APCI1710_GATE_INPUT) */
-
-				/****************************/
-									/* Save the PCI input clock */
-				/****************************/
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TorCounterModuleInfo.
-										b_PCIInputClock
-										=
-										b_PCIInputClock;
-
-				/************************/
-									/* Save the timing unit */
-				/************************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TorCounterModuleInfo.
-										s_TorCounterInfo
-										[b_TorCounter].
-										b_TimingUnit
-										=
-										b_TimingUnit;
-
-				/************************/
-									/* Save the base timing */
-				/************************/
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TorCounterModuleInfo.
-										s_TorCounterInfo
-										[b_TorCounter].
-										d_TimingInterval
-										=
-										d_RealTimingInterval;
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TorCounterModuleInfo.
-										s_TorCounterInfo
-										[b_TorCounter].
-										ul_RealTimingInterval
-										=
-										ul_RealTimingInterval;
-
-				/*******************/
-									/* Get the command */
-				/*******************/
-
-									dw_Command
-										=
-										inl
-										(devpriv->
-										s_BoardInfos.
-										ui_Address
-										+
-										4
-										+
-										(16 * b_TorCounter) + (64 * b_ModulNbr));
-
-									dw_Command
-										=
-										(dw_Command
-										>>
-										4)
-										&
-										0xF;
-
-				/******************/
-									/* Test if 40 MHz */
-				/******************/
-
-									if (b_PCIInputClock == APCI1710_40MHZ) {
-				   /****************************/
-										/* Set the 40 MHz selection */
-				   /****************************/
-
-										dw_Command
-											=
-											dw_Command
-											|
-											0x10;
-									}
-
-				/*****************************/
-									/* Test if extern clock used */
-				/*****************************/
-
-									if (b_PCIInputClock == APCI1710_GATE_INPUT) {
-				   /****************************/
-										/* Set the 40 MHz selection */
-				   /****************************/
-
-										dw_Command
-											=
-											dw_Command
-											|
-											0x20;
-									}
-
-				/*************************/
-									/* Write the new command */
-				/*************************/
-
-									outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
-				/*******************/
-									/* Disable the tor */
-				/*******************/
-
-									outl(0, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-				/*************************/
-									/* Set the timer 1 value */
-				/*************************/
-
-									outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
-				/*********************/
-									/* Tor counter init. */
-				/*********************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TorCounterModuleInfo.
-										s_TorCounterInfo
-										[b_TorCounter].
-										b_TorCounterInit
-										=
-										1;
-								} else {
-				/***********************************************/
-									/* TOR version error for 40MHz clock selection */
-				/***********************************************/
-
-									DPRINTK("TOR version error for 40MHz clock selection\n");
-									i_ReturnValue
-										=
-										-9;
-								}
-							} else {
-			     /**************************************************************/
-								/* You can not used the 40MHz clock selection wich this board */
-			     /**************************************************************/
-
-								DPRINTK("You can not used the 40MHz clock selection wich this board\n");
-								i_ReturnValue =
-									-8;
-							}
-						} else {
-			  /**********************************/
-							/* Base timing selection is wrong */
-			  /**********************************/
-
-							DPRINTK("Base timing selection is wrong\n");
-							i_ReturnValue = -7;
-						}
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-					else {
-		       /**********************************/
-						/* Timing unit selection is wrong */
-		       /**********************************/
-
-						DPRINTK("Timing unit selection is wrong\n");
-						i_ReturnValue = -6;
-					}	/*  if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */
-				}	/*  if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
-				else {
-		    /*****************************************/
-					/* The selected PCI input clock is wrong */
-		    /*****************************************/
-
-					DPRINTK("The selected PCI input clock is wrong\n");
-					i_ReturnValue = -5;
-				}	/*  if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */
-			}	/*  if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */
-			else {
-		 /**********************************/
-				/* Tor Counter selection is wrong */
-		 /**********************************/
-
-				DPRINTK("Tor Counter selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */
-		} else {
-	      /******************************************/
-			/* The module is not a tor counter module */
-	      /******************************************/
-
-			DPRINTK("The module is not a tor counter module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-	data[0] = (unsigned int) ul_RealTimingInterval;
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_EnableTorCounter                      |
-|                                               (unsigned char_ b_BoardHandle,        |
-|                                                unsigned char_ b_ModulNbr,           |
-|						 unsigned char_ b_TorCounter,         |
-|						 unsigned char_ b_InputMode,          |
-|						 unsigned char_ b_ExternGate,         |
-|                                                unsigned char_ b_CycleMode,          |
-|                                                unsigned char_ b_InterruptEnable)    |
-+----------------------------------------------------------------------------+
-| Task              : Enable the tor counter (b_TorCounter) from selected    |
-|		      module (b_ModulNbr). You must calling the              |
-|                     "i_APCI1710_InitTorCounter" function be for you call   |
-|		      this function.                                         |
-|                     If you enable the tor counter interrupt, the           |
-|                     tor counter generate a interrupt after the timing cycle|
-|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
-|                     Interrupt mask description chapter from this manual.   |
-|                     The b_CycleMode parameter determine if you will        |
-|                     measured a single or more cycle.                       |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr     : Selected module number (0 to 3) |
-|                     unsigned char_ b_TorCounter   : Tor counter selection (0 or 1). |
-|		      unsigned char_ b_InputMode    : Input signal level selection    |
-|						0 : Tor count each low level |
-|						1 : Tor count each high level|
-|		      unsigned char_ b_ExternGate   : Extern gate action selection    |
-|						0 : Extern gate signal not   |
-|						    used                     |
-|						1 : Extern gate signal used. |
-|						    If you selected the      |
-|						    single mode, each high   |
-|						    level signal start the   |
-|						    counter.                 |
-|						    If you selected the      |
-|						    continuous mode, the     |
-|						    first high level signal  |
-|						    start the tor counter    |
-|									     |
-|					      APCI1710_TOR_QUADRUPLE _MODE : |
-|					      In the quadruple mode, the edge|
-|					      analysis circuit generates a   |
-|					      counting pulse from each edge  |
-|					      of 2 signals which are phase   |
-|					      shifted in relation to each    |
-|					      other.                         |
-|					      The gate input is used for the |
-|					      signal B                       |
-|									     |
-|					      APCI1710_TOR_DOUBLE_MODE:      |
-|					      Functions in the same way as   |
-|					      the quadruple mode, except that|
-|					      only two of the four edges are |
-|					      analysed per period.           |
-|					      The gate input is used for the |
-|					      signal B                       |
-|									     |
-|					      APCI1710_TOR_SIMPLE_MODE:      |
-|					      Functions in the same way as   |
-|					      the quadruple mode, except that|
-|					      only one of the four edges is  |
-|					      analysed per period.           |
-|					      The gate input is used for the |
-|					      signal B                       |
-|									     |
-|                     unsigned char_ b_CycleMode    : Selected the tor counter        |
-|                                            acquisition mode                |
-|                     unsigned char_ b_InterruptEnable : Enable or disable the        |
-|                                               tor counter interrupt.       |
-|                                               APCI1710_ENABLE:             |
-|                                               Enable the tor counter       |
-|                                               interrupt                    |
-|                                               APCI1710_DISABLE:            |
-|                                               Disable the tor counter      |
-|                                               interrupt                    |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a tor counter module             |
-|                     -4: Tor counter selection is wrong                     |
-|                     -5: Tor counter not initialised see function           |
-|                         "i_APCI1710_InitTorCounter"                        |
-|                     -6: Tor input signal selection is wrong                |
-|                     -7: Extern gate signal mode is wrong                   |
-|                     -8: Tor counter acquisition mode cycle is wrong        |
-|                     -9: Interrupt parameter is wrong                       |
-|                     -10:Interrupt function not initialised.                |
-|                         See function "i_APCI1710_SetBoardIntRoutineX"      |
-+----------------------------------------------------------------------------+
-*/
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_DisableTorCounter                     |
-|                                               (unsigned char_  b_BoardHandle,       |
-|                                                unsigned char_  b_ModulNbr,          |
-|						 unsigned char_  b_TorCounter)        |
-+----------------------------------------------------------------------------+
-| Task              : Disable the tor counter (b_TorCounter) from selected   |
-|		      module (b_ModulNbr). If you disable the tor counter    |
-|		      after a start cycle occur and you restart the tor      |
-|		      counter witch the " i_APCI1710_EnableTorCounter"       |
-|		      function, the status register is cleared               |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr     : Selected module number (0 to 3) |
-|                     unsigned char_ b_TorCounter   : Tor counter selection (0 or 1). |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a tor counter module             |
-|                     -4: Tor counter selection is wrong                     |
-|                     -5: Tor counter not initialised see function           |
-|                         "i_APCI1710_InitTorCounter"                        |
-|                     -6: Tor counter not enabled see function               |
-|                         "i_APCI1710_EnableTorCounter"                      |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev,
-						       struct comedi_subdevice *s,
-						       struct comedi_insn *insn,
-						       unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned int dw_DummyRead;
-	unsigned int dw_ConfigReg;
-	unsigned char b_ModulNbr, b_Action;
-	unsigned char b_TorCounter;
-	unsigned char b_InputMode;
-	unsigned char b_ExternGate;
-	unsigned char b_CycleMode;
-	unsigned char b_InterruptEnable;
-
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_Action = (unsigned char) data[0];	/*  enable or disable */
-	b_TorCounter = (unsigned char) data[1];
-	b_InputMode = (unsigned char) data[2];
-	b_ExternGate = (unsigned char) data[3];
-	b_CycleMode = (unsigned char) data[4];
-	b_InterruptEnable = (unsigned char) data[5];
-	i_ReturnValue = insn->n;
-	devpriv->tsk_Current = current;	/*  Save the current process task structure */
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if tor counter */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
-	      /**********************************/
-			/* Test the tor counter selection */
-	      /**********************************/
-
-			if (b_TorCounter <= 1) {
-				switch (b_Action)	/*  Enable or Disable */
-				{
-				case APCI1710_ENABLE:
-		 /***********************************/
-					/* Test if tor counter initialised */
-		 /***********************************/
-
-					dw_Status =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 8 +
-						(16 * b_TorCounter) +
-						(64 * b_ModulNbr));
-
-					if (dw_Status & 0x10) {
-		    /******************************/
-						/* Test the input signal mode */
-		    /******************************/
-
-						if (b_InputMode == 0 ||
-							b_InputMode == 1 ||
-							b_InputMode ==
-							APCI1710_TOR_SIMPLE_MODE
-							|| b_InputMode ==
-							APCI1710_TOR_DOUBLE_MODE
-							|| b_InputMode ==
-							APCI1710_TOR_QUADRUPLE_MODE)
-						{
-		       /************************************/
-							/* Test the extern gate signal mode */
-		       /************************************/
-
-							if (b_ExternGate == 0
-								|| b_ExternGate
-								== 1
-								|| b_InputMode >
-								1) {
-			  /*********************************/
-								/* Test the cycle mode parameter */
-			  /*********************************/
-
-								if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) {
-			     /***************************/
-									/* Test the interrupt flag */
-			     /***************************/
-
-									if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) {
-
-				   /***************************/
-										/* Save the interrupt mode */
-				   /***************************/
-
-										devpriv->
-											s_ModuleInfo
-											[b_ModulNbr].
-											s_TorCounterModuleInfo.
-											s_TorCounterInfo
-											[b_TorCounter].
-											b_InterruptEnable
-											=
-											b_InterruptEnable;
-
-				   /*******************/
-										/* Get the command */
-				   /*******************/
-
-										dw_ConfigReg
-											=
-											inl
-											(devpriv->
-											s_BoardInfos.
-											ui_Address
-											+
-											4
-											+
-											(16 * b_TorCounter) + (64 * b_ModulNbr));
-
-										dw_ConfigReg
-											=
-											(dw_ConfigReg
-											>>
-											4)
-											&
-											0x30;
-
-				   /********************************/
-										/* Test if not direct mode used */
-				   /********************************/
-
-										if (b_InputMode > 1) {
-				      /*******************************/
-											/* Extern gate can not be used */
-				      /*******************************/
-
-											b_ExternGate
-												=
-												0;
-
-				      /*******************************************/
-											/* Enable the extern gate for the Signal B */
-				      /*******************************************/
-
-											dw_ConfigReg
-												=
-												dw_ConfigReg
-												|
-												0x40;
-
-				      /***********************/
-											/* Test if simple mode */
-				      /***********************/
-
-											if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) {
-					 /**************************/
-												/* Enable the sinple mode */
-					 /**************************/
-
-												dw_ConfigReg
-													=
-													dw_ConfigReg
-													|
-													0x780;
-
-											}	/*  if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) */
-
-				      /***********************/
-											/* Test if double mode */
-				      /***********************/
-
-											if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) {
-					 /**************************/
-												/* Enable the double mode */
-					 /**************************/
-
-												dw_ConfigReg
-													=
-													dw_ConfigReg
-													|
-													0x180;
-
-											}	/*  if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) */
-
-											b_InputMode
-												=
-												0;
-										}	/*  if (b_InputMode > 1) */
-
-				   /*******************/
-										/* Set the command */
-				   /*******************/
-
-										dw_ConfigReg
-											=
-											dw_ConfigReg
-											|
-											b_CycleMode
-											|
-											(b_InterruptEnable
-											*
-											2)
-											|
-											(b_InputMode
-											*
-											4)
-											|
-											(b_ExternGate
-											*
-											8);
-
-				   /*****************************/
-										/* Clear the status register */
-				   /*****************************/
-
-										dw_DummyRead
-											=
-											inl
-											(devpriv->
-											s_BoardInfos.
-											ui_Address
-											+
-											0
-											+
-											(16 * b_TorCounter) + (64 * b_ModulNbr));
-
-				   /***************************************/
-										/* Clear the interrupt status register */
-				   /***************************************/
-
-										dw_DummyRead
-											=
-											inl
-											(devpriv->
-											s_BoardInfos.
-											ui_Address
-											+
-											12
-											+
-											(16 * b_TorCounter) + (64 * b_ModulNbr));
-
-				   /********************/
-										/* Set the commando */
-				   /********************/
-
-										outl(dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
-				   /****************/
-										/* Set the gate */
-				   /****************/
-
-										outl(1, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr));
-
-									}	/*  if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
-									else {
-				/********************************/
-										/* Interrupt parameter is wrong */
-				/********************************/
-
-										DPRINTK("Interrupt parameter is wrong\n");
-										i_ReturnValue
-											=
-											-9;
-									}	/*  if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */
-								}	/*  if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
-								else {
-			     /***********************************************/
-									/* Tor counter acquisition mode cycle is wrong */
-			     /***********************************************/
-
-									DPRINTK("Tor counter acquisition mode cycle is wrong\n");
-									i_ReturnValue
-										=
-										-8;
-								}	/*  if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */
-							}	/*  if (b_ExternGate >= 0 && b_ExternGate <= 1) */
-							else {
-			  /***********************************/
-								/* Extern gate input mode is wrong */
-			  /***********************************/
-
-								DPRINTK("Extern gate input mode is wrong\n");
-								i_ReturnValue =
-									-7;
-							}	/*  if (b_ExternGate >= 0 && b_ExternGate <= 1) */
-						}	/*  if (b_InputMode >= 0 && b_InputMode <= 1) */
-						else {
-		       /***************************************/
-							/* Tor input signal selection is wrong */
-		       /***************************************/
-
-							DPRINTK("Tor input signal selection is wrong\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-		    /*******************************/
-						/* Tor counter not initialised */
-		    /*******************************/
-
-						DPRINTK("Tor counter not initialised\n");
-						i_ReturnValue = -5;
-					}
-					break;
-
-				case APCI1710_DISABLE:
-			 /***********************************/
-					/* Test if tor counter initialised */
-		 /***********************************/
-
-					dw_Status = inl(devpriv->s_BoardInfos.
-						ui_Address + 8 +
-						(16 * b_TorCounter) +
-						(64 * b_ModulNbr));
-
-		 /*******************************/
-					/* Test if counter initialised */
-		 /*******************************/
-
-					if (dw_Status & 0x10) {
-		    /***************************/
-						/* Test if counter enabled */
-		    /***************************/
-
-						if (dw_Status & 0x1) {
-		       /****************************/
-							/* Clear the interrupt mode */
-		       /****************************/
-							devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_TorCounterModuleInfo.
-								s_TorCounterInfo
-								[b_TorCounter].
-								b_InterruptEnable
-								=
-								APCI1710_DISABLE;
-
-		       /******************/
-							/* Clear the gate */
-		       /******************/
-
-							outl(0, devpriv->
-								s_BoardInfos.
-								ui_Address + 8 +
-								(16 * b_TorCounter) + (64 * b_ModulNbr));
-						}	/*  if (dw_Status & 0x1) */
-						else {
-		       /***************************/
-							/* Tor counter not enabled */
-		       /***************************/
-
-							DPRINTK("Tor counter not enabled \n");
-							i_ReturnValue = -6;
-						}	/*  if (dw_Status & 0x1) */
-					}	/*  if (dw_Status & 0x10) */
-					else {
-		    /*******************************/
-						/* Tor counter not initialised */
-		    /*******************************/
-
-						DPRINTK("Tor counter not initialised\n");
-						i_ReturnValue = -5;
-					}	/*  // if (dw_Status & 0x10) */
-
-				}	/*  switch */
-			}	/*  if (b_TorCounter <= 1) */
-			else {
-		 /**********************************/
-				/* Tor counter selection is wrong */
-		 /**********************************/
-
-				DPRINTK("Tor counter selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_TorCounter <= 1) */
-		} else {
-	      /******************************************/
-			/* The module is not a tor counter module */
-	      /******************************************/
-
-			DPRINTK("The module is not a tor counter module \n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error \n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_GetTorCounterInitialisation           |
-|                                               (unsigned char_     b_BoardHandle,    |
-|                                                unsigned char_     b_ModulNbr,       |
-|						 unsigned char_     b_TorCounter,     |
-|                                        	 unsigned char *_   pb_TimingUnit,     |
-|                                        	 PULONG_ pul_TimingInterval, |
-|						 unsigned char *_   pb_InputMode,      |
-|						 unsigned char *_   pb_ExternGate,     |
-|                                                unsigned char *_   pb_CycleMode,      |
-|						 unsigned char *_   pb_Enable,         |
-|                                                unsigned char *_   pb_InterruptEnable)|
-+----------------------------------------------------------------------------+
-| Task              : Enable the tor counter (b_TorCounter) from selected    |
-|		      module (b_ModulNbr). You must calling the              |
-|                     "i_APCI1710_InitTorCounter" function be for you call   |
-|		      this function.                                         |
-|                     If you enable the tor counter interrupt, the           |
-|                     tor counter generate a interrupt after the timing cycle|
-|                     See function "i_APCI1710_SetBoardIntRoutineX" and the  |
-|                     Interrupt mask description chapter from this manual.   |
-|                     The b_CycleMode parameter determine if you will        |
-|                     measured a single or more cycle.                       |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr     : Selected module number (0 to 3) |
-|                     unsigned char_ b_TorCounter   : Tor counter selection (0 or 1)
-
-	b_ModulNbr			=	CR_AREF(insn->chanspec);
-	b_TorCounter		=	CR_CHAN(insn->chanspec);
-. |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_  pb_TimingUnit    : Base timing unit (0 to 4)   |
-|                                                 0 : ns                     |
-|                                                 1 : µs                     |
-|                                                 2 : ms                     |
-|                                                 3 : s                      |
-|                                                 4 : mn                     |
-|                     PULONG_ pul_TimingInterval : Base timing value.        |
-|		      unsigned char *_ pb_InputMode        : Input signal level        |
-|						   selection  		     |
-|						0 : Tor count each low level |
-|						1 : Tor count each high level|
-|		      unsigned char *_ pb_ExternGate	: Extern gate action         |
-|						  selection                  |
-|						  0 : Extern gate signal not |
-|						      used                   |
-|						  1 : Extern gate signal used|
-|                     unsigned char *_ pb_CycleMode       : Tor counter acquisition    |
-|						  mode           	     |
-|		      unsigned char *_ pb_Enable		: Indicate if the tor counter|
-|						  is enabled or no           |
-|						  0 : Tor counter disabled   |
-|						  1 : Tor counter enabled    |
-|                     unsigned char *_ pb_InterruptEnable : Enable or disable the      |
-|                                                 tor counter interrupt.     |
-|                                                 APCI1710_ENABLE:           |
-|                                                 Enable the tor counter     |
-|                                                 interrupt                  |
-|                                                 APCI1710_DISABLE:          |
-|                                                 Disable the tor counter    |
-|                                                 interrupt
-	pb_TimingUnit		=	(unsigned char *) &data[0];
-	pul_TimingInterval	=  (unsigned int *) &data[1];
-	pb_InputMode		=	(unsigned char *) &data[2];
-	pb_ExternGate		=	(unsigned char *) &data[3];
-	pb_CycleMode		=	(unsigned char *) &data[4];
-	pb_Enable			=	(unsigned char *) &data[5];
-	pb_InterruptEnable	=	(unsigned char *) &data[6];
-                 |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a tor counter module             |
-|                     -4: Tor counter selection is wrong                     |
-|                     -5: Tor counter not initialised see function           |
-|                         "i_APCI1710_InitTorCounter"                        |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev,
-							  struct comedi_subdevice *s,
-							  struct comedi_insn *insn,
-							  unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned char b_ModulNbr;
-	unsigned char b_TorCounter;
-	unsigned char *pb_TimingUnit;
-	unsigned int *pul_TimingInterval;
-	unsigned char *pb_InputMode;
-	unsigned char *pb_ExternGate;
-	unsigned char *pb_CycleMode;
-	unsigned char *pb_Enable;
-	unsigned char *pb_InterruptEnable;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_TorCounter = CR_CHAN(insn->chanspec);
-
-	pb_TimingUnit = (unsigned char *) &data[0];
-	pul_TimingInterval = (unsigned int *) &data[1];
-	pb_InputMode = (unsigned char *) &data[2];
-	pb_ExternGate = (unsigned char *) &data[3];
-	pb_CycleMode = (unsigned char *) &data[4];
-	pb_Enable = (unsigned char *) &data[5];
-	pb_InterruptEnable = (unsigned char *) &data[6];
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if tor counter */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
-	      /**********************************/
-			/* Test the tor counter selection */
-	      /**********************************/
-
-			if (b_TorCounter <= 1) {
-
-		 /***********************************/
-				/* Test if tor counter initialised */
-		 /***********************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 8 + (16 * b_TorCounter) +
-					(64 * b_ModulNbr));
-
-				if (dw_Status & 0x10) {
-					*pb_Enable = dw_Status & 1;
-
-		    /********************/
-					/* Get the commando */
-		    /********************/
-
-					dw_Status = inl(devpriv->s_BoardInfos.
-						ui_Address + 4 +
-						(16 * b_TorCounter) +
-						(64 * b_ModulNbr));
-
-					*pb_CycleMode =
-						(unsigned char) ((dw_Status >> 4) & 1);
-					*pb_InterruptEnable =
-						(unsigned char) ((dw_Status >> 5) & 1);
-
-		    /******************************************************/
-					/* Test if extern gate used for clock or for signal B */
-		    /******************************************************/
-
-					if (dw_Status & 0x600) {
-		       /*****************************************/
-						/* Test if extern gate used for signal B */
-		       /*****************************************/
-
-						if (dw_Status & 0x400) {
-			  /***********************/
-							/* Test if simple mode */
-			  /***********************/
-
-							if ((dw_Status & 0x7800)
-								== 0x7800) {
-								*pb_InputMode =
-									APCI1710_TOR_SIMPLE_MODE;
-							}
-
-			  /***********************/
-							/* Test if double mode */
-			  /***********************/
-
-							if ((dw_Status & 0x7800)
-								== 0x1800) {
-								*pb_InputMode =
-									APCI1710_TOR_DOUBLE_MODE;
-							}
-
-			  /**************************/
-							/* Test if quadruple mode */
-			  /**************************/
-
-							if ((dw_Status & 0x7800)
-								== 0x0000) {
-								*pb_InputMode =
-									APCI1710_TOR_QUADRUPLE_MODE;
-							}
-						}	/*  if (dw_Status & 0x400) */
-						else {
-							*pb_InputMode = 1;
-						}	/*  // if (dw_Status & 0x400) */
-
-		       /************************/
-						/* Extern gate not used */
-		       /************************/
-
-						*pb_ExternGate = 0;
-					}	/*  if (dw_Status & 0x600) */
-					else {
-						*pb_InputMode =
-							(unsigned char) ((dw_Status >> 6)
-							& 1);
-						*pb_ExternGate =
-							(unsigned char) ((dw_Status >> 7)
-							& 1);
-					}	/*  if (dw_Status & 0x600) */
-
-					*pb_TimingUnit =
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_TorCounterModuleInfo.
-						s_TorCounterInfo[b_TorCounter].
-						b_TimingUnit;
-
-					*pul_TimingInterval =
-						devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_TorCounterModuleInfo.
-						s_TorCounterInfo[b_TorCounter].
-						ul_RealTimingInterval;
-				} else {
-		    /*******************************/
-					/* Tor counter not initialised */
-		    /*******************************/
-
-					DPRINTK("Tor counter not initialised\n");
-					i_ReturnValue = -5;
-				}
-
-			}	/*  if (b_TorCounter <= 1) */
-			else {
-		 /**********************************/
-				/* Tor counter selection is wrong */
-		 /**********************************/
-
-				DPRINTK("Tor counter selection is wrong \n");
-				i_ReturnValue = -4;
-			}	/*  if (b_TorCounter <= 1) */
-		} else {
-	      /******************************************/
-			/* The module is not a tor counter module */
-	      /******************************************/
-
-			DPRINTK("The module is not a tor counter module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_ReadTorCounterValue                   |
-|                               (unsigned char_     b_BoardHandle,                    |
-|                                unsigned char_     b_ModulNbr,                       |
-|				 unsigned char_     b_TorCounter,                     |
-|                                unsigned int_    ui_TimeOut,                        |
-|                                unsigned char *_   pb_TorCounterStatus,               |
-|                                PULONG_ pul_TorCounterValue)                |
-+----------------------------------------------------------------------------+
-| Task        	case APCI1710_TOR_GETPROGRESSSTATUS: Return the tor counter
-(b_TorCounter) status (pb_TorCounterStatus) from selected tor counter        |
-|		      module (b_ModulNbr).
-
-				 case APCI1710_TOR_GETCOUNTERVALUE :
-  Return the tor counter (b_TorCounter) status           |
-|		      (pb_TorCounterStatus) and the timing value             |
-|		      (pul_TorCounterValue) after a conting cycle stop       |
-|                     from selected tor counter module (b_ModulNbr).         |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle  : Handle of board APCI-1710       |
-|                     unsigned char_ b_ModulNbr     : Selected module number (0 to 3) |
-|                     unsigned char_ b_TorCounter   : Tor counter selection (0 or 1).
-	b_ModulNbr    = CR_AREF(insn->chanspec);
-	b_ReadType    = (unsigned char) data[0];
-	b_TorCounter  =	(unsigned char) data[1];
-	ui_TimeOut	  = (unsigned int) data[2]; |
-+----------------------------------------------------------------------------+
-| Output Parameters : unsigned char *_  pb_TorCounterStatus : Return the tor counter   |
-|                                                    status.                 |
-|                                               0 : Conting cycle not started|
-|                                                   Software gate not set.   |
-|                                               1 : Conting cycle started.   |
-|                                                   Software gate set.       |
-|                                               2 : Conting cycle stopped.   |
-|                                                   The conting cycle is     |
-|                                                   terminate.               |
-|                                               3 : A overflow occur. You    |
-|                                                   must change the base     |
-|                                                   timing witch the         |
-|                                                   function                 |
-|                                                 "i_APCI1710_InitTorCounter"|
-|						4 : Timeeout occur           |
-|                     unsigned int *  pul_TorCounterValue  : Tor counter value.
-	pb_TorCounterStatus=(unsigned char *) &data[0];
-	pul_TorCounterValue=(unsigned int *) &data[1];    |
-+----------------------------------------------------------------------------+
-| Return Value      :  0: No error                                           |
-|                     -1: The handle parameter of the board is wrong         |
-|                     -2: Module selection wrong                             |
-|                     -3: The module is not a tor counter module             |
-|                     -4: Tor counter selection is wrong                     |
-|                     -5: Tor counter not initialised see function           |
-|                         "i_APCI1710_InitTorCounter"                        |
-|                     -6: Tor counter not enabled see function               |
-|                         "i_APCI1710_EnableTorCounter"                      |
-|                     -7: Timeout parameter is wrong (0 to 65535)            |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev,
-								  struct comedi_subdevice *s,
-								  struct comedi_insn *insn,
-								  unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_Status;
-	unsigned int dw_TimeOut = 0;
-	unsigned char b_ModulNbr;
-	unsigned char b_TorCounter;
-	unsigned char b_ReadType;
-	unsigned int ui_TimeOut;
-	unsigned char *pb_TorCounterStatus;
-	unsigned int *pul_TorCounterValue;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_ReadType = (unsigned char) data[0];
-	b_TorCounter = (unsigned char) data[1];
-	ui_TimeOut = (unsigned int) data[2];
-	pb_TorCounterStatus = (unsigned char *) &data[0];
-	pul_TorCounterValue = (unsigned int *) &data[1];
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ReadType == APCI1710_TOR_READINTERRUPT) {
-
-		data[0] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].b_OldModuleMask;
-		data[1] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].ul_OldInterruptMask;
-		data[2] = devpriv->s_InterruptParameters.
-			s_FIFOInterruptParameters[devpriv->
-			s_InterruptParameters.ui_Read].ul_OldCounterLatchValue;
-
-			   /**************************/
-		/* Increment the read FIFO */
-			   /***************************/
-
-		devpriv->
-			s_InterruptParameters.
-			ui_Read = (devpriv->
-			s_InterruptParameters.
-			ui_Read + 1) % APCI1710_SAVE_INTERRUPT;
-
-		return insn->n;
-	}
-
-	if (b_ModulNbr < 4) {
-	   /***********************/
-		/* Test if tor counter */
-	   /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
-	      /**********************************/
-			/* Test the tor counter selection */
-	      /**********************************/
-
-			if (b_TorCounter <= 1) {
-		 /***********************************/
-				/* Test if tor counter initialised */
-		 /***********************************/
-
-				dw_Status = inl(devpriv->s_BoardInfos.
-					ui_Address + 8 + (16 * b_TorCounter) +
-					(64 * b_ModulNbr));
-
-		 /*******************************/
-				/* Test if counter initialised */
-		 /*******************************/
-
-				if (dw_Status & 0x10) {
-		    /***************************/
-					/* Test if counter enabled */
-		    /***************************/
-
-					if (dw_Status & 0x1) {
-
-						switch (b_ReadType) {
-
-						case APCI1710_TOR_GETPROGRESSSTATUS:
-		       /*******************/
-							/* Read the status */
-		       /*******************/
-
-							dw_Status =
-								inl(devpriv->
-								s_BoardInfos.
-								ui_Address + 4 +
-								(16 * b_TorCounter) + (64 * b_ModulNbr));
-
-							dw_Status =
-								dw_Status & 0xF;
-
-		       /*****************/
-							/* Test if start */
-		       /*****************/
-
-							if (dw_Status & 1) {
-								if (dw_Status &
-									2) {
-									if (dw_Status & 4) {
-				/************************/
-										/* Tor counter overflow */
-				/************************/
-
-										*pb_TorCounterStatus
-											=
-											3;
-									} else {
-				/***********************/
-										/* Tor counter started */
-				/***********************/
-
-										*pb_TorCounterStatus
-											=
-											2;
-									}
-								} else {
-			     /***********************/
-									/* Tor counter started */
-			     /***********************/
-
-									*pb_TorCounterStatus
-										=
-										1;
-								}
-							} else {
-			  /***************************/
-								/* Tor counter not started */
-			  /***************************/
-
-								*pb_TorCounterStatus
-									= 0;
-							}
-							break;
-
-						case APCI1710_TOR_GETCOUNTERVALUE:
-
-		       /*****************************/
-							/* Test the timout parameter */
-		       /*****************************/
-
-							if ((ui_TimeOut >= 0)
-								&& (ui_TimeOut
-									<=
-									65535UL))
-							{
-								for (;;) {
-			     /*******************/
-									/* Read the status */
-			     /*******************/
-
-									dw_Status
-										=
-										inl
-										(devpriv->
-										s_BoardInfos.
-										ui_Address
-										+
-										4
-										+
-										(16 * b_TorCounter) + (64 * b_ModulNbr));
-			     /********************/
-									/* Test if overflow */
-			     /********************/
-
-									if ((dw_Status & 4) == 4) {
-				/******************/
-										/* Overflow occur */
-				/******************/
-
-										*pb_TorCounterStatus
-											=
-											3;
-
-				/******************/
-										/* Read the value */
-				/******************/
-
-										*pul_TorCounterValue
-											=
-											inl
-											(devpriv->
-											s_BoardInfos.
-											ui_Address
-											+
-											0
-											+
-											(16 * b_TorCounter) + (64 * b_ModulNbr));
-										break;
-									}	/*  if ((dw_Status & 4) == 4) */
-									else {
-				/*******************************/
-										/* Test if measurement stopped */
-				/*******************************/
-
-										if ((dw_Status & 2) == 2) {
-				   /***********************/
-											/* A stop signal occur */
-				   /***********************/
-
-											*pb_TorCounterStatus
-												=
-												2;
-
-				   /******************/
-											/* Read the value */
-				   /******************/
-
-											*pul_TorCounterValue
-												=
-												inl
-												(devpriv->
-												s_BoardInfos.
-												ui_Address
-												+
-												0
-												+
-												(16 * b_TorCounter) + (64 * b_ModulNbr));
-
-											break;
-										}	/*  if ((dw_Status & 2) == 2) */
-										else {
-				   /*******************************/
-											/* Test if measurement started */
-				   /*******************************/
-
-											if ((dw_Status & 1) == 1) {
-				      /************************/
-												/* A start signal occur */
-				      /************************/
-
-												*pb_TorCounterStatus
-													=
-													1;
-											}	/*  if ((dw_Status & 1) == 1) */
-											else {
-				      /***************************/
-												/* Measurement not started */
-				      /***************************/
-
-												*pb_TorCounterStatus
-													=
-													0;
-											}	/*  if ((dw_Status & 1) == 1) */
-										}	/*  if ((dw_Status & 2) == 2) */
-									}	/*  if ((dw_Status & 8) == 8) */
-
-									if (dw_TimeOut == ui_TimeOut) {
-				/*****************/
-										/* Timeout occur */
-				/*****************/
-
-										break;
-									} else {
-				/*************************/
-										/* Increment the timeout */
-				/*************************/
-
-										dw_TimeOut
-											=
-											dw_TimeOut
-											+
-											1;
-
-										mdelay(1000);
-									}
-								}	/*  for (;;) */
-
-			  /*************************/
-								/* Test if timeout occur */
-			  /*************************/
-
-								if ((*pb_TorCounterStatus != 3) && (dw_TimeOut == ui_TimeOut) && (ui_TimeOut != 0)) {
-			     /*****************/
-									/* Timeout occur */
-			     /*****************/
-
-									*pb_TorCounterStatus
-										=
-										4;
-								}
-							} else {
-			  /******************************/
-								/* Timeout parameter is wrong */
-			  /******************************/
-
-								DPRINTK("Timeout parameter is wrong\n");
-								i_ReturnValue =
-									-7;
-							}
-							break;
-
-						default:
-							printk("Inputs wrong\n");
-						}	/*  switch end */
-					}	/*  if (dw_Status & 0x1) */
-					else {
-		       /***************************/
-						/* Tor counter not enabled */
-		       /***************************/
-
-						DPRINTK("Tor counter not enabled\n");
-						i_ReturnValue = -6;
-					}	/*  if (dw_Status & 0x1) */
-				} else {
-		    /*******************************/
-					/* Tor counter not initialised */
-		    /*******************************/
-
-					DPRINTK("Tor counter not initialised\n");
-					i_ReturnValue = -5;
-				}
-			}	/*  if (b_TorCounter <= 1) */
-			else {
-		 /**********************************/
-				/* Tor counter selection is wrong */
-		 /**********************************/
-
-				DPRINTK("Tor counter selection is wrong\n");
-				i_ReturnValue = -4;
-			}	/*  if (b_TorCounter <= 1) */
-		} else {
-	      /******************************************/
-			/* The module is not a tor counter module */
-	      /******************************************/
-
-			DPRINTK("The module is not a tor counter module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
deleted file mode 100644
index fb56360..0000000
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c
+++ /dev/null
@@ -1,1044 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-----------------------------------------------------------------------+
-  | Project     : API APCI1710    | Compiler : gcc                        |
-  | Module name : TTL.C           | Version  : 2.96                       |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date     :  02/12/2002                |
-  +-----------------------------------------------------------------------+
-  | Description :   APCI-1710 TTL I/O module                              |
-  |                                                                       |
-  |                                                                       |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +-----------------------------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  | 13/05/98 | S. Weber  | TTL digital input / output implementation      |
-  |----------|-----------|------------------------------------------------|
-  | 08/05/00 | Guinot C  | - 0400/0228 All Function in RING 0             |
-  |          |           |   available                                    |
-  +-----------------------------------------------------------------------+
-  |          |           |                                                |
-  |          |           |                                                |
-  +-----------------------------------------------------------------------+
-*/
-
-#define APCI1710_TTL_INIT		0
-#define APCI1710_TTL_INITDIRECTION	1
-
-#define APCI1710_TTL_READCHANNEL	0
-#define APCI1710_TTL_READPORT		1
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_InitTTLIODirection                    |
-|                               (unsigned char_    b_BoardHandle,                     |
-|				 unsigned char_    b_ModulNbr,                        |
-|				 unsigned char_    b_PortAMode,                       |
-|				 unsigned char_    b_PortBMode,                       |
-|				 unsigned char_    b_PortCMode,                       |
-|				 unsigned char_    b_PortDMode)                       |
-+----------------------------------------------------------------------------+
-| Task           APCI1710_TTL_INIT (using defaults)   : Configure the TTL I/O operating mode from selected     |
-|                     module  (b_ModulNbr). You must calling this function be|
-|                     for you call any other function witch access of TTL.   |
-				 APCI1710_TTL_INITDIRECTION(user inputs for direction)
-
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 3)
-		b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-		b_InitType = (unsigned char) data[0];
-		b_PortAMode	= (unsigned char) data[1];
-		b_PortBMode = (unsigned char) data[2];
-		b_PortCMode = (unsigned char) data[3];
-		b_PortDMode	= (unsigned char) data[4];|
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a TTL module                      |
-|		     -4: Function not available for this version             |
-|		     -5: Port A mode selection is wrong                      |
-|		     -6: Port B mode selection is wrong                      |
-|		     -7: Port C mode selection is wrong                      |
-|		     -8: Port D mode selection is wrong                      |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev,
-					  struct comedi_subdevice *s,
-					  struct comedi_insn *insn,
-					  unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned char b_ModulNbr;
-	unsigned char b_InitType;
-	unsigned char b_PortAMode;
-	unsigned char b_PortBMode;
-	unsigned char b_PortCMode;
-	unsigned char b_PortDMode;
-
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	b_InitType = (unsigned char) data[0];
-	i_ReturnValue = insn->n;
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /**************************/
-		/* Test if TTL I/O module */
-	   /**************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TTL_IO) {
-			switch (b_InitType) {
-			case APCI1710_TTL_INIT:
-
-				devpriv->s_ModuleInfo[b_ModulNbr].
-					s_TTLIOInfo.b_TTLInit = 1;
-
-	      /***************************/
-				/* Set TTL port A to input */
-	      /***************************/
-
-				devpriv->s_ModuleInfo[b_ModulNbr].
-					s_TTLIOInfo.b_PortConfiguration[0] = 0;
-
-	      /***************************/
-				/* Set TTL port B to input */
-	      /***************************/
-
-				devpriv->s_ModuleInfo[b_ModulNbr].
-					s_TTLIOInfo.b_PortConfiguration[1] = 0;
-
-	      /***************************/
-				/* Set TTL port C to input */
-	      /***************************/
-
-				devpriv->s_ModuleInfo[b_ModulNbr].
-					s_TTLIOInfo.b_PortConfiguration[2] = 0;
-
-	      /****************************/
-				/* Set TTL port D to output */
-	      /****************************/
-
-				devpriv->s_ModuleInfo[b_ModulNbr].
-					s_TTLIOInfo.b_PortConfiguration[3] = 1;
-
-	      /*************************/
-				/* Set the configuration */
-	      /*************************/
-
-				outl(0x8,
-					devpriv->s_BoardInfos.ui_Address + 20 +
-					(64 * b_ModulNbr));
-				break;
-
-			case APCI1710_TTL_INITDIRECTION:
-
-				b_PortAMode = (unsigned char) data[1];
-				b_PortBMode = (unsigned char) data[2];
-				b_PortCMode = (unsigned char) data[3];
-				b_PortDMode = (unsigned char) data[4];
-
-	      /********************/
-				/* Test the version */
-	      /********************/
-
-				if ((devpriv->s_BoardInfos.
-						dw_MolduleConfiguration
-						[b_ModulNbr] & 0xFFFF) >=
-					0x3230) {
-		 /************************/
-					/* Test the port A mode */
-		 /************************/
-
-					if ((b_PortAMode == 0)
-						|| (b_PortAMode == 1)) {
-		    /************************/
-						/* Test the port B mode */
-		    /************************/
-
-						if ((b_PortBMode == 0)
-							|| (b_PortBMode == 1)) {
-		       /************************/
-							/* Test the port C mode */
-		       /************************/
-
-							if ((b_PortCMode == 0)
-								|| (b_PortCMode
-									== 1)) {
-			  /************************/
-								/* Test the port D mode */
-			  /************************/
-
-								if ((b_PortDMode == 0) || (b_PortDMode == 1)) {
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TTLIOInfo.
-										b_TTLInit
-										=
-										1;
-
-			     /***********************/
-									/* Set TTL port A mode */
-			     /***********************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TTLIOInfo.
-										b_PortConfiguration
-										[0]
-										=
-										b_PortAMode;
-
-			     /***********************/
-									/* Set TTL port B mode */
-			     /***********************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TTLIOInfo.
-										b_PortConfiguration
-										[1]
-										=
-										b_PortBMode;
-
-			     /***********************/
-									/* Set TTL port C mode */
-			     /***********************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TTLIOInfo.
-										b_PortConfiguration
-										[2]
-										=
-										b_PortCMode;
-
-			     /***********************/
-									/* Set TTL port D mode */
-			     /***********************/
-
-									devpriv->
-										s_ModuleInfo
-										[b_ModulNbr].
-										s_TTLIOInfo.
-										b_PortConfiguration
-										[3]
-										=
-										b_PortDMode;
-
-			     /*************************/
-									/* Set the configuration */
-			     /*************************/
-
-									outl((b_PortAMode << 0) | (b_PortBMode << 1) | (b_PortCMode << 2) | (b_PortDMode << 3), devpriv->s_BoardInfos.ui_Address + 20 + (64 * b_ModulNbr));
-								} else {
-			     /**********************************/
-									/* Port D mode selection is wrong */
-			     /**********************************/
-
-									DPRINTK("Port D mode selection is wrong\n");
-									i_ReturnValue
-										=
-										-8;
-								}
-							} else {
-			  /**********************************/
-								/* Port C mode selection is wrong */
-			  /**********************************/
-
-								DPRINTK("Port C mode selection is wrong\n");
-								i_ReturnValue =
-									-7;
-							}
-						} else {
-		       /**********************************/
-							/* Port B mode selection is wrong */
-		       /**********************************/
-
-							DPRINTK("Port B mode selection is wrong\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-		    /**********************************/
-						/* Port A mode selection is wrong */
-		    /**********************************/
-
-						DPRINTK("Port A mode selection is wrong\n");
-						i_ReturnValue = -5;
-					}
-				} else {
-		 /*******************************************/
-					/* Function not available for this version */
-		 /*******************************************/
-
-					DPRINTK("Function not available for this version\n");
-					i_ReturnValue = -4;
-				}
-				break;
-
-				DPRINTK("\n");
-			default:
-				printk("Bad Config Type\n");
-			}	/*  switch end */
-		} else {
-	      /**********************************/
-			/* The module is not a TTL module */
-	      /**********************************/
-
-			DPRINTK("The module is not a TTL module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-|                            INPUT FUNCTIONS                                 |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_   i_APCI1710_ReadTTLIOChannelValue               |
-|                                       (unsigned char_     b_BoardHandle,            |
-|                                        unsigned char_     b_ModulNbr,               |
-|                                        unsigned char_     b_SelectedPort,           |
-|                                        unsigned char_     b_InputChannel,           |
-|                                        unsigned char *_   pb_ChannelStatus)          |
-+----------------------------------------------------------------------------+
-| Task              : Read the status from selected TTL digital input        |
-|                     (b_InputChannel)
-+----------------------------------------------------------------------------+
-| Task              : Read the status from digital input port                |
-|                     (b_SelectedPort) from selected TTL module (b_ModulNbr) |
-+----------------------------------------------------------------------------+
-
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 7)       |
-|                     unsigned char_ b_SelectedPort,       : Selection from TTL I/O   |
-|                                                   port (0 to 2)            |
-|                                                      0 : Port A selection  |
-|                                                      1 : Port B selection  |
-|                                                      2 : Port C selection  |
-|                                                      3 : Port D selection  |
-|                     unsigned char_ b_InputChannel        : Selection from digital   |
-|                                                   input ( 0 to 2)
-APCI1710_TTL_READCHANNEL
-	b_ModulNbr	  = CR_AREF(insn->chanspec);
-	b_SelectedPort= CR_RANGE(insn->chanspec);
-	b_InputChannel= CR_CHAN(insn->chanspec);
-	b_ReadType	  = (unsigned char) data[0];
-
- APCI1710_TTL_READPORT|
-	b_ModulNbr	  = CR_AREF(insn->chanspec);
-	b_SelectedPort= CR_RANGE(insn->chanspec);
-	b_ReadType	  = (unsigned char) data[0];
-
-+----------------------------------------------------------------------------+
-| Output Parameters : data[0]
-
-	unsigned char *_  pb_ChannelStatus    : Digital input channel    |
-|                                                   status                   |
-|                                                   0 : Channle is not active|
-|                                                   1 : Channle is active    |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a TTL module                      |
-|                    -4: The selected TTL input port is wrong                |
-|                    -5: The selected TTL digital input is wrong             |
-|                    -6: TTL I/O not initialised                             |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev,
-					struct comedi_subdevice *s,
-					struct comedi_insn *insn,
-					unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg;
-	unsigned char b_ModulNbr;
-	unsigned char b_SelectedPort;
-	unsigned char b_InputChannel;
-	unsigned char b_ReadType;
-	unsigned char *pb_ChannelStatus;
-	unsigned char *pb_PortValue;
-
-	i_ReturnValue = insn->n;
-	b_ReadType = (unsigned char) data[0];
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_SelectedPort = CR_RANGE(insn->chanspec);
-	b_InputChannel = CR_CHAN(insn->chanspec);
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /**************************/
-		/* Test if TTL I/O module */
-	   /**************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TTL_IO) {
-			switch (b_ReadType) {
-
-			case APCI1710_TTL_READCHANNEL:
-				pb_ChannelStatus = (unsigned char *) &data[0];
-	      /********************************/
-				/* Test the TTL I/O port number */
-	      /********************************/
-
-				if (((b_SelectedPort <= 2)
-						&& ((devpriv->s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) ==
-							0x3130))
-					|| ((b_SelectedPort <= 3)
-						&& ((devpriv->s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) >=
-							0x3230))) {
-		 /******************************************/
-					/* Test the digital imnput channel number */
-		 /******************************************/
-
-					if (((b_InputChannel <= 7)
-							&& (b_SelectedPort < 3))
-						|| ((b_InputChannel <= 1)
-							&& (b_SelectedPort ==
-								3))) {
-		    /******************************************/
-						/* Test if the TTL I/O module initialised */
-		    /******************************************/
-
-						if (devpriv->
-							s_ModuleInfo
-							[b_ModulNbr].
-							s_TTLIOInfo.b_TTLInit ==
-							1) {
-		       /***********************************/
-							/* Test if TTL port used for input */
-		       /***********************************/
-
-							if (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) == 0x3130) || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) {
-			  /**************************/
-								/* Read all digital input */
-			  /**************************/
-
-								dw_StatusReg =
-									inl
-									(devpriv->
-									s_BoardInfos.
-									ui_Address
-									+
-									(64 * b_ModulNbr));
-
-								*pb_ChannelStatus
-									=
-									(unsigned char) (
-									(dw_StatusReg
-										>>
-										(8 * b_SelectedPort)) >> b_InputChannel) & 1;
-							} else {
-			  /*******************************/
-								/* Selected TTL I/O port error */
-			  /*******************************/
-
-								DPRINTK("Selected TTL I/O port error\n");
-								i_ReturnValue =
-									-4;
-							}
-						} else {
-		       /***************************/
-							/* TTL I/O not initialised */
-		       /***************************/
-
-							DPRINTK("TTL I/O not initialised\n");
-							i_ReturnValue = -6;
-						}
-					} else {
-		    /********************************/
-						/* Selected digital input error */
-		    /********************************/
-
-						DPRINTK("Selected digital input error\n");
-						i_ReturnValue = -5;
-					}
-				} else {
-		 /*******************************/
-					/* Selected TTL I/O port error */
-		 /*******************************/
-
-					DPRINTK("Selected TTL I/O port error\n");
-					i_ReturnValue = -4;
-				}
-				break;
-
-			case APCI1710_TTL_READPORT:
-				pb_PortValue = (unsigned char *) &data[0];
-			  /********************************/
-				/* Test the TTL I/O port number */
-			  /********************************/
-
-				if (((b_SelectedPort <= 2)
-						&& ((devpriv->s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) ==
-							0x3130))
-					|| ((b_SelectedPort <= 3)
-						&& ((devpriv->s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) >=
-							0x3230))) {
-		 /******************************************/
-					/* Test if the TTL I/O module initialised */
-		 /******************************************/
-
-					if (devpriv->s_ModuleInfo[b_ModulNbr].
-						s_TTLIOInfo.b_TTLInit == 1) {
-		    /***********************************/
-						/* Test if TTL port used for input */
-		    /***********************************/
-
-						if (((devpriv->s_BoardInfos.
-									dw_MolduleConfiguration
-									[b_ModulNbr]
-									&
-									0xFFFF)
-								== 0x3130)
-							|| (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) {
-		       /**************************/
-							/* Read all digital input */
-		       /**************************/
-
-							dw_StatusReg =
-								inl(devpriv->
-								s_BoardInfos.
-								ui_Address +
-								(64 * b_ModulNbr));
-
-							*pb_PortValue =
-								(unsigned char) (
-								(dw_StatusReg >>
-									(8 * b_SelectedPort)) & 0xFF);
-						} else {
-		       /*******************************/
-							/* Selected TTL I/O port error */
-		       /*******************************/
-
-							DPRINTK("Selected TTL I/O port error\n");
-							i_ReturnValue = -4;
-						}
-					} else {
-		    /***************************/
-						/* TTL I/O not initialised */
-		    /***************************/
-
-						DPRINTK("TTL I/O not initialised\n");
-						i_ReturnValue = -5;
-					}
-				} else {
-		 /*******************************/
-					/* Selected TTL I/O port error */
-		 /*******************************/
-
-					DPRINTK("Selected TTL I/O port error\n");
-					i_ReturnValue = -4;
-				}
-				break;
-
-			default:
-				printk("Bad ReadType\n");
-
-			}	/* End Switch */
-		} else {
-	      /**********************************/
-			/* The module is not a TTL module */
-	      /**********************************/
-
-			DPRINTK("The module is not a TTL module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : int i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device
-*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)              |
-+----------------------------------------------------------------------------+
-| Task              : Read the status from all digital input ports           |
-|                     (port A, port B and port C) from selected TTL          |
-|		      module (b_ModulNbr) 				     |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle         : Handle of board APCI-1710|
-|                     unsigned char_ b_ModulNbr            : Module number to         |
-|                                                   configure (0 to 3)       |
-+----------------------------------------------------------------------------+
-| Output Parameters : PULONG_  pul_PortValue      : Digital TTL inputs port  |
-|                                                   status                   |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a TTL module                      |
-|                    -4: TTL I/O not initialised                             |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev,
-						struct comedi_subdevice *s,
-						struct comedi_insn *insn,
-						unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg;
-	unsigned char b_ModulNbr;
-	unsigned int *pul_PortValue;
-
-	b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec);
-	i_ReturnValue = insn->n;
-	pul_PortValue = (unsigned int *) &data[0];
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /**************************/
-		/* Test if TTL I/O module */
-	   /**************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TTL_IO) {
-	      /******************************************/
-			/* Test if the TTL I/O module initialised */
-	      /******************************************/
-
-			if (devpriv->
-				s_ModuleInfo[b_ModulNbr].
-				s_TTLIOInfo.b_TTLInit == 1) {
-		 /**************************/
-				/* Read all digital input */
-		 /**************************/
-
-				dw_StatusReg = inl(devpriv->s_BoardInfos.
-					ui_Address + (64 * b_ModulNbr));
-
-		 /**********************/
-				/* Test if TTL Rev1.0 */
-		 /**********************/
-
-				if ((devpriv->s_BoardInfos.
-						dw_MolduleConfiguration
-						[b_ModulNbr] & 0xFFFF) ==
-					0x3130) {
-					*pul_PortValue =
-						dw_StatusReg & 0xFFFFFFUL;
-				} else {
-		    /**************************************/
-					/* Test if port A not used for output */
-		    /**************************************/
-
-					if (devpriv->s_ModuleInfo[b_ModulNbr].
-						s_TTLIOInfo.
-						b_PortConfiguration[0] == 1) {
-						*pul_PortValue =
-							dw_StatusReg &
-							0x3FFFF00UL;
-					}
-
-		    /**************************************/
-					/* Test if port B not used for output */
-		    /**************************************/
-
-					if (devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_TTLIOInfo.
-						b_PortConfiguration[1] == 1) {
-						*pul_PortValue =
-							dw_StatusReg &
-							0x3FF00FFUL;
-					}
-
-		    /**************************************/
-					/* Test if port C not used for output */
-		    /**************************************/
-
-					if (devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_TTLIOInfo.
-						b_PortConfiguration[2] == 1) {
-						*pul_PortValue =
-							dw_StatusReg &
-							0x300FFFFUL;
-					}
-
-		    /**************************************/
-					/* Test if port D not used for output */
-		    /**************************************/
-
-					if (devpriv->
-						s_ModuleInfo[b_ModulNbr].
-						s_TTLIOInfo.
-						b_PortConfiguration[3] == 1) {
-						*pul_PortValue =
-							dw_StatusReg &
-							0xFFFFFFUL;
-					}
-				}
-			} else {
-		 /***************************/
-				/* TTL I/O not initialised */
-		 /***************************/
-				DPRINTK("TTL I/O not initialised\n");
-				i_ReturnValue = -5;
-			}
-		} else {
-	      /**********************************/
-			/* The module is not a TTL module */
-	      /**********************************/
-			DPRINTK("The module is not a TTL module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
-
-/*
-+----------------------------------------------------------------------------+
-|                            OUTPUT FUNCTIONS                                |
-+----------------------------------------------------------------------------+
-*/
-
-/*
-+----------------------------------------------------------------------------+
-| Function Name     : _INT_ i_APCI1710_SetTTLIOChlOn                         |
-|                               (unsigned char_           b_BoardHandle,              |
-|                                unsigned char_           b_ModulNbr,                 |
-|                                unsigned char_           b_OutputChannel)
-int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s,
-	struct comedi_insn *insn,unsigned int *data)           |
-+----------------------------------------------------------------------------+
-| Task              : Sets or resets  the output witch has been passed with the         |
-|                     parameter b_Channel. Setting an output means setting   |
-|                     an ouput high.                                         |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char_ b_BoardHandle   : Handle of board APCI-1710      |
-|                     unsigned char_ b_ModulNbr      : Selected module number (0 to 3)|
-|                     unsigned char_ b_OutputChannel : Selection from digital output  |
-|                                             channel (0 or 1)               |
-|                                                0      : PD0                |
-|                                                1      : PD1                |
-|						 2 to 9 : PA                 |
-|						10 to 17: PB                 |
-|						18 to 25: PC                 |
-
-  b_ModulNbr	   = CR_AREF(insn->chanspec);
-	b_OutputChannel= CR_CHAN(insn->chanspec);
-	ui_State	   = data[0]; /*  ON or OFF */
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0: No error                                            |
-|                    -1: The handle parameter of the board is wrong          |
-|                    -2: The module parameter is wrong                       |
-|                    -3: The module is not a TTL I/O module                  |
-|                    -4: The selected digital output is wrong                |
-|                    -5: TTL I/O not initialised see function                |
-|                        " i_APCI1710_InitTTLIO"
-+----------------------------------------------------------------------------+
-*/
-
-static int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,
-						struct comedi_subdevice *s,
-						struct comedi_insn *insn,
-						unsigned int *data)
-{
-	struct addi_private *devpriv = dev->private;
-	int i_ReturnValue = 0;
-	unsigned int dw_StatusReg = 0;
-	unsigned char b_ModulNbr;
-	unsigned char b_OutputChannel;
-	unsigned int ui_State;
-
-	i_ReturnValue = insn->n;
-	b_ModulNbr = CR_AREF(insn->chanspec);
-	b_OutputChannel = CR_CHAN(insn->chanspec);
-	ui_State = data[0];	/*  ON or OFF */
-
-	/**************************/
-	/* Test the module number */
-	/**************************/
-
-	if (b_ModulNbr < 4) {
-	   /**************************/
-		/* Test if TTL I/O module */
-	   /**************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModulNbr] &
-				0xFFFF0000UL) == APCI1710_TTL_IO) {
-	      /******************************************/
-			/* Test if the TTL I/O module initialised */
-	      /******************************************/
-
-			if (devpriv->s_ModuleInfo[b_ModulNbr].
-				s_TTLIOInfo.b_TTLInit == 1) {
-		 /***********************************/
-				/* Test the TTL I/O channel number */
-		 /***********************************/
-
-				if (((b_OutputChannel <= 1)
-						&& ((devpriv->s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) ==
-							0x3130))
-					|| ((b_OutputChannel <= 25)
-						&& ((devpriv->s_BoardInfos.
-								dw_MolduleConfiguration
-								[b_ModulNbr] &
-								0xFFFF) >=
-							0x3230))) {
-		    /****************************************************/
-					/* Test if the selected channel is a output channel */
-		    /****************************************************/
-
-					if (((b_OutputChannel <= 1)
-							&& (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_TTLIOInfo.
-								b_PortConfiguration
-								[3] == 1))
-						|| ((b_OutputChannel >= 2)
-							&& (b_OutputChannel <=
-								9)
-							&& (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_TTLIOInfo.
-								b_PortConfiguration
-								[0] == 1))
-						|| ((b_OutputChannel >= 10)
-							&& (b_OutputChannel <=
-								17)
-							&& (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_TTLIOInfo.
-								b_PortConfiguration
-								[1] == 1))
-						|| ((b_OutputChannel >= 18)
-							&& (b_OutputChannel <=
-								25)
-							&& (devpriv->
-								s_ModuleInfo
-								[b_ModulNbr].
-								s_TTLIOInfo.
-								b_PortConfiguration
-								[2] == 1))) {
-		       /************************/
-						/* Test if PD0 selected */
-		       /************************/
-
-						if (b_OutputChannel == 0) {
-
-							outl(ui_State,
-								devpriv->
-								s_BoardInfos.
-								ui_Address +
-								(64 * b_ModulNbr));
-						} else {
-			  /************************/
-							/* Test if PD1 selected */
-			  /************************/
-
-							if (b_OutputChannel ==
-								1) {
-
-								outl(ui_State,
-									devpriv->
-									s_BoardInfos.
-									ui_Address
-									+ 4 +
-									(64 * b_ModulNbr));
-							} else {
-								b_OutputChannel
-									=
-									b_OutputChannel
-									- 2;
-
-			     /********************/
-								/* Read all channel */
-			     /********************/
-
-								dw_StatusReg =
-									inl
-									(devpriv->
-									s_BoardInfos.
-									ui_Address
-									+
-									(64 * b_ModulNbr));
-								if (ui_State)	/*  ON */
-								{
-									dw_StatusReg
-										=
-										(dw_StatusReg
-										>>
-										((b_OutputChannel / 8) * 8)) & 0xFF;
-									dw_StatusReg
-										=
-										dw_StatusReg
-										|
-										(1
-										<<
-										(b_OutputChannel
-											%
-											8));
-								} else	/*  Off */
-								{
-									dw_StatusReg
-										=
-										(dw_StatusReg
-										>>
-										((b_OutputChannel / 8) * 8)) & 0xFF;
-									dw_StatusReg
-										=
-										dw_StatusReg
-										&
-										(0xFF
-										-
-										(1 << (b_OutputChannel % 8)));
-
-								}
-
-			     /****************************/
-								/* Set the new output value */
-			     /****************************/
-
-								outl(dw_StatusReg, devpriv->s_BoardInfos.ui_Address + 8 + ((b_OutputChannel / 8) * 4) + (64 * b_ModulNbr));
-							}
-						}
-					} else {
-		       /************************************/
-						/* The selected TTL output is wrong */
-		       /************************************/
-
-						DPRINTK(" The selected TTL output is wrong\n");
-						i_ReturnValue = -4;
-					}
-				} else {
-		    /************************************/
-					/* The selected TTL output is wrong */
-		    /************************************/
-
-					DPRINTK("The selected TTL output is wrong\n");
-					i_ReturnValue = -4;
-				}
-			} else {
-		 /***************************/
-				/* TTL I/O not initialised */
-		 /***************************/
-
-				DPRINTK("TTL I/O not initialised\n");
-				i_ReturnValue = -5;
-			}
-		} else {
-	      /**************************************/
-			/* The module is not a TTL I/O module */
-	      /**************************************/
-
-			DPRINTK("The module is not a TTL I/O module\n");
-			i_ReturnValue = -3;
-		}
-	} else {
-	   /***********************/
-		/* Module number error */
-	   /***********************/
-
-		DPRINTK("Module number error\n");
-		i_ReturnValue = -2;
-	}
-
-	return i_ReturnValue;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index f25e008..63dff77 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -85,10 +85,9 @@
 
 	dev->board_name = this_board->pc_DriverName;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index f1be5ad..dfd1e66 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -113,150 +113,6 @@
 			  struct comedi_insn *, unsigned int *);
 };
 
-/* MODULE INFO STRUCTURE */
-
-union str_ModuleInfo {
-	/* Incremental counter infos */
-	struct {
-		union {
-			struct {
-				unsigned char b_ModeRegister1;
-				unsigned char b_ModeRegister2;
-				unsigned char b_ModeRegister3;
-				unsigned char b_ModeRegister4;
-			} s_ByteModeRegister;
-			unsigned int dw_ModeRegister1_2_3_4;
-		} s_ModeRegister;
-
-		struct {
-			unsigned int b_IndexInit:1;
-			unsigned int b_CounterInit:1;
-			unsigned int b_ReferenceInit:1;
-			unsigned int b_IndexInterruptOccur:1;
-			unsigned int b_CompareLogicInit:1;
-			unsigned int b_FrequencyMeasurementInit:1;
-			unsigned int b_FrequencyMeasurementEnable:1;
-		} s_InitFlag;
-
-	} s_SiemensCounterInfo;
-
-	/* SSI infos */
-	struct {
-		unsigned char b_SSIProfile;
-		unsigned char b_PositionTurnLength;
-		unsigned char b_TurnCptLength;
-		unsigned char b_SSIInit;
-	} s_SSICounterInfo;
-
-	/* TTL I/O infos */
-	struct {
-		unsigned char b_TTLInit;
-		unsigned char b_PortConfiguration[4];
-	} s_TTLIOInfo;
-
-	/* Digital I/O infos */
-	struct {
-		unsigned char b_DigitalInit;
-		unsigned char b_ChannelAMode;
-		unsigned char b_ChannelBMode;
-		unsigned char b_OutputMemoryEnabled;
-		unsigned int dw_OutputMemory;
-	} s_DigitalIOInfo;
-
-      /*********************/
-	/* 82X54 timer infos */
-      /*********************/
-
-	struct {
-		struct {
-			unsigned char b_82X54Init;
-			unsigned char b_InputClockSelection;
-			unsigned char b_InputClockLevel;
-			unsigned char b_OutputLevel;
-			unsigned char b_HardwareGateLevel;
-			unsigned int dw_ConfigurationWord;
-		} s_82X54TimerInfo[3];
-		unsigned char b_InterruptMask;
-	} s_82X54ModuleInfo;
-
-      /*********************/
-	/* Chronometer infos */
-      /*********************/
-
-	struct {
-		unsigned char b_ChronoInit;
-		unsigned char b_InterruptMask;
-		unsigned char b_PCIInputClock;
-		unsigned char b_TimingUnit;
-		unsigned char b_CycleMode;
-		double d_TimingInterval;
-		unsigned int dw_ConfigReg;
-	} s_ChronoModuleInfo;
-
-      /***********************/
-	/* Pulse encoder infos */
-      /***********************/
-
-	struct {
-		struct {
-			unsigned char b_PulseEncoderInit;
-		} s_PulseEncoderInfo[4];
-		unsigned int dw_SetRegister;
-		unsigned int dw_ControlRegister;
-		unsigned int dw_StatusRegister;
-	} s_PulseEncoderModuleInfo;
-
-	/* Tor conter infos */
-	struct {
-		struct {
-			unsigned char b_TorCounterInit;
-			unsigned char b_TimingUnit;
-			unsigned char b_InterruptEnable;
-			double d_TimingInterval;
-			unsigned int ul_RealTimingInterval;
-		} s_TorCounterInfo[2];
-		unsigned char b_PCIInputClock;
-	} s_TorCounterModuleInfo;
-
-	/* PWM infos */
-	struct {
-		struct {
-			unsigned char b_PWMInit;
-			unsigned char b_TimingUnit;
-			unsigned char b_InterruptEnable;
-			double d_LowTiming;
-			double d_HighTiming;
-			unsigned int ul_RealLowTiming;
-			unsigned int ul_RealHighTiming;
-		} s_PWMInfo[2];
-		unsigned char b_ClockSelection;
-	} s_PWMModuleInfo;
-
-	/* ETM infos */
-	struct {
-		struct {
-			unsigned char b_ETMEnable;
-			unsigned char b_ETMInterrupt;
-		} s_ETMInfo[2];
-		unsigned char b_ETMInit;
-		unsigned char b_TimingUnit;
-		unsigned char b_ClockSelection;
-		double d_TimingInterval;
-		unsigned int ul_Timing;
-	} s_ETMModuleInfo;
-
-	/* CDA infos */
-	struct {
-		unsigned char b_CDAEnable;
-		unsigned char b_CDAInterrupt;
-		unsigned char b_CDAInit;
-		unsigned char b_FctSelection;
-		unsigned char b_CDAReadFIFOOverflow;
-	} s_CDAModuleInfo;
-
-};
-
-/* Private structure for the addi_apci3120 driver */
 struct addi_private {
 	int iobase;
 	int i_IobaseAmcc;	/*  base+size for AMCC chip */
@@ -299,31 +155,6 @@
 	/* Pointer to the current process */
 	struct task_struct *tsk_Current;
 
-	/* Hardware board infos for 1710 */
-	struct {
-		unsigned int ui_Address;	/* Board address */
-		unsigned int ui_FlashAddress;
-		unsigned char b_InterruptNbr;	/* Board interrupt number */
-		unsigned char b_SlotNumber;	/* PCI slot number */
-		unsigned char b_BoardVersion;
-		unsigned int dw_MolduleConfiguration[4];	/* Module config */
-	} s_BoardInfos;
-
-	/* Interrupt infos */
-	struct {
-		unsigned int ul_InterruptOccur;	/* 0   : No interrupt occur */
-						/* > 0 : Interrupt occur */
-		unsigned int ui_Read;	/* Read FIFO */
-		unsigned int ui_Write;	/* Write FIFO */
-		struct {
-			unsigned char b_OldModuleMask;
-			unsigned int ul_OldInterruptMask;	/* Interrupt mask */
-			unsigned int ul_OldCounterLatchValue;	/* Interrupt counter value */
-		} s_FIFOInterruptParameters[APCI1710_SAVE_INTERRUPT];
-	} s_InterruptParameters;
-
-	union str_ModuleInfo s_ModuleInfo[4];
-
 	/* Parameters read from EEPROM overriding static board info */
 	struct {
 		int i_NbrAiChannel;	/*  num of A/D chans */
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
index dc031c4..aafc172 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c
@@ -22,6 +22,8 @@
  * for more details.
  */
 
+#include <linux/delay.h>
+
 #define NVRAM_USER_DATA_START	0x100
 
 #define NVCMD_BEGIN_READ	(0x7 << 5)	/* nvRam begin read command */
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
deleted file mode 100644
index b1a7ec1..0000000
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
+++ /dev/null
@@ -1,1314 +0,0 @@
-/**
-@verbatim
-
-Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
-
-	ADDI-DATA GmbH
-	Dieselstrasse 3
-	D-77833 Ottersweier
-	Tel: +19(0)7223/9493-0
-	Fax: +49(0)7223/9493-92
-	http://www.addi-data.com
-	info@addi-data.com
-
-This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-@endverbatim
-*/
-/*
-  +-----------------------------------------------------------------------+
-  | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
-  +-----------------------------------------------------------------------+
-  | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
-  | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
-  +-------------------------------+---------------------------------------+
-  | Project     : APCI-1710       | Compiler   : GCC                      |
-  | Module name : hwdrv_apci1710.c| Version    : 2.96                     |
-  +-------------------------------+---------------------------------------+
-  | Project manager: Eric Stolz   | Date       :  02/12/2002              |
-  +-------------------------------+---------------------------------------+
-  | Description :   Hardware Layer Access For APCI-1710                   |
-  +-----------------------------------------------------------------------+
-  |                             UPDATES                                   |
-  +----------+-----------+------------------------------------------------+
-  |   Date   |   Author  |          Description of updates                |
-  +----------+-----------+------------------------------------------------+
-  |          |           |                                                |
-  |          |           |                                                |
-  |          |           |                                                |
-  +----------+-----------+------------------------------------------------+
-*/
-
-#define COMEDI_SUBD_TTLIO		11	/* Digital Input Output But TTL */
-#define COMEDI_SUBD_PWM			12	/* Pulse width Measurement */
-#define COMEDI_SUBD_SSI			13	/* Synchronous serial interface */
-#define COMEDI_SUBD_TOR			14	/* Tor counter */
-#define COMEDI_SUBD_CHRONO		15	/* Chrono meter */
-#define COMEDI_SUBD_PULSEENCODER	16	/* Pulse Encoder INP CPT */
-#define COMEDI_SUBD_INCREMENTALCOUNTER	17	/* Incremental Counter */
-
-#define APCI1710_BOARD_NAME		"apci1710"
-#define APCI1710_BOARD_DEVICE_ID	0x818F
-#define APCI1710_ADDRESS_RANGE		256
-#define APCI1710_CONFIG_ADDRESS_RANGE	8
-#define APCI1710_INCREMENTAL_COUNTER	0x53430000UL
-#define APCI1710_SSI_COUNTER		0x53490000UL
-#define APCI1710_TTL_IO			0x544C0000UL
-#define APCI1710_DIGITAL_IO		0x44490000UL
-#define APCI1710_82X54_TIMER		0x49430000UL
-#define APCI1710_CHRONOMETER		0x43480000UL
-#define APCI1710_PULSE_ENCODER		0x495A0000UL
-#define APCI1710_TOR_COUNTER		0x544F0000UL
-#define APCI1710_PWM			0x50570000UL
-#define APCI1710_ETM			0x45540000UL
-#define APCI1710_CDA			0x43440000UL
-#define APCI1710_DISABLE		0
-#define APCI1710_ENABLE			1
-#define APCI1710_SYNCHRONOUS_MODE	1
-#define APCI1710_ASYNCHRONOUS_MODE	0
-
-#include "APCI1710_Inp_cpt.c"
-
-#include "APCI1710_Ssi.c"
-#include "APCI1710_Tor.c"
-#include "APCI1710_Ttl.c"
-#include "APCI1710_Dig_io.c"
-#include "APCI1710_82x54.c"
-#include "APCI1710_Chrono.c"
-#include "APCI1710_Pwm.c"
-#include "APCI1710_INCCPT.c"
-
-static const struct comedi_lrange range_apci1710_ttl = {
-	4, {
-		BIP_RANGE(10),
-		BIP_RANGE(5),
-		BIP_RANGE(2),
-		BIP_RANGE(1)
-	}
-};
-
-static const struct comedi_lrange range_apci1710_ssi = {
-	4, {
-		BIP_RANGE(10),
-		BIP_RANGE(5),
-		BIP_RANGE(2),
-		BIP_RANGE(1)
-	}
-};
-
-static const struct comedi_lrange range_apci1710_inccpt = {
-	4, {
-		BIP_RANGE(10),
-		BIP_RANGE(5),
-		BIP_RANGE(2),
-		BIP_RANGE(1)
-	}
-};
-
-static void i_ADDI_AttachPCI1710(struct comedi_device *dev)
-{
-	struct comedi_subdevice *s;
-	int ret = 0;
-	int n_subdevices = 9;
-
-	ret = comedi_alloc_subdevices(dev, n_subdevices);
-	if (ret)
-		return;
-
-	/*  Allocate and Initialise Timer Subdevice Structures */
-	s = &dev->subdevices[0];
-
-	s->type = COMEDI_SUBD_TIMER;
-	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 3;
-	s->maxdata = 0;
-	s->len_chanlist = 3;
-	s->range_table = &range_digital;
-	s->insn_write = i_APCI1710_InsnWriteEnableDisableTimer;
-	s->insn_read = i_APCI1710_InsnReadAllTimerValue;
-	s->insn_config = i_APCI1710_InsnConfigInitTimer;
-	s->insn_bits = i_APCI1710_InsnBitsTimer;
-
-	/*  Allocate and Initialise DIO Subdevice Structures */
-	s = &dev->subdevices[1];
-
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 7;
-	s->maxdata = 1;
-	s->len_chanlist = 7;
-	s->range_table = &range_digital;
-	s->insn_config = i_APCI1710_InsnConfigDigitalIO;
-	s->insn_read = i_APCI1710_InsnReadDigitalIOChlValue;
-	s->insn_bits = i_APCI1710_InsnBitsDigitalIOPortOnOff;
-	s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff;
-
-	/*  Allocate and Initialise Chrono Subdevice Structures */
-	s = &dev->subdevices[2];
-
-	s->type = COMEDI_SUBD_CHRONO;
-	s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 4;
-	s->maxdata = 0;
-	s->len_chanlist = 4;
-	s->range_table = &range_digital;
-	s->insn_write = i_APCI1710_InsnWriteEnableDisableChrono;
-	s->insn_read = i_APCI1710_InsnReadChrono;
-	s->insn_config = i_APCI1710_InsnConfigInitChrono;
-	s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO;
-
-	/*  Allocate and Initialise PWM Subdevice Structures */
-	s = &dev->subdevices[3];
-	s->type = COMEDI_SUBD_PWM;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 3;
-	s->maxdata = 1;
-	s->len_chanlist = 3;
-	s->range_table = &range_digital;
-	s->io_bits = 0;		/* all bits input */
-	s->insn_config = i_APCI1710_InsnConfigPWM;
-	s->insn_read = i_APCI1710_InsnReadGetPWMStatus;
-	s->insn_write = i_APCI1710_InsnWritePWM;
-	s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt;
-
-	/*  Allocate and Initialise TTLIO Subdevice Structures */
-	s = &dev->subdevices[4];
-	s->type = COMEDI_SUBD_TTLIO;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->len_chanlist = 8;
-	s->range_table = &range_apci1710_ttl;	/*  to pass arguments in range */
-	s->insn_config = i_APCI1710_InsnConfigInitTTLIO;
-	s->insn_bits = i_APCI1710_InsnBitsReadTTLIO;
-	s->insn_write = i_APCI1710_InsnWriteSetTTLIOChlOnOff;
-	s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue;
-
-	/*  Allocate and Initialise TOR Subdevice Structures */
-	s = &dev->subdevices[5];
-	s->type = COMEDI_SUBD_TOR;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->len_chanlist = 8;
-	s->range_table = &range_digital;
-	s->io_bits = 0;		/* all bits input */
-	s->insn_config = i_APCI1710_InsnConfigInitTorCounter;
-	s->insn_read = i_APCI1710_InsnReadGetTorCounterInitialisation;
-	s->insn_write = i_APCI1710_InsnWriteEnableDisableTorCounter;
-	s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue;
-
-	/*  Allocate and Initialise SSI Subdevice Structures */
-	s = &dev->subdevices[6];
-	s->type = COMEDI_SUBD_SSI;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 4;
-	s->maxdata = 1;
-	s->len_chanlist = 4;
-	s->range_table = &range_apci1710_ssi;
-	s->insn_config = i_APCI1710_InsnConfigInitSSI;
-	s->insn_read = i_APCI1710_InsnReadSSIValue;
-	s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO;
-
-	/*  Allocate and Initialise PULSEENCODER Subdevice Structures */
-	s = &dev->subdevices[7];
-	s->type = COMEDI_SUBD_PULSEENCODER;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 4;
-	s->maxdata = 1;
-	s->len_chanlist = 4;
-	s->range_table = &range_digital;
-	s->insn_config = i_APCI1710_InsnConfigInitPulseEncoder;
-	s->insn_write = i_APCI1710_InsnWriteEnableDisablePulseEncoder;
-	s->insn_bits = i_APCI1710_InsnBitsReadWritePulseEncoder;
-	s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder;
-
-	/*  Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */
-	s = &dev->subdevices[8];
-	s->type = COMEDI_SUBD_INCREMENTALCOUNTER;
-	s->subdev_flags =
-		SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON;
-	s->n_chan = 500;
-	s->maxdata = 1;
-	s->len_chanlist = 500;
-	s->range_table = &range_apci1710_inccpt;
-	s->insn_config = i_APCI1710_InsnConfigINCCPT;
-	s->insn_write = i_APCI1710_InsnWriteINCCPT;
-	s->insn_read = i_APCI1710_InsnReadINCCPT;
-	s->insn_bits = i_APCI1710_InsnBitsINCCPT;
-}
-
-static int i_APCI1710_Reset(struct comedi_device *dev)
-{
-	struct addi_private *devpriv = dev->private;
-	int ret;
-	unsigned int dw_Dummy;
-
-	/*********************************/
-	/* Read all module configuration */
-	/*********************************/
-	ret = inl(devpriv->s_BoardInfos.ui_Address + 60);
-	devpriv->s_BoardInfos.dw_MolduleConfiguration[0] = ret;
-
-	ret = inl(devpriv->s_BoardInfos.ui_Address + 124);
-	devpriv->s_BoardInfos.dw_MolduleConfiguration[1] = ret;
-
-	ret = inl(devpriv->s_BoardInfos.ui_Address + 188);
-	devpriv->s_BoardInfos.dw_MolduleConfiguration[2] = ret;
-
-	ret = inl(devpriv->s_BoardInfos.ui_Address + 252);
-	devpriv->s_BoardInfos.dw_MolduleConfiguration[3] = ret;
-
-	/*  outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60); */
-	outl(0x83838383, devpriv->s_BoardInfos.ui_Address + 0x60);
-
-	devpriv->s_BoardInfos.b_BoardVersion = 1;
-
-	/*  Enable the interrupt for the controller */
-	dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38);
-	outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38);
-
-	return 0;
-}
-
-/*
-+----------------------------------------------------------------------------+
-| Function's Name   : __void__ v_APCI1710_InterruptFunction                  |
-|				(unsigned char b_Interrupt, __CPPARGS)                |
-+----------------------------------------------------------------------------+
-| Task              : APCI-1710 interrupt function                           |
-+----------------------------------------------------------------------------+
-| Input Parameters  : unsigned char b_Interrupt : Interrupt number                    |
-+----------------------------------------------------------------------------+
-| Output Parameters : -                                                      |
-+----------------------------------------------------------------------------+
-| Return Value      : 0 : OK                                                 |
-|                    -1 : Error                                              |
-+----------------------------------------------------------------------------+
-*/
-
-static void v_APCI1710_Interrupt(int irq, void *d)
-{
-	struct comedi_device *dev = d;
-	struct addi_private *devpriv = dev->private;
-	unsigned char b_ModuleCpt = 0;
-	unsigned char b_InterruptFlag = 0;
-	unsigned char b_PWMCpt = 0;
-	unsigned char b_TorCounterCpt = 0;
-	unsigned char b_PulseIncoderCpt = 0;
-	unsigned int ui_16BitValue;
-	unsigned int ul_InterruptLatchReg = 0;
-	unsigned int ul_LatchRegisterValue = 0;
-	unsigned int ul_82X54InterruptStatus;
-	unsigned int ul_StatusRegister;
-
-	union str_ModuleInfo *ps_ModuleInfo;
-
-	printk("APCI1710 Interrupt\n");
-	for (b_ModuleCpt = 0; b_ModuleCpt < 4; b_ModuleCpt++, ps_ModuleInfo++) {
-
-		 /**************************/
-		/* 1199/0225 to 0100/0226 */
-		 /**************************/
-		ps_ModuleInfo = &devpriv->s_ModuleInfo[b_ModuleCpt];
-
-		 /***********************/
-		/* Test if 82X54 timer */
-		 /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_82X54_TIMER) {
-
-			/* printk("TIMER Interrupt Occurred\n"); */
-			ul_82X54InterruptStatus = inl(devpriv->s_BoardInfos.
-				ui_Address + 12 + (64 * b_ModuleCpt));
-
-		    /***************************/
-			/* Test if interrupt occur */
-		    /***************************/
-
-			if ((ul_82X54InterruptStatus & ps_ModuleInfo->
-					s_82X54ModuleInfo.
-					b_InterruptMask) != 0) {
-				devpriv->
-					s_InterruptParameters.
-					s_FIFOInterruptParameters[devpriv->
-					s_InterruptParameters.
-					ui_Write].
-					ul_OldInterruptMask =
-					(ul_82X54InterruptStatus &
-					ps_ModuleInfo->s_82X54ModuleInfo.
-					b_InterruptMask) << 4;
-
-				devpriv->
-					s_InterruptParameters.
-					s_FIFOInterruptParameters[devpriv->
-					s_InterruptParameters.
-					ui_Write].
-					b_OldModuleMask = 1 << b_ModuleCpt;
-
-				devpriv->
-					s_InterruptParameters.
-					s_FIFOInterruptParameters[devpriv->
-					s_InterruptParameters.
-					ui_Write].ul_OldCounterLatchValue = 0;
-
-				devpriv->
-					s_InterruptParameters.
-					ul_InterruptOccur++;
-
-		       /****************************/
-				/* Increment the write FIFO */
-		       /****************************/
-
-				devpriv->
-					s_InterruptParameters.
-					ui_Write = (devpriv->
-					s_InterruptParameters.
-					ui_Write + 1) % APCI1710_SAVE_INTERRUPT;
-
-				b_InterruptFlag = 1;
-
-			     /**********************/
-				/* Call user function */
-			     /**********************/
-				/* Send a signal to from kernel to user space */
-				send_sig(SIGIO, devpriv->tsk_Current, 0);
-
-			}	/*  if ((ul_82X54InterruptStatus & 0x7) != 0) */
-		}		/*  82X54 timer */
-
-		 /***************************/
-		/* Test if increm. counter */
-		 /***************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) {
-
-			ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
-				ui_Address + (64 * b_ModuleCpt));
-
-		    /*********************/
-			/* Test if interrupt */
-		    /*********************/
-
-			if ((ul_InterruptLatchReg & 0x22) && (ps_ModuleInfo->
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister2 & 0x80)) {
-		       /************************************/
-				/* Test if strobe latch I interrupt */
-		       /************************************/
-
-				if (ul_InterruptLatchReg & 2) {
-					ul_LatchRegisterValue =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 4 +
-						(64 * b_ModuleCpt));
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].ul_OldInterruptMask =
-						1UL;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].b_OldModuleMask =
-						1 << b_ModuleCpt;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].
-						ul_OldCounterLatchValue =
-						ul_LatchRegisterValue;
-
-					devpriv->
-						s_InterruptParameters.
-						ul_InterruptOccur++;
-
-			  /****************************/
-					/* 0899/0224 to 1199/0225   */
-			  /****************************/
-					/* Increment the write FIFO */
-		      /****************************/
-
-					devpriv->
-						s_InterruptParameters.
-						ui_Write = (devpriv->
-						s_InterruptParameters.
-						ui_Write +
-						1) % APCI1710_SAVE_INTERRUPT;
-
-					b_InterruptFlag = 1;
-
-				/**********************/
-					/* Call user function */
-				/**********************/
-					/* Send a signal to from kernel to user space */
-					send_sig(SIGIO, devpriv->tsk_Current,
-						0);
-
-				}
-
-		       /*************************************/
-				/* Test if strobe latch II interrupt */
-		       /*************************************/
-
-				if (ul_InterruptLatchReg & 0x20) {
-
-					ul_LatchRegisterValue =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 8 +
-						(64 * b_ModuleCpt));
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].ul_OldInterruptMask =
-						2UL;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].b_OldModuleMask =
-						1 << b_ModuleCpt;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].
-						ul_OldCounterLatchValue =
-						ul_LatchRegisterValue;
-
-					devpriv->
-						s_InterruptParameters.
-						ul_InterruptOccur++;
-
-			  /****************************/
-					/* 0899/0224 to 1199/0225   */
-			  /****************************/
-					/* Increment the write FIFO */
-			  /****************************/
-
-					devpriv->
-						s_InterruptParameters.
-						ui_Write = (devpriv->
-						s_InterruptParameters.
-						ui_Write +
-						1) % APCI1710_SAVE_INTERRUPT;
-
-					b_InterruptFlag = 1;
-
-			    /**********************/
-					/* Call user function */
-				/**********************/
-					/* Send a signal to from kernel to user space */
-					send_sig(SIGIO, devpriv->tsk_Current,
-						0);
-
-				}
-			}
-
-			ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
-				ui_Address + 24 + (64 * b_ModuleCpt));
-
-		    /***************************/
-			/* Test if index interrupt */
-		    /***************************/
-
-			if (ul_InterruptLatchReg & 0x8) {
-				ps_ModuleInfo->
-					s_SiemensCounterInfo.
-					s_InitFlag.b_IndexInterruptOccur = 1;
-
-				if (ps_ModuleInfo->
-					s_SiemensCounterInfo.
-					s_ModeRegister.
-					s_ByteModeRegister.
-					b_ModeRegister2 &
-					APCI1710_INDEX_AUTO_MODE) {
-
-					outl(ps_ModuleInfo->
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						dw_ModeRegister1_2_3_4,
-						devpriv->s_BoardInfos.
-						ui_Address + 20 +
-						(64 * b_ModuleCpt));
-				}
-
-		       /*****************************/
-				/* Test if interrupt enabled */
-		       /*****************************/
-
-				if ((ps_ModuleInfo->
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister3 &
-						APCI1710_ENABLE_INDEX_INT) ==
-					APCI1710_ENABLE_INDEX_INT) {
-					devpriv->s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].ul_OldInterruptMask =
-						4UL;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].b_OldModuleMask =
-						1 << b_ModuleCpt;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].
-						ul_OldCounterLatchValue =
-						ul_LatchRegisterValue;
-
-					devpriv->
-						s_InterruptParameters.
-						ul_InterruptOccur++;
-
-			  /****************************/
-					/* 0899/0224 to 1199/0225   */
-			  /****************************/
-					/* Increment the write FIFO */
-			  /****************************/
-
-					devpriv->
-						s_InterruptParameters.
-						ui_Write = (devpriv->
-						s_InterruptParameters.
-						ui_Write +
-						1) % APCI1710_SAVE_INTERRUPT;
-
-					b_InterruptFlag = 1;
-
-				/**********************/
-					/* Call user function */
-				/**********************/
-					/* Send a signal to from kernel to user space */
-					send_sig(SIGIO, devpriv->tsk_Current,
-						0);
-
-				}
-			}
-
-		    /*****************************/
-			/* Test if compare interrupt */
-		    /*****************************/
-
-			if (ul_InterruptLatchReg & 0x10) {
-		       /*****************************/
-				/* Test if interrupt enabled */
-		       /*****************************/
-
-				if ((ps_ModuleInfo->
-						s_SiemensCounterInfo.
-						s_ModeRegister.
-						s_ByteModeRegister.
-						b_ModeRegister3 &
-						APCI1710_ENABLE_COMPARE_INT) ==
-					APCI1710_ENABLE_COMPARE_INT) {
-					devpriv->s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].ul_OldInterruptMask =
-						8UL;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].b_OldModuleMask =
-						1 << b_ModuleCpt;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].
-						ul_OldCounterLatchValue =
-						ul_LatchRegisterValue;
-
-					devpriv->
-						s_InterruptParameters.
-						ul_InterruptOccur++;
-
-			  /****************************/
-					/* 0899/0224 to 1199/0225   */
-			  /****************************/
-					/* Increment the write FIFO */
-		      /****************************/
-
-					devpriv->
-						s_InterruptParameters.
-						ui_Write = (devpriv->
-						s_InterruptParameters.
-						ui_Write +
-						1) % APCI1710_SAVE_INTERRUPT;
-
-					b_InterruptFlag = 1;
-
-				/**********************/
-					/* Call user function */
-				/**********************/
-					/* Send a signal to from kernel to user space */
-					send_sig(SIGIO, devpriv->tsk_Current,
-						0);
-
-				}
-			}
-
-		    /*******************************************/
-			/* Test if frequency measurement interrupt */
-		    /*******************************************/
-
-			if (ul_InterruptLatchReg & 0x20) {
-		       /*******************/
-				/* Read the status */
-		       /*******************/
-
-				ul_StatusRegister = inl(devpriv->s_BoardInfos.
-					ui_Address + 32 + (64 * b_ModuleCpt));
-
-		       /******************/
-				/* Read the value */
-		       /******************/
-
-				ul_LatchRegisterValue =
-					inl(devpriv->s_BoardInfos.ui_Address +
-					28 + (64 * b_ModuleCpt));
-
-				switch ((ul_StatusRegister >> 1) & 3) {
-				case 0:
-			       /*************************/
-					/* Test the counter mode */
-			       /*************************/
-
-					if ((devpriv->s_ModuleInfo[b_ModuleCpt].
-							s_SiemensCounterInfo.
-							s_ModeRegister.
-							s_ByteModeRegister.
-							b_ModeRegister1 &
-							APCI1710_16BIT_COUNTER)
-						== APCI1710_16BIT_COUNTER) {
-				  /****************************************/
-						/* Test if 16-bit counter 1 pulse occur */
-				  /****************************************/
-
-						if ((ul_LatchRegisterValue &
-								0xFFFFU) != 0) {
-							ui_16BitValue =
-								(unsigned int)
-								ul_LatchRegisterValue
-								& 0xFFFFU;
-							ul_LatchRegisterValue =
-								(ul_LatchRegisterValue
-								& 0xFFFF0000UL)
-								| (0xFFFFU -
-								ui_16BitValue);
-						}
-
-				  /****************************************/
-						/* Test if 16-bit counter 2 pulse occur */
-				  /****************************************/
-
-						if ((ul_LatchRegisterValue &
-								0xFFFF0000UL) !=
-							0) {
-							ui_16BitValue =
-								(unsigned int) (
-								(ul_LatchRegisterValue
-									>> 16) &
-								0xFFFFU);
-							ul_LatchRegisterValue =
-								(ul_LatchRegisterValue
-								& 0xFFFFUL) |
-								((0xFFFFU -
-									ui_16BitValue)
-								<< 16);
-						}
-					} else {
-						if (ul_LatchRegisterValue != 0) {
-							ul_LatchRegisterValue =
-								0xFFFFFFFFUL -
-								ul_LatchRegisterValue;
-						}
-					}
-					break;
-
-				case 1:
-			       /****************************************/
-					/* Test if 16-bit counter 2 pulse occur */
-			       /****************************************/
-
-					if ((ul_LatchRegisterValue &
-							0xFFFF0000UL) != 0) {
-						ui_16BitValue =
-							(unsigned int) (
-							(ul_LatchRegisterValue
-								>> 16) &
-							0xFFFFU);
-						ul_LatchRegisterValue =
-							(ul_LatchRegisterValue &
-							0xFFFFUL) | ((0xFFFFU -
-								ui_16BitValue)
-							<< 16);
-					}
-					break;
-
-				case 2:
-			       /****************************************/
-					/* Test if 16-bit counter 1 pulse occur */
-			       /****************************************/
-
-					if ((ul_LatchRegisterValue & 0xFFFFU) !=
-						0) {
-						ui_16BitValue =
-							(unsigned int)
-							ul_LatchRegisterValue &
-							0xFFFFU;
-						ul_LatchRegisterValue =
-							(ul_LatchRegisterValue &
-							0xFFFF0000UL) | (0xFFFFU
-							- ui_16BitValue);
-					}
-					break;
-				}
-
-				devpriv->
-					s_InterruptParameters.
-					s_FIFOInterruptParameters[devpriv->
-					s_InterruptParameters.
-					ui_Write].
-					ul_OldInterruptMask = 0x10000UL;
-
-				devpriv->
-					s_InterruptParameters.
-					s_FIFOInterruptParameters[devpriv->
-					s_InterruptParameters.
-					ui_Write].
-					b_OldModuleMask = 1 << b_ModuleCpt;
-
-				devpriv->
-					s_InterruptParameters.
-					s_FIFOInterruptParameters[devpriv->
-					s_InterruptParameters.
-					ui_Write].
-					ul_OldCounterLatchValue =
-					ul_LatchRegisterValue;
-
-				devpriv->
-					s_InterruptParameters.
-					ul_InterruptOccur++;
-
-		       /****************************/
-				/* 0899/0224 to 1199/0225   */
-		       /****************************/
-				/* Increment the write FIFO */
-		       /****************************/
-
-				devpriv->
-					s_InterruptParameters.
-					ui_Write = (devpriv->
-					s_InterruptParameters.
-					ui_Write + 1) % APCI1710_SAVE_INTERRUPT;
-
-				b_InterruptFlag = 1;
-
-			     /**********************/
-				/* Call user function */
-			     /**********************/
-				/* Send a signal to from kernel to user space */
-				send_sig(SIGIO, devpriv->tsk_Current, 0);
-
-			}
-		}		/*  Incremental counter */
-
-		 /***************/
-		/* Test if CDA */
-		 /***************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_CDA) {
-		    /******************************************/
-			/* Test if CDA enable and functionality 0 */
-		    /******************************************/
-
-			if ((devpriv->s_ModuleInfo[b_ModuleCpt].
-					s_CDAModuleInfo.
-					b_CDAEnable == APCI1710_ENABLE)
-				&& (devpriv->s_ModuleInfo[b_ModuleCpt].
-					s_CDAModuleInfo.b_FctSelection == 0)) {
-		       /****************************/
-				/* Get the interrupt status */
-		       /****************************/
-
-				ul_StatusRegister = inl(devpriv->s_BoardInfos.
-					ui_Address + 16 + (64 * b_ModuleCpt));
-		       /***************************/
-				/* Test if interrupt occur */
-		       /***************************/
-
-				if (ul_StatusRegister & 1) {
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].ul_OldInterruptMask =
-						0x80000UL;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].b_OldModuleMask =
-						1 << b_ModuleCpt;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].
-						ul_OldCounterLatchValue = 0;
-
-					devpriv->
-						s_InterruptParameters.
-						ul_InterruptOccur++;
-
-			  /****************************/
-					/* Increment the write FIFO */
-			  /****************************/
-
-					devpriv->
-						s_InterruptParameters.
-						ui_Write = (devpriv->
-						s_InterruptParameters.
-						ui_Write +
-						1) % APCI1710_SAVE_INTERRUPT;
-
-					b_InterruptFlag = 1;
-
-				/**********************/
-					/* Call user function */
-				/**********************/
-
-					/* Send a signal to from kernel to user space */
-					send_sig(SIGIO, devpriv->tsk_Current,
-						0);
-
-				}	/*  if (ul_StatusRegister & 1) */
-
-			}
-		}		/*  CDA */
-
-		 /***********************/
-		/* Test if PWM counter */
-		 /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_PWM) {
-			for (b_PWMCpt = 0; b_PWMCpt < 2; b_PWMCpt++) {
-		       /*************************************/
-				/* Test if PWM interrupt initialised */
-		       /*************************************/
-
-				if (devpriv->
-					s_ModuleInfo[b_ModuleCpt].
-					s_PWMModuleInfo.
-					s_PWMInfo[b_PWMCpt].
-					b_InterruptEnable == APCI1710_ENABLE) {
-			  /*****************************/
-					/* Read the interrupt status */
-			  /*****************************/
-
-					ul_StatusRegister =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 16 +
-						(20 * b_PWMCpt) +
-						(64 * b_ModuleCpt));
-
-			  /***************************/
-					/* Test if interrupt occur */
-			  /***************************/
-
-					if (ul_StatusRegister & 0x1) {
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							ul_OldInterruptMask =
-							0x4000UL << b_PWMCpt;
-
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							b_OldModuleMask =
-							1 << b_ModuleCpt;
-
-						devpriv->
-							s_InterruptParameters.
-							ul_InterruptOccur++;
-
-			     /****************************/
-						/* Increment the write FIFO */
-			     /****************************/
-
-						devpriv->
-							s_InterruptParameters.
-							ui_Write = (devpriv->
-							s_InterruptParameters.
-							ui_Write +
-							1) %
-							APCI1710_SAVE_INTERRUPT;
-
-						b_InterruptFlag = 1;
-
-				   /**********************/
-						/* Call user function */
-				   /**********************/
-						/* Send a signal to from kernel to user space */
-						send_sig(SIGIO,
-							devpriv->tsk_Current,
-							0);
-
-					}	/*  if (ul_StatusRegister & 0x1) */
-				}	/*  if (APCI1710_ENABLE) */
-			}	/*  for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++) */
-		}		/*  PWM counter */
-
-		 /***********************/
-		/* Test if tor counter */
-		 /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_TOR_COUNTER) {
-			for (b_TorCounterCpt = 0; b_TorCounterCpt < 2;
-				b_TorCounterCpt++) {
-		       /*************************************/
-				/* Test if tor interrupt initialised */
-		       /*************************************/
-
-				if (devpriv->
-					s_ModuleInfo[b_ModuleCpt].
-					s_TorCounterModuleInfo.
-					s_TorCounterInfo[b_TorCounterCpt].
-					b_InterruptEnable == APCI1710_ENABLE) {
-			  /*****************************/
-					/* Read the interrupt status */
-			  /*****************************/
-
-					ul_StatusRegister =
-						inl(devpriv->s_BoardInfos.
-						ui_Address + 12 +
-						(16 * b_TorCounterCpt) +
-						(64 * b_ModuleCpt));
-
-			  /***************************/
-					/* Test if interrupt occur */
-			  /***************************/
-
-					if (ul_StatusRegister & 0x1) {
-			     /******************************/
-						/* Read the tor counter value */
-			     /******************************/
-
-						ul_LatchRegisterValue =
-							inl(devpriv->
-							s_BoardInfos.
-							ui_Address + 0 +
-							(16 * b_TorCounterCpt) +
-							(64 * b_ModuleCpt));
-
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							ul_OldInterruptMask =
-							0x1000UL <<
-							b_TorCounterCpt;
-
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							b_OldModuleMask =
-							1 << b_ModuleCpt;
-
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							ul_OldCounterLatchValue
-							= ul_LatchRegisterValue;
-
-						devpriv->
-							s_InterruptParameters.
-							ul_InterruptOccur++;
-
-			     /****************************/
-						/* Increment the write FIFO */
-			     /****************************/
-
-						devpriv->
-							s_InterruptParameters.
-							ui_Write = (devpriv->
-							s_InterruptParameters.
-							ui_Write +
-							1) %
-							APCI1710_SAVE_INTERRUPT;
-
-						b_InterruptFlag = 1;
-
-				   /**********************/
-						/* Call user function */
-				   /**********************/
-
-						/* Send a signal to from kernel to user space */
-						send_sig(SIGIO,
-							devpriv->tsk_Current,
-							0);
-					}	/*  if (ul_StatusRegister & 0x1) */
-				}	/*  if (APCI1710_ENABLE) */
-			}	/*  for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++) */
-		}		/*  Tor counter */
-
-		 /***********************/
-		/* Test if chronometer */
-		 /***********************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_CHRONOMETER) {
-
-			/* printk("APCI1710 Chrono Interrupt\n"); */
-		    /*****************************/
-			/* Read the interrupt status */
-		    /*****************************/
-
-			ul_InterruptLatchReg = inl(devpriv->s_BoardInfos.
-				ui_Address + 12 + (64 * b_ModuleCpt));
-
-		    /***************************/
-			/* Test if interrupt occur */
-		    /***************************/
-
-			if ((ul_InterruptLatchReg & 0x8) == 0x8) {
-		       /****************************/
-				/* Clear the interrupt flag */
-		       /****************************/
-
-				outl(0, devpriv->s_BoardInfos.
-					ui_Address + 32 + (64 * b_ModuleCpt));
-
-		       /***************************/
-				/* Test if continuous mode */
-		       /***************************/
-
-				if (ps_ModuleInfo->
-					s_ChronoModuleInfo.
-					b_CycleMode == APCI1710_ENABLE) {
-			  /********************/
-					/* Clear the status */
-			  /********************/
-
-					outl(0, devpriv->s_BoardInfos.
-						ui_Address + 36 +
-						(64 * b_ModuleCpt));
-				}
-
-		       /*************************/
-				/* Read the timing value */
-		       /*************************/
-
-				ul_LatchRegisterValue =
-					inl(devpriv->s_BoardInfos.ui_Address +
-					4 + (64 * b_ModuleCpt));
-
-		       /*****************************/
-				/* Test if interrupt enabled */
-		       /*****************************/
-
-				if (ps_ModuleInfo->
-					s_ChronoModuleInfo.b_InterruptMask) {
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].ul_OldInterruptMask =
-						0x80;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].b_OldModuleMask =
-						1 << b_ModuleCpt;
-
-					devpriv->
-						s_InterruptParameters.
-						s_FIFOInterruptParameters
-						[devpriv->s_InterruptParameters.
-						ui_Write].
-						ul_OldCounterLatchValue =
-						ul_LatchRegisterValue;
-
-					devpriv->
-						s_InterruptParameters.
-						ul_InterruptOccur++;
-
-			  /****************************/
-					/* Increment the write FIFO */
-		      /****************************/
-
-					devpriv->
-						s_InterruptParameters.
-						ui_Write = (devpriv->
-						s_InterruptParameters.
-						ui_Write +
-						1) % APCI1710_SAVE_INTERRUPT;
-
-					b_InterruptFlag = 1;
-
-				/**********************/
-					/* Call user function */
-				/**********************/
-					/* Send a signal to from kernel to user space */
-					send_sig(SIGIO, devpriv->tsk_Current,
-						0);
-
-				}
-			}
-		}		/*  Chronometer */
-
-		 /*************************/
-		/* Test if pulse encoder */
-		 /*************************/
-
-		if ((devpriv->s_BoardInfos.
-				dw_MolduleConfiguration[b_ModuleCpt] &
-				0xFFFF0000UL) == APCI1710_PULSE_ENCODER) {
-		    /****************************/
-			/* Read the status register */
-		    /****************************/
-
-			ul_StatusRegister = inl(devpriv->s_BoardInfos.
-				ui_Address + 20 + (64 * b_ModuleCpt));
-
-			if (ul_StatusRegister & 0xF) {
-				for (b_PulseIncoderCpt = 0;
-					b_PulseIncoderCpt < 4;
-					b_PulseIncoderCpt++) {
-			  /*************************************/
-					/* Test if pulse encoder initialised */
-			  /*************************************/
-
-					if ((ps_ModuleInfo->
-							s_PulseEncoderModuleInfo.
-							s_PulseEncoderInfo
-							[b_PulseIncoderCpt].
-							b_PulseEncoderInit == 1)
-						&& (((ps_ModuleInfo->s_PulseEncoderModuleInfo.dw_SetRegister >> b_PulseIncoderCpt) & 1) == 1) && (((ul_StatusRegister >> (b_PulseIncoderCpt)) & 1) == 1)) {
-						devpriv->s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							ul_OldInterruptMask =
-							0x100UL <<
-							b_PulseIncoderCpt;
-
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							b_OldModuleMask =
-							1 << b_ModuleCpt;
-
-						devpriv->
-							s_InterruptParameters.
-							s_FIFOInterruptParameters
-							[devpriv->
-							s_InterruptParameters.
-							ui_Write].
-							ul_OldCounterLatchValue
-							= ul_LatchRegisterValue;
-
-						devpriv->
-							s_InterruptParameters.
-							ul_InterruptOccur++;
-
-			     /****************************/
-						/* 0899/0224 to 1199/0225   */
-			     /****************************/
-						/* Increment the write FIFO */
-			     /****************************/
-
-						devpriv->
-							s_InterruptParameters.
-							ui_Write = (devpriv->
-							s_InterruptParameters.
-							ui_Write +
-							1) %
-							APCI1710_SAVE_INTERRUPT;
-
-						b_InterruptFlag = 1;
-
-				   /**********************/
-						/* Call user function */
-				   /**********************/
-						/* Send a signal to from kernel to user space */
-						send_sig(SIGIO,
-							devpriv->tsk_Current,
-							0);
-
-					}
-				}
-			}
-		}		/* pulse encoder */
-
-	}
-	return;
-
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index a89e505..1449b92 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -40,6 +40,8 @@
   +----------+-----------+------------------------------------------------+
 */
 
+#include <linux/delay.h>
+
 /*
  * ADDON RELATED ADDITIONS
  */
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index 43c2c10..8d229b2 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index 8a93542..34ab067 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -22,6 +22,7 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -289,10 +290,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index b52cfe0..ae9ded6 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index b626738..08674c1 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -22,6 +22,7 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -136,10 +137,9 @@
 	dev->board_ptr = this_board;
 	dev->board_name = this_board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 22bace6..c5717d6 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index 1f7bed9..9652374 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -22,6 +22,7 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -59,36 +60,22 @@
 				struct comedi_insn *insn,
 				unsigned int *data)
 {
-	unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
-	unsigned int bits;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	/*
-	 * Each 8-bit "port" is configurable as either input or
-	 * output. Changing the configuration of any channel in
-	 * a port changes the entire port.
-	 */
-	if (chan_mask & 0x000000ff)
-		bits = 0x000000ff;
-	else if (chan_mask & 0x0000ff00)
-		bits = 0x0000ff00;
-	else if (chan_mask & 0x00ff0000)
-		bits = 0x00ff0000;
+	if (chan < 8)
+		mask = 0x000000ff;
+	else if (chan < 16)
+		mask = 0x0000ff00;
+	else if (chan < 24)
+		mask = 0x00ff0000;
 	else
-		bits = 0xff000000;
+		mask = 0xff000000;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_INPUT : COMEDI_OUTPUT;
-		return insn->n;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index));
 
diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c
deleted file mode 100644
index c9e6471..0000000
--- a/drivers/staging/comedi/drivers/addi_apci_1710.c
+++ /dev/null
@@ -1,99 +0,0 @@
-#include <linux/pci.h>
-
-#include <asm/i387.h>
-
-#include "../comedidev.h"
-#include "comedi_fc.h"
-#include "amcc_s5933.h"
-
-#include "addi-data/addi_common.h"
-
-static void fpu_begin(void)
-{
-	kernel_fpu_begin();
-}
-
-static void fpu_end(void)
-{
-	kernel_fpu_end();
-}
-
-#include "addi-data/addi_eeprom.c"
-#include "addi-data/hwdrv_APCI1710.c"
-
-static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
-{
-	v_APCI1710_Interrupt(irq, d);
-	return IRQ_RETVAL(1);
-}
-
-static int apci1710_auto_attach(struct comedi_device *dev,
-					  unsigned long context_unused)
-{
-	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-	struct addi_private *devpriv;
-	struct comedi_subdevice *s;
-	int ret;
-
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
-	if (!devpriv)
-		return -ENOMEM;
-	dev->private = devpriv;
-
-	ret = comedi_pci_enable(dev);
-	if (ret)
-		return ret;
-	devpriv->s_BoardInfos.ui_Address = pci_resource_start(pcidev, 2);
-
-	if (pcidev->irq > 0) {
-		ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
-				  dev->board_name, dev);
-		if (ret == 0)
-			dev->irq = pcidev->irq;
-	}
-
-	i_ADDI_AttachPCI1710(dev);
-
-	i_APCI1710_Reset(dev);
-	return 0;
-}
-
-static void apci1710_detach(struct comedi_device *dev)
-{
-	if (dev->iobase)
-		i_APCI1710_Reset(dev);
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-	comedi_pci_disable(dev);
-}
-
-static struct comedi_driver apci1710_driver = {
-	.driver_name	= "addi_apci_1710",
-	.module		= THIS_MODULE,
-	.auto_attach	= apci1710_auto_attach,
-	.detach		= apci1710_detach,
-};
-
-static int apci1710_pci_probe(struct pci_dev *dev,
-			      const struct pci_device_id *id)
-{
-	return comedi_pci_auto_config(dev, &apci1710_driver, id->driver_data);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(apci1710_pci_table) = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMCC, APCI1710_BOARD_DEVICE_ID) },
-	{ 0 }
-};
-MODULE_DEVICE_TABLE(pci, apci1710_pci_table);
-
-static struct pci_driver apci1710_pci_driver = {
-	.name		= "addi_apci_1710",
-	.id_table	= apci1710_pci_table,
-	.probe		= apci1710_pci_probe,
-	.remove		= comedi_pci_auto_unconfig,
-};
-module_comedi_pci_driver(apci1710_driver, apci1710_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index 89ead8e..6b0ea16 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -22,8 +22,10 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 
 #include "../comedidev.h"
 #include "addi_watchdog.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index ca1bd92..92ac8ec 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -22,6 +22,7 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 6145284..d804957 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -65,10 +66,9 @@
 	dev->board_ptr = this_board;
 	dev->board_name = this_board->pc_DriverName;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c
index 17b540d..1213d5a 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3200.c
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include <asm/i387.h>
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index f9b6368..d9650ff 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -22,6 +22,7 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
@@ -332,10 +333,9 @@
 	int ao_n_chan;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index 5b37cbf..cf5dd10 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -22,6 +22,7 @@
  * more details.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -685,38 +686,28 @@
 				    unsigned int *data)
 {
 	unsigned int chan = CR_CHAN(insn->chanspec);
-	unsigned int mask = 1 << chan;
-	unsigned int bits;
+	unsigned int mask;
+	int ret;
 
 	/*
 	 * Port 0 (channels 0-7) are always inputs
 	 * Port 1 (channels 8-15) are always outputs
 	 * Port 2 (channels 16-23) are programmable i/o
-	 *
-	 * Changing any channel in port 2 changes the entire port.
 	 */
-	if (mask & 0xff0000)
-		bits = 0xff0000;
-	else
-		bits = 0;
-
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-	default:
-		return -EINVAL;
+	if (chan < 16) {
+		if (data[0] != INSN_CONFIG_DIO_QUERY)
+			return -EINVAL;
+	} else {
+		/* changing any channel in port 2 changes the entire port */
+		mask = 0xff0000;
 	}
 
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
 	/* update port 2 configuration */
-	if (bits)
-		outl((s->io_bits >> 24) & 0xff, dev->iobase + 224);
+	outl((s->io_bits >> 24) & 0xff, dev->iobase + 224);
 
 	return insn->n;
 }
@@ -801,10 +792,9 @@
 	dev->board_ptr = board;
 	dev->board_name = board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c
index 7b21acc..23031fe 100644
--- a/drivers/staging/comedi/drivers/addi_watchdog.c
+++ b/drivers/staging/comedi/drivers/addi_watchdog.c
@@ -18,6 +18,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 #include "addi_watchdog.h"
 
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index b5e4e53..a67ad57 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -38,6 +38,7 @@
 	- adl_pci9118.c
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -172,10 +173,9 @@
 	dev->board_ptr = boardinfo;
 	dev->board_name = boardinfo->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index 0d9243a..81b7203 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -44,6 +44,7 @@
 Configuration Options: not applicable, uses comedi PCI auto config
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 0b591b0..b3d0092 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -27,6 +27,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index af51c74..78cea19 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -64,6 +64,7 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -855,10 +856,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL);
+	dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
 	if (!dev_private)
 		return -ENOMEM;
-	dev->private = dev_private;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index cb4ef2d..22196ad 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -77,6 +77,7 @@
  * manual attachment.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
@@ -2140,10 +2141,9 @@
 	softsshdelay = it->options[4];
 	hw_err_mask = it->options[5];
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	pcidev = pci9118_find_pci(dev, it);
 	if (!pcidev)
@@ -2160,10 +2160,9 @@
 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 	struct pci9118_private *devpriv;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	dev->board_ptr = pci9118_find_boardinfo(pcidev);
 	if (dev->board_ptr == NULL) {
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index d187a7b..cdf5ba2 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -73,6 +73,9 @@
 
 */
 
+#include <linux/module.h>
+#include <linux/delay.h>
+
 #include "../comedidev.h"
 
 /* address scheme (page 2.17 of the manual) */
@@ -214,10 +217,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->unipolar = it->options[1];
 	devpriv->differential = it->options[2];
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index f847bbc..f84df46 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -41,6 +41,7 @@
 	device will be used.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -1233,10 +1234,9 @@
 	dev->board_ptr = this_board;
 	dev->board_name = this_board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 8430a27..b793d69 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -43,6 +43,7 @@
 3. Implement calibration.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -179,38 +180,29 @@
 				   struct comedi_subdevice *s,
 				   struct comedi_insn *insn, unsigned int *data)
 {
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	unsigned int mask;
-	unsigned int bits;
-	unsigned short dio_mode;
+	unsigned short mode;
+	int ret;
 
-	mask = 1 << CR_CHAN(insn->chanspec);
-	if (mask & 0x00FF)
-		bits = 0x00FF;
+	if (chan < 8)
+		mask = 0x00ff;
 	else
-		bits = 0xFF00;
+		mask = 0xff00;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	/* update hardware DIO mode */
-	dio_mode = 0x0000;	/* low byte output, high byte output */
-	if ((s->io_bits & 0x00FF) == 0)
-		dio_mode |= 0x0001;	/* low byte input */
-	if ((s->io_bits & 0xFF00) == 0)
-		dio_mode |= 0x0002;	/* high byte input */
-	outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET);
-	return 1;
+	mode = 0x0000;			/* assume output */
+	if (!(s->io_bits & 0x00ff))
+		mode |= 0x0001;		/* low byte input */
+	if (!(s->io_bits & 0xff00))
+		mode |= 0x0002;		/* high byte input */
+	outw(mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET);
+
+	return insn->n;
 }
 
 /*
@@ -237,10 +229,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
index da7462e..009a303 100644
--- a/drivers/staging/comedi/drivers/adv_pci1724.c
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -52,6 +52,8 @@
 
 */
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -123,10 +125,6 @@
 	}
 };
 
-static const struct comedi_lrange *const ao_range_list_1724[NUM_AO_CHANNELS] = {
-	[0 ... NUM_AO_CHANNELS - 1] = &ao_ranges_1724,
-};
-
 /* this structure is for data unique to this hardware driver. */
 struct adv_pci1724_private {
 	int ao_value[NUM_AO_CHANNELS];
@@ -306,7 +304,7 @@
 	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
 	s->n_chan = NUM_AO_CHANNELS;
 	s->maxdata = 0x3fff;
-	s->range_table_list = ao_range_list_1724;
+	s->range_table = &ao_ranges_1724;
 	s->insn_read = ao_readback_insn;
 	s->insn_write = ao_winsn;
 
@@ -340,10 +338,9 @@
 	int retval;
 	unsigned int board_id;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* init software copies of output values to indicate we don't know
 	 * what the output value is since it has never been written. */
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 8e6ec75..f091fa0 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -29,6 +29,7 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 
@@ -1107,10 +1108,9 @@
 	dev->board_ptr = this_board;
 	dev->board_name = this_board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 279dfe8..abb2849 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -35,8 +35,8 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
-#include <linux/ioport.h>
 #include "8255.h"
 
 /*
@@ -202,10 +202,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 029834d..afe87cc 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -30,8 +30,8 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
-#include <linux/ioport.h>
 
 #define AIO_IIRO_16_SIZE	0x08
 #define AIO_IIRO_16_RELAY_0_7	0x00
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index e247810..dc1dee7 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -192,8 +192,7 @@
  * order they appear in the channel list.
  */
 
-#include <linux/slab.h>
-
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include "amplc_dio200.h"
@@ -272,10 +271,9 @@
 
 	irq = it->options[1];
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], thisboard->mainsize);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
index 649fc69..c1f723e 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_common.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -19,8 +19,8 @@
     GNU General Public License for more details.
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 
 #include "../comedidev.h"
 
@@ -976,34 +976,26 @@
 				     struct comedi_insn *insn,
 				     unsigned int *data)
 {
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	unsigned int mask;
-	unsigned int bits;
+	int ret;
 
-	mask = 1 << CR_CHAN(insn->chanspec);
-	if (mask & 0x0000ff)
-		bits = 0x0000ff;
-	else if (mask & 0x00ff00)
-		bits = 0x00ff00;
-	else if (mask & 0x0f0000)
-		bits = 0x0f0000;
+	if (chan < 8)
+		mask = 0x0000ff;
+	else if (chan < 16)
+		mask = 0x00ff00;
+	else if (chan < 20)
+		mask = 0x0f0000;
 	else
-		bits = 0xf00000;
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+		mask = 0xf00000;
+
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
 	dio200_subdev_8255_set_dir(dev, s);
-	return 1;
+
+	return insn->n;
 }
 
 /*
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
index d7d9f5c..a810a24 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200_pci.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
@@ -220,9 +220,9 @@
  * order they appear in the channel list.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 
 #include "../comedidev.h"
 
@@ -380,10 +380,9 @@
 	dev_info(dev->class_dev, "%s: attach pci %s (%s)\n",
 		 dev->driver->driver_name, pci_name(pci_dev), dev->board_name);
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 4e889b8..98075f9 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -47,6 +47,7 @@
 unused.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -467,10 +468,9 @@
 	struct pc236_private *devpriv;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* Process options according to bus type. */
 	if (is_isa_board(thisboard)) {
@@ -510,10 +510,9 @@
 	dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n",
 		 pci_name(pci_dev));
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	dev->board_ptr = pc236_find_pci_board(pci_dev);
 	if (dev->board_ptr == NULL) {
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 6546095..e710804 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -33,6 +33,7 @@
 The state of the outputs can be read.
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #define PC263_DRIVER_NAME	"amplc_pc263"
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index f1e36f0..179de53 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -98,6 +98,7 @@
      correctly.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -1419,10 +1420,9 @@
 
 	dev_info(dev->class_dev, DRIVER_NAME ": attach\n");
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	pci_dev = pci224_find_pci_dev(dev, it);
 	if (!pci_dev)
@@ -1440,10 +1440,9 @@
 	dev_info(dev->class_dev, DRIVER_NAME ": attach pci %s\n",
 		 pci_name(pci_dev));
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	dev->board_ptr = pci224_find_pci_board(pci_dev);
 	if (dev->board_ptr == NULL) {
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 846d644..43059c2 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -184,6 +184,7 @@
 for (or detection of) various hardware problems added by Ian Abbott.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -2615,10 +2616,9 @@
 {
 	struct pci230_private *devpriv;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	spin_lock_init(&devpriv->isr_spinlock);
 	spin_lock_init(&devpriv->res_spinlock);
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
index 4da900c..145bb48 100644
--- a/drivers/staging/comedi/drivers/amplc_pci263.c
+++ b/drivers/staging/comedi/drivers/amplc_pci263.c
@@ -32,6 +32,7 @@
 The state of the outputs can be read.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 929218a3..217aa19c 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -35,8 +35,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/timer.h>
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index ae9a208..0ce93da 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -34,8 +34,8 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
 
 #include "../comedidev.h"
@@ -341,33 +341,22 @@
 
 static int das16cs_dio_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn, unsigned int *data)
+				   struct comedi_insn *insn,
+				   unsigned int *data)
 {
 	struct das16cs_private *devpriv = dev->private;
-	int chan = CR_CHAN(insn->chanspec);
-	int bits;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
 	if (chan < 4)
-		bits = 0x0f;
+		mask = 0x0f;
 	else
-		bits = 0xf0;
+		mask = 0xf0;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	devpriv->status2 &= ~0x00c0;
 	devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0;
@@ -420,10 +409,9 @@
 		return ret;
 	dev->irq = link->irq;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 3);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 58bca18..41d89ee 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -61,6 +61,7 @@
 analog triggering on 1602 series
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -1444,10 +1445,9 @@
 	dev->board_ptr  = thisboard;
 	dev->board_name = thisboard->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 43c0bf5..388dbd7 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -82,6 +82,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -3509,31 +3510,20 @@
 
 static int dio_60xx_config_insn(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 	struct pcidas64_private *devpriv = dev->private;
-	unsigned int mask;
+	int ret;
 
-	mask = 1 << CR_CHAN(insn->chanspec);
-
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~mask;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= mask;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return 2;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
 	writeb(s->io_bits,
 	       devpriv->dio_counter_iobase + DIO_DIRECTION_60XX_REG);
 
-	return 1;
+	return insn->n;
 }
 
 static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -4034,10 +4024,9 @@
 		return -ENODEV;
 	dev->board_ptr = thisboard;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	retval = comedi_pci_enable(dev);
 	if (retval)
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 2d3e920..94f1158 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -37,6 +37,7 @@
  * Only simple analog output writing is supported.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -348,10 +349,9 @@
 	dev->board_ptr = thisboard;
 	dev->board_name = thisboard->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 8b5c198..30520d4 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -35,8 +35,8 @@
 See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
 
 #include "../comedidev.h"
@@ -210,10 +210,9 @@
 	unsigned long iobase_8255;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 406cba8c..edf17b6 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -74,6 +74,7 @@
     -Calin Culianu <calin@ajvar.org>
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -156,10 +157,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 1a51866..51a59e5 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -1,130 +1,131 @@
 /*
-    comedi/drivers/comedi_bond.c
-    A Comedi driver to 'bond' or merge multiple drivers and devices as one.
+ * comedi_bond.c
+ * A Comedi driver to 'bond' or merge multiple drivers and devices as one.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2005 Calin A. Culianu <calin@ajvar.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.
+ *
+ * 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.
+ */
 
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-    Copyright (C) 2005 Calin A. Culianu <calin@ajvar.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.
-
-    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.
-*/
 /*
-Driver: comedi_bond
-Description: A driver to 'bond' (merge) multiple subdevices from multiple
-	     devices together as one.
-Devices:
-Author: ds
-Updated: Mon, 10 Oct 00:18:25 -0500
-Status: works
+ * Driver: comedi_bond
+ * Description: A driver to 'bond' (merge) multiple subdevices from multiple
+ * devices together as one.
+ * Devices:
+ * Author: ds
+ * Updated: Mon, 10 Oct 00:18:25 -0500
+ * Status: works
+ *
+ * This driver allows you to 'bond' (merge) multiple comedi subdevices
+ * (coming from possibly difference boards and/or drivers) together.  For
+ * example, if you had a board with 2 different DIO subdevices, and
+ * another with 1 DIO subdevice, you could 'bond' them with this driver
+ * so that they look like one big fat DIO subdevice.  This makes writing
+ * applications slightly easier as you don't have to worry about managing
+ * different subdevices in the application -- you just worry about
+ * indexing one linear array of channel id's.
+ *
+ * Right now only DIO subdevices are supported as that's the personal itch
+ * I am scratching with this driver.  If you want to add support for AI and AO
+ * subdevs, go right on ahead and do so!
+ *
+ * Commands aren't supported -- although it would be cool if they were.
+ *
+ * Configuration Options:
+ *   List of comedi-minors to bond.  All subdevices of the same type
+ *   within each minor will be concatenated together in the order given here.
+ */
 
-This driver allows you to 'bond' (merge) multiple comedi subdevices
-(coming from possibly difference boards and/or drivers) together.  For
-example, if you had a board with 2 different DIO subdevices, and
-another with 1 DIO subdevice, you could 'bond' them with this driver
-so that they look like one big fat DIO subdevice.  This makes writing
-applications slightly easier as you don't have to worry about managing
-different subdevices in the application -- you just worry about
-indexing one linear array of channel id's.
-
-Right now only DIO subdevices are supported as that's the personal itch
-I am scratching with this driver.  If you want to add support for AI and AO
-subdevs, go right on ahead and do so!
-
-Commands aren't supported -- although it would be cool if they were.
-
-Configuration Options:
-  List of comedi-minors to bond.  All subdevices of the same type
-  within each minor will be concatenated together in the order given here.
-*/
-
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include "../comedi.h"
 #include "../comedilib.h"
 #include "../comedidev.h"
 
-/* The maxiumum number of channels per subdevice. */
-#define MAX_CHANS 256
-
-struct BondedDevice {
+struct bonded_device {
 	struct comedi_device *dev;
 	unsigned minor;
 	unsigned subdev;
-	unsigned subdev_type;
 	unsigned nchans;
-	unsigned chanid_offset;	/* The offset into our unified linear
-				   channel-id's of chanid 0 on this
-				   subdevice. */
 };
 
-/* this structure is for data unique to this hardware driver.  If
-   several hardware drivers keep similar information in this structure,
-   feel free to suggest moving the variable to the struct comedi_device struct.  */
 struct comedi_bond_private {
 # define MAX_BOARD_NAME 256
 	char name[MAX_BOARD_NAME];
-	struct BondedDevice **devs;
+	struct bonded_device **devs;
 	unsigned ndevs;
-	struct BondedDevice *chanIdDevMap[MAX_CHANS];
 	unsigned nchans;
 };
 
-/* DIO devices are slightly special.  Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels.  The
- * comedi core can convert between insn_bits and insn_read/write */
 static int bonding_dio_insn_bits(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
 				 struct comedi_insn *insn, unsigned int *data)
 {
 	struct comedi_bond_private *devpriv = dev->private;
-#define LSAMPL_BITS (sizeof(unsigned int)*8)
-	unsigned nchans = LSAMPL_BITS, num_done = 0, i;
+	unsigned int n_left, n_done, base_chan;
+	unsigned int write_mask, data_bits;
+	struct bonded_device **devs;
 
-	if (devpriv->nchans < nchans)
-		nchans = devpriv->nchans;
+	write_mask = data[0];
+	data_bits = data[1];
+	base_chan = CR_CHAN(insn->chanspec);
+	/* do a maximum of 32 channels, starting from base_chan. */
+	n_left = devpriv->nchans - base_chan;
+	if (n_left > 32)
+		n_left = 32;
 
-	/* The insn data is a mask in data[0] and the new data
-	 * in data[1], each channel cooresponding to a bit. */
-	for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) {
-		struct BondedDevice *bdev = devpriv->devs[i];
-		/* Grab the channel mask and data of only the bits corresponding
-		   to this subdevice.. need to shift them to zero position of
-		   course. */
-		/* Bits corresponding to this subdev. */
-		unsigned int subdevMask = ((1 << bdev->nchans) - 1);
-		unsigned int writeMask, dataBits;
+	n_done = 0;
+	devs = devpriv->devs;
+	do {
+		struct bonded_device *bdev = *devs++;
 
-		/* Argh, we have >= LSAMPL_BITS chans.. take all bits */
-		if (bdev->nchans >= LSAMPL_BITS)
-			subdevMask = (unsigned int)(-1);
+		if (base_chan < bdev->nchans) {
+			/* base channel falls within bonded device */
+			unsigned int b_chans, b_mask, b_write_mask, b_data_bits;
+			int ret;
 
-		writeMask = (data[0] >> num_done) & subdevMask;
-		dataBits = (data[1] >> num_done) & subdevMask;
-
-		/* Read/Write the new digital lines */
-		if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask,
-					&dataBits) != 2)
-			return -EINVAL;
-
-		/* Make room for the new bits in data[1], the return value */
-		data[1] &= ~(subdevMask << num_done);
-		/* Put the bits in the return value */
-		data[1] |= (dataBits & subdevMask) << num_done;
-		/* Save the new bits to the saved state.. */
-		s->state = data[1];
-
-		num_done += bdev->nchans;
-	}
+			/*
+			 * Get num channels to do for bonded device and set
+			 * up mask and data bits for bonded device.
+			 */
+			b_chans = bdev->nchans - base_chan;
+			if (b_chans > n_left)
+				b_chans = n_left;
+			b_mask = (1U << b_chans) - 1;
+			b_write_mask = (write_mask >> n_done) & b_mask;
+			b_data_bits = (data_bits >> n_done) & b_mask;
+			/* Read/Write the new digital lines. */
+			ret = comedi_dio_bitfield2(bdev->dev, bdev->subdev,
+						   b_write_mask, &b_data_bits,
+						   base_chan);
+			if (ret < 0)
+				return ret;
+			/* Place read bits into data[1]. */
+			data[1] &= ~(b_mask << n_done);
+			data[1] |= (b_data_bits & b_mask) << n_done;
+			/*
+			 * Set up for following bonded device (if still have
+			 * channels to read/write).
+			 */
+			base_chan = 0;
+			n_done += b_chans;
+			n_left -= b_chans;
+		} else {
+			/* Skip bonded devices before base channel. */
+			base_chan -= bdev->nchans;
+		}
+	} while (n_left);
 
 	return insn->n;
 }
@@ -134,99 +135,91 @@
 				   struct comedi_insn *insn, unsigned int *data)
 {
 	struct comedi_bond_private *devpriv = dev->private;
-	int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits;
-	unsigned int io;
-	struct BondedDevice *bdev;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int ret;
+	struct bonded_device *bdev;
+	struct bonded_device **devs;
 
-	if (chan < 0 || chan >= devpriv->nchans)
-		return -EINVAL;
-	bdev = devpriv->chanIdDevMap[chan];
+	/*
+	 * Locate bonded subdevice and adjust channel.
+	 */
+	devs = devpriv->devs;
+	for (bdev = *devs++; chan >= bdev->nchans; bdev = *devs++)
+		chan -= bdev->nchans;
 
-	/* The input or output configuration of each digital line is
+	/*
+	 * 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. */
+	 * configuration instruction INSN_CONFIG_DIO_OUTPUT,
+	 * INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_QUERY.
+	 *
+	 * Note that INSN_CONFIG_DIO_OUTPUT == COMEDI_OUTPUT,
+	 * and INSN_CONFIG_DIO_INPUT == COMEDI_INPUT.  This is deliberate ;)
+	 */
 	switch (data[0]) {
 	case INSN_CONFIG_DIO_OUTPUT:
-		io = COMEDI_OUTPUT;	/* is this really necessary? */
-		io_bits |= 1 << chan;
-		break;
 	case INSN_CONFIG_DIO_INPUT:
-		io = COMEDI_INPUT;	/* is this really necessary? */
-		io_bits &= ~(1 << chan);
+		ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, data[0]);
 		break;
 	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
+		ret = comedi_dio_get_config(bdev->dev, bdev->subdev, chan,
+					    &data[1]);
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 		break;
 	}
-	/* 'real' channel id for this subdev.. */
-	chan -= bdev->chanid_offset;
-	ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io);
-	if (ret != 1)
-		return -EINVAL;
-	/* Finally, save the new io_bits values since we didn't get
-	   an error above. */
-	s->io_bits = io_bits;
-	return insn->n;
+	if (ret >= 0)
+		ret = insn->n;
+	return ret;
 }
 
-static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen)
-{
-	void *newmem = kmalloc(newlen, GFP_KERNEL);
-
-	if (newmem && oldmem)
-		memcpy(newmem, oldmem, min(oldlen, newlen));
-	kfree(oldmem);
-	return newmem;
-}
-
-static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
+static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	struct comedi_bond_private *devpriv = dev->private;
+	DECLARE_BITMAP(devs_opened, COMEDI_NUM_BOARD_MINORS);
 	int i;
-	struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS];
 
-	memset(devs_opened, 0, sizeof(devs_opened));
+	memset(&devs_opened, 0, sizeof(devs_opened));
 	devpriv->name[0] = 0;
-	/* Loop through all comedi devices specified on the command-line,
-	   building our device list */
+	/*
+	 * Loop through all comedi devices specified on the command-line,
+	 * building our device list.
+	 */
 	for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) {
-		char file[] = "/dev/comediXXXXXX";
+		char file[sizeof("/dev/comediXXXXXX")];
 		int minor = it->options[i];
 		struct comedi_device *d;
-		int sdev = -1, nchans, tmp;
-		struct BondedDevice *bdev = NULL;
+		int sdev = -1, nchans;
+		struct bonded_device *bdev;
+		struct bonded_device **devs;
 
 		if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) {
 			dev_err(dev->class_dev,
 				"Minor %d is invalid!\n", minor);
-			return 0;
+			return -EINVAL;
 		}
 		if (minor == dev->minor) {
 			dev_err(dev->class_dev,
 				"Cannot bond this driver to itself!\n");
-			return 0;
+			return -EINVAL;
 		}
-		if (devs_opened[minor]) {
+		if (test_and_set_bit(minor, devs_opened)) {
 			dev_err(dev->class_dev,
 				"Minor %d specified more than once!\n", minor);
-			return 0;
+			return -EINVAL;
 		}
 
 		snprintf(file, sizeof(file), "/dev/comedi%u", minor);
 		file[sizeof(file) - 1] = 0;
 
-		d = devs_opened[minor] = comedi_open(file);
+		d = comedi_open(file);
 
 		if (!d) {
 			dev_err(dev->class_dev,
 				"Minor %u could not be opened\n", minor);
-			return 0;
+			return -ENODEV;
 		}
 
 		/* Do DIO, as that's all we support now.. */
@@ -237,45 +230,41 @@
 				dev_err(dev->class_dev,
 					"comedi_get_n_channels() returned %d on minor %u subdev %d!\n",
 					nchans, minor, sdev);
-				return 0;
+				return -EINVAL;
 			}
 			bdev = kmalloc(sizeof(*bdev), GFP_KERNEL);
 			if (!bdev)
-				return 0;
+				return -ENOMEM;
 
 			bdev->dev = d;
 			bdev->minor = minor;
 			bdev->subdev = sdev;
-			bdev->subdev_type = COMEDI_SUBD_DIO;
 			bdev->nchans = nchans;
-			bdev->chanid_offset = devpriv->nchans;
+			devpriv->nchans += nchans;
 
-			/* map channel id's to BondedDevice * pointer.. */
-			while (nchans--)
-				devpriv->chanIdDevMap[devpriv->nchans++] = bdev;
-
-			/* Now put bdev pointer at end of devpriv->devs array
-			 * list.. */
+			/*
+			 * Now put bdev pointer at end of devpriv->devs array
+			 * list..
+			 */
 
 			/* ergh.. ugly.. we need to realloc :(  */
-			tmp = devpriv->ndevs * sizeof(bdev);
-			devpriv->devs =
-			    Realloc(devpriv->devs,
-				    ++devpriv->ndevs * sizeof(bdev), tmp);
-			if (!devpriv->devs) {
+			devs = krealloc(devpriv->devs,
+					(devpriv->ndevs + 1) * sizeof(*devs),
+					GFP_KERNEL);
+			if (!devs) {
 				dev_err(dev->class_dev,
 					"Could not allocate memory. Out of memory?\n");
-				return 0;
+				return -ENOMEM;
 			}
-
-			devpriv->devs[devpriv->ndevs - 1] = bdev;
+			devpriv->devs = devs;
+			devpriv->devs[devpriv->ndevs++] = bdev;
 			{
-	/** Append dev:subdev to devpriv->name */
+				/* Append dev:subdev to devpriv->name */
 				char buf[20];
 				int left =
 				    MAX_BOARD_NAME - strlen(devpriv->name) - 1;
-				snprintf(buf, sizeof(buf), "%d:%d ", dev->minor,
-					 bdev->subdev);
+				snprintf(buf, sizeof(buf), "%d:%d ",
+					 bdev->minor, bdev->subdev);
 				buf[sizeof(buf) - 1] = 0;
 				strncat(devpriv->name, buf, left);
 			}
@@ -285,10 +274,10 @@
 
 	if (!devpriv->nchans) {
 		dev_err(dev->class_dev, "No channels found!\n");
-		return 0;
+		return -EINVAL;
 	}
 
-	return 1;
+	return 0;
 }
 
 static int bonding_attach(struct comedi_device *dev,
@@ -298,16 +287,16 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/*
 	 * Setup our bonding from config params.. sets up our private struct..
 	 */
-	if (!doDevConfig(dev, it))
-		return -EINVAL;
+	ret = do_dev_config(dev, it);
+	if (ret)
+		return ret;
 
 	dev->board_name = devpriv->name;
 
@@ -329,31 +318,29 @@
 		dev->driver->driver_name, dev->board_name,
 		devpriv->nchans, devpriv->ndevs);
 
-	return 1;
+	return 0;
 }
 
 static void bonding_detach(struct comedi_device *dev)
 {
 	struct comedi_bond_private *devpriv = dev->private;
-	unsigned long devs_closed = 0;
 
-	if (devpriv) {
-		while (devpriv->ndevs-- && devpriv->devs) {
-			struct BondedDevice *bdev;
+	if (devpriv && devpriv->devs) {
+		DECLARE_BITMAP(devs_closed, COMEDI_NUM_BOARD_MINORS);
+
+		memset(&devs_closed, 0, sizeof(devs_closed));
+		while (devpriv->ndevs--) {
+			struct bonded_device *bdev;
 
 			bdev = devpriv->devs[devpriv->ndevs];
 			if (!bdev)
 				continue;
-			if (!(devs_closed & (0x1 << bdev->minor))) {
+			if (!test_and_set_bit(bdev->minor, devs_closed))
 				comedi_close(bdev->dev);
-				devs_closed |= (0x1 << bdev->minor);
-			}
 			kfree(bdev);
 		}
 		kfree(devpriv->devs);
 		devpriv->devs = NULL;
-		kfree(devpriv);
-		dev->private = NULL;
 	}
 }
 
@@ -366,7 +353,5 @@
 module_comedi_driver(bonding_driver);
 
 MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI "
-		   "devices together as one.  In the words of John Lennon: "
-		   "'And the world will live as one...'");
+MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI devices together as one.");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c
index b3d89c8..26d9dbc 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.c
+++ b/drivers/staging/comedi/drivers/comedi_fc.c
@@ -19,6 +19,7 @@
     GNU General Public License for more details.
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include "comedi_fc.h"
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 772a8f5..f28a15f 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -76,9 +76,9 @@
    or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 #include <linux/interrupt.h>
-#include <linux/ioport.h>
 
 #include "comedi_fc.h"
 
@@ -279,10 +279,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	s = &dev->subdevices[0];
 	s->type = COMEDI_SUBD_DIO;
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 907e7a3..16c0780 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -45,6 +45,7 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include <asm/div64.h>
@@ -379,10 +380,9 @@
 	int i;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* set default amplitude and period */
 	if (amplitude <= 0)
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 0fb9027..e781716 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -25,6 +25,7 @@
 Configuration Options: not applicable, uses comedi PCI auto config
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index 44c912b..de920cc 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -102,6 +102,7 @@
 
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -683,10 +684,9 @@
 	dev->board_ptr = board;
 	dev->board_name = board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	result = comedi_pci_enable(dev);
 	if (result)
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 2e7e3e2..5f66970 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -33,7 +33,7 @@
  * cheap das08 hardware doesn't really support them.
  */
 
-#include <linux/delay.h>
+#include <linux/module.h>
 
 #include "../comedidev.h"
 
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index 885fb17..f3ccc2c 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -39,8 +39,7 @@
 Command support does not exist, but could be added for this board.
 */
 
-#include <linux/delay.h>
-#include <linux/slab.h>
+#include <linux/module.h>
 
 #include "../comedidev.h"
 
@@ -78,10 +77,9 @@
 		return ret;
 	iobase = link->resource[0]->start;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	return das08_common_attach(dev, iobase);
 }
diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c
index 21a94389..4fb03d3 100644
--- a/drivers/staging/comedi/drivers/das08_isa.c
+++ b/drivers/staging/comedi/drivers/das08_isa.c
@@ -43,6 +43,7 @@
  *	[0] - base io address
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include "das08.h"
@@ -177,10 +178,9 @@
 	struct das08_private_struct *devpriv;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], thisboard->iosize);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index 9c5d234..3a6d372 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -31,6 +31,7 @@
  * Configuration Options: not applicable, uses PCI auto config
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -59,10 +60,9 @@
 	struct das08_private_struct *devpriv;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* The das08 driver needs the board_ptr */
 	dev->board_ptr = &das08_pci_boards[0];
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index dbec3ba..1b0793f 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -1,80 +1,89 @@
 /*
-    comedi/drivers/das16.c
-    DAS16 driver
+ * das16.c
+ * DAS16 driver
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
+ * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * 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.
+ */
 
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-    Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
-    Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
-
-    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.
-*/
 /*
-Driver: das16
-Description: DAS16 compatible boards
-Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
-Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
-  DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
-  DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
-  DAS-1602 (das-1602),
-  [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
-  PC104-DAS16JR/16 (pc104-das16jr/16),
-  CIO-DAS16JR/16 (cio-das16jr/16),
-  CIO-DAS16/JR (cio-das16/jr), CIO-DAS1401/12 (cio-das1401/12),
-  CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
-  CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
-  CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
-Status: works
-Updated: 2003-10-12
+ * Driver: das16
+ * Description: DAS16 compatible boards
+ * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
+ * Devices: (Keithley Metrabyte) DAS-16 [das-16]
+ *	    (Keithley Metrabyte) DAS-16G [das-16g]
+ *	    (Keithley Metrabyte) DAS-16F [das-16f]
+ *	    (Keithley Metrabyte) DAS-1201 [das-1201]
+ *	    (Keithley Metrabyte) DAS-1202 [das-1202]
+ *	    (Keithley Metrabyte) DAS-1401 [das-1401]
+ *	    (Keithley Metrabyte) DAS-1402 [das-1402]
+ *	    (Keithley Metrabyte) DAS-1601 [das-1601]
+ *	    (Keithley Metrabyte) DAS-1602 [das-1602]
+ *	    (ComputerBoards) PC104-DAS16/JR [pc104-das16jr]
+ *	    (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16]
+ *	    (ComputerBoards) CIO-DAS16 [cio-das16]
+ *	    (ComputerBoards) CIO-DAS16F [cio-das16/f]
+ *	    (ComputerBoards) CIO-DAS16/JR [cio-das16/jr]
+ *	    (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16]
+ *	    (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12]
+ *	    (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12]
+ *	    (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16]
+ *	    (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12]
+ *	    (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12]
+ *	    (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16]
+ *	    (ComputerBoards) CIO-DAS16/330 [cio-das16/330]
+ * Status: works
+ * Updated: 2003-10-12
+ *
+ * A rewrite of the das16 and das1600 drivers.
+ *
+ * Options:
+ *	[0] - base io address
+ *	[1] - irq (does nothing, irq is not used anymore)
+ *	[2] - dma channel (optional, required for comedi_command support)
+ *	[3] - master clock speed in MHz (optional, 1 or 10, ignored if
+ *		board can probe clock, defaults to 1)
+ *	[4] - analog input range lowest voltage in microvolts (optional,
+ *		only useful if your board does not have software
+ *		programmable gain)
+ *	[5] - analog input range highest voltage in microvolts (optional,
+ *		only useful if board does not have software programmable
+ *		gain)
+ *	[6] - analog output range lowest voltage in microvolts (optional)
+ *	[7] - analog output range highest voltage in microvolts (optional)
+ *
+ * Passing a zero for an option is the same as leaving it unspecified.
+ */
 
-A rewrite of the das16 and das1600 drivers.
-Options:
-	[0] - base io address
-	[1] - irq (does nothing, irq is not used anymore)
-	[2] - dma (optional, required for comedi_command support)
-	[3] - master clock speed in MHz (optional, 1 or 10, ignored if
-		board can probe clock, defaults to 1)
-	[4] - analog input range lowest voltage in microvolts (optional,
-		only useful if your board does not have software
-		programmable gain)
-	[5] - analog input range highest voltage in microvolts (optional,
-		only useful if board does not have software programmable
-		gain)
-	[6] - analog output range lowest voltage in microvolts (optional)
-	[7] - analog output range highest voltage in microvolts (optional)
-	[8] - use timer mode for DMA.  Timer mode is needed e.g. for
-		buggy DMA controllers in NS CS5530A (Geode Companion), and for
-		'jr' cards that lack a hardware fifo.  This option is no
-		longer needed, since timer mode is _always_ used.
-
-Passing a zero for an option is the same as leaving it unspecified.
-
-*/
 /*
+ * Testing and debugging help provided by Daniel Koch.
+ *
+ * Keithley Manuals:
+ *	2309.PDF (das16)
+ *	4919.PDF (das1400, 1600)
+ *	4922.PDF (das-1400)
+ *	4923.PDF (das1200, 1400, 1600)
+ *
+ * Computer boards manuals also available from their website
+ * www.measurementcomputing.com
+ */
 
-Testing and debugging help provided by Daniel Koch.
-
-Keithley Manuals:
-	2309.PDF (das16)
-	4919.PDF (das1400, 1600)
-	4922.PDF (das-1400)
-	4923.PDF (das1200, 1400, 1600)
-
-Computer boards manuals also available from their website
-www.measurementcomputing.com
-
-*/
-
-#include <linux/pci.h>
+#include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
 #include <linux/interrupt.h>
 
 #include <asm/dma.h>
@@ -85,214 +94,112 @@
 #include "8255.h"
 #include "comedi_fc.h"
 
-#undef DEBUG
-/* #define DEBUG */
-
-#ifdef DEBUG
-#define DEBUG_PRINT(format, args...)	\
-	printk(KERN_DEBUG "das16: " format, ## args)
-#else
-#define DEBUG_PRINT(format, args...)
-#endif
-
-#define DAS16_SIZE 20		/*  number of ioports */
 #define DAS16_DMA_SIZE 0xff00	/*  size in bytes of allocated dma buffer */
 
 /*
-    cio-das16.pdf
+ * Register I/O map
+ */
+#define DAS16_TRIG_REG			0x00
+#define DAS16_AI_LSB_REG		0x00
+#define DAS16_AI_MSB_REG		0x01
+#define DAS16_MUX_REG			0x02
+#define DAS16_DIO_REG			0x03
+#define DAS16_AO_LSB_REG(x)		((x) ? 0x06 : 0x04)
+#define DAS16_AO_MSB_REG(x)		((x) ? 0x07 : 0x05)
+#define DAS16_STATUS_REG		0x08
+#define DAS16_STATUS_BUSY		(1 << 7)
+#define DAS16_STATUS_UNIPOLAR		(1 << 6)
+#define DAS16_STATUS_MUXBIT		(1 << 5)
+#define DAS16_STATUS_INT		(1 << 4)
+#define DAS16_CTRL_REG			0x09
+#define DAS16_CTRL_INTE			(1 << 7)
+#define DAS16_CTRL_IRQ(x)		(((x) & 0x7) << 4)
+#define DAS16_CTRL_DMAE			(1 << 2)
+#define DAS16_CTRL_PACING_MASK		(3 << 0)
+#define DAS16_CTRL_INT_PACER		(3 << 0)
+#define DAS16_CTRL_EXT_PACER		(2 << 0)
+#define DAS16_CTRL_SOFT_PACER		(0 << 0)
+#define DAS16_PACER_REG			0x0a
+#define DAS16_PACER_BURST_LEN(x)	(((x) & 0xf) << 4)
+#define DAS16_PACER_CTR0		(1 << 1)
+#define DAS16_PACER_TRIG0		(1 << 0)
+#define DAS16_GAIN_REG			0x0b
+#define DAS16_TIMER_BASE_REG		0x0c	/* to 0x0f */
 
-    "das16"
-    "das16/f"
+#define DAS1600_CONV_REG		0x404
+#define DAS1600_CONV_DISABLE		(1 << 6)
+#define DAS1600_BURST_REG		0x405
+#define DAS1600_BURST_VAL		(1 << 6)
+#define DAS1600_ENABLE_REG		0x406
+#define DAS1600_ENABLE_VAL		(1 << 6)
+#define DAS1600_STATUS_REG		0x407
+#define DAS1600_STATUS_BME		(1 << 6)
+#define DAS1600_STATUS_ME		(1 << 5)
+#define DAS1600_STATUS_CD		(1 << 4)
+#define DAS1600_STATUS_WS		(1 << 1)
+#define DAS1600_STATUS_CLK_10MHZ	(1 << 0)
 
-  0	a/d bits 0-3		start 12 bit
-  1	a/d bits 4-11		unused
-  2	mux read		mux set
-  3	di 4 bit		do 4 bit
-  4	unused			ao0_lsb
-  5	unused			ao0_msb
-  6	unused			ao1_lsb
-  7	unused			ao1_msb
-  8	status eoc uni/bip	interrupt reset
-  9	dma, int, trig ctrl	set dma, int
-  a	pacer control		unused
-  b	reserved		reserved
-  cdef	8254
-  0123	8255
-
-*/
-
-/*
-    cio-das16jr.pdf
-
-    "das16jr"
-
-  0	a/d bits 0-3		start 12 bit
-  1	a/d bits 4-11		unused
-  2	mux read		mux set
-  3	di 4 bit		do 4 bit
-  4567	unused			unused
-  8	status eoc uni/bip	interrupt reset
-  9	dma, int, trig ctrl	set dma, int
-  a	pacer control		unused
-  b	gain status		gain control
-  cdef	8254
-
-*/
-
-/*
-    cio-das16jr_16.pdf
-
-    "das16jr_16"
-
-  0	a/d bits 0-7		start 16 bit
-  1	a/d bits 8-15		unused
-  2	mux read		mux set
-  3	di 4 bit		do 4 bit
-  4567	unused			unused
-  8	status eoc uni/bip	interrupt reset
-  9	dma, int, trig ctrl	set dma, int
-  a	pacer control		unused
-  b	gain status		gain control
-  cdef	8254
-
-*/
-/*
-    cio-das160x-1x.pdf
-
-    "das1601/12"
-    "das1602/12"
-    "das1602/16"
-
-  0	a/d bits 0-3		start 12 bit
-  1	a/d bits 4-11		unused
-  2	mux read		mux set
-  3	di 4 bit		do 4 bit
-  4	unused			ao0_lsb
-  5	unused			ao0_msb
-  6	unused			ao1_lsb
-  7	unused			ao1_msb
-  8	status eoc uni/bip	interrupt reset
-  9	dma, int, trig ctrl	set dma, int
-  a	pacer control		unused
-  b	gain status		gain control
-  cdef	8254
-  400	8255
-  404	unused			conversion enable
-  405	unused			burst enable
-  406	unused			das1600 enable
-  407	status
-
-*/
-
-/*  size in bytes of a sample from board */
-static const int sample_size = 2;
-
-#define DAS16_TRIG		0
-#define DAS16_AI_LSB		0
-#define DAS16_AI_MSB		1
-#define DAS16_MUX		2
-#define DAS16_DIO		3
-#define DAS16_AO_LSB(x)	((x) ? 6 : 4)
-#define DAS16_AO_MSB(x)	((x) ? 7 : 5)
-#define DAS16_STATUS		8
-#define   BUSY			(1<<7)
-#define   UNIPOLAR			(1<<6)
-#define   DAS16_MUXBIT			(1<<5)
-#define   DAS16_INT			(1<<4)
-#define DAS16_CONTROL		9
-#define   DAS16_INTE			(1<<7)
-#define   DAS16_IRQ(x)			(((x) & 0x7) << 4)
-#define   DMA_ENABLE			(1<<2)
-#define   PACING_MASK	0x3
-#define   INT_PACER		0x03
-#define   EXT_PACER			0x02
-#define   DAS16_SOFT		0x00
-#define DAS16_PACER		0x0A
-#define   DAS16_CTR0			(1<<1)
-#define   DAS16_TRIG0			(1<<0)
-#define   BURST_LEN_BITS(x)			(((x) & 0xf) << 4)
-#define DAS16_GAIN		0x0B
-#define DAS16_CNTR0_DATA		0x0C
-#define DAS16_CNTR1_DATA		0x0D
-#define DAS16_CNTR2_DATA		0x0E
-#define DAS16_CNTR_CONTROL	0x0F
-#define   DAS16_TERM_CNT	0x00
-#define   DAS16_ONE_SHOT	0x02
-#define   DAS16_RATE_GEN	0x04
-#define   DAS16_CNTR_LSB_MSB	0x30
-#define   DAS16_CNTR0		0x00
-#define   DAS16_CNTR1		0x40
-#define   DAS16_CNTR2		0x80
-
-#define DAS1600_CONV		0x404
-#define   DAS1600_CONV_DISABLE		0x40
-#define DAS1600_BURST		0x405
-#define   DAS1600_BURST_VAL		0x40
-#define DAS1600_ENABLE		0x406
-#define   DAS1600_ENABLE_VAL		0x40
-#define DAS1600_STATUS_B	0x407
-#define   DAS1600_BME		0x40
-#define   DAS1600_ME		0x20
-#define   DAS1600_CD			0x10
-#define   DAS1600_WS			0x02
-#define   DAS1600_CLK_10MHZ		0x01
-
-static const struct comedi_lrange range_das1x01_bip = { 4, {
-							    BIP_RANGE(10),
-							    BIP_RANGE(1),
-							    BIP_RANGE(0.1),
-							    BIP_RANGE(0.01),
-							    }
+static const struct comedi_lrange range_das1x01_bip = {
+	4, {
+		BIP_RANGE(10),
+		BIP_RANGE(1),
+		BIP_RANGE(0.1),
+		BIP_RANGE(0.01)
+	}
 };
 
-static const struct comedi_lrange range_das1x01_unip = { 4, {
-							     UNI_RANGE(10),
-							     UNI_RANGE(1),
-							     UNI_RANGE(0.1),
-							     UNI_RANGE(0.01),
-							     }
+static const struct comedi_lrange range_das1x01_unip = {
+	4, {
+		UNI_RANGE(10),
+		UNI_RANGE(1),
+		UNI_RANGE(0.1),
+		UNI_RANGE(0.01)
+	}
 };
 
-static const struct comedi_lrange range_das1x02_bip = { 4, {
-							    BIP_RANGE(10),
-							    BIP_RANGE(5),
-							    BIP_RANGE(2.5),
-							    BIP_RANGE(1.25),
-							    }
+static const struct comedi_lrange range_das1x02_bip = {
+	4, {
+		BIP_RANGE(10),
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25)
+	}
 };
 
-static const struct comedi_lrange range_das1x02_unip = { 4, {
-							     UNI_RANGE(10),
-							     UNI_RANGE(5),
-							     UNI_RANGE(2.5),
-							     UNI_RANGE(1.25),
-							     }
+static const struct comedi_lrange range_das1x02_unip = {
+	4, {
+		UNI_RANGE(10),
+		UNI_RANGE(5),
+		UNI_RANGE(2.5),
+		UNI_RANGE(1.25)
+	}
 };
 
-static const struct comedi_lrange range_das16jr = { 9, {
-						/*  also used by 16/330 */
-							BIP_RANGE(10),
-							BIP_RANGE(5),
-							BIP_RANGE(2.5),
-							BIP_RANGE(1.25),
-							BIP_RANGE(0.625),
-							UNI_RANGE(10),
-							UNI_RANGE(5),
-							UNI_RANGE(2.5),
-							UNI_RANGE(1.25),
-							}
+static const struct comedi_lrange range_das16jr = {
+	9, {
+		BIP_RANGE(10),
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25),
+		BIP_RANGE(0.625),
+		UNI_RANGE(10),
+		UNI_RANGE(5),
+		UNI_RANGE(2.5),
+		UNI_RANGE(1.25)
+	}
 };
 
-static const struct comedi_lrange range_das16jr_16 = { 8, {
-							   BIP_RANGE(10),
-							   BIP_RANGE(5),
-							   BIP_RANGE(2.5),
-							   BIP_RANGE(1.25),
-							   UNI_RANGE(10),
-							   UNI_RANGE(5),
-							   UNI_RANGE(2.5),
-							   UNI_RANGE(1.25),
-							   }
+static const struct comedi_lrange range_das16jr_16 = {
+	8, {
+		BIP_RANGE(10),
+		BIP_RANGE(5),
+		BIP_RANGE(2.5),
+		BIP_RANGE(1.25),
+		UNI_RANGE(10),
+		UNI_RANGE(5),
+		UNI_RANGE(2.5),
+		UNI_RANGE(1.25)
+	}
 };
 
 static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
@@ -330,30 +237,211 @@
 	&range_das1x02_bip,
 };
 
-struct munge_info {
-	uint8_t byte;
-	unsigned have_byte:1;
-};
-
 struct das16_board {
 	const char *name;
-	void *ai;
-	unsigned int ai_nbits;
+	unsigned int ai_maxdata;
 	unsigned int ai_speed;	/*  max conversion speed in nanosec */
 	unsigned int ai_pg;
-	void *ao;
-	unsigned int ao_nbits;
-	void *di;
-	void *do_;
+	unsigned int has_ao:1;
+	unsigned int has_8255:1;
 
 	unsigned int i8255_offset;
-	unsigned int i8254_offset;
 
 	unsigned int size;
 	unsigned int id;
 };
 
-#define DAS16_TIMEOUT 1000
+static const struct das16_board das16_boards[] = {
+	{
+		.name		= "das-16",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 15000,
+		.ai_pg		= das16_pg_none,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x10,
+		.size		= 0x14,
+		.id		= 0x00,
+	}, {
+		.name		= "das-16g",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 15000,
+		.ai_pg		= das16_pg_none,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x10,
+		.size		= 0x14,
+		.id		= 0x00,
+	}, {
+		.name		= "das-16f",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 8500,
+		.ai_pg		= das16_pg_none,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x10,
+		.size		= 0x14,
+		.id		= 0x00,
+	}, {
+		.name		= "cio-das16",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 20000,
+		.ai_pg		= das16_pg_none,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x10,
+		.size		= 0x14,
+		.id		= 0x80,
+	}, {
+		.name		= "cio-das16/f",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_none,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x10,
+		.size		= 0x14,
+		.id		= 0x80,
+	}, {
+		.name		= "cio-das16/jr",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 7692,
+		.ai_pg		= das16_pg_16jr,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "pc104-das16jr",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 3300,
+		.ai_pg		= das16_pg_16jr,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "cio-das16jr/16",
+		.ai_maxdata	= 0xffff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_16jr_16,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "pc104-das16jr/16",
+		.ai_maxdata	= 0xffff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_16jr_16,
+		.size		= 0x10,
+		.id		= 0x00,
+	}, {
+		.name		= "das-1201",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 20000,
+		.ai_pg		= das16_pg_none,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0x20,
+	}, {
+		.name		= "das-1202",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_none,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0x20,
+	}, {
+		.name		= "das-1401",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1601,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "das-1402",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "das-1601",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1601,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "das-1602",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1401/12",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 6250,
+		.ai_pg		= das16_pg_1601,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1402/12",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 6250,
+		.ai_pg		= das16_pg_1602,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1402/16",
+		.ai_maxdata	= 0xffff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1601/12",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 6250,
+		.ai_pg		= das16_pg_1601,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1602/12",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das1602/16",
+		.ai_maxdata	= 0xffff,
+		.ai_speed	= 10000,
+		.ai_pg		= das16_pg_1602,
+		.has_ao		= 1,
+		.has_8255	= 1,
+		.i8255_offset	= 0x400,
+		.size		= 0x408,
+		.id		= 0xc0,
+	}, {
+		.name		= "cio-das16/330",
+		.ai_maxdata	= 0x0fff,
+		.ai_speed	= 3030,
+		.ai_pg		= das16_pg_16jr,
+		.size		= 0x14,
+		.id		= 0xf0,
+	},
+};
 
 /* Period for timer interrupt in jiffies.  It's a function
  * to deal with possibility of dynamic HZ patches  */
@@ -363,34 +451,155 @@
 }
 
 struct das16_private_struct {
-	unsigned int ai_unipolar;	/*  unipolar flag */
-	unsigned int ai_singleended;	/*  single ended flag */
-	unsigned int clockbase;	/*  master clock speed in ns */
-	volatile unsigned int control_state;	/*  dma, interrupt and trigger control bits */
-	volatile unsigned long adc_byte_count;	/*  number of bytes remaining */
-	/*  divisor dividing master clock to get conversion frequency */
-	unsigned int divisor1;
-	/*  divisor dividing master clock to get conversion frequency */
-	unsigned int divisor2;
-	unsigned int dma_chan;	/*  dma channel */
-	uint16_t *dma_buffer[2];
-	dma_addr_t dma_buffer_addr[2];
-	unsigned int current_buffer;
-	volatile unsigned int dma_transfer_size;	/*  target number of bytes to transfer per dma shot */
-	/**
-	 * user-defined analog input and output ranges
-	 * defined from config options
-	 */
-	struct comedi_lrange *user_ai_range_table;
-	struct comedi_lrange *user_ao_range_table;
-
-	struct timer_list timer;	/*  for timed interrupt */
-	volatile short timer_running;
-	volatile short timer_mode;	/*  true if using timer mode */
-
-	unsigned long extra_iobase;
+	unsigned int		clockbase;
+	unsigned int		ctrl_reg;
+	unsigned long		adc_byte_count;
+	unsigned int		divisor1;
+	unsigned int		divisor2;
+	unsigned int		dma_chan;
+	uint16_t		*dma_buffer[2];
+	dma_addr_t		dma_buffer_addr[2];
+	unsigned int		current_buffer;
+	unsigned int		dma_transfer_size;
+	struct comedi_lrange	*user_ai_range_table;
+	struct comedi_lrange	*user_ao_range_table;
+	struct timer_list	timer;
+	short			timer_running;
+	unsigned long		extra_iobase;
+	unsigned int		can_burst:1;
 };
 
+static void das16_ai_enable(struct comedi_device *dev,
+			    unsigned int mode, unsigned int src)
+{
+	struct das16_private_struct *devpriv = dev->private;
+
+	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
+			       DAS16_CTRL_DMAE |
+			       DAS16_CTRL_PACING_MASK);
+	devpriv->ctrl_reg |= mode;
+
+	if (src == TRIG_EXT)
+		devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
+	else
+		devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
+	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+}
+
+static void das16_ai_disable(struct comedi_device *dev)
+{
+	struct das16_private_struct *devpriv = dev->private;
+
+	/* disable interrupts, dma and pacer clocked conversions */
+	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
+			       DAS16_CTRL_DMAE |
+			       DAS16_CTRL_PACING_MASK);
+	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+}
+
+/* the pc104-das16jr (at least) has problems if the dma
+	transfer is interrupted in the middle of transferring
+	a 16 bit sample, so this function takes care to get
+	an even transfer count after disabling dma
+	channel.
+*/
+static int disable_dma_on_even(struct comedi_device *dev)
+{
+	struct das16_private_struct *devpriv = dev->private;
+	int residue;
+	int i;
+	static const int disable_limit = 100;
+	static const int enable_timeout = 100;
+
+	disable_dma(devpriv->dma_chan);
+	residue = get_dma_residue(devpriv->dma_chan);
+	for (i = 0; i < disable_limit && (residue % 2); ++i) {
+		int j;
+		enable_dma(devpriv->dma_chan);
+		for (j = 0; j < enable_timeout; ++j) {
+			int new_residue;
+			udelay(2);
+			new_residue = get_dma_residue(devpriv->dma_chan);
+			if (new_residue != residue)
+				break;
+		}
+		disable_dma(devpriv->dma_chan);
+		residue = get_dma_residue(devpriv->dma_chan);
+	}
+	if (i == disable_limit) {
+		dev_err(dev->class_dev,
+			"failed to get an even dma transfer, could be trouble\n");
+	}
+	return residue;
+}
+
+static void das16_interrupt(struct comedi_device *dev)
+{
+	struct das16_private_struct *devpriv = dev->private;
+	struct comedi_subdevice *s = dev->read_subdev;
+	struct comedi_async *async = s->async;
+	struct comedi_cmd *cmd = &async->cmd;
+	unsigned long spin_flags;
+	unsigned long dma_flags;
+	int num_bytes, residue;
+	int buffer_index;
+
+	spin_lock_irqsave(&dev->spinlock, spin_flags);
+	if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
+		spin_unlock_irqrestore(&dev->spinlock, spin_flags);
+		return;
+	}
+
+	dma_flags = claim_dma_lock();
+	clear_dma_ff(devpriv->dma_chan);
+	residue = disable_dma_on_even(dev);
+
+	/*  figure out how many points to read */
+	if (residue > devpriv->dma_transfer_size) {
+		dev_err(dev->class_dev, "residue > transfer size!\n");
+		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+		num_bytes = 0;
+	} else
+		num_bytes = devpriv->dma_transfer_size - residue;
+
+	if (cmd->stop_src == TRIG_COUNT &&
+					num_bytes >= devpriv->adc_byte_count) {
+		num_bytes = devpriv->adc_byte_count;
+		async->events |= COMEDI_CB_EOA;
+	}
+
+	buffer_index = devpriv->current_buffer;
+	devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
+	devpriv->adc_byte_count -= num_bytes;
+
+	/*  re-enable  dma */
+	if ((async->events & COMEDI_CB_EOA) == 0) {
+		set_dma_addr(devpriv->dma_chan,
+			     devpriv->dma_buffer_addr[devpriv->current_buffer]);
+		set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
+		enable_dma(devpriv->dma_chan);
+	}
+	release_dma_lock(dma_flags);
+
+	spin_unlock_irqrestore(&dev->spinlock, spin_flags);
+
+	cfc_write_array_to_buffer(s,
+				  devpriv->dma_buffer[buffer_index], num_bytes);
+
+	cfc_handle_events(dev, s);
+}
+
+static void das16_timer_interrupt(unsigned long arg)
+{
+	struct comedi_device *dev = (struct comedi_device *)arg;
+	struct das16_private_struct *devpriv = dev->private;
+
+	das16_interrupt(dev);
+
+	if (devpriv->timer_running)
+		mod_timer(&devpriv->timer, jiffies + timer_period());
+}
+
 static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 			  struct comedi_cmd *cmd)
 {
@@ -405,15 +614,13 @@
 	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
 
 	mask = TRIG_FOLLOW;
-	/*  if board supports burst mode */
-	if (board->size > 0x400)
+	if (devpriv->can_burst)
 		mask |= TRIG_TIMER | TRIG_EXT;
 	err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask);
 
 	tmp = cmd->convert_src;
 	mask = TRIG_TIMER | TRIG_EXT;
-	/*  if board supports burst mode */
-	if (board->size > 0x400)
+	if (devpriv->can_burst)
 		mask |= TRIG_NOW;
 	err |= cfc_check_trigger_src(&cmd->convert_src, mask);
 
@@ -469,9 +676,9 @@
 		unsigned int tmp = cmd->scan_begin_arg;
 		/*  set divisors, correct timing arguments */
 		i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
-					       &(devpriv->divisor1),
-					       &(devpriv->divisor2),
-					       &(cmd->scan_begin_arg),
+					       &devpriv->divisor1,
+					       &devpriv->divisor2,
+					       &cmd->scan_begin_arg,
 					       cmd->flags & TRIG_ROUND_MASK);
 		err += (tmp != cmd->scan_begin_arg);
 	}
@@ -479,9 +686,9 @@
 		unsigned int tmp = cmd->convert_arg;
 		/*  set divisors, correct timing arguments */
 		i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
-					       &(devpriv->divisor1),
-					       &(devpriv->divisor2),
-					       &(cmd->convert_arg),
+					       &devpriv->divisor1,
+					       &devpriv->divisor2,
+					       &cmd->convert_arg,
 					       cmd->flags & TRIG_ROUND_MASK);
 		err += (tmp != cmd->convert_arg);
 	}
@@ -495,16 +702,13 @@
 		for (i = 1; i < cmd->chanlist_len; i++) {
 			if (CR_CHAN(cmd->chanlist[i]) !=
 			    (start_chan + i) % s->n_chan) {
-				comedi_error(dev,
-						"entries in chanlist must be "
-						"consecutive channels, "
-						"counting upwards\n");
+				dev_err(dev->class_dev,
+					"entries in chanlist must be consecutive channels, counting upwards\n");
 				err++;
 			}
 			if (CR_RANGE(cmd->chanlist[i]) != gain) {
-				comedi_error(dev,
-						"entries in chanlist must all "
-						"have the same gain\n");
+				dev_err(dev->class_dev,
+					"entries in chanlist must all have the same gain\n");
 				err++;
 			}
 		}
@@ -515,61 +719,21 @@
 	return 0;
 }
 
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
-						const struct comedi_cmd *cmd)
-{
-	struct das16_private_struct *devpriv = dev->private;
-	unsigned int size;
-	unsigned int freq;
-
-	/* if we are using timer interrupt, we don't care how long it
-	 * will take to complete transfer since it will be interrupted
-	 * by timer interrupt */
-	if (devpriv->timer_mode)
-		return DAS16_DMA_SIZE;
-
-	/* otherwise, we are relying on dma terminal count interrupt,
-	 * so pick a reasonable size */
-	if (cmd->convert_src == TRIG_TIMER)
-		freq = 1000000000 / cmd->convert_arg;
-	else if (cmd->scan_begin_src == TRIG_TIMER)
-		freq = (1000000000 / cmd->scan_begin_arg) * cmd->chanlist_len;
-	/*  return some default value */
-	else
-		freq = 0xffffffff;
-
-	if (cmd->flags & TRIG_WAKE_EOS) {
-		size = sample_size * cmd->chanlist_len;
-	} else {
-		/*  make buffer fill in no more than 1/3 second */
-		size = (freq / 3) * sample_size;
-	}
-
-	/*  set a minimum and maximum size allowed */
-	if (size > DAS16_DMA_SIZE)
-		size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
-	else if (size < sample_size)
-		size = sample_size;
-
-	if (cmd->stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
-		size = devpriv->adc_byte_count;
-
-	return size;
-}
-
 static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
 				    int rounding_flags)
 {
 	struct das16_private_struct *devpriv = dev->private;
+	unsigned long timer_base = dev->iobase + DAS16_TIMER_BASE_REG;
 
-	i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
-				       &(devpriv->divisor2), &ns,
+	i8253_cascade_ns_to_timer_2div(devpriv->clockbase,
+				       &devpriv->divisor1,
+				       &devpriv->divisor2,
+				       &ns,
 				       rounding_flags & TRIG_ROUND_MASK);
 
 	/* Write the values of ctr1 and ctr2 into counters 1 and 2 */
-	i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
-	i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+	i8254_load(timer_base, 0, 1, devpriv->divisor1, 2);
+	i8254_load(timer_base, 0, 2, devpriv->divisor2, 2);
 
 	return ns;
 }
@@ -584,30 +748,22 @@
 	unsigned long flags;
 	int range;
 
-	if (devpriv->dma_chan == 0 || (dev->irq == 0
-				       && devpriv->timer_mode == 0)) {
-		comedi_error(dev,
-				"irq (or use of 'timer mode') dma required to "
-							"execute comedi_cmd");
-		return -1;
-	}
 	if (cmd->flags & TRIG_RT) {
-		comedi_error(dev, "isa dma transfers cannot be performed with "
-							"TRIG_RT, aborting");
+		dev_err(dev->class_dev,
+			 "isa dma transfers cannot be performed with TRIG_RT, aborting\n");
 		return -1;
 	}
 
 	devpriv->adc_byte_count =
 	    cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t);
 
-	/*  disable conversions for das1600 mode */
-	if (board->size > 0x400)
-		outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV);
+	if (devpriv->can_burst)
+		outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
 
 	/*  set scan limits */
 	byte = CR_CHAN(cmd->chanlist[0]);
 	byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;
-	outb(byte, dev->iobase + DAS16_MUX);
+	outb(byte, dev->iobase + DAS16_MUX_REG);
 
 	/* set gain (this is also burst rate register but according to
 	 * computer boards manual, burst rate does nothing, even on
@@ -615,28 +771,27 @@
 	if (board->ai_pg != das16_pg_none) {
 		range = CR_RANGE(cmd->chanlist[0]);
 		outb((das16_gainlists[board->ai_pg])[range],
-		     dev->iobase + DAS16_GAIN);
+		     dev->iobase + DAS16_GAIN_REG);
 	}
 
 	/* set counter mode and counts */
 	cmd->convert_arg =
 	    das16_set_pacer(dev, cmd->convert_arg,
 			    cmd->flags & TRIG_ROUND_MASK);
-	DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg);
 
 	/* enable counters */
 	byte = 0;
-	/* Enable burst mode if appropriate. */
-	if (board->size > 0x400) {
+	if (devpriv->can_burst) {
 		if (cmd->convert_src == TRIG_NOW) {
-			outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST);
+			outb(DAS1600_BURST_VAL,
+			     dev->iobase + DAS1600_BURST_REG);
 			/*  set burst length */
-			byte |= BURST_LEN_BITS(cmd->chanlist_len - 1);
+			byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1);
 		} else {
-			outb(0, dev->iobase + DAS1600_BURST);
+			outb(0, dev->iobase + DAS1600_BURST_REG);
 		}
 	}
-	outb(byte, dev->iobase + DAS16_PACER);
+	outb(byte, dev->iobase + DAS16_PACER_REG);
 
 	/*  set up dma transfer */
 	flags = claim_dma_lock();
@@ -647,465 +802,220 @@
 	devpriv->current_buffer = 0;
 	set_dma_addr(devpriv->dma_chan,
 		     devpriv->dma_buffer_addr[devpriv->current_buffer]);
-	/*  set appropriate size of transfer */
-	devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, cmd);
+	devpriv->dma_transfer_size = DAS16_DMA_SIZE;
 	set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
 	enable_dma(devpriv->dma_chan);
 	release_dma_lock(flags);
 
 	/*  set up interrupt */
-	if (devpriv->timer_mode) {
-		devpriv->timer_running = 1;
-		devpriv->timer.expires = jiffies + timer_period();
-		add_timer(&devpriv->timer);
-		devpriv->control_state &= ~DAS16_INTE;
-	} else {
-		/* clear interrupt bit */
-		outb(0x00, dev->iobase + DAS16_STATUS);
-		/* enable interrupts */
-		devpriv->control_state |= DAS16_INTE;
-	}
-	devpriv->control_state |= DMA_ENABLE;
-	devpriv->control_state &= ~PACING_MASK;
-	if (cmd->convert_src == TRIG_EXT)
-		devpriv->control_state |= EXT_PACER;
-	else
-		devpriv->control_state |= INT_PACER;
-	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
+	devpriv->timer_running = 1;
+	devpriv->timer.expires = jiffies + timer_period();
+	add_timer(&devpriv->timer);
 
-	/* Enable conversions if using das1600 mode */
-	if (board->size > 0x400)
-		outb(0, dev->iobase + DAS1600_CONV);
+	das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src);
 
+	if (devpriv->can_burst)
+		outb(0, dev->iobase + DAS1600_CONV_REG);
 
 	return 0;
 }
 
 static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-	const struct das16_board *board = comedi_board(dev);
 	struct das16_private_struct *devpriv = dev->private;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->spinlock, flags);
-	/* disable interrupts, dma and pacer clocked conversions */
-	devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE;
-	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
-	if (devpriv->dma_chan)
-		disable_dma(devpriv->dma_chan);
+
+	das16_ai_disable(dev);
+	disable_dma(devpriv->dma_chan);
 
 	/*  disable SW timer */
-	if (devpriv->timer_mode && devpriv->timer_running) {
+	if (devpriv->timer_running) {
 		devpriv->timer_running = 0;
 		del_timer(&devpriv->timer);
 	}
 
-	/* disable burst mode */
-	if (board->size > 0x400)
-		outb(0, dev->iobase + DAS1600_BURST);
-
+	if (devpriv->can_burst)
+		outb(0, dev->iobase + DAS1600_BURST_REG);
 
 	spin_unlock_irqrestore(&dev->spinlock, flags);
 
 	return 0;
 }
 
-static void das16_reset(struct comedi_device *dev)
-{
-	outb(0, dev->iobase + DAS16_STATUS);
-	outb(0, dev->iobase + DAS16_CONTROL);
-	outb(0, dev->iobase + DAS16_PACER);
-	outb(0, dev->iobase + DAS16_CNTR_CONTROL);
-}
-
-static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data)
-{
-	const struct das16_board *board = comedi_board(dev);
-	struct das16_private_struct *devpriv = dev->private;
-	int i, n;
-	int range;
-	int chan;
-	int msb, lsb;
-
-	/*  disable interrupts and pacing */
-	devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK;
-	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
-
-	/* set multiplexer */
-	chan = CR_CHAN(insn->chanspec);
-	chan |= CR_CHAN(insn->chanspec) << 4;
-	outb(chan, dev->iobase + DAS16_MUX);
-
-	/* set gain */
-	if (board->ai_pg != das16_pg_none) {
-		range = CR_RANGE(insn->chanspec);
-		outb((das16_gainlists[board->ai_pg])[range],
-		     dev->iobase + DAS16_GAIN);
-	}
-
-	for (n = 0; n < insn->n; n++) {
-		/* trigger conversion */
-		outb_p(0, dev->iobase + DAS16_TRIG);
-
-		for (i = 0; i < DAS16_TIMEOUT; i++) {
-			if (!(inb(dev->iobase + DAS16_STATUS) & BUSY))
-				break;
-		}
-		if (i == DAS16_TIMEOUT) {
-			printk("das16: timeout\n");
-			return -ETIME;
-		}
-		msb = inb(dev->iobase + DAS16_AI_MSB);
-		lsb = inb(dev->iobase + DAS16_AI_LSB);
-		if (board->ai_nbits == 12)
-			data[n] = ((lsb >> 4) & 0xf) | (msb << 4);
-		else
-			data[n] = lsb | (msb << 8);
-
-	}
-
-	return n;
-}
-
-static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data)
-{
-	unsigned int bits;
-
-	bits = inb(dev->iobase + DAS16_DIO) & 0xf;
-	data[1] = bits;
-	data[0] = 0;
-
-	return insn->n;
-}
-
-static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data)
-{
-	unsigned int wbits;
-
-	/*  only set bits that have been masked */
-	data[0] &= 0xf;
-	wbits = s->state;
-	/*  zero bits that have been masked */
-	wbits &= ~data[0];
-	/*  set masked bits */
-	wbits |= data[0] & data[1];
-	s->state = wbits;
-	data[1] = wbits;
-
-	outb(s->state, dev->iobase + DAS16_DIO);
-
-	return insn->n;
-}
-
-static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
-			  struct comedi_insn *insn, unsigned int *data)
-{
-	const struct das16_board *board = comedi_board(dev);
-	int i;
-	int lsb, msb;
-	int chan;
-
-	chan = CR_CHAN(insn->chanspec);
-
-	for (i = 0; i < insn->n; i++) {
-		if (board->ao_nbits == 12) {
-			lsb = (data[i] << 4) & 0xff;
-			msb = (data[i] >> 4) & 0xff;
-		} else {
-			lsb = data[i] & 0xff;
-			msb = (data[i] >> 8) & 0xff;
-		}
-		outb(lsb, dev->iobase + DAS16_AO_LSB(chan));
-		outb(msb, dev->iobase + DAS16_AO_MSB(chan));
-	}
-
-	return i;
-}
-
-/* the pc104-das16jr (at least) has problems if the dma
-	transfer is interrupted in the middle of transferring
-	a 16 bit sample, so this function takes care to get
-	an even transfer count after disabling dma
-	channel.
-*/
-static int disable_dma_on_even(struct comedi_device *dev)
-{
-	struct das16_private_struct *devpriv = dev->private;
-	int residue;
-	int i;
-	static const int disable_limit = 100;
-	static const int enable_timeout = 100;
-
-	disable_dma(devpriv->dma_chan);
-	residue = get_dma_residue(devpriv->dma_chan);
-	for (i = 0; i < disable_limit && (residue % 2); ++i) {
-		int j;
-		enable_dma(devpriv->dma_chan);
-		for (j = 0; j < enable_timeout; ++j) {
-			int new_residue;
-			udelay(2);
-			new_residue = get_dma_residue(devpriv->dma_chan);
-			if (new_residue != residue)
-				break;
-		}
-		disable_dma(devpriv->dma_chan);
-		residue = get_dma_residue(devpriv->dma_chan);
-	}
-	if (i == disable_limit) {
-		comedi_error(dev, "failed to get an even dma transfer, "
-							"could be trouble.");
-	}
-	return residue;
-}
-
-static void das16_interrupt(struct comedi_device *dev)
-{
-	const struct das16_board *board = comedi_board(dev);
-	struct das16_private_struct *devpriv = dev->private;
-	unsigned long dma_flags, spin_flags;
-	struct comedi_subdevice *s = dev->read_subdev;
-	struct comedi_async *async;
-	struct comedi_cmd *cmd;
-	int num_bytes, residue;
-	int buffer_index;
-
-	if (!dev->attached) {
-		comedi_error(dev, "premature interrupt");
-		return;
-	}
-	/*  initialize async here to make sure it is not NULL */
-	async = s->async;
-	cmd = &async->cmd;
-
-	if (devpriv->dma_chan == 0) {
-		comedi_error(dev, "interrupt with no dma channel?");
-		return;
-	}
-
-	spin_lock_irqsave(&dev->spinlock, spin_flags);
-	if ((devpriv->control_state & DMA_ENABLE) == 0) {
-		spin_unlock_irqrestore(&dev->spinlock, spin_flags);
-		DEBUG_PRINT("interrupt while dma disabled?\n");
-		return;
-	}
-
-	dma_flags = claim_dma_lock();
-	clear_dma_ff(devpriv->dma_chan);
-	residue = disable_dma_on_even(dev);
-
-	/*  figure out how many points to read */
-	if (residue > devpriv->dma_transfer_size) {
-		comedi_error(dev, "residue > transfer size!\n");
-		async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
-		num_bytes = 0;
-	} else
-		num_bytes = devpriv->dma_transfer_size - residue;
-
-	if (cmd->stop_src == TRIG_COUNT &&
-					num_bytes >= devpriv->adc_byte_count) {
-		num_bytes = devpriv->adc_byte_count;
-		async->events |= COMEDI_CB_EOA;
-	}
-
-	buffer_index = devpriv->current_buffer;
-	devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
-	devpriv->adc_byte_count -= num_bytes;
-
-	/*  figure out how many bytes for next transfer */
-	if (cmd->stop_src == TRIG_COUNT && devpriv->timer_mode == 0 &&
-	    devpriv->dma_transfer_size > devpriv->adc_byte_count)
-		devpriv->dma_transfer_size = devpriv->adc_byte_count;
-
-	/*  re-enable  dma */
-	if ((async->events & COMEDI_CB_EOA) == 0) {
-		set_dma_addr(devpriv->dma_chan,
-			     devpriv->dma_buffer_addr[devpriv->current_buffer]);
-		set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
-		enable_dma(devpriv->dma_chan);
-		/* reenable conversions for das1600 mode, (stupid hardware) */
-		if (board->size > 0x400 && devpriv->timer_mode == 0)
-			outb(0x00, dev->iobase + DAS1600_CONV);
-
-	}
-	release_dma_lock(dma_flags);
-
-	spin_unlock_irqrestore(&dev->spinlock, spin_flags);
-
-	cfc_write_array_to_buffer(s,
-				  devpriv->dma_buffer[buffer_index], num_bytes);
-
-	cfc_handle_events(dev, s);
-}
-
-static irqreturn_t das16_dma_interrupt(int irq, void *d)
-{
-	int status;
-	struct comedi_device *dev = d;
-
-	status = inb(dev->iobase + DAS16_STATUS);
-
-	if ((status & DAS16_INT) == 0) {
-		DEBUG_PRINT("spurious interrupt\n");
-		return IRQ_NONE;
-	}
-
-	/* clear interrupt */
-	outb(0x00, dev->iobase + DAS16_STATUS);
-	das16_interrupt(dev);
-	return IRQ_HANDLED;
-}
-
-static void das16_timer_interrupt(unsigned long arg)
-{
-	struct comedi_device *dev = (struct comedi_device *)arg;
-	struct das16_private_struct *devpriv = dev->private;
-
-	das16_interrupt(dev);
-
-	if (devpriv->timer_running)
-		mod_timer(&devpriv->timer, jiffies + timer_period());
-}
-
-static void reg_dump(struct comedi_device *dev)
-{
-	DEBUG_PRINT("********DAS1600 REGISTER DUMP********\n");
-	DEBUG_PRINT("DAS16_MUX: %x\n", inb(dev->iobase + DAS16_MUX));
-	DEBUG_PRINT("DAS16_DIO: %x\n", inb(dev->iobase + DAS16_DIO));
-	DEBUG_PRINT("DAS16_STATUS: %x\n", inb(dev->iobase + DAS16_STATUS));
-	DEBUG_PRINT("DAS16_CONTROL: %x\n", inb(dev->iobase + DAS16_CONTROL));
-	DEBUG_PRINT("DAS16_PACER: %x\n", inb(dev->iobase + DAS16_PACER));
-	DEBUG_PRINT("DAS16_GAIN: %x\n", inb(dev->iobase + DAS16_GAIN));
-	DEBUG_PRINT("DAS16_CNTR_CONTROL: %x\n",
-		    inb(dev->iobase + DAS16_CNTR_CONTROL));
-	DEBUG_PRINT("DAS1600_CONV: %x\n", inb(dev->iobase + DAS1600_CONV));
-	DEBUG_PRINT("DAS1600_BURST: %x\n", inb(dev->iobase + DAS1600_BURST));
-	DEBUG_PRINT("DAS1600_ENABLE: %x\n", inb(dev->iobase + DAS1600_ENABLE));
-	DEBUG_PRINT("DAS1600_STATUS_B: %x\n",
-		    inb(dev->iobase + DAS1600_STATUS_B));
-}
-
-static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-	const struct das16_board *board = comedi_board(dev);
-	struct das16_private_struct *devpriv = dev->private;
-	int status;
-	int diobits;
-
-	/* status is available on all boards */
-
-	status = inb(dev->iobase + DAS16_STATUS);
-
-	if ((status & UNIPOLAR))
-		devpriv->ai_unipolar = 1;
-	else
-		devpriv->ai_unipolar = 0;
-
-
-	if ((status & DAS16_MUXBIT))
-		devpriv->ai_singleended = 1;
-	else
-		devpriv->ai_singleended = 0;
-
-
-	/* diobits indicates boards */
-
-	diobits = inb(dev->iobase + DAS16_DIO) & 0xf0;
-
-	printk(KERN_INFO " id bits are 0x%02x\n", diobits);
-	if (board->id != diobits) {
-		printk(KERN_INFO " requested board's id bits are 0x%x (ignore)\n",
-		       board->id);
-	}
-
-	return 0;
-}
-
-static int das1600_mode_detect(struct comedi_device *dev)
-{
-	struct das16_private_struct *devpriv = dev->private;
-	int status = 0;
-
-	status = inb(dev->iobase + DAS1600_STATUS_B);
-
-	if (status & DAS1600_CLK_10MHZ) {
-		devpriv->clockbase = 100;
-		printk(KERN_INFO " 10MHz pacer clock\n");
-	} else {
-		devpriv->clockbase = 1000;
-		printk(KERN_INFO " 1MHz pacer clock\n");
-	}
-
-	reg_dump(dev);
-
-	return 0;
-}
-
 static void das16_ai_munge(struct comedi_device *dev,
 			   struct comedi_subdevice *s, void *array,
 			   unsigned int num_bytes,
 			   unsigned int start_chan_index)
 {
-	const struct das16_board *board = comedi_board(dev);
 	unsigned int i, num_samples = num_bytes / sizeof(short);
 	short *data = array;
 
 	for (i = 0; i < num_samples; i++) {
 		data[i] = le16_to_cpu(data[i]);
-		if (board->ai_nbits == 12)
-			data[i] = (data[i] >> 4) & 0xfff;
-
+		if (s->maxdata == 0x0fff)
+			data[i] >>= 4;
+		data[i] &= s->maxdata;
 	}
 }
 
-/*
- *
- * Options list:
- *   0  I/O base
- *   1  IRQ
- *   2  DMA
- *   3  Clock speed (in MHz)
- */
+static int das16_ai_wait_for_conv(struct comedi_device *dev,
+				  unsigned int timeout)
+{
+	unsigned int status;
+	int i;
+
+	for (i = 0; i < timeout; i++) {
+		status = inb(dev->iobase + DAS16_STATUS_REG);
+		if (!(status & DAS16_STATUS_BUSY))
+			return 0;
+	}
+	return -ETIME;
+}
+
+static int das16_ai_insn_read(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      struct comedi_insn *insn,
+			      unsigned int *data)
+{
+	const struct das16_board *board = comedi_board(dev);
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
+	unsigned int val;
+	int ret;
+	int i;
+
+	das16_ai_disable(dev);
+
+	/* set multiplexer */
+	outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG);
+
+	/* set gain */
+	if (board->ai_pg != das16_pg_none) {
+		outb((das16_gainlists[board->ai_pg])[range],
+		     dev->iobase + DAS16_GAIN_REG);
+	}
+
+	for (i = 0; i < insn->n; i++) {
+		/* trigger conversion */
+		outb_p(0, dev->iobase + DAS16_TRIG_REG);
+
+		ret = das16_ai_wait_for_conv(dev, 1000);
+		if (ret)
+			return ret;
+
+		val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8;
+		val |= inb(dev->iobase + DAS16_AI_LSB_REG);
+		if (s->maxdata == 0x0fff)
+			val >>= 4;
+		val &= s->maxdata;
+
+		data[i] = val;
+	}
+
+	return insn->n;
+}
+
+static int das16_ao_insn_write(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn,
+			       unsigned int *data)
+{
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int val;
+	int i;
+
+	for (i = 0; i < insn->n; i++) {
+		val = data[i];
+		val <<= 4;
+
+		outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan));
+		outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan));
+	}
+
+	return insn->n;
+}
+
+static int das16_di_insn_bits(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      struct comedi_insn *insn,
+			      unsigned int *data)
+{
+	data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf;
+
+	return insn->n;
+}
+
+static int das16_do_insn_bits(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      struct comedi_insn *insn,
+			      unsigned int *data)
+{
+	unsigned int mask = data[0];
+	unsigned int bits = data[1];
+
+	if (mask) {
+		s->state &= ~mask;
+		s->state |= (bits & mask);
+
+		outb(s->state, dev->iobase + DAS16_DIO_REG);
+	}
+
+	data[1] = s->state;
+
+	return insn->n;
+}
+
+static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+	const struct das16_board *board = comedi_board(dev);
+	int diobits;
+
+	/* diobits indicates boards */
+	diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0;
+	if (board->id != diobits) {
+		dev_err(dev->class_dev,
+			"requested board's id bits are incorrect (0x%x != 0x%x)\n",
+			board->id, diobits);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void das16_reset(struct comedi_device *dev)
+{
+	outb(0, dev->iobase + DAS16_STATUS_REG);
+	outb(0, dev->iobase + DAS16_CTRL_REG);
+	outb(0, dev->iobase + DAS16_PACER_REG);
+	outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg);
+}
+
 static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
 	const struct das16_board *board = comedi_board(dev);
 	struct das16_private_struct *devpriv;
 	struct comedi_subdevice *s;
+	struct comedi_lrange *lrange;
+	struct comedi_krange *krange;
+	unsigned int dma_chan = it->options[2];
+	unsigned int status;
 	int ret;
-	unsigned int irq;
-	unsigned int dma_chan;
-	int timer_mode;
-	unsigned long flags;
-	struct comedi_krange *user_ai_range, *user_ao_range;
-
-#if 0
-	irq = it->options[1];
-	timer_mode = it->options[8];
-#endif
-	/* always use time_mode since using irq can drop samples while
-	 * waiting for dma done interrupt (due to hardware limitations) */
-	irq = 0;
-	timer_mode = 1;
-	if (timer_mode)
-		irq = 0;
 
 	/*  check that clock setting is valid */
 	if (it->options[3]) {
 		if (it->options[3] != 0 &&
 		    it->options[3] != 1 && it->options[3] != 10) {
-			printk
-			    ("\n Invalid option.  Master clock must be set "
-							"to 1 or 10 (MHz)\n");
+			dev_err(dev->class_dev,
+				"Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
 			return -EINVAL;
 		}
 	}
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	if (board->size < 0x400) {
 		ret = comedi_request_region(dev, it->options[0], board->size);
@@ -1121,207 +1031,183 @@
 		if (ret)
 			return ret;
 		devpriv->extra_iobase = dev->iobase + 0x400;
+		devpriv->can_burst = 1;
 	}
 
 	/*  probe id bits to make sure they are consistent */
-	if (das16_probe(dev, it)) {
-		printk(KERN_ERR " id bits do not match selected board, aborting\n");
+	if (das16_probe(dev, it))
 		return -EINVAL;
-	}
 
 	/*  get master clock speed */
-	if (board->size < 0x400) {
+	if (devpriv->can_burst) {
+		status = inb(dev->iobase + DAS1600_STATUS_REG);
+
+		if (status & DAS1600_STATUS_CLK_10MHZ)
+			devpriv->clockbase = 100;
+		else
+			devpriv->clockbase = 1000;
+	} else {
 		if (it->options[3])
 			devpriv->clockbase = 1000 / it->options[3];
 		else
 			devpriv->clockbase = 1000;	/*  1 MHz default */
-	} else {
-		das1600_mode_detect(dev);
 	}
 
-	/* now for the irq */
-	if (irq > 1 && irq < 8) {
-		ret = request_irq(irq, das16_dma_interrupt, 0,
-				  dev->board_name, dev);
-
-		if (ret < 0)
-			return ret;
-		dev->irq = irq;
-		printk(KERN_INFO " ( irq = %u )", irq);
-	} else if (irq == 0) {
-		printk(" ( no irq )");
-	} else {
-		printk(" invalid irq\n");
-		return -EINVAL;
-	}
-
-	/*  initialize dma */
-	dma_chan = it->options[2];
+	/* initialize dma */
 	if (dma_chan == 1 || dma_chan == 3) {
-		/*  allocate dma buffers */
+		unsigned long flags;
 		int i;
-		for (i = 0; i < 2; i++) {
-			devpriv->dma_buffer[i] = pci_alloc_consistent(
-						NULL, DAS16_DMA_SIZE,
-						&devpriv->dma_buffer_addr[i]);
 
-			if (devpriv->dma_buffer[i] == NULL)
-				return -ENOMEM;
-		}
 		if (request_dma(dma_chan, dev->board_name)) {
-			printk(KERN_ERR " failed to allocate dma channel %i\n",
-			       dma_chan);
+			dev_err(dev->class_dev,
+				"failed to request dma channel %i\n",
+				dma_chan);
 			return -EINVAL;
 		}
 		devpriv->dma_chan = dma_chan;
+
+		/* allocate dma buffers */
+		for (i = 0; i < 2; i++) {
+			void *p;
+
+			p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE,
+						 &devpriv->dma_buffer_addr[i]);
+			if (!p)
+				return -ENOMEM;
+			devpriv->dma_buffer[i] = p;
+		}
+
 		flags = claim_dma_lock();
 		disable_dma(devpriv->dma_chan);
 		set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
 		release_dma_lock(flags);
-		printk(KERN_INFO " ( dma = %u)\n", dma_chan);
-	} else if (dma_chan == 0) {
-		printk(KERN_INFO " ( no dma )\n");
-	} else {
-		printk(KERN_ERR " invalid dma channel\n");
-		return -EINVAL;
-	}
 
-	/*  get any user-defined input range */
-	if (board->ai_pg == das16_pg_none &&
-	    (it->options[4] || it->options[5])) {
-		/*  allocate single-range range table */
-		devpriv->user_ai_range_table =
-		    kmalloc(sizeof(struct comedi_lrange) +
-			    sizeof(struct comedi_krange), GFP_KERNEL);
-		/*  initialize ai range */
-		devpriv->user_ai_range_table->length = 1;
-		user_ai_range = devpriv->user_ai_range_table->range;
-		user_ai_range->min = it->options[4];
-		user_ai_range->max = it->options[5];
-		user_ai_range->flags = UNIT_volt;
-	}
-	/*  get any user-defined output range */
-	if (it->options[6] || it->options[7]) {
-		/*  allocate single-range range table */
-		devpriv->user_ao_range_table =
-		    kmalloc(sizeof(struct comedi_lrange) +
-			    sizeof(struct comedi_krange), GFP_KERNEL);
-		/*  initialize ao range */
-		devpriv->user_ao_range_table->length = 1;
-		user_ao_range = devpriv->user_ao_range_table->range;
-		user_ao_range->min = it->options[6];
-		user_ao_range->max = it->options[7];
-		user_ao_range->flags = UNIT_volt;
-	}
-
-	if (timer_mode) {
-		init_timer(&(devpriv->timer));
+		init_timer(&devpriv->timer);
 		devpriv->timer.function = das16_timer_interrupt;
 		devpriv->timer.data = (unsigned long)dev;
 	}
-	devpriv->timer_mode = timer_mode ? 1 : 0;
 
-	ret = comedi_alloc_subdevices(dev, 5);
+	/* get any user-defined input range */
+	if (board->ai_pg == das16_pg_none &&
+	    (it->options[4] || it->options[5])) {
+		/* allocate single-range range table */
+		lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
+		if (!lrange)
+			return -ENOMEM;
+
+		/* initialize ai range */
+		devpriv->user_ai_range_table = lrange;
+		lrange->length = 1;
+		krange = devpriv->user_ai_range_table->range;
+		krange->min = it->options[4];
+		krange->max = it->options[5];
+		krange->flags = UNIT_volt;
+	}
+
+	/* get any user-defined output range */
+	if (it->options[6] || it->options[7]) {
+		/* allocate single-range range table */
+		lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
+		if (!lrange)
+			return -ENOMEM;
+
+		/* initialize ao range */
+		devpriv->user_ao_range_table = lrange;
+		lrange->length = 1;
+		krange = devpriv->user_ao_range_table->range;
+		krange->min = it->options[6];
+		krange->max = it->options[7];
+		krange->flags = UNIT_volt;
+	}
+
+	ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
 	if (ret)
 		return ret;
 
+	status = inb(dev->iobase + DAS16_STATUS_REG);
+
+	/* Analog Input subdevice */
 	s = &dev->subdevices[0];
-	dev->read_subdev = s;
-	/* ai */
-	if (board->ai) {
-		s->type = COMEDI_SUBD_AI;
-		s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
-		if (devpriv->ai_singleended) {
-			s->n_chan = 16;
-			s->len_chanlist = 16;
-			s->subdev_flags |= SDF_GROUND;
-		} else {
-			s->n_chan = 8;
-			s->len_chanlist = 8;
-			s->subdev_flags |= SDF_DIFF;
-		}
-		s->maxdata = (1 << board->ai_nbits) - 1;
-		if (devpriv->user_ai_range_table) { /*  user defined ai range */
-			s->range_table = devpriv->user_ai_range_table;
-		} else if (devpriv->ai_unipolar) {
-			s->range_table = das16_ai_uni_lranges[board->ai_pg];
-		} else {
-			s->range_table = das16_ai_bip_lranges[board->ai_pg];
-		}
-		s->insn_read = board->ai;
-		s->do_cmdtest = das16_cmd_test;
-		s->do_cmd = das16_cmd_exec;
-		s->cancel = das16_cancel;
-		s->munge = das16_ai_munge;
+	s->type		= COMEDI_SUBD_AI;
+	s->subdev_flags	= SDF_READABLE;
+	if (status & DAS16_STATUS_MUXBIT) {
+		s->subdev_flags	|= SDF_GROUND;
+		s->n_chan	= 16;
 	} else {
-		s->type = COMEDI_SUBD_UNUSED;
+		s->subdev_flags	|= SDF_DIFF;
+		s->n_chan	= 8;
+	}
+	s->len_chanlist	= s->n_chan;
+	s->maxdata	= board->ai_maxdata;
+	if (devpriv->user_ai_range_table) { /*  user defined ai range */
+		s->range_table	= devpriv->user_ai_range_table;
+	} else if (status & DAS16_STATUS_UNIPOLAR) {
+		s->range_table	= das16_ai_uni_lranges[board->ai_pg];
+	} else {
+		s->range_table	= das16_ai_bip_lranges[board->ai_pg];
+	}
+	s->insn_read	= das16_ai_insn_read;
+	if (devpriv->dma_chan) {
+		dev->read_subdev = s;
+		s->subdev_flags	|= SDF_CMD_READ;
+		s->do_cmdtest	= das16_cmd_test;
+		s->do_cmd	= das16_cmd_exec;
+		s->cancel	= das16_cancel;
+		s->munge	= das16_ai_munge;
 	}
 
+	/* Analog Output subdevice */
 	s = &dev->subdevices[1];
-	/* ao */
-	if (board->ao) {
-		s->type = COMEDI_SUBD_AO;
-		s->subdev_flags = SDF_WRITABLE;
-		s->n_chan = 2;
-		s->maxdata = (1 << board->ao_nbits) - 1;
-		/*  user defined ao range */
-		if (devpriv->user_ao_range_table)
-			s->range_table = devpriv->user_ao_range_table;
-		else
-			s->range_table = &range_unknown;
-
-		s->insn_write = board->ao;
+	if (board->has_ao) {
+		s->type		= COMEDI_SUBD_AO;
+		s->subdev_flags	= SDF_WRITABLE;
+		s->n_chan	= 2;
+		s->maxdata	= 0x0fff;
+		s->range_table	= devpriv->user_ao_range_table;
+		s->insn_write	= das16_ao_insn_write;
 	} else {
-		s->type = COMEDI_SUBD_UNUSED;
+		s->type		= COMEDI_SUBD_UNUSED;
 	}
 
+	/* Digital Input subdevice */
 	s = &dev->subdevices[2];
-	/* di */
-	if (board->di) {
-		s->type = COMEDI_SUBD_DI;
-		s->subdev_flags = SDF_READABLE;
-		s->n_chan = 4;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_bits = board->di;
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
+	s->type		= COMEDI_SUBD_DI;
+	s->subdev_flags	= SDF_READABLE;
+	s->n_chan	= 4;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= das16_di_insn_bits;
 
+	/* Digital Output subdevice */
 	s = &dev->subdevices[3];
-	/* do */
-	if (board->do_) {
-		s->type = COMEDI_SUBD_DO;
-		s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-		s->n_chan = 4;
-		s->maxdata = 1;
-		s->range_table = &range_digital;
-		s->insn_bits = board->do_;
-		/*  initialize digital output lines */
-		outb(s->state, dev->iobase + DAS16_DIO);
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
-	}
+	s->type		= COMEDI_SUBD_DO;
+	s->subdev_flags	= SDF_WRITABLE;
+	s->n_chan	= 4;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= das16_do_insn_bits;
 
-	s = &dev->subdevices[4];
-	/* 8255 */
-	if (board->i8255_offset != 0) {
-		subdev_8255_init(dev, s, NULL, (dev->iobase +
-						board->i8255_offset));
-	} else {
-		s->type = COMEDI_SUBD_UNUSED;
+	/* initialize digital output lines */
+	outb(s->state, dev->iobase + DAS16_DIO_REG);
+
+	/* 8255 Digital I/O subdevice */
+	if (board->has_8255) {
+		s = &dev->subdevices[4];
+		ret = subdev_8255_init(dev, s, NULL,
+				       dev->iobase + board->i8255_offset);
+		if (ret)
+			return ret;
 	}
 
 	das16_reset(dev);
 	/* set the interrupt level */
-	devpriv->control_state = DAS16_IRQ(dev->irq);
-	outb(devpriv->control_state, dev->iobase + DAS16_CONTROL);
+	devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq);
+	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
 
-	/*  turn on das1600 mode if available */
-	if (board->size > 0x400) {
-		outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE);
-		outb(0, dev->iobase + DAS1600_CONV);
-		outb(0, dev->iobase + DAS1600_BURST);
+	if (devpriv->can_burst) {
+		outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG);
+		outb(0, dev->iobase + DAS1600_CONV_REG);
+		outb(0, dev->iobase + DAS1600_BURST_REG);
 	}
 
 	return 0;
@@ -1331,10 +1217,12 @@
 {
 	const struct das16_board *board = comedi_board(dev);
 	struct das16_private_struct *devpriv = dev->private;
+	int i;
 
-	das16_reset(dev);
 	if (devpriv) {
-		int i;
+		if (dev->iobase)
+			das16_reset(dev);
+
 		for (i = 0; i < 2; i++) {
 			if (devpriv->dma_buffer[i])
 				pci_free_consistent(NULL, DAS16_DMA_SIZE,
@@ -1346,312 +1234,15 @@
 			free_dma(devpriv->dma_chan);
 		kfree(devpriv->user_ai_range_table);
 		kfree(devpriv->user_ao_range_table);
+
+		if (devpriv->extra_iobase)
+			release_region(devpriv->extra_iobase,
+				       board->size & 0x3ff);
 	}
-	if (devpriv->extra_iobase)
-		release_region(devpriv->extra_iobase, board->size & 0x3ff);
+
 	comedi_legacy_detach(dev);
 }
 
-static const struct das16_board das16_boards[] = {
-	{
-		.name		= "das-16",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 15000,
-		.ai_pg		= das16_pg_none,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x10,
-		.i8254_offset	= 0x0c,
-		.size		= 0x14,
-		.id		= 0x00,
-	}, {
-		.name		= "das-16g",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 15000,
-		.ai_pg		= das16_pg_none,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x10,
-		.i8254_offset	= 0x0c,
-		.size		= 0x14,
-		.id		= 0x00,
-	}, {
-		.name		= "das-16f",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 8500,
-		.ai_pg		= das16_pg_none,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x10,
-		.i8254_offset	= 0x0c,
-		.size		= 0x14,
-		.id		= 0x00,
-	}, {
-		.name		= "cio-das16",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 20000,
-		.ai_pg		= das16_pg_none,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x10,
-		.i8254_offset	= 0x0c,
-		.size		= 0x14,
-		.id		= 0x80,
-	}, {
-		.name		= "cio-das16/f",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_none,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x10,
-		.i8254_offset	= 0x0c,
-		.size		= 0x14,
-		.id		= 0x80,
-	}, {
-		.name		= "cio-das16/jr",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 7692,
-		.ai_pg		= das16_pg_16jr,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x10,
-		.id		= 0x00,
-	}, {
-		.name		= "pc104-das16jr",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 3300,
-		.ai_pg		= das16_pg_16jr,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x10,
-		.id		= 0x00,
-	}, {
-		.name		= "cio-das16jr/16",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 16,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_16jr_16,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x10,
-		.id		= 0x00,
-	}, {
-		.name		= "pc104-das16jr/16",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 16,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_16jr_16,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x10,
-		.id		= 0x00,
-	}, {
-		.name		= "das-1201",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 20000,
-		.ai_pg		= das16_pg_none,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0x20,
-	}, {
-		.name		= "das-1202",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_none,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0x20,
-	}, {
-		.name		= "das-1401",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1601,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "das-1402",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1602,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "das-1601",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1601,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "das-1602",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1602,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das1401/12",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 6250,
-		.ai_pg		= das16_pg_1601,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das1402/12",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 6250,
-		.ai_pg		= das16_pg_1602,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das1402/16",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 16,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1602,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das1601/12",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 6250,
-		.ai_pg		= das16_pg_1601,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das1602/12",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1602,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das1602/16",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 16,
-		.ai_speed	= 10000,
-		.ai_pg		= das16_pg_1602,
-		.ao		= das16_ao_winsn,
-		.ao_nbits	= 12,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0x400,
-		.i8254_offset	= 0x0c,
-		.size		= 0x408,
-		.id		= 0xc0,
-	}, {
-		.name		= "cio-das16/330",
-		.ai		= das16_ai_rinsn,
-		.ai_nbits	= 12,
-		.ai_speed	= 3030,
-		.ai_pg		= das16_pg_16jr,
-		.ao		= NULL,
-		.di		= das16_di_rbits,
-		.do_		= das16_do_wbits,
-		.i8255_offset	= 0,
-		.i8254_offset	= 0x0c,
-		.size		= 0x14,
-		.id		= 0xf0,
-	},
-};
-
 static struct comedi_driver das16_driver = {
 	.driver_name	= "das16",
 	.module		= THIS_MODULE,
@@ -1664,5 +1255,5 @@
 module_comedi_driver(das16_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 0b33808..b943c44 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -52,7 +52,7 @@
 irq can be omitted, although the cmd interface will not work without it.
 */
 
-#include <linux/ioport.h>
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
@@ -567,10 +567,9 @@
 	int ret;
 	unsigned int irq;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], DAS16M1_SIZE);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 23b4a66..5b30029 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -94,12 +94,12 @@
 	read insn for analog out
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <asm/dma.h>
 
 #include "8253.h"
@@ -1511,10 +1511,9 @@
 	int board;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], DAS1800_SIZE);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index f053077..fb25cb8 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -33,11 +33,10 @@
 This driver has suffered bitrot.
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #define DAS6402_SIZE 16
 
 #define N_WORDS (3000*64)
@@ -294,10 +293,9 @@
 
 	dev->irq = irq;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 091cd91..11e1611 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -56,10 +56,10 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/delay.h>
 
 #include "8253.h"
@@ -700,10 +700,9 @@
 	int board;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], DAS800_SIZE);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index e29847d..118a4fd 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -32,9 +32,10 @@
   comedi_config /dev/comedi0 dmm32at baseaddr,irq
 */
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
-#include <linux/ioport.h>
 
 #include "comedi_fc.h"
 
@@ -647,31 +648,34 @@
 
 static int dmm32at_dio_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn, unsigned int *data)
+				   struct comedi_insn *insn,
+				   unsigned int *data)
 {
 	struct dmm32at_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
 	unsigned char chanbit;
-	int chan = CR_CHAN(insn->chanspec);
+	int ret;
 
-	if (insn->n != 1)
-		return -EINVAL;
-
-	if (chan < 8)
+	if (chan < 8) {
+		mask = 0x0000ff;
 		chanbit = DMM32AT_DIRA;
-	else if (chan < 16)
+	} else if (chan < 16) {
+		mask = 0x00ff00;
 		chanbit = DMM32AT_DIRB;
-	else if (chan < 20)
+	} else if (chan < 20) {
+		mask = 0x0f0000;
 		chanbit = DMM32AT_DIRCL;
-	else
+	} else {
+		mask = 0xf00000;
 		chanbit = DMM32AT_DIRCH;
+	}
 
-	/* 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. */
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
-	/* if output clear the bit, otherwise set it */
-	if (data[0] == COMEDI_OUTPUT)
+	if (data[0] == INSN_CONFIG_DIO_OUTPUT)
 		devpriv->dio_config &= ~chanbit;
 	else
 		devpriv->dio_config |= chanbit;
@@ -680,7 +684,7 @@
 	/* set the DIO's to the new configuration setting */
 	outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF);
 
-	return 1;
+	return insn->n;
 }
 
 static int dmm32at_attach(struct comedi_device *dev,
@@ -753,10 +757,9 @@
 		dev->irq = irq;
 	}
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 3);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index 8f5006d..38918a1 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -29,9 +29,9 @@
   [5] - D/A 1 range (same choices)
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 #include <linux/delay.h>
-#include <linux/ioport.h>
 
 #define DT2801_TIMEOUT 1000
 
@@ -551,32 +551,19 @@
 
 static int dt2801_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	int which = 0;
+	int ret;
 
-	if (s == &dev->subdevices[3])
-		which = 1;
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
+	if (ret)
+		return ret;
 
-	/* configure */
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits = 0xff;
-		dt2801_writecmd(dev, DT_C_SET_DIGOUT);
-		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);
+	dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN);
+	dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0);
 
-	return 1;
+	return insn->n;
 }
 
 /*
@@ -627,10 +614,9 @@
 	if (ret)
 		goto out;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	dev->board_name = board->name;
 
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 5348cda..a41a571 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -41,11 +41,10 @@
   [4] - D/A 1 range (same choices)
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
 	4, {
 		RANGE(0, 5),
@@ -450,10 +449,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	switch (it->options[2]) {
 	case 0:
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 87e9749..6514b9e 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -34,10 +34,10 @@
 addition, the clock does not seem to be very accurate.
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/delay.h>
 
 #include "comedi_fc.h"
@@ -298,10 +298,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	s = &dev->subdevices[0];
 	dev->read_subdev = s;
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 0fcd4fe..34040f0 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -51,9 +51,9 @@
   [12] - Analog output 7 range configuration (same options)
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/delay.h>
 
 #define DT2815_SIZE 2
@@ -165,10 +165,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	s = &dev->subdevices[0];
 	/* ao subdevice */
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 2f46be7..f4a8529 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -33,10 +33,9 @@
   [0] - I/O port base base address
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #define DT2817_SIZE 5
 
 #define DT2817_CR 0
@@ -44,28 +43,26 @@
 
 static int dt2817_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	int mask;
-	int chan;
-	int oe = 0;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int oe = 0;
+	unsigned int mask;
+	int ret;
 
-	if (insn->n != 1)
-		return -EINVAL;
-
-	chan = CR_CHAN(insn->chanspec);
 	if (chan < 8)
-		mask = 0xff;
+		mask = 0x000000ff;
 	else if (chan < 16)
-		mask = 0xff00;
+		mask = 0x0000ff00;
 	else if (chan < 24)
-		mask = 0xff0000;
+		mask = 0x00ff0000;
 	else
 		mask = 0xff000000;
-	if (data[0])
-		s->io_bits |= mask;
-	else
-		s->io_bits &= ~mask;
+
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	if (s->io_bits & 0x000000ff)
 		oe |= 0x1;
@@ -78,7 +75,7 @@
 
 	outb(oe, dev->iobase + DT2817_CR);
 
-	return 1;
+	return insn->n;
 }
 
 static int dt2817_dio_insn_bits(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index c1950e3..da3ee85 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -51,13 +51,16 @@
     be fixed to check for this situation and return an error.
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
+#include <linux/delay.h>
 #include <linux/gfp.h>
-#include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+
 #include <asm/dma.h>
+
 #include "comedi_fc.h"
 
 #define DEBUG
@@ -264,8 +267,9 @@
 			}					\
 			udelay(5);				\
 		}						\
-		if (_i)						\
+		if (_i) {					\
 			b					\
+		}						\
 	} while (0)
 
 static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
@@ -978,29 +982,32 @@
 
 static int dt282x_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
 	struct dt282x_private *devpriv = dev->private;
-	int mask;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00;
-	if (data[0])
-		s->io_bits |= mask;
+	if (chan < 8)
+		mask = 0x00ff;
 	else
-		s->io_bits &= ~mask;
+		mask = 0xff00;
 
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
+	devpriv->dacsr &= ~(DT2821_LBOE | DT2821_HBOE);
 	if (s->io_bits & 0x00ff)
 		devpriv->dacsr |= DT2821_LBOE;
-	else
-		devpriv->dacsr &= ~DT2821_LBOE;
 	if (s->io_bits & 0xff00)
 		devpriv->dacsr |= DT2821_HBOE;
-	else
-		devpriv->dacsr &= ~DT2821_HBOE;
 
 	outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
 
-	return 1;
+	return insn->n;
 }
 
 static const struct comedi_lrange *const ai_range_table[] = {
@@ -1188,10 +1195,9 @@
 #endif
 	}
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = dt282x_grab_dma(dev, it->options[opt_dma1],
 			      it->options[opt_dma2]);
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 01a2f88..64ef875 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -50,6 +50,7 @@
 
 #define DEBUG 1
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -641,32 +642,23 @@
 
 static int dt3k_dio_insn_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	int mask;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
+	if (chan < 4)
+		mask = 0x0f;
+	else
+		mask = 0xf0;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= mask;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~mask;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->
-		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
-		    COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-	mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
-	dt3k_dio_config(dev, mask);
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
+	dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3));
 
 	return insn->n;
 }
@@ -722,10 +714,9 @@
 	dev->board_ptr = this_board;
 	dev->board_name = this_board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret < 0)
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 6c60949..b5e6f33 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -39,10 +39,9 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 
@@ -188,8 +187,8 @@
 };
 
 struct dt9812_flash_data {
-	u16 numbytes;
-	u16 address;
+	__le16 numbytes;
+	__le16 address;
 };
 
 #define DT9812_MAX_NUM_MULTI_BYTE_RDS  \
@@ -230,7 +229,7 @@
 };
 
 struct dt9812_usb_cmd {
-	u32 cmd;
+	__le32 cmd;
 	union {
 		struct dt9812_flash_data flash_data_info;
 		struct dt9812_read_multi read_multi_info;
@@ -707,8 +706,9 @@
 	u32 serial;
 	u16 vendor;
 	u16 product;
-	u16 tmp16;
 	u8 tmp8;
+	__le16 tmp16;
+	__le32 tmp32;
 	int ret;
 	int i;
 
@@ -731,19 +731,19 @@
 		}
 	}
 
-	ret = dt9812_read_info(dev, 1, &vendor, sizeof(vendor));
+	ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16));
 	if (ret) {
 		dev_err(dev->class_dev, "failed to read vendor id\n");
 		return ret;
 	}
-	vendor = le16_to_cpu(vendor);
+	vendor = le16_to_cpu(tmp16);
 
-	ret = dt9812_read_info(dev, 3, &product, sizeof(product));
+	ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16));
 	if (ret) {
 		dev_err(dev->class_dev, "failed to read product id\n");
 		return ret;
 	}
-	product = le16_to_cpu(product);
+	product = le16_to_cpu(tmp16);
 
 	ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16));
 	if (ret) {
@@ -752,12 +752,12 @@
 	}
 	devpriv->device = le16_to_cpu(tmp16);
 
-	ret = dt9812_read_info(dev, 7, &serial, sizeof(serial));
+	ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32));
 	if (ret) {
 		dev_err(dev->class_dev, "failed to read serial number\n");
 		return ret;
 	}
-	serial = le32_to_cpu(serial);
+	serial = le32_to_cpu(tmp32);
 
 	/* let the user know what node this device is now attached to */
 	dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n",
@@ -781,10 +781,9 @@
 	bool is_unipolar;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	sema_init(&devpriv->sem, 1);
 	usb_set_intfdata(intf, devpriv);
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index e14dd3a..fd525f4 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -33,6 +33,8 @@
  their cards in their manuals.
 */
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/mutex.h>
 
@@ -183,10 +185,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index ff6f0bd..8d70f64 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -18,10 +18,10 @@
 
 #define DEBUG 0
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include <linux/delay.h>
-#include <linux/ioport.h>
 
 #define FL512_SIZE 16		/* the size of the used memory */
 struct fl512_private {
@@ -118,10 +118,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 2);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 2fceff9..559bf55 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -42,6 +42,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -223,37 +224,26 @@
 	volatile uint32_t bits[24];
 	/* number of bytes at which to generate COMEDI_CB_BLOCK events */
 	volatile unsigned int block_size;
-	unsigned dio_config_output:1;
 };
 
 static int dio_config_insn(struct comedi_device *dev,
-			   struct comedi_subdevice *s, struct comedi_insn *insn,
+			   struct comedi_subdevice *s,
+			   struct comedi_insn *insn,
 			   unsigned int *data)
 {
-	struct hpdi_private *devpriv = dev->private;
+	int ret;
 
 	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		devpriv->dio_config_output = 1;
-		return insn->n;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		devpriv->dio_config_output = 0;
-		return insn->n;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    devpriv->dio_config_output ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
 	case INSN_CONFIG_BLOCK_SIZE:
 		return dio_config_block_size(dev, data);
-		break;
 	default:
+		ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff);
+		if (ret)
+			return ret;
 		break;
 	}
 
-	return -EINVAL;
+	return insn->n;
 }
 
 static void disable_plx_interrupts(struct comedi_device *dev)
@@ -483,10 +473,9 @@
 	dev->board_ptr = thisboard;
 	dev->board_name = thisboard->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	retval = comedi_pci_enable(dev);
 	if (retval)
@@ -673,9 +662,7 @@
 static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
 			 struct comedi_cmd *cmd)
 {
-	struct hpdi_private *devpriv = dev->private;
-
-	if (devpriv->dio_config_output)
+	if (s->io_bits)
 		return -EINVAL;
 	else
 		return di_cmd_test(dev, s, cmd);
@@ -746,9 +733,7 @@
 
 static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
-	struct hpdi_private *devpriv = dev->private;
-
-	if (devpriv->dio_config_output)
+	if (s->io_bits)
 		return -EINVAL;
 	else
 		return di_cmd(dev, s);
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index a11e015..3889d23 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -42,6 +42,7 @@
 Configuration options: not applicable, uses PCI auto config
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -495,10 +496,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index ee7537d..5c3a318 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -1,662 +1,537 @@
 /*
- *	comedi/drivers/ii_pci20kc.c
- *	Driver for Intelligent Instruments PCI-20001C carrier board
- *	and modules.
+ * ii_pci20kc.c
+ * Driver for Intelligent Instruments PCI-20001C carrier board and modules.
  *
- *	Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de>
- *	with suggestions from David Schleef
- *			16.06.2000
- *
- *	Linux device driver for COMEDI
- *	Intelligent Instrumentation
- *	PCI-20001 C-2A Carrier Board
- *	PCI-20341 M-1A 16-Bit analog input module
- *				- differential
- *				- range (-5V - +5V)
- *				- 16 bit
- *	PCI-20006 M-2 16-Bit analog output module
- *				- ranges (-10V - +10V) (0V - +10V) (-5V - +5V)
- *				- 16 bit
- *
- *	only ONE PCI-20341 module possible
- *	only ONE PCI-20006 module possible
- *	no extern trigger implemented
- *
- *	NOT WORKING (but soon) only 4 on-board differential channels supported
- *	NOT WORKING (but soon) only ONE di-port and ONE do-port supported
- *			       instead of 4 digital ports
- *	di-port == Port 0
- *	do-port == Port 1
- *
- *	The state of this driver is only a starting point for a complete
- *	COMEDI-driver. The final driver should support all features of the
- *	carrier board and modules.
- *
- *	The test configuration:
- *
- *	kernel 2.2.14 with RTAI v1.2  and patch-2.2.14rthal2
- *	COMEDI 0.7.45
- *	COMEDILIB 0.7.9
- *
+ * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de>
+ * with suggestions from David Schleef		16.06.2000
  */
+
 /*
-Driver: ii_pci20kc
-Description: Intelligent Instruments PCI-20001C carrier board
-Author: Markus Kempf <kempf@matsci.uni-sb.de>
-Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc)
-Status: works
+ * Driver: ii_pci20kc
+ * Description: Intelligent Instruments PCI-20001C carrier board
+ * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc]
+ * Author: Markus Kempf <kempf@matsci.uni-sb.de>
+ * Status: works
+ *
+ * Supports the PCI-20001C-1a and PCI-20001C-2a carrier boards. The
+ * -2a version has 32 on-board DIO channels. Three add-on modules
+ * can be added to the carrier board for additional functionality.
+ *
+ * Supported add-on modules:
+ *	PCI-20006M-1   1 channel, 16-bit analog output module
+ *	PCI-20006M-2   2 channel, 16-bit analog output module
+ *	PCI-20341M-1A  4 channel, 16-bit analog input module
+ *
+ * Options:
+ *   0   Board base address
+ *   1   IRQ (not-used)
+ */
 
-Supports the PCI-20001 C-2a Carrier board, and could probably support
-the other carrier boards with small modifications.  Modules supported
-are:
-	PCI-20006 M-2 16-bit analog output module
-	PCI-20341 M-1A 16-bit analog input module
-
-Options:
-  0   Board base address
-  1   IRQ
-  2   first option for module 1
-  3   second option for module 1
-  4   first option for module 2
-  5   second option for module 2
-  6   first option for module 3
-  7   second option for module 3
-
-options for PCI-20006M:
-  first:   Analog output channel 0 range configuration
-	     0  bipolar 10  (-10V -- +10V)
-	     1  unipolar 10  (0V -- +10V)
-	     2  bipolar 5  (-5V -- 5V)
-  second:  Analog output channel 1 range configuration
-
-options for PCI-20341M:
-  first:   Analog input gain configuration
-	     0  1
-	     1  10
-	     2  100
-	     3  200
-*/
-
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#define PCI20000_ID			0x1d
-#define PCI20341_ID			0x77
-#define PCI20006_ID			0xe3
-#define PCI20xxx_EMPTY_ID		0xff
-
-#define PCI20000_OFFSET			0x100
-#define PCI20000_MODULES		3
-
-#define PCI20000_DIO_0			0x80
-#define PCI20000_DIO_1			0x81
-#define PCI20000_DIO_2			0xc0
-#define PCI20000_DIO_3			0xc1
-#define PCI20000_DIO_CONTROL_01		0x83	/* port 0, 1 control */
-#define PCI20000_DIO_CONTROL_23		0xc3	/* port 2, 3 control */
-#define PCI20000_DIO_BUFFER		0x82	/* buffer direction & enable */
-#define PCI20000_DIO_EOC		0xef	/* even port, control output */
-#define PCI20000_DIO_OOC		0xfd	/* odd port, control output */
-#define PCI20000_DIO_EIC		0x90	/* even port, control input */
-#define PCI20000_DIO_OIC		0x82	/* odd port, control input */
-#define DIO_CAND			0x12	/* and bit 1 & 4 of control */
-#define DIO_BE				0x01	/* buffer: port enable */
-#define DIO_BO				0x04	/* buffer: output */
-#define DIO_BI				0x05	/* buffer: input */
-#define DIO_PS_0			0x00	/* buffer: port shift 0 */
-#define DIO_PS_1			0x01	/* buffer: port shift 1 */
-#define DIO_PS_2			0x04	/* buffer: port shift 2 */
-#define DIO_PS_3			0x05	/* buffer: port shift 3 */
-
-#define PCI20006_LCHAN0			0x0d
-#define PCI20006_STROBE0		0x0b
-#define PCI20006_LCHAN1			0x15
-#define PCI20006_STROBE1		0x13
-
-#define PCI20341_INIT			0x04
-#define PCI20341_REPMODE		0x00	/* single shot mode */
-#define PCI20341_PACER			0x00	/* Hardware Pacer disabled */
-#define PCI20341_CHAN_NR		0x04	/* number of input channels */
-#define PCI20341_CONFIG_REG		0x10
-#define PCI20341_MOD_STATUS		0x01
-#define PCI20341_OPT_REG		0x11
-#define PCI20341_SET_TIME_REG		0x15
-#define PCI20341_LCHAN_ADDR_REG		0x13
-#define PCI20341_CHAN_LIST		0x80
-#define PCI20341_CC_RESET		0x1b
-#define PCI20341_CHAN_RESET		0x19
-#define PCI20341_SOFT_PACER		0x04
-#define PCI20341_STATUS_REG		0x12
-#define PCI20341_LDATA			0x02
-#define PCI20341_DAISY_CHAIN		0x20	/* On-board inputs only */
-#define PCI20341_MUX			0x04	/* Enable on-board MUX */
-#define PCI20341_SCANLIST		0x80	/* Channel/Gain Scan List */
-
-union pci20xxx_subdev_private {
-	void __iomem *iobase;
-	struct {
-		void __iomem *iobase;
-		const struct comedi_lrange *ao_range_list[2];
-					/* range of channels of ao module */
-		unsigned int last_data[2];
-	} pci20006;
-	struct {
-		void __iomem *iobase;
-		int timebase;
-		int settling_time;
-		int ai_gain;
-	} pci20341;
-};
-
-struct pci20xxx_private {
-
-	void __iomem *ioaddr;
-	union pci20xxx_subdev_private subdev_private[PCI20000_MODULES];
-};
-
-#define CHAN (CR_CHAN(it->chanlist[0]))
-
-static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
-			 int opt0, int opt1);
-static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
-			 int opt0, int opt1);
-static int pci20xxx_dio_init(struct comedi_device *dev,
-			     struct comedi_subdevice *s);
-
 /*
-  options[0]	Board base address
-  options[1]	IRQ
-  options[2]	first option for module 1
-  options[3]	second option for module 1
-  options[4]	first option for module 2
-  options[5]	second option for module 2
-  options[6]	first option for module 3
-  options[7]	second option for module 3
+ * Register I/O map
+ */
+#define II20K_MOD_OFFSET		0x100
+#define II20K_ID_REG			0x00
+#define II20K_ID_MOD1_EMPTY		(1 << 7)
+#define II20K_ID_MOD2_EMPTY		(1 << 6)
+#define II20K_ID_MOD3_EMPTY		(1 << 5)
+#define II20K_ID_MASK			0x1f
+#define II20K_ID_PCI20001C_1A		0x1b	/* no on-board DIO */
+#define II20K_ID_PCI20001C_2A		0x1d	/* on-board DIO */
+#define II20K_MOD_STATUS_REG		0x40
+#define II20K_MOD_STATUS_IRQ_MOD1	(1 << 7)
+#define II20K_MOD_STATUS_IRQ_MOD2	(1 << 6)
+#define II20K_MOD_STATUS_IRQ_MOD3	(1 << 5)
+#define II20K_DIO0_REG			0x80
+#define II20K_DIO1_REG			0x81
+#define II20K_DIR_ENA_REG		0x82
+#define II20K_DIR_DIO3_OUT		(1 << 7)
+#define II20K_DIR_DIO2_OUT		(1 << 6)
+#define II20K_BUF_DISAB_DIO3		(1 << 5)
+#define II20K_BUF_DISAB_DIO2		(1 << 4)
+#define II20K_DIR_DIO1_OUT		(1 << 3)
+#define II20K_DIR_DIO0_OUT		(1 << 2)
+#define II20K_BUF_DISAB_DIO1		(1 << 1)
+#define II20K_BUF_DISAB_DIO0		(1 << 0)
+#define II20K_CTRL01_REG		0x83
+#define II20K_CTRL01_SET		(1 << 7)
+#define II20K_CTRL01_DIO0_IN		(1 << 4)
+#define II20K_CTRL01_DIO1_IN		(1 << 1)
+#define II20K_DIO2_REG			0xc0
+#define II20K_DIO3_REG			0xc1
+#define II20K_CTRL23_REG		0xc3
+#define II20K_CTRL23_SET		(1 << 7)
+#define II20K_CTRL23_DIO2_IN		(1 << 4)
+#define II20K_CTRL23_DIO3_IN		(1 << 1)
 
-  options for PCI-20341M:
-  first		Analog input gain configuration
-		0 == 1
-		1 == 10
-		2 == 100
-		3 == 200
+#define II20K_ID_PCI20006M_1		0xe2	/* 1 AO channels */
+#define II20K_ID_PCI20006M_2		0xe3	/* 2 AO channels */
+#define II20K_AO_STRB_REG(x)		(0x0b + ((x) * 0x08))
+#define II20K_AO_LSB_REG(x)		(0x0d + ((x) * 0x08))
+#define II20K_AO_MSB_REG(x)		(0x0e + ((x) * 0x08))
+#define II20K_AO_STRB_BOTH_REG		0x1b
 
-  options for PCI-20006M:
-  first		Analog output channel 0 range configuration
-		0 == bipolar 10  (-10V -- +10V)
-		1 == unipolar 10V  (0V -- +10V)
-		2 == bipolar 5V  (-5V -- +5V)
-  second	Analog output channel 1 range configuration
-		0 == bipolar 10  (-10V -- +10V)
-		1 == unipolar 10V  (0V -- +10V)
-		2 == bipolar 5V  (-5V -- +5V)
-*/
-static int pci20xxx_attach(struct comedi_device *dev,
-			   struct comedi_devconfig *it)
-{
-	struct pci20xxx_private *devpriv;
-	unsigned char i;
-	int ret;
-	int id;
-	struct comedi_subdevice *s;
-	union pci20xxx_subdev_private *sdp;
+#define II20K_ID_PCI20341M_1		0x77	/* 4 AI channels */
+#define II20K_AI_STATUS_CMD_REG		0x01
+#define II20K_AI_STATUS_CMD_BUSY	(1 << 7)
+#define II20K_AI_STATUS_CMD_HW_ENA	(1 << 1)
+#define II20K_AI_STATUS_CMD_EXT_START	(1 << 0)
+#define II20K_AI_LSB_REG		0x02
+#define II20K_AI_MSB_REG		0x03
+#define II20K_AI_PACER_RESET_REG	0x04
+#define II20K_AI_16BIT_DATA_REG		0x06
+#define II20K_AI_CONF_REG		0x10
+#define II20K_AI_CONF_ENA		(1 << 2)
+#define II20K_AI_OPT_REG		0x11
+#define II20K_AI_OPT_TRIG_ENA		(1 << 5)
+#define II20K_AI_OPT_TRIG_INV		(1 << 4)
+#define II20K_AI_OPT_TIMEBASE(x)	(((x) & 0x3) << 1)
+#define II20K_AI_OPT_BURST_MODE		(1 << 0)
+#define II20K_AI_STATUS_REG		0x12
+#define II20K_AI_STATUS_INT		(1 << 7)
+#define II20K_AI_STATUS_TRIG		(1 << 6)
+#define II20K_AI_STATUS_TRIG_ENA	(1 << 5)
+#define II20K_AI_STATUS_PACER_ERR	(1 << 2)
+#define II20K_AI_STATUS_DATA_ERR	(1 << 1)
+#define II20K_AI_STATUS_SET_TIME_ERR	(1 << 0)
+#define II20K_AI_LAST_CHAN_ADDR_REG	0x13
+#define II20K_AI_CUR_ADDR_REG		0x14
+#define II20K_AI_SET_TIME_REG		0x15
+#define II20K_AI_DELAY_LSB_REG		0x16
+#define II20K_AI_DELAY_MSB_REG		0x17
+#define II20K_AI_CHAN_ADV_REG		0x18
+#define II20K_AI_CHAN_RESET_REG		0x19
+#define II20K_AI_START_TRIG_REG		0x1a
+#define II20K_AI_COUNT_RESET_REG	0x1b
+#define II20K_AI_CHANLIST_REG		0x80
+#define II20K_AI_CHANLIST_ONBOARD_ONLY	(1 << 5)
+#define II20K_AI_CHANLIST_GAIN(x)	(((x) & 0x3) << 3)
+#define II20K_AI_CHANLIST_MUX_ENA	(1 << 2)
+#define II20K_AI_CHANLIST_CHAN(x)	(((x) & 0x3) << 0)
+#define II20K_AI_CHANLIST_LEN		0x80
 
-	ret = comedi_alloc_subdevices(dev, 1 + PCI20000_MODULES);
-	if (ret)
-		return ret;
-
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
-	if (!devpriv)
-		return -ENOMEM;
-	dev->private = devpriv;
-
-	devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
-
-	/* Check PCI-20001 C-2A Carrier Board ID */
-	if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) {
-		dev_warn(dev->class_dev,
-			 "PCI-20001 C-2A Carrier Board at base=0x%p not found !\n",
-			 devpriv->ioaddr);
-		return -EINVAL;
+/* the AO range is set by jumpers on the 20006M module */
+static const struct comedi_lrange ii20k_ao_ranges = {
+	3, {
+		BIP_RANGE(5),	/* Chan 0 - W1/W3 in   Chan 1 - W2/W4 in  */
+		UNI_RANGE(10),	/* Chan 0 - W1/W3 out  Chan 1 - W2/W4 in  */
+		BIP_RANGE(10)	/* Chan 0 - W1/W3 in   Chan 1 - W2/W4 out */
 	}
-	dev_info(dev->class_dev, "PCI-20001 C-2A at base=0x%p\n",
-		 devpriv->ioaddr);
+};
 
-	for (i = 0; i < PCI20000_MODULES; i++) {
-		s = &dev->subdevices[i];
-		id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET);
-		s->private = devpriv->subdev_private + i;
-		sdp = s->private;
-		switch (id) {
-		case PCI20006_ID:
-			sdp->pci20006.iobase =
-			    devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
-			pci20006_init(dev, s, it->options[2 * i + 2],
-				      it->options[2 * i + 3]);
-			dev_info(dev->class_dev,
-				 "PCI-20006 module in slot %d\n", i + 1);
-			break;
-		case PCI20341_ID:
-			sdp->pci20341.iobase =
-			    devpriv->ioaddr + (i + 1) * PCI20000_OFFSET;
-			pci20341_init(dev, s, it->options[2 * i + 2],
-				      it->options[2 * i + 3]);
-			dev_info(dev->class_dev,
-				 "PCI-20341 module in slot %d\n", i + 1);
-			break;
-		default:
-			dev_warn(dev->class_dev,
-				 "unknown module code 0x%02x in slot %d: module disabled\n",
-				 id, i); /* XXX this looks like a bug! i + 1 ?? */
-			/* fall through */
-		case PCI20xxx_EMPTY_ID:
-			s->type = COMEDI_SUBD_UNUSED;
-			break;
-		}
-	}
+static const struct comedi_lrange ii20k_ai_ranges = {
+	4, {
+		BIP_RANGE(5),		/* gain 1 */
+		BIP_RANGE(0.5),		/* gain 10 */
+		BIP_RANGE(0.05),	/* gain 100 */
+		BIP_RANGE(0.025)	/* gain 200 */
+	},
+};
 
-	/* initialize struct pci20xxx_private */
-	pci20xxx_dio_init(dev, &dev->subdevices[PCI20000_MODULES]);
+struct ii20k_ao_private {
+	unsigned int last_data[2];
+};
 
-	return 1;
-}
+struct ii20k_private {
+	void __iomem *ioaddr;
+};
 
-static void pci20xxx_detach(struct comedi_device *dev)
+static void __iomem *ii20k_module_iobase(struct comedi_device *dev,
+					 struct comedi_subdevice *s)
 {
-	/* Nothing to cleanup */
+	struct ii20k_private *devpriv = dev->private;
+
+	return devpriv->ioaddr + (s->index + 1) * II20K_MOD_OFFSET;
 }
 
-/* pci20006m */
-
-static int pci20006_insn_read(struct comedi_device *dev,
+static int ii20k_ao_insn_read(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-static int pci20006_insn_write(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data);
-
-static const struct comedi_lrange *pci20006_range_list[] = {
-	&range_bipolar10,
-	&range_unipolar10,
-	&range_bipolar5,
-};
-
-static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
-			 int opt0, int opt1)
+			      struct comedi_insn *insn,
+			      unsigned int *data)
 {
-	union pci20xxx_subdev_private *sdp = s->private;
+	struct ii20k_ao_private *ao_spriv = s->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int i;
 
-	if (opt0 < 0 || opt0 > 2)
-		opt0 = 0;
-	if (opt1 < 0 || opt1 > 2)
-		opt1 = 0;
-
-	sdp->pci20006.ao_range_list[0] = pci20006_range_list[opt0];
-	sdp->pci20006.ao_range_list[1] = pci20006_range_list[opt1];
-
-	/* ao subdevice */
-	s->type = COMEDI_SUBD_AO;
-	s->subdev_flags = SDF_WRITABLE;
-	s->n_chan = 2;
-	s->len_chanlist = 2;
-	s->insn_read = pci20006_insn_read;
-	s->insn_write = pci20006_insn_write;
-	s->maxdata = 0xffff;
-	s->range_table_list = sdp->pci20006.ao_range_list;
-	return 0;
-}
-
-static int pci20006_insn_read(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data)
-{
-	union pci20xxx_subdev_private *sdp = s->private;
-
-	data[0] = sdp->pci20006.last_data[CR_CHAN(insn->chanspec)];
-
-	return 1;
-}
-
-static int pci20006_insn_write(struct comedi_device *dev,
-			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
-{
-	union pci20xxx_subdev_private *sdp = s->private;
-	int hi, lo;
-	unsigned int boarddata;
-
-	sdp->pci20006.last_data[CR_CHAN(insn->chanspec)] = data[0];
-	boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff);
-						/* comedi-data -> board-data */
-	lo = (boarddata & 0xff);
-	hi = ((boarddata >> 8) & 0xff);
-
-	switch (CR_CHAN(insn->chanspec)) {
-	case 0:
-		writeb(lo, sdp->iobase + PCI20006_LCHAN0);
-		writeb(hi, sdp->iobase + PCI20006_LCHAN0 + 1);
-		writeb(0x00, sdp->iobase + PCI20006_STROBE0);
-		break;
-	case 1:
-		writeb(lo, sdp->iobase + PCI20006_LCHAN1);
-		writeb(hi, sdp->iobase + PCI20006_LCHAN1 + 1);
-		writeb(0x00, sdp->iobase + PCI20006_STROBE1);
-		break;
-	default:
-		dev_warn(dev->class_dev, "ao channel Error!\n");
-		return -EINVAL;
-	}
-
-	return 1;
-}
-
-/* PCI20341M */
-
-static int pci20341_insn_read(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data);
-
-static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 };
-static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 };
-
-static const struct comedi_lrange range_bipolar0_5 = {
-	1,
-	{BIP_RANGE(0.5)}
-};
-
-static const struct comedi_lrange range_bipolar0_05 = {
-	1,
-	{BIP_RANGE(0.05)}
-};
-
-static const struct comedi_lrange range_bipolar0_025 = {
-	1,
-	{BIP_RANGE(0.025)}
-};
-
-static const struct comedi_lrange *const pci20341_ranges[] = {
-	&range_bipolar5,
-	&range_bipolar0_5,
-	&range_bipolar0_05,
-	&range_bipolar0_025,
-};
-
-static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
-			 int opt0, int opt1)
-{
-	union pci20xxx_subdev_private *sdp = s->private;
-	int option;
-
-	/* options handling */
-	if (opt0 < 0 || opt0 > 3)
-		opt0 = 0;
-	sdp->pci20341.timebase = pci20341_timebase[opt0];
-	sdp->pci20341.settling_time = pci20341_settling_time[opt0];
-
-	/* ai subdevice */
-	s->type = COMEDI_SUBD_AI;
-	s->subdev_flags = SDF_READABLE;
-	s->n_chan = PCI20341_CHAN_NR;
-	s->len_chanlist = PCI20341_SCANLIST;
-	s->insn_read = pci20341_insn_read;
-	s->maxdata = 0xffff;
-	s->range_table = pci20341_ranges[opt0];
-
-	/* depends on gain, trigger, repetition mode */
-	option = sdp->pci20341.timebase | PCI20341_REPMODE;
-
-	/* initialize Module */
-	writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG);
-	/* set Pacer */
-	writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS);
-	/* option register */
-	writeb(option, sdp->iobase + PCI20341_OPT_REG);
-	/* settling time counter */
-	writeb(sdp->pci20341.settling_time,
-		sdp->iobase + PCI20341_SET_TIME_REG);
-	/* trigger not implemented */
-	return 0;
-}
-
-static int pci20341_insn_read(struct comedi_device *dev,
-			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data)
-{
-	union pci20xxx_subdev_private *sdp = s->private;
-	unsigned int i = 0, j = 0;
-	int lo, hi;
-	unsigned char eoc;	/* end of conversion */
-	unsigned int clb;	/* channel list byte */
-	unsigned int boarddata;
-
-	/* write number of input channels */
-	writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG);
-	clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3)
-	    | CR_CHAN(insn->chanspec);
-	writeb(clb, sdp->iobase + PCI20341_CHAN_LIST);
-
-	/* reset settling time counter and trigger delay counter */
-	writeb(0x00, sdp->iobase + PCI20341_CC_RESET);
-
-	writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET);
-
-	/* generate Pacer */
-
-	for (i = 0; i < insn->n; i++) {
-		/* data polling isn't the niciest way to get the data, I know,
-		 * but there are only 6 cycles (mean) and it is easier than
-		 * the whole interrupt stuff
-		 */
-		j = 0;
-		/* generate Pacer */
-		readb(sdp->iobase + PCI20341_SOFT_PACER);
-
-		eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
-		/* poll Interrupt Flag */
-		while ((eoc < 0x80) && j < 100) {
-			j++;
-			eoc = readb(sdp->iobase + PCI20341_STATUS_REG);
-		}
-		if (j >= 100) {
-			dev_warn(dev->class_dev,
-				 "AI interrupt channel %i polling exit !\n", i);
-			return -EINVAL;
-		}
-		lo = readb(sdp->iobase + PCI20341_LDATA);
-		hi = readb(sdp->iobase + PCI20341_LDATA + 1);
-		boarddata = lo + 0x100 * hi;
-
-		/* board-data -> comedi-data */
-		data[i] = (short)((boarddata + 0x8000) & 0xffff);
-	}
-
-	return i;
-}
-
-/* native DIO */
-
-static void pci20xxx_dio_config(struct comedi_device *dev,
-				struct comedi_subdevice *s);
-static int pci20xxx_dio_insn_bits(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data);
-static int pci20xxx_dio_insn_config(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data);
-
-/* initialize struct pci20xxx_private */
-static int pci20xxx_dio_init(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 32;
-	s->insn_bits = pci20xxx_dio_insn_bits;
-	s->insn_config = pci20xxx_dio_insn_config;
-	s->maxdata = 1;
-	s->len_chanlist = 32;
-	s->range_table = &range_digital;
-	s->io_bits = 0;
-
-	/* digital I/O lines default to input on board reset. */
-	pci20xxx_dio_config(dev, s);
-
-	return 0;
-}
-
-static int pci20xxx_dio_insn_config(struct comedi_device *dev,
-				    struct comedi_subdevice *s,
-				    struct comedi_insn *insn,
-				    unsigned int *data)
-{
-	int mask, bits;
-
-	mask = 1 << CR_CHAN(insn->chanspec);
-	if (mask & 0x000000ff)
-		bits = 0x000000ff;
-	else if (mask & 0x0000ff00)
-		bits = 0x0000ff00;
-	else if (mask & 0x00ff0000)
-		bits = 0x00ff0000;
-	else
-		bits = 0xff000000;
-	if (data[0])
-		s->io_bits |= bits;
-	else
-		s->io_bits &= ~bits;
-	pci20xxx_dio_config(dev, s);
-
-	return 1;
-}
-
-static int pci20xxx_dio_insn_bits(struct comedi_device *dev,
-				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
-{
-	struct pci20xxx_private *devpriv = dev->private;
-	unsigned int mask = data[0];
-
-	s->state &= ~mask;
-	s->state |= (mask & data[1]);
-
-	mask &= s->io_bits;
-	if (mask & 0x000000ff)
-		writeb((s->state >> 0) & 0xff,
-		       devpriv->ioaddr + PCI20000_DIO_0);
-	if (mask & 0x0000ff00)
-		writeb((s->state >> 8) & 0xff,
-		       devpriv->ioaddr + PCI20000_DIO_1);
-	if (mask & 0x00ff0000)
-		writeb((s->state >> 16) & 0xff,
-		       devpriv->ioaddr + PCI20000_DIO_2);
-	if (mask & 0xff000000)
-		writeb((s->state >> 24) & 0xff,
-		       devpriv->ioaddr + PCI20000_DIO_3);
-
-	data[1] = readb(devpriv->ioaddr + PCI20000_DIO_0);
-	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
-	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
-	data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
+	for (i = 0; i < insn->n; i++)
+		data[i] = ao_spriv->last_data[chan];
 
 	return insn->n;
 }
 
-static void pci20xxx_dio_config(struct comedi_device *dev,
-				struct comedi_subdevice *s)
+static int ii20k_ao_insn_write(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
-	struct pci20xxx_private *devpriv = dev->private;
-	unsigned char control_01;
-	unsigned char control_23;
-	unsigned char buffer;
+	struct ii20k_ao_private *ao_spriv = s->private;
+	void __iomem *iobase = ii20k_module_iobase(dev, s);
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int val = ao_spriv->last_data[chan];
+	int i;
 
-	control_01 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
-	control_23 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
-	buffer = readb(devpriv->ioaddr + PCI20000_DIO_BUFFER);
+	for (i = 0; i < insn->n; i++) {
+		val = data[i];
 
+		/* munge data */
+		val += ((s->maxdata + 1) >> 1);
+		val &= s->maxdata;
+
+		writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan));
+		writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan));
+		writeb(0x00, iobase + II20K_AO_STRB_REG(chan));
+	}
+
+	ao_spriv->last_data[chan] = val;
+
+	return insn->n;
+}
+
+static int ii20k_ai_wait_eoc(struct comedi_device *dev,
+			     struct comedi_subdevice *s,
+			     int timeout)
+{
+	void __iomem *iobase = ii20k_module_iobase(dev, s);
+	unsigned char status;
+
+	do {
+		status = readb(iobase + II20K_AI_STATUS_REG);
+		if ((status & II20K_AI_STATUS_INT) == 0)
+			return 0;
+	} while (timeout--);
+
+	return -ETIME;
+}
+
+static void ii20k_ai_setup(struct comedi_device *dev,
+			   struct comedi_subdevice *s,
+			   unsigned int chanspec)
+{
+	void __iomem *iobase = ii20k_module_iobase(dev, s);
+	unsigned int chan = CR_CHAN(chanspec);
+	unsigned int range = CR_RANGE(chanspec);
+	unsigned char val;
+
+	/* initialize module */
+	writeb(II20K_AI_CONF_ENA, iobase + II20K_AI_CONF_REG);
+
+	/* software conversion */
+	writeb(0, iobase + II20K_AI_STATUS_CMD_REG);
+
+	/* set the time base for the settling time counter based on the gain */
+	val = (range < 3) ? II20K_AI_OPT_TIMEBASE(0) : II20K_AI_OPT_TIMEBASE(2);
+	writeb(val, iobase + II20K_AI_OPT_REG);
+
+	/* set the settling time counter based on the gain */
+	val = (range < 2) ? 0x58 : (range < 3) ? 0x93 : 0x99;
+	writeb(val, iobase + II20K_AI_SET_TIME_REG);
+
+	/* set number of input channels */
+	writeb(1, iobase + II20K_AI_LAST_CHAN_ADDR_REG);
+
+	/* set the channel list byte */
+	val = II20K_AI_CHANLIST_ONBOARD_ONLY |
+	      II20K_AI_CHANLIST_MUX_ENA |
+	      II20K_AI_CHANLIST_GAIN(range) |
+	      II20K_AI_CHANLIST_CHAN(chan);
+	writeb(val, iobase + II20K_AI_CHANLIST_REG);
+
+	/* reset settling time counter and trigger delay counter */
+	writeb(0, iobase + II20K_AI_COUNT_RESET_REG);
+
+	/* reset channel scanner */
+	writeb(0, iobase + II20K_AI_CHAN_RESET_REG);
+}
+
+static int ii20k_ai_insn_read(struct comedi_device *dev,
+			      struct comedi_subdevice *s,
+			      struct comedi_insn *insn,
+			      unsigned int *data)
+{
+	void __iomem *iobase = ii20k_module_iobase(dev, s);
+	int ret;
+	int i;
+
+	ii20k_ai_setup(dev, s, insn->chanspec);
+
+	for (i = 0; i < insn->n; i++) {
+		unsigned int val;
+
+		/* generate a software start convert signal */
+		readb(iobase + II20K_AI_PACER_RESET_REG);
+
+		ret = ii20k_ai_wait_eoc(dev, s, 100);
+		if (ret)
+			return ret;
+
+		val = readb(iobase + II20K_AI_LSB_REG);
+		val |= (readb(iobase + II20K_AI_MSB_REG) << 8);
+
+		/* munge two's complement data */
+		val += ((s->maxdata + 1) >> 1);
+		val &= s->maxdata;
+
+		data[i] = val;
+	}
+
+	return insn->n;
+}
+
+static void ii20k_dio_config(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	struct ii20k_private *devpriv = dev->private;
+	unsigned char ctrl01 = 0;
+	unsigned char ctrl23 = 0;
+	unsigned char dir_ena = 0;
+
+	/* port 0 - channels 0-7 */
 	if (s->io_bits & 0x000000ff) {
-		/* output port 0 */
-		control_01 &= PCI20000_DIO_EOC;
-		buffer = (buffer & (~(DIO_BE << DIO_PS_0))) | (DIO_BO <<
-							       DIO_PS_0);
+		/* output port */
+		ctrl01 &= ~II20K_CTRL01_DIO0_IN;
+		dir_ena &= ~II20K_BUF_DISAB_DIO0;
+		dir_ena |= II20K_DIR_DIO0_OUT;
 	} else {
-		/* input port 0 */
-		control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_EIC;
-		buffer = (buffer & (~(DIO_BI << DIO_PS_0)));
+		/* input port */
+		ctrl01 |= II20K_CTRL01_DIO0_IN;
+		dir_ena &= ~II20K_DIR_DIO0_OUT;
 	}
+
+	/* port 1 - channels 8-15 */
 	if (s->io_bits & 0x0000ff00) {
-		/* output port 1 */
-		control_01 &= PCI20000_DIO_OOC;
-		buffer = (buffer & (~(DIO_BE << DIO_PS_1))) | (DIO_BO <<
-							       DIO_PS_1);
+		/* output port */
+		ctrl01 &= ~II20K_CTRL01_DIO1_IN;
+		dir_ena &= ~II20K_BUF_DISAB_DIO1;
+		dir_ena |= II20K_DIR_DIO1_OUT;
 	} else {
-		/* input port 1 */
-		control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_OIC;
-		buffer = (buffer & (~(DIO_BI << DIO_PS_1)));
+		/* input port */
+		ctrl01 |= II20K_CTRL01_DIO1_IN;
+		dir_ena &= ~II20K_DIR_DIO1_OUT;
 	}
+
+	/* port 2 - channels 16-23 */
 	if (s->io_bits & 0x00ff0000) {
-		/* output port 2 */
-		control_23 &= PCI20000_DIO_EOC;
-		buffer = (buffer & (~(DIO_BE << DIO_PS_2))) | (DIO_BO <<
-							       DIO_PS_2);
+		/* output port */
+		ctrl23 &= ~II20K_CTRL23_DIO2_IN;
+		dir_ena &= ~II20K_BUF_DISAB_DIO2;
+		dir_ena |= II20K_DIR_DIO2_OUT;
 	} else {
-		/* input port 2 */
-		control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_EIC;
-		buffer = (buffer & (~(DIO_BI << DIO_PS_2)));
+		/* input port */
+		ctrl23 |= II20K_CTRL23_DIO2_IN;
+		dir_ena &= ~II20K_DIR_DIO2_OUT;
 	}
+
+	/* port 3 - channels 24-31 */
 	if (s->io_bits & 0xff000000) {
-		/* output port 3 */
-		control_23 &= PCI20000_DIO_OOC;
-		buffer = (buffer & (~(DIO_BE << DIO_PS_3))) | (DIO_BO <<
-							       DIO_PS_3);
+		/* output port */
+		ctrl23 &= ~II20K_CTRL23_DIO3_IN;
+		dir_ena &= ~II20K_BUF_DISAB_DIO3;
+		dir_ena |= II20K_DIR_DIO3_OUT;
 	} else {
-		/* input port 3 */
-		control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_OIC;
-		buffer = (buffer & (~(DIO_BI << DIO_PS_3)));
+		/* input port */
+		ctrl23 |= II20K_CTRL23_DIO3_IN;
+		dir_ena &= ~II20K_DIR_DIO3_OUT;
 	}
-	writeb(control_01, devpriv->ioaddr + PCI20000_DIO_CONTROL_01);
-	writeb(control_23, devpriv->ioaddr + PCI20000_DIO_CONTROL_23);
-	writeb(buffer, devpriv->ioaddr + PCI20000_DIO_BUFFER);
+
+	ctrl23 |= II20K_CTRL01_SET;
+	ctrl23 |= II20K_CTRL23_SET;
+
+	/* order is important */
+	writeb(ctrl01, devpriv->ioaddr + II20K_CTRL01_REG);
+	writeb(ctrl23, devpriv->ioaddr + II20K_CTRL23_REG);
+	writeb(dir_ena, devpriv->ioaddr + II20K_DIR_ENA_REG);
 }
 
-#if 0
-static void pci20xxx_do(struct comedi_device *dev, struct comedi_subdevice *s)
+static int ii20k_dio_insn_config(struct comedi_device *dev,
+				 struct comedi_subdevice *s,
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
-	struct pci20xxx_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	/* XXX if the channel is configured for input, does this
-	   do bad things? */
-	/* XXX it would be a good idea to only update the registers
-	   that _need_ to be updated.  This requires changes to
-	   comedi, however. */
-	writeb((s->state >> 0) & 0xff, devpriv->ioaddr + PCI20000_DIO_0);
-	writeb((s->state >> 8) & 0xff, devpriv->ioaddr + PCI20000_DIO_1);
-	writeb((s->state >> 16) & 0xff, devpriv->ioaddr + PCI20000_DIO_2);
-	writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3);
+	if (chan < 8)
+		mask = 0x000000ff;
+	else if (chan < 16)
+		mask = 0x0000ff00;
+	else if (chan < 24)
+		mask = 0x00ff0000;
+	else
+		mask = 0xff000000;
+
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
+	ii20k_dio_config(dev, s);
+
+	return insn->n;
 }
 
-static unsigned int pci20xxx_di(struct comedi_device *dev,
-				struct comedi_subdevice *s)
+static int ii20k_dio_insn_bits(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
-	struct pci20xxx_private *devpriv = dev->private;
-	unsigned int bits;
+	struct ii20k_private *devpriv = dev->private;
+	unsigned int mask = data[0] & s->io_bits;	/* outputs only */
+	unsigned int bits = data[1];
 
-	/* XXX same note as above */
-	bits = readb(devpriv->ioaddr + PCI20000_DIO_0);
-	bits |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8;
-	bits |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16;
-	bits |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24;
+	if (mask) {
+		s->state &= ~mask;
+		s->state |= (bits & mask);
 
-	return bits;
+		if (mask & 0x000000ff)
+			writeb((s->state >> 0) & 0xff,
+			       devpriv->ioaddr + II20K_DIO0_REG);
+		if (mask & 0x0000ff00)
+			writeb((s->state >> 8) & 0xff,
+			       devpriv->ioaddr + II20K_DIO1_REG);
+		if (mask & 0x00ff0000)
+			writeb((s->state >> 16) & 0xff,
+			       devpriv->ioaddr + II20K_DIO2_REG);
+		if (mask & 0xff000000)
+			writeb((s->state >> 24) & 0xff,
+			       devpriv->ioaddr + II20K_DIO3_REG);
+	}
+
+	data[1] = readb(devpriv->ioaddr + II20K_DIO0_REG);
+	data[1] |= readb(devpriv->ioaddr + II20K_DIO1_REG) << 8;
+	data[1] |= readb(devpriv->ioaddr + II20K_DIO2_REG) << 16;
+	data[1] |= readb(devpriv->ioaddr + II20K_DIO3_REG) << 24;
+
+	return insn->n;
 }
-#endif
 
-static struct comedi_driver pci20xxx_driver = {
+static int ii20k_init_module(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	struct ii20k_ao_private *ao_spriv;
+	void __iomem *iobase = ii20k_module_iobase(dev, s);
+	unsigned char id;
+
+	id = readb(iobase + II20K_ID_REG);
+	switch (id) {
+	case II20K_ID_PCI20006M_1:
+	case II20K_ID_PCI20006M_2:
+		ao_spriv = comedi_alloc_spriv(s, sizeof(*ao_spriv));
+		if (!ao_spriv)
+			return -ENOMEM;
+
+		/* Analog Output subdevice */
+		s->type		= COMEDI_SUBD_AO;
+		s->subdev_flags	= SDF_WRITABLE;
+		s->n_chan	= (id == II20K_ID_PCI20006M_2) ? 2 : 1;
+		s->maxdata	= 0xffff;
+		s->range_table	= &ii20k_ao_ranges;
+		s->insn_read	= ii20k_ao_insn_read;
+		s->insn_write	= ii20k_ao_insn_write;
+		break;
+	case II20K_ID_PCI20341M_1:
+		/* Analog Input subdevice */
+		s->type		= COMEDI_SUBD_AI;
+		s->subdev_flags	= SDF_READABLE | SDF_DIFF;
+		s->n_chan	= 4;
+		s->maxdata	= 0xffff;
+		s->range_table	= &ii20k_ai_ranges;
+		s->insn_read	= ii20k_ai_insn_read;
+		break;
+	default:
+		s->type = COMEDI_SUBD_UNUSED;
+		break;
+	}
+
+	return 0;
+}
+
+static int ii20k_attach(struct comedi_device *dev,
+			struct comedi_devconfig *it)
+{
+	struct ii20k_private *devpriv;
+	struct comedi_subdevice *s;
+	unsigned char id;
+	bool has_dio;
+	int ret;
+
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+	if (!devpriv)
+		return -ENOMEM;
+
+	devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
+
+	id = readb(devpriv->ioaddr + II20K_ID_REG);
+	switch (id & II20K_ID_MASK) {
+	case II20K_ID_PCI20001C_1A:
+		break;
+	case II20K_ID_PCI20001C_2A:
+		has_dio = true;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ret = comedi_alloc_subdevices(dev, 4);
+	if (ret)
+		return ret;
+
+	s = &dev->subdevices[0];
+	if (id & II20K_ID_MOD1_EMPTY) {
+		s->type = COMEDI_SUBD_UNUSED;
+	} else {
+		ret = ii20k_init_module(dev, s);
+		if (ret)
+			return ret;
+	}
+
+	s = &dev->subdevices[1];
+	if (id & II20K_ID_MOD2_EMPTY) {
+		s->type = COMEDI_SUBD_UNUSED;
+	} else {
+		ret = ii20k_init_module(dev, s);
+		if (ret)
+			return ret;
+	}
+
+	s = &dev->subdevices[2];
+	if (id & II20K_ID_MOD3_EMPTY) {
+		s->type = COMEDI_SUBD_UNUSED;
+	} else {
+		ret = ii20k_init_module(dev, s);
+		if (ret)
+			return ret;
+	}
+
+	/* Digital I/O subdevice */
+	s = &dev->subdevices[3];
+	if (has_dio) {
+		s->type		= COMEDI_SUBD_DIO;
+		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+		s->n_chan	= 32;
+		s->maxdata	= 1;
+		s->range_table	= &range_digital;
+		s->insn_bits	= ii20k_dio_insn_bits;
+		s->insn_config	= ii20k_dio_insn_config;
+
+		/* default all channels to input */
+		ii20k_dio_config(dev, s);
+	} else {
+		s->type = COMEDI_SUBD_UNUSED;
+	}
+
+	return 0;
+}
+
+static struct comedi_driver ii20k_driver = {
 	.driver_name	= "ii_pci20kc",
 	.module		= THIS_MODULE,
-	.attach		= pci20xxx_attach,
-	.detach		= pci20xxx_detach,
+	.attach		= ii20k_attach,
+	.detach		= comedi_legacy_detach,
 };
-module_comedi_driver(pci20xxx_driver);
+module_comedi_driver(ii20k_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
 MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 94609f4..b52d58e 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -38,6 +38,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
@@ -638,10 +639,9 @@
 		return -EINVAL;
 	}
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	init_timer(&devpriv->timer);
 	switch (pcidev->device) {
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index f10cf10..15589f6 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -29,6 +29,7 @@
 Kolter Electronic PCI Counter Card.
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index c2308fd..8f4afad 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -40,6 +40,7 @@
 
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -1357,98 +1358,57 @@
 
 static int me4000_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	unsigned long tmp;
-	int chan = CR_CHAN(insn->chanspec);
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	unsigned int tmp;
+	int ret;
 
-	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;
-	}
+	if (chan < 8)
+		mask = 0x000000ff;
+	else if (chan < 16)
+		mask = 0x0000ff00;
+	else if (chan < 24)
+		mask = 0x00ff0000;
+	else
+		mask = 0xff000000;
 
-	/*
-	 * 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 INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
-	 * On the ME-4000 it is only possible to switch port wise (8 bit)
-	 */
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG);
+	tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 |
+		 ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 |
+		 ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 |
+		 ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7);
+	if (s->io_bits & 0x000000ff)
+		tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
+	if (s->io_bits & 0x0000ff00)
+		tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
+	if (s->io_bits & 0x00ff0000)
+		tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
+	if (s->io_bits & 0xff000000)
+		tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
 
-	if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
-		if (chan < 8) {
-			s->io_bits |= 0xFF;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
-				 ME4000_DIO_CTRL_BIT_MODE_1);
-			tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
-		} else if (chan < 16) {
-			/*
-			 * Chech for optoisolated ME-4000 version.
-			 * If one the first port is a fixed output
-			 * port and the second is a fixed input port.
-			 */
-			if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
-				return -ENODEV;
-
-			s->io_bits |= 0xFF00;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
-				 ME4000_DIO_CTRL_BIT_MODE_3);
-			tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
-		} else if (chan < 24) {
-			s->io_bits |= 0xFF0000;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
-				 ME4000_DIO_CTRL_BIT_MODE_5);
-			tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
-		} else if (chan < 32) {
-			s->io_bits |= 0xFF000000;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
-				 ME4000_DIO_CTRL_BIT_MODE_7);
-			tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
-		} else {
-			return -EINVAL;
-		}
-	} else {
-		if (chan < 8) {
-			/*
-			 * Chech for optoisolated ME-4000 version.
-			 * If one the first port is a fixed output
-			 * port and the second is a fixed input port.
-			 */
-			if (!inl(dev->iobase + ME4000_DIO_DIR_REG))
-				return -ENODEV;
-
-			s->io_bits &= ~0xFF;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |
-				 ME4000_DIO_CTRL_BIT_MODE_1);
-		} else if (chan < 16) {
-			s->io_bits &= ~0xFF00;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
-				 ME4000_DIO_CTRL_BIT_MODE_3);
-		} else if (chan < 24) {
-			s->io_bits &= ~0xFF0000;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 |
-				 ME4000_DIO_CTRL_BIT_MODE_5);
-		} else if (chan < 32) {
-			s->io_bits &= ~0xFF000000;
-			tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 |
-				 ME4000_DIO_CTRL_BIT_MODE_7);
-		} else {
-			return -EINVAL;
-		}
+	/*
+	 * Check for optoisolated ME-4000 version.
+	 * If one the first port is a fixed output
+	 * port and the second is a fixed input port.
+	 */
+	if (inl(dev->iobase + ME4000_DIO_DIR_REG)) {
+		s->io_bits |= 0x000000ff;
+		s->io_bits &= ~0x0000ff00;
+		tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
+		tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+			 ME4000_DIO_CTRL_BIT_MODE_3);
 	}
 
 	outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG);
 
-	return 1;
+	return insn->n;
 }
 
 /*=============================================================================
@@ -1544,10 +1504,9 @@
 	dev->board_ptr = thisboard;
 	dev->board_name = thisboard->name;
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = comedi_alloc_devpriv(dev, sizeof(*info));
 	if (!info)
 		return -ENOMEM;
-	dev->private = info;
 
 	result = comedi_pci_enable(dev);
 	if (result)
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 7533ece..a6f6d4a 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -30,6 +30,7 @@
  *    Analog Input, Analog Output, Digital I/O
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
@@ -185,38 +186,30 @@
 			      struct comedi_insn *insn,
 			      unsigned int *data)
 {
-	struct me_private_data *dev_private = dev->private;
-	unsigned int mask = 1 << CR_CHAN(insn->chanspec);
-	unsigned int bits;
-	unsigned int port;
+	struct me_private_data *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	if (mask & 0x0000ffff) {
-		bits = 0x0000ffff;
-		port = ENABLE_PORT_A;
-	} else {
-		bits = 0xffff0000;
-		port = ENABLE_PORT_B;
-	}
+	if (chan < 16)
+		mask = 0x0000ffff;
+	else
+		mask = 0xffff0000;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		dev_private->control_2 &= ~port;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		dev_private->control_2 |= port;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
-	/* Update the port configuration */
-	writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2);
+	if (s->io_bits & 0x0000ffff)
+		devpriv->control_2 |= ENABLE_PORT_A;
+	else
+		devpriv->control_2 &= ~ENABLE_PORT_A;
+	if (s->io_bits & 0xffff0000)
+		devpriv->control_2 |= ENABLE_PORT_B;
+	else
+		devpriv->control_2 &= ~ENABLE_PORT_B;
+
+	writew(devpriv->control_2, devpriv->me_regbase + ME_CONTROL_2);
 
 	return insn->n;
 }
@@ -490,10 +483,9 @@
 	dev->board_ptr = board;
 	dev->board_name = board->name;
 
-	dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL);
+	dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private));
 	if (!dev_private)
 		return -ENOMEM;
-	dev->private = dev_private;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index 12c34db..35cb4ac 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -46,6 +46,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index d4487e8..8423b8b 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -21,6 +21,7 @@
 
 #include <linux/pci.h>
 #include <linux/log2.h>
+#include <linux/slab.h>
 #include "../comedidev.h"
 
 /*  #define DEBUG_MITE */
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index 713842a..acbaeee 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -51,9 +51,9 @@
 	1      -10.1V .. +10.1V
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/delay.h>
 
 /* Consecutive I/O port addresses */
@@ -286,10 +286,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	switch (it->options[1]) {
 	case 0:
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index 5ecd1b1..9d75ea4 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -24,11 +24,10 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #define MULTIQ3_SIZE 16
 
 /*
@@ -232,10 +231,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	s = &dev->subdevices[0];
 	/* ai subdevice */
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 903c2ef..c2745f2 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -36,6 +36,7 @@
 #define DEBUG 1
 #define DEBUG_FLAGS
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -335,10 +336,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->mite = mite_alloc(pcidev);
 	if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 42a78de..3ba4c57 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -46,9 +46,9 @@
 #define DEBUG 1
 #define DEBUG_FLAGS
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 
 #include "../comedidev.h"
 
@@ -591,10 +591,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->mite = mite_alloc(pcidev);
 	if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index a9e0004..3607336 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -34,6 +34,7 @@
  * DAQ 6601/6602 User Manual (NI 322137B-01)
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -929,10 +930,9 @@
 	struct ni_660x_private *devpriv;
 	unsigned i;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	spin_lock_init(&devpriv->mite_channel_lock);
 	spin_lock_init(&devpriv->interrupt_lock);
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 1a185b9..e2926ce 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -36,9 +36,9 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 
 #include "../comedidev.h"
 
@@ -158,27 +158,16 @@
 
 static int ni_670x_dio_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn, unsigned int *data)
+				   struct comedi_insn *insn,
+				   unsigned int *data)
 {
 	struct ni_670x_private *devpriv = dev->private;
-	int chan = CR_CHAN(insn->chanspec);
+	int ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << chan;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << chan);
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
+
 	writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET);
 
 	return insn->n;
@@ -205,10 +194,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->mite = mite_alloc(pcidev);
 	if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 7ea5aa3..2512ce8 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -58,12 +58,14 @@
 
 */
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/io.h>
+
 #include <asm/dma.h>
 
 #include "8253.h"
@@ -719,10 +721,9 @@
 	int i;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], A2150_SIZE);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index e080053..b9122fd 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -36,10 +36,9 @@
  * document 320379.pdf.
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 /* board egisters */
 /* registers with _2_ are accessed when GRP2WR is set in CFG1 */
 
@@ -249,42 +248,35 @@
 
 static int atao_dio_insn_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 	struct atao_private *devpriv = dev->private;
-	int chan = CR_CHAN(insn->chanspec);
-	unsigned int mask, bit;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	/* 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. */
+	if (chan < 4)
+		mask = 0x0f;
+	else
+		mask = 0xf0;
 
-	mask = (chan < 4) ? 0x0f : 0xf0;
-	bit = (chan < 4) ? DOUTEN1 : DOUTEN2;
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= mask;
-		devpriv->cfg3 |= bit;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~mask;
-		devpriv->cfg3 &= ~bit;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
+	if (s->io_bits & 0x0f)
+		devpriv->cfg3 |= DOUTEN1;
+	else
+		devpriv->cfg3 &= ~DOUTEN1;
+	if (s->io_bits & 0xf0)
+		devpriv->cfg3 |= DOUTEN2;
+	else
+		devpriv->cfg3 &= ~DOUTEN2;
 
 	outw(devpriv->cfg3, dev->iobase + ATAO_CFG3);
 
-	return 1;
+	return insn->n;
 }
 
 /*
@@ -341,10 +333,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 713edd5..856c73d 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -89,10 +89,10 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/delay.h>
 #include <linux/isapnp.h>
 
 #include "ni_stc.h"
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index da7396f..bb3491f 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -30,11 +30,10 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #include "comedi_fc.h"
 #include "8255.h"
 
@@ -577,15 +576,19 @@
 				    unsigned int *data)
 {
 	struct atmio16d_private *devpriv = dev->private;
-	int i;
-	int mask;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	int ret;
 
-	for (i = 0; i < insn->n; i++) {
-		mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
-		s->io_bits &= ~mask;
-		if (data[i])
-			s->io_bits |= mask;
-	}
+	if (chan < 4)
+		mask = 0x0f;
+	else
+		mask = 0xf0;
+
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
 	devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1);
 	if (s->io_bits & 0x0f)
 		devpriv->com_reg_2_state |= COMREG2_DOUTEN0;
@@ -593,7 +596,7 @@
 		devpriv->com_reg_2_state |= COMREG2_DOUTEN1;
 	outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
 
-	return i;
+	return insn->n;
 }
 
 /*
@@ -645,10 +648,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* reset the atmio16d hardware */
 	reset_atmio16d(dev);
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 3c50e31..404f83d 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -45,9 +45,9 @@
 		User Manual:	http://www.ni.com/pdf/manuals/320676d.pdf
 */
 
-#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 
 #include "../comedidev.h"
 
@@ -90,21 +90,17 @@
 
 static int daq700_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	unsigned int chan = 1 << CR_CHAN(insn->chanspec);
+	int ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & chan) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
+
+	/* The DIO channels are not configurable, fix the io_bits */
+	s->io_bits = 0x00ff;
 
 	return insn->n;
 }
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index d3d4eb9..335ea34 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -31,6 +31,7 @@
 the PCMCIA interface.
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include <pcmcia/cistpl.h>
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index f161e70..1add114 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -57,6 +57,7 @@
  * 320502b (lab-pc+)
  */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -64,79 +65,12 @@
 
 #include "../comedidev.h"
 
-#include <asm/dma.h>
-
 #include "8253.h"
 #include "8255.h"
 #include "comedi_fc.h"
 #include "ni_labpc.h"
-
-/*
- * Register map (all registers are 8-bit)
- */
-#define STAT1_REG		0x00	/* R: Status 1 reg */
-#define STAT1_DAVAIL		(1 << 0)
-#define STAT1_OVERRUN		(1 << 1)
-#define STAT1_OVERFLOW		(1 << 2)
-#define STAT1_CNTINT		(1 << 3)
-#define STAT1_GATA0		(1 << 5)
-#define STAT1_EXTGATA0		(1 << 6)
-#define CMD1_REG		0x00	/* W: Command 1 reg */
-#define CMD1_MA(x)		(((x) & 0x7) << 0)
-#define CMD1_TWOSCMP		(1 << 3)
-#define CMD1_GAIN(x)		(((x) & 0x7) << 4)
-#define CMD1_SCANEN		(1 << 7)
-#define CMD2_REG		0x01	/* W: Command 2 reg */
-#define CMD2_PRETRIG		(1 << 0)
-#define CMD2_HWTRIG		(1 << 1)
-#define CMD2_SWTRIG		(1 << 2)
-#define CMD2_TBSEL		(1 << 3)
-#define CMD2_2SDAC0		(1 << 4)
-#define CMD2_2SDAC1		(1 << 5)
-#define CMD2_LDAC(x)		(1 << (6 + (x)))
-#define CMD3_REG		0x02	/* W: Command 3 reg */
-#define CMD3_DMAEN		(1 << 0)
-#define CMD3_DIOINTEN		(1 << 1)
-#define CMD3_DMATCINTEN		(1 << 2)
-#define CMD3_CNTINTEN		(1 << 3)
-#define CMD3_ERRINTEN		(1 << 4)
-#define CMD3_FIFOINTEN		(1 << 5)
-#define ADC_START_CONVERT_REG	0x03	/* W: Start Convert reg */
-#define DAC_LSB_REG(x)		(0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */
-#define DAC_MSB_REG(x)		(0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */
-#define ADC_FIFO_CLEAR_REG	0x08	/* W: A/D FIFO Clear reg */
-#define ADC_FIFO_REG		0x0a	/* R: A/D FIFO reg */
-#define DMATC_CLEAR_REG		0x0a	/* W: DMA Interrupt Clear reg */
-#define TIMER_CLEAR_REG		0x0c	/* W: Timer Interrupt Clear reg */
-#define CMD6_REG		0x0e	/* W: Command 6 reg */
-#define CMD6_NRSE		(1 << 0)
-#define CMD6_ADCUNI		(1 << 1)
-#define CMD6_DACUNI(x)		(1 << (2 + (x)))
-#define CMD6_HFINTEN		(1 << 5)
-#define CMD6_DQINTEN		(1 << 6)
-#define CMD6_SCANUP		(1 << 7)
-#define CMD4_REG		0x0f	/* W: Command 3 reg */
-#define CMD4_INTSCAN		(1 << 0)
-#define CMD4_EOIRCV		(1 << 1)
-#define CMD4_ECLKDRV		(1 << 2)
-#define CMD4_SEDIFF		(1 << 3)
-#define CMD4_ECLKRCV		(1 << 4)
-#define DIO_BASE_REG		0x10	/* R/W: 8255 DIO base reg */
-#define COUNTER_A_BASE_REG	0x14	/* R/W: 8253 Counter A base reg */
-#define COUNTER_B_BASE_REG	0x18	/* R/W: 8253 Counter B base reg */
-#define CMD5_REG		0x1c	/* W: Command 5 reg */
-#define CMD5_WRTPRT		(1 << 2)
-#define CMD5_DITHEREN		(1 << 3)
-#define CMD5_CALDACLD		(1 << 4)
-#define CMD5_SCLK		(1 << 5)
-#define CMD5_SDATA		(1 << 6)
-#define CMD5_EEPROMCS		(1 << 7)
-#define STAT2_REG		0x1d	/* R: Status 2 reg */
-#define STAT2_PROMOUT		(1 << 0)
-#define STAT2_OUTA1		(1 << 1)
-#define STAT2_FIFONHF		(1 << 2)
-#define INTERVAL_COUNT_REG	0x1e	/* W: Interval Counter Data reg */
-#define INTERVAL_STROBE_REG	0x1f	/* W: Interval Counter Strobe reg */
+#include "ni_labpc_regs.h"
+#include "ni_labpc_isadma.h"
 
 #define LABPC_SIZE		0x20	/* size of ISA io region */
 #define LABPC_TIMER_BASE	500	/* 2 MHz master clock */
@@ -239,11 +173,6 @@
 };
 #endif
 
-/* size in bytes of dma buffer */
-static const int dma_buffer_size = 0xff00;
-/* 2 bytes per sample */
-static const int sample_size = 2;
-
 static int labpc_counter_load(struct comedi_device *dev,
 			      unsigned long base_address,
 			      unsigned int counter_number,
@@ -451,32 +380,6 @@
 	return insn->n;
 }
 
-#ifdef CONFIG_ISA_DMA_API
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
-{
-	unsigned int size;
-	unsigned int freq;
-
-	if (cmd->convert_src == TRIG_TIMER)
-		freq = 1000000000 / cmd->convert_arg;
-	/* return some default value */
-	else
-		freq = 0xffffffff;
-
-	/* make buffer fill in no more than 1/3 second */
-	size = (freq / 3) * sample_size;
-
-	/* set a minimum and maximum size allowed */
-	if (size > dma_buffer_size)
-		size = dma_buffer_size - dma_buffer_size % sample_size;
-	else if (size < sample_size)
-		size = sample_size;
-
-	return size;
-}
-#endif
-
 static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd,
 				      enum scan_mode mode)
 {
@@ -869,25 +772,20 @@
 		return ret;
 	}
 
-#ifdef CONFIG_ISA_DMA_API
-	/*  figure out what method we will use to transfer data */
-	if (devpriv->dma_chan &&	/*  need a dma channel allocated */
-		/*
-		 * dma unsafe at RT priority,
-		 * and too much setup time for TRIG_WAKE_EOS for
-		 */
-	    (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) {
+	/* figure out what method we will use to transfer data */
+	if (labpc_have_dma_chan(dev) &&
+	    /* dma unsafe at RT priority,
+	     * and too much setup time for TRIG_WAKE_EOS */
+	    (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0)
 		xfer = isa_dma_transfer;
-		/* pc-plus has no fifo-half full interrupt */
-	} else
-#endif
-	if (board->is_labpc1200 &&
-		   /*  wake-end-of-scan should interrupt on fifo not empty */
-		   (cmd->flags & TRIG_WAKE_EOS) == 0 &&
-		   /*  make sure we are taking more than just a few points */
-		   (cmd->stop_src != TRIG_COUNT || devpriv->count > 256)) {
+	else if (/* pc-plus has no fifo-half full interrupt */
+		 board->is_labpc1200 &&
+		 /* wake-end-of-scan should interrupt on fifo not empty */
+		 (cmd->flags & TRIG_WAKE_EOS) == 0 &&
+		 /* make sure we are taking more than just a few points */
+		 (cmd->stop_src != TRIG_COUNT || devpriv->count > 256))
 		xfer = fifo_half_full_transfer;
-	} else
+	else
 		xfer = fifo_not_empty_transfer;
 	devpriv->current_transfer = xfer;
 
@@ -952,40 +850,14 @@
 
 	labpc_clear_adc_fifo(dev);
 
-#ifdef CONFIG_ISA_DMA_API
-	/*  set up dma transfer */
-	if (xfer == isa_dma_transfer) {
-		unsigned long irq_flags;
-
-		irq_flags = claim_dma_lock();
-		disable_dma(devpriv->dma_chan);
-		/* clear flip-flop to make sure 2-byte registers for
-		 * count and address get set correctly */
-		clear_dma_ff(devpriv->dma_chan);
-		set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
-		/*  set appropriate size of transfer */
-		devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
-		if (cmd->stop_src == TRIG_COUNT &&
-		    devpriv->count * sample_size < devpriv->dma_transfer_size) {
-			devpriv->dma_transfer_size =
-			    devpriv->count * sample_size;
-		}
-		set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
-		enable_dma(devpriv->dma_chan);
-		release_dma_lock(irq_flags);
-		/*  enable board's dma */
-		devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
-	} else
-		devpriv->cmd3 &= ~(CMD3_DMAEN | CMD3_DMATCINTEN);
-#endif
+	if (xfer == isa_dma_transfer)
+		labpc_setup_dma(dev, s);
 
 	/*  enable error interrupts */
 	devpriv->cmd3 |= CMD3_ERRINTEN;
 	/*  enable fifo not empty interrupt? */
 	if (xfer == fifo_not_empty_transfer)
 		devpriv->cmd3 |= CMD3_FIFOINTEN;
-	else
-		devpriv->cmd3 &= ~CMD3_FIFOINTEN;
 	devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
 
 	/*  setup any external triggering/pacing (cmd4 register) */
@@ -1026,74 +898,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_ISA_DMA_API
-static void labpc_drain_dma(struct comedi_device *dev)
-{
-	struct labpc_private *devpriv = dev->private;
-	struct comedi_subdevice *s = dev->read_subdev;
-	struct comedi_async *async = s->async;
-	int status;
-	unsigned long flags;
-	unsigned int max_points, num_points, residue, leftover;
-	int i;
-
-	status = devpriv->stat1;
-
-	flags = claim_dma_lock();
-	disable_dma(devpriv->dma_chan);
-	/* clear flip-flop to make sure 2-byte registers for
-	 * count and address get set correctly */
-	clear_dma_ff(devpriv->dma_chan);
-
-	/*  figure out how many points to read */
-	max_points = devpriv->dma_transfer_size / sample_size;
-	/* residue is the number of points left to be done on the dma
-	 * transfer.  It should always be zero at this point unless
-	 * the stop_src is set to external triggering.
-	 */
-	residue = get_dma_residue(devpriv->dma_chan) / sample_size;
-	num_points = max_points - residue;
-	if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
-		num_points = devpriv->count;
-
-	/*  figure out how many points will be stored next time */
-	leftover = 0;
-	if (async->cmd.stop_src != TRIG_COUNT) {
-		leftover = devpriv->dma_transfer_size / sample_size;
-	} else if (devpriv->count > num_points) {
-		leftover = devpriv->count - num_points;
-		if (leftover > max_points)
-			leftover = max_points;
-	}
-
-	/* write data to comedi buffer */
-	for (i = 0; i < num_points; i++)
-		cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
-
-	if (async->cmd.stop_src == TRIG_COUNT)
-		devpriv->count -= num_points;
-
-	/*  set address and count for next transfer */
-	set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
-	set_dma_count(devpriv->dma_chan, leftover * sample_size);
-	release_dma_lock(flags);
-
-	async->events |= COMEDI_CB_BLOCK;
-}
-
-static void handle_isa_dma(struct comedi_device *dev)
-{
-	struct labpc_private *devpriv = dev->private;
-
-	labpc_drain_dma(dev);
-
-	enable_dma(devpriv->dma_chan);
-
-	/*  clear dma tc interrupt */
-	devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
-}
-#endif
-
 /* read all available samples from ai fifo */
 static int labpc_drain_fifo(struct comedi_device *dev)
 {
@@ -1130,12 +934,10 @@
  * when acquisition is terminated by stop_src == TRIG_EXT). */
 static void labpc_drain_dregs(struct comedi_device *dev)
 {
-#ifdef CONFIG_ISA_DMA_API
 	struct labpc_private *devpriv = dev->private;
 
 	if (devpriv->current_transfer == isa_dma_transfer)
 		labpc_drain_dma(dev);
-#endif
 
 	labpc_drain_fifo(dev);
 }
@@ -1180,18 +982,9 @@
 		return IRQ_HANDLED;
 	}
 
-#ifdef CONFIG_ISA_DMA_API
-	if (devpriv->current_transfer == isa_dma_transfer) {
-		/*
-		 * if a dma terminal count of external stop trigger
-		 * has occurred
-		 */
-		if (devpriv->stat1 & STAT1_GATA0 ||
-		    (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) {
-			handle_isa_dma(dev);
-		}
-	} else
-#endif
+	if (devpriv->current_transfer == isa_dma_transfer)
+		labpc_handle_dma_status(dev);
+	else
 		labpc_drain_fifo(dev);
 
 	if (devpriv->stat1 & STAT1_CNTINT) {
@@ -1697,10 +1490,9 @@
 	unsigned int dma_chan = it->options[2];
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_request_region(dev, it->options[0], LABPC_SIZE);
 	if (ret)
@@ -1710,29 +1502,8 @@
 	if (ret)
 		return ret;
 
-#ifdef CONFIG_ISA_DMA_API
-	if (dev->irq && (dma_chan == 1 || dma_chan == 3)) {
-		devpriv->dma_buffer = kmalloc(dma_buffer_size,
-					      GFP_KERNEL | GFP_DMA);
-		if (devpriv->dma_buffer) {
-			ret = request_dma(dma_chan, dev->board_name);
-			if (ret == 0) {
-				unsigned long dma_flags;
-
-				devpriv->dma_chan = dma_chan;
-				devpriv->dma_addr =
-					virt_to_bus(devpriv->dma_buffer);
-
-				dma_flags = claim_dma_lock();
-				disable_dma(devpriv->dma_chan);
-				set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
-				release_dma_lock(dma_flags);
-			} else {
-				kfree(devpriv->dma_buffer);
-			}
-		}
-	}
-#endif
+	if (dev->irq)
+		labpc_init_dma_chan(dev, dma_chan);
 
 	return 0;
 }
@@ -1741,11 +1512,9 @@
 {
 	struct labpc_private *devpriv = dev->private;
 
-	if (devpriv) {
-		kfree(devpriv->dma_buffer);
-		if (devpriv->dma_chan)
-			free_dma(devpriv->dma_chan);
-	}
+	if (devpriv)
+		labpc_free_dma_chan(dev);
+
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index ce67f4b..0a8b322 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -53,10 +53,10 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include <linux/delay.h>
-#include <linux/slab.h>
 
 #include "8253.h"
 #include "8255.h"
@@ -96,10 +96,9 @@
 	if (!link->irq)
 		return -EINVAL;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	return labpc_common_attach(dev, link->irq, IRQF_SHARED);
 }
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
new file mode 100644
index 0000000..2149596
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
@@ -0,0 +1,226 @@
+/*
+ * comedi/drivers/ni_labpc_isadma.c
+ * ISA DMA support for National Instruments Lab-PC series boards and
+ * compatibles.
+ *
+ * Extracted from ni_labpc.c:
+ * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "../comedidev.h"
+
+#include <asm/dma.h>
+
+#include "comedi_fc.h"
+#include "ni_labpc.h"
+#include "ni_labpc_regs.h"
+#include "ni_labpc_isadma.h"
+
+/* size in bytes of dma buffer */
+static const int dma_buffer_size = 0xff00;
+/* 2 bytes per sample */
+static const int sample_size = 2;
+
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
+{
+	unsigned int size;
+	unsigned int freq;
+
+	if (cmd->convert_src == TRIG_TIMER)
+		freq = 1000000000 / cmd->convert_arg;
+	else
+		/* return some default value */
+		freq = 0xffffffff;
+
+	/* make buffer fill in no more than 1/3 second */
+	size = (freq / 3) * sample_size;
+
+	/* set a minimum and maximum size allowed */
+	if (size > dma_buffer_size)
+		size = dma_buffer_size - dma_buffer_size % sample_size;
+	else if (size < sample_size)
+		size = sample_size;
+
+	return size;
+}
+
+void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+	struct labpc_private *devpriv = dev->private;
+	struct comedi_cmd *cmd = &s->async->cmd;
+	unsigned long irq_flags;
+
+	irq_flags = claim_dma_lock();
+	disable_dma(devpriv->dma_chan);
+	/* clear flip-flop to make sure 2-byte registers for
+	 * count and address get set correctly */
+	clear_dma_ff(devpriv->dma_chan);
+	set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
+	/* set appropriate size of transfer */
+	devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
+	if (cmd->stop_src == TRIG_COUNT &&
+	    devpriv->count * sample_size < devpriv->dma_transfer_size)
+		devpriv->dma_transfer_size = devpriv->count * sample_size;
+	set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
+	enable_dma(devpriv->dma_chan);
+	release_dma_lock(irq_flags);
+	/* set CMD3 bits for caller to enable DMA and interrupt */
+	devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
+}
+EXPORT_SYMBOL_GPL(labpc_setup_dma);
+
+void labpc_drain_dma(struct comedi_device *dev)
+{
+	struct labpc_private *devpriv = dev->private;
+	struct comedi_subdevice *s = dev->read_subdev;
+	struct comedi_async *async = s->async;
+	int status;
+	unsigned long flags;
+	unsigned int max_points, num_points, residue, leftover;
+	int i;
+
+	status = devpriv->stat1;
+
+	flags = claim_dma_lock();
+	disable_dma(devpriv->dma_chan);
+	/* clear flip-flop to make sure 2-byte registers for
+	 * count and address get set correctly */
+	clear_dma_ff(devpriv->dma_chan);
+
+	/* figure out how many points to read */
+	max_points = devpriv->dma_transfer_size / sample_size;
+	/* residue is the number of points left to be done on the dma
+	 * transfer.  It should always be zero at this point unless
+	 * the stop_src is set to external triggering.
+	 */
+	residue = get_dma_residue(devpriv->dma_chan) / sample_size;
+	num_points = max_points - residue;
+	if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT)
+		num_points = devpriv->count;
+
+	/* figure out how many points will be stored next time */
+	leftover = 0;
+	if (async->cmd.stop_src != TRIG_COUNT) {
+		leftover = devpriv->dma_transfer_size / sample_size;
+	} else if (devpriv->count > num_points) {
+		leftover = devpriv->count - num_points;
+		if (leftover > max_points)
+			leftover = max_points;
+	}
+
+	/* write data to comedi buffer */
+	for (i = 0; i < num_points; i++)
+		cfc_write_to_buffer(s, devpriv->dma_buffer[i]);
+
+	if (async->cmd.stop_src == TRIG_COUNT)
+		devpriv->count -= num_points;
+
+	/* set address and count for next transfer */
+	set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
+	set_dma_count(devpriv->dma_chan, leftover * sample_size);
+	release_dma_lock(flags);
+
+	async->events |= COMEDI_CB_BLOCK;
+}
+EXPORT_SYMBOL_GPL(labpc_drain_dma);
+
+static void handle_isa_dma(struct comedi_device *dev)
+{
+	struct labpc_private *devpriv = dev->private;
+
+	labpc_drain_dma(dev);
+
+	enable_dma(devpriv->dma_chan);
+
+	/* clear dma tc interrupt */
+	devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG);
+}
+
+void labpc_handle_dma_status(struct comedi_device *dev)
+{
+	const struct labpc_boardinfo *board = comedi_board(dev);
+	struct labpc_private *devpriv = dev->private;
+
+	/*
+	 * if a dma terminal count of external stop trigger
+	 * has occurred
+	 */
+	if (devpriv->stat1 & STAT1_GATA0 ||
+	    (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1))
+		handle_isa_dma(dev);
+}
+EXPORT_SYMBOL_GPL(labpc_handle_dma_status);
+
+int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
+{
+	struct labpc_private *devpriv = dev->private;
+	void *dma_buffer;
+	unsigned long dma_flags;
+	int ret;
+
+	if (dma_chan != 1 && dma_chan != 3)
+		return -EINVAL;
+
+	dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
+	if (!dma_buffer)
+		return -ENOMEM;
+
+	ret = request_dma(dma_chan, dev->board_name);
+	if (ret) {
+		kfree(dma_buffer);
+		return ret;
+	}
+
+	devpriv->dma_buffer = dma_buffer;
+	devpriv->dma_chan = dma_chan;
+	devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer);
+
+	dma_flags = claim_dma_lock();
+	disable_dma(devpriv->dma_chan);
+	set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
+	release_dma_lock(dma_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(labpc_init_dma_chan);
+
+void labpc_free_dma_chan(struct comedi_device *dev)
+{
+	struct labpc_private *devpriv = dev->private;
+
+	kfree(devpriv->dma_buffer);
+	devpriv->dma_buffer = NULL;
+	if (devpriv->dma_chan) {
+		free_dma(devpriv->dma_chan);
+		devpriv->dma_chan = 0;
+	}
+}
+EXPORT_SYMBOL_GPL(labpc_free_dma_chan);
+
+static int __init ni_labpc_isadma_init_module(void)
+{
+	return 0;
+}
+module_init(ni_labpc_isadma_init_module);
+
+static void __exit ni_labpc_isadma_cleanup_module(void)
+{
+}
+module_exit(ni_labpc_isadma_cleanup_module);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi NI Lab-PC ISA DMA support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
new file mode 100644
index 0000000..771af4b
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
@@ -0,0 +1,57 @@
+/*
+ * ni_labpc ISA DMA support.
+*/
+
+#ifndef _NI_LABPC_ISADMA_H
+#define _NI_LABPC_ISADMA_H
+
+#define NI_LABPC_HAVE_ISA_DMA	IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA)
+
+#if NI_LABPC_HAVE_ISA_DMA
+
+static inline bool labpc_have_dma_chan(struct comedi_device *dev)
+{
+	struct labpc_private *devpriv = dev->private;
+
+	return (bool)devpriv->dma_chan;
+}
+
+int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan);
+void labpc_free_dma_chan(struct comedi_device *dev);
+void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s);
+void labpc_drain_dma(struct comedi_device *dev);
+void labpc_handle_dma_status(struct comedi_device *dev);
+
+#else
+
+static inline bool labpc_have_dma_chan(struct comedi_device *dev)
+{
+	return false;
+}
+
+static inline int labpc_init_dma_chan(struct comedi_device *dev,
+				      unsigned int dma_chan)
+{
+	return -ENOTSUPP;
+}
+
+static inline void labpc_free_dma_chan(struct comedi_device *dev)
+{
+}
+
+static inline void labpc_setup_dma(struct comedi_device *dev,
+				   struct comedi_subdevice *s)
+{
+}
+
+static inline void labpc_drain_dma(struct comedi_device *dev)
+{
+}
+
+static inline void labpc_handle_dma_status(struct comedi_device *dev)
+{
+}
+
+#endif
+
+#endif /* _NI_LABPC_ISADMA_H */
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
index 6c79237..8be681f 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_pci.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -29,8 +29,8 @@
  * 340914a (pci-1200)
  */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -72,10 +72,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->mite = mite_alloc(pcidev);
 	if (!devpriv->mite)
diff --git a/drivers/staging/comedi/drivers/ni_labpc_regs.h b/drivers/staging/comedi/drivers/ni_labpc_regs.h
new file mode 100644
index 0000000..2a274a3
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_regs.h
@@ -0,0 +1,75 @@
+/*
+ * ni_labpc register definitions.
+*/
+
+#ifndef _NI_LABPC_REGS_H
+#define _NI_LABPC_REGS_H
+
+/*
+ * Register map (all registers are 8-bit)
+ */
+#define STAT1_REG		0x00	/* R: Status 1 reg */
+#define STAT1_DAVAIL		(1 << 0)
+#define STAT1_OVERRUN		(1 << 1)
+#define STAT1_OVERFLOW		(1 << 2)
+#define STAT1_CNTINT		(1 << 3)
+#define STAT1_GATA0		(1 << 5)
+#define STAT1_EXTGATA0		(1 << 6)
+#define CMD1_REG		0x00	/* W: Command 1 reg */
+#define CMD1_MA(x)		(((x) & 0x7) << 0)
+#define CMD1_TWOSCMP		(1 << 3)
+#define CMD1_GAIN(x)		(((x) & 0x7) << 4)
+#define CMD1_SCANEN		(1 << 7)
+#define CMD2_REG		0x01	/* W: Command 2 reg */
+#define CMD2_PRETRIG		(1 << 0)
+#define CMD2_HWTRIG		(1 << 1)
+#define CMD2_SWTRIG		(1 << 2)
+#define CMD2_TBSEL		(1 << 3)
+#define CMD2_2SDAC0		(1 << 4)
+#define CMD2_2SDAC1		(1 << 5)
+#define CMD2_LDAC(x)		(1 << (6 + (x)))
+#define CMD3_REG		0x02	/* W: Command 3 reg */
+#define CMD3_DMAEN		(1 << 0)
+#define CMD3_DIOINTEN		(1 << 1)
+#define CMD3_DMATCINTEN		(1 << 2)
+#define CMD3_CNTINTEN		(1 << 3)
+#define CMD3_ERRINTEN		(1 << 4)
+#define CMD3_FIFOINTEN		(1 << 5)
+#define ADC_START_CONVERT_REG	0x03	/* W: Start Convert reg */
+#define DAC_LSB_REG(x)		(0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */
+#define DAC_MSB_REG(x)		(0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */
+#define ADC_FIFO_CLEAR_REG	0x08	/* W: A/D FIFO Clear reg */
+#define ADC_FIFO_REG		0x0a	/* R: A/D FIFO reg */
+#define DMATC_CLEAR_REG		0x0a	/* W: DMA Interrupt Clear reg */
+#define TIMER_CLEAR_REG		0x0c	/* W: Timer Interrupt Clear reg */
+#define CMD6_REG		0x0e	/* W: Command 6 reg */
+#define CMD6_NRSE		(1 << 0)
+#define CMD6_ADCUNI		(1 << 1)
+#define CMD6_DACUNI(x)		(1 << (2 + (x)))
+#define CMD6_HFINTEN		(1 << 5)
+#define CMD6_DQINTEN		(1 << 6)
+#define CMD6_SCANUP		(1 << 7)
+#define CMD4_REG		0x0f	/* W: Command 3 reg */
+#define CMD4_INTSCAN		(1 << 0)
+#define CMD4_EOIRCV		(1 << 1)
+#define CMD4_ECLKDRV		(1 << 2)
+#define CMD4_SEDIFF		(1 << 3)
+#define CMD4_ECLKRCV		(1 << 4)
+#define DIO_BASE_REG		0x10	/* R/W: 8255 DIO base reg */
+#define COUNTER_A_BASE_REG	0x14	/* R/W: 8253 Counter A base reg */
+#define COUNTER_B_BASE_REG	0x18	/* R/W: 8253 Counter B base reg */
+#define CMD5_REG		0x1c	/* W: Command 5 reg */
+#define CMD5_WRTPRT		(1 << 2)
+#define CMD5_DITHEREN		(1 << 3)
+#define CMD5_CALDACLD		(1 << 4)
+#define CMD5_SCLK		(1 << 5)
+#define CMD5_SDATA		(1 << 6)
+#define CMD5_EEPROMCS		(1 << 7)
+#define STAT2_REG		0x1d	/* R: Status 2 reg */
+#define STAT2_PROMOUT		(1 << 0)
+#define STAT2_OUTA1		(1 << 1)
+#define STAT2_FIFONHF		(1 << 2)
+#define INTERVAL_COUNT_REG	0x1e	/* W: Interval Counter Data reg */
+#define INTERVAL_STROBE_REG	0x1f	/* W: Interval Counter Strobe reg */
+
+#endif /* _NI_LABPC_REGS_H */
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 3e9f544..4e02770 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -58,6 +58,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include "8255.h"
 #include "mite.h"
 #include "comedi_fc.h"
@@ -3527,37 +3528,21 @@
 
 static int ni_dio_insn_config(struct comedi_device *dev,
 			      struct comedi_subdevice *s,
-			      struct comedi_insn *insn, unsigned int *data)
+			      struct comedi_insn *insn,
+			      unsigned int *data)
 {
 	struct ni_private *devpriv = dev->private;
+	int ret;
 
-#ifdef DEBUG_DIO
-	printk("ni_dio_insn_config() chan=%d io=%d\n",
-	       CR_CHAN(insn->chanspec), data[0]);
-#endif
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << CR_CHAN(insn->chanspec);
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->
-		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
-		    COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
 	devpriv->dio_control &= ~DIO_Pins_Dir_Mask;
 	devpriv->dio_control |= DIO_Pins_Dir(s->io_bits);
 	devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register);
 
-	return 1;
+	return insn->n;
 }
 
 static int ni_dio_insn_bits(struct comedi_device *dev,
@@ -3595,32 +3580,15 @@
 				       unsigned int *data)
 {
 	struct ni_private *devpriv __maybe_unused = dev->private;
+	int ret;
 
-#ifdef DEBUG_DIO
-	printk("ni_m_series_dio_insn_config() chan=%d io=%d\n",
-	       CR_CHAN(insn->chanspec), data[0]);
-#endif
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << CR_CHAN(insn->chanspec);
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->
-		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
-		    COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
 	ni_writel(s->io_bits, M_Offset_DIO_Direction);
 
-	return 1;
+	return insn->n;
 }
 
 static int ni_m_series_dio_insn_bits(struct comedi_device *dev,
@@ -4363,10 +4331,9 @@
 {
 	struct ni_private *devpriv;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	spin_lock_init(&devpriv->window_lock);
 	spin_lock_init(&devpriv->soft_reg_copy_lock);
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index f813f57..229a273 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -36,6 +36,7 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include <linux/delay.h>
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 5b2f72e..fad81bc 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -50,6 +50,7 @@
 /* #define DEBUG 1 */
 /* #define DEBUG_FLAGS */
 
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
@@ -639,32 +640,19 @@
 
 static int ni_pcidio_insn_config(struct comedi_device *dev,
 				 struct comedi_subdevice *s,
-				 struct comedi_insn *insn, unsigned int *data)
+				 struct comedi_insn *insn,
+				 unsigned int *data)
 {
 	struct nidio96_private *devpriv = dev->private;
+	int ret;
 
-	if (insn->n != 1)
-		return -EINVAL;
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << CR_CHAN(insn->chanspec);
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->
-		     io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
-		    COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
+
 	writel(s->io_bits, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));
 
-	return 1;
+	return insn->n;
 }
 
 static int ni_pcidio_insn_bits(struct comedi_device *dev,
@@ -1108,10 +1096,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	spin_lock_init(&devpriv->mite_channel_lock);
 
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 35681ba..536be83 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -106,6 +106,7 @@
 
 */
 
+#include <linux/module.h>
 #include <linux/delay.h>
 
 #include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index f2cf76d..9b120c7 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -44,6 +44,9 @@
 	Support use of both banks X and Y
 */
 
+#include <linux/module.h>
+#include <linux/slab.h>
+
 #include "ni_tio_internal.h"
 
 static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter,
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index cff50bc..45691ef 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -44,6 +44,7 @@
 	Support use of both banks X and Y
 */
 
+#include <linux/module.h>
 #include "comedi_fc.h"
 #include "ni_tio_internal.h"
 #include "mite.h"
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 7abf3f7..e859f85 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -53,10 +53,10 @@
 
  */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/delay.h>
 
 #include "comedi_fc.h"
@@ -474,10 +474,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	s = &dev->subdevices[0];
 	/* AI subdevice */
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index cea657c..8af13e7 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -1,6 +1,6 @@
 /*
  * pcl724.c
- * Comedi driver for 8255 based ISA DIO boards
+ * Comedi driver for 8255 based ISA and PC/104 DIO boards
  *
  * Michal Dobes <dobes@tesnet.cz>
  */
@@ -14,6 +14,7 @@
  *	    (ADLink) ACL-7122 [acl7122]
  *	    (ADLink) ACL-7124 [acl7124]
  *	    (ADLink) PET-48DIO [pet48dio]
+ *	    (WinSystems) PCM-IO48 [pcmio48]
  * Author: Michal Dobes <dobes@tesnet.cz>
  * Status: untested
  *
@@ -25,11 +26,9 @@
  *	   1,  96:  96 DIO configuration
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-#include <linux/delay.h>
-
 #include "8255.h"
 
 #define SIZE_8255	4
@@ -70,6 +69,10 @@
 		.io_range	= 0x02,
 		.is_pet48	= 1,
 		.numofports	= 2,	/* 48 DIO channels */
+	}, {
+		.name		= "pcmio48",
+		.io_range	= 0x08,
+		.numofports	= 2,	/* 48 DIO channels */
 	},
 };
 
@@ -148,5 +151,5 @@
 module_comedi_driver(pcl724_driver);
 
 MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi driver for 8255 based ISA DIO boards");
+MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 893f012..a4d0bcc 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -62,10 +62,9 @@
     their web page.  (http://www.cir.com/)
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #undef ACL6126_IRQ		/* no interrupt support (yet) */
 
 #define PCL726_SIZE 16
@@ -229,10 +228,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	for (i = 0; i < 12; i++) {
 		devpriv->bipolar[i] = 0;
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index 862e75f..2a659f2 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -27,10 +27,9 @@
  * The ACL-7130 card has an 8254 timer/counter not supported by this driver.
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 /*
  * Register map
  *
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index cd02786..03a0989 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -108,12 +108,12 @@
  *	   3= 20V unipolar inputs
  */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/gfp.h>
 #include "../comedidev.h"
 
 #include <linux/delay.h>
-#include <linux/ioport.h>
 #include <linux/io.h>
 #include <asm/dma.h>
 
@@ -1110,10 +1110,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	irq = 0;
 	if (board->IRQbits != 0) {	/* board support IRQ */
@@ -1405,6 +1404,7 @@
 		if (it->options[3] > 0)
 						/*  we use external trigger */
 			devpriv->use_ext_trg = 1;
+		break;
 	case boardA821:
 		devpriv->max_812_ai_mode0_rangewait = 1;
 		devpriv->mode_reg_int = (irq << 4) & 0xf0;
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 91bd207..f031349 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -32,9 +32,9 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
 #include <linux/gfp.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -922,10 +922,9 @@
 		return -EIO;
 	}
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* grab our IRQ */
 	irq = 0;
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 91cb1bd..a52ba82 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -98,7 +98,7 @@
 
 */
 
-#include <linux/ioport.h>
+#include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -1227,10 +1227,9 @@
 	unsigned long pages;
 	struct comedi_subdevice *s;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->io_range = board->io_range;
 	if ((board->fifo) && (it->options[2] == -1)) {
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 5a9cd38..cc1dc7f 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -28,11 +28,9 @@
  *   struct comedi_insn
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-#include <linux/delay.h>
-
 #include "8255.h"
 
 #define PCM3724_SIZE   16
@@ -186,39 +184,30 @@
 /* overriding the 8255 insn config */
 static int subdev_3724_insn_config(struct comedi_device *dev,
 				   struct comedi_subdevice *s,
-				   struct comedi_insn *insn, unsigned int *data)
+				   struct comedi_insn *insn,
+				   unsigned int *data)
 {
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	unsigned int mask;
-	unsigned int bits;
+	int ret;
 
-	mask = 1 << CR_CHAN(insn->chanspec);
-	if (mask & 0x0000ff)
-		bits = 0x0000ff;
-	else if (mask & 0x00ff00)
-		bits = 0x00ff00;
-	else if (mask & 0x0f0000)
-		bits = 0x0f0000;
+	if (chan < 8)
+		mask = 0x0000ff;
+	else if (chan < 16)
+		mask = 0x00ff00;
+	else if (chan < 20)
+		mask = 0x0f0000;
 	else
-		bits = 0xf00000;
+		mask = 0xf00000;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~bits;
-		break;
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= bits;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
 
 	do_3724_config(dev, s, insn->chanspec);
 	enable_chan(dev, s, insn->chanspec);
-	return 1;
+
+	return insn->n;
 }
 
 static int pcm3724_attach(struct comedi_device *dev,
@@ -228,10 +217,9 @@
 	struct comedi_subdevice *s;
 	int ret, i;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = comedi_alloc_devpriv(dev, sizeof(*priv));
 	if (!priv)
 		return -ENOMEM;
-	dev->private = priv;
 
 	ret = comedi_request_region(dev, it->options[0], PCM3724_SIZE);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index d5c728d..423f236 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -38,6 +38,7 @@
  *	   1 = two's complement (+-10V input range)
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #define PCMAD_STATUS		0
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 774a63d..1c7a135 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -48,6 +48,7 @@
  *   [1] - Do Simultaneous Xfer (see description)
  */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 /* AI range is not configurable, it's set by jumpers on the board */
@@ -138,10 +139,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->simultaneous_xfer_mode = it->options[1];
 
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 9f76b1f..574443d 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -72,6 +72,7 @@
 	leave out if you don't need this feature)
 */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
@@ -309,68 +310,27 @@
 	return insn->n;
 }
 
-/* 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. */
 static int pcmmio_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no =
-	    chan % 8;
-	unsigned long ioaddr;
-	unsigned char byte;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int byte_no = chan / 8;
+	int bit_no = chan % 8;
+	int ret;
 
-	/* Compute ioaddr for this channel */
-	ioaddr = subpriv->iobases[byte_no];
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
-	/* NOTE:
-	   writing a 0 an IO channel's bit sets the channel to INPUT
-	   and pulls the line high as well
+	if (data[0] == INSN_CONFIG_DIO_INPUT) {
+		unsigned long ioaddr = subpriv->iobases[byte_no];
+		unsigned char val;
 
-	   writing a 1 to an IO channel's  bit pulls the line low
-
-	   All channels are implicitly always in OUTPUT mode -- but when
-	   they are high they can be considered to be in INPUT mode..
-
-	   Thus, we only force channels low if the config request was INPUT,
-	   otherwise we do nothing to the hardware.    */
-
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		/* save to io_bits -- don't actually do anything since
-		   all input channels are also output channels... */
-		s->io_bits |= 1 << chan;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		/* write a 0 to the actual register representing the channel
-		   to set it to 'input'.  0 means "float high". */
-		byte = inb(ioaddr);
-		byte &= ~(1 << bit_no);
-				/**< set input channel to '0' */
-
-		/*
-		 * write out byte -- this is the only time we actually affect
-		 * the hardware as all channels are implicitly output
-		 * -- but input channels are set to float-high
-		 */
-		outb(byte, ioaddr);
-
-		/* save to io_bits */
-		s->io_bits &= ~(1 << chan);
-		break;
-
-	case INSN_CONFIG_DIO_QUERY:
-		/* retrieve from shadow register */
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-
-	default:
-		return -EINVAL;
-		break;
+		val = inb(ioaddr);
+		val &= ~(1 << bit_no);
+		outb(val, ioaddr);
 	}
 
 	return insn->n;
@@ -1039,10 +999,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	for (asic = 0; asic < MAX_ASICS; ++asic) {
 		devpriv->asics[asic].num = asic;
@@ -1197,12 +1156,13 @@
 	struct pcmmio_private *devpriv = dev->private;
 	int i;
 
-	for (i = 0; i < MAX_ASICS; ++i) {
-		if (devpriv && devpriv->asics[i].irq)
-			free_irq(devpriv->asics[i].irq, dev);
-	}
-	if (devpriv && devpriv->sprivs)
+	if (devpriv) {
+		for (i = 0; i < MAX_ASICS; ++i) {
+			if (devpriv->asics[i].irq)
+				free_irq(devpriv->asics[i].irq, dev);
+		}
 		kfree(devpriv->sprivs);
+	}
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index c43b633..67e2bb1 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -73,6 +73,7 @@
  *             can be the same as first irq!)
  */
 
+#include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
@@ -232,27 +233,19 @@
 
 static int pcmuio_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec);
 	int asic = s->index / 2;
 	int port = (s->index % 2) ? 3 : 0;
+	int ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= chan_mask;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~chan_mask;
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
+
+	if (data[0] == INSN_CONFIG_DIO_INPUT)
 		pcmuio_write(dev, s->io_bits, asic, 0, port);
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & chan_mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
 
 	return insn->n;
 }
@@ -609,10 +602,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	for (asic = 0; asic < PCMUIO_MAX_ASICS; ++asic)
 		spin_lock_init(&devpriv->asics[asic].spinlock);
@@ -680,12 +672,13 @@
 	struct pcmuio_private *devpriv = dev->private;
 	int i;
 
-	for (i = 0; i < PCMUIO_MAX_ASICS; ++i) {
-		if (devpriv->asics[i].irq)
-			free_irq(devpriv->asics[i].irq, dev);
-	}
-	if (devpriv && devpriv->sprivs)
+	if (devpriv) {
+		for (i = 0; i < PCMUIO_MAX_ASICS; ++i) {
+			if (devpriv->asics[i].irq)
+				free_irq(devpriv->asics[i].irq, dev);
+		}
 		kfree(devpriv->sprivs);
+	}
 	comedi_legacy_detach(dev);
 }
 
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index 005fbef..2ae4ee1 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -30,10 +30,9 @@
   [0] - I/O port base
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 struct boarddef_struct {
 	const char *name;
 	unsigned int iosize;
@@ -109,10 +108,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* analog output subdevice */
 	s = &dev->subdevices[0];
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index e092ce8..9775d36 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -47,6 +47,7 @@
 Devices: [Quatech] DAQP-208 (daqp), DAQP-308
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 #include <linux/semaphore.h>
 
@@ -715,10 +716,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
 	ret = comedi_pcmcia_enable(dev, NULL);
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 9b93a1f..93c980c 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -95,6 +95,7 @@
  * Digital-IO and Analog-Out only support instruction mode.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -1237,23 +1238,11 @@
 			       unsigned int *data)
 {
 	struct rtd_private *devpriv = dev->private;
-	unsigned int chan = CR_CHAN(insn->chanspec);
-	unsigned int mask = 1 << chan;
+	int ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= mask;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~mask;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
 	/* TODO support digital match interrupts and strobes */
 
@@ -1338,10 +1327,9 @@
 	dev->board_ptr = board;
 	dev->board_name = board->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index f698c7f..cbb4ba5 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -49,11 +49,11 @@
  *   [8] - DAC 1 encoding (same as DAC 0)
  */
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/interrupt.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 /*
  * Register map
  */
@@ -298,10 +298,9 @@
 	inb(dev->iobase + RTI800_ADCHI);
 	outb(0, dev->iobase + RTI800_CLRFLAGS);
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->adc_2comp = (it->options[4] == 0);
 	devpriv->dac_2comp[0] = (it->options[6] == 0);
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 9e74450..a3fa2a4 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -32,10 +32,9 @@
     [17] - dac#7 ...
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
-#include <linux/ioport.h>
-
 #define RTI802_SIZE 4
 
 #define RTI802_SELECT 0
@@ -93,10 +92,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 1);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index e1587e5..d629463 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -36,8 +36,8 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
-#include <linux/ioport.h>
 #include <asm/byteorder.h>
 
 #define S526_SIZE 64
@@ -515,32 +515,35 @@
 
 static int s526_dio_insn_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 	unsigned int chan = CR_CHAN(insn->chanspec);
-	int group, mask;
+	unsigned int mask;
+	int ret;
 
-	group = chan >> 2;
-	mask = 0xF << (group << 2);
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		/* bit 10/11 set the group 1/2's mode */
-		s->state |= 1 << (group + 10);
-		s->io_bits |= mask;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */
-		s->io_bits &= ~mask;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-	default:
-		return -EINVAL;
-	}
+	if (chan < 4)
+		mask = 0x0f;
+	else
+		mask = 0xf0;
+
+	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
+	if (ret)
+		return ret;
+
+	/* bit 10/11 set the group 1/2's mode */
+	if (s->io_bits & 0x0f)
+		s->state |= (1 << 10);
+	else
+		s->state &= ~(1 << 10);
+	if (s->io_bits & 0xf0)
+		s->state |= (1 << 11);
+	else
+		s->state &= ~(1 << 11);
+
 	outw(s->state, dev->iobase + REG_DIO);
 
-	return 1;
+	return insn->n;
 }
 
 static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -553,10 +556,9 @@
 	if (ret)
 		return ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_alloc_subdevices(dev, 4);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 48c4b70..d22b95d 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -59,6 +59,8 @@
    comedi_do_insn(cf,&insn); //executing configuration
 */
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -1660,24 +1662,12 @@
 				unsigned int *data)
 {
 	unsigned long group = (unsigned long)s->private;
-	unsigned int chan = CR_CHAN(insn->chanspec);
-	unsigned int mask = 1 << chan;
+	int ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	case COMEDI_INPUT:
-		s->io_bits &= ~mask;
-		break;
-	case COMEDI_OUTPUT:
-		s->io_bits |= mask;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
+
 	DEBIwrite(dev, LP_WRDOUT(group), s->io_bits);
 
 	return insn->n;
@@ -2585,10 +2575,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	ret = comedi_pci_enable(dev);
 	if (ret)
diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h
index d2756b8..a85e6bd 100644
--- a/drivers/staging/comedi/drivers/s626.h
+++ b/drivers/staging/comedi/drivers/s626.h
@@ -65,8 +65,6 @@
 #define FALSE   (0)
 #endif
 
-#include <linux/slab.h>
-
 #define S626_SIZE 0x0200
 #define DMABUF_SIZE			4096	/*  4k pages */
 
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index b4f5fe3..441813f 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -26,10 +26,10 @@
 
 */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 #include <linux/delay.h>
-#include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 
@@ -719,10 +719,9 @@
 	struct comedi_subdevice *s;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->port = it->options[0];
 	devpriv->speed = it->options[1];
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index 06aee30..9e96495 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -67,6 +67,7 @@
  * options that are used with comedi_config.
  */
 
+#include <linux/module.h>
 #include <linux/pci.h>
 
 #include "../comedidev.h"
@@ -361,31 +362,27 @@
 
 static int skel_dio_insn_config(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	int chan = CR_CHAN(insn->chanspec);
+	int ret;
 
-	/* 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. */
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << chan;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << chan);
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-	/* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */
+	/*
+	 * The input or output configuration of each digital line is
+	 * configured by special insn_config instructions.
+	 *
+	 * chanspec contains the channel to be changed
+	 * data[0] contains the instruction to perform on the channel
+	 *
+	 * Normally the core provided comedi_dio_insn_config() function
+	 * can be used to handle the boilerplpate.
+	 */
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
+
+	/* Update the hardware to the new configuration */
+	/* outw(s->io_bits, dev->iobase + SKEL_DIO_CONFIG); */
 
 	return insn->n;
 }
@@ -484,10 +481,9 @@
 	/* dev->board_name = thisboard->name; */
 
 	/* Allocate the private data */
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 /*
  * Supported boards are usually either auto-attached via the
@@ -558,10 +554,9 @@
 	dev->board_name = thisboard->name;
 
 	/* Allocate the private data */
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	/* Enable the PCI device. */
 	ret = comedi_pci_enable(dev);
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 45c661c..11758a5 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -26,6 +26,7 @@
 
 /* include files ----------------------------------------------------------- */
 
+#include <linux/module.h>
 #include "../comedidev.h"
 
 /* Some global definitions: the registers of the DNP ----------------------- */
@@ -92,68 +93,48 @@
 
 }
 
-/* ------------------------------------------------------------------------- */
-/* Configure the direction of the bidirectional digital i/o pins. chanspec   */
-/* contains the channel to be changed and data[0] contains either            */
-/* COMEDI_INPUT or COMEDI_OUTPUT.                                            */
-/* ------------------------------------------------------------------------- */
-
 static int dnp_dio_insn_config(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int mask;
+	unsigned int val;
+	int ret;
 
-	u8 register_buffer;
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
-	/* reduces chanspec to lower 16 bits */
-	int chan = CR_CHAN(insn->chanspec);
-
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-	case INSN_CONFIG_DIO_INPUT:
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (inb(CSCDR) & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		return insn->n;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-	/* Test: which port does the channel belong to?                       */
-
-	/* We have to pay attention with port C: this is the meaning of PCMR: */
-	/* Bit in PCMR:              7 6 5 4 3 2 1 0                          */
-	/* Corresponding port C pin: d 3 d 2 d 1 d 0   d= don't touch         */
-
-	if ((chan >= 0) && (chan <= 7)) {
-		/* this is port A */
+	if (chan < 8) {			/* Port A */
+		mask = 1 << chan;
 		outb(PAMR, CSCIR);
-	} else if ((chan >= 8) && (chan <= 15)) {
-		/* this is port B */
-		chan -= 8;
+	} else if (chan < 16) {		/* Port B */
+		mask = 1 << (chan - 8);
 		outb(PBMR, CSCIR);
-	} else if ((chan >= 16) && (chan <= 19)) {
-		/* this is port C; multiplication with 2 brings bits into     */
-		/* correct position for PCMR!                                 */
-		chan -= 16;
-		chan *= 2;
+	} else {			/* Port C */
+		/*
+		 * We have to pay attention with port C.
+		 * This is the meaning of PCMR:
+		 *   Bit in PCMR:              7 6 5 4 3 2 1 0
+		 *   Corresponding port C pin: d 3 d 2 d 1 d 0   d= don't touch
+		 *
+		 * Multiplication by 2 brings bits into correct position
+		 * for PCMR!
+		 */
+		mask = 1 << ((chan - 16) * 2);
 		outb(PCMR, CSCIR);
-	} else {
-		return -EINVAL;
 	}
 
-	/* read 'old' direction of the port and set bits (out=1, in=0)        */
-	register_buffer = inb(CSCDR);
+	val = inb(CSCDR);
 	if (data[0] == COMEDI_OUTPUT)
-		register_buffer |= (1 << chan);
+		val |= mask;
 	else
-		register_buffer &= ~(1 << chan);
+		val &= ~mask;
+	outb(val, CSCDR);
 
-	outb(register_buffer, CSCDR);
-
-	return 1;
+	return insn->n;
 
 }
 
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index c9201d8..93eec2f 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -40,9 +40,9 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/module.h>
+#include <linux/delay.h>
 #include "../comedidev.h"
-#include <linux/ioport.h>
-#include <linux/slab.h>
 
 #define DRIVER_NAME "unioxx5"
 #define UNIOXX5_SIZE 0x10
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 279e5bd..701ad1a 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -78,9 +78,6 @@
  *
  */
 
-/* generates loads of debug info */
-/* #define NOISY_DUX_DEBUGBUG */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -94,42 +91,29 @@
 
 #include "comedi_fc.h"
 
-/* timeout for the USB-transfer in ms*/
-#define BULK_TIMEOUT 1000
+/* constants for firmware upload and download */
+#define USBDUX_FIRMWARE		"usbdux_firmware.bin"
+#define USBDUX_FIRMWARE_MAX_LEN	0x2000
+#define USBDUX_FIRMWARE_CMD	0xa0
+#define VENDOR_DIR_IN		0xc0
+#define VENDOR_DIR_OUT		0x40
+#define USBDUX_CPU_CS		0xe600
 
-/* constants for "firmware" upload and download */
-#define FIRMWARE "usbdux_firmware.bin"
-#define USBDUXSUB_FIRMWARE 0xA0
-#define VENDOR_DIR_IN  0xC0
-#define VENDOR_DIR_OUT 0x40
+/* usbdux bulk transfer commands */
+#define USBDUX_CMD_MULT_AI	0
+#define USBDUX_CMD_AO		1
+#define USBDUX_CMD_DIO_CFG	2
+#define USBDUX_CMD_DIO_BITS	3
+#define USBDUX_CMD_SINGLE_AI	4
+#define USBDUX_CMD_TIMER_RD	5
+#define USBDUX_CMD_TIMER_WR	6
+#define USBDUX_CMD_PWM_ON	7
+#define USBDUX_CMD_PWM_OFF	8
 
-/* internal addresses of the 8051 processor */
-#define USBDUXSUB_CPUCS 0xE600
+#define USBDUX_NUM_AO_CHAN	4
 
-/*
- * the minor device number, major is 180 only for debugging purposes and to
- * upload special firmware (programming the eeprom etc) which is not compatible
- * with the comedi framwork
- */
-#define USBDUXSUB_MINOR 32
-
-/* max lenghth of the transfer-buffer for software upload */
-#define TB_LEN 0x2000
-
-/* Input endpoint number: ISO/IRQ */
-#define ISOINEP           6
-
-/* Output endpoint number: ISO/IRQ */
-#define ISOOUTEP          2
-
-/* This EP sends DUX commands to USBDUX */
-#define COMMAND_OUT_EP     1
-
-/* This EP receives the DUX commands from USBDUX */
-#define COMMAND_IN_EP        8
-
-/* Output endpoint for PWM */
-#define PWM_EP         4
+/* timeout for the USB-transfer in ms */
+#define BULK_TIMEOUT		1000
 
 /* 300Hz max frequ under PWM */
 #define MIN_PWM_PERIOD  ((long)(1E9/300))
@@ -137,9 +121,6 @@
 /* Default PWM frequency */
 #define PWM_DEFAULT_PERIOD ((long)(1E9/100))
 
-/* Number of channels */
-#define NUMCHANNELS       8
-
 /* Size of one A/D value */
 #define SIZEADIN          ((sizeof(int16_t)))
 
@@ -152,9 +133,6 @@
 /* 16 bytes. */
 #define SIZEINSNBUF       16
 
-/* Number of DA channels */
-#define NUMOUTCHANNELS    8
-
 /* size of one value for the D/A converter: channel and value */
 #define SIZEDAOUT          ((sizeof(int8_t)+sizeof(int16_t)))
 
@@ -185,101 +163,56 @@
 /* must have more buffers due to buggy USB ctr */
 #define NUMOFOUTBUFFERSHIGH    10
 
-/* Total number of usbdux devices */
-#define NUMUSBDUX             16
-
-/* Analogue in subdevice */
-#define SUBDEV_AD             0
-
-/* Analogue out subdevice */
-#define SUBDEV_DA             1
-
-/* Digital I/O */
-#define SUBDEV_DIO            2
-
-/* counter */
-#define SUBDEV_COUNTER        3
-
-/* timer aka pwm output */
-#define SUBDEV_PWM            4
-
 /* number of retries to get the right dux command */
 #define RETRIES 10
 
-/**************************************************/
-/* comedi constants */
-static const struct comedi_lrange range_usbdux_ai_range = { 4, {
-								BIP_RANGE
-								(4.096),
-								BIP_RANGE(4.096
-									  / 2),
-								UNI_RANGE
-								(4.096),
-								UNI_RANGE(4.096
-									  / 2)
-								}
+static const struct comedi_lrange range_usbdux_ai_range = {
+	4, {
+		BIP_RANGE(4.096),
+		BIP_RANGE(4.096 / 2),
+		UNI_RANGE(4.096),
+		UNI_RANGE(4.096 / 2)
+	}
 };
 
-static const struct comedi_lrange range_usbdux_ao_range = { 2, {
-								BIP_RANGE
-								(4.096),
-								UNI_RANGE
-								(4.096),
-								}
+static const struct comedi_lrange range_usbdux_ao_range = {
+	2, {
+		BIP_RANGE(4.096),
+		UNI_RANGE(4.096)
+	}
 };
 
-/*
- * private structure of one subdevice
- */
-
-/*
- * This is the structure which holds all the data of
- * this driver one sub device just now: A/D
- */
-struct usbduxsub {
-	/* attached? */
-	int attached;
-	/* is it associated with a subdevice? */
-	int probed;
-	/* pointer to the usb-device */
-	struct usb_device *usbdev;
+struct usbdux_private {
 	/* actual number of in-buffers */
-	int num_in_buffers;
+	int n_ai_urbs;
 	/* actual number of out-buffers */
-	int num_out_buffers;
+	int n_ao_urbs;
 	/* ISO-transfer handling: buffers */
-	struct urb **urb_in;
-	struct urb **urb_out;
+	struct urb **ai_urbs;
+	struct urb **ao_urbs;
 	/* pwm-transfer handling */
-	struct urb *urb_pwm;
+	struct urb *pwm_urb;
 	/* PWM period */
 	unsigned int pwm_period;
 	/* PWM internal delay for the GPIF in the FX2 */
-	int8_t pwn_delay;
+	int8_t pwm_delay;
 	/* size of the PWM buffer which holds the bit pattern */
-	int size_pwm_buf;
+	int pwm_buf_sz;
 	/* input buffer for the ISO-transfer */
-	int16_t *in_buffer;
+	int16_t *in_buf;
 	/* input buffer for single insn */
-	int16_t *insn_buffer;
-	/* output buffer for single DA outputs */
-	int16_t *out_buffer;
-	/* interface number */
-	int ifnum;
-	/* interface structure in 2.6 */
-	struct usb_interface *interface;
-	/* comedi device for the interrupt context */
-	struct comedi_device *comedidev;
-	/* is it USB_SPEED_HIGH or not? */
-	short int high_speed;
-	/* asynchronous command is running */
-	short int ai_cmd_running;
-	short int ao_cmd_running;
-	/* pwm is running */
-	short int pwm_cmd_running;
-	/* continous acquisition */
-	short int ai_continous;
-	short int ao_continous;
+	int16_t *insn_buf;
+
+	int8_t ao_chanlist[USBDUX_NUM_AO_CHAN];
+	unsigned int ao_readback[USBDUX_NUM_AO_CHAN];
+
+	unsigned int high_speed:1;
+	unsigned int ai_cmd_running:1;
+	unsigned int ai_continous:1;
+	unsigned int ao_cmd_running:1;
+	unsigned int ao_continous:1;
+	unsigned int pwm_cmd_running:1;
+
 	/* number of samples to acquire */
 	int ai_sample_count;
 	int ao_sample_count;
@@ -291,132 +224,62 @@
 	unsigned int ao_counter;
 	/* interval in frames/uframes */
 	unsigned int ai_interval;
-	/* D/A commands */
-	int8_t *dac_commands;
 	/* commands */
 	int8_t *dux_commands;
 	struct semaphore sem;
 };
 
-/*
- * The pointer to the private usb-data of the driver is also the private data
- * for the comedi-device.  This has to be global as the usb subsystem needs
- * global variables. The other reason is that this structure must be there
- * _before_ any comedi command is issued. The usb subsystem must be initialised
- * before comedi can access it.
- */
-static struct usbduxsub usbduxsub[NUMUSBDUX];
-
-static DEFINE_SEMAPHORE(start_stop_sem);
-
-/*
- * Stops the data acquision
- * It should be safe to call this function from any context
- */
-static int usbduxsub_unlink_inurbs(struct usbduxsub *usbduxsub_tmp)
+static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs)
 {
-	int i = 0;
-	int err = 0;
+	int i;
 
-	if (usbduxsub_tmp && usbduxsub_tmp->urb_in) {
-		for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
-			if (usbduxsub_tmp->urb_in[i]) {
-				/* We wait here until all transfers have been
-				 * cancelled. */
-				usb_kill_urb(usbduxsub_tmp->urb_in[i]);
-			}
-			dev_dbg(&usbduxsub_tmp->interface->dev,
-				"comedi: usbdux: unlinked InURB %d, err=%d\n",
-				i, err);
-		}
-	}
-	return err;
+	for (i = 0; i < num_urbs; i++)
+		usb_kill_urb(urbs[i]);
 }
 
-/*
- * This will stop a running acquisition operation
- * Is called from within this driver from both the
- * interrupt context and from comedi
- */
-static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
+static void usbdux_ai_stop(struct comedi_device *dev, int do_unlink)
 {
-	int ret = 0;
+	struct usbdux_private *devpriv = dev->private;
 
-	if (!this_usbduxsub) {
-		pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
-		return -EFAULT;
-	}
-	dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n");
+	if (do_unlink && devpriv->ai_urbs)
+		usbdux_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs);
 
-	if (do_unlink) {
-		/* stop aquistion */
-		ret = usbduxsub_unlink_inurbs(this_usbduxsub);
-	}
-
-	this_usbduxsub->ai_cmd_running = 0;
-
-	return ret;
+	devpriv->ai_cmd_running = 0;
 }
 
-/*
- * This will cancel a running acquisition operation.
- * This is called by comedi but never from inside the driver.
- */
 static int usbdux_ai_cancel(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
-	struct usbduxsub *this_usbduxsub;
-	int res = 0;
-
-	/* force unlink of all urbs */
-	this_usbduxsub = dev->private;
-	if (!this_usbduxsub)
-		return -EFAULT;
-
-	dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n");
+	struct usbdux_private *devpriv = dev->private;
 
 	/* prevent other CPUs from submitting new commands just now */
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
+	down(&devpriv->sem);
 	/* unlink only if the urb really has been submitted */
-	res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running);
-	up(&this_usbduxsub->sem);
-	return res;
+	usbdux_ai_stop(dev, devpriv->ai_cmd_running);
+	up(&devpriv->sem);
+
+	return 0;
 }
 
 /* analogue IN - interrupt service routine */
 static void usbduxsub_ai_isoc_irq(struct urb *urb)
 {
+	struct comedi_device *dev = urb->context;
+	struct comedi_subdevice *s = dev->read_subdev;
+	struct usbdux_private *devpriv = dev->private;
 	int i, err, n;
-	struct usbduxsub *this_usbduxsub;
-	struct comedi_device *this_comedidev;
-	struct comedi_subdevice *s;
-
-	/* the context variable points to the subdevice */
-	this_comedidev = urb->context;
-	/* the private structure of the subdevice is struct usbduxsub */
-	this_usbduxsub = this_comedidev->private;
-	/* subdevice which is the AD converter */
-	s = &this_comedidev->subdevices[SUBDEV_AD];
 
 	/* first we test if something unusual has just happened */
 	switch (urb->status) {
 	case 0:
 		/* copy the result in the transfer buffer */
-		memcpy(this_usbduxsub->in_buffer,
-		       urb->transfer_buffer, SIZEINBUF);
+		memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF);
 		break;
 	case -EILSEQ:
 		/* error in the ISOchronous data */
 		/* we don't copy the data into the transfer buffer */
 		/* and recycle the last data byte */
-		dev_dbg(&urb->dev->dev,
-			"comedi%d: usbdux: CRC error in ISO IN stream.\n",
-			this_usbduxsub->comedidev->minor);
-
+		dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n");
 		break;
 
 	case -ECONNRESET:
@@ -424,29 +287,27 @@
 	case -ESHUTDOWN:
 	case -ECONNABORTED:
 		/* happens after an unlink command */
-		if (this_usbduxsub->ai_cmd_running) {
-			/* we are still running a command */
-			/* tell this comedi */
+		if (devpriv->ai_cmd_running) {
 			s->async->events |= COMEDI_CB_EOA;
 			s->async->events |= COMEDI_CB_ERROR;
-			comedi_event(this_usbduxsub->comedidev, s);
+			comedi_event(dev, s);
 			/* stop the transfer w/o unlink */
-			usbdux_ai_stop(this_usbduxsub, 0);
+			usbdux_ai_stop(dev, 0);
 		}
 		return;
 
 	default:
 		/* a real error on the bus */
 		/* pass error to comedi if we are really running a command */
-		if (this_usbduxsub->ai_cmd_running) {
-			dev_err(&urb->dev->dev,
-				"Non-zero urb status received in ai intr "
-				"context: %d\n", urb->status);
+		if (devpriv->ai_cmd_running) {
+			dev_err(dev->class_dev,
+				"Non-zero urb status received in ai intr context: %d\n",
+				urb->status);
 			s->async->events |= COMEDI_CB_EOA;
 			s->async->events |= COMEDI_CB_ERROR;
-			comedi_event(this_usbduxsub->comedidev, s);
+			comedi_event(dev, s);
 			/* don't do an unlink here */
-			usbdux_ai_stop(this_usbduxsub, 0);
+			usbdux_ai_stop(dev, 0);
 		}
 		return;
 	}
@@ -455,7 +316,7 @@
 	 * at this point we are reasonably sure that nothing dodgy has happened
 	 * are we running a command?
 	 */
-	if (unlikely((!(this_usbduxsub->ai_cmd_running)))) {
+	if (unlikely(!devpriv->ai_cmd_running)) {
 		/*
 		 * not running a command, do not continue execution if no
 		 * asynchronous command is running in particular not resubmit
@@ -463,144 +324,101 @@
 		return;
 	}
 
-	urb->dev = this_usbduxsub->usbdev;
+	urb->dev = comedi_to_usb_dev(dev);
 
 	/* resubmit the urb */
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (unlikely(err < 0)) {
-		dev_err(&urb->dev->dev,
-			"comedi_: urb resubmit failed in int-context! err=%d\n",
-			err);
+		dev_err(dev->class_dev,
+			"urb resubmit failed in int-context! err=%d\n", err);
 		if (err == -EL2NSYNC)
-			dev_err(&urb->dev->dev,
-				"buggy USB host controller or bug in IRQ "
-				"handler!\n");
+			dev_err(dev->class_dev,
+				"buggy USB host controller or bug in IRQ handler!\n");
 		s->async->events |= COMEDI_CB_EOA;
 		s->async->events |= COMEDI_CB_ERROR;
-		comedi_event(this_usbduxsub->comedidev, s);
+		comedi_event(dev, s);
 		/* don't do an unlink here */
-		usbdux_ai_stop(this_usbduxsub, 0);
+		usbdux_ai_stop(dev, 0);
 		return;
 	}
 
-	this_usbduxsub->ai_counter--;
-	if (likely(this_usbduxsub->ai_counter > 0))
+	devpriv->ai_counter--;
+	if (likely(devpriv->ai_counter > 0))
 		return;
 
 	/* timer zero, transfer measurements to comedi */
-	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
+	devpriv->ai_counter = devpriv->ai_timer;
 
 	/* test, if we transmit only a fixed number of samples */
-	if (!(this_usbduxsub->ai_continous)) {
+	if (!devpriv->ai_continous) {
 		/* not continuous, fixed number of samples */
-		this_usbduxsub->ai_sample_count--;
+		devpriv->ai_sample_count--;
 		/* all samples received? */
-		if (this_usbduxsub->ai_sample_count < 0) {
+		if (devpriv->ai_sample_count < 0) {
 			/* prevent a resubmit next time */
-			usbdux_ai_stop(this_usbduxsub, 0);
+			usbdux_ai_stop(dev, 0);
 			/* say comedi that the acquistion is over */
 			s->async->events |= COMEDI_CB_EOA;
-			comedi_event(this_usbduxsub->comedidev, s);
+			comedi_event(dev, s);
 			return;
 		}
 	}
 	/* get the data from the USB bus and hand it over to comedi */
 	n = s->async->cmd.chanlist_len;
 	for (i = 0; i < n; i++) {
+		unsigned int range = CR_RANGE(s->async->cmd.chanlist[i]);
+		int16_t val = le16_to_cpu(devpriv->in_buf[i]);
+
+		/* bipolar data is two's-complement */
+		if (comedi_range_is_bipolar(s, range))
+			val ^= ((s->maxdata + 1) >> 1);
+
 		/* transfer data */
-		if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
-			err = comedi_buf_put
-			    (s->async,
-			     le16_to_cpu(this_usbduxsub->in_buffer[i]) ^ 0x800);
-		} else {
-			err = comedi_buf_put
-			    (s->async,
-			     le16_to_cpu(this_usbduxsub->in_buffer[i]));
-		}
+		err = comedi_buf_put(s->async, val);
 		if (unlikely(err == 0)) {
 			/* buffer overflow */
-			usbdux_ai_stop(this_usbduxsub, 0);
+			usbdux_ai_stop(dev, 0);
 			return;
 		}
 	}
 	/* tell comedi that data is there */
 	s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
-	comedi_event(this_usbduxsub->comedidev, s);
+	comedi_event(dev, s);
 }
 
-static int usbduxsub_unlink_outurbs(struct usbduxsub *usbduxsub_tmp)
+static void usbdux_ao_stop(struct comedi_device *dev, int do_unlink)
 {
-	int i = 0;
-	int err = 0;
+	struct usbdux_private *devpriv = dev->private;
 
-	if (usbduxsub_tmp && usbduxsub_tmp->urb_out) {
-		for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
-			if (usbduxsub_tmp->urb_out[i])
-				usb_kill_urb(usbduxsub_tmp->urb_out[i]);
+	if (do_unlink && devpriv->ao_urbs)
+		usbdux_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs);
 
-			dev_dbg(&usbduxsub_tmp->interface->dev,
-				"comedi: usbdux: unlinked OutURB %d: res=%d\n",
-				i, err);
-		}
-	}
-	return err;
+	devpriv->ao_cmd_running = 0;
 }
 
-/* This will cancel a running acquisition operation
- * in any context.
- */
-static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
-{
-	int ret = 0;
-
-	if (!this_usbduxsub)
-		return -EFAULT;
-	dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n");
-
-	if (do_unlink)
-		ret = usbduxsub_unlink_outurbs(this_usbduxsub);
-
-	this_usbduxsub->ao_cmd_running = 0;
-
-	return ret;
-}
-
-/* force unlink, is called by comedi */
 static int usbdux_ao_cancel(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int res = 0;
-
-	if (!this_usbduxsub)
-		return -EFAULT;
+	struct usbdux_private *devpriv = dev->private;
 
 	/* prevent other CPUs from submitting a command just now */
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
+	down(&devpriv->sem);
 	/* unlink only if it is really running */
-	res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running);
-	up(&this_usbduxsub->sem);
-	return res;
+	usbdux_ao_stop(dev, devpriv->ao_cmd_running);
+	up(&devpriv->sem);
+
+	return 0;
 }
 
 static void usbduxsub_ao_isoc_irq(struct urb *urb)
 {
-	int i, ret;
+	struct comedi_device *dev = urb->context;
+	struct comedi_subdevice *s = dev->write_subdev;
+	struct usbdux_private *devpriv = dev->private;
 	int8_t *datap;
-	struct usbduxsub *this_usbduxsub;
-	struct comedi_device *this_comedidev;
-	struct comedi_subdevice *s;
-
-	/* the context variable points to the subdevice */
-	this_comedidev = urb->context;
-	/* the private structure of the subdevice is struct usbduxsub */
-	this_usbduxsub = this_comedidev->private;
-
-	s = &this_comedidev->subdevices[SUBDEV_DA];
+	int len;
+	int ret;
+	int i;
 
 	switch (urb->status) {
 	case 0:
@@ -613,246 +431,131 @@
 	case -ECONNABORTED:
 		/* after an unlink command, unplug, ... etc */
 		/* no unlink needed here. Already shutting down. */
-		if (this_usbduxsub->ao_cmd_running) {
+		if (devpriv->ao_cmd_running) {
 			s->async->events |= COMEDI_CB_EOA;
-			comedi_event(this_usbduxsub->comedidev, s);
-			usbdux_ao_stop(this_usbduxsub, 0);
+			comedi_event(dev, s);
+			usbdux_ao_stop(dev, 0);
 		}
 		return;
 
 	default:
 		/* a real error */
-		if (this_usbduxsub->ao_cmd_running) {
-			dev_err(&urb->dev->dev,
-				"comedi_: Non-zero urb status received in ao "
-				"intr context: %d\n", urb->status);
+		if (devpriv->ao_cmd_running) {
+			dev_err(dev->class_dev,
+				"Non-zero urb status received in ao intr context: %d\n",
+				urb->status);
 			s->async->events |= COMEDI_CB_ERROR;
 			s->async->events |= COMEDI_CB_EOA;
-			comedi_event(this_usbduxsub->comedidev, s);
+			comedi_event(dev, s);
 			/* we do an unlink if we are in the high speed mode */
-			usbdux_ao_stop(this_usbduxsub, 0);
+			usbdux_ao_stop(dev, 0);
 		}
 		return;
 	}
 
 	/* are we actually running? */
-	if (!(this_usbduxsub->ao_cmd_running))
+	if (!devpriv->ao_cmd_running)
 		return;
 
 	/* normal operation: executing a command in this subdevice */
-	this_usbduxsub->ao_counter--;
-	if ((int)this_usbduxsub->ao_counter <= 0) {
+	devpriv->ao_counter--;
+	if ((int)devpriv->ao_counter <= 0) {
 		/* timer zero */
-		this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
+		devpriv->ao_counter = devpriv->ao_timer;
 
 		/* handle non continous acquisition */
-		if (!(this_usbduxsub->ao_continous)) {
+		if (!devpriv->ao_continous) {
 			/* fixed number of samples */
-			this_usbduxsub->ao_sample_count--;
-			if (this_usbduxsub->ao_sample_count < 0) {
+			devpriv->ao_sample_count--;
+			if (devpriv->ao_sample_count < 0) {
 				/* all samples transmitted */
-				usbdux_ao_stop(this_usbduxsub, 0);
+				usbdux_ao_stop(dev, 0);
 				s->async->events |= COMEDI_CB_EOA;
-				comedi_event(this_usbduxsub->comedidev, s);
+				comedi_event(dev, s);
 				/* no resubmit of the urb */
 				return;
 			}
 		}
-		/* transmit data to the USB bus */
-		((uint8_t *) (urb->transfer_buffer))[0] =
-		    s->async->cmd.chanlist_len;
-		for (i = 0; i < s->async->cmd.chanlist_len; i++) {
-			short temp;
-			if (i >= NUMOUTCHANNELS)
-				break;
 
-			/* pointer to the DA */
-			datap =
-			    (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1]));
-			/* get the data from comedi */
-			ret = comedi_buf_get(s->async, &temp);
-			datap[0] = temp;
-			datap[1] = temp >> 8;
-			datap[2] = this_usbduxsub->dac_commands[i];
-			/* printk("data[0]=%x, data[1]=%x, data[2]=%x\n", */
-			/* datap[0],datap[1],datap[2]); */
+		/* transmit data to the USB bus */
+		datap = urb->transfer_buffer;
+		len = s->async->cmd.chanlist_len;
+		*datap++ = len;
+		for (i = 0; i < s->async->cmd.chanlist_len; i++) {
+			unsigned int chan = devpriv->ao_chanlist[i];
+			short val;
+
+			ret = comedi_buf_get(s->async, &val);
 			if (ret < 0) {
-				dev_err(&urb->dev->dev,
-					"comedi: buffer underflow\n");
-				s->async->events |= COMEDI_CB_EOA;
-				s->async->events |= COMEDI_CB_OVERFLOW;
+				dev_err(dev->class_dev, "buffer underflow\n");
+				s->async->events |= (COMEDI_CB_EOA |
+						     COMEDI_CB_OVERFLOW);
 			}
-			/* transmit data to comedi */
+			/* pointer to the DA */
+			*datap++ = val & 0xff;
+			*datap++ = (val >> 8) & 0xff;
+			*datap++ = chan;
+			devpriv->ao_readback[chan] = val;
+
 			s->async->events |= COMEDI_CB_BLOCK;
-			comedi_event(this_usbduxsub->comedidev, s);
+			comedi_event(dev, s);
 		}
 	}
 	urb->transfer_buffer_length = SIZEOUTBUF;
-	urb->dev = this_usbduxsub->usbdev;
+	urb->dev = comedi_to_usb_dev(dev);
 	urb->status = 0;
-	if (this_usbduxsub->ao_cmd_running) {
-		if (this_usbduxsub->high_speed) {
-			/* uframes */
-			urb->interval = 8;
-		} else {
-			/* frames */
-			urb->interval = 1;
-		}
+	if (devpriv->ao_cmd_running) {
+		if (devpriv->high_speed)
+			urb->interval = 8;	/* uframes */
+		else
+			urb->interval = 1;	/* frames */
 		urb->number_of_packets = 1;
 		urb->iso_frame_desc[0].offset = 0;
 		urb->iso_frame_desc[0].length = SIZEOUTBUF;
 		urb->iso_frame_desc[0].status = 0;
 		ret = usb_submit_urb(urb, GFP_ATOMIC);
 		if (ret < 0) {
-			dev_err(&urb->dev->dev,
-				"comedi_: ao urb resubm failed in int-cont. "
-				"ret=%d", ret);
+			dev_err(dev->class_dev,
+				"ao urb resubm failed in int-cont. ret=%d",
+				ret);
 			if (ret == EL2NSYNC)
-				dev_err(&urb->dev->dev,
-					"buggy USB host controller or bug in "
-					"IRQ handling!\n");
+				dev_err(dev->class_dev,
+					"buggy USB host controller or bug in IRQ handling!\n");
 
 			s->async->events |= COMEDI_CB_EOA;
 			s->async->events |= COMEDI_CB_ERROR;
-			comedi_event(this_usbduxsub->comedidev, s);
+			comedi_event(dev, s);
 			/* don't do an unlink here */
-			usbdux_ao_stop(this_usbduxsub, 0);
+			usbdux_ao_stop(dev, 0);
 		}
 	}
 }
 
-#define FIRMWARE_MAX_LEN 0x2000
-
-static int usbdux_firmware_upload(struct comedi_device *dev,
-				  const u8 *data, size_t size,
-				  unsigned long context)
+static int usbdux_submit_urbs(struct comedi_device *dev,
+			      struct urb **urbs, int num_urbs,
+			      int input_urb)
 {
-	struct usbduxsub *usbduxsub = dev->private;
-	struct usb_device *usb = usbduxsub->usbdev;
-	uint8_t *buf;
-	uint8_t *tmp;
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	struct usbdux_private *devpriv = dev->private;
+	struct urb *urb;
 	int ret;
-
-	if (!data)
-		return 0;
-
-	if (size > FIRMWARE_MAX_LEN) {
-		dev_err(&usbduxsub->interface->dev,
-			"usbdux firmware binary it too large for FX2.\n");
-		return -ENOMEM;
-	}
-
-	/* we generate a local buffer for the firmware */
-	buf = kmemdup(data, size, GFP_KERNEL);
-	if (!buf)
-		return -ENOMEM;
-
-	/* we need a malloc'ed buffer for usb_control_msg() */
-	tmp = kmalloc(1, GFP_KERNEL);
-	if (!tmp) {
-		kfree(buf);
-		return -ENOMEM;
-	}
-
-	/* stop the current firmware on the device */
-	*tmp = 1;	/* 7f92 to one */
-	ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
-			      USBDUXSUB_FIRMWARE,
-			      VENDOR_DIR_OUT,
-			      USBDUXSUB_CPUCS, 0x0000,
-			      tmp, 1,
-			      BULK_TIMEOUT);
-	if (ret < 0) {
-		dev_err(&usbduxsub->interface->dev,
-			"comedi_: can not stop firmware\n");
-		goto done;
-	}
-
-	/* upload the new firmware to the device */
-	ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
-			      USBDUXSUB_FIRMWARE,
-			      VENDOR_DIR_OUT,
-			      0, 0x0000,
-			      buf, size,
-			      BULK_TIMEOUT);
-	if (ret < 0) {
-		dev_err(&usbduxsub->interface->dev,
-			"comedi_: firmware upload failed\n");
-		goto done;
-	}
-
-	/* start the new firmware on the device */
-	*tmp = 0;	/* 7f92 to zero */
-	ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
-			      USBDUXSUB_FIRMWARE,
-			      VENDOR_DIR_OUT,
-			      USBDUXSUB_CPUCS, 0x0000,
-			      tmp, 1,
-			      BULK_TIMEOUT);
-	if (ret < 0)
-		dev_err(&usbduxsub->interface->dev,
-			"comedi_: can not start firmware\n");
-
-done:
-	kfree(tmp);
-	kfree(buf);
-	return ret;
-}
-
-static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub)
-{
-	int i, err_flag;
-
-	if (!usbduxsub)
-		return -EFAULT;
+	int i;
 
 	/* Submit all URBs and start the transfer on the bus */
-	for (i = 0; i < usbduxsub->num_in_buffers; i++) {
+	for (i = 0; i < num_urbs; i++) {
+		urb = urbs[i];
+
 		/* in case of a resubmission after an unlink... */
-		usbduxsub->urb_in[i]->interval = usbduxsub->ai_interval;
-		usbduxsub->urb_in[i]->context = usbduxsub->comedidev;
-		usbduxsub->urb_in[i]->dev = usbduxsub->usbdev;
-		usbduxsub->urb_in[i]->status = 0;
-		usbduxsub->urb_in[i]->transfer_flags = URB_ISO_ASAP;
-		dev_dbg(&usbduxsub->interface->dev,
-			"comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n",
-			usbduxsub->comedidev->minor, i,
-			(usbduxsub->urb_in[i]->context),
-			(usbduxsub->urb_in[i]->dev),
-			(usbduxsub->urb_in[i]->interval));
-		err_flag = usb_submit_urb(usbduxsub->urb_in[i], GFP_ATOMIC);
-		if (err_flag) {
-			dev_err(&usbduxsub->interface->dev,
-				"comedi_: ai: usb_submit_urb(%d) error %d\n",
-				i, err_flag);
-			return err_flag;
-		}
-	}
-	return 0;
-}
+		if (input_urb)
+			urb->interval = devpriv->ai_interval;
+		urb->context = dev;
+		urb->dev = usb;
+		urb->status = 0;
+		urb->transfer_flags = URB_ISO_ASAP;
 
-static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub)
-{
-	int i, err_flag;
-
-	if (!usbduxsub)
-		return -EFAULT;
-
-	for (i = 0; i < usbduxsub->num_out_buffers; i++) {
-		dev_dbg(&usbduxsub->interface->dev,
-			"comedi_: submitting out-urb[%d]\n", i);
-		/* in case of a resubmission after an unlink... */
-		usbduxsub->urb_out[i]->context = usbduxsub->comedidev;
-		usbduxsub->urb_out[i]->dev = usbduxsub->usbdev;
-		usbduxsub->urb_out[i]->status = 0;
-		usbduxsub->urb_out[i]->transfer_flags = URB_ISO_ASAP;
-		err_flag = usb_submit_urb(usbduxsub->urb_out[i], GFP_ATOMIC);
-		if (err_flag) {
-			dev_err(&usbduxsub->interface->dev,
-				"comedi_: ao: usb_submit_urb(%d) error %d\n",
-				i, err_flag);
-			return err_flag;
-		}
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret)
+			return ret;
 	}
 	return 0;
 }
@@ -860,13 +563,10 @@
 static int usbdux_ai_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *this_usbduxsub = dev->private;
 	int err = 0, i;
 	unsigned int tmp_timer;
 
-	if (!(this_usbduxsub->probed))
-		return -ENODEV;
-
 	/* Step 1 : check if triggers are trivially valid */
 
 	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
@@ -956,221 +656,143 @@
 	return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3);
 }
 
-/* bulk transfers to usbdux */
-
-#define SENDADCOMMANDS            0
-#define SENDDACOMMANDS            1
-#define SENDDIOCONFIGCOMMAND      2
-#define SENDDIOBITSCOMMAND        3
-#define SENDSINGLEAD              4
-#define READCOUNTERCOMMAND        5
-#define WRITECOUNTERCOMMAND       6
-#define SENDPWMON                 7
-#define SENDPWMOFF                8
-
-static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type)
+static int send_dux_commands(struct comedi_device *dev, int cmd_type)
 {
-	int result, nsent;
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	struct usbdux_private *devpriv = dev->private;
+	int nsent;
 
-	this_usbduxsub->dux_commands[0] = cmd_type;
-#ifdef NOISY_DUX_DEBUGBUG
-	printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ",
-	       this_usbduxsub->comedidev->minor);
-	for (result = 0; result < SIZEOFDUXBUFFER; result++)
-		printk(" %02x", this_usbduxsub->dux_commands[result]);
-	printk("\n");
-#endif
-	result = usb_bulk_msg(this_usbduxsub->usbdev,
-			      usb_sndbulkpipe(this_usbduxsub->usbdev,
-					      COMMAND_OUT_EP),
-			      this_usbduxsub->dux_commands, SIZEOFDUXBUFFER,
-			      &nsent, BULK_TIMEOUT);
-	if (result < 0)
-		dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
-			"could not transmit dux_command to the usb-device, "
-			"err=%d\n", this_usbduxsub->comedidev->minor, result);
+	devpriv->dux_commands[0] = cmd_type;
 
-	return result;
+	return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1),
+			    devpriv->dux_commands, SIZEOFDUXBUFFER,
+			    &nsent, BULK_TIMEOUT);
 }
 
-static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
+static int receive_dux_commands(struct comedi_device *dev, int command)
 {
-	int result = (-EFAULT);
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	struct usbdux_private *devpriv = dev->private;
+	int ret;
 	int nrec;
 	int i;
 
 	for (i = 0; i < RETRIES; i++) {
-		result = usb_bulk_msg(this_usbduxsub->usbdev,
-				      usb_rcvbulkpipe(this_usbduxsub->usbdev,
-						      COMMAND_IN_EP),
-				      this_usbduxsub->insn_buffer, SIZEINSNBUF,
+		ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8),
+				      devpriv->insn_buf, SIZEINSNBUF,
 				      &nrec, BULK_TIMEOUT);
-		if (result < 0) {
-			dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
-				"insn: USB error %d while receiving DUX command"
-				"\n", this_usbduxsub->comedidev->minor, result);
-			return result;
-		}
-		if (le16_to_cpu(this_usbduxsub->insn_buffer[0]) == command)
-			return result;
+		if (ret < 0)
+			return ret;
+		if (le16_to_cpu(devpriv->insn_buf[0]) == command)
+			return ret;
 	}
-	/* this is only reached if the data has been requested a couple of
-	 * times */
-	dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: "
-		"wrong data returned from firmware: want cmd %d, got cmd %d.\n",
-		this_usbduxsub->comedidev->minor, command,
-		le16_to_cpu(this_usbduxsub->insn_buffer[0]));
+	/* command not received */
 	return -EFAULT;
 }
 
 static int usbdux_ai_inttrig(struct comedi_device *dev,
-			     struct comedi_subdevice *s, unsigned int trignum)
+			     struct comedi_subdevice *s,
+			     unsigned int trignum)
 {
-	int ret;
-	struct usbduxsub *this_usbduxsub = dev->private;
-	if (!this_usbduxsub)
-		return -EFAULT;
+	struct usbdux_private *devpriv = dev->private;
+	int ret = -EINVAL;
 
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi%d: usbdux_ai_inttrig\n", dev->minor);
+	down(&devpriv->sem);
 
-	if (trignum != 0) {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: usbdux_ai_inttrig: invalid trignum\n",
-			dev->minor);
-		up(&this_usbduxsub->sem);
-		return -EINVAL;
-	}
-	if (!(this_usbduxsub->ai_cmd_running)) {
-		this_usbduxsub->ai_cmd_running = 1;
-		ret = usbduxsub_submit_inurbs(this_usbduxsub);
+	if (trignum != 0)
+		goto ai_trig_exit;
+
+	if (!devpriv->ai_cmd_running) {
+		devpriv->ai_cmd_running = 1;
+		ret = usbdux_submit_urbs(dev, devpriv->ai_urbs,
+					 devpriv->n_ai_urbs, 1);
 		if (ret < 0) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi%d: usbdux_ai_inttrig: "
-				"urbSubmit: err=%d\n", dev->minor, ret);
-			this_usbduxsub->ai_cmd_running = 0;
-			up(&this_usbduxsub->sem);
-			return ret;
+			devpriv->ai_cmd_running = 0;
+			goto ai_trig_exit;
 		}
 		s->async->inttrig = NULL;
 	} else {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: ai_inttrig but acqu is already running\n",
-			dev->minor);
+		ret = -EBUSY;
 	}
-	up(&this_usbduxsub->sem);
-	return 1;
+
+ai_trig_exit:
+	up(&devpriv->sem);
+	return ret;
 }
 
 static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	struct usbdux_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int chan, range;
-	int i, ret;
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int result;
-
-	if (!this_usbduxsub)
-		return -EFAULT;
-
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi%d: usbdux_ai_cmd\n", dev->minor);
+	int len = cmd->chanlist_len;
+	int ret = -EBUSY;
+	int i;
 
 	/* block other CPUs from starting an ai_cmd */
-	down(&this_usbduxsub->sem);
+	down(&devpriv->sem);
 
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
-	if (this_usbduxsub->ai_cmd_running) {
-		dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
-			"ai_cmd not possible. Another ai_cmd is running.\n",
-			dev->minor);
-		up(&this_usbduxsub->sem);
-		return -EBUSY;
-	}
+	if (devpriv->ai_cmd_running)
+		goto ai_cmd_exit;
+
 	/* set current channel of the running acquisition to zero */
 	s->async->cur_chan = 0;
 
-	this_usbduxsub->dux_commands[1] = cmd->chanlist_len;
-	for (i = 0; i < cmd->chanlist_len; ++i) {
-		chan = CR_CHAN(cmd->chanlist[i]);
-		range = CR_RANGE(cmd->chanlist[i]);
-		if (i >= NUMCHANNELS) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi%d: channel list too long\n",
-				dev->minor);
-			break;
-		}
-		this_usbduxsub->dux_commands[i + 2] =
-		    create_adc_command(chan, range);
+	devpriv->dux_commands[1] = len;
+	for (i = 0; i < len; ++i) {
+		unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+		unsigned int range = CR_RANGE(cmd->chanlist[i]);
+
+		devpriv->dux_commands[i + 2] = create_adc_command(chan, range);
 	}
 
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi %d: sending commands to the usb device: size=%u\n",
-		dev->minor, NUMCHANNELS);
+	ret = send_dux_commands(dev, USBDUX_CMD_MULT_AI);
+	if (ret < 0)
+		goto ai_cmd_exit;
 
-	result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS);
-	if (result < 0) {
-		up(&this_usbduxsub->sem);
-		return result;
-	}
-
-	if (this_usbduxsub->high_speed) {
+	if (devpriv->high_speed) {
 		/*
 		 * every channel gets a time window of 125us. Thus, if we
 		 * sample all 8 channels we need 1ms. If we sample only one
 		 * channel we need only 125us
 		 */
-		this_usbduxsub->ai_interval = 1;
+		devpriv->ai_interval = 1;
 		/* find a power of 2 for the interval */
-		while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) {
-			this_usbduxsub->ai_interval =
-			    (this_usbduxsub->ai_interval) * 2;
-		}
-		this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 *
-							  (this_usbduxsub->
-							   ai_interval));
+		while (devpriv->ai_interval < len)
+			devpriv->ai_interval *= 2;
+
+		devpriv->ai_timer = cmd->scan_begin_arg /
+				    (125000 * devpriv->ai_interval);
 	} else {
 		/* interval always 1ms */
-		this_usbduxsub->ai_interval = 1;
-		this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000;
+		devpriv->ai_interval = 1;
+		devpriv->ai_timer = cmd->scan_begin_arg / 1000000;
 	}
-	if (this_usbduxsub->ai_timer < 1) {
-		dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: "
-			"timer=%d, scan_begin_arg=%d. "
-			"Not properly tested by cmdtest?\n", dev->minor,
-			this_usbduxsub->ai_timer, cmd->scan_begin_arg);
-		up(&this_usbduxsub->sem);
-		return -EINVAL;
+	if (devpriv->ai_timer < 1) {
+		ret = -EINVAL;
+		goto ai_cmd_exit;
 	}
-	this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
+
+	devpriv->ai_counter = devpriv->ai_timer;
 
 	if (cmd->stop_src == TRIG_COUNT) {
 		/* data arrives as one packet */
-		this_usbduxsub->ai_sample_count = cmd->stop_arg;
-		this_usbduxsub->ai_continous = 0;
+		devpriv->ai_sample_count = cmd->stop_arg;
+		devpriv->ai_continous = 0;
 	} else {
 		/* continous acquisition */
-		this_usbduxsub->ai_continous = 1;
-		this_usbduxsub->ai_sample_count = 0;
+		devpriv->ai_continous = 1;
+		devpriv->ai_sample_count = 0;
 	}
 
 	if (cmd->start_src == TRIG_NOW) {
 		/* enable this acquisition operation */
-		this_usbduxsub->ai_cmd_running = 1;
-		ret = usbduxsub_submit_inurbs(this_usbduxsub);
+		devpriv->ai_cmd_running = 1;
+		ret = usbdux_submit_urbs(dev, devpriv->ai_urbs,
+					 devpriv->n_ai_urbs, 1);
 		if (ret < 0) {
-			this_usbduxsub->ai_cmd_running = 0;
+			devpriv->ai_cmd_running = 0;
 			/* fixme: unlink here?? */
-			up(&this_usbduxsub->sem);
-			return ret;
+			goto ai_cmd_exit;
 		}
 		s->async->inttrig = NULL;
 	} else {
@@ -1179,202 +801,156 @@
 		/* wait for an internal signal */
 		s->async->inttrig = usbdux_ai_inttrig;
 	}
-	up(&this_usbduxsub->sem);
-	return 0;
+
+ai_cmd_exit:
+	up(&devpriv->sem);
+
+	return ret;
 }
 
 /* Mode 0 is used to get a single conversion on demand */
 static int usbdux_ai_insn_read(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int range = CR_RANGE(insn->chanspec);
+	unsigned int val;
+	int ret = -EBUSY;
 	int i;
-	unsigned int one = 0;
-	int chan, range;
-	int err;
-	struct usbduxsub *this_usbduxsub = dev->private;
 
-	if (!this_usbduxsub)
-		return 0;
+	down(&devpriv->sem);
 
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n",
-		dev->minor, insn->n, insn->subdev);
+	if (devpriv->ai_cmd_running)
+		goto ai_read_exit;
 
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
-	if (this_usbduxsub->ai_cmd_running) {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: ai_insn_read not possible. "
-			"Async Command is running.\n", dev->minor);
-		up(&this_usbduxsub->sem);
-		return 0;
-	}
-
-	/* sample one channel */
-	chan = CR_CHAN(insn->chanspec);
-	range = CR_RANGE(insn->chanspec);
 	/* set command for the first channel */
-	this_usbduxsub->dux_commands[1] = create_adc_command(chan, range);
+	devpriv->dux_commands[1] = create_adc_command(chan, range);
 
 	/* adc commands */
-	err = send_dux_commands(this_usbduxsub, SENDSINGLEAD);
-	if (err < 0) {
-		up(&this_usbduxsub->sem);
-		return err;
-	}
+	ret = send_dux_commands(dev, USBDUX_CMD_SINGLE_AI);
+	if (ret < 0)
+		goto ai_read_exit;
 
 	for (i = 0; i < insn->n; i++) {
-		err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD);
-		if (err < 0) {
-			up(&this_usbduxsub->sem);
-			return 0;
-		}
-		one = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
-		if (CR_RANGE(insn->chanspec) <= 1)
-			one = one ^ 0x800;
+		ret = receive_dux_commands(dev, USBDUX_CMD_SINGLE_AI);
+		if (ret < 0)
+			goto ai_read_exit;
 
-		data[i] = one;
+		val = le16_to_cpu(devpriv->insn_buf[1]);
+
+		/* bipolar data is two's-complement */
+		if (comedi_range_is_bipolar(s, range))
+			val ^= ((s->maxdata + 1) >> 1);
+
+		data[i] = val;
 	}
-	up(&this_usbduxsub->sem);
-	return i;
-}
 
-/************************************/
-/* analog out */
+ai_read_exit:
+	up(&devpriv->sem);
+
+	return ret ? ret : insn->n;
+}
 
 static int usbdux_ao_insn_read(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
 	int i;
-	int chan = CR_CHAN(insn->chanspec);
-	struct usbduxsub *this_usbduxsub = dev->private;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
-
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
+	down(&devpriv->sem);
 	for (i = 0; i < insn->n; i++)
-		data[i] = this_usbduxsub->out_buffer[chan];
+		data[i] = devpriv->ao_readback[chan];
+	up(&devpriv->sem);
 
-	up(&this_usbduxsub->sem);
-	return i;
+	return insn->n;
 }
 
 static int usbdux_ao_insn_write(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	int i, err;
-	int chan = CR_CHAN(insn->chanspec);
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	unsigned int val = devpriv->ao_readback[chan];
+	int16_t *p = (int16_t *)&devpriv->dux_commands[2];
+	int ret = -EBUSY;
+	int i;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
+	down(&devpriv->sem);
 
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi%d: ao_insn_write\n", dev->minor);
+	if (devpriv->ao_cmd_running)
+		goto ao_write_exit;
 
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
-	if (this_usbduxsub->ao_cmd_running) {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: ao_insn_write: "
-			"ERROR: asynchronous ao_cmd is running\n", dev->minor);
-		up(&this_usbduxsub->sem);
-		return 0;
-	}
+	/* number of channels: 1 */
+	devpriv->dux_commands[1] = 1;
+	/* channel number */
+	devpriv->dux_commands[4] = chan << 6;
 
 	for (i = 0; i < insn->n; i++) {
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n",
-			dev->minor, chan, i, data[i]);
+		val = data[i];
 
-		/* number of channels: 1 */
-		this_usbduxsub->dux_commands[1] = 1;
 		/* one 16 bit value */
-		*((int16_t *) (this_usbduxsub->dux_commands + 2)) =
-		    cpu_to_le16(data[i]);
-		this_usbduxsub->out_buffer[chan] = data[i];
-		/* channel number */
-		this_usbduxsub->dux_commands[4] = (chan << 6);
-		err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS);
-		if (err < 0) {
-			up(&this_usbduxsub->sem);
-			return err;
-		}
-	}
-	up(&this_usbduxsub->sem);
+		*p = cpu_to_le16(val);
 
-	return i;
+		ret = send_dux_commands(dev, USBDUX_CMD_AO);
+		if (ret < 0)
+			goto ao_write_exit;
+	}
+	devpriv->ao_readback[chan] = val;
+
+ao_write_exit:
+	up(&devpriv->sem);
+
+	return ret ? ret : insn->n;
 }
 
 static int usbdux_ao_inttrig(struct comedi_device *dev,
-			     struct comedi_subdevice *s, unsigned int trignum)
+			     struct comedi_subdevice *s,
+			     unsigned int trignum)
 {
-	int ret;
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *devpriv = dev->private;
+	int ret = -EINVAL;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
+	down(&devpriv->sem);
 
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
-	if (trignum != 0) {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: usbdux_ao_inttrig: invalid trignum\n",
-			dev->minor);
-		up(&this_usbduxsub->sem);
-		return -EINVAL;
-	}
-	if (!(this_usbduxsub->ao_cmd_running)) {
-		this_usbduxsub->ao_cmd_running = 1;
-		ret = usbduxsub_submit_outurbs(this_usbduxsub);
+	if (trignum != 0)
+		goto ao_trig_exit;
+
+	if (!devpriv->ao_cmd_running) {
+		devpriv->ao_cmd_running = 1;
+		ret = usbdux_submit_urbs(dev, devpriv->ao_urbs,
+					 devpriv->n_ao_urbs, 0);
 		if (ret < 0) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi%d: usbdux_ao_inttrig: submitURB: "
-				"err=%d\n", dev->minor, ret);
-			this_usbduxsub->ao_cmd_running = 0;
-			up(&this_usbduxsub->sem);
-			return ret;
+			devpriv->ao_cmd_running = 0;
+			goto ao_trig_exit;
 		}
 		s->async->inttrig = NULL;
 	} else {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: ao_inttrig but acqu is already running.\n",
-			dev->minor);
+		ret = -EBUSY;
 	}
-	up(&this_usbduxsub->sem);
-	return 1;
+
+ao_trig_exit:
+	up(&devpriv->sem);
+	return ret;
 }
 
 static int usbdux_ao_cmdtest(struct comedi_device *dev,
 			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *this_usbduxsub = dev->private;
 	int err = 0;
 	unsigned int flags;
 
 	if (!this_usbduxsub)
 		return -EFAULT;
 
-	if (!(this_usbduxsub->probed))
-		return -ENODEV;
-
 	/* Step 1 : check if triggers are trivially valid */
 
 	err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
@@ -1451,99 +1027,72 @@
 
 static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
 {
+	struct usbdux_private *devpriv = dev->private;
 	struct comedi_cmd *cmd = &s->async->cmd;
-	unsigned int chan, gain;
-	int i, ret;
-	struct usbduxsub *this_usbduxsub = dev->private;
+	int ret = -EBUSY;
+	int i;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
+	down(&devpriv->sem);
 
-	down(&this_usbduxsub->sem);
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi%d: %s\n", dev->minor, __func__);
+	if (devpriv->ao_cmd_running)
+		goto ao_cmd_exit;
 
 	/* 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]);
-		gain = CR_RANGE(cmd->chanlist[i]);
-		if (i >= NUMOUTCHANNELS) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi%d: %s: channel list too long\n",
-				dev->minor, __func__);
-			break;
-		}
-		this_usbduxsub->dac_commands[i] = (chan << 6);
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: dac command for ch %d is %x\n",
-			dev->minor, i, this_usbduxsub->dac_commands[i]);
+		unsigned int chan = CR_CHAN(cmd->chanlist[i]);
+
+		devpriv->ao_chanlist[i] = chan << 6;
 	}
 
 	/* we count in steps of 1ms (125us) */
 	/* 125us mode not used yet */
-	if (0) {		/* (this_usbduxsub->high_speed) */
+	if (0) {		/* (devpriv->high_speed) */
 		/* 125us */
 		/* timing of the conversion itself: every 125 us */
-		this_usbduxsub->ao_timer = cmd->convert_arg / 125000;
+		devpriv->ao_timer = cmd->convert_arg / 125000;
 	} else {
 		/* 1ms */
 		/* timing of the scan: we get all channels at once */
-		this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000;
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: scan_begin_src=%d, scan_begin_arg=%d, "
-			"convert_src=%d, convert_arg=%d\n", dev->minor,
-			cmd->scan_begin_src, cmd->scan_begin_arg,
-			cmd->convert_src, cmd->convert_arg);
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: ao_timer=%d (ms)\n",
-			dev->minor, this_usbduxsub->ao_timer);
-		if (this_usbduxsub->ao_timer < 1) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi%d: usbdux: ao_timer=%d, "
-				"scan_begin_arg=%d. "
-				"Not properly tested by cmdtest?\n",
-				dev->minor, this_usbduxsub->ao_timer,
-				cmd->scan_begin_arg);
-			up(&this_usbduxsub->sem);
-			return -EINVAL;
+		devpriv->ao_timer = cmd->scan_begin_arg / 1000000;
+		if (devpriv->ao_timer < 1) {
+			ret = -EINVAL;
+			goto ao_cmd_exit;
 		}
 	}
-	this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
+
+	devpriv->ao_counter = devpriv->ao_timer;
 
 	if (cmd->stop_src == TRIG_COUNT) {
 		/* not continuous */
 		/* counter */
 		/* high speed also scans everything at once */
-		if (0) {	/* (this_usbduxsub->high_speed) */
-			this_usbduxsub->ao_sample_count =
-			    (cmd->stop_arg) * (cmd->scan_end_arg);
+		if (0) {	/* (devpriv->high_speed) */
+			devpriv->ao_sample_count = cmd->stop_arg *
+						   cmd->scan_end_arg;
 		} else {
 			/* there's no scan as the scan has been */
 			/* perf inside the FX2 */
 			/* data arrives as one packet */
-			this_usbduxsub->ao_sample_count = cmd->stop_arg;
+			devpriv->ao_sample_count = cmd->stop_arg;
 		}
-		this_usbduxsub->ao_continous = 0;
+		devpriv->ao_continous = 0;
 	} else {
 		/* continous acquisition */
-		this_usbduxsub->ao_continous = 1;
-		this_usbduxsub->ao_sample_count = 0;
+		devpriv->ao_continous = 1;
+		devpriv->ao_sample_count = 0;
 	}
 
 	if (cmd->start_src == TRIG_NOW) {
 		/* enable this acquisition operation */
-		this_usbduxsub->ao_cmd_running = 1;
-		ret = usbduxsub_submit_outurbs(this_usbduxsub);
+		devpriv->ao_cmd_running = 1;
+		ret = usbdux_submit_urbs(dev, devpriv->ao_urbs,
+					 devpriv->n_ao_urbs, 0);
 		if (ret < 0) {
-			this_usbduxsub->ao_cmd_running = 0;
+			devpriv->ao_cmd_running = 0;
 			/* fixme: unlink here?? */
-			up(&this_usbduxsub->sem);
-			return ret;
+			goto ao_cmd_exit;
 		}
 		s->async->inttrig = NULL;
 	} else {
@@ -1553,149 +1102,123 @@
 		s->async->inttrig = usbdux_ao_inttrig;
 	}
 
-	up(&this_usbduxsub->sem);
-	return 0;
+ao_cmd_exit:
+	up(&devpriv->sem);
+
+	return ret;
 }
 
 static int usbdux_dio_insn_config(struct comedi_device *dev,
 				  struct comedi_subdevice *s,
-				  struct comedi_insn *insn, unsigned int *data)
+				  struct comedi_insn *insn,
+				  unsigned int *data)
 {
-	int chan = CR_CHAN(insn->chanspec);
+	int ret;
 
-	/* 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. */
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= 1 << chan;	/* 1 means Out */
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~(1 << chan);
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] =
-		    (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-	/* we don't tell the firmware here as it would take 8 frames */
-	/* to submit the information. We do it in the insn_bits. */
+	/*
+	 * We don't tell the firmware here as it would take 8 frames
+	 * to submit the information. We do it in the insn_bits.
+	 */
 	return insn->n;
 }
 
 static int usbdux_dio_insn_bits(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
 
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int err;
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int mask = data[0];
+	unsigned int bits = data[1];
+	int ret;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
+	down(&devpriv->sem);
 
-	down(&this_usbduxsub->sem);
+	s->state &= ~mask;
+	s->state |= (bits & mask);
 
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
-	}
+	devpriv->dux_commands[1] = s->io_bits;
+	devpriv->dux_commands[2] = s->state;
 
-	/* The insn data is a mask in data[0] and the new data
-	 * in data[1], each channel cooresponding to a bit. */
-	s->state &= ~data[0];
-	s->state |= data[0] & data[1];
-	this_usbduxsub->dux_commands[1] = s->io_bits;
-	this_usbduxsub->dux_commands[2] = s->state;
+	/*
+	 * This command also tells the firmware to return
+	 * the digital input lines.
+	 */
+	ret = send_dux_commands(dev, USBDUX_CMD_DIO_BITS);
+	if (ret < 0)
+		goto dio_exit;
+	ret = receive_dux_commands(dev, USBDUX_CMD_DIO_BITS);
+	if (ret < 0)
+		goto dio_exit;
 
-	/* This command also tells the firmware to return */
-	/* the digital input lines */
-	err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
-	if (err < 0) {
-		up(&this_usbduxsub->sem);
-		return err;
-	}
-	err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND);
-	if (err < 0) {
-		up(&this_usbduxsub->sem);
-		return err;
-	}
+	data[1] = le16_to_cpu(devpriv->insn_buf[1]);
 
-	data[1] = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
-	up(&this_usbduxsub->sem);
-	return insn->n;
+dio_exit:
+	up(&devpriv->sem);
+
+	return ret ? ret : insn->n;
 }
 
-/* reads the 4 counters, only two are used just now */
 static int usbdux_counter_read(struct comedi_device *dev,
 			       struct comedi_subdevice *s,
-			       struct comedi_insn *insn, unsigned int *data)
+			       struct comedi_insn *insn,
+			       unsigned int *data)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int chan = insn->chanspec;
-	int err;
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int ret = 0;
+	int i;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
+	down(&devpriv->sem);
 
-	down(&this_usbduxsub->sem);
+	for (i = 0; i < insn->n; i++) {
+		ret = send_dux_commands(dev, USBDUX_CMD_TIMER_RD);
+		if (ret < 0)
+			goto counter_read_exit;
+		ret = receive_dux_commands(dev, USBDUX_CMD_TIMER_RD);
+		if (ret < 0)
+			goto counter_read_exit;
 
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
+		data[i] = le16_to_cpu(devpriv->insn_buf[chan + 1]);
 	}
 
-	err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
-	if (err < 0) {
-		up(&this_usbduxsub->sem);
-		return err;
-	}
+counter_read_exit:
+	up(&devpriv->sem);
 
-	err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND);
-	if (err < 0) {
-		up(&this_usbduxsub->sem);
-		return err;
-	}
-
-	data[0] = le16_to_cpu(this_usbduxsub->insn_buffer[chan + 1]);
-	up(&this_usbduxsub->sem);
-	return 1;
+	return ret ? ret : insn->n;
 }
 
 static int usbdux_counter_write(struct comedi_device *dev,
 				struct comedi_subdevice *s,
-				struct comedi_insn *insn, unsigned int *data)
+				struct comedi_insn *insn,
+				unsigned int *data)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int err;
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+	int16_t *p = (int16_t *)&devpriv->dux_commands[2];
+	int ret = 0;
+	int i;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
+	down(&devpriv->sem);
 
-	down(&this_usbduxsub->sem);
+	devpriv->dux_commands[1] = chan;
 
-	if (!(this_usbduxsub->probed)) {
-		up(&this_usbduxsub->sem);
-		return -ENODEV;
+	for (i = 0; i < insn->n; i++) {
+		*p = cpu_to_le16(data[i]);
+
+		ret = send_dux_commands(dev, USBDUX_CMD_TIMER_WR);
+		if (ret < 0)
+			break;
 	}
 
-	this_usbduxsub->dux_commands[1] = insn->chanspec;
-	*((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data);
+	up(&devpriv->sem);
 
-	err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND);
-	if (err < 0) {
-		up(&this_usbduxsub->sem);
-		return err;
-	}
-
-	up(&this_usbduxsub->sem);
-
-	return 1;
+	return ret ? ret : insn->n;
 }
 
 static int usbdux_counter_config(struct comedi_device *dev,
@@ -1706,73 +1229,43 @@
 	return 2;
 }
 
-/***********************************/
-/* PWM */
-
-static int usbduxsub_unlink_pwm_urbs(struct usbduxsub *usbduxsub_tmp)
+static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev)
 {
-	int err = 0;
+	struct usbdux_private *devpriv = dev->private;
 
-	if (usbduxsub_tmp && usbduxsub_tmp->urb_pwm) {
-		if (usbduxsub_tmp->urb_pwm)
-			usb_kill_urb(usbduxsub_tmp->urb_pwm);
-		dev_dbg(&usbduxsub_tmp->interface->dev,
-			"comedi: unlinked PwmURB: res=%d\n", err);
-	}
-	return err;
+	usb_kill_urb(devpriv->pwm_urb);
 }
 
-/* This cancels a running acquisition operation
- * in any context.
- */
-static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
+static void usbdux_pwm_stop(struct comedi_device *dev, int do_unlink)
 {
-	int ret = 0;
+	struct usbdux_private *devpriv = dev->private;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
-
-	dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__);
 	if (do_unlink)
-		ret = usbduxsub_unlink_pwm_urbs(this_usbduxsub);
+		usbduxsub_unlink_pwm_urbs(dev);
 
-	this_usbduxsub->pwm_cmd_running = 0;
+	devpriv->pwm_cmd_running = 0;
+}
+
+static int usbdux_pwm_cancel(struct comedi_device *dev,
+			     struct comedi_subdevice *s)
+{
+	struct usbdux_private *devpriv = dev->private;
+	int ret;
+
+	down(&devpriv->sem);
+	/* unlink only if it is really running */
+	usbdux_pwm_stop(dev, devpriv->pwm_cmd_running);
+	ret = send_dux_commands(dev, USBDUX_CMD_PWM_OFF);
+	up(&devpriv->sem);
 
 	return ret;
 }
 
-/* force unlink - is called by comedi */
-static int usbdux_pwm_cancel(struct comedi_device *dev,
-			     struct comedi_subdevice *s)
-{
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int res = 0;
-
-	/* unlink only if it is really running */
-	res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running);
-
-	dev_dbg(&this_usbduxsub->interface->dev,
-		"comedi %d: sending pwm off command to the usb device.\n",
-		dev->minor);
-
-	return send_dux_commands(this_usbduxsub, SENDPWMOFF);
-}
-
 static void usbduxsub_pwm_irq(struct urb *urb)
 {
+	struct comedi_device *dev = urb->context;
+	struct usbdux_private *devpriv = dev->private;
 	int ret;
-	struct usbduxsub *this_usbduxsub;
-	struct comedi_device *this_comedidev;
-	struct comedi_subdevice *s;
-
-	/* printk(KERN_DEBUG "PWM: IRQ\n"); */
-
-	/* the context variable points to the subdevice */
-	this_comedidev = urb->context;
-	/* the private structure of the subdevice is struct usbduxsub */
-	this_usbduxsub = this_comedidev->private;
-
-	s = &this_comedidev->subdevices[SUBDEV_DA];
 
 	switch (urb->status) {
 	case 0:
@@ -1787,220 +1280,171 @@
 		 * after an unlink command, unplug, ... etc
 		 * no unlink needed here. Already shutting down.
 		 */
-		if (this_usbduxsub->pwm_cmd_running)
-			usbdux_pwm_stop(this_usbduxsub, 0);
+		if (devpriv->pwm_cmd_running)
+			usbdux_pwm_stop(dev, 0);
 
 		return;
 
 	default:
 		/* a real error */
-		if (this_usbduxsub->pwm_cmd_running) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi_: Non-zero urb status received in "
-				"pwm intr context: %d\n", urb->status);
-			usbdux_pwm_stop(this_usbduxsub, 0);
+		if (devpriv->pwm_cmd_running) {
+			dev_err(dev->class_dev,
+				"Non-zero urb status received in pwm intr context: %d\n",
+				urb->status);
+			usbdux_pwm_stop(dev, 0);
 		}
 		return;
 	}
 
 	/* are we actually running? */
-	if (!(this_usbduxsub->pwm_cmd_running))
+	if (!devpriv->pwm_cmd_running)
 		return;
 
-	urb->transfer_buffer_length = this_usbduxsub->size_pwm_buf;
-	urb->dev = this_usbduxsub->usbdev;
+	urb->transfer_buffer_length = devpriv->pwm_buf_sz;
+	urb->dev = comedi_to_usb_dev(dev);
 	urb->status = 0;
-	if (this_usbduxsub->pwm_cmd_running) {
+	if (devpriv->pwm_cmd_running) {
 		ret = usb_submit_urb(urb, GFP_ATOMIC);
 		if (ret < 0) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi_: pwm urb resubm failed in int-cont. "
-				"ret=%d", ret);
+			dev_err(dev->class_dev,
+				"pwm urb resubm failed in int-cont. ret=%d",
+				ret);
 			if (ret == EL2NSYNC)
-				dev_err(&this_usbduxsub->interface->dev,
-					"buggy USB host controller or bug in "
-					"IRQ handling!\n");
+				dev_err(dev->class_dev,
+					"buggy USB host controller or bug in IRQ handling!\n");
 
 			/* don't do an unlink here */
-			usbdux_pwm_stop(this_usbduxsub, 0);
+			usbdux_pwm_stop(dev, 0);
 		}
 	}
 }
 
-static int usbduxsub_submit_pwm_urbs(struct usbduxsub *usbduxsub)
+static int usbduxsub_submit_pwm_urbs(struct comedi_device *dev)
 {
-	int err_flag;
-
-	if (!usbduxsub)
-		return -EFAULT;
-
-	dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n");
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	struct usbdux_private *devpriv = dev->private;
+	struct urb *urb = devpriv->pwm_urb;
 
 	/* in case of a resubmission after an unlink... */
-	usb_fill_bulk_urb(usbduxsub->urb_pwm,
-			  usbduxsub->usbdev,
-			  usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
-			  usbduxsub->urb_pwm->transfer_buffer,
-			  usbduxsub->size_pwm_buf, usbduxsub_pwm_irq,
-			  usbduxsub->comedidev);
+	usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4),
+			  urb->transfer_buffer,
+			  devpriv->pwm_buf_sz,
+			  usbduxsub_pwm_irq,
+			  dev);
 
-	err_flag = usb_submit_urb(usbduxsub->urb_pwm, GFP_ATOMIC);
-	if (err_flag) {
-		dev_err(&usbduxsub->interface->dev,
-			"comedi_: usbdux: pwm: usb_submit_urb error %d\n",
-			err_flag);
-		return err_flag;
-	}
-	return 0;
+	return usb_submit_urb(urb, GFP_ATOMIC);
 }
 
 static int usbdux_pwm_period(struct comedi_device *dev,
-			     struct comedi_subdevice *s, unsigned int period)
+			     struct comedi_subdevice *s,
+			     unsigned int period)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *devpriv = dev->private;
 	int fx2delay = 255;
 
 	if (period < MIN_PWM_PERIOD) {
-		dev_err(&this_usbduxsub->interface->dev,
-			"comedi%d: illegal period setting for pwm.\n",
-			dev->minor);
 		return -EAGAIN;
 	} else {
-		fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6;
-		if (fx2delay > 255) {
-			dev_err(&this_usbduxsub->interface->dev,
-				"comedi%d: period %d for pwm is too low.\n",
-				dev->minor, period);
+		fx2delay = (period / (6 * 512 * 1000 / 33)) - 6;
+		if (fx2delay > 255)
 			return -EAGAIN;
-		}
 	}
-	this_usbduxsub->pwn_delay = fx2delay;
-	this_usbduxsub->pwm_period = period;
-	dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n",
-		__func__, period, fx2delay);
+	devpriv->pwm_delay = fx2delay;
+	devpriv->pwm_period = period;
+
 	return 0;
 }
 
-/* is called from insn so there's no need to do all the sanity checks */
 static int usbdux_pwm_start(struct comedi_device *dev,
 			    struct comedi_subdevice *s)
 {
-	int ret, i;
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *devpriv = dev->private;
+	int ret = 0;
 
-	dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n",
-		dev->minor, __func__);
+	down(&devpriv->sem);
 
-	if (this_usbduxsub->pwm_cmd_running) {
-		/* already running */
-		return 0;
-	}
+	if (devpriv->pwm_cmd_running)
+		goto pwm_start_exit;
 
-	this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwn_delay);
-	ret = send_dux_commands(this_usbduxsub, SENDPWMON);
+	devpriv->dux_commands[1] = devpriv->pwm_delay;
+	ret = send_dux_commands(dev, USBDUX_CMD_PWM_ON);
 	if (ret < 0)
-		return ret;
+		goto pwm_start_exit;
 
 	/* initialise the buffer */
-	for (i = 0; i < this_usbduxsub->size_pwm_buf; i++)
-		((char *)(this_usbduxsub->urb_pwm->transfer_buffer))[i] = 0;
+	memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz);
 
-	this_usbduxsub->pwm_cmd_running = 1;
-	ret = usbduxsub_submit_pwm_urbs(this_usbduxsub);
-	if (ret < 0) {
-		this_usbduxsub->pwm_cmd_running = 0;
-		return ret;
-	}
-	return 0;
+	devpriv->pwm_cmd_running = 1;
+	ret = usbduxsub_submit_pwm_urbs(dev);
+	if (ret < 0)
+		devpriv->pwm_cmd_running = 0;
+
+pwm_start_exit:
+	up(&devpriv->sem);
+
+	return ret;
 }
 
-/* generates the bit pattern for PWM with the optional sign bit */
-static int usbdux_pwm_pattern(struct comedi_device *dev,
-			      struct comedi_subdevice *s, int channel,
-			      unsigned int value, unsigned int sign)
+static void usbdux_pwm_pattern(struct comedi_device *dev,
+			       struct comedi_subdevice *s,
+			       unsigned int chan,
+			       unsigned int value,
+			       unsigned int sign)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
-	int i, szbuf;
-	char *p_buf;
-	char pwm_mask;
-	char sgn_mask;
-	char c;
+	struct usbdux_private *devpriv = dev->private;
+	char pwm_mask = (1 << chan);	/* DIO bit for the PWM data */
+	char sgn_mask = (16 << chan);	/* DIO bit for the sign */
+	char *buf = (char *)(devpriv->pwm_urb->transfer_buffer);
+	int szbuf = devpriv->pwm_buf_sz;
+	int i;
 
-	if (!this_usbduxsub)
-		return -EFAULT;
-
-	/* this is the DIO bit which carries the PWM data */
-	pwm_mask = (1 << channel);
-	/* this is the DIO bit which carries the optional direction bit */
-	sgn_mask = (16 << channel);
-	/* this is the buffer which will be filled with the with bit */
-	/* pattern for one period */
-	szbuf = this_usbduxsub->size_pwm_buf;
-	p_buf = (char *)(this_usbduxsub->urb_pwm->transfer_buffer);
 	for (i = 0; i < szbuf; i++) {
-		c = *p_buf;
-		/* reset bits */
-		c = c & (~pwm_mask);
-		/* set the bit as long as the index is lower than the value */
+		char c = *buf;
+
+		c &= ~pwm_mask;
 		if (i < value)
-			c = c | pwm_mask;
-		/* set the optional sign bit for a relay */
-		if (!sign) {
-			/* positive value */
-			c = c & (~sgn_mask);
-		} else {
-			/* negative value */
-			c = c | sgn_mask;
-		}
-		*(p_buf++) = c;
+			c |= pwm_mask;
+		if (!sign)
+			c &= ~sgn_mask;
+		else
+			c |= sgn_mask;
+		*buf++ = c;
 	}
-	return 1;
 }
 
 static int usbdux_pwm_write(struct comedi_device *dev,
 			    struct comedi_subdevice *s,
-			    struct comedi_insn *insn, unsigned int *data)
+			    struct comedi_insn *insn,
+			    unsigned int *data)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
-
-	if (!this_usbduxsub)
-		return -EFAULT;
-
-	if ((insn->n) != 1) {
-		/*
-		 * doesn't make sense to have more than one value here because
-		 * it would just overwrite the PWM buffer a couple of times
-		 */
-		return -EINVAL;
-	}
+	unsigned int chan = CR_CHAN(insn->chanspec);
 
 	/*
-	 * the sign is set via a special INSN only, this gives us 8 bits for
-	 * normal operation
-	 * relay sign 0 by default
+	 * It doesn't make sense to support more than one value here
+	 * because it would just overwrite the PWM buffer.
 	 */
-	return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0);
+	if (insn->n != 1)
+		return -EINVAL;
+
+	/*
+	 * The sign is set via a special INSN only, this gives us 8 bits
+	 * for normal operation, sign is 0 by default.
+	 */
+	usbdux_pwm_pattern(dev, s, chan, data[0], 0);
+
+	return insn->n;
 }
 
-static int usbdux_pwm_read(struct comedi_device *x1,
-			   struct comedi_subdevice *x2, struct comedi_insn *x3,
-			   unsigned int *x4)
-{
-	/* not needed */
-	return -EINVAL;
-};
-
-/* switches on/off PWM */
 static int usbdux_pwm_config(struct comedi_device *dev,
 			     struct comedi_subdevice *s,
-			     struct comedi_insn *insn, unsigned int *data)
+			     struct comedi_insn *insn,
+			     unsigned int *data)
 {
-	struct usbduxsub *this_usbduxsub = dev->private;
+	struct usbdux_private *devpriv = dev->private;
+	unsigned int chan = CR_CHAN(insn->chanspec);
+
 	switch (data[0]) {
 	case INSN_CONFIG_ARM:
-		/* switch it on */
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: %s: pwm on\n", dev->minor, __func__);
 		/*
 		 * if not zero the PWM is limited to a certain time which is
 		 * not supported here
@@ -2009,33 +1453,22 @@
 			return -EINVAL;
 		return usbdux_pwm_start(dev, s);
 	case INSN_CONFIG_DISARM:
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: %s: pwm off\n", dev->minor, __func__);
 		return usbdux_pwm_cancel(dev, s);
 	case INSN_CONFIG_GET_PWM_STATUS:
-		/*
-		 * to check if the USB transmission has failed or in case PWM
-		 * was limited to n cycles to check if it has terminated
-		 */
-		data[1] = this_usbduxsub->pwm_cmd_running;
+		data[1] = devpriv->pwm_cmd_running;
 		return 0;
 	case INSN_CONFIG_PWM_SET_PERIOD:
-		dev_dbg(&this_usbduxsub->interface->dev,
-			"comedi%d: %s: setting period\n", dev->minor, __func__);
 		return usbdux_pwm_period(dev, s, data[1]);
 	case INSN_CONFIG_PWM_GET_PERIOD:
-		data[1] = this_usbduxsub->pwm_period;
+		data[1] = devpriv->pwm_period;
 		return 0;
 	case INSN_CONFIG_PWM_SET_H_BRIDGE:
-		/* value in the first byte and the sign in the second for a
-		   relay */
-		return usbdux_pwm_pattern(dev, s,
-					  /* the channel number */
-					  CR_CHAN(insn->chanspec),
-					  /* actual PWM data */
-					  data[1],
-					  /* just a sign */
-					  (data[2] != 0));
+		/*
+		 * data[1] = value
+		 * data[2] = sign (for a relay)
+		 */
+		usbdux_pwm_pattern(dev, s, chan, data[1], (data[2] != 0));
+		return 0;
 	case INSN_CONFIG_PWM_GET_H_BRIDGE:
 		/* values are not kept in this driver, nothing to return here */
 		return -EINVAL;
@@ -2043,253 +1476,331 @@
 	return -EINVAL;
 }
 
-/* end of PWM */
-/*****************************************************************/
-
-static void tidy_up(struct usbduxsub *usbduxsub_tmp)
+static int usbdux_firmware_upload(struct comedi_device *dev,
+				  const u8 *data, size_t size,
+				  unsigned long context)
 {
-	int i;
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	uint8_t *buf;
+	uint8_t *tmp;
+	int ret;
 
-	if (!usbduxsub_tmp)
-		return;
-	dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n");
+	if (!data)
+		return 0;
 
-	/* shows the usb subsystem that the driver is down */
-	if (usbduxsub_tmp->interface)
-		usb_set_intfdata(usbduxsub_tmp->interface, NULL);
-
-	usbduxsub_tmp->probed = 0;
-
-	if (usbduxsub_tmp->urb_in) {
-		if (usbduxsub_tmp->ai_cmd_running) {
-			usbduxsub_tmp->ai_cmd_running = 0;
-			usbduxsub_unlink_inurbs(usbduxsub_tmp);
-		}
-		for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
-			kfree(usbduxsub_tmp->urb_in[i]->transfer_buffer);
-			usbduxsub_tmp->urb_in[i]->transfer_buffer = NULL;
-			usb_kill_urb(usbduxsub_tmp->urb_in[i]);
-			usb_free_urb(usbduxsub_tmp->urb_in[i]);
-			usbduxsub_tmp->urb_in[i] = NULL;
-		}
-		kfree(usbduxsub_tmp->urb_in);
-		usbduxsub_tmp->urb_in = NULL;
+	if (size > USBDUX_FIRMWARE_MAX_LEN) {
+		dev_err(dev->class_dev,
+			"usbdux firmware binary it too large for FX2.\n");
+		return -ENOMEM;
 	}
-	if (usbduxsub_tmp->urb_out) {
-		if (usbduxsub_tmp->ao_cmd_running) {
-			usbduxsub_tmp->ao_cmd_running = 0;
-			usbduxsub_unlink_outurbs(usbduxsub_tmp);
-		}
-		for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
-			kfree(usbduxsub_tmp->urb_out[i]->transfer_buffer);
-			usbduxsub_tmp->urb_out[i]->transfer_buffer = NULL;
-			if (usbduxsub_tmp->urb_out[i]) {
-				usb_kill_urb(usbduxsub_tmp->urb_out[i]);
-				usb_free_urb(usbduxsub_tmp->urb_out[i]);
-				usbduxsub_tmp->urb_out[i] = NULL;
-			}
-		}
-		kfree(usbduxsub_tmp->urb_out);
-		usbduxsub_tmp->urb_out = NULL;
+
+	/* we generate a local buffer for the firmware */
+	buf = kmemdup(data, size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* we need a malloc'ed buffer for usb_control_msg() */
+	tmp = kmalloc(1, GFP_KERNEL);
+	if (!tmp) {
+		kfree(buf);
+		return -ENOMEM;
 	}
-	if (usbduxsub_tmp->urb_pwm) {
-		if (usbduxsub_tmp->pwm_cmd_running) {
-			usbduxsub_tmp->pwm_cmd_running = 0;
-			usbduxsub_unlink_pwm_urbs(usbduxsub_tmp);
-		}
-		kfree(usbduxsub_tmp->urb_pwm->transfer_buffer);
-		usbduxsub_tmp->urb_pwm->transfer_buffer = NULL;
-		usb_kill_urb(usbduxsub_tmp->urb_pwm);
-		usb_free_urb(usbduxsub_tmp->urb_pwm);
-		usbduxsub_tmp->urb_pwm = NULL;
+
+	/* stop the current firmware on the device */
+	*tmp = 1;	/* 7f92 to one */
+	ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
+			      USBDUX_FIRMWARE_CMD,
+			      VENDOR_DIR_OUT,
+			      USBDUX_CPU_CS, 0x0000,
+			      tmp, 1,
+			      BULK_TIMEOUT);
+	if (ret < 0) {
+		dev_err(dev->class_dev, "can not stop firmware\n");
+		goto done;
 	}
-	kfree(usbduxsub_tmp->in_buffer);
-	usbduxsub_tmp->in_buffer = NULL;
-	kfree(usbduxsub_tmp->insn_buffer);
-	usbduxsub_tmp->insn_buffer = NULL;
-	kfree(usbduxsub_tmp->out_buffer);
-	usbduxsub_tmp->out_buffer = NULL;
-	kfree(usbduxsub_tmp->dac_commands);
-	usbduxsub_tmp->dac_commands = NULL;
-	kfree(usbduxsub_tmp->dux_commands);
-	usbduxsub_tmp->dux_commands = NULL;
-	usbduxsub_tmp->ai_cmd_running = 0;
-	usbduxsub_tmp->ao_cmd_running = 0;
-	usbduxsub_tmp->pwm_cmd_running = 0;
+
+	/* upload the new firmware to the device */
+	ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
+			      USBDUX_FIRMWARE_CMD,
+			      VENDOR_DIR_OUT,
+			      0, 0x0000,
+			      buf, size,
+			      BULK_TIMEOUT);
+	if (ret < 0) {
+		dev_err(dev->class_dev, "firmware upload failed\n");
+		goto done;
+	}
+
+	/* start the new firmware on the device */
+	*tmp = 0;	/* 7f92 to zero */
+	ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0),
+			      USBDUX_FIRMWARE_CMD,
+			      VENDOR_DIR_OUT,
+			      USBDUX_CPU_CS, 0x0000,
+			      tmp, 1,
+			      BULK_TIMEOUT);
+	if (ret < 0)
+		dev_err(dev->class_dev, "can not start firmware\n");
+
+done:
+	kfree(tmp);
+	kfree(buf);
+	return ret;
 }
 
-static int usbdux_attach_common(struct comedi_device *dev,
-				struct usbduxsub *udev)
+static int usbdux_alloc_usb_buffers(struct comedi_device *dev)
 {
-	int ret;
-	struct comedi_subdevice *s = NULL;
-	int n_subdevs;
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	struct usbdux_private *devpriv = dev->private;
+	struct urb *urb;
+	int i;
 
-	down(&udev->sem);
-	/* pointer back to the corresponding comedi device */
-	udev->comedidev = dev;
+	devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
+	devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL);
+	devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL);
+	devpriv->ai_urbs = kcalloc(devpriv->n_ai_urbs, sizeof(void *),
+				   GFP_KERNEL);
+	devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(void *),
+				   GFP_KERNEL);
+	if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf ||
+	    !devpriv->ai_urbs || !devpriv->ao_urbs)
+		return -ENOMEM;
 
-	/* set number of subdevices */
-	if (udev->high_speed) {
-		/* with pwm */
-		n_subdevs = 5;
-	} else {
-		/* without pwm */
-		n_subdevs = 4;
+	for (i = 0; i < devpriv->n_ai_urbs; i++) {
+		/* one frame: 1ms */
+		urb = usb_alloc_urb(1, GFP_KERNEL);
+		if (!urb)
+			return -ENOMEM;
+		devpriv->ai_urbs[i] = urb;
+
+		urb->dev = usb;
+		urb->context = dev;
+		urb->pipe = usb_rcvisocpipe(usb, 6);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
+		if (!urb->transfer_buffer)
+			return -ENOMEM;
+
+		urb->complete = usbduxsub_ai_isoc_irq;
+		urb->number_of_packets = 1;
+		urb->transfer_buffer_length = SIZEINBUF;
+		urb->iso_frame_desc[0].offset = 0;
+		urb->iso_frame_desc[0].length = SIZEINBUF;
 	}
 
-	ret = comedi_alloc_subdevices(dev, n_subdevs);
-	if (ret) {
-		up(&udev->sem);
-		return ret;
+	for (i = 0; i < devpriv->n_ao_urbs; i++) {
+		/* one frame: 1ms */
+		urb = usb_alloc_urb(1, GFP_KERNEL);
+		if (!urb)
+			return -ENOMEM;
+		devpriv->ao_urbs[i] = urb;
+
+		urb->dev = usb;
+		urb->context = dev;
+		urb->pipe = usb_sndisocpipe(usb, 2);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
+		if (!urb->transfer_buffer)
+			return -ENOMEM;
+
+		urb->complete = usbduxsub_ao_isoc_irq;
+		urb->number_of_packets = 1;
+		urb->transfer_buffer_length = SIZEOUTBUF;
+		urb->iso_frame_desc[0].offset = 0;
+		urb->iso_frame_desc[0].length = SIZEOUTBUF;
+		if (devpriv->high_speed)
+			urb->interval = 8;	/* uframes */
+		else
+			urb->interval = 1;	/* frames */
 	}
 
-	/* private structure is also simply the usb-structure */
-	dev->private = udev;
+	/* pwm */
+	if (devpriv->pwm_buf_sz) {
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (!urb)
+			return -ENOMEM;
+		devpriv->pwm_urb = urb;
 
-	/* the first subdevice is the A/D converter */
-	s = &dev->subdevices[SUBDEV_AD];
-	/* the URBs get the comedi subdevice */
-	/* which is responsible for reading */
-	/* this is the subdevice which reads data */
-	dev->read_subdev = s;
-	/* the subdevice receives as private structure the */
-	/* usb-structure */
-	s->private = NULL;
-	/* analog input */
-	s->type = COMEDI_SUBD_AI;
-	/* readable and ref is to ground */
-	s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
-	/* 8 channels */
-	s->n_chan = 8;
-	/* length of the channellist */
-	s->len_chanlist = 8;
-	/* callback functions */
-	s->insn_read = usbdux_ai_insn_read;
-	s->do_cmdtest = usbdux_ai_cmdtest;
-	s->do_cmd = usbdux_ai_cmd;
-	s->cancel = usbdux_ai_cancel;
-	/* max value from the A/D converter (12bit) */
-	s->maxdata = 0xfff;
-	/* range table to convert to physical units */
-	s->range_table = (&range_usbdux_ai_range);
-
-	/* analog out */
-	s = &dev->subdevices[SUBDEV_DA];
-	/* analog out */
-	s->type = COMEDI_SUBD_AO;
-	/* backward pointer */
-	dev->write_subdev = s;
-	/* the subdevice receives as private structure the */
-	/* usb-structure */
-	s->private = NULL;
-	/* are writable */
-	s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
-	/* 4 channels */
-	s->n_chan = 4;
-	/* length of the channellist */
-	s->len_chanlist = 4;
-	/* 12 bit resolution */
-	s->maxdata = 0x0fff;
-	/* bipolar range */
-	s->range_table = (&range_usbdux_ao_range);
-	/* callback */
-	s->do_cmdtest = usbdux_ao_cmdtest;
-	s->do_cmd = usbdux_ao_cmd;
-	s->cancel = usbdux_ao_cancel;
-	s->insn_read = usbdux_ao_insn_read;
-	s->insn_write = usbdux_ao_insn_write;
-
-	/* digital I/O */
-	s = &dev->subdevices[SUBDEV_DIO];
-	s->type = COMEDI_SUBD_DIO;
-	s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-	s->n_chan = 8;
-	s->maxdata = 1;
-	s->range_table = (&range_digital);
-	s->insn_bits = usbdux_dio_insn_bits;
-	s->insn_config = usbdux_dio_insn_config;
-	/* we don't use it */
-	s->private = NULL;
-
-	/* counter */
-	s = &dev->subdevices[SUBDEV_COUNTER];
-	s->type = COMEDI_SUBD_COUNTER;
-	s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
-	s->n_chan = 4;
-	s->maxdata = 0xFFFF;
-	s->insn_read = usbdux_counter_read;
-	s->insn_write = usbdux_counter_write;
-	s->insn_config = usbdux_counter_config;
-
-	if (udev->high_speed) {
-		/* timer / pwm */
-		s = &dev->subdevices[SUBDEV_PWM];
-		s->type = COMEDI_SUBD_PWM;
-		s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
-		s->n_chan = 8;
-		/* this defines the max duty cycle resolution */
-		s->maxdata = udev->size_pwm_buf;
-		s->insn_write = usbdux_pwm_write;
-		s->insn_read = usbdux_pwm_read;
-		s->insn_config = usbdux_pwm_config;
-		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+		/* max bulk ep size in high speed */
+		urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz,
+					       GFP_KERNEL);
+		if (!urb->transfer_buffer)
+			return -ENOMEM;
 	}
-	/* finally decide that it's attached */
-	udev->attached = 1;
-
-	up(&udev->sem);
-
-	dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
-		 dev->minor);
 
 	return 0;
 }
 
+static void usbdux_free_usb_buffers(struct comedi_device *dev)
+{
+	struct usbdux_private *devpriv = dev->private;
+	struct urb *urb;
+	int i;
+
+	urb = devpriv->pwm_urb;
+	if (urb) {
+		kfree(urb->transfer_buffer);
+		usb_free_urb(urb);
+	}
+	if (devpriv->ao_urbs) {
+		for (i = 0; i < devpriv->n_ao_urbs; i++) {
+			urb = devpriv->ao_urbs[i];
+			if (urb) {
+				kfree(urb->transfer_buffer);
+				usb_free_urb(urb);
+			}
+		}
+		kfree(devpriv->ao_urbs);
+	}
+	if (devpriv->ai_urbs) {
+		for (i = 0; i < devpriv->n_ai_urbs; i++) {
+			urb = devpriv->ai_urbs[i];
+			if (urb) {
+				kfree(urb->transfer_buffer);
+				usb_free_urb(urb);
+			}
+		}
+		kfree(devpriv->ai_urbs);
+	}
+	kfree(devpriv->insn_buf);
+	kfree(devpriv->in_buf);
+	kfree(devpriv->dux_commands);
+}
+
 static int usbdux_auto_attach(struct comedi_device *dev,
 			      unsigned long context_unused)
 {
-	struct usb_interface *uinterf = comedi_to_usb_interface(dev);
-	struct usbduxsub *this_usbduxsub = usb_get_intfdata(uinterf);
-	struct usb_device *usb = usbduxsub->usbdev;
+	struct usb_interface *intf = comedi_to_usb_interface(dev);
+	struct usb_device *usb = comedi_to_usb_dev(dev);
+	struct usbdux_private *devpriv;
+	struct comedi_subdevice *s;
 	int ret;
 
-	dev->private = this_usbduxsub;	/* This is temporary... */
-	ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
-				   usbdux_firmware_upload, 0);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+	if (!devpriv)
+		return -ENOMEM;
+
+	sema_init(&devpriv->sem, 1);
+
+	usb_set_intfdata(intf, devpriv);
+
+	devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
+	if (devpriv->high_speed) {
+		devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH;
+		devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH;
+		devpriv->pwm_buf_sz = 512;
+	} else {
+		devpriv->n_ai_urbs = NUMOFINBUFFERSFULL;
+		devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL;
+	}
+
+	ret = usbdux_alloc_usb_buffers(dev);
+	if (ret)
+		return ret;
+
+	/* setting to alternate setting 3: enabling iso ep and bulk ep. */
+	ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber,
+				3);
 	if (ret < 0) {
-		dev->private = NULL;
+		dev_err(dev->class_dev,
+			"could not set alternate setting 3 in high speed\n");
 		return ret;
 	}
 
-	dev->private = NULL;
+	ret = comedi_load_firmware(dev, &usb->dev, USBDUX_FIRMWARE,
+				   usbdux_firmware_upload, 0);
+	if (ret < 0)
+		return ret;
 
-	down(&start_stop_sem);
-	if (!this_usbduxsub || !this_usbduxsub->probed) {
-		dev_err(dev->class_dev,
-			"usbdux: error: auto_attach failed, not connected\n");
-		ret = -ENODEV;
-	} else if (this_usbduxsub->attached) {
-		dev_err(dev->class_dev,
-			"error: auto_attach failed, already attached\n");
-		ret = -ENODEV;
-	} else
-		ret = usbdux_attach_common(dev, this_usbduxsub);
-	up(&start_stop_sem);
-	return ret;
+	ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 5 : 4);
+	if (ret)
+		return ret;
+
+	/* Analog Input subdevice */
+	s = &dev->subdevices[0];
+	dev->read_subdev = s;
+	s->type		= COMEDI_SUBD_AI;
+	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+	s->n_chan	= 8;
+	s->maxdata	= 0x0fff;
+	s->len_chanlist	= 8;
+	s->range_table	= &range_usbdux_ai_range;
+	s->insn_read	= usbdux_ai_insn_read;
+	s->do_cmdtest	= usbdux_ai_cmdtest;
+	s->do_cmd	= usbdux_ai_cmd;
+	s->cancel	= usbdux_ai_cancel;
+
+	/* Analog Output subdevice */
+	s = &dev->subdevices[1];
+	dev->write_subdev = s;
+	s->type		= COMEDI_SUBD_AO;
+	s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
+	s->n_chan	= USBDUX_NUM_AO_CHAN;
+	s->maxdata	= 0x0fff;
+	s->len_chanlist	= s->n_chan;
+	s->range_table	= &range_usbdux_ao_range;
+	s->do_cmdtest	= usbdux_ao_cmdtest;
+	s->do_cmd	= usbdux_ao_cmd;
+	s->cancel	= usbdux_ao_cancel;
+	s->insn_read	= usbdux_ao_insn_read;
+	s->insn_write	= usbdux_ao_insn_write;
+
+	/* Digital I/O subdevice */
+	s = &dev->subdevices[2];
+	s->type		= COMEDI_SUBD_DIO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 8;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= usbdux_dio_insn_bits;
+	s->insn_config	= usbdux_dio_insn_config;
+
+	/* Counter subdevice */
+	s = &dev->subdevices[3];
+	s->type		= COMEDI_SUBD_COUNTER;
+	s->subdev_flags	= SDF_WRITABLE | SDF_READABLE;
+	s->n_chan	= 4;
+	s->maxdata	= 0xffff;
+	s->insn_read	= usbdux_counter_read;
+	s->insn_write	= usbdux_counter_write;
+	s->insn_config	= usbdux_counter_config;
+
+	if (devpriv->high_speed) {
+		/* PWM subdevice */
+		s = &dev->subdevices[4];
+		s->type		= COMEDI_SUBD_PWM;
+		s->subdev_flags	= SDF_WRITABLE | SDF_PWM_HBRIDGE;
+		s->n_chan	= 8;
+		s->maxdata	= devpriv->pwm_buf_sz;
+		s->insn_write	= usbdux_pwm_write;
+		s->insn_config	= usbdux_pwm_config;
+
+		usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+	}
+
+	return 0;
 }
 
 static void usbdux_detach(struct comedi_device *dev)
 {
-	struct usbduxsub *usb = dev->private;
+	struct usb_interface *intf = comedi_to_usb_interface(dev);
+	struct usbdux_private *devpriv = dev->private;
 
-	if (usb) {
-		down(&usb->sem);
-		dev->private = NULL;
-		usb->attached = 0;
-		usb->comedidev = NULL;
-		up(&usb->sem);
-	}
+	usb_set_intfdata(intf, NULL);
+
+	if (!devpriv)
+		return;
+
+	down(&devpriv->sem);
+
+	/* force unlink all urbs */
+	usbdux_pwm_stop(dev, 1);
+	usbdux_ao_stop(dev, 1);
+	usbdux_ai_stop(dev, 1);
+
+	usbdux_free_usb_buffers(dev);
+
+	up(&devpriv->sem);
 }
 
 static struct comedi_driver usbdux_driver = {
@@ -2299,253 +1810,10 @@
 	.detach		= usbdux_detach,
 };
 
-static int usbdux_usb_probe(struct usb_interface *uinterf,
+static int usbdux_usb_probe(struct usb_interface *intf,
 			    const struct usb_device_id *id)
 {
-	struct usb_device *udev = interface_to_usbdev(uinterf);
-	struct device *dev = &uinterf->dev;
-	int i;
-	int index;
-
-	dev_dbg(dev, "comedi_: usbdux_: "
-		"finding a free structure for the usb-device\n");
-
-	down(&start_stop_sem);
-	/* look for a free place in the usbdux array */
-	index = -1;
-	for (i = 0; i < NUMUSBDUX; i++) {
-		if (!(usbduxsub[i].probed)) {
-			index = i;
-			break;
-		}
-	}
-
-	/* no more space */
-	if (index == -1) {
-		dev_err(dev, "Too many usbdux-devices connected.\n");
-		up(&start_stop_sem);
-		return -EMFILE;
-	}
-	dev_dbg(dev, "comedi_: usbdux: "
-		"usbduxsub[%d] is ready to connect to comedi.\n", index);
-
-	sema_init(&(usbduxsub[index].sem), 1);
-	/* save a pointer to the usb device */
-	usbduxsub[index].usbdev = udev;
-
-	/* 2.6: save the interface itself */
-	usbduxsub[index].interface = uinterf;
-	/* get the interface number from the interface */
-	usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber;
-	/* hand the private data over to the usb subsystem */
-	/* will be needed for disconnect */
-	usb_set_intfdata(uinterf, &(usbduxsub[index]));
-
-	dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum);
-
-	/* test if it is high speed (USB 2.0) */
-	usbduxsub[index].high_speed =
-	    (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH);
-
-	/* create space for the commands of the DA converter */
-	usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
-	if (!usbduxsub[index].dac_commands) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	/* create space for the commands going to the usb device */
-	usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
-	if (!usbduxsub[index].dux_commands) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	/* create space for the in buffer and set it to zero */
-	usbduxsub[index].in_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
-	if (!(usbduxsub[index].in_buffer)) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	/* create space of the instruction buffer */
-	usbduxsub[index].insn_buffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
-	if (!(usbduxsub[index].insn_buffer)) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	/* create space for the outbuffer */
-	usbduxsub[index].out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
-	if (!(usbduxsub[index].out_buffer)) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	/* setting to alternate setting 3: enabling iso ep and bulk ep. */
-	i = usb_set_interface(usbduxsub[index].usbdev,
-			      usbduxsub[index].ifnum, 3);
-	if (i < 0) {
-		dev_err(dev, "comedi_: usbdux%d: "
-			"could not set alternate setting 3 in high speed.\n",
-			index);
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENODEV;
-	}
-	if (usbduxsub[index].high_speed)
-		usbduxsub[index].num_in_buffers = NUMOFINBUFFERSHIGH;
-	else
-		usbduxsub[index].num_in_buffers = NUMOFINBUFFERSFULL;
-
-	usbduxsub[index].urb_in =
-		kcalloc(usbduxsub[index].num_in_buffers, sizeof(struct urb *),
-			GFP_KERNEL);
-	if (!(usbduxsub[index].urb_in)) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	for (i = 0; i < usbduxsub[index].num_in_buffers; i++) {
-		/* one frame: 1ms */
-		usbduxsub[index].urb_in[i] = usb_alloc_urb(1, GFP_KERNEL);
-		if (usbduxsub[index].urb_in[i] == NULL) {
-			dev_err(dev, "comedi_: usbdux%d: "
-				"Could not alloc. urb(%d)\n", index, i);
-			tidy_up(&(usbduxsub[index]));
-			up(&start_stop_sem);
-			return -ENOMEM;
-		}
-		usbduxsub[index].urb_in[i]->dev = usbduxsub[index].usbdev;
-		/* will be filled later with a pointer to the comedi-device */
-		/* and ONLY then the urb should be submitted */
-		usbduxsub[index].urb_in[i]->context = NULL;
-		usbduxsub[index].urb_in[i]->pipe =
-		    usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
-		usbduxsub[index].urb_in[i]->transfer_flags = URB_ISO_ASAP;
-		usbduxsub[index].urb_in[i]->transfer_buffer =
-		    kzalloc(SIZEINBUF, GFP_KERNEL);
-		if (!(usbduxsub[index].urb_in[i]->transfer_buffer)) {
-			tidy_up(&(usbduxsub[index]));
-			up(&start_stop_sem);
-			return -ENOMEM;
-		}
-		usbduxsub[index].urb_in[i]->complete = usbduxsub_ai_isoc_irq;
-		usbduxsub[index].urb_in[i]->number_of_packets = 1;
-		usbduxsub[index].urb_in[i]->transfer_buffer_length = SIZEINBUF;
-		usbduxsub[index].urb_in[i]->iso_frame_desc[0].offset = 0;
-		usbduxsub[index].urb_in[i]->iso_frame_desc[0].length = SIZEINBUF;
-	}
-
-	/* out */
-	if (usbduxsub[index].high_speed)
-		usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSHIGH;
-	else
-		usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSFULL;
-
-	usbduxsub[index].urb_out =
-		kcalloc(usbduxsub[index].num_out_buffers, sizeof(struct urb *),
-			GFP_KERNEL);
-	if (!(usbduxsub[index].urb_out)) {
-		tidy_up(&(usbduxsub[index]));
-		up(&start_stop_sem);
-		return -ENOMEM;
-	}
-	for (i = 0; i < usbduxsub[index].num_out_buffers; i++) {
-		/* one frame: 1ms */
-		usbduxsub[index].urb_out[i] = usb_alloc_urb(1, GFP_KERNEL);
-		if (usbduxsub[index].urb_out[i] == NULL) {
-			dev_err(dev, "comedi_: usbdux%d: "
-				"Could not alloc. urb(%d)\n", index, i);
-			tidy_up(&(usbduxsub[index]));
-			up(&start_stop_sem);
-			return -ENOMEM;
-		}
-		usbduxsub[index].urb_out[i]->dev = usbduxsub[index].usbdev;
-		/* will be filled later with a pointer to the comedi-device */
-		/* and ONLY then the urb should be submitted */
-		usbduxsub[index].urb_out[i]->context = NULL;
-		usbduxsub[index].urb_out[i]->pipe =
-		    usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
-		usbduxsub[index].urb_out[i]->transfer_flags = URB_ISO_ASAP;
-		usbduxsub[index].urb_out[i]->transfer_buffer =
-		    kzalloc(SIZEOUTBUF, GFP_KERNEL);
-		if (!(usbduxsub[index].urb_out[i]->transfer_buffer)) {
-			tidy_up(&(usbduxsub[index]));
-			up(&start_stop_sem);
-			return -ENOMEM;
-		}
-		usbduxsub[index].urb_out[i]->complete = usbduxsub_ao_isoc_irq;
-		usbduxsub[index].urb_out[i]->number_of_packets = 1;
-		usbduxsub[index].urb_out[i]->transfer_buffer_length = SIZEOUTBUF;
-		usbduxsub[index].urb_out[i]->iso_frame_desc[0].offset = 0;
-		usbduxsub[index].urb_out[i]->iso_frame_desc[0].length =
-		    SIZEOUTBUF;
-		if (usbduxsub[index].high_speed) {
-			/* uframes */
-			usbduxsub[index].urb_out[i]->interval = 8;
-		} else {
-			/* frames */
-			usbduxsub[index].urb_out[i]->interval = 1;
-		}
-	}
-
-	/* pwm */
-	if (usbduxsub[index].high_speed) {
-		/* max bulk ep size in high speed */
-		usbduxsub[index].size_pwm_buf = 512;
-		usbduxsub[index].urb_pwm = usb_alloc_urb(0, GFP_KERNEL);
-		if (usbduxsub[index].urb_pwm == NULL) {
-			dev_err(dev, "comedi_: usbdux%d: "
-				"Could not alloc. pwm urb\n", index);
-			tidy_up(&(usbduxsub[index]));
-			up(&start_stop_sem);
-			return -ENOMEM;
-		}
-		usbduxsub[index].urb_pwm->transfer_buffer =
-		    kzalloc(usbduxsub[index].size_pwm_buf, GFP_KERNEL);
-		if (!(usbduxsub[index].urb_pwm->transfer_buffer)) {
-			tidy_up(&(usbduxsub[index]));
-			up(&start_stop_sem);
-			return -ENOMEM;
-		}
-	} else {
-		usbduxsub[index].urb_pwm = NULL;
-		usbduxsub[index].size_pwm_buf = 0;
-	}
-
-	usbduxsub[index].ai_cmd_running = 0;
-	usbduxsub[index].ao_cmd_running = 0;
-	usbduxsub[index].pwm_cmd_running = 0;
-
-	/* we've reached the bottom of the function */
-	usbduxsub[index].probed = 1;
-	up(&start_stop_sem);
-
-	return comedi_usb_auto_config(uinterf, &usbdux_driver, 0);
-}
-
-static void usbdux_usb_disconnect(struct usb_interface *intf)
-{
-	struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf);
-	struct usb_device *udev = interface_to_usbdev(intf);
-
-	if (!usbduxsub_tmp) {
-		dev_err(&intf->dev,
-			"comedi_: disconnect called with null pointer.\n");
-		return;
-	}
-	if (usbduxsub_tmp->usbdev != udev) {
-		dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
-		return;
-	}
-	comedi_usb_auto_unconfig(intf);
-	down(&start_stop_sem);
-	down(&usbduxsub_tmp->sem);
-	tidy_up(usbduxsub_tmp);
-	up(&usbduxsub_tmp->sem);
-	up(&start_stop_sem);
-	dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
+	return comedi_usb_auto_config(intf, &usbdux_driver, 0);
 }
 
 static const struct usb_device_id usbdux_usb_table[] = {
@@ -2553,13 +1821,12 @@
 	{ USB_DEVICE(0x13d8, 0x0002) },
 	{ }
 };
-
 MODULE_DEVICE_TABLE(usb, usbdux_usb_table);
 
 static struct usb_driver usbdux_usb_driver = {
 	.name		= "usbdux",
 	.probe		= usbdux_usb_probe,
-	.disconnect	= usbdux_usb_disconnect,
+	.disconnect	= comedi_usb_auto_unconfig,
 	.id_table	= usbdux_usb_table,
 };
 module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
@@ -2567,4 +1834,4 @@
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE);
+MODULE_FIRMWARE(USBDUX_FIRMWARE);
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 27898c4..9707dd1 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -1061,10 +1061,9 @@
 		return -ENODEV;
 	}
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	sema_init(&devpriv->sem, 1);
 	usb_set_intfdata(intf, devpriv);
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 898c3c4..c47f408 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -66,13 +66,6 @@
 /* internal addresses of the 8051 processor */
 #define USBDUXSUB_CPUCS 0xE600
 
-/* USB endpoints */
-#define USBDUXSIGMA_CMD_OUT_EP		1	/* command output */
-#define USBDUXSIGMA_ISO_OUT_EP		2	/* analog output ISO/IRQ */
-#define USBDUXSIGMA_PWM_OUT_EP		4	/* pwm output */
-#define USBDUXSIGMA_ISO_IN_EP		6	/* analog input ISO/IRQ */
-#define USBDUXSIGMA_CMD_IN_EP		8	/* command input */
-
 /* 300Hz max frequ under PWM */
 #define MIN_PWM_PERIOD  ((long)(1E9/300))
 
@@ -168,6 +161,7 @@
 	/* input buffer for single insn */
 	int8_t *insn_buf;
 
+	int8_t ao_chanlist[USBDUXSIGMA_NUM_AO_CHAN];
 	unsigned int ao_readback[USBDUXSIGMA_NUM_AO_CHAN];
 
 	unsigned high_speed:1;
@@ -188,25 +182,25 @@
 	unsigned int ao_counter;
 	/* interval in frames/uframes */
 	unsigned int ai_interval;
-	/* D/A commands */
-	uint8_t *dac_commands;
 	/* commands */
 	uint8_t *dux_commands;
 	struct semaphore sem;
 };
 
+static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs)
+{
+	int i;
+
+	for (i = 0; i < num_urbs; i++)
+		usb_kill_urb(urbs[i]);
+}
+
 static void usbduxsigma_ai_stop(struct comedi_device *dev, int do_unlink)
 {
 	struct usbduxsigma_private *devpriv = dev->private;
 
-	if (do_unlink) {
-		int i;
-
-		for (i = 0; i < devpriv->n_ai_urbs; i++) {
-			if (devpriv->ai_urbs[i])
-				usb_kill_urb(devpriv->ai_urbs[i]);
-		}
-	}
+	if (do_unlink && devpriv->ai_urbs)
+		usbduxsigma_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs);
 
 	devpriv->ai_cmd_running = 0;
 }
@@ -342,14 +336,8 @@
 {
 	struct usbduxsigma_private *devpriv = dev->private;
 
-	if (do_unlink) {
-		int i;
-
-		for (i = 0; i < devpriv->n_ao_urbs; i++) {
-			if (devpriv->ao_urbs[i])
-				usb_kill_urb(devpriv->ao_urbs[i]);
-		}
-	}
+	if (do_unlink && devpriv->ao_urbs)
+		usbduxsigma_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs);
 
 	devpriv->ao_cmd_running = 0;
 }
@@ -432,7 +420,7 @@
 		len = s->async->cmd.chanlist_len;
 		*datap++ = len;
 		for (i = 0; i < len; i++) {
-			unsigned int chan = devpriv->dac_commands[i];
+			unsigned int chan = devpriv->ao_chanlist[i];
 			short val;
 
 			ret = comedi_buf_get(s->async, &val);
@@ -643,7 +631,7 @@
 
 	devpriv->dux_commands[0] = cmd_type;
 
-	return usb_bulk_msg(usb, usb_sndbulkpipe(usb, USBDUXSIGMA_CMD_OUT_EP),
+	return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1),
 			    devpriv->dux_commands, SIZEOFDUXBUFFER,
 			    &nsent, BULK_TIMEOUT);
 }
@@ -657,8 +645,7 @@
 	int i;
 
 	for (i = 0; i < RETRIES; i++) {
-		ret = usb_bulk_msg(usb,
-				   usb_rcvbulkpipe(usb, USBDUXSIGMA_CMD_IN_EP),
+		ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8),
 				   devpriv->insn_buf, SIZEINSNBUF,
 				   &nrec, BULK_TIMEOUT);
 		if (ret < 0)
@@ -686,13 +673,14 @@
 
 	down(&devpriv->sem);
 	if (!devpriv->ai_cmd_running) {
+		devpriv->ai_cmd_running = 1;
 		ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs,
 					      devpriv->n_ai_urbs, 1);
 		if (ret < 0) {
+			devpriv->ai_cmd_running = 0;
 			up(&devpriv->sem);
 			return ret;
 		}
-		devpriv->ai_cmd_running = 1;
 		s->async->inttrig = NULL;
 	}
 	up(&devpriv->sem);
@@ -740,14 +728,15 @@
 
 	if (cmd->start_src == TRIG_NOW) {
 		/* enable this acquisition operation */
+		devpriv->ai_cmd_running = 1;
 		ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs,
 					      devpriv->n_ai_urbs, 1);
 		if (ret < 0) {
+			devpriv->ai_cmd_running = 0;
 			up(&devpriv->sem);
 			return ret;
 		}
 		s->async->inttrig = NULL;
-		devpriv->ai_cmd_running = 1;
 	} else {	/* TRIG_INT */
 		/* wait for an internal signal and submit the urbs later */
 		s->async->inttrig = usbduxsigma_ai_inttrig;
@@ -876,13 +865,14 @@
 
 	down(&devpriv->sem);
 	if (!devpriv->ao_cmd_running) {
+		devpriv->ao_cmd_running = 1;
 		ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs,
 					      devpriv->n_ao_urbs, 0);
 		if (ret < 0) {
+			devpriv->ao_cmd_running = 0;
 			up(&devpriv->sem);
 			return ret;
 		}
-		devpriv->ao_cmd_running = 1;
 		s->async->inttrig = NULL;
 	}
 	up(&devpriv->sem);
@@ -1020,20 +1010,21 @@
 	/* set current channel of the running acquisition to zero */
 	s->async->cur_chan = 0;
 	for (i = 0; i < cmd->chanlist_len; ++i)
-		devpriv->dac_commands[i] = CR_CHAN(cmd->chanlist[i]);
+		devpriv->ao_chanlist[i] = CR_CHAN(cmd->chanlist[i]);
 
 	devpriv->ao_counter = devpriv->ao_timer;
 
 	if (cmd->start_src == TRIG_NOW) {
 		/* enable this acquisition operation */
+		devpriv->ao_cmd_running = 1;
 		ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs,
 					      devpriv->n_ao_urbs, 0);
 		if (ret < 0) {
+			devpriv->ao_cmd_running = 0;
 			up(&devpriv->sem);
 			return ret;
 		}
 		s->async->inttrig = NULL;
-		devpriv->ao_cmd_running = 1;
 	} else {	/* TRIG_INT */
 		/* wait for an internal signal and submit the urbs later */
 		s->async->inttrig = usbduxsigma_ao_inttrig;
@@ -1049,23 +1040,11 @@
 				       struct comedi_insn *insn,
 				       unsigned int *data)
 {
-	unsigned int chan = CR_CHAN(insn->chanspec);
-	unsigned int mask = 1 << chan;
+	int ret;
 
-	switch (data[0]) {
-	case INSN_CONFIG_DIO_OUTPUT:
-		s->io_bits |= mask;
-		break;
-	case INSN_CONFIG_DIO_INPUT:
-		s->io_bits &= ~mask;
-		break;
-	case INSN_CONFIG_DIO_QUERY:
-		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
+	ret = comedi_dio_insn_config(dev, s, insn, data, 0);
+	if (ret)
+		return ret;
 
 	/*
 	 * We don't tell the firmware here as it would take 8 frames
@@ -1194,8 +1173,7 @@
 	struct urb *urb = devpriv->pwm_urb;
 
 	/* in case of a resubmission after an unlink... */
-	usb_fill_bulk_urb(urb,
-			  usb, usb_sndbulkpipe(usb, USBDUXSIGMA_PWM_OUT_EP),
+	usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4),
 			  urb->transfer_buffer, devpriv->pwm_buf_sz,
 			  usbduxsigma_pwm_urb_complete, dev);
 
@@ -1237,19 +1215,21 @@
 
 	memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz);
 
-	ret = usbduxsigma_submit_pwm_urb(dev);
-	if (ret < 0)
-		return ret;
 	devpriv->pwm_cmd_running = 1;
+	ret = usbduxsigma_submit_pwm_urb(dev);
+	if (ret < 0) {
+		devpriv->pwm_cmd_running = 0;
+		return ret;
+	}
 
 	return 0;
 }
 
-static int usbduxsigma_pwm_pattern(struct comedi_device *dev,
-				   struct comedi_subdevice *s,
-				   unsigned int chan,
-				   unsigned int value,
-				   unsigned int sign)
+static void usbduxsigma_pwm_pattern(struct comedi_device *dev,
+				    struct comedi_subdevice *s,
+				    unsigned int chan,
+				    unsigned int value,
+				    unsigned int sign)
 {
 	struct usbduxsigma_private *devpriv = dev->private;
 	char pwm_mask = (1 << chan);	/* DIO bit for the PWM data */
@@ -1270,7 +1250,6 @@
 			c |= sgn_mask;
 		*buf++ = c;
 	}
-	return 1;
 }
 
 static int usbduxsigma_pwm_write(struct comedi_device *dev,
@@ -1291,7 +1270,9 @@
 	 * The sign is set via a special INSN only, this gives us 8 bits
 	 * for normal operation, sign is 0 by default.
 	 */
-	return usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0);
+	usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0);
+
+	return insn->n;
 }
 
 static int usbduxsigma_pwm_config(struct comedi_device *dev,
@@ -1326,8 +1307,8 @@
 		 * data[1] = value
 		 * data[2] = sign (for a relay)
 		 */
-		return usbduxsigma_pwm_pattern(dev, s, chan,
-					       data[1], (data[2] != 0));
+		usbduxsigma_pwm_pattern(dev, s, chan, data[1], (data[2] != 0));
+		return 0;
 	case INSN_CONFIG_PWM_GET_H_BRIDGE:
 		/* values are not kept in this driver, nothing to return */
 		return -EINVAL;
@@ -1386,90 +1367,6 @@
 	return (int)val;
 }
 
-static int usbduxsigma_attach_common(struct comedi_device *dev)
-{
-	struct usbduxsigma_private *devpriv = dev->private;
-	struct comedi_subdevice *s;
-	int n_subdevs;
-	int offset;
-	int ret;
-
-	down(&devpriv->sem);
-
-	if (devpriv->high_speed)
-		n_subdevs = 4;	/* with pwm */
-	else
-		n_subdevs = 3;	/* without pwm */
-	ret = comedi_alloc_subdevices(dev, n_subdevs);
-	if (ret) {
-		up(&devpriv->sem);
-		return ret;
-	}
-
-	/* Analog Input subdevice */
-	s = &dev->subdevices[0];
-	dev->read_subdev = s;
-	s->type		= COMEDI_SUBD_AI;
-	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL;
-	s->n_chan	= NUMCHANNELS;
-	s->len_chanlist	= NUMCHANNELS;
-	s->maxdata	= 0x00ffffff;
-	s->range_table	= &usbduxsigma_ai_range;
-	s->insn_read	= usbduxsigma_ai_insn_read;
-	s->do_cmdtest	= usbduxsigma_ai_cmdtest;
-	s->do_cmd	= usbduxsigma_ai_cmd;
-	s->cancel	= usbduxsigma_ai_cancel;
-
-	/* Analog Output subdevice */
-	s = &dev->subdevices[1];
-	dev->write_subdev = s;
-	s->type		= COMEDI_SUBD_AO;
-	s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
-	s->n_chan	= USBDUXSIGMA_NUM_AO_CHAN;
-	s->len_chanlist	= s->n_chan;
-	s->maxdata	= 0x00ff;
-	s->range_table	= &range_unipolar2_5;
-	s->insn_write	= usbduxsigma_ao_insn_write;
-	s->insn_read	= usbduxsigma_ao_insn_read;
-	s->do_cmdtest	= usbduxsigma_ao_cmdtest;
-	s->do_cmd	= usbduxsigma_ao_cmd;
-	s->cancel	= usbduxsigma_ao_cancel;
-
-	/* Digital I/O subdevice */
-	s = &dev->subdevices[2];
-	s->type		= COMEDI_SUBD_DIO;
-	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
-	s->n_chan	= 24;
-	s->maxdata	= 1;
-	s->range_table	= &range_digital;
-	s->insn_bits	= usbduxsigma_dio_insn_bits;
-	s->insn_config	= usbduxsigma_dio_insn_config;
-
-	if (devpriv->high_speed) {
-		/* Timer / pwm subdevice */
-		s = &dev->subdevices[3];
-		s->type		= COMEDI_SUBD_PWM;
-		s->subdev_flags	= SDF_WRITABLE | SDF_PWM_HBRIDGE;
-		s->n_chan	= 8;
-		s->maxdata	= devpriv->pwm_buf_sz;
-		s->insn_write	= usbduxsigma_pwm_write;
-		s->insn_config	= usbduxsigma_pwm_config;
-
-		usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
-	}
-
-	up(&devpriv->sem);
-
-	offset = usbduxsigma_getstatusinfo(dev, 0);
-	if (offset < 0)
-		dev_err(dev->class_dev,
-			"Communication to USBDUXSIGMA failed! Check firmware and cabling\n");
-
-	dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset);
-
-	return 0;
-}
-
 static int usbduxsigma_firmware_upload(struct comedi_device *dev,
 				       const u8 *data, size_t size,
 				       unsigned long context)
@@ -1548,7 +1445,6 @@
 	struct urb *urb;
 	int i;
 
-	devpriv->dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL);
 	devpriv->dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL);
 	devpriv->in_buf = kzalloc(SIZEINBUF, GFP_KERNEL);
 	devpriv->insn_buf = kzalloc(SIZEINSNBUF, GFP_KERNEL);
@@ -1556,8 +1452,7 @@
 				   GFP_KERNEL);
 	devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(*urb),
 				   GFP_KERNEL);
-	if (!devpriv->dac_commands || !devpriv->dux_commands ||
-	    !devpriv->in_buf || !devpriv->insn_buf ||
+	if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf ||
 	    !devpriv->ai_urbs || !devpriv->ao_urbs)
 		return -ENOMEM;
 
@@ -1571,7 +1466,7 @@
 		/* will be filled later with a pointer to the comedi-device */
 		/* and ONLY then the urb should be submitted */
 		urb->context = NULL;
-		urb->pipe = usb_rcvisocpipe(usb, USBDUXSIGMA_ISO_IN_EP);
+		urb->pipe = usb_rcvisocpipe(usb, 6);
 		urb->transfer_flags = URB_ISO_ASAP;
 		urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
 		if (!urb->transfer_buffer)
@@ -1593,7 +1488,7 @@
 		/* will be filled later with a pointer to the comedi-device */
 		/* and ONLY then the urb should be submitted */
 		urb->context = NULL;
-		urb->pipe = usb_sndisocpipe(usb, USBDUXSIGMA_ISO_OUT_EP);
+		urb->pipe = usb_sndisocpipe(usb, 2);
 		urb->transfer_flags = URB_ISO_ASAP;
 		urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
 		if (!urb->transfer_buffer)
@@ -1609,19 +1504,16 @@
 			urb->interval = 1;	/* frames */
 	}
 
-	if (devpriv->high_speed) {
-		/* max bulk ep size in high speed */
-		devpriv->pwm_buf_sz = 512;
+	if (devpriv->pwm_buf_sz) {
 		urb = usb_alloc_urb(0, GFP_KERNEL);
 		if (!urb)
 			return -ENOMEM;
 		devpriv->pwm_urb = urb;
-		urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, GFP_KERNEL);
+
+		urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz,
+					       GFP_KERNEL);
 		if (!urb->transfer_buffer)
 			return -ENOMEM;
-	} else {
-		devpriv->pwm_urb = NULL;
-		devpriv->pwm_buf_sz = 0;
 	}
 
 	return 0;
@@ -1633,11 +1525,6 @@
 	struct urb *urb;
 	int i;
 
-	/* force unlink all urbs */
-	usbduxsigma_ai_stop(dev, 1);
-	usbduxsigma_ao_stop(dev, 1);
-	usbduxsigma_pwm_stop(dev, 1);
-
 	urb = devpriv->pwm_urb;
 	if (urb) {
 		kfree(urb->transfer_buffer);
@@ -1666,7 +1553,6 @@
 	kfree(devpriv->insn_buf);
 	kfree(devpriv->in_buf);
 	kfree(devpriv->dux_commands);
-	kfree(devpriv->dac_commands);
 }
 
 static int usbduxsigma_auto_attach(struct comedi_device *dev,
@@ -1675,29 +1561,23 @@
 	struct usb_interface *intf = comedi_to_usb_interface(dev);
 	struct usb_device *usb = comedi_to_usb_dev(dev);
 	struct usbduxsigma_private *devpriv;
+	struct comedi_subdevice *s;
+	int offset;
 	int ret;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	sema_init(&devpriv->sem, 1);
+
 	usb_set_intfdata(intf, devpriv);
 
-	ret = usb_set_interface(usb,
-				intf->altsetting->desc.bInterfaceNumber, 3);
-	if (ret < 0) {
-		dev_err(dev->class_dev,
-			"could not set alternate setting 3 in high speed\n");
-		return -ENODEV;
-	}
-
-	/* test if it is high speed (USB 2.0) */
 	devpriv->high_speed = (usb->speed == USB_SPEED_HIGH);
 	if (devpriv->high_speed) {
 		devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH;
 		devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH;
+		devpriv->pwm_buf_sz = 512;
 	} else {
 		devpriv->n_ai_urbs = NUMOFINBUFFERSFULL;
 		devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL;
@@ -1707,12 +1587,84 @@
 	if (ret)
 		return ret;
 
+	/* setting to alternate setting 3: enabling iso ep and bulk ep. */
+	ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber,
+				3);
+	if (ret < 0) {
+		dev_err(dev->class_dev,
+			"could not set alternate setting 3 in high speed\n");
+		return ret;
+	}
+
 	ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE,
 				   usbduxsigma_firmware_upload, 0);
 	if (ret)
 		return ret;
 
-	return usbduxsigma_attach_common(dev);
+	ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 4 : 3);
+	if (ret)
+		return ret;
+
+	/* Analog Input subdevice */
+	s = &dev->subdevices[0];
+	dev->read_subdev = s;
+	s->type		= COMEDI_SUBD_AI;
+	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL;
+	s->n_chan	= NUMCHANNELS;
+	s->len_chanlist	= NUMCHANNELS;
+	s->maxdata	= 0x00ffffff;
+	s->range_table	= &usbduxsigma_ai_range;
+	s->insn_read	= usbduxsigma_ai_insn_read;
+	s->do_cmdtest	= usbduxsigma_ai_cmdtest;
+	s->do_cmd	= usbduxsigma_ai_cmd;
+	s->cancel	= usbduxsigma_ai_cancel;
+
+	/* Analog Output subdevice */
+	s = &dev->subdevices[1];
+	dev->write_subdev = s;
+	s->type		= COMEDI_SUBD_AO;
+	s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
+	s->n_chan	= USBDUXSIGMA_NUM_AO_CHAN;
+	s->len_chanlist	= s->n_chan;
+	s->maxdata	= 0x00ff;
+	s->range_table	= &range_unipolar2_5;
+	s->insn_write	= usbduxsigma_ao_insn_write;
+	s->insn_read	= usbduxsigma_ao_insn_read;
+	s->do_cmdtest	= usbduxsigma_ao_cmdtest;
+	s->do_cmd	= usbduxsigma_ao_cmd;
+	s->cancel	= usbduxsigma_ao_cancel;
+
+	/* Digital I/O subdevice */
+	s = &dev->subdevices[2];
+	s->type		= COMEDI_SUBD_DIO;
+	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
+	s->n_chan	= 24;
+	s->maxdata	= 1;
+	s->range_table	= &range_digital;
+	s->insn_bits	= usbduxsigma_dio_insn_bits;
+	s->insn_config	= usbduxsigma_dio_insn_config;
+
+	if (devpriv->high_speed) {
+		/* Timer / pwm subdevice */
+		s = &dev->subdevices[3];
+		s->type		= COMEDI_SUBD_PWM;
+		s->subdev_flags	= SDF_WRITABLE | SDF_PWM_HBRIDGE;
+		s->n_chan	= 8;
+		s->maxdata	= devpriv->pwm_buf_sz;
+		s->insn_write	= usbduxsigma_pwm_write;
+		s->insn_config	= usbduxsigma_pwm_config;
+
+		usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD);
+	}
+
+	offset = usbduxsigma_getstatusinfo(dev, 0);
+	if (offset < 0)
+		dev_err(dev->class_dev,
+			"Communication to USBDUXSIGMA failed! Check firmware and cabling\n");
+
+	dev_info(dev->class_dev, "attached, ADC_zero = %x\n", offset);
+
+	return 0;
 }
 
 static void usbduxsigma_detach(struct comedi_device *dev)
@@ -1720,13 +1672,20 @@
 	struct usb_interface *intf = comedi_to_usb_interface(dev);
 	struct usbduxsigma_private *devpriv = dev->private;
 
+	usb_set_intfdata(intf, NULL);
+
 	if (!devpriv)
 		return;
 
-	usb_set_intfdata(intf, NULL);
-
 	down(&devpriv->sem);
+
+	/* force unlink all urbs */
+	usbduxsigma_ai_stop(dev, 1);
+	usbduxsigma_ao_stop(dev, 1);
+	usbduxsigma_pwm_stop(dev, 1);
+
 	usbduxsigma_free_usb_buffers(dev);
+
 	up(&devpriv->sem);
 }
 
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 0ab04c0..06efa16 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -875,10 +875,9 @@
 	dev->board_ptr = boardinfo;
 	dev->board_name = boardinfo->name;
 
-	devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 	if (!devpriv)
 		return -ENOMEM;
-	dev->private = devpriv;
 
 	devpriv->model = boardinfo->model;
 
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index da8988c..cd60677 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -22,8 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fcntl.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/io.h>
 
@@ -125,6 +123,27 @@
 	return ret;
 }
 
+int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev,
+			  unsigned int chan, unsigned int *io)
+{
+	struct comedi_insn insn;
+	unsigned int data[2];
+	int ret;
+
+	memset(&insn, 0, sizeof(insn));
+	insn.insn = INSN_CONFIG;
+	insn.n = 2;
+	insn.subdev = subdev;
+	insn.chanspec = CR_PACK(chan, 0, 0);
+	data[0] = INSN_CONFIG_DIO_QUERY;
+	data[1] = 0;
+	ret = comedi_do_insn(dev, &insn, data);
+	if (ret >= 0)
+		*io = data[1];
+	return ret;
+}
+EXPORT_SYMBOL_GPL(comedi_dio_get_config);
+
 int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
 		      unsigned int chan, unsigned int io)
 {
@@ -140,28 +159,53 @@
 }
 EXPORT_SYMBOL_GPL(comedi_dio_config);
 
-int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
-			unsigned int mask, unsigned int *bits)
+int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev,
+			 unsigned int mask, unsigned int *bits,
+			 unsigned int base_channel)
 {
 	struct comedi_insn insn;
 	unsigned int data[2];
+	unsigned int n_chan;
+	unsigned int shift;
 	int ret;
 
+	if (subdev >= dev->n_subdevices)
+		return -EINVAL;
+
+	base_channel = CR_CHAN(base_channel);
+	n_chan = comedi_get_n_channels(dev, subdev);
+	if (base_channel >= n_chan)
+		return -EINVAL;
+
 	memset(&insn, 0, sizeof(insn));
 	insn.insn = INSN_BITS;
+	insn.chanspec = base_channel;
 	insn.n = 2;
 	insn.subdev = subdev;
 
 	data[0] = mask;
 	data[1] = *bits;
 
+	/*
+	 * Most drivers ignore the base channel in insn->chanspec.
+	 * Fix this here if the subdevice has <= 32 channels.
+	 */
+	if (n_chan <= 32) {
+		shift = base_channel;
+		if (shift) {
+			insn.chanspec = 0;
+			data[0] <<= shift;
+			data[1] <<= shift;
+		}
+	} else {
+		shift = 0;
+	}
+
 	ret = comedi_do_insn(dev, &insn, data);
-
-	*bits = data[1];
-
+	*bits = data[1] >> shift;
 	return ret;
 }
-EXPORT_SYMBOL_GPL(comedi_dio_bitfield);
+EXPORT_SYMBOL_GPL(comedi_dio_bitfield2);
 
 int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
 				  unsigned int subd)
diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c
index 8ee9442..ade0003 100644
--- a/drivers/staging/comedi/proc.c
+++ b/drivers/staging/comedi/proc.c
@@ -55,6 +55,7 @@
 	if (!devices_q)
 		seq_puts(m, "no devices\n");
 
+	mutex_lock(&comedi_drivers_list_lock);
 	for (driv = comedi_drivers; driv; driv = driv->next) {
 		seq_printf(m, "%s:\n", driv->driver_name);
 		for (i = 0; i < driv->num_names; i++)
@@ -65,6 +66,7 @@
 		if (!driv->num_names)
 			seq_printf(m, " %s\n", driv->driver_name);
 	}
+	mutex_unlock(&comedi_drivers_list_lock);
 
 	return 0;
 }
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 1f20332..8fde554 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -127,38 +127,35 @@
 	return 1;
 }
 
-/*
-   This function checks each element in a channel/gain list to make
-   make sure it is valid.
+/**
+ * comedi_check_chanlist() - Validate each element in a chanlist.
+ * @s: comedi_subdevice struct
+ * @n: number of elements in the chanlist
+ * @chanlist: the chanlist to validate
 */
 int comedi_check_chanlist(struct comedi_subdevice *s, int n,
 			  unsigned int *chanlist)
 {
 	struct comedi_device *dev = s->device;
-	int i;
-	int chan;
+	unsigned int chanspec;
+	int chan, range_len, i;
 
-	if (s->range_table) {
-		for (i = 0; i < n; i++)
-			if (CR_CHAN(chanlist[i]) >= s->n_chan ||
-			    CR_RANGE(chanlist[i]) >= s->range_table->length
-			    || aref_invalid(s, chanlist[i])) {
-				dev_warn(dev->class_dev,
-					 "bad chanlist[%d]=0x%08x in_chan=%d range length=%d\n",
-					 i, chanlist[i], s->n_chan,
-					 s->range_table->length);
-				return -EINVAL;
-			}
-	} else if (s->range_table_list) {
+	if (s->range_table || s->range_table_list) {
 		for (i = 0; i < n; i++) {
-			chan = CR_CHAN(chanlist[i]);
+			chanspec = chanlist[i];
+			chan = CR_CHAN(chanspec);
+			if (s->range_table)
+				range_len = s->range_table->length;
+			else if (s->range_table_list && chan < s->n_chan)
+				range_len = s->range_table_list[chan]->length;
+			else
+				range_len = 0;
 			if (chan >= s->n_chan ||
-			    CR_RANGE(chanlist[i]) >=
-			    s->range_table_list[chan]->length
-			    || aref_invalid(s, chanlist[i])) {
+			    CR_RANGE(chanspec) >= range_len ||
+			    aref_invalid(s, chanspec)) {
 				dev_warn(dev->class_dev,
-					 "bad chanlist[%d]=0x%08x\n",
-					 i, chanlist[i]);
+					 "bad chanlist[%d]=0x%08x chan=%d range length=%d\n",
+					 i, chanspec, chan, range_len);
 				return -EINVAL;
 			}
 		}
diff --git a/drivers/staging/crystalhd/crystalhd_cmds.c b/drivers/staging/crystalhd/crystalhd_cmds.c
index 3ab502b..07a2f24 100644
--- a/drivers/staging/crystalhd/crystalhd_cmds.c
+++ b/drivers/staging/crystalhd/crystalhd_cmds.c
@@ -94,8 +94,7 @@
 	for (i = 0; i < BC_LINK_MAX_OPENS; i++) {
 		if (ctx->user[i].mode == DTS_DIAG_MODE ||
 		    ctx->user[i].mode == DTS_PLAYBACK_MODE) {
-			BCMLOG_ERR("multiple playback sessions are not "
-				   "supported..\n");
+			BCMLOG_ERR("multiple playback sessions are not supported..\n");
 			return BC_STS_ERR_USAGE;
 		}
 	}
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c
index 0c8cb32..5845e89 100644
--- a/drivers/staging/crystalhd/crystalhd_hw.c
+++ b/drivers/staging/crystalhd/crystalhd_hw.c
@@ -1061,7 +1061,7 @@
 	dst_pib->aspect_ratio        = src_pib->ppb.aspect_ratio;
 	dst_pib->colour_primaries     = src_pib->ppb.colour_primaries;
 	dst_pib->picture_meta_payload = src_pib->ppb.picture_meta_payload;
-	dst_pib->frame_rate		= src_pib->resolution ;
+	dst_pib->frame_rate		= src_pib->resolution;
 	return;
 }
 
@@ -1553,11 +1553,10 @@
 				crystalhd_get_dnsz(hw, i, &y_dn_sz, &uv_dn_sz);
 				/* FIXME: jarod: this is where
 				 my mini pci-e card is tripping up */
-				BCMLOG(BCMLOG_DBG, "list_index:%x rx[%d] Y:%x "
-				       "UV:%x Int:%x YDnSz:%x UVDnSz:%x\n",
+				BCMLOG(BCMLOG_DBG, "list_index:%x rx[%d] Y:%x UV:%x Int:%x YDnSz:%x UVDnSz:%x\n",
 				       i, hw->stats.rx_errors, y_err_sts,
 				       uv_err_sts, intr_sts, y_dn_sz,
-				       		 uv_dn_sz);
+				       uv_dn_sz);
 				hw->rx_list_sts[i] = sts_free;
 				comp_sts = BC_STS_ERROR;
 				break;
diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c
index c1f6163..b17fbf8 100644
--- a/drivers/staging/crystalhd/crystalhd_lnx.c
+++ b/drivers/staging/crystalhd/crystalhd_lnx.c
@@ -545,8 +545,7 @@
 	int rc;
 	enum BC_STATUS sts = BC_STS_SUCCESS;
 
-	BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x "
-	       "s_vendor:0x%04x s_device: 0x%04x\n",
+	BCMLOG(BCMLOG_DBG, "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n",
 	       pdev->vendor, pdev->device, pdev->subsystem_vendor,
 	       pdev->subsystem_device);
 
diff --git a/drivers/staging/crystalhd/crystalhd_misc.h b/drivers/staging/crystalhd/crystalhd_misc.h
index 4dae3a7..aa736c8 100644
--- a/drivers/staging/crystalhd/crystalhd_misc.h
+++ b/drivers/staging/crystalhd/crystalhd_misc.h
@@ -177,8 +177,8 @@
 
 extern enum BC_STATUS crystalhd_unmap_dio(struct crystalhd_adp *,
 					 struct crystalhd_dio_req*);
-#define crystalhd_get_sgle_paddr(_dio, _ix) (cpu_to_le64(sg_dma_address(&_dio->sg[_ix])))
-#define crystalhd_get_sgle_len(_dio, _ix) (cpu_to_le32(sg_dma_len(&_dio->sg[_ix])))
+#define crystalhd_get_sgle_paddr(_dio, _ix) (sg_dma_address(&_dio->sg[_ix]))
+#define crystalhd_get_sgle_len(_dio, _ix) (sg_dma_len(&_dio->sg[_ix]))
 
 /*================ General Purpose Queues ==================*/
 extern enum BC_STATUS crystalhd_create_dioq(struct crystalhd_adp *,
diff --git a/drivers/staging/cxt1e1/Makefile b/drivers/staging/cxt1e1/Makefile
index b9ccb76..2f217e9 100644
--- a/drivers/staging/cxt1e1/Makefile
+++ b/drivers/staging/cxt1e1/Makefile
@@ -2,7 +2,6 @@
 
 ccflags-y := -DSBE_PMCC4_ENABLE
 ccflags-y += -DSBE_ISR_TASKLET
-ccflags-y += -DSBE_INCLUDE_SYMBOLS
 
 cxt1e1-y := 	\
   ossiRelease.o 	\
diff --git a/drivers/staging/cxt1e1/comet.c b/drivers/staging/cxt1e1/comet.c
index fabfd77..d71aea5 100644
--- a/drivers/staging/cxt1e1/comet.c
+++ b/drivers/staging/cxt1e1/comet.c
@@ -22,22 +22,15 @@
 #include "comet.h"
 #include "comet_tables.h"
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
-
 extern int  cxt1e1_log_level;
 
 #define COMET_NUM_SAMPLES   24  /* Number of entries in the waveform table */
 #define COMET_NUM_UNITS     5   /* Number of points per entry in table */
 
 /* forward references */
-STATIC void SetPwrLevel(comet_t *comet);
-STATIC void WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table);
-STATIC void WrtXmtWaveformTbl(ci_t *ci, comet_t *comet, u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]);
+static void SetPwrLevel(comet_t *comet);
+static void WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table);
+static void WrtXmtWaveformTbl(ci_t *ci, comet_t *comet, u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS]);
 
 
 void       *TWV_table[12] = {
@@ -407,7 +400,7 @@
 **                Write the data to the Pulse Waveform Storage Data register.
 ** Returns:     Nothing
 */
-STATIC void
+static void
 WrtXmtWaveform(ci_t *ci, comet_t *comet, u_int32_t sample, u_int32_t unit, u_int8_t data)
 {
 	u_int8_t    WaveformAddr;
@@ -425,7 +418,7 @@
 **                for driving the transmitter DAC.
 ** Returns:     Nothing
 */
-STATIC void
+static void
 WrtXmtWaveformTbl(ci_t *ci, comet_t *comet,
 		  u_int8_t table[COMET_NUM_SAMPLES][COMET_NUM_UNITS])
 {
@@ -452,7 +445,7 @@
 **           is coded with early setup of indirect address.
 */
 
-STATIC void
+static void
 WrtRcvEqualizerTbl(ci_t *ci, comet_t *comet, u_int32_t *table)
 {
 	u_int32_t   ramaddr;
@@ -516,7 +509,7 @@
 ** Returns:     Nothing
 */
 
-STATIC void
+static void
 SetPwrLevel(comet_t *comet)
 {
 	volatile u_int32_t temp;
@@ -558,7 +551,7 @@
 ** Returns:     Nothing
 */
 #if 0
-STATIC void
+static void
 SetCometOps(comet_t *comet)
 {
 	volatile u_int8_t rd_value;
diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c
index 6167dc5..d021b31 100644
--- a/drivers/staging/cxt1e1/functions.c
+++ b/drivers/staging/cxt1e1/functions.c
@@ -24,13 +24,6 @@
 #include "libsbew.h"
 #include "pmcc4.h"
 
-
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
 #if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \
     defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE)
 #define _v7_hdlc_  1
@@ -111,7 +104,7 @@
 }
 
 
-STATIC void
+static void
 watchdog_func (unsigned long arg)
 {
     struct watchdog *wd = (void *) arg;
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c
index 110c252..53e9237 100644
--- a/drivers/staging/cxt1e1/hwprobe.c
+++ b/drivers/staging/cxt1e1/hwprobe.c
@@ -31,12 +31,6 @@
 #include "sbeproc.h"
 #endif
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
 extern int  cxt1e1_log_level;
 extern int  error_flag;
 extern int  drvr_state;
@@ -221,7 +215,7 @@
 }
 
 
-STATIC int  __init
+static int  __init
 c4_hdw_init (struct pci_dev *pdev, int found)
 {
     hdw_info_t *hi;
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c
index e5889ef..142691c 100644
--- a/drivers/staging/cxt1e1/linux.c
+++ b/drivers/staging/cxt1e1/linux.c
@@ -52,12 +52,6 @@
 
 /*****************************************************************************************/
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
 #define CHANNAME "hdlc"
 
 /*******************************************************************/
@@ -285,7 +279,7 @@
 }
 
 
-STATIC int
+static int
 chan_open (struct net_device *ndev)
 {
     hdlc_device *hdlc = dev_to_hdlc (ndev);
@@ -305,7 +299,7 @@
 }
 
 
-STATIC int
+static int
 chan_close (struct net_device *ndev)
 {
     hdlc_device *hdlc = dev_to_hdlc (ndev);
@@ -319,14 +313,14 @@
 }
 
 
-STATIC int
+static int
 chan_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 {
     return hdlc_ioctl (dev, ifr, cmd);
 }
 
 
-STATIC int
+static int
 chan_attach_noop (struct net_device *ndev, unsigned short foo_1, unsigned short foo_2)
 {
     return 0;                   /* our driver has nothing to do here, show's
@@ -334,7 +328,7 @@
 }
 
 
-STATIC struct net_device_stats *
+static struct net_device_stats *
 chan_get_stats (struct net_device *ndev)
 {
     mch_t      *ch;
@@ -394,7 +388,7 @@
 }
 
 
-STATIC int
+static int
 c4_linux_xmit (struct sk_buff *skb, struct net_device *ndev)
 {
     const struct c4_priv *priv;
@@ -416,7 +410,7 @@
        .ndo_get_stats  = chan_get_stats,
 };
 
-STATIC struct net_device *
+static struct net_device *
 create_chan (struct net_device *ndev, ci_t *ci,
              struct sbecom_chan_param *cp)
 {
@@ -509,7 +503,7 @@
 
 
 /* the idea here is to get port information and pass it back (using pointer) */
-STATIC      status_t
+static      status_t
 do_get_port (struct net_device *ndev, void *data)
 {
     int         ret;
@@ -534,7 +528,7 @@
 }
 
 /* this function copys the user data and then calls the real action function */
-STATIC      status_t
+static      status_t
 do_set_port (struct net_device *ndev, void *data)
 {
     ci_t       *ci;             /* ci stands for card information */
@@ -556,7 +550,7 @@
 }
 
 /* work the port loopback mode as per directed */
-STATIC      status_t
+static      status_t
 do_port_loop (struct net_device *ndev, void *data)
 {
     struct sbecom_port_param pp;
@@ -571,7 +565,7 @@
 }
 
 /* set the specified register with the given value / or just read it */
-STATIC      status_t
+static      status_t
 do_framer_rw (struct net_device *ndev, void *data)
 {
     struct sbecom_port_param pp;
@@ -592,7 +586,7 @@
 }
 
 /* set the specified register with the given value / or just read it */
-STATIC      status_t
+static      status_t
 do_pld_rw (struct net_device *ndev, void *data)
 {
     struct sbecom_port_param pp;
@@ -613,7 +607,7 @@
 }
 
 /* set the specified register with the given value / or just read it */
-STATIC      status_t
+static      status_t
 do_musycc_rw (struct net_device *ndev, void *data)
 {
     struct c4_musycc_param mp;
@@ -633,7 +627,7 @@
     return 0;
 }
 
-STATIC      status_t
+static      status_t
 do_get_chan (struct net_device *ndev, void *data)
 {
     struct sbecom_chan_param cp;
@@ -651,7 +645,7 @@
     return 0;
 }
 
-STATIC      status_t
+static      status_t
 do_set_chan (struct net_device *ndev, void *data)
 {
     struct sbecom_chan_param cp;
@@ -672,7 +666,7 @@
     }
 }
 
-STATIC      status_t
+static      status_t
 do_create_chan (struct net_device *ndev, void *data)
 {
     ci_t       *ci;
@@ -699,7 +693,7 @@
     return ret;
 }
 
-STATIC      status_t
+static      status_t
 do_get_chan_stats (struct net_device *ndev, void *data)
 {
     struct c4_chan_stats_wrap ccs;
@@ -720,7 +714,7 @@
         return -EFAULT;
     return 0;
 }
-STATIC      status_t
+static      status_t
 do_set_loglevel (struct net_device *ndev, void *data)
 {
     unsigned int cxt1e1_log_level;
@@ -731,7 +725,7 @@
     return 0;
 }
 
-STATIC      status_t
+static      status_t
 do_deluser (struct net_device *ndev, int lockit)
 {
     if (ndev->flags & IFF_UP)
@@ -826,7 +820,7 @@
     return mkret (c4_del_chan_stats (cp.channum));
 }
 
-STATIC      status_t
+static      status_t
 c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd)
 {
     ci_t       *ci;
@@ -1102,7 +1096,7 @@
     return ndev;
 }
 
-STATIC int  __init
+static int  __init
 c4_mod_init (void)
 {
     int         rtn;
@@ -1144,7 +1138,7 @@
   * do_deluser()
   */
 
-STATIC void __exit
+static void __exit
 cleanup_hdlc (void)
 {
     hdw_info_t *hi;
@@ -1168,7 +1162,7 @@
 }
 
 
-STATIC void __exit
+static void __exit
 c4_mod_remove (void)
 {
 	cleanup_hdlc();            /* delete any missed channels */
diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c
index 1037086..52b6d7f 100644
--- a/drivers/staging/cxt1e1/musycc.c
+++ b/drivers/staging/cxt1e1/musycc.c
@@ -35,12 +35,6 @@
 #include "pmcc4.h"
 #include "musycc.h"
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
 #define sd_find_chan(ci,ch)   c4_find_chan(ch)
 
 
@@ -65,7 +59,6 @@
 void        musycc_bh_tx_eom(mpi_t *, int);
 int         musycc_chan_up(ci_t *, int);
 status_t __init musycc_init(ci_t *);
-STATIC void __init musycc_init_port(mpi_t *);
 void        musycc_intr_bh_tasklet(ci_t *);
 void        musycc_serv_req(mpi_t *, u_int32_t);
 void        musycc_update_timeslots(mpi_t *);
@@ -73,7 +66,7 @@
 /*******************************************************************/
 
 #if 1
-STATIC int
+static int
 musycc_dump_rxbuffer_ring(mch_t *ch, int lockit)
 {
     struct mdesc *m;
@@ -139,7 +132,7 @@
 #endif
 
 #if 1
-STATIC int
+static int
 musycc_dump_txbuffer_ring(mch_t *ch, int lockit)
 {
     struct mdesc *m;
@@ -702,7 +695,7 @@
 }
 
 #ifdef SBE_WAN256T3_ENABLE
-STATIC void __init
+static void __init
 musycc_init_port(mpi_t *pi)
 {
     pci_write_32((u_int32_t *) &pi->reg->gbp, OS_vtophys(pi->regram));
@@ -1009,7 +1002,7 @@
 }
 
 
-STATIC void
+static void
 musycc_bh_rx_eom(mpi_t *pi, int gchan)
 {
     mch_t      *ch;
diff --git a/drivers/staging/cxt1e1/pmc93x6_eeprom.c b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
index 62b12fb..137b63c 100644
--- a/drivers/staging/cxt1e1/pmc93x6_eeprom.c
+++ b/drivers/staging/cxt1e1/pmc93x6_eeprom.c
@@ -34,13 +34,6 @@
 #define FALSE  0
 #endif
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
-
 /*------------------------------------------------------------------------
  *      EEPROM address definitions
  *------------------------------------------------------------------------
@@ -120,7 +113,7 @@
  *      (the MSB becomes the LSB etc.).
  */
 
-STATIC void
+static void
 BuildByteReverse (void)
 {
     long        half;           /* Used to build by powers to 2 */
@@ -141,7 +134,7 @@
  *------------------------------------------------------------------------
  */
 
-STATIC void
+static void
 eeprom_delay (void)
 {
     int         timeout;
@@ -224,7 +217,7 @@
  *      Issue the EEPROM command to disable writes.
  */
 
-STATIC void
+static void
 disable_pmc_eeprom (long addr)
 {
     eeprom_put_byte (addr, EPROM_EWDS, SIZE_ADDR_OP);
@@ -241,7 +234,7 @@
  *      Issue the EEPROM command to enable writes.
  */
 
-STATIC void
+static void
 enable_pmc_eeprom (long addr)
 {
     eeprom_put_byte (addr, EPROM_EWEN, SIZE_ADDR_OP);
diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c
index 32d7a21..2383c60 100644
--- a/drivers/staging/cxt1e1/pmcc4_drv.c
+++ b/drivers/staging/cxt1e1/pmcc4_drv.c
@@ -39,13 +39,6 @@
 #include "comet.h"
 #include "sbe_bid.h"
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
-
 #define KERN_WARN KERN_WARNING
 
 /* forward references */
@@ -458,7 +451,7 @@
 }
 
 
-STATIC void
+static void
 c4_watchdog (ci_t *ci)
 {
     if (drvr_state != SBE_DRVR_AVAILABLE)
@@ -1184,7 +1177,7 @@
     return 0;
 }
 
-STATIC int
+static int
 c4_fifo_alloc (mpi_t *pi, int chan, int *len)
 {
     int         i, l = 0, start = 0, max = 0, maxstart = 0;
diff --git a/drivers/staging/cxt1e1/sbeid.c b/drivers/staging/cxt1e1/sbeid.c
index 0f9bd5f..791993f 100644
--- a/drivers/staging/cxt1e1/sbeid.c
+++ b/drivers/staging/cxt1e1/sbeid.c
@@ -19,13 +19,6 @@
 #include "pmcc4.h"
 #include "sbe_bid.h"
 
-#ifdef SBE_INCLUDE_SYMBOLS
-#define STATIC
-#else
-#define STATIC  static
-#endif
-
-
 char       *
 sbeid_get_bdname (ci_t *ci)
 {
diff --git a/drivers/staging/dgap/Kconfig b/drivers/staging/dgap/Kconfig
new file mode 100644
index 0000000..31f1d75
--- /dev/null
+++ b/drivers/staging/dgap/Kconfig
@@ -0,0 +1,6 @@
+config DGAP
+       tristate "Digi EPCA PCI products"
+       default n
+       depends on TTY
+       ---help---
+       Driver for the Digi International EPCA PCI based product line
diff --git a/drivers/staging/dgap/Makefile b/drivers/staging/dgap/Makefile
new file mode 100644
index 0000000..9f1fce1
--- /dev/null
+++ b/drivers/staging/dgap/Makefile
@@ -0,0 +1,9 @@
+EXTRA_CFLAGS += -DDG_NAME=\"dgap-1.3-16\" -DDG_PART=\"40002347_C\"
+
+obj-$(CONFIG_DGAP) += dgap.o
+
+
+dgap-objs :=	dgap_driver.o   dgap_fep5.o \
+		dgap_parse.o	dgap_trace.o \
+		dgap_tty.o	dgap_sysfs.o
+
diff --git a/drivers/staging/dgap/dgap_conf.h b/drivers/staging/dgap/dgap_conf.h
new file mode 100644
index 0000000..8809701
--- /dev/null
+++ b/drivers/staging/dgap/dgap_conf.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *****************************************************************************
+ *
+ *	dgap_conf.h - Header file for installations and parse files.
+ *
+ *	$Id: dgap_conf.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef _DGAP_CONF_H
+#define _DGAP_CONF_H
+
+#define NULLNODE 0		/* header node, not used */
+#define BNODE 1			/* Board node */
+#define LNODE 2			/* Line node */
+#define CNODE 3			/* Concentrator node */
+#define MNODE 4			/* EBI Module node */
+#define TNODE 5			/* tty name prefix node */
+#define	CUNODE 6		/* cu name prefix (non-SCO) */
+#define PNODE 7			/* trans. print prefix node */
+#define JNODE 8			/* maJor number node */
+#define ANODE 9			/* altpin */
+#define	TSNODE 10		/* tty structure size */
+#define CSNODE 11		/* channel structure size */
+#define BSNODE 12		/* board structure size */
+#define USNODE 13		/* unit schedule structure size */
+#define FSNODE 14		/* f2200 structure size */
+#define VSNODE 15		/* size of VPIX structures */
+#define INTRNODE 16		/* enable interrupt */
+
+/* Enumeration of tokens */
+#define	BEGIN	1
+#define	END	2
+#define	BOARD	10
+
+#define EPCFS	11 /* start of EPC family definitions */
+#define	ICX		11
+#define	MCX		13
+#define PCX	14
+#define	IEPC	15
+#define	EEPC	16
+#define	MEPC	17
+#define	IPCM	18
+#define	EPCM	19
+#define	MPCM	20
+#define PEPC	21
+#define PPCM	22
+#ifdef CP
+#define ICP     23
+#define ECP     24
+#define MCP     25
+#endif
+#define EPCFE	25 /* end of EPC family definitions */
+#define	PC2E	26
+#define	PC4E	27
+#define	PC4E8K	28
+#define	PC8E	29
+#define	PC8E8K	30
+#define	PC16E	31
+#define MC2E8K  34
+#define MC4E8K  35
+#define MC8E8K  36
+
+#define AVANFS	42	/* start of Avanstar family definitions */
+#define A8P 	42
+#define A16P	43
+#define AVANFE	43	/* end of Avanstar family definitions */
+
+#define DA2000FS	44	/* start of AccelePort 2000 family definitions */
+#define DA22 		44 /* AccelePort 2002 */
+#define DA24 		45 /* AccelePort 2004 */
+#define DA28		46 /* AccelePort 2008 */
+#define DA216		47 /* AccelePort 2016 */
+#define DAR4		48 /* AccelePort RAS 4 port */
+#define DAR8		49 /* AccelePort RAS 8 port */
+#define DDR24		50 /* DataFire RAS 24 port */
+#define DDR30		51 /* DataFire RAS 30 port */
+#define DDR48		52 /* DataFire RAS 48 port */
+#define DDR60		53 /* DataFire RAS 60 port */
+#define DA2000FE	53 /* end of AccelePort 2000/RAS family definitions */
+
+#define PCXRFS	106	/* start of PCXR family definitions */
+#define	APORT4	106
+#define	APORT8	107
+#define PAPORT4 108
+#define PAPORT8 109
+#define APORT4_920I	110
+#define APORT8_920I	111
+#define APORT4_920P	112
+#define APORT8_920P	113
+#define APORT2_920P 114
+#define PCXRFE	117	/* end of PCXR family definitions */
+
+#define	LINE	82
+#ifdef T1
+#define T1M	83
+#define E1M	84
+#endif
+#define	CONC	64
+#define	CX	65
+#define	EPC	66
+#define	MOD	67
+#define	PORTS	68
+#define METHOD	69
+#define CUSTOM	70
+#define BASIC	71
+#define STATUS	72
+#define MODEM	73
+/* The following tokens can appear in multiple places */
+#define	SPEED	74
+#define	NPORTS	75
+#define	ID	76
+#define CABLE	77
+#define CONNECT	78
+#define	IO	79
+#define	MEM	80
+#define DPSZ	81
+
+#define	TTYN	90
+#define	CU	91
+#define	PRINT	92
+#define	XPRINT	93
+#define CMAJOR   94 
+#define ALTPIN  95
+#define STARTO 96
+#define USEINTR  97
+#define PCIINFO  98
+
+#define	TTSIZ	100
+#define	CHSIZ	101
+#define BSSIZ	102
+#define	UNTSIZ	103
+#define	F2SIZ	104
+#define	VPSIZ	105
+
+#define	TOTAL_BOARD	2
+#define	CURRENT_BRD	4
+#define	BOARD_TYPE	6
+#define	IO_ADDRESS	8
+#define	MEM_ADDRESS	10
+
+#define	FIELDS_PER_PAGE	18
+
+#define TB_FIELD	1
+#define CB_FIELD	3
+#define BT_FIELD	5
+#define IO_FIELD	7
+#define ID_FIELD	8
+#define ME_FIELD	9
+#define TTY_FIELD	11
+#define CU_FIELD	13
+#define PR_FIELD	15
+#define MPR_FIELD	17
+
+#define	MAX_FIELD	512
+
+#define	INIT		0
+#define	NITEMS		128
+#define MAX_ITEM	512
+
+#define	DSCRINST	1
+#define	DSCRNUM		3
+#define	ALTPINQ		5
+#define	SSAVE		7
+
+#define	DSCR		"32"
+#define	ONETONINE	"123456789"
+#define	ALL		"1234567890"
+
+
+struct cnode {
+	struct cnode *next;
+	int type;
+	int numbrd;
+
+	union {
+		struct {
+			char  type;	/* Board Type 		*/
+			short port;	/* I/O Address		*/
+			char  *portstr; /* I/O Address in string */
+			long  addr;	/* Memory Address	*/
+			char  *addrstr; /* Memory Address in string */
+			long  pcibus;	/* PCI BUS		*/
+			char  *pcibusstr; /* PCI BUS in string */
+			long  pcislot;	/* PCI SLOT		*/
+			char  *pcislotstr; /* PCI SLOT in string */
+			char  nport;	/* Number of Ports	*/
+			char  *id;	/* tty id		*/
+			int   start;	/* start of tty counting */
+			char  *method;  /* Install method       */
+			char  v_type;
+			char  v_port;
+			char  v_addr;
+			char  v_pcibus;
+			char  v_pcislot;
+			char  v_nport;
+			char  v_id;
+			char  v_start;
+			char  v_method;
+			char  line1;
+			char  line2;
+			char  conc1;   /* total concs in line1 */
+			char  conc2;   /* total concs in line2 */
+			char  module1; /* total modules for line1 */
+			char  module2; /* total modules for line2 */
+			char  *status; /* config status */
+			char  *dimstatus;	 /* Y/N */
+			int   status_index; /* field pointer */
+		} board;
+
+		struct {
+			char  *cable;
+			char  v_cable;
+			char  speed;
+			char  v_speed;
+		} line;
+
+		struct {
+			char  type;
+			char  *connect;
+			char  speed;
+			char  nport;
+			char  *id;
+			char  *idstr;
+			int   start;
+			char  v_type;
+			char  v_connect;
+			char  v_speed;
+			char  v_nport;
+			char  v_id;
+			char  v_start;
+		} conc;
+
+		struct {
+			char type;
+			char nport;
+			char *id;
+			char *idstr;
+			int  start;
+			char v_type;
+			char v_nport;
+			char v_id;
+			char v_start;
+		} module;
+
+		char *ttyname;
+		
+		char *cuname;
+		
+		char *printname;
+
+		int  majornumber;
+
+		int  altpin;
+
+		int  ttysize;
+
+		int  chsize;
+
+		int  bssize;
+
+		int  unsize;
+
+		int  f2size;
+
+		int  vpixsize;
+
+		int  useintr;
+	} u;
+};
+
+#endif
diff --git a/drivers/staging/dgap/dgap_downld.h b/drivers/staging/dgap/dgap_downld.h
new file mode 100644
index 0000000..f79e65c
--- /dev/null
+++ b/drivers/staging/dgap/dgap_downld.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * $Id: dgap_downld.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ */
+
+/*
+** downld.h 
+**  - describes the interface between the user level download process
+**    and the concentrator download driver.
+*/
+
+#ifndef _DGAP_DOWNLD_H_
+#define _DGAP_DOWNLD_H_
+
+
+struct fepimg {
+    int type;				/* board type */
+    int	len;				/* length of image */
+    char fepimage[1];			/* begining of image */
+};
+
+struct downldio {
+    unsigned int req_type;		/* FEP or concentrator */
+    unsigned int bdid;			/* opaque board identifier */
+    union {
+	struct downld_t dl;		/* download structure */
+	struct fepimg   fi;		/* fep/bios image structure */
+    } image;
+};
+
+#define DIGI_DLREQ_GET	(('d'<<8) | 220)
+#define DIGI_DLREQ_SET	(('d'<<8) | 221)
+
+#define DIGI_DL_NUKE    (('d'<<8) | 222) /* Not really a dl request, but
+					  dangerous enuff to not put in
+					  digi.h */
+/* Packed bits of intarg for DIGI_DL_NUKE */
+#define DIGI_NUKE_RESET_ALL	 (1 << 31)
+#define DIGI_NUKE_INHIBIT_POLLER (1 << 30)
+#define DIGI_NUKE_BRD_NUMB        0x0f
+	
+
+
+#define	DLREQ_BIOS	0
+#define	DLREQ_FEP	1
+#define	DLREQ_CONC	2
+#define	DLREQ_CONFIG	3
+#define DLREQ_DEVCREATE 4
+
+#endif
diff --git a/drivers/staging/dgap/dgap_driver.c b/drivers/staging/dgap/dgap_driver.c
new file mode 100644
index 0000000..724a685
--- /dev/null
+++ b/drivers/staging/dgap/dgap_driver.c
@@ -0,0 +1,1048 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ * $Id: dgap_driver.c,v 1.3 2011/06/21 10:35:16 markh Exp $
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>	/* For udelay */
+#include <linux/slab.h>
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#include <linux/sched.h>
+#endif
+
+#include "dgap_driver.h"
+#include "dgap_pci.h"
+#include "dgap_fep5.h"
+#include "dgap_tty.h"
+#include "dgap_conf.h"
+#include "dgap_parse.h"
+#include "dgap_trace.h"
+#include "dgap_sysfs.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line");
+MODULE_SUPPORTED_DEVICE("dgap");
+
+/*
+ * insmod command line overrideable parameters
+ *
+ * NOTE: we use a set of macros to create the variables, which allows
+ * us to specify the variable type, name, initial value, and description.
+ */
+PARM_INT(debug,		0x00,		0644,	"Driver debugging level");
+PARM_INT(rawreadok,	1,		0644,	"Bypass flip buffers on input");
+PARM_INT(trcbuf_size,	0x100000,	0644,	"Debugging trace buffer size.");
+
+
+/**************************************************************************
+ *
+ * protos for this file
+ *
+ */
+
+static int		dgap_start(void);
+static void		dgap_init_globals(void);
+static int		dgap_found_board(struct pci_dev *pdev, int id);
+static void		dgap_cleanup_board(struct board_t *brd);
+static void		dgap_poll_handler(ulong dummy);
+static int		dgap_init_pci(void);
+static int		dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void		dgap_remove_one(struct pci_dev *dev);
+static int		dgap_probe1(struct pci_dev *pdev, int card_type);
+static void		dgap_mbuf(struct board_t *brd, const char *fmt, ...);
+static int		dgap_do_remap(struct board_t *brd);
+static irqreturn_t	dgap_intr(int irq, void *voidbrd);
+
+/* Driver load/unload functions */
+int			dgap_init_module(void);
+void			dgap_cleanup_module(void);
+
+module_init(dgap_init_module);
+module_exit(dgap_cleanup_module);
+
+
+/*
+ * File operations permitted on Control/Management major.
+ */
+static struct file_operations DgapBoardFops =
+{
+	.owner		=	THIS_MODULE,
+};
+
+
+/*
+ * Globals
+ */
+uint			dgap_NumBoards;
+struct board_t		*dgap_Board[MAXBOARDS];
+DEFINE_SPINLOCK(dgap_global_lock);
+ulong			dgap_poll_counter;
+char			*dgap_config_buf;
+int			dgap_driver_state = DRIVER_INITIALIZED;
+DEFINE_SPINLOCK(dgap_dl_lock);
+wait_queue_head_t	dgap_dl_wait;
+int			dgap_dl_action;
+int			dgap_poll_tick = 20;	/* Poll interval - 20 ms */
+
+/*
+ * Static vars.
+ */
+static int		dgap_Major_Control_Registered = FALSE;
+static uint		dgap_driver_start = FALSE;
+
+static struct class *	dgap_class;
+
+/*
+ * Poller stuff
+ */
+static 			DEFINE_SPINLOCK(dgap_poll_lock);	/* Poll scheduling lock */
+static ulong		dgap_poll_time;				/* Time of next poll */
+static uint		dgap_poll_stop;				/* Used to tell poller to stop */
+static struct timer_list dgap_poll_timer;
+
+
+static struct pci_device_id dgap_pci_tbl[] = {
+	{       DIGI_VID, PCI_DEVICE_XEM_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	0 },
+	{       DIGI_VID, PCI_DEVICE_CX_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,   1 },
+	{       DIGI_VID, PCI_DEVICE_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	2 },
+	{       DIGI_VID, PCI_DEVICE_EPCJ_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	3 },
+	{       DIGI_VID, PCI_DEVICE_920_2_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	4 },
+	{       DIGI_VID, PCI_DEVICE_920_4_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	5 },
+	{       DIGI_VID, PCI_DEVICE_920_8_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	6 },
+	{       DIGI_VID, PCI_DEVICE_XR_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	7 },
+	{       DIGI_VID, PCI_DEVICE_XRJ_DID,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,	8 },
+	{       DIGI_VID, PCI_DEVICE_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	9 },
+	{       DIGI_VID, PCI_DEVICE_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	10 },
+	{       DIGI_VID, PCI_DEVICE_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	11 },
+	{       DIGI_VID, PCI_DEVICE_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	12 },
+	{       DIGI_VID, PCI_DEVICE_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
+	{       DIGI_VID, PCI_DEVICE_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	14 },
+	{0,}					/* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, dgap_pci_tbl);
+
+
+/*
+ * A generic list of Product names, PCI Vendor ID, and PCI Device ID.
+ */
+struct board_id {
+	uint config_type;
+	uchar *name;
+	uint maxports;
+	uint dpatype;
+};
+
+static struct board_id dgap_Ids[] =
+{
+	{	PPCM,		PCI_DEVICE_XEM_NAME,	64,	(T_PCXM | T_PCLITE | T_PCIBUS)	},
+	{	PCX,		PCI_DEVICE_CX_NAME,	128,	(T_CX | T_PCIBUS)		},
+	{	PCX,		PCI_DEVICE_CX_IBM_NAME,	128,	(T_CX | T_PCIBUS)		},
+	{	PEPC,		PCI_DEVICE_EPCJ_NAME,	224,	(T_EPC  | T_PCIBUS)		},
+	{	APORT2_920P,	PCI_DEVICE_920_2_NAME,	2,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	APORT4_920P,	PCI_DEVICE_920_4_NAME,	4,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	APORT8_920P,	PCI_DEVICE_920_8_NAME,	8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PAPORT8,	PCI_DEVICE_XR_NAME,	8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PAPORT8,	PCI_DEVICE_XRJ_NAME,	8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PAPORT8,	PCI_DEVICE_XR_422_NAME,	8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PAPORT8,	PCI_DEVICE_XR_IBM_NAME,	8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PAPORT8,	PCI_DEVICE_XR_SAIP_NAME, 8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PAPORT8,	PCI_DEVICE_XR_BULL_NAME, 8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	APORT8_920P,	PCI_DEVICE_920_8_HP_NAME, 8,	(T_PCXR | T_PCLITE | T_PCIBUS)	},
+	{	PPCM,		PCI_DEVICE_XEM_HP_NAME,	64,	(T_PCXM | T_PCLITE | T_PCIBUS)	},
+	{0,}						/* 0 terminated list. */
+};
+
+static struct pci_driver dgap_driver = {
+	.name		= "dgap",
+	.probe		= dgap_init_one,
+	.id_table	= dgap_pci_tbl,
+	.remove		= dgap_remove_one,
+};
+
+
+char *dgap_state_text[] = {
+	"Board Failed",
+	"Configuration for board not found.\n\t\t\tRun mpi to configure board.",
+	"Board Found",
+	"Need Reset",
+	"Finished Reset",
+	"Need Config",
+	"Finished Config",
+	"Need Device Creation",
+	"Requested Device Creation",
+	"Finished Device Creation",
+	"Need BIOS Load", 
+	"Requested BIOS", 
+	"Doing BIOS Load",
+	"Finished BIOS Load",
+	"Need FEP Load", 
+	"Requested FEP",
+	"Doing FEP Load",
+	"Finished FEP Load",
+	"Requested PROC creation",
+	"Finished PROC creation",
+	"Board READY",
+};
+
+char *dgap_driver_state_text[] = {
+	"Driver Initialized",
+	"Driver needs configuration load.",
+	"Driver requested configuration from download daemon.",
+	"Driver Ready."
+};
+
+
+
+/************************************************************************
+ *
+ * Driver load/unload functions
+ *
+ ************************************************************************/
+
+/*
+ * init_module()
+ *
+ * Module load.  This is where it all starts.
+ */
+int dgap_init_module(void)
+{
+	int rc = 0;
+
+	APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART));
+
+	/*
+	 * Initialize global stuff
+	 */
+	rc = dgap_start();
+
+	if (rc < 0) {
+		return(rc);
+	}
+
+	/*
+	 * Find and configure all the cards
+	 */
+	rc = dgap_init_pci();
+
+	/*
+	 * If something went wrong in the scan, bail out of driver.
+	 */
+	if (rc < 0) {
+		/* Only unregister the pci driver if it was actually registered. */
+		if (dgap_NumBoards)
+			pci_unregister_driver(&dgap_driver);
+		else
+			printk("WARNING: dgap driver load failed.  No DGAP boards found.\n");
+
+		dgap_cleanup_module();
+	}
+	else {
+		dgap_create_driver_sysfiles(&dgap_driver);
+	}
+  
+	DPR_INIT(("Finished init_module. Returning %d\n", rc));
+	return (rc);
+}
+
+
+/*
+ * Start of driver.
+ */
+static int dgap_start(void)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	if (dgap_driver_start == FALSE) {
+
+		dgap_driver_start = TRUE;
+
+	        /* make sure that the globals are init'd before we do anything else */
+	        dgap_init_globals();
+
+		dgap_NumBoards = 0;
+
+		APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
+
+		/*
+		 * Register our base character device into the kernel.
+		 * This allows the download daemon to connect to the downld device
+		 * before any of the boards are init'ed.
+		 */
+		if (!dgap_Major_Control_Registered) {
+			/*
+			 * Register management/dpa devices
+			 */
+			rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops);
+			if (rc < 0) {
+				APR(("Can't register dgap driver device (%d)\n", rc));
+				return (rc);
+			}
+
+			dgap_class = class_create(THIS_MODULE, "dgap_mgmt");
+			device_create(dgap_class, NULL,
+				MKDEV(DIGI_DGAP_MAJOR, 0),
+				NULL, "dgap_mgmt");
+			device_create(dgap_class, NULL,
+				MKDEV(DIGI_DGAP_MAJOR, 1),
+				NULL, "dgap_downld");
+			dgap_Major_Control_Registered = TRUE;
+		}
+
+		/*
+		 * Init any global tty stuff.
+		 */
+		rc = dgap_tty_preinit();
+
+		if (rc < 0) {
+			APR(("tty preinit - not enough memory (%d)\n", rc));
+			return(rc); 
+		}
+
+		/* Start the poller */
+		DGAP_LOCK(dgap_poll_lock, flags);
+		init_timer(&dgap_poll_timer);
+		dgap_poll_timer.function = dgap_poll_handler;
+		dgap_poll_timer.data = 0;
+		dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick);
+		dgap_poll_timer.expires = dgap_poll_time;
+		DGAP_UNLOCK(dgap_poll_lock, flags);
+
+		add_timer(&dgap_poll_timer);
+
+		dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
+	}
+
+	return (rc);
+}
+
+
+/*
+ * Register pci driver, and return how many boards we have.
+ */
+static int dgap_init_pci(void)
+{
+	return pci_register_driver(&dgap_driver);
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+
+	/* wake up and enable device */
+	rc = pci_enable_device(pdev);
+
+	if (rc < 0) {
+		rc = -EIO;
+	} else {  
+		rc = dgap_probe1(pdev, ent->driver_data);
+		if (rc == 0) {
+			dgap_NumBoards++;
+			DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards));
+		}
+	}
+	return rc;
+}               
+
+
+static int dgap_probe1(struct pci_dev *pdev, int card_type)
+{
+	return dgap_found_board(pdev, card_type);
+}
+         
+        
+static void dgap_remove_one(struct pci_dev *dev)
+{
+	/* Do Nothing */
+}
+
+
+/*
+ * dgap_cleanup_module()
+ *
+ * Module unload.  This is where it all ends.
+ */
+void dgap_cleanup_module(void)
+{
+	int i;
+	ulong lock_flags;
+
+	DGAP_LOCK(dgap_poll_lock, lock_flags);
+	dgap_poll_stop = 1;
+	DGAP_UNLOCK(dgap_poll_lock, lock_flags);
+
+	/* Turn off poller right away. */
+	del_timer_sync( &dgap_poll_timer);
+
+	dgap_remove_driver_sysfiles(&dgap_driver);
+
+
+	if (dgap_Major_Control_Registered) {
+		device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0));
+		device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 1));
+		class_destroy(dgap_class);
+		unregister_chrdev(DIGI_DGAP_MAJOR, "dgap");
+	}
+
+	if (dgap_config_buf)
+		kfree(dgap_config_buf);
+
+	for (i = 0; i < dgap_NumBoards; ++i) {
+		dgap_remove_ports_sysfiles(dgap_Board[i]);
+		dgap_tty_uninit(dgap_Board[i]);
+		dgap_cleanup_board(dgap_Board[i]);
+	}
+
+	dgap_tty_post_uninit();
+
+#if defined(DGAP_TRACER)
+	/* last thing, make sure we release the tracebuffer */
+	dgap_tracer_free();
+#endif
+	if (dgap_NumBoards)
+		pci_unregister_driver(&dgap_driver);
+}
+
+
+/*
+ * dgap_cleanup_board()
+ *
+ * Free all the memory associated with a board
+ */
+static void dgap_cleanup_board(struct board_t *brd)
+{
+	int i = 0;
+
+        if(!brd || brd->magic != DGAP_BOARD_MAGIC)
+                return;
+
+	if (brd->intr_used && brd->irq)
+		free_irq(brd->irq, brd);
+
+	tasklet_kill(&brd->helper_tasklet);
+
+	if (brd->re_map_port) {
+		release_mem_region(brd->membase + 0x200000, 0x200000);
+		iounmap(brd->re_map_port);
+		brd->re_map_port = NULL;
+	}
+
+	if (brd->re_map_membase) {
+		release_mem_region(brd->membase, 0x200000);
+		iounmap(brd->re_map_membase);
+		brd->re_map_membase = NULL;
+	}
+
+        if (brd->msgbuf_head) {
+                unsigned long flags;
+
+                DGAP_LOCK(dgap_global_lock, flags);
+                brd->msgbuf = NULL;
+                printk(brd->msgbuf_head);
+                kfree(brd->msgbuf_head);
+                brd->msgbuf_head = NULL;
+                DGAP_UNLOCK(dgap_global_lock, flags);
+        }
+
+	/* Free all allocated channels structs */
+	for (i = 0; i < MAXPORTS ; i++) {
+		if (brd->channels[i]) {
+			kfree(brd->channels[i]);
+			brd->channels[i] = NULL;
+		}
+	}
+
+	if (brd->flipbuf)
+		kfree(brd->flipbuf);
+	if (brd->flipflagbuf)
+		kfree(brd->flipflagbuf);
+
+	dgap_Board[brd->boardnum] = NULL;
+
+        kfree(brd);
+}
+
+
+/*
+ * dgap_found_board()
+ *
+ * A board has been found, init it.
+ */
+static int dgap_found_board(struct pci_dev *pdev, int id)
+{
+	struct board_t *brd;
+	unsigned int pci_irq;
+	int i = 0;
+	unsigned long flags;
+
+	/* get the board structure and prep it */
+	brd = dgap_Board[dgap_NumBoards] =
+	(struct board_t *) dgap_driver_kzmalloc(sizeof(struct board_t), GFP_KERNEL);
+	if (!brd) {
+		APR(("memory allocation for board structure failed\n"));
+		return(-ENOMEM);
+	}
+
+	/* make a temporary message buffer for the boot messages */
+	brd->msgbuf = brd->msgbuf_head =
+		(char *) dgap_driver_kzmalloc(sizeof(char) * 8192, GFP_KERNEL);
+	if(!brd->msgbuf) {
+		kfree(brd);
+		APR(("memory allocation for board msgbuf failed\n"));
+		return(-ENOMEM);
+	}
+
+	/* store the info for the board we've found */
+	brd->magic = DGAP_BOARD_MAGIC;
+	brd->boardnum = dgap_NumBoards;
+	brd->firstminor = 0;
+	brd->vendor = dgap_pci_tbl[id].vendor;
+	brd->device = dgap_pci_tbl[id].device;
+	brd->pdev = pdev;
+	brd->pci_bus = pdev->bus->number;
+	brd->pci_slot = PCI_SLOT(pdev->devfn);
+	brd->name = dgap_Ids[id].name;
+	brd->maxports = dgap_Ids[id].maxports;
+	brd->type = dgap_Ids[id].config_type;
+	brd->dpatype = dgap_Ids[id].dpatype;
+	brd->dpastatus = BD_NOFEP;
+	init_waitqueue_head(&brd->state_wait);
+
+	DGAP_SPINLOCK_INIT(brd->bd_lock);
+
+	brd->state		= BOARD_FOUND;
+	brd->runwait		= 0;
+	brd->inhibit_poller	= FALSE;
+	brd->wait_for_bios	= 0;
+	brd->wait_for_fep	= 0;
+
+	for (i = 0; i < MAXPORTS; i++) {
+		brd->channels[i] = NULL;
+	}
+
+	/* store which card & revision we have */
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+	pci_irq = pdev->irq;
+	brd->irq = pci_irq;
+
+	/* get the PCI Base Address Registers */
+
+	/* Xr Jupiter and EPC use BAR 2 */
+	if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) {
+		brd->membase     = pci_resource_start(pdev, 2);
+		brd->membase_end = pci_resource_end(pdev, 2);
+	}
+	/* Everyone else uses BAR 0 */
+	else {
+		brd->membase     = pci_resource_start(pdev, 0);
+		brd->membase_end = pci_resource_end(pdev, 0);
+	}
+
+	if (!brd->membase) {
+		APR(("card has no PCI IO resources, failing board.\n"));
+		return -ENODEV;
+	}
+
+	if (brd->membase & 1)
+		brd->membase &= ~3;
+	else
+		brd->membase &= ~15;
+
+	/*
+	 * On the PCI boards, there is no IO space allocated
+	 * The I/O registers will be in the first 3 bytes of the
+	 * upper 2MB of the 4MB memory space.  The board memory
+	 * will be mapped into the low 2MB of the 4MB memory space
+	 */
+	brd->port = brd->membase + PCI_IO_OFFSET;
+	brd->port_end = brd->port + PCI_IO_SIZE;
+
+
+	/*
+	 * Special initialization for non-PLX boards
+	 */
+	if (brd->device != PCI_DEVICE_XRJ_DID && brd->device != PCI_DEVICE_EPCJ_DID) {
+		unsigned short cmd;
+
+		pci_write_config_byte(pdev, 0x40, 0);
+		pci_write_config_byte(pdev, 0x46, 0);
+
+		/* Limit burst length to 2 doubleword transactions */ 
+		pci_write_config_byte(pdev, 0x42, 1);
+
+		/*
+		 * Enable IO and mem if not already done.
+		 * This was needed for support on Itanium.
+		 */
+		pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+		pci_write_config_word(pdev, PCI_COMMAND, cmd);
+	}
+
+	/* init our poll helper tasklet */
+	tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, (unsigned long) brd);
+
+	 /* Log the information about the board */
+	dgap_mbuf(brd, DRVSTR": board %d: %s (rev %d), irq %d\n",
+		dgap_NumBoards, brd->name, brd->rev, brd->irq);
+
+	DPR_INIT(("dgap_scan(%d) - printing out the msgbuf\n", i));
+	DGAP_LOCK(dgap_global_lock, flags);
+	brd->msgbuf = NULL;
+	printk(brd->msgbuf_head);
+	kfree(brd->msgbuf_head);
+	brd->msgbuf_head = NULL;
+	DGAP_UNLOCK(dgap_global_lock, flags);
+
+	i = dgap_do_remap(brd);
+	if (i)
+		brd->state = BOARD_FAILED;
+	else
+		brd->state = NEED_RESET;
+
+        return(0);
+}
+
+
+int dgap_finalize_board_init(struct board_t *brd) {
+
+        int rc;
+
+        DPR_INIT(("dgap_finalize_board_init() - start\n"));
+
+	if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+                return(-ENODEV);
+
+        DPR_INIT(("dgap_finalize_board_init() - start #2\n"));
+
+	brd->use_interrupts = dgap_config_get_useintr(brd);
+
+	/*
+	 * Set up our interrupt handler if we are set to do interrupts.
+	 */
+	if (brd->use_interrupts && brd->irq) {
+
+		rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd);
+
+		if (rc) {
+			dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n",
+                                  brd->irq);
+			brd->intr_used = 0;
+		}
+		else
+			brd->intr_used = 1;
+	} else {
+		brd->intr_used = 0;
+	}
+
+	return(0);
+}
+
+
+/*
+ * Remap PCI memory.
+ */
+static int dgap_do_remap(struct board_t *brd)
+{
+	if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+		return -ENXIO;
+
+	if (!request_mem_region(brd->membase, 0x200000, "dgap")) {
+		APR(("dgap: mem_region %lx already in use.\n", brd->membase));
+		return -ENOMEM;
+        }
+
+	if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, "dgap")) {
+		APR(("dgap: mem_region IO %lx already in use.\n",
+			brd->membase + PCI_IO_OFFSET));
+		release_mem_region(brd->membase, 0x200000);
+		return -ENOMEM;
+        }
+
+	brd->re_map_membase = ioremap(brd->membase, 0x200000);
+	if (!brd->re_map_membase) {
+		APR(("dgap: ioremap mem %lx cannot be mapped.\n", brd->membase));
+		release_mem_region(brd->membase, 0x200000);
+		release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+		return -ENOMEM;
+	}
+
+	brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
+	if (!brd->re_map_port) {
+		release_mem_region(brd->membase, 0x200000);
+		release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+		iounmap(brd->re_map_membase);
+		APR(("dgap: ioremap IO mem %lx cannot be mapped.\n",
+			brd->membase + PCI_IO_OFFSET));
+		return -ENOMEM;
+	}
+
+	DPR_INIT(("remapped io: 0x%p  remapped mem: 0x%p\n",
+		brd->re_map_port, brd->re_map_membase));
+	return 0;
+}
+
+
+/*****************************************************************************
+*
+* Function:
+*                                       
+*    dgap_poll_handler
+*
+* Author:
+*
+*    Scott H Kilau
+*       
+* Parameters:
+*
+*    dummy -- ignored                    
+*
+* Return Values:
+*
+*    none
+*
+* Description:   
+*                                       
+*    As each timer expires, it determines (a) whether the "transmit"
+*    waiter needs to be woken up, and (b) whether the poller needs to
+*    be rescheduled.
+*
+******************************************************************************/
+
+static void dgap_poll_handler(ulong dummy)
+{
+	int i;
+        struct board_t *brd;
+        unsigned long lock_flags;
+        unsigned long lock_flags2;
+	ulong new_time;
+
+	dgap_poll_counter++;
+
+
+	/*
+	 * If driver needs the config file still,
+	 * keep trying to wake up the downloader to
+	 * send us the file.
+	 */
+        if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) {
+		/*
+		 * Signal downloader, its got some work to do.
+		 */
+		DGAP_LOCK(dgap_dl_lock, lock_flags2);
+		if (dgap_dl_action != 1) {
+			dgap_dl_action = 1;
+			wake_up_interruptible(&dgap_dl_wait);
+		}
+		DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+		goto schedule_poller;
+        }
+	/*
+	 * Do not start the board state machine until
+	 * driver tells us its up and running, and has
+	 * everything it needs.
+	 */
+	else if (dgap_driver_state != DRIVER_READY) {
+		goto schedule_poller;
+	}
+
+	/*
+	 * If we have just 1 board, or the system is not SMP,
+	 * then use the typical old style poller.
+	 * Otherwise, use our new tasklet based poller, which should
+	 * speed things up for multiple boards.
+	 */
+	if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) {
+		for (i = 0; i < dgap_NumBoards; i++) {
+
+			brd = dgap_Board[i];
+
+			if (brd->state == BOARD_FAILED) {
+				continue;
+			}
+			if (!brd->intr_running) {
+				/* Call the real board poller directly */
+				dgap_poll_tasklet((unsigned long) brd);
+			}
+		}
+	}
+	else {
+		/* Go thru each board, kicking off a tasklet for each if needed */
+		for (i = 0; i < dgap_NumBoards; i++) {
+			brd = dgap_Board[i];
+
+			/*
+			 * Attempt to grab the board lock.
+			 *
+			 * If we can't get it, no big deal, the next poll will get it.
+			 * Basically, I just really don't want to spin in here, because I want
+			 * to kick off my tasklets as fast as I can, and then get out the poller.
+			 */
+			if (!spin_trylock(&brd->bd_lock)) {
+				continue;
+			}
+
+			/* If board is in a failed state, don't bother scheduling a tasklet */
+			if (brd->state == BOARD_FAILED) {
+				spin_unlock(&brd->bd_lock);
+				continue;
+			}
+
+			/* Schedule a poll helper task */
+			if (!brd->intr_running) {
+				tasklet_schedule(&brd->helper_tasklet);
+			}
+
+			/*
+			 * Can't do DGAP_UNLOCK here, as we don't have
+			 * lock_flags because we did a trylock above.
+			 */
+			spin_unlock(&brd->bd_lock);
+		}
+	}
+
+schedule_poller:
+
+	/*
+	 * Schedule ourself back at the nominal wakeup interval.
+	 */
+	DGAP_LOCK(dgap_poll_lock, lock_flags );
+	dgap_poll_time +=  dgap_jiffies_from_ms(dgap_poll_tick);
+
+	new_time = dgap_poll_time - jiffies;
+
+	if ((ulong) new_time >= 2 * dgap_poll_tick) {
+		dgap_poll_time = jiffies +  dgap_jiffies_from_ms(dgap_poll_tick);
+	}
+
+	dgap_poll_timer.function = dgap_poll_handler;
+	dgap_poll_timer.data = 0;
+	dgap_poll_timer.expires = dgap_poll_time;
+	DGAP_UNLOCK(dgap_poll_lock, lock_flags );
+
+	if (!dgap_poll_stop)
+		add_timer(&dgap_poll_timer);
+}
+
+
+
+
+/*
+ * dgap_intr()
+ *
+ * Driver interrupt handler.
+ */
+static irqreturn_t dgap_intr(int irq, void *voidbrd)
+{
+	struct board_t *brd = (struct board_t *) voidbrd;
+
+	if (!brd) {
+		APR(("Received interrupt (%d) with null board associated\n", irq));
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Check to make sure its for us.
+	 */
+	if (brd->magic != DGAP_BOARD_MAGIC) {
+		APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
+		return IRQ_NONE;
+	}
+
+	brd->intr_count++;
+
+	/*
+	 * Schedule tasklet to run at a better time.
+	 */
+	tasklet_schedule(&brd->helper_tasklet);
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * dgap_init_globals()
+ *
+ * This is where we initialize the globals from the static insmod
+ * configuration variables.  These are declared near the head of
+ * this file.
+ */
+static void dgap_init_globals(void)
+{
+	int i = 0;
+
+	dgap_rawreadok		= rawreadok;
+        dgap_trcbuf_size	= trcbuf_size;
+	dgap_debug		= debug;
+
+	for (i = 0; i < MAXBOARDS; i++) {
+		dgap_Board[i] = NULL;
+	}
+
+	init_timer( &dgap_poll_timer ); 
+
+	init_waitqueue_head(&dgap_dl_wait);
+	dgap_dl_action = 0;
+}
+
+
+/************************************************************************
+ *
+ * Utility functions
+ *
+ ************************************************************************/
+
+
+/*
+ * dgap_driver_kzmalloc()
+ *
+ * Malloc and clear memory,
+ */
+void *dgap_driver_kzmalloc(size_t size, int priority)
+{
+ 	void *p = kmalloc(size, priority);
+	if(p)
+		memset(p, 0, size);
+	return(p);
+}
+
+
+/*
+ * dgap_mbuf()
+ *
+ * Used to print to the message buffer during board init.
+ */
+static void dgap_mbuf(struct board_t *brd, const char *fmt, ...) {
+	va_list		ap;
+	char		buf[1024];
+	int		i;
+	unsigned long	flags;
+
+	DGAP_LOCK(dgap_global_lock, flags);
+
+	/* Format buf using fmt and arguments contained in ap. */
+	va_start(ap, fmt);
+	i = vsprintf(buf, fmt,  ap);
+	va_end(ap);
+
+	DPR((buf));
+
+	if (!brd || !brd->msgbuf) {
+		printk(buf);
+		DGAP_UNLOCK(dgap_global_lock, flags);
+		return;
+	}
+
+	memcpy(brd->msgbuf, buf, strlen(buf));
+	brd->msgbuf += strlen(buf);
+	*brd->msgbuf = 0;
+
+	DGAP_UNLOCK(dgap_global_lock, flags);
+}
+
+
+/*
+ * dgap_ms_sleep()
+ *
+ * Put the driver to sleep for x ms's
+ *
+ * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
+ */
+int dgap_ms_sleep(ulong ms)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout((ms * HZ) / 1000);
+	return (signal_pending(current));
+}
+
+
+
+/*
+ *      dgap_ioctl_name() : Returns a text version of each ioctl value.
+ */
+char *dgap_ioctl_name(int cmd)
+{
+	switch(cmd) {
+
+	case TCGETA:		return("TCGETA");
+	case TCGETS:		return("TCGETS");
+	case TCSETA:		return("TCSETA");
+	case TCSETS:		return("TCSETS");
+	case TCSETAW:		return("TCSETAW");
+	case TCSETSW:		return("TCSETSW");
+	case TCSETAF:		return("TCSETAF");
+	case TCSETSF:		return("TCSETSF");
+	case TCSBRK:		return("TCSBRK");
+	case TCXONC:		return("TCXONC");
+	case TCFLSH:		return("TCFLSH");
+	case TIOCGSID:		return("TIOCGSID");
+
+	case TIOCGETD:		return("TIOCGETD");
+	case TIOCSETD:		return("TIOCSETD");
+	case TIOCGWINSZ:	return("TIOCGWINSZ");
+	case TIOCSWINSZ:	return("TIOCSWINSZ");
+
+	case TIOCMGET:		return("TIOCMGET");
+	case TIOCMSET:		return("TIOCMSET");
+	case TIOCMBIS:		return("TIOCMBIS");
+	case TIOCMBIC:		return("TIOCMBIC");
+
+	/* from digi.h */
+	case DIGI_SETA:		return("DIGI_SETA");
+	case DIGI_SETAW:	return("DIGI_SETAW");
+	case DIGI_SETAF:	return("DIGI_SETAF");
+	case DIGI_SETFLOW:	return("DIGI_SETFLOW");
+	case DIGI_SETAFLOW:	return("DIGI_SETAFLOW");
+	case DIGI_GETFLOW:	return("DIGI_GETFLOW");
+	case DIGI_GETAFLOW:	return("DIGI_GETAFLOW");
+	case DIGI_GETA:		return("DIGI_GETA");
+	case DIGI_GEDELAY:	return("DIGI_GEDELAY");
+	case DIGI_SEDELAY:	return("DIGI_SEDELAY");
+	case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD");
+	case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD");
+	case TIOCMODG:		return("TIOCMODG");
+	case TIOCMODS:		return("TIOCMODS");
+	case TIOCSDTR:		return("TIOCSDTR");
+	case TIOCCDTR:		return("TIOCCDTR");
+
+	default:		return("unknown");
+	}
+}
diff --git a/drivers/staging/dgap/dgap_driver.h b/drivers/staging/dgap/dgap_driver.h
new file mode 100644
index 0000000..b1cf489
--- /dev/null
+++ b/drivers/staging/dgap/dgap_driver.h
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * Driver includes
+ *
+ *************************************************************************/
+
+#ifndef __DGAP_DRIVER_H
+#define __DGAP_DRIVER_H
+
+#include <linux/version.h>	/* To get the current Linux version */
+#include <linux/types.h>        /* To pick up the varions Linux types */
+#include <linux/tty.h>          /* To pick up the various tty structs/defines */
+#include <linux/interrupt.h>    /* For irqreturn_t type */
+
+#include "dgap_types.h"         /* Additional types needed by the Digi header files */
+#include "digi.h"               /* Digi specific ioctl header */
+#include "dgap_kcompat.h"       /* Kernel 2.4/2.6 compat includes */
+#include "dgap_sysfs.h"		/* Support for SYSFS */
+
+/*************************************************************************
+ *
+ * Driver defines
+ *
+ *************************************************************************/
+
+/*
+ * Driver identification, error and debugging statments
+ *
+ * In theory, you can change all occurances of "digi" in the next
+ * three lines, and the driver printk's will all automagically change.
+ *
+ * APR((fmt, args, ...));	Always prints message
+ * DPR((fmt, args, ...));	Only prints if DGAP_TRACER is defined at
+ *				  compile time and dgap_debug!=0
+ */
+#define	PROCSTR		"dgap"			/* /proc entries	 */
+#define	DEVSTR		"/dev/dg/dgap"		/* /dev entries		 */
+#define	DRVSTR		"dgap"			/* Driver name string 
+						 * displayed by APR	 */
+#define	APR(args)	do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \
+			   } while (0)
+#define	RAPR(args)	do { PRINTF_TO_KMEM(args); printk args; } while (0)
+
+#define TRC_TO_CONSOLE 1
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+
+#define	DBG_INIT		(dgap_debug & 0x01)
+#define	DBG_BASIC		(dgap_debug & 0x02)
+#define	DBG_CORE		(dgap_debug & 0x04)
+
+#define	DBG_OPEN		(dgap_debug & 0x08)
+#define	DBG_CLOSE		(dgap_debug & 0x10)
+#define	DBG_READ		(dgap_debug & 0x20)
+#define	DBG_WRITE		(dgap_debug & 0x40)
+
+#define	DBG_IOCTL		(dgap_debug & 0x80)
+
+#define	DBG_PROC		(dgap_debug & 0x100)
+#define	DBG_PARAM		(dgap_debug & 0x200)
+#define	DBG_PSCAN		(dgap_debug & 0x400)
+#define	DBG_EVENT		(dgap_debug & 0x800)
+
+#define	DBG_DRAIN		(dgap_debug & 0x1000)
+#define	DBG_CARR		(dgap_debug & 0x2000)
+
+#define	DBG_MGMT		(dgap_debug & 0x4000)
+
+
+#if defined(DGAP_TRACER)
+
+# if defined(TRC_TO_KMEM)
+/* Choose one: */
+#  define TRC_ON_OVERFLOW_WRAP_AROUND
+#  undef  TRC_ON_OVERFLOW_SHIFT_BUFFER
+# endif //TRC_TO_KMEM
+
+# define TRC_MAXMSG		1024
+# define TRC_OVERFLOW		"(OVERFLOW)"
+# define TRC_DTRC		"/usr/bin/dtrc"
+
+#if defined TRC_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; }
+#else //!defined TRACE_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args)
+#endif
+
+#if defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args) dgap_tracef args 
+#else //!defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args)
+#endif
+
+#define	TRC(args)	{ PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) }
+
+# define DPR_INIT(ARGS)		if (DBG_INIT) TRC(ARGS)
+# define DPR_BASIC(ARGS)	if (DBG_BASIC) TRC(ARGS)
+# define DPR_CORE(ARGS)		if (DBG_CORE) TRC(ARGS)
+# define DPR_OPEN(ARGS)		if (DBG_OPEN)  TRC(ARGS)
+# define DPR_CLOSE(ARGS)	if (DBG_CLOSE)  TRC(ARGS)
+# define DPR_READ(ARGS)		if (DBG_READ)  TRC(ARGS)
+# define DPR_WRITE(ARGS)	if (DBG_WRITE) TRC(ARGS)
+# define DPR_IOCTL(ARGS)	if (DBG_IOCTL) TRC(ARGS)
+# define DPR_PROC(ARGS)		if (DBG_PROC)  TRC(ARGS)
+# define DPR_PARAM(ARGS)	if (DBG_PARAM)  TRC(ARGS)
+# define DPR_PSCAN(ARGS)	if (DBG_PSCAN)  TRC(ARGS)
+# define DPR_EVENT(ARGS)	if (DBG_EVENT)  TRC(ARGS)
+# define DPR_DRAIN(ARGS)	if (DBG_DRAIN)  TRC(ARGS)
+# define DPR_CARR(ARGS)		if (DBG_CARR)  TRC(ARGS)
+# define DPR_MGMT(ARGS)		if (DBG_MGMT)  TRC(ARGS)
+
+# define DPR(ARGS)		if (dgap_debug) TRC(ARGS)
+# define P(X)			dgap_tracef(#X "=%p\n", X)
+# define X(X)			dgap_tracef(#X "=%x\n", X)
+
+#else//!defined DGAP_TRACER
+
+#define PRINTF_TO_KMEM(args)
+# define TRC(ARGS)
+# define DPR_INIT(ARGS)
+# define DPR_BASIC(ARGS)
+# define DPR_CORE(ARGS)
+# define DPR_OPEN(ARGS)
+# define DPR_CLOSE(ARGS)
+# define DPR_READ(ARGS)
+# define DPR_WRITE(ARGS)
+# define DPR_IOCTL(ARGS)
+# define DPR_PROC(ARGS)
+# define DPR_PARAM(ARGS)
+# define DPR_PSCAN(ARGS)
+# define DPR_EVENT(ARGS)
+# define DPR_DRAIN(ARGS)
+# define DPR_CARR(ARGS)
+# define DPR_MGMT(ARGS)
+
+# define DPR(args)
+
+#endif//DGAP_TRACER
+
+/* Number of boards we support at once. */
+#define	MAXBOARDS	32
+#define	MAXPORTS	224
+#define MAXTTYNAMELEN	200
+
+/* Our 3 magic numbers for our board, channel and unit structs */
+#define DGAP_BOARD_MAGIC	0x5c6df104
+#define DGAP_CHANNEL_MAGIC	0x6c6df104
+#define DGAP_UNIT_MAGIC		0x7c6df104
+
+/* Serial port types */
+#define DGAP_SERIAL		0
+#define DGAP_PRINT		1
+
+#define	SERIAL_TYPE_NORMAL	1
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN		((4096) + 4)
+#define MYFLIPLEN		N_TTY_BUF_SIZE
+
+#define SBREAK_TIME 0x25
+#define U2BSIZE 0x400
+
+#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000)
+
+/*
+ * Our major for the mgmt devices.
+ *
+ * We can use 22, because Digi was allocated 22 and 23 for the epca driver.
+ * 22 has now become obsolete now that the "cu" devices have 
+ * been removed from 2.6.
+ * Also, this *IS* the epca driver, just PCI only now.
+ */
+#ifndef DIGI_DGAP_MAJOR
+# define DIGI_DGAP_MAJOR         22
+#endif
+
+/*
+ * The parameters we use to define the periods of the moving averages.
+ */
+#define		MA_PERIOD	(HZ / 10)
+#define		SMA_DUR		(1 * HZ)
+#define		EMA_DUR		(1 * HZ)
+#define		SMA_NPERIODS	(SMA_DUR / MA_PERIOD)
+#define		EMA_NPERIODS	(EMA_DUR / MA_PERIOD)
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.  This is the same structure that is defined
+ * as the default in tty_io.c with the same settings overriden as in serial.c
+ *
+ * In short, this should match the internal serial ports' defaults.
+ */
+#define	DEFAULT_IFLAGS	(ICRNL | IXON)
+#define	DEFAULT_OFLAGS	(OPOST | ONLCR)
+#define	DEFAULT_CFLAGS	(B9600 | CS8 | CREAD | HUPCL | CLOCAL)
+#define	DEFAULT_LFLAGS	(ISIG | ICANON | ECHO | ECHOE | ECHOK | \
+			ECHOCTL | ECHOKE | IEXTEN)
+
+#ifndef _POSIX_VDISABLE
+#define   _POSIX_VDISABLE '\0'
+#endif
+
+#define SNIFF_MAX	65536		/* Sniff buffer size (2^n) */
+#define SNIFF_MASK	(SNIFF_MAX - 1)	/* Sniff wrap mask */
+
+#define VPDSIZE (512)
+
+/*
+ * Lock function/defines.
+ * Makes spotting lock/unlock locations easier.
+ */
+# define DGAP_SPINLOCK_INIT(x)		spin_lock_init(&(x))
+# define DGAP_LOCK(x,y)			spin_lock_irqsave(&(x), y)
+# define DGAP_UNLOCK(x,y)		spin_unlock_irqrestore(&(x), y)
+# define DGAP_TRYLOCK(x,y)		spin_trylock(&(x))
+
+/*
+ * All the possible states the driver can be while being loaded.
+ */
+enum {
+	DRIVER_INITIALIZED = 0,
+	DRIVER_NEED_CONFIG_LOAD,
+	DRIVER_REQUESTED_CONFIG,
+	DRIVER_READY
+};
+
+/*
+ * All the possible states the board can be while booting up.
+ */
+enum {
+	BOARD_FAILED = 0,
+	CONFIG_NOT_FOUND,
+	BOARD_FOUND,
+	NEED_RESET,
+	FINISHED_RESET,
+	NEED_CONFIG,
+	FINISHED_CONFIG,
+	NEED_DEVICE_CREATION,
+	REQUESTED_DEVICE_CREATION,
+	FINISHED_DEVICE_CREATION,
+	NEED_BIOS_LOAD,
+	REQUESTED_BIOS,
+	WAIT_BIOS_LOAD,
+	FINISHED_BIOS_LOAD,
+	NEED_FEP_LOAD,
+	REQUESTED_FEP,
+	WAIT_FEP_LOAD,
+	FINISHED_FEP_LOAD,
+	NEED_PROC_CREATION,
+	FINISHED_PROC_CREATION,
+	BOARD_READY
+};
+
+/*
+ * All the possible states that a requested concentrator image can be in.
+ */
+enum {
+	NO_PENDING_CONCENTRATOR_REQUESTS = 0,
+	NEED_CONCENTRATOR,
+	REQUESTED_CONCENTRATOR
+};
+
+extern char *dgap_state_text[];
+extern char *dgap_driver_state_text[];
+
+
+/* 
+ * Modem line constants are defined as macros because DSR and
+ * DCD are swapable using the ditty altpin option.
+ */
+#define D_CD(ch)        ch->ch_cd       /* Carrier detect       */
+#define D_DSR(ch)       ch->ch_dsr      /* Data set ready       */
+#define D_RTS(ch)       DM_RTS          /* Request to send      */
+#define D_CTS(ch)       DM_CTS          /* Clear to send        */
+#define D_RI(ch)        DM_RI           /* Ring indicator       */
+#define D_DTR(ch)       DM_DTR          /* Data terminal ready  */
+
+
+/*************************************************************************
+ *
+ * Structures and closely related defines.
+ *
+ *************************************************************************/
+
+
+/*
+ * A structure to hold a statistics counter.  We also
+ * compute moving averages for this counter.
+ */
+struct macounter
+{
+	u32		cnt;	/* Total count */
+	ulong		accum;	/* Acuumulator per period */
+	ulong		sma;	/* Simple moving average */
+	ulong		ema;	/* Exponential moving average */
+};
+
+
+/************************************************************************ 
+ * Device flag definitions for bd_flags.
+ ************************************************************************/
+#define	BD_FEP5PLUS	0x0001          /* Supports FEP5 Plus commands */
+#define BD_HAS_VPD	0x0002		/* Board has VPD info available */
+
+
+/*
+ *	Per-board information
+ */
+struct board_t
+{
+	int		magic;		/* Board Magic number.  */
+	int		boardnum;	/* Board number: 0-3 */
+	int		firstminor;	/* First minor, e.g. 0, 30, 60 */
+
+	int		type;		/* Type of board */
+	char		*name;		/* Product Name */
+	struct pci_dev	*pdev;		/* Pointer to the pci_dev struct */ 
+	u16		vendor;		/* PCI vendor ID */
+	u16		device;		/* PCI device ID */
+	u16		subvendor;	/* PCI subsystem vendor ID */
+	u16		subdevice;	/* PCI subsystem device ID */
+	uchar		rev;		/* PCI revision ID */
+	uint		pci_bus;	/* PCI bus value */
+	uint		pci_slot;	/* PCI slot value */
+	u16		maxports;	/* MAX ports this board can handle */
+	uchar		vpd[VPDSIZE];	/* VPD of board, if found */
+	u32		bd_flags;	/* Board flags */
+
+	spinlock_t	bd_lock;	/* Used to protect board */
+
+	u32		state;		/* State of card. */
+	wait_queue_head_t state_wait;	/* Place to sleep on for state change */
+
+	struct		tasklet_struct helper_tasklet; /* Poll helper tasklet */
+
+	u32		wait_for_bios;
+	u32		wait_for_fep;
+
+	struct cnode *  bd_config;	/* Config of board */
+
+	u16		nasync;		/* Number of ports on card */
+
+	u32		use_interrupts;	/* Should we be interrupt driven? */
+	ulong		irq;		/* Interrupt request number */
+	ulong		intr_count;	/* Count of interrupts */
+	u32		intr_used;	/* Non-zero if using interrupts */
+	u32		intr_running;	/* Non-zero if FEP knows its doing interrupts */
+
+	ulong		port;		/* Start of base io port of the card */
+	ulong		port_end;	/* End of base io port of the card */
+	ulong		membase;	/* Start of base memory of the card */
+	ulong		membase_end;	/* End of base memory of the card */
+
+	uchar 		*re_map_port;	/* Remapped io port of the card */
+	uchar		*re_map_membase;/* Remapped memory of the card */
+
+	uchar		runwait;	/* # Processes waiting for FEP  */
+	uchar		inhibit_poller; /* Tells  the poller to leave us alone */
+
+	struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */
+
+	struct tty_driver	*SerialDriver;
+	char		SerialName[200];
+	struct tty_driver	*PrintDriver;
+	char		PrintName[200];
+
+	u32		dgap_Major_Serial_Registered;
+	u32		dgap_Major_TransparentPrint_Registered;
+
+	u32		dgap_Serial_Major;
+	u32		dgap_TransparentPrint_Major;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	u32		TtyRefCnt;
+#endif
+
+	struct bs_t	*bd_bs;			/* Base structure pointer       */
+
+	char	*flipbuf;		/* Our flip buffer, alloced if board is found */
+	char	*flipflagbuf;		/* Our flip flag buffer, alloced if board is found */
+
+	u16		dpatype;	/* The board "type", as defined by DPA */
+	u16		dpastatus;	/* The board "status", as defined by DPA */
+	wait_queue_head_t kme_wait;	/* Needed for DPA support */
+
+	u32		conc_dl_status;	/* Status of any pending conc download */
+	/*
+	 *	Mgmt data.
+	 */
+        char		*msgbuf_head;
+        char		*msgbuf;
+};
+
+
+
+/************************************************************************ 
+ * Unit flag definitions for un_flags.
+ ************************************************************************/
+#define UN_ISOPEN	0x0001		/* Device is open		*/
+#define UN_CLOSING	0x0002		/* Line is being closed		*/
+#define UN_IMM		0x0004		/* Service immediately		*/
+#define UN_BUSY		0x0008		/* Some work this channel	*/
+#define UN_BREAKI	0x0010		/* Input break received		*/
+#define UN_PWAIT	0x0020		/* Printer waiting for terminal	*/
+#define UN_TIME		0x0040		/* Waiting on time		*/
+#define UN_EMPTY	0x0080		/* Waiting output queue empty	*/
+#define UN_LOW		0x0100		/* Waiting output low water mark*/
+#define UN_EXCL_OPEN	0x0200		/* Open for exclusive use	*/
+#define UN_WOPEN	0x0400		/* Device waiting for open	*/
+#define UN_WIOCTL	0x0800		/* Device waiting for open	*/
+#define UN_HANGUP	0x8000		/* Carrier lost			*/
+
+struct device;
+
+/************************************************************************
+ * Structure for terminal or printer unit. 
+ ************************************************************************/
+struct un_t {
+	int	magic;		/* Unit Magic Number.			*/
+	struct	channel_t *un_ch;
+	u32	un_time;
+	u32	un_type;
+	u32	un_open_count;	/* Counter of opens to port		*/
+	struct tty_struct *un_tty;/* Pointer to unit tty structure	*/
+	u32	un_flags;	/* Unit flags				*/
+	wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */
+	u32	un_dev;		/* Minor device number			*/
+	tcflag_t un_oflag;	/* oflags being done on board		*/
+	tcflag_t un_lflag;	/* lflags being done on board		*/
+	struct device *un_sysfs;
+};
+
+
+/************************************************************************ 
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON         0x0001          /* Printer on string                */
+#define CH_OUT          0x0002          /* Dial-out device open             */
+#define CH_STOP         0x0004          /* Output is stopped                */
+#define CH_STOPI        0x0008          /* Input is stopped                 */
+#define CH_CD           0x0010          /* Carrier is present               */
+#define CH_FCAR         0x0020          /* Carrier forced on                */
+
+#define CH_RXBLOCK      0x0080          /* Enable rx blocked flag           */
+#define CH_WLOW         0x0100          /* Term waiting low event           */
+#define CH_WEMPTY       0x0200          /* Term waiting empty event         */
+#define CH_RENABLE      0x0400          /* Buffer just emptied          */
+#define CH_RACTIVE      0x0800          /* Process active in xxread()   */
+#define CH_RWAIT        0x1000          /* Process waiting in xxread()  */
+#define CH_BAUD0	0x2000		/* Used for checking B0 transitions */
+#define CH_HANGUP       0x8000		/* Hangup received                  */
+
+/*
+ * Definitions for ch_sniff_flags
+ */
+#define SNIFF_OPEN	0x1
+#define SNIFF_WAIT_DATA	0x2
+#define SNIFF_WAIT_SPACE 0x4
+
+
+/************************************************************************ 
+ * Channel information structure.
+ ************************************************************************/
+struct channel_t {
+	int magic;			/* Channel Magic Number		*/
+	struct bs_t	*ch_bs;		/* Base structure pointer       */
+	struct cm_t	*ch_cm;		/* Command queue pointer        */
+	struct board_t *ch_bd;		/* Board structure pointer      */
+	unsigned char *ch_vaddr;	/* FEP memory origin            */
+	unsigned char *ch_taddr;	/* Write buffer origin          */
+	unsigned char *ch_raddr;	/* Read buffer origin           */
+	struct digi_t  ch_digi;		/* Transparent Print structure  */
+	struct un_t ch_tun;		/* Terminal unit info           */
+	struct un_t ch_pun;		/* Printer unit info            */
+
+	spinlock_t	ch_lock;	/* provide for serialization */
+	wait_queue_head_t ch_flags_wait;
+
+	u32	pscan_state;
+	uchar	pscan_savechar;
+
+	u32 ch_portnum;			/* Port number, 0 offset.	*/
+	u32 ch_open_count;		/* open count			*/
+	u32	ch_flags;		/* Channel flags                */
+
+
+	u32	ch_close_delay;		/* How long we should drop RTS/DTR for */
+
+	u32	ch_cpstime;		/* Time for CPS calculations    */
+
+	tcflag_t ch_c_iflag;		/* channel iflags               */
+	tcflag_t ch_c_cflag;		/* channel cflags               */
+	tcflag_t ch_c_oflag;		/* channel oflags               */
+	tcflag_t ch_c_lflag;		/* channel lflags               */
+
+	u16  ch_fepiflag;            /* FEP tty iflags               */
+	u16  ch_fepcflag;		/* FEP tty cflags               */
+	u16  ch_fepoflag;		/* FEP tty oflags               */
+	u16  ch_wopen;			/* Waiting for open process cnt */
+	u16  ch_tstart;			/* Transmit buffer start        */
+	u16  ch_tsize;			/* Transmit buffer size         */
+	u16  ch_rstart;			/* Receive buffer start         */
+	u16  ch_rsize;			/* Receive buffer size          */
+	u16  ch_rdelay;			/* Receive delay time           */
+
+	u16	ch_tlw;			/* Our currently set low water mark */
+
+	u16  ch_cook;			/* Output character mask        */
+
+	uchar   ch_card;		/* Card channel is on           */
+	uchar   ch_stopc;		/* Stop character               */
+	uchar   ch_startc;		/* Start character              */
+
+	uchar   ch_mostat;		/* FEP output modem status      */
+	uchar   ch_mistat;		/* FEP input modem status       */
+	uchar   ch_mforce;		/* Modem values to be forced    */
+	uchar   ch_mval;		/* Force values                 */
+	uchar   ch_fepstopc;		/* FEP stop character           */
+	uchar   ch_fepstartc;		/* FEP start character          */
+
+	uchar   ch_astopc;		/* Auxiliary Stop character     */
+	uchar   ch_astartc;		/* Auxiliary Start character    */
+	uchar   ch_fepastopc;		/* Auxiliary FEP stop char      */
+	uchar   ch_fepastartc;		/* Auxiliary FEP start char     */
+
+	uchar   ch_hflow;		/* FEP hardware handshake       */
+	uchar   ch_dsr;			/* stores real dsr value        */
+	uchar   ch_cd;			/* stores real cd value         */
+	uchar   ch_tx_win;		/* channel tx buffer window     */
+	uchar   ch_rx_win;		/* channel rx buffer window     */
+	uint	ch_custom_speed;	/* Custom baud, if set		*/
+	uint	ch_baud_info;		/* Current baud info for /proc output	*/
+	ulong	ch_rxcount;		/* total of data received so far	*/
+	ulong	ch_txcount;		/* total of data transmitted so far	*/
+	ulong	ch_err_parity;		/* Count of parity errors on channel	*/
+	ulong	ch_err_frame;		/* Count of framing errors on channel	*/
+	ulong	ch_err_break;		/* Count of breaks on channel	*/
+	ulong	ch_err_overrun;		/* Count of overruns on channel	*/
+
+	uint ch_sniff_in;
+	uint ch_sniff_out;
+	char *ch_sniff_buf;		/* Sniff buffer for proc */
+	ulong ch_sniff_flags;		/* Channel flags                */
+	wait_queue_head_t ch_sniff_wait;
+};
+
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+
+extern int		dgap_ms_sleep(ulong ms);
+extern void		*dgap_driver_kzmalloc(size_t size, int priority);
+extern char		*dgap_ioctl_name(int cmd);
+extern void		dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len);
+extern void		dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len);
+extern void		dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len);
+extern void		dgap_do_config_load(uchar __user *uaddr, int len);
+extern int		dgap_after_config_loaded(void);
+extern int		dgap_finalize_board_init(struct board_t *brd);
+
+/*
+ * Our Global Variables.
+ */
+extern int		dgap_driver_state;	/* The state of the driver	*/
+extern int		dgap_debug;		/* Debug variable		*/
+extern int		dgap_rawreadok;		/* Set if user wants rawreads	*/
+extern int		dgap_poll_tick;		/* Poll interval - 20 ms	*/
+extern spinlock_t	dgap_global_lock;	/* Driver global spinlock	*/
+extern uint		dgap_NumBoards;		/* Total number of boards	*/
+extern struct board_t	*dgap_Board[MAXBOARDS];	/* Array of board structs	*/
+extern ulong		dgap_poll_counter;	/* Times the poller has run	*/
+extern char		*dgap_config_buf;	/* The config file buffer	*/
+extern spinlock_t	dgap_dl_lock;		/* Downloader spinlock		*/
+extern wait_queue_head_t dgap_dl_wait;		/* Wait queue for downloader	*/
+extern int		dgap_dl_action;		/* Action flag for downloader	*/
+extern int		dgap_registerttyswithsysfs; /* Should we register the	*/
+						    /* ttys with sysfs or not	*/
+
+/*
+ * Global functions declared in dgap_fep5.c, but must be hidden from
+ * user space programs.
+ */
+extern void	dgap_poll_tasklet(unsigned long data); 
+extern void	dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds);
+extern void	dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds);
+extern void	dgap_wmove(struct channel_t *ch, char *buf, uint cnt);
+extern int	dgap_param(struct tty_struct *tty);
+extern void	dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len);
+extern uint	dgap_get_custom_baud(struct channel_t *ch);
+extern void	dgap_firmware_reset_port(struct channel_t *ch);
+
+#endif
diff --git a/drivers/staging/dgap/dgap_fep5.c b/drivers/staging/dgap/dgap_fep5.c
new file mode 100644
index 0000000..4464f02
--- /dev/null
+++ b/drivers/staging/dgap/dgap_fep5.c
@@ -0,0 +1,1953 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ * $Id: dgap_fep5.c,v 1.2 2011/06/21 10:35:40 markh Exp $
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>	/* For udelay */
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+#include <linux/tty.h>
+#include <linux/tty_flip.h>	/* For tty_schedule_flip */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#include <linux/sched.h>
+#endif
+
+#include "dgap_driver.h"
+#include "dgap_pci.h"
+#include "dgap_fep5.h"
+#include "dgap_tty.h"
+#include "dgap_conf.h"
+#include "dgap_parse.h"
+#include "dgap_trace.h"
+
+/*
+ * Our function prototypes
+ */
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds);
+static int dgap_event(struct board_t *bd);
+
+/*
+ * internal variables
+ */
+static uint dgap_count = 500;
+
+
+/*
+ * Loads the dgap.conf config file from the user.
+ */
+void dgap_do_config_load(uchar __user *uaddr, int len)
+{
+	int orig_len = len;
+	char *to_addr;
+	uchar __user *from_addr = uaddr;
+	char buf[U2BSIZE];
+	int n;
+
+	to_addr = dgap_config_buf = dgap_driver_kzmalloc(len + 1, GFP_ATOMIC);
+	if (!dgap_config_buf) {
+		DPR_INIT(("dgap_do_config_load - unable to allocate memory for file\n"));
+		dgap_driver_state = DRIVER_NEED_CONFIG_LOAD;
+		return;
+	}
+
+	n = U2BSIZE;
+	while (len) {
+
+		if (n > len)
+			n = len;
+
+		if (copy_from_user((char *) &buf, from_addr, n) == -1 )
+			return;
+
+		/* Copy data from buffer to kernel memory */
+		memcpy(to_addr, buf, n);
+
+		/* increment counts */
+		len -= n;
+		to_addr += n;
+		from_addr += n;
+		n = U2BSIZE;
+        }
+
+	dgap_config_buf[orig_len] = '\0';
+
+	to_addr = dgap_config_buf;
+	dgap_parsefile(&to_addr, TRUE);
+
+	DPR_INIT(("dgap_config_load() finish\n"));
+
+	return;
+}
+
+
+int dgap_after_config_loaded(void)
+{
+	int i = 0;
+	int rc = 0;
+
+	/*
+	 * Register our ttys, now that we have the config loaded.
+	 */
+	for (i = 0; i < dgap_NumBoards; ++i) {
+
+		/*
+		 * Initialize KME waitqueues...
+		 */
+		init_waitqueue_head(&(dgap_Board[i]->kme_wait));
+
+		/*
+		 * allocate flip buffer for board.
+		 */
+		dgap_Board[i]->flipbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+		dgap_Board[i]->flipflagbuf = dgap_driver_kzmalloc(MYFLIPLEN, GFP_ATOMIC);
+	}
+
+	return (rc);
+}
+
+
+
+/*=======================================================================
+ *
+ *      usertoboard - copy from user space to board space.
+ *
+ *=======================================================================*/
+static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len)
+{
+	char buf[U2BSIZE];
+	int n = U2BSIZE;
+
+	if (!brd || brd->magic != DGAP_BOARD_MAGIC)
+		return(-EFAULT);
+
+	while (len) {
+		if (n > len)
+			n = len;
+
+		if (copy_from_user((char *) &buf, from_addr, n) == -1 ) {
+			return(-EFAULT);
+		}
+
+		/* Copy data from buffer to card memory */
+		memcpy_toio(to_addr, buf, n);
+
+		/* increment counts */
+		len -= n;
+		to_addr += n;
+		from_addr += n;   
+		n = U2BSIZE;
+        }
+	return(0);
+}
+
+
+/*
+ * Copies the BIOS code from the user to the board,
+ * and starts the BIOS running.
+ */
+void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len)
+{
+	uchar *addr;
+	uint offset;
+	int i;
+
+	if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+		return;
+
+	DPR_INIT(("dgap_do_bios_load() start\n"));
+
+	addr = brd->re_map_membase;
+
+	/*
+	 * clear POST area
+	 */
+	for (i = 0; i < 16; i++)
+		writeb(0, addr + POSTAREA + i);
+                                
+	/*
+	 * Download bios
+	 */
+	offset = 0x1000;
+	if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) {
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+		return;
+	}
+
+	writel(0x0bf00401, addr);
+	writel(0, (addr + 4));
+
+	/* Clear the reset, and change states. */
+	writeb(FEPCLR, brd->re_map_port);
+	brd->state = WAIT_BIOS_LOAD;
+}
+
+
+/*
+ * Checks to see if the BIOS completed running on the card.
+ */
+static void dgap_do_wait_for_bios(struct board_t *brd)
+{
+	uchar *addr;
+	u16 word;
+
+	if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+		return;
+
+	addr = brd->re_map_membase;
+	word = readw(addr + POSTAREA);
+
+	/* Check to see if BIOS thinks board is good. (GD). */
+	if (word == *(u16 *) "GD") {
+		DPR_INIT(("GOT GD in memory, moving states.\n"));
+		brd->state = FINISHED_BIOS_LOAD;
+		return;
+	}
+
+	/* Give up on board after too long of time taken */
+	if (brd->wait_for_bios++ > 5000) {
+		u16 err1 = readw(addr + SEQUENCE);
+		u16 err2 = readw(addr + ERROR);
+		APR(("***WARNING*** %s failed diagnostics.  Error #(%x,%x).\n",
+			brd->name, err1, err2));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+	}
+}
+
+
+/*
+ * Copies the FEP code from the user to the board,
+ * and starts the FEP running.
+ */
+void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len)
+{
+	uchar *addr;
+	uint offset;
+
+	if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+		return;
+
+	addr = brd->re_map_membase;
+
+	DPR_INIT(("dgap_do_fep_load() for board %s : start\n", brd->name));
+
+	/*
+	 * Download FEP
+	 */
+	offset = 0x1000;
+	if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) {
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+		return;
+	}
+
+	/*
+	 * If board is a concentrator product, we need to give
+	 * it its config string describing how the concentrators look.
+	 */
+	if ((brd->type == PCX) || (brd->type == PEPC)) {
+		uchar string[100];
+		uchar *config, *xconfig;
+		int i = 0;
+
+		xconfig = dgap_create_config_string(brd, string);
+
+		/* Write string to board memory */
+		config = addr + CONFIG;
+		for (; i < CONFIGSIZE; i++, config++, xconfig++) {
+			writeb(*xconfig, config);
+			if ((*xconfig & 0xff) == 0xff)
+				break;
+		}
+	}
+
+	writel(0xbfc01004, (addr + 0xc34));
+	writel(0x3, (addr + 0xc30));
+
+	/* change states. */
+	brd->state = WAIT_FEP_LOAD;
+
+	DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name));
+
+}
+
+
+/*
+ * Waits for the FEP to report thats its ready for us to use.
+ */
+static void dgap_do_wait_for_fep(struct board_t *brd)
+{
+	uchar *addr;
+	u16 word;
+
+	if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+		return;
+
+	addr = brd->re_map_membase;
+
+	DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr));
+
+	word = readw(addr + FEPSTAT);
+
+	/* Check to see if FEP is up and running now. */
+	if (word == *(u16 *) "OS") {
+		DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name));
+		brd->state = FINISHED_FEP_LOAD;
+
+		/*
+		 * Check to see if the board can support FEP5+ commands.
+		 */
+		word = readw(addr + FEP5_PLUS);
+		if (word == *(u16 *) "5A") {
+			DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name));
+			brd->bd_flags |= BD_FEP5PLUS;
+		}
+
+		return;
+	}
+
+	/* Give up on board after too long of time taken */
+	if (brd->wait_for_fep++ > 5000) {
+		u16 err1 = readw(addr + SEQUENCE);
+		u16 err2 = readw(addr + ERROR);
+		APR(("***WARNING*** FEPOS for %s not functioning.  Error #(%x,%x).\n",
+			brd->name, err1, err2));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+	}
+
+	DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name));
+}
+
+
+/*
+ * Physically forces the FEP5 card to reset itself.
+ */
+static void dgap_do_reset_board(struct board_t *brd)
+{
+	uchar check;
+	u32 check1;
+	u32 check2;
+	int i = 0;
+
+	if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase || !brd->re_map_port) {
+		DPR_INIT(("dgap_do_reset_board() start. bad values. brd: %p mem: %p io: %p\n", 
+			brd, brd ? brd->re_map_membase : 0, brd ? brd->re_map_port : 0));
+		return;
+	}
+
+	DPR_INIT(("dgap_do_reset_board() start. io: %p\n", brd->re_map_port));
+
+	/* FEPRST does not vary among supported boards */
+	writeb(FEPRST, brd->re_map_port);
+
+	for (i = 0; i <= 1000; i++) {
+		check = readb(brd->re_map_port) & 0xe;
+		if (check == FEPRST)
+			break;
+		udelay(10);
+
+	}
+	if (i > 1000) {
+		APR(("*** WARNING *** Board not resetting...  Failing board.\n"));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+		goto failed;
+	}
+
+	/*
+	 * Make sure there really is memory out there.
+	 */
+	writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM));
+	writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM));
+	check1 = readl(brd->re_map_membase + LOWMEM);
+	check2 = readl(brd->re_map_membase + HIGHMEM);
+
+	if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) {
+		APR(("*** Warning *** No memory at %p for board.\n", brd->re_map_membase));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+		goto failed;
+	}
+
+	if (brd->state != BOARD_FAILED)
+		brd->state = FINISHED_RESET;
+
+failed:
+	DPR_INIT(("dgap_do_reset_board() finish\n"));
+}
+
+
+/*
+ * Sends a concentrator image into the FEP5 board.
+ */
+void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len)
+{
+	char *vaddr;
+	u16 offset = 0;
+	struct downld_t *to_dp;
+
+	if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase)
+		return;
+
+	vaddr = brd->re_map_membase;
+
+	offset = readw((u16 *) (vaddr + DOWNREQ));
+	to_dp = (struct downld_t *) (vaddr + (int) offset);
+
+	/*
+	 * The image was already read into kernel space,
+	 * we do NOT need a user space read here
+	 */
+	memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t));
+
+	/* Tell card we have data for it */
+	writew(0, vaddr + (DOWNREQ));
+
+	brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS;
+}
+
+
+#define EXPANSION_ROM_SIZE	(64 * 1024)
+#define FEP5_ROM_MAGIC		(0xFEFFFFFF)
+
+static void dgap_get_vpd(struct board_t *brd)
+{
+	u32 magic;
+	u32 base_offset;
+	u16 rom_offset;
+	u16 vpd_offset;
+	u16 image_length;
+	u16 i;
+	uchar byte1;
+	uchar byte2;
+
+	/*
+	 * Poke the magic number at the PCI Rom Address location.
+	 * If VPD is supported, the value read from that address
+	 * will be non-zero.
+	 */
+	magic = FEP5_ROM_MAGIC;
+	pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+	pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
+
+	/* VPD not supported, bail */
+	if (!magic)
+		return;
+
+	/*
+	 * To get to the OTPROM memory, we have to send the boards base
+         * address or'ed with 1 into the PCI Rom Address location.
+	 */
+	magic = brd->membase | 0x01;
+	pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+	pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic);
+
+	byte1 = readb(brd->re_map_membase);
+	byte2 = readb(brd->re_map_membase + 1);
+
+	/*
+	 * If the board correctly swapped to the OTPROM memory,
+	 * the first 2 bytes (header) should be 0x55, 0xAA
+	 */
+	if (byte1 == 0x55 && byte2 == 0xAA) {
+
+		base_offset = 0;
+
+		/*
+		 * We have to run through all the OTPROM memory looking
+		 * for the VPD offset.
+		 */
+		while (base_offset <= EXPANSION_ROM_SIZE) {
+                
+			/*
+			 * Lots of magic numbers here.
+			 *
+			 * The VPD offset is located inside the ROM Data Structure.
+			 * We also have to remember the length of each
+			 * ROM Data Structure, so we can "hop" to the next
+			 * entry if the VPD isn't in the current
+			 * ROM Data Structure.
+			 */
+			rom_offset = readw(brd->re_map_membase + base_offset + 0x18);
+			image_length = readw(brd->re_map_membase + rom_offset + 0x10) * 512;
+			vpd_offset = readw(brd->re_map_membase + rom_offset + 0x08);
+
+			/* Found the VPD entry */
+			if (vpd_offset)
+				break;
+
+			/* We didn't find a VPD entry, go to next ROM entry. */
+			base_offset += image_length;
+
+			byte1 = readb(brd->re_map_membase + base_offset);
+			byte2 = readb(brd->re_map_membase + base_offset + 1);
+
+			/*
+			 * If the new ROM offset doesn't have 0x55, 0xAA
+			 * as its header, we have run out of ROM.
+			 */
+			if (byte1 != 0x55 || byte2 != 0xAA)
+				break;
+		}
+
+		/*
+		 * If we have a VPD offset, then mark the board
+		 * as having a valid VPD, and copy VPDSIZE (512) bytes of
+		 * that VPD to the buffer we have in our board structure.
+		 */
+		if (vpd_offset) {
+			brd->bd_flags |= BD_HAS_VPD;
+			for (i = 0; i < VPDSIZE; i++)
+				brd->vpd[i] = readb(brd->re_map_membase + vpd_offset + i);
+		}
+	}
+
+	/*
+	 * We MUST poke the magic number at the PCI Rom Address location again.
+	 * This makes the card report the regular board memory back to us,
+	 * rather than the OTPROM memory.
+	 */
+	magic = FEP5_ROM_MAGIC;
+	pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic);
+}
+
+
+/*
+ * Our board poller function.
+ */
+void dgap_poll_tasklet(unsigned long data)
+{
+        struct board_t *bd = (struct board_t *) data;
+	ulong  lock_flags;
+	ulong  lock_flags2;
+	char *vaddr;
+	u16 head, tail;
+	u16 *chk_addr;
+	u16 check = 0;
+
+	if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) {
+		APR(("dgap_poll_tasklet() - NULL or bad bd.\n"));
+		return;
+	}
+
+	if (bd->inhibit_poller)
+		return;
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+
+	vaddr = bd->re_map_membase;
+
+	/*
+	 * If board is ready, parse deeper to see if there is anything to do.
+	 */
+	if (bd->state == BOARD_READY) {
+
+		struct ev_t *eaddr = NULL;
+
+		if (!bd->re_map_membase) {
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			return;
+		}
+		if (!bd->re_map_port) {
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			return;
+		}
+
+		if (!bd->nasync) {
+			goto out;
+		}
+
+		/*
+		 * If this is a CX or EPCX, we need to see if the firmware
+		 * is requesting a concentrator image from us.
+		 */
+		if ((bd->type == PCX) || (bd->type == PEPC)) {
+			chk_addr = (u16 *) (vaddr + DOWNREQ);
+			check = readw(chk_addr);
+			/* Nonzero if FEP is requesting concentrator image. */
+			if (check) {
+				if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS)
+					bd->conc_dl_status = NEED_CONCENTRATOR;
+				/*
+				 * Signal downloader, its got some work to do.
+				 */
+				DGAP_LOCK(dgap_dl_lock, lock_flags2);
+				if (dgap_dl_action != 1) {
+					dgap_dl_action = 1;
+					wake_up_interruptible(&dgap_dl_wait);
+				}
+				DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+
+			}
+		}
+
+		eaddr = (struct ev_t *) (vaddr + EVBUF);
+
+		/* Get our head and tail */
+		head = readw(&(eaddr->ev_head));
+		tail = readw(&(eaddr->ev_tail));
+
+		/*
+		 * If there is an event pending. Go service it.
+		 */
+		if (head != tail) {
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			dgap_event(bd);
+			DGAP_LOCK(bd->bd_lock, lock_flags);
+		}
+
+out:
+		/*
+		 * If board is doing interrupts, ACK the interrupt.
+		 */
+		if (bd && bd->intr_running) {
+			readb(bd->re_map_port + 2);
+		}
+
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return;
+	}
+
+	/* Our state machine to get the board up and running */
+
+	/* Reset board */
+	if (bd->state == NEED_RESET) {
+
+		/* Get VPD info */
+		dgap_get_vpd(bd);
+
+		dgap_do_reset_board(bd);
+	}
+
+	/* Move to next state */
+	if (bd->state == FINISHED_RESET) {
+		bd->state = NEED_CONFIG;
+	}
+
+	if (bd->state == NEED_CONFIG) {
+		/*
+		 * Match this board to a config the user created for us.
+		 */
+		bd->bd_config = dgap_find_config(bd->type, bd->pci_bus, bd->pci_slot);
+
+		/*
+		 * Because the 4 port Xr products share the same PCI ID
+		 * as the 8 port Xr products, if we receive a NULL config
+		 * back, and this is a PAPORT8 board, retry with a
+		 * PAPORT4 attempt as well.
+		 */
+		if (bd->type == PAPORT8 && !bd->bd_config) {
+			bd->bd_config = dgap_find_config(PAPORT4, bd->pci_bus, bd->pci_slot);
+		}
+
+		/*
+		 * Register the ttys (if any) into the kernel.
+		 */
+		if (bd->bd_config) {
+			bd->state = FINISHED_CONFIG;
+		}
+		else {
+			bd->state = CONFIG_NOT_FOUND;
+		}
+	}
+
+	/* Move to next state */
+	if (bd->state == FINISHED_CONFIG) {
+		bd->state = NEED_DEVICE_CREATION;
+	}
+
+	/* Move to next state */
+	if (bd->state == NEED_DEVICE_CREATION) {
+		/*
+		 * Signal downloader, its got some work to do.
+		 */
+		DGAP_LOCK(dgap_dl_lock, lock_flags2);
+		if (dgap_dl_action != 1) {
+			dgap_dl_action = 1;
+			wake_up_interruptible(&dgap_dl_wait);
+		}
+		DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+	}
+
+	/* Move to next state */
+	if (bd->state == FINISHED_DEVICE_CREATION) {
+		bd->state = NEED_BIOS_LOAD;
+	}
+
+	/* Move to next state */
+	if (bd->state == NEED_BIOS_LOAD) {
+		/*
+		 * Signal downloader, its got some work to do.
+		 */
+		DGAP_LOCK(dgap_dl_lock, lock_flags2);
+		if (dgap_dl_action != 1) {
+			dgap_dl_action = 1;
+			wake_up_interruptible(&dgap_dl_wait);
+		}
+		DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+	}
+
+	/* Wait for BIOS to test board... */
+	if (bd->state == WAIT_BIOS_LOAD) {
+		dgap_do_wait_for_bios(bd);
+	}
+
+	/* Move to next state */
+	if (bd->state == FINISHED_BIOS_LOAD) {
+		bd->state = NEED_FEP_LOAD;
+
+		/*
+		 * Signal downloader, its got some work to do.
+		 */
+		DGAP_LOCK(dgap_dl_lock, lock_flags2);
+		if (dgap_dl_action != 1) {
+			dgap_dl_action = 1;
+			wake_up_interruptible(&dgap_dl_wait);
+		}
+		DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+	}
+
+	/* Wait for FEP to load on board... */
+	if (bd->state == WAIT_FEP_LOAD) {
+		dgap_do_wait_for_fep(bd);
+	}
+
+
+	/* Move to next state */
+	if (bd->state == FINISHED_FEP_LOAD) {
+
+		/*
+		 * Do tty device initialization.
+		 */
+		int rc = dgap_tty_init(bd);
+
+		if (rc < 0) {
+			dgap_tty_uninit(bd);
+			APR(("Can't init tty devices (%d)\n", rc));
+			bd->state = BOARD_FAILED;
+			bd->dpastatus = BD_NOFEP;
+		}
+		else {
+			bd->state = NEED_PROC_CREATION;
+
+			/*
+			 * Signal downloader, its got some work to do.
+			 */
+			DGAP_LOCK(dgap_dl_lock, lock_flags2);
+			if (dgap_dl_action != 1) {
+				dgap_dl_action = 1;
+				wake_up_interruptible(&dgap_dl_wait);
+			}
+			DGAP_UNLOCK(dgap_dl_lock, lock_flags2);
+		}
+	}
+
+	/* Move to next state */
+	if (bd->state == FINISHED_PROC_CREATION) {
+
+		bd->state = BOARD_READY;
+		bd->dpastatus = BD_RUNNING;
+
+		/*
+		 * If user requested the board to run in interrupt mode,
+		 * go and set it up on the board.
+		 */
+		if (bd->intr_used) {
+			writew(1, (bd->re_map_membase + ENABLE_INTR));
+			/*
+			 * Tell the board to poll the UARTS as fast as possible.
+			 */
+			writew(FEPPOLL_MIN, (bd->re_map_membase + FEPPOLL));
+			bd->intr_running = 1;
+		}
+
+		/* Wake up anyone waiting for board state to change to ready */
+		wake_up_interruptible(&bd->state_wait);
+	}
+
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+}
+
+
+/*=======================================================================
+ *
+ *      dgap_cmdb - Sends a 2 byte command to the FEP.
+ *
+ *              ch      - Pointer to channel structure.
+ *              cmd     - Command to be sent.
+ *              byte1   - Integer containing first byte to be sent.
+ *              byte2   - Integer containing second byte to be sent.
+ *              ncmds   - Wait until ncmds or fewer cmds are left
+ *                        in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds)
+{                       
+	char		*vaddr = NULL;
+	struct cm_t	*cm_addr = NULL;
+	uint		count;
+	uint		n;
+	u16		head;
+        u16		tail;
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	/*
+	 * Check if board is still alive.
+	 */
+	if (ch->ch_bd->state == BOARD_FAILED) {
+		DPR_CORE(("%s:%d board is in failed state.\n", __FILE__, __LINE__));
+		return;
+        }               
+
+	/*
+	 * Make sure the pointers are in range before
+	 * writing to the FEP memory.
+	 */
+	vaddr = ch->ch_bd->re_map_membase;
+
+	if (!vaddr)
+		return;
+
+	cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+	head = readw(&(cm_addr->cm_head));
+
+	/* 
+	 * Forget it if pointers out of range.
+	 */
+	if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+		DPR_CORE(("%s:%d pointers out of range, failing board!\n", __FILE__, __LINE__));
+		ch->ch_bd->state = BOARD_FAILED;
+		return; 
+	}
+
+	/*
+	 * Put the data in the circular command buffer.
+	 */
+	writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
+	writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
+	writeb(byte1, (char *) (vaddr + head + CMDSTART + 2));
+	writeb(byte2, (char *) (vaddr + head + CMDSTART + 3));
+
+	head = (head + 4) & (CMDMAX - CMDSTART - 4);
+
+	writew(head, &(cm_addr->cm_head));
+
+	/*
+	 * Wait if necessary before updating the head  
+	 * pointer to limit the number of outstanding
+	 * commands to the FEP.   If the time spent waiting
+	 * is outlandish, declare the FEP dead.
+	 */
+	for (count = dgap_count ;;) {
+
+		head = readw(&(cm_addr->cm_head));
+		tail = readw(&(cm_addr->cm_tail));
+
+		n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+		if (n <= ncmds * sizeof(struct cm_t))
+			break;
+
+		if (--count == 0) {
+			DPR_CORE(("%s:%d failing board.\n",__FILE__, __LINE__));
+			ch->ch_bd->state = BOARD_FAILED;
+			return;
+		}
+		udelay(10);
+	}  
+}
+
+
+/*=======================================================================
+ *
+ *      dgap_cmdw - Sends a 1 word command to the FEP.
+ *      
+ *              ch      - Pointer to channel structure.
+ *              cmd     - Command to be sent.
+ *              word    - Integer containing word to be sent.
+ *              ncmds   - Wait until ncmds or fewer cmds are left
+ *                        in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds)
+{
+	char		*vaddr = NULL;
+	struct cm_t	*cm_addr = NULL;
+	uint		count;
+	uint		n;
+	u16		head;
+	u16		tail;
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	/*
+	 * Check if board is still alive.
+	 */
+	if (ch->ch_bd->state == BOARD_FAILED) {
+		DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__));
+		return;
+	}
+
+	/*
+	 * Make sure the pointers are in range before
+	 * writing to the FEP memory.
+	 */
+	vaddr = ch->ch_bd->re_map_membase;
+	if (!vaddr)
+		return;
+
+	cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+	head = readw(&(cm_addr->cm_head));
+
+	/* 
+	 * Forget it if pointers out of range.
+	 */
+	if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+		DPR_CORE(("%s:%d Pointers out of range.  Failing board.\n",__FILE__, __LINE__));
+		ch->ch_bd->state = BOARD_FAILED;
+		return;
+	}
+
+	/*
+	 * Put the data in the circular command buffer.
+	 */
+	writeb(cmd, (char *) (vaddr + head + CMDSTART + 0));
+	writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1));
+	writew((u16) word, (char *) (vaddr + head + CMDSTART + 2));
+
+	head = (head + 4) & (CMDMAX - CMDSTART - 4);
+
+	writew(head, &(cm_addr->cm_head));
+
+	/*
+	 * Wait if necessary before updating the head
+	 * pointer to limit the number of outstanding  
+	 * commands to the FEP.   If the time spent waiting
+	 * is outlandish, declare the FEP dead.
+	 */
+	for (count = dgap_count ;;) {
+
+		head = readw(&(cm_addr->cm_head));
+		tail = readw(&(cm_addr->cm_tail));
+
+		n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+		if (n <= ncmds * sizeof(struct cm_t))
+			break;
+
+		if (--count == 0) {
+			DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__));
+			ch->ch_bd->state = BOARD_FAILED;
+			return;
+		}
+		udelay(10);
+	}  
+}
+
+
+
+/*=======================================================================
+ *
+ *      dgap_cmdw_ext - Sends a extended word command to the FEP.
+ *      
+ *              ch      - Pointer to channel structure.
+ *              cmd     - Command to be sent.
+ *              word    - Integer containing word to be sent.
+ *              ncmds   - Wait until ncmds or fewer cmds are left
+ *                        in the cmd buffer before returning.
+ *
+ *=======================================================================*/
+static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds)
+{
+	char		*vaddr = NULL;
+	struct cm_t	*cm_addr = NULL;
+	uint		count;
+	uint		n;
+	u16		head;
+	u16		tail;
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	/*
+	 * Check if board is still alive.
+	 */
+	if (ch->ch_bd->state == BOARD_FAILED) {
+		DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__));
+		return;
+	}
+
+	/*
+	 * Make sure the pointers are in range before
+	 * writing to the FEP memory.
+	 */
+	vaddr = ch->ch_bd->re_map_membase;
+	if (!vaddr)
+		return;
+
+	cm_addr = (struct cm_t *) (vaddr + CMDBUF);
+	head = readw(&(cm_addr->cm_head));
+
+	/* 
+	 * Forget it if pointers out of range.
+	 */
+	if (head >= (CMDMAX - CMDSTART) || (head & 03)) {
+		DPR_CORE(("%s:%d Pointers out of range.  Failing board.\n",__FILE__, __LINE__));
+		ch->ch_bd->state = BOARD_FAILED;
+		return;
+	}
+
+	/*
+	 * Put the data in the circular command buffer.
+	 */
+
+	/* Write an FF to tell the FEP that we want an extended command */
+	writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0));
+
+	writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1));
+	writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2));
+
+	/*
+	 * If the second part of the command won't fit,
+	 * put it at the beginning of the circular buffer.
+	 */
+	if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) {
+		writew((u16) word, (char *) (vaddr + CMDSTART));
+	} else {
+		writew((u16) word, (char *) (vaddr + head + CMDSTART + 4));
+	}
+
+	head = (head + 8) & (CMDMAX - CMDSTART - 4);
+
+	writew(head, &(cm_addr->cm_head));
+
+	/*
+	 * Wait if necessary before updating the head
+	 * pointer to limit the number of outstanding  
+	 * commands to the FEP.   If the time spent waiting
+	 * is outlandish, declare the FEP dead.
+	 */
+	for (count = dgap_count ;;) {
+
+		head = readw(&(cm_addr->cm_head));
+		tail = readw(&(cm_addr->cm_tail));
+
+		n = (head - tail) & (CMDMAX - CMDSTART - 4);
+
+		if (n <= ncmds * sizeof(struct cm_t))
+			break;
+
+		if (--count == 0) {
+			DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__));
+			ch->ch_bd->state = BOARD_FAILED;
+			return;
+		}
+		udelay(10);
+	}  
+}
+
+
+/*=======================================================================
+ *
+ *      dgap_wmove - Write data to FEP buffer.
+ *
+ *              ch      - Pointer to channel structure.
+ *              buf     - Poiter to characters to be moved.
+ *              cnt     - Number of characters to move.
+ *
+ *=======================================================================*/
+void dgap_wmove(struct channel_t *ch, char *buf, uint cnt)
+{
+	int    n;
+	char   *taddr;
+	struct bs_t    *bs;
+	u16    head;
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+ 
+	/*
+	 * Check parameters.
+	 */
+	bs   = ch->ch_bs;
+	head = readw(&(bs->tx_head));
+
+	/*
+	 * If pointers are out of range, just return.
+	 */
+	if ((cnt > ch->ch_tsize) || (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) {
+		DPR_CORE(("%s:%d pointer out of range", __FILE__, __LINE__));
+		return;
+	}
+
+	/*
+	 * If the write wraps over the top of the circular buffer,
+	 * move the portion up to the wrap point, and reset the
+	 * pointers to the bottom.
+	 */
+	n = ch->ch_tstart + ch->ch_tsize - head;
+
+	if (cnt >= n) {
+		cnt -= n;
+		taddr = ch->ch_taddr + head;
+		memcpy_toio(taddr, buf, n);
+		head = ch->ch_tstart;
+		buf += n;
+	}
+
+	/*
+	 * Move rest of data.
+	 */
+	taddr = ch->ch_taddr + head;
+	n = cnt;
+	memcpy_toio(taddr, buf, n);
+	head += cnt;
+
+	writew(head, &(bs->tx_head));
+}
+
+/*
+ * Retrives the current custom baud rate from FEP memory,
+ * and returns it back to the user.
+ * Returns 0 on error.
+ */
+uint dgap_get_custom_baud(struct channel_t *ch)
+{
+	uchar *vaddr;
+	ulong offset = 0;
+	uint value = 0;
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+		return (0);
+	}
+
+	if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) {
+		return (0);
+	}
+
+	if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS))
+		return (0);
+
+	vaddr = ch->ch_bd->re_map_membase;
+
+	if (!vaddr)
+		return (0);
+
+	/*
+	 * Go get from fep mem, what the fep
+	 * believes the custom baud rate is. 
+	 */
+	offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) +  
+		(ch->ch_portnum * 0x28) + LINE_SPEED));
+
+	value = readw(vaddr + offset);
+	return (value);
+}
+
+
+/*
+ * Calls the firmware to reset this channel.
+ */
+void dgap_firmware_reset_port(struct channel_t *ch)
+{
+	dgap_cmdb(ch, CHRESET, 0, 0, 0);
+
+	/*
+	 * Now that the channel is reset, we need to make sure
+	 * all the current settings get reapplied to the port
+	 * in the firmware.
+	 *
+	 * So we will set the driver's cache of firmware
+	 * settings all to 0, and then call param.
+	 */
+	ch->ch_fepiflag = 0;
+	ch->ch_fepcflag = 0;
+	ch->ch_fepoflag = 0;
+	ch->ch_fepstartc = 0;
+	ch->ch_fepstopc = 0;
+	ch->ch_fepastartc = 0;
+	ch->ch_fepastopc = 0;
+	ch->ch_mostat = 0;
+	ch->ch_hflow = 0;
+}
+
+
+/*=======================================================================
+ *      
+ *      dgap_param - Set Digi parameters.
+ *
+ *              struct tty_struct *     - TTY for port.
+ *
+ *=======================================================================*/
+int dgap_param(struct tty_struct *tty)
+{
+	struct ktermios *ts;
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct bs_t   *bs;
+	struct un_t   *un;
+	u16	head;
+	u16	cflag;
+	u16	iflag;
+	uchar	mval;
+	uchar	hflow;
+
+	if (!tty || tty->magic != TTY_MAGIC) {
+		return (-ENXIO);
+	}
+
+	un = (struct un_t *) tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC) {
+		return (-ENXIO);
+	}
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+		return (-ENXIO);
+	}
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC) {
+		return (-ENXIO);
+	}
+
+        bs = ch->ch_bs;
+	if (bs == 0) {
+		return (-ENXIO);
+	}
+
+	DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
+		ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
+
+	ts = &tty->termios;
+
+	/*
+	 * If baud rate is zero, flush queues, and set mval to drop DTR.
+	 */
+	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+
+		/* flush rx */
+		head = readw(&(ch->ch_bs->rx_head));
+		writew(head, &(ch->ch_bs->rx_tail));
+
+		/* flush tx */
+		head = readw(&(ch->ch_bs->tx_head));
+		writew(head, &(ch->ch_bs->tx_tail));
+
+		ch->ch_flags |= (CH_BAUD0);
+
+		/* Drop RTS and DTR */
+		ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch));
+		mval = D_DTR(ch) | D_RTS(ch);
+		ch->ch_baud_info = 0;
+
+	} else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) {
+		/*
+		 * Tell the fep to do the command
+		 */
+
+		DPR_PARAM(("param: Want %d speed\n", ch->ch_custom_speed));
+
+		dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0);
+
+		/*
+		 * Now go get from fep mem, what the fep
+		 * believes the custom baud rate is. 
+		 */
+		ch->ch_baud_info = ch->ch_custom_speed = dgap_get_custom_baud(ch);
+
+		DPR_PARAM(("param: Got %d speed\n", ch->ch_custom_speed));
+
+		/* Handle transition from B0 */   
+		if (ch->ch_flags & CH_BAUD0) {
+			ch->ch_flags &= ~(CH_BAUD0);
+			ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
+		}
+		mval = D_DTR(ch) | D_RTS(ch);
+
+	} else {
+		/*
+		 * Set baud rate, character size, and parity.
+		 */
+
+
+		int iindex = 0;
+		int jindex = 0;
+		int baud = 0;
+
+		ulong bauds[4][16] = {
+			{ /* slowbaud */
+				0,	50,	75,	110,
+				134,	150,	200,	300,
+				600,	1200,	1800,	2400,
+				4800,	9600,	19200,	38400 },
+			{ /* slowbaud & CBAUDEX */
+				0,	57600,	115200,	230400,
+				460800,	150,	200,	921600,
+				600,	1200,	1800,	2400,
+				4800,	9600,	19200,	38400 },
+			{ /* fastbaud */
+				0,	57600,	76800,	115200,
+				14400,	57600,	230400,	76800,
+				115200,	230400,	28800,	460800,
+				921600,	9600,	19200,	38400 },
+			{ /* fastbaud & CBAUDEX */
+				0,	57600,	115200,	230400,
+				460800,	150,	200,	921600,
+				600,	1200,	1800,	2400,
+				4800,	9600,	19200,	38400 }
+		};
+
+		/* Only use the TXPrint baud rate if the terminal unit is NOT open */
+		if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGAP_PRINT))
+			baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+		else
+			baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+		if (ch->ch_c_cflag & CBAUDEX)
+			iindex = 1;
+
+		if (ch->ch_digi.digi_flags & DIGI_FAST)
+			iindex += 2;
+
+		jindex = baud;
+
+		if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
+			baud = bauds[iindex][jindex];
+		} else {
+			DPR_IOCTL(("baud indices were out of range (%d)(%d)",
+				iindex, jindex));
+			baud = 0;
+		}
+
+		if (baud == 0)  
+			baud = 9600;
+
+		ch->ch_baud_info = baud;
+
+
+		/*
+		 * CBAUD has bit position 0x1000 set these days to indicate Linux
+		 * baud rate remap.
+		 * We use a different bit assignment for high speed.  Clear this
+		 * bit out while grabbing the parts of "cflag" we want.
+		 */
+		cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
+
+		/*
+		 * HUPCL bit is used by FEP to indicate fast baud
+		 * table is to be used.
+		 */
+		if ((ch->ch_digi.digi_flags & DIGI_FAST) || (ch->ch_c_cflag & CBAUDEX))
+			cflag |= HUPCL;
+
+
+		if ((ch->ch_c_cflag & CBAUDEX) && !(ch->ch_digi.digi_flags & DIGI_FAST)) {
+		/*
+		 * The below code is trying to guarantee that only baud rates
+		 * 115200, 230400, 460800, 921600 are remapped.  We use exclusive or
+		 * because the various baud rates share common bit positions
+		 * and therefore can't be tested for easily.
+		 */
+			tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX;
+			int baudpart = 0;
+
+			/* Map high speed requests to index into FEP's baud table */
+			switch (tcflag) {
+			case B57600 :
+				baudpart = 1;
+				break;
+#ifdef B76800
+			case B76800 :
+				baudpart = 2;
+				break;
+#endif
+			case B115200 :
+				baudpart = 3;
+				break;
+			case B230400 :
+				baudpart = 9;
+				break;
+			case B460800 :
+				baudpart = 11;
+				break;
+#ifdef B921600
+			case B921600 :
+				baudpart = 12;
+				break;
+#endif
+			default:
+				baudpart = 0;
+			}
+
+			if (baudpart)
+				cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart;
+		}
+
+		cflag &= 0xffff;
+
+		if (cflag != ch->ch_fepcflag) {
+			ch->ch_fepcflag = (u16) (cflag & 0xffff);
+
+			/* Okay to have channel and board locks held calling this */
+			dgap_cmdw(ch, SCFLAG, (u16) cflag, 0);
+		}
+
+		/* Handle transition from B0 */   
+		if (ch->ch_flags & CH_BAUD0) {
+			ch->ch_flags &= ~(CH_BAUD0);
+			ch->ch_mval |= (D_RTS(ch)|D_DTR(ch));
+		}
+		mval = D_DTR(ch) | D_RTS(ch);
+	}
+
+	/*
+	 * Get input flags.
+	 */
+	iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON | IXANY | IXOFF);
+
+	if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE)) {
+		iflag &= ~(IXON | IXOFF);
+		ch->ch_c_iflag &= ~(IXON | IXOFF);
+	}
+
+	/*
+	 * Only the IBM Xr card can switch between
+	 * 232 and 422 modes on the fly
+	 */
+	if (bd->device == PCI_DEVICE_XR_IBM_DID) {
+		if (ch->ch_digi.digi_flags & DIGI_422)
+			dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0);
+		else
+			dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0);
+	}
+
+	if (ch->ch_digi.digi_flags & DIGI_ALTPIN)
+		iflag |= IALTPIN ;
+
+	if (iflag != ch->ch_fepiflag) {
+		ch->ch_fepiflag = iflag;
+
+		/* Okay to have channel and board locks held calling this */
+		dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0);
+	}
+
+	/*
+	 * Select hardware handshaking.
+	 */
+	hflow = 0;
+
+	if (ch->ch_c_cflag & CRTSCTS) {
+		hflow |= (D_RTS(ch) | D_CTS(ch));
+	}
+	if (ch->ch_digi.digi_flags & RTSPACE)
+		hflow |= D_RTS(ch);
+	if (ch->ch_digi.digi_flags & DTRPACE)
+		hflow |= D_DTR(ch);  
+	if (ch->ch_digi.digi_flags & CTSPACE)
+		hflow |= D_CTS(ch);
+	if (ch->ch_digi.digi_flags & DSRPACE)
+		hflow |= D_DSR(ch);
+	if (ch->ch_digi.digi_flags & DCDPACE)
+		hflow |= D_CD(ch);
+
+	if (hflow != ch->ch_hflow) {
+		ch->ch_hflow = hflow;
+
+		/* Okay to have channel and board locks held calling this */
+		dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0);
+        }
+
+
+	/*
+	 * Set RTS and/or DTR Toggle if needed, but only if product is FEP5+ based.
+	 */
+	if (bd->bd_flags & BD_FEP5PLUS) {
+		u16 hflow2 = 0;
+		if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+			hflow2 |= (D_RTS(ch));
+		}
+		if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+			hflow2 |= (D_DTR(ch));
+		}
+
+		dgap_cmdw_ext(ch, 0xff03, hflow2, 0);
+	}
+
+	/*
+	 * Set modem control lines.  
+	 */
+
+	mval ^= ch->ch_mforce & (mval ^ ch->ch_mval);
+
+	DPR_PARAM(("dgap_param: mval: %x ch_mforce: %x ch_mval: %x ch_mostat: %x\n",
+		mval, ch->ch_mforce, ch->ch_mval, ch->ch_mostat));
+
+	if (ch->ch_mostat ^ mval) {
+		ch->ch_mostat = mval;
+
+		/* Okay to have channel and board locks held calling this */
+		DPR_PARAM(("dgap_param: Sending SMODEM mval: %x\n", mval));
+		dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0);
+	}
+
+	/*
+	 * Read modem signals, and then call carrier function.             
+	 */
+	ch->ch_mistat = readb(&(bs->m_stat));
+	dgap_carrier(ch);
+
+	/*      
+	 * Set the start and stop characters.
+	 */
+	if (ch->ch_startc != ch->ch_fepstartc || ch->ch_stopc != ch->ch_fepstopc) {
+		ch->ch_fepstartc = ch->ch_startc;
+		ch->ch_fepstopc =  ch->ch_stopc;
+
+		/* Okay to have channel and board locks held calling this */
+		dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0);
+	}
+
+	/*
+	 * Set the Auxiliary start and stop characters.
+	 */     
+	if (ch->ch_astartc != ch->ch_fepastartc || ch->ch_astopc != ch->ch_fepastopc) {
+		ch->ch_fepastartc = ch->ch_astartc;
+		ch->ch_fepastopc = ch->ch_astopc;
+
+		/* Okay to have channel and board locks held calling this */
+		dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0);
+	}
+
+	DPR_PARAM(("param finish\n"));
+
+	return (0);
+}
+
+
+/*
+ * dgap_parity_scan()
+ *
+ * Convert the FEP5 way of reporting parity errors and breaks into
+ * the Linux line discipline way.
+ */
+void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len)
+{
+	int l = *len;
+	int count = 0;
+	unsigned char *in, *cout, *fout;
+	unsigned char c;
+
+	in = cbuf;
+	cout = cbuf;
+	fout = fbuf;
+
+	DPR_PSCAN(("dgap_parity_scan start\n"));
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	while (l--) {
+		c = *in++;
+		switch (ch->pscan_state) {
+		default:
+			/* reset to sanity and fall through */
+			ch->pscan_state = 0;
+
+		case 0:
+			/* No FF seen yet */
+			if (c == (unsigned char) '\377') {
+				/* delete this character from stream */
+				ch->pscan_state = 1;
+			} else {
+				*cout++ = c;
+				*fout++ = TTY_NORMAL;
+				count += 1;
+			}
+			break;
+
+		case 1:
+			/* first FF seen */
+			if (c == (unsigned char) '\377') {
+				/* doubled ff, transform to single ff */
+				*cout++ = c;
+				*fout++ = TTY_NORMAL;
+				count += 1;
+				ch->pscan_state = 0;
+			} else {
+				/* save value examination in next state */
+				ch->pscan_savechar = c;
+				ch->pscan_state = 2; 
+			}
+			break;
+
+		case 2:
+			/* third character of ff sequence */
+
+			*cout++ = c;
+
+			if (ch->pscan_savechar == 0x0) {
+
+				if (c == 0x0) {
+					DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting break.\n", c));
+					ch->ch_err_break++;
+					*fout++ = TTY_BREAK;
+				}
+				else {
+					DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting parity.\n", c));
+					ch->ch_err_parity++;
+					*fout++ = TTY_PARITY;
+				}
+			}
+			else {
+				DPR_PSCAN(("%s:%d Logic Error.\n", __FILE__, __LINE__));
+			}
+
+			count += 1;
+			ch->pscan_state = 0;
+		}       
+	}
+	*len = count;
+	DPR_PSCAN(("dgap_parity_scan finish\n"));
+}
+
+
+
+
+/*=======================================================================
+ *
+ *      dgap_event - FEP to host event processing routine.
+ *
+ *              bd     - Board of current event.
+ *
+ *=======================================================================*/
+static int dgap_event(struct board_t *bd)
+{
+	struct channel_t *ch;
+	ulong		lock_flags;
+	ulong		lock_flags2;
+	struct bs_t	*bs;
+	uchar		*event;
+	uchar		*vaddr = NULL;
+	struct ev_t	*eaddr = NULL;
+	uint		head;
+	uint		tail;
+	int		port;
+	int		reason;
+	int		modem;
+	int		b1;
+
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (-ENXIO);
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+
+	vaddr = bd->re_map_membase;
+
+	if (!vaddr) {
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return (-ENXIO);
+	}
+
+	eaddr = (struct ev_t *) (vaddr + EVBUF);
+
+	/* Get our head and tail */
+	head = readw(&(eaddr->ev_head));
+	tail = readw(&(eaddr->ev_tail));
+
+	/*
+	 * Forget it if pointers out of range.
+	 */
+
+	if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART ||
+	    (head | tail) & 03) {
+		DPR_EVENT(("should be calling xxfail %d\n", __LINE__));
+		/* Let go of board lock */
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return (-ENXIO);
+	}
+
+	/*
+	 * Loop to process all the events in the buffer.
+	 */
+	while (tail != head) {
+
+		/*
+		 * Get interrupt information.
+		 */
+
+		event = bd->re_map_membase + tail + EVSTART;
+
+		port   = event[0];
+		reason = event[1];
+		modem  = event[2];
+		b1     = event[3];
+
+		DPR_EVENT(("event: jiffies: %ld port: %d reason: %x modem: %x\n",
+			jiffies, port, reason, modem));
+
+		/*
+		 * Make sure the interrupt is valid.
+		 */
+                if ( port >= bd->nasync) {
+			goto next;
+		}
+
+		if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) {
+			goto next;
+		}
+
+		ch = bd->channels[port];
+
+		if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+			goto next;
+		}
+
+		/*
+		 * If we have made it here, the event was valid.
+		 * Lock down the channel.
+		 */
+		DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+		bs = ch->ch_bs;
+
+		if (!bs) {
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			goto next;
+		}
+
+		/*
+		 * Process received data.
+		 */
+		if (reason & IFDATA) {
+
+			/*
+			 * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT!
+			 * input could send some data to ld, which in turn
+			 * could do a callback to one of our other functions.
+			 */
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+			dgap_input(ch);
+
+			DGAP_LOCK(bd->bd_lock, lock_flags);
+			DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+			if (ch->ch_flags & CH_RACTIVE)
+				ch->ch_flags |= CH_RENABLE;
+			else
+				writeb(1, &(bs->idata));
+
+			if (ch->ch_flags & CH_RWAIT) {
+				ch->ch_flags &= ~CH_RWAIT;
+
+				wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+			}
+		}
+
+		/*
+		 * Process Modem change signals. 
+		 */
+		if (reason & IFMODEM) {
+			ch->ch_mistat = modem;
+			dgap_carrier(ch);
+		}
+
+		/*
+		 * Process break.
+		 */
+		if (reason & IFBREAK) {
+
+			DPR_EVENT(("got IFBREAK\n"));
+
+			if (ch->ch_tun.un_tty) {
+				/* A break has been indicated */
+				ch->ch_err_break++;
+				tty_buffer_request_room(ch->ch_tun.un_tty->port, 1);
+				tty_insert_flip_char(ch->ch_tun.un_tty->port, 0, TTY_BREAK);
+				tty_flip_buffer_push(ch->ch_tun.un_tty->port);
+			}
+		}
+
+		/*
+		 * Process Transmit low.
+		 */
+		if (reason & IFTLW) {
+
+			DPR_EVENT(("event: got low event\n"));
+
+			if (ch->ch_tun.un_flags & UN_LOW) {
+				ch->ch_tun.un_flags &= ~UN_LOW;
+
+				if (ch->ch_tun.un_flags & UN_ISOPEN) {
+					if ((ch->ch_tun.un_tty->flags & 
+					   (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
+#else
+						ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
+#endif
+					{
+						DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+						DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						(ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
+#else
+						(ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
+#endif
+						DGAP_LOCK(bd->bd_lock, lock_flags);
+						DGAP_LOCK(ch->ch_lock, lock_flags2);
+					}
+					wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+					wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+
+					DPR_EVENT(("event: Got low event. jiffies: %lu\n", jiffies));
+				}
+			}
+
+			if (ch->ch_pun.un_flags & UN_LOW) {
+				ch->ch_pun.un_flags &= ~UN_LOW;
+				if (ch->ch_pun.un_flags & UN_ISOPEN) {
+					if ((ch->ch_pun.un_tty->flags & 
+					   (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
+#else
+						ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
+#endif
+					{
+						DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+						DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						(ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
+#else
+						(ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
+#endif
+						DGAP_LOCK(bd->bd_lock, lock_flags);
+						DGAP_LOCK(ch->ch_lock, lock_flags2);
+					}
+					wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+					wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+				}
+			}
+
+			if (ch->ch_flags & CH_WLOW) {
+				ch->ch_flags &= ~CH_WLOW;
+				wake_up_interruptible(&ch->ch_flags_wait);
+			}
+		}
+
+		/*
+		 * Process Transmit empty.
+		 */
+		if (reason & IFTEM) {
+			DPR_EVENT(("event: got empty event\n"));
+
+			if (ch->ch_tun.un_flags & UN_EMPTY) {
+				ch->ch_tun.un_flags &= ~UN_EMPTY;
+				if (ch->ch_tun.un_flags & UN_ISOPEN) {
+					if ((ch->ch_tun.un_tty->flags & 
+					   (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
+#else
+						ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
+#endif
+					{
+						DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+						DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						(ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
+#else
+						(ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
+#endif
+						DGAP_LOCK(bd->bd_lock, lock_flags);
+						DGAP_LOCK(ch->ch_lock, lock_flags2);
+					}
+					wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+					wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+				}
+			}
+
+			if (ch->ch_pun.un_flags & UN_EMPTY) {
+				ch->ch_pun.un_flags &= ~UN_EMPTY;
+				if (ch->ch_pun.un_flags & UN_ISOPEN) {
+					if ((ch->ch_pun.un_tty->flags & 
+					   (1 << TTY_DO_WRITE_WAKEUP)) &&
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
+#else
+						ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
+#endif
+					{
+						DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+						DGAP_UNLOCK(bd->bd_lock, lock_flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+						(ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
+#else
+						(ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
+#endif
+						DGAP_LOCK(bd->bd_lock, lock_flags);
+						DGAP_LOCK(ch->ch_lock, lock_flags2);
+					}
+					wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+					wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+				}
+			}
+
+
+			if (ch->ch_flags & CH_WEMPTY) {
+				ch->ch_flags &= ~CH_WEMPTY;
+				wake_up_interruptible(&ch->ch_flags_wait);
+			}
+		}
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+
+next:
+		tail = (tail + 4) & (EVMAX - EVSTART - 4);
+	}
+
+	writew(tail, &(eaddr->ev_tail));
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	return (0);
+}               
diff --git a/drivers/staging/dgap/dgap_fep5.h b/drivers/staging/dgap/dgap_fep5.h
new file mode 100644
index 0000000..3a12ba5
--- /dev/null
+++ b/drivers/staging/dgap/dgap_fep5.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ ************************************************************************ 
+ ***	FEP Version 5 dependent definitions
+ ************************************************************************/
+
+#ifndef __DGAP_FEP5_H
+#define __DGAP_FEP5_H
+
+/************************************************************************
+ *      FEP memory offsets
+ ************************************************************************/
+#define START           0x0004L         /* Execution start address      */
+
+#define CMDBUF          0x0d10L         /* Command (cm_t) structure offset */
+#define CMDSTART        0x0400L         /* Start of command buffer      */   
+#define CMDMAX          0x0800L         /* End of command buffer        */
+
+#define EVBUF           0x0d18L         /* Event (ev_t) structure       */
+#define EVSTART         0x0800L         /* Start of event buffer        */
+#define EVMAX           0x0c00L         /* End of event buffer          */
+#define FEP5_PLUS       0x0E40          /* ASCII '5' and ASCII 'A' is here  */
+#define ECS_SEG         0x0E44          /* Segment of the extended channel structure */
+#define LINE_SPEED      0x10            /* Offset into ECS_SEG for line speed   */
+                                        /* if the fep has extended capabilities */
+
+/* BIOS MAGIC SPOTS */
+#define ERROR           0x0C14L		/* BIOS error code              */
+#define SEQUENCE	0x0C12L		/* BIOS sequence indicator      */
+#define POSTAREA	0x0C00L		/* POST complete message area   */
+
+/* FEP MAGIC SPOTS */
+#define FEPSTAT         POSTAREA        /* OS here when FEP comes up    */
+#define NCHAN           0x0C02L         /* number of ports FEP sees     */
+#define PANIC           0x0C10L         /* PANIC area for FEP           */
+#define KMEMEM          0x0C30L         /* Memory for KME use           */   
+#define CONFIG          0x0CD0L         /* Concentrator configuration info */
+#define CONFIGSIZE      0x0030          /* configuration info size      */
+#define DOWNREQ         0x0D00          /* Download request buffer pointer */
+
+#define CHANBUF         0x1000L         /* Async channel (bs_t) structs */
+#define FEPOSSIZE       0x1FFF          /* 8K FEPOS                     */
+
+#define XEMPORTS    0xC02	/*
+				 * Offset in board memory where FEP5 stores
+				 * how many ports it has detected.
+				 * NOTE: FEP5 reports 64 ports when the user
+				 * has the cable in EBI OUT instead of EBI IN.
+				 */
+
+#define FEPCLR      0x00
+#define FEPMEM      0x02 
+#define FEPRST      0x04 
+#define FEPINT      0x08
+#define FEPMASK     0x0e
+#define FEPWIN      0x80
+
+#define LOWMEM      0x0100
+#define HIGHMEM     0x7f00
+
+#define FEPTIMEOUT 200000
+
+#define ENABLE_INTR		0x0e04		/* Enable interrupts flag */
+#define FEPPOLL_MIN		1		/* minimum of 1 millisecond */  
+#define FEPPOLL_MAX		20		/* maximum of 20 milliseconds */
+#define FEPPOLL			0x0c26		/* Fep event poll interval */   
+
+#define	IALTPIN			0x0080		/* Input flag to swap DSR <-> DCD */
+
+/************************************************************************ 
+ * Command structure definition.
+ ************************************************************************/
+struct cm_t {
+	volatile unsigned short cm_head;	/* Command buffer head offset	*/
+	volatile unsigned short cm_tail;	/* Command buffer tail offset	*/
+	volatile unsigned short cm_start;	/* start offset of buffer	*/
+	volatile unsigned short cm_max;		/* last offset of buffer	*/
+};
+
+/************************************************************************
+ * Event structure definition.
+ ************************************************************************/
+struct ev_t {
+	volatile unsigned short ev_head;	/* Command buffer head offset	*/
+	volatile unsigned short ev_tail;	/* Command buffer tail offset	*/
+	volatile unsigned short ev_start;	/* start offset of buffer	*/
+	volatile unsigned short ev_max;		/* last offset of buffer	*/
+};
+
+/************************************************************************
+ * Download buffer structure.
+ ************************************************************************/
+struct downld_t {
+	uchar	dl_type;		/* Header                       */
+	uchar	dl_seq;			/* Download sequence            */
+	ushort	dl_srev;		/* Software revision number     */
+	ushort	dl_lrev;		/* Low revision number          */
+	ushort	dl_hrev;		/* High revision number         */
+	ushort	dl_seg;			/* Start segment address        */
+	ushort	dl_size;		/* Number of bytes to download  */
+	uchar	dl_data[1024];		/* Download data                */
+};
+
+/************************************************************************ 
+ * Per channel buffer structure
+ ************************************************************************
+ *              Base Structure Entries Usage Meanings to Host           * 
+ *                                                                      * 
+ *        W = read write        R = read only                           * 
+ *        C = changed by commands only                                  * 
+ *        U = unknown (may be changed w/o notice)                       *
+ ************************************************************************/
+struct bs_t {
+	volatile unsigned short  tp_jmp;	/* Transmit poll jump		 */
+	volatile unsigned short  tc_jmp;	/* Cooked procedure jump	 */
+	volatile unsigned short  ri_jmp;	/* Not currently used		 */
+	volatile unsigned short  rp_jmp;	/* Receive poll jump		 */
+
+	volatile unsigned short  tx_seg;	/* W  Tx segment	 */
+	volatile unsigned short  tx_head;	/* W  Tx buffer head offset	*/
+	volatile unsigned short  tx_tail;	/* R  Tx buffer tail offset	*/
+	volatile unsigned short  tx_max;	/* W  Tx buffer size - 1	 */
+ 
+	volatile unsigned short  rx_seg;	/* W  Rx segment		*/
+	volatile unsigned short  rx_head;	/* W  Rx buffer head offset	*/
+	volatile unsigned short  rx_tail;	/* R  Rx buffer tail offset	*/
+	volatile unsigned short  rx_max;	/* W  Rx buffer size - 1	 */
+
+	volatile unsigned short  tx_lw;		/* W  Tx buffer low water mark  */
+	volatile unsigned short  rx_lw;		/* W  Rx buffer low water mark  */
+	volatile unsigned short  rx_hw;		/* W  Rx buffer high water mark */
+	volatile unsigned short  incr;		/* W  Increment to next channel */
+
+	volatile unsigned short  fepdev;	/* U  SCC device base address    */
+	volatile unsigned short  edelay;	/* W  Exception delay            */
+	volatile unsigned short  blen;		/* W  Break length              */
+	volatile unsigned short  btime;		/* U  Break complete time       */
+
+	volatile unsigned short  iflag;		/* C  UNIX input flags          */
+	volatile unsigned short  oflag;		/* C  UNIX output flags         */
+	volatile unsigned short  cflag;		/* C  UNIX control flags        */
+	volatile unsigned short  wfill[13];	/* U  Reserved for expansion    */
+
+	volatile unsigned char   num;		/* U  Channel number            */
+	volatile unsigned char   ract;		/* U  Receiver active counter   */
+	volatile unsigned char   bstat;		/* U  Break status bits         */
+	volatile unsigned char   tbusy;		/* W  Transmit busy             */
+	volatile unsigned char   iempty;	/* W  Transmit empty event enable */
+	volatile unsigned char   ilow;		/* W  Transmit low-water event enable */
+	volatile unsigned char   idata;		/* W  Receive data interrupt enable */
+	volatile unsigned char   eflag;		/* U  Host event flags          */
+
+	volatile unsigned char   tflag;		/* U  Transmit flags            */
+	volatile unsigned char   rflag;		/* U  Receive flags             */
+	volatile unsigned char   xmask;		/* U  Transmit ready flags      */
+	volatile unsigned char   xval;		/* U  Transmit ready value      */
+	volatile unsigned char   m_stat;	/* RC Modem status bits          */
+	volatile unsigned char   m_change;	/* U  Modem bits which changed  */
+	volatile unsigned char   m_int;		/* W  Modem interrupt enable bits */
+	volatile unsigned char   m_last;	/* U  Last modem status         */
+
+	volatile unsigned char   mtran;		/* C   Unreported modem trans   */
+	volatile unsigned char   orun;		/* C   Buffer overrun occurred  */
+	volatile unsigned char   astartc;	/* W   Auxiliary Xon char       */  
+	volatile unsigned char   astopc;	/* W   Auxiliary Xoff char      */
+	volatile unsigned char   startc;	/* W   Xon character             */
+	volatile unsigned char   stopc;		/* W   Xoff character           */
+	volatile unsigned char   vnextc;	/* W   Vnext character           */
+	volatile unsigned char   hflow;		/* C   Software flow control    */
+
+	volatile unsigned char   fillc;		/* U   Delay Fill character     */
+	volatile unsigned char   ochar;		/* U   Saved output character   */
+	volatile unsigned char   omask;		/* U   Output character mask    */
+
+	volatile unsigned char   bfill[13];	/* U   Reserved for expansion   */  
+
+	volatile unsigned char   scc[16];	/* U   SCC registers            */
+};
+
+
+/************************************************************************   
+ * FEP supported functions
+ ************************************************************************/
+#define SRLOW		0xe0		/* Set receive low water	*/
+#define SRHIGH		0xe1		/* Set receive high water	*/
+#define FLUSHTX		0xe2		/* Flush transmit buffer	*/
+#define PAUSETX		0xe3		/* Pause data transmission	*/
+#define RESUMETX	0xe4		/* Resume data transmission	*/
+#define SMINT		0xe5		/* Set Modem Interrupt		*/
+#define SAFLOWC		0xe6		/* Set Aux. flow control chars	*/
+#define SBREAK		0xe8		/* Send break			*/
+#define SMODEM		0xe9		/* Set 8530 modem control lines	*/  
+#define SIFLAG		0xea		/* Set UNIX iflags		*/
+#define SFLOWC		0xeb		/* Set flow control characters	*/
+#define STLOW		0xec		/* Set transmit low water mark	*/
+#define RPAUSE		0xee		/* Pause recieve		*/
+#define RRESUME		0xef		/* Resume receive		*/  
+#define CHRESET		0xf0		/* Reset Channel		*/
+#define BUFSETALL	0xf2		/* Set Tx & Rx buffer size avail*/
+#define SOFLAG		0xf3		/* Set UNIX oflags		*/
+#define SHFLOW		0xf4		/* Set hardware handshake	*/
+#define SCFLAG		0xf5		/* Set UNIX cflags		*/
+#define SVNEXT		0xf6		/* Set VNEXT character		*/
+#define SPINTFC		0xfc		/* Reserved			*/
+#define SCOMMODE	0xfd		/* Set RS232/422 mode		*/
+
+
+/************************************************************************ 
+ *	Modes for SCOMMODE
+ ************************************************************************/
+#define MODE_232	0x00
+#define MODE_422	0x01
+
+
+/************************************************************************ 
+ *      Event flags.
+ ************************************************************************/
+#define IFBREAK         0x01            /* Break received               */  
+#define IFTLW           0x02            /* Transmit low water           */
+#define IFTEM           0x04            /* Transmitter empty            */
+#define IFDATA          0x08            /* Receive data present         */
+#define IFMODEM         0x20            /* Modem status change          */
+
+/************************************************************************   
+ *      Modem flags
+ ************************************************************************/
+#       define  DM_RTS          0x02    /* Request to send              */
+#       define  DM_CD           0x80    /* Carrier detect               */
+#       define  DM_DSR          0x20    /* Data set ready               */
+#       define  DM_CTS          0x10    /* Clear to send                */
+#       define  DM_RI           0x40    /* Ring indicator               */
+#       define  DM_DTR          0x01    /* Data terminal ready          */
+
+
+#endif
diff --git a/drivers/staging/dgap/dgap_kcompat.h b/drivers/staging/dgap/dgap_kcompat.h
new file mode 100644
index 0000000..8ebf4b7
--- /dev/null
+++ b/drivers/staging/dgap/dgap_kcompat.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * This file is intended to contain all the kernel "differences" between the
+ * various kernels that we support.
+ *
+ *************************************************************************/
+
+#ifndef __DGAP_KCOMPAT_H
+#define __DGAP_KCOMPAT_H
+
+# ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(a,b,c)  (((a) << 16) + ((b) << 8) + (c))
+# endif
+
+
+#if !defined(TTY_FLIPBUF_SIZE)
+# define TTY_FLIPBUF_SIZE 512
+#endif
+
+
+/* Sparse stuff */
+# ifndef __user
+#  define __user
+#  define __kernel
+#  define __safe
+#  define __force
+#  define __chk_user_ptr(x) (void)0
+# endif
+
+
+#  define PARM_STR(VAR, INIT, PERM, DESC) \
+		static char *VAR = INIT; \
+		char *dgap_##VAR; \
+		module_param(VAR, charp, PERM); \
+		MODULE_PARM_DESC(VAR, DESC);
+
+#  define PARM_INT(VAR, INIT, PERM, DESC) \
+		static int VAR = INIT; \
+		int dgap_##VAR; \
+		module_param(VAR, int, PERM); \
+		MODULE_PARM_DESC(VAR, DESC);
+
+#  define PARM_ULONG(VAR, INIT, PERM, DESC) \
+		static ulong VAR = INIT; \
+		ulong dgap_##VAR; \
+		module_param(VAR, long, PERM); \
+		MODULE_PARM_DESC(VAR, DESC);
+
+
+
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+
+
+
+
+/* NOTHING YET */
+
+
+
+
+# else
+
+
+
+# error "this driver does not support anything below the 2.6.27 kernel series."
+
+
+
+# endif
+
+#endif /* ! __DGAP_KCOMPAT_H */
diff --git a/drivers/staging/dgap/dgap_parse.c b/drivers/staging/dgap/dgap_parse.c
new file mode 100644
index 0000000..5497e6d
--- /dev/null
+++ b/drivers/staging/dgap/dgap_parse.c
@@ -0,0 +1,1371 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE! 
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com. 
+ *	Thank you.
+ *
+ *
+ *****************************************************************************
+ *
+ * dgap_parse.c - Parses the configuration information from the input file.
+ *
+ * $Id: dgap_parse.c,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#include "dgap_types.h"
+#include "dgap_fep5.h"
+#include "dgap_driver.h"
+#include "dgap_conf.h"
+
+
+/*
+ * Function prototypes.
+ */
+static int dgap_gettok(char **in, struct cnode *p);
+static char *dgap_getword(char **in);
+static char *dgap_savestring(char *s);
+static struct cnode *dgap_newnode(int t);
+static int dgap_checknode(struct cnode *p);
+static void dgap_err(char *s);
+
+/*
+ * Our needed internal static variables...
+ */
+static struct cnode dgap_head;
+#define MAXCWORD 200
+static char dgap_cword[MAXCWORD];
+
+struct toklist {
+	int	token;
+	char	*string;
+};
+
+static struct toklist dgap_tlist[] = {
+	{	BEGIN,		"config_begin"			},
+	{	END,		"config_end"			},
+	{	BOARD,		"board"				},
+	{	PCX,		"Digi_AccelePort_C/X_PCI"	},	/* C/X_PCI */
+	{	PEPC,		"Digi_AccelePort_EPC/X_PCI"	},	/* EPC/X_PCI */
+	{	PPCM,		"Digi_AccelePort_Xem_PCI"	},	/* PCI/Xem */
+	{	APORT2_920P,	"Digi_AccelePort_2r_920_PCI"	},
+	{	APORT4_920P,	"Digi_AccelePort_4r_920_PCI"	},
+	{	APORT8_920P,	"Digi_AccelePort_8r_920_PCI"	},
+	{	PAPORT4,	"Digi_AccelePort_4r_PCI(EIA-232/RS-422)" },
+	{	PAPORT8,	"Digi_AccelePort_8r_PCI(EIA-232/RS-422)" },
+	{	IO,		"io"				},
+	{	PCIINFO,	"pciinfo"			},
+	{	LINE,		"line"				},
+	{	CONC,		"conc"				},
+	{	CONC,		"concentrator"			},
+	{	CX,		"cx"				},
+	{	CX,		"ccon"				},
+	{	EPC,		"epccon"			},
+	{	EPC,		"epc"				},
+	{	MOD,		"module"			},
+	{	ID,		"id"				},
+	{	STARTO,		"start"				},
+	{	SPEED,		"speed"				},
+	{	CABLE,		"cable"				},
+	{	CONNECT,	"connect"			},
+	{	METHOD,		"method"			},
+	{	STATUS,		"status"			},
+	{	CUSTOM,		"Custom"			},
+	{	BASIC,		"Basic"				},
+	{	MEM,		"mem"				},
+	{	MEM,		"memory"			},
+	{	PORTS,		"ports"				},
+	{	MODEM,		"modem"				},
+	{	NPORTS,		"nports"			},
+	{	TTYN,		"ttyname"			},
+	{	CU,		"cuname"			},
+	{	PRINT,		"prname"			},
+	{	CMAJOR,		"major"				},
+	{	ALTPIN,		"altpin"			},
+	{	USEINTR,	"useintr"			},
+	{	TTSIZ,		"ttysize"			},
+	{	CHSIZ,		"chsize"			},
+	{	BSSIZ,		"boardsize"			},
+	{	UNTSIZ,		"schedsize"			},
+	{	F2SIZ,		"f2200size"			},
+	{	VPSIZ,		"vpixsize"			},
+	{	0,		NULL				}
+};
+
+
+/*
+ * Parse a configuration file read into memory as a string.
+ */
+int	dgap_parsefile(char **in, int Remove)
+{
+	struct cnode *p, *brd, *line, *conc;
+	int	rc;
+	char	*s = NULL, *s2 = NULL;
+	int	linecnt = 0;
+
+	p = &dgap_head;
+	brd = line = conc = NULL;
+
+	/* perhaps we are adding to an existing list? */
+	while (p->next != NULL) {
+		p = p->next;
+	}
+
+	/* file must start with a BEGIN */
+	while ( (rc = dgap_gettok(in,p)) != BEGIN ) {
+		if (rc == 0) {
+			dgap_err("unexpected EOF");
+			return(-1);
+		}
+	}
+
+	for (; ; ) {
+		rc = dgap_gettok(in,p);
+		if (rc == 0) {
+			dgap_err("unexpected EOF");
+			return(-1);
+		}
+
+		switch (rc) {
+		case 0:
+			dgap_err("unexpected end of file");
+			return(-1);
+
+		case BEGIN:	/* should only be 1 begin */
+			dgap_err("unexpected config_begin\n");
+			return(-1);
+
+		case END:
+			return(0);
+
+		case BOARD:	/* board info */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(BNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+
+			p->u.board.status = dgap_savestring("No");
+			line = conc = NULL;
+			brd = p;
+			linecnt = -1;
+			break;
+
+		case APORT2_920P:	/* AccelePort_4 */
+			if (p->type != BNODE) {
+				dgap_err("unexpected Digi_2r_920 string");
+				return(-1);
+			}
+			p->u.board.type = APORT2_920P;
+			p->u.board.v_type = 1;
+			DPR_INIT(("Adding Digi_2r_920 PCI to config...\n"));
+			break;
+
+		case APORT4_920P:	/* AccelePort_4 */
+			if (p->type != BNODE) {
+				dgap_err("unexpected Digi_4r_920 string");
+				return(-1);
+			}
+			p->u.board.type = APORT4_920P;
+			p->u.board.v_type = 1;
+			DPR_INIT(("Adding Digi_4r_920 PCI to config...\n"));
+			break;
+
+		case APORT8_920P:	/* AccelePort_8 */
+			if (p->type != BNODE) {
+				dgap_err("unexpected Digi_8r_920 string");
+				return(-1);
+			}
+			p->u.board.type = APORT8_920P;
+			p->u.board.v_type = 1;
+			DPR_INIT(("Adding Digi_8r_920 PCI to config...\n"));
+			break;
+
+		case PAPORT4:	/* AccelePort_4 PCI */
+			if (p->type != BNODE) {
+				dgap_err("unexpected Digi_4r(PCI) string");
+				return(-1);
+			}
+			p->u.board.type = PAPORT4;
+			p->u.board.v_type = 1;
+			DPR_INIT(("Adding Digi_4r PCI to config...\n"));
+			break;
+
+		case PAPORT8:	/* AccelePort_8 PCI */
+			if (p->type != BNODE) {
+				dgap_err("unexpected Digi_8r string");
+				return(-1);
+			}
+			p->u.board.type = PAPORT8;
+			p->u.board.v_type = 1;
+			DPR_INIT(("Adding Digi_8r PCI to config...\n"));
+			break;
+
+		case PCX:	/* PCI C/X */
+			if (p->type != BNODE) {
+				dgap_err("unexpected Digi_C/X_(PCI) string");
+				return(-1);
+			}
+			p->u.board.type = PCX;
+			p->u.board.v_type = 1;
+			p->u.board.conc1 = 0;
+			p->u.board.conc2 = 0;
+			p->u.board.module1 = 0;
+			p->u.board.module2 = 0;
+			DPR_INIT(("Adding PCI C/X to config...\n"));
+			break;
+
+		case PEPC:	/* PCI EPC/X */
+			if (p->type != BNODE) {
+				dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string");
+				return(-1);
+			}
+			p->u.board.type = PEPC;
+			p->u.board.v_type = 1;
+			p->u.board.conc1 = 0;
+			p->u.board.conc2 = 0;
+			p->u.board.module1 = 0;
+			p->u.board.module2 = 0;
+			DPR_INIT(("Adding PCI EPC/X to config...\n"));
+			break;
+
+		case PPCM:	/* PCI/Xem */
+			if (p->type != BNODE) {
+				dgap_err("unexpected PCI/Xem string");
+				return(-1);
+			}
+			p->u.board.type = PPCM;
+			p->u.board.v_type = 1;
+			p->u.board.conc1 = 0;
+			p->u.board.conc2 = 0;
+			DPR_INIT(("Adding PCI XEM to config...\n"));
+			break;
+
+		case IO:	/* i/o port */
+			if (p->type != BNODE) {
+				dgap_err("IO port only vaild for boards");
+				return(-1);
+			}
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.board.portstr = dgap_savestring(s);
+			p->u.board.port = (short)simple_strtol(s, &s2, 0);
+			if ((short)strlen(s) > (short)(s2 - s)) {
+				dgap_err("bad number for IO port");
+				return(-1);
+			}
+			p->u.board.v_port = 1;
+			DPR_INIT(("Adding IO (%s) to config...\n", s));
+			break;
+
+		case MEM:	/* memory address */
+			if (p->type != BNODE) {
+				dgap_err("memory address only vaild for boards");
+				return(-1);
+			}
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.board.addrstr = dgap_savestring(s);
+			p->u.board.addr = simple_strtoul(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for memory address");
+				return(-1);
+			}
+			p->u.board.v_addr = 1;
+			DPR_INIT(("Adding MEM (%s) to config...\n", s));
+			break;
+
+		case PCIINFO:	/* pci information */
+			if (p->type != BNODE) {
+				dgap_err("memory address only vaild for boards");
+				return(-1);
+			}
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.board.pcibusstr = dgap_savestring(s);
+			p->u.board.pcibus = simple_strtoul(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for pci bus");
+				return(-1);
+			}
+			p->u.board.v_pcibus = 1;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.board.pcislotstr = dgap_savestring(s);
+			p->u.board.pcislot = simple_strtoul(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for pci slot");
+				return(-1);
+			}
+			p->u.board.v_pcislot = 1;
+
+			DPR_INIT(("Adding PCIINFO (%s %s) to config...\n", p->u.board.pcibusstr, 
+				p->u.board.pcislotstr));
+			break;
+
+		case METHOD:
+			if (p->type != BNODE) {
+				dgap_err("install method only vaild for boards");
+				return(-1);
+			}
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.board.method = dgap_savestring(s);
+			p->u.board.v_method = 1;
+			DPR_INIT(("Adding METHOD (%s) to config...\n", s));
+			break;
+
+		case STATUS:
+			if (p->type != BNODE) {
+				dgap_err("config status only vaild for boards");
+				return(-1);
+			}
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.board.status = dgap_savestring(s);
+			DPR_INIT(("Adding STATUS (%s) to config...\n", s));
+			break;
+
+		case NPORTS:	/* number of ports */
+			if (p->type == BNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.board.nport = (char)simple_strtol(s, &s2, 0);
+				if ((int)strlen(s) > (int)(s2 - s)) {
+					dgap_err("bad number for number of ports");
+					return(-1);
+				}
+				p->u.board.v_nport = 1;
+			} else if (p->type == CNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.conc.nport = (char)simple_strtol(s, &s2, 0);
+				if ((int)strlen(s) > (int)(s2 - s)) {
+					dgap_err("bad number for number of ports");
+					return(-1);
+				}
+				p->u.conc.v_nport = 1;
+			} else if (p->type == MNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.module.nport = (char)simple_strtol(s, &s2, 0);
+				if ((int)strlen(s) > (int)(s2 - s)) {
+					dgap_err("bad number for number of ports");
+					return(-1);
+				}
+				p->u.module.v_nport = 1;
+			} else {
+				dgap_err("nports only valid for concentrators or modules");
+				return(-1);
+			}
+			DPR_INIT(("Adding NPORTS (%s) to config...\n", s));
+			break;
+
+		case ID:	/* letter ID used in tty name */
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+
+			p->u.board.status = dgap_savestring(s);
+
+			if (p->type == CNODE) {
+				p->u.conc.id = dgap_savestring(s);
+				p->u.conc.v_id = 1;
+			} else if (p->type == MNODE) {
+				p->u.module.id = dgap_savestring(s);
+				p->u.module.v_id = 1;
+			} else {
+				dgap_err("id only valid for concentrators or modules");
+				return(-1);
+			}
+			DPR_INIT(("Adding ID (%s) to config...\n", s));
+			break;
+
+		case STARTO:	/* start offset of ID */
+			if (p->type == BNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.board.start = simple_strtol(s, &s2, 0);
+				if ((int)strlen(s) > (int)(s2 - s)) {
+					dgap_err("bad number for start of tty count");
+					return(-1);
+				}
+				p->u.board.v_start = 1;
+			} else if (p->type == CNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.conc.start = simple_strtol(s, &s2, 0);
+				if ((int)strlen(s) > (int)(s2 - s)) {
+					dgap_err("bad number for start of tty count");
+					return(-1);
+				}
+				p->u.conc.v_start = 1;
+			} else if (p->type == MNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.module.start = simple_strtol(s, &s2, 0);
+				if ((int)strlen(s) > (int)(s2 - s)) {
+					dgap_err("bad number for start of tty count");
+					return(-1);
+				}
+				p->u.module.v_start = 1;
+			} else {
+				dgap_err("start only valid for concentrators or modules");
+				return(-1);
+			}
+			DPR_INIT(("Adding START (%s) to config...\n", s));
+			break;
+
+		case TTYN:	/* tty name prefix */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(TNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			if ( (s = dgap_getword(in)) == NULL ) {
+				dgap_err("unexpeced end of file");
+				return(-1);
+			}
+			if ( (p->u.ttyname = dgap_savestring(s)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			DPR_INIT(("Adding TTY (%s) to config...\n", s));
+			break;
+
+		case CU:	/* cu name prefix */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(CUNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			if ( (s = dgap_getword(in)) == NULL ) {
+				dgap_err("unexpeced end of file");
+				return(-1);
+			}
+			if ( (p->u.cuname = dgap_savestring(s)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			DPR_INIT(("Adding CU (%s) to config...\n", s));
+			break;
+
+		case LINE:	/* line information */
+			if (dgap_checknode(p))
+				return(-1);
+			if (brd == NULL) {
+				dgap_err("must specify board before line info");
+				return(-1);
+			}
+			switch (brd->u.board.type) {
+			case PPCM:
+				dgap_err("line not vaild for PC/em");
+				return(-1);
+			}
+			if ( (p->next = dgap_newnode(LNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			conc = NULL;
+			line = p;
+			linecnt++;
+			DPR_INIT(("Adding LINE to config...\n"));
+			break;
+
+		case CONC:	/* concentrator information */
+			if (dgap_checknode(p))
+				return(-1);
+			if (line == NULL) {
+				dgap_err("must specify line info before concentrator");
+				return(-1);
+			}
+			if ( (p->next = dgap_newnode(CNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			conc = p;
+			if (linecnt)
+				brd->u.board.conc2++;
+			else
+				brd->u.board.conc1++;
+
+			DPR_INIT(("Adding CONC to config...\n"));
+			break;
+
+		case CX:	/* c/x type concentrator */
+			if (p->type != CNODE) {
+				dgap_err("cx only valid for concentrators");
+				return(-1);
+			}
+			p->u.conc.type = CX;
+			p->u.conc.v_type = 1;
+			DPR_INIT(("Adding CX to config...\n"));
+			break;
+
+		case EPC:	/* epc type concentrator */
+			if (p->type != CNODE) {
+				dgap_err("cx only valid for concentrators");
+				return(-1);
+			}
+			p->u.conc.type = EPC;
+			p->u.conc.v_type = 1;
+			DPR_INIT(("Adding EPC to config...\n"));
+			break;
+
+		case MOD:	/* EBI module */
+			if (dgap_checknode(p))
+				return(-1);
+			if (brd == NULL) {
+				dgap_err("must specify board info before EBI modules");
+				return(-1);
+			}
+			switch (brd->u.board.type) {
+			case PPCM:
+				linecnt = 0;
+				break;
+			default:
+				if (conc == NULL) {
+					dgap_err("must specify concentrator info before EBI module");
+					return(-1);
+				}
+			}
+			if ( (p->next = dgap_newnode(MNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			if (linecnt)
+				brd->u.board.module2++;
+			else
+				brd->u.board.module1++;
+
+			DPR_INIT(("Adding MOD to config...\n"));
+			break;
+
+		case PORTS:	/* ports type EBI module */
+			if (p->type != MNODE) {
+				dgap_err("ports only valid for EBI modules");
+				return(-1);
+			}
+			p->u.module.type = PORTS;
+			p->u.module.v_type = 1;
+			DPR_INIT(("Adding PORTS to config...\n"));
+			break;
+
+		case MODEM:	/* ports type EBI module */
+			if (p->type != MNODE) {
+				dgap_err("modem only valid for modem modules");
+				return(-1);
+			}
+			p->u.module.type = MODEM;
+			p->u.module.v_type = 1;
+			DPR_INIT(("Adding MODEM to config...\n"));
+			break;
+
+		case CABLE:
+			if (p->type == LNODE) {
+				if ((s = dgap_getword(in)) == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.line.cable = dgap_savestring(s);
+				p->u.line.v_cable = 1;
+			}
+			DPR_INIT(("Adding CABLE (%s) to config...\n", s));
+			break;
+
+		case SPEED:	/* sync line speed indication */
+			if (p->type == LNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.line.speed = (char)simple_strtol(s, &s2, 0);
+				if ((short)strlen(s) > (short)(s2 - s)) {
+					dgap_err("bad number for line speed");
+					return(-1);
+				}
+				p->u.line.v_speed = 1;
+			} else if (p->type == CNODE) {
+				s = dgap_getword(in);
+				if (s == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.conc.speed = (char)simple_strtol(s, &s2, 0);
+				if ((short)strlen(s) > (short)(s2 - s)) {
+					dgap_err("bad number for line speed");
+					return(-1);
+				}
+				p->u.conc.v_speed = 1;
+			} else {
+				dgap_err("speed valid only for lines or concentrators.");
+				return(-1);
+			}
+			DPR_INIT(("Adding SPEED (%s) to config...\n", s));
+			break;
+
+		case CONNECT:
+			if (p->type == CNODE) {
+				if ((s = dgap_getword(in)) == NULL) {
+					dgap_err("unexpected end of file");
+					return(-1);
+				}
+				p->u.conc.connect = dgap_savestring(s);
+				p->u.conc.v_connect = 1;
+			}
+			DPR_INIT(("Adding CONNECT (%s) to config...\n", s));
+			break;
+		case PRINT:	/* transparent print name prefix */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(PNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			if ( (s = dgap_getword(in)) == NULL ) {
+				dgap_err("unexpeced end of file");
+				return(-1);
+			}
+			if ( (p->u.printname = dgap_savestring(s)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			DPR_INIT(("Adding PRINT (%s) to config...\n", s));
+			break;
+
+		case CMAJOR:	/* major number */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(JNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.majornumber = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for major number");
+				return(-1);
+			}
+			DPR_INIT(("Adding CMAJOR (%s) to config...\n", s));
+			break;
+
+		case ALTPIN:	/* altpin setting */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(ANODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.altpin = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for altpin");
+				return(-1);
+			}
+			DPR_INIT(("Adding ALTPIN (%s) to config...\n", s));
+			break;
+
+		case USEINTR:		/* enable interrupt setting */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(INTRNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.useintr = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for useintr");
+				return(-1);
+			}
+			DPR_INIT(("Adding USEINTR (%s) to config...\n", s));
+			break;
+
+		case TTSIZ:	/* size of tty structure */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(TSNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.ttysize = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for ttysize");
+				return(-1);
+			}
+			DPR_INIT(("Adding TTSIZ (%s) to config...\n", s));
+			break;
+
+		case CHSIZ:	/* channel structure size */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(CSNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.chsize = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for chsize");
+				return(-1);
+			}
+			DPR_INIT(("Adding CHSIZE (%s) to config...\n", s));
+			break;
+
+		case BSSIZ:	/* board structure size */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(BSNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.bssize = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for bssize");
+				return(-1);
+			}
+			DPR_INIT(("Adding BSSIZ (%s) to config...\n", s));
+			break;
+
+		case UNTSIZ:	/* sched structure size */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(USNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.unsize = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for schedsize");
+				return(-1);
+			}
+			DPR_INIT(("Adding UNTSIZ (%s) to config...\n", s));
+			break;
+
+		case F2SIZ:	/* f2200 structure size */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(FSNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.f2size = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for f2200size");
+				return(-1);
+			}
+			DPR_INIT(("Adding F2SIZ (%s) to config...\n", s));
+			break;
+
+		case VPSIZ:	/* vpix structure size */
+			if (dgap_checknode(p))
+				return(-1);
+			if ( (p->next = dgap_newnode(VSNODE)) == NULL ) {
+				dgap_err("out of memory");
+				return(-1);
+			}
+			p = p->next;
+			s = dgap_getword(in);
+			if (s == NULL) {
+				dgap_err("unexpected end of file");
+				return(-1);
+			}
+			p->u.vpixsize = simple_strtol(s, &s2, 0);
+			if ((int)strlen(s) > (int)(s2 - s)) {
+				dgap_err("bad number for vpixsize");
+				return(-1);
+			}
+			DPR_INIT(("Adding VPSIZ (%s) to config...\n", s));
+			break;
+		}
+	}
+}
+
+
+/*
+ * dgap_sindex: much like index(), but it looks for a match of any character in
+ * the group, and returns that position.  If the first character is a ^, then
+ * this will match the first occurence not in that group.
+ */
+static char *dgap_sindex (char *string, char *group)
+{
+	char    *ptr;
+
+	if (!string || !group)
+		return (char *) NULL;
+
+	if (*group == '^') {   
+		group++;
+		for (; *string; string++) {
+			for (ptr = group; *ptr; ptr++) {
+				if (*ptr == *string)
+					break;
+			}
+			if (*ptr == '\0')
+				return string;
+		}
+	}   
+	else {
+		for (; *string; string++) {
+			for (ptr = group; *ptr; ptr++) {
+				if (*ptr == *string)
+					return string;
+			}
+		}
+	}
+
+	return (char *) NULL;
+}
+
+
+/*
+ * Get a token from the input file; return 0 if end of file is reached
+ */
+static int dgap_gettok(char **in, struct cnode *p)
+{
+	char	*w;
+	struct toklist *t;
+	
+	if (strstr(dgap_cword, "boar")) {
+		w = dgap_getword(in);
+		snprintf(dgap_cword, MAXCWORD, "%s", w);
+		for (t = dgap_tlist; t->token != 0; t++) {
+			if ( !strcmp(w, t->string)) {
+				return(t->token);
+			} 
+		}
+		dgap_err("board !!type not specified");
+		return(1);
+	}
+	else {
+		while ( (w = dgap_getword(in)) != NULL ) {
+			snprintf(dgap_cword, MAXCWORD, "%s", w);
+			for (t = dgap_tlist; t->token != 0; t++) {
+				if ( !strcmp(w, t->string) )
+					return(t->token);
+			}
+		}
+		return(0);
+	}
+}
+
+
+/*
+ * get a word from the input stream, also keep track of current line number.
+ * words are separated by whitespace.
+ */
+static char *dgap_getword(char **in)
+{
+	char *ret_ptr = *in;
+
+        char *ptr = dgap_sindex(*in, " \t\n");
+
+	/* If no word found, return null */
+	if (!ptr)
+		return NULL;
+
+	/* Mark new location for our buffer */
+	*ptr = '\0';
+	*in = ptr + 1;
+
+	/* Eat any extra spaces/tabs/newlines that might be present */
+	while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) {
+		**in = '\0';
+		*in = *in + 1;
+	}
+
+	return ret_ptr;
+}
+
+
+/*
+ * print an error message, giving the line number in the file where
+ * the error occurred.
+ */
+static void dgap_err(char *s)
+{
+	printk("DGAP: parse: %s\n", s);
+}
+
+
+/*
+ * allocate a new configuration node of type t
+ */
+static struct cnode *dgap_newnode(int t)
+{
+	struct cnode *n;
+	if ( (n = (struct cnode *) kmalloc(sizeof(struct cnode ), GFP_ATOMIC) ) != NULL) {
+		memset( (char *)n, 0, sizeof(struct cnode ) );
+		n->type = t;
+	}
+	return(n);
+}
+
+
+/*
+ * dgap_checknode: see if all the necessary info has been supplied for a node
+ * before creating the next node.
+ */
+static int dgap_checknode(struct cnode *p)
+{
+	switch (p->type) {
+	case BNODE:
+		if (p->u.board.v_type == 0) {
+			dgap_err("board type !not specified");
+			return(1);
+		}
+
+		return(0);
+
+	case LNODE:
+		if (p->u.line.v_speed == 0) {
+			dgap_err("line speed not specified");
+			return(1);
+		}
+		return(0);
+
+	case CNODE:
+		if (p->u.conc.v_type == 0) {
+			dgap_err("concentrator type not specified");
+			return(1);
+		}
+		if (p->u.conc.v_speed == 0) {
+			dgap_err("concentrator line speed not specified");
+			return(1);
+		}
+		if (p->u.conc.v_nport == 0) {
+			dgap_err("number of ports on concentrator not specified");
+			return(1);
+		}
+		if (p->u.conc.v_id == 0) {
+			dgap_err("concentrator id letter not specified");
+			return(1);
+		}
+		return(0);
+
+	case MNODE:
+		if (p->u.module.v_type == 0) {
+			dgap_err("EBI module type not specified");
+			return(1);
+		}
+		if (p->u.module.v_nport == 0) {
+			dgap_err("number of ports on EBI module not specified");
+			return(1);
+		}
+		if (p->u.module.v_id == 0) {
+			dgap_err("EBI module id letter not specified");
+			return(1);
+		}
+		return(0);
+	}
+	return(0);
+}
+
+/*
+ * save a string somewhere
+ */
+static char	*dgap_savestring(char *s)
+{
+	char	*p;
+	if ( (p = kmalloc(strlen(s) + 1, GFP_ATOMIC) ) != NULL) {
+		strcpy(p, s);
+	}
+	return(p);
+}
+
+
+/*
+ * Given a board pointer, returns whether we should use interrupts or not.
+ */
+uint dgap_config_get_useintr(struct board_t *bd)
+{
+	struct cnode *p = NULL;
+
+	if (!bd)
+		return(0);
+
+	for (p = bd->bd_config; p; p = p->next) {
+		switch (p->type) {
+		case INTRNODE:
+			/*
+			 * check for pcxr types.
+			 */
+			return p->u.useintr;
+		default:
+			break;
+		}
+	}
+
+	/* If not found, then don't turn on interrupts. */
+	return 0;
+}
+
+
+/*
+ * Given a board pointer, returns whether we turn on altpin or not.
+ */
+uint dgap_config_get_altpin(struct board_t *bd)
+{
+	struct cnode *p = NULL;
+
+	if (!bd)
+		return(0);
+
+	for (p = bd->bd_config; p; p = p->next) {
+		switch (p->type) {
+		case ANODE:
+			/*
+			 * check for pcxr types.
+			 */
+			return p->u.altpin;
+		default:
+			break;
+		}
+	}
+
+	/* If not found, then don't turn on interrupts. */
+	return 0;
+}
+
+
+
+/*
+ * Given a specific type of board, if found, detached link and 
+ * returns the first occurance in the list.
+ */
+struct cnode *dgap_find_config(int type, int bus, int slot)
+{
+	struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL;
+
+	p = &dgap_head;
+
+	while (p->next != NULL) {
+		prev = p;
+		p = p->next;
+
+		if (p->type == BNODE) {
+
+			if (p->u.board.type == type) {
+
+				if (p->u.board.v_pcibus && p->u.board.pcibus != bus) {
+					DPR(("Found matching board, but wrong bus position. System says bus %d, we want bus %ld\n",
+						bus, p->u.board.pcibus));
+					continue;
+				}
+				if (p->u.board.v_pcislot && p->u.board.pcislot != slot) {
+					DPR_INIT(("Found matching board, but wrong slot position. System says slot %d, we want slot %ld\n",
+						slot, p->u.board.pcislot));
+					continue;
+				}
+
+				DPR_INIT(("Matched type in config file\n"));
+
+				found = p;
+				/*
+				 * Keep walking thru the list till we find the next board.
+				 */
+				while (p->next != NULL) {
+					prev2 = p;
+					p = p->next;
+					if (p->type == BNODE) {
+
+						/*
+						 * Mark the end of our 1 board chain of configs.
+						 */
+						prev2->next = NULL;
+
+						/*
+						 * Link the "next" board to the previous board,
+						 * effectively "unlinking" our board from the main config.
+						 */
+						prev->next = p;
+
+						return found;
+					}
+				}
+				/*
+				 * It must be the last board in the list.
+				 */
+				prev->next = NULL;
+				return found;
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Given a board pointer, walks the config link, counting up
+ * all ports user specified should be on the board.
+ * (This does NOT mean they are all actually present right now tho)
+ */
+uint dgap_config_get_number_of_ports(struct board_t *bd)
+{
+	int count = 0;
+	struct cnode *p = NULL;
+
+	if (!bd)
+		return(0);
+
+	for (p = bd->bd_config; p; p = p->next) {
+
+		switch (p->type) {
+		case BNODE:
+			/*
+			 * check for pcxr types.
+			 */
+			if (p->u.board.type > EPCFE)
+				count += p->u.board.nport;
+			break;
+		case CNODE:
+			count += p->u.conc.nport;
+			break;
+		case MNODE:
+			count += p->u.module.nport;
+			break;
+		}
+	}
+	return (count);
+}
+
+char *dgap_create_config_string(struct board_t *bd, char *string)
+{
+	char *ptr = string;
+	struct cnode *p = NULL;
+	struct cnode *q = NULL;
+	int speed;
+
+	if (!bd) {
+		*ptr = 0xff;
+		return string;
+	}
+
+	for (p = bd->bd_config; p; p = p->next) {
+
+		switch (p->type) {
+		case LNODE:
+			*ptr = '\0';
+			ptr++;
+			*ptr = p->u.line.speed;
+			ptr++;
+			break;
+		case CNODE:
+			/*
+			 * Because the EPC/con concentrators can have EM modules
+			 * hanging off of them, we have to walk ahead in the list
+			 * and keep adding the number of ports on each EM to the config.
+			 * UGH!
+			 */
+			speed = p->u.conc.speed;
+			q = p->next;
+			if ((q != NULL) && (q->type == MNODE) ) {
+				*ptr = (p->u.conc.nport + 0x80);
+				ptr++;
+				p = q;
+				while ((q->next != NULL) && (q->next->type) == MNODE) {
+					*ptr = (q->u.module.nport + 0x80);
+					ptr++;
+					p = q;
+					q = q->next;
+				}
+				*ptr = q->u.module.nport;
+				ptr++;
+			} else {
+				*ptr = p->u.conc.nport;
+				ptr++;
+			}
+
+			*ptr = speed;
+			ptr++;
+			break;
+		}
+	}
+
+	*ptr = 0xff;
+	return string;
+}
+
+
+
+char *dgap_get_config_letters(struct board_t *bd, char *string)
+{
+	int found = FALSE;
+	char *ptr = string;
+	struct cnode *cptr = NULL;
+	int len = 0;
+	int left = MAXTTYNAMELEN;
+
+	if (!bd) {
+		return "<NULL>";
+	}
+
+	for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
+
+		if ((cptr->type == BNODE) &&
+		     ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
+		     (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
+		     (cptr->u.board.type == PAPORT8))) {
+
+			found = TRUE;
+		}
+
+		if (cptr->type == TNODE && found == TRUE) {
+			char *ptr1;
+			if (strstr(cptr->u.ttyname, "tty")) {
+				ptr1 = cptr->u.ttyname;
+				ptr1 += 3;
+			}
+			else {
+				ptr1 = cptr->u.ttyname;
+			}
+			if (ptr1) {
+				len = snprintf(ptr, left, "%s", ptr1);
+				left -= len;
+				ptr  += len;
+				if (left <= 0)
+					break;
+			}
+		}
+
+		if (cptr->type == CNODE) {
+			if (cptr->u.conc.id) {
+				len = snprintf(ptr, left, "%s", cptr->u.conc.id);
+				left -= len;
+				ptr  += len;
+				if (left <= 0)
+					break;
+			}
+                }
+
+		if (cptr->type == MNODE) {
+			if (cptr->u.module.id) {
+				len = snprintf(ptr, left, "%s", cptr->u.module.id);
+				left -= len;
+				ptr  += len;
+				if (left <= 0)
+					break;
+			}
+		}
+	}
+
+	return string;
+}
diff --git a/drivers/staging/dgap/dgap_parse.h b/drivers/staging/dgap/dgap_parse.h
new file mode 100644
index 0000000..8128c47
--- /dev/null
+++ b/drivers/staging/dgap/dgap_parse.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef _DGAP_PARSE_H
+#define _DGAP_PARSE_H
+
+#include "dgap_driver.h"
+
+extern int dgap_parsefile(char **in, int Remove);
+extern struct cnode *dgap_find_config(int type, int bus, int slot);
+extern uint dgap_config_get_number_of_ports(struct board_t *bd);
+extern char *dgap_create_config_string(struct board_t *bd, char *string);
+extern char *dgap_get_config_letters(struct board_t *bd, char *string);
+extern uint dgap_config_get_useintr(struct board_t *bd);
+extern uint dgap_config_get_altpin(struct board_t *bd);
+
+#endif
diff --git a/drivers/staging/dgap/dgap_pci.h b/drivers/staging/dgap/dgap_pci.h
new file mode 100644
index 0000000..05ed374
--- /dev/null
+++ b/drivers/staging/dgap/dgap_pci.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+/* $Id: dgap_pci.h,v 1.1 2009/10/23 14:01:57 markh Exp $ */
+
+#ifndef __DGAP_PCI_H
+#define __DGAP_PCI_H
+
+#define PCIMAX 32			/* maximum number of PCI boards */
+
+#define DIGI_VID		0x114F
+
+#define PCI_DEVICE_EPC_DID	0x0002
+#define PCI_DEVICE_XEM_DID	0x0004
+#define PCI_DEVICE_XR_DID	0x0005
+#define PCI_DEVICE_CX_DID	0x0006
+#define PCI_DEVICE_XRJ_DID	0x0009	/* PLX-based Xr adapter */
+#define PCI_DEVICE_XR_IBM_DID	0x0011	/* IBM 8-port Async Adapter */
+#define PCI_DEVICE_XR_BULL_DID	0x0013	/* BULL 8-port Async Adapter */
+#define PCI_DEVICE_XR_SAIP_DID	0x001c	/* SAIP card - Xr adapter */
+#define PCI_DEVICE_XR_422_DID	0x0012	/* Xr-422 */
+#define PCI_DEVICE_920_2_DID	0x0034	/* XR-Plus 920 K, 2 port */
+#define PCI_DEVICE_920_4_DID	0x0026	/* XR-Plus 920 K, 4 port */
+#define PCI_DEVICE_920_8_DID	0x0027	/* XR-Plus 920 K, 8 port */
+#define PCI_DEVICE_EPCJ_DID	0x000a	/* PLX 9060 chip for PCI  */
+#define PCI_DEVICE_CX_IBM_DID	0x001b	/* IBM 128-port Async Adapter */
+#define PCI_DEVICE_920_8_HP_DID	0x0058	/* HP XR-Plus 920 K, 8 port */
+#define PCI_DEVICE_XEM_HP_DID	0x0059  /* HP Xem PCI */
+
+#define PCI_DEVICE_XEM_NAME	"AccelePort XEM"
+#define PCI_DEVICE_CX_NAME	"AccelePort CX"
+#define PCI_DEVICE_XR_NAME	"AccelePort Xr"
+#define PCI_DEVICE_XRJ_NAME	"AccelePort Xr (PLX)"
+#define PCI_DEVICE_XR_SAIP_NAME	"AccelePort Xr (SAIP)"
+#define PCI_DEVICE_920_2_NAME	"AccelePort Xr920 2 port"
+#define PCI_DEVICE_920_4_NAME	"AccelePort Xr920 4 port"
+#define PCI_DEVICE_920_8_NAME	"AccelePort Xr920 8 port"
+#define PCI_DEVICE_XR_422_NAME	"AccelePort Xr 422"
+#define PCI_DEVICE_EPCJ_NAME	"AccelePort EPC (PLX)"
+#define PCI_DEVICE_XR_BULL_NAME	"AccelePort Xr (BULL)"
+#define PCI_DEVICE_XR_IBM_NAME	"AccelePort Xr (IBM)"
+#define PCI_DEVICE_CX_IBM_NAME	"AccelePort CX (IBM)"
+#define PCI_DEVICE_920_8_HP_NAME "AccelePort Xr920 8 port (HP)"
+#define PCI_DEVICE_XEM_HP_NAME	"AccelePort XEM (HP)"
+
+
+/*
+ * On the PCI boards, there is no IO space allocated
+ * The I/O registers will be in the first 3 bytes of the
+ * upper 2MB of the 4MB memory space.  The board memory
+ * will be mapped into the low 2MB of the 4MB memory space
+ */
+
+/* Potential location of PCI Bios from E0000 to FFFFF*/
+#define PCI_BIOS_SIZE		0x00020000
+
+/* Size of Memory and I/O for PCI (4MB) */
+#define PCI_RAM_SIZE		0x00400000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE		0x00200000
+
+/* Max PCI Window Size (2MB) */
+#define PCI_WIN_SIZE		0x00200000
+
+#define PCI_WIN_SHIFT		21 /* 21 bits max */
+
+/* Offset of I/0 in Memory (2MB) */
+#define PCI_IO_OFFSET		0x00200000
+
+/* Size of IO (2MB) */
+#define PCI_IO_SIZE		0x00200000
+
+#endif
diff --git a/drivers/staging/dgap/dgap_sysfs.c b/drivers/staging/dgap/dgap_sysfs.c
new file mode 100644
index 0000000..94da06f
--- /dev/null
+++ b/drivers/staging/dgap/dgap_sysfs.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * 
+ *      NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *      This is shared code between Digi's CVS archive and the
+ *      Linux Kernel sources.
+ *      Changing the source just for reformatting needlessly breaks
+ *      our CVS diff history.
+ *
+ *      Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *      Thank you.
+ *
+ *
+ * 
+ * $Id: dgap_sysfs.c,v 1.1 2009/10/23 14:01:57 markh Exp $   
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/serial_reg.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+  
+#include "dgap_driver.h"
+#include "dgap_conf.h"
+#include "dgap_parse.h"
+
+
+static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
+}
+static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL);
+
+
+static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards);
+}
+static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL);
+
+
+static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
+}
+static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL);
+
+
+static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter);
+}
+static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL);
+
+
+static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]);
+}
+static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL);
+
+
+static ssize_t dgap_driver_debug_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_debug);
+}
+
+static ssize_t dgap_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+	sscanf(buf, "0x%x\n", &dgap_debug);
+	return count;
+}
+static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgap_driver_debug_show, dgap_driver_debug_store);
+
+
+static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok);
+}
+
+static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+	sscanf(buf, "0x%x\n", &dgap_rawreadok);
+	return count;
+}
+static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store);
+
+
+static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick);
+}
+
+static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+	sscanf(buf, "%d\n", &dgap_poll_tick);
+	return count;
+}
+static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store);
+
+
+void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver)
+{
+	int rc = 0;
+	struct device_driver *driverfs = &dgap_driver->driver;
+
+	rc |= driver_create_file(driverfs, &driver_attr_version);
+	rc |= driver_create_file(driverfs, &driver_attr_boards);
+	rc |= driver_create_file(driverfs, &driver_attr_maxboards);
+	rc |= driver_create_file(driverfs, &driver_attr_debug);
+	rc |= driver_create_file(driverfs, &driver_attr_rawreadok); 
+	rc |= driver_create_file(driverfs, &driver_attr_pollrate);
+	rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
+	rc |= driver_create_file(driverfs, &driver_attr_state);
+	if (rc) {
+		printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n");
+	}
+}
+
+
+void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver)
+{
+	struct device_driver *driverfs = &dgap_driver->driver;
+	driver_remove_file(driverfs, &driver_attr_version);
+	driver_remove_file(driverfs, &driver_attr_boards);
+	driver_remove_file(driverfs, &driver_attr_maxboards);
+	driver_remove_file(driverfs, &driver_attr_debug);
+	driver_remove_file(driverfs, &driver_attr_rawreadok);
+	driver_remove_file(driverfs, &driver_attr_pollrate);
+	driver_remove_file(driverfs, &driver_attr_pollcounter);
+	driver_remove_file(driverfs, &driver_attr_state);
+}
+
+
+#define DGAP_VERIFY_BOARD(p, bd)			\
+	if (!p)						\
+		return (0);				\
+							\
+	bd = dev_get_drvdata(p);			\
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)	\
+		return (0);				\
+	if (bd->state != BOARD_READY)			\
+		return (0);				\
+
+
+static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count,
+			"%d %s\n", bd->channels[i]->ch_portnum,
+			bd->channels[i]->ch_open_count ? "Open" : "Closed");
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL);
+
+
+static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count +=  snprintf(buf + count, PAGE_SIZE - count,
+			"%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL);
+
+
+static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		if (bd->channels[i]->ch_open_count) {
+			count += snprintf(buf + count, PAGE_SIZE - count,
+				"%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
+				(bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+				(bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
+		} else {
+			count += snprintf(buf + count, PAGE_SIZE - count,
+				"%d\n", bd->channels[i]->ch_portnum);
+		}
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL);
+
+
+static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL);
+
+
+static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL);
+
+
+static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL);
+
+
+static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL);
+
+
+static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL);
+
+
+static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL);
+
+
+static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGAP_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL);
+
+
+/* this function creates the sys files that will export each signal status
+ * to sysfs each value will be put in a separate filename
+ */
+void dgap_create_ports_sysfiles(struct board_t *bd)
+{
+	int rc = 0;
+
+	dev_set_drvdata(&bd->pdev->dev, bd);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+	if (rc) {
+		printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n");
+	}
+}
+
+
+/* removes all the sys files created for that port */
+void dgap_remove_ports_sysfiles(struct board_t *bd)
+{
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+}
+
+
+static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
+}
+static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL);
+
+
+static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info);
+}
+static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL);
+
+
+static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	if (ch->ch_open_count) {
+		return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+			(ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+			(ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+			(ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+			(ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+			(ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+			(ch->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
+	}
+	return 0;
+}
+static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL);
+
+
+static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
+}
+static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL);
+
+
+static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
+}
+static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL);
+
+
+static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
+}
+static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL);
+
+
+static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
+}
+static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL);
+
+
+static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL);
+
+
+static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL);
+
+
+static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL);
+
+
+static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int	cn;
+	int	bn;
+	struct cnode *cptr = NULL;
+	int found = FALSE;
+	int ncount = 0;
+	int starto = 0;
+	int i = 0;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+        bn = bd->boardnum;
+	cn = ch->ch_portnum;
+
+	for (cptr = bd->bd_config; cptr; cptr = cptr->next) {
+
+		if ((cptr->type == BNODE) &&
+		    ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) ||
+		     (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) ||
+		     (cptr->u.board.type == PAPORT8))) {
+
+				found = TRUE;
+				if (cptr->u.board.v_start)
+					starto = cptr->u.board.start;
+				else
+					starto = 1;
+		}
+
+		if (cptr->type == TNODE && found == TRUE) {
+			char *ptr1;
+			if (strstr(cptr->u.ttyname, "tty")) {
+				ptr1 = cptr->u.ttyname;
+				ptr1 += 3;
+			}
+			else {
+				ptr1 = cptr->u.ttyname;
+			}
+
+			for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) {
+				if (cn == i) {
+					return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+						(un->un_type == DGAP_PRINT) ? "pr" : "tty",
+						ptr1, i + starto);
+				}
+			}
+		}
+
+		if (cptr->type == CNODE) {
+
+			for (i = 0; i < cptr->u.conc.nport; i++) {
+				if (cn == (i + ncount)) {
+
+					return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+						(un->un_type == DGAP_PRINT) ? "pr" : "tty",
+						cptr->u.conc.id,
+						i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1));
+				}
+			}
+
+			ncount += cptr->u.conc.nport;
+		}
+
+		if (cptr->type == MNODE) {
+
+			for (i = 0; i < cptr->u.module.nport; i++) {
+				if (cn == (i + ncount)) {
+					return snprintf(buf, PAGE_SIZE, "%s%s%02d\n",
+						(un->un_type == DGAP_PRINT) ? "pr" : "tty",
+						cptr->u.module.id,
+						i + (cptr->u.module.v_start ? cptr->u.module.start : 1));
+				}
+			}
+
+			ncount += cptr->u.module.nport;
+
+		}
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n",
+		(un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn);
+
+}
+static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL);
+
+
+static struct attribute *dgap_sysfs_tty_entries[] = {
+	&dev_attr_state.attr,
+	&dev_attr_baud.attr,
+	&dev_attr_msignals.attr,
+	&dev_attr_iflag.attr,
+	&dev_attr_cflag.attr,
+	&dev_attr_oflag.attr,
+	&dev_attr_lflag.attr,
+	&dev_attr_digi_flag.attr,
+	&dev_attr_rxcount.attr,
+	&dev_attr_txcount.attr,
+	&dev_attr_custom_name.attr,
+	NULL
+};
+
+
+static struct attribute_group dgap_tty_attribute_group = {
+	.name = NULL,
+	.attrs = dgap_sysfs_tty_entries,
+};
+
+
+
+
+void dgap_create_tty_sysfs(struct un_t *un, struct device *c)
+{
+	int ret;
+
+	ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group);
+	if (ret) {
+		printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n");
+		sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
+		return;
+	}
+
+	dev_set_drvdata(c, un);
+
+}
+
+
+void dgap_remove_tty_sysfs(struct device *c)
+{
+	sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group);
+}
diff --git a/drivers/staging/dgap/dgap_sysfs.h b/drivers/staging/dgap/dgap_sysfs.h
new file mode 100644
index 0000000..dde690e
--- /dev/null
+++ b/drivers/staging/dgap/dgap_sysfs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGAP_SYSFS_H
+#define __DGAP_SYSFS_H
+
+#include "dgap_driver.h"
+
+#include <linux/device.h>
+
+struct board_t;
+struct channel_t;
+struct un_t;
+struct pci_driver;
+struct class_device;
+
+extern void dgap_create_ports_sysfiles(struct board_t *bd); 
+extern void dgap_remove_ports_sysfiles(struct board_t *bd);
+
+extern void dgap_create_driver_sysfiles(struct pci_driver *);
+extern void dgap_remove_driver_sysfiles(struct pci_driver *);
+
+extern int dgap_tty_class_init(void);
+extern int dgap_tty_class_destroy(void);
+
+extern void dgap_create_tty_sysfs(struct un_t *un, struct device *c);
+extern void dgap_remove_tty_sysfs(struct device *c);
+
+
+#endif
diff --git a/drivers/staging/dgap/dgap_trace.c b/drivers/staging/dgap/dgap_trace.c
new file mode 100644
index 0000000..0f9a956
--- /dev/null
+++ b/drivers/staging/dgap/dgap_trace.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE! 
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com. 
+ *	Thank you. 
+ *
+ */
+
+/* $Id: dgap_trace.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/vmalloc.h>
+
+#include "dgap_driver.h"
+
+#define TRC_TO_CONSOLE 1
+
+/* file level globals */
+static char *dgap_trcbuf;		/* the ringbuffer */
+
+#if defined(TRC_TO_KMEM)
+static int dgap_trcbufi = 0;		/* index of the tilde at the end of */
+#endif
+
+extern int dgap_trcbuf_size;		/* size of the ringbuffer */
+
+#if defined(TRC_TO_KMEM)
+static DEFINE_SPINLOCK(dgap_tracef_lock);
+#endif
+
+#if 0
+
+#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
+void dgap_tracef(const char *fmt, ...)
+{
+	return;
+}
+
+#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+void dgap_tracef(const char *fmt, ...)
+{
+	va_list	         ap;
+	char  	         buf[TRC_MAXMSG+1];
+	size_t		 lenbuf;
+	int		 i;
+	static int	 failed = FALSE;
+# if defined(TRC_TO_KMEM)
+	unsigned long	 flags;
+#endif
+
+	if(failed)
+		return;
+# if defined(TRC_TO_KMEM)
+	DGAP_LOCK(dgap_tracef_lock, flags);
+#endif
+
+	/* Format buf using fmt and arguments contained in ap. */
+	va_start(ap, fmt);
+	i = vsprintf(buf, fmt,  ap);
+	va_end(ap);
+	lenbuf = strlen(buf);
+
+# if defined(TRC_TO_KMEM)
+	{
+		static int	 initd=0;
+
+		/*
+		 * Now, in addition to (or instead of) printing this stuff out
+		 * (which is a buffered operation), also tuck it away into a
+		 * corner of memory which can be examined post-crash in kdb.
+		 */
+		if (!initd) {
+			dgap_trcbuf = (char *) vmalloc(dgap_trcbuf_size);
+			if(!dgap_trcbuf) {
+				failed = TRUE;
+				printk("dgap: tracing init failed!\n");
+				return;
+			}
+
+			memset(dgap_trcbuf, '\0',  dgap_trcbuf_size);
+			dgap_trcbufi = 0;
+			initd++;
+
+			printk("dgap: tracing enabled - " TRC_DTRC 
+				" 0x%lx 0x%x\n",
+				(unsigned long)dgap_trcbuf, 
+				dgap_trcbuf_size);
+		}
+
+#  if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
+		/*
+		 * This is the less CPU-intensive way to do things.  We simply
+		 * wrap around before we fall off the end of the buffer.  A 
+		 * tilde (~) demarcates the current end of the trace.
+		 *
+		 * This method should be used if you are concerned about race
+		 * conditions as it is less likely to affect the timing of
+		 * things.
+		 */
+
+		if (dgap_trcbufi + lenbuf >= dgap_trcbuf_size) {
+			/* We are wrapping, so wipe out the last tilde. */
+			dgap_trcbuf[dgap_trcbufi] = '\0';
+			/* put the new string at the beginning of the buffer */
+			dgap_trcbufi = 0;
+		}
+
+		strcpy(&dgap_trcbuf[dgap_trcbufi], buf);	
+		dgap_trcbufi += lenbuf;
+		dgap_trcbuf[dgap_trcbufi] = '~';
+
+#  elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
+		/*
+		 * This is the more CPU-intensive way to do things.  If we
+		 * venture into the last 1/8 of the buffer, we shift the 
+		 * last 7/8 of the buffer forward, wiping out the first 1/8.
+		 * Advantage: No wrap-around, only truncation from the
+		 * beginning.
+		 *
+		 * This method should not be used if you are concerned about
+		 * timing changes affecting the behaviour of the driver (ie,
+		 * race conditions).
+		 */
+		strcpy(&dgap_trcbuf[dgap_trcbufi], buf);
+		dgap_trcbufi += lenbuf;
+		dgap_trcbuf[dgap_trcbufi] = '~';
+		dgap_trcbuf[dgap_trcbufi+1] = '\0';
+
+		/* If we're near the end of the trace buffer... */
+		if (dgap_trcbufi > (dgap_trcbuf_size/8)*7) {
+			/* Wipe out the first eighth to make some more room. */
+			strcpy(dgap_trcbuf, &dgap_trcbuf[dgap_trcbuf_size/8]);
+			dgap_trcbufi = strlen(dgap_trcbuf)-1;
+			/* Plop overflow message at the top of the buffer. */
+			bcopy(TRC_OVERFLOW, dgap_trcbuf, strlen(TRC_OVERFLOW));
+		}
+#  else
+#   error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
+#  endif
+	}
+	DGAP_UNLOCK(dgap_tracef_lock, flags);
+
+# endif /* defined(TRC_TO_KMEM) */
+}
+
+#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+#endif
+
+/*
+ * dgap_tracer_free()
+ *
+ *
+ */
+void dgap_tracer_free(void)
+{
+	if(dgap_trcbuf)
+		vfree(dgap_trcbuf);
+}
diff --git a/drivers/staging/dgap/dgap_trace.h b/drivers/staging/dgap/dgap_trace.h
new file mode 100644
index 0000000..b21f461
--- /dev/null
+++ b/drivers/staging/dgap/dgap_trace.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *****************************************************************************
+ * Header file for dgap_trace.c
+ *
+ * $Id: dgap_trace.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ */
+
+#ifndef __DGAP_TRACE_H
+#define __DGAP_TRACE_H
+
+#include "dgap_driver.h"
+
+void dgap_tracef(const char *fmt, ...);
+void dgap_tracer_free(void);
+
+#endif
+
diff --git a/drivers/staging/dgap/dgap_tty.c b/drivers/staging/dgap/dgap_tty.c
new file mode 100644
index 0000000..b906db3
--- /dev/null
+++ b/drivers/staging/dgap/dgap_tty.c
@@ -0,0 +1,3597 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE! 
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com. 
+ *	Thank you. 
+ */
+
+/************************************************************************
+ * 
+ * This file implements the tty driver functionality for the
+ * FEP5 based product lines.
+ * 
+ ************************************************************************
+ *
+ * $Id: dgap_tty.c,v 1.3 2011/06/23 12:11:31 markh Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/delay.h>	/* For udelay */
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+#include <asm/io.h>		/* For read[bwl]/write[bwl] */
+#include <linux/pci.h>
+
+#include "dgap_driver.h"
+#include "dgap_tty.h"
+#include "dgap_types.h"
+#include "dgap_fep5.h"
+#include "dgap_parse.h"
+#include "dgap_conf.h"
+#include "dgap_sysfs.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+#define init_MUTEX(sem)         sema_init(sem, 1)
+#define DECLARE_MUTEX(name)     \
+        struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
+#endif
+
+/*
+ * internal variables
+ */
+static struct board_t	*dgap_BoardsByMajor[256];
+static uchar		*dgap_TmpWriteBuf = NULL;
+static DECLARE_MUTEX(dgap_TmpWriteSem);
+
+/*
+ * Default transparent print information.
+ */
+static struct digi_t dgap_digi_init = {
+	.digi_flags =	DIGI_COOK,	/* Flags			*/
+	.digi_maxcps =	100,		/* Max CPS			*/
+	.digi_maxchar =	50,		/* Max chars in print queue	*/
+	.digi_bufsize =	100,		/* Printer buffer size		*/
+	.digi_onlen =	4,		/* size of printer on string	*/
+	.digi_offlen =	4,		/* size of printer off string	*/
+	.digi_onstr =	"\033[5i",	/* ANSI printer on string ]	*/
+	.digi_offstr =	"\033[4i",	/* ANSI printer off string ]	*/
+	.digi_term =	"ansi"		/* default terminal type	*/
+};
+
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+
+static struct ktermios DgapDefaultTermios =
+{
+	.c_iflag =	(DEFAULT_IFLAGS),	/* iflags */
+	.c_oflag =	(DEFAULT_OFLAGS),	/* oflags */
+	.c_cflag =	(DEFAULT_CFLAGS),	/* cflags */
+	.c_lflag =	(DEFAULT_LFLAGS),	/* lflags */
+	.c_cc =		INIT_C_CC,
+	.c_line = 	0,
+};
+
+/* Our function prototypes */
+static int dgap_tty_open(struct tty_struct *tty, struct file *file);
+static void dgap_tty_close(struct tty_struct *tty, struct file *file);
+static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch);
+static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
+static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo);
+static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info);
+static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo);
+static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info);
+static int dgap_tty_write_room(struct tty_struct* tty);
+static int dgap_tty_chars_in_buffer(struct tty_struct* tty);
+static void dgap_tty_start(struct tty_struct *tty);
+static void dgap_tty_stop(struct tty_struct *tty);
+static void dgap_tty_throttle(struct tty_struct *tty);
+static void dgap_tty_unthrottle(struct tty_struct *tty);
+static void dgap_tty_flush_chars(struct tty_struct *tty);
+static void dgap_tty_flush_buffer(struct tty_struct *tty);
+static void dgap_tty_hangup(struct tty_struct *tty);
+static int dgap_wait_for_drain(struct tty_struct *tty);
+static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value);
+static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value);
+static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info);
+static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgap_tty_tiocmget(struct tty_struct *tty);
+static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
+#else
+static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file);
+static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);
+#endif
+static int dgap_tty_send_break(struct tty_struct *tty, int msec);
+static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout);
+static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
+static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios);
+static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c);
+static void dgap_tty_send_xchar(struct tty_struct *tty, char ch);
+
+static const struct tty_operations dgap_tty_ops = {
+	.open = dgap_tty_open,
+	.close = dgap_tty_close,
+	.write = dgap_tty_write,
+	.write_room = dgap_tty_write_room,
+	.flush_buffer = dgap_tty_flush_buffer,
+	.chars_in_buffer = dgap_tty_chars_in_buffer,
+	.flush_chars = dgap_tty_flush_chars,
+	.ioctl = dgap_tty_ioctl,
+	.set_termios = dgap_tty_set_termios,
+	.stop = dgap_tty_stop, 
+	.start = dgap_tty_start,
+	.throttle = dgap_tty_throttle,
+	.unthrottle = dgap_tty_unthrottle,
+	.hangup = dgap_tty_hangup,
+	.put_char = dgap_tty_put_char,
+	.tiocmget = dgap_tty_tiocmget,
+	.tiocmset = dgap_tty_tiocmset,
+	.break_ctl = dgap_tty_send_break,
+	.wait_until_sent = dgap_tty_wait_until_sent,
+	.send_xchar = dgap_tty_send_xchar
+};
+
+
+
+
+
+/************************************************************************
+ *                      
+ * TTY Initialization/Cleanup Functions
+ *      
+ ************************************************************************/
+         
+/*
+ * dgap_tty_preinit()
+ *
+ * Initialize any global tty related data before we download any boards.
+ */
+int dgap_tty_preinit(void)
+{
+	unsigned long flags;
+
+	DGAP_LOCK(dgap_global_lock, flags);  
+
+	/*
+	 * Allocate a buffer for doing the copy from user space to
+	 * kernel space in dgap_input().  We only use one buffer and
+	 * control access to it with a semaphore.  If we are paging, we
+	 * are already in trouble so one buffer won't hurt much anyway.
+	 */
+	dgap_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_ATOMIC);
+
+	if (!dgap_TmpWriteBuf) {
+		DGAP_UNLOCK(dgap_global_lock, flags);
+		DPR_INIT(("unable to allocate tmp write buf"));
+		return (-ENOMEM);
+	}
+         
+        DGAP_UNLOCK(dgap_global_lock, flags);
+        return(0);
+}
+
+
+/*
+ * dgap_tty_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+int dgap_tty_register(struct board_t *brd)
+{
+	int rc = 0;
+
+	DPR_INIT(("tty_register start"));
+
+	brd->SerialDriver = alloc_tty_driver(MAXPORTS);
+
+	snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum);
+	brd->SerialDriver->name = brd->SerialName;
+	brd->SerialDriver->name_base = 0;
+	brd->SerialDriver->major = 0;
+	brd->SerialDriver->minor_start = 0;
+	brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL; 
+	brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL;   
+	brd->SerialDriver->init_termios = DgapDefaultTermios;
+	brd->SerialDriver->driver_name = DRVSTR;
+	brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+	/* The kernel wants space to store pointers to tty_structs */
+	brd->SerialDriver->ttys = dgap_driver_kzmalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!brd->SerialDriver->ttys)
+		return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	brd->SerialDriver->refcount = brd->TtyRefCnt;
+#endif
+
+	/*
+	 * Entry points for driver.  Called by the kernel from
+	 * tty_io.c and n_tty.c.
+	 */
+	tty_set_operations(brd->SerialDriver, &dgap_tty_ops);
+
+	/*
+	 * If we're doing transparent print, we have to do all of the above
+	 * again, seperately so we don't get the LD confused about what major
+	 * we are when we get into the dgap_tty_open() routine.
+	 */
+	brd->PrintDriver = alloc_tty_driver(MAXPORTS);
+
+	snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum);
+	brd->PrintDriver->name = brd->PrintName;
+	brd->PrintDriver->name_base = 0;
+	brd->PrintDriver->major = 0;
+	brd->PrintDriver->minor_start = 0;
+	brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL;   
+	brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL;
+	brd->PrintDriver->init_termios = DgapDefaultTermios;
+	brd->PrintDriver->driver_name = DRVSTR;
+	brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+	/* The kernel wants space to store pointers to tty_structs */
+	brd->PrintDriver->ttys = dgap_driver_kzmalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!brd->PrintDriver->ttys)
+		return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	brd->PrintDriver->refcount = brd->TtyRefCnt;
+#endif
+
+	/*
+	 * Entry points for driver.  Called by the kernel from
+	 * tty_io.c and n_tty.c.
+	 */
+	tty_set_operations(brd->PrintDriver, &dgap_tty_ops);
+
+	if (!brd->dgap_Major_Serial_Registered) {
+		/* Register tty devices */
+		rc = tty_register_driver(brd->SerialDriver);
+		if (rc < 0) {
+			APR(("Can't register tty device (%d)\n", rc));
+			return(rc);
+		}
+		brd->dgap_Major_Serial_Registered = TRUE;
+		dgap_BoardsByMajor[brd->SerialDriver->major] = brd;
+		brd->dgap_Serial_Major = brd->SerialDriver->major;
+	}
+
+	if (!brd->dgap_Major_TransparentPrint_Registered) {
+		/* Register Transparent Print devices */
+ 		rc = tty_register_driver(brd->PrintDriver);
+		if (rc < 0) {
+			APR(("Can't register Transparent Print device (%d)\n", rc));
+			return(rc);
+		}
+		brd->dgap_Major_TransparentPrint_Registered = TRUE;
+		dgap_BoardsByMajor[brd->PrintDriver->major] = brd;
+		brd->dgap_TransparentPrint_Major = brd->PrintDriver->major;
+	}
+
+	DPR_INIT(("DGAP REGISTER TTY: MAJORS: %d %d\n", brd->SerialDriver->major,
+		brd->PrintDriver->major));
+
+	return (rc);
+}
+
+
+/*
+ * dgap_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int dgap_tty_init(struct board_t *brd)
+{
+	int i;
+	int tlw;
+	uint true_count = 0;
+	uchar *vaddr;
+	uchar modem = 0;
+	struct channel_t *ch;
+	struct bs_t *bs;
+	struct cm_t *cm;
+
+	if (!brd)
+		return (-ENXIO);
+
+	DPR_INIT(("dgap_tty_init start\n"));
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	vaddr = brd->re_map_membase;
+	true_count = readw((vaddr + NCHAN));
+
+	brd->nasync = dgap_config_get_number_of_ports(brd);
+
+	if (!brd->nasync) {
+		brd->nasync = brd->maxports;
+	}
+
+	if (brd->nasync > brd->maxports) {
+		brd->nasync = brd->maxports;
+	}
+
+	if (true_count != brd->nasync) {
+		if ((brd->type == PPCM) && (true_count == 64)) {
+			APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n",
+				brd->name, brd->nasync, true_count));
+		}
+		else if ((brd->type == PPCM) && (true_count == 0)) {
+			APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n",
+				brd->name, brd->nasync, true_count));
+		}
+		else {
+			APR(("***WARNING**** %s configured for %d ports, has %d ports.\n",
+				brd->name, brd->nasync, true_count));
+		}
+
+		brd->nasync = true_count;
+
+		/* If no ports, don't bother going any further */
+		if (!brd->nasync) {
+			brd->state = BOARD_FAILED;
+			brd->dpastatus = BD_NOFEP;
+			return(-ENXIO);
+		}
+	}
+
+	/*
+	 * Allocate channel memory that might not have been allocated
+	 * when the driver was first loaded.
+	 */
+	for (i = 0; i < brd->nasync; i++) {
+		if (!brd->channels[i]) {
+			brd->channels[i] = dgap_driver_kzmalloc(sizeof(struct channel_t), GFP_ATOMIC);
+			if (!brd->channels[i]) {
+				DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n",
+				    __FILE__, __LINE__));
+			}
+		}
+	}
+
+	ch = brd->channels[0];
+	vaddr = brd->re_map_membase;
+
+	bs = (struct bs_t *) ((ulong) vaddr + CHANBUF);
+	cm = (struct cm_t *) ((ulong) vaddr + CMDBUF);
+
+	brd->bd_bs = bs;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) {
+
+		if (!brd->channels[i])
+			continue;
+
+		DGAP_SPINLOCK_INIT(ch->ch_lock);
+
+		/* Store all our magic numbers */
+		ch->magic = DGAP_CHANNEL_MAGIC;
+		ch->ch_tun.magic = DGAP_UNIT_MAGIC;
+		ch->ch_tun.un_type = DGAP_SERIAL;
+		ch->ch_tun.un_ch = ch;
+		ch->ch_tun.un_dev = i;
+
+		ch->ch_pun.magic = DGAP_UNIT_MAGIC;
+		ch->ch_pun.un_type = DGAP_PRINT;
+		ch->ch_pun.un_ch = ch;
+		ch->ch_pun.un_dev = i;
+
+		ch->ch_vaddr = vaddr;
+		ch->ch_bs = bs;
+		ch->ch_cm = cm;
+		ch->ch_bd = brd;
+		ch->ch_portnum = i;
+		ch->ch_digi = dgap_digi_init;
+
+		/*
+		 * Set up digi dsr and dcd bits based on altpin flag.
+		 */
+		if (dgap_config_get_altpin(brd)) {
+			ch->ch_dsr	= DM_CD;
+			ch->ch_cd	= DM_DSR;
+			ch->ch_digi.digi_flags |= DIGI_ALTPIN;
+		}
+		else {
+			ch->ch_cd	= DM_CD;
+			ch->ch_dsr	= DM_DSR;
+		}
+
+		ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4);
+		ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4);
+		ch->ch_tx_win = 0;
+		ch->ch_rx_win = 0;
+		ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1;
+		ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1;
+		ch->ch_tstart = 0;
+		ch->ch_rstart = 0;
+
+		/* .25 second delay */
+		ch->ch_close_delay = 250;
+
+		/*
+		 * Set queue water marks, interrupt mask,
+		 * and general tty parameters. 
+		 */
+		ch->ch_tlw = tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : ch->ch_tsize / 2;
+
+		dgap_cmdw(ch, STLOW, tlw, 0);
+
+		dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0);
+
+		dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0);
+
+		ch->ch_mistat = readb(&(ch->ch_bs->m_stat));
+
+		init_waitqueue_head(&ch->ch_flags_wait);
+		init_waitqueue_head(&ch->ch_tun.un_flags_wait);
+		init_waitqueue_head(&ch->ch_pun.un_flags_wait);
+		init_waitqueue_head(&ch->ch_sniff_wait);
+
+		/* Turn on all modem interrupts for now */
+		modem = (DM_CD | DM_DSR | DM_CTS | DM_RI);
+		writeb(modem, &(ch->ch_bs->m_int));
+
+		/*
+		 * Set edelay to 0 if interrupts are turned on,
+		 * otherwise set edelay to the usual 100.
+		 */
+		if (brd->intr_used)
+			writew(0, &(ch->ch_bs->edelay));
+		else
+			writew(100, &(ch->ch_bs->edelay));
+	
+		writeb(1, &(ch->ch_bs->idata));
+	}
+
+
+	DPR_INIT(("dgap_tty_init finish\n"));
+
+	return (0);
+}
+
+
+/*
+ * dgap_tty_post_uninit()
+ *
+ * UnInitialize any global tty related data.
+ */
+void dgap_tty_post_uninit(void)
+{
+	if (dgap_TmpWriteBuf) {
+		kfree(dgap_TmpWriteBuf);
+		dgap_TmpWriteBuf = NULL;
+	}
+}
+
+
+/*
+ * dgap_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver.  Free all memory and
+ * resources. 
+ */
+void dgap_tty_uninit(struct board_t *brd)
+{
+	int i = 0;
+
+	if (brd->dgap_Major_Serial_Registered) {
+		dgap_BoardsByMajor[brd->SerialDriver->major] = NULL;
+		brd->dgap_Serial_Major = 0;
+		for (i = 0; i < brd->nasync; i++) {
+			dgap_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs);
+			tty_unregister_device(brd->SerialDriver, i);
+		}
+		tty_unregister_driver(brd->SerialDriver);
+		if (brd->SerialDriver->ttys) {
+			kfree(brd->SerialDriver->ttys);
+			brd->SerialDriver->ttys = NULL;
+		}
+		put_tty_driver(brd->SerialDriver);
+		brd->dgap_Major_Serial_Registered = FALSE;
+	}
+
+	if (brd->dgap_Major_TransparentPrint_Registered) {
+		dgap_BoardsByMajor[brd->PrintDriver->major] = NULL;
+		brd->dgap_TransparentPrint_Major = 0;
+		for (i = 0; i < brd->nasync; i++) {
+			dgap_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs);
+			tty_unregister_device(brd->PrintDriver, i);
+		}
+		tty_unregister_driver(brd->PrintDriver);
+		if (brd->PrintDriver->ttys) {
+			kfree(brd->PrintDriver->ttys);
+			brd->PrintDriver->ttys = NULL;
+	        }
+		put_tty_driver(brd->PrintDriver);
+		brd->dgap_Major_TransparentPrint_Registered = FALSE;
+	}
+}
+
+
+#define TMPBUFLEN (1024)
+
+/*
+ * dgap_sniff - Dump data out to the "sniff" buffer if the
+ * proc sniff file is opened...
+ */
+static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
+{
+	struct timeval tv;
+	int n;
+	int r;
+	int nbuf;
+	int i;
+	int tmpbuflen;
+	char tmpbuf[TMPBUFLEN];
+	char *p = tmpbuf;
+	int too_much_data;
+
+	/* Leave if sniff not open */
+	if (!(ch->ch_sniff_flags & SNIFF_OPEN))
+		return;
+
+	do_gettimeofday(&tv);
+
+	/* Create our header for data dump */
+	p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
+	tmpbuflen = p - tmpbuf;
+
+	do {
+		too_much_data = 0;
+
+		for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
+			p += sprintf(p, "%02x ", *buf);
+			buf++;
+			tmpbuflen = p - tmpbuf;
+		}
+
+		if (tmpbuflen < (TMPBUFLEN - 4)) {
+			if (i > 0)
+				p += sprintf(p - 1, "%s\n", ">");
+			else
+				p += sprintf(p, "%s\n", ">");
+		} else {
+			too_much_data = 1;
+			len -= i;
+		}
+
+		nbuf = strlen(tmpbuf);
+		p = tmpbuf;
+
+		/*
+		 *  Loop while data remains.
+		 */
+		while (nbuf > 0 && ch->ch_sniff_buf != 0) {
+			/*
+			 *  Determine the amount of available space left in the
+			 *  buffer.  If there's none, wait until some appears.
+			 */
+			n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK;
+
+			/*
+			 * If there is no space left to write to in our sniff buffer,
+			 * we have no choice but to drop the data.
+			 * We *cannot* sleep here waiting for space, because this
+			 * function was probably called by the interrupt/timer routines!
+			 */
+			if (n == 0) {
+				return;
+			}
+	
+			/*
+			 * Copy as much data as will fit.
+			 */
+
+			if (n > nbuf)
+				n = nbuf;
+
+			r = SNIFF_MAX - ch->ch_sniff_in;
+
+			if (r <= n) {
+				memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r);
+
+				n -= r;
+				ch->ch_sniff_in = 0;
+				p += r;
+				nbuf -= r;
+			}
+
+			memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
+
+			ch->ch_sniff_in += n;
+			p += n;
+			nbuf -= n;
+
+			/*
+			 *  Wakeup any thread waiting for data
+			 */
+			if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
+				ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
+				wake_up_interruptible(&ch->ch_sniff_wait);
+			}
+		}
+
+		/*
+		 * If the user sent us too much data to push into our tmpbuf,
+		 * we need to keep looping around on all the data.
+		 */
+		if (too_much_data) {
+			p = tmpbuf;
+			tmpbuflen = 0;
+		}
+
+	} while (too_much_data);
+}
+
+
+/*=======================================================================
+ *
+ *      dgap_input - Process received data.
+ * 
+ *              ch      - Pointer to channel structure.
+ * 
+ *=======================================================================*/
+
+void dgap_input(struct channel_t *ch)
+{
+	struct board_t *bd;
+	struct bs_t	*bs;
+	struct tty_struct *tp;
+	struct tty_ldisc *ld;
+	uint	rmask;
+	uint	head;
+	uint	tail;
+	int	data_len;
+	ulong	lock_flags;
+	ulong   lock_flags2;
+	int flip_len;
+	int len = 0;
+	int n = 0;
+	uchar *buf;
+	uchar tmpchar;
+	int s = 0;
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	tp = ch->ch_tun.un_tty;
+
+	bs  = ch->ch_bs;
+	if (!bs) {
+		return;
+	}
+
+	bd = ch->ch_bd;
+	if(!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_READ(("dgap_input start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	/* 
+	 *      Figure the number of characters in the buffer.   
+	 *      Exit immediately if none.
+	 */
+
+	rmask = ch->ch_rsize - 1;
+
+	head = readw(&(bs->rx_head));
+	head &= rmask;
+	tail = readw(&(bs->rx_tail));
+	tail &= rmask;
+
+	data_len = (head - tail) & rmask;
+
+	if (data_len == 0) {
+		writeb(1, &(bs->idata));
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		DPR_READ(("No data on port %d\n", ch->ch_portnum));
+		return;
+	}
+
+	/*
+	 * If the device is not open, or CREAD is off, flush
+	 * input data and return immediately.
+	 */
+	if ((bd->state != BOARD_READY) || !tp  || (tp->magic != TTY_MAGIC) ||
+            !(ch->ch_tun.un_flags & UN_ISOPEN) || !(tp->termios.c_cflag & CREAD) ||
+	    (ch->ch_tun.un_flags & UN_CLOSING)) {
+
+		DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum));
+		DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n",
+			tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags));
+		writew(head, &(bs->rx_tail));
+		writeb(1, &(bs->idata));
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return;
+	}
+
+	/*
+	 * If we are throttled, simply don't read any data.
+	 */
+	if (ch->ch_flags & CH_RXBLOCK) {
+		writeb(1, &(bs->idata));
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n",
+			ch->ch_portnum, head, tail));
+		return;
+	}
+
+	/*
+	 *      Ignore oruns.
+	 */
+	tmpchar = readb(&(bs->orun));
+	if (tmpchar) {
+		ch->ch_err_overrun++;
+		writeb(0, &(bs->orun));
+	}
+
+	DPR_READ(("dgap_input start 2\n"));
+
+	/* Decide how much data we can send into the tty layer */
+	flip_len = TTY_FLIPBUF_SIZE;
+
+	/* Chop down the length, if needed */
+	len = min(data_len, flip_len);
+	len = min(len, (N_TTY_BUF_SIZE - 1));
+
+	ld = tty_ldisc_ref(tp);
+                
+#ifdef TTY_DONT_FLIP
+	/*
+	 * If the DONT_FLIP flag is on, don't flush our buffer, and act
+	 * like the ld doesn't have any space to put the data right now.  
+	 */
+	if (test_bit(TTY_DONT_FLIP, &tp->flags))   
+		len = 0;
+#endif
+
+	/*
+	 * If we were unable to get a reference to the ld,
+	 * don't flush our buffer, and act like the ld doesn't
+	 * have any space to put the data right now.
+	 */
+	if (!ld) {
+		len = 0;
+	} else {
+		/*
+		 * If ld doesn't have a pointer to a receive_buf function,
+		 * flush the data, then act like the ld doesn't have any
+		 * space to put the data right now.
+		 */
+		if (!ld->ops->receive_buf) {
+			writew(head, &(bs->rx_tail));
+			len = 0;
+		}
+	}
+
+	if (len <= 0) {
+		writeb(1, &(bs->idata));
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		DPR_READ(("dgap_input 1 - finish\n"));
+		if (ld)
+			tty_ldisc_deref(ld);
+		return;
+	}
+
+	buf = ch->ch_bd->flipbuf;
+	n = len;
+
+	/*
+	 * n now contains the most amount of data we can copy,
+	 * bounded either by our buffer size or the amount
+	 * of data the card actually has pending...
+	 */
+	while (n) {
+
+		s = ((head >= tail) ? head : ch->ch_rsize) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s);
+		dgap_sniff_nowait_nolock(ch, "USER READ", buf, s);
+
+		tail += s;
+		buf += s;
+
+		n -= s;
+		/* Flip queue if needed */
+		tail &= rmask;
+	}
+
+	writew(tail, &(bs->rx_tail));
+	writeb(1, &(bs->idata));
+	ch->ch_rxcount += len;
+
+	/*
+	 * If we are completely raw, we don't need to go through a lot
+	 * of the tty layers that exist.
+	 * In this case, we take the shortest and fastest route we
+	 * can to relay the data to the user.
+	 *
+	 * On the other hand, if we are not raw, we need to go through
+	 * the tty layer, which has its API more well defined.
+	 */
+	if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+		dgap_parity_scan(ch, ch->ch_bd->flipbuf, ch->ch_bd->flipflagbuf, &len);
+
+		len = tty_buffer_request_room(tp->port, len);
+		tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf,
+			ch->ch_bd->flipflagbuf, len);
+	}
+	else {
+		len = tty_buffer_request_room(tp->port, len);
+		tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len);
+	}
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	/* Tell the tty layer its okay to "eat" the data now */
+	tty_flip_buffer_push(tp->port);
+
+	if (ld)
+		tty_ldisc_deref(ld);
+
+	DPR_READ(("dgap_input - finish\n"));
+}
+
+
+/************************************************************************   
+ * Determines when CARRIER changes state and takes appropriate
+ * action. 
+ ************************************************************************/
+void dgap_carrier(struct channel_t *ch)
+{
+	struct board_t *bd;
+
+        int virt_carrier = 0;
+        int phys_carrier = 0;
+ 
+	DPR_CARR(("dgap_carrier called...\n"));
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	/* Make sure altpin is always set correctly */
+	if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+		ch->ch_dsr      = DM_CD;
+		ch->ch_cd       = DM_DSR;
+	}
+	else {
+		ch->ch_dsr      = DM_DSR;
+		ch->ch_cd       = DM_CD;
+	}
+
+	if (ch->ch_mistat & D_CD(ch)) {
+		DPR_CARR(("mistat: %x  D_CD: %x\n", ch->ch_mistat, D_CD(ch)));
+		phys_carrier = 1;
+	}
+
+	if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) {
+		virt_carrier = 1;
+	}  
+
+	if (ch->ch_c_cflag & CLOCAL) {
+		virt_carrier = 1;
+	}  
+
+
+	DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier));
+
+	/*
+	 * Test for a VIRTUAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		DPR_CARR(("carrier: virt DCD rose\n"));
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 * Test for a PHYSICAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		DPR_CARR(("carrier: physical DCD rose\n"));
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 *  Test for a PHYSICAL transition to low, so long as we aren't
+	 *  currently ignoring physical transitions (which is what "virtual
+	 *  carrier" indicates).
+	 *
+	 *  The transition of the virtual carrier to low really doesn't
+	 *  matter... it really only means "ignore carrier state", not
+	 *  "make pretend that carrier is there".
+	 */
+	if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) &&
+	    (phys_carrier == 0)) 
+	{
+
+		/*
+		 *   When carrier drops:
+		 *
+		 *   Drop carrier on all open units.
+		 *
+		 *   Flush queues, waking up any task waiting in the
+		 *   line discipline.
+		 *
+		 *   Send a hangup to the control terminal.
+		 *
+		 *   Enable all select calls.
+		 */
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+
+		if (ch->ch_tun.un_open_count > 0) {
+			DPR_CARR(("Sending tty hangup\n"));
+			tty_hangup(ch->ch_tun.un_tty);
+		}
+
+		if (ch->ch_pun.un_open_count > 0) { 
+			DPR_CARR(("Sending pr hangup\n"));
+			tty_hangup(ch->ch_pun.un_tty);
+		}
+	}
+
+	/*
+	 *  Make sure that our cached values reflect the current reality.
+	 */
+	if (virt_carrier == 1)
+		ch->ch_flags |= CH_FCAR;
+	else      
+		ch->ch_flags &= ~CH_FCAR;
+
+	if (phys_carrier == 1)
+		ch->ch_flags |= CH_CD;
+	else
+		ch->ch_flags &= ~CH_CD;
+}
+
+
+/************************************************************************
+ *      
+ * TTY Entry points and helper functions
+ *              
+ ************************************************************************/
+
+/*
+ * dgap_tty_open()
+ *
+ */
+static int dgap_tty_open(struct tty_struct *tty, struct file *file)
+{
+	struct board_t	*brd;
+	struct channel_t *ch;
+	struct un_t	*un;
+	struct bs_t	*bs;
+	uint		major = 0;
+	uint		minor = 0;
+	int		rc = 0;
+	ulong		lock_flags;
+	ulong		lock_flags2;
+	u16		head;
+
+	rc = 0;
+
+	major = MAJOR(tty_devnum(tty));
+	minor = MINOR(tty_devnum(tty));
+
+	if (major > 255) {
+		return -ENXIO;
+	}
+
+	/* Get board pointer from our array of majors we have allocated */
+	brd = dgap_BoardsByMajor[major];
+	if (!brd) {
+		return -ENXIO;
+	}
+
+	/*
+	 * If board is not yet up to a state of READY, go to
+	 * sleep waiting for it to happen or they cancel the open.
+	 */
+	rc = wait_event_interruptible(brd->state_wait,
+		(brd->state & BOARD_READY));
+
+	if (rc) {
+		return rc;
+	}
+
+	DGAP_LOCK(brd->bd_lock, lock_flags);
+
+	/* The wait above should guarentee this cannot happen */
+	if (brd->state != BOARD_READY) {
+		DGAP_UNLOCK(brd->bd_lock, lock_flags);
+		return -ENXIO;
+	}
+
+	/* If opened device is greater than our number of ports, bail. */
+	if (MINOR(tty_devnum(tty)) > brd->nasync) {
+		DGAP_UNLOCK(brd->bd_lock, lock_flags);
+		return -ENXIO;
+	}
+
+	ch = brd->channels[minor];
+	if (!ch) {
+		DGAP_UNLOCK(brd->bd_lock, lock_flags);
+		return -ENXIO;
+	}
+
+	/* Grab channel lock */
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	/* Figure out our type */
+	if (major == brd->dgap_Serial_Major) {
+		un = &brd->channels[minor]->ch_tun;
+		un->un_type = DGAP_SERIAL;
+	}
+	else if (major == brd->dgap_TransparentPrint_Major) {
+		un = &brd->channels[minor]->ch_pun;
+		un->un_type = DGAP_PRINT;
+	}
+	else {
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(brd->bd_lock, lock_flags);
+		DPR_OPEN(("%d Unknown TYPE!\n", __LINE__));
+		return -ENXIO;
+	}
+
+	/* Store our unit into driver_data, so we always have it available. */
+	tty->driver_data = un;
+
+	DPR_OPEN(("Open called. MAJOR: %d MINOR:%d unit: %p NAME: %s\n",
+		MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), un, brd->name));
+
+	/*
+	 * Error if channel info pointer is 0.
+	 */
+	if ((bs = ch->ch_bs) == 0) {
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(brd->bd_lock, lock_flags);
+		DPR_OPEN(("%d BS is 0!\n", __LINE__));
+		return -ENXIO;
+        }
+
+	DPR_OPEN(("%d: tflag=%x  pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags));
+
+	/*
+	 * Initialize tty's
+	 */
+	if (!(un->un_flags & UN_ISOPEN)) {
+		/* Store important variables. */
+		un->un_tty     = tty;
+
+		/* Maybe do something here to the TTY struct as well? */
+	}
+
+	/*
+	 * Initialize if neither terminal or printer is open.
+	 */
+	if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
+
+		DPR_OPEN(("dgap_open: initializing channel in open...\n"));
+
+		ch->ch_mforce = 0;
+		ch->ch_mval = 0;
+
+		/*
+		 * Flush input queue.
+		 */
+		head = readw(&(bs->rx_head));
+		writew(head, &(bs->rx_tail));
+
+		ch->ch_flags = 0;
+		ch->pscan_state = 0;
+		ch->pscan_savechar = 0;
+
+		ch->ch_c_cflag   = tty->termios.c_cflag;
+		ch->ch_c_iflag   = tty->termios.c_iflag;
+		ch->ch_c_oflag   = tty->termios.c_oflag;
+		ch->ch_c_lflag   = tty->termios.c_lflag;
+		ch->ch_startc = tty->termios.c_cc[VSTART];
+		ch->ch_stopc  = tty->termios.c_cc[VSTOP];
+
+		/* TODO: flush our TTY struct here? */
+	}
+
+	dgap_carrier(ch);
+	/*
+	 * Run param in case we changed anything
+	 */
+	dgap_param(tty);
+
+	/*                              
+	 * follow protocol for opening port
+	 */
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(brd->bd_lock, lock_flags);
+
+	rc = dgap_block_til_ready(tty, file, ch);
+
+	if (!un->un_tty) {
+		return -ENODEV;
+	}
+
+	if (rc) {
+		DPR_OPEN(("dgap_tty_open returning after dgap_block_til_ready "
+			"with %d\n", rc));
+	}
+
+	/* No going back now, increment our unit and channel counters */
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+	ch->ch_open_count++;
+	un->un_open_count++;
+	un->un_flags |= (UN_ISOPEN);
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_OPEN(("dgap_tty_open finished\n"));
+	return (rc);
+}
+
+
+/*   
+ * dgap_block_til_ready()
+ *
+ * Wait for DCD, if needed.
+ */
+static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch)
+{ 
+	int retval = 0;
+	struct un_t *un = NULL;
+	ulong   lock_flags;
+	uint	old_flags = 0;
+	int sleep_on_un_flags = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGAP_CHANNEL_MAGIC) {
+		return (-ENXIO);
+	}
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC) {
+		return (-ENXIO);
+	}
+
+	DPR_OPEN(("dgap_block_til_ready - before block.\n"));
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_wopen++;
+
+	/* Loop forever */
+	while (1) {
+
+		sleep_on_un_flags = 0;
+
+		/*
+		 * If board has failed somehow during our sleep, bail with error.
+		 */
+		if (ch->ch_bd->state == BOARD_FAILED) {
+			retval = -ENXIO;
+			break;
+		}
+
+		/* If tty was hung up, break out of loop and set error. */
+		if (tty_hung_up_p(file)) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		/*
+		 * If either unit is in the middle of the fragile part of close,
+		 * we just cannot touch the channel safely.
+		 * Go back to sleep, knowing that when the channel can be
+		 * touched safely, the close routine will signal the 
+		 * ch_wait_flags to wake us back up.
+		 */
+		if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) {
+
+			/*
+			 * Our conditions to leave cleanly and happily:
+			 * 1) NONBLOCKING on the tty is set.
+			 * 2) CLOCAL is set.
+			 * 3) DCD (fake or real) is active.
+			 */
+
+			if (file->f_flags & O_NONBLOCK) {
+				break;
+			}
+
+			if (tty->flags & (1 << TTY_IO_ERROR)) {
+				break;
+			}
+
+			if (ch->ch_flags & CH_CD) {
+				DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+				break;
+			}
+
+			if (ch->ch_flags & CH_FCAR) {
+				DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+				break;
+			}
+		}
+		else {
+			sleep_on_un_flags = 1;
+		}
+
+		/*
+		 * If there is a signal pending, the user probably
+		 * interrupted (ctrl-c) us.
+		 * Leave loop with error set.
+		 */
+		if (signal_pending(current)) {
+			DPR_OPEN(("%d: signal pending...\n", __LINE__));
+			retval = -ERESTARTSYS;
+			break;
+		}
+
+		DPR_OPEN(("dgap_block_til_ready - blocking.\n"));
+
+		/*
+		 * Store the flags before we let go of channel lock
+		 */
+		if (sleep_on_un_flags)
+			old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
+		else
+			old_flags = ch->ch_flags;
+
+		/*
+		 * Let go of channel lock before calling schedule.
+		 * Our poller will get any FEP events and wake us up when DCD
+		 * eventually goes active.
+		 */
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+		DPR_OPEN(("Going to sleep on %s flags...\n",
+			(sleep_on_un_flags ? "un" : "ch")));
+
+		/*
+		 * Wait for something in the flags to change from the current value.
+		 */
+		if (sleep_on_un_flags) {
+			retval = wait_event_interruptible(un->un_flags_wait,
+				(old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags)));
+		}
+		else {
+			retval = wait_event_interruptible(ch->ch_flags_wait,
+				(old_flags != ch->ch_flags));
+		}
+
+		DPR_OPEN(("After sleep... retval: %x\n", retval));
+
+		/*
+		 * We got woken up for some reason.
+		 * Before looping around, grab our channel lock.
+		 */
+		DGAP_LOCK(ch->ch_lock, lock_flags);
+	}
+
+	ch->ch_wopen--;
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_OPEN(("dgap_block_til_ready - after blocking.\n"));
+
+	if (retval) {
+		DPR_OPEN(("dgap_block_til_ready - done. error. retval: %x\n", retval));
+		return(retval);
+	}
+
+	DPR_OPEN(("dgap_block_til_ready - done no error. jiffies: %lu\n", jiffies));
+
+	return(0);
+}
+
+
+/*
+ * dgap_tty_hangup()
+ *
+ * Hangup the port.  Like a close, but don't wait for output to drain.
+ */     
+static void dgap_tty_hangup(struct tty_struct *tty)
+{
+	struct board_t	*bd;
+	struct channel_t *ch;
+	struct un_t	*un;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_CLOSE(("dgap_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n",
+		ch->ch_open_count, un->un_open_count));
+
+	/* flush the transmit queues */
+	dgap_tty_flush_buffer(tty);
+
+	DPR_CLOSE(("dgap_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n",
+		ch->ch_open_count, un->un_open_count));
+}
+
+
+
+/*
+ * dgap_tty_close()
+ *
+ */
+static void dgap_tty_close(struct tty_struct *tty, struct file *file)
+{
+	struct ktermios *ts;
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+	int rc = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	ts = &tty->termios;
+
+	DPR_CLOSE(("Close called\n"));
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 * Determine if this is the last close or not - and if we agree about
+	 * which type of close it is with the Line Discipline
+	 */
+	if ((tty->count == 1) && (un->un_open_count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  un_open_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.
+		 */
+		APR(("tty->count is 1, un open count is %d\n", un->un_open_count));
+		un->un_open_count = 1;
+	}  
+
+	if (--un->un_open_count < 0) {
+		APR(("bad serial port open count of %d\n", un->un_open_count));
+		un->un_open_count = 0;
+	}
+
+	ch->ch_open_count--;
+
+	if (ch->ch_open_count && un->un_open_count) {
+		DPR_CLOSE(("dgap_tty_close: not last close ch: %d un:%d\n",
+			ch->ch_open_count, un->un_open_count));
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+                return;
+        }
+
+	/* OK, its the last close on the unit */
+	DPR_CLOSE(("dgap_tty_close - last close on unit procedures\n"));
+
+	un->un_flags |= UN_CLOSING;
+
+	tty->closing = 1;
+
+	/*
+	 * Only officially close channel if count is 0 and
+         * DIGI_PRINTER bit is not set.
+	 */
+	if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
+
+		ch->ch_flags &= ~(CH_RXBLOCK);
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+		/* wait for output to drain */
+		/* This will also return if we take an interrupt */
+
+		DPR_CLOSE(("Calling wait_for_drain\n"));
+		rc = dgap_wait_for_drain(tty);
+		DPR_CLOSE(("After calling wait_for_drain\n"));
+
+		if (rc) {
+			DPR_BASIC(("dgap_tty_close - bad return: %d ", rc));
+		}
+
+		dgap_tty_flush_buffer(tty);
+		tty_ldisc_flush(tty);
+
+		DGAP_LOCK(ch->ch_lock, lock_flags);
+
+		tty->closing = 0;
+
+		/*
+		 * If we have HUPCL set, lower DTR and RTS
+		 */
+		if (ch->ch_c_cflag & HUPCL ) {
+			DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n"));
+			ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch));
+			dgap_cmdb( ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0 );
+
+			/*
+			 * Go to sleep to ensure RTS/DTR 
+			 * have been dropped for modems to see it.
+			 */
+			if (ch->ch_close_delay) {
+				DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n"));
+
+				DGAP_UNLOCK(ch->ch_lock, lock_flags);
+				dgap_ms_sleep(ch->ch_close_delay);
+				DGAP_LOCK(ch->ch_lock, lock_flags);
+
+				DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n"));
+			}
+		}
+
+		ch->pscan_state = 0;
+		ch->pscan_savechar = 0;
+		ch->ch_baud_info = 0;
+
+	}
+
+	/*
+	 * turn off print device when closing print device.
+	 */
+	if ((un->un_type == DGAP_PRINT)  && (ch->ch_flags & CH_PRON) ) {
+		dgap_wmove(ch, ch->ch_digi.digi_offstr,
+			(int) ch->ch_digi.digi_offlen);
+		ch->ch_flags &= ~CH_PRON;
+	}
+
+	un->un_tty = NULL;
+	un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
+	tty->driver_data = NULL;
+
+	DPR_CLOSE(("Close. Doing wakeups\n"));
+	wake_up_interruptible(&ch->ch_flags_wait);
+	wake_up_interruptible(&un->un_flags_wait);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+                
+        DPR_BASIC(("dgap_tty_close - complete\n"));
+}
+
+
+/*
+ * dgap_tty_chars_in_buffer()
+ *
+ * Return number of characters that have not been transmitted yet.
+ *
+ * This routine is used by the line discipline to determine if there
+ * is data waiting to be transmitted/drained/flushed or not.
+ */
+static int dgap_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct board_t *bd = NULL;
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+	struct bs_t *bs = NULL;
+	uchar tbusy;
+	uint chars = 0;
+	u16 thead, ttail, tmask, chead, ctail;
+	ulong   lock_flags = 0;
+	ulong   lock_flags2 = 0;
+
+	if (tty == NULL)
+		return(0);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (0);
+
+        bs = ch->ch_bs;
+	if (!bs)
+		return (0);
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	tmask = (ch->ch_tsize - 1);
+
+	/* Get Transmit queue pointers */
+	thead = readw(&(bs->tx_head)) & tmask;
+	ttail = readw(&(bs->tx_tail)) & tmask;
+
+	/* Get tbusy flag */
+	tbusy = readb(&(bs->tbusy));
+
+	/* Get Command queue pointers */
+	chead = readw(&(ch->ch_cm->cm_head));
+	ctail = readw(&(ch->ch_cm->cm_tail));
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	/*
+	 * The only way we know for sure if there is no pending
+	 * data left to be transferred, is if:
+	 * 1) Transmit head and tail are equal (empty).
+	 * 2) Command queue head and tail are equal (empty).
+	 * 3) The "TBUSY" flag is 0. (Transmitter not busy).
+ 	 */
+
+	if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) {
+		chars = 0;
+	}
+	else {
+		if (thead >= ttail)
+			chars = thead - ttail;
+		else
+			chars = thead - ttail + ch->ch_tsize;
+		/*
+		 * Fudge factor here.
+		 * If chars is zero, we know that the command queue had
+		 * something in it or tbusy was set.  Because we cannot
+		 * be sure if there is still some data to be transmitted,
+		 * lets lie, and tell ld we have 1 byte left.
+		 */
+		if (chars == 0) {
+			/*
+			 * If TBUSY is still set, and our tx buffers are empty,
+			 * force the firmware to send me another wakeup after
+			 * TBUSY has been cleared.
+			 */
+			if (tbusy != 0) {
+				DGAP_LOCK(ch->ch_lock, lock_flags);
+				un->un_flags |= UN_EMPTY;
+				writeb(1, &(bs->iempty));
+				DGAP_UNLOCK(ch->ch_lock, lock_flags);
+			}
+			chars = 1;
+		}
+	}
+
+ 	DPR_WRITE(("dgap_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d tsize: %d)\n", 
+		ch->ch_portnum, chars, thead, ttail, ch->ch_tsize));
+        return(chars);
+}
+
+
+static int dgap_wait_for_drain(struct tty_struct *tty)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	struct bs_t *bs;
+	int ret = -EIO;
+	uint count = 1;
+	ulong   lock_flags = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return ret;
+
+        bs = ch->ch_bs;
+	if (!bs)
+		return ret;
+
+	ret = 0;
+
+	DPR_DRAIN(("dgap_wait_for_drain start\n"));
+
+	/* Loop until data is drained */
+	while (count != 0) {
+
+		count = dgap_tty_chars_in_buffer(tty);
+
+		if (count == 0)
+			break;
+
+		/* Set flag waiting for drain */
+		DGAP_LOCK(ch->ch_lock, lock_flags);
+		un->un_flags |= UN_EMPTY;
+		writeb(1, &(bs->iempty));
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+		/* Go to sleep till we get woken up */
+		ret = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
+		/* If ret is non-zero, user ctrl-c'ed us */
+		if (ret) {
+			break;
+		}
+	}
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+	un->un_flags &= ~(UN_EMPTY);
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_DRAIN(("dgap_wait_for_drain finish\n"));
+	return (ret);
+}
+
+
+/*               
+ * dgap_maxcps_room
+ *
+ * Reduces bytes_available to the max number of characters
+ * that can be sent currently given the maxcps value, and
+ * returns the new bytes_available.  This only affects printer
+ * output.
+ */                     
+static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+
+	if (tty == NULL)
+		return (bytes_available);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (bytes_available);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (bytes_available);
+
+	/*
+	 * If its not the Transparent print device, return
+	 * the full data amount.
+	 */
+	if (un->un_type != DGAP_PRINT)
+		return (bytes_available);
+
+	if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) {
+		int cps_limit = 0;
+		unsigned long current_time = jiffies;
+		unsigned long buffer_time = current_time +
+			(HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps;
+
+		if (ch->ch_cpstime < current_time) {
+			/* buffer is empty */
+			ch->ch_cpstime = current_time;            /* reset ch_cpstime */
+			cps_limit = ch->ch_digi.digi_bufsize;
+		}
+		else if (ch->ch_cpstime < buffer_time) {
+			/* still room in the buffer */
+			cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ;
+		}
+		else {
+			/* no room in the buffer */
+			cps_limit = 0; 
+		}
+
+		bytes_available = min(cps_limit, bytes_available);
+	}
+
+	return (bytes_available);
+}
+
+
+static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event)
+{
+	struct channel_t *ch = NULL;
+	struct bs_t *bs = NULL;
+
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+        bs = ch->ch_bs;
+	if (!bs)
+		return;
+
+	if ((event & UN_LOW) != 0) {
+		if ((un->un_flags & UN_LOW) == 0) {
+			un->un_flags |= UN_LOW;
+			writeb(1, &(bs->ilow));
+		}
+	}
+	if ((event & UN_LOW) != 0) {
+		if ((un->un_flags & UN_EMPTY) == 0) {
+			un->un_flags |= UN_EMPTY;
+			writeb(1, &(bs->iempty));
+		}
+	}
+}
+
+
+/*
+ * dgap_tty_write_room()
+ *
+ * Return space available in Tx buffer
+ */        
+static int dgap_tty_write_room(struct tty_struct *tty)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+	struct bs_t *bs = NULL;
+	u16 head, tail, tmask;
+	int ret = 0;
+	ulong   lock_flags = 0;
+
+	if (tty == NULL || dgap_TmpWriteBuf == NULL)
+		return(0);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (0);
+
+        bs = ch->ch_bs;
+	if (!bs)
+		return (0);
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+
+	tmask = ch->ch_tsize - 1;
+	head = readw(&(bs->tx_head)) & tmask;
+	tail = readw(&(bs->tx_tail)) & tmask;
+
+        if ((ret = tail - head - 1) < 0)
+                ret += ch->ch_tsize;
+
+	/* Limit printer to maxcps */
+	ret = dgap_maxcps_room(tty, ret);
+
+	/*
+	 * If we are printer device, leave space for 
+	 * possibly both the on and off strings.
+	 */
+	if (un->un_type == DGAP_PRINT) {
+		if (!(ch->ch_flags & CH_PRON))
+			ret -= ch->ch_digi.digi_onlen;
+		ret -= ch->ch_digi.digi_offlen;
+	}
+	else {
+		if (ch->ch_flags & CH_PRON)
+			ret -= ch->ch_digi.digi_offlen;
+	}
+
+	if (ret < 0)
+		ret = 0;
+
+	/*
+	 * Schedule FEP to wake us up if needed.
+	 *
+	 * TODO:  This might be overkill...
+	 * Do we really need to schedule callbacks from the FEP
+	 * in every case?  Can we get smarter based on ret?
+	 */
+	dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+ 
+	DPR_WRITE(("dgap_tty_write_room - %d tail: %d head: %d\n", ret, tail, head));
+
+        return(ret);
+}
+
+
+/*
+ * dgap_tty_put_char()
+ *
+ * Put a character into ch->ch_buf
+ *                              
+ *      - used by the line discipline for OPOST processing
+ */
+static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c)
+{
+	/*
+	 * Simply call tty_write.
+	 */
+	DPR_WRITE(("dgap_tty_put_char called\n"));
+	dgap_tty_write(tty, &c, 1);
+	return 1;
+}
+
+
+/*
+ * dgap_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+	struct bs_t *bs = NULL;
+	char *vaddr = NULL;
+	u16 head, tail, tmask, remain;
+	int bufcount = 0, n = 0;
+	int orig_count = 0;
+	ulong lock_flags;
+	int from_user = 0;
+
+	if (tty == NULL || dgap_TmpWriteBuf == NULL)
+		return(0);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (0);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return(0);
+
+        bs = ch->ch_bs;
+	if (!bs)
+		return(0);
+
+	if (!count)
+		return(0);
+
+	DPR_WRITE(("dgap_tty_write: Port: %x tty=%p user=%d len=%d\n",
+		ch->ch_portnum, tty, from_user, count));
+
+	/*
+	 * Store original amount of characters passed in.
+	 * This helps to figure out if we should ask the FEP
+	 * to send us an event when it has more space available.
+	 */
+	orig_count = count;
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+
+	/* Get our space available for the channel from the board */
+	tmask = ch->ch_tsize - 1;
+	head = readw(&(bs->tx_head)) & tmask;
+	tail = readw(&(bs->tx_tail)) & tmask;
+
+	if ((bufcount = tail - head - 1) < 0)
+		bufcount += ch->ch_tsize;
+
+	DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n",
+		__LINE__, bufcount, count, tail, head, tmask));
+
+	/*
+	 * Limit printer output to maxcps overall, with bursts allowed
+	 * up to bufsize characters.
+	 */
+	bufcount = dgap_maxcps_room(tty, bufcount);
+
+	/*
+	 * Take minimum of what the user wants to send, and the
+	 * space available in the FEP buffer.
+	 */
+	count = min(count, bufcount);
+
+	/*
+	 * Bail if no space left.
+	 */
+	if (count <= 0) {
+		dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+		return(0);
+	}
+
+	/*
+	 * Output the printer ON string, if we are in terminal mode, but
+	 * need to be in printer mode.
+	 */
+	if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) {
+		dgap_wmove(ch, ch->ch_digi.digi_onstr,
+		    (int) ch->ch_digi.digi_onlen);
+		head = readw(&(bs->tx_head)) & tmask;
+		ch->ch_flags |= CH_PRON;
+	}
+
+	/*
+	 * On the other hand, output the printer OFF string, if we are
+	 * currently in printer mode, but need to output to the terminal.
+	 */
+	if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+		dgap_wmove(ch, ch->ch_digi.digi_offstr,
+			(int) ch->ch_digi.digi_offlen);
+		head = readw(&(bs->tx_head)) & tmask;
+		ch->ch_flags &= ~CH_PRON;
+	}
+
+	/*
+	 * If there is nothing left to copy, or I can't handle any more data, leave.
+	 */
+	if (count <= 0) {
+		dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+		return(0);
+	}
+
+	if (from_user) {
+
+		count = min(count, WRITEBUFLEN);
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+		/*
+		 * If data is coming from user space, copy it into a temporary
+		 * buffer so we don't get swapped out while doing the copy to
+		 * the board.
+		 */
+		/* we're allowed to block if it's from_user */
+		if (down_interruptible(&dgap_TmpWriteSem)) {
+			return (-EINTR);
+		}
+
+		if (copy_from_user(dgap_TmpWriteBuf, (const uchar __user *) buf, count)) {
+			up(&dgap_TmpWriteSem);
+			printk("Write: Copy from user failed!\n");
+			return -EFAULT;
+		}
+
+		DGAP_LOCK(ch->ch_lock, lock_flags);
+
+		buf = dgap_TmpWriteBuf;
+	}
+
+	n = count;
+
+	/*
+	 * If the write wraps over the top of the circular buffer,
+	 * move the portion up to the wrap point, and reset the
+	 * pointers to the bottom.
+	 */
+	remain = ch->ch_tstart + ch->ch_tsize - head;
+
+	if (n >= remain) {
+		n -= remain;
+		vaddr = ch->ch_taddr + head;
+
+		memcpy_toio(vaddr, (uchar *) buf, remain);
+		dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain);
+
+		head = ch->ch_tstart;
+		buf += remain;
+	}
+
+	if (n > 0) {
+
+		/*
+		 * Move rest of data.
+		 */
+		vaddr = ch->ch_taddr + head;
+		remain = n;
+
+		memcpy_toio(vaddr, (uchar *) buf, remain);
+		dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain);
+
+		head += remain;
+
+	}
+
+	if (count) {
+		ch->ch_txcount += count;
+		head &= tmask;
+		writew(head, &(bs->tx_head));
+	}
+
+
+	dgap_set_firmware_event(un, UN_LOW | UN_EMPTY);
+
+	/*
+	 * If this is the print device, and the
+	 * printer is still on, we need to turn it
+	 * off before going idle.  If the buffer is
+	 * non-empty, wait until it goes empty.
+	 * Otherwise turn it off right now.
+	 */
+	if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) {
+		tail = readw(&(bs->tx_tail)) & tmask;
+
+		if (tail != head) {
+			un->un_flags |= UN_EMPTY;
+			writeb(1, &(bs->iempty));
+		}
+		else {
+			dgap_wmove(ch, ch->ch_digi.digi_offstr,
+				(int) ch->ch_digi.digi_offlen);
+			head = readw(&(bs->tx_head)) & tmask;
+			ch->ch_flags &= ~CH_PRON;
+		}
+	}
+
+	/* Update printer buffer empty time. */
+	if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0)
+	    && (ch->ch_digi.digi_bufsize > 0)) {
+                ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
+	}
+
+	if (from_user) {
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+		up(&dgap_TmpWriteSem);
+	} 
+	else {
+		DGAP_UNLOCK(ch->ch_lock, lock_flags);
+	}
+
+	DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count));
+
+	return (count);
+}
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgap_tty_tiocmget(struct tty_struct *tty)
+#else
+static int dgap_tty_tiocmget(struct tty_struct *tty, struct file *file)
+#endif
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	int result = -EIO;
+	uchar mstat = 0;
+	ulong lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return result;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return result;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return result;
+
+	DPR_IOCTL(("dgap_tty_tiocmget start\n"));
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+
+	mstat = readb(&(ch->ch_bs->m_stat));
+        /* Append any outbound signals that might be pending... */
+        mstat |= ch->ch_mostat;
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	result = 0;
+
+	if (mstat & D_DTR(ch))
+		result |= TIOCM_DTR;
+	if (mstat & D_RTS(ch))
+		result |= TIOCM_RTS;
+	if (mstat & D_CTS(ch))
+		result |= TIOCM_CTS;
+	if (mstat & D_DSR(ch))
+		result |= TIOCM_DSR;
+	if (mstat & D_RI(ch))
+		result |= TIOCM_RI;
+	if (mstat & D_CD(ch))
+		result |= TIOCM_CD;
+
+	DPR_IOCTL(("dgap_tty_tiocmget finish\n"));
+
+	return result;
+}
+
+
+/*
+ * dgap_tty_tiocmset()
+ *
+ * Set modem signals, called by ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgap_tty_tiocmset(struct tty_struct *tty,
+                unsigned int set, unsigned int clear)
+#else
+static int dgap_tty_tiocmset(struct tty_struct *tty, struct file *file,
+		unsigned int set, unsigned int clear)
+#endif
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int ret = -EIO;
+	ulong lock_flags;
+	ulong lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return ret;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return ret;
+
+	DPR_IOCTL(("dgap_tty_tiocmset start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	if (set & TIOCM_RTS) {
+		ch->ch_mforce |= D_RTS(ch);
+		ch->ch_mval   |= D_RTS(ch);
+        }         
+
+	if (set & TIOCM_DTR) {
+		ch->ch_mforce |= D_DTR(ch);
+		ch->ch_mval   |= D_DTR(ch);
+        }         
+
+	if (clear & TIOCM_RTS) {
+		ch->ch_mforce |= D_RTS(ch);
+		ch->ch_mval   &= ~(D_RTS(ch));
+        }
+
+	if (clear & TIOCM_DTR) {
+		ch->ch_mforce |= D_DTR(ch);
+		ch->ch_mval   &= ~(D_DTR(ch));
+        }
+
+	dgap_param(tty);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_tiocmset finish\n"));
+
+	return (0);
+}
+
+
+
+/*
+ * dgap_tty_send_break()
+ *
+ * Send a Break, called by ld.
+ */
+static int dgap_tty_send_break(struct tty_struct *tty, int msec)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int ret = -EIO;
+	ulong lock_flags;
+	ulong lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return ret;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return ret;
+
+	switch (msec) {
+	case -1:
+		msec = 0xFFFF;
+		break;
+	case 0:
+		msec = 1;
+		break;
+	default:
+		msec /= 10;
+		break;
+	}
+
+	DPR_IOCTL(("dgap_tty_send_break start 1.  %lx\n", jiffies));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+#if 0
+	dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+#endif
+	dgap_cmdw(ch, SBREAK, (u16) msec, 0);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_send_break finish\n"));
+
+	return (0);
+}
+
+
+
+
+/*
+ * dgap_tty_wait_until_sent()
+ *
+ * wait until data has been transmitted, called by ld.
+ */
+static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	int rc;
+	rc = dgap_wait_for_drain(tty);
+	if (rc) {
+		DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+		return;
+	}
+	return;
+}
+
+
+
+/*
+ * dgap_send_xchar()
+ * 
+ * send a high priority character, called by ld.
+ */
+static void dgap_tty_send_xchar(struct tty_struct *tty, char c)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+	ulong lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_send_xchar start 1.  %lx\n", jiffies));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	/*
+	 * This is technically what we should do.
+	 * However, the NIST tests specifically want
+	 * to see each XON or XOFF character that it
+	 * sends, so lets just send each character
+	 * by hand...
+	 */
+#if 0
+	if (c == STOP_CHAR(tty)) {
+		dgap_cmdw(ch, RPAUSE, 0, 0);
+	}
+	else if (c == START_CHAR(tty)) {
+		dgap_cmdw(ch, RRESUME, 0, 0);
+	}
+	else {
+		dgap_wmove(ch, &c, 1);
+	}
+#else
+	dgap_wmove(ch, &c, 1);
+#endif
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_send_xchar finish\n"));
+
+	return;
+}
+
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value)
+{
+	int result = 0;
+	uchar mstat = 0;
+	ulong lock_flags;
+	int rc = 0;
+
+	DPR_IOCTL(("dgap_get_modem_info start\n"));
+
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return(-ENXIO);
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+
+	mstat = readb(&(ch->ch_bs->m_stat));
+	/* Append any outbound signals that might be pending... */
+	mstat |= ch->ch_mostat;
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	result = 0;
+
+	if (mstat & D_DTR(ch))
+		result |= TIOCM_DTR;
+	if (mstat & D_RTS(ch))
+		result |= TIOCM_RTS;
+	if (mstat & D_CTS(ch))
+		result |= TIOCM_CTS;
+	if (mstat & D_DSR(ch))
+		result |= TIOCM_DSR;
+	if (mstat & D_RI(ch))
+		result |= TIOCM_RI;
+	if (mstat & D_CD(ch))
+		result |= TIOCM_CD;
+
+	rc = put_user(result, value);
+
+	DPR_IOCTL(("dgap_get_modem_info finish\n"));
+	return(rc);
+}
+
+
+/*
+ * dgap_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int ret = -ENXIO;
+	unsigned int arg = 0;
+	ulong lock_flags;
+	ulong lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return ret;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return ret;
+
+	DPR_IOCTL(("dgap_set_modem_info() start\n"));
+
+	ret = get_user(arg, value);
+	if (ret) {
+		DPR_IOCTL(("dgap_set_modem_info %d ret: %x. finished.\n", __LINE__, ret));
+		return(ret);
+	}
+
+	DPR_IOCTL(("dgap_set_modem_info: command: %x arg: %x\n", command, arg));
+
+	switch (command) {
+	case TIOCMBIS:
+		if (arg & TIOCM_RTS) {
+			ch->ch_mforce |= D_RTS(ch);
+			ch->ch_mval   |= D_RTS(ch);
+        	}
+
+		if (arg & TIOCM_DTR) {
+			ch->ch_mforce |= D_DTR(ch);
+			ch->ch_mval   |= D_DTR(ch);
+        	}
+
+		break;
+
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS) {
+			ch->ch_mforce |= D_RTS(ch);
+			ch->ch_mval   &= ~(D_RTS(ch));
+        	}
+
+		if (arg & TIOCM_DTR) {
+			ch->ch_mforce |= D_DTR(ch);
+			ch->ch_mval   &= ~(D_DTR(ch));
+        	}
+
+		break;
+
+        case TIOCMSET:
+		ch->ch_mforce = D_DTR(ch)|D_RTS(ch);
+
+		if (arg & TIOCM_RTS) {
+			ch->ch_mval |= D_RTS(ch);
+        	}
+		else {
+			ch->ch_mval &= ~(D_RTS(ch));
+		}
+
+		if (arg & TIOCM_DTR) {
+			ch->ch_mval |= (D_DTR(ch));
+        	}
+		else {
+			ch->ch_mval &= ~(D_DTR(ch));
+		}
+
+		break;
+
+	default:
+		return(-EINVAL);
+	}
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	dgap_param(tty);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_set_modem_info finish\n"));
+
+	return (0);
+}
+
+
+/*
+ * dgap_tty_digigeta() 
+ *
+ * Ioctl to get the information for ditty.
+ *
+ *
+ *
+ */
+static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	struct digi_t tmp;
+	ulong lock_flags;
+
+	if (!retinfo)
+		return (-EFAULT);
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+	memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return (-EFAULT);
+
+	return (0);
+}
+
+
+/*
+ * dgap_tty_digiseta() 
+ *
+ * Ioctl to set the information for ditty.
+ *
+ *
+ *
+ */
+static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	struct digi_t new_digi;
+	ulong   lock_flags = 0;
+	unsigned long lock_flags2;
+
+	DPR_IOCTL(("DIGI_SETA start\n"));
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (-EFAULT);
+
+        if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) {
+		DPR_IOCTL(("DIGI_SETA failed copy_from_user\n"));
+                return(-EFAULT);
+	}
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
+
+	if (ch->ch_digi.digi_maxcps < 1) 
+		ch->ch_digi.digi_maxcps = 1;
+
+	if (ch->ch_digi.digi_maxcps > 10000) 
+		ch->ch_digi.digi_maxcps = 10000;
+
+	if (ch->ch_digi.digi_bufsize < 10)
+		ch->ch_digi.digi_bufsize = 10;
+
+	if (ch->ch_digi.digi_maxchar < 1)
+		ch->ch_digi.digi_maxchar = 1;
+
+	if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+		ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+	if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+		ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+	if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+		ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+	dgap_param(tty);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("DIGI_SETA finish\n"));
+
+	return(0);
+}
+
+
+/*
+ * dgap_tty_digigetedelay() 
+ *
+ * Ioctl to get the current edelay setting.
+ *
+ *
+ *
+ */
+static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	int tmp;
+	ulong lock_flags;
+
+	if (!retinfo)
+		return (-EFAULT);
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+	tmp = readw(&(ch->ch_bs->edelay));
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return (-EFAULT);
+
+	return (0);
+}
+
+
+/*
+ * dgap_tty_digisetedelay() 
+ *
+ * Ioctl to set the EDELAY setting
+ *
+ */
+static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int new_digi;
+	ulong lock_flags;
+	ulong lock_flags2;
+
+	DPR_IOCTL(("DIGI_SETA start\n"));
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (-EFAULT);
+
+        if (copy_from_user(&new_digi, new_info, sizeof(int))) {
+		DPR_IOCTL(("DIGI_SETEDELAY failed copy_from_user\n"));
+                return(-EFAULT);
+	}
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	writew((u16) new_digi, &(ch->ch_bs->edelay));
+
+	dgap_param(tty);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("DIGI_SETA finish\n"));
+
+	return(0);
+}
+
+
+/*
+ * dgap_tty_digigetcustombaud()
+ *
+ * Ioctl to get the current custom baud rate setting.
+ */
+static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	int tmp;
+	ulong lock_flags;
+
+	if (!retinfo)
+		return (-EFAULT);
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	DGAP_LOCK(ch->ch_lock, lock_flags);
+	tmp = dgap_get_custom_baud(ch);
+	DGAP_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("DIGI_GETCUSTOMBAUD. Returning %d\n", tmp));
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return (-EFAULT);
+
+	return (0);
+}
+
+
+/*
+ * dgap_tty_digisetcustombaud() 
+ *
+ * Ioctl to set the custom baud rate setting
+ */
+static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	uint new_rate;
+	ulong lock_flags;
+	ulong lock_flags2;
+
+	DPR_IOCTL(("DIGI_SETCUSTOMBAUD start\n"));
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (-EFAULT);
+
+
+	if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) {
+		DPR_IOCTL(("DIGI_SETCUSTOMBAUD failed copy_from_user\n"));
+		return(-EFAULT);
+	}
+
+	if (bd->bd_flags & BD_FEP5PLUS) {
+
+		DPR_IOCTL(("DIGI_SETCUSTOMBAUD. Setting %d\n", new_rate));
+
+		DGAP_LOCK(bd->bd_lock, lock_flags);
+		DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+		ch->ch_custom_speed = new_rate;
+
+		dgap_param(tty);
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+	}
+
+	DPR_IOCTL(("DIGI_SETCUSTOMBAUD finish\n"));
+
+	return(0);
+}
+
+
+/*
+ * dgap_set_termios()
+ */
+static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	unsigned long lock_flags;
+	unsigned long lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	ch->ch_c_cflag   = tty->termios.c_cflag;
+	ch->ch_c_iflag   = tty->termios.c_iflag;
+	ch->ch_c_oflag   = tty->termios.c_oflag;
+	ch->ch_c_lflag   = tty->termios.c_lflag;
+	ch->ch_startc    = tty->termios.c_cc[VSTART];
+	ch->ch_stopc     = tty->termios.c_cc[VSTOP];
+
+	dgap_carrier(ch);
+	dgap_param(tty);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+}
+
+
+static void dgap_tty_throttle(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+	ulong   lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+        
+        ch = un->un_ch;
+        if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+                return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_throttle start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	ch->ch_flags |= (CH_RXBLOCK);
+#if 1
+	dgap_cmdw(ch, RPAUSE, 0, 0);
+#endif
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_throttle finish\n"));
+}
+
+
+static void dgap_tty_unthrottle(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+	ulong   lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+        
+        ch = un->un_ch;
+        if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+                return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_unthrottle start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	ch->ch_flags &= ~(CH_RXBLOCK);
+
+#if 1
+	dgap_cmdw(ch, RRESUME, 0, 0);
+#endif
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_unthrottle finish\n"));
+}
+
+
+static void dgap_tty_start(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+	ulong   lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+        
+        ch = un->un_ch;
+        if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+                return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_start start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	dgap_cmdw(ch, RESUMETX, 0, 0);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_start finish\n"));
+}
+
+
+static void dgap_tty_stop(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+	ulong   lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+        
+        ch = un->un_ch;
+        if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+                return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_stop start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	dgap_cmdw(ch, PAUSETX, 0, 0);
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_stop finish\n"));
+}
+
+
+/* 
+ * dgap_tty_flush_chars()
+ *
+ * Flush the cook buffer
+ *
+ * Note to self, and any other poor souls who venture here:
+ *
+ * flush in this case DOES NOT mean dispose of the data.
+ * instead, it means "stop buffering and send it if you
+ * haven't already."  Just guess how I figured that out...   SRW 2-Jun-98
+ *
+ * It is also always called in interrupt context - JAR 8-Sept-99
+ */
+static void dgap_tty_flush_chars(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+	ulong   lock_flags2;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+        
+        ch = un->un_ch;
+        if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+                return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_flush_chars start\n"));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	/* TODO: Do something here */
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_flush_chars finish\n"));
+}
+
+
+
+/*
+ * dgap_tty_flush_buffer()
+ *              
+ * Flush Tx buffer (make in == out)
+ */
+static void dgap_tty_flush_buffer(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+	ulong   lock_flags2;
+	u16	head = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return;
+        
+        ch = un->un_ch;
+        if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+                return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgap_tty_flush_buffer on port: %d start\n", ch->ch_portnum));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	ch->ch_flags &= ~CH_STOP;
+	head = readw(&(ch->ch_bs->tx_head));
+	dgap_cmdw(ch, FLUSHTX, (u16) head, 0);
+	dgap_cmdw(ch, RESUMETX, 0, 0);
+	if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+		ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+		wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+	}
+	if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+		ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+		wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+	}
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+	if (waitqueue_active(&tty->write_wait))
+		wake_up_interruptible(&tty->write_wait);
+	tty_wakeup(tty);
+
+	DPR_IOCTL(("dgap_tty_flush_buffer finish\n"));
+}
+
+
+
+/*****************************************************************************
+ *
+ * The IOCTL function and all of its helpers
+ *
+ *****************************************************************************/
+                        
+/*
+ * dgap_tty_ioctl()
+ *
+ * The usual assortment of ioctl's
+ */
+static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+		unsigned long arg)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int rc;
+	u16	head = 0;
+	ulong   lock_flags = 0;
+	ulong   lock_flags2 = 0;
+	void __user *uarg = (void __user *) arg;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-ENODEV);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGAP_UNIT_MAGIC)
+		return (-ENODEV);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGAP_CHANNEL_MAGIC)
+		return (-ENODEV);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGAP_BOARD_MAGIC)
+		return (-ENODEV);
+
+	DPR_IOCTL(("dgap_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n", 
+		ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+	DGAP_LOCK(bd->bd_lock, lock_flags);
+	DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+	if (un->un_open_count <= 0) {
+		DPR_BASIC(("dgap_tty_ioctl - unit not open.\n"));
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(-EIO);
+	}
+
+	switch (cmd) {
+
+	/* Here are all the standard ioctl's that we MUST implement */
+
+	case TCSBRK:
+		/*
+		 * TCSBRK is SVID version: non-zero arg --> no break  
+		 * this behaviour is exploited by tcdrain().
+		 *
+		 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+		 * between 0.25 and 0.5 seconds so we'll ask for something
+		 * in the middle: 0.375 seconds.
+		 */
+		rc = tty_check_change(tty);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		if (rc) {
+			return(rc);
+		}
+
+		rc = dgap_wait_for_drain(tty);
+
+		if (rc) {
+			DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DGAP_LOCK(bd->bd_lock, lock_flags);
+		DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+		if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) {
+			dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+		}
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", 
+			ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+                return(0);
+
+
+	case TCSBRKP:
+ 		/* support for POSIX tcsendbreak()
+
+		 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+		 * between 0.25 and 0.5 seconds so we'll ask for something
+		 * in the middle: 0.375 seconds.
+		 */
+		rc = tty_check_change(tty);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		if (rc) {
+			return(rc);
+		}
+
+		rc = dgap_wait_for_drain(tty);
+		if (rc) {
+			DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DGAP_LOCK(bd->bd_lock, lock_flags);
+		DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+		dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", 
+			ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+		return(0);
+
+        case TIOCSBRK:
+		/*
+		 * FEP5 doesn't support turning on a break unconditionally.
+		 * The FEP5 device will stop sending a break automatically
+		 * after the specified time value that was sent when turning on
+		 * the break.
+		 */
+		rc = tty_check_change(tty);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		if (rc) {
+			return(rc);
+		}
+
+		rc = dgap_wait_for_drain(tty);
+		if (rc) {
+			DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DGAP_LOCK(bd->bd_lock, lock_flags);
+		DGAP_LOCK(ch->ch_lock, lock_flags2);
+
+		dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0);
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", 
+			ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+		return 0;
+                
+        case TIOCCBRK:
+		/*
+		 * FEP5 doesn't support turning off a break unconditionally.
+		 * The FEP5 device will stop sending a break automatically
+		 * after the specified time value that was sent when turning on
+		 * the break.
+		 */
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return 0;
+
+	case TIOCGSOFTCAR:
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
+		return(rc);
+
+	case TIOCSSOFTCAR:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		rc = get_user(arg, (unsigned long __user *) arg);
+		if (rc)
+			return(rc);
+
+		DGAP_LOCK(bd->bd_lock, lock_flags);
+		DGAP_LOCK(ch->ch_lock, lock_flags2);
+		tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+		dgap_param(tty);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		return(0);
+                        
+	case TIOCMGET:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+                return(dgap_get_modem_info(ch, uarg));
+
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_set_modem_info(tty, cmd, uarg));
+
+		/*
+		 * Here are any additional ioctl's that we want to implement
+		 */
+                        
+	case TCFLSH:  
+		/*
+		 * The linux tty driver doesn't have a flush
+		 * input routine for the driver, assuming all backed
+		 * up data is in the line disc. buffers.  However,
+		 * we all know that's not the case.  Here, we
+		 * act on the ioctl, but then lie and say we didn't
+		 * so the line discipline will process the flush
+		 * also.
+		 */   
+		rc = tty_check_change(tty);
+		if (rc) {
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			return(rc);
+		}
+
+		if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
+			if (!(un->un_type == DGAP_PRINT)) {
+				head = readw(&(ch->ch_bs->rx_head));
+				writew(head, &(ch->ch_bs->rx_tail));
+				writeb(0, &(ch->ch_bs->orun));
+			}
+		}
+
+		if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) {
+			ch->ch_flags &= ~CH_STOP;
+			head = readw(&(ch->ch_bs->tx_head));
+			dgap_cmdw(ch, FLUSHTX, (u16) head, 0 );
+			dgap_cmdw(ch, RESUMETX, 0, 0);
+			if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+				ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+				wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+			}
+			if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+				ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+				wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+			}
+			if (waitqueue_active(&tty->write_wait))
+				wake_up_interruptible(&tty->write_wait);
+
+			/* Can't hold any locks when calling tty_wakeup! */
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			tty_wakeup(tty);
+			DGAP_LOCK(bd->bd_lock, lock_flags);
+			DGAP_LOCK(ch->ch_lock, lock_flags2);
+		}                  
+
+		/* pretend we didn't recognize this IOCTL */  
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		DPR_IOCTL(("dgap_tty_ioctl (LINE:%d) finish on port %d - cmd %s (%x), arg %lx\n", 
+			__LINE__, ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+		return(-ENOIOCTLCMD);
+
+	case TCSETSF:
+	case TCSETSW:
+		/*
+		 * The linux tty driver doesn't have a flush
+		 * input routine for the driver, assuming all backed
+		 * up data is in the line disc. buffers.  However,
+		 * we all know that's not the case.  Here, we
+		 * act on the ioctl, but then lie and say we didn't
+		 * so the line discipline will process the flush
+		 * also.
+		 */
+		if (cmd == TCSETSF) {
+			/* flush rx */
+			ch->ch_flags &= ~CH_STOP;
+			head = readw(&(ch->ch_bs->rx_head));
+			writew(head, &(ch->ch_bs->rx_tail));
+		}
+
+		/* now wait for all the output to drain */
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		rc = dgap_wait_for_drain(tty);
+		if (rc) {
+			DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", 
+			ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg));
+
+		/* pretend we didn't recognize this */
+		return(-ENOIOCTLCMD);
+
+	case TCSETAW:
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		rc = dgap_wait_for_drain(tty);
+		if (rc) {
+			DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		/* pretend we didn't recognize this */
+		return(-ENOIOCTLCMD);  
+
+	case TCXONC:
+		/*
+		 * The Linux Line Discipline (LD) would do this for us if we
+		 * let it, but we have the special firmware options to do this
+		 * the "right way" regardless of hardware or software flow
+		 * control so we'll do it outselves instead of letting the LD
+		 * do it.
+		 */
+		rc = tty_check_change(tty);
+		if (rc) {
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			return(rc);
+		}
+
+		DPR_IOCTL(("dgap_ioctl - in TCXONC - %d\n", cmd));
+		switch (arg) {
+
+		case TCOON:
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			dgap_tty_start(tty);
+			return(0);
+		case TCOOFF:
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			dgap_tty_stop(tty);
+			return(0);
+		case TCION:
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			/* Make the ld do it */
+			return(-ENOIOCTLCMD);
+		case TCIOFF:
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			/* Make the ld do it */
+			return(-ENOIOCTLCMD);
+		default:
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			return(-EINVAL);
+		}
+
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(-ENOIOCTLCMD);
+
+	case DIGI_GETA:
+		/* get information for ditty */
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_tty_digigeta(tty, uarg));
+
+	case DIGI_SETAW:
+	case DIGI_SETAF:
+
+		/* set information for ditty */
+		if (cmd == (DIGI_SETAW)) {
+
+			DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+			DGAP_UNLOCK(bd->bd_lock, lock_flags);
+			rc = dgap_wait_for_drain(tty);
+			if (rc) {
+				DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc));
+				return(-EINTR);
+			}
+			DGAP_LOCK(bd->bd_lock, lock_flags);
+			DGAP_LOCK(ch->ch_lock, lock_flags2);
+		}
+		else {
+			tty_ldisc_flush(tty);
+		}
+		/* fall thru */
+
+	case DIGI_SETA:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_tty_digiseta(tty, uarg));
+
+	case DIGI_GEDELAY:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_tty_digigetedelay(tty, uarg));
+
+	case DIGI_SEDELAY:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_tty_digisetedelay(tty, uarg));
+
+	case DIGI_GETCUSTOMBAUD:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_tty_digigetcustombaud(tty, uarg));
+
+	case DIGI_SETCUSTOMBAUD:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return(dgap_tty_digisetcustombaud(tty, uarg));
+
+	case DIGI_RESET_PORT:
+		dgap_firmware_reset_port(ch);
+		dgap_param(tty);
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+		return 0;
+
+	default:
+		DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+		DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+		DPR_IOCTL(("dgap_tty_ioctl - in default\n"));
+		DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n", 
+			dgap_ioctl_name(cmd), cmd, arg));
+
+		return(-ENOIOCTLCMD);
+	}
+
+	DGAP_UNLOCK(ch->ch_lock, lock_flags2);
+	DGAP_UNLOCK(bd->bd_lock, lock_flags);
+
+	DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n", 
+		dgap_ioctl_name(cmd), cmd, arg));
+                        
+	return(0);
+}
diff --git a/drivers/staging/dgap/dgap_tty.h b/drivers/staging/dgap/dgap_tty.h
new file mode 100644
index 0000000..464a460
--- /dev/null
+++ b/drivers/staging/dgap/dgap_tty.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGAP_TTY_H
+#define __DGAP_TTY_H
+
+#include "dgap_driver.h"
+
+int	dgap_tty_register(struct board_t *brd);
+
+int	dgap_tty_preinit(void);
+int     dgap_tty_init(struct board_t *);
+
+void	dgap_tty_post_uninit(void);
+void	dgap_tty_uninit(struct board_t *);
+
+void	dgap_carrier(struct channel_t *ch);
+void	dgap_input(struct channel_t *ch);
+
+
+#endif
diff --git a/drivers/staging/dgap/dgap_types.h b/drivers/staging/dgap/dgap_types.h
new file mode 100644
index 0000000..eca38c7
--- /dev/null
+++ b/drivers/staging/dgap/dgap_types.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGAP_TYPES_H
+#define __DGAP_TYPES_H
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+/* Required for our shared headers! */
+typedef unsigned char		uchar;
+
+#endif
diff --git a/drivers/staging/dgap/digi.h b/drivers/staging/dgap/digi.h
new file mode 100644
index 0000000..651e2e5
--- /dev/null
+++ b/drivers/staging/dgap/digi.h
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * $Id: digi.h,v 1.1 2009/10/23 14:01:57 markh Exp $
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DIGI_H
+#define __DIGI_H
+
+/************************************************************************
+ ***	Definitions for Digi ditty(1) command.
+ ************************************************************************/
+
+
+/*
+ * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved.
+ */
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+#if !defined(TIOCMODG)
+
+#define	TIOCMODG	('d'<<8) | 250		/* get modem ctrl state	*/
+#define	TIOCMODS	('d'<<8) | 251		/* set modem ctrl state	*/
+
+#ifndef TIOCM_LE 
+#define		TIOCM_LE	0x01		/* line enable		*/
+#define		TIOCM_DTR	0x02		/* data terminal ready	*/
+#define		TIOCM_RTS	0x04		/* request to send	*/
+#define		TIOCM_ST	0x08		/* secondary transmit	*/
+#define		TIOCM_SR	0x10		/* secondary receive	*/
+#define		TIOCM_CTS	0x20		/* clear to send	*/
+#define		TIOCM_CAR	0x40		/* carrier detect	*/
+#define		TIOCM_RNG	0x80		/* ring	indicator	*/
+#define		TIOCM_DSR	0x100		/* data set ready	*/
+#define		TIOCM_RI	TIOCM_RNG	/* ring (alternate)	*/
+#define		TIOCM_CD	TIOCM_CAR	/* carrier detect (alt)	*/
+#endif
+
+#endif
+
+#if !defined(TIOCMSET)
+#define	TIOCMSET	('d'<<8) | 252		/* set modem ctrl state	*/
+#define	TIOCMGET	('d'<<8) | 253		/* set modem ctrl state	*/
+#endif
+
+#if !defined(TIOCMBIC)
+#define	TIOCMBIC	('d'<<8) | 254		/* set modem ctrl state */
+#define	TIOCMBIS	('d'<<8) | 255		/* set modem ctrl state */
+#endif
+
+
+#if !defined(TIOCSDTR)
+#define	TIOCSDTR	('e'<<8) | 0		/* set DTR		*/
+#define	TIOCCDTR	('e'<<8) | 1		/* clear DTR		*/
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA	('e'<<8) | 94		/* Read params		*/
+
+#define DIGI_SETA	('e'<<8) | 95		/* Set params		*/
+#define DIGI_SETAW	('e'<<8) | 96		/* Drain & set params	*/
+#define DIGI_SETAF	('e'<<8) | 97		/* Drain, flush & set params */
+
+#define DIGI_KME	('e'<<8) | 98		/* Read/Write Host	*/
+						/* Adapter Memory	*/
+
+#define	DIGI_GETFLOW	('e'<<8) | 99		/* Get startc/stopc flow */
+						/* control characters 	 */
+#define	DIGI_SETFLOW	('e'<<8) | 100		/* Set startc/stopc flow */
+						/* control characters	 */
+#define	DIGI_GETAFLOW	('e'<<8) | 101		/* Get Aux. startc/stopc */
+						/* flow control chars 	 */
+#define	DIGI_SETAFLOW	('e'<<8) | 102		/* Set Aux. startc/stopc */
+						/* flow control chars	 */
+
+#define DIGI_GEDELAY	('d'<<8) | 246		/* Get edelay */
+#define DIGI_SEDELAY	('d'<<8) | 247		/* Set edelay */
+
+struct	digiflow_t {
+	unsigned char	startc;				/* flow cntl start char	*/
+	unsigned char	stopc;				/* flow cntl stop char	*/
+};
+
+
+#ifdef	FLOW_2200
+#define	F2200_GETA	('e'<<8) | 104		/* Get 2x36 flow cntl flags */
+#define	F2200_SETAW	('e'<<8) | 105		/* Set 2x36 flow cntl flags */
+#define		F2200_MASK	0x03		/* 2200 flow cntl bit mask  */
+#define		FCNTL_2200	0x01		/* 2x36 terminal flow cntl  */
+#define		PCNTL_2200	0x02		/* 2x36 printer flow cntl   */
+#define	F2200_XON	0xf8
+#define	P2200_XON	0xf9
+#define	F2200_XOFF	0xfa
+#define	P2200_XOFF	0xfb
+
+#define	FXOFF_MASK	0x03			/* 2200 flow status mask    */
+#define	RCVD_FXOFF	0x01			/* 2x36 Terminal XOFF rcvd  */
+#define	RCVD_PXOFF	0x02			/* 2x36 Printer XOFF rcvd   */
+#endif
+
+/************************************************************************
+ * Values for digi_flags 
+ ************************************************************************/
+#define DIGI_IXON	0x0001		/* Handle IXON in the FEP	*/
+#define DIGI_FAST	0x0002		/* Fast baud rates		*/
+#define RTSPACE		0x0004		/* RTS input flow control	*/
+#define CTSPACE		0x0008		/* CTS output flow control	*/
+#define DSRPACE		0x0010		/* DSR output flow control	*/
+#define DCDPACE		0x0020		/* DCD output flow control	*/
+#define DTRPACE		0x0040		/* DTR input flow control	*/
+#define DIGI_COOK	0x0080		/* Cooked processing done in FEP */
+#define DIGI_FORCEDCD	0x0100		/* Force carrier		*/
+#define	DIGI_ALTPIN	0x0200		/* Alternate RJ-45 pin config	*/
+#define	DIGI_AIXON	0x0400		/* Aux flow control in fep	*/
+#define	DIGI_PRINTER	0x0800		/* Hold port open for flow cntrl*/
+#define DIGI_PP_INPUT	0x1000		/* Change parallel port to input*/
+#define DIGI_DTR_TOGGLE 0x2000		/* Support DTR Toggle		*/
+#define	DIGI_422	0x4000		/* for 422/232 selectable panel */
+#define DIGI_RTS_TOGGLE	0x8000		/* Support RTS Toggle		*/
+
+/************************************************************************
+ * These options are not supported on the comxi.
+ ************************************************************************/
+#define	DIGI_COMXI	(DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE)
+
+#define DIGI_PLEN	28		/* String length		*/
+#define	DIGI_TSIZ	10		/* Terminal string len		*/
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_t {
+	unsigned short	digi_flags;		/* Flags (see above)	*/
+	unsigned short	digi_maxcps;		/* Max printer CPS	*/
+	unsigned short	digi_maxchar;		/* Max chars in print queue */
+	unsigned short	digi_bufsize;		/* Buffer size		*/
+	unsigned char	digi_onlen;		/* Length of ON string	*/
+	unsigned char	digi_offlen;		/* Length of OFF string	*/
+	char		digi_onstr[DIGI_PLEN];	/* Printer on string	*/
+	char		digi_offstr[DIGI_PLEN];	/* Printer off string	*/
+	char		digi_term[DIGI_TSIZ];	/* terminal string	*/
+};
+
+/************************************************************************
+ * KME definitions and structures.
+ ************************************************************************/
+#define	RW_IDLE		0	/* Operation complete			*/
+#define	RW_READ		1	/* Read Concentrator Memory		*/
+#define	RW_WRITE	2	/* Write Concentrator Memory		*/
+
+struct rw_t {
+	unsigned char	rw_req;		/* Request type			*/
+	unsigned char	rw_board;	/* Host Adapter board number	*/
+	unsigned char	rw_conc;	/* Concentrator number		*/
+	unsigned char	rw_reserved;	/* Reserved for expansion	*/
+	unsigned long	rw_addr;	/* Address in concentrator	*/
+	unsigned short	rw_size;	/* Read/write request length	*/
+	unsigned char	rw_data[128];	/* Data to read/write		*/
+};
+
+/***********************************************************************
+ * Shrink Buffer and Board Information definitions and structures.
+
+ ************************************************************************/
+			/* Board type return codes */
+#define	PCXI_TYPE 1     /* Board type at the designated port is a PC/Xi */
+#define PCXM_TYPE 2     /* Board type at the designated port is a PC/Xm */
+#define	PCXE_TYPE 3     /* Board type at the designated port is a PC/Xe */
+#define	MCXI_TYPE 4     /* Board type at the designated port is a MC/Xi */
+#define COMXI_TYPE 5     /* Board type at the designated port is a COM/Xi */
+
+			 /* Non-Zero Result codes. */
+#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */ 
+#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */ 
+#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */
+#define RESULT_TOOSML  4 /* Too small an area to shrink.  */
+#define RESULT_NOCHAN  5 /* Channel structure for the board was not found */
+
+struct shrink_buf_struct {
+	unsigned long	shrink_buf_vaddr;	/* Virtual address of board */
+	unsigned long	shrink_buf_phys;	/* Physical address of board */
+	unsigned long	shrink_buf_bseg;	/* Amount of board memory */
+	unsigned long	shrink_buf_hseg;	/* '186 Begining of Dual-Port */
+
+	unsigned long	shrink_buf_lseg;	/* '186 Begining of freed memory						*/ 
+	unsigned long	shrink_buf_mseg;	/* Linear address from start of
+						   dual-port were freed memory
+						   begins, host viewpoint. */
+
+	unsigned long	shrink_buf_bdparam;	/* Parameter for xxmemon and
+						   xxmemoff */
+
+	unsigned long	shrink_buf_reserva;	/* Reserved */
+	unsigned long	shrink_buf_reservb;	/* Reserved */
+	unsigned long	shrink_buf_reservc;	/* Reserved */
+	unsigned long	shrink_buf_reservd;	/* Reserved */
+
+	unsigned char	shrink_buf_result;	/* Reason for call failing
+						   Zero is Good return */
+	unsigned char	shrink_buf_init;	/* Non-Zero if it caused an     
+						   xxinit call. */
+
+	unsigned char	shrink_buf_anports;	/* Number of async ports  */
+	unsigned char	shrink_buf_snports; 	/* Number of sync  ports */
+	unsigned char	shrink_buf_type;	/* Board type 1 = PC/Xi,
+							      2 = PC/Xm,
+							      3 = PC/Xe  
+							      4 = MC/Xi  
+							      5 = COMX/i */
+	unsigned char	shrink_buf_card;	/* Card number */
+	
+};
+
+/************************************************************************
+ * Structure to get driver status information
+ ************************************************************************/
+struct digi_dinfo {
+	unsigned long	dinfo_nboards;		/* # boards configured	*/
+	char		dinfo_reserved[12];	/* for future expansion */
+	char		dinfo_version[16];	/* driver version       */
+};
+
+#define	DIGI_GETDD	('d'<<8) | 248		/* get driver info      */
+ 
+/************************************************************************
+ * Structure used with ioctl commands for per-board information
+ *
+ * physsize and memsize differ when board has "windowed" memory
+ ************************************************************************/
+struct digi_info {
+	unsigned long	info_bdnum;		/* Board number (0 based)  */
+	unsigned long	info_ioport;		/* io port address         */
+	unsigned long	info_physaddr;		/* memory address          */
+	unsigned long	info_physsize;		/* Size of host mem window */
+	unsigned long	info_memsize;		/* Amount of dual-port mem */
+						/* on board                */
+	unsigned short	info_bdtype;		/* Board type              */
+	unsigned short	info_nports;		/* number of ports         */
+	char		info_bdstate;		/* board state             */
+	char		info_reserved[7];	/* for future expansion    */
+};
+
+#define	DIGI_GETBD	('d'<<8) | 249		/* get board info          */
+ 
+struct digi_stat {
+	unsigned int	info_chan;		/* Channel number (0 based)  */
+	unsigned int	info_brd;		/* Board number (0 based)  */
+	unsigned long	info_cflag;		/* cflag for channel       */
+	unsigned long	info_iflag;		/* iflag for channel       */
+	unsigned long	info_oflag;		/* oflag for channel       */
+	unsigned long	info_mstat;		/* mstat for channel       */
+	unsigned long	info_tx_data;		/* tx_data for channel       */
+	unsigned long	info_rx_data;		/* rx_data for channel       */
+	unsigned long	info_hflow;		/* hflow for channel       */
+	unsigned long	info_reserved[8];	/* for future expansion    */
+};
+
+#define	DIGI_GETSTAT	('d'<<8) | 244		/* get board info          */
+/************************************************************************
+ *
+ * Structure used with ioctl commands for per-channel information
+ *
+ ************************************************************************/
+struct digi_ch {
+	unsigned long	info_bdnum;		/* Board number (0 based)  */
+	unsigned long	info_channel;		/* Channel index number    */
+	unsigned long	info_ch_cflag;		/* Channel cflag   	   */
+	unsigned long	info_ch_iflag;		/* Channel iflag   	   */
+	unsigned long	info_ch_oflag;		/* Channel oflag   	   */
+	unsigned long	info_chsize;		/* Channel structure size  */
+	unsigned long	info_sleep_stat;	/* sleep status		   */
+	dev_t		info_dev;		/* device number	   */
+	unsigned char	info_initstate;		/* Channel init state	   */
+	unsigned char	info_running;		/* Channel running state   */
+	long		reserved[8];		/* reserved for future use */
+};
+
+/*
+* This structure is used with the DIGI_FEPCMD ioctl to 
+* tell the driver which port to send the command for.
+*/
+struct digi_cmd {
+	int	cmd;
+	int	word;
+	int	ncmds;
+	int	chan; /* channel index (zero based) */
+	int	bdid; /* board index (zero based) */
+};
+
+/*
+*  info_sleep_stat defines
+*/
+#define INFO_RUNWAIT	0x0001
+#define INFO_WOPEN	0x0002
+#define INFO_TTIOW	0x0004
+#define INFO_CH_RWAIT	0x0008
+#define INFO_CH_WEMPTY	0x0010
+#define INFO_CH_WLOW	0x0020
+#define INFO_XXBUF_BUSY 0x0040
+
+#define	DIGI_GETCH	('d'<<8) | 245		/* get board info          */
+
+/* Board type definitions */
+
+#define	SUBTYPE		0007
+#define	T_PCXI		0000
+#define T_PCXM		0001
+#define T_PCXE		0002
+#define T_PCXR		0003
+#define T_SP		0004
+#define T_SP_PLUS	0005
+#	define T_HERC	0000
+#	define T_HOU	0001
+#	define T_LON	0002
+#	define T_CHA	0003
+#define FAMILY		0070
+#define T_COMXI		0000
+#define T_PCXX		0010
+#define T_CX		0020
+#define T_EPC		0030
+#define	T_PCLITE	0040
+#define	T_SPXX		0050
+#define	T_AVXX		0060
+#define T_DXB		0070
+#define T_A2K_4_8	0070
+#define BUSTYPE		0700
+#define T_ISABUS	0000
+#define T_MCBUS		0100
+#define	T_EISABUS	0200
+#define	T_PCIBUS	0400
+
+/* Board State Definitions */
+
+#define	BD_RUNNING	0x0
+#define	BD_REASON	0x7f
+#define	BD_NOTFOUND	0x1
+#define	BD_NOIOPORT	0x2
+#define	BD_NOMEM	0x3
+#define	BD_NOBIOS	0x4
+#define	BD_NOFEP	0x5
+#define	BD_FAILED	0x6
+#define BD_ALLOCATED	0x7
+#define BD_TRIBOOT	0x8
+#define	BD_BADKME	0x80
+
+#define DIGI_LOOPBACK	      ('d'<<8) | 252		/* Enable/disable UART internal loopback */
+#define DIGI_SPOLL            ('d'<<8) | 254		/* change poller rate   */
+
+#define DIGI_SETCUSTOMBAUD	_IOW('e', 106, int)	/* Set integer baud rate */
+#define DIGI_GETCUSTOMBAUD	_IOR('e', 107, int)	/* Get integer baud rate */
+#define DIGI_RESET_PORT		('e'<<8) | 93		/* Reset port		*/
+
+#endif /* DIGI_H */
diff --git a/drivers/staging/dgap/downld.c b/drivers/staging/dgap/downld.c
new file mode 100644
index 0000000..57dfd6b
--- /dev/null
+++ b/drivers/staging/dgap/downld.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $
+ */
+
+/*
+** downld.c
+**
+**  This is the daemon that sends the fep, bios, and concentrator images
+**  from user space to the driver.
+** BUGS: 
+**  If the file changes in the middle of the download, you probably
+**     will get what you deserve.
+**
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+#include "dgap_types.h"
+#include "digi.h"
+#include "dgap_fep5.h"
+
+#include "dgap_downld.h"
+
+#include <string.h>
+#include <malloc.h>
+#include <stddef.h>
+#include <unistd.h>
+
+char		*pgm;
+void		myperror();
+
+/*
+**  This structure is used to keep track of the diferent images available
+**  to give to the driver.  It is arranged so that the things that are
+**  constants or that have defaults are first inthe strucutre to simplify
+**  the table of initializers.
+*/
+struct image_info {
+	short	type;		/* bios, fep, conc */
+	short	family;		/* boards this applies to */
+	short	subtype;	/* subtype */
+	int	len;		/* size of image */
+	char	*image;		/* ioctl struct + image */
+	char	*name;
+	char	*fname;		/* filename of binary (i.e. "asfep.bin") */
+	char	*pathname;	/* pathname to this binary ("/etc/dgap/xrfep.bin"); */
+	time_t	mtime;		/* Last modification time */
+};
+
+#define IBIOS	0
+#define	IFEP	1
+#define	ICONC	2
+#define ICONFIG	3
+#define	IBAD	4
+
+#define DEFAULT_LOC "/lib/firmware/dgap/"
+
+struct image_info	*image_list;
+int			nimages, count;
+
+struct image_info images[] = {
+{IBIOS, T_EPC,      SUBTYPE, 0, NULL, "EPC/X",	"fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 },
+{IFEP,  T_EPC,      SUBTYPE, 0, NULL, "EPC/X",	"fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 },
+{ICONC, T_EPC,      SUBTYPE, 0, NULL, "EPC/X",	"fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 },
+
+{IBIOS, T_CX,       SUBTYPE, 0, NULL, "C/X",	"cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 },
+{IFEP,  T_CX,       SUBTYPE, 0, NULL, "C/X",	"cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 },
+
+{IBIOS, T_CX,       T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 },
+{IFEP,  T_CX,       T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 },
+
+{ICONC, T_CX,       SUBTYPE, 0, NULL, "C/X",	"cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 },
+{ICONC, T_CX,       SUBTYPE, 0, NULL, "C/X",	"ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 },
+{ICONC, T_CX,       SUBTYPE, 0, NULL, "C/X",	"ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 },
+
+{IBIOS, FAMILY,   T_PCXR, 0, NULL, "PCXR",	"xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 },
+{IFEP,  FAMILY,   T_PCXR, 0,  NULL,  "PCXR",	"xrfep.bin", DEFAULT_LOC "xrfep.bin", 0  },
+
+{IBIOS, T_PCLITE,   SUBTYPE, 0, NULL, "X/em",	"sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 },
+{IFEP,  T_PCLITE,   SUBTYPE, 0,  NULL,  "X/em",	"sxfep.bin", DEFAULT_LOC "sxfep.bin", 0  },
+
+{IBIOS, T_EPC,      T_PCIBUS, 0, NULL, "PCI",	"pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 },
+{IFEP,  T_EPC,      T_PCIBUS, 0, NULL, "PCI",	"pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 },
+{ICONFIG, 0,	    0, 0, NULL,         NULL,	"dgap.conf",	"/etc/dgap.conf", 0 },
+
+/* IBAD/NULL entry indicating end-of-table */
+
+{IBAD,  0,     0, 0,  NULL,  NULL, NULL, NULL, 0 }
+
+} ;
+
+int 	errorprint = 1;
+int 	nodldprint = 1;
+int	debugflag;
+int 	fd;
+
+struct downld_t *ip;	/* Image pointer in current image  */
+struct downld_t *dp; 	/* conc. download */
+
+
+/*
+ * The same for either the FEP or the BIOS. 
+ *  Append the downldio header, issue the ioctl, then free
+ *  the buffer.  Not horribly CPU efficient, but quite RAM efficient.
+ */
+
+void squirt(int req_type, int bdid, struct image_info *ii)
+{
+	struct downldio	*dliop;
+	int size_buf;
+	int sfd;
+	struct stat sb;
+
+	/*
+	 * If this binary comes from a file, stat it to see how
+	 * large it is. Yes, we intentionally do this each
+	 * time for the binary may change between loads. 
+	 */
+
+	if (ii->pathname) {
+		sfd = open(ii->pathname, O_RDONLY);
+
+		if (sfd < 0 ) {
+			myperror(ii->pathname);
+			goto squirt_end; 
+		}
+
+		if (fstat(sfd, &sb) == -1 ) {
+			myperror(ii->pathname);
+			goto squirt_end;
+		}
+
+		ii->len = sb.st_size ; 
+	}
+
+	size_buf = ii->len + sizeof(struct downldio);
+
+	/*
+	 * This buffer will be freed at the end of this function.  It is
+	 * not resilient and should be around only long enough for the d/l
+	 * to happen.
+	 */
+	dliop = (struct downldio *) malloc(size_buf);
+
+	if (dliop == NULL) {
+		fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n", 
+			pgm, size_buf);
+		exit (1);
+	}
+
+	/* Now, stick the image in fepimage.  This can come from either
+	 *  the compiled-in image or from the filesystem.
+	 */
+	if (ii->pathname)
+		read(sfd, dliop->image.fi.fepimage, ii->len);
+	else
+		memcpy(dliop ->image.fi.fepimage, ii->image, ii->len);
+
+	dliop->req_type = req_type;
+	dliop->bdid = bdid;
+
+	dliop->image.fi.len = ii->len;
+
+	if (debugflag)
+		printf("sending %d bytes of %s %s from %s\n",
+			ii->len, 
+			(ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG",
+			ii->name ? ii->name : "",
+			(ii->pathname) ? ii->pathname : "internal image" );
+
+	if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) {
+		if(errorprint) {
+			fprintf(stderr,
+				"%s: warning - download ioctl failed\n",pgm);
+			errorprint = 0;
+		}
+		sleep(2);
+	}
+
+squirt_end:
+
+	if (ii->pathname) {
+		close(sfd);
+	}
+	free(dliop);
+}
+
+
+/*
+ *  See if we need to reload the download image in core 
+ * 
+ */
+void consider_file_rescan(struct image_info *ii)
+{
+	int sfd ; 
+	int len ; 
+	struct stat 	sb;
+
+	/* This operation only makes sense when we're working from a file */
+
+	if (ii->pathname) {
+
+		sfd = open (ii->pathname, O_RDONLY) ;
+		if (sfd < 0 ) {
+			myperror(ii->pathname);
+			exit(1) ;
+		}
+
+		if( fstat(sfd,&sb) == -1 ) {
+			myperror(ii->pathname);
+			exit(1);
+		}
+		
+		/* If the file hasn't changed since we last did this, 
+		 * and we have not done a free() on the image, bail  
+		 */
+		if (ii->image && (sb.st_mtime == ii->mtime))
+			goto end_rescan;
+
+		ii->len = len = sb.st_size ; 
+
+		/* Record the timestamp of the file */
+		ii->mtime = sb.st_mtime;
+
+		/* image should be NULL unless there is an image malloced
+		 * in already.  Before we malloc again, make sure we don't
+		 * have a memory leak.
+		 */
+		if ( ii->image ) {
+			free( ii->image ); 
+			/* ii->image = NULL; */ /* not necessary */
+		}
+
+		/* This image will be kept only long enough for the 
+		 * download to happen.  After sending the last block, 
+		 * it will be freed
+		 */
+		ii->image = malloc(len) ;
+
+		if (ii->image == NULL) {
+			fprintf(stderr,
+				"%s: can't get %d bytes of memory; aborting\n",
+				 pgm, len);
+			exit (1);
+		}
+
+		if (read(sfd, ii->image, len) < len) {
+			fprintf(stderr,"%s: read error on %s; aborting\n", 
+				pgm, ii->pathname);
+			exit (1);
+		}
+
+end_rescan:
+		close(sfd);
+		
+	}
+}
+
+/*
+ * Scan for images to match the driver requests
+ */
+
+struct image_info * find_conc_image()
+{
+	int x ; 
+	struct image_info *i = NULL ; 
+
+	for ( x = 0; x < nimages; x++ ) {
+		i=&image_list[x];
+				
+		if(i->type != ICONC)
+			continue;
+
+		consider_file_rescan(i) ;
+
+		ip = (struct downld_t *) image_list[x].image;
+		if (ip == NULL) continue;
+
+		/*
+		 * When I removed Clusterport, I kept only the code that I
+		 * was SURE wasn't ClusterPort.  We may not need the next two
+		 * lines of code.
+		 */
+		if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev ))
+			return i;
+	} 
+	return NULL ; 
+}
+
+
+int main(int argc, char **argv)
+{
+	struct downldio	dlio;
+	int 		offset, bsize;
+	int 		x;
+	char 		*down, *image, *fname;
+	struct image_info *ii;
+
+	pgm = argv[0];
+	dp = &dlio.image.dl;		/* conc. download */
+
+	while((argc > 2) && !strcmp(argv[1],"-d")) {
+		debugflag++ ;
+		argc-- ;
+		argv++ ;
+	}
+
+	if(argc < 2) {
+		fprintf(stderr,
+			"usage: %s download-device [image-file] ...\n",
+			pgm);
+		exit(1);
+	}
+
+
+
+	/*
+	 * Daemonize, unless debugging is turned on.
+	 */
+	if (debugflag == 0) {
+		switch (fork())
+		{
+		case 0:
+			break;
+
+		case -1:
+			return 1;
+
+		default:
+			return 0;
+		}
+
+		setsid();
+
+		/*
+		 * The child no longer needs "stdin", "stdout", or "stderr",
+		 * and should not block processes waiting for them to close.
+		 */
+		fclose(stdin);
+		fclose(stdout);
+		fclose(stderr);
+
+	}
+
+	while (1) {
+		if( (fd = open(argv[1], O_RDWR)) == -1 ) {
+			sleep(1);
+		}
+		else
+			break;
+	}
+
+	/*
+	** create a list of images to search through when trying to match
+	** requests from the driver.  Put images from the command line in
+	** the list before built in images so that the command line images
+	** can override the built in ones.
+	*/
+	
+	/* allocate space for the list */
+
+	nimages = argc - 2;
+
+	/* count the number of default list entries */
+
+	for (count = 0; images[count].type != IBAD; ++count) ;
+
+	nimages += count;
+
+	/* Really should just remove the variable "image_list".... robertl */
+	image_list = images ; 
+	   
+	/* get the images from the command line */
+	for(x = 2; x < argc; x++) {
+		int xx; 
+
+		/*
+		 * strip off any leading path information for 
+		 * determining file type 
+		 */
+		if( (fname = strrchr(argv[x],'/')) == NULL)
+			fname = argv[x];
+		else
+			fname++;	/* skip the slash */
+
+		for (xx = 0; xx < count; xx++) {
+			if (strcmp(fname, images[xx].fname) == 0 ) { 
+				images[xx].pathname = argv[x];
+
+				/* image should be NULL until */
+				/* space is malloced */
+				images[xx].image = NULL ;  
+			}
+		}
+	}
+
+        sleep(3);
+	
+	/*
+	** Endless loop: get a request from the fep, and service that request.
+	*/
+	for(;;) {
+		/* get the request */
+		if (debugflag)
+			printf("b4 get ioctl...");
+	
+		if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) {
+			if (errorprint) {
+				fprintf(stderr,
+					"%s: warning - download ioctl failed\n",
+					pgm);
+				errorprint = 0;
+			}
+			sleep(2);
+		} else {
+			if (debugflag)
+				printf("dlio.req_type is %d bd %d\n",
+					dlio.req_type,dlio.bdid);
+	
+			switch(dlio.req_type) {
+			case DLREQ_BIOS:
+				/*
+				** find the bios image for this type
+				*/
+				for ( x = 0; x < nimages; x++ ) {
+					if(image_list[x].type != IBIOS)
+						continue;
+	
+					if ((dlio.image.fi.type & FAMILY) == 
+						image_list[x].family) {
+						
+						if ( image_list[x].family == T_CX   ) { 
+							if ((dlio.image.fi.type & BUSTYPE) 
+								== T_PCIBUS ) {
+								if ( image_list[x].subtype 
+									== T_PCIBUS )
+									break;
+							}
+							else { 
+								break;
+							}
+						}
+						else if ( image_list[x].family == T_EPC ) {
+						/* If subtype of image is T_PCIBUS, it is */
+						/* a PCI EPC image, so the board must */
+						/* have bus type T_PCIBUS to match */
+							if ((dlio.image.fi.type & BUSTYPE) 
+								== T_PCIBUS ) {
+								if ( image_list[x].subtype 
+									== T_PCIBUS )
+									break;
+							}
+							else { 
+							/* NON PCI EPC doesn't use PCI image */
+								if ( image_list[x].subtype 
+									!= T_PCIBUS )
+									break;
+							}
+						}
+						else
+							break;
+					}
+					else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
+						/* PCXR board will break out of the loop here */
+						if ( image_list[x].subtype == T_PCXR   ) { 
+									break;
+						}
+					}
+				}
+	
+				if ( x >= nimages) {
+					/*
+					** no valid images exist
+					*/
+					if(nodldprint) {
+						fprintf(stderr,
+						"%s: cannot find correct BIOS image\n",
+							pgm);
+						nodldprint = 0;
+					}
+					dlio.image.fi.type = -1;
+					if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) {
+						if (errorprint) {
+							fprintf(stderr,
+							"%s: warning - download ioctl failed\n",
+							pgm);
+							errorprint = 0;
+						}
+						sleep(2);
+					}
+					break;
+				}
+				squirt(dlio.req_type, dlio.bdid, &image_list[x]);
+				break ;
+	
+			case DLREQ_FEP:
+				/*
+				** find the fep image for this type
+				*/
+				for ( x = 0; x < nimages; x++ ) {
+					if(image_list[x].type != IFEP)
+						continue;
+					if( (dlio.image.fi.type & FAMILY) == 
+						image_list[x].family ) {
+						if ( image_list[x].family == T_CX   ) { 
+							/* C/X PCI board */
+							if ((dlio.image.fi.type & BUSTYPE) 
+								== T_PCIBUS ) {
+								if ( image_list[x].subtype
+									== T_PCIBUS )
+									break;
+							}
+							else { 
+							/* Regular CX */
+								break;
+							}
+						}
+						else if ( image_list[x].family == T_EPC   )  {
+						/* If subtype of image is T_PCIBUS, it is */
+						/* a PCI EPC image, so the board must */
+						/* have bus type T_PCIBUS to match */
+							if ((dlio.image.fi.type & BUSTYPE) 
+								== T_PCIBUS ) {
+								if ( image_list[x].subtype 
+									== T_PCIBUS )
+									break;
+							}
+							else { 
+							/* NON PCI EPC doesn't use PCI image */
+								if ( image_list[x].subtype 
+									!= T_PCIBUS )
+									break;
+							}
+						}
+						else
+							break;
+					}
+					else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) {
+						/* PCXR board will break out of the loop here */
+						if ( image_list[x].subtype == T_PCXR   ) { 
+									break;
+						}
+					}
+				}
+	
+				if ( x >= nimages) {
+					/*
+					** no valid images exist
+					*/
+					if(nodldprint) {
+						fprintf(stderr,
+						"%s: cannot find correct FEP image\n",
+							pgm);
+						nodldprint = 0;
+					}
+					dlio.image.fi.type=-1;
+					if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) {
+						if(errorprint) {
+							fprintf(stderr,
+						"%s: warning - download ioctl failed\n",
+								pgm);
+							errorprint=0;
+						}
+						sleep(2);
+					}
+					break;
+				}
+				squirt(dlio.req_type, dlio.bdid, &image_list[x]);
+				break;
+
+			case DLREQ_DEVCREATE:
+				{
+					char string[1024];
+#if 0
+					sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid);
+#endif
+					sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid);
+					system(string);
+
+					if (debugflag)
+						printf("Created Devices.\n");
+					if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
+						if(errorprint) {
+							fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm);
+							errorprint = 0;
+						}
+						sleep(2);
+					}
+					if (debugflag)
+						printf("After ioctl set - Created Device.\n");
+				}
+
+				break;
+	
+			case DLREQ_CONFIG:
+				for ( x = 0; x < nimages; x++ ) {
+					if(image_list[x].type != ICONFIG)
+						continue;
+					else
+						break;
+				}
+
+				if ( x >= nimages) {
+					/*
+					** no valid images exist
+					*/
+					if(nodldprint) {
+						fprintf(stderr,
+						"%s: cannot find correct CONFIG image\n",
+							pgm);
+						nodldprint = 0;
+					}
+					dlio.image.fi.type=-1;
+					if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
+						if(errorprint) {
+							fprintf(stderr,
+						"%s: warning - download ioctl failed\n",
+								pgm);
+							errorprint=0;
+						}
+						sleep(2);
+					}
+					break;
+				}
+
+				squirt(dlio.req_type, dlio.bdid, &image_list[x]);
+				break;
+
+			case DLREQ_CONC:
+				/*
+				** find the image needed for this download
+				*/
+				if ( dp->dl_seq == 0 ) {
+					/*
+					** find image for hardware rev range
+					*/
+					for ( x = 0; x < nimages; x++ ) {
+						ii=&image_list[x];
+		
+						if(image_list[x].type != ICONC)
+							continue;
+		
+						consider_file_rescan(ii) ;
+		
+						ip = (struct downld_t *) image_list[x].image;
+						if (ip == NULL) continue;
+		
+						/*
+						 * When I removed Clusterport, I kept only the
+						 * code that I was SURE wasn't ClusterPort.
+						 * We may not need the next four lines of code.
+						 */
+
+						if ((dp->dl_type != 'P' ) &&
+						 (ip->dl_lrev <= dp->dl_lrev ) && 
+						 ( dp->dl_lrev <= ip->dl_hrev))
+							break;
+					}
+				    
+					if ( x >= nimages ) {
+						/*
+						** No valid images exist
+						*/
+						if(nodldprint) {
+							fprintf(stderr,
+						"%s: cannot find correct download image %d\n",
+								pgm, dp->dl_lrev);
+							nodldprint=0;
+						}
+						continue;
+					}
+				    
+				} else {
+					/*
+					** find image version required
+					*/
+					if ((ii = find_conc_image()) == NULL ) {
+						/*
+						** No valid images exist
+						*/
+						fprintf(stderr,
+						"%s: can't find rest of download image??\n",
+							pgm);
+						continue;
+					}
+				}
+			
+				/*
+				** download block of image
+				*/
+			
+				offset = 1024 * dp->dl_seq;
+				
+				/*
+				** test if block requested within image
+				*/
+				if ( offset < ii->len ) { 
+	
+					/*
+					** if it is, determine block size, set segment,
+					** set size, set pointers, and copy block
+					*/
+					if (( bsize = ii->len - offset ) > 1024 )
+						bsize = 1024;
+				    
+					/*
+					** copy image version info to download area
+					*/
+					dp->dl_srev = ip->dl_srev;
+					dp->dl_lrev = ip->dl_lrev;
+					dp->dl_hrev = ip->dl_hrev;
+				    
+					dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg;
+					dp->dl_size = bsize;
+				    
+					down = (char *)&dp->dl_data[0];
+					image = (char *)((char *)ip + offset);
+	
+					memcpy(down, image, bsize);
+				} 
+				else {
+					/*
+					** Image has been downloaded, set segment and
+					** size to indicate no more blocks
+					*/
+					dp->dl_seg = ip->dl_seg;
+					dp->dl_size = 0;
+	
+					/* Now, we can release the concentrator */
+					/* image from memory if we're running  */
+					/* from filesystem images */
+		
+					if (ii->pathname)
+						if (ii->image) {
+							free(ii->image);
+							ii->image = NULL ; 
+						} 
+				}
+			
+				if (debugflag)
+						printf(
+						"sending conc dl section %d to %s from %s\n",
+							dp->dl_seq, ii->name,
+						ii->pathname ? ii->pathname : "Internal Image");
+		
+				if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) {
+					if (errorprint) {
+						fprintf(stderr,
+						"%s: warning - download ioctl failed\n",
+							pgm);
+						errorprint=0;
+					}
+					sleep(2);
+				}
+				break;
+			} /* switch */
+		}
+		if (debugflag > 1) {
+			printf("pausing: "); fflush(stdout);
+			fflush(stdin);
+			while(getchar() != '\n');
+				printf("continuing\n");
+		}
+	}
+}
+
+/*
+** myperror()
+**
+**  Same as normal perror(), but places the program name at the begining
+**  of the message.
+*/
+void myperror(char *s)
+{
+	fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno));
+}
diff --git a/drivers/staging/dgnc/Kconfig b/drivers/staging/dgnc/Kconfig
new file mode 100644
index 0000000..032c2a7
--- /dev/null
+++ b/drivers/staging/dgnc/Kconfig
@@ -0,0 +1,6 @@
+config DGNC
+       tristate "Digi Neo and Classic PCI Products"
+       default n
+       depends on TTY && PCI
+       ---help---
+       Driver for the Digi International Neo and Classic PCI based product line.
diff --git a/drivers/staging/dgnc/Makefile b/drivers/staging/dgnc/Makefile
new file mode 100644
index 0000000..888c433
--- /dev/null
+++ b/drivers/staging/dgnc/Makefile
@@ -0,0 +1,7 @@
+EXTRA_CFLAGS += -DDG_NAME=\"dgnc-1.3-16\" -DDG_PART=\"40002369_F\"
+
+obj-$(CONFIG_DGNC) += dgnc.o
+
+dgnc-objs :=   dgnc_cls.o dgnc_driver.o\
+               dgnc_mgmt.o dgnc_neo.o\
+               dgnc_trace.o dgnc_tty.o dgnc_sysfs.o
diff --git a/drivers/staging/dgnc/TODO b/drivers/staging/dgnc/TODO
new file mode 100644
index 0000000..1ff2d18
--- /dev/null
+++ b/drivers/staging/dgnc/TODO
@@ -0,0 +1,17 @@
+* remove kzalloc casts
+* checkpatch fixes
+* sparse fixes
+* fix use of sizeof(). Example replace sizeof(struct board_t) 
+  with sizeof(*brd) and remove sizeof(char)
+* change name of board_t to dgnc_board
+* split two assignments into the two assignments on two lines;
+  don't use two equals signs
+* remove unecessary comments
+* remove unecessary error messages. Example kzalloc() has its 
+  own error message. Adding an extra one is useless.
+* use goto statements for error handling when appropriate
+* there is a lot of unecessary code in the driver. It was 
+  originally a standalone driver. Remove uneeded code.
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and 
+Cc: Lidza Louina <lidza.louina@gmail.com>
diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c
new file mode 100644
index 0000000..117e158
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_cls.c
@@ -0,0 +1,1409 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/delay.h>	/* For udelay */
+#include <asm/io.h>		/* For read[bwl]/write[bwl] */
+#include <linux/serial.h>	/* For struct async_serial */
+#include <linux/serial_reg.h>	/* For the various UART offsets */
+#include <linux/pci.h>
+
+#include "dgnc_driver.h"	/* Driver main header file */
+#include "dgnc_cls.h"
+#include "dgnc_tty.h"
+#include "dgnc_trace.h"
+
+static inline void cls_parse_isr(struct board_t *brd, uint port);
+static inline void cls_clear_break(struct channel_t *ch, int force);
+static inline void cls_set_cts_flow_control(struct channel_t *ch);
+static inline void cls_set_rts_flow_control(struct channel_t *ch);
+static inline void cls_set_ixon_flow_control(struct channel_t *ch);
+static inline void cls_set_ixoff_flow_control(struct channel_t *ch);
+static inline void cls_set_no_output_flow_control(struct channel_t *ch);
+static inline void cls_set_no_input_flow_control(struct channel_t *ch);
+static void cls_parse_modem(struct channel_t *ch, uchar signals);
+static void cls_tasklet(unsigned long data);
+static void cls_vpd(struct board_t *brd);
+static void cls_uart_init(struct channel_t *ch);
+static void cls_uart_off(struct channel_t *ch);
+static int cls_drain(struct tty_struct *tty, uint seconds);
+static void cls_param(struct tty_struct *tty);
+static void cls_assert_modem_signals(struct channel_t *ch);
+static void cls_flush_uart_write(struct channel_t *ch);
+static void cls_flush_uart_read(struct channel_t *ch);
+static void cls_disable_receiver(struct channel_t *ch);
+static void cls_enable_receiver(struct channel_t *ch);
+static void cls_send_break(struct channel_t *ch, int msecs);
+static void cls_send_start_character(struct channel_t *ch);
+static void cls_send_stop_character(struct channel_t *ch);
+static void cls_copy_data_from_uart_to_queue(struct channel_t *ch);
+static void cls_copy_data_from_queue_to_uart(struct channel_t *ch);
+static uint cls_get_uart_bytes_left(struct channel_t *ch);
+static void cls_send_immediate_char(struct channel_t *ch, unsigned char);
+static irqreturn_t cls_intr(int irq, void *voidbrd);
+
+struct board_ops dgnc_cls_ops = {
+	.tasklet =			cls_tasklet,
+	.intr =				cls_intr,
+	.uart_init =			cls_uart_init,
+	.uart_off =			cls_uart_off,
+	.drain =			cls_drain,
+	.param =			cls_param,
+	.vpd =				cls_vpd,
+	.assert_modem_signals =		cls_assert_modem_signals,
+	.flush_uart_write =		cls_flush_uart_write,
+	.flush_uart_read =		cls_flush_uart_read,
+	.disable_receiver =		cls_disable_receiver,
+	.enable_receiver =		cls_enable_receiver,
+	.send_break =			cls_send_break,
+	.send_start_character =		cls_send_start_character,
+	.send_stop_character =		cls_send_stop_character,
+	.copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
+	.get_uart_bytes_left =		cls_get_uart_bytes_left,
+	.send_immediate_char =		cls_send_immediate_char
+};
+
+
+static inline void cls_set_cts_flow_control(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar ier = readb(&ch->ch_cls_uart->ier);
+	uchar isr_fcr = 0;
+
+	DPR_PARAM(("Setting CTSFLOW\n"));
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn on CTS flow control, turn off IXON flow control */
+	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
+	isr_fcr &= ~(UART_EXAR654_EFR_IXON);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+	/* Enable interrupts for CTS flow, turn off interrupts for received XOFF chars */
+	ier |= (UART_EXAR654_IER_CTSDSR);
+	ier &= ~(UART_EXAR654_IER_XOFF);
+	writeb(ier, &ch->ch_cls_uart->ier);
+
+	/* Set the usual FIFO values */
+	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
+		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+		&ch->ch_cls_uart->isr_fcr);
+
+	ch->ch_t_tlevel = 16;
+
+}
+
+
+static inline void cls_set_ixon_flow_control(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar ier = readb(&ch->ch_cls_uart->ier);
+	uchar isr_fcr = 0;
+
+	DPR_PARAM(("Setting IXON FLOW\n"));
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn on IXON flow control, turn off CTS flow control */
+	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
+	isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Now set our current start/stop chars while in enhanced mode */
+	writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
+	writeb(0, &ch->ch_cls_uart->lsr);
+	writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
+	writeb(0, &ch->ch_cls_uart->spr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+	/* Disable interrupts for CTS flow, turn on interrupts for received XOFF chars */
+	ier &= ~(UART_EXAR654_IER_CTSDSR);
+	ier |= (UART_EXAR654_IER_XOFF);
+	writeb(ier, &ch->ch_cls_uart->ier);
+
+	/* Set the usual FIFO values */
+	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+		&ch->ch_cls_uart->isr_fcr);
+
+}
+
+
+static inline void cls_set_no_output_flow_control(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar ier = readb(&ch->ch_cls_uart->ier);
+	uchar isr_fcr = 0;
+
+	DPR_PARAM(("Unsetting Output FLOW\n"));
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn off IXON flow control, turn off CTS flow control */
+	isr_fcr |= (UART_EXAR654_EFR_ECB);
+	isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+	/* Disable interrupts for CTS flow, turn off interrupts for received XOFF chars */
+	ier &= ~(UART_EXAR654_IER_CTSDSR);
+	ier &= ~(UART_EXAR654_IER_XOFF);
+	writeb(ier, &ch->ch_cls_uart->ier);
+
+	/* Set the usual FIFO values */
+	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+		&ch->ch_cls_uart->isr_fcr);
+
+	ch->ch_r_watermark = 0;
+        ch->ch_t_tlevel = 16;
+        ch->ch_r_tlevel = 16;
+
+}
+
+
+static inline void cls_set_rts_flow_control(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar ier = readb(&ch->ch_cls_uart->ier);
+	uchar isr_fcr = 0;
+
+	DPR_PARAM(("Setting RTSFLOW\n"));
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn on RTS flow control, turn off IXOFF flow control */
+	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
+	isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+	/* Enable interrupts for RTS flow */
+	ier |= (UART_EXAR654_IER_RTSDTR);
+	writeb(ier, &ch->ch_cls_uart->ier);
+
+	/* Set the usual FIFO values */
+	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
+		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+		&ch->ch_cls_uart->isr_fcr);
+
+
+	ch->ch_r_watermark = 4;
+	ch->ch_r_tlevel = 8;
+
+}
+
+
+static inline void cls_set_ixoff_flow_control(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar ier = readb(&ch->ch_cls_uart->ier);
+	uchar isr_fcr = 0;
+
+	DPR_PARAM(("Setting IXOFF FLOW\n"));
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn on IXOFF flow control, turn off RTS flow control */
+	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
+	isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Now set our current start/stop chars while in enhanced mode */
+	writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
+	writeb(0, &ch->ch_cls_uart->lsr);
+	writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
+	writeb(0, &ch->ch_cls_uart->spr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+	/* Disable interrupts for RTS flow */
+	ier &= ~(UART_EXAR654_IER_RTSDTR);
+	writeb(ier, &ch->ch_cls_uart->ier);
+
+	/* Set the usual FIFO values */
+	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+		&ch->ch_cls_uart->isr_fcr);
+
+}
+
+
+static inline void cls_set_no_input_flow_control(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar ier = readb(&ch->ch_cls_uart->ier);
+	uchar isr_fcr = 0;
+
+	DPR_PARAM(("Unsetting Input FLOW\n"));
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn off IXOFF flow control, turn off RTS flow control */
+	isr_fcr |= (UART_EXAR654_EFR_ECB);
+	isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+	/* Disable interrupts for RTS flow */
+	ier &= ~(UART_EXAR654_IER_RTSDTR);
+	writeb(ier, &ch->ch_cls_uart->ier);
+
+	/* Set the usual FIFO values */
+	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
+		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
+		&ch->ch_cls_uart->isr_fcr);
+
+        ch->ch_t_tlevel = 16;
+        ch->ch_r_tlevel = 16;
+
+}
+
+
+/*
+ * cls_clear_break.
+ * Determines whether its time to shut off break condition.
+ *
+ * No locks are assumed to be held when calling this function.
+ * channel lock is held and released in this function.
+ */
+static inline void cls_clear_break(struct channel_t *ch, int force)
+{
+	ulong lock_flags;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* Bail if we aren't currently sending a break. */
+	if (!ch->ch_stop_sending_break) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/* Turn break off, and unset some variables */
+	if (ch->ch_flags & CH_BREAK_SENDING) {
+		if ((jiffies >= ch->ch_stop_sending_break) || force) {
+			uchar temp = readb(&ch->ch_cls_uart->lcr);
+        	        writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
+			ch->ch_flags &= ~(CH_BREAK_SENDING);
+			ch->ch_stop_sending_break = 0;
+			DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+		}
+	}
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/* Parse the ISR register for the specific port */
+static inline void cls_parse_isr(struct board_t *brd, uint port)
+{
+	struct channel_t *ch;
+	uchar isr = 0;
+	ulong lock_flags;
+
+	/*
+	 * No need to verify board pointer, it was already
+	 * verified in the interrupt routine.
+	 */
+
+	if (port > brd->nasync)
+		return;
+
+	ch = brd->channels[port];
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	/* Here we try to figure out what caused the interrupt to happen */
+	while (1) {
+
+		isr = readb(&ch->ch_cls_uart->isr_fcr);
+
+		/* Bail if no pending interrupt on port */
+		if (isr & UART_IIR_NO_INT)  {
+			break;
+		}
+
+		DPR_INTR(("%s:%d port: %x isr: %x\n", __FILE__, __LINE__, port, isr));
+
+		/* Receive Interrupt pending */
+		if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
+			/* Read data from uart -> queue */
+			brd->intr_rx++;
+			ch->ch_intr_rx++;
+			cls_copy_data_from_uart_to_queue(ch);
+			dgnc_check_queue_flow_control(ch);
+		}
+
+		/* Transmit Hold register empty pending */
+		if (isr & UART_IIR_THRI) {
+			/* Transfer data (if any) from Write Queue -> UART. */
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+			brd->intr_tx++;
+			ch->ch_intr_tx++;
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			cls_copy_data_from_queue_to_uart(ch);
+		}
+
+		/* Received Xoff signal/Special character */
+		if (isr & UART_IIR_XOFF) {
+			/* Empty */
+		}
+
+		/* CTS/RTS change of state */
+		if (isr & UART_IIR_CTSRTS) {
+			brd->intr_modem++;
+			ch->ch_intr_modem++;
+			/*
+			 * Don't need to do anything, the cls_parse_modem
+			 * below will grab the updated modem signals.
+			 */
+		}
+
+		/* Parse any modem signal changes */
+		DPR_INTR(("MOD_STAT: sending to parse_modem_sigs\n"));
+		cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
+	}
+}
+
+
+/*
+ * cls_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void cls_param(struct tty_struct *tty)
+{
+	uchar lcr = 0;
+	uchar uart_lcr = 0;
+	uchar ier = 0;
+	uchar uart_ier = 0;
+        uint baud = 9600;
+	int quot = 0;
+        struct board_t *bd;
+	struct channel_t *ch;
+        struct un_t   *un;
+
+	if (!tty || tty->magic != TTY_MAGIC) {
+		return;
+	}
+
+	un = (struct un_t *) tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC) {
+		return;
+	}
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return;
+	}
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+		return;
+	}
+
+	DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
+		ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
+
+	/*
+	 * If baud rate is zero, flush queues, and set mval to drop DTR.
+	 */
+	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+		ch->ch_r_head = ch->ch_r_tail = 0;
+		ch->ch_e_head = ch->ch_e_tail = 0;
+		ch->ch_w_head = ch->ch_w_tail = 0;
+
+		cls_flush_uart_write(ch);
+                cls_flush_uart_read(ch);
+
+		/* The baudrate is B0 so all modem lines are to be dropped. */
+		ch->ch_flags |= (CH_BAUD0);
+		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+		cls_assert_modem_signals(ch);
+		ch->ch_old_baud = 0;
+		return;
+	} else if (ch->ch_custom_speed) {
+
+		baud = ch->ch_custom_speed;
+		/* Handle transition from B0 */
+		if (ch->ch_flags & CH_BAUD0) {
+			ch->ch_flags &= ~(CH_BAUD0);
+
+			/*
+			 * Bring back up RTS and DTR...
+			 * Also handle RTS or DTR toggle if set.
+			 */
+			if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_RTS);
+			if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_DTR);
+		}
+
+	} else {
+		int iindex = 0;
+		int jindex = 0;
+
+		ulong bauds[4][16] = {
+			{ /* slowbaud */
+				0,      50,     75,     110,
+				134,    150,    200,    300,
+				600,    1200,   1800,   2400,
+				4800,   9600,   19200,  38400 },
+			{ /* slowbaud & CBAUDEX */
+				0,      57600,  115200, 230400,
+				460800, 150,    200,    921600,
+				600,    1200,   1800,   2400,
+				4800,   9600,   19200,  38400 },
+			{ /* fastbaud */
+				0,      57600,   76800, 115200,
+				131657, 153600, 230400, 460800,
+				921600, 1200,   1800,   2400,
+				4800,   9600,   19200,  38400 },
+			{ /* fastbaud & CBAUDEX */
+				0,      57600,  115200, 230400,
+				460800, 150,    200,    921600,
+				600,    1200,   1800,   2400,
+				4800,   9600,   19200,  38400 }
+		};
+
+		/* Only use the TXPrint baud rate if the terminal unit is NOT open */
+		if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGNC_PRINT))
+			baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+		else
+			baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+		if (ch->ch_c_cflag & CBAUDEX)
+			iindex = 1;
+
+		if (ch->ch_digi.digi_flags & DIGI_FAST)
+			iindex += 2;
+
+		jindex = baud;
+
+		if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
+			baud = bauds[iindex][jindex];
+		} else {
+			DPR_IOCTL(("baud indices were out of range (%d)(%d)",
+				iindex, jindex));
+			baud = 0;
+		}
+
+		if (baud == 0)
+			baud = 9600;
+
+		/* Handle transition from B0 */
+		if (ch->ch_flags & CH_BAUD0) {
+			ch->ch_flags &= ~(CH_BAUD0);
+
+			/*
+			 * Bring back up RTS and DTR...
+			 * Also handle RTS or DTR toggle if set.
+			 */
+			if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_RTS);
+			if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_DTR);
+		}
+	}
+
+	if (ch->ch_c_cflag & PARENB) {
+		lcr |= UART_LCR_PARITY;
+	}
+
+	if (!(ch->ch_c_cflag & PARODD)) {
+		lcr |= UART_LCR_EPAR;
+	}
+
+	/*
+	 * Not all platforms support mark/space parity,
+	 * so this will hide behind an ifdef.
+	 */
+#ifdef CMSPAR
+	if (ch->ch_c_cflag & CMSPAR)
+		lcr |= UART_LCR_SPAR;
+#endif
+
+	if (ch->ch_c_cflag & CSTOPB)
+		lcr |= UART_LCR_STOP;
+
+	switch (ch->ch_c_cflag & CSIZE) {
+	case CS5:
+		lcr |= UART_LCR_WLEN5;
+		break;
+	case CS6:
+		lcr |= UART_LCR_WLEN6;
+		break;
+	case CS7:
+		lcr |= UART_LCR_WLEN7;
+		break;
+	case CS8:
+	default:
+		lcr |= UART_LCR_WLEN8;
+		break;
+	}
+
+	ier = uart_ier = readb(&ch->ch_cls_uart->ier);
+	uart_lcr = readb(&ch->ch_cls_uart->lcr);
+
+	if (baud == 0)
+		baud = 9600;
+
+	quot = ch->ch_bd->bd_dividend / baud;
+
+	if (quot != 0 && ch->ch_old_baud != baud) {
+		ch->ch_old_baud = baud;
+		writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
+		writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
+		writeb((quot >> 8), &ch->ch_cls_uart->ier);
+		writeb(lcr, &ch->ch_cls_uart->lcr);
+        }
+
+	if (uart_lcr != lcr)
+		writeb(lcr, &ch->ch_cls_uart->lcr);
+
+	if (ch->ch_c_cflag & CREAD) {
+		ier |= (UART_IER_RDI | UART_IER_RLSI);
+	}
+	else {
+		ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+	}
+
+	/*
+	 * Have the UART interrupt on modem signal changes ONLY when
+	 * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
+	 */
+	if ((ch->ch_digi.digi_flags & CTSPACE) || (ch->ch_digi.digi_flags & RTSPACE) ||
+		(ch->ch_c_cflag & CRTSCTS) || !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
+		!(ch->ch_c_cflag & CLOCAL))
+	{
+		ier |= UART_IER_MSI;
+	}
+	else {
+		ier &= ~UART_IER_MSI;
+	}
+
+	ier |= UART_IER_THRI;
+
+	if (ier != uart_ier)
+		writeb(ier, &ch->ch_cls_uart->ier);
+
+	if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
+		cls_set_cts_flow_control(ch);
+	}
+	else if (ch->ch_c_iflag & IXON) {
+		/* If start/stop is set to disable, then we should disable flow control */
+		if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+			cls_set_no_output_flow_control(ch);
+		else
+			cls_set_ixon_flow_control(ch);
+	}
+	else {
+		cls_set_no_output_flow_control(ch);
+	}
+
+	if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
+		cls_set_rts_flow_control(ch);
+	}
+	else if (ch->ch_c_iflag & IXOFF) {
+		/* If start/stop is set to disable, then we should disable flow control */
+		if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+			cls_set_no_input_flow_control(ch);
+		else
+			cls_set_ixoff_flow_control(ch);
+	}
+	else {
+		cls_set_no_input_flow_control(ch);
+	}
+
+	cls_assert_modem_signals(ch);
+
+	/* Get current status of the modem signals now */
+	cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
+}
+
+
+/*
+ * Our board poller function.
+ */
+static void cls_tasklet(unsigned long data)
+{
+        struct board_t *bd = (struct board_t *) data;
+	struct channel_t *ch;
+	ulong  lock_flags;
+	int i;
+	int state = 0;
+	int ports = 0;
+
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+		APR(("poll_tasklet() - NULL or bad bd.\n"));
+		return;
+	}
+
+	/* Cache a couple board values */
+	DGNC_LOCK(bd->bd_lock, lock_flags);
+	state = bd->state;
+	ports = bd->nasync;
+	DGNC_UNLOCK(bd->bd_lock, lock_flags);
+
+	/*
+	 * Do NOT allow the interrupt routine to read the intr registers
+	 * Until we release this lock.
+	 */
+	DGNC_LOCK(bd->bd_intr_lock, lock_flags);
+
+	/*
+	 * If board is ready, parse deeper to see if there is anything to do.
+	 */
+	if ((state == BOARD_READY) && (ports > 0)) {
+
+		/* Loop on each port */
+		for (i = 0; i < ports; i++) {
+			ch = bd->channels[i];
+			if (!ch)
+				continue;
+
+			/*
+			 * NOTE: Remember you CANNOT hold any channel
+			 * locks when calling input.
+			 * During input processing, its possible we
+			 * will call ld, which might do callbacks back
+			 * into us.
+			 */
+			dgnc_input(ch);
+
+			/*
+			 * Channel lock is grabbed and then released
+			 * inside this routine.
+			 */
+			cls_copy_data_from_queue_to_uart(ch);
+			dgnc_wakeup_writes(ch);
+
+			/*
+			 * Check carrier function.
+			 */
+			dgnc_carrier(ch);
+
+			/*
+			 * The timing check of turning off the break is done
+			 * inside clear_break()
+			 */
+			if (ch->ch_stop_sending_break)
+				cls_clear_break(ch, 0);
+		}
+	}
+
+	DGNC_UNLOCK(bd->bd_intr_lock, lock_flags);
+
+}
+
+
+/*
+ * cls_intr()
+ *
+ * Classic specific interrupt handler.
+ */
+static irqreturn_t cls_intr(int irq, void *voidbrd)
+{
+	struct board_t *brd = (struct board_t *) voidbrd;
+	uint i = 0;
+	uchar poll_reg;
+	unsigned long lock_flags;
+
+	if (!brd) {
+		APR(("Received interrupt (%d) with null board associated\n", irq));
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Check to make sure its for us.
+	 */
+	if (brd->magic != DGNC_BOARD_MAGIC) {
+		APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
+		return IRQ_NONE;
+	}
+
+	DGNC_LOCK(brd->bd_intr_lock, lock_flags);
+
+	brd->intr_count++;
+
+	/*
+	 * Check the board's global interrupt offset to see if we
+	 * we actually do have an interrupt pending for us.
+	 */
+	poll_reg = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
+
+	/* If 0, no interrupts pending */
+	if (!poll_reg) {
+		DPR_INTR(("Kernel interrupted to me, but no pending interrupts...\n"));
+		DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+		return IRQ_NONE;
+	}
+
+	DPR_INTR(("%s:%d poll_reg: %x\n", __FILE__, __LINE__, poll_reg));
+
+	/* Parse each port to find out what caused the interrupt */
+	for (i = 0; i < brd->nasync; i++) {
+		cls_parse_isr(brd, i);
+	}
+
+	/*
+	 * Schedule tasklet to more in-depth servicing at a better time.
+	 */
+	tasklet_schedule(&brd->helper_tasklet);
+
+	DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+
+	DPR_INTR(("dgnc_intr finish.\n"));
+	return IRQ_HANDLED;
+}
+
+
+static void cls_disable_receiver(struct channel_t *ch)
+{
+	uchar tmp = readb(&ch->ch_cls_uart->ier);
+	tmp &= ~(UART_IER_RDI);
+	writeb(tmp, &ch->ch_cls_uart->ier);
+}
+
+
+static void cls_enable_receiver(struct channel_t *ch)
+{
+	uchar tmp = readb(&ch->ch_cls_uart->ier);
+	tmp |= (UART_IER_RDI);
+	writeb(tmp, &ch->ch_cls_uart->ier);
+}
+
+
+static void cls_copy_data_from_uart_to_queue(struct channel_t *ch)
+{
+        int qleft = 0;
+        uchar linestatus = 0;
+	uchar error_mask = 0;
+	ushort head;
+	ushort tail;
+	ulong lock_flags;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* cache head and tail of queue */
+	head = ch->ch_r_head;
+	tail = ch->ch_r_tail;
+
+	/* Store how much space we have left in the queue */
+	if ((qleft = tail - head - 1) < 0)
+		qleft += RQUEUEMASK + 1;
+
+	/*
+	 * Create a mask to determine whether we should
+	 * insert the character (if any) into our queue.
+	 */
+	if (ch->ch_c_iflag & IGNBRK)
+		error_mask |= UART_LSR_BI;
+
+	while (1) {
+		linestatus = readb(&ch->ch_cls_uart->lsr);
+
+		if (!(linestatus & (UART_LSR_DR)))
+			break;
+
+		/*
+		 * Discard character if we are ignoring the error mask.
+		*/
+		if (linestatus & error_mask)  {
+			uchar discard;
+			linestatus = 0;
+			discard = readb(&ch->ch_cls_uart->txrx);
+			continue;
+		}
+
+		/*
+		 * If our queue is full, we have no choice but to drop some data.
+		 * The assumption is that HWFLOW or SWFLOW should have stopped
+		 * things way way before we got to this point.
+		 *
+		 * I decided that I wanted to ditch the oldest data first,
+		 * I hope thats okay with everyone? Yes? Good.
+		 */
+		while (qleft < 1) {
+			DPR_READ(("Queue full, dropping DATA:%x LSR:%x\n",
+				ch->ch_rqueue[tail], ch->ch_equeue[tail]));
+
+			ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+			ch->ch_err_overrun++;
+			qleft++;
+		}
+
+		ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE);
+		ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
+		dgnc_sniff_nowait_nolock(ch, "UART READ", ch->ch_rqueue + head, 1);
+
+		qleft--;
+
+		DPR_READ(("DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]));
+
+		if (ch->ch_equeue[head] & UART_LSR_PE)
+			ch->ch_err_parity++;
+		if (ch->ch_equeue[head] & UART_LSR_BI)
+			ch->ch_err_break++;
+		if (ch->ch_equeue[head] & UART_LSR_FE)
+			ch->ch_err_frame++;
+
+		/* Add to, and flip head if needed */
+		head = (head + 1) & RQUEUEMASK;
+		ch->ch_rxcount++;
+	}
+
+	/*
+	 * Write new final heads to channel structure.
+	 */
+	ch->ch_r_head = head & RQUEUEMASK;
+	ch->ch_e_head = head & EQUEUEMASK;
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/*
+ * This function basically goes to sleep for secs, or until
+ * it gets signalled that the port has fully drained.
+ */
+static int cls_drain(struct tty_struct *tty, uint seconds)
+{
+	ulong lock_flags;
+	struct channel_t *ch;
+        struct un_t *un;
+	int rc = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC) {
+		return (-ENXIO);
+	}
+
+	un = (struct un_t *) tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC) {
+		return (-ENXIO);
+	}
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return (-ENXIO);
+	}
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+	un->un_flags |= UN_EMPTY;
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 * NOTE: Do something with time passed in.
+	 */
+	rc = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
+
+	/* If ret is non-zero, user ctrl-c'ed us */
+	if (rc)
+		DPR_IOCTL(("%d Drain - User ctrl c'ed\n", __LINE__));
+
+        return (rc);
+}
+
+
+/* Channel lock MUST be held before calling this function! */
+static void cls_flush_uart_write(struct channel_t *ch)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return;
+	}
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_cls_uart->isr_fcr);
+	udelay(10);
+
+	ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/* Channel lock MUST be held before calling this function! */
+static void cls_flush_uart_read(struct channel_t *ch)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return;
+	}
+
+	/*
+	 * For complete POSIX compatibility, we should be purging the
+	 * read FIFO in the UART here.
+	 *
+	 * However, doing the statement below also incorrectly flushes
+	 * write data as well as just basically trashing the FIFO.
+	 *
+	 * I believe this is a BUG in this UART.
+	 * So for now, we will leave the code #ifdef'ed out...
+	 */
+#if 0
+	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_cls_uart->isr_fcr);
+#endif
+	udelay(10);
+}
+
+
+static void cls_copy_data_from_queue_to_uart(struct channel_t *ch)
+{
+	ushort head;
+	ushort tail;
+	int n;
+	int qlen;
+	uint len_written = 0;
+	ulong lock_flags;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* No data to write to the UART */
+	if (ch->ch_w_tail == ch->ch_w_head) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/* If port is "stopped", don't send any data to the UART */
+	if ((ch->ch_flags & CH_FORCED_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	n = 32;
+
+        /* cache head and tail of queue */
+        head = ch->ch_w_head & WQUEUEMASK;
+        tail = ch->ch_w_tail & WQUEUEMASK;
+        qlen = (head - tail) & WQUEUEMASK;
+
+	/* Find minimum of the FIFO space, versus queue length */
+	n = min(n, qlen);
+
+	while (n > 0) {
+
+		/*
+		 * If RTS Toggle mode is on, turn on RTS now if not already set,
+		 * and make sure we get an event when the data transfer has completed.
+		 */
+		if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+			if (!(ch->ch_mostat & UART_MCR_RTS)) {
+				ch->ch_mostat |= (UART_MCR_RTS);
+				cls_assert_modem_signals(ch);
+			}
+			ch->ch_tun.un_flags |= (UN_EMPTY);
+		}
+
+		/*
+		 * If DTR Toggle mode is on, turn on DTR now if not already set,
+		 * and make sure we get an event when the data transfer has completed.
+		 */
+		if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+			if (!(ch->ch_mostat & UART_MCR_DTR)) {
+				ch->ch_mostat |= (UART_MCR_DTR);
+				cls_assert_modem_signals(ch);
+			}
+			ch->ch_tun.un_flags |= (UN_EMPTY);
+		}
+		writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_cls_uart->txrx);
+		dgnc_sniff_nowait_nolock(ch, "UART WRITE", ch->ch_wqueue + ch->ch_w_tail, 1);
+		DPR_WRITE(("Tx data: %x\n", ch->ch_wqueue[ch->ch_w_tail]));
+		ch->ch_w_tail++;
+		ch->ch_w_tail &= WQUEUEMASK;
+		ch->ch_txcount++;
+		len_written++;
+		n--;
+	}
+
+	if (len_written > 0)
+		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	return;
+}
+
+
+static void cls_parse_modem(struct channel_t *ch, uchar signals)
+{
+	volatile uchar msignals = signals;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DPR_MSIGS(("cls_parse_modem: port: %d signals: %d\n", ch->ch_portnum, msignals));
+
+	/*
+	 * Do altpin switching. Altpin switches DCD and DSR.
+	 * This prolly breaks DSRPACE, so we should be more clever here.
+	 */
+	if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+		uchar mswap = signals;
+		if (mswap & UART_MSR_DDCD) {
+			msignals &= ~UART_MSR_DDCD;
+			msignals |= UART_MSR_DDSR;
+		}
+		if (mswap & UART_MSR_DDSR) {
+			msignals &= ~UART_MSR_DDSR;
+			msignals |= UART_MSR_DDCD;
+		}
+		if (mswap & UART_MSR_DCD) {
+			msignals &= ~UART_MSR_DCD;
+			msignals |= UART_MSR_DSR;
+		}
+		if (mswap & UART_MSR_DSR) {
+			msignals &= ~UART_MSR_DSR;
+			msignals |= UART_MSR_DCD;
+		}
+	}
+
+	/* Scrub off lower bits. They signify delta's, which I don't care about */
+	signals &= 0xf0;
+
+	if (msignals & UART_MSR_DCD)
+		ch->ch_mistat |= UART_MSR_DCD;
+	else
+		ch->ch_mistat &= ~UART_MSR_DCD;
+
+	if (msignals & UART_MSR_DSR)
+		ch->ch_mistat |= UART_MSR_DSR;
+	else
+		ch->ch_mistat &= ~UART_MSR_DSR;
+
+	if (msignals & UART_MSR_RI)
+		ch->ch_mistat |= UART_MSR_RI;
+	else
+		ch->ch_mistat &= ~UART_MSR_RI;
+
+	if (msignals & UART_MSR_CTS)
+		ch->ch_mistat |= UART_MSR_CTS;
+	else
+		ch->ch_mistat &= ~UART_MSR_CTS;
+
+
+	DPR_MSIGS(("Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+		ch->ch_portnum,
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)));
+}
+
+
+/* Make the UART raise any of the output signals we want up */
+static void cls_assert_modem_signals(struct channel_t *ch)
+{
+	uchar out;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	out = ch->ch_mostat;
+
+	if (ch->ch_flags & CH_LOOPBACK)
+		out |= UART_MCR_LOOP;
+
+        writeb(out, &ch->ch_cls_uart->mcr);
+
+	/* Give time for the UART to actually drop the signals */
+	udelay(10);
+}
+
+
+static void cls_send_start_character(struct channel_t *ch)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	if (ch->ch_startc != _POSIX_VDISABLE) {
+		ch->ch_xon_sends++;
+		writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
+        }
+}
+
+
+static void cls_send_stop_character(struct channel_t *ch)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	if (ch->ch_stopc != _POSIX_VDISABLE) {
+		ch->ch_xoff_sends++;
+		writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
+        }
+}
+
+
+/* Inits UART */
+static void cls_uart_init(struct channel_t *ch)
+{
+	uchar lcrb = readb(&ch->ch_cls_uart->lcr);
+	uchar isr_fcr = 0;
+
+	writeb(0, &ch->ch_cls_uart->ier);
+
+	/*
+	 * The Enhanced Register Set may only be accessed when
+	 * the Line Control Register is set to 0xBFh.
+	 */
+	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
+
+	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
+
+	/* Turn on Enhanced/Extended controls */
+	isr_fcr |= (UART_EXAR654_EFR_ECB);
+
+	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
+
+	/* Write old LCR value back out, which turns enhanced access off */
+	writeb(lcrb, &ch->ch_cls_uart->lcr);
+
+        /* Clear out UART and FIFO */
+	readb(&ch->ch_cls_uart->txrx);
+
+	writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_cls_uart->isr_fcr);
+	udelay(10);
+
+	ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+
+	readb(&ch->ch_cls_uart->lsr);
+	readb(&ch->ch_cls_uart->msr);
+}
+
+
+/*
+ * Turns off UART.
+ */
+static void cls_uart_off(struct channel_t *ch)
+{
+	writeb(0, &ch->ch_cls_uart->ier);
+}
+
+
+/*
+ * cls_get_uarts_bytes_left.
+ * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static uint cls_get_uart_bytes_left(struct channel_t *ch)
+{
+	uchar left = 0;
+	uchar lsr = 0;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return 0;
+
+	lsr = readb(&ch->ch_cls_uart->lsr);
+
+	/* Determine whether the Transmitter is empty or not */
+	if (!(lsr & UART_LSR_TEMT)) {
+		if (ch->ch_flags & CH_TX_FIFO_EMPTY) {
+			tasklet_schedule(&ch->ch_bd->helper_tasklet);
+		}
+		left = 1;
+	}
+	else {
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		left = 0;
+	}
+
+	return left;
+}
+
+
+/*
+ * cls_send_break.
+ * Starts sending a break thru the UART.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void cls_send_break(struct channel_t *ch, int msecs)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	/*
+	 * If we receive a time of 0, this means turn off the break.
+	 */
+	if (msecs == 0) {
+		/* Turn break off, and unset some variables */
+		if (ch->ch_flags & CH_BREAK_SENDING) {
+			uchar temp = readb(&ch->ch_cls_uart->lcr);
+			writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
+			ch->ch_flags &= ~(CH_BREAK_SENDING);
+			ch->ch_stop_sending_break = 0;
+			DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+		}
+		return;
+        }
+
+	/*
+	 * Set the time we should stop sending the break.
+	 * If we are already sending a break, toss away the existing
+	 * time to stop, and use this new value instead.
+	 */
+	ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
+
+	/* Tell the UART to start sending the break */
+	if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+		uchar temp = readb(&ch->ch_cls_uart->lcr);
+		writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
+		ch->ch_flags |= (CH_BREAK_SENDING);
+		DPR_IOCTL(("Port %d. Starting UART_LCR_SBC! start: %lx should end: %lx\n",
+			ch->ch_portnum, jiffies, ch->ch_stop_sending_break));
+	}
+}
+
+
+/*
+ * cls_send_immediate_char.
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void cls_send_immediate_char(struct channel_t *ch, unsigned char c)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	writeb(c, &ch->ch_cls_uart->txrx);
+}
+
+static void cls_vpd(struct board_t *brd)
+{
+        ulong           vpdbase;        /* Start of io base of the card */
+        u8 __iomem           *re_map_vpdbase;/* Remapped memory of the card */
+	int i = 0;
+
+
+	vpdbase = pci_resource_start(brd->pdev, 3);
+
+	/* No VPD */
+	if (!vpdbase)
+		return;
+
+	re_map_vpdbase = ioremap(vpdbase, 0x400);
+
+	if (!re_map_vpdbase)
+		return;
+
+        /* Store the VPD into our buffer */
+        for (i = 0; i < 0x40; i++) {
+		brd->vpd[i] = readb(re_map_vpdbase + i);
+		printk("%x ", brd->vpd[i]);
+        }
+	printk("\n");
+
+	if (re_map_vpdbase)
+		iounmap(re_map_vpdbase);
+}
+
diff --git a/drivers/staging/dgnc/dgnc_cls.h b/drivers/staging/dgnc/dgnc_cls.h
new file mode 100644
index 0000000..ffe8535
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_cls.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ */
+
+#ifndef __DGNC_CLS_H
+#define __DGNC_CLS_H
+
+#include "dgnc_types.h"
+
+
+/************************************************************************
+ * Per channel/port Classic UART structure				*
+ ************************************************************************
+ *		Base Structure Entries Usage Meanings to Host		*
+ *									*
+ *	W = read write		R = read only				*
+ *			U = Unused.					*
+ ************************************************************************/
+
+struct cls_uart_struct {
+	u8 txrx;		/* WR  RHR/THR - Holding Reg */
+	u8 ier;		/* WR  IER - Interrupt Enable Reg */
+	u8 isr_fcr;		/* WR  ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+	u8 lcr;		/* WR  LCR - Line Control Reg */
+	u8 mcr;		/* WR  MCR - Modem Control Reg */
+	u8 lsr;		/* WR  LSR - Line Status Reg */
+	u8 msr;		/* WR  MSR - Modem Status Reg */
+	u8 spr;		/* WR  SPR - Scratch Pad Reg */
+};
+
+/* Where to read the interrupt register (8bits) */
+#define	UART_CLASSIC_POLL_ADDR_OFFSET	0x40
+
+#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF
+
+#define UART_16654_FCR_TXTRIGGER_8	0x0
+#define UART_16654_FCR_TXTRIGGER_16	0x10
+#define UART_16654_FCR_TXTRIGGER_32	0x20
+#define UART_16654_FCR_TXTRIGGER_56	0x30
+
+#define UART_16654_FCR_RXTRIGGER_8	0x0
+#define UART_16654_FCR_RXTRIGGER_16	0x40
+#define UART_16654_FCR_RXTRIGGER_56	0x80
+#define UART_16654_FCR_RXTRIGGER_60     0xC0
+
+#define UART_IIR_XOFF			0x10	/* Received Xoff signal/Special character */
+#define UART_IIR_CTSRTS			0x20	/* Received CTS/RTS change of state */
+#define UART_IIR_RDI_TIMEOUT		0x0C    /* Receiver data TIMEOUT */
+
+/*
+ * These are the EXTENDED definitions for the Exar 654's Interrupt
+ * Enable Register.
+ */
+#define UART_EXAR654_EFR_ECB      0x10    /* Enhanced control bit */
+#define UART_EXAR654_EFR_IXON     0x2     /* Receiver compares Xon1/Xoff1 */
+#define UART_EXAR654_EFR_IXOFF    0x8     /* Transmit Xon1/Xoff1 */
+#define UART_EXAR654_EFR_RTSDTR   0x40    /* Auto RTS/DTR Flow Control Enable */
+#define UART_EXAR654_EFR_CTSDSR   0x80    /* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_EXAR654_XOFF_DETECT  0x1     /* Indicates whether chip saw an incoming XOFF char  */
+#define UART_EXAR654_XON_DETECT   0x2     /* Indicates whether chip saw an incoming XON char */
+
+#define UART_EXAR654_IER_XOFF     0x20    /* Xoff Interrupt Enable */
+#define UART_EXAR654_IER_RTSDTR   0x40    /* Output Interrupt Enable */
+#define UART_EXAR654_IER_CTSDSR   0x80    /* Input Interrupt Enable */
+
+/*
+ * Our Global Variables
+ */
+extern struct board_ops dgnc_cls_ops;
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
new file mode 100644
index 0000000..f8c1e22
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -0,0 +1,958 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#include <linux/sched.h>
+#endif
+
+#include "dgnc_driver.h"
+#include "dgnc_pci.h"
+#include "dpacompat.h"
+#include "dgnc_mgmt.h"
+#include "dgnc_tty.h"
+#include "dgnc_trace.h"
+#include "dgnc_cls.h"
+#include "dgnc_neo.h"
+#include "dgnc_sysfs.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Digi International, http://www.digi.com");
+MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
+MODULE_SUPPORTED_DEVICE("dgnc");
+
+/*
+ * insmod command line overrideable parameters
+ *
+ * NOTE: we use a set of macros to create the variables, which allows
+ * us to specify the variable type, name, initial value, and description.
+ */
+PARM_INT(debug,		0x00,		0644,	"Driver debugging level");
+PARM_INT(rawreadok,	1,		0644,	"Bypass flip buffers on input");
+PARM_INT(trcbuf_size,	0x100000,	0644, 	"Debugging trace buffer size.");
+
+/**************************************************************************
+ *
+ * protos for this file
+ *
+ */
+static int		dgnc_start(void);
+static int		dgnc_finalize_board_init(struct board_t *brd);
+static void		dgnc_init_globals(void);
+static int		dgnc_found_board(struct pci_dev *pdev, int id);
+static void		dgnc_cleanup_board(struct board_t *brd);
+static void		dgnc_poll_handler(ulong dummy);
+static int		dgnc_init_pci(void);
+static int		dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void		dgnc_remove_one(struct pci_dev *dev);
+static int		dgnc_probe1(struct pci_dev *pdev, int card_type);
+static void		dgnc_do_remap(struct board_t *brd);
+
+/* Driver load/unload functions */
+int		dgnc_init_module(void);
+void		dgnc_cleanup_module(void);
+
+module_init(dgnc_init_module);
+module_exit(dgnc_cleanup_module);
+
+
+/*
+ * File operations permitted on Control/Management major.
+ */
+static struct file_operations dgnc_BoardFops =
+{
+	.owner		=	THIS_MODULE,
+	.unlocked_ioctl =  	dgnc_mgmt_ioctl,
+	.open		=	dgnc_mgmt_open,
+	.release	=	dgnc_mgmt_close
+};
+
+
+/*
+ * Globals
+ */
+uint			dgnc_NumBoards;
+struct board_t		*dgnc_Board[MAXBOARDS];
+DEFINE_SPINLOCK(dgnc_global_lock);
+int			dgnc_driver_state = DRIVER_INITIALIZED;
+ulong			dgnc_poll_counter;
+uint			dgnc_Major;
+int			dgnc_poll_tick = 20;	/* Poll interval - 20 ms */
+
+/*
+ * Static vars.
+ */
+static uint		dgnc_Major_Control_Registered = FALSE;
+static uint		dgnc_driver_start = FALSE;
+
+static struct class *dgnc_class;
+
+/*
+ * Poller stuff
+ */
+static 			DEFINE_SPINLOCK(dgnc_poll_lock);	/* Poll scheduling lock */
+static ulong		dgnc_poll_time;				/* Time of next poll */
+static uint		dgnc_poll_stop;				/* Used to tell poller to stop */
+static struct timer_list dgnc_poll_timer;
+
+
+static struct pci_device_id dgnc_pci_tbl[] = {
+	{	DIGI_VID, PCI_DEVICE_CLASSIC_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	0 },
+	{	DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	1 },
+	{	DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	2 },
+	{	DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	3 },
+	{	DIGI_VID, PCI_DEVICE_NEO_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		4 },
+	{	DIGI_VID, PCI_DEVICE_NEO_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,		5 },
+	{	DIGI_VID, PCI_DEVICE_NEO_2DB9_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	6 },
+	{	DIGI_VID, PCI_DEVICE_NEO_2DB9PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	7 },
+	{	DIGI_VID, PCI_DEVICE_NEO_2RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	8 },
+	{	DIGI_VID, PCI_DEVICE_NEO_2RJ45PRI_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	9 },
+	{	DIGI_VID, PCI_DEVICE_NEO_1_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	10 },
+	{	DIGI_VID, PCI_DEVICE_NEO_1_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	11 },
+	{	DIGI_VID, PCI_DEVICE_NEO_2_422_485_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	12 },
+	{	DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	 13 },
+	{	DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	14 },
+	{	DIGI_VID, PCI_DEVICE_NEO_EXPRESS_4RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	15 },
+	{	DIGI_VID, PCI_DEVICE_NEO_EXPRESS_8RJ45_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0,	16 },
+	{0,}						/* 0 terminated list. */
+};
+MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
+
+struct board_id {
+	uchar *name;
+	uint maxports;
+	unsigned int is_pci_express;
+};
+
+static struct board_id dgnc_Ids[] =
+{
+	{	PCI_DEVICE_CLASSIC_4_PCI_NAME,		4,	0	},
+	{	PCI_DEVICE_CLASSIC_4_422_PCI_NAME,	4,	0	},
+	{	PCI_DEVICE_CLASSIC_8_PCI_NAME,		8,	0	},
+	{	PCI_DEVICE_CLASSIC_8_422_PCI_NAME,	8,	0	},
+	{	PCI_DEVICE_NEO_4_PCI_NAME,		4,	0	},
+	{	PCI_DEVICE_NEO_8_PCI_NAME,		8,	0	},
+	{	PCI_DEVICE_NEO_2DB9_PCI_NAME,		2,	0	},
+	{	PCI_DEVICE_NEO_2DB9PRI_PCI_NAME,	2,	0	},
+	{	PCI_DEVICE_NEO_2RJ45_PCI_NAME,		2,	0	},
+	{	PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME,	2,	0	},
+	{	PCI_DEVICE_NEO_1_422_PCI_NAME,		1,	0	},
+	{	PCI_DEVICE_NEO_1_422_485_PCI_NAME,	1,	0	},
+	{	PCI_DEVICE_NEO_2_422_485_PCI_NAME,	2,	0	},
+	{	PCI_DEVICE_NEO_EXPRESS_8_PCI_NAME,	8,	1	},
+	{	PCI_DEVICE_NEO_EXPRESS_4_PCI_NAME,	4,	1	},
+	{	PCI_DEVICE_NEO_EXPRESS_4RJ45_PCI_NAME,	4,	1	},
+	{	PCI_DEVICE_NEO_EXPRESS_8RJ45_PCI_NAME,	8,	1	},
+	{	NULL,					0,	0	}
+};
+
+static struct pci_driver dgnc_driver = {
+	.name		= "dgnc",
+	.probe		= dgnc_init_one,
+	.id_table       = dgnc_pci_tbl,
+	.remove		= dgnc_remove_one,
+};
+
+
+char *dgnc_state_text[] = {
+	"Board Failed",
+	"Board Found",
+	"Board READY",
+};
+
+char *dgnc_driver_state_text[] = {
+	"Driver Initialized",
+	"Driver Ready."
+};
+
+
+
+/************************************************************************
+ *
+ * Driver load/unload functions
+ *
+ ************************************************************************/
+
+
+/*
+ * init_module()
+ *
+ * Module load.  This is where it all starts.
+ */
+int dgnc_init_module(void)
+{
+	int rc = 0;
+
+	APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART));
+
+	/*
+	 * Initialize global stuff
+	 */
+	rc = dgnc_start();
+
+	if (rc < 0) {
+		return(rc);
+	}
+
+	/*
+	 * Find and configure all the cards
+	 */
+	rc = dgnc_init_pci();
+
+	/*
+	 * If something went wrong in the scan, bail out of driver.
+	 */
+	if (rc < 0) {
+		/* Only unregister the pci driver if it was actually registered. */
+		if (dgnc_NumBoards)
+			pci_unregister_driver(&dgnc_driver);
+		else
+			printk("WARNING: dgnc driver load failed.  No Digi Neo or Classic boards found.\n");
+
+		dgnc_cleanup_module();
+	}
+	else {
+		dgnc_create_driver_sysfiles(&dgnc_driver);
+	}
+
+	DPR_INIT(("Finished init_module. Returning %d\n", rc));
+	return (rc);
+}
+
+
+/*
+ * Start of driver.
+ */
+static int dgnc_start(void)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	if (dgnc_driver_start == FALSE) {
+
+		dgnc_driver_start = TRUE;
+
+		/* make sure that the globals are init'd before we do anything else */
+		dgnc_init_globals();
+
+		dgnc_NumBoards = 0;
+
+		APR(("For the tools package or updated drivers please visit http://www.digi.com\n"));
+
+		/*
+		 * Register our base character device into the kernel.
+		 * This allows the download daemon to connect to the downld device
+		 * before any of the boards are init'ed.
+		 */
+		if (!dgnc_Major_Control_Registered) {
+			/*
+			 * Register management/dpa devices
+			 */
+			rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
+			if (rc <= 0) {
+				APR(("Can't register dgnc driver device (%d)\n", rc));
+				rc = -ENXIO;
+				return(rc);
+			}
+			dgnc_Major = rc;
+
+			dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+			device_create_drvdata(dgnc_class, NULL,
+				MKDEV(dgnc_Major, 0),
+				NULL, "dgnc_mgmt");
+#else
+			device_create(dgnc_class, NULL,
+				MKDEV(dgnc_Major, 0),
+				NULL, "dgnc_mgmt");
+#endif
+
+			dgnc_Major_Control_Registered = TRUE;
+		}
+
+		/*
+		 * Init any global tty stuff.
+		 */
+		rc = dgnc_tty_preinit();
+
+		if (rc < 0) {
+			APR(("tty preinit - not enough memory (%d)\n", rc));
+			return(rc);
+		}
+
+		/* Start the poller */
+		DGNC_LOCK(dgnc_poll_lock, flags);
+		init_timer(&dgnc_poll_timer);
+		dgnc_poll_timer.function = dgnc_poll_handler;
+		dgnc_poll_timer.data = 0;
+		dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
+		dgnc_poll_timer.expires = dgnc_poll_time;
+		DGNC_UNLOCK(dgnc_poll_lock, flags);
+
+		add_timer(&dgnc_poll_timer);
+
+		dgnc_driver_state = DRIVER_READY;
+	}
+
+	return(rc);
+}
+
+/*
+ * Register pci driver, and return how many boards we have.
+ */
+static int dgnc_init_pci(void)
+{
+	return pci_register_driver(&dgnc_driver);
+}
+
+
+/* returns count (>= 0), or negative on error */
+static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+
+	/* wake up and enable device */
+	rc = pci_enable_device(pdev);
+
+	if (rc < 0) {
+		rc = -EIO;
+	} else {
+		rc = dgnc_probe1(pdev, ent->driver_data);
+		if (rc == 0) {
+			dgnc_NumBoards++;
+			DPR_INIT(("Incrementing numboards to %d\n", dgnc_NumBoards));
+		}
+	}
+	return rc;
+}
+
+static int dgnc_probe1(struct pci_dev *pdev, int card_type)
+{
+	return dgnc_found_board(pdev, card_type);
+}
+
+
+static void dgnc_remove_one(struct pci_dev *dev)
+{
+	/* Do Nothing */
+}
+
+/*
+ * dgnc_cleanup_module()
+ *
+ * Module unload.  This is where it all ends.
+ */
+void dgnc_cleanup_module(void)
+{
+	int i;
+	ulong lock_flags;
+
+	DGNC_LOCK(dgnc_poll_lock, lock_flags);
+	dgnc_poll_stop = 1;
+	DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
+
+	/* Turn off poller right away. */
+	del_timer_sync(&dgnc_poll_timer);
+
+	dgnc_remove_driver_sysfiles(&dgnc_driver);
+
+	if (dgnc_Major_Control_Registered) {
+		device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
+		class_destroy(dgnc_class);
+		unregister_chrdev(dgnc_Major, "dgnc");
+	}
+
+	for (i = 0; i < dgnc_NumBoards; ++i) {
+		dgnc_remove_ports_sysfiles(dgnc_Board[i]);
+		dgnc_tty_uninit(dgnc_Board[i]);
+		dgnc_cleanup_board(dgnc_Board[i]);
+	}
+
+	dgnc_tty_post_uninit();
+
+#if defined(DGNC_TRACER)
+	/* last thing, make sure we release the tracebuffer */
+	dgnc_tracer_free();
+#endif
+	if (dgnc_NumBoards)
+		pci_unregister_driver(&dgnc_driver);
+}
+
+
+/*
+ * dgnc_cleanup_board()
+ *
+ * Free all the memory associated with a board
+ */
+static void dgnc_cleanup_board(struct board_t *brd)
+{
+	int i = 0;
+
+	if(!brd || brd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	switch (brd->device) {
+	case PCI_DEVICE_CLASSIC_4_DID:
+	case PCI_DEVICE_CLASSIC_8_DID:
+	case PCI_DEVICE_CLASSIC_4_422_DID:
+	case PCI_DEVICE_CLASSIC_8_422_DID:
+
+		/* Tell card not to interrupt anymore. */
+		outb(0, brd->iobase + 0x4c);
+		break;
+
+	default:
+		break;
+	}
+
+	if (brd->irq)
+		free_irq(brd->irq, brd);
+
+	tasklet_kill(&brd->helper_tasklet);
+
+	if (brd->re_map_membase) {
+		iounmap(brd->re_map_membase);
+		brd->re_map_membase = NULL;
+	}
+
+	if (brd->msgbuf_head) {
+		unsigned long flags;
+
+		DGNC_LOCK(dgnc_global_lock, flags);
+		brd->msgbuf = NULL;
+		printk(brd->msgbuf_head);
+		kfree(brd->msgbuf_head);
+		brd->msgbuf_head = NULL;
+		DGNC_UNLOCK(dgnc_global_lock, flags);
+	}
+
+	/* Free all allocated channels structs */
+	for (i = 0; i < MAXPORTS ; i++) {
+		if (brd->channels[i]) {
+			if (brd->channels[i]->ch_rqueue)
+				kfree(brd->channels[i]->ch_rqueue);
+			if (brd->channels[i]->ch_equeue)
+				kfree(brd->channels[i]->ch_equeue);
+			if (brd->channels[i]->ch_wqueue)
+				kfree(brd->channels[i]->ch_wqueue);
+
+			kfree(brd->channels[i]);
+			brd->channels[i] = NULL;
+		}
+	}
+
+	if (brd->flipbuf)
+		kfree(brd->flipbuf);
+
+	dgnc_Board[brd->boardnum] = NULL;
+
+	kfree(brd);
+}
+
+
+/*
+ * dgnc_found_board()
+ *
+ * A board has been found, init it.
+ */
+static int dgnc_found_board(struct pci_dev *pdev, int id)
+{
+	struct board_t *brd;
+	unsigned int pci_irq;
+	int i = 0;
+	int rc = 0;
+	unsigned long flags;
+
+	/* get the board structure and prep it */
+	brd = dgnc_Board[dgnc_NumBoards] =
+	(struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL);
+	if (!brd) {
+		APR(("memory allocation for board structure failed\n"));
+		return(-ENOMEM);
+	}
+
+	/* make a temporary message buffer for the boot messages */
+	brd->msgbuf = brd->msgbuf_head =
+		(char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL);
+	if (!brd->msgbuf) {
+		kfree(brd);
+		APR(("memory allocation for board msgbuf failed\n"));
+		return(-ENOMEM);
+	}
+
+	/* store the info for the board we've found */
+	brd->magic = DGNC_BOARD_MAGIC;
+	brd->boardnum = dgnc_NumBoards;
+	brd->vendor = dgnc_pci_tbl[id].vendor;
+	brd->device = dgnc_pci_tbl[id].device;
+	brd->pdev = pdev;
+	brd->pci_bus = pdev->bus->number;
+	brd->pci_slot = PCI_SLOT(pdev->devfn);
+	brd->name = dgnc_Ids[id].name;
+	brd->maxports = dgnc_Ids[id].maxports;
+	if (dgnc_Ids[i].is_pci_express)
+		brd->bd_flags |= BD_IS_PCI_EXPRESS;
+	brd->dpastatus = BD_NOFEP;
+	init_waitqueue_head(&brd->state_wait);
+
+	DGNC_SPINLOCK_INIT(brd->bd_lock);
+	DGNC_SPINLOCK_INIT(brd->bd_intr_lock);
+
+	brd->state		= BOARD_FOUND;
+
+	for (i = 0; i < MAXPORTS; i++) {
+		brd->channels[i] = NULL;
+	}
+
+	/* store which card & revision we have */
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+
+	pci_irq = pdev->irq;
+	brd->irq = pci_irq;
+
+
+	switch(brd->device) {
+
+	case PCI_DEVICE_CLASSIC_4_DID:
+	case PCI_DEVICE_CLASSIC_8_DID:
+	case PCI_DEVICE_CLASSIC_4_422_DID:
+	case PCI_DEVICE_CLASSIC_8_422_DID:
+
+		brd->dpatype = T_CLASSIC | T_PCIBUS;
+
+		DPR_INIT(("dgnc_found_board - Classic.\n"));
+
+		/*
+		 * For PCI ClassicBoards
+		 * PCI Local Address (i.e. "resource" number) space
+		 * 0	PLX Memory Mapped Config
+		 * 1	PLX I/O Mapped Config
+		 * 2	I/O Mapped UARTs and Status
+		 * 3	Memory Mapped VPD
+		 * 4	Memory Mapped UARTs and Status
+		 */
+
+
+		/* get the PCI Base Address Registers */
+		brd->membase = pci_resource_start(pdev, 4);
+
+		if (!brd->membase) {
+			APR(("card has no PCI IO resources, failing board.\n"));
+			return -ENODEV;
+		}
+
+		brd->membase_end = pci_resource_end(pdev, 4);
+
+		if (brd->membase & 1)
+			brd->membase &= ~3;
+		else
+			brd->membase &= ~15;
+
+		brd->iobase	= pci_resource_start(pdev, 1);
+		brd->iobase_end = pci_resource_end(pdev, 1);
+		brd->iobase	= ((unsigned int) (brd->iobase)) & 0xFFFE;
+
+		/* Assign the board_ops struct */
+		brd->bd_ops = &dgnc_cls_ops;
+
+		brd->bd_uart_offset = 0x8;
+		brd->bd_dividend = 921600;
+
+		dgnc_do_remap(brd);
+
+		/* Get and store the board VPD, if it exists */
+		brd->bd_ops->vpd(brd);
+
+		/*
+		 * Enable Local Interrupt 1		  (0x1),
+		 * Local Interrupt 1 Polarity Active high (0x2),
+		 * Enable PCI interrupt			  (0x40)
+		 */
+		outb(0x43, brd->iobase + 0x4c);
+
+		break;
+
+
+	case PCI_DEVICE_NEO_4_DID:
+	case PCI_DEVICE_NEO_8_DID:
+	case PCI_DEVICE_NEO_2DB9_DID:
+	case PCI_DEVICE_NEO_2DB9PRI_DID:
+	case PCI_DEVICE_NEO_2RJ45_DID:
+	case PCI_DEVICE_NEO_2RJ45PRI_DID:
+	case PCI_DEVICE_NEO_1_422_DID:
+	case PCI_DEVICE_NEO_1_422_485_DID:
+	case PCI_DEVICE_NEO_2_422_485_DID:
+	case PCI_DEVICE_NEO_EXPRESS_8_DID:
+	case PCI_DEVICE_NEO_EXPRESS_4_DID:
+	case PCI_DEVICE_NEO_EXPRESS_4RJ45_DID:
+	case PCI_DEVICE_NEO_EXPRESS_8RJ45_DID:
+
+		/*
+		 * This chip is set up 100% when we get to it.
+		 * No need to enable global interrupts or anything.
+		 */
+		if (brd->bd_flags & BD_IS_PCI_EXPRESS)
+			brd->dpatype = T_NEO_EXPRESS | T_PCIBUS;
+		else
+			brd->dpatype = T_NEO | T_PCIBUS;
+
+		DPR_INIT(("dgnc_found_board - NEO.\n"));
+
+		/* get the PCI Base Address Registers */
+		brd->membase     = pci_resource_start(pdev, 0);
+		brd->membase_end = pci_resource_end(pdev, 0);
+
+		if (brd->membase & 1)
+			brd->membase &= ~3;
+		else
+			brd->membase &= ~15;
+
+		/* Assign the board_ops struct */
+		brd->bd_ops = &dgnc_neo_ops;
+
+		brd->bd_uart_offset = 0x200;
+		brd->bd_dividend = 921600;
+
+		dgnc_do_remap(brd);
+
+		if (brd->re_map_membase) {
+
+			/* After remap is complete, we need to read and store the dvid */
+			brd->dvid = readb(brd->re_map_membase + 0x8D);
+
+			/* Get and store the board VPD, if it exists */
+			brd->bd_ops->vpd(brd);
+		}
+		break;
+
+	default:
+		APR(("Did not find any compatible Neo or Classic PCI boards in system.\n"));
+		return (-ENXIO);
+
+	}
+
+	/*
+	 * Do tty device initialization.
+	 */
+
+	rc = dgnc_tty_register(brd);
+	if (rc < 0) {
+		dgnc_tty_uninit(brd);
+		APR(("Can't register tty devices (%d)\n", rc));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+		goto failed;
+	}
+
+	rc = dgnc_finalize_board_init(brd);
+	if (rc < 0) {
+		APR(("Can't finalize board init (%d)\n", rc));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+
+		goto failed;
+	}
+
+	rc = dgnc_tty_init(brd);
+	if (rc < 0) {
+		dgnc_tty_uninit(brd);
+		APR(("Can't init tty devices (%d)\n", rc));
+		brd->state = BOARD_FAILED;
+		brd->dpastatus = BD_NOFEP;
+
+		goto failed;
+	}
+
+	brd->state = BOARD_READY;
+	brd->dpastatus = BD_RUNNING;
+
+	dgnc_create_ports_sysfiles(brd);
+
+	/* init our poll helper tasklet */
+	tasklet_init(&brd->helper_tasklet, brd->bd_ops->tasklet, (unsigned long) brd);
+
+	DPR_INIT(("dgnc_scan(%d) - printing out the msgbuf\n", i));
+	DGNC_LOCK(dgnc_global_lock, flags);
+	brd->msgbuf = NULL;
+	printk(brd->msgbuf_head);
+	kfree(brd->msgbuf_head);
+	brd->msgbuf_head = NULL;
+	DGNC_UNLOCK(dgnc_global_lock, flags);
+
+	/*
+	 * allocate flip buffer for board.
+	 *
+	 * Okay to malloc with GFP_KERNEL, we are not at interrupt
+	 * context, and there are no locks held.
+	 */
+	brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
+
+	wake_up_interruptible(&brd->state_wait);
+
+	return(0);
+
+failed:
+
+	return (-ENXIO);
+
+}
+
+
+static int dgnc_finalize_board_init(struct board_t *brd) {
+	int rc = 0;
+
+	DPR_INIT(("dgnc_finalize_board_init() - start\n"));
+
+	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+		return(-ENODEV);
+
+	DPR_INIT(("dgnc_finalize_board_init() - start #2\n"));
+
+	if (brd->irq) {
+		rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "DGNC", brd);
+
+		if (rc) {
+			printk("Failed to hook IRQ %d\n",brd->irq);
+			brd->state = BOARD_FAILED;
+			brd->dpastatus = BD_NOFEP;
+			rc = -ENODEV;
+		} else {
+			DPR_INIT(("Requested and received usage of IRQ %d\n", brd->irq));
+		}
+	}
+	return(rc);
+}
+
+/*
+ * Remap PCI memory.
+ */
+static void dgnc_do_remap(struct board_t *brd)
+{
+
+	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	brd->re_map_membase = ioremap(brd->membase, 0x1000);
+
+	DPR_INIT(("remapped mem: 0x%p\n", brd->re_map_membase));
+}
+
+
+/*****************************************************************************
+*
+* Function:
+*
+*    dgnc_poll_handler
+*
+* Author:
+*
+*    Scott H Kilau
+*
+* Parameters:
+*
+*    dummy -- ignored
+*
+* Return Values:
+*
+*    none
+*
+* Description:
+*
+*    As each timer expires, it determines (a) whether the "transmit"
+*    waiter needs to be woken up, and (b) whether the poller needs to
+*    be rescheduled.
+*
+******************************************************************************/
+
+static void dgnc_poll_handler(ulong dummy)
+{
+	struct board_t *brd;
+	unsigned long lock_flags;
+	int i;
+	unsigned long new_time;
+
+	dgnc_poll_counter++;
+
+	/*
+	 * Do not start the board state machine until
+	 * driver tells us its up and running, and has
+	 * everything it needs.
+	 */
+	if (dgnc_driver_state != DRIVER_READY) {
+		goto schedule_poller;
+	}
+
+	/* Go thru each board, kicking off a tasklet for each if needed */
+	for (i = 0; i < dgnc_NumBoards; i++) {
+		brd = dgnc_Board[i];
+
+		DGNC_LOCK(brd->bd_lock, lock_flags);
+
+		/* If board is in a failed state, don't bother scheduling a tasklet */
+		if (brd->state == BOARD_FAILED) {
+			DGNC_UNLOCK(brd->bd_lock, lock_flags);
+			continue;
+		}
+
+		/* Schedule a poll helper task */
+		tasklet_schedule(&brd->helper_tasklet);
+
+		DGNC_UNLOCK(brd->bd_lock, lock_flags);
+	}
+
+schedule_poller:
+
+	/*
+	 * Schedule ourself back at the nominal wakeup interval.
+	 */
+	DGNC_LOCK(dgnc_poll_lock, lock_flags);
+	dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick);
+
+	new_time = dgnc_poll_time - jiffies;
+
+	if ((ulong) new_time >= 2 * dgnc_poll_tick) {
+		dgnc_poll_time = jiffies +  dgnc_jiffies_from_ms(dgnc_poll_tick);
+	}
+
+	init_timer(&dgnc_poll_timer);
+	dgnc_poll_timer.function = dgnc_poll_handler;
+	dgnc_poll_timer.data = 0;
+	dgnc_poll_timer.expires = dgnc_poll_time;
+	DGNC_UNLOCK(dgnc_poll_lock, lock_flags);
+
+	if (!dgnc_poll_stop)
+		add_timer(&dgnc_poll_timer);
+}
+
+/*
+ * dgnc_init_globals()
+ *
+ * This is where we initialize the globals from the static insmod
+ * configuration variables.  These are declared near the head of
+ * this file.
+ */
+static void dgnc_init_globals(void)
+{
+	int i = 0;
+
+	dgnc_rawreadok		= rawreadok;
+	dgnc_trcbuf_size	= trcbuf_size;
+	dgnc_debug		= debug;
+
+	for (i = 0; i < MAXBOARDS; i++) {
+		dgnc_Board[i] = NULL;
+	}
+
+	init_timer(&dgnc_poll_timer);
+}
+
+
+/************************************************************************
+ *
+ * Utility functions
+ *
+ ************************************************************************/
+
+/*
+ * dgnc_ms_sleep()
+ *
+ * Put the driver to sleep for x ms's
+ *
+ * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal.
+ */
+int dgnc_ms_sleep(ulong ms)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout((ms * HZ) / 1000);
+	return (signal_pending(current));
+}
+
+
+
+/*
+ *      dgnc_ioctl_name() : Returns a text version of each ioctl value.
+ */
+char *dgnc_ioctl_name(int cmd)
+{
+	switch(cmd) {
+
+	case TCGETA:		return("TCGETA");
+	case TCGETS:		return("TCGETS");
+	case TCSETA:		return("TCSETA");
+	case TCSETS:		return("TCSETS");
+	case TCSETAW:		return("TCSETAW");
+	case TCSETSW:		return("TCSETSW");
+	case TCSETAF:		return("TCSETAF");
+	case TCSETSF:		return("TCSETSF");
+	case TCSBRK:		return("TCSBRK");
+	case TCXONC:		return("TCXONC");
+	case TCFLSH:		return("TCFLSH");
+	case TIOCGSID:		return("TIOCGSID");
+
+	case TIOCGETD:		return("TIOCGETD");
+	case TIOCSETD:		return("TIOCSETD");
+	case TIOCGWINSZ:	return("TIOCGWINSZ");
+	case TIOCSWINSZ:	return("TIOCSWINSZ");
+
+	case TIOCMGET:		return("TIOCMGET");
+	case TIOCMSET:		return("TIOCMSET");
+	case TIOCMBIS:		return("TIOCMBIS");
+	case TIOCMBIC:		return("TIOCMBIC");
+
+	/* from digi.h */
+	case DIGI_SETA:		return("DIGI_SETA");
+	case DIGI_SETAW:	return("DIGI_SETAW");
+	case DIGI_SETAF:	return("DIGI_SETAF");
+	case DIGI_SETFLOW:	return("DIGI_SETFLOW");
+	case DIGI_SETAFLOW:	return("DIGI_SETAFLOW");
+	case DIGI_GETFLOW:	return("DIGI_GETFLOW");
+	case DIGI_GETAFLOW:	return("DIGI_GETAFLOW");
+	case DIGI_GETA:		return("DIGI_GETA");
+	case DIGI_GEDELAY:	return("DIGI_GEDELAY");
+	case DIGI_SEDELAY:	return("DIGI_SEDELAY");
+	case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD");
+	case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD");
+	case TIOCMODG:		return("TIOCMODG");
+	case TIOCMODS:		return("TIOCMODS");
+	case TIOCSDTR:		return("TIOCSDTR");
+	case TIOCCDTR:		return("TIOCCDTR");
+
+	default:		return("unknown");
+	}
+}
diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h
new file mode 100644
index 0000000..218b15d
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_driver.h
@@ -0,0 +1,563 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * Driver includes
+ *
+ *************************************************************************/
+
+#ifndef __DGNC_DRIVER_H
+#define __DGNC_DRIVER_H
+
+#include <linux/types.h>	/* To pick up the varions Linux types */
+#include <linux/tty.h>	  /* To pick up the various tty structs/defines */
+#include <linux/interrupt.h>	/* For irqreturn_t type */
+
+#include "dgnc_types.h"		/* Additional types needed by the Digi header files */
+#include "digi.h"		/* Digi specific ioctl header */
+#include "dgnc_kcompat.h"	/* Kernel 2.4/2.6 compat includes */
+#include "dgnc_sysfs.h"		/* Support for SYSFS */
+
+/*************************************************************************
+ *
+ * Driver defines
+ *
+ *************************************************************************/
+
+/*
+ * Driver identification, error and debugging statments
+ *
+ * In theory, you can change all occurances of "digi" in the next
+ * three lines, and the driver printk's will all automagically change.
+ *
+ * APR((fmt, args, ...));	Always prints message
+ * DPR((fmt, args, ...));	Only prints if DGNC_TRACER is defined at
+ *				  compile time and dgnc_debug!=0
+ */
+#define	PROCSTR		"dgnc"			/* /proc entries	 */
+#define	DEVSTR		"/dev/dg/dgnc"		/* /dev entries		 */
+#define	DRVSTR		"dgnc"			/* Driver name string
+						 * displayed by APR	 */
+#define	APR(args)	do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \
+			   } while (0)
+#define	RAPR(args)	do { PRINTF_TO_KMEM(args); printk args; } while (0)
+
+#define TRC_TO_CONSOLE 1
+
+/*
+ * Debugging levels can be set using debug insmod variable
+ * They can also be compiled out completely.
+ */
+
+#define	DBG_INIT		(dgnc_debug & 0x01)
+#define	DBG_BASIC		(dgnc_debug & 0x02)
+#define	DBG_CORE		(dgnc_debug & 0x04)
+
+#define	DBG_OPEN		(dgnc_debug & 0x08)
+#define	DBG_CLOSE		(dgnc_debug & 0x10)
+#define	DBG_READ		(dgnc_debug & 0x20)
+#define	DBG_WRITE		(dgnc_debug & 0x40)
+
+#define	DBG_IOCTL		(dgnc_debug & 0x80)
+
+#define	DBG_PROC		(dgnc_debug & 0x100)
+#define	DBG_PARAM		(dgnc_debug & 0x200)
+#define	DBG_PSCAN		(dgnc_debug & 0x400)
+#define	DBG_EVENT		(dgnc_debug & 0x800)
+
+#define	DBG_DRAIN		(dgnc_debug & 0x1000)
+#define	DBG_MSIGS		(dgnc_debug & 0x2000)
+
+#define	DBG_MGMT		(dgnc_debug & 0x4000)
+#define	DBG_INTR		(dgnc_debug & 0x8000)
+
+#define	DBG_CARR		(dgnc_debug & 0x10000)
+
+
+#if defined(DGNC_TRACER)
+
+# if defined(TRC_TO_KMEM)
+/* Choose one: */
+#  define TRC_ON_OVERFLOW_WRAP_AROUND
+#  undef  TRC_ON_OVERFLOW_SHIFT_BUFFER
+# endif //TRC_TO_KMEM
+
+# define TRC_MAXMSG		1024
+# define TRC_OVERFLOW		"(OVERFLOW)"
+# define TRC_DTRC		"/usr/bin/dtrc"
+
+#if defined TRC_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; }
+#else //!defined TRACE_TO_CONSOLE
+#define PRINTF_TO_CONSOLE(args)
+#endif
+
+#if defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args) dgnc_tracef args
+#else //!defined TRC_TO_KMEM
+#define PRINTF_TO_KMEM(args)
+#endif
+
+#define	TRC(args)	{ PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) }
+
+# define DPR_INIT(ARGS)		if (DBG_INIT) TRC(ARGS)
+# define DPR_BASIC(ARGS)	if (DBG_BASIC) TRC(ARGS)
+# define DPR_CORE(ARGS)		if (DBG_CORE) TRC(ARGS)
+# define DPR_OPEN(ARGS)		if (DBG_OPEN)  TRC(ARGS)
+# define DPR_CLOSE(ARGS)	if (DBG_CLOSE)  TRC(ARGS)
+# define DPR_READ(ARGS)		if (DBG_READ)  TRC(ARGS)
+# define DPR_WRITE(ARGS)	if (DBG_WRITE) TRC(ARGS)
+# define DPR_IOCTL(ARGS)	if (DBG_IOCTL) TRC(ARGS)
+# define DPR_PROC(ARGS)		if (DBG_PROC)  TRC(ARGS)
+# define DPR_PARAM(ARGS)	if (DBG_PARAM)  TRC(ARGS)
+# define DPR_PSCAN(ARGS)	if (DBG_PSCAN)  TRC(ARGS)
+# define DPR_EVENT(ARGS)	if (DBG_EVENT)  TRC(ARGS)
+# define DPR_DRAIN(ARGS)	if (DBG_DRAIN)  TRC(ARGS)
+# define DPR_CARR(ARGS)		if (DBG_CARR)  TRC(ARGS)
+# define DPR_MGMT(ARGS)		if (DBG_MGMT)  TRC(ARGS)
+# define DPR_INTR(ARGS)		if (DBG_INTR)  TRC(ARGS)
+# define DPR_MSIGS(ARGS)	if (DBG_MSIGS)  TRC(ARGS)
+
+# define DPR(ARGS)		if (dgnc_debug) TRC(ARGS)
+# define P(X)			dgnc_tracef(#X "=%p\n", X)
+# define X(X)			dgnc_tracef(#X "=%x\n", X)
+
+#else//!defined DGNC_TRACER
+
+#define PRINTF_TO_KMEM(args)
+# define TRC(ARGS)
+# define DPR_INIT(ARGS)
+# define DPR_BASIC(ARGS)
+# define DPR_CORE(ARGS)
+# define DPR_OPEN(ARGS)
+# define DPR_CLOSE(ARGS)
+# define DPR_READ(ARGS)
+# define DPR_WRITE(ARGS)
+# define DPR_IOCTL(ARGS)
+# define DPR_PROC(ARGS)
+# define DPR_PARAM(ARGS)
+# define DPR_PSCAN(ARGS)
+# define DPR_EVENT(ARGS)
+# define DPR_DRAIN(ARGS)
+# define DPR_CARR(ARGS)
+# define DPR_MGMT(ARGS)
+# define DPR_INTR(ARGS)
+# define DPR_MSIGS(ARGS)
+
+# define DPR(args)
+
+#endif//DGNC_TRACER
+
+/* Number of boards we support at once. */
+#define	MAXBOARDS	20
+#define	MAXPORTS	8
+#define MAXTTYNAMELEN	200
+
+/* Our 3 magic numbers for our board, channel and unit structs */
+#define DGNC_BOARD_MAGIC	0x5c6df104
+#define DGNC_CHANNEL_MAGIC	0x6c6df104
+#define DGNC_UNIT_MAGIC		0x7c6df104
+
+/* Serial port types */
+#define DGNC_SERIAL		0
+#define DGNC_PRINT		1
+
+#define	SERIAL_TYPE_NORMAL	1
+
+#define PORT_NUM(dev)	((dev) & 0x7f)
+#define IS_PRINT(dev)	(((dev) & 0xff) >= 0x80)
+
+/* MAX number of stop characters we will send when our read queue is getting full */
+#define MAX_STOPS_SENT 5
+
+/* 4 extra for alignment play space */
+#define WRITEBUFLEN		((4096) + 4)
+#define MYFLIPLEN		N_TTY_BUF_SIZE
+
+#define dgnc_jiffies_from_ms(a) (((a) * HZ) / 1000)
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.  This is the same structure that is defined
+ * as the default in tty_io.c with the same settings overriden as in serial.c
+ *
+ * In short, this should match the internal serial ports' defaults.
+ */
+#define	DEFAULT_IFLAGS	(ICRNL | IXON)
+#define	DEFAULT_OFLAGS	(OPOST | ONLCR)
+#define	DEFAULT_CFLAGS	(B9600 | CS8 | CREAD | HUPCL | CLOCAL)
+#define	DEFAULT_LFLAGS	(ISIG | ICANON | ECHO | ECHOE | ECHOK | \
+			ECHOCTL | ECHOKE | IEXTEN)
+
+#ifndef _POSIX_VDISABLE
+#define   _POSIX_VDISABLE '\0'
+#endif
+
+#define SNIFF_MAX	65536		/* Sniff buffer size (2^n) */
+#define SNIFF_MASK	(SNIFF_MAX - 1)	/* Sniff wrap mask */
+
+/*
+ * Lock function/defines.
+ * Makes spotting lock/unlock locations easier.
+ */
+# define DGNC_SPINLOCK_INIT(x)		spin_lock_init(&(x))
+# define DGNC_LOCK(x,y)			spin_lock_irqsave(&(x), y)
+# define DGNC_UNLOCK(x,y)		spin_unlock_irqrestore(&(x), y)
+
+/*
+ * All the possible states the driver can be while being loaded.
+ */
+enum {
+	DRIVER_INITIALIZED = 0,
+	DRIVER_READY
+};
+
+/*
+ * All the possible states the board can be while booting up.
+ */
+enum {
+	BOARD_FAILED = 0,
+	BOARD_FOUND,
+	BOARD_READY
+};
+
+
+/*************************************************************************
+ *
+ * Structures and closely related defines.
+ *
+ *************************************************************************/
+
+struct board_t;
+struct channel_t;
+
+/************************************************************************
+ * Per board operations structure				       *
+ ************************************************************************/
+struct board_ops {
+	void (*tasklet) (unsigned long data);
+	irqreturn_t (*intr) (int irq, void *voidbrd);
+	void (*uart_init) (struct channel_t *ch);
+	void (*uart_off) (struct channel_t *ch);
+	int  (*drain) (struct tty_struct *tty, uint seconds);
+	void (*param) (struct tty_struct *tty);
+	void (*vpd) (struct board_t *brd);
+	void (*assert_modem_signals) (struct channel_t *ch);
+	void (*flush_uart_write) (struct channel_t *ch);
+	void (*flush_uart_read) (struct channel_t *ch);
+	void (*disable_receiver) (struct channel_t *ch);
+	void (*enable_receiver) (struct channel_t *ch);
+	void (*send_break) (struct channel_t *ch, int);
+	void (*send_start_character) (struct channel_t *ch);
+	void (*send_stop_character) (struct channel_t *ch);
+	void (*copy_data_from_queue_to_uart) (struct channel_t *ch);
+	uint (*get_uart_bytes_left) (struct channel_t *ch);
+	void (*send_immediate_char) (struct channel_t *ch, unsigned char);
+};
+
+/************************************************************************
+ * Device flag definitions for bd_flags.
+ ************************************************************************/
+#define BD_IS_PCI_EXPRESS     0x0001	  /* Is a PCI Express board */
+
+
+/*
+ *	Per-board information
+ */
+struct board_t {
+	int		magic;		/* Board Magic number.  */
+	int		boardnum;	/* Board number: 0-32 */
+
+	int		type;		/* Type of board */
+	char		*name;		/* Product Name */
+	struct pci_dev	*pdev;		/* Pointer to the pci_dev struct */
+	unsigned long	bd_flags;	/* Board flags */
+	u16		vendor;		/* PCI vendor ID */
+	u16		device;		/* PCI device ID */
+	u16		subvendor;	/* PCI subsystem vendor ID */
+	u16		subdevice;	/* PCI subsystem device ID */
+	uchar		rev;		/* PCI revision ID */
+	uint		pci_bus;	/* PCI bus value */
+	uint		pci_slot;	/* PCI slot value */
+	uint		maxports;	/* MAX ports this board can handle */
+	uchar		dvid;		/* Board specific device id */
+	uchar		vpd[128];	/* VPD of board, if found */
+	uchar		serial_num[20];	/* Serial number of board, if found in VPD */
+
+	spinlock_t	bd_lock;	/* Used to protect board */
+
+	spinlock_t	bd_intr_lock;	/* Used to protect the poller tasklet and
+					 * the interrupt routine from each other.
+					 */
+
+	uint		state;		/* State of card. */
+	wait_queue_head_t state_wait;	/* Place to sleep on for state change */
+
+	struct		tasklet_struct helper_tasklet; /* Poll helper tasklet */
+
+	uint		nasync;		/* Number of ports on card */
+
+	uint		irq;		/* Interrupt request number */
+	ulong		intr_count;	/* Count of interrupts */
+	ulong		intr_modem;	/* Count of interrupts */
+	ulong		intr_tx;	/* Count of interrupts */
+	ulong		intr_rx;	/* Count of interrupts */
+
+	ulong		membase;	/* Start of base memory of the card */
+	ulong		membase_end;	/* End of base memory of the card */
+
+	u8 __iomem		*re_map_membase;/* Remapped memory of the card */
+
+	ulong		iobase;		/* Start of io base of the card */
+	ulong		iobase_end;	/* End of io base of the card */
+
+	uint		bd_uart_offset;	/* Space between each UART */
+
+	struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */
+
+	struct tty_driver	SerialDriver;
+	char		SerialName[200];
+	struct tty_driver	PrintDriver;
+	char		PrintName[200];
+
+	uint		dgnc_Major_Serial_Registered;
+	uint		dgnc_Major_TransparentPrint_Registered;
+
+	uint		dgnc_Serial_Major;
+	uint		dgnc_TransparentPrint_Major;
+
+	uint		TtyRefCnt;
+
+	char		*flipbuf;	/* Our flip buffer, alloced if board is found */
+
+	u16		dpatype;	/* The board "type", as defined by DPA */
+	u16		dpastatus;	/* The board "status", as defined by DPA */
+
+	/*
+	 *	Mgmt data.
+	 */
+	char		*msgbuf_head;
+	char		*msgbuf;
+
+	uint		bd_dividend;	/* Board/UARTs specific dividend */
+
+	struct board_ops *bd_ops;
+
+	/* /proc/<board> entries */
+	struct proc_dir_entry *proc_entry_pointer;
+	struct dgnc_proc_entry *dgnc_board_table;
+
+};
+
+
+/************************************************************************
+ * Unit flag definitions for un_flags.
+ ************************************************************************/
+#define UN_ISOPEN	0x0001		/* Device is open		*/
+#define UN_CLOSING	0x0002		/* Line is being closed		*/
+#define UN_IMM		0x0004		/* Service immediately		*/
+#define UN_BUSY		0x0008		/* Some work this channel	*/
+#define UN_BREAKI	0x0010		/* Input break received		*/
+#define UN_PWAIT	0x0020		/* Printer waiting for terminal	*/
+#define UN_TIME		0x0040		/* Waiting on time		*/
+#define UN_EMPTY	0x0080		/* Waiting output queue empty	*/
+#define UN_LOW		0x0100		/* Waiting output low water mark*/
+#define UN_EXCL_OPEN	0x0200		/* Open for exclusive use	*/
+#define UN_WOPEN	0x0400		/* Device waiting for open	*/
+#define UN_WIOCTL	0x0800		/* Device waiting for open	*/
+#define UN_HANGUP	0x8000		/* Carrier lost			*/
+
+struct device;
+
+/************************************************************************
+ * Structure for terminal or printer unit.
+ ************************************************************************/
+struct un_t {
+	int	magic;		/* Unit Magic Number.			*/
+	struct	channel_t *un_ch;
+	ulong	un_time;
+	uint	un_type;
+	uint	un_open_count;	/* Counter of opens to port		*/
+	struct tty_struct *un_tty;/* Pointer to unit tty structure	*/
+	uint	un_flags;	/* Unit flags				*/
+	wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */
+	uint	un_dev;		/* Minor device number			*/
+	struct device *un_sysfs;
+};
+
+
+/************************************************************************
+ * Device flag definitions for ch_flags.
+ ************************************************************************/
+#define CH_PRON		0x0001		/* Printer on string		*/
+#define CH_STOP		0x0002		/* Output is stopped		*/
+#define CH_STOPI	0x0004		/* Input is stopped		*/
+#define CH_CD		0x0008		/* Carrier is present		*/
+#define CH_FCAR		0x0010		/* Carrier forced on		*/
+#define CH_HANGUP       0x0020		/* Hangup received		*/
+
+#define CH_RECEIVER_OFF	0x0040		/* Receiver is off		*/
+#define CH_OPENING	0x0080		/* Port in fragile open state	*/
+#define CH_CLOSING	0x0100		/* Port in fragile close state	*/
+#define CH_FIFO_ENABLED 0x0200		/* Port has FIFOs enabled	*/
+#define CH_TX_FIFO_EMPTY 0x0400		/* TX Fifo is completely empty	*/
+#define CH_TX_FIFO_LWM  0x0800		/* TX Fifo is below Low Water	*/
+#define CH_BREAK_SENDING 0x1000		/* Break is being sent		*/
+#define CH_LOOPBACK 0x2000		/* Channel is in lookback mode	*/
+#define CH_FLIPBUF_IN_USE 0x4000	/* Channel's flipbuf is in use	*/
+#define CH_BAUD0	0x08000		/* Used for checking B0 transitions */
+#define CH_FORCED_STOP  0x20000		/* Output is forcibly stopped	*/
+#define CH_FORCED_STOPI 0x40000		/* Input is forcibly stopped	*/
+
+/*
+ * Definitions for ch_sniff_flags
+ */
+#define SNIFF_OPEN	0x1
+#define SNIFF_WAIT_DATA	0x2
+#define SNIFF_WAIT_SPACE 0x4
+
+
+/* Our Read/Error/Write queue sizes */
+#define RQUEUEMASK	0x1FFF		/* 8 K - 1 */
+#define EQUEUEMASK	0x1FFF		/* 8 K - 1 */
+#define WQUEUEMASK	0x0FFF		/* 4 K - 1 */
+#define RQUEUESIZE	(RQUEUEMASK + 1)
+#define EQUEUESIZE	RQUEUESIZE
+#define WQUEUESIZE	(WQUEUEMASK + 1)
+
+
+/************************************************************************
+ * Channel information structure.
+ ************************************************************************/
+struct channel_t {
+	int magic;			/* Channel Magic Number		*/
+	struct board_t	*ch_bd;		/* Board structure pointer      */
+	struct digi_t	ch_digi;	/* Transparent Print structure  */
+	struct un_t	ch_tun;		/* Terminal unit info	   */
+	struct un_t	ch_pun;		/* Printer unit info	    */
+
+	spinlock_t	ch_lock;	/* provide for serialization */
+	wait_queue_head_t ch_flags_wait;
+
+	uint		ch_portnum;	/* Port number, 0 offset.	*/
+	uint		ch_open_count;	/* open count			*/
+	uint		ch_flags;	/* Channel flags		*/
+
+	ulong		ch_close_delay;	/* How long we should drop RTS/DTR for */
+
+	ulong		ch_cpstime;	/* Time for CPS calculations    */
+
+	tcflag_t	ch_c_iflag;	/* channel iflags	       */
+	tcflag_t	ch_c_cflag;	/* channel cflags	       */
+	tcflag_t	ch_c_oflag;	/* channel oflags	       */
+	tcflag_t	ch_c_lflag;	/* channel lflags	       */
+	uchar		ch_stopc;	/* Stop character	       */
+	uchar		ch_startc;	/* Start character	      */
+
+	uint		ch_old_baud;	/* Cache of the current baud */
+	uint		ch_custom_speed;/* Custom baud, if set */
+
+	uint		ch_wopen;	/* Waiting for open process cnt */
+
+	uchar		ch_mostat;	/* FEP output modem status      */
+	uchar		ch_mistat;	/* FEP input modem status       */
+
+	struct neo_uart_struct __iomem *ch_neo_uart;	/* Pointer to the "mapped" UART struct */
+	struct cls_uart_struct __iomem *ch_cls_uart;	/* Pointer to the "mapped" UART struct */
+
+	uchar		ch_cached_lsr;	/* Cached value of the LSR register */
+
+	uchar		*ch_rqueue;	/* Our read queue buffer - malloc'ed */
+	ushort		ch_r_head;	/* Head location of the read queue */
+	ushort		ch_r_tail;	/* Tail location of the read queue */
+
+	uchar		*ch_equeue;	/* Our error queue buffer - malloc'ed */
+	ushort		ch_e_head;	/* Head location of the error queue */
+	ushort		ch_e_tail;	/* Tail location of the error queue */
+
+	uchar		*ch_wqueue;	/* Our write queue buffer - malloc'ed */
+	ushort		ch_w_head;	/* Head location of the write queue */
+	ushort		ch_w_tail;	/* Tail location of the write queue */
+
+	ulong		ch_rxcount;	/* total of data received so far */
+	ulong		ch_txcount;	/* total of data transmitted so far */
+
+	uchar		ch_r_tlevel;	/* Receive Trigger level */
+	uchar		ch_t_tlevel;	/* Transmit Trigger level */
+
+	uchar		ch_r_watermark;	/* Receive Watermark */
+
+	ulong		ch_stop_sending_break;	/* Time we should STOP sending a break */
+
+	uint		ch_stops_sent;	/* How many times I have sent a stop character
+					 * to try to stop the other guy sending.
+					 */
+	ulong		ch_err_parity;	/* Count of parity errors on channel */
+	ulong		ch_err_frame;	/* Count of framing errors on channel */
+	ulong		ch_err_break;	/* Count of breaks on channel */
+	ulong		ch_err_overrun; /* Count of overruns on channel */
+
+	ulong		ch_xon_sends;	/* Count of xons transmitted */
+	ulong		ch_xoff_sends;	/* Count of xoffs transmitted */
+
+	ulong		ch_intr_modem;	/* Count of interrupts */
+	ulong		ch_intr_tx;	/* Count of interrupts */
+	ulong		ch_intr_rx;	/* Count of interrupts */
+
+
+	/* /proc/<board>/<channel> entries */
+	struct proc_dir_entry *proc_entry_pointer;
+	struct dgnc_proc_entry *dgnc_channel_table;
+
+	uint ch_sniff_in;
+	uint ch_sniff_out;
+	char *ch_sniff_buf;		/* Sniff buffer for proc */
+	ulong ch_sniff_flags;		/* Channel flags		*/
+	wait_queue_head_t ch_sniff_wait;
+};
+
+
+/*************************************************************************
+ *
+ * Prototypes for non-static functions used in more than one module
+ *
+ *************************************************************************/
+
+extern int		dgnc_ms_sleep(ulong ms);
+extern char		*dgnc_ioctl_name(int cmd);
+
+/*
+ * Our Global Variables.
+ */
+extern int		dgnc_driver_state;	/* The state of the driver	*/
+extern uint		dgnc_Major;		/* Our driver/mgmt major	*/
+extern int		dgnc_debug;		/* Debug variable		*/
+extern int		dgnc_rawreadok;		/* Set if user wants rawreads	*/
+extern int		dgnc_poll_tick;		/* Poll interval - 20 ms	*/
+extern int		dgnc_trcbuf_size;	/* Size of the ringbuffer	*/
+extern spinlock_t	dgnc_global_lock;	/* Driver global spinlock	*/
+extern uint		dgnc_NumBoards;		/* Total number of boards	*/
+extern struct board_t	*dgnc_Board[MAXBOARDS];	/* Array of board structs	*/
+extern ulong		dgnc_poll_counter;	/* Times the poller has run	*/
+extern char		*dgnc_state_text[];	/* Array of state text		*/
+extern char		*dgnc_driver_state_text[];/* Array of driver state text */
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_kcompat.h b/drivers/staging/dgnc/dgnc_kcompat.h
new file mode 100644
index 0000000..00f589a
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_kcompat.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *************************************************************************
+ *
+ * This file is intended to contain all the kernel "differences" between the
+ * various kernels that we support.
+ *
+ *************************************************************************/
+
+#ifndef __DGNC_KCOMPAT_H
+#define __DGNC_KCOMPAT_H
+
+#include <linux/version.h>
+
+# ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(a,b,c)  (((a) << 16) + ((b) << 8) + (c))
+# endif
+
+
+#if !defined(TTY_FLIPBUF_SIZE)
+# define TTY_FLIPBUF_SIZE 512
+#endif
+
+
+/* Sparse stuff */
+# ifndef __user
+#  define __user
+#  define __kernel
+#  define __safe
+#  define __force
+#  define __chk_user_ptr(x) (void)0
+# endif
+
+
+#  define PARM_STR(VAR, INIT, PERM, DESC) \
+		static char *VAR = INIT; \
+		char *dgnc_##VAR; \
+		module_param(VAR, charp, PERM); \
+		MODULE_PARM_DESC(VAR, DESC);
+
+#  define PARM_INT(VAR, INIT, PERM, DESC) \
+		static int VAR = INIT; \
+		int dgnc_##VAR; \
+		module_param(VAR, int, PERM); \
+		MODULE_PARM_DESC(VAR, DESC);
+
+#  define PARM_ULONG(VAR, INIT, PERM, DESC) \
+		static ulong VAR = INIT; \
+		ulong dgnc_##VAR; \
+		module_param(VAR, long, PERM); \
+		MODULE_PARM_DESC(VAR, DESC);
+
+
+
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+
+
+
+/* NOTHING YET */
+
+
+
+# else
+
+
+
+# error "this driver does not support anything below the 2.6.27 kernel series."
+
+
+
+# endif
+
+#endif /* ! __DGNC_KCOMPAT_H */
diff --git a/drivers/staging/dgnc/dgnc_mgmt.c b/drivers/staging/dgnc/dgnc_mgmt.c
new file mode 100644
index 0000000..c4629d7
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_mgmt.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ */
+
+/************************************************************************
+ *
+ * This file implements the mgmt functionality for the
+ * Neo and ClassicBoard based product lines.
+ *
+ ************************************************************************
+ */
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/serial_reg.h>
+#include <linux/termios.h>
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+
+#include "dgnc_driver.h"
+#include "dgnc_pci.h"
+#include "dgnc_kcompat.h"	/* Kernel 2.4/2.6 compat includes */
+#include "dgnc_mgmt.h"
+#include "dpacompat.h"
+
+
+/* Our "in use" variables, to enforce 1 open only */
+static int dgnc_mgmt_in_use[MAXMGMTDEVICES];
+
+
+/*
+ * dgnc_mgmt_open()
+ *
+ * Open the mgmt/downld/dpa device
+ */
+int dgnc_mgmt_open(struct inode *inode, struct file *file)
+{
+	unsigned long lock_flags;
+	unsigned int minor = iminor(inode);
+
+	DPR_MGMT(("dgnc_mgmt_open start.\n"));
+
+	DGNC_LOCK(dgnc_global_lock, lock_flags);
+
+	/* mgmt device */
+	if (minor < MAXMGMTDEVICES) {
+		/* Only allow 1 open at a time on mgmt device */
+		if (dgnc_mgmt_in_use[minor]) {
+			DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+			return (-EBUSY);
+		}
+		dgnc_mgmt_in_use[minor]++;
+	}
+	else {
+		DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+		return (-ENXIO);
+	}
+
+	DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+
+	DPR_MGMT(("dgnc_mgmt_open finish.\n"));
+
+	return 0;
+}
+
+
+/*
+ * dgnc_mgmt_close()
+ *
+ * Open the mgmt/dpa device
+ */
+int dgnc_mgmt_close(struct inode *inode, struct file *file)
+{
+	unsigned long lock_flags;
+	unsigned int minor = iminor(inode);
+
+	DPR_MGMT(("dgnc_mgmt_close start.\n"));
+
+	DGNC_LOCK(dgnc_global_lock, lock_flags);
+
+	/* mgmt device */
+	if (minor < MAXMGMTDEVICES) {
+		if (dgnc_mgmt_in_use[minor]) {
+			dgnc_mgmt_in_use[minor] = 0;
+		}
+	}
+	DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+
+	DPR_MGMT(("dgnc_mgmt_close finish.\n"));
+
+	return 0;
+}
+
+
+/*
+ * dgnc_mgmt_ioctl()
+ *
+ * ioctl the mgmt/dpa device
+ */
+
+long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned long lock_flags;
+	void __user *uarg = (void __user *) arg;
+
+	DPR_MGMT(("dgnc_mgmt_ioctl start.\n"));
+
+	switch (cmd) {
+
+	case DIGI_GETDD:
+	{
+		/*
+		 * This returns the total number of boards
+		 * in the system, as well as driver version
+		 * and has space for a reserved entry
+		 */
+		struct digi_dinfo ddi;
+
+		DGNC_LOCK(dgnc_global_lock, lock_flags);
+
+		ddi.dinfo_nboards = dgnc_NumBoards;
+		sprintf(ddi.dinfo_version, "%s", DG_PART);
+
+		DGNC_UNLOCK(dgnc_global_lock, lock_flags);
+
+		DPR_MGMT(("DIGI_GETDD returning numboards: %d version: %s\n",
+			ddi.dinfo_nboards, ddi.dinfo_version));
+
+		if (copy_to_user(uarg, &ddi, sizeof (ddi)))
+			return(-EFAULT);
+
+		break;
+	}
+
+	case DIGI_GETBD:
+	{
+		int brd;
+
+		struct digi_info di;
+
+		if (copy_from_user(&brd, uarg, sizeof(int))) {
+			return(-EFAULT);
+		}
+
+		DPR_MGMT(("DIGI_GETBD asking about board: %d\n", brd));
+
+		if ((brd < 0) || (brd > dgnc_NumBoards) || (dgnc_NumBoards == 0))
+			return (-ENODEV);
+
+		memset(&di, 0, sizeof(di));
+
+		di.info_bdnum = brd;
+
+		DGNC_LOCK(dgnc_Board[brd]->bd_lock, lock_flags);
+
+		di.info_bdtype = dgnc_Board[brd]->dpatype;
+		di.info_bdstate = dgnc_Board[brd]->dpastatus;
+		di.info_ioport = 0;
+		di.info_physaddr = (ulong) dgnc_Board[brd]->membase;
+		di.info_physsize = (ulong) dgnc_Board[brd]->membase - dgnc_Board[brd]->membase_end;
+		if (dgnc_Board[brd]->state != BOARD_FAILED)
+			di.info_nports = dgnc_Board[brd]->nasync;
+		else
+			di.info_nports = 0;
+
+		DGNC_UNLOCK(dgnc_Board[brd]->bd_lock, lock_flags);
+
+		DPR_MGMT(("DIGI_GETBD returning type: %x state: %x ports: %x size: %x\n",
+			di.info_bdtype, di.info_bdstate, di.info_nports, di.info_physsize));
+
+		if (copy_to_user(uarg, &di, sizeof (di)))
+			return (-EFAULT);
+
+		break;
+	}
+
+	case DIGI_GET_NI_INFO:
+	{
+		struct channel_t *ch;
+		struct ni_info ni;
+		uchar mstat = 0;
+		uint board = 0;
+		uint channel = 0;
+
+		if (copy_from_user(&ni, uarg, sizeof(struct ni_info))) {
+			return(-EFAULT);
+		}
+
+		DPR_MGMT(("DIGI_GETBD asking about board: %d channel: %d\n",
+			ni.board, ni.channel));
+
+		board = ni.board;
+		channel = ni.channel;
+
+		/* Verify boundaries on board */
+		if ((board < 0) || (board > dgnc_NumBoards) || (dgnc_NumBoards == 0))
+			return (-ENODEV);
+
+		/* Verify boundaries on channel */
+		if ((channel < 0) || (channel > dgnc_Board[board]->nasync))
+			return (-ENODEV);
+
+		ch = dgnc_Board[board]->channels[channel];
+
+		if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+			return (-ENODEV);
+
+		memset(&ni, 0, sizeof(ni));
+		ni.board = board;
+		ni.channel = channel;
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		mstat = (ch->ch_mostat | ch->ch_mistat);
+
+		if (mstat & UART_MCR_DTR) {
+			ni.mstat |= TIOCM_DTR;
+			ni.dtr = TIOCM_DTR;
+		}
+		if (mstat & UART_MCR_RTS) {
+			ni.mstat |= TIOCM_RTS;
+			ni.rts = TIOCM_RTS;
+		}
+		if (mstat & UART_MSR_CTS) {
+			ni.mstat |= TIOCM_CTS;
+			ni.cts = TIOCM_CTS;
+		}
+		if (mstat & UART_MSR_RI) {
+			ni.mstat |= TIOCM_RI;
+			ni.ri = TIOCM_RI;
+		}
+		if (mstat & UART_MSR_DCD) {
+			ni.mstat |= TIOCM_CD;
+			ni.dcd = TIOCM_CD;
+		}
+		if (mstat & UART_MSR_DSR)
+			ni.mstat |= TIOCM_DSR;
+
+		ni.iflag = ch->ch_c_iflag;
+		ni.oflag = ch->ch_c_oflag;
+		ni.cflag = ch->ch_c_cflag;
+		ni.lflag = ch->ch_c_lflag;
+
+		if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS)
+			ni.hflow = 1;
+		else
+			ni.hflow = 0;
+
+		if ((ch->ch_flags & CH_STOPI) || (ch->ch_flags & CH_FORCED_STOPI))
+			ni.recv_stopped = 1;
+		else
+			ni.recv_stopped = 0;
+
+		if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP))
+			ni.xmit_stopped = 1;
+		else
+			ni.xmit_stopped = 0;
+
+		ni.curtx = ch->ch_txcount;
+		ni.currx = ch->ch_rxcount;
+
+		ni.baud = ch->ch_old_baud;
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		if (copy_to_user(uarg, &ni, sizeof(ni)))
+			return (-EFAULT);
+
+		break;
+	}
+
+
+	}
+
+	DPR_MGMT(("dgnc_mgmt_ioctl finish.\n"));
+
+	return 0;
+}
diff --git a/drivers/staging/dgnc/dgnc_mgmt.h b/drivers/staging/dgnc/dgnc_mgmt.h
new file mode 100644
index 0000000..567f687
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_mgmt.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_MGMT_H
+#define __DGNC_MGMT_H
+
+#define MAXMGMTDEVICES 8
+
+int dgnc_mgmt_open(struct inode *inode, struct file *file);
+int dgnc_mgmt_close(struct inode *inode, struct file *file);
+long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+
diff --git a/drivers/staging/dgnc/dgnc_neo.c b/drivers/staging/dgnc/dgnc_neo.c
new file mode 100644
index 0000000..8b9e09a
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_neo.c
@@ -0,0 +1,1974 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>    /* For tasklet and interrupt structs/defines */
+#include <linux/delay.h>	/* For udelay */
+#include <asm/io.h>		/* For read[bwl]/write[bwl] */
+#include <linux/serial.h>	/* For struct async_serial */
+#include <linux/serial_reg.h>	/* For the various UART offsets */
+
+#include "dgnc_driver.h"	/* Driver main header file */
+#include "dgnc_neo.h"		/* Our header file */
+#include "dgnc_tty.h"
+#include "dgnc_trace.h"
+
+static inline void neo_parse_lsr(struct board_t *brd, uint port);
+static inline void neo_parse_isr(struct board_t *brd, uint port);
+static void neo_copy_data_from_uart_to_queue(struct channel_t *ch);
+static inline void neo_clear_break(struct channel_t *ch, int force);
+static inline void neo_set_cts_flow_control(struct channel_t *ch);
+static inline void neo_set_rts_flow_control(struct channel_t *ch);
+static inline void neo_set_ixon_flow_control(struct channel_t *ch);
+static inline void neo_set_ixoff_flow_control(struct channel_t *ch);
+static inline void neo_set_no_output_flow_control(struct channel_t *ch);
+static inline void neo_set_no_input_flow_control(struct channel_t *ch);
+static inline void neo_set_new_start_stop_chars(struct channel_t *ch);
+static void neo_parse_modem(struct channel_t *ch, uchar signals);
+static void neo_tasklet(unsigned long data);
+static void neo_vpd(struct board_t *brd);
+static void neo_uart_init(struct channel_t *ch);
+static void neo_uart_off(struct channel_t *ch);
+static int neo_drain(struct tty_struct *tty, uint seconds);
+static void neo_param(struct tty_struct *tty);
+static void neo_assert_modem_signals(struct channel_t *ch);
+static void neo_flush_uart_write(struct channel_t *ch);
+static void neo_flush_uart_read(struct channel_t *ch);
+static void neo_disable_receiver(struct channel_t *ch);
+static void neo_enable_receiver(struct channel_t *ch);
+static void neo_send_break(struct channel_t *ch, int msecs);
+static void neo_send_start_character(struct channel_t *ch);
+static void neo_send_stop_character(struct channel_t *ch);
+static void neo_copy_data_from_queue_to_uart(struct channel_t *ch);
+static uint neo_get_uart_bytes_left(struct channel_t *ch);
+static void neo_send_immediate_char(struct channel_t *ch, unsigned char c);
+static irqreturn_t neo_intr(int irq, void *voidbrd);
+
+
+struct board_ops dgnc_neo_ops = {
+	.tasklet =			neo_tasklet,
+	.intr =				neo_intr,
+	.uart_init =			neo_uart_init,
+	.uart_off =			neo_uart_off,
+	.drain =			neo_drain,
+	.param =			neo_param,
+	.vpd =				neo_vpd,
+	.assert_modem_signals =		neo_assert_modem_signals,
+	.flush_uart_write =		neo_flush_uart_write,
+	.flush_uart_read =		neo_flush_uart_read,
+	.disable_receiver =		neo_disable_receiver,
+	.enable_receiver =		neo_enable_receiver,
+	.send_break =			neo_send_break,
+	.send_start_character =		neo_send_start_character,
+	.send_stop_character =		neo_send_stop_character,
+	.copy_data_from_queue_to_uart =	neo_copy_data_from_queue_to_uart,
+	.get_uart_bytes_left =		neo_get_uart_bytes_left,
+	.send_immediate_char =		neo_send_immediate_char
+};
+
+static uint dgnc_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+
+
+/*
+ * This function allows calls to ensure that all outstanding
+ * PCI writes have been completed, by doing a PCI read against
+ * a non-destructive, read-only location on the Neo card.
+ *
+ * In this case, we are reading the DVID (Read-only Device Identification)
+ * value of the Neo card.
+ */
+static inline void neo_pci_posting_flush(struct board_t *bd)
+{
+	readb(bd->re_map_membase + 0x8D);
+}
+
+static inline void neo_set_cts_flow_control(struct channel_t *ch)
+{
+	uchar ier = readb(&ch->ch_neo_uart->ier);
+	uchar efr = readb(&ch->ch_neo_uart->efr);
+
+
+	DPR_PARAM(("Setting CTSFLOW\n"));
+
+	/* Turn on auto CTS flow control */
+#if 1
+	ier |= (UART_17158_IER_CTSDSR);
+#else
+	ier &= ~(UART_17158_IER_CTSDSR);
+#endif
+
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR);
+
+	/* Turn off auto Xon flow control */
+	efr &= ~(UART_17158_EFR_IXON);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+
+	/* Feed the UART our trigger levels */
+	writeb(8, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 8;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_rts_flow_control(struct channel_t *ch)
+{
+	uchar ier = readb(&ch->ch_neo_uart->ier);
+	uchar efr = readb(&ch->ch_neo_uart->efr);
+
+	DPR_PARAM(("Setting RTSFLOW\n"));
+
+	/* Turn on auto RTS flow control */
+#if 1
+	ier |= (UART_17158_IER_RTSDTR);
+#else
+	ier &= ~(UART_17158_IER_RTSDTR);
+#endif
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR);
+
+	/* Turn off auto Xoff flow control */
+	ier &= ~(UART_17158_IER_XOFF);
+	efr &= ~(UART_17158_EFR_IXOFF);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr);
+	ch->ch_r_watermark = 4;
+
+	writeb(32, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 32;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	/*
+	 * From the Neo UART spec sheet:
+	 * The auto RTS/DTR function must be started by asserting
+	 * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after
+	 * it is enabled.
+	 */
+	ch->ch_mostat |= (UART_MCR_RTS);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_ixon_flow_control(struct channel_t *ch)
+{
+	uchar ier = readb(&ch->ch_neo_uart->ier);
+	uchar efr = readb(&ch->ch_neo_uart->efr);
+
+	DPR_PARAM(("Setting IXON FLOW\n"));
+
+	/* Turn off auto CTS flow control */
+	ier &= ~(UART_17158_IER_CTSDSR);
+	efr &= ~(UART_17158_EFR_CTSDSR);
+
+	/* Turn on auto Xon flow control */
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+	ch->ch_r_watermark = 4;
+
+	writeb(32, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 32;
+
+	/* Tell UART what start/stop chars it should be looking for */
+	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+	writeb(0, &ch->ch_neo_uart->xonchar2);
+
+	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+	writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_ixoff_flow_control(struct channel_t *ch)
+{
+	uchar ier = readb(&ch->ch_neo_uart->ier);
+	uchar efr = readb(&ch->ch_neo_uart->efr);
+
+	DPR_PARAM(("Setting IXOFF FLOW\n"));
+
+	/* Turn off auto RTS flow control */
+	ier &= ~(UART_17158_IER_RTSDTR);
+	efr &= ~(UART_17158_EFR_RTSDTR);
+
+	/* Turn on auto Xoff flow control */
+	ier |= (UART_17158_IER_XOFF);
+	efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+	writeb(8, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 8;
+
+	/* Tell UART what start/stop chars it should be looking for */
+	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+	writeb(0, &ch->ch_neo_uart->xonchar2);
+
+	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+	writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_no_input_flow_control(struct channel_t *ch)
+{
+	uchar ier = readb(&ch->ch_neo_uart->ier);
+	uchar efr = readb(&ch->ch_neo_uart->efr);
+
+	DPR_PARAM(("Unsetting Input FLOW\n"));
+
+	/* Turn off auto RTS flow control */
+	ier &= ~(UART_17158_IER_RTSDTR);
+	efr &= ~(UART_17158_EFR_RTSDTR);
+
+	/* Turn off auto Xoff flow control */
+	ier &= ~(UART_17158_IER_XOFF);
+	if (ch->ch_c_iflag & IXON)
+		efr &= ~(UART_17158_EFR_IXOFF);
+	else
+		efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF);
+
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+	ch->ch_r_watermark = 0;
+
+	writeb(16, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 16;
+
+	writeb(16, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 16;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static inline void neo_set_no_output_flow_control(struct channel_t *ch)
+{
+	uchar ier = readb(&ch->ch_neo_uart->ier);
+	uchar efr = readb(&ch->ch_neo_uart->efr);
+
+	DPR_PARAM(("Unsetting Output FLOW\n"));
+
+	/* Turn off auto CTS flow control */
+	ier &= ~(UART_17158_IER_CTSDSR);
+	efr &= ~(UART_17158_EFR_CTSDSR);
+
+	/* Turn off auto Xon flow control */
+	if (ch->ch_c_iflag & IXOFF)
+		efr &= ~(UART_17158_EFR_IXON);
+	else
+		efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON);
+
+	/* Why? Becuz Exar's spec says we have to zero it out before setting it */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Turn on UART enhanced bits */
+	writeb(efr, &ch->ch_neo_uart->efr);
+
+	/* Turn on table D, with 8 char hi/low watermarks */
+	writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr);
+
+	ch->ch_r_watermark = 0;
+
+	writeb(16, &ch->ch_neo_uart->tfifo);
+	ch->ch_t_tlevel = 16;
+
+	writeb(16, &ch->ch_neo_uart->rfifo);
+	ch->ch_r_tlevel = 16;
+
+	writeb(ier, &ch->ch_neo_uart->ier);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/* change UARTs start/stop chars */
+static inline void neo_set_new_start_stop_chars(struct channel_t *ch)
+{
+
+	/* if hardware flow control is set, then skip this whole thing */
+	if (ch->ch_digi.digi_flags & (CTSPACE | RTSPACE) || ch->ch_c_cflag & CRTSCTS)
+		return;
+
+	DPR_PARAM(("In new start stop chars\n"));
+
+	/* Tell UART what start/stop chars it should be looking for */
+	writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1);
+	writeb(0, &ch->ch_neo_uart->xonchar2);
+
+	writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1);
+	writeb(0, &ch->ch_neo_uart->xoffchar2);
+
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * No locks are assumed to be held when calling this function.
+ */
+static inline void neo_clear_break(struct channel_t *ch, int force)
+{
+	ulong lock_flags;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* Bail if we aren't currently sending a break. */
+	if (!ch->ch_stop_sending_break) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/* Turn break off, and unset some variables */
+	if (ch->ch_flags & CH_BREAK_SENDING) {
+		if ((jiffies >= ch->ch_stop_sending_break) || force) {
+			uchar temp = readb(&ch->ch_neo_uart->lcr);
+			writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+			neo_pci_posting_flush(ch->ch_bd);
+			ch->ch_flags &= ~(CH_BREAK_SENDING);
+			ch->ch_stop_sending_break = 0;
+			DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+		}
+	}
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/*
+ * Parse the ISR register.
+ */
+static inline void neo_parse_isr(struct board_t *brd, uint port)
+{
+	struct channel_t *ch;
+	uchar isr;
+	uchar cause;
+	ulong lock_flags;
+
+	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	if (port > brd->maxports)
+		return;
+
+	ch = brd->channels[port];
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	/* Here we try to figure out what caused the interrupt to happen */
+	while (1) {
+
+		isr = readb(&ch->ch_neo_uart->isr_fcr);
+
+		/* Bail if no pending interrupt */
+		if (isr & UART_IIR_NO_INT)  {
+			break;
+		}
+
+		/*
+		 * Yank off the upper 2 bits, which just show that the FIFO's are enabled.
+		 */
+		isr &= ~(UART_17158_IIR_FIFO_ENABLED);
+
+		DPR_INTR(("%s:%d isr: %x\n", __FILE__, __LINE__, isr));
+
+		if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) {
+			/* Read data from uart -> queue */
+			brd->intr_rx++;
+			ch->ch_intr_rx++;
+			neo_copy_data_from_uart_to_queue(ch);
+
+			/* Call our tty layer to enforce queue flow control if needed. */
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+			dgnc_check_queue_flow_control(ch);
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		}
+
+		if (isr & UART_IIR_THRI) {
+			brd->intr_tx++;
+			ch->ch_intr_tx++;
+			/* Transfer data (if any) from Write Queue -> UART. */
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			neo_copy_data_from_queue_to_uart(ch);
+		}
+
+		if (isr & UART_17158_IIR_XONXOFF) {
+			cause = readb(&ch->ch_neo_uart->xoffchar1);
+
+			DPR_INTR(("Port %d. Got ISR_XONXOFF: cause:%x\n", port, cause));
+
+			/*
+			 * Since the UART detected either an XON or
+			 * XOFF match, we need to figure out which
+			 * one it was, so we can suspend or resume data flow.
+			 */
+			if (cause == UART_17158_XON_DETECT) {
+				/* Is output stopped right now, if so, resume it */
+				if (brd->channels[port]->ch_flags & CH_STOP) {
+					DGNC_LOCK(ch->ch_lock, lock_flags);
+					ch->ch_flags &= ~(CH_STOP);
+					DGNC_UNLOCK(ch->ch_lock, lock_flags);
+				}
+				DPR_INTR(("Port %d. XON detected in incoming data\n", port));
+			}
+			else if (cause == UART_17158_XOFF_DETECT) {
+				if (!(brd->channels[port]->ch_flags & CH_STOP)) {
+					DGNC_LOCK(ch->ch_lock, lock_flags);
+					ch->ch_flags |= CH_STOP;
+					DGNC_UNLOCK(ch->ch_lock, lock_flags);
+					DPR_INTR(("Setting CH_STOP\n"));
+				}
+				DPR_INTR(("Port: %d. XOFF detected in incoming data\n", port));
+			}
+		}
+
+		if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) {
+			/*
+			 * If we get here, this means the hardware is doing auto flow control.
+			 * Check to see whether RTS/DTR or CTS/DSR caused this interrupt.
+			 */
+			brd->intr_modem++;
+			ch->ch_intr_modem++;
+			cause = readb(&ch->ch_neo_uart->mcr);
+			/* Which pin is doing auto flow? RTS or DTR? */
+			if ((cause & 0x4) == 0) {
+				if (cause & UART_MCR_RTS) {
+					DGNC_LOCK(ch->ch_lock, lock_flags);
+					ch->ch_mostat |= UART_MCR_RTS;
+					DGNC_UNLOCK(ch->ch_lock, lock_flags);
+				}
+				else {
+					DGNC_LOCK(ch->ch_lock, lock_flags);
+					ch->ch_mostat &= ~(UART_MCR_RTS);
+					DGNC_UNLOCK(ch->ch_lock, lock_flags);
+				}
+			} else {
+				if (cause & UART_MCR_DTR) {
+					DGNC_LOCK(ch->ch_lock, lock_flags);
+					ch->ch_mostat |= UART_MCR_DTR;
+					DGNC_UNLOCK(ch->ch_lock, lock_flags);
+				}
+				else {
+					DGNC_LOCK(ch->ch_lock, lock_flags);
+					ch->ch_mostat &= ~(UART_MCR_DTR);
+					DGNC_UNLOCK(ch->ch_lock, lock_flags);
+				}
+			}
+		}
+
+		/* Parse any modem signal changes */
+		DPR_INTR(("MOD_STAT: sending to parse_modem_sigs\n"));
+		neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+	}
+}
+
+
+static inline void neo_parse_lsr(struct board_t *brd, uint port)
+{
+	struct channel_t *ch;
+	int linestatus;
+	ulong lock_flags;
+
+	if (!brd)
+		return;
+
+	if (brd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	if (port > brd->maxports)
+		return;
+
+	ch = brd->channels[port];
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	linestatus = readb(&ch->ch_neo_uart->lsr);
+
+	DPR_INTR(("%s:%d port: %d linestatus: %x\n", __FILE__, __LINE__, port, linestatus));
+
+	ch->ch_cached_lsr |= linestatus;
+
+	if (ch->ch_cached_lsr & UART_LSR_DR) {
+		brd->intr_rx++;
+		ch->ch_intr_rx++;
+		/* Read data from uart -> queue */
+		neo_copy_data_from_uart_to_queue(ch);
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+		dgnc_check_queue_flow_control(ch);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+	}
+
+	/*
+	 * This is a special flag. It indicates that at least 1
+	 * RX error (parity, framing, or break) has happened.
+	 * Mark this in our struct, which will tell me that I have
+	 *to do the special RX+LSR read for this FIFO load.
+	 */
+	if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) {
+		DPR_INTR(("%s:%d Port: %d Got an RX error, need to parse LSR\n",
+			__FILE__, __LINE__, port));
+	}
+
+	/*
+	 * The next 3 tests should *NOT* happen, as the above test
+	 * should encapsulate all 3... At least, thats what Exar says.
+	 */
+
+	if (linestatus & UART_LSR_PE) {
+		ch->ch_err_parity++;
+		DPR_INTR(("%s:%d Port: %d. PAR ERR!\n", __FILE__, __LINE__, port));
+	}
+
+	if (linestatus & UART_LSR_FE) {
+		ch->ch_err_frame++;
+		DPR_INTR(("%s:%d Port: %d. FRM ERR!\n", __FILE__, __LINE__, port));
+	}
+
+	if (linestatus & UART_LSR_BI) {
+		ch->ch_err_break++;
+		DPR_INTR(("%s:%d Port: %d. BRK INTR!\n", __FILE__, __LINE__, port));
+	}
+
+	if (linestatus & UART_LSR_OE) {
+		/*
+		 * Rx Oruns. Exar says that an orun will NOT corrupt
+		 * the FIFO. It will just replace the holding register
+		 * with this new data byte. So basically just ignore this.
+		 * Probably we should eventually have an orun stat in our driver...
+		 */
+		ch->ch_err_overrun++;
+		DPR_INTR(("%s:%d Port: %d. Rx Overrun!\n", __FILE__, __LINE__, port));
+	}
+
+	if (linestatus & UART_LSR_THRE) {
+		brd->intr_tx++;
+		ch->ch_intr_tx++;
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		/* Transfer data (if any) from Write Queue -> UART. */
+		neo_copy_data_from_queue_to_uart(ch);
+	}
+	else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
+		brd->intr_tx++;
+		ch->ch_intr_tx++;
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		/* Transfer data (if any) from Write Queue -> UART. */
+		neo_copy_data_from_queue_to_uart(ch);
+	}
+}
+
+
+/*
+ * neo_param()
+ * Send any/all changes to the line to the UART.
+ */
+static void neo_param(struct tty_struct *tty)
+{
+	uchar lcr = 0;
+	uchar uart_lcr = 0;
+	uchar ier = 0;
+	uchar uart_ier = 0;
+	uint baud = 9600;
+	int quot = 0;
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t   *un;
+
+	if (!tty || tty->magic != TTY_MAGIC) {
+		return;
+	}
+
+	un = (struct un_t *) tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC) {
+		return;
+	}
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return;
+	}
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+		return;
+	}
+
+	DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n",
+		ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag));
+
+	/*
+	 * If baud rate is zero, flush queues, and set mval to drop DTR.
+	 */
+	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
+		ch->ch_r_head = ch->ch_r_tail = 0;
+		ch->ch_e_head = ch->ch_e_tail = 0;
+		ch->ch_w_head = ch->ch_w_tail = 0;
+
+		neo_flush_uart_write(ch);
+		neo_flush_uart_read(ch);
+
+		/* The baudrate is B0 so all modem lines are to be dropped. */
+		ch->ch_flags |= (CH_BAUD0);
+		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
+		neo_assert_modem_signals(ch);
+		ch->ch_old_baud = 0;
+		return;
+
+	} else if (ch->ch_custom_speed) {
+
+		baud = ch->ch_custom_speed;
+		/* Handle transition from B0 */
+		if (ch->ch_flags & CH_BAUD0) {
+			ch->ch_flags &= ~(CH_BAUD0);
+
+			/*
+			 * Bring back up RTS and DTR...
+			 * Also handle RTS or DTR toggle if set.
+			 */
+			if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_RTS);
+			if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_DTR);
+		}
+	} else {
+		int iindex = 0;
+		int jindex = 0;
+
+		ulong bauds[4][16] = {
+			{ /* slowbaud */
+				0,      50,     75,     110,
+				134,    150,    200,    300,
+				600,    1200,   1800,   2400,
+				4800,   9600,   19200,  38400 },
+			{ /* slowbaud & CBAUDEX */
+				0,      57600,  115200, 230400,
+				460800, 150,    200,    921600,
+				600,    1200,   1800,   2400,
+				4800,   9600,   19200,  38400 },
+			{ /* fastbaud */
+				0,      57600,   76800, 115200,
+				131657, 153600, 230400, 460800,
+				921600, 1200,   1800,   2400,
+				4800,   9600,   19200,  38400 },
+			{ /* fastbaud & CBAUDEX */
+				0,      57600,  115200, 230400,
+				460800, 150,    200,    921600,
+				600,    1200,   1800,   2400,
+				4800,   9600,   19200,  38400 }
+		};
+
+		/* Only use the TXPrint baud rate if the terminal unit is NOT open */
+		if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGNC_PRINT))
+			baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
+		else
+			baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
+
+		if (ch->ch_c_cflag & CBAUDEX)
+			iindex = 1;
+
+		if (ch->ch_digi.digi_flags & DIGI_FAST)
+			iindex += 2;
+
+		jindex = baud;
+
+		if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) {
+			baud = bauds[iindex][jindex];
+		} else {
+			DPR_IOCTL(("baud indices were out of range (%d)(%d)",
+				iindex, jindex));
+			baud = 0;
+		}
+
+		if (baud == 0)
+			baud = 9600;
+
+		/* Handle transition from B0 */
+		if (ch->ch_flags & CH_BAUD0) {
+			ch->ch_flags &= ~(CH_BAUD0);
+
+			/*
+			 * Bring back up RTS and DTR...
+			 * Also handle RTS or DTR toggle if set.
+			 */
+			if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_RTS);
+			if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+				ch->ch_mostat |= (UART_MCR_DTR);
+		}
+	}
+
+	if (ch->ch_c_cflag & PARENB) {
+		lcr |= UART_LCR_PARITY;
+	}
+
+	if (!(ch->ch_c_cflag & PARODD)) {
+		lcr |= UART_LCR_EPAR;
+	}
+
+	/*
+	 * Not all platforms support mark/space parity,
+	 * so this will hide behind an ifdef.
+	 */
+#ifdef CMSPAR
+	if (ch->ch_c_cflag & CMSPAR)
+		lcr |= UART_LCR_SPAR;
+#endif
+
+	if (ch->ch_c_cflag & CSTOPB)
+		lcr |= UART_LCR_STOP;
+
+	switch (ch->ch_c_cflag & CSIZE) {
+	case CS5:
+		lcr |= UART_LCR_WLEN5;
+		break;
+	case CS6:
+		lcr |= UART_LCR_WLEN6;
+		break;
+	case CS7:
+		lcr |= UART_LCR_WLEN7;
+		break;
+	case CS8:
+	default:
+		lcr |= UART_LCR_WLEN8;
+		break;
+	}
+
+	ier = uart_ier = readb(&ch->ch_neo_uart->ier);
+	uart_lcr = readb(&ch->ch_neo_uart->lcr);
+
+	if (baud == 0)
+		baud = 9600;
+
+	quot = ch->ch_bd->bd_dividend / baud;
+
+	if (quot != 0 && ch->ch_old_baud != baud) {
+		ch->ch_old_baud = baud;
+		writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr);
+		writeb((quot & 0xff), &ch->ch_neo_uart->txrx);
+		writeb((quot >> 8), &ch->ch_neo_uart->ier);
+		writeb(lcr, &ch->ch_neo_uart->lcr);
+	}
+
+	if (uart_lcr != lcr)
+		writeb(lcr, &ch->ch_neo_uart->lcr);
+
+	if (ch->ch_c_cflag & CREAD) {
+		ier |= (UART_IER_RDI | UART_IER_RLSI);
+	}
+	else {
+		ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+	}
+
+	/*
+	 * Have the UART interrupt on modem signal changes ONLY when
+	 * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
+	 */
+	if ((ch->ch_digi.digi_flags & CTSPACE) || (ch->ch_digi.digi_flags & RTSPACE) ||
+		(ch->ch_c_cflag & CRTSCTS) || !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
+		!(ch->ch_c_cflag & CLOCAL))
+	{
+		ier |= UART_IER_MSI;
+	}
+	else {
+		ier &= ~UART_IER_MSI;
+	}
+
+	ier |= UART_IER_THRI;
+
+	if (ier != uart_ier)
+		writeb(ier, &ch->ch_neo_uart->ier);
+
+	/* Set new start/stop chars */
+	neo_set_new_start_stop_chars(ch);
+
+	if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
+		neo_set_cts_flow_control(ch);
+	}
+	else if (ch->ch_c_iflag & IXON) {
+		/* If start/stop is set to disable, then we should disable flow control */
+		if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+			neo_set_no_output_flow_control(ch);
+		else
+			neo_set_ixon_flow_control(ch);
+	}
+	else {
+		neo_set_no_output_flow_control(ch);
+	}
+
+	if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
+		neo_set_rts_flow_control(ch);
+	}
+	else if (ch->ch_c_iflag & IXOFF) {
+		/* If start/stop is set to disable, then we should disable flow control */
+		if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE))
+			neo_set_no_input_flow_control(ch);
+		else
+			neo_set_ixoff_flow_control(ch);
+	}
+	else {
+		neo_set_no_input_flow_control(ch);
+	}
+
+	/*
+	 * Adjust the RX FIFO Trigger level if baud is less than 9600.
+	 * Not exactly elegant, but this is needed because of the Exar chip's
+	 * delay on firing off the RX FIFO interrupt on slower baud rates.
+	 */
+	if (baud < 9600) {
+		writeb(1, &ch->ch_neo_uart->rfifo);
+		ch->ch_r_tlevel = 1;
+	}
+
+	neo_assert_modem_signals(ch);
+
+	/* Get current status of the modem signals now */
+	neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
+}
+
+
+/*
+ * Our board poller function.
+ */
+static void neo_tasklet(unsigned long data)
+{
+	struct board_t *bd = (struct board_t *) data;
+	struct channel_t *ch;
+	ulong  lock_flags;
+	int i;
+	int state = 0;
+	int ports = 0;
+
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC) {
+		APR(("poll_tasklet() - NULL or bad bd.\n"));
+		return;
+	}
+
+	/* Cache a couple board values */
+	DGNC_LOCK(bd->bd_lock, lock_flags);
+	state = bd->state;
+	ports = bd->nasync;
+	DGNC_UNLOCK(bd->bd_lock, lock_flags);
+
+	/*
+	 * Do NOT allow the interrupt routine to read the intr registers
+	 * Until we release this lock.
+	 */
+	DGNC_LOCK(bd->bd_intr_lock, lock_flags);
+
+	/*
+	 * If board is ready, parse deeper to see if there is anything to do.
+	 */
+	if ((state == BOARD_READY) && (ports > 0)) {
+		/* Loop on each port */
+		for (i = 0; i < ports; i++) {
+			ch = bd->channels[i];
+
+			/* Just being careful... */
+			if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+				continue;
+
+			/*
+			 * NOTE: Remember you CANNOT hold any channel
+			 * locks when calling the input routine.
+			 *
+			 * During input processing, its possible we
+			 * will call the Linux ld, which might in turn,
+			 * do a callback right back into us, resulting
+			 * in us trying to grab the channel lock twice!
+			 */
+			dgnc_input(ch);
+
+			/*
+			 * Channel lock is grabbed and then released
+			 * inside both of these routines, but neither
+			 * call anything else that could call back into us.
+			 */
+			neo_copy_data_from_queue_to_uart(ch);
+			dgnc_wakeup_writes(ch);
+
+			/*
+			 * Call carrier carrier function, in case something
+			 * has changed.
+			 */
+			dgnc_carrier(ch);
+
+			/*
+			 * Check to see if we need to turn off a sending break.
+			 * The timing check is done inside clear_break()
+			 */
+			if (ch->ch_stop_sending_break)
+				neo_clear_break(ch, 0);
+		}
+	}
+
+	/* Allow interrupt routine to access the interrupt register again */
+	DGNC_UNLOCK(bd->bd_intr_lock, lock_flags);
+
+}
+
+
+/*
+ * dgnc_neo_intr()
+ *
+ * Neo specific interrupt handler.
+ */
+static irqreturn_t neo_intr(int irq, void *voidbrd)
+{
+	struct board_t *brd = (struct board_t *) voidbrd;
+	struct channel_t *ch;
+	int port = 0;
+	int type = 0;
+	int current_port;
+	u32 tmp;
+	u32 uart_poll;
+	unsigned long lock_flags;
+	unsigned long lock_flags2;
+
+	if (!brd) {
+		APR(("Received interrupt (%d) with null board associated\n", irq));
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Check to make sure its for us.
+	 */
+	if (brd->magic != DGNC_BOARD_MAGIC) {
+		APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq));
+		return IRQ_NONE;
+	}
+
+	brd->intr_count++;
+
+	/* Lock out the slow poller from running on this board. */
+	DGNC_LOCK(brd->bd_intr_lock, lock_flags);
+
+	/*
+	 * Read in "extended" IRQ information from the 32bit Neo register.
+	 * Bits 0-7: What port triggered the interrupt.
+	 * Bits 8-31: Each 3bits indicate what type of interrupt occurred.
+	 */
+	uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET);
+
+	DPR_INTR(("%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll));
+
+	/*
+	 * If 0, no interrupts pending.
+	 * This can happen if the IRQ is shared among a couple Neo/Classic boards.
+	 */
+	if (!uart_poll) {
+		DPR_INTR(("Kernel interrupted to me, but no pending interrupts...\n"));
+		DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+		return IRQ_NONE;
+	}
+
+	/* At this point, we have at least SOMETHING to service, dig further... */
+
+	current_port = 0;
+
+	/* Loop on each port */
+	while ((uart_poll & 0xff) != 0) {
+
+		tmp = uart_poll;
+
+		/* Check current port to see if it has interrupt pending */
+		if ((tmp & dgnc_offset_table[current_port]) != 0) {
+			port = current_port;
+			type = tmp >> (8 + (port * 3));
+			type &= 0x7;
+		} else {
+			current_port++;
+			continue;
+		}
+
+		DPR_INTR(("%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type));
+
+		/* Remove this port + type from uart_poll */
+		uart_poll &= ~(dgnc_offset_table[port]);
+
+		if (!type) {
+			/* If no type, just ignore it, and move onto next port */
+			DPR_INTR(("Interrupt with no type! port: %d\n", port));
+			continue;
+		}
+
+		/* Switch on type of interrupt we have */
+		switch (type) {
+
+		case UART_17158_RXRDY_TIMEOUT:
+			/*
+			 * RXRDY Time-out is cleared by reading data in the
+			 * RX FIFO until it falls below the trigger level.
+			 */
+
+			/* Verify the port is in range. */
+			if (port > brd->nasync)
+				continue;
+
+			ch = brd->channels[port];
+			neo_copy_data_from_uart_to_queue(ch);
+
+			/* Call our tty layer to enforce queue flow control if needed. */
+			DGNC_LOCK(ch->ch_lock, lock_flags2);
+			dgnc_check_queue_flow_control(ch);
+			DGNC_UNLOCK(ch->ch_lock, lock_flags2);
+
+			continue;
+
+		case UART_17158_RX_LINE_STATUS:
+			/*
+			 * RXRDY and RX LINE Status (logic OR of LSR[4:1])
+			 */
+			neo_parse_lsr(brd, port);
+			continue;
+
+		case UART_17158_TXRDY:
+			/*
+			 * TXRDY interrupt clears after reading ISR register for the UART channel.
+			 */
+
+			/*
+			 * Yes, this is odd...
+			 * Why would I check EVERY possibility of type of
+			 * interrupt, when we know its TXRDY???
+			 * Becuz for some reason, even tho we got triggered for TXRDY,
+			 * it seems to be occassionally wrong. Instead of TX, which
+			 * it should be, I was getting things like RXDY too. Weird.
+			 */
+			neo_parse_isr(brd, port);
+			continue;
+
+		case UART_17158_MSR:
+			/*
+			 * MSR or flow control was seen.
+			 */
+			neo_parse_isr(brd, port);
+			continue;
+
+		default:
+			/*
+			 * The UART triggered us with a bogus interrupt type.
+			 * It appears the Exar chip, when REALLY bogged down, will throw
+			 * these once and awhile.
+			 * Its harmless, just ignore it and move on.
+			 */
+			DPR_INTR(("%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type));
+			continue;
+		}
+	}
+
+	/*
+	 * Schedule tasklet to more in-depth servicing at a better time.
+	 */
+	tasklet_schedule(&brd->helper_tasklet);
+
+	DGNC_UNLOCK(brd->bd_intr_lock, lock_flags);
+
+	DPR_INTR(("dgnc_intr finish.\n"));
+	return IRQ_HANDLED;
+}
+
+
+/*
+ * Neo specific way of turning off the receiver.
+ * Used as a way to enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_disable_receiver(struct channel_t *ch)
+{
+	uchar tmp = readb(&ch->ch_neo_uart->ier);
+	tmp &= ~(UART_IER_RDI);
+	writeb(tmp, &ch->ch_neo_uart->ier);
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Neo specific way of turning on the receiver.
+ * Used as a way to un-enforce queue flow control when in
+ * hardware flow control mode.
+ */
+static void neo_enable_receiver(struct channel_t *ch)
+{
+	uchar tmp = readb(&ch->ch_neo_uart->ier);
+	tmp |= (UART_IER_RDI);
+	writeb(tmp, &ch->ch_neo_uart->ier);
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
+{
+	int qleft = 0;
+	uchar linestatus = 0;
+	uchar error_mask = 0;
+	int n = 0;
+	int total = 0;
+	ushort head;
+	ushort tail;
+	ulong lock_flags;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* cache head and tail of queue */
+	head = ch->ch_r_head & RQUEUEMASK;
+	tail = ch->ch_r_tail & RQUEUEMASK;
+
+	/* Get our cached LSR */
+	linestatus = ch->ch_cached_lsr;
+	ch->ch_cached_lsr = 0;
+
+	/* Store how much space we have left in the queue */
+	if ((qleft = tail - head - 1) < 0)
+		qleft += RQUEUEMASK + 1;
+
+	/*
+	 * If the UART is not in FIFO mode, force the FIFO copy to
+	 * NOT be run, by setting total to 0.
+	 *
+	 * On the other hand, if the UART IS in FIFO mode, then ask
+	 * the UART to give us an approximation of data it has RX'ed.
+	 */
+	if (!(ch->ch_flags & CH_FIFO_ENABLED))
+		total = 0;
+	else {
+		total = readb(&ch->ch_neo_uart->rfifo);
+
+		/*
+		 * EXAR chip bug - RX FIFO COUNT - Fudge factor.
+		 *
+		 * This resolves a problem/bug with the Exar chip that sometimes
+		 * returns a bogus value in the rfifo register.
+		 * The count can be any where from 0-3 bytes "off".
+		 * Bizarre, but true.
+		 */
+		if ((ch->ch_bd->dvid & 0xf0) >= UART_XR17E158_DVID) {
+			total -= 1;
+		}
+		else {
+			total -= 3;
+		}
+	}
+
+
+	/*
+	 * Finally, bound the copy to make sure we don't overflow
+	 * our own queue...
+	 * The byte by byte copy loop below this loop this will
+	 * deal with the queue overflow possibility.
+	 */
+	total = min(total, qleft);
+
+	while (total > 0) {
+
+		/*
+		 * Grab the linestatus register, we need to check
+		 * to see if there are any errors in the FIFO.
+		 */
+		linestatus = readb(&ch->ch_neo_uart->lsr);
+
+		/*
+		 * Break out if there is a FIFO error somewhere.
+		 * This will allow us to go byte by byte down below,
+		 * finding the exact location of the error.
+		 */
+		if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
+			break;
+
+		/* Make sure we don't go over the end of our queue */
+		n = min(((uint) total), (RQUEUESIZE - (uint) head));
+
+		/*
+		 * Cut down n even further if needed, this is to fix
+		 * a problem with memcpy_fromio() with the Neo on the
+		 * IBM pSeries platform.
+		 * 15 bytes max appears to be the magic number.
+		 */
+		n = min((uint) n, (uint) 12);
+
+		/*
+		 * Since we are grabbing the linestatus register, which
+		 * will reset some bits after our read, we need to ensure
+		 * we don't miss our TX FIFO emptys.
+		 */
+		if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		}
+
+		linestatus = 0;
+
+		/* Copy data from uart to the queue */
+		memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n);
+		dgnc_sniff_nowait_nolock(ch, "UART READ", ch->ch_rqueue + head, n);
+
+		/*
+		 * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed
+		 * that all the data currently in the FIFO is free of
+		 * breaks and parity/frame/orun errors.
+		 */
+		memset(ch->ch_equeue + head, 0, n);
+
+		/* Add to and flip head if needed */
+		head = (head + n) & RQUEUEMASK;
+		total -= n;
+		qleft -= n;
+		ch->ch_rxcount += n;
+	}
+
+	/*
+	 * Create a mask to determine whether we should
+	 * insert the character (if any) into our queue.
+	 */
+	if (ch->ch_c_iflag & IGNBRK)
+		error_mask |= UART_LSR_BI;
+
+	/*
+	 * Now cleanup any leftover bytes still in the UART.
+	 * Also deal with any possible queue overflow here as well.
+	 */
+	while (1) {
+
+		/*
+		 * Its possible we have a linestatus from the loop above
+		 * this, so we "OR" on any extra bits.
+		 */
+		linestatus |= readb(&ch->ch_neo_uart->lsr);
+
+		/*
+		 * If the chip tells us there is no more data pending to
+		 * be read, we can then leave.
+		 * But before we do, cache the linestatus, just in case.
+		 */
+		if (!(linestatus & UART_LSR_DR)) {
+			ch->ch_cached_lsr = linestatus;
+			break;
+		}
+
+		/* No need to store this bit */
+		linestatus &= ~UART_LSR_DR;
+
+		/*
+		 * Since we are grabbing the linestatus register, which
+		 * will reset some bits after our read, we need to ensure
+		 * we don't miss our TX FIFO emptys.
+		 */
+		if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) {
+			linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR);
+			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		}
+
+		/*
+		 * Discard character if we are ignoring the error mask.
+		 */
+		if (linestatus & error_mask)  {
+			uchar discard;
+			linestatus = 0;
+			memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1);
+			continue;
+		}
+
+		/*
+		 * If our queue is full, we have no choice but to drop some data.
+		 * The assumption is that HWFLOW or SWFLOW should have stopped
+		 * things way way before we got to this point.
+		 *
+		 * I decided that I wanted to ditch the oldest data first,
+		 * I hope thats okay with everyone? Yes? Good.
+		 */
+		while (qleft < 1) {
+			DPR_READ(("Queue full, dropping DATA:%x LSR:%x\n",
+				ch->ch_rqueue[tail], ch->ch_equeue[tail]));
+
+			ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK;
+			ch->ch_err_overrun++;
+			qleft++;
+		}
+
+		memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1);
+		ch->ch_equeue[head] = (uchar) linestatus;
+		dgnc_sniff_nowait_nolock(ch, "UART READ", ch->ch_rqueue + head, 1);
+
+		DPR_READ(("DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]));
+
+		/* Ditch any remaining linestatus value. */
+		linestatus = 0;
+
+		/* Add to and flip head if needed */
+		head = (head + 1) & RQUEUEMASK;
+
+		qleft--;
+		ch->ch_rxcount++;
+	}
+
+	/*
+	 * Write new final heads to channel structure.
+	 */
+	ch->ch_r_head = head & RQUEUEMASK;
+	ch->ch_e_head = head & EQUEUEMASK;
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+/*
+ * This function basically goes to sleep for secs, or until
+ * it gets signalled that the port has fully drained.
+ */
+static int neo_drain(struct tty_struct *tty, uint seconds)
+{
+	ulong lock_flags;
+	struct channel_t *ch;
+	struct un_t *un;
+	int rc = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC) {
+		return (-ENXIO);
+	}
+
+	un = (struct un_t *) tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC) {
+		return (-ENXIO);
+	}
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return (-ENXIO);
+	}
+
+	DPR_IOCTL(("%d Drain wait started.\n", __LINE__));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+	un->un_flags |= UN_EMPTY;
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 * Go to sleep waiting for the tty layer to wake me back up when
+	 * the empty flag goes away.
+	 *
+	 * NOTE: TODO: Do something with time passed in.
+	 */
+	rc = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0));
+
+	/* If ret is non-zero, user ctrl-c'ed us */
+	if (rc) {
+		DPR_IOCTL(("%d Drain - User ctrl c'ed\n", __LINE__));
+	}
+	else {
+		DPR_IOCTL(("%d Drain wait finished.\n", __LINE__));
+	}
+
+	return (rc);
+}
+
+
+/*
+ * Flush the WRITE FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_write(struct channel_t *ch)
+{
+	uchar tmp = 0;
+	int i = 0;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return;
+	}
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+	neo_pci_posting_flush(ch->ch_bd);
+
+	for (i = 0; i < 10; i++) {
+
+		/* Check to see if the UART feels it completely flushed the FIFO. */
+		tmp = readb(&ch->ch_neo_uart->isr_fcr);
+		if (tmp & 4) {
+			DPR_IOCTL(("Still flushing TX UART... i: %d\n", i));
+			udelay(10);
+		}
+		else
+			break;
+	}
+
+	ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+}
+
+
+/*
+ * Flush the READ FIFO on the Neo.
+ *
+ * NOTE: Channel lock MUST be held before calling this function!
+ */
+static void neo_flush_uart_read(struct channel_t *ch)
+{
+	uchar tmp = 0;
+	int i = 0;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return;
+	}
+
+	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr);
+	neo_pci_posting_flush(ch->ch_bd);
+
+	for (i = 0; i < 10; i++) {
+
+		/* Check to see if the UART feels it completely flushed the FIFO. */
+		tmp = readb(&ch->ch_neo_uart->isr_fcr);
+		if (tmp & 2) {
+			DPR_IOCTL(("Still flushing RX UART... i: %d\n", i));
+			udelay(10);
+		}
+		else
+			break;
+	}
+}
+
+
+static void neo_copy_data_from_queue_to_uart(struct channel_t *ch)
+{
+	ushort head;
+	ushort tail;
+	int n;
+	int s;
+	int qlen;
+	uint len_written = 0;
+	ulong lock_flags;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* No data to write to the UART */
+	if (ch->ch_w_tail == ch->ch_w_head) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/* If port is "stopped", don't send any data to the UART */
+	if ((ch->ch_flags & CH_FORCED_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/*
+	 * If FIFOs are disabled. Send data directly to txrx register
+	 */
+	if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
+		uchar lsrbits = readb(&ch->ch_neo_uart->lsr);
+
+		/* Cache the LSR bits for later parsing */
+		ch->ch_cached_lsr |= lsrbits;
+		if (ch->ch_cached_lsr & UART_LSR_THRE) {
+			ch->ch_cached_lsr &= ~(UART_LSR_THRE);
+
+			/*
+			 * If RTS Toggle mode is on, turn on RTS now if not already set,
+			 * and make sure we get an event when the data transfer has completed.
+			 */
+			if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+				if (!(ch->ch_mostat & UART_MCR_RTS)) {
+					ch->ch_mostat |= (UART_MCR_RTS);
+					neo_assert_modem_signals(ch);
+				}
+				ch->ch_tun.un_flags |= (UN_EMPTY);
+			}
+			/*
+			 * If DTR Toggle mode is on, turn on DTR now if not already set,
+			 * and make sure we get an event when the data transfer has completed.
+			 */
+			if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+				if (!(ch->ch_mostat & UART_MCR_DTR)) {
+					ch->ch_mostat |= (UART_MCR_DTR);
+					neo_assert_modem_signals(ch);
+				}
+				ch->ch_tun.un_flags |= (UN_EMPTY);
+			}
+
+			writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx);
+			DPR_WRITE(("Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]));
+			ch->ch_w_tail++;
+			ch->ch_w_tail &= WQUEUEMASK;
+			ch->ch_txcount++;
+		}
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/*
+	 * We have to do it this way, because of the EXAR TXFIFO count bug.
+	 */
+	if ((ch->ch_bd->dvid & 0xf0) < UART_XR17E158_DVID) {
+		if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) {
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			return;
+		}
+
+		len_written = 0;
+
+		n = readb(&ch->ch_neo_uart->tfifo);
+
+		if ((unsigned int) n > ch->ch_t_tlevel) {
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			return;
+		}
+
+		n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
+	}
+	else {
+		n = UART_17158_TX_FIFOSIZE - readb(&ch->ch_neo_uart->tfifo);
+	}
+
+	/* cache head and tail of queue */
+	head = ch->ch_w_head & WQUEUEMASK;
+	tail = ch->ch_w_tail & WQUEUEMASK;
+	qlen = (head - tail) & WQUEUEMASK;
+
+	/* Find minimum of the FIFO space, versus queue length */
+	n = min(n, qlen);
+
+	while (n > 0) {
+
+		s = ((head >= tail) ? head : WQUEUESIZE) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		/*
+		 * If RTS Toggle mode is on, turn on RTS now if not already set,
+		 * and make sure we get an event when the data transfer has completed.
+		 */
+		if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+			if (!(ch->ch_mostat & UART_MCR_RTS)) {
+				ch->ch_mostat |= (UART_MCR_RTS);
+				neo_assert_modem_signals(ch);
+			}
+			ch->ch_tun.un_flags |= (UN_EMPTY);
+		}
+
+		/*
+		 * If DTR Toggle mode is on, turn on DTR now if not already set,
+		 * and make sure we get an event when the data transfer has completed.
+		 */
+		if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+			if (!(ch->ch_mostat & UART_MCR_DTR)) {
+				ch->ch_mostat |= (UART_MCR_DTR);
+				neo_assert_modem_signals(ch);
+			}
+			ch->ch_tun.un_flags |= (UN_EMPTY);
+		}
+
+		memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s);
+		dgnc_sniff_nowait_nolock(ch, "UART WRITE", ch->ch_wqueue + tail, s);
+
+		/* Add and flip queue if needed */
+		tail = (tail + s) & WQUEUEMASK;
+		n -= s;
+		ch->ch_txcount += s;
+		len_written += s;
+	}
+
+	/* Update the final tail */
+	ch->ch_w_tail = tail & WQUEUEMASK;
+
+	if (len_written > 0) {
+		neo_pci_posting_flush(ch->ch_bd);
+		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+	}
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+static void neo_parse_modem(struct channel_t *ch, uchar signals)
+{
+	volatile uchar msignals = signals;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DPR_MSIGS(("neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals));
+
+	/*
+	 * Do altpin switching. Altpin switches DCD and DSR.
+	 * This prolly breaks DSRPACE, so we should be more clever here.
+	 */
+	if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
+		uchar mswap = msignals;
+
+		if (mswap & UART_MSR_DDCD) {
+			msignals &= ~UART_MSR_DDCD;
+			msignals |= UART_MSR_DDSR;
+		}
+		if (mswap & UART_MSR_DDSR) {
+			msignals &= ~UART_MSR_DDSR;
+			msignals |= UART_MSR_DDCD;
+		}
+		if (mswap & UART_MSR_DCD) {
+			msignals &= ~UART_MSR_DCD;
+			msignals |= UART_MSR_DSR;
+		}
+		if (mswap & UART_MSR_DSR) {
+			msignals &= ~UART_MSR_DSR;
+			msignals |= UART_MSR_DCD;
+		}
+	}
+
+	/* Scrub off lower bits. They signify delta's, which I don't care about */
+	msignals &= 0xf0;
+
+	if (msignals & UART_MSR_DCD)
+		ch->ch_mistat |= UART_MSR_DCD;
+	else
+		ch->ch_mistat &= ~UART_MSR_DCD;
+
+	if (msignals & UART_MSR_DSR)
+		ch->ch_mistat |= UART_MSR_DSR;
+	else
+		ch->ch_mistat &= ~UART_MSR_DSR;
+
+	if (msignals & UART_MSR_RI)
+		ch->ch_mistat |= UART_MSR_RI;
+	else
+		ch->ch_mistat &= ~UART_MSR_RI;
+
+	if (msignals & UART_MSR_CTS)
+		ch->ch_mistat |= UART_MSR_CTS;
+	else
+		ch->ch_mistat &= ~UART_MSR_CTS;
+
+	DPR_MSIGS(("Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
+		ch->ch_portnum,
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
+		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)));
+}
+
+
+/* Make the UART raise any of the output signals we want up */
+static void neo_assert_modem_signals(struct channel_t *ch)
+{
+	uchar out;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	out = ch->ch_mostat;
+
+	if (ch->ch_flags & CH_LOOPBACK)
+		out |= UART_MCR_LOOP;
+
+	writeb(out, &ch->ch_neo_uart->mcr);
+	neo_pci_posting_flush(ch->ch_bd);
+
+	/* Give time for the UART to actually raise/drop the signals */
+	udelay(10);
+}
+
+
+static void neo_send_start_character(struct channel_t *ch)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	if (ch->ch_startc != _POSIX_VDISABLE) {
+		ch->ch_xon_sends++;
+		writeb(ch->ch_startc, &ch->ch_neo_uart->txrx);
+		neo_pci_posting_flush(ch->ch_bd);
+		udelay(10);
+	}
+}
+
+
+static void neo_send_stop_character(struct channel_t *ch)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	if (ch->ch_stopc != _POSIX_VDISABLE) {
+		ch->ch_xoff_sends++;
+		writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx);
+		neo_pci_posting_flush(ch->ch_bd);
+		udelay(10);
+	}
+}
+
+
+/*
+ * neo_uart_init
+ */
+static void neo_uart_init(struct channel_t *ch)
+{
+
+	writeb(0, &ch->ch_neo_uart->ier);
+	writeb(0, &ch->ch_neo_uart->efr);
+	writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr);
+
+
+	/* Clear out UART and FIFO */
+	readb(&ch->ch_neo_uart->txrx);
+	writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr);
+	readb(&ch->ch_neo_uart->lsr);
+	readb(&ch->ch_neo_uart->msr);
+
+	ch->ch_flags |= CH_FIFO_ENABLED;
+
+	/* Assert any signals we want up */
+	writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+/*
+ * Make the UART completely turn off.
+ */
+static void neo_uart_off(struct channel_t *ch)
+{
+	/* Turn off UART enhanced bits */
+	writeb(0, &ch->ch_neo_uart->efr);
+
+	/* Stop all interrupts from occurring. */
+	writeb(0, &ch->ch_neo_uart->ier);
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static uint neo_get_uart_bytes_left(struct channel_t *ch)
+{
+	uchar left = 0;
+	uchar lsr = readb(&ch->ch_neo_uart->lsr);
+
+	/* We must cache the LSR as some of the bits get reset once read... */
+	ch->ch_cached_lsr |= lsr;
+
+	/* Determine whether the Transmitter is empty or not */
+	if (!(lsr & UART_LSR_TEMT)) {
+		if (ch->ch_flags & CH_TX_FIFO_EMPTY) {
+			tasklet_schedule(&ch->ch_bd->helper_tasklet);
+		}
+		left = 1;
+	} else {
+		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
+		left = 0;
+	}
+
+	return left;
+}
+
+
+/* Channel lock MUST be held by the calling function! */
+static void neo_send_break(struct channel_t *ch, int msecs)
+{
+	/*
+	 * If we receive a time of 0, this means turn off the break.
+	 */
+	if (msecs == 0) {
+		if (ch->ch_flags & CH_BREAK_SENDING) {
+			uchar temp = readb(&ch->ch_neo_uart->lcr);
+			writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+			neo_pci_posting_flush(ch->ch_bd);
+			ch->ch_flags &= ~(CH_BREAK_SENDING);
+			ch->ch_stop_sending_break = 0;
+			DPR_IOCTL(("Finishing UART_LCR_SBC! finished: %lx\n", jiffies));
+		}
+		return;
+	}
+
+	/*
+	 * Set the time we should stop sending the break.
+	 * If we are already sending a break, toss away the existing
+	 * time to stop, and use this new value instead.
+	 */
+	ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
+
+	/* Tell the UART to start sending the break */
+	if (!(ch->ch_flags & CH_BREAK_SENDING)) {
+		uchar temp = readb(&ch->ch_neo_uart->lcr);
+		writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr);
+		neo_pci_posting_flush(ch->ch_bd);
+		ch->ch_flags |= (CH_BREAK_SENDING);
+		DPR_IOCTL(("Port %d. Starting UART_LCR_SBC! start: %lx should end: %lx\n",
+			ch->ch_portnum, jiffies, ch->ch_stop_sending_break));
+	}
+}
+
+
+/*
+ * neo_send_immediate_char.
+ *
+ * Sends a specific character as soon as possible to the UART,
+ * jumping over any bytes that might be in the write queue.
+ *
+ * The channel lock MUST be held by the calling function.
+ */
+static void neo_send_immediate_char(struct channel_t *ch, unsigned char c)
+{
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	writeb(c, &ch->ch_neo_uart->txrx);
+	neo_pci_posting_flush(ch->ch_bd);
+}
+
+
+static unsigned int neo_read_eeprom(unsigned char __iomem *base, unsigned int address)
+{
+	unsigned int enable;
+	unsigned int bits;
+	unsigned int databit;
+	unsigned int val;
+
+	/* enable chip select */
+	writeb(NEO_EECS, base + NEO_EEREG);
+	/* READ */
+	enable = (address | 0x180);
+
+	for (bits = 9; bits--; ) {
+		databit = (enable & (1 << bits)) ? NEO_EEDI : 0;
+		/* Set read address */
+		writeb(databit | NEO_EECS, base + NEO_EEREG);
+		writeb(databit | NEO_EECS | NEO_EECK, base + NEO_EEREG);
+	}
+
+	val = 0;
+
+	for (bits = 17; bits--; ) {
+		/* clock to EEPROM */
+		writeb(NEO_EECS, base + NEO_EEREG);
+		writeb(NEO_EECS | NEO_EECK, base + NEO_EEREG);
+		val <<= 1;
+		/* read EEPROM */
+		if (readb(base + NEO_EEREG) & NEO_EEDO)
+			val |= 1;
+	}
+
+	/* clock falling edge */
+	writeb(NEO_EECS, base + NEO_EEREG);
+
+	/* drop chip select */
+	writeb(0x00, base + NEO_EEREG);
+
+	return val;
+}
+
+
+static void neo_vpd(struct board_t *brd)
+{
+	unsigned int i = 0;
+	unsigned int a;
+
+	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	if (!brd->re_map_membase)
+		return;
+
+	/* Store the VPD into our buffer */
+	for (i = 0; i < NEO_VPD_IMAGESIZE; i++) {
+		a = neo_read_eeprom(brd->re_map_membase, i);
+		brd->vpd[i*2] = a & 0xff;
+		brd->vpd[(i*2)+1] = (a >> 8) & 0xff;
+	}
+
+	if  (((brd->vpd[0x08] != 0x82)	   /* long resource name tag */
+		&&  (brd->vpd[0x10] != 0x82))   /* long resource name tag (PCI-66 files)*/
+		||  (brd->vpd[0x7F] != 0x78))   /* small resource end tag */
+	{
+		memset(brd->vpd, '\0', NEO_VPD_IMAGESIZE);
+	}
+	else {
+		/* Search for the serial number */
+		for (i = 0; i < NEO_VPD_IMAGESIZE * 2; i++) {
+			if (brd->vpd[i] == 'S' && brd->vpd[i + 1] == 'N') {
+				strncpy(brd->serial_num, &(brd->vpd[i + 3]), 9);
+			}
+		}
+	}
+}
diff --git a/drivers/staging/dgnc/dgnc_neo.h b/drivers/staging/dgnc/dgnc_neo.h
new file mode 100644
index 0000000..7ec5710
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_neo.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ */
+
+#ifndef __DGNC_NEO_H
+#define __DGNC_NEO_H
+
+#include "dgnc_types.h"
+#include "dgnc_driver.h"
+
+/************************************************************************
+ * Per channel/port NEO UART structure					*
+ ************************************************************************
+ *		Base Structure Entries Usage Meanings to Host		*
+ *									*
+ *	W = read write		R = read only				*
+ *			U = Unused.					*
+ ************************************************************************/
+
+struct neo_uart_struct {
+	u8 txrx;		/* WR  RHR/THR - Holding Reg */
+	u8 ier;		/* WR  IER - Interrupt Enable Reg */
+	u8 isr_fcr;		/* WR  ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
+	u8 lcr;		/* WR  LCR - Line Control Reg */
+	u8 mcr;		/* WR  MCR - Modem Control Reg */
+	u8 lsr;		/* WR  LSR - Line Status Reg */
+	u8 msr;		/* WR  MSR - Modem Status Reg */
+	u8 spr;		/* WR  SPR - Scratch Pad Reg */
+	u8 fctr;		/* WR  FCTR - Feature Control Reg */
+	u8 efr;		/* WR  EFR - Enhanced Function Reg */
+	u8 tfifo;		/* WR  TXCNT/TXTRG - Transmit FIFO Reg */
+	u8 rfifo;		/* WR  RXCNT/RXTRG - Recieve  FIFO Reg */
+	u8 xoffchar1;	/* WR  XOFF 1 - XOff Character 1 Reg */
+	u8 xoffchar2;	/* WR  XOFF 2 - XOff Character 2 Reg */
+	u8 xonchar1;	/* WR  XON 1 - Xon Character 1 Reg */
+	u8 xonchar2;	/* WR  XON 2 - XOn Character 2 Reg */
+
+	u8 reserved1[0x2ff - 0x200]; /* U   Reserved by Exar */
+	u8 txrxburst[64];	/* RW  64 bytes of RX/TX FIFO Data */
+	u8 reserved2[0x37f - 0x340]; /* U   Reserved by Exar */
+	u8 rxburst_with_errors[64];	/* R  64 bytes of RX FIFO Data + LSR */
+};
+
+/* Where to read the extended interrupt register (32bits instead of 8bits) */
+#define	UART_17158_POLL_ADDR_OFFSET	0x80
+
+/* These are the current dvid's of the Neo boards */
+#define UART_XR17C158_DVID 0x20
+#define UART_XR17D158_DVID 0x20
+#define UART_XR17E158_DVID 0x40
+
+#define NEO_EECK  0x10		/* Clock */
+#define NEO_EECS  0x20		/* Chip Select */
+#define NEO_EEDI  0x40		/* Data In  is an Output Pin */
+#define NEO_EEDO  0x80		/* Data Out is an Input Pin */
+#define NEO_EEREG 0x8E		/* offset to EEPROM control reg */
+
+
+#define NEO_VPD_IMAGESIZE 0x40	/* size of image to read from EEPROM in words */
+#define NEO_VPD_IMAGEBYTES (NEO_VPD_IMAGESIZE * 2)
+
+/*
+ * These are the redefinitions for the FCTR on the XR17C158, since
+ * Exar made them different than their earlier design. (XR16C854)
+ */
+
+/* These are only applicable when table D is selected */
+#define UART_17158_FCTR_RTS_NODELAY	0x00
+#define UART_17158_FCTR_RTS_4DELAY	0x01
+#define UART_17158_FCTR_RTS_6DELAY	0x02
+#define UART_17158_FCTR_RTS_8DELAY	0x03
+#define UART_17158_FCTR_RTS_12DELAY	0x12
+#define UART_17158_FCTR_RTS_16DELAY	0x05
+#define UART_17158_FCTR_RTS_20DELAY	0x13
+#define UART_17158_FCTR_RTS_24DELAY	0x06
+#define UART_17158_FCTR_RTS_28DELAY	0x14
+#define UART_17158_FCTR_RTS_32DELAY	0x07
+#define UART_17158_FCTR_RTS_36DELAY	0x16
+#define UART_17158_FCTR_RTS_40DELAY	0x08
+#define UART_17158_FCTR_RTS_44DELAY	0x09
+#define UART_17158_FCTR_RTS_48DELAY	0x10
+#define UART_17158_FCTR_RTS_52DELAY	0x11
+
+#define UART_17158_FCTR_RTS_IRDA	0x10
+#define UART_17158_FCTR_RS485		0x20
+#define UART_17158_FCTR_TRGA		0x00
+#define UART_17158_FCTR_TRGB		0x40
+#define UART_17158_FCTR_TRGC		0x80
+#define UART_17158_FCTR_TRGD		0xC0
+
+/* 17158 trigger table selects.. */
+#define UART_17158_FCTR_BIT6		0x40
+#define UART_17158_FCTR_BIT7		0x80
+
+/* 17158 TX/RX memmapped buffer offsets */
+#define UART_17158_RX_FIFOSIZE		64
+#define UART_17158_TX_FIFOSIZE		64
+
+/* 17158 Extended IIR's */
+#define UART_17158_IIR_RDI_TIMEOUT	0x0C	/* Receiver data TIMEOUT */
+#define UART_17158_IIR_XONXOFF		0x10	/* Received an XON/XOFF char */
+#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20	/* CTS/DSR or RTS/DTR state change */
+#define UART_17158_IIR_FIFO_ENABLED	0xC0	/* 16550 FIFOs are Enabled */
+
+/*
+ * These are the extended interrupts that get sent
+ * back to us from the UART's 32bit interrupt register
+ */
+#define UART_17158_RX_LINE_STATUS	0x1	/* RX Ready */
+#define UART_17158_RXRDY_TIMEOUT	0x2	/* RX Ready Timeout */
+#define UART_17158_TXRDY		0x3	/* TX Ready */
+#define UART_17158_MSR			0x4	/* Modem State Change */
+#define UART_17158_TX_AND_FIFO_CLR	0x40	/* Transmitter Holding Reg Empty */
+#define UART_17158_RX_FIFO_DATA_ERROR	0x80	/* UART detected an RX FIFO Data error */
+
+/*
+ * These are the EXTENDED definitions for the 17C158's Interrupt
+ * Enable Register.
+ */
+#define UART_17158_EFR_ECB	0x10	/* Enhanced control bit */
+#define UART_17158_EFR_IXON	0x2	/* Receiver compares Xon1/Xoff1 */
+#define UART_17158_EFR_IXOFF	0x8	/* Transmit Xon1/Xoff1 */
+#define UART_17158_EFR_RTSDTR	0x40	/* Auto RTS/DTR Flow Control Enable */
+#define UART_17158_EFR_CTSDSR	0x80	/* Auto CTS/DSR Flow COntrol Enable */
+
+#define UART_17158_XOFF_DETECT	0x1	/* Indicates whether chip saw an incoming XOFF char  */
+#define UART_17158_XON_DETECT	0x2	/* Indicates whether chip saw an incoming XON char */
+
+#define UART_17158_IER_RSVD1	0x10	/* Reserved by Exar */
+#define UART_17158_IER_XOFF	0x20	/* Xoff Interrupt Enable */
+#define UART_17158_IER_RTSDTR	0x40	/* Output Interrupt Enable */
+#define UART_17158_IER_CTSDSR	0x80	/* Input Interrupt Enable */
+
+/*
+ * Our Global Variables
+ */
+extern struct board_ops dgnc_neo_ops;
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_pci.h b/drivers/staging/dgnc/dgnc_pci.h
new file mode 100644
index 0000000..5b6f76d
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_pci.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_PCI_H
+#define __DGNC_PCI_H
+
+#define PCIMAX 32			/* maximum number of PCI boards */
+
+#define DIGI_VID				0x114F
+
+#define PCI_DEVICE_CLASSIC_4_DID		0x0028
+#define PCI_DEVICE_CLASSIC_8_DID		0x0029
+#define PCI_DEVICE_CLASSIC_4_422_DID		0x00D0
+#define PCI_DEVICE_CLASSIC_8_422_DID		0x00D1
+#define PCI_DEVICE_NEO_4_DID			0x00B0
+#define PCI_DEVICE_NEO_8_DID			0x00B1
+#define PCI_DEVICE_NEO_2DB9_DID			0x00C8
+#define PCI_DEVICE_NEO_2DB9PRI_DID		0x00C9
+#define PCI_DEVICE_NEO_2RJ45_DID		0x00CA
+#define PCI_DEVICE_NEO_2RJ45PRI_DID		0x00CB
+#define PCI_DEVICE_NEO_1_422_DID		0x00CC
+#define PCI_DEVICE_NEO_1_422_485_DID		0x00CD
+#define PCI_DEVICE_NEO_2_422_485_DID		0x00CE
+#define PCI_DEVICE_NEO_EXPRESS_8_DID		0x00F0
+#define PCI_DEVICE_NEO_EXPRESS_4_DID		0x00F1
+#define PCI_DEVICE_NEO_EXPRESS_4RJ45_DID	0x00F2
+#define PCI_DEVICE_NEO_EXPRESS_8RJ45_DID	0x00F3
+#define PCI_DEVICE_NEO_EXPRESS_4_IBM_DID	0x00F4
+
+#define PCI_DEVICE_CLASSIC_4_PCI_NAME		"ClassicBoard 4 PCI"
+#define PCI_DEVICE_CLASSIC_8_PCI_NAME		"ClassicBoard 8 PCI"
+#define PCI_DEVICE_CLASSIC_4_422_PCI_NAME	"ClassicBoard 4 422 PCI"
+#define PCI_DEVICE_CLASSIC_8_422_PCI_NAME	"ClassicBoard 8 422 PCI"
+#define PCI_DEVICE_NEO_4_PCI_NAME		"Neo 4 PCI"
+#define PCI_DEVICE_NEO_8_PCI_NAME		"Neo 8 PCI"
+#define PCI_DEVICE_NEO_2DB9_PCI_NAME		"Neo 2 - DB9 Universal PCI"
+#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME		"Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_2RJ45_PCI_NAME		"Neo 2 - RJ45 Universal PCI"
+#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME	"Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCI_DEVICE_NEO_1_422_PCI_NAME		"Neo 1 422 PCI"
+#define PCI_DEVICE_NEO_1_422_485_PCI_NAME	"Neo 1 422/485 PCI"
+#define PCI_DEVICE_NEO_2_422_485_PCI_NAME	"Neo 2 422/485 PCI"
+
+#define PCI_DEVICE_NEO_EXPRESS_8_PCI_NAME	"Neo 8 PCI Express"
+#define PCI_DEVICE_NEO_EXPRESS_4_PCI_NAME	"Neo 4 PCI Express"
+#define PCI_DEVICE_NEO_EXPRESS_4RJ45_PCI_NAME	"Neo 4 PCI Express RJ45"
+#define PCI_DEVICE_NEO_EXPRESS_8RJ45_PCI_NAME	"Neo 8 PCI Express RJ45"
+#define PCI_DEVICE_NEO_EXPRESS_4_IBM_PCI_NAME	"Neo 4 PCI Express IBM"
+
+
+/* Size of Memory and I/O for PCI (4 K) */
+#define PCI_RAM_SIZE				0x1000
+
+/* Size of Memory (2MB) */
+#define PCI_MEM_SIZE				0x1000
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_sysfs.c b/drivers/staging/dgnc/dgnc_sysfs.c
new file mode 100644
index 0000000..0ea6c80
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_sysfs.c
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2004 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *      NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *      This is shared code between Digi's CVS archive and the
+ *      Linux Kernel sources.
+ *      Changing the source just for reformatting needlessly breaks
+ *      our CVS diff history.
+ *
+ *      Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *      Thank you.
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/serial_reg.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+
+#include "dgnc_driver.h"
+#include "dgnc_mgmt.h"
+
+
+static ssize_t dgnc_driver_version_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART);
+}
+static DRIVER_ATTR(version, S_IRUSR, dgnc_driver_version_show, NULL);
+
+
+static ssize_t dgnc_driver_boards_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dgnc_NumBoards);
+}
+static DRIVER_ATTR(boards, S_IRUSR, dgnc_driver_boards_show, NULL);
+
+
+static ssize_t dgnc_driver_maxboards_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS);
+}
+static DRIVER_ATTR(maxboards, S_IRUSR, dgnc_driver_maxboards_show, NULL);
+
+
+static ssize_t dgnc_driver_pollcounter_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%ld\n", dgnc_poll_counter);
+}
+static DRIVER_ATTR(pollcounter, S_IRUSR, dgnc_driver_pollcounter_show, NULL);
+
+
+static ssize_t dgnc_driver_state_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", dgnc_driver_state_text[dgnc_driver_state]);
+}
+static DRIVER_ATTR(state, S_IRUSR, dgnc_driver_state_show, NULL);
+
+
+static ssize_t dgnc_driver_debug_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n", dgnc_debug);
+}
+
+static ssize_t dgnc_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+	sscanf(buf, "0x%x\n", &dgnc_debug);
+	return count;
+}
+static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgnc_driver_debug_show, dgnc_driver_debug_store);
+
+
+static ssize_t dgnc_driver_rawreadok_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%x\n", dgnc_rawreadok);
+}
+
+static ssize_t dgnc_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+	sscanf(buf, "0x%x\n", &dgnc_rawreadok);
+	return count;
+}
+static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgnc_driver_rawreadok_show, dgnc_driver_rawreadok_store);
+
+
+static ssize_t dgnc_driver_pollrate_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%dms\n", dgnc_poll_tick);
+}
+
+static ssize_t dgnc_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+	sscanf(buf, "%d\n", &dgnc_poll_tick);
+	return count;
+}
+static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgnc_driver_pollrate_show, dgnc_driver_pollrate_store);
+
+
+void dgnc_create_driver_sysfiles(struct pci_driver *dgnc_driver)
+{
+	int rc = 0;
+	struct device_driver *driverfs = &dgnc_driver->driver;
+
+	rc |= driver_create_file(driverfs, &driver_attr_version);
+	rc |= driver_create_file(driverfs, &driver_attr_boards);
+	rc |= driver_create_file(driverfs, &driver_attr_maxboards);
+	rc |= driver_create_file(driverfs, &driver_attr_debug);
+	rc |= driver_create_file(driverfs, &driver_attr_rawreadok);
+	rc |= driver_create_file(driverfs, &driver_attr_pollrate);
+	rc |= driver_create_file(driverfs, &driver_attr_pollcounter);
+	rc |= driver_create_file(driverfs, &driver_attr_state);
+	if (rc) {
+		printk(KERN_ERR "DGNC: sysfs driver_create_file failed!\n");
+	}
+}
+
+
+void dgnc_remove_driver_sysfiles(struct pci_driver *dgnc_driver)
+{
+	struct device_driver *driverfs = &dgnc_driver->driver;
+	driver_remove_file(driverfs, &driver_attr_version);
+	driver_remove_file(driverfs, &driver_attr_boards);
+	driver_remove_file(driverfs, &driver_attr_maxboards);
+	driver_remove_file(driverfs, &driver_attr_debug);
+	driver_remove_file(driverfs, &driver_attr_rawreadok);
+	driver_remove_file(driverfs, &driver_attr_pollrate);
+	driver_remove_file(driverfs, &driver_attr_pollcounter);
+	driver_remove_file(driverfs, &driver_attr_state);
+}
+
+
+#define DGNC_VERIFY_BOARD(p, bd)			\
+	if (!p)						\
+		return (0);				\
+							\
+	bd = dev_get_drvdata(p);			\
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)	\
+		return (0);				\
+	if (bd->state != BOARD_READY)			\
+		return (0);				\
+
+
+
+static ssize_t dgnc_vpd_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	count += sprintf(buf + count, "\n      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
+	for (i = 0; i < 0x40 * 2; i++) {
+		if (!(i % 16))
+			count += sprintf(buf + count, "\n%04X ", i * 2);
+		count += sprintf(buf + count, "%02X ", bd->vpd[i]);
+	}
+	count += sprintf(buf + count, "\n");
+
+	return count;
+}
+static DEVICE_ATTR(vpd, S_IRUSR, dgnc_vpd_show, NULL);
+
+static ssize_t dgnc_serial_number_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	if (bd->serial_num[0] == '\0')
+		count += sprintf(buf + count, "<UNKNOWN>\n");
+	else
+		count += sprintf(buf + count, "%s\n", bd->serial_num);
+
+	return count;
+}
+static DEVICE_ATTR(serial_number, S_IRUSR, dgnc_serial_number_show, NULL);
+
+
+static ssize_t dgnc_ports_state_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count,
+			"%d %s\n", bd->channels[i]->ch_portnum,
+			bd->channels[i]->ch_open_count ? "Open" : "Closed");
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_state, S_IRUSR, dgnc_ports_state_show, NULL);
+
+
+static ssize_t dgnc_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count +=  snprintf(buf + count, PAGE_SIZE - count,
+			"%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_old_baud);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_baud, S_IRUSR, dgnc_ports_baud_show, NULL);
+
+
+static ssize_t dgnc_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		if (bd->channels[i]->ch_open_count) {
+			count += snprintf(buf + count, PAGE_SIZE - count,
+				"%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum,
+				(bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+				(bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+				(bd->channels[i]->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
+		} else {
+			count += snprintf(buf + count, PAGE_SIZE - count,
+				"%d\n", bd->channels[i]->ch_portnum);
+		}
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_msignals, S_IRUSR, dgnc_ports_msignals_show, NULL);
+
+
+static ssize_t dgnc_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_iflag, S_IRUSR, dgnc_ports_iflag_show, NULL);
+
+
+static ssize_t dgnc_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_cflag, S_IRUSR, dgnc_ports_cflag_show, NULL);
+
+
+static ssize_t dgnc_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_oflag, S_IRUSR, dgnc_ports_oflag_show, NULL);
+
+
+static ssize_t dgnc_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_lflag, S_IRUSR, dgnc_ports_lflag_show, NULL);
+
+
+static ssize_t dgnc_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgnc_ports_digi_flag_show, NULL);
+
+
+static ssize_t dgnc_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgnc_ports_rxcount_show, NULL);
+
+
+static ssize_t dgnc_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	int count = 0;
+	int i = 0;
+
+	DGNC_VERIFY_BOARD(p, bd);
+
+	for (i = 0; i < bd->nasync; i++) {
+		count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n",
+			bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount);
+	}
+	return count;
+}
+static DEVICE_ATTR(ports_txcount, S_IRUSR, dgnc_ports_txcount_show, NULL);
+
+
+/* this function creates the sys files that will export each signal status
+ * to sysfs each value will be put in a separate filename
+ */
+void dgnc_create_ports_sysfiles(struct board_t *bd)
+{
+	int rc = 0;
+
+	dev_set_drvdata(&bd->pdev->dev, bd);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_vpd);
+	rc |= device_create_file(&(bd->pdev->dev), &dev_attr_serial_number);
+	if (rc) {
+		printk(KERN_ERR "DGNC: sysfs device_create_file failed!\n");
+	}
+}
+
+
+/* removes all the sys files created for that port */
+void dgnc_remove_ports_sysfiles(struct board_t *bd)
+{
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_vpd);
+	device_remove_file(&(bd->pdev->dev), &dev_attr_serial_number);
+}
+
+
+static ssize_t dgnc_tty_state_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed");
+}
+static DEVICE_ATTR(state, S_IRUSR, dgnc_tty_state_show, NULL);
+
+
+static ssize_t dgnc_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_old_baud);
+}
+static DEVICE_ATTR(baud, S_IRUSR, dgnc_tty_baud_show, NULL);
+
+
+static ssize_t dgnc_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	if (ch->ch_open_count) {
+		return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n",
+			(ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "",
+			(ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "",
+			(ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "",
+			(ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "",
+			(ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "",
+			(ch->ch_mistat & UART_MSR_RI)  ? "RI"  : "");
+	}
+	return 0;
+}
+static DEVICE_ATTR(msignals, S_IRUSR, dgnc_tty_msignals_show, NULL);
+
+
+static ssize_t dgnc_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag);
+}
+static DEVICE_ATTR(iflag, S_IRUSR, dgnc_tty_iflag_show, NULL);
+
+
+static ssize_t dgnc_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag);
+}
+static DEVICE_ATTR(cflag, S_IRUSR, dgnc_tty_cflag_show, NULL);
+
+
+static ssize_t dgnc_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag);
+}
+static DEVICE_ATTR(oflag, S_IRUSR, dgnc_tty_oflag_show, NULL);
+
+
+static ssize_t dgnc_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag);
+}
+static DEVICE_ATTR(lflag, S_IRUSR, dgnc_tty_lflag_show, NULL);
+
+
+static ssize_t dgnc_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags);
+}
+static DEVICE_ATTR(digi_flag, S_IRUSR, dgnc_tty_digi_flag_show, NULL);
+
+
+static ssize_t dgnc_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount);
+}
+static DEVICE_ATTR(rxcount, S_IRUSR, dgnc_tty_rxcount_show, NULL);
+
+
+static ssize_t dgnc_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount);
+}
+static DEVICE_ATTR(txcount, S_IRUSR, dgnc_tty_txcount_show, NULL);
+
+
+static ssize_t dgnc_tty_name_show(struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+
+	if (!d)
+		return (0);
+	un = (struct un_t *) dev_get_drvdata(d);
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (0);
+	if (bd->state != BOARD_READY)
+		return (0);
+
+	return snprintf(buf, PAGE_SIZE, "%sn%d%c\n",
+		(un->un_type == DGNC_PRINT) ? "pr" : "tty",
+		bd->boardnum + 1, 'a' + ch->ch_portnum);
+}
+static DEVICE_ATTR(custom_name, S_IRUSR, dgnc_tty_name_show, NULL);
+
+
+static struct attribute *dgnc_sysfs_tty_entries[] = {
+	&dev_attr_state.attr,
+	&dev_attr_baud.attr,
+	&dev_attr_msignals.attr,
+	&dev_attr_iflag.attr,
+	&dev_attr_cflag.attr,
+	&dev_attr_oflag.attr,
+	&dev_attr_lflag.attr,
+	&dev_attr_digi_flag.attr,
+	&dev_attr_rxcount.attr,
+	&dev_attr_txcount.attr,
+	&dev_attr_custom_name.attr,
+	NULL
+};
+
+
+static struct attribute_group dgnc_tty_attribute_group = {
+	.name = NULL,
+	.attrs = dgnc_sysfs_tty_entries,
+};
+
+
+void dgnc_create_tty_sysfs(struct un_t *un, struct device *c)
+{
+	int ret;
+
+	ret = sysfs_create_group(&c->kobj, &dgnc_tty_attribute_group);
+	if (ret) {
+		printk(KERN_ERR "dgnc: failed to create sysfs tty device attributes.\n");
+		sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
+		return;
+	}
+
+	dev_set_drvdata(c, un);
+
+}
+
+
+void dgnc_remove_tty_sysfs(struct device *c)
+{
+	sysfs_remove_group(&c->kobj, &dgnc_tty_attribute_group);
+}
+
diff --git a/drivers/staging/dgnc/dgnc_sysfs.h b/drivers/staging/dgnc/dgnc_sysfs.h
new file mode 100644
index 0000000..4b87ce1
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_sysfs.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_SYSFS_H
+#define __DGNC_SYSFS_H
+
+#include "dgnc_driver.h"
+
+#include <linux/device.h>
+
+struct board_t;
+struct channel_t;
+struct un_t;
+struct pci_driver;
+struct class_device;
+
+extern void dgnc_create_ports_sysfiles(struct board_t *bd);
+extern void dgnc_remove_ports_sysfiles(struct board_t *bd);
+
+extern void dgnc_create_driver_sysfiles(struct pci_driver *);
+extern void dgnc_remove_driver_sysfiles(struct pci_driver *);
+
+extern int dgnc_tty_class_init(void);
+extern int dgnc_tty_class_destroy(void);
+
+extern void dgnc_create_tty_sysfs(struct un_t *un, struct device *c);
+extern void dgnc_remove_tty_sysfs(struct device *c);
+
+
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_trace.c b/drivers/staging/dgnc/dgnc_trace.c
new file mode 100644
index 0000000..a98b7d4
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_trace.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/vmalloc.h>
+
+#include "dgnc_driver.h"
+
+#define TRC_TO_CONSOLE 1
+
+/* file level globals */
+static char *dgnc_trcbuf;		/* the ringbuffer */
+
+#if defined(TRC_TO_KMEM)
+static int dgnc_trcbufi = 0;		/* index of the tilde at the end of */
+#endif
+
+#if defined(TRC_TO_KMEM)
+static DEFINE_SPINLOCK(dgnc_tracef_lock);
+#endif
+
+
+#if 0
+
+#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
+
+void dgnc_tracef(const char *fmt, ...)
+{
+	return;
+}
+
+#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+void dgnc_tracef(const char *fmt, ...)
+{
+	va_list	         ap;
+	char  	         buf[TRC_MAXMSG+1];
+	size_t		 lenbuf;
+	int		 i;
+	static int	 failed = FALSE;
+# if defined(TRC_TO_KMEM)
+	unsigned long	 flags;
+#endif
+
+	if(failed)
+		return;
+# if defined(TRC_TO_KMEM)
+	DGNC_LOCK(dgnc_tracef_lock, flags);
+#endif
+
+	/* Format buf using fmt and arguments contained in ap. */
+	va_start(ap, fmt);
+	i = vsprintf(buf, fmt,  ap);
+	va_end(ap);
+	lenbuf = strlen(buf);
+
+# if defined(TRC_TO_KMEM)
+	{
+		static int	 initd=0;
+
+		/*
+		 * Now, in addition to (or instead of) printing this stuff out
+		 * (which is a buffered operation), also tuck it away into a
+		 * corner of memory which can be examined post-crash in kdb.
+		 */
+		if (!initd) {
+			dgnc_trcbuf = (char *) vmalloc(dgnc_trcbuf_size);
+			if(!dgnc_trcbuf) {
+				failed = TRUE;
+				printk("dgnc: tracing init failed!\n");
+				return;
+			}
+
+			memset(dgnc_trcbuf, '\0',  dgnc_trcbuf_size);
+			dgnc_trcbufi = 0;
+			initd++;
+
+			printk("dgnc: tracing enabled - " TRC_DTRC
+				" 0x%lx 0x%x\n",
+				(unsigned long)dgnc_trcbuf,
+				dgnc_trcbuf_size);
+		}
+
+#  if defined(TRC_ON_OVERFLOW_WRAP_AROUND)
+		/*
+		 * This is the less CPU-intensive way to do things.  We simply
+		 * wrap around before we fall off the end of the buffer.  A
+		 * tilde (~) demarcates the current end of the trace.
+		 *
+		 * This method should be used if you are concerned about race
+		 * conditions as it is less likely to affect the timing of
+		 * things.
+		 */
+
+		if (dgnc_trcbufi + lenbuf >= dgnc_trcbuf_size) {
+			/* We are wrapping, so wipe out the last tilde. */
+			dgnc_trcbuf[dgnc_trcbufi] = '\0';
+			/* put the new string at the beginning of the buffer */
+			dgnc_trcbufi = 0;
+		}
+
+		strcpy(&dgnc_trcbuf[dgnc_trcbufi], buf);
+		dgnc_trcbufi += lenbuf;
+		dgnc_trcbuf[dgnc_trcbufi] = '~';
+
+#  elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER)
+		/*
+		 * This is the more CPU-intensive way to do things.  If we
+		 * venture into the last 1/8 of the buffer, we shift the
+		 * last 7/8 of the buffer forward, wiping out the first 1/8.
+		 * Advantage: No wrap-around, only truncation from the
+		 * beginning.
+		 *
+		 * This method should not be used if you are concerned about
+		 * timing changes affecting the behaviour of the driver (ie,
+		 * race conditions).
+		 */
+		strcpy(&dgnc_trcbuf[dgnc_trcbufi], buf);
+		dgnc_trcbufi += lenbuf;
+		dgnc_trcbuf[dgnc_trcbufi] = '~';
+		dgnc_trcbuf[dgnc_trcbufi+1] = '\0';
+
+		/* If we're near the end of the trace buffer... */
+		if (dgnc_trcbufi > (dgnc_trcbuf_size/8)*7) {
+			/* Wipe out the first eighth to make some more room. */
+			strcpy(dgnc_trcbuf, &dgnc_trcbuf[dgnc_trcbuf_size/8]);
+			dgnc_trcbufi = strlen(dgnc_trcbuf)-1;
+			/* Plop overflow message at the top of the buffer. */
+			bcopy(TRC_OVERFLOW, dgnc_trcbuf, strlen(TRC_OVERFLOW));
+		}
+#  else
+#   error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?"
+#  endif
+	}
+	DGNC_UNLOCK(dgnc_tracef_lock, flags);
+
+# endif /* defined(TRC_TO_KMEM) */
+}
+
+#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */
+
+#endif
+
+
+/*
+ * dgnc_tracer_free()
+ *
+ *
+ */
+void dgnc_tracer_free(void)
+{
+	if(dgnc_trcbuf)
+		vfree(dgnc_trcbuf);
+}
diff --git a/drivers/staging/dgnc/dgnc_trace.h b/drivers/staging/dgnc/dgnc_trace.h
new file mode 100644
index 0000000..efed88a
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_trace.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ *
+ *****************************************************************************
+ * Header file for dgnc_trace.c
+ *
+ */
+
+#ifndef __DGNC_TRACE_H
+#define __DGNC_TRACE_H
+
+#include "dgnc_driver.h"
+
+#if 0
+
+# if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE)
+   void dgnc_tracef(const char *fmt, ...);
+# else
+   void dgnc_tracef(const char *fmt, ...);
+# endif
+
+#endif
+
+void dgnc_tracer_free(void);
+
+#endif
+
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c
new file mode 100644
index 0000000..a7bb6bc
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_tty.c
@@ -0,0 +1,3544 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *
+ *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
+ *
+ *	This is shared code between Digi's CVS archive and the
+ *	Linux Kernel sources.
+ *	Changing the source just for reformatting needlessly breaks
+ *	our CVS diff history.
+ *
+ *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
+ *	Thank you.
+ */
+
+/************************************************************************
+ *
+ * This file implements the tty driver functionality for the
+ * Neo and ClassicBoard PCI based product lines.
+ *
+ ************************************************************************
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/sched.h>	/* For jiffies, task states */
+#include <linux/interrupt.h>	/* For tasklet and interrupt structs/defines */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/delay.h>	/* For udelay */
+#include <asm/uaccess.h>	/* For copy_from_user/copy_to_user */
+#include <linux/pci.h>
+
+#include "dgnc_driver.h"
+#include "dgnc_tty.h"
+#include "dgnc_types.h"
+#include "dgnc_trace.h"
+#include "dgnc_neo.h"
+#include "dgnc_cls.h"
+#include "dpacompat.h"
+#include "dgnc_sysfs.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+#define init_MUTEX(sem)	 sema_init(sem, 1)
+#define DECLARE_MUTEX(name)     \
+	struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
+#endif
+
+/*
+ * internal variables
+ */
+static struct board_t	*dgnc_BoardsByMajor[256];
+static uchar		*dgnc_TmpWriteBuf = NULL;
+static DECLARE_MUTEX(dgnc_TmpWriteSem);
+
+/*
+ * Default transparent print information.
+ */
+static struct digi_t dgnc_digi_init = {
+	.digi_flags =	DIGI_COOK,	/* Flags			*/
+	.digi_maxcps =	100,		/* Max CPS			*/
+	.digi_maxchar =	50,		/* Max chars in print queue	*/
+	.digi_bufsize =	100,		/* Printer buffer size		*/
+	.digi_onlen =	4,		/* size of printer on string	*/
+	.digi_offlen =	4,		/* size of printer off string	*/
+	.digi_onstr =	"\033[5i",	/* ANSI printer on string ]	*/
+	.digi_offstr =	"\033[4i",	/* ANSI printer off string ]	*/
+	.digi_term =	"ansi"		/* default terminal type	*/
+};
+
+
+/*
+ * Define a local default termios struct. All ports will be created
+ * with this termios initially.
+ *
+ * This defines a raw port at 9600 baud, 8 data bits, no parity,
+ * 1 stop bit.
+ */
+static struct ktermios DgncDefaultTermios =
+{
+	.c_iflag =	(DEFAULT_IFLAGS),	/* iflags */
+	.c_oflag =	(DEFAULT_OFLAGS),	/* oflags */
+	.c_cflag =	(DEFAULT_CFLAGS),	/* cflags */
+	.c_lflag =	(DEFAULT_LFLAGS),	/* lflags */
+	.c_cc =		INIT_C_CC,
+	.c_line =	0,
+};
+
+
+/* Our function prototypes */
+static int dgnc_tty_open(struct tty_struct *tty, struct file *file);
+static void dgnc_tty_close(struct tty_struct *tty, struct file *file);
+static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch);
+static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
+static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo);
+static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info);
+static int dgnc_tty_write_room(struct tty_struct *tty);
+static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c);
+static int dgnc_tty_chars_in_buffer(struct tty_struct *tty);
+static void dgnc_tty_start(struct tty_struct *tty);
+static void dgnc_tty_stop(struct tty_struct *tty);
+static void dgnc_tty_throttle(struct tty_struct *tty);
+static void dgnc_tty_unthrottle(struct tty_struct *tty);
+static void dgnc_tty_flush_chars(struct tty_struct *tty);
+static void dgnc_tty_flush_buffer(struct tty_struct *tty);
+static void dgnc_tty_hangup(struct tty_struct *tty);
+static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value);
+static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgnc_tty_tiocmget(struct tty_struct *tty);
+static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
+#else
+static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file);
+static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);
+#endif
+static int dgnc_tty_send_break(struct tty_struct *tty, int msec);
+static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout);
+static int dgnc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
+static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios);
+static void dgnc_tty_send_xchar(struct tty_struct *tty, char ch);
+
+
+static const struct tty_operations dgnc_tty_ops = {
+	.open = dgnc_tty_open,
+	.close = dgnc_tty_close,
+	.write = dgnc_tty_write,
+	.write_room = dgnc_tty_write_room,
+	.flush_buffer = dgnc_tty_flush_buffer,
+	.chars_in_buffer = dgnc_tty_chars_in_buffer,
+	.flush_chars = dgnc_tty_flush_chars,
+	.ioctl = dgnc_tty_ioctl,
+	.set_termios = dgnc_tty_set_termios,
+	.stop = dgnc_tty_stop,
+	.start = dgnc_tty_start,
+	.throttle = dgnc_tty_throttle,
+	.unthrottle = dgnc_tty_unthrottle,
+	.hangup = dgnc_tty_hangup,
+	.put_char = dgnc_tty_put_char,
+	.tiocmget = dgnc_tty_tiocmget,
+	.tiocmset = dgnc_tty_tiocmset,
+	.break_ctl = dgnc_tty_send_break,
+	.wait_until_sent = dgnc_tty_wait_until_sent,
+	.send_xchar = dgnc_tty_send_xchar
+};
+
+/************************************************************************
+ *
+ * TTY Initialization/Cleanup Functions
+ *
+ ************************************************************************/
+
+/*
+ * dgnc_tty_preinit()
+ *
+ * Initialize any global tty related data before we download any boards.
+ */
+int dgnc_tty_preinit(void)
+{
+	/*
+	 * Allocate a buffer for doing the copy from user space to
+	 * kernel space in dgnc_write().  We only use one buffer and
+	 * control access to it with a semaphore.  If we are paging, we
+	 * are already in trouble so one buffer won't hurt much anyway.
+	 *
+	 * We are okay to sleep in the malloc, as this routine
+	 * is only called during module load, (not in interrupt context),
+	 * and with no locks held.
+	 */
+	dgnc_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_KERNEL);
+
+	if (!dgnc_TmpWriteBuf) {
+		DPR_INIT(("unable to allocate tmp write buf"));
+		return (-ENOMEM);
+	}
+
+	return(0);
+}
+
+
+/*
+ * dgnc_tty_register()
+ *
+ * Init the tty subsystem for this board.
+ */
+int dgnc_tty_register(struct board_t *brd)
+{
+	int rc = 0;
+
+	DPR_INIT(("tty_register start\n"));
+
+	memset(&brd->SerialDriver, 0, sizeof(struct tty_driver));
+	memset(&brd->PrintDriver, 0, sizeof(struct tty_driver));
+
+	brd->SerialDriver.magic = TTY_DRIVER_MAGIC;
+
+	snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgnc_%d_", brd->boardnum);
+
+	brd->SerialDriver.name = brd->SerialName;
+	brd->SerialDriver.name_base = 0;
+	brd->SerialDriver.major = 0;
+	brd->SerialDriver.minor_start = 0;
+	brd->SerialDriver.num = brd->maxports;
+	brd->SerialDriver.type = TTY_DRIVER_TYPE_SERIAL;
+	brd->SerialDriver.subtype = SERIAL_TYPE_NORMAL;
+	brd->SerialDriver.init_termios = DgncDefaultTermios;
+	brd->SerialDriver.driver_name = DRVSTR;
+	brd->SerialDriver.flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+	/*
+	 * The kernel wants space to store pointers to
+	 * tty_struct's and termios's.
+	 */
+	brd->SerialDriver.ttys = kzalloc(brd->maxports * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!brd->SerialDriver.ttys)
+		return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	brd->SerialDriver.refcount = brd->TtyRefCnt;
+#else
+	kref_init(&brd->SerialDriver.kref);
+#endif
+
+	brd->SerialDriver.termios = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+	if (!brd->SerialDriver.termios)
+		return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+	brd->SerialDriver.termios_locked = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+	if (!brd->SerialDriver.termios_locked)
+		return(-ENOMEM);
+#endif
+	/*
+	 * Entry points for driver.  Called by the kernel from
+	 * tty_io.c and n_tty.c.
+	 */
+	tty_set_operations(&brd->SerialDriver, &dgnc_tty_ops);
+
+	if (!brd->dgnc_Major_Serial_Registered) {
+		/* Register tty devices */
+		rc = tty_register_driver(&brd->SerialDriver);
+		if (rc < 0) {
+			APR(("Can't register tty device (%d)\n", rc));
+			return(rc);
+		}
+		brd->dgnc_Major_Serial_Registered = TRUE;
+	}
+
+	/*
+	 * If we're doing transparent print, we have to do all of the above
+	 * again, seperately so we don't get the LD confused about what major
+	 * we are when we get into the dgnc_tty_open() routine.
+	 */
+	brd->PrintDriver.magic = TTY_DRIVER_MAGIC;
+	snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgnc_%d_", brd->boardnum);
+
+	brd->PrintDriver.name = brd->PrintName;
+	brd->PrintDriver.name_base = 0;
+	brd->PrintDriver.major = brd->SerialDriver.major;
+	brd->PrintDriver.minor_start = 0x80;
+	brd->PrintDriver.num = brd->maxports;
+	brd->PrintDriver.type = TTY_DRIVER_TYPE_SERIAL;
+	brd->PrintDriver.subtype = SERIAL_TYPE_NORMAL;
+	brd->PrintDriver.init_termios = DgncDefaultTermios;
+	brd->PrintDriver.driver_name = DRVSTR;
+	brd->PrintDriver.flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK);
+
+	/*
+	 * The kernel wants space to store pointers to
+	 * tty_struct's and termios's.  Must be seperate from
+	 * the Serial Driver so we don't get confused
+	 */
+	brd->PrintDriver.ttys = kzalloc(brd->maxports * sizeof(struct tty_struct *), GFP_KERNEL);
+	if (!brd->PrintDriver.ttys)
+		return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
+	brd->PrintDriver.refcount = brd->TtyRefCnt;
+#else
+	kref_init(&brd->PrintDriver.kref);
+#endif
+
+	brd->PrintDriver.termios = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+	if (!brd->PrintDriver.termios)
+		return(-ENOMEM);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+	brd->PrintDriver.termios_locked = kzalloc(brd->maxports * sizeof(struct ktermios *), GFP_KERNEL);
+	if (!brd->PrintDriver.termios_locked)
+		return(-ENOMEM);
+#endif
+
+	/*
+	 * Entry points for driver.  Called by the kernel from
+	 * tty_io.c and n_tty.c.
+	 */
+	tty_set_operations(&brd->PrintDriver, &dgnc_tty_ops);
+
+	if (!brd->dgnc_Major_TransparentPrint_Registered) {
+		/* Register Transparent Print devices */
+		rc = tty_register_driver(&brd->PrintDriver);
+		if (rc < 0) {
+			APR(("Can't register Transparent Print device (%d)\n", rc));
+			return(rc);
+		}
+		brd->dgnc_Major_TransparentPrint_Registered = TRUE;
+	}
+
+	dgnc_BoardsByMajor[brd->SerialDriver.major] = brd;
+	brd->dgnc_Serial_Major = brd->SerialDriver.major;
+	brd->dgnc_TransparentPrint_Major = brd->PrintDriver.major;
+
+	DPR_INIT(("DGNC REGISTER TTY: MAJOR: %d\n", brd->SerialDriver.major));
+
+	return (rc);
+}
+
+
+/*
+ * dgnc_tty_init()
+ *
+ * Init the tty subsystem.  Called once per board after board has been
+ * downloaded and init'ed.
+ */
+int dgnc_tty_init(struct board_t *brd)
+{
+	int i;
+	void __iomem *vaddr;
+	struct channel_t *ch;
+
+	if (!brd)
+		return (-ENXIO);
+
+	DPR_INIT(("dgnc_tty_init start\n"));
+
+	/*
+	 * Initialize board structure elements.
+	 */
+
+	vaddr = brd->re_map_membase;
+
+	brd->nasync = brd->maxports;
+
+	/*
+	 * Allocate channel memory that might not have been allocated
+	 * when the driver was first loaded.
+	 */
+	for (i = 0; i < brd->nasync; i++) {
+		if (!brd->channels[i]) {
+
+			/*
+			 * Okay to malloc with GFP_KERNEL, we are not at
+			 * interrupt context, and there are no locks held.
+			 */
+			brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_KERNEL);
+			if (!brd->channels[i]) {
+				DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n",
+				    __FILE__, __LINE__));
+			}
+		}
+	}
+
+	ch = brd->channels[0];
+	vaddr = brd->re_map_membase;
+
+	/* Set up channel variables */
+	for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
+
+		if (!brd->channels[i])
+			continue;
+
+		DGNC_SPINLOCK_INIT(ch->ch_lock);
+
+		/* Store all our magic numbers */
+		ch->magic = DGNC_CHANNEL_MAGIC;
+		ch->ch_tun.magic = DGNC_UNIT_MAGIC;
+		ch->ch_tun.un_ch = ch;
+		ch->ch_tun.un_type = DGNC_SERIAL;
+		ch->ch_tun.un_dev = i;
+
+		ch->ch_pun.magic = DGNC_UNIT_MAGIC;
+		ch->ch_pun.un_ch = ch;
+		ch->ch_pun.un_type = DGNC_PRINT;
+		ch->ch_pun.un_dev = i + 128;
+
+		if (brd->bd_uart_offset == 0x200)
+			ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i);
+		else
+			ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i);
+
+		ch->ch_bd = brd;
+		ch->ch_portnum = i;
+		ch->ch_digi = dgnc_digi_init;
+
+		/* .25 second delay */
+		ch->ch_close_delay = 250;
+
+		init_waitqueue_head(&ch->ch_flags_wait);
+		init_waitqueue_head(&ch->ch_tun.un_flags_wait);
+		init_waitqueue_head(&ch->ch_pun.un_flags_wait);
+		init_waitqueue_head(&ch->ch_sniff_wait);
+
+		{
+			struct device *classp;
+			classp = tty_register_device(&brd->SerialDriver, i,
+				&(ch->ch_bd->pdev->dev));
+			ch->ch_tun.un_sysfs = classp;
+			dgnc_create_tty_sysfs(&ch->ch_tun, classp);
+
+			classp = tty_register_device(&brd->PrintDriver, i,
+				&(ch->ch_bd->pdev->dev));
+			ch->ch_pun.un_sysfs = classp;
+			dgnc_create_tty_sysfs(&ch->ch_pun, classp);
+		}
+
+	}
+
+	DPR_INIT(("dgnc_tty_init finish\n"));
+
+	return (0);
+}
+
+
+/*
+ * dgnc_tty_post_uninit()
+ *
+ * UnInitialize any global tty related data.
+ */
+void dgnc_tty_post_uninit(void)
+{
+	if (dgnc_TmpWriteBuf) {
+		kfree(dgnc_TmpWriteBuf);
+		dgnc_TmpWriteBuf = NULL;
+	}
+}
+
+
+/*
+ * dgnc_tty_uninit()
+ *
+ * Uninitialize the TTY portion of this driver.  Free all memory and
+ * resources.
+ */
+void dgnc_tty_uninit(struct board_t *brd)
+{
+	int i = 0;
+
+	if (brd->dgnc_Major_Serial_Registered) {
+		dgnc_BoardsByMajor[brd->SerialDriver.major] = NULL;
+		brd->dgnc_Serial_Major = 0;
+		for (i = 0; i < brd->nasync; i++) {
+			dgnc_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs);
+			tty_unregister_device(&brd->SerialDriver, i);
+		}
+		tty_unregister_driver(&brd->SerialDriver);
+		brd->dgnc_Major_Serial_Registered = FALSE;
+	}
+
+	if (brd->dgnc_Major_TransparentPrint_Registered) {
+		dgnc_BoardsByMajor[brd->PrintDriver.major] = NULL;
+		brd->dgnc_TransparentPrint_Major = 0;
+		for (i = 0; i < brd->nasync; i++) {
+			dgnc_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs);
+			tty_unregister_device(&brd->PrintDriver, i);
+		}
+		tty_unregister_driver(&brd->PrintDriver);
+		brd->dgnc_Major_TransparentPrint_Registered = FALSE;
+	}
+
+	if (brd->SerialDriver.ttys) {
+		kfree(brd->SerialDriver.ttys);
+		brd->SerialDriver.ttys = NULL;
+	}
+	if (brd->PrintDriver.ttys) {
+		kfree(brd->PrintDriver.ttys);
+		brd->PrintDriver.ttys = NULL;
+	}
+}
+
+
+#define TMPBUFLEN (1024)
+
+/*
+ * dgnc_sniff - Dump data out to the "sniff" buffer if the
+ * proc sniff file is opened...
+ */
+void dgnc_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len)
+{
+	struct timeval tv;
+	int n;
+	int r;
+	int nbuf;
+	int i;
+	int tmpbuflen;
+	char tmpbuf[TMPBUFLEN];
+	char *p = tmpbuf;
+	int too_much_data;
+
+	/* Leave if sniff not open */
+	if (!(ch->ch_sniff_flags & SNIFF_OPEN))
+		return;
+
+	do_gettimeofday(&tv);
+
+	/* Create our header for data dump */
+	p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text);
+	tmpbuflen = p - tmpbuf;
+
+	do {
+		too_much_data = 0;
+
+		for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) {
+			p += sprintf(p, "%02x ", *buf);
+			buf++;
+			tmpbuflen = p - tmpbuf;
+		}
+
+		if (tmpbuflen < (TMPBUFLEN - 4)) {
+			if (i > 0)
+				p += sprintf(p - 1, "%s\n", ">");
+			else
+				p += sprintf(p, "%s\n", ">");
+		} else {
+			too_much_data = 1;
+			len -= i;
+		}
+
+		nbuf = strlen(tmpbuf);
+		p = tmpbuf;
+
+		/*
+		 *  Loop while data remains.
+		 */
+		while (nbuf > 0 && ch->ch_sniff_buf != 0) {
+			/*
+			 *  Determine the amount of available space left in the
+			 *  buffer.  If there's none, wait until some appears.
+			 */
+			n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK;
+
+			/*
+			 * If there is no space left to write to in our sniff buffer,
+			 * we have no choice but to drop the data.
+			 * We *cannot* sleep here waiting for space, because this
+			 * function was probably called by the interrupt/timer routines!
+			 */
+			if (n == 0) {
+				return;
+			}
+
+			/*
+			 * Copy as much data as will fit.
+			 */
+
+			if (n > nbuf)
+				n = nbuf;
+
+			r = SNIFF_MAX - ch->ch_sniff_in;
+
+			if (r <= n) {
+				memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r);
+
+				n -= r;
+				ch->ch_sniff_in = 0;
+				p += r;
+				nbuf -= r;
+			}
+
+			memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n);
+
+			ch->ch_sniff_in += n;
+			p += n;
+			nbuf -= n;
+
+			/*
+			 *  Wakeup any thread waiting for data
+			 */
+			if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) {
+				ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA;
+				wake_up_interruptible(&ch->ch_sniff_wait);
+			}
+		}
+
+		/*
+		 * If the user sent us too much data to push into our tmpbuf,
+		 * we need to keep looping around on all the data.
+		 */
+		if (too_much_data) {
+			p = tmpbuf;
+			tmpbuflen = 0;
+		}
+
+	} while (too_much_data);
+}
+
+
+/*=======================================================================
+ *
+ *	dgnc_wmove - Write data to transmit queue.
+ *
+ *		ch	- Pointer to channel structure.
+ *		buf	- Poiter to characters to be moved.
+ *		n	- Number of characters to move.
+ *
+ *=======================================================================*/
+static void dgnc_wmove(struct channel_t *ch, char *buf, uint n)
+{
+	int	remain;
+	uint	head;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	head = ch->ch_w_head & WQUEUEMASK;
+
+	/*
+	 * If the write wraps over the top of the circular buffer,
+	 * move the portion up to the wrap point, and reset the
+	 * pointers to the bottom.
+	 */
+	remain = WQUEUESIZE - head;
+
+	if (n >= remain) {
+		n -= remain;
+		memcpy(ch->ch_wqueue + head, buf, remain);
+		head = 0;
+		buf += remain;
+	}
+
+	if (n > 0) {
+		/*
+		 * Move rest of data.
+		 */
+		remain = n;
+		memcpy(ch->ch_wqueue + head, buf, remain);
+		head += remain;
+	}
+
+	head &= WQUEUEMASK;
+	ch->ch_w_head = head;
+}
+
+
+
+
+/*=======================================================================
+ *
+ *      dgnc_input - Process received data.
+ *
+ *	      ch      - Pointer to channel structure.
+ *
+ *=======================================================================*/
+void dgnc_input(struct channel_t *ch)
+{
+	struct board_t *bd;
+	struct tty_struct *tp;
+	struct tty_ldisc *ld;
+	uint	rmask;
+	ushort	head;
+	ushort	tail;
+	int	data_len;
+	ulong	lock_flags;
+	int flip_len;
+	int len = 0;
+	int n = 0;
+	int s = 0;
+	int i = 0;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	tp = ch->ch_tun.un_tty;
+
+	bd = ch->ch_bd;
+	if(!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 *      Figure the number of characters in the buffer.
+	 *      Exit immediately if none.
+	 */
+	rmask = RQUEUEMASK;
+	head = ch->ch_r_head & rmask;
+	tail = ch->ch_r_tail & rmask;
+	data_len = (head - tail) & rmask;
+
+	if (data_len == 0) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	DPR_READ(("dgnc_input start\n"));
+
+	/*
+	 * If the device is not open, or CREAD is off,
+	 * flush input data and return immediately.
+	 */
+	if (!tp || (tp->magic != TTY_MAGIC) || !(ch->ch_tun.un_flags & UN_ISOPEN) ||
+	    !(tp->termios.c_cflag & CREAD) || (ch->ch_tun.un_flags & UN_CLOSING)) {
+
+		DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum));
+		DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n",
+			tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags));
+
+		ch->ch_r_head = tail;
+
+		/* Force queue flow control to be released, if needed */
+		dgnc_check_queue_flow_control(ch);
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/*
+	 * If we are throttled, simply don't read any data.
+	 */
+	if (ch->ch_flags & CH_FORCED_STOPI) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n",
+			ch->ch_portnum, head, tail));
+		return;
+	}
+
+	DPR_READ(("dgnc_input start 2\n"));
+
+	flip_len = TTY_FLIPBUF_SIZE;
+
+	/* Chop down the length, if needed */
+	len = min(data_len, flip_len);
+	len = min(len, (N_TTY_BUF_SIZE - 1));
+
+	ld = tty_ldisc_ref(tp);
+
+#ifdef TTY_DONT_FLIP
+	/*
+	 * If the DONT_FLIP flag is on, don't flush our buffer, and act
+	 * like the ld doesn't have any space to put the data right now.
+	 */
+	if (test_bit(TTY_DONT_FLIP, &tp->flags))
+		len = 0;
+#endif
+
+	/*
+	 * If we were unable to get a reference to the ld,
+	 * don't flush our buffer, and act like the ld doesn't
+	 * have any space to put the data right now.
+	 */
+	if (!ld) {
+		len = 0;
+	} else {
+		/*
+		 * If ld doesn't have a pointer to a receive_buf function,
+		 * flush the data, then act like the ld doesn't have any
+		 * space to put the data right now.
+		 */
+		if (!ld->ops->receive_buf) {
+			ch->ch_r_head = ch->ch_r_tail;
+			len = 0;
+		}
+	}
+
+	if (len <= 0) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		if (ld)
+			tty_ldisc_deref(ld);
+		return;
+	}
+
+	/*
+	 * The tty layer in the kernel has changed in 2.6.16+.
+	 *
+	 * The flip buffers in the tty structure are no longer exposed,
+	 * and probably will be going away eventually.
+	 *
+	 * If we are completely raw, we don't need to go through a lot
+	 * of the tty layers that exist.
+	 * In this case, we take the shortest and fastest route we
+	 * can to relay the data to the user.
+	 *
+	 * On the other hand, if we are not raw, we need to go through
+	 * the new 2.6.16+ tty layer, which has its API more well defined.
+	 */
+	len = tty_buffer_request_room(tp->port, len);
+	n = len;
+
+	/*
+	 * n now contains the most amount of data we can copy,
+	 * bounded either by how much the Linux tty layer can handle,
+	 * or the amount of data the card actually has pending...
+	 */
+	while (n) {
+		s = ((head >= tail) ? head : RQUEUESIZE) - tail;
+		s = min(s, n);
+
+		if (s <= 0)
+			break;
+
+		/*
+		 * If conditions are such that ld needs to see all
+		 * UART errors, we will have to walk each character
+		 * and error byte and send them to the buffer one at
+		 * a time.
+		 */
+		if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
+			for (i = 0; i < s; i++) {
+				if (*(ch->ch_equeue + tail + i) & UART_LSR_BI)
+					tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_BREAK);
+				else if (*(ch->ch_equeue + tail + i) & UART_LSR_PE)
+					tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_PARITY);
+				else if (*(ch->ch_equeue + tail + i) & UART_LSR_FE)
+					tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_FRAME);
+				else
+					tty_insert_flip_char(tp->port, *(ch->ch_rqueue + tail + i), TTY_NORMAL);
+			}
+		}
+		else {
+			tty_insert_flip_string(tp->port, ch->ch_rqueue + tail, s);
+		}
+
+		dgnc_sniff_nowait_nolock(ch, "USER READ", ch->ch_rqueue + tail, s);
+
+		tail += s;
+		n -= s;
+		/* Flip queue if needed */
+		tail &= rmask;
+	}
+
+	ch->ch_r_tail = tail & rmask;
+	ch->ch_e_tail = tail & rmask;
+	dgnc_check_queue_flow_control(ch);
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	/* Tell the tty layer its okay to "eat" the data now */
+	tty_flip_buffer_push(tp->port);
+
+	if (ld)
+		tty_ldisc_deref(ld);
+
+	DPR_READ(("dgnc_input - finish\n"));
+}
+
+
+/************************************************************************
+ * Determines when CARRIER changes state and takes appropriate
+ * action.
+ ************************************************************************/
+void dgnc_carrier(struct channel_t *ch)
+{
+	struct board_t *bd;
+
+	int virt_carrier = 0;
+	int phys_carrier = 0;
+
+	DPR_CARR(("dgnc_carrier called...\n"));
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	if (ch->ch_mistat & UART_MSR_DCD) {
+		DPR_CARR(("mistat: %x  D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD));
+		phys_carrier = 1;
+	}
+
+	if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) {
+		virt_carrier = 1;
+	}
+
+	if (ch->ch_c_cflag & CLOCAL) {
+		virt_carrier = 1;
+	}
+
+
+	DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier));
+
+	/*
+	 * Test for a VIRTUAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		DPR_CARR(("carrier: virt DCD rose\n"));
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 * Test for a PHYSICAL carrier transition to HIGH.
+	 */
+	if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
+
+		/*
+		 * When carrier rises, wake any threads waiting
+		 * for carrier in the open routine.
+		 */
+
+		DPR_CARR(("carrier: physical DCD rose\n"));
+
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+	}
+
+	/*
+	 *  Test for a PHYSICAL transition to low, so long as we aren't
+	 *  currently ignoring physical transitions (which is what "virtual
+	 *  carrier" indicates).
+	 *
+	 *  The transition of the virtual carrier to low really doesn't
+	 *  matter... it really only means "ignore carrier state", not
+	 *  "make pretend that carrier is there".
+	 */
+	if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) &&
+	    (phys_carrier == 0))
+	{
+
+		/*
+		 *   When carrier drops:
+		 *
+		 *   Drop carrier on all open units.
+		 *
+		 *   Flush queues, waking up any task waiting in the
+		 *   line discipline.
+		 *
+		 *   Send a hangup to the control terminal.
+		 *
+		 *   Enable all select calls.
+		 */
+		if (waitqueue_active(&(ch->ch_flags_wait)))
+			wake_up_interruptible(&ch->ch_flags_wait);
+
+		if (ch->ch_tun.un_open_count > 0) {
+			DPR_CARR(("Sending tty hangup\n"));
+			tty_hangup(ch->ch_tun.un_tty);
+		}
+
+		if (ch->ch_pun.un_open_count > 0) {
+			DPR_CARR(("Sending pr hangup\n"));
+			tty_hangup(ch->ch_pun.un_tty);
+		}
+	}
+
+	/*
+	 *  Make sure that our cached values reflect the current reality.
+	 */
+	if (virt_carrier == 1)
+		ch->ch_flags |= CH_FCAR;
+	else
+		ch->ch_flags &= ~CH_FCAR;
+
+	if (phys_carrier == 1)
+		ch->ch_flags |= CH_CD;
+	else
+		ch->ch_flags &= ~CH_CD;
+}
+
+/*
+ *  Assign the custom baud rate to the channel structure
+ */
+static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate)
+{
+	int testdiv;
+	int testrate_high;
+	int testrate_low;
+	int deltahigh;
+	int deltalow;
+
+	if (newrate < 0)
+		newrate = 0;
+
+	/*
+	 *  Since the divisor is stored in a 16-bit integer, we make sure
+	 *  we don't allow any rates smaller than a 16-bit integer would allow.
+	 *  And of course, rates above the dividend won't fly.
+	 */
+	if (newrate && newrate < ((ch->ch_bd->bd_dividend / 0xFFFF) + 1))
+		newrate = ((ch->ch_bd->bd_dividend / 0xFFFF) + 1);
+
+	if (newrate && newrate > ch->ch_bd->bd_dividend)
+		newrate = ch->ch_bd->bd_dividend;
+
+	while (newrate > 0) {
+		testdiv = ch->ch_bd->bd_dividend / newrate;
+
+		/*
+		 *  If we try to figure out what rate the board would use
+		 *  with the test divisor, it will be either equal or higher
+		 *  than the requested baud rate.  If we then determine the
+		 *  rate with a divisor one higher, we will get the next lower
+		 *  supported rate below the requested.
+		 */
+		testrate_high = ch->ch_bd->bd_dividend / testdiv;
+		testrate_low  = ch->ch_bd->bd_dividend / (testdiv + 1);
+
+		/*
+		 *  If the rate for the requested divisor is correct, just
+		 *  use it and be done.
+		 */
+		if (testrate_high == newrate )
+			break;
+
+		/*
+		 *  Otherwise, pick the rate that is closer (i.e. whichever rate
+		 *  has a smaller delta).
+		 */
+		deltahigh = testrate_high - newrate;
+		deltalow = newrate - testrate_low;
+
+		if (deltahigh < deltalow) {
+			newrate = testrate_high;
+		} else {
+			newrate = testrate_low;
+		}
+
+		break;
+	}
+
+	ch->ch_custom_speed = newrate;
+
+	return;
+}
+
+
+void dgnc_check_queue_flow_control(struct channel_t *ch)
+{
+	int qleft = 0;
+
+	/* Store how much space we have left in the queue */
+	if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0)
+		qleft += RQUEUEMASK + 1;
+
+	/*
+	 * Check to see if we should enforce flow control on our queue because
+	 * the ld (or user) isn't reading data out of our queue fast enuf.
+	 *
+	 * NOTE: This is done based on what the current flow control of the
+	 * port is set for.
+	 *
+	 * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
+	 *	This will cause the UART's FIFO to back up, and force
+	 *	the RTS signal to be dropped.
+	 * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
+	 *	the other side, in hopes it will stop sending data to us.
+	 * 3) NONE - Nothing we can do.  We will simply drop any extra data
+	 *	that gets sent into us when the queue fills up.
+	 */
+	if (qleft < 256) {
+		/* HWFLOW */
+		if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
+			if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
+				ch->ch_bd->bd_ops->disable_receiver(ch);
+				ch->ch_flags |= (CH_RECEIVER_OFF);
+				DPR_READ(("Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
+					qleft));
+			}
+		}
+		/* SWFLOW */
+		else if (ch->ch_c_iflag & IXOFF) {
+			if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
+				ch->ch_bd->bd_ops->send_stop_character(ch);
+				ch->ch_stops_sent++;
+				DPR_READ(("Sending stop char!  Times sent: %x\n", ch->ch_stops_sent));
+			}
+		}
+		/* No FLOW */
+		else {
+			/* Empty... Can't do anything about the impending overflow... */
+		}
+	}
+
+	/*
+	 * Check to see if we should unenforce flow control because
+	 * ld (or user) finally read enuf data out of our queue.
+	 *
+	 * NOTE: This is done based on what the current flow control of the
+	 * port is set for.
+	 *
+	 * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
+	 *	This will cause the UART's FIFO to raise RTS back up,
+	 *	which will allow the other side to start sending data again.
+	 * 2) SWFLOW (IXOFF) - Send a start character to
+	 *	the other side, so it will start sending data to us again.
+	 * 3) NONE - Do nothing. Since we didn't do anything to turn off the
+	 *	other side, we don't need to do anything now.
+	 */
+	if (qleft > (RQUEUESIZE / 2)) {
+		/* HWFLOW */
+		if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
+			if (ch->ch_flags & CH_RECEIVER_OFF) {
+				ch->ch_bd->bd_ops->enable_receiver(ch);
+				ch->ch_flags &= ~(CH_RECEIVER_OFF);
+				DPR_READ(("Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
+					qleft));
+			}
+		}
+		/* SWFLOW */
+		else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
+			ch->ch_stops_sent = 0;
+			ch->ch_bd->bd_ops->send_start_character(ch);
+			DPR_READ(("Sending start char!\n"));
+		}
+		/* No FLOW */
+		else {
+			/* Nothing needed. */
+		}
+	}
+}
+
+
+void dgnc_wakeup_writes(struct channel_t *ch)
+{
+	int qlen = 0;
+	ulong lock_flags;
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 * If channel now has space, wake up anyone waiting on the condition.
+	 */
+	if ((qlen = ch->ch_w_head - ch->ch_w_tail) < 0)
+		qlen += WQUEUESIZE;
+
+	if (qlen >= (WQUEUESIZE - 256)) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	if (ch->ch_tun.un_flags & UN_ISOPEN) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+		if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			ch->ch_tun.un_tty->ldisc->ops->write_wakeup)
+		{
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			(ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty);
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+		}
+#else
+		if ((ch->ch_tun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			ch->ch_tun.un_tty->ldisc.ops->write_wakeup)
+		{
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			(ch->ch_tun.un_tty->ldisc.ops->write_wakeup)(ch->ch_tun.un_tty);
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+		}
+#endif
+
+		wake_up_interruptible(&ch->ch_tun.un_tty->write_wait);
+
+		/*
+		 * If unit is set to wait until empty, check to make sure
+		 * the queue AND FIFO are both empty.
+		 */
+		if (ch->ch_tun.un_flags & UN_EMPTY) {
+			if ((qlen == 0) && (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) {
+				ch->ch_tun.un_flags &= ~(UN_EMPTY);
+
+				/*
+				 * If RTS Toggle mode is on, whenever
+				 * the queue and UART is empty, keep RTS low.
+				 */
+				if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
+					ch->ch_mostat &= ~(UART_MCR_RTS);
+					ch->ch_bd->bd_ops->assert_modem_signals(ch);
+				}
+
+				/*
+				 * If DTR Toggle mode is on, whenever
+				 * the queue and UART is empty, keep DTR low.
+				 */
+				if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
+					ch->ch_mostat &= ~(UART_MCR_DTR);
+					ch->ch_bd->bd_ops->assert_modem_signals(ch);
+				}
+			}
+		}
+
+		wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+	}
+
+	if (ch->ch_pun.un_flags & UN_ISOPEN) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)
+		if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			ch->ch_pun.un_tty->ldisc->ops->write_wakeup)
+		{
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			(ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty);
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+		}
+#else
+		if ((ch->ch_pun.un_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			ch->ch_pun.un_tty->ldisc.ops->write_wakeup)
+		{
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			(ch->ch_pun.un_tty->ldisc.ops->write_wakeup)(ch->ch_pun.un_tty);
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+		}
+#endif
+
+		wake_up_interruptible(&ch->ch_pun.un_tty->write_wait);
+
+		/*
+		 * If unit is set to wait until empty, check to make sure
+		 * the queue AND FIFO are both empty.
+		 */
+		if (ch->ch_pun.un_flags & UN_EMPTY) {
+			if ((qlen == 0) && (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) {
+				ch->ch_pun.un_flags &= ~(UN_EMPTY);
+			}
+		}
+
+		wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+	}
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+
+/************************************************************************
+ *
+ * TTY Entry points and helper functions
+ *
+ ************************************************************************/
+
+/*
+ * dgnc_tty_open()
+ *
+ */
+static int dgnc_tty_open(struct tty_struct *tty, struct file *file)
+{
+	struct board_t	*brd;
+	struct channel_t *ch;
+	struct un_t	*un;
+	uint		major = 0;
+	uint		minor = 0;
+	int		rc = 0;
+	ulong		lock_flags;
+
+	rc = 0;
+
+	major = MAJOR(tty_devnum(tty));
+	minor = MINOR(tty_devnum(tty));
+
+	if (major > 255) {
+		return -ENXIO;
+	}
+
+	/* Get board pointer from our array of majors we have allocated */
+	brd = dgnc_BoardsByMajor[major];
+	if (!brd) {
+		return -ENXIO;
+	}
+
+	/*
+	 * If board is not yet up to a state of READY, go to
+	 * sleep waiting for it to happen or they cancel the open.
+	 */
+	rc = wait_event_interruptible(brd->state_wait,
+		(brd->state & BOARD_READY));
+
+	if (rc) {
+		return rc;
+	}
+
+	DGNC_LOCK(brd->bd_lock, lock_flags);
+
+	/* If opened device is greater than our number of ports, bail. */
+	if (PORT_NUM(minor) > brd->nasync) {
+		DGNC_UNLOCK(brd->bd_lock, lock_flags);
+		return -ENXIO;
+	}
+
+	ch = brd->channels[PORT_NUM(minor)];
+	if (!ch) {
+		DGNC_UNLOCK(brd->bd_lock, lock_flags);
+		return -ENXIO;
+	}
+
+	/* Drop board lock */
+	DGNC_UNLOCK(brd->bd_lock, lock_flags);
+
+	/* Grab channel lock */
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* Figure out our type */
+	if (!IS_PRINT(minor)) {
+		un = &brd->channels[PORT_NUM(minor)]->ch_tun;
+		un->un_type = DGNC_SERIAL;
+	}
+	else if (IS_PRINT(minor)) {
+		un = &brd->channels[PORT_NUM(minor)]->ch_pun;
+		un->un_type = DGNC_PRINT;
+	}
+	else {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		DPR_OPEN(("%d Unknown TYPE!\n", __LINE__));
+		return -ENXIO;
+	}
+
+	/*
+	 * If the port is still in a previous open, and in a state
+	 * where we simply cannot safely keep going, wait until the
+	 * state clears.
+	 */
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	rc = wait_event_interruptible(ch->ch_flags_wait, ((ch->ch_flags & CH_OPENING) == 0));
+
+	/* If ret is non-zero, user ctrl-c'ed us */
+	if (rc) {
+		DPR_OPEN(("%d User ctrl c'ed\n", __LINE__));
+		return -EINTR;
+	}
+
+	/*
+	 * If either unit is in the middle of the fragile part of close,
+	 * we just cannot touch the channel safely.
+	 * Go to sleep, knowing that when the channel can be
+	 * touched safely, the close routine will signal the
+	 * ch_flags_wait to wake us back up.
+	 */
+	rc = wait_event_interruptible(ch->ch_flags_wait,
+		(((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING) == 0));
+
+	/* If ret is non-zero, user ctrl-c'ed us */
+	if (rc) {
+		DPR_OPEN(("%d User ctrl c'ed\n", __LINE__));
+		return -EINTR;
+	}
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+
+	/* Store our unit into driver_data, so we always have it available. */
+	tty->driver_data = un;
+
+	DPR_OPEN(("Open called. MAJOR: %d MINOR:%d PORT_NUM: %x unit: %p NAME: %s\n",
+		MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), PORT_NUM(minor), un, brd->name));
+
+	DPR_OPEN(("%d: tflag=%x  pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags));
+
+	/*
+	 * Initialize tty's
+	 */
+	if (!(un->un_flags & UN_ISOPEN)) {
+		/* Store important variables. */
+		un->un_tty     = tty;
+
+		/* Maybe do something here to the TTY struct as well? */
+	}
+
+
+	/*
+	 * Allocate channel buffers for read/write/error.
+	 * Set flag, so we don't get trounced on.
+	 */
+	ch->ch_flags |= (CH_OPENING);
+
+	/* Drop locks, as malloc with GFP_KERNEL can sleep */
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	if (!ch->ch_rqueue)
+		ch->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
+	if (!ch->ch_equeue)
+		ch->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
+	if (!ch->ch_wqueue)
+		ch->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_flags &= ~(CH_OPENING);
+	wake_up_interruptible(&ch->ch_flags_wait);
+
+	/*
+	 * Initialize if neither terminal or printer is open.
+	 */
+	if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) {
+
+		DPR_OPEN(("dgnc_open: initializing channel in open...\n"));
+
+		/*
+		 * Flush input queues.
+		 */
+		ch->ch_r_head = ch->ch_r_tail = 0;
+		ch->ch_e_head = ch->ch_e_tail = 0;
+		ch->ch_w_head = ch->ch_w_tail = 0;
+
+		brd->bd_ops->flush_uart_write(ch);
+		brd->bd_ops->flush_uart_read(ch);
+
+		ch->ch_flags = 0;
+		ch->ch_cached_lsr = 0;
+		ch->ch_stop_sending_break = 0;
+		ch->ch_stops_sent = 0;
+
+		ch->ch_c_cflag   = tty->termios.c_cflag;
+		ch->ch_c_iflag   = tty->termios.c_iflag;
+		ch->ch_c_oflag   = tty->termios.c_oflag;
+		ch->ch_c_lflag   = tty->termios.c_lflag;
+		ch->ch_startc = tty->termios.c_cc[VSTART];
+		ch->ch_stopc  = tty->termios.c_cc[VSTOP];
+
+		/*
+		 * Bring up RTS and DTR...
+		 * Also handle RTS or DTR toggle if set.
+		 */
+		if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
+			ch->ch_mostat |= (UART_MCR_RTS);
+		if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
+			ch->ch_mostat |= (UART_MCR_DTR);
+
+		/* Tell UART to init itself */
+		brd->bd_ops->uart_init(ch);
+	}
+
+	/*
+	 * Run param in case we changed anything
+	 */
+	brd->bd_ops->param(tty);
+
+	dgnc_carrier(ch);
+
+	/*
+	 * follow protocol for opening port
+	 */
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	rc = dgnc_block_til_ready(tty, file, ch);
+
+	if (rc) {
+		DPR_OPEN(("dgnc_tty_open returning after dgnc_block_til_ready "
+			"with %d\n", rc));
+	}
+
+	/* No going back now, increment our unit and channel counters */
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+	ch->ch_open_count++;
+	un->un_open_count++;
+	un->un_flags |= (UN_ISOPEN);
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_OPEN(("dgnc_tty_open finished\n"));
+	return (rc);
+}
+
+
+/*
+ * dgnc_block_til_ready()
+ *
+ * Wait for DCD, if needed.
+ */
+static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch)
+{
+	int retval = 0;
+	struct un_t *un = NULL;
+	ulong   lock_flags;
+	uint	old_flags = 0;
+	int	sleep_on_un_flags = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGNC_CHANNEL_MAGIC) {
+		return (-ENXIO);
+	}
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC) {
+		return (-ENXIO);
+	}
+
+	DPR_OPEN(("dgnc_block_til_ready - before block.\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_wopen++;
+
+	/* Loop forever */
+	while (1) {
+
+		sleep_on_un_flags = 0;
+
+		/*
+		 * If board has failed somehow during our sleep, bail with error.
+		 */
+		if (ch->ch_bd->state == BOARD_FAILED) {
+			retval = -ENXIO;
+			break;
+		}
+
+		/* If tty was hung up, break out of loop and set error. */
+		if (tty_hung_up_p(file)) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		/*
+		 * If either unit is in the middle of the fragile part of close,
+		 * we just cannot touch the channel safely.
+		 * Go back to sleep, knowing that when the channel can be
+		 * touched safely, the close routine will signal the
+		 * ch_wait_flags to wake us back up.
+		 */
+		if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) {
+
+			/*
+			 * Our conditions to leave cleanly and happily:
+			 * 1) NONBLOCKING on the tty is set.
+			 * 2) CLOCAL is set.
+			 * 3) DCD (fake or real) is active.
+			 */
+
+			if (file->f_flags & O_NONBLOCK) {
+				break;
+			}
+
+			if (tty->flags & (1 << TTY_IO_ERROR)) {
+				retval = -EIO;
+				break;
+			}
+
+			if (ch->ch_flags & CH_CD) {
+				DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+				break;
+			}
+
+			if (ch->ch_flags & CH_FCAR) {
+				DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags));
+				break;
+			}
+		}
+		else {
+			sleep_on_un_flags = 1;
+		}
+
+		/*
+		 * If there is a signal pending, the user probably
+		 * interrupted (ctrl-c) us.
+		 * Leave loop with error set.
+		 */
+		if (signal_pending(current)) {
+			DPR_OPEN(("%d: signal pending...\n", __LINE__));
+			retval = -ERESTARTSYS;
+			break;
+		}
+
+		DPR_OPEN(("dgnc_block_til_ready - blocking.\n"));
+
+		/*
+		 * Store the flags before we let go of channel lock
+		 */
+		if (sleep_on_un_flags)
+			old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags;
+		else
+			old_flags = ch->ch_flags;
+
+		/*
+		 * Let go of channel lock before calling schedule.
+		 * Our poller will get any FEP events and wake us up when DCD
+		 * eventually goes active.
+		 */
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		DPR_OPEN(("Going to sleep on %s flags...\n",
+			(sleep_on_un_flags ? "un" : "ch")));
+
+		/*
+		 * Wait for something in the flags to change from the current value.
+		 */
+		if (sleep_on_un_flags) {
+			retval = wait_event_interruptible(un->un_flags_wait,
+				(old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags)));
+		}
+		else {
+			retval = wait_event_interruptible(ch->ch_flags_wait,
+				(old_flags != ch->ch_flags));
+		}
+
+		DPR_OPEN(("After sleep... retval: %x\n", retval));
+
+		/*
+		 * We got woken up for some reason.
+		 * Before looping around, grab our channel lock.
+		 */
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+	}
+
+	ch->ch_wopen--;
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_OPEN(("dgnc_block_til_ready - after blocking.\n"));
+
+	if (retval) {
+		DPR_OPEN(("dgnc_block_til_ready - done. error. retval: %x\n", retval));
+		return(retval);
+	}
+
+	DPR_OPEN(("dgnc_block_til_ready - done no error. jiffies: %lu\n", jiffies));
+
+	return(0);
+}
+
+
+/*
+ * dgnc_tty_hangup()
+ *
+ * Hangup the port.  Like a close, but don't wait for output to drain.
+ */
+static void dgnc_tty_hangup(struct tty_struct *tty)
+{
+	struct un_t	*un;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	DPR_CLOSE(("dgnc_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n",
+		un->un_ch->ch_open_count, un->un_open_count));
+
+	/* flush the transmit queues */
+	dgnc_tty_flush_buffer(tty);
+
+	DPR_CLOSE(("dgnc_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n",
+		un->un_ch->ch_open_count, un->un_open_count));
+}
+
+
+/*
+ * dgnc_tty_close()
+ *
+ */
+static void dgnc_tty_close(struct tty_struct *tty, struct file *file)
+{
+	struct ktermios *ts;
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+	int rc = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	ts = &tty->termios;
+
+	DPR_CLOSE(("Close called\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 * Determine if this is the last close or not - and if we agree about
+	 * which type of close it is with the Line Discipline
+	 */
+	if ((tty->count == 1) && (un->un_open_count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  un_open_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.
+		 */
+		APR(("tty->count is 1, un open count is %d\n", un->un_open_count));
+		un->un_open_count = 1;
+	}
+
+	if (--un->un_open_count < 0) {
+		APR(("bad serial port open count of %d\n", un->un_open_count));
+		un->un_open_count = 0;
+	}
+
+	ch->ch_open_count--;
+
+	if (ch->ch_open_count && un->un_open_count) {
+		DPR_CLOSE(("dgnc_tty_close: not last close ch: %d un:%d\n",
+			ch->ch_open_count, un->un_open_count));
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return;
+	}
+
+	/* OK, its the last close on the unit */
+	DPR_CLOSE(("dgnc_tty_close - last close on unit procedures\n"));
+
+	un->un_flags |= UN_CLOSING;
+
+	tty->closing = 1;
+
+
+	/*
+	 * Only officially close channel if count is 0 and
+	 * DIGI_PRINTER bit is not set.
+	 */
+	if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) {
+
+		ch->ch_flags &= ~(CH_STOPI | CH_FORCED_STOPI);
+
+		/*
+		 * turn off print device when closing print device.
+		 */
+		if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON) ) {
+			dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+				(int) ch->ch_digi.digi_offlen);
+			ch->ch_flags &= ~CH_PRON;
+		}
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		/* wait for output to drain */
+		/* This will also return if we take an interrupt */
+
+		DPR_CLOSE(("Calling wait_for_drain\n"));
+		rc = bd->bd_ops->drain(tty, 0);
+
+		DPR_CLOSE(("After calling wait_for_drain\n"));
+
+		if (rc) {
+			DPR_BASIC(("dgnc_tty_close - bad return: %d ", rc));
+		}
+
+		dgnc_tty_flush_buffer(tty);
+		tty_ldisc_flush(tty);
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		tty->closing = 0;
+
+		/*
+		 * If we have HUPCL set, lower DTR and RTS
+		 */
+		if (ch->ch_c_cflag & HUPCL) {
+			DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n"));
+
+			/* Drop RTS/DTR */
+			ch->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
+			bd->bd_ops->assert_modem_signals(ch);
+
+			/*
+			 * Go to sleep to ensure RTS/DTR
+			 * have been dropped for modems to see it.
+			 */
+			if (ch->ch_close_delay) {
+				DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n"));
+
+				DGNC_UNLOCK(ch->ch_lock, lock_flags);
+				dgnc_ms_sleep(ch->ch_close_delay);
+				DGNC_LOCK(ch->ch_lock, lock_flags);
+
+				DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n"));
+			}
+		}
+
+		ch->ch_old_baud = 0;
+
+		/* Turn off UART interrupts for this port */
+		ch->ch_bd->bd_ops->uart_off(ch);
+	}
+	else {
+		/*
+		 * turn off print device when closing print device.
+		 */
+		if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON) ) {
+			dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+				(int) ch->ch_digi.digi_offlen);
+			ch->ch_flags &= ~CH_PRON;
+		}
+	}
+
+	un->un_tty = NULL;
+	un->un_flags &= ~(UN_ISOPEN | UN_CLOSING);
+
+	DPR_CLOSE(("Close. Doing wakeups\n"));
+	wake_up_interruptible(&ch->ch_flags_wait);
+	wake_up_interruptible(&un->un_flags_wait);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_BASIC(("dgnc_tty_close - complete\n"));
+}
+
+
+/*
+ * dgnc_tty_chars_in_buffer()
+ *
+ * Return number of characters that have not been transmitted yet.
+ *
+ * This routine is used by the line discipline to determine if there
+ * is data waiting to be transmitted/drained/flushed or not.
+ */
+static int dgnc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+	ushort thead;
+	ushort ttail;
+	uint tmask;
+	uint chars = 0;
+	ulong   lock_flags = 0;
+
+	if (tty == NULL)
+		return(0);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	tmask = WQUEUEMASK;
+	thead = ch->ch_w_head & tmask;
+	ttail = ch->ch_w_tail & tmask;
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	if (ttail == thead) {
+		chars = 0;
+	} else {
+		if (thead >= ttail)
+			chars = thead - ttail;
+		else
+			chars = thead - ttail + WQUEUESIZE;
+	}
+
+	DPR_WRITE(("dgnc_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d)\n",
+		ch->ch_portnum, chars, thead, ttail));
+
+	return(chars);
+}
+
+
+/*
+ * dgnc_maxcps_room
+ *
+ * Reduces bytes_available to the max number of characters
+ * that can be sent currently given the maxcps value, and
+ * returns the new bytes_available.  This only affects printer
+ * output.
+ */
+static int dgnc_maxcps_room(struct tty_struct *tty, int bytes_available)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+
+	if (!tty)
+		return (bytes_available);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (bytes_available);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (bytes_available);
+
+	/*
+	 * If its not the Transparent print device, return
+	 * the full data amount.
+	 */
+	if (un->un_type != DGNC_PRINT)
+		return (bytes_available);
+
+	if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) {
+		int cps_limit = 0;
+		unsigned long current_time = jiffies;
+		unsigned long buffer_time = current_time +
+			(HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps;
+
+		if (ch->ch_cpstime < current_time) {
+			/* buffer is empty */
+			ch->ch_cpstime = current_time;	    /* reset ch_cpstime */
+			cps_limit = ch->ch_digi.digi_bufsize;
+		}
+		else if (ch->ch_cpstime < buffer_time) {
+			/* still room in the buffer */
+			cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ;
+		}
+		else {
+			/* no room in the buffer */
+			cps_limit = 0;
+		}
+
+		bytes_available = min(cps_limit, bytes_available);
+	}
+
+	return (bytes_available);
+}
+
+
+/*
+ * dgnc_tty_write_room()
+ *
+ * Return space available in Tx buffer
+ */
+static int dgnc_tty_write_room(struct tty_struct *tty)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+	ushort head;
+	ushort tail;
+	ushort tmask;
+	int ret = 0;
+	ulong   lock_flags = 0;
+
+	if (tty == NULL || dgnc_TmpWriteBuf == NULL)
+		return(0);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (0);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (0);
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	tmask = WQUEUEMASK;
+	head = (ch->ch_w_head) & tmask;
+	tail = (ch->ch_w_tail) & tmask;
+
+	if ((ret = tail - head - 1) < 0)
+		ret += WQUEUESIZE;
+
+	/* Limit printer to maxcps */
+	ret = dgnc_maxcps_room(tty, ret);
+
+	/*
+	 * If we are printer device, leave space for
+	 * possibly both the on and off strings.
+	 */
+	if (un->un_type == DGNC_PRINT) {
+		if (!(ch->ch_flags & CH_PRON))
+			ret -= ch->ch_digi.digi_onlen;
+		ret -= ch->ch_digi.digi_offlen;
+	}
+	else {
+		if (ch->ch_flags & CH_PRON)
+			ret -= ch->ch_digi.digi_offlen;
+	}
+
+	if (ret < 0)
+		ret = 0;
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_WRITE(("dgnc_tty_write_room - %d tail: %d head: %d\n", ret, tail, head));
+
+	return(ret);
+}
+
+
+/*
+ * dgnc_tty_put_char()
+ *
+ * Put a character into ch->ch_buf
+ *
+ *      - used by the line discipline for OPOST processing
+ */
+static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c)
+{
+	/*
+	 * Simply call tty_write.
+	 */
+	DPR_WRITE(("dgnc_tty_put_char called\n"));
+	dgnc_tty_write(tty, &c, 1);
+	return 1;
+}
+
+
+/*
+ * dgnc_tty_write()
+ *
+ * Take data from the user or kernel and send it out to the FEP.
+ * In here exists all the Transparent Print magic as well.
+ */
+static int dgnc_tty_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct channel_t *ch = NULL;
+	struct un_t *un = NULL;
+	int bufcount = 0, n = 0;
+	int orig_count = 0;
+	ulong lock_flags;
+	ushort head;
+	ushort tail;
+	ushort tmask;
+	uint remain;
+	int from_user = 0;
+
+	if (tty == NULL || dgnc_TmpWriteBuf == NULL)
+		return(0);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return(0);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return(0);
+
+	if (!count)
+		return(0);
+
+	DPR_WRITE(("dgnc_tty_write: Port: %x tty=%p user=%d len=%d\n",
+		ch->ch_portnum, tty, from_user, count));
+
+	/*
+	 * Store original amount of characters passed in.
+	 * This helps to figure out if we should ask the FEP
+	 * to send us an event when it has more space available.
+	 */
+	orig_count = count;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* Get our space available for the channel from the board */
+	tmask = WQUEUEMASK;
+	head = (ch->ch_w_head) & tmask;
+	tail = (ch->ch_w_tail) & tmask;
+
+	if ((bufcount = tail - head - 1) < 0)
+		bufcount += WQUEUESIZE;
+
+	DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n",
+		__LINE__, bufcount, count, tail, head, tmask));
+
+	/*
+	 * Limit printer output to maxcps overall, with bursts allowed
+	 * up to bufsize characters.
+	 */
+	bufcount = dgnc_maxcps_room(tty, bufcount);
+
+	/*
+	 * Take minimum of what the user wants to send, and the
+	 * space available in the FEP buffer.
+	 */
+	count = min(count, bufcount);
+
+	/*
+	 * Bail if no space left.
+	 */
+	if (count <= 0) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(0);
+	}
+
+	/*
+	 * Output the printer ON string, if we are in terminal mode, but
+	 * need to be in printer mode.
+	 */
+	if ((un->un_type == DGNC_PRINT) && !(ch->ch_flags & CH_PRON)) {
+		dgnc_wmove(ch, ch->ch_digi.digi_onstr,
+		    (int) ch->ch_digi.digi_onlen);
+		head = (ch->ch_w_head) & tmask;
+		ch->ch_flags |= CH_PRON;
+	}
+
+	/*
+	 * On the other hand, output the printer OFF string, if we are
+	 * currently in printer mode, but need to output to the terminal.
+	 */
+	if ((un->un_type != DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
+		dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+			(int) ch->ch_digi.digi_offlen);
+		head = (ch->ch_w_head) & tmask;
+		ch->ch_flags &= ~CH_PRON;
+	}
+
+	/*
+	 * If there is nothing left to copy, or I can't handle any more data, leave.
+	 */
+	if (count <= 0) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(0);
+	}
+
+	if (from_user) {
+
+		count = min(count, WRITEBUFLEN);
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		/*
+		 * If data is coming from user space, copy it into a temporary
+		 * buffer so we don't get swapped out while doing the copy to
+		 * the board.
+		 */
+		/* we're allowed to block if it's from_user */
+		if (down_interruptible(&dgnc_TmpWriteSem)) {
+			return (-EINTR);
+		}
+
+		/*
+		 * copy_from_user() returns the number
+		 * of bytes that could *NOT* be copied.
+		 */
+		count -= copy_from_user(dgnc_TmpWriteBuf, (const uchar __user *) buf, count);
+
+		if (!count) {
+			up(&dgnc_TmpWriteSem);
+			return(-EFAULT);
+		}
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		buf = dgnc_TmpWriteBuf;
+
+	}
+
+	n = count;
+
+	/*
+	 * If the write wraps over the top of the circular buffer,
+	 * move the portion up to the wrap point, and reset the
+	 * pointers to the bottom.
+	 */
+	remain = WQUEUESIZE - head;
+
+	if (n >= remain) {
+		n -= remain;
+		memcpy(ch->ch_wqueue + head, buf, remain);
+		dgnc_sniff_nowait_nolock(ch, "USER WRITE", ch->ch_wqueue + head, remain);
+		head = 0;
+		buf += remain;
+	}
+
+	if (n > 0) {
+		/*
+		 * Move rest of data.
+		 */
+		remain = n;
+		memcpy(ch->ch_wqueue + head, buf, remain);
+		dgnc_sniff_nowait_nolock(ch, "USER WRITE", ch->ch_wqueue + head, remain);
+		head += remain;
+	}
+
+	if (count) {
+		head &= tmask;
+		ch->ch_w_head = head;
+	}
+
+#if 0
+	/*
+	 * If this is the print device, and the
+	 * printer is still on, we need to turn it
+	 * off before going idle.
+	 */
+	if (count == orig_count) {
+		if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) {
+			head &= tmask;
+			ch->ch_w_head = head;
+			dgnc_wmove(ch, ch->ch_digi.digi_offstr,
+				(int) ch->ch_digi.digi_offlen);
+			head = (ch->ch_w_head) & tmask;
+			ch->ch_flags &= ~CH_PRON;
+		}
+	}
+#endif
+
+	/* Update printer buffer empty time. */
+	if ((un->un_type == DGNC_PRINT) && (ch->ch_digi.digi_maxcps > 0)
+	    && (ch->ch_digi.digi_bufsize > 0)) {
+		ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps;
+	}
+
+	if (from_user) {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		up(&dgnc_TmpWriteSem);
+	} else {
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+	}
+
+	DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count));
+
+	if (count) {
+		/*
+		 * Channel lock is grabbed and then released
+		 * inside this routine.
+		 */
+		ch->ch_bd->bd_ops->copy_data_from_queue_to_uart(ch);
+	}
+
+	return (count);
+}
+
+
+/*
+ * Return modem signals to ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgnc_tty_tiocmget(struct tty_struct *tty)
+#else
+static int dgnc_tty_tiocmget(struct tty_struct *tty, struct file *file)
+#endif
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	int result = -EIO;
+	uchar mstat = 0;
+	ulong   lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return result;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return result;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return result;
+
+	DPR_IOCTL(("dgnc_tty_tiocmget start\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	mstat = (ch->ch_mostat | ch->ch_mistat);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	result = 0;
+
+	if (mstat & UART_MCR_DTR)
+		result |= TIOCM_DTR;
+	if (mstat & UART_MCR_RTS)
+		result |= TIOCM_RTS;
+	if (mstat & UART_MSR_CTS)
+		result |= TIOCM_CTS;
+	if (mstat & UART_MSR_DSR)
+		result |= TIOCM_DSR;
+	if (mstat & UART_MSR_RI)
+		result |= TIOCM_RI;
+	if (mstat & UART_MSR_DCD)
+		result |= TIOCM_CD;
+
+	DPR_IOCTL(("dgnc_tty_tiocmget finish\n"));
+
+	return result;
+}
+
+
+/*
+ * dgnc_tty_tiocmset()
+ *
+ * Set modem signals, called by ld.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+static int dgnc_tty_tiocmset(struct tty_struct *tty,
+		unsigned int set, unsigned int clear)
+#else
+static int dgnc_tty_tiocmset(struct tty_struct *tty, struct file *file,
+		unsigned int set, unsigned int clear)
+#endif
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int ret = -EIO;
+	ulong   lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return ret;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return ret;
+
+	DPR_IOCTL(("dgnc_tty_tiocmset start\n"));
+
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	if (set & TIOCM_RTS) {
+		ch->ch_mostat |= UART_MCR_RTS;
+	}
+
+	if (set & TIOCM_DTR) {
+		ch->ch_mostat |= UART_MCR_DTR;
+	}
+
+	if (clear & TIOCM_RTS) {
+		ch->ch_mostat &= ~(UART_MCR_RTS);
+	}
+
+	if (clear & TIOCM_DTR) {
+		ch->ch_mostat &= ~(UART_MCR_DTR);
+	}
+
+	ch->ch_bd->bd_ops->assert_modem_signals(ch);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_tiocmset finish\n"));
+
+	return (0);
+}
+
+
+/*
+ * dgnc_tty_send_break()
+ *
+ * Send a Break, called by ld.
+ */
+static int dgnc_tty_send_break(struct tty_struct *tty, int msec)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int ret = -EIO;
+	ulong   lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return ret;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return ret;
+
+	switch (msec) {
+	case -1:
+		msec = 0xFFFF;
+		break;
+	case 0:
+		msec = 0;
+		break;
+	default:
+		break;
+	}
+
+	DPR_IOCTL(("dgnc_tty_send_break start 1.  %lx\n", jiffies));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_bd->bd_ops->send_break(ch, msec);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_send_break finish\n"));
+
+	return (0);
+
+}
+
+
+/*
+ * dgnc_tty_wait_until_sent()
+ *
+ * wait until data has been transmitted, called by ld.
+ */
+static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int rc;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	rc = bd->bd_ops->drain(tty, 0);
+	if (rc) {
+		DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+		return;
+	}
+	return;
+}
+
+
+/*
+ * dgnc_send_xchar()
+ *
+ * send a high priority character, called by ld.
+ */
+static void dgnc_tty_send_xchar(struct tty_struct *tty, char c)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgnc_tty_send_xchar start\n"));
+	printk("dgnc_tty_send_xchar start\n");
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+	bd->bd_ops->send_immediate_char(ch, c);
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_send_xchar finish\n"));
+	printk("dgnc_tty_send_xchar finish\n");
+	return;
+}
+
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+static inline int dgnc_get_mstat(struct channel_t *ch)
+{
+	unsigned char mstat;
+	int result = -EIO;
+	ulong   lock_flags;
+
+	DPR_IOCTL(("dgnc_getmstat start\n"));
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return(-ENXIO);
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	mstat = (ch->ch_mostat | ch->ch_mistat);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	result = 0;
+
+	if (mstat & UART_MCR_DTR)
+		result |= TIOCM_DTR;
+	if (mstat & UART_MCR_RTS)
+		result |= TIOCM_RTS;
+	if (mstat & UART_MSR_CTS)
+		result |= TIOCM_CTS;
+	if (mstat & UART_MSR_DSR)
+		result |= TIOCM_DSR;
+	if (mstat & UART_MSR_RI)
+		result |= TIOCM_RI;
+	if (mstat & UART_MSR_DCD)
+		result |= TIOCM_CD;
+
+	DPR_IOCTL(("dgnc_getmstat finish\n"));
+
+	return(result);
+}
+
+
+
+/*
+ * Return modem signals to ld.
+ */
+static int dgnc_get_modem_info(struct channel_t *ch, unsigned int  __user *value)
+{
+	int result;
+	int rc;
+
+	DPR_IOCTL(("dgnc_get_modem_info start\n"));
+
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return(-ENXIO);
+
+	result = dgnc_get_mstat(ch);
+
+	if (result < 0)
+		return (-ENXIO);
+
+	rc = put_user(result, value);
+
+	DPR_IOCTL(("dgnc_get_modem_info finish\n"));
+	return(rc);
+}
+
+
+/*
+ * dgnc_set_modem_info()
+ *
+ * Set modem signals, called by ld.
+ */
+static int dgnc_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int ret = -ENXIO;
+	unsigned int arg = 0;
+	ulong   lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return ret;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return ret;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return ret;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return ret;
+
+	ret = 0;
+
+	DPR_IOCTL(("dgnc_set_modem_info() start\n"));
+
+	ret = get_user(arg, value);
+	if (ret)
+		return(ret);
+
+	switch (command) {
+	case TIOCMBIS:
+		if (arg & TIOCM_RTS) {
+			ch->ch_mostat |= UART_MCR_RTS;
+		}
+
+		if (arg & TIOCM_DTR) {
+			ch->ch_mostat |= UART_MCR_DTR;
+		}
+
+		break;
+
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS) {
+			ch->ch_mostat &= ~(UART_MCR_RTS);
+		}
+
+		if (arg & TIOCM_DTR) {
+			ch->ch_mostat &= ~(UART_MCR_DTR);
+		}
+
+		break;
+
+	case TIOCMSET:
+
+		if (arg & TIOCM_RTS) {
+			ch->ch_mostat |= UART_MCR_RTS;
+		}
+		else {
+			ch->ch_mostat &= ~(UART_MCR_RTS);
+		}
+
+		if (arg & TIOCM_DTR) {
+			ch->ch_mostat |= UART_MCR_DTR;
+		}
+		else {
+			ch->ch_mostat &= ~(UART_MCR_DTR);
+		}
+
+		break;
+
+	default:
+		return(-EINVAL);
+	}
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_bd->bd_ops->assert_modem_signals(ch);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_set_modem_info finish\n"));
+
+	return (0);
+}
+
+
+/*
+ * dgnc_tty_digigeta()
+ *
+ * Ioctl to get the information for ditty.
+ *
+ *
+ *
+ */
+static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	struct digi_t tmp;
+	ulong   lock_flags;
+
+	if (!retinfo)
+		return (-EFAULT);
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+	memcpy(&tmp, &ch->ch_digi, sizeof(tmp));
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return (-EFAULT);
+
+	return (0);
+}
+
+
+/*
+ * dgnc_tty_digiseta()
+ *
+ * Ioctl to set the information for ditty.
+ *
+ *
+ *
+ */
+static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	struct digi_t new_digi;
+	ulong lock_flags;
+
+	DPR_IOCTL(("DIGI_SETA start\n"));
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-EFAULT);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (-EFAULT);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (-EFAULT);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (-EFAULT);
+
+	if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) {
+		DPR_IOCTL(("DIGI_SETA failed copy_from_user\n"));
+		return(-EFAULT);
+	}
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/*
+	 * Handle transistions to and from RTS Toggle.
+	 */
+	if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && (new_digi.digi_flags & DIGI_RTS_TOGGLE))
+		ch->ch_mostat &= ~(UART_MCR_RTS);
+	if ((ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && !(new_digi.digi_flags & DIGI_RTS_TOGGLE))
+		ch->ch_mostat |= (UART_MCR_RTS);
+
+	/*
+	 * Handle transistions to and from DTR Toggle.
+	 */
+	if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && (new_digi.digi_flags & DIGI_DTR_TOGGLE))
+		ch->ch_mostat &= ~(UART_MCR_DTR);
+	if ((ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && !(new_digi.digi_flags & DIGI_DTR_TOGGLE))
+		ch->ch_mostat |= (UART_MCR_DTR);
+
+	memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t));
+
+	if (ch->ch_digi.digi_maxcps < 1)
+		ch->ch_digi.digi_maxcps = 1;
+
+	if (ch->ch_digi.digi_maxcps > 10000)
+		ch->ch_digi.digi_maxcps = 10000;
+
+	if (ch->ch_digi.digi_bufsize < 10)
+		ch->ch_digi.digi_bufsize = 10;
+
+	if (ch->ch_digi.digi_maxchar < 1)
+		ch->ch_digi.digi_maxchar = 1;
+
+	if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize)
+		ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize;
+
+	if (ch->ch_digi.digi_onlen > DIGI_PLEN)
+		ch->ch_digi.digi_onlen = DIGI_PLEN;
+
+	if (ch->ch_digi.digi_offlen > DIGI_PLEN)
+		ch->ch_digi.digi_offlen = DIGI_PLEN;
+
+	ch->ch_bd->bd_ops->param(tty);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("DIGI_SETA finish\n"));
+
+	return(0);
+}
+
+
+/*
+ * dgnc_set_termios()
+ */
+static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	unsigned long lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_c_cflag   = tty->termios.c_cflag;
+	ch->ch_c_iflag   = tty->termios.c_iflag;
+	ch->ch_c_oflag   = tty->termios.c_oflag;
+	ch->ch_c_lflag   = tty->termios.c_lflag;
+	ch->ch_startc = tty->termios.c_cc[VSTART];
+	ch->ch_stopc  = tty->termios.c_cc[VSTOP];
+
+	ch->ch_bd->bd_ops->param(tty);
+	dgnc_carrier(ch);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+}
+
+
+static void dgnc_tty_throttle(struct tty_struct *tty)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags = 0;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgnc_tty_throttle start\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_flags |= (CH_FORCED_STOPI);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_throttle finish\n"));
+}
+
+
+static void dgnc_tty_unthrottle(struct tty_struct *tty)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong   lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgnc_tty_unthrottle start\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_flags &= ~(CH_FORCED_STOPI);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_unthrottle finish\n"));
+}
+
+
+static void dgnc_tty_start(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgcn_tty_start start\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_flags &= ~(CH_FORCED_STOP);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_start finish\n"));
+}
+
+
+static void dgnc_tty_stop(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgnc_tty_stop start\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_flags |= (CH_FORCED_STOP);
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_stop finish\n"));
+}
+
+
+/*
+ * dgnc_tty_flush_chars()
+ *
+ * Flush the cook buffer
+ *
+ * Note to self, and any other poor souls who venture here:
+ *
+ * flush in this case DOES NOT mean dispose of the data.
+ * instead, it means "stop buffering and send it if you
+ * haven't already."  Just guess how I figured that out...   SRW 2-Jun-98
+ *
+ * It is also always called in interrupt context - JAR 8-Sept-99
+ */
+static void dgnc_tty_flush_chars(struct tty_struct *tty)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgnc_tty_flush_chars start\n"));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	/* Do something maybe here */
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_flush_chars finish\n"));
+}
+
+
+
+/*
+ * dgnc_tty_flush_buffer()
+ *
+ * Flush Tx buffer (make in == out)
+ */
+static void dgnc_tty_flush_buffer(struct tty_struct *tty)
+{
+	struct channel_t *ch;
+	struct un_t *un;
+	ulong lock_flags;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return;
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return;
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return;
+
+	DPR_IOCTL(("dgnc_tty_flush_buffer on port: %d start\n", ch->ch_portnum));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	ch->ch_flags &= ~CH_STOP;
+
+	/* Flush our write queue */
+	ch->ch_w_head = ch->ch_w_tail;
+
+	/* Flush UARTs transmit FIFO */
+	ch->ch_bd->bd_ops->flush_uart_write(ch);
+
+	if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+		ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+		wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+	}
+	if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+		ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+		wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+	}
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_flush_buffer finish\n"));
+}
+
+
+
+/*****************************************************************************
+ *
+ * The IOCTL function and all of its helpers
+ *
+ *****************************************************************************/
+
+/*
+ * dgnc_tty_ioctl()
+ *
+ * The usual assortment of ioctl's
+ */
+static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
+		unsigned long arg)
+{
+	struct board_t *bd;
+	struct channel_t *ch;
+	struct un_t *un;
+	int rc;
+	ulong lock_flags;
+	void __user *uarg = (void __user *) arg;
+
+	if (!tty || tty->magic != TTY_MAGIC)
+		return (-ENODEV);
+
+	un = tty->driver_data;
+	if (!un || un->magic != DGNC_UNIT_MAGIC)
+		return (-ENODEV);
+
+	ch = un->un_ch;
+	if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
+		return (-ENODEV);
+
+	bd = ch->ch_bd;
+	if (!bd || bd->magic != DGNC_BOARD_MAGIC)
+		return (-ENODEV);
+
+	DPR_IOCTL(("dgnc_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n",
+		ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+	DGNC_LOCK(ch->ch_lock, lock_flags);
+
+	if (un->un_open_count <= 0) {
+		DPR_BASIC(("dgnc_tty_ioctl - unit not open.\n"));
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(-EIO);
+	}
+
+	switch (cmd) {
+
+	/* Here are all the standard ioctl's that we MUST implement */
+
+	case TCSBRK:
+		/*
+		 * TCSBRK is SVID version: non-zero arg --> no break
+		 * this behaviour is exploited by tcdrain().
+		 *
+		 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+		 * between 0.25 and 0.5 seconds so we'll ask for something
+		 * in the middle: 0.375 seconds.
+		 */
+		rc = tty_check_change(tty);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		if (rc) {
+			return(rc);
+		}
+
+		rc = ch->ch_bd->bd_ops->drain(tty, 0);
+
+		if (rc) {
+			DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) {
+			ch->ch_bd->bd_ops->send_break(ch, 250);
+		}
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+			ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+		return(0);
+
+
+	case TCSBRKP:
+		/* support for POSIX tcsendbreak()
+		 * According to POSIX.1 spec (7.2.2.1.2) breaks should be
+		 * between 0.25 and 0.5 seconds so we'll ask for something
+		 * in the middle: 0.375 seconds.
+		 */
+		rc = tty_check_change(tty);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		if (rc) {
+			return(rc);
+		}
+
+		rc = ch->ch_bd->bd_ops->drain(tty, 0);
+		if (rc) {
+			DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		ch->ch_bd->bd_ops->send_break(ch, 250);
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+			ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+		return(0);
+
+	case TIOCSBRK:
+		rc = tty_check_change(tty);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		if (rc) {
+			return(rc);
+		}
+
+		rc = ch->ch_bd->bd_ops->drain(tty, 0);
+		if (rc) {
+			DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		ch->ch_bd->bd_ops->send_break(ch, 250);
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+			ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+		return(0);
+
+	case TIOCCBRK:
+		/* Do Nothing */
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return 0;
+
+	case TIOCGSOFTCAR:
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg);
+		return(rc);
+
+	case TIOCSSOFTCAR:
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = get_user(arg, (unsigned long __user *) arg);
+		if (rc)
+			return(rc);
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+		tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+		ch->ch_bd->bd_ops->param(tty);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		return(0);
+
+	case TIOCMGET:
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(dgnc_get_modem_info(ch, uarg));
+
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(dgnc_set_modem_info(tty, cmd, uarg));
+
+		/*
+		 * Here are any additional ioctl's that we want to implement
+		 */
+
+	case TCFLSH:
+		/*
+		 * The linux tty driver doesn't have a flush
+		 * input routine for the driver, assuming all backed
+		 * up data is in the line disc. buffers.  However,
+		 * we all know that's not the case.  Here, we
+		 * act on the ioctl, but then lie and say we didn't
+		 * so the line discipline will process the flush
+		 * also.
+		 */
+		rc = tty_check_change(tty);
+		if (rc) {
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			return(rc);
+		}
+
+		if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) {
+			ch->ch_r_head = ch->ch_r_tail;
+			ch->ch_bd->bd_ops->flush_uart_read(ch);
+			/* Force queue flow control to be released, if needed */
+			dgnc_check_queue_flow_control(ch);
+		}
+
+		if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) {
+			if (!(un->un_type == DGNC_PRINT)) {
+				ch->ch_w_head = ch->ch_w_tail;
+				ch->ch_bd->bd_ops->flush_uart_write(ch);
+
+				if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) {
+					ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY);
+					wake_up_interruptible(&ch->ch_tun.un_flags_wait);
+				}
+
+				if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) {
+					ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY);
+					wake_up_interruptible(&ch->ch_pun.un_flags_wait);
+				}
+
+			}
+		}
+
+		/* pretend we didn't recognize this IOCTL */
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(-ENOIOCTLCMD);
+	case TCSETSF:
+	case TCSETSW:
+		/*
+		 * The linux tty driver doesn't have a flush
+		 * input routine for the driver, assuming all backed
+		 * up data is in the line disc. buffers.  However,
+		 * we all know that's not the case.  Here, we
+		 * act on the ioctl, but then lie and say we didn't
+		 * so the line discipline will process the flush
+		 * also.
+		 */
+		if (cmd == TCSETSF) {
+			/* flush rx */
+			ch->ch_flags &= ~CH_STOP;
+			ch->ch_r_head = ch->ch_r_tail;
+			ch->ch_bd->bd_ops->flush_uart_read(ch);
+			/* Force queue flow control to be released, if needed */
+			dgnc_check_queue_flow_control(ch);
+		}
+
+		/* now wait for all the output to drain */
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = ch->ch_bd->bd_ops->drain(tty, 0);
+		if (rc) {
+			DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d\n", rc));
+			return(-EINTR);
+		}
+
+		DPR_IOCTL(("dgnc_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n",
+			ch->ch_portnum, dgnc_ioctl_name(cmd), cmd, arg));
+
+		/* pretend we didn't recognize this */
+		return(-ENOIOCTLCMD);
+
+	case TCSETAW:
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = ch->ch_bd->bd_ops->drain(tty, 0);
+		if (rc) {
+			DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+			return(-EINTR);
+		}
+
+		/* pretend we didn't recognize this */
+		return(-ENOIOCTLCMD);
+
+	case TCXONC:
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		/* Make the ld do it */
+		return(-ENOIOCTLCMD);
+
+	case DIGI_GETA:
+		/* get information for ditty */
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(dgnc_tty_digigeta(tty, uarg));
+
+	case DIGI_SETAW:
+	case DIGI_SETAF:
+
+		/* set information for ditty */
+		if (cmd == (DIGI_SETAW)) {
+
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			rc = ch->ch_bd->bd_ops->drain(tty, 0);
+			if (rc) {
+				DPR_IOCTL(("dgnc_tty_ioctl - bad return: %d ", rc));
+				return(-EINTR);
+			}
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+		}
+		else {
+			tty_ldisc_flush(tty);
+		}
+		/* fall thru */
+
+	case DIGI_SETA:
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(dgnc_tty_digiseta(tty, uarg));
+
+	case DIGI_LOOPBACK:
+		{
+			uint loopback = 0;
+			/* Let go of locks when accessing user space, could sleep */
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			rc = get_user(loopback, (unsigned int __user *) arg);
+			if (rc)
+				return(rc);
+			DGNC_LOCK(ch->ch_lock, lock_flags);
+
+			/* Enable/disable internal loopback for this port */
+			if (loopback)
+				ch->ch_flags |= CH_LOOPBACK;
+			else
+				ch->ch_flags &= ~(CH_LOOPBACK);
+
+			ch->ch_bd->bd_ops->param(tty);
+			DGNC_UNLOCK(ch->ch_lock, lock_flags);
+			return(0);
+		}
+
+	case DIGI_GETCUSTOMBAUD:
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = put_user(ch->ch_custom_speed, (unsigned int __user *) arg);
+		return(rc);
+
+	case DIGI_SETCUSTOMBAUD:
+	{
+		uint new_rate;
+		/* Let go of locks when accessing user space, could sleep */
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = get_user(new_rate, (unsigned int __user *) arg);
+		if (rc)
+			return(rc);
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+		dgnc_set_custom_speed(ch, new_rate);
+		ch->ch_bd->bd_ops->param(tty);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(0);
+	}
+
+	/*
+	 * This ioctl allows insertion of a character into the front
+	 * of any pending data to be transmitted.
+	 *
+	 * This ioctl is to satify the "Send Character Immediate"
+	 * call that the RealPort protocol spec requires.
+	 */
+	case DIGI_REALPORT_SENDIMMEDIATE:
+	{
+		unsigned char c;
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = get_user(c, (unsigned char __user *) arg);
+		if (rc)
+			return(rc);
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+		ch->ch_bd->bd_ops->send_immediate_char(ch, c);
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		return(0);
+	}
+
+	/*
+	 * This ioctl returns all the current counts for the port.
+	 *
+	 * This ioctl is to satify the "Line Error Counters"
+	 * call that the RealPort protocol spec requires.
+	 */
+	case DIGI_REALPORT_GETCOUNTERS:
+	{
+		struct digi_getcounter buf;
+
+		buf.norun = ch->ch_err_overrun;
+		buf.noflow = 0;  	/* The driver doesn't keep this stat */
+		buf.nframe = ch->ch_err_frame;
+		buf.nparity = ch->ch_err_parity;
+		buf.nbreak = ch->ch_err_break;
+		buf.rbytes = ch->ch_rxcount;
+		buf.tbytes = ch->ch_txcount;
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		if (copy_to_user(uarg, &buf, sizeof(struct digi_getcounter))) {
+			return (-EFAULT);
+		}
+		return(0);
+	}
+
+	/*
+	 * This ioctl returns all current events.
+	 *
+	 * This ioctl is to satify the "Event Reporting"
+	 * call that the RealPort protocol spec requires.
+	 */
+	case DIGI_REALPORT_GETEVENTS:
+	{
+		unsigned int events = 0;
+
+		/* NOTE: MORE EVENTS NEEDS TO BE ADDED HERE */
+		if (ch->ch_flags & CH_BREAK_SENDING)
+			events |= EV_TXB;
+		if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP)) {
+			events |= (EV_OPU | EV_OPS);
+		}
+		if ((ch->ch_flags & CH_STOPI) || (ch->ch_flags & CH_FORCED_STOPI)) {
+			events |= (EV_IPU | EV_IPS);
+		}
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+		rc = put_user(events, (unsigned int __user *) arg);
+		return(rc);
+	}
+
+	/*
+	 * This ioctl returns TOUT and TIN counters based
+	 * upon the values passed in by the RealPort Server.
+	 * It also passes back whether the UART Transmitter is
+	 * empty as well.
+	 */
+	case DIGI_REALPORT_GETBUFFERS:
+	{
+		struct digi_getbuffer buf;
+		int tdist;
+		int count;
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		/*
+		 * Get data from user first.
+		 */
+		if (copy_from_user(&buf, uarg, sizeof(struct digi_getbuffer))) {
+			return (-EFAULT);
+		}
+
+		DGNC_LOCK(ch->ch_lock, lock_flags);
+
+		/*
+		 * Figure out how much data is in our RX and TX queues.
+		 */
+		buf.rxbuf = (ch->ch_r_head - ch->ch_r_tail) & RQUEUEMASK;
+		buf.txbuf = (ch->ch_w_head - ch->ch_w_tail) & WQUEUEMASK;
+
+		/*
+		 * Is the UART empty? Add that value to whats in our TX queue.
+		 */
+		count = buf.txbuf + ch->ch_bd->bd_ops->get_uart_bytes_left(ch);
+
+		/*
+		 * Figure out how much data the RealPort Server believes should
+		 * be in our TX queue.
+		 */
+		tdist = (buf.tIn - buf.tOut) & 0xffff;
+
+		/*
+		 * If we have more data than the RealPort Server believes we
+		 * should have, reduce our count to its amount.
+		 *
+		 * This count difference CAN happen because the Linux LD can
+		 * insert more characters into our queue for OPOST processing
+		 * that the RealPort Server doesn't know about.
+		 */
+		if (buf.txbuf > tdist) {
+			buf.txbuf = tdist;
+		}
+
+		/*
+		 * Report whether our queue and UART TX are completely empty.
+		 */
+		if (count) {
+			buf.txdone = 0;
+		} else {
+			buf.txdone = 1;
+		}
+
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		if (copy_to_user(uarg, &buf, sizeof(struct digi_getbuffer))) {
+			return (-EFAULT);
+		}
+		return(0);
+	}
+	default:
+		DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+		DPR_IOCTL(("dgnc_tty_ioctl - in default\n"));
+		DPR_IOCTL(("dgnc_tty_ioctl end - cmd %s (%x), arg %lx\n",
+			dgnc_ioctl_name(cmd), cmd, arg));
+
+		return(-ENOIOCTLCMD);
+	}
+
+	DGNC_UNLOCK(ch->ch_lock, lock_flags);
+
+	DPR_IOCTL(("dgnc_tty_ioctl end - cmd %s (%x), arg %lx\n",
+		dgnc_ioctl_name(cmd), cmd, arg));
+
+	return(0);
+}
diff --git a/drivers/staging/dgnc/dgnc_tty.h b/drivers/staging/dgnc/dgnc_tty.h
new file mode 100644
index 0000000..deb388d
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_tty.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_TTY_H
+#define __DGNC_TTY_H
+
+#include "dgnc_driver.h"
+
+int	dgnc_tty_register(struct board_t *brd);
+
+int	dgnc_tty_preinit(void);
+int     dgnc_tty_init(struct board_t *);
+
+void	dgnc_tty_post_uninit(void);
+void	dgnc_tty_uninit(struct board_t *);
+
+void	dgnc_input(struct channel_t *ch);
+void	dgnc_carrier(struct channel_t *ch);
+void	dgnc_wakeup_writes(struct channel_t *ch);
+void	dgnc_check_queue_flow_control(struct channel_t *ch);
+
+void	dgnc_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int nbuf);
+
+#endif
diff --git a/drivers/staging/dgnc/dgnc_types.h b/drivers/staging/dgnc/dgnc_types.h
new file mode 100644
index 0000000..4fa3585
--- /dev/null
+++ b/drivers/staging/dgnc/dgnc_types.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DGNC_TYPES_H
+#define __DGNC_TYPES_H
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+/* Required for our shared headers! */
+typedef unsigned char uchar;
+
+#endif
diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h
new file mode 100644
index 0000000..eb6e371
--- /dev/null
+++ b/drivers/staging/dgnc/digi.h
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *	Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *	NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+#ifndef __DIGI_H
+#define __DIGI_H
+
+/************************************************************************
+ ***	Definitions for Digi ditty(1) command.
+ ************************************************************************/
+
+
+/*
+ * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved.
+ */
+
+/************************************************************************
+ * This module provides application access to special Digi
+ * serial line enhancements which are not standard UNIX(tm) features.
+ ************************************************************************/
+
+#if !defined(TIOCMODG)
+
+#define	TIOCMODG	('d'<<8) | 250		/* get modem ctrl state	*/
+#define	TIOCMODS	('d'<<8) | 251		/* set modem ctrl state	*/
+
+#ifndef TIOCM_LE
+#define		TIOCM_LE	0x01		/* line enable		*/
+#define		TIOCM_DTR	0x02		/* data terminal ready	*/
+#define		TIOCM_RTS	0x04		/* request to send	*/
+#define		TIOCM_ST	0x08		/* secondary transmit	*/
+#define		TIOCM_SR	0x10		/* secondary receive	*/
+#define		TIOCM_CTS	0x20		/* clear to send	*/
+#define		TIOCM_CAR	0x40		/* carrier detect	*/
+#define		TIOCM_RNG	0x80		/* ring	indicator	*/
+#define		TIOCM_DSR	0x100		/* data set ready	*/
+#define		TIOCM_RI	TIOCM_RNG	/* ring (alternate)	*/
+#define		TIOCM_CD	TIOCM_CAR	/* carrier detect (alt)	*/
+#endif
+
+#endif
+
+#if !defined(TIOCMSET)
+#define	TIOCMSET	('d'<<8) | 252		/* set modem ctrl state	*/
+#define	TIOCMGET	('d'<<8) | 253		/* set modem ctrl state	*/
+#endif
+
+#if !defined(TIOCMBIC)
+#define	TIOCMBIC	('d'<<8) | 254		/* set modem ctrl state */
+#define	TIOCMBIS	('d'<<8) | 255		/* set modem ctrl state */
+#endif
+
+
+#if !defined(TIOCSDTR)
+#define	TIOCSDTR	('e'<<8) | 0		/* set DTR		*/
+#define	TIOCCDTR	('e'<<8) | 1		/* clear DTR		*/
+#endif
+
+/************************************************************************
+ * Ioctl command arguments for DIGI parameters.
+ ************************************************************************/
+#define DIGI_GETA	('e'<<8) | 94		/* Read params		*/
+
+#define DIGI_SETA	('e'<<8) | 95		/* Set params		*/
+#define DIGI_SETAW	('e'<<8) | 96		/* Drain & set params	*/
+#define DIGI_SETAF	('e'<<8) | 97		/* Drain, flush & set params */
+
+#define DIGI_KME	('e'<<8) | 98		/* Read/Write Host	*/
+						/* Adapter Memory	*/
+
+#define	DIGI_GETFLOW	('e'<<8) | 99		/* Get startc/stopc flow */
+						/* control characters 	 */
+#define	DIGI_SETFLOW	('e'<<8) | 100		/* Set startc/stopc flow */
+						/* control characters	 */
+#define	DIGI_GETAFLOW	('e'<<8) | 101		/* Get Aux. startc/stopc */
+						/* flow control chars 	 */
+#define	DIGI_SETAFLOW	('e'<<8) | 102		/* Set Aux. startc/stopc */
+						/* flow control chars	 */
+
+#define DIGI_GEDELAY	('d'<<8) | 246		/* Get edelay */
+#define DIGI_SEDELAY	('d'<<8) | 247		/* Set edelay */
+
+struct	digiflow_t {
+	unsigned char	startc;				/* flow cntl start char	*/
+	unsigned char	stopc;				/* flow cntl stop char	*/
+};
+
+
+#ifdef	FLOW_2200
+#define	F2200_GETA	('e'<<8) | 104		/* Get 2x36 flow cntl flags */
+#define	F2200_SETAW	('e'<<8) | 105		/* Set 2x36 flow cntl flags */
+#define		F2200_MASK	0x03		/* 2200 flow cntl bit mask  */
+#define		FCNTL_2200	0x01		/* 2x36 terminal flow cntl  */
+#define		PCNTL_2200	0x02		/* 2x36 printer flow cntl   */
+#define	F2200_XON	0xf8
+#define	P2200_XON	0xf9
+#define	F2200_XOFF	0xfa
+#define	P2200_XOFF	0xfb
+
+#define	FXOFF_MASK	0x03			/* 2200 flow status mask    */
+#define	RCVD_FXOFF	0x01			/* 2x36 Terminal XOFF rcvd  */
+#define	RCVD_PXOFF	0x02			/* 2x36 Printer XOFF rcvd   */
+#endif
+
+/************************************************************************
+ * Values for digi_flags
+ ************************************************************************/
+#define DIGI_IXON	0x0001		/* Handle IXON in the FEP	*/
+#define DIGI_FAST	0x0002		/* Fast baud rates		*/
+#define RTSPACE		0x0004		/* RTS input flow control	*/
+#define CTSPACE		0x0008		/* CTS output flow control	*/
+#define DSRPACE		0x0010		/* DSR output flow control	*/
+#define DCDPACE		0x0020		/* DCD output flow control	*/
+#define DTRPACE		0x0040		/* DTR input flow control	*/
+#define DIGI_COOK	0x0080		/* Cooked processing done in FEP */
+#define DIGI_FORCEDCD	0x0100		/* Force carrier		*/
+#define	DIGI_ALTPIN	0x0200		/* Alternate RJ-45 pin config	*/
+#define	DIGI_AIXON	0x0400		/* Aux flow control in fep	*/
+#define	DIGI_PRINTER	0x0800		/* Hold port open for flow cntrl*/
+#define DIGI_PP_INPUT	0x1000		/* Change parallel port to input*/
+#define DIGI_DTR_TOGGLE	0x2000		/* Support DTR Toggle           */
+#define DIGI_422	0x4000		/* for 422/232 selectable panel */
+#define DIGI_RTS_TOGGLE	0x8000		/* Support RTS Toggle		*/
+
+/************************************************************************
+ * These options are not supported on the comxi.
+ ************************************************************************/
+#define	DIGI_COMXI	(DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE)
+
+#define DIGI_PLEN	28		/* String length		*/
+#define	DIGI_TSIZ	10		/* Terminal string len		*/
+
+/************************************************************************
+ * Structure used with ioctl commands for DIGI parameters.
+ ************************************************************************/
+struct digi_t {
+	unsigned short	digi_flags;		/* Flags (see above)	*/
+	unsigned short	digi_maxcps;		/* Max printer CPS	*/
+	unsigned short	digi_maxchar;		/* Max chars in print queue */
+	unsigned short	digi_bufsize;		/* Buffer size		*/
+	unsigned char	digi_onlen;		/* Length of ON string	*/
+	unsigned char	digi_offlen;		/* Length of OFF string	*/
+	char		digi_onstr[DIGI_PLEN];	/* Printer on string	*/
+	char		digi_offstr[DIGI_PLEN];	/* Printer off string	*/
+	char		digi_term[DIGI_TSIZ];	/* terminal string	*/
+};
+
+/************************************************************************
+ * KME definitions and structures.
+ ************************************************************************/
+#define	RW_IDLE		0	/* Operation complete			*/
+#define	RW_READ		1	/* Read Concentrator Memory		*/
+#define	RW_WRITE	2	/* Write Concentrator Memory		*/
+
+struct rw_t {
+	unsigned char	rw_req;		/* Request type			*/
+	unsigned char	rw_board;	/* Host Adapter board number	*/
+	unsigned char	rw_conc;	/* Concentrator number		*/
+	unsigned char	rw_reserved;	/* Reserved for expansion	*/
+	unsigned int	rw_addr;	/* Address in concentrator	*/
+	unsigned short	rw_size;	/* Read/write request length	*/
+	unsigned char	rw_data[128];	/* Data to read/write		*/
+};
+
+/***********************************************************************
+ * Shrink Buffer and Board Information definitions and structures.
+
+ ************************************************************************/
+			/* Board type return codes */
+#define	PCXI_TYPE 1     /* Board type at the designated port is a PC/Xi */
+#define PCXM_TYPE 2     /* Board type at the designated port is a PC/Xm */
+#define	PCXE_TYPE 3     /* Board type at the designated port is a PC/Xe */
+#define	MCXI_TYPE 4     /* Board type at the designated port is a MC/Xi */
+#define COMXI_TYPE 5     /* Board type at the designated port is a COM/Xi */
+
+			 /* Non-Zero Result codes. */
+#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */
+#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */
+#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */
+#define RESULT_TOOSML  4 /* Too small an area to shrink.  */
+#define RESULT_NOCHAN  5 /* Channel structure for the board was not found */
+
+struct shrink_buf_struct {
+	unsigned int	shrink_buf_vaddr;	/* Virtual address of board */
+	unsigned int	shrink_buf_phys;	/* Physical address of board */
+	unsigned int	shrink_buf_bseg;	/* Amount of board memory */
+	unsigned int	shrink_buf_hseg;	/* '186 Begining of Dual-Port */
+
+	unsigned int	shrink_buf_lseg;	/* '186 Begining of freed memory */
+	unsigned int	shrink_buf_mseg;	/* Linear address from start of
+						   dual-port were freed memory
+						   begins, host viewpoint. */
+
+	unsigned int	shrink_buf_bdparam;	/* Parameter for xxmemon and
+						   xxmemoff */
+
+	unsigned int	shrink_buf_reserva;	/* Reserved */
+	unsigned int	shrink_buf_reservb;	/* Reserved */
+	unsigned int	shrink_buf_reservc;	/* Reserved */
+	unsigned int	shrink_buf_reservd;	/* Reserved */
+
+	unsigned char	shrink_buf_result;	/* Reason for call failing
+						   Zero is Good return */
+	unsigned char	shrink_buf_init;	/* Non-Zero if it caused an
+						   xxinit call. */
+
+	unsigned char	shrink_buf_anports;	/* Number of async ports  */
+	unsigned char	shrink_buf_snports; 	/* Number of sync  ports */
+	unsigned char	shrink_buf_type;	/* Board type 1 = PC/Xi,
+							      2 = PC/Xm,
+							      3 = PC/Xe
+							      4 = MC/Xi
+							      5 = COMX/i */
+	unsigned char	shrink_buf_card;	/* Card number */
+
+};
+
+/************************************************************************
+ * Structure to get driver status information
+ ************************************************************************/
+struct digi_dinfo {
+	unsigned int	dinfo_nboards;		/* # boards configured	*/
+	char		dinfo_reserved[12];	/* for future expansion */
+	char		dinfo_version[16];	/* driver version       */
+};
+
+#define	DIGI_GETDD	('d'<<8) | 248		/* get driver info      */
+
+/************************************************************************
+ * Structure used with ioctl commands for per-board information
+ *
+ * physsize and memsize differ when board has "windowed" memory
+ ************************************************************************/
+struct digi_info {
+	unsigned int	info_bdnum;		/* Board number (0 based)  */
+	unsigned int	info_ioport;		/* io port address         */
+	unsigned int	info_physaddr;		/* memory address          */
+	unsigned int	info_physsize;		/* Size of host mem window */
+	unsigned int	info_memsize;		/* Amount of dual-port mem */
+						/* on board                */
+	unsigned short	info_bdtype;		/* Board type              */
+	unsigned short	info_nports;		/* number of ports         */
+	char		info_bdstate;		/* board state             */
+	char		info_reserved[7];	/* for future expansion    */
+};
+
+#define	DIGI_GETBD	('d'<<8) | 249		/* get board info          */
+
+struct digi_stat {
+	unsigned int	info_chan;		/* Channel number (0 based)  */
+	unsigned int	info_brd;		/* Board number (0 based)  */
+	unsigned int	info_cflag;		/* cflag for channel       */
+	unsigned int	info_iflag;		/* iflag for channel       */
+	unsigned int	info_oflag;		/* oflag for channel       */
+	unsigned int	info_mstat;		/* mstat for channel       */
+	unsigned int	info_tx_data;		/* tx_data for channel       */
+	unsigned int	info_rx_data;		/* rx_data for channel       */
+	unsigned int	info_hflow;		/* hflow for channel       */
+	unsigned int	info_reserved[8];	/* for future expansion    */
+};
+
+#define	DIGI_GETSTAT	('d'<<8) | 244		/* get board info          */
+/************************************************************************
+ *
+ * Structure used with ioctl commands for per-channel information
+ *
+ ************************************************************************/
+struct digi_ch {
+	unsigned int	info_bdnum;		/* Board number (0 based)  */
+	unsigned int	info_channel;		/* Channel index number    */
+	unsigned int	info_ch_cflag;		/* Channel cflag   	   */
+	unsigned int	info_ch_iflag;		/* Channel iflag   	   */
+	unsigned int	info_ch_oflag;		/* Channel oflag   	   */
+	unsigned int	info_chsize;		/* Channel structure size  */
+	unsigned int	info_sleep_stat;	/* sleep status		   */
+	dev_t		info_dev;		/* device number	   */
+	unsigned char	info_initstate;		/* Channel init state	   */
+	unsigned char	info_running;		/* Channel running state   */
+	int		reserved[8];		/* reserved for future use */
+};
+
+/*
+* This structure is used with the DIGI_FEPCMD ioctl to
+* tell the driver which port to send the command for.
+*/
+struct digi_cmd {
+	int	cmd;
+	int	word;
+	int	ncmds;
+	int	chan; /* channel index (zero based) */
+	int	bdid; /* board index (zero based) */
+};
+
+
+struct digi_getbuffer /* Struct for holding buffer use counts */
+{
+	unsigned long tIn;
+	unsigned long tOut;
+	unsigned long rxbuf;
+	unsigned long txbuf;
+	unsigned long txdone;
+};
+
+struct digi_getcounter {
+	unsigned long norun;		/* number of UART overrun errors */
+	unsigned long noflow;		/* number of buffer overflow errors */
+	unsigned long nframe;		/* number of framing errors */
+	unsigned long nparity;		/* number of parity errors */
+	unsigned long nbreak;		/* number of breaks received */
+	unsigned long rbytes;		/* number of received bytes */
+	unsigned long tbytes;		/* number of bytes transmitted fully */
+};
+
+/*
+*  info_sleep_stat defines
+*/
+#define INFO_RUNWAIT	0x0001
+#define INFO_WOPEN	0x0002
+#define INFO_TTIOW	0x0004
+#define INFO_CH_RWAIT	0x0008
+#define INFO_CH_WEMPTY	0x0010
+#define INFO_CH_WLOW	0x0020
+#define INFO_XXBUF_BUSY 0x0040
+
+#define	DIGI_GETCH	('d'<<8) | 245		/* get board info          */
+
+/* Board type definitions */
+
+#define	SUBTYPE		0007
+#define	T_PCXI		0000
+#define T_PCXM		0001
+#define T_PCXE		0002
+#define T_PCXR		0003
+#define T_SP		0004
+#define T_SP_PLUS	0005
+#	define T_HERC	0000
+#	define T_HOU	0001
+#	define T_LON	0002
+#	define T_CHA	0003
+#define FAMILY		0070
+#define T_COMXI		0000
+#define T_PCXX		0010
+#define T_CX		0020
+#define T_EPC		0030
+#define	T_PCLITE	0040
+#define	T_SPXX		0050
+#define	T_AVXX		0060
+#define T_DXB		0070
+#define T_A2K_4_8	0070
+#define BUSTYPE		0700
+#define T_ISABUS	0000
+#define T_MCBUS		0100
+#define	T_EISABUS	0200
+#define	T_PCIBUS	0400
+
+/* Board State Definitions */
+
+#define	BD_RUNNING	0x0
+#define	BD_REASON	0x7f
+#define	BD_NOTFOUND	0x1
+#define	BD_NOIOPORT	0x2
+#define	BD_NOMEM	0x3
+#define	BD_NOBIOS	0x4
+#define	BD_NOFEP	0x5
+#define	BD_FAILED	0x6
+#define BD_ALLOCATED	0x7
+#define BD_TRIBOOT	0x8
+#define	BD_BADKME	0x80
+
+#define DIGI_SPOLL            ('d'<<8) | 254  /* change poller rate   */
+
+#define DIGI_SETCUSTOMBAUD	_IOW('e', 106, int)	/* Set integer baud rate */
+#define DIGI_GETCUSTOMBAUD	_IOR('e', 107, int)	/* Get integer baud rate */
+
+#define DIGI_REALPORT_GETBUFFERS ('e'<<8 ) | 108
+#define DIGI_REALPORT_SENDIMMEDIATE ('e'<<8 ) | 109
+#define DIGI_REALPORT_GETCOUNTERS ('e'<<8 ) | 110
+#define DIGI_REALPORT_GETEVENTS ('e'<<8 ) | 111
+
+#define EV_OPU		0x0001		//!<Output paused by client
+#define EV_OPS		0x0002		//!<Output paused by reqular sw flowctrl
+#define EV_OPX		0x0004		//!<Output paused by extra sw flowctrl
+#define EV_OPH		0x0008		//!<Output paused by hw flowctrl
+#define EV_OPT		0x0800		//!<Output paused for RTS Toggle predelay
+
+#define EV_IPU		0x0010		//!<Input paused unconditionally by user
+#define EV_IPS		0x0020		//!<Input paused by high/low water marks
+//#define EV_IPH	0x0040		//!<Input paused w/ hardware
+#define EV_IPA		0x0400		//!<Input paused by pattern alarm module
+
+#define EV_TXB		0x0040		//!<Transmit break pending
+#define EV_TXI		0x0080		//!<Transmit immediate pending
+#define EV_TXF		0x0100		//!<Transmit flowctrl char pending
+#define EV_RXB		0x0200		//!<Break received
+
+#define EV_OPALL	0x080f		//!<Output pause flags
+#define EV_IPALL	0x0430		//!<Input pause flags
+
+#endif /* DIGI_H */
diff --git a/drivers/staging/dgnc/dpacompat.h b/drivers/staging/dgnc/dpacompat.h
new file mode 100644
index 0000000..f96963b
--- /dev/null
+++ b/drivers/staging/dgnc/dpacompat.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2003 Digi International (www.digi.com)
+ *      Scott H Kilau <Scott_Kilau at digi dot 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; 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.
+ *
+ *      NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!!
+ */
+
+
+/*
+ * This structure holds data needed for the intelligent <--> nonintelligent
+ * DPA translation
+ */
+ struct ni_info {
+	int board;
+	int channel;
+	int dtr;
+	int rts;
+	int cts;
+	int dsr;
+	int ri;
+	int dcd;
+	int curtx;
+	int currx;
+	unsigned short iflag;
+	unsigned short oflag;
+	unsigned short cflag;
+	unsigned short lflag;
+
+	unsigned int mstat;
+	unsigned char hflow;
+
+	unsigned char xmit_stopped;
+	unsigned char recv_stopped;
+
+	unsigned int baud;
+};
+
+#define RW_READ		1
+#define RW_WRITE        2
+#define DIGI_KME        ('e'<<8) | 98           /* Read/Write Host */
+
+#define SUBTYPE         0007
+#define T_PCXI          0000
+#define T_PCXEM         0001
+#define T_PCXE          0002
+#define T_PCXR          0003
+#define T_SP            0004
+#define T_SP_PLUS       0005
+
+#define T_HERC   0000
+#define T_HOU    0001
+#define T_LON    0002
+#define T_CHA    0003
+
+#define T_NEO	 0000
+#define T_NEO_EXPRESS  0001
+#define T_CLASSIC 0002
+
+#define FAMILY          0070
+#define T_COMXI         0000
+#define	T_NI		0000
+#define T_PCXX          0010
+#define T_CX            0020
+#define T_EPC           0030
+#define T_PCLITE        0040
+#define T_SPXX          0050
+#define T_AVXX          0060
+#define T_DXB           0070
+#define T_A2K_4_8       0070
+
+#define BUSTYPE         0700
+#define T_ISABUS        0000
+#define T_MCBUS         0100
+#define T_EISABUS       0200
+#define T_PCIBUS        0400
+
+/* Board State Definitions */
+
+#define BD_RUNNING      0x0
+#define BD_REASON       0x7f
+#define BD_NOTFOUND     0x1
+#define BD_NOIOPORT     0x2
+#define BD_NOMEM        0x3
+#define BD_NOBIOS       0x4
+#define BD_NOFEP        0x5
+#define BD_FAILED       0x6
+#define BD_ALLOCATED    0x7
+#define BD_TRIBOOT      0x8
+#define BD_BADKME       0x80
+
+#define DIGI_AIXON      0x0400          /* Aux flow control in fep */
+
+/* Ioctls needed for dpa operation */
+
+#define DIGI_GETDD      ('d'<<8) | 248          /* get driver info      */
+#define DIGI_GETBD      ('d'<<8) | 249          /* get board info       */
+#define DIGI_GET_NI_INFO ('d'<<8) | 250		/* nonintelligent state snfo */
+
+/* Other special ioctls */
+#define DIGI_TIMERIRQ ('d'<<8) | 251		/* Enable/disable RS_TIMER use */
+#define DIGI_LOOPBACK ('d'<<8) | 252		/* Enable/disable UART internal loopback */
diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c
index e456dc6c..08eedf0 100644
--- a/drivers/staging/dgrp/dgrp_driver.c
+++ b/drivers/staging/dgrp/dgrp_driver.c
@@ -52,19 +52,12 @@
 module_param_named(pollrate, dgrp_poll_tick, int, 0644);
 MODULE_PARM_DESC(pollrate, "Poll interval in ms");
 
-/* Driver load/unload functions */
-static int dgrp_init_module(void);
-static void dgrp_cleanup_module(void);
-
-module_init(dgrp_init_module);
-module_exit(dgrp_cleanup_module);
-
 /*
  * init_module()
  *
  * Module load.  This is where it all starts.
  */
-static int dgrp_init_module(void)
+static int __init dgrp_init_module(void)
 {
 	int ret;
 
@@ -89,7 +82,7 @@
 /*
  *	Module unload.  This is where it all ends.
  */
-static void dgrp_cleanup_module(void)
+static void __exit dgrp_cleanup_module(void)
 {
 	struct nd_struct *nd, *next;
 
@@ -108,3 +101,6 @@
 		kfree(nd);
 	}
 }
+
+module_init(dgrp_init_module);
+module_exit(dgrp_cleanup_module);
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c
index 654f601..0d52de3 100644
--- a/drivers/staging/dgrp/dgrp_tty.c
+++ b/drivers/staging/dgrp/dgrp_tty.c
@@ -1120,7 +1120,9 @@
 				if (!sent_printer_offstr)
 					dgrp_tty_flush_buffer(tty);
 
+				spin_unlock_irqrestore(&nd->nd_lock, lock_flags);
 				tty_ldisc_flush(tty);
+				spin_lock_irqsave(&nd->nd_lock, lock_flags);
 				break;
 		}
 
diff --git a/drivers/staging/dwc2/Kconfig b/drivers/staging/dwc2/Kconfig
index d15d9d5..be947d6 100644
--- a/drivers/staging/dwc2/Kconfig
+++ b/drivers/staging/dwc2/Kconfig
@@ -1,7 +1,6 @@
 config USB_DWC2
 	tristate "DesignWare USB2 DRD Core Support"
 	depends on USB
-	depends on VIRT_TO_BUS
 	help
 	  Say Y or M here if your system has a Dual Role HighSpeed
 	  USB controller based on the DesignWare HSOTG IP Core.
diff --git a/drivers/staging/dwc2/core.c b/drivers/staging/dwc2/core.c
index e3a0e77..06dae67 100644
--- a/drivers/staging/dwc2/core.c
+++ b/drivers/staging/dwc2/core.c
@@ -90,12 +90,10 @@
  */
 static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
 {
-	u32 hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
-	u32 fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
 	u32 hcfg, val;
 
-	if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
-	     fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+	if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+	     hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
 	     hsotg->core_params->ulpi_fs_ls > 0) ||
 	    hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
 		/* Full speed PHY */
@@ -108,7 +106,7 @@
 	dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
 	hcfg = readl(hsotg->regs + HCFG);
 	hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
-	hcfg |= val;
+	hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
 	writel(hcfg, hsotg->regs + HCFG);
 }
 
@@ -245,7 +243,7 @@
 
 static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 {
-	u32 usbcfg, hs_phy_type, fs_phy_type;
+	u32 usbcfg;
 
 	if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
 	    hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
@@ -256,11 +254,8 @@
 		dwc2_hs_phy_init(hsotg, select_phy);
 	}
 
-	hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
-	fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
-
-	if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
-	    fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+	if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
 	    hsotg->core_params->ulpi_fs_ls > 0) {
 		dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
 		usbcfg = readl(hsotg->regs + GUSBCFG);
@@ -277,20 +272,20 @@
 
 static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
 {
-	u32 ahbcfg = 0;
+	u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
 
-	switch (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) {
+	switch (hsotg->hw_params.arch) {
 	case GHWCFG2_EXT_DMA_ARCH:
 		dev_err(hsotg->dev, "External DMA Mode not supported\n");
 		return -EINVAL;
 
 	case GHWCFG2_INT_DMA_ARCH:
 		dev_dbg(hsotg->dev, "Internal DMA Mode\n");
-		/*
-		 * Old value was GAHBCFG_HBSTLEN_INCR - done for
-		 * Host mode ISOC in issue fix - vahrama
-		 */
-		ahbcfg |= GAHBCFG_HBSTLEN_INCR4;
+		if (hsotg->core_params->ahbcfg != -1) {
+			ahbcfg &= GAHBCFG_CTRL_MASK;
+			ahbcfg |= hsotg->core_params->ahbcfg &
+				  ~GAHBCFG_CTRL_MASK;
+		}
 		break;
 
 	case GHWCFG2_SLAVE_ONLY_ARCH:
@@ -313,9 +308,6 @@
 		hsotg->core_params->dma_desc_enable = 0;
 	}
 
-	if (hsotg->core_params->ahb_single > 0)
-		ahbcfg |= GAHBCFG_AHB_SINGLE;
-
 	if (hsotg->core_params->dma_enable > 0)
 		ahbcfg |= GAHBCFG_DMA_EN;
 
@@ -331,7 +323,7 @@
 	usbcfg = readl(hsotg->regs + GUSBCFG);
 	usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
 
-	switch (hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK) {
+	switch (hsotg->hw_params.op_mode) {
 	case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
 		if (hsotg->core_params->otg_cap ==
 				DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
@@ -392,21 +384,6 @@
 	/* Reset the Controller */
 	dwc2_core_reset(hsotg);
 
-	dev_dbg(hsotg->dev, "num_dev_perio_in_ep=%d\n",
-		hsotg->hwcfg4 >> GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT &
-		GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK >>
-				GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT);
-
-	hsotg->total_fifo_size = hsotg->hwcfg3 >> GHWCFG3_DFIFO_DEPTH_SHIFT &
-			GHWCFG3_DFIFO_DEPTH_MASK >> GHWCFG3_DFIFO_DEPTH_SHIFT;
-	hsotg->rx_fifo_size = readl(hsotg->regs + GRXFSIZ);
-	hsotg->nperio_tx_fifo_size =
-			readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
-
-	dev_dbg(hsotg->dev, "Total FIFO SZ=%d\n", hsotg->total_fifo_size);
-	dev_dbg(hsotg->dev, "RxFIFO SZ=%d\n", hsotg->rx_fifo_size);
-	dev_dbg(hsotg->dev, "NP TxFIFO SZ=%d\n", hsotg->nperio_tx_fifo_size);
-
 	/*
 	 * This needs to happen in FS mode before any other programming occurs
 	 */
@@ -504,22 +481,18 @@
 static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
 {
 	struct dwc2_core_params *params = hsotg->core_params;
-	u32 rxfsiz, nptxfsiz, ptxfsiz, hptxfsiz, dfifocfg;
+	u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz;
 
 	if (!params->enable_dynamic_fifo)
 		return;
 
-	dev_dbg(hsotg->dev, "Total FIFO Size=%d\n", hsotg->total_fifo_size);
-	dev_dbg(hsotg->dev, "Rx FIFO Size=%d\n", params->host_rx_fifo_size);
-	dev_dbg(hsotg->dev, "NP Tx FIFO Size=%d\n",
-		params->host_nperio_tx_fifo_size);
-	dev_dbg(hsotg->dev, "P Tx FIFO Size=%d\n",
-		params->host_perio_tx_fifo_size);
-
 	/* Rx FIFO */
-	dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n",
-		readl(hsotg->regs + GRXFSIZ));
-	writel(params->host_rx_fifo_size, hsotg->regs + GRXFSIZ);
+	grxfsiz = readl(hsotg->regs + GRXFSIZ);
+	dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
+	grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
+	grxfsiz |= params->host_rx_fifo_size <<
+		   GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
+	writel(grxfsiz, hsotg->regs + GRXFSIZ);
 	dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", readl(hsotg->regs + GRXFSIZ));
 
 	/* Non-periodic Tx FIFO */
@@ -536,27 +509,26 @@
 	/* Periodic Tx FIFO */
 	dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
 		readl(hsotg->regs + HPTXFSIZ));
-	ptxfsiz = params->host_perio_tx_fifo_size <<
-		  FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
-	ptxfsiz |= (params->host_rx_fifo_size +
-		    params->host_nperio_tx_fifo_size) <<
-		   FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
-	writel(ptxfsiz, hsotg->regs + HPTXFSIZ);
+	hptxfsiz = params->host_perio_tx_fifo_size <<
+		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+	hptxfsiz |= (params->host_rx_fifo_size +
+		     params->host_nperio_tx_fifo_size) <<
+		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+	writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
 	dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
 		readl(hsotg->regs + HPTXFSIZ));
 
 	if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
-	    hsotg->snpsid <= DWC2_CORE_REV_2_94a) {
+	    hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) {
 		/*
 		 * Global DFIFOCFG calculation for Host mode -
 		 * include RxFIFO, NPTXFIFO and HPTXFIFO
 		 */
 		dfifocfg = readl(hsotg->regs + GDFIFOCFG);
-		rxfsiz = readl(hsotg->regs + GRXFSIZ) & 0x0000ffff;
-		nptxfsiz = readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
-		hptxfsiz = readl(hsotg->regs + HPTXFSIZ) >> 16 & 0xffff;
 		dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
-		dfifocfg |= (rxfsiz + nptxfsiz + hptxfsiz) <<
+		dfifocfg |= (params->host_rx_fifo_size +
+			     params->host_nperio_tx_fifo_size +
+			     params->host_perio_tx_fifo_size) <<
 			    GDFIFOCFG_EPINFOBASE_SHIFT &
 			    GDFIFOCFG_EPINFOBASE_MASK;
 		writel(dfifocfg, hsotg->regs + GDFIFOCFG);
@@ -602,10 +574,9 @@
 	}
 
 	if (hsotg->core_params->dma_desc_enable > 0) {
-		u32 op_mode = hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK;
-
-		if (hsotg->snpsid < DWC2_CORE_REV_2_90a ||
-		    !(hsotg->hwcfg4 & GHWCFG4_DESC_DMA) ||
+		u32 op_mode = hsotg->hw_params.op_mode;
+		if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a ||
+		    !hsotg->hw_params.dma_desc_enable ||
 		    op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
 		    op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
 		    op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
@@ -883,26 +854,20 @@
 		dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
 			 hc_num, hcchar);
 
-		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, hc_num);
+		dev_vdbg(hsotg->dev, "%s: Channel %d\n",
+			 __func__, hc_num);
 		dev_vdbg(hsotg->dev, "	 Dev Addr: %d\n",
-			 hcchar >> HCCHAR_DEVADDR_SHIFT &
-			 HCCHAR_DEVADDR_MASK >> HCCHAR_DEVADDR_SHIFT);
+			 chan->dev_addr);
 		dev_vdbg(hsotg->dev, "	 Ep Num: %d\n",
-			 hcchar >> HCCHAR_EPNUM_SHIFT &
-			 HCCHAR_EPNUM_MASK >> HCCHAR_EPNUM_SHIFT);
+			 chan->ep_num);
 		dev_vdbg(hsotg->dev, "	 Is In: %d\n",
-			 !!(hcchar & HCCHAR_EPDIR));
+			 chan->ep_is_in);
 		dev_vdbg(hsotg->dev, "	 Is Low Speed: %d\n",
-			 !!(hcchar & HCCHAR_LSPDDEV));
+			 chan->speed == USB_SPEED_LOW);
 		dev_vdbg(hsotg->dev, "	 Ep Type: %d\n",
-			 hcchar >> HCCHAR_EPTYPE_SHIFT &
-			 HCCHAR_EPTYPE_MASK >> HCCHAR_EPTYPE_SHIFT);
+			 chan->ep_type);
 		dev_vdbg(hsotg->dev, "	 Max Pkt: %d\n",
-			 hcchar >> HCCHAR_MPS_SHIFT &
-			 HCCHAR_MPS_MASK >> HCCHAR_MPS_SHIFT);
-		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n",
-			 hcchar >> HCCHAR_MULTICNT_SHIFT &
-			 HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+			 chan->max_packet);
 	}
 
 	/* Program the HCSPLT register for SPLITs */
@@ -932,8 +897,7 @@
 			dev_vdbg(hsotg->dev, "	  is_in %d\n",
 				 chan->ep_is_in);
 			dev_vdbg(hsotg->dev, "	  Max Pkt %d\n",
-				 hcchar >> HCCHAR_MPS_SHIFT &
-				 HCCHAR_MPS_MASK >> HCCHAR_MPS_SHIFT);
+				 chan->max_packet);
 			dev_vdbg(hsotg->dev, "	  xferlen %d\n",
 				 chan->xfer_len);
 		}
@@ -1382,14 +1346,14 @@
 		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
 			 chan->hc_num);
 		dev_vdbg(hsotg->dev, "	 Xfer Size: %d\n",
-			 hctsiz >> TSIZ_XFERSIZE_SHIFT &
-			 TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT);
+			 (hctsiz & TSIZ_XFERSIZE_MASK) >>
+			 TSIZ_XFERSIZE_SHIFT);
 		dev_vdbg(hsotg->dev, "	 Num Pkts: %d\n",
-			 hctsiz >> TSIZ_PKTCNT_SHIFT &
-			 TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT);
+			 (hctsiz & TSIZ_PKTCNT_MASK) >>
+			 TSIZ_PKTCNT_SHIFT);
 		dev_vdbg(hsotg->dev, "	 Start PID: %d\n",
-			 hctsiz >> TSIZ_SC_MC_PID_SHIFT &
-			 TSIZ_SC_MC_PID_MASK >> TSIZ_SC_MC_PID_SHIFT);
+			 (hctsiz & TSIZ_SC_MC_PID_MASK) >>
+			 TSIZ_SC_MC_PID_SHIFT);
 	}
 
 	if (hsotg->core_params->dma_enable > 0) {
@@ -1433,8 +1397,8 @@
 
 	if (dbg_hc(chan))
 		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n",
-			 hcchar >> HCCHAR_MULTICNT_SHIFT &
-			 HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+			 (hcchar & HCCHAR_MULTICNT_MASK) >>
+			 HCCHAR_MULTICNT_SHIFT);
 
 	writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
 	if (dbg_hc(chan))
@@ -1522,8 +1486,8 @@
 
 	if (dbg_hc(chan))
 		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n",
-			 hcchar >> HCCHAR_MULTICNT_SHIFT &
-			 HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+			 (hcchar & HCCHAR_MULTICNT_MASK) >>
+			 HCCHAR_MULTICNT_SHIFT);
 
 	writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
 	if (dbg_hc(chan))
@@ -1658,18 +1622,16 @@
 u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
 {
 	u32 usbcfg;
-	u32 hwcfg2;
 	u32 hprt0;
 	int clock = 60;	/* default value */
 
 	usbcfg = readl(hsotg->regs + GUSBCFG);
-	hwcfg2 = readl(hsotg->regs + GHWCFG2);
 	hprt0 = readl(hsotg->regs + HPRT0);
 
 	if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
 	    !(usbcfg & GUSBCFG_PHYIF16))
 		clock = 60;
-	if ((usbcfg & GUSBCFG_PHYSEL) && (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
+	if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type ==
 	    GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
 		clock = 48;
 	if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
@@ -1682,14 +1644,13 @@
 	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
 		clock = 48;
 	if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
-	    (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
-	    GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
+	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
 		clock = 48;
-	if ((usbcfg & GUSBCFG_PHYSEL) && (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
-	    GHWCFG2_FS_PHY_TYPE_DEDICATED)
+	if ((usbcfg & GUSBCFG_PHYSEL) &&
+	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
 		clock = 48;
 
-	if ((hprt0 & HPRT0_SPD_MASK) == HPRT0_SPD_HIGH_SPEED)
+	if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED)
 		/* High speed case */
 		return 125 * clock;
 	else
@@ -1958,17 +1919,14 @@
 {
 	int valid = 1;
 	int retval = 0;
-	u32 op_mode;
-
-	op_mode = hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK;
 
 	switch (val) {
 	case DWC2_CAP_PARAM_HNP_SRP_CAPABLE:
-		if (op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
+		if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
 			valid = 0;
 		break;
 	case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE:
-		switch (op_mode) {
+		switch (hsotg->hw_params.op_mode) {
 		case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
 		case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
 		case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
@@ -1992,7 +1950,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for otg_cap parameter. Check HW configuration.\n",
 				val);
-		switch (op_mode) {
+		switch (hsotg->hw_params.op_mode) {
 		case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
 			val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
 			break;
@@ -2018,8 +1976,7 @@
 	int valid = 1;
 	int retval = 0;
 
-	if (val > 0 && (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) ==
-	    GHWCFG2_SLAVE_ONLY_ARCH)
+	if (val > 0 && hsotg->hw_params.arch == GHWCFG2_SLAVE_ONLY_ARCH)
 		valid = 0;
 	if (val < 0)
 		valid = 0;
@@ -2029,8 +1986,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for dma_enable parameter. Check HW configuration.\n",
 				val);
-		val = (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) !=
-			GHWCFG2_SLAVE_ONLY_ARCH;
+		val = hsotg->hw_params.arch != GHWCFG2_SLAVE_ONLY_ARCH;
 		dev_dbg(hsotg->dev, "Setting dma_enable to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2045,7 +2001,7 @@
 	int retval = 0;
 
 	if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
-			!(hsotg->hwcfg4 & GHWCFG4_DESC_DMA)))
+			!hsotg->hw_params.dma_desc_enable))
 		valid = 0;
 	if (val < 0)
 		valid = 0;
@@ -2056,7 +2012,7 @@
 				"%d invalid for dma_desc_enable parameter. Check HW configuration.\n",
 				val);
 		val = (hsotg->core_params->dma_enable > 0 &&
-			(hsotg->hwcfg4 & GHWCFG4_DESC_DMA));
+			hsotg->hw_params.dma_desc_enable);
 		dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2092,7 +2048,7 @@
 	int valid = 1;
 	int retval = 0;
 
-	if (val > 0 && !(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO))
+	if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo)
 		valid = 0;
 	if (val < 0)
 		valid = 0;
@@ -2102,7 +2058,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n",
 				val);
-		val = !!(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+		val = hsotg->hw_params.enable_dynamic_fifo;
 		dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2116,7 +2072,7 @@
 	int valid = 1;
 	int retval = 0;
 
-	if (val < 16 || val > readl(hsotg->regs + GRXFSIZ))
+	if (val < 16 || val > hsotg->hw_params.host_rx_fifo_size)
 		valid = 0;
 
 	if (!valid) {
@@ -2124,7 +2080,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for host_rx_fifo_size. Check HW configuration.\n",
 				val);
-		val = readl(hsotg->regs + GRXFSIZ);
+		val = hsotg->hw_params.host_rx_fifo_size;
 		dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2138,7 +2094,7 @@
 	int valid = 1;
 	int retval = 0;
 
-	if (val < 16 || val > (readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff))
+	if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size)
 		valid = 0;
 
 	if (!valid) {
@@ -2146,7 +2102,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
 				val);
-		val = readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
+		val = hsotg->hw_params.host_nperio_tx_fifo_size;
 		dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n",
 			val);
 		retval = -EINVAL;
@@ -2161,7 +2117,7 @@
 	int valid = 1;
 	int retval = 0;
 
-	if (val < 16 || val > (hsotg->hptxfsiz >> 16))
+	if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size)
 		valid = 0;
 
 	if (!valid) {
@@ -2169,7 +2125,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
 				val);
-		val = hsotg->hptxfsiz >> 16;
+		val = hsotg->hw_params.host_perio_tx_fifo_size;
 		dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n",
 			val);
 		retval = -EINVAL;
@@ -2183,11 +2139,8 @@
 {
 	int valid = 1;
 	int retval = 0;
-	int width = hsotg->hwcfg3 >> GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT &
-		    GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK >>
-				GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
 
-	if (val < 2047 || val >= (1 << (width + 11)))
+	if (val < 2047 || val > hsotg->hw_params.max_transfer_size)
 		valid = 0;
 
 	if (!valid) {
@@ -2195,7 +2148,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for max_transfer_size. Check HW configuration.\n",
 				val);
-		val = (1 << (width + 11)) - 1;
+		val = hsotg->hw_params.max_transfer_size;
 		dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2208,11 +2161,8 @@
 {
 	int valid = 1;
 	int retval = 0;
-	int width = hsotg->hwcfg3 >> GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT &
-		    GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK >>
-				GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
 
-	if (val < 15 || val > (1 << (width + 4)))
+	if (val < 15 || val > hsotg->hw_params.max_packet_count)
 		valid = 0;
 
 	if (!valid) {
@@ -2220,7 +2170,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for max_packet_count. Check HW configuration.\n",
 				val);
-		val = (1 << (width + 4)) - 1;
+		val = hsotg->hw_params.max_packet_count;
 		dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2233,10 +2183,8 @@
 {
 	int valid = 1;
 	int retval = 0;
-	int num_chan = hsotg->hwcfg2 >> GHWCFG2_NUM_HOST_CHAN_SHIFT &
-		GHWCFG2_NUM_HOST_CHAN_MASK >> GHWCFG2_NUM_HOST_CHAN_SHIFT;
 
-	if (val < 1 || val > num_chan + 1)
+	if (val < 1 || val > hsotg->hw_params.host_channels)
 		valid = 0;
 
 	if (!valid) {
@@ -2244,7 +2192,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for host_channels. Check HW configuration.\n",
 				val);
-		val = num_chan + 1;
+		val = hsotg->hw_params.host_channels;
 		dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2257,8 +2205,7 @@
 {
 #ifndef NO_FS_PHY_HW_CHECKS
 	int valid = 0;
-	u32 hs_phy_type;
-	u32 fs_phy_type;
+        u32 hs_phy_type, fs_phy_type;
 #endif
 	int retval = 0;
 
@@ -2279,9 +2226,8 @@
 	}
 
 #ifndef NO_FS_PHY_HW_CHECKS
-	hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
-	fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
-
+	hs_phy_type = hsotg->hw_params.hs_phy_type;
+	fs_phy_type = hsotg->hw_params.fs_phy_type;
 	if (val == DWC2_PHY_TYPE_PARAM_UTMI &&
 	    (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
 	     hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
@@ -2430,14 +2376,29 @@
 
 int dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val)
 {
+	int valid = 0;
 	int retval = 0;
 
-	if (DWC2_PARAM_TEST(val, 8, 8) && DWC2_PARAM_TEST(val, 16, 16)) {
+	switch (hsotg->hw_params.utmi_phy_data_width) {
+	case GHWCFG4_UTMI_PHY_DATA_WIDTH_8:
+		valid = (val == 8);
+		break;
+	case GHWCFG4_UTMI_PHY_DATA_WIDTH_16:
+		valid = (val == 16);
+		break;
+	case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16:
+		valid = (val == 8 || val == 16);
+		break;
+	}
+
+	if (!valid) {
 		if (val >= 0) {
-			dev_err(hsotg->dev, "Wrong value for phy_utmi_width\n");
-			dev_err(hsotg->dev, "phy_utmi_width must be 8 or 16\n");
+			dev_err(hsotg->dev,
+				"%d invalid for phy_utmi_width. Check HW configuration.\n",
+				val);
 		}
-		val = 8;
+		val = (hsotg->hw_params.utmi_phy_data_width ==
+		       GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16;
 		dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2505,7 +2466,7 @@
 	}
 
 #ifndef NO_FS_PHY_HW_CHECKS
-	if (val == 1 && !(hsotg->hwcfg3 & GHWCFG3_I2C))
+	if (val == 1 && !(hsotg->hw_params.i2c_enable))
 		valid = 0;
 
 	if (!valid) {
@@ -2513,7 +2474,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for i2c_enable. Check HW configuration.\n",
 				val);
-		val = !!(hsotg->hwcfg3 & GHWCFG3_I2C);
+		val = hsotg->hw_params.i2c_enable;
 		dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2538,7 +2499,7 @@
 		valid = 0;
 	}
 
-	if (val == 1 && !(hsotg->hwcfg4 & GHWCFG4_DED_FIFO_EN))
+	if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo)
 		valid = 0;
 
 	if (!valid) {
@@ -2546,7 +2507,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
 				val);
-		val = !!(hsotg->hwcfg4 & GHWCFG4_DED_FIFO_EN);
+		val = hsotg->hw_params.en_multiple_tx_fifo;
 		dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2569,7 +2530,7 @@
 		valid = 0;
 	}
 
-	if (val == 1 && hsotg->snpsid < DWC2_CORE_REV_2_92a)
+	if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a)
 		valid = 0;
 
 	if (!valid) {
@@ -2577,7 +2538,7 @@
 			dev_err(hsotg->dev,
 				"%d invalid for parameter reload_ctl. Check HW configuration.\n",
 				val);
-		val = hsotg->snpsid >= DWC2_CORE_REV_2_92a;
+		val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a;
 		dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val);
 		retval = -EINVAL;
 	}
@@ -2586,35 +2547,14 @@
 	return retval;
 }
 
-int dwc2_set_param_ahb_single(struct dwc2_hsotg *hsotg, int val)
+int dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val)
 {
-	int valid = 1;
-	int retval = 0;
-
-	if (DWC2_PARAM_TEST(val, 0, 1)) {
-		if (val >= 0) {
-			dev_err(hsotg->dev,
-				"'%d' invalid for parameter ahb_single\n", val);
-			dev_err(hsotg->dev, "ahb_single must be 0 or 1\n");
-		}
-		valid = 0;
-	}
-
-	if (val > 0 && hsotg->snpsid < DWC2_CORE_REV_2_94a)
-		valid = 0;
-
-	if (!valid) {
-		if (val >= 0)
-			dev_err(hsotg->dev,
-				"%d invalid for parameter ahb_single. Check HW configuration.\n",
-				val);
-		val = 0;
-		dev_dbg(hsotg->dev, "Setting ahb_single to %d\n", val);
-		retval = -EINVAL;
-	}
-
-	hsotg->core_params->ahb_single = val;
-	return retval;
+	if (val != -1)
+		hsotg->core_params->ahbcfg = val;
+	else
+		hsotg->core_params->ahbcfg = GAHBCFG_HBSTLEN_INCR4 <<
+                                             GAHBCFG_HBSTLEN_SHIFT;
+	return 0;
 }
 
 int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val)
@@ -2637,6 +2577,165 @@
 	return retval;
 }
 
+/**
+ * During device initialization, read various hardware configuration
+ * registers and interpret the contents.
+ */
+int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
+{
+	struct dwc2_hw_params *hw = &hsotg->hw_params;
+	unsigned width;
+	u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
+	u32 hptxfsiz, grxfsiz, gnptxfsiz;
+	u32 gusbcfg;
+
+	/*
+	 * Attempt to ensure this device is really a DWC_otg Controller.
+	 * Read and verify the GSNPSID register contents. The value should be
+	 * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
+	 * as in "OTG version 2.xx" or "OTG version 3.xx".
+	 */
+	hw->snpsid = readl(hsotg->regs + GSNPSID);
+	if ((hw->snpsid & 0xfffff000) != 0x4f542000 &&
+	    (hw->snpsid & 0xfffff000) != 0x4f543000) {
+		dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
+			hw->snpsid);
+		return -ENODEV;
+	}
+
+	dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
+		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
+		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
+
+	hwcfg1 = readl(hsotg->regs + GHWCFG1);
+	hwcfg2 = readl(hsotg->regs + GHWCFG2);
+	hwcfg3 = readl(hsotg->regs + GHWCFG3);
+	hwcfg4 = readl(hsotg->regs + GHWCFG4);
+	gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ);
+	grxfsiz = readl(hsotg->regs + GRXFSIZ);
+
+	dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1);
+	dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2);
+	dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3);
+	dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4);
+	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz);
+	dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz);
+
+	/* Force host mode to get HPTXFSIZ exact power on value */
+	gusbcfg = readl(hsotg->regs + GUSBCFG);
+	gusbcfg |= GUSBCFG_FORCEHOSTMODE;
+	writel(gusbcfg, hsotg->regs + GUSBCFG);
+	usleep_range(100000, 150000);
+
+	hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
+	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz);
+	gusbcfg = readl(hsotg->regs + GUSBCFG);
+	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+	writel(gusbcfg, hsotg->regs + GUSBCFG);
+	usleep_range(100000, 150000);
+
+	/* hwcfg2 */
+	hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >>
+		      GHWCFG2_OP_MODE_SHIFT;
+	hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >>
+		   GHWCFG2_ARCHITECTURE_SHIFT;
+	hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+	hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >>
+				GHWCFG2_NUM_HOST_CHAN_SHIFT);
+	hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >>
+			  GHWCFG2_HS_PHY_TYPE_SHIFT;
+	hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >>
+			  GHWCFG2_FS_PHY_TYPE_SHIFT;
+	hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >>
+			 GHWCFG2_NUM_DEV_EP_SHIFT;
+	hw->nperio_tx_q_depth =
+		(hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >>
+		GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1;
+	hw->host_perio_tx_q_depth =
+		(hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >>
+		GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1;
+	hw->dev_token_q_depth =
+		(hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >>
+		GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT;
+
+	/* hwcfg3 */
+	width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >>
+		GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
+	hw->max_transfer_size = (1 << (width + 11)) - 1;
+	width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >>
+		GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
+	hw->max_packet_count = (1 << (width + 4)) - 1;
+	hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C);
+	hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >>
+			      GHWCFG3_DFIFO_DEPTH_SHIFT;
+
+	/* hwcfg4 */
+	hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN);
+	hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >>
+				  GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
+	hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA);
+	hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
+	hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
+				  GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
+
+	/* fifo sizes */
+	hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
+				GRXFSIZ_DEPTH_SHIFT;
+	hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+				       FIFOSIZE_DEPTH_SHIFT;
+	hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >>
+				      FIFOSIZE_DEPTH_SHIFT;
+
+	dev_dbg(hsotg->dev, "Detected values from hardware:\n");
+	dev_dbg(hsotg->dev, "  op_mode=%d\n",
+		hw->op_mode);
+	dev_dbg(hsotg->dev, "  arch=%d\n",
+		hw->arch);
+	dev_dbg(hsotg->dev, "  dma_desc_enable=%d\n",
+		hw->dma_desc_enable);
+	dev_dbg(hsotg->dev, "  power_optimized=%d\n",
+		hw->power_optimized);
+	dev_dbg(hsotg->dev, "  i2c_enable=%d\n",
+		hw->i2c_enable);
+	dev_dbg(hsotg->dev, "  hs_phy_type=%d\n",
+		hw->hs_phy_type);
+	dev_dbg(hsotg->dev, "  fs_phy_type=%d\n",
+		hw->fs_phy_type);
+	dev_dbg(hsotg->dev, "  utmi_phy_data_wdith=%d\n",
+		hw->utmi_phy_data_width);
+	dev_dbg(hsotg->dev, "  num_dev_ep=%d\n",
+		hw->num_dev_ep);
+	dev_dbg(hsotg->dev, "  num_dev_perio_in_ep=%d\n",
+		hw->num_dev_perio_in_ep);
+	dev_dbg(hsotg->dev, "  host_channels=%d\n",
+		hw->host_channels);
+	dev_dbg(hsotg->dev, "  max_transfer_size=%d\n",
+		hw->max_transfer_size);
+	dev_dbg(hsotg->dev, "  max_packet_count=%d\n",
+		hw->max_packet_count);
+	dev_dbg(hsotg->dev, "  nperio_tx_q_depth=0x%0x\n",
+		hw->nperio_tx_q_depth);
+	dev_dbg(hsotg->dev, "  host_perio_tx_q_depth=0x%0x\n",
+		hw->host_perio_tx_q_depth);
+	dev_dbg(hsotg->dev, "  dev_token_q_depth=0x%0x\n",
+		hw->dev_token_q_depth);
+	dev_dbg(hsotg->dev, "  enable_dynamic_fifo=%d\n",
+		hw->enable_dynamic_fifo);
+	dev_dbg(hsotg->dev, "  en_multiple_tx_fifo=%d\n",
+		hw->en_multiple_tx_fifo);
+	dev_dbg(hsotg->dev, "  total_fifo_size=%d\n",
+		hw->total_fifo_size);
+	dev_dbg(hsotg->dev, "  host_rx_fifo_size=%d\n",
+		hw->host_rx_fifo_size);
+	dev_dbg(hsotg->dev, "  host_nperio_tx_fifo_size=%d\n",
+		hw->host_nperio_tx_fifo_size);
+	dev_dbg(hsotg->dev, "  host_perio_tx_fifo_size=%d\n",
+		hw->host_perio_tx_fifo_size);
+	dev_dbg(hsotg->dev, "\n");
+
+	return 0;
+}
+
 /*
  * This function is called during module intialization to pass module parameters
  * for the DWC_otg core. It returns non-0 if any parameters are invalid.
@@ -2681,7 +2780,7 @@
 	retval |= dwc2_set_param_en_multiple_tx_fifo(hsotg,
 			params->en_multiple_tx_fifo);
 	retval |= dwc2_set_param_reload_ctl(hsotg, params->reload_ctl);
-	retval |= dwc2_set_param_ahb_single(hsotg, params->ahb_single);
+	retval |= dwc2_set_param_ahbcfg(hsotg, params->ahbcfg);
 	retval |= dwc2_set_param_otg_ver(hsotg, params->otg_ver);
 
 	return retval;
diff --git a/drivers/staging/dwc2/core.h b/drivers/staging/dwc2/core.h
index fc075a7..9102f66 100644
--- a/drivers/staging/dwc2/core.h
+++ b/drivers/staging/dwc2/core.h
@@ -68,16 +68,18 @@
 /**
  * struct dwc2_core_params - Parameters for configuring the core
  *
- * @otg_cap:            Specifies the OTG capabilities. The driver will
- *                      automatically detect the value for this parameter if
- *                      none is specified.
- *                       0 - HNP and SRP capable (default)
+ * @otg_cap:            Specifies the OTG capabilities.
+ *                       0 - HNP and SRP capable
  *                       1 - SRP Only capable
- *                       2 - No HNP/SRP capable
+ *                       2 - No HNP/SRP capable (always available)
+ *                      Defaults to best available option (0, 1, then 2)
+ * @otg_ver:            OTG version supported
+ *                       0 - 1.3 (default)
+ *                       1 - 2.0
  * @dma_enable:         Specifies whether to use slave or DMA mode for accessing
  *                      the data FIFOs. The driver will automatically detect the
  *                      value for this parameter if none is specified.
- *                       0 - Slave
+ *                       0 - Slave (always available)
  *                       1 - DMA (default, if available)
  * @dma_desc_enable:    When DMA mode is enabled, specifies whether to use
  *                      address DMA mode or descriptor DMA mode for accessing
@@ -88,39 +90,47 @@
  * @speed:              Specifies the maximum speed of operation in host and
  *                      device mode. The actual speed depends on the speed of
  *                      the attached device and the value of phy_type.
- *                       0 - High Speed (default)
+ *                       0 - High Speed
+ *                           (default when phy_type is UTMI+ or ULPI)
  *                       1 - Full Speed
- * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
- *                      when attached to a Full Speed or Low Speed device in
- *                      host mode.
- *                       0 - Don't support low power mode (default)
- *                       1 - Support low power mode
- * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
- *                      when connected to a Low Speed device in host mode. This
- *                      parameter is applicable only if
- *                      host_support_fs_ls_low_power is enabled. If phy_type is
- *                      set to FS then defaults to 6 MHZ otherwise 48 MHZ.
- *                       0 - 48 MHz
- *                       1 - 6 MHz
+ *                           (default when phy_type is Full Speed)
  * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
- *                       1 - Allow dynamic FIFO sizing (default)
+ *                       1 - Allow dynamic FIFO sizing (default, if available)
+ * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
+ *                      are enabled
  * @host_rx_fifo_size:  Number of 4-byte words in the Rx FIFO in host mode when
  *                      dynamic FIFO sizing is enabled
- *                       16 to 32768 (default 1024)
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
  * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
  *                      in host mode when dynamic FIFO sizing is enabled
- *                       16 to 32768 (default 1024)
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
  * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
  *                      host mode when dynamic FIFO sizing is enabled
- *                       16 to 32768 (default 1024)
+ *                       16 to 32768
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
  * @max_transfer_size:  The maximum transfer size supported, in bytes
- *                       2047 to 65,535 (default 65,535)
+ *                       2047 to 65,535
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
  * @max_packet_count:   The maximum number of packets in a transfer
- *                       15 to 511 (default 511)
+ *                       15 to 511
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
  * @host_channels:      The number of host channel registers to use
- *                       1 to 16 (default 12)
+ *                       1 to 16
+ *                      Actual maximum value is autodetected and also
+ *                      the default.
  * @phy_type:           Specifies the type of PHY interface to use. By default,
  *                      the driver will automatically detect the phy_type.
+ *                       0 - Full Speed Phy
+ *                       1 - UTMI+ Phy
+ *                       2 - ULPI Phy
+ *                      Defaults to best available option (2, 1, then 0)
  * @phy_utmi_width:     Specifies the UTMI+ Data Width (in bits). This parameter
  *                      is applicable for a phy_type of UTMI+ or ULPI. (For a
  *                      ULPI phy_type, this parameter indicates the data width
@@ -129,7 +139,7 @@
  *                      parameter was set to "8 and 16 bits", meaning that the
  *                      core has been configured to work at either data path
  *                      width.
- *                       8 or 16 (default 16)
+ *                       8 or 16 (default 16 if available)
  * @phy_ulpi_ddr:       Specifies whether the ULPI operates at double or single
  *                      data rate. This parameter is only applicable if phy_type
  *                      is ULPI.
@@ -139,27 +149,51 @@
  *                           data bus
  * @phy_ulpi_ext_vbus:  For a ULPI phy, specifies whether to use the internal or
  *                      external supply to drive the VBus
+ *                       0 - Internal supply (default)
+ *                       1 - External supply
  * @i2c_enable:         Specifies whether to use the I2Cinterface for a full
  *                      speed PHY. This parameter is only applicable if phy_type
  *                      is FS.
  *                       0 - No (default)
  *                       1 - Yes
- * @ulpi_fs_ls:         True to make ULPI phy operate in FS/LS mode only
- * @ts_dline:           True to enable Term Select Dline pulsing
- * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
- *                      are enabled
- * @reload_ctl:         True to allow dynamic reloading of HFIR register during
- *                      runtime
- * @ahb_single:         This bit enables SINGLE transfers for remainder data in
- *                      a transfer for DMA mode of operation.
- *                       0 - remainder data will be sent using INCR burst size
- *                       1 - remainder data will be sent using SINGLE burst size
- * @otg_ver:            OTG version supported
- *                       0 - 1.3
- *                       1 - 2.0
+ * @ulpi_fs_ls:         Make ULPI phy operate in FS/LS mode only
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
+ *                      when attached to a Full Speed or Low Speed device in
+ *                      host mode.
+ *                       0 - Don't support low power mode (default)
+ *                       1 - Support low power mode
+ * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
+ *                      when connected to a Low Speed device in host
+ *                      mode. This parameter is applicable only if
+ *                      host_support_fs_ls_low_power is enabled.
+ *                       0 - 48 MHz
+ *                           (default when phy_type is UTMI+ or ULPI)
+ *                       1 - 6 MHz
+ *                           (default when phy_type is Full Speed)
+ * @ts_dline:           Enable Term Select Dline pulsing
+ *                       0 - No (default)
+ *                       1 - Yes
+ * @reload_ctl:         Allow dynamic reloading of HFIR register during runtime
+ *                       0 - No (default for core < 2.92a)
+ *                       1 - Yes (default for core >= 2.92a)
+ * @ahbcfg:             This field allows the default value of the GAHBCFG
+ *                      register to be overridden
+ *                       -1         - GAHBCFG value will be set to 0x06
+ *                                    (INCR4, default)
+ *                       all others - GAHBCFG value will be overridden with
+ *                                    this value
+ *                      Not all bits can be controlled like this, the
+ *                      bits defined by GAHBCFG_CTRL_MASK are controlled
+ *                      by the driver and are ignored in this
+ *                      configuration value.
  *
  * The following parameters may be specified when starting the module. These
- * parameters define how the DWC_otg controller should be configured.
+ * parameters define how the DWC_otg controller should be configured. A
+ * value of -1 (or any other out of range value) for any parameter means
+ * to read the value from hardware (if possible) or use the builtin
+ * default described above.
  */
 struct dwc2_core_params {
 	/*
@@ -189,7 +223,85 @@
 	int host_ls_low_power_phy_clk;
 	int ts_dline;
 	int reload_ctl;
-	int ahb_single;
+	int ahbcfg;
+};
+
+/**
+ * struct dwc2_hw_params - Autodetected parameters.
+ *
+ * These parameters are the various parameters read from hardware
+ * registers during initialization. They typically contain the best
+ * supported or maximum value that can be configured in the
+ * corresponding dwc2_core_params value.
+ *
+ * The values that are not in dwc2_core_params are documented below.
+ *
+ * @op_mode             Mode of Operation
+ *                       0 - HNP- and SRP-Capable OTG (Host & Device)
+ *                       1 - SRP-Capable OTG (Host & Device)
+ *                       2 - Non-HNP and Non-SRP Capable OTG (Host & Device)
+ *                       3 - SRP-Capable Device
+ *                       4 - Non-OTG Device
+ *                       5 - SRP-Capable Host
+ *                       6 - Non-OTG Host
+ * @arch                Architecture
+ *                       0 - Slave only
+ *                       1 - External DMA
+ *                       2 - Internal DMA
+ * @power_optimized     Are power optimizations enabled?
+ * @num_dev_ep          Number of device endpoints available
+ * @num_dev_perio_in_ep Number of device periodic IN endpoints
+ *                      avaialable
+ * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue
+ *                      Depth
+ *                       0 to 30
+ * @host_perio_tx_q_depth
+ *                      Host Mode Periodic Request Queue Depth
+ *                       2, 4 or 8
+ * @nperio_tx_q_depth
+ *                      Non-Periodic Request Queue Depth
+ *                       2, 4 or 8
+ * @hs_phy_type         High-speed PHY interface type
+ *                       0 - High-speed interface not supported
+ *                       1 - UTMI+
+ *                       2 - ULPI
+ *                       3 - UTMI+ and ULPI
+ * @fs_phy_type         Full-speed PHY interface type
+ *                       0 - Full speed interface not supported
+ *                       1 - Dedicated full speed interface
+ *                       2 - FS pins shared with UTMI+ pins
+ *                       3 - FS pins shared with ULPI pins
+ * @total_fifo_size:    Total internal RAM for FIFOs (bytes)
+ * @utmi_phy_data_width UTMI+ PHY data width
+ *                       0 - 8 bits
+ *                       1 - 16 bits
+ *                       2 - 8 or 16 bits
+ * @snpsid:             Value from SNPSID register
+ */
+struct dwc2_hw_params {
+	unsigned op_mode:3;
+	unsigned arch:2;
+	unsigned dma_desc_enable:1;
+	unsigned enable_dynamic_fifo:1;
+	unsigned en_multiple_tx_fifo:1;
+	unsigned host_rx_fifo_size:16;
+	unsigned host_nperio_tx_fifo_size:16;
+	unsigned host_perio_tx_fifo_size:16;
+	unsigned nperio_tx_q_depth:3;
+	unsigned host_perio_tx_q_depth:3;
+	unsigned dev_token_q_depth:5;
+	unsigned max_transfer_size:26;
+	unsigned max_packet_count:11;
+	unsigned host_channels:4;
+	unsigned hs_phy_type:2;
+	unsigned fs_phy_type:2;
+	unsigned i2c_enable:1;
+	unsigned num_dev_ep:4;
+	unsigned num_dev_perio_in_ep:4;
+	unsigned total_fifo_size:16;
+	unsigned power_optimized:1;
+	unsigned utmi_phy_data_width:2;
+	u32 snpsid;
 };
 
 /**
@@ -199,15 +311,8 @@
  * @dev:                The struct device pointer
  * @regs:		Pointer to controller regs
  * @core_params:        Parameters that define how the core should be configured
- * @hwcfg1:             Hardware Configuration - stored here for convenience
- * @hwcfg2:             Hardware Configuration - stored here for convenience
- * @hwcfg3:             Hardware Configuration - stored here for convenience
- * @hwcfg4:             Hardware Configuration - stored here for convenience
- * @hptxfsiz:           Hardware Configuration - stored here for convenience
- * @snpsid:             Value from SNPSID register
- * @total_fifo_size:    Total internal RAM for FIFOs (bytes)
- * @rx_fifo_size:       Size of Rx FIFO (bytes)
- * @nperio_tx_fifo_size: Size of Non-periodic Tx FIFO (Bytes)
+ * @hw_params:          Parameters that were autodetected from the
+ *                      hardware registers
  * @op_state:           The operational State, during transitions (a_host=>
  *                      a_peripheral and b_device=>b_host) this may not match
  *                      the core, but allows the software to determine
@@ -295,16 +400,10 @@
 struct dwc2_hsotg {
 	struct device *dev;
 	void __iomem *regs;
+	/** Params detected from hardware */
+	struct dwc2_hw_params hw_params;
+	/** Params to actually use */
 	struct dwc2_core_params *core_params;
-	u32 hwcfg1;
-	u32 hwcfg2;
-	u32 hwcfg3;
-	u32 hwcfg4;
-	u32 hptxfsiz;
-	u32 snpsid;
-	u16 total_fifo_size;
-	u16 rx_fifo_size;
-	u16 nperio_tx_fifo_size;
 	enum usb_otg_state op_state;
 
 	unsigned int queuing_high_bandwidth:1;
@@ -643,7 +742,7 @@
 
 extern int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val);
 
-extern int dwc2_set_param_ahb_single(struct dwc2_hsotg *hsotg, int val);
+extern int dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
 
 extern int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
 
diff --git a/drivers/staging/dwc2/core_intr.c b/drivers/staging/dwc2/core_intr.c
index 98c51bb..07cfa2f 100644
--- a/drivers/staging/dwc2/core_intr.c
+++ b/drivers/staging/dwc2/core_intr.c
@@ -166,7 +166,7 @@
 		 * WA for 3.00a- HW is not setting cur_mode, even sometimes
 		 * this does not help
 		 */
-		if (hsotg->snpsid >= DWC2_CORE_REV_3_00a)
+		if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)
 			udelay(100);
 		if (gotgctl & GOTGCTL_HSTNEGSCS) {
 			if (dwc2_is_host_mode(hsotg)) {
@@ -380,7 +380,7 @@
 		dev_dbg(hsotg->dev,
 			"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
 			!!(dsts & DSTS_SUSPSTS),
-			!!(hsotg->hwcfg4 & GHWCFG4_POWER_OPTIMIZ));
+			hsotg->hw_params.power_optimized);
 	} else {
 		if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
 			dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c
index 2ed54b1..da0d35c 100644
--- a/drivers/staging/dwc2/hcd.c
+++ b/drivers/staging/dwc2/hcd.c
@@ -134,11 +134,8 @@
 	list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
 		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
 					 qtd_list_entry) {
-			if (qtd->urb != NULL) {
-				dwc2_host_complete(hsotg, qtd->urb->priv,
-						   qtd->urb, -ETIMEDOUT);
-				dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-			}
+			dwc2_host_complete(hsotg, qtd, -ETIMEDOUT);
+			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
 		}
 	}
 }
@@ -421,6 +418,8 @@
 		return -EINVAL;
 	}
 
+	urb->priv = NULL;
+
 	if (urb_qtd->in_process && qh->channel) {
 		dwc2_dump_channel_info(hsotg, qh->channel);
 
@@ -1006,10 +1005,10 @@
 		dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
 
 	tx_status = readl(hsotg->regs + HPTXSTS);
-	qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-		    TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
-	fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-		    TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+	qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+		    TXSTS_QSPCAVAIL_SHIFT;
+	fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+		    TXSTS_FSPCAVAIL_SHIFT;
 
 	if (dbg_perio()) {
 		dev_vdbg(hsotg->dev, "  P Tx Req Queue Space Avail (before queue): %d\n",
@@ -1021,7 +1020,9 @@
 	qh_ptr = hsotg->periodic_sched_assigned.next;
 	while (qh_ptr != &hsotg->periodic_sched_assigned) {
 		tx_status = readl(hsotg->regs + HPTXSTS);
-		if ((tx_status & TXSTS_QSPCAVAIL_MASK) == 0) {
+		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+			    TXSTS_QSPCAVAIL_SHIFT;
+		if (qspcavail == 0) {
 			no_queue_space = 1;
 			break;
 		}
@@ -1047,8 +1048,8 @@
 				qh->channel->multi_count > 1)
 			hsotg->queuing_high_bandwidth = 1;
 
-		fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-			    TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+			    TXSTS_FSPCAVAIL_SHIFT;
 		status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
 		if (status < 0) {
 			no_fifo_space = 1;
@@ -1079,10 +1080,10 @@
 
 	if (hsotg->core_params->dma_enable <= 0) {
 		tx_status = readl(hsotg->regs + HPTXSTS);
-		qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-			    TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
-		fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-			    TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+			    TXSTS_QSPCAVAIL_SHIFT;
+		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+			    TXSTS_FSPCAVAIL_SHIFT;
 		if (dbg_perio()) {
 			dev_vdbg(hsotg->dev,
 				 "  P Tx Req Queue Space Avail (after queue): %d\n",
@@ -1144,10 +1145,10 @@
 	dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
 
 	tx_status = readl(hsotg->regs + GNPTXSTS);
-	qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-		    TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
-	fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-		    TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+	qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+		    TXSTS_QSPCAVAIL_SHIFT;
+	fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+		    TXSTS_FSPCAVAIL_SHIFT;
 	dev_vdbg(hsotg->dev, "  NP Tx Req Queue Space Avail (before queue): %d\n",
 		 qspcavail);
 	dev_vdbg(hsotg->dev, "  NP Tx FIFO Space Avail (before queue): %d\n",
@@ -1167,8 +1168,8 @@
 	 */
 	do {
 		tx_status = readl(hsotg->regs + GNPTXSTS);
-		qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-			    TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+			    TXSTS_QSPCAVAIL_SHIFT;
 		if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
 			no_queue_space = 1;
 			break;
@@ -1183,8 +1184,8 @@
 		if (qh->tt_buffer_dirty)
 			goto next;
 
-		fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-			    TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+			    TXSTS_FSPCAVAIL_SHIFT;
 		status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
 
 		if (status > 0) {
@@ -1204,10 +1205,10 @@
 
 	if (hsotg->core_params->dma_enable <= 0) {
 		tx_status = readl(hsotg->regs + GNPTXSTS);
-		qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-			    TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
-		fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-			    TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
+			    TXSTS_QSPCAVAIL_SHIFT;
+		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
+			    TXSTS_FSPCAVAIL_SHIFT;
 		dev_vdbg(hsotg->dev,
 			 "  NP Tx Req Queue Space Avail (after queue): %d\n",
 			 qspcavail);
@@ -1613,7 +1614,7 @@
 		if (hprt0 & HPRT0_PWR)
 			port_status |= USB_PORT_STAT_POWER;
 
-		speed = hprt0 & HPRT0_SPD_MASK;
+		speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
 		if (speed == HPRT0_SPD_HIGH_SPEED)
 			port_status |= USB_PORT_STAT_HIGH_SPEED;
 		else if (speed == HPRT0_SPD_LOW_SPEED)
@@ -1762,11 +1763,9 @@
 
 #ifdef DWC2_DEBUG_SOF
 	dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
-		 hfnum >> HFNUM_FRNUM_SHIFT &
-		 HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT);
+		 (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT);
 #endif
-	return hfnum >> HFNUM_FRNUM_SHIFT &
-	       HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT;
+	return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
 }
 
 int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
@@ -1917,18 +1916,14 @@
 	dev_dbg(hsotg->dev, "  periodic_usecs: %d\n", hsotg->periodic_usecs);
 	np_tx_status = readl(hsotg->regs + GNPTXSTS);
 	dev_dbg(hsotg->dev, "  NP Tx Req Queue Space Avail: %d\n",
-		np_tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-		TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT);
+		(np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
 	dev_dbg(hsotg->dev, "  NP Tx FIFO Space Avail: %d\n",
-		np_tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-		TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT);
+		(np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
 	p_tx_status = readl(hsotg->regs + HPTXSTS);
 	dev_dbg(hsotg->dev, "  P Tx Req Queue Space Avail: %d\n",
-		p_tx_status >> TXSTS_QSPCAVAIL_SHIFT &
-		TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT);
+		(p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
 	dev_dbg(hsotg->dev, "  P Tx FIFO Space Avail: %d\n",
-		p_tx_status >> TXSTS_FSPCAVAIL_SHIFT &
-		TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT);
+		(p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
 	dwc2_hcd_dump_frrem(hsotg);
 	dwc2_dump_global_registers(hsotg);
 	dwc2_dump_host_registers(hsotg);
@@ -2088,23 +2083,29 @@
  *
  * Must be called with interrupt disabled and spinlock held
  */
-void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
-			struct dwc2_hcd_urb *dwc2_urb, int status)
+void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+			int status)
 {
-	struct urb *urb = context;
+	struct urb *urb;
 	int i;
 
+	if (!qtd) {
+		dev_dbg(hsotg->dev, "## %s: qtd is NULL ##\n", __func__);
+		return;
+	}
+
+	if (!qtd->urb) {
+		dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__);
+		return;
+	}
+
+	urb = qtd->urb->priv;
 	if (!urb) {
-		dev_dbg(hsotg->dev, "## %s: context is NULL ##\n", __func__);
+		dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__);
 		return;
 	}
 
-	if (!dwc2_urb) {
-		dev_dbg(hsotg->dev, "## %s: dwc2_urb is NULL ##\n", __func__);
-		return;
-	}
-
-	urb->actual_length = dwc2_hcd_urb_get_actual_length(dwc2_urb);
+	urb->actual_length = dwc2_hcd_urb_get_actual_length(qtd->urb);
 
 	if (dbg_urb(urb))
 		dev_vdbg(hsotg->dev,
@@ -2121,18 +2122,17 @@
 	}
 
 	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-		urb->error_count = dwc2_hcd_urb_get_error_count(dwc2_urb);
+		urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb);
 		for (i = 0; i < urb->number_of_packets; ++i) {
 			urb->iso_frame_desc[i].actual_length =
 				dwc2_hcd_urb_get_iso_desc_actual_length(
-						dwc2_urb, i);
+						qtd->urb, i);
 			urb->iso_frame_desc[i].status =
-				dwc2_hcd_urb_get_iso_desc_status(dwc2_urb, i);
+				dwc2_hcd_urb_get_iso_desc_status(qtd->urb, i);
 		}
 	}
 
 	urb->status = status;
-	urb->hcpriv = NULL;
 	if (!status) {
 		if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
 		    urb->actual_length < urb->transfer_buffer_length)
@@ -2149,7 +2149,10 @@
 					urb);
 	}
 
-	kfree(dwc2_urb);
+	usb_hcd_unlink_urb_from_ep(dwc2_hsotg_to_hcd(hsotg), urb);
+	urb->hcpriv = NULL;
+	kfree(qtd->urb);
+	qtd->urb = NULL;
 
 	spin_unlock(&hsotg->lock);
 	usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
@@ -2337,8 +2340,8 @@
 	struct usb_host_endpoint *ep = urb->ep;
 	struct dwc2_hcd_urb *dwc2_urb;
 	int i;
+	int retval;
 	int alloc_bandwidth = 0;
-	int retval = 0;
 	u8 ep_type = 0;
 	u32 tflags = 0;
 	void *buf;
@@ -2389,14 +2392,15 @@
 						!(usb_pipein(urb->pipe))));
 
 	buf = urb->transfer_buffer;
+
 	if (hcd->self.uses_dma) {
-		/*
-		 * Calculate virtual address from physical address, because
-		 * some class driver may not fill transfer_buffer.
-		 * In Buffer DMA mode virtual address is used, when handling
-		 * non-DWORD aligned buffers.
-		 */
-		buf = bus_to_virt(urb->transfer_dma);
+		if (!buf && (urb->transfer_dma & 3)) {
+			dev_err(hsotg->dev,
+				"%s: unaligned transfer with no transfer_buffer",
+				__func__);
+			retval = -EINVAL;
+			goto fail1;
+		}
 	}
 
 	if (!(urb->transfer_flags & URB_NO_INTERRUPT))
@@ -2420,21 +2424,36 @@
 						 urb->iso_frame_desc[i].length);
 
 	urb->hcpriv = dwc2_urb;
-	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv,
-				      mem_flags);
-	if (retval) {
-		urb->hcpriv = NULL;
-		kfree(dwc2_urb);
-	} else {
-		if (alloc_bandwidth) {
-			spin_lock_irqsave(&hsotg->lock, flags);
-			dwc2_allocate_bus_bandwidth(hcd,
-					dwc2_hcd_get_ep_bandwidth(hsotg, ep),
-					urb);
-			spin_unlock_irqrestore(&hsotg->lock, flags);
-		}
+
+	spin_lock_irqsave(&hsotg->lock, flags);
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+	if (retval)
+		goto fail1;
+
+	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags);
+	if (retval)
+		goto fail2;
+
+	if (alloc_bandwidth) {
+		spin_lock_irqsave(&hsotg->lock, flags);
+		dwc2_allocate_bus_bandwidth(hcd,
+				dwc2_hcd_get_ep_bandwidth(hsotg, ep),
+				urb);
+		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
 
+	return 0;
+
+fail2:
+	spin_lock_irqsave(&hsotg->lock, flags);
+	dwc2_urb->priv = NULL;
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+fail1:
+	urb->hcpriv = NULL;
+	kfree(dwc2_urb);
+
 	return retval;
 }
 
@@ -2445,7 +2464,7 @@
 				 int status)
 {
 	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-	int rc = 0;
+	int rc;
 	unsigned long flags;
 
 	dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n");
@@ -2453,6 +2472,10 @@
 
 	spin_lock_irqsave(&hsotg->lock, flags);
 
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto out;
+
 	if (!urb->hcpriv) {
 		dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n");
 		goto out;
@@ -2460,6 +2483,8 @@
 
 	rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv);
 
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+
 	kfree(urb->hcpriv);
 	urb->hcpriv = NULL;
 
@@ -2653,7 +2678,7 @@
 	writel(ahbcfg, hsotg->regs + GAHBCFG);
 	writel(0, hsotg->regs + GINTMSK);
 
-	if (hsotg->snpsid >= DWC2_CORE_REV_3_00a) {
+	if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
 		dctl = readl(hsotg->regs + DCTL);
 		dctl |= DCTL_SFTDISCON;
 		writel(dctl, hsotg->regs + DCTL);
@@ -2690,7 +2715,7 @@
 	int i;
 
 	for (i = 0; i < size; i++)
-		p[i] = -1;
+		p[i] = value;
 }
 EXPORT_SYMBOL_GPL(dwc2_set_all_params);
 
@@ -2705,79 +2730,22 @@
 {
 	struct usb_hcd *hcd;
 	struct dwc2_host_chan *channel;
-	u32 snpsid, gusbcfg, hcfg;
+	u32 hcfg;
 	int i, num_channels;
-	int retval = -ENOMEM;
+	int retval;
 
 	dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
 
-	/*
-	 * Attempt to ensure this device is really a DWC_otg Controller.
-	 * Read and verify the GSNPSID register contents. The value should be
-	 * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
-	 * as in "OTG version 2.xx" or "OTG version 3.xx".
-	 */
-	snpsid = readl(hsotg->regs + GSNPSID);
-	if ((snpsid & 0xfffff000) != 0x4f542000 &&
-	    (snpsid & 0xfffff000) != 0x4f543000) {
-		dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", snpsid);
-		retval = -ENODEV;
-		goto error1;
-	}
+	/* Detect config values from hardware */
+	retval = dwc2_get_hwparams(hsotg);
 
-	/*
-	 * Store the contents of the hardware configuration registers here for
-	 * easy access later
-	 */
-	hsotg->hwcfg1 = readl(hsotg->regs + GHWCFG1);
-	hsotg->hwcfg2 = readl(hsotg->regs + GHWCFG2);
-	hsotg->hwcfg3 = readl(hsotg->regs + GHWCFG3);
-	hsotg->hwcfg4 = readl(hsotg->regs + GHWCFG4);
+	if (retval)
+		return retval;
 
-	dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hsotg->hwcfg1);
-	dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hsotg->hwcfg2);
-	dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hsotg->hwcfg3);
-	dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hsotg->hwcfg4);
-
-	/* Force host mode to get HPTXFSIZ exact power on value */
-	gusbcfg = readl(hsotg->regs + GUSBCFG);
-	gusbcfg |= GUSBCFG_FORCEHOSTMODE;
-	writel(gusbcfg, hsotg->regs + GUSBCFG);
-	usleep_range(100000, 150000);
-
-	hsotg->hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
-	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hsotg->hptxfsiz);
-	gusbcfg = readl(hsotg->regs + GUSBCFG);
-	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
-	writel(gusbcfg, hsotg->regs + GUSBCFG);
-	usleep_range(100000, 150000);
+	retval = -ENOMEM;
 
 	hcfg = readl(hsotg->regs + HCFG);
 	dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
-	dev_dbg(hsotg->dev, "op_mode=%0x\n",
-		hsotg->hwcfg2 >> GHWCFG2_OP_MODE_SHIFT &
-		GHWCFG2_OP_MODE_MASK >> GHWCFG2_OP_MODE_SHIFT);
-	dev_dbg(hsotg->dev, "arch=%0x\n",
-		hsotg->hwcfg2 >> GHWCFG2_ARCHITECTURE_SHIFT &
-		GHWCFG2_ARCHITECTURE_MASK >> GHWCFG2_ARCHITECTURE_SHIFT);
-	dev_dbg(hsotg->dev, "num_dev_ep=%d\n",
-		hsotg->hwcfg2 >> GHWCFG2_NUM_DEV_EP_SHIFT &
-		GHWCFG2_NUM_DEV_EP_MASK >> GHWCFG2_NUM_DEV_EP_SHIFT);
-	dev_dbg(hsotg->dev, "max_host_chan=%d\n",
-		hsotg->hwcfg2 >> GHWCFG2_NUM_HOST_CHAN_SHIFT &
-		GHWCFG2_NUM_HOST_CHAN_MASK >> GHWCFG2_NUM_HOST_CHAN_SHIFT);
-	dev_dbg(hsotg->dev, "nonperio_tx_q_depth=0x%0x\n",
-		hsotg->hwcfg2 >> GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT &
-		GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK >>
-				GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT);
-	dev_dbg(hsotg->dev, "host_perio_tx_q_depth=0x%0x\n",
-		hsotg->hwcfg2 >> GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT &
-		GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK >>
-				GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT);
-	dev_dbg(hsotg->dev, "dev_token_q_depth=0x%0x\n",
-		hsotg->hwcfg2 >> GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT &
-		GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK >>
-				GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT);
 
 #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
 	hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) *
@@ -2801,22 +2769,30 @@
 	/* Validate parameter values */
 	dwc2_set_parameters(hsotg, params);
 
+	/* Check if the bus driver or platform code has setup a dma_mask */
+	if (hsotg->core_params->dma_enable > 0 &&
+	    hsotg->dev->dma_mask == NULL) {
+		dev_warn(hsotg->dev,
+			 "dma_mask not set, disabling DMA\n");
+		hsotg->core_params->dma_enable = 0;
+		hsotg->core_params->dma_desc_enable = 0;
+	}
+
 	/* Set device flags indicating whether the HCD supports DMA */
 	if (hsotg->core_params->dma_enable > 0) {
 		if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
 			dev_warn(hsotg->dev, "can't set DMA mask\n");
-		if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0)
-			dev_warn(hsotg->dev,
-				 "can't enable workaround for >2GB RAM\n");
-	} else {
-		dma_set_mask(hsotg->dev, 0);
-		dma_set_coherent_mask(hsotg->dev, 0);
+		if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
+			dev_warn(hsotg->dev, "can't set coherent DMA mask\n");
 	}
 
 	hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
 	if (!hcd)
 		goto error1;
 
+	if (hsotg->core_params->dma_enable <= 0)
+		hcd->self.uses_dma = 0;
+
 	hcd->has_tt = 1;
 
 	spin_lock_init(&hsotg->lock);
@@ -2843,11 +2819,6 @@
 	}
 	INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change);
 
-	hsotg->snpsid = readl(hsotg->regs + GSNPSID);
-	dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x\n",
-		hsotg->snpsid >> 12 & 0xf, hsotg->snpsid >> 8 & 0xf,
-		hsotg->snpsid >> 4 & 0xf, hsotg->snpsid & 0xf);
-
 	setup_timer(&hsotg->wkp_timer, dwc2_wakeup_detected,
 		    (unsigned long)hsotg);
 
@@ -2922,8 +2893,6 @@
 	if (retval < 0)
 		goto error3;
 
-	dwc2_dump_global_registers(hsotg);
-	dwc2_dump_host_registers(hsotg);
 	dwc2_hcd_dump_state(hsotg);
 
 	dwc2_enable_global_interrupts(hsotg);
diff --git a/drivers/staging/dwc2/hcd.h b/drivers/staging/dwc2/hcd.h
index cf6c055..cc0a117 100644
--- a/drivers/staging/dwc2/hcd.h
+++ b/drivers/staging/dwc2/hcd.h
@@ -122,11 +122,11 @@
 	unsigned ep_type:2;
 	unsigned max_packet:11;
 	unsigned data_pid_start:2;
-#define DWC2_HC_PID_DATA0	(TSIZ_SC_MC_PID_DATA0 >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_DATA2	(TSIZ_SC_MC_PID_DATA2 >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_DATA1	(TSIZ_SC_MC_PID_DATA1 >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_MDATA	(TSIZ_SC_MC_PID_MDATA >> TSIZ_SC_MC_PID_SHIFT)
-#define DWC2_HC_PID_SETUP	(TSIZ_SC_MC_PID_SETUP >> TSIZ_SC_MC_PID_SHIFT)
+#define DWC2_HC_PID_DATA0	TSIZ_SC_MC_PID_DATA0
+#define DWC2_HC_PID_DATA2	TSIZ_SC_MC_PID_DATA2
+#define DWC2_HC_PID_DATA1	TSIZ_SC_MC_PID_DATA1
+#define DWC2_HC_PID_MDATA	TSIZ_SC_MC_PID_MDATA
+#define DWC2_HC_PID_SETUP	TSIZ_SC_MC_PID_SETUP
 
 	unsigned multi_count:2;
 
@@ -146,10 +146,10 @@
 	u8 hub_addr;
 	u8 hub_port;
 	u8 xact_pos;
-#define DWC2_HCSPLT_XACTPOS_MID	(HCSPLT_XACTPOS_MID >> HCSPLT_XACTPOS_SHIFT)
-#define DWC2_HCSPLT_XACTPOS_END	(HCSPLT_XACTPOS_END >> HCSPLT_XACTPOS_SHIFT)
-#define DWC2_HCSPLT_XACTPOS_BEGIN (HCSPLT_XACTPOS_BEGIN >> HCSPLT_XACTPOS_SHIFT)
-#define DWC2_HCSPLT_XACTPOS_ALL	(HCSPLT_XACTPOS_ALL >> HCSPLT_XACTPOS_SHIFT)
+#define DWC2_HCSPLT_XACTPOS_MID	HCSPLT_XACTPOS_MID
+#define DWC2_HCSPLT_XACTPOS_END	HCSPLT_XACTPOS_END
+#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN
+#define DWC2_HCSPLT_XACTPOS_ALL	HCSPLT_XACTPOS_ALL
 
 	u8 requests;
 	u8 schinfo;
@@ -232,16 +232,19 @@
  *                       - DWC2_HC_PID_DATA1
  * @ping_state:         Ping state
  * @do_split:           Full/low speed endpoint on high-speed hub requires split
- * @qtd_list:           List of QTDs for this QH
- * @channel:            Host channel currently processing transfers for this QH
+ * @td_first:           Index of first activated isochronous transfer descriptor
+ * @td_last:            Index of last activated isochronous transfer descriptor
  * @usecs:              Bandwidth in microseconds per (micro)frame
  * @interval:           Interval between transfers in (micro)frames
- * @sched_frame:        (micro)frame to initialize a periodic transfer.
+ * @sched_frame:        (Micro)frame to initialize a periodic transfer.
  *                      The transfer executes in the following (micro)frame.
  * @start_split_frame:  (Micro)frame at which last start split was initialized
+ * @ntd:                Actual number of transfer descriptors in a list
  * @dw_align_buf:       Used instead of original buffer if its physical address
  *                      is not dword-aligned
  * @dw_align_buf_dma:   DMA address for align_buf
+ * @qtd_list:           List of QTDs for this QH
+ * @channel:            Host channel currently processing transfers for this QH
  * @qh_list_entry:      Entry for QH in either the periodic or non-periodic
  *                      schedule
  * @desc_list:          List of transfer descriptors
@@ -249,9 +252,6 @@
  * @n_bytes:            Xfer Bytes array. Each element corresponds to a transfer
  *                      descriptor and indicates original XferSize value for the
  *                      descriptor
- * @ntd:                Actual number of transfer descriptors in a list
- * @td_first:           Index of first activated isochronous transfer descriptor
- * @td_last:            Index of last activated isochronous transfer descriptor
  * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending
  *
  * A Queue Head (QH) holds the static characteristics of an endpoint and
@@ -266,21 +266,21 @@
 	u8 data_toggle;
 	u8 ping_state;
 	u8 do_split;
-	struct list_head qtd_list;
-	struct dwc2_host_chan *channel;
+	u8 td_first;
+	u8 td_last;
 	u16 usecs;
 	u16 interval;
 	u16 sched_frame;
 	u16 start_split_frame;
+	u16 ntd;
 	u8 *dw_align_buf;
 	dma_addr_t dw_align_buf_dma;
+	struct list_head qtd_list;
+	struct dwc2_host_chan *channel;
 	struct list_head qh_list_entry;
 	struct dwc2_hcd_dma_desc *desc_list;
 	dma_addr_t desc_list_dma;
 	u32 *n_bytes;
-	u16 ntd;
-	u8 td_first;
-	u8 td_last;
 	unsigned tt_buffer_dirty:1;
 };
 
@@ -453,6 +453,7 @@
 extern int dwc2_set_parameters(struct dwc2_hsotg *hsotg,
 			       const struct dwc2_core_params *params);
 extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
+extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
 
 /* Transaction Execution Functions */
 extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
@@ -716,8 +717,8 @@
 extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
 			       int *hub_addr, int *hub_port);
 extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
-extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
-			       struct dwc2_hcd_urb *dwc2_urb, int status);
+extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+			       int status);
 
 #ifdef DEBUG
 /*
diff --git a/drivers/staging/dwc2/hcd_ddma.c b/drivers/staging/dwc2/hcd_ddma.c
index 5c0fd27..69070f4 100644
--- a/drivers/staging/dwc2/hcd_ddma.c
+++ b/drivers/staging/dwc2/hcd_ddma.c
@@ -800,11 +800,14 @@
 	u16 remain = 0;
 	int rc = 0;
 
+	if (!qtd->urb)
+		return -EINVAL;
+
 	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
 	dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
 	if (chan->ep_is_in)
-		remain = dma_desc->status >> HOST_DMA_ISOC_NBYTES_SHIFT &
-			HOST_DMA_ISOC_NBYTES_MASK >> HOST_DMA_ISOC_NBYTES_SHIFT;
+		remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >>
+			 HOST_DMA_ISOC_NBYTES_SHIFT;
 
 	if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
 		/*
@@ -826,7 +829,7 @@
 		 * urb->status is not used for isoc transfers here. The
 		 * individual frame_desc status are used instead.
 		 */
-		dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, 0);
+		dwc2_host_complete(hsotg, qtd, 0);
 		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
 
 		/*
@@ -884,13 +887,16 @@
 
 		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
 					 qtd_list_entry) {
-			for (idx = 0; idx < qtd->urb->packet_count; idx++) {
-				frame_desc = &qtd->urb->iso_descs[idx];
-				frame_desc->status = err;
+			if (qtd->urb) {
+				for (idx = 0; idx < qtd->urb->packet_count;
+				     idx++) {
+					frame_desc = &qtd->urb->iso_descs[idx];
+					frame_desc->status = err;
+				}
+
+				dwc2_host_complete(hsotg, qtd, err);
 			}
 
-			dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
-					   err);
 			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
 		}
 
@@ -929,8 +935,8 @@
 	u16 remain = 0;
 
 	if (chan->ep_is_in)
-		remain = dma_desc->status >> HOST_DMA_NBYTES_SHIFT &
-			 HOST_DMA_NBYTES_MASK >> HOST_DMA_NBYTES_SHIFT;
+		remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >>
+			 HOST_DMA_NBYTES_SHIFT;
 
 	dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb);
 
@@ -1015,6 +1021,9 @@
 
 	dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
+	if (!urb)
+		return -EINVAL;
+
 	dma_desc = &qh->desc_list[desc_num];
 	n_bytes = qh->n_bytes[desc_num];
 	dev_vdbg(hsotg->dev,
@@ -1024,7 +1033,7 @@
 						     halt_status, n_bytes,
 						     xfer_done);
 	if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
-		dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+		dwc2_host_complete(hsotg, qtd, urb->status);
 		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
 		dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
 			 failed, *xfer_done, urb->status);
diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c
index e75dccb..e143f69 100644
--- a/drivers/staging/dwc2/hcd_intr.c
+++ b/drivers/staging/dwc2/hcd_intr.c
@@ -89,15 +89,20 @@
 {
 	struct urb *usb_urb;
 
-	if (!chan->qh || !qtd->urb)
+	if (!chan->qh)
+		return;
+
+	if (chan->qh->dev_speed == USB_SPEED_HIGH)
+		return;
+
+	if (!qtd->urb)
 		return;
 
 	usb_urb = qtd->urb->priv;
-	if (!usb_urb || !usb_urb->dev)
+	if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt)
 		return;
 
-	if (chan->qh->dev_speed != USB_SPEED_HIGH &&
-	    qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
+	if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
 		chan->qh->tt_buffer_dirty = 1;
 		if (usb_hub_clear_tt_buffer(usb_urb))
 			/* Clear failed; let's hope things work anyway */
@@ -160,19 +165,16 @@
 		dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
 
 	grxsts = readl(hsotg->regs + GRXSTSP);
-	chnum = grxsts >> GRXSTS_HCHNUM_SHIFT &
-		GRXSTS_HCHNUM_MASK >> GRXSTS_HCHNUM_SHIFT;
+	chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
 	chan = hsotg->hc_ptr_array[chnum];
 	if (!chan) {
 		dev_err(hsotg->dev, "Unable to get corresponding channel\n");
 		return;
 	}
 
-	bcnt = grxsts >> GRXSTS_BYTECNT_SHIFT &
-	       GRXSTS_BYTECNT_MASK >> GRXSTS_BYTECNT_SHIFT;
-	dpid = grxsts >> GRXSTS_DPID_SHIFT &
-	       GRXSTS_DPID_MASK >> GRXSTS_DPID_SHIFT;
-	pktsts = grxsts & GRXSTS_PKTSTS_MASK;
+	bcnt = (grxsts & GRXSTS_BYTECNT_MASK) >> GRXSTS_BYTECNT_SHIFT;
+	dpid = (grxsts & GRXSTS_DPID_MASK) >> GRXSTS_DPID_SHIFT;
+	pktsts = (grxsts & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT;
 
 	/* Packet Status */
 	if (dbg_perio()) {
@@ -180,9 +182,7 @@
 		dev_vdbg(hsotg->dev, "    Count = %d\n", bcnt);
 		dev_vdbg(hsotg->dev, "    DPID = %d, chan.dpid = %d\n", dpid,
 			 chan->data_pid_start);
-		dev_vdbg(hsotg->dev, "    PStatus = %d\n",
-			 pktsts >> GRXSTS_PKTSTS_SHIFT &
-			 GRXSTS_PKTSTS_MASK >> GRXSTS_PKTSTS_SHIFT);
+		dev_vdbg(hsotg->dev, "    PStatus = %d\n", pktsts);
 	}
 
 	switch (pktsts) {
@@ -261,7 +261,7 @@
 	}
 
 	usbcfg = readl(hsotg->regs + GUSBCFG);
-	prtspd = hprt0 & HPRT0_SPD_MASK;
+	prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
 
 	if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
 		/* Low power */
@@ -273,7 +273,8 @@
 		}
 
 		hcfg = readl(hsotg->regs + HCFG);
-		fslspclksel = hcfg & HCFG_FSLSPCLKSEL_MASK;
+		fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
+			      HCFG_FSLSPCLKSEL_SHIFT;
 
 		if (prtspd == HPRT0_SPD_LOW_SPEED &&
 		    params->host_ls_low_power_phy_clk ==
@@ -282,8 +283,9 @@
 			dev_vdbg(hsotg->dev,
 				 "FS_PHY programming HCFG to 6 MHz\n");
 			if (fslspclksel != HCFG_FSLSPCLKSEL_6_MHZ) {
+				fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
 				hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
-				hcfg |= HCFG_FSLSPCLKSEL_6_MHZ;
+				hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
 				writel(hcfg, hsotg->regs + HCFG);
 				do_reset = 1;
 			}
@@ -292,8 +294,9 @@
 			dev_vdbg(hsotg->dev,
 				 "FS_PHY programming HCFG to 48 MHz\n");
 			if (fslspclksel != HCFG_FSLSPCLKSEL_48_MHZ) {
+				fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
 				hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
-				hcfg |= HCFG_FSLSPCLKSEL_48_MHZ;
+				hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
 				writel(hcfg, hsotg->regs + HCFG);
 				do_reset = 1;
 			}
@@ -406,8 +409,8 @@
 
 	if (halt_status == DWC2_HC_XFER_COMPLETE) {
 		if (chan->ep_is_in) {
-			count = hctsiz >> TSIZ_XFERSIZE_SHIFT &
-				TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT;
+			count = (hctsiz & TSIZ_XFERSIZE_MASK) >>
+				TSIZ_XFERSIZE_SHIFT;
 			length = chan->xfer_len - count;
 			if (short_read != NULL)
 				*short_read = (count != 0);
@@ -426,8 +429,7 @@
 		 * hctsiz.xfersize field because that reflects the number of
 		 * bytes transferred via the AHB, not the USB).
 		 */
-		count = hctsiz >> TSIZ_PKTCNT_SHIFT &
-			TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT;
+		count = (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT;
 		length = (chan->start_pkt_count - count) * chan->max_packet;
 	}
 
@@ -462,7 +464,7 @@
 
 	/* Non DWORD-aligned buffer case handling */
 	if (chan->align_buf && xfer_length && chan->ep_is_in) {
-		dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+		dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
 		dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
 					DMA_FROM_DEVICE);
 		memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
@@ -490,8 +492,7 @@
 		 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
 	dev_vdbg(hsotg->dev, "  chan->xfer_len %d\n", chan->xfer_len);
 	dev_vdbg(hsotg->dev, "  hctsiz.xfersize %d\n",
-		 hctsiz >> TSIZ_XFERSIZE_SHIFT &
-		 TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT);
+		 (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT);
 	dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n", urb->length);
 	dev_vdbg(hsotg->dev, "  urb->actual_length %d\n", urb->actual_length);
 	dev_vdbg(hsotg->dev, "  short_read %d, xfer_done %d\n", short_read,
@@ -510,7 +511,7 @@
 			       struct dwc2_qtd *qtd)
 {
 	u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
-	u32 pid = hctsiz & TSIZ_SC_MC_PID_MASK;
+	u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
 
 	if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
 		if (pid == TSIZ_SC_MC_PID_DATA0)
@@ -557,8 +558,8 @@
 		/* Non DWORD-aligned buffer case handling */
 		if (chan->align_buf && frame_desc->actual_length &&
 		    chan->ep_is_in) {
-			dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n",
-				__func__);
+			dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
+				 __func__);
 			dma_sync_single_for_cpu(hsotg->dev, urb->dma,
 						urb->length, DMA_FROM_DEVICE);
 			memcpy(urb->buf + frame_desc->offset +
@@ -591,8 +592,8 @@
 		/* Non DWORD-aligned buffer case handling */
 		if (chan->align_buf && frame_desc->actual_length &&
 		    chan->ep_is_in) {
-			dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n",
-				__func__);
+			dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n",
+				 __func__);
 			dma_sync_single_for_cpu(hsotg->dev, urb->dma,
 						urb->length, DMA_FROM_DEVICE);
 			memcpy(urb->buf + frame_desc->offset +
@@ -623,7 +624,7 @@
 		 * urb->status is not used for isoc transfers. The individual
 		 * frame_desc statuses are used instead.
 		 */
-		dwc2_host_complete(hsotg, urb->priv, urb, 0);
+		dwc2_host_complete(hsotg, qtd, 0);
 		halt_status = DWC2_HC_XFER_URB_COMPLETE;
 	} else {
 		halt_status = DWC2_HC_XFER_COMPLETE;
@@ -714,11 +715,7 @@
 			dev_vdbg(hsotg->dev,
 				 "  Complete URB with transaction error\n");
 			free_qtd = 1;
-			if (qtd->urb) {
-				qtd->urb->status = -EPROTO;
-				dwc2_host_complete(hsotg, qtd->urb->priv,
-						   qtd->urb, -EPROTO);
-			}
+			dwc2_host_complete(hsotg, qtd, -EPROTO);
 		}
 		break;
 	case DWC2_HC_XFER_URB_DEQUEUE:
@@ -731,11 +728,7 @@
 	case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
 		dev_vdbg(hsotg->dev, "  Complete URB with I/O error\n");
 		free_qtd = 1;
-		if (qtd && qtd->urb) {
-			qtd->urb->status = -EIO;
-			dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
-					   -EIO);
-		}
+		dwc2_host_complete(hsotg, qtd, -EIO);
 		break;
 	case DWC2_HC_XFER_NO_HALT_STATUS:
 	default:
@@ -938,7 +931,7 @@
 	frame_desc->actual_length += len;
 
 	if (chan->align_buf && len) {
-		dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+		dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
 		dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma,
 					qtd->urb->length, DMA_FROM_DEVICE);
 		memcpy(qtd->urb->buf + frame_desc->offset +
@@ -957,7 +950,7 @@
 	}
 
 	if (qtd->isoc_frame_index == qtd->urb->packet_count) {
-		dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, 0);
+		dwc2_host_complete(hsotg, qtd, 0);
 		dwc2_release_channel(hsotg, chan, qtd,
 				     DWC2_HC_XFER_URB_COMPLETE);
 	} else {
@@ -1040,7 +1033,7 @@
 			dev_vdbg(hsotg->dev, "  Control transfer complete\n");
 			if (urb->status == -EINPROGRESS)
 				urb->status = 0;
-			dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+			dwc2_host_complete(hsotg, qtd, urb->status);
 			halt_status = DWC2_HC_XFER_URB_COMPLETE;
 			break;
 		}
@@ -1053,7 +1046,7 @@
 		urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
 						      qtd);
 		if (urb_xfer_done) {
-			dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+			dwc2_host_complete(hsotg, qtd, urb->status);
 			halt_status = DWC2_HC_XFER_URB_COMPLETE;
 		} else {
 			halt_status = DWC2_HC_XFER_COMPLETE;
@@ -1073,11 +1066,10 @@
 		 * interrupt
 		 */
 		if (urb_xfer_done) {
-				dwc2_host_complete(hsotg, urb->priv, urb,
-						   urb->status);
-				halt_status = DWC2_HC_XFER_URB_COMPLETE;
+			dwc2_host_complete(hsotg, qtd, urb->status);
+			halt_status = DWC2_HC_XFER_URB_COMPLETE;
 		} else {
-				halt_status = DWC2_HC_XFER_COMPLETE;
+			halt_status = DWC2_HC_XFER_COMPLETE;
 		}
 
 		dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
@@ -1123,11 +1115,11 @@
 		goto handle_stall_halt;
 
 	if (pipe_type == USB_ENDPOINT_XFER_CONTROL)
-		dwc2_host_complete(hsotg, urb->priv, urb, -EPIPE);
+		dwc2_host_complete(hsotg, qtd, -EPIPE);
 
 	if (pipe_type == USB_ENDPOINT_XFER_BULK ||
 	    pipe_type == USB_ENDPOINT_XFER_INT) {
-		dwc2_host_complete(hsotg, urb->priv, urb, -EPIPE);
+		dwc2_host_complete(hsotg, qtd, -EPIPE);
 		/*
 		 * USB protocol requires resetting the data toggle for bulk
 		 * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
@@ -1168,7 +1160,7 @@
 
 	/* Non DWORD-aligned buffer case handling */
 	if (chan->align_buf && xfer_length && chan->ep_is_in) {
-		dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+		dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
 		dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
 					DMA_FROM_DEVICE);
 		memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
@@ -1185,8 +1177,7 @@
 	dev_vdbg(hsotg->dev, "  chan->start_pkt_count %d\n",
 		 chan->start_pkt_count);
 	dev_vdbg(hsotg->dev, "  hctsiz.pktcnt %d\n",
-		 hctsiz >> TSIZ_PKTCNT_SHIFT &
-		 TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT);
+		 (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT);
 	dev_vdbg(hsotg->dev, "  chan->max_packet %d\n", chan->max_packet);
 	dev_vdbg(hsotg->dev, "  bytes_transferred %d\n",
 		 xfer_length);
@@ -1372,10 +1363,10 @@
 		    hsotg->core_params->dma_enable > 0) {
 			qtd->complete_split = 0;
 			qtd->isoc_split_offset = 0;
+			qtd->isoc_frame_index++;
 			if (qtd->urb &&
-			    ++qtd->isoc_frame_index == qtd->urb->packet_count) {
-				dwc2_host_complete(hsotg, qtd->urb->priv,
-						   qtd->urb, 0);
+			    qtd->isoc_frame_index == qtd->urb->packet_count) {
+				dwc2_host_complete(hsotg, qtd, 0);
 				dwc2_release_channel(hsotg, chan, qtd,
 						     DWC2_HC_XFER_URB_COMPLETE);
 			} else {
@@ -1445,16 +1436,16 @@
 	dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n",
 		chnum);
 
+	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
 	if (hsotg->core_params->dma_desc_enable > 0) {
 		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
 					    DWC2_HC_XFER_BABBLE_ERR);
-		goto handle_babble_done;
+		goto disable_int;
 	}
 
 	if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
-		if (qtd->urb)
-			dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
-					   -EOVERFLOW);
+		dwc2_host_complete(hsotg, qtd, -EOVERFLOW);
 		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR);
 	} else {
 		enum dwc2_halt_status halt_status;
@@ -1464,8 +1455,7 @@
 		dwc2_halt_channel(hsotg, chan, qtd, halt_status);
 	}
 
-handle_babble_done:
-	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+disable_int:
 	disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR);
 }
 
@@ -1490,6 +1480,8 @@
 	if (!urb)
 		goto handle_ahberr_halt;
 
+	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
 	hcchar = readl(hsotg->regs + HCCHAR(chnum));
 	hcsplt = readl(hsotg->regs + HCSPLT(chnum));
 	hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
@@ -1557,7 +1549,7 @@
 		goto handle_ahberr_done;
 	}
 
-	dwc2_host_complete(hsotg, urb->priv, urb, -EIO);
+	dwc2_host_complete(hsotg, qtd, -EIO);
 
 handle_ahberr_halt:
 	/*
@@ -1567,7 +1559,6 @@
 	dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR);
 
 handle_ahberr_done:
-	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
 	disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR);
 }
 
@@ -1582,6 +1573,8 @@
 	dev_dbg(hsotg->dev,
 		"--Host Channel %d Interrupt: Transaction Error--\n", chnum);
 
+	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
 	if (hsotg->core_params->dma_desc_enable > 0) {
 		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
 					    DWC2_HC_XFER_XACT_ERR);
@@ -1625,7 +1618,6 @@
 	}
 
 handle_xacterr_done:
-	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
 	disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR);
 }
 
@@ -1643,6 +1635,8 @@
 		dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n",
 			chnum);
 
+	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+
 	switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
 	case USB_ENDPOINT_XFER_CONTROL:
 	case USB_ENDPOINT_XFER_BULK:
@@ -1657,7 +1651,6 @@
 		break;
 	}
 
-	dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
 	disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN);
 }
 
@@ -1766,7 +1759,7 @@
 	 * For core with OUT NAK enhancement, the flow for high-speed
 	 * CONTROL/BULK OUT is handled a little differently
 	 */
-	if (hsotg->snpsid >= DWC2_CORE_REV_2_71a) {
+	if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_71a) {
 		if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in &&
 		    (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
 		     chan->ep_type == USB_ENDPOINT_XFER_BULK)) {
diff --git a/drivers/staging/dwc2/hcd_queue.c b/drivers/staging/dwc2/hcd_queue.c
index b36f783..b1980ef 100644
--- a/drivers/staging/dwc2/hcd_queue.c
+++ b/drivers/staging/dwc2/hcd_queue.c
@@ -116,7 +116,7 @@
 			qh->interval = 8;
 #endif
 		hprt = readl(hsotg->regs + HPRT0);
-		prtspd = hprt & HPRT0_SPD_MASK;
+		prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
 		if (prtspd == HPRT0_SPD_HIGH_SPEED &&
 		    (dev_speed == USB_SPEED_LOW ||
 		     dev_speed == USB_SPEED_FULL)) {
@@ -197,6 +197,9 @@
 {
 	struct dwc2_qh *qh;
 
+	if (!urb->priv)
+		return NULL;
+
 	/* Allocate memory */
 	qh = kzalloc(sizeof(*qh), mem_flags);
 	if (!qh)
@@ -638,7 +641,7 @@
 	struct dwc2_hcd_urb *urb = qtd->urb;
 	unsigned long flags;
 	int allocated = 0;
-	int retval = 0;
+	int retval;
 
 	/*
 	 * Get the QH which holds the QTD-list to insert to. Create QH if it
@@ -652,8 +655,19 @@
 	}
 
 	spin_lock_irqsave(&hsotg->lock, flags);
+
 	retval = dwc2_hcd_qh_add(hsotg, *qh);
-	if (retval && allocated) {
+	if (retval)
+		goto fail;
+
+	qtd->qh = *qh;
+	list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
+	spin_unlock_irqrestore(&hsotg->lock, flags);
+
+	return 0;
+
+fail:
+	if (allocated) {
 		struct dwc2_qtd *qtd2, *qtd2_tmp;
 		struct dwc2_qh *qh_tmp = *qh;
 
@@ -668,8 +682,6 @@
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 		dwc2_hcd_qh_free(hsotg, qh_tmp);
 	} else {
-		qtd->qh = *qh;
-		list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
 		spin_unlock_irqrestore(&hsotg->lock, flags);
 	}
 
diff --git a/drivers/staging/dwc2/hw.h b/drivers/staging/dwc2/hw.h
index 382a1d7..9c92a3c 100644
--- a/drivers/staging/dwc2/hw.h
+++ b/drivers/staging/dwc2/hw.h
@@ -72,12 +72,16 @@
 #define GAHBCFG_DMA_EN			(1 << 5)
 #define GAHBCFG_HBSTLEN_MASK		(0xf << 1)
 #define GAHBCFG_HBSTLEN_SHIFT		1
-#define GAHBCFG_HBSTLEN_SINGLE			(0 << 1)
-#define GAHBCFG_HBSTLEN_INCR			(1 << 1)
-#define GAHBCFG_HBSTLEN_INCR4			(3 << 1)
-#define GAHBCFG_HBSTLEN_INCR8			(5 << 1)
-#define GAHBCFG_HBSTLEN_INCR16			(7 << 1)
+#define GAHBCFG_HBSTLEN_SINGLE		0
+#define GAHBCFG_HBSTLEN_INCR		1
+#define GAHBCFG_HBSTLEN_INCR4		3
+#define GAHBCFG_HBSTLEN_INCR8		5
+#define GAHBCFG_HBSTLEN_INCR16		7
 #define GAHBCFG_GLBL_INTR_EN		(1 << 0)
+#define GAHBCFG_CTRL_MASK		(GAHBCFG_P_TXF_EMP_LVL | \
+					 GAHBCFG_NP_TXF_EMP_LVL | \
+					 GAHBCFG_DMA_EN | \
+					 GAHBCFG_GLBL_INTR_EN)
 
 #define GUSBCFG				HSOTG_REG(0x00C)
 #define GUSBCFG_FORCEDEVMODE		(1 << 30)
@@ -165,15 +169,15 @@
 #define GRXSTS_FN_SHIFT			25
 #define GRXSTS_PKTSTS_MASK		(0xf << 17)
 #define GRXSTS_PKTSTS_SHIFT		17
-#define GRXSTS_PKTSTS_GLOBALOUTNAK		(1 << 17)
-#define GRXSTS_PKTSTS_OUTRX			(2 << 17)
-#define GRXSTS_PKTSTS_HCHIN			(2 << 17)
-#define GRXSTS_PKTSTS_OUTDONE			(3 << 17)
-#define GRXSTS_PKTSTS_HCHIN_XFER_COMP		(3 << 17)
-#define GRXSTS_PKTSTS_SETUPDONE			(4 << 17)
-#define GRXSTS_PKTSTS_DATATOGGLEERR		(5 << 17)
-#define GRXSTS_PKTSTS_SETUPRX			(6 << 17)
-#define GRXSTS_PKTSTS_HCHHALTED			(7 << 17)
+#define GRXSTS_PKTSTS_GLOBALOUTNAK	1
+#define GRXSTS_PKTSTS_OUTRX		2
+#define GRXSTS_PKTSTS_HCHIN		2
+#define GRXSTS_PKTSTS_OUTDONE		3
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP	3
+#define GRXSTS_PKTSTS_SETUPDONE		4
+#define GRXSTS_PKTSTS_DATATOGGLEERR	5
+#define GRXSTS_PKTSTS_SETUPRX		6
+#define GRXSTS_PKTSTS_HCHHALTED		7
 #define GRXSTS_HCHNUM_MASK		(0xf << 0)
 #define GRXSTS_HCHNUM_SHIFT		0
 #define GRXSTS_DPID_MASK		(0x3 << 15)
@@ -184,16 +188,11 @@
 #define GRXSTS_EPNUM_SHIFT		0
 
 #define GRXFSIZ				HSOTG_REG(0x024)
+#define GRXFSIZ_DEPTH_MASK		(0xffff << 0)
+#define GRXFSIZ_DEPTH_SHIFT		0
 
 #define GNPTXFSIZ			HSOTG_REG(0x028)
-#define GNPTXFSIZ_NP_TXF_DEP_MASK	(0xffff << 16)
-#define GNPTXFSIZ_NP_TXF_DEP_SHIFT	16
-#define GNPTXFSIZ_NP_TXF_DEP_LIMIT	0xffff
-#define GNPTXFSIZ_NP_TXF_DEP(_x)	((_x) << 16)
-#define GNPTXFSIZ_NP_TXF_ST_ADDR_MASK	(0xffff << 0)
-#define GNPTXFSIZ_NP_TXF_ST_ADDR_SHIFT	0
-#define GNPTXFSIZ_NP_TXF_ST_ADDR_LIMIT	0xffff
-#define GNPTXFSIZ_NP_TXF_ST_ADDR(_x)	((_x) << 0)
+/* Use FIFOSIZE_* constants to access this register */
 
 #define GNPTXSTS			HSOTG_REG(0x02C)
 #define GNPTXSTS_NP_TXQ_TOP_MASK		(0x7f << 24)
@@ -244,32 +243,32 @@
 #define GHWCFG2_NUM_DEV_EP_SHIFT		10
 #define GHWCFG2_FS_PHY_TYPE_MASK		(0x3 << 8)
 #define GHWCFG2_FS_PHY_TYPE_SHIFT		8
-#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED		(0 << 8)
-#define GHWCFG2_FS_PHY_TYPE_DEDICATED			(1 << 8)
-#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI			(2 << 8)
-#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI			(3 << 8)
+#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED	0
+#define GHWCFG2_FS_PHY_TYPE_DEDICATED		1
+#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI		2
+#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI		3
 #define GHWCFG2_HS_PHY_TYPE_MASK		(0x3 << 6)
 #define GHWCFG2_HS_PHY_TYPE_SHIFT		6
-#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED		(0 << 6)
-#define GHWCFG2_HS_PHY_TYPE_UTMI			(1 << 6)
-#define GHWCFG2_HS_PHY_TYPE_ULPI			(2 << 6)
-#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI			(3 << 6)
+#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED	0
+#define GHWCFG2_HS_PHY_TYPE_UTMI		1
+#define GHWCFG2_HS_PHY_TYPE_ULPI		2
+#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI		3
 #define GHWCFG2_POINT2POINT			(1 << 5)
 #define GHWCFG2_ARCHITECTURE_MASK		(0x3 << 3)
 #define GHWCFG2_ARCHITECTURE_SHIFT		3
-#define GHWCFG2_SLAVE_ONLY_ARCH				(0 << 3)
-#define GHWCFG2_EXT_DMA_ARCH				(1 << 3)
-#define GHWCFG2_INT_DMA_ARCH				(2 << 3)
+#define GHWCFG2_SLAVE_ONLY_ARCH			0
+#define GHWCFG2_EXT_DMA_ARCH			1
+#define GHWCFG2_INT_DMA_ARCH			2
 #define GHWCFG2_OP_MODE_MASK			(0x7 << 0)
 #define GHWCFG2_OP_MODE_SHIFT			0
-#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE			(0 << 0)
-#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE		(1 << 0)
-#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE		(2 << 0)
-#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE		(3 << 0)
-#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE		(4 << 0)
-#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST		(5 << 0)
-#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST		(6 << 0)
-#define GHWCFG2_OP_MODE_UNDEFINED			(7 << 0)
+#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE		0
+#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE	1
+#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE	2
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE	3
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE	4
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST	5
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST	6
+#define GHWCFG2_OP_MODE_UNDEFINED		7
 
 #define GHWCFG3				HSOTG_REG(0x004c)
 #define GHWCFG3_DFIFO_DEPTH_MASK		(0xffff << 16)
@@ -303,6 +302,9 @@
 #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT	16
 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK	(0x3 << 14)
 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT	14
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8		0
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16		1
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16	2
 #define GHWCFG4_XHIBER				(1 << 7)
 #define GHWCFG4_HIBER				(1 << 6)
 #define GHWCFG4_MIN_AHB_FREQ			(1 << 5)
@@ -391,16 +393,12 @@
 #define ADPCTL_PRB_DSCHRG_SHIFT		0
 
 #define HPTXFSIZ			HSOTG_REG(0x100)
+/* Use FIFOSIZE_* constants to access this register */
 
 #define DPTXFSIZN(_a)			HSOTG_REG(0x104 + (((_a) - 1) * 4))
-#define DPTXFSIZN_DP_TXF_SIZE_MASK	(0xffff << 16)
-#define DPTXFSIZN_DP_TXF_SIZE_SHIFT	16
-#define DPTXFSIZN_DP_TXF_SIZE_GET(_v)	(((_v) >> 16) & 0xffff)
-#define DPTXFSIZN_DP_TXF_SIZE_LIMIT	0xffff
-#define DPTXFSIZN_DP_TXF_SIZE(_x)	((_x) << 16)
-#define DPTXFSIZN_DP_TXF_ST_ADDR_MASK	(0xffff << 0)
-#define DPTXFSIZN_DP_TXF_ST_ADDR_SHIFT	0
+/* Use FIFOSIZE_* constants to access this register */
 
+/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */
 #define FIFOSIZE_DEPTH_MASK		(0xffff << 16)
 #define FIFOSIZE_DEPTH_SHIFT		16
 #define FIFOSIZE_STARTADDR_MASK		(0xffff << 0)
@@ -424,10 +422,10 @@
 #define DCFG_NZ_STS_OUT_HSHK		(1 << 2)
 #define DCFG_DEVSPD_MASK		(0x3 << 0)
 #define DCFG_DEVSPD_SHIFT		0
-#define DCFG_DEVSPD_HS				(0 << 0)
-#define DCFG_DEVSPD_FS				(1 << 0)
-#define DCFG_DEVSPD_LS				(2 << 0)
-#define DCFG_DEVSPD_FS48			(3 << 0)
+#define DCFG_DEVSPD_HS			0
+#define DCFG_DEVSPD_FS			1
+#define DCFG_DEVSPD_LS			2
+#define DCFG_DEVSPD_FS48		3
 
 #define DCTL				HSOTG_REG(0x804)
 #define DCTL_PWRONPRGDONE		(1 << 11)
@@ -450,10 +448,10 @@
 #define DSTS_ERRATICERR			(1 << 3)
 #define DSTS_ENUMSPD_MASK		(0x3 << 1)
 #define DSTS_ENUMSPD_SHIFT		1
-#define DSTS_ENUMSPD_HS				(0 << 1)
-#define DSTS_ENUMSPD_FS				(1 << 1)
-#define DSTS_ENUMSPD_LS				(2 << 1)
-#define DSTS_ENUMSPD_FS48			(3 << 1)
+#define DSTS_ENUMSPD_HS			0
+#define DSTS_ENUMSPD_FS			1
+#define DSTS_ENUMSPD_LS			2
+#define DSTS_ENUMSPD_FS48		3
 #define DSTS_SUSPSTS			(1 << 0)
 
 #define DIEPMSK				HSOTG_REG(0x810)
@@ -501,10 +499,10 @@
  */
 #define D0EPCTL_MPS_MASK		(0x3 << 0)
 #define D0EPCTL_MPS_SHIFT		0
-#define D0EPCTL_MPS_64				(0 << 0)
-#define D0EPCTL_MPS_32				(1 << 0)
-#define D0EPCTL_MPS_16				(2 << 0)
-#define D0EPCTL_MPS_8				(3 << 0)
+#define D0EPCTL_MPS_64			0
+#define D0EPCTL_MPS_32			1
+#define D0EPCTL_MPS_16			2
+#define D0EPCTL_MPS_8			3
 
 #define DXEPCTL_EPENA			(1 << 31)
 #define DXEPCTL_EPDIS			(1 << 30)
@@ -522,10 +520,10 @@
 #define DXEPCTL_SNP			(1 << 20)
 #define DXEPCTL_EPTYPE_MASK		(0x3 << 18)
 #define DXEPCTL_EPTYPE_SHIFT		18
-#define DXEPCTL_EPTYPE_CONTROL			(0 << 18)
-#define DXEPCTL_EPTYPE_ISO			(1 << 18)
-#define DXEPCTL_EPTYPE_BULK			(2 << 18)
-#define DXEPCTL_EPTYPE_INTTERUPT		(3 << 18)
+#define DXEPCTL_EPTYPE_CONTROL		0
+#define DXEPCTL_EPTYPE_ISO		1
+#define DXEPCTL_EPTYPE_BULK		2
+#define DXEPCTL_EPTYPE_INTTERUPT	3
 #define DXEPCTL_NAKSTS			(1 << 17)
 #define DXEPCTL_DPID			(1 << 16)
 #define DXEPCTL_EOFRNUM			(1 << 16)
@@ -645,9 +643,9 @@
 #define HCFG_FSLSSUPP			(1 << 2)
 #define HCFG_FSLSPCLKSEL_MASK		(0x3 << 0)
 #define HCFG_FSLSPCLKSEL_SHIFT		0
-#define HCFG_FSLSPCLKSEL_30_60_MHZ		(0 << 0)
-#define HCFG_FSLSPCLKSEL_48_MHZ			(1 << 0)
-#define HCFG_FSLSPCLKSEL_6_MHZ			(2 << 0)
+#define HCFG_FSLSPCLKSEL_30_60_MHZ	0
+#define HCFG_FSLSPCLKSEL_48_MHZ		1
+#define HCFG_FSLSPCLKSEL_6_MHZ		2
 
 #define HFIR				HSOTG_REG(0x0404)
 #define HFIR_FRINT_MASK			(0xffff << 0)
@@ -680,9 +678,9 @@
 #define HPRT0				HSOTG_REG(0x0440)
 #define HPRT0_SPD_MASK			(0x3 << 17)
 #define HPRT0_SPD_SHIFT			17
-#define HPRT0_SPD_HIGH_SPEED		(0 << 17)
-#define HPRT0_SPD_FULL_SPEED		(1 << 17)
-#define HPRT0_SPD_LOW_SPEED		(2 << 17)
+#define HPRT0_SPD_HIGH_SPEED		0
+#define HPRT0_SPD_FULL_SPEED		1
+#define HPRT0_SPD_LOW_SPEED		2
 #define HPRT0_TSTCTL_MASK		(0xf << 13)
 #define HPRT0_TSTCTL_SHIFT		13
 #define HPRT0_PWR			(1 << 12)
@@ -720,10 +718,10 @@
 #define HCSPLT_COMPSPLT			(1 << 16)
 #define HCSPLT_XACTPOS_MASK		(0x3 << 14)
 #define HCSPLT_XACTPOS_SHIFT		14
-#define HCSPLT_XACTPOS_MID		(0 << 14)
-#define HCSPLT_XACTPOS_END		(1 << 14)
-#define HCSPLT_XACTPOS_BEGIN		(2 << 14)
-#define HCSPLT_XACTPOS_ALL		(3 << 14)
+#define HCSPLT_XACTPOS_MID		0
+#define HCSPLT_XACTPOS_END		1
+#define HCSPLT_XACTPOS_BEGIN		2
+#define HCSPLT_XACTPOS_ALL		3
 #define HCSPLT_HUBADDR_MASK		(0x7f << 7)
 #define HCSPLT_HUBADDR_SHIFT		7
 #define HCSPLT_PRTADDR_MASK		(0x7f << 0)
@@ -751,11 +749,11 @@
 #define TSIZ_DOPNG			(1 << 31)
 #define TSIZ_SC_MC_PID_MASK		(0x3 << 29)
 #define TSIZ_SC_MC_PID_SHIFT		29
-#define TSIZ_SC_MC_PID_DATA0		(0 << 29)
-#define TSIZ_SC_MC_PID_DATA2		(1 << 29)
-#define TSIZ_SC_MC_PID_DATA1		(2 << 29)
-#define TSIZ_SC_MC_PID_MDATA		(3 << 29)
-#define TSIZ_SC_MC_PID_SETUP		(3 << 29)
+#define TSIZ_SC_MC_PID_DATA0		0
+#define TSIZ_SC_MC_PID_DATA2		1
+#define TSIZ_SC_MC_PID_DATA1		2
+#define TSIZ_SC_MC_PID_MDATA		3
+#define TSIZ_SC_MC_PID_SETUP		3
 #define TSIZ_PKTCNT_MASK		(0x3ff << 19)
 #define TSIZ_PKTCNT_SHIFT		19
 #define TSIZ_NTD_MASK			(0xff << 8)
diff --git a/drivers/staging/dwc2/pci.c b/drivers/staging/dwc2/pci.c
index 3ca54d6..9020260 100644
--- a/drivers/staging/dwc2/pci.c
+++ b/drivers/staging/dwc2/pci.c
@@ -74,7 +74,7 @@
 	.max_packet_count		= 511,
 	.host_channels			= -1,
 	.phy_type			= -1,
-	.phy_utmi_width			= 16,	/* 16 bits - NOT DETECTABLE */
+	.phy_utmi_width			= -1,
 	.phy_ulpi_ddr			= -1,
 	.phy_ulpi_ext_vbus		= -1,
 	.i2c_enable			= -1,
@@ -83,7 +83,7 @@
 	.host_ls_low_power_phy_clk	= -1,
 	.ts_dline			= -1,
 	.reload_ctl			= -1,
-	.ahb_single			= -1,
+	.ahbcfg				= -1,
 };
 
 /**
diff --git a/drivers/staging/et131x/README b/drivers/staging/et131x/README
index 05ad085..9272a24 100644
--- a/drivers/staging/et131x/README
+++ b/drivers/staging/et131x/README
@@ -8,7 +8,6 @@
 driver as they did not build properly at the time.
 
 TODO:
-	- some rx packets have CRC/code/frame errors
 	- Look at reducing the number of spinlocks
 	- Simplify code in nic_rx_pkts(), when determining multicast_pkts_rcvd
 	- Implement NAPI support
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 6cbf9c7..074b0e5 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -177,24 +177,24 @@
 }
 
 #define show_int(value)	\
-	static ssize_t show_##value(struct device *dev,	\
+	static ssize_t value##_show(struct device *dev,	\
 			      struct device_attribute *attr, char *buf)	\
 	{	\
 		struct usb_interface *intf = to_usb_interface(dev);	\
 		struct usb_tranzport *t = usb_get_intfdata(intf);	\
 		return sprintf(buf, "%d\n", t->value);	\
 	}	\
-	static DEVICE_ATTR(value, S_IRUGO, show_##value, NULL);
+	static DEVICE_ATTR_RO(value)
 
 #define show_set_int(value)	\
-	static ssize_t show_##value(struct device *dev,	\
+	static ssize_t value##_show(struct device *dev,	\
 			      struct device_attribute *attr, char *buf)	\
 	{	\
 		struct usb_interface *intf = to_usb_interface(dev);	\
 		struct usb_tranzport *t = usb_get_intfdata(intf);	\
 		return sprintf(buf, "%d\n", t->value);	\
 	}	\
-	static ssize_t set_##value(struct device *dev,	\
+	static ssize_t value##_store(struct device *dev,	\
 			     struct device_attribute *attr,		\
 			     const char *buf, size_t count)		\
 	{	\
@@ -206,7 +206,7 @@
 		t->value = temp;	\
 		return count;	\
 	}	\
-	static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value);
+	static DEVICE_ATTR_RW(value)
 
 show_int(enable);
 show_int(offline);
diff --git a/drivers/staging/gdm724x/Kconfig b/drivers/staging/gdm724x/Kconfig
new file mode 100644
index 0000000..0a1f090
--- /dev/null
+++ b/drivers/staging/gdm724x/Kconfig
@@ -0,0 +1,15 @@
+#
+# GCT GDM724x LTE driver configuration
+#
+
+config LTE_GDM724X
+	tristate "GCT GDM724x LTE support"
+	depends on NET && USB && TTY && m
+	help
+	  This driver supports GCT GDM724x LTE chip based USB modem devices.
+	  It exposes 4 network devices to be used per PDN and 2 tty devices to be
+	  used for AT commands and DM monitoring applications.
+	  The modules will be called gdmulte.ko and gdmtty.ko
+
+	  GCT-ATCx can be used for AT Commands
+	  GCT-DMx can be used for LTE protocol monitoring
diff --git a/drivers/staging/gdm724x/Makefile b/drivers/staging/gdm724x/Makefile
new file mode 100644
index 0000000..ba7f11a
--- /dev/null
+++ b/drivers/staging/gdm724x/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_LTE_GDM724X) := gdmulte.o
+gdmulte-y += gdm_lte.o netlink_k.o
+gdmulte-y += gdm_usb.o gdm_endian.o
+
+obj-$(CONFIG_LTE_GDM724X) += gdmtty.o
+gdmtty-y := gdm_tty.o gdm_mux.o
+
diff --git a/drivers/staging/gdm724x/TODO b/drivers/staging/gdm724x/TODO
new file mode 100644
index 0000000..b2b571e
--- /dev/null
+++ b/drivers/staging/gdm724x/TODO
@@ -0,0 +1,16 @@
+TODO:
+- Clean up coding style to meet kernel standard. (80 line limit, netdev_err)
+- Remove test for host endian
+- Remove confusing macros (endian, hci_send, sdu_send, rcv_with_cb)
+- Fixes for every instances of function returning -1
+- Check for skb->len in gdm_lte_emulate_arp()
+- Use ALIGN() macro for dummy_cnt in up_to_host()
+- Error handling in init_usb()
+- Explain reason for multiples of 512 bytes in alloc_tx_struct()
+- Review use of atomic allocation for tx structs
+- No error checking for alloc_tx_struct in do_tx()
+- fix up static tty port allocation to be dynamic
+
+Patches to:
+	Jonathan Kim <jonathankim@gctsemi.com>
+	Dean ahn <deanahn@gctsemi.com>
diff --git a/drivers/staging/gdm724x/gdm_endian.c b/drivers/staging/gdm724x/gdm_endian.c
new file mode 100644
index 0000000..f6cc90a
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_endian.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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/slab.h>
+#include "gdm_endian.h"
+
+void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian)
+{
+	u8 a[2] = {0x12, 0x34};
+	u8 b[2] = {0, };
+	u16 c = 0x1234;
+
+	if (dev_endian == ENDIANNESS_BIG)
+		ed->dev_ed = ENDIANNESS_BIG;
+	else
+		ed->dev_ed = ENDIANNESS_LITTLE;
+
+	memcpy(b, &c, 2);
+
+	if (a[0] != b[0])
+		ed->host_ed = ENDIANNESS_LITTLE;
+	else
+		ed->host_ed = ENDIANNESS_BIG;
+
+}
+
+u16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x)
+{
+	if (ed->dev_ed == ed->host_ed)
+		return x;
+
+	return Endian16_Swap(x);
+}
+
+u16 gdm_dev16_to_cpu(struct gdm_endian *ed, u16 x)
+{
+	if (ed->dev_ed == ed->host_ed)
+		return x;
+
+	return Endian16_Swap(x);
+}
+
+u32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x)
+{
+	if (ed->dev_ed == ed->host_ed)
+		return x;
+
+	return Endian32_Swap(x);
+}
+
+u32 gdm_dev32_to_cpu(struct gdm_endian *ed, u32 x)
+{
+	if (ed->dev_ed == ed->host_ed)
+		return x;
+
+	return Endian32_Swap(x);
+}
diff --git a/drivers/staging/gdm724x/gdm_endian.h b/drivers/staging/gdm724x/gdm_endian.h
new file mode 100644
index 0000000..9b2531f
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_endian.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 __GDM_ENDIAN_H__
+#define __GDM_ENDIAN_H__
+
+#include <linux/types.h>
+
+#define Endian16_Swap(value) \
+	((((u16)((value) & 0x00FF)) << 8) | \
+	 (((u16)((value) & 0xFF00)) >> 8))
+
+#define Endian32_Swap(value) \
+	((((u32)((value) & 0x000000FF)) << 24) | \
+	 (((u32)((value) & 0x0000FF00)) << 8) | \
+	 (((u32)((value) & 0x00FF0000)) >> 8) | \
+	 (((u32)((value) & 0xFF000000)) >> 24))
+
+enum {
+	ENDIANNESS_MIN = 0,
+	ENDIANNESS_UNKNOWN,
+	ENDIANNESS_LITTLE,
+	ENDIANNESS_BIG,
+	ENDIANNESS_MIDDLE,
+	ENDIANNESS_MAX
+};
+
+struct gdm_endian {
+	u8 dev_ed;
+	u8 host_ed;
+};
+
+void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian);
+u16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x);
+u16 gdm_dev16_to_cpu(struct gdm_endian *ed, u16 x);
+u32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x);
+u32 gdm_dev32_to_cpu(struct gdm_endian *ed, u32 x);
+
+#endif /*__GDM_ENDIAN_H__*/
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
new file mode 100644
index 0000000..bc0d510
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -0,0 +1,877 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/in6.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+#include <linux/icmpv6.h>
+#include <linux/uaccess.h>
+#include <net/ndisc.h>
+
+#include "gdm_lte.h"
+#include "netlink_k.h"
+#include "hci.h"
+#include "hci_packet.h"
+#include "gdm_endian.h"
+
+/*
+ * Netlink protocol number
+ */
+#define NETLINK_LTE 30
+
+/*
+ * Default MTU Size
+ */
+#define DEFAULT_MTU_SIZE 1500
+
+#define gdm_dev_endian(n) (\
+	n->phy_dev->get_endian(n->phy_dev->priv_dev))
+
+#define gdm_lte_hci_send(n, d, l) (\
+	n->phy_dev->send_hci_func(n->phy_dev->priv_dev, d, l, NULL, NULL))
+
+#define gdm_lte_sdu_send(n, d, l, c, b, i, t) (\
+	n->phy_dev->send_sdu_func(n->phy_dev->priv_dev, d, l, n->pdn_table.dft_eps_id, 0, c, b, i, t))
+
+#define gdm_lte_rcv_with_cb(n, c, b, e) (\
+	n->rcv_func(n->priv_dev, c, b, e))
+
+#define IP_VERSION_4	4
+#define IP_VERSION_6	6
+
+static struct {
+	int ref_cnt;
+	struct sock *sock;
+} lte_event;
+
+static struct device_type wwan_type = {
+	.name   = "wwan",
+};
+
+static int gdm_lte_open(struct net_device *dev)
+{
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int gdm_lte_close(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int gdm_lte_set_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+	return 0;
+}
+
+static void tx_complete(void *arg)
+{
+	struct nic *nic = arg;
+
+	if (netif_queue_stopped(nic->netdev))
+		netif_wake_queue(nic->netdev);
+}
+
+static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type)
+{
+	int ret;
+
+	ret = netif_rx_ni(skb);
+	if (ret == NET_RX_DROP) {
+		nic->stats.rx_dropped++;
+	} else {
+		nic->stats.rx_packets++;
+		nic->stats.rx_bytes += skb->len + ETH_HLEN;
+	}
+
+	return 0;
+}
+
+int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type)
+{
+	struct nic *nic = netdev_priv(skb_in->dev);
+	struct sk_buff *skb_out;
+	struct ethhdr eth;
+	struct vlan_ethhdr vlan_eth;
+	struct arphdr *arp_in;
+	struct arphdr *arp_out;
+	struct arpdata {
+		u8 ar_sha[ETH_ALEN];
+		u8 ar_sip[4];
+		u8 ar_tha[ETH_ALEN];
+		u8 ar_tip[4];
+	};
+	struct arpdata *arp_data_in;
+	struct arpdata *arp_data_out;
+	u8 arp_temp[60];
+	void *mac_header_data;
+	u32 mac_header_len;
+
+	/* Format the mac header so that it can be put to skb */
+	if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) {
+		memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr));
+		mac_header_data = &vlan_eth;
+		mac_header_len = VLAN_ETH_HLEN;
+	} else {
+		memcpy(&eth, skb_in->data, sizeof(struct ethhdr));
+		mac_header_data = &eth;
+		mac_header_len = ETH_HLEN;
+	}
+
+	/* Get the pointer of the original request */
+	arp_in = (struct arphdr *)(skb_in->data + mac_header_len);
+	arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len + sizeof(struct arphdr));
+
+	/* Get the pointer of the outgoing response */
+	arp_out = (struct arphdr *)arp_temp;
+	arp_data_out = (struct arpdata *)(arp_temp + sizeof(struct arphdr));
+
+	/* Copy the arp header */
+	memcpy(arp_out, arp_in, sizeof(struct arphdr));
+	arp_out->ar_op = htons(ARPOP_REPLY);
+
+	/* Copy the arp payload: based on 2 bytes of mac and fill the IP */
+	arp_data_out->ar_sha[0] = arp_data_in->ar_sha[0];
+	arp_data_out->ar_sha[1] = arp_data_in->ar_sha[1];
+	memcpy(&arp_data_out->ar_sha[2], &arp_data_in->ar_tip[0], 4);
+	memcpy(&arp_data_out->ar_sip[0], &arp_data_in->ar_tip[0], 4);
+	memcpy(&arp_data_out->ar_tha[0], &arp_data_in->ar_sha[0], 6);
+	memcpy(&arp_data_out->ar_tip[0], &arp_data_in->ar_sip[0], 4);
+
+	/* Fill the destination mac with source mac of the received packet */
+	memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN);
+	/* Fill the source mac with nic's source mac */
+	memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
+
+	/* Alloc skb and reserve align */
+	skb_out = dev_alloc_skb(skb_in->len);
+	if (!skb_out)
+		return -ENOMEM;
+	skb_reserve(skb_out, NET_IP_ALIGN);
+
+	memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len);
+	memcpy(skb_put(skb_out, sizeof(struct arphdr)), arp_out, sizeof(struct arphdr));
+	memcpy(skb_put(skb_out, sizeof(struct arpdata)), arp_data_out, sizeof(struct arpdata));
+
+	skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
+	skb_out->dev = skb_in->dev;
+	skb_reset_mac_header(skb_out);
+	skb_pull(skb_out, ETH_HLEN);
+
+	gdm_lte_rx(skb_out, nic, nic_type);
+
+	return 0;
+}
+
+int icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len)
+{
+	unsigned short *w = ptr;
+	int sum = 0;
+	int i;
+
+	union {
+		struct {
+			u8 ph_src[16];
+			u8 ph_dst[16];
+			u32 ph_len;
+			u8 ph_zero[3];
+			u8 ph_nxt;
+		} ph __packed;
+		u16 pa[20];
+	} pseudo_header;
+
+	memset(&pseudo_header, 0, sizeof(pseudo_header));
+	memcpy(&pseudo_header.ph.ph_src, &ipv6->saddr.in6_u.u6_addr8, 16);
+	memcpy(&pseudo_header.ph.ph_dst, &ipv6->daddr.in6_u.u6_addr8, 16);
+	pseudo_header.ph.ph_len = ipv6->payload_len;
+	pseudo_header.ph.ph_nxt = ipv6->nexthdr;
+
+	w = (u16 *)&pseudo_header;
+	for (i = 0; i < sizeof(pseudo_header.pa) / sizeof(pseudo_header.pa[0]); i++)
+		sum += pseudo_header.pa[i];
+
+	w = ptr;
+	while (len > 1) {
+		sum += *w++;
+		len -= 2;
+	}
+
+	sum = (sum >> 16) + (sum & 0xFFFF);
+	sum += (sum >> 16);
+	sum = ~sum & 0xffff;
+
+	return sum;
+}
+
+int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
+{
+	struct nic *nic = netdev_priv(skb_in->dev);
+	struct sk_buff *skb_out;
+	struct ethhdr eth;
+	struct vlan_ethhdr vlan_eth;
+	struct neighbour_advertisement {
+		u8 target_address[16];
+		u8 type;
+		u8 length;
+		u8 link_layer_address[6];
+	};
+	struct neighbour_advertisement na;
+	struct neighbour_solicitation {
+		u8 target_address[16];
+	};
+	struct neighbour_solicitation *ns;
+	struct ipv6hdr *ipv6_in;
+	struct ipv6hdr ipv6_out;
+	struct icmp6hdr *icmp6_in;
+	struct icmp6hdr icmp6_out;
+
+	void *mac_header_data;
+	u32 mac_header_len;
+
+	/* Format the mac header so that it can be put to skb */
+	if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) {
+		memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr));
+		if (ntohs(vlan_eth.h_vlan_encapsulated_proto) != ETH_P_IPV6)
+			return -1;
+		mac_header_data = &vlan_eth;
+		mac_header_len = VLAN_ETH_HLEN;
+	} else {
+		memcpy(&eth, skb_in->data, sizeof(struct ethhdr));
+		if (ntohs(eth.h_proto) != ETH_P_IPV6)
+			return -1;
+		mac_header_data = &eth;
+		mac_header_len = ETH_HLEN;
+	}
+
+	/* Check if this is IPv6 ICMP packet */
+	ipv6_in = (struct ipv6hdr *)(skb_in->data + mac_header_len);
+	if (ipv6_in->version != 6 || ipv6_in->nexthdr != IPPROTO_ICMPV6)
+		return -1;
+
+	/* Check if this is NDP packet */
+	icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr));
+	if (icmp6_in->icmp6_type == NDISC_ROUTER_SOLICITATION) { /* Check RS */
+		return -1;
+	} else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { /* Check NS */
+		u8 icmp_na[sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement)];
+		u8 zero_addr8[16] = {0,};
+
+		if (memcmp(ipv6_in->saddr.in6_u.u6_addr8, zero_addr8, 16) == 0)
+			/* Duplicate Address Detection: Source IP is all zero */
+			return 0;
+
+		icmp6_out.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+		icmp6_out.icmp6_code = 0;
+		icmp6_out.icmp6_cksum = 0;
+		icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); /* R=0, S=1, O=1 */
+
+		ns = (struct neighbour_solicitation *)(skb_in->data + mac_header_len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr));
+		memcpy(&na.target_address, ns->target_address, 16);
+		na.type = 0x02;
+		na.length = 1;
+		na.link_layer_address[0] = 0x00;
+		na.link_layer_address[1] = 0x0a;
+		na.link_layer_address[2] = 0x3b;
+		na.link_layer_address[3] = 0xaf;
+		na.link_layer_address[4] = 0x63;
+		na.link_layer_address[5] = 0xc7;
+
+		memcpy(&ipv6_out, ipv6_in, sizeof(struct ipv6hdr));
+		memcpy(ipv6_out.saddr.in6_u.u6_addr8, &na.target_address, 16);
+		memcpy(ipv6_out.daddr.in6_u.u6_addr8, ipv6_in->saddr.in6_u.u6_addr8, 16);
+		ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) + sizeof(struct neighbour_advertisement));
+
+		memcpy(icmp_na, &icmp6_out, sizeof(struct icmp6hdr));
+		memcpy(icmp_na + sizeof(struct icmp6hdr), &na, sizeof(struct neighbour_advertisement));
+
+		icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, (u16 *)icmp_na, sizeof(icmp_na));
+	} else {
+		return -1;
+	}
+
+	/* Fill the destination mac with source mac of the received packet */
+	memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN);
+	/* Fill the source mac with nic's source mac */
+	memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
+
+	/* Alloc skb and reserve align */
+	skb_out = dev_alloc_skb(skb_in->len);
+	if (!skb_out)
+		return -ENOMEM;
+	skb_reserve(skb_out, NET_IP_ALIGN);
+
+	memcpy(skb_put(skb_out, mac_header_len), mac_header_data, mac_header_len);
+	memcpy(skb_put(skb_out, sizeof(struct ipv6hdr)), &ipv6_out, sizeof(struct ipv6hdr));
+	memcpy(skb_put(skb_out, sizeof(struct icmp6hdr)), &icmp6_out, sizeof(struct icmp6hdr));
+	memcpy(skb_put(skb_out, sizeof(struct neighbour_advertisement)), &na, sizeof(struct neighbour_advertisement));
+
+	skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
+	skb_out->dev = skb_in->dev;
+	skb_reset_mac_header(skb_out);
+	skb_pull(skb_out, ETH_HLEN);
+
+	gdm_lte_rx(skb_out, nic, nic_type);
+
+	return 0;
+}
+
+static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct ethhdr *eth;
+	struct vlan_ethhdr *vlan_eth;
+	struct iphdr *ip;
+	struct ipv6hdr *ipv6;
+	int mac_proto;
+	void *network_data;
+	u32 nic_type = 0;
+
+	/* NIC TYPE is based on the nic_id of this net_device */
+	nic_type = 0x00000010 | nic->nic_id;
+
+	/* Get ethernet protocol */
+	eth = (struct ethhdr *)skb->data;
+	if (ntohs(eth->h_proto) == ETH_P_8021Q) {
+		vlan_eth = (struct vlan_ethhdr *)skb->data;
+		mac_proto = ntohs(vlan_eth->h_vlan_encapsulated_proto);
+		network_data = skb->data + VLAN_ETH_HLEN;
+		nic_type |= NIC_TYPE_F_VLAN;
+	} else {
+		mac_proto = ntohs(eth->h_proto);
+		network_data = skb->data + ETH_HLEN;
+	}
+
+	/* Process packet for nic type */
+	switch (mac_proto) {
+	case ETH_P_ARP:
+		nic_type |= NIC_TYPE_ARP;
+		break;
+	case ETH_P_IP:
+		nic_type |= NIC_TYPE_F_IPV4;
+		ip = (struct iphdr *)network_data;
+
+		/* Check DHCPv4 */
+		if (ip->protocol == IPPROTO_UDP) {
+			struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct iphdr));
+			if (ntohs(udp->dest) == 67 || ntohs(udp->dest) == 68)
+				nic_type |= NIC_TYPE_F_DHCP;
+		}
+		break;
+	case ETH_P_IPV6:
+		nic_type |= NIC_TYPE_F_IPV6;
+		ipv6 = (struct ipv6hdr *)network_data;
+
+		if (ipv6->nexthdr == IPPROTO_ICMPV6) /* Check NDP request */ {
+			struct icmp6hdr *icmp6 = (struct icmp6hdr *)(network_data + sizeof(struct ipv6hdr));
+			if (/*icmp6->icmp6_type == NDISC_ROUTER_SOLICITATION || */
+				icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
+				nic_type |= NIC_TYPE_ICMPV6;
+		} else if (ipv6->nexthdr == IPPROTO_UDP) /* Check DHCPv6 */ {
+			struct udphdr *udp = (struct udphdr *)(network_data + sizeof(struct ipv6hdr));
+			if (ntohs(udp->dest) == 546 || ntohs(udp->dest) == 547)
+				nic_type |= NIC_TYPE_F_DHCP;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return nic_type;
+}
+
+static int gdm_lte_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	u32 nic_type;
+	void *data_buf;
+	int data_len;
+	int idx;
+	int ret = 0;
+
+	nic_type = gdm_lte_tx_nic_type(dev, skb);
+	if (nic_type == 0) {
+		netdev_err(dev, "tx - invalid nic_type\n");
+		return -1;
+	}
+
+	if (nic_type & NIC_TYPE_ARP) {
+		if (gdm_lte_emulate_arp(skb, nic_type) == 0) {
+			dev_kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	if (nic_type & NIC_TYPE_ICMPV6) {
+		if (gdm_lte_emulate_ndp(skb, nic_type) == 0) {
+			dev_kfree_skb(skb);
+			return 0;
+		}
+	}
+
+	/*
+	Need byte shift (that is, remove VLAN tag) if there is one
+	For the case of ARP, this breaks the offset as vlan_ethhdr+4 is treated as ethhdr
+	However, it shouldn't be a problem as the response starts from arp_hdr and ethhdr
+	is created by this driver based on the NIC mac
+	*/
+	if (nic_type & NIC_TYPE_F_VLAN) {
+		struct vlan_ethhdr *vlan_eth = (struct vlan_ethhdr *)skb->data;
+		nic->vlan_id = ntohs(vlan_eth->h_vlan_TCI) & VLAN_VID_MASK;
+		data_buf = skb->data + (VLAN_ETH_HLEN - ETH_HLEN);
+		data_len = skb->len - (VLAN_ETH_HLEN - ETH_HLEN);
+	} else {
+		nic->vlan_id = 0;
+		data_buf = skb->data;
+		data_len = skb->len;
+	}
+
+	/* If it is a ICMPV6 packet, clear all the other bits : for backward compatibility with the firmware */
+	if (nic_type & NIC_TYPE_ICMPV6)
+		nic_type = NIC_TYPE_ICMPV6;
+
+	/* If it is not a dhcp packet, clear all the flag bits : original NIC, otherwise the special flag (IPVX | DHCP) */
+	if (!(nic_type & NIC_TYPE_F_DHCP))
+		nic_type &= NIC_TYPE_MASK;
+
+	sscanf(dev->name, "lte%d", &idx);
+
+	ret = gdm_lte_sdu_send(nic,
+			       data_buf,
+			       data_len,
+			       tx_complete,
+			       nic,
+			       idx,
+			       nic_type);
+
+	if (ret == TX_NO_BUFFER || ret == TX_NO_SPC) {
+		netif_stop_queue(dev);
+		if (ret == TX_NO_BUFFER)
+			ret = 0;
+		else
+			ret = -ENOSPC;
+	} else if (ret == TX_NO_DEV) {
+		ret = -ENODEV;
+	}
+
+	/* Updates tx stats */
+	if (ret) {
+		nic->stats.tx_dropped++;
+	} else {
+		nic->stats.tx_packets++;
+		nic->stats.tx_bytes += data_len;
+	}
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static struct net_device_stats *gdm_lte_stats(struct net_device *dev)
+{
+	struct nic *nic = netdev_priv(dev);
+	return &nic->stats;
+}
+
+static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct hci_packet *hci = (struct hci_packet *)buf;
+	int idx;
+
+	sscanf(dev->name, "lte%d", &idx);
+
+	return netlink_send(lte_event.sock, idx, 0, buf,
+			    gdm_dev16_to_cpu(gdm_dev_endian(nic), hci->len) + HCI_HEADER_SIZE);
+}
+
+static void gdm_lte_event_rcv(struct net_device *dev, u16 type, void *msg, int len)
+{
+	struct nic *nic = netdev_priv(dev);
+
+	gdm_lte_hci_send(nic, msg, len);
+}
+
+int gdm_lte_event_init(void)
+{
+	if (lte_event.ref_cnt == 0)
+		lte_event.sock = netlink_init(NETLINK_LTE, gdm_lte_event_rcv);
+
+	if (lte_event.sock) {
+		lte_event.ref_cnt++;
+		return 0;
+	}
+
+	pr_err("event init failed\n");
+	return -1;
+}
+
+void gdm_lte_event_exit(void)
+{
+	if (lte_event.sock && --lte_event.ref_cnt == 0) {
+		netlink_exit(lte_event.sock);
+		lte_event.sock = NULL;
+	}
+}
+
+static u8 find_dev_index(u32 nic_type)
+{
+	u8 index;
+
+	index = (u8)(nic_type & 0x0000000f);
+	if (index > MAX_NIC_TYPE)
+		index = 0;
+
+	return index;
+}
+
+static void gdm_lte_netif_rx(struct net_device *dev, char *buf, int len, int flagged_nic_type)
+{
+	u32 nic_type;
+	struct nic *nic;
+	struct sk_buff *skb;
+	struct ethhdr eth;
+	struct vlan_ethhdr vlan_eth;
+	void *mac_header_data;
+	u32 mac_header_len;
+	char ip_version = 0;
+
+	nic_type = flagged_nic_type & NIC_TYPE_MASK;
+	nic = netdev_priv(dev);
+
+	if (flagged_nic_type & NIC_TYPE_F_DHCP) {
+		/* Change the destination mac address with the one requested the IP */
+		if (flagged_nic_type & NIC_TYPE_F_IPV4) {
+			struct dhcp_packet {
+				u8 op;      /* BOOTREQUEST or BOOTREPLY */
+				u8 htype;   /* hardware address type. 1 = 10mb ethernet */
+				u8 hlen;    /* hardware address length */
+				u8 hops;    /* used by relay agents only */
+				u32 xid;    /* unique id */
+				u16 secs;   /* elapsed since client began acquisition/renewal */
+				u16 flags;  /* only one flag so far: */
+				#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
+				u32 ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
+				u32 yiaddr; /* 'your' (client) IP address */
+				/* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
+				u32 siaddr_nip;
+				u32 gateway_nip; /* relay agent IP address */
+				u8 chaddr[16];   /* link-layer client hardware address (MAC) */
+				u8 sname[64];    /* server host name (ASCIZ) */
+				u8 file[128];    /* boot file name (ASCIZ) */
+				u32 cookie;      /* fixed first four option bytes (99,130,83,99 dec) */
+			} __packed;
+			void *addr = buf + sizeof(struct iphdr) + sizeof(struct udphdr) + offsetof(struct dhcp_packet, chaddr);
+			memcpy(nic->dest_mac_addr, addr, ETH_ALEN);
+		}
+	}
+
+	if (nic->vlan_id > 0) {
+		mac_header_data = (void *)&vlan_eth;
+		mac_header_len = VLAN_ETH_HLEN;
+	} else {
+		mac_header_data = (void *)&eth;
+		mac_header_len = ETH_HLEN;
+	}
+
+	/* Format the data so that it can be put to skb */
+	memcpy(mac_header_data, nic->dest_mac_addr, ETH_ALEN);
+	memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
+
+	vlan_eth.h_vlan_TCI = htons(nic->vlan_id);
+	vlan_eth.h_vlan_proto = htons(ETH_P_8021Q);
+
+	if (nic_type == NIC_TYPE_ARP) {
+		/* Should be response: Only happens because there was a request from the host */
+		eth.h_proto = htons(ETH_P_ARP);
+		vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_ARP);
+	} else {
+		ip_version = buf[0] >> 4;
+		if (ip_version == IP_VERSION_4) {
+			eth.h_proto = htons(ETH_P_IP);
+			vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_IP);
+		} else if (ip_version == IP_VERSION_6) {
+			eth.h_proto = htons(ETH_P_IPV6);
+			vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_IPV6);
+		} else {
+			netdev_err(dev, "Unknown IP version %d\n", ip_version);
+			return;
+		}
+	}
+
+	/* Alloc skb and reserve align */
+	skb = dev_alloc_skb(len + mac_header_len + NET_IP_ALIGN);
+	if (!skb)
+		return;
+	skb_reserve(skb, NET_IP_ALIGN);
+
+	memcpy(skb_put(skb, mac_header_len), mac_header_data, mac_header_len);
+	memcpy(skb_put(skb, len), buf, len);
+
+	skb->protocol = ((struct ethhdr *)mac_header_data)->h_proto;
+	skb->dev = dev;
+	skb_reset_mac_header(skb);
+	skb_pull(skb, ETH_HLEN);
+
+	gdm_lte_rx(skb, nic, nic_type);
+}
+
+static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len)
+{
+	struct net_device *dev;
+	struct multi_sdu *multi_sdu = (struct multi_sdu *)buf;
+	struct sdu *sdu = NULL;
+	u8 *data = (u8 *)multi_sdu->data;
+	u16 i = 0;
+	u16 num_packet;
+	u16 hci_len;
+	u16 cmd_evt;
+	u32 nic_type;
+	u8 index;
+
+	hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->len);
+	num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), multi_sdu->num_packet);
+
+	for (i = 0; i < num_packet; i++) {
+		sdu = (struct sdu *)data;
+
+		cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->cmd_evt);
+		hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->len);
+		nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type);
+
+		if (cmd_evt != LTE_RX_SDU) {
+			pr_err("rx sdu wrong hci %04x\n", cmd_evt);
+			return;
+		}
+		if (hci_len < 12) {
+			pr_err("rx sdu invalid len %d\n", hci_len);
+			return;
+		}
+
+		index = find_dev_index(nic_type);
+		if (index < MAX_NIC_TYPE) {
+			dev = phy_dev->dev[index];
+			gdm_lte_netif_rx(dev, (char *)sdu->data, (int)(hci_len-12), nic_type);
+		} else {
+			pr_err("rx sdu invalid nic_type :%x\n", nic_type);
+		}
+
+		data += ((hci_len+3) & 0xfffc) + HCI_HEADER_SIZE;
+	}
+}
+
+static void gdm_lte_pdn_table(struct net_device *dev, char *buf, int len)
+{
+	struct nic *nic = netdev_priv(dev);
+	struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
+
+	if (pdn_table->activate) {
+		nic->pdn_table.activate = pdn_table->activate;
+		nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu(gdm_dev_endian(nic), pdn_table->dft_eps_id);
+		nic->pdn_table.nic_type = gdm_dev32_to_cpu(gdm_dev_endian(nic), pdn_table->nic_type);
+
+		netdev_info(dev, "pdn activated, nic_type=0x%x\n",
+			    nic->pdn_table.nic_type);
+	} else {
+		memset(&nic->pdn_table, 0x00, sizeof(struct pdn_table));
+		netdev_info(dev, "pdn deactivated\n");
+	}
+}
+
+static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len)
+{
+	struct hci_packet *hci = (struct hci_packet *)buf;
+	struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
+	struct sdu *sdu;
+	struct net_device *dev;
+	int ret = 0;
+	u16 cmd_evt;
+	u32 nic_type;
+	u8 index;
+
+	if (!len)
+		return ret;
+
+	cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), hci->cmd_evt);
+
+	dev = phy_dev->dev[0];
+	if (dev == NULL)
+		return 0;
+
+	switch (cmd_evt) {
+	case LTE_RX_SDU:
+		sdu = (struct sdu *)hci->data;
+		nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), sdu->nic_type);
+		index = find_dev_index(nic_type);
+		dev = phy_dev->dev[index];
+		gdm_lte_netif_rx(dev, hci->data, len, nic_type);
+		break;
+	case LTE_RX_MULTI_SDU:
+		gdm_lte_multi_sdu_pkt(phy_dev, buf, len);
+		break;
+	case LTE_LINK_ON_OFF_INDICATION:
+		netdev_info(dev, "link %s\n",
+			    ((struct hci_connect_ind *)buf)->connect
+			    ? "on" : "off");
+		break;
+	case LTE_PDN_TABLE_IND:
+		pdn_table = (struct hci_pdn_table_ind *)buf;
+		nic_type = gdm_dev32_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), pdn_table->nic_type);
+		index = find_dev_index(nic_type);
+		dev = phy_dev->dev[index];
+		gdm_lte_pdn_table(dev, buf, len);
+		/* Fall through */
+	default:
+		ret = gdm_lte_event_send(dev, buf, len);
+		break;
+	}
+
+	return ret;
+}
+
+static int rx_complete(void *arg, void *data, int len, int context)
+{
+	struct phy_dev *phy_dev = (struct phy_dev *)arg;
+
+	return gdm_lte_receive_pkt(phy_dev, (char *)data, len);
+}
+
+void start_rx_proc(struct phy_dev *phy_dev)
+{
+	int i;
+
+	for (i = 0; i < MAX_RX_SUBMIT_COUNT; i++)
+		gdm_lte_rcv_with_cb(phy_dev, rx_complete, phy_dev, USB_COMPLETE);
+}
+
+static struct net_device_ops gdm_netdev_ops = {
+	.ndo_open			= gdm_lte_open,
+	.ndo_stop			= gdm_lte_close,
+	.ndo_set_config			= gdm_lte_set_config,
+	.ndo_start_xmit			= gdm_lte_tx,
+	.ndo_get_stats			= gdm_lte_stats,
+};
+
+static u8 gdm_lte_macaddr[ETH_ALEN] = {0x00, 0x0a, 0x3b, 0x00, 0x00, 0x00};
+
+static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, u8 *mac_address, u8 index)
+{
+	/* Form the dev_addr */
+	if (!mac_address)
+		memcpy(dev_addr, gdm_lte_macaddr, ETH_ALEN);
+	else
+		memcpy(dev_addr, mac_address, ETH_ALEN);
+
+	/* The last byte of the mac address should be less than or equal to 0xFC */
+	dev_addr[ETH_ALEN-1] += index;
+
+	/* Create random nic src and copy the first 3 bytes to be the same as dev_addr */
+	random_ether_addr(nic_src);
+	memcpy(nic_src, dev_addr, 3);
+
+	/* Copy the nic_dest from dev_addr*/
+	memcpy(nic_dest, dev_addr, ETH_ALEN);
+}
+
+static void validate_mac_address(u8 *mac_address)
+{
+	/* if zero address or multicast bit set, restore the default value */
+	if (is_zero_ether_addr(mac_address) || (mac_address[0] & 0x01)) {
+		pr_err("MAC invalid, restoring default\n");
+		memcpy(mac_address, gdm_lte_macaddr, 6);
+	}
+}
+
+int register_lte_device(struct phy_dev *phy_dev, struct device *dev, u8 *mac_address)
+{
+	struct nic *nic;
+	struct net_device *net;
+	char pdn_dev_name[16];
+	int ret = 0;
+	u8 index;
+
+	validate_mac_address(mac_address);
+
+	for (index = 0; index < MAX_NIC_TYPE; index++) {
+		/* Create device name lteXpdnX */
+		sprintf(pdn_dev_name, "lte%%dpdn%d", index);
+
+		/* Allocate netdev */
+		net = alloc_netdev(sizeof(struct nic), pdn_dev_name, ether_setup);
+		if (net == NULL) {
+			pr_err("alloc_netdev failed\n");
+			ret = -ENOMEM;
+			goto err;
+		}
+		net->netdev_ops = &gdm_netdev_ops;
+		net->flags &= ~IFF_MULTICAST;
+		net->mtu = DEFAULT_MTU_SIZE;
+
+		nic = netdev_priv(net);
+		memset(nic, 0, sizeof(struct nic));
+		nic->netdev = net;
+		nic->phy_dev = phy_dev;
+		nic->nic_id = index;
+
+		form_mac_address(
+				net->dev_addr,
+				nic->src_mac_addr,
+				nic->dest_mac_addr,
+				mac_address,
+				index);
+
+		SET_NETDEV_DEV(net, dev);
+		SET_NETDEV_DEVTYPE(net, &wwan_type);
+
+		ret = register_netdev(net);
+		if (ret)
+			goto err;
+
+		netif_carrier_on(net);
+
+		phy_dev->dev[index] = net;
+	}
+
+	return 0;
+
+err:
+	unregister_lte_device(phy_dev);
+
+	return ret;
+}
+
+void unregister_lte_device(struct phy_dev *phy_dev)
+{
+	struct net_device *net;
+	int index;
+
+	for (index = 0; index < MAX_NIC_TYPE; index++) {
+		net = phy_dev->dev[index];
+		if (net == NULL)
+			continue;
+
+		unregister_netdev(net);
+		free_netdev(net);
+	}
+}
diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h
new file mode 100644
index 0000000..9287d31
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_lte.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _GDM_LTE_H_
+#define _GDM_LTE_H_
+
+#include <linux/netdevice.h>
+#include <linux/types.h>
+
+#include "gdm_endian.h"
+
+#define MAX_NIC_TYPE		4
+#define MAX_RX_SUBMIT_COUNT	3
+#define DRIVER_VERSION		"3.7.17.0"
+
+enum TX_ERROR_CODE {
+	TX_NO_ERROR = 0,
+	TX_NO_DEV,
+	TX_NO_SPC,
+	TX_NO_BUFFER,
+};
+
+enum CALLBACK_CONTEXT {
+	KERNEL_THREAD = 0,
+	USB_COMPLETE,
+};
+
+struct pdn_table {
+	u8 activate;
+	u32 dft_eps_id;
+	u32 nic_type;
+} __packed;
+
+struct nic;
+
+struct phy_dev {
+	void	*priv_dev;
+	struct net_device *dev[MAX_NIC_TYPE];
+	int	(*send_hci_func)(void *priv_dev, void *data, int len,
+			void (*cb)(void *cb_data), void *cb_data);
+	int	(*send_sdu_func)(void *priv_dev, void *data, int len,
+			unsigned int dftEpsId, unsigned int epsId,
+			void (*cb)(void *cb_data), void *cb_data,
+			int dev_idx, int nic_type);
+	int	(*rcv_func)(void *priv_dev,
+			int (*cb)(void *cb_data, void *data, int len,
+				  int context),
+			void *cb_data, int context);
+	struct gdm_endian *(*get_endian)(void *priv_dev);
+};
+
+struct nic {
+	struct net_device *netdev;
+	struct phy_dev *phy_dev;
+	struct net_device_stats stats;
+	struct pdn_table pdn_table;
+	u8 dest_mac_addr[ETH_ALEN];
+	u8 src_mac_addr[ETH_ALEN];
+	u32 nic_id;
+	u16 vlan_id;
+};
+
+int gdm_lte_event_init(void);
+void gdm_lte_event_exit(void);
+
+void start_rx_proc(struct phy_dev *phy_dev);
+int register_lte_device(struct phy_dev *phy_dev, struct device *dev,
+			u8 *mac_address);
+void unregister_lte_device(struct phy_dev *phy_dev);
+
+#endif /* _GDM_LTE_H_ */
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
new file mode 100644
index 0000000..5b1ef40
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/usb/cdc.h>
+
+#include "gdm_mux.h"
+
+struct workqueue_struct *mux_rx_wq;
+
+static u16 packet_type[TTY_MAX_COUNT] = {0xF011, 0xF010};
+
+#define USB_DEVICE_CDC_DATA(vid, pid) \
+	.match_flags = \
+		USB_DEVICE_ID_MATCH_DEVICE |\
+		USB_DEVICE_ID_MATCH_INT_CLASS |\
+		USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
+	.idVendor = vid,\
+	.idProduct = pid,\
+	.bInterfaceClass = USB_CLASS_COMM,\
+	.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE_CDC_DATA(0x1076, 0x8000) }, /* GCT GDM7240 */
+	{ USB_DEVICE_CDC_DATA(0x1076, 0x8f00) }, /* GCT GDM7243 */
+	{ USB_DEVICE_CDC_DATA(0x1076, 0x9000) }, /* GCT GDM7243 */
+	{ USB_DEVICE_CDC_DATA(0x1d74, 0x2300) }, /* LGIT Phoenix */
+	{}
+};
+
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+int packet_type_to_index(u16 packetType)
+{
+	int i;
+
+	for (i = 0; i < TTY_MAX_COUNT; i++) {
+		if (packet_type[i] == packetType)
+			return i;
+	}
+
+	return -1;
+}
+
+static struct mux_tx *alloc_mux_tx(int len)
+{
+	struct mux_tx *t = NULL;
+
+	t = kzalloc(sizeof(struct mux_tx), GFP_ATOMIC);
+	if (!t)
+		return NULL;
+
+	t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	t->buf = kmalloc(MUX_TX_MAX_SIZE, GFP_ATOMIC);
+	if (!t->urb || !t->buf) {
+		usb_free_urb(t->urb);
+		kfree(t->buf);
+		kfree(t);
+		return NULL;
+	}
+
+	return t;
+}
+
+static void free_mux_tx(struct mux_tx *t)
+{
+	if (t) {
+		usb_free_urb(t->urb);
+		kfree(t->buf);
+		kfree(t);
+	}
+}
+
+static struct mux_rx *alloc_mux_rx(void)
+{
+	struct mux_rx *r = NULL;
+
+	r = kzalloc(sizeof(struct mux_rx), GFP_ATOMIC);
+	if (!r)
+		return NULL;
+
+	r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	r->buf = kmalloc(MUX_RX_MAX_SIZE, GFP_ATOMIC);
+	if (!r->urb || !r->buf) {
+		usb_free_urb(r->urb);
+		kfree(r->buf);
+		kfree(r);
+		return NULL;
+	}
+
+	return r;
+}
+
+static void free_mux_rx(struct mux_rx *r)
+{
+	if (r) {
+		usb_free_urb(r->urb);
+		kfree(r->buf);
+		kfree(r);
+	}
+}
+
+static struct mux_rx *get_rx_struct(struct rx_cxt *rx)
+{
+	struct mux_rx *r;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rx->free_list_lock, flags);
+
+	if (list_empty(&rx->rx_free_list)) {
+		spin_unlock_irqrestore(&rx->free_list_lock, flags);
+		return NULL;
+	}
+
+	r = list_entry(rx->rx_free_list.prev, struct mux_rx, free_list);
+	list_del(&r->free_list);
+
+	spin_unlock_irqrestore(&rx->free_list_lock, flags);
+
+	return r;
+}
+
+static void put_rx_struct(struct rx_cxt *rx, struct mux_rx *r)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rx->free_list_lock, flags);
+	list_add_tail(&r->free_list, &rx->rx_free_list);
+	spin_unlock_irqrestore(&rx->free_list_lock, flags);
+}
+
+
+static int up_to_host(struct mux_rx *r)
+{
+	struct mux_dev *mux_dev = (struct mux_dev *)r->mux_dev;
+	struct mux_pkt_header *mux_header;
+	unsigned int start_flag;
+	unsigned int payload_size;
+	unsigned short packet_type;
+	int remain;
+	int dummy_cnt;
+	u32 packet_size_sum = r->offset;
+	int index;
+	int ret = TO_HOST_INVALID_PACKET;
+	int len = r->len;
+
+	while (1) {
+		mux_header = (struct mux_pkt_header *)(r->buf + packet_size_sum);
+		start_flag = __le32_to_cpu(mux_header->start_flag);
+		payload_size = __le32_to_cpu(mux_header->payload_size);
+		packet_type = __le16_to_cpu(mux_header->packet_type);
+
+		if (start_flag != START_FLAG) {
+			pr_err("invalid START_FLAG %x\n", start_flag);
+			break;
+		}
+
+		remain = (MUX_HEADER_SIZE + payload_size) % 4;
+		dummy_cnt = remain ? (4-remain) : 0;
+
+		if (len - packet_size_sum <
+			MUX_HEADER_SIZE + payload_size + dummy_cnt) {
+			pr_err("invalid payload : %d %d %04x\n",
+			       payload_size, len, packet_type);
+			break;
+		}
+
+		index = packet_type_to_index(packet_type);
+		if (index < 0) {
+			pr_err("invalid index %d\n", index);
+			break;
+		}
+
+		ret = r->callback(mux_header->data,
+				payload_size,
+				index,
+				mux_dev->tty_dev,
+				RECV_PACKET_PROCESS_CONTINUE
+				);
+		if (ret == TO_HOST_BUFFER_REQUEST_FAIL) {
+			r->offset += packet_size_sum;
+			break;
+		}
+
+		packet_size_sum += MUX_HEADER_SIZE + payload_size + dummy_cnt;
+		if (len - packet_size_sum <= MUX_HEADER_SIZE + 2) {
+			ret = r->callback(NULL,
+					0,
+					index,
+					mux_dev->tty_dev,
+					RECV_PACKET_PROCESS_COMPLETE
+					);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static void do_rx(struct work_struct *work)
+{
+	struct mux_dev *mux_dev =
+		container_of(work, struct mux_dev , work_rx.work);
+	struct mux_rx *r;
+	struct rx_cxt *rx = (struct rx_cxt *)&mux_dev->rx;
+	unsigned long flags;
+	int ret = 0;
+
+	while (1) {
+		spin_lock_irqsave(&rx->to_host_lock, flags);
+		if (list_empty(&rx->to_host_list)) {
+			spin_unlock_irqrestore(&rx->to_host_lock, flags);
+			break;
+		}
+		r = list_entry(rx->to_host_list.next, struct mux_rx, to_host_list);
+		list_del(&r->to_host_list);
+		spin_unlock_irqrestore(&rx->to_host_lock, flags);
+
+		ret = up_to_host(r);
+		if (ret == TO_HOST_BUFFER_REQUEST_FAIL)
+			pr_err("failed to send mux data to host\n");
+		else
+			put_rx_struct(rx, r);
+	}
+}
+
+static void remove_rx_submit_list(struct mux_rx *r, struct rx_cxt *rx)
+{
+	unsigned long flags;
+	struct mux_rx	*r_remove, *r_remove_next;
+
+	spin_lock_irqsave(&rx->submit_list_lock, flags);
+	list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list) {
+		if (r == r_remove)
+			list_del(&r->rx_submit_list);
+	}
+	spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+}
+
+static void gdm_mux_rcv_complete(struct urb *urb)
+{
+	struct mux_rx *r = urb->context;
+	struct mux_dev *mux_dev = (struct mux_dev *)r->mux_dev;
+	struct rx_cxt *rx = &mux_dev->rx;
+	unsigned long flags;
+
+	remove_rx_submit_list(r, rx);
+
+	if (urb->status) {
+		if (mux_dev->usb_state == PM_NORMAL)
+			pr_err("%s: urb status error %d\n",
+			       __func__, urb->status);
+		put_rx_struct(rx, r);
+	} else {
+		r->len = r->urb->actual_length;
+		spin_lock_irqsave(&rx->to_host_lock, flags);
+		list_add_tail(&r->to_host_list, &rx->to_host_list);
+		queue_work(mux_rx_wq, &mux_dev->work_rx.work);
+		spin_unlock_irqrestore(&rx->to_host_lock, flags);
+	}
+}
+
+static int gdm_mux_recv(void *priv_dev,
+			int (*cb)(void *data, int len, int tty_index, struct tty_dev *tty_dev, int complete)
+			)
+{
+	struct mux_dev *mux_dev = priv_dev;
+	struct usb_device *usbdev = mux_dev->usbdev;
+	struct mux_rx *r;
+	struct rx_cxt *rx = &mux_dev->rx;
+	unsigned long flags;
+	int ret;
+
+	if (!usbdev) {
+		pr_err("device is disconnected\n");
+		return -ENODEV;
+	}
+
+	r = get_rx_struct(rx);
+	if (!r) {
+		pr_err("get_rx_struct fail\n");
+		return -ENOMEM;
+	}
+
+	r->offset = 0;
+	r->mux_dev = (void *)mux_dev;
+	r->callback = cb;
+	mux_dev->rx_cb = cb;
+
+	usb_fill_bulk_urb(r->urb,
+			  usbdev,
+			  usb_rcvbulkpipe(usbdev, 0x86),
+			  r->buf,
+			  MUX_RX_MAX_SIZE,
+			  gdm_mux_rcv_complete,
+			  r);
+
+	spin_lock_irqsave(&rx->submit_list_lock, flags);
+	list_add_tail(&r->rx_submit_list, &rx->rx_submit_list);
+	spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+	ret = usb_submit_urb(r->urb, GFP_KERNEL);
+
+	if (ret) {
+		spin_lock_irqsave(&rx->submit_list_lock, flags);
+		list_del(&r->rx_submit_list);
+		spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+		put_rx_struct(rx, r);
+
+		pr_err("usb_submit_urb ret=%d\n", ret);
+	}
+
+	usb_mark_last_busy(usbdev);
+
+	return ret;
+}
+
+static void gdm_mux_send_complete(struct urb *urb)
+{
+	struct mux_tx *t = urb->context;
+
+	if (urb->status == -ECONNRESET) {
+		pr_info("CONNRESET\n");
+		free_mux_tx(t);
+		return;
+	}
+
+	if (t->callback)
+		t->callback(t->cb_data);
+
+	free_mux_tx(t);
+}
+
+static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index,
+			void (*cb)(void *data), void *cb_data)
+{
+	struct mux_dev *mux_dev = priv_dev;
+	struct usb_device *usbdev = mux_dev->usbdev;
+	struct mux_pkt_header *mux_header;
+	struct mux_tx *t = NULL;
+	static u32 seq_num = 1;
+	int remain;
+	int dummy_cnt;
+	int total_len;
+	int ret;
+	unsigned long flags;
+
+	if (mux_dev->usb_state == PM_SUSPEND) {
+		ret = usb_autopm_get_interface(mux_dev->intf);
+		if (!ret)
+			usb_autopm_put_interface(mux_dev->intf);
+	}
+
+	spin_lock_irqsave(&mux_dev->write_lock, flags);
+
+	remain = (MUX_HEADER_SIZE + len) % 4;
+	dummy_cnt = remain ? (4 - remain) : 0;
+
+	total_len = len + MUX_HEADER_SIZE + dummy_cnt;
+
+	t = alloc_mux_tx(total_len);
+	if (!t) {
+		pr_err("alloc_mux_tx fail\n");
+		spin_unlock_irqrestore(&mux_dev->write_lock, flags);
+		return -ENOMEM;
+	}
+
+	mux_header = (struct mux_pkt_header *)t->buf;
+	mux_header->start_flag = __cpu_to_le32(START_FLAG);
+	mux_header->seq_num = __cpu_to_le32(seq_num++);
+	mux_header->payload_size = __cpu_to_le32((u32)len);
+	mux_header->packet_type = __cpu_to_le16(packet_type[tty_index]);
+
+	memcpy(t->buf+MUX_HEADER_SIZE, data, len);
+	memset(t->buf+MUX_HEADER_SIZE+len, 0, dummy_cnt);
+
+	t->len = total_len;
+	t->callback = cb;
+	t->cb_data = cb_data;
+
+	usb_fill_bulk_urb(t->urb,
+			  usbdev,
+			  usb_sndbulkpipe(usbdev, 5),
+			  t->buf,
+			  total_len,
+			  gdm_mux_send_complete,
+			  t);
+
+	ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+	spin_unlock_irqrestore(&mux_dev->write_lock, flags);
+
+	if (ret)
+		pr_err("usb_submit_urb Error: %d\n", ret);
+
+	usb_mark_last_busy(usbdev);
+
+	return ret;
+}
+
+static int gdm_mux_send_control(void *priv_dev, int request, int value, void *buf, int len)
+{
+	struct mux_dev *mux_dev = priv_dev;
+	struct usb_device *usbdev = mux_dev->usbdev;
+	int ret;
+
+	ret = usb_control_msg(usbdev,
+			      usb_sndctrlpipe(usbdev, 0),
+			      request,
+			      USB_RT_ACM,
+			      value,
+			      2,
+			      buf,
+			      len,
+			      5000
+			     );
+
+	if (ret < 0)
+		pr_err("usb_control_msg error: %d\n", ret);
+
+	return ret < 0 ? ret : 0;
+}
+
+static void release_usb(struct mux_dev *mux_dev)
+{
+	struct rx_cxt		*rx = &mux_dev->rx;
+	struct mux_rx		*r, *r_next;
+	unsigned long		flags;
+
+	cancel_delayed_work(&mux_dev->work_rx);
+
+	spin_lock_irqsave(&rx->submit_list_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) {
+		spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+		usb_kill_urb(r->urb);
+		spin_lock_irqsave(&rx->submit_list_lock, flags);
+	}
+	spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+	spin_lock_irqsave(&rx->free_list_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->rx_free_list, free_list) {
+		list_del(&r->free_list);
+		free_mux_rx(r);
+	}
+	spin_unlock_irqrestore(&rx->free_list_lock, flags);
+
+	spin_lock_irqsave(&rx->to_host_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list) {
+		if (r->mux_dev == (void *)mux_dev) {
+			list_del(&r->to_host_list);
+			free_mux_rx(r);
+		}
+	}
+	spin_unlock_irqrestore(&rx->to_host_lock, flags);
+}
+
+
+static int init_usb(struct mux_dev *mux_dev)
+{
+	struct mux_rx *r;
+	struct rx_cxt *rx = &mux_dev->rx;
+	int ret = 0;
+	int i;
+
+	spin_lock_init(&mux_dev->write_lock);
+	INIT_LIST_HEAD(&rx->to_host_list);
+	INIT_LIST_HEAD(&rx->rx_submit_list);
+	INIT_LIST_HEAD(&rx->rx_free_list);
+	spin_lock_init(&rx->to_host_lock);
+	spin_lock_init(&rx->submit_list_lock);
+	spin_lock_init(&rx->free_list_lock);
+
+	for (i = 0; i < MAX_ISSUE_NUM * 2; i++) {
+		r = alloc_mux_rx();
+		if (r == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		list_add(&r->free_list, &rx->rx_free_list);
+	}
+
+	INIT_DELAYED_WORK(&mux_dev->work_rx, do_rx);
+
+	return ret;
+}
+
+static int gdm_mux_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct mux_dev *mux_dev;
+	struct tty_dev *tty_dev;
+	u16 idVendor, idProduct;
+	int bInterfaceNumber;
+	int ret;
+	int i;
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+	bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	idVendor = __le16_to_cpu(usbdev->descriptor.idVendor);
+	idProduct = __le16_to_cpu(usbdev->descriptor.idProduct);
+
+	pr_info("mux vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct);
+
+	if (bInterfaceNumber != 2)
+		return -ENODEV;
+
+	mux_dev = kzalloc(sizeof(struct mux_dev), GFP_KERNEL);
+	if (!mux_dev)
+		return -ENOMEM;
+
+	tty_dev = kzalloc(sizeof(struct tty_dev), GFP_KERNEL);
+	if (!tty_dev) {
+		ret = -ENOMEM;
+		goto err_free_mux;
+	}
+
+	mux_dev->usbdev = usbdev;
+	mux_dev->control_intf = intf;
+
+	ret = init_usb(mux_dev);
+	if (ret)
+		goto err_free_tty;
+
+	tty_dev->priv_dev = (void *)mux_dev;
+	tty_dev->send_func = gdm_mux_send;
+	tty_dev->recv_func = gdm_mux_recv;
+	tty_dev->send_control = gdm_mux_send_control;
+
+	ret = register_lte_tty_device(tty_dev, &intf->dev);
+	if (ret)
+		goto err_unregister_tty;
+
+	for (i = 0; i < TTY_MAX_COUNT; i++)
+		mux_dev->tty_dev = tty_dev;
+
+	mux_dev->intf = intf;
+	mux_dev->usb_state = PM_NORMAL;
+
+	usb_get_dev(usbdev);
+	usb_set_intfdata(intf, tty_dev);
+
+	return 0;
+
+err_unregister_tty:
+	unregister_lte_tty_device(tty_dev);
+	release_usb(mux_dev);
+err_free_tty:
+	kfree(tty_dev);
+err_free_mux:
+	kfree(mux_dev);
+
+	return ret;
+}
+
+static void gdm_mux_disconnect(struct usb_interface *intf)
+{
+	struct tty_dev *tty_dev;
+	struct mux_dev *mux_dev;
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+
+	tty_dev = usb_get_intfdata(intf);
+
+	mux_dev = tty_dev->priv_dev;
+
+	release_usb(mux_dev);
+	unregister_lte_tty_device(tty_dev);
+
+	kfree(mux_dev);
+	kfree(tty_dev);
+
+	usb_put_dev(usbdev);
+}
+
+static int gdm_mux_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+	struct tty_dev *tty_dev;
+	struct mux_dev *mux_dev;
+	struct rx_cxt *rx;
+	struct mux_rx *r, *r_next;
+	unsigned long flags;
+
+	tty_dev = usb_get_intfdata(intf);
+	mux_dev = tty_dev->priv_dev;
+	rx = &mux_dev->rx;
+
+	if (mux_dev->usb_state != PM_NORMAL) {
+		pr_err("usb suspend - invalid state\n");
+		return -1;
+	}
+
+	mux_dev->usb_state = PM_SUSPEND;
+
+
+	spin_lock_irqsave(&rx->submit_list_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list) {
+		spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+		usb_kill_urb(r->urb);
+		spin_lock_irqsave(&rx->submit_list_lock, flags);
+	}
+	spin_unlock_irqrestore(&rx->submit_list_lock, flags);
+
+	return 0;
+}
+
+static int gdm_mux_resume(struct usb_interface *intf)
+{
+	struct tty_dev *tty_dev;
+	struct mux_dev *mux_dev;
+	u8 i;
+
+	tty_dev = usb_get_intfdata(intf);
+	mux_dev = tty_dev->priv_dev;
+
+	if (mux_dev->usb_state != PM_SUSPEND) {
+		pr_err("usb resume - invalid state\n");
+		return -1;
+	}
+
+	mux_dev->usb_state = PM_NORMAL;
+
+	for (i = 0; i < MAX_ISSUE_NUM; i++)
+		gdm_mux_recv(mux_dev, mux_dev->rx_cb);
+
+	return 0;
+}
+
+static struct usb_driver gdm_mux_driver = {
+	.name = "gdm_mux",
+	.probe = gdm_mux_probe,
+	.disconnect = gdm_mux_disconnect,
+	.id_table = id_table,
+	.supports_autosuspend = 1,
+	.suspend = gdm_mux_suspend,
+	.resume = gdm_mux_resume,
+	.reset_resume = gdm_mux_resume,
+};
+
+static int __init gdm_usb_mux_init(void)
+{
+
+	mux_rx_wq = create_workqueue("mux_rx_wq");
+	if (mux_rx_wq == NULL) {
+		pr_err("work queue create fail\n");
+		return -1;
+	}
+
+	register_lte_tty_driver();
+
+	return usb_register(&gdm_mux_driver);
+}
+
+static void __exit gdm_usb_mux_exit(void)
+{
+	unregister_lte_tty_driver();
+
+	if (mux_rx_wq) {
+		flush_workqueue(mux_rx_wq);
+		destroy_workqueue(mux_rx_wq);
+	}
+
+	usb_deregister(&gdm_mux_driver);
+}
+
+module_init(gdm_usb_mux_init);
+module_exit(gdm_usb_mux_exit);
+
+MODULE_DESCRIPTION("GCT LTE TTY Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm724x/gdm_mux.h b/drivers/staging/gdm724x/gdm_mux.h
new file mode 100644
index 0000000..0163b24
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_mux.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _GDM_MUX_H_
+#define _GDM_MUX_H_
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#include "gdm_tty.h"
+
+#define PM_NORMAL 0
+#define PM_SUSPEND 1
+
+#define USB_RT_ACM          (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+#define START_FLAG 0xA512485A
+#define MUX_HEADER_SIZE 14
+#define MUX_TX_MAX_SIZE (1024*10)
+#define MUX_RX_MAX_SIZE (1024*30)
+#define AT_PKT_TYPE 0xF011
+#define DM_PKT_TYPE 0xF010
+
+#define RETRY_TIMER 30 /* msec */
+
+struct mux_pkt_header {
+	unsigned int start_flag;
+	unsigned int seq_num;
+	unsigned int payload_size;
+	unsigned short packet_type;
+	unsigned char data[0];
+};
+
+struct mux_tx {
+	struct urb *urb;
+	u8 *buf;
+	int  len;
+	void (*callback)(void *cb_data);
+	void *cb_data;
+};
+
+struct mux_rx {
+	struct list_head free_list;
+	struct list_head rx_submit_list;
+	struct list_head to_host_list;
+	struct urb *urb;
+	u8 *buf;
+	void *mux_dev;
+	u32 offset;
+	u32 len;
+	int (*callback)(void *data,
+			int len,
+			int tty_index,
+			struct tty_dev *tty_dev,
+			int complete);
+};
+
+struct rx_cxt {
+	struct list_head to_host_list;
+	struct list_head rx_submit_list;
+	struct list_head rx_free_list;
+	spinlock_t to_host_lock;
+	spinlock_t submit_list_lock;
+	spinlock_t free_list_lock;
+};
+
+struct mux_dev {
+	struct usb_device *usbdev;
+	struct usb_interface *control_intf;
+	struct usb_interface *data_intf;
+	struct rx_cxt	rx;
+	struct delayed_work work_rx;
+	struct usb_interface *intf;
+	int usb_state;
+	int (*rx_cb)(void *data,
+		     int len,
+		     int tty_index,
+		     struct tty_dev *tty_dev,
+		     int complete);
+	spinlock_t write_lock;
+	struct tty_dev *tty_dev;
+};
+
+#endif /* _GDM_MUX_H_ */
diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c
new file mode 100644
index 0000000..0247a20
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_tty.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/cdc.h>
+#include <linux/serial.h>
+#include "gdm_tty.h"
+
+#define GDM_TTY_MAJOR 0
+#define GDM_TTY_MINOR 32
+
+#define ACM_CTRL_DTR 0x01
+#define ACM_CTRL_RTS 0x02
+#define ACM_CTRL_DSR 0x02
+#define ACM_CTRL_RI  0x08
+#define ACM_CTRL_DCD 0x01
+
+#define WRITE_SIZE 2048
+
+#define MUX_TX_MAX_SIZE 2048
+
+#define gdm_tty_send(n, d, l, i, c, b) (\
+	n->tty_dev->send_func(n->tty_dev->priv_dev, d, l, i, c, b))
+#define gdm_tty_recv(n, c) (\
+	n->tty_dev->recv_func(n->tty_dev->priv_dev, c))
+#define gdm_tty_send_control(n, r, v, d, l) (\
+	n->tty_dev->send_control(n->tty_dev->priv_dev, r, v, d, l))
+
+#define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count)
+
+static struct tty_driver *gdm_driver[TTY_MAX_COUNT];
+static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR];
+static DEFINE_MUTEX(gdm_table_lock);
+
+static char *DRIVER_STRING[TTY_MAX_COUNT] = {"GCTATC", "GCTDM"};
+static char *DEVICE_STRING[TTY_MAX_COUNT] = {"GCT-ATC", "GCT-DM"};
+
+static void gdm_port_destruct(struct tty_port *port)
+{
+	struct gdm *gdm = container_of(port, struct gdm, port);
+
+	mutex_lock(&gdm_table_lock);
+	gdm_table[gdm->index][gdm->minor] = NULL;
+	mutex_unlock(&gdm_table_lock);
+
+	kfree(gdm);
+}
+
+static struct tty_port_operations gdm_port_ops = {
+	.destruct = gdm_port_destruct,
+};
+
+static int gdm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+	struct gdm *gdm = NULL;
+	int ret;
+	int i;
+	int j;
+
+	j = GDM_TTY_MINOR;
+	for (i = 0; i < TTY_MAX_COUNT; i++) {
+		if (!strcmp(tty->driver->driver_name, DRIVER_STRING[i])) {
+			j = tty->index;
+			break;
+		}
+	}
+
+	if (j == GDM_TTY_MINOR)
+		return -ENODEV;
+
+	mutex_lock(&gdm_table_lock);
+	gdm = gdm_table[i][j];
+	if (gdm == NULL) {
+		mutex_unlock(&gdm_table_lock);
+		return -ENODEV;
+	}
+
+	tty_port_get(&gdm->port);
+
+	ret = tty_standard_install(driver, tty);
+	if (ret) {
+		tty_port_put(&gdm->port);
+		mutex_unlock(&gdm_table_lock);
+		return ret;
+	}
+
+	tty->driver_data = gdm;
+	mutex_unlock(&gdm_table_lock);
+
+	return 0;
+}
+
+static int gdm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	struct gdm *gdm = tty->driver_data;
+	return tty_port_open(&gdm->port, tty, filp);
+}
+
+static void gdm_tty_cleanup(struct tty_struct *tty)
+{
+	struct gdm *gdm = tty->driver_data;
+	tty_port_put(&gdm->port);
+}
+
+static void gdm_tty_hangup(struct tty_struct *tty)
+{
+	struct gdm *gdm = tty->driver_data;
+	tty_port_hangup(&gdm->port);
+}
+
+static void gdm_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	struct gdm *gdm = tty->driver_data;
+	tty_port_close(&gdm->port, tty, filp);
+}
+
+static int gdm_tty_recv_complete(void *data,
+				 int len,
+				 int index,
+				 struct tty_dev *tty_dev,
+				 int complete)
+{
+	struct gdm *gdm = tty_dev->gdm[index];
+	if (!GDM_TTY_READY(gdm)) {
+		if (complete == RECV_PACKET_PROCESS_COMPLETE)
+			gdm_tty_recv(gdm, gdm_tty_recv_complete);
+		return TO_HOST_PORT_CLOSE;
+	}
+
+	if (data && len) {
+		if (tty_buffer_request_room(&gdm->port, len) == len) {
+			tty_insert_flip_string(&gdm->port, data, len);
+			tty_flip_buffer_push(&gdm->port);
+		} else {
+			return TO_HOST_BUFFER_REQUEST_FAIL;
+		}
+	}
+
+	if (complete == RECV_PACKET_PROCESS_COMPLETE)
+		gdm_tty_recv(gdm, gdm_tty_recv_complete);
+
+	return 0;
+}
+
+static void gdm_tty_send_complete(void *arg)
+{
+	struct gdm *gdm = (struct gdm *)arg;
+
+	if (!GDM_TTY_READY(gdm))
+		return;
+
+	tty_port_tty_wakeup(&gdm->port);
+}
+
+static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, int len)
+{
+	struct gdm *gdm = tty->driver_data;
+	int remain = len;
+	int sent_len = 0;
+	int sending_len = 0;
+
+	if (!GDM_TTY_READY(gdm))
+		return -ENODEV;
+
+	if (!len)
+		return 0;
+
+	while (1) {
+		sending_len = remain > MUX_TX_MAX_SIZE ? MUX_TX_MAX_SIZE : remain;
+		gdm_tty_send(gdm,
+			     (void *)(buf+sent_len),
+			     sending_len,
+			     gdm->index,
+			     gdm_tty_send_complete,
+			     gdm
+			    );
+		sent_len += sending_len;
+		remain -= sending_len;
+		if (remain <= 0)
+			break;
+	}
+
+	return len;
+}
+
+static int gdm_tty_write_room(struct tty_struct *tty)
+{
+	struct gdm *gdm = tty->driver_data;
+
+	if (!GDM_TTY_READY(gdm))
+		return -ENODEV;
+
+	return WRITE_SIZE;
+}
+
+int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device)
+{
+	struct gdm *gdm;
+	int i;
+	int j;
+
+	for (i = 0; i < TTY_MAX_COUNT; i++) {
+
+		gdm = kmalloc(sizeof(struct gdm), GFP_KERNEL);
+		if (!gdm)
+			return -ENOMEM;
+
+		mutex_lock(&gdm_table_lock);
+		for (j = 0; j < GDM_TTY_MINOR; j++) {
+			if (!gdm_table[i][j])
+				break;
+		}
+
+		if (j == GDM_TTY_MINOR) {
+			kfree(gdm);
+			mutex_unlock(&gdm_table_lock);
+			return -EINVAL;
+		}
+
+		gdm_table[i][j] = gdm;
+		mutex_unlock(&gdm_table_lock);
+
+		tty_dev->gdm[i] = gdm;
+		tty_port_init(&gdm->port);
+
+		gdm->port.ops = &gdm_port_ops;
+		gdm->index = i;
+		gdm->minor = j;
+		gdm->tty_dev = tty_dev;
+
+		tty_port_register_device(&gdm->port, gdm_driver[i], gdm->minor, device);
+	}
+
+	for (i = 0; i < MAX_ISSUE_NUM; i++)
+		gdm_tty_recv(gdm, gdm_tty_recv_complete);
+
+	return 0;
+}
+
+void unregister_lte_tty_device(struct tty_dev *tty_dev)
+{
+	struct gdm *gdm;
+	struct tty_struct *tty;
+	int i;
+
+	for (i = 0; i < TTY_MAX_COUNT; i++) {
+		gdm = tty_dev->gdm[i];
+		if (!gdm)
+			continue;
+
+		mutex_lock(&gdm_table_lock);
+		gdm_table[gdm->index][gdm->minor] = NULL;
+		mutex_unlock(&gdm_table_lock);
+
+		tty = tty_port_tty_get(&gdm->port);
+		if (tty) {
+			tty_vhangup(tty);
+			tty_kref_put(tty);
+		}
+
+		tty_unregister_device(gdm_driver[i], gdm->minor);
+		tty_port_put(&gdm->port);
+	}
+}
+
+static const struct tty_operations gdm_tty_ops = {
+	.install =	gdm_tty_install,
+	.open =		gdm_tty_open,
+	.close =	gdm_tty_close,
+	.cleanup =	gdm_tty_cleanup,
+	.hangup =	gdm_tty_hangup,
+	.write =	gdm_tty_write,
+	.write_room =	gdm_tty_write_room,
+};
+
+int register_lte_tty_driver(void)
+{
+	struct tty_driver *tty_driver;
+	int i;
+	int ret;
+
+	for (i = 0; i < TTY_MAX_COUNT; i++) {
+		tty_driver = alloc_tty_driver(GDM_TTY_MINOR);
+		if (!tty_driver)
+			return -ENOMEM;
+
+		tty_driver->owner = THIS_MODULE;
+		tty_driver->driver_name = DRIVER_STRING[i];
+		tty_driver->name = DEVICE_STRING[i];
+		tty_driver->major = GDM_TTY_MAJOR;
+		tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+		tty_driver->subtype = SERIAL_TYPE_NORMAL;
+		tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+		tty_driver->init_termios = tty_std_termios;
+		tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL;
+		tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN;
+		tty_set_operations(tty_driver, &gdm_tty_ops);
+
+		ret = tty_register_driver(tty_driver);
+		if (ret) {
+			put_tty_driver(tty_driver);
+			return ret;
+		}
+
+		gdm_driver[i] = tty_driver;
+	}
+
+	return ret;
+}
+
+void unregister_lte_tty_driver(void)
+{
+	struct tty_driver *tty_driver;
+	int i;
+
+	for (i = 0; i < TTY_MAX_COUNT; i++) {
+		tty_driver = gdm_driver[i];
+		if (tty_driver) {
+			tty_unregister_driver(tty_driver);
+			put_tty_driver(tty_driver);
+		}
+	}
+}
+
diff --git a/drivers/staging/gdm724x/gdm_tty.h b/drivers/staging/gdm724x/gdm_tty.h
new file mode 100644
index 0000000..297438b
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_tty.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _GDM_TTY_H_
+#define _GDM_TTY_H_
+
+#include <linux/types.h>
+#include <linux/tty.h>
+
+
+#define TTY_MAX_COUNT		2
+
+#define MAX_ISSUE_NUM 3
+
+enum TO_HOST_RESULT {
+	TO_HOST_BUFFER_REQUEST_FAIL = 1,
+	TO_HOST_PORT_CLOSE = 2,
+	TO_HOST_INVALID_PACKET = 3,
+};
+
+enum RECV_PACKET_PROCESS {
+	RECV_PACKET_PROCESS_COMPLETE = 0,
+	RECV_PACKET_PROCESS_CONTINUE = 1,
+};
+
+struct gdm {
+	struct tty_dev *tty_dev;
+	struct tty_port port;
+	unsigned int index;
+	unsigned int minor;
+};
+
+struct tty_dev {
+	void *priv_dev;
+	int (*send_func)(void *priv_dev,
+			 void *data,
+			 int len,
+			 int tty_index,
+			 void (*cb)(void *cb_data),
+			 void *cb_data);
+	int (*recv_func)(void *priv_dev,
+			 int (*cb)(void *data,
+				   int len,
+				   int tty_index,
+				   struct tty_dev *tty_dev,
+				   int complete));
+	int (*send_control)(void *priv_dev,
+			    int request,
+			    int value,
+			    void *data,
+			    int len);
+	struct gdm *gdm[2];
+};
+
+int register_lte_tty_driver(void);
+void unregister_lte_tty_driver(void);
+int register_lte_tty_device(struct tty_dev *tty_dev, struct device *dev);
+void unregister_lte_tty_device(struct tty_dev *tty_dev);
+
+#endif /* _GDM_USB_H_ */
+
diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c
new file mode 100644
index 0000000..bdc9637
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_usb.c
@@ -0,0 +1,1049 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/usb/cdc.h>
+#include <linux/wait.h>
+#include <linux/if_ether.h>
+#include <linux/pm_runtime.h>
+
+#include "gdm_usb.h"
+#include "gdm_lte.h"
+#include "hci.h"
+#include "hci_packet.h"
+#include "gdm_endian.h"
+
+#define USB_DEVICE_CDC_DATA(vid, pid) \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS,\
+	.idVendor = vid,\
+	.idProduct = pid,\
+	.bInterfaceClass = USB_CLASS_COMM,\
+	.bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET
+
+#define USB_DEVICE_MASS_DATA(vid, pid) \
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,\
+	.idVendor = vid,\
+	.idProduct = pid,\
+	.bInterfaceSubClass = USB_SC_SCSI, \
+	.bInterfaceClass = USB_CLASS_MASS_STORAGE,\
+	.bInterfaceProtocol = USB_PR_BULK
+
+static const struct usb_device_id id_table[] = {
+	{ USB_DEVICE_CDC_DATA(VID_GCT, PID_GDM7240) }, /* GCT GDM7240 */
+	{ USB_DEVICE_CDC_DATA(VID_GCT, PID_GDM7243) }, /* GCT GDM7243 */
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct workqueue_struct *usb_tx_wq;
+static struct workqueue_struct *usb_rx_wq;
+
+static void do_tx(struct work_struct *work);
+static void do_rx(struct work_struct *work);
+
+static int gdm_usb_recv(void *priv_dev,
+			int (*cb)(void *cb_data, void *data, int len, int context),
+			void *cb_data,
+			int context);
+
+static int request_mac_address(struct lte_udev *udev)
+{
+	u8 buf[16] = {0,};
+	struct hci_packet *hci = (struct hci_packet *)buf;
+	struct usb_device *usbdev = udev->usbdev;
+	int actual;
+	int ret = -1;
+
+	hci->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_GET_INFORMATION);
+	hci->len = gdm_cpu_to_dev16(&udev->gdm_ed, 1);
+	hci->data[0] = MAC_ADDRESS;
+
+	ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), buf, 5,
+		     &actual, 1000);
+
+	udev->request_mac_addr = 1;
+
+	return ret;
+}
+
+static struct usb_tx *alloc_tx_struct(int len)
+{
+	struct usb_tx *t = NULL;
+	int ret = 0;
+
+	t = kmalloc(sizeof(struct usb_tx), GFP_ATOMIC);
+	if (!t) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	memset(t, 0, sizeof(struct usb_tx));
+
+	t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!(len % 512))
+		len++;
+
+	t->buf = kmalloc(len, GFP_ATOMIC);
+	if (!t->urb || !t->buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+out:
+	if (ret < 0) {
+		if (t) {
+			usb_free_urb(t->urb);
+			kfree(t->buf);
+			kfree(t);
+		}
+		return NULL;
+	}
+
+	return t;
+}
+
+static struct usb_tx_sdu *alloc_tx_sdu_struct(void)
+{
+	struct usb_tx_sdu *t_sdu = NULL;
+	int ret = 0;
+
+
+	t_sdu = kmalloc(sizeof(struct usb_tx_sdu), GFP_ATOMIC);
+	if (!t_sdu) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	memset(t_sdu, 0, sizeof(struct usb_tx_sdu));
+
+	t_sdu->buf = kmalloc(SDU_BUF_SIZE, GFP_ATOMIC);
+	if (!t_sdu->buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+out:
+
+	if (ret < 0) {
+		if (t_sdu) {
+			kfree(t_sdu->buf);
+			kfree(t_sdu);
+		}
+		return NULL;
+	}
+
+	return t_sdu;
+}
+
+static void free_tx_struct(struct usb_tx *t)
+{
+	if (t) {
+		usb_free_urb(t->urb);
+		kfree(t->buf);
+		kfree(t);
+	}
+}
+
+static void free_tx_sdu_struct(struct usb_tx_sdu *t_sdu)
+{
+	if (t_sdu) {
+		kfree(t_sdu->buf);
+		kfree(t_sdu);
+	}
+}
+
+static struct usb_tx_sdu *get_tx_sdu_struct(struct tx_cxt *tx, int *no_spc)
+{
+	struct usb_tx_sdu *t_sdu;
+
+	if (list_empty(&tx->free_list))
+		return NULL;
+
+	t_sdu = list_entry(tx->free_list.next, struct usb_tx_sdu, list);
+	list_del(&t_sdu->list);
+
+	tx->avail_count--;
+
+	*no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+	return t_sdu;
+}
+
+static void put_tx_struct(struct tx_cxt *tx, struct usb_tx_sdu *t_sdu)
+{
+	list_add_tail(&t_sdu->list, &tx->free_list);
+	tx->avail_count++;
+}
+
+static struct usb_rx *alloc_rx_struct(void)
+{
+	struct usb_rx *r = NULL;
+	int ret = 0;
+
+	r = kmalloc(sizeof(struct usb_rx), GFP_ATOMIC);
+	if (!r) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+	r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
+	if (!r->urb || !r->buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+out:
+
+	if (ret < 0) {
+		if (r) {
+			usb_free_urb(r->urb);
+			kfree(r->buf);
+			kfree(r);
+		}
+		return NULL;
+	}
+
+	return r;
+}
+
+static void free_rx_struct(struct usb_rx *r)
+{
+	if (r) {
+		usb_free_urb(r->urb);
+		kfree(r->buf);
+		kfree(r);
+	}
+}
+
+static struct usb_rx *get_rx_struct(struct rx_cxt *rx, int *no_spc)
+{
+	struct usb_rx *r;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rx->rx_lock, flags);
+
+	if (list_empty(&rx->free_list)) {
+		spin_unlock_irqrestore(&rx->rx_lock, flags);
+		return NULL;
+	}
+
+	r = list_entry(rx->free_list.next, struct usb_rx, free_list);
+	list_del(&r->free_list);
+
+	rx->avail_count--;
+
+	*no_spc = list_empty(&rx->free_list) ? 1 : 0;
+
+	spin_unlock_irqrestore(&rx->rx_lock, flags);
+
+	return r;
+}
+
+static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rx->rx_lock, flags);
+
+	list_add_tail(&r->free_list, &rx->free_list);
+	rx->avail_count++;
+
+	spin_unlock_irqrestore(&rx->rx_lock, flags);
+}
+
+static void release_usb(struct lte_udev *udev)
+{
+	struct rx_cxt	*rx = &udev->rx;
+	struct tx_cxt	*tx = &udev->tx;
+	struct usb_tx	*t, *t_next;
+	struct usb_rx	*r, *r_next;
+	struct usb_tx_sdu	*t_sdu, *t_sdu_next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	list_for_each_entry_safe(t_sdu, t_sdu_next, &tx->sdu_list, list)
+	{
+		list_del(&t_sdu->list);
+		free_tx_sdu_struct(t_sdu);
+	}
+
+	list_for_each_entry_safe(t, t_next, &tx->hci_list, list)
+	{
+		list_del(&t->list);
+		free_tx_struct(t);
+	}
+
+	list_for_each_entry_safe(t_sdu, t_sdu_next, &tx->free_list, list)
+	{
+		list_del(&t_sdu->list);
+		free_tx_sdu_struct(t_sdu);
+	}
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	spin_lock_irqsave(&rx->submit_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list)
+	{
+		spin_unlock_irqrestore(&rx->submit_lock, flags);
+		usb_kill_urb(r->urb);
+		spin_lock_irqsave(&rx->submit_lock, flags);
+	}
+	spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+	spin_lock_irqsave(&rx->rx_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->free_list, free_list)
+	{
+		list_del(&r->free_list);
+		free_rx_struct(r);
+	}
+	spin_unlock_irqrestore(&rx->rx_lock, flags);
+
+	spin_lock_irqsave(&rx->to_host_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list)
+	{
+		if (r->index == (void *)udev) {
+			list_del(&r->to_host_list);
+			free_rx_struct(r);
+		}
+	}
+	spin_unlock_irqrestore(&rx->to_host_lock, flags);
+}
+
+static int init_usb(struct lte_udev *udev)
+{
+	int ret = 0;
+	int i;
+	struct tx_cxt *tx = &udev->tx;
+	struct rx_cxt *rx = &udev->rx;
+	struct usb_tx_sdu *t_sdu = NULL;
+	struct usb_rx *r = NULL;
+
+	udev->send_complete = 1;
+	udev->tx_stop = 0;
+	udev->request_mac_addr = 0;
+	udev->usb_state = PM_NORMAL;
+
+	INIT_LIST_HEAD(&tx->sdu_list);
+	INIT_LIST_HEAD(&tx->hci_list);
+	INIT_LIST_HEAD(&tx->free_list);
+	INIT_LIST_HEAD(&rx->rx_submit_list);
+	INIT_LIST_HEAD(&rx->free_list);
+	INIT_LIST_HEAD(&rx->to_host_list);
+	spin_lock_init(&tx->lock);
+	spin_lock_init(&rx->rx_lock);
+	spin_lock_init(&rx->submit_lock);
+	spin_lock_init(&rx->to_host_lock);
+
+	tx->avail_count = 0;
+	rx->avail_count = 0;
+
+	udev->rx_cb = NULL;
+
+	for (i = 0; i < MAX_NUM_SDU_BUF; i++) {
+		t_sdu = alloc_tx_sdu_struct();
+		if (t_sdu == NULL) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		list_add(&t_sdu->list, &tx->free_list);
+		tx->avail_count++;
+	}
+
+	for (i = 0; i < MAX_RX_SUBMIT_COUNT*2; i++) {
+		r = alloc_rx_struct();
+		if (r == NULL) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		list_add(&r->free_list, &rx->free_list);
+		rx->avail_count++;
+	}
+	INIT_DELAYED_WORK(&udev->work_tx, do_tx);
+	INIT_DELAYED_WORK(&udev->work_rx, do_rx);
+	return 0;
+fail:
+	return ret;
+}
+
+static int set_mac_address(u8 *data, void *arg)
+{
+	struct phy_dev *phy_dev = (struct phy_dev *)arg;
+	struct lte_udev *udev = phy_dev->priv_dev;
+	struct tlv *tlv = (struct tlv *)data;
+	u8 mac_address[ETH_ALEN] = {0, };
+
+	if (tlv->type == MAC_ADDRESS && udev->request_mac_addr) {
+		memcpy(mac_address, tlv->data, tlv->len);
+
+		if (register_lte_device(phy_dev, &udev->intf->dev, mac_address) < 0)
+			pr_err("register lte device failed\n");
+
+		udev->request_mac_addr = 0;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static void do_rx(struct work_struct *work)
+{
+	struct lte_udev *udev = container_of(work, struct lte_udev, work_rx.work);
+	struct rx_cxt *rx = &udev->rx;
+	struct usb_rx *r;
+	struct hci_packet *hci;
+	struct phy_dev *phy_dev;
+	u16 cmd_evt;
+	int ret;
+	unsigned long flags;
+
+	while (1) {
+		spin_lock_irqsave(&rx->to_host_lock, flags);
+		if (list_empty(&rx->to_host_list)) {
+			spin_unlock_irqrestore(&rx->to_host_lock, flags);
+			break;
+		}
+		r = list_entry(rx->to_host_list.next, struct usb_rx, to_host_list);
+		list_del(&r->to_host_list);
+		spin_unlock_irqrestore(&rx->to_host_lock, flags);
+
+		phy_dev = (struct phy_dev *)r->cb_data;
+		udev = (struct lte_udev *)phy_dev->priv_dev;
+		hci = (struct hci_packet *)r->buf;
+		cmd_evt = gdm_dev16_to_cpu(&udev->gdm_ed, hci->cmd_evt);
+
+		switch (cmd_evt) {
+		case LTE_GET_INFORMATION_RESULT:
+			if (set_mac_address(hci->data, r->cb_data) == 0) {
+				ret = r->callback(r->cb_data,
+						  r->buf,
+						  r->urb->actual_length,
+						  KERNEL_THREAD);
+			}
+			break;
+
+		default:
+			if (r->callback) {
+				ret = r->callback(r->cb_data,
+						  r->buf,
+						  r->urb->actual_length,
+						  KERNEL_THREAD);
+
+				if (ret == -EAGAIN)
+					pr_err("failed to send received data\n");
+			}
+			break;
+		}
+
+		put_rx_struct(rx, r);
+
+		gdm_usb_recv(udev,
+			     r->callback,
+			     r->cb_data,
+			     USB_COMPLETE);
+	}
+}
+
+static void remove_rx_submit_list(struct usb_rx *r, struct rx_cxt *rx)
+{
+	unsigned long flags;
+	struct usb_rx	*r_remove, *r_remove_next;
+
+	spin_lock_irqsave(&rx->submit_lock, flags);
+	list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, rx_submit_list)
+	{
+		if (r == r_remove) {
+			list_del(&r->rx_submit_list);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&rx->submit_lock, flags);
+}
+
+static void gdm_usb_rcv_complete(struct urb *urb)
+{
+	struct usb_rx *r = urb->context;
+	struct rx_cxt *rx = r->rx;
+	unsigned long flags;
+	struct lte_udev *udev = container_of(r->rx, struct lte_udev, rx);
+	struct usb_device *usbdev = udev->usbdev;
+
+	remove_rx_submit_list(r, rx);
+
+	if (!urb->status && r->callback) {
+		spin_lock_irqsave(&rx->to_host_lock, flags);
+		list_add_tail(&r->to_host_list, &rx->to_host_list);
+		queue_work(usb_rx_wq, &udev->work_rx.work);
+		spin_unlock_irqrestore(&rx->to_host_lock, flags);
+	} else {
+		if (urb->status && udev->usb_state == PM_NORMAL)
+			pr_err("%s: urb status error %d\n",
+			       __func__, urb->status);
+
+		put_rx_struct(rx, r);
+	}
+
+	usb_mark_last_busy(usbdev);
+}
+
+static int gdm_usb_recv(void *priv_dev,
+			int (*cb)(void *cb_data, void *data, int len, int context),
+			void *cb_data,
+			int context)
+{
+	struct lte_udev *udev = priv_dev;
+	struct usb_device *usbdev = udev->usbdev;
+	struct rx_cxt *rx = &udev->rx;
+	struct usb_rx *r;
+	int no_spc;
+	int ret;
+	unsigned long flags;
+
+	if (!udev->usbdev) {
+		pr_err("invalid device\n");
+		return -ENODEV;
+	}
+
+	r = get_rx_struct(rx, &no_spc);
+	if (!r) {
+		pr_err("Out of Memory\n");
+		return -ENOMEM;
+	}
+
+	udev->rx_cb = cb;
+	r->callback = cb;
+	r->cb_data = cb_data;
+	r->index = (void *)udev;
+	r->rx = rx;
+
+	usb_fill_bulk_urb(r->urb,
+			  usbdev,
+			  usb_rcvbulkpipe(usbdev, 0x83),
+			  r->buf,
+			  RX_BUF_SIZE,
+			  gdm_usb_rcv_complete,
+			  r);
+
+	spin_lock_irqsave(&rx->submit_lock, flags);
+	list_add_tail(&r->rx_submit_list, &rx->rx_submit_list);
+	spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+	if (context == KERNEL_THREAD)
+		ret = usb_submit_urb(r->urb, GFP_KERNEL);
+	else
+		ret = usb_submit_urb(r->urb, GFP_ATOMIC);
+
+	if (ret) {
+		spin_lock_irqsave(&rx->submit_lock, flags);
+		list_del(&r->rx_submit_list);
+		spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+		pr_err("usb_submit_urb failed (%p)\n", r);
+		put_rx_struct(rx, r);
+	}
+
+	return ret;
+}
+
+static void gdm_usb_send_complete(struct urb *urb)
+{
+	struct usb_tx *t = urb->context;
+	struct tx_cxt *tx = t->tx;
+	struct lte_udev *udev = container_of(tx, struct lte_udev, tx);
+	unsigned long flags;
+
+	if (urb->status == -ECONNRESET) {
+		pr_info("CONNRESET\n");
+		return;
+	}
+
+	if (t->callback)
+		t->callback(t->cb_data);
+
+	free_tx_struct(t);
+
+	spin_lock_irqsave(&tx->lock, flags);
+	udev->send_complete = 1;
+	queue_work(usb_tx_wq, &udev->work_tx.work);
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static int send_tx_packet(struct usb_device *usbdev, struct usb_tx *t, u32 len)
+{
+	int ret = 0;
+
+	if (!(len%512))
+		len++;
+
+	usb_fill_bulk_urb(t->urb,
+			  usbdev,
+			  usb_sndbulkpipe(usbdev, 2),
+			  t->buf,
+			  len,
+			  gdm_usb_send_complete,
+			  t);
+
+	ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+	if (ret)
+		pr_err("usb_submit_urb failed: %d\n", ret);
+
+	usb_mark_last_busy(usbdev);
+
+	return ret;
+}
+
+static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf)
+{
+	struct tx_cxt *tx = &udev->tx;
+	struct usb_tx_sdu *t_sdu = NULL;
+	struct multi_sdu *multi_sdu = (struct multi_sdu *)send_buf;
+	u16 send_len = 0;
+	u16 num_packet = 0;
+	unsigned long flags;
+
+	multi_sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_MULTI_SDU);
+
+	while (num_packet < MAX_PACKET_IN_MULTI_SDU) {
+		spin_lock_irqsave(&tx->lock, flags);
+		if (list_empty(&tx->sdu_list)) {
+			spin_unlock_irqrestore(&tx->lock, flags);
+			break;
+		}
+
+		t_sdu = list_entry(tx->sdu_list.next, struct usb_tx_sdu, list);
+		if (send_len + t_sdu->len > MAX_SDU_SIZE) {
+			spin_unlock_irqrestore(&tx->lock, flags);
+			break;
+		}
+
+		list_del(&t_sdu->list);
+		spin_unlock_irqrestore(&tx->lock, flags);
+
+		memcpy(multi_sdu->data + send_len, t_sdu->buf, t_sdu->len);
+
+		send_len += (t_sdu->len + 3) & 0xfffc;
+		num_packet++;
+
+		if (tx->avail_count > 10)
+			t_sdu->callback(t_sdu->cb_data);
+
+		spin_lock_irqsave(&tx->lock, flags);
+		put_tx_struct(tx, t_sdu);
+		spin_unlock_irqrestore(&tx->lock, flags);
+	}
+
+	multi_sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len);
+	multi_sdu->num_packet = gdm_cpu_to_dev16(&udev->gdm_ed, num_packet);
+
+	return send_len + offsetof(struct multi_sdu, data);
+}
+
+static void do_tx(struct work_struct *work)
+{
+	struct lte_udev *udev = container_of(work, struct lte_udev, work_tx.work);
+	struct usb_device *usbdev = udev->usbdev;
+	struct tx_cxt *tx = &udev->tx;
+	struct usb_tx *t = NULL;
+	int is_send = 0;
+	u32 len = 0;
+	unsigned long flags;
+
+	if (!usb_autopm_get_interface(udev->intf))
+		usb_autopm_put_interface(udev->intf);
+
+	if (udev->usb_state == PM_SUSPEND)
+		return;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	if (!udev->send_complete) {
+		spin_unlock_irqrestore(&tx->lock, flags);
+		return;
+	} else {
+		udev->send_complete = 0;
+	}
+
+	if (!list_empty(&tx->hci_list)) {
+		t = list_entry(tx->hci_list.next, struct usb_tx, list);
+		list_del(&t->list);
+		len = t->len;
+		t->is_sdu = 0;
+		is_send = 1;
+	} else if (!list_empty(&tx->sdu_list)) {
+		if (udev->tx_stop) {
+			udev->send_complete = 1;
+			spin_unlock_irqrestore(&tx->lock, flags);
+			return;
+		}
+
+		t = alloc_tx_struct(TX_BUF_SIZE);
+		t->callback = NULL;
+		t->tx = tx;
+		t->is_sdu = 1;
+		is_send = 1;
+	}
+
+	if (!is_send) {
+		udev->send_complete = 1;
+		spin_unlock_irqrestore(&tx->lock, flags);
+		return;
+	}
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (t->is_sdu)
+		len = packet_aggregation(udev, t->buf);
+
+	if (send_tx_packet(usbdev, t, len)) {
+		pr_err("send_tx_packet failed\n");
+		t->callback = NULL;
+		gdm_usb_send_complete(t->urb);
+	}
+}
+
+#define SDU_PARAM_LEN 12
+static int gdm_usb_sdu_send(void *priv_dev, void *data, int len,
+				unsigned int dftEpsId, unsigned int epsId,
+				void (*cb)(void *data), void *cb_data,
+			    int dev_idx, int nic_type)
+{
+	struct lte_udev *udev = priv_dev;
+	struct tx_cxt *tx = &udev->tx;
+	struct usb_tx_sdu *t_sdu;
+	struct sdu *sdu = NULL;
+	unsigned long flags;
+	int no_spc = 0;
+	u16 send_len;
+
+	if (!udev->usbdev) {
+		pr_err("sdu send - invalid device\n");
+		return TX_NO_DEV;
+	}
+
+	spin_lock_irqsave(&tx->lock, flags);
+	t_sdu = get_tx_sdu_struct(tx, &no_spc);
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (t_sdu == NULL) {
+		pr_err("sdu send - free list empty\n");
+		return TX_NO_SPC;
+	}
+
+	sdu = (struct sdu *)t_sdu->buf;
+	sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_SDU);
+	if (nic_type == NIC_TYPE_ARP) {
+		send_len = len + SDU_PARAM_LEN;
+	    memcpy(sdu->data, data, len);
+	} else {
+	    send_len = len - ETH_HLEN;
+	    send_len += SDU_PARAM_LEN;
+	    memcpy(sdu->data, data+ETH_HLEN, len-ETH_HLEN);
+	}
+
+	sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len);
+	sdu->dftEpsId = gdm_cpu_to_dev32(&udev->gdm_ed, dftEpsId);
+	sdu->bearer_ID = gdm_cpu_to_dev32(&udev->gdm_ed, epsId);
+	sdu->nic_type = gdm_cpu_to_dev32(&udev->gdm_ed, nic_type);
+
+	t_sdu->len = send_len + HCI_HEADER_SIZE;
+	t_sdu->callback = cb;
+	t_sdu->cb_data = cb_data;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	list_add_tail(&t_sdu->list, &tx->sdu_list);
+	queue_work(usb_tx_wq, &udev->work_tx.work);
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	if (no_spc)
+		return TX_NO_BUFFER;
+
+	return 0;
+}
+
+static int gdm_usb_hci_send(void *priv_dev, void *data, int len,
+			void (*cb)(void *data), void *cb_data)
+{
+	struct lte_udev *udev = priv_dev;
+	struct tx_cxt *tx = &udev->tx;
+	struct usb_tx *t;
+	unsigned long flags;
+
+	if (!udev->usbdev) {
+		pr_err("hci send - invalid device\n");
+		return -ENODEV;
+	}
+
+	t = alloc_tx_struct(len);
+	if (t == NULL) {
+		pr_err("hci_send - out of memory\n");
+		return -ENOMEM;
+	}
+
+	memcpy(t->buf, data, len);
+	t->callback = cb;
+	t->cb_data = cb_data;
+	t->len = len;
+	t->tx = tx;
+	t->is_sdu = 0;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	list_add_tail(&t->list, &tx->hci_list);
+	queue_work(usb_tx_wq, &udev->work_tx.work);
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	return 0;
+}
+
+static struct gdm_endian *gdm_usb_get_endian(void *priv_dev)
+{
+	struct lte_udev *udev = priv_dev;
+
+	return &udev->gdm_ed;
+}
+
+static int gdm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+	int ret = 0;
+	struct phy_dev *phy_dev = NULL;
+	struct lte_udev *udev = NULL;
+	u16 idVendor, idProduct;
+	int bInterfaceNumber;
+	struct usb_device *usbdev = interface_to_usbdev(intf);
+
+	bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
+	idVendor = __le16_to_cpu(usbdev->descriptor.idVendor);
+	idProduct = __le16_to_cpu(usbdev->descriptor.idProduct);
+
+	pr_info("net vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct);
+
+	if (bInterfaceNumber > NETWORK_INTERFACE) {
+		pr_info("not a network device\n");
+		return -1;
+	}
+
+	phy_dev = kmalloc(sizeof(struct phy_dev), GFP_ATOMIC);
+	if (!phy_dev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	udev = kmalloc(sizeof(struct lte_udev), GFP_ATOMIC);
+	if (!udev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(phy_dev, 0, sizeof(struct phy_dev));
+	memset(udev, 0, sizeof(struct lte_udev));
+
+	phy_dev->priv_dev = (void *)udev;
+	phy_dev->send_hci_func = gdm_usb_hci_send;
+	phy_dev->send_sdu_func = gdm_usb_sdu_send;
+	phy_dev->rcv_func = gdm_usb_recv;
+	phy_dev->get_endian = gdm_usb_get_endian;
+
+	udev->usbdev = usbdev;
+	ret = init_usb(udev);
+	if (ret < 0) {
+		pr_err("init_usb func failed\n");
+		goto out;
+	}
+	udev->intf = intf;
+
+	intf->needs_remote_wakeup = 1;
+	usb_enable_autosuspend(usbdev);
+	pm_runtime_set_autosuspend_delay(&usbdev->dev, AUTO_SUSPEND_TIMER);
+
+	/* List up hosts with big endians, otherwise, defaults to little endian */
+	if (idProduct == PID_GDM7243)
+		gdm_set_endian(&udev->gdm_ed, ENDIANNESS_BIG);
+	else
+		gdm_set_endian(&udev->gdm_ed, ENDIANNESS_LITTLE);
+
+	ret = request_mac_address(udev);
+	if (ret < 0) {
+		pr_err("request Mac address failed\n");
+		goto out;
+	}
+
+	start_rx_proc(phy_dev);
+out:
+
+	if (ret < 0) {
+		kfree(phy_dev);
+		if (udev) {
+			release_usb(udev);
+			kfree(udev);
+		}
+	}
+
+	usb_get_dev(usbdev);
+	usb_set_intfdata(intf, phy_dev);
+
+	return ret;
+}
+
+static void gdm_usb_disconnect(struct usb_interface *intf)
+{
+	struct phy_dev *phy_dev;
+	struct lte_udev *udev;
+	u16 idVendor, idProduct;
+	struct usb_device *usbdev;
+	usbdev = interface_to_usbdev(intf);
+
+	idVendor = __le16_to_cpu(usbdev->descriptor.idVendor);
+	idProduct = __le16_to_cpu(usbdev->descriptor.idProduct);
+
+	phy_dev = usb_get_intfdata(intf);
+
+	udev = phy_dev->priv_dev;
+	unregister_lte_device(phy_dev);
+
+	release_usb(udev);
+
+	kfree(udev);
+	udev = NULL;
+
+	kfree(phy_dev);
+	phy_dev = NULL;
+
+	usb_put_dev(usbdev);
+}
+
+static int gdm_usb_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+	struct phy_dev *phy_dev;
+	struct lte_udev *udev;
+	struct rx_cxt *rx;
+	struct usb_rx *r;
+	struct usb_rx *r_next;
+	unsigned long flags;
+
+	phy_dev = usb_get_intfdata(intf);
+	udev = phy_dev->priv_dev;
+	rx = &udev->rx;
+	if (udev->usb_state != PM_NORMAL) {
+		pr_err("usb suspend - invalid state\n");
+		return -1;
+	}
+
+	udev->usb_state = PM_SUSPEND;
+
+	spin_lock_irqsave(&rx->submit_lock, flags);
+	list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, rx_submit_list)
+	{
+		spin_unlock_irqrestore(&rx->submit_lock, flags);
+		usb_kill_urb(r->urb);
+		spin_lock_irqsave(&rx->submit_lock, flags);
+	}
+	spin_unlock_irqrestore(&rx->submit_lock, flags);
+
+	return 0;
+}
+
+static int gdm_usb_resume(struct usb_interface *intf)
+{
+	struct phy_dev *phy_dev;
+	struct lte_udev *udev;
+	struct tx_cxt *tx;
+	struct rx_cxt *rx;
+	unsigned long flags;
+	int issue_count;
+	int i;
+
+	phy_dev = usb_get_intfdata(intf);
+	udev = phy_dev->priv_dev;
+	rx = &udev->rx;
+
+	if (udev->usb_state != PM_SUSPEND) {
+		pr_err("usb resume - invalid state\n");
+		return -1;
+	}
+	udev->usb_state = PM_NORMAL;
+
+	spin_lock_irqsave(&rx->rx_lock, flags);
+	issue_count = rx->avail_count - MAX_RX_SUBMIT_COUNT;
+	spin_unlock_irqrestore(&rx->rx_lock, flags);
+
+	if (issue_count >= 0) {
+		for (i = 0; i < issue_count; i++)
+			gdm_usb_recv(phy_dev->priv_dev,
+				     udev->rx_cb,
+				     phy_dev,
+				     USB_COMPLETE);
+	}
+
+	tx = &udev->tx;
+	spin_lock_irqsave(&tx->lock, flags);
+	queue_work(usb_tx_wq, &udev->work_tx.work);
+	spin_unlock_irqrestore(&tx->lock, flags);
+
+	return 0;
+}
+
+static struct usb_driver gdm_usb_lte_driver = {
+	.name = "gdm_lte",
+	.probe = gdm_usb_probe,
+	.disconnect = gdm_usb_disconnect,
+	.id_table = id_table,
+	.supports_autosuspend = 1,
+	.suspend = gdm_usb_suspend,
+	.resume = gdm_usb_resume,
+	.reset_resume = gdm_usb_resume,
+};
+
+static int __init gdm_usb_lte_init(void)
+{
+	if (gdm_lte_event_init() < 0) {
+		pr_err("error creating event\n");
+		return -1;
+	}
+
+	usb_tx_wq = create_workqueue("usb_tx_wq");
+	if (usb_tx_wq == NULL)
+		return -1;
+
+	usb_rx_wq = create_workqueue("usb_rx_wq");
+	if (usb_rx_wq == NULL)
+		return -1;
+
+	return usb_register(&gdm_usb_lte_driver);
+}
+
+static void __exit gdm_usb_lte_exit(void)
+{
+	gdm_lte_event_exit();
+
+	usb_deregister(&gdm_usb_lte_driver);
+
+	if (usb_tx_wq) {
+		flush_workqueue(usb_tx_wq);
+		destroy_workqueue(usb_tx_wq);
+	}
+
+	if (usb_rx_wq) {
+		flush_workqueue(usb_rx_wq);
+		destroy_workqueue(usb_rx_wq);
+	}
+}
+
+module_init(gdm_usb_lte_init);
+module_exit(gdm_usb_lte_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT LTE USB Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm724x/gdm_usb.h b/drivers/staging/gdm724x/gdm_usb.h
new file mode 100644
index 0000000..e6486e7
--- /dev/null
+++ b/drivers/staging/gdm724x/gdm_usb.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _GDM_USB_H_
+#define _GDM_USB_H_
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+#include <linux/time.h>
+
+#include "gdm_endian.h"
+#include "hci_packet.h"
+
+#define PM_NORMAL 0
+#define PM_SUSPEND 1
+#define AUTO_SUSPEND_TIMER 5000 /* ms */
+
+#define RX_BUF_SIZE		(1024*32)
+#define TX_BUF_SIZE		(1024*32)
+#define SDU_BUF_SIZE	2048
+#define MAX_SDU_SIZE	(1024*30)
+#define MAX_PACKET_IN_MULTI_SDU	256
+
+#define VID_GCT			0x1076
+#define PID_GDM7240		0x8000
+#define PID_GDM7243		0x9000
+
+#define NETWORK_INTERFACE 1
+#define USB_SC_SCSI 0x06
+#define USB_PR_BULK 0x50
+
+#define MAX_NUM_SDU_BUF	64
+
+struct usb_tx {
+	struct list_head list;
+	struct urb *urb;
+	u8 *buf;
+	u32 len;
+	void (*callback)(void *cb_data);
+	void *cb_data;
+	struct tx_cxt *tx;
+	u8 is_sdu;
+};
+
+struct usb_tx_sdu {
+	struct list_head list;
+	u8 *buf;
+	u32 len;
+	void (*callback)(void *cb_data);
+	void *cb_data;
+};
+
+struct usb_rx {
+	struct list_head to_host_list;
+	struct list_head free_list;
+	struct list_head rx_submit_list;
+	struct rx_cxt	*rx;
+	struct urb *urb;
+	u8 *buf;
+	int (*callback)(void *cb_data, void *data, int len, int context);
+	void *cb_data;
+	void *index;
+};
+
+struct tx_cxt {
+	struct list_head sdu_list;
+	struct list_head hci_list;
+	struct list_head free_list;
+	u32 avail_count;
+	spinlock_t lock;
+};
+
+struct rx_cxt {
+	struct list_head to_host_list;
+	struct list_head rx_submit_list;
+	struct list_head free_list;
+	u32	avail_count;
+	spinlock_t to_host_lock;
+	spinlock_t rx_lock;
+	spinlock_t submit_lock;
+};
+
+struct lte_udev {
+	struct usb_device *usbdev;
+	struct gdm_endian gdm_ed;
+	struct tx_cxt tx;
+	struct rx_cxt rx;
+	struct delayed_work work_tx;
+	struct delayed_work work_rx;
+	u8 send_complete;
+	u8 tx_stop;
+	struct usb_interface *intf;
+	int (*rx_cb)(void *cb_data, void *data, int len, int context);
+	int usb_state;
+	u8 request_mac_addr;
+};
+
+#endif /* _GDM_USB_H_ */
diff --git a/drivers/staging/gdm724x/hci.h b/drivers/staging/gdm724x/hci.h
new file mode 100644
index 0000000..9a591b0
--- /dev/null
+++ b/drivers/staging/gdm724x/hci.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _HCI_H_
+#define _HCI_H_
+
+#define LTE_GET_INFORMATION		0x3002
+#define LTE_GET_INFORMATION_RESULT	0xB003
+	#define MAC_ADDRESS		0xA2
+
+#define LTE_LINK_ON_OFF_INDICATION	0xB133
+#define LTE_PDN_TABLE_IND		0xB143
+
+#define LTE_TX_SDU			0x3200
+#define LTE_RX_SDU			0xB201
+#define LTE_TX_MULTI_SDU		0x3202
+#define LTE_RX_MULTI_SDU		0xB203
+
+#define LTE_DL_SDU_FLOW_CONTROL		0x3305
+#define LTE_UL_SDU_FLOW_CONTROL		0xB306
+
+#define LTE_AT_CMD_TO_DEVICE		0x3307
+#define LTE_AT_CMD_FROM_DEVICE		0xB308
+
+#define LTE_SDIO_DM_SEND_PKT		0x3312
+#define LTE_SDIO_DM_RECV_PKT		0xB313
+
+#define LTE_NV_RESTORE_REQUEST		0xB30C
+#define LTE_NV_RESTORE_RESPONSE		0x330D
+#define LTE_NV_SAVE_REQUEST		0xB30E
+	#define NV_TYPE_LTE_INFO	0x00
+	#define NV_TYPE_BOARD_CONFIG	0x01
+	#define NV_TYPE_RF_CAL		0x02
+	#define NV_TYPE_TEMP		0x03
+	#define NV_TYPE_NET_INFO	0x04
+	#define NV_TYPE_SAFETY_INFO	0x05
+	#define NV_TYPE_CDMA_CAL	0x06
+	#define NV_TYPE_VENDOR		0x07
+	#define NV_TYPE_ALL		0xff
+#define LTE_NV_SAVE_RESPONSE		0x330F
+
+#define LTE_AT_CMD_TO_DEVICE_EXT	0x3323
+#define LTE_AT_CMD_FROM_DEVICE_EXT	0xB324
+
+#endif /* _HCI_H_ */
diff --git a/drivers/staging/gdm724x/hci_packet.h b/drivers/staging/gdm724x/hci_packet.h
new file mode 100644
index 0000000..7fba8a6
--- /dev/null
+++ b/drivers/staging/gdm724x/hci_packet.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _HCI_PACKET_H_
+#define _HCI_PACKET_H_
+
+#define HCI_HEADER_SIZE 4
+
+/*
+ * The NIC type definition:
+ * For backward compatibility, lower 16 bits used as they were.
+ * Lower 16 bit: NIC_TYPE values
+ * Uppoer 16 bit: NIC_TYPE Flags
+ */
+#define NIC_TYPE_NIC0		0x00000010
+#define NIC_TYPE_NIC1		0x00000011
+#define NIC_TYPE_NIC2		0x00000012
+#define NIC_TYPE_NIC3		0x00000013
+#define NIC_TYPE_ARP		0x00000100
+#define NIC_TYPE_ICMPV6		0x00000200
+#define NIC_TYPE_MASK		0x0000FFFF
+#define NIC_TYPE_F_IPV4		0x00010000
+#define NIC_TYPE_F_IPV6		0x00020000
+#define NIC_TYPE_F_DHCP		0x00040000
+#define NIC_TYPE_F_NDP		0x00080000
+#define NIC_TYPE_F_VLAN		0x00100000
+
+struct hci_packet {
+	u16 cmd_evt;
+	u16 len;
+	u8 data[0];
+} __packed;
+
+struct tlv {
+	u8 type;
+	u8 len;
+	u8 *data[1];
+} __packed;
+
+struct sdu_header {
+	u16 cmd_evt;
+	u16 len;
+	u32 dftEpsId;
+	u32 bearer_ID;
+	u32 nic_type;
+} __packed;
+
+struct sdu {
+	u16 cmd_evt;
+	u16 len;
+	u32 dftEpsId;
+	u32 bearer_ID;
+	u32 nic_type;
+	u8 data[0];
+} __packed;
+
+struct multi_sdu {
+	u16 cmd_evt;
+	u16 len;
+	u16 num_packet;
+	u16 reserved;
+	u8 data[0];
+} __packed;
+
+struct hci_pdn_table_ind {
+	u16 cmd_evt;
+	u16 len;
+	u8 activate;
+	u32 dft_eps_id;
+	u32 nic_type;
+	u8 pdn_type;
+	u8 ipv4_addr[4];
+	u8 ipv6_intf_id[8];
+} __packed;
+
+struct hci_connect_ind {
+	u16 cmd_evt;
+	u16 len;
+	u32 connect;
+} __packed;
+
+
+#endif /* _HCI_PACKET_H_ */
diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c
new file mode 100644
index 0000000..77fc64e
--- /dev/null
+++ b/drivers/staging/gdm724x/netlink_k.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/export.h>
+#include <linux/etherdevice.h>
+#include <linux/netlink.h>
+#include <asm/byteorder.h>
+#include <net/sock.h>
+
+#include "netlink_k.h"
+
+#if defined(DEFINE_MUTEX)
+static DEFINE_MUTEX(netlink_mutex);
+#else
+static struct semaphore netlink_mutex;
+#define mutex_lock(x)		down(x)
+#define mutex_unlock(x)		up(x)
+#endif
+
+#define ND_MAX_GROUP		30
+#define ND_IFINDEX_LEN		sizeof(int)
+#define ND_NLMSG_SPACE(len)	(NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_DATA(nlh)	((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_S_LEN(len)	(len+ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh)	(nlh->nlmsg_len-ND_IFINDEX_LEN)
+#define ND_NLMSG_IFIDX(nlh)	NLMSG_DATA(nlh)
+#define ND_MAX_MSG_LEN		(1024 * 32)
+
+static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
+
+static void netlink_rcv_cb(struct sk_buff *skb)
+{
+	struct nlmsghdr	*nlh;
+	struct net_device *dev;
+	u32 mlen;
+	void *msg;
+	int ifindex;
+
+	if (!rcv_cb) {
+		pr_err("nl cb - unregistered\n");
+		return;
+	}
+
+	if (skb->len < NLMSG_SPACE(0)) {
+		pr_err("nl cb - invalid skb length\n");
+		return;
+	}
+
+	nlh = (struct nlmsghdr *)skb->data;
+
+	if (skb->len < nlh->nlmsg_len || nlh->nlmsg_len > ND_MAX_MSG_LEN) {
+		pr_err("nl cb - invalid length (%d,%d)\n",
+		       skb->len, nlh->nlmsg_len);
+		return;
+	}
+
+	memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
+	msg = ND_NLMSG_DATA(nlh);
+	mlen = ND_NLMSG_R_LEN(nlh);
+
+	dev = dev_get_by_index(&init_net, ifindex);
+	if (dev) {
+		rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
+		dev_put(dev);
+	} else {
+		pr_err("nl cb - dev (%d) not found\n", ifindex);
+	}
+}
+
+static void netlink_rcv(struct sk_buff *skb)
+{
+	mutex_lock(&netlink_mutex);
+	netlink_rcv_cb(skb);
+	mutex_unlock(&netlink_mutex);
+}
+
+struct sock *netlink_init(int unit,
+	void (*cb)(struct net_device *dev, u16 type, void *msg, int len))
+{
+	struct sock *sock;
+	struct netlink_kernel_cfg cfg = {
+		.input  = netlink_rcv,
+	};
+
+#if !defined(DEFINE_MUTEX)
+	init_MUTEX(&netlink_mutex);
+#endif
+
+	sock = netlink_kernel_create(&init_net, unit, &cfg);
+
+	if (sock)
+		rcv_cb = cb;
+
+	return sock;
+}
+
+void netlink_exit(struct sock *sock)
+{
+	sock_release(sock->sk_socket);
+}
+
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
+{
+	static u32 seq;
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh;
+	int ret = 0;
+
+	if (group > ND_MAX_GROUP)
+		return -EINVAL;
+
+	if (!netlink_has_listeners(sock, group+1))
+		return -ESRCH;
+
+	skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	seq++;
+
+	nlh = nlmsg_put(skb, 0, seq, type, len, 0);
+	memcpy(NLMSG_DATA(nlh), msg, len);
+	NETLINK_CB(skb).portid = 0;
+	NETLINK_CB(skb).dst_group = 0;
+
+	ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC);
+	if (!ret)
+		return len;
+
+	if (ret != -ESRCH)
+		pr_err("nl broadcast g=%d, t=%d, l=%d, r=%d\n",
+		       group, type, len, ret);
+	else if (netlink_has_listeners(sock, group+1))
+		return -EAGAIN;
+
+	return ret;
+}
diff --git a/drivers/staging/gdm724x/netlink_k.h b/drivers/staging/gdm724x/netlink_k.h
new file mode 100644
index 0000000..589486d
--- /dev/null
+++ b/drivers/staging/gdm724x/netlink_k.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * 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 _NETLINK_K_H
+#define _NETLINK_K_H
+
+#include <linux/netdevice.h>
+#include <net/sock.h>
+
+struct sock *netlink_init(int unit,
+	void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
+void netlink_exit(struct sock *sock);
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
+
+#endif /* _NETLINK_K_H_ */
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index ea08d62..8be32e5 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -56,7 +56,7 @@
 
 - indio_dev->modes:
 	Specify whether direct access and / or ring buffer access is supported.
-- indio_dev->ring:
+- indio_dev->buffer:
 	An optional associated buffer.
 - indio_dev->pollfunc:
 	Poll function related elements. This controls what occurs when a trigger
@@ -67,7 +67,7 @@
 - indio_dev->num_channels:
 	How many channels are there?
 
-Once these are set up, a call to iio_device_register(indio_dev),
+Once these are set up, a call to iio_device_register(indio_dev)
 will register the device with the iio core.
 
 Worth noting here is that, if a ring buffer is to be used, it can be
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index ab8ec7a..2105576 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -182,11 +182,10 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -201,10 +200,10 @@
 
 	ret = adis_init(st, indio_dev, spi, &adis16201_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 	ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adis_initial_startup(st);
@@ -218,9 +217,6 @@
 
 error_cleanup_buffer_trigger:
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -231,7 +227,6 @@
 
 	iio_device_unregister(indio_dev);
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index b08ac8f..409a28e 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -148,11 +148,9 @@
 	struct adis *st;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -166,11 +164,11 @@
 
 	ret = adis_init(st, indio_dev, spi, &adis16203_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adis_initial_startup(st);
@@ -185,9 +183,6 @@
 
 error_cleanup_buffer_trigger:
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -198,7 +193,6 @@
 
 	iio_device_unregister(indio_dev);
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index 792ec25..b8ea768 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -187,11 +187,9 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -205,11 +203,11 @@
 
 	ret = adis_init(st, indio_dev, spi, &adis16204_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adis_initial_startup(st);
@@ -223,9 +221,6 @@
 
 error_cleanup_buffer_trigger:
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -236,7 +231,6 @@
 
 	iio_device_unregister(indio_dev);
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index 323c169..4492e51 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -183,11 +183,9 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -201,10 +199,10 @@
 
 	ret = adis_init(st, indio_dev, spi, &adis16209_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 	ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adis_initial_startup(st);
@@ -218,9 +216,6 @@
 
 error_cleanup_buffer_trigger:
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -231,7 +226,6 @@
 
 	iio_device_unregister(indio_dev);
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 0e72f79..5c28961 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -428,11 +428,9 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
@@ -447,7 +445,7 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &accel_bin);
 	if (ret)
@@ -478,9 +476,6 @@
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
 error_unregister_dev:
 	iio_device_unregister(indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -492,7 +487,6 @@
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
 	sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index fd1f0fd..3a303a0 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -236,11 +236,9 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -254,10 +252,10 @@
 
 	ret = adis_init(st, indio_dev, spi, &adis16240_data);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 	ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	/* Get the device into a sane initial state */
 	ret = adis_initial_startup(st);
@@ -270,9 +268,6 @@
 
 error_cleanup_buffer_trigger:
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -283,7 +278,6 @@
 
 	iio_device_unregister(indio_dev);
 	adis_cleanup_buffer_and_trigger(st, indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 8ed75a9..bb852dc 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -668,11 +668,9 @@
 	struct lis3l02dq_state *st;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_device_alloc(sizeof *st);
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	st = iio_priv(indio_dev);
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
@@ -690,7 +688,7 @@
 
 	ret = lis3l02dq_configure_buffer(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	ret = iio_buffer_register(indio_dev,
 				  lis3l02dq_channels,
@@ -736,9 +734,6 @@
 	iio_buffer_unregister(indio_dev);
 error_unreg_buffer_funcs:
 	lis3l02dq_unconfigure_buffer(indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
 	return ret;
 }
 
@@ -786,8 +781,6 @@
 	iio_buffer_unregister(indio_dev);
 	lis3l02dq_unconfigure_buffer(indio_dev);
 
-	iio_device_free(indio_dev);
-
 	return 0;
 }
 
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 32950ad..48a25ba 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -1135,11 +1135,9 @@
 	struct sca3000_state *st;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 
 	st = iio_priv(indio_dev);
 	spi_set_drvdata(spi, indio_dev);
@@ -1162,7 +1160,7 @@
 	sca3000_configure_ring(indio_dev);
 	ret = iio_device_register(indio_dev);
 	if (ret < 0)
-		goto error_free_dev;
+		return ret;
 
 	ret = iio_buffer_register(indio_dev,
 				  sca3000_channels,
@@ -1198,10 +1196,6 @@
 	iio_buffer_unregister(indio_dev);
 error_unregister_dev:
 	iio_device_unregister(indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-
-error_ret:
 	return ret;
 }
 
@@ -1235,7 +1229,6 @@
 	iio_device_unregister(indio_dev);
 	iio_buffer_unregister(indio_dev);
 	sca3000_unconfigure_ring(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index 9f52a28..a08c173 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -225,6 +225,9 @@
 #define	LRADC_CTRL4_LRADCSELECT_MASK(n)		(0xf << ((n) * 4))
 #define	LRADC_CTRL4_LRADCSELECT_OFFSET(n)	((n) * 4)
 
+#define LRADC_RESOLUTION			12
+#define LRADC_SINGLE_SAMPLE_MASK		((1 << LRADC_RESOLUTION) - 1)
+
 /*
  * Raw I/O operations
  */
@@ -540,9 +543,10 @@
 	__set_bit(EV_ABS, input->evbit);
 	__set_bit(EV_KEY, input->evbit);
 	__set_bit(BTN_TOUCH, input->keybit);
-	input_set_abs_params(input, ABS_X, 0, LRADC_CH_VALUE_MASK, 0, 0);
-	input_set_abs_params(input, ABS_Y, 0, LRADC_CH_VALUE_MASK, 0, 0);
-	input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_CH_VALUE_MASK, 0, 0);
+	input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK,
+			     0, 0);
 
 	lradc->ts_input = input;
 	input_set_drvdata(input, lradc);
@@ -817,7 +821,7 @@
 	.channel = (idx),					\
 	.scan_type = {						\
 		.sign = 'u',					\
-		.realbits = 18,					\
+		.realbits = LRADC_RESOLUTION,			\
 		.storagebits = 32,				\
 	},							\
 }
@@ -841,14 +845,16 @@
 	MXS_ADC_CHAN(15, IIO_VOLTAGE),	/* VDD5V */
 };
 
-static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
+static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
 {
 	/* The ADC always uses DELAY CHANNEL 0. */
 	const uint32_t adc_cfg =
 		(1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) |
 		(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
 
-	stmp_reset_block(lradc->base);
+	int ret = stmp_reset_block(lradc->base);
+	if (ret)
+		return ret;
 
 	/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
 	writel(adc_cfg, lradc->base + LRADC_DELAY(0));
@@ -869,6 +875,8 @@
 
 	/* Start internal temperature sensing. */
 	writel(0, lradc->base + LRADC_CTRL2);
+
+	return 0;
 }
 
 static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
@@ -905,7 +913,7 @@
 	int i;
 
 	/* Allocate the IIO device. */
-	iio = iio_device_alloc(sizeof(*lradc));
+	iio = devm_iio_device_alloc(dev, sizeof(*lradc));
 	if (!iio) {
 		dev_err(dev, "Failed to allocate IIO device\n");
 		return -ENOMEM;
@@ -917,10 +925,8 @@
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	lradc->dev = &pdev->dev;
 	lradc->base = devm_ioremap_resource(dev, iores);
-	if (IS_ERR(lradc->base)) {
-		ret = PTR_ERR(lradc->base);
-		goto err_addr;
-	}
+	if (IS_ERR(lradc->base))
+		return PTR_ERR(lradc->base);
 
 	INIT_WORK(&lradc->ts_work, mxs_lradc_ts_work);
 
@@ -940,16 +946,14 @@
 	/* Grab all IRQ sources */
 	for (i = 0; i < of_cfg->irq_count; i++) {
 		lradc->irq[i] = platform_get_irq(pdev, i);
-		if (lradc->irq[i] < 0) {
-			ret = -EINVAL;
-			goto err_addr;
-		}
+		if (lradc->irq[i] < 0)
+			return -EINVAL;
 
 		ret = devm_request_irq(dev, lradc->irq[i],
 					mxs_lradc_handle_irq, 0,
 					of_cfg->irq_name[i], iio);
 		if (ret)
-			goto err_addr;
+			return ret;
 	}
 
 	platform_set_drvdata(pdev, iio);
@@ -969,14 +973,16 @@
 				&mxs_lradc_trigger_handler,
 				&mxs_lradc_buffer_ops);
 	if (ret)
-		goto err_addr;
+		return ret;
 
 	ret = mxs_lradc_trigger_init(iio);
 	if (ret)
 		goto err_trig;
 
 	/* Configure the hardware. */
-	mxs_lradc_hw_init(lradc);
+	ret = mxs_lradc_hw_init(lradc);
+	if (ret)
+		goto err_dev;
 
 	/* Register the touchscreen input device. */
 	ret = mxs_lradc_ts_register(lradc);
@@ -998,8 +1004,6 @@
 	mxs_lradc_trigger_remove(iio);
 err_trig:
 	iio_triggered_buffer_cleanup(iio);
-err_addr:
-	iio_device_free(iio);
 	return ret;
 }
 
@@ -1015,7 +1019,6 @@
 	iio_device_unregister(iio);
 	iio_triggered_buffer_cleanup(iio);
 	mxs_lradc_trigger_remove(iio);
-	iio_device_free(iio);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
index 736219c..20f2d55 100644
--- a/drivers/staging/iio/adc/spear_adc.c
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -300,11 +300,10 @@
 	int ret = -ENODEV;
 	int irq;
 
-	iodev = iio_device_alloc(sizeof(struct spear_adc_info));
+	iodev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_info));
 	if (!iodev) {
 		dev_err(dev, "failed allocating iio device\n");
-		ret = -ENOMEM;
-		goto errout1;
+		return -ENOMEM;
 	}
 
 	info = iio_priv(iodev);
@@ -318,8 +317,7 @@
 	info->adc_base_spear6xx = of_iomap(np, 0);
 	if (!info->adc_base_spear6xx) {
 		dev_err(dev, "failed mapping memory\n");
-		ret = -ENOMEM;
-		goto errout2;
+		return -ENOMEM;
 	}
 	info->adc_base_spear3xx =
 		(struct adc_regs_spear3xx *)info->adc_base_spear6xx;
@@ -327,33 +325,33 @@
 	info->clk = clk_get(dev, NULL);
 	if (IS_ERR(info->clk)) {
 		dev_err(dev, "failed getting clock\n");
-		goto errout3;
+		goto errout1;
 	}
 
 	ret = clk_prepare_enable(info->clk);
 	if (ret) {
 		dev_err(dev, "failed enabling clock\n");
-		goto errout4;
+		goto errout2;
 	}
 
 	irq = platform_get_irq(pdev, 0);
 	if ((irq < 0) || (irq >= NR_IRQS)) {
 		dev_err(dev, "failed getting interrupt resource\n");
 		ret = -EINVAL;
-		goto errout5;
+		goto errout3;
 	}
 
 	ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
 	if (ret < 0) {
 		dev_err(dev, "failed requesting interrupt\n");
-		goto errout5;
+		goto errout3;
 	}
 
 	if (of_property_read_u32(np, "sampling-frequency",
 				 &info->sampling_freq)) {
 		dev_err(dev, "sampling-frequency missing in DT\n");
 		ret = -EINVAL;
-		goto errout5;
+		goto errout3;
 	}
 
 	/*
@@ -383,21 +381,18 @@
 
 	ret = iio_device_register(iodev);
 	if (ret)
-		goto errout5;
+		goto errout3;
 
 	dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
 
 	return 0;
 
-errout5:
-	clk_disable_unprepare(info->clk);
-errout4:
-	clk_put(info->clk);
 errout3:
-	iounmap(info->adc_base_spear6xx);
+	clk_disable_unprepare(info->clk);
 errout2:
-	iio_device_free(iodev);
+	clk_put(info->clk);
 errout1:
+	iounmap(info->adc_base_spear6xx);
 	return ret;
 }
 
@@ -410,7 +405,6 @@
 	clk_disable_unprepare(info->clk);
 	clk_put(info->clk);
 	iounmap(info->adc_base_spear6xx);
-	iio_device_free(iodev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 506b5a7..1e13568 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -551,31 +551,6 @@
 		adt7316_store_enable_smbus_timeout,
 		0);
 
-
-static ssize_t adt7316_store_reset(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *dev_info = dev_to_iio_dev(dev);
-	struct adt7316_chip_info *chip = iio_priv(dev_info);
-	u8 config2;
-	int ret;
-
-	config2 = chip->config2 | ADT7316_RESET;
-
-	ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
-	if (ret)
-		return -EIO;
-
-	return len;
-}
-
-static IIO_DEVICE_ATTR(reset, S_IWUSR,
-		NULL,
-		adt7316_store_reset,
-		0);
-
 static ssize_t adt7316_show_powerdown(struct device *dev,
 		struct device_attribute *attr,
 		char *buf)
@@ -1675,7 +1650,6 @@
 static struct attribute *adt7316_attributes[] = {
 	&iio_dev_attr_all_modes.dev_attr.attr,
 	&iio_dev_attr_mode.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_enabled.dev_attr.attr,
 	&iio_dev_attr_ad_channel.dev_attr.attr,
 	&iio_dev_attr_all_ad_channels.dev_attr.attr,
@@ -1719,7 +1693,6 @@
 	&iio_dev_attr_all_modes.dev_attr.attr,
 	&iio_dev_attr_mode.dev_attr.attr,
 	&iio_dev_attr_select_ex_temp.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_enabled.dev_attr.attr,
 	&iio_dev_attr_ad_channel.dev_attr.attr,
 	&iio_dev_attr_all_ad_channels.dev_attr.attr,
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index 687dd2c..f4a0341 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -558,11 +558,9 @@
 	struct ad7150_chip_info *chip;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_device_alloc(sizeof(*chip));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+	if (!indio_dev)
+		return -ENOMEM;
 	chip = iio_priv(indio_dev);
 	mutex_init(&chip->state_lock);
 	/* this is only used for device removal purposes */
@@ -581,7 +579,7 @@
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
 	if (client->irq) {
-		ret = request_threaded_irq(client->irq,
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
 					   NULL,
 					   &ad7150_event_handler,
 					   IRQF_TRIGGER_RISING |
@@ -590,11 +588,11 @@
 					   "ad7150_irq1",
 					   indio_dev);
 		if (ret)
-			goto error_free_dev;
+			return ret;
 	}
 
 	if (client->dev.platform_data) {
-		ret = request_threaded_irq(*(unsigned int *)
+		ret = devm_request_threaded_irq(&client->dev, *(unsigned int *)
 					   client->dev.platform_data,
 					   NULL,
 					   &ad7150_event_handler,
@@ -604,28 +602,17 @@
 					   "ad7150_irq2",
 					   indio_dev);
 		if (ret)
-			goto error_free_irq;
+			return ret;
 	}
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_irq2;
+		return ret;
 
 	dev_info(&client->dev, "%s capacitive sensor registered,irq: %d\n",
 		 id->name, client->irq);
 
 	return 0;
-error_free_irq2:
-	if (client->dev.platform_data)
-		free_irq(*(unsigned int *)client->dev.platform_data,
-			 indio_dev);
-error_free_irq:
-	if (client->irq)
-		free_irq(client->irq, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
 }
 
 static int ad7150_remove(struct i2c_client *client)
@@ -633,13 +620,6 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	if (client->irq)
-		free_irq(client->irq, indio_dev);
-
-	if (client->dev.platform_data)
-		free_irq(*(unsigned int *)client->dev.platform_data, indio_dev);
-
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index 1d7c528..f2c309d 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -481,11 +481,9 @@
 	struct ad7152_chip_info *chip;
 	struct iio_dev *indio_dev;
 
-	indio_dev = iio_device_alloc(sizeof(*chip));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+	if (!indio_dev)
+		return -ENOMEM;
 	chip = iio_priv(indio_dev);
 	/* this is only used for device removal purposes */
 	i2c_set_clientdata(client, indio_dev);
@@ -506,16 +504,11 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	dev_err(&client->dev, "%s capacitive sensor registered\n", id->name);
 
 	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
 }
 
 static int ad7152_remove(struct i2c_client *client)
@@ -523,7 +516,6 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 94f9ca7..75a533b 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -699,11 +699,9 @@
 	int ret = 0;
 	unsigned char regval = 0;
 
-	indio_dev = iio_device_alloc(sizeof(*chip));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+	if (!indio_dev)
+		return -ENOMEM;
 	chip = iio_priv(indio_dev);
 	/* this is only used for device removal purposes */
 	i2c_set_clientdata(client, indio_dev);
@@ -748,20 +746,15 @@
 	ret = i2c_smbus_write_byte_data(chip->client,
 					AD7746_REG_EXC_SETUP, regval);
 	if (ret < 0)
-		goto error_free_dev;
+		return ret;
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	dev_info(&client->dev, "%s capacitive sensor registered\n", id->name);
 
 	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
 }
 
 static int ad7746_remove(struct i2c_client *client)
@@ -769,7 +762,6 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig
index b433371..88b199b 100644
--- a/drivers/staging/iio/gyro/Kconfig
+++ b/drivers/staging/iio/gyro/Kconfig
@@ -10,16 +10,4 @@
 	  Say yes here to build support for Analog Devices adis16060 wide bandwidth
 	  yaw rate gyroscope with SPI.
 
-config ADIS16260
-	tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"
-	depends on SPI
-	select IIO_ADIS_LIB
-	select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
-	help
-	  Say yes here to build support for Analog Devices ADIS16260 ADIS16265
-	  ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called adis16260.
-
 endmenu
diff --git a/drivers/staging/iio/gyro/Makefile b/drivers/staging/iio/gyro/Makefile
index 975f95b..cf22d6d 100644
--- a/drivers/staging/iio/gyro/Makefile
+++ b/drivers/staging/iio/gyro/Makefile
@@ -4,6 +4,3 @@
 
 adis16060-y             := adis16060_core.o
 obj-$(CONFIG_ADIS16060) += adis16060.o
-
-adis16260-y             := adis16260_core.o
-obj-$(CONFIG_ADIS16260) += adis16260.o
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index c67d3a8..6d3d771 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -151,11 +151,9 @@
 	struct iio_dev *indio_dev;
 
 	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
 	/* this is only used for removal purposes */
 	spi_set_drvdata(spi, indio_dev);
 	st = iio_priv(indio_dev);
@@ -171,23 +169,16 @@
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-		goto error_free_dev;
+		return ret;
 
 	adis16060_iio_dev = indio_dev;
 	return 0;
-
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
 }
 
 /* fixme, confirm ordering in this function */
 static int adis16060_r_remove(struct spi_device *spi)
 {
 	iio_device_unregister(spi_get_drvdata(spi));
-	iio_device_free(spi_get_drvdata(spi));
-
 	return 0;
 }
 
diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h
deleted file mode 100644
index df3c0b7..0000000
--- a/drivers/staging/iio/gyro/adis16260.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef SPI_ADIS16260_H_
-#define SPI_ADIS16260_H_
-
-#include "adis16260_platform_data.h"
-#include <linux/iio/imu/adis.h>
-
-#define ADIS16260_STARTUP_DELAY	220 /* ms */
-
-#define ADIS16260_FLASH_CNT  0x00 /* Flash memory write count */
-#define ADIS16260_SUPPLY_OUT 0x02 /* Power supply measurement */
-#define ADIS16260_GYRO_OUT   0x04 /* X-axis gyroscope output */
-#define ADIS16260_AUX_ADC    0x0A /* analog input channel measurement */
-#define ADIS16260_TEMP_OUT   0x0C /* internal temperature measurement */
-#define ADIS16260_ANGL_OUT   0x0E /* angle displacement */
-#define ADIS16260_GYRO_OFF   0x14 /* Calibration, offset/bias adjustment */
-#define ADIS16260_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
-#define ADIS16260_ALM_MAG1   0x20 /* Alarm 1 magnitude/polarity setting */
-#define ADIS16260_ALM_MAG2   0x22 /* Alarm 2 magnitude/polarity setting */
-#define ADIS16260_ALM_SMPL1  0x24 /* Alarm 1 dynamic rate of change setting */
-#define ADIS16260_ALM_SMPL2  0x26 /* Alarm 2 dynamic rate of change setting */
-#define ADIS16260_ALM_CTRL   0x28 /* Alarm control */
-#define ADIS16260_AUX_DAC    0x30 /* Auxiliary DAC data */
-#define ADIS16260_GPIO_CTRL  0x32 /* Control, digital I/O line */
-#define ADIS16260_MSC_CTRL   0x34 /* Control, data ready, self-test settings */
-#define ADIS16260_SMPL_PRD   0x36 /* Control, internal sample rate */
-#define ADIS16260_SENS_AVG   0x38 /* Control, dynamic range, filtering */
-#define ADIS16260_SLP_CNT    0x3A /* Control, sleep mode initiation */
-#define ADIS16260_DIAG_STAT  0x3C /* Diagnostic, error flags */
-#define ADIS16260_GLOB_CMD   0x3E /* Control, global commands */
-#define ADIS16260_LOT_ID1    0x52 /* Lot Identification Code 1 */
-#define ADIS16260_LOT_ID2    0x54 /* Lot Identification Code 2 */
-#define ADIS16260_PROD_ID    0x56 /* Product identifier;
-				   * convert to decimal = 16,265/16,260 */
-#define ADIS16260_SERIAL_NUM 0x58 /* Serial number */
-
-#define ADIS16260_ERROR_ACTIVE			(1<<14)
-#define ADIS16260_NEW_DATA			(1<<15)
-
-/* MSC_CTRL */
-#define ADIS16260_MSC_CTRL_MEM_TEST		(1<<11)
-/* Internal self-test enable */
-#define ADIS16260_MSC_CTRL_INT_SELF_TEST	(1<<10)
-#define ADIS16260_MSC_CTRL_NEG_SELF_TEST	(1<<9)
-#define ADIS16260_MSC_CTRL_POS_SELF_TEST	(1<<8)
-#define ADIS16260_MSC_CTRL_DATA_RDY_EN		(1<<2)
-#define ADIS16260_MSC_CTRL_DATA_RDY_POL_HIGH	(1<<1)
-#define ADIS16260_MSC_CTRL_DATA_RDY_DIO2	(1<<0)
-
-/* SMPL_PRD */
-/* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
-#define ADIS16260_SMPL_PRD_TIME_BASE	(1<<7)
-#define ADIS16260_SMPL_PRD_DIV_MASK	0x7F
-
-/* SLP_CNT */
-#define ADIS16260_SLP_CNT_POWER_OFF     0x80
-
-/* DIAG_STAT */
-#define ADIS16260_DIAG_STAT_ALARM2	(1<<9)
-#define ADIS16260_DIAG_STAT_ALARM1	(1<<8)
-#define ADIS16260_DIAG_STAT_FLASH_CHK_BIT	6
-#define ADIS16260_DIAG_STAT_SELF_TEST_BIT	5
-#define ADIS16260_DIAG_STAT_OVERFLOW_BIT	4
-#define ADIS16260_DIAG_STAT_SPI_FAIL_BIT	3
-#define ADIS16260_DIAG_STAT_FLASH_UPT_BIT	2
-#define ADIS16260_DIAG_STAT_POWER_HIGH_BIT	1
-#define ADIS16260_DIAG_STAT_POWER_LOW_BIT	0
-
-/* GLOB_CMD */
-#define ADIS16260_GLOB_CMD_SW_RESET	(1<<7)
-#define ADIS16260_GLOB_CMD_FLASH_UPD	(1<<3)
-#define ADIS16260_GLOB_CMD_DAC_LATCH	(1<<2)
-#define ADIS16260_GLOB_CMD_FAC_CALIB	(1<<1)
-#define ADIS16260_GLOB_CMD_AUTO_NULL	(1<<0)
-
-#define ADIS16260_SPI_SLOW	(u32)(300 * 1000)
-#define ADIS16260_SPI_BURST	(u32)(1000 * 1000)
-#define ADIS16260_SPI_FAST	(u32)(2000 * 1000)
-
-/**
- * struct adis16260_state - device instance specific data
- * @negate:		negate the scale parameter
- **/
-struct adis16260_state {
-	unsigned	negate:1;
-	struct adis	adis;
-};
-
-/* At the moment triggers are only used for ring buffer
- * filling. This may change!
- */
-
-#define ADIS16260_SCAN_GYRO	0
-#define ADIS16260_SCAN_SUPPLY	1
-#define ADIS16260_SCAN_AUX_ADC	2
-#define ADIS16260_SCAN_TEMP	3
-#define ADIS16260_SCAN_ANGL	4
-
-#endif /* SPI_ADIS16260_H_ */
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
deleted file mode 100644
index 620d63f..0000000
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/spi/spi.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/buffer.h>
-
-#include "adis16260.h"
-
-static ssize_t adis16260_read_frequency_available(struct device *dev,
-						  struct device_attribute *attr,
-						  char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct adis16260_state *st = iio_priv(indio_dev);
-	if (spi_get_device_id(st->adis.spi)->driver_data)
-		return sprintf(buf, "%s\n", "0.129 ~ 256");
-	else
-		return sprintf(buf, "%s\n", "256 2048");
-}
-
-static ssize_t adis16260_read_frequency(struct device *dev,
-		struct device_attribute *attr,
-		char *buf)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct adis16260_state *st = iio_priv(indio_dev);
-	int ret, len = 0;
-	u16 t;
-	int sps;
-	ret = adis_read_reg_16(&st->adis, ADIS16260_SMPL_PRD, &t);
-	if (ret)
-		return ret;
-
-	if (spi_get_device_id(st->adis.spi)->driver_data) /* If an adis16251 */
-		sps =  (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
-	else
-		sps =  (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
-	sps /= (t & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
-	len = sprintf(buf, "%d SPS\n", sps);
-	return len;
-}
-
-static ssize_t adis16260_write_frequency(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf,
-		size_t len)
-{
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct adis16260_state *st = iio_priv(indio_dev);
-	long val;
-	int ret;
-	u8 t;
-
-	ret = strict_strtol(buf, 10, &val);
-	if (ret)
-		return ret;
-	if (val == 0)
-		return -EINVAL;
-
-	mutex_lock(&indio_dev->mlock);
-	if (spi_get_device_id(st->adis.spi)->driver_data) {
-		t = (256 / val);
-		if (t > 0)
-			t--;
-		t &= ADIS16260_SMPL_PRD_DIV_MASK;
-	} else {
-		t = (2048 / val);
-		if (t > 0)
-			t--;
-		t &= ADIS16260_SMPL_PRD_DIV_MASK;
-	}
-	if ((t & ADIS16260_SMPL_PRD_DIV_MASK) >= 0x0A)
-		st->adis.spi->max_speed_hz = ADIS16260_SPI_SLOW;
-	else
-		st->adis.spi->max_speed_hz = ADIS16260_SPI_FAST;
-	ret = adis_write_reg_8(&st->adis,
-			ADIS16260_SMPL_PRD,
-			t);
-
-	mutex_unlock(&indio_dev->mlock);
-
-	return ret ? ret : len;
-}
-
-/* Power down the device */
-static int adis16260_stop_device(struct iio_dev *indio_dev)
-{
-	struct adis16260_state *st = iio_priv(indio_dev);
-	int ret;
-	u16 val = ADIS16260_SLP_CNT_POWER_OFF;
-
-	ret = adis_write_reg_16(&st->adis, ADIS16260_SLP_CNT, val);
-	if (ret)
-		dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
-
-	return ret;
-}
-
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
-		adis16260_read_frequency,
-		adis16260_write_frequency);
-
-static IIO_DEVICE_ATTR(sampling_frequency_available,
-		       S_IRUGO, adis16260_read_frequency_available, NULL, 0);
-
-#define ADIS16260_GYRO_CHANNEL_SET(axis, mod)				\
-struct iio_chan_spec adis16260_channels_##axis[] = {		\
-	ADIS_GYRO_CHAN(mod, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, \
-		BIT(IIO_CHAN_INFO_CALIBBIAS) | \
-		BIT(IIO_CHAN_INFO_CALIBSCALE), 14), \
-	ADIS_INCLI_CHAN(mod, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14), \
-	ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12), \
-	ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12), \
-	ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12), \
-	IIO_CHAN_SOFT_TIMESTAMP(5),				\
-}
-
-static const ADIS16260_GYRO_CHANNEL_SET(x, X);
-static const ADIS16260_GYRO_CHANNEL_SET(y, Y);
-static const ADIS16260_GYRO_CHANNEL_SET(z, Z);
-
-static const u8 adis16260_addresses[][2] = {
-	[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
-};
-
-static int adis16260_read_raw(struct iio_dev *indio_dev,
-			      struct iio_chan_spec const *chan,
-			      int *val, int *val2,
-			      long mask)
-{
-	struct adis16260_state *st = iio_priv(indio_dev);
-	int ret;
-	int bits;
-	u8 addr;
-	s16 val16;
-
-	switch (mask) {
-	case IIO_CHAN_INFO_RAW:
-		return adis_single_conversion(indio_dev, chan,
-				ADIS16260_ERROR_ACTIVE, val);
-	case IIO_CHAN_INFO_SCALE:
-		switch (chan->type) {
-		case IIO_ANGL_VEL:
-			*val = 0;
-			if (spi_get_device_id(st->adis.spi)->driver_data) {
-				/* 0.01832 degree / sec */
-				*val2 = IIO_DEGREE_TO_RAD(18320);
-			} else {
-				/* 0.07326 degree / sec */
-				*val2 = IIO_DEGREE_TO_RAD(73260);
-			}
-			return IIO_VAL_INT_PLUS_MICRO;
-		case IIO_VOLTAGE:
-			if (chan->channel == 0) {
-				*val = 1;
-				*val2 = 831500; /* 1.8315 mV */
-			} else {
-				*val = 0;
-				*val2 = 610500; /* 610.5 uV */
-			}
-			return IIO_VAL_INT_PLUS_MICRO;
-		case IIO_TEMP:
-			*val = 145;
-			*val2 = 300000; /* 0.1453 C */
-			return IIO_VAL_INT_PLUS_MICRO;
-		default:
-			return -EINVAL;
-		}
-		break;
-	case IIO_CHAN_INFO_OFFSET:
-		*val = 250000 / 1453; /* 25 C = 0x00 */
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBBIAS:
-		switch (chan->type) {
-		case IIO_ANGL_VEL:
-			bits = 12;
-			break;
-		default:
-			return -EINVAL;
-		}
-		mutex_lock(&indio_dev->mlock);
-		addr = adis16260_addresses[chan->scan_index][0];
-		ret = adis_read_reg_16(&st->adis, addr, &val16);
-		if (ret) {
-			mutex_unlock(&indio_dev->mlock);
-			return ret;
-		}
-		val16 &= (1 << bits) - 1;
-		val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
-		*val = val16;
-		mutex_unlock(&indio_dev->mlock);
-		return IIO_VAL_INT;
-	case IIO_CHAN_INFO_CALIBSCALE:
-		switch (chan->type) {
-		case IIO_ANGL_VEL:
-			bits = 12;
-			break;
-		default:
-			return -EINVAL;
-		}
-		mutex_lock(&indio_dev->mlock);
-		addr = adis16260_addresses[chan->scan_index][1];
-		ret = adis_read_reg_16(&st->adis, addr, &val16);
-		if (ret) {
-			mutex_unlock(&indio_dev->mlock);
-			return ret;
-		}
-		*val = (1 << bits) - 1;
-		mutex_unlock(&indio_dev->mlock);
-		return IIO_VAL_INT;
-	}
-	return -EINVAL;
-}
-
-static int adis16260_write_raw(struct iio_dev *indio_dev,
-			       struct iio_chan_spec const *chan,
-			       int val,
-			       int val2,
-			       long mask)
-{
-	struct adis16260_state *st = iio_priv(indio_dev);
-	int bits = 12;
-	s16 val16;
-	u8 addr;
-	switch (mask) {
-	case IIO_CHAN_INFO_CALIBBIAS:
-		val16 = val & ((1 << bits) - 1);
-		addr = adis16260_addresses[chan->scan_index][0];
-		return adis_write_reg_16(&st->adis, addr, val16);
-	case IIO_CHAN_INFO_CALIBSCALE:
-		val16 = val & ((1 << bits) - 1);
-		addr = adis16260_addresses[chan->scan_index][1];
-		return adis_write_reg_16(&st->adis, addr, val16);
-	}
-	return -EINVAL;
-}
-
-static struct attribute *adis16260_attributes[] = {
-	&iio_dev_attr_sampling_frequency.dev_attr.attr,
-	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
-	NULL
-};
-
-static const struct attribute_group adis16260_attribute_group = {
-	.attrs = adis16260_attributes,
-};
-
-static const struct iio_info adis16260_info = {
-	.attrs = &adis16260_attribute_group,
-	.read_raw = &adis16260_read_raw,
-	.write_raw = &adis16260_write_raw,
-	.update_scan_mode = adis_update_scan_mode,
-	.driver_module = THIS_MODULE,
-};
-
-static const char * const adis1620_status_error_msgs[] = {
-	[ADIS16260_DIAG_STAT_FLASH_CHK_BIT] = "Flash checksum error",
-	[ADIS16260_DIAG_STAT_SELF_TEST_BIT] = "Self test error",
-	[ADIS16260_DIAG_STAT_OVERFLOW_BIT] = "Sensor overrange",
-	[ADIS16260_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
-	[ADIS16260_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
-	[ADIS16260_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 5.25",
-	[ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75",
-};
-
-static const struct adis_data adis16260_data = {
-	.write_delay = 30,
-	.read_delay = 30,
-	.msc_ctrl_reg = ADIS16260_MSC_CTRL,
-	.glob_cmd_reg = ADIS16260_GLOB_CMD,
-	.diag_stat_reg = ADIS16260_DIAG_STAT,
-
-	.self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,
-	.startup_delay = ADIS16260_STARTUP_DELAY,
-
-	.status_error_msgs = adis1620_status_error_msgs,
-	.status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) |
-		BIT(ADIS16260_DIAG_STAT_SELF_TEST_BIT) |
-		BIT(ADIS16260_DIAG_STAT_OVERFLOW_BIT) |
-		BIT(ADIS16260_DIAG_STAT_SPI_FAIL_BIT) |
-		BIT(ADIS16260_DIAG_STAT_FLASH_UPT_BIT) |
-		BIT(ADIS16260_DIAG_STAT_POWER_HIGH_BIT) |
-		BIT(ADIS16260_DIAG_STAT_POWER_LOW_BIT),
-};
-
-static int adis16260_probe(struct spi_device *spi)
-{
-	int ret;
-	struct adis16260_platform_data *pd = spi->dev.platform_data;
-	struct adis16260_state *st;
-	struct iio_dev *indio_dev;
-
-	/* setup the industrialio driver allocated elements */
-	indio_dev = iio_device_alloc(sizeof(*st));
-	if (indio_dev == NULL) {
-		ret = -ENOMEM;
-		goto error_ret;
-	}
-	st = iio_priv(indio_dev);
-	if (pd)
-		st->negate = pd->negate;
-	/* this is only used for removal purposes */
-	spi_set_drvdata(spi, indio_dev);
-
-	indio_dev->name = spi_get_device_id(spi)->name;
-	indio_dev->dev.parent = &spi->dev;
-	indio_dev->info = &adis16260_info;
-	indio_dev->num_channels
-		= ARRAY_SIZE(adis16260_channels_x);
-	if (pd && pd->direction)
-		switch (pd->direction) {
-		case 'x':
-			indio_dev->channels = adis16260_channels_x;
-			break;
-		case 'y':
-			indio_dev->channels = adis16260_channels_y;
-			break;
-		case 'z':
-			indio_dev->channels = adis16260_channels_z;
-			break;
-		default:
-			return -EINVAL;
-		}
-	else
-		indio_dev->channels = adis16260_channels_x;
-	indio_dev->num_channels = ARRAY_SIZE(adis16260_channels_x);
-	indio_dev->modes = INDIO_DIRECT_MODE;
-
-	ret = adis_init(&st->adis, indio_dev, spi, &adis16260_data);
-	if (ret)
-		goto error_free_dev;
-
-	ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
-	if (ret)
-		goto error_free_dev;
-
-	if (indio_dev->buffer) {
-		/* Set default scan mode */
-		iio_scan_mask_set(indio_dev, indio_dev->buffer,
-				  ADIS16260_SCAN_SUPPLY);
-		iio_scan_mask_set(indio_dev, indio_dev->buffer,
-				  ADIS16260_SCAN_GYRO);
-		iio_scan_mask_set(indio_dev, indio_dev->buffer,
-				  ADIS16260_SCAN_AUX_ADC);
-		iio_scan_mask_set(indio_dev, indio_dev->buffer,
-				  ADIS16260_SCAN_TEMP);
-		iio_scan_mask_set(indio_dev, indio_dev->buffer,
-				  ADIS16260_SCAN_ANGL);
-	}
-
-	/* Get the device into a sane initial state */
-	ret = adis_initial_startup(&st->adis);
-	if (ret)
-		goto error_cleanup_buffer_trigger;
-	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto error_cleanup_buffer_trigger;
-
-	return 0;
-
-error_cleanup_buffer_trigger:
-	adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-error_free_dev:
-	iio_device_free(indio_dev);
-error_ret:
-	return ret;
-}
-
-static int adis16260_remove(struct spi_device *spi)
-{
-	struct iio_dev *indio_dev = spi_get_drvdata(spi);
-	struct adis16260_state *st = iio_priv(indio_dev);
-
-	iio_device_unregister(indio_dev);
-	adis16260_stop_device(indio_dev);
-	adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
-	iio_device_free(indio_dev);
-
-	return 0;
-}
-
-/*
- * These parts do not need to be differentiated until someone adds
- * support for the on chip filtering.
- */
-static const struct spi_device_id adis16260_id[] = {
-	{"adis16260", 0},
-	{"adis16265", 0},
-	{"adis16250", 0},
-	{"adis16255", 0},
-	{"adis16251", 1},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, adis16260_id);
-
-static struct spi_driver adis16260_driver = {
-	.driver = {
-		.name = "adis16260",
-		.owner = THIS_MODULE,
-	},
-	.probe = adis16260_probe,
-	.remove = adis16260_remove,
-	.id_table = adis16260_id,
-};
-module_spi_driver(adis16260_driver);
-
-MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16260_platform_data.h b/drivers/staging/iio/gyro/adis16260_platform_data.h
deleted file mode 100644
index 12802e9..0000000
--- a/drivers/staging/iio/gyro/adis16260_platform_data.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * ADIS16260 Programmable Digital Gyroscope Sensor Driver Platform Data
- *
- * Based on adis16255.h Matthia Brugger <m_brugger&web.de>
- *
- * Copyright (C) 2010 Fraunhofer Institute for Integrated Circuits
-  *
- * Licensed under the GPL-2 or later.
- */
-
-/**
- * struct adis16260_platform_data - instance specific data
- * @direction: x y or z
- * @negate: flag to indicate value should be inverted.
- **/
-struct adis16260_platform_data {
-	char direction;
-	unsigned negate:1;
-};
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 82478a5..351936c 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -550,11 +550,10 @@
 	struct iio_dev *indio_dev;
 	int err;
 
-	indio_dev = iio_device_alloc(sizeof(*chip));
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
 	if (indio_dev == NULL) {
 		dev_err(&client->dev, "iio allocation fails\n");
-		err = -ENOMEM;
-		goto exit;
+		return -ENOMEM;
 	}
 	chip = iio_priv(indio_dev);
 
@@ -572,12 +571,12 @@
 	if (IS_ERR(chip->regmap)) {
 		err = PTR_ERR(chip->regmap);
 		dev_err(chip->dev, "regmap initialization failed: %d\n", err);
-		goto exit;
+		return err;
 	}
 
 	err = isl29018_chip_init(chip);
 	if (err)
-		goto exit_iio_free;
+		return err;
 
 	indio_dev->info = &isl29108_info;
 	indio_dev->channels = isl29018_channels;
@@ -588,14 +587,10 @@
 	err = iio_device_register(indio_dev);
 	if (err) {
 		dev_err(&client->dev, "iio registration fails\n");
-		goto exit_iio_free;
+		return err;
 	}
 
 	return 0;
-exit_iio_free:
-	iio_device_free(indio_dev);
-exit:
-	return err;
 }
 
 static int isl29018_remove(struct i2c_client *client)
@@ -604,7 +599,6 @@
 
 	dev_dbg(&client->dev, "%s()\n", __func__);
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 
 	return 0;
 }
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index 8bb0d03..6014625 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -482,7 +482,7 @@
 	struct iio_dev *indio_dev;
 	int ret;
 
-	indio_dev = iio_device_alloc(sizeof(*chip));
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
 	if (!indio_dev) {
 		dev_err(&client->dev, "iio allocation fails\n");
 		return -ENOMEM;
@@ -498,13 +498,13 @@
 	if (IS_ERR(chip->regmap)) {
 		ret = PTR_ERR(chip->regmap);
 		dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
-		goto exit_iio_free;
+		return ret;
 	}
 
 	ret = isl29028_chip_init(chip);
 	if (ret < 0) {
 		dev_err(chip->dev, "chip initialization failed: %d\n", ret);
-		goto exit_iio_free;
+		return ret;
 	}
 
 	indio_dev->info = &isl29028_info;
@@ -517,13 +517,9 @@
 	if (ret < 0) {
 		dev_err(chip->dev, "iio registration fails with error %d\n",
 			ret);
-		goto exit_iio_free;
+		return ret;
 	}
 	return 0;
-
-exit_iio_free:
-	iio_device_free(indio_dev);
-	return ret;
 }
 
 static int isl29028_remove(struct i2c_client *client)
@@ -531,7 +527,6 @@
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	iio_device_unregister(indio_dev);
-	iio_device_free(indio_dev);
 	return 0;
 }
 
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index 86c6bf9..d2748c3 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -20,12 +20,10 @@
 */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/types.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/delay.h>
 
 #define HMC5843_CONFIG_REG_A			0x00
 #define HMC5843_CONFIG_REG_B			0x01
@@ -42,9 +40,6 @@
 #define HMC5883_DATA_OUT_Y_MSB_REG		0x07
 #define HMC5883_DATA_OUT_Y_LSB_REG		0x08
 #define HMC5843_STATUS_REG			0x09
-#define HMC5843_ID_REG_A			0x0A
-#define HMC5843_ID_REG_B			0x0B
-#define HMC5843_ID_REG_C			0x0C
 
 enum hmc5843_ids {
 	HMC5843_ID,
@@ -53,14 +48,6 @@
 };
 
 /*
- * Beware: identification of the HMC5883 is still "H43";
- * I2C address is also unchanged
- */
-#define HMC5843_ID_REG_LENGTH			0x03
-#define HMC5843_ID_STRING			"H43"
-#define HMC5843_I2C_ADDRESS			0x1E
-
-/*
  * Range gain settings in (+-)Ga
  * Beware: HMC5843 and HMC5883 have different recommended sensor field
  * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
@@ -185,14 +172,9 @@
 	"0.75", "1.5", "3", "7.5", "15", "30", "75",
 };
 
-/* Addresses to scan: 0x1E */
-static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS,
-					     I2C_CLIENT_END };
-
 /* Describe chip variants */
 struct hmc5843_chip_info {
 	const struct iio_chan_spec *channels;
-	int num_channels;
 	const char * const *regval_to_sample_freq;
 	const int *regval_to_input_field_mga;
 	const int *regval_to_nanoscale;
@@ -225,18 +207,29 @@
 	struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
 	struct hmc5843_data *data = iio_priv(indio_dev);
 	s32 result;
+	int tries = 150;
 
 	mutex_lock(&data->lock);
-	result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
-	while (!(result & HMC5843_DATA_READY))
-		result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
+	while (tries-- > 0) {
+		result = i2c_smbus_read_byte_data(client,
+			HMC5843_STATUS_REG);
+		if (result & HMC5843_DATA_READY)
+			break;
+		msleep(20);
+	}
 
-	result = i2c_smbus_read_word_data(client, address);
+	if (tries < 0) {
+		dev_err(&client->dev, "data not ready\n");
+		mutex_unlock(&data->lock);
+		return -EIO;
+	}
+
+	result = i2c_smbus_read_word_swapped(client, address);
 	mutex_unlock(&data->lock);
 	if (result < 0)
 		return -EINVAL;
 
-	*val = (s16)swab16((u16)result);
+	*val = result;
 	return IIO_VAL_INT;
 }
 
@@ -559,14 +552,14 @@
 	return -EINVAL;
 }
 
-#define HMC5843_CHANNEL(axis, add)					\
+#define HMC5843_CHANNEL(axis, addr)					\
 	{								\
 		.type = IIO_MAGN,					\
 		.modified = 1,						\
 		.channel2 = IIO_MOD_##axis,				\
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
-		.address = add						\
+		.address = addr						\
 	}
 
 static const struct iio_chan_spec hmc5843_channels[] = {
@@ -597,7 +590,6 @@
 static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
 	[HMC5843_ID] = {
 		.channels = hmc5843_channels,
-		.num_channels = ARRAY_SIZE(hmc5843_channels),
 		.regval_to_sample_freq = hmc5843_regval_to_sample_freq,
 		.regval_to_input_field_mga =
 			hmc5843_regval_to_input_field_mga,
@@ -605,7 +597,6 @@
 	},
 	[HMC5883_ID] = {
 		.channels = hmc5883_channels,
-		.num_channels = ARRAY_SIZE(hmc5883_channels),
 		.regval_to_sample_freq = hmc5883_regval_to_sample_freq,
 		.regval_to_input_field_mga =
 			hmc5883_regval_to_input_field_mga,
@@ -613,7 +604,6 @@
 	},
 	[HMC5883L_ID] = {
 		.channels = hmc5883_channels,
-		.num_channels = ARRAY_SIZE(hmc5883_channels),
 		.regval_to_sample_freq = hmc5883_regval_to_sample_freq,
 		.regval_to_input_field_mga =
 			hmc5883l_regval_to_input_field_mga,
@@ -621,25 +611,6 @@
 	},
 };
 
-static int hmc5843_detect(struct i2c_client *client,
-			  struct i2c_board_info *info)
-{
-	unsigned char id_str[HMC5843_ID_REG_LENGTH];
-
-	if (client->addr != HMC5843_I2C_ADDRESS)
-		return -ENODEV;
-
-	if (i2c_smbus_read_i2c_block_data(client, HMC5843_ID_REG_A,
-				HMC5843_ID_REG_LENGTH, id_str)
-			!= HMC5843_ID_REG_LENGTH)
-		return -ENODEV;
-
-	if (0 != strncmp(id_str, HMC5843_ID_STRING, HMC5843_ID_REG_LENGTH))
-		return -ENODEV;
-
-	return 0;
-}
-
 /* Called when we have found a new HMC58X3 */
 static void hmc5843_init_client(struct i2c_client *client,
 				const struct i2c_device_id *id)
@@ -649,7 +620,7 @@
 
 	data->variant = &hmc5843_chip_info_tbl[id->driver_data];
 	indio_dev->channels = data->variant->channels;
-	indio_dev->num_channels = data->variant->num_channels;
+	indio_dev->num_channels = 3;
 	hmc5843_set_meas_conf(client, data->meas_conf);
 	hmc5843_set_rate(client, data->rate);
 	hmc5843_configure(client, data->operating_mode);
@@ -756,8 +727,6 @@
 	.id_table	= hmc5843_id,
 	.probe		= hmc5843_probe,
 	.remove		= hmc5843_remove,
-	.detect		= hmc5843_detect,
-	.address_list	= normal_i2c,
 };
 module_i2c_driver(hmc5843_driver);
 
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index e5943e2..74025fb 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -225,21 +225,6 @@
 	return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
 }
 
-static ssize_t ade7753_write_reset(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t len)
-{
-	if (len < 1)
-		return -1;
-	switch (buf[0]) {
-	case '1':
-	case 'y':
-	case 'Y':
-		return ade7753_reset(dev);
-	}
-	return -1;
-}
-
 static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY);
 static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY);
 static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY);
@@ -458,8 +443,6 @@
 		ade7753_read_frequency,
 		ade7753_write_frequency);
 
-static IIO_DEV_ATTR_RESET(ade7753_write_reset);
-
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
 
 static struct attribute *ade7753_attributes[] = {
@@ -468,7 +451,6 @@
 	&iio_const_attr_in_temp_scale.dev_attr.attr,
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_phcal.dev_attr.attr,
 	&iio_dev_attr_cfden.dev_attr.attr,
 	&iio_dev_attr_aenergy.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 7b6503b..f649ebe 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -224,22 +224,6 @@
 	return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val);
 }
 
-
-static ssize_t ade7754_write_reset(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t len)
-{
-	if (len < 1)
-		return -1;
-	switch (buf[0]) {
-	case '1':
-	case 'y':
-	case 'Y':
-		return ade7754_reset(dev);
-	}
-	return -1;
-}
-
 static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY);
 static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY);
 static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY);
@@ -478,8 +462,6 @@
 		ade7754_read_frequency,
 		ade7754_write_frequency);
 
-static IIO_DEV_ATTR_RESET(ade7754_write_reset);
-
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
 
 static struct attribute *ade7754_attributes[] = {
@@ -488,7 +470,6 @@
 	&iio_const_attr_in_temp_scale.dev_attr.attr,
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_aenergy.dev_attr.attr,
 	&iio_dev_attr_laenergy.dev_attr.attr,
 	&iio_dev_attr_vaenergy.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index 8f5bcfa..6005d4a 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -313,21 +313,6 @@
 	return ret;
 }
 
-static ssize_t ade7758_write_reset(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t len)
-{
-	if (len < 1)
-		return -1;
-	switch (buf[0]) {
-	case '1':
-	case 'y':
-	case 'Y':
-		return ade7758_reset(dev);
-	}
-	return len;
-}
-
 static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
 		ade7758_read_8bit,
 		ade7758_write_8bit,
@@ -591,8 +576,6 @@
 		ade7758_read_frequency,
 		ade7758_write_frequency);
 
-static IIO_DEV_ATTR_RESET(ade7758_write_reset);
-
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26040 13020 6510 3255");
 
 static struct attribute *ade7758_attributes[] = {
@@ -601,7 +584,6 @@
 	&iio_const_attr_in_temp_scale.dev_attr.attr,
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_awatthr.dev_attr.attr,
 	&iio_dev_attr_bwatthr.dev_attr.attr,
 	&iio_dev_attr_cwatthr.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index b29e2d5..7d5db71 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -54,7 +54,7 @@
 	return ret;
 }
 
-/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is too device
  * specific to be rolled into the core.
  */
 static irqreturn_t ade7758_trigger_handler(int irq, void *p)
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 17dc373..d214ac49 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -229,21 +229,6 @@
 	return ret;
 }
 
-static ssize_t ade7759_write_reset(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t len)
-{
-	if (len < 1)
-		return -1;
-	switch (buf[0]) {
-	case '1':
-	case 'y':
-	case 'Y':
-		return ade7759_reset(dev);
-	}
-	return -1;
-}
-
 static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY);
 static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
 		ade7759_read_16bit,
@@ -418,8 +403,6 @@
 		ade7759_read_frequency,
 		ade7759_write_frequency);
 
-static IIO_DEV_ATTR_RESET(ade7759_write_reset);
-
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
 
 static struct attribute *ade7759_attributes[] = {
@@ -428,7 +411,6 @@
 	&iio_const_attr_in_temp_scale.dev_attr.attr,
 	&iio_dev_attr_sampling_frequency.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_phcal.dev_attr.attr,
 	&iio_dev_attr_cfden.dev_attr.attr,
 	&iio_dev_attr_aenergy.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index c642da8..e8379c0 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -186,22 +186,6 @@
 	return st->write_reg_16(dev, ADE7854_CONFIG, val);
 }
 
-
-static ssize_t ade7854_write_reset(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t len)
-{
-	if (len < 1)
-		return -1;
-	switch (buf[0]) {
-	case '1':
-	case 'y':
-	case 'Y':
-		return ade7854_reset(dev);
-	}
-	return -1;
-}
-
 static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
 		ade7854_read_24bit,
 		ade7854_write_24bit,
@@ -468,8 +452,6 @@
 	return ret;
 }
 
-static IIO_DEV_ATTR_RESET(ade7854_write_reset);
-
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000");
 
 static IIO_CONST_ATTR(name, "ade7854");
@@ -515,7 +497,6 @@
 	&iio_dev_attr_bvahr.dev_attr.attr,
 	&iio_dev_attr_cvahr.dev_attr.attr,
 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_const_attr_name.dev_attr.attr,
 	&iio_dev_attr_vpeak.dev_attr.attr,
 	&iio_dev_attr_ipeak.dev_attr.attr,
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 0d3356d..dcdadbb 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -192,21 +192,6 @@
 	return ad2s1210_config_write(st, 0x0);
 }
 
-static ssize_t ad2s1210_store_softreset(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf,
-					size_t len)
-{
-	struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
-	int ret;
-
-	mutex_lock(&st->lock);
-	ret = ad2s1210_soft_reset(st);
-	mutex_unlock(&st->lock);
-
-	return ret < 0 ? ret : len;
-}
-
 static ssize_t ad2s1210_show_fclkin(struct device *dev,
 				    struct device_attribute *attr,
 				    char *buf)
@@ -536,8 +521,6 @@
 	return ret;
 }
 
-static IIO_DEVICE_ATTR(reset, S_IWUSR,
-		       NULL, ad2s1210_store_softreset, 0);
 static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR,
 		       ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0);
 static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR,
@@ -587,7 +570,6 @@
 };
 
 static struct attribute *ad2s1210_attributes[] = {
-	&iio_dev_attr_reset.dev_attr.attr,
 	&iio_dev_attr_fclkin.dev_attr.attr,
 	&iio_dev_attr_fexcit.dev_attr.attr,
 	&iio_dev_attr_control.dev_attr.attr,
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index bd0f2fd..394254f 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -15,7 +15,7 @@
 	help
 	  The DRM framework can provide a legacy /dev/fb0 framebuffer
 	  for your device. This is necessary to get a framebuffer console
-	  and also for appplications using the legacy framebuffer API
+	  and also for applications using the legacy framebuffer API
 
 config DRM_IMX_PARALLEL_DISPLAY
 	tristate "Support for parallel displays"
@@ -32,7 +32,7 @@
 
 config DRM_IMX_LDB
 	tristate "Support for LVDS displays"
-	depends on DRM_IMX
+	depends on DRM_IMX && MFD_SYSCON
 	help
 	  Choose this to enable the internal LVDS Display Bridge (LDB)
 	  found on i.MX53 and i.MX6 processors.
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
index f806415..9cfa2a7 100644
--- a/drivers/staging/imx-drm/TODO
+++ b/drivers/staging/imx-drm/TODO
@@ -10,7 +10,6 @@
 Missing features (not necessarily for moving out of staging):
 
 - Add KMS plane support for CRTC driver
-- Add LDB (LVDS Display Bridge) support
 - Add i.MX6 HDMI support
 - Add support for IC (Image converter)
 - Add support for CSI (CMOS Sensor interface)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 9854a1d..878f168 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -69,28 +69,20 @@
 	struct module				*owner;
 };
 
-static int imx_drm_driver_firstopen(struct drm_device *drm)
-{
-	if (!imx_drm_device_get())
-		return -EINVAL;
-
-	return 0;
-}
-
 static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
 	if (imxdrm->fbhelper)
 		drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
-
-	imx_drm_device_put();
 }
 
 static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+	imx_drm_device_put();
+
 	drm_mode_config_cleanup(imxdrm->drm);
 	drm_kms_helper_poll_fini(imxdrm->drm);
 
@@ -226,8 +218,6 @@
 	struct imx_drm_connector *con;
 	struct imx_drm_crtc *crtc;
 
-	mutex_lock(&imxdrm->mutex);
-
 	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
 		if (!try_module_get(enc->owner)) {
 			dev_err(imxdrm->dev, "could not get module %s\n",
@@ -254,8 +244,6 @@
 
 	imxdrm->references++;
 
-	mutex_unlock(&imxdrm->mutex);
-
 	return imxdrm->drm;
 
 unwind_crtc:
@@ -447,6 +435,9 @@
 	 */
 	imxdrm->drm->vblank_disable_allowed = 1;
 
+	if (!imx_drm_device_get())
+		ret = -EINVAL;
+
 	ret = 0;
 
 err_init:
@@ -678,6 +669,7 @@
 
 	return i;
 }
+EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
 /*
  * imx_drm_remove_encoder - remove an encoder
@@ -791,7 +783,6 @@
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM,
 	.load			= imx_drm_driver_load,
 	.unload			= imx_drm_driver_unload,
-	.firstopen		= imx_drm_driver_firstopen,
 	.lastclose		= imx_drm_driver_lastclose,
 	.gem_free_object	= drm_gem_cma_free_object,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 8af7f3b..af733ea 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -497,7 +497,7 @@
 		imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
 
 	/*
-	 * There are three diferent possible clock mux configurations:
+	 * There are three different possible clock mux configurations:
 	 * i.MX53:  ipu1_di0_sel, ipu1_di1_sel
 	 * i.MX6q:  ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
 	 * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
@@ -623,3 +623,4 @@
 MODULE_DESCRIPTION("i.MX LVDS driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index a56797d..3c024b4 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -131,12 +131,14 @@
 };
 
 static void tve_lock(void *__tve)
+__acquires(&tve->lock)
 {
 	struct imx_tve *tve = __tve;
 	spin_lock(&tve->lock);
 }
 
 static void tve_unlock(void *__tve)
+__releases(&tve->lock)
 {
 	struct imx_tve *tve = __tve;
 	spin_unlock(&tve->lock);
@@ -164,7 +166,10 @@
 		regmap_write(tve->regmap, TVE_INT_CONT_REG, 0);
 	else
 		regmap_write(tve->regmap, TVE_INT_CONT_REG,
-			     TVE_CD_SM_IEN | TVE_CD_LM_IEN | TVE_CD_MON_END_IEN);
+			     TVE_CD_SM_IEN |
+			     TVE_CD_LM_IEN |
+			     TVE_CD_MON_END_IEN);
+
 	spin_unlock_irqrestore(&tve->enable_lock, flags);
 }
 
@@ -465,7 +470,9 @@
 	else
 		val = TVE_DAC_FULL_RATE;
 
-	ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, TVE_DAC_SAMP_RATE_MASK, val);
+	ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+				 TVE_DAC_SAMP_RATE_MASK, val);
+
 	if (ret < 0) {
 		dev_err(tve->dev, "failed to set divider: %d\n", ret);
 		return ret;
@@ -609,13 +616,17 @@
 	}
 
 	if (tve->mode == TVE_MODE_VGA) {
-		ret = of_property_read_u32(np, "fsl,hsync-pin", &tve->hsync_pin);
+		ret = of_property_read_u32(np, "fsl,hsync-pin",
+					   &tve->hsync_pin);
+
 		if (ret < 0) {
 			dev_err(&pdev->dev, "failed to get vsync pin\n");
 			return ret;
 		}
 
-		ret |= of_property_read_u32(np, "fsl,vsync-pin", &tve->vsync_pin);
+		ret |= of_property_read_u32(np, "fsl,vsync-pin",
+					    &tve->vsync_pin);
+
 		if (ret < 0) {
 			dev_err(&pdev->dev, "failed to get vsync pin\n");
 			return ret;
@@ -623,11 +634,6 @@
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "failed to get memory region\n");
-		return -ENOENT;
-	}
-
 	base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
@@ -743,3 +749,4 @@
 MODULE_DESCRIPTION("i.MX Television Encoder driver");
 MODULE_AUTHOR("Philipp Zabel, Pengutronix");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-tve");
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index e35d0bf..ba464e5 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -1075,21 +1075,23 @@
 	ipu->cpmem_base = devm_ioremap(&pdev->dev,
 			ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
 
-	if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) {
-		ret = -ENOMEM;
-		goto failed_ioremap;
-	}
+	if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
+		return -ENOMEM;
 
 	ipu->clk = devm_clk_get(&pdev->dev, "bus");
 	if (IS_ERR(ipu->clk)) {
 		ret = PTR_ERR(ipu->clk);
 		dev_err(&pdev->dev, "clk_get failed with %d", ret);
-		goto failed_clk_get;
+		return ret;
 	}
 
 	platform_set_drvdata(pdev, ipu);
 
-	clk_prepare_enable(ipu->clk);
+	ret = clk_prepare_enable(ipu->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+		return ret;
+	}
 
 	ipu->dev = &pdev->dev;
 	ipu->irq_sync = irq_sync;
@@ -1134,8 +1136,6 @@
 	ipu_irq_exit(ipu);
 out_failed_irq:
 	clk_disable_unprepare(ipu->clk);
-failed_clk_get:
-failed_ioremap:
 	return ret;
 }
 
@@ -1163,6 +1163,7 @@
 
 module_platform_driver(imx_ipu_driver);
 
+MODULE_ALIAS("platform:imx-ipuv3");
 MODULE_DESCRIPTION("i.MX IPU v3 driver");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index 59f03f9..21bf1c8 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -161,14 +161,15 @@
 		u32 pixel_fmt, u32 width)
 {
 	struct ipu_dc_priv *priv = dc->priv;
-	u32 reg = 0, map;
+	u32 reg = 0;
+	int map;
 
 	dc->di = ipu_di_get_num(di);
 
 	map = ipu_pixfmt_to_map(pixel_fmt);
 	if (map < 0) {
 		dev_dbg(priv->dev, "IPU_DISP: No MAP\n");
-		return -EINVAL;
+		return map;
 	}
 
 	if (interlaced) {
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 0b6806e..948a49b 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -654,7 +654,9 @@
 
 int ipu_di_enable(struct ipu_di *di)
 {
-	clk_prepare_enable(di->clk_di_pixel);
+	int ret = clk_prepare_enable(di->clk_di_pixel);
+	if (ret)
+		return ret;
 
 	ipu_module_enable(di->ipu, di->module);
 
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 113b046..231afd6 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -46,6 +46,8 @@
 #define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
 #define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
 
+#define IPUV3_NUM_FLOWS		3
+
 struct ipu_dp_priv;
 
 struct ipu_dp {
@@ -67,7 +69,7 @@
 	struct ipu_soc *ipu;
 	struct device *dev;
 	void __iomem *base;
-	struct ipu_flow flow[3];
+	struct ipu_flow flow[IPUV3_NUM_FLOWS];
 	struct mutex mutex;
 	int use_count;
 };
@@ -280,7 +282,7 @@
 	struct ipu_dp_priv *priv = ipu->dp_priv;
 	struct ipu_dp *dp;
 
-	if (flow > 5)
+	if ((flow >> 1) >= IPUV3_NUM_FLOWS)
 		return ERR_PTR(-EINVAL);
 
 	if (flow & 1)
@@ -309,19 +311,20 @@
 	int i;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
 	priv->dev = dev;
 	priv->ipu = ipu;
 
 	ipu->dp_priv = priv;
 
 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
-	if (!priv->base) {
+	if (!priv->base)
 		return -ENOMEM;
-	}
 
 	mutex_init(&priv->mutex);
 
-	for (i = 0; i < 3; i++) {
+	for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
 		priv->flow[i].foreground.foreground = 1;
 		priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
 		priv->flow[i].priv = priv;
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 9176a81..bae0e2e 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -562,3 +562,4 @@
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-ipuv3-crtc");
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index cea9f14..24aa9be 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -272,3 +272,4 @@
 MODULE_DESCRIPTION("i.MX parallel display driver");
 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-parallel-display");
diff --git a/drivers/staging/keucr/scsiglue.c b/drivers/staging/keucr/scsiglue.c
index afb00d8..ac3d34d 100644
--- a/drivers/staging/keucr/scsiglue.c
+++ b/drivers/staging/keucr/scsiglue.c
@@ -289,10 +289,7 @@
  ***********************************************************************/
 
 /* Output routine for the sysfs max_sectors file */
-/*
- * show_max_sectors()
- */
-static ssize_t show_max_sectors(struct device *dev,
+static ssize_t max_sectors_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev = to_scsi_device(dev);
@@ -302,10 +299,7 @@
 }
 
 /* Input routine for the sysfs max_sectors file */
-/*
- * store_max_sectors()
- */
-static ssize_t store_max_sectors(struct device *dev,
+static ssize_t max_sectors_store(struct device *dev,
 				struct device_attribute *attr,
 				const char *buf, size_t count)
 {
@@ -319,9 +313,8 @@
 	}
 	return -EINVAL;
 }
+static DEVICE_ATTR_RW(max_sectors);
 
-static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
-							store_max_sectors);
 static struct device_attribute *sysfs_device_attr_list[] = {
 	&dev_attr_max_sectors, NULL,
 };
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 6252aca..471c10c 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -568,15 +568,6 @@
 }
 
 /*
-	No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_write(struct device *dev, struct device_attribute *attr,
-			const char *buf, size_t count)
-{
-	return count;
-}
-
-/*
 	Generic destructor.
 */
 static void line6_destruct(struct usb_interface *interface)
diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
index a8341f9..34ae95e 100644
--- a/drivers/staging/line6/driver.h
+++ b/drivers/staging/line6/driver.h
@@ -190,9 +190,6 @@
 				      int code2, int size);
 extern ssize_t line6_nop_read(struct device *dev,
 			      struct device_attribute *attr, char *buf);
-extern ssize_t line6_nop_write(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count);
 extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
 			   size_t datalen);
 extern int line6_read_serial_number(struct usb_line6 *line6,
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 0dd08ef..6a0648c 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -34,8 +34,8 @@
 /*
 	"read" request on "impulse_volume" special file.
 */
-static ssize_t pcm_get_impulse_volume(struct device *dev,
-				      struct device_attribute *attr, char *buf)
+static ssize_t impulse_volume_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
 }
@@ -43,9 +43,9 @@
 /*
 	"write" request on "impulse_volume" special file.
 */
-static ssize_t pcm_set_impulse_volume(struct device *dev,
-				      struct device_attribute *attr,
-				      const char *buf, size_t count)
+static ssize_t impulse_volume_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
 {
 	struct snd_line6_pcm *line6pcm = dev2pcm(dev);
 	int value;
@@ -64,12 +64,13 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(impulse_volume);
 
 /*
 	"read" request on "impulse_period" special file.
 */
-static ssize_t pcm_get_impulse_period(struct device *dev,
-				      struct device_attribute *attr, char *buf)
+static ssize_t impulse_period_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
 }
@@ -77,9 +78,9 @@
 /*
 	"write" request on "impulse_period" special file.
 */
-static ssize_t pcm_set_impulse_period(struct device *dev,
-				      struct device_attribute *attr,
-				      const char *buf, size_t count)
+static ssize_t impulse_period_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
 {
 	int value;
 	int ret;
@@ -91,11 +92,7 @@
 	dev2pcm(dev)->impulse_period = value;
 	return count;
 }
-
-static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume,
-		   pcm_set_impulse_volume);
-static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period,
-		   pcm_set_impulse_period);
+static DEVICE_ATTR_RW(impulse_period);
 
 #endif
 
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
index 699b217..f4e95a6 100644
--- a/drivers/staging/line6/pod.c
+++ b/drivers/staging/line6/pod.c
@@ -192,8 +192,8 @@
 /*
 	"read" request on "serial_number" special file.
 */
-static ssize_t pod_get_serial_number(struct device *dev,
-				     struct device_attribute *attr, char *buf)
+static ssize_t serial_number_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *interface = to_usb_interface(dev);
 	struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -203,9 +203,8 @@
 /*
 	"read" request on "firmware_version" special file.
 */
-static ssize_t pod_get_firmware_version(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
+static ssize_t firmware_version_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *interface = to_usb_interface(dev);
 	struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -216,8 +215,8 @@
 /*
 	"read" request on "device_id" special file.
 */
-static ssize_t pod_get_device_id(struct device *dev,
-				 struct device_attribute *attr, char *buf)
+static ssize_t device_id_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *interface = to_usb_interface(dev);
 	struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -274,11 +273,9 @@
 }
 
 /* POD special files: */
-static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
-static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
-		   line6_nop_write);
-static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
-		   line6_nop_write);
+static DEVICE_ATTR_RO(device_id);
+static DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(serial_number);
 
 /* control info callback */
 static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
diff --git a/drivers/staging/lustre/Makefile b/drivers/staging/lustre/Makefile
index 2616289..fb0e0fa 100644
--- a/drivers/staging/lustre/Makefile
+++ b/drivers/staging/lustre/Makefile
@@ -1,4 +1,4 @@
 subdir-ccflags-y := -I$(src)/include/
 
-obj-$(CONFIG_LUSTRE_FS)		+= lustre/
 obj-$(CONFIG_LNET)		+= lnet/
+obj-$(CONFIG_LUSTRE_FS)		+= lustre/
diff --git a/drivers/staging/lustre/include/linux/libcfs/bitmap.h b/drivers/staging/lustre/include/linux/libcfs/bitmap.h
index 3f1c37b..f3d4a89 100644
--- a/drivers/staging/lustre/include/linux/libcfs/bitmap.h
+++ b/drivers/staging/lustre/include/linux/libcfs/bitmap.h
@@ -52,11 +52,11 @@
 
 	OBD_ALLOC(ptr, CFS_BITMAP_SIZE(size));
 	if (ptr == NULL)
-		RETURN(ptr);
+		return ptr;
 
 	ptr->size = size;
 
-	RETURN (ptr);
+	return ptr;
 }
 
 #define CFS_FREE_BITMAP(ptr)	OBD_FREE(ptr, CFS_BITMAP_SIZE(ptr->size))
diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h
index 90d7ce6..de8e35b 100644
--- a/drivers/staging/lustre/include/linux/libcfs/curproc.h
+++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h
@@ -49,8 +49,6 @@
  * Implemented in portals/include/libcfs/<os>/
  */
 int    cfs_curproc_groups_nr(void);
-int    current_is_in_group(gid_t group);
-void   cfs_curproc_groups_dump(gid_t *array, int size);
 
 /*
  * Plus, platform-specific constant
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
index 1ab1f2b..687dbab 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
@@ -80,26 +80,10 @@
 #define LERRCHKSUM(hexnum) (((hexnum) & 0xf) ^ ((hexnum) >> 4 & 0xf) ^ \
 			   ((hexnum) >> 8 & 0xf))
 
-
-/*
- * Some (nomina odiosa sunt) platforms define NULL as naked 0. This confuses
- * Lustre RETURN(NULL) macro.
- */
-#if defined(NULL)
-#undef NULL
-#endif
-
-#define NULL ((void *)0)
-
 #define LUSTRE_SRV_LNET_PID      LUSTRE_LNET_PID
 
-
 #include <linux/list.h>
 
-#ifndef cfs_for_each_possible_cpu
-#  error cfs_for_each_possible_cpu is not supported by kernel!
-#endif
-
 /* libcfs tcpip */
 int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask);
 int libcfs_ipif_enumerate(char ***names);
@@ -117,31 +101,6 @@
 int libcfs_sock_read(socket_t *sock, void *buffer, int nob, int timeout);
 void libcfs_sock_release(socket_t *sock);
 
-/* libcfs watchdogs */
-struct lc_watchdog;
-
-/* Add a watchdog which fires after "time" milliseconds of delay.  You have to
- * touch it once to enable it. */
-struct lc_watchdog *lc_watchdog_add(int time,
-				    void (*cb)(pid_t pid, void *),
-				    void *data);
-
-/* Enables a watchdog and resets its timer. */
-void lc_watchdog_touch(struct lc_watchdog *lcw, int timeout);
-#define CFS_GET_TIMEOUT(svc) (max_t(int, obd_timeout,		   \
-			  AT_OFF ? 0 : at_get(&svc->srv_at_estimate)) * \
-			  svc->srv_watchdog_factor)
-
-/* Disable a watchdog; touch it to restart it. */
-void lc_watchdog_disable(struct lc_watchdog *lcw);
-
-/* Clean up the watchdog */
-void lc_watchdog_delete(struct lc_watchdog *lcw);
-
-/* Dump a debug log */
-void lc_watchdog_dumplog(pid_t pid, void *data);
-
-
 /* need both kernel and user-land acceptor */
 #define LNET_ACCEPTOR_MIN_RESERVED_PORT    512
 #define LNET_ACCEPTOR_MAX_RESERVED_PORT    1023
@@ -149,11 +108,6 @@
 /*
  * libcfs pseudo device operations
  *
- * struct psdev_t and
- * misc_register() and
- * misc_deregister() are declared in
- * libcfs/<os>/<os>-prim.h
- *
  * It's just draft now.
  */
 
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
index 6ae7415..c87efb4 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_cpu.h
@@ -75,11 +75,19 @@
 #ifndef __LIBCFS_CPU_H__
 #define __LIBCFS_CPU_H__
 
-#ifndef HAVE_LIBCFS_CPT
+/* any CPU partition */
+#define CFS_CPT_ANY		(-1)
 
-typedef unsigned long		cpumask_t;
-typedef unsigned long		nodemask_t;
-
+#ifdef CONFIG_SMP
+/**
+ * return cpumask of CPU partition \a cpt
+ */
+cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
+/**
+ * print string information of cpt-table
+ */
+int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
+#else /* !CONFIG_SMP */
 struct cfs_cpt_table {
 	/* # of CPU partitions */
 	int			ctb_nparts;
@@ -91,10 +99,18 @@
 	__u64			ctb_version;
 };
 
-#endif /* !HAVE_LIBCFS_CPT */
+static inline cpumask_t *
+cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt)
+{
+       return NULL;
+}
 
-/* any CPU partition */
-#define CFS_CPT_ANY		(-1)
+static inline int
+cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len)
+{
+       return 0;
+}
+#endif /* CONFIG_SMP */
 
 extern struct cfs_cpt_table	*cfs_cpt_table;
 
@@ -107,10 +123,6 @@
  */
 struct cfs_cpt_table *cfs_cpt_table_alloc(unsigned int ncpt);
 /**
- * print string information of cpt-table
- */
-int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len);
-/**
  * return total number of CPU partitions in \a cptab
  */
 int
@@ -124,10 +136,6 @@
  */
 int cfs_cpt_online(struct cfs_cpt_table *cptab, int cpt);
 /**
- * return cpumask of CPU partition \a cpt
- */
-cpumask_t *cfs_cpt_cpumask(struct cfs_cpt_table *cptab, int cpt);
-/**
  * return nodemask of CPU partition \a cpt
  */
 nodemask_t *cfs_cpt_nodemask(struct cfs_cpt_table *cptab, int cpt);
@@ -200,14 +208,6 @@
 #define cfs_cpt_for_each(i, cptab)	\
 	for (i = 0; i < cfs_cpt_number(cptab); i++)
 
-#ifndef __read_mostly
-# define __read_mostly
-#endif
-
-#ifndef ____cacheline_aligned
-#define ____cacheline_aligned
-#endif
-
 int  cfs_cpu_init(void);
 void cfs_cpu_fini(void);
 
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
index 64ca62f..776e9c0 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h
@@ -136,13 +136,13 @@
 /* cfs crypto hash descriptor */
 struct cfs_crypto_hash_desc;
 
-/**     Allocate and initialize desriptor for hash algorithm.
+/**     Allocate and initialize descriptor for hash algorithm.
  *      @param alg	    algorithm id
  *      @param key	    initial value for algorithm, if it is NULL,
  *			    default initial value should be used.
  *      @param key_len	len of initial value
  *      @returns	      pointer to descriptor of hash instance
- *      @retval ERR_PTR(error) when errors occured.
+ *      @retval ERR_PTR(error) when errors occurred.
  */
 struct cfs_crypto_hash_desc*
 	cfs_crypto_hash_init(unsigned char alg,
@@ -175,7 +175,7 @@
  *     @param desc	      hash descriptor
  *     @param hash	      buffer pointer to store hash digest
  *     @param hash_len	  pointer to hash buffer size, if NULL
- *			      destory hash descriptor
+ *			      destroy hash descriptor
  *     @returns		 status of operation
  *     @retval -ENOSPC	  if hash is NULL, or *hash_len less than
  *			      digest size
@@ -195,7 +195,7 @@
 void cfs_crypto_unregister(void);
 
 /**     Return hash speed in Mbytes per second for valid hash algorithm
- *      identifier. If test was unsuccessfull -1 would be return.
+ *      identifier. If test was unsuccessful -1 would be returned.
  */
 int cfs_crypto_hash_speed(unsigned char hash_alg);
 #endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
index dd8ac2f..e6439d1 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h
@@ -262,74 +262,6 @@
 } while (0)
 
 
-/*
- * if rc == NULL, we need to code as RETURN((void *)NULL), otherwise
- * there will be a warning in osx.
- */
-#if defined(__GNUC__)
-
-long libcfs_log_return(struct libcfs_debug_msg_data *, long rc);
-#if BITS_PER_LONG > 32
-#define RETURN(rc)							\
-do {									\
-	EXIT_NESTING;							\
-	if (cfs_cdebug_show(D_TRACE, DEBUG_SUBSYSTEM)) {		\
-		LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_TRACE, NULL);	\
-		return (typeof(rc))libcfs_log_return(&msgdata,		\
-						     (long)(rc));	\
-	}								\
-									\
-	return (rc);							\
-} while (0)
-#else /* BITS_PER_LONG == 32 */
-/* We need an on-stack variable, because we cannot case a 32-bit pointer
- * directly to (long long) without generating a complier warning/error, yet
- * casting directly to (long) will truncate 64-bit return values. The log
- * values will print as 32-bit values, but they always have been. LU-1436
- */
-#define RETURN(rc)							\
-do {									\
-	EXIT_NESTING;							\
-	if (cfs_cdebug_show(D_TRACE, DEBUG_SUBSYSTEM)) {		\
-		typeof(rc) __rc = (rc);					\
-		LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, D_TRACE, NULL);	\
-		libcfs_log_return(&msgdata, (long_ptr_t)__rc);		\
-		return __rc;						\
-	}								\
-									\
-	return (rc);							\
-} while (0)
-#endif /* BITS_PER_LONG > 32 */
-
-#elif defined(_MSC_VER)
-#define RETURN(rc)						      \
-do {								    \
-	CDEBUG(D_TRACE, "Process leaving.\n");			  \
-	EXIT_NESTING;						   \
-	return (rc);						    \
-} while (0)
-#else
-# error "Unkown compiler"
-#endif /* __GNUC__ */
-
-#define ENTRY							   \
-ENTRY_NESTING;							  \
-do {								    \
-	CDEBUG(D_TRACE, "Process entered\n");			   \
-} while (0)
-
-#define EXIT							    \
-do {								    \
-	CDEBUG(D_TRACE, "Process leaving\n");			   \
-	EXIT_NESTING;						   \
-} while(0)
-
-#define RETURN_EXIT							\
-do {									\
-	EXIT;								\
-	return;								\
-} while (0)
-
 extern int libcfs_debug_msg(struct libcfs_debug_msg_data *msgdata,
 			    const char *format1, ...)
 	__attribute__ ((format (printf, 2, 3)));
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
index f6361b3..98f5be2 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
@@ -720,7 +720,7 @@
 
 /*
  * Rehash - Theta is calculated to be the average chained
- * hash depth assuming a perfectly uniform hash funcion.
+ * hash depth assuming a perfectly uniform hash function.
  */
 void cfs_hash_rehash_cancel_locked(cfs_hash_t *hs);
 void cfs_hash_rehash_cancel(cfs_hash_t *hs);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
index 9c40ed9..e6e417a 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_prim.h
@@ -40,10 +40,6 @@
 #ifndef __LIBCFS_PRIM_H__
 #define __LIBCFS_PRIM_H__
 
-#ifndef EXPORT_SYMBOL
-# define EXPORT_SYMBOL(s)
-#endif
-
 /*
  * Schedule
  */
@@ -53,20 +49,20 @@
  * Timer
  */
 typedef  void (cfs_timer_func_t)(ulong_ptr_t);
-void schedule_timeout_and_set_state(cfs_task_state_t, int64_t);
+void schedule_timeout_and_set_state(long, int64_t);
 
 void init_waitqueue_entry_current(wait_queue_t *link);
-int64_t waitq_timedwait(wait_queue_t *, cfs_task_state_t, int64_t);
-void waitq_wait(wait_queue_t *, cfs_task_state_t);
+int64_t waitq_timedwait(wait_queue_t *, long, int64_t);
+void waitq_wait(wait_queue_t *, long);
 void add_wait_queue_exclusive_head(wait_queue_head_t *, wait_queue_t *);
 
-void cfs_init_timer(timer_list_t *t);
-void cfs_timer_init(timer_list_t *t, cfs_timer_func_t *func, void *arg);
-void cfs_timer_done(timer_list_t *t);
-void cfs_timer_arm(timer_list_t *t, cfs_time_t deadline);
-void cfs_timer_disarm(timer_list_t *t);
-int  cfs_timer_is_armed(timer_list_t *t);
-cfs_time_t cfs_timer_deadline(timer_list_t *t);
+void cfs_init_timer(struct timer_list *t);
+void cfs_timer_init(struct timer_list *t, cfs_timer_func_t *func, void *arg);
+void cfs_timer_done(struct timer_list *t);
+void cfs_timer_arm(struct timer_list *t, cfs_time_t deadline);
+void cfs_timer_disarm(struct timer_list *t);
+int  cfs_timer_is_armed(struct timer_list *t);
+cfs_time_t cfs_timer_deadline(struct timer_list *t);
 
 /*
  * Memory
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
index 056caa4..d0d942c 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
@@ -210,7 +210,6 @@
 #define ntohs(x) ___ntohs(x)
 #endif
 
-void libcfs_debug_dumpstack(task_t *tsk);
 void libcfs_run_upcall(char **argv);
 void libcfs_run_lbug_upcall(struct libcfs_debug_msg_data *);
 void libcfs_debug_dumplog(void);
@@ -230,7 +229,7 @@
  */
 void *cfs_percpt_alloc(struct cfs_cpt_table *cptab, unsigned int size);
 /*
- * destory per-cpu-partition variable
+ * destroy per-cpu-partition variable
  */
 void  cfs_percpt_free(void *vars);
 int   cfs_percpt_number(void *vars);
@@ -456,10 +455,6 @@
 /* logical equivalence */
 #define equi(a, b) (!!(a) == !!(b))
 
-#ifndef CFS_CURRENT_TIME
-# define CFS_CURRENT_TIME time(0)
-#endif
-
 /* --------------------------------------------------------------------
  * Light-weight trace
  * Support for temporary event tracing with minimal Heisenberg effect.
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h b/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h
index 4b7ae1c..c204b67 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/kp30.h
@@ -55,7 +55,6 @@
 #include <linux/interrupt.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
 #include <linux/rwsem.h>
@@ -74,34 +73,6 @@
 #include <linux/libcfs/linux/portals_compat25.h>
 
 
-#define prepare_work(wq,cb,cbdata)					    \
-do {									  \
-	INIT_WORK((wq), (void *)(cb));					\
-} while (0)
-
-#define cfs_get_work_data(type,field,data) container_of(data,type,field)
-
-
-#define our_recalc_sigpending(current) recalc_sigpending()
-#define strtok(a,b) strpbrk(a, b)
-#define work_struct_t      struct work_struct
-
-#ifdef CONFIG_SMP
-#else
-#endif
-
-
-#define SEM_COUNT(sem)	  ((sem)->count)
-
-
-/* ------------------------------------------------------------------- */
-
-#define PORTAL_SYMBOL_REGISTER(x)
-#define PORTAL_SYMBOL_UNREGISTER(x)
-
-
-
-
 /******************************************************************************/
 /* Module parameter support */
 #define CFS_MODULE_PARM(name, t, type, perm, desc) \
@@ -111,26 +82,6 @@
 #define CFS_SYSFS_MODULE_PARM  1 /* module parameters accessible via sysfs */
 
 /******************************************************************************/
-
-#if (__GNUC__)
-/* Use the special GNU C __attribute__ hack to have the compiler check the
- * printf style argument string against the actual argument count and
- * types.
- */
-#ifdef printf
-# warning printf has been defined as a macro...
-# undef printf
-#endif
-
-#endif /* __GNUC__ */
-
-# define fprintf(a, format, b...) CDEBUG(D_OTHER, format , ## b)
-# define printf(format, b...) CDEBUG(D_OTHER, format , ## b)
-# define time(a) CURRENT_TIME
-
-# define cfs_num_present_cpus()  num_present_cpus()
-
-/******************************************************************************/
 /* Light-weight trace
  * Support for temporary event tracing with minimal Heisenberg effect. */
 #define LWT_SUPPORT  0
@@ -236,9 +187,13 @@
 # endif
 #endif
 
-# define LI_POISON ((int)0x5a5a5a5a5a5a5a5a)
-# define LL_POISON ((long)0x5a5a5a5a5a5a5a5a)
-# define LP_POISON ((void *)(long)0x5a5a5a5a5a5a5a5a)
+# define LI_POISON 0x5a5a5a5a
+#if BITS_PER_LONG > 32
+# define LL_POISON 0x5a5a5a5a5a5a5a5aL
+#else
+# define LL_POISON 0x5a5a5a5aL
+#endif
+# define LP_POISON ((void *)LL_POISON)
 
 /* this is a bit chunky */
 
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h
index 292a3ba..60ecaf6 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/libcfs.h
@@ -97,9 +97,6 @@
 /* initial pid  */
 #define LUSTRE_LNET_PID	  12345
 
-#define ENTRY_NESTING_SUPPORT (1)
-#define ENTRY_NESTING   do {;} while (0)
-#define EXIT_NESTING   do {;} while (0)
 #define __current_nesting_level() (0)
 
 /**
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h
index 224371c..8dd354d 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-cpu.h
@@ -46,8 +46,6 @@
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
 #include <linux/topology.h>
-#include <linux/version.h>
-
 
 #ifdef CONFIG_SMP
 
@@ -81,15 +79,8 @@
 	nodemask_t			*ctb_nodemask;
 };
 
-void cfs_cpu_core_siblings(int cpu, cpumask_t *mask);
-void cfs_cpu_ht_siblings(int cpu, cpumask_t *mask);
-void cfs_node_to_cpumask(int node, cpumask_t *mask);
-int cfs_cpu_core_nsiblings(int cpu);
-int cfs_cpu_ht_nsiblings(int cpu);
-
 /**
  * comment out definitions for compatible layer
- * #define CFS_CPU_NR			  NR_CPUS
  *
  * typedef cpumask_t			   cfs_cpumask_t;
  *
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h
index 6fbcbf3..d6e00f9 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-lock.h
@@ -52,7 +52,7 @@
  * IMPORTANT !!!!!!!!
  *
  * All locks' declaration are not guaranteed to be initialized,
- * Althought some of they are initialized in Linux. All locks
+ * although some of them are initialized in Linux. All locks
  * declared by CFS_DECL_* should be initialized explicitly.
  */
 
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
index 042a2bc..63efb7b 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
@@ -63,9 +63,9 @@
 #if BITS_PER_LONG == 32
 /* limit to lowmem on 32-bit systems */
 #define NUM_CACHEPAGES \
-	min(num_physpages, 1UL << (30 - PAGE_CACHE_SHIFT) * 3 / 4)
+	min(totalram_pages, 1UL << (30 - PAGE_CACHE_SHIFT) * 3 / 4)
 #else
-#define NUM_CACHEPAGES num_physpages
+#define NUM_CACHEPAGES totalram_pages
 #endif
 
 /*
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h
index a4963a8..1ec4ca1 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-prim.h
@@ -49,7 +49,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/proc_fs.h>
 #include <linux/mm.h>
 #include <linux/timer.h>
@@ -64,43 +63,12 @@
 
 #include <linux/libcfs/linux/linux-time.h>
 
-
-/*
- * CPU
- */
-#ifdef for_each_possible_cpu
-#define cfs_for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
-#elif defined(for_each_cpu)
-#define cfs_for_each_possible_cpu(cpu) for_each_cpu(cpu)
-#endif
-
-#ifdef NR_CPUS
-#else
-#define NR_CPUS     1
-#endif
-
-/*
- * cache
- */
-
-/*
- * IRQs
- */
-
-
-/*
- * Pseudo device register
- */
-typedef struct miscdevice		psdev_t;
-
 /*
  * Sysctl register
  */
 typedef struct ctl_table		ctl_table_t;
 typedef struct ctl_table_header		ctl_table_header_t;
 
-#define cfs_register_sysctl_table(t, a) register_sysctl_table(t)
-
 #define DECLARE_PROC_HANDLER(name)		      \
 static int					      \
 LL_PROC_PROTO(name)				     \
@@ -112,130 +80,4 @@
 				 __##name);	     \
 }
 
-/*
- * Symbol register
- */
-#define cfs_symbol_register(s, p)       do {} while(0)
-#define cfs_symbol_unregister(s)	do {} while(0)
-#define cfs_symbol_get(s)	       symbol_get(s)
-#define cfs_symbol_put(s)	       symbol_put(s)
-
-typedef struct module module_t;
-
-/*
- * Proc file system APIs
- */
-typedef struct proc_dir_entry	   proc_dir_entry_t;
-
-/*
- * Wait Queue
- */
-
-
-typedef long			    cfs_task_state_t;
-
-#define CFS_DECL_WAITQ(wq)		DECLARE_WAIT_QUEUE_HEAD(wq)
-
-/*
- * Task struct
- */
-typedef struct task_struct	      task_t;
-#define DECL_JOURNAL_DATA	   void *journal_info
-#define PUSH_JOURNAL		do {    \
-	journal_info = current->journal_info;   \
-	current->journal_info = NULL;	   \
-	} while(0)
-#define POP_JOURNAL		 do {    \
-	current->journal_info = journal_info;   \
-	} while(0)
-
-/* Module interfaces */
-#define cfs_module(name, version, init, fini) \
-	module_init(init);		    \
-	module_exit(fini)
-
-/*
- * Signal
- */
-
-/*
- * Timer
- */
-typedef struct timer_list timer_list_t;
-
-
-#ifndef wait_event_timeout /* Only for RHEL3 2.4.21 kernel */
-#define __wait_event_timeout(wq, condition, timeout, ret)	\
-do {							     \
-	int __ret = 0;					   \
-	if (!(condition)) {				      \
-		wait_queue_t __wait;			     \
-		unsigned long expire;			    \
-								 \
-		init_waitqueue_entry(&__wait, current);	  \
-		expire = timeout + jiffies;		      \
-		add_wait_queue(&wq, &__wait);		    \
-		for (;;) {				       \
-			set_current_state(TASK_UNINTERRUPTIBLE); \
-			if (condition)			   \
-				break;			   \
-			if (jiffies > expire) {		  \
-				ret = jiffies - expire;	  \
-				break;			   \
-			}					\
-			schedule_timeout(timeout);	       \
-		}						\
-		current->state = TASK_RUNNING;		   \
-		remove_wait_queue(&wq, &__wait);		 \
-	}							\
-} while (0)
-/*
-   retval == 0; condition met; we're good.
-   retval > 0; timed out.
-*/
-#define cfs_waitq_wait_event_timeout(wq, condition, timeout, ret)    \
-do {								 \
-	ret = 0;						     \
-	if (!(condition))					    \
-		__wait_event_timeout(wq, condition, timeout, ret);   \
-} while (0)
-#else
-#define cfs_waitq_wait_event_timeout(wq, condition, timeout, ret)    \
-	ret = wait_event_timeout(wq, condition, timeout)
-#endif
-
-#define cfs_waitq_wait_event_interruptible_timeout(wq, c, timeout, ret) \
-	ret = wait_event_interruptible_timeout(wq, c, timeout)
-
-/*
- * atomic
- */
-
-
-#define cfs_atomic_add_unless(atom, a, u)    atomic_add_unless(atom, a, u)
-#define cfs_atomic_cmpxchg(atom, old, nv)    atomic_cmpxchg(atom, old, nv)
-
-/*
- * membar
- */
-
-
-/*
- * interrupt
- */
-
-
-/*
- * might_sleep
- */
-
-/*
- * group_info
- */
-typedef struct group_info group_info_t;
-
-
-/*
- * Random bytes
- */
 #endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h
index 687f33f..7a8d006 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-tcpip.h
@@ -48,21 +48,6 @@
 
 #include <net/sock.h>
 
-#ifndef HIPQUAD
-// XXX Should just kill all users
-#if defined(__LITTLE_ENDIAN)
-#define HIPQUAD(addr) \
-	((unsigned char *)&addr)[3], \
-	((unsigned char *)&addr)[2], \
-	((unsigned char *)&addr)[1], \
-	((unsigned char *)&addr)[0]
-#elif defined(__BIG_ENDIAN)
-#define HIPQUAD NIPQUAD
-#else
-#error "Please fix asm/byteorder.h"
-#endif /* __LITTLE_ENDIAN */
-#endif
-
 typedef struct socket   socket_t;
 
 #define SOCK_SNDBUF(so)	 ((so)->sk->sk_sndbuf)
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
index 4a48b91..a386d1b 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h
@@ -91,7 +91,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/time.h>
 #include <asm/div64.h>
 
diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h b/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h
index 132a4be..fe4c63f 100644
--- a/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h
+++ b/drivers/staging/lustre/include/linux/libcfs/linux/portals_compat25.h
@@ -95,20 +95,5 @@
 		      loff_t *ppos, void *buffer, size_t *lenp,
 		      int (*handler)(void *data, int write,
 				     loff_t pos, void *buffer, int len));
-/*
- * CPU
- */
-#ifdef for_each_possible_cpu
-#define cfs_for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
-#elif defined(for_each_cpu)
-#define cfs_for_each_possible_cpu(cpu) for_each_cpu(cpu)
-#endif
-
-#ifdef NR_CPUS
-#else
-#define NR_CPUS     1
-#endif
-
-#define cfs_register_sysctl_table(t, a) register_sysctl_table(t)
 
 #endif /* _PORTALS_COMPAT_H */
diff --git a/drivers/staging/lustre/include/linux/libcfs/lucache.h b/drivers/staging/lustre/include/linux/libcfs/lucache.h
index 7ae36fc..9668b39 100644
--- a/drivers/staging/lustre/include/linux/libcfs/lucache.h
+++ b/drivers/staging/lustre/include/linux/libcfs/lucache.h
@@ -77,7 +77,7 @@
 	struct upcall_cache_entry *mi_uc_entry;
 	uid_t		      mi_uid;
 	gid_t		      mi_gid;
-	group_info_t	  *mi_ginfo;
+	struct group_info	*mi_ginfo;
 	int			mi_nperms;
 	struct md_perm	    *mi_perms;
 };
diff --git a/drivers/staging/lustre/include/linux/libcfs/params_tree.h b/drivers/staging/lustre/include/linux/libcfs/params_tree.h
index 3f18a44..78a2c4e 100644
--- a/drivers/staging/lustre/include/linux/libcfs/params_tree.h
+++ b/drivers/staging/lustre/include/linux/libcfs/params_tree.h
@@ -54,7 +54,6 @@
 typedef struct seq_file			 cfs_seq_file_t;
 typedef struct seq_operations		   cfs_seq_ops_t;
 typedef struct file_operations		  cfs_param_file_ops_t;
-typedef module_t			   *cfs_param_module_t;
 typedef struct proc_dir_entry		   cfs_param_dentry_t;
 typedef struct poll_table_struct		cfs_poll_table_t;
 #define CFS_PARAM_MODULE			THIS_MODULE
@@ -115,11 +114,10 @@
 	int   (*show) (cfs_seq_file_t *m, void *v);
 } cfs_seq_ops_t;
 
-typedef void *cfs_param_module_t;
 typedef void *cfs_poll_table_t;
 
 typedef struct cfs_param_file_ops {
-	cfs_param_module_t owner;
+	struct module *owner;
 	int (*open) (cfs_inode_t *, struct file *);
 	loff_t (*llseek)(struct file *, loff_t, int);
 	int (*release) (cfs_inode_t *, cfs_param_file_t *);
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h
index 86428d4..e579e7e 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-types.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h
@@ -181,11 +181,11 @@
 	lnet_nid_t		msg_from;
 	__u32			msg_type;
 
-	/* commited for sending */
+	/* committed for sending */
 	unsigned int		msg_tx_committed:1;
 	/* CPT # this message committed for sending */
 	unsigned int		msg_tx_cpt:15;
-	/* commited for receiving */
+	/* committed for receiving */
 	unsigned int		msg_rx_committed:1;
 	/* CPT # this message committed for receiving */
 	unsigned int		msg_rx_cpt:15;
@@ -619,7 +619,7 @@
 	unsigned int		ptl_index;	/* portal ID, reserved */
 	/* flags on this portal: lazy, unique... */
 	unsigned int		ptl_options;
-	/* list of messags which are stealing buffer */
+	/* list of messages which are stealing buffer */
 	struct list_head		ptl_msg_stealing;
 	/* messages blocking for MD */
 	struct list_head		ptl_msg_delayed;
diff --git a/drivers/staging/lustre/include/linux/lnet/lnetst.h b/drivers/staging/lustre/include/linux/lnet/lnetst.h
index d90f94e..e060599 100644
--- a/drivers/staging/lustre/include/linux/lnet/lnetst.h
+++ b/drivers/staging/lustre/include/linux/lnet/lnetst.h
@@ -59,7 +59,7 @@
 #define LSTIO_SESSION_INFO      0xC03	   /* query session */
 #define LSTIO_GROUP_ADD	 0xC10	   /* add group */
 #define LSTIO_GROUP_LIST	0xC11	   /* list all groups in session */
-#define LSTIO_GROUP_INFO	0xC12	   /* query defailt infomation of specified group */
+#define LSTIO_GROUP_INFO	0xC12	   /* query default information of specified group */
 #define LSTIO_GROUP_DEL	 0xC13	   /* delete group */
 #define LSTIO_NODES_ADD	 0xC14	   /* add nodes to specified group */
 #define LSTIO_GROUP_UPDATE      0xC15	   /* update group */
diff --git a/drivers/staging/lustre/include/linux/lnet/ptllnd.h b/drivers/staging/lustre/include/linux/lnet/ptllnd.h
index fc1ce8e..564f5d3 100644
--- a/drivers/staging/lustre/include/linux/lnet/ptllnd.h
+++ b/drivers/staging/lustre/include/linux/lnet/ptllnd.h
@@ -68,7 +68,7 @@
 /* Can compare handles directly on Cray Portals */
 #define PtlHandleIsEqual(a,b) ((a) == (b))
 
-/* Diffrent error types on Cray Portals*/
+/* Different error types on Cray Portals*/
 #define ptl_err_t ptl_ni_fail_t
 
 /*
@@ -76,7 +76,7 @@
  * maximum is limited only by memory and size of the
  * int parameters (2^31-1).
  * Lustre only really require that the underyling
- * implemenation to support at least LNET_MAX_IOV,
+ * implementation to support at least LNET_MAX_IOV,
  * so for Cray portals we can safely just use that
  * value here.
  *
diff --git a/drivers/staging/lustre/lnet/Makefile b/drivers/staging/lustre/lnet/Makefile
index 374212b..f6f03e3 100644
--- a/drivers/staging/lustre/lnet/Makefile
+++ b/drivers/staging/lustre/lnet/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_LNET) := klnds/ lnet/ selftest/
+obj-$(CONFIG_LNET) += lnet/ klnds/ selftest/
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 29a9794..86397f9 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -702,6 +702,8 @@
 		return 0;
 
 	mask = cfs_cpt_cpumask(lnet_cpt_table(), cpt);
+	if (mask == NULL)
+		return 0;
 
 	/* hash NID to CPU id in this partition... */
 	off = do_div(nid, cpus_weight(*mask));
@@ -2574,8 +2576,8 @@
 	rc = rdma_resolve_addr(cmid, (struct sockaddr *)&srcaddr,
 			       (struct sockaddr *)&dstaddr, 1);
 	if (rc != 0 || cmid->device == NULL) {
-		CERROR("Failed to bind %s:%u.%u.%u.%u to device(%p): %d\n",
-		       dev->ibd_ifname, HIPQUAD(dev->ibd_ifip),
+		CERROR("Failed to bind %s:%pI4h to device(%p): %d\n",
+		       dev->ibd_ifname, &dev->ibd_ifip,
 		       cmid->device, rc);
 		rdma_destroy_id(cmid);
 		return rc;
@@ -2647,8 +2649,8 @@
 	/* Bind to failover device or port */
 	rc = rdma_bind_addr(cmid, (struct sockaddr *)&addr);
 	if (rc != 0 || cmid->device == NULL) {
-		CERROR("Failed to bind %s:%u.%u.%u.%u to device(%p): %d\n",
-		       dev->ibd_ifname, HIPQUAD(dev->ibd_ifip),
+		CERROR("Failed to bind %s:%pI4h to device(%p): %d\n",
+		       dev->ibd_ifname, &dev->ibd_ifip,
 		       cmid->device, rc);
 		rdma_destroy_id(cmid);
 		goto out;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index e4626bf..938df0c 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -53,7 +53,6 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/stat.h>
 #include <linux/list.h>
 #include <linux/kmod.h>
 #include <linux/sysctl.h>
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index cc62321..086ca3d 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -1319,9 +1319,9 @@
 	}
 
 	LASSERT (cmid->device != NULL);
-	CDEBUG(D_NET, "%s: connection bound to %s:%u.%u.%u.%u:%s\n",
+	CDEBUG(D_NET, "%s: connection bound to %s:%pI4h:%s\n",
 	       libcfs_nid2str(peer->ibp_nid), dev->ibd_ifname,
-	       HIPQUAD(dev->ibd_ifip), cmid->device->name);
+	       &dev->ibd_ifip, cmid->device->name);
 
 	return;
 
@@ -1802,7 +1802,7 @@
 int
 kiblnd_thread_start(int (*fn)(void *arg), void *arg, char *name)
 {
-	task_t *task = kthread_run(fn, arg, name);
+	struct task_struct *task = kthread_run(fn, arg, name);
 
 	if (IS_ERR(task))
 		return PTR_ERR(task);
@@ -2209,8 +2209,8 @@
 	if (*kiblnd_tunables.kib_require_priv_port &&
 	    ntohs(peer_addr->sin_port) >= PROT_SOCK) {
 		__u32 ip = ntohl(peer_addr->sin_addr.s_addr);
-		CERROR("Peer's port (%u.%u.%u.%u:%hu) is not privileged\n",
-		       HIPQUAD(ip), ntohs(peer_addr->sin_port));
+		CERROR("Peer's port (%pI4h:%hu) is not privileged\n",
+		       &ip, ntohs(peer_addr->sin_port));
 		goto failed;
 	}
 
@@ -2254,11 +2254,11 @@
 	if (ni == NULL ||			 /* no matching net */
 	    ni->ni_nid != reqmsg->ibm_dstnid ||   /* right NET, wrong NID! */
 	    net->ibn_dev != ibdev) {	      /* wrong device */
-		CERROR("Can't accept %s on %s (%s:%d:%u.%u.%u.%u): "
+		CERROR("Can't accept %s on %s (%s:%d:%pI4h): "
 		       "bad dst nid %s\n", libcfs_nid2str(nid),
 		       ni == NULL ? "NA" : libcfs_nid2str(ni->ni_nid),
 		       ibdev->ibd_ifname, ibdev->ibd_nnets,
-		       HIPQUAD(ibdev->ibd_ifip),
+		       &ibdev->ibd_ifip,
 		       libcfs_nid2str(reqmsg->ibm_dstnid));
 
 		goto failed;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c
index e21028b..92dc567 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c
@@ -404,7 +404,7 @@
 			      sizeof(ipif_basename_space));
 
 	kiblnd_tunables.kib_sysctl =
-		cfs_register_sysctl_table(kiblnd_top_ctl_table, 0);
+		register_sysctl_table(kiblnd_top_ctl_table);
 
 	if (kiblnd_tunables.kib_sysctl == NULL)
 		CWARN("Can't setup /proc tunables\n");
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index c826bf9..6825b45 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -334,17 +334,17 @@
 	if (route->ksnr_myipaddr != conn->ksnc_myipaddr) {
 		if (route->ksnr_myipaddr == 0) {
 			/* route wasn't bound locally yet (the initial route) */
-			CDEBUG(D_NET, "Binding %s %u.%u.%u.%u to %u.%u.%u.%u\n",
+			CDEBUG(D_NET, "Binding %s %pI4h to %pI4h\n",
 			       libcfs_id2str(peer->ksnp_id),
-			       HIPQUAD(route->ksnr_ipaddr),
-			       HIPQUAD(conn->ksnc_myipaddr));
+			       &route->ksnr_ipaddr,
+			       &conn->ksnc_myipaddr);
 		} else {
-			CDEBUG(D_NET, "Rebinding %s %u.%u.%u.%u from "
-			       "%u.%u.%u.%u to %u.%u.%u.%u\n",
+			CDEBUG(D_NET, "Rebinding %s %pI4h from "
+			       "%pI4h to %pI4h\n",
 			       libcfs_id2str(peer->ksnp_id),
-			       HIPQUAD(route->ksnr_ipaddr),
-			       HIPQUAD(route->ksnr_myipaddr),
-			       HIPQUAD(conn->ksnc_myipaddr));
+			       &route->ksnr_ipaddr,
+			       &route->ksnr_myipaddr,
+			       &conn->ksnc_myipaddr);
 
 			iface = ksocknal_ip2iface(route->ksnr_peer->ksnp_ni,
 						  route->ksnr_myipaddr);
@@ -384,9 +384,9 @@
 		route2 = list_entry(tmp, ksock_route_t, ksnr_list);
 
 		if (route2->ksnr_ipaddr == route->ksnr_ipaddr) {
-			CERROR ("Duplicate route %s %u.%u.%u.%u\n",
+			CERROR("Duplicate route %s %pI4h\n",
 				libcfs_id2str(peer->ksnp_id),
-				HIPQUAD(route->ksnr_ipaddr));
+				&route->ksnr_ipaddr);
 			LBUG();
 		}
 	}
@@ -982,8 +982,8 @@
 	LIBCFS_ALLOC(cr, sizeof(*cr));
 	if (cr == NULL) {
 		LCONSOLE_ERROR_MSG(0x12f, "Dropping connection request from "
-				   "%u.%u.%u.%u: memory exhausted\n",
-				   HIPQUAD(peer_ip));
+				   "%pI4h: memory exhausted\n",
+				   &peer_ip);
 		return -ENOMEM;
 	}
 
@@ -1236,10 +1236,10 @@
 	 * code below probably isn't going to work. */
 	if (active &&
 	    route->ksnr_ipaddr != conn->ksnc_ipaddr) {
-		CERROR("Route %s %u.%u.%u.%u connected to %u.%u.%u.%u\n",
+		CERROR("Route %s %pI4h connected to %pI4h\n",
 		       libcfs_id2str(peer->ksnp_id),
-		       HIPQUAD(route->ksnr_ipaddr),
-		       HIPQUAD(conn->ksnc_ipaddr));
+		       &route->ksnr_ipaddr,
+		       &conn->ksnc_ipaddr);
 	}
 
 	/* Search for a route corresponding to the new connection and
@@ -1297,10 +1297,10 @@
 	 *	socket callbacks.
 	 */
 
-	CDEBUG(D_NET, "New conn %s p %d.x %u.%u.%u.%u -> %u.%u.%u.%u/%d"
+	CDEBUG(D_NET, "New conn %s p %d.x %pI4h -> %pI4h/%d"
 	       " incarnation:"LPD64" sched[%d:%d]\n",
 	       libcfs_id2str(peerid), conn->ksnc_proto->pro_version,
-	       HIPQUAD(conn->ksnc_myipaddr), HIPQUAD(conn->ksnc_ipaddr),
+	       &conn->ksnc_myipaddr, &conn->ksnc_ipaddr,
 	       conn->ksnc_port, incarnation, cpt,
 	       (int)(sched - &sched->kss_info->ksi_scheds[0]));
 
@@ -1441,7 +1441,7 @@
 
 		conn->ksnc_route = NULL;
 
-#if 0	   /* irrelevent with only eager routes */
+#if 0	   /* irrelevant with only eager routes */
 		/* make route least favourite */
 		list_del (&route->ksnr_list);
 		list_add_tail (&route->ksnr_list, &peer->ksnp_routes);
@@ -1496,7 +1496,7 @@
 
 	/* There has been a connection failure or comms error; but I'll only
 	 * tell LNET I think the peer is dead if it's to another kernel and
-	 * there are no connections or connection attempts in existance. */
+	 * there are no connections or connection attempts in existence. */
 
 	read_lock(&ksocknal_data.ksnd_global_lock);
 
@@ -1648,10 +1648,10 @@
 		last_rcv = conn->ksnc_rx_deadline -
 			   cfs_time_seconds(*ksocknal_tunables.ksnd_timeout);
 		CERROR("Completing partial receive from %s[%d]"
-		       ", ip %d.%d.%d.%d:%d, with error, wanted: %d, left: %d, "
+		       ", ip %pI4h:%d, with error, wanted: %d, left: %d, "
 		       "last alive is %ld secs ago\n",
 		       libcfs_id2str(conn->ksnc_peer->ksnp_id), conn->ksnc_type,
-		       HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port,
+		       &conn->ksnc_ipaddr, conn->ksnc_port,
 		       conn->ksnc_rx_nob_wanted, conn->ksnc_rx_nob_left,
 		       cfs_duration_sec(cfs_time_sub(cfs_time_current(),
 					last_rcv)));
@@ -1661,25 +1661,25 @@
 	case SOCKNAL_RX_LNET_HEADER:
 		if (conn->ksnc_rx_started)
 			CERROR("Incomplete receive of lnet header from %s"
-			       ", ip %d.%d.%d.%d:%d, with error, protocol: %d.x.\n",
+			       ", ip %pI4h:%d, with error, protocol: %d.x.\n",
 			       libcfs_id2str(conn->ksnc_peer->ksnp_id),
-			       HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port,
+			       &conn->ksnc_ipaddr, conn->ksnc_port,
 			       conn->ksnc_proto->pro_version);
 		break;
 	case SOCKNAL_RX_KSM_HEADER:
 		if (conn->ksnc_rx_started)
 			CERROR("Incomplete receive of ksock message from %s"
-			       ", ip %d.%d.%d.%d:%d, with error, protocol: %d.x.\n",
+			       ", ip %pI4h:%d, with error, protocol: %d.x.\n",
 			       libcfs_id2str(conn->ksnc_peer->ksnp_id),
-			       HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port,
+			       &conn->ksnc_ipaddr, conn->ksnc_port,
 			       conn->ksnc_proto->pro_version);
 		break;
 	case SOCKNAL_RX_SLOP:
 		if (conn->ksnc_rx_started)
 			CERROR("Incomplete receive of slops from %s"
-			       ", ip %d.%d.%d.%d:%d, with error\n",
+			       ", ip %pI4h:%d, with error\n",
 			       libcfs_id2str(conn->ksnc_peer->ksnp_id),
-			       HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+			       &conn->ksnc_ipaddr, conn->ksnc_port);
 	       break;
 	default:
 		LBUG ();
@@ -2358,7 +2358,7 @@
 	/* The incarnation number is the time this module loaded and it
 	 * identifies this particular instance of the socknal.  Hopefully
 	 * we won't be able to reboot more frequently than 1MHz for the
-	 * forseeable future :) */
+	 * foreseeable future :) */
 
 	do_gettimeofday(&tv);
 
@@ -2898,5 +2898,7 @@
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Kernel TCP Socket LND v3.0.0");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("3.0.0");
 
-cfs_module(ksocknal, "3.0.0", ksocknal_module_init, ksocknal_module_fini);
+module_init(ksocknal_module_init);
+module_exit(ksocknal_module_fini);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index ad5e241..2c581b7 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -343,7 +343,6 @@
 	 * Caller checks ksnc_rx_nob_wanted to determine
 	 * progress/completion. */
 	int     rc;
-	ENTRY;
 
 	if (ksocknal_data.ksnd_stall_rx != 0) {
 		cfs_pause(cfs_time_seconds (ksocknal_data.ksnd_stall_rx));
@@ -381,7 +380,7 @@
 	}
 
 	ksocknal_connsock_decref(conn);
-	RETURN (rc);
+	return rc;
 }
 
 void
@@ -389,7 +388,6 @@
 {
 	lnet_msg_t  *lnetmsg = tx->tx_lnetmsg;
 	int	  rc = (tx->tx_resid == 0 && !tx->tx_zc_aborted) ? 0 : -EIO;
-	ENTRY;
 
 	LASSERT(ni != NULL || tx->tx_conn != NULL);
 
@@ -402,8 +400,6 @@
 	ksocknal_free_tx (tx);
 	if (lnetmsg != NULL) /* KSOCK_MSG_NOOP go without lnetmsg */
 		lnet_finalize (ni, lnetmsg, rc);
-
-	EXIT;
 }
 
 void
@@ -553,21 +549,21 @@
 	if (!conn->ksnc_closing) {
 		switch (rc) {
 		case -ECONNRESET:
-			LCONSOLE_WARN("Host %u.%u.%u.%u reset our connection "
+			LCONSOLE_WARN("Host %pI4h reset our connection "
 				      "while we were sending data; it may have "
 				      "rebooted.\n",
-				      HIPQUAD(conn->ksnc_ipaddr));
+				      &conn->ksnc_ipaddr);
 			break;
 		default:
 			LCONSOLE_WARN("There was an unexpected network error "
-				      "while writing to %u.%u.%u.%u: %d.\n",
-				      HIPQUAD(conn->ksnc_ipaddr), rc);
+				      "while writing to %pI4h: %d.\n",
+				      &conn->ksnc_ipaddr, rc);
 			break;
 		}
 		CDEBUG(D_NET, "[%p] Error %d on write to %s"
-		       " ip %d.%d.%d.%d:%d\n", conn, rc,
+		       " ip %pI4h:%d\n", conn, rc,
 		       libcfs_id2str(conn->ksnc_peer->ksnp_id),
-		       HIPQUAD(conn->ksnc_ipaddr),
+		       &conn->ksnc_ipaddr,
 		       conn->ksnc_port);
 	}
 
@@ -700,9 +696,9 @@
 	 * ksnc_sock... */
 	LASSERT(!conn->ksnc_closing);
 
-	CDEBUG (D_NET, "Sending to %s ip %d.%d.%d.%d:%d\n",
+	CDEBUG(D_NET, "Sending to %s ip %pI4h:%d\n",
 		libcfs_id2str(conn->ksnc_peer->ksnp_id),
-		HIPQUAD(conn->ksnc_ipaddr),
+		&conn->ksnc_ipaddr,
 		conn->ksnc_port);
 
 	ksocknal_tx_prep(conn, tx);
@@ -801,9 +797,9 @@
 		if (!(route->ksnr_retry_interval == 0 || /* first attempt */
 		      cfs_time_aftereq(now, route->ksnr_timeout))) {
 			CDEBUG(D_NET,
-			       "Too soon to retry route %u.%u.%u.%u "
+			       "Too soon to retry route %pI4h "
 			       "(cnted %d, interval %ld, %ld secs later)\n",
-			       HIPQUAD(route->ksnr_ipaddr),
+			       &route->ksnr_ipaddr,
 			       route->ksnr_connected,
 			       route->ksnr_retry_interval,
 			       cfs_duration_sec(route->ksnr_timeout - now));
@@ -1009,7 +1005,7 @@
 int
 ksocknal_thread_start(int (*fn)(void *arg), void *arg, char *name)
 {
-	task_t *task = kthread_run(fn, arg, name);
+	struct task_struct *task = kthread_run(fn, arg, name);
 
 	if (IS_ERR(task))
 		return PTR_ERR(task);
@@ -1120,7 +1116,7 @@
 	LASSERT (atomic_read(&conn->ksnc_conn_refcount) > 0);
 
 	/* NB: sched lock NOT held */
-	/* SOCKNAL_RX_LNET_HEADER is here for backward compatability */
+	/* SOCKNAL_RX_LNET_HEADER is here for backward compatibility */
 	LASSERT (conn->ksnc_rx_state == SOCKNAL_RX_KSM_HEADER ||
 		 conn->ksnc_rx_state == SOCKNAL_RX_LNET_PAYLOAD ||
 		 conn->ksnc_rx_state == SOCKNAL_RX_LNET_HEADER ||
@@ -1133,17 +1129,17 @@
 			LASSERT (rc != -EAGAIN);
 
 			if (rc == 0)
-				CDEBUG (D_NET, "[%p] EOF from %s"
-					" ip %d.%d.%d.%d:%d\n", conn,
+				CDEBUG(D_NET, "[%p] EOF from %s"
+					" ip %pI4h:%d\n", conn,
 					libcfs_id2str(conn->ksnc_peer->ksnp_id),
-					HIPQUAD(conn->ksnc_ipaddr),
+					&conn->ksnc_ipaddr,
 					conn->ksnc_port);
 			else if (!conn->ksnc_closing)
-				CERROR ("[%p] Error %d on read from %s"
-					" ip %d.%d.%d.%d:%d\n",
+				CERROR("[%p] Error %d on read from %s"
+					" ip %pI4h:%d\n",
 					conn, rc,
 					libcfs_id2str(conn->ksnc_peer->ksnp_id),
-					HIPQUAD(conn->ksnc_ipaddr),
+					&conn->ksnc_ipaddr,
 					conn->ksnc_port);
 
 			/* it's not an error if conn is being closed */
@@ -1562,7 +1558,6 @@
 void ksocknal_read_callback (ksock_conn_t *conn)
 {
 	ksock_sched_t *sched;
-	ENTRY;
 
 	sched = conn->ksnc_scheduler;
 
@@ -1580,8 +1575,6 @@
 		wake_up (&sched->kss_waitq);
 	}
 	spin_unlock_bh(&sched->kss_lock);
-
-	EXIT;
 }
 
 /*
@@ -1591,7 +1584,6 @@
 void ksocknal_write_callback (ksock_conn_t *conn)
 {
 	ksock_sched_t *sched;
-	ENTRY;
 
 	sched = conn->ksnc_scheduler;
 
@@ -1611,8 +1603,6 @@
 	}
 
 	spin_unlock_bh(&sched->kss_lock);
-
-	EXIT;
 }
 
 ksock_proto_t *
@@ -1722,8 +1712,8 @@
 
 	rc = libcfs_sock_read(sock, &hello->kshm_magic, sizeof (hello->kshm_magic), timeout);
 	if (rc != 0) {
-		CERROR ("Error %d reading HELLO from %u.%u.%u.%u\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr));
+		CERROR("Error %d reading HELLO from %pI4h\n",
+			rc, &conn->ksnc_ipaddr);
 		LASSERT (rc < 0);
 		return rc;
 	}
@@ -1732,18 +1722,18 @@
 	    hello->kshm_magic != __swab32(LNET_PROTO_MAGIC) &&
 	    hello->kshm_magic != le32_to_cpu (LNET_PROTO_TCP_MAGIC)) {
 		/* Unexpected magic! */
-		CERROR ("Bad magic(1) %#08x (%#08x expected) from "
-			"%u.%u.%u.%u\n", __cpu_to_le32 (hello->kshm_magic),
+		CERROR("Bad magic(1) %#08x (%#08x expected) from "
+			"%pI4h\n", __cpu_to_le32 (hello->kshm_magic),
 			LNET_PROTO_TCP_MAGIC,
-			HIPQUAD(conn->ksnc_ipaddr));
+			&conn->ksnc_ipaddr);
 		return -EPROTO;
 	}
 
 	rc = libcfs_sock_read(sock, &hello->kshm_version,
 			      sizeof(hello->kshm_version), timeout);
 	if (rc != 0) {
-		CERROR ("Error %d reading HELLO from %u.%u.%u.%u\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr));
+		CERROR("Error %d reading HELLO from %pI4h\n",
+			rc, &conn->ksnc_ipaddr);
 		LASSERT (rc < 0);
 		return rc;
 	}
@@ -1763,10 +1753,10 @@
 			ksocknal_send_hello(ni, conn, ni->ni_nid, hello);
 		}
 
-		CERROR ("Unknown protocol version (%d.x expected)"
-			" from %u.%u.%u.%u\n",
+		CERROR("Unknown protocol version (%d.x expected)"
+			" from %pI4h\n",
 			conn->ksnc_proto->pro_version,
-			HIPQUAD(conn->ksnc_ipaddr));
+			&conn->ksnc_ipaddr);
 
 		return -EPROTO;
 	}
@@ -1777,8 +1767,8 @@
 	/* receive the rest of hello message anyway */
 	rc = conn->ksnc_proto->pro_recv_hello(conn, hello, timeout);
 	if (rc != 0) {
-		CERROR("Error %d reading or checking hello from from %u.%u.%u.%u\n",
-		       rc, HIPQUAD(conn->ksnc_ipaddr));
+		CERROR("Error %d reading or checking hello from from %pI4h\n",
+		       rc, &conn->ksnc_ipaddr);
 		LASSERT (rc < 0);
 		return rc;
 	}
@@ -1787,7 +1777,7 @@
 
 	if (hello->kshm_src_nid == LNET_NID_ANY) {
 		CERROR("Expecting a HELLO hdr with a NID, but got LNET_NID_ANY"
-		       "from %u.%u.%u.%u\n", HIPQUAD(conn->ksnc_ipaddr));
+		       "from %pI4h\n", &conn->ksnc_ipaddr);
 		return -EPROTO;
 	}
 
@@ -1807,9 +1797,9 @@
 		/* peer determines type */
 		conn->ksnc_type = ksocknal_invert_type(hello->kshm_ctype);
 		if (conn->ksnc_type == SOCKLND_CONN_NONE) {
-			CERROR ("Unexpected type %d from %s ip %u.%u.%u.%u\n",
+			CERROR("Unexpected type %d from %s ip %pI4h\n",
 				hello->kshm_ctype, libcfs_id2str(*peerid),
-				HIPQUAD(conn->ksnc_ipaddr));
+				&conn->ksnc_ipaddr);
 			return -EPROTO;
 		}
 
@@ -1819,11 +1809,11 @@
 	if (peerid->pid != recv_id.pid ||
 	    peerid->nid != recv_id.nid) {
 		LCONSOLE_ERROR_MSG(0x130, "Connected successfully to %s on host"
-				   " %u.%u.%u.%u, but they claimed they were "
+				   " %pI4h, but they claimed they were "
 				   "%s; please check your Lustre "
 				   "configuration.\n",
 				   libcfs_id2str(*peerid),
-				   HIPQUAD(conn->ksnc_ipaddr),
+				   &conn->ksnc_ipaddr,
 				   libcfs_id2str(recv_id));
 		return -EPROTO;
 	}
@@ -1834,9 +1824,9 @@
 	}
 
 	if (ksocknal_invert_type(hello->kshm_ctype) != conn->ksnc_type) {
-		CERROR ("Mismatched types: me %d, %s ip %u.%u.%u.%u %d\n",
+		CERROR("Mismatched types: me %d, %s ip %pI4h %d\n",
 			conn->ksnc_type, libcfs_id2str(*peerid),
-			HIPQUAD(conn->ksnc_ipaddr),
+			&conn->ksnc_ipaddr,
 			hello->kshm_ctype);
 		return -EPROTO;
 	}
@@ -1995,7 +1985,7 @@
 		list_splice_init(&peer->ksnp_tx_queue, &zombies);
 	}
 
-#if 0	   /* irrelevent with only eager routes */
+#if 0	   /* irrelevant with only eager routes */
 	if (!route->ksnr_deleted) {
 		/* make this route least-favourite for re-selection */
 		list_del(&route->ksnr_list);
@@ -2208,8 +2198,8 @@
 				/* consecutive retry */
 				if (cons_retry++ > SOCKNAL_INSANITY_RECONN) {
 					CWARN("massive consecutive "
-					      "re-connecting to %u.%u.%u.%u\n",
-					      HIPQUAD(route->ksnr_ipaddr));
+					      "re-connecting to %pI4h\n",
+					      &route->ksnr_ipaddr);
 					cons_retry = 0;
 				}
 			} else {
@@ -2274,26 +2264,26 @@
 			switch (error) {
 			case ECONNRESET:
 				CNETERR("A connection with %s "
-					"(%u.%u.%u.%u:%d) was reset; "
+					"(%pI4h:%d) was reset; "
 					"it may have rebooted.\n",
 					libcfs_id2str(peer->ksnp_id),
-					HIPQUAD(conn->ksnc_ipaddr),
+					&conn->ksnc_ipaddr,
 					conn->ksnc_port);
 				break;
 			case ETIMEDOUT:
 				CNETERR("A connection with %s "
-					"(%u.%u.%u.%u:%d) timed out; the "
+					"(%pI4h:%d) timed out; the "
 					"network or node may be down.\n",
 					libcfs_id2str(peer->ksnp_id),
-					HIPQUAD(conn->ksnc_ipaddr),
+					&conn->ksnc_ipaddr,
 					conn->ksnc_port);
 				break;
 			default:
 				CNETERR("An unexpected network error %d "
 					"occurred with %s "
-					"(%u.%u.%u.%u:%d\n", error,
+					"(%pI4h:%d\n", error,
 					libcfs_id2str(peer->ksnp_id),
-					HIPQUAD(conn->ksnc_ipaddr),
+					&conn->ksnc_ipaddr,
 					conn->ksnc_port);
 				break;
 			}
@@ -2306,10 +2296,10 @@
 				     conn->ksnc_rx_deadline)) {
 			/* Timed out incomplete incoming message */
 			ksocknal_conn_addref(conn);
-			CNETERR("Timeout receiving from %s (%u.%u.%u.%u:%d), "
+			CNETERR("Timeout receiving from %s (%pI4h:%d), "
 				"state %d wanted %d left %d\n",
 				libcfs_id2str(peer->ksnp_id),
-				HIPQUAD(conn->ksnc_ipaddr),
+				&conn->ksnc_ipaddr,
 				conn->ksnc_port,
 				conn->ksnc_rx_state,
 				conn->ksnc_rx_nob_wanted,
@@ -2324,10 +2314,10 @@
 			/* Timed out messages queued for sending or
 			 * buffered in the socket's send buffer */
 			ksocknal_conn_addref(conn);
-			CNETERR("Timeout sending data to %s (%u.%u.%u.%u:%d) "
+			CNETERR("Timeout sending data to %s (%pI4h:%d) "
 				"the network or that node may be down.\n",
 				libcfs_id2str(peer->ksnp_id),
-				HIPQUAD(conn->ksnc_ipaddr),
+				&conn->ksnc_ipaddr,
 				conn->ksnc_port);
 			return (conn);
 		}
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
index 3e08fe2..a1c6a51 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
@@ -316,7 +316,7 @@
 		*ksocknal_tunables.ksnd_zc_recv_min_nfrags = LNET_MAX_IOV;
 
 	ksocknal_tunables.ksnd_sysctl =
-		cfs_register_sysctl_table(ksocknal_top_ctl_table, 0);
+		register_sysctl_table(ksocknal_top_ctl_table);
 
 	if (ksocknal_tunables.ksnd_sysctl == NULL)
 		CWARN("Can't setup /proc tunables\n");
@@ -325,20 +325,20 @@
 }
 
 void
-ksocknal_lib_tunables_fini ()
+ksocknal_lib_tunables_fini(void)
 {
 	if (ksocknal_tunables.ksnd_sysctl != NULL)
 		unregister_sysctl_table(ksocknal_tunables.ksnd_sysctl);
 }
 #else
 int
-ksocknal_lib_tunables_init ()
+ksocknal_lib_tunables_init(void)
 {
 	return 0;
 }
 
 void
-ksocknal_lib_tunables_fini ()
+ksocknal_lib_tunables_fini(void)
 {
 }
 #endif /* # if CONFIG_SYSCTL && !CFS_SYSFS_MODULE_PARM */
@@ -964,7 +964,6 @@
 ksocknal_data_ready (struct sock *sk, int n)
 {
 	ksock_conn_t  *conn;
-	ENTRY;
 
 	/* interleave correctly with closing sockets... */
 	LASSERT(!in_irq());
@@ -978,8 +977,6 @@
 		ksocknal_read_callback(conn);
 
 	read_unlock(&ksocknal_data.ksnd_global_lock);
-
-	EXIT;
 }
 
 static void
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h
index 3c13578..1cfc1b1 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.h
@@ -41,7 +41,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/stat.h>
@@ -58,11 +57,9 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/stat.h>
 #include <linux/list.h>
 #include <linux/kmod.h>
 #include <linux/sysctl.h>
-#include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <linux/syscalls.h>
 
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
index ec57179..71205e2 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
@@ -218,7 +218,7 @@
 	if (tx->tx_msg.ksm_zc_cookies[0] > tx->tx_msg.ksm_zc_cookies[1]) {
 		__u64   tmp = 0;
 
-		/* two seperated cookies: (a+2, a) or (a+1, a) */
+		/* two separated cookies: (a+2, a) or (a+1, a) */
 		LASSERT (tx->tx_msg.ksm_zc_cookies[0] -
 			 tx->tx_msg.ksm_zc_cookies[1] <= 2);
 
@@ -496,8 +496,8 @@
 	rc = libcfs_sock_write(sock, hdr, sizeof(*hdr),lnet_acceptor_timeout());
 
 	if (rc != 0) {
-		CNETERR("Error %d sending HELLO hdr to %u.%u.%u.%u/%d\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+		CNETERR("Error %d sending HELLO hdr to %pI4h/%d\n",
+			rc, &conn->ksnc_ipaddr, conn->ksnc_port);
 		goto out;
 	}
 
@@ -513,8 +513,8 @@
 			       lnet_acceptor_timeout());
 	if (rc != 0) {
 		CNETERR("Error %d sending HELLO payload (%d)"
-			" to %u.%u.%u.%u/%d\n", rc, hello->kshm_nips,
-			HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+			" to %pI4h/%d\n", rc, hello->kshm_nips,
+			&conn->ksnc_ipaddr, conn->ksnc_port);
 	}
 out:
 	LIBCFS_FREE(hdr, sizeof(*hdr));
@@ -545,8 +545,8 @@
 			       lnet_acceptor_timeout());
 
 	if (rc != 0) {
-		CNETERR("Error %d sending HELLO hdr to %u.%u.%u.%u/%d\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+		CNETERR("Error %d sending HELLO hdr to %pI4h/%d\n",
+			rc, &conn->ksnc_ipaddr, conn->ksnc_port);
 		return rc;
 	}
 
@@ -558,8 +558,8 @@
 			       lnet_acceptor_timeout());
 	if (rc != 0) {
 		CNETERR("Error %d sending HELLO payload (%d)"
-			" to %u.%u.%u.%u/%d\n", rc, hello->kshm_nips,
-			HIPQUAD(conn->ksnc_ipaddr), conn->ksnc_port);
+			" to %pI4h/%d\n", rc, hello->kshm_nips,
+			&conn->ksnc_ipaddr, conn->ksnc_port);
 	}
 
 	return rc;
@@ -583,18 +583,18 @@
 			      sizeof (*hdr) - offsetof (lnet_hdr_t, src_nid),
 			      timeout);
 	if (rc != 0) {
-		CERROR ("Error %d reading rest of HELLO hdr from %u.%u.%u.%u\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr));
+		CERROR("Error %d reading rest of HELLO hdr from %pI4h\n",
+			rc, &conn->ksnc_ipaddr);
 		LASSERT (rc < 0 && rc != -EALREADY);
 		goto out;
 	}
 
 	/* ...and check we got what we expected */
 	if (hdr->type != cpu_to_le32 (LNET_MSG_HELLO)) {
-		CERROR ("Expecting a HELLO hdr,"
-			" but got type %d from %u.%u.%u.%u\n",
+		CERROR("Expecting a HELLO hdr,"
+			" but got type %d from %pI4h\n",
 			le32_to_cpu (hdr->type),
-			HIPQUAD(conn->ksnc_ipaddr));
+			&conn->ksnc_ipaddr);
 		rc = -EPROTO;
 		goto out;
 	}
@@ -607,8 +607,8 @@
 					 sizeof (__u32);
 
 	if (hello->kshm_nips > LNET_MAX_INTERFACES) {
-		CERROR("Bad nips %d from ip %u.%u.%u.%u\n",
-		       hello->kshm_nips, HIPQUAD(conn->ksnc_ipaddr));
+		CERROR("Bad nips %d from ip %pI4h\n",
+		       hello->kshm_nips, &conn->ksnc_ipaddr);
 		rc = -EPROTO;
 		goto out;
 	}
@@ -619,9 +619,9 @@
 	rc = libcfs_sock_read(sock, hello->kshm_ips,
 			      hello->kshm_nips * sizeof(__u32), timeout);
 	if (rc != 0) {
-		CERROR ("Error %d reading IPs from ip %u.%u.%u.%u\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr));
-		LASSERT (rc < 0 && rc != -EALREADY);
+		CERROR("Error %d reading IPs from ip %pI4h\n",
+			rc, &conn->ksnc_ipaddr);
+		LASSERT(rc < 0 && rc != -EALREADY);
 		goto out;
 	}
 
@@ -629,8 +629,8 @@
 		hello->kshm_ips[i] = __le32_to_cpu(hello->kshm_ips[i]);
 
 		if (hello->kshm_ips[i] == 0) {
-			CERROR("Zero IP[%d] from ip %u.%u.%u.%u\n",
-			       i, HIPQUAD(conn->ksnc_ipaddr));
+			CERROR("Zero IP[%d] from ip %pI4h\n",
+			       i, &conn->ksnc_ipaddr);
 			rc = -EPROTO;
 			break;
 		}
@@ -658,9 +658,9 @@
 				       offsetof(ksock_hello_msg_t, kshm_src_nid),
 			      timeout);
 	if (rc != 0) {
-		CERROR ("Error %d reading HELLO from %u.%u.%u.%u\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr));
-		LASSERT (rc < 0 && rc != -EALREADY);
+		CERROR("Error %d reading HELLO from %pI4h\n",
+			rc, &conn->ksnc_ipaddr);
+		LASSERT(rc < 0 && rc != -EALREADY);
 		return rc;
 	}
 
@@ -676,8 +676,8 @@
 	}
 
 	if (hello->kshm_nips > LNET_MAX_INTERFACES) {
-		CERROR("Bad nips %d from ip %u.%u.%u.%u\n",
-		       hello->kshm_nips, HIPQUAD(conn->ksnc_ipaddr));
+		CERROR("Bad nips %d from ip %pI4h\n",
+		       hello->kshm_nips, &conn->ksnc_ipaddr);
 		return -EPROTO;
 	}
 
@@ -687,9 +687,9 @@
 	rc = libcfs_sock_read(sock, hello->kshm_ips,
 			      hello->kshm_nips * sizeof(__u32), timeout);
 	if (rc != 0) {
-		CERROR ("Error %d reading IPs from ip %u.%u.%u.%u\n",
-			rc, HIPQUAD(conn->ksnc_ipaddr));
-		LASSERT (rc < 0 && rc != -EALREADY);
+		CERROR("Error %d reading IPs from ip %pI4h\n",
+			rc, &conn->ksnc_ipaddr);
+		LASSERT(rc < 0 && rc != -EALREADY);
 		return rc;
 	}
 
@@ -698,8 +698,8 @@
 			__swab32s(&hello->kshm_ips[i]);
 
 		if (hello->kshm_ips[i] == 0) {
-			CERROR("Zero IP[%d] from ip %u.%u.%u.%u\n",
-			       i, HIPQUAD(conn->ksnc_ipaddr));
+			CERROR("Zero IP[%d] from ip %pI4h\n",
+			       i, &conn->ksnc_ipaddr);
 			return -EPROTO;
 		}
 	}
diff --git a/drivers/staging/lustre/lnet/lnet/Makefile b/drivers/staging/lustre/lnet/lnet/Makefile
index 1bd9ef7..b815fe1 100644
--- a/drivers/staging/lustre/lnet/lnet/Makefile
+++ b/drivers/staging/lustre/lnet/lnet/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_LNET) += lnet.o
 
-lnet-y := api-errno.o api-ni.o config.o lib-me.o lib-msg.o lib-eq.o	\
+lnet-y := api-ni.o config.o lib-me.o lib-msg.o lib-eq.o	\
 	  lib-md.o lib-ptl.o lib-move.o module.o lo.o router.o		\
 	  router_proc.o acceptor.o peer.o
 
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index 81ef28b..bb15bde 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -101,52 +101,52 @@
 	switch (rc) {
 	/* "normal" errors */
 	case -ECONNREFUSED:
-		CNETERR("Connection to %s at host %u.%u.%u.%u on port %d was "
+		CNETERR("Connection to %s at host %pI4h on port %d was "
 			"refused: check that Lustre is running on that node.\n",
 			libcfs_nid2str(peer_nid),
-			HIPQUAD(peer_ip), peer_port);
+			&peer_ip, peer_port);
 		break;
 	case -EHOSTUNREACH:
 	case -ENETUNREACH:
-		CNETERR("Connection to %s at host %u.%u.%u.%u "
+		CNETERR("Connection to %s at host %pI4h "
 			"was unreachable: the network or that node may "
 			"be down, or Lustre may be misconfigured.\n",
-			libcfs_nid2str(peer_nid), HIPQUAD(peer_ip));
+			libcfs_nid2str(peer_nid), &peer_ip);
 		break;
 	case -ETIMEDOUT:
-		CNETERR("Connection to %s at host %u.%u.%u.%u on "
+		CNETERR("Connection to %s at host %pI4h on "
 			"port %d took too long: that node may be hung "
 			"or experiencing high load.\n",
 			libcfs_nid2str(peer_nid),
-			HIPQUAD(peer_ip), peer_port);
+			&peer_ip, peer_port);
 		break;
 	case -ECONNRESET:
-		LCONSOLE_ERROR_MSG(0x11b, "Connection to %s at host %u.%u.%u.%u"
+		LCONSOLE_ERROR_MSG(0x11b, "Connection to %s at host %pI4h"
 				   " on port %d was reset: "
 				   "is it running a compatible version of "
 				   "Lustre and is %s one of its NIDs?\n",
 				   libcfs_nid2str(peer_nid),
-				   HIPQUAD(peer_ip), peer_port,
+				   &peer_ip, peer_port,
 				   libcfs_nid2str(peer_nid));
 		break;
 	case -EPROTO:
 		LCONSOLE_ERROR_MSG(0x11c, "Protocol error connecting to %s at "
-				   "host %u.%u.%u.%u on port %d: is it running "
+				   "host %pI4h on port %d: is it running "
 				   "a compatible version of Lustre?\n",
 				   libcfs_nid2str(peer_nid),
-				   HIPQUAD(peer_ip), peer_port);
+				   &peer_ip, peer_port);
 		break;
 	case -EADDRINUSE:
 		LCONSOLE_ERROR_MSG(0x11d, "No privileged ports available to "
-				   "connect to %s at host %u.%u.%u.%u on port "
+				   "connect to %s at host %pI4h on port "
 				   "%d\n", libcfs_nid2str(peer_nid),
-				   HIPQUAD(peer_ip), peer_port);
+				   &peer_ip, peer_port);
 		break;
 	default:
 		LCONSOLE_ERROR_MSG(0x11e, "Unexpected error %d connecting to %s"
-				   " at host %u.%u.%u.%u on port %d\n", rc,
+				   " at host %pI4h on port %d\n", rc,
 				   libcfs_nid2str(peer_nid),
-				   HIPQUAD(peer_ip), peer_port);
+				   &peer_ip, peer_port);
 		break;
 	}
 }
@@ -253,8 +253,8 @@
 
 			if (rc != 0)
 				CERROR("Error sending magic+version in response"
-				       "to LNET magic from %u.%u.%u.%u: %d\n",
-				       HIPQUAD(peer_ip), rc);
+				       "to LNET magic from %pI4h: %d\n",
+				       &peer_ip, rc);
 			return -EPROTO;
 		}
 
@@ -265,9 +265,9 @@
 		else
 			str = "unrecognised";
 
-		LCONSOLE_ERROR_MSG(0x11f, "Refusing connection from %u.%u.%u.%u"
+		LCONSOLE_ERROR_MSG(0x11f, "Refusing connection from %pI4h"
 				   " magic %08x: %s acceptor protocol\n",
-				   HIPQUAD(peer_ip), magic, str);
+				   &peer_ip, magic, str);
 		return -EPROTO;
 	}
 
@@ -278,7 +278,7 @@
 			      accept_timeout);
 	if (rc != 0) {
 		CERROR("Error %d reading connection request version from "
-		       "%u.%u.%u.%u\n", rc, HIPQUAD(peer_ip));
+		       "%pI4h\n", rc, &peer_ip);
 		return -EIO;
 	}
 
@@ -301,8 +301,8 @@
 
 		if (rc != 0)
 			CERROR("Error sending magic+version in response"
-			       "to version %d from %u.%u.%u.%u: %d\n",
-			       peer_version, HIPQUAD(peer_ip), rc);
+			       "to version %d from %pI4h: %d\n",
+			       peer_version, &peer_ip, rc);
 		return -EPROTO;
 	}
 
@@ -312,7 +312,7 @@
 			      accept_timeout);
 	if (rc != 0) {
 		CERROR("Error %d reading connection request from "
-		       "%u.%u.%u.%u\n", rc, HIPQUAD(peer_ip));
+		       "%pI4h\n", rc, &peer_ip);
 		return -EIO;
 	}
 
@@ -324,23 +324,23 @@
 	    ni->ni_nid != cr.acr_nid) { /* right NET, wrong NID! */
 		if (ni != NULL)
 			lnet_ni_decref(ni);
-		LCONSOLE_ERROR_MSG(0x120, "Refusing connection from %u.%u.%u.%u"
+		LCONSOLE_ERROR_MSG(0x120, "Refusing connection from %pI4h"
 				   " for %s: No matching NI\n",
-				   HIPQUAD(peer_ip), libcfs_nid2str(cr.acr_nid));
+				   &peer_ip, libcfs_nid2str(cr.acr_nid));
 		return -EPERM;
 	}
 
 	if (ni->ni_lnd->lnd_accept == NULL) {
 		/* This catches a request for the loopback LND */
 		lnet_ni_decref(ni);
-		LCONSOLE_ERROR_MSG(0x121, "Refusing connection from %u.%u.%u.%u"
+		LCONSOLE_ERROR_MSG(0x121, "Refusing connection from %pI4h"
 				  " for %s: NI doesn not accept IP connections\n",
-				  HIPQUAD(peer_ip), libcfs_nid2str(cr.acr_nid));
+				  &peer_ip, libcfs_nid2str(cr.acr_nid));
 		return -EPERM;
 	}
 
-	CDEBUG(D_NET, "Accept %s from %u.%u.%u.%u\n",
-	       libcfs_nid2str(cr.acr_nid), HIPQUAD(peer_ip));
+	CDEBUG(D_NET, "Accept %s from %pI4h\n",
+	       libcfs_nid2str(cr.acr_nid), &peer_ip);
 
 	rc = ni->ni_lnd->lnd_accept(ni, sock);
 
@@ -410,9 +410,9 @@
 		}
 
 		if (secure && peer_port > LNET_ACCEPTOR_MAX_RESERVED_PORT) {
-			CERROR("Refusing connection from %u.%u.%u.%u: "
+			CERROR("Refusing connection from %pI4h: "
 			       "insecure port %d\n",
-			       HIPQUAD(peer_ip), peer_port);
+			       &peer_ip, peer_port);
 			goto failed;
 		}
 
@@ -420,7 +420,7 @@
 				      accept_timeout);
 		if (rc != 0) {
 			CERROR("Error %d reading connection request from "
-			       "%u.%u.%u.%u\n", rc, HIPQUAD(peer_ip));
+			       "%pI4h\n", rc, &peer_ip);
 			goto failed;
 		}
 
diff --git a/drivers/staging/lustre/lnet/lnet/api-errno.c b/drivers/staging/lustre/lnet/lnet/api-errno.c
deleted file mode 100644
index 695b272..0000000
--- a/drivers/staging/lustre/lnet/lnet/api-errno.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lnet/lnet/api-errno.c
- *
- * Instantiate the string table of errors
- */
-
-/* If you change these, you must update the number table in portals/errno.h */
diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c
index e88bee3..160a429 100644
--- a/drivers/staging/lustre/lnet/lnet/api-ni.c
+++ b/drivers/staging/lustre/lnet/lnet/api-ni.c
@@ -1371,7 +1371,7 @@
  * \return always 0 for current implementation.
  */
 int
-LNetNIFini()
+LNetNIFini(void)
 {
 	LNET_MUTEX_LOCK(&the_lnet.ln_api_mutex);
 
@@ -1541,7 +1541,10 @@
 	int		rc = -ENOENT;
 
 	LASSERT(the_lnet.ln_init);
-	LASSERT(the_lnet.ln_refcount > 0);
+
+	/* LNetNI initilization failed? */
+	if (the_lnet.ln_refcount == 0)
+		return rc;
 
 	cpt = lnet_net_lock_current();
 
diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c
index 78297a7..4ce68d3 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-eq.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c
@@ -244,11 +244,10 @@
 	int		new_index = eq->eq_deq_seq & (eq->eq_size - 1);
 	lnet_event_t	*new_event = &eq->eq_events[new_index];
 	int		rc;
-	ENTRY;
 
 	/* must called with lnet_eq_wait_lock hold */
 	if (LNET_SEQ_GT(eq->eq_deq_seq, new_event->sequence))
-		RETURN(0);
+		return 0;
 
 	/* We've got a new event... */
 	*ev = *new_event;
@@ -268,7 +267,7 @@
 	}
 
 	eq->eq_deq_seq = new_event->sequence + 1;
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -400,13 +399,12 @@
 	int	wait = 1;
 	int	rc;
 	int	i;
-	ENTRY;
 
 	LASSERT (the_lnet.ln_init);
 	LASSERT (the_lnet.ln_refcount > 0);
 
 	if (neq < 1)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	lnet_eq_wait_lock();
 
@@ -416,14 +414,14 @@
 
 			if (eq == NULL) {
 				lnet_eq_wait_unlock();
-				RETURN(-ENOENT);
+				return -ENOENT;
 			}
 
 			rc = lnet_eq_dequeue_event(eq, event);
 			if (rc != 0) {
 				lnet_eq_wait_unlock();
 				*which = i;
-				RETURN(rc);
+				return rc;
 			}
 		}
 
@@ -443,5 +441,5 @@
 	}
 
 	lnet_eq_wait_unlock();
-	RETURN(0);
+	return 0;
 }
diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c
index 8f3a50b..61ae88b 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-msg.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c
@@ -45,8 +45,6 @@
 void
 lnet_build_unlink_event (lnet_libmd_t *md, lnet_event_t *ev)
 {
-	ENTRY;
-
 	memset(ev, 0, sizeof(*ev));
 
 	ev->status   = 0;
@@ -54,7 +52,6 @@
 	ev->type     = LNET_EVENT_UNLINK;
 	lnet_md_deconstruct(md, &ev->md);
 	lnet_md2handle(&ev->md_handle, md);
-	EXIT;
 }
 
 /*
@@ -319,7 +316,7 @@
 	LASSERT(!msg->msg_routing);
 
 	msg->msg_md = md;
-	if (msg->msg_receiving) { /* commited for receiving */
+	if (msg->msg_receiving) { /* committed for receiving */
 		msg->msg_offset = offset;
 		msg->msg_wanted = mlen;
 	}
@@ -395,7 +392,7 @@
 		 * NB: message is committed for sending, we should return
 		 * on success because LND will finalize this message later.
 		 *
-		 * Also, there is possibility that message is commited for
+		 * Also, there is possibility that message is committed for
 		 * sending and also failed before delivering to LND,
 		 * i.e: ENOMEM, in that case we can't fall through either
 		 * because CPT for sending can be different with CPT for
@@ -417,7 +414,7 @@
 		 * NB: message is committed for sending, we should return
 		 * on success because LND will finalize this message later.
 		 *
-		 * Also, there is possibility that message is commited for
+		 * Also, there is possibility that message is committed for
 		 * sending and also failed before delivering to LND,
 		 * i.e: ENOMEM, in that case we can't fall through either:
 		 * - The rule is message must decommit for sending first if
@@ -477,14 +474,14 @@
  again:
 	rc = 0;
 	if (!msg->msg_tx_committed && !msg->msg_rx_committed) {
-		/* not commited to network yet */
+		/* not committed to network yet */
 		LASSERT(!msg->msg_onactivelist);
 		lnet_msg_free(msg);
 		return;
 	}
 
 	/*
-	 * NB: routed message can be commited for both receiving and sending,
+	 * NB: routed message can be committed for both receiving and sending,
 	 * we should finalize in LIFO order and keep counters correct.
 	 * (finalize sending first then finalize receiving)
 	 */
diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c
index c832385..afb8175 100644
--- a/drivers/staging/lustre/lnet/lnet/module.c
+++ b/drivers/staging/lustre/lnet/lnet/module.c
@@ -114,14 +114,13 @@
 init_lnet(void)
 {
 	int		  rc;
-	ENTRY;
 
 	mutex_init(&lnet_config_mutex);
 
 	rc = LNetInit();
 	if (rc != 0) {
 		CERROR("LNetInit: error %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = libcfs_register_ioctl(&lnet_ioctl_handler);
@@ -133,7 +132,7 @@
 		(void) kthread_run(lnet_configure, NULL, "lnet_initd");
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 void
@@ -150,5 +149,7 @@
 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
 MODULE_DESCRIPTION("Portals v3.1");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
 
-cfs_module(lnet, "1.0.0", init_lnet, fini_lnet);
+module_init(init_lnet);
+module_exit(fini_lnet);
diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c
index 3084b0c..931f6ca2 100644
--- a/drivers/staging/lustre/lnet/lnet/router_proc.c
+++ b/drivers/staging/lustre/lnet/lnet/router_proc.c
@@ -920,7 +920,7 @@
 {
 #ifdef CONFIG_SYSCTL
 	if (lnet_table_header == NULL)
-		lnet_table_header = cfs_register_sysctl_table(top_table, 0);
+		lnet_table_header = register_sysctl_table(top_table);
 #endif
 }
 
diff --git a/drivers/staging/lustre/lnet/selftest/brw_test.c b/drivers/staging/lustre/lnet/selftest/brw_test.c
index 3bb6fbe..ef5064e 100644
--- a/drivers/staging/lustre/lnet/selftest/brw_test.c
+++ b/drivers/staging/lustre/lnet/selftest/brw_test.c
@@ -361,7 +361,7 @@
 			blk->bk_sink ? "from" : "to",
 			libcfs_id2str(rpc->srpc_peer), rpc->srpc_status);
 	else
-		CDEBUG (D_NET, "Transfered %d pages bulk data %s %s\n",
+		CDEBUG (D_NET, "Transferred %d pages bulk data %s %s\n",
 			blk->bk_niov, blk->bk_sink ? "from" : "to",
 			libcfs_id2str(rpc->srpc_peer));
 
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 446de0e..cbce662 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -1356,7 +1356,7 @@
 
 	lst_wait_until((atomic_read(&console_session.ses_rpc_counter) == 0),
 		       console_session.ses_rpc_lock,
-		       "Network is not accessable or target is down, "
+		       "Network is not accessible or target is down, "
 		       "waiting for %d console RPCs to being recycled\n",
 		       atomic_read(&console_session.ses_rpc_counter));
 
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index 78e8d04..09e4700 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -1773,7 +1773,7 @@
 }
 
 int
-lstcon_session_end()
+lstcon_session_end(void)
 {
 	lstcon_rpc_trans_t *trans;
 	lstcon_group_t     *grp;
diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c
index 5257e56..6dd4309 100644
--- a/drivers/staging/lustre/lnet/selftest/module.c
+++ b/drivers/staging/lustre/lnet/selftest/module.c
@@ -165,5 +165,7 @@
 
 MODULE_DESCRIPTION("LNet Selftest");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("0.9.0");
 
-cfs_module(lnet, "0.9.0", lnet_selftest_init, lnet_selftest_fini);
+module_init(lnet_selftest_init);
+module_exit(lnet_selftest_fini);
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index bc1f38b..7659a26 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -661,8 +661,10 @@
 
 	cfs_percpt_for_each(scd, i, sv->sv_cpt_data) {
 		spin_lock(&scd->scd_lock);
-		if (!swi_deschedule_workitem(&scd->scd_buf_wi))
+		if (!swi_deschedule_workitem(&scd->scd_buf_wi)) {
+			spin_unlock(&scd->scd_lock);
 			return 0;
+		}
 
 		if (scd->scd_buf_nposted > 0) {
 			CDEBUG(D_NET, "waiting for %d posted buffers to unlink",
@@ -1115,7 +1117,7 @@
 	if (rpc->crpc_timeout == 0)
 		return;
 
-	/* timer sucessfully defused */
+	/* timer successfully defused */
 	if (stt_del_timer(&rpc->crpc_timer))
 		return;
 
diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c
index 2c07855..3bf4afb 100644
--- a/drivers/staging/lustre/lnet/selftest/timer.c
+++ b/drivers/staging/lustre/lnet/selftest/timer.c
@@ -195,7 +195,7 @@
 int
 stt_start_timer_thread (void)
 {
-	task_t *task;
+	struct task_struct *task;
 
 	LASSERT(!stt_data.stt_shuttingdown);
 
diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig
index e0eb830..4e898e4 100644
--- a/drivers/staging/lustre/lustre/Kconfig
+++ b/drivers/staging/lustre/lustre/Kconfig
@@ -1,6 +1,6 @@
 config LUSTRE_FS
 	tristate "Lustre file system client support"
-	depends on STAGING && INET && BROKEN
+	depends on INET && m
 	select LNET
 	select CRYPTO
 	select CRYPTO_CRC32
@@ -43,9 +43,18 @@
 config LUSTRE_DEBUG_EXPENSIVE_CHECK
 	bool "Enable Lustre DEBUG checks"
 	depends on LUSTRE_FS
-	default false
 	help
 	  This option is mainly for debug purpose. It enables Lustre code to do
 	  expensive checks that may have a performance impact.
 
 	  Use with caution. If unsure, say N.
+
+config LUSTRE_TRANSLATE_ERRNOS
+	bool
+	depends on LUSTRE_FS && !X86
+	default true
+
+config LUSTRE_LLITE_LLOOP
+	bool "Lustre virtual block device"
+	depends on LUSTRE_FS && BLOCK
+	default m
diff --git a/drivers/staging/lustre/lustre/Makefile b/drivers/staging/lustre/lustre/Makefile
index 3fb94fc..d1eb0bd 100644
--- a/drivers/staging/lustre/lustre/Makefile
+++ b/drivers/staging/lustre/lustre/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_LUSTRE_FS) := fid/ lvfs/ obdclass/ ptlrpc/ obdecho/ mgc/ lov/ \
-			   osc/ mdc/ lmv/ llite/ fld/ libcfs/
+obj-$(CONFIG_LUSTRE_FS) += libcfs/ lvfs/ obdclass/ ptlrpc/ fld/ osc/ mgc/ \
+			   fid/ lov/ mdc/ lmv/ llite/ obdecho/
diff --git a/drivers/staging/lustre/lustre/fid/Makefile b/drivers/staging/lustre/lustre/fid/Makefile
index b8d6d21..ed21bea 100644
--- a/drivers/staging/lustre/lustre/fid/Makefile
+++ b/drivers/staging/lustre/lustre/fid/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_LUSTRE_FS) += fid.o
-fid-y := fid_handler.o fid_store.o fid_request.o lproc_fid.o fid_lib.o
+fid-y := fid_request.o lproc_fid.o fid_lib.o
 
 
 ccflags-y := -I$(src)/../include
diff --git a/drivers/staging/lustre/lustre/fid/fid_handler.c b/drivers/staging/lustre/lustre/fid/fid_handler.c
deleted file mode 100644
index bbbb3cf..0000000
--- a/drivers/staging/lustre/lustre/fid/fid_handler.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2012, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fid/fid_handler.c
- *
- * Lustre Sequence Manager
- *
- * Author: Yury Umanets <umka@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FID
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <dt_object.h>
-#include <md_object.h>
-#include <obd_support.h>
-#include <lustre_req_layout.h>
-#include <lustre_fid.h>
-#include "fid_internal.h"
-
-int client_fid_init(struct obd_device *obd,
-		    struct obd_export *exp, enum lu_cli_type type)
-{
-	struct client_obd *cli = &obd->u.cli;
-	char *prefix;
-	int rc;
-	ENTRY;
-
-	OBD_ALLOC_PTR(cli->cl_seq);
-	if (cli->cl_seq == NULL)
-		RETURN(-ENOMEM);
-
-	OBD_ALLOC(prefix, MAX_OBD_NAME + 5);
-	if (prefix == NULL)
-		GOTO(out_free_seq, rc = -ENOMEM);
-
-	snprintf(prefix, MAX_OBD_NAME + 5, "cli-%s", obd->obd_name);
-
-	/* Init client side sequence-manager */
-	rc = seq_client_init(cli->cl_seq, exp, type, prefix, NULL);
-	OBD_FREE(prefix, MAX_OBD_NAME + 5);
-	if (rc)
-		GOTO(out_free_seq, rc);
-
-	RETURN(rc);
-out_free_seq:
-	OBD_FREE_PTR(cli->cl_seq);
-	cli->cl_seq = NULL;
-	return rc;
-}
-EXPORT_SYMBOL(client_fid_init);
-
-int client_fid_fini(struct obd_device *obd)
-{
-	struct client_obd *cli = &obd->u.cli;
-	ENTRY;
-
-	if (cli->cl_seq != NULL) {
-		seq_client_fini(cli->cl_seq);
-		OBD_FREE_PTR(cli->cl_seq);
-		cli->cl_seq = NULL;
-	}
-
-	RETURN(0);
-}
-EXPORT_SYMBOL(client_fid_fini);
-
-static void seq_server_proc_fini(struct lu_server_seq *seq);
-
-/* Assigns client to sequence controller node. */
-int seq_server_set_cli(struct lu_server_seq *seq,
-		       struct lu_client_seq *cli,
-		       const struct lu_env *env)
-{
-	int rc = 0;
-	ENTRY;
-
-	/*
-	 * Ask client for new range, assign that range to ->seq_space and write
-	 * seq state to backing store should be atomic.
-	 */
-	mutex_lock(&seq->lss_mutex);
-
-	if (cli == NULL) {
-		CDEBUG(D_INFO, "%s: Detached sequence client %s\n",
-		       seq->lss_name, cli->lcs_name);
-		seq->lss_cli = cli;
-		GOTO(out_up, rc = 0);
-	}
-
-	if (seq->lss_cli != NULL) {
-		CDEBUG(D_HA, "%s: Sequence controller is already "
-		       "assigned\n", seq->lss_name);
-		GOTO(out_up, rc = -EEXIST);
-	}
-
-	CDEBUG(D_INFO, "%s: Attached sequence controller %s\n",
-	       seq->lss_name, cli->lcs_name);
-
-	seq->lss_cli = cli;
-	cli->lcs_space.lsr_index = seq->lss_site->ss_node_id;
-	EXIT;
-out_up:
-	mutex_unlock(&seq->lss_mutex);
-	return rc;
-}
-EXPORT_SYMBOL(seq_server_set_cli);
-/*
- * allocate \a w units of sequence from range \a from.
- */
-static inline void range_alloc(struct lu_seq_range *to,
-			       struct lu_seq_range *from,
-			       __u64 width)
-{
-	width = min(range_space(from), width);
-	to->lsr_start = from->lsr_start;
-	to->lsr_end = from->lsr_start + width;
-	from->lsr_start += width;
-}
-
-/**
- * On controller node, allocate new super sequence for regular sequence server.
- * As this super sequence controller, this node suppose to maintain fld
- * and update index.
- * \a out range always has currect mds node number of requester.
- */
-
-static int __seq_server_alloc_super(struct lu_server_seq *seq,
-				    struct lu_seq_range *out,
-				    const struct lu_env *env)
-{
-	struct lu_seq_range *space = &seq->lss_space;
-	int rc;
-	ENTRY;
-
-	LASSERT(range_is_sane(space));
-
-	if (range_is_exhausted(space)) {
-		CERROR("%s: Sequences space is exhausted\n",
-		       seq->lss_name);
-		RETURN(-ENOSPC);
-	} else {
-		range_alloc(out, space, seq->lss_width);
-	}
-
-	rc = seq_store_update(env, seq, out, 1 /* sync */);
-
-	LCONSOLE_INFO("%s: super-sequence allocation rc = %d " DRANGE"\n",
-		      seq->lss_name, rc, PRANGE(out));
-
-	RETURN(rc);
-}
-
-int seq_server_alloc_super(struct lu_server_seq *seq,
-			   struct lu_seq_range *out,
-			   const struct lu_env *env)
-{
-	int rc;
-	ENTRY;
-
-	mutex_lock(&seq->lss_mutex);
-	rc = __seq_server_alloc_super(seq, out, env);
-	mutex_unlock(&seq->lss_mutex);
-
-	RETURN(rc);
-}
-
-static int __seq_set_init(const struct lu_env *env,
-			    struct lu_server_seq *seq)
-{
-	struct lu_seq_range *space = &seq->lss_space;
-	int rc;
-
-	range_alloc(&seq->lss_lowater_set, space, seq->lss_set_width);
-	range_alloc(&seq->lss_hiwater_set, space, seq->lss_set_width);
-
-	rc = seq_store_update(env, seq, NULL, 1);
-
-	return rc;
-}
-
-/*
- * This function implements new seq allocation algorithm using async
- * updates to seq file on disk. ref bug 18857 for details.
- * there are four variable to keep track of this process
- *
- * lss_space; - available lss_space
- * lss_lowater_set; - lu_seq_range for all seqs before barrier, i.e. safe to use
- * lss_hiwater_set; - lu_seq_range after barrier, i.e. allocated but may be
- *		    not yet committed
- *
- * when lss_lowater_set reaches the end it is replaced with hiwater one and
- * a write operation is initiated to allocate new hiwater range.
- * if last seq write opearion is still not commited, current operation is
- * flaged as sync write op.
- */
-static int range_alloc_set(const struct lu_env *env,
-			    struct lu_seq_range *out,
-			    struct lu_server_seq *seq)
-{
-	struct lu_seq_range *space = &seq->lss_space;
-	struct lu_seq_range *loset = &seq->lss_lowater_set;
-	struct lu_seq_range *hiset = &seq->lss_hiwater_set;
-	int rc = 0;
-
-	if (range_is_zero(loset))
-		__seq_set_init(env, seq);
-
-	if (OBD_FAIL_CHECK(OBD_FAIL_SEQ_ALLOC)) /* exhaust set */
-		loset->lsr_start = loset->lsr_end;
-
-	if (range_is_exhausted(loset)) {
-		/* reached high water mark. */
-		struct lu_device *dev = seq->lss_site->ss_lu->ls_top_dev;
-		int obd_num_clients = dev->ld_obd->obd_num_exports;
-		__u64 set_sz;
-
-		/* calculate new seq width based on number of clients */
-		set_sz = max(seq->lss_set_width,
-			     obd_num_clients * seq->lss_width);
-		set_sz = min(range_space(space), set_sz);
-
-		/* Switch to hiwater range now */
-		*loset = *hiset;
-		/* allocate new hiwater range */
-		range_alloc(hiset, space, set_sz);
-
-		/* update ondisk seq with new *space */
-		rc = seq_store_update(env, seq, NULL, seq->lss_need_sync);
-	}
-
-	LASSERTF(!range_is_exhausted(loset) || range_is_sane(loset),
-		 DRANGE"\n", PRANGE(loset));
-
-	if (rc == 0)
-		range_alloc(out, loset, seq->lss_width);
-
-	RETURN(rc);
-}
-
-static int __seq_server_alloc_meta(struct lu_server_seq *seq,
-				   struct lu_seq_range *out,
-				   const struct lu_env *env)
-{
-	struct lu_seq_range *space = &seq->lss_space;
-	int rc = 0;
-
-	ENTRY;
-
-	LASSERT(range_is_sane(space));
-
-	/* Check if available space ends and allocate new super seq */
-	if (range_is_exhausted(space)) {
-		if (!seq->lss_cli) {
-			CERROR("%s: No sequence controller is attached.\n",
-			       seq->lss_name);
-			RETURN(-ENODEV);
-		}
-
-		rc = seq_client_alloc_super(seq->lss_cli, env);
-		if (rc) {
-			CERROR("%s: Can't allocate super-sequence, rc %d\n",
-			       seq->lss_name, rc);
-			RETURN(rc);
-		}
-
-		/* Saving new range to allocation space. */
-		*space = seq->lss_cli->lcs_space;
-		LASSERT(range_is_sane(space));
-	}
-
-	rc = range_alloc_set(env, out, seq);
-	if (rc != 0) {
-		CERROR("%s: Allocated meta-sequence failed: rc = %d\n",
-			seq->lss_name, rc);
-		RETURN(rc);
-	}
-
-	CDEBUG(D_INFO, "%s: Allocated meta-sequence " DRANGE"\n",
-		seq->lss_name, PRANGE(out));
-
-	RETURN(rc);
-}
-
-int seq_server_alloc_meta(struct lu_server_seq *seq,
-			  struct lu_seq_range *out,
-			  const struct lu_env *env)
-{
-	int rc;
-	ENTRY;
-
-	mutex_lock(&seq->lss_mutex);
-	rc = __seq_server_alloc_meta(seq, out, env);
-	mutex_unlock(&seq->lss_mutex);
-
-	RETURN(rc);
-}
-EXPORT_SYMBOL(seq_server_alloc_meta);
-
-static int seq_server_handle(struct lu_site *site,
-			     const struct lu_env *env,
-			     __u32 opc, struct lu_seq_range *out)
-{
-	int rc;
-	struct seq_server_site *ss_site;
-	ENTRY;
-
-	ss_site = lu_site2seq(site);
-
-	switch (opc) {
-	case SEQ_ALLOC_META:
-		if (!ss_site->ss_server_seq) {
-			CERROR("Sequence server is not "
-			       "initialized\n");
-			RETURN(-EINVAL);
-		}
-		rc = seq_server_alloc_meta(ss_site->ss_server_seq, out, env);
-		break;
-	case SEQ_ALLOC_SUPER:
-		if (!ss_site->ss_control_seq) {
-			CERROR("Sequence controller is not "
-			       "initialized\n");
-			RETURN(-EINVAL);
-		}
-		rc = seq_server_alloc_super(ss_site->ss_control_seq, out, env);
-		break;
-	default:
-		rc = -EINVAL;
-		break;
-	}
-
-	RETURN(rc);
-}
-
-static int seq_req_handle(struct ptlrpc_request *req,
-			  const struct lu_env *env,
-			  struct seq_thread_info *info)
-{
-	struct lu_seq_range *out, *tmp;
-	struct lu_site *site;
-	int rc = -EPROTO;
-	__u32 *opc;
-	ENTRY;
-
-	LASSERT(!(lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY));
-	site = req->rq_export->exp_obd->obd_lu_dev->ld_site;
-	LASSERT(site != NULL);
-
-	rc = req_capsule_server_pack(info->sti_pill);
-	if (rc)
-		RETURN(err_serious(rc));
-
-	opc = req_capsule_client_get(info->sti_pill, &RMF_SEQ_OPC);
-	if (opc != NULL) {
-		out = req_capsule_server_get(info->sti_pill, &RMF_SEQ_RANGE);
-		if (out == NULL)
-			RETURN(err_serious(-EPROTO));
-
-		tmp = req_capsule_client_get(info->sti_pill, &RMF_SEQ_RANGE);
-
-		/* seq client passed mdt id, we need to pass that using out
-		 * range parameter */
-
-		out->lsr_index = tmp->lsr_index;
-		out->lsr_flags = tmp->lsr_flags;
-		rc = seq_server_handle(site, env, *opc, out);
-	} else
-		rc = err_serious(-EPROTO);
-
-	RETURN(rc);
-}
-
-/* context key constructor/destructor: seq_key_init, seq_key_fini */
-LU_KEY_INIT_FINI(seq, struct seq_thread_info);
-
-/* context key: seq_thread_key */
-LU_CONTEXT_KEY_DEFINE(seq, LCT_MD_THREAD | LCT_DT_THREAD);
-
-static void seq_thread_info_init(struct ptlrpc_request *req,
-				 struct seq_thread_info *info)
-{
-	info->sti_pill = &req->rq_pill;
-	/* Init request capsule */
-	req_capsule_init(info->sti_pill, req, RCL_SERVER);
-	req_capsule_set(info->sti_pill, &RQF_SEQ_QUERY);
-}
-
-static void seq_thread_info_fini(struct seq_thread_info *info)
-{
-	req_capsule_fini(info->sti_pill);
-}
-
-int seq_handle(struct ptlrpc_request *req)
-{
-	const struct lu_env *env;
-	struct seq_thread_info *info;
-	int rc;
-
-	env = req->rq_svc_thread->t_env;
-	LASSERT(env != NULL);
-
-	info = lu_context_key_get(&env->le_ctx, &seq_thread_key);
-	LASSERT(info != NULL);
-
-	seq_thread_info_init(req, info);
-	rc = seq_req_handle(req, env, info);
-	/* XXX: we don't need replay but MDT assign transno in any case,
-	 * remove it manually before reply*/
-	lustre_msg_set_transno(req->rq_repmsg, 0);
-	seq_thread_info_fini(info);
-
-	return rc;
-}
-EXPORT_SYMBOL(seq_handle);
-
-/*
- * Entry point for handling FLD RPCs called from MDT.
- */
-int seq_query(struct com_thread_info *info)
-{
-	return seq_handle(info->cti_pill->rc_req);
-}
-EXPORT_SYMBOL(seq_query);
-
-
-#ifdef LPROCFS
-static int seq_server_proc_init(struct lu_server_seq *seq)
-{
-	int rc;
-	ENTRY;
-
-	seq->lss_proc_dir = lprocfs_register(seq->lss_name,
-					     seq_type_proc_dir,
-					     NULL, NULL);
-	if (IS_ERR(seq->lss_proc_dir)) {
-		rc = PTR_ERR(seq->lss_proc_dir);
-		RETURN(rc);
-	}
-
-	rc = lprocfs_add_vars(seq->lss_proc_dir,
-			      seq_server_proc_list, seq);
-	if (rc) {
-		CERROR("%s: Can't init sequence manager "
-		       "proc, rc %d\n", seq->lss_name, rc);
-		GOTO(out_cleanup, rc);
-	}
-
-	RETURN(0);
-
-out_cleanup:
-	seq_server_proc_fini(seq);
-	return rc;
-}
-
-static void seq_server_proc_fini(struct lu_server_seq *seq)
-{
-	ENTRY;
-	if (seq->lss_proc_dir != NULL) {
-		if (!IS_ERR(seq->lss_proc_dir))
-			lprocfs_remove(&seq->lss_proc_dir);
-		seq->lss_proc_dir = NULL;
-	}
-	EXIT;
-}
-#else
-static int seq_server_proc_init(struct lu_server_seq *seq)
-{
-	return 0;
-}
-
-static void seq_server_proc_fini(struct lu_server_seq *seq)
-{
-	return;
-}
-#endif
-
-
-int seq_server_init(struct lu_server_seq *seq,
-		    struct dt_device *dev,
-		    const char *prefix,
-		    enum lu_mgr_type type,
-		    struct seq_server_site *ss,
-		    const struct lu_env *env)
-{
-	int rc, is_srv = (type == LUSTRE_SEQ_SERVER);
-	ENTRY;
-
-	LASSERT(dev != NULL);
-	LASSERT(prefix != NULL);
-	LASSERT(ss != NULL);
-	LASSERT(ss->ss_lu != NULL);
-
-	seq->lss_cli = NULL;
-	seq->lss_type = type;
-	seq->lss_site = ss;
-	range_init(&seq->lss_space);
-
-	range_init(&seq->lss_lowater_set);
-	range_init(&seq->lss_hiwater_set);
-	seq->lss_set_width = LUSTRE_SEQ_BATCH_WIDTH;
-
-	mutex_init(&seq->lss_mutex);
-
-	seq->lss_width = is_srv ?
-		LUSTRE_SEQ_META_WIDTH : LUSTRE_SEQ_SUPER_WIDTH;
-
-	snprintf(seq->lss_name, sizeof(seq->lss_name),
-		 "%s-%s", (is_srv ? "srv" : "ctl"), prefix);
-
-	rc = seq_store_init(seq, env, dev);
-	if (rc)
-		GOTO(out, rc);
-	/* Request backing store for saved sequence info. */
-	rc = seq_store_read(seq, env);
-	if (rc == -ENODATA) {
-
-		/* Nothing is read, init by default value. */
-		seq->lss_space = is_srv ?
-			LUSTRE_SEQ_ZERO_RANGE:
-			LUSTRE_SEQ_SPACE_RANGE;
-
-		LASSERT(ss != NULL);
-		seq->lss_space.lsr_index = ss->ss_node_id;
-		LCONSOLE_INFO("%s: No data found "
-			      "on store. Initialize space\n",
-			      seq->lss_name);
-
-		rc = seq_store_update(env, seq, NULL, 0);
-		if (rc) {
-			CERROR("%s: Can't write space data, "
-			       "rc %d\n", seq->lss_name, rc);
-		}
-	} else if (rc) {
-		CERROR("%s: Can't read space data, rc %d\n",
-		       seq->lss_name, rc);
-		GOTO(out, rc);
-	}
-
-	if (is_srv) {
-		LASSERT(range_is_sane(&seq->lss_space));
-	} else {
-		LASSERT(!range_is_zero(&seq->lss_space) &&
-			range_is_sane(&seq->lss_space));
-	}
-
-	rc  = seq_server_proc_init(seq);
-	if (rc)
-		GOTO(out, rc);
-
-	EXIT;
-out:
-	if (rc)
-		seq_server_fini(seq, env);
-	return rc;
-}
-EXPORT_SYMBOL(seq_server_init);
-
-void seq_server_fini(struct lu_server_seq *seq,
-		     const struct lu_env *env)
-{
-	ENTRY;
-
-	seq_server_proc_fini(seq);
-	seq_store_fini(seq, env);
-
-	EXIT;
-}
-EXPORT_SYMBOL(seq_server_fini);
-
-int seq_site_fini(const struct lu_env *env, struct seq_server_site *ss)
-{
-	if (ss == NULL)
-		RETURN(0);
-
-	if (ss->ss_server_seq) {
-		seq_server_fini(ss->ss_server_seq, env);
-		OBD_FREE_PTR(ss->ss_server_seq);
-		ss->ss_server_seq = NULL;
-	}
-
-	if (ss->ss_control_seq) {
-		seq_server_fini(ss->ss_control_seq, env);
-		OBD_FREE_PTR(ss->ss_control_seq);
-		ss->ss_control_seq = NULL;
-	}
-
-	if (ss->ss_client_seq) {
-		seq_client_fini(ss->ss_client_seq);
-		OBD_FREE_PTR(ss->ss_client_seq);
-		ss->ss_client_seq = NULL;
-	}
-
-	RETURN(0);
-}
-EXPORT_SYMBOL(seq_site_fini);
-
-proc_dir_entry_t *seq_type_proc_dir = NULL;
-
-static int __init fid_mod_init(void)
-{
-	seq_type_proc_dir = lprocfs_register(LUSTRE_SEQ_NAME,
-					     proc_lustre_root,
-					     NULL, NULL);
-	if (IS_ERR(seq_type_proc_dir))
-		return PTR_ERR(seq_type_proc_dir);
-
-	LU_CONTEXT_KEY_INIT(&seq_thread_key);
-	lu_context_key_register(&seq_thread_key);
-	return 0;
-}
-
-static void __exit fid_mod_exit(void)
-{
-	lu_context_key_degister(&seq_thread_key);
-	if (seq_type_proc_dir != NULL && !IS_ERR(seq_type_proc_dir)) {
-		lprocfs_remove(&seq_type_proc_dir);
-		seq_type_proc_dir = NULL;
-	}
-}
-
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
-MODULE_DESCRIPTION("Lustre FID Module");
-MODULE_LICENSE("GPL");
-
-cfs_module(fid, "0.1.0", fid_mod_init, fid_mod_exit);
diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h
index 407a743..1dbe46b 100644
--- a/drivers/staging/lustre/lustre/fid/fid_internal.h
+++ b/drivers/staging/lustre/lustre/fid/fid_internal.h
@@ -41,44 +41,16 @@
 #define __FID_INTERNAL_H
 
 #include <lustre/lustre_idl.h>
-#include <dt_object.h>
-
 #include <linux/libcfs/libcfs.h>
 
-struct seq_thread_info {
-	struct req_capsule     *sti_pill;
-	struct lu_seq_range     sti_space;
-	struct lu_buf	   sti_buf;
-};
-
-enum {
-	SEQ_TXN_STORE_CREDITS = 20
-};
-
-extern struct lu_context_key seq_thread_key;
-
+/* Functions used internally in module. */
 int seq_client_alloc_super(struct lu_client_seq *seq,
 			   const struct lu_env *env);
-/* Store API functions. */
-int seq_store_init(struct lu_server_seq *seq,
-		   const struct lu_env *env,
-		   struct dt_device *dt);
 
-void seq_store_fini(struct lu_server_seq *seq,
-		    const struct lu_env *env);
-
-int seq_store_read(struct lu_server_seq *seq,
-		   const struct lu_env *env);
-
-int seq_store_update(const struct lu_env *env, struct lu_server_seq *seq,
-		     struct lu_seq_range *out, int sync);
-
-#ifdef LPROCFS
-extern struct lprocfs_vars seq_server_proc_list[];
+# ifdef LPROCFS
 extern struct lprocfs_vars seq_client_proc_list[];
-#endif
+# endif
 
-
-extern proc_dir_entry_t *seq_type_proc_dir;
+extern struct proc_dir_entry *seq_type_proc_dir;
 
 #endif /* __FID_INTERNAL_H */
diff --git a/drivers/staging/lustre/lustre/fid/fid_lib.c b/drivers/staging/lustre/lustre/fid/fid_lib.c
index eaff51a..f03afde 100644
--- a/drivers/staging/lustre/lustre/fid/fid_lib.c
+++ b/drivers/staging/lustre/lustre/fid/fid_lib.c
@@ -43,11 +43,9 @@
 
 #define DEBUG_SUBSYSTEM S_FID
 
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-
-#include <obd.h>
-#include <lu_object.h>
+#include <linux/libcfs/libcfs.h>
+#include <linux/module.h>
+#include <lustre/lustre_idl.h>
 #include <lustre_fid.h>
 
 /**
@@ -56,9 +54,9 @@
  *
  * Fid namespace:
  * <pre>
- * Normal FID:	seq:64 [2^33,2^64-1]      oid:32	  ver:32
- * IGIF      :	0:32, ino:32	      gen:32	  0:32
- * IDIF      :	0:31, 1:1, ost-index:16,  objd:48	 0:32
+ * Normal FID:        seq:64 [2^33,2^64-1]      oid:32          ver:32
+ * IGIF      :        0:32, ino:32              gen:32          0:32
+ * IDIF      :        0:31, 1:1, ost-index:16,  objd:48         0:32
  * </pre>
  *
  * The first 0x400 sequences of normal FID are reserved for special purpose.
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index fcaaca7..66007b5 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -27,7 +27,7 @@
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2013, Intel Corporation.
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
@@ -42,15 +42,12 @@
 
 #define DEBUG_SUBSYSTEM S_FID
 
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
+#include <linux/libcfs/libcfs.h>
+#include <linux/module.h>
 
 #include <obd.h>
 #include <obd_class.h>
-#include <dt_object.h>
-#include <md_object.h>
 #include <obd_support.h>
-#include <lustre_req_layout.h>
 #include <lustre_fid.h>
 /* mdc RPC locks */
 #include <lustre_mdc.h>
@@ -63,15 +60,14 @@
 	struct obd_export     *exp = seq->lcs_exp;
 	struct ptlrpc_request *req;
 	struct lu_seq_range   *out, *in;
-	__u32		 *op;
-	unsigned int	   debug_mask;
-	int		    rc;
-	ENTRY;
+	__u32                 *op;
+	unsigned int           debug_mask;
+	int                    rc;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), &RQF_SEQ_QUERY,
 					LUSTRE_MDS_VERSION, SEQ_QUERY);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* Init operation code */
 	op = req_capsule_client_get(&req->rq_pill, &RMF_SEQ_OPC);
@@ -137,7 +133,6 @@
 	CDEBUG_LIMIT(debug_mask, "%s: Allocated %s-sequence "DRANGE"]\n",
 		     seq->lcs_name, opcname, PRANGE(output));
 
-	EXIT;
 out_req:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -148,27 +143,24 @@
 			   const struct lu_env *env)
 {
 	int rc;
-	ENTRY;
 
 	mutex_lock(&seq->lcs_mutex);
 
 	if (seq->lcs_srv) {
-		LASSERT(env != NULL);
-		rc = seq_server_alloc_super(seq->lcs_srv, &seq->lcs_space,
-					    env);
+		rc = 0;
 	} else {
 		/* Check whether the connection to seq controller has been
 		 * setup (lcs_exp != NULL) */
 		if (seq->lcs_exp == NULL) {
 			mutex_unlock(&seq->lcs_mutex);
-			RETURN(-EINPROGRESS);
+			return -EINPROGRESS;
 		}
 
 		rc = seq_client_rpc(seq, &seq->lcs_space,
 				    SEQ_ALLOC_SUPER, "super");
 	}
 	mutex_unlock(&seq->lcs_mutex);
-	RETURN(rc);
+	return rc;
 }
 
 /* Request sequence-controller node to allocate new meta-sequence. */
@@ -176,11 +168,9 @@
 				 struct lu_client_seq *seq)
 {
 	int rc;
-	ENTRY;
 
 	if (seq->lcs_srv) {
-		LASSERT(env != NULL);
-		rc = seq_server_alloc_meta(seq->lcs_srv, &seq->lcs_space, env);
+		rc = 0;
 	} else {
 		do {
 			/* If meta server return -EINPROGRESS or EAGAIN,
@@ -191,7 +181,8 @@
 					    SEQ_ALLOC_META, "meta");
 		} while (rc == -EINPROGRESS || rc == -EAGAIN);
 	}
-	RETURN(rc);
+
+	return rc;
 }
 
 /* Allocate new sequence for client. */
@@ -199,7 +190,6 @@
 				struct lu_client_seq *seq, seqno_t *seqnr)
 {
 	int rc;
-	ENTRY;
 
 	LASSERT(range_is_sane(&seq->lcs_space));
 
@@ -208,7 +198,7 @@
 		if (rc) {
 			CERROR("%s: Can't allocate new meta-sequence,"
 			       "rc %d\n", seq->lcs_name, rc);
-			RETURN(rc);
+			return rc;
 		} else {
 			CDEBUG(D_INFO, "%s: New range - "DRANGE"\n",
 			       seq->lcs_name, PRANGE(&seq->lcs_space));
@@ -224,7 +214,7 @@
 	CDEBUG(D_INFO, "%s: Allocated sequence ["LPX64"]\n", seq->lcs_name,
 	       *seqnr);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int seq_fid_alloc_prep(struct lu_client_seq *seq,
@@ -312,7 +302,6 @@
 {
 	wait_queue_t link;
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 	LASSERT(fid != NULL);
@@ -344,7 +333,7 @@
 			       "rc %d\n", seq->lcs_name, rc);
 			seq_fid_alloc_fini(seq);
 			mutex_unlock(&seq->lcs_mutex);
-			RETURN(rc);
+			return rc;
 		}
 
 		CDEBUG(D_INFO, "%s: Switch to sequence "
@@ -368,7 +357,7 @@
 	mutex_unlock(&seq->lcs_mutex);
 
 	CDEBUG(D_INFO, "%s: Allocated FID "DFID"\n", seq->lcs_name,  PFID(fid));
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(seq_client_alloc_fid);
 
@@ -409,13 +398,21 @@
 }
 EXPORT_SYMBOL(seq_client_flush);
 
-static void seq_client_proc_fini(struct lu_client_seq *seq);
-
+static void seq_client_proc_fini(struct lu_client_seq *seq)
+{
 #ifdef LPROCFS
+	if (seq->lcs_proc_dir) {
+		if (!IS_ERR(seq->lcs_proc_dir))
+			lprocfs_remove(&seq->lcs_proc_dir);
+		seq->lcs_proc_dir = NULL;
+	}
+#endif /* LPROCFS */
+}
+
 static int seq_client_proc_init(struct lu_client_seq *seq)
 {
+#ifdef LPROCFS
 	int rc;
-	ENTRY;
 
 	seq->lcs_proc_dir = lprocfs_register(seq->lcs_name,
 					     seq_type_proc_dir,
@@ -425,7 +422,7 @@
 		CERROR("%s: LProcFS failed in seq-init\n",
 		       seq->lcs_name);
 		rc = PTR_ERR(seq->lcs_proc_dir);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = lprocfs_add_vars(seq->lcs_proc_dir,
@@ -436,34 +433,16 @@
 		GOTO(out_cleanup, rc);
 	}
 
-	RETURN(0);
+	return 0;
 
 out_cleanup:
 	seq_client_proc_fini(seq);
 	return rc;
-}
 
-static void seq_client_proc_fini(struct lu_client_seq *seq)
-{
-	ENTRY;
-	if (seq->lcs_proc_dir) {
-		if (!IS_ERR(seq->lcs_proc_dir))
-			lprocfs_remove(&seq->lcs_proc_dir);
-		seq->lcs_proc_dir = NULL;
-	}
-	EXIT;
-}
-#else
-static int seq_client_proc_init(struct lu_client_seq *seq)
-{
+#else /* LPROCFS */
 	return 0;
-}
-
-static void seq_client_proc_fini(struct lu_client_seq *seq)
-{
-	return;
-}
 #endif
+}
 
 int seq_client_init(struct lu_client_seq *seq,
 		    struct obd_export *exp,
@@ -472,7 +451,6 @@
 		    struct lu_server_seq *srv)
 {
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 	LASSERT(prefix != NULL);
@@ -501,14 +479,12 @@
 	rc = seq_client_proc_init(seq);
 	if (rc)
 		seq_client_fini(seq);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(seq_client_init);
 
 void seq_client_fini(struct lu_client_seq *seq)
 {
-	ENTRY;
-
 	seq_client_proc_fini(seq);
 
 	if (seq->lcs_exp != NULL) {
@@ -517,6 +493,78 @@
 	}
 
 	seq->lcs_srv = NULL;
-	EXIT;
 }
 EXPORT_SYMBOL(seq_client_fini);
+
+int client_fid_init(struct obd_device *obd,
+		    struct obd_export *exp, enum lu_cli_type type)
+{
+	struct client_obd *cli = &obd->u.cli;
+	char *prefix;
+	int rc;
+
+	OBD_ALLOC_PTR(cli->cl_seq);
+	if (cli->cl_seq == NULL)
+		return -ENOMEM;
+
+	OBD_ALLOC(prefix, MAX_OBD_NAME + 5);
+	if (prefix == NULL)
+		GOTO(out_free_seq, rc = -ENOMEM);
+
+	snprintf(prefix, MAX_OBD_NAME + 5, "cli-%s", obd->obd_name);
+
+	/* Init client side sequence-manager */
+	rc = seq_client_init(cli->cl_seq, exp, type, prefix, NULL);
+	OBD_FREE(prefix, MAX_OBD_NAME + 5);
+	if (rc)
+		GOTO(out_free_seq, rc);
+
+	return rc;
+out_free_seq:
+	OBD_FREE_PTR(cli->cl_seq);
+	cli->cl_seq = NULL;
+	return rc;
+}
+EXPORT_SYMBOL(client_fid_init);
+
+int client_fid_fini(struct obd_device *obd)
+{
+	struct client_obd *cli = &obd->u.cli;
+
+	if (cli->cl_seq != NULL) {
+		seq_client_fini(cli->cl_seq);
+		OBD_FREE_PTR(cli->cl_seq);
+		cli->cl_seq = NULL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(client_fid_fini);
+
+struct proc_dir_entry *seq_type_proc_dir;
+
+static int __init fid_mod_init(void)
+{
+	seq_type_proc_dir = lprocfs_register(LUSTRE_SEQ_NAME,
+					     proc_lustre_root,
+					     NULL, NULL);
+	if (IS_ERR(seq_type_proc_dir))
+		return PTR_ERR(seq_type_proc_dir);
+	return 0;
+}
+
+static void __exit fid_mod_exit(void)
+{
+	if (seq_type_proc_dir != NULL && !IS_ERR(seq_type_proc_dir)) {
+		lprocfs_remove(&seq_type_proc_dir);
+		seq_type_proc_dir = NULL;
+	}
+}
+
+MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_DESCRIPTION("Lustre FID Module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.0");
+
+module_init(fid_mod_init);
+module_exit(fid_mod_exit);
diff --git a/drivers/staging/lustre/lustre/fid/fid_store.c b/drivers/staging/lustre/lustre/fid/fid_store.c
deleted file mode 100644
index a90e6e3..0000000
--- a/drivers/staging/lustre/lustre/fid/fid_store.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2013, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fid/fid_store.c
- *
- * Lustre Sequence Manager
- *
- * Author: Yury Umanets <umka@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FID
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <dt_object.h>
-#include <md_object.h>
-#include <obd_support.h>
-#include <lustre_req_layout.h>
-#include <lustre_fid.h>
-#include "fid_internal.h"
-
-
-static struct lu_buf *seq_store_buf(struct seq_thread_info *info)
-{
-	struct lu_buf *buf;
-
-	buf = &info->sti_buf;
-	buf->lb_buf = &info->sti_space;
-	buf->lb_len = sizeof(info->sti_space);
-	return buf;
-}
-
-struct seq_update_callback {
-	struct dt_txn_commit_cb suc_cb;
-	struct lu_server_seq   *suc_seq;
-};
-
-void seq_update_cb(struct lu_env *env, struct thandle *th,
-		   struct dt_txn_commit_cb *cb, int err)
-{
-	struct seq_update_callback *ccb;
-
-	ccb = container_of0(cb, struct seq_update_callback, suc_cb);
-
-	LASSERT(ccb->suc_seq != NULL);
-
-	ccb->suc_seq->lss_need_sync = 0;
-	OBD_FREE_PTR(ccb);
-}
-
-int seq_update_cb_add(struct thandle *th, struct lu_server_seq *seq)
-{
-	struct seq_update_callback *ccb;
-	struct dt_txn_commit_cb	   *dcb;
-	int			   rc;
-
-	OBD_ALLOC_PTR(ccb);
-	if (ccb == NULL)
-		return -ENOMEM;
-
-	ccb->suc_seq	   = seq;
-	seq->lss_need_sync = 1;
-
-	dcb	       = &ccb->suc_cb;
-	dcb->dcb_func  = seq_update_cb;
-	INIT_LIST_HEAD(&dcb->dcb_linkage);
-	strncpy(dcb->dcb_name, "seq_update_cb", MAX_COMMIT_CB_STR_LEN);
-	dcb->dcb_name[MAX_COMMIT_CB_STR_LEN - 1] = '\0';
-
-	rc = dt_trans_cb_add(th, dcb);
-	if (rc)
-		OBD_FREE_PTR(ccb);
-	return rc;
-}
-
-/* This function implies that caller takes care about locking. */
-int seq_store_update(const struct lu_env *env, struct lu_server_seq *seq,
-		     struct lu_seq_range *out, int sync)
-{
-	struct dt_device *dt_dev = lu2dt_dev(seq->lss_obj->do_lu.lo_dev);
-	struct seq_thread_info *info;
-	struct thandle *th;
-	loff_t pos = 0;
-	int rc;
-
-	info = lu_context_key_get(&env->le_ctx, &seq_thread_key);
-	LASSERT(info != NULL);
-
-	th = dt_trans_create(env, dt_dev);
-	if (IS_ERR(th))
-		RETURN(PTR_ERR(th));
-
-	rc = dt_declare_record_write(env, seq->lss_obj,
-				     sizeof(struct lu_seq_range), 0, th);
-	if (rc)
-		GOTO(exit, rc);
-
-	if (out != NULL) {
-		rc = fld_declare_server_create(env,
-					       seq->lss_site->ss_server_fld,
-					       out, th);
-		if (rc)
-			GOTO(exit, rc);
-	}
-
-	rc = dt_trans_start_local(env, dt_dev, th);
-	if (rc)
-		GOTO(exit, rc);
-
-	/* Store ranges in le format. */
-	range_cpu_to_le(&info->sti_space, &seq->lss_space);
-
-	rc = dt_record_write(env, seq->lss_obj, seq_store_buf(info), &pos, th);
-	if (rc) {
-		CERROR("%s: Can't write space data, rc %d\n",
-		       seq->lss_name, rc);
-		GOTO(exit, rc);
-	} else if (out != NULL) {
-		rc = fld_server_create(env, seq->lss_site->ss_server_fld, out,
-				       th);
-		if (rc) {
-			CERROR("%s: Can't Update fld database, rc %d\n",
-				seq->lss_name, rc);
-			GOTO(exit, rc);
-		}
-	}
-	/* next sequence update will need sync until this update is committed
-	 * in case of sync operation this is not needed obviously */
-	if (!sync)
-		/* if callback can't be added then sync always */
-		sync = !!seq_update_cb_add(th, seq);
-
-	th->th_sync |= sync;
-exit:
-	dt_trans_stop(env, dt_dev, th);
-	return rc;
-}
-
-/*
- * This function implies that caller takes care about locking or locking is not
- * needed (init time).
- */
-int seq_store_read(struct lu_server_seq *seq,
-		   const struct lu_env *env)
-{
-	struct seq_thread_info *info;
-	loff_t pos = 0;
-	int rc;
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &seq_thread_key);
-	LASSERT(info != NULL);
-
-	rc = seq->lss_obj->do_body_ops->dbo_read(env, seq->lss_obj,
-						 seq_store_buf(info),
-						 &pos, BYPASS_CAPA);
-
-	if (rc == sizeof(info->sti_space)) {
-		range_le_to_cpu(&seq->lss_space, &info->sti_space);
-		CDEBUG(D_INFO, "%s: Space - "DRANGE"\n",
-		       seq->lss_name, PRANGE(&seq->lss_space));
-		rc = 0;
-	} else if (rc == 0) {
-		rc = -ENODATA;
-	} else if (rc > 0) {
-		CERROR("%s: Read only %d bytes of %d\n", seq->lss_name,
-		       rc, (int)sizeof(info->sti_space));
-		rc = -EIO;
-	}
-
-	RETURN(rc);
-}
-
-int seq_store_init(struct lu_server_seq *seq,
-		   const struct lu_env *env,
-		   struct dt_device *dt)
-{
-	struct dt_object *dt_obj;
-	struct lu_fid fid;
-	struct lu_attr attr;
-	struct dt_object_format dof;
-	const char *name;
-	int rc;
-	ENTRY;
-
-	name = seq->lss_type == LUSTRE_SEQ_SERVER ?
-		LUSTRE_SEQ_SRV_NAME : LUSTRE_SEQ_CTL_NAME;
-
-	if (seq->lss_type == LUSTRE_SEQ_SERVER)
-		lu_local_obj_fid(&fid, FID_SEQ_SRV_OID);
-	else
-		lu_local_obj_fid(&fid, FID_SEQ_CTL_OID);
-
-	memset(&attr, 0, sizeof(attr));
-	attr.la_valid = LA_MODE;
-	attr.la_mode = S_IFREG | 0666;
-	dof.dof_type = DFT_REGULAR;
-
-	dt_obj = dt_find_or_create(env, dt, &fid, &dof, &attr);
-	if (!IS_ERR(dt_obj)) {
-		seq->lss_obj = dt_obj;
-		rc = 0;
-	} else {
-		CERROR("%s: Can't find \"%s\" obj %d\n",
-		       seq->lss_name, name, (int)PTR_ERR(dt_obj));
-		rc = PTR_ERR(dt_obj);
-	}
-
-	RETURN(rc);
-}
-
-void seq_store_fini(struct lu_server_seq *seq,
-		    const struct lu_env *env)
-{
-	ENTRY;
-
-	if (seq->lss_obj != NULL) {
-		if (!IS_ERR(seq->lss_obj))
-			lu_object_put(env, &seq->lss_obj->do_lu);
-		seq->lss_obj = NULL;
-	}
-
-	EXIT;
-}
diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c
index af817a8..294070d 100644
--- a/drivers/staging/lustre/lustre/fid/lproc_fid.c
+++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c
@@ -65,7 +65,6 @@
 {
 	struct lu_seq_range tmp;
 	int rc;
-	ENTRY;
 
 	LASSERT(range != NULL);
 
@@ -73,9 +72,9 @@
 		    (long long unsigned *)&tmp.lsr_start,
 		    (long long unsigned *)&tmp.lsr_end);
 	if (rc != 2 || !range_is_sane(&tmp) || range_is_zero(&tmp))
-		RETURN(-EINVAL);
+		return -EINVAL;
 	*range = tmp;
-	RETURN(0);
+	return 0;
 }
 
 /* Client side procfs stuff */
@@ -85,7 +84,6 @@
 {
 	struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private;
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 
@@ -99,7 +97,7 @@
 
 	mutex_unlock(&seq->lcs_mutex);
 
-	RETURN(count);
+	return count;
 }
 
 static int
@@ -107,7 +105,6 @@
 {
 	struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 
@@ -115,7 +112,7 @@
 	rc = seq_printf(m, "["LPX64" - "LPX64"]:%x:%s\n", PRANGE(&seq->lcs_space));
 	mutex_unlock(&seq->lcs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 
 static ssize_t
@@ -125,13 +122,12 @@
 	struct lu_client_seq *seq = ((struct seq_file *)file->private_data)->private;
 	__u64  max;
 	int rc, val;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 
 	rc = lprocfs_write_helper(buffer, count, &val);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	mutex_lock(&seq->lcs_mutex);
 	if (seq->lcs_type == LUSTRE_SEQ_DATA)
@@ -150,7 +146,7 @@
 
 	mutex_unlock(&seq->lcs_mutex);
 
-	RETURN(count);
+	return count;
 }
 
 static int
@@ -158,7 +154,6 @@
 {
 	struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 
@@ -166,7 +161,7 @@
 	rc = seq_printf(m, LPU64"\n", seq->lcs_width);
 	mutex_unlock(&seq->lcs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -174,7 +169,6 @@
 {
 	struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 
@@ -182,7 +176,7 @@
 	rc = seq_printf(m, DFID"\n", PFID(&seq->lcs_fid));
 	mutex_unlock(&seq->lcs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -191,7 +185,6 @@
 	struct lu_client_seq *seq = (struct lu_client_seq *)m->private;
 	struct client_obd *cli;
 	int rc;
-	ENTRY;
 
 	LASSERT(seq != NULL);
 
@@ -201,12 +194,9 @@
 	} else {
 		rc = seq_printf(m, "%s\n", seq->lcs_srv->lss_name);
 	}
-	RETURN(rc);
+	return rc;
 }
 
-struct lprocfs_vars seq_server_proc_list[] = {
-};
-
 LPROC_SEQ_FOPS(lprocfs_fid_space);
 LPROC_SEQ_FOPS(lprocfs_fid_width);
 LPROC_SEQ_FOPS_RO(lprocfs_fid_server);
diff --git a/drivers/staging/lustre/lustre/fld/Makefile b/drivers/staging/lustre/lustre/fld/Makefile
index e7f2881..90d46d8 100644
--- a/drivers/staging/lustre/lustre/fld/Makefile
+++ b/drivers/staging/lustre/lustre/fld/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_LUSTRE_FS) += fld.o
-fld-y := fld_handler.o fld_request.o fld_cache.o fld_index.o lproc_fld.o
+fld-y := fld_request.o fld_cache.o lproc_fld.o
 
 
 ccflags-y := -I$(src)/../include
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index 347f2ae..25099cb 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -45,7 +45,6 @@
 
 # include <linux/libcfs/libcfs.h>
 # include <linux/module.h>
-# include <linux/jbd.h>
 # include <asm/div64.h>
 
 #include <obd.h>
@@ -67,14 +66,13 @@
 				 int cache_size, int cache_threshold)
 {
 	struct fld_cache *cache;
-	ENTRY;
 
 	LASSERT(name != NULL);
 	LASSERT(cache_threshold < cache_size);
 
 	OBD_ALLOC_PTR(cache);
 	if (cache == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&cache->fci_entries_head);
 	INIT_LIST_HEAD(&cache->fci_lru);
@@ -94,7 +92,7 @@
 	CDEBUG(D_INFO, "%s: FLD cache - Size: %d, Threshold: %d\n",
 	       cache->fci_name, cache_size, cache_threshold);
 
-	RETURN(cache);
+	return cache;
 }
 
 /**
@@ -103,7 +101,6 @@
 void fld_cache_fini(struct fld_cache *cache)
 {
 	__u64 pct;
-	ENTRY;
 
 	LASSERT(cache != NULL);
 	fld_cache_flush(cache);
@@ -121,8 +118,6 @@
 	CDEBUG(D_INFO, "  Cache hits: "LPU64"%%\n", pct);
 
 	OBD_FREE_PTR(cache);
-
-	EXIT;
 }
 
 /**
@@ -147,7 +142,6 @@
 	struct lu_seq_range *c_range;
 	struct lu_seq_range *n_range;
 	struct list_head *head = &cache->fci_entries_head;
-	ENTRY;
 
 restart_fixup:
 
@@ -200,8 +194,6 @@
 		    c_range->lsr_end == n_range->lsr_end)
 			fld_cache_entry_delete(cache, f_curr);
 	}
-
-	EXIT;
 }
 
 /**
@@ -227,12 +219,11 @@
 	struct fld_cache_entry *flde;
 	struct list_head *curr;
 	int num = 0;
-	ENTRY;
 
 	LASSERT(cache != NULL);
 
 	if (cache->fci_cache_count < cache->fci_cache_size)
-		RETURN(0);
+		return 0;
 
 	curr = cache->fci_lru.prev;
 
@@ -248,7 +239,7 @@
 	CDEBUG(D_INFO, "%s: FLD cache - Shrunk by "
 	       "%d entries\n", cache->fci_name, num);
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -256,14 +247,10 @@
  */
 void fld_cache_flush(struct fld_cache *cache)
 {
-	ENTRY;
-
 	write_lock(&cache->fci_lock);
 	cache->fci_cache_size = 0;
 	fld_cache_shrink(cache);
 	write_unlock(&cache->fci_lock);
-
-	EXIT;
 }
 
 /**
@@ -280,11 +267,9 @@
 	const seqno_t new_end  = range->lsr_end;
 	struct fld_cache_entry *fldt;
 
-	ENTRY;
 	OBD_ALLOC_GFP(fldt, sizeof *fldt, GFP_ATOMIC);
 	if (!fldt) {
 		OBD_FREE_PTR(f_new);
-		EXIT;
 		/* overlap is not allowed, so dont mess up list. */
 		return;
 	}
@@ -307,7 +292,6 @@
 	fld_cache_entry_add(cache, fldt, &f_new->fce_list);
 
 	/* no need to fixup */
-	EXIT;
 }
 
 /**
@@ -383,10 +367,10 @@
 
 	OBD_ALLOC_PTR(f_new);
 	if (!f_new)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	f_new->fce_range = *range;
-	RETURN(f_new);
+	return f_new;
 }
 
 /**
@@ -405,7 +389,6 @@
 	const seqno_t new_start  = f_new->fce_range.lsr_start;
 	const seqno_t new_end  = f_new->fce_range.lsr_end;
 	__u32 new_flags  = f_new->fce_range.lsr_flags;
-	ENTRY;
 
 	/*
 	 * Duplicate entries are eliminated in insert op.
@@ -441,7 +424,7 @@
 	/* Add new entry to cache and lru list. */
 	fld_cache_entry_add(cache, f_new, prev);
 out:
-	RETURN(0);
+	return 0;
 }
 
 int fld_cache_insert(struct fld_cache *cache,
@@ -452,7 +435,7 @@
 
 	flde = fld_cache_entry_create(range);
 	if (IS_ERR(flde))
-		RETURN(PTR_ERR(flde));
+		return PTR_ERR(flde);
 
 	write_lock(&cache->fci_lock);
 	rc = fld_cache_insert_nolock(cache, flde);
@@ -460,7 +443,7 @@
 	if (rc)
 		OBD_FREE_PTR(flde);
 
-	RETURN(rc);
+	return rc;
 }
 
 void fld_cache_delete_nolock(struct fld_cache *cache,
@@ -512,7 +495,7 @@
 		}
 	}
 
-	RETURN(got);
+	return got;
 }
 
 /**
@@ -522,12 +505,11 @@
 *fld_cache_entry_lookup(struct fld_cache *cache, struct lu_seq_range *range)
 {
 	struct fld_cache_entry *got = NULL;
-	ENTRY;
 
 	read_lock(&cache->fci_lock);
 	got = fld_cache_entry_lookup_nolock(cache, range);
 	read_unlock(&cache->fci_lock);
-	RETURN(got);
+	return got;
 }
 
 /**
@@ -539,7 +521,6 @@
 	struct fld_cache_entry *flde;
 	struct fld_cache_entry *prev = NULL;
 	struct list_head *head;
-	ENTRY;
 
 	read_lock(&cache->fci_lock);
 	head = &cache->fci_entries_head;
@@ -558,9 +539,9 @@
 
 			cache->fci_stat.fst_cache++;
 			read_unlock(&cache->fci_lock);
-			RETURN(0);
+			return 0;
 		}
 	}
 	read_unlock(&cache->fci_lock);
-	RETURN(-ENOENT);
+	return -ENOENT;
 }
diff --git a/drivers/staging/lustre/lustre/fld/fld_handler.c b/drivers/staging/lustre/lustre/fld/fld_handler.c
deleted file mode 100644
index d2707ae..0000000
--- a/drivers/staging/lustre/lustre/fld/fld_handler.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2013, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fld/fld_handler.c
- *
- * FLD (Fids Location Database)
- *
- * Author: Yury Umanets <umka@clusterfs.com>
- * Author: WangDi <wangdi@clusterfs.com>
- * Author: Pravin Shelar <pravin.shelar@sun.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FLD
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-# include <linux/jbd.h>
-# include <asm/div64.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <lustre_ver.h>
-#include <obd_support.h>
-#include <lprocfs_status.h>
-
-#include <md_object.h>
-#include <lustre_fid.h>
-#include <lustre_req_layout.h>
-#include "fld_internal.h"
-#include <lustre_fid.h>
-
-
-/* context key constructor/destructor: fld_key_init, fld_key_fini */
-LU_KEY_INIT_FINI(fld, struct fld_thread_info);
-
-/* context key: fld_thread_key */
-LU_CONTEXT_KEY_DEFINE(fld, LCT_MD_THREAD | LCT_DT_THREAD | LCT_MG_THREAD);
-
-proc_dir_entry_t *fld_type_proc_dir = NULL;
-
-static int __init fld_mod_init(void)
-{
-	fld_type_proc_dir = lprocfs_register(LUSTRE_FLD_NAME,
-					     proc_lustre_root,
-					     NULL, NULL);
-	if (IS_ERR(fld_type_proc_dir))
-		return PTR_ERR(fld_type_proc_dir);
-
-	LU_CONTEXT_KEY_INIT(&fld_thread_key);
-	lu_context_key_register(&fld_thread_key);
-	return 0;
-}
-
-static void __exit fld_mod_exit(void)
-{
-	lu_context_key_degister(&fld_thread_key);
-	if (fld_type_proc_dir != NULL && !IS_ERR(fld_type_proc_dir)) {
-		lprocfs_remove(&fld_type_proc_dir);
-		fld_type_proc_dir = NULL;
-	}
-}
-
-int fld_declare_server_create(const struct lu_env *env,
-			      struct lu_server_fld *fld,
-			      struct lu_seq_range *range,
-			      struct thandle *th)
-{
-	int rc;
-
-	rc = fld_declare_index_create(env, fld, range, th);
-	RETURN(rc);
-}
-EXPORT_SYMBOL(fld_declare_server_create);
-
-/**
- * Insert FLD index entry and update FLD cache.
- *
- * This function is called from the sequence allocator when a super-sequence
- * is granted to a server.
- */
-int fld_server_create(const struct lu_env *env, struct lu_server_fld *fld,
-		      struct lu_seq_range *range, struct thandle *th)
-{
-	int rc;
-
-	mutex_lock(&fld->lsf_lock);
-	rc = fld_index_create(env, fld, range, th);
-	mutex_unlock(&fld->lsf_lock);
-
-	RETURN(rc);
-}
-EXPORT_SYMBOL(fld_server_create);
-
-/**
- *  Lookup mds by seq, returns a range for given seq.
- *
- *  If that entry is not cached in fld cache, request is sent to super
- *  sequence controller node (MDT0). All other MDT[1...N] and client
- *  cache fld entries, but this cache is not persistent.
- */
-int fld_server_lookup(const struct lu_env *env, struct lu_server_fld *fld,
-		      seqno_t seq, struct lu_seq_range *range)
-{
-	struct lu_seq_range *erange;
-	struct fld_thread_info *info;
-	int rc;
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-	LASSERT(info != NULL);
-	erange = &info->fti_lrange;
-
-	/* Lookup it in the cache. */
-	rc = fld_cache_lookup(fld->lsf_cache, seq, erange);
-	if (rc == 0) {
-		if (unlikely(fld_range_type(erange) != fld_range_type(range) &&
-			     !fld_range_is_any(range))) {
-			CERROR("%s: FLD cache range "DRANGE" does not match"
-			       "requested flag %x: rc = %d\n", fld->lsf_name,
-			       PRANGE(erange), range->lsr_flags, -EIO);
-			RETURN(-EIO);
-		}
-		*range = *erange;
-		RETURN(0);
-	}
-
-	if (fld->lsf_obj) {
-		/* On server side, all entries should be in cache.
-		 * If we can not find it in cache, just return error */
-		CERROR("%s: Cannot find sequence "LPX64": rc = %d\n",
-			fld->lsf_name, seq, -EIO);
-		RETURN(-EIO);
-	} else {
-		LASSERT(fld->lsf_control_exp);
-		/* send request to mdt0 i.e. super seq. controller.
-		 * This is temporary solution, long term solution is fld
-		 * replication on all mdt servers.
-		 */
-		range->lsr_start = seq;
-		rc = fld_client_rpc(fld->lsf_control_exp,
-				    range, FLD_LOOKUP);
-		if (rc == 0)
-			fld_cache_insert(fld->lsf_cache, range);
-	}
-	RETURN(rc);
-}
-EXPORT_SYMBOL(fld_server_lookup);
-
-/**
- * All MDT server handle fld lookup operation. But only MDT0 has fld index.
- * if entry is not found in cache we need to forward lookup request to MDT0
- */
-
-static int fld_server_handle(struct lu_server_fld *fld,
-			     const struct lu_env *env,
-			     __u32 opc, struct lu_seq_range *range,
-			     struct fld_thread_info *info)
-{
-	int rc;
-	ENTRY;
-
-	switch (opc) {
-	case FLD_LOOKUP:
-		rc = fld_server_lookup(env, fld, range->lsr_start, range);
-		break;
-	default:
-		rc = -EINVAL;
-		break;
-	}
-
-	CDEBUG(D_INFO, "%s: FLD req handle: error %d (opc: %d, range: "
-	       DRANGE"\n", fld->lsf_name, rc, opc, PRANGE(range));
-
-	RETURN(rc);
-
-}
-
-static int fld_req_handle(struct ptlrpc_request *req,
-			  struct fld_thread_info *info)
-{
-	struct obd_export *exp = req->rq_export;
-	struct lu_site *site = exp->exp_obd->obd_lu_dev->ld_site;
-	struct lu_seq_range *in;
-	struct lu_seq_range *out;
-	int rc;
-	__u32 *opc;
-	ENTRY;
-
-	rc = req_capsule_server_pack(info->fti_pill);
-	if (rc)
-		RETURN(err_serious(rc));
-
-	opc = req_capsule_client_get(info->fti_pill, &RMF_FLD_OPC);
-	if (opc != NULL) {
-		in = req_capsule_client_get(info->fti_pill, &RMF_FLD_MDFLD);
-		if (in == NULL)
-			RETURN(err_serious(-EPROTO));
-		out = req_capsule_server_get(info->fti_pill, &RMF_FLD_MDFLD);
-		if (out == NULL)
-			RETURN(err_serious(-EPROTO));
-		*out = *in;
-
-		/* For old 2.0 client, the 'lsr_flags' is uninitialized.
-		 * Set it as 'LU_SEQ_RANGE_MDT' by default. */
-		if (!(exp_connect_flags(exp) & OBD_CONNECT_64BITHASH) &&
-		    !(exp_connect_flags(exp) & OBD_CONNECT_MDS_MDS) &&
-		    !(exp_connect_flags(exp) & OBD_CONNECT_LIGHTWEIGHT) &&
-		    !exp->exp_libclient)
-			fld_range_set_mdt(out);
-
-		rc = fld_server_handle(lu_site2seq(site)->ss_server_fld,
-				       req->rq_svc_thread->t_env,
-				       *opc, out, info);
-	} else {
-		rc = err_serious(-EPROTO);
-	}
-
-	RETURN(rc);
-}
-
-static void fld_thread_info_init(struct ptlrpc_request *req,
-				 struct fld_thread_info *info)
-{
-	info->fti_pill = &req->rq_pill;
-	/* Init request capsule. */
-	req_capsule_init(info->fti_pill, req, RCL_SERVER);
-	req_capsule_set(info->fti_pill, &RQF_FLD_QUERY);
-}
-
-static void fld_thread_info_fini(struct fld_thread_info *info)
-{
-	req_capsule_fini(info->fti_pill);
-}
-
-static int fld_handle(struct ptlrpc_request *req)
-{
-	struct fld_thread_info *info;
-	const struct lu_env *env;
-	int rc;
-
-	env = req->rq_svc_thread->t_env;
-	LASSERT(env != NULL);
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-	LASSERT(info != NULL);
-
-	fld_thread_info_init(req, info);
-	rc = fld_req_handle(req, info);
-	fld_thread_info_fini(info);
-
-	return rc;
-}
-
-/*
- * Entry point for handling FLD RPCs called from MDT.
- */
-int fld_query(struct com_thread_info *info)
-{
-	return fld_handle(info->cti_pill->rc_req);
-}
-EXPORT_SYMBOL(fld_query);
-
-/*
- * Returns true, if fid is local to this server node.
- *
- * WARNING: this function is *not* guaranteed to return false if fid is
- * remote: it makes an educated conservative guess only.
- *
- * fid_is_local() is supposed to be used in assertion checks only.
- */
-int fid_is_local(const struct lu_env *env,
-		 struct lu_site *site, const struct lu_fid *fid)
-{
-	int result;
-	struct seq_server_site *ss_site;
-	struct lu_seq_range *range;
-	struct fld_thread_info *info;
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-	range = &info->fti_lrange;
-
-	result = 1; /* conservatively assume fid is local */
-	ss_site = lu_site2seq(site);
-	if (ss_site->ss_client_fld != NULL) {
-		int rc;
-
-		rc = fld_cache_lookup(ss_site->ss_client_fld->lcf_cache,
-				      fid_seq(fid), range);
-		if (rc == 0)
-			result = (range->lsr_index == ss_site->ss_node_id);
-	}
-	return result;
-}
-EXPORT_SYMBOL(fid_is_local);
-
-static void fld_server_proc_fini(struct lu_server_fld *fld);
-
-#ifdef LPROCFS
-static int fld_server_proc_init(struct lu_server_fld *fld)
-{
-	int rc = 0;
-	ENTRY;
-
-	fld->lsf_proc_dir = lprocfs_register(fld->lsf_name,
-					     fld_type_proc_dir,
-					     fld_server_proc_list, fld);
-	if (IS_ERR(fld->lsf_proc_dir)) {
-		rc = PTR_ERR(fld->lsf_proc_dir);
-		RETURN(rc);
-	}
-
-	rc = lprocfs_seq_create(fld->lsf_proc_dir, "fldb", 0444,
-				&fld_proc_seq_fops, fld);
-	if (rc) {
-		lprocfs_remove(&fld->lsf_proc_dir);
-		fld->lsf_proc_dir = NULL;
-	}
-
-	RETURN(rc);
-}
-
-static void fld_server_proc_fini(struct lu_server_fld *fld)
-{
-	ENTRY;
-	if (fld->lsf_proc_dir != NULL) {
-		if (!IS_ERR(fld->lsf_proc_dir))
-			lprocfs_remove(&fld->lsf_proc_dir);
-		fld->lsf_proc_dir = NULL;
-	}
-	EXIT;
-}
-#else
-static int fld_server_proc_init(struct lu_server_fld *fld)
-{
-	return 0;
-}
-
-static void fld_server_proc_fini(struct lu_server_fld *fld)
-{
-	return;
-}
-#endif
-
-int fld_server_init(const struct lu_env *env, struct lu_server_fld *fld,
-		    struct dt_device *dt, const char *prefix, int mds_node_id,
-		    int type)
-{
-	int cache_size, cache_threshold;
-	int rc;
-	ENTRY;
-
-	snprintf(fld->lsf_name, sizeof(fld->lsf_name),
-		 "srv-%s", prefix);
-
-	cache_size = FLD_SERVER_CACHE_SIZE /
-		sizeof(struct fld_cache_entry);
-
-	cache_threshold = cache_size *
-		FLD_SERVER_CACHE_THRESHOLD / 100;
-
-	mutex_init(&fld->lsf_lock);
-	fld->lsf_cache = fld_cache_init(fld->lsf_name,
-					cache_size, cache_threshold);
-	if (IS_ERR(fld->lsf_cache)) {
-		rc = PTR_ERR(fld->lsf_cache);
-		fld->lsf_cache = NULL;
-		GOTO(out, rc);
-	}
-
-	if (!mds_node_id && type == LU_SEQ_RANGE_MDT) {
-		rc = fld_index_init(env, fld, dt);
-		if (rc)
-			GOTO(out, rc);
-	} else {
-		fld->lsf_obj = NULL;
-	}
-
-	rc = fld_server_proc_init(fld);
-	if (rc)
-		GOTO(out, rc);
-
-	fld->lsf_control_exp = NULL;
-
-	GOTO(out, rc);
-
-out:
-	if (rc)
-		fld_server_fini(env, fld);
-	return rc;
-}
-EXPORT_SYMBOL(fld_server_init);
-
-void fld_server_fini(const struct lu_env *env, struct lu_server_fld *fld)
-{
-	ENTRY;
-
-	fld_server_proc_fini(fld);
-	fld_index_fini(env, fld);
-
-	if (fld->lsf_cache != NULL) {
-		if (!IS_ERR(fld->lsf_cache))
-			fld_cache_fini(fld->lsf_cache);
-		fld->lsf_cache = NULL;
-	}
-
-	EXIT;
-}
-EXPORT_SYMBOL(fld_server_fini);
-
-MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
-MODULE_DESCRIPTION("Lustre FLD");
-MODULE_LICENSE("GPL");
-
-cfs_module(mdd, "0.1.0", fld_mod_init, fld_mod_exit);
diff --git a/drivers/staging/lustre/lustre/fld/fld_index.c b/drivers/staging/lustre/lustre/fld/fld_index.c
deleted file mode 100644
index ec68a54..0000000
--- a/drivers/staging/lustre/lustre/fld/fld_index.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2011, 2013, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * lustre/fld/fld_index.c
- *
- * Author: WangDi <wangdi@clusterfs.com>
- * Author: Yury Umanets <umka@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_FLD
-
-# include <linux/libcfs/libcfs.h>
-# include <linux/module.h>
-# include <linux/jbd.h>
-
-#include <obd.h>
-#include <obd_class.h>
-#include <lustre_ver.h>
-#include <obd_support.h>
-#include <lprocfs_status.h>
-
-#include <dt_object.h>
-#include <md_object.h>
-#include <lustre_mdc.h>
-#include <lustre_fid.h>
-#include <lustre_fld.h>
-#include "fld_internal.h"
-
-const char fld_index_name[] = "fld";
-
-static const struct lu_seq_range IGIF_FLD_RANGE = {
-	.lsr_start = FID_SEQ_IGIF,
-	.lsr_end   = FID_SEQ_IGIF_MAX + 1,
-	.lsr_index = 0,
-	.lsr_flags = LU_SEQ_RANGE_MDT
-};
-
-static const struct lu_seq_range DOT_LUSTRE_FLD_RANGE = {
-	.lsr_start = FID_SEQ_DOT_LUSTRE,
-	.lsr_end   = FID_SEQ_DOT_LUSTRE + 1,
-	.lsr_index = 0,
-	.lsr_flags = LU_SEQ_RANGE_MDT
-};
-
-static const struct lu_seq_range ROOT_FLD_RANGE = {
-	.lsr_start = FID_SEQ_ROOT,
-	.lsr_end   = FID_SEQ_ROOT + 1,
-	.lsr_index = 0,
-	.lsr_flags = LU_SEQ_RANGE_MDT
-};
-
-const struct dt_index_features fld_index_features = {
-	.dif_flags       = DT_IND_UPDATE,
-	.dif_keysize_min = sizeof(seqno_t),
-	.dif_keysize_max = sizeof(seqno_t),
-	.dif_recsize_min = sizeof(struct lu_seq_range),
-	.dif_recsize_max = sizeof(struct lu_seq_range),
-	.dif_ptrsize     = 4
-};
-
-extern struct lu_context_key fld_thread_key;
-
-int fld_declare_index_create(const struct lu_env *env,
-			     struct lu_server_fld *fld,
-			     const struct lu_seq_range *new_range,
-			     struct thandle *th)
-{
-	struct lu_seq_range	*tmp;
-	struct lu_seq_range	*range;
-	struct fld_thread_info	*info;
-	int			rc = 0;
-
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-	range = &info->fti_lrange;
-	tmp = &info->fti_irange;
-	memset(range, 0, sizeof(*range));
-
-	rc = fld_index_lookup(env, fld, new_range->lsr_start, range);
-	if (rc == 0) {
-		/* In case of duplicate entry, the location must be same */
-		LASSERT((range_compare_loc(new_range, range) == 0));
-		GOTO(out, rc = -EEXIST);
-	}
-
-	if (rc != -ENOENT) {
-		CERROR("%s: lookup range "DRANGE" error: rc = %d\n",
-			fld->lsf_name, PRANGE(range), rc);
-		GOTO(out, rc);
-	}
-
-	/* Check for merge case, since the fld entry can only be increamental,
-	 * so we will only check whether it can be merged from the left. */
-	if (new_range->lsr_start == range->lsr_end && range->lsr_end != 0 &&
-	    range_compare_loc(new_range, range) == 0) {
-		range_cpu_to_be(tmp, range);
-		rc = dt_declare_delete(env, fld->lsf_obj,
-				       (struct dt_key *)&tmp->lsr_start, th);
-		if (rc) {
-			CERROR("%s: declare record "DRANGE" failed: rc = %d\n",
-			       fld->lsf_name, PRANGE(range), rc);
-			GOTO(out, rc);
-		}
-		memcpy(tmp, new_range, sizeof(*new_range));
-		tmp->lsr_start = range->lsr_start;
-	} else {
-		memcpy(tmp, new_range, sizeof(*new_range));
-	}
-
-	range_cpu_to_be(tmp, tmp);
-	rc = dt_declare_insert(env, fld->lsf_obj, (struct dt_rec *)tmp,
-			       (struct dt_key *)&tmp->lsr_start, th);
-out:
-	RETURN(rc);
-}
-
-/**
- * insert range in fld store.
- *
- *      \param  range  range to be inserted
- *      \param  th     transaction for this operation as it could compound
- *		     transaction.
- *
- *      \retval  0  success
- *      \retval  -ve error
- *
- * The whole fld index insertion is protected by seq->lss_mutex (see
- * seq_server_alloc_super), i.e. only one thread will access fldb each
- * time, so we do not need worry the fld file and cache will being
- * changed between declare and create.
- * Because the fld entry can only be increamental, so we will only check
- * whether it can be merged from the left.
- **/
-int fld_index_create(const struct lu_env *env, struct lu_server_fld *fld,
-		     const struct lu_seq_range *new_range, struct thandle *th)
-{
-	struct lu_seq_range	*range;
-	struct lu_seq_range	*tmp;
-	struct fld_thread_info	*info;
-	int			rc = 0;
-	int			deleted = 0;
-	struct fld_cache_entry	*flde;
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-
-	LASSERT(mutex_is_locked(&fld->lsf_lock));
-
-	range = &info->fti_lrange;
-	memset(range, 0, sizeof(*range));
-	tmp = &info->fti_irange;
-	rc = fld_index_lookup(env, fld, new_range->lsr_start, range);
-	if (rc != -ENOENT) {
-		rc = rc == 0 ? -EEXIST : rc;
-		GOTO(out, rc);
-	}
-
-	if (new_range->lsr_start == range->lsr_end && range->lsr_end != 0 &&
-	    range_compare_loc(new_range, range) == 0) {
-		range_cpu_to_be(tmp, range);
-		rc = dt_delete(env, fld->lsf_obj,
-			       (struct dt_key *)&tmp->lsr_start, th,
-				BYPASS_CAPA);
-		if (rc != 0)
-			GOTO(out, rc);
-		memcpy(tmp, new_range, sizeof(*new_range));
-		tmp->lsr_start = range->lsr_start;
-		deleted = 1;
-	} else {
-		memcpy(tmp, new_range, sizeof(*new_range));
-	}
-
-	range_cpu_to_be(tmp, tmp);
-	rc = dt_insert(env, fld->lsf_obj, (struct dt_rec *)tmp,
-		       (struct dt_key *)&tmp->lsr_start, th, BYPASS_CAPA, 1);
-	if (rc != 0) {
-		CERROR("%s: insert range "DRANGE" failed: rc = %d\n",
-		       fld->lsf_name, PRANGE(new_range), rc);
-		GOTO(out, rc);
-	}
-
-	flde = fld_cache_entry_create(new_range);
-	if (IS_ERR(flde))
-		GOTO(out, rc = PTR_ERR(flde));
-
-	write_lock(&fld->lsf_cache->fci_lock);
-	if (deleted)
-		fld_cache_delete_nolock(fld->lsf_cache, new_range);
-	rc = fld_cache_insert_nolock(fld->lsf_cache, flde);
-	write_unlock(&fld->lsf_cache->fci_lock);
-	if (rc)
-		OBD_FREE_PTR(flde);
-out:
-	RETURN(rc);
-}
-
-/**
- * lookup range for a seq passed. note here we only care about the start/end,
- * caller should handle the attached location data (flags, index).
- *
- * \param  seq     seq for lookup.
- * \param  range   result of lookup.
- *
- * \retval  0	   found, \a range is the matched range;
- * \retval -ENOENT      not found, \a range is the left-side range;
- * \retval  -ve	 other error;
- */
-int fld_index_lookup(const struct lu_env *env, struct lu_server_fld *fld,
-		     seqno_t seq, struct lu_seq_range *range)
-{
-	struct lu_seq_range     *fld_rec;
-	struct fld_thread_info  *info;
-	int rc;
-
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-	fld_rec = &info->fti_rec;
-
-	rc = fld_cache_lookup(fld->lsf_cache, seq, fld_rec);
-	if (rc == 0) {
-		*range = *fld_rec;
-		if (range_within(range, seq))
-			rc = 0;
-		else
-			rc = -ENOENT;
-	}
-
-	CDEBUG(D_INFO, "%s: lookup seq = "LPX64" range : "DRANGE" rc = %d\n",
-	       fld->lsf_name, seq, PRANGE(range), rc);
-
-	RETURN(rc);
-}
-
-int fld_insert_entry(const struct lu_env *env,
-		     struct lu_server_fld *fld,
-		     const struct lu_seq_range *range)
-{
-	struct thandle *th;
-	int rc;
-	ENTRY;
-
-	th = dt_trans_create(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev));
-	if (IS_ERR(th))
-		RETURN(PTR_ERR(th));
-
-	rc = fld_declare_index_create(env, fld, range, th);
-	if (rc != 0) {
-		if (rc == -EEXIST)
-			rc = 0;
-		GOTO(out, rc);
-	}
-
-	rc = dt_trans_start_local(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev),
-				  th);
-	if (rc)
-		GOTO(out, rc);
-
-	rc = fld_index_create(env, fld, range, th);
-	if (rc == -EEXIST)
-		rc = 0;
-out:
-	dt_trans_stop(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th);
-	RETURN(rc);
-}
-EXPORT_SYMBOL(fld_insert_entry);
-
-static int fld_insert_special_entries(const struct lu_env *env,
-				      struct lu_server_fld *fld)
-{
-	int rc;
-
-	rc = fld_insert_entry(env, fld, &IGIF_FLD_RANGE);
-	if (rc != 0)
-		RETURN(rc);
-
-	rc = fld_insert_entry(env, fld, &DOT_LUSTRE_FLD_RANGE);
-	if (rc != 0)
-		RETURN(rc);
-
-	rc = fld_insert_entry(env, fld, &ROOT_FLD_RANGE);
-
-	RETURN(rc);
-}
-
-int fld_index_init(const struct lu_env *env, struct lu_server_fld *fld,
-		   struct dt_device *dt)
-{
-	struct dt_object	*dt_obj = NULL;
-	struct lu_fid		fid;
-	struct lu_attr		*attr = NULL;
-	struct lu_seq_range	*range = NULL;
-	struct fld_thread_info	*info;
-	struct dt_object_format	dof;
-	struct dt_it		*it;
-	const struct dt_it_ops	*iops;
-	int			rc;
-	ENTRY;
-
-	info = lu_context_key_get(&env->le_ctx, &fld_thread_key);
-	LASSERT(info != NULL);
-
-	lu_local_obj_fid(&fid, FLD_INDEX_OID);
-	OBD_ALLOC_PTR(attr);
-	if (attr == NULL)
-		RETURN(-ENOMEM);
-
-	memset(attr, 0, sizeof(*attr));
-	attr->la_valid = LA_MODE;
-	attr->la_mode = S_IFREG | 0666;
-	dof.dof_type = DFT_INDEX;
-	dof.u.dof_idx.di_feat = &fld_index_features;
-
-	dt_obj = dt_find_or_create(env, dt, &fid, &dof, attr);
-	if (IS_ERR(dt_obj)) {
-		rc = PTR_ERR(dt_obj);
-		CERROR("%s: Can't find \"%s\" obj %d\n", fld->lsf_name,
-			fld_index_name, rc);
-		dt_obj = NULL;
-		GOTO(out, rc);
-	}
-
-	fld->lsf_obj = dt_obj;
-	rc = dt_obj->do_ops->do_index_try(env, dt_obj, &fld_index_features);
-	if (rc != 0) {
-		CERROR("%s: File \"%s\" is not an index: rc = %d!\n",
-		       fld->lsf_name, fld_index_name, rc);
-		GOTO(out, rc);
-	}
-
-	range = &info->fti_rec;
-	/* Load fld entry to cache */
-	iops = &dt_obj->do_index_ops->dio_it;
-	it = iops->init(env, dt_obj, 0, NULL);
-	if (IS_ERR(it))
-		GOTO(out, rc = PTR_ERR(it));
-
-	rc = iops->load(env, it, 0);
-	if (rc < 0)
-		GOTO(out_it_fini, rc);
-
-	if (rc > 0) {
-		/* Load FLD entry into server cache */
-		do {
-			rc = iops->rec(env, it, (struct dt_rec *)range, 0);
-			if (rc != 0)
-				GOTO(out_it_put, rc);
-			LASSERT(range != NULL);
-			range_be_to_cpu(range, range);
-			rc = fld_cache_insert(fld->lsf_cache, range);
-			if (rc != 0)
-				GOTO(out_it_put, rc);
-			rc = iops->next(env, it);
-		} while (rc == 0);
-	}
-
-	/* Note: fld_insert_entry will detect whether these
-	 * special entries already exist inside FLDB */
-	mutex_lock(&fld->lsf_lock);
-	rc = fld_insert_special_entries(env, fld);
-	mutex_unlock(&fld->lsf_lock);
-	if (rc != 0) {
-		CERROR("%s: insert special entries failed!: rc = %d\n",
-		       fld->lsf_name, rc);
-		GOTO(out_it_put, rc);
-	}
-
-out_it_put:
-	iops->put(env, it);
-out_it_fini:
-	iops->fini(env, it);
-out:
-	if (attr != NULL)
-		OBD_FREE_PTR(attr);
-
-	if (rc != 0) {
-		if (dt_obj != NULL)
-			lu_object_put(env, &dt_obj->do_lu);
-		fld->lsf_obj = NULL;
-	}
-	RETURN(rc);
-}
-
-void fld_index_fini(const struct lu_env *env, struct lu_server_fld *fld)
-{
-	ENTRY;
-	if (fld->lsf_obj != NULL) {
-		if (!IS_ERR(fld->lsf_obj))
-			lu_object_put(env, &fld->lsf_obj->do_lu);
-		fld->lsf_obj = NULL;
-	}
-	EXIT;
-}
diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h
index 9fa9e01..56686b1 100644
--- a/drivers/staging/lustre/lustre/fld/fld_internal.h
+++ b/drivers/staging/lustre/lustre/fld/fld_internal.h
@@ -139,38 +139,10 @@
 
 extern struct lu_fld_hash fld_hash[];
 
-
-struct fld_thread_info {
-	struct req_capsule *fti_pill;
-	__u64	       fti_key;
-	struct lu_seq_range fti_rec;
-	struct lu_seq_range fti_lrange;
-	struct lu_seq_range fti_irange;
-};
-
-extern struct lu_context_key fld_thread_key;
-
-int fld_index_init(const struct lu_env *env, struct lu_server_fld *fld,
-		   struct dt_device *dt);
-
-void fld_index_fini(const struct lu_env *env, struct lu_server_fld *fld);
-
-int fld_declare_index_create(const struct lu_env *env,
-			     struct lu_server_fld *fld,
-			     const struct lu_seq_range *new,
-			     struct thandle *th);
-
-int fld_index_create(const struct lu_env *env, struct lu_server_fld *fld,
-		     const struct lu_seq_range *new, struct thandle *th);
-
-int fld_index_lookup(const struct lu_env *env, struct lu_server_fld *fld,
-		     seqno_t seq, struct lu_seq_range *range);
-
 int fld_client_rpc(struct obd_export *exp,
 		   struct lu_seq_range *range, __u32 fld_op);
 
 #ifdef LPROCFS
-extern struct lprocfs_vars fld_server_proc_list[];
 extern struct lprocfs_vars fld_client_proc_list[];
 #endif
 
@@ -218,6 +190,5 @@
 	return (const char *)tar->ft_exp->exp_obd->obd_name;
 }
 
-extern proc_dir_entry_t *fld_type_proc_dir;
-extern struct file_operations fld_proc_seq_fops;
+extern struct proc_dir_entry *fld_type_proc_dir;
 #endif /* __FLD_INTERNAL_H */
diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c
index e9f0739..078e98b 100644
--- a/drivers/staging/lustre/lustre/fld/fld_request.c
+++ b/drivers/staging/lustre/lustre/fld/fld_request.c
@@ -44,7 +44,6 @@
 
 # include <linux/libcfs/libcfs.h>
 # include <linux/module.h>
-# include <linux/jbd.h>
 # include <asm/div64.h>
 
 #include <obd.h>
@@ -60,16 +59,18 @@
 #include <lustre_mdc.h>
 #include "fld_internal.h"
 
+struct lu_context_key fld_thread_key;
+
 /* TODO: these 3 functions are copies of flow-control code from mdc_lib.c
  * It should be common thing. The same about mdc RPC lock */
 static int fld_req_avail(struct client_obd *cli, struct mdc_cache_waiter *mcw)
 {
 	int rc;
-	ENTRY;
+
 	client_obd_list_lock(&cli->cl_loi_list_lock);
 	rc = list_empty(&mcw->mcw_entry);
 	client_obd_list_unlock(&cli->cl_loi_list_lock);
-	RETURN(rc);
+	return rc;
 };
 
 static void fld_enter_request(struct client_obd *cli)
@@ -123,7 +124,6 @@
 {
 	struct lu_fld_target *target;
 	int hash;
-	ENTRY;
 
 	/* Because almost all of special sequence located in MDT0,
 	 * it should go to index 0 directly, instead of calculating
@@ -137,7 +137,7 @@
 
 	list_for_each_entry(target, &fld->lcf_targets, ft_chain) {
 		if (target->ft_idx == hash)
-			RETURN(target);
+			return target;
 	}
 
 	CERROR("%s: Can't find target by hash %d (seq "LPX64"). "
@@ -161,7 +161,7 @@
 	 * LBUG() to catch this situation.
 	 */
 	LBUG();
-	RETURN(NULL);
+	return NULL;
 }
 
 struct lu_fld_hash fld_hash[] = {
@@ -179,7 +179,6 @@
 fld_client_get_target(struct lu_client_fld *fld, seqno_t seq)
 {
 	struct lu_fld_target *target;
-	ENTRY;
 
 	LASSERT(fld->lcf_hash != NULL);
 
@@ -193,7 +192,7 @@
 		       target->ft_idx, seq);
 	}
 
-	RETURN(target);
+	return target;
 }
 
 /*
@@ -205,7 +204,6 @@
 {
 	const char *name;
 	struct lu_fld_target *target, *tmp;
-	ENTRY;
 
 	LASSERT(tar != NULL);
 	name = fld_target_name(tar);
@@ -216,7 +214,7 @@
 		CERROR("%s: Attempt to add target %s (idx "LPU64") "
 		       "on fly - skip it\n", fld->lcf_name, name,
 		       tar->ft_idx);
-		RETURN(0);
+		return 0;
 	} else {
 		CDEBUG(D_INFO, "%s: Adding target %s (idx "
 		       LPU64")\n", fld->lcf_name, name, tar->ft_idx);
@@ -224,7 +222,7 @@
 
 	OBD_ALLOC_PTR(target);
 	if (target == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	spin_lock(&fld->lcf_lock);
 	list_for_each_entry(tmp, &fld->lcf_targets, ft_chain) {
@@ -233,7 +231,7 @@
 			OBD_FREE_PTR(target);
 			CERROR("Target %s exists in FLD and known as %s:#"LPU64"\n",
 			       name, fld_target_name(tmp), tmp->ft_idx);
-			RETURN(-EEXIST);
+			return -EEXIST;
 		}
 	}
 
@@ -249,7 +247,7 @@
 	fld->lcf_count++;
 	spin_unlock(&fld->lcf_lock);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(fld_client_add_target);
 
@@ -257,7 +255,6 @@
 int fld_client_del_target(struct lu_client_fld *fld, __u64 idx)
 {
 	struct lu_fld_target *target, *tmp;
-	ENTRY;
 
 	spin_lock(&fld->lcf_lock);
 	list_for_each_entry_safe(target, tmp,
@@ -271,19 +268,20 @@
 				class_export_put(target->ft_exp);
 
 			OBD_FREE_PTR(target);
-			RETURN(0);
+			return 0;
 		}
 	}
 	spin_unlock(&fld->lcf_lock);
-	RETURN(-ENOENT);
+	return -ENOENT;
 }
 EXPORT_SYMBOL(fld_client_del_target);
 
 #ifdef LPROCFS
+struct proc_dir_entry *fld_type_proc_dir = NULL;
+
 static int fld_client_proc_init(struct lu_client_fld *fld)
 {
 	int rc;
-	ENTRY;
 
 	fld->lcf_proc_dir = lprocfs_register(fld->lcf_name,
 					     fld_type_proc_dir,
@@ -293,7 +291,7 @@
 		CERROR("%s: LProcFS failed in fld-init\n",
 		       fld->lcf_name);
 		rc = PTR_ERR(fld->lcf_proc_dir);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = lprocfs_add_vars(fld->lcf_proc_dir,
@@ -304,7 +302,7 @@
 		GOTO(out_cleanup, rc);
 	}
 
-	RETURN(0);
+	return 0;
 
 out_cleanup:
 	fld_client_proc_fini(fld);
@@ -313,13 +311,11 @@
 
 void fld_client_proc_fini(struct lu_client_fld *fld)
 {
-	ENTRY;
 	if (fld->lcf_proc_dir) {
 		if (!IS_ERR(fld->lcf_proc_dir))
 			lprocfs_remove(&fld->lcf_proc_dir);
 		fld->lcf_proc_dir = NULL;
 	}
-	EXIT;
 }
 #else
 static int fld_client_proc_init(struct lu_client_fld *fld)
@@ -345,7 +341,6 @@
 {
 	int cache_size, cache_threshold;
 	int rc;
-	ENTRY;
 
 	LASSERT(fld != NULL);
 
@@ -355,7 +350,7 @@
 	if (!hash_is_sane(hash)) {
 		CERROR("%s: Wrong hash function %#x\n",
 		       fld->lcf_name, hash);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	fld->lcf_count = 0;
@@ -381,7 +376,6 @@
 	rc = fld_client_proc_init(fld);
 	if (rc)
 		GOTO(out, rc);
-	EXIT;
 out:
 	if (rc)
 		fld_client_fini(fld);
@@ -395,7 +389,6 @@
 void fld_client_fini(struct lu_client_fld *fld)
 {
 	struct lu_fld_target *target, *tmp;
-	ENTRY;
 
 	spin_lock(&fld->lcf_lock);
 	list_for_each_entry_safe(target, tmp,
@@ -413,8 +406,6 @@
 			fld_cache_fini(fld->lcf_cache);
 		fld->lcf_cache = NULL;
 	}
-
-	EXIT;
 }
 EXPORT_SYMBOL(fld_client_fini);
 
@@ -426,7 +417,6 @@
 	__u32		 *op;
 	int		    rc;
 	struct obd_import     *imp;
-	ENTRY;
 
 	LASSERT(exp != NULL);
 
@@ -434,7 +424,7 @@
 	req = ptlrpc_request_alloc_pack(imp, &RQF_FLD_QUERY, LUSTRE_MDS_VERSION,
 					FLD_QUERY);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	op = req_capsule_client_get(&req->rq_pill, &RMF_FLD_OPC);
 	*op = fld_op;
@@ -464,7 +454,6 @@
 	if (prange == NULL)
 		GOTO(out_req, rc = -EFAULT);
 	*range = *prange;
-	EXIT;
 out_req:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -476,14 +465,13 @@
 	struct lu_seq_range res = { 0 };
 	struct lu_fld_target *target;
 	int rc;
-	ENTRY;
 
 	fld->lcf_flags |= LUSTRE_FLD_RUN;
 
 	rc = fld_cache_lookup(fld->lcf_cache, seq, &res);
 	if (rc == 0) {
 		*mds = res.lsr_index;
-		RETURN(0);
+		return 0;
 	}
 
 	/* Can not find it in the cache */
@@ -496,19 +484,14 @@
 
 	res.lsr_start = seq;
 	fld_range_set_type(&res, flags);
-	if (target->ft_srv != NULL) {
-		LASSERT(env != NULL);
-		rc = fld_server_lookup(env, target->ft_srv, seq, &res);
-	} else {
-		rc = fld_client_rpc(target->ft_exp, &res, FLD_LOOKUP);
-	}
+	rc = fld_client_rpc(target->ft_exp, &res, FLD_LOOKUP);
 
 	if (rc == 0) {
 		*mds = res.lsr_index;
 
 		fld_cache_insert(fld->lcf_cache, &res);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(fld_client_lookup);
 
@@ -517,3 +500,32 @@
 	fld_cache_flush(fld->lcf_cache);
 }
 EXPORT_SYMBOL(fld_client_flush);
+
+static int __init fld_mod_init(void)
+{
+	fld_type_proc_dir = lprocfs_register(LUSTRE_FLD_NAME,
+					     proc_lustre_root,
+					     NULL, NULL);
+	if (IS_ERR(fld_type_proc_dir))
+		return PTR_ERR(fld_type_proc_dir);
+
+	LU_CONTEXT_KEY_INIT(&fld_thread_key);
+	lu_context_key_register(&fld_thread_key);
+	return 0;
+}
+
+static void __exit fld_mod_exit(void)
+{
+	lu_context_key_degister(&fld_thread_key);
+	if (fld_type_proc_dir != NULL && !IS_ERR(fld_type_proc_dir)) {
+		lprocfs_remove(&fld_type_proc_dir);
+		fld_type_proc_dir = NULL;
+	}
+}
+
+MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
+MODULE_DESCRIPTION("Lustre FLD");
+MODULE_LICENSE("GPL");
+
+module_init(fld_mod_init)
+module_exit(fld_mod_exit)
diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c
index c1bd803..052f7d5 100644
--- a/drivers/staging/lustre/lustre/fld/lproc_fld.c
+++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c
@@ -62,7 +62,6 @@
 {
 	struct lu_client_fld *fld = (struct lu_client_fld *)m->private;
 	struct lu_fld_target *target;
-	ENTRY;
 
 	LASSERT(fld != NULL);
 
@@ -72,14 +71,13 @@
 		seq_printf(m, "%s\n", fld_target_name(target));
 	spin_unlock(&fld->lcf_lock);
 
-	RETURN(0);
+	return 0;
 }
 
 static int
 fld_proc_hash_seq_show(struct seq_file *m, void *unused)
 {
 	struct lu_client_fld *fld = (struct lu_client_fld *)m->private;
-	ENTRY;
 
 	LASSERT(fld != NULL);
 
@@ -87,7 +85,7 @@
 	seq_printf(m, "%s\n", fld->lcf_hash->fh_name);
 	spin_unlock(&fld->lcf_lock);
 
-	RETURN(0);
+	return 0;
 }
 
 static ssize_t
@@ -97,7 +95,6 @@
 	struct lu_client_fld *fld = ((struct seq_file *)file->private_data)->private;
 	struct lu_fld_hash *hash = NULL;
 	int i;
-	ENTRY;
 
 	LASSERT(fld != NULL);
 
@@ -120,7 +117,7 @@
 		       fld->lcf_name, hash->fh_name);
 	}
 
-	RETURN(count);
+	return count;
 }
 
 static ssize_t
@@ -128,7 +125,6 @@
 			       size_t count, loff_t *pos)
 {
 	struct lu_client_fld *fld = file->private_data;
-	ENTRY;
 
 	LASSERT(fld != NULL);
 
@@ -136,7 +132,7 @@
 
 	CDEBUG(D_INFO, "%s: Lookup cache is flushed\n", fld->lcf_name);
 
-	RETURN(count);
+	return count;
 }
 
 static int fld_proc_cache_flush_open(struct inode *inode, struct file *file)
@@ -158,202 +154,6 @@
 	.release	= fld_proc_cache_flush_release,
 };
 
-struct fld_seq_param {
-	struct lu_env		fsp_env;
-	struct dt_it		*fsp_it;
-	struct lu_server_fld	*fsp_fld;
-	unsigned int		fsp_stop:1;
-};
-
-static void *fldb_seq_start(struct seq_file *p, loff_t *pos)
-{
-	struct fld_seq_param    *param = p->private;
-	struct lu_server_fld    *fld;
-	struct dt_object	*obj;
-	const struct dt_it_ops  *iops;
-
-	if (param == NULL || param->fsp_stop)
-		return NULL;
-
-	fld = param->fsp_fld;
-	obj = fld->lsf_obj;
-	LASSERT(obj != NULL);
-	iops = &obj->do_index_ops->dio_it;
-
-	iops->load(&param->fsp_env, param->fsp_it, *pos);
-
-	*pos = be64_to_cpu(*(__u64 *)iops->key(&param->fsp_env, param->fsp_it));
-	return param;
-}
-
-static void fldb_seq_stop(struct seq_file *p, void *v)
-{
-	struct fld_seq_param    *param = p->private;
-	const struct dt_it_ops	*iops;
-	struct lu_server_fld	*fld;
-	struct dt_object	*obj;
-
-	if (param == NULL)
-		return;
-
-	fld = param->fsp_fld;
-	obj = fld->lsf_obj;
-	LASSERT(obj != NULL);
-	iops = &obj->do_index_ops->dio_it;
-
-	iops->put(&param->fsp_env, param->fsp_it);
-}
-
-static void *fldb_seq_next(struct seq_file *p, void *v, loff_t *pos)
-{
-	struct fld_seq_param    *param = p->private;
-	struct lu_server_fld	*fld;
-	struct dt_object	*obj;
-	const struct dt_it_ops	*iops;
-	int			rc;
-
-	if (param == NULL || param->fsp_stop)
-		return NULL;
-
-	fld = param->fsp_fld;
-	obj = fld->lsf_obj;
-	LASSERT(obj != NULL);
-	iops = &obj->do_index_ops->dio_it;
-
-	rc = iops->next(&param->fsp_env, param->fsp_it);
-	if (rc > 0) {
-		param->fsp_stop = 1;
-		return NULL;
-	}
-
-	*pos = be64_to_cpu(*(__u64 *)iops->key(&param->fsp_env, param->fsp_it));
-	return param;
-}
-
-static int fldb_seq_show(struct seq_file *p, void *v)
-{
-	struct fld_seq_param    *param = p->private;
-	struct lu_server_fld	*fld;
-	struct dt_object	*obj;
-	const struct dt_it_ops	*iops;
-	struct fld_thread_info	*info;
-	struct lu_seq_range	*fld_rec;
-	int			rc;
-
-	if (param == NULL || param->fsp_stop)
-		return 0;
-
-	fld = param->fsp_fld;
-	obj = fld->lsf_obj;
-	LASSERT(obj != NULL);
-	iops = &obj->do_index_ops->dio_it;
-
-	info = lu_context_key_get(&param->fsp_env.le_ctx,
-				  &fld_thread_key);
-	fld_rec = &info->fti_rec;
-	rc = iops->rec(&param->fsp_env, param->fsp_it,
-		       (struct dt_rec *)fld_rec, 0);
-	if (rc != 0) {
-		CERROR("%s:read record error: rc %d\n",
-		       fld->lsf_name, rc);
-	} else if (fld_rec->lsr_start != 0) {
-		range_be_to_cpu(fld_rec, fld_rec);
-		rc = seq_printf(p, DRANGE"\n", PRANGE(fld_rec));
-	}
-
-	return rc;
-}
-
-struct seq_operations fldb_sops = {
-	.start = fldb_seq_start,
-	.stop = fldb_seq_stop,
-	.next = fldb_seq_next,
-	.show = fldb_seq_show,
-};
-
-static int fldb_seq_open(struct inode *inode, struct file *file)
-{
-	struct seq_file		*seq;
-	struct lu_server_fld    *fld = (struct lu_server_fld *)PDE_DATA(inode);
-	struct dt_object	*obj;
-	const struct dt_it_ops  *iops;
-	struct fld_seq_param    *param = NULL;
-	int			env_init = 0;
-	int			rc;
-
-	rc = seq_open(file, &fldb_sops);
-	if (rc)
-		GOTO(out, rc);
-
-	obj = fld->lsf_obj;
-	if (obj == NULL) {
-		seq = file->private_data;
-		seq->private = NULL;
-		return 0;
-	}
-
-	OBD_ALLOC_PTR(param);
-	if (param == NULL)
-		GOTO(out, rc = -ENOMEM);
-
-	rc = lu_env_init(&param->fsp_env, LCT_MD_THREAD);
-	if (rc != 0)
-		GOTO(out, rc);
-
-	env_init = 1;
-	iops = &obj->do_index_ops->dio_it;
-	param->fsp_it = iops->init(&param->fsp_env, obj, 0, NULL);
-	if (IS_ERR(param->fsp_it))
-		GOTO(out, rc = PTR_ERR(param->fsp_it));
-
-	param->fsp_fld = fld;
-	param->fsp_stop = 0;
-
-	seq = file->private_data;
-	seq->private = param;
-out:
-	if (rc != 0) {
-		if (env_init == 1)
-			lu_env_fini(&param->fsp_env);
-		if (param != NULL)
-			OBD_FREE_PTR(param);
-	}
-	return rc;
-}
-
-static int fldb_seq_release(struct inode *inode, struct file *file)
-{
-	struct seq_file		*seq = file->private_data;
-	struct fld_seq_param	*param;
-	struct lu_server_fld	*fld;
-	struct dt_object	*obj;
-	const struct dt_it_ops	*iops;
-
-	param = seq->private;
-	if (param == NULL) {
-		lprocfs_seq_release(inode, file);
-		return 0;
-	}
-
-	fld = param->fsp_fld;
-	obj = fld->lsf_obj;
-	LASSERT(obj != NULL);
-	iops = &obj->do_index_ops->dio_it;
-
-	LASSERT(iops != NULL);
-	LASSERT(obj != NULL);
-	LASSERT(param->fsp_it != NULL);
-	iops->fini(&param->fsp_env, param->fsp_it);
-	lu_env_fini(&param->fsp_env);
-	OBD_FREE_PTR(param);
-	lprocfs_seq_release(inode, file);
-
-	return 0;
-}
-
-struct lprocfs_vars fld_server_proc_list[] = {
-	{ NULL }};
-
 LPROC_SEQ_FOPS_RO(fld_proc_targets);
 LPROC_SEQ_FOPS(fld_proc_hash);
 
@@ -363,11 +163,4 @@
 	{ "cache_flush", &fld_proc_cache_flush_fops },
 	{ NULL }};
 
-struct file_operations fld_proc_seq_fops = {
-	.owner   = THIS_MODULE,
-	.open    = fldb_seq_open,
-	.read    = seq_read,
-	.release = fldb_seq_release,
-};
-
-#endif
+#endif /* LPROCFS */
diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h
index 4bb6880..edb40af 100644
--- a/drivers/staging/lustre/lustre/include/cl_object.h
+++ b/drivers/staging/lustre/lustre/include/cl_object.h
@@ -758,7 +758,7 @@
 	/**
 	 * Debug information, the task is owning the page.
 	 */
-	task_t	      *cp_task;
+	struct task_struct	*cp_task;
 	/**
 	 * Owning IO request in cl_page_state::CPS_PAGEOUT and
 	 * cl_page_state::CPS_PAGEIN states. This field is maintained only in
@@ -768,11 +768,11 @@
 	/** List of references to this page, for debugging. */
 	struct lu_ref	    cp_reference;
 	/** Link to an object, for debugging. */
-	struct lu_ref_link      *cp_obj_ref;
+	struct lu_ref_link       cp_obj_ref;
 	/** Link to a queue, for debugging. */
-	struct lu_ref_link      *cp_queue_ref;
+	struct lu_ref_link       cp_queue_ref;
 	/** Per-page flags from enum cl_page_flags. Protected by a VM lock. */
-	unsigned		 cp_flags;
+	unsigned                 cp_flags;
 	/** Assigned if doing a sync_io */
 	struct cl_sync_io       *cp_sync_io;
 };
@@ -1576,13 +1576,13 @@
 	 * \see osc_lock_enqueue_wait(), lov_lock_cancel(), lov_sublock_wait().
 	 */
 	struct mutex		cll_guard;
-	task_t	   *cll_guarder;
+	struct task_struct	*cll_guarder;
 	int		   cll_depth;
 
 	/**
 	 * the owner for INTRANSIT state
 	 */
-	task_t	   *cll_intransit_owner;
+	struct task_struct	*cll_intransit_owner;
 	int		   cll_error;
 	/**
 	 * Number of holds on a lock. A hold prevents a lock from being
@@ -1625,7 +1625,7 @@
 	/**
 	 * A reference for cl_lock::cll_descr::cld_obj. For debugging.
 	 */
-	struct lu_ref_link   *cll_obj_ref;
+	struct lu_ref_link    cll_obj_ref;
 #ifdef CONFIG_LOCKDEP
 	/* "dep_map" name is assumed by lockdep.h macros. */
 	struct lockdep_map    dep_map;
@@ -1869,7 +1869,7 @@
 struct cl_page_list {
 	unsigned	     pl_nr;
 	struct list_head	   pl_pages;
-	task_t	  *pl_owner;
+	struct task_struct	*pl_owner;
 };
 
 /**
@@ -2517,7 +2517,7 @@
 	/** object itself */
 	struct cl_object   *ro_obj;
 	/** reference to cl_req_obj::ro_obj. For debugging. */
-	struct lu_ref_link *ro_obj_ref;
+	struct lu_ref_link  ro_obj_ref;
 	/* something else? Number of pages for a given object? */
 };
 
diff --git a/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h b/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h
index 5866922..4bcc4dc 100644
--- a/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/linux/lprocfs_status.h
@@ -48,7 +48,6 @@
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/version.h>
 #include <linux/smp.h>
 #include <linux/rwsem.h>
 #include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
index dff0468..9243dfa 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h
@@ -87,22 +87,6 @@
 
 #define LTIME_S(time)		   (time.tv_sec)
 
-#define ll_permission(inode,mask,nd)    inode_permission(inode,mask)
-
-# define ll_generic_permission(inode, mask, flags, check_acl) \
-	 generic_permission(inode, mask)
-
-#define ll_blkdev_put(a, b) blkdev_put(a, b)
-
-#define ll_dentry_open(a,b,c)	dentry_open(a,b,c)
-
-#define ll_vfs_symlink(dir, dentry, mnt, path, mode) \
-		       vfs_symlink(dir, dentry, path)
-
-
-#define ll_generic_file_llseek_size(file, offset, origin, maxbytes, eof) \
-		generic_file_llseek_size(file, offset, origin, maxbytes, eof);
-
 /* inode_dio_wait(i) use as-is for write lock */
 # define inode_dio_write_done(i)	do {} while (0) /* for write unlock */
 # define inode_dio_read(i)		atomic_inc(&(i)->i_dio_count)
@@ -111,88 +95,10 @@
 #define TREE_READ_LOCK_IRQ(mapping)	spin_lock_irq(&(mapping)->tree_lock)
 #define TREE_READ_UNLOCK_IRQ(mapping)	spin_unlock_irq(&(mapping)->tree_lock)
 
-static inline
-int ll_unregister_blkdev(unsigned int dev, const char *name)
-{
-	unregister_blkdev(dev, name);
-	return 0;
-}
-
-#define ll_invalidate_bdev(a,b)	 invalidate_bdev((a))
-
 #ifndef FS_HAS_FIEMAP
 #define FS_HAS_FIEMAP			(0)
 #endif
 
-
-
-/* add a lustre compatible layer for crypto API */
-#include <linux/crypto.h>
-#define ll_crypto_hash	  crypto_hash
-#define ll_crypto_cipher	crypto_blkcipher
-#define ll_crypto_alloc_hash(name, type, mask)  crypto_alloc_hash(name, type, mask)
-#define ll_crypto_hash_setkey(tfm, key, keylen) crypto_hash_setkey(tfm, key, keylen)
-#define ll_crypto_hash_init(desc)	       crypto_hash_init(desc)
-#define ll_crypto_hash_update(desc, sl, bytes)  crypto_hash_update(desc, sl, bytes)
-#define ll_crypto_hash_final(desc, out)	 crypto_hash_final(desc, out)
-#define ll_crypto_blkcipher_setkey(tfm, key, keylen) \
-		crypto_blkcipher_setkey(tfm, key, keylen)
-#define ll_crypto_blkcipher_set_iv(tfm, src, len) \
-		crypto_blkcipher_set_iv(tfm, src, len)
-#define ll_crypto_blkcipher_get_iv(tfm, dst, len) \
-		crypto_blkcipher_get_iv(tfm, dst, len)
-#define ll_crypto_blkcipher_encrypt(desc, dst, src, bytes) \
-		crypto_blkcipher_encrypt(desc, dst, src, bytes)
-#define ll_crypto_blkcipher_decrypt(desc, dst, src, bytes) \
-		crypto_blkcipher_decrypt(desc, dst, src, bytes)
-#define ll_crypto_blkcipher_encrypt_iv(desc, dst, src, bytes) \
-		crypto_blkcipher_encrypt_iv(desc, dst, src, bytes)
-#define ll_crypto_blkcipher_decrypt_iv(desc, dst, src, bytes) \
-		crypto_blkcipher_decrypt_iv(desc, dst, src, bytes)
-
-static inline
-struct ll_crypto_cipher *ll_crypto_alloc_blkcipher(const char *name,
-						   u32 type, u32 mask)
-{
-	struct ll_crypto_cipher *rtn = crypto_alloc_blkcipher(name, type, mask);
-
-	return (rtn == NULL ? ERR_PTR(-ENOMEM) : rtn);
-}
-
-static inline int ll_crypto_hmac(struct ll_crypto_hash *tfm,
-				 u8 *key, unsigned int *keylen,
-				 struct scatterlist *sg,
-				 unsigned int size, u8 *result)
-{
-	struct hash_desc desc;
-	int	      rv;
-	desc.tfm   = tfm;
-	desc.flags = 0;
-	rv = crypto_hash_setkey(desc.tfm, key, *keylen);
-	if (rv) {
-		CERROR("failed to hash setkey: %d\n", rv);
-		return rv;
-	}
-	return crypto_hash_digest(&desc, sg, size, result);
-}
-static inline
-unsigned int ll_crypto_tfm_alg_max_keysize(struct crypto_blkcipher *tfm)
-{
-	return crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher.max_keysize;
-}
-static inline
-unsigned int ll_crypto_tfm_alg_min_keysize(struct crypto_blkcipher *tfm)
-{
-	return crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher.min_keysize;
-}
-
-#define ll_crypto_hash_blocksize(tfm)       crypto_hash_blocksize(tfm)
-#define ll_crypto_hash_digestsize(tfm)      crypto_hash_digestsize(tfm)
-#define ll_crypto_blkcipher_ivsize(tfm)     crypto_blkcipher_ivsize(tfm)
-#define ll_crypto_blkcipher_blocksize(tfm)  crypto_blkcipher_blocksize(tfm)
-#define ll_crypto_free_hash(tfm)	    crypto_free_hash(tfm)
-#define ll_crypto_free_blkcipher(tfm)       crypto_free_blkcipher(tfm)
-
 #define ll_vfs_rmdir(dir,entry,mnt)	     vfs_rmdir(dir,entry)
 #define ll_vfs_mkdir(inode,dir,mnt,mode)	vfs_mkdir(inode,dir,mode)
 #define ll_vfs_link(old,mnt,dir,new,mnt1)       vfs_link(old,dir,new)
@@ -202,12 +108,6 @@
 #define ll_vfs_rename(old,old_dir,mnt,new,new_dir,mnt1) \
 		vfs_rename(old,old_dir,new,new_dir)
 
-#ifdef for_each_possible_cpu
-#define cfs_for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
-#elif defined(for_each_cpu)
-#define cfs_for_each_possible_cpu(cpu) for_each_cpu(cpu)
-#endif
-
 #define cfs_bio_io_error(a,b)   bio_io_error((a))
 #define cfs_bio_endio(a,b,c)    bio_endio((a),(c))
 
@@ -266,9 +166,6 @@
 #define queue_max_phys_segments(rq)       queue_max_segments(rq)
 #define queue_max_hw_segments(rq)	 queue_max_segments(rq)
 
-#define ll_kmap_atomic(a, b)	kmap_atomic(a)
-#define ll_kunmap_atomic(a, b)	kunmap_atomic(a)
-
 
 #define ll_d_hlist_node hlist_node
 #define ll_d_hlist_empty(list) hlist_empty(list)
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h b/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h
index 6c72609..4da6e372 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_fsfilt.h
@@ -54,7 +54,7 @@
 
 struct fsfilt_operations {
 	struct list_head fs_list;
-	module_t *fs_owner;
+	struct module *fs_owner;
 	char   *fs_type;
 	char   *(* fs_getlabel)(struct super_block *sb);
 	void   *(* fs_start)(struct inode *inode, int op, void *desc_private,
@@ -145,16 +145,6 @@
 	return rc;
 }
 
-static inline int fsfilt_map_inode_pages(struct obd_device *obd,
-					 struct inode *inode,
-					 struct page **page, int pages,
-					 unsigned long *blocks,
-					 int create, struct mutex *mutex)
-{
-	return obd->obd_fsops->fs_map_inode_pages(inode, page, pages, blocks,
-						  create, mutex);
-}
-
 static inline int fsfilt_read_record(struct obd_device *obd, struct file *file,
 				     void *buf, loff_t size, loff_t *offs)
 {
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_handles.h b/drivers/staging/lustre/lustre/include/linux/lustre_handles.h
index ecf1840..459b238 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_handles.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_handles.h
@@ -42,7 +42,6 @@
 #include <asm/types.h>
 #include <asm/atomic.h>
 #include <linux/list.h>
-#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_lib.h b/drivers/staging/lustre/lustre/include/linux/lustre_lib.h
index b2f755a..57f3b01 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_lib.h
@@ -53,15 +53,13 @@
 # include <linux/lustre_common.h>
 
 #ifndef LP_POISON
+# define LI_POISON 0x5a5a5a5a
 #if BITS_PER_LONG > 32
-# define LI_POISON ((int)0x5a5a5a5a5a5a5a5a)
-# define LL_POISON ((long)0x5a5a5a5a5a5a5a5a)
-# define LP_POISON ((void *)(long)0x5a5a5a5a5a5a5a5a)
+# define LL_POISON 0x5a5a5a5a5a5a5a5aL
 #else
-# define LI_POISON ((int)0x5a5a5a5a)
-# define LL_POISON ((long)0x5a5a5a5a)
-# define LP_POISON ((void *)(long)0x5a5a5a5a)
+# define LL_POISON 0x5a5a5a5aL
 #endif
+# define LP_POISON ((void *)LL_POISON)
 #endif
 
 /* This macro is only for compatibility reasons with older Linux Lustre user
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h
index c95dff9..9e5df8d 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_lite.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_lite.h
@@ -40,8 +40,6 @@
 #endif
 
 
-#include <linux/version.h>
-
 #include <asm/statfs.h>
 
 #include <linux/fs.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_net.h b/drivers/staging/lustre/lustre/include/linux/lustre_net.h
index 2d7c425..05de4d8 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_net.h
@@ -39,7 +39,6 @@
 #error Do not #include this file directly. #include <lustre_net.h> instead
 #endif
 
-#include <linux/version.h>
 #include <linux/workqueue.h>
 
 /* XXX Liang: should be moved to other header instead of here */
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h
index a8e9c0c..a260e99 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h
@@ -53,7 +53,7 @@
 		return;
 
 	if (PagePrivate(page))
-		page->mapping->a_ops->invalidatepage(page, 0);
+		page->mapping->a_ops->invalidatepage(page, 0, PAGE_CACHE_SIZE);
 
 	cancel_dirty_page(page, PAGE_SIZE);
 	ClearPageMappedToDisk(page);
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_quota.h b/drivers/staging/lustre/lustre/include/linux/lustre_quota.h
index 421866b..a395050 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_quota.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_quota.h
@@ -39,7 +39,6 @@
 #error Do not #include this file directly. #include <lustre_quota.h> instead
 #endif
 
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <linux/quota.h>
 #include <linux/quotaops.h>
diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_user.h b/drivers/staging/lustre/lustre/include/linux/lustre_user.h
index ebaf929..9cc2849 100644
--- a/drivers/staging/lustre/lustre/include/linux/lustre_user.h
+++ b/drivers/staging/lustre/lustre/include/linux/lustre_user.h
@@ -41,7 +41,6 @@
 #ifndef _LINUX_LUSTRE_USER_H
 #define _LINUX_LUSTRE_USER_H
 
-# include <linux/version.h>
 # include <linux/quota.h>
 
 /*
@@ -53,15 +52,19 @@
 
 #include <linux/string.h>
 
-#if defined(__x86_64__) || defined(__ia64__) || defined(__ppc64__) || \
-    defined(__craynv) || defined (__mips64__) || defined(__powerpc64__)
-typedef struct stat     lstat_t;
-#define lstat_f	 lstat
-#define HAVE_LOV_USER_MDS_DATA
-#else
+/*
+ * We need to always use 64bit version because the structure
+ * is shared across entire cluster where 32bit and 64bit machines
+ * are co-existing.
+ */
+#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64)
 typedef struct stat64   lstat_t;
 #define lstat_f	 lstat64
-#define HAVE_LOV_USER_MDS_DATA
+#else
+typedef struct stat     lstat_t;
+#define lstat_f	 lstat
 #endif
 
+#define HAVE_LOV_USER_MDS_DATA
+
 #endif /* _LUSTRE_USER_H */
diff --git a/drivers/staging/lustre/lustre/include/linux/lvfs.h b/drivers/staging/lustre/lustre/include/linux/lvfs.h
index eb59ac7..e61f1b8 100644
--- a/drivers/staging/lustre/lustre/include/linux/lvfs.h
+++ b/drivers/staging/lustre/lustre/include/linux/lvfs.h
@@ -54,10 +54,10 @@
 /* simple.c */
 
 struct lvfs_ucred {
-	__u32		   luc_uid;
-	__u32		   luc_gid;
-	__u32		   luc_fsuid;
-	__u32		   luc_fsgid;
+	kuid_t		luc_uid;
+	kgid_t		luc_gid;
+	kuid_t		luc_fsuid;
+	kgid_t		luc_fsgid;
 	kernel_cap_t	luc_cap;
 	__u32		   luc_umask;
 	struct group_info      *luc_ginfo;
diff --git a/drivers/staging/lustre/lustre/include/linux/obd.h b/drivers/staging/lustre/lustre/include/linux/obd.h
index 2c36c0d..01a5026 100644
--- a/drivers/staging/lustre/lustre/include/linux/obd.h
+++ b/drivers/staging/lustre/lustre/include/linux/obd.h
@@ -93,11 +93,8 @@
 				      lock, task->comm, task->pid,
 				      lock->func, lock->line,
 				      (jiffies - lock->time) / HZ);
-			LCONSOLE_WARN("====== for process holding the "
-				      "lock =====\n");
-			libcfs_debug_dumpstack(task);
 			LCONSOLE_WARN("====== for current process =====\n");
-			libcfs_debug_dumpstack(NULL);
+			dump_stack();
 			LCONSOLE_WARN("====== end =======\n");
 			cfs_pause(1000 * HZ);
 		}
diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h
index 55f1822..56b0572 100644
--- a/drivers/staging/lustre/lustre/include/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h
@@ -345,7 +345,7 @@
 
 #define EXTRA_FIRST_OPC LDLM_GLIMPSE_ENQUEUE
 /* class_obd.c */
-extern proc_dir_entry_t *proc_lustre_root;
+extern struct proc_dir_entry *proc_lustre_root;
 
 struct obd_device;
 struct obd_histogram;
@@ -370,18 +370,6 @@
 #define JOBSTATS_DISABLE		"disable"
 #define JOBSTATS_PROCNAME_UID		"procname_uid"
 
-typedef void (*cntr_init_callback)(struct lprocfs_stats *stats);
-
-struct obd_job_stats {
-	cfs_hash_t	*ojs_hash;
-	struct list_head	 ojs_list;
-	rwlock_t       ojs_lock; /* protect the obj_list */
-	cntr_init_callback ojs_cntr_init_fn;
-	int		ojs_cntr_num;
-	int		ojs_cleanup_interval;
-	time_t		   ojs_last_cleanup;
-};
-
 #ifdef LPROCFS
 
 extern int lprocfs_stats_alloc_one(struct lprocfs_stats *stats,
@@ -562,11 +550,11 @@
 struct obd_export;
 struct nid_stat;
 extern int lprocfs_add_clear_entry(struct obd_device * obd,
-				   proc_dir_entry_t *entry);
+				   struct proc_dir_entry *entry);
 extern int lprocfs_exp_setup(struct obd_export *exp,
 			     lnet_nid_t *peer_nid, int *newnid);
 extern int lprocfs_exp_cleanup(struct obd_export *exp);
-extern proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
+extern struct proc_dir_entry *lprocfs_add_simple(struct proc_dir_entry *root,
 						char *name,
 						void *data,
 						struct file_operations *fops);
@@ -579,27 +567,27 @@
 			      unsigned long count, void *data);
 extern int lprocfs_nid_stats_clear_read(struct seq_file *m, void *data);
 
-extern int lprocfs_register_stats(proc_dir_entry_t *root, const char *name,
+extern int lprocfs_register_stats(struct proc_dir_entry *root, const char *name,
 				  struct lprocfs_stats *stats);
 
 /* lprocfs_status.c */
-extern int lprocfs_add_vars(proc_dir_entry_t *root,
+extern int lprocfs_add_vars(struct proc_dir_entry *root,
 			    struct lprocfs_vars *var,
 			    void *data);
 
-extern proc_dir_entry_t *lprocfs_register(const char *name,
-					      proc_dir_entry_t *parent,
+extern struct proc_dir_entry *lprocfs_register(const char *name,
+					      struct proc_dir_entry *parent,
 					      struct lprocfs_vars *list,
 					      void *data);
 
-extern void lprocfs_remove(proc_dir_entry_t **root);
+extern void lprocfs_remove(struct proc_dir_entry **root);
 extern void lprocfs_remove_proc_entry(const char *name,
 				      struct proc_dir_entry *parent);
 
 extern int lprocfs_obd_setup(struct obd_device *obd, struct lprocfs_vars *list);
 extern int lprocfs_obd_cleanup(struct obd_device *obd);
 
-extern int lprocfs_seq_create(proc_dir_entry_t *parent, const char *name,
+extern int lprocfs_seq_create(struct proc_dir_entry *parent, const char *name,
 			      umode_t mode,
 			      const struct file_operations *seq_fops,
 			      void *data);
@@ -663,8 +651,8 @@
 extern int lprocfs_write_frac_u64_helper(const char *buffer,
 					 unsigned long count,
 					 __u64 *val, int mult);
-char *lprocfs_find_named_value(const char *buffer, const char *name,
-				unsigned long *count);
+extern char *lprocfs_find_named_value(const char *buffer, const char *name,
+				      size_t *count);
 void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value);
 void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value);
 void lprocfs_oh_clear(struct obd_histogram *oh);
@@ -748,16 +736,6 @@
 		.release = lprocfs_single_release,			\
 	};
 
-/* lprocfs_jobstats.c */
-int lprocfs_job_stats_log(struct obd_device *obd, char *jobid,
-			  int event, long amount);
-void lprocfs_job_stats_fini(struct obd_device *obd);
-int lprocfs_job_stats_init(struct obd_device *obd, int cntr_num,
-			   cntr_init_callback fn);
-int lprocfs_rd_job_interval(struct seq_file *m, void *data);
-int lprocfs_wr_job_interval(struct file *file, const char *buffer,
-			    unsigned long count, void *data);
-
 /* lproc_ptlrpc.c */
 struct ptlrpc_request;
 extern void target_print_req(void *seq_file, struct ptlrpc_request *req);
@@ -826,9 +804,6 @@
 extern int lprocfs_quota_wr_qs_factor(struct file *file,
 				      const char *buffer,
 				      unsigned long count, void *data);
-
-
-
 #else
 /* LPROCFS is not defined */
 
@@ -863,7 +838,7 @@
 { return; }
 static inline void lprocfs_free_stats(struct lprocfs_stats **stats)
 { return; }
-static inline int lprocfs_register_stats(proc_dir_entry_t *root,
+static inline int lprocfs_register_stats(struct proc_dir_entry *root,
 					 const char *name,
 					 struct lprocfs_stats *stats)
 { return 0; }
@@ -894,7 +869,7 @@
 { return 0; }
 static inline int lprocfs_exp_cleanup(struct obd_export *exp)
 { return 0; }
-static inline proc_dir_entry_t *
+static inline struct proc_dir_entry *
 lprocfs_add_simple(struct proc_dir_entry *root, char *name,
 		   void *data, struct file_operations *fops)
 {return 0; }
@@ -912,15 +887,15 @@
 int lprocfs_nid_stats_clear_read(struct seq_file *m, void *data)
 { return 0; }
 
-static inline proc_dir_entry_t *
-lprocfs_register(const char *name, proc_dir_entry_t *parent,
+static inline struct proc_dir_entry *
+lprocfs_register(const char *name, struct proc_dir_entry *parent,
 		 struct lprocfs_vars *list, void *data)
 { return NULL; }
-static inline int lprocfs_add_vars(proc_dir_entry_t *root,
+static inline int lprocfs_add_vars(struct proc_dir_entry *root,
 				   struct lprocfs_vars *var,
 				   void *data)
 { return 0; }
-static inline void lprocfs_remove(proc_dir_entry_t **root)
+static inline void lprocfs_remove(struct proc_dir_entry **root)
 { return; }
 static inline void lprocfs_remove_proc_entry(const char *name,
 					     struct proc_dir_entry *parent)
@@ -1021,20 +996,6 @@
 #define LPROC_SEQ_FOPS_RW_TYPE(name, type)
 #define LPROC_SEQ_FOPS_WR_ONLY(name, type)
 
-/* lprocfs_jobstats.c */
-static inline
-int lprocfs_job_stats_log(struct obd_device *obd, char *jobid, int event,
-			  long amount)
-{ return 0; }
-static inline
-void lprocfs_job_stats_fini(struct obd_device *obd)
-{ return; }
-static inline
-int lprocfs_job_stats_init(struct obd_device *obd, int cntr_num,
-			   cntr_init_callback fn)
-{ return 0; }
-
-
 /* lproc_ptlrpc.c */
 #define target_print_req NULL
 
diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h
index d40ad81..fa31be8 100644
--- a/drivers/staging/lustre/lustre/include/lu_object.h
+++ b/drivers/staging/lustre/lustre/include/lu_object.h
@@ -496,7 +496,7 @@
 	/**
 	 * Link to the device, for debugging.
 	 */
-	struct lu_ref_link		*lo_dev_ref;
+	struct lu_ref_link                 lo_dev_ref;
 };
 
 enum lu_object_header_flags {
@@ -665,6 +665,11 @@
 	return cfs_hash_bd_extra_get(site->ls_obj_hash, &bd);
 }
 
+static inline struct seq_server_site *lu_site2seq(const struct lu_site *s)
+{
+	return s->ld_seq_site;
+}
+
 /** \name ctors
  * Constructors/destructors.
  * @{
@@ -868,11 +873,19 @@
 	return o->lo_header->loh_attr;
 }
 
-static inline struct lu_ref_link *lu_object_ref_add(struct lu_object *o,
-						    const char *scope,
-						    const void *source)
+static inline void lu_object_ref_add(struct lu_object *o,
+				     const char *scope,
+				     const void *source)
 {
-	return lu_ref_add(&o->lo_header->loh_reference, scope, source);
+	lu_ref_add(&o->lo_header->loh_reference, scope, source);
+}
+
+static inline void lu_object_ref_add_at(struct lu_object *o,
+					struct lu_ref_link *link,
+					const char *scope,
+					const void *source)
+{
+	lu_ref_add_at(&o->lo_header->loh_reference, link, scope, source);
 }
 
 static inline void lu_object_ref_del(struct lu_object *o,
@@ -1118,7 +1131,7 @@
 	/**
 	 * Internal implementation detail: module for this key.
 	 */
-	module_t *lct_owner;
+	struct module *lct_owner;
 	/**
 	 * References to this key. For debugging.
 	 */
diff --git a/drivers/staging/lustre/lustre/include/lu_ref.h b/drivers/staging/lustre/lustre/include/lu_ref.h
index 624c19b..50a2a7f7 100644
--- a/drivers/staging/lustre/lustre/include/lu_ref.h
+++ b/drivers/staging/lustre/lustre/include/lu_ref.h
@@ -108,7 +108,12 @@
  */
 
 
-struct lu_ref  {};
+/*
+ * dummy data structures/functions to pass compile for now.
+ * We need to reimplement them with kref.
+ */
+struct lu_ref {};
+struct lu_ref_link {};
 
 static inline void lu_ref_init(struct lu_ref *ref)
 {
@@ -132,6 +137,13 @@
 	return NULL;
 }
 
+static inline void lu_ref_add_at(struct lu_ref *ref,
+				 struct lu_ref_link *link,
+				 const char *scope,
+				 const void *source)
+{
+}
+
 static inline void lu_ref_del(struct lu_ref *ref, const char *scope,
 			      const void *source)
 {
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h b/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h
new file mode 100644
index 0000000..2870487
--- /dev/null
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_errno.h
@@ -0,0 +1,215 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.txt
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (C) 2011 FUJITSU LIMITED.  All rights reserved.
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ */
+
+#ifndef LUSTRE_ERRNO_H
+#define LUSTRE_ERRNO_H
+
+/*
+ * Only "network" errnos, which are defined below, are allowed on wire (or on
+ * disk).  Generic routines exist to help translate between these and a subset
+ * of the "host" errnos.  Some host errnos (e.g., EDEADLOCK) are intentionally
+ * left out.  See also the comment on lustre_errno_hton_mapping[].
+ *
+ * To maintain compatibility with existing x86 clients and servers, each of
+ * these network errnos has the same numerical value as its corresponding host
+ * errno on x86.
+ */
+#define LUSTRE_EPERM		1	/* Operation not permitted */
+#define LUSTRE_ENOENT		2	/* No such file or directory */
+#define LUSTRE_ESRCH		3	/* No such process */
+#define LUSTRE_EINTR		4	/* Interrupted system call */
+#define LUSTRE_EIO		5	/* I/O error */
+#define LUSTRE_ENXIO		6	/* No such device or address */
+#define LUSTRE_E2BIG		7	/* Argument list too long */
+#define LUSTRE_ENOEXEC		8	/* Exec format error */
+#define LUSTRE_EBADF		9	/* Bad file number */
+#define LUSTRE_ECHILD		10	/* No child processes */
+#define LUSTRE_EAGAIN		11	/* Try again */
+#define LUSTRE_ENOMEM		12	/* Out of memory */
+#define LUSTRE_EACCES		13	/* Permission denied */
+#define LUSTRE_EFAULT		14	/* Bad address */
+#define LUSTRE_ENOTBLK		15	/* Block device required */
+#define LUSTRE_EBUSY		16	/* Device or resource busy */
+#define LUSTRE_EEXIST		17	/* File exists */
+#define LUSTRE_EXDEV		18	/* Cross-device link */
+#define LUSTRE_ENODEV		19	/* No such device */
+#define LUSTRE_ENOTDIR		20	/* Not a directory */
+#define LUSTRE_EISDIR		21	/* Is a directory */
+#define LUSTRE_EINVAL		22	/* Invalid argument */
+#define LUSTRE_ENFILE		23	/* File table overflow */
+#define LUSTRE_EMFILE		24	/* Too many open files */
+#define LUSTRE_ENOTTY		25	/* Not a typewriter */
+#define LUSTRE_ETXTBSY		26	/* Text file busy */
+#define LUSTRE_EFBIG		27	/* File too large */
+#define LUSTRE_ENOSPC		28	/* No space left on device */
+#define LUSTRE_ESPIPE		29	/* Illegal seek */
+#define LUSTRE_EROFS		30	/* Read-only file system */
+#define LUSTRE_EMLINK		31	/* Too many links */
+#define LUSTRE_EPIPE		32	/* Broken pipe */
+#define LUSTRE_EDOM		33	/* Math argument out of domain of
+					   func */
+#define LUSTRE_ERANGE		34	/* Math result not representable */
+#define LUSTRE_EDEADLK		35	/* Resource deadlock would occur */
+#define LUSTRE_ENAMETOOLONG	36	/* File name too long */
+#define LUSTRE_ENOLCK		37	/* No record locks available */
+#define LUSTRE_ENOSYS		38	/* Function not implemented */
+#define LUSTRE_ENOTEMPTY	39	/* Directory not empty */
+#define LUSTRE_ELOOP		40	/* Too many symbolic links
+					   encountered */
+#define LUSTRE_ENOMSG		42	/* No message of desired type */
+#define LUSTRE_EIDRM		43	/* Identifier removed */
+#define LUSTRE_ECHRNG		44	/* Channel number out of range */
+#define LUSTRE_EL2NSYNC		45	/* Level 2 not synchronized */
+#define LUSTRE_EL3HLT		46	/* Level 3 halted */
+#define LUSTRE_EL3RST		47	/* Level 3 reset */
+#define LUSTRE_ELNRNG		48	/* Link number out of range */
+#define LUSTRE_EUNATCH		49	/* Protocol driver not attached */
+#define LUSTRE_ENOCSI		50	/* No CSI structure available */
+#define LUSTRE_EL2HLT		51	/* Level 2 halted */
+#define LUSTRE_EBADE		52	/* Invalid exchange */
+#define LUSTRE_EBADR		53	/* Invalid request descriptor */
+#define LUSTRE_EXFULL		54	/* Exchange full */
+#define LUSTRE_ENOANO		55	/* No anode */
+#define LUSTRE_EBADRQC		56	/* Invalid request code */
+#define LUSTRE_EBADSLT		57	/* Invalid slot */
+#define LUSTRE_EBFONT		59	/* Bad font file format */
+#define LUSTRE_ENOSTR		60	/* Device not a stream */
+#define LUSTRE_ENODATA		61	/* No data available */
+#define LUSTRE_ETIME		62	/* Timer expired */
+#define LUSTRE_ENOSR		63	/* Out of streams resources */
+#define LUSTRE_ENONET		64	/* Machine is not on the network */
+#define LUSTRE_ENOPKG		65	/* Package not installed */
+#define LUSTRE_EREMOTE		66	/* Object is remote */
+#define LUSTRE_ENOLINK		67	/* Link has been severed */
+#define LUSTRE_EADV		68	/* Advertise error */
+#define LUSTRE_ESRMNT		69	/* Srmount error */
+#define LUSTRE_ECOMM		70	/* Communication error on send */
+#define LUSTRE_EPROTO		71	/* Protocol error */
+#define LUSTRE_EMULTIHOP	72	/* Multihop attempted */
+#define LUSTRE_EDOTDOT		73	/* RFS specific error */
+#define LUSTRE_EBADMSG		74	/* Not a data message */
+#define LUSTRE_EOVERFLOW	75	/* Value too large for defined data
+					   type */
+#define LUSTRE_ENOTUNIQ		76	/* Name not unique on network */
+#define LUSTRE_EBADFD		77	/* File descriptor in bad state */
+#define LUSTRE_EREMCHG		78	/* Remote address changed */
+#define LUSTRE_ELIBACC		79	/* Can not access a needed shared
+					   library */
+#define LUSTRE_ELIBBAD		80	/* Accessing a corrupted shared
+					   library */
+#define LUSTRE_ELIBSCN		81	/* .lib section in a.out corrupted */
+#define LUSTRE_ELIBMAX		82	/* Attempting to link in too many shared
+					   libraries */
+#define LUSTRE_ELIBEXEC		83	/* Cannot exec a shared library
+					   directly */
+#define LUSTRE_EILSEQ		84	/* Illegal byte sequence */
+#define LUSTRE_ERESTART		85	/* Interrupted system call should be
+					   restarted */
+#define LUSTRE_ESTRPIPE		86	/* Streams pipe error */
+#define LUSTRE_EUSERS		87	/* Too many users */
+#define LUSTRE_ENOTSOCK		88	/* Socket operation on non-socket */
+#define LUSTRE_EDESTADDRREQ	89	/* Destination address required */
+#define LUSTRE_EMSGSIZE		90	/* Message too long */
+#define LUSTRE_EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define LUSTRE_ENOPROTOOPT	92	/* Protocol not available */
+#define LUSTRE_EPROTONOSUPPORT	93	/* Protocol not supported */
+#define LUSTRE_ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define LUSTRE_EOPNOTSUPP	95	/* Operation not supported on transport
+					   endpoint */
+#define LUSTRE_EPFNOSUPPORT	96	/* Protocol family not supported */
+#define LUSTRE_EAFNOSUPPORT	97	/* Address family not supported by
+					   protocol */
+#define LUSTRE_EADDRINUSE	98	/* Address already in use */
+#define LUSTRE_EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define LUSTRE_ENETDOWN		100	/* Network is down */
+#define LUSTRE_ENETUNREACH	101	/* Network is unreachable */
+#define LUSTRE_ENETRESET	102	/* Network dropped connection because of
+					   reset */
+#define LUSTRE_ECONNABORTED	103	/* Software caused connection abort */
+#define LUSTRE_ECONNRESET	104	/* Connection reset by peer */
+#define LUSTRE_ENOBUFS		105	/* No buffer space available */
+#define LUSTRE_EISCONN		106	/* Transport endpoint is already
+					   connected */
+#define LUSTRE_ENOTCONN		107	/* Transport endpoint is not
+					   connected */
+#define LUSTRE_ESHUTDOWN	108	/* Cannot send after transport endpoint
+					   shutdown */
+#define LUSTRE_ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define LUSTRE_ETIMEDOUT	110	/* Connection timed out */
+#define LUSTRE_ECONNREFUSED	111	/* Connection refused */
+#define LUSTRE_EHOSTDOWN	112	/* Host is down */
+#define LUSTRE_EHOSTUNREACH	113	/* No route to host */
+#define LUSTRE_EALREADY		114	/* Operation already in progress */
+#define LUSTRE_EINPROGRESS	115	/* Operation now in progress */
+#define LUSTRE_ESTALE		116	/* Stale NFS file handle */
+#define LUSTRE_EUCLEAN		117	/* Structure needs cleaning */
+#define LUSTRE_ENOTNAM		118	/* Not a XENIX named type file */
+#define LUSTRE_ENAVAIL		119	/* No XENIX semaphores available */
+#define LUSTRE_EISNAM		120	/* Is a named type file */
+#define LUSTRE_EREMOTEIO	121	/* Remote I/O error */
+#define LUSTRE_EDQUOT		122	/* Quota exceeded */
+#define LUSTRE_ENOMEDIUM	123	/* No medium found */
+#define LUSTRE_EMEDIUMTYPE	124	/* Wrong medium type */
+#define LUSTRE_ECANCELED	125	/* Operation Canceled */
+#define LUSTRE_ENOKEY		126	/* Required key not available */
+#define LUSTRE_EKEYEXPIRED	127	/* Key has expired */
+#define LUSTRE_EKEYREVOKED	128	/* Key has been revoked */
+#define LUSTRE_EKEYREJECTED	129	/* Key was rejected by service */
+#define LUSTRE_EOWNERDEAD	130	/* Owner died */
+#define LUSTRE_ENOTRECOVERABLE	131	/* State not recoverable */
+#define LUSTRE_ERESTARTSYS	512
+#define LUSTRE_ERESTARTNOINTR	513
+#define LUSTRE_ERESTARTNOHAND	514	/* restart if no handler.. */
+#define LUSTRE_ENOIOCTLCMD	515	/* No ioctl command */
+#define LUSTRE_ERESTART_RESTARTBLOCK 516 /* restart by calling
+					    sys_restart_syscall */
+#define LUSTRE_EBADHANDLE	521	/* Illegal NFS file handle */
+#define LUSTRE_ENOTSYNC		522	/* Update synchronization mismatch */
+#define LUSTRE_EBADCOOKIE	523	/* Cookie is stale */
+#define LUSTRE_ENOTSUPP		524	/* Operation is not supported */
+#define LUSTRE_ETOOSMALL	525	/* Buffer or request is too small */
+#define LUSTRE_ESERVERFAULT	526	/* An untranslatable error occurred */
+#define LUSTRE_EBADTYPE		527	/* Type not supported by server */
+#define LUSTRE_EJUKEBOX		528	/* Request initiated, but will not
+					   complete before timeout */
+#define LUSTRE_EIOCBQUEUED	529	/* iocb queued, will get completion
+					   event */
+#define LUSTRE_EIOCBRETRY	530	/* iocb queued, will trigger a retry */
+
+/*
+ * Translations are optimized away on x86.  Host errnos that shouldn't be put
+ * on wire could leak through as a result.  Do not count on this side effect.
+ */
+#ifdef CONFIG_LUSTRE_TRANSLATE_ERRNOS
+unsigned int lustre_errno_hton(unsigned int h);
+unsigned int lustre_errno_ntoh(unsigned int n);
+#else
+#define lustre_errno_hton(h) (h)
+#define lustre_errno_ntoh(n) (n)
+#endif
+
+#endif /* LUSTRE_ERRNO_H */
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index 8825460..984235c 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -98,6 +98,8 @@
 /* Defn's shared with user-space. */
 #include <lustre/lustre_user.h>
 
+#include <lustre/lustre_errno.h>
+
 /*
  *  GENERAL STUFF
  */
@@ -911,7 +913,7 @@
 		__diff_normalize(fid_ver(f0), fid_ver(f1));
 }
 
-static inline void ostid_cpu_to_le(struct ost_id *src_oi,
+static inline void ostid_cpu_to_le(const struct ost_id *src_oi,
 				   struct ost_id *dst_oi)
 {
 	if (fid_seq_is_mdt0(ostid_seq(src_oi))) {
@@ -922,7 +924,7 @@
 	}
 }
 
-static inline void ostid_le_to_cpu(struct ost_id *src_oi,
+static inline void ostid_le_to_cpu(const struct ost_id *src_oi,
 				   struct ost_id *dst_oi)
 {
 	if (fid_seq_is_mdt0(ostid_seq(src_oi))) {
@@ -1544,10 +1546,16 @@
 #define LOV_MAGIC_V1_DEF  0x0CD10BD0
 #define LOV_MAGIC_V3_DEF  0x0CD30BD0
 
-#define LOV_PATTERN_RAID0 0x001   /* stripes are used round-robin */
-#define LOV_PATTERN_RAID1 0x002   /* stripes are mirrors of each other */
-#define LOV_PATTERN_FIRST 0x100   /* first stripe is not in round-robin */
-#define LOV_PATTERN_CMOBD 0x200
+#define LOV_PATTERN_RAID0	0x001   /* stripes are used round-robin */
+#define LOV_PATTERN_RAID1	0x002   /* stripes are mirrors of each other */
+#define LOV_PATTERN_FIRST	0x100   /* first stripe is not in round-robin */
+#define LOV_PATTERN_CMOBD	0x200
+
+#define LOV_PATTERN_F_MASK	0xffff0000
+#define LOV_PATTERN_F_RELEASED	0x80000000 /* HSM released file */
+
+#define lov_pattern(pattern)		(pattern & ~LOV_PATTERN_F_MASK)
+#define lov_pattern_flags(pattern)	(pattern & LOV_PATTERN_F_MASK)
 
 #define lov_ost_data lov_ost_data_v1
 struct lov_ost_data_v1 {	  /* per-stripe data structure (little-endian)*/
@@ -1662,6 +1670,17 @@
 	struct lov_ost_data_v1 lmm_objects[0]; /* per-stripe data */
 };
 
+static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic)
+{
+	if (lmm_magic == LOV_MAGIC_V3)
+		return sizeof(struct lov_mds_md_v3) +
+				stripes * sizeof(struct lov_ost_data_v1);
+	else
+		return sizeof(struct lov_mds_md_v1) +
+				stripes * sizeof(struct lov_ost_data_v1);
+}
+
+
 #define OBD_MD_FLID	(0x00000001ULL) /* object ID */
 #define OBD_MD_FLATIME     (0x00000002ULL) /* access time */
 #define OBD_MD_FLMTIME     (0x00000004ULL) /* data modification time */
@@ -2671,6 +2690,10 @@
 	__u64 name[RES_NAME_SIZE];
 };
 
+#define DLDLMRES	"["LPX64":"LPX64":"LPX64"]."LPX64i
+#define PLDLMRES(res)	(res)->lr_name.name[0], (res)->lr_name.name[1], \
+			(res)->lr_name.name[2], (res)->lr_name.name[3]
+
 extern void lustre_swab_ldlm_res_id (struct ldlm_res_id *id);
 
 static inline int ldlm_res_eq(const struct ldlm_res_id *res0,
@@ -2963,6 +2986,7 @@
 	/* LLOG_JOIN_REC	= LLOG_OP_MAGIC | 0x50000, obsolete  1.8.0 */
 	CHANGELOG_REC		= LLOG_OP_MAGIC | 0x60000,
 	CHANGELOG_USER_REC	= LLOG_OP_MAGIC | 0x70000,
+	HSM_AGENT_REC		= LLOG_OP_MAGIC | 0x80000,
 	LLOG_HDR_MAGIC		= LLOG_OP_MAGIC | 0x45539,
 	LLOG_LOGID_MAGIC	= LLOG_OP_MAGIC | 0x4553b,
 } llog_op_type;
@@ -3082,6 +3106,52 @@
 	struct llog_rec_tail  cur_tail;
 } __attribute__((packed));
 
+enum agent_req_status {
+	ARS_WAITING,
+	ARS_STARTED,
+	ARS_FAILED,
+	ARS_CANCELED,
+	ARS_SUCCEED,
+};
+
+static inline char *agent_req_status2name(enum agent_req_status ars)
+{
+	switch (ars) {
+	case ARS_WAITING:
+		return "WAITING";
+	case ARS_STARTED:
+		return "STARTED";
+	case ARS_FAILED:
+		return "FAILED";
+	case ARS_CANCELED:
+		return "CANCELED";
+	case ARS_SUCCEED:
+		return "SUCCEED";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline bool agent_req_in_final_state(enum agent_req_status ars)
+{
+	return ((ars == ARS_SUCCEED) || (ars == ARS_FAILED) ||
+		(ars == ARS_CANCELED));
+}
+
+struct llog_agent_req_rec {
+	struct llog_rec_hdr	arr_hdr;	/**< record header */
+	__u32			arr_status;	/**< status of the request */
+						/* must match enum
+						 * agent_req_status */
+	__u32			arr_archive_id;	/**< backend archive number */
+	__u64			arr_flags;	/**< req flags */
+	__u64			arr_compound_id;	/**< compound cookie */
+	__u64			arr_req_create;	/**< req. creation time */
+	__u64			arr_req_change;	/**< req. status change time */
+	struct hsm_action_item	arr_hai;	/**< req. to the agent */
+	struct llog_rec_tail	arr_tail; /**< record tail for_sizezof_only */
+} __attribute__((packed));
+
 /* Old llog gen for compatibility */
 struct llog_gen {
 	__u64 mnt_cnt;
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
index 7e9f575..c7bd447 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h
@@ -347,6 +347,16 @@
 	struct lov_user_ost_data_v1 lmm_objects[0]; /* per-stripe data */
 } __attribute__((packed));
 
+static inline __u32 lov_user_md_size(__u16 stripes, __u32 lmm_magic)
+{
+	if (lmm_magic == LOV_USER_MAGIC_V3)
+		return sizeof(struct lov_user_md_v3) +
+				stripes * sizeof(struct lov_user_ost_data_v1);
+	else
+		return sizeof(struct lov_user_md_v1) +
+				stripes * sizeof(struct lov_user_ost_data_v1);
+}
+
 /* Compile with -D_LARGEFILE64_SOURCE or -D_GNU_SOURCE (or #define) to
  * use this.  It is unsafe to #define those values in this header as it
  * is possible the application has already #included <sys/stat.h>. */
@@ -462,6 +472,8 @@
 
 /* printf display format
    e.g. printf("file FID is "DFID"\n", PFID(fid)); */
+#define FID_NOBRACE_LEN 40
+#define FID_LEN (FID_NOBRACE_LEN + 2)
 #define DFID_NOBRACE LPX64":0x%x:0x%x"
 #define DFID "["DFID_NOBRACE"]"
 #define PFID(fid)     \
diff --git a/drivers/staging/lustre/lustre/include/lustre_cfg.h b/drivers/staging/lustre/lustre/include/lustre_cfg.h
index f12429f..e14a5f6 100644
--- a/drivers/staging/lustre/lustre/include/lustre_cfg.h
+++ b/drivers/staging/lustre/lustre/include/lustre_cfg.h
@@ -211,13 +211,12 @@
 {
 	int i;
 	int len;
-	ENTRY;
 
 	len = LCFG_HDR_SIZE(bufcount);
 	for (i = 0; i < bufcount; i++)
 		len += cfs_size_round(buflens[i]);
 
-	RETURN(cfs_size_round(len));
+	return cfs_size_round(len);
 }
 
 
@@ -230,12 +229,10 @@
 	char *ptr;
 	int i;
 
-	ENTRY;
-
 	OBD_ALLOC(lcfg, lustre_cfg_len(bufs->lcfg_bufcount,
 				       bufs->lcfg_buflen));
 	if (!lcfg)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	lcfg->lcfg_version = LUSTRE_CFG_VERSION;
 	lcfg->lcfg_command = cmd;
@@ -246,7 +243,7 @@
 		lcfg->lcfg_buflens[i] = bufs->lcfg_buflen[i];
 		LOGL((char *)bufs->lcfg_buf[i], bufs->lcfg_buflen[i], ptr);
 	}
-	RETURN(lcfg);
+	return lcfg;
 }
 
 static inline void lustre_cfg_free(struct lustre_cfg *lcfg)
@@ -256,44 +253,39 @@
 	len = lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens);
 
 	OBD_FREE(lcfg, len);
-	EXIT;
 	return;
 }
 
 static inline int lustre_cfg_sanity_check(void *buf, int len)
 {
 	struct lustre_cfg *lcfg = (struct lustre_cfg *)buf;
-	ENTRY;
+
 	if (!lcfg)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* check that the first bits of the struct are valid */
 	if (len < LCFG_HDR_SIZE(0))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if (lcfg->lcfg_version != LUSTRE_CFG_VERSION)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if (lcfg->lcfg_bufcount >= LUSTRE_CFG_MAX_BUFCOUNT)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* check that the buflens are valid */
 	if (len < LCFG_HDR_SIZE(lcfg->lcfg_bufcount))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* make sure all the pointers point inside the data */
 	if (len < lustre_cfg_len(lcfg->lcfg_bufcount, lcfg->lcfg_buflens))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
-	RETURN(0);
+	return 0;
 }
 
 #include <lustre/lustre_user.h>
 
-#ifndef INVALID_UID
-#define INVALID_UID     (-1)
-#endif
-
 /** @} cfg */
 
 #endif // _LUSTRE_CFG_H
diff --git a/drivers/staging/lustre/lustre/include/lustre_disk.h b/drivers/staging/lustre/lustre/include/lustre_disk.h
index 8db6086..9228b16 100644
--- a/drivers/staging/lustre/lustre/include/lustre_disk.h
+++ b/drivers/staging/lustre/lustre/include/lustre_disk.h
@@ -53,20 +53,21 @@
 
 /****************** on-disk files *********************/
 
-#define MDT_LOGS_DIR      "LOGS"  /* COMPAT_146 */
-#define MOUNT_CONFIGS_DIR "CONFIGS"
-#define CONFIGS_FILE      "mountdata"
+#define MDT_LOGS_DIR		"LOGS"  /* COMPAT_146 */
+#define MOUNT_CONFIGS_DIR	"CONFIGS"
+#define CONFIGS_FILE		"mountdata"
 /** Persistent mount data are stored on the disk in this file. */
-#define MOUNT_DATA_FILE    MOUNT_CONFIGS_DIR"/"CONFIGS_FILE
-#define LAST_RCVD	 "last_rcvd"
-#define LOV_OBJID	 "lov_objid"
+#define MOUNT_DATA_FILE		MOUNT_CONFIGS_DIR"/"CONFIGS_FILE
+#define LAST_RCVD		"last_rcvd"
+#define LOV_OBJID		"lov_objid"
 #define LOV_OBJSEQ		"lov_objseq"
-#define HEALTH_CHECK      "health_check"
-#define CAPA_KEYS	 "capa_keys"
-#define CHANGELOG_USERS   "changelog_users"
-#define MGS_NIDTBL_DIR    "NIDTBL_VERSIONS"
-#define QMT_DIR	   "quota_master"
-#define QSD_DIR	   "quota_slave"
+#define HEALTH_CHECK		"health_check"
+#define CAPA_KEYS		"capa_keys"
+#define CHANGELOG_USERS		"changelog_users"
+#define MGS_NIDTBL_DIR		"NIDTBL_VERSIONS"
+#define QMT_DIR			"quota_master"
+#define QSD_DIR			"quota_slave"
+#define HSM_ACTIONS		"hsm_actions"
 
 /****************** persistent mount data *********************/
 
@@ -226,21 +227,22 @@
 	char	*lmd_osd_type;      /* OSD type */
 };
 
-#define LMD_FLG_SERVER       0x0001  /* Mounting a server */
-#define LMD_FLG_CLIENT       0x0002  /* Mounting a client */
-#define LMD_FLG_ABORT_RECOV  0x0008  /* Abort recovery */
-#define LMD_FLG_NOSVC	0x0010  /* Only start MGS/MGC for servers,
-					no other services */
-#define LMD_FLG_NOMGS	0x0020  /* Only start target for servers, reusing
-					existing MGS services */
-#define LMD_FLG_WRITECONF    0x0040  /* Rewrite config log */
-#define LMD_FLG_NOIR	 0x0080  /* NO imperative recovery */
-#define LMD_FLG_NOSCRUB	     0x0100  /* Do not trigger scrub automatically */
-#define LMD_FLG_MGS	     0x0200  /* Also start MGS along with server */
-#define LMD_FLG_IAM	     0x0400  /* IAM dir */
-#define LMD_FLG_NO_PRIMNODE  0x0800  /* all nodes are service nodes */
-#define LMD_FLG_VIRGIN	     0x1000  /* the service registers first time */
-#define LMD_FLG_UPDATE	     0x2000  /* update parameters */
+#define LMD_FLG_SERVER		0x0001	/* Mounting a server */
+#define LMD_FLG_CLIENT		0x0002	/* Mounting a client */
+#define LMD_FLG_ABORT_RECOV	0x0008	/* Abort recovery */
+#define LMD_FLG_NOSVC		0x0010	/* Only start MGS/MGC for servers,
+					   no other services */
+#define LMD_FLG_NOMGS		0x0020	/* Only start target for servers, reusing
+					   existing MGS services */
+#define LMD_FLG_WRITECONF	0x0040	/* Rewrite config log */
+#define LMD_FLG_NOIR		0x0080	/* NO imperative recovery */
+#define LMD_FLG_NOSCRUB		0x0100	/* Do not trigger scrub automatically */
+#define LMD_FLG_MGS		0x0200	/* Also start MGS along with server */
+#define LMD_FLG_IAM		0x0400	/* IAM dir */
+#define LMD_FLG_NO_PRIMNODE	0x0800	/* all nodes are service nodes */
+#define LMD_FLG_VIRGIN		0x1000	/* the service registers first time */
+#define LMD_FLG_UPDATE		0x2000	/* update parameters */
+#define LMD_FLG_HSM		0x4000	/* Start coordinator */
 
 #define lmd_is_client(x) ((x)->lmd_flags & LMD_FLG_CLIENT)
 
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h
index 317f928..7020d9c 100644
--- a/drivers/staging/lustre/lustre/include/lustre_dlm.h
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h
@@ -57,6 +57,8 @@
 #include <interval_tree.h> /* for interval_node{}, ldlm_extent */
 #include <lu_ref.h>
 
+#include "lustre_dlm_flags.h"
+
 struct obd_ops;
 struct obd_device;
 
@@ -96,161 +98,6 @@
 } ldlm_side_t;
 
 /**
- * Declaration of flags sent through the wire.
- **/
-#define LDLM_FL_LOCK_CHANGED   0x000001 /* extent, mode, or resource changed */
-
-/**
- * If the server returns one of these flags, then the lock was put on that list.
- * If the client sends one of these flags (during recovery ONLY!), it wants the
- * lock added to the specified list, no questions asked.
- */
-#define LDLM_FL_BLOCK_GRANTED  0x000002
-#define LDLM_FL_BLOCK_CONV     0x000004
-#define LDLM_FL_BLOCK_WAIT     0x000008
-
-/* Used to be LDLM_FL_CBPENDING 0x000010 moved to non-wire flags */
-
-#define LDLM_FL_AST_SENT       0x000020 /* blocking or cancel packet was
-					 * queued for sending. */
-/* Used to be LDLM_FL_WAIT_NOREPROC 0x000040   moved to non-wire flags */
-/* Used to be LDLM_FL_CANCEL	0x000080   moved to non-wire flags */
-
-/**
- * Lock is being replayed.  This could probably be implied by the fact that one
- * of BLOCK_{GRANTED,CONV,WAIT} is set, but that is pretty dangerous.
- */
-#define LDLM_FL_REPLAY	 0x000100
-
-#define LDLM_FL_INTENT_ONLY    0x000200 /* Don't grant lock, just do intent. */
-
-/* Used to be LDLM_FL_LOCAL_ONLY 0x000400  moved to non-wire flags */
-/* Used to be LDLM_FL_FAILED     0x000800  moved to non-wire flags */
-
-#define LDLM_FL_HAS_INTENT     0x001000 /* lock request has intent */
-
-/* Used to be LDLM_FL_CANCELING  0x002000  moved to non-wire flags */
-/* Used to be LDLM_FL_LOCAL      0x004000  moved to non-wire flags */
-
-#define LDLM_FL_DISCARD_DATA   0x010000 /* discard (no writeback) on cancel */
-
-#define LDLM_FL_NO_TIMEOUT     0x020000 /* Blocked by group lock - wait
-					 * indefinitely */
-
-/** file & record locking */
-#define LDLM_FL_BLOCK_NOWAIT   0x040000 /* Server told not to wait if blocked.
-					 * For AGL, OST will not send glimpse
-					 * callback. */
-#define LDLM_FL_TEST_LOCK      0x080000 // return blocking lock
-
-/* Used to be LDLM_FL_LVB_READY  0x100000 moved to non-wire flags */
-/* Used to be LDLM_FL_KMS_IGNORE 0x200000 moved to non-wire flags */
-/* Used to be LDLM_FL_NO_LRU     0x400000 moved to non-wire flags */
-
-/* Immediatelly cancel such locks when they block some other locks. Send
- * cancel notification to original lock holder, but expect no reply. This is
- * for clients (like liblustre) that cannot be expected to reliably response
- * to blocking AST. */
-#define LDLM_FL_CANCEL_ON_BLOCK 0x800000
-
-/* Flags flags inherited from parent lock when doing intents. */
-#define LDLM_INHERIT_FLAGS     (LDLM_FL_CANCEL_ON_BLOCK)
-
-/* Used to be LDLM_FL_CP_REQD	0x1000000 moved to non-wire flags */
-/* Used to be LDLM_FL_CLEANED	0x2000000 moved to non-wire flags */
-/* Used to be LDLM_FL_ATOMIC_CB      0x4000000 moved to non-wire flags */
-/* Used to be LDLM_FL_BL_AST	 0x10000000 moved to non-wire flags */
-/* Used to be LDLM_FL_BL_DONE	0x20000000 moved to non-wire flags */
-
-/* measure lock contention and return -EUSERS if locking contention is high */
-#define LDLM_FL_DENY_ON_CONTENTION 0x40000000
-
-/* These are flags that are mapped into the flags and ASTs of blocking locks */
-#define LDLM_AST_DISCARD_DATA  0x80000000 /* Add FL_DISCARD to blocking ASTs */
-
-/* Flags sent in AST lock_flags to be mapped into the receiving lock. */
-#define LDLM_AST_FLAGS	 (LDLM_FL_DISCARD_DATA)
-
-/*
- * --------------------------------------------------------------------------
- * NOTE! Starting from this point, that is, LDLM_FL_* flags with values above
- * 0x80000000 will not be sent over the wire.
- * --------------------------------------------------------------------------
- */
-
-/**
- * Declaration of flags not sent through the wire.
- **/
-
-/**
- * Used for marking lock as a target for -EINTR while cp_ast sleep
- * emulation + race with upcoming bl_ast.
- */
-#define LDLM_FL_FAIL_LOC       0x100000000ULL
-
-/**
- * Used while processing the unused list to know that we have already
- * handled this lock and decided to skip it.
- */
-#define LDLM_FL_SKIPPED	0x200000000ULL
-/* this lock is being destroyed */
-#define LDLM_FL_CBPENDING      0x400000000ULL
-/* not a real flag, not saved in lock */
-#define LDLM_FL_WAIT_NOREPROC  0x800000000ULL
-/* cancellation callback already run */
-#define LDLM_FL_CANCEL	 0x1000000000ULL
-#define LDLM_FL_LOCAL_ONLY     0x2000000000ULL
-/* don't run the cancel callback under ldlm_cli_cancel_unused */
-#define LDLM_FL_FAILED	 0x4000000000ULL
-/* lock cancel has already been sent */
-#define LDLM_FL_CANCELING      0x8000000000ULL
-/* local lock (ie, no srv/cli split) */
-#define LDLM_FL_LOCAL	  0x10000000000ULL
-/* XXX FIXME: This is being added to b_size as a low-risk fix to the fact that
- * the LVB filling happens _after_ the lock has been granted, so another thread
- * can match it before the LVB has been updated.  As a dirty hack, we set
- * LDLM_FL_LVB_READY only after we've done the LVB poop.
- * this is only needed on LOV/OSC now, where LVB is actually used and callers
- * must set it in input flags.
- *
- * The proper fix is to do the granting inside of the completion AST, which can
- * be replaced with a LVB-aware wrapping function for OSC locks.  That change is
- * pretty high-risk, though, and would need a lot more testing. */
-#define LDLM_FL_LVB_READY      0x20000000000ULL
-/* A lock contributes to the known minimum size (KMS) calculation until it has
- * finished the part of its cancelation that performs write back on its dirty
- * pages.  It can remain on the granted list during this whole time.  Threads
- * racing to update the KMS after performing their writeback need to know to
- * exclude each other's locks from the calculation as they walk the granted
- * list. */
-#define LDLM_FL_KMS_IGNORE     0x40000000000ULL
-/* completion AST to be executed */
-#define LDLM_FL_CP_REQD	0x80000000000ULL
-/* cleanup_resource has already handled the lock */
-#define LDLM_FL_CLEANED	0x100000000000ULL
-/* optimization hint: LDLM can run blocking callback from current context
- * w/o involving separate thread. in order to decrease cs rate */
-#define LDLM_FL_ATOMIC_CB      0x200000000000ULL
-
-/* It may happen that a client initiates two operations, e.g. unlink and
- * mkdir, such that the server sends a blocking AST for conflicting
- * locks to this client for the first operation, whereas the second
- * operation has canceled this lock and is waiting for rpc_lock which is
- * taken by the first operation. LDLM_FL_BL_AST is set by
- * ldlm_callback_handler() in the lock to prevent the Early Lock Cancel
- * (ELC) code from cancelling it.
- *
- * LDLM_FL_BL_DONE is to be set by ldlm_cancel_callback() when lock
- * cache is dropped to let ldlm_callback_handler() return EINVAL to the
- * server. It is used when ELC RPC is already prepared and is waiting
- * for rpc_lock, too late to send a separate CANCEL RPC. */
-#define LDLM_FL_BL_AST	  0x400000000000ULL
-#define LDLM_FL_BL_DONE	 0x800000000000ULL
-/* Don't put lock into the LRU list, so that it is not canceled due to aging.
- * Used by MGC locks, they are cancelled only at unmount or by callback. */
-#define LDLM_FL_NO_LRU		0x1000000000000ULL
-
-/**
  * The blocking callback is overloaded to perform two functions.  These flags
  * indicate which operation should be performed.
  */
@@ -388,7 +235,7 @@
  */
 struct ldlm_pool {
 	/** Pool proc directory. */
-	proc_dir_entry_t	*pl_proc_dir;
+	struct proc_dir_entry	*pl_proc_dir;
 	/** Pool name, must be long enough to hold compound proc entry name. */
 	char			pl_name[100];
 	/** Lock for protecting SLV/CLV updates. */
@@ -720,8 +567,6 @@
 					void *data);
 /** Type for glimpse callback function of a lock. */
 typedef int (*ldlm_glimpse_callback)(struct ldlm_lock *lock, void *data);
-/** Type for weight callback function of a lock. */
-typedef unsigned long (*ldlm_weigh_callback)(struct ldlm_lock *lock);
 
 /** Work list for sending GL ASTs to multiple locks. */
 struct ldlm_glimpse_work {
@@ -890,9 +735,6 @@
 	 */
 	ldlm_glimpse_callback	l_glimpse_ast;
 
-	/** XXX apparently unused "weight" handler. To be removed? */
-	ldlm_weigh_callback	l_weigh_ast;
-
 	/**
 	 * Lock export.
 	 * This is a pointer to actual client export for locks that were granted
@@ -919,11 +761,11 @@
 	ldlm_policy_data_t	l_policy_data;
 
 	/**
-	 * Lock state flags.
-	 * Like whenever we receive any blocking requests for this lock, etc.
-	 * Protected by lr_lock.
+	 * Lock state flags. Protected by lr_lock.
+	 * \see lustre_dlm_flags.h where the bits are defined.
 	 */
 	__u64			l_flags;
+
 	/**
 	 * Lock r/w usage counters.
 	 * Protected by lr_lock.
@@ -952,34 +794,6 @@
 	/** Originally requested extent for the extent lock. */
 	struct ldlm_extent	l_req_extent;
 
-	unsigned int		l_failed:1,
-	/**
-	 * Set for locks that were removed from class hash table and will be
-	 * destroyed when last reference to them is released. Set by
-	 * ldlm_lock_destroy_internal().
-	 *
-	 * Protected by lock and resource locks.
-	 */
-				l_destroyed:1,
-	/*
-	 * it's set in lock_res_and_lock() and unset in unlock_res_and_lock().
-	 *
-	 * NB: compared with check_res_locked(), checking this bit is cheaper.
-	 * Also, spin_is_locked() is deprecated for kernel code; one reason is
-	 * because it works only for SMP so user needs to add extra macros like
-	 * LASSERT_SPIN_LOCKED for uniprocessor kernels.
-	 */
-				l_res_locked:1,
-	/*
-	 * It's set once we call ldlm_add_waiting_lock_res_locked()
-	 * to start the lock-timeout timer and it will never be reset.
-	 *
-	 * Protected by lock_res_and_lock().
-	 */
-				l_waited:1,
-	/** Flag whether this is a server namespace lock. */
-				l_ns_srv:1;
-
 	/*
 	 * Client-side-only members.
 	 */
@@ -1230,7 +1044,6 @@
 	void *ei_cb_bl;  /** blocking lock callback */
 	void *ei_cb_cp;  /** lock completion callback */
 	void *ei_cb_gl;  /** lock glimpse callback */
-	void *ei_cb_wg;  /** lock weigh callback */
 	void *ei_cbdata; /** Data to be passed into callbacks. */
 };
 
@@ -1328,7 +1141,6 @@
 	ldlm_completion_callback lcs_completion;
 	ldlm_blocking_callback   lcs_blocking;
 	ldlm_glimpse_callback    lcs_glimpse;
-	ldlm_weigh_callback      lcs_weigh;
 };
 
 /* ldlm_lockd.c */
@@ -1471,8 +1283,6 @@
 			 struct obd_import *imp, int force);
 void ldlm_namespace_register(struct ldlm_namespace *ns, ldlm_side_t client);
 void ldlm_namespace_unregister(struct ldlm_namespace *ns, ldlm_side_t client);
-void ldlm_namespace_move_locked(struct ldlm_namespace *ns, ldlm_side_t client);
-struct ldlm_namespace *ldlm_namespace_first_locked(ldlm_side_t client);
 void ldlm_namespace_get(struct ldlm_namespace *ns);
 void ldlm_namespace_put(struct ldlm_namespace *ns);
 int ldlm_proc_setup(void);
@@ -1645,7 +1455,7 @@
  * There are not used outside of ldlm.
  * @{
  */
-void ldlm_pools_recalc(ldlm_side_t client);
+int ldlm_pools_recalc(ldlm_side_t client);
 int ldlm_pools_init(void);
 void ldlm_pools_fini(void);
 
diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
new file mode 100644
index 0000000..8c34d9d
--- /dev/null
+++ b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h
@@ -0,0 +1,460 @@
+/*  -*- buffer-read-only: t -*- vi: set ro:
+ *
+ * DO NOT EDIT THIS FILE   (lustre_dlm_flags.h)
+ *
+ * It has been AutoGen-ed
+ * From the definitions    lustre_dlm_flags.def
+ * and the template file   lustre_dlm_flags.tpl
+ *
+ * lustre 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * lustre 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, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * \file lustre_dlm_flags.h
+ * The flags and collections of flags (masks) for \see struct ldlm_lock.
+ * This file is derived from flag definitions in lustre_dlm_flags.def.
+ * The format is defined in the lustre_dlm_flags.tpl template file.
+ *
+ * \addtogroup LDLM Lustre Distributed Lock Manager
+ * @{
+ *
+ * \name flags
+ * The flags and collections of flags (masks) for \see struct ldlm_lock.
+ * @{
+ */
+#ifndef LDLM_ALL_FLAGS_MASK
+
+/** l_flags bits marked as "all_flags" bits */
+#define LDLM_FL_ALL_FLAGS_MASK          0x007FFFFFC08F132FULL
+
+/** l_flags bits marked as "ast" bits */
+#define LDLM_FL_AST_MASK                0x0000000080000000ULL
+
+/** l_flags bits marked as "blocked" bits */
+#define LDLM_FL_BLOCKED_MASK            0x000000000000000EULL
+
+/** l_flags bits marked as "gone" bits */
+#define LDLM_FL_GONE_MASK               0x0006004000000000ULL
+
+/** l_flags bits marked as "hide_lock" bits */
+#define LDLM_FL_HIDE_LOCK_MASK          0x0000206400000000ULL
+
+/** l_flags bits marked as "inherit" bits */
+#define LDLM_FL_INHERIT_MASK            0x0000000000800000ULL
+
+/** l_flags bits marked as "local_only" bits */
+#define LDLM_FL_LOCAL_ONLY_MASK         0x007FFFFF00000000ULL
+
+/** l_flags bits marked as "on_wire" bits */
+#define LDLM_FL_ON_WIRE_MASK            0x00000000C08F132FULL
+
+/** extent, mode, or resource changed */
+#define LDLM_FL_LOCK_CHANGED            0x0000000000000001ULL // bit   0
+#define ldlm_is_lock_changed(_l)        LDLM_TEST_FLAG(( _l), 1ULL <<  0)
+#define ldlm_set_lock_changed(_l)       LDLM_SET_FLAG((  _l), 1ULL <<  0)
+#define ldlm_clear_lock_changed(_l)     LDLM_CLEAR_FLAG((_l), 1ULL <<  0)
+
+/**
+ * Server placed lock on granted list, or a recovering client wants the
+ * lock added to the granted list, no questions asked. */
+#define LDLM_FL_BLOCK_GRANTED           0x0000000000000002ULL // bit   1
+#define ldlm_is_block_granted(_l)       LDLM_TEST_FLAG(( _l), 1ULL <<  1)
+#define ldlm_set_block_granted(_l)      LDLM_SET_FLAG((  _l), 1ULL <<  1)
+#define ldlm_clear_block_granted(_l)    LDLM_CLEAR_FLAG((_l), 1ULL <<  1)
+
+/**
+ * Server placed lock on conv list, or a recovering client wants the lock
+ * added to the conv list, no questions asked. */
+#define LDLM_FL_BLOCK_CONV              0x0000000000000004ULL // bit   2
+#define ldlm_is_block_conv(_l)          LDLM_TEST_FLAG(( _l), 1ULL <<  2)
+#define ldlm_set_block_conv(_l)         LDLM_SET_FLAG((  _l), 1ULL <<  2)
+#define ldlm_clear_block_conv(_l)       LDLM_CLEAR_FLAG((_l), 1ULL <<  2)
+
+/**
+ * Server placed lock on wait list, or a recovering client wants the lock
+ * added to the wait list, no questions asked. */
+#define LDLM_FL_BLOCK_WAIT              0x0000000000000008ULL // bit   3
+#define ldlm_is_block_wait(_l)          LDLM_TEST_FLAG(( _l), 1ULL <<  3)
+#define ldlm_set_block_wait(_l)         LDLM_SET_FLAG((  _l), 1ULL <<  3)
+#define ldlm_clear_block_wait(_l)       LDLM_CLEAR_FLAG((_l), 1ULL <<  3)
+
+/** blocking or cancel packet was queued for sending. */
+#define LDLM_FL_AST_SENT                0x0000000000000020ULL // bit   5
+#define ldlm_is_ast_sent(_l)            LDLM_TEST_FLAG(( _l), 1ULL <<  5)
+#define ldlm_set_ast_sent(_l)           LDLM_SET_FLAG((  _l), 1ULL <<  5)
+#define ldlm_clear_ast_sent(_l)         LDLM_CLEAR_FLAG((_l), 1ULL <<  5)
+
+/**
+ * Lock is being replayed.  This could probably be implied by the fact that
+ * one of BLOCK_{GRANTED,CONV,WAIT} is set, but that is pretty dangerous. */
+#define LDLM_FL_REPLAY                  0x0000000000000100ULL // bit   8
+#define ldlm_is_replay(_l)              LDLM_TEST_FLAG(( _l), 1ULL <<  8)
+#define ldlm_set_replay(_l)             LDLM_SET_FLAG((  _l), 1ULL <<  8)
+#define ldlm_clear_replay(_l)           LDLM_CLEAR_FLAG((_l), 1ULL <<  8)
+
+/** Don't grant lock, just do intent. */
+#define LDLM_FL_INTENT_ONLY             0x0000000000000200ULL // bit   9
+#define ldlm_is_intent_only(_l)         LDLM_TEST_FLAG(( _l), 1ULL <<  9)
+#define ldlm_set_intent_only(_l)        LDLM_SET_FLAG((  _l), 1ULL <<  9)
+#define ldlm_clear_intent_only(_l)      LDLM_CLEAR_FLAG((_l), 1ULL <<  9)
+
+/** lock request has intent */
+#define LDLM_FL_HAS_INTENT              0x0000000000001000ULL // bit  12
+#define ldlm_is_has_intent(_l)          LDLM_TEST_FLAG(( _l), 1ULL << 12)
+#define ldlm_set_has_intent(_l)         LDLM_SET_FLAG((  _l), 1ULL << 12)
+#define ldlm_clear_has_intent(_l)       LDLM_CLEAR_FLAG((_l), 1ULL << 12)
+
+/** discard (no writeback) on cancel */
+#define LDLM_FL_DISCARD_DATA            0x0000000000010000ULL // bit  16
+#define ldlm_is_discard_data(_l)        LDLM_TEST_FLAG(( _l), 1ULL << 16)
+#define ldlm_set_discard_data(_l)       LDLM_SET_FLAG((  _l), 1ULL << 16)
+#define ldlm_clear_discard_data(_l)     LDLM_CLEAR_FLAG((_l), 1ULL << 16)
+
+/** Blocked by group lock - wait indefinitely */
+#define LDLM_FL_NO_TIMEOUT              0x0000000000020000ULL // bit  17
+#define ldlm_is_no_timeout(_l)          LDLM_TEST_FLAG(( _l), 1ULL << 17)
+#define ldlm_set_no_timeout(_l)         LDLM_SET_FLAG((  _l), 1ULL << 17)
+#define ldlm_clear_no_timeout(_l)       LDLM_CLEAR_FLAG((_l), 1ULL << 17)
+
+/**
+ * Server told not to wait if blocked. For AGL, OST will not send glimpse
+ * callback. */
+#define LDLM_FL_BLOCK_NOWAIT            0x0000000000040000ULL // bit  18
+#define ldlm_is_block_nowait(_l)        LDLM_TEST_FLAG(( _l), 1ULL << 18)
+#define ldlm_set_block_nowait(_l)       LDLM_SET_FLAG((  _l), 1ULL << 18)
+#define ldlm_clear_block_nowait(_l)     LDLM_CLEAR_FLAG((_l), 1ULL << 18)
+
+/** return blocking lock */
+#define LDLM_FL_TEST_LOCK               0x0000000000080000ULL // bit  19
+#define ldlm_is_test_lock(_l)           LDLM_TEST_FLAG(( _l), 1ULL << 19)
+#define ldlm_set_test_lock(_l)          LDLM_SET_FLAG((  _l), 1ULL << 19)
+#define ldlm_clear_test_lock(_l)        LDLM_CLEAR_FLAG((_l), 1ULL << 19)
+
+/**
+ * Immediatelly cancel such locks when they block some other locks. Send
+ * cancel notification to original lock holder, but expect no reply. This
+ * is for clients (like liblustre) that cannot be expected to reliably
+ * response to blocking AST. */
+#define LDLM_FL_CANCEL_ON_BLOCK         0x0000000000800000ULL // bit  23
+#define ldlm_is_cancel_on_block(_l)     LDLM_TEST_FLAG(( _l), 1ULL << 23)
+#define ldlm_set_cancel_on_block(_l)    LDLM_SET_FLAG((  _l), 1ULL << 23)
+#define ldlm_clear_cancel_on_block(_l)  LDLM_CLEAR_FLAG((_l), 1ULL << 23)
+
+/**
+ * measure lock contention and return -EUSERS if locking contention is high */
+#define LDLM_FL_DENY_ON_CONTENTION        0x0000000040000000ULL // bit  30
+#define ldlm_is_deny_on_contention(_l)    LDLM_TEST_FLAG(( _l), 1ULL << 30)
+#define ldlm_set_deny_on_contention(_l)   LDLM_SET_FLAG((  _l), 1ULL << 30)
+#define ldlm_clear_deny_on_contention(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 30)
+
+/**
+ * These are flags that are mapped into the flags and ASTs of blocking
+ * locks Add FL_DISCARD to blocking ASTs */
+#define LDLM_FL_AST_DISCARD_DATA        0x0000000080000000ULL // bit  31
+#define ldlm_is_ast_discard_data(_l)    LDLM_TEST_FLAG(( _l), 1ULL << 31)
+#define ldlm_set_ast_discard_data(_l)   LDLM_SET_FLAG((  _l), 1ULL << 31)
+#define ldlm_clear_ast_discard_data(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 31)
+
+/**
+ * Used for marking lock as a target for -EINTR while cp_ast sleep emulation
+ * + race with upcoming bl_ast. */
+#define LDLM_FL_FAIL_LOC                0x0000000100000000ULL // bit  32
+#define ldlm_is_fail_loc(_l)            LDLM_TEST_FLAG(( _l), 1ULL << 32)
+#define ldlm_set_fail_loc(_l)           LDLM_SET_FLAG((  _l), 1ULL << 32)
+#define ldlm_clear_fail_loc(_l)         LDLM_CLEAR_FLAG((_l), 1ULL << 32)
+
+/**
+ * Used while processing the unused list to know that we have already
+ * handled this lock and decided to skip it. */
+#define LDLM_FL_SKIPPED                 0x0000000200000000ULL // bit  33
+#define ldlm_is_skipped(_l)             LDLM_TEST_FLAG(( _l), 1ULL << 33)
+#define ldlm_set_skipped(_l)            LDLM_SET_FLAG((  _l), 1ULL << 33)
+#define ldlm_clear_skipped(_l)          LDLM_CLEAR_FLAG((_l), 1ULL << 33)
+
+/** this lock is being destroyed */
+#define LDLM_FL_CBPENDING               0x0000000400000000ULL // bit  34
+#define ldlm_is_cbpending(_l)           LDLM_TEST_FLAG(( _l), 1ULL << 34)
+#define ldlm_set_cbpending(_l)          LDLM_SET_FLAG((  _l), 1ULL << 34)
+#define ldlm_clear_cbpending(_l)        LDLM_CLEAR_FLAG((_l), 1ULL << 34)
+
+/** not a real flag, not saved in lock */
+#define LDLM_FL_WAIT_NOREPROC           0x0000000800000000ULL // bit  35
+#define ldlm_is_wait_noreproc(_l)       LDLM_TEST_FLAG(( _l), 1ULL << 35)
+#define ldlm_set_wait_noreproc(_l)      LDLM_SET_FLAG((  _l), 1ULL << 35)
+#define ldlm_clear_wait_noreproc(_l)    LDLM_CLEAR_FLAG((_l), 1ULL << 35)
+
+/** cancellation callback already run */
+#define LDLM_FL_CANCEL                  0x0000001000000000ULL // bit  36
+#define ldlm_is_cancel(_l)              LDLM_TEST_FLAG(( _l), 1ULL << 36)
+#define ldlm_set_cancel(_l)             LDLM_SET_FLAG((  _l), 1ULL << 36)
+#define ldlm_clear_cancel(_l)           LDLM_CLEAR_FLAG((_l), 1ULL << 36)
+
+/** whatever it might mean */
+#define LDLM_FL_LOCAL_ONLY              0x0000002000000000ULL // bit  37
+#define ldlm_is_local_only(_l)          LDLM_TEST_FLAG(( _l), 1ULL << 37)
+#define ldlm_set_local_only(_l)         LDLM_SET_FLAG((  _l), 1ULL << 37)
+#define ldlm_clear_local_only(_l)       LDLM_CLEAR_FLAG((_l), 1ULL << 37)
+
+/** don't run the cancel callback under ldlm_cli_cancel_unused */
+#define LDLM_FL_FAILED                  0x0000004000000000ULL // bit  38
+#define ldlm_is_failed(_l)              LDLM_TEST_FLAG(( _l), 1ULL << 38)
+#define ldlm_set_failed(_l)             LDLM_SET_FLAG((  _l), 1ULL << 38)
+#define ldlm_clear_failed(_l)           LDLM_CLEAR_FLAG((_l), 1ULL << 38)
+
+/** lock cancel has already been sent */
+#define LDLM_FL_CANCELING               0x0000008000000000ULL // bit  39
+#define ldlm_is_canceling(_l)           LDLM_TEST_FLAG(( _l), 1ULL << 39)
+#define ldlm_set_canceling(_l)          LDLM_SET_FLAG((  _l), 1ULL << 39)
+#define ldlm_clear_canceling(_l)        LDLM_CLEAR_FLAG((_l), 1ULL << 39)
+
+/** local lock (ie, no srv/cli split) */
+#define LDLM_FL_LOCAL                   0x0000010000000000ULL // bit  40
+#define ldlm_is_local(_l)               LDLM_TEST_FLAG(( _l), 1ULL << 40)
+#define ldlm_set_local(_l)              LDLM_SET_FLAG((  _l), 1ULL << 40)
+#define ldlm_clear_local(_l)            LDLM_CLEAR_FLAG((_l), 1ULL << 40)
+
+/**
+ * XXX FIXME: This is being added to b_size as a low-risk fix to the
+ * fact that the LVB filling happens _after_ the lock has been granted,
+ * so another thread can match it before the LVB has been updated.  As a
+ * dirty hack, we set LDLM_FL_LVB_READY only after we've done the LVB poop.
+ * this is only needed on LOV/OSC now, where LVB is actually used and
+ * callers must set it in input flags.
+ *
+ * The proper fix is to do the granting inside of the completion AST,
+ * which can be replaced with a LVB-aware wrapping function for OSC locks.
+ * That change is pretty high-risk, though, and would need a lot more
+ * testing. */
+#define LDLM_FL_LVB_READY               0x0000020000000000ULL // bit  41
+#define ldlm_is_lvb_ready(_l)           LDLM_TEST_FLAG(( _l), 1ULL << 41)
+#define ldlm_set_lvb_ready(_l)          LDLM_SET_FLAG((  _l), 1ULL << 41)
+#define ldlm_clear_lvb_ready(_l)        LDLM_CLEAR_FLAG((_l), 1ULL << 41)
+
+/**
+ * A lock contributes to the known minimum size (KMS) calculation until it
+ * has finished the part of its cancelation that performs write back on its
+ * dirty pages.  It can remain on the granted list during this whole time.
+ * Threads racing to update the KMS after performing their writeback need
+ * to know to exclude each other's locks from the calculation as they walk
+ * the granted list. */
+#define LDLM_FL_KMS_IGNORE              0x0000040000000000ULL // bit  42
+#define ldlm_is_kms_ignore(_l)          LDLM_TEST_FLAG(( _l), 1ULL << 42)
+#define ldlm_set_kms_ignore(_l)         LDLM_SET_FLAG((  _l), 1ULL << 42)
+#define ldlm_clear_kms_ignore(_l)       LDLM_CLEAR_FLAG((_l), 1ULL << 42)
+
+/** completion AST to be executed */
+#define LDLM_FL_CP_REQD                 0x0000080000000000ULL // bit  43
+#define ldlm_is_cp_reqd(_l)             LDLM_TEST_FLAG(( _l), 1ULL << 43)
+#define ldlm_set_cp_reqd(_l)            LDLM_SET_FLAG((  _l), 1ULL << 43)
+#define ldlm_clear_cp_reqd(_l)          LDLM_CLEAR_FLAG((_l), 1ULL << 43)
+
+/** cleanup_resource has already handled the lock */
+#define LDLM_FL_CLEANED                 0x0000100000000000ULL // bit  44
+#define ldlm_is_cleaned(_l)             LDLM_TEST_FLAG(( _l), 1ULL << 44)
+#define ldlm_set_cleaned(_l)            LDLM_SET_FLAG((  _l), 1ULL << 44)
+#define ldlm_clear_cleaned(_l)          LDLM_CLEAR_FLAG((_l), 1ULL << 44)
+
+/**
+ * optimization hint: LDLM can run blocking callback from current context
+ * w/o involving separate thread. in order to decrease cs rate */
+#define LDLM_FL_ATOMIC_CB               0x0000200000000000ULL // bit  45
+#define ldlm_is_atomic_cb(_l)           LDLM_TEST_FLAG(( _l), 1ULL << 45)
+#define ldlm_set_atomic_cb(_l)          LDLM_SET_FLAG((  _l), 1ULL << 45)
+#define ldlm_clear_atomic_cb(_l)        LDLM_CLEAR_FLAG((_l), 1ULL << 45)
+
+/**
+ * It may happen that a client initiates two operations, e.g. unlink and
+ * mkdir, such that the server sends a blocking AST for conflicting locks
+ * to this client for the first operation, whereas the second operation
+ * has canceled this lock and is waiting for rpc_lock which is taken by
+ * the first operation. LDLM_FL_BL_AST is set by ldlm_callback_handler() in
+ * the lock to prevent the Early Lock Cancel (ELC) code from cancelling it.
+ *
+ * LDLM_FL_BL_DONE is to be set by ldlm_cancel_callback() when lock cache is
+ * dropped to let ldlm_callback_handler() return EINVAL to the server. It
+ * is used when ELC RPC is already prepared and is waiting for rpc_lock,
+ * too late to send a separate CANCEL RPC. */
+#define LDLM_FL_BL_AST                  0x0000400000000000ULL // bit  46
+#define ldlm_is_bl_ast(_l)              LDLM_TEST_FLAG(( _l), 1ULL << 46)
+#define ldlm_set_bl_ast(_l)             LDLM_SET_FLAG((  _l), 1ULL << 46)
+#define ldlm_clear_bl_ast(_l)           LDLM_CLEAR_FLAG((_l), 1ULL << 46)
+
+/** whatever it might mean */
+#define LDLM_FL_BL_DONE                 0x0000800000000000ULL // bit  47
+#define ldlm_is_bl_done(_l)             LDLM_TEST_FLAG(( _l), 1ULL << 47)
+#define ldlm_set_bl_done(_l)            LDLM_SET_FLAG((  _l), 1ULL << 47)
+#define ldlm_clear_bl_done(_l)          LDLM_CLEAR_FLAG((_l), 1ULL << 47)
+
+/**
+ * Don't put lock into the LRU list, so that it is not canceled due
+ * to aging.  Used by MGC locks, they are cancelled only at unmount or
+ * by callback. */
+#define LDLM_FL_NO_LRU                  0x0001000000000000ULL // bit  48
+#define ldlm_is_no_lru(_l)              LDLM_TEST_FLAG(( _l), 1ULL << 48)
+#define ldlm_set_no_lru(_l)             LDLM_SET_FLAG((  _l), 1ULL << 48)
+#define ldlm_clear_no_lru(_l)           LDLM_CLEAR_FLAG((_l), 1ULL << 48)
+
+/**
+ * Set for locks that failed and where the server has been notified.
+ *
+ * Protected by lock and resource locks. */
+#define LDLM_FL_FAIL_NOTIFIED           0x0002000000000000ULL // bit  49
+#define ldlm_is_fail_notified(_l)       LDLM_TEST_FLAG(( _l), 1ULL << 49)
+#define ldlm_set_fail_notified(_l)      LDLM_SET_FLAG((  _l), 1ULL << 49)
+#define ldlm_clear_fail_notified(_l)    LDLM_CLEAR_FLAG((_l), 1ULL << 49)
+
+/**
+ * Set for locks that were removed from class hash table and will
+ * be destroyed when last reference to them is released. Set by
+ * ldlm_lock_destroy_internal().
+ *
+ * Protected by lock and resource locks. */
+#define LDLM_FL_DESTROYED               0x0004000000000000ULL // bit  50
+#define ldlm_is_destroyed(_l)           LDLM_TEST_FLAG(( _l), 1ULL << 50)
+#define ldlm_set_destroyed(_l)          LDLM_SET_FLAG((  _l), 1ULL << 50)
+#define ldlm_clear_destroyed(_l)        LDLM_CLEAR_FLAG((_l), 1ULL << 50)
+
+/** flag whether this is a server namespace lock */
+#define LDLM_FL_SERVER_LOCK             0x0008000000000000ULL // bit  51
+#define ldlm_is_server_lock(_l)         LDLM_TEST_FLAG(( _l), 1ULL << 51)
+#define ldlm_set_server_lock(_l)        LDLM_SET_FLAG((  _l), 1ULL << 51)
+#define ldlm_clear_server_lock(_l)      LDLM_CLEAR_FLAG((_l), 1ULL << 51)
+
+/**
+ * It's set in lock_res_and_lock() and unset in unlock_res_and_lock().
+ *
+ * NB: compared with check_res_locked(), checking this bit is cheaper.
+ * Also, spin_is_locked() is deprecated for kernel code; one reason is
+ * because it works only for SMP so user needs to add extra macros like
+ * LASSERT_SPIN_LOCKED for uniprocessor kernels. */
+#define LDLM_FL_RES_LOCKED              0x0010000000000000ULL // bit  52
+#define ldlm_is_res_locked(_l)          LDLM_TEST_FLAG(( _l), 1ULL << 52)
+#define ldlm_set_res_locked(_l)         LDLM_SET_FLAG((  _l), 1ULL << 52)
+#define ldlm_clear_res_locked(_l)       LDLM_CLEAR_FLAG((_l), 1ULL << 52)
+
+/**
+ * It's set once we call ldlm_add_waiting_lock_res_locked() to start the
+ * lock-timeout timer and it will never be reset.
+ *
+ * Protected by lock and resource locks. */
+#define LDLM_FL_WAITED                  0x0020000000000000ULL // bit  53
+#define ldlm_is_waited(_l)              LDLM_TEST_FLAG(( _l), 1ULL << 53)
+#define ldlm_set_waited(_l)             LDLM_SET_FLAG((  _l), 1ULL << 53)
+#define ldlm_clear_waited(_l)           LDLM_CLEAR_FLAG((_l), 1ULL << 53)
+
+/** Flag whether this is a server namespace lock. */
+#define LDLM_FL_NS_SRV                  0x0040000000000000ULL // bit  54
+#define ldlm_is_ns_srv(_l)              LDLM_TEST_FLAG(( _l), 1ULL << 54)
+#define ldlm_set_ns_srv(_l)             LDLM_SET_FLAG((  _l), 1ULL << 54)
+#define ldlm_clear_ns_srv(_l)           LDLM_CLEAR_FLAG((_l), 1ULL << 54)
+
+/** test for ldlm_lock flag bit set */
+#define LDLM_TEST_FLAG(_l, _b)        (((_l)->l_flags & (_b)) != 0)
+
+/** set a ldlm_lock flag bit */
+#define LDLM_SET_FLAG(_l, _b)         (((_l)->l_flags |= (_b))
+
+/** clear a ldlm_lock flag bit */
+#define LDLM_CLEAR_FLAG(_l, _b)       (((_l)->l_flags &= ~(_b))
+
+/** Mask of flags inherited from parent lock when doing intents. */
+#define LDLM_INHERIT_FLAGS            LDLM_FL_INHERIT_MASK
+
+/** Mask of Flags sent in AST lock_flags to map into the receiving lock. */
+#define LDLM_AST_FLAGS                LDLM_FL_AST_MASK
+
+/** @} subgroup */
+/** @} group */
+#ifdef WIRESHARK_COMPILE
+static int hf_lustre_ldlm_fl_lock_changed        = -1;
+static int hf_lustre_ldlm_fl_block_granted       = -1;
+static int hf_lustre_ldlm_fl_block_conv          = -1;
+static int hf_lustre_ldlm_fl_block_wait          = -1;
+static int hf_lustre_ldlm_fl_ast_sent            = -1;
+static int hf_lustre_ldlm_fl_replay              = -1;
+static int hf_lustre_ldlm_fl_intent_only         = -1;
+static int hf_lustre_ldlm_fl_has_intent          = -1;
+static int hf_lustre_ldlm_fl_discard_data        = -1;
+static int hf_lustre_ldlm_fl_no_timeout          = -1;
+static int hf_lustre_ldlm_fl_block_nowait        = -1;
+static int hf_lustre_ldlm_fl_test_lock           = -1;
+static int hf_lustre_ldlm_fl_cancel_on_block     = -1;
+static int hf_lustre_ldlm_fl_deny_on_contention  = -1;
+static int hf_lustre_ldlm_fl_ast_discard_data    = -1;
+static int hf_lustre_ldlm_fl_fail_loc            = -1;
+static int hf_lustre_ldlm_fl_skipped             = -1;
+static int hf_lustre_ldlm_fl_cbpending           = -1;
+static int hf_lustre_ldlm_fl_wait_noreproc       = -1;
+static int hf_lustre_ldlm_fl_cancel              = -1;
+static int hf_lustre_ldlm_fl_local_only          = -1;
+static int hf_lustre_ldlm_fl_failed              = -1;
+static int hf_lustre_ldlm_fl_canceling           = -1;
+static int hf_lustre_ldlm_fl_local               = -1;
+static int hf_lustre_ldlm_fl_lvb_ready           = -1;
+static int hf_lustre_ldlm_fl_kms_ignore          = -1;
+static int hf_lustre_ldlm_fl_cp_reqd             = -1;
+static int hf_lustre_ldlm_fl_cleaned             = -1;
+static int hf_lustre_ldlm_fl_atomic_cb           = -1;
+static int hf_lustre_ldlm_fl_bl_ast              = -1;
+static int hf_lustre_ldlm_fl_bl_done             = -1;
+static int hf_lustre_ldlm_fl_no_lru              = -1;
+static int hf_lustre_ldlm_fl_fail_notified       = -1;
+static int hf_lustre_ldlm_fl_destroyed           = -1;
+static int hf_lustre_ldlm_fl_server_lock         = -1;
+static int hf_lustre_ldlm_fl_res_locked          = -1;
+static int hf_lustre_ldlm_fl_waited              = -1;
+static int hf_lustre_ldlm_fl_ns_srv              = -1;
+
+const value_string lustre_ldlm_flags_vals[] = {
+  {LDLM_FL_LOCK_CHANGED,        "LDLM_FL_LOCK_CHANGED"},
+  {LDLM_FL_BLOCK_GRANTED,       "LDLM_FL_BLOCK_GRANTED"},
+  {LDLM_FL_BLOCK_CONV,          "LDLM_FL_BLOCK_CONV"},
+  {LDLM_FL_BLOCK_WAIT,          "LDLM_FL_BLOCK_WAIT"},
+  {LDLM_FL_AST_SENT,            "LDLM_FL_AST_SENT"},
+  {LDLM_FL_REPLAY,              "LDLM_FL_REPLAY"},
+  {LDLM_FL_INTENT_ONLY,         "LDLM_FL_INTENT_ONLY"},
+  {LDLM_FL_HAS_INTENT,          "LDLM_FL_HAS_INTENT"},
+  {LDLM_FL_DISCARD_DATA,        "LDLM_FL_DISCARD_DATA"},
+  {LDLM_FL_NO_TIMEOUT,          "LDLM_FL_NO_TIMEOUT"},
+  {LDLM_FL_BLOCK_NOWAIT,        "LDLM_FL_BLOCK_NOWAIT"},
+  {LDLM_FL_TEST_LOCK,           "LDLM_FL_TEST_LOCK"},
+  {LDLM_FL_CANCEL_ON_BLOCK,     "LDLM_FL_CANCEL_ON_BLOCK"},
+  {LDLM_FL_DENY_ON_CONTENTION,  "LDLM_FL_DENY_ON_CONTENTION"},
+  {LDLM_FL_AST_DISCARD_DATA,    "LDLM_FL_AST_DISCARD_DATA"},
+  {LDLM_FL_FAIL_LOC,            "LDLM_FL_FAIL_LOC"},
+  {LDLM_FL_SKIPPED,             "LDLM_FL_SKIPPED"},
+  {LDLM_FL_CBPENDING,           "LDLM_FL_CBPENDING"},
+  {LDLM_FL_WAIT_NOREPROC,       "LDLM_FL_WAIT_NOREPROC"},
+  {LDLM_FL_CANCEL,              "LDLM_FL_CANCEL"},
+  {LDLM_FL_LOCAL_ONLY,          "LDLM_FL_LOCAL_ONLY"},
+  {LDLM_FL_FAILED,              "LDLM_FL_FAILED"},
+  {LDLM_FL_CANCELING,           "LDLM_FL_CANCELING"},
+  {LDLM_FL_LOCAL,               "LDLM_FL_LOCAL"},
+  {LDLM_FL_LVB_READY,           "LDLM_FL_LVB_READY"},
+  {LDLM_FL_KMS_IGNORE,          "LDLM_FL_KMS_IGNORE"},
+  {LDLM_FL_CP_REQD,             "LDLM_FL_CP_REQD"},
+  {LDLM_FL_CLEANED,             "LDLM_FL_CLEANED"},
+  {LDLM_FL_ATOMIC_CB,           "LDLM_FL_ATOMIC_CB"},
+  {LDLM_FL_BL_AST,              "LDLM_FL_BL_AST"},
+  {LDLM_FL_BL_DONE,             "LDLM_FL_BL_DONE"},
+  {LDLM_FL_NO_LRU,              "LDLM_FL_NO_LRU"},
+  {LDLM_FL_FAIL_NOTIFIED,       "LDLM_FL_FAIL_NOTIFIED"},
+  {LDLM_FL_DESTROYED,           "LDLM_FL_DESTROYED"},
+  {LDLM_FL_SERVER_LOCK,         "LDLM_FL_SERVER_LOCK"},
+  {LDLM_FL_RES_LOCKED,          "LDLM_FL_RES_LOCKED"},
+  {LDLM_FL_WAITED,              "LDLM_FL_WAITED"},
+  {LDLM_FL_NS_SRV,              "LDLM_FL_NS_SRV"},
+  { 0, NULL }
+};
+#endif /*  WIRESHARK_COMPILE */
+#endif /* LDLM_ALL_FLAGS_MASK */
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index 7d20cba..d9d5814 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -38,8 +38,8 @@
  * Author: Yury Umanets <umka@clusterfs.com>
  */
 
-#ifndef __LINUX_FID_H
-#define __LINUX_FID_H
+#ifndef __LUSTRE_FID_H
+#define __LUSTRE_FID_H
 
 /** \defgroup fid fid
  *
@@ -154,13 +154,12 @@
 
 #include <linux/libcfs/libcfs.h>
 #include <lustre/lustre_idl.h>
-#include <lustre_req_layout.h>
-#include <lustre_mdt.h>
-#include <obd.h>
 
-
+struct lu_env;
 struct lu_site;
 struct lu_context;
+struct obd_device;
+struct obd_export;
 
 /* Whole sequences space range and zero range definitions */
 extern const struct lu_seq_range LUSTRE_SEQ_SPACE_RANGE;
@@ -320,6 +319,12 @@
 	fid->f_ver = 0;
 }
 
+/* seq client type */
+enum lu_cli_type {
+	LUSTRE_SEQ_METADATA = 1,
+	LUSTRE_SEQ_DATA
+};
+
 enum lu_mgr_type {
 	LUSTRE_SEQ_SERVER,
 	LUSTRE_SEQ_CONTROLLER
@@ -341,7 +346,7 @@
 	struct lu_seq_range	 lcs_space;
 
 	/* Seq related proc */
-	proc_dir_entry_t   *lcs_proc_dir;
+	struct proc_dir_entry   *lcs_proc_dir;
 
 	/* This holds last allocated fid in last obtained seq */
 	struct lu_fid	   lcs_fid;
@@ -388,7 +393,7 @@
 	struct dt_object       *lss_obj;
 
 	/* Seq related proc */
-	proc_dir_entry_t   *lss_proc_dir;
+	struct proc_dir_entry   *lss_proc_dir;
 
 	/* LUSTRE_SEQ_SERVER or LUSTRE_SEQ_CONTROLLER */
 	enum lu_mgr_type       lss_type;
@@ -426,10 +431,14 @@
 	struct seq_server_site  *lss_site;
 };
 
+struct com_thread_info;
 int seq_query(struct com_thread_info *info);
+
+struct ptlrpc_request;
 int seq_handle(struct ptlrpc_request *req);
 
 /* Server methods */
+
 int seq_server_init(struct lu_server_seq *seq,
 		    struct dt_device *dev,
 		    const char *prefix,
@@ -472,6 +481,7 @@
 int fid_is_local(const struct lu_env *env,
 		 struct lu_site *site, const struct lu_fid *fid);
 
+enum lu_cli_type;
 int client_fid_init(struct obd_device *obd, struct obd_export *exp,
 		    enum lu_cli_type type);
 int client_fid_fini(struct obd_device *obd);
@@ -488,74 +498,75 @@
  * renaming name[2,3] fields that need to be used for the quota identifier.
  */
 static inline struct ldlm_res_id *
-fid_build_reg_res_name(const struct lu_fid *f,
-		       struct ldlm_res_id *name)
+fid_build_reg_res_name(const struct lu_fid *fid, struct ldlm_res_id *res)
 {
-	memset(name, 0, sizeof *name);
-	name->name[LUSTRE_RES_ID_SEQ_OFF] = fid_seq(f);
-	name->name[LUSTRE_RES_ID_VER_OID_OFF] = fid_ver_oid(f);
-	return name;
+	memset(res, 0, sizeof(*res));
+	res->name[LUSTRE_RES_ID_SEQ_OFF] = fid_seq(fid);
+	res->name[LUSTRE_RES_ID_VER_OID_OFF] = fid_ver_oid(fid);
+
+	return res;
+}
+
+/*
+ * Return true if resource is for object identified by FID.
+ */
+static inline int fid_res_name_eq(const struct lu_fid *fid,
+				  const struct ldlm_res_id *res)
+{
+	return res->name[LUSTRE_RES_ID_SEQ_OFF] == fid_seq(fid) &&
+	       res->name[LUSTRE_RES_ID_VER_OID_OFF] == fid_ver_oid(fid);
+}
+
+/*
+ * Extract FID from LDLM resource. Reverse of fid_build_reg_res_name().
+ */
+static inline struct lu_fid *
+fid_extract_from_res_name(struct lu_fid *fid, const struct ldlm_res_id *res)
+{
+	fid->f_seq = res->name[LUSTRE_RES_ID_SEQ_OFF];
+	fid->f_oid = (__u32)(res->name[LUSTRE_RES_ID_VER_OID_OFF]);
+	fid->f_ver = (__u32)(res->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32);
+	LASSERT(fid_res_name_eq(fid, res));
+
+	return fid;
 }
 
 /*
  * Build (DLM) resource identifier from global quota FID and quota ID.
  */
 static inline struct ldlm_res_id *
-fid_build_quota_resid(const struct lu_fid *glb_fid, union lquota_id *qid,
+fid_build_quota_res_name(const struct lu_fid *glb_fid, union lquota_id *qid,
 		      struct ldlm_res_id *res)
 {
 	fid_build_reg_res_name(glb_fid, res);
 	res->name[LUSTRE_RES_ID_QUOTA_SEQ_OFF] = fid_seq(&qid->qid_fid);
 	res->name[LUSTRE_RES_ID_QUOTA_VER_OID_OFF] = fid_ver_oid(&qid->qid_fid);
+
 	return res;
 }
 
 /*
  * Extract global FID and quota ID from resource name
  */
-static inline void fid_extract_quota_resid(struct ldlm_res_id *res,
-					   struct lu_fid *glb_fid,
-					   union lquota_id *qid)
+static inline void fid_extract_from_quota_res(struct lu_fid *glb_fid,
+					      union lquota_id *qid,
+					      const struct ldlm_res_id *res)
 {
-	glb_fid->f_seq = res->name[LUSTRE_RES_ID_SEQ_OFF];
-	glb_fid->f_oid = (__u32)res->name[LUSTRE_RES_ID_VER_OID_OFF];
-	glb_fid->f_ver = (__u32)(res->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32);
-
+	fid_extract_from_res_name(glb_fid, res);
 	qid->qid_fid.f_seq = res->name[LUSTRE_RES_ID_QUOTA_SEQ_OFF];
 	qid->qid_fid.f_oid = (__u32)res->name[LUSTRE_RES_ID_QUOTA_VER_OID_OFF];
 	qid->qid_fid.f_ver =
 		(__u32)(res->name[LUSTRE_RES_ID_QUOTA_VER_OID_OFF] >> 32);
 }
 
-/*
- * Return true if resource is for object identified by fid.
- */
-static inline int fid_res_name_eq(const struct lu_fid *f,
-				  const struct ldlm_res_id *name)
-{
-	return name->name[LUSTRE_RES_ID_SEQ_OFF] == fid_seq(f) &&
-	       name->name[LUSTRE_RES_ID_VER_OID_OFF] == fid_ver_oid(f);
-}
-
-/* reverse function of fid_build_reg_res_name() */
-static inline void fid_build_from_res_name(struct lu_fid *f,
-					   const struct ldlm_res_id *name)
-{
-	fid_zero(f);
-	f->f_seq = name->name[LUSTRE_RES_ID_SEQ_OFF];
-	f->f_oid = name->name[LUSTRE_RES_ID_VER_OID_OFF] & 0xffffffff;
-	f->f_ver = name->name[LUSTRE_RES_ID_VER_OID_OFF] >> 32;
-	LASSERT(fid_res_name_eq(f, name));
-}
-
 static inline struct ldlm_res_id *
-fid_build_pdo_res_name(const struct lu_fid *f,
-		       unsigned int hash,
-		       struct ldlm_res_id *name)
+fid_build_pdo_res_name(const struct lu_fid *fid, unsigned int hash,
+		       struct ldlm_res_id *res)
 {
-	fid_build_reg_res_name(f, name);
-	name->name[LUSTRE_RES_ID_HSH_OFF] = hash;
-	return name;
+	fid_build_reg_res_name(fid, res);
+	res->name[LUSTRE_RES_ID_HSH_OFF] = hash;
+
+	return res;
 }
 
 /**
@@ -584,7 +595,7 @@
 		name->name[LUSTRE_RES_ID_SEQ_OFF] = ostid_id(oi);
 		name->name[LUSTRE_RES_ID_VER_OID_OFF] = ostid_seq(oi);
 	} else {
-		fid_build_reg_res_name((struct lu_fid *)oi, name);
+		fid_build_reg_res_name(&oi->oi_fid, name);
 	}
 }
 
@@ -597,7 +608,7 @@
 		ostid_set_id(oi, name->name[LUSTRE_RES_ID_SEQ_OFF]);
 	} else {
 		/* new resid */
-		fid_build_from_res_name((struct lu_fid *)oi, name);
+		fid_extract_from_res_name(&oi->oi_fid, name);
 	}
 }
 
@@ -644,7 +655,7 @@
 		ostid_to_fid(fid, &oi, 0);
 	} else {
 		/* new resid */
-		fid_build_from_res_name(fid, name);
+		fid_extract_from_res_name(fid, name);
 	}
 }
 
@@ -666,14 +677,14 @@
 
 	if (fid_is_igif(fid)) {
 		ino = lu_igif_ino(fid);
-		RETURN(ino);
+		return ino;
 	}
 
 	seq = fid_seq(fid);
 
 	ino = (seq << 24) + ((seq >> 24) & 0xffffff0000ULL) + fid_oid(fid);
 
-	RETURN(ino ? ino : fid_oid(fid));
+	return ino ? ino : fid_oid(fid);
 }
 
 static inline __u32 fid_hash(const struct lu_fid *f, int bits)
@@ -692,7 +703,7 @@
 
 	if (fid_is_igif(fid)) {
 		ino = lu_igif_ino(fid);
-		RETURN(ino);
+		return ino;
 	}
 
 	seq = fid_seq(fid) - FID_SEQ_START;
@@ -706,7 +717,7 @@
 	       (seq >> (64 - (40-8)) & 0xffffff00) +
 	       (fid_oid(fid) & 0xff000fff) + ((fid_oid(fid) & 0x00fff000) << 8);
 
-	RETURN(ino ? ino : fid_oid(fid));
+	return ino ? ino : fid_oid(fid);
 }
 
 static inline int lu_fid_diff(struct lu_fid *fid1, struct lu_fid *fid2)
@@ -759,4 +770,4 @@
 
 /** @} fid */
 
-#endif /* __LINUX_FID_H */
+#endif /* __LUSTRE_FID_H */
diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h
index 11e034a..550fff5 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fld.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fld.h
@@ -43,9 +43,6 @@
  */
 
 #include <lustre/lustre_idl.h>
-#include <lustre_mdt.h>
-#include <dt_object.h>
-
 #include <linux/libcfs/libcfs.h>
 
 struct lu_client_fld;
@@ -75,7 +72,7 @@
 struct lu_server_fld {
 	/**
 	 * Fld dir proc entry. */
-	proc_dir_entry_t    *lsf_proc_dir;
+	struct proc_dir_entry    *lsf_proc_dir;
 
 	/**
 	 * /fld file object device */
@@ -103,7 +100,7 @@
 struct lu_client_fld {
 	/**
 	 * Client side proc entry. */
-	proc_dir_entry_t    *lcf_proc_dir;
+	struct proc_dir_entry    *lcf_proc_dir;
 
 	/**
 	 * List of exports client FLD knows about. */
@@ -129,47 +126,9 @@
 	 * Client fld proc entry name. */
 	char		     lcf_name[80];
 
-	const struct lu_context *lcf_ctx;
-
 	int		      lcf_flags;
 };
 
-/**
- * number of blocks to reserve for particular operations. Should be function of
- * ... something. Stub for now.
- */
-enum {
-	/* one insert operation can involve two delete and one insert */
-	FLD_TXN_INDEX_INSERT_CREDITS  = 60,
-	FLD_TXN_INDEX_DELETE_CREDITS  = 20,
-};
-
-int fld_query(struct com_thread_info *info);
-
-/* Server methods */
-int fld_server_init(const struct lu_env *env, struct lu_server_fld *fld,
-		    struct dt_device *dt, const char *prefix, int mds_node_id,
-		    int type);
-
-void fld_server_fini(const struct lu_env *env, struct lu_server_fld *fld);
-
-int fld_declare_server_create(const struct lu_env *env,
-			      struct lu_server_fld *fld,
-			      struct lu_seq_range *new,
-			      struct thandle *th);
-
-int fld_server_create(const struct lu_env *env,
-		      struct lu_server_fld *fld,
-		      struct lu_seq_range *add_range,
-		      struct thandle *th);
-
-int fld_insert_entry(const struct lu_env *env,
-		     struct lu_server_fld *fld,
-		     const struct lu_seq_range *range);
-
-int fld_server_lookup(const struct lu_env *env, struct lu_server_fld *fld,
-		      seqno_t seq, struct lu_seq_range *range);
-
 /* Client methods */
 int fld_client_init(struct lu_client_fld *fld,
 		    const char *prefix, int hash);
diff --git a/drivers/staging/lustre/lustre/include/lustre_idmap.h b/drivers/staging/lustre/lustre/include/lustre_idmap.h
index 084bdd6..2da8596 100644
--- a/drivers/staging/lustre/lustre/include/lustre_idmap.h
+++ b/drivers/staging/lustre/lustre/include/lustre_idmap.h
@@ -80,8 +80,8 @@
 
 struct lu_ucred;
 
-extern void lustre_groups_from_list(group_info_t *ginfo, gid_t *glist);
-extern void lustre_groups_sort(group_info_t *group_info);
+extern void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist);
+extern void lustre_groups_sort(struct group_info *group_info);
 extern int lustre_in_group_p(struct lu_ucred *mu, gid_t grp);
 
 extern int lustre_idmap_add(struct lustre_idmap_table *t,
diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h
index 3a5dd6a..67259eb 100644
--- a/drivers/staging/lustre/lustre/include/lustre_import.h
+++ b/drivers/staging/lustre/lustre/include/lustre_import.h
@@ -336,9 +336,11 @@
 }
 
 static inline void at_reset(struct adaptive_timeout *at, int val) {
+	spin_lock(&at->at_lock);
 	at->at_current = val;
 	at->at_worst_ever = val;
 	at->at_worst_time = cfs_time_current_sec();
+	spin_unlock(&at->at_lock);
 }
 static inline void at_init(struct adaptive_timeout *at, int val, int flags) {
 	memset(at, 0, sizeof(*at));
diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h
index bdfc539..5e11107 100644
--- a/drivers/staging/lustre/lustre/include/lustre_lib.h
+++ b/drivers/staging/lustre/lustre/include/lustre_lib.h
@@ -96,7 +96,7 @@
 /* l_lock.c */
 struct lustre_lock {
 	int			l_depth;
-	task_t		*l_owner;
+	struct task_struct	*l_owner;
 	struct semaphore	l_sem;
 	spinlock_t		l_spin;
 };
@@ -260,10 +260,7 @@
 
 static inline void obd_ioctl_freedata(char *buf, int len)
 {
-	ENTRY;
-
 	OBD_FREE_LARGE(buf, len);
-	EXIT;
 	return;
 }
 
diff --git a/drivers/staging/lustre/lustre/include/lustre_log.h b/drivers/staging/lustre/lustre/include/lustre_log.h
index 714ab37..721aa05 100644
--- a/drivers/staging/lustre/lustre/include/lustre_log.h
+++ b/drivers/staging/lustre/lustre/include/lustre_log.h
@@ -469,16 +469,14 @@
 	struct llog_operations *lop;
 	int rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(handle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_destroy == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	rc = lop->lop_destroy(env, handle);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int llog_next_block(const struct lu_env *env,
@@ -489,17 +487,15 @@
 	struct llog_operations *lop;
 	int rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(loghandle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_next_block == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	rc = lop->lop_next_block(env, loghandle, cur_idx, next_idx,
 				 cur_offset, buf, len);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int llog_prev_block(const struct lu_env *env,
@@ -509,16 +505,14 @@
 	struct llog_operations *lop;
 	int rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(loghandle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_prev_block == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	rc = lop->lop_prev_block(env, loghandle, prev_idx, buf, len);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int llog_connect(struct llog_ctxt *ctxt,
@@ -528,16 +522,14 @@
 	struct llog_operations	*lop;
 	int			 rc;
 
-	ENTRY;
-
 	rc = llog_obd2ops(ctxt, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_connect == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	rc = lop->lop_connect(ctxt, logid, gen, uuid);
-	RETURN(rc);
+	return rc;
 }
 
 /* llog.c */
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h
index fb1561a..1900025 100644
--- a/drivers/staging/lustre/lustre/include/lustre_mdc.h
+++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h
@@ -84,9 +84,8 @@
 static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck,
 				    struct lookup_intent *it)
 {
-	ENTRY;
-
-	if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP))
+	if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
+			   it->it_op == IT_LAYOUT))
 		return;
 
 	/* This would normally block until the existing request finishes.
@@ -123,8 +122,9 @@
 static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck,
 				    struct lookup_intent *it)
 {
-	if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP))
-		goto out;
+	if (it != NULL && (it->it_op == IT_GETATTR || it->it_op == IT_LOOKUP ||
+			   it->it_op == IT_LAYOUT))
+		return;
 
 	if (lck->rpcl_it == MDC_FAKE_RPCL_IT) { /* OBD_FAIL_MDC_RPCS_SEM */
 		mutex_lock(&lck->rpcl_mutex);
@@ -141,8 +141,6 @@
 	}
 
 	mutex_unlock(&lck->rpcl_mutex);
- out:
-	EXIT;
 }
 
 static inline void mdc_update_max_ea_from_body(struct obd_export *exp,
diff --git a/drivers/staging/lustre/lustre/include/lustre_mdt.h b/drivers/staging/lustre/lustre/include/lustre_mdt.h
deleted file mode 100644
index dba26a6..0000000
--- a/drivers/staging/lustre/lustre/include/lustre_mdt.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- */
-
-#ifndef __LINUX_MDT_H
-#define __LINUX_MDT_H
-
-/** \defgroup mdt mdt
- *
- * @{
- */
-
-#include <lustre/lustre_idl.h>
-#include <lustre_req_layout.h>
-#include <md_object.h>
-#include <dt_object.h>
-#include <linux/libcfs/libcfs.h>
-
-/*
- * Common thread info for mdt, seq and fld
- */
-struct com_thread_info {
-	/*
-	 * for req-layout interface.
-	 */
-	struct req_capsule *cti_pill;
-};
-
-enum {
-	ESERIOUS = 0x0001000
-};
-
-static inline int err_serious(int rc)
-{
-	LASSERT(rc < 0);
-	LASSERT(-rc < ESERIOUS);
-	return -(-rc | ESERIOUS);
-}
-
-static inline int clear_serious(int rc)
-{
-	if (rc < 0)
-		rc = -(-rc & ~ESERIOUS);
-	return rc;
-}
-
-static inline int is_serious(int rc)
-{
-	return (rc < 0 && -rc & ESERIOUS);
-}
-
-/** @} mdt */
-
-#endif
diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h
index 293dd90..e947002 100644
--- a/drivers/staging/lustre/lustre/include/lustre_net.h
+++ b/drivers/staging/lustre/lustre/include/lustre_net.h
@@ -1136,7 +1136,7 @@
 	 * different module to the one the NRS framework is held within
 	 * (currently ptlrpc), should set this field to THIS_MODULE.
 	 */
-	module_t			  *nc_owner;
+	struct module			  *nc_owner;
 	/**
 	 * Policy registration flags; a bitmast of \e nrs_policy_flags
 	 */
@@ -1211,7 +1211,7 @@
 	 *   then unregistration and lprocfs operations will be properly
 	 *   serialized.
 	 */
-	module_t			       *pd_owner;
+	struct module			       *pd_owner;
 	/**
 	 * Bitmask of \e nrs_policy_flags
 	 */
@@ -2322,8 +2322,13 @@
 	pid_t t_pid;
 	/**
 	 * put watchdog in the structure per thread b=14840
+	 *
+	 * Lustre watchdog is removed for client in the hope
+	 * of a generic watchdog can be merged in kernel.
+	 * When that happens, we should add below back.
+	 *
+	 * struct lc_watchdog *t_watchdog;
 	 */
-	struct lc_watchdog *t_watchdog;
 	/**
 	 * the svc this thread belonged to b=18582
 	 */
@@ -2484,7 +2489,7 @@
 	/** limit of threads number for each partition */
 	int				srv_nthrs_cpt_limit;
 	/** Root of /proc dir tree for this service */
-	proc_dir_entry_t	   *srv_procroot;
+	struct proc_dir_entry	   *srv_procroot;
 	/** Pointer to statistic data for this service */
 	struct lprocfs_stats	   *srv_stats;
 	/** # hp per lp reqs to handle */
@@ -2631,7 +2636,7 @@
 	/** reqs waiting for replies */
 	struct ptlrpc_at_array		scp_at_array;
 	/** early reply timer */
-	timer_list_t			scp_at_timer;
+	struct timer_list		scp_at_timer;
 	/** debug */
 	cfs_time_t			scp_at_checktime;
 	/** check early replies */
@@ -3161,6 +3166,38 @@
 	req->rq_replen = lustre_shrink_msg(req->rq_repmsg, segment,
 					   newlen, move_data);
 }
+
+#ifdef CONFIG_LUSTRE_TRANSLATE_ERRNOS
+
+static inline int ptlrpc_status_hton(int h)
+{
+	/*
+	 * Positive errnos must be network errnos, such as LUSTRE_EDEADLK,
+	 * ELDLM_LOCK_ABORTED, etc.
+	 */
+	if (h < 0)
+		return -lustre_errno_hton(-h);
+	else
+		return h;
+}
+
+static inline int ptlrpc_status_ntoh(int n)
+{
+	/*
+	 * See the comment in ptlrpc_status_hton().
+	 */
+	if (n < 0)
+		return -lustre_errno_ntoh(-n);
+	else
+		return n;
+}
+
+#else
+
+#define ptlrpc_status_hton(h) (h)
+#define ptlrpc_status_ntoh(n) (n)
+
+#endif
 /** @} */
 
 /** Change request phase of \a req to \a new_phase */
diff --git a/drivers/staging/lustre/lustre/include/lustre_quota.h b/drivers/staging/lustre/lustre/include/lustre_quota.h
index 1c3041f..71b5d97 100644
--- a/drivers/staging/lustre/lustre/include/lustre_quota.h
+++ b/drivers/staging/lustre/lustre/include/lustre_quota.h
@@ -168,7 +168,7 @@
  * enforcement. Arguments are documented where each function is defined.  */
 
 struct qsd_instance *qsd_init(const struct lu_env *, char *, struct dt_device *,
-			      proc_dir_entry_t *);
+			      struct proc_dir_entry *);
 int qsd_prepare(const struct lu_env *, struct qsd_instance *);
 int qsd_start(const struct lu_env *, struct qsd_instance *);
 void qsd_fini(const struct lu_env *, struct qsd_instance *);
diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h
index 9e0908e..70b8b13 100644
--- a/drivers/staging/lustre/lustre/include/lustre_sec.h
+++ b/drivers/staging/lustre/lustre/include/lustre_sec.h
@@ -796,7 +796,7 @@
 };
 
 struct ptlrpc_sec_policy {
-	module_t		   *sp_owner;
+	struct module		   *sp_owner;
 	char			   *sp_name;
 	__u16			   sp_policy; /* policy number */
 	struct ptlrpc_sec_cops	 *sp_cops;   /* client ops */
diff --git a/drivers/staging/lustre/lustre/include/md_object.h b/drivers/staging/lustre/lustre/include/md_object.h
index 92d6420..daf93af 100644
--- a/drivers/staging/lustre/lustre/include/md_object.h
+++ b/drivers/staging/lustre/lustre/include/md_object.h
@@ -503,11 +503,6 @@
 	return container_of0(o->mo_lu.lo_dev, struct md_device, md_lu_dev);
 }
 
-static inline struct seq_server_site *lu_site2seq(const struct lu_site *s)
-{
-	return s->ld_seq_site;
-}
-
 static inline int md_device_init(struct md_device *md, struct lu_device_type *t)
 {
 	return lu_device_init(&md->md_lu_dev, t);
@@ -876,7 +871,7 @@
 	__u32	       uc_suppgids[2];
 	cfs_cap_t	   uc_cap;
 	__u32	       uc_umask;
-	group_info_t   *uc_ginfo;
+	struct group_info *uc_ginfo;
 	struct md_identity *uc_identity;
 };
 
diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h
index 0a251fd..a612255 100644
--- a/drivers/staging/lustre/lustre/include/obd.h
+++ b/drivers/staging/lustre/lustre/include/obd.h
@@ -49,15 +49,14 @@
 #define IOC_MDC_MAX_NR       50
 
 #include <lustre/lustre_idl.h>
-#include <lu_ref.h>
 #include <lustre_lib.h>
+#include <linux/libcfs/bitmap.h>
+#include <lu_ref.h>
 #include <lustre_export.h>
+#include <lustre_fid.h>
 #include <lustre_fld.h>
 #include <lustre_capa.h>
 
-#include <linux/libcfs/bitmap.h>
-
-
 #define MAX_OBD_DEVICES 8192
 
 struct osc_async_rc {
@@ -119,6 +118,20 @@
 #define lsm_stripe_count lsm_wire.lw_stripe_count
 #define lsm_pool_name    lsm_wire.lw_pool_name
 
+static inline bool lsm_is_released(struct lov_stripe_md *lsm)
+{
+	return !!(lsm->lsm_pattern & LOV_PATTERN_F_RELEASED);
+}
+
+static inline bool lsm_has_objects(struct lov_stripe_md *lsm)
+{
+	if (lsm == NULL)
+		return false;
+	if (lsm_is_released(lsm))
+		return false;
+	return true;
+}
+
 struct obd_info;
 
 typedef int (*obd_enqueue_update_f)(void *cookie, int rc);
@@ -225,7 +238,7 @@
 	struct list_head typ_chain;
 	struct obd_ops *typ_dt_ops;
 	struct md_ops *typ_md_ops;
-	proc_dir_entry_t *typ_procroot;
+	struct proc_dir_entry *typ_procroot;
 	char *typ_name;
 	int  typ_refcnt;
 	struct lu_device_type *typ_lu;
@@ -239,30 +252,6 @@
 	obd_flag flag;
 };
 
-/* Individual type definitions */
-
-struct ost_server_data;
-
-struct osd_properties {
-	size_t osd_max_ea_size;
-};
-
-#define OBT_MAGIC       0xBDDECEAE
-/* hold common fields for "target" device */
-struct obd_device_target {
-	__u32		     obt_magic;
-	__u32		     obt_instance;
-	struct super_block       *obt_sb;
-	/** last_rcvd file */
-	struct file	      *obt_rcvd_filp;
-	__u64		     obt_mount_count;
-	struct rw_semaphore	  obt_rwsem;
-	struct vfsmount	  *obt_vfsmnt;
-	struct file	      *obt_health_check_filp;
-	struct osd_properties     obt_osd_properties;
-	struct obd_job_stats      obt_jobstats;
-};
-
 /* llog contexts */
 enum llog_ctxt_id {
 	LLOG_CONFIG_ORIG_CTXT  =  0,
@@ -277,100 +266,13 @@
 	LLOG_TEST_REPL_CTXT,
 	LLOG_LOVEA_ORIG_CTXT,
 	LLOG_LOVEA_REPL_CTXT,
-	LLOG_CHANGELOG_ORIG_CTXT,      /**< changelog generation on mdd */
-	LLOG_CHANGELOG_REPL_CTXT,      /**< changelog access on clients */
-	LLOG_CHANGELOG_USER_ORIG_CTXT, /**< for multiple changelog consumers */
+	LLOG_CHANGELOG_ORIG_CTXT,	/**< changelog generation on mdd */
+	LLOG_CHANGELOG_REPL_CTXT,	/**< changelog access on clients */
+	LLOG_CHANGELOG_USER_ORIG_CTXT,	/**< for multiple changelog consumers */
+	LLOG_AGENT_ORIG_CTXT,		/**< agent requests generation on cdt */
 	LLOG_MAX_CTXTS
 };
 
-#define FILTER_SUBDIR_COUNT      32	    /* set to zero for no subdirs */
-
-struct filter_subdirs {
-	struct dentry *dentry[FILTER_SUBDIR_COUNT];
-};
-
-
-struct filter_ext {
-	__u64		fe_start;
-	__u64		fe_end;
-};
-
-struct filter_obd {
-	/* NB this field MUST be first */
-	struct obd_device_target fo_obt;
-	const char		*fo_fstype;
-
-	int			fo_group_count;
-	struct dentry		*fo_dentry_O;
-	struct dentry		**fo_dentry_O_groups;
-	struct filter_subdirs	*fo_dentry_O_sub;
-	struct mutex		fo_init_lock;	/* group initialization lock*/
-	int			fo_committed_group;
-
-	spinlock_t		fo_objidlock;	/* protect fo_lastobjid */
-
-	unsigned long		fo_destroys_in_progress;
-	struct mutex		fo_create_locks[FILTER_SUBDIR_COUNT];
-
-	struct list_head fo_export_list;
-	int		  fo_subdir_count;
-
-	obd_size	     fo_tot_dirty;      /* protected by obd_osfs_lock */
-	obd_size	     fo_tot_granted;    /* all values in bytes */
-	obd_size	     fo_tot_pending;
-	int		  fo_tot_granted_clients;
-
-	obd_size	     fo_readcache_max_filesize;
-	spinlock_t		fo_flags_lock;
-	unsigned int	 fo_read_cache:1,   /**< enable read-only cache */
-			     fo_writethrough_cache:1,/**< read cache writes */
-			     fo_mds_ost_sync:1, /**< MDS-OST orphan recovery*/
-			     fo_raid_degraded:1;/**< RAID device degraded */
-
-	struct obd_import   *fo_mdc_imp;
-	struct obd_uuid      fo_mdc_uuid;
-	struct lustre_handle fo_mdc_conn;
-	struct file	**fo_last_objid_files;
-	__u64	       *fo_last_objids; /* last created objid for groups,
-					      * protected by fo_objidlock */
-
-	struct mutex		fo_alloc_lock;
-
-	atomic_t	 fo_r_in_flight;
-	atomic_t	 fo_w_in_flight;
-
-	/*
-	 * per-filter pool of kiobuf's allocated by filter_common_setup() and
-	 * torn down by filter_cleanup().
-	 *
-	 * This pool contains kiobuf used by
-	 * filter_{prep,commit}rw_{read,write}() and is shared by all OST
-	 * threads.
-	 *
-	 * Locking: protected by internal lock of cfs_hash, pool can be
-	 * found from this hash table by t_id of ptlrpc_thread.
-	 */
-	struct cfs_hash		*fo_iobuf_hash;
-
-	struct brw_stats	 fo_filter_stats;
-
-	int		      fo_fmd_max_num; /* per exp filter_mod_data */
-	int		      fo_fmd_max_age; /* jiffies to fmd expiry */
-	unsigned long	    fo_syncjournal:1, /* sync journal on writes */
-				 fo_sync_lock_cancel:2;/* sync on lock cancel */
-
-
-	/* sptlrpc stuff */
-	rwlock_t		fo_sptlrpc_lock;
-	struct sptlrpc_rule_set  fo_sptlrpc_rset;
-
-	/* capability related */
-	unsigned int	     fo_fl_oss_capa;
-	struct list_head	       fo_capa_keys;
-	struct hlist_head	*fo_capa_hash;
-	int		      fo_sec_level;
-};
-
 struct timeout_item {
 	enum timeout_event ti_event;
 	cfs_time_t	 ti_timeout;
@@ -536,25 +438,6 @@
 	obd_id  *data;
 };
 
-/* */
-
-struct echo_obd {
-	struct obd_device_target eo_obt;
-	struct obdo		eo_oa;
-	spinlock_t		 eo_lock;
-	__u64			 eo_lastino;
-	struct lustre_handle	eo_nl_lock;
-	atomic_t		eo_prep;
-};
-
-struct ost_obd {
-	struct ptlrpc_service	*ost_service;
-	struct ptlrpc_service	*ost_create_service;
-	struct ptlrpc_service	*ost_io_service;
-	struct ptlrpc_service	*ost_seq_service;
-	struct mutex		ost_health_mutex;
-};
-
 struct echo_client_obd {
 	struct obd_export	*ec_exp;   /* the local connection to osc/lov */
 	spinlock_t		ec_lock;
@@ -654,7 +537,7 @@
 	struct lov_qos_rr     pool_rr;		/* round robin qos */
 	struct hlist_node      pool_hash;	      /* access by poolname */
 	struct list_head	    pool_list;	      /* serial access */
-	proc_dir_entry_t *pool_proc_entry;	/* file in /proc */
+	struct proc_dir_entry *pool_proc_entry;	/* file in /proc */
 	struct obd_device    *pool_lobd;	      /* obd of the lov/lod to which
 						       * this pool belongs */
 };
@@ -675,7 +558,7 @@
 	int		     lov_pool_count;
 	cfs_hash_t	     *lov_pools_hash_body; /* used for key access */
 	struct list_head	      lov_pool_list; /* used for sequential access */
-	proc_dir_entry_t   *lov_pool_proc_entry;
+	struct proc_dir_entry   *lov_pool_proc_entry;
 	enum lustre_sec_part    lov_sp_me;
 
 	/* Cached LRU pages from upper layer */
@@ -1017,7 +900,7 @@
 	int			      obd_requests_queued_for_recovery;
 	wait_queue_head_t		      obd_next_transno_waitq;
 	/* protected by obd_recovery_task_lock */
-	timer_list_t		      obd_recovery_timer;
+	struct timer_list	      obd_recovery_timer;
 	time_t			   obd_recovery_start; /* seconds */
 	time_t			   obd_recovery_end; /* seconds, for lprocfs_status */
 	int			      obd_recovery_time_hard;
@@ -1036,12 +919,8 @@
 	int			      obd_recovery_stage;
 
 	union {
-		struct obd_device_target obt;
-		struct filter_obd filter;
 		struct client_obd cli;
-		struct ost_obd ost;
 		struct echo_client_obd echo_client;
-		struct echo_obd echo;
 		struct lov_obd lov;
 		struct lmv_obd lmv;
 	} u;
@@ -1052,10 +931,10 @@
 	unsigned int	   md_cntr_base;
 	struct lprocfs_stats  *md_stats;
 
-	proc_dir_entry_t  *obd_proc_entry;
+	struct proc_dir_entry  *obd_proc_entry;
 	void		  *obd_proc_private; /* type private PDEs */
-	proc_dir_entry_t  *obd_proc_exports_entry;
-	proc_dir_entry_t  *obd_svc_procroot;
+	struct proc_dir_entry  *obd_proc_exports_entry;
+	struct proc_dir_entry  *obd_svc_procroot;
 	struct lprocfs_stats  *obd_svc_stats;
 	atomic_t	   obd_evict_inprogress;
 	wait_queue_head_t	    obd_evict_inprogress_waitq;
@@ -1218,12 +1097,6 @@
 				struct md_enqueue_info *minfo,
 				int rc);
 
-/* seq client type */
-enum lu_cli_type {
-	LUSTRE_SEQ_METADATA = 1,
-	LUSTRE_SEQ_DATA
-};
-
 struct md_enqueue_info {
 	struct md_op_data       mi_data;
 	struct lookup_intent    mi_it;
@@ -1235,7 +1108,7 @@
 };
 
 struct obd_ops {
-	module_t *o_owner;
+	struct module *o_owner;
 	int (*o_iocontrol)(unsigned int cmd, struct obd_export *exp, int len,
 			   void *karg, void *uarg);
 	int (*o_get_info)(const struct lu_env *env, struct obd_export *,
diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h
index de5c585..983718f 100644
--- a/drivers/staging/lustre/lustre/include/obd_class.h
+++ b/drivers/staging/lustre/lustre/include/obd_class.h
@@ -326,7 +326,7 @@
 do {							    \
 	if (!(obd)) {					   \
 		CERROR("NULL device\n");			\
-		RETURN(-ENODEV);				\
+		return -ENODEV;				\
 	}						       \
 } while (0)
 
@@ -337,7 +337,7 @@
 	if (!(obd)->obd_set_up || (obd)->obd_stopping) {	\
 		CERROR("Device %d not setup\n",		 \
 		       (obd)->obd_minor);		       \
-		RETURN(-ENODEV);				\
+		return -ENODEV;				\
 	}						       \
 } while (0)
 
@@ -424,7 +424,7 @@
 		if (err)					\
 			CERROR("md_" #op ": dev %s/%d no operation\n", \
 			       obd->obd_name, obd->obd_minor);  \
-		RETURN(err);				    \
+		return err;				    \
 	}						       \
 } while (0)
 
@@ -432,17 +432,17 @@
 do {							    \
 	if ((exp) == NULL) {				    \
 		CERROR("obd_" #op ": NULL export\n");	   \
-		RETURN(-ENODEV);				\
+		return -ENODEV;				\
 	}						       \
 	if ((exp)->exp_obd == NULL || !OBT((exp)->exp_obd)) {   \
 		CERROR("obd_" #op ": cleaned up obd\n");	\
-		RETURN(-EOPNOTSUPP);			    \
+		return -EOPNOTSUPP;			    \
 	}						       \
 	if (!OBT((exp)->exp_obd) || !MDP((exp)->exp_obd, op)) { \
 		CERROR("obd_" #op ": dev %s/%d no operation\n", \
 		       (exp)->exp_obd->obd_name,		\
 		       (exp)->exp_obd->obd_minor);	      \
-		RETURN(-EOPNOTSUPP);			    \
+		return -EOPNOTSUPP;			    \
 	}						       \
 } while (0)
 
@@ -453,7 +453,7 @@
 		if (err)					\
 			CERROR("obd_" #op ": dev %d no operation\n",    \
 			       obd->obd_minor);		 \
-		RETURN(err);				    \
+		return err;				    \
 	}						       \
 } while (0)
 
@@ -461,16 +461,16 @@
 do {							    \
 	if ((exp) == NULL) {				    \
 		CERROR("obd_" #op ": NULL export\n");	   \
-		RETURN(-ENODEV);				\
+		return -ENODEV;				\
 	}						       \
 	if ((exp)->exp_obd == NULL || !OBT((exp)->exp_obd)) {   \
 		CERROR("obd_" #op ": cleaned up obd\n");	\
-		RETURN(-EOPNOTSUPP);			    \
+		return -EOPNOTSUPP;			    \
 	}						       \
 	if (!OBT((exp)->exp_obd) || !OBP((exp)->exp_obd, op)) { \
 		CERROR("obd_" #op ": dev %d no operation\n",    \
 		       (exp)->exp_obd->obd_minor);	      \
-		RETURN(-EOPNOTSUPP);			    \
+		return -EOPNOTSUPP;			    \
 	}						       \
 } while (0)
 
@@ -480,7 +480,7 @@
 		if (err)					     \
 			CERROR("lop_" #op ": dev %d no operation\n", \
 			       ctxt->loc_obd->obd_minor);	    \
-		RETURN(err);					 \
+		return err;					 \
 	}							    \
 } while (0)
 
@@ -495,14 +495,13 @@
 			       struct lov_stripe_md *lsm)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, get_info);
 	EXP_COUNTER_INCREMENT(exp, get_info);
 
 	rc = OBP(exp->exp_obd, get_info)(env, exp, keylen, key, vallen, val,
 					 lsm);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_set_info_async(const struct lu_env *env,
@@ -511,14 +510,13 @@
 				     struct ptlrpc_request_set *set)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, set_info_async);
 	EXP_COUNTER_INCREMENT(exp, set_info_async);
 
 	rc = OBP(exp->exp_obd, set_info_async)(env, exp, keylen, key, vallen,
 					       val, set);
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -547,7 +545,6 @@
 {
 	int rc;
 	DECLARE_LU_VARS(ldt, d);
-	ENTRY;
 
 	ldt = obd->obd_type->typ_lu;
 	if (ldt != NULL) {
@@ -577,7 +574,7 @@
 		OBD_COUNTER_INCREMENT(obd, setup);
 		rc = OBP(obd, setup)(obd, cfg);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_precleanup(struct obd_device *obd,
@@ -585,7 +582,6 @@
 {
 	int rc;
 	DECLARE_LU_VARS(ldt, d);
-	ENTRY;
 
 	OBD_CHECK_DEV(obd);
 	ldt = obd->obd_type->typ_lu;
@@ -605,14 +601,13 @@
 	OBD_COUNTER_INCREMENT(obd, precleanup);
 
 	rc = OBP(obd, precleanup)(obd, cleanup_stage);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_cleanup(struct obd_device *obd)
 {
 	int rc;
 	DECLARE_LU_VARS(ldt, d);
-	ENTRY;
 
 	OBD_CHECK_DEV(obd);
 
@@ -632,13 +627,11 @@
 	OBD_COUNTER_INCREMENT(obd, cleanup);
 
 	rc = OBP(obd, cleanup)(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static inline void obd_cleanup_client_import(struct obd_device *obd)
 {
-	ENTRY;
-
 	/* If we set up but never connected, the
 	   client import will not have been cleaned. */
 	down_write(&obd->u.cli.cl_sem);
@@ -656,8 +649,6 @@
 		obd->u.cli.cl_import = NULL;
 	}
 	up_write(&obd->u.cli.cl_sem);
-
-	EXIT;
 }
 
 static inline int
@@ -665,7 +656,6 @@
 {
 	int rc;
 	DECLARE_LU_VARS(ldt, d);
-	ENTRY;
 
 	OBD_CHECK_DEV(obd);
 
@@ -687,7 +677,7 @@
 	OBD_COUNTER_INCREMENT(obd, process_config);
 	obd->obd_process_conf = 0;
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Pack an in-memory MD struct for storage on disk.
@@ -702,13 +692,12 @@
 			     struct lov_stripe_md *mem_src)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, packmd);
 	EXP_COUNTER_INCREMENT(exp, packmd);
 
 	rc = OBP(exp->exp_obd, packmd)(exp, disk_tgt, mem_src);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_size_diskmd(struct obd_export *exp,
@@ -757,13 +746,12 @@
 			       int disk_len)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, unpackmd);
 	EXP_COUNTER_INCREMENT(exp, unpackmd);
 
 	rc = OBP(exp->exp_obd, unpackmd)(exp, mem_tgt, disk_src, disk_len);
-	RETURN(rc);
+	return rc;
 }
 
 /* helper functions */
@@ -790,13 +778,12 @@
 static inline int obd_precreate(struct obd_export *exp)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, precreate);
 	OBD_COUNTER_INCREMENT(exp->exp_obd, precreate);
 
 	rc = OBP(exp->exp_obd, precreate)(exp);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_create_async(struct obd_export *exp,
@@ -805,13 +792,12 @@
 				   struct obd_trans_info *oti)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, create_async);
 	EXP_COUNTER_INCREMENT(exp, create_async);
 
 	rc = OBP(exp->exp_obd, create_async)(exp, oinfo, ea, oti);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_create(const struct lu_env *env, struct obd_export *exp,
@@ -819,13 +805,12 @@
 			     struct obd_trans_info *oti)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, create);
 	EXP_COUNTER_INCREMENT(exp, create);
 
 	rc = OBP(exp->exp_obd, create)(env, exp, obdo, ea, oti);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_destroy(const struct lu_env *env, struct obd_export *exp,
@@ -834,26 +819,24 @@
 			      struct obd_export *md_exp, void *capa)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, destroy);
 	EXP_COUNTER_INCREMENT(exp, destroy);
 
 	rc = OBP(exp->exp_obd, destroy)(env, exp, obdo, ea, oti, md_exp, capa);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_getattr(const struct lu_env *env, struct obd_export *exp,
 			      struct obd_info *oinfo)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, getattr);
 	EXP_COUNTER_INCREMENT(exp, getattr);
 
 	rc = OBP(exp->exp_obd, getattr)(env, exp, oinfo);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_getattr_async(struct obd_export *exp,
@@ -861,13 +844,12 @@
 				    struct ptlrpc_request_set *set)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, getattr_async);
 	EXP_COUNTER_INCREMENT(exp, getattr_async);
 
 	rc = OBP(exp->exp_obd, getattr_async)(exp, oinfo, set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_setattr(const struct lu_env *env, struct obd_export *exp,
@@ -875,13 +857,12 @@
 			      struct obd_trans_info *oti)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, setattr);
 	EXP_COUNTER_INCREMENT(exp, setattr);
 
 	rc = OBP(exp->exp_obd, setattr)(env, exp, oinfo, oti);
-	RETURN(rc);
+	return rc;
 }
 
 /* This performs all the requests set init/wait/destroy actions. */
@@ -891,20 +872,19 @@
 {
 	struct ptlrpc_request_set *set = NULL;
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, setattr_async);
 	EXP_COUNTER_INCREMENT(exp, setattr_async);
 
 	set =  ptlrpc_prep_set();
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = OBP(exp->exp_obd, setattr_async)(exp, oinfo, oti, set);
 	if (rc == 0)
 		rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
-	RETURN(rc);
+	return rc;
 }
 
 /* This adds all the requests into @set if @set != NULL, otherwise
@@ -915,13 +895,12 @@
 				    struct ptlrpc_request_set *set)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, setattr_async);
 	EXP_COUNTER_INCREMENT(exp, setattr_async);
 
 	rc = OBP(exp->exp_obd, setattr_async)(exp, oinfo, oti, set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_add_conn(struct obd_import *imp, struct obd_uuid *uuid,
@@ -929,40 +908,37 @@
 {
 	struct obd_device *obd = imp->imp_obd;
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DEV_ACTIVE(obd);
 	OBD_CHECK_DT_OP(obd, add_conn, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, add_conn);
 
 	rc = OBP(obd, add_conn)(imp, uuid, priority);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_del_conn(struct obd_import *imp, struct obd_uuid *uuid)
 {
 	struct obd_device *obd = imp->imp_obd;
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DEV_ACTIVE(obd);
 	OBD_CHECK_DT_OP(obd, del_conn, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, del_conn);
 
 	rc = OBP(obd, del_conn)(imp, uuid);
-	RETURN(rc);
+	return rc;
 }
 
 static inline struct obd_uuid *obd_get_uuid(struct obd_export *exp)
 {
 	struct obd_uuid *uuid;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, get_uuid, NULL);
 	EXP_COUNTER_INCREMENT(exp, get_uuid);
 
 	uuid = OBP(exp->exp_obd, get_uuid)(exp);
-	RETURN(uuid);
+	return uuid;
 }
 
 /** Create a new /a exp on device /a obd for the uuid /a cluuid
@@ -979,7 +955,6 @@
 	int rc;
 	__u64 ocf = data ? data->ocd_connect_flags : 0; /* for post-condition
 						   * check */
-	ENTRY;
 
 	OBD_CHECK_DEV_ACTIVE(obd);
 	OBD_CHECK_DT_OP(obd, connect, -EOPNOTSUPP);
@@ -989,7 +964,7 @@
 	/* check that only subset is granted */
 	LASSERT(ergo(data != NULL, (data->ocd_connect_flags & ocf) ==
 				    data->ocd_connect_flags));
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_reconnect(const struct lu_env *env,
@@ -1003,8 +978,6 @@
 	__u64 ocf = d ? d->ocd_connect_flags : 0; /* for post-condition
 						   * check */
 
-	ENTRY;
-
 	OBD_CHECK_DEV_ACTIVE(obd);
 	OBD_CHECK_DT_OP(obd, reconnect, 0);
 	OBD_COUNTER_INCREMENT(obd, reconnect);
@@ -1013,44 +986,41 @@
 	/* check that only subset is granted */
 	LASSERT(ergo(d != NULL,
 		     (d->ocd_connect_flags & ocf) == d->ocd_connect_flags));
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_disconnect(struct obd_export *exp)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, disconnect);
 	EXP_COUNTER_INCREMENT(exp, disconnect);
 
 	rc = OBP(exp->exp_obd, disconnect)(exp);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_fid_init(struct obd_device *obd, struct obd_export *exp,
 			       enum lu_cli_type type)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(obd, fid_init, 0);
 	OBD_COUNTER_INCREMENT(obd, fid_init);
 
 	rc = OBP(obd, fid_init)(obd, exp, type);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_fid_fini(struct obd_device *obd)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(obd, fid_fini, 0);
 	OBD_COUNTER_INCREMENT(obd, fid_fini);
 
 	rc = OBP(obd, fid_fini)(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_fid_alloc(struct obd_export *exp,
@@ -1058,113 +1028,101 @@
 				struct md_op_data *op_data)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, fid_alloc);
 	EXP_COUNTER_INCREMENT(exp, fid_alloc);
 
 	rc = OBP(exp->exp_obd, fid_alloc)(exp, fid, op_data);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_ping(const struct lu_env *env, struct obd_export *exp)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, ping, 0);
 	EXP_COUNTER_INCREMENT(exp, ping);
 
 	rc = OBP(exp->exp_obd, ping)(env, exp);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_pool_new(struct obd_device *obd, char *poolname)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(obd, pool_new, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, pool_new);
 
 	rc = OBP(obd, pool_new)(obd, poolname);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_pool_del(struct obd_device *obd, char *poolname)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(obd, pool_del, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, pool_del);
 
 	rc = OBP(obd, pool_del)(obd, poolname);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_pool_add(struct obd_device *obd, char *poolname, char *ostname)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(obd, pool_add, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, pool_add);
 
 	rc = OBP(obd, pool_add)(obd, poolname, ostname);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_pool_rem(struct obd_device *obd, char *poolname, char *ostname)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(obd, pool_rem, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, pool_rem);
 
 	rc = OBP(obd, pool_rem)(obd, poolname, ostname);
-	RETURN(rc);
+	return rc;
 }
 
 static inline void obd_getref(struct obd_device *obd)
 {
-	ENTRY;
 	if (OBT(obd) && OBP(obd, getref)) {
 		OBD_COUNTER_INCREMENT(obd, getref);
 		OBP(obd, getref)(obd);
 	}
-	EXIT;
 }
 
 static inline void obd_putref(struct obd_device *obd)
 {
-	ENTRY;
 	if (OBT(obd) && OBP(obd, putref)) {
 		OBD_COUNTER_INCREMENT(obd, putref);
 		OBP(obd, putref)(obd);
 	}
-	EXIT;
 }
 
 static inline int obd_init_export(struct obd_export *exp)
 {
 	int rc = 0;
 
-	ENTRY;
 	if ((exp)->exp_obd != NULL && OBT((exp)->exp_obd) &&
 	    OBP((exp)->exp_obd, init_export))
 		rc = OBP(exp->exp_obd, init_export)(exp);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_destroy_export(struct obd_export *exp)
 {
-	ENTRY;
 	if ((exp)->exp_obd != NULL && OBT((exp)->exp_obd) &&
 	    OBP((exp)->exp_obd, destroy_export))
 		OBP(exp->exp_obd, destroy_export)(exp);
-	RETURN(0);
+	return 0;
 }
 
 static inline int obd_extent_calc(struct obd_export *exp,
@@ -1172,10 +1130,10 @@
 				  int cmd, obd_off *offset)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_DT_OP(exp, extent_calc);
 	rc = OBP(exp->exp_obd, extent_calc)(exp, md, cmd, offset);
-	RETURN(rc);
+	return rc;
 }
 
 static inline struct dentry *
@@ -1198,10 +1156,9 @@
 {
 	int rc = 0;
 	struct obd_device *obd;
-	ENTRY;
 
 	if (exp == NULL || exp->exp_obd == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	obd = exp->exp_obd;
 	OBD_CHECK_DT_OP(obd, statfs, -EOPNOTSUPP);
@@ -1224,7 +1181,7 @@
 		if (oinfo->oi_cb_up)
 			oinfo->oi_cb_up(oinfo, 0);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_statfs_rqset(struct obd_export *exp,
@@ -1234,11 +1191,10 @@
 	struct ptlrpc_request_set *set = NULL;
 	struct obd_info oinfo = { { { 0 } } };
 	int rc = 0;
-	ENTRY;
 
 	set =  ptlrpc_prep_set();
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	oinfo.oi_osfs = osfs;
 	oinfo.oi_flags = flags;
@@ -1246,7 +1202,7 @@
 	if (rc == 0)
 		rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
-	RETURN(rc);
+	return rc;
 }
 
 /* @max_age is the oldest time in jiffies that we accept using a cached data.
@@ -1258,10 +1214,9 @@
 {
 	int rc = 0;
 	struct obd_device *obd = exp->exp_obd;
-	ENTRY;
 
 	if (obd == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	OBD_CHECK_DT_OP(obd, statfs, -EOPNOTSUPP);
 	OBD_COUNTER_INCREMENT(obd, statfs);
@@ -1286,7 +1241,7 @@
 		memcpy(osfs, &obd->obd_osfs, sizeof(*osfs));
 		spin_unlock(&obd->obd_osfs_lock);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_sync_rqset(struct obd_export *exp, struct obd_info *oinfo,
@@ -1294,20 +1249,19 @@
 {
 	struct ptlrpc_request_set *set = NULL;
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, sync, -EOPNOTSUPP);
 	EXP_COUNTER_INCREMENT(exp, sync);
 
 	set =  ptlrpc_prep_set();
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = OBP(exp->exp_obd, sync)(NULL, exp, oinfo, start, end, set);
 	if (rc == 0)
 		rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_sync(const struct lu_env *env, struct obd_export *exp,
@@ -1315,13 +1269,12 @@
 			   struct ptlrpc_request_set *set)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, sync, -EOPNOTSUPP);
 	EXP_COUNTER_INCREMENT(exp, sync);
 
 	rc = OBP(exp->exp_obd, sync)(env, exp, oinfo, start, end, set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_punch_rqset(struct obd_export *exp,
@@ -1330,20 +1283,19 @@
 {
 	struct ptlrpc_request_set *set = NULL;
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, punch);
 	EXP_COUNTER_INCREMENT(exp, punch);
 
 	set =  ptlrpc_prep_set();
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = OBP(exp->exp_obd, punch)(NULL, exp, oinfo, oti, set);
 	if (rc == 0)
 		rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_punch(const struct lu_env *env, struct obd_export *exp,
@@ -1351,13 +1303,12 @@
 			    struct ptlrpc_request_set *rqset)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, punch);
 	EXP_COUNTER_INCREMENT(exp, punch);
 
 	rc = OBP(exp->exp_obd, punch)(env, exp, oinfo, oti, rqset);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_brw(int cmd, struct obd_export *exp,
@@ -1365,7 +1316,6 @@
 			  struct brw_page *pg, struct obd_trans_info *oti)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, brw);
 	EXP_COUNTER_INCREMENT(exp, brw);
@@ -1377,7 +1327,7 @@
 	}
 
 	rc = OBP(exp->exp_obd, brw)(cmd, exp, oinfo, oa_bufs, pg, oti);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_preprw(const struct lu_env *env, int cmd,
@@ -1389,14 +1339,13 @@
 			     struct lustre_capa *capa)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, preprw);
 	EXP_COUNTER_INCREMENT(exp, preprw);
 
 	rc = OBP(exp->exp_obd, preprw)(env, cmd, exp, oa, objcount, obj, remote,
 				       pages, local, oti, capa);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_commitrw(const struct lu_env *env, int cmd,
@@ -1406,14 +1355,12 @@
 			       struct niobuf_local *local,
 			       struct obd_trans_info *oti, int rc)
 {
-	ENTRY;
-
 	EXP_CHECK_DT_OP(exp, commitrw);
 	EXP_COUNTER_INCREMENT(exp, commitrw);
 
 	rc = OBP(exp->exp_obd, commitrw)(env, cmd, exp, oa, objcount, obj,
 					 rnb, pages, local, oti, rc);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_merge_lvb(struct obd_export *exp,
@@ -1421,13 +1368,12 @@
 				struct ost_lvb *lvb, int kms_only)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, merge_lvb);
 	EXP_COUNTER_INCREMENT(exp, merge_lvb);
 
 	rc = OBP(exp->exp_obd, merge_lvb)(exp, lsm, lvb, kms_only);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_adjust_kms(struct obd_export *exp,
@@ -1435,26 +1381,24 @@
 				 int shrink)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, adjust_kms);
 	EXP_COUNTER_INCREMENT(exp, adjust_kms);
 
 	rc = OBP(exp->exp_obd, adjust_kms)(exp, lsm, size, shrink);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_iocontrol(unsigned int cmd, struct obd_export *exp,
 				int len, void *karg, void *uarg)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, iocontrol);
 	EXP_COUNTER_INCREMENT(exp, iocontrol);
 
 	rc = OBP(exp->exp_obd, iocontrol)(cmd, exp, len, karg, uarg);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_enqueue_rqset(struct obd_export *exp,
@@ -1463,20 +1407,19 @@
 {
 	struct ptlrpc_request_set *set = NULL;
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, enqueue);
 	EXP_COUNTER_INCREMENT(exp, enqueue);
 
 	set =  ptlrpc_prep_set();
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = OBP(exp->exp_obd, enqueue)(exp, oinfo, einfo, set);
 	if (rc == 0)
 		rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_enqueue(struct obd_export *exp,
@@ -1485,13 +1428,12 @@
 			      struct ptlrpc_request_set *set)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, enqueue);
 	EXP_COUNTER_INCREMENT(exp, enqueue);
 
 	rc = OBP(exp->exp_obd, enqueue)(exp, oinfo, einfo, set);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_change_cbdata(struct obd_export *exp,
@@ -1499,13 +1441,12 @@
 				    ldlm_iterator_t it, void *data)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, change_cbdata);
 	EXP_COUNTER_INCREMENT(exp, change_cbdata);
 
 	rc = OBP(exp->exp_obd, change_cbdata)(exp, lsm, it, data);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_find_cbdata(struct obd_export *exp,
@@ -1513,13 +1454,12 @@
 				  ldlm_iterator_t it, void *data)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, find_cbdata);
 	EXP_COUNTER_INCREMENT(exp, find_cbdata);
 
 	rc = OBP(exp->exp_obd, find_cbdata)(exp, lsm, it, data);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_cancel(struct obd_export *exp,
@@ -1527,13 +1467,12 @@
 			     struct lustre_handle *lockh)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, cancel);
 	EXP_COUNTER_INCREMENT(exp, cancel);
 
 	rc = OBP(exp->exp_obd, cancel)(exp, ea, mode, lockh);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_cancel_unused(struct obd_export *exp,
@@ -1542,13 +1481,12 @@
 				    void *opaque)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, cancel_unused);
 	EXP_COUNTER_INCREMENT(exp, cancel_unused);
 
 	rc = OBP(exp->exp_obd, cancel_unused)(exp, ea, flags, opaque);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_pin(struct obd_export *exp, const struct lu_fid *fid,
@@ -1556,26 +1494,24 @@
 			  int flag)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, pin);
 	EXP_COUNTER_INCREMENT(exp, pin);
 
 	rc = OBP(exp->exp_obd, pin)(exp, fid, oc, handle, flag);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_unpin(struct obd_export *exp,
 			    struct obd_client_handle *handle, int flag)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, unpin);
 	EXP_COUNTER_INCREMENT(exp, unpin);
 
 	rc = OBP(exp->exp_obd, unpin)(exp, handle, flag);
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1583,30 +1519,26 @@
 				    struct obd_import *imp,
 				    enum obd_import_event event)
 {
-	ENTRY;
 	if (!obd) {
 		CERROR("NULL device\n");
-		EXIT;
 		return;
 	}
 	if (obd->obd_set_up && OBP(obd, import_event)) {
 		OBD_COUNTER_INCREMENT(obd, import_event);
 		OBP(obd, import_event)(obd, imp, event);
 	}
-	EXIT;
 }
 
 static inline int obd_llog_connect(struct obd_export *exp,
 				   struct llogd_conn_body *body)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, llog_connect, 0);
 	EXP_COUNTER_INCREMENT(exp, llog_connect);
 
 	rc = OBP(exp->exp_obd, llog_connect)(exp, body);
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1616,7 +1548,7 @@
 			     void *data)
 {
 	int rc;
-	ENTRY;
+
 	OBD_CHECK_DEV(obd);
 
 	/* the check for async_recov is a complete hack - I'm hereby
@@ -1625,17 +1557,17 @@
 	   by this point, and it needs to get them to execute mds_postrecov. */
 	if (!obd->obd_set_up && !obd->obd_async_recov) {
 		CDEBUG(D_HA, "obd %s not set up\n", obd->obd_name);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (!OBP(obd, notify)) {
 		CDEBUG(D_HA, "obd %s has no notify handler\n", obd->obd_name);
-		RETURN(-ENOSYS);
+		return -ENOSYS;
 	}
 
 	OBD_COUNTER_INCREMENT(obd, notify);
 	rc = OBP(obd, notify)(obd, watched, ev, data);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_notify_observer(struct obd_device *observer,
@@ -1669,26 +1601,24 @@
 				 struct obd_quotactl *oqctl)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, quotacheck);
 	EXP_COUNTER_INCREMENT(exp, quotacheck);
 
 	rc = OBP(exp->exp_obd, quotacheck)(exp->exp_obd, exp, oqctl);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_quotactl(struct obd_export *exp,
 			       struct obd_quotactl *oqctl)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_DT_OP(exp, quotactl);
 	EXP_COUNTER_INCREMENT(exp, quotactl);
 
 	rc = OBP(exp->exp_obd, quotactl)(exp->exp_obd, exp, oqctl);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_health_check(const struct lu_env *env,
@@ -1702,56 +1632,52 @@
 	 *	 <0 on error
 	 */
 	int rc;
-	ENTRY;
 
 	/* don't use EXP_CHECK_DT_OP, because NULL method is normal here */
 	if (obd == NULL || !OBT(obd)) {
 		CERROR("cleaned up obd\n");
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	}
 	if (!obd->obd_set_up || obd->obd_stopping)
-		RETURN(0);
+		return 0;
 	if (!OBP(obd, health_check))
-		RETURN(0);
+		return 0;
 
 	rc = OBP(obd, health_check)(env, obd);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_register_observer(struct obd_device *obd,
 					struct obd_device *observer)
 {
-	ENTRY;
 	OBD_CHECK_DEV(obd);
 	down_write(&obd->obd_observer_link_sem);
 	if (obd->obd_observer && observer) {
 		up_write(&obd->obd_observer_link_sem);
-		RETURN(-EALREADY);
+		return -EALREADY;
 	}
 	obd->obd_observer = observer;
 	up_write(&obd->obd_observer_link_sem);
-	RETURN(0);
+	return 0;
 }
 
 static inline int obd_pin_observer(struct obd_device *obd,
 				   struct obd_device **observer)
 {
-	ENTRY;
 	down_read(&obd->obd_observer_link_sem);
 	if (!obd->obd_observer) {
 		*observer = NULL;
 		up_read(&obd->obd_observer_link_sem);
-		RETURN(-ENOENT);
+		return -ENOENT;
 	}
 	*observer = obd->obd_observer;
-	RETURN(0);
+	return 0;
 }
 
 static inline int obd_unpin_observer(struct obd_device *obd)
 {
-	ENTRY;
 	up_read(&obd->obd_observer_link_sem);
-	RETURN(0);
+	return 0;
 }
 
 #if 0
@@ -1760,52 +1686,48 @@
 					       obd_pin_extent_cb pin_cb)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, register_page_removal_cb, 0);
 	OBD_COUNTER_INCREMENT(exp->exp_obd, register_page_removal_cb);
 
 	rc = OBP(exp->exp_obd, register_page_removal_cb)(exp, cb, pin_cb);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_unregister_page_removal_cb(struct obd_export *exp,
 						 obd_page_removal_cb_t cb)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, unregister_page_removal_cb, 0);
 	OBD_COUNTER_INCREMENT(exp->exp_obd, unregister_page_removal_cb);
 
 	rc = OBP(exp->exp_obd, unregister_page_removal_cb)(exp, cb);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_register_lock_cancel_cb(struct obd_export *exp,
 					      obd_lock_cancel_cb cb)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, register_lock_cancel_cb, 0);
 	OBD_COUNTER_INCREMENT(exp->exp_obd, register_lock_cancel_cb);
 
 	rc = OBP(exp->exp_obd, register_lock_cancel_cb)(exp, cb);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int obd_unregister_lock_cancel_cb(struct obd_export *exp,
 						 obd_lock_cancel_cb cb)
 {
 	int rc;
-	ENTRY;
 
 	OBD_CHECK_DT_OP(exp->exp_obd, unregister_lock_cancel_cb, 0);
 	OBD_COUNTER_INCREMENT(exp->exp_obd, unregister_lock_cancel_cb);
 
 	rc = OBP(exp->exp_obd, unregister_lock_cancel_cb)(exp, cb);
-	RETURN(rc);
+	return rc;
 }
 #endif
 
@@ -1814,34 +1736,33 @@
 			       struct lu_fid *fid, struct obd_capa **pc)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_MD_OP(exp, getstatus);
 	EXP_MD_COUNTER_INCREMENT(exp, getstatus);
 	rc = MDP(exp->exp_obd, getstatus)(exp, fid, pc);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_getattr(struct obd_export *exp, struct md_op_data *op_data,
 			     struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, getattr);
 	EXP_MD_COUNTER_INCREMENT(exp, getattr);
 	rc = MDP(exp->exp_obd, getattr)(exp, op_data, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_null_inode(struct obd_export *exp,
 				   const struct lu_fid *fid)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, null_inode);
 	EXP_MD_COUNTER_INCREMENT(exp, null_inode);
 	rc = MDP(exp->exp_obd, null_inode)(exp, fid);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_find_cbdata(struct obd_export *exp,
@@ -1849,11 +1770,11 @@
 				 ldlm_iterator_t it, void *data)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, find_cbdata);
 	EXP_MD_COUNTER_INCREMENT(exp, find_cbdata);
 	rc = MDP(exp->exp_obd, find_cbdata)(exp, fid, it, data);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_close(struct obd_export *exp, struct md_op_data *op_data,
@@ -1861,11 +1782,11 @@
 			   struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, close);
 	EXP_MD_COUNTER_INCREMENT(exp, close);
 	rc = MDP(exp->exp_obd, close)(exp, op_data, mod, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_create(struct obd_export *exp, struct md_op_data *op_data,
@@ -1874,12 +1795,12 @@
 			    struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, create);
 	EXP_MD_COUNTER_INCREMENT(exp, create);
 	rc = MDP(exp->exp_obd, create)(exp, op_data, data, datalen, mode,
 				       uid, gid, cap_effective, rdev, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_done_writing(struct obd_export *exp,
@@ -1887,11 +1808,11 @@
 				  struct md_open_data *mod)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, done_writing);
 	EXP_MD_COUNTER_INCREMENT(exp, done_writing);
 	rc = MDP(exp->exp_obd, done_writing)(exp, op_data, mod);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_enqueue(struct obd_export *exp,
@@ -1904,12 +1825,12 @@
 			     int extra_lock_flags)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, enqueue);
 	EXP_MD_COUNTER_INCREMENT(exp, enqueue);
 	rc = MDP(exp->exp_obd, enqueue)(exp, einfo, it, op_data, lockh,
 					lmm, lmmsize, req, extra_lock_flags);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_getattr_name(struct obd_export *exp,
@@ -1917,11 +1838,11 @@
 				  struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, getattr_name);
 	EXP_MD_COUNTER_INCREMENT(exp, getattr_name);
 	rc = MDP(exp->exp_obd, getattr_name)(exp, op_data, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_intent_lock(struct obd_export *exp,
@@ -1932,24 +1853,24 @@
 				 __u64 extra_lock_flags)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, intent_lock);
 	EXP_MD_COUNTER_INCREMENT(exp, intent_lock);
 	rc = MDP(exp->exp_obd, intent_lock)(exp, op_data, lmm, lmmsize,
 					    it, lookup_flags, reqp, cb_blocking,
 					    extra_lock_flags);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_link(struct obd_export *exp, struct md_op_data *op_data,
 			  struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, link);
 	EXP_MD_COUNTER_INCREMENT(exp, link);
 	rc = MDP(exp->exp_obd, link)(exp, op_data, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_rename(struct obd_export *exp, struct md_op_data *op_data,
@@ -1957,12 +1878,12 @@
 			    int newlen, struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, rename);
 	EXP_MD_COUNTER_INCREMENT(exp, rename);
 	rc = MDP(exp->exp_obd, rename)(exp, op_data, old, oldlen, new,
 				       newlen, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_is_subdir(struct obd_export *exp,
@@ -1971,11 +1892,11 @@
 			       struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, is_subdir);
 	EXP_MD_COUNTER_INCREMENT(exp, is_subdir);
 	rc = MDP(exp->exp_obd, is_subdir)(exp, pfid, cfid, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_setattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -1984,23 +1905,23 @@
 			     struct md_open_data **mod)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, setattr);
 	EXP_MD_COUNTER_INCREMENT(exp, setattr);
 	rc = MDP(exp->exp_obd, setattr)(exp, op_data, ea, ealen,
 					ea2, ea2len, request, mod);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_sync(struct obd_export *exp, const struct lu_fid *fid,
 			  struct obd_capa *oc, struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, sync);
 	EXP_MD_COUNTER_INCREMENT(exp, sync);
 	rc = MDP(exp->exp_obd, sync)(exp, fid, oc, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_readpage(struct obd_export *exp, struct md_op_data *opdata,
@@ -2008,22 +1929,22 @@
 			      struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, readpage);
 	EXP_MD_COUNTER_INCREMENT(exp, readpage);
 	rc = MDP(exp->exp_obd, readpage)(exp, opdata, pages, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_unlink(struct obd_export *exp, struct md_op_data *op_data,
 			    struct ptlrpc_request **request)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, unlink);
 	EXP_MD_COUNTER_INCREMENT(exp, unlink);
 	rc = MDP(exp->exp_obd, unlink)(exp, op_data, request);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_get_lustre_md(struct obd_export *exp,
@@ -2032,19 +1953,17 @@
 				   struct obd_export *md_exp,
 				   struct lustre_md *md)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, get_lustre_md);
 	EXP_MD_COUNTER_INCREMENT(exp, get_lustre_md);
-	RETURN(MDP(exp->exp_obd, get_lustre_md)(exp, req, dt_exp, md_exp, md));
+	return MDP(exp->exp_obd, get_lustre_md)(exp, req, dt_exp, md_exp, md);
 }
 
 static inline int md_free_lustre_md(struct obd_export *exp,
 				    struct lustre_md *md)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, free_lustre_md);
 	EXP_MD_COUNTER_INCREMENT(exp, free_lustre_md);
-	RETURN(MDP(exp->exp_obd, free_lustre_md)(exp, md));
+	return MDP(exp->exp_obd, free_lustre_md)(exp, md);
 }
 
 static inline int md_setxattr(struct obd_export *exp,
@@ -2054,12 +1973,11 @@
 			      int output_size, int flags, __u32 suppgid,
 			      struct ptlrpc_request **request)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, setxattr);
 	EXP_MD_COUNTER_INCREMENT(exp, setxattr);
-	RETURN(MDP(exp->exp_obd, setxattr)(exp, fid, oc, valid, name, input,
+	return MDP(exp->exp_obd, setxattr)(exp, fid, oc, valid, name, input,
 					   input_size, output_size, flags,
-					   suppgid, request));
+					   suppgid, request);
 }
 
 static inline int md_getxattr(struct obd_export *exp,
@@ -2069,40 +1987,36 @@
 			      int output_size, int flags,
 			      struct ptlrpc_request **request)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, getxattr);
 	EXP_MD_COUNTER_INCREMENT(exp, getxattr);
-	RETURN(MDP(exp->exp_obd, getxattr)(exp, fid, oc, valid, name, input,
+	return MDP(exp->exp_obd, getxattr)(exp, fid, oc, valid, name, input,
 					   input_size, output_size, flags,
-					   request));
+					   request);
 }
 
 static inline int md_set_open_replay_data(struct obd_export *exp,
 					  struct obd_client_handle *och,
 					  struct ptlrpc_request *open_req)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, set_open_replay_data);
 	EXP_MD_COUNTER_INCREMENT(exp, set_open_replay_data);
-	RETURN(MDP(exp->exp_obd, set_open_replay_data)(exp, och, open_req));
+	return MDP(exp->exp_obd, set_open_replay_data)(exp, och, open_req);
 }
 
 static inline int md_clear_open_replay_data(struct obd_export *exp,
 					    struct obd_client_handle *och)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, clear_open_replay_data);
 	EXP_MD_COUNTER_INCREMENT(exp, clear_open_replay_data);
-	RETURN(MDP(exp->exp_obd, clear_open_replay_data)(exp, och));
+	return MDP(exp->exp_obd, clear_open_replay_data)(exp, och);
 }
 
 static inline int md_set_lock_data(struct obd_export *exp,
 				   __u64 *lockh, void *data, __u64 *bits)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, set_lock_data);
 	EXP_MD_COUNTER_INCREMENT(exp, set_lock_data);
-	RETURN(MDP(exp->exp_obd, set_lock_data)(exp, lockh, data, bits));
+	return MDP(exp->exp_obd, set_lock_data)(exp, lockh, data, bits);
 }
 
 static inline int md_cancel_unused(struct obd_export *exp,
@@ -2113,14 +2027,13 @@
 				   void *opaque)
 {
 	int rc;
-	ENTRY;
 
 	EXP_CHECK_MD_OP(exp, cancel_unused);
 	EXP_MD_COUNTER_INCREMENT(exp, cancel_unused);
 
 	rc = MDP(exp->exp_obd, cancel_unused)(exp, fid, policy, mode,
 					      flags, opaque);
-	RETURN(rc);
+	return rc;
 }
 
 static inline ldlm_mode_t md_lock_match(struct obd_export *exp, __u64 flags,
@@ -2130,21 +2043,19 @@
 					ldlm_mode_t mode,
 					struct lustre_handle *lockh)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, lock_match);
 	EXP_MD_COUNTER_INCREMENT(exp, lock_match);
-	RETURN(MDP(exp->exp_obd, lock_match)(exp, flags, fid, type,
-					     policy, mode, lockh));
+	return MDP(exp->exp_obd, lock_match)(exp, flags, fid, type,
+					     policy, mode, lockh);
 }
 
 static inline int md_init_ea_size(struct obd_export *exp, int easize,
 				  int def_asize, int cookiesize)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, init_ea_size);
 	EXP_MD_COUNTER_INCREMENT(exp, init_ea_size);
-	RETURN(MDP(exp->exp_obd, init_ea_size)(exp, easize, def_asize,
-					       cookiesize));
+	return MDP(exp->exp_obd, init_ea_size)(exp, easize, def_asize,
+					       cookiesize);
 }
 
 static inline int md_get_remote_perm(struct obd_export *exp,
@@ -2152,22 +2063,21 @@
 				     struct obd_capa *oc, __u32 suppgid,
 				     struct ptlrpc_request **request)
 {
-	ENTRY;
 	EXP_CHECK_MD_OP(exp, get_remote_perm);
 	EXP_MD_COUNTER_INCREMENT(exp, get_remote_perm);
-	RETURN(MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, suppgid,
-						  request));
+	return MDP(exp->exp_obd, get_remote_perm)(exp, fid, oc, suppgid,
+						  request);
 }
 
 static inline int md_renew_capa(struct obd_export *exp, struct obd_capa *ocapa,
 				renew_capa_cb_t cb)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, renew_capa);
 	EXP_MD_COUNTER_INCREMENT(exp, renew_capa);
 	rc = MDP(exp->exp_obd, renew_capa)(exp, ocapa, cb);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_unpack_capa(struct obd_export *exp,
@@ -2176,11 +2086,11 @@
 				 struct obd_capa **oc)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, unpack_capa);
 	EXP_MD_COUNTER_INCREMENT(exp, unpack_capa);
 	rc = MDP(exp->exp_obd, unpack_capa)(exp, req, field, oc);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_intent_getattr_async(struct obd_export *exp,
@@ -2188,11 +2098,11 @@
 					  struct ldlm_enqueue_info *einfo)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, intent_getattr_async);
 	EXP_MD_COUNTER_INCREMENT(exp, intent_getattr_async);
 	rc = MDP(exp->exp_obd, intent_getattr_async)(exp, minfo, einfo);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int md_revalidate_lock(struct obd_export *exp,
@@ -2200,11 +2110,11 @@
 				     struct lu_fid *fid, __u64 *bits)
 {
 	int rc;
-	ENTRY;
+
 	EXP_CHECK_MD_OP(exp, revalidate_lock);
 	EXP_MD_COUNTER_INCREMENT(exp, revalidate_lock);
 	rc = MDP(exp->exp_obd, revalidate_lock)(exp, it, fid, bits);
-	RETURN(rc);
+	return rc;
 }
 
 
diff --git a/drivers/staging/lustre/lustre/include/obd_lov.h b/drivers/staging/lustre/lustre/include/obd_lov.h
index d82f334..235718b 100644
--- a/drivers/staging/lustre/lustre/include/obd_lov.h
+++ b/drivers/staging/lustre/lustre/include/obd_lov.h
@@ -44,16 +44,6 @@
 	return sizeof(struct lov_stripe_md) + stripes*sizeof(struct lov_oinfo*);
 }
 
-static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic)
-{
-	if (lmm_magic == LOV_MAGIC_V3)
-		return sizeof(struct lov_mds_md_v3) +
-			stripes * sizeof(struct lov_ost_data_v1);
-	else
-		return sizeof(struct lov_mds_md_v1) +
-			stripes * sizeof(struct lov_ost_data_v1);
-}
-
 struct lov_version_size {
 	__u32   lvs_magic;
 	size_t  lvs_lmm_size;
diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h
index b5d40af..03e6133 100644
--- a/drivers/staging/lustre/lustre/include/obd_support.h
+++ b/drivers/staging/lustre/lustre/include/obd_support.h
@@ -470,6 +470,7 @@
 #define OBD_FAIL_LFSCK_DELAY3		0x1602
 #define OBD_FAIL_LFSCK_LINKEA_CRASH	0x1603
 #define OBD_FAIL_LFSCK_LINKEA_MORE	0x1604
+#define OBD_FAIL_LFSCK_LINKEA_MORE2	0x1605
 #define OBD_FAIL_LFSCK_FATAL1		0x1608
 #define OBD_FAIL_LFSCK_FATAL2		0x1609
 #define OBD_FAIL_LFSCK_CRASH		0x160a
diff --git a/drivers/staging/lustre/lustre/lclient/glimpse.c b/drivers/staging/lustre/lustre/lclient/glimpse.c
index 7f3974b..7bbca4b 100644
--- a/drivers/staging/lustre/lustre/lclient/glimpse.c
+++ b/drivers/staging/lustre/lustre/lclient/glimpse.c
@@ -93,7 +93,6 @@
 	struct cl_lock       *lock;
 	int result;
 
-	ENTRY;
 	result = 0;
 	if (!(lli->lli_flags & LLIF_MDS_SIZE_LOCK)) {
 		CDEBUG(D_DLMTRACE, "Glimpsing inode "DFID"\n", PFID(fid));
@@ -131,10 +130,10 @@
 			cio->cui_glimpse = 0;
 
 			if (lock == NULL)
-				RETURN(0);
+				return 0;
 
 			if (IS_ERR(lock))
-				RETURN(PTR_ERR(lock));
+				return PTR_ERR(lock);
 
 			LASSERT(agl == 0);
 			result = cl_wait(env, lock);
@@ -159,7 +158,7 @@
 		}
 	}
 
-	RETURN(result);
+	return result;
 }
 
 static int cl_io_get(struct inode *inode, struct lu_env **envout,
@@ -203,8 +202,6 @@
 	int		     result;
 	int		     refcheck;
 
-	ENTRY;
-
 	result = cl_io_get(inode, &env, &io, &refcheck);
 	if (result > 0) {
 	again:
@@ -226,7 +223,7 @@
 			goto again;
 		cl_env_put(env, &refcheck);
 	}
-	RETURN(result);
+	return result;
 }
 
 int cl_local_size(struct inode *inode)
@@ -240,14 +237,12 @@
 	int		      result;
 	int		      refcheck;
 
-	ENTRY;
-
 	if (!cl_i2info(inode)->lli_has_smd)
-		RETURN(0);
+		return 0;
 
 	result = cl_io_get(inode, &env, &io, &refcheck);
 	if (result <= 0)
-		RETURN(result);
+		return result;
 
 	clob = io->ci_obj;
 	result = cl_io_init(env, io, CIT_MISC, clob);
@@ -270,5 +265,5 @@
 	}
 	cl_io_fini(env, io);
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
index 4a01666..8ff38c6 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
@@ -169,7 +169,6 @@
 {
 	struct ccc_device  *vdv;
 	int rc;
-	ENTRY;
 
 	vdv = lu2ccc_dev(d);
 	vdv->cdv_next = lu2cl_dev(next);
@@ -182,7 +181,7 @@
 		lu_device_get(next);
 		lu_ref_add(&next->ld_reference, "lu-stack", &lu_site_init);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 struct lu_device *ccc_device_fini(const struct lu_env *env,
@@ -201,11 +200,10 @@
 	struct lu_device  *lud;
 	struct cl_site    *site;
 	int rc;
-	ENTRY;
 
 	OBD_ALLOC_PTR(vdv);
 	if (vdv == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	lud = &vdv->cdv_cl.cd_lu_dev;
 	cl_device_init(&vdv->cdv_cl, t);
@@ -228,7 +226,7 @@
 		ccc_device_free(env, lud);
 		lud = ERR_PTR(rc);
 	}
-	RETURN(lud);
+	return lud;
 }
 
 struct lu_device *ccc_device_free(const struct lu_env *env,
@@ -418,7 +416,6 @@
 {
 	struct inode *inode = ccc_object_inode(obj);
 
-	ENTRY;
 	lvb->lvb_mtime = cl_inode_mtime(inode);
 	lvb->lvb_atime = cl_inode_atime(inode);
 	lvb->lvb_ctime = cl_inode_ctime(inode);
@@ -429,7 +426,7 @@
 	 */
 	if (lvb->lvb_size > 0 && lvb->lvb_blocks == 0)
 		lvb->lvb_blocks = dirty_cnt(inode);
-	RETURN(0);
+	return 0;
 }
 
 
@@ -479,8 +476,6 @@
 
 	int result;
 
-	ENTRY;
-
 	if (io->ci_type == CIT_READ || io->ci_type == CIT_WRITE ||
 	    io->ci_type == CIT_FAULT) {
 		if (cio->cui_fd->fd_flags & LL_FILE_GROUP_LOCKED)
@@ -495,7 +490,7 @@
 		}
 	} else
 		result = 0;
-	RETURN(result);
+	return result;
 }
 
 int ccc_fail(const struct lu_env *env, const struct cl_page_slice *slice)
@@ -559,9 +554,8 @@
 				   const struct cl_page_slice *slice,
 				   struct cl_io *unused)
 {
-	ENTRY;
 	/* transient page should always be sent. */
-	RETURN(0);
+	return 0;
 }
 
 /*****************************************************************************
@@ -623,7 +617,6 @@
 	const struct ccc_io	*cio   = ccc_env_io(env);
 	int			 result;
 
-	ENTRY;
 	/*
 	 * Work around DLM peculiarity: it assumes that glimpse
 	 * (LDLM_FL_HAS_INTENT) lock is always LCK_PR, and returns reads lock
@@ -642,7 +635,7 @@
 		result = lock->cll_state >= CLS_ENQUEUED;
 	else
 		result = 1;
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -655,7 +648,6 @@
 		    enum cl_lock_state state)
 {
 	struct cl_lock *lock = slice->cls_lock;
-	ENTRY;
 
 	/*
 	 * Refresh inode attributes when the lock is moving into CLS_HELD
@@ -682,7 +674,6 @@
 		    lock->cll_descr.cld_end == CL_PAGE_EOF)
 			cl_merge_lvb(env, inode);
 	}
-	EXIT;
 }
 
 /*****************************************************************************
@@ -707,7 +698,6 @@
 	struct cl_object       *obj   = io->ci_obj;
 
 	CLOBINVRNT(env, obj, ccc_object_invariant(obj));
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "lock: %d [%lu, %lu]\n", mode, start, end);
 
@@ -725,7 +715,7 @@
 	descr->cld_enq_flags = enqflags;
 
 	cl_io_lock_add(env, io, &cio->cui_link);
-	RETURN(0);
+	return 0;
 }
 
 void ccc_io_update_iov(const struct lu_env *env,
@@ -986,11 +976,9 @@
 	int	    result;
 	int	    refcheck;
 
-	ENTRY;
-
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	io = ccc_env_thread_io(env);
 	io->ci_obj = cl_i2info(inode)->lli_clob;
@@ -1019,7 +1007,7 @@
 	if (unlikely(io->ci_need_restart))
 		goto again;
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
 
 /*****************************************************************************
@@ -1166,7 +1154,7 @@
 			 * locked by I_NEW bit.
 			 */
 			lli->lli_clob = clob;
-			lli->lli_has_smd = md->lsm != NULL;
+			lli->lli_has_smd = lsm_has_objects(md->lsm);
 			lu_object_ref_add(&clob->co_lu, "inode", inode);
 		} else
 			result = PTR_ERR(clob);
@@ -1284,9 +1272,9 @@
 __u64 cl_fid_build_ino(const struct lu_fid *fid, int api32)
 {
 	if (BITS_PER_LONG == 32 || api32)
-		RETURN(fid_flatten32(fid));
+		return fid_flatten32(fid);
 	else
-		RETURN(fid_flatten(fid));
+		return fid_flatten(fid);
 }
 
 /**
@@ -1295,15 +1283,14 @@
 __u32 cl_fid_build_gen(const struct lu_fid *fid)
 {
 	__u32 gen;
-	ENTRY;
 
 	if (fid_is_igif(fid)) {
 		gen = lu_igif_gen(fid);
-		RETURN(gen);
+		return gen;
 	}
 
 	gen = (fid_flatten(fid) >> 32);
-	RETURN(gen);
+	return gen;
 }
 
 /* lsm is unreliable after hsm implementation as layout can be changed at
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_misc.c b/drivers/staging/lustre/lustre/lclient/lcommon_misc.c
index 8ecbef9..2b4dbee 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_misc.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_misc.c
@@ -57,12 +57,11 @@
 	int rc, easize, def_easize, cookiesize;
 	struct lov_desc desc;
 	__u16 stripes;
-	ENTRY;
 
 	rc = obd_get_info(NULL, dt_exp, sizeof(KEY_LOVDESC), KEY_LOVDESC,
 			  &valsize, &desc, NULL);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	stripes = min(desc.ld_tgt_count, (__u32)LOV_MAX_STRIPE_COUNT);
 	lsm.lsm_stripe_count = stripes;
@@ -77,7 +76,7 @@
 	       easize, cookiesize);
 
 	rc = md_init_ea_size(md_exp, easize, def_easize, cookiesize);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -95,7 +94,6 @@
 	__u64 flags;
 	int   result;
 
-	ENTRY;
 	if (!strcmp(watched->obd_type->typ_name, LUSTRE_OSC_NAME)) {
 		cli = &watched->u.cli;
 		lco = owner;
@@ -116,7 +114,7 @@
 		       watched->obd_name);
 		result = -EINVAL;
 	}
-	RETURN(result);
+	return result;
 }
 
 #define GROUPLOCK_SCOPE "grouplock"
diff --git a/drivers/staging/lustre/lustre/ldlm/interval_tree.c b/drivers/staging/lustre/lustre/ldlm/interval_tree.c
index ce90c7e..c65b13c 100644
--- a/drivers/staging/lustre/lustre/ldlm/interval_tree.c
+++ b/drivers/staging/lustre/lustre/ldlm/interval_tree.c
@@ -133,53 +133,45 @@
 
 static struct interval_node *interval_first(struct interval_node *node)
 {
-	ENTRY;
-
 	if (!node)
-		RETURN(NULL);
+		return NULL;
 	while (node->in_left)
 		node = node->in_left;
-	RETURN(node);
+	return node;
 }
 
 static struct interval_node *interval_last(struct interval_node *node)
 {
-	ENTRY;
-
 	if (!node)
-		RETURN(NULL);
+		return NULL;
 	while (node->in_right)
 		node = node->in_right;
-	RETURN(node);
+	return node;
 }
 
 static struct interval_node *interval_next(struct interval_node *node)
 {
-	ENTRY;
-
 	if (!node)
-		RETURN(NULL);
+		return NULL;
 	if (node->in_right)
-		RETURN(interval_first(node->in_right));
+		return interval_first(node->in_right);
 	while (node->in_parent && node_is_right_child(node))
 		node = node->in_parent;
-	RETURN(node->in_parent);
+	return node->in_parent;
 }
 
 static struct interval_node *interval_prev(struct interval_node *node)
 {
-	ENTRY;
-
 	if (!node)
-		RETURN(NULL);
+		return NULL;
 
 	if (node->in_left)
-		RETURN(interval_last(node->in_left));
+		return interval_last(node->in_left);
 
 	while (node->in_parent && node_is_left_child(node))
 		node = node->in_parent;
 
-	RETURN(node->in_parent);
+	return node->in_parent;
 }
 
 enum interval_iter interval_iterate(struct interval_node *root,
@@ -188,7 +180,6 @@
 {
 	struct interval_node *node;
 	enum interval_iter rc = INTERVAL_ITER_CONT;
-	ENTRY;
 
 	interval_for_each(node, root) {
 		rc = func(node, data);
@@ -196,7 +187,7 @@
 			break;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(interval_iterate);
 
@@ -206,7 +197,6 @@
 {
 	struct interval_node *node;
 	enum interval_iter rc = INTERVAL_ITER_CONT;
-	ENTRY;
 
 	interval_for_each_reverse(node, root) {
 		rc = func(node, data);
@@ -214,7 +204,7 @@
 			break;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(interval_iterate_reverse);
 
@@ -225,7 +215,6 @@
 {
 	struct interval_node *walk = root;
 	int rc;
-	ENTRY;
 
 	while (walk) {
 		rc = extent_compare(ex, &walk->in_extent);
@@ -237,7 +226,7 @@
 			walk = walk->in_right;
 	}
 
-	RETURN(walk);
+	return walk;
 }
 EXPORT_SYMBOL(interval_find);
 
@@ -326,7 +315,6 @@
 				  struct interval_node **root)
 {
 	struct interval_node *parent, *gparent;
-	ENTRY;
 
 	while ((parent = node->in_parent) && node_is_red(parent)) {
 		gparent = parent->in_parent;
@@ -373,7 +361,6 @@
 	}
 
 	(*root)->in_color = INTERVAL_BLACK;
-	EXIT;
 }
 
 struct interval_node *interval_insert(struct interval_node *node,
@@ -381,14 +368,13 @@
 
 {
 	struct interval_node **p, *parent = NULL;
-	ENTRY;
 
 	LASSERT(!interval_is_intree(node));
 	p = root;
 	while (*p) {
 		parent = *p;
 		if (node_equal(parent, node))
-			RETURN(parent);
+			return parent;
 
 		/* max_high field must be updated after each iteration */
 		if (parent->in_max_high < interval_high(node))
@@ -409,7 +395,7 @@
 	interval_insert_color(node, root);
 	node->in_intree = 1;
 
-	RETURN(NULL);
+	return NULL;
 }
 EXPORT_SYMBOL(interval_insert);
 
@@ -423,7 +409,6 @@
 				 struct interval_node **root)
 {
 	struct interval_node *tmp;
-	ENTRY;
 
 	while (node_is_black_or_0(node) && node != *root) {
 		if (parent->in_left == node) {
@@ -490,7 +475,6 @@
 	}
 	if (node)
 		node->in_color = INTERVAL_BLACK;
-	EXIT;
 }
 
 /*
@@ -501,7 +485,6 @@
 			   __u64  old_maxhigh)
 {
 	__u64 left_max, right_max;
-	ENTRY;
 
 	while (node) {
 		left_max = node->in_left ? node->in_left->in_max_high : 0;
@@ -513,7 +496,6 @@
 			break;
 		node = node->in_parent;
 	}
-	EXIT;
 }
 
 void interval_erase(struct interval_node *node,
@@ -521,7 +503,6 @@
 {
 	struct interval_node *child, *parent;
 	int color;
-	ENTRY;
 
 	LASSERT(interval_is_intree(node));
 	node->in_intree = 0;
@@ -586,7 +567,6 @@
 color:
 	if (color == INTERVAL_BLACK)
 		interval_erase_color(child, parent, root);
-	EXIT;
 }
 EXPORT_SYMBOL(interval_erase);
 
diff --git a/drivers/staging/lustre/lustre/ldlm/l_lock.c b/drivers/staging/lustre/lustre/ldlm/l_lock.c
index 853409a..32f4d52 100644
--- a/drivers/staging/lustre/lustre/ldlm/l_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/l_lock.c
@@ -51,12 +51,12 @@
 struct ldlm_resource *lock_res_and_lock(struct ldlm_lock *lock)
 {
 	/* on server-side resource of lock doesn't change */
-	if (!lock->l_ns_srv)
+	if ((lock->l_flags & LDLM_FL_NS_SRV) == 0)
 		spin_lock(&lock->l_lock);
 
 	lock_res(lock->l_resource);
 
-	lock->l_res_locked = 1;
+	lock->l_flags |= LDLM_FL_RES_LOCKED;
 	return lock->l_resource;
 }
 EXPORT_SYMBOL(lock_res_and_lock);
@@ -67,10 +67,10 @@
 void unlock_res_and_lock(struct ldlm_lock *lock)
 {
 	/* on server-side resource of lock doesn't change */
-	lock->l_res_locked = 0;
+	lock->l_flags &= ~LDLM_FL_RES_LOCKED;
 
 	unlock_res(lock->l_resource);
-	if (!lock->l_ns_srv)
+	if ((lock->l_flags & LDLM_FL_NS_SRV) == 0)
 		spin_unlock(&lock->l_lock);
 }
 EXPORT_SYMBOL(unlock_res_and_lock);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
index f7432f7..7e31663 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_extent.c
@@ -72,7 +72,6 @@
 	struct list_head *tmp;
 	struct ldlm_lock *lck;
 	__u64 kms = 0;
-	ENTRY;
 
 	/* don't let another thread in ldlm_extent_shift_kms race in
 	 * just after we finish and take our lock into account in its
@@ -86,7 +85,7 @@
 			continue;
 
 		if (lck->l_policy_data.l_extent.end >= old_kms)
-			RETURN(old_kms);
+			return old_kms;
 
 		/* This extent _has_ to be smaller than old_kms (checked above)
 		 * so kms can only ever be smaller or the same as old_kms. */
@@ -95,7 +94,7 @@
 	}
 	LASSERTF(kms <= old_kms, "kms "LPU64" old_kms "LPU64"\n", kms, old_kms);
 
-	RETURN(kms);
+	return kms;
 }
 EXPORT_SYMBOL(ldlm_extent_shift_kms);
 
@@ -103,16 +102,15 @@
 struct ldlm_interval *ldlm_interval_alloc(struct ldlm_lock *lock)
 {
 	struct ldlm_interval *node;
-	ENTRY;
 
 	LASSERT(lock->l_resource->lr_type == LDLM_EXTENT);
 	OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO);
 	if (node == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	INIT_LIST_HEAD(&node->li_group);
 	ldlm_interval_attach(node, lock);
-	RETURN(node);
+	return node;
 }
 
 void ldlm_interval_free(struct ldlm_interval *node)
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
index f100a84..c68ed27 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
@@ -142,8 +142,6 @@
 static inline void
 ldlm_flock_destroy(struct ldlm_lock *lock, ldlm_mode_t mode, __u64 flags)
 {
-	ENTRY;
-
 	LDLM_DEBUG(lock, "ldlm_flock_destroy(mode: %d, flags: 0x%llx)",
 		   mode, flags);
 
@@ -162,7 +160,6 @@
 	}
 
 	ldlm_lock_destroy_nolock(lock);
-	EXIT;
 }
 
 /**
@@ -198,6 +195,7 @@
 		if (lock == NULL)
 			break;
 
+		LASSERT(req != lock);
 		flock = &lock->l_policy_data.l_flock;
 		LASSERT(flock->owner == bl_owner);
 		bl_owner = flock->blocking_owner;
@@ -253,7 +251,6 @@
 	int splitted = 0;
 	const struct ldlm_callback_suite null_cbs = { NULL };
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_DLMTRACE, "flags %#llx owner "LPU64" pid %u mode %u start "
 	       LPU64" end "LPU64"\n", *flags,
@@ -308,12 +305,12 @@
 				continue;
 
 			if (!first_enq)
-				RETURN(LDLM_ITER_CONTINUE);
+				return LDLM_ITER_CONTINUE;
 
 			if (*flags & LDLM_FL_BLOCK_NOWAIT) {
 				ldlm_flock_destroy(req, mode, *flags);
 				*err = -EAGAIN;
-				RETURN(LDLM_ITER_STOP);
+				return LDLM_ITER_STOP;
 			}
 
 			if (*flags & LDLM_FL_TEST_LOCK) {
@@ -326,24 +323,27 @@
 				req->l_policy_data.l_flock.end =
 					lock->l_policy_data.l_flock.end;
 				*flags |= LDLM_FL_LOCK_CHANGED;
-				RETURN(LDLM_ITER_STOP);
+				return LDLM_ITER_STOP;
 			}
 
-			if (ldlm_flock_deadlock(req, lock)) {
-				ldlm_flock_destroy(req, mode, *flags);
-				*err = -EDEADLK;
-				RETURN(LDLM_ITER_STOP);
-			}
-
+			/* add lock to blocking list before deadlock
+			 * check to prevent race */
 			rc = ldlm_flock_blocking_link(req, lock);
 			if (rc) {
 				ldlm_flock_destroy(req, mode, *flags);
 				*err = rc;
-				RETURN(LDLM_ITER_STOP);
+				return LDLM_ITER_STOP;
 			}
+			if (ldlm_flock_deadlock(req, lock)) {
+				ldlm_flock_blocking_unlink(req);
+				ldlm_flock_destroy(req, mode, *flags);
+				*err = -EDEADLK;
+				return LDLM_ITER_STOP;
+			}
+
 			ldlm_resource_add_lock(res, &res->lr_waiting, req);
 			*flags |= LDLM_FL_BLOCK_GRANTED;
-			RETURN(LDLM_ITER_STOP);
+			return LDLM_ITER_STOP;
 		}
 	}
 
@@ -351,7 +351,7 @@
 		ldlm_flock_destroy(req, mode, *flags);
 		req->l_req_mode = LCK_NL;
 		*flags |= LDLM_FL_LOCK_CHANGED;
-		RETURN(LDLM_ITER_STOP);
+		return LDLM_ITER_STOP;
 	}
 
 	/* In case we had slept on this lock request take it off of the
@@ -463,7 +463,7 @@
 				ldlm_flock_destroy(req, lock->l_granted_mode,
 						   *flags);
 				*err = -ENOLCK;
-				RETURN(LDLM_ITER_STOP);
+				return LDLM_ITER_STOP;
 			}
 			goto reprocess;
 		}
@@ -530,7 +530,7 @@
 		ldlm_flock_destroy(req, mode, *flags);
 
 	ldlm_resource_dump(D_INFO, res);
-	RETURN(LDLM_ITER_CONTINUE);
+	return LDLM_ITER_CONTINUE;
 }
 
 struct ldlm_flock_wait_data {
@@ -542,7 +542,6 @@
 ldlm_flock_interrupted_wait(void *data)
 {
 	struct ldlm_lock *lock;
-	ENTRY;
 
 	lock = ((struct ldlm_flock_wait_data *)data)->fwd_lock;
 
@@ -553,8 +552,6 @@
 	/* client side - set flag to prevent lock from being put on LRU list */
 	lock->l_flags |= LDLM_FL_CBPENDING;
 	unlock_res_and_lock(lock);
-
-	EXIT;
 }
 
 /**
@@ -577,7 +574,6 @@
 	struct l_wait_info	      lwi;
 	ldlm_error_t		    err;
 	int			     rc = 0;
-	ENTRY;
 
 	CDEBUG(D_DLMTRACE, "flags: 0x%llx data: %p getlk: %p\n",
 	       flags, data, getlk);
@@ -595,7 +591,7 @@
 
 		/* Need to wake up the waiter if we were evicted */
 		wake_up(&lock->l_waitq);
-		RETURN(0);
+		return 0;
 	}
 
 	LASSERT(flags != LDLM_FL_WAIT_NOREPROC);
@@ -607,7 +603,7 @@
 			goto granted;
 		/* CP AST RPC: lock get granted, wake it up */
 		wake_up(&lock->l_waitq);
-		RETURN(0);
+		return 0;
 	}
 
 	LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, "
@@ -633,26 +629,26 @@
 	if (rc) {
 		LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
 			   rc);
-		RETURN(rc);
+		return rc;
 	}
 
 granted:
 	OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT, 10);
 
-	if (lock->l_destroyed) {
+	if (lock->l_flags & LDLM_FL_DESTROYED) {
 		LDLM_DEBUG(lock, "client-side enqueue waking up: destroyed");
-		RETURN(0);
+		return 0;
 	}
 
 	if (lock->l_flags & LDLM_FL_FAILED) {
 		LDLM_DEBUG(lock, "client-side enqueue waking up: failed");
-		RETURN(-EIO);
+		return -EIO;
 	}
 
 	if (rc) {
 		LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
 			   rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	LDLM_DEBUG(lock, "client-side enqueue granted");
@@ -694,15 +690,13 @@
 		ldlm_process_flock_lock(lock, &noreproc, 1, &err, NULL);
 	}
 	unlock_res_and_lock(lock);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_flock_completion_ast);
 
 int ldlm_flock_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
 			    void *data, int flag)
 {
-	ENTRY;
-
 	LASSERT(lock);
 	LASSERT(flag == LDLM_CB_CANCELING);
 
@@ -710,7 +704,7 @@
 	lock_res_and_lock(lock);
 	ldlm_flock_blocking_unlink(lock);
 	unlock_res_and_lock(lock);
-	RETURN(0);
+	return 0;
 }
 
 void ldlm_flock_policy_wire18_to_local(const ldlm_wire_policy_data_t *wpolicy,
@@ -831,19 +825,17 @@
 				&ldlm_export_flock_ops,
 				CFS_HASH_DEFAULT | CFS_HASH_NBLK_CHANGE);
 	if (!exp->exp_flock_hash)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_init_flock_export);
 
 void ldlm_destroy_flock_export(struct obd_export *exp)
 {
-	ENTRY;
 	if (exp->exp_flock_hash) {
 		cfs_hash_putref(exp->exp_flock_hash);
 		exp->exp_flock_hash = NULL;
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_destroy_flock_export);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
index 141a957..8cd7963 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
@@ -36,23 +36,46 @@
 
 #define MAX_STRING_SIZE 128
 
-extern atomic_t ldlm_srv_namespace_nr;
-extern atomic_t ldlm_cli_namespace_nr;
+extern int ldlm_srv_namespace_nr;
+extern int ldlm_cli_namespace_nr;
 extern struct mutex ldlm_srv_namespace_lock;
 extern struct list_head ldlm_srv_namespace_list;
 extern struct mutex ldlm_cli_namespace_lock;
-extern struct list_head ldlm_cli_namespace_list;
+extern struct list_head ldlm_cli_active_namespace_list;
+extern struct list_head ldlm_cli_inactive_namespace_list;
 
-static inline atomic_t *ldlm_namespace_nr(ldlm_side_t client)
+static inline int ldlm_namespace_nr_read(ldlm_side_t client)
 {
 	return client == LDLM_NAMESPACE_SERVER ?
-		&ldlm_srv_namespace_nr : &ldlm_cli_namespace_nr;
+		ldlm_srv_namespace_nr : ldlm_cli_namespace_nr;
+}
+
+static inline void ldlm_namespace_nr_inc(ldlm_side_t client)
+{
+	if (client == LDLM_NAMESPACE_SERVER)
+		ldlm_srv_namespace_nr++;
+	else
+		ldlm_cli_namespace_nr++;
+}
+
+static inline void ldlm_namespace_nr_dec(ldlm_side_t client)
+{
+	if (client == LDLM_NAMESPACE_SERVER)
+		ldlm_srv_namespace_nr--;
+	else
+		ldlm_cli_namespace_nr--;
 }
 
 static inline struct list_head *ldlm_namespace_list(ldlm_side_t client)
 {
 	return client == LDLM_NAMESPACE_SERVER ?
-		&ldlm_srv_namespace_list : &ldlm_cli_namespace_list;
+		&ldlm_srv_namespace_list : &ldlm_cli_active_namespace_list;
+}
+
+static inline struct list_head *ldlm_namespace_inactive_list(ldlm_side_t client)
+{
+	return client == LDLM_NAMESPACE_SERVER ?
+		&ldlm_srv_namespace_list : &ldlm_cli_inactive_namespace_list;
 }
 
 static inline struct mutex *ldlm_namespace_lock(ldlm_side_t client)
@@ -61,6 +84,16 @@
 		&ldlm_srv_namespace_lock : &ldlm_cli_namespace_lock;
 }
 
+/* ns_bref is the number of resources in this namespace */
+static inline int ldlm_ns_empty(struct ldlm_namespace *ns)
+{
+	return atomic_read(&ns->ns_bref) == 0;
+}
+
+void ldlm_namespace_move_to_active_locked(struct ldlm_namespace *, ldlm_side_t);
+void ldlm_namespace_move_to_inactive_locked(struct ldlm_namespace *, ldlm_side_t);
+struct ldlm_namespace *ldlm_namespace_first_locked(ldlm_side_t);
+
 /* ldlm_request.c */
 /* Cancel lru flag, it indicates we cancel aged locks. */
 enum {
@@ -159,8 +192,8 @@
 void l_check_ns_lock(struct ldlm_namespace *ns);
 void l_check_no_ns_lock(struct ldlm_namespace *ns);
 
-extern proc_dir_entry_t *ldlm_svc_proc_dir;
-extern proc_dir_entry_t *ldlm_type_proc_dir;
+extern struct proc_dir_entry *ldlm_svc_proc_dir;
+extern struct proc_dir_entry *ldlm_type_proc_dir;
 
 struct ldlm_state {
 	struct ptlrpc_service *ldlm_cb_service;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
index 42df530..1a8c0d7 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c
@@ -60,17 +60,16 @@
 	struct ptlrpc_connection *ptlrpc_conn;
 	struct obd_import_conn *imp_conn = NULL, *item;
 	int rc = 0;
-	ENTRY;
 
 	if (!create && !priority) {
 		CDEBUG(D_HA, "Nothing to do\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	ptlrpc_conn = ptlrpc_uuid_to_connection(uuid);
 	if (!ptlrpc_conn) {
 		CDEBUG(D_HA, "can't find connection %s\n", uuid->uuid);
-		RETURN (-ENOENT);
+		return -ENOENT;
 	}
 
 	if (create) {
@@ -115,13 +114,13 @@
 	}
 
 	spin_unlock(&imp->imp_lock);
-	RETURN(0);
+	return 0;
 out_free:
 	if (imp_conn)
 		OBD_FREE(imp_conn, sizeof(*imp_conn));
 out_put:
 	ptlrpc_connection_put(ptlrpc_conn);
-	RETURN(rc);
+	return rc;
 }
 
 int import_set_conn_priority(struct obd_import *imp, struct obd_uuid *uuid)
@@ -141,7 +140,6 @@
 	struct obd_import_conn *imp_conn;
 	struct obd_export *dlmexp;
 	int rc = -ENOENT;
-	ENTRY;
 
 	spin_lock(&imp->imp_lock);
 	if (list_empty(&imp->imp_conn_list)) {
@@ -187,7 +185,7 @@
 	spin_unlock(&imp->imp_lock);
 	if (rc == -ENOENT)
 		CERROR("connection %s not found\n", uuid->uuid);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(client_import_del_conn);
 
@@ -200,7 +198,6 @@
 {
 	struct obd_import_conn *conn;
 	int rc = -ENOENT;
-	ENTRY;
 
 	spin_lock(&imp->imp_lock);
 	list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
@@ -212,7 +209,7 @@
 		}
 	}
 	spin_unlock(&imp->imp_lock);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(client_import_find_conn);
 
@@ -267,7 +264,6 @@
 	ldlm_ns_type_t ns_type = LDLM_NS_TYPE_UNKNOWN;
 	int rc;
 	char	*cli_name = lustre_cfg_buf(lcfg, 0);
-	ENTRY;
 
 	/* In a more perfect world, we would hang a ptlrpc_client off of
 	 * obd_type and just use the values from there. */
@@ -305,27 +301,27 @@
 	} else {
 		CERROR("unknown client OBD type \"%s\", can't setup\n",
 		       name);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
 		CERROR("requires a TARGET UUID\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 1) > 37) {
 		CERROR("client UUID must be less than 38 characters\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 2) < 1) {
 		CERROR("setup requires a SERVER UUID\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 2) > 37) {
 		CERROR("target UUID must be less than 38 characters\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	init_rwsem(&cli->cl_sem);
@@ -339,8 +335,8 @@
 	cli->cl_avail_grant = 0;
 	/* FIXME: Should limit this for the sum of all cl_dirty_max. */
 	cli->cl_dirty_max = OSC_MAX_DIRTY_DEFAULT * 1024 * 1024;
-	if (cli->cl_dirty_max >> PAGE_CACHE_SHIFT > num_physpages / 8)
-		cli->cl_dirty_max = num_physpages << (PAGE_CACHE_SHIFT - 3);
+	if (cli->cl_dirty_max >> PAGE_CACHE_SHIFT > totalram_pages / 8)
+		cli->cl_dirty_max = totalram_pages << (PAGE_CACHE_SHIFT - 3);
 	INIT_LIST_HEAD(&cli->cl_cache_waiters);
 	INIT_LIST_HEAD(&cli->cl_loi_ready_list);
 	INIT_LIST_HEAD(&cli->cl_loi_hp_ready_list);
@@ -388,11 +384,11 @@
 
 	if (!strcmp(name, LUSTRE_MDC_NAME)) {
 		cli->cl_max_rpcs_in_flight = MDC_MAX_RIF_DEFAULT;
-	} else if (num_physpages >> (20 - PAGE_CACHE_SHIFT) <= 128 /* MB */) {
+	} else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 128 /* MB */) {
 		cli->cl_max_rpcs_in_flight = 2;
-	} else if (num_physpages >> (20 - PAGE_CACHE_SHIFT) <= 256 /* MB */) {
+	} else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 256 /* MB */) {
 		cli->cl_max_rpcs_in_flight = 3;
-	} else if (num_physpages >> (20 - PAGE_CACHE_SHIFT) <= 512 /* MB */) {
+	} else if (totalram_pages >> (20 - PAGE_CACHE_SHIFT) <= 512 /* MB */) {
 		cli->cl_max_rpcs_in_flight = 4;
 	} else {
 		if (osc_on_mdt(obddev->obd_name))
@@ -452,29 +448,27 @@
 
 	cli->cl_qchk_stat = CL_NOT_QUOTACHECKED;
 
-	RETURN(rc);
+	return rc;
 
 err_import:
 	class_destroy_import(imp);
 err_ldlm:
 	ldlm_put_ref();
 err:
-	RETURN(rc);
+	return rc;
 
 }
 EXPORT_SYMBOL(client_obd_setup);
 
 int client_obd_cleanup(struct obd_device *obddev)
 {
-	ENTRY;
-
 	ldlm_namespace_free_post(obddev->obd_namespace);
 	obddev->obd_namespace = NULL;
 
 	LASSERT(obddev->u.cli.cl_import == NULL);
 
 	ldlm_put_ref();
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(client_obd_cleanup);
 
@@ -489,7 +483,6 @@
 	struct obd_connect_data *ocd;
 	struct lustre_handle    conn    = { 0 };
 	int		     rc;
-	ENTRY;
 
 	*exp = NULL;
 	down_write(&cli->cl_sem);
@@ -532,8 +525,6 @@
 
 	ptlrpc_pinger_add_import(imp);
 
-	EXIT;
-
 	if (rc) {
 out_ldlm:
 		cli->cl_conn_count--;
@@ -553,12 +544,11 @@
 	struct client_obd *cli;
 	struct obd_import *imp;
 	int rc = 0, err;
-	ENTRY;
 
 	if (!obd) {
 		CERROR("invalid export for disconnect: exp %p cookie "LPX64"\n",
 		       exp, exp ? exp->exp_handle.h_cookie : -1);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	cli = &obd->u.cli;
@@ -605,8 +595,6 @@
 
 	ptlrpc_invalidate_import(imp);
 
-	EXIT;
-
 out_disconnect:
 	/* Use server style - class_disconnect should be always called for
 	 * o_disconnect. */
@@ -616,7 +604,7 @@
 
 	up_write(&cli->cl_sem);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(client_disconnect_export);
 
@@ -627,7 +615,6 @@
 int target_pack_pool_reply(struct ptlrpc_request *req)
 {
 	struct obd_device *obd;
-	ENTRY;
 
 	/* Check that we still have all structures alive as this may
 	 * be some late RPC at shutdown time. */
@@ -635,7 +622,7 @@
 		     !exp_connect_lru_resize(req->rq_export))) {
 		lustre_msg_set_slv(req->rq_repmsg, 0);
 		lustre_msg_set_limit(req->rq_repmsg, 0);
-		RETURN(0);
+		return 0;
 	}
 
 	/* OBD is alive here as export is alive, which we checked above. */
@@ -646,7 +633,7 @@
 	lustre_msg_set_limit(req->rq_repmsg, obd->obd_pool_limit);
 	read_unlock(&obd->obd_pool_lock);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(target_pack_pool_reply);
 
@@ -674,10 +661,8 @@
 	int			netrc;
 	struct ptlrpc_reply_state *rs;
 	struct obd_export	 *exp;
-	ENTRY;
 
 	if (req->rq_no_reply) {
-		EXIT;
 		return;
 	}
 
@@ -686,7 +671,6 @@
 	if (rs == NULL || !rs->rs_difficult) {
 		/* no notifiers */
 		target_send_reply_msg (req, rc, fail_id);
-		EXIT;
 		return;
 	}
 
@@ -757,19 +741,18 @@
 	}
 	spin_unlock(&rs->rs_lock);
 	spin_unlock(&svcpt->scp_rep_lock);
-	EXIT;
 }
 EXPORT_SYMBOL(target_send_reply);
 
 ldlm_mode_t lck_compat_array[] = {
-	[LCK_EX] LCK_COMPAT_EX,
-	[LCK_PW] LCK_COMPAT_PW,
-	[LCK_PR] LCK_COMPAT_PR,
-	[LCK_CW] LCK_COMPAT_CW,
-	[LCK_CR] LCK_COMPAT_CR,
-	[LCK_NL] LCK_COMPAT_NL,
-	[LCK_GROUP] LCK_COMPAT_GROUP,
-	[LCK_COS] LCK_COMPAT_COS,
+	[LCK_EX]	= LCK_COMPAT_EX,
+	[LCK_PW]	= LCK_COMPAT_PW,
+	[LCK_PR]	= LCK_COMPAT_PR,
+	[LCK_CW]	= LCK_COMPAT_CW,
+	[LCK_CR]	= LCK_COMPAT_CR,
+	[LCK_NL]	= LCK_COMPAT_NL,
+	[LCK_GROUP]	= LCK_COMPAT_GROUP,
+	[LCK_COS]	= LCK_COMPAT_COS,
 };
 
 /**
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
index 33b76a1..6133b3f 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c
@@ -49,45 +49,45 @@
 
 /* lock types */
 char *ldlm_lockname[] = {
-	[0] "--",
-	[LCK_EX] "EX",
-	[LCK_PW] "PW",
-	[LCK_PR] "PR",
-	[LCK_CW] "CW",
-	[LCK_CR] "CR",
-	[LCK_NL] "NL",
-	[LCK_GROUP] "GROUP",
-	[LCK_COS] "COS"
+	[0]		= "--",
+	[LCK_EX]	= "EX",
+	[LCK_PW]	= "PW",
+	[LCK_PR]	= "PR",
+	[LCK_CW]	= "CW",
+	[LCK_CR]	= "CR",
+	[LCK_NL]	= "NL",
+	[LCK_GROUP]	= "GROUP",
+	[LCK_COS]	= "COS",
 };
 EXPORT_SYMBOL(ldlm_lockname);
 
 char *ldlm_typename[] = {
-	[LDLM_PLAIN] "PLN",
-	[LDLM_EXTENT] "EXT",
-	[LDLM_FLOCK] "FLK",
-	[LDLM_IBITS] "IBT",
+	[LDLM_PLAIN]	= "PLN",
+	[LDLM_EXTENT]	= "EXT",
+	[LDLM_FLOCK]	= "FLK",
+	[LDLM_IBITS]	= "IBT",
 };
 EXPORT_SYMBOL(ldlm_typename);
 
 static ldlm_policy_wire_to_local_t ldlm_policy_wire18_to_local[] = {
-	[LDLM_PLAIN - LDLM_MIN_TYPE] ldlm_plain_policy_wire_to_local,
-	[LDLM_EXTENT - LDLM_MIN_TYPE] ldlm_extent_policy_wire_to_local,
-	[LDLM_FLOCK - LDLM_MIN_TYPE] ldlm_flock_policy_wire18_to_local,
-	[LDLM_IBITS - LDLM_MIN_TYPE] ldlm_ibits_policy_wire_to_local,
+	[LDLM_PLAIN - LDLM_MIN_TYPE]	= ldlm_plain_policy_wire_to_local,
+	[LDLM_EXTENT - LDLM_MIN_TYPE]	= ldlm_extent_policy_wire_to_local,
+	[LDLM_FLOCK - LDLM_MIN_TYPE]	= ldlm_flock_policy_wire18_to_local,
+	[LDLM_IBITS - LDLM_MIN_TYPE]	= ldlm_ibits_policy_wire_to_local,
 };
 
 static ldlm_policy_wire_to_local_t ldlm_policy_wire21_to_local[] = {
-	[LDLM_PLAIN - LDLM_MIN_TYPE] ldlm_plain_policy_wire_to_local,
-	[LDLM_EXTENT - LDLM_MIN_TYPE] ldlm_extent_policy_wire_to_local,
-	[LDLM_FLOCK - LDLM_MIN_TYPE] ldlm_flock_policy_wire21_to_local,
-	[LDLM_IBITS - LDLM_MIN_TYPE] ldlm_ibits_policy_wire_to_local,
+	[LDLM_PLAIN - LDLM_MIN_TYPE]	= ldlm_plain_policy_wire_to_local,
+	[LDLM_EXTENT - LDLM_MIN_TYPE]	= ldlm_extent_policy_wire_to_local,
+	[LDLM_FLOCK - LDLM_MIN_TYPE]	= ldlm_flock_policy_wire21_to_local,
+	[LDLM_IBITS - LDLM_MIN_TYPE]	= ldlm_ibits_policy_wire_to_local,
 };
 
 static ldlm_policy_local_to_wire_t ldlm_policy_local_to_wire[] = {
-	[LDLM_PLAIN - LDLM_MIN_TYPE] ldlm_plain_policy_local_to_wire,
-	[LDLM_EXTENT - LDLM_MIN_TYPE] ldlm_extent_policy_local_to_wire,
-	[LDLM_FLOCK - LDLM_MIN_TYPE] ldlm_flock_policy_local_to_wire,
-	[LDLM_IBITS - LDLM_MIN_TYPE] ldlm_ibits_policy_local_to_wire,
+	[LDLM_PLAIN - LDLM_MIN_TYPE]	= ldlm_plain_policy_local_to_wire,
+	[LDLM_EXTENT - LDLM_MIN_TYPE]	= ldlm_extent_policy_local_to_wire,
+	[LDLM_FLOCK - LDLM_MIN_TYPE]	= ldlm_flock_policy_local_to_wire,
+	[LDLM_IBITS - LDLM_MIN_TYPE]	= ldlm_ibits_policy_local_to_wire,
 };
 
 /**
@@ -188,8 +188,6 @@
  */
 void ldlm_lock_put(struct ldlm_lock *lock)
 {
-	ENTRY;
-
 	LASSERT(lock->l_resource != LP_POISON);
 	LASSERT(atomic_read(&lock->l_refc) > 0);
 	if (atomic_dec_and_test(&lock->l_refc)) {
@@ -199,7 +197,7 @@
 			   "final lock_put on destroyed lock, freeing it.");
 
 		res = lock->l_resource;
-		LASSERT(lock->l_destroyed);
+		LASSERT(lock->l_flags & LDLM_FL_DESTROYED);
 		LASSERT(list_empty(&lock->l_res_link));
 		LASSERT(list_empty(&lock->l_pending_chain));
 
@@ -220,8 +218,6 @@
 		lu_ref_fini(&lock->l_reference);
 		OBD_FREE_RCU(lock, sizeof(*lock), &lock->l_handle);
 	}
-
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_lock_put);
 
@@ -253,16 +249,14 @@
 	struct ldlm_namespace *ns = ldlm_lock_to_ns(lock);
 	int rc;
 
-	ENTRY;
-	if (lock->l_ns_srv) {
+	if (lock->l_flags & LDLM_FL_NS_SRV) {
 		LASSERT(list_empty(&lock->l_lru));
-		RETURN(0);
+		return 0;
 	}
 
 	spin_lock(&ns->ns_lock);
 	rc = ldlm_lock_remove_from_lru_nolock(lock);
 	spin_unlock(&ns->ns_lock);
-	EXIT;
 	return rc;
 }
 
@@ -289,11 +283,9 @@
 {
 	struct ldlm_namespace *ns = ldlm_lock_to_ns(lock);
 
-	ENTRY;
 	spin_lock(&ns->ns_lock);
 	ldlm_lock_add_to_lru_nolock(lock);
 	spin_unlock(&ns->ns_lock);
-	EXIT;
 }
 
 /**
@@ -304,10 +296,8 @@
 {
 	struct ldlm_namespace *ns = ldlm_lock_to_ns(lock);
 
-	ENTRY;
-	if (lock->l_ns_srv) {
+	if (lock->l_flags & LDLM_FL_NS_SRV) {
 		LASSERT(list_empty(&lock->l_lru));
-		EXIT;
 		return;
 	}
 
@@ -317,7 +307,6 @@
 		ldlm_lock_add_to_lru_nolock(lock);
 	}
 	spin_unlock(&ns->ns_lock);
-	EXIT;
 }
 
 /**
@@ -341,8 +330,6 @@
  */
 int ldlm_lock_destroy_internal(struct ldlm_lock *lock)
 {
-	ENTRY;
-
 	if (lock->l_readers || lock->l_writers) {
 		LDLM_ERROR(lock, "lock still has references");
 		LBUG();
@@ -353,12 +340,11 @@
 		LBUG();
 	}
 
-	if (lock->l_destroyed) {
+	if (lock->l_flags & LDLM_FL_DESTROYED) {
 		LASSERT(list_empty(&lock->l_lru));
-		EXIT;
 		return 0;
 	}
-	lock->l_destroyed = 1;
+	lock->l_flags |= LDLM_FL_DESTROYED;
 
 	if (lock->l_export && lock->l_export->exp_lock_hash) {
 		/* NB: it's safe to call cfs_hash_del() even lock isn't
@@ -383,7 +369,6 @@
 	if (lock->l_export && lock->l_completion_ast)
 		lock->l_completion_ast(lock, 0);
 #endif
-	EXIT;
 	return 1;
 }
 
@@ -393,7 +378,7 @@
 void ldlm_lock_destroy(struct ldlm_lock *lock)
 {
 	int first;
-	ENTRY;
+
 	lock_res_and_lock(lock);
 	first = ldlm_lock_destroy_internal(lock);
 	unlock_res_and_lock(lock);
@@ -403,7 +388,6 @@
 		lu_ref_del(&lock->l_reference, "hash", lock);
 		LDLM_LOCK_RELEASE(lock);
 	}
-	EXIT;
 }
 
 /**
@@ -412,14 +396,13 @@
 void ldlm_lock_destroy_nolock(struct ldlm_lock *lock)
 {
 	int first;
-	ENTRY;
+
 	first = ldlm_lock_destroy_internal(lock);
 	/* drop reference from hashtable only for first destroy */
 	if (first) {
 		lu_ref_del(&lock->l_reference, "hash", lock);
 		LDLM_LOCK_RELEASE(lock);
 	}
-	EXIT;
 }
 
 /* this is called by portals_handle2object with the handle lock taken */
@@ -450,14 +433,13 @@
 static struct ldlm_lock *ldlm_lock_new(struct ldlm_resource *resource)
 {
 	struct ldlm_lock *lock;
-	ENTRY;
 
 	if (resource == NULL)
 		LBUG();
 
 	OBD_SLAB_ALLOC_PTR_GFP(lock, ldlm_lock_slab, __GFP_IO);
 	if (lock == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	spin_lock_init(&lock->l_lock);
 	lock->l_resource = resource;
@@ -493,7 +475,7 @@
 #endif
 	INIT_LIST_HEAD(&lock->l_exp_list);
 
-	RETURN(lock);
+	return lock;
 }
 
 /**
@@ -507,7 +489,6 @@
 	struct ldlm_resource *oldres = lock->l_resource;
 	struct ldlm_resource *newres;
 	int type;
-	ENTRY;
 
 	LASSERT(ns_is_client(ns));
 
@@ -516,7 +497,7 @@
 		   sizeof(lock->l_resource->lr_name)) == 0) {
 		/* Nothing to do */
 		unlock_res_and_lock(lock);
-		RETURN(0);
+		return 0;
 	}
 
 	LASSERT(new_resid->name[0] != 0);
@@ -529,7 +510,7 @@
 
 	newres = ldlm_resource_get(ns, NULL, new_resid, type, 1);
 	if (newres == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	lu_ref_add(&newres->lr_reference, "lock", lock);
 	/*
@@ -557,7 +538,7 @@
 	lu_ref_del(&oldres->lr_reference, "lock", lock);
 	ldlm_resource_putref(oldres);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_lock_change_resource);
 
@@ -586,19 +567,18 @@
 				     __u64 flags)
 {
 	struct ldlm_lock *lock;
-	ENTRY;
 
 	LASSERT(handle);
 
 	lock = class_handle2object(handle->cookie);
 	if (lock == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	/* It's unlikely but possible that someone marked the lock as
 	 * destroyed after we did handle2object on it */
-	if (flags == 0 && !lock->l_destroyed) {
+	if (flags == 0 && ((lock->l_flags & LDLM_FL_DESTROYED)== 0)) {
 		lu_ref_add(&lock->l_reference, "handle", current);
-		RETURN(lock);
+		return lock;
 	}
 
 	lock_res_and_lock(lock);
@@ -606,24 +586,24 @@
 	LASSERT(lock->l_resource != NULL);
 
 	lu_ref_add_atomic(&lock->l_reference, "handle", current);
-	if (unlikely(lock->l_destroyed)) {
+	if (unlikely(lock->l_flags & LDLM_FL_DESTROYED)) {
 		unlock_res_and_lock(lock);
 		CDEBUG(D_INFO, "lock already destroyed: lock %p\n", lock);
 		LDLM_LOCK_PUT(lock);
-		RETURN(NULL);
+		return NULL;
 	}
 
 	if (flags && (lock->l_flags & flags)) {
 		unlock_res_and_lock(lock);
 		LDLM_LOCK_PUT(lock);
-		RETURN(NULL);
+		return NULL;
 	}
 
 	if (flags)
 		lock->l_flags |= flags;
 
 	unlock_res_and_lock(lock);
-	RETURN(lock);
+	return lock;
 }
 EXPORT_SYMBOL(__ldlm_handle2lock);
 /** @} ldlm_handles */
@@ -695,7 +675,7 @@
 		lock->l_flags |= LDLM_FL_AST_SENT;
 		/* If the enqueuing client said so, tell the AST recipient to
 		 * discard dirty data, rather than writing back. */
-		if (new->l_flags & LDLM_AST_DISCARD_DATA)
+		if (new->l_flags & LDLM_FL_AST_DISCARD_DATA)
 			lock->l_flags |= LDLM_FL_DISCARD_DATA;
 		LASSERT(list_empty(&lock->l_bl_ast));
 		list_add(&lock->l_bl_ast, work_list);
@@ -728,13 +708,11 @@
 void ldlm_add_ast_work_item(struct ldlm_lock *lock, struct ldlm_lock *new,
 			    struct list_head *work_list)
 {
-	ENTRY;
 	check_res_locked(lock->l_resource);
 	if (new)
 		ldlm_add_bl_work_item(lock, new, work_list);
 	else
 		ldlm_add_cp_work_item(lock, work_list);
-	EXIT;
 }
 
 /**
@@ -853,7 +831,6 @@
 void ldlm_lock_decref_internal(struct ldlm_lock *lock, __u32 mode)
 {
 	struct ldlm_namespace *ns;
-	ENTRY;
 
 	lock_res_and_lock(lock);
 
@@ -873,7 +850,7 @@
 	    (lock->l_flags & LDLM_FL_CBPENDING)) {
 		/* If we received a blocked AST and this was the last reference,
 		 * run the callback. */
-		if (lock->l_ns_srv && lock->l_export)
+		if ((lock->l_flags & LDLM_FL_NS_SRV) && lock->l_export)
 			CERROR("FL_CBPENDING set on non-local lock--just a "
 			       "warning\n");
 
@@ -914,8 +891,6 @@
 		LDLM_DEBUG(lock, "do not add lock into lru list");
 		unlock_res_and_lock(lock);
 	}
-
-	EXIT;
 }
 
 /**
@@ -940,7 +915,6 @@
 void ldlm_lock_decref_and_cancel(struct lustre_handle *lockh, __u32 mode)
 {
 	struct ldlm_lock *lock = __ldlm_handle2lock(lockh, 0);
-	ENTRY;
 
 	LASSERT(lock != NULL);
 
@@ -979,7 +953,6 @@
 {
 	struct list_head *tmp;
 	struct ldlm_lock *lock, *mode_end, *policy_end;
-	ENTRY;
 
 	list_for_each(tmp, queue) {
 		lock = list_entry(tmp, struct ldlm_lock, l_res_link);
@@ -999,7 +972,6 @@
 			prev->res_link = &mode_end->l_res_link;
 			prev->mode_link = &mode_end->l_sl_mode;
 			prev->policy_link = &req->l_sl_policy;
-			EXIT;
 			return;
 		} else if (lock->l_resource->lr_type == LDLM_IBITS) {
 			for (;;) {
@@ -1018,7 +990,6 @@
 						&policy_end->l_sl_mode;
 					prev->policy_link =
 						&policy_end->l_sl_policy;
-					EXIT;
 					return;
 				}
 
@@ -1037,7 +1008,6 @@
 			prev->res_link = &mode_end->l_res_link;
 			prev->mode_link = &mode_end->l_sl_mode;
 			prev->policy_link = &req->l_sl_policy;
-			EXIT;
 			return;
 		} else {
 			LDLM_ERROR(lock,"is not LDLM_PLAIN or LDLM_IBITS lock");
@@ -1050,7 +1020,6 @@
 	prev->res_link = queue->prev;
 	prev->mode_link = &req->l_sl_mode;
 	prev->policy_link = &req->l_sl_policy;
-	EXIT;
 	return;
 }
 
@@ -1062,14 +1031,13 @@
 				       struct sl_insert_point *prev)
 {
 	struct ldlm_resource *res = lock->l_resource;
-	ENTRY;
 
 	check_res_locked(res);
 
 	ldlm_resource_dump(D_INFO, res);
 	LDLM_DEBUG(lock, "About to add lock:");
 
-	if (lock->l_destroyed) {
+	if (lock->l_flags & LDLM_FL_DESTROYED) {
 		CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
 		return;
 	}
@@ -1088,8 +1056,6 @@
 		list_add(&lock->l_sl_mode, prev->mode_link);
 	if (&lock->l_sl_policy != prev->policy_link)
 		list_add(&lock->l_sl_policy, prev->policy_link);
-
-	EXIT;
 }
 
 /**
@@ -1099,13 +1065,11 @@
 static void ldlm_grant_lock_with_skiplist(struct ldlm_lock *lock)
 {
 	struct sl_insert_point prev;
-	ENTRY;
 
 	LASSERT(lock->l_req_mode == lock->l_granted_mode);
 
 	search_granted_lock(&lock->l_resource->lr_granted, lock, &prev);
 	ldlm_granted_list_add_lock(lock, &prev);
-	EXIT;
 }
 
 /**
@@ -1122,7 +1086,6 @@
 void ldlm_grant_lock(struct ldlm_lock *lock, struct list_head *work_list)
 {
 	struct ldlm_resource *res = lock->l_resource;
-	ENTRY;
 
 	check_res_locked(res);
 
@@ -1141,7 +1104,6 @@
 		ldlm_add_ast_work_item(lock, NULL, work_list);
 
 	ldlm_pool_add(&ldlm_res_to_ns(res)->ns_pool, lock);
-	EXIT;
 }
 
 /**
@@ -1203,9 +1165,7 @@
 		      policy->l_inodebits.bits))
 			continue;
 
-		if (!unref &&
-		    (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED ||
-		     lock->l_failed))
+		if (!unref && (lock->l_flags & LDLM_FL_GONE_MASK))
 			continue;
 
 		if ((flags & LDLM_FL_LOCAL_ONLY) &&
@@ -1227,8 +1187,8 @@
 
 void ldlm_lock_fail_match_locked(struct ldlm_lock *lock)
 {
-	if (!lock->l_failed) {
-		lock->l_failed = 1;
+	if ((lock->l_flags & LDLM_FL_FAIL_NOTIFIED) == 0) {
+		lock->l_flags |= LDLM_FL_FAIL_NOTIFIED;
 		wake_up_all(&lock->l_waitq);
 	}
 }
@@ -1306,7 +1266,6 @@
 	struct ldlm_resource *res;
 	struct ldlm_lock *lock, *old_lock = NULL;
 	int rc = 0;
-	ENTRY;
 
 	if (ns == NULL) {
 		old_lock = ldlm_handle2lock(lockh);
@@ -1321,7 +1280,7 @@
 	res = ldlm_resource_get(ns, NULL, res_id, type, 0);
 	if (res == NULL) {
 		LASSERT(old_lock == NULL);
-		RETURN(0);
+		return 0;
 	}
 
 	LDLM_RESOURCE_ADDREF(res);
@@ -1342,7 +1301,6 @@
 	if (lock != NULL)
 		GOTO(out, rc = 1);
 
-	EXIT;
  out:
 	unlock_res(res);
 	LDLM_RESOURCE_DELREF(res);
@@ -1352,6 +1310,8 @@
 		ldlm_lock2handle(lock, lockh);
 		if ((flags & LDLM_FL_LVB_READY) &&
 		    (!(lock->l_flags & LDLM_FL_LVB_READY))) {
+			__u64 wait_flags = LDLM_FL_LVB_READY |
+				LDLM_FL_DESTROYED | LDLM_FL_FAIL_NOTIFIED;
 			struct l_wait_info lwi;
 			if (lock->l_completion_ast) {
 				int err = lock->l_completion_ast(lock,
@@ -1373,8 +1333,7 @@
 
 			/* XXX FIXME see comment on CAN_MATCH in lustre_dlm.h */
 			l_wait_event(lock->l_waitq,
-				     lock->l_flags & LDLM_FL_LVB_READY ||
-				     lock->l_destroyed || lock->l_failed,
+				     lock->l_flags & wait_flags,
 				     &lwi);
 			if (!(lock->l_flags & LDLM_FL_LVB_READY)) {
 				if (flags & LDLM_FL_TEST_LOCK)
@@ -1426,13 +1385,11 @@
 {
 	struct ldlm_lock *lock;
 	ldlm_mode_t mode = 0;
-	ENTRY;
 
 	lock = ldlm_handle2lock(lockh);
 	if (lock != NULL) {
 		lock_res_and_lock(lock);
-		if (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED ||
-		    lock->l_failed)
+		if (lock->l_flags & LDLM_FL_GONE_MASK)
 			GOTO(out, mode);
 
 		if (lock->l_flags & LDLM_FL_CBPENDING &&
@@ -1445,8 +1402,6 @@
 		ldlm_lock_addref_internal_nolock(lock, mode);
 	}
 
-	EXIT;
-
 out:
 	if (lock != NULL) {
 		unlock_res_and_lock(lock);
@@ -1461,7 +1416,6 @@
 		  enum req_location loc, void *data, int size)
 {
 	void *lvb;
-	ENTRY;
 
 	LASSERT(data != NULL);
 	LASSERT(size >= 0);
@@ -1479,7 +1433,7 @@
 						lustre_swab_ost_lvb);
 			if (unlikely(lvb == NULL)) {
 				LDLM_ERROR(lock, "no LVB");
-				RETURN(-EPROTO);
+				return -EPROTO;
 			}
 
 			memcpy(data, lvb, size);
@@ -1496,7 +1450,7 @@
 						lustre_swab_ost_lvb_v1);
 			if (unlikely(lvb == NULL)) {
 				LDLM_ERROR(lock, "no LVB");
-				RETURN(-EPROTO);
+				return -EPROTO;
 			}
 
 			memcpy(data, lvb, size);
@@ -1506,7 +1460,7 @@
 		} else {
 			LDLM_ERROR(lock, "Replied unexpected ost LVB size %d",
 				   size);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		break;
 	case LVB_T_LQUOTA:
@@ -1521,14 +1475,14 @@
 						lustre_swab_lquota_lvb);
 			if (unlikely(lvb == NULL)) {
 				LDLM_ERROR(lock, "no LVB");
-				RETURN(-EPROTO);
+				return -EPROTO;
 			}
 
 			memcpy(data, lvb, size);
 		} else {
 			LDLM_ERROR(lock, "Replied unexpected lquota LVB size %d",
 				   size);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		break;
 	case LVB_T_LAYOUT:
@@ -1541,18 +1495,18 @@
 			lvb = req_capsule_server_get(pill, &RMF_DLM_LVB);
 		if (unlikely(lvb == NULL)) {
 			LDLM_ERROR(lock, "no LVB");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		memcpy(data, lvb, size);
 		break;
 	default:
 		LDLM_ERROR(lock, "Unknown LVB type: %d\n", lock->l_lvb_type);
-		libcfs_debug_dumpstack(NULL);
-		RETURN(-EINVAL);
+		dump_stack();
+		return -EINVAL;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1569,26 +1523,25 @@
 {
 	struct ldlm_lock *lock;
 	struct ldlm_resource *res;
-	ENTRY;
 
 	res = ldlm_resource_get(ns, NULL, res_id, type, 1);
 	if (res == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	lock = ldlm_lock_new(res);
 
 	if (lock == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	lock->l_req_mode = mode;
 	lock->l_ast_data = data;
 	lock->l_pid = current_pid();
-	lock->l_ns_srv = !!ns_is_server(ns);
+	if (ns_is_server(ns))
+		lock->l_flags |= LDLM_FL_NS_SRV;
 	if (cbs) {
 		lock->l_blocking_ast = cbs->lcs_blocking;
 		lock->l_completion_ast = cbs->lcs_completion;
 		lock->l_glimpse_ast = cbs->lcs_glimpse;
-		lock->l_weigh_ast = cbs->lcs_weigh;
 	}
 
 	lock->l_tree_node = NULL;
@@ -1609,7 +1562,7 @@
 	if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_NEW_LOCK))
 		GOTO(out, 0);
 
-	RETURN(lock);
+	return lock;
 
 out:
 	ldlm_lock_destroy(lock);
@@ -1636,7 +1589,6 @@
 	int local = ns_is_client(ldlm_res_to_ns(res));
 	ldlm_error_t rc = ELDLM_OK;
 	struct ldlm_interval *node = NULL;
-	ENTRY;
 
 	lock->l_last_activity = cfs_time_current_sec();
 	/* policies are not executed on the client or during replay */
@@ -1654,11 +1606,11 @@
 				LDLM_LOCK_RELEASE(lock);
 			}
 			*flags |= LDLM_FL_LOCK_CHANGED;
-			RETURN(0);
+			return 0;
 		} else if (rc != ELDLM_OK ||
 			   (rc == ELDLM_OK && (*flags & LDLM_FL_INTENT_ONLY))) {
 			ldlm_lock_destroy(lock);
-			RETURN(rc);
+			return rc;
 		}
 	}
 
@@ -1693,7 +1645,7 @@
 
 	/* Some flags from the enqueue want to make it into the AST, via the
 	 * lock's l_flags. */
-	lock->l_flags |= *flags & LDLM_AST_DISCARD_DATA;
+	lock->l_flags |= *flags & LDLM_FL_AST_DISCARD_DATA;
 
 	/* This distinction between local lock trees is very important; a client
 	 * namespace only has information about locks taken by that client, and
@@ -1738,10 +1690,9 @@
 	struct ldlm_lock_desc   d;
 	int		     rc;
 	struct ldlm_lock       *lock;
-	ENTRY;
 
 	if (list_empty(arg->list))
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	lock = list_entry(arg->list->next, struct ldlm_lock, l_bl_ast);
 
@@ -1762,7 +1713,7 @@
 	lock->l_blocking_lock = NULL;
 	LDLM_LOCK_RELEASE(lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1775,10 +1726,9 @@
 	int		      rc = 0;
 	struct ldlm_lock	*lock;
 	ldlm_completion_callback completion_callback;
-	ENTRY;
 
 	if (list_empty(arg->list))
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	lock = list_entry(arg->list->next, struct ldlm_lock, l_cp_ast);
 
@@ -1807,7 +1757,7 @@
 		rc = completion_callback(lock, 0, (void *)arg);
 	LDLM_LOCK_RELEASE(lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1820,10 +1770,9 @@
 	struct ldlm_lock_desc   desc;
 	int		     rc;
 	struct ldlm_lock       *lock;
-	ENTRY;
 
 	if (list_empty(arg->list))
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	lock = list_entry(arg->list->next, struct ldlm_lock, l_rk_ast);
 	list_del_init(&lock->l_rk_ast);
@@ -1836,7 +1785,7 @@
 	rc = lock->l_blocking_ast(lock, &desc, (void*)arg, LDLM_CB_BLOCKING);
 	LDLM_LOCK_RELEASE(lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1848,10 +1797,9 @@
 	struct ldlm_glimpse_work	*gl_work;
 	struct ldlm_lock		*lock;
 	int				 rc = 0;
-	ENTRY;
 
 	if (list_empty(arg->list))
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	gl_work = list_entry(arg->list->next, struct ldlm_glimpse_work,
 				 gl_list);
@@ -1871,7 +1819,7 @@
 	if ((gl_work->gl_flags & LDLM_GL_WORK_NOFREE) == 0)
 		OBD_FREE_PTR(gl_work);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1888,11 +1836,11 @@
 	int		     rc;
 
 	if (list_empty(rpc_list))
-		RETURN(0);
+		return 0;
 
 	OBD_ALLOC_PTR(arg);
 	if (arg == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	atomic_set(&arg->restart, 0);
 	arg->list = rpc_list;
@@ -1960,13 +1908,10 @@
  */
 void ldlm_reprocess_all_ns(struct ldlm_namespace *ns)
 {
-	ENTRY;
-
 	if (ns != NULL) {
 		cfs_hash_for_each_nolock(ns->ns_rs_hash,
 					 ldlm_reprocess_res, NULL);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_reprocess_all_ns);
 
@@ -1982,13 +1927,11 @@
 {
 	LIST_HEAD(rpc_list);
 
-	ENTRY;
 	if (!ns_is_client(ldlm_res_to_ns(res))) {
 		CERROR("This is client-side-only module, cannot handle "
 		       "LDLM_NAMESPACE_SERVER resource type lock.\n");
 		LBUG();
 	}
-	EXIT;
 }
 
 /**
@@ -2032,7 +1975,6 @@
 {
 	struct ldlm_resource *res;
 	struct ldlm_namespace *ns;
-	ENTRY;
 
 	lock_res_and_lock(lock);
 
@@ -2046,15 +1988,15 @@
 		LBUG();
 	}
 
-	if (lock->l_waited)
+	if (lock->l_flags & LDLM_FL_WAITED)
 		ldlm_del_waiting_lock(lock);
 
 	/* Releases cancel callback. */
 	ldlm_cancel_callback(lock);
 
 	/* Yes, second time, just in case it was added again while we were
-	   running with no res lock in ldlm_cancel_callback */
-	if (lock->l_waited)
+	 * running with no res lock in ldlm_cancel_callback */
+	if (lock->l_flags & LDLM_FL_WAITED)
 		ldlm_del_waiting_lock(lock);
 
 	ldlm_resource_unlink_lock(lock);
@@ -2067,8 +2009,6 @@
 	 * if not to zero out lock->l_granted_mode */
 	lock->l_granted_mode = LCK_MINMODE;
 	unlock_res_and_lock(lock);
-
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_lock_cancel);
 
@@ -2079,7 +2019,6 @@
 {
 	struct ldlm_lock *lock = ldlm_handle2lock(lockh);
 	int rc = -EINVAL;
-	ENTRY;
 
 	if (lock) {
 		if (lock->l_ast_data == NULL)
@@ -2088,7 +2027,7 @@
 			rc = 0;
 		LDLM_LOCK_PUT(lock);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_lock_set_data);
 
@@ -2160,8 +2099,6 @@
  */
 void ldlm_lock_downgrade(struct ldlm_lock *lock, int new_mode)
 {
-	ENTRY;
-
 	LASSERT(lock->l_granted_mode & (LCK_PW | LCK_EX));
 	LASSERT(new_mode == LCK_COS);
 
@@ -2177,8 +2114,6 @@
 	ldlm_grant_lock(lock, NULL);
 	unlock_res_and_lock(lock);
 	ldlm_reprocess_all(lock->l_resource);
-
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_lock_downgrade);
 
@@ -2197,19 +2132,19 @@
 	struct ldlm_namespace *ns;
 	int granted = 0;
 	struct ldlm_interval *node;
-	ENTRY;
 
 	/* Just return if mode is unchanged. */
 	if (new_mode == lock->l_granted_mode) {
 		*flags |= LDLM_FL_BLOCK_GRANTED;
-		RETURN(lock->l_resource);
+		return lock->l_resource;
 	}
 
 	/* I can't check the type of lock here because the bitlock of lock
 	 * is not held here, so do the allocation blindly. -jay */
 	OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, __GFP_IO);
-	if (node == NULL)  /* Actually, this causes EDEADLOCK to be returned */
-		RETURN(NULL);
+	if (node == NULL)
+		/* Actually, this causes EDEADLOCK to be returned */
+		return NULL;
 
 	LASSERTF((new_mode == LCK_PW && lock->l_granted_mode == LCK_PR),
 		 "new_mode %u, granted %u\n", new_mode, lock->l_granted_mode);
@@ -2268,7 +2203,7 @@
 		ldlm_run_ast_work(ns, &rpc_list, LDLM_WORK_CP_AST);
 	if (node)
 		OBD_SLAB_FREE(node, ldlm_interval_slab, sizeof(*node));
-	RETURN(res);
+	return res;
 }
 EXPORT_SYMBOL(ldlm_lock_convert);
 
@@ -2337,91 +2272,90 @@
 	switch (resource->lr_type) {
 	case LDLM_EXTENT:
 		libcfs_debug_vmsg2(msgdata, fmt, args,
-		       " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
-		       "res: "LPU64"/"LPU64" rrc: %d type: %s ["LPU64"->"LPU64
-		       "] (req "LPU64"->"LPU64") flags: "LPX64" nid: %s remote:"
-		       " "LPX64" expref: %d pid: %u timeout: %lu lvb_type: %d\n",
-		       ldlm_lock_to_ns_name(lock), lock,
-		       lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
-		       lock->l_readers, lock->l_writers,
-		       ldlm_lockname[lock->l_granted_mode],
-		       ldlm_lockname[lock->l_req_mode],
-		       resource->lr_name.name[0],
-		       resource->lr_name.name[1],
-		       atomic_read(&resource->lr_refcount),
-		       ldlm_typename[resource->lr_type],
-		       lock->l_policy_data.l_extent.start,
-		       lock->l_policy_data.l_extent.end,
-		       lock->l_req_extent.start, lock->l_req_extent.end,
-		       lock->l_flags, nid, lock->l_remote_handle.cookie,
-		       exp ? atomic_read(&exp->exp_refcount) : -99,
-		       lock->l_pid, lock->l_callback_timeout, lock->l_lvb_type);
+			" ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+			"res: "DLDLMRES" rrc: %d type: %s ["LPU64"->"LPU64"] "
+			"(req "LPU64"->"LPU64") flags: "LPX64" nid: %s remote: "
+			LPX64" expref: %d pid: %u timeout: %lu lvb_type: %d\n",
+			ldlm_lock_to_ns_name(lock), lock,
+			lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
+			lock->l_readers, lock->l_writers,
+			ldlm_lockname[lock->l_granted_mode],
+			ldlm_lockname[lock->l_req_mode],
+			PLDLMRES(resource),
+			atomic_read(&resource->lr_refcount),
+			ldlm_typename[resource->lr_type],
+			lock->l_policy_data.l_extent.start,
+			lock->l_policy_data.l_extent.end,
+			lock->l_req_extent.start, lock->l_req_extent.end,
+			lock->l_flags, nid, lock->l_remote_handle.cookie,
+			exp ? atomic_read(&exp->exp_refcount) : -99,
+			lock->l_pid, lock->l_callback_timeout,
+			lock->l_lvb_type);
 		break;
 
 	case LDLM_FLOCK:
 		libcfs_debug_vmsg2(msgdata, fmt, args,
-		       " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
-		       "res: "LPU64"/"LPU64" rrc: %d type: %s pid: %d "
-		       "["LPU64"->"LPU64"] flags: "LPX64" nid: %s remote: "LPX64
-		       " expref: %d pid: %u timeout: %lu\n",
-		       ldlm_lock_to_ns_name(lock), lock,
-		       lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
-		       lock->l_readers, lock->l_writers,
-		       ldlm_lockname[lock->l_granted_mode],
-		       ldlm_lockname[lock->l_req_mode],
-		       resource->lr_name.name[0],
-		       resource->lr_name.name[1],
-		       atomic_read(&resource->lr_refcount),
-		       ldlm_typename[resource->lr_type],
-		       lock->l_policy_data.l_flock.pid,
-		       lock->l_policy_data.l_flock.start,
-		       lock->l_policy_data.l_flock.end,
-		       lock->l_flags, nid, lock->l_remote_handle.cookie,
-		       exp ? atomic_read(&exp->exp_refcount) : -99,
-		       lock->l_pid, lock->l_callback_timeout);
+			" ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+			"res: "DLDLMRES" rrc: %d type: %s pid: %d "
+			"["LPU64"->"LPU64"] flags: "LPX64" nid: %s "
+			"remote: "LPX64" expref: %d pid: %u timeout: %lu\n",
+			ldlm_lock_to_ns_name(lock), lock,
+			lock->l_handle.h_cookie, atomic_read(&lock->l_refc),
+			lock->l_readers, lock->l_writers,
+			ldlm_lockname[lock->l_granted_mode],
+			ldlm_lockname[lock->l_req_mode],
+			PLDLMRES(resource),
+			atomic_read(&resource->lr_refcount),
+			ldlm_typename[resource->lr_type],
+			lock->l_policy_data.l_flock.pid,
+			lock->l_policy_data.l_flock.start,
+			lock->l_policy_data.l_flock.end,
+			lock->l_flags, nid, lock->l_remote_handle.cookie,
+			exp ? atomic_read(&exp->exp_refcount) : -99,
+			lock->l_pid, lock->l_callback_timeout);
 		break;
 
 	case LDLM_IBITS:
 		libcfs_debug_vmsg2(msgdata, fmt, args,
-		       " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
-		       "res: "LPU64"/"LPU64" bits "LPX64" rrc: %d type: %s "
-		       "flags: "LPX64" nid: %s remote: "LPX64" expref: %d "
-		       "pid: %u timeout: %lu lvb_type: %d\n",
-		       ldlm_lock_to_ns_name(lock),
-		       lock, lock->l_handle.h_cookie,
-		       atomic_read (&lock->l_refc),
-		       lock->l_readers, lock->l_writers,
-		       ldlm_lockname[lock->l_granted_mode],
-		       ldlm_lockname[lock->l_req_mode],
-		       resource->lr_name.name[0],
-		       resource->lr_name.name[1],
-		       lock->l_policy_data.l_inodebits.bits,
-		       atomic_read(&resource->lr_refcount),
-		       ldlm_typename[resource->lr_type],
-		       lock->l_flags, nid, lock->l_remote_handle.cookie,
-		       exp ? atomic_read(&exp->exp_refcount) : -99,
-		       lock->l_pid, lock->l_callback_timeout, lock->l_lvb_type);
+			" ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+			"res: "DLDLMRES" bits "LPX64" rrc: %d type: %s "
+			"flags: "LPX64" nid: %s remote: "LPX64" expref: %d "
+			"pid: %u timeout: %lu lvb_type: %d\n",
+			ldlm_lock_to_ns_name(lock),
+			lock, lock->l_handle.h_cookie,
+			atomic_read(&lock->l_refc),
+			lock->l_readers, lock->l_writers,
+			ldlm_lockname[lock->l_granted_mode],
+			ldlm_lockname[lock->l_req_mode],
+			PLDLMRES(resource),
+			lock->l_policy_data.l_inodebits.bits,
+			atomic_read(&resource->lr_refcount),
+			ldlm_typename[resource->lr_type],
+			lock->l_flags, nid, lock->l_remote_handle.cookie,
+			exp ? atomic_read(&exp->exp_refcount) : -99,
+			lock->l_pid, lock->l_callback_timeout,
+			lock->l_lvb_type);
 		break;
 
 	default:
 		libcfs_debug_vmsg2(msgdata, fmt, args,
-		       " ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
-		       "res: "LPU64"/"LPU64" rrc: %d type: %s flags: "LPX64" "
-		       "nid: %s remote: "LPX64" expref: %d pid: %u timeout: %lu"
-		       "lvb_type: %d\n",
-		       ldlm_lock_to_ns_name(lock),
-		       lock, lock->l_handle.h_cookie,
-		       atomic_read (&lock->l_refc),
-		       lock->l_readers, lock->l_writers,
-		       ldlm_lockname[lock->l_granted_mode],
-		       ldlm_lockname[lock->l_req_mode],
-		       resource->lr_name.name[0],
-		       resource->lr_name.name[1],
-		       atomic_read(&resource->lr_refcount),
-		       ldlm_typename[resource->lr_type],
-		       lock->l_flags, nid, lock->l_remote_handle.cookie,
-		       exp ? atomic_read(&exp->exp_refcount) : -99,
-		       lock->l_pid, lock->l_callback_timeout, lock->l_lvb_type);
+			" ns: %s lock: %p/"LPX64" lrc: %d/%d,%d mode: %s/%s "
+			"res: "DLDLMRES" rrc: %d type: %s flags: "LPX64" "
+			"nid: %s remote: "LPX64" expref: %d pid: %u "
+			"timeout: %lu lvb_type: %d\n",
+			ldlm_lock_to_ns_name(lock),
+			lock, lock->l_handle.h_cookie,
+			atomic_read(&lock->l_refc),
+			lock->l_readers, lock->l_writers,
+			ldlm_lockname[lock->l_granted_mode],
+			ldlm_lockname[lock->l_req_mode],
+			PLDLMRES(resource),
+			atomic_read(&resource->lr_refcount),
+			ldlm_typename[resource->lr_type],
+			lock->l_flags, nid, lock->l_remote_handle.cookie,
+			exp ? atomic_read(&exp->exp_refcount) : -99,
+			lock->l_pid, lock->l_callback_timeout,
+			lock->l_lvb_type);
 		break;
 	}
 	va_end(args);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
index 324d5e4..3916bda 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c
@@ -127,12 +127,12 @@
 
 int ldlm_del_waiting_lock(struct ldlm_lock *lock)
 {
-	RETURN(0);
+	return 0;
 }
 
 int ldlm_refresh_waiting_lock(struct ldlm_lock *lock, int timeout)
 {
-	RETURN(0);
+	return 0;
 }
 
 
@@ -146,7 +146,6 @@
 			     struct ldlm_lock_desc *ld, struct ldlm_lock *lock)
 {
 	int do_ast;
-	ENTRY;
 
 	LDLM_DEBUG(lock, "client blocking AST callback handler");
 
@@ -172,7 +171,6 @@
 
 	LDLM_DEBUG(lock, "client blocking callback handler END");
 	LDLM_LOCK_RELEASE(lock);
-	EXIT;
 }
 
 /**
@@ -188,7 +186,6 @@
 	int lvb_len;
 	LIST_HEAD(ast_list);
 	int rc = 0;
-	ENTRY;
 
 	LDLM_DEBUG(lock, "client completion callback handler START");
 
@@ -198,7 +195,7 @@
 			schedule_timeout_and_set_state(
 				TASK_INTERRUPTIBLE, to);
 			if (lock->l_granted_mode == lock->l_req_mode ||
-			    lock->l_destroyed)
+			    lock->l_flags & LDLM_FL_DESTROYED)
 				break;
 		}
 	}
@@ -238,7 +235,7 @@
 	}
 
 	lock_res_and_lock(lock);
-	if (lock->l_destroyed ||
+	if ((lock->l_flags & LDLM_FL_DESTROYED) ||
 	    lock->l_granted_mode == lock->l_req_mode) {
 		/* bug 11300: the lock has already been granted */
 		unlock_res_and_lock(lock);
@@ -332,7 +329,6 @@
 				    struct ldlm_lock *lock)
 {
 	int rc = -ENOSYS;
-	ENTRY;
 
 	LDLM_DEBUG(lock, "client glimpse AST callback handler");
 
@@ -356,12 +352,10 @@
 		if (ldlm_bl_to_thread_lock(ns, NULL, lock))
 			ldlm_handle_bl_callback(ns, NULL, lock);
 
-		EXIT;
 		return;
 	}
 	unlock_res_and_lock(lock);
 	LDLM_LOCK_RELEASE(lock);
-	EXIT;
 }
 
 static int ldlm_callback_reply(struct ptlrpc_request *req, int rc)
@@ -382,7 +376,6 @@
 			       ldlm_cancel_flags_t cancel_flags)
 {
 	struct ldlm_bl_pool *blp = ldlm_state->ldlm_bl_pool;
-	ENTRY;
 
 	spin_lock(&blp->blp_lock);
 	if (blwi->blwi_lock &&
@@ -402,7 +395,7 @@
 	if (!(cancel_flags & LCF_ASYNC))
 		wait_for_completion(&blwi->blwi_comp);
 
-	RETURN(0);
+	return 0;
 }
 
 static inline void init_blwi(struct ldlm_bl_work_item *blwi,
@@ -446,20 +439,18 @@
 			     struct list_head *cancels, int count,
 			     ldlm_cancel_flags_t cancel_flags)
 {
-	ENTRY;
-
 	if (cancels && count == 0)
-		RETURN(0);
+		return 0;
 
 	if (cancel_flags & LCF_ASYNC) {
 		struct ldlm_bl_work_item *blwi;
 
 		OBD_ALLOC(blwi, sizeof(*blwi));
 		if (blwi == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		init_blwi(blwi, ns, ld, cancels, count, lock, cancel_flags);
 
-		RETURN(__ldlm_bl_to_thread(blwi, cancel_flags));
+		return __ldlm_bl_to_thread(blwi, cancel_flags);
 	} else {
 		/* if it is synchronous call do minimum mem alloc, as it could
 		 * be triggered from kernel shrinker
@@ -468,7 +459,7 @@
 
 		memset(&blwi, 0, sizeof(blwi));
 		init_blwi(&blwi, ns, ld, cancels, count, lock, cancel_flags);
-		RETURN(__ldlm_bl_to_thread(&blwi, cancel_flags));
+		return __ldlm_bl_to_thread(&blwi, cancel_flags);
 	}
 }
 
@@ -494,7 +485,6 @@
 	void *val;
 	int keylen, vallen;
 	int rc = -ENOSYS;
-	ENTRY;
 
 	DEBUG_REQ(D_HSM, req, "%s: handle setinfo\n", obd->obd_name);
 
@@ -503,14 +493,14 @@
 	key = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
 	if (key == NULL) {
 		DEBUG_REQ(D_IOCTL, req, "no set_info key");
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 	keylen = req_capsule_get_size(&req->rq_pill, &RMF_SETINFO_KEY,
 				      RCL_CLIENT);
 	val = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_VAL);
 	if (val == NULL) {
 		DEBUG_REQ(D_IOCTL, req, "no set_info val");
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 	vallen = req_capsule_get_size(&req->rq_pill, &RMF_SETINFO_VAL,
 				      RCL_CLIENT);
@@ -552,9 +542,11 @@
 	oqctl = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
 	if (oqctl == NULL) {
 		CERROR("Can't unpack obd_quotactl\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
+	oqctl->qc_stat = ptlrpc_status_ntoh(oqctl->qc_stat);
+
 	cli->cl_qchk_stat = oqctl->qc_stat;
 	return 0;
 }
@@ -566,7 +558,6 @@
 	struct ldlm_request *dlm_req;
 	struct ldlm_lock *lock;
 	int rc;
-	ENTRY;
 
 	/* Requests arrive in sender's byte order.  The ptlrpc service
 	 * handler has already checked and, if necessary, byte-swapped the
@@ -575,7 +566,7 @@
 
 	/* do nothing for sec context finalize */
 	if (lustre_msg_get_opc(req->rq_reqmsg) == SEC_CTX_FINI)
-		RETURN(0);
+		return 0;
 
 	req_capsule_init(&req->rq_pill, req, RCL_SERVER);
 
@@ -583,7 +574,7 @@
 		rc = ldlm_callback_reply(req, -ENOTCONN);
 		ldlm_callback_errmsg(req, "Operate on unconnected server",
 				     rc, NULL);
-		RETURN(0);
+		return 0;
 	}
 
 	LASSERT(req->rq_export != NULL);
@@ -592,71 +583,71 @@
 	switch (lustre_msg_get_opc(req->rq_reqmsg)) {
 	case LDLM_BL_CALLBACK:
 		if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_BL_CALLBACK_NET))
-			RETURN(0);
+			return 0;
 		break;
 	case LDLM_CP_CALLBACK:
 		if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CP_CALLBACK_NET))
-			RETURN(0);
+			return 0;
 		break;
 	case LDLM_GL_CALLBACK:
 		if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_GL_CALLBACK_NET))
-			RETURN(0);
+			return 0;
 		break;
 	case LDLM_SET_INFO:
 		rc = ldlm_handle_setinfo(req);
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	case OBD_LOG_CANCEL: /* remove this eventually - for 1.4.0 compat */
 		CERROR("shouldn't be handling OBD_LOG_CANCEL on DLM thread\n");
 		req_capsule_set(&req->rq_pill, &RQF_LOG_CANCEL);
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOG_CANCEL_NET))
-			RETURN(0);
+			return 0;
 		rc = llog_origin_handle_cancel(req);
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOG_CANCEL_REP))
-			RETURN(0);
+			return 0;
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	case LLOG_ORIGIN_HANDLE_CREATE:
 		req_capsule_set(&req->rq_pill, &RQF_LLOG_ORIGIN_HANDLE_CREATE);
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
-			RETURN(0);
+			return 0;
 		rc = llog_origin_handle_open(req);
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	case LLOG_ORIGIN_HANDLE_NEXT_BLOCK:
 		req_capsule_set(&req->rq_pill,
 				&RQF_LLOG_ORIGIN_HANDLE_NEXT_BLOCK);
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
-			RETURN(0);
+			return 0;
 		rc = llog_origin_handle_next_block(req);
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	case LLOG_ORIGIN_HANDLE_READ_HEADER:
 		req_capsule_set(&req->rq_pill,
 				&RQF_LLOG_ORIGIN_HANDLE_READ_HEADER);
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
-			RETURN(0);
+			return 0;
 		rc = llog_origin_handle_read_header(req);
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	case LLOG_ORIGIN_HANDLE_CLOSE:
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_LOGD_NET))
-			RETURN(0);
+			return 0;
 		rc = llog_origin_handle_close(req);
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	case OBD_QC_CALLBACK:
 		req_capsule_set(&req->rq_pill, &RQF_QC_CALLBACK);
 		if (OBD_FAIL_CHECK(OBD_FAIL_OBD_QC_CALLBACK_NET))
-			RETURN(0);
+			return 0;
 		rc = ldlm_handle_qc_callback(req);
 		ldlm_callback_reply(req, rc);
-		RETURN(0);
+		return 0;
 	default:
 		CERROR("unknown opcode %u\n",
 		       lustre_msg_get_opc(req->rq_reqmsg));
 		ldlm_callback_reply(req, -EPROTO);
-		RETURN(0);
+		return 0;
 	}
 
 	ns = req->rq_export->exp_obd->obd_namespace;
@@ -669,7 +660,7 @@
 		rc = ldlm_callback_reply(req, -EPROTO);
 		ldlm_callback_errmsg(req, "Operate without parameter", rc,
 				     NULL);
-		RETURN(0);
+		return 0;
 	}
 
 	/* Force a known safe race, send a cancel to the server for a lock
@@ -688,7 +679,7 @@
 		rc = ldlm_callback_reply(req, -EINVAL);
 		ldlm_callback_errmsg(req, "Operate with invalid parameter", rc,
 				     &dlm_req->lock_handle[0]);
-		RETURN(0);
+		return 0;
 	}
 
 	if ((lock->l_flags & LDLM_FL_FAIL_LOC) &&
@@ -715,7 +706,7 @@
 			rc = ldlm_callback_reply(req, -EINVAL);
 			ldlm_callback_errmsg(req, "Operate on stale lock", rc,
 					     &dlm_req->lock_handle[0]);
-			RETURN(0);
+			return 0;
 		}
 		/* BL_AST locks are not needed in LRU.
 		 * Let ldlm_cancel_lru() be fast. */
@@ -761,7 +752,7 @@
 		LBUG();			 /* checked above */
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 
@@ -805,7 +796,7 @@
 static int ldlm_bl_thread_start(struct ldlm_bl_pool *blp)
 {
 	struct ldlm_bl_thread_data bltd = { .bltd_blp = blp };
-	task_t *task;
+	struct task_struct *task;
 
 	init_completion(&bltd.bltd_comp);
 	bltd.bltd_num = atomic_read(&blp->blp_num_threads);
@@ -832,7 +823,6 @@
 static int ldlm_bl_thread_main(void *arg)
 {
 	struct ldlm_bl_pool *blp;
-	ENTRY;
 
 	{
 		struct ldlm_bl_thread_data *bltd = arg;
@@ -904,7 +894,7 @@
 	atomic_dec(&blp->blp_busy_threads);
 	atomic_dec(&blp->blp_num_threads);
 	complete(&blp->blp_comp);
-	RETURN(0);
+	return 0;
 }
 
 
@@ -914,7 +904,7 @@
 int ldlm_get_ref(void)
 {
 	int rc = 0;
-	ENTRY;
+
 	mutex_lock(&ldlm_ref_mutex);
 	if (++ldlm_refcount == 1) {
 		rc = ldlm_setup();
@@ -923,13 +913,12 @@
 	}
 	mutex_unlock(&ldlm_ref_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_get_ref);
 
 void ldlm_put_ref(void)
 {
-	ENTRY;
 	mutex_lock(&ldlm_ref_mutex);
 	if (ldlm_refcount == 1) {
 		int rc = ldlm_cleanup();
@@ -941,8 +930,6 @@
 		ldlm_refcount--;
 	}
 	mutex_unlock(&ldlm_ref_mutex);
-
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_put_ref);
 
@@ -1016,8 +1003,6 @@
 
 int ldlm_init_export(struct obd_export *exp)
 {
-	ENTRY;
-
 	exp->exp_lock_hash =
 		cfs_hash_create(obd_uuid2str(&exp->exp_client_uuid),
 				HASH_EXP_LOCK_CUR_BITS,
@@ -1029,20 +1014,18 @@
 				CFS_HASH_NBLK_CHANGE);
 
 	if (!exp->exp_lock_hash)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_init_export);
 
 void ldlm_destroy_export(struct obd_export *exp)
 {
-	ENTRY;
 	cfs_hash_putref(exp->exp_lock_hash);
 	exp->exp_lock_hash = NULL;
 
 	ldlm_destroy_flock_export(exp);
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_destroy_export);
 
@@ -1052,14 +1035,13 @@
 	struct ldlm_bl_pool			*blp = NULL;
 	int rc = 0;
 	int i;
-	ENTRY;
 
 	if (ldlm_state != NULL)
-		RETURN(-EALREADY);
+		return -EALREADY;
 
 	OBD_ALLOC(ldlm_state, sizeof(*ldlm_state));
 	if (ldlm_state == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 #ifdef LPROCFS
 	rc = ldlm_proc_setup();
@@ -1139,23 +1121,21 @@
 		CERROR("Failed to initialize LDLM pools: %d\n", rc);
 		GOTO(out, rc);
 	}
-	RETURN(0);
+	return 0;
 
  out:
 	ldlm_cleanup();
-	RETURN(rc);
+	return rc;
 }
 
 static int ldlm_cleanup(void)
 {
-	ENTRY;
-
 	if (!list_empty(ldlm_namespace_list(LDLM_NAMESPACE_SERVER)) ||
 	    !list_empty(ldlm_namespace_list(LDLM_NAMESPACE_CLIENT))) {
 		CERROR("ldlm still has namespaces; clean these up first.\n");
 		ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE);
 		ldlm_dump_all_namespaces(LDLM_NAMESPACE_CLIENT, D_DLMTRACE);
-		RETURN(-EBUSY);
+		return -EBUSY;
 	}
 
 	ldlm_pools_fini();
@@ -1188,7 +1168,7 @@
 	OBD_FREE(ldlm_state, sizeof(*ldlm_state));
 	ldlm_state = NULL;
 
-	RETURN(0);
+	return 0;
 }
 
 int ldlm_init(void)
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index b3b6028..454027d 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -142,7 +142,7 @@
  */
 #define LDLM_POOL_SLV_SHIFT (10)
 
-extern proc_dir_entry_t *ldlm_ns_proc_dir;
+extern struct proc_dir_entry *ldlm_ns_proc_dir;
 
 static inline __u64 dru(__u64 val, __u32 shift, int round_up)
 {
@@ -335,17 +335,16 @@
 static int ldlm_srv_pool_recalc(struct ldlm_pool *pl)
 {
 	time_t recalc_interval_sec;
-	ENTRY;
 
 	recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
 	if (recalc_interval_sec < pl->pl_recalc_period)
-		RETURN(0);
+		return 0;
 
 	spin_lock(&pl->pl_lock);
 	recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
 	if (recalc_interval_sec < pl->pl_recalc_period) {
 		spin_unlock(&pl->pl_lock);
-		RETURN(0);
+		return 0;
 	}
 	/*
 	 * Recalc SLV after last period. This should be done
@@ -367,7 +366,7 @@
 	lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
 			    recalc_interval_sec);
 	spin_unlock(&pl->pl_lock);
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -394,7 +393,7 @@
 	 * and can't cancel anything. Let's catch this race.
 	 */
 	if (atomic_read(&pl->pl_granted) == 0)
-		RETURN(0);
+		return 0;
 
 	spin_lock(&pl->pl_lock);
 
@@ -473,11 +472,10 @@
 static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
 {
 	time_t recalc_interval_sec;
-	ENTRY;
 
 	recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
 	if (recalc_interval_sec < pl->pl_recalc_period)
-		RETURN(0);
+		return 0;
 
 	spin_lock(&pl->pl_lock);
 	/*
@@ -486,7 +484,7 @@
 	recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
 	if (recalc_interval_sec < pl->pl_recalc_period) {
 		spin_unlock(&pl->pl_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	/*
@@ -503,7 +501,7 @@
 	 * Do not cancel locks in case lru resize is disabled for this ns.
 	 */
 	if (!ns_connect_lru_resize(ldlm_pl2ns(pl)))
-		RETURN(0);
+		return 0;
 
 	/*
 	 * In the time of canceling locks on client we do not need to maintain
@@ -511,8 +509,7 @@
 	 * It may be called when SLV has changed much, this is why we do not
 	 * take into account pl->pl_recalc_time here.
 	 */
-	RETURN(ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC,
-			       LDLM_CANCEL_LRUR));
+	return ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
 }
 
 /**
@@ -532,7 +529,7 @@
 	 * Do not cancel locks in case lru resize is disabled for this ns.
 	 */
 	if (!ns_connect_lru_resize(ns))
-		RETURN(0);
+		return 0;
 
 	/*
 	 * Make sure that pool knows last SLV and Limit from obd.
@@ -578,7 +575,6 @@
 		goto recalc;
 
 	spin_lock(&pl->pl_lock);
-	recalc_interval_sec = cfs_time_current_sec() - pl->pl_recalc_time;
 	if (recalc_interval_sec > 0) {
 		/*
 		 * Update pool statistics every 1s.
@@ -598,12 +594,12 @@
 		count = pl->pl_ops->po_recalc(pl);
 		lprocfs_counter_add(pl->pl_stats, LDLM_POOL_RECALC_STAT,
 				    count);
-		return count;
 	}
+	recalc_interval_sec = pl->pl_recalc_time - cfs_time_current_sec() +
+			      pl->pl_recalc_period;
 
-	return 0;
+	return recalc_interval_sec;
 }
-EXPORT_SYMBOL(ldlm_pool_recalc);
 
 /**
  * Pool shrink wrapper. Will call either client or server pool recalc callback
@@ -734,11 +730,10 @@
 	struct lprocfs_vars pool_vars[2];
 	char *var_name = NULL;
 	int rc = 0;
-	ENTRY;
 
 	OBD_ALLOC(var_name, MAX_STRING_SIZE + 1);
 	if (!var_name)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	parent_ns_proc = ns->ns_proc_dir_entry;
 	if (parent_ns_proc == NULL) {
@@ -751,6 +746,7 @@
 	if (IS_ERR(pl->pl_proc_dir)) {
 		CERROR("LProcFS failed in ldlm-pool-init\n");
 		rc = PTR_ERR(pl->pl_proc_dir);
+		pl->pl_proc_dir = NULL;
 		GOTO(out_free_name, rc);
 	}
 
@@ -813,7 +809,6 @@
 			     "recalc_timing", "sec");
 	rc = lprocfs_register_stats(pl->pl_proc_dir, "stats", pl->pl_stats);
 
-	EXIT;
 out_free_name:
 	OBD_FREE(var_name, MAX_STRING_SIZE + 1);
 	return rc;
@@ -835,7 +830,6 @@
 		   int idx, ldlm_side_t client)
 {
 	int rc;
-	ENTRY;
 
 	spin_lock_init(&pl->pl_lock);
 	atomic_set(&pl->pl_granted, 0);
@@ -863,17 +857,16 @@
 	pl->pl_client_lock_volume = 0;
 	rc = ldlm_pool_proc_init(pl);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_DLMTRACE, "Lock pool %s is initialized\n", pl->pl_name);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_pool_init);
 
 void ldlm_pool_fini(struct ldlm_pool *pl)
 {
-	ENTRY;
 	ldlm_pool_proc_fini(pl);
 
 	/*
@@ -882,7 +875,6 @@
 	 * any abnormal using cases.
 	 */
 	POISON(pl, 0x5a, sizeof(*pl));
-	EXIT;
 }
 EXPORT_SYMBOL(ldlm_pool_fini);
 
@@ -1039,6 +1031,7 @@
 {
 	int total = 0, cached = 0, nr_ns;
 	struct ldlm_namespace *ns;
+	struct ldlm_namespace *ns_old = NULL; /* loop detection */
 	void *cookie;
 
 	if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
@@ -1053,7 +1046,7 @@
 	/*
 	 * Find out how many resources we may release.
 	 */
-	for (nr_ns = atomic_read(ldlm_namespace_nr(client));
+	for (nr_ns = ldlm_namespace_nr_read(client);
 	     nr_ns > 0; nr_ns--)
 	{
 		mutex_lock(ldlm_namespace_lock(client));
@@ -1063,8 +1056,23 @@
 			return 0;
 		}
 		ns = ldlm_namespace_first_locked(client);
+
+		if (ns == ns_old) {
+			mutex_unlock(ldlm_namespace_lock(client));
+			break;
+		}
+
+		if (ldlm_ns_empty(ns)) {
+			ldlm_namespace_move_to_inactive_locked(ns, client);
+			mutex_unlock(ldlm_namespace_lock(client));
+			continue;
+		}
+
+		if (ns_old == NULL)
+			ns_old = ns;
+
 		ldlm_namespace_get(ns);
-		ldlm_namespace_move_locked(ns, client);
+		ldlm_namespace_move_to_active_locked(ns, client);
 		mutex_unlock(ldlm_namespace_lock(client));
 		total += ldlm_pool_shrink(&ns->ns_pool, 0, gfp_mask);
 		ldlm_namespace_put(ns);
@@ -1078,7 +1086,7 @@
 	/*
 	 * Shrink at least ldlm_namespace_nr(client) namespaces.
 	 */
-	for (nr_ns = atomic_read(ldlm_namespace_nr(client));
+	for (nr_ns = ldlm_namespace_nr_read(client) - nr_ns;
 	     nr_ns > 0; nr_ns--)
 	{
 		int cancel, nr_locks;
@@ -1099,7 +1107,7 @@
 		}
 		ns = ldlm_namespace_first_locked(client);
 		ldlm_namespace_get(ns);
-		ldlm_namespace_move_locked(ns, client);
+		ldlm_namespace_move_to_active_locked(ns, client);
 		mutex_unlock(ldlm_namespace_lock(client));
 
 		nr_locks = ldlm_pool_granted(&ns->ns_pool);
@@ -1128,11 +1136,13 @@
 				 shrink_param(sc, gfp_mask));
 }
 
-void ldlm_pools_recalc(ldlm_side_t client)
+int ldlm_pools_recalc(ldlm_side_t client)
 {
 	__u32 nr_l = 0, nr_p = 0, l;
 	struct ldlm_namespace *ns;
+	struct ldlm_namespace *ns_old = NULL;
 	int nr, equal = 0;
+	int time = 50; /* seconds of sleep if no active namespaces */
 
 	/*
 	 * No need to setup pool limit for client pools.
@@ -1190,16 +1200,14 @@
 				 * for _all_ pools.
 				 */
 				l = LDLM_POOL_HOST_L /
-					atomic_read(
-						ldlm_namespace_nr(client));
+					ldlm_namespace_nr_read(client);
 			} else {
 				/*
 				 * All the rest of greedy pools will have
 				 * all locks in equal parts.
 				 */
 				l = (LDLM_POOL_HOST_L - nr_l) /
-					(atomic_read(
-						ldlm_namespace_nr(client)) -
+					(ldlm_namespace_nr_read(client) -
 					 nr_p);
 			}
 			ldlm_pool_setup(&ns->ns_pool, l);
@@ -1210,7 +1218,7 @@
 	/*
 	 * Recalc at least ldlm_namespace_nr(client) namespaces.
 	 */
-	for (nr = atomic_read(ldlm_namespace_nr(client)); nr > 0; nr--) {
+	for (nr = ldlm_namespace_nr_read(client); nr > 0; nr--) {
 		int     skip;
 		/*
 		 * Lock the list, get first @ns in the list, getref, move it
@@ -1226,6 +1234,30 @@
 		}
 		ns = ldlm_namespace_first_locked(client);
 
+		if (ns_old == ns) { /* Full pass complete */
+			mutex_unlock(ldlm_namespace_lock(client));
+			break;
+		}
+
+		/* We got an empty namespace, need to move it back to inactive
+		 * list.
+		 * The race with parallel resource creation is fine:
+		 * - If they do namespace_get before our check, we fail the
+		 *   check and they move this item to the end of the list anyway
+		 * - If we do the check and then they do namespace_get, then
+		 *   we move the namespace to inactive and they will move
+		 *   it back to active (synchronised by the lock, so no clash
+		 *   there).
+		 */
+		if (ldlm_ns_empty(ns)) {
+			ldlm_namespace_move_to_inactive_locked(ns, client);
+			mutex_unlock(ldlm_namespace_lock(client));
+			continue;
+		}
+
+		if (ns_old == NULL)
+			ns_old = ns;
+
 		spin_lock(&ns->ns_lock);
 		/*
 		 * skip ns which is being freed, and we don't want to increase
@@ -1239,24 +1271,29 @@
 		}
 		spin_unlock(&ns->ns_lock);
 
-		ldlm_namespace_move_locked(ns, client);
+		ldlm_namespace_move_to_active_locked(ns, client);
 		mutex_unlock(ldlm_namespace_lock(client));
 
 		/*
 		 * After setup is done - recalc the pool.
 		 */
 		if (!skip) {
-			ldlm_pool_recalc(&ns->ns_pool);
+			int ttime = ldlm_pool_recalc(&ns->ns_pool);
+
+			if (ttime < time)
+				time = ttime;
+
 			ldlm_namespace_put(ns);
 		}
 	}
+	return time;
 }
 EXPORT_SYMBOL(ldlm_pools_recalc);
 
 static int ldlm_pools_thread_main(void *arg)
 {
 	struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
-	ENTRY;
+	int s_time, c_time;
 
 	thread_set_flags(thread, SVC_RUNNING);
 	wake_up(&thread->t_ctl_waitq);
@@ -1270,14 +1307,14 @@
 		/*
 		 * Recal all pools on this tick.
 		 */
-		ldlm_pools_recalc(LDLM_NAMESPACE_SERVER);
-		ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
+		s_time = ldlm_pools_recalc(LDLM_NAMESPACE_SERVER);
+		c_time = ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT);
 
 		/*
 		 * Wait until the next check time, or until we're
 		 * stopped.
 		 */
-		lwi = LWI_TIMEOUT(cfs_time_seconds(LDLM_POOLS_THREAD_PERIOD),
+		lwi = LWI_TIMEOUT(cfs_time_seconds(min(s_time, c_time)),
 				  NULL, NULL);
 		l_wait_event(thread->t_ctl_waitq,
 			     thread_is_stopping(thread) ||
@@ -1302,15 +1339,14 @@
 static int ldlm_pools_thread_start(void)
 {
 	struct l_wait_info lwi = { 0 };
-	task_t *task;
-	ENTRY;
+	struct task_struct *task;
 
 	if (ldlm_pools_thread != NULL)
-		RETURN(-EALREADY);
+		return -EALREADY;
 
 	OBD_ALLOC_PTR(ldlm_pools_thread);
 	if (ldlm_pools_thread == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	init_completion(&ldlm_pools_comp);
 	init_waitqueue_head(&ldlm_pools_thread->t_ctl_waitq);
@@ -1321,19 +1357,16 @@
 		CERROR("Can't start pool thread, error %ld\n", PTR_ERR(task));
 		OBD_FREE(ldlm_pools_thread, sizeof(*ldlm_pools_thread));
 		ldlm_pools_thread = NULL;
-		RETURN(PTR_ERR(task));
+		return PTR_ERR(task);
 	}
 	l_wait_event(ldlm_pools_thread->t_ctl_waitq,
 		     thread_is_running(ldlm_pools_thread), &lwi);
-	RETURN(0);
+	return 0;
 }
 
 static void ldlm_pools_thread_stop(void)
 {
-	ENTRY;
-
 	if (ldlm_pools_thread == NULL) {
-		EXIT;
 		return;
 	}
 
@@ -1348,13 +1381,11 @@
 	wait_for_completion(&ldlm_pools_comp);
 	OBD_FREE_PTR(ldlm_pools_thread);
 	ldlm_pools_thread = NULL;
-	EXIT;
 }
 
 int ldlm_pools_init(void)
 {
 	int rc;
-	ENTRY;
 
 	rc = ldlm_pools_thread_start();
 	if (rc == 0) {
@@ -1365,7 +1396,7 @@
 			set_shrinker(DEFAULT_SEEKS,
 					 ldlm_pools_cli_shrink);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_pools_init);
 
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
index 1a690ed..21cb523 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c
@@ -94,12 +94,11 @@
 	struct obd_import *imp;
 	struct obd_device *obd;
 
-	ENTRY;
 	if (lock->l_conn_export == NULL) {
 		static cfs_time_t next_dump = 0, last_dump = 0;
 
 		if (ptlrpc_check_suspend())
-			RETURN(0);
+			return 0;
 
 		LCONSOLE_WARN("lock timed out (enqueued at "CFS_TIME_T", "
 			      CFS_DURATION_T"s ago)\n",
@@ -120,7 +119,7 @@
 			if (last_dump == 0)
 				libcfs_debug_dumplog();
 		}
-		RETURN(0);
+		return 0;
 	}
 
 	obd = lock->l_conn_export->exp_obd;
@@ -132,7 +131,7 @@
 		  cfs_time_sub(cfs_time_current_sec(), lock->l_last_activity),
 		  obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_expired_completion_wait);
 
@@ -160,7 +159,7 @@
 	long delay;
 	int  result;
 
-	if (lock->l_destroyed || lock->l_flags & LDLM_FL_FAILED) {
+	if (lock->l_flags & (LDLM_FL_DESTROYED | LDLM_FL_FAILED)) {
 		LDLM_DEBUG(lock, "client-side enqueue: destroyed");
 		result = -EIO;
 	} else {
@@ -184,23 +183,21 @@
  */
 int ldlm_completion_ast_async(struct ldlm_lock *lock, __u64 flags, void *data)
 {
-	ENTRY;
-
 	if (flags == LDLM_FL_WAIT_NOREPROC) {
 		LDLM_DEBUG(lock, "client-side enqueue waiting on pending lock");
-		RETURN(0);
+		return 0;
 	}
 
 	if (!(flags & (LDLM_FL_BLOCK_WAIT | LDLM_FL_BLOCK_GRANTED |
 		       LDLM_FL_BLOCK_CONV))) {
 		wake_up(&lock->l_waitq);
-		RETURN(ldlm_completion_tail(lock));
+		return ldlm_completion_tail(lock);
 	}
 
 	LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, "
 		   "going forward");
 	ldlm_reprocess_all(lock->l_resource);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_completion_ast_async);
 
@@ -234,7 +231,6 @@
 	struct l_wait_info lwi;
 	__u32 timeout;
 	int rc = 0;
-	ENTRY;
 
 	if (flags == LDLM_FL_WAIT_NOREPROC) {
 		LDLM_DEBUG(lock, "client-side enqueue waiting on pending lock");
@@ -244,7 +240,7 @@
 	if (!(flags & (LDLM_FL_BLOCK_WAIT | LDLM_FL_BLOCK_GRANTED |
 		       LDLM_FL_BLOCK_CONV))) {
 		wake_up(&lock->l_waitq);
-		RETURN(0);
+		return 0;
 	}
 
 	LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, "
@@ -295,10 +291,10 @@
 	if (rc) {
 		LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)",
 			   rc);
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(ldlm_completion_tail(lock));
+	return ldlm_completion_tail(lock);
 }
 EXPORT_SYMBOL(ldlm_completion_ast);
 
@@ -316,7 +312,6 @@
 int ldlm_blocking_ast_nocheck(struct ldlm_lock *lock)
 {
 	int do_ast;
-	ENTRY;
 
 	lock->l_flags |= LDLM_FL_CBPENDING;
 	do_ast = (!lock->l_readers && !lock->l_writers);
@@ -335,7 +330,7 @@
 		LDLM_DEBUG(lock, "Lock still has references, will be "
 			   "cancelled later");
 	}
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_blocking_ast_nocheck);
 
@@ -355,11 +350,9 @@
 int ldlm_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
 		      void *data, int flag)
 {
-	ENTRY;
-
 	if (flag == LDLM_CB_CANCELING) {
 		/* Don't need to do anything here. */
-		RETURN(0);
+		return 0;
 	}
 
 	lock_res_and_lock(lock);
@@ -370,9 +363,9 @@
 	 * early, if so. */
 	if (lock->l_blocking_ast != ldlm_blocking_ast) {
 		unlock_res_and_lock(lock);
-		RETURN(0);
+		return 0;
 	}
-	RETURN(ldlm_blocking_ast_nocheck(lock));
+	return ldlm_blocking_ast_nocheck(lock);
 }
 EXPORT_SYMBOL(ldlm_blocking_ast);
 
@@ -424,7 +417,6 @@
 						 .lcs_blocking   = blocking,
 						 .lcs_glimpse    = glimpse,
 	};
-	ENTRY;
 
 	LASSERT(!(*flags & LDLM_FL_REPLAY));
 	if (unlikely(ns_is_client(ns))) {
@@ -464,7 +456,6 @@
 		lock->l_completion_ast(lock, *flags, NULL);
 
 	LDLM_DEBUG(lock, "client-side local enqueue handler, new lock created");
-	EXIT;
  out:
 	LDLM_LOCK_RELEASE(lock);
  out_nolock:
@@ -530,13 +521,12 @@
 	struct ldlm_reply *reply;
 	int cleanup_phase = 1;
 	int size = 0;
-	ENTRY;
 
 	lock = ldlm_handle2lock(lockh);
 	/* ldlm_cli_enqueue is holding a reference on this lock. */
 	if (!lock) {
 		LASSERT(type == LDLM_FLOCK);
-		RETURN(-ENOLCK);
+		return -ENOLCK;
 	}
 
 	LASSERTF(ergo(lvb_len != 0, lvb_len == lock->l_lvb_len),
@@ -698,7 +688,6 @@
 	}
 
 	LDLM_DEBUG(lock, "client-side enqueue END");
-	EXIT;
 cleanup:
 	if (cleanup_phase == 1 && rc)
 		failed_lock_cleanup(ns, lock, mode);
@@ -763,7 +752,6 @@
 	int flags, avail, to_free, pack = 0;
 	LIST_HEAD(head);
 	int rc;
-	ENTRY;
 
 	if (cancels == NULL)
 		cancels = &head;
@@ -794,7 +782,7 @@
 	rc = ptlrpc_request_pack(req, version, opc);
 	if (rc) {
 		ldlm_lock_list_put(cancels, l_bl_ast, count);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (ns_connect_cancelset(ns)) {
@@ -814,7 +802,7 @@
 	} else {
 		ldlm_lock_list_put(cancels, l_bl_ast, count);
 	}
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_prep_elc_req);
 
@@ -830,21 +818,20 @@
 {
 	struct ptlrpc_request *req;
 	int rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LDLM_ENQUEUE);
 	if (req == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, lvb_len);
 	ptlrpc_request_set_replen(req);
-	RETURN(req);
+	return req;
 }
 EXPORT_SYMBOL(ldlm_enqueue_pack);
 
@@ -872,7 +859,6 @@
 	int		    req_passed_in = 1;
 	int		    rc, err;
 	struct ptlrpc_request *req;
-	ENTRY;
 
 	LASSERT(exp != NULL);
 
@@ -888,15 +874,14 @@
 	} else {
 		const struct ldlm_callback_suite cbs = {
 			.lcs_completion = einfo->ei_cb_cp,
-			.lcs_blocking   = einfo->ei_cb_bl,
-			.lcs_glimpse    = einfo->ei_cb_gl,
-			.lcs_weigh      = einfo->ei_cb_wg
+			.lcs_blocking	= einfo->ei_cb_bl,
+			.lcs_glimpse	= einfo->ei_cb_gl
 		};
 		lock = ldlm_lock_create(ns, res_id, einfo->ei_type,
 					einfo->ei_mode, &cbs, einfo->ei_cbdata,
 					lvb_len, lvb_type);
 		if (lock == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		/* for the local lock, add the reference */
 		ldlm_lock_addref_internal(lock, einfo->ei_mode);
 		ldlm_lock2handle(lock, lockh);
@@ -937,7 +922,7 @@
 		if (req == NULL) {
 			failed_lock_cleanup(ns, lock, einfo->ei_mode);
 			LDLM_LOCK_RELEASE(lock);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		req_passed_in = 0;
 		if (reqp)
@@ -978,7 +963,7 @@
 
 	if (async) {
 		LASSERT(reqp != NULL);
-		RETURN(0);
+		return 0;
 	}
 
 	LDLM_DEBUG(lock, "sending request");
@@ -1002,7 +987,7 @@
 			*reqp = NULL;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_cli_enqueue);
 
@@ -1011,7 +996,7 @@
 {
 	struct ldlm_resource *res;
 	int rc;
-	ENTRY;
+
 	if (ns_is_client(ldlm_lock_to_ns(lock))) {
 		CERROR("Trying to cancel local lock\n");
 		LBUG();
@@ -1023,11 +1008,11 @@
 		ldlm_reprocess_all(res);
 		rc = 0;
 	} else {
-		rc = EDEADLOCK;
+		rc = LUSTRE_EDEADLK;
 	}
 	LDLM_DEBUG(lock, "client-side local convert handler END");
 	LDLM_LOCK_PUT(lock);
-	RETURN(rc);
+	return rc;
 }
 
 /* FIXME: one of ldlm_cli_convert or the server side should reject attempted
@@ -1042,17 +1027,16 @@
 	struct ldlm_resource  *res;
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	lock = ldlm_handle2lock(lockh);
 	if (!lock) {
 		LBUG();
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	*flags = 0;
 
 	if (lock->l_conn_export == NULL)
-		RETURN(ldlm_cli_convert_local(lock, new_mode, flags));
+		return ldlm_cli_convert_local(lock, new_mode, flags);
 
 	LDLM_DEBUG(lock, "client-side convert");
 
@@ -1061,7 +1045,7 @@
 					LDLM_CONVERT);
 	if (req == NULL) {
 		LDLM_LOCK_PUT(lock);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	body = req_capsule_client_get(&req->rq_pill, &RMF_DLM_REQ);
@@ -1095,9 +1079,8 @@
 				GOTO(out, rc);
 		}
 	} else {
-		rc = EDEADLOCK;
+		rc = LUSTRE_EDEADLK;
 	}
-	EXIT;
  out:
 	LDLM_LOCK_PUT(lock);
 	ptlrpc_req_finished(req);
@@ -1115,7 +1098,6 @@
 static __u64 ldlm_cli_cancel_local(struct ldlm_lock *lock)
 {
 	__u64 rc = LDLM_FL_LOCAL_ONLY;
-	ENTRY;
 
 	if (lock->l_conn_export) {
 		bool local_only;
@@ -1147,7 +1129,7 @@
 		ldlm_reprocess_all(lock->l_resource);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1159,7 +1141,6 @@
 	struct ldlm_request *dlm;
 	struct ldlm_lock *lock;
 	int max, packed = 0;
-	ENTRY;
 
 	dlm = req_capsule_client_get(&req->rq_pill, &RMF_DLM_REQ);
 	LASSERT(dlm != NULL);
@@ -1184,7 +1165,6 @@
 		packed++;
 	}
 	CDEBUG(D_DLMTRACE, "%d locks packed\n", packed);
-	EXIT;
 }
 
 /**
@@ -1197,7 +1177,6 @@
 	struct obd_import *imp;
 	int free, sent = 0;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(exp != NULL);
 	LASSERT(count > 0);
@@ -1205,7 +1184,7 @@
 	CFS_FAIL_TIMEOUT(OBD_FAIL_LDLM_PAUSE_CANCEL, cfs_fail_val);
 
 	if (CFS_FAIL_CHECK(OBD_FAIL_LDLM_CANCEL_RACE))
-		RETURN(count);
+		return count;
 
 	free = ldlm_format_handles_avail(class_exp2cliimp(exp),
 					 &RQF_LDLM_CANCEL, RCL_CLIENT, 0);
@@ -1217,7 +1196,7 @@
 		if (imp == NULL || imp->imp_invalid) {
 			CDEBUG(D_DLMTRACE,
 			       "skipping cancel on invalid import %p\n", imp);
-			RETURN(count);
+			return count;
 		}
 
 		req = ptlrpc_request_alloc(imp, &RQF_LDLM_CANCEL);
@@ -1248,7 +1227,7 @@
 		} else {
 			rc = ptlrpc_queue_wait(req);
 		}
-		if (rc == ESTALE) {
+		if (rc == LUSTRE_ESTALE) {
 			CDEBUG(D_DLMTRACE, "client/server (nid %s) "
 			       "out of sync -- not fatal\n",
 			       libcfs_nid2str(req->rq_import->
@@ -1270,7 +1249,6 @@
 	}
 
 	ptlrpc_req_finished(req);
-	EXIT;
 out:
 	return sent ? sent : rc;
 }
@@ -1290,14 +1268,14 @@
 	struct obd_device *obd;
 	__u64 new_slv;
 	__u32 new_limit;
-	ENTRY;
+
 	if (unlikely(!req->rq_import || !req->rq_import->imp_obd ||
 		     !imp_connect_lru_resize(req->rq_import)))
 	{
 		/*
 		 * Do nothing for corner cases.
 		 */
-		RETURN(0);
+		return 0;
 	}
 
 	/* In some cases RPC may contain SLV and limit zeroed out. This
@@ -1311,7 +1289,7 @@
 			  "(SLV: "LPU64", Limit: %u)",
 			  lustre_msg_get_slv(req->rq_repmsg),
 			  lustre_msg_get_limit(req->rq_repmsg));
-		RETURN(0);
+		return 0;
 	}
 
 	new_limit = lustre_msg_get_limit(req->rq_repmsg);
@@ -1328,7 +1306,7 @@
 	obd->obd_pool_limit = new_limit;
 	write_unlock(&obd->obd_pool_lock);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_cli_update_pool);
 
@@ -1346,19 +1324,18 @@
 	struct ldlm_namespace *ns;
 	struct ldlm_lock *lock;
 	LIST_HEAD(cancels);
-	ENTRY;
 
 	/* concurrent cancels on the same handle can happen */
 	lock = ldlm_handle2lock_long(lockh, LDLM_FL_CANCELING);
 	if (lock == NULL) {
 		LDLM_DEBUG_NOLOCK("lock is already being destroyed\n");
-		RETURN(0);
+		return 0;
 	}
 
 	rc = ldlm_cli_cancel_local(lock);
 	if (rc == LDLM_FL_LOCAL_ONLY) {
 		LDLM_LOCK_RELEASE(lock);
-		RETURN(0);
+		return 0;
 	}
 	/* Even if the lock is marked as LDLM_FL_BL_AST, this is a LDLM_CANCEL
 	 * RPC which goes to canceld portal, so we can cancel other LRU locks
@@ -1380,7 +1357,7 @@
 					       LCF_BL_AST, flags);
 	}
 	ldlm_cli_cancel_list(&cancels, count, NULL, cancel_flags);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_cli_cancel);
 
@@ -1430,7 +1407,7 @@
 		ldlm_cli_cancel_list(&head, bl_ast, NULL, 0);
 	}
 
-	RETURN(count);
+	return count;
 }
 EXPORT_SYMBOL(ldlm_cli_cancel_list_local);
 
@@ -1462,7 +1439,7 @@
 	}
 
 	unlock_res_and_lock(lock);
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -1631,7 +1608,6 @@
 	ldlm_cancel_lru_policy_t pf;
 	struct ldlm_lock *lock, *next;
 	int added = 0, unused, remained;
-	ENTRY;
 
 	spin_lock(&ns->ns_lock);
 	unused = ns->ns_nr_unused;
@@ -1754,7 +1730,7 @@
 		unused--;
 	}
 	spin_unlock(&ns->ns_lock);
-	RETURN(added);
+	return added;
 }
 
 int ldlm_cancel_lru_local(struct ldlm_namespace *ns, struct list_head *cancels,
@@ -1782,16 +1758,15 @@
 {
 	LIST_HEAD(cancels);
 	int count, rc;
-	ENTRY;
 
 	/* Just prepare the list of locks, do not actually cancel them yet.
 	 * Locks are cancelled later in a separate thread. */
 	count = ldlm_prepare_lru_list(ns, &cancels, nr, 0, flags);
 	rc = ldlm_bl_to_thread_list(ns, NULL, &cancels, count, cancel_flags);
 	if (rc == 0)
-		RETURN(count);
+		return count;
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1807,7 +1782,6 @@
 {
 	struct ldlm_lock *lock;
 	int count = 0;
-	ENTRY;
 
 	lock_res(res);
 	list_for_each_entry(lock, &res->lr_granted, l_res_link) {
@@ -1848,7 +1822,7 @@
 	}
 	unlock_res(res);
 
-	RETURN(ldlm_cli_cancel_list_local(cancels, count, cancel_flags));
+	return ldlm_cli_cancel_list_local(cancels, count, cancel_flags);
 }
 EXPORT_SYMBOL(ldlm_cancel_resource_local);
 
@@ -1867,10 +1841,9 @@
 {
 	struct ldlm_lock *lock;
 	int res = 0;
-	ENTRY;
 
 	if (list_empty(cancels) || count == 0)
-		RETURN(0);
+		return 0;
 
 	/* XXX: requests (both batched and not) could be sent in parallel.
 	 * Usually it is enough to have just 1 RPC, but it is possible that
@@ -1906,7 +1879,7 @@
 		ldlm_lock_list_put(cancels, l_bl_ast, res);
 	}
 	LASSERT(count == 0);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_cli_cancel_list);
 
@@ -1926,13 +1899,12 @@
 	LIST_HEAD(cancels);
 	int count;
 	int rc;
-	ENTRY;
 
 	res = ldlm_resource_get(ns, NULL, res_id, 0, 0);
 	if (res == NULL) {
 		/* This is not a problem. */
 		CDEBUG(D_INFO, "No resource "LPU64"\n", res_id->name[0]);
-		RETURN(0);
+		return 0;
 	}
 
 	LDLM_RESOURCE_ADDREF(res);
@@ -1944,7 +1916,7 @@
 
 	LDLM_RESOURCE_DELREF(res);
 	ldlm_resource_putref(res);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ldlm_cli_cancel_unused_resource);
 
@@ -1986,19 +1958,17 @@
 		.lc_opaque      = opaque,
 	};
 
-	ENTRY;
-
 	if (ns == NULL)
-		RETURN(ELDLM_OK);
+		return ELDLM_OK;
 
 	if (res_id != NULL) {
-		RETURN(ldlm_cli_cancel_unused_resource(ns, res_id, NULL,
+		return ldlm_cli_cancel_unused_resource(ns, res_id, NULL,
 						       LCK_MINMODE, flags,
-						       opaque));
+						       opaque);
 	} else {
 		cfs_hash_for_each_nolock(ns->ns_rs_hash,
 					 ldlm_cli_hash_cancel_unused, &arg);
-		RETURN(ELDLM_OK);
+		return ELDLM_OK;
 	}
 }
 EXPORT_SYMBOL(ldlm_cli_cancel_unused);
@@ -2012,10 +1982,8 @@
 	struct ldlm_lock *lock;
 	int rc = LDLM_ITER_CONTINUE;
 
-	ENTRY;
-
 	if (!res)
-		RETURN(LDLM_ITER_CONTINUE);
+		return LDLM_ITER_CONTINUE;
 
 	lock_res(res);
 	list_for_each_safe(tmp, next, &res->lr_granted) {
@@ -2040,7 +2008,7 @@
 	}
  out:
 	unlock_res(res);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_resource_foreach);
 
@@ -2069,7 +2037,10 @@
 			    ldlm_iterator_t iter, void *closure)
 
 {
-	struct iter_helper_data helper = { iter: iter, closure: closure };
+	struct iter_helper_data helper = {
+		.iter		= iter,
+		.closure	= closure,
+	};
 
 	cfs_hash_for_each_nolock(ns->ns_rs_hash,
 				 ldlm_res_iter_helper, &helper);
@@ -2088,7 +2059,6 @@
 {
 	struct ldlm_resource *res;
 	int rc;
-	ENTRY;
 
 	if (ns == NULL) {
 		CERROR("must pass in namespace\n");
@@ -2097,13 +2067,13 @@
 
 	res = ldlm_resource_get(ns, NULL, res_id, 0, 0);
 	if (res == NULL)
-		RETURN(0);
+		return 0;
 
 	LDLM_RESOURCE_ADDREF(res);
 	rc = ldlm_resource_foreach(res, iter, data);
 	LDLM_RESOURCE_DELREF(res);
 	ldlm_resource_putref(res);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_resource_iterate);
 
@@ -2137,7 +2107,6 @@
 	struct ldlm_reply    *reply;
 	struct obd_export    *exp;
 
-	ENTRY;
 	atomic_dec(&req->rq_import->imp_replay_inflight);
 	if (rc != ELDLM_OK)
 		GOTO(out, rc);
@@ -2178,7 +2147,7 @@
 	if (rc != ELDLM_OK)
 		ptlrpc_connect_import(req->rq_import);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int replay_one_lock(struct obd_import *imp, struct ldlm_lock *lock)
@@ -2187,13 +2156,11 @@
 	struct ldlm_async_args *aa;
 	struct ldlm_request   *body;
 	int flags;
-	ENTRY;
-
 
 	/* Bug 11974: Do not replay a lock which is actively being canceled */
 	if (lock->l_flags & LDLM_FL_CANCELING) {
 		LDLM_DEBUG(lock, "Not replaying canceled lock:");
-		RETURN(0);
+		return 0;
 	}
 
 	/* If this is reply-less callback lock, we cannot replay it, since
@@ -2202,7 +2169,7 @@
 	if (lock->l_flags & LDLM_FL_CANCEL_ON_BLOCK) {
 		LDLM_DEBUG(lock, "Not replaying reply-less lock:");
 		ldlm_lock_cancel(lock);
-		RETURN(0);
+		return 0;
 	}
 
 	/*
@@ -2231,7 +2198,7 @@
 	req = ptlrpc_request_alloc_pack(imp, &RQF_LDLM_ENQUEUE,
 					LUSTRE_DLM_VERSION, LDLM_ENQUEUE);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* We're part of recovery, so don't wait for it. */
 	req->rq_send_state = LUSTRE_IMP_REPLAY_LOCKS;
@@ -2261,7 +2228,7 @@
 	req->rq_interpret_reply = (ptlrpc_interpterer_t)replay_lock_interpret;
 	ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -2300,13 +2267,11 @@
 	struct ldlm_lock *lock, *next;
 	int rc = 0;
 
-	ENTRY;
-
 	LASSERT(atomic_read(&imp->imp_replay_inflight) == 0);
 
 	/* don't replay locks if import failed recovery */
 	if (imp->imp_vbr_failed)
-		RETURN(0);
+		return 0;
 
 	/* ensure this doesn't fall to 0 before all have been queued */
 	atomic_inc(&imp->imp_replay_inflight);
@@ -2328,6 +2293,6 @@
 
 	atomic_dec(&imp->imp_replay_inflight);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ldlm_replay_locks);
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 9052dc5..208751a 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -48,18 +48,23 @@
 
 struct kmem_cache *ldlm_resource_slab, *ldlm_lock_slab;
 
-atomic_t ldlm_srv_namespace_nr = ATOMIC_INIT(0);
-atomic_t ldlm_cli_namespace_nr = ATOMIC_INIT(0);
+int ldlm_srv_namespace_nr = 0;
+int ldlm_cli_namespace_nr = 0;
 
 struct mutex ldlm_srv_namespace_lock;
 LIST_HEAD(ldlm_srv_namespace_list);
 
 struct mutex ldlm_cli_namespace_lock;
-LIST_HEAD(ldlm_cli_namespace_list);
+/* Client Namespaces that have active resources in them.
+ * Once all resources go away, ldlm_poold moves such namespaces to the
+ * inactive list */
+LIST_HEAD(ldlm_cli_active_namespace_list);
+/* Client namespaces that don't have any locks in them */
+LIST_HEAD(ldlm_cli_inactive_namespace_list);
 
-proc_dir_entry_t *ldlm_type_proc_dir = NULL;
-proc_dir_entry_t *ldlm_ns_proc_dir = NULL;
-proc_dir_entry_t *ldlm_svc_proc_dir = NULL;
+struct proc_dir_entry *ldlm_type_proc_dir = NULL;
+struct proc_dir_entry *ldlm_ns_proc_dir = NULL;
+struct proc_dir_entry *ldlm_svc_proc_dir = NULL;
 
 extern unsigned int ldlm_cancel_unused_locks_before_replay;
 
@@ -73,7 +78,7 @@
 {
 	ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE);
 	ldlm_dump_all_namespaces(LDLM_NAMESPACE_CLIENT, D_DLMTRACE);
-	RETURN(count);
+	return count;
 }
 LPROC_SEQ_FOPS_WR_ONLY(ldlm, dump_ns);
 
@@ -90,7 +95,6 @@
 		{ "cancel_unused_locks_before_replay", &ldlm_rw_uint_fops,
 		  &ldlm_cancel_unused_locks_before_replay },
 		{ NULL }};
-	ENTRY;
 	LASSERT(ldlm_ns_proc_dir == NULL);
 
 	ldlm_type_proc_dir = lprocfs_register(OBD_LDLM_DEVICENAME,
@@ -122,7 +126,7 @@
 
 	rc = lprocfs_add_vars(ldlm_type_proc_dir, list, NULL);
 
-	RETURN(0);
+	return 0;
 
 err_ns:
 	lprocfs_remove(&ldlm_ns_proc_dir);
@@ -132,7 +136,7 @@
 	ldlm_svc_proc_dir = NULL;
 	ldlm_type_proc_dir = NULL;
 	ldlm_ns_proc_dir = NULL;
-	RETURN(rc);
+	return rc;
 }
 
 void ldlm_proc_cleanup(void)
@@ -325,7 +329,7 @@
 {
 	struct lprocfs_vars lock_vars[2];
 	char lock_name[MAX_STRING_SIZE + 1];
-	proc_dir_entry_t *ns_pde;
+	struct proc_dir_entry *ns_pde;
 
 	LASSERT(ns != NULL);
 	LASSERT(ns->ns_rs_hash != NULL);
@@ -563,14 +567,13 @@
 	cfs_hash_bd_t	  bd;
 	int		    idx;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(obd != NULL);
 
 	rc = ldlm_get_ref();
 	if (rc) {
 		CERROR("ldlm_get_ref failed: %d\n", rc);
-		RETURN(NULL);
+		return NULL;
 	}
 
 	for (idx = 0;;idx++) {
@@ -636,7 +639,7 @@
 		GOTO(out_hash, rc);
 	}
 
-	idx = atomic_read(ldlm_namespace_nr(client));
+	idx = ldlm_namespace_nr_read(client);
 	rc = ldlm_pool_init(&ns->ns_pool, ns, idx, client);
 	if (rc) {
 		CERROR("Can't initialize lock pool, rc %d\n", rc);
@@ -644,7 +647,7 @@
 	}
 
 	ldlm_namespace_register(ns, client);
-	RETURN(ns);
+	return ns;
 out_proc:
 	ldlm_namespace_proc_unregister(ns);
 	ldlm_namespace_cleanup(ns, 0);
@@ -654,7 +657,7 @@
 	OBD_FREE_PTR(ns);
 out_ref:
 	ldlm_put_ref();
-	RETURN(NULL);
+	return NULL;
 }
 EXPORT_SYMBOL(ldlm_namespace_new);
 
@@ -803,8 +806,6 @@
  */
 static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force)
 {
-	ENTRY;
-
 	/* At shutdown time, don't call the cancellation callback */
 	ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0);
 
@@ -836,13 +837,13 @@
 				       "with %d resources in use, (rc=%d)\n",
 				       ldlm_ns_name(ns),
 				       atomic_read(&ns->ns_bref), rc);
-			RETURN(ELDLM_NAMESPACE_EXISTS);
+			return ELDLM_NAMESPACE_EXISTS;
 		}
 		CDEBUG(D_DLMTRACE, "dlm namespace %s free done waiting\n",
 		       ldlm_ns_name(ns));
 	}
 
-	RETURN(ELDLM_OK);
+	return ELDLM_OK;
 }
 
 /**
@@ -859,9 +860,8 @@
 			       int force)
 {
 	int rc;
-	ENTRY;
+
 	if (!ns) {
-		EXIT;
 		return;
 	}
 
@@ -886,7 +886,6 @@
 		rc = __ldlm_namespace_free(ns, 1);
 		LASSERT(rc == 0);
 	}
-	EXIT;
 }
 
 /**
@@ -896,9 +895,7 @@
  */
 void ldlm_namespace_free_post(struct ldlm_namespace *ns)
 {
-	ENTRY;
 	if (!ns) {
-		EXIT;
 		return;
 	}
 
@@ -917,7 +914,6 @@
 	LASSERT(list_empty(&ns->ns_list_chain));
 	OBD_FREE_PTR(ns);
 	ldlm_put_ref();
-	EXIT;
 }
 
 /**
@@ -953,6 +949,12 @@
 }
 EXPORT_SYMBOL(ldlm_namespace_get);
 
+/* This is only for callers that care about refcount */
+int ldlm_namespace_get_return(struct ldlm_namespace *ns)
+{
+	return atomic_inc_return(&ns->ns_bref);
+}
+
 void ldlm_namespace_put(struct ldlm_namespace *ns)
 {
 	if (atomic_dec_and_lock(&ns->ns_bref, &ns->ns_lock)) {
@@ -967,8 +969,8 @@
 {
 	mutex_lock(ldlm_namespace_lock(client));
 	LASSERT(list_empty(&ns->ns_list_chain));
-	list_add(&ns->ns_list_chain, ldlm_namespace_list(client));
-	atomic_inc(ldlm_namespace_nr(client));
+	list_add(&ns->ns_list_chain, ldlm_namespace_inactive_list(client));
+	ldlm_namespace_nr_inc(client);
 	mutex_unlock(ldlm_namespace_lock(client));
 }
 
@@ -981,12 +983,13 @@
 	 * using list_empty(&ns->ns_list_chain). This is why it is
 	 * important to use list_del_init() here. */
 	list_del_init(&ns->ns_list_chain);
-	atomic_dec(ldlm_namespace_nr(client));
+	ldlm_namespace_nr_dec(client);
 	mutex_unlock(ldlm_namespace_lock(client));
 }
 
 /** Should be called with ldlm_namespace_lock(client) taken. */
-void ldlm_namespace_move_locked(struct ldlm_namespace *ns, ldlm_side_t client)
+void ldlm_namespace_move_to_active_locked(struct ldlm_namespace *ns,
+					  ldlm_side_t client)
 {
 	LASSERT(!list_empty(&ns->ns_list_chain));
 	LASSERT(mutex_is_locked(ldlm_namespace_lock(client)));
@@ -994,6 +997,16 @@
 }
 
 /** Should be called with ldlm_namespace_lock(client) taken. */
+void ldlm_namespace_move_to_inactive_locked(struct ldlm_namespace *ns,
+					    ldlm_side_t client)
+{
+	LASSERT(!list_empty(&ns->ns_list_chain));
+	LASSERT(mutex_is_locked(ldlm_namespace_lock(client)));
+	list_move_tail(&ns->ns_list_chain,
+		       ldlm_namespace_inactive_list(client));
+}
+
+/** Should be called with ldlm_namespace_lock(client) taken. */
 struct ldlm_namespace *ldlm_namespace_first_locked(ldlm_side_t client)
 {
 	LASSERT(mutex_is_locked(ldlm_namespace_lock(client)));
@@ -1049,6 +1062,7 @@
 	struct ldlm_resource *res;
 	cfs_hash_bd_t	 bd;
 	__u64		 version;
+	int		      ns_refcount = 0;
 
 	LASSERT(ns != NULL);
 	LASSERT(parent == NULL);
@@ -1119,7 +1133,7 @@
 	/* We won! Let's add the resource. */
 	cfs_hash_bd_add_locked(ns->ns_rs_hash, &bd, &res->lr_hash);
 	if (cfs_hash_bd_count_get(&bd) == 1)
-		ldlm_namespace_get(ns);
+		ns_refcount = ldlm_namespace_get_return(ns);
 
 	cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
 	if (ns->ns_lvbo && ns->ns_lvbo->lvbo_init) {
@@ -1128,8 +1142,9 @@
 		OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CREATE_RESOURCE, 2);
 		rc = ns->ns_lvbo->lvbo_init(res);
 		if (rc < 0) {
-			CERROR("lvbo_init failed for resource "
-			       LPU64": rc %d\n", name->name[0], rc);
+			CERROR("%s: lvbo_init failed for resource "LPX64":"
+			       LPX64": rc = %d\n", ns->ns_obd->obd_name,
+			       name->name[0], name->name[1], rc);
 			if (res->lr_lvb_data) {
 				OBD_FREE(res->lr_lvb_data, res->lr_lvb_len);
 				res->lr_lvb_data = NULL;
@@ -1144,6 +1159,16 @@
 	/* We create resource with locked lr_lvb_mutex. */
 	mutex_unlock(&res->lr_lvb_mutex);
 
+	/* Let's see if we happened to be the very first resource in this
+	 * namespace. If so, and this is a client namespace, we need to move
+	 * the namespace into the active namespaces list to be patrolled by
+	 * the ldlm_poold. */
+	if (ns_is_client(ns) && ns_refcount == 1) {
+		mutex_lock(ldlm_namespace_lock(LDLM_NAMESPACE_CLIENT));
+		ldlm_namespace_move_to_active_locked(ns, LDLM_NAMESPACE_CLIENT);
+		mutex_unlock(ldlm_namespace_lock(LDLM_NAMESPACE_CLIENT));
+	}
+
 	return res;
 }
 EXPORT_SYMBOL(ldlm_resource_get);
@@ -1249,7 +1274,7 @@
 
 	LDLM_DEBUG(lock, "About to add this lock:\n");
 
-	if (lock->l_destroyed) {
+	if (lock->l_flags & LDLM_FL_DESTROYED) {
 		CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
 		return;
 	}
@@ -1274,7 +1299,7 @@
 	ldlm_resource_dump(D_INFO, res);
 	LDLM_DEBUG(new, "About to insert this lock after %p:\n", original);
 
-	if (new->l_destroyed) {
+	if (new->l_flags & LDLM_FL_DESTROYED) {
 		CDEBUG(D_OTHER, "Lock destroyed, not adding to resource\n");
 		goto out;
 	}
diff --git a/drivers/staging/lustre/lustre/libcfs/Makefile b/drivers/staging/lustre/lustre/libcfs/Makefile
index bf5c563..6e489d7 100644
--- a/drivers/staging/lustre/lustre/libcfs/Makefile
+++ b/drivers/staging/lustre/lustre/libcfs/Makefile
@@ -11,7 +11,7 @@
 libcfs-linux-objs := $(addprefix linux/,$(libcfs-linux-objs))
 
 libcfs-all-objs := debug.o fail.o nidstrings.o module.o tracefile.o \
-		   watchdog.o libcfs_string.o hash.o kernel_user_comm.o \
+		   libcfs_string.o hash.o kernel_user_comm.o \
 		   prng.o workitem.o upcall_cache.o libcfs_cpu.o \
 		   libcfs_mem.o libcfs_lock.o
 
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index 5a87b08..9b9c451 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -335,9 +335,10 @@
  */
 void libcfs_debug_dumplog_internal(void *arg)
 {
-	DECL_JOURNAL_DATA;
+	void *journal_info;
 
-	PUSH_JOURNAL;
+	journal_info = current->journal_info;
+	current->journal_info = NULL;
 
 	if (strncmp(libcfs_debug_file_path_arr, "NONE", 4) != 0) {
 		snprintf(debug_file_name, sizeof(debug_file_name) - 1,
@@ -348,7 +349,8 @@
 		cfs_tracefile_dump_all_pages(debug_file_name);
 		libcfs_run_debug_log_upcall(debug_file_name);
 	}
-	POP_JOURNAL;
+
+	current->journal_info = journal_info;
 }
 
 int libcfs_debug_dumplog_thread(void *arg)
@@ -361,8 +363,7 @@
 void libcfs_debug_dumplog(void)
 {
 	wait_queue_t wait;
-	task_t    *dumper;
-	ENTRY;
+	struct task_struct *dumper;
 
 	/* we're being careful to ensure that the kernel thread is
 	 * able to set our state to running as it exits before we
@@ -459,14 +460,6 @@
 
 EXPORT_SYMBOL(libcfs_debug_set_level);
 
-long libcfs_log_return(struct libcfs_debug_msg_data *msgdata, long rc)
-{
-	libcfs_debug_msg(msgdata, "Process leaving (rc=%lu : %ld : %lx)\n",
-			 rc, rc, rc);
-	return rc;
-}
-EXPORT_SYMBOL(libcfs_log_return);
-
 void libcfs_log_goto(struct libcfs_debug_msg_data *msgdata, const char *label,
 		     long_ptr_t rc)
 {
diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c
index 98c76df..0dd12c8 100644
--- a/drivers/staging/lustre/lustre/libcfs/hash.c
+++ b/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -1026,8 +1026,6 @@
 	cfs_hash_t *hs;
 	int	 len;
 
-	ENTRY;
-
 	CLASSERT(CFS_HASH_THETA_BITS < 15);
 
 	LASSERT(name != NULL);
@@ -1055,7 +1053,7 @@
 	      CFS_HASH_NAME_LEN : CFS_HASH_BIGNAME_LEN;
 	LIBCFS_ALLOC(hs, offsetof(cfs_hash_t, hs_name[len]));
 	if (hs == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	strncpy(hs->hs_name, name, len);
 	hs->hs_name[len - 1] = '\0';
@@ -1087,7 +1085,7 @@
 		return hs;
 
 	LIBCFS_FREE(hs, offsetof(cfs_hash_t, hs_name[len]));
-	RETURN(NULL);
+	return NULL;
 }
 EXPORT_SYMBOL(cfs_hash_create);
 
@@ -1101,7 +1099,6 @@
 	struct hlist_node     *pos;
 	cfs_hash_bd_t	 bd;
 	int		   i;
-	ENTRY;
 
 	LASSERT(hs != NULL);
 	LASSERT(!cfs_hash_is_exiting(hs) &&
@@ -1152,8 +1149,6 @@
 	i = cfs_hash_with_bigname(hs) ?
 	    CFS_HASH_BIGNAME_LEN : CFS_HASH_NAME_LEN;
 	LIBCFS_FREE(hs, offsetof(cfs_hash_t, hs_name[i]));
-
-	EXIT;
 }
 
 cfs_hash_t *cfs_hash_getref(cfs_hash_t *hs)
@@ -1449,7 +1444,6 @@
 	int		   excl  = !!remove_safe;
 	int		   loop  = 0;
 	int		   i;
-	ENTRY;
 
 	cfs_hash_for_each_enter(hs);
 
@@ -1489,7 +1483,7 @@
 	cfs_hash_unlock(hs, 0);
 
 	cfs_hash_for_each_exit(hs);
-	RETURN(count);
+	return count;
 }
 
 typedef struct {
@@ -1594,7 +1588,6 @@
 	int	       stop_on_change;
 	int	       rc;
 	int	       i;
-	ENTRY;
 
 	stop_on_change = cfs_hash_with_rehash_key(hs) ||
 			 !cfs_hash_with_no_itemref(hs) ||
@@ -1649,23 +1642,21 @@
 cfs_hash_for_each_nolock(cfs_hash_t *hs,
 			 cfs_hash_for_each_cb_t func, void *data)
 {
-	ENTRY;
-
 	if (cfs_hash_with_no_lock(hs) ||
 	    cfs_hash_with_rehash_key(hs) ||
 	    !cfs_hash_with_no_itemref(hs))
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	if (CFS_HOP(hs, get) == NULL ||
 	    (CFS_HOP(hs, put) == NULL &&
 	     CFS_HOP(hs, put_locked) == NULL))
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	cfs_hash_for_each_enter(hs);
 	cfs_hash_for_each_relax(hs, func, data);
 	cfs_hash_for_each_exit(hs);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(cfs_hash_for_each_nolock);
 
@@ -1685,7 +1676,6 @@
 			cfs_hash_for_each_cb_t func, void *data)
 {
 	unsigned  i = 0;
-	ENTRY;
 
 	if (cfs_hash_with_no_lock(hs))
 		return -EOPNOTSUPP;
@@ -1701,7 +1691,7 @@
 		       hs->hs_name, i++);
 	}
 	cfs_hash_for_each_exit(hs);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(cfs_hash_for_each_empty);
 
diff --git a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
index d6d3b2e..74a0db5 100644
--- a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
+++ b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
@@ -246,10 +246,9 @@
 int libcfs_kkuc_group_rem(int uid, int group)
 {
 	struct kkuc_reg *reg, *next;
-	ENTRY;
 
 	if (kkuc_groups[group].next == NULL)
-		RETURN(0);
+		return 0;
 
 	if (uid == 0) {
 		/* Broadcast a shutdown message */
@@ -275,7 +274,7 @@
 	}
 	up_write(&kg_sem);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(libcfs_kkuc_group_rem);
 
@@ -284,7 +283,6 @@
 	struct kkuc_reg	*reg;
 	int		 rc = 0;
 	int one_success = 0;
-	ENTRY;
 
 	down_read(&kg_sem);
 	list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
@@ -305,7 +303,7 @@
 	if (one_success)
 		rc = 0;
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(libcfs_kkuc_group_put);
 
@@ -320,16 +318,15 @@
 {
 	struct kkuc_reg *reg;
 	int rc = 0;
-	ENTRY;
 
 	if (group > KUC_GRP_MAX) {
 		CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* no link for this group */
 	if (kkuc_groups[group].next == NULL)
-		RETURN(0);
+		return 0;
 
 	down_read(&kg_sem);
 	list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
@@ -339,7 +336,7 @@
 	}
 	up_read(&kg_sem);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(libcfs_kkuc_group_foreach);
 
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c
index 8e88eb5..1fb3700 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c
@@ -33,9 +33,6 @@
  * Author: liang@whamcloud.com
  */
 
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
 #define DEBUG_SUBSYSTEM S_LNET
 
 #include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c b/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
index 8d6c4ad..a2ce4c0 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_lock.c
@@ -30,9 +30,6 @@
  * Author: liang@whamcloud.com
  */
 
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
 #define DEBUG_SUBSYSTEM S_LNET
 
 #include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c b/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
index 8791373..feab537 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_mem.c
@@ -31,9 +31,6 @@
  * Author: liang@whamcloud.com
  */
 
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
 #define DEBUG_SUBSYSTEM S_LNET
 
 #include <linux/libcfs/libcfs.h>
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
index 9edccc9..922debd 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
@@ -69,7 +69,6 @@
 	const char *debugstr;
 	char op = 0;
 	int newmask = minmask, i, len, found = 0;
-	ENTRY;
 
 	/* <str> must be a list of tokens separated by whitespace
 	 * and optionally an operator ('+' or '-').  If an operator
@@ -132,54 +131,6 @@
 }
 EXPORT_SYMBOL(cfs_str2mask);
 
-/* Duplicate a string in a platform-independent way */
-char *cfs_strdup(const char *str, u_int32_t flags)
-{
-	size_t lenz; /* length of str + zero byte */
-	char *dup_str;
-
-	lenz = strlen(str) + 1;
-
-	dup_str = kmalloc(lenz, flags);
-	if (dup_str == NULL)
-		return NULL;
-
-	memcpy(dup_str, str, lenz);
-
-	return dup_str;
-}
-EXPORT_SYMBOL(cfs_strdup);
-
-/**
- * cfs_{v}snprintf() return the actual size that is printed rather than
- * the size that would be printed in standard functions.
- */
-/* safe vsnprintf */
-int cfs_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
-{
-	int i;
-
-	LASSERT(size > 0);
-	i = vsnprintf(buf, size, fmt, args);
-
-	return  (i >= size ? size - 1 : i);
-}
-EXPORT_SYMBOL(cfs_vsnprintf);
-
-/* safe snprintf */
-int cfs_snprintf(char *buf, size_t size, const char *fmt, ...)
-{
-	va_list args;
-	int i;
-
-	va_start(args, fmt);
-	i = cfs_vsnprintf(buf, size, fmt, args);
-	va_end(args);
-
-	return  i;
-}
-EXPORT_SYMBOL(cfs_snprintf);
-
 /* get the first string out of @str */
 char *cfs_firststr(char *str, size_t size)
 {
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
index 95142d1..00ab8fd 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c
@@ -76,62 +76,22 @@
 
 static struct cfs_cpt_data	cpt_data;
 
-void
-cfs_cpu_core_siblings(int cpu, cpumask_t *mask)
+static void cfs_cpu_core_siblings(int cpu, cpumask_t *mask)
 {
 	/* return cpumask of cores in the same socket */
 	cpumask_copy(mask, topology_core_cpumask(cpu));
 }
-EXPORT_SYMBOL(cfs_cpu_core_siblings);
-
-/* return number of cores in the same socket of \a cpu */
-int
-cfs_cpu_core_nsiblings(int cpu)
-{
-	int	num;
-
-	down(&cpt_data.cpt_mutex);
-
-	cfs_cpu_core_siblings(cpu, cpt_data.cpt_cpumask);
-	num = cpus_weight(*cpt_data.cpt_cpumask);
-
-	up(&cpt_data.cpt_mutex);
-
-	return num;
-}
-EXPORT_SYMBOL(cfs_cpu_core_nsiblings);
 
 /* return cpumask of HTs in the same core */
-void
-cfs_cpu_ht_siblings(int cpu, cpumask_t *mask)
+static void cfs_cpu_ht_siblings(int cpu, cpumask_t *mask)
 {
 	cpumask_copy(mask, topology_thread_cpumask(cpu));
 }
-EXPORT_SYMBOL(cfs_cpu_ht_siblings);
 
-/* return number of HTs in the same core of \a cpu */
-int
-cfs_cpu_ht_nsiblings(int cpu)
-{
-	int	num;
-
-	down(&cpt_data.cpt_mutex);
-
-	cfs_cpu_ht_siblings(cpu, cpt_data.cpt_cpumask);
-	num = cpus_weight(*cpt_data.cpt_cpumask);
-
-	up(&cpt_data.cpt_mutex);
-
-	return num;
-}
-EXPORT_SYMBOL(cfs_cpu_ht_nsiblings);
-
-void
-cfs_node_to_cpumask(int node, cpumask_t *mask)
+static void cfs_node_to_cpumask(int node, cpumask_t *mask)
 {
 	cpumask_copy(mask, cpumask_of_node(node));
 }
-EXPORT_SYMBOL(cfs_node_to_cpumask);
 
 void
 cfs_cpt_table_free(struct cfs_cpt_table *cptab)
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
index 8e35777..b6c79bc 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c
@@ -274,6 +274,8 @@
 
 int cfs_crypto_register(void)
 {
+	request_module("crc32c");
+
 	adler32 = cfs_crypto_adler32_register();
 
 	/* check all algorithms and do performance test */
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
index f236510..ea9e949 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
@@ -65,20 +65,6 @@
 	return nr;
 }
 
-void   cfs_curproc_groups_dump(gid_t *array, int size)
-{
-	task_lock(current);
-	size = min_t(int, size, current_cred()->group_info->ngroups);
-	memcpy(array, current_cred()->group_info->blocks[0], size * sizeof(__u32));
-	task_unlock(current);
-}
-
-
-int    current_is_in_group(gid_t gid)
-{
-	return in_group_p(gid);
-}
-
 /* Currently all the CFS_CAP_* defines match CAP_* ones. */
 #define cfs_cap_pack(cap) (cap)
 #define cfs_cap_unpack(cap) (cap)
@@ -226,16 +212,15 @@
 	int key_len = strlen(key);
 	unsigned long addr;
 	int rc;
-	ENTRY;
 
 	buffer = kmalloc(buf_len, GFP_USER);
 	if (!buffer)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mm = get_task_mm(current);
 	if (!mm) {
 		kfree(buffer);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* Avoid deadlocks on mmap_sem if called from sys_mmap_pgoff(),
@@ -318,8 +303,6 @@
 EXPORT_SYMBOL(cfs_get_environ);
 
 EXPORT_SYMBOL(cfs_curproc_groups_nr);
-EXPORT_SYMBOL(cfs_curproc_groups_dump);
-EXPORT_SYMBOL(current_is_in_group);
 EXPORT_SYMBOL(cfs_cap_raise);
 EXPORT_SYMBOL(cfs_cap_lower);
 EXPORT_SYMBOL(cfs_cap_raised);
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
index e2c195b..ab1e7316 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-debug.c
@@ -48,14 +48,10 @@
 #include <linux/errno.h>
 #include <linux/unistd.h>
 #include <linux/interrupt.h>
-#include <asm/uaccess.h>
 #include <linux/completion.h>
-
 #include <linux/fs.h>
-#include <linux/stat.h>
 #include <asm/uaccess.h>
 #include <linux/miscdevice.h>
-#include <linux/version.h>
 
 # define DEBUG_SUBSYSTEM S_LNET
 
@@ -82,7 +78,6 @@
 		"HOME=/",
 		"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
 		NULL};
-	ENTRY;
 
 	argv[0] = lnet_debug_log_upcall;
 
@@ -100,8 +95,6 @@
 		CDEBUG(D_HA, "Invoked LNET debug log upcall %s %s\n",
 		       argv[0], argv[1]);
 	}
-
-	EXIT;
 }
 
 void libcfs_run_upcall(char **argv)
@@ -112,7 +105,6 @@
 		"HOME=/",
 		"PATH=/sbin:/bin:/usr/sbin:/usr/bin",
 		NULL};
-	ENTRY;
 
 	argv[0] = lnet_upcall;
 	argc = 1;
@@ -145,7 +137,6 @@
 	char *argv[6];
 	char buf[32];
 
-	ENTRY;
 	snprintf (buf, sizeof buf, "%d", msgdata->msg_line);
 
 	argv[1] = "LBUG";
@@ -168,7 +159,7 @@
 		/* not reached */
 	}
 
-	libcfs_debug_dumpstack(NULL);
+	dump_stack();
 	if (!libcfs_panic_on_lbug)
 		libcfs_debug_dumplog();
 	libcfs_run_lbug_upcall(msgdata);
@@ -179,54 +170,6 @@
 		schedule();
 }
 
-
-#include <linux/nmi.h>
-#include <asm/stacktrace.h>
-
-
-static int print_trace_stack(void *data, char *name)
-{
-	printk(" <%s> ", name);
-	return 0;
-}
-
-# define RELIABLE reliable
-# define DUMP_TRACE_CONST const
-static void print_trace_address(void *data, unsigned long addr, int reliable)
-{
-	char fmt[32];
-	touch_nmi_watchdog();
-	sprintf(fmt, " [<%016lx>] %s%%s\n", addr, RELIABLE ? "": "? ");
-	__print_symbol(fmt, addr);
-}
-
-static DUMP_TRACE_CONST struct stacktrace_ops print_trace_ops = {
-	.stack = print_trace_stack,
-	.address = print_trace_address,
-	.walk_stack = print_context_stack,
-};
-
-void libcfs_debug_dumpstack(struct task_struct *tsk)
-{
-	/* dump_stack() */
-	/* show_trace() */
-	if (tsk == NULL)
-		tsk = current;
-	printk("Pid: %d, comm: %.20s\n", tsk->pid, tsk->comm);
-	/* show_trace_log_lvl() */
-	printk("\nCall Trace:\n");
-	dump_trace(tsk, NULL, NULL,
-		   0,
-		   &print_trace_ops, NULL);
-	printk("\n");
-}
-
-task_t *libcfs_current(void)
-{
-	CWARN("current task struct is %p\n", current);
-	return current;
-}
-
 static int panic_notifier(struct notifier_block *self, unsigned long unused1,
 			 void *unused2)
 {
@@ -240,9 +183,9 @@
 }
 
 static struct notifier_block libcfs_panic_notifier = {
-	notifier_call :     panic_notifier,
-	next :	      NULL,
-	priority :	  10000
+	.notifier_call	= panic_notifier,
+	.next		= NULL,
+	.priority	= 10000,
 };
 
 void libcfs_register_panic_notifier(void)
@@ -255,10 +198,6 @@
 	atomic_notifier_chain_unregister(&panic_notifier_list, &libcfs_panic_notifier);
 }
 
-EXPORT_SYMBOL(libcfs_debug_dumpstack);
-EXPORT_SYMBOL(libcfs_current);
-
-
 EXPORT_SYMBOL(libcfs_run_upcall);
 EXPORT_SYMBOL(libcfs_run_lbug_upcall);
 EXPORT_SYMBOL(lbug_with_loc);
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
index 2c7d4a3..55296a3 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c
@@ -45,38 +45,37 @@
 	struct libcfs_ioctl_hdr   *hdr;
 	struct libcfs_ioctl_data  *data;
 	int err;
-	ENTRY;
 
 	hdr = (struct libcfs_ioctl_hdr *)buf;
 	data = (struct libcfs_ioctl_data *)buf;
 
 	err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
 	if (err)
-		RETURN(err);
+		return err;
 
 	if (hdr->ioc_version != LIBCFS_IOCTL_VERSION) {
 		CERROR("PORTALS: version mismatch kernel vs application\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (hdr->ioc_len + buf >= end) {
 		CERROR("PORTALS: user buffer exceeds kernel buffer\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 
 	if (hdr->ioc_len < sizeof(struct libcfs_ioctl_data)) {
 		CERROR("PORTALS: user buffer too small for ioctl\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
 	if (err)
-		RETURN(err);
+		return err;
 
 	if (libcfs_ioctl_is_invalid(data)) {
 		CERROR("PORTALS: ioctl not correctly formatted\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (data->ioc_inllen1)
@@ -86,7 +85,7 @@
 		data->ioc_inlbuf2 = &data->ioc_bulk[0] +
 			cfs_size_round(data->ioc_inllen1);
 
-	RETURN(0);
+	return 0;
 }
 
 int libcfs_ioctl_popdata(void *arg, void *data, int size)
@@ -137,7 +136,7 @@
 	struct cfs_psdev_file	 pfile;
 	int    rc = 0;
 
-	if (current_fsuid() != 0)
+	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
 	if ( _IOC_TYPE(cmd) != IOC_LIBCFS_TYPE ||
@@ -171,13 +170,13 @@
 }
 
 static struct file_operations libcfs_fops = {
-	unlocked_ioctl: libcfs_ioctl,
-	open :	  libcfs_psdev_open,
-	release :       libcfs_psdev_release
+	.unlocked_ioctl	= libcfs_ioctl,
+	.open		= libcfs_psdev_open,
+	.release	= libcfs_psdev_release,
 };
 
-psdev_t libcfs_dev = {
-	LNET_MINOR,
-	"lnet",
-	&libcfs_fops
+struct miscdevice libcfs_dev = {
+	.minor = LNET_MINOR,
+	.name = "lnet",
+	.fops = &libcfs_fops,
 };
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
index b652a79..cc9829f 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-prim.c
@@ -81,22 +81,21 @@
 EXPORT_SYMBOL(add_wait_queue_exclusive_head);
 
 void
-waitq_wait(wait_queue_t *link, cfs_task_state_t state)
+waitq_wait(wait_queue_t *link, long state)
 {
 	schedule();
 }
 EXPORT_SYMBOL(waitq_wait);
 
 int64_t
-waitq_timedwait(wait_queue_t *link, cfs_task_state_t state,
-		    int64_t timeout)
+waitq_timedwait(wait_queue_t *link, long state, int64_t timeout)
 {
 	return schedule_timeout(timeout);
 }
 EXPORT_SYMBOL(waitq_timedwait);
 
 void
-schedule_timeout_and_set_state(cfs_task_state_t state, int64_t timeout)
+schedule_timeout_and_set_state(long state, int64_t timeout)
 {
 	set_current_state(state);
 	schedule_timeout(timeout);
@@ -112,13 +111,13 @@
 }
 EXPORT_SYMBOL(cfs_pause);
 
-void cfs_init_timer(timer_list_t *t)
+void cfs_init_timer(struct timer_list *t)
 {
 	init_timer(t);
 }
 EXPORT_SYMBOL(cfs_init_timer);
 
-void cfs_timer_init(timer_list_t *t, cfs_timer_func_t *func, void *arg)
+void cfs_timer_init(struct timer_list *t, cfs_timer_func_t *func, void *arg)
 {
 	init_timer(t);
 	t->function = func;
@@ -126,31 +125,31 @@
 }
 EXPORT_SYMBOL(cfs_timer_init);
 
-void cfs_timer_done(timer_list_t *t)
+void cfs_timer_done(struct timer_list *t)
 {
 	return;
 }
 EXPORT_SYMBOL(cfs_timer_done);
 
-void cfs_timer_arm(timer_list_t *t, cfs_time_t deadline)
+void cfs_timer_arm(struct timer_list *t, cfs_time_t deadline)
 {
 	mod_timer(t, deadline);
 }
 EXPORT_SYMBOL(cfs_timer_arm);
 
-void cfs_timer_disarm(timer_list_t *t)
+void cfs_timer_disarm(struct timer_list *t)
 {
 	del_timer(t);
 }
 EXPORT_SYMBOL(cfs_timer_disarm);
 
-int  cfs_timer_is_armed(timer_list_t *t)
+int  cfs_timer_is_armed(struct timer_list *t)
 {
 	return timer_pending(t);
 }
 EXPORT_SYMBOL(cfs_timer_is_armed);
 
-cfs_time_t cfs_timer_deadline(timer_list_t *t)
+cfs_time_t cfs_timer_deadline(struct timer_list *t)
 {
 	return t->expires;
 }
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
index 522b28e..fc6c977 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
@@ -54,9 +54,7 @@
 
 #include <linux/fs.h>
 #include <linux/file.h>
-#include <linux/stat.h>
 #include <linux/list.h>
-#include <asm/uaccess.h>
 
 #include <linux/proc_fs.h>
 #include <linux/sysctl.h>
@@ -564,7 +562,7 @@
 {
 #ifdef CONFIG_SYSCTL
 	if (lnet_table_header == NULL)
-		lnet_table_header = cfs_register_sysctl_table(top_table, 0);
+		lnet_table_header = register_sysctl_table(top_table);
 #endif
 	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
index 855c7e8..e6069d7 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
@@ -36,7 +36,6 @@
 #define DEBUG_SUBSYSTEM S_LNET
 
 #include <linux/libcfs/libcfs.h>
-#include <linux/libcfs/libcfs.h>
 
 #include <linux/if.h>
 #include <linux/in.h>
@@ -641,8 +640,8 @@
 	*fatal = !(rc == -EADDRNOTAVAIL);
 
 	CDEBUG_LIMIT(*fatal ? D_NETERROR : D_NET,
-	       "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc,
-	       HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port);
+	       "Error %d connecting %pI4h/%d -> %pI4h/%d\n", rc,
+	       &local_ip, local_port, &peer_ip, peer_port);
 
 	sock_release(*sockp);
 	return rc;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
index 6f56343..162beee 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
@@ -51,7 +51,7 @@
 
 struct rw_semaphore cfs_tracefile_sem;
 
-int cfs_tracefile_init_arch()
+int cfs_tracefile_init_arch(void)
 {
 	int    i;
 	int    j;
@@ -96,7 +96,7 @@
 	return -ENOMEM;
 }
 
-void cfs_tracefile_fini_arch()
+void cfs_tracefile_fini_arch(void)
 {
 	int    i;
 	int    j;
@@ -116,27 +116,27 @@
 	fini_rwsem(&cfs_tracefile_sem);
 }
 
-void cfs_tracefile_read_lock()
+void cfs_tracefile_read_lock(void)
 {
 	down_read(&cfs_tracefile_sem);
 }
 
-void cfs_tracefile_read_unlock()
+void cfs_tracefile_read_unlock(void)
 {
 	up_read(&cfs_tracefile_sem);
 }
 
-void cfs_tracefile_write_lock()
+void cfs_tracefile_write_lock(void)
 {
 	down_write(&cfs_tracefile_sem);
 }
 
-void cfs_tracefile_write_unlock()
+void cfs_tracefile_write_unlock(void)
 {
 	up_write(&cfs_tracefile_sem);
 }
 
-cfs_trace_buf_type_t cfs_trace_buf_idx_get()
+cfs_trace_buf_type_t cfs_trace_buf_idx_get(void)
 {
 	if (in_irq())
 		return CFS_TCD_TYPE_IRQ;
@@ -269,7 +269,7 @@
 
 int cfs_trace_max_debug_mb(void)
 {
-	int  total_mb = (num_physpages >> (20 - PAGE_SHIFT));
+	int  total_mb = (totalram_pages >> (20 - PAGE_SHIFT));
 
 	return MAX(512, (total_mb * 80)/100);
 }
diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c
index 3372537..f3108c7 100644
--- a/drivers/staging/lustre/lustre/libcfs/module.c
+++ b/drivers/staging/lustre/lustre/libcfs/module.c
@@ -155,7 +155,6 @@
 static int libcfs_psdev_open(unsigned long flags, void *args)
 {
 	struct libcfs_device_userstate *ldu;
-	ENTRY;
 
 	try_module_get(THIS_MODULE);
 
@@ -166,14 +165,13 @@
 	}
 	*(struct libcfs_device_userstate **)args = ldu;
 
-	RETURN(0);
+	return 0;
 }
 
 /* called when closing /dev/device */
 static int libcfs_psdev_release(unsigned long flags, void *args)
 {
 	struct libcfs_device_userstate *ldu;
-	ENTRY;
 
 	ldu = (struct libcfs_device_userstate *)args;
 	if (ldu != NULL) {
@@ -182,7 +180,7 @@
 	}
 
 	module_put(THIS_MODULE);
-	RETURN(0);
+	return 0;
 }
 
 static struct rw_semaphore ioctl_list_sem;
@@ -222,12 +220,11 @@
 			    void *arg, struct libcfs_ioctl_data *data)
 {
 	int err = -EINVAL;
-	ENTRY;
 
 	switch (cmd) {
 	case IOC_LIBCFS_CLEAR_DEBUG:
 		libcfs_debug_clear_buffer();
-		RETURN(0);
+		return 0;
 	/*
 	 * case IOC_LIBCFS_PANIC:
 	 * Handled in arch/cfs_module.c
@@ -235,9 +232,9 @@
 	case IOC_LIBCFS_MARK_DEBUG:
 		if (data->ioc_inlbuf1 == NULL ||
 		    data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
-			RETURN(-EINVAL);
+			return -EINVAL;
 		libcfs_debug_mark_buffer(data->ioc_inlbuf1);
-		RETURN(0);
+		return 0;
 #if LWT_SUPPORT
 	case IOC_LIBCFS_LWT_CONTROL:
 		err = lwt_control ((data->ioc_flags & 1) != 0,
@@ -301,7 +298,7 @@
 			ping(data);
 			symbol_put(kping_client);
 		}
-		RETURN(0);
+		return 0;
 	}
 
 	default: {
@@ -322,7 +319,7 @@
 	}
 	}
 
-	RETURN(err);
+	return err;
 }
 
 static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
@@ -330,11 +327,10 @@
 	char    *buf;
 	struct libcfs_ioctl_data *data;
 	int err = 0;
-	ENTRY;
 
 	LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS);
 	if (buf == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* 'cmd' and permissions get checked in our arch-specific caller */
 	if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) {
@@ -347,7 +343,7 @@
 
 out:
 	LIBCFS_FREE(buf, 1024);
-	RETURN(err);
+	return err;
 }
 
 
@@ -365,7 +361,7 @@
 MODULE_DESCRIPTION("Portals v3.1");
 MODULE_LICENSE("GPL");
 
-extern psdev_t libcfs_dev;
+extern struct miscdevice libcfs_dev;
 extern struct rw_semaphore cfs_tracefile_sem;
 extern struct mutex cfs_trace_thread_mutex;
 extern struct cfs_wi_sched *cfs_sched_rehash;
@@ -495,4 +491,6 @@
 	libcfs_arch_cleanup();
 }
 
-cfs_module(libcfs, "1.0.0", init_libcfs_module, exit_libcfs_module);
+MODULE_VERSION("1.0.0");
+module_init(init_libcfs_module);
+module_exit(exit_libcfs_module);
diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
index ccfd107..99c9e9d 100644
--- a/drivers/staging/lustre/lustre/libcfs/nidstrings.c
+++ b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
@@ -785,7 +785,6 @@
 	struct cfs_lstr src;
 	struct cfs_lstr res;
 	int rc;
-	ENTRY;
 
 	src.ls_str = str;
 	src.ls_len = len;
@@ -794,15 +793,15 @@
 		rc = cfs_gettok(&src, ' ', &res);
 		if (rc == 0) {
 			cfs_free_nidlist(nidlist);
-			RETURN(0);
+			return 0;
 		}
 		rc = parse_nidrange(&res, nidlist);
 		if (rc == 0) {
 			cfs_free_nidlist(nidlist);
-			RETURN(0);
+			return 0;
 		}
 	}
-	RETURN(1);
+	return 1;
 }
 
 /*
@@ -834,7 +833,6 @@
 {
 	struct nidrange *nr;
 	struct addrrange *ar;
-	ENTRY;
 
 	list_for_each_entry(nr, nidlist, nr_link) {
 		if (nr->nr_netstrfns->nf_type != LNET_NETTYP(LNET_NIDNET(nid)))
@@ -842,13 +840,13 @@
 		if (nr->nr_netnum != LNET_NETNUM(LNET_NIDNET(nid)))
 			continue;
 		if (nr->nr_all)
-			RETURN(1);
+			return 1;
 		list_for_each_entry(ar, &nr->nr_addrranges, ar_link)
 			if (nr->nr_netstrfns->nf_match_addr(LNET_NIDADDR(nid),
 						       &ar->ar_numaddr_ranges))
-				RETURN(1);
+				return 1;
 	}
-	RETURN(0);
+	return 0;
 }
 
 
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index 439e71d..357f400 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -275,12 +275,9 @@
 	int			i;
 	int			remain;
 	int			mask = msgdata->msg_mask;
-	char		      *file = (char *)msgdata->msg_file;
+	const char		*file = kbasename(msgdata->msg_file);
 	cfs_debug_limit_state_t   *cdls = msgdata->msg_cdls;
 
-	if (strchr(file, '/'))
-		file = strrchr(file, '/') + 1;
-
 	tcd = cfs_trace_get_tcd();
 
 	/* cfs_trace_get_tcd() grabs a lock, which disables preemption and
@@ -529,7 +526,7 @@
 	int i, cpu;
 
 	spin_lock(&pc->pc_lock);
-	cfs_for_each_possible_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		cfs_tcd_for_each_type_lock(tcd, i, cpu) {
 			list_splice_init(&tcd->tcd_pages, &pc->pc_pages);
 			tcd->tcd_cur_pages = 0;
@@ -562,7 +559,7 @@
 	int i, cpu;
 
 	spin_lock(&pc->pc_lock);
-	cfs_for_each_possible_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		cfs_tcd_for_each_type_lock(tcd, i, cpu) {
 			cur_head = tcd->tcd_pages.next;
 
@@ -630,7 +627,7 @@
 	struct cfs_trace_cpu_data *tcd;
 	int i, cpu;
 
-	cfs_for_each_possible_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		cfs_tcd_for_each_type_lock(tcd, i, cpu)
 			put_pages_on_tcd_daemon_list(pc, tcd);
 	}
@@ -1159,7 +1156,7 @@
 	struct cfs_trace_page *tmp;
 	int i, cpu;
 
-	cfs_for_each_possible_cpu(cpu) {
+	for_each_possible_cpu(cpu) {
 		cfs_tcd_for_each_type_lock(tcd, i, cpu) {
 			tcd->tcd_shutting_down = 1;
 
diff --git a/drivers/staging/lustre/lustre/libcfs/upcall_cache.c b/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
index 18c68c3..245b46f 100644
--- a/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
+++ b/drivers/staging/lustre/lustre/libcfs/upcall_cache.c
@@ -152,7 +152,6 @@
 	struct list_head *head;
 	wait_queue_t wait;
 	int rc, found;
-	ENTRY;
 
 	LASSERT(cache);
 
@@ -176,7 +175,7 @@
 			new = alloc_entry(cache, key, args);
 			if (!new) {
 				CERROR("fail to alloc entry\n");
-				RETURN(ERR_PTR(-ENOMEM));
+				return ERR_PTR(-ENOMEM);
 			}
 			goto find_again;
 		} else {
@@ -266,17 +265,14 @@
 	/* Now we know it's good */
 out:
 	spin_unlock(&cache->uc_lock);
-	RETURN(entry);
+	return entry;
 }
 EXPORT_SYMBOL(upcall_cache_get_entry);
 
 void upcall_cache_put_entry(struct upcall_cache *cache,
 			    struct upcall_cache_entry *entry)
 {
-	ENTRY;
-
 	if (!entry) {
-		EXIT;
 		return;
 	}
 
@@ -284,7 +280,6 @@
 	spin_lock(&cache->uc_lock);
 	put_entry(cache, entry);
 	spin_unlock(&cache->uc_lock);
-	EXIT;
 }
 EXPORT_SYMBOL(upcall_cache_put_entry);
 
@@ -294,7 +289,6 @@
 	struct upcall_cache_entry *entry = NULL;
 	struct list_head *head;
 	int found = 0, rc = 0;
-	ENTRY;
 
 	LASSERT(cache);
 
@@ -314,7 +308,7 @@
 		       cache->uc_name, key);
 		/* haven't found, it's possible */
 		spin_unlock(&cache->uc_lock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (err) {
@@ -356,7 +350,7 @@
 	wake_up_all(&entry->ue_waitq);
 	put_entry(cache, entry);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(upcall_cache_downcall);
 
@@ -364,7 +358,6 @@
 {
 	struct upcall_cache_entry *entry, *next;
 	int i;
-	ENTRY;
 
 	spin_lock(&cache->uc_lock);
 	for (i = 0; i < UC_CACHE_HASH_SIZE; i++) {
@@ -379,7 +372,6 @@
 		}
 	}
 	spin_unlock(&cache->uc_lock);
-	EXIT;
 }
 
 void upcall_cache_flush_idle(struct upcall_cache *cache)
@@ -399,7 +391,6 @@
 	struct list_head *head;
 	struct upcall_cache_entry *entry;
 	int found = 0;
-	ENTRY;
 
 	head = &cache->uc_hashtable[UC_CACHE_HASH_INDEX(key)];
 
@@ -431,11 +422,10 @@
 {
 	struct upcall_cache *cache;
 	int i;
-	ENTRY;
 
 	LIBCFS_ALLOC(cache, sizeof(*cache));
 	if (!cache)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	spin_lock_init(&cache->uc_lock);
 	rwlock_init(&cache->uc_upcall_rwlock);
@@ -448,7 +438,7 @@
 	cache->uc_acquire_expire = 30;
 	cache->uc_ops = ops;
 
-	RETURN(cache);
+	return cache;
 }
 EXPORT_SYMBOL(upcall_cache_init);
 
diff --git a/drivers/staging/lustre/lustre/libcfs/watchdog.c b/drivers/staging/lustre/lustre/libcfs/watchdog.c
deleted file mode 100644
index 7c385ad..0000000
--- a/drivers/staging/lustre/lustre/libcfs/watchdog.c
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Use is subject to license terms.
- *
- * Copyright (c) 2012, Intel Corporation.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
- *
- * libcfs/libcfs/watchdog.c
- *
- * Author: Jacob Berkman <jacob@clusterfs.com>
- */
-
-#define DEBUG_SUBSYSTEM S_LNET
-
-#include <linux/libcfs/libcfs.h>
-#include "tracefile.h"
-
-struct lc_watchdog {
-	spinlock_t  lcw_lock;     /* check or change lcw_list */
-	int	     lcw_refcount; /* must hold lcw_pending_timers_lock */
-	timer_list_t     lcw_timer;    /* kernel timer */
-	struct list_head      lcw_list;     /* chain on pending list */
-	cfs_time_t      lcw_last_touched; /* last touched stamp */
-	task_t     *lcw_task;     /* owner task */
-	void	  (*lcw_callback)(pid_t, void *);
-	void	   *lcw_data;
-
-	pid_t	   lcw_pid;
-
-	enum {
-		LC_WATCHDOG_DISABLED,
-		LC_WATCHDOG_ENABLED,
-		LC_WATCHDOG_EXPIRED
-	} lcw_state;
-};
-
-#ifdef WITH_WATCHDOG
-/*
- * The dispatcher will complete lcw_start_completion when it starts,
- * and lcw_stop_completion when it exits.
- * Wake lcw_event_waitq to signal timer callback dispatches.
- */
-static struct completion lcw_start_completion;
-static struct completion  lcw_stop_completion;
-static wait_queue_head_t lcw_event_waitq;
-
-/*
- * Set this and wake lcw_event_waitq to stop the dispatcher.
- */
-enum {
-	LCW_FLAG_STOP = 0
-};
-static unsigned long lcw_flags = 0;
-
-/*
- * Number of outstanding watchdogs.
- * When it hits 1, we start the dispatcher.
- * When it hits 0, we stop the dispatcher.
- */
-static __u32	 lcw_refcount = 0;
-static DEFINE_MUTEX(lcw_refcount_mutex);
-
-/*
- * List of timers that have fired that need their callbacks run by the
- * dispatcher.
- */
-/* BH lock! */
-static DEFINE_SPINLOCK(lcw_pending_timers_lock);
-static struct list_head lcw_pending_timers = LIST_HEAD_INIT(lcw_pending_timers);
-
-/* Last time a watchdog expired */
-static cfs_time_t lcw_last_watchdog_time;
-static int lcw_recent_watchdog_count;
-
-static void
-lcw_dump(struct lc_watchdog *lcw)
-{
-	ENTRY;
-	rcu_read_lock();
-       if (lcw->lcw_task == NULL) {
-		LCONSOLE_WARN("Process " LPPID " was not found in the task "
-			      "list; watchdog callback may be incomplete\n",
-			      (int)lcw->lcw_pid);
-	} else {
-		libcfs_debug_dumpstack(lcw->lcw_task);
-	}
-
-	rcu_read_unlock();
-	EXIT;
-}
-
-static void lcw_cb(ulong_ptr_t data)
-{
-	struct lc_watchdog *lcw = (struct lc_watchdog *)data;
-	ENTRY;
-
-	if (lcw->lcw_state != LC_WATCHDOG_ENABLED) {
-		EXIT;
-		return;
-	}
-
-	lcw->lcw_state = LC_WATCHDOG_EXPIRED;
-
-	spin_lock_bh(&lcw->lcw_lock);
-	LASSERT(list_empty(&lcw->lcw_list));
-
-	spin_lock_bh(&lcw_pending_timers_lock);
-	lcw->lcw_refcount++; /* +1 for pending list */
-	list_add(&lcw->lcw_list, &lcw_pending_timers);
-	wake_up(&lcw_event_waitq);
-
-	spin_unlock_bh(&lcw_pending_timers_lock);
-	spin_unlock_bh(&lcw->lcw_lock);
-	EXIT;
-}
-
-static int is_watchdog_fired(void)
-{
-	int rc;
-
-	if (test_bit(LCW_FLAG_STOP, &lcw_flags))
-		return 1;
-
-	spin_lock_bh(&lcw_pending_timers_lock);
-	rc = !list_empty(&lcw_pending_timers);
-	spin_unlock_bh(&lcw_pending_timers_lock);
-	return rc;
-}
-
-static void lcw_dump_stack(struct lc_watchdog *lcw)
-{
-	cfs_time_t      current_time;
-	cfs_duration_t  delta_time;
-	struct timeval  timediff;
-
-	current_time = cfs_time_current();
-	delta_time = cfs_time_sub(current_time, lcw->lcw_last_touched);
-	cfs_duration_usec(delta_time, &timediff);
-
-	/*
-	 * Check to see if we should throttle the watchdog timer to avoid
-	 * too many dumps going to the console thus triggering an NMI.
-	 */
-	delta_time = cfs_duration_sec(cfs_time_sub(current_time,
-						   lcw_last_watchdog_time));
-
-	if (delta_time < libcfs_watchdog_ratelimit &&
-	    lcw_recent_watchdog_count > 3) {
-		LCONSOLE_WARN("Service thread pid %u was inactive for "
-			      "%lu.%.02lus. Watchdog stack traces are limited "
-			      "to 3 per %d seconds, skipping this one.\n",
-			      (int)lcw->lcw_pid,
-			      timediff.tv_sec,
-			      timediff.tv_usec / 10000,
-			      libcfs_watchdog_ratelimit);
-	} else {
-		if (delta_time < libcfs_watchdog_ratelimit) {
-			lcw_recent_watchdog_count++;
-		} else {
-			memcpy(&lcw_last_watchdog_time, &current_time,
-			       sizeof(current_time));
-			lcw_recent_watchdog_count = 0;
-		}
-
-		LCONSOLE_WARN("Service thread pid %u was inactive for "
-			      "%lu.%.02lus. The thread might be hung, or it "
-			      "might only be slow and will resume later. "
-			      "Dumping the stack trace for debugging purposes:"
-			      "\n",
-			      (int)lcw->lcw_pid,
-			      timediff.tv_sec,
-			      timediff.tv_usec / 10000);
-		lcw_dump(lcw);
-	}
-}
-
-static int lcw_dispatch_main(void *data)
-{
-	int		 rc = 0;
-	struct lc_watchdog *lcw;
-	LIST_HEAD      (zombies);
-
-	ENTRY;
-
-	complete(&lcw_start_completion);
-
-	while (1) {
-		int dumplog = 1;
-
-		cfs_wait_event_interruptible(lcw_event_waitq,
-					     is_watchdog_fired(), rc);
-		CDEBUG(D_INFO, "Watchdog got woken up...\n");
-		if (test_bit(LCW_FLAG_STOP, &lcw_flags)) {
-			CDEBUG(D_INFO, "LCW_FLAG_STOP set, shutting down...\n");
-
-			spin_lock_bh(&lcw_pending_timers_lock);
-			rc = !list_empty(&lcw_pending_timers);
-			spin_unlock_bh(&lcw_pending_timers_lock);
-			if (rc) {
-				CERROR("pending timers list was not empty at "
-				       "time of watchdog dispatch shutdown\n");
-			}
-			break;
-		}
-
-		spin_lock_bh(&lcw_pending_timers_lock);
-		while (!list_empty(&lcw_pending_timers)) {
-			int is_dumplog;
-
-			lcw = list_entry(lcw_pending_timers.next,
-					     struct lc_watchdog, lcw_list);
-			/* +1 ref for callback to make sure lwc wouldn't be
-			 * deleted after releasing lcw_pending_timers_lock */
-			lcw->lcw_refcount++;
-			spin_unlock_bh(&lcw_pending_timers_lock);
-
-			/* lock ordering */
-			spin_lock_bh(&lcw->lcw_lock);
-			spin_lock_bh(&lcw_pending_timers_lock);
-
-			if (list_empty(&lcw->lcw_list)) {
-				/* already removed from pending list */
-				lcw->lcw_refcount--; /* -1 ref for callback */
-				if (lcw->lcw_refcount == 0)
-					list_add(&lcw->lcw_list, &zombies);
-				spin_unlock_bh(&lcw->lcw_lock);
-				/* still hold lcw_pending_timers_lock */
-				continue;
-			}
-
-			list_del_init(&lcw->lcw_list);
-			lcw->lcw_refcount--; /* -1 ref for pending list */
-
-			spin_unlock_bh(&lcw_pending_timers_lock);
-			spin_unlock_bh(&lcw->lcw_lock);
-
-			CDEBUG(D_INFO, "found lcw for pid " LPPID "\n",
-			       lcw->lcw_pid);
-			lcw_dump_stack(lcw);
-
-			is_dumplog = lcw->lcw_callback == lc_watchdog_dumplog;
-			if (lcw->lcw_state != LC_WATCHDOG_DISABLED &&
-			    (dumplog || !is_dumplog)) {
-				lcw->lcw_callback(lcw->lcw_pid, lcw->lcw_data);
-				if (dumplog && is_dumplog)
-					dumplog = 0;
-			}
-
-			spin_lock_bh(&lcw_pending_timers_lock);
-			lcw->lcw_refcount--; /* -1 ref for callback */
-			if (lcw->lcw_refcount == 0)
-				list_add(&lcw->lcw_list, &zombies);
-		}
-		spin_unlock_bh(&lcw_pending_timers_lock);
-
-		while (!list_empty(&zombies)) {
-			lcw = list_entry(lcw_pending_timers.next,
-					 struct lc_watchdog, lcw_list);
-			list_del(&lcw->lcw_list);
-			LIBCFS_FREE(lcw, sizeof(*lcw));
-		}
-	}
-
-	complete(&lcw_stop_completion);
-
-	RETURN(rc);
-}
-
-static void lcw_dispatch_start(void)
-{
-	task_t *task;
-
-	ENTRY;
-	LASSERT(lcw_refcount == 1);
-
-	init_completion(&lcw_stop_completion);
-	init_completion(&lcw_start_completion);
-	init_waitqueue_head(&lcw_event_waitq);
-
-	CDEBUG(D_INFO, "starting dispatch thread\n");
-	task = kthread_run(lcw_dispatch_main, NULL, "lc_watchdogd");
-	if (IS_ERR(task)) {
-		CERROR("error spawning watchdog dispatch thread: %ld\n",
-			PTR_ERR(task));
-		EXIT;
-		return;
-	}
-	wait_for_completion(&lcw_start_completion);
-	CDEBUG(D_INFO, "watchdog dispatcher initialization complete.\n");
-
-	EXIT;
-}
-
-static void lcw_dispatch_stop(void)
-{
-	ENTRY;
-	LASSERT(lcw_refcount == 0);
-
-	CDEBUG(D_INFO, "trying to stop watchdog dispatcher.\n");
-
-	set_bit(LCW_FLAG_STOP, &lcw_flags);
-	wake_up(&lcw_event_waitq);
-
-	wait_for_completion(&lcw_stop_completion);
-
-	CDEBUG(D_INFO, "watchdog dispatcher has shut down.\n");
-
-	EXIT;
-}
-
-struct lc_watchdog *lc_watchdog_add(int timeout,
-				    void (*callback)(pid_t, void *),
-				    void *data)
-{
-	struct lc_watchdog *lcw = NULL;
-	ENTRY;
-
-	LIBCFS_ALLOC(lcw, sizeof(*lcw));
-	if (lcw == NULL) {
-		CDEBUG(D_INFO, "Could not allocate new lc_watchdog\n");
-		RETURN(ERR_PTR(-ENOMEM));
-	}
-
-	spin_lock_init(&lcw->lcw_lock);
-	lcw->lcw_refcount = 1; /* refcount for owner */
-	lcw->lcw_task     = current;
-	lcw->lcw_pid      = current_pid();
-	lcw->lcw_callback = (callback != NULL) ? callback : lc_watchdog_dumplog;
-	lcw->lcw_data     = data;
-	lcw->lcw_state    = LC_WATCHDOG_DISABLED;
-
-	INIT_LIST_HEAD(&lcw->lcw_list);
-	cfs_timer_init(&lcw->lcw_timer, lcw_cb, lcw);
-
-	mutex_lock(&lcw_refcount_mutex);
-	if (++lcw_refcount == 1)
-		lcw_dispatch_start();
-	mutex_unlock(&lcw_refcount_mutex);
-
-	/* Keep this working in case we enable them by default */
-	if (lcw->lcw_state == LC_WATCHDOG_ENABLED) {
-		lcw->lcw_last_touched = cfs_time_current();
-		cfs_timer_arm(&lcw->lcw_timer, cfs_time_seconds(timeout) +
-			      cfs_time_current());
-	}
-
-	RETURN(lcw);
-}
-EXPORT_SYMBOL(lc_watchdog_add);
-
-static void lcw_update_time(struct lc_watchdog *lcw, const char *message)
-{
-	cfs_time_t newtime = cfs_time_current();;
-
-	if (lcw->lcw_state == LC_WATCHDOG_EXPIRED) {
-		struct timeval timediff;
-		cfs_time_t delta_time = cfs_time_sub(newtime,
-						     lcw->lcw_last_touched);
-		cfs_duration_usec(delta_time, &timediff);
-
-		LCONSOLE_WARN("Service thread pid %u %s after %lu.%.02lus. "
-			      "This indicates the system was overloaded (too "
-			      "many service threads, or there were not enough "
-			      "hardware resources).\n",
-			      lcw->lcw_pid,
-			      message,
-			      timediff.tv_sec,
-			      timediff.tv_usec / 10000);
-	}
-	lcw->lcw_last_touched = newtime;
-}
-
-static void lc_watchdog_del_pending(struct lc_watchdog *lcw)
-{
-	spin_lock_bh(&lcw->lcw_lock);
-	if (unlikely(!list_empty(&lcw->lcw_list))) {
-		spin_lock_bh(&lcw_pending_timers_lock);
-		list_del_init(&lcw->lcw_list);
-		lcw->lcw_refcount--; /* -1 ref for pending list */
-		spin_unlock_bh(&lcw_pending_timers_lock);
-	}
-
-	spin_unlock_bh(&lcw->lcw_lock);
-}
-
-void lc_watchdog_touch(struct lc_watchdog *lcw, int timeout)
-{
-	ENTRY;
-	LASSERT(lcw != NULL);
-
-	lc_watchdog_del_pending(lcw);
-
-	lcw_update_time(lcw, "resumed");
-	lcw->lcw_state = LC_WATCHDOG_ENABLED;
-
-	cfs_timer_arm(&lcw->lcw_timer, cfs_time_current() +
-		      cfs_time_seconds(timeout));
-
-	EXIT;
-}
-EXPORT_SYMBOL(lc_watchdog_touch);
-
-void lc_watchdog_disable(struct lc_watchdog *lcw)
-{
-	ENTRY;
-	LASSERT(lcw != NULL);
-
-	lc_watchdog_del_pending(lcw);
-
-	lcw_update_time(lcw, "completed");
-	lcw->lcw_state = LC_WATCHDOG_DISABLED;
-
-	EXIT;
-}
-EXPORT_SYMBOL(lc_watchdog_disable);
-
-void lc_watchdog_delete(struct lc_watchdog *lcw)
-{
-	int dead;
-
-	ENTRY;
-	LASSERT(lcw != NULL);
-
-	cfs_timer_disarm(&lcw->lcw_timer);
-
-	lcw_update_time(lcw, "stopped");
-
-	spin_lock_bh(&lcw->lcw_lock);
-	spin_lock_bh(&lcw_pending_timers_lock);
-	if (unlikely(!list_empty(&lcw->lcw_list))) {
-		list_del_init(&lcw->lcw_list);
-		lcw->lcw_refcount--; /* -1 ref for pending list */
-	}
-
-	lcw->lcw_refcount--; /* -1 ref for owner */
-	dead = lcw->lcw_refcount == 0;
-	spin_unlock_bh(&lcw_pending_timers_lock);
-	spin_unlock_bh(&lcw->lcw_lock);
-
-	if (dead)
-		LIBCFS_FREE(lcw, sizeof(*lcw));
-
-	mutex_lock(&lcw_refcount_mutex);
-	if (--lcw_refcount == 0)
-		lcw_dispatch_stop();
-	mutex_unlock(&lcw_refcount_mutex);
-
-	EXIT;
-}
-EXPORT_SYMBOL(lc_watchdog_delete);
-
-/*
- * Provided watchdog handlers
- */
-
-void lc_watchdog_dumplog(pid_t pid, void *data)
-{
-	libcfs_debug_dumplog_internal((void *)((long_ptr_t)pid));
-}
-EXPORT_SYMBOL(lc_watchdog_dumplog);
-
-#else   /* !defined(WITH_WATCHDOG) */
-
-struct lc_watchdog *lc_watchdog_add(int timeout,
-				    void (*callback)(pid_t pid, void *),
-				    void *data)
-{
-	static struct lc_watchdog      watchdog;
-	return &watchdog;
-}
-EXPORT_SYMBOL(lc_watchdog_add);
-
-void lc_watchdog_touch(struct lc_watchdog *lcw, int timeout)
-{
-}
-EXPORT_SYMBOL(lc_watchdog_touch);
-
-void lc_watchdog_disable(struct lc_watchdog *lcw)
-{
-}
-EXPORT_SYMBOL(lc_watchdog_disable);
-
-void lc_watchdog_delete(struct lc_watchdog *lcw)
-{
-}
-EXPORT_SYMBOL(lc_watchdog_delete);
-
-#endif
diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c
index b533666..462172d 100644
--- a/drivers/staging/lustre/lustre/libcfs/workitem.c
+++ b/drivers/staging/lustre/lustre/libcfs/workitem.c
@@ -376,7 +376,8 @@
 	rc = 0;
 	while (nthrs > 0)  {
 		char	name[16];
-		task_t	*task;
+		struct task_struct *task;
+
 		spin_lock(&cfs_wi_data.wi_glock);
 		while (sched->ws_starting > 0) {
 			spin_unlock(&cfs_wi_data.wi_glock);
diff --git a/drivers/staging/lustre/lustre/llite/Makefile b/drivers/staging/lustre/lustre/llite/Makefile
index dff0c04..f493e07 100644
--- a/drivers/staging/lustre/lustre/llite/Makefile
+++ b/drivers/staging/lustre/lustre/llite/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_LUSTRE_FS) += lustre.o
-obj-$(CONFIG_LUSTRE_FS) += llite_lloop.o
+obj-$(CONFIG_LUSTRE_LLITE_LLOOP) += llite_lloop.o
 lustre-y := dcache.o dir.o file.o llite_close.o llite_lib.o llite_nfs.o \
 	    rw.o lproc_llite.o namei.o symlink.o llite_mmap.o \
 	    xattr.o remote_perm.o llite_rmtacl.o llite_capa.o \
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index ff0d085..e7629be 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -59,11 +59,11 @@
 static void ll_release(struct dentry *de)
 {
 	struct ll_dentry_data *lld;
-	ENTRY;
+
 	LASSERT(de != NULL);
 	lld = ll_d2d(de);
 	if (lld == NULL) /* NFS copies the de->d_op methods (bug 4655) */
-		RETURN_EXIT;
+		return;
 
 	if (lld->lld_it) {
 		ll_intent_release(lld->lld_it);
@@ -73,8 +73,6 @@
 	LASSERT(lld->lld_mnt_count == 0);
 	de->d_fsdata = NULL;
 	call_rcu(&lld->lld_rcu_head, free_dentry_data);
-
-	EXIT;
 }
 
 /* Compare if two dentries are the same.  Don't match if the existing dentry
@@ -84,17 +82,14 @@
  * an AST before calling d_revalidate_it().  The dentry still exists (marked
  * INVALID) so d_lookup() matches it, but we have no lock on it (so
  * lock_match() fails) and we spin around real_lookup(). */
-int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
-		const struct dentry *dentry, const struct inode *inode,
+int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
 		unsigned int len, const char *str, const struct qstr *name)
 {
-	ENTRY;
-
 	if (len != name->len)
-		RETURN(1);
+		return 1;
 
 	if (memcmp(str, name->name, len))
-		RETURN(1);
+		return 1;
 
 	CDEBUG(D_DENTRY, "found name %.*s(%p) flags %#x refc %d\n",
 	       name->len, name->name, dentry, dentry->d_flags,
@@ -102,12 +97,12 @@
 
 	/* mountpoint is always valid */
 	if (d_mountpoint((struct dentry *)dentry))
-		RETURN(0);
+		return 0;
 
 	if (d_lustre_invalid(dentry))
-		RETURN(1);
+		return 1;
 
-	RETURN(0);
+	return 0;
 }
 
 static inline int return_if_equal(struct ldlm_lock *lock, void *data)
@@ -128,22 +123,21 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct lov_stripe_md *lsm;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(inode);
 	rc = md_find_cbdata(sbi->ll_md_exp, ll_inode2fid(inode),
 			    return_if_equal, NULL);
 	if (rc != 0)
-		 RETURN(rc);
+		 return rc;
 
 	lsm = ccc_inode_lsm_get(inode);
 	if (lsm == NULL)
-		RETURN(rc);
+		return rc;
 
 	rc = obd_find_cbdata(sbi->ll_dt_exp, lsm, return_if_equal, NULL);
 	ccc_inode_lsm_put(inode, lsm);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -155,7 +149,6 @@
  */
 static int ll_ddelete(const struct dentry *de)
 {
-	ENTRY;
 	LASSERT(de);
 
 	CDEBUG(D_DENTRY, "%s dentry %.*s (%p, parent %p, inode %p) %s%s\n",
@@ -179,13 +172,12 @@
 #endif
 
 	if (d_lustre_invalid((struct dentry *)de))
-		RETURN(1);
-	RETURN(0);
+		return 1;
+	return 0;
 }
 
 static int ll_set_dd(struct dentry *de)
 {
-	ENTRY;
 	LASSERT(de != NULL);
 
 	CDEBUG(D_DENTRY, "ldd on dentry %.*s (%p) parent %p inode %p refc %d\n",
@@ -204,11 +196,11 @@
 				OBD_FREE_PTR(lld);
 			spin_unlock(&de->d_lock);
 		} else {
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int ll_dops_init(struct dentry *de, int block, int init_sa)
@@ -260,8 +252,6 @@
 
 void ll_intent_release(struct lookup_intent *it)
 {
-	ENTRY;
-
 	CDEBUG(D_INFO, "intent %p released\n", it);
 	ll_intent_drop_lock(it);
 	/* We are still holding extra reference on a request, need to free it */
@@ -275,14 +265,12 @@
 
 	it->d.lustre.it_disposition = 0;
 	it->d.lustre.it_data = NULL;
-	EXIT;
 }
 
 void ll_invalidate_aliases(struct inode *inode)
 {
 	struct dentry *dentry;
 	struct ll_d_hlist_node *p;
-	ENTRY;
 
 	LASSERT(inode != NULL);
 
@@ -296,18 +284,17 @@
 		       dentry->d_name.name, dentry, dentry->d_parent,
 		       dentry->d_inode, dentry->d_flags);
 
-		if (dentry->d_name.len == 1 && dentry->d_name.name[0] == '/') {
-			CERROR("called on root (?) dentry=%p, inode=%p "
-			       "ino=%lu\n", dentry, inode, inode->i_ino);
+		if (unlikely(dentry == dentry->d_sb->s_root)) {
+			CERROR("%s: called on root dentry=%p, fid="DFID"\n",
+			       ll_get_fsname(dentry->d_sb, NULL, 0),
+			       dentry, PFID(ll_inode2fid(inode)));
 			lustre_dump_dentry(dentry, 1);
-			libcfs_debug_dumpstack(NULL);
+			dump_stack();
 		}
 
 		d_lustre_invalidate(dentry, 0);
 	}
 	ll_unlock_dcache(inode);
-
-	EXIT;
 }
 
 int ll_revalidate_it_finish(struct ptlrpc_request *request,
@@ -315,17 +302,16 @@
 			    struct dentry *de)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (!request)
-		RETURN(0);
+		return 0;
 
 	if (it_disposition(it, DISP_LOOKUP_NEG))
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	rc = ll_prep_inode(&de->d_inode, request, NULL, it);
 
-	RETURN(rc);
+	return rc;
 }
 
 void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry)
@@ -370,7 +356,6 @@
 	struct inode *parent = de->d_parent->d_inode;
 	int rc;
 
-	ENTRY;
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name,
 	       LL_IT2STR(it));
 
@@ -383,10 +368,10 @@
 		   away this negative dentry and actually do the request to
 		   kernel to create whatever needs to be created (if possible)*/
 		if (it && (it->it_op & IT_CREAT))
-			RETURN(0);
+			return 0;
 
 		if (d_lustre_invalid(de))
-			RETURN(0);
+			return 0;
 
 		ibits = MDS_INODELOCK_UPDATE;
 		rc = ll_have_md_lock(parent, &ibits, LCK_MINMODE);
@@ -413,7 +398,7 @@
 	LASSERT(it);
 
 	if (it->it_op == IT_LOOKUP && !d_lustre_invalid(de))
-		RETURN(1);
+		return 1;
 
 	if (it->it_op == IT_OPEN) {
 		struct inode *inode = de->d_inode;
@@ -460,7 +445,7 @@
 			   if it would be, we'll reopen the open request to
 			   MDS later during file open path */
 			mutex_unlock(&lli->lli_och_mutex);
-			RETURN(1);
+			return 1;
 		} else {
 			mutex_unlock(&lli->lli_och_mutex);
 		}
@@ -479,7 +464,7 @@
 				     de->d_name.name, de->d_name.len,
 				     0, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	if (!IS_POSIXACL(parent) || !exp_connect_umask(exp))
 		it->it_create_mode &= ~current_umask();
@@ -566,7 +551,7 @@
 mark:
 	if (it != NULL && it->it_op == IT_GETATTR && rc > 0)
 		ll_statahead_mark(parent, de);
-	RETURN(rc);
+	return rc;
 
 	/*
 	 * This part is here to combat evil-evil race in real_lookup on 2.6
@@ -598,7 +583,7 @@
 							 LUSTRE_OPC_CREATE :
 							 LUSTRE_OPC_ANY), NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	rc = md_intent_lock(exp, op_data, NULL, 0,  it, 0, &req,
 			    ll_md_blocking_ast, 0);
@@ -639,14 +624,13 @@
 	struct inode *parent = dentry->d_parent->d_inode;
 	int unplug = 0;
 
-	ENTRY;
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%s,flags=%u\n",
 	       dentry->d_name.name, flags);
 
 	if (!(flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE)) &&
 	    ll_need_statahead(parent, dentry) > 0) {
 		if (flags & LOOKUP_RCU)
-			RETURN(-ECHILD);
+			return -ECHILD;
 
 		if (dentry->d_inode == NULL)
 			unplug = 1;
@@ -654,7 +638,7 @@
 		ll_statahead_mark(parent, dentry);
 	}
 
-	RETURN(1);
+	return 1;
 }
 
 
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 23c61fe..09844be 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -41,14 +41,13 @@
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/mm.h>
-#include <linux/version.h>
 #include <asm/uaccess.h>
 #include <linux/buffer_head.h>   // for wait_on_buffer
 #include <linux/pagevec.h>
+#include <linux/prefetch.h>
 
 #define DEBUG_SUBSYSTEM S_LLITE
 
-#include <lustre/lustre_idl.h>
 #include <obd_support.h>
 #include <obd_class.h>
 #include <lustre_lib.h>
@@ -158,7 +157,6 @@
 	int npages;
 	int i;
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) hash "LPU64"\n",
 	       inode->i_ino, inode->i_generation, inode, hash);
@@ -239,7 +237,6 @@
 
 	if (page_pool != &page0)
 		OBD_FREE(page_pool, sizeof(struct page *) * max_pages);
-	EXIT;
 	return rc;
 }
 
@@ -355,15 +352,12 @@
 	rc = md_lock_match(ll_i2sbi(dir)->ll_md_exp, LDLM_FL_BLOCK_GRANTED,
 			   ll_inode2fid(dir), LDLM_IBITS, &policy, mode, &lockh);
 	if (!rc) {
-		struct ldlm_enqueue_info einfo = {.ei_type = LDLM_IBITS,
-						  .ei_mode = mode,
-						  .ei_cb_bl =
-						  ll_md_blocking_ast,
-						  .ei_cb_cp =
-						  ldlm_completion_ast,
-						  .ei_cb_gl = NULL,
-						  .ei_cb_wg = NULL,
-						  .ei_cbdata = NULL};
+		struct ldlm_enqueue_info einfo = {
+			.ei_type = LDLM_IBITS,
+			.ei_mode = mode,
+			.ei_cb_bl = ll_md_blocking_ast,
+			.ei_cb_cp = ldlm_completion_ast,
+		};
 		struct lookup_intent it = { .it_op = IT_READDIR };
 		struct ptlrpc_request *request;
 		struct md_op_data *op_data;
@@ -482,19 +476,17 @@
 	goto out_unlock;
 }
 
-int ll_dir_read(struct inode *inode, __u64 *_pos, void *cookie,
-		filldir_t filldir)
+int ll_dir_read(struct inode *inode, struct dir_context *ctx)
 {
 	struct ll_inode_info *info       = ll_i2info(inode);
 	struct ll_sb_info    *sbi	= ll_i2sbi(inode);
-	__u64		 pos	= *_pos;
+	__u64		   pos		= ctx->pos;
 	int		   api32      = ll_need_32bit_api(sbi);
 	int		   hash64     = sbi->ll_flags & LL_SBI_64BIT_HASH;
 	struct page	  *page;
 	struct ll_dir_chain   chain;
 	int		   done = 0;
 	int		   rc = 0;
-	ENTRY;
 
 	ll_dir_chain_init(&chain);
 
@@ -547,12 +539,14 @@
 				fid_le_to_cpu(&fid, &ent->lde_fid);
 				ino = cl_fid_build_ino(&fid, api32);
 				type = ll_dirent_type_get(ent);
+				ctx->pos = lhash;
 				/* For 'll_nfs_get_name_filldir()', it will try
 				 * to access the 'ent' through its 'lde_name',
-				 * so the parameter 'name' for 'filldir()' must
-				 * be part of the 'ent'. */
-				done = filldir(cookie, ent->lde_name, namelen,
-					       lhash, ino, type);
+				 * so the parameter 'name' for 'ctx->actor()'
+				 * must be part of the 'ent'.
+				 */
+				done = !dir_emit(ctx, ent->lde_name,
+						 namelen, ino, type);
 			}
 			next = le64_to_cpu(dp->ldp_hash_end);
 			if (!done) {
@@ -593,56 +587,49 @@
 		}
 	}
 
-	*_pos = pos;
+	ctx->pos = pos;
 	ll_dir_chain_fini(&chain);
-	RETURN(rc);
+	return rc;
 }
 
-static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
+static int ll_readdir(struct file *filp, struct dir_context *ctx)
 {
 	struct inode		*inode	= filp->f_dentry->d_inode;
 	struct ll_file_data	*lfd	= LUSTRE_FPRIVATE(filp);
 	struct ll_sb_info	*sbi	= ll_i2sbi(inode);
-	__u64			pos	= lfd->lfd_pos;
 	int			hash64	= sbi->ll_flags & LL_SBI_64BIT_HASH;
 	int			api32	= ll_need_32bit_api(sbi);
 	int			rc;
-	struct path		path;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) pos %lu/%llu "
 	       " 32bit_api %d\n", inode->i_ino, inode->i_generation,
-	       inode, (unsigned long)pos, i_size_read(inode), api32);
+	       inode, (unsigned long)lfd->lfd_pos, i_size_read(inode), api32);
 
-	if (pos == MDS_DIR_END_OFF)
+	if (lfd->lfd_pos == MDS_DIR_END_OFF)
 		/*
 		 * end-of-file.
 		 */
 		GOTO(out, rc = 0);
 
-	rc = ll_dir_read(inode, &pos, cookie, filldir);
-	lfd->lfd_pos = pos;
-	if (pos == MDS_DIR_END_OFF) {
+	ctx->pos = lfd->lfd_pos;
+	rc = ll_dir_read(inode, ctx);
+	lfd->lfd_pos = ctx->pos;
+	if (ctx->pos == MDS_DIR_END_OFF) {
 		if (api32)
-			filp->f_pos = LL_DIR_END_OFF_32BIT;
+			ctx->pos = LL_DIR_END_OFF_32BIT;
 		else
-			filp->f_pos = LL_DIR_END_OFF;
+			ctx->pos = LL_DIR_END_OFF;
 	} else {
 		if (api32 && hash64)
-			filp->f_pos = pos >> 32;
-		else
-			filp->f_pos = pos;
+			ctx->pos >>= 32;
 	}
 	filp->f_version = inode->i_version;
-	path.mnt = filp->f_path.mnt;
-	path.dentry = filp->f_dentry;
-	touch_atime(&path);
 
 out:
 	if (!rc)
 		ll_stats_ops_tally(sbi, LPROC_LL_READDIR, 1);
 
-	RETURN(rc);
+	return rc;
 }
 
 int ll_send_mgc_param(struct obd_export *mgc, char *string)
@@ -673,8 +660,6 @@
 	int mode;
 	int err;
 
-	ENTRY;
-
 	mode = (0755 & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
 	op_data = ll_prep_md_op_data(NULL, dir, NULL, filename,
 				     strlen(filename), mode, LUSTRE_OPC_MKDIR,
@@ -684,7 +669,8 @@
 
 	op_data->op_cli_flags |= CLI_SET_MEA;
 	err = md_create(sbi->ll_md_exp, op_data, lump, sizeof(*lump), mode,
-			current_fsuid(), current_fsgid(),
+			from_kuid(&init_user_ns, current_fsuid()),
+			from_kgid(&init_user_ns, current_fsgid()),
 			cfs_curproc_cap_pack(), 0, &request);
 	ll_finish_md_op_data(op_data);
 	if (err)
@@ -704,7 +690,6 @@
 	struct lustre_sb_info *lsi = s2lsi(inode->i_sb);
 	struct obd_device *mgc = lsi->lsi_mgc;
 	int lum_size;
-	ENTRY;
 
 	if (lump != NULL) {
 		/*
@@ -731,7 +716,7 @@
 					" %#08x != %#08x nor %#08x\n",
 					lump->lmm_magic, LOV_USER_MAGIC_V1,
 					LOV_USER_MAGIC_V3);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		}
 	} else {
@@ -741,7 +726,7 @@
 	op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	if (lump != NULL && lump->lmm_magic == cpu_to_le32(LMV_USER_MAGIC))
 		op_data->op_cli_flags |= CLI_SET_MEA;
@@ -797,7 +782,7 @@
 		if (param != NULL)
 			OBD_FREE(param, MGS_PARAM_MAXLEN);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmmp,
@@ -812,13 +797,13 @@
 
 	rc = ll_get_max_mdsize(sbi, &lmmsize);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL,
 				     0, lmmsize, LUSTRE_OPC_ANY,
 				     NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
 	rc = md_getattr(sbi->ll_md_exp, op_data, &req);
@@ -878,12 +863,11 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct md_op_data *op_data;
 	int rc, mdtidx;
-	ENTRY;
 
 	op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0,
 				     0, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	op_data->op_flags |= MF_GET_MDT_IDX;
 	rc = md_getattr(sbi->ll_md_exp, op_data, NULL);
@@ -891,7 +875,7 @@
 	ll_finish_md_op_data(op_data);
 	if (rc < 0) {
 		CDEBUG(D_INFO, "md_getattr_name: %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 	return mdtidx;
 }
@@ -912,7 +896,6 @@
 	struct ll_sb_info		*sbi = ll_s2sbi(sb);
 	struct hsm_progress_kernel	 hpk;
 	int				 rc;
-	ENTRY;
 
 	/* Forge a hsm_progress based on data from copy. */
 	hpk.hpk_fid = copy->hc_hai.hai_fid;
@@ -962,7 +945,7 @@
 	rc = obd_iocontrol(LL_IOC_HSM_PROGRESS, sbi->ll_md_exp, sizeof(hpk),
 			   &hpk, NULL);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -985,7 +968,6 @@
 	struct ll_sb_info		*sbi = ll_s2sbi(sb);
 	struct hsm_progress_kernel	 hpk;
 	int				 rc;
-	ENTRY;
 
 	/* If you modify the logic here, also check llapi_hsm_copy_end(). */
 	/* Take care: copy->hc_hai.hai_action, len, gid and data are not
@@ -1062,7 +1044,7 @@
 	rc = obd_iocontrol(LL_IOC_HSM_PROGRESS, sbi->ll_md_exp, sizeof(hpk),
 			   &hpk, NULL);
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1090,7 +1072,6 @@
 	int id = qctl->qc_id;
 	int valid = qctl->qc_valid;
 	int rc = 0;
-	ENTRY;
 
 	switch (cmd) {
 	case LUSTRE_Q_INVALIDATE:
@@ -1101,32 +1082,34 @@
 	case Q_SETINFO:
 		if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
 		    sbi->ll_flags & LL_SBI_RMT_CLIENT)
-			RETURN(-EPERM);
+			return -EPERM;
 		break;
 	case Q_GETQUOTA:
-		if (((type == USRQUOTA && current_euid() != id) ||
-		     (type == GRPQUOTA && !in_egroup_p(id))) &&
+		if (((type == USRQUOTA &&
+		      uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
+		     (type == GRPQUOTA &&
+		      !in_egroup_p(make_kgid(&init_user_ns, id)))) &&
 		    (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
 		     sbi->ll_flags & LL_SBI_RMT_CLIENT))
-			RETURN(-EPERM);
+			return -EPERM;
 		break;
 	case Q_GETINFO:
 		break;
 	default:
 		CERROR("unsupported quotactl op: %#x\n", cmd);
-		RETURN(-ENOTTY);
+		return -ENOTTY;
 	}
 
 	if (valid != QC_GENERAL) {
 		if (sbi->ll_flags & LL_SBI_RMT_CLIENT)
-			RETURN(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 
 		if (cmd == Q_GETINFO)
 			qctl->qc_cmd = Q_GETOINFO;
 		else if (cmd == Q_GETQUOTA)
 			qctl->qc_cmd = Q_GETOQUOTA;
 		else
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		switch (valid) {
 		case QC_MDTIDX:
@@ -1151,7 +1134,7 @@
 		}
 
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		qctl->qc_cmd = cmd;
 	} else {
@@ -1159,7 +1142,7 @@
 
 		OBD_ALLOC_PTR(oqctl);
 		if (oqctl == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		QCTL_COPY(oqctl, qctl);
 		rc = obd_quotactl(sbi->ll_md_exp, oqctl);
@@ -1169,7 +1152,7 @@
 				obd_quotactl(sbi->ll_md_exp, oqctl);
 			}
 			OBD_FREE_PTR(oqctl);
-			RETURN(rc);
+			return rc;
 		}
 		/* If QIF_SPACE is not set, client should collect the
 		 * space usage from OSSs by itself */
@@ -1216,7 +1199,7 @@
 		OBD_FREE_PTR(oqctl);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static char *
@@ -1249,7 +1232,6 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct obd_ioctl_data *data;
 	int rc = 0;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), cmd=%#x\n",
 	       inode->i_ino, inode->i_generation, inode, cmd);
@@ -1262,10 +1244,10 @@
 	switch(cmd) {
 	case FSFILT_IOC_GETFLAGS:
 	case FSFILT_IOC_SETFLAGS:
-		RETURN(ll_iocontrol(inode, file, cmd, arg));
+		return ll_iocontrol(inode, file, cmd, arg);
 	case FSFILT_IOC_GETVERSION_OLD:
 	case FSFILT_IOC_GETVERSION:
-		RETURN(put_user(inode->i_generation, (int *)arg));
+		return put_user(inode->i_generation, (int *)arg);
 	/* We need to special case any other ioctls we want to handle,
 	 * to send them to the MDS/OST as appropriate and to properly
 	 * network encode the arg field.
@@ -1277,10 +1259,10 @@
 
 		mdtidx = ll_get_mdt_idx(inode);
 		if (mdtidx < 0)
-			RETURN(mdtidx);
+			return mdtidx;
 
 		if (put_user((int)mdtidx, (int*)arg))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		return 0;
 	}
@@ -1293,7 +1275,7 @@
 
 		rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		data = (void *)buf;
 
 		filename = data->ioc_inlbuf1;
@@ -1317,7 +1299,6 @@
 			GOTO(out_free, rc);
 		}
 		ptlrpc_req_finished(request);
-		EXIT;
 out_free:
 		obd_ioctl_freedata(buf, len);
 		return rc;
@@ -1333,7 +1314,7 @@
 
 		rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		data = (void *)buf;
 		if (data->ioc_inlbuf1 == NULL || data->ioc_inlbuf2 == NULL ||
@@ -1364,7 +1345,7 @@
 		rc = ll_dir_setdirstripe(inode, lum, filename);
 lmv_out_free:
 		obd_ioctl_freedata(buf, len);
-		RETURN(rc);
+		return rc;
 
 	}
 	case LL_IOC_LOV_SETSTRIPE: {
@@ -1380,11 +1361,11 @@
 			sizeof(lumv3p->lmm_objects[0]));
 		/* first try with v1 which is smaller than v3 */
 		if (copy_from_user(lumv1, lumv1p, sizeof(*lumv1)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		if ((lumv1->lmm_magic == LOV_USER_MAGIC_V3) ) {
 			if (copy_from_user(&lumv3, lumv3p, sizeof(lumv3)))
-				RETURN(-EFAULT);
+				return -EFAULT;
 		}
 
 		if (inode->i_sb->s_root == file->f_dentry)
@@ -1393,7 +1374,7 @@
 		/* in v1 and v3 cases lumv1 points to data */
 		rc = ll_dir_setstripe(inode, lumv1, set_default);
 
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_LMV_GETSTRIPE: {
 		struct lmv_user_md *lump = (struct lmv_user_md *)arg;
@@ -1404,10 +1385,10 @@
 		int mdtindex;
 
 		if (copy_from_user(&lum, lump, sizeof(struct lmv_user_md)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		if (lum.lum_magic != LMV_MAGIC_V1)
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		lum_size = lmv_user_md_size(1, LMV_MAGIC_V1);
 		OBD_ALLOC(tmp, lum_size);
@@ -1430,7 +1411,7 @@
 free_lmv:
 		if (tmp)
 			OBD_FREE(tmp, lum_size);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_REMOVE_ENTRY: {
 		char		*filename = NULL;
@@ -1447,7 +1428,7 @@
 
 		filename = ll_getname((const char *)arg);
 		if (IS_ERR(filename))
-			RETURN(PTR_ERR(filename));
+			return PTR_ERR(filename);
 
 		namelen = strlen(filename);
 		if (namelen < 1)
@@ -1457,12 +1438,12 @@
 out_rmdir:
 		if (filename)
 			ll_putname(filename);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_LOV_SWAP_LAYOUTS:
-		RETURN(-EPERM);
+		return -EPERM;
 	case LL_IOC_OBD_STATFS:
-		RETURN(ll_obd_statfs(inode, (void *)arg));
+		return ll_obd_statfs(inode, (void *)arg);
 	case LL_IOC_LOV_GETSTRIPE:
 	case LL_IOC_MDC_GETINFO:
 	case IOC_MDC_GETFILEINFO:
@@ -1478,7 +1459,7 @@
 		    cmd == IOC_MDC_GETFILESTRIPE) {
 			filename = ll_getname((const char *)arg);
 			if (IS_ERR(filename))
-				RETURN(PTR_ERR(filename));
+				return PTR_ERR(filename);
 
 			rc = ll_lov_getstripe_ea_info(inode, filename, &lmm,
 						      &lmmsize, &request);
@@ -1539,7 +1520,6 @@
 				GOTO(out_req, rc = -EFAULT);
 		}
 
-		EXIT;
 	out_req:
 		ptlrpc_req_finished(request);
 		if (filename)
@@ -1559,9 +1539,11 @@
 
 		rc = ll_get_max_mdsize(sbi, &lmmsize);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		OBD_ALLOC_LARGE(lmm, lmmsize);
+		if (lmm == NULL)
+			return -ENOMEM;
 		if (copy_from_user(lmm, lum, lmmsize))
 			GOTO(free_lmm, rc = -EFAULT);
 
@@ -1602,7 +1584,6 @@
 		if (copy_to_user(&lumd->lmd_st, &st, sizeof(st)))
 			GOTO(free_lsm, rc = -EFAULT);
 
-		EXIT;
 	free_lsm:
 		obd_free_memmd(sbi->ll_dt_exp, &lsm);
 	free_lmm:
@@ -1610,7 +1591,7 @@
 		return rc;
 	}
 	case OBD_IOC_LLOG_CATINFO: {
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	}
 	case OBD_IOC_QUOTACHECK: {
 		struct obd_quotactl *oqctl;
@@ -1618,11 +1599,11 @@
 
 		if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
 		    sbi->ll_flags & LL_SBI_RMT_CLIENT)
-			RETURN(-EPERM);
+			return -EPERM;
 
 		OBD_ALLOC_PTR(oqctl);
 		if (!oqctl)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		oqctl->qc_type = arg;
 		rc = obd_quotacheck(sbi->ll_md_exp, oqctl);
 		if (rc < 0) {
@@ -1642,11 +1623,11 @@
 
 		if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
 		    sbi->ll_flags & LL_SBI_RMT_CLIENT)
-			RETURN(-EPERM);
+			return -EPERM;
 
 		OBD_ALLOC_PTR(check);
 		if (!check)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		rc = obd_iocontrol(cmd, sbi->ll_md_exp, 0, (void *)check,
 				   NULL);
@@ -1669,7 +1650,7 @@
 		}
 	out_poll:
 		OBD_FREE_PTR(check);
-		RETURN(rc);
+		return rc;
 	}
 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0)
 	case LL_IOC_QUOTACTL_18: {
@@ -1680,7 +1661,7 @@
 
 		OBD_ALLOC_PTR(qctl_18);
 		if (!qctl_18)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		OBD_ALLOC_PTR(qctl_20);
 		if (!qctl_20)
@@ -1720,7 +1701,7 @@
 		OBD_FREE_PTR(qctl_20);
 	out_quotactl_18:
 		OBD_FREE_PTR(qctl_18);
-		RETURN(rc);
+		return rc;
 	}
 #else
 #warning "remove old LL_IOC_QUOTACTL_18 compatibility code"
@@ -1730,7 +1711,7 @@
 
 		OBD_ALLOC_PTR(qctl);
 		if (!qctl)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		if (copy_from_user(qctl, (void *)arg, sizeof(*qctl)))
 			GOTO(out_quotactl, rc = -EFAULT);
@@ -1742,13 +1723,13 @@
 
 	out_quotactl:
 		OBD_FREE_PTR(qctl);
-		RETURN(rc);
+		return rc;
 	}
 	case OBD_IOC_GETDTNAME:
 	case OBD_IOC_GETMDNAME:
-		RETURN(ll_get_obd_name(inode, cmd, arg));
+		return ll_get_obd_name(inode, cmd, arg);
 	case LL_IOC_FLUSHCTX:
-		RETURN(ll_flush_ctx(inode));
+		return ll_flush_ctx(inode);
 #ifdef CONFIG_FS_POSIX_ACL
 	case LL_IOC_RMTACL: {
 	    if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
@@ -1759,9 +1740,9 @@
 		rc = rct_add(&sbi->ll_rct, current_pid(), arg);
 		if (!rc)
 			fd->fd_flags |= LL_FILE_RMTACL;
-		RETURN(rc);
+		return rc;
 	    } else
-		RETURN(0);
+		return 0;
 	}
 #endif
 	case LL_IOC_GETOBDCOUNT: {
@@ -1769,7 +1750,7 @@
 		struct obd_export *exp;
 
 		if (copy_from_user(&count, (int *)arg, sizeof(int)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		/* get ost count when count is zero, get mdt count otherwise */
 		exp = count ? sbi->ll_md_exp : sbi->ll_dt_exp;
@@ -1778,41 +1759,41 @@
 				  KEY_TGT_COUNT, &vallen, &count, NULL);
 		if (rc) {
 			CERROR("get target count failed: %d\n", rc);
-			RETURN(rc);
+			return rc;
 		}
 
 		if (copy_to_user((int *)arg, &count, sizeof(int)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
-		RETURN(0);
+		return 0;
 	}
 	case LL_IOC_PATH2FID:
 		if (copy_to_user((void *)arg, ll_inode2fid(inode),
 				     sizeof(struct lu_fid)))
-			RETURN(-EFAULT);
-		RETURN(0);
+			return -EFAULT;
+		return 0;
 	case LL_IOC_GET_CONNECT_FLAGS: {
-		RETURN(obd_iocontrol(cmd, sbi->ll_md_exp, 0, NULL, (void*)arg));
+		return obd_iocontrol(cmd, sbi->ll_md_exp, 0, NULL, (void*)arg);
 	}
 	case OBD_IOC_CHANGELOG_SEND:
 	case OBD_IOC_CHANGELOG_CLEAR:
 		rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void *)arg,
 				    sizeof(struct ioc_changelog));
-		RETURN(rc);
+		return rc;
 	case OBD_IOC_FID2PATH:
-		RETURN(ll_fid2path(inode, (void *)arg));
+		return ll_fid2path(inode, (void *)arg);
 	case LL_IOC_HSM_REQUEST: {
 		struct hsm_user_request	*hur;
 		int			 totalsize;
 
 		OBD_ALLOC_PTR(hur);
 		if (hur == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		/* We don't know the true size yet; copy the fixed-size part */
 		if (copy_from_user(hur, (void *)arg, sizeof(*hur))) {
 			OBD_FREE_PTR(hur);
-			RETURN(-EFAULT);
+			return -EFAULT;
 		}
 
 		/* Compute the whole struct size */
@@ -1820,12 +1801,12 @@
 		OBD_FREE_PTR(hur);
 		OBD_ALLOC_LARGE(hur, totalsize);
 		if (hur == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		/* Copy the whole struct */
 		if (copy_from_user(hur, (void *)arg, totalsize)) {
 			OBD_FREE_LARGE(hur, totalsize);
-			RETURN(-EFAULT);
+			return -EFAULT;
 		}
 
 		rc = obd_iocontrol(cmd, ll_i2mdexp(inode), totalsize,
@@ -1833,14 +1814,14 @@
 
 		OBD_FREE_LARGE(hur, totalsize);
 
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_HSM_PROGRESS: {
 		struct hsm_progress_kernel	hpk;
 		struct hsm_progress		hp;
 
 		if (copy_from_user(&hp, (void *)arg, sizeof(hp)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		hpk.hpk_fid = hp.hp_fid;
 		hpk.hpk_cookie = hp.hp_cookie;
@@ -1853,12 +1834,12 @@
 		 * reported to Lustre root */
 		rc = obd_iocontrol(cmd, sbi->ll_md_exp, sizeof(hpk), &hpk,
 				   NULL);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_HSM_CT_START:
 		rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void *)arg,
 				    sizeof(struct lustre_kernelcomm));
-		RETURN(rc);
+		return rc;
 
 	case LL_IOC_HSM_COPY_START: {
 		struct hsm_copy	*copy;
@@ -1866,10 +1847,10 @@
 
 		OBD_ALLOC_PTR(copy);
 		if (copy == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		if (copy_from_user(copy, (char *)arg, sizeof(*copy))) {
 			OBD_FREE_PTR(copy);
-			RETURN(-EFAULT);
+			return -EFAULT;
 		}
 
 		rc = ll_ioc_copy_start(inode->i_sb, copy);
@@ -1877,7 +1858,7 @@
 			rc = -EFAULT;
 
 		OBD_FREE_PTR(copy);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_HSM_COPY_END: {
 		struct hsm_copy	*copy;
@@ -1885,10 +1866,10 @@
 
 		OBD_ALLOC_PTR(copy);
 		if (copy == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		if (copy_from_user(copy, (char *)arg, sizeof(*copy))) {
 			OBD_FREE_PTR(copy);
-			RETURN(-EFAULT);
+			return -EFAULT;
 		}
 
 		rc = ll_ioc_copy_end(inode->i_sb, copy);
@@ -1896,11 +1877,10 @@
 			rc = -EFAULT;
 
 		OBD_FREE_PTR(copy);
-		RETURN(rc);
+		return rc;
 	}
 	default:
-		RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL,
-				     (void *)arg));
+		return obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL, (void *)arg);
 	}
 }
 
@@ -1911,7 +1891,6 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	int api32 = ll_need_32bit_api(sbi);
 	loff_t ret = -EINVAL;
-	ENTRY;
 
 	mutex_lock(&inode->i_mutex);
 	switch (origin) {
@@ -1957,14 +1936,12 @@
 
 int ll_dir_open(struct inode *inode, struct file *file)
 {
-	ENTRY;
-	RETURN(ll_file_open(inode, file));
+	return ll_file_open(inode, file);
 }
 
 int ll_dir_release(struct inode *inode, struct file *file)
 {
-	ENTRY;
-	RETURN(ll_file_release(inode, file));
+	return ll_file_release(inode, file);
 }
 
 struct file_operations ll_dir_operations = {
@@ -1972,7 +1949,7 @@
 	.open     = ll_dir_open,
 	.release  = ll_dir_release,
 	.read     = generic_read_dir,
-	.readdir  = ll_readdir,
+	.iterate  = ll_readdir,
 	.unlocked_ioctl   = ll_dir_ioctl,
 	.fsync    = ll_fsync,
 };
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index ed1e3f7..253f026 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -55,6 +55,8 @@
 	struct ll_file_data *fd;
 
 	OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, __GFP_IO);
+	if (fd == NULL)
+		return NULL;
 	fd->fd_write_failed = false;
 	return fd;
 }
@@ -93,8 +95,6 @@
 static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data,
 			     struct obd_client_handle *och)
 {
-	ENTRY;
-
 	op_data->op_attr.ia_valid = ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
 					ATTR_MTIME | ATTR_MTIME_SET |
 					ATTR_CTIME | ATTR_CTIME_SET;
@@ -111,7 +111,6 @@
 	ll_pack_inode2opdata(inode, op_data, &och->och_fh);
 	ll_prep_md_op_data(op_data, inode, NULL, NULL,
 			   0, 0, LUSTRE_OPC_ANY, NULL);
-	EXIT;
 }
 
 static int ll_close_inode_openhandle(struct obd_export *md_exp,
@@ -124,7 +123,6 @@
 	struct obd_device *obd = class_exp2obd(exp);
 	int epoch_close = 1;
 	int rc;
-	ENTRY;
 
 	if (obd == NULL) {
 		/*
@@ -178,9 +176,7 @@
 			       inode->i_ino, rc);
 	}
 
-	EXIT;
 out:
-
 	if (exp_connect_som(exp) && !epoch_close &&
 	    S_ISREG(inode->i_mode) && (och->och_flags & FMODE_WRITE)) {
 		ll_queue_done_writing(inode, LLIF_DONE_WRITING);
@@ -202,7 +198,6 @@
 	struct obd_client_handle *och;
 	__u64 *och_usecount;
 	int rc = 0;
-	ENTRY;
 
 	if (flags & FMODE_WRITE) {
 		och_p = &lli->lli_mds_write_och;
@@ -220,7 +215,7 @@
 	if (*och_usecount) { /* There are still users of this handle, so
 				skip freeing it. */
 		mutex_unlock(&lli->lli_och_mutex);
-		RETURN(0);
+		return 0;
 	}
 	och=*och_p;
 	*och_p = NULL;
@@ -232,7 +227,7 @@
 					       inode, och);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 int ll_md_close(struct obd_export *md_exp, struct inode *inode,
@@ -241,7 +236,6 @@
 	struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
 	struct ll_inode_info *lli = ll_i2info(inode);
 	int rc = 0;
-	ENTRY;
 
 	/* clear group lock, if present */
 	if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED))
@@ -287,7 +281,7 @@
 	ll_file_data_put(fd);
 	ll_capa_close(inode);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* While this returns an error code, fput() the caller does not, so we need
@@ -301,7 +295,6 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct ll_inode_info *lli = ll_i2info(inode);
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
 	       inode->i_generation, inode);
@@ -335,7 +328,7 @@
 	if (inode->i_sb->s_root == file->f_dentry) {
 		LUSTRE_FPRIVATE(file) = NULL;
 		ll_file_data_put(fd);
-		RETURN(0);
+		return 0;
 	}
 
 	if (!S_ISDIR(inode->i_mode)) {
@@ -348,7 +341,7 @@
 	if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
 		libcfs_debug_dumplog();
 
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_intent_file_open(struct file *file, void *lmm,
@@ -362,10 +355,9 @@
 	struct ptlrpc_request *req;
 	__u32 opc = LUSTRE_OPC_ANY;
 	int rc;
-	ENTRY;
 
 	if (!parent)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	/* Usually we come here only for NFSD, and we want open lock.
 	   But we can also get here with pre 2.6.15 patchless kernels, and in
@@ -386,7 +378,7 @@
 				      file->f_dentry->d_inode, name, len,
 				      O_RDWR, opc, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	itp->it_flags |= MDS_OPEN_BY_FID;
 	rc = md_intent_lock(sbi->ll_md_exp, op_data, lmm, lmmsize, itp,
@@ -422,7 +414,7 @@
 	it_clear_disposition(itp, DISP_ENQ_COMPLETE);
 	ll_intent_drop_lock(itp);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -464,7 +456,6 @@
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct ll_inode_info *lli = ll_i2info(inode);
-	ENTRY;
 
 	LASSERT(!LUSTRE_FPRIVATE(file));
 
@@ -477,7 +468,7 @@
 
 		rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, lli, it, och);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 		if ((it->it_flags & FMODE_WRITE) &&
@@ -489,7 +480,7 @@
 	LUSTRE_FPRIVATE(file) = fd;
 	ll_readahead_init(inode, &fd->fd_ras);
 	fd->fd_omode = it->it_flags;
-	RETURN(0);
+	return 0;
 }
 
 /* Open a file, and (for the very first open) create objects on the OSTs at
@@ -514,7 +505,6 @@
 	__u64 *och_usecount = NULL;
 	struct ll_file_data *fd;
 	int rc = 0, opendir_set = 0;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), flags %o\n", inode->i_ino,
 	       inode->i_generation, inode, file->f_flags);
@@ -524,7 +514,7 @@
 
 	fd = ll_file_data_get();
 	if (fd == NULL)
-		GOTO(out_och_free, rc = -ENOMEM);
+		GOTO(out_openerr, rc = -ENOMEM);
 
 	fd->fd_file = file;
 	if (S_ISDIR(inode->i_mode)) {
@@ -540,7 +530,7 @@
 
 	if (inode->i_sb->s_root == file->f_dentry) {
 		LUSTRE_FPRIVATE(file) = fd;
-		RETURN(0);
+		return 0;
 	}
 
 	if (!it || !it->d.lustre.it_disposition) {
@@ -700,8 +690,6 @@
 	struct obd_info	    oinfo = { { { 0 } } };
 	int			rc;
 
-	ENTRY;
-
 	LASSERT(lsm != NULL);
 
 	oinfo.oi_md = lsm;
@@ -736,7 +724,7 @@
 					 OBD_MD_FLATIME | OBD_MD_FLMTIME |
 					 OBD_MD_FLCTIME | OBD_MD_FLSIZE |
 					 OBD_MD_FLDATAVERSION);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -749,7 +737,6 @@
 	struct obd_capa      *capa = ll_mdscapa_get(inode);
 	struct lov_stripe_md *lsm;
 	int rc;
-	ENTRY;
 
 	lsm = ccc_inode_lsm_get(inode);
 	rc = ll_lsm_getattr(lsm, ll_i2dtexp(inode),
@@ -765,7 +752,7 @@
 		       (unsigned long)ll_inode_blksize(inode));
 	}
 	ccc_inode_lsm_put(inode, lsm);
-	RETURN(rc);
+	return rc;
 }
 
 int ll_merge_lvb(const struct lu_env *env, struct inode *inode)
@@ -776,8 +763,6 @@
 	struct ost_lvb lvb;
 	int rc = 0;
 
-	ENTRY;
-
 	ll_inode_size_lock(inode);
 	/* merge timestamps the most recently obtained from mds with
 	   timestamps obtained from osts */
@@ -810,7 +795,7 @@
 	}
 	ll_inode_size_unlock(inode);
 
-	RETURN(rc);
+	return rc;
 }
 
 int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm,
@@ -860,7 +845,6 @@
 	struct ll_file_data  *fd  = LUSTRE_FPRIVATE(file);
 	struct cl_io	 *io;
 	ssize_t	       result;
-	ENTRY;
 
 restart:
 	io = ccc_env_thread_io(env);
@@ -986,15 +970,14 @@
 	size_t	      count;
 	ssize_t	     result;
 	int		 refcheck;
-	ENTRY;
 
 	result = ll_file_get_iov_count(iov, &nr_segs, &count);
 	if (result)
-		RETURN(result);
+		return result;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	args = vvp_env_args(env, IO_NORMAL);
 	args->u.normal.via_iov = (struct iovec *)iov;
@@ -1004,7 +987,7 @@
 	result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
 				    &iocb->ki_pos, count);
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
 
 static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
@@ -1015,11 +998,10 @@
 	struct kiocb  *kiocb;
 	ssize_t	result;
 	int	    refcheck;
-	ENTRY;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	local_iov = &vvp_env_info(env)->vti_local_iov;
 	kiocb = &vvp_env_info(env)->vti_kiocb;
@@ -1033,7 +1015,7 @@
 	*ppos = kiocb->ki_pos;
 
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
 
 /*
@@ -1047,15 +1029,14 @@
 	size_t	      count;
 	ssize_t	     result;
 	int		 refcheck;
-	ENTRY;
 
 	result = ll_file_get_iov_count(iov, &nr_segs, &count);
 	if (result)
-		RETURN(result);
+		return result;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	args = vvp_env_args(env, IO_NORMAL);
 	args->u.normal.via_iov = (struct iovec *)iov;
@@ -1065,7 +1046,7 @@
 	result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
 				  &iocb->ki_pos, count);
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
 
 static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
@@ -1076,11 +1057,10 @@
 	struct kiocb  *kiocb;
 	ssize_t	result;
 	int	    refcheck;
-	ENTRY;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	local_iov = &vvp_env_info(env)->vti_local_iov;
 	kiocb = &vvp_env_info(env)->vti_kiocb;
@@ -1094,7 +1074,7 @@
 	*ppos = kiocb->ki_pos;
 
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
 
 
@@ -1110,11 +1090,10 @@
 	struct vvp_io_args *args;
 	ssize_t	     result;
 	int		 refcheck;
-	ENTRY;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	args = vvp_env_args(env, IO_SPLICE);
 	args->u.splice.via_pipe = pipe;
@@ -1122,7 +1101,7 @@
 
 	result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count);
 	cl_env_put(env, &refcheck);
-	RETURN(result);
+	return result;
 }
 
 static int ll_lov_recreate(struct inode *inode, struct ost_id *oi,
@@ -1134,14 +1113,13 @@
 	int lsm_size;
 	int rc = 0;
 	struct lov_stripe_md *lsm = NULL, *lsm2;
-	ENTRY;
 
 	OBDO_ALLOC(oa);
 	if (oa == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	lsm = ccc_inode_lsm_get(inode);
-	if (lsm == NULL)
+	if (!lsm_has_objects(lsm))
 		GOTO(out, rc = -ENOENT);
 
 	lsm_size = sizeof(*lsm) + (sizeof(struct lov_oinfo) *
@@ -1175,18 +1153,17 @@
 {
 	struct ll_recreate_obj ucreat;
 	struct ost_id		oi;
-	ENTRY;
 
 	if (!cfs_capable(CFS_CAP_SYS_ADMIN))
-		RETURN(-EPERM);
+		return -EPERM;
 
 	if (copy_from_user(&ucreat, (struct ll_recreate_obj *)arg,
 			   sizeof(ucreat)))
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	ostid_set_seq_mdt0(&oi);
 	ostid_set_id(&oi, ucreat.lrc_id);
-	RETURN(ll_lov_recreate(inode, &oi, ucreat.lrc_ost_idx));
+	return ll_lov_recreate(inode, &oi, ucreat.lrc_ost_idx);
 }
 
 static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
@@ -1194,17 +1171,16 @@
 	struct lu_fid	fid;
 	struct ost_id	oi;
 	obd_count	ost_idx;
-	ENTRY;
 
 	if (!cfs_capable(CFS_CAP_SYS_ADMIN))
-		RETURN(-EPERM);
+		return -EPERM;
 
 	if (copy_from_user(&fid, (struct lu_fid *)arg, sizeof(fid)))
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	fid_to_ostid(&fid, &oi);
 	ost_idx = (fid_seq(&fid) >> 16) & 0xffff;
-	RETURN(ll_lov_recreate(inode, &oi, ost_idx));
+	return ll_lov_recreate(inode, &oi, ost_idx);
 }
 
 int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
@@ -1213,14 +1189,13 @@
 	struct lov_stripe_md *lsm = NULL;
 	struct lookup_intent oit = {.it_op = IT_OPEN, .it_flags = flags};
 	int rc = 0;
-	ENTRY;
 
 	lsm = ccc_inode_lsm_get(inode);
 	if (lsm != NULL) {
 		ccc_inode_lsm_put(inode, lsm);
 		CDEBUG(D_IOCTL, "stripe already exists for ino %lu\n",
 		       inode->i_ino);
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 
 	ll_inode_size_lock(inode);
@@ -1237,7 +1212,7 @@
 	ll_inode_size_unlock(inode);
 	ll_intent_release(&oit);
 	ccc_inode_lsm_put(inode, lsm);
-	RETURN(rc);
+	return rc;
 out_req_free:
 	ptlrpc_req_finished((struct ptlrpc_request *) oit.d.lustre.it_data);
 	goto out;
@@ -1256,13 +1231,13 @@
 
 	rc = ll_get_max_mdsize(sbi, &lmmsize);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	op_data = ll_prep_md_op_data(NULL, inode, NULL, filename,
 				     strlen(filename), lmmsize,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
 	rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
@@ -1297,6 +1272,12 @@
 	 * passing it to userspace.
 	 */
 	if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC)) {
+		int stripe_count;
+
+		stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+		if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+			stripe_count = 0;
+
 		/* if function called for directory - we should
 		 * avoid swab not existent lsm objects */
 		if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) {
@@ -1304,13 +1285,13 @@
 			if (S_ISREG(body->mode))
 				lustre_swab_lov_user_md_objects(
 				 ((struct lov_user_md_v1 *)lmm)->lmm_objects,
-				 ((struct lov_user_md_v1 *)lmm)->lmm_stripe_count);
+				 stripe_count);
 		} else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) {
 			lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)lmm);
 			if (S_ISREG(body->mode))
 				lustre_swab_lov_user_md_objects(
 				 ((struct lov_user_md_v3 *)lmm)->lmm_objects,
-				 ((struct lov_user_md_v3 *)lmm)->lmm_stripe_count);
+				 stripe_count);
 		}
 	}
 
@@ -1329,24 +1310,23 @@
 	int			 lum_size = sizeof(struct lov_user_md) +
 					    sizeof(struct lov_user_ost_data);
 	int			 rc;
-	ENTRY;
 
 	if (!cfs_capable(CFS_CAP_SYS_ADMIN))
-		RETURN(-EPERM);
+		return -EPERM;
 
 	OBD_ALLOC_LARGE(lump, lum_size);
 	if (lump == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (copy_from_user(lump, (struct lov_user_md  *)arg, lum_size)) {
 		OBD_FREE_LARGE(lump, lum_size);
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 
 	rc = ll_lov_setstripe_ea_info(inode, file, flags, lump, lum_size);
 
 	OBD_FREE_LARGE(lump, lum_size);
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_lov_setstripe(struct inode *inode, struct file *file,
@@ -1358,17 +1338,16 @@
 	struct lov_user_md_v3	*lumv3p = (struct lov_user_md_v3 *)arg;
 	int			 lum_size, rc;
 	int			 flags = FMODE_WRITE;
-	ENTRY;
 
 	/* first try with v1 which is smaller than v3 */
 	lum_size = sizeof(struct lov_user_md_v1);
 	if (copy_from_user(lumv1, lumv1p, lum_size))
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	if (lumv1->lmm_magic == LOV_USER_MAGIC_V3) {
 		lum_size = sizeof(struct lov_user_md_v3);
 		if (copy_from_user(&lumv3, lumv3p, lum_size))
-			RETURN(-EFAULT);
+			return -EFAULT;
 	}
 
 	rc = ll_lov_setstripe_ea_info(inode, file, flags, lumv1, lum_size);
@@ -1384,21 +1363,20 @@
 				   0, lsm, (void *)arg);
 		ccc_inode_lsm_put(inode, lsm);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_lov_getstripe(struct inode *inode, unsigned long arg)
 {
 	struct lov_stripe_md *lsm;
 	int rc = -ENODATA;
-	ENTRY;
 
 	lsm = ccc_inode_lsm_get(inode);
 	if (lsm != NULL)
 		rc = obd_iocontrol(LL_IOC_LOV_GETSTRIPE, ll_i2dtexp(inode), 0,
 				   lsm, (void *)arg);
 	ccc_inode_lsm_put(inode, lsm);
-	RETURN(rc);
+	return rc;
 }
 
 int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
@@ -1407,17 +1385,16 @@
 	struct ll_file_data    *fd = LUSTRE_FPRIVATE(file);
 	struct ccc_grouplock    grouplock;
 	int		     rc;
-	ENTRY;
 
 	if (ll_file_nolock(file))
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	spin_lock(&lli->lli_lock);
 	if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
 		CWARN("group lock already existed with gid %lu\n",
 		      fd->fd_grouplock.cg_gid);
 		spin_unlock(&lli->lli_lock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	LASSERT(fd->fd_grouplock.cg_lock == NULL);
 	spin_unlock(&lli->lli_lock);
@@ -1425,14 +1402,14 @@
 	rc = cl_get_grouplock(cl_i2info(inode)->lli_clob,
 			      arg, (file->f_flags & O_NONBLOCK), &grouplock);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	spin_lock(&lli->lli_lock);
 	if (fd->fd_flags & LL_FILE_GROUP_LOCKED) {
 		spin_unlock(&lli->lli_lock);
 		CERROR("another thread just won the race\n");
 		cl_put_grouplock(&grouplock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	fd->fd_flags |= LL_FILE_GROUP_LOCKED;
@@ -1440,7 +1417,7 @@
 	spin_unlock(&lli->lli_lock);
 
 	CDEBUG(D_INFO, "group lock %lu obtained\n", arg);
-	RETURN(0);
+	return 0;
 }
 
 int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
@@ -1448,13 +1425,12 @@
 	struct ll_inode_info   *lli = ll_i2info(inode);
 	struct ll_file_data    *fd = LUSTRE_FPRIVATE(file);
 	struct ccc_grouplock    grouplock;
-	ENTRY;
 
 	spin_lock(&lli->lli_lock);
 	if (!(fd->fd_flags & LL_FILE_GROUP_LOCKED)) {
 		spin_unlock(&lli->lli_lock);
 		CWARN("no group lock held\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	LASSERT(fd->fd_grouplock.cg_lock != NULL);
 
@@ -1462,7 +1438,7 @@
 		CWARN("group lock %lu doesn't match current id %lu\n",
 		       arg, fd->fd_grouplock.cg_gid);
 		spin_unlock(&lli->lli_lock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	grouplock = fd->fd_grouplock;
@@ -1472,7 +1448,7 @@
 
 	cl_put_grouplock(&grouplock);
 	CDEBUG(D_INFO, "group lock %lu released\n", arg);
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1489,17 +1465,16 @@
 	struct inode *inode = dentry->d_inode;
 	struct obd_client_handle *och;
 	int rc;
-	ENTRY;
 
 	LASSERT(inode);
 
 	/* Root ? Do nothing. */
 	if (dentry->d_inode->i_sb->s_root == dentry)
-		RETURN(0);
+		return 0;
 
 	/* No open handle to close? Move away */
 	if (!it_disposition(it, DISP_OPEN_OPEN))
-		RETURN(0);
+		return 0;
 
 	LASSERT(it_open_error(DISP_OPEN_OPEN, it) == 0);
 
@@ -1518,7 +1493,7 @@
 		ptlrpc_req_finished(it->d.lustre.it_data);
 		it_clear_disposition(it, DISP_ENQ_OPEN_REF);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1533,7 +1508,6 @@
 	struct ll_fiemap_info_key fm_key = { .name = KEY_FIEMAP, };
 	int vallen = num_bytes;
 	int rc;
-	ENTRY;
 
 	/* Checks for fiemap flags */
 	if (fiemap->fm_flags & ~LUSTRE_FIEMAP_FLAGS_COMPAT) {
@@ -1579,7 +1553,7 @@
 
 out:
 	ccc_inode_lsm_put(inode, lsm);
-	RETURN(rc);
+	return rc;
 }
 
 int ll_fid2path(struct inode *inode, void *arg)
@@ -1587,26 +1561,25 @@
 	struct obd_export	*exp = ll_i2mdexp(inode);
 	struct getinfo_fid2path	*gfout, *gfin;
 	int			 outsize, rc;
-	ENTRY;
 
 	if (!cfs_capable(CFS_CAP_DAC_READ_SEARCH) &&
 	    !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH))
-		RETURN(-EPERM);
+		return -EPERM;
 
 	/* Need to get the buflen */
 	OBD_ALLOC_PTR(gfin);
 	if (gfin == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	if (copy_from_user(gfin, arg, sizeof(*gfin))) {
 		OBD_FREE_PTR(gfin);
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 
 	outsize = sizeof(*gfout) + gfin->gf_pathlen;
 	OBD_ALLOC(gfout, outsize);
 	if (gfout == NULL) {
 		OBD_FREE_PTR(gfin);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 	memcpy(gfout, gfin, sizeof(*gfout));
 	OBD_FREE_PTR(gfin);
@@ -1621,7 +1594,7 @@
 
 gf_free:
 	OBD_FREE(gfout, outsize);
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_ioctl_fiemap(struct inode *inode, unsigned long arg)
@@ -1635,13 +1608,13 @@
 	 * required fiemap buffer */
 	if (get_user(extent_count,
 	    &((struct ll_user_fiemap __user *)arg)->fm_extent_count))
-		RETURN(-EFAULT);
+		return -EFAULT;
 	num_bytes = sizeof(*fiemap_s) + (extent_count *
 					 sizeof(struct ll_fiemap_extent));
 
 	OBD_ALLOC_LARGE(fiemap_s, num_bytes);
 	if (fiemap_s == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* get the fiemap value */
 	if (copy_from_user(fiemap_s, (struct ll_user_fiemap __user *)arg,
@@ -1673,7 +1646,7 @@
 
 error:
 	OBD_FREE_LARGE(fiemap_s, num_bytes);
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -1692,24 +1665,21 @@
 	struct ll_sb_info	*sbi = ll_i2sbi(inode);
 	struct obdo		*obdo = NULL;
 	int			 rc;
-	ENTRY;
 
 	/* If no stripe, we consider version is 0. */
 	lsm = ccc_inode_lsm_get(inode);
-	if (lsm == NULL) {
+	if (!lsm_has_objects(lsm)) {
 		*data_version = 0;
 		CDEBUG(D_INODE, "No object for inode\n");
-		RETURN(0);
+		GOTO(out, rc = 0);
 	}
 
 	OBD_ALLOC_PTR(obdo);
-	if (obdo == NULL) {
-		ccc_inode_lsm_put(inode, lsm);
-		RETURN(-ENOMEM);
-	}
+	if (obdo == NULL)
+		GOTO(out, rc = -ENOMEM);
 
 	rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, obdo, 0, extent_lock);
-	if (!rc) {
+	if (rc == 0) {
 		if (!(obdo->o_valid & OBD_MD_FLDATAVERSION))
 			rc = -EOPNOTSUPP;
 		else
@@ -1717,9 +1687,9 @@
 	}
 
 	OBD_FREE_PTR(obdo);
+out:
 	ccc_inode_lsm_put(inode, lsm);
-
-	RETURN(rc);
+	return rc;
 }
 
 struct ll_swap_stack {
@@ -1741,7 +1711,7 @@
 
 	OBD_ALLOC_PTR(llss);
 	if (llss == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	llss->inode1 = file1->f_dentry->d_inode;
 	llss->inode2 = file2->f_dentry->d_inode;
@@ -1749,8 +1719,8 @@
 	if (!S_ISREG(llss->inode2->i_mode))
 		GOTO(free, rc = -EINVAL);
 
-	if (ll_permission(llss->inode1, MAY_WRITE, NULL) ||
-	    ll_permission(llss->inode2, MAY_WRITE, NULL))
+	if (inode_permission(llss->inode1, MAY_WRITE) ||
+	    inode_permission(llss->inode2, MAY_WRITE))
 		GOTO(free, rc = -EPERM);
 
 	if (llss->inode2->i_sb != llss->inode1->i_sb)
@@ -1830,12 +1800,12 @@
 	rc = -ENOMEM;
 	op_data = ll_prep_md_op_data(NULL, llss->inode1, llss->inode2, NULL, 0,
 				     0, LUSTRE_OPC_ANY, &msl);
-	if (op_data != NULL) {
-		rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS,
-				   ll_i2mdexp(llss->inode1),
-				   sizeof(*op_data), op_data, NULL);
-		ll_finish_md_op_data(op_data);
-	}
+	if (IS_ERR(op_data))
+		GOTO(free, rc = PTR_ERR(op_data));
+
+	rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS, ll_i2mdexp(llss->inode1),
+			   sizeof(*op_data), op_data, NULL);
+	ll_finish_md_op_data(op_data);
 
 putgl:
 	if (gid != 0) {
@@ -1880,7 +1850,7 @@
 	if (llss != NULL)
 		OBD_FREE_PTR(llss);
 
-	RETURN(rc);
+	return rc;
 }
 
 long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1888,7 +1858,6 @@
 	struct inode		*inode = file->f_dentry->d_inode;
 	struct ll_file_data	*fd = LUSTRE_FPRIVATE(file);
 	int			 flags, rc;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),cmd=%x\n", inode->i_ino,
 	       inode->i_generation, inode, cmd);
@@ -1896,7 +1865,7 @@
 
 	/* asm-ppc{,64} declares TCGETS, et. al. as type 't' not 'T' */
 	if (_IOC_TYPE(cmd) == 'T' || _IOC_TYPE(cmd) == 't') /* tty ioctls */
-		RETURN(-ENOTTY);
+		return -ENOTTY;
 
 	switch(cmd) {
 	case LL_IOC_GETFLAGS:
@@ -1909,66 +1878,66 @@
 		 *     not abused, and to handle any flag side effects.
 		 */
 		if (get_user(flags, (int *) arg))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		if (cmd == LL_IOC_SETFLAGS) {
 			if ((flags & LL_FILE_IGNORE_LOCK) &&
 			    !(file->f_flags & O_DIRECT)) {
 				CERROR("%s: unable to disable locking on "
 				       "non-O_DIRECT file\n", current->comm);
-				RETURN(-EINVAL);
+				return -EINVAL;
 			}
 
 			fd->fd_flags |= flags;
 		} else {
 			fd->fd_flags &= ~flags;
 		}
-		RETURN(0);
+		return 0;
 	case LL_IOC_LOV_SETSTRIPE:
-		RETURN(ll_lov_setstripe(inode, file, arg));
+		return ll_lov_setstripe(inode, file, arg);
 	case LL_IOC_LOV_SETEA:
-		RETURN(ll_lov_setea(inode, file, arg));
+		return ll_lov_setea(inode, file, arg);
 	case LL_IOC_LOV_SWAP_LAYOUTS: {
 		struct file *file2;
 		struct lustre_swap_layouts lsl;
 
 		if (copy_from_user(&lsl, (char *)arg,
 				       sizeof(struct lustre_swap_layouts)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		if ((file->f_flags & O_ACCMODE) == 0) /* O_RDONLY */
-			RETURN(-EPERM);
+			return -EPERM;
 
 		file2 = fget(lsl.sl_fd);
 		if (file2 == NULL)
-			RETURN(-EBADF);
+			return -EBADF;
 
 		rc = -EPERM;
 		if ((file2->f_flags & O_ACCMODE) != 0) /* O_WRONLY or O_RDWR */
 			rc = ll_swap_layouts(file, file2, &lsl);
 		fput(file2);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_LOV_GETSTRIPE:
-		RETURN(ll_lov_getstripe(inode, arg));
+		return ll_lov_getstripe(inode, arg);
 	case LL_IOC_RECREATE_OBJ:
-		RETURN(ll_lov_recreate_obj(inode, arg));
+		return ll_lov_recreate_obj(inode, arg);
 	case LL_IOC_RECREATE_FID:
-		RETURN(ll_lov_recreate_fid(inode, arg));
+		return ll_lov_recreate_fid(inode, arg);
 	case FSFILT_IOC_FIEMAP:
-		RETURN(ll_ioctl_fiemap(inode, arg));
+		return ll_ioctl_fiemap(inode, arg);
 	case FSFILT_IOC_GETFLAGS:
 	case FSFILT_IOC_SETFLAGS:
-		RETURN(ll_iocontrol(inode, file, cmd, arg));
+		return ll_iocontrol(inode, file, cmd, arg);
 	case FSFILT_IOC_GETVERSION_OLD:
 	case FSFILT_IOC_GETVERSION:
-		RETURN(put_user(inode->i_generation, (int *)arg));
+		return put_user(inode->i_generation, (int *)arg);
 	case LL_IOC_GROUP_LOCK:
-		RETURN(ll_get_grouplock(inode, file, arg));
+		return ll_get_grouplock(inode, file, arg);
 	case LL_IOC_GROUP_UNLOCK:
-		RETURN(ll_put_grouplock(inode, file, arg));
+		return ll_put_grouplock(inode, file, arg);
 	case IOC_OBD_STATFS:
-		RETURN(ll_obd_statfs(inode, (void *)arg));
+		return ll_obd_statfs(inode, (void *)arg);
 
 	/* We need to special case any other ioctls we want to handle,
 	 * to send them to the MDS/OST as appropriate and to properly
@@ -1977,30 +1946,30 @@
 	case FSFILT_IOC_SETVERSION:
 	*/
 	case LL_IOC_FLUSHCTX:
-		RETURN(ll_flush_ctx(inode));
+		return ll_flush_ctx(inode);
 	case LL_IOC_PATH2FID: {
 		if (copy_to_user((void *)arg, ll_inode2fid(inode),
 				 sizeof(struct lu_fid)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
-		RETURN(0);
+		return 0;
 	}
 	case OBD_IOC_FID2PATH:
-		RETURN(ll_fid2path(inode, (void *)arg));
+		return ll_fid2path(inode, (void *)arg);
 	case LL_IOC_DATA_VERSION: {
 		struct ioc_data_version	idv;
 		int			rc;
 
 		if (copy_from_user(&idv, (char *)arg, sizeof(idv)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		rc = ll_data_version(inode, &idv.idv_version,
 				!(idv.idv_flags & LL_DV_NOFLUSH));
 
 		if (rc == 0 && copy_to_user((char *) arg, &idv, sizeof(idv)))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
-		RETURN(rc);
+		return rc;
 	}
 
 	case LL_IOC_GET_MDTIDX: {
@@ -2008,16 +1977,16 @@
 
 		mdtidx = ll_get_mdt_idx(inode);
 		if (mdtidx < 0)
-			RETURN(mdtidx);
+			return mdtidx;
 
 		if (put_user((int)mdtidx, (int*)arg))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
-		RETURN(0);
+		return 0;
 	}
 	case OBD_IOC_GETDTNAME:
 	case OBD_IOC_GETMDNAME:
-		RETURN(ll_get_obd_name(inode, cmd, arg));
+		return ll_get_obd_name(inode, cmd, arg);
 	case LL_IOC_HSM_STATE_GET: {
 		struct md_op_data	*op_data;
 		struct hsm_user_state	*hus;
@@ -2025,13 +1994,13 @@
 
 		OBD_ALLOC_PTR(hus);
 		if (hus == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, hus);
-		if (op_data == NULL) {
+		if (IS_ERR(op_data)) {
 			OBD_FREE_PTR(hus);
-			RETURN(-ENOMEM);
+			return PTR_ERR(op_data);
 		}
 
 		rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2042,7 +2011,7 @@
 
 		ll_finish_md_op_data(op_data);
 		OBD_FREE_PTR(hus);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_HSM_STATE_SET: {
 		struct md_op_data	*op_data;
@@ -2051,10 +2020,10 @@
 
 		OBD_ALLOC_PTR(hss);
 		if (hss == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		if (copy_from_user(hss, (char *)arg, sizeof(*hss))) {
 			OBD_FREE_PTR(hss);
-			RETURN(-EFAULT);
+			return -EFAULT;
 		}
 
 		/* Non-root users are forbidden to set or clear flags which are
@@ -2062,14 +2031,14 @@
 		if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK)
 		    && !cfs_capable(CFS_CAP_SYS_ADMIN)) {
 			OBD_FREE_PTR(hss);
-			RETURN(-EPERM);
+			return -EPERM;
 		}
 
 		op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, hss);
-		if (op_data == NULL) {
+		if (IS_ERR(op_data)) {
 			OBD_FREE_PTR(hss);
-			RETURN(-ENOMEM);
+			return PTR_ERR(op_data);
 		}
 
 		rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2078,7 +2047,7 @@
 		ll_finish_md_op_data(op_data);
 
 		OBD_FREE_PTR(hss);
-		RETURN(rc);
+		return rc;
 	}
 	case LL_IOC_HSM_ACTION: {
 		struct md_op_data		*op_data;
@@ -2087,13 +2056,13 @@
 
 		OBD_ALLOC_PTR(hca);
 		if (hca == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, hca);
-		if (op_data == NULL) {
+		if (IS_ERR(op_data)) {
 			OBD_FREE_PTR(hca);
-			RETURN(-ENOMEM);
+			return PTR_ERR(op_data);
 		}
 
 		rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
@@ -2104,17 +2073,17 @@
 
 		ll_finish_md_op_data(op_data);
 		OBD_FREE_PTR(hca);
-		RETURN(rc);
+		return rc;
 	}
 	default: {
 		int err;
 
 		if (LLIOC_STOP ==
 		     ll_iocontrol_call(inode, file, cmd, arg, &err))
-			RETURN(err);
+			return err;
 
-		RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
-				     (void *)arg));
+		return obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
+				     (void *)arg);
 	}
 	}
 }
@@ -2125,7 +2094,6 @@
 	struct inode *inode = file->f_dentry->d_inode;
 	loff_t retval, eof = 0;
 
-	ENTRY;
 	retval = offset + ((origin == SEEK_END) ? i_size_read(inode) :
 			   (origin == SEEK_CUR) ? file->f_pos : 0);
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), to=%llu=%#llx(%d)\n",
@@ -2136,13 +2104,13 @@
 	if (origin == SEEK_END || origin == SEEK_HOLE || origin == SEEK_DATA) {
 		retval = ll_glimpse_size(inode);
 		if (retval != 0)
-			RETURN(retval);
+			return retval;
 		eof = i_size_read(inode);
 	}
 
-	retval = ll_generic_file_llseek_size(file, offset, origin,
+	retval = generic_file_llseek_size(file, offset, origin,
 					  ll_file_maxbytes(inode), eof);
-	RETURN(retval);
+	return retval;
 }
 
 int ll_flush(struct file *file, fl_owner_t id)
@@ -2184,15 +2152,14 @@
 	struct obd_capa *capa = NULL;
 	struct cl_fsync_io *fio;
 	int result;
-	ENTRY;
 
 	if (mode != CL_FSYNC_NONE && mode != CL_FSYNC_LOCAL &&
 	    mode != CL_FSYNC_DISCARD && mode != CL_FSYNC_ALL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	env = cl_env_nested_get(&nest);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	capa = ll_osscapa_get(inode, CAPA_OPC_OSS_WRITE);
 
@@ -2220,7 +2187,7 @@
 
 	capa_put(capa);
 
-	RETURN(result);
+	return result;
 }
 
 /*
@@ -2237,7 +2204,6 @@
 	struct ptlrpc_request *req;
 	struct obd_capa *oc;
 	int rc, err;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
 	       inode->i_generation, inode);
@@ -2281,23 +2247,24 @@
 	}
 
 	mutex_unlock(&inode->i_mutex);
-	RETURN(rc);
+	return rc;
 }
 
 int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
-	struct ldlm_enqueue_info einfo = { .ei_type = LDLM_FLOCK,
-					   .ei_cb_cp =ldlm_flock_completion_ast,
-					   .ei_cbdata = file_lock };
+	struct ldlm_enqueue_info einfo = {
+		.ei_type	= LDLM_FLOCK,
+		.ei_cb_cp	= ldlm_flock_completion_ast,
+		.ei_cbdata	= file_lock,
+	};
 	struct md_op_data *op_data;
 	struct lustre_handle lockh = {0};
 	ldlm_policy_data_t flock = {{0}};
 	int flags = 0;
 	int rc;
 	int rc2 = 0;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu file_lock=%p\n",
 	       inode->i_ino, file_lock);
@@ -2315,7 +2282,7 @@
 		flock.l_flock.start = file_lock->fl_start;
 		flock.l_flock.end = file_lock->fl_end;
 	} else {
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	flock.l_flock.pid = file_lock->fl_pid;
 
@@ -2350,7 +2317,7 @@
 	default:
 		CDEBUG(D_INFO, "Unknown fcntl lock type: %d\n",
 			file_lock->fl_type);
-		RETURN (-ENOTSUPP);
+		return -ENOTSUPP;
 	}
 
 	switch (cmd) {
@@ -2377,13 +2344,13 @@
 		break;
 	default:
 		CERROR("unknown fcntl lock command: %d\n", cmd);
-		RETURN (-EINVAL);
+		return -EINVAL;
 	}
 
 	op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	CDEBUG(D_DLMTRACE, "inode=%lu, pid=%u, flags=%#x, mode=%u, "
 	       "start="LPU64", end="LPU64"\n", inode->i_ino, flock.l_flock.pid,
@@ -2409,14 +2376,12 @@
 
 	ll_finish_md_op_data(op_data);
 
-	RETURN(rc);
+	return rc;
 }
 
 int ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock)
 {
-	ENTRY;
-
-	RETURN(-ENOSYS);
+	return -ENOSYS;
 }
 
 /**
@@ -2438,17 +2403,16 @@
 	struct lu_fid *fid;
 	__u64 flags;
 	int i;
-	ENTRY;
 
 	if (!inode)
-	       RETURN(0);
+	       return 0;
 
 	fid = &ll_i2info(inode)->lli_fid;
 	CDEBUG(D_INFO, "trying to match res "DFID" mode %s\n", PFID(fid),
 	       ldlm_lockname[mode]);
 
 	flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
-	for (i = 0; i < MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
+	for (i = 0; i <= MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
 		policy.l_inodebits.bits = *bits & (1 << i);
 		if (policy.l_inodebits.bits == 0)
 			continue;
@@ -2467,7 +2431,7 @@
 			}
 		}
 	}
-	RETURN(*bits == 0);
+	return *bits == 0;
 }
 
 ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
@@ -2476,7 +2440,6 @@
 	ldlm_policy_data_t policy = { .l_inodebits = {bits}};
 	struct lu_fid *fid;
 	ldlm_mode_t rc;
-	ENTRY;
 
 	fid = &ll_i2info(inode)->lli_fid;
 	CDEBUG(D_INFO, "trying to match res "DFID"\n", PFID(fid));
@@ -2484,7 +2447,7 @@
 	rc = md_lock_match(ll_i2mdexp(inode), LDLM_FL_BLOCK_GRANTED|flags,
 			   fid, LDLM_IBITS, &policy,
 			   LCK_CR|LCK_CW|LCK_PR|LCK_PW, lockh);
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_inode_revalidate_fini(struct inode *inode, int rc)
@@ -2513,7 +2476,6 @@
 	struct ptlrpc_request *req = NULL;
 	struct obd_export *exp;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(inode != NULL);
 
@@ -2537,7 +2499,7 @@
 					     dentry->d_inode, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, NULL);
 		if (IS_ERR(op_data))
-			RETURN(PTR_ERR(op_data));
+			return PTR_ERR(op_data);
 
 		oit.it_create_mode |= M_CHECK_STALE;
 		rc = md_intent_lock(exp, op_data, NULL, 0,
@@ -2575,7 +2537,7 @@
 		if (S_ISREG(inode->i_mode)) {
 			rc = ll_get_max_mdsize(sbi, &ealen);
 			if (rc)
-				RETURN(rc);
+				return rc;
 			valid |= OBD_MD_FLEASIZE | OBD_MD_FLMODEASIZE;
 		}
 
@@ -2583,7 +2545,7 @@
 					     0, ealen, LUSTRE_OPC_ANY,
 					     NULL);
 		if (IS_ERR(op_data))
-			RETURN(PTR_ERR(op_data));
+			return PTR_ERR(op_data);
 
 		op_data->op_valid = valid;
 		/* Once OBD_CONNECT_ATTRFID is not supported, we can't find one
@@ -2593,7 +2555,7 @@
 		ll_finish_md_op_data(op_data);
 		if (rc) {
 			rc = ll_inode_revalidate_fini(inode, rc);
-			RETURN(rc);
+			return rc;
 		}
 
 		rc = ll_prep_inode(&inode, req, NULL, NULL);
@@ -2608,11 +2570,10 @@
 {
 	struct inode *inode = dentry->d_inode;
 	int rc;
-	ENTRY;
 
 	rc = __ll_inode_revalidate_it(dentry, it, ibits);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	/* if object isn't regular file, don't validate size */
 	if (!S_ISREG(inode->i_mode)) {
@@ -2622,7 +2583,7 @@
 	} else {
 		rc = ll_glimpse_size(inode);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int ll_getattr_it(struct vfsmount *mnt, struct dentry *de,
@@ -2672,21 +2633,19 @@
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
 	struct posix_acl *acl = NULL;
-	ENTRY;
 
 	spin_lock(&lli->lli_lock);
 	/* VFS' acl_permission_check->check_acl will release the refcount */
 	acl = posix_acl_dup(lli->lli_posix_acl);
 	spin_unlock(&lli->lli_lock);
 
-	RETURN(acl);
+	return acl;
 }
 
 
 int ll_inode_permission(struct inode *inode, int mask)
 {
 	int rc = 0;
-	ENTRY;
 
 #ifdef MAY_NOT_BLOCK
 	if (mask & MAY_NOT_BLOCK)
@@ -2702,7 +2661,7 @@
 		rc = __ll_inode_revalidate_it(inode->i_sb->s_root, &it,
 					      MDS_INODELOCK_LOOKUP);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), inode mode %x mask %o\n",
@@ -2712,9 +2671,9 @@
 		return lustre_check_remote_perm(inode, mask);
 
 	ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1);
-	rc = ll_generic_permission(inode, mask, flags, ll_check_acl);
+	rc = generic_permission(inode, mask);
 
-	RETURN(rc);
+	return rc;
 }
 
 #define READ_METHOD aio_read
@@ -2806,16 +2765,15 @@
 {
 	unsigned int size;
 	struct llioc_data *in_data = NULL;
-	ENTRY;
 
 	if (cb == NULL || cmd == NULL ||
 	    count > LLIOC_MAX_CMD || count < 0)
-		RETURN(NULL);
+		return NULL;
 
 	size = sizeof(*in_data) + count * sizeof(unsigned int);
 	OBD_ALLOC(in_data, size);
 	if (in_data == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	memset(in_data, 0, sizeof(*in_data));
 	in_data->iocd_size = size;
@@ -2827,7 +2785,7 @@
 	list_add_tail(&in_data->iocd_list, &llioc.ioc_head);
 	up_write(&llioc.ioc_sem);
 
-	RETURN(in_data);
+	return in_data;
 }
 
 void ll_iocontrol_unregister(void *magic)
@@ -2890,14 +2848,13 @@
 	struct cl_env_nest nest;
 	struct lu_env *env;
 	int result;
-	ENTRY;
 
 	if (lli->lli_clob == NULL)
-		RETURN(0);
+		return 0;
 
 	env = cl_env_nested_get(&nest);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	result = cl_conf_set(env, lli->lli_clob, conf);
 	cl_env_nested_put(&nest, env);
@@ -2915,7 +2872,7 @@
 			ldlm_lock_allow_match(lock);
 		}
 	}
-	RETURN(result);
+	return result;
 }
 
 /* Fetch layout from MDT with getxattr request, if it's not ready yet */
@@ -2930,10 +2887,13 @@
 	void *lmm;
 	int lmmsize;
 	int rc;
-	ENTRY;
 
-	if (lock->l_lvb_data != NULL)
-		RETURN(0);
+	CDEBUG(D_INODE, DFID" LVB_READY=%d l_lvb_data=%p l_lvb_len=%d\n",
+	       PFID(ll_inode2fid(inode)), !!(lock->l_flags & LDLM_FL_LVB_READY),
+	       lock->l_lvb_data, lock->l_lvb_len);
+
+	if ((lock->l_lvb_data != NULL) && (lock->l_flags & LDLM_FL_LVB_READY))
+		return 0;
 
 	/* if layout lock was granted right away, the layout is returned
 	 * within DLM_LVB of dlm reply; otherwise if the lock was ever
@@ -2948,7 +2908,7 @@
 				lmmsize, 0, &req);
 	capa_put(oc);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 	if (body == NULL || body->eadatasize > lmmsize)
@@ -2968,16 +2928,12 @@
 
 	memcpy(lvbdata, lmm, lmmsize);
 	lock_res_and_lock(lock);
-	if (lock->l_lvb_data == NULL) {
-		lock->l_lvb_data = lvbdata;
-		lock->l_lvb_len = lmmsize;
-		lvbdata = NULL;
-	}
-	unlock_res_and_lock(lock);
+	if (lock->l_lvb_data != NULL)
+		OBD_FREE_LARGE(lock->l_lvb_data, lock->l_lvb_len);
 
-	if (lvbdata != NULL)
-		OBD_FREE_LARGE(lvbdata, lmmsize);
-	EXIT;
+	lock->l_lvb_data = lvbdata;
+	lock->l_lvb_len = lmmsize;
+	unlock_res_and_lock(lock);
 
 out:
 	ptlrpc_req_finished(req);
@@ -2999,7 +2955,6 @@
 	int rc = 0;
 	bool lvb_ready;
 	bool wait_layout = false;
-	ENTRY;
 
 	LASSERT(lustre_handle_is_used(lockh));
 
@@ -3008,7 +2963,7 @@
 	LASSERT(ldlm_has_layout(lock));
 
 	LDLM_DEBUG(lock, "File %p/"DFID" being reconfigured: %d.\n",
-		inode, PFID(&lli->lli_fid), reconf);
+		   inode, PFID(&lli->lli_fid), reconf);
 
 	/* in case this is a caching lock and reinstate with new inode */
 	md_set_lock_data(sbi->ll_md_exp, &lockh->cookie, inode, NULL);
@@ -3068,7 +3023,6 @@
 
 	/* refresh layout failed, need to wait */
 	wait_layout = rc == -EBUSY;
-	EXIT;
 
 out:
 	LDLM_LOCK_PUT(lock);
@@ -3090,7 +3044,7 @@
 		CDEBUG(D_INODE, "file: "DFID" waiting layout return: %d.\n",
 			PFID(&lli->lli_fid), rc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -3114,17 +3068,17 @@
 	struct lookup_intent   it;
 	struct lustre_handle   lockh;
 	ldlm_mode_t	       mode;
-	struct ldlm_enqueue_info einfo = { .ei_type = LDLM_IBITS,
-					   .ei_mode = LCK_CR,
-					   .ei_cb_bl = ll_md_blocking_ast,
-					   .ei_cb_cp = ldlm_completion_ast,
-					   .ei_cbdata = NULL };
+	struct ldlm_enqueue_info einfo = {
+		.ei_type = LDLM_IBITS,
+		.ei_mode = LCK_CR,
+		.ei_cb_bl = ll_md_blocking_ast,
+		.ei_cb_cp = ldlm_completion_ast,
+	};
 	int rc;
-	ENTRY;
 
 	*gen = lli->lli_layout_gen;
 	if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK))
-		RETURN(0);
+		return 0;
 
 	/* sanity checks */
 	LASSERT(fid_is_sane(ll_inode2fid(inode)));
@@ -3136,7 +3090,7 @@
 	if (mode != 0) { /* hit cached lock */
 		rc = ll_layout_lock_set(&lockh, mode, inode, gen, false);
 		if (rc == 0)
-			RETURN(0);
+			return 0;
 
 		/* better hold lli_layout_mutex to try again otherwise
 		 * it will have starvation problem. */
@@ -3154,14 +3108,14 @@
 			goto again;
 
 		mutex_unlock(&lli->lli_layout_mutex);
-		RETURN(rc);
+		return rc;
 	}
 
 	op_data = ll_prep_md_op_data(NULL, inode, inode, NULL,
 			0, 0, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data)) {
 		mutex_unlock(&lli->lli_layout_mutex);
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 	}
 
 	/* have to enqueue one */
@@ -3194,5 +3148,5 @@
 	}
 	mutex_unlock(&lli->lli_layout_mutex);
 
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c
index b6fd959..edd512b2 100644
--- a/drivers/staging/lustre/lustre/llite/llite_capa.c
+++ b/drivers/staging/lustre/lustre/llite/llite_capa.c
@@ -41,7 +41,6 @@
 #define DEBUG_SUBSYSTEM S_LLITE
 
 #include <linux/fs.h>
-#include <linux/version.h>
 #include <asm/uaccess.h>
 #include <linux/file.h>
 #include <linux/kmod.h>
@@ -171,7 +170,6 @@
 	struct inode *inode = NULL;
 	struct l_wait_info lwi = { 0 };
 	int rc;
-	ENTRY;
 
 	thread_set_flags(&ll_capa_thread, SVC_RUNNING);
 	wake_up(&ll_capa_thread.t_ctl_waitq);
@@ -281,7 +279,7 @@
 
 	thread_set_flags(&ll_capa_thread, SVC_STOPPED);
 	wake_up(&ll_capa_thread.t_ctl_waitq);
-	RETURN(0);
+	return 0;
 }
 
 void ll_capa_timer_callback(unsigned long unused)
@@ -291,8 +289,7 @@
 
 int ll_capa_thread_start(void)
 {
-	task_t *task;
-	ENTRY;
+	struct task_struct *task;
 
 	init_waitqueue_head(&ll_capa_thread.t_ctl_waitq);
 
@@ -300,12 +297,12 @@
 	if (IS_ERR(task)) {
 		CERROR("cannot start expired capa thread: rc %ld\n",
 			PTR_ERR(task));
-		RETURN(PTR_ERR(task));
+		return PTR_ERR(task);
 	}
 	wait_event(ll_capa_thread.t_ctl_waitq,
 		       thread_is_running(&ll_capa_thread));
 
-	RETURN(0);
+	return 0;
 }
 
 void ll_capa_thread_stop(void)
@@ -322,10 +319,8 @@
 	struct obd_capa *ocapa;
 	int found = 0;
 
-	ENTRY;
-
 	if ((ll_i2sbi(inode)->ll_flags & LL_SBI_OSS_CAPA) == 0)
-		RETURN(NULL);
+		return NULL;
 
 	LASSERT(opc == CAPA_OPC_OSS_WRITE || opc == CAPA_OPC_OSS_RW ||
 		opc == CAPA_OPC_OSS_TRUNC);
@@ -369,7 +364,7 @@
 	}
 	spin_unlock(&capa_lock);
 
-	RETURN(ocapa);
+	return ocapa;
 }
 EXPORT_SYMBOL(ll_osscapa_get);
 
@@ -377,12 +372,11 @@
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
 	struct obd_capa *ocapa;
-	ENTRY;
 
 	LASSERT(inode != NULL);
 
 	if ((ll_i2sbi(inode)->ll_flags & LL_SBI_MDS_CAPA) == 0)
-		RETURN(NULL);
+		return NULL;
 
 	spin_lock(&capa_lock);
 	ocapa = capa_get(lli->lli_mds_capa);
@@ -392,7 +386,7 @@
 		atomic_set(&ll_capa_debug, 0);
 	}
 
-	RETURN(ocapa);
+	return ocapa;
 }
 
 static struct obd_capa *do_add_mds_capa(struct inode *inode,
@@ -525,7 +519,6 @@
 {
 	struct inode *inode = ocapa->u.cli.inode;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(ocapa);
 
@@ -561,7 +554,7 @@
 
 		capa_put(ocapa);
 		iput(inode);
-		RETURN(rc);
+		return rc;
 	}
 
 	spin_lock(&ocapa->c_lock);
@@ -575,7 +568,6 @@
 	if (capa_for_oss(capa))
 		inode_add_oss_capa(inode, ocapa);
 	DEBUG_CAPA(D_SEC, capa, "renew");
-	EXIT;
 retry:
 	list_del_init(&ocapa->c_list);
 	sort_add_capa(ocapa, ll_capa_list);
diff --git a/drivers/staging/lustre/lustre/llite/llite_close.c b/drivers/staging/lustre/lustre/llite/llite_close.c
index 00b2b38..1f5825c8 100644
--- a/drivers/staging/lustre/lustre/llite/llite_close.c
+++ b/drivers/staging/lustre/lustre/llite/llite_close.c
@@ -50,14 +50,12 @@
 {
 	struct ll_inode_info *lli = ll_i2info(club->cob_inode);
 
-	ENTRY;
 	spin_lock(&lli->lli_lock);
 	lli->lli_flags |= LLIF_SOM_DIRTY;
 	if (page != NULL && list_empty(&page->cpg_pending_linkage))
 		list_add(&page->cpg_pending_linkage,
 			     &club->cob_pending_list);
 	spin_unlock(&lli->lli_lock);
-	EXIT;
 }
 
 /** records that a write has completed */
@@ -66,7 +64,6 @@
 	struct ll_inode_info *lli = ll_i2info(club->cob_inode);
 	int rc = 0;
 
-	ENTRY;
 	spin_lock(&lli->lli_lock);
 	if (page != NULL && !list_empty(&page->cpg_pending_linkage)) {
 		list_del_init(&page->cpg_pending_linkage);
@@ -75,7 +72,6 @@
 	spin_unlock(&lli->lli_lock);
 	if (rc)
 		ll_queue_done_writing(club->cob_inode, 0);
-	EXIT;
 }
 
 /** Queues DONE_WRITING if
@@ -85,7 +81,6 @@
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
 	struct ccc_object *club = cl2ccc(ll_i2info(inode)->lli_clob);
-	ENTRY;
 
 	spin_lock(&lli->lli_lock);
 	lli->lli_flags |= flags;
@@ -119,14 +114,12 @@
 		spin_unlock(&lcq->lcq_lock);
 	}
 	spin_unlock(&lli->lli_lock);
-	EXIT;
 }
 
 /** Pack SOM attributes info @opdata for CLOSE, DONE_WRITING rpc. */
 void ll_done_writing_attr(struct inode *inode, struct md_op_data *op_data)
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
-	ENTRY;
 
 	op_data->op_flags |= MF_SOM_CHANGE;
 	/* Check if Size-on-MDS attributes are valid. */
@@ -140,7 +133,6 @@
 		op_data->op_attr.ia_valid |= ATTR_MTIME_SET | ATTR_CTIME_SET |
 				ATTR_ATIME_SET | ATTR_SIZE | ATTR_BLOCKS;
 	}
-	EXIT;
 }
 
 /** Closes ioepoch and packs Size-on-MDS attribute if needed into @op_data. */
@@ -149,7 +141,6 @@
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
 	struct ccc_object *club = cl2ccc(ll_i2info(inode)->lli_clob);
-	ENTRY;
 
 	spin_lock(&lli->lli_lock);
 	if (!(list_empty(&club->cob_pending_list))) {
@@ -209,7 +200,6 @@
 	spin_unlock(&lli->lli_lock);
 	ll_done_writing_attr(inode, op_data);
 
-	EXIT;
 out:
 	return;
 }
@@ -225,7 +215,6 @@
 	__u32 old_flags;
 	struct obdo *oa;
 	int rc;
-	ENTRY;
 
 	LASSERT(op_data != NULL);
 	if (lli->lli_flags & LLIF_MDS_SIZE_LOCK)
@@ -236,7 +225,7 @@
 	OBDO_ALLOC(oa);
 	if (!oa) {
 		CERROR("can't allocate memory for Size-on-MDS update.\n");
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	old_flags = op_data->op_flags;
@@ -266,7 +255,7 @@
 	ptlrpc_req_finished(request);
 
 	OBDO_FREE(oa);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -293,14 +282,12 @@
 	struct obd_client_handle *och = NULL;
 	struct md_op_data *op_data;
 	int rc;
-	ENTRY;
 
 	LASSERT(exp_connect_som(ll_i2mdexp(inode)));
 
 	OBD_ALLOC_PTR(op_data);
 	if (op_data == NULL) {
 		CERROR("can't allocate op_data\n");
-		EXIT;
 		return;
 	}
 
@@ -324,7 +311,6 @@
 		md_clear_open_replay_data(ll_i2sbi(inode)->ll_md_exp, och);
 		OBD_FREE_PTR(och);
 	}
-	EXIT;
 }
 
 static struct ll_inode_info *ll_close_next_lli(struct ll_close_queue *lcq)
@@ -347,7 +333,6 @@
 static int ll_close_thread(void *arg)
 {
 	struct ll_close_queue *lcq = arg;
-	ENTRY;
 
 	complete(&lcq->lcq_comp);
 
@@ -371,13 +356,13 @@
 
 	CDEBUG(D_INFO, "ll_close exiting\n");
 	complete(&lcq->lcq_comp);
-	RETURN(0);
+	return 0;
 }
 
 int ll_close_thread_start(struct ll_close_queue **lcq_ret)
 {
 	struct ll_close_queue *lcq;
-	task_t *task;
+	struct task_struct *task;
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CLOSE_THREAD))
 		return -EINTR;
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 5227c5c..47e443d 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -90,6 +90,7 @@
 #define REMOTE_PERM_HASHSIZE 16
 
 struct ll_getname_data {
+	struct dir_context ctx;
 	char	    *lgd_name;      /* points to a buffer with NAME_MAX+1 size */
 	struct lu_fid    lgd_fid;       /* target fid we are looking for */
 	int	      lgd_found;     /* inode matched? */
@@ -438,14 +439,6 @@
 
 #define EE_HASHES       32
 
-struct eacl_entry {
-	struct list_head	    ee_list;
-	pid_t		 ee_key; /* hash key */
-	struct lu_fid	 ee_fid;
-	int		   ee_type; /* ACL type for ACCESS or DEFAULT */
-	ext_acl_xattr_header *ee_acl;
-};
-
 struct eacl_table {
 	spinlock_t	et_lock;
 	struct list_head	et_entries[EE_HASHES];
@@ -512,6 +505,7 @@
 						 * clustred nfs */
 	struct rmtacl_ctl_table   ll_rct;
 	struct eacl_table	 ll_et;
+	__kernel_fsid_t		  ll_fsid;
 };
 
 #define LL_DEFAULT_MAX_RW_CHUNK      (32 * 1024 * 1024)
@@ -687,8 +681,7 @@
 extern struct inode_operations ll_dir_inode_operations;
 struct page *ll_get_dir_page(struct inode *dir, __u64 hash,
 			     struct ll_dir_chain *chain);
-int ll_dir_read(struct inode *inode, __u64 *_pos, void *cookie,
-		filldir_t filldir);
+int ll_dir_read(struct inode *inode, struct dir_context *ctx);
 
 int ll_get_mdt_idx(struct inode *inode);
 /* llite/namei.c */
@@ -792,8 +785,7 @@
 void ll_invalidate_aliases(struct inode *);
 void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft);
 void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry);
-int ll_dcompare(const struct dentry *parent, const struct inode *pinode,
-		const struct dentry *dentry, const struct inode *inode,
+int ll_dcompare(const struct dentry *parent, const struct dentry *dentry,
 		unsigned int len, const char *str, const struct qstr *d_name);
 int ll_revalidate_it_finish(struct ptlrpc_request *request,
 			    struct lookup_intent *it, struct dentry *de);
@@ -842,6 +834,7 @@
 /* llite/llite_nfs.c */
 extern struct export_operations lustre_export_operations;
 __u32 get_uuid2int(const char *name, int len);
+void get_uuid2fsid(const char *name, int len, __kernel_fsid_t *fsid);
 struct inode *search_inode_for_lustre(struct super_block *sb,
 				      const struct lu_fid *fid);
 
@@ -1129,7 +1122,7 @@
 int lustre_check_remote_perm(struct inode *inode, int mask);
 
 /* llite/llite_capa.c */
-extern timer_list_t ll_capa_timer;
+extern struct timer_list ll_capa_timer;
 
 int ll_capa_thread_start(void);
 void ll_capa_thread_stop(void);
@@ -1168,6 +1161,14 @@
 
 /* llite/llite_rmtacl.c */
 #ifdef CONFIG_FS_POSIX_ACL
+struct eacl_entry {
+	struct list_head	    ee_list;
+	pid_t		 ee_key; /* hash key */
+	struct lu_fid	 ee_fid;
+	int		   ee_type; /* ACL type for ACCESS or DEFAULT */
+	ext_acl_xattr_header *ee_acl;
+};
+
 obd_valid rce_ops2valid(int ops);
 struct rmtacl_ctl_entry *rct_search(struct rmtacl_ctl_table *rct, pid_t key);
 int rct_add(struct rmtacl_ctl_table *rct, pid_t key, int ops);
@@ -1183,6 +1184,11 @@
 void et_search_free(struct eacl_table *et, pid_t key);
 void et_init(struct eacl_table *et);
 void et_fini(struct eacl_table *et);
+#else
+static inline obd_valid rce_ops2valid(int ops)
+{
+	return 0;
+}
 #endif
 
 /* statahead.c */
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index afae801..b868c2b 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -42,7 +42,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 
 #include <lustre_lite.h>
@@ -79,11 +78,10 @@
 	struct sysinfo si;
 	class_uuid_t uuid;
 	int i;
-	ENTRY;
 
 	OBD_ALLOC(sbi, sizeof(*sbi));
 	if (!sbi)
-		RETURN(NULL);
+		return NULL;
 
 	spin_lock_init(&sbi->ll_lock);
 	mutex_init(&sbi->ll_lco.lco_lock);
@@ -141,13 +139,12 @@
 	atomic_set(&sbi->ll_agl_total, 0);
 	sbi->ll_flags |= LL_SBI_AGL_ENABLED;
 
-	RETURN(sbi);
+	return sbi;
 }
 
 void ll_free_sbi(struct super_block *sb)
 {
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
-	ENTRY;
 
 	if (sbi != NULL) {
 		spin_lock(&ll_sb_lock);
@@ -155,7 +152,6 @@
 		spin_unlock(&ll_sb_lock);
 		OBD_FREE(sbi, sizeof(*sbi));
 	}
-	EXIT;
 }
 
 static struct dentry_operations ll_d_root_ops = {
@@ -178,22 +174,21 @@
 	struct lustre_md lmd;
 	obd_valid valid;
 	int size, err, checksum;
-	ENTRY;
 
 	obd = class_name2obd(md);
 	if (!obd) {
 		CERROR("MD %s: not setup or attached\n", md);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	OBD_ALLOC_PTR(data);
 	if (data == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	OBD_ALLOC_PTR(osfs);
 	if (osfs == NULL) {
 		OBD_FREE_PTR(data);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	if (proc_lustre_fs_root) {
@@ -583,15 +578,17 @@
 	/* s_dev is also used in lt_compare() to compare two fs, but that is
 	 * only a node-local comparison. */
 	uuid = obd_get_uuid(sbi->ll_md_exp);
-	if (uuid != NULL)
+	if (uuid != NULL) {
 		sb->s_dev = get_uuid2int(uuid->uuid, strlen(uuid->uuid));
+		get_uuid2fsid(uuid->uuid, strlen(uuid->uuid), &sbi->ll_fsid);
+	}
 
 	if (data != NULL)
 		OBD_FREE_PTR(data);
 	if (osfs != NULL)
 		OBD_FREE_PTR(osfs);
 
-	RETURN(err);
+	return err;
 out_root:
 	if (root)
 		iput(root);
@@ -627,7 +624,7 @@
 	if (rc)
 		CERROR("Get max mdsize error rc %d \n", rc);
 
-	RETURN(rc);
+	return rc;
 }
 
 void ll_dump_inode(struct inode *inode)
@@ -676,7 +673,6 @@
 void client_common_put_super(struct super_block *sb)
 {
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
-	ENTRY;
 
 #ifdef CONFIG_FS_POSIX_ACL
 	if (sbi->ll_flags & LL_SBI_RMT_CLIENT) {
@@ -703,16 +699,12 @@
 	obd_fid_fini(sbi->ll_md_exp->exp_obd);
 	obd_disconnect(sbi->ll_md_exp);
 	sbi->ll_md_exp = NULL;
-
-	EXIT;
 }
 
 void ll_kill_super(struct super_block *sb)
 {
 	struct ll_sb_info *sbi;
 
-	ENTRY;
-
 	/* not init sb ?*/
 	if (!(sb->s_flags & MS_ACTIVE))
 		return;
@@ -725,31 +717,29 @@
 		sb->s_dev = sbi->ll_sdev_orig;
 		sbi->ll_umounting = 1;
 	}
-	EXIT;
 }
 
 char *ll_read_opt(const char *opt, char *data)
 {
 	char *value;
 	char *retval;
-	ENTRY;
 
 	CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data);
 	if (strncmp(opt, data, strlen(opt)))
-		RETURN(NULL);
+		return NULL;
 	if ((value = strchr(data, '=')) == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	value++;
 	OBD_ALLOC(retval, strlen(value) + 1);
 	if (!retval) {
 		CERROR("out of memory!\n");
-		RETURN(NULL);
+		return NULL;
 	}
 
 	memcpy(retval, value, strlen(value)+1);
 	CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval);
-	RETURN(retval);
+	return retval;
 }
 
 static inline int ll_set_opt(const char *opt, char *data, int fl)
@@ -765,10 +755,9 @@
 {
 	int tmp;
 	char *s1 = options, *s2;
-	ENTRY;
 
 	if (!options)
-		RETURN(0);
+		return 0;
 
 	CDEBUG(D_CONFIG, "Parsing opts %s\n", options);
 
@@ -891,7 +880,7 @@
 		}
 		LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n",
 				   s1);
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 next:
 		/* Find next opt */
@@ -900,7 +889,7 @@
 			break;
 		s1 = s2 + 1;
 	}
-	RETURN(0);
+	return 0;
 }
 
 void ll_lli_init(struct ll_inode_info *lli)
@@ -977,13 +966,12 @@
 	/* %p for void* in printf needs 16+2 characters: 0xffffffffffffffff */
 	const int instlen = sizeof(cfg->cfg_instance) * 2 + 2;
 	int    err;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb);
 
 	OBD_ALLOC_PTR(cfg);
 	if (cfg == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	try_module_get(THIS_MODULE);
 
@@ -992,7 +980,7 @@
 	if (!sbi) {
 		module_put(THIS_MODULE);
 		OBD_FREE_PTR(cfg);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	err = ll_options(lsi->lsi_lmd->lmd_opts, &sbi->ll_flags);
@@ -1058,7 +1046,7 @@
 		LCONSOLE_WARN("Mounted %s\n", profilenm);
 
 	OBD_FREE_PTR(cfg);
-	RETURN(err);
+	return err;
 } /* ll_fill_super */
 
 void ll_put_super(struct super_block *sb)
@@ -1069,7 +1057,6 @@
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	char *profilenm = get_profile_name(sb);
 	int next, force = 1;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm);
 
@@ -1121,8 +1108,6 @@
 	lustre_common_put_super(sb);
 
 	module_put(THIS_MODULE);
-
-	EXIT;
 } /* client_put_super */
 
 struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock)
@@ -1176,7 +1161,6 @@
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino,
 	       inode->i_generation, inode);
@@ -1188,7 +1172,9 @@
 		LASSERT(lli->lli_opendir_pid == 0);
 	}
 
+	spin_lock(&lli->lli_lock);
 	ll_i2info(inode)->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+	spin_unlock(&lli->lli_lock);
 	md_null_inode(sbi->ll_md_exp, ll_inode2fid(inode));
 
 	LASSERT(!lli->lli_open_fd_write_count);
@@ -1235,8 +1221,6 @@
 	 */
 	cl_inode_fini(inode);
 	lli->lli_has_smd = false;
-
-	EXIT;
 }
 
 int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data,
@@ -1247,12 +1231,11 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct ptlrpc_request *request = NULL;
 	int rc, ia_valid;
-	ENTRY;
 
 	op_data = ll_prep_md_op_data(op_data, inode, NULL, NULL, 0, 0,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, NULL, 0,
 			&request, mod);
@@ -1272,14 +1255,14 @@
 		} else if (rc != -EPERM && rc != -EACCES && rc != -ETXTBSY) {
 			CERROR("md_setattr fails: rc = %d\n", rc);
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp,
 			      sbi->ll_md_exp, &md);
 	if (rc) {
 		ptlrpc_req_finished(request);
-		RETURN(rc);
+		return rc;
 	}
 
 	ia_valid = op_data->op_attr.ia_valid;
@@ -1296,7 +1279,7 @@
 	ll_update_inode(inode, &md);
 	ptlrpc_req_finished(request);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Close IO epoch and send Size-on-MDS attribute update. */
@@ -1306,11 +1289,10 @@
 {
 	struct ll_inode_info *lli = ll_i2info(inode);
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(op_data != NULL);
 	if (!S_ISREG(inode->i_mode))
-		RETURN(0);
+		return 0;
 
 	CDEBUG(D_INODE, "Epoch "LPU64" closed on "DFID" for truncate\n",
 	       op_data->op_ioepoch, PFID(&lli->lli_fid));
@@ -1328,7 +1310,7 @@
 		CERROR("inode %lu mdc truncate failed: rc = %d\n",
 		       inode->i_ino, rc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_setattr_ost(struct inode *inode, struct iattr *attr)
@@ -1372,7 +1354,6 @@
 	struct md_op_data *op_data = NULL;
 	struct md_open_data *mod = NULL;
 	int rc = 0, rc1 = 0;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "%s: setattr inode %p/fid:"DFID" from %llu to %llu, "
 		"valid %x\n", ll_get_fsname(inode->i_sb, NULL, 0), inode,
@@ -1383,7 +1364,7 @@
 		/* Check new size against VFS/VM file size limit and rlimit */
 		rc = inode_newsize_ok(inode, attr->ia_size);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		/* The maximum Lustre file size is variable, based on the
 		 * OST maximum object size and number of stripes.  This
@@ -1392,7 +1373,7 @@
 			CDEBUG(D_INODE,"file "DFID" too large %llu > "LPU64"\n",
 			       PFID(&lli->lli_fid), attr->ia_size,
 			       ll_file_maxbytes(inode));
-			RETURN(-EFBIG);
+			return -EFBIG;
 		}
 
 		attr->ia_valid |= ATTR_MTIME | ATTR_CTIME;
@@ -1400,24 +1381,24 @@
 
 	/* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */
 	if (attr->ia_valid & TIMES_SET_FLAGS) {
-		if (current_fsuid() != inode->i_uid &&
+		if ((!uid_eq(current_fsuid(), inode->i_uid)) &&
 		    !cfs_capable(CFS_CAP_FOWNER))
-			RETURN(-EPERM);
+			return -EPERM;
 	}
 
 	/* We mark all of the fields "set" so MDS/OST does not re-set them */
 	if (attr->ia_valid & ATTR_CTIME) {
-		attr->ia_ctime = CFS_CURRENT_TIME;
+		attr->ia_ctime = CURRENT_TIME;
 		attr->ia_valid |= ATTR_CTIME_SET;
 	}
 	if (!(attr->ia_valid & ATTR_ATIME_SET) &&
 	    (attr->ia_valid & ATTR_ATIME)) {
-		attr->ia_atime = CFS_CURRENT_TIME;
+		attr->ia_atime = CURRENT_TIME;
 		attr->ia_valid |= ATTR_ATIME_SET;
 	}
 	if (!(attr->ia_valid & ATTR_MTIME_SET) &&
 	    (attr->ia_valid & ATTR_MTIME)) {
-		attr->ia_mtime = CFS_CURRENT_TIME;
+		attr->ia_mtime = CURRENT_TIME;
 		attr->ia_valid |= ATTR_MTIME_SET;
 	}
 
@@ -1439,7 +1420,7 @@
 
 	OBD_ALLOC_PTR(op_data);
 	if (op_data == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (!S_ISDIR(inode->i_mode)) {
 		if (attr->ia_valid & ATTR_SIZE)
@@ -1480,7 +1461,6 @@
 		 * setting times to past, but it is necessary due to possible
 		 * time de-synchronization between MDT inode and OST objects */
 		rc = ll_setattr_ost(inode, attr);
-	EXIT;
 out:
 	if (op_data) {
 		if (op_data->op_ioepoch) {
@@ -1537,12 +1517,11 @@
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	struct obd_statfs obd_osfs;
 	int rc;
-	ENTRY;
 
 	rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags);
 	if (rc) {
 		CERROR("md_statfs fails: rc = %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	osfs->os_type = sb->s_magic;
@@ -1556,7 +1535,7 @@
 	rc = obd_statfs_rqset(sbi->ll_dt_exp, &obd_osfs, max_age, flags);
 	if (rc) {
 		CERROR("obd_statfs fails: rc = %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	CDEBUG(D_SUPER, "OSC blocks "LPU64"/"LPU64" objects "LPU64"/"LPU64"\n",
@@ -1578,7 +1557,7 @@
 		osfs->os_ffree = obd_osfs.os_ffree;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 int ll_statfs(struct dentry *de, struct kstatfs *sfs)
 {
@@ -1615,7 +1594,7 @@
 	sfs->f_blocks = osfs.os_blocks;
 	sfs->f_bfree = osfs.os_bfree;
 	sfs->f_bavail = osfs.os_bavail;
-
+	sfs->f_fsid = ll_s2sbi(sb)->ll_fsid;
 	return 0;
 }
 
@@ -1707,9 +1686,9 @@
 		inode->i_blkbits = inode->i_sb->s_blocksize_bits;
 	}
 	if (body->valid & OBD_MD_FLUID)
-		inode->i_uid = body->uid;
+		inode->i_uid = make_kuid(&init_user_ns, body->uid);
 	if (body->valid & OBD_MD_FLGID)
-		inode->i_gid = body->gid;
+		inode->i_gid = make_kgid(&init_user_ns, body->gid);
 	if (body->valid & OBD_MD_FLFLAGS)
 		inode->i_flags = ll_ext_to_inode_flags(body->flags);
 	if (body->valid & OBD_MD_FLNLINK)
@@ -1755,7 +1734,9 @@
 					/* Use old size assignment to avoid
 					 * deadlock bz14138 & bz14326 */
 					i_size_write(inode, body->size);
+					spin_lock(&lli->lli_lock);
 					lli->lli_flags |= LLIF_MDS_SIZE_LOCK;
+					spin_unlock(&lli->lli_lock);
 				}
 				ldlm_lock_decref(&lockh, mode);
 			}
@@ -1786,7 +1767,6 @@
 {
 	struct lustre_md *md = opaque;
 	struct ll_inode_info *lli = ll_i2info(inode);
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
 	       PFID(&lli->lli_fid), inode);
@@ -1814,28 +1794,22 @@
 		inode->i_op = &ll_file_inode_operations;
 		inode->i_fop = sbi->ll_fop;
 		inode->i_mapping->a_ops = (struct address_space_operations *)&ll_aops;
-		EXIT;
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &ll_dir_inode_operations;
 		inode->i_fop = &ll_dir_operations;
-		EXIT;
 	} else if (S_ISLNK(inode->i_mode)) {
 		inode->i_op = &ll_fast_symlink_inode_operations;
-		EXIT;
 	} else {
 		inode->i_op = &ll_special_inode_operations;
 
 		init_special_inode(inode, inode->i_mode,
 				   inode->i_rdev);
-
-		EXIT;
 	}
 }
 
 void ll_delete_inode(struct inode *inode)
 {
 	struct cl_inode_info *lli = cl_i2info(inode);
-	ENTRY;
 
 	if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL)
 		/* discard all dirty pages before truncating them, required by
@@ -1859,8 +1833,6 @@
 
 	ll_clear_inode(inode);
 	clear_inode(inode);
-
-	EXIT;
 }
 
 int ll_iocontrol(struct inode *inode, struct file *file,
@@ -1869,7 +1841,6 @@
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct ptlrpc_request *req = NULL;
 	int rc, flags = 0;
-	ENTRY;
 
 	switch(cmd) {
 	case FSFILT_IOC_GETFLAGS: {
@@ -1880,14 +1851,14 @@
 					     0, 0, LUSTRE_OPC_ANY,
 					     NULL);
 		if (IS_ERR(op_data))
-			RETURN(PTR_ERR(op_data));
+			return PTR_ERR(op_data);
 
 		op_data->op_valid = OBD_MD_FLFLAGS;
 		rc = md_getattr(sbi->ll_md_exp, op_data, &req);
 		ll_finish_md_op_data(op_data);
 		if (rc) {
 			CERROR("failure %d inode %lu\n", rc, inode->i_ino);
-			RETURN(-abs(rc));
+			return -abs(rc);
 		}
 
 		body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
@@ -1896,7 +1867,7 @@
 
 		ptlrpc_req_finished(req);
 
-		RETURN(put_user(flags, (int *)arg));
+		return put_user(flags, (int *)arg);
 	}
 	case FSFILT_IOC_SETFLAGS: {
 		struct lov_stripe_md *lsm;
@@ -1904,12 +1875,12 @@
 		struct md_op_data *op_data;
 
 		if (get_user(flags, (int *)arg))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
 					     LUSTRE_OPC_ANY, NULL);
 		if (IS_ERR(op_data))
-			RETURN(PTR_ERR(op_data));
+			return PTR_ERR(op_data);
 
 		((struct ll_iattr *)&op_data->op_attr)->ia_attr_flags = flags;
 		op_data->op_attr.ia_valid |= ATTR_ATTR_FLAG;
@@ -1918,18 +1889,20 @@
 		ll_finish_md_op_data(op_data);
 		ptlrpc_req_finished(req);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		inode->i_flags = ll_ext_to_inode_flags(flags);
 
 		lsm = ccc_inode_lsm_get(inode);
-		if (lsm == NULL)
-			RETURN(0);
+		if (!lsm_has_objects(lsm)) {
+			ccc_inode_lsm_put(inode, lsm);
+			return 0;
+		}
 
 		OBDO_ALLOC(oinfo.oi_oa);
 		if (!oinfo.oi_oa) {
 			ccc_inode_lsm_put(inode, lsm);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		oinfo.oi_md = lsm;
 		oinfo.oi_oa->o_oi = lsm->lsm_oi;
@@ -1946,20 +1919,21 @@
 		if (rc && rc != -EPERM && rc != -EACCES)
 			CERROR("osc_setattr_async fails: rc = %d\n", rc);
 
-		RETURN(rc);
+		return rc;
 	}
 	default:
-		RETURN(-ENOSYS);
+		return -ENOSYS;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int ll_flush_ctx(struct inode *inode)
 {
 	struct ll_sb_info  *sbi = ll_i2sbi(inode);
 
-	CDEBUG(D_SEC, "flush context for user %d\n", current_uid());
+	CDEBUG(D_SEC, "flush context for user %d\n",
+		      from_kuid(&init_user_ns, current_uid()));
 
 	obd_set_info_async(NULL, sbi->ll_md_exp,
 			   sizeof(KEY_FLUSH_CTX), KEY_FLUSH_CTX,
@@ -1976,8 +1950,6 @@
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	struct obd_device *obd;
 	struct obd_ioctl_data *ioc_data;
-	ENTRY;
-
 
 	CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb,
 	       sb->s_count, atomic_read(&sb->s_active));
@@ -1986,7 +1958,6 @@
 	if (obd == NULL) {
 		CERROR("Invalid MDC connection handle "LPX64"\n",
 		       sbi->ll_md_exp->exp_handle.h_cookie);
-		EXIT;
 		return;
 	}
 	obd->obd_force = 1;
@@ -1995,7 +1966,6 @@
 	if (obd == NULL) {
 		CERROR("Invalid LOV connection handle "LPX64"\n",
 		       sbi->ll_dt_exp->exp_handle.h_cookie);
-		EXIT;
 		return;
 	}
 	obd->obd_force = 1;
@@ -2016,8 +1986,6 @@
 	 * schedule() and sleep one second if needed, and hope.
 	 */
 	schedule();
-
-	EXIT;
 }
 
 int ll_remount_fs(struct super_block *sb, int *flags, char *data)
@@ -2058,14 +2026,13 @@
 	struct ll_sb_info *sbi = NULL;
 	struct lustre_md md;
 	int rc;
-	ENTRY;
 
 	LASSERT(*inode || sb);
 	sbi = sb ? ll_s2sbi(sb) : ll_i2sbi(*inode);
 	rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp,
 			      sbi->ll_md_exp, &md);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (*inode) {
 		ll_update_inode(*inode, &md);
@@ -2127,7 +2094,7 @@
 	if (md.lsm != NULL)
 		obd_free_memmd(sbi->ll_dt_exp, &md.lsm);
 	md_free_lustre_md(sbi->ll_md_exp, &md);
-	RETURN(rc);
+	return rc;
 }
 
 int ll_obd_statfs(struct inode *inode, void *arg)
@@ -2238,8 +2205,8 @@
 	op_data->op_namelen = namelen;
 	op_data->op_mode = mode;
 	op_data->op_mod_time = cfs_time_current_sec();
-	op_data->op_fsuid = current_fsuid();
-	op_data->op_fsgid = current_fsgid();
+	op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+	op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
 	op_data->op_cap = cfs_curproc_cap_pack();
 	op_data->op_bias = 0;
 	op_data->op_cli_flags = 0;
@@ -2303,7 +2270,7 @@
 	if (sbi->ll_flags & LL_SBI_USER_FID2PATH)
 		seq_puts(seq, ",user_fid2path");
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -2313,23 +2280,22 @@
 {
 	struct ll_sb_info *sbi = ll_i2sbi(inode);
 	struct obd_device *obd;
-	ENTRY;
 
 	if (cmd == OBD_IOC_GETDTNAME)
 		obd = class_exp2obd(sbi->ll_dt_exp);
 	else if (cmd == OBD_IOC_GETMDNAME)
 		obd = class_exp2obd(sbi->ll_md_exp);
 	else
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if (!obd)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	if (copy_to_user((void *)arg, obd->obd_name,
 			     strlen(obd->obd_name) + 1))
-		RETURN(-EFAULT);
+		return -EFAULT;
 
-	RETURN(0);
+	return 0;
 }
 
 /**
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c
index d9590d8..caed642 100644
--- a/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -40,13 +40,9 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
-#include <linux/version.h>
 #include <asm/uaccess.h>
 
 #include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
 #include <linux/pagemap.h>
 
 #define DEBUG_SUBSYSTEM S_LLITE
@@ -74,7 +70,6 @@
 			       size_t count)
 {
 	struct vm_area_struct *vma, *ret = NULL;
-	ENTRY;
 
 	/* mmap_sem must have been held by caller. */
 	LASSERT(!down_write_trylock(&mm->mmap_sem));
@@ -87,7 +82,7 @@
 			break;
 		}
 	}
-	RETURN(ret);
+	return ret;
 }
 
 /**
@@ -107,16 +102,16 @@
 			       struct cl_env_nest *nest,
 			       pgoff_t index, unsigned long *ra_flags)
 {
-	struct file       *file  = vma->vm_file;
-	struct inode      *inode = file->f_dentry->d_inode;
-	struct cl_io      *io;
-	struct cl_fault_io *fio;
-	struct lu_env     *env;
-	ENTRY;
+	struct file	       *file = vma->vm_file;
+	struct inode	       *inode = file->f_dentry->d_inode;
+	struct cl_io	       *io;
+	struct cl_fault_io     *fio;
+	struct lu_env	       *env;
+	int			rc;
 
 	*env_ret = NULL;
 	if (ll_file_nolock(file))
-		RETURN(ERR_PTR(-EOPNOTSUPP));
+		return ERR_PTR(-EOPNOTSUPP);
 
 	/*
 	 * page fault can be called when lustre IO is
@@ -127,7 +122,7 @@
 	 */
 	env = cl_env_nested_get(nest);
 	if (IS_ERR(env))
-		 RETURN(ERR_PTR(-EINVAL));
+		 return ERR_PTR(-EINVAL);
 
 	*env_ret = env;
 
@@ -152,17 +147,22 @@
 	CDEBUG(D_MMAP, "vm_flags: %lx (%lu %d)\n", vma->vm_flags,
 	       fio->ft_index, fio->ft_executable);
 
-	if (cl_io_init(env, io, CIT_FAULT, io->ci_obj) == 0) {
+	rc = cl_io_init(env, io, CIT_FAULT, io->ci_obj);
+	if (rc == 0) {
 		struct ccc_io *cio = ccc_env_io(env);
 		struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
 
 		LASSERT(cio->cui_cl.cis_io == io);
 
-		/* mmap lock must be MANDATORY
-		 * it has to cache pages. */
+		/* mmap lock must be MANDATORY it has to cache
+		 * pages. */
 		io->ci_lockreq = CILR_MANDATORY;
-
-		cio->cui_fd  = fd;
+		cio->cui_fd = fd;
+	} else {
+		LASSERT(rc < 0);
+		cl_io_fini(env, io);
+		cl_env_nested_put(nest, env);
+		io = ERR_PTR(rc);
 	}
 
 	return io;
@@ -180,7 +180,6 @@
 	sigset_t	     set;
 	struct inode	     *inode;
 	struct ll_inode_info     *lli;
-	ENTRY;
 
 	LASSERT(vmpage != NULL);
 
@@ -190,7 +189,7 @@
 
 	result = io->ci_result;
 	if (result < 0)
-		GOTO(out, result);
+		GOTO(out_io, result);
 
 	io->u.ci_fault.ft_mkwrite = 1;
 	io->u.ci_fault.ft_writable = 1;
@@ -250,16 +249,15 @@
 			spin_unlock(&lli->lli_lock);
 		}
 	}
-	EXIT;
 
-out:
+out_io:
 	cl_io_fini(env, io);
 	cl_env_nested_put(&nest, env);
-
+out:
 	CDEBUG(D_MMAP, "%s mkwrite with %d\n", current->comm, result);
-
 	LASSERT(ergo(result == 0, PageLocked(vmpage)));
-	return(result);
+
+	return result;
 }
 
 
@@ -304,11 +302,10 @@
 	struct cl_env_nest       nest;
 	int		      result;
 	int		      fault_ret = 0;
-	ENTRY;
 
 	io = ll_fault_io_init(vma, &env,  &nest, vmf->pgoff, &ra_flags);
 	if (IS_ERR(io))
-		RETURN(to_fault_error(PTR_ERR(io)));
+		return to_fault_error(PTR_ERR(io));
 
 	result = io->ci_result;
 	if (result == 0) {
@@ -335,7 +332,7 @@
 
 	CDEBUG(D_MMAP, "%s fault %d/%d\n",
 	       current->comm, fault_ret, result);
-	RETURN(fault_ret);
+	return fault_ret;
 }
 
 static int ll_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -431,11 +428,9 @@
 	struct inode *inode    = vma->vm_file->f_dentry->d_inode;
 	struct ccc_object *vob = cl_inode2ccc(inode);
 
-	ENTRY;
 	LASSERT(vma->vm_file);
 	LASSERT(atomic_read(&vob->cob_mmap_cnt) >= 0);
 	atomic_inc(&vob->cob_mmap_cnt);
-	EXIT;
 }
 
 /**
@@ -446,11 +441,9 @@
 	struct inode      *inode = vma->vm_file->f_dentry->d_inode;
 	struct ccc_object *vob   = cl_inode2ccc(inode);
 
-	ENTRY;
 	LASSERT(vma->vm_file);
 	atomic_dec(&vob->cob_mmap_cnt);
 	LASSERT(atomic_read(&vob->cob_mmap_cnt) >= 0);
-	EXIT;
 }
 
 
@@ -466,7 +459,6 @@
 int ll_teardown_mmaps(struct address_space *mapping, __u64 first, __u64 last)
 {
 	int rc = -ENOENT;
-	ENTRY;
 
 	LASSERTF(last > first, "last "LPU64" first "LPU64"\n", last, first);
 	if (mapping_mapped(mapping)) {
@@ -475,7 +467,7 @@
 				    last - first + 1, 0);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static struct vm_operations_struct ll_file_vm_ops = {
@@ -489,10 +481,9 @@
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	int rc;
-	ENTRY;
 
 	if (ll_file_nolock(file))
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_MAP, 1);
 	rc = generic_file_mmap(file, vma);
@@ -503,5 +494,5 @@
 		rc = ll_glimpse_size(inode);
 	}
 
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c
index 28cc41e..1767c74 100644
--- a/drivers/staging/lustre/lustre/llite/llite_nfs.c
+++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c
@@ -58,6 +58,22 @@
 	return (key0 << 1);
 }
 
+void get_uuid2fsid(const char *name, int len, __kernel_fsid_t *fsid)
+{
+	__u64 key = 0, key0 = 0x12a3fe2d, key1 = 0x37abe8f9;
+
+	while (len--) {
+		key = key1 + (key0 ^ (*name++ * 7152373));
+		if (key & 0x8000000000000000ULL)
+			key -= 0x7fffffffffffffffULL;
+		key1 = key0;
+		key0 = key;
+	}
+
+	fsid->val[0] = key;
+	fsid->val[1] = key >> 32;
+}
+
 static int ll_nfs_test_inode(struct inode *inode, void *opaque)
 {
 	return lu_fid_eq(&ll_i2info(inode)->lli_fid,
@@ -75,17 +91,16 @@
 						      ll_need_32bit_api(sbi));
 	struct  md_op_data    *op_data;
 	int		   rc;
-	ENTRY;
 
 	CDEBUG(D_INFO, "searching inode for:(%lu,"DFID")\n", hash, PFID(fid));
 
 	inode = ilookup5(sb, hash, ll_nfs_test_inode, (void *)fid);
 	if (inode)
-		RETURN(inode);
+		return inode;
 
 	rc = ll_get_max_mdsize(sbi, &eadatalen);
 	if (rc)
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 
 	/* Because inode is NULL, ll_prep_md_op_data can not
 	 * be used here. So we allocate op_data ourselves */
@@ -103,14 +118,14 @@
 	if (rc) {
 		CERROR("can't get object attrs, fid "DFID", rc %d\n",
 		       PFID(fid), rc);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 	rc = ll_prep_inode(&inode, req, sb, NULL);
 	ptlrpc_req_finished(req);
 	if (rc)
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 
-	RETURN(inode);
+	return inode;
 }
 
 struct lustre_nfs_fid {
@@ -123,20 +138,19 @@
 {
 	struct inode  *inode;
 	struct dentry *result;
-	ENTRY;
 
 	CDEBUG(D_INFO, "Get dentry for fid: "DFID"\n", PFID(fid));
 	if (!fid_is_sane(fid))
-		RETURN(ERR_PTR(-ESTALE));
+		return ERR_PTR(-ESTALE);
 
 	inode = search_inode_for_lustre(sb, fid);
 	if (IS_ERR(inode))
-		RETURN(ERR_PTR(PTR_ERR(inode)));
+		return ERR_CAST(inode);
 
 	if (is_bad_inode(inode)) {
 		/* we didn't find the right inode.. */
 		iput(inode);
-		RETURN(ERR_PTR(-ESTALE));
+		return ERR_PTR(-ESTALE);
 	}
 
 	/**
@@ -154,11 +168,11 @@
 
 	result = d_obtain_alias(inode);
 	if (IS_ERR(result))
-		RETURN(result);
+		return result;
 
 	ll_dops_init(result, 1, 0);
 
-	RETURN(result);
+	return result;
 }
 
 #define LUSTRE_NFS_FID	  0x97
@@ -176,20 +190,19 @@
 			struct inode *parent)
 {
 	struct lustre_nfs_fid *nfs_fid = (void *)fh;
-	ENTRY;
 
 	CDEBUG(D_INFO, "encoding for (%lu,"DFID") maxlen=%d minlen=%d\n",
 	      inode->i_ino, PFID(ll_inode2fid(inode)), *plen,
 	      (int)sizeof(struct lustre_nfs_fid));
 
 	if (*plen < sizeof(struct lustre_nfs_fid) / 4)
-		RETURN(255);
+		return 255;
 
 	nfs_fid->lnf_child = *ll_inode2fid(inode);
 	nfs_fid->lnf_parent = *ll_inode2fid(parent);
 	*plen = sizeof(struct lustre_nfs_fid) / 4;
 
-	RETURN(LUSTRE_NFS_FID);
+	return LUSTRE_NFS_FID;
 }
 
 static int ll_nfs_get_name_filldir(void *cookie, const char *name, int namelen,
@@ -214,10 +227,12 @@
 		       struct dentry *child)
 {
 	struct inode *dir = dentry->d_inode;
-	struct ll_getname_data lgd;
-	__u64 offset = 0;
 	int rc;
-	ENTRY;
+	struct ll_getname_data lgd = {
+		.lgd_name = name,
+		.lgd_fid = ll_i2info(child->d_inode)->lli_fid,
+		.ctx.actor = ll_nfs_get_name_filldir,
+	};
 
 	if (!dir || !S_ISDIR(dir->i_mode))
 		GOTO(out, rc = -ENOTDIR);
@@ -225,17 +240,11 @@
 	if (!dir->i_fop)
 		GOTO(out, rc = -EINVAL);
 
-	lgd.lgd_name = name;
-	lgd.lgd_fid = ll_i2info(child->d_inode)->lli_fid;
-	lgd.lgd_found = 0;
-
 	mutex_lock(&dir->i_mutex);
-	rc = ll_dir_read(dir, &offset, &lgd, ll_nfs_get_name_filldir);
+	rc = ll_dir_read(dir, &lgd.ctx);
 	mutex_unlock(&dir->i_mutex);
 	if (!rc && !lgd.lgd_found)
 		rc = -ENOENT;
-	EXIT;
-
 out:
 	return rc;
 }
@@ -246,9 +255,9 @@
 	struct lustre_nfs_fid *nfs_fid = (struct lustre_nfs_fid *)fid;
 
 	if (fh_type != LUSTRE_NFS_FID)
-		RETURN(ERR_PTR(-EPROTO));
+		return ERR_PTR(-EPROTO);
 
-	RETURN(ll_iget_for_nfs(sb, &nfs_fid->lnf_child, &nfs_fid->lnf_parent));
+	return ll_iget_for_nfs(sb, &nfs_fid->lnf_child, &nfs_fid->lnf_parent);
 }
 
 static struct dentry *ll_fh_to_parent(struct super_block *sb, struct fid *fid,
@@ -257,9 +266,9 @@
 	struct lustre_nfs_fid *nfs_fid = (struct lustre_nfs_fid *)fid;
 
 	if (fh_type != LUSTRE_NFS_FID)
-		RETURN(ERR_PTR(-EPROTO));
+		return ERR_PTR(-EPROTO);
 
-	RETURN(ll_iget_for_nfs(sb, &nfs_fid->lnf_parent, NULL));
+	return ll_iget_for_nfs(sb, &nfs_fid->lnf_parent, NULL);
 }
 
 static struct dentry *ll_get_parent(struct dentry *dchild)
@@ -273,7 +282,6 @@
 	struct md_op_data     *op_data;
 	int		   rc;
 	int		      lmmsize;
-	ENTRY;
 
 	LASSERT(dir && S_ISDIR(dir->i_mode));
 
@@ -284,19 +292,19 @@
 
 	rc = ll_get_max_mdsize(sbi, &lmmsize);
 	if (rc != 0)
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 
 	op_data = ll_prep_md_op_data(NULL, dir, NULL, dotdot,
 				     strlen(dotdot), lmmsize,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN((void *)op_data);
+		return (void *)op_data;
 
 	rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
 	ll_finish_md_op_data(op_data);
 	if (rc) {
 		CERROR("failure %d inode %lu get parent\n", rc, dir->i_ino);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 	body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 	LASSERT(body->valid & OBD_MD_FLID);
@@ -307,7 +315,7 @@
 	result = ll_iget_for_nfs(dir->i_sb, &body->fid1, NULL);
 
 	ptlrpc_req_finished(req);
-	RETURN(result);
+	return result;
 }
 
 struct export_operations lustre_export_operations = {
diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c
index 9d4c17e..2340458 100644
--- a/drivers/staging/lustre/lustre/llite/lloop.c
+++ b/drivers/staging/lustre/lustre/llite/lloop.c
@@ -99,7 +99,6 @@
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
-#include <linux/swap.h>
 #include <linux/pagevec.h>
 
 #include <asm/uaccess.h>
@@ -574,7 +573,7 @@
 	lo->lo_offset = 0;
 	lo->lo_sizelimit = 0;
 	lo->lo_flags = 0;
-	ll_invalidate_bdev(bdev, 0);
+	invalidate_bdev(bdev);
 	set_capacity(disks[lo->lo_number], 0);
 	bd_set_size(bdev, 0);
 	mapping_set_gfp_mask(filp->f_mapping, gfp);
@@ -618,7 +617,7 @@
 	case LL_IOC_LLOOP_DETACH: {
 		err = loop_clr_fd(lo, bdev, 2);
 		if (err == 0)
-			ll_blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
+			blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
 		break;
 	}
 
@@ -713,7 +712,7 @@
 		err = loop_set_fd(lo, NULL, bdev, file);
 		if (err) {
 			fput(file);
-			ll_blkdev_put(bdev, 0);
+			blkdev_put(bdev, 0);
 		}
 
 		break;
@@ -737,7 +736,7 @@
 		bdev = lo->lo_device;
 		err = loop_clr_fd(lo, bdev, 1);
 		if (err == 0)
-			ll_blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
+			blkdev_put(bdev, 0); /* grabbed in LLOOP_ATTACH */
 
 		break;
 	}
@@ -849,10 +848,8 @@
 		blk_cleanup_queue(loop_dev[i].lo_queue);
 		put_disk(disks[i]);
 	}
-	if (ll_unregister_blkdev(lloop_major, "lloop"))
-		CWARN("lloop: cannot unregister blkdev\n");
-	else
-		CDEBUG(D_CONFIG, "unregistered lloop major %d\n", lloop_major);
+
+	unregister_blkdev(lloop_major, "lloop");
 
 	OBD_FREE(disks, max_loop * sizeof(*disks));
 	OBD_FREE(loop_dev, max_loop * sizeof(*loop_dev));
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index 6a82505..d4d3c17 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -35,7 +35,6 @@
  */
 #define DEBUG_SUBSYSTEM S_LLITE
 
-#include <linux/version.h>
 #include <lustre_lite.h>
 #include <lprocfs_status.h>
 #include <linux/seq_file.h>
@@ -243,9 +242,9 @@
 	if (rc)
 		return rc;
 
-	if (pages_number < 0 || pages_number > num_physpages / 2) {
+	if (pages_number < 0 || pages_number > totalram_pages / 2) {
 		CERROR("can't set file readahead more than %lu MB\n",
-		       num_physpages >> (20 - PAGE_CACHE_SHIFT + 1)); /*1/2 of RAM*/
+		       totalram_pages >> (20 - PAGE_CACHE_SHIFT + 1)); /*1/2 of RAM*/
 		return -ERANGE;
 	}
 
@@ -380,23 +379,22 @@
 	int mult, rc, pages_number;
 	int diff = 0;
 	int nrpages = 0;
-	ENTRY;
 
 	mult = 1 << (20 - PAGE_CACHE_SHIFT);
 	buffer = lprocfs_find_named_value(buffer, "max_cached_mb:", &count);
 	rc = lprocfs_write_frac_helper(buffer, count, &pages_number, mult);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
-	if (pages_number < 0 || pages_number > num_physpages) {
+	if (pages_number < 0 || pages_number > totalram_pages) {
 		CERROR("%s: can't set max cache more than %lu MB\n",
 		       ll_get_fsname(sb, NULL, 0),
-		       num_physpages >> (20 - PAGE_CACHE_SHIFT));
-		RETURN(-ERANGE);
+		       totalram_pages >> (20 - PAGE_CACHE_SHIFT));
+		return -ERANGE;
 	}
 
 	if (sbi->ll_dt_exp == NULL)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	spin_lock(&sbi->ll_lock);
 	diff = pages_number - cache->ccc_lru_max;
@@ -421,7 +419,7 @@
 				break;
 
 			nv = ov > diff ? ov - diff : 0;
-			rc = cfs_atomic_cmpxchg(&cache->ccc_lru_left, ov, nv);
+			rc = atomic_cmpxchg(&cache->ccc_lru_left, ov, nv);
 			if (likely(ov == rc)) {
 				diff -= ov - nv;
 				nrpages += ov - nv;
@@ -822,7 +820,8 @@
 		 sbi->ll_stats_track_id == current->parent->pid)
 		lprocfs_counter_add(sbi->ll_stats, op, count);
 	else if (sbi->ll_stats_track_type == STATS_TRACK_GID &&
-		 sbi->ll_stats_track_id == current_gid())
+		 sbi->ll_stats_track_id ==
+			from_kgid(&init_user_ns, current_gid()))
 		lprocfs_counter_add(sbi->ll_stats, op, count);
 }
 EXPORT_SYMBOL(ll_stats_ops_tally);
@@ -852,10 +851,9 @@
 	struct lustre_sb_info *lsi = s2lsi(sb);
 	struct ll_sb_info *sbi = ll_s2sbi(sb);
 	struct obd_device *obd;
-	proc_dir_entry_t *dir;
+	struct proc_dir_entry *dir;
 	char name[MAX_STRING_SIZE + 1], *ptr;
 	int err, id, len, rc;
-	ENTRY;
 
 	memset(lvars, 0, sizeof(lvars));
 
@@ -880,7 +878,7 @@
 	if (IS_ERR(sbi->ll_proc_root)) {
 		err = PTR_ERR(sbi->ll_proc_root);
 		sbi->ll_proc_root = NULL;
-		RETURN(err);
+		return err;
 	}
 
 	rc = lprocfs_seq_create(sbi->ll_proc_root, "dump_page_cache", 0444,
@@ -994,7 +992,7 @@
 		lprocfs_free_stats(&sbi->ll_ra_stats);
 		lprocfs_free_stats(&sbi->ll_stats);
 	}
-	RETURN(err);
+	return err;
 }
 
 void lprocfs_unregister_mountpoint(struct ll_sb_info *sbi)
@@ -1302,8 +1300,9 @@
 	/* We stored the discontiguous offsets here; print them first */
 	for(i = 0; i < LL_OFFSET_HIST_MAX; i++) {
 		if (offset[i].rw_pid != 0)
-			seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
-				   offset[i].rw_op ? 'W' : 'R',
+			seq_printf(seq,
+				   "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
+				   offset[i].rw_op == READ ? 'R' : 'W',
 				   offset[i].rw_pid,
 				   offset[i].rw_range_start,
 				   offset[i].rw_range_end,
@@ -1314,8 +1313,9 @@
 	/* Then print the current offsets for each process */
 	for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
 		if (process[i].rw_pid != 0)
-			seq_printf(seq,"%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
-				   process[i].rw_op ? 'W' : 'R',
+			seq_printf(seq,
+				   "%3c %10d %14Lu %14Lu %17lu %17lu %14Lu",
+				   process[i].rw_op == READ ? 'R' : 'W',
 				   process[i].rw_pid,
 				   process[i].rw_range_start,
 				   process[i].rw_last_file_pos,
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index ff8f63d..34815b5 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -77,11 +77,9 @@
 
 int ll_unlock(__u32 mode, struct lustre_handle *lockh)
 {
-	ENTRY;
-
 	ldlm_lock_decref(lockh, mode);
 
-	RETURN(0);
+	return 0;
 }
 
 
@@ -139,7 +137,6 @@
 		      struct lustre_md *md)
 {
 	struct inode	 *inode;
-	ENTRY;
 
 	LASSERT(hash != 0);
 	inode = iget5_locked(sb, hash, ll_test_inode, ll_set_inode, md);
@@ -169,7 +166,7 @@
 		CDEBUG(D_VFSTRACE, "got inode: %p for "DFID"\n",
 		       inode, PFID(&md->body->fid1));
 	}
-	RETURN(inode);
+	return inode;
 }
 
 static void ll_invalidate_negative_children(struct inode *dir)
@@ -200,7 +197,6 @@
 {
 	int rc;
 	struct lustre_handle lockh;
-	ENTRY;
 
 	switch (flag) {
 	case LDLM_CB_BLOCKING:
@@ -208,7 +204,7 @@
 		rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
 		if (rc < 0) {
 			CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc);
-			RETURN(rc);
+			return rc;
 		}
 		break;
 	case LDLM_CB_CANCELING: {
@@ -275,8 +271,11 @@
 				CDEBUG(D_INODE, "invaliding layout %d.\n", rc);
 		}
 
-		if (bits & MDS_INODELOCK_UPDATE)
+		if (bits & MDS_INODELOCK_UPDATE) {
+			spin_lock(&lli->lli_lock);
 			lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+			spin_unlock(&lli->lli_lock);
+		}
 
 		if (S_ISDIR(inode->i_mode) &&
 		     (bits & MDS_INODELOCK_UPDATE)) {
@@ -297,13 +296,13 @@
 		LBUG();
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 __u32 ll_i2suppgid(struct inode *i)
 {
-	if (current_is_in_group(i->i_gid))
-		return (__u32)i->i_gid;
+	if (in_group_p(i->i_gid))
+		return (__u32)from_kgid(&init_user_ns, i->i_gid);
 	else
 		return (__u32)(-1);
 }
@@ -430,7 +429,6 @@
 	struct inode *inode = NULL;
 	__u64 bits = 0;
 	int rc;
-	ENTRY;
 
 	/* NB 1 request reference will be taken away by ll_intent_lock()
 	 * when I return */
@@ -439,7 +437,7 @@
 	if (!it_disposition(it, DISP_LOOKUP_NEG)) {
 		rc = ll_prep_inode(&inode, request, (*de)->d_sb, it);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		ll_set_lock_data(ll_i2sbi(parent)->ll_md_exp, inode, it, &bits);
 
@@ -480,7 +478,7 @@
 		}
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
@@ -493,10 +491,9 @@
 	struct it_cb_data icbd;
 	__u32 opc;
 	int rc;
-	ENTRY;
 
 	if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
-		RETURN(ERR_PTR(-ENAMETOOLONG));
+		return ERR_PTR(-ENAMETOOLONG);
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
 	       dentry->d_name.len, dentry->d_name.name, parent->i_ino,
@@ -514,7 +511,7 @@
 		rc = ll_inode_revalidate_it(parent->i_sb->s_root, it,
 					    MDS_INODELOCK_LOOKUP);
 		if (rc)
-			RETURN(ERR_PTR(rc));
+			return ERR_PTR(rc);
 	}
 
 	if (it->it_op == IT_GETATTR) {
@@ -539,7 +536,7 @@
 				     dentry->d_name.len, lookup_flags, opc,
 				     NULL);
 	if (IS_ERR(op_data))
-		RETURN((void *)op_data);
+		return (void *)op_data;
 
 	/* enforce umask if acl disabled or MDS doesn't support umask */
 	if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
@@ -618,7 +615,6 @@
 	struct dentry *de;
 	long long lookup_flags = LOOKUP_OPEN;
 	int rc = 0;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),file %p,"
 			   "open_flags %x,mode %x opened %d\n",
@@ -627,7 +623,7 @@
 
 	OBD_ALLOC(it, sizeof(*it));
 	if (!it)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	it->it_op = IT_OPEN;
 	if (mode) {
@@ -686,7 +682,7 @@
 	ll_intent_release(it);
 	OBD_FREE(it, sizeof(*it));
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -700,7 +696,6 @@
 	struct ptlrpc_request *request = NULL;
 	struct ll_sb_info *sbi = ll_i2sbi(dir);
 	int rc;
-	ENTRY;
 
 	LASSERT(it && it->d.lustre.it_disposition);
 
@@ -719,7 +714,6 @@
 	CDEBUG(D_DLMTRACE, "setting l_ast_data to inode %p (%lu/%u)\n",
 	       inode, inode->i_ino, inode->i_generation);
 	ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL);
-	EXIT;
  out:
 	ptlrpc_req_finished(request);
 	return inode;
@@ -744,7 +738,6 @@
 {
 	struct inode *inode;
 	int rc = 0;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
 	       dentry->d_name.len, dentry->d_name.name, dir->i_ino,
@@ -752,18 +745,18 @@
 
 	rc = it_open_error(DISP_OPEN_CREATE, it);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
 			       NULL, 0, mode, 0, it);
 	if (IS_ERR(inode))
-		RETURN(PTR_ERR(inode));
+		return PTR_ERR(inode);
 
 	if (filename_is_volatile(dentry->d_name.name, dentry->d_name.len, NULL))
 		ll_i2info(inode)->lli_volatile = true;
 
 	d_instantiate(dentry, inode);
-	RETURN(0);
+	return 0;
 }
 
 static void ll_update_times(struct ptlrpc_request *request,
@@ -795,7 +788,6 @@
 	int tgt_len = 0;
 	int err;
 
-	ENTRY;
 	if (unlikely(tgt != NULL))
 		tgt_len = strlen(tgt) + 1;
 
@@ -805,7 +797,8 @@
 		GOTO(err_exit, err = PTR_ERR(op_data));
 
 	err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
-			current_fsuid(), current_fsgid(),
+			from_kuid(&init_user_ns, current_fsuid()),
+			from_kgid(&init_user_ns, current_fsgid()),
 			cfs_curproc_cap_pack(), rdev, &request);
 	ll_finish_md_op_data(op_data);
 	if (err)
@@ -820,7 +813,6 @@
 
 		d_instantiate(dchild, inode);
 	}
-	EXIT;
 err_exit:
 	ptlrpc_req_finished(request);
 
@@ -831,7 +823,6 @@
 			    unsigned rdev, struct dentry *dchild)
 {
 	int err;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p) mode %o dev %x\n",
 	       name->len, name->name, dir->i_ino, dir->i_generation, dir,
@@ -861,7 +852,7 @@
 	if (!err)
 		ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKNOD, 1);
 
-	RETURN(err);
+	return err;
 }
 
 /*
@@ -891,7 +882,6 @@
 			      const char *tgt, struct dentry *dchild)
 {
 	int err;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),target=%.*s\n",
 	       name->len, name->name, dir->i_ino, dir->i_generation,
@@ -903,7 +893,7 @@
 	if (!err)
 		ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_SYMLINK, 1);
 
-	RETURN(err);
+	return err;
 }
 
 static int ll_link_generic(struct inode *src,  struct inode *dir,
@@ -914,7 +904,6 @@
 	struct md_op_data *op_data;
 	int err;
 
-	ENTRY;
 	CDEBUG(D_VFSTRACE,
 	       "VFS Op: inode=%lu/%u(%p), dir=%lu/%u(%p), target=%.*s\n",
 	       src->i_ino, src->i_generation, src, dir->i_ino,
@@ -923,7 +912,7 @@
 	op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
 				     0, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	err = md_link(sbi->ll_md_exp, op_data, &request);
 	ll_finish_md_op_data(op_data);
@@ -932,10 +921,9 @@
 
 	ll_update_times(request, dir);
 	ll_stats_ops_tally(sbi, LPROC_LL_LINK, 1);
-	EXIT;
 out:
 	ptlrpc_req_finished(request);
-	RETURN(err);
+	return err;
 }
 
 static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
@@ -943,7 +931,6 @@
 
 {
 	int err;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
 	       name->len, name->name, dir->i_ino, dir->i_generation, dir);
@@ -956,7 +943,7 @@
 	if (!err)
 		ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKDIR, 1);
 
-	RETURN(err);
+	return err;
 }
 
 /* Try to find the child dentry by its name.
@@ -981,18 +968,17 @@
 	struct ptlrpc_request *request = NULL;
 	struct md_op_data *op_data;
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
 	       name->len, name->name, dir->i_ino, dir->i_generation, dir);
 
 	if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
-		RETURN(-EBUSY);
+		return -EBUSY;
 
 	op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name, name->len,
 				     S_IFDIR, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	ll_get_child_fid(dir, name, &op_data->op_fid3);
 	op_data->op_fid2 = op_data->op_fid3;
@@ -1004,7 +990,7 @@
 	}
 
 	ptlrpc_req_finished(request);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1015,7 +1001,6 @@
 	struct ptlrpc_request *request = NULL;
 	struct md_op_data *op_data;
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
 	       namelen, name, dir->i_ino, dir->i_generation, dir);
@@ -1023,7 +1008,7 @@
 	op_data = ll_prep_md_op_data(NULL, dir, NULL, name, strlen(name),
 				     S_IFDIR, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 	op_data->op_cli_flags |= CLI_RM_ENTRY;
 	rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
 	ll_finish_md_op_data(op_data);
@@ -1033,7 +1018,7 @@
 	}
 
 	ptlrpc_req_finished(request);
-	RETURN(rc);
+	return rc;
 }
 
 int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
@@ -1045,12 +1030,11 @@
 	struct obdo *oa;
 	struct obd_capa *oc = NULL;
 	int rc;
-	ENTRY;
 
 	/* req is swabbed so this is safe */
 	body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
 	if (!(body->valid & OBD_MD_FLEASIZE))
-		RETURN(0);
+		return 0;
 
 	if (body->eadatasize == 0) {
 		CERROR("OBD_MD_FLEASIZE set but eadatasize zero\n");
@@ -1122,7 +1106,6 @@
 	struct ptlrpc_request *request = NULL;
 	struct md_op_data *op_data;
 	int rc;
-	ENTRY;
 	CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
 	       name->len, name->name, dir->i_ino, dir->i_generation, dir);
 
@@ -1131,12 +1114,12 @@
 	 * just check it as vfs_unlink does.
 	 */
 	if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
-		RETURN(-EBUSY);
+		return -EBUSY;
 
 	op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
 				     name->len, 0, LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	ll_get_child_fid(dir, name, &op_data->op_fid3);
 	op_data->op_fid2 = op_data->op_fid3;
@@ -1151,7 +1134,7 @@
 	rc = ll_objects_destroy(request, dir);
  out:
 	ptlrpc_req_finished(request);
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
@@ -1163,7 +1146,7 @@
 	struct ll_sb_info *sbi = ll_i2sbi(src);
 	struct md_op_data *op_data;
 	int err;
-	ENTRY;
+
 	CDEBUG(D_VFSTRACE,"VFS Op:oldname=%.*s,src_dir=%lu/%u(%p),newname=%.*s,"
 	       "tgt_dir=%lu/%u(%p)\n", src_name->len, src_name->name,
 	       src->i_ino, src->i_generation, src, tgt_name->len,
@@ -1171,12 +1154,12 @@
 
 	if (unlikely(ll_d_mountpoint(src_dparent, src_dchild, src_name) ||
 	    ll_d_mountpoint(tgt_dparent, tgt_dchild, tgt_name)))
-		RETURN(-EBUSY);
+		return -EBUSY;
 
 	op_data = ll_prep_md_op_data(NULL, src, tgt, NULL, 0, 0,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	ll_get_child_fid(src, src_name, &op_data->op_fid3);
 	ll_get_child_fid(tgt, tgt_name, &op_data->op_fid4);
@@ -1193,7 +1176,7 @@
 
 	ptlrpc_req_finished(request);
 
-	RETURN(err);
+	return err;
 }
 
 static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
diff --git a/drivers/staging/lustre/lustre/llite/remote_perm.c b/drivers/staging/lustre/lustre/llite/remote_perm.c
index 68b2dc4..dedd56a 100644
--- a/drivers/staging/lustre/lustre/llite/remote_perm.c
+++ b/drivers/staging/lustre/lustre/llite/remote_perm.c
@@ -45,7 +45,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/version.h>
 
 #include <lustre_lite.h>
 #include <lustre_ha.h>
@@ -124,22 +123,22 @@
 	struct hlist_head *head;
 	struct ll_remote_perm *lrp;
 	int found = 0, rc;
-	ENTRY;
 
 	if (!lli->lli_remote_perms)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
-	head = lli->lli_remote_perms + remote_perm_hashfunc(current_uid());
+	head = lli->lli_remote_perms +
+		remote_perm_hashfunc(from_kuid(&init_user_ns, current_uid()));
 
 	spin_lock(&lli->lli_lock);
 	hlist_for_each_entry(lrp, head, lrp_list) {
-		if (lrp->lrp_uid != current_uid())
+		if (lrp->lrp_uid != from_kuid(&init_user_ns, current_uid()))
 			continue;
-		if (lrp->lrp_gid != current_gid())
+		if (lrp->lrp_gid != from_kgid(&init_user_ns, current_gid()))
 			continue;
-		if (lrp->lrp_fsuid != current_fsuid())
+		if (lrp->lrp_fsuid != from_kuid(&init_user_ns, current_fsuid()))
 			continue;
-		if (lrp->lrp_fsgid != current_fsgid())
+		if (lrp->lrp_fsgid != from_kgid(&init_user_ns, current_fsgid()))
 			continue;
 		found = 1;
 		break;
@@ -163,7 +162,6 @@
 	struct ll_inode_info *lli = ll_i2info(inode);
 	struct ll_remote_perm *lrp = NULL, *tmp = NULL;
 	struct hlist_head *head, *perm_hash = NULL;
-	ENTRY;
 
 	LASSERT(ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT);
 
@@ -178,7 +176,7 @@
 		       perm->rp_uid, perm->rp_gid, perm->rp_fsuid,
 		       perm->rp_fsgid, current->uid, current->gid,
 		       current->fsuid, current->fsgid);
-		RETURN(-EAGAIN);
+		return -EAGAIN;
 	}
 #endif
 
@@ -186,7 +184,7 @@
 		perm_hash = alloc_rmtperm_hash();
 		if (perm_hash == NULL) {
 			CERROR("alloc lli_remote_perms failed!\n");
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 	}
 
@@ -220,7 +218,7 @@
 		lrp = alloc_ll_remote_perm();
 		if (!lrp) {
 			CERROR("alloc memory for ll_remote_perm failed!\n");
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		spin_lock(&lli->lli_lock);
 		goto again;
@@ -241,7 +239,7 @@
 	       lrp, lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid,
 	       lrp->lrp_access_perm);
 
-	RETURN(0);
+	return 0;
 }
 
 int lustre_check_remote_perm(struct inode *inode, int mask)
@@ -253,7 +251,6 @@
 	struct obd_capa *oc;
 	cfs_time_t save;
 	int i = 0, rc;
-	ENTRY;
 
 	do {
 		save = lli->lli_rmtperm_time;
@@ -304,7 +301,7 @@
 		req = NULL;
 	} while (1);
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 #if 0  /* NB: remote perms can't be freed in ll_mdc_blocking_ast of UPDATE lock,
diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c
index fac1178..ae0dc44 100644
--- a/drivers/staging/lustre/lustre/llite/rw.c
+++ b/drivers/staging/lustre/lustre/llite/rw.c
@@ -48,9 +48,6 @@
 #include <asm/uaccess.h>
 
 #include <linux/fs.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
 #include <linux/pagemap.h>
 /* current_is_kswapd() */
 #include <linux/swap.h>
@@ -110,7 +107,7 @@
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		return ERR_PTR(PTR_ERR(env));
+		return ERR_CAST(env);
 
 	lcc = &vvp_env_info(env)->vti_io_ctx;
 	memset(lcc, 0, sizeof(*lcc));
@@ -132,7 +129,7 @@
 			 * add dirty pages into cache during truncate */
 			CERROR("Proc %s is dirting page w/o inode lock, this"
 			       "will break truncate.\n", current->comm);
-			libcfs_debug_dumpstack(NULL);
+			dump_stack();
 			LBUG();
 			return ERR_PTR(-EIO);
 		}
@@ -228,7 +225,6 @@
 {
 	struct ll_cl_context *lcc;
 	int result;
-	ENTRY;
 
 	lcc = ll_cl_init(file, vmpage, 1);
 	if (!IS_ERR(lcc)) {
@@ -256,7 +252,7 @@
 	} else {
 		result = PTR_ERR(lcc);
 	}
-	RETURN(result);
+	return result;
 }
 
 int ll_commit_write(struct file *file, struct page *vmpage, unsigned from,
@@ -267,7 +263,6 @@
 	struct cl_io     *io;
 	struct cl_page   *page;
 	int result = 0;
-	ENTRY;
 
 	lcc  = ll_cl_get();
 	env  = lcc->lcc_env;
@@ -287,7 +282,7 @@
 	lu_ref_del(&page->cp_reference, "prepare_write", current);
 	cl_page_put(env, page);
 	ll_cl_fini(lcc);
-	RETURN(result);
+	return result;
 }
 
 struct obd_capa *cl_capa_lookup(struct inode *inode, enum cl_req_type crt)
@@ -325,7 +320,6 @@
 {
 	struct ll_ra_info *ra = &sbi->ll_ra_info;
 	long ret;
-	ENTRY;
 
 	/* If read-ahead pages left are less than 1M, do not do read-ahead,
 	 * otherwise it will form small read RPC(< 1M), which hurt server
@@ -357,7 +351,7 @@
 	}
 
 out:
-	RETURN(ret);
+	return ret;
 }
 
 void ll_ra_count_put(struct ll_sb_info *sbi, unsigned long len)
@@ -468,8 +462,6 @@
 	struct ccc_page *cp;
 	int	      rc;
 
-	ENTRY;
-
 	rc = 0;
 	cl_page_assume(env, io, page);
 	lu_ref_add(&page->cp_reference, "ra", current);
@@ -491,7 +483,7 @@
 	}
 	lu_ref_del(&page->cp_reference, "ra", current);
 	cl_page_put(env, page);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -516,8 +508,6 @@
 	int	       rc    = 0;
 	const char       *msg   = NULL;
 
-	ENTRY;
-
 	gfp_mask = GFP_HIGHUSER & ~__GFP_WAIT;
 #ifdef __GFP_NOWARN
 	gfp_mask |= __GFP_NOWARN;
@@ -554,7 +544,7 @@
 		ll_ra_stats_inc(mapping, which);
 		CDEBUG(D_READA, "%s\n", msg);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 #define RIA_DEBUG(ria)						       \
@@ -722,7 +712,6 @@
 	struct cl_object *clob;
 	int ret = 0;
 	__u64 kms;
-	ENTRY;
 
 	inode = mapping->host;
 	lli = ll_i2info(inode);
@@ -735,11 +724,11 @@
 	cl_object_attr_unlock(clob);
 
 	if (ret != 0)
-		RETURN(ret);
+		return ret;
 	kms = attr->cat_kms;
 	if (kms == 0) {
 		ll_ra_stats_inc(mapping, RA_STAT_ZERO_LEN);
-		RETURN(0);
+		return 0;
 	}
 
 	spin_lock(&ras->ras_lock);
@@ -797,11 +786,11 @@
 
 	if (end == 0) {
 		ll_ra_stats_inc(mapping, RA_STAT_ZERO_WINDOW);
-		RETURN(0);
+		return 0;
 	}
 	len = ria_page_count(ria);
 	if (len == 0)
-		RETURN(0);
+		return 0;
 
 	reserved = ll_ra_count_get(ll_i2sbi(inode), ria, len);
 	if (reserved < len)
@@ -840,7 +829,7 @@
 		spin_unlock(&ras->ras_lock);
 	}
 
-	RETURN(ret);
+	return ret;
 }
 
 static void ras_set_start(struct inode *inode, struct ll_readahead_state *ras,
@@ -999,7 +988,6 @@
 {
 	struct ll_ra_info *ra = &sbi->ll_ra_info;
 	int zero = 0, stride_detect = 0, ra_miss = 0;
-	ENTRY;
 
 	spin_lock(&ras->ras_lock);
 
@@ -1135,7 +1123,6 @@
 	if ((ras->ras_consecutive_requests > 1 || stride_detect) &&
 	    !ras->ras_request_index)
 		ras_increase_window(inode, ras, ra);
-	EXIT;
 out_unlock:
 	RAS_CDEBUG(ras);
 	ras->ras_request_index++;
@@ -1155,7 +1142,6 @@
 	bool redirtied = false;
 	bool unlocked = false;
 	int result;
-	ENTRY;
 
 	LASSERT(PageLocked(vmpage));
 	LASSERT(!PageWriteback(vmpage));
@@ -1247,7 +1233,6 @@
 	int range_whole = 0;
 	int result;
 	int ignore_layout = 0;
-	ENTRY;
 
 	if (wbc->range_cyclic) {
 		start = mapping->writeback_index << PAGE_CACHE_SHIFT;
@@ -1281,14 +1266,13 @@
 			end = i_size_read(inode);
 		mapping->writeback_index = (end >> PAGE_CACHE_SHIFT) + 1;
 	}
-	RETURN(result);
+	return result;
 }
 
 int ll_readpage(struct file *file, struct page *vmpage)
 {
 	struct ll_cl_context *lcc;
 	int result;
-	ENTRY;
 
 	lcc = ll_cl_init(file, vmpage, 0);
 	if (!IS_ERR(lcc)) {
@@ -1310,5 +1294,5 @@
 		unlock_page(vmpage);
 		result = PTR_ERR(lcc);
 	}
-	RETURN(result);
+	return result;
 }
diff --git a/drivers/staging/lustre/lustre/llite/rw26.c b/drivers/staging/lustre/lustre/llite/rw26.c
index 27e4e64..96c29ad 100644
--- a/drivers/staging/lustre/lustre/llite/rw26.c
+++ b/drivers/staging/lustre/lustre/llite/rw26.c
@@ -51,9 +51,6 @@
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
 #include <linux/writeback.h>
-#include <linux/stat.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
 #include <linux/pagemap.h>
 
 #define DEBUG_SUBSYSTEM S_LLITE
@@ -72,7 +69,8 @@
  * aligned truncate). Lustre leaves partially truncated page in the cache,
  * relying on struct inode::i_size to limit further accesses.
  */
-static void ll_invalidatepage(struct page *vmpage, unsigned long offset)
+static void ll_invalidatepage(struct page *vmpage, unsigned int offset,
+			      unsigned int length)
 {
 	struct inode     *inode;
 	struct lu_env    *env;
@@ -89,7 +87,7 @@
 	 * below because they are run with page locked and all our io is
 	 * happening with locked page too
 	 */
-	if (offset == 0) {
+	if (offset == 0 && length == PAGE_CACHE_SIZE) {
 		env = cl_env_get(&refcheck);
 		if (!IS_ERR(env)) {
 			inode = vmpage->mapping->host;
@@ -182,7 +180,7 @@
 	 */
 	vvp_write_pending(obj, cpg);
 #endif
-	RETURN(__set_page_dirty_nobuffers(vmpage));
+	return __set_page_dirty_nobuffers(vmpage);
 }
 
 #define MAX_DIRECTIO_SIZE 2*1024*1024*1024UL
@@ -249,7 +247,6 @@
 	long page_size      = cl_page_size(obj);
 	bool do_io;
 	int  io_pages       = 0;
-	ENTRY;
 
 	queue = &io->ci_queue;
 	cl_2queue_init(queue);
@@ -286,11 +283,11 @@
 			src_page = (rw == WRITE) ? pages[i] : vmpage;
 			dst_page = (rw == WRITE) ? vmpage : pages[i];
 
-			src = ll_kmap_atomic(src_page, KM_USER0);
-			dst = ll_kmap_atomic(dst_page, KM_USER1);
+			src = kmap_atomic(src_page);
+			dst = kmap_atomic(dst_page);
 			memcpy(dst, src, min(page_size, size));
-			ll_kunmap_atomic(dst, KM_USER1);
-			ll_kunmap_atomic(src, KM_USER0);
+			kunmap_atomic(dst);
+			kunmap_atomic(src);
 
 			/* make sure page will be added to the transfer by
 			 * cl_io_submit()->...->vvp_page_prep_write(). */
@@ -335,7 +332,7 @@
 	cl_2queue_discard(env, io, queue);
 	cl_2queue_disown(env, io, queue);
 	cl_2queue_fini(env, queue);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ll_direct_rw_pages);
 
@@ -383,14 +380,13 @@
 	unsigned long seg = 0;
 	long size = MAX_DIO_SIZE;
 	int refcheck;
-	ENTRY;
 
 	if (!lli->lli_has_smd)
-		RETURN(-EBADF);
+		return -EBADF;
 
 	/* FIXME: io smaller than PAGE_SIZE is broken on ia64 ??? */
 	if ((file_offset & ~CFS_PAGE_MASK) || (count & ~CFS_PAGE_MASK))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), size=%lu (max %lu), "
 	       "offset=%lld=%llx, pages %lu (max %lu)\n",
@@ -402,7 +398,7 @@
 	for (seg = 0; seg < nr_segs; seg++) {
 		if (((unsigned long)iov[seg].iov_base & ~CFS_PAGE_MASK) ||
 		    (iov[seg].iov_len & ~CFS_PAGE_MASK))
-			RETURN(-EINVAL);
+			return -EINVAL;
 	}
 
 	env = cl_env_get(&refcheck);
@@ -495,7 +491,7 @@
 	}
 
 	cl_env_put(env, &refcheck);
-	RETURN(tot_bytes ? : result);
+	return tot_bytes ? : result;
 }
 
 static int ll_write_begin(struct file *file, struct address_space *mapping,
@@ -506,11 +502,10 @@
 	struct page *page;
 	int rc;
 	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
-	ENTRY;
 
 	page = grab_cache_page_write_begin(mapping, index, flags);
 	if (!page)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	*pagep = page;
 
@@ -519,7 +514,7 @@
 		unlock_page(page);
 		page_cache_release(page);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int ll_write_end(struct file *file, struct address_space *mapping,
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 7747f8f..8eaa38e9 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -200,12 +200,11 @@
 	struct ll_sa_entry   *entry;
 	int		   entry_size;
 	char		 *dname;
-	ENTRY;
 
 	entry_size = sizeof(struct ll_sa_entry) + (len & ~3) + 4;
 	OBD_ALLOC(entry, entry_size);
 	if (unlikely(entry == NULL))
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	CDEBUG(D_READA, "alloc sa entry %.*s(%p) index "LPU64"\n",
 	       len, name, entry, index);
@@ -254,7 +253,7 @@
 
 	atomic_inc(&sai->sai_cache_count);
 
-	RETURN(entry);
+	return entry;
 }
 
 /*
@@ -465,11 +464,10 @@
 {
 	struct ll_statahead_info *sai;
 	int		       i;
-	ENTRY;
 
 	OBD_ALLOC_PTR(sai);
 	if (!sai)
-		RETURN(NULL);
+		return NULL;
 
 	atomic_set(&sai->sai_refcount, 1);
 
@@ -496,7 +494,7 @@
 	}
 	atomic_set(&sai->sai_cache_count, 0);
 
-	RETURN(sai);
+	return sai;
 }
 
 static inline struct ll_statahead_info *
@@ -510,7 +508,6 @@
 {
 	struct inode	 *inode = sai->sai_inode;
 	struct ll_inode_info *lli   = ll_i2info(inode);
-	ENTRY;
 
 	if (atomic_dec_and_lock(&sai->sai_refcount, &lli->lli_sa_lock)) {
 		struct ll_sa_entry *entry, *next;
@@ -519,7 +516,7 @@
 			/* It is race case, the interpret callback just hold
 			 * a reference count */
 			spin_unlock(&lli->lli_sa_lock);
-			RETURN_EXIT;
+			return;
 		}
 
 		LASSERT(lli->lli_opendir_key == NULL);
@@ -550,8 +547,6 @@
 		iput(inode);
 		OBD_FREE_PTR(sai);
 	}
-
-	EXIT;
 }
 
 /* Do NOT forget to drop inode refcount when into sai_entries_agl. */
@@ -560,7 +555,6 @@
 	struct ll_inode_info *lli   = ll_i2info(inode);
 	__u64		 index = lli->lli_agl_index;
 	int		   rc;
-	ENTRY;
 
 	LASSERT(list_empty(&lli->lli_agl_list));
 
@@ -568,7 +562,7 @@
 	if (is_omitted_entry(sai, index + 1)) {
 		lli->lli_agl_index = 0;
 		iput(inode);
-		RETURN_EXIT;
+		return;
 	}
 
 	/* Someone is in glimpse (sync or async), do nothing. */
@@ -576,7 +570,7 @@
 	if (rc == 0) {
 		lli->lli_agl_index = 0;
 		iput(inode);
-		RETURN_EXIT;
+		return;
 	}
 
 	/*
@@ -597,7 +591,7 @@
 		up_write(&lli->lli_glimpse_sem);
 		lli->lli_agl_index = 0;
 		iput(inode);
-		RETURN_EXIT;
+		return;
 	}
 
 	CDEBUG(D_READA, "Handling (init) async glimpse: inode = "
@@ -613,8 +607,6 @@
 	       PFID(&lli->lli_fid), index, rc);
 
 	iput(inode);
-
-	EXIT;
 }
 
 static void ll_post_statahead(struct ll_statahead_info *sai)
@@ -628,12 +620,11 @@
 	struct ptlrpc_request  *req;
 	struct mdt_body	*body;
 	int		     rc    = 0;
-	ENTRY;
 
 	spin_lock(&lli->lli_sa_lock);
 	if (unlikely(sa_received_empty(sai))) {
 		spin_unlock(&lli->lli_sa_lock);
-		RETURN_EXIT;
+		return;
 	}
 	entry = sa_first_received_entry(sai);
 	atomic_inc(&entry->se_refcount);
@@ -690,8 +681,6 @@
 	if (agl_should_run(sai, child))
 		ll_agl_add(sai, child, entry->se_index);
 
-	EXIT;
-
 out:
 	/* The "ll_sa_entry_to_stated()" will drop related ldlm ibits lock
 	 * reference count by calling "ll_intent_drop_lock()" in spite of the
@@ -713,7 +702,6 @@
 	struct ll_statahead_info *sai = NULL;
 	struct ll_sa_entry       *entry;
 	int		       wakeup;
-	ENTRY;
 
 	if (it_disposition(it, DISP_LOOKUP_NEG))
 		rc = -ENOENT;
@@ -763,8 +751,6 @@
 			wake_up(&sai->sai_thread.t_ctl_waitq);
 	}
 
-	EXIT;
-
 out:
 	if (rc != 0) {
 		ll_intent_release(it);
@@ -852,11 +838,10 @@
 	struct ldlm_enqueue_info *einfo;
 	struct obd_capa	  *capas[2];
 	int		       rc;
-	ENTRY;
 
 	rc = sa_args_init(dir, NULL, entry, &minfo, &einfo, capas);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo, einfo);
 	if (!rc) {
@@ -866,7 +851,7 @@
 		sa_args_fini(minfo, einfo);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -885,30 +870,29 @@
 	struct ldlm_enqueue_info *einfo;
 	struct obd_capa	  *capas[2];
 	int rc;
-	ENTRY;
 
 	if (unlikely(inode == NULL))
-		RETURN(1);
+		return 1;
 
 	if (d_mountpoint(dentry))
-		RETURN(1);
+		return 1;
 
 	if (unlikely(dentry == dentry->d_sb->s_root))
-		RETURN(1);
+		return 1;
 
 	entry->se_inode = igrab(inode);
 	rc = md_revalidate_lock(ll_i2mdexp(dir), &it, ll_inode2fid(inode),NULL);
 	if (rc == 1) {
 		entry->se_handle = it.d.lustre.it_lock_handle;
 		ll_intent_release(&it);
-		RETURN(1);
+		return 1;
 	}
 
 	rc = sa_args_init(dir, inode, entry, &minfo, &einfo, capas);
 	if (rc) {
 		entry->se_inode = NULL;
 		iput(inode);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo, einfo);
@@ -921,7 +905,7 @@
 		sa_args_fini(minfo, einfo);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static void ll_statahead_one(struct dentry *parent, const char* entry_name,
@@ -934,12 +918,11 @@
 	struct ll_sa_entry       *entry;
 	int		       rc;
 	int		       rc1;
-	ENTRY;
 
 	entry = ll_sa_entry_alloc(sai, sai->sai_index, entry_name,
 				  entry_name_len);
 	if (IS_ERR(entry))
-		RETURN_EXIT;
+		return;
 
 	dentry = d_lookup(parent, &entry->se_qstr);
 	if (!dentry) {
@@ -965,8 +948,6 @@
 	sai->sai_index++;
 	/* drop one refcount on entry by ll_sa_entry_alloc */
 	ll_sa_entry_put(sai, entry);
-
-	EXIT;
 }
 
 static int ll_agl_thread(void *arg)
@@ -979,7 +960,6 @@
 	struct ll_statahead_info *sai    = ll_sai_get(plli->lli_sai);
 	struct ptlrpc_thread     *thread = &sai->sai_agl_thread;
 	struct l_wait_info	lwi    = { 0 };
-	ENTRY;
 
 	CDEBUG(D_READA, "agl thread started: [pid %d] [parent %.*s]\n",
 	       current_pid(), parent->d_name.len, parent->d_name.name);
@@ -1029,7 +1009,7 @@
 	ll_sai_put(sai);
 	CDEBUG(D_READA, "agl thread stopped: [pid %d] [parent %.*s]\n",
 	       current_pid(), parent->d_name.len, parent->d_name.name);
-	RETURN(0);
+	return 0;
 }
 
 static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
@@ -1037,8 +1017,7 @@
 	struct ptlrpc_thread *thread = &sai->sai_agl_thread;
 	struct l_wait_info    lwi    = { 0 };
 	struct ll_inode_info  *plli;
-	task_t	      *task;
-	ENTRY;
+	struct task_struct *task;
 
 	CDEBUG(D_READA, "start agl thread: [pid %d] [parent %.*s]\n",
 	       current_pid(), parent->d_name.len, parent->d_name.name);
@@ -1049,13 +1028,12 @@
 	if (IS_ERR(task)) {
 		CERROR("can't start ll_agl thread, rc: %ld\n", PTR_ERR(task));
 		thread_set_flags(thread, SVC_STOPPED);
-		RETURN_EXIT;
+		return;
 	}
 
 	l_wait_event(thread->t_ctl_waitq,
 		     thread_is_running(thread) || thread_is_stopped(thread),
 		     &lwi);
-	EXIT;
 }
 
 static int ll_statahead_thread(void *arg)
@@ -1074,7 +1052,6 @@
 	int		       rc     = 0;
 	struct ll_dir_chain       chain;
 	struct l_wait_info	lwi    = { 0 };
-	ENTRY;
 
 	CDEBUG(D_READA, "statahead thread started: [pid %d] [parent %.*s]\n",
 	       current_pid(), parent->d_name.len, parent->d_name.name);
@@ -1257,7 +1234,6 @@
 			 */
 		}
 	}
-	EXIT;
 
 out:
 	if (sai->sai_agl_valid) {
@@ -1369,7 +1345,6 @@
 	__u64		 pos    = 0;
 	int		   dot_de;
 	int		   rc     = LS_NONE_FIRST_DE;
-	ENTRY;
 
 	ll_dir_chain_init(&chain);
 	page = ll_get_dir_page(dir, pos, &chain);
@@ -1468,7 +1443,6 @@
 			ll_release_page(page, 1);
 		}
 	}
-	EXIT;
 
 out:
 	ll_dir_chain_fini(&chain);
@@ -1481,7 +1455,6 @@
 	struct ptlrpc_thread *thread = &sai->sai_thread;
 	struct ll_sb_info    *sbi    = ll_i2sbi(sai->sai_inode);
 	int		   hit;
-	ENTRY;
 
 	if (entry != NULL && entry->se_stat == SA_ENTRY_SUCC)
 		hit = 1;
@@ -1516,8 +1489,6 @@
 
 	if (!thread_is_stopped(thread))
 		wake_up(&thread->t_ctl_waitq);
-
-	EXIT;
 }
 
 /**
@@ -1540,7 +1511,6 @@
 	struct l_wait_info	lwi   = { 0 };
 	int		       rc    = 0;
 	struct ll_inode_info     *plli;
-	ENTRY;
 
 	LASSERT(lli->lli_opendir_pid == current_pid());
 
@@ -1550,7 +1520,7 @@
 			     list_empty(&sai->sai_entries_stated))) {
 			/* to release resource */
 			ll_stop_statahead(dir, lli->lli_opendir_key);
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 		}
 
 		if ((*dentryp)->d_name.name[0] == '.') {
@@ -1576,14 +1546,14 @@
 				 * "sai_ls_all" enabled as above.
 				 */
 				sai->sai_miss_hidden++;
-				RETURN(-EAGAIN);
+				return -EAGAIN;
 			}
 		}
 
 		entry = ll_sa_entry_get_byname(sai, &(*dentryp)->d_name);
 		if (entry == NULL || only_unplug) {
 			ll_sai_unplug(sai, entry);
-			RETURN(entry ? 1 : -EAGAIN);
+			return entry ? 1 : -EAGAIN;
 		}
 
 		/* if statahead is busy in readdir, help it do post-work */
@@ -1602,7 +1572,7 @@
 					  &lwi);
 			if (rc < 0) {
 				ll_sai_unplug(sai, entry);
-				RETURN(-EAGAIN);
+				return -EAGAIN;
 			}
 		}
 
@@ -1632,7 +1602,7 @@
 					      inode->i_ino,
 					      inode->i_generation);
 					ll_sai_unplug(sai, entry);
-					RETURN(-ESTALE);
+					return -ESTALE;
 				} else {
 					iput(inode);
 				}
@@ -1646,7 +1616,7 @@
 		}
 
 		ll_sai_unplug(sai, entry);
-		RETURN(rc);
+		return rc;
 	}
 
 	/* I am the "lli_opendir_pid" owner, only me can set "lli_sai". */
@@ -1698,7 +1668,7 @@
 		thread_set_flags(&sai->sai_agl_thread, SVC_STOPPED);
 		ll_sai_put(sai);
 		LASSERT(lli->lli_sai == NULL);
-		RETURN(-EAGAIN);
+		return -EAGAIN;
 	}
 
 	l_wait_event(thread->t_ctl_waitq,
@@ -1709,7 +1679,7 @@
 	 * We don't stat-ahead for the first dirent since we are already in
 	 * lookup.
 	 */
-	RETURN(-EAGAIN);
+	return -EAGAIN;
 
 out:
 	if (sai != NULL)
diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c
index 82c14a9..0beaf4e 100644
--- a/drivers/staging/lustre/lustre/llite/super25.c
+++ b/drivers/staging/lustre/lustre/llite/super25.c
@@ -38,7 +38,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/version.h>
 #include <lustre_lite.h>
 #include <lustre_ha.h>
 #include <lustre_dlm.h>
@@ -214,7 +213,7 @@
 	ll_remote_perm_cachep = NULL;
 
 	kmem_cache_destroy(ll_file_data_slab);
-	if (proc_lustre_fs_root)
+	if (proc_lustre_fs_root && !IS_ERR(proc_lustre_fs_root))
 		lprocfs_remove(&proc_lustre_fs_root);
 }
 
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index 5260e98..ab06891 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -37,7 +37,6 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/stat.h>
-#include <linux/version.h>
 #define DEBUG_SUBSYSTEM S_LLITE
 
 #include <lustre_lite.h>
@@ -51,7 +50,6 @@
 	int rc, symlen = i_size_read(inode) + 1;
 	struct mdt_body *body;
 	struct md_op_data *op_data;
-	ENTRY;
 
 	*request = NULL;
 
@@ -65,13 +63,13 @@
 		CDEBUG(D_INODE, "using cached symlink %s%.*s, len = %d\n",
 		       print_limit < symlen ? "..." : "", print_limit,
 		       (*symname) + symlen - print_limit, symlen);
-		RETURN(0);
+		return 0;
 	}
 
 	op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, symlen,
 				     LUSTRE_OPC_ANY, NULL);
 	if (IS_ERR(op_data))
-		RETURN(PTR_ERR(op_data));
+		return PTR_ERR(op_data);
 
 	op_data->op_valid = OBD_MD_LINKNAME;
 	rc = md_getattr(sbi->ll_md_exp, op_data, request);
@@ -111,10 +109,10 @@
 		memcpy(lli->lli_symlink_name, *symname, symlen);
 		*symname = lli->lli_symlink_name;
 	}
-	RETURN(0);
+	return 0;
 
 failed:
-	RETURN (rc);
+	return rc;
 }
 
 static int ll_readlink(struct dentry *dentry, char *buffer, int buflen)
@@ -123,7 +121,6 @@
 	struct ptlrpc_request *request;
 	char *symname;
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op\n");
 
@@ -136,7 +133,7 @@
  out:
 	ptlrpc_req_finished(request);
 	ll_inode_size_unlock(inode);
-	RETURN(rc);
+	return rc;
 }
 
 static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
@@ -145,7 +142,6 @@
 	struct ptlrpc_request *request = NULL;
 	int rc;
 	char *symname;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op\n");
 	/* Limit the recursive symlink depth to 5 instead of default
@@ -170,7 +166,7 @@
 	/* symname may contain a pointer to the request message buffer,
 	 * we delay request releasing until ll_put_link then.
 	 */
-	RETURN(request);
+	return request;
 }
 
 static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c
index 9254b99..be125b9 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_dev.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c
@@ -213,7 +213,7 @@
 		cl_env_put(env, &refcheck);
 	} else
 		rc = PTR_ERR(env);
-	RETURN(rc);
+	return rc;
 }
 
 int cl_sb_fini(struct super_block *sb)
@@ -224,7 +224,6 @@
 	int		refcheck;
 	int		result;
 
-	ENTRY;
 	sbi = ll_s2sbi(sb);
 	env = cl_env_get(&refcheck);
 	if (!IS_ERR(env)) {
@@ -247,7 +246,7 @@
 	 * automatically when last device is destroyed).
 	 */
 	lu_types_stop();
-	RETURN(result);
+	return result;
 }
 
 /****************************************************************************
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index eb964ac..3ff664c 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -176,19 +176,18 @@
 	unsigned long	   seg;
 	ssize_t		 count;
 	int		     result;
-	ENTRY;
 
 	LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
 
 	if (!cl_is_normalio(env, io))
-		RETURN(0);
+		return 0;
 
 	if (vio->cui_iov == NULL) /* nfs or loop back device write */
-		RETURN(0);
+		return 0;
 
 	/* No MM (e.g. NFS)? No vmas too. */
 	if (mm == NULL)
-		RETURN(0);
+		return 0;
 
 	for (seg = 0; seg < vio->cui_nrsegs; seg++) {
 		const struct iovec *iv = &vio->cui_iov[seg];
@@ -234,7 +233,7 @@
 			       descr->cld_end);
 
 			if (result < 0)
-				RETURN(result);
+				return result;
 
 			if (vma->vm_end - addr >= count)
 				break;
@@ -244,7 +243,7 @@
 		}
 		up_read(&mm->mmap_sem);
 	}
-	RETURN(0);
+	return 0;
 }
 
 static int vvp_io_rw_lock(const struct lu_env *env, struct cl_io *io,
@@ -255,7 +254,6 @@
 	int ast_flags = 0;
 
 	LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
-	ENTRY;
 
 	ccc_io_update_iov(env, cio, io);
 
@@ -264,7 +262,7 @@
 	result = vvp_mmap_locks(env, cio, io);
 	if (result == 0)
 		result = ccc_io_one_lock(env, io, ast_flags, mode, start, end);
-	RETURN(result);
+	return result;
 }
 
 static int vvp_io_read_lock(const struct lu_env *env,
@@ -274,7 +272,6 @@
 	struct ll_inode_info *lli = ll_i2info(ccc_object_inode(io->ci_obj));
 	int result;
 
-	ENTRY;
 	/* XXX: Layer violation, we shouldn't see lsm at llite level. */
 	if (lli->lli_has_smd) /* lsm-less file doesn't need to lock */
 		result = vvp_io_rw_lock(env, io, CLM_READ,
@@ -283,7 +280,7 @@
 					io->u.ci_rd.rd.crw_count - 1);
 	else
 		result = 0;
-	RETURN(result);
+	return result;
 }
 
 static int vvp_io_fault_lock(const struct lu_env *env,
@@ -407,13 +404,15 @@
 {
 	struct cl_io	*io    = ios->cis_io;
 	struct inode	*inode = ccc_object_inode(io->ci_obj);
+	int result = 0;
 
 	mutex_lock(&inode->i_mutex);
 	if (cl_io_is_trunc(io))
-		return vvp_io_setattr_trunc(env, ios, inode,
-					    io->u.ci_setattr.sa_attr.lvb_size);
-	else
-		return vvp_io_setattr_time(env, ios);
+		result = vvp_io_setattr_trunc(env, ios, inode,
+					io->u.ci_setattr.sa_attr.lvb_size);
+	if (result == 0)
+		result = vvp_io_setattr_time(env, ios);
+	return result;
 }
 
 static void vvp_io_setattr_end(const struct lu_env *env,
@@ -525,7 +524,7 @@
 			io->ci_continue = 0;
 		io->ci_nob += result;
 		ll_rw_stats_tally(ll_i2sbi(inode), current->pid,
-				  cio->cui_fd, pos, result, 0);
+				  cio->cui_fd, pos, result, READ);
 		result = 0;
 	}
 	return result;
@@ -554,8 +553,6 @@
 	loff_t pos = io->u.ci_wr.wr.crw_pos;
 	size_t cnt = io->u.ci_wr.wr.crw_count;
 
-	ENTRY;
-
 	if (!can_populate_pages(env, io, inode))
 		return 0;
 
@@ -580,10 +577,10 @@
 			io->ci_continue = 0;
 		io->ci_nob += result;
 		ll_rw_stats_tally(ll_i2sbi(inode), current->pid,
-				  cio->cui_fd, pos, result, 0);
+				  cio->cui_fd, pos, result, WRITE);
 		result = 0;
 	}
-	RETURN(result);
+	return result;
 }
 
 static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
@@ -767,7 +764,6 @@
 
 	lu_ref_add(&page->cp_reference, "fault", io);
 	fio->ft_page = page;
-	EXIT;
 
 out:
 	/* return unlocked vmpage to avoid deadlocking */
@@ -805,8 +801,6 @@
 	CLOBINVRNT(env, obj, ccc_object_invariant(obj));
 	LASSERT(slice->cpl_obj == obj);
 
-	ENTRY;
-
 	if (sbi->ll_ra_info.ra_max_pages_per_file &&
 	    sbi->ll_ra_info.ra_max_pages)
 		ras_update(sbi, inode, ras, page->cp_index,
@@ -819,7 +813,7 @@
 			       rc == -ENODATA ? "without a lock" :
 			       "match failed", rc);
 		if (rc != -ENODATA)
-			RETURN(rc);
+			return rc;
 	}
 
 	if (cp->cpg_defer_uptodate) {
@@ -836,7 +830,7 @@
 		ll_readahead(env, io, ras,
 			     vmpage->mapping, &queue->c2_qin, fd->fd_flags);
 
-	RETURN(0);
+	return 0;
 }
 
 static int vvp_page_sync_io(const struct lu_env *env, struct cl_io *io,
@@ -887,10 +881,10 @@
 		 * purposes here we can treat it like i_size.
 		 */
 		if (attr->cat_kms <= offset) {
-			char *kaddr = ll_kmap_atomic(cp->cpg_page, KM_USER0);
+			char *kaddr = kmap_atomic(cp->cpg_page);
 
 			memset(kaddr, 0, cl_page_size(obj));
-			ll_kunmap_atomic(kaddr, KM_USER0);
+			kunmap_atomic(kaddr);
 		} else if (cp->cpg_defer_uptodate)
 			cp->cpg_ra_used = 1;
 		else
@@ -921,8 +915,6 @@
 
 	int result;
 
-	ENTRY;
-
 	LINVRNT(cl_page_is_vmlocked(env, pg));
 	LASSERT(vmpage->mapping->host == ccc_object_inode(obj));
 
@@ -942,7 +934,7 @@
 							pg, cp, from, to);
 	} else
 		CL_PAGE_HEADER(D_PAGE, env, pg, "uptodate\n");
-	RETURN(result);
+	return result;
 }
 
 static int vvp_io_commit_write(const struct lu_env *env,
@@ -963,12 +955,10 @@
 	int    tallyop;
 	loff_t size;
 
-	ENTRY;
-
 	LINVRNT(cl_page_is_vmlocked(env, pg));
 	LASSERT(vmpage->mapping->host == inode);
 
-	LU_OBJECT_HEADER(D_INODE, env, &obj->co_lu, "commiting page write\n");
+	LU_OBJECT_HEADER(D_INODE, env, &obj->co_lu, "committing page write\n");
 	CL_PAGE_HEADER(D_PAGE, env, pg, "committing: [%d, %d]\n", from, to);
 
 	/*
@@ -1067,7 +1057,7 @@
 			cl_page_discard(env, io, pg);
 	}
 	ll_inode_size_unlock(inode);
-	RETURN(result);
+	return result;
 }
 
 static const struct cl_io_operations vvp_io_ops = {
@@ -1120,7 +1110,6 @@
 	int		 result;
 
 	CLOBINVRNT(env, obj, ccc_object_invariant(obj));
-	ENTRY;
 
 	CL_IO_SLICE_CLEAN(cio, cui_cl);
 	cl_io_slice_add(io, &cio->cui_cl, obj, &vvp_io_ops);
@@ -1174,7 +1163,7 @@
 				PFID(lu_object_fid(&obj->co_lu)), result);
 	}
 
-	RETURN(result);
+	return result;
 }
 
 static struct vvp_io *cl2vvp_io(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c
index 9b8712b..e16b31e 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_lock.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c
@@ -63,8 +63,7 @@
 {
 	struct ccc_object *cob = cl2ccc(slice->cls_obj);
 
-	ENTRY;
-	RETURN(atomic_read(&cob->cob_mmap_cnt) > 0 ? ~0UL >> 2 : 0);
+	return atomic_read(&cob->cob_mmap_cnt) > 0 ? ~0UL >> 2 : 0;
 }
 
 static const struct cl_lock_operations vvp_lock_ops = {
diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c
index 01edc5b..33173fc 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_object.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_object.c
@@ -91,8 +91,8 @@
 	attr->cat_atime = LTIME_S(inode->i_atime);
 	attr->cat_ctime = LTIME_S(inode->i_ctime);
 	attr->cat_blocks = inode->i_blocks;
-	attr->cat_uid = inode->i_uid;
-	attr->cat_gid = inode->i_gid;
+	attr->cat_uid = from_kuid(&init_user_ns, inode->i_uid);
+	attr->cat_gid = from_kgid(&init_user_ns, inode->i_gid);
 	/* KMS is not known by this layer */
 	return 0; /* layers below have to fill in the rest */
 }
@@ -103,9 +103,9 @@
 	struct inode *inode = ccc_object_inode(obj);
 
 	if (valid & CAT_UID)
-		inode->i_uid = attr->cat_uid;
+		inode->i_uid = make_kuid(&init_user_ns, attr->cat_uid);
 	if (valid & CAT_GID)
-		inode->i_gid = attr->cat_gid;
+		inode->i_gid = make_kgid(&init_user_ns, attr->cat_gid);
 	if (valid & CAT_ATIME)
 		LTIME_S(inode->i_atime) = attr->cat_atime;
 	if (valid & CAT_MTIME)
diff --git a/drivers/staging/lustre/lustre/llite/vvp_page.c b/drivers/staging/lustre/lustre/llite/vvp_page.c
index 4568e69..1c02c12 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_page.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_page.c
@@ -218,9 +218,8 @@
 			      const struct cl_page_slice *slice,
 			      struct cl_io *unused)
 {
-	ENTRY;
 	/* Skip the page already marked as PG_uptodate. */
-	RETURN(PageUptodate(cl2vm_page(slice)) ? -EALREADY : 0);
+	return PageUptodate(cl2vm_page(slice)) ? -EALREADY : 0;
 }
 
 static int vvp_page_prep_write(const struct lu_env *env,
@@ -274,7 +273,6 @@
 	struct page      *vmpage = cp->cpg_page;
 	struct cl_page  *page   = cl_page_top(slice->cpl_page);
 	struct inode    *inode  = ccc_object_inode(page->cp_obj);
-	ENTRY;
 
 	LASSERT(PageLocked(vmpage));
 	CL_PAGE_HEADER(D_PAGE, env, page, "completing READ with %d\n", ioret);
@@ -290,8 +288,6 @@
 
 	if (page->cp_sync_io == NULL)
 		unlock_page(vmpage);
-
-	EXIT;
 }
 
 static void vvp_page_completion_write(const struct lu_env *env,
@@ -301,7 +297,6 @@
 	struct ccc_page *cp     = cl2ccc_page(slice);
 	struct cl_page  *pg     = slice->cpl_page;
 	struct page      *vmpage = cp->cpg_page;
-	ENTRY;
 
 	LASSERT(ergo(pg->cp_sync_io != NULL, PageLocked(vmpage)));
 	LASSERT(PageWriteback(vmpage));
@@ -329,7 +324,6 @@
 		vvp_vmpage_error(ccc_object_inode(pg->cp_obj), vmpage, ioret);
 
 	end_page_writeback(vmpage);
-	EXIT;
 }
 
 /**
@@ -372,7 +366,7 @@
 		LBUG();
 	}
 	unlock_page(vmpage);
-	RETURN(result);
+	return result;
 }
 
 static int vvp_page_print(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 4176264..bcf86bac 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -112,31 +112,32 @@
 	struct ptlrpc_request *req;
 	int xattr_type, rc;
 	struct obd_capa *oc;
+#ifdef CONFIG_FS_POSIX_ACL
 	posix_acl_xattr_header *new_value = NULL;
 	struct rmtacl_ctl_entry *rce = NULL;
 	ext_acl_xattr_header *acl = NULL;
+#endif
 	const char *pv = value;
-	ENTRY;
 
 	xattr_type = get_xattr_type(name);
 	rc = xattr_type_filter(sbi, xattr_type);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	/* b10667: ignore lustre special xattr for now */
 	if ((xattr_type == XATTR_TRUSTED_T && strcmp(name, "trusted.lov") == 0) ||
 	    (xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0))
-		RETURN(0);
+		return 0;
 
 	/* b15587: ignore security.capability xattr for now */
 	if ((xattr_type == XATTR_SECURITY_T &&
 	    strcmp(name, "security.capability") == 0))
-		RETURN(0);
+		return 0;
 
 	/* LU-549:  Disable security.selinux when selinux is disabled */
 	if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
 	    strcmp(name, "security.selinux") == 0)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 #ifdef CONFIG_FS_POSIX_ACL
 	if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
@@ -146,7 +147,7 @@
 		if (rce == NULL ||
 		    (rce->rce_ops != RMT_LSETFACL &&
 		    rce->rce_ops != RMT_RSETFACL))
-			RETURN(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 
 		if (rce->rce_ops == RMT_LSETFACL) {
 			struct eacl_entry *ee;
@@ -160,7 +161,7 @@
 						size, ee->ee_acl);
 				if (IS_ERR(acl)) {
 					ee_free(ee);
-					RETURN(PTR_ERR(acl));
+					return PTR_ERR(acl);
 				}
 				size =  CFS_ACL_XATTR_SIZE(\
 						le32_to_cpu(acl->a_count), \
@@ -173,11 +174,11 @@
 						(posix_acl_xattr_header *)value,
 						size, &new_value);
 			if (unlikely(size < 0))
-				RETURN(size);
+				return size;
 
 			pv = (const char *)new_value;
 		} else
-			RETURN(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 
 		valid |= rce_ops2valid(rce->rce_ops);
 	}
@@ -199,11 +200,11 @@
 				      "it is not supported on the server\n");
 			sbi->ll_flags &= ~LL_SBI_USER_XATTR;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	ptlrpc_req_finished(req);
-	RETURN(0);
+	return 0;
 }
 
 int ll_setxattr(struct dentry *dentry, const char *name,
@@ -285,7 +286,6 @@
 	void *xdata;
 	struct obd_capa *oc;
 	struct rmtacl_ctl_entry *rce = NULL;
-	ENTRY;
 
 	CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n",
 	       inode->i_ino, inode->i_generation, inode);
@@ -302,17 +302,17 @@
 	xattr_type = get_xattr_type(name);
 	rc = xattr_type_filter(sbi, xattr_type);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	/* b15587: ignore security.capability xattr for now */
 	if ((xattr_type == XATTR_SECURITY_T &&
 	    strcmp(name, "security.capability") == 0))
-		RETURN(-ENODATA);
+		return -ENODATA;
 
 	/* LU-549:  Disable security.selinux when selinux is disabled */
 	if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
 	    strcmp(name, "security.selinux") == 0)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 #ifdef CONFIG_FS_POSIX_ACL
 	if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
@@ -324,7 +324,7 @@
 		    rce->rce_ops != RMT_LGETFACL &&
 		    rce->rce_ops != RMT_RSETFACL &&
 		    rce->rce_ops != RMT_RGETFACL))
-			RETURN(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 	}
 
 	/* posix acl is under protection of LOOKUP lock. when calling to this,
@@ -341,14 +341,14 @@
 		spin_unlock(&lli->lli_lock);
 
 		if (!acl)
-			RETURN(-ENODATA);
+			return -ENODATA;
 
 		rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
 		posix_acl_release(acl);
-		RETURN(rc);
+		return rc;
 	}
 	if (xattr_type == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
-		RETURN(-ENODATA);
+		return -ENODATA;
 #endif
 
 do_getxattr:
@@ -363,7 +363,7 @@
 				      "it is not supported on the server\n");
 			sbi->ll_flags &= ~LL_SBI_USER_XATTR;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
@@ -413,7 +413,6 @@
 		memcpy(buffer, xdata, body->eadatasize);
 		rc = body->eadatasize;
 	}
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -562,7 +561,12 @@
 		const size_t name_len   = sizeof("lov") - 1;
 		const size_t total_len  = prefix_len + name_len + 1;
 
-		if (buffer && (rc + total_len) <= size) {
+		if (((rc + total_len) > size) && (buffer != NULL)) {
+			ptlrpc_req_finished(request);
+			return -ERANGE;
+		}
+
+		if (buffer != NULL) {
 			buffer += rc;
 			memcpy(buffer, XATTR_LUSTRE_PREFIX, prefix_len);
 			memcpy(buffer + prefix_len, "lov", name_len);
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_fld.c b/drivers/staging/lustre/lustre/lmv/lmv_fld.c
index a4805ae..0b2d38d 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_fld.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_fld.c
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <asm/div64.h>
 #include <linux/seq_file.h>
@@ -58,8 +57,6 @@
 		   mdsno_t *mds)
 {
 	int rc;
-	ENTRY;
-
 
 	/* FIXME: Currently ZFS still use local seq for ROOT unfortunately, and
 	 * this fid_is_local check should be removed once LU-2240 is fixed */
@@ -72,7 +69,7 @@
 	if (rc) {
 		CERROR("Error while looking for mds number. Seq "LPX64
 		       ", err = %d\n", fid_seq(fid), rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	CDEBUG(D_INODE, "FLD lookup got mds #%x for fid="DFID"\n",
@@ -84,5 +81,5 @@
 		       PFID(fid));
 		rc = -EINVAL;
 	}
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
index 7eefab5..511b3b4 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <asm/div64.h>
 #include <linux/seq_file.h>
@@ -70,11 +69,10 @@
 	struct mdt_body		*body;
 	int			pmode;
 	int			rc = 0;
-	ENTRY;
 
 	body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
 	if (body == NULL)
-		RETURN(-EPROTO);
+		return -EPROTO;
 
 	LASSERT((body->valid & OBD_MD_MDS));
 
@@ -142,7 +140,6 @@
 	it->d.lustre.it_lock_handle = plock.cookie;
 	it->d.lustre.it_lock_mode = pmode;
 
-	EXIT;
 out_free_op_data:
 	OBD_FREE_PTR(op_data);
 out:
@@ -169,11 +166,10 @@
 	struct lmv_tgt_desc	*tgt;
 	struct mdt_body		*body;
 	int			rc;
-	ENTRY;
 
 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	/* If it is ready to open the file by FID, do not need
 	 * allocate FID at all, otherwise it will confuse MDT */
@@ -186,7 +182,7 @@
 		op_data->op_fid3 = op_data->op_fid2;
 		rc = lmv_fid_alloc(exp, &op_data->op_fid2, op_data);
 		if (rc != 0)
-			RETURN(rc);
+			return rc;
 	}
 
 	CDEBUG(D_INODE, "OPEN_INTENT with fid1="DFID", fid2="DFID","
@@ -196,7 +192,7 @@
 	rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, flags,
 			    reqp, cb_blocking, extra_lock_flags);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 	/*
 	 * Nothing is found, do not access body->fid1 as it is zero and thus
 	 * pointless.
@@ -204,16 +200,16 @@
 	if ((it->d.lustre.it_disposition & DISP_LOOKUP_NEG) &&
 	    !(it->d.lustre.it_disposition & DISP_OPEN_CREATE) &&
 	    !(it->d.lustre.it_disposition & DISP_OPEN_OPEN))
-		RETURN(rc);
+		return rc;
 
 	body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
 	if (body == NULL)
-		RETURN(-EPROTO);
+		return -EPROTO;
 	/*
 	 * Not cross-ref case, just get out of here.
 	 */
 	if (likely(!(body->valid & OBD_MD_MDS)))
-		RETURN(0);
+		return 0;
 
 	/*
 	 * Okay, MDS has returned success. Probably name has been resolved in
@@ -233,10 +229,10 @@
 		       "%*s: %d\n", LL_IT2STR(it), PFID(&op_data->op_fid2),
 		       PFID(&op_data->op_fid1), op_data->op_namelen,
 		       op_data->op_name, rc);
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -253,11 +249,10 @@
 	struct lmv_tgt_desc    *tgt = NULL;
 	struct mdt_body	*body;
 	int		     rc = 0;
-	ENTRY;
 
 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	if (!fid_is_sane(&op_data->op_fid2))
 		fid_zero(&op_data->op_fid2);
@@ -274,7 +269,7 @@
 			     flags, reqp, cb_blocking, extra_lock_flags);
 
 	if (rc < 0 || *reqp == NULL)
-		RETURN(rc);
+		return rc;
 
 	/*
 	 * MDS has returned success. Probably name has been resolved in
@@ -282,15 +277,15 @@
 	 */
 	body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
 	if (body == NULL)
-		RETURN(-EPROTO);
+		return -EPROTO;
 	/* Not cross-ref case, just get out of here. */
 	if (likely(!(body->valid & OBD_MD_MDS)))
-		RETURN(0);
+		return 0;
 
 	rc = lmv_intent_remote(exp, lmm, lmmsize, it, NULL, flags, reqp,
 			       cb_blocking, extra_lock_flags);
 
-	RETURN(rc);
+	return rc;
 }
 
 int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
@@ -301,7 +296,6 @@
 {
 	struct obd_device *obd = exp->exp_obd;
 	int		rc;
-	ENTRY;
 
 	LASSERT(it != NULL);
 	LASSERT(fid_is_sane(&op_data->op_fid1));
@@ -312,7 +306,7 @@
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_LAYOUT))
 		rc = lmv_intent_lookup(exp, op_data, lmm, lmmsize, it,
@@ -324,5 +318,5 @@
 				     extra_lock_flags);
 	else
 		LBUG();
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index 1eebfbf..c286604 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -38,12 +38,12 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/mm.h>
 #include <asm/div64.h>
 #include <linux/seq_file.h>
 #include <linux/namei.h>
+#include <asm/uaccess.h>
 
 #include <lustre/lustre_idl.h>
 #include <obd_support.h>
@@ -80,7 +80,6 @@
 	struct obd_device      *obd;
 	int		     i;
 	int		     rc = 0;
-	ENTRY;
 
 	CDEBUG(D_INFO, "Searching in lmv %p for uuid %s (activate=%d)\n",
 	       lmv, uuid->uuid, activate);
@@ -119,7 +118,6 @@
 	CDEBUG(D_INFO, "Marking OBD %p %sactive\n", obd,
 	       activate ? "" : "in");
 	lmv_activate_target(lmv, tgt, activate);
-	EXIT;
 
  out_lmv_lock:
 	spin_unlock(&lmv->lmv_lock);
@@ -140,13 +138,12 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct obd_uuid	 *uuid;
 	int		      rc = 0;
-	ENTRY;
 
 	if (strcmp(watched->obd_type->typ_name, LUSTRE_MDC_NAME)) {
 		CERROR("unexpected notification of %s %s!\n",
 		       watched->obd_type->typ_name,
 		       watched->obd_name);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	uuid = &watched->u.cli.cl_target_uuid;
@@ -161,7 +158,7 @@
 			CERROR("%sactivation of %s failed: %d\n",
 			       ev == OBD_NOTIFY_ACTIVE ? "" : "de",
 			       uuid->uuid, rc);
-			RETURN(rc);
+			return rc;
 		}
 	} else if (ev == OBD_NOTIFY_OCD) {
 		conn_data = &watched->u.cli.cl_import->imp_connect_data;
@@ -186,7 +183,7 @@
 	if (obd->obd_observer)
 		rc = obd_notify(obd->obd_observer, watched, ev, data);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -202,7 +199,6 @@
 	struct lmv_obd	*lmv = &obd->u.lmv;
 	struct lustre_handle  conn = { 0 };
 	int		    rc = 0;
-	ENTRY;
 
 	/*
 	 * We don't want to actually do the underlying connections more than
@@ -211,13 +207,13 @@
 	lmv->refcount++;
 	if (lmv->refcount > 1) {
 		*exp = NULL;
-		RETURN(0);
+		return 0;
 	}
 
 	rc = class_connect(&conn, obd, cluuid);
 	if (rc) {
 		CERROR("class_connection() returned %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	*exp = class_conn2export(&conn);
@@ -257,7 +253,7 @@
 		obd->obd_proc_private = NULL;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static void lmv_set_timeouts(struct obd_device *obd)
@@ -291,7 +287,6 @@
 	int		  i;
 	int		  rc = 0;
 	int		  change = 0;
-	ENTRY;
 
 	if (lmv->max_easize < easize) {
 		lmv->max_easize = easize;
@@ -306,10 +301,10 @@
 		change = 1;
 	}
 	if (change == 0)
-		RETURN(0);
+		return 0;
 
 	if (lmv->connected == 0)
-		RETURN(0);
+		return 0;
 
 	for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
 		if (lmv->tgts[i] == NULL ||
@@ -327,7 +322,7 @@
 			break;
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 
 #define MAX_STRING_SIZE 128
@@ -342,13 +337,12 @@
 	struct obd_export       *mdc_exp;
 	struct lu_fld_target     target;
 	int		      rc;
-	ENTRY;
 
 	mdc_obd = class_find_client_obd(&tgt->ltd_uuid, LUSTRE_MDC_NAME,
 					&obd->obd_uuid);
 	if (!mdc_obd) {
 		CERROR("target %s not attached\n", tgt->ltd_uuid.uuid);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	CDEBUG(D_CONFIG, "connect to %s(%s) - %s, %s FOR %s\n",
@@ -358,14 +352,14 @@
 
 	if (!mdc_obd->obd_set_up) {
 		CERROR("target %s is not set up\n", tgt->ltd_uuid.uuid);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = obd_connect(NULL, &mdc_exp, mdc_obd, &lmv_mdc_uuid,
 			 &lmv->conn_data, NULL);
 	if (rc) {
 		CERROR("target %s connect error %d\n", tgt->ltd_uuid.uuid, rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	/*
@@ -373,7 +367,7 @@
 	 */
 	rc = obd_fid_init(mdc_obd, mdc_exp, LUSTRE_SEQ_METADATA);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	target.ft_srv = NULL;
 	target.ft_exp = mdc_exp;
@@ -386,7 +380,7 @@
 		obd_disconnect(mdc_exp);
 		CERROR("target %s register_observer error %d\n",
 		       tgt->ltd_uuid.uuid, rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (obd->obd_observer) {
@@ -398,7 +392,7 @@
 				(void *)(tgt - lmv->tgts[0]));
 		if (rc) {
 			obd_disconnect(mdc_exp);
-			RETURN(rc);
+			return rc;
 		}
 	}
 
@@ -433,7 +427,7 @@
 			obd->obd_proc_private = NULL;
 		}
 	}
-	RETURN(0);
+	return 0;
 }
 
 static void lmv_del_target(struct lmv_obd *lmv, int index)
@@ -452,7 +446,6 @@
 	struct lmv_obd      *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc *tgt;
 	int		  rc = 0;
-	ENTRY;
 
 	CDEBUG(D_CONFIG, "Target uuid: %s. index %d\n", uuidp->uuid, index);
 
@@ -467,7 +460,7 @@
 			lmv_init_unlock(lmv);
 			CERROR("%s: Target %s not attached: rc = %d\n",
 			       obd->obd_name, uuidp->uuid, -EINVAL);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	}
 
@@ -477,7 +470,7 @@
 		       " rc = %d\n", obd->obd_name,
 		       obd_uuid2str(&tgt->ltd_uuid), index, -EEXIST);
 		lmv_init_unlock(lmv);
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 
 	if (index >= lmv->tgts_size) {
@@ -491,7 +484,7 @@
 		OBD_ALLOC(newtgts, sizeof(*newtgts) * newsize);
 		if (newtgts == NULL) {
 			lmv_init_unlock(lmv);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 
 		if (lmv->tgts_size) {
@@ -514,7 +507,7 @@
 	OBD_ALLOC_PTR(tgt);
 	if (!tgt) {
 		lmv_init_unlock(lmv);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	mutex_init(&tgt->ltd_fid_mutex);
@@ -541,7 +534,7 @@
 	}
 
 	lmv_init_unlock(lmv);
-	RETURN(rc);
+	return rc;
 }
 
 int lmv_check_connect(struct obd_device *obd)
@@ -551,21 +544,20 @@
 	int		   i;
 	int		   rc;
 	int		   easize;
-	ENTRY;
 
 	if (lmv->connected)
-		RETURN(0);
+		return 0;
 
 	lmv_init_lock(lmv);
 	if (lmv->connected) {
 		lmv_init_unlock(lmv);
-		RETURN(0);
+		return 0;
 	}
 
 	if (lmv->desc.ld_tgt_count == 0) {
 		lmv_init_unlock(lmv);
 		CERROR("%s: no targets configured.\n", obd->obd_name);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	CDEBUG(D_CONFIG, "Time to connect %s to %s\n",
@@ -588,7 +580,7 @@
 	easize = lmv_get_easize(lmv);
 	lmv_init_ea_size(obd->obd_self_export, easize, 0, 0);
 	lmv_init_unlock(lmv);
-	RETURN(0);
+	return 0;
 
  out_disc:
 	while (i-- > 0) {
@@ -609,7 +601,7 @@
 	}
 	class_disconnect(lmv->exp);
 	lmv_init_unlock(lmv);
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_disconnect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
@@ -618,7 +610,6 @@
 	struct lmv_obd	 *lmv = &obd->u.lmv;
 	struct obd_device      *mdc_obd;
 	int		     rc;
-	ENTRY;
 
 	LASSERT(tgt != NULL);
 	LASSERT(obd != NULL);
@@ -654,7 +645,7 @@
 
 	lmv_activate_target(lmv, tgt, 0);
 	tgt->ltd_exp = NULL;
-	RETURN(0);
+	return 0;
 }
 
 static int lmv_disconnect(struct obd_export *exp)
@@ -663,7 +654,6 @@
 	struct lmv_obd	*lmv = &obd->u.lmv;
 	int		    rc;
 	int		    i;
-	ENTRY;
 
 	if (!lmv->tgts)
 		goto out_local;
@@ -683,7 +673,7 @@
 	}
 
 	if (obd->obd_proc_private)
-		lprocfs_remove((proc_dir_entry_t **)&obd->obd_proc_private);
+		lprocfs_remove((struct proc_dir_entry **)&obd->obd_proc_private);
 	else
 		CERROR("/proc/fs/lustre/%s/%s/target_obds missing\n",
 		       obd->obd_type->typ_name, obd->obd_name);
@@ -698,7 +688,7 @@
 	rc = class_disconnect(exp);
 	if (lmv->refcount == 0)
 		lmv->connected = 0;
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_fid2path(struct obd_export *exp, int len, void *karg, void *uarg)
@@ -714,7 +704,7 @@
 	gf = (struct getinfo_fid2path *)karg;
 	tgt = lmv_find_target(lmv, &gf->gf_fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 repeat_fid2path:
 	rc = obd_iocontrol(OBD_IOC_FID2PATH, tgt->ltd_exp, len, gf, uarg);
@@ -780,9 +770,126 @@
 out_fid2path:
 	if (remote_gf != NULL)
 		OBD_FREE(remote_gf, remote_gf_size);
-	RETURN(rc);
+	return rc;
 }
 
+static int lmv_hsm_req_count(struct lmv_obd *lmv,
+			     const struct hsm_user_request *hur,
+			     const struct lmv_tgt_desc *tgt_mds)
+{
+	int			i, nr = 0;
+	struct lmv_tgt_desc    *curr_tgt;
+
+	/* count how many requests must be sent to the given target */
+	for (i = 0; i < hur->hur_request.hr_itemcount; i++) {
+		curr_tgt = lmv_find_target(lmv, &hur->hur_user_item[i].hui_fid);
+		if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid))
+			nr++;
+	}
+	return nr;
+}
+
+static void lmv_hsm_req_build(struct lmv_obd *lmv,
+			      struct hsm_user_request *hur_in,
+			      const struct lmv_tgt_desc *tgt_mds,
+			      struct hsm_user_request *hur_out)
+{
+	int			i, nr_out;
+	struct lmv_tgt_desc    *curr_tgt;
+
+	/* build the hsm_user_request for the given target */
+	hur_out->hur_request = hur_in->hur_request;
+	nr_out = 0;
+	for (i = 0; i < hur_in->hur_request.hr_itemcount; i++) {
+		curr_tgt = lmv_find_target(lmv,
+					&hur_in->hur_user_item[i].hui_fid);
+		if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid)) {
+			hur_out->hur_user_item[nr_out] =
+				hur_in->hur_user_item[i];
+			nr_out++;
+		}
+	}
+	hur_out->hur_request.hr_itemcount = nr_out;
+	memcpy(hur_data(hur_out), hur_data(hur_in),
+	       hur_in->hur_request.hr_data_len);
+}
+
+static int lmv_hsm_ct_unregister(struct lmv_obd *lmv, unsigned int cmd, int len,
+				 struct lustre_kernelcomm *lk, void *uarg)
+{
+	int	i, rc = 0;
+
+	/* unregister request (call from llapi_hsm_copytool_fini) */
+	for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
+		/* best effort: try to clean as much as possible
+		 * (continue on error) */
+		obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp, len, lk, uarg);
+	}
+
+	/* Whatever the result, remove copytool from kuc groups.
+	 * Unreached coordinators will get EPIPE on next requests
+	 * and will unregister automatically.
+	 */
+	rc = libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group);
+	return rc;
+}
+
+static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len,
+			       struct lustre_kernelcomm *lk, void *uarg)
+{
+	struct file	*filp;
+	int		 i, j, err;
+	int		 rc = 0;
+	bool		 any_set = false;
+
+	/* All or nothing: try to register to all MDS.
+	 * In case of failure, unregister from previous MDS,
+	 * except if it because of inactive target. */
+	for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
+		err = obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp,
+				   len, lk, uarg);
+		if (err) {
+			if (lmv->tgts[i]->ltd_active) {
+				/* permanent error */
+				CERROR("error: iocontrol MDC %s on MDT"
+				       "idx %d cmd %x: err = %d\n",
+					lmv->tgts[i]->ltd_uuid.uuid,
+					i, cmd, err);
+				rc = err;
+				lk->lk_flags |= LK_FLG_STOP;
+				/* unregister from previous MDS */
+				for (j = 0; j < i; j++)
+					obd_iocontrol(cmd,
+						  lmv->tgts[j]->ltd_exp,
+						  len, lk, uarg);
+				return rc;
+			}
+			/* else: transient error.
+			 * kuc will register to the missing MDT
+			 * when it is back */
+		} else {
+			any_set = true;
+		}
+	}
+
+	if (!any_set)
+		/* no registration done: return error */
+		return -ENOTCONN;
+
+	/* at least one registration done, with no failure */
+	filp = fget(lk->lk_wfd);
+	if (filp == NULL) {
+		return -EBADF;
+	}
+	rc = libcfs_kkuc_group_add(filp, lk->lk_uid, lk->lk_group, lk->lk_data);
+	if (rc != 0 && filp != NULL)
+		fput(filp);
+	return rc;
+}
+
+
+
+
 static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp,
 			 int len, void *karg, void *uarg)
 {
@@ -792,10 +899,9 @@
 	int		   rc = 0;
 	int		   set = 0;
 	int		   count = lmv->desc.ld_tgt_count;
-	ENTRY;
 
 	if (count == 0)
-		RETURN(-ENOTTY);
+		return -ENOTTY;
 
 	switch (cmd) {
 	case IOC_OBD_STATFS: {
@@ -806,31 +912,31 @@
 
 		memcpy(&index, data->ioc_inlbuf2, sizeof(__u32));
 		if ((index >= count))
-			RETURN(-ENODEV);
+			return -ENODEV;
 
 		if (lmv->tgts[index] == NULL ||
 		    lmv->tgts[index]->ltd_active == 0)
-			RETURN(-ENODATA);
+			return -ENODATA;
 
 		mdc_obd = class_exp2obd(lmv->tgts[index]->ltd_exp);
 		if (!mdc_obd)
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		/* copy UUID */
 		if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(mdc_obd),
 				     min((int) data->ioc_plen2,
 					 (int) sizeof(struct obd_uuid))))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		rc = obd_statfs(NULL, lmv->tgts[index]->ltd_exp, &stat_buf,
 				cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
 				0);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		if (copy_to_user(data->ioc_pbuf1, &stat_buf,
 				     min((int) data->ioc_plen1,
 					 (int) sizeof(stat_buf))))
-			RETURN(-EFAULT);
+			return -EFAULT;
 		break;
 	}
 	case OBD_IOC_QUOTACTL: {
@@ -840,11 +946,11 @@
 
 		if (qctl->qc_valid == QC_MDTIDX) {
 			if (qctl->qc_idx < 0 || count <= qctl->qc_idx)
-				RETURN(-EINVAL);
+				return -EINVAL;
 
 			tgt = lmv->tgts[qctl->qc_idx];
 			if (tgt == NULL || tgt->ltd_exp == NULL)
-				RETURN(-EINVAL);
+				return -EINVAL;
 		} else if (qctl->qc_valid == QC_UUID) {
 			for (i = 0; i < count; i++) {
 				tgt = lmv->tgts[i];
@@ -855,21 +961,21 @@
 					continue;
 
 				if (tgt->ltd_exp == NULL)
-					RETURN(-EINVAL);
+					return -EINVAL;
 
 				break;
 			}
 		} else {
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (i >= count)
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 
 		LASSERT(tgt && tgt->ltd_exp);
 		OBD_ALLOC_PTR(oqctl);
 		if (!oqctl)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		QCTL_COPY(oqctl, qctl);
 		rc = obd_quotactl(tgt->ltd_exp, oqctl);
@@ -886,19 +992,19 @@
 		struct ioc_changelog *icc = karg;
 
 		if (icc->icc_mdtindex >= count)
-			RETURN(-ENODEV);
+			return -ENODEV;
 
 		if (lmv->tgts[icc->icc_mdtindex] == NULL ||
 		    lmv->tgts[icc->icc_mdtindex]->ltd_exp == NULL ||
 		    lmv->tgts[icc->icc_mdtindex]->ltd_active == 0)
-			RETURN(-ENODEV);
+			return -ENODEV;
 		rc = obd_iocontrol(cmd, lmv->tgts[icc->icc_mdtindex]->ltd_exp,
 				   sizeof(*icc), icc, NULL);
 		break;
 	}
 	case LL_IOC_GET_CONNECT_FLAGS: {
 		if (lmv->tgts[0] == NULL)
-			RETURN(-ENODATA);
+			return -ENODATA;
 		rc = obd_iocontrol(cmd, lmv->tgts[0]->ltd_exp, len, karg, uarg);
 		break;
 	}
@@ -908,29 +1014,107 @@
 	}
 	case LL_IOC_HSM_STATE_GET:
 	case LL_IOC_HSM_STATE_SET:
-	case LL_IOC_HSM_ACTION:
+	case LL_IOC_HSM_ACTION: {
+		struct md_op_data	*op_data = karg;
+		struct lmv_tgt_desc	*tgt;
+
+		tgt = lmv_find_target(lmv, &op_data->op_fid1);
+		if (IS_ERR(tgt))
+				return PTR_ERR(tgt);
+
+		if (tgt->ltd_exp == NULL)
+				return -EINVAL;
+
+		rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
+		break;
+	}
+	case LL_IOC_HSM_PROGRESS: {
+		const struct hsm_progress_kernel *hpk = karg;
+		struct lmv_tgt_desc	*tgt;
+
+		tgt = lmv_find_target(lmv, &hpk->hpk_fid);
+		if (IS_ERR(tgt))
+			return PTR_ERR(tgt);
+		rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
+		break;
+	}
+	case LL_IOC_HSM_REQUEST: {
+		struct hsm_user_request *hur = karg;
+		struct lmv_tgt_desc	*tgt;
+		unsigned int reqcount = hur->hur_request.hr_itemcount;
+
+		if (reqcount == 0)
+			return 0;
+
+		/* if the request is about a single fid
+		 * or if there is a single MDS, no need to split
+		 * the request. */
+		if (reqcount == 1 || count == 1) {
+			tgt = lmv_find_target(lmv,
+					      &hur->hur_user_item[0].hui_fid);
+			if (IS_ERR(tgt))
+				return PTR_ERR(tgt);
+			rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg);
+		} else {
+			/* split fid list to their respective MDS */
+			for (i = 0; i < count; i++) {
+				unsigned int		nr, reqlen;
+				int			rc1;
+				struct hsm_user_request *req;
+
+				nr = lmv_hsm_req_count(lmv, hur, lmv->tgts[i]);
+				if (nr == 0) /* nothing for this MDS */
+					continue;
+
+				/* build a request with fids for this MDS */
+				reqlen = offsetof(typeof(*hur),
+						  hur_user_item[nr])
+					 + hur->hur_request.hr_data_len;
+				OBD_ALLOC_LARGE(req, reqlen);
+				if (req == NULL)
+					return -ENOMEM;
+
+				lmv_hsm_req_build(lmv, hur, lmv->tgts[i], req);
+
+				rc1 = obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp,
+						    reqlen, req, uarg);
+				if (rc1 != 0 && rc == 0)
+					rc = rc1;
+				OBD_FREE_LARGE(req, reqlen);
+			}
+		}
+		break;
+	}
 	case LL_IOC_LOV_SWAP_LAYOUTS: {
 		struct md_op_data	*op_data = karg;
 		struct lmv_tgt_desc	*tgt1, *tgt2;
 
 		tgt1 = lmv_find_target(lmv, &op_data->op_fid1);
 		if (IS_ERR(tgt1))
-			RETURN(PTR_ERR(tgt1));
+			return PTR_ERR(tgt1);
 
 		tgt2 = lmv_find_target(lmv, &op_data->op_fid2);
 		if (IS_ERR(tgt2))
-			RETURN(PTR_ERR(tgt2));
+			return PTR_ERR(tgt2);
 
 		if ((tgt1->ltd_exp == NULL) || (tgt2->ltd_exp == NULL))
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		/* only files on same MDT can have their layouts swapped */
 		if (tgt1->ltd_idx != tgt2->ltd_idx)
-			RETURN(-EPERM);
+			return -EPERM;
 
 		rc = obd_iocontrol(cmd, tgt1->ltd_exp, len, karg, uarg);
 		break;
 	}
+	case LL_IOC_HSM_CT_START: {
+		struct lustre_kernelcomm *lk = karg;
+		if (lk->lk_flags & LK_FLG_STOP)
+			rc = lmv_hsm_ct_unregister(lmv, cmd, len, lk, uarg);
+		else
+			rc = lmv_hsm_ct_register(lmv, cmd, len, lk, uarg);
+		break;
+	}
 	default:
 		for (i = 0; i < count; i++) {
 			struct obd_device *mdc_obd;
@@ -946,7 +1130,7 @@
 			err = obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp, len,
 					    karg, uarg);
 			if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
-				RETURN(err);
+				return err;
 			} else if (err) {
 				if (lmv->tgts[i]->ltd_active) {
 					CERROR("error: iocontrol MDC %s on MDT"
@@ -962,7 +1146,7 @@
 		if (!set && !rc)
 			rc = -EIO;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 #if 0
@@ -1018,13 +1202,12 @@
 				mdsno_t *mds)
 {
 	struct lmv_obd	  *lmv = &obd->u.lmv;
-	ENTRY;
 
 	LASSERT(mds != NULL);
 
 	if (lmv->desc.ld_tgt_count == 1) {
 		*mds = 0;
-		RETURN(0);
+		return 0;
 	}
 
 	/**
@@ -1042,17 +1225,17 @@
 				       " rc = %d\n", obd->obd_name,
 				       lum->lum_stripe_offset,
 				       lmv->desc.ld_tgt_count, -ERANGE);
-				RETURN(-ERANGE);
+				return -ERANGE;
 			}
 			*mds = lum->lum_stripe_offset;
-			RETURN(0);
+			return 0;
 		}
 	}
 
 	/* Allocate new fid on target according to operation type and parent
 	 * home mds. */
 	*mds = op_data->op_mds;
-	RETURN(0);
+	return 0;
 }
 
 int __lmv_fid_alloc(struct lmv_obd *lmv, struct lu_fid *fid,
@@ -1060,11 +1243,10 @@
 {
 	struct lmv_tgt_desc	*tgt;
 	int			 rc;
-	ENTRY;
 
 	tgt = lmv_get_target(lmv, mds);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	/*
 	 * New seq alloc and FLD setup should be atomic. Otherwise we may find
@@ -1084,7 +1266,6 @@
 		rc = 0;
 	}
 
-	EXIT;
 out:
 	mutex_unlock(&tgt->ltd_fid_mutex);
 	return rc;
@@ -1097,7 +1278,6 @@
 	struct lmv_obd	*lmv = &obd->u.lmv;
 	mdsno_t		mds = 0;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(op_data != NULL);
 	LASSERT(fid != NULL);
@@ -1106,16 +1286,16 @@
 	if (rc) {
 		CERROR("Can't get target for allocating fid, "
 		       "rc %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = __lmv_fid_alloc(lmv, fid, mds);
 	if (rc) {
 		CERROR("Can't alloc new fid, rc %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -1124,23 +1304,22 @@
 	struct lprocfs_static_vars  lvars;
 	struct lmv_desc	    *desc;
 	int			 rc;
-	ENTRY;
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
 		CERROR("LMV setup requires a descriptor\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	desc = (struct lmv_desc *)lustre_cfg_buf(lcfg, 1);
 	if (sizeof(*desc) > LUSTRE_CFG_BUFLEN(lcfg, 1)) {
 		CERROR("Lmv descriptor size wrong: %d > %d\n",
 		       (int)sizeof(*desc), LUSTRE_CFG_BUFLEN(lcfg, 1));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	OBD_ALLOC(lmv->tgts, sizeof(*lmv->tgts) * 32);
 	if (lmv->tgts == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lmv->tgts_size = 32;
 
 	obd_str2uuid(&lmv->desc.ld_uuid, desc->ld_uuid.uuid);
@@ -1173,7 +1352,7 @@
 		GOTO(out, rc);
 	}
 
-	RETURN(0);
+	return 0;
 
 out:
 	return rc;
@@ -1182,7 +1361,6 @@
 static int lmv_cleanup(struct obd_device *obd)
 {
 	struct lmv_obd   *lmv = &obd->u.lmv;
-	ENTRY;
 
 	fld_client_fini(&lmv->lmv_fld);
 	if (lmv->tgts != NULL) {
@@ -1195,7 +1373,7 @@
 		OBD_FREE(lmv->tgts, sizeof(*lmv->tgts) * lmv->tgts_size);
 		lmv->tgts_size = 0;
 	}
-	RETURN(0);
+	return 0;
 }
 
 static int lmv_process_config(struct obd_device *obd, obd_count len, void *buf)
@@ -1205,7 +1383,6 @@
 	int			gen;
 	__u32			index;
 	int			rc;
-	ENTRY;
 
 	switch (lcfg->lcfg_command) {
 	case LCFG_ADD_MDC:
@@ -1227,7 +1404,7 @@
 		GOTO(out, rc = -EINVAL);
 	}
 out:
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_statfs(const struct lu_env *env, struct obd_export *exp,
@@ -1238,15 +1415,14 @@
 	struct obd_statfs     *temp;
 	int		    rc = 0;
 	int		    i;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	OBD_ALLOC(temp, sizeof(*temp));
 	if (temp == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
 		if (lmv->tgts[i] == NULL || lmv->tgts[i]->ltd_exp == NULL)
@@ -1279,7 +1455,6 @@
 		}
 	}
 
-	EXIT;
 out_free_temp:
 	OBD_FREE(temp, sizeof(*temp));
 	return rc;
@@ -1292,14 +1467,13 @@
 	struct obd_device    *obd = exp->exp_obd;
 	struct lmv_obd       *lmv = &obd->u.lmv;
 	int		   rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = md_getstatus(lmv->tgts[0]->ltd_exp, fid, pc);
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid,
@@ -1311,20 +1485,19 @@
 	struct lmv_obd	 *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc    *tgt;
 	int		     rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_getxattr(tgt->ltd_exp, fid, oc, valid, name, input,
 			 input_size, output_size, flags, request);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid,
@@ -1337,21 +1510,20 @@
 	struct lmv_obd	 *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc    *tgt;
 	int		     rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_setxattr(tgt->ltd_exp, fid, oc, valid, name, input,
 			 input_size, output_size, flags, suppgid,
 			 request);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_getattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -1361,24 +1533,23 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	if (op_data->op_flags & MF_GET_MDT_IDX) {
 		op_data->op_mds = tgt->ltd_idx;
-		RETURN(0);
+		return 0;
 	}
 
 	rc = md_getattr(tgt->ltd_exp, op_data, request);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid)
@@ -1387,11 +1558,10 @@
 	struct lmv_obd      *lmv = &obd->u.lmv;
 	int		  i;
 	int		  rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "CBDATA for "DFID"\n", PFID(fid));
 
@@ -1406,7 +1576,7 @@
 		md_null_inode(lmv->tgts[i]->ltd_exp, fid);
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static int lmv_find_cbdata(struct obd_export *exp, const struct lu_fid *fid,
@@ -1416,11 +1586,10 @@
 	struct lmv_obd      *lmv = &obd->u.lmv;
 	int		  i;
 	int		  rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "CBDATA for "DFID"\n", PFID(fid));
 
@@ -1434,10 +1603,10 @@
 			continue;
 		rc = md_find_cbdata(lmv->tgts[i]->ltd_exp, fid, it, data);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1448,19 +1617,18 @@
 	struct lmv_obd	*lmv = &obd->u.lmv;
 	struct lmv_tgt_desc   *tgt;
 	int		    rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	CDEBUG(D_INODE, "CLOSE "DFID"\n", PFID(&op_data->op_fid1));
 	rc = md_close(tgt->ltd_exp, op_data, mod, request);
-	RETURN(rc);
+	return rc;
 }
 
 struct lmv_tgt_desc
@@ -1487,22 +1655,21 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (!lmv->desc.ld_active_tgt_count)
-		RETURN(-EIO);
+		return -EIO;
 
 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = lmv_fid_alloc(exp, &op_data->op_fid2, op_data);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "CREATE '%*s' on "DFID" -> mds #%x\n",
 	       op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
@@ -1514,10 +1681,10 @@
 
 	if (rc == 0) {
 		if (*request == NULL)
-			RETURN(rc);
+			return rc;
 		CDEBUG(D_INODE, "Created - "DFID"\n", PFID(&op_data->op_fid2));
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_done_writing(struct obd_export *exp,
@@ -1528,18 +1695,17 @@
 	struct lmv_obd	*lmv = &obd->u.lmv;
 	struct lmv_tgt_desc   *tgt;
 	int		    rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_done_writing(tgt->ltd_exp, op_data, mod);
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -1558,13 +1724,12 @@
 	struct mdt_body	    *body;
 	int			 rc = 0;
 	int			 pmode;
-	ENTRY;
 
 	body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
 	LASSERT(body != NULL);
 
 	if (!(body->valid & OBD_MD_MDS))
-		RETURN(0);
+		return 0;
 
 	CDEBUG(D_INODE, "REMOTE_ENQUEUE '%s' on "DFID" -> "DFID"\n",
 	       LL_IT2STR(it), PFID(&op_data->op_fid1), PFID(&body->fid1));
@@ -1596,7 +1761,6 @@
 	rc = md_enqueue(tgt->ltd_exp, einfo, it, rdata, lockh,
 			lmm, lmmsize, NULL, extra_lock_flags);
 	OBD_FREE_PTR(rdata);
-	EXIT;
 out:
 	ldlm_lock_decref(&plock, pmode);
 	return rc;
@@ -1612,18 +1776,17 @@
 	struct lmv_obd	   *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc      *tgt;
 	int		       rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "ENQUEUE '%s' on "DFID"\n",
 	       LL_IT2STR(it), PFID(&op_data->op_fid1));
 
 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	CDEBUG(D_INODE, "ENQUEUE '%s' on "DFID" -> mds #%d\n",
 	       LL_IT2STR(it), PFID(&op_data->op_fid1), tgt->ltd_idx);
@@ -1635,7 +1798,7 @@
 		rc = lmv_enqueue_remote(exp, einfo, it, op_data, lockh,
 					lmm, lmmsize, extra_lock_flags);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -1648,15 +1811,14 @@
 	struct lmv_tgt_desc     *tgt;
 	struct mdt_body	 *body;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	CDEBUG(D_INODE, "GETATTR_NAME for %*s on "DFID" -> mds #%d\n",
 	       op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
@@ -1664,7 +1826,7 @@
 
 	rc = md_getattr_name(tgt->ltd_exp, op_data, request);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	body = req_capsule_server_get(&(*request)->rq_pill,
 				      &RMF_MDT_BODY);
@@ -1678,7 +1840,7 @@
 		tgt = lmv_find_target(lmv, &rid);
 		if (IS_ERR(tgt)) {
 			ptlrpc_req_finished(*request);
-			RETURN(PTR_ERR(tgt));
+			return PTR_ERR(tgt);
 		}
 
 		op_data->op_fid1 = rid;
@@ -1690,7 +1852,7 @@
 		*request = req;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 #define md_op_data_fid(op_data, fl)		     \
@@ -1709,14 +1871,13 @@
 	struct lmv_tgt_desc    *tgt;
 	ldlm_policy_data_t      policy = {{0}};
 	int		     rc = 0;
-	ENTRY;
 
 	if (!fid_is_sane(fid))
-		RETURN(0);
+		return 0;
 
 	tgt = lmv_find_target(lmv, fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	if (tgt->ltd_idx != op_tgt) {
 		CDEBUG(D_INODE, "EARLY_CANCEL on "DFID"\n", PFID(fid));
@@ -1731,7 +1892,7 @@
 		rc = 0;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -1745,11 +1906,10 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	LASSERT(op_data->op_namelen != 0);
 
@@ -1757,12 +1917,12 @@
 	       PFID(&op_data->op_fid2), op_data->op_namelen,
 	       op_data->op_name, PFID(&op_data->op_fid1));
 
-	op_data->op_fsuid = current_fsuid();
-	op_data->op_fsgid = current_fsgid();
+	op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+	op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
 	op_data->op_cap = cfs_curproc_cap_pack();
 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid2);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	/*
 	 * Cancel UPDATE lock on child (fid1).
@@ -1771,11 +1931,11 @@
 	rc = lmv_early_cancel(exp, op_data, tgt->ltd_idx, LCK_EX,
 			      MDS_INODELOCK_UPDATE, MF_MDC_CANCEL_FID1);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	rc = md_link(tgt->ltd_exp, op_data, request);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data,
@@ -1787,7 +1947,6 @@
 	struct lmv_tgt_desc     *src_tgt;
 	struct lmv_tgt_desc     *tgt_tgt;
 	int			rc;
-	ENTRY;
 
 	LASSERT(oldlen != 0);
 
@@ -1797,18 +1956,18 @@
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
-	op_data->op_fsuid = current_fsuid();
-	op_data->op_fsgid = current_fsgid();
+	op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+	op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
 	op_data->op_cap = cfs_curproc_cap_pack();
 	src_tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(src_tgt))
-		RETURN(PTR_ERR(src_tgt));
+		return PTR_ERR(src_tgt);
 
 	tgt_tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid2);
 	if (IS_ERR(tgt_tgt))
-		RETURN(PTR_ERR(tgt_tgt));
+		return PTR_ERR(tgt_tgt);
 	/*
 	 * LOOKUP lock on src child (fid3) should also be cancelled for
 	 * src_tgt in mdc_rename.
@@ -1843,7 +2002,7 @@
 	if (rc == 0)
 		rc = md_rename(src_tgt->ltd_exp, op_data, old, oldlen,
 			       new, newlen, request);
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -1855,11 +2014,10 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc = 0;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "SETATTR for "DFID", valid 0x%x\n",
 	       PFID(&op_data->op_fid1), op_data->op_attr.ia_valid);
@@ -1867,12 +2025,12 @@
 	op_data->op_flags |= MF_MDC_CANCEL_FID1;
 	tgt = lmv_find_target(lmv, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_setattr(tgt->ltd_exp, op_data, ea, ealen, ea2,
 			ea2len, request, mod);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_sync(struct obd_export *exp, const struct lu_fid *fid,
@@ -1882,18 +2040,17 @@
 	struct lmv_obd	    *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc       *tgt;
 	int			rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_sync(tgt->ltd_exp, fid, oc, request);
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -1959,7 +2116,7 @@
 		__u64			hash_end = dp->ldp_hash_end;
 		__u32			flags = dp->ldp_flags;
 
-		for (; nlupgs > 1; nlupgs--) {
+		while (--nlupgs > 0) {
 			ent = lu_dirent_start(dp);
 			for (end_dirent = ent; ent != NULL;
 			     end_dirent = ent, ent = lu_dirent_next(ent));
@@ -1993,6 +2150,7 @@
 
 		kunmap(pages[i]);
 	}
+	LASSERTF(nlupgs == 0, "left = %d", nlupgs);
 }
 #else
 #define lmv_adjust_dirpages(pages, ncfspgs, nlupgs) do {} while (0)
@@ -2008,22 +2166,21 @@
 	int			ncfspgs; /* pages read in PAGE_CACHE_SIZE */
 	int			nlupgs; /* pages read in LU_PAGE_SIZE */
 	struct lmv_tgt_desc	*tgt;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "READPAGE at "LPX64" from "DFID"\n",
 	       offset, PFID(&op_data->op_fid1));
 
 	tgt = lmv_find_target(lmv, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_readpage(tgt->ltd_exp, op_data, pages, request);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	ncfspgs = ((*request)->rq_bulk->bd_nob_transferred + PAGE_CACHE_SIZE - 1)
 		 >> PAGE_CACHE_SHIFT;
@@ -2036,7 +2193,7 @@
 
 	lmv_adjust_dirpages(pages, ncfspgs, nlupgs);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_unlink(struct obd_export *exp, struct md_op_data *op_data,
@@ -2047,11 +2204,10 @@
 	struct lmv_tgt_desc     *tgt = NULL;
 	struct mdt_body		*body;
 	int		     rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 retry:
 	/* Send unlink requests to the MDT where the child is located */
 	if (likely(!fid_is_zero(&op_data->op_fid2)))
@@ -2059,10 +2215,10 @@
 	else
 		tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
-	op_data->op_fsuid = current_fsuid();
-	op_data->op_fsgid = current_fsgid();
+	op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid());
+	op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid());
 	op_data->op_cap = cfs_curproc_cap_pack();
 
 	/*
@@ -2081,22 +2237,22 @@
 			      MDS_INODELOCK_FULL, MF_MDC_CANCEL_FID3);
 
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INODE, "unlink with fid="DFID"/"DFID" -> mds #%d\n",
 	       PFID(&op_data->op_fid1), PFID(&op_data->op_fid2), tgt->ltd_idx);
 
 	rc = md_unlink(tgt->ltd_exp, op_data, request);
 	if (rc != 0 && rc != -EREMOTE)
-		RETURN(rc);
+		return rc;
 
 	body = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_BODY);
 	if (body == NULL)
-		RETURN(-EPROTO);
+		return -EPROTO;
 
 	/* Not cross-ref case, just get out of here. */
 	if (likely(!(body->valid & OBD_MD_MDS)))
-		RETURN(0);
+		return 0;
 
 	CDEBUG(D_INODE, "%s: try unlink to another MDT for "DFID"\n",
 	       exp->exp_obd->obd_name, PFID(&body->fid1));
@@ -2144,7 +2300,7 @@
 	default:
 		break;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
@@ -2154,13 +2310,12 @@
 	struct obd_device       *obd;
 	struct lmv_obd	  *lmv;
 	int		      rc = 0;
-	ENTRY;
 
 	obd = class_exp2obd(exp);
 	if (obd == NULL) {
 		CDEBUG(D_IOCTL, "Invalid client cookie "LPX64"\n",
 		       exp->exp_handle.h_cookie);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	lmv = &obd->u.lmv;
@@ -2170,7 +2325,7 @@
 
 		rc = lmv_check_connect(obd);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		LASSERT(*vallen == sizeof(__u32));
 		for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
@@ -2183,13 +2338,13 @@
 
 			if (!obd_get_info(env, tgt->ltd_exp, keylen, key,
 					  vallen, val, NULL))
-				RETURN(0);
+				return 0;
 		}
-		RETURN(-EINVAL);
+		return -EINVAL;
 	} else if (KEY_IS(KEY_MAX_EASIZE) || KEY_IS(KEY_CONN_DATA)) {
 		rc = lmv_check_connect(obd);
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		/*
 		 * Forwarding this request to first MDS, it should know LOV
@@ -2199,14 +2354,14 @@
 				  vallen, val, NULL);
 		if (!rc && KEY_IS(KEY_CONN_DATA))
 			exp->exp_connect_data = *(struct obd_connect_data *)val;
-		RETURN(rc);
+		return rc;
 	} else if (KEY_IS(KEY_TGT_COUNT)) {
 		*((int *)val) = lmv->desc.ld_tgt_count;
-		RETURN(0);
+		return 0;
 	}
 
 	CDEBUG(D_IOCTL, "Invalid key\n");
-	RETURN(-EINVAL);
+	return -EINVAL;
 }
 
 int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -2217,13 +2372,12 @@
 	struct obd_device      *obd;
 	struct lmv_obd	 *lmv;
 	int rc = 0;
-	ENTRY;
 
 	obd = class_exp2obd(exp);
 	if (obd == NULL) {
 		CDEBUG(D_IOCTL, "Invalid client cookie "LPX64"\n",
 		       exp->exp_handle.h_cookie);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	lmv = &obd->u.lmv;
 
@@ -2242,10 +2396,10 @@
 				rc = err;
 		}
 
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(-EINVAL);
+	return -EINVAL;
 }
 
 int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
@@ -2257,33 +2411,32 @@
 	struct lmv_stripe_md      *lsmp;
 	int			mea_size;
 	int			i;
-	ENTRY;
 
 	mea_size = lmv_get_easize(lmv);
 	if (!lmmp)
-		RETURN(mea_size);
+		return mea_size;
 
 	if (*lmmp && !lsm) {
 		OBD_FREE_LARGE(*lmmp, mea_size);
 		*lmmp = NULL;
-		RETURN(0);
+		return 0;
 	}
 
 	if (*lmmp == NULL) {
 		OBD_ALLOC_LARGE(*lmmp, mea_size);
 		if (*lmmp == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 	}
 
 	if (!lsm)
-		RETURN(mea_size);
+		return mea_size;
 
 	lsmp = (struct lmv_stripe_md *)lsm;
 	meap = (struct lmv_stripe_md *)*lmmp;
 
 	if (lsmp->mea_magic != MEA_MAGIC_LAST_CHAR &&
 	    lsmp->mea_magic != MEA_MAGIC_ALL_CHARS)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	meap->mea_magic = cpu_to_le32(lsmp->mea_magic);
 	meap->mea_count = cpu_to_le32(lsmp->mea_count);
@@ -2294,7 +2447,7 @@
 		fid_cpu_to_le(&meap->mea_ids[i], &lsmp->mea_ids[i]);
 	}
 
-	RETURN(mea_size);
+	return mea_size;
 }
 
 int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
@@ -2307,7 +2460,6 @@
 	int			 mea_size;
 	int			 i;
 	__u32		       magic;
-	ENTRY;
 
 	mea_size = lmv_get_easize(lmv);
 	if (lsmp == NULL)
@@ -2316,17 +2468,17 @@
 	if (*lsmp != NULL && lmm == NULL) {
 		OBD_FREE_LARGE(*tmea, mea_size);
 		*lsmp = NULL;
-		RETURN(0);
+		return 0;
 	}
 
 	LASSERT(mea_size == lmm_size);
 
 	OBD_ALLOC_LARGE(*tmea, mea_size);
 	if (*tmea == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (!lmm)
-		RETURN(mea_size);
+		return mea_size;
 
 	if (mea->mea_magic == MEA_MAGIC_LAST_CHAR ||
 	    mea->mea_magic == MEA_MAGIC_ALL_CHARS ||
@@ -2349,7 +2501,7 @@
 		(*tmea)->mea_ids[i] = mea->mea_ids[i];
 		fid_le_to_cpu(&(*tmea)->mea_ids[i], &(*tmea)->mea_ids[i]);
 	}
-	RETURN(mea_size);
+	return mea_size;
 }
 
 static int lmv_cancel_unused(struct obd_export *exp, const struct lu_fid *fid,
@@ -2361,7 +2513,6 @@
 	int		      rc = 0;
 	int		      err;
 	int		      i;
-	ENTRY;
 
 	LASSERT(fid != NULL);
 
@@ -2375,7 +2526,7 @@
 		if (!rc)
 			rc = err;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
@@ -2383,10 +2534,9 @@
 {
 	struct lmv_obd	  *lmv = &exp->exp_obd->u.lmv;
 	int		      rc;
-	ENTRY;
 
 	rc =  md_set_lock_data(lmv->tgts[0]->ltd_exp, lockh, data, bits);
-	RETURN(rc);
+	return rc;
 }
 
 ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
@@ -2398,7 +2548,6 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	ldlm_mode_t	      rc;
 	int		      i;
-	ENTRY;
 
 	CDEBUG(D_INODE, "Lock match for "DFID"\n", PFID(fid));
 
@@ -2417,10 +2566,10 @@
 		rc = md_lock_match(lmv->tgts[i]->ltd_exp, flags, fid,
 				   type, policy, mode, lockh);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int lmv_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
@@ -2436,11 +2585,10 @@
 {
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
-	ENTRY;
 
 	if (md->mea)
 		obd_free_memmd(exp, (void *)&md->mea);
-	RETURN(md_free_lustre_md(lmv->tgts[0]->ltd_exp, md));
+	return md_free_lustre_md(lmv->tgts[0]->ltd_exp, md);
 }
 
 int lmv_set_open_replay_data(struct obd_export *exp,
@@ -2450,13 +2598,12 @@
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
-	ENTRY;
 
 	tgt = lmv_find_target(lmv, &och->och_fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
-	RETURN(md_set_open_replay_data(tgt->ltd_exp, och, open_req));
+	return md_set_open_replay_data(tgt->ltd_exp, och, open_req);
 }
 
 int lmv_clear_open_replay_data(struct obd_export *exp,
@@ -2465,13 +2612,12 @@
 	struct obd_device       *obd = exp->exp_obd;
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
-	ENTRY;
 
 	tgt = lmv_find_target(lmv, &och->och_fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
-	RETURN(md_clear_open_replay_data(tgt->ltd_exp, och));
+	return md_clear_open_replay_data(tgt->ltd_exp, och);
 }
 
 static int lmv_get_remote_perm(struct obd_export *exp,
@@ -2483,18 +2629,17 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_get_remote_perm(tgt->ltd_exp, fid, oc, suppgid, request);
-	RETURN(rc);
+	return rc;
 }
 
 static int lmv_renew_capa(struct obd_export *exp, struct obd_capa *oc,
@@ -2504,18 +2649,17 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, &oc->c_capa.lc_fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_renew_capa(tgt->ltd_exp, oc, cb);
-	RETURN(rc);
+	return rc;
 }
 
 int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
@@ -2535,18 +2679,17 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt = NULL;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, &op_data->op_fid1);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_intent_getattr_async(tgt->ltd_exp, minfo, einfo);
-	RETURN(rc);
+	return rc;
 }
 
 int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
@@ -2556,18 +2699,17 @@
 	struct lmv_obd	  *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc     *tgt;
 	int		      rc;
-	ENTRY;
 
 	rc = lmv_check_connect(obd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = lmv_find_target(lmv, fid);
 	if (IS_ERR(tgt))
-		RETURN(PTR_ERR(tgt));
+		return PTR_ERR(tgt);
 
 	rc = md_revalidate_lock(tgt->ltd_exp, it, fid, bits);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2583,16 +2725,15 @@
 	struct lmv_tgt_desc *tgt = lmv->tgts[0];
 	int		  rc = 0, i;
 	__u64		curspace, curinodes;
-	ENTRY;
 
 	if (!lmv->desc.ld_tgt_count || !tgt->ltd_active) {
 		CERROR("master lmv inactive\n");
-		RETURN(-EIO);
+		return -EIO;
 	}
 
 	if (oqctl->qc_cmd != Q_GETOQUOTA) {
 		rc = obd_quotactl(tgt->ltd_exp, oqctl);
-		RETURN(rc);
+		return rc;
 	}
 
 	curspace = curinodes = 0;
@@ -2620,7 +2761,7 @@
 	oqctl->qc_dqblk.dqb_curspace = curspace;
 	oqctl->qc_dqblk.dqb_curinodes = curinodes;
 
-	RETURN(rc);
+	return rc;
 }
 
 int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
@@ -2630,14 +2771,13 @@
 	struct lmv_obd      *lmv = &obd->u.lmv;
 	struct lmv_tgt_desc *tgt;
 	int		  i, rc = 0;
-	ENTRY;
 
 	for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
 		int err;
 		tgt = lmv->tgts[i];
 		if (tgt == NULL || tgt->ltd_exp == NULL || !tgt->ltd_active) {
 			CERROR("lmv idx %d inactive\n", i);
-			RETURN(-EIO);
+			return -EIO;
 		}
 
 		err = obd_quotacheck(tgt->ltd_exp, oqctl);
@@ -2645,7 +2785,7 @@
 			rc = err;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 struct obd_ops lmv_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
index d1c45b5..edb5a3a 100644
--- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
+++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
@@ -36,7 +36,6 @@
 
 #define DEBUG_SUBSYSTEM S_CLASS
 
-#include <linux/version.h>
 #include <linux/seq_file.h>
 #include <asm/statfs.h>
 #include <lprocfs_status.h>
diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
index 28801b8..33d9ce6 100644
--- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
+++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h
@@ -162,10 +162,9 @@
  * Layout type.
  */
 enum lov_layout_type {
-	/** empty file without body */
-	LLT_EMPTY,
-	/** striped file */
-	LLT_RAID0,
+	LLT_EMPTY,	/** empty file without body (mknod + truncate) */
+	LLT_RAID0,	/** striped file */
+	LLT_RELEASED,	/** file with no objects (data in HSM) */
 	LLT_NR
 };
 
@@ -255,12 +254,14 @@
 		} raid0;
 		struct lov_layout_state_empty {
 		} empty;
+		struct lov_layout_state_released {
+		} released;
 	} u;
 	/**
 	 * Thread that acquired lov_object::lo_type_guard in an exclusive
 	 * mode.
 	 */
-	task_t	    *lo_owner;
+	struct task_struct	*lo_owner;
 };
 
 /**
@@ -582,6 +583,8 @@
 			   struct cl_io *io);
 int   lov_io_init_empty   (const struct lu_env *env, struct cl_object *obj,
 			   struct cl_io *io);
+int   lov_io_init_released(const struct lu_env *env, struct cl_object *obj,
+			   struct cl_io *io);
 void  lov_lock_unlink     (const struct lu_env *env, struct lov_lock_link *link,
 			   struct lovsub_lock *sub);
 
diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c
index f94f8d9..a4006ef 100644
--- a/drivers/staging/lustre/lustre/lov/lov_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lov_dev.c
@@ -122,10 +122,8 @@
 {
 	struct lov_req *lr;
 
-	ENTRY;
 	lr = cl2lov_req(slice);
 	OBD_SLAB_FREE_PTR(lr, lov_req_kmem);
-	EXIT;
 }
 
 static const struct cl_req_operations lov_req_ops = {
@@ -200,7 +198,7 @@
 
 	LASSERT(ld->ld_lov != NULL);
 	if (ld->ld_target == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	lov_foreach_target(ld, i) {
 		struct lovsub_device *lsd;
@@ -211,7 +209,7 @@
 			ld->ld_target[i] = NULL;
 		}
 	}
-	RETURN(NULL);
+	return NULL;
 }
 
 static int lov_device_init(const struct lu_env *env, struct lu_device *d,
@@ -223,7 +221,7 @@
 
 	LASSERT(d->ld_site != NULL);
 	if (ld->ld_target == NULL)
-		RETURN(rc);
+		return rc;
 
 	lov_foreach_target(ld, i) {
 		struct lovsub_device *lsd;
@@ -251,7 +249,7 @@
 	else
 		ld->ld_flags |= LOV_DEV_INITIALIZED;
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_req_init(const struct lu_env *env, struct cl_device *dev,
@@ -260,14 +258,13 @@
 	struct lov_req *lr;
 	int result;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(lr, lov_req_kmem, __GFP_IO);
 	if (lr != NULL) {
 		cl_req_slice_add(req, &lr->lr_cl, dev, &lov_req_ops);
 		result = 0;
 	} else
 		result = -ENOMEM;
-	RETURN(result);
+	return result;
 }
 
 static const struct cl_device_operations lov_cl_ops = {
@@ -311,13 +308,11 @@
 			      __u32 index)
 {
 	struct lov_device *ld = lu2lov_dev(dev);
-	ENTRY;
 
 	if (ld->ld_target[index] != NULL) {
 		cl_stack_fini(env, lovsub2cl_dev(ld->ld_target[index]));
 		ld->ld_target[index] = NULL;
 	}
-	EXIT;
 }
 
 static struct lov_device_emerg **lov_emerg_alloc(int nr)
@@ -360,7 +355,6 @@
 	__u32 tgt_size;
 	__u32 sub_size;
 
-	ENTRY;
 	result = 0;
 	tgt_size = dev->ld_lov->lov_tgt_size;
 	sub_size = dev->ld_target_nr;
@@ -371,7 +365,7 @@
 
 		emerg = lov_emerg_alloc(tgt_size);
 		if (IS_ERR(emerg))
-			RETURN(PTR_ERR(emerg));
+			return PTR_ERR(emerg);
 
 		OBD_ALLOC(newd, tgt_size * sz);
 		if (newd != NULL) {
@@ -392,7 +386,7 @@
 			result = -ENOMEM;
 		}
 	}
-	RETURN(result);
+	return result;
 }
 
 static int lov_cl_add_target(const struct lu_env *env, struct lu_device *dev,
@@ -404,7 +398,6 @@
 	struct lovsub_device *lsd;
 	struct cl_device     *cl;
 	int rc;
-	ENTRY;
 
 	obd_getref(obd);
 
@@ -414,7 +407,7 @@
 
 	if (!tgt->ltd_obd->obd_set_up) {
 		CERROR("Target %s not set up\n", obd_uuid2str(&tgt->ltd_uuid));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = lov_expand_targets(env, ld);
@@ -436,7 +429,7 @@
 		}
 	}
 	obd_putref(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_process_config(const struct lu_env *env,
@@ -466,7 +459,7 @@
 		}
 	}
 	obd_putref(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static const struct lu_device_operations lov_lu_ops = {
@@ -485,7 +478,7 @@
 
 	OBD_ALLOC_PTR(ld);
 	if (ld == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	cl_device_init(&ld->ld_cl, t);
 	d = lov2lu_dev(ld);
@@ -501,11 +494,11 @@
 	rc = lov_setup(obd, cfg);
 	if (rc) {
 		lov_device_free(env, d);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	ld->ld_lov = &obd->u.lov;
-	RETURN(d);
+	return d;
 }
 
 static const struct lu_device_type_operations lov_device_type_ops = {
diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c
index 340dbcf..e6c6015 100644
--- a/drivers/staging/lustre/lustre/lov/lov_ea.c
+++ b/drivers/staging/lustre/lustre/lov/lov_ea.c
@@ -57,7 +57,7 @@
 static int lsm_lmm_verify_common(struct lov_mds_md *lmm, int lmm_bytes,
 				 __u16 stripe_count)
 {
-	if (stripe_count == 0 || stripe_count > LOV_V1_INSANE_STRIPE_COUNT) {
+	if (stripe_count > LOV_V1_INSANE_STRIPE_COUNT) {
 		CERROR("bad stripe count %d\n", stripe_count);
 		lov_dump_lmm_common(D_WARNING, lmm);
 		return -EINVAL;
@@ -69,7 +69,7 @@
 		return -EINVAL;
 	}
 
-	if (lmm->lmm_pattern != cpu_to_le32(LOV_PATTERN_RAID0)) {
+	if (lov_pattern(le32_to_cpu(lmm->lmm_pattern)) != LOV_PATTERN_RAID0) {
 		CERROR("bad striping pattern\n");
 		lov_dump_lmm_common(D_WARNING, lmm);
 		return -EINVAL;
@@ -197,6 +197,8 @@
 	}
 
 	*stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+	if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+		*stripe_count = 0;
 
 	if (lmm_bytes < lov_mds_md_size(*stripe_count, LOV_MAGIC_V1)) {
 		CERROR("LOV EA V1 too small: %d, need %d\n",
@@ -213,11 +215,14 @@
 {
 	struct lov_oinfo *loi;
 	int i;
+	int stripe_count;
 	__u64 stripe_maxbytes = OBD_OBJECT_EOF;
 
 	lsm_unpackmd_common(lsm, lmm);
 
-	for (i = 0; i < lsm->lsm_stripe_count; i++) {
+	stripe_count = lsm_is_released(lsm) ? 0 : lsm->lsm_stripe_count;
+
+	for (i = 0; i < stripe_count; i++) {
 		/* XXX LOV STACKING call down to osc_unpackmd() */
 		loi = lsm->lsm_oinfo[i];
 		ostid_le_to_cpu(&lmm->lmm_objects[i].l_ost_oi, &loi->loi_oi);
@@ -240,6 +245,8 @@
 	}
 
 	lsm->lsm_maxbytes = stripe_maxbytes * lsm->lsm_stripe_count;
+	if (lsm->lsm_stripe_count == 0)
+		lsm->lsm_maxbytes = stripe_maxbytes * lov->desc.ld_tgt_count;
 
 	return 0;
 }
@@ -267,6 +274,8 @@
 	}
 
 	*stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+	if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+		*stripe_count = 0;
 
 	if (lmm_bytes < lov_mds_md_size(*stripe_count, LOV_MAGIC_V3)) {
 		CERROR("LOV EA V3 too small: %d, need %d\n",
@@ -285,18 +294,22 @@
 	struct lov_mds_md_v3 *lmm;
 	struct lov_oinfo *loi;
 	int i;
+	int stripe_count;
 	__u64 stripe_maxbytes = OBD_OBJECT_EOF;
 	int cplen = 0;
 
 	lmm = (struct lov_mds_md_v3 *)lmmv1;
 
 	lsm_unpackmd_common(lsm, (struct lov_mds_md_v1 *)lmm);
+
+	stripe_count = lsm_is_released(lsm) ? 0 : lsm->lsm_stripe_count;
+
 	cplen = strlcpy(lsm->lsm_pool_name, lmm->lmm_pool_name,
 			sizeof(lsm->lsm_pool_name));
 	if (cplen >= sizeof(lsm->lsm_pool_name))
 		return -E2BIG;
 
-	for (i = 0; i < lsm->lsm_stripe_count; i++) {
+	for (i = 0; i < stripe_count; i++) {
 		/* XXX LOV STACKING call down to osc_unpackmd() */
 		loi = lsm->lsm_oinfo[i];
 		ostid_le_to_cpu(&lmm->lmm_objects[i].l_ost_oi, &loi->loi_oi);
@@ -319,6 +332,8 @@
 	}
 
 	lsm->lsm_maxbytes = stripe_maxbytes * lsm->lsm_stripe_count;
+	if (lsm->lsm_stripe_count == 0)
+		lsm->lsm_maxbytes = stripe_maxbytes * lov->desc.ld_tgt_count;
 
 	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c
index 1a87abd..b611aa4 100644
--- a/drivers/staging/lustre/lustre/lov/lov_io.c
+++ b/drivers/staging/lustre/lustre/lov/lov_io.c
@@ -59,7 +59,6 @@
 static void lov_io_sub_fini(const struct lu_env *env, struct lov_io *lio,
 			    struct lov_io_sub *sub)
 {
-	ENTRY;
 	if (sub->sub_io != NULL) {
 		if (sub->sub_io_initialized) {
 			lov_sub_enter(sub);
@@ -79,7 +78,6 @@
 			cl_env_put(sub->sub_env, &sub->sub_refcheck);
 		sub->sub_env = NULL;
 	}
-	EXIT;
 }
 
 static void lov_io_sub_inherit(struct cl_io *io, struct lov_io *lio,
@@ -149,7 +147,6 @@
 	LASSERT(sub->sub_io == NULL);
 	LASSERT(sub->sub_env == NULL);
 	LASSERT(sub->sub_stripe < lio->lis_stripe_count);
-	ENTRY;
 
 	result = 0;
 	sub->sub_io_initialized = 0;
@@ -210,7 +207,7 @@
 	}
 	if (result != 0)
 		lov_io_sub_fini(env, lio, sub);
-	RETURN(result);
+	return result;
 }
 
 struct lov_io_sub *lov_sub_get(const struct lu_env *env,
@@ -220,7 +217,6 @@
 	struct lov_io_sub *sub = &lio->lis_subs[stripe];
 
 	LASSERT(stripe < lio->lis_stripe_count);
-	ENTRY;
 
 	if (!sub->sub_io_initialized) {
 		sub->sub_stripe = stripe;
@@ -231,7 +227,7 @@
 		lov_sub_enter(sub);
 	else
 		sub = ERR_PTR(rc);
-	RETURN(sub);
+	return sub;
 }
 
 void lov_sub_put(struct lov_io_sub *sub)
@@ -249,12 +245,11 @@
 {
 	struct lovsub_object *subobj;
 
-	ENTRY;
 	subobj = lu2lovsub(
 		lu_object_locate(page->cp_child->cp_obj->co_lu.lo_header,
 				 &lovsub_device_type));
 	LASSERT(subobj != NULL);
-	RETURN(subobj->lso_index);
+	return subobj->lso_index;
 }
 
 struct lov_io_sub *lov_page_subio(const struct lu_env *env, struct lov_io *lio,
@@ -268,10 +263,9 @@
 	LASSERT(cl2lov(slice->cpl_obj) == lio->lis_object);
 	LASSERT(lsm != NULL);
 	LASSERT(lio->lis_nr_subios > 0);
-	ENTRY;
 
 	stripe = lov_page_stripe(page);
-	RETURN(lov_sub_get(env, lio, stripe));
+	return lov_sub_get(env, lio, stripe);
 }
 
 
@@ -282,7 +276,6 @@
 	int result;
 
 	LASSERT(lio->lis_object != NULL);
-	ENTRY;
 
 	/*
 	 * Need to be optimized, we can't afford to allocate a piece of memory
@@ -297,14 +290,12 @@
 		result = 0;
 	} else
 		result = -ENOMEM;
-	RETURN(result);
+	return result;
 }
 
 static void lov_io_slice_init(struct lov_io *lio,
 			      struct lov_object *obj, struct cl_io *io)
 {
-	ENTRY;
-
 	io->ci_result = 0;
 	lio->lis_object = obj;
 
@@ -353,8 +344,6 @@
 	default:
 		LBUG();
 	}
-
-	EXIT;
 }
 
 static void lov_io_fini(const struct lu_env *env, const struct cl_io_slice *ios)
@@ -363,7 +352,6 @@
 	struct lov_object *lov = cl2lov(ios->cis_obj);
 	int i;
 
-	ENTRY;
 	if (lio->lis_subs != NULL) {
 		for (i = 0; i < lio->lis_nr_subios; i++)
 			lov_io_sub_fini(env, lio, &lio->lis_subs[i]);
@@ -375,7 +363,6 @@
 	LASSERT(atomic_read(&lov->lo_active_ios) > 0);
 	if (atomic_dec_and_test(&lov->lo_active_ios))
 		wake_up_all(&lov->lo_waitq);
-	EXIT;
 }
 
 static obd_off lov_offset_mod(obd_off val, int delta)
@@ -397,7 +384,6 @@
 	int stripe;
 	int rc = 0;
 
-	ENTRY;
 	endpos = lov_offset_mod(lio->lis_endpos, -1);
 	for (stripe = 0; stripe < lio->lis_stripe_count; stripe++) {
 		if (!lov_stripe_intersects(lsm, stripe, lio->lis_pos,
@@ -421,7 +407,7 @@
 		else
 			break;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_io_rw_iter_init(const struct lu_env *env,
@@ -430,12 +416,11 @@
 	struct lov_io	*lio = cl2lov_io(env, ios);
 	struct cl_io	 *io  = ios->cis_io;
 	struct lov_stripe_md *lsm = lio->lis_object->lo_lsm;
-	loff_t start = io->u.ci_rw.crw_pos;
+	__u64 start = io->u.ci_rw.crw_pos;
 	loff_t next;
 	unsigned long ssize = lsm->lsm_stripe_size;
 
 	LASSERT(io->ci_type == CIT_READ || io->ci_type == CIT_WRITE);
-	ENTRY;
 
 	/* fast path for common case. */
 	if (lio->lis_nr_subios != 1 && !cl_io_is_append(io)) {
@@ -458,7 +443,7 @@
 	 * XXX The following call should be optimized: we know, that
 	 * [lio->lis_pos, lio->lis_endpos) intersects with exactly one stripe.
 	 */
-	RETURN(lov_io_iter_init(env, ios));
+	return lov_io_iter_init(env, ios);
 }
 
 static int lov_io_call(const struct lu_env *env, struct lov_io *lio,
@@ -468,7 +453,6 @@
 	struct lov_io_sub *sub;
 	int rc = 0;
 
-	ENTRY;
 	list_for_each_entry(sub, &lio->lis_active, sub_linkage) {
 		lov_sub_enter(sub);
 		rc = iofunc(sub->sub_env, sub->sub_io);
@@ -479,24 +463,21 @@
 		if (parent->ci_result == 0)
 			parent->ci_result = sub->sub_io->ci_result;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_io_lock(const struct lu_env *env, const struct cl_io_slice *ios)
 {
-	ENTRY;
-	RETURN(lov_io_call(env, cl2lov_io(env, ios), cl_io_lock));
+	return lov_io_call(env, cl2lov_io(env, ios), cl_io_lock);
 }
 
 static int lov_io_start(const struct lu_env *env, const struct cl_io_slice *ios)
 {
-	ENTRY;
-	RETURN(lov_io_call(env, cl2lov_io(env, ios), cl_io_start));
+	return lov_io_call(env, cl2lov_io(env, ios), cl_io_start);
 }
 
 static int lov_io_end_wrapper(const struct lu_env *env, struct cl_io *io)
 {
-	ENTRY;
 	/*
 	 * It's possible that lov_io_start() wasn't called against this
 	 * sub-io, either because previous sub-io failed, or upper layer
@@ -506,19 +487,19 @@
 		cl_io_end(env, io);
 	else
 		io->ci_state = CIS_IO_FINISHED;
-	RETURN(0);
+	return 0;
 }
 
 static int lov_io_iter_fini_wrapper(const struct lu_env *env, struct cl_io *io)
 {
 	cl_io_iter_fini(env, io);
-	RETURN(0);
+	return 0;
 }
 
 static int lov_io_unlock_wrapper(const struct lu_env *env, struct cl_io *io)
 {
 	cl_io_unlock(env, io);
-	RETURN(0);
+	return 0;
 }
 
 static void lov_io_end(const struct lu_env *env, const struct cl_io_slice *ios)
@@ -535,12 +516,10 @@
 	struct lov_io *lio = cl2lov_io(env, ios);
 	int rc;
 
-	ENTRY;
 	rc = lov_io_call(env, lio, lov_io_iter_fini_wrapper);
 	LASSERT(rc == 0);
 	while (!list_empty(&lio->lis_active))
 		list_del_init(lio->lis_active.next);
-	EXIT;
 }
 
 static void lov_io_unlock(const struct lu_env *env,
@@ -548,10 +527,8 @@
 {
 	int rc;
 
-	ENTRY;
 	rc = lov_io_call(env, cl2lov_io(env, ios), lov_io_unlock_wrapper);
 	LASSERT(rc == 0);
-	EXIT;
 }
 
 
@@ -596,7 +573,7 @@
 	int rc = 0;
 	int alloc =
 		!(current->flags & PF_MEMALLOC);
-	ENTRY;
+
 	if (lio->lis_active_subios == 1) {
 		int idx = lio->lis_single_subio_index;
 		struct lov_io_sub *sub;
@@ -608,7 +585,7 @@
 		rc = cl_io_submit_rw(sub->sub_env, sub->sub_io,
 				     crt, queue);
 		lov_sub_put(sub);
-		RETURN(rc);
+		return rc;
 	}
 
 	LASSERT(lio->lis_subs != NULL);
@@ -616,7 +593,7 @@
 		OBD_ALLOC_LARGE(stripes_qin,
 				sizeof(*stripes_qin) * lio->lis_nr_subios);
 		if (stripes_qin == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		for (stripe = 0; stripe < lio->lis_nr_subios; stripe++)
 			cl_page_list_init(&stripes_qin[stripe]);
@@ -682,7 +659,7 @@
 		mutex_unlock(&ld->ld_mutex);
 	}
 
-	RETURN(rc);
+	return rc;
 #undef QIN
 }
 
@@ -696,7 +673,6 @@
 	struct lov_io_sub *sub;
 	int result;
 
-	ENTRY;
 	sub = lov_page_subio(env, lio, slice);
 	if (!IS_ERR(sub)) {
 		result = cl_io_prepare_write(sub->sub_env, sub->sub_io,
@@ -704,7 +680,7 @@
 		lov_sub_put(sub);
 	} else
 		result = PTR_ERR(sub);
-	RETURN(result);
+	return result;
 }
 
 static int lov_io_commit_write(const struct lu_env *env,
@@ -717,7 +693,6 @@
 	struct lov_io_sub *sub;
 	int result;
 
-	ENTRY;
 	sub = lov_page_subio(env, lio, slice);
 	if (!IS_ERR(sub)) {
 		result = cl_io_commit_write(sub->sub_env, sub->sub_io,
@@ -725,7 +700,7 @@
 		lov_sub_put(sub);
 	} else
 		result = PTR_ERR(sub);
-	RETURN(result);
+	return result;
 }
 
 static int lov_io_fault_start(const struct lu_env *env,
@@ -735,13 +710,12 @@
 	struct lov_io      *lio;
 	struct lov_io_sub  *sub;
 
-	ENTRY;
 	fio = &ios->cis_io->u.ci_fault;
 	lio = cl2lov_io(env, ios);
 	sub = lov_sub_get(env, lio, lov_page_stripe(fio->ft_page));
 	sub->sub_io->u.ci_fault.ft_nob = fio->ft_nob;
 	lov_sub_put(sub);
-	RETURN(lov_io_start(env, ios));
+	return lov_io_start(env, ios);
 }
 
 static void lov_io_fsync_end(const struct lu_env *env,
@@ -750,7 +724,6 @@
 	struct lov_io *lio = cl2lov_io(env, ios);
 	struct lov_io_sub *sub;
 	unsigned int *written = &ios->cis_io->u.ci_fsync.fi_nr_written;
-	ENTRY;
 
 	*written = 0;
 	list_for_each_entry(sub, &lio->lis_active, sub_linkage) {
@@ -763,7 +736,6 @@
 		if (subio->ci_result == 0)
 			*written += subio->u.ci_fsync.fi_nr_written;
 	}
-	RETURN_EXIT;
 }
 
 static const struct cl_io_operations lov_io_ops = {
@@ -839,11 +811,9 @@
 			      const struct cl_io_slice *ios)
 {
 	struct lov_object *lov = cl2lov(ios->cis_obj);
-	ENTRY;
 
 	if (atomic_dec_and_test(&lov->lo_active_ios))
 		wake_up_all(&lov->lo_waitq);
-	EXIT;
 }
 
 static void lov_empty_impossible(const struct lu_env *env,
@@ -913,7 +883,6 @@
 	struct lov_io       *lio = lov_env_io(env);
 	struct lov_object   *lov = cl2lov(obj);
 
-	ENTRY;
 	INIT_LIST_HEAD(&lio->lis_active);
 	lov_io_slice_init(lio, lov, io);
 	if (io->ci_result == 0) {
@@ -923,7 +892,7 @@
 			atomic_inc(&lov->lo_active_ios);
 		}
 	}
-	RETURN(io->ci_result);
+	return io->ci_result;
 }
 
 int lov_io_init_empty(const struct lu_env *env, struct cl_object *obj,
@@ -932,7 +901,6 @@
 	struct lov_object *lov = cl2lov(obj);
 	struct lov_io *lio = lov_env_io(env);
 	int result;
-	ENTRY;
 
 	lio->lis_object = lov;
 	switch (io->ci_type) {
@@ -961,7 +929,40 @@
 	}
 
 	io->ci_result = result < 0 ? result : 0;
-	RETURN(result != 0);
+	return result != 0;
 }
 
+int lov_io_init_released(const struct lu_env *env, struct cl_object *obj,
+			struct cl_io *io)
+{
+	struct lov_object *lov = cl2lov(obj);
+	struct lov_io *lio = lov_env_io(env);
+	int result;
+
+	LASSERT(lov->lo_lsm != NULL);
+	lio->lis_object = lov;
+
+	switch (io->ci_type) {
+	default:
+		LASSERTF(0, "invalid type %d\n", io->ci_type);
+	case CIT_MISC:
+	case CIT_FSYNC:
+		result = +1;
+		break;
+	case CIT_SETATTR:
+	case CIT_READ:
+	case CIT_WRITE:
+	case CIT_FAULT:
+		/* TODO: need to restore the file. */
+		result = -EBADF;
+		break;
+	}
+	if (result == 0) {
+		cl_io_slice_add(io, &lio->lis_cl, obj, &lov_empty_io_ops);
+		atomic_inc(&lov->lo_active_ios);
+	}
+
+	io->ci_result = result < 0 ? result : 0;
+	return result != 0;
+}
 /** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c
index bdf3334..ec297e8 100644
--- a/drivers/staging/lustre/lustre/lov/lov_lock.c
+++ b/drivers/staging/lustre/lustre/lov/lov_lock.c
@@ -110,7 +110,6 @@
 
 	LASSERT(cl_lock_is_mutexed(parent));
 	LASSERT(cl_lock_is_mutexed(sublock));
-	ENTRY;
 
 	lsl = cl2sub_lock(sublock);
 	/*
@@ -132,7 +131,6 @@
 
 	rc = lov_sublock_modify(env, lck, lsl, &sublock->cll_descr, idx);
 	LASSERT(rc == 0); /* there is no way this can fail, currently */
-	EXIT;
 }
 
 static struct cl_lock *lov_sublock_alloc(const struct lu_env *env,
@@ -145,7 +143,6 @@
 	struct lov_lock_link *link;
 
 	LASSERT(idx < lck->lls_nr);
-	ENTRY;
 
 	OBD_SLAB_ALLOC_PTR_GFP(link, lov_lock_link_kmem, __GFP_IO);
 	if (link != NULL) {
@@ -179,7 +176,7 @@
 			OBD_SLAB_FREE_PTR(link, lov_lock_link_kmem);
 	} else
 		sublock = ERR_PTR(-ENOMEM);
-	RETURN(sublock);
+	return sublock;
 }
 
 static void lov_sublock_unlock(const struct lu_env *env,
@@ -187,11 +184,9 @@
 			       struct cl_lock_closure *closure,
 			       struct lov_sublock_env *subenv)
 {
-	ENTRY;
 	lov_sublock_env_put(subenv);
 	lsl->lss_active = NULL;
 	cl_lock_disclosure(env, closure);
-	EXIT;
 }
 
 static int lov_sublock_lock(const struct lu_env *env,
@@ -203,7 +198,6 @@
 	struct lovsub_lock *sublock;
 	struct cl_lock     *child;
 	int		 result = 0;
-	ENTRY;
 
 	LASSERT(list_empty(&closure->clc_list));
 
@@ -243,7 +237,7 @@
 			}
 		}
 	}
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -267,8 +261,6 @@
 	int result_rank;
 	int rc_rank;
 
-	ENTRY;
-
 	LASSERTF(result <= 0 || result == CLO_REPEAT || result == CLO_WAIT,
 		 "result = %d", result);
 	LASSERTF(rc <= 0 || rc == CLO_REPEAT || rc == CLO_WAIT,
@@ -281,7 +273,7 @@
 
 	if (result_rank < rc_rank)
 		result = rc;
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -307,8 +299,6 @@
 	struct lov_layout_raid0 *r0     = lov_r0(loo);
 	struct cl_lock	  *parent = lck->lls_cl.cls_lock;
 
-	ENTRY;
-
 	lck->lls_orig = parent->cll_descr;
 	file_start = cl_offset(lov2cl(loo), parent->cll_descr.cld_start);
 	file_end   = cl_offset(lov2cl(loo), parent->cll_descr.cld_end + 1) - 1;
@@ -325,7 +315,7 @@
 	LASSERT(nr > 0);
 	OBD_ALLOC_LARGE(lck->lls_sub, nr * sizeof lck->lls_sub[0]);
 	if (lck->lls_sub == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	lck->lls_nr = nr;
 	/*
@@ -396,7 +386,7 @@
 	 * because enqueue will create them anyway. Main duty of this function
 	 * is to fill in sub-lock descriptions in a race free manner.
 	 */
-	RETURN(result);
+	return result;
 }
 
 static int lov_sublock_release(const struct lu_env *env, struct lov_lock *lck,
@@ -405,7 +395,6 @@
 	struct cl_lock *parent = lck->lls_cl.cls_lock;
 
 	LASSERT(cl_lock_is_mutexed(parent));
-	ENTRY;
 
 	if (lck->lls_sub[i].sub_flags & LSF_HELD) {
 		struct cl_lock    *sublock;
@@ -442,7 +431,7 @@
 		 * sub-lock is destroyed.
 		 */
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static void lov_sublock_hold(const struct lu_env *env, struct lov_lock *lck,
@@ -451,7 +440,6 @@
 	struct cl_lock *parent = lck->lls_cl.cls_lock;
 
 	LASSERT(cl_lock_is_mutexed(parent));
-	ENTRY;
 
 	if (!(lck->lls_sub[i].sub_flags & LSF_HELD)) {
 		struct cl_lock *sublock;
@@ -468,7 +456,6 @@
 		cl_lock_user_add(env, sublock);
 		cl_lock_put(env, sublock);
 	}
-	EXIT;
 }
 
 static void lov_lock_fini(const struct lu_env *env,
@@ -477,7 +464,6 @@
 	struct lov_lock *lck;
 	int i;
 
-	ENTRY;
 	lck = cl2lov_lock(slice);
 	LASSERT(lck->lls_nr_filled == 0);
 	if (lck->lls_sub != NULL) {
@@ -491,7 +477,6 @@
 			       lck->lls_nr * sizeof lck->lls_sub[0]);
 	}
 	OBD_SLAB_FREE_PTR(lck, lov_lock_kmem);
-	EXIT;
 }
 
 static int lov_lock_enqueue_wait(const struct lu_env *env,
@@ -500,14 +485,13 @@
 {
 	struct cl_lock *lock = lck->lls_cl.cls_lock;
 	int	     result;
-	ENTRY;
 
 	LASSERT(cl_lock_is_mutexed(lock));
 
 	cl_lock_mutex_put(env, lock);
 	result = cl_lock_enqueue_wait(env, sublock, 0);
 	cl_lock_mutex_get(env, lock);
-	RETURN(result ?: CLO_REPEAT);
+	return result ?: CLO_REPEAT;
 }
 
 /**
@@ -522,7 +506,6 @@
 				struct cl_io *io, __u32 enqflags, int last)
 {
 	int result;
-	ENTRY;
 
 	/* first, try to enqueue a sub-lock ... */
 	result = cl_enqueue_try(env, sublock, io, enqflags);
@@ -541,7 +524,7 @@
 	if ((result == CLO_WAIT) && (sublock->cll_state <= CLS_HELD) &&
 	    (enqflags & CEF_ASYNC) && (!last || (enqflags & CEF_AGL)))
 		result = 0;
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -600,8 +583,6 @@
 	int result;
 	enum cl_lock_state minstate;
 
-	ENTRY;
-
 	for (result = 0, minstate = CLS_FREEING, i = 0; i < lck->lls_nr; ++i) {
 		int rc;
 		struct lovsub_lock     *sub;
@@ -680,7 +661,7 @@
 			break;
 	}
 	cl_lock_closure_fini(closure);
-	RETURN(result ?: minstate >= CLS_ENQUEUED ? 0 : CLO_WAIT);
+	return result ?: minstate >= CLS_ENQUEUED ? 0 : CLO_WAIT;
 }
 
 static int lov_lock_unuse(const struct lu_env *env,
@@ -691,8 +672,6 @@
 	int i;
 	int result;
 
-	ENTRY;
-
 	for (result = 0, i = 0; i < lck->lls_nr; ++i) {
 		int rc;
 		struct lovsub_lock     *sub;
@@ -728,7 +707,7 @@
 		result = -ESTALE;
 	}
 	cl_lock_closure_fini(closure);
-	RETURN(result);
+	return result;
 }
 
 
@@ -740,8 +719,6 @@
 	int i;
 	int result;
 
-	ENTRY;
-
 	for (result = 0, i = 0; i < lck->lls_nr; ++i) {
 		int rc;
 		struct lovsub_lock     *sub;
@@ -802,8 +779,6 @@
 	int		     result;
 	int		     i;
 
-	ENTRY;
-
 again:
 	for (result = 0, minstate = CLS_FREEING, i = 0, reenqueued = 0;
 	     i < lck->lls_nr; ++i) {
@@ -839,7 +814,7 @@
 	if (result == 0 && reenqueued != 0)
 		goto again;
 	cl_lock_closure_fini(closure);
-	RETURN(result ?: minstate >= CLS_HELD ? 0 : CLO_WAIT);
+	return result ?: minstate >= CLS_HELD ? 0 : CLO_WAIT;
 }
 
 static int lov_lock_use(const struct lu_env *env,
@@ -851,7 +826,6 @@
 	int		     i;
 
 	LASSERT(slice->cls_lock->cll_state == CLS_INTRANSIT);
-	ENTRY;
 
 	for (result = 0, i = 0; i < lck->lls_nr; ++i) {
 		int rc;
@@ -908,7 +882,7 @@
 		result = -ESTALE;
 	}
 	cl_lock_closure_fini(closure);
-	RETURN(result);
+	return result;
 }
 
 #if 0
@@ -1016,8 +990,6 @@
 	LASSERT(cl_object_same(need->cld_obj, slice->cls_obj));
 	LASSERT(lov->lls_nr > 0);
 
-	ENTRY;
-
 	/* for top lock, it's necessary to match enq flags otherwise it will
 	 * run into problem if a sublock is missing and reenqueue. */
 	if (need->cld_enq_flags != lov->lls_orig.cld_enq_flags)
@@ -1055,7 +1027,7 @@
 	       PDESCR(&lov->lls_orig), PDESCR(&lov->lls_sub[0].sub_got),
 	       lov->lls_sub[0].sub_stripe, lov->lls_nr, lov_r0(obj)->lo_nr,
 	       result);
-	RETURN(result);
+	return result;
 }
 
 void lov_lock_unlink(const struct lu_env *env,
@@ -1066,7 +1038,6 @@
 
 	LASSERT(cl_lock_is_mutexed(parent));
 	LASSERT(cl_lock_is_mutexed(sub->lss_cl.cls_lock));
-	ENTRY;
 
 	list_del_init(&link->lll_list);
 	LASSERT(lck->lls_sub[link->lll_idx].sub_lock == sub);
@@ -1077,7 +1048,6 @@
 	lu_ref_del(&parent->cll_reference, "lov-child", sub->lss_cl.cls_lock);
 	cl_lock_put(env, parent);
 	OBD_SLAB_FREE_PTR(link, lov_lock_link_kmem);
-	EXIT;
 }
 
 struct lov_lock_link *lov_lock_link_find(const struct lu_env *env,
@@ -1087,13 +1057,12 @@
 	struct lov_lock_link *scan;
 
 	LASSERT(cl_lock_is_mutexed(sub->lss_cl.cls_lock));
-	ENTRY;
 
 	list_for_each_entry(scan, &sub->lss_parents, lll_list) {
 		if (scan->lll_super == lck)
-			RETURN(scan);
+			return scan;
 	}
-	RETURN(NULL);
+	return NULL;
 }
 
 /**
@@ -1120,7 +1089,6 @@
 	int		     i;
 
 	LASSERT(slice->cls_lock->cll_state == CLS_FREEING);
-	ENTRY;
 
 	for (i = 0; i < lck->lls_nr; ++i) {
 		struct lov_lock_sub *lls = &lck->lls_sub[i];
@@ -1150,7 +1118,6 @@
 	}
 
 	cl_lock_closure_fini(closure);
-	EXIT;
 }
 
 static int lov_lock_print(const struct lu_env *env, void *cookie,
@@ -1192,14 +1159,13 @@
 	struct lov_lock *lck;
 	int result;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, __GFP_IO);
 	if (lck != NULL) {
 		cl_lock_slice_add(lock, &lck->lls_cl, obj, &lov_lock_ops);
 		result = lov_lock_sub_init(env, lck, io);
 	} else
 		result = -ENOMEM;
-	RETURN(result);
+	return result;
 }
 
 static void lov_empty_lock_fini(const struct lu_env *env,
@@ -1228,14 +1194,13 @@
 	struct lov_lock *lck;
 	int result = -ENOMEM;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(lck, lov_lock_kmem, __GFP_IO);
 	if (lck != NULL) {
 		cl_lock_slice_add(lock, &lck->lls_cl, obj, &lov_empty_lock_ops);
 		lck->lls_orig = lock->cll_descr;
 		result = 0;
 	}
-	RETURN(result);
+	return result;
 }
 
 static struct cl_lock_closure *lov_closure_get(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/lov/lov_log.c b/drivers/staging/lustre/lustre/lov/lov_log.c
index 63b7f8d..3eedd93 100644
--- a/drivers/staging/lustre/lustre/lov/lov_log.c
+++ b/drivers/staging/lustre/lustre/lov/lov_log.c
@@ -71,7 +71,6 @@
 	struct obd_device *obd = ctxt->loc_obd;
 	struct lov_obd *lov = &obd->u.lov;
 	int i, rc = 0, cookies = 0;
-	ENTRY;
 
 	LASSERTF(logcookies && numcookies >= lsm->lsm_stripe_count,
 		 "logcookies %p, numcookies %d lsm->lsm_stripe_count %d \n",
@@ -118,7 +117,7 @@
 		/* Note that rc is always 1 if llog_obd_add was successful */
 		cookies += rc;
 	}
-	RETURN(cookies);
+	return cookies;
 }
 
 static int lov_llog_origin_connect(struct llog_ctxt *ctxt,
@@ -129,7 +128,6 @@
 	struct obd_device *obd = ctxt->loc_obd;
 	struct lov_obd *lov = &obd->u.lov;
 	int i, rc = 0, err = 0;
-	ENTRY;
 
 	obd_getref(obd);
 	for (i = 0; i < lov->desc.ld_tgt_count; i++) {
@@ -154,7 +152,7 @@
 	}
 	obd_putref(obd);
 
-	RETURN(err);
+	return err;
 }
 
 /* the replicators commit callback */
@@ -167,7 +165,6 @@
 	struct lov_obd *lov;
 	struct obd_device *obd = ctxt->loc_obd;
 	int rc = 0, i;
-	ENTRY;
 
 	LASSERT(lsm != NULL);
 	LASSERT(count == lsm->lsm_stripe_count);
@@ -194,7 +191,7 @@
 		}
 	}
 	obd_putref(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static struct llog_operations lov_mds_ost_orig_logops = {
@@ -212,13 +209,12 @@
 	struct lov_obd *lov = &obd->u.lov;
 	struct obd_device *child;
 	int i, rc = 0;
-	ENTRY;
 
 	LASSERT(olg == &obd->obd_olg);
 	rc = llog_setup(NULL, obd, olg, LLOG_MDS_OST_ORIG_CTXT, disk_obd,
 			&lov_mds_ost_orig_logops);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = llog_setup(NULL, obd, olg, LLOG_SIZE_REPL_CTXT, disk_obd,
 			&lov_size_repl_logops);
@@ -261,8 +257,6 @@
 {
 	struct llog_ctxt *ctxt;
 
-	ENTRY;
-
 	/* cleanup our llogs only if the ctxts have been setup
 	 * (client lov doesn't setup, mds lov does). */
 	ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
@@ -274,5 +268,5 @@
 		llog_cleanup(NULL, ctxt);
 
 	/* lov->tgt llogs are cleaned during osc_cleanup. */
-	RETURN(0);
+	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c
index ddbac12..d204fed 100644
--- a/drivers/staging/lustre/lustre/lov/lov_merge.c
+++ b/drivers/staging/lustre/lustre/lov/lov_merge.c
@@ -109,7 +109,7 @@
 	lvb->lvb_mtime = current_mtime;
 	lvb->lvb_atime = current_atime;
 	lvb->lvb_ctime = current_ctime;
-	RETURN(rc);
+	return rc;
 }
 
 /** Merge the lock value block(&lvb) attributes from each of the stripes in a
@@ -127,7 +127,6 @@
 	int   rc;
 	__u64 kms;
 
-	ENTRY;
 	lov_stripe_lock(lsm);
 	rc = lov_merge_lvb_kms(lsm, lvb, &kms);
 	lov_stripe_unlock(lsm);
@@ -137,7 +136,7 @@
 	CDEBUG(D_INODE, "merged for ID "DOSTID" s="LPU64" m="LPU64" a="LPU64
 	       " c="LPU64" b="LPU64"\n", POSTID(&lsm->lsm_oi), lvb->lvb_size,
 	       lvb->lvb_mtime, lvb->lvb_atime, lvb->lvb_ctime, lvb->lvb_blocks);
-	RETURN(rc);
+	return rc;
 }
 
 /* Must be called under the lov_stripe_lock() */
@@ -147,7 +146,6 @@
 	struct lov_oinfo *loi;
 	int stripe = 0;
 	__u64 kms;
-	ENTRY;
 
 	LASSERT(spin_is_locked(&lsm->lsm_lock));
 	LASSERT(lsm->lsm_lock_owner == current_pid());
@@ -162,7 +160,7 @@
 			       loi->loi_kms, kms);
 			loi_kms_set(loi, loi->loi_lvb.lvb_size = kms);
 		}
-		RETURN(0);
+		return 0;
 	}
 
 	if (size > 0)
@@ -175,7 +173,7 @@
 	if (kms > loi->loi_kms)
 		loi_kms_set(loi, kms);
 
-	RETURN(0);
+	return 0;
 }
 
 void lov_merge_attrs(struct obdo *tgt, struct obdo *src, obd_valid valid,
diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c
index ef7ff09..0b47aba 100644
--- a/drivers/staging/lustre/lustre/lov/lov_obd.c
+++ b/drivers/staging/lustre/lustre/lov/lov_obd.c
@@ -131,19 +131,18 @@
 	struct obd_device *tgt_obd;
 	static struct obd_uuid lov_osc_uuid = { "LOV_OSC_UUID" };
 	struct obd_import *imp;
-	proc_dir_entry_t *lov_proc_dir;
+	struct proc_dir_entry *lov_proc_dir;
 	int rc;
-	ENTRY;
 
 	if (!lov->lov_tgts[index])
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	tgt_uuid = &lov->lov_tgts[index]->ltd_uuid;
 	tgt_obd = lov->lov_tgts[index]->ltd_obd;
 
 	if (!tgt_obd->obd_set_up) {
 		CERROR("Target %s not set up\n", obd_uuid2str(tgt_uuid));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* override the sp_me from lov */
@@ -168,14 +167,14 @@
 	if (rc) {
 		CERROR("Target %s register_observer error %d\n",
 		       obd_uuid2str(tgt_uuid), rc);
-		RETURN(rc);
+		return rc;
 	}
 
 
 	if (imp->imp_invalid) {
 		CDEBUG(D_CONFIG, "not connecting OSC %s; administratively "
 		       "disabled\n", obd_uuid2str(tgt_uuid));
-		RETURN(0);
+		return 0;
 	}
 
 	rc = obd_connect(NULL, &lov->lov_tgts[index]->ltd_exp, tgt_obd,
@@ -183,7 +182,7 @@
 	if (rc || !lov->lov_tgts[index]->ltd_exp) {
 		CERROR("Target %s connect error %d\n",
 		       obd_uuid2str(tgt_uuid), rc);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	lov->lov_tgts[index]->ltd_reap = 0;
@@ -194,7 +193,7 @@
 	lov_proc_dir = obd->obd_proc_private;
 	if (lov_proc_dir) {
 		struct obd_device *osc_obd = lov->lov_tgts[index]->ltd_exp->exp_obd;
-		proc_dir_entry_t *osc_symlink;
+		struct proc_dir_entry *osc_symlink;
 
 		LASSERT(osc_obd != NULL);
 		LASSERT(osc_obd->obd_magic == OBD_DEVICE_MAGIC);
@@ -215,7 +214,7 @@
 		}
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static int lov_connect(const struct lu_env *env,
@@ -227,13 +226,12 @@
 	struct lov_tgt_desc *tgt;
 	struct lustre_handle conn;
 	int i, rc;
-	ENTRY;
 
 	CDEBUG(D_CONFIG, "connect #%d\n", lov->lov_connects);
 
 	rc = class_connect(&conn, obd, cluuid);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	*exp = class_conn2export(&conn);
 
@@ -270,16 +268,15 @@
 	}
 	obd_putref(obd);
 
-	RETURN(0);
+	return 0;
 }
 
 static int lov_disconnect_obd(struct obd_device *obd, struct lov_tgt_desc *tgt)
 {
-	proc_dir_entry_t *lov_proc_dir;
+	struct proc_dir_entry *lov_proc_dir;
 	struct lov_obd *lov = &obd->u.lov;
 	struct obd_device *osc_obd;
 	int rc;
-	ENTRY;
 
 	osc_obd = class_exp2obd(tgt->ltd_exp);
 	CDEBUG(D_CONFIG, "%s: disconnecting target %s\n",
@@ -315,7 +312,7 @@
 	}
 
 	tgt->ltd_exp = NULL;
-	RETURN(0);
+	return 0;
 }
 
 static int lov_disconnect(struct obd_export *exp)
@@ -323,7 +320,6 @@
 	struct obd_device *obd = class_exp2obd(exp);
 	struct lov_obd *lov = &obd->u.lov;
 	int i, rc;
-	ENTRY;
 
 	if (!lov->lov_tgts)
 		goto out;
@@ -350,7 +346,7 @@
 
 out:
 	rc = class_disconnect(exp); /* bz 9811 */
-	RETURN(rc);
+	return rc;
 }
 
 /* Error codes:
@@ -366,7 +362,6 @@
 	struct lov_obd *lov = &obd->u.lov;
 	struct lov_tgt_desc *tgt;
 	int index, activate, active;
-	ENTRY;
 
 	CDEBUG(D_INFO, "Searching in lov %p for uuid %s event(%d)\n",
 	       lov, uuid->uuid, ev);
@@ -438,7 +433,7 @@
 
  out:
 	obd_putref(obd);
-	RETURN(index);
+	return index;
 }
 
 static int lov_notify(struct obd_device *obd, struct obd_device *watched,
@@ -446,12 +441,11 @@
 {
 	int rc = 0;
 	struct lov_obd *lov = &obd->u.lov;
-	ENTRY;
 
 	down_read(&lov->lov_notify_lock);
 	if (!lov->lov_connects) {
 		up_read(&lov->lov_notify_lock);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (ev == OBD_NOTIFY_ACTIVE || ev == OBD_NOTIFY_INACTIVE ||
@@ -465,7 +459,7 @@
 			CERROR("unexpected notification of %s %s!\n",
 			       watched->obd_type->typ_name,
 			       watched->obd_name);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		uuid = &watched->u.cli.cl_target_uuid;
 
@@ -477,7 +471,7 @@
 			up_read(&lov->lov_notify_lock);
 			CERROR("event(%d) of %s failed: %d\n", ev,
 			       obd_uuid2str(uuid), rc);
-			RETURN(rc);
+			return rc;
 		}
 		/* active event should be pass lov target index as data */
 		data = &rc;
@@ -520,7 +514,7 @@
 	}
 
 	up_read(&lov->lov_notify_lock);
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_add_target(struct obd_device *obd, struct obd_uuid *uuidp,
@@ -530,7 +524,6 @@
 	struct lov_tgt_desc *tgt;
 	struct obd_device *tgt_obd;
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_CONFIG, "uuid:%s idx:%d gen:%d active:%d\n",
 	       uuidp->uuid, index, gen, active);
@@ -538,13 +531,13 @@
 	if (gen <= 0) {
 		CERROR("request to add OBD %s with invalid generation: %d\n",
 		       uuidp->uuid, gen);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	tgt_obd = class_find_client_obd(uuidp, LUSTRE_OSC_NAME,
 					&obd->obd_uuid);
 	if (tgt_obd == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	mutex_lock(&lov->lov_lock);
 
@@ -553,7 +546,7 @@
 		CERROR("UUID %s already assigned at LOV target index %d\n",
 		       obd_uuid2str(&tgt->ltd_uuid), index);
 		mutex_unlock(&lov->lov_lock);
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 
 	if (index >= lov->lov_tgt_size) {
@@ -567,7 +560,7 @@
 		OBD_ALLOC(newtgts, sizeof(*newtgts) * newsize);
 		if (newtgts == NULL) {
 			mutex_unlock(&lov->lov_lock);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 
 		if (lov->lov_tgt_size) {
@@ -590,14 +583,14 @@
 	OBD_ALLOC_PTR(tgt);
 	if (!tgt) {
 		mutex_unlock(&lov->lov_lock);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	rc = lov_ost_pool_add(&lov->lov_packed, index, lov->lov_tgt_size);
 	if (rc) {
 		mutex_unlock(&lov->lov_lock);
 		OBD_FREE_PTR(tgt);
-		RETURN(rc);
+		return rc;
 	}
 
 	tgt->ltd_uuid = *uuidp;
@@ -621,7 +614,7 @@
 		/* lov_connect hasn't been called yet. We'll do the
 		   lov_connect_obd on this target when that fn first runs,
 		   because we don't know the connect flags yet. */
-		RETURN(0);
+		return 0;
 	}
 
 	obd_getref(obd);
@@ -654,7 +647,7 @@
 		lov_del_target(obd, index, 0, 0);
 	}
 	obd_putref(obd);
-	RETURN(rc);
+	return rc;
 }
 
 /* Schedule a target for deletion */
@@ -664,12 +657,11 @@
 	struct lov_obd *lov = &obd->u.lov;
 	int count = lov->desc.ld_tgt_count;
 	int rc = 0;
-	ENTRY;
 
 	if (index >= count) {
 		CERROR("LOV target index %d >= number of LOV OBDs %d.\n",
 		       index, count);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* to make sure there's no ongoing lov_notify() now */
@@ -700,7 +692,7 @@
 	obd_putref(obd);
 	up_write(&lov->lov_notify_lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 static void __lov_del_obd(struct obd_device *obd, struct lov_tgt_desc *tgt)
@@ -780,11 +772,10 @@
 	struct lov_desc *desc;
 	struct lov_obd *lov = &obd->u.lov;
 	int rc;
-	ENTRY;
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
 		CERROR("LOV setup requires a descriptor\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	desc = (struct lov_desc *)lustre_cfg_buf(lcfg, 1);
@@ -792,7 +783,7 @@
 	if (sizeof(*desc) > LUSTRE_CFG_BUFLEN(lcfg, 1)) {
 		CERROR("descriptor size wrong: %d > %d\n",
 		       (int)sizeof(*desc), LUSTRE_CFG_BUFLEN(lcfg, 1));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (desc->ld_magic != LOV_DESC_MAGIC) {
@@ -803,7 +794,7 @@
 		} else {
 			CERROR("%s: Bad lov desc magic: %#x\n",
 			       obd->obd_name, desc->ld_magic);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	}
 
@@ -836,11 +827,11 @@
 	lprocfs_obd_setup(obd, lvars.obd_vars);
 #ifdef LPROCFS
 	{
-		int rc;
+		int rc1;
 
-		rc = lprocfs_seq_create(obd->obd_proc_entry, "target_obd",
+		rc1 = lprocfs_seq_create(obd->obd_proc_entry, "target_obd",
 					0444, &lov_proc_target_fops, obd);
-		if (rc)
+		if (rc1)
 			CWARN("Error adding the target_obd file\n");
 	}
 #endif
@@ -848,7 +839,7 @@
 						    obd->obd_proc_entry,
 						    NULL, NULL);
 
-	RETURN(0);
+	return 0;
 
 out:
 	return rc;
@@ -859,8 +850,6 @@
 	int rc = 0;
 	struct lov_obd *lov = &obd->u.lov;
 
-	ENTRY;
-
 	switch (stage) {
 	case OBD_CLEANUP_EARLY: {
 		int i;
@@ -878,7 +867,7 @@
 			CERROR("failed to cleanup llogging subsystems\n");
 		break;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_cleanup(struct obd_device *obd)
@@ -886,7 +875,6 @@
 	struct lov_obd *lov = &obd->u.lov;
 	struct list_head *pos, *tmp;
 	struct pool_desc *pool;
-	ENTRY;
 
 	list_for_each_safe(pos, tmp, &lov->lov_pool_list) {
 		pool = list_entry(pos, struct pool_desc, pool_list);
@@ -925,7 +913,7 @@
 			 lov->lov_tgt_size);
 		lov->lov_tgt_size = 0;
 	}
-	RETURN(0);
+	return 0;
 }
 
 int lov_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg,
@@ -934,7 +922,6 @@
 	struct obd_uuid obd_uuid;
 	int cmd;
 	int rc = 0;
-	ENTRY;
 
 	switch(cmd = lcfg->lcfg_command) {
 	case LCFG_LOV_ADD_OBD:
@@ -990,7 +977,7 @@
 	}
 	}
 out:
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_recreate(struct obd_export *exp, struct obdo *src_oa,
@@ -1000,14 +987,13 @@
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	unsigned ost_idx;
 	int rc, i;
-	ENTRY;
 
 	LASSERT(src_oa->o_valid & OBD_MD_FLFLAGS &&
 		src_oa->o_flags & OBD_FL_RECREATE_OBJS);
 
 	OBD_ALLOC(obj_mdp, sizeof(*obj_mdp));
 	if (obj_mdp == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	ost_idx = src_oa->o_nlink;
 	lsm = *ea;
@@ -1032,7 +1018,7 @@
 			src_oa, &obj_mdp, oti);
 out:
 	OBD_FREE(obj_mdp, sizeof(*obj_mdp));
-	RETURN(rc);
+	return rc;
 }
 
 /* the LOV expects oa->o_id to be set to the LOV object id */
@@ -1042,11 +1028,10 @@
 {
 	struct lov_obd *lov;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(ea != NULL);
 	if (exp == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if ((src_oa->o_valid & OBD_MD_FLFLAGS) &&
 	    src_oa->o_flags == OBD_FL_DELORPHAN) {
@@ -1056,7 +1041,7 @@
 
 	lov = &exp->exp_obd->u.lov;
 	if (!lov->desc.ld_active_tgt_count)
-		RETURN(-EIO);
+		return -EIO;
 
 	obd_getref(exp->exp_obd);
 	/* Recreate a specific object id at the given OST index */
@@ -1066,7 +1051,7 @@
 	}
 
 	obd_putref(exp->exp_obd);
-	RETURN(rc);
+	return rc;
 }
 
 #define ASSERT_LSM_MAGIC(lsmp)						  \
@@ -1088,12 +1073,11 @@
 	struct list_head *pos;
 	struct lov_obd *lov;
 	int rc = 0, err = 0;
-	ENTRY;
 
 	ASSERT_LSM_MAGIC(lsm);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	if (oa->o_valid & OBD_MD_FLCOOKIE) {
 		LASSERT(oti);
@@ -1133,7 +1117,7 @@
 	err = lov_fini_destroy_set(set);
 out:
 	obd_putref(exp->exp_obd);
-	RETURN(rc ? rc : err);
+	return rc ? rc : err;
 }
 
 static int lov_getattr(const struct lu_env *env, struct obd_export *exp,
@@ -1144,19 +1128,18 @@
 	struct list_head *pos;
 	struct lov_obd *lov;
 	int err = 0, rc = 0;
-	ENTRY;
 
 	LASSERT(oinfo);
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 
 	rc = lov_prep_getattr_set(exp, oinfo, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each (pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -1182,7 +1165,7 @@
 	rc = lov_fini_getattr_set(set);
 	if (err)
 		rc = err;
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_getattr_interpret(struct ptlrpc_request_set *rqset,
@@ -1190,13 +1173,12 @@
 {
 	struct lov_request_set *lovset = (struct lov_request_set *)data;
 	int err;
-	ENTRY;
 
 	/* don't do attribute merge if this aysnc op failed */
 	if (rc)
 		atomic_set(&lovset->set_completes, 0);
 	err = lov_fini_getattr_set(lovset);
-	RETURN(rc ? rc : err);
+	return rc ? rc : err;
 }
 
 static int lov_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -1207,19 +1189,18 @@
 	struct list_head *pos;
 	struct lov_request *req;
 	int rc = 0, err;
-	ENTRY;
 
 	LASSERT(oinfo);
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 
 	rc = lov_prep_getattr_set(exp, oinfo, &lovset);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INFO, "objid "DOSTID": %ux%u byte stripes\n",
 	       POSTID(&oinfo->oi_md->lsm_oi), oinfo->oi_md->lsm_stripe_count,
@@ -1249,13 +1230,13 @@
 		LASSERT (rqset->set_interpret == NULL);
 		rqset->set_interpret = lov_getattr_interpret;
 		rqset->set_arg = (void *)lovset;
-		RETURN(rc);
+		return rc;
 	}
 out:
 	if (rc)
 		atomic_set(&lovset->set_completes, 0);
 	err = lov_fini_getattr_set(lovset);
-	RETURN(rc ? rc : err);
+	return rc ? rc : err;
 }
 
 static int lov_setattr(const struct lu_env *env, struct obd_export *exp,
@@ -1266,13 +1247,12 @@
 	struct list_head *pos;
 	struct lov_request *req;
 	int err = 0, rc = 0;
-	ENTRY;
 
 	LASSERT(oinfo);
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	/* for now, we only expect the following updates here */
 	LASSERT(!(oinfo->oi_oa->o_valid & ~(OBD_MD_FLID | OBD_MD_FLTYPE |
@@ -1285,7 +1265,7 @@
 	lov = &exp->exp_obd->u.lov;
 	rc = lov_prep_setattr_set(exp, oinfo, oti, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each (pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -1307,7 +1287,7 @@
 	err = lov_fini_setattr_set(set);
 	if (!rc)
 		rc = err;
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_setattr_interpret(struct ptlrpc_request_set *rqset,
@@ -1315,12 +1295,11 @@
 {
 	struct lov_request_set *lovset = (struct lov_request_set *)data;
 	int err;
-	ENTRY;
 
 	if (rc)
 		atomic_set(&lovset->set_completes, 0);
 	err = lov_fini_setattr_set(lovset);
-	RETURN(rc ? rc : err);
+	return rc ? rc : err;
 }
 
 /* If @oti is given, the request goes from MDS and responses from OSTs are not
@@ -1334,7 +1313,6 @@
 	struct list_head *pos;
 	struct lov_obd *lov;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(oinfo);
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
@@ -1344,12 +1322,12 @@
 	}
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	rc = lov_prep_setattr_set(exp, oinfo, oti, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INFO, "objid "DOSTID": %ux%u byte stripes\n",
 	       POSTID(&oinfo->oi_md->lsm_oi),
@@ -1384,14 +1362,14 @@
 		if (rc)
 			atomic_set(&set->set_completes, 0);
 		err = lov_fini_setattr_set(set);
-		RETURN(rc ? rc : err);
+		return rc ? rc : err;
 	}
 
 	LASSERT(rqset->set_interpret == NULL);
 	rqset->set_interpret = lov_setattr_interpret;
 	rqset->set_arg = (void *)set;
 
-	RETURN(0);
+	return 0;
 }
 
 static int lov_punch_interpret(struct ptlrpc_request_set *rqset,
@@ -1399,12 +1377,11 @@
 {
 	struct lov_request_set *lovset = (struct lov_request_set *)data;
 	int err;
-	ENTRY;
 
 	if (rc)
 		atomic_set(&lovset->set_completes, 0);
 	err = lov_fini_punch_set(lovset);
-	RETURN(rc ? rc : err);
+	return rc ? rc : err;
 }
 
 /* FIXME: maybe we'll just make one node the authoritative attribute node, then
@@ -1419,18 +1396,17 @@
 	struct list_head *pos;
 	struct lov_request *req;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(oinfo);
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	rc = lov_prep_punch_set(exp, oinfo, oti, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each (pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -1450,14 +1426,14 @@
 	if (rc || list_empty(&rqset->set_requests)) {
 		int err;
 		err = lov_fini_punch_set(set);
-		RETURN(rc ? rc : err);
+		return rc ? rc : err;
 	}
 
 	LASSERT(rqset->set_interpret == NULL);
 	rqset->set_interpret = lov_punch_interpret;
 	rqset->set_arg = (void *)set;
 
-	RETURN(0);
+	return 0;
 }
 
 static int lov_sync_interpret(struct ptlrpc_request_set *rqset,
@@ -1465,12 +1441,11 @@
 {
 	struct lov_request_set *lovset = data;
 	int err;
-	ENTRY;
 
 	if (rc)
 		atomic_set(&lovset->set_completes, 0);
 	err = lov_fini_sync_set(lovset);
-	RETURN(rc ?: err);
+	return rc ?: err;
 }
 
 static int lov_sync(const struct lu_env *env, struct obd_export *exp,
@@ -1482,18 +1457,17 @@
 	struct list_head *pos;
 	struct lov_request *req;
 	int rc = 0;
-	ENTRY;
 
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
 	LASSERT(rqset != NULL);
 
 	if (!exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	rc = lov_prep_sync_set(exp, oinfo, start, end, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_INFO, "fsync objid "DOSTID" ["LPX64", "LPX64"]\n",
 	       POSTID(&set->set_oi->oi_oa->o_oi), start, end);
@@ -1519,14 +1493,14 @@
 	if (rc || list_empty(&rqset->set_requests)) {
 		int err = lov_fini_sync_set(set);
 
-		RETURN(rc ?: err);
+		return rc ?: err;
 	}
 
 	LASSERT(rqset->set_interpret == NULL);
 	rqset->set_interpret = lov_sync_interpret;
 	rqset->set_arg = (void *)set;
 
-	RETURN(0);
+	return 0;
 }
 
 static int lov_brw_check(struct lov_obd *lov, struct obd_info *lov_oinfo,
@@ -1571,18 +1545,17 @@
 	struct list_head *pos;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int err, rc = 0;
-	ENTRY;
 
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
 
 	if (cmd == OBD_BRW_CHECK) {
 		rc = lov_brw_check(lov, oinfo, oa_bufs, pga);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = lov_prep_brw_set(exp, oinfo, oa_bufs, pga, oti, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each (pos, &set->set_list) {
 		struct obd_export *sub_exp;
@@ -1601,16 +1574,16 @@
 	err = lov_fini_brw_set(set);
 	if (!rc)
 		rc = err;
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_enqueue_interpret(struct ptlrpc_request_set *rqset,
 				 void *data, int rc)
 {
 	struct lov_request_set *lovset = (struct lov_request_set *)data;
-	ENTRY;
+
 	rc = lov_fini_enqueue_set(lovset, lovset->set_ei->ei_mode, rc, rqset);
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_enqueue(struct obd_export *exp, struct obd_info *oinfo,
@@ -1623,7 +1596,6 @@
 	struct list_head *pos;
 	struct lov_obd *lov;
 	ldlm_error_t rc;
-	ENTRY;
 
 	LASSERT(oinfo);
 	ASSERT_LSM_MAGIC(oinfo->oi_md);
@@ -1633,12 +1605,12 @@
 	LASSERT((oinfo->oi_flags & LDLM_FL_REPLAY) == 0);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	rc = lov_prep_enqueue_set(exp, oinfo, einfo, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each (pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -1654,11 +1626,11 @@
 		LASSERT(rqset->set_interpret == NULL);
 		rqset->set_interpret = lov_enqueue_interpret;
 		rqset->set_arg = (void *)set;
-		RETURN(rc);
+		return rc;
 	}
 out:
 	rc = lov_fini_enqueue_set(set, mode, rc, rqset);
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_change_cbdata(struct obd_export *exp,
@@ -1667,12 +1639,11 @@
 {
 	struct lov_obd *lov;
 	int rc = 0, i;
-	ENTRY;
 
 	ASSERT_LSM_MAGIC(lsm);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	for (i = 0; i < lsm->lsm_stripe_count; i++) {
@@ -1689,7 +1660,7 @@
 		rc = obd_change_cbdata(lov->lov_tgts[loi->loi_ost_idx]->ltd_exp,
 				       &submd, it, data);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /* find any ldlm lock of the inode in lov
@@ -1702,12 +1673,11 @@
 {
 	struct lov_obd *lov;
 	int rc = 0, i;
-	ENTRY;
 
 	ASSERT_LSM_MAGIC(lsm);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	for (i = 0; i < lsm->lsm_stripe_count; i++) {
@@ -1723,9 +1693,9 @@
 		rc = obd_find_cbdata(lov->lov_tgts[loi->loi_ost_idx]->ltd_exp,
 				     &submd, it, data);
 		if (rc != 0)
-			RETURN(rc);
+			return rc;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_cancel(struct obd_export *exp, struct lov_stripe_md *lsm,
@@ -1738,18 +1708,17 @@
 	struct lov_obd *lov;
 	struct lustre_handle *lov_lockhp;
 	int err = 0, rc = 0;
-	ENTRY;
 
 	ASSERT_LSM_MAGIC(lsm);
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	LASSERT(lockh);
 	lov = &exp->exp_obd->u.lov;
 	rc = lov_prep_cancel_set(exp, &oinfo, lsm, mode, lockh, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each(pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -1769,7 +1738,7 @@
 
 	}
 	lov_fini_cancel_set(set);
-	RETURN(err);
+	return err;
 }
 
 static int lov_cancel_unused(struct obd_export *exp,
@@ -1778,10 +1747,9 @@
 {
 	struct lov_obd *lov;
 	int rc = 0, i;
-	ENTRY;
 
 	if (!exp || !exp->exp_obd)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	lov = &exp->exp_obd->u.lov;
 	if (lsm == NULL) {
@@ -1795,7 +1763,7 @@
 			if (!rc)
 				rc = err;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	ASSERT_LSM_MAGIC(lsm);
@@ -1827,20 +1795,19 @@
 				rc = err;
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int lov_statfs_interpret(struct ptlrpc_request_set *rqset, void *data, int rc)
 {
 	struct lov_request_set *lovset = (struct lov_request_set *)data;
 	int err;
-	ENTRY;
 
 	if (rc)
 		atomic_set(&lovset->set_completes, 0);
 
 	err = lov_fini_statfs_set(lovset);
-	RETURN(rc ? rc : err);
+	return rc ? rc : err;
 }
 
 static int lov_statfs_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -1852,7 +1819,6 @@
 	struct list_head *pos;
 	struct lov_obd *lov;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(oinfo != NULL);
 	LASSERT(oinfo->oi_osfs != NULL);
@@ -1860,7 +1826,7 @@
 	lov = &obd->u.lov;
 	rc = lov_prep_statfs_set(obd, oinfo, &set);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each (pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -1875,13 +1841,13 @@
 		if (rc)
 			atomic_set(&set->set_completes, 0);
 		err = lov_fini_statfs_set(set);
-		RETURN(rc ? rc : err);
+		return rc ? rc : err;
 	}
 
 	LASSERT(rqset->set_interpret == NULL);
 	rqset->set_interpret = lov_statfs_interpret;
 	rqset->set_arg = (void *)set;
-	RETURN(0);
+	return 0;
 }
 
 static int lov_statfs(const struct lu_env *env, struct obd_export *exp,
@@ -1890,14 +1856,12 @@
 	struct ptlrpc_request_set *set = NULL;
 	struct obd_info oinfo = { { { 0 } } };
 	int rc = 0;
-	ENTRY;
-
 
 	/* for obdclass we forbid using obd_statfs_rqset, but prefer using async
 	 * statfs requests */
 	set = ptlrpc_prep_set();
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	oinfo.oi_osfs = osfs;
 	oinfo.oi_flags = flags;
@@ -1906,7 +1870,7 @@
 		rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
@@ -1916,7 +1880,6 @@
 	struct lov_obd *lov = &obddev->u.lov;
 	int i = 0, rc = 0, count = lov->desc.ld_tgt_count;
 	struct obd_uuid *uuidp;
-	ENTRY;
 
 	switch (cmd) {
 	case IOC_OBD_STATFS: {
@@ -1928,23 +1891,23 @@
 
 		memcpy(&index, data->ioc_inlbuf2, sizeof(__u32));
 		if ((index >= count))
-			RETURN(-ENODEV);
+			return -ENODEV;
 
 		if (!lov->lov_tgts[index])
 			/* Try again with the next index */
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 		if (!lov->lov_tgts[index]->ltd_active)
-			RETURN(-ENODATA);
+			return -ENODATA;
 
 		osc_obd = class_exp2obd(lov->lov_tgts[index]->ltd_exp);
 		if (!osc_obd)
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		/* copy UUID */
 		if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(osc_obd),
 				     min((int) data->ioc_plen2,
 					 (int) sizeof(struct obd_uuid))))
-			RETURN(-EFAULT);
+			return -EFAULT;
 
 		flags = uarg ? *(__u32*)uarg : 0;
 		/* got statfs data */
@@ -1952,11 +1915,11 @@
 				cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS),
 				flags);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		if (copy_to_user(data->ioc_pbuf1, &stat_buf,
 				     min((int) data->ioc_plen1,
 					 (int) sizeof(stat_buf))))
-			RETURN(-EFAULT);
+			return -EFAULT;
 		break;
 	}
 	case OBD_IOC_LOV_GET_CONFIG: {
@@ -1967,23 +1930,23 @@
 
 		len = 0;
 		if (obd_ioctl_getdata(&buf, &len, (void *)uarg))
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		data = (struct obd_ioctl_data *)buf;
 
 		if (sizeof(*desc) > data->ioc_inllen1) {
 			obd_ioctl_freedata(buf, len);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (sizeof(uuidp->uuid) * count > data->ioc_inllen2) {
 			obd_ioctl_freedata(buf, len);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (sizeof(__u32) * count > data->ioc_inllen3) {
 			obd_ioctl_freedata(buf, len);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		desc = (struct lov_desc *)data->ioc_inlbuf1;
@@ -2020,11 +1983,11 @@
 
 		if (qctl->qc_valid == QC_OSTIDX) {
 			if (qctl->qc_idx < 0 || count <= qctl->qc_idx)
-				RETURN(-EINVAL);
+				return -EINVAL;
 
 			tgt = lov->lov_tgts[qctl->qc_idx];
 			if (!tgt || !tgt->ltd_exp)
-				RETURN(-EINVAL);
+				return -EINVAL;
 		} else if (qctl->qc_valid == QC_UUID) {
 			for (i = 0; i < count; i++) {
 				tgt = lov->lov_tgts[i];
@@ -2034,21 +1997,21 @@
 					continue;
 
 				if (tgt->ltd_exp == NULL)
-					RETURN(-EINVAL);
+					return -EINVAL;
 
 				break;
 			}
 		} else {
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (i >= count)
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 
 		LASSERT(tgt && tgt->ltd_exp);
 		OBD_ALLOC_PTR(oqctl);
 		if (!oqctl)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		QCTL_COPY(oqctl, qctl);
 		rc = obd_quotactl(tgt->ltd_exp, oqctl);
@@ -2064,7 +2027,7 @@
 		int set = 0;
 
 		if (count == 0)
-			RETURN(-ENOTTY);
+			return -ENOTTY;
 
 		for (i = 0; i < count; i++) {
 			int err;
@@ -2081,7 +2044,7 @@
 			err = obd_iocontrol(cmd, lov->lov_tgts[i]->ltd_exp,
 					    len, karg, uarg);
 			if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
-				RETURN(err);
+				return err;
 			} else if (err) {
 				if (lov->lov_tgts[i]->ltd_active) {
 					CDEBUG(err == -ENOTTY ?
@@ -2102,7 +2065,7 @@
 	}
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 #define FIEMAP_BUFFER_SIZE 4096
@@ -2259,7 +2222,7 @@
 	int cur_stripe = 0, cur_stripe_wrap = 0, stripe_count;
 	unsigned int buffer_size = FIEMAP_BUFFER_SIZE;
 
-	if (lsm == NULL)
+	if (!lsm_has_objects(lsm))
 		GOTO(out, rc = 0);
 
 	if (fiemap_count_to_size(fm_key->fiemap.fm_extent_count) < buffer_size)
@@ -2469,10 +2432,9 @@
 	struct obd_device *obddev = class_exp2obd(exp);
 	struct lov_obd *lov = &obddev->u.lov;
 	int i, rc;
-	ENTRY;
 
 	if (!vallen || !val)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	obd_getref(obddev);
 
@@ -2553,7 +2515,7 @@
 
 out:
 	obd_putref(obddev);
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -2568,14 +2530,13 @@
 	unsigned incr, check_uuid,
 		 do_inactive, no_set;
 	unsigned next_id = 0,  mds_con = 0, capa = 0;
-	ENTRY;
 
 	incr = check_uuid = do_inactive = no_set = 0;
 	if (set == NULL) {
 		no_set = 1;
 		set = ptlrpc_prep_set();
 		if (!set)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 	}
 
 	obd_getref(obddev);
@@ -2667,7 +2628,7 @@
 			rc = err;
 		ptlrpc_set_destroy(set);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_extent_calc(struct obd_export *exp, struct lov_stripe_md *lsm,
@@ -2691,7 +2652,7 @@
 		LBUG();
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 void lov_stripe_lock(struct lov_stripe_md *md)
@@ -2719,7 +2680,6 @@
 	__u64		curspace = 0;
 	__u64		bhardlimit = 0;
 	int		  i, rc = 0;
-	ENTRY;
 
 	if (oqctl->qc_cmd != LUSTRE_Q_QUOTAON &&
 	    oqctl->qc_cmd != LUSTRE_Q_QUOTAOFF &&
@@ -2728,7 +2688,7 @@
 	    oqctl->qc_cmd != LUSTRE_Q_SETQUOTA &&
 	    oqctl->qc_cmd != Q_FINVALIDATE) {
 		CERROR("bad quota opc %x for lov obd", oqctl->qc_cmd);
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 
 	/* for lov tgt */
@@ -2770,7 +2730,7 @@
 		oqctl->qc_dqblk.dqb_curspace = curspace;
 		oqctl->qc_dqblk.dqb_bhardlimit = bhardlimit;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_quotacheck(struct obd_device *obd, struct obd_export *exp,
@@ -2778,7 +2738,6 @@
 {
 	struct lov_obd *lov = &obd->u.lov;
 	int	     i, rc = 0;
-	ENTRY;
 
 	obd_getref(obd);
 
@@ -2814,7 +2773,7 @@
 out:
 	obd_putref(obd);
 
-	RETURN(rc);
+	return rc;
 }
 
 struct obd_ops lov_obd_ops = {
@@ -2870,7 +2829,6 @@
 {
 	struct lprocfs_static_vars lvars = { 0 };
 	int rc;
-	ENTRY;
 
 	/* print an address of _any_ initialized kernel symbol from this
 	 * module, to allow debugging with gdb that doesn't support data
@@ -2898,7 +2856,7 @@
 		lu_kmem_fini(lov_caches);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static void /*__exit*/ lov_exit(void)
@@ -2912,5 +2870,7 @@
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Lustre Logical Object Volume OBD driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
 
-cfs_module(lov, LUSTRE_VERSION_STRING, lov_init, lov_exit);
+module_init(lov_init);
+module_exit(lov_exit);
diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c
index aa8ae80..84e55ce 100644
--- a/drivers/staging/lustre/lustre/lov/lov_object.c
+++ b/drivers/staging/lustre/lustre/lov/lov_object.c
@@ -116,10 +116,9 @@
 {
 	struct lu_object *o;
 
-	ENTRY;
 	o = lu_object_find_at(env, cl2lu_dev(dev), fid, &conf->coc_lu);
 	LASSERT(ergo(!IS_ERR(o), o->lo_dev->ld_type == &lovsub_device_type));
-	RETURN(lu2cl(o));
+	return lu2cl(o);
 }
 
 static int lov_init_sub(const struct lu_env *env, struct lov_object *lov,
@@ -204,8 +203,6 @@
 	struct lu_fid	   *ofid    = &lti->lti_fid;
 	struct lov_layout_raid0 *r0      = &state->raid0;
 
-	ENTRY;
-
 	if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3) {
 		dump_lsm(D_ERROR, lsm);
 		LASSERTF(0, "magic mismatch, expected %d/%d, actual %d.\n",
@@ -255,13 +252,28 @@
 	} else
 		result = -ENOMEM;
 out:
-	RETURN(result);
+	return result;
+}
+
+static int lov_init_released(const struct lu_env *env,
+			struct lov_device *dev, struct lov_object *lov,
+			const struct cl_object_conf *conf,
+			union  lov_layout_state *state)
+{
+	struct lov_stripe_md *lsm = conf->u.coc_md->lsm;
+
+	LASSERT(lsm != NULL);
+	LASSERT(lsm_is_released(lsm));
+	LASSERT(lov->lo_lsm == NULL);
+
+	lov->lo_lsm = lsm_addref(lsm);
+	return 0;
 }
 
 static int lov_delete_empty(const struct lu_env *env, struct lov_object *lov,
 			    union lov_layout_state *state)
 {
-	LASSERT(lov->lo_type == LLT_EMPTY);
+	LASSERT(lov->lo_type == LLT_EMPTY || lov->lo_type == LLT_RELEASED);
 
 	lov_layout_wait(env, lov);
 
@@ -323,8 +335,6 @@
 	struct lov_stripe_md    *lsm = lov->lo_lsm;
 	int i;
 
-	ENTRY;
-
 	dump_lsm(D_INODE, lsm);
 
 	lov_layout_wait(env, lov);
@@ -343,20 +353,19 @@
 		}
 	}
 	cl_object_prune(env, &lov->lo_cl);
-	RETURN(0);
+	return 0;
 }
 
 static void lov_fini_empty(const struct lu_env *env, struct lov_object *lov,
 			   union lov_layout_state *state)
 {
-	LASSERT(lov->lo_type == LLT_EMPTY);
+	LASSERT(lov->lo_type == LLT_EMPTY || lov->lo_type == LLT_RELEASED);
 }
 
 static void lov_fini_raid0(const struct lu_env *env, struct lov_object *lov,
 			   union lov_layout_state *state)
 {
 	struct lov_layout_raid0 *r0 = &state->raid0;
-	ENTRY;
 
 	if (r0->lo_sub != NULL) {
 		OBD_FREE_LARGE(r0->lo_sub, r0->lo_nr * sizeof r0->lo_sub[0]);
@@ -365,8 +374,13 @@
 
 	dump_lsm(D_INODE, lov->lo_lsm);
 	lov_free_memmd(&lov->lo_lsm);
+}
 
-	EXIT;
+static void lov_fini_released(const struct lu_env *env, struct lov_object *lov,
+				union lov_layout_state *state)
+{
+	dump_lsm(D_INODE, lov->lo_lsm);
+	lov_free_memmd(&lov->lo_lsm);
 }
 
 static int lov_print_empty(const struct lu_env *env, void *cookie,
@@ -400,6 +414,13 @@
 	return 0;
 }
 
+static int lov_print_released(const struct lu_env *env, void *cookie,
+				lu_printer_t p, const struct lu_object *o)
+{
+	(*p)(env, cookie, "released\n");
+	return 0;
+}
+
 /**
  * Implements cl_object_operations::coo_attr_get() method for an object
  * without stripes (LLT_EMPTY layout type).
@@ -422,8 +443,6 @@
 	struct cl_attr		*lov_attr = &r0->lo_attr;
 	int			 result = 0;
 
-	ENTRY;
-
 	/* this is called w/o holding type guard mutex, so it must be inside
 	 * an on going IO otherwise lsm may be replaced.
 	 * LU-2117: it turns out there exists one exception. For mmaped files,
@@ -478,7 +497,7 @@
 		if (attr->cat_mtime < lov_attr->cat_mtime)
 			attr->cat_mtime = lov_attr->cat_mtime;
 	}
-	RETURN(result);
+	return result;
 }
 
 const static struct lov_layout_operations lov_dispatch[] = {
@@ -503,10 +522,20 @@
 		.llo_lock_init = lov_lock_init_raid0,
 		.llo_io_init   = lov_io_init_raid0,
 		.llo_getattr   = lov_attr_get_raid0
+	},
+	[LLT_RELEASED] = {
+		.llo_init      = lov_init_released,
+		.llo_delete    = lov_delete_empty,
+		.llo_fini      = lov_fini_released,
+		.llo_install   = lov_install_empty,
+		.llo_print     = lov_print_released,
+		.llo_page_init = lov_page_init_empty,
+		.llo_lock_init = lov_lock_init_empty,
+		.llo_io_init   = lov_io_init_released,
+		.llo_getattr   = lov_attr_get_empty
 	}
 };
 
-
 /**
  * Performs a double-dispatch based on the layout type of an object.
  */
@@ -520,6 +549,18 @@
 	lov_dispatch[__llt].op(__VA_ARGS__);			    \
 })
 
+/**
+ * Return lov_layout_type associated with a given lsm
+ */
+enum lov_layout_type lov_type(struct lov_stripe_md *lsm)
+{
+	if (lsm == NULL)
+		return LLT_EMPTY;
+	if (lsm_is_released(lsm))
+		return LLT_RELEASED;
+	return LLT_RAID0;
+}
+
 static inline void lov_conf_freeze(struct lov_object *lov)
 {
 	if (lov->lo_owner != current)
@@ -581,7 +622,6 @@
 static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov)
 {
 	struct l_wait_info lwi = { 0 };
-	ENTRY;
 
 	while (atomic_read(&lov->lo_active_ios) > 0) {
 		CDEBUG(D_INODE, "file:"DFID" wait for active IO, now: %d.\n",
@@ -591,7 +631,7 @@
 		l_wait_event(lov->lo_waitq,
 			     atomic_read(&lov->lo_active_ios) == 0, &lwi);
 	}
-	RETURN(0);
+	return 0;
 }
 
 static int lov_layout_change(const struct lu_env *unused,
@@ -608,19 +648,18 @@
 	void *cookie;
 	struct lu_env *env;
 	int refcheck;
-	ENTRY;
 
 	LASSERT(0 <= lov->lo_type && lov->lo_type < ARRAY_SIZE(lov_dispatch));
 
-	if (conf->u.coc_md != NULL && conf->u.coc_md->lsm != NULL)
-		llt = LLT_RAID0; /* only raid0 is supported. */
+	if (conf->u.coc_md != NULL)
+		llt = lov_type(conf->u.coc_md->lsm);
 	LASSERT(0 <= llt && llt < ARRAY_SIZE(lov_dispatch));
 
 	cookie = cl_env_reenter();
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env)) {
 		cl_env_reexit(cookie);
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 	}
 
 	old_ops = &lov_dispatch[lov->lo_type];
@@ -650,7 +689,7 @@
 
 	cl_env_put(env, &refcheck);
 	cl_env_reexit(cookie);
-	RETURN(result);
+	return result;
 }
 
 /*****************************************************************************
@@ -658,7 +697,6 @@
  * Lov object operations.
  *
  */
-
 int lov_object_init(const struct lu_env *env, struct lu_object *obj,
 		    const struct lu_object_conf *conf)
 {
@@ -669,7 +707,6 @@
 	const struct lov_layout_operations *ops;
 	int result;
 
-	ENTRY;
 	init_rwsem(&lov->lo_type_guard);
 	atomic_set(&lov->lo_active_ios, 0);
 	init_waitqueue_head(&lov->lo_waitq);
@@ -677,21 +714,20 @@
 	cl_object_page_init(lu2cl(obj), sizeof(struct lov_page));
 
 	/* no locking is necessary, as object is being created */
-	lov->lo_type = cconf->u.coc_md->lsm != NULL ? LLT_RAID0 : LLT_EMPTY;
+	lov->lo_type = lov_type(cconf->u.coc_md->lsm);
 	ops = &lov_dispatch[lov->lo_type];
 	result = ops->llo_init(env, dev, lov, cconf, set);
 	if (result == 0)
 		ops->llo_install(env, lov, set);
-	RETURN(result);
+	return result;
 }
 
 static int lov_conf_set(const struct lu_env *env, struct cl_object *obj,
 			const struct cl_object_conf *conf)
 {
-	struct lov_stripe_md *lsm = NULL;
-	struct lov_object *lov = cl2lov(obj);
-	int result = 0;
-	ENTRY;
+	struct lov_stripe_md	*lsm = NULL;
+	struct lov_object	*lov = cl2lov(obj);
+	int			 result = 0;
 
 	lov_conf_lock(lov);
 	if (conf->coc_opc == OBJECT_CONF_INVALIDATE) {
@@ -728,31 +764,26 @@
 	}
 
 	lov->lo_layout_invalid = lov_layout_change(env, lov, conf);
-	EXIT;
 
 out:
 	lov_conf_unlock(lov);
-	RETURN(result);
+	return result;
 }
 
 static void lov_object_delete(const struct lu_env *env, struct lu_object *obj)
 {
 	struct lov_object *lov = lu2lov(obj);
 
-	ENTRY;
 	LOV_2DISPATCH_VOID(lov, llo_delete, env, lov, &lov->u);
-	EXIT;
 }
 
 static void lov_object_free(const struct lu_env *env, struct lu_object *obj)
 {
 	struct lov_object *lov = lu2lov(obj);
 
-	ENTRY;
 	LOV_2DISPATCH_VOID(lov, llo_fini, env, lov, &lov->u);
 	lu_object_fini(obj);
 	OBD_SLAB_FREE_PTR(lov, lov_object_kmem);
-	EXIT;
 }
 
 static int lov_object_print(const struct lu_env *env, void *cookie,
@@ -835,7 +866,6 @@
 	struct lov_object *lov;
 	struct lu_object  *obj;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(lov, lov_object_kmem, __GFP_IO);
 	if (lov != NULL) {
 		obj = lov2lu(lov);
@@ -850,7 +880,7 @@
 		obj->lo_ops = &lov_lu_obj_ops;
 	} else
 		obj = NULL;
-	RETURN(obj);
+	return obj;
 }
 
 struct lov_stripe_md *lov_lsm_addref(struct lov_object *lov)
@@ -906,7 +936,6 @@
 {
 	struct lu_object *luobj;
 	int rc = 0;
-	ENTRY;
 
 	luobj = lu_object_locate(&cl_object_header(clob)->coh_lu,
 				 &lov_device_type);
@@ -928,6 +957,7 @@
 				loi->loi_ar.ar_rc = 0;
 			}
 		}
+		case LLT_RELEASED:
 		case LLT_EMPTY:
 			break;
 		default:
@@ -935,7 +965,7 @@
 		}
 		lov_conf_thaw(lov);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(lov_read_and_clear_async_rc);
 
diff --git a/drivers/staging/lustre/lustre/lov/lov_offset.c b/drivers/staging/lustre/lustre/lov/lov_offset.c
index f62b7e5..04863a7 100644
--- a/drivers/staging/lustre/lustre/lov/lov_offset.c
+++ b/drivers/staging/lustre/lustre/lov/lov_offset.c
@@ -52,10 +52,9 @@
 	obd_off swidth;
 	obd_size lov_size;
 	int magic = lsm->lsm_magic;
-	ENTRY;
 
 	if (ost_size == 0)
-		RETURN(0);
+		return 0;
 
 	LASSERT(lsm_op_find(magic) != NULL);
 	lsm_op_find(magic)->lsm_stripe_by_index(lsm, &stripeno, NULL, &swidth);
@@ -67,7 +66,7 @@
 	else
 		lov_size = (ost_size - 1) * swidth + (stripeno + 1) * ssize;
 
-	RETURN(lov_size);
+	return lov_size;
 }
 
 /* we have an offset in file backed by an lov and want to find out where
diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c
index 492948a..55ec267 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pack.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pack.c
@@ -143,7 +143,6 @@
 	int lmm_size, lmm_magic;
 	int i;
 	int cplen = 0;
-	ENTRY;
 
 	if (lsm) {
 		lmm_magic = lsm->lsm_magic;
@@ -159,7 +158,7 @@
 	    (lmm_magic != LOV_MAGIC_V3)) {
 		CERROR("bad mem LOV MAGIC: 0x%08X != 0x%08X nor 0x%08X\n",
 			lmm_magic, LOV_MAGIC_V1, LOV_MAGIC_V3);
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	}
 
@@ -168,10 +167,12 @@
 		 * to the actual number of OSTs in this filesystem. */
 		if (!lmmp) {
 			stripe_count = lov_get_stripecnt(lov, lmm_magic,
-							 lsm->lsm_stripe_count);
+							lsm->lsm_stripe_count);
 			lsm->lsm_stripe_count = stripe_count;
-		} else {
+		} else if (!lsm_is_released(lsm)) {
 			stripe_count = lsm->lsm_stripe_count;
+		} else {
+			stripe_count = 0;
 		}
 	} else {
 		/* No need to allocate more than maximum supported stripes.
@@ -188,20 +189,20 @@
 	lmm_size = lov_mds_md_size(stripe_count, lmm_magic);
 
 	if (!lmmp)
-		RETURN(lmm_size);
+		return lmm_size;
 
 	if (*lmmp && !lsm) {
 		stripe_count = le16_to_cpu((*lmmp)->lmm_stripe_count);
 		lmm_size = lov_mds_md_size(stripe_count, lmm_magic);
 		OBD_FREE_LARGE(*lmmp, lmm_size);
 		*lmmp = NULL;
-		RETURN(0);
+		return 0;
 	}
 
 	if (!*lmmp) {
 		OBD_ALLOC_LARGE(*lmmp, lmm_size);
 		if (!*lmmp)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 	}
 
 	CDEBUG(D_INFO, "lov_packmd: LOV_MAGIC 0x%08X, lmm_size = %d \n",
@@ -215,7 +216,7 @@
 		lmmv1->lmm_magic = cpu_to_le32(LOV_MAGIC_V1);
 
 	if (!lsm)
-		RETURN(lmm_size);
+		return lmm_size;
 
 	/* lmmv1 and lmmv3 point to the same struct and have the
 	 * same first fields
@@ -229,7 +230,7 @@
 		cplen = strlcpy(lmmv3->lmm_pool_name, lsm->lsm_pool_name,
 				sizeof(lmmv3->lmm_pool_name));
 		if (cplen >= sizeof(lmmv3->lmm_pool_name))
-			RETURN(-E2BIG);
+			return -E2BIG;
 		lmm_objects = lmmv3->lmm_objects;
 	} else {
 		lmm_objects = lmmv1->lmm_objects;
@@ -246,7 +247,7 @@
 		lmm_objects[i].l_ost_idx = cpu_to_le32(loi->loi_ost_idx);
 	}
 
-	RETURN(lmm_size);
+	return lmm_size;
 }
 
 /* Find the max stripecount we should use */
@@ -307,14 +308,13 @@
 		    int pattern, int magic)
 {
 	int i, lsm_size;
-	ENTRY;
 
 	CDEBUG(D_INFO, "alloc lsm, stripe_count %d\n", stripe_count);
 
 	*lsmp = lsm_alloc_plain(stripe_count, &lsm_size);
 	if (!*lsmp) {
 		CERROR("can't allocate lsmp stripe_count %d\n", stripe_count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	atomic_set(&(*lsmp)->lsm_refc, 1);
@@ -325,12 +325,13 @@
 	(*lsmp)->lsm_pattern = pattern;
 	(*lsmp)->lsm_pool_name[0] = '\0';
 	(*lsmp)->lsm_layout_gen = 0;
-	(*lsmp)->lsm_oinfo[0]->loi_ost_idx = ~0;
+	if (stripe_count > 0)
+		(*lsmp)->lsm_oinfo[0]->loi_ost_idx = ~0;
 
 	for (i = 0; i < stripe_count; i++)
 		loi_init((*lsmp)->lsm_oinfo[i]);
 
-	RETURN(lsm_size);
+	return lsm_size;
 }
 
 int lov_free_memmd(struct lov_stripe_md **lsmp)
@@ -359,13 +360,13 @@
 	int rc = 0, lsm_size;
 	__u16 stripe_count;
 	__u32 magic;
-	ENTRY;
+	__u32 pattern;
 
 	/* If passed an MDS struct use values from there, otherwise defaults */
 	if (lmm) {
 		rc = lov_verify_lmm(lmm, lmm_bytes, &stripe_count);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		magic = le32_to_cpu(lmm->lmm_magic);
 	} else {
 		magic = LOV_MAGIC;
@@ -376,31 +377,31 @@
 	if (!lsmp) {
 		/* XXX LOV STACKING call into osc for sizes */
 		LBUG();
-		RETURN(lov_stripe_md_size(stripe_count));
+		return lov_stripe_md_size(stripe_count);
 	}
 	/* If we are passed an allocated struct but nothing to unpack, free */
 	if (*lsmp && !lmm) {
 		lov_free_memmd(lsmp);
-		RETURN(0);
+		return 0;
 	}
 
-	lsm_size = lov_alloc_memmd(lsmp, stripe_count, LOV_PATTERN_RAID0,
-				   magic);
+	pattern = le32_to_cpu(lmm->lmm_pattern);
+	lsm_size = lov_alloc_memmd(lsmp, stripe_count, pattern, magic);
 	if (lsm_size < 0)
-		RETURN(lsm_size);
+		return lsm_size;
 
 	/* If we are passed a pointer but nothing to unpack, we only alloc */
 	if (!lmm)
-		RETURN(lsm_size);
+		return lsm_size;
 
 	LASSERT(lsm_op_find(magic) != NULL);
 	rc = lsm_op_find(magic)->lsm_unpackmd(lov, *lsmp, lmm);
 	if (rc) {
 		lov_free_memmd(lsmp);
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(lsm_size);
+	return lsm_size;
 }
 
 static int __lov_setstripe(struct obd_export *exp, int max_lmm_size,
@@ -416,11 +417,10 @@
 	__u16 stripe_count;
 	int rc;
 	int cplen = 0;
-	ENTRY;
 
 	rc = lov_lum_swab_if_needed(lumv3, &lmm_magic, lump);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	/* in the rest of the tests, as *lumv1 and lumv3 have the same
 	 * fields, we use lumv1 to avoid code duplication */
@@ -430,10 +430,10 @@
 			lov->desc.ld_pattern : LOV_PATTERN_RAID0;
 	}
 
-	if (lumv1->lmm_pattern != LOV_PATTERN_RAID0) {
+	if (lov_pattern(lumv1->lmm_pattern) != LOV_PATTERN_RAID0) {
 		CDEBUG(D_IOCTL, "bad userland stripe pattern: %#x\n",
 		       lumv1->lmm_pattern);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* 64kB is the largest common page size we see (ia64), and matches the
@@ -449,7 +449,7 @@
 	     (typeof(lumv1->lmm_stripe_offset))(-1))) {
 		CDEBUG(D_IOCTL, "stripe offset %u > number of OSTs %u\n",
 		       lumv1->lmm_stripe_offset, lov->desc.ld_tgt_count);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	stripe_count = lov_get_stripecnt(lov, lmm_magic,
 					 lumv1->lmm_stripe_count);
@@ -479,7 +479,7 @@
 					lumv3->lmm_stripe_offset, pool);
 				if (rc < 0) {
 					lov_pool_putref(pool);
-					RETURN(-EINVAL);
+					return -EINVAL;
 				}
 			}
 
@@ -490,6 +490,9 @@
 		}
 	}
 
+	if (lumv1->lmm_pattern & LOV_PATTERN_F_RELEASED)
+		stripe_count = 0;
+
 	rc = lov_alloc_memmd(lsmp, stripe_count, lumv1->lmm_pattern, lmm_magic);
 
 	if (rc >= 0) {
@@ -505,7 +508,7 @@
 		rc = 0;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Configure object striping information on a new file.
@@ -526,7 +529,7 @@
 
 	rc = __lov_setstripe(exp, max_lmm_size, lsmp, lump);
 	set_fs(seg);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_setea(struct obd_export *exp, struct lov_stripe_md **lsmp,
@@ -539,8 +542,6 @@
 	obd_id last_id = 0;
 	struct lov_user_ost_data_v1 *lmm_objects;
 
-	ENTRY;
-
 	if (lump->lmm_magic == LOV_USER_MAGIC_V3)
 		lmm_objects = ((struct lov_user_md_v3 *)lump)->lmm_objects;
 	else
@@ -552,26 +553,26 @@
 		rc = obd_get_info(NULL, oexp, sizeof(KEY_LAST_ID), KEY_LAST_ID,
 				  &len, &last_id, NULL);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		if (ostid_id(&lmm_objects[i].l_ost_oi) > last_id) {
 			CERROR("Setting EA for object > than last id on"
 			       " ost idx %d "DOSTID" > "LPD64" \n",
 			       lmm_objects[i].l_ost_idx,
 			       POSTID(&lmm_objects[i].l_ost_oi), last_id);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	}
 
 	rc = lov_setstripe(exp, 0, lsmp, lump);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	for (i = 0; i < lump->lmm_stripe_count; i++) {
 		(*lsmp)->lsm_oinfo[i]->loi_ost_idx =
 			lmm_objects[i].l_ost_idx;
 		(*lsmp)->lsm_oinfo[i]->loi_oi = lmm_objects[i].l_ost_oi;
 	}
-	RETURN(0);
+	return 0;
 }
 
 
@@ -593,10 +594,9 @@
 	int rc, lmm_size;
 	int lum_size;
 	mm_segment_t seg;
-	ENTRY;
 
 	if (!lsm)
-		RETURN(-ENODATA);
+		return -ENODATA;
 
 	/*
 	 * "Switch to kernel segment" to allow copying from kernel space by
@@ -674,5 +674,5 @@
 	obd_free_diskmd(exp, &lmmk);
 out_set:
 	set_fs(seg);
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/lov/lov_page.c b/drivers/staging/lustre/lustre/lov/lov_page.c
index 65790d68..674e617 100644
--- a/drivers/staging/lustre/lustre/lov/lov_page.c
+++ b/drivers/staging/lustre/lustre/lov/lov_page.c
@@ -69,7 +69,6 @@
 	struct cl_page  *sub = lov_sub_page(slice);
 
 	LINVRNT(lov_page_invariant(slice));
-	ENTRY;
 
 	if (sub != NULL) {
 		LASSERT(sub->cp_state == CPS_FREEING);
@@ -78,7 +77,6 @@
 		slice->cpl_page->cp_child = NULL;
 		cl_page_put(env, sub);
 	}
-	EXIT;
 }
 
 static int lov_page_own(const struct lu_env *env,
@@ -90,7 +88,6 @@
 
 	LINVRNT(lov_page_invariant(slice));
 	LINVRNT(!cl2lov_page(slice)->lps_invalid);
-	ENTRY;
 
 	sub = lov_page_subio(env, lio, slice);
 	if (!IS_ERR(sub)) {
@@ -98,7 +95,7 @@
 		lov_sub_put(sub);
 	} else
 		LBUG(); /* Arrgh */
-	RETURN(0);
+	return 0;
 }
 
 static void lov_page_assume(const struct lu_env *env,
@@ -117,7 +114,6 @@
 
 	LINVRNT(lov_page_invariant(slice));
 	LINVRNT(!cl2lov_page(slice)->lps_invalid);
-	ENTRY;
 
 	sub = lov_page_subio(env, lio, slice);
 	if (!IS_ERR(sub)) {
@@ -128,7 +124,7 @@
 		rc = PTR_ERR(sub);
 		CL_PAGE_DEBUG(D_ERROR, env, slice->cpl_page, "rc = %d\n", rc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int lov_page_print(const struct lu_env *env,
@@ -172,7 +168,6 @@
 	obd_off	    suboff;
 	int		stripe;
 	int		rc;
-	ENTRY;
 
 	offset = cl_offset(obj, page->cp_index);
 	stripe = lov_stripe_number(loo->lo_lsm, offset);
@@ -205,7 +200,6 @@
 		LASSERT(0);
 	}
 
-	EXIT;
 out:
 	return rc;
 }
@@ -221,14 +215,13 @@
 {
 	struct lov_page *lpg = cl_object_page_slice(obj, page);
 	void *addr;
-	ENTRY;
 
 	cl_page_slice_add(page, &lpg->lps_cl, obj, &lov_empty_page_ops);
 	addr = kmap(vmpage);
 	memset(addr, 0, cl_page_size(obj));
 	kunmap(vmpage);
 	cl_page_export(env, page, 1);
-	RETURN(0);
+	return 0;
 }
 
 
diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c
index a96f908..dd3c07d 100644
--- a/drivers/staging/lustre/lustre/lov/lov_pool.c
+++ b/drivers/staging/lustre/lustre/lov/lov_pool.c
@@ -68,7 +68,6 @@
 		lov_ost_pool_free(&(pool->pool_rr.lqr_pool));
 		lov_ost_pool_free(&(pool->pool_obds));
 		OBD_FREE_PTR(pool);
-		EXIT;
 	}
 }
 
@@ -322,8 +321,6 @@
 #define LOV_POOL_INIT_COUNT 2
 int lov_ost_pool_init(struct ost_pool *op, unsigned int count)
 {
-	ENTRY;
-
 	if (count == 0)
 		count = LOV_POOL_INIT_COUNT;
 	op->op_array = NULL;
@@ -333,9 +330,8 @@
 	OBD_ALLOC(op->op_array, op->op_size * sizeof(op->op_array[0]));
 	if (op->op_array == NULL) {
 		op->op_size = 0;
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
-	EXIT;
 	return 0;
 }
 
@@ -366,7 +362,6 @@
 int lov_ost_pool_add(struct ost_pool *op, __u32 idx, unsigned int min_count)
 {
 	int rc = 0, i;
-	ENTRY;
 
 	down_write(&op->op_rw_sem);
 
@@ -382,7 +377,6 @@
 	/* ost not found we add it */
 	op->op_array[op->op_count] = idx;
 	op->op_count++;
-	EXIT;
 out:
 	up_write(&op->op_rw_sem);
 	return rc;
@@ -391,7 +385,6 @@
 int lov_ost_pool_remove(struct ost_pool *op, __u32 idx)
 {
 	int i;
-	ENTRY;
 
 	down_write(&op->op_rw_sem);
 
@@ -401,21 +394,18 @@
 				(op->op_count - i - 1) * sizeof(op->op_array[0]));
 			op->op_count--;
 			up_write(&op->op_rw_sem);
-			EXIT;
 			return 0;
 		}
 	}
 
 	up_write(&op->op_rw_sem);
-	RETURN(-EINVAL);
+	return -EINVAL;
 }
 
 int lov_ost_pool_free(struct ost_pool *op)
 {
-	ENTRY;
-
 	if (op->op_size == 0)
-		RETURN(0);
+		return 0;
 
 	down_write(&op->op_rw_sem);
 
@@ -425,7 +415,7 @@
 	op->op_size = 0;
 
 	up_write(&op->op_rw_sem);
-	RETURN(0);
+	return 0;
 }
 
 
@@ -434,16 +424,15 @@
 	struct lov_obd *lov;
 	struct pool_desc *new_pool;
 	int rc;
-	ENTRY;
 
 	lov = &(obd->u.lov);
 
 	if (strlen(poolname) > LOV_MAXPOOLNAME)
-		RETURN(-ENAMETOOLONG);
+		return -ENAMETOOLONG;
 
 	OBD_ALLOC_PTR(new_pool);
 	if (new_pool == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	strncpy(new_pool->pool_name, poolname, LOV_MAXPOOLNAME);
 	new_pool->pool_name[LOV_MAXPOOLNAME] = '\0';
@@ -492,7 +481,7 @@
 	CDEBUG(D_CONFIG, LOV_POOLNAMEF" is pool #%d\n",
 	       poolname, lov->lov_pool_count);
 
-	RETURN(0);
+	return 0;
 
 out_err:
 	spin_lock(&obd->obd_dev_lock);
@@ -513,14 +502,13 @@
 {
 	struct lov_obd *lov;
 	struct pool_desc *pool;
-	ENTRY;
 
 	lov = &(obd->u.lov);
 
 	/* lookup and kill hash reference */
 	pool = cfs_hash_del_key(lov->lov_pools_hash_body, poolname);
 	if (pool == NULL)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	if (pool->pool_proc_entry != NULL) {
 		CDEBUG(D_INFO, "proc entry %p\n", pool->pool_proc_entry);
@@ -536,7 +524,7 @@
 	/* release last reference */
 	lov_pool_putref(pool);
 
-	RETURN(0);
+	return 0;
 }
 
 
@@ -547,13 +535,12 @@
 	struct pool_desc *pool;
 	unsigned int lov_idx;
 	int rc;
-	ENTRY;
 
 	lov = &(obd->u.lov);
 
 	pool = cfs_hash_lookup(lov->lov_pools_hash_body, poolname);
 	if (pool == NULL)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	obd_str2uuid(&ost_uuid, ostname);
 
@@ -580,7 +567,6 @@
 	CDEBUG(D_CONFIG, "Added %s to "LOV_POOLNAMEF" as member %d\n",
 	       ostname, poolname,  pool_tgt_count(pool));
 
-	EXIT;
 out:
 	obd_putref(obd);
 	lov_pool_putref(pool);
@@ -594,13 +580,12 @@
 	struct pool_desc *pool;
 	unsigned int lov_idx;
 	int rc = 0;
-	ENTRY;
 
 	lov = &(obd->u.lov);
 
 	pool = cfs_hash_lookup(lov->lov_pools_hash_body, poolname);
 	if (pool == NULL)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	obd_str2uuid(&ost_uuid, ostname);
 
@@ -626,7 +611,6 @@
 	CDEBUG(D_CONFIG, "%s removed from "LOV_POOLNAMEF"\n", ostname,
 	       poolname);
 
-	EXIT;
 out:
 	obd_putref(obd);
 	lov_pool_putref(pool);
@@ -636,7 +620,6 @@
 int lov_check_index_in_pool(__u32 idx, struct pool_desc *pool)
 {
 	int i, rc;
-	ENTRY;
 
 	/* caller may no have a ref on pool if it got the pool
 	 * without calling lov_find_pool() (e.g. go through the lov pool
@@ -651,7 +634,6 @@
 			GOTO(out, rc = 0);
 	}
 	rc = -ENOENT;
-	EXIT;
 out:
 	up_read(&pool_tgt_rw_sem(pool));
 
diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c
index 13f1637..61e6d0b 100644
--- a/drivers/staging/lustre/lustre/lov/lov_request.c
+++ b/drivers/staging/lustre/lustre/lov/lov_request.c
@@ -60,7 +60,6 @@
 void lov_finish_set(struct lov_request_set *set)
 {
 	struct list_head *pos, *n;
-	ENTRY;
 
 	LASSERT(set);
 	list_for_each_safe(pos, n, &set->set_list) {
@@ -87,7 +86,6 @@
 		lov_llh_put(set->set_lockh);
 
 	OBD_FREE(set, sizeof(*set));
-	EXIT;
 }
 
 int lov_set_finished(struct lov_request_set *set, int idempotent)
@@ -122,7 +120,6 @@
 			  struct lov_request *req, int rc)
 {
 	struct lov_obd *lov = &set->set_exp->exp_obd->u.lov;
-	ENTRY;
 
 	lov_update_set(set, req, rc);
 
@@ -132,7 +129,7 @@
 		rc = 0;
 
 	/* FIXME in raid1 regime, should return 0 */
-	RETURN(rc);
+	return rc;
 }
 
 void lov_set_add_req(struct lov_request *req, struct lov_request_set *set)
@@ -232,7 +229,6 @@
 	struct lustre_handle *lov_lockhp;
 	struct obd_info *oi = set->set_oi;
 	struct lov_oinfo *loi;
-	ENTRY;
 
 	LASSERT(oi != NULL);
 
@@ -254,7 +250,7 @@
 				    req->rq_idx, &oi->oi_md->lsm_oi, rc);
 	lov_stripe_unlock(oi->oi_md);
 	lov_update_set(set, req, rc);
-	RETURN(rc);
+	return rc;
 }
 
 /* The callback for osc_enqueue that updates lov info for every OSC request. */
@@ -275,11 +271,10 @@
 	struct lov_obd *lov = &set->set_exp->exp_obd->u.lov;
 	int completes = atomic_read(&set->set_completes);
 	int rc = 0;
-	ENTRY;
 
 	/* enqueue/match success, just return */
 	if (completes && completes == atomic_read(&set->set_success))
-		RETURN(0);
+		return 0;
 
 	/* cancel enqueued/matched locks */
 	list_for_each_entry(req, &set->set_list, rq_link) {
@@ -305,17 +300,16 @@
 	}
 	if (set->set_lockh)
 		lov_llh_put(set->set_lockh);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_enqueue_set(struct lov_request_set *set, __u32 mode, int rc,
 			 struct ptlrpc_request_set *rqset)
 {
 	int ret = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	/* Do enqueue_done only for sync requests and if any request
 	 * succeeded. */
@@ -328,7 +322,7 @@
 
 	lov_put_reqset(set);
 
-	RETURN(rc ? rc : ret);
+	return rc ? rc : ret;
 }
 
 static void lov_llh_addref(void *llhp)
@@ -369,11 +363,10 @@
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	struct lov_request_set *set;
 	int i, rc = 0;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -445,19 +438,18 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(0);
+	return 0;
 out_set:
 	lov_fini_enqueue_set(set, einfo->ei_mode, rc, NULL);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_match_set(struct lov_request_set *set, __u32 mode, int flags)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	rc = enqueue_done(set, mode);
 	if ((set->set_count == atomic_read(&set->set_success)) &&
@@ -466,7 +458,7 @@
 
 	lov_put_reqset(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 int lov_prep_match_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -477,11 +469,10 @@
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	struct lov_request_set *set;
 	int i, rc = 0;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -535,19 +526,18 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_match_set(set, mode, 0);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_cancel_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 
 	LASSERT(set->set_exp);
 	if (set->set_lockh)
@@ -555,7 +545,7 @@
 
 	lov_put_reqset(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 int lov_prep_cancel_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -565,11 +555,10 @@
 {
 	struct lov_request_set *set;
 	int i, rc = 0;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -617,10 +606,10 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_cancel_set(set);
-	RETURN(rc);
+	return rc;
 }
 static int common_attr_done(struct lov_request_set *set)
 {
@@ -628,15 +617,14 @@
 	struct lov_request *req;
 	struct obdo *tmp_oa;
 	int rc = 0, attrset = 0;
-	ENTRY;
 
 	LASSERT(set->set_oi != NULL);
 
 	if (set->set_oi->oi_oa == NULL)
-		RETURN(0);
+		return 0;
 
 	if (!atomic_read(&set->set_success))
-		RETURN(-EIO);
+		return -EIO;
 
 	OBDO_ALLOC(tmp_oa);
 	if (tmp_oa == NULL)
@@ -670,7 +658,7 @@
 out:
 	if (tmp_oa)
 		OBDO_FREE(tmp_oa);
-	RETURN(rc);
+	return rc;
 
 }
 
@@ -680,7 +668,6 @@
 	struct lov_oinfo     *loi = NULL;
 	struct list_head *pos;
 	struct lov_request *req;
-	ENTRY;
 
 	list_for_each (pos, &set->set_list) {
 		req = list_entry(pos, struct lov_request, rq_link);
@@ -694,16 +681,15 @@
 			loi->loi_lvb.lvb_blocks = req->rq_oi.oi_oa->o_blocks;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int lov_fini_brw_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	if (atomic_read(&set->set_completes)) {
 		rc = brw_done(set);
@@ -711,7 +697,7 @@
 	}
 	lov_put_reqset(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 int lov_prep_brw_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -727,11 +713,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int rc = 0, i, shift;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -832,23 +817,22 @@
 	else
 		lov_fini_brw_set(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_getattr_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	if (atomic_read(&set->set_completes))
 		rc = common_attr_done(set);
 
 	lov_put_reqset(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* The callback for osc_getattr_async that finilizes a request info when a
@@ -867,11 +851,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int rc = 0, i;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -913,18 +896,16 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_getattr_set(set);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_destroy_set(struct lov_request_set *set)
 {
-	ENTRY;
-
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	if (atomic_read(&set->set_completes)) {
 		/* FIXME update qos data here */
@@ -932,7 +913,7 @@
 
 	lov_put_reqset(set);
 
-	RETURN(0);
+	return 0;
 }
 
 int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo,
@@ -943,11 +924,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int rc = 0, i;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -987,19 +967,18 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_destroy_set(set);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_setattr_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	if (atomic_read(&set->set_completes)) {
 		rc = common_attr_done(set);
@@ -1007,7 +986,7 @@
 	}
 
 	lov_put_reqset(set);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_update_setattr_set(struct lov_request_set *set,
@@ -1015,7 +994,6 @@
 {
 	struct lov_obd *lov = &req->rq_rqset->set_exp->exp_obd->u.lov;
 	struct lov_stripe_md *lsm = req->rq_rqset->set_oi->oi_md;
-	ENTRY;
 
 	lov_update_set(set, req, rc);
 
@@ -1036,7 +1014,7 @@
 				req->rq_oi.oi_oa->o_atime;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /* The callback for osc_setattr_async that finilizes a request info when a
@@ -1056,11 +1034,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int rc = 0, i;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -1113,19 +1090,18 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_setattr_set(set);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_punch_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	if (atomic_read(&set->set_completes)) {
 		rc = -EIO;
@@ -1136,7 +1112,7 @@
 
 	lov_put_reqset(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 int lov_update_punch_set(struct lov_request_set *set,
@@ -1144,7 +1120,6 @@
 {
 	struct lov_obd *lov = &req->rq_rqset->set_exp->exp_obd->u.lov;
 	struct lov_stripe_md *lsm = req->rq_rqset->set_oi->oi_md;
-	ENTRY;
 
 	lov_update_set(set, req, rc);
 
@@ -1162,7 +1137,7 @@
 		lov_stripe_unlock(lsm);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /* The callback for osc_punch that finilizes a request info when a response
@@ -1182,11 +1157,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int rc = 0, i;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_oi = oinfo;
@@ -1238,19 +1212,18 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_punch_set(set);
-	RETURN(rc);
+	return rc;
 }
 
 int lov_fini_sync_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 	LASSERT(set->set_exp);
 	if (atomic_read(&set->set_completes)) {
 		if (!atomic_read(&set->set_success))
@@ -1260,7 +1233,7 @@
 
 	lov_put_reqset(set);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* The callback for osc_sync that finilizes a request info when a
@@ -1281,11 +1254,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &exp->exp_obd->u.lov;
 	int rc = 0, i;
-	ENTRY;
 
 	OBD_ALLOC_PTR(set);
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_exp = exp;
@@ -1330,10 +1302,10 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_sync_set(set);
-	RETURN(rc);
+	return rc;
 }
 
 #define LOV_U64_MAX ((__u64)~0ULL)
@@ -1347,8 +1319,6 @@
 
 int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs,int success)
 {
-	ENTRY;
-
 	if (success) {
 		__u32 expected_stripes = lov_get_stripecnt(&obd->u.lov,
 							   LOV_MAGIC, 0);
@@ -1361,26 +1331,25 @@
 		memcpy(&obd->obd_osfs, osfs, sizeof(*osfs));
 		obd->obd_osfs_age = cfs_time_current_64();
 		spin_unlock(&obd->obd_osfs_lock);
-		RETURN(0);
+		return 0;
 	}
 
-	RETURN(-EIO);
+	return -EIO;
 }
 
 int lov_fini_statfs_set(struct lov_request_set *set)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (set == NULL)
-		RETURN(0);
+		return 0;
 
 	if (atomic_read(&set->set_completes)) {
 		rc = lov_fini_statfs(set->set_obd, set->set_oi->oi_osfs,
 				     atomic_read(&set->set_success));
 	}
 	lov_put_reqset(set);
-	RETURN(rc);
+	return rc;
 }
 
 void lov_update_statfs(struct obd_statfs *osfs, struct obd_statfs *lov_sfs,
@@ -1450,7 +1419,6 @@
 	struct lov_tgt_desc *tgt;
 	struct obd_device *lovobd, *tgtobd;
 	int success;
-	ENTRY;
 
 	lovreq = container_of(oinfo, struct lov_request, rq_oi);
 	set = lovreq->rq_rqset;
@@ -1488,7 +1456,7 @@
 				     atomic_read(&set->set_success));
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo,
@@ -1497,11 +1465,10 @@
 	struct lov_request_set *set;
 	struct lov_obd *lov = &obd->u.lov;
 	int rc = 0, i;
-	ENTRY;
 
 	OBD_ALLOC(set, sizeof(*set));
 	if (set == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lov_init_set(set);
 
 	set->set_obd = obd;
@@ -1544,8 +1511,8 @@
 	if (!set->set_count)
 		GOTO(out_set, rc = -EIO);
 	*reqset = set;
-	RETURN(rc);
+	return rc;
 out_set:
 	lov_fini_statfs_set(set);
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_dev.c b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
index 204ecd0..998ea1c 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_dev.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_dev.c
@@ -55,10 +55,8 @@
 {
 	struct lovsub_req *lsr;
 
-	ENTRY;
 	lsr = cl2lovsub_req(slice);
 	OBD_SLAB_FREE_PTR(lsr, lovsub_req_kmem);
-	EXIT;
 }
 
 /**
@@ -73,14 +71,12 @@
 {
 	struct lovsub_object *subobj;
 
-	ENTRY;
 	subobj = cl2lovsub(obj);
 	/*
 	 * There is no OBD_MD_* flag for obdo::o_stripe_idx, so set it
 	 * unconditionally. It never changes anyway.
 	 */
 	attr->cra_oa->o_stripe_idx = subobj->lso_index;
-	EXIT;
 }
 
 static const struct cl_req_operations lovsub_req_ops = {
@@ -101,20 +97,19 @@
 	struct lu_device_type *ldt;
 	int rc;
 
-	ENTRY;
 	next->ld_site = d->ld_site;
 	ldt = next->ld_type;
 	LASSERT(ldt != NULL);
 	rc = ldt->ldt_ops->ldto_device_init(env, next, ldt->ldt_name, NULL);
 	if (rc) {
 		next->ld_site = NULL;
-		RETURN(rc);
+		return rc;
 	}
 
 	lu_device_get(next);
 	lu_ref_add(&next->ld_reference, "lu-stack", &lu_site_init);
 	lsd->acid_next = lu2cl_dev(next);
-	RETURN(rc);
+	return rc;
 }
 
 static struct lu_device *lovsub_device_fini(const struct lu_env *env,
@@ -123,12 +118,11 @@
 	struct lu_device *next;
 	struct lovsub_device *lsd;
 
-	ENTRY;
 	lsd = lu2lovsub_dev(d);
 	next = cl2lu_dev(lsd->acid_next);
 	lsd->acid_super = NULL;
 	lsd->acid_next = NULL;
-	RETURN(next);
+	return next;
 }
 
 static struct lu_device *lovsub_device_free(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_lock.c b/drivers/staging/lustre/lustre/lov/lovsub_lock.c
index 03bab17..80305aa 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_lock.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_lock.c
@@ -57,35 +57,29 @@
 {
 	struct lovsub_lock   *lsl;
 
-	ENTRY;
 	lsl = cl2lovsub_lock(slice);
 	LASSERT(list_empty(&lsl->lss_parents));
 	OBD_SLAB_FREE_PTR(lsl, lovsub_lock_kmem);
-	EXIT;
 }
 
 static void lovsub_parent_lock(const struct lu_env *env, struct lov_lock *lov)
 {
 	struct cl_lock *parent;
 
-	ENTRY;
 	parent = lov->lls_cl.cls_lock;
 	cl_lock_get(parent);
 	lu_ref_add(&parent->cll_reference, "lovsub-parent", current);
 	cl_lock_mutex_get(env, parent);
-	EXIT;
 }
 
 static void lovsub_parent_unlock(const struct lu_env *env, struct lov_lock *lov)
 {
 	struct cl_lock *parent;
 
-	ENTRY;
 	parent = lov->lls_cl.cls_lock;
 	cl_lock_mutex_put(env, lov->lls_cl.cls_lock);
 	lu_ref_del(&parent->cll_reference, "lovsub-parent", current);
 	cl_lock_put(env, parent);
-	EXIT;
 }
 
 /**
@@ -101,7 +95,6 @@
 	struct lov_lock_link *scan;
 
 	LASSERT(cl_lock_is_mutexed(slice->cls_lock));
-	ENTRY;
 
 	list_for_each_entry(scan, &sub->lss_parents, lll_list) {
 		struct lov_lock *lov    = scan->lll_super;
@@ -113,7 +106,6 @@
 			lovsub_parent_unlock(env, lov);
 		}
 	}
-	EXIT;
 }
 
 /**
@@ -127,8 +119,6 @@
 	struct lov_lock    *lov;
 	unsigned long       dumbbell;
 
-	ENTRY;
-
 	LASSERT(cl_lock_is_mutexed(slice->cls_lock));
 
 	if (!list_empty(&lock->lss_parents)) {
@@ -146,7 +136,7 @@
 	} else
 		dumbbell = 0;
 
-	RETURN(dumbbell);
+	return dumbbell;
 }
 
 /**
@@ -162,7 +152,6 @@
 	pgoff_t start;
 	pgoff_t end;
 
-	ENTRY;
 	start = in->cld_start;
 	end   = in->cld_end;
 
@@ -184,7 +173,6 @@
 	}
 	out->cld_start = start;
 	out->cld_end   = end;
-	EXIT;
 }
 
 /**
@@ -241,8 +229,6 @@
 	struct lov_lock      *lov;
 	int result		   = 0;
 
-	ENTRY;
-
 	LASSERT(cl_lock_mode_match(d->cld_mode,
 				   s->cls_lock->cll_descr.cld_mode));
 	list_for_each_entry(scan, &lock->lss_parents, lll_list) {
@@ -254,7 +240,7 @@
 		lovsub_parent_unlock(env, lov);
 		result = result ?: rc;
 	}
-	RETURN(result);
+	return result;
 }
 
 static int lovsub_lock_closure(const struct lu_env *env,
@@ -267,7 +253,6 @@
 	int		   result;
 
 	LASSERT(cl_lock_is_mutexed(slice->cls_lock));
-	ENTRY;
 
 	sub    = cl2lovsub_lock(slice);
 	result = 0;
@@ -278,7 +263,7 @@
 		if (result != 0)
 			break;
 	}
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -290,11 +275,10 @@
 {
 	struct cl_lock *parent;
 	int	     result;
-	ENTRY;
 
 	parent = lov->lls_cl.cls_lock;
 	if (parent->cll_error)
-		RETURN(0);
+		return 0;
 
 	result = 0;
 	switch (parent->cll_state) {
@@ -386,7 +370,7 @@
 		break;
 	}
 
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -403,7 +387,6 @@
 
 	LASSERT(cl_lock_is_mutexed(child));
 
-	ENTRY;
 	/*
 	 * Destruction of a sub-lock might take multiple iterations, because
 	 * when the last sub-lock of a given top-lock is deleted, top-lock is
@@ -434,7 +417,6 @@
 			}
 	       }
 	} while (restart);
-	EXIT;
 }
 
 static int lovsub_lock_print(const struct lu_env *env, void *cookie,
@@ -471,7 +453,6 @@
 	struct lovsub_lock *lsk;
 	int result;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(lsk, lovsub_lock_kmem, __GFP_IO);
 	if (lsk != NULL) {
 		INIT_LIST_HEAD(&lsk->lss_parents);
@@ -479,7 +460,7 @@
 		result = 0;
 	} else
 		result = -ENOMEM;
-	RETURN(result);
+	return result;
 }
 
 /** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_object.c b/drivers/staging/lustre/lustre/lov/lovsub_object.c
index 1b83d90..89760b3 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_object.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_object.c
@@ -61,7 +61,6 @@
 
 	int result;
 
-	ENTRY;
 	under = &dev->acid_next->cd_lu_dev;
 	below = under->ld_ops->ldo_object_alloc(env, obj->lo_header, under);
 	if (below != NULL) {
@@ -70,7 +69,7 @@
 		result = 0;
 	} else
 		result = -ENOMEM;
-	RETURN(result);
+	return result;
 
 }
 
@@ -78,7 +77,6 @@
 {
 	struct lovsub_object *los = lu2lovsub(obj);
 	struct lov_object    *lov = los->lso_super;
-	ENTRY;
 
 	/* We can't assume lov was assigned here, because of the shadow
 	 * object handling in lu_object_find.
@@ -94,7 +92,6 @@
 	lu_object_fini(obj);
 	lu_object_header_fini(&los->lso_header.coh_lu);
 	OBD_SLAB_FREE_PTR(los, lovsub_object_kmem);
-	EXIT;
 }
 
 static int lovsub_object_print(const struct lu_env *env, void *cookie,
@@ -110,9 +107,8 @@
 {
 	struct lov_object *lov = cl2lovsub(obj)->lso_super;
 
-	ENTRY;
 	lov_r0(lov)->lo_attr_valid = 0;
-	RETURN(0);
+	return 0;
 }
 
 static int lovsub_object_glimpse(const struct lu_env *env,
@@ -121,8 +117,7 @@
 {
 	struct lovsub_object *los = cl2lovsub(obj);
 
-	ENTRY;
-	RETURN(cl_object_glimpse(env, &los->lso_super->lo_cl, lvb));
+	return cl_object_glimpse(env, &los->lso_super->lo_cl, lvb);
 }
 
 
@@ -150,7 +145,6 @@
 	struct lovsub_object *los;
 	struct lu_object     *obj;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(los, lovsub_object_kmem, __GFP_IO);
 	if (los != NULL) {
 		struct cl_object_header *hdr;
@@ -164,7 +158,7 @@
 		obj->lo_ops = &lovsub_lu_obj_ops;
 	} else
 		obj = NULL;
-	RETURN(obj);
+	return obj;
 }
 
 /** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lovsub_page.c b/drivers/staging/lustre/lustre/lov/lovsub_page.c
index bc9e683..3f00ce9 100644
--- a/drivers/staging/lustre/lustre/lov/lovsub_page.c
+++ b/drivers/staging/lustre/lustre/lov/lovsub_page.c
@@ -63,10 +63,9 @@
 			struct cl_page *page, struct page *unused)
 {
 	struct lovsub_page *lsb = cl_object_page_slice(obj, page);
-	ENTRY;
 
 	cl_page_slice_add(page, &lsb->lsb_cl, obj, &lovsub_page_ops);
-	RETURN(0);
+	return 0;
 }
 
 /** @} lov */
diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c
index 5b2c0d8..15744e1 100644
--- a/drivers/staging/lustre/lustre/lov/lproc_lov.c
+++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c
@@ -35,7 +35,6 @@
  */
 #define DEBUG_SUBSYSTEM S_CLASS
 
-#include <linux/version.h>
 #include <asm/statfs.h>
 #include <lprocfs_status.h>
 #include <obd_class.h>
diff --git a/drivers/staging/lustre/lustre/lvfs/fsfilt.c b/drivers/staging/lustre/lustre/lvfs/fsfilt.c
index 064445c..e86df73 100644
--- a/drivers/staging/lustre/lustre/lvfs/fsfilt.c
+++ b/drivers/staging/lustre/lustre/lvfs/fsfilt.c
@@ -35,7 +35,6 @@
 #define DEBUG_SUBSYSTEM S_FILTER
 
 #include <linux/fs.h>
-#include <linux/jbd.h>
 #include <linux/module.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
@@ -68,7 +67,7 @@
 			CERROR("different operations for type %s\n",
 			       fs_ops->fs_type);
 			/* unlock fsfilt_types list */
-			RETURN(-EEXIST);
+			return -EEXIST;
 		}
 	} else {
 		try_module_get(THIS_MODULE);
@@ -120,7 +119,7 @@
 
 		if (rc) {
 			CERROR("Can't find %s interface\n", name);
-			RETURN(ERR_PTR(rc < 0 ? rc : -rc));
+			return ERR_PTR(rc < 0 ? rc : -rc);
 			/* unlock fsfilt_types list */
 		}
 	}
diff --git a/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c b/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c
index c1e99b3..ee75994 100644
--- a/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c
+++ b/drivers/staging/lustre/lustre/lvfs/fsfilt_ext3.c
@@ -48,7 +48,6 @@
 #include <ldiskfs/ldiskfs_config.h>
 #include <ext4/ext4.h>
 #include <ext4/ext4_jbd2.h>
-#include <linux/version.h>
 #include <linux/bitops.h>
 #include <linux/quota.h>
 
diff --git a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
index e70d8fe..18e1b47 100644
--- a/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
+++ b/drivers/staging/lustre/lustre/lvfs/lvfs_linux.c
@@ -40,16 +40,12 @@
 
 #define DEBUG_SUBSYSTEM S_FILTER
 
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <asm/unistd.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/quotaops.h>
-#include <linux/version.h>
 #include <linux/libcfs/libcfs.h>
-#include <lustre_fsfilt.h>
-#include <obd.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/lustre_compat25.h>
@@ -207,7 +203,6 @@
 {
 	struct dentry *dchild_old, *dchild_new;
 	int err = 0;
-	ENTRY;
 
 	ASSERT_KERNEL_CTXT("kernel doing rename outside kernel context\n");
 	CDEBUG(D_INODE, "renaming file %.*s to %.*s\n",
@@ -215,7 +210,7 @@
 
 	dchild_old = ll_lookup_one_len(oldname, dir, strlen(oldname));
 	if (IS_ERR(dchild_old))
-		RETURN(PTR_ERR(dchild_old));
+		return PTR_ERR(dchild_old);
 
 	if (!dchild_old->d_inode)
 		GOTO(put_old, err = -ENOENT);
@@ -230,7 +225,7 @@
 	dput(dchild_new);
 put_old:
 	dput(dchild_old);
-	RETURN(err);
+	return err;
 }
 EXPORT_SYMBOL(lustre_rename);
 
@@ -242,7 +237,7 @@
 		.dentry = de,
 		.mnt = ctxt->pwdmnt,
 	};
-	return ll_dentry_open(&path, flags, current_cred());
+	return dentry_open(&path, flags, current_cred());
 }
 EXPORT_SYMBOL(l_dentry_open);
 
@@ -255,7 +250,7 @@
 	__s64 ret = 0;
 
 	if (lc == NULL || header == NULL)
-		RETURN(0);
+		return 0;
 
 	switch (field) {
 		case LPROCFS_FIELDS_FLAGS_CONFIG:
@@ -285,7 +280,7 @@
 			break;
 	};
 
-	RETURN(ret);
+	return ret;
 }
 EXPORT_SYMBOL(lprocfs_read_helper);
 #endif /* LPROCFS */
diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
index 6592478..e0b8f18 100644
--- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
+++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
@@ -35,7 +35,6 @@
  */
 #define DEBUG_SUBSYSTEM S_CLASS
 
-#include <linux/version.h>
 #include <linux/vfs.h>
 #include <obd_class.h>
 #include <lprocfs_status.h>
@@ -93,14 +92,13 @@
 	struct hsm_action_item	*hai;
 	int			 len;
 	int			 fd, rc;
-	ENTRY;
 
 	rc = lprocfs_write_helper(buffer, count, &fd);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (fd < 0)
-		RETURN(-ERANGE);
+		return -ERANGE;
 	CWARN("message to fd %d\n", fd);
 
 	len = sizeof(*lh) + sizeof(*hal) + MTI_NAME_MAXLEN +
@@ -141,8 +139,8 @@
 	}
 	OBD_FREE(lh, len);
 	if (rc < 0)
-		RETURN(rc);
-	RETURN(count);
+		return rc;
+	return count;
 }
 
 struct file_operations mdc_kuc_fops = {
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
index e789aed..b2de478 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
@@ -45,10 +45,10 @@
 	LASSERT (b != NULL);
 
 	b->suppgid = suppgid;
-	b->uid = current_uid();
-	b->gid = current_gid();
-	b->fsuid = current_fsuid();
-	b->fsgid = current_fsgid();
+	b->uid = from_kuid(&init_user_ns, current_uid());
+	b->gid = from_kgid(&init_user_ns, current_gid());
+	b->fsuid = from_kuid(&init_user_ns, current_fsuid());
+	b->fsgid = from_kgid(&init_user_ns, current_fsgid());
 	b->capability = cfs_curproc_cap_pack();
 }
 
@@ -219,8 +219,8 @@
 
 	/* XXX do something about time, uid, gid */
 	rec->cr_opcode   = REINT_OPEN;
-	rec->cr_fsuid   = current_fsuid();
-	rec->cr_fsgid   = current_fsgid();
+	rec->cr_fsuid    = from_kuid(&init_user_ns, current_fsuid());
+	rec->cr_fsgid    = from_kgid(&init_user_ns, current_fsgid());
 	rec->cr_cap      = cfs_curproc_cap_pack();
 	if (op_data != NULL) {
 		rec->cr_fid1 = op_data->op_fid1;
@@ -299,16 +299,16 @@
 				 struct md_op_data *op_data)
 {
 	rec->sa_opcode  = REINT_SETATTR;
-	rec->sa_fsuid   = current_fsuid();
-	rec->sa_fsgid   = current_fsgid();
+	rec->sa_fsuid   = from_kuid(&init_user_ns, current_fsuid());
+	rec->sa_fsgid   = from_kgid(&init_user_ns, current_fsgid());
 	rec->sa_cap     = cfs_curproc_cap_pack();
 	rec->sa_suppgid = -1;
 
 	rec->sa_fid    = op_data->op_fid1;
 	rec->sa_valid  = attr_pack(op_data->op_attr.ia_valid);
 	rec->sa_mode   = op_data->op_attr.ia_mode;
-	rec->sa_uid    = op_data->op_attr.ia_uid;
-	rec->sa_gid    = op_data->op_attr.ia_gid;
+	rec->sa_uid    = from_kuid(&init_user_ns, op_data->op_attr.ia_uid);
+	rec->sa_gid    = from_kgid(&init_user_ns, op_data->op_attr.ia_gid);
 	rec->sa_size   = op_data->op_attr.ia_size;
 	rec->sa_blocks = op_data->op_attr_blocks;
 	rec->sa_atime  = LTIME_S(op_data->op_attr.ia_atime);
@@ -316,8 +316,9 @@
 	rec->sa_ctime  = LTIME_S(op_data->op_attr.ia_ctime);
 	rec->sa_attr_flags = ((struct ll_iattr *)&op_data->op_attr)->ia_attr_flags;
 	if ((op_data->op_attr.ia_valid & ATTR_GID) &&
-	    current_is_in_group(op_data->op_attr.ia_gid))
-		rec->sa_suppgid = op_data->op_attr.ia_gid;
+	    in_group_p(op_data->op_attr.ia_gid))
+		rec->sa_suppgid =
+			from_kgid(&init_user_ns, op_data->op_attr.ia_gid);
 	else
 		rec->sa_suppgid = op_data->op_suppgids[0];
 
@@ -504,11 +505,11 @@
 static int mdc_req_avail(struct client_obd *cli, struct mdc_cache_waiter *mcw)
 {
 	int rc;
-	ENTRY;
+
 	client_obd_list_lock(&cli->cl_loi_list_lock);
 	rc = list_empty(&mcw->mcw_entry);
 	client_obd_list_unlock(&cli->cl_loi_list_lock);
-	RETURN(rc);
+	return rc;
 };
 
 /* We record requests in flight in cli->cl_r_in_flight here.
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index 1cc90b6..fb5a995 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -115,13 +115,12 @@
 {
 	struct ldlm_lock *lock;
 	struct inode *new_inode = data;
-	ENTRY;
 
 	if(bits)
 		*bits = 0;
 
 	if (!*lockh)
-		RETURN(0);
+		return 0;
 
 	lock = ldlm_handle2lock((struct lustre_handle *)lockh);
 
@@ -144,7 +143,7 @@
 	unlock_res_and_lock(lock);
 	LDLM_LOCK_PUT(lock);
 
-	RETURN(0);
+	return 0;
 }
 
 ldlm_mode_t mdc_lock_match(struct obd_export *exp, __u64 flags,
@@ -154,12 +153,11 @@
 {
 	struct ldlm_res_id res_id;
 	ldlm_mode_t rc;
-	ENTRY;
 
 	fid_build_reg_res_name(fid, &res_id);
 	rc = ldlm_lock_match(class_exp2obd(exp)->obd_namespace, flags,
 			     &res_id, type, policy, mode, lockh, 0);
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_cancel_unused(struct obd_export *exp,
@@ -173,12 +171,10 @@
 	struct obd_device *obd = class_exp2obd(exp);
 	int rc;
 
-	ENTRY;
-
 	fid_build_reg_res_name(fid, &res_id);
 	rc = ldlm_cli_cancel_unused_resource(obd->obd_namespace, &res_id,
 					     policy, mode, flags, opaque);
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_null_inode(struct obd_export *exp,
@@ -187,7 +183,6 @@
 	struct ldlm_res_id res_id;
 	struct ldlm_resource *res;
 	struct ldlm_namespace *ns = class_exp2obd(exp)->obd_namespace;
-	ENTRY;
 
 	LASSERTF(ns != NULL, "no namespace passed\n");
 
@@ -195,14 +190,14 @@
 
 	res = ldlm_resource_get(ns, NULL, &res_id, 0, 0);
 	if(res == NULL)
-		RETURN(0);
+		return 0;
 
 	lock_res(res);
 	res->lr_lvb_inode = NULL;
 	unlock_res(res);
 
 	ldlm_resource_putref(res);
-	RETURN(0);
+	return 0;
 }
 
 /* find any ldlm lock of the inode in mdc
@@ -215,16 +210,15 @@
 {
 	struct ldlm_res_id res_id;
 	int rc = 0;
-	ENTRY;
 
 	fid_build_reg_res_name((struct lu_fid*)fid, &res_id);
 	rc = ldlm_resource_iterate(class_exp2obd(exp)->obd_namespace, &res_id,
 				   it, data);
 	if (rc == LDLM_ITER_STOP)
-		RETURN(1);
+		return 1;
 	else if (rc == LDLM_ITER_CONTINUE)
-		RETURN(0);
-	RETURN(rc);
+		return 0;
+	return rc;
 }
 
 static inline void mdc_clear_replay_flag(struct ptlrpc_request *req, int rc)
@@ -281,7 +275,6 @@
 	int		    count = 0;
 	int		    mode;
 	int		    rc;
-	ENTRY;
 
 	it->it_create_mode = (it->it_create_mode & ~S_IFMT) | S_IFREG;
 
@@ -314,7 +307,7 @@
 				   &RQF_LDLM_INTENT_OPEN);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 	}
 
 	/* parent capability */
@@ -362,12 +355,11 @@
 	struct obd_device     *obddev = class_exp2obd(exp);
 	struct ldlm_intent    *lit;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_LDLM_INTENT_UNLINK);
 	if (req == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -376,7 +368,7 @@
 	rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	/* pack the intent */
@@ -391,7 +383,7 @@
 	req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
 			     obddev->u.cli.cl_max_mds_cookiesize);
 	ptlrpc_request_set_replen(req);
-	RETURN(req);
+	return req;
 }
 
 static struct ptlrpc_request *mdc_intent_getattr_pack(struct obd_export *exp,
@@ -407,12 +399,11 @@
 					       OBD_MD_FLRMTPERM : OBD_MD_FLACL);
 	struct ldlm_intent    *lit;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_LDLM_INTENT_GETATTR);
 	if (req == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -421,7 +412,7 @@
 	rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	/* pack the intent */
@@ -438,7 +429,7 @@
 		req_capsule_set_size(&req->rq_pill, &RMF_ACL, RCL_SERVER,
 				     sizeof(struct mdt_remote_perm));
 	ptlrpc_request_set_replen(req);
-	RETURN(req);
+	return req;
 }
 
 static struct ptlrpc_request *mdc_intent_layout_pack(struct obd_export *exp,
@@ -450,18 +441,17 @@
 	struct ldlm_intent    *lit;
 	struct layout_intent  *layout;
 	int rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				&RQF_LDLM_INTENT_LAYOUT);
 	if (req == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_CLIENT, 0);
 	rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	/* pack the intent */
@@ -477,7 +467,7 @@
 	req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
 			obd->u.cli.cl_max_mds_easize);
 	ptlrpc_request_set_replen(req);
-	RETURN(req);
+	return req;
 }
 
 static struct ptlrpc_request *
@@ -485,21 +475,20 @@
 {
 	struct ptlrpc_request *req;
 	int rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_LDLM_ENQUEUE);
 	if (req == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	rc = ldlm_prep_enqueue_req(exp, req, NULL, 0);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, lvb_len);
 	ptlrpc_request_set_replen(req);
-	RETURN(req);
+	return req;
 }
 
 static int mdc_finish_enqueue(struct obd_export *exp,
@@ -516,7 +505,6 @@
 	struct ldlm_lock    *lock;
 	void		*lvb_data = NULL;
 	int		  lvb_len = 0;
-	ENTRY;
 
 	LASSERT(rc >= 0);
 	/* Similarly, if we're going to replay this request, we don't want to
@@ -579,7 +567,7 @@
 		body = req_capsule_server_get(pill, &RMF_MDT_BODY);
 		if (body == NULL) {
 			CERROR ("Can't swab mdt_body\n");
-			RETURN (-EPROTO);
+			return -EPROTO;
 		}
 
 		if (it_disposition(it, DISP_OPEN_OPEN) &&
@@ -605,7 +593,7 @@
 			eadata = req_capsule_server_sized_get(pill, &RMF_MDT_MD,
 							      body->eadatasize);
 			if (eadata == NULL)
-				RETURN(-EPROTO);
+				return -EPROTO;
 
 			/* save lvb data and length in case this is for layout
 			 * lock */
@@ -649,14 +637,14 @@
 			perm = req_capsule_server_swab_get(pill, &RMF_ACL,
 						lustre_swab_mdt_remote_perm);
 			if (perm == NULL)
-				RETURN(-EPROTO);
+				return -EPROTO;
 		}
 		if (body->valid & OBD_MD_FLMDSCAPA) {
 			struct lustre_capa *capa, *p;
 
 			capa = req_capsule_server_get(pill, &RMF_CAPA1);
 			if (capa == NULL)
-				RETURN(-EPROTO);
+				return -EPROTO;
 
 			if (it->it_op & IT_OPEN) {
 				/* client fid capa will be checked in replay */
@@ -670,7 +658,7 @@
 
 			capa = req_capsule_server_get(pill, &RMF_CAPA2);
 			if (capa == NULL)
-				RETURN(-EPROTO);
+				return -EPROTO;
 		}
 	} else if (it->it_op & IT_LAYOUT) {
 		/* maybe the lock was granted right away and layout
@@ -680,7 +668,7 @@
 			lvb_data = req_capsule_server_sized_get(pill,
 							&RMF_DLM_LVB, lvb_len);
 			if (lvb_data == NULL)
-				RETURN(-EPROTO);
+				return -EPROTO;
 		}
 	}
 
@@ -695,7 +683,7 @@
 		OBD_ALLOC_LARGE(lmm, lvb_len);
 		if (lmm == NULL) {
 			LDLM_LOCK_PUT(lock);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		memcpy(lmm, lvb_data, lvb_len);
 
@@ -713,7 +701,7 @@
 	if (lock != NULL)
 		LDLM_LOCK_PUT(lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* We always reserve enough space in the reply packet for a stripe MD, because
@@ -738,7 +726,6 @@
 	int		    generation, resends = 0;
 	struct ldlm_reply     *lockrep;
 	enum lvb_type	       lvb_type = 0;
-	ENTRY;
 
 	LASSERTF(!it || einfo->ei_type == LDLM_IBITS, "lock type %d\n",
 		 einfo->ei_type);
@@ -780,17 +767,17 @@
 		req = mdc_enqueue_pack(exp, 0);
 	} else if (it->it_op & IT_LAYOUT) {
 		if (!imp_connect_lvb_type(class_exp2cliimp(exp)))
-			RETURN(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 
 		req = mdc_intent_layout_pack(exp, it, op_data);
 		lvb_type = LVB_T_LAYOUT;
 	} else {
 		LBUG();
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (IS_ERR(req))
-		RETURN(PTR_ERR(req));
+		return PTR_ERR(req);
 
 	if (req != NULL && it && it->it_op & IT_CREAT)
 		/* ask ptlrpc not to resend on EINPROGRESS since we have our own
@@ -813,7 +800,7 @@
 			mdc_put_rpc_lock(obddev->u.cli.cl_rpc_lock, it);
 			mdc_clear_replay_flag(req, 0);
 			ptlrpc_req_finished(req);
-			RETURN(rc);
+			return rc;
 		}
 	}
 
@@ -823,8 +810,14 @@
 		/* For flock requests we immediatelly return without further
 		   delay and let caller deal with the rest, since rest of
 		   this function metadata processing makes no sense for flock
-		   requests anyway */
-		RETURN(rc);
+		   requests anyway. But in case of problem during comms with
+		   Server (ETIMEDOUT) or any signal/kill attempt (EINTR), we
+		   can not rely on caller and this mainly for F_UNLCKs
+		   (explicits or automatically generated by Kernel to clean
+		   current FLocks upon exit) that can't be trashed */
+		if ((rc == -EINTR) || (rc == -ETIMEDOUT))
+			goto resend;
+		return rc;
 	}
 
 	mdc_exit_request(&obddev->u.cli);
@@ -834,12 +827,15 @@
 		CERROR("ldlm_cli_enqueue: %d\n", rc);
 		mdc_clear_replay_flag(req, rc);
 		ptlrpc_req_finished(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	lockrep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
 	LASSERT(lockrep != NULL);
 
+	lockrep->lock_policy_res2 =
+		ptlrpc_status_ntoh(lockrep->lock_policy_res2);
+
 	/* Retry the create infinitely when we get -EINPROGRESS from
 	 * server. This is required by the new quota design. */
 	if (it && it->it_op & IT_CREAT &&
@@ -856,7 +852,7 @@
 			goto resend;
 		} else {
 			CDEBUG(D_HA, "resend cross eviction\n");
-			RETURN(-EIO);
+			return -EIO;
 		}
 	}
 
@@ -868,7 +864,7 @@
 		}
 		ptlrpc_req_finished(req);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_finish_intent_lock(struct obd_export *exp,
@@ -882,7 +878,6 @@
 	struct ldlm_lock *lock;
 	int rc;
 
-
 	LASSERT(request != NULL);
 	LASSERT(request != LP_POISON);
 	LASSERT(request->rq_repmsg != LP_POISON);
@@ -891,11 +886,11 @@
 		/* The server failed before it even started executing the
 		 * intent, i.e. because it couldn't unpack the request. */
 		LASSERT(it->d.lustre.it_status != 0);
-		RETURN(it->d.lustre.it_status);
+		return it->d.lustre.it_status;
 	}
 	rc = it_open_error(DISP_IT_EXECD, it);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	mdt_body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
 	LASSERT(mdt_body != NULL);      /* mdc_enqueue checked */
@@ -917,13 +912,13 @@
 			CDEBUG(D_DENTRY, "Found stale data "DFID"("DFID")/"DFID
 			       "\n", PFID(&op_data->op_fid2),
 			       PFID(&op_data->op_fid2), PFID(&mdt_body->fid1));
-			RETURN(-ESTALE);
+			return -ESTALE;
 		}
 	}
 
 	rc = it_open_error(DISP_LOOKUP_EXECD, it);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	/* keep requests around for the multiple phases of the call
 	 * this shows the DISP_XX must guarantee we make it into the call
@@ -984,7 +979,7 @@
 	CDEBUG(D_DENTRY,"D_IT dentry %.*s intent: %s status %d disp %x rc %d\n",
 	       op_data->op_namelen, op_data->op_name, ldlm_it2str(it->it_op),
 	       it->d.lustre.it_status, it->d.lustre.it_disposition, rc);
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
@@ -997,7 +992,6 @@
 	struct lustre_handle lockh;
 	ldlm_policy_data_t policy;
 	ldlm_mode_t mode;
-	ENTRY;
 
 	if (it->d.lustre.it_lock_handle) {
 		lockh.cookie = it->d.lustre.it_lock_handle;
@@ -1029,7 +1023,7 @@
 		it->d.lustre.it_lock_mode = 0;
 	}
 
-	RETURN(!!mode);
+	return !!mode;
 }
 
 /*
@@ -1067,7 +1061,7 @@
 {
 	struct lustre_handle lockh;
 	int rc = 0;
-	ENTRY;
+
 	LASSERT(it);
 
 	CDEBUG(D_DLMTRACE, "(name: %.*s,"DFID") in obj "DFID
@@ -1087,7 +1081,7 @@
 		/* Only return failure if it was not GETATTR by cfid
 		   (from inode_revalidate) */
 		if (rc || op_data->op_namelen != 0)
-			RETURN(rc);
+			return rc;
 	}
 
 	/* lookup_it may be called only after revalidate_it has run, because
@@ -1099,22 +1093,25 @@
 	 * this and use the request from revalidate.  In this case, revalidate
 	 * never dropped its reference, so the refcounts are all OK */
 	if (!it_disposition(it, DISP_ENQ_COMPLETE)) {
-		struct ldlm_enqueue_info einfo =
-			{ LDLM_IBITS, it_to_lock_mode(it), cb_blocking,
-			  ldlm_completion_ast, NULL, NULL, NULL };
+		struct ldlm_enqueue_info einfo = {
+			.ei_type	= LDLM_IBITS,
+			.ei_mode	= it_to_lock_mode(it),
+			.ei_cb_bl	= cb_blocking,
+			.ei_cb_cp	= ldlm_completion_ast,
+		};
 
 		/* For case if upper layer did not alloc fid, do it now. */
 		if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) {
 			rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
 			if (rc < 0) {
 				CERROR("Can't alloc new fid, rc %d\n", rc);
-				RETURN(rc);
+				return rc;
 			}
 		}
 		rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh,
 				 lmm, lmmsize, NULL, extra_lock_flags);
 		if (rc < 0)
-			RETURN(rc);
+			return rc;
 	} else if (!fid_is_sane(&op_data->op_fid2) ||
 		   !(it->it_create_mode & M_CHECK_STALE)) {
 		/* DISP_ENQ_COMPLETE set means there is extra reference on
@@ -1125,7 +1122,7 @@
 	}
 	*reqp = it->d.lustre.it_data;
 	rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh);
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_intent_getattr_async_interpret(const struct lu_env *env,
@@ -1139,8 +1136,8 @@
 	struct lookup_intent     *it;
 	struct lustre_handle     *lockh;
 	struct obd_device	*obddev;
+	struct ldlm_reply	 *lockrep;
 	__u64		     flags = LDLM_FL_HAS_INTENT;
-	ENTRY;
 
 	it    = &minfo->mi_it;
 	lockh = &minfo->mi_lockh;
@@ -1159,12 +1156,17 @@
 		GOTO(out, rc);
 	}
 
+	lockrep = req_capsule_server_get(&req->rq_pill, &RMF_DLM_REP);
+	LASSERT(lockrep != NULL);
+
+	lockrep->lock_policy_res2 =
+		ptlrpc_status_ntoh(lockrep->lock_policy_res2);
+
 	rc = mdc_finish_enqueue(exp, req, einfo, it, lockh, rc);
 	if (rc)
 		GOTO(out, rc);
 
 	rc = mdc_finish_intent_lock(exp, req, &minfo->mi_data, it, lockh);
-	EXIT;
 
 out:
 	OBD_FREE_PTR(einfo);
@@ -1191,7 +1193,6 @@
 				 };
 	int		      rc = 0;
 	__u64		    flags = LDLM_FL_HAS_INTENT;
-	ENTRY;
 
 	CDEBUG(D_DLMTRACE,"name: %.*s in inode "DFID", intent: %s flags %#o\n",
 	       op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1),
@@ -1200,12 +1201,12 @@
 	fid_build_reg_res_name(&op_data->op_fid1, &res_id);
 	req = mdc_intent_getattr_pack(exp, it, op_data);
 	if (!req)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = mdc_enter_request(&obddev->u.cli);
 	if (rc != 0) {
 		ptlrpc_req_finished(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = ldlm_cli_enqueue(exp, &req, einfo, &res_id, &policy, &flags, NULL,
@@ -1213,7 +1214,7 @@
 	if (rc < 0) {
 		mdc_exit_request(&obddev->u.cli);
 		ptlrpc_req_finished(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	CLASSERT(sizeof(*ga) <= sizeof(req->rq_async_args));
@@ -1225,5 +1226,5 @@
 	req->rq_interpret_reply = mdc_intent_getattr_async_interpret;
 	ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
 
-	RETURN(0);
+	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
index 5e25a07..9f3a345 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c
@@ -75,7 +75,6 @@
 	struct ldlm_res_id res_id;
 	struct ldlm_resource *res;
 	int count;
-	ENTRY;
 
 	/* Return, i.e. cancel nothing, only if ELC is supported (flag in
 	 * export) but disabled through procfs (flag in NS).
@@ -84,13 +83,13 @@
 	 * when we still want to cancel locks in advance and just cancel them
 	 * locally, without sending any RPC. */
 	if (exp_connect_cancelset(exp) && !ns_connect_cancelset(ns))
-		RETURN(0);
+		return 0;
 
 	fid_build_reg_res_name(fid, &res_id);
 	res = ldlm_resource_get(exp->exp_obd->obd_namespace,
 				NULL, &res_id, 0, 0);
 	if (res == NULL)
-		RETURN(0);
+		return 0;
 	LDLM_RESOURCE_ADDREF(res);
 	/* Initialize ibits lock policy. */
 	policy.l_inodebits.bits = bits;
@@ -98,7 +97,7 @@
 					   mode, 0, 0, NULL);
 	LDLM_RESOURCE_DELREF(res);
 	ldlm_resource_putref(res);
-	RETURN(count);
+	return count;
 }
 
 int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -111,7 +110,6 @@
 	struct obd_device *obd = exp->exp_obd;
 	int count = 0, rc;
 	__u64 bits;
-	ENTRY;
 
 	LASSERT(op_data != NULL);
 
@@ -127,7 +125,7 @@
 				   &RQF_MDS_REINT_SETATTR);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	if ((op_data->op_flags & (MF_SOM_CHANGE | MF_EPOCH_OPEN)) == 0)
@@ -140,7 +138,7 @@
 	rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	rpc_lock = obd->u.cli.cl_rpc_lock;
@@ -203,7 +201,7 @@
 		obd_mod_put(*mod);
 		req->rq_commit_cb(req);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_create(struct obd_export *exp, struct md_op_data *op_data,
@@ -217,7 +215,6 @@
 	struct obd_import *import = exp->exp_obd->u.cli.cl_import;
 	int generation = import->imp_generation;
 	LIST_HEAD(cancels);
-	ENTRY;
 
 	/* For case if upper layer did not alloc fid, do it now. */
 	if (!fid_is_sane(&op_data->op_fid2)) {
@@ -228,7 +225,7 @@
 		rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data);
 		if (rc < 0) {
 			CERROR("Can't alloc new fid, rc %d\n", rc);
-			RETURN(rc);
+			return rc;
 		}
 	}
 
@@ -244,7 +241,7 @@
 				   &RQF_MDS_REINT_CREATE_RMT_ACL);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -255,7 +252,7 @@
 	rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	/*
@@ -298,7 +295,7 @@
 			goto rebuild;
 		} else {
 			CDEBUG(D_HA, "resend cross eviction\n");
-			RETURN(-EIO);
+			return -EIO;
 		}
 	} else if (rc == 0) {
 		struct mdt_body *body;
@@ -315,7 +312,7 @@
 	}
 
 	*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
@@ -325,7 +322,6 @@
 	struct obd_device *obd = class_exp2obd(exp);
 	struct ptlrpc_request *req = *request;
 	int count = 0, rc;
-	ENTRY;
 
 	LASSERT(req == NULL);
 
@@ -345,7 +341,7 @@
 				   &RQF_MDS_REINT_UNLINK);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -354,7 +350,7 @@
 	rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_unlink_pack(req, op_data);
@@ -370,7 +366,7 @@
 	rc = mdc_reint(req, obd->u.cli.cl_rpc_lock, LUSTRE_IMP_FULL);
 	if (rc == -ERESTARTSYS)
 		rc = 0;
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
@@ -380,7 +376,6 @@
 	struct obd_device *obd = exp->exp_obd;
 	struct ptlrpc_request *req;
 	int count = 0, rc;
-	ENTRY;
 
 	if ((op_data->op_flags & MF_MDC_CANCEL_FID2) &&
 	    (fid_is_sane(&op_data->op_fid2)))
@@ -396,7 +391,7 @@
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_REINT_LINK);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	mdc_set_capa_size(req, &RMF_CAPA2, op_data->op_capa2);
@@ -406,7 +401,7 @@
 	rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_link_pack(req, op_data);
@@ -417,7 +412,7 @@
 	if (rc == -ERESTARTSYS)
 		rc = 0;
 
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
@@ -428,7 +423,6 @@
 	struct obd_device *obd = exp->exp_obd;
 	struct ptlrpc_request *req;
 	int count = 0, rc;
-	ENTRY;
 
 	if ((op_data->op_flags & MF_MDC_CANCEL_FID1) &&
 	    (fid_is_sane(&op_data->op_fid1)))
@@ -455,7 +449,7 @@
 				   &RQF_MDS_REINT_RENAME);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
@@ -466,7 +460,7 @@
 	rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (exp_connect_cancelset(exp) && req)
@@ -485,5 +479,5 @@
 	if (rc == -ERESTARTSYS)
 		rc = 0;
 
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 3cf9d8d..ed3a7a0 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -65,21 +65,20 @@
 {
 	struct lustre_capa *capa;
 	struct obd_capa *c;
-	ENTRY;
 
 	/* swabbed already in mdc_enqueue */
 	capa = req_capsule_server_get(&req->rq_pill, field);
 	if (capa == NULL)
-		RETURN(-EPROTO);
+		return -EPROTO;
 
 	c = alloc_capa(CAPA_SITE_CLIENT);
 	if (IS_ERR(c)) {
 		CDEBUG(D_INFO, "alloc capa failed!\n");
-		RETURN(PTR_ERR(c));
+		return PTR_ERR(c);
 	} else {
 		c->c_capa = *capa;
 		*oc = c;
-		RETURN(0);
+		return 0;
 	}
 }
 
@@ -109,12 +108,11 @@
 	struct ptlrpc_request *req;
 	struct mdt_body       *body;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_GETSTATUS,
 					LUSTRE_MDS_VERSION, MDS_GETSTATUS);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_pack_body(req, NULL, NULL, 0, 0, -1, 0);
 	lustre_msg_add_flags(req->rq_reqmsg, msg_flags);
@@ -141,7 +139,6 @@
 	       "root fid="DFID", last_committed="LPU64"\n",
 	       PFID(rootfid),
 	       lustre_msg_get_last_committed(req->rq_repmsg));
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -172,17 +169,16 @@
 	struct mdt_body    *body;
 	void	       *eadata;
 	int		 rc;
-	ENTRY;
 
 	/* Request message already built. */
 	rc = ptlrpc_queue_wait(req);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	/* sanity check for the reply */
 	body = req_capsule_server_get(pill, &RMF_MDT_BODY);
 	if (body == NULL)
-		RETURN(-EPROTO);
+		return -EPROTO;
 
 	CDEBUG(D_NET, "mode: %o\n", body->mode);
 
@@ -192,7 +188,7 @@
 		eadata = req_capsule_server_sized_get(pill, &RMF_MDT_MD,
 						      body->eadatasize);
 		if (eadata == NULL)
-			RETURN(-EPROTO);
+			return -EPROTO;
 	}
 
 	if (body->valid & OBD_MD_FLRMTPERM) {
@@ -202,17 +198,17 @@
 		perm = req_capsule_server_swab_get(pill, &RMF_ACL,
 						lustre_swab_mdt_remote_perm);
 		if (perm == NULL)
-			RETURN(-EPROTO);
+			return -EPROTO;
 	}
 
 	if (body->valid & OBD_MD_FLMDSCAPA) {
 		struct lustre_capa *capa;
 		capa = req_capsule_server_get(pill, &RMF_CAPA1);
 		if (capa == NULL)
-			RETURN(-EPROTO);
+			return -EPROTO;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int mdc_getattr(struct obd_export *exp, struct md_op_data *op_data,
@@ -220,24 +216,23 @@
 {
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	/* Single MDS without an LMV case */
 	if (op_data->op_flags & MF_GET_MDT_IDX) {
 		op_data->op_mds = 0;
-		RETURN(0);
+		return 0;
 	}
 	*request = NULL;
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_GETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -257,7 +252,7 @@
 		ptlrpc_req_finished(req);
 	else
 		*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_getattr_name(struct obd_export *exp, struct md_op_data *op_data,
@@ -265,13 +260,12 @@
 {
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	*request = NULL;
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_MDS_GETATTR_NAME);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
@@ -280,7 +274,7 @@
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR_NAME);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -303,7 +297,7 @@
 		ptlrpc_req_finished(req);
 	else
 		*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_is_subdir(struct obd_export *exp,
@@ -314,14 +308,12 @@
 	struct ptlrpc_request  *req;
 	int		     rc;
 
-	ENTRY;
-
 	*request = NULL;
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_MDS_IS_SUBDIR, LUSTRE_MDS_VERSION,
 					MDS_IS_SUBDIR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_is_subdir_pack(req, pfid, cfid, 0);
 	ptlrpc_request_set_replen(req);
@@ -331,7 +323,7 @@
 		ptlrpc_req_finished(req);
 	else
 		*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_xattr_common(struct obd_export *exp,const struct req_format *fmt,
@@ -345,12 +337,11 @@
 	int   xattr_namelen = 0;
 	char *tmp;
 	int   rc;
-	ENTRY;
 
 	*request = NULL;
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), fmt);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, oc);
 	if (xattr_name) {
@@ -367,7 +358,7 @@
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, opcode);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (opcode == MDS_REINT) {
@@ -377,12 +368,8 @@
 			 sizeof(struct mdt_rec_reint));
 		rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
 		rec->sx_opcode = REINT_SETXATTR;
-		/* TODO:
-		 *  cfs_curproc_fs{u,g}id() should replace
-		 *  current->fs{u,g}id for portability.
-		 */
-		rec->sx_fsuid  = current_fsuid();
-		rec->sx_fsgid  = current_fsgid();
+		rec->sx_fsuid  = from_kuid(&init_user_ns, current_fsuid());
+		rec->sx_fsgid  = from_kgid(&init_user_ns, current_fsgid());
 		rec->sx_cap    = cfs_curproc_cap_pack();
 		rec->sx_suppgid1 = suppgid;
 		rec->sx_suppgid2 = -1;
@@ -424,7 +411,7 @@
 		ptlrpc_req_finished(req);
 	else
 		*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_setxattr(struct obd_export *exp, const struct lu_fid *fid,
@@ -457,32 +444,31 @@
 	struct posix_acl       *acl;
 	void		   *buf;
 	int		     rc;
-	ENTRY;
 
 	if (!body->aclsize)
-		RETURN(0);
+		return 0;
 
 	buf = req_capsule_server_sized_get(pill, &RMF_ACL, body->aclsize);
 
 	if (!buf)
-		RETURN(-EPROTO);
+		return -EPROTO;
 
 	acl = posix_acl_from_xattr(&init_user_ns, buf, body->aclsize);
 	if (IS_ERR(acl)) {
 		rc = PTR_ERR(acl);
 		CERROR("convert xattr to acl: %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = posix_acl_valid(acl);
 	if (rc) {
 		CERROR("validate acl: %d\n", rc);
 		posix_acl_release(acl);
-		RETURN(rc);
+		return rc;
 	}
 
 	md->posix_acl = acl;
-	RETURN(0);
+	return 0;
 }
 #else
 #define mdc_unpack_acl(req, md) 0
@@ -494,7 +480,6 @@
 {
 	struct req_capsule *pill = &req->rq_pill;
 	int rc;
-	ENTRY;
 
 	LASSERT(md);
 	memset(md, 0, sizeof(*md));
@@ -546,7 +531,7 @@
 		if (md->body->eadatasize == 0) {
 			CDEBUG(D_INFO, "OBD_MD_FLDIREA is set, "
 			       "but eadatasize 0\n");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 		if (md->body->valid & OBD_MD_MEA) {
 			lmvsize = md->body->eadatasize;
@@ -611,7 +596,6 @@
 		md->oss_capa = oc;
 	}
 
-	EXIT;
 out:
 	if (rc) {
 		if (md->oss_capa) {
@@ -633,8 +617,7 @@
 
 int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
 {
-	ENTRY;
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -648,12 +631,10 @@
 	struct obd_client_handle *och;
 	struct lustre_handle old;
 	struct mdt_body *body;
-	ENTRY;
 
 	if (mod == NULL) {
 		DEBUG_REQ(D_ERROR, req,
 			  "Can't properly replay without open data.");
-		EXIT;
 		return;
 	}
 
@@ -687,7 +668,6 @@
 		DEBUG_REQ(D_HA, close_req, "updating close body with new fh");
 		epoch->handle = body->handle;
 	}
-	EXIT;
 }
 
 void mdc_commit_open(struct ptlrpc_request *req)
@@ -726,10 +706,9 @@
 	struct mdt_rec_create *rec;
 	struct mdt_body       *body;
 	struct obd_import     *imp = open_req->rq_import;
-	ENTRY;
 
 	if (!open_req->rq_replay)
-		RETURN(0);
+		return 0;
 
 	rec = req_capsule_client_get(&open_req->rq_pill, &RMF_REC_REINT);
 	body = req_capsule_server_get(&open_req->rq_pill, &RMF_MDT_BODY);
@@ -744,7 +723,7 @@
 		if (mod == NULL) {
 			DEBUG_REQ(D_ERROR, open_req,
 				  "Can't allocate md_open_data");
-			RETURN(0);
+			return 0;
 		}
 
 		/**
@@ -776,21 +755,20 @@
 	}
 
 	DEBUG_REQ(D_RPCTRACE, open_req, "Set up open replay data");
-	RETURN(0);
+	return 0;
 }
 
 int mdc_clear_open_replay_data(struct obd_export *exp,
 			       struct obd_client_handle *och)
 {
 	struct md_open_data *mod = och->och_mod;
-	ENTRY;
 
 	/**
 	 * It is possible to not have \var mod in a case of eviction between
 	 * lookup and ll_file_open().
 	 **/
 	if (mod == NULL)
-		RETURN(0);
+		return 0;
 
 	LASSERT(mod != LP_POISON);
 
@@ -798,7 +776,7 @@
 	och->och_mod = NULL;
 	obd_mod_put(mod);
 
-	RETURN(0);
+	return 0;
 }
 
 /* Prepares the request for the replay by the given reply */
@@ -823,19 +801,18 @@
 	struct obd_device     *obd = class_exp2obd(exp);
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	*request = NULL;
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_CLOSE);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_CLOSE);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	/* To avoid a livelock (bug 7034), we need to send CLOSE RPCs to a
@@ -916,7 +893,7 @@
 	}
 	*request = req;
 	mdc_close_handle_reply(req, op_data, rc);
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
@@ -925,18 +902,17 @@
 	struct obd_device     *obd = class_exp2obd(exp);
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_MDS_DONE_WRITING);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_DONE_WRITING);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (mod != NULL) {
@@ -983,7 +959,7 @@
 
 	mdc_close_handle_reply(req, op_data, rc);
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -997,7 +973,6 @@
 	int		      resends = 0;
 	struct l_wait_info       lwi;
 	int		      rc;
-	ENTRY;
 
 	*request = NULL;
 	init_waitqueue_head(&waitq);
@@ -1005,14 +980,14 @@
 restart_bulk:
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_READPAGE);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_READPAGE);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	req->rq_request_portal = MDS_READPAGE_PORTAL;
@@ -1022,7 +997,7 @@
 				    MDS_BULK_PORTAL);
 	if (desc == NULL) {
 		ptlrpc_request_free(req);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	/* NB req now owns desc and will free it when it gets freed */
@@ -1038,12 +1013,12 @@
 	if (rc) {
 		ptlrpc_req_finished(req);
 		if (rc != -ETIMEDOUT)
-			RETURN(rc);
+			return rc;
 
 		resends++;
 		if (!client_should_resend(resends, &exp->exp_obd->u.cli)) {
 			CERROR("too many resend retries, returning error\n");
-			RETURN(-EIO);
+			return -EIO;
 		}
 		lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(resends), NULL, NULL, NULL);
 		l_wait_event(waitq, 0, &lwi);
@@ -1055,7 +1030,7 @@
 					  req->rq_bulk->bd_nob_transferred);
 	if (rc < 0) {
 		ptlrpc_req_finished(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (req->rq_bulk->bd_nob_transferred & ~LU_PAGE_MASK) {
@@ -1063,11 +1038,11 @@
 			req->rq_bulk->bd_nob_transferred,
 			PAGE_CACHE_SIZE * op_data->op_npages);
 		ptlrpc_req_finished(req);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	*request = req;
-	RETURN(0);
+	return 0;
 }
 
 static int mdc_statfs(const struct lu_env *env,
@@ -1079,7 +1054,6 @@
 	struct obd_statfs     *msfs;
 	struct obd_import     *imp = NULL;
 	int		    rc;
-	ENTRY;
 
 	/*
 	 * Since the request might also come from lprocfs, so we need
@@ -1090,7 +1064,7 @@
 		imp = class_import_get(obd->u.cli.cl_import);
 	up_read(&obd->u.cli.cl_sem);
 	if (!imp)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_STATFS,
 					LUSTRE_MDS_VERSION, MDS_STATFS);
@@ -1118,7 +1092,6 @@
 		GOTO(out, rc = -EPROTO);
 
 	*osfs = *msfs;
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 output:
@@ -1133,15 +1106,15 @@
 	int rc;
 
 	if (gf->gf_pathlen > PATH_MAX)
-		RETURN(-ENAMETOOLONG);
+		return -ENAMETOOLONG;
 	if (gf->gf_pathlen < 2)
-		RETURN(-EOVERFLOW);
+		return -EOVERFLOW;
 
 	/* Key is KEY_FID2PATH + getinfo_fid2path description */
 	keylen = cfs_size_round(sizeof(KEY_FID2PATH)) + sizeof(*gf);
 	OBD_ALLOC(key, keylen);
 	if (key == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	memcpy(key, KEY_FID2PATH, sizeof(KEY_FID2PATH));
 	memcpy(key + cfs_size_round(sizeof(KEY_FID2PATH)), gf, sizeof(*gf));
 
@@ -1178,7 +1151,6 @@
 	struct hsm_progress_kernel	*req_hpk;
 	struct ptlrpc_request		*req;
 	int				 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_HSM_PROGRESS,
 					LUSTRE_MDS_VERSION, MDS_HSM_PROGRESS);
@@ -1193,6 +1165,7 @@
 		GOTO(out, rc = -EPROTO);
 
 	*req_hpk = *hpk;
+	req_hpk->hpk_errval = lustre_errno_hton(hpk->hpk_errval);
 
 	ptlrpc_request_set_replen(req);
 
@@ -1208,7 +1181,6 @@
 	__u32			*archive_mask;
 	struct ptlrpc_request	*req;
 	int			 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_HSM_CT_REGISTER,
 					LUSTRE_MDS_VERSION,
@@ -1242,19 +1214,18 @@
 	struct hsm_current_action	*req_hca;
 	struct ptlrpc_request		*req;
 	int				 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_MDS_HSM_ACTION);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_ACTION);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -1273,7 +1244,6 @@
 
 	*hca = *req_hca;
 
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -1283,7 +1253,6 @@
 {
 	struct ptlrpc_request	*req;
 	int			 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(imp, &RQF_MDS_HSM_CT_UNREGISTER,
 					LUSTRE_MDS_VERSION,
@@ -1309,19 +1278,18 @@
 	struct hsm_user_state	*req_hus;
 	struct ptlrpc_request	*req;
 	int			 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_MDS_HSM_STATE_GET);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_STATE_GET);
 	if (rc != 0) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -1339,7 +1307,6 @@
 
 	*hus = *req_hus;
 
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -1352,19 +1319,18 @@
 	struct hsm_state_set	*req_hss;
 	struct ptlrpc_request	*req;
 	int			 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 				   &RQF_MDS_HSM_STATE_SET);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_STATE_SET);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, &op_data->op_fid1, op_data->op_capa1,
@@ -1381,7 +1347,6 @@
 	rc = mdc_queue_wait(req);
 	GOTO(out, rc);
 
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -1396,7 +1361,6 @@
 	struct hsm_user_item	*req_hui;
 	char			*req_opaque;
 	int			 rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(imp, &RQF_MDS_HSM_REQUEST);
 	if (req == NULL)
@@ -1411,7 +1375,7 @@
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_HSM_REQUEST);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, NULL, NULL, OBD_MD_FLRMTPERM, 0, 0, 0);
@@ -1476,21 +1440,20 @@
 	struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr;
 	struct kuc_hdr *lh;
 	int len, rc;
-	ENTRY;
 
 	if (rec->cr_hdr.lrh_type != CHANGELOG_REC) {
 		rc = -EINVAL;
 		CERROR("%s: not a changelog rec %x/%d: rc = %d\n",
 		       cs->cs_obd->obd_name, rec->cr_hdr.lrh_type,
 		       rec->cr.cr_type, rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (rec->cr.cr_index < cs->cs_startrec) {
 		/* Skip entries earlier than what we are interested in */
 		CDEBUG(D_CHANGELOG, "rec="LPU64" start="LPU64"\n",
 		       rec->cr.cr_index, cs->cs_startrec);
-		RETURN(0);
+		return 0;
 	}
 
 	CDEBUG(D_CHANGELOG, LPU64" %02d%-5s "LPU64" 0x%x t="DFID" p="DFID
@@ -1509,7 +1472,7 @@
 	rc = libcfs_kkuc_msg_put(cs->cs_fp, lh);
 	CDEBUG(D_CHANGELOG, "kucmsg fp %p len %d rc %d\n", cs->cs_fp, len,rc);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_changelog_send_thread(void *csdata)
@@ -1608,13 +1571,12 @@
 	struct ptlrpc_request   *req;
 	struct obd_quotactl     *body;
 	int		      rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_MDS_QUOTACHECK, LUSTRE_MDS_VERSION,
 					MDS_QUOTACHECK);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	body = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
 	*body = *oqctl;
@@ -1628,7 +1590,7 @@
 	if (rc)
 		cli->cl_qchk_stat = rc;
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_quota_poll_check(struct obd_export *exp,
@@ -1636,7 +1598,6 @@
 {
 	struct client_obd *cli = &exp->exp_obd->u.cli;
 	int rc;
-	ENTRY;
 
 	qchk->obd_uuid = cli->cl_target_uuid;
 	memcpy(qchk->obd_type, LUSTRE_MDS_NAME, strlen(LUSTRE_MDS_NAME));
@@ -1645,7 +1606,7 @@
 	/* the client is not the previous one */
 	if (rc == CL_NOT_QUOTACHECKED)
 		rc = -EINTR;
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
@@ -1654,13 +1615,12 @@
 	struct ptlrpc_request   *req;
 	struct obd_quotactl     *oqc;
 	int		      rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_MDS_QUOTACTL, LUSTRE_MDS_VERSION,
 					MDS_QUOTACTL);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
 	*oqc = *oqctl;
@@ -1682,7 +1642,7 @@
 	}
 	ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_ioc_swap_layouts(struct obd_export *exp,
@@ -1692,7 +1652,6 @@
 	struct ptlrpc_request	*req;
 	int			 rc, count;
 	struct mdc_swap_layouts *msl, *payload;
-	ENTRY;
 
 	msl = op_data->op_data;
 
@@ -1711,7 +1670,7 @@
 				   &RQF_MDS_SWAP_LAYOUTS);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	mdc_set_capa_size(req, &RMF_CAPA1, op_data->op_capa1);
@@ -1720,7 +1679,7 @@
 	rc = mdc_prep_elc_req(exp, req, MDS_SWAP_LAYOUTS, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_swap_layouts_pack(req, op_data);
@@ -1735,7 +1694,6 @@
 	rc = ptlrpc_queue_wait(req);
 	if (rc)
 		GOTO(out, rc);
-	EXIT;
 
 out:
 	ptlrpc_req_finished(req);
@@ -1750,7 +1708,6 @@
 	struct obd_import *imp = obd->u.cli.cl_import;
 	struct llog_ctxt *ctxt;
 	int rc;
-	ENTRY;
 
 	if (!try_module_get(THIS_MODULE)) {
 		CERROR("Can't get module. Is it alive?");
@@ -1774,6 +1731,9 @@
 		GOTO(out, rc);
 	case LL_IOC_HSM_CT_START:
 		rc = mdc_ioc_hsm_ct_start(exp, karg);
+		/* ignore if it was already registered on this MDS. */
+		if (rc == -EEXIST)
+			rc = 0;
 		GOTO(out, rc);
 	case LL_IOC_HSM_PROGRESS:
 		rc = mdc_ioc_hsm_progress(exp, karg);
@@ -1855,7 +1815,7 @@
 
 		OBD_ALLOC_PTR(oqctl);
 		if (!oqctl)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		QCTL_COPY(oqctl, qctl);
 		rc = obd_quotactl(exp, oqctl);
@@ -1897,11 +1857,10 @@
 	struct ptlrpc_request  *req;
 	char		   *tmp;
 	int		     rc = -EINVAL;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(imp, &RQF_MDS_GET_INFO);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req_capsule_set_size(&req->rq_pill, &RMF_GETINFO_KEY,
 			     RCL_CLIENT, keylen);
@@ -1911,7 +1870,7 @@
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GET_INFO);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	tmp = req_capsule_client_get(&req->rq_pill, &RMF_GETINFO_KEY);
@@ -1936,7 +1895,7 @@
 	}
 	ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 static void lustre_swab_hai(struct hsm_action_item *h)
@@ -1991,19 +1950,10 @@
 	       lk->lk_uid, lk->lk_group, lk->lk_flags);
 
 	if (lk->lk_flags & LK_FLG_STOP) {
-		rc = libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group);
 		/* Unregister with the coordinator */
-		if (rc == 0)
-			rc = mdc_ioc_hsm_ct_unregister(imp);
+		rc = mdc_ioc_hsm_ct_unregister(imp);
 	} else {
-		struct file *fp = fget(lk->lk_wfd);
-
-		rc = libcfs_kkuc_group_add(fp, lk->lk_uid, lk->lk_group,
-					   lk->lk_data);
-		if (rc && fp)
-			fput(fp);
-		if (rc == 0)
-			rc = mdc_ioc_hsm_ct_register(imp, archive);
+		rc = mdc_ioc_hsm_ct_register(imp, archive);
 	}
 
 	return rc;
@@ -2019,19 +1969,18 @@
 	struct kuc_hdr		*lh = (struct kuc_hdr *)val;
 	struct hsm_action_list	*hal = (struct hsm_action_list *)(lh + 1);
 	int			 rc;
-	ENTRY;
 
 	if (len < sizeof(*lh) + sizeof(*hal)) {
 		CERROR("Short HSM message %d < %d\n", len,
 		       (int) (sizeof(*lh) + sizeof(*hal)));
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 	if (lh->kuc_magic == __swab16(KUC_MAGIC)) {
 		lustre_swab_kuch(lh);
 		lustre_swab_hal(hal);
 	} else if (lh->kuc_magic != KUC_MAGIC) {
 		CERROR("Bad magic %x!=%x\n", lh->kuc_magic, KUC_MAGIC);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	CDEBUG(D_HSM, " Received message mg=%x t=%d m=%d l=%d actions=%d "
@@ -2042,7 +1991,7 @@
 	/* Broadcast to HSM listeners */
 	rc = libcfs_kkuc_group_put(KUC_GRP_HSM, lh);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2084,11 +2033,10 @@
 {
 	struct obd_import	*imp = class_exp2cliimp(exp);
 	int			 rc;
-	ENTRY;
 
 	if (KEY_IS(KEY_READ_ONLY)) {
 		if (vallen != sizeof(int))
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		spin_lock(&imp->imp_lock);
 		if (*((int *)val)) {
@@ -2104,15 +2052,15 @@
 
 		rc = do_set_info_async(imp, MDS_SET_INFO, LUSTRE_MDS_VERSION,
 				       keylen, key, vallen, val, set);
-		RETURN(rc);
+		return rc;
 	}
 	if (KEY_IS(KEY_SPTLRPC_CONF)) {
 		sptlrpc_conf_client_adapt(exp->exp_obd);
-		RETURN(0);
+		return 0;
 	}
 	if (KEY_IS(KEY_FLUSH_CTX)) {
 		sptlrpc_import_flush_my_ctx(imp);
-		RETURN(0);
+		return 0;
 	}
 	if (KEY_IS(KEY_MDS_CONN)) {
 		/* mds-mds import */
@@ -2121,20 +2069,20 @@
 		spin_unlock(&imp->imp_lock);
 		imp->imp_client->cli_request_portal = MDS_MDS_PORTAL;
 		CDEBUG(D_OTHER, "%s: timeout / 2\n", exp->exp_obd->obd_name);
-		RETURN(0);
+		return 0;
 	}
 	if (KEY_IS(KEY_CHANGELOG_CLEAR)) {
 		rc = do_set_info_async(imp, MDS_SET_INFO, LUSTRE_MDS_VERSION,
 				       keylen, key, vallen, val, set);
-		RETURN(rc);
+		return rc;
 	}
 	if (KEY_IS(KEY_HSM_COPYTOOL_SEND)) {
 		rc = mdc_hsm_copytool_send(vallen, val);
-		RETURN(rc);
+		return rc;
 	}
 
 	CERROR("Unknown key %s\n", (char *)key);
-	RETURN(-EINVAL);
+	return -EINVAL;
 }
 
 int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
@@ -2147,30 +2095,30 @@
 		int mdsize, *max_easize;
 
 		if (*vallen != sizeof(int))
-			RETURN(-EINVAL);
+			return -EINVAL;
 		mdsize = *(int*)val;
 		if (mdsize > exp->exp_obd->u.cli.cl_max_mds_easize)
 			exp->exp_obd->u.cli.cl_max_mds_easize = mdsize;
 		max_easize = val;
 		*max_easize = exp->exp_obd->u.cli.cl_max_mds_easize;
-		RETURN(0);
+		return 0;
 	} else if (KEY_IS(KEY_CONN_DATA)) {
 		struct obd_import *imp = class_exp2cliimp(exp);
 		struct obd_connect_data *data = val;
 
 		if (*vallen != sizeof(*data))
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		*data = imp->imp_connect_data;
-		RETURN(0);
+		return 0;
 	} else if (KEY_IS(KEY_TGT_COUNT)) {
 		*((int *)val) = 1;
-		RETURN(0);
+		return 0;
 	}
 
 	rc = mdc_get_info_rpc(exp, keylen, key, *vallen, val);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_pin(struct obd_export *exp, const struct lu_fid *fid,
@@ -2180,18 +2128,17 @@
 	struct ptlrpc_request *req;
 	struct mdt_body       *body;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_PIN);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, oc);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_PIN);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, fid, oc, 0, 0, -1, flags);
@@ -2220,11 +2167,11 @@
 	}
 	handle->och_mod->mod_open_req = req; /* will be dropped by unpin */
 
-	RETURN(0);
+	return 0;
 
 err_out:
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_unpin(struct obd_export *exp, struct obd_client_handle *handle,
@@ -2233,12 +2180,11 @@
 	struct ptlrpc_request *req;
 	struct mdt_body       *body;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), &RQF_MDS_UNPIN,
 					LUSTRE_MDS_VERSION, MDS_UNPIN);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	body = req_capsule_client_get(&req->rq_pill, &RMF_MDT_BODY);
 	body->handle = handle->och_fh;
@@ -2257,7 +2203,7 @@
 	ptlrpc_req_finished(handle->och_mod->mod_open_req);
 
 	obd_mod_put(handle->och_mod);
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
@@ -2265,19 +2211,18 @@
 {
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	*request = NULL;
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_SYNC);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, oc);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_SYNC);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, fid, oc, 0, 0, -1, 0);
@@ -2289,7 +2234,7 @@
 		ptlrpc_req_finished(req);
 	else
 		*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_import_event(struct obd_device *obd, struct obd_import *imp,
@@ -2328,7 +2273,7 @@
 	}
 	case IMP_EVENT_ACTIVE:
 		rc = obd_notify_observer(obd, obd, OBD_NOTIFY_ACTIVE, NULL);
-		/* restore re-establish kuc registration after reconnecting */
+		/* redo the kuc registration after reconnecting */
 		if (rc == 0)
 			rc = mdc_kuc_reregister(imp);
 		break;
@@ -2342,7 +2287,7 @@
 		CERROR("Unknown import event %x\n", event);
 		LBUG();
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int mdc_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
@@ -2350,8 +2295,8 @@
 {
 	struct client_obd *cli = &exp->exp_obd->u.cli;
 	struct lu_client_seq *seq = cli->cl_seq;
-	ENTRY;
-	RETURN(seq_client_alloc_fid(NULL, seq, fid));
+
+	return seq_client_alloc_fid(NULL, seq, fid);
 }
 
 struct obd_uuid *mdc_get_uuid(struct obd_export *exp) {
@@ -2367,15 +2312,15 @@
 static int mdc_cancel_for_recovery(struct ldlm_lock *lock)
 {
 	if (lock->l_resource->lr_type != LDLM_IBITS)
-		RETURN(0);
+		return 0;
 
 	/* FIXME: if we ever get into a situation where there are too many
 	 * opened files with open locks on a single node, then we really
 	 * should replay these open locks to reget it */
 	if (lock->l_policy_data.l_inodebits.bits & MDS_INODELOCK_OPEN)
-		RETURN(0);
+		return 0;
 
-	RETURN(1);
+	return 1;
 }
 
 static int mdc_resource_inode_free(struct ldlm_resource *res)
@@ -2387,7 +2332,7 @@
 }
 
 struct ldlm_valblock_ops inode_lvbo = {
-	lvbo_free: mdc_resource_inode_free
+	.lvbo_free = mdc_resource_inode_free,
 };
 
 static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg)
@@ -2395,11 +2340,10 @@
 	struct client_obd *cli = &obd->u.cli;
 	struct lprocfs_static_vars lvars = { 0 };
 	int rc;
-	ENTRY;
 
 	OBD_ALLOC(cli->cl_rpc_lock, sizeof (*cli->cl_rpc_lock));
 	if (!cli->cl_rpc_lock)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	mdc_init_rpc_lock(cli->cl_rpc_lock);
 
 	ptlrpcd_addref();
@@ -2427,14 +2371,14 @@
 		CERROR("failed to setup llogging subsystems\n");
 	}
 
-	RETURN(rc);
+	return rc;
 
 err_close_lock:
 	OBD_FREE(cli->cl_close_lock, sizeof (*cli->cl_close_lock));
 err_rpc_lock:
 	OBD_FREE(cli->cl_rpc_lock, sizeof (*cli->cl_rpc_lock));
 	ptlrpcd_decref();
-	RETURN(rc);
+	return rc;
 }
 
 /* Initialize the default and maximum LOV EA and cookie sizes.  This allows
@@ -2446,7 +2390,6 @@
 {
 	struct obd_device *obd = exp->exp_obd;
 	struct client_obd *cli = &obd->u.cli;
-	ENTRY;
 
 	if (cli->cl_max_mds_easize < easize)
 		cli->cl_max_mds_easize = easize;
@@ -2457,13 +2400,12 @@
 	if (cli->cl_max_mds_cookiesize < cookiesize)
 		cli->cl_max_mds_cookiesize = cookiesize;
 
-	RETURN(0);
+	return 0;
 }
 
 static int mdc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
 {
 	int rc = 0;
-	ENTRY;
 
 	switch (stage) {
 	case OBD_CLEANUP_EARLY:
@@ -2482,7 +2424,7 @@
 			CERROR("failed to cleanup llogging subsystems\n");
 		break;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_cleanup(struct obd_device *obd)
@@ -2504,33 +2446,29 @@
 	struct llog_ctxt	*ctxt;
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(olg == &obd->obd_olg);
 
 	rc = llog_setup(NULL, obd, olg, LLOG_CHANGELOG_REPL_CTXT, tgt,
 			&llog_client_ops);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	ctxt = llog_group_get_ctxt(olg, LLOG_CHANGELOG_REPL_CTXT);
 	llog_initiator_connect(ctxt);
 	llog_ctxt_put(ctxt);
 
-	RETURN(0);
+	return 0;
 }
 
 static int mdc_llog_finish(struct obd_device *obd, int count)
 {
 	struct llog_ctxt *ctxt;
 
-	ENTRY;
-
 	ctxt = llog_get_context(obd, LLOG_CHANGELOG_REPL_CTXT);
 	if (ctxt)
 		llog_cleanup(NULL, ctxt);
 
-	RETURN(0);
+	return 0;
 }
 
 static int mdc_process_config(struct obd_device *obd, obd_count len, void *buf)
@@ -2559,21 +2497,20 @@
 {
 	struct ptlrpc_request  *req;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(client_is_remote(exp));
 
 	*request = NULL;
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_GETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	mdc_set_capa_size(req, &RMF_CAPA1, oc);
 
 	rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_GETATTR);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	mdc_pack_body(req, fid, oc, OBD_MD_FLRMTPERM, 0, suppgid, 0);
@@ -2588,7 +2525,7 @@
 		ptlrpc_req_finished(req);
 	else
 		*request = req;
-	RETURN(rc);
+	return rc;
 }
 
 static int mdc_interpret_renew_capa(const struct lu_env *env,
@@ -2598,7 +2535,6 @@
 	struct mdc_renew_capa_args *ra = args;
 	struct mdt_body *body = NULL;
 	struct lustre_capa *capa;
-	ENTRY;
 
 	if (status)
 		GOTO(out, capa = ERR_PTR(status));
@@ -2613,7 +2549,6 @@
 	capa = req_capsule_server_get(&req->rq_pill, &RMF_CAPA2);
 	if (!capa)
 		GOTO(out, capa = ERR_PTR(-EFAULT));
-	EXIT;
 out:
 	ra->ra_cb(ra->ra_oc, capa);
 	return 0;
@@ -2624,12 +2559,11 @@
 {
 	struct ptlrpc_request *req;
 	struct mdc_renew_capa_args *ra;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), &RQF_MDS_GETATTR,
 					LUSTRE_MDS_VERSION, MDS_GETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* NB, OBD_MD_FLOSSCAPA is set here, but it doesn't necessarily mean the
 	 * capa to renew is oss capa.
@@ -2643,7 +2577,7 @@
 	ra->ra_cb = cb;
 	req->rq_interpret_reply = mdc_interpret_renew_capa;
 	ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
-	RETURN(0);
+	return 0;
 }
 
 static int mdc_connect(const struct lu_env *env,
@@ -2737,7 +2671,7 @@
 
 	rc = class_register_type(&mdc_obd_ops, &mdc_md_ops, lvars.module_vars,
 				 LUSTRE_MDC_NAME, NULL);
-	RETURN(rc);
+	return rc;
 }
 
 static void /*__exit*/ mdc_exit(void)
diff --git a/drivers/staging/lustre/lustre/mgc/libmgc.c b/drivers/staging/lustre/lustre/mgc/libmgc.c
index 442146c..7b4947c 100644
--- a/drivers/staging/lustre/lustre/mgc/libmgc.c
+++ b/drivers/staging/lustre/lustre/mgc/libmgc.c
@@ -56,7 +56,6 @@
 static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 {
 	int rc;
-	ENTRY;
 
 	ptlrpcd_addref();
 
@@ -73,19 +72,18 @@
 		GOTO(err_cleanup, rc);
 	}
 
-	RETURN(rc);
+	return rc;
 
 err_cleanup:
 	client_obd_cleanup(obd);
 err_decref:
 	ptlrpcd_decref();
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
 {
 	int rc = 0;
-	ENTRY;
 
 	switch (stage) {
 	case OBD_CLEANUP_EARLY:
@@ -96,21 +94,20 @@
 			CERROR("failed to cleanup llogging subsystems\n");
 		break;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_cleanup(struct obd_device *obd)
 {
 	struct client_obd *cli = &obd->u.cli;
 	int rc;
-	ENTRY;
 
 	LASSERT(cli->cl_mgc_vfsmnt == NULL);
 
 	ptlrpcd_decref();
 
 	rc = client_obd_cleanup(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
@@ -118,32 +115,30 @@
 {
 	struct llog_ctxt *ctxt;
 	int rc;
-	ENTRY;
 
 	LASSERT(olg == &obd->obd_olg);
 	rc = llog_setup(NULL, obd, olg, LLOG_CONFIG_REPL_CTXT, tgt,
 			&llog_client_ops);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	ctxt = llog_group_get_ctxt(olg, LLOG_CONFIG_REPL_CTXT);
 	llog_initiator_connect(ctxt);
 	llog_ctxt_put(ctxt);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_llog_finish(struct obd_device *obd, int count)
 {
 	struct llog_ctxt *ctxt;
 
-	ENTRY;
 
 	ctxt = llog_get_context(obd, LLOG_CONFIG_REPL_CTXT);
 	if (ctxt)
 		llog_cleanup(NULL, ctxt);
 
-	RETURN(0);
+	return 0;
 }
 
 struct obd_ops mgc_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c
index 1105eaa..ebecec2 100644
--- a/drivers/staging/lustre/lustre/mgc/lproc_mgc.c
+++ b/drivers/staging/lustre/lustre/mgc/lproc_mgc.c
@@ -35,7 +35,6 @@
  */
 #define DEBUG_SUBSYSTEM S_CLASS
 
-#include <linux/version.h>
 #include <linux/vfs.h>
 #include <obd_class.h>
 #include <lprocfs_status.h>
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index c6c84d9..12a9ede 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -118,19 +118,16 @@
 /* Take a reference to a config log */
 static int config_log_get(struct config_llog_data *cld)
 {
-	ENTRY;
 	atomic_inc(&cld->cld_refcount);
 	CDEBUG(D_INFO, "log %s refs %d\n", cld->cld_logname,
 	       atomic_read(&cld->cld_refcount));
-	RETURN(0);
+	return 0;
 }
 
 /* Drop a reference to a config log.  When no longer referenced,
    we can free the config log data */
 static void config_log_put(struct config_llog_data *cld)
 {
-	ENTRY;
-
 	CDEBUG(D_INFO, "log %s refs %d\n", cld->cld_logname,
 	       atomic_read(&cld->cld_refcount));
 	LASSERT(atomic_read(&cld->cld_refcount) > 0);
@@ -152,8 +149,6 @@
 		class_export_put(cld->cld_mgcexp);
 		OBD_FREE(cld, sizeof(*cld) + strlen(cld->cld_logname) + 1);
 	}
-
-	EXIT;
 }
 
 /* Find a config log by name */
@@ -164,7 +159,6 @@
 	struct config_llog_data *cld;
 	struct config_llog_data *found = NULL;
 	void *		   instance;
-	ENTRY;
 
 	LASSERT(logname != NULL);
 
@@ -186,7 +180,7 @@
 		LASSERT(found->cld_stopping == 0 || cld_is_sptlrpc(found) == 0);
 	}
 	spin_unlock(&config_list_lock);
-	RETURN(found);
+	return found;
 }
 
 static
@@ -198,14 +192,13 @@
 {
 	struct config_llog_data *cld;
 	int		      rc;
-	ENTRY;
 
 	CDEBUG(D_MGC, "do adding config log %s:%p\n", logname,
 	       cfg ? cfg->cfg_instance : 0);
 
 	OBD_ALLOC(cld, sizeof(*cld) + strlen(logname) + 1);
 	if (!cld)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	strcpy(cld->cld_logname, logname);
 	if (cfg)
@@ -235,7 +228,7 @@
 
 	if (rc) {
 		config_log_put(cld);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	if (cld_is_sptlrpc(cld)) {
@@ -244,7 +237,7 @@
 			CERROR("failed processing sptlrpc log: %d\n", rc);
 	}
 
-	RETURN(cld);
+	return cld;
 }
 
 static struct config_llog_data *config_recover_log_add(struct obd_device *obd,
@@ -296,7 +289,6 @@
 	struct config_llog_data *sptlrpc_cld;
 	char		     seclogname[32];
 	char		    *ptr;
-	ENTRY;
 
 	CDEBUG(D_MGC, "adding config log %s:%p\n", logname, cfg->cfg_instance);
 
@@ -307,7 +299,7 @@
 	ptr = strrchr(logname, '-');
 	if (ptr == NULL || ptr - logname > 8) {
 		CERROR("logname %s is too long\n", logname);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	memcpy(seclogname, logname, ptr - logname);
@@ -319,7 +311,7 @@
 						CONFIG_T_SPTLRPC, NULL, NULL);
 		if (IS_ERR(sptlrpc_cld)) {
 			CERROR("can't create sptlrpc log: %s\n", seclogname);
-			RETURN(PTR_ERR(sptlrpc_cld));
+			return PTR_ERR(sptlrpc_cld);
 		}
 	}
 
@@ -327,7 +319,7 @@
 	if (IS_ERR(cld)) {
 		CERROR("can't create log: %s\n", logname);
 		config_log_put(sptlrpc_cld);
-		RETURN(PTR_ERR(cld));
+		return PTR_ERR(cld);
 	}
 
 	cld->cld_sptlrpc = sptlrpc_cld;
@@ -339,12 +331,12 @@
 		recover_cld = config_recover_log_add(obd, seclogname, cfg, sb);
 		if (IS_ERR(recover_cld)) {
 			config_log_put(cld);
-			RETURN(PTR_ERR(recover_cld));
+			return PTR_ERR(recover_cld);
 		}
 		cld->cld_recover = recover_cld;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 DEFINE_MUTEX(llog_process_lock);
@@ -357,11 +349,10 @@
 	struct config_llog_data *cld_sptlrpc = NULL;
 	struct config_llog_data *cld_recover = NULL;
 	int rc = 0;
-	ENTRY;
 
 	cld = config_log_find(logname, cfg);
 	if (cld == NULL)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	mutex_lock(&cld->cld_lock);
 	/*
@@ -375,7 +366,7 @@
 		mutex_unlock(&cld->cld_lock);
 		/* drop the ref from the find */
 		config_log_put(cld);
-		RETURN(rc);
+		return rc;
 	}
 
 	cld->cld_stopping = 1;
@@ -406,7 +397,7 @@
 
 	CDEBUG(D_MGC, "end config log %s (%d)\n", logname ? logname : "client",
 	       rc);
-	RETURN(rc);
+	return rc;
 }
 
 int lprocfs_mgc_rd_ir_state(struct seq_file *m, void *data)
@@ -415,7 +406,6 @@
 	struct obd_import       *imp = obd->u.cli.cl_import;
 	struct obd_connect_data *ocd = &imp->imp_connect_data;
 	struct config_llog_data *cld;
-	ENTRY;
 
 	seq_printf(m, "imperative_recovery: %s\n",
 		      OCD_HAS_FLAG(ocd, IMP_RECOV) ? "ENABLED" : "DISABLED");
@@ -431,7 +421,7 @@
 	}
 	spin_unlock(&config_list_lock);
 
-	RETURN(0);
+	return 0;
 }
 
 /* reenqueue any lost locks */
@@ -445,7 +435,6 @@
 
 static void do_requeue(struct config_llog_data *cld)
 {
-	ENTRY;
 	LASSERT(atomic_read(&cld->cld_refcount) > 0);
 
 	/* Do not run mgc_process_log on a disconnected export or an
@@ -460,8 +449,6 @@
 		       cld->cld_logname);
 	}
 	up_read(&cld->cld_mgcexp->exp_obd->u.cli.cl_sem);
-
-	EXIT;
 }
 
 /* this timeout represents how many seconds MGC should wait before
@@ -474,7 +461,6 @@
 static int mgc_requeue_thread(void *data)
 {
 	int rc = 0;
-	ENTRY;
 
 	CDEBUG(D_MGC, "Starting requeue thread\n");
 
@@ -556,15 +542,13 @@
 	complete(&rq_exit);
 
 	CDEBUG(D_MGC, "Ending requeue thread\n");
-	RETURN(rc);
+	return rc;
 }
 
 /* Add a cld to the list to requeue.  Start the requeue thread if needed.
    We are responsible for dropping the config log reference from here on out. */
 static void mgc_requeue_add(struct config_llog_data *cld)
 {
-	ENTRY;
-
 	CDEBUG(D_INFO, "log %s: requeue (r=%d sp=%d st=%x)\n",
 	       cld->cld_logname, atomic_read(&cld->cld_refcount),
 	       cld->cld_stopping, rq_state);
@@ -573,7 +557,7 @@
 	mutex_lock(&cld->cld_lock);
 	if (cld->cld_stopping || cld->cld_lostlock) {
 		mutex_unlock(&cld->cld_lock);
-		RETURN_EXIT;
+		return;
 	}
 	/* this refcount will be released in mgc_requeue_thread. */
 	config_log_get(cld);
@@ -591,7 +575,6 @@
 		spin_unlock(&config_list_lock);
 		wake_up(&rq_waitq);
 	}
-	EXIT;
 }
 
 /********************** class fns **********************/
@@ -605,7 +588,6 @@
 	struct dentry *dentry;
 	char *label;
 	int err = 0;
-	ENTRY;
 
 	LASSERT(lsi);
 	LASSERT(lsi->lsi_srv_mnt == mnt);
@@ -620,7 +602,7 @@
 		up(&cli->cl_mgc_sem);
 		CERROR("%s: No fstype %s: rc = %ld\n", lsi->lsi_fstype,
 		       obd->obd_name, PTR_ERR(obd->obd_fsops));
-		RETURN(PTR_ERR(obd->obd_fsops));
+		return PTR_ERR(obd->obd_fsops);
 	}
 
 	cli->cl_mgc_vfsmnt = mnt;
@@ -654,21 +636,20 @@
 		CDEBUG(D_MGC, "MGC using disk labelled=%s\n", label);
 
 	/* We keep the cl_mgc_sem until mgc_fs_cleanup */
-	RETURN(0);
+	return 0;
 
 err_ops:
 	fsfilt_put_ops(obd->obd_fsops);
 	obd->obd_fsops = NULL;
 	cli->cl_mgc_vfsmnt = NULL;
 	up(&cli->cl_mgc_sem);
-	RETURN(err);
+	return err;
 }
 
 static int mgc_fs_cleanup(struct obd_device *obd)
 {
 	struct client_obd *cli = &obd->u.cli;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(cli->cl_mgc_vfsmnt != NULL);
 
@@ -687,14 +668,13 @@
 
 	up(&cli->cl_mgc_sem);
 
-	RETURN(rc);
+	return rc;
 }
 
 static atomic_t mgc_count = ATOMIC_INIT(0);
 static int mgc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
 {
 	int rc = 0;
-	ENTRY;
 
 	switch (stage) {
 	case OBD_CLEANUP_EARLY:
@@ -719,14 +699,13 @@
 			CERROR("failed to cleanup llogging subsystems\n");
 		break;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_cleanup(struct obd_device *obd)
 {
 	struct client_obd *cli = &obd->u.cli;
 	int rc;
-	ENTRY;
 
 	LASSERT(cli->cl_mgc_vfsmnt == NULL);
 
@@ -740,14 +719,13 @@
 	ptlrpcd_decref();
 
 	rc = client_obd_cleanup(obd);
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 {
 	struct lprocfs_static_vars lvars;
 	int rc;
-	ENTRY;
 
 	ptlrpcd_addref();
 
@@ -782,13 +760,13 @@
 		rc = 0;
 	}
 
-	RETURN(rc);
+	return rc;
 
 err_cleanup:
 	client_obd_cleanup(obd);
 err_decref:
 	ptlrpcd_decref();
-	RETURN(rc);
+	return rc;
 }
 
 /* based on ll_mdc_blocking_ast */
@@ -798,7 +776,6 @@
 	struct lustre_handle lockh;
 	struct config_llog_data *cld = (struct config_llog_data *)data;
 	int rc = 0;
-	ENTRY;
 
 	switch (flag) {
 	case LDLM_CB_BLOCKING:
@@ -847,7 +824,7 @@
 		LBUG();
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Not sure where this should go... */
@@ -862,18 +839,17 @@
 	struct ptlrpc_request *req;
 	struct mgs_send_param *req_msp, *rep_msp;
 	int rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_MGS_SET_INFO, LUSTRE_MGS_VERSION,
 					MGS_SET_INFO);
 	if (!req)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req_msp = req_capsule_client_get(&req->rq_pill, &RMF_MGS_SEND_PARAM);
 	if (!req_msp) {
 		ptlrpc_req_finished(req);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	memcpy(req_msp, msp, sizeof(*req_msp));
@@ -889,7 +865,7 @@
 
 	ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Take a config lock so we can get cancel notifications */
@@ -900,12 +876,15 @@
 		       struct lustre_handle *lockh)
 {
 	struct config_llog_data *cld = (struct config_llog_data *)data;
-	struct ldlm_enqueue_info einfo = { type, mode, mgc_blocking_ast,
-			 ldlm_completion_ast, NULL, NULL, NULL };
+	struct ldlm_enqueue_info einfo = {
+		.ei_type	= type,
+		.ei_mode	= mode,
+		.ei_cb_bl	= mgc_blocking_ast,
+		.ei_cb_cp	= ldlm_completion_ast,
+	};
 	struct ptlrpc_request *req;
 	int short_limit = cld_is_sptlrpc(cld);
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_MGC, "Enqueue for %s (res "LPX64")\n", cld->cld_logname,
 	       cld->cld_resid.name[0]);
@@ -916,7 +895,7 @@
 					&RQF_LDLM_ENQUEUE, LUSTRE_DLM_VERSION,
 					LDLM_ENQUEUE);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER, 0);
 	ptlrpc_request_set_replen(req);
@@ -934,17 +913,15 @@
 	/* A failed enqueue should still call the mgc_blocking_ast,
 	   where it will be requeued if needed ("grant failed"). */
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_cancel(struct obd_export *exp, struct lov_stripe_md *md,
 		      __u32 mode, struct lustre_handle *lockh)
 {
-	ENTRY;
-
 	ldlm_lock_decref(lockh, mode);
 
-	RETURN(0);
+	return 0;
 }
 
 static void mgc_notify_active(struct obd_device *unused)
@@ -965,18 +942,17 @@
 	struct ptlrpc_request  *req;
 	struct mgs_target_info *req_mti, *rep_mti;
 	int		     rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_MGS_TARGET_REG, LUSTRE_MGS_VERSION,
 					MGS_TARGET_REG);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req_mti = req_capsule_client_get(&req->rq_pill, &RMF_MGS_TARGET_INFO);
 	if (!req_mti) {
 		ptlrpc_req_finished(req);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	memcpy(req_mti, mti, sizeof(*req_mti));
@@ -995,7 +971,7 @@
 	}
 	ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 int mgc_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -1003,14 +979,13 @@
 		       void *val, struct ptlrpc_request_set *set)
 {
 	int rc = -EINVAL;
-	ENTRY;
 
 	/* Turn off initial_recov after we try all backup servers once */
 	if (KEY_IS(KEY_INIT_RECOV_BACKUP)) {
 		struct obd_import *imp = class_exp2cliimp(exp);
 		int value;
 		if (vallen != sizeof(int))
-			RETURN(-EINVAL);
+			return -EINVAL;
 		value = *(int *)val;
 		CDEBUG(D_MGC, "InitRecov %s %d/d%d:i%d:r%d:or%d:%s\n",
 		       imp->imp_obd->obd_name, value,
@@ -1021,46 +996,46 @@
 		if ((imp->imp_state != LUSTRE_IMP_FULL &&
 		     imp->imp_state != LUSTRE_IMP_NEW) || value > 1)
 			ptlrpc_reconnect_import(imp);
-		RETURN(0);
+		return 0;
 	}
 	/* FIXME move this to mgc_process_config */
 	if (KEY_IS(KEY_REGISTER_TARGET)) {
 		struct mgs_target_info *mti;
 		if (vallen != sizeof(struct mgs_target_info))
-			RETURN(-EINVAL);
+			return -EINVAL;
 		mti = (struct mgs_target_info *)val;
 		CDEBUG(D_MGC, "register_target %s %#x\n",
 		       mti->mti_svname, mti->mti_flags);
 		rc =  mgc_target_register(exp, mti);
-		RETURN(rc);
+		return rc;
 	}
 	if (KEY_IS(KEY_SET_FS)) {
 		struct super_block *sb = (struct super_block *)val;
 		struct lustre_sb_info *lsi;
 		if (vallen != sizeof(struct super_block))
-			RETURN(-EINVAL);
+			return -EINVAL;
 		lsi = s2lsi(sb);
 		rc = mgc_fs_setup(exp->exp_obd, sb, lsi->lsi_srv_mnt);
 		if (rc) {
 			CERROR("set_fs got %d\n", rc);
 		}
-		RETURN(rc);
+		return rc;
 	}
 	if (KEY_IS(KEY_CLEAR_FS)) {
 		if (vallen != 0)
-			RETURN(-EINVAL);
+			return -EINVAL;
 		rc = mgc_fs_cleanup(exp->exp_obd);
 		if (rc) {
 			CERROR("clear_fs got %d\n", rc);
 		}
-		RETURN(rc);
+		return rc;
 	}
 	if (KEY_IS(KEY_SET_INFO)) {
 		struct mgs_send_param *msp;
 
 		msp = (struct mgs_send_param *)val;
 		rc =  mgc_set_mgs_param(exp, msp);
-		RETURN(rc);
+		return rc;
 	}
 	if (KEY_IS(KEY_MGSSEC)) {
 		struct client_obd     *cli = &exp->exp_obd->u.cli;
@@ -1075,7 +1050,7 @@
 		 */
 		if (vallen == 0) {
 			if (cli->cl_flvr_mgc.sf_rpc != SPTLRPC_FLVR_INVALID)
-				RETURN(0);
+				return 0;
 			val = "null";
 			vallen = 4;
 		}
@@ -1084,7 +1059,7 @@
 		if (rc) {
 			CERROR("invalid sptlrpc flavor %s to MGS\n",
 			       (char *) val);
-			RETURN(rc);
+			return rc;
 		}
 
 		/*
@@ -1103,10 +1078,10 @@
 				       (char *) val, str);
 			rc = -EPERM;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_get_info(const struct lu_env *env, struct obd_export *exp,
@@ -1167,7 +1142,7 @@
 		CERROR("Unknown import event %#x\n", event);
 		LBUG();
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_llog_init(struct obd_device *obd, struct obd_llog_group *olg,
@@ -1175,7 +1150,6 @@
 {
 	struct llog_ctxt *ctxt;
 	int rc;
-	ENTRY;
 
 	LASSERT(olg == &obd->obd_olg);
 
@@ -1192,20 +1166,18 @@
 	llog_initiator_connect(ctxt);
 	llog_ctxt_put(ctxt);
 
-	RETURN(0);
+	return 0;
 out:
 	ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
 	if (ctxt)
 		llog_cleanup(NULL, ctxt);
-	RETURN(rc);
+	return rc;
 }
 
 static int mgc_llog_finish(struct obd_device *obd, int count)
 {
 	struct llog_ctxt *ctxt;
 
-	ENTRY;
-
 	ctxt = llog_get_context(obd, LLOG_CONFIG_REPL_CTXT);
 	if (ctxt)
 		llog_cleanup(NULL, ctxt);
@@ -1213,7 +1185,7 @@
 	ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
 	if (ctxt)
 		llog_cleanup(NULL, ctxt);
-	RETURN(0);
+	return 0;
 }
 
 enum {
@@ -1238,14 +1210,13 @@
 	int   pos;
 	int   rc  = 0;
 	int   off = 0;
-	ENTRY;
 
 	LASSERT(cfg->cfg_instance != NULL);
 	LASSERT(cfg->cfg_sb == cfg->cfg_instance);
 
 	OBD_ALLOC(inst, PAGE_CACHE_SIZE);
 	if (inst == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (!IS_SERVER(lsi)) {
 		pos = snprintf(inst, PAGE_CACHE_SIZE, "%p", cfg->cfg_instance);
@@ -1259,7 +1230,7 @@
 					PAGE_CACHE_SIZE);
 		if (rc) {
 			OBD_FREE(inst, PAGE_CACHE_SIZE);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		pos = strlen(inst);
 	}
@@ -1417,7 +1388,7 @@
 	}
 
 	OBD_FREE(inst, PAGE_CACHE_SIZE);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1439,7 +1410,6 @@
 	int i;
 	int ealen;
 	int rc;
-	ENTRY;
 
 	/* allocate buffer for bulk transfer.
 	 * if this is the first time for this mgs to read logs,
@@ -1582,8 +1552,6 @@
 	int rc = 0, must_pop = 0;
 	bool sptlrpc_started = false;
 
-	ENTRY;
-
 	LASSERT(cld);
 	LASSERT(mutex_is_locked(&cld->cld_lock));
 
@@ -1592,7 +1560,7 @@
 	 * read it up here.
 	 */
 	if (cld_is_sptlrpc(cld) && local_only)
-		RETURN(0);
+		return 0;
 
 	if (cld->cld_cfg.cfg_sb)
 		lsi = s2lsi(cld->cld_cfg.cfg_sb);
@@ -1600,12 +1568,12 @@
 	ctxt = llog_get_context(mgc, LLOG_CONFIG_REPL_CTXT);
 	if (!ctxt) {
 		CERROR("missing llog context\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	OBD_ALLOC_PTR(saved_ctxt);
 	if (saved_ctxt == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	lctxt = llog_get_context(mgc, LLOG_CONFIG_ORIG_CTXT);
 
@@ -1623,7 +1591,6 @@
 	   be updated here. */
 	rc = class_config_parse_llog(NULL, ctxt, cld->cld_logname,
 				     &cld->cld_cfg);
-	EXIT;
 
 out_pop:
 	llog_ctxt_put(ctxt);
@@ -1647,7 +1614,7 @@
 					  strlen("-sptlrpc"));
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /** Get a config log from the MGS and process it.
@@ -1659,7 +1626,6 @@
 	struct lustre_handle lockh = { 0 };
 	__u64 flags = LDLM_FL_NO_LRU;
 	int rc = 0, rcl;
-	ENTRY;
 
 	LASSERT(cld);
 
@@ -1670,7 +1636,7 @@
 	mutex_lock(&cld->cld_lock);
 	if (cld->cld_stopping) {
 		mutex_unlock(&cld->cld_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	OBD_FAIL_TIMEOUT(OBD_FAIL_MGC_PAUSE_PROCESS_LOG, 20);
@@ -1719,7 +1685,7 @@
 			CERROR("Can't drop cfg lock: %d\n", rcl);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1733,7 +1699,6 @@
 	struct config_llog_instance *cfg = NULL;
 	char *logname;
 	int rc = 0;
-	ENTRY;
 
 	switch(lcfg->lcfg_command) {
 	case LCFG_LOV_ADD_OBD: {
@@ -1818,7 +1783,7 @@
 	}
 	}
 out:
-	RETURN(rc);
+	return rc;
 }
 
 struct obd_ops mgc_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/obdclass/Makefile b/drivers/staging/lustre/lustre/obdclass/Makefile
index b80c13c..8a0e08c 100644
--- a/drivers/staging/lustre/lustre/obdclass/Makefile
+++ b/drivers/staging/lustre/lustre/obdclass/Makefile
@@ -3,7 +3,7 @@
 obdclass-y := linux/linux-module.o linux/linux-obdo.o linux/linux-sysctl.o \
 	      llog.o llog_cat.o llog_obd.o llog_swab.o class_obd.o debug.o \
 	      genops.o uuid.o llog_ioctl.o lprocfs_status.o		   \
-	      lprocfs_jobstats.o lustre_handles.o lustre_peer.o llog_osd.o \
+	      lustre_handles.o lustre_peer.o llog_osd.o \
 	      local_storage.o statfs_pack.o obdo.o obd_config.o obd_mount.o\
 	      mea.o lu_object.o dt_object.o capa.o cl_object.o   \
 	      cl_page.o cl_lock.o cl_io.o lu_ref.o acl.o idmap.o	   \
diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c
index c2a6702..f0bb632 100644
--- a/drivers/staging/lustre/lustre/obdclass/acl.c
+++ b/drivers/staging/lustre/lustre/obdclass/acl.c
@@ -144,10 +144,9 @@
 {
 	int count, i, esize;
 	ext_acl_xattr_header *new;
-	ENTRY;
 
 	if (unlikely(size < 0))
-		RETURN(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 	else if (!size)
 		count = 0;
 	else
@@ -155,7 +154,7 @@
 	esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
 	OBD_ALLOC(new, esize);
 	if (unlikely(new == NULL))
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	new->a_count = cpu_to_le32(count);
 	for (i = 0; i < count; i++) {
@@ -165,7 +164,7 @@
 		new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
 	}
 
-	RETURN(new);
+	return new;
 }
 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
 
@@ -178,16 +177,15 @@
 	int count, i, j, rc = 0;
 	__u32 id;
 	posix_acl_xattr_header *new;
-	ENTRY;
 
 	if (unlikely(size < 0))
-		RETURN(-EINVAL);
+		return -EINVAL;
 	else if (!size)
-		RETURN(0);
+		return 0;
 
 	OBD_ALLOC(new, size);
 	if (unlikely(new == NULL))
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
 	count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
@@ -228,7 +226,6 @@
 		*out = new;
 		rc = 0;
 	}
-	EXIT;
 
 _out:
 	if (rc) {
@@ -302,7 +299,6 @@
 	posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
 	posix_acl_xattr_header *new;
 	ext_acl_xattr_entry *ee, ae;
-	ENTRY;
 
 	lustre_posix_acl_cpu_to_le(&pe, &pe);
 	ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
@@ -312,7 +308,7 @@
 		posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
 		OBD_ALLOC(new, posix_size);
 		if (unlikely(new == NULL))
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
 		for (i = 0, j = 0; i < ext_count; i++) {
@@ -349,7 +345,7 @@
 		int ori_posix_count;
 
 		if (unlikely(size < 0))
-			RETURN(-EINVAL);
+			return -EINVAL;
 		else if (!size)
 			ori_posix_count = 0;
 		else
@@ -360,7 +356,7 @@
 			CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
 		OBD_ALLOC(new, posix_size);
 		if (unlikely(new == NULL))
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
 		/* 1. process the unchanged ACL entries
@@ -397,7 +393,6 @@
 		*out = new;
 		rc = 0;
 	}
-	EXIT;
 
 _out:
 	if (rc) {
@@ -420,10 +415,9 @@
 	posix_acl_xattr_entry pae;
 	ext_acl_xattr_header *new;
 	ext_acl_xattr_entry *ee, eae;
-	ENTRY;
 
 	if (unlikely(size < 0))
-		RETURN(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 	else if (!size)
 		posix_count = 0;
 	else
@@ -434,7 +428,7 @@
 
 	OBD_ALLOC(new, ext_size);
 	if (unlikely(new == NULL))
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	for (i = 0, j = 0; i < posix_count; i++) {
 		lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
@@ -532,7 +526,6 @@
 	new->a_count = cpu_to_le32(j);
 	/* free unused space. */
 	rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
-	EXIT;
 
 out:
 	if (rc) {
diff --git a/drivers/staging/lustre/lustre/obdclass/capa.c b/drivers/staging/lustre/lustre/obdclass/capa.c
index 3e532f5..68d797b 100644
--- a/drivers/staging/lustre/lustre/obdclass/capa.c
+++ b/drivers/staging/lustre/lustre/obdclass/capa.c
@@ -42,12 +42,12 @@
 
 #define DEBUG_SUBSYSTEM S_SEC
 
-#include <linux/version.h>
 #include <linux/fs.h>
 #include <asm/unistd.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/crypto.h>
 
 #include <obd_class.h>
 #include <lustre_debug.h>
@@ -77,6 +77,12 @@
 EXPORT_SYMBOL(capa_lock);
 EXPORT_SYMBOL(capa_count);
 
+static inline
+unsigned int ll_crypto_tfm_alg_min_keysize(struct crypto_blkcipher *tfm)
+{
+	return crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher.min_keysize;
+}
+
 struct hlist_head *init_capa_hash(void)
 {
 	struct hlist_head *hash;
@@ -235,9 +241,26 @@
 }
 EXPORT_SYMBOL(capa_lookup);
 
+static inline int ll_crypto_hmac(struct crypto_hash *tfm,
+				 u8 *key, unsigned int *keylen,
+				 struct scatterlist *sg,
+				 unsigned int size, u8 *result)
+{
+	struct hash_desc desc;
+	int	      rv;
+	desc.tfm   = tfm;
+	desc.flags = 0;
+	rv = crypto_hash_setkey(desc.tfm, key, *keylen);
+	if (rv) {
+		CERROR("failed to hash setkey: %d\n", rv);
+		return rv;
+	}
+	return crypto_hash_digest(&desc, sg, size, result);
+}
+
 int capa_hmac(__u8 *hmac, struct lustre_capa *capa, __u8 *key)
 {
-	struct ll_crypto_hash *tfm;
+	struct crypto_hash *tfm;
 	struct capa_hmac_alg  *alg;
 	int keylen;
 	struct scatterlist sl;
@@ -249,7 +272,7 @@
 
 	alg = &capa_hmac_algs[capa_alg(capa)];
 
-	tfm = ll_crypto_alloc_hash(alg->ha_name, 0, 0);
+	tfm = crypto_alloc_hash(alg->ha_name, 0, 0);
 	if (!tfm) {
 		CERROR("crypto_alloc_tfm failed, check whether your kernel"
 		       "has crypto support!\n");
@@ -262,7 +285,7 @@
 		    (unsigned long)(capa) % PAGE_CACHE_SIZE);
 
 	ll_crypto_hmac(tfm, key, &keylen, &sl, sl.length, hmac);
-	ll_crypto_free_hash(tfm);
+	crypto_free_hash(tfm);
 
 	return 0;
 }
@@ -270,21 +293,20 @@
 
 int capa_encrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
 {
-	struct ll_crypto_cipher *tfm;
+	struct crypto_blkcipher *tfm;
 	struct scatterlist sd;
 	struct scatterlist ss;
 	struct blkcipher_desc desc;
 	unsigned int min;
 	int rc;
 	char alg[CRYPTO_MAX_ALG_NAME+1] = "aes";
-	ENTRY;
 
 	/* passing "aes" in a variable instead of a constant string keeps gcc
 	 * 4.3.2 happy */
-	tfm = ll_crypto_alloc_blkcipher(alg, 0, 0 );
+	tfm = crypto_alloc_blkcipher(alg, 0, 0 );
 	if (IS_ERR(tfm)) {
 		CERROR("failed to load transform for aes\n");
-		RETURN(PTR_ERR(tfm));
+		return PTR_ERR(tfm);
 	}
 
 	min = ll_crypto_tfm_alg_min_keysize(tfm);
@@ -293,7 +315,7 @@
 		GOTO(out, rc = -EINVAL);
 	}
 
-	rc = ll_crypto_blkcipher_setkey(tfm, key, min);
+	rc = crypto_blkcipher_setkey(tfm, key, min);
 	if (rc) {
 		CERROR("failed to setting key for aes\n");
 		GOTO(out, rc);
@@ -307,37 +329,34 @@
 	desc.tfm   = tfm;
 	desc.info  = NULL;
 	desc.flags = 0;
-	rc = ll_crypto_blkcipher_encrypt(&desc, &sd, &ss, 16);
+	rc = crypto_blkcipher_encrypt(&desc, &sd, &ss, 16);
 	if (rc) {
 		CERROR("failed to encrypt for aes\n");
 		GOTO(out, rc);
 	}
 
-	EXIT;
-
 out:
-	ll_crypto_free_blkcipher(tfm);
+	crypto_free_blkcipher(tfm);
 	return rc;
 }
 EXPORT_SYMBOL(capa_encrypt_id);
 
 int capa_decrypt_id(__u32 *d, __u32 *s, __u8 *key, int keylen)
 {
-	struct ll_crypto_cipher *tfm;
+	struct crypto_blkcipher *tfm;
 	struct scatterlist sd;
 	struct scatterlist ss;
 	struct blkcipher_desc desc;
 	unsigned int min;
 	int rc;
 	char alg[CRYPTO_MAX_ALG_NAME+1] = "aes";
-	ENTRY;
 
 	/* passing "aes" in a variable instead of a constant string keeps gcc
 	 * 4.3.2 happy */
-	tfm = ll_crypto_alloc_blkcipher(alg, 0, 0 );
+	tfm = crypto_alloc_blkcipher(alg, 0, 0 );
 	if (IS_ERR(tfm)) {
 		CERROR("failed to load transform for aes\n");
-		RETURN(PTR_ERR(tfm));
+		return PTR_ERR(tfm);
 	}
 
 	min = ll_crypto_tfm_alg_min_keysize(tfm);
@@ -346,7 +365,7 @@
 		GOTO(out, rc = -EINVAL);
 	}
 
-	rc = ll_crypto_blkcipher_setkey(tfm, key, min);
+	rc = crypto_blkcipher_setkey(tfm, key, min);
 	if (rc) {
 		CERROR("failed to setting key for aes\n");
 		GOTO(out, rc);
@@ -361,16 +380,14 @@
 	desc.tfm   = tfm;
 	desc.info  = NULL;
 	desc.flags = 0;
-	rc = ll_crypto_blkcipher_decrypt(&desc, &sd, &ss, 16);
+	rc = crypto_blkcipher_decrypt(&desc, &sd, &ss, 16);
 	if (rc) {
 		CERROR("failed to decrypt for aes\n");
 		GOTO(out, rc);
 	}
 
-	EXIT;
-
 out:
-	ll_crypto_free_blkcipher(tfm);
+	crypto_free_blkcipher(tfm);
 	return rc;
 }
 EXPORT_SYMBOL(capa_decrypt_id);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c
index 75c9be8..4269793 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_io.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c
@@ -106,7 +106,6 @@
 
 	LINVRNT(cl_io_type_is_valid(io->ci_type));
 	LINVRNT(cl_io_invariant(io));
-	ENTRY;
 
 	while (!list_empty(&io->ci_layers)) {
 		slice = container_of(io->ci_layers.prev, struct cl_io_slice,
@@ -144,7 +143,6 @@
 	default:
 		LBUG();
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_io_fini);
 
@@ -157,7 +155,6 @@
 	LINVRNT(io->ci_state == CIS_ZERO || io->ci_state == CIS_FINI);
 	LINVRNT(cl_io_type_is_valid(iot));
 	LINVRNT(cl_io_invariant(io));
-	ENTRY;
 
 	io->ci_type = iot;
 	INIT_LIST_HEAD(&io->ci_lockset.cls_todo);
@@ -175,7 +172,7 @@
 	}
 	if (result == 0)
 		io->ci_state = CIS_INIT;
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -228,7 +225,6 @@
 {
 	LINVRNT(iot == CIT_READ || iot == CIT_WRITE);
 	LINVRNT(io->ci_obj != NULL);
-	ENTRY;
 
 	LU_OBJECT_HEADER(D_VFSTRACE, env, &io->ci_obj->co_lu,
 			 "io range: %u ["LPU64", "LPU64") %u %u\n",
@@ -236,7 +232,7 @@
 			 io->u.ci_rw.crw_nonblock, io->u.ci_wr.wr_append);
 	io->u.ci_rw.crw_pos    = pos;
 	io->u.ci_rw.crw_count  = count;
-	RETURN(cl_io_init(env, io, iot, io->ci_obj));
+	return cl_io_init(env, io, iot, io->ci_obj);
 }
 EXPORT_SYMBOL(cl_io_rw_init);
 
@@ -288,7 +284,6 @@
 {
 	int done = 0;
 
-	ENTRY;
 	/* hidden treasure: bubble sort for now. */
 	do {
 		struct cl_io_lock_link *curr;
@@ -325,7 +320,6 @@
 			prev = curr;
 		}
 	} while (!done);
-	EXIT;
 }
 
 /**
@@ -339,12 +333,11 @@
 {
        struct cl_io_lock_link *scan;
 
-       ENTRY;
        list_for_each_entry(scan, queue, cill_linkage) {
 	       if (cl_lock_descr_match(&scan->cill_descr, need))
-		       RETURN(+1);
+		       return +1;
        }
-       RETURN(0);
+       return 0;
 }
 EXPORT_SYMBOL(cl_queue_match);
 
@@ -353,7 +346,6 @@
 {
        struct cl_io_lock_link *scan;
 
-       ENTRY;
        list_for_each_entry(scan, queue, cill_linkage) {
 	       if (cl_lock_descr_cmp(&scan->cill_descr, need))
 		       continue;
@@ -361,9 +353,9 @@
 	       CDEBUG(D_VFSTRACE, "lock: %d: [%lu, %lu]\n",
 		      scan->cill_descr.cld_mode, scan->cill_descr.cld_start,
 		      scan->cill_descr.cld_end);
-	       RETURN(+1);
+	       return +1;
        }
-       RETURN(0);
+       return 0;
 
 }
 
@@ -388,8 +380,6 @@
 	struct cl_lock *lock;
 	int	     result;
 
-	ENTRY;
-
 	lock = cl_lock_request(env, io, &link->cill_descr, "io", io);
 
 	if (!IS_ERR(lock)) {
@@ -404,7 +394,7 @@
 			result = 0;
 	} else
 		result = PTR_ERR(lock);
-	RETURN(result);
+	return result;
 }
 
 static void cl_lock_link_fini(const struct lu_env *env, struct cl_io *io,
@@ -412,7 +402,6 @@
 {
 	struct cl_lock *lock = link->cill_lock;
 
-	ENTRY;
 	list_del_init(&link->cill_linkage);
 	if (lock != NULL) {
 		cl_lock_release(env, lock, "io", io);
@@ -420,7 +409,6 @@
 	}
 	if (link->cill_fini != NULL)
 		link->cill_fini(env, link);
-	EXIT;
 }
 
 static int cl_lockset_lock(const struct lu_env *env, struct cl_io *io,
@@ -431,7 +419,6 @@
 	struct cl_lock	 *lock;
 	int result;
 
-	ENTRY;
 	result = 0;
 	list_for_each_entry_safe(link, temp, &set->cls_todo, cill_linkage) {
 		if (!cl_lockset_match(set, &link->cill_descr)) {
@@ -455,7 +442,7 @@
 				break;
 		}
 	}
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -474,7 +461,6 @@
 	LINVRNT(io->ci_state == CIS_IT_STARTED);
 	LINVRNT(cl_io_invariant(io));
 
-	ENTRY;
 	cl_io_for_each(scan, io) {
 		if (scan->cis_iop->op[io->ci_type].cio_lock == NULL)
 			continue;
@@ -490,7 +476,7 @@
 		cl_io_unlock(env, io);
 	else
 		io->ci_state = CIS_LOCKED;
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_lock);
 
@@ -508,7 +494,6 @@
 	LASSERT(CIS_IT_STARTED <= io->ci_state && io->ci_state < CIS_UNLOCKED);
 	LINVRNT(cl_io_invariant(io));
 
-	ENTRY;
 	set = &io->ci_lockset;
 
 	list_for_each_entry_safe(link, temp, &set->cls_todo, cill_linkage)
@@ -527,7 +512,6 @@
 	}
 	io->ci_state = CIS_UNLOCKED;
 	LASSERT(!cl_env_info(env)->clt_counters[CNL_TOP].ctc_nr_locks_acquired);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_io_unlock);
 
@@ -547,7 +531,6 @@
 	LINVRNT(io->ci_state == CIS_INIT || io->ci_state == CIS_IT_ENDED);
 	LINVRNT(cl_io_invariant(io));
 
-	ENTRY;
 	result = 0;
 	cl_io_for_each(scan, io) {
 		if (scan->cis_iop->op[io->ci_type].cio_iter_init == NULL)
@@ -559,7 +542,7 @@
 	}
 	if (result == 0)
 		io->ci_state = CIS_IT_STARTED;
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_iter_init);
 
@@ -576,13 +559,11 @@
 	LINVRNT(io->ci_state == CIS_UNLOCKED);
 	LINVRNT(cl_io_invariant(io));
 
-	ENTRY;
 	cl_io_for_each_reverse(scan, io) {
 		if (scan->cis_iop->op[io->ci_type].cio_iter_fini != NULL)
 			scan->cis_iop->op[io->ci_type].cio_iter_fini(env, scan);
 	}
 	io->ci_state = CIS_IT_ENDED;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_io_iter_fini);
 
@@ -598,8 +579,6 @@
 	LINVRNT(cl_io_is_loopable(io));
 	LINVRNT(cl_io_invariant(io));
 
-	ENTRY;
-
 	io->u.ci_rw.crw_pos   += nob;
 	io->u.ci_rw.crw_count -= nob;
 
@@ -609,7 +588,6 @@
 			scan->cis_iop->op[io->ci_type].cio_advance(env, scan,
 								   nob);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_io_rw_advance);
 
@@ -621,14 +599,13 @@
 {
 	int result;
 
-	ENTRY;
 	if (cl_lockset_merge(&io->ci_lockset, &link->cill_descr))
 		result = +1;
 	else {
 		list_add(&link->cill_linkage, &io->ci_lockset.cls_todo);
 		result = 0;
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_lock_add);
 
@@ -647,7 +624,6 @@
 	struct cl_io_lock_link *link;
 	int result;
 
-	ENTRY;
 	OBD_ALLOC_PTR(link);
 	if (link != NULL) {
 		link->cill_descr     = *descr;
@@ -658,7 +634,7 @@
 	} else
 		result = -ENOMEM;
 
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_lock_alloc_add);
 
@@ -673,7 +649,6 @@
 	LINVRNT(cl_io_is_loopable(io));
 	LINVRNT(io->ci_state == CIS_LOCKED);
 	LINVRNT(cl_io_invariant(io));
-	ENTRY;
 
 	io->ci_state = CIS_IO_GOING;
 	cl_io_for_each(scan, io) {
@@ -685,7 +660,7 @@
 	}
 	if (result >= 0)
 		result = 0;
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_start);
 
@@ -700,7 +675,6 @@
 	LINVRNT(cl_io_is_loopable(io));
 	LINVRNT(io->ci_state == CIS_IO_GOING);
 	LINVRNT(cl_io_invariant(io));
-	ENTRY;
 
 	cl_io_for_each_reverse(scan, io) {
 		if (scan->cis_iop->op[io->ci_type].cio_end != NULL)
@@ -708,7 +682,6 @@
 		/* TODO: error handling. */
 	}
 	io->ci_state = CIS_IO_FINISHED;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_io_end);
 
@@ -774,7 +747,6 @@
 	LINVRNT(io->ci_state == CIS_IO_GOING || io->ci_state == CIS_LOCKED);
 	LINVRNT(cl_page_in_io(page, io));
 	LINVRNT(cl_io_invariant(io));
-	ENTRY;
 
 	queue = &io->ci_queue;
 
@@ -807,7 +779,7 @@
 	 */
 	cl_page_list_disown(env, io, &queue->c2_qin);
 	cl_2queue_fini(env, queue);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_read_page);
 
@@ -827,7 +799,6 @@
 	LINVRNT(io->ci_state == CIS_IO_GOING || io->ci_state == CIS_LOCKED);
 	LINVRNT(cl_io_invariant(io));
 	LASSERT(cl_page_in_io(page, io));
-	ENTRY;
 
 	cl_io_for_each_reverse(scan, io) {
 		if (scan->cis_iop->cio_prepare_write != NULL) {
@@ -841,7 +812,7 @@
 				break;
 		}
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_prepare_write);
 
@@ -867,7 +838,6 @@
 	 */
 	LASSERT(cl_page_is_owned(page, io) || page->cp_parent != NULL);
 	LASSERT(cl_page_in_io(page, io));
-	ENTRY;
 
 	cl_io_for_each(scan, io) {
 		if (scan->cis_iop->cio_commit_write != NULL) {
@@ -882,7 +852,7 @@
 		}
 	}
 	LINVRNT(result <= 0);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_commit_write);
 
@@ -903,7 +873,6 @@
 	int result = 0;
 
 	LINVRNT(crt < ARRAY_SIZE(scan->cis_iop->req_op));
-	ENTRY;
 
 	cl_io_for_each(scan, io) {
 		if (scan->cis_iop->req_op[crt].cio_submit == NULL)
@@ -917,7 +886,7 @@
 	 * If ->cio_submit() failed, no pages were sent.
 	 */
 	LASSERT(ergo(result != 0, list_empty(&queue->c2_qout.pl_pages)));
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_io_submit_rw);
 
@@ -1009,7 +978,6 @@
 	int result   = 0;
 
 	LINVRNT(cl_io_is_loopable(io));
-	ENTRY;
 
 	do {
 		size_t nob;
@@ -1043,7 +1011,7 @@
 	} while (result == 0 && io->ci_continue);
 	if (result == 0)
 		result = io->ci_result;
-	RETURN(result < 0 ? result : 0);
+	return result < 0 ? result : 0;
 }
 EXPORT_SYMBOL(cl_io_loop);
 
@@ -1064,13 +1032,11 @@
 
 	LASSERT((linkage->prev == NULL && linkage->next == NULL) ||
 		list_empty(linkage));
-	ENTRY;
 
 	list_add_tail(linkage, &io->ci_layers);
 	slice->cis_io  = io;
 	slice->cis_obj = obj;
 	slice->cis_iop = ops;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_io_slice_add);
 
@@ -1080,11 +1046,9 @@
  */
 void cl_page_list_init(struct cl_page_list *plist)
 {
-	ENTRY;
 	plist->pl_nr = 0;
 	INIT_LIST_HEAD(&plist->pl_pages);
 	plist->pl_owner = current;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_init);
 
@@ -1093,7 +1057,6 @@
  */
 void cl_page_list_add(struct cl_page_list *plist, struct cl_page *page)
 {
-	ENTRY;
 	/* it would be better to check that page is owned by "current" io, but
 	 * it is not passed here. */
 	LASSERT(page->cp_owner != NULL);
@@ -1105,9 +1068,8 @@
 	LASSERT(list_empty(&page->cp_batch));
 	list_add_tail(&page->cp_batch, &plist->pl_pages);
 	++plist->pl_nr;
-	page->cp_queue_ref = lu_ref_add(&page->cp_reference, "queue", plist);
+	lu_ref_add_at(&page->cp_reference, &page->cp_queue_ref, "queue", plist);
 	cl_page_get(page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_add);
 
@@ -1120,15 +1082,13 @@
 	LASSERT(plist->pl_nr > 0);
 	LINVRNT(plist->pl_owner == current);
 
-	ENTRY;
 	list_del_init(&page->cp_batch);
 	lockdep_off();
 	mutex_unlock(&page->cp_mutex);
 	lockdep_on();
 	--plist->pl_nr;
-	lu_ref_del_at(&page->cp_reference, page->cp_queue_ref, "queue", plist);
+	lu_ref_del_at(&page->cp_reference, &page->cp_queue_ref, "queue", plist);
 	cl_page_put(env, page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_del);
 
@@ -1142,13 +1102,11 @@
 	LINVRNT(dst->pl_owner == current);
 	LINVRNT(src->pl_owner == current);
 
-	ENTRY;
 	list_move_tail(&page->cp_batch, &dst->pl_pages);
 	--src->pl_nr;
 	++dst->pl_nr;
-	lu_ref_set_at(&page->cp_reference,
-		      page->cp_queue_ref, "queue", src, dst);
-	EXIT;
+	lu_ref_set_at(&page->cp_reference, &page->cp_queue_ref, "queue",
+		      src, dst);
 }
 EXPORT_SYMBOL(cl_page_list_move);
 
@@ -1163,10 +1121,8 @@
 	LINVRNT(list->pl_owner == current);
 	LINVRNT(head->pl_owner == current);
 
-	ENTRY;
 	cl_page_list_for_each_safe(page, tmp, list)
 		cl_page_list_move(head, list, page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_splice);
 
@@ -1184,7 +1140,6 @@
 
 	LINVRNT(plist->pl_owner == current);
 
-	ENTRY;
 	cl_page_list_for_each_safe(page, temp, plist) {
 		LASSERT(plist->pl_nr > 0);
 
@@ -1202,10 +1157,10 @@
 		 * XXX cl_page_disown0() will fail if page is not locked.
 		 */
 		cl_page_disown0(env, io, page);
-		lu_ref_del(&page->cp_reference, "queue", plist);
+		lu_ref_del_at(&page->cp_reference, &page->cp_queue_ref, "queue",
+			      plist);
 		cl_page_put(env, page);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_disown);
 
@@ -1219,11 +1174,9 @@
 
 	LINVRNT(plist->pl_owner == current);
 
-	ENTRY;
 	cl_page_list_for_each_safe(page, temp, plist)
 		cl_page_list_del(env, plist, page);
 	LASSERT(plist->pl_nr == 0);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_fini);
 
@@ -1240,7 +1193,6 @@
 
 	LINVRNT(plist->pl_owner == current);
 
-	ENTRY;
 	result = 0;
 	cl_page_list_for_each_safe(page, temp, plist) {
 		LASSERT(index <= page->cp_index);
@@ -1250,7 +1202,7 @@
 		else
 			cl_page_list_del(env, plist, page);
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_page_list_own);
 
@@ -1278,10 +1230,8 @@
 	struct cl_page *page;
 
 	LINVRNT(plist->pl_owner == current);
-	ENTRY;
 	cl_page_list_for_each(page, plist)
 		cl_page_discard(env, io, page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_list_discard);
 
@@ -1295,14 +1245,13 @@
 	int result;
 
 	LINVRNT(plist->pl_owner == current);
-	ENTRY;
 	result = 0;
 	cl_page_list_for_each(page, plist) {
 		result = cl_page_unmap(env, io, page);
 		if (result != 0)
 			break;
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_page_list_unmap);
 
@@ -1311,10 +1260,8 @@
  */
 void cl_2queue_init(struct cl_2queue *queue)
 {
-	ENTRY;
 	cl_page_list_init(&queue->c2_qin);
 	cl_page_list_init(&queue->c2_qout);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_2queue_init);
 
@@ -1323,9 +1270,7 @@
  */
 void cl_2queue_add(struct cl_2queue *queue, struct cl_page *page)
 {
-	ENTRY;
 	cl_page_list_add(&queue->c2_qin, page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_2queue_add);
 
@@ -1335,10 +1280,8 @@
 void cl_2queue_disown(const struct lu_env *env,
 		      struct cl_io *io, struct cl_2queue *queue)
 {
-	ENTRY;
 	cl_page_list_disown(env, io, &queue->c2_qin);
 	cl_page_list_disown(env, io, &queue->c2_qout);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_2queue_disown);
 
@@ -1348,10 +1291,8 @@
 void cl_2queue_discard(const struct lu_env *env,
 		       struct cl_io *io, struct cl_2queue *queue)
 {
-	ENTRY;
 	cl_page_list_discard(env, io, &queue->c2_qin);
 	cl_page_list_discard(env, io, &queue->c2_qout);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_2queue_discard);
 
@@ -1371,10 +1312,8 @@
  */
 void cl_2queue_fini(const struct lu_env *env, struct cl_2queue *queue)
 {
-	ENTRY;
 	cl_page_list_fini(env, &queue->c2_qout);
 	cl_page_list_fini(env, &queue->c2_qin);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_2queue_fini);
 
@@ -1383,10 +1322,8 @@
  */
 void cl_2queue_init_page(struct cl_2queue *queue, struct cl_page *page)
 {
-	ENTRY;
 	cl_2queue_init(queue);
 	cl_2queue_add(queue, page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_2queue_init_page);
 
@@ -1397,10 +1334,9 @@
  */
 struct cl_io *cl_io_top(struct cl_io *io)
 {
-	ENTRY;
 	while (io->ci_parent != NULL)
 		io = io->ci_parent;
-	RETURN(io);
+	return io;
 }
 EXPORT_SYMBOL(cl_io_top);
 
@@ -1425,12 +1361,10 @@
 		      struct cl_device *dev,
 		      const struct cl_req_operations *ops)
 {
-	ENTRY;
 	list_add_tail(&slice->crs_linkage, &req->crq_layers);
 	slice->crs_dev = dev;
 	slice->crs_ops = ops;
 	slice->crs_req = req;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_req_slice_add);
 
@@ -1442,14 +1376,13 @@
 	LASSERT(req->crq_nrpages == 0);
 	LINVRNT(list_empty(&req->crq_layers));
 	LINVRNT(equi(req->crq_nrobjs > 0, req->crq_o != NULL));
-	ENTRY;
 
 	if (req->crq_o != NULL) {
 		for (i = 0; i < req->crq_nrobjs; ++i) {
 			struct cl_object *obj = req->crq_o[i].ro_obj;
 			if (obj != NULL) {
 				lu_object_ref_del_at(&obj->co_lu,
-						     req->crq_o[i].ro_obj_ref,
+						     &req->crq_o[i].ro_obj_ref,
 						     "cl_req", req);
 				cl_object_put(env, obj);
 			}
@@ -1457,7 +1390,6 @@
 		OBD_FREE(req->crq_o, req->crq_nrobjs * sizeof req->crq_o[0]);
 	}
 	OBD_FREE_PTR(req);
-	EXIT;
 }
 
 static int cl_req_init(const struct lu_env *env, struct cl_req *req,
@@ -1467,7 +1399,6 @@
 	struct cl_page_slice *slice;
 	int result;
 
-	ENTRY;
 	result = 0;
 	page = cl_page_top(page);
 	do {
@@ -1482,7 +1413,7 @@
 		}
 		page = page->cp_child;
 	} while (page != NULL && result == 0);
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -1493,7 +1424,6 @@
 {
 	struct cl_req_slice *slice;
 
-	ENTRY;
 	/*
 	 * for the lack of list_for_each_entry_reverse_safe()...
 	 */
@@ -1505,7 +1435,6 @@
 			slice->crs_ops->cro_completion(env, slice, rc);
 	}
 	cl_req_free(env, req);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_req_completion);
 
@@ -1518,7 +1447,6 @@
 	struct cl_req *req;
 
 	LINVRNT(nr_objects > 0);
-	ENTRY;
 
 	OBD_ALLOC_PTR(req);
 	if (req != NULL) {
@@ -1539,7 +1467,7 @@
 		}
 	} else
 		req = ERR_PTR(-ENOMEM);
-	RETURN(req);
+	return req;
 }
 EXPORT_SYMBOL(cl_req_alloc);
 
@@ -1553,7 +1481,6 @@
 	struct cl_req_obj *rqo;
 	int i;
 
-	ENTRY;
 	page = cl_page_top(page);
 
 	LASSERT(list_empty(&page->cp_flight));
@@ -1570,13 +1497,12 @@
 		if (rqo->ro_obj == NULL) {
 			rqo->ro_obj = obj;
 			cl_object_get(obj);
-			rqo->ro_obj_ref = lu_object_ref_add(&obj->co_lu,
-							    "cl_req", req);
+			lu_object_ref_add_at(&obj->co_lu, &rqo->ro_obj_ref,
+					     "cl_req", req);
 			break;
 		}
 	}
 	LASSERT(i < req->crq_nrobjs);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_req_page_add);
 
@@ -1587,7 +1513,6 @@
 {
 	struct cl_req *req = page->cp_req;
 
-	ENTRY;
 	page = cl_page_top(page);
 
 	LASSERT(!list_empty(&page->cp_flight));
@@ -1596,7 +1521,6 @@
 	list_del_init(&page->cp_flight);
 	--req->crq_nrpages;
 	page->cp_req = NULL;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_req_page_done);
 
@@ -1610,7 +1534,6 @@
 	int result;
 	const struct cl_req_slice *slice;
 
-	ENTRY;
 	/*
 	 * Check that the caller of cl_req_alloc() didn't lie about the number
 	 * of objects.
@@ -1626,7 +1549,7 @@
 				break;
 		}
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_req_prep);
 
@@ -1643,7 +1566,6 @@
 	int i;
 
 	LASSERT(!list_empty(&req->crq_pages));
-	ENTRY;
 
 	/* Take any page to use as a model. */
 	page = list_entry(req->crq_pages.next, struct cl_page, cp_flight);
@@ -1662,7 +1584,6 @@
 							     attr + i, flags);
 		}
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_req_attr_set);
 
@@ -1675,12 +1596,10 @@
  */
 void cl_sync_io_init(struct cl_sync_io *anchor, int nrpages)
 {
-	ENTRY;
 	init_waitqueue_head(&anchor->csi_waitq);
 	atomic_set(&anchor->csi_sync_nr, nrpages);
 	atomic_set(&anchor->csi_barrier, nrpages > 0);
 	anchor->csi_sync_rc = 0;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_sync_io_init);
 
@@ -1695,7 +1614,6 @@
 	struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout),
 						  NULL, NULL, NULL);
 	int rc;
-	ENTRY;
 
 	LASSERT(timeout >= 0);
 
@@ -1725,7 +1643,7 @@
 	}
 
 	POISON(anchor, 0x5a, sizeof *anchor);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(cl_sync_io_wait);
 
@@ -1734,7 +1652,6 @@
  */
 void cl_sync_io_note(struct cl_sync_io *anchor, int ioret)
 {
-	ENTRY;
 	if (anchor->csi_sync_rc == 0 && ioret < 0)
 		anchor->csi_sync_rc = ioret;
 	/*
@@ -1748,6 +1665,5 @@
 		/* it's safe to nuke or reuse anchor now */
 		atomic_set(&anchor->csi_barrier, 0);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_sync_io_note);
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
index d34e044..749eb08 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c
@@ -191,12 +191,10 @@
 		       struct cl_object *obj,
 		       const struct cl_lock_operations *ops)
 {
-	ENTRY;
 	slice->cls_lock = lock;
 	list_add_tail(&slice->cls_linkage, &lock->cll_layers);
 	slice->cls_obj = obj;
 	slice->cls_ops = ops;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_slice_add);
 
@@ -254,7 +252,6 @@
 
 	LINVRNT(!cl_lock_is_mutexed(lock));
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "free lock", lock);
 	might_sleep();
 	while (!list_empty(&lock->cll_layers)) {
@@ -267,13 +264,12 @@
 	}
 	CS_LOCK_DEC(obj, total);
 	CS_LOCKSTATE_DEC(obj, lock->cll_state);
-	lu_object_ref_del_at(&obj->co_lu, lock->cll_obj_ref, "cl_lock", lock);
+	lu_object_ref_del_at(&obj->co_lu, &lock->cll_obj_ref, "cl_lock", lock);
 	cl_object_put(env, obj);
 	lu_ref_fini(&lock->cll_reference);
 	lu_ref_fini(&lock->cll_holders);
 	mutex_destroy(&lock->cll_guard);
 	OBD_SLAB_FREE_PTR(lock, cl_lock_kmem);
-	EXIT;
 }
 
 /**
@@ -290,7 +286,6 @@
 	struct cl_object	*obj;
 
 	LINVRNT(cl_lock_invariant(env, lock));
-	ENTRY;
 	obj = lock->cll_descr.cld_obj;
 	LINVRNT(obj != NULL);
 
@@ -304,7 +299,6 @@
 		}
 		CS_LOCK_DEC(obj, busy);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_put);
 
@@ -366,15 +360,14 @@
 	struct cl_lock	  *lock;
 	struct lu_object_header *head;
 
-	ENTRY;
 	OBD_SLAB_ALLOC_PTR_GFP(lock, cl_lock_kmem, __GFP_IO);
 	if (lock != NULL) {
 		atomic_set(&lock->cll_ref, 1);
 		lock->cll_descr = *descr;
 		lock->cll_state = CLS_NEW;
 		cl_object_get(obj);
-		lock->cll_obj_ref = lu_object_ref_add(&obj->co_lu,
-						      "cl_lock", lock);
+		lu_object_ref_add_at(&obj->co_lu, &lock->cll_obj_ref, "cl_lock",
+				     lock);
 		INIT_LIST_HEAD(&lock->cll_layers);
 		INIT_LIST_HEAD(&lock->cll_linkage);
 		INIT_LIST_HEAD(&lock->cll_inclosure);
@@ -401,7 +394,7 @@
 		}
 	} else
 		lock = ERR_PTR(-ENOMEM);
-	RETURN(lock);
+	return lock;
 }
 
 /**
@@ -468,13 +461,12 @@
 	const struct cl_lock_slice *slice;
 
 	LINVRNT(cl_lock_invariant_trusted(env, lock));
-	ENTRY;
 	list_for_each_entry(slice, &lock->cll_layers, cls_linkage) {
 		if (slice->cls_ops->clo_fits_into != NULL &&
 		    !slice->cls_ops->clo_fits_into(env, slice, need, io))
-			RETURN(0);
+			return 0;
 	}
-	RETURN(1);
+	return 1;
 }
 
 static struct cl_lock *cl_lock_lookup(const struct lu_env *env,
@@ -485,8 +477,6 @@
 	struct cl_lock	  *lock;
 	struct cl_object_header *head;
 
-	ENTRY;
-
 	head = cl_object_header(obj);
 	LINVRNT(spin_is_locked(&head->coh_lock_guard));
 	CS_LOCK_INC(obj, lookup);
@@ -504,10 +494,10 @@
 		if (matched) {
 			cl_lock_get_trust(lock);
 			CS_LOCK_INC(obj, hit);
-			RETURN(lock);
+			return lock;
 		}
 	}
-	RETURN(NULL);
+	return NULL;
 }
 
 /**
@@ -528,8 +518,6 @@
 	struct cl_object	*obj;
 	struct cl_lock	  *lock;
 
-	ENTRY;
-
 	obj  = need->cld_obj;
 	head = cl_object_header(obj);
 
@@ -561,7 +549,7 @@
 			}
 		}
 	}
-	RETURN(lock);
+	return lock;
 }
 
 /**
@@ -630,13 +618,12 @@
 	const struct cl_lock_slice *slice;
 
 	LINVRNT(cl_lock_invariant_trusted(NULL, lock));
-	ENTRY;
 
 	list_for_each_entry(slice, &lock->cll_layers, cls_linkage) {
 		if (slice->cls_obj->co_lu.lo_dev->ld_type == dtype)
-			RETURN(slice);
+			return slice;
 	}
-	RETURN(NULL);
+	return NULL;
 }
 EXPORT_SYMBOL(cl_lock_at);
 
@@ -705,7 +692,6 @@
 	int result;
 
 	LINVRNT(cl_lock_invariant_trusted(env, lock));
-	ENTRY;
 
 	result = 0;
 	if (lock->cll_guarder == current) {
@@ -717,7 +703,7 @@
 		cl_lock_mutex_tail(env, lock);
 	} else
 		result = -EBUSY;
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_lock_mutex_try);
 
@@ -784,7 +770,6 @@
 {
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
-	ENTRY;
 	if (!(lock->cll_flags & CLF_CANCELLED)) {
 		const struct cl_lock_slice *slice;
 
@@ -795,7 +780,6 @@
 				slice->cls_ops->clo_cancel(env, slice);
 		}
 	}
-	EXIT;
 }
 
 static void cl_lock_delete0(const struct lu_env *env, struct cl_lock *lock)
@@ -806,7 +790,6 @@
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 
-	ENTRY;
 	if (lock->cll_state < CLS_FREEING) {
 		LASSERT(lock->cll_state != CLS_INTRANSIT);
 		cl_lock_state_set(env, lock, CLS_FREEING);
@@ -836,7 +819,6 @@
 		 * existing references goes away.
 		 */
 	}
-	EXIT;
 }
 
 /**
@@ -886,7 +868,6 @@
 	LINVRNT(cl_lock_invariant(env, lock));
 	LASSERT(lock->cll_holds > 0);
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "hold release lock", lock);
 	lu_ref_del(&lock->cll_holders, scope, source);
 	cl_lock_hold_mod(env, lock, -1);
@@ -910,7 +891,6 @@
 			cl_lock_delete0(env, lock);
 		}
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_hold_release);
 
@@ -939,7 +919,6 @@
 	sigset_t blocked;
 	int result;
 
-	ENTRY;
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 	LASSERT(lock->cll_depth == 1);
@@ -976,7 +955,7 @@
 		/* Restore old blocked signals */
 		cfs_restore_sigs(blocked);
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_lock_state_wait);
 
@@ -985,7 +964,6 @@
 {
 	const struct cl_lock_slice *slice;
 
-	ENTRY;
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 
@@ -993,7 +971,6 @@
 		if (slice->cls_ops->clo_state != NULL)
 			slice->cls_ops->clo_state(env, slice, state);
 	wake_up_all(&lock->cll_wq);
-	EXIT;
 }
 
 /**
@@ -1005,10 +982,8 @@
  */
 void cl_lock_signal(const struct lu_env *env, struct cl_lock *lock)
 {
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "state signal lock", lock);
 	cl_lock_state_signal(env, lock, lock->cll_state);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_signal);
 
@@ -1025,7 +1000,6 @@
 void cl_lock_state_set(const struct lu_env *env, struct cl_lock *lock,
 		       enum cl_lock_state state)
 {
-	ENTRY;
 	LASSERT(lock->cll_state <= state ||
 		(lock->cll_state == CLS_CACHED &&
 		 (state == CLS_HELD || /* lock found in cache */
@@ -1041,7 +1015,6 @@
 		cl_lock_state_signal(env, lock, state);
 		lock->cll_state = state;
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_state_set);
 
@@ -1084,12 +1057,11 @@
 	int result;
 	enum cl_lock_state state;
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "use lock", lock);
 
 	LASSERT(lock->cll_state == CLS_CACHED);
 	if (lock->cll_error)
-		RETURN(lock->cll_error);
+		return lock->cll_error;
 
 	result = -ENOSYS;
 	state = cl_lock_intransit(env, lock);
@@ -1129,7 +1101,7 @@
 
 	}
 	cl_lock_extransit(env, lock, state);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_use_try);
 
@@ -1144,7 +1116,6 @@
 	int result;
 	const struct cl_lock_slice *slice;
 
-	ENTRY;
 	result = -ENOSYS;
 	list_for_each_entry(slice, &lock->cll_layers, cls_linkage) {
 		if (slice->cls_ops->clo_enqueue != NULL) {
@@ -1155,7 +1126,7 @@
 		}
 	}
 	LASSERT(result != -ENOSYS);
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -1176,7 +1147,6 @@
 {
 	int result;
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "enqueue lock", lock);
 	do {
 		LINVRNT(cl_lock_is_mutexed(lock));
@@ -1219,7 +1189,7 @@
 			LBUG();
 		}
 	} while (result == CLO_REPEAT);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_enqueue_try);
 
@@ -1235,7 +1205,6 @@
 {
 	struct cl_lock  *conflict;
 	int	      rc = 0;
-	ENTRY;
 
 	LASSERT(cl_lock_is_mutexed(lock));
 	LASSERT(lock->cll_state == CLS_QUEUING);
@@ -1265,7 +1234,7 @@
 		cl_lock_mutex_get(env, lock);
 
 	LASSERT(rc <= 0);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(cl_lock_enqueue_wait);
 
@@ -1274,8 +1243,6 @@
 {
 	int result;
 
-	ENTRY;
-
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 	LASSERT(lock->cll_holds > 0);
@@ -1298,7 +1265,7 @@
 	LASSERT(ergo(result == 0 && !(enqflags & CEF_AGL),
 		     lock->cll_state == CLS_ENQUEUED ||
 		     lock->cll_state == CLS_HELD));
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -1315,8 +1282,6 @@
 {
 	int result;
 
-	ENTRY;
-
 	cl_lock_lockdep_acquire(env, lock, enqflags);
 	cl_lock_mutex_get(env, lock);
 	result = cl_enqueue_locked(env, lock, io, enqflags);
@@ -1325,7 +1290,7 @@
 		cl_lock_lockdep_release(env, lock);
 	LASSERT(ergo(result == 0, lock->cll_state == CLS_ENQUEUED ||
 		     lock->cll_state == CLS_HELD));
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_enqueue);
 
@@ -1346,19 +1311,18 @@
 	int			 result;
 	enum cl_lock_state	  state = CLS_NEW;
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "unuse lock", lock);
 
 	if (lock->cll_users > 1) {
 		cl_lock_user_del(env, lock);
-		RETURN(0);
+		return 0;
 	}
 
 	/* Only if the lock is in CLS_HELD or CLS_ENQUEUED state, it can hold
 	 * underlying resources. */
 	if (!(lock->cll_state == CLS_HELD || lock->cll_state == CLS_ENQUEUED)) {
 		cl_lock_user_del(env, lock);
-		RETURN(0);
+		return 0;
 	}
 
 	/*
@@ -1404,20 +1368,17 @@
 		state = CLS_NEW;
 		cl_lock_extransit(env, lock, state);
 	}
-	RETURN(result ?: lock->cll_error);
+	return result ?: lock->cll_error;
 }
 EXPORT_SYMBOL(cl_unuse_try);
 
 static void cl_unuse_locked(const struct lu_env *env, struct cl_lock *lock)
 {
 	int result;
-	ENTRY;
 
 	result = cl_unuse_try(env, lock);
 	if (result)
 		CL_LOCK_DEBUG(D_ERROR, env, lock, "unuse return %d\n", result);
-
-	EXIT;
 }
 
 /**
@@ -1425,12 +1386,10 @@
  */
 void cl_unuse(const struct lu_env *env, struct cl_lock *lock)
 {
-	ENTRY;
 	cl_lock_mutex_get(env, lock);
 	cl_unuse_locked(env, lock);
 	cl_lock_mutex_put(env, lock);
 	cl_lock_lockdep_release(env, lock);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_unuse);
 
@@ -1449,7 +1408,6 @@
 	const struct cl_lock_slice *slice;
 	int			 result;
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "wait lock try", lock);
 	do {
 		LINVRNT(cl_lock_is_mutexed(lock));
@@ -1489,7 +1447,7 @@
 			cl_lock_state_set(env, lock, CLS_HELD);
 		}
 	} while (result == CLO_REPEAT);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_wait_try);
 
@@ -1506,7 +1464,6 @@
 {
 	int result;
 
-	ENTRY;
 	cl_lock_mutex_get(env, lock);
 
 	LINVRNT(cl_lock_invariant(env, lock));
@@ -1530,7 +1487,7 @@
 	cl_lock_trace(D_DLMTRACE, env, "wait lock", lock);
 	cl_lock_mutex_put(env, lock);
 	LASSERT(ergo(result == 0, lock->cll_state == CLS_HELD));
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_wait);
 
@@ -1544,7 +1501,6 @@
 	unsigned long pound;
 	unsigned long ounce;
 
-	ENTRY;
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 
@@ -1557,7 +1513,7 @@
 				pound = ~0UL;
 		}
 	}
-	RETURN(pound);
+	return pound;
 }
 EXPORT_SYMBOL(cl_lock_weigh);
 
@@ -1579,7 +1535,6 @@
 	struct cl_object_header    *hdr = cl_object_header(obj);
 	int result;
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "modify lock", lock);
 	/* don't allow object to change */
 	LASSERT(obj == desc->cld_obj);
@@ -1590,7 +1545,7 @@
 		if (slice->cls_ops->clo_modify != NULL) {
 			result = slice->cls_ops->clo_modify(env, slice, desc);
 			if (result != 0)
-				RETURN(result);
+				return result;
 		}
 	}
 	CL_LOCK_DEBUG(D_DLMTRACE, env, lock, " -> "DDESCR"@"DFID"\n",
@@ -1603,7 +1558,7 @@
 	spin_lock(&hdr->coh_lock_guard);
 	lock->cll_descr = *desc;
 	spin_unlock(&hdr->coh_lock_guard);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(cl_lock_modify);
 
@@ -1642,7 +1597,6 @@
 	const struct cl_lock_slice *slice;
 	int result;
 
-	ENTRY;
 	LINVRNT(cl_lock_is_mutexed(closure->clc_origin));
 	LINVRNT(cl_lock_invariant(env, closure->clc_origin));
 
@@ -1659,7 +1613,7 @@
 	}
 	if (result != 0)
 		cl_lock_disclosure(env, closure);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_lock_closure_build);
 
@@ -1674,7 +1628,7 @@
 		      struct cl_lock_closure *closure)
 {
 	int result = 0;
-	ENTRY;
+
 	cl_lock_trace(D_DLMTRACE, env, "enclosure lock", lock);
 	if (!cl_lock_mutex_try(env, lock)) {
 		/*
@@ -1706,7 +1660,7 @@
 		}
 		result = CLO_REPEAT;
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_lock_enclosure);
 
@@ -1766,13 +1720,11 @@
 	LASSERT(ergo(cl_lock_nesting(lock) == CNL_TOP,
 		     cl_lock_nr_mutexed(env) == 1));
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "delete lock", lock);
 	if (lock->cll_holds == 0)
 		cl_lock_delete0(env, lock);
 	else
 		lock->cll_flags |= CLF_DOOMED;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_delete);
 
@@ -1791,7 +1743,6 @@
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 
-	ENTRY;
 	if (lock->cll_error == 0 && error != 0) {
 		cl_lock_trace(D_DLMTRACE, env, "set lock error", lock);
 		lock->cll_error = error;
@@ -1799,7 +1750,6 @@
 		cl_lock_cancel(env, lock);
 		cl_lock_delete(env, lock);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_error);
 
@@ -1819,13 +1769,11 @@
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "cancel lock", lock);
 	if (lock->cll_holds == 0)
 		cl_lock_cancel0(env, lock);
 	else
 		lock->cll_flags |= CLF_CANCELPEND;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_cancel);
 
@@ -1843,8 +1791,6 @@
 	struct cl_lock	  *lock;
 	struct cl_lock_descr    *need;
 
-	ENTRY;
-
 	head = cl_object_header(obj);
 	need = &cl_env_info(env)->clt_descr;
 	lock = NULL;
@@ -1878,7 +1824,7 @@
 		}
 	}
 	spin_unlock(&head->coh_lock_guard);
-	RETURN(lock);
+	return lock;
 }
 EXPORT_SYMBOL(cl_lock_at_pgoff);
 
@@ -1979,7 +1925,6 @@
 	int result;
 
 	LINVRNT(cl_lock_invariant(env, lock));
-	ENTRY;
 
 	io->ci_obj = cl_object_top(descr->cld_obj);
 	io->ci_ignore_layout = 1;
@@ -2001,7 +1946,7 @@
 	} while (res != CLP_GANG_OKAY);
 out:
 	cl_io_fini(env, io);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_lock_discard_pages);
 
@@ -2018,7 +1963,6 @@
 	struct cl_object_header *head;
 	struct cl_lock	  *lock;
 
-	ENTRY;
 	head = cl_object_header(obj);
 	/*
 	 * If locks are destroyed without cancellation, all pages must be
@@ -2059,7 +2003,6 @@
 		spin_lock(&head->coh_lock_guard);
 	}
 	spin_unlock(&head->coh_lock_guard);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_locks_prune);
 
@@ -2070,8 +2013,6 @@
 {
 	struct cl_lock *lock;
 
-	ENTRY;
-
 	while (1) {
 		lock = cl_lock_find(env, io, need);
 		if (IS_ERR(lock))
@@ -2087,7 +2028,7 @@
 		cl_lock_mutex_put(env, lock);
 		cl_lock_put(env, lock);
 	}
-	RETURN(lock);
+	return lock;
 }
 
 /**
@@ -2103,12 +2044,10 @@
 {
 	struct cl_lock *lock;
 
-	ENTRY;
-
 	lock = cl_lock_hold_mutex(env, io, need, scope, source);
 	if (!IS_ERR(lock))
 		cl_lock_mutex_put(env, lock);
-	RETURN(lock);
+	return lock;
 }
 EXPORT_SYMBOL(cl_lock_hold);
 
@@ -2124,7 +2063,6 @@
 	int		   rc;
 	__u32		 enqflags = need->cld_enq_flags;
 
-	ENTRY;
 	do {
 		lock = cl_lock_hold_mutex(env, io, need, scope, source);
 		if (IS_ERR(lock))
@@ -2156,7 +2094,7 @@
 			lock = ERR_PTR(rc);
 		}
 	} while (rc == 0);
-	RETURN(lock);
+	return lock;
 }
 EXPORT_SYMBOL(cl_lock_request);
 
@@ -2170,12 +2108,10 @@
 	LINVRNT(cl_lock_invariant(env, lock));
 	LASSERT(lock->cll_state != CLS_FREEING);
 
-	ENTRY;
 	cl_lock_hold_mod(env, lock, +1);
 	cl_lock_get(lock);
 	lu_ref_add(&lock->cll_holders, scope, source);
 	lu_ref_add(&lock->cll_reference, scope, source);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_hold_add);
 
@@ -2187,11 +2123,9 @@
 		    const char *scope, const void *source)
 {
 	LINVRNT(cl_lock_invariant(env, lock));
-	ENTRY;
 	cl_lock_hold_release(env, lock, scope, source);
 	lu_ref_del(&lock->cll_reference, scope, source);
 	cl_lock_put(env, lock);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_unhold);
 
@@ -2202,14 +2136,12 @@
 		     const char *scope, const void *source)
 {
 	LINVRNT(cl_lock_invariant(env, lock));
-	ENTRY;
 	cl_lock_trace(D_DLMTRACE, env, "release lock", lock);
 	cl_lock_mutex_get(env, lock);
 	cl_lock_hold_release(env, lock, scope, source);
 	cl_lock_mutex_put(env, lock);
 	lu_ref_del(&lock->cll_reference, scope, source);
 	cl_lock_put(env, lock);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_release);
 
@@ -2218,9 +2150,7 @@
 	LINVRNT(cl_lock_is_mutexed(lock));
 	LINVRNT(cl_lock_invariant(env, lock));
 
-	ENTRY;
 	cl_lock_used_mod(env, lock, +1);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_user_add);
 
@@ -2230,11 +2160,9 @@
 	LINVRNT(cl_lock_invariant(env, lock));
 	LASSERT(lock->cll_users > 0);
 
-	ENTRY;
 	cl_lock_used_mod(env, lock, -1);
 	if (lock->cll_users == 0)
 		wake_up_all(&lock->cll_wq);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lock_user_del);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index cdb5fba..7b0e9d2 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -79,7 +79,6 @@
 {
 	int result;
 
-	ENTRY;
 	result = lu_object_header_init(&h->coh_lu);
 	if (result == 0) {
 		spin_lock_init(&h->coh_page_guard);
@@ -94,7 +93,7 @@
 		INIT_LIST_HEAD(&h->coh_locks);
 		h->coh_page_bufsize = ALIGN(sizeof(struct cl_page), 8);
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_object_header_init);
 
@@ -222,7 +221,6 @@
 	int result;
 
 	LASSERT(spin_is_locked(cl_object_attr_guard(obj)));
-	ENTRY;
 
 	top = obj->co_lu.lo_header;
 	result = 0;
@@ -236,7 +234,7 @@
 			}
 		}
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_object_attr_get);
 
@@ -254,7 +252,6 @@
 	int result;
 
 	LASSERT(spin_is_locked(cl_object_attr_guard(obj)));
-	ENTRY;
 
 	top = obj->co_lu.lo_header;
 	result = 0;
@@ -269,7 +266,7 @@
 			}
 		}
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_object_attr_set);
 
@@ -287,7 +284,6 @@
 	struct lu_object_header *top;
 	int result;
 
-	ENTRY;
 	top = obj->co_lu.lo_header;
 	result = 0;
 	list_for_each_entry_reverse(obj, &top->loh_layers,
@@ -303,7 +299,7 @@
 			 "ctime: "LPU64" blocks: "LPU64"\n",
 			 lvb->lvb_size, lvb->lvb_mtime, lvb->lvb_atime,
 			 lvb->lvb_ctime, lvb->lvb_blocks);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_object_glimpse);
 
@@ -316,7 +312,6 @@
 	struct lu_object_header *top;
 	int result;
 
-	ENTRY;
 	top = obj->co_lu.lo_header;
 	result = 0;
 	list_for_each_entry(obj, &top->loh_layers, co_lu.lo_linkage) {
@@ -326,7 +321,7 @@
 				break;
 		}
 	}
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_conf_set);
 
@@ -362,10 +357,8 @@
  */
 void cl_object_prune(const struct lu_env *env, struct cl_object *obj)
 {
-	ENTRY;
 	cl_pages_prune(env, obj);
 	cl_locks_prune(env, obj, 1);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_object_prune);
 
@@ -941,13 +934,11 @@
  */
 void cl_attr2lvb(struct ost_lvb *lvb, const struct cl_attr *attr)
 {
-	ENTRY;
 	lvb->lvb_size   = attr->cat_size;
 	lvb->lvb_mtime  = attr->cat_mtime;
 	lvb->lvb_atime  = attr->cat_atime;
 	lvb->lvb_ctime  = attr->cat_ctime;
 	lvb->lvb_blocks = attr->cat_blocks;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_attr2lvb);
 
@@ -958,13 +949,11 @@
  */
 void cl_lvb2attr(struct cl_attr *attr, const struct ost_lvb *lvb)
 {
-	ENTRY;
 	attr->cat_size   = lvb->lvb_size;
 	attr->cat_mtime  = lvb->lvb_mtime;
 	attr->cat_atime  = lvb->lvb_atime;
 	attr->cat_ctime  = lvb->lvb_ctime;
 	attr->cat_blocks = lvb->lvb_blocks;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_lvb2attr);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c
index bb93359..2a5ce37 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_page.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c
@@ -108,17 +108,16 @@
 		   const struct lu_device_type *dtype)
 {
 	const struct cl_page_slice *slice;
-	ENTRY;
 
 	page = cl_page_top_trusted((struct cl_page *)page);
 	do {
 		list_for_each_entry(slice, &page->cp_layers, cpl_linkage) {
 			if (slice->cpl_obj->co_lu.lo_dev->ld_type == dtype)
-				RETURN(slice);
+				return slice;
 		}
 		page = page->cp_child;
 	} while (page != NULL);
-	RETURN(NULL);
+	return NULL;
 }
 
 /**
@@ -167,7 +166,6 @@
 	unsigned int	     j;
 	int		      res = CLP_GANG_OKAY;
 	int		      tree_lock = 1;
-	ENTRY;
 
 	idx = start;
 	hdr = cl_object_header(obj);
@@ -243,7 +241,7 @@
 	}
 	if (tree_lock)
 		spin_unlock(&hdr->coh_page_guard);
-	RETURN(res);
+	return res;
 }
 EXPORT_SYMBOL(cl_page_gang_lookup);
 
@@ -258,7 +256,6 @@
 	PASSERT(env, page, page->cp_parent == NULL);
 	PASSERT(env, page, page->cp_state == CPS_FREEING);
 
-	ENTRY;
 	might_sleep();
 	while (!list_empty(&page->cp_layers)) {
 		struct cl_page_slice *slice;
@@ -270,11 +267,10 @@
 	}
 	CS_PAGE_DEC(obj, total);
 	CS_PAGESTATE_DEC(obj, page->cp_state);
-	lu_object_ref_del_at(&obj->co_lu, page->cp_obj_ref, "cl_page", page);
+	lu_object_ref_del_at(&obj->co_lu, &page->cp_obj_ref, "cl_page", page);
 	cl_object_put(env, obj);
 	lu_ref_fini(&page->cp_reference);
 	OBD_FREE(page, pagesize);
-	EXIT;
 }
 
 /**
@@ -295,7 +291,6 @@
 	struct cl_page	  *page;
 	struct lu_object_header *head;
 
-	ENTRY;
 	OBD_ALLOC_GFP(page, cl_object_header(o)->coh_page_bufsize,
 			__GFP_IO);
 	if (page != NULL) {
@@ -305,7 +300,8 @@
 			atomic_inc(&page->cp_ref);
 		page->cp_obj = o;
 		cl_object_get(o);
-		page->cp_obj_ref = lu_object_ref_add(&o->co_lu, "cl_page",page);
+		lu_object_ref_add_at(&o->co_lu, &page->cp_obj_ref, "cl_page",
+				     page);
 		page->cp_index = ind;
 		cl_page_state_set_trust(page, CPS_CACHED);
 		page->cp_type = type;
@@ -336,7 +332,7 @@
 	} else {
 		page = ERR_PTR(-ENOMEM);
 	}
-	RETURN(page);
+	return page;
 }
 
 /**
@@ -364,8 +360,6 @@
 	LASSERT(type == CPT_CACHEABLE || type == CPT_TRANSIENT);
 	might_sleep();
 
-	ENTRY;
-
 	hdr = cl_object_header(o);
 	CS_PAGE_INC(o, lookup);
 
@@ -395,13 +389,13 @@
 
 	if (page != NULL) {
 		CS_PAGE_INC(o, hit);
-		RETURN(page);
+		return page;
 	}
 
 	/* allocate and initialize cl_page */
 	page = cl_page_alloc(env, o, idx, vmpage, type);
 	if (IS_ERR(page))
-		RETURN(page);
+		return page;
 
 	if (type == CPT_TRANSIENT) {
 		if (parent) {
@@ -409,7 +403,7 @@
 			page->cp_parent = parent;
 			parent->cp_child = page;
 		}
-		RETURN(page);
+		return page;
 	}
 
 	/*
@@ -450,7 +444,7 @@
 		cl_page_delete0(env, ghost, 0);
 		cl_page_free(env, ghost);
 	}
-	RETURN(page);
+	return page;
 }
 
 struct cl_page *cl_page_find(const struct lu_env *env, struct cl_object *o,
@@ -553,7 +547,6 @@
 		}
 	};
 
-	ENTRY;
 	old = page->cp_state;
 	PASSERT(env, page, allowed_transitions[old][state]);
 	CL_PAGE_HEADER(D_TRACE, env, page, "%d -> %d\n", old, state);
@@ -566,7 +559,6 @@
 		CS_PAGESTATE_INC(page->cp_obj, state);
 		cl_page_state_set_trust(page, state);
 	}
-	EXIT;
 }
 
 static void cl_page_state_set(const struct lu_env *env,
@@ -585,9 +577,7 @@
  */
 void cl_page_get(struct cl_page *page)
 {
-	ENTRY;
 	cl_page_get_trust(page);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_get);
 
@@ -604,7 +594,6 @@
 {
 	PASSERT(env, page, atomic_read(&page->cp_ref) > !!page->cp_parent);
 
-	ENTRY;
 	CL_PAGE_HEADER(D_TRACE, env, page, "%d\n",
 		       atomic_read(&page->cp_ref));
 
@@ -620,8 +609,6 @@
 		 */
 		cl_page_free(env, page);
 	}
-
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_put);
 
@@ -640,7 +627,7 @@
 	do {
 		list_for_each_entry(slice, &page->cp_layers, cpl_linkage) {
 			if (slice->cpl_ops->cpo_vmpage != NULL)
-				RETURN(slice->cpl_ops->cpo_vmpage(env, slice));
+				return slice->cpl_ops->cpo_vmpage(env, slice);
 		}
 		page = page->cp_child;
 	} while (page != NULL);
@@ -656,7 +643,6 @@
 	struct cl_page *top;
 	struct cl_page *page;
 
-	ENTRY;
 	KLASSERT(PageLocked(vmpage));
 
 	/*
@@ -671,7 +657,7 @@
 	 */
 	top = (struct cl_page *)vmpage->private;
 	if (top == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	for (page = top; page != NULL; page = page->cp_child) {
 		if (cl_object_same(page->cp_obj, obj)) {
@@ -680,7 +666,7 @@
 		}
 	}
 	LASSERT(ergo(page, page->cp_type == CPT_CACHEABLE));
-	RETURN(page);
+	return page;
 }
 EXPORT_SYMBOL(cl_vmpage_page);
 
@@ -785,11 +771,10 @@
 
 {
 	PINVRNT(env, page, cl_object_same(page->cp_obj, io->ci_obj));
-	ENTRY;
-	RETURN(CL_PAGE_INVOKE(env, page, op,
+	return CL_PAGE_INVOKE(env, page, op,
 			      (const struct lu_env *,
 			       const struct cl_page_slice *, struct cl_io *),
-			      io));
+			      io);
 }
 
 static void cl_page_invoid(const struct lu_env *env,
@@ -797,16 +782,13 @@
 
 {
 	PINVRNT(env, page, cl_object_same(page->cp_obj, io->ci_obj));
-	ENTRY;
 	CL_PAGE_INVOID(env, page, op,
 		       (const struct lu_env *,
 			const struct cl_page_slice *, struct cl_io *), io);
-	EXIT;
 }
 
 static void cl_page_owner_clear(struct cl_page *page)
 {
-	ENTRY;
 	for (page = cl_page_top(page); page != NULL; page = page->cp_child) {
 		if (page->cp_owner != NULL) {
 			LASSERT(page->cp_owner->ci_owned_nr > 0);
@@ -815,17 +797,14 @@
 			page->cp_task = NULL;
 		}
 	}
-	EXIT;
 }
 
 static void cl_page_owner_set(struct cl_page *page)
 {
-	ENTRY;
 	for (page = cl_page_top(page); page != NULL; page = page->cp_child) {
 		LASSERT(page->cp_owner != NULL);
 		page->cp_owner->ci_owned_nr++;
 	}
-	EXIT;
 }
 
 void cl_page_disown0(const struct lu_env *env,
@@ -833,7 +812,6 @@
 {
 	enum cl_page_state state;
 
-	ENTRY;
 	state = pg->cp_state;
 	PINVRNT(env, pg, state == CPS_OWNED || state == CPS_FREEING);
 	PINVRNT(env, pg, cl_page_invariant(pg));
@@ -850,7 +828,6 @@
 			       (const struct lu_env *,
 				const struct cl_page_slice *, struct cl_io *),
 			       io);
-	EXIT;
 }
 
 /**
@@ -859,8 +836,7 @@
 int cl_page_is_owned(const struct cl_page *pg, const struct cl_io *io)
 {
 	LINVRNT(cl_object_same(pg->cp_obj, io->ci_obj));
-	ENTRY;
-	RETURN(pg->cp_state == CPS_OWNED && pg->cp_owner == io);
+	return pg->cp_state == CPS_OWNED && pg->cp_owner == io;
 }
 EXPORT_SYMBOL(cl_page_is_owned);
 
@@ -891,7 +867,6 @@
 
 	PINVRNT(env, pg, !cl_page_is_owned(pg, io));
 
-	ENTRY;
 	pg = cl_page_top(pg);
 	io = cl_io_top(io);
 
@@ -918,7 +893,7 @@
 		}
 	}
 	PINVRNT(env, pg, ergo(result == 0, cl_page_invariant(pg)));
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -960,7 +935,6 @@
 {
 	PINVRNT(env, pg, cl_object_same(pg->cp_obj, io->ci_obj));
 
-	ENTRY;
 	pg = cl_page_top(pg);
 	io = cl_io_top(io);
 
@@ -970,7 +944,6 @@
 	pg->cp_task = current;
 	cl_page_owner_set(pg);
 	cl_page_state_set(env, pg, CPS_OWNED);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_assume);
 
@@ -991,7 +964,6 @@
 	PINVRNT(env, pg, cl_page_is_owned(pg, io));
 	PINVRNT(env, pg, cl_page_invariant(pg));
 
-	ENTRY;
 	pg = cl_page_top(pg);
 	io = cl_io_top(io);
 	cl_page_owner_clear(pg);
@@ -1000,7 +972,6 @@
 			       (const struct lu_env *,
 				const struct cl_page_slice *, struct cl_io *),
 			       io);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_unassume);
 
@@ -1020,11 +991,9 @@
 {
 	PINVRNT(env, pg, cl_page_is_owned(pg, io));
 
-	ENTRY;
 	pg = cl_page_top(pg);
 	io = cl_io_top(io);
 	cl_page_disown0(env, io, pg);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_disown);
 
@@ -1057,7 +1026,6 @@
 			    int radix)
 {
 	struct cl_page *tmp = pg;
-	ENTRY;
 
 	PASSERT(env, pg, pg == cl_page_top(pg));
 	PASSERT(env, pg, pg->cp_state != CPS_FREEING);
@@ -1102,8 +1070,6 @@
 			cl_page_put(env, tmp);
 		}
 	}
-
-	EXIT;
 }
 
 /**
@@ -1134,9 +1100,7 @@
 void cl_page_delete(const struct lu_env *env, struct cl_page *pg)
 {
 	PINVRNT(env, pg, cl_page_invariant(pg));
-	ENTRY;
 	cl_page_delete0(env, pg, 1);
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_delete);
 
@@ -1186,7 +1150,6 @@
 	int result;
 	const struct cl_page_slice *slice;
 
-	ENTRY;
 	pg = cl_page_top_trusted((struct cl_page *)pg);
 	slice = container_of(pg->cp_layers.next,
 			     const struct cl_page_slice, cpl_linkage);
@@ -1198,14 +1161,13 @@
 	 */
 	result = slice->cpl_ops->cpo_is_vmlocked(env, slice);
 	PASSERT(env, pg, result == -EBUSY || result == -ENODATA);
-	RETURN(result == -EBUSY);
+	return result == -EBUSY;
 }
 EXPORT_SYMBOL(cl_page_is_vmlocked);
 
 static enum cl_page_state cl_req_type_state(enum cl_req_type crt)
 {
-	ENTRY;
-	RETURN(crt == CRT_WRITE ? CPS_PAGEOUT : CPS_PAGEIN);
+	return crt == CRT_WRITE ? CPS_PAGEOUT : CPS_PAGEIN;
 }
 
 static void cl_page_io_start(const struct lu_env *env,
@@ -1214,10 +1176,8 @@
 	/*
 	 * Page is queued for IO, change its state.
 	 */
-	ENTRY;
 	cl_page_owner_clear(pg);
 	cl_page_state_set(env, pg, cl_req_type_state(crt));
-	EXIT;
 }
 
 /**
@@ -1280,7 +1240,6 @@
 	PASSERT(env, pg, pg->cp_req == NULL);
 	PASSERT(env, pg, pg->cp_state == cl_req_type_state(crt));
 
-	ENTRY;
 	CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, ioret);
 	if (crt == CRT_READ && ioret == 0) {
 		PASSERT(env, pg, !(pg->cp_flags & CPF_READ_COMPLETED));
@@ -1307,8 +1266,6 @@
 
 	if (anchor)
 		cl_sync_io_note(anchor, ioret);
-
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_completion);
 
@@ -1328,9 +1285,8 @@
 
 	PINVRNT(env, pg, crt < CRT_NR);
 
-	ENTRY;
 	if (crt >= CRT_NR)
-		RETURN(-EINVAL);
+		return -EINVAL;
 	result = CL_PAGE_INVOKE(env, pg, CL_PAGE_OP(io[crt].cpo_make_ready),
 				(const struct lu_env *,
 				 const struct cl_page_slice *));
@@ -1339,7 +1295,7 @@
 		cl_page_io_start(env, pg, crt);
 	}
 	CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_page_make_ready);
 
@@ -1365,10 +1321,8 @@
 	PINVRNT(env, pg, cl_page_is_owned(pg, io));
 	PINVRNT(env, pg, cl_page_invariant(pg));
 
-	ENTRY;
-
 	if (crt >= CRT_NR)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	list_for_each_entry(scan, &pg->cp_layers, cpl_linkage) {
 		if (scan->cpl_ops->io[crt].cpo_cache_add == NULL)
@@ -1379,7 +1333,7 @@
 			break;
 	}
 	CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_page_cache_add);
 
@@ -1399,12 +1353,10 @@
 	PINVRNT(env, pg, cl_page_is_owned(pg, io));
 	PINVRNT(env, pg, cl_page_invariant(pg));
 
-	ENTRY;
-
 	result = cl_page_invoke(env, io, pg, CL_PAGE_OP(cpo_flush));
 
 	CL_PAGE_HEADER(D_TRACE, env, pg, "%d\n", result);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_page_flush);
 
@@ -1422,13 +1374,12 @@
 
 	PINVRNT(env, page, cl_page_invariant(page));
 
-	ENTRY;
 	rc = CL_PAGE_INVOKE(env, page, CL_PAGE_OP(cpo_is_under_lock),
 			    (const struct lu_env *,
 			     const struct cl_page_slice *, struct cl_io *),
 			    io);
 	PASSERT(env, page, rc != 0);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(cl_page_is_under_lock);
 
@@ -1452,7 +1403,6 @@
 	struct cl_io	    *io;
 	int		      result;
 
-	ENTRY;
 	info  = cl_env_info(env);
 	io    = &info->clt_io;
 
@@ -1465,7 +1415,7 @@
 	result = cl_io_init(env, io, CIT_MISC, obj);
 	if (result != 0) {
 		cl_io_fini(env, io);
-		RETURN(io->ci_result);
+		return io->ci_result;
 	}
 
 	do {
@@ -1476,7 +1426,7 @@
 	} while (result != CLP_GANG_OKAY);
 
 	cl_io_fini(env, io);
-	RETURN(result);
+	return result;
 }
 EXPORT_SYMBOL(cl_pages_prune);
 
@@ -1586,12 +1536,10 @@
 		       struct cl_object *obj,
 		       const struct cl_page_operations *ops)
 {
-	ENTRY;
 	list_add_tail(&slice->cpl_linkage, &page->cp_layers);
 	slice->cpl_obj  = obj;
 	slice->cpl_ops  = ops;
 	slice->cpl_page = page;
-	EXIT;
 }
 EXPORT_SYMBOL(cl_page_slice_add);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c
index af1c2d0..b1024a6 100644
--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c
@@ -112,18 +112,18 @@
 {
 	int jobid_len = JOBSTATS_JOBID_SIZE;
 	int rc = 0;
-	ENTRY;
 
 	memset(jobid, 0, JOBSTATS_JOBID_SIZE);
 	/* Jobstats isn't enabled */
 	if (strcmp(obd_jobid_var, JOBSTATS_DISABLE) == 0)
-		RETURN(0);
+		return 0;
 
 	/* Use process name + fsuid as jobid */
 	if (strcmp(obd_jobid_var, JOBSTATS_PROCNAME_UID) == 0) {
 		snprintf(jobid, JOBSTATS_JOBID_SIZE, "%s.%u",
-			 current_comm(), current_fsuid());
-		RETURN(0);
+			 current_comm(),
+			 from_kuid(&init_user_ns, current_fsuid()));
+		return 0;
 	}
 
 	rc = cfs_get_environ(obd_jobid_var, jobid, &jobid_len);
@@ -150,7 +150,7 @@
 			       obd_jobid_var, rc);
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(lustre_get_jobid);
 
@@ -193,7 +193,6 @@
 	int rc;
 	int dev;
 
-	ENTRY;
 	if (!len || !name) {
 		CERROR("No name passed,!\n");
 		GOTO(out, rc = -EINVAL);
@@ -214,7 +213,7 @@
 	rc = dev;
 
 out:
-	RETURN(rc);
+	return rc;
 }
 
 int class_handle_ioctl(unsigned int cmd, unsigned long arg)
@@ -224,7 +223,6 @@
 	struct libcfs_debug_ioctl_data *debug_data;
 	struct obd_device *obd = NULL;
 	int err = 0, len = 0;
-	ENTRY;
 
 	/* only for debugging */
 	if (cmd == LIBCFS_IOC_DEBUG_MASK) {
@@ -237,7 +235,7 @@
 	CDEBUG(D_IOCTL, "cmd = %x\n", cmd);
 	if (obd_ioctl_getdata(&buf, &len, (void *)arg)) {
 		CERROR("OBD ioctl: data error\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	data = (struct obd_ioctl_data *)buf;
 
@@ -428,10 +426,10 @@
  out:
 	if (buf)
 		obd_ioctl_freedata(buf, len);
-	RETURN(err);
+	return err;
 } /* class_handle_ioctl */
 
-extern psdev_t obd_psdev;
+extern struct miscdevice obd_psdev;
 
 #define OBD_INIT_CHECK
 int obd_init_checks(void)
@@ -524,7 +522,7 @@
 					 LPROCFS_STATS_FLAG_IRQ_SAFE);
 	if (obd_memory == NULL) {
 		CERROR("kmalloc of 'obd_memory' failed\n");
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	lprocfs_counter_init(obd_memory, OBD_MEMORY_STAT,
@@ -558,10 +556,10 @@
 	/* Default the dirty page cache cap to 1/2 of system memory.
 	 * For clients with less memory, a larger fraction is needed
 	 * for other purposes (mostly for BGL). */
-	if (num_physpages <= 512 << (20 - PAGE_CACHE_SHIFT))
-		obd_max_dirty_pages = num_physpages / 4;
+	if (totalram_pages <= 512 << (20 - PAGE_CACHE_SHIFT))
+		obd_max_dirty_pages = totalram_pages / 4;
 	else
-		obd_max_dirty_pages = num_physpages / 2;
+		obd_max_dirty_pages = totalram_pages / 2;
 
 	err = obd_init_caches();
 	if (err)
@@ -638,7 +636,6 @@
 	int lustre_unregister_fs(void);
 	__u64 memory_leaked, pages_leaked;
 	__u64 memory_max, pages_max;
-	ENTRY;
 
 	lustre_unregister_fs();
 
@@ -678,12 +675,12 @@
 	CDEBUG((pages_leaked) ? D_ERROR : D_INFO,
 	       "obd_memory_pages max: "LPU64", leaked: "LPU64"\n",
 	       pages_max, pages_leaked);
-
-	EXIT;
 }
 
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Lustre Class Driver Build Version: " BUILD_VERSION);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
 
-cfs_module(obdclass, LUSTRE_VERSION_STRING, init_obdclass, cleanup_obdclass);
+module_init(init_obdclass);
+module_exit(cleanup_obdclass);
diff --git a/drivers/staging/lustre/lustre/obdclass/dt_object.c b/drivers/staging/lustre/lustre/obdclass/dt_object.c
index 1c962dd..1b164c7 100644
--- a/drivers/staging/lustre/lustre/obdclass/dt_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/dt_object.c
@@ -219,7 +219,6 @@
 			       struct lu_device *top_dev)
 {
 	struct lu_object *lo, *n;
-	ENTRY;
 
 	lo = lu_object_find_at(env, top_dev, fid, NULL);
 	if (IS_ERR(lo))
@@ -376,15 +375,13 @@
 	struct thandle *th;
 	int rc;
 
-	ENTRY;
-
 	dto = dt_locate(env, dt, fid);
 	if (IS_ERR(dto))
-		RETURN(dto);
+		return dto;
 
 	LASSERT(dto != NULL);
 	if (dt_object_exists(dto))
-		RETURN(dto);
+		return dto;
 
 	th = dt_trans_create(env, dt);
 	if (IS_ERR(th))
@@ -415,9 +412,9 @@
 out:
 	if (rc) {
 		lu_object_put(env, &dto->do_lu);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
-	RETURN(dto);
+	return dto;
 }
 EXPORT_SYMBOL(dt_find_or_create);
 
@@ -659,7 +656,6 @@
 	struct lu_idxpage	*lip = &lp->lp_idx;
 	char			*entry;
 	int			 rc, size;
-	ENTRY;
 
 	/* no support for variable key & record size for now */
 	LASSERT((ii->ii_flags & II_FL_VARKEY) == 0);
@@ -763,21 +759,20 @@
 	const struct dt_it_ops	*iops;
 	unsigned int		 pageidx, nob, nlupgs = 0;
 	int			 rc;
-	ENTRY;
 
 	LASSERT(rdpg->rp_pages != NULL);
 	LASSERT(obj->do_index_ops != NULL);
 
 	nob = rdpg->rp_count;
 	if (nob <= 0)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	/* Iterate through index and fill containers from @rdpg */
 	iops = &obj->do_index_ops->dio_it;
 	LASSERT(iops != NULL);
 	it = iops->init(env, obj, rdpg->rp_attrs, BYPASS_CAPA);
 	if (IS_ERR(it))
-		RETURN(PTR_ERR(it));
+		return PTR_ERR(it);
 
 	rc = iops->load(env, it, rdpg->rp_hash);
 	if (rc == 0) {
@@ -831,7 +826,7 @@
 	if (rc >= 0)
 		rc = min_t(unsigned int, nlupgs * LU_PAGE_SIZE, rdpg->rp_count);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(dt_index_walk);
 
@@ -855,26 +850,25 @@
 	const struct dt_index_features	*feat;
 	struct dt_object		*obj;
 	int				 rc;
-	ENTRY;
 
 	/* rp_count shouldn't be null and should be a multiple of the container
 	 * size */
 	if (rdpg->rp_count <= 0 && (rdpg->rp_count & (LU_PAGE_SIZE - 1)) != 0)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	if (fid_seq(&ii->ii_fid) >= FID_SEQ_NORMAL)
 		/* we don't support directory transfer via OBD_IDX_READ for the
 		 * time being */
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	if (!fid_is_quota(&ii->ii_fid))
 		/* block access to all local files except quota files */
-		RETURN(-EPERM);
+		return -EPERM;
 
 	/* lookup index object subject to the transfer */
 	obj = dt_locate(env, dev, &ii->ii_fid);
 	if (IS_ERR(obj))
-		RETURN(PTR_ERR(obj));
+		return PTR_ERR(obj);
 	if (dt_object_exists(obj) == 0)
 		GOTO(out, rc = -ENOENT);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index d96876e..68fe71c 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -163,20 +163,19 @@
 {
 	struct obd_type *type;
 	int rc = 0;
-	ENTRY;
 
 	/* sanity check */
 	LASSERT(strnlen(name, CLASS_MAX_NAME) < CLASS_MAX_NAME);
 
 	if (class_search_type(name)) {
 		CDEBUG(D_IOCTL, "Type %s already registered\n", name);
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 
 	rc = -ENOMEM;
 	OBD_ALLOC(type, sizeof(*type));
 	if (type == NULL)
-		RETURN(rc);
+		return rc;
 
 	OBD_ALLOC_PTR(type->typ_dt_ops);
 	OBD_ALLOC_PTR(type->typ_md_ops);
@@ -214,7 +213,7 @@
 	list_add(&type->typ_chain, &obd_types);
 	spin_unlock(&obd_types_lock);
 
-	RETURN (0);
+	return 0;
 
  failed:
 	if (type->typ_name != NULL)
@@ -224,18 +223,17 @@
 	if (type->typ_dt_ops != NULL)
 		OBD_FREE_PTR(type->typ_dt_ops);
 	OBD_FREE(type, sizeof(*type));
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_register_type);
 
 int class_unregister_type(const char *name)
 {
 	struct obd_type *type = class_search_type(name);
-	ENTRY;
 
 	if (!type) {
 		CERROR("unknown obd type\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (type->typ_refcnt) {
@@ -244,7 +242,7 @@
 		/* Remove ops, but leave the name for debugging */
 		OBD_FREE_PTR(type->typ_dt_ops);
 		OBD_FREE_PTR(type->typ_md_ops);
-		RETURN(-EBUSY);
+		return -EBUSY;
 	}
 
 	if (type->typ_procroot) {
@@ -263,7 +261,7 @@
 	if (type->typ_md_ops != NULL)
 		OBD_FREE_PTR(type->typ_md_ops);
 	OBD_FREE(type, sizeof(*type));
-	RETURN(0);
+	return 0;
 } /* class_unregister_type */
 EXPORT_SYMBOL(class_unregister_type);
 
@@ -285,17 +283,16 @@
 	struct obd_type *type = NULL;
 	int i;
 	int new_obd_minor = 0;
-	ENTRY;
 
 	if (strlen(name) >= MAX_OBD_NAME) {
 		CERROR("name/uuid must be < %u bytes long\n", MAX_OBD_NAME);
-		RETURN(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 	}
 
 	type = class_get_type(type_name);
 	if (type == NULL){
 		CERROR("OBD: unknown type: %s\n", type_name);
-		RETURN(ERR_PTR(-ENODEV));
+		return ERR_PTR(-ENODEV);
 	}
 
 	newdev = obd_device_alloc();
@@ -349,7 +346,7 @@
 	CDEBUG(D_IOCTL, "Adding new device %s (%p)\n",
 	       result->obd_name, result);
 
-	RETURN(result);
+	return result;
 out:
 	obd_device_free(newdev);
 out_type:
@@ -635,7 +632,6 @@
 
 void obd_cleanup_caches(void)
 {
-	ENTRY;
 	if (obd_device_cachep) {
 		kmem_cache_destroy(obd_device_cachep);
 		obd_device_cachep = NULL;
@@ -652,13 +648,10 @@
 		kmem_cache_destroy(capa_cachep);
 		capa_cachep = NULL;
 	}
-	EXIT;
 }
 
 int obd_init_caches(void)
 {
-	ENTRY;
-
 	LASSERT(obd_device_cachep == NULL);
 	obd_device_cachep = kmem_cache_create("ll_obd_dev_cache",
 						 sizeof(struct obd_device),
@@ -685,10 +678,10 @@
 	if (!capa_cachep)
 		GOTO(out, -ENOMEM);
 
-	RETURN(0);
+	return 0;
  out:
 	obd_cleanup_caches();
-	RETURN(-ENOMEM);
+	return -ENOMEM;
 
 }
 
@@ -696,21 +689,20 @@
 struct obd_export *class_conn2export(struct lustre_handle *conn)
 {
 	struct obd_export *export;
-	ENTRY;
 
 	if (!conn) {
 		CDEBUG(D_CACHE, "looking for null handle\n");
-		RETURN(NULL);
+		return NULL;
 	}
 
 	if (conn->cookie == -1) {  /* this means assign a new connection */
 		CDEBUG(D_CACHE, "want a new connection\n");
-		RETURN(NULL);
+		return NULL;
 	}
 
 	CDEBUG(D_INFO, "looking for export cookie "LPX64"\n", conn->cookie);
 	export = class_handle2object(conn->cookie);
-	RETURN(export);
+	return export;
 }
 EXPORT_SYMBOL(class_conn2export);
 
@@ -757,7 +749,6 @@
 static void class_export_destroy(struct obd_export *exp)
 {
 	struct obd_device *obd = exp->exp_obd;
-	ENTRY;
 
 	LASSERT_ATOMIC_ZERO(&exp->exp_refcount);
 	LASSERT(obd != NULL);
@@ -777,7 +768,6 @@
 	class_decref(obd, "export", exp);
 
 	OBD_FREE_RCU(exp, sizeof(*exp), &exp->exp_handle);
-	EXIT;
 }
 
 static void export_handle_addref(void *export)
@@ -828,7 +818,6 @@
 	struct obd_export *export;
 	cfs_hash_t *hash = NULL;
 	int rc = 0;
-	ENTRY;
 
 	OBD_ALLOC_PTR(export);
 	if (!export)
@@ -899,7 +888,7 @@
 	export->exp_obd->obd_num_exports++;
 	spin_unlock(&obd->obd_dev_lock);
 	cfs_hash_putref(hash);
-	RETURN(export);
+	return export;
 
 exit_unlock:
 	spin_unlock(&obd->obd_dev_lock);
@@ -936,8 +925,6 @@
 /* Import management functions */
 void class_import_destroy(struct obd_import *imp)
 {
-	ENTRY;
-
 	CDEBUG(D_IOCTL, "destroying import %p for %s\n", imp,
 		imp->imp_obd->obd_name);
 
@@ -958,7 +945,6 @@
 	LASSERT(imp->imp_sec == NULL);
 	class_decref(imp->imp_obd, "import", imp);
 	OBD_FREE_RCU(imp, sizeof(*imp), &imp->imp_handle);
-	EXIT;
 }
 
 static void import_handle_addref(void *import)
@@ -983,8 +969,6 @@
 
 void class_import_put(struct obd_import *imp)
 {
-	ENTRY;
-
 	LASSERT(list_empty(&imp->imp_zombie_chain));
 	LASSERT_ATOMIC_GT_LT(&imp->imp_refcount, 0, LI_POISON);
 
@@ -999,7 +983,6 @@
 
 	/* catch possible import put race */
 	LASSERT_ATOMIC_GE_LT(&imp->imp_refcount, 0, LI_POISON);
-	EXIT;
 }
 EXPORT_SYMBOL(class_import_put);
 
@@ -1121,18 +1104,17 @@
 	LASSERT(conn != NULL);
 	LASSERT(obd != NULL);
 	LASSERT(cluuid != NULL);
-	ENTRY;
 
 	export = class_new_export(obd, cluuid);
 	if (IS_ERR(export))
-		RETURN(PTR_ERR(export));
+		return PTR_ERR(export);
 
 	conn->cookie = export->exp_handle.h_cookie;
 	class_export_put(export);
 
 	CDEBUG(D_IOCTL, "connect: client %s, cookie "LPX64"\n",
 	       cluuid->uuid, conn->cookie);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(class_connect);
 
@@ -1188,11 +1170,10 @@
 int class_disconnect(struct obd_export *export)
 {
 	int already_disconnected;
-	ENTRY;
 
 	if (export == NULL) {
 		CWARN("attempting to free NULL export %p\n", export);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	spin_lock(&export->exp_lock);
@@ -1220,7 +1201,7 @@
 	class_unlink_export(export);
 no_disconn:
 	class_export_put(export);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(class_disconnect);
 
@@ -1243,7 +1224,6 @@
 {
 	int rc;
 	struct obd_export *exp;
-	ENTRY;
 
 	/* It's possible that an export may disconnect itself, but
 	 * nothing else will be added to this list. */
@@ -1281,13 +1261,11 @@
 		       obd_export_nid2str(exp), exp, rc);
 		class_export_put(exp);
 	}
-	EXIT;
 }
 
 void class_disconnect_exports(struct obd_device *obd)
 {
 	struct list_head work_list;
-	ENTRY;
 
 	/* Move all of the exports from obd_exports to a work list, en masse. */
 	INIT_LIST_HEAD(&work_list);
@@ -1304,7 +1282,6 @@
 	} else
 		CDEBUG(D_HA, "OBD device %d (%p) has no exports\n",
 		       obd->obd_minor, obd);
-	EXIT;
 }
 EXPORT_SYMBOL(class_disconnect_exports);
 
@@ -1316,7 +1293,6 @@
 	struct list_head work_list;
 	struct obd_export *exp, *n;
 	int evicted = 0;
-	ENTRY;
 
 	INIT_LIST_HEAD(&work_list);
 	spin_lock(&obd->obd_dev_lock);
@@ -1356,7 +1332,6 @@
 
 	class_disconnect_export_list(&work_list, exp_flags_from_obd(obd) |
 						 OBD_OPT_ABORT_RECOV);
-	EXIT;
 }
 EXPORT_SYMBOL(class_disconnect_stale_exports);
 
@@ -1484,7 +1459,7 @@
 		CERROR("%s: can't disconnect %s: no exports found\n",
 		       obd->obd_name, uuid);
 	} else {
-		CWARN("%s: evicting %s at adminstrative request\n",
+		CWARN("%s: evicting %s at administrative request\n",
 		       obd->obd_name, doomed_exp->exp_client_uuid.uuid);
 		class_fail_export(doomed_exp);
 		class_export_put(doomed_exp);
@@ -1585,7 +1560,6 @@
 {
 	struct obd_import *import;
 	struct obd_export *export;
-	ENTRY;
 
 	do {
 		spin_lock(&obd_zombie_impexp_lock);
@@ -1624,7 +1598,6 @@
 
 		cond_resched();
 	} while (import != NULL || export != NULL);
-	EXIT;
 }
 
 static struct completion	obd_zombie_start;
@@ -1649,7 +1622,7 @@
 	     !test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags);
 	spin_unlock(&obd_zombie_impexp_lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1751,7 +1724,7 @@
 
 	complete(&obd_zombie_stop);
 
-	RETURN(0);
+	return 0;
 }
 
 
@@ -1760,7 +1733,7 @@
  */
 int obd_zombie_impexp_init(void)
 {
-	task_t *task;
+	struct task_struct *task;
 
 	INIT_LIST_HEAD(&obd_zombie_imports);
 	INIT_LIST_HEAD(&obd_zombie_exports);
@@ -1772,10 +1745,10 @@
 
 	task = kthread_run(obd_zombie_impexp_thread, NULL, "obd_zombid");
 	if (IS_ERR(task))
-		RETURN(PTR_ERR(task));
+		return PTR_ERR(task);
 
 	wait_for_completion(&obd_zombie_start);
-	RETURN(0);
+	return 0;
 }
 /**
  * stop destroy zombie import/export thread
diff --git a/drivers/staging/lustre/lustre/obdclass/idmap.c b/drivers/staging/lustre/lustre/obdclass/idmap.c
index 622f8d1..ec2590f 100644
--- a/drivers/staging/lustre/lustre/obdclass/idmap.c
+++ b/drivers/staging/lustre/lustre/obdclass/idmap.c
@@ -59,8 +59,7 @@
  * groups_search() is copied from linux kernel!
  * A simple bsearch.
  */
-static int lustre_groups_search(group_info_t *group_info,
-				gid_t grp)
+static int lustre_groups_search(const struct group_info *group_info, gid_t grp)
 {
 	int left, right;
 
@@ -71,7 +70,8 @@
 	right = group_info->ngroups;
 	while (left < right) {
 		int mid = (left + right) / 2;
-		int cmp = grp - CFS_GROUP_AT(group_info, mid);
+		int cmp = grp -
+			from_kgid(&init_user_ns, CFS_GROUP_AT(group_info, mid));
 
 		if (cmp > 0)
 			left = mid + 1;
@@ -83,7 +83,7 @@
 	return 0;
 }
 
-void lustre_groups_from_list(group_info_t *ginfo, gid_t *glist)
+void lustre_groups_from_list(struct group_info *ginfo, gid_t *glist)
 {
 	int i;
 	int count = ginfo->ngroups;
@@ -102,7 +102,7 @@
 
 /* groups_sort() is copied from linux kernel! */
 /* a simple shell-metzner sort */
-void lustre_groups_sort(group_info_t *group_info)
+void lustre_groups_sort(struct group_info *group_info)
 {
 	int base, max, stride;
 	int gidsetsize = group_info->ngroups;
@@ -116,16 +116,19 @@
 		for (base = 0; base < max; base++) {
 			int left = base;
 			int right = left + stride;
-			gid_t tmp = CFS_GROUP_AT(group_info, right);
+			gid_t tmp = from_kgid(&init_user_ns,
+					      CFS_GROUP_AT(group_info, right));
 
 			while (left >= 0 &&
-			       CFS_GROUP_AT(group_info, left) > tmp) {
+			       tmp < from_kgid(&init_user_ns,
+					       CFS_GROUP_AT(group_info, left))) {
 				CFS_GROUP_AT(group_info, right) =
 				    CFS_GROUP_AT(group_info, left);
 				right = left;
 				left -= stride;
 			}
-			CFS_GROUP_AT(group_info, right) = tmp;
+			CFS_GROUP_AT(group_info, right) =
+						make_kgid(&init_user_ns, tmp);
 		}
 		stride /= 3;
 	}
@@ -137,7 +140,7 @@
 	int rc = 1;
 
 	if (grp != mu->uc_fsgid) {
-		group_info_t *group_info = NULL;
+		struct group_info *group_info = NULL;
 
 		if (mu->uc_ginfo || !mu->uc_identity ||
 		    mu->uc_valid == UCRED_OLD)
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index d2c3072..d1a57eb 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -83,27 +83,26 @@
 	struct obd_ioctl_data *data;
 	int err;
 	int offset = 0;
-	ENTRY;
 
 	err = copy_from_user(&hdr, (void *)arg, sizeof(hdr));
 	if ( err )
-		RETURN(err);
+		return err;
 
 	if (hdr.ioc_version != OBD_IOCTL_VERSION) {
 		CERROR("Version mismatch kernel (%x) vs application (%x)\n",
 		       OBD_IOCTL_VERSION, hdr.ioc_version);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (hdr.ioc_len > OBD_MAX_IOCTL_BUFFER) {
 		CERROR("User buffer len %d exceeds %d max buffer\n",
 		       hdr.ioc_len, OBD_MAX_IOCTL_BUFFER);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (hdr.ioc_len < sizeof(struct obd_ioctl_data)) {
 		CERROR("User buffer too small for ioctl (%d)\n", hdr.ioc_len);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* When there are lots of processes calling vmalloc on multi-core
@@ -114,7 +113,7 @@
 	if (*buf == NULL) {
 		CERROR("Cannot allocate control buffer of len %d\n",
 		       hdr.ioc_len);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	*len = hdr.ioc_len;
 	data = (struct obd_ioctl_data *)*buf;
@@ -122,13 +121,13 @@
 	err = copy_from_user(*buf, (void *)arg, hdr.ioc_len);
 	if ( err ) {
 		OBD_FREE_LARGE(*buf, hdr.ioc_len);
-		RETURN(err);
+		return err;
 	}
 
 	if (obd_ioctl_is_invalid(data)) {
 		CERROR("ioctl not correctly formatted\n");
 		OBD_FREE_LARGE(*buf, hdr.ioc_len);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (data->ioc_inllen1) {
@@ -150,7 +149,6 @@
 		data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
 	}
 
-	EXIT;
 	return 0;
 }
 EXPORT_SYMBOL(obd_ioctl_getdata);
@@ -169,19 +167,15 @@
 /*  opening /dev/obd */
 static int obd_class_open(struct inode * inode, struct file * file)
 {
-	ENTRY;
-
 	try_module_get(THIS_MODULE);
-	RETURN(0);
+	return 0;
 }
 
 /*  closing /dev/obd */
 static int obd_class_release(struct inode * inode, struct file * file)
 {
-	ENTRY;
-
 	module_put(THIS_MODULE);
-	RETURN(0);
+	return 0;
 }
 
 /* to control /dev/obd */
@@ -189,17 +183,16 @@
 			    unsigned long arg)
 {
 	int err = 0;
-	ENTRY;
 
 	/* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */
 	if (!cfs_capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET))
-		RETURN(err = -EACCES);
+		return err = -EACCES;
 	if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */
-		RETURN(err = -ENOTTY);
+		return err = -ENOTTY;
 
 	err = class_handle_ioctl(cmd, (unsigned long)arg);
 
-	RETURN(err);
+	return err;
 }
 
 /* declare character device */
@@ -211,7 +204,7 @@
 };
 
 /* modules setup */
-psdev_t obd_psdev = {
+struct miscdevice obd_psdev = {
 	.minor = OBD_DEV_MINOR,
 	.name  = OBD_DEV_NAME,
 	.fops  = &obd_psdev_fops,
@@ -385,24 +378,29 @@
 
 int class_procfs_init(void)
 {
-	int rc;
-	ENTRY;
+	int rc = 0;
 
 	obd_sysctl_init();
 	proc_lustre_root = lprocfs_register("fs/lustre", NULL,
 					    lprocfs_base, NULL);
+	if (IS_ERR(proc_lustre_root)) {
+		rc = PTR_ERR(proc_lustre_root);
+		proc_lustre_root = NULL;
+		goto out;
+	}
+
 	rc = lprocfs_seq_create(proc_lustre_root, "devices", 0444,
 				&obd_device_list_fops, NULL);
+out:
 	if (rc)
 		CERROR("error adding /proc/fs/lustre/devices file\n");
-	RETURN(0);
+	return 0;
 }
 
 int class_procfs_clean(void)
 {
-	ENTRY;
 	if (proc_lustre_root) {
 		lprocfs_remove(&proc_lustre_root);
 	}
-	RETURN(0);
+	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c
index 6ee3471..d3bb5ff 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-obdo.c
@@ -213,9 +213,9 @@
 	if (valid & OBD_MD_FLMODE)
 		dst->i_mode = (dst->i_mode & S_IFMT) | (src->o_mode & ~S_IFMT);
 	if (valid & OBD_MD_FLUID)
-		dst->i_uid = src->o_uid;
+		dst->i_uid = make_kuid(&init_user_ns, src->o_uid);
 	if (valid & OBD_MD_FLGID)
-		dst->i_gid = src->o_gid;
+		dst->i_gid = make_kgid(&init_user_ns, src->o_gid);
 	if (valid & OBD_MD_FLFLAGS)
 		dst->i_flags = src->o_flags;
 }
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
index 46aad68..acd2619 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c
@@ -38,8 +38,6 @@
 #include <linux/sysctl.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/sysctl.h>
-#include <linux/version.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
@@ -202,12 +200,12 @@
 					       1 << (20 - PAGE_CACHE_SHIFT));
 		/* Don't allow them to let dirty pages exceed 90% of system
 		 * memory and set a hard minimum of 4MB. */
-		if (obd_max_dirty_pages > ((num_physpages / 10) * 9)) {
+		if (obd_max_dirty_pages > ((totalram_pages / 10) * 9)) {
 			CERROR("Refusing to set max dirty pages to %u, which "
 			       "is more than 90%% of available RAM; setting "
 			       "to %lu\n", obd_max_dirty_pages,
-			       ((num_physpages / 10) * 9));
-			obd_max_dirty_pages = ((num_physpages / 10) * 9);
+			       ((totalram_pages / 10) * 9));
+			obd_max_dirty_pages = ((totalram_pages / 10) * 9);
 		} else if (obd_max_dirty_pages < 4 << (20 - PAGE_CACHE_SHIFT)) {
 			obd_max_dirty_pages = 4 << (20 - PAGE_CACHE_SHIFT);
 		}
@@ -431,7 +429,7 @@
 {
 #ifdef CONFIG_SYSCTL
 	if ( !obd_table_header )
-		obd_table_header = cfs_register_sysctl_table(parent_table, 0);
+		obd_table_header = register_sysctl_table(parent_table);
 #endif
 }
 
diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c
index b1d215e..0cb4428 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog.c
@@ -111,21 +111,20 @@
 {
 	struct llog_log_hdr *llh = loghandle->lgh_hdr;
 	int rc = 0;
-	ENTRY;
 
 	CDEBUG(D_RPCTRACE, "Canceling %d in log "DOSTID"\n",
 	       index, POSTID(&loghandle->lgh_id.lgl_oi));
 
 	if (index == 0) {
 		CERROR("Can't cancel index 0 which is header\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	spin_lock(&loghandle->lgh_hdr_lock);
 	if (!ext2_clear_bit(index, llh->llh_bitmap)) {
 		spin_unlock(&loghandle->lgh_hdr_lock);
 		CDEBUG(D_RPCTRACE, "Catalog index %u already clear?\n", index);
-		RETURN(-ENOENT);
+		return -ENOENT;
 	}
 
 	llh->llh_count--;
@@ -143,7 +142,7 @@
 			       loghandle->lgh_id.lgl_ogen, rc);
 			GOTO(out_err, rc);
 		}
-		RETURN(1);
+		return 1;
 	}
 	spin_unlock(&loghandle->lgh_hdr_lock);
 
@@ -156,7 +155,7 @@
 		       loghandle->lgh_id.lgl_ogen, rc);
 		GOTO(out_err, rc);
 	}
-	RETURN(0);
+	return 0;
 out_err:
 	spin_lock(&loghandle->lgh_hdr_lock);
 	ext2_set_bit(index, llh->llh_bitmap);
@@ -175,10 +174,10 @@
 
 	rc = llog_handle2ops(handle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (lop->lop_read_header == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	rc = lop->lop_read_header(env, handle);
 	if (rc == LLOG_EEMPTY) {
@@ -206,12 +205,11 @@
 	struct llog_log_hdr	*llh;
 	int			 rc;
 
-	ENTRY;
 	LASSERT(handle->lgh_hdr == NULL);
 
 	OBD_ALLOC_PTR(llh);
 	if (llh == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	handle->lgh_hdr = llh;
 	/* first assign flags to use llog_client_ops */
 	llh->llh_flags = flags;
@@ -263,7 +261,7 @@
 		OBD_FREE_PTR(llh);
 		handle->lgh_hdr = NULL;
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_init_handle);
 
@@ -277,7 +275,6 @@
 	char *cfg_buf = (char*) (rec + 1);
 	struct lustre_cfg *lcfg;
 	int rc = 0;
-	ENTRY;
 
 	/* Append all records */
 	local_rec.lrh_len -= sizeof(*rec) + sizeof(struct llog_rec_tail);
@@ -289,7 +286,7 @@
 	       rec->lrh_index, rc, rec->lrh_len, lcfg->lcfg_command,
 	       lustre_cfg_string(lcfg, 0), lustre_cfg_string(lcfg, 1));
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_copy_handler);
 
@@ -306,14 +303,12 @@
 	int				 saved_index = 0;
 	int				 last_called_index = 0;
 
-	ENTRY;
-
 	LASSERT(llh);
 
 	OBD_ALLOC(buf, LLOG_CHUNK_SIZE);
 	if (!buf) {
 		lpi->lpi_rc = -ENOMEM;
-		RETURN(0);
+		return 0;
 	}
 
 	if (cd != NULL) {
@@ -457,12 +452,10 @@
 	struct llog_process_info *lpi;
 	int		      rc;
 
-	ENTRY;
-
 	OBD_ALLOC_PTR(lpi);
 	if (lpi == NULL) {
 		CERROR("cannot alloc pointer\n");
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 	lpi->lpi_loghandle = loghandle;
 	lpi->lpi_cb	= cb;
@@ -480,7 +473,7 @@
 			CERROR("%s: cannot start thread: rc = %d\n",
 			       loghandle->lgh_ctxt->loc_obd->obd_name, rc);
 			OBD_FREE_PTR(lpi);
-			RETURN(rc);
+			return rc;
 		}
 		wait_for_completion(&lpi->lpi_completion);
 	} else {
@@ -489,7 +482,7 @@
 	}
 	rc = lpi->lpi_rc;
 	OBD_FREE_PTR(lpi);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_process_or_fork);
 
@@ -516,11 +509,10 @@
 	struct llog_process_cat_data *cd = catdata;
 	void *buf;
 	int rc = 0, first_index = 1, index, idx;
-	ENTRY;
 
 	OBD_ALLOC(buf, LLOG_CHUNK_SIZE);
 	if (!buf)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (cd != NULL)
 		first_index = cd->lpcd_first_idx + 1;
@@ -594,7 +586,7 @@
 out:
 	if (buf)
 		OBD_FREE(buf, LLOG_CHUNK_SIZE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_reverse_process);
 
@@ -617,16 +609,14 @@
 	struct llog_operations	*lop;
 	int			 rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(loghandle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_exist == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	rc = lop->lop_exist(loghandle);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_exist);
 
@@ -636,13 +626,11 @@
 	struct llog_operations	*lop;
 	int			 raised, rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(loghandle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_declare_create == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
 	if (!raised)
@@ -650,7 +638,7 @@
 	rc = lop->lop_declare_create(env, loghandle, th);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_declare_create);
 
@@ -660,13 +648,11 @@
 	struct llog_operations	*lop;
 	int			 raised, rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(handle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	if (lop->lop_create == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
 	if (!raised)
@@ -674,7 +660,7 @@
 	rc = lop->lop_create(env, handle, th);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_create);
 
@@ -686,14 +672,12 @@
 	struct llog_operations	*lop;
 	int			 raised, rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(handle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 	LASSERT(lop);
 	if (lop->lop_declare_write_rec == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
 	if (!raised)
@@ -701,7 +685,7 @@
 	rc = lop->lop_declare_write_rec(env, handle, rec, idx, th);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_declare_write_rec);
 
@@ -712,15 +696,13 @@
 	struct llog_operations	*lop;
 	int			 raised, rc, buflen;
 
-	ENTRY;
-
 	rc = llog_handle2ops(handle, &lop);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	LASSERT(lop);
 	if (lop->lop_write_rec == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	if (buf)
 		buflen = rec->lrh_len + sizeof(struct llog_rec_hdr) +
@@ -736,7 +718,7 @@
 				buf, idx, th);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_write_rec);
 
@@ -746,10 +728,8 @@
 {
 	int raised, rc;
 
-	ENTRY;
-
 	if (lgh->lgh_logops->lop_add == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
 	if (!raised)
@@ -757,7 +737,7 @@
 	rc = lgh->lgh_logops->lop_add(env, lgh, rec, logcookies, buf, th);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_add);
 
@@ -766,10 +746,8 @@
 {
 	int raised, rc;
 
-	ENTRY;
-
 	if (lgh->lgh_logops->lop_declare_add == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
 	if (!raised)
@@ -777,7 +755,7 @@
 	rc = lgh->lgh_logops->lop_declare_add(env, lgh, rec, th);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_declare_add);
 
@@ -792,14 +770,12 @@
 	struct thandle	*th;
 	int		 rc;
 
-	ENTRY;
-
 	rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (llog_exist(*res))
-		RETURN(0);
+		return 0;
 
 	if ((*res)->lgh_obj != NULL) {
 		struct dt_device *d;
@@ -825,7 +801,7 @@
 out:
 	if (rc)
 		llog_close(env, *res);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_open_create);
 
@@ -838,15 +814,13 @@
 	struct llog_handle	*handle;
 	int			 rc = 0, rc2;
 
-	ENTRY;
-
 	/* nothing to erase */
 	if (name == NULL && logid == NULL)
-		RETURN(0);
+		return 0;
 
 	rc = llog_open(env, ctxt, &handle, logid, name, LLOG_OPEN_EXISTS);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	rc = llog_init_handle(env, handle, LLOG_F_IS_PLAIN, NULL);
 	if (rc == 0)
@@ -855,7 +829,7 @@
 	rc2 = llog_close(env, handle);
 	if (rc == 0)
 		rc = rc2;
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_erase);
 
@@ -870,8 +844,6 @@
 {
 	int rc;
 
-	ENTRY;
-
 	LASSERT(loghandle);
 	LASSERT(loghandle->lgh_ctxt);
 
@@ -883,7 +855,7 @@
 
 		th = dt_trans_create(env, dt);
 		if (IS_ERR(th))
-			RETURN(PTR_ERR(th));
+			return PTR_ERR(th);
 
 		rc = llog_declare_write_rec(env, loghandle, rec, idx, th);
 		if (rc)
@@ -905,7 +877,7 @@
 				    cookiecount, buf, idx, NULL);
 		up_write(&loghandle->lgh_lock);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_write);
 
@@ -916,19 +888,17 @@
 	int	 raised;
 	int	 rc;
 
-	ENTRY;
-
 	LASSERT(ctxt);
 	LASSERT(ctxt->loc_logops);
 
 	if (ctxt->loc_logops->lop_open == NULL) {
 		*lgh = NULL;
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 	}
 
 	*lgh = llog_alloc_handle();
 	if (*lgh == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	(*lgh)->lgh_ctxt = ctxt;
 	(*lgh)->lgh_logops = ctxt->loc_logops;
 
@@ -942,7 +912,7 @@
 		llog_free_handle(*lgh);
 		*lgh = NULL;
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_open);
 
@@ -951,8 +921,6 @@
 	struct llog_operations	*lop;
 	int			 rc;
 
-	ENTRY;
-
 	rc = llog_handle2ops(loghandle, &lop);
 	if (rc)
 		GOTO(out, rc);
@@ -961,6 +929,6 @@
 	rc = lop->lop_close(env, loghandle);
 out:
 	llog_handle_put(loghandle);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_close);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_cat.c b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
index cf00b2f..c0f3af7 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_cat.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_cat.c
@@ -67,7 +67,6 @@
 	struct llog_log_hdr *llh;
 	struct llog_logid_rec rec = { { 0 }, };
 	int rc, index, bitmap_size;
-	ENTRY;
 
 	llh = cathandle->lgh_hdr;
 	bitmap_size = LLOG_BITMAP_SIZE(llh);
@@ -77,20 +76,20 @@
 	/* maximum number of available slots in catlog is bitmap_size - 2 */
 	if (llh->llh_cat_idx == index) {
 		CERROR("no free catalog slots for log...\n");
-		RETURN(-ENOSPC);
+		return -ENOSPC;
 	}
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_MDS_LLOG_CREATE_FAILED))
-		RETURN(-ENOSPC);
+		return -ENOSPC;
 
 	rc = llog_create(env, loghandle, th);
 	/* if llog is already created, no need to initialize it */
 	if (rc == -EEXIST) {
-		RETURN(0);
+		return 0;
 	} else if (rc != 0) {
 		CERROR("%s: can't create new plain llog in catalog: rc = %d\n",
 		       loghandle->lgh_ctxt->loc_obd->obd_name, rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = llog_init_handle(env, loghandle,
@@ -134,10 +133,10 @@
 		GOTO(out_destroy, rc);
 
 	loghandle->lgh_hdr->llh_cat_idx = index;
-	RETURN(0);
+	return 0;
 out_destroy:
 	llog_destroy(env, loghandle);
-	RETURN(rc);
+	return rc;
 }
 
 /* Open an existent log handle and add it to the open list.
@@ -155,10 +154,8 @@
 	struct llog_handle	*loghandle;
 	int			 rc = 0;
 
-	ENTRY;
-
 	if (cathandle == NULL)
-		RETURN(-EBADF);
+		return -EBADF;
 
 	down_write(&cathandle->lgh_lock);
 	list_for_each_entry(loghandle, &cathandle->u.chd.chd_head,
@@ -187,14 +184,14 @@
 		CERROR("%s: error opening log id "DOSTID":%x: rc = %d\n",
 		       cathandle->lgh_ctxt->loc_obd->obd_name,
 		       POSTID(&logid->lgl_oi), logid->lgl_ogen, rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = llog_init_handle(env, loghandle, LLOG_F_IS_PLAIN, NULL);
 	if (rc < 0) {
 		llog_close(env, loghandle);
 		loghandle = NULL;
-		RETURN(rc);
+		return rc;
 	}
 
 	down_write(&cathandle->lgh_lock);
@@ -205,7 +202,6 @@
 	loghandle->u.phd.phd_cookie.lgc_lgl = cathandle->lgh_id;
 	loghandle->u.phd.phd_cookie.lgc_index =
 				loghandle->lgh_hdr->llh_cat_idx;
-	EXIT;
 out:
 	llog_handle_get(loghandle);
 	*res = loghandle;
@@ -217,8 +213,6 @@
 	struct llog_handle	*loghandle, *n;
 	int			 rc;
 
-	ENTRY;
-
 	list_for_each_entry_safe(loghandle, n, &cathandle->u.chd.chd_head,
 				     u.phd.phd_entry) {
 		struct llog_log_hdr	*llh = loghandle->lgh_hdr;
@@ -246,7 +240,7 @@
 	if (cathandle->lgh_ctxt->loc_handle == cathandle)
 		cathandle->lgh_ctxt->loc_handle = NULL;
 	rc = llog_close(env, cathandle);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_close);
 
@@ -272,7 +266,6 @@
 						struct thandle *th)
 {
 	struct llog_handle *loghandle = NULL;
-	ENTRY;
 
 	down_read_nested(&cathandle->lgh_lock, LLOGH_CAT);
 	loghandle = cathandle->u.chd.chd_current_log;
@@ -284,7 +277,7 @@
 		if (llh == NULL ||
 		    loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
 			up_read(&cathandle->lgh_lock);
-			RETURN(loghandle);
+			return loghandle;
 		} else {
 			up_write(&loghandle->lgh_lock);
 		}
@@ -304,7 +297,7 @@
 		LASSERT(llh);
 		if (loghandle->lgh_last_idx < LLOG_BITMAP_SIZE(llh) - 1) {
 			up_write(&cathandle->lgh_lock);
-			RETURN(loghandle);
+			return loghandle;
 		} else {
 			up_write(&loghandle->lgh_lock);
 		}
@@ -318,7 +311,7 @@
 	down_write_nested(&loghandle->lgh_lock, LLOGH_LOG);
 	up_write(&cathandle->lgh_lock);
 	LASSERT(loghandle);
-	RETURN(loghandle);
+	return loghandle;
 }
 
 /* Add a single record to the recovery log(s) using a catalog
@@ -332,7 +325,6 @@
 {
 	struct llog_handle *loghandle;
 	int rc;
-	ENTRY;
 
 	LASSERT(rec->lrh_len <= LLOG_CHUNK_SIZE);
 	loghandle = llog_cat_current_log(cathandle, th);
@@ -343,7 +335,7 @@
 		rc = llog_cat_new_log(env, cathandle, loghandle, th);
 		if (rc < 0) {
 			up_write(&loghandle->lgh_lock);
-			RETURN(rc);
+			return rc;
 		}
 	}
 	/* now let's try to add the record */
@@ -361,7 +353,7 @@
 			rc = llog_cat_new_log(env, cathandle, loghandle, th);
 			if (rc < 0) {
 				up_write(&loghandle->lgh_lock);
-				RETURN(rc);
+				return rc;
 			}
 		}
 		/* now let's try to add the record */
@@ -372,7 +364,7 @@
 		up_write(&loghandle->lgh_lock);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_add_rec);
 
@@ -383,8 +375,6 @@
 	struct llog_handle	*loghandle, *next;
 	int			 rc = 0;
 
-	ENTRY;
-
 	if (cathandle->u.chd.chd_current_log == NULL) {
 		/* declare new plain llog */
 		down_write(&cathandle->lgh_lock);
@@ -437,7 +427,7 @@
 		llog_declare_write_rec(env, next, rec, -1, th);
 	}
 out:
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_declare_add_rec);
 
@@ -460,7 +450,7 @@
 
 		th = dt_trans_create(env, dt);
 		if (IS_ERR(th))
-			RETURN(PTR_ERR(th));
+			return PTR_ERR(th);
 
 		rc = llog_cat_declare_add_rec(env, cathandle, rec, th);
 		if (rc)
@@ -479,7 +469,7 @@
 			rc = llog_cat_add_rec(env, cathandle, rec, reccookie,
 					      buf, th);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_add);
 
@@ -498,8 +488,6 @@
 {
 	int i, index, rc = 0, failed = 0;
 
-	ENTRY;
-
 	for (i = 0; i < count; i++, cookies++) {
 		struct llog_handle	*loghandle;
 		struct llog_logid	*lgl = &cookies->lgc_lgl;
@@ -533,7 +521,7 @@
 		       cathandle->lgh_ctxt->loc_obd->obd_name, failed, count,
 		       rc);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_cancel_records);
 
@@ -545,10 +533,9 @@
 	struct llog_handle *llh;
 	int rc;
 
-	ENTRY;
 	if (rec->lrh_type != LLOG_LOGID_MAGIC) {
 		CERROR("invalid record in catalog\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
 	       DOSTID"\n", POSTID(&lir->lid_id.lgl_oi), lir->lid_id.lgl_ogen,
@@ -559,12 +546,12 @@
 		CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
 		       cat_llh->lgh_ctxt->loc_obd->obd_name,
 		       POSTID(&lir->lid_id.lgl_oi), rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (rec->lrh_index < d->lpd_startcat)
 		/* Skip processing of the logs until startcat */
-		RETURN(0);
+		return 0;
 
 	if (d->lpd_startidx > 0) {
 		struct llog_process_cat_data cd;
@@ -581,7 +568,7 @@
 	}
 	llog_handle_put(llh);
 
-	RETURN(rc);
+	return rc;
 }
 
 int llog_cat_process_or_fork(const struct lu_env *env,
@@ -592,7 +579,6 @@
 	struct llog_process_data d;
 	struct llog_log_hdr *llh = cat_llh->lgh_hdr;
 	int rc;
-	ENTRY;
 
 	LASSERT(llh->llh_flags & LLOG_F_IS_CAT);
 	d.lpd_data = data;
@@ -611,7 +597,7 @@
 		rc = llog_process_or_fork(env, cat_llh, llog_cat_process_cb,
 					  &d, &cd, fork);
 		if (rc != 0)
-			RETURN(rc);
+			return rc;
 
 		cd.lpcd_first_idx = 0;
 		cd.lpcd_last_idx = cat_llh->lgh_last_idx;
@@ -622,7 +608,7 @@
 					  &d, NULL, fork);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_process_or_fork);
 
@@ -645,7 +631,7 @@
 
 	if (le32_to_cpu(rec->lrh_type) != LLOG_LOGID_MAGIC) {
 		CERROR("invalid record in catalog\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
 	       DOSTID"\n", POSTID(&lir->lid_id.lgl_oi), lir->lid_id.lgl_ogen,
@@ -656,12 +642,12 @@
 		CERROR("%s: cannot find handle for llog "DOSTID": %d\n",
 		       cat_llh->lgh_ctxt->loc_obd->obd_name,
 		       POSTID(&lir->lid_id.lgl_oi), rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = llog_reverse_process(env, llh, d->lpd_cb, d->lpd_data, NULL);
 	llog_handle_put(llh);
-	RETURN(rc);
+	return rc;
 }
 
 int llog_cat_reverse_process(const struct lu_env *env,
@@ -672,7 +658,6 @@
 	struct llog_process_cat_data cd;
 	struct llog_log_hdr *llh = cat_llh->lgh_hdr;
 	int rc;
-	ENTRY;
 
 	LASSERT(llh->llh_flags & LLOG_F_IS_CAT);
 	d.lpd_data = data;
@@ -688,7 +673,7 @@
 					  llog_cat_reverse_process_cb,
 					  &d, &cd);
 		if (rc != 0)
-			RETURN(rc);
+			return rc;
 
 		cd.lpcd_first_idx = le32_to_cpu(llh->llh_cat_idx);
 		cd.lpcd_last_idx = 0;
@@ -701,7 +686,7 @@
 					  &d, NULL);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cat_reverse_process);
 
@@ -709,7 +694,6 @@
 {
 	struct llog_log_hdr *llh = cathandle->lgh_hdr;
 	int i, bitmap_size, idx;
-	ENTRY;
 
 	bitmap_size = LLOG_BITMAP_SIZE(llh);
 	if (llh->llh_cat_idx == (index - 1)) {
@@ -734,7 +718,7 @@
 		       POSTID(&cathandle->lgh_id.lgl_oi), llh->llh_cat_idx);
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 /* Cleanup deleted plain llog traces from catalog */
@@ -774,11 +758,9 @@
 	struct llog_log_hdr	*llh;
 	int			 rc;
 
-	ENTRY;
-
 	if (rec->lrh_type != LLOG_LOGID_MAGIC) {
 		CERROR("invalid record in catalog\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	CDEBUG(D_HA, "processing log "DOSTID":%x at index %u of catalog "
@@ -794,7 +776,7 @@
 			/* remove index from catalog */
 			llog_cat_cleanup(env, cathandle, NULL, rec->lrh_index);
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	llh = loghandle->lgh_hdr;
@@ -810,7 +792,7 @@
 	}
 	llog_handle_put(loghandle);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(cat_cancel_cb);
 
@@ -822,12 +804,12 @@
 
 	rc = llog_init_handle(env, llh, LLOG_F_IS_CAT, NULL);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = llog_process_or_fork(env, llh, cat_cancel_cb, NULL, NULL, false);
 	if (rc)
 		CERROR("%s: llog_process() with cat_cancel_cb failed: rc = "
 		       "%d\n", llh->lgh_ctxt->loc_obd->obd_name, rc);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(llog_cat_init_and_process);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c b/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
index 0732874..da558a5 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_ioctl.c
@@ -45,46 +45,45 @@
 	char *start, *end, *endp;
 	__u64 id, seq;
 
-	ENTRY;
 	start = str;
 	if (*start != '#')
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	start++;
 	if (start - str >= len - 1)
-		RETURN(-EINVAL);
+		return -EINVAL;
 	end = strchr(start, '#');
 	if (end == NULL || end == start)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	*end = '\0';
 	id = simple_strtoull(start, &endp, 0);
 	if (endp != end)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	start = ++end;
 	if (start - str >= len - 1)
-		RETURN(-EINVAL);
+		return -EINVAL;
 	end = strchr(start, '#');
 	if (end == NULL || end == start)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	*end = '\0';
 	seq = simple_strtoull(start, &endp, 0);
 	if (endp != end)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	ostid_set_seq(&logid->lgl_oi, seq);
 	ostid_set_id(&logid->lgl_oi, id);
 
 	start = ++end;
 	if (start - str >= len - 1)
-		RETURN(-EINVAL);
+		return -EINVAL;
 	logid->lgl_ogen = simple_strtoul(start, &endp, 16);
 	if (*endp != '\0')
-		RETURN(-EINVAL);
+		return -EINVAL;
 
-	RETURN(0);
+	return 0;
 }
 
 static int llog_check_cb(const struct lu_env *env, struct llog_handle *handle,
@@ -96,8 +95,6 @@
 	char *endp;
 	int cur_index, rc = 0;
 
-	ENTRY;
-
 	if (ioc_data && ioc_data->ioc_inllen1 > 0) {
 		l = 0;
 		remains = ioc_data->ioc_inllen4 +
@@ -106,19 +103,19 @@
 			cfs_size_round(ioc_data->ioc_inllen3);
 		from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
 		if (*endp != '\0')
-			RETURN(-EINVAL);
+			return -EINVAL;
 		to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
 		if (*endp != '\0')
-			RETURN(-EINVAL);
+			return -EINVAL;
 		ioc_data->ioc_inllen1 = 0;
 		out = ioc_data->ioc_bulk;
 	}
 
 	cur_index = rec->lrh_index;
 	if (cur_index < from)
-		RETURN(0);
+		return 0;
 	if (to > 0 && cur_index > to)
-		RETURN(-LLOG_EEMPTY);
+		return -LLOG_EEMPTY;
 
 	if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
 		struct llog_logid_rec	*lir = (struct llog_logid_rec *)rec;
@@ -131,13 +128,13 @@
 				     rec->lrh_len);
 		}
 		if (handle->lgh_ctxt == NULL)
-			RETURN(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 		rc = llog_cat_id2handle(env, handle, &loghandle, &lir->lid_id);
 		if (rc) {
 			CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
 			       POSTID(&lir->lid_id.lgl_oi),
 			       lir->lid_id.lgl_ogen);
-			RETURN(rc);
+			return rc;
 		}
 		rc = llog_process(env, loghandle, llog_check_cb, NULL, NULL);
 		llog_handle_put(loghandle);
@@ -167,10 +164,10 @@
 		if (remains <= 0) {
 			CERROR("%s: no space to print log records\n",
 			       handle->lgh_ctxt->loc_obd->obd_name);
-			RETURN(-LLOG_EEMPTY);
+			return -LLOG_EEMPTY;
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_print_cb(const struct lu_env *env, struct llog_handle *handle,
@@ -182,7 +179,6 @@
 	char *endp;
 	int cur_index;
 
-	ENTRY;
 	if (ioc_data != NULL && ioc_data->ioc_inllen1 > 0) {
 		l = 0;
 		remains = ioc_data->ioc_inllen4 +
@@ -191,26 +187,26 @@
 			cfs_size_round(ioc_data->ioc_inllen3);
 		from = simple_strtol(ioc_data->ioc_inlbuf2, &endp, 0);
 		if (*endp != '\0')
-			RETURN(-EINVAL);
+			return -EINVAL;
 		to = simple_strtol(ioc_data->ioc_inlbuf3, &endp, 0);
 		if (*endp != '\0')
-			RETURN(-EINVAL);
+			return -EINVAL;
 		out = ioc_data->ioc_bulk;
 		ioc_data->ioc_inllen1 = 0;
 	}
 
 	cur_index = rec->lrh_index;
 	if (cur_index < from)
-		RETURN(0);
+		return 0;
 	if (to > 0 && cur_index > to)
-		RETURN(-LLOG_EEMPTY);
+		return -LLOG_EEMPTY;
 
 	if (handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT) {
 		struct llog_logid_rec *lir = (struct llog_logid_rec *)rec;
 
 		if (rec->lrh_type != LLOG_LOGID_MAGIC) {
 			CERROR("invalid record in catalog\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		l = snprintf(out, remains,
@@ -222,7 +218,7 @@
 
 		rc = class_config_parse_rec(rec, out, remains);
 		if (rc < 0)
-			RETURN(rc);
+			return rc;
 		l = rc;
 	} else {
 		l = snprintf(out, remains,
@@ -233,10 +229,10 @@
 	remains -= l;
 	if (remains <= 0) {
 		CERROR("not enough space for print log records\n");
-		RETURN(-LLOG_EEMPTY);
+		return -LLOG_EEMPTY;
 	}
 
-	RETURN(0);
+	return 0;
 }
 static int llog_remove_log(const struct lu_env *env, struct llog_handle *cat,
 			   struct llog_logid *logid)
@@ -244,13 +240,11 @@
 	struct llog_handle	*log;
 	int			 rc;
 
-	ENTRY;
-
 	rc = llog_cat_id2handle(env, cat, &log, logid);
 	if (rc) {
 		CDEBUG(D_IOCTL, "cannot find log #"DOSTID"#%08x\n",
 		       POSTID(&logid->lgl_oi), logid->lgl_ogen);
-		RETURN(-ENOENT);
+		return -ENOENT;
 	}
 
 	rc = llog_destroy(env, log);
@@ -261,7 +255,7 @@
 	llog_cat_cleanup(env, cat, log, log->u.phd.phd_cookie.lgc_index);
 out:
 	llog_handle_put(log);
-	RETURN(rc);
+	return rc;
 
 }
 
@@ -271,12 +265,11 @@
 	struct llog_logid_rec	*lir = (struct llog_logid_rec *)rec;
 	int			 rc;
 
-	ENTRY;
 	if (rec->lrh_type != LLOG_LOGID_MAGIC)
-		RETURN(-EINVAL);
+		return -EINVAL;
 	rc = llog_remove_log(env, handle, &lir->lid_id);
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -287,25 +280,23 @@
 	int			 rc = 0;
 	struct llog_handle	*handle = NULL;
 
-	ENTRY;
-
 	if (*data->ioc_inlbuf1 == '#') {
 		rc = str2logid(&logid, data->ioc_inlbuf1, data->ioc_inllen1);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		rc = llog_open(env, ctxt, &handle, &logid, NULL,
 			       LLOG_OPEN_EXISTS);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	} else if (*data->ioc_inlbuf1 == '$') {
 		char *name = data->ioc_inlbuf1 + 1;
 
 		rc = llog_open(env, ctxt, &handle, NULL, name,
 			       LLOG_OPEN_EXISTS);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	} else {
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = llog_init_handle(env, handle, 0, NULL);
@@ -422,6 +413,6 @@
 		llog_cat_close(env, handle);
 	else
 		llog_close(env, handle);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_ioctl);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c b/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
index 7e12dc6..5385d8e 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_lvfs.c
@@ -64,7 +64,6 @@
 	struct llog_rec_hdr rec = { 0 };
 	struct llog_rec_tail tail;
 	int rc;
-	ENTRY;
 
 	LASSERT(len >= LLOG_MIN_REC_SIZE && (len & 0x7) == 0);
 
@@ -86,7 +85,7 @@
 	}
 
  out:
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_lvfs_write_blob(struct obd_device *obd, struct l_file *file,
@@ -97,8 +96,6 @@
 	loff_t saved_off = file->f_pos;
 	int buflen = rec->lrh_len;
 
-	ENTRY;
-
 	file->f_pos = off;
 
 	if (buflen == 0)
@@ -140,7 +137,7 @@
 	if (saved_off > file->f_pos)
 		file->f_pos = saved_off;
 	LASSERT(rc <= 0);
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_lvfs_read_blob(struct obd_device *obd, struct l_file *file,
@@ -148,14 +145,13 @@
 {
 	loff_t offset = off;
 	int rc;
-	ENTRY;
 
 	rc = fsfilt_read_record(obd, file, buf, size, &offset);
 	if (rc) {
 		CERROR("error reading log record: rc %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
-	RETURN(0);
+	return 0;
 }
 
 static int llog_lvfs_read_header(const struct lu_env *env,
@@ -163,7 +159,6 @@
 {
 	struct obd_device *obd;
 	int rc;
-	ENTRY;
 
 	LASSERT(sizeof(*handle->lgh_hdr) == LLOG_CHUNK_SIZE);
 
@@ -171,7 +166,7 @@
 
 	if (i_size_read(handle->lgh_file->f_dentry->d_inode) == 0) {
 		CDEBUG(D_HA, "not reading header from 0-byte log\n");
-		RETURN(LLOG_EEMPTY);
+		return LLOG_EEMPTY;
 	}
 
 	rc = llog_lvfs_read_blob(obd, handle->lgh_file, handle->lgh_hdr,
@@ -206,7 +201,7 @@
 	handle->lgh_last_idx = handle->lgh_hdr->llh_tail.lrt_index;
 	handle->lgh_file->f_pos = i_size_read(handle->lgh_file->f_dentry->d_inode);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* returns negative in on error; 0 if success && reccookie == 0; 1 otherwise */
@@ -223,7 +218,6 @@
 	struct obd_device *obd;
 	struct file *file;
 	size_t left;
-	ENTRY;
 
 	llh = loghandle->lgh_hdr;
 	file = loghandle->lgh_file;
@@ -236,7 +230,7 @@
 	else
 		rc = (reclen > LLOG_CHUNK_SIZE) ? -E2BIG : 0;
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (buf)
 		/* write_blob adds header and tail to lrh_len. */
@@ -253,7 +247,7 @@
 		}
 
 		if (idx && llh->llh_size && llh->llh_size != rec->lrh_len)
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		if (!ext2_test_bit(idx, llh->llh_bitmap))
 			CERROR("Modify unset record %u\n", idx);
@@ -263,7 +257,7 @@
 		rc = llog_lvfs_write_blob(obd, file, &llh->llh_hdr, NULL, 0);
 		/* we are done if we only write the header or on error */
 		if (rc || idx == 0)
-			RETURN(rc);
+			return rc;
 
 		if (buf) {
 			/* We assume that caller has set lgh_cur_* */
@@ -277,7 +271,7 @@
 			if (rec->lrh_index != loghandle->lgh_cur_idx) {
 				CERROR("modify idx mismatch %u/%d\n",
 				       idx, loghandle->lgh_cur_idx);
-				RETURN(-EFAULT);
+				return -EFAULT;
 			}
 		} else {
 			/* Assumes constant lrh_len */
@@ -290,7 +284,7 @@
 			reccookie->lgc_index = idx;
 			rc = 1;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	/* Make sure that records don't cross a chunk boundary, so we can
@@ -308,12 +302,12 @@
 		 index = loghandle->lgh_last_idx + 1;
 		 rc = llog_lvfs_pad(obd, file, left, index);
 		 if (rc)
-			 RETURN(rc);
+			 return rc;
 		 loghandle->lgh_last_idx++; /*for pad rec*/
 	 }
 	 /* if it's the last idx in log file, then return -ENOSPC */
 	 if (loghandle->lgh_last_idx >= LLOG_BITMAP_SIZE(llh) - 1)
-		 RETURN(-ENOSPC);
+		 return -ENOSPC;
 	loghandle->lgh_last_idx++;
 	index = loghandle->lgh_last_idx;
 	LASSERT(index < LLOG_BITMAP_SIZE(llh));
@@ -339,11 +333,11 @@
 
 	rc = llog_lvfs_write_blob(obd, file, &llh->llh_hdr, NULL, 0);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = llog_lvfs_write_blob(obd, file, rec, buf, file->f_pos);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CDEBUG(D_RPCTRACE, "added record "DOSTID": idx: %u, %u \n",
 	       POSTID(&loghandle->lgh_id.lgl_oi), index, rec->lrh_len);
@@ -362,7 +356,7 @@
 	if (rc == 0 && rec->lrh_type == LLOG_GEN_REC)
 		rc = 1;
 
-	RETURN(rc);
+	return rc;
 }
 
 /* We can skip reading at least as many log blocks as the number of
@@ -391,10 +385,9 @@
 				int len)
 {
 	int rc;
-	ENTRY;
 
 	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
 	       next_idx, *cur_idx, *cur_offset);
@@ -419,7 +412,7 @@
 			       POSTID(&loghandle->lgh_id.lgl_oi),
 			       loghandle->lgh_id.lgl_ogen,
 			       *cur_offset);
-			RETURN(rc);
+			return rc;
 		}
 
 		/* put number of bytes read into rc to make code simpler */
@@ -430,13 +423,13 @@
 		}
 
 		if (rc == 0) /* end of file, nothing to do */
-			RETURN(0);
+			return 0;
 
 		if (rc < sizeof(*tail)) {
 			CERROR("Invalid llog block at log id "DOSTID"/%u offset"
 			       LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
 			       loghandle->lgh_id.lgl_ogen, *cur_offset);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		rec = buf;
@@ -461,7 +454,7 @@
 			CERROR("Invalid llog tail at log id "DOSTID"/%u offset "
 			       LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
 			       loghandle->lgh_id.lgl_ogen, *cur_offset);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		if (tail->lrt_index < next_idx)
 			continue;
@@ -471,11 +464,11 @@
 		if (rec->lrh_index > next_idx) {
 			CERROR("missed desired record? %u > %u\n",
 			       rec->lrh_index, next_idx);
-			RETURN(-ENOENT);
+			return -ENOENT;
 		}
-		RETURN(0);
+		return 0;
 	}
-	RETURN(-EIO);
+	return -EIO;
 }
 
 static int llog_lvfs_prev_block(const struct lu_env *env,
@@ -484,10 +477,9 @@
 {
 	__u64 cur_offset;
 	int rc;
-	ENTRY;
 
 	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx);
 
@@ -508,20 +500,20 @@
 			       POSTID(&loghandle->lgh_id.lgl_oi),
 			       loghandle->lgh_id.lgl_ogen,
 			       cur_offset);
-			RETURN(rc);
+			return rc;
 		}
 
 		/* put number of bytes read into rc to make code simpler */
 		rc = cur_offset - ppos;
 
 		if (rc == 0) /* end of file, nothing to do */
-			RETURN(0);
+			return 0;
 
 		if (rc < sizeof(*tail)) {
 			CERROR("Invalid llog block at log id "DOSTID"/%u offset"
 			       LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
 			       loghandle->lgh_id.lgl_ogen, cur_offset);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		rec = buf;
@@ -544,7 +536,7 @@
 			CERROR("Invalid llog tail at log id "DOSTID"/%u offset"
 			       LPU64"\n", POSTID(&loghandle->lgh_id.lgl_oi),
 			       loghandle->lgh_id.lgl_ogen, cur_offset);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		if (tail->lrt_index < prev_idx)
 			continue;
@@ -554,11 +546,11 @@
 		if (rec->lrh_index > prev_idx) {
 			CERROR("missed desired record? %u > %u\n",
 			       rec->lrh_index, prev_idx);
-			RETURN(-ENOENT);
+			return -ENOENT;
 		}
-		RETURN(0);
+		return 0;
 	}
-	RETURN(-EIO);
+	return -EIO;
 }
 
 static struct file *llog_filp_open(char *dir, char *name, int flags, int mode)
@@ -593,8 +585,6 @@
 	struct obd_device	*obd;
 	int			 rc = 0;
 
-	ENTRY;
-
 	LASSERT(ctxt);
 	LASSERT(ctxt->loc_exp);
 	LASSERT(ctxt->loc_exp->exp_obd);
@@ -661,12 +651,12 @@
 	if (open_param != LLOG_OPEN_NEW && handle->lgh_file == NULL)
 		GOTO(out_name, rc = -ENOENT);
 
-	RETURN(0);
+	return 0;
 out_name:
 	if (handle->lgh_name != NULL)
 		OBD_FREE(handle->lgh_name, strlen(name) + 1);
 out:
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_lvfs_exist(struct llog_handle *handle)
@@ -688,8 +678,6 @@
 	int			 rc = 0;
 	int			 open_flags = O_RDWR | O_CREAT | O_LARGEFILE;
 
-	ENTRY;
-
 	LASSERT(ctxt);
 	LASSERT(ctxt->loc_exp);
 	obd = ctxt->loc_exp->exp_obd;
@@ -699,7 +687,7 @@
 		file = llog_filp_open(MOUNT_CONFIGS_DIR, handle->lgh_name,
 				      open_flags, 0644);
 		if (IS_ERR(file))
-			RETURN(PTR_ERR(file));
+			return PTR_ERR(file);
 
 		lustre_build_llog_lvfs_oid(&handle->lgh_id,
 				file->f_dentry->d_inode->i_ino,
@@ -708,7 +696,7 @@
 	} else {
 		OBDO_ALLOC(oa);
 		if (oa == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		ostid_set_seq_llog(&oa->o_oi);
 		oa->o_valid = OBD_MD_FLGENER | OBD_MD_FLGROUP;
@@ -736,7 +724,7 @@
 out:
 		OBDO_FREE(oa);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_lvfs_close(const struct lu_env *env,
@@ -744,10 +732,8 @@
 {
 	int rc;
 
-	ENTRY;
-
 	if (handle->lgh_file == NULL)
-		RETURN(0);
+		return 0;
 	rc = filp_close(handle->lgh_file, 0);
 	if (rc)
 		CERROR("%s: error closing llog #"DOSTID"#%08x: "
@@ -759,7 +745,7 @@
 		OBD_FREE(handle->lgh_name, strlen(handle->lgh_name) + 1);
 		handle->lgh_name = NULL;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_lvfs_destroy(const struct lu_env *env,
@@ -772,7 +758,6 @@
 	void *th;
 	struct inode *inode;
 	int rc, rc1;
-	ENTRY;
 
 	dir = MOUNT_CONFIGS_DIR;
 
@@ -795,12 +780,12 @@
 
 		dput(fdentry);
 		pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
-		RETURN(rc);
+		return rc;
 	}
 
 	OBDO_ALLOC(oa);
 	if (oa == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	oa->o_oi = handle->lgh_id.lgl_oi;
 	oa->o_generation = handle->lgh_id.lgl_ogen;
@@ -825,7 +810,7 @@
 		rc = rc1;
  out:
 	OBDO_FREE(oa);
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_lvfs_declare_create(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
index 7e22907..71817af 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c
@@ -110,7 +110,6 @@
 	struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 	struct obd_llog_group *olg;
 	int rc, idx;
-	ENTRY;
 
 	LASSERT(ctxt != NULL);
 	LASSERT(ctxt != LP_POISON);
@@ -139,7 +138,7 @@
 	l_wait_event(olg->olg_waitq,
 		     llog_group_ctxt_null(olg, idx), &lwi);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cleanup);
 
@@ -149,16 +148,15 @@
 {
 	struct llog_ctxt *ctxt;
 	int rc = 0;
-	ENTRY;
 
 	if (index < 0 || index >= LLOG_MAX_CTXTS)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	LASSERT(olg != NULL);
 
 	ctxt = llog_new_ctxt(obd);
 	if (!ctxt)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	ctxt->loc_obd = obd;
 	ctxt->loc_olg = olg;
@@ -189,7 +187,7 @@
 			}
 			rc = 0;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	if (op->lop_setup) {
@@ -210,22 +208,21 @@
 		ctxt->loc_flags &= ~LLOG_CTXT_FLAG_UNINITIALIZED;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_setup);
 
 int llog_sync(struct llog_ctxt *ctxt, struct obd_export *exp, int flags)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (!ctxt)
-		RETURN(0);
+		return 0;
 
 	if (CTXTP(ctxt, sync))
 		rc = CTXTP(ctxt, sync)(ctxt, exp, flags);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_sync);
 
@@ -234,15 +231,14 @@
 		 struct llog_cookie *logcookies, int numcookies)
 {
 	int raised, rc;
-	ENTRY;
 
 	if (!ctxt) {
 		CERROR("No ctxt\n");
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	if (ctxt->loc_flags & LLOG_CTXT_FLAG_UNINITIALIZED)
-		RETURN(-ENXIO);
+		return -ENXIO;
 
 	CTXT_CHECK_OP(ctxt, obd_add, -EOPNOTSUPP);
 	raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE);
@@ -252,7 +248,7 @@
 				  numcookies);
 	if (!raised)
 		cfs_cap_lower(CFS_CAP_SYS_RESOURCE);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_obd_add);
 
@@ -261,16 +257,15 @@
 		struct llog_cookie *cookies, int flags)
 {
 	int rc;
-	ENTRY;
 
 	if (!ctxt) {
 		CERROR("No ctxt\n");
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	CTXT_CHECK_OP(ctxt, cancel, -EOPNOTSUPP);
 	rc = CTXTP(ctxt, cancel)(env, ctxt, lsm, count, cookies, flags);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_cancel);
 
@@ -278,24 +273,24 @@
 		  struct obd_device *disk_obd, int *index)
 {
 	int rc;
-	ENTRY;
+
 	OBD_CHECK_DT_OP(obd, llog_init, 0);
 	OBD_COUNTER_INCREMENT(obd, llog_init);
 
 	rc = OBP(obd, llog_init)(obd, olg, disk_obd, index);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(obd_llog_init);
 
 int obd_llog_finish(struct obd_device *obd, int count)
 {
 	int rc;
-	ENTRY;
+
 	OBD_CHECK_DT_OP(obd, llog_finish, 0);
 	OBD_COUNTER_INCREMENT(obd, llog_finish);
 
 	rc = OBP(obd, llog_finish)(obd, count);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(obd_llog_finish);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_osd.c b/drivers/staging/lustre/lustre/obdclass/llog_osd.c
index 6dbd21a..654c8e1 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_osd.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_osd.c
@@ -41,10 +41,6 @@
 
 #define DEBUG_SUBSYSTEM S_LOG
 
-#ifndef EXPORT_SYMTAB
-#define EXPORT_SYMTAB
-#endif
-
 #include <obd.h>
 #include <obd_class.h>
 #include <lustre_fid.h>
@@ -97,8 +93,6 @@
 	struct llog_thread_info	*lgi = llog_info(env);
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(th);
 	LASSERT(off);
 	LASSERT(len >= LLOG_MIN_REC_SIZE && (len & 0x7) == 0);
@@ -126,7 +120,7 @@
 		       o->do_lu.lo_dev->ld_obd->obd_name, rc);
 out:
 	dt_write_unlock(env, o);
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_osd_write_blob(const struct lu_env *env, struct dt_object *o,
@@ -137,8 +131,6 @@
 	int			 buflen = rec->lrh_len;
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(env);
 	LASSERT(o);
 
@@ -203,7 +195,7 @@
 		dt_attr_set(env, o, &lgi->lgi_attr, th, BYPASS_CAPA);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_osd_read_header(const struct lu_env *env,
@@ -214,8 +206,6 @@
 	struct llog_thread_info	*lgi;
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(sizeof(*handle->lgh_hdr) == LLOG_CHUNK_SIZE);
 
 	o = handle->lgh_obj;
@@ -225,13 +215,13 @@
 
 	rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	LASSERT(lgi->lgi_attr.la_valid & LA_SIZE);
 
 	if (lgi->lgi_attr.la_size == 0) {
 		CDEBUG(D_HA, "not reading header from 0-byte log\n");
-		RETURN(LLOG_EEMPTY);
+		return LLOG_EEMPTY;
 	}
 
 	lgi->lgi_off = 0;
@@ -243,7 +233,7 @@
 		CERROR("%s: error reading log header from "DFID": rc = %d\n",
 		       o->do_lu.lo_dev->ld_obd->obd_name,
 		       PFID(lu_object_fid(&o->do_lu)), rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	llh_hdr = &handle->lgh_hdr->llh_hdr;
@@ -256,7 +246,7 @@
 		       handle->lgh_name ? handle->lgh_name : "",
 		       PFID(lu_object_fid(&o->do_lu)),
 		       llh_hdr->lrh_type, LLOG_HDR_MAGIC);
-		RETURN(-EIO);
+		return -EIO;
 	} else if (llh_hdr->lrh_len != LLOG_CHUNK_SIZE) {
 		CERROR("%s: incorrectly sized log %s "DFID" header: "
 		       "%#x (expected %#x)\n"
@@ -265,12 +255,12 @@
 		       handle->lgh_name ? handle->lgh_name : "",
 		       PFID(lu_object_fid(&o->do_lu)),
 		       llh_hdr->lrh_len, LLOG_CHUNK_SIZE);
-		RETURN(-EIO);
+		return -EIO;
 	}
 
 	handle->lgh_last_idx = handle->lgh_hdr->llh_tail.lrt_index;
 
-	RETURN(0);
+	return 0;
 }
 
 static int llog_osd_declare_write_rec(const struct lu_env *env,
@@ -282,8 +272,6 @@
 	struct dt_object	*o;
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(env);
 	LASSERT(th);
 	LASSERT(loghandle);
@@ -295,18 +283,18 @@
 	rc = dt_declare_record_write(env, o, sizeof(struct llog_log_hdr), 0,
 				     th);
 	if (rc || idx == 0) /* if error or just header */
-		RETURN(rc);
+		return rc;
 
 	if (dt_object_exists(o)) {
 		rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA);
 		lgi->lgi_off = lgi->lgi_attr.la_size;
 		LASSERT(ergo(rc == 0, lgi->lgi_attr.la_valid & LA_SIZE));
 		if (rc)
-			RETURN(rc);
+			return rc;
 
 		rc = dt_declare_punch(env, o, lgi->lgi_off, OBD_OBJECT_EOF, th);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	} else {
 		lgi->lgi_off = 0;
 	}
@@ -314,7 +302,7 @@
 	/* XXX: implement declared window or multi-chunks approach */
 	rc = dt_declare_record_write(env, o, 32 * 1024, lgi->lgi_off, th);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* returns negative in on error; 0 if success && reccookie == 0; 1 otherwise */
@@ -333,8 +321,6 @@
 	struct dt_object	*o;
 	size_t			 left;
 
-	ENTRY;
-
 	LASSERT(env);
 	llh = loghandle->lgh_hdr;
 	LASSERT(llh);
@@ -352,11 +338,11 @@
 	else
 		rc = (reclen > LLOG_CHUNK_SIZE) ? -E2BIG : 0;
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (buf)
 		/* write_blob adds header and tail to lrh_len. */
@@ -369,7 +355,7 @@
 			LBUG();
 
 		if (idx && llh->llh_size && llh->llh_size != rec->lrh_len)
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		if (!ext2_test_bit(idx, llh->llh_bitmap))
 			CERROR("%s: modify unset record %u\n",
@@ -384,7 +370,7 @@
 					 &lgi->lgi_off, th);
 		/* we are done if we only write the header or on error */
 		if (rc || idx == 0)
-			RETURN(rc);
+			return rc;
 
 		if (buf) {
 			/* We assume that caller has set lgh_cur_* */
@@ -400,7 +386,7 @@
 				CERROR("%s: modify idx mismatch %u/%d\n",
 				       o->do_lu.lo_dev->ld_obd->obd_name, idx,
 				       loghandle->lgh_cur_idx);
-				RETURN(-EFAULT);
+				return -EFAULT;
 			}
 		} else {
 			/* Assumes constant lrh_len */
@@ -413,7 +399,7 @@
 			reccookie->lgc_index = idx;
 			rc = 1;
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	/* Make sure that records don't cross a chunk boundary, so we can
@@ -432,12 +418,12 @@
 		index = loghandle->lgh_last_idx + 1;
 		rc = llog_osd_pad(env, o, &lgi->lgi_off, left, index, th);
 		if (rc)
-			RETURN(rc);
+			return rc;
 		loghandle->lgh_last_idx++; /*for pad rec*/
 	}
 	/* if it's the last idx in log file, then return -ENOSPC */
 	if (loghandle->lgh_last_idx >= LLOG_BITMAP_SIZE(llh) - 1)
-		RETURN(-ENOSPC);
+		return -ENOSPC;
 
 	loghandle->lgh_last_idx++;
 	index = loghandle->lgh_last_idx;
@@ -509,7 +495,7 @@
 			reccookie->lgc_subsys = -1;
 		rc = 1;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /* We can skip reading at least as many log blocks as the number of
@@ -541,13 +527,11 @@
 	struct dt_device	*dt;
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(env);
 	LASSERT(lgi);
 
 	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
 	       next_idx, *cur_idx, *cur_offset);
@@ -668,10 +652,8 @@
 	loff_t			 cur_offset;
 	int			 rc;
 
-	ENTRY;
-
 	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx);
 
@@ -798,8 +780,6 @@
 	struct local_oid_storage	*los;
 	int				 rc = 0;
 
-	ENTRY;
-
 	LASSERT(env);
 	LASSERT(ctxt);
 	LASSERT(ctxt->loc_exp);
@@ -809,7 +789,7 @@
 
 	ls = ls_device_get(dt);
 	if (IS_ERR(ls))
-		RETURN(PTR_ERR(ls));
+		return PTR_ERR(ls);
 
 	mutex_lock(&ls->ls_los_mutex);
 	los = dt_los_find(ls, name != NULL ? FID_SEQ_LLOG_NAME : FID_SEQ_LLOG);
@@ -864,7 +844,7 @@
 	handle->private_data = los;
 	LASSERT(handle->lgh_ctxt);
 
-	RETURN(rc);
+	return rc;
 
 out_put:
 	lu_object_put(env, &o->do_lu);
@@ -873,7 +853,7 @@
 		OBD_FREE(handle->lgh_name, strlen(name) + 1);
 out:
 	dt_los_put(los);
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_osd_exist(struct llog_handle *handle)
@@ -891,33 +871,31 @@
 	struct dt_object		*o;
 	int				 rc;
 
-	ENTRY;
-
 	LASSERT(res->lgh_obj);
 	LASSERT(th);
 
 	/* object can be created by another thread */
 	o = res->lgh_obj;
 	if (dt_object_exists(o))
-		RETURN(0);
+		return 0;
 
 	los = res->private_data;
 	LASSERT(los);
 
 	rc = llog_osd_declare_new_object(env, los, o, th);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = dt_declare_record_write(env, o, LLOG_CHUNK_SIZE, 0, th);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (res->lgh_name) {
 		struct dt_object *llog_dir;
 
 		llog_dir = llog_osd_dir_get(env, res->lgh_ctxt);
 		if (IS_ERR(llog_dir))
-			RETURN(PTR_ERR(llog_dir));
+			return PTR_ERR(llog_dir);
 		logid_to_fid(&res->lgh_id, &lgi->lgi_fid);
 		rc = dt_declare_insert(env, llog_dir,
 				       (struct dt_rec *)&lgi->lgi_fid,
@@ -928,7 +906,7 @@
 			       o->do_lu.lo_dev->ld_obd->obd_name,
 			       res->lgh_name, rc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /* This is a callback from the llog_* functions.
@@ -941,15 +919,13 @@
 	struct dt_object	*o;
 	int		      rc = 0;
 
-	ENTRY;
-
 	LASSERT(env);
 	o = res->lgh_obj;
 	LASSERT(o);
 
 	/* llog can be already created */
 	if (dt_object_exists(o))
-		RETURN(-EEXIST);
+		return -EEXIST;
 
 	los = res->private_data;
 	LASSERT(los);
@@ -962,14 +938,14 @@
 
 	dt_write_unlock(env, o);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (res->lgh_name) {
 		struct dt_object *llog_dir;
 
 		llog_dir = llog_osd_dir_get(env, res->lgh_ctxt);
 		if (IS_ERR(llog_dir))
-			RETURN(PTR_ERR(llog_dir));
+			return PTR_ERR(llog_dir);
 
 		logid_to_fid(&res->lgh_id, &lgi->lgi_fid);
 		dt_read_lock(env, llog_dir, 0);
@@ -984,7 +960,7 @@
 			       o->do_lu.lo_dev->ld_obd->obd_name,
 			       res->lgh_name, rc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_osd_close(const struct lu_env *env, struct llog_handle *handle)
@@ -992,8 +968,6 @@
 	struct local_oid_storage	*los;
 	int				 rc = 0;
 
-	ENTRY;
-
 	LASSERT(handle->lgh_obj);
 
 	lu_object_put(env, &handle->lgh_obj->do_lu);
@@ -1005,7 +979,7 @@
 	if (handle->lgh_name)
 		OBD_FREE(handle->lgh_name, strlen(handle->lgh_name) + 1);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_osd_destroy(const struct lu_env *env,
@@ -1018,8 +992,6 @@
 	char			*name = NULL;
 	int			 rc;
 
-	ENTRY;
-
 	ctxt = loghandle->lgh_ctxt;
 	LASSERT(ctxt);
 
@@ -1032,7 +1004,7 @@
 
 	th = dt_trans_create(env, d);
 	if (IS_ERR(th))
-		RETURN(PTR_ERR(th));
+		return PTR_ERR(th);
 
 	if (loghandle->lgh_name) {
 		llog_dir = llog_osd_dir_get(env, ctxt);
@@ -1082,7 +1054,7 @@
 	dt_trans_stop(env, d, th);
 	if (llog_dir != NULL)
 		lu_object_put(env, &llog_dir->do_lu);
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_osd_setup(const struct lu_env *env, struct obd_device *obd,
@@ -1094,8 +1066,6 @@
 	struct llog_ctxt		*ctxt;
 	int				 rc = 0;
 
-	ENTRY;
-
 	LASSERT(obd);
 	LASSERT(olg->olg_ctxts[ctxt_idx]);
 
@@ -1131,7 +1101,7 @@
 	dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt;
 	ls = ls_device_get(dt);
 	if (IS_ERR(ls))
-		RETURN(PTR_ERR(ls));
+		return PTR_ERR(ls);
 
 	mutex_lock(&ls->ls_los_mutex);
 	los = dt_los_find(ls, FID_SEQ_LLOG);
@@ -1175,8 +1145,6 @@
 	struct thandle		*th;
 	int			 rc, size;
 
-	ENTRY;
-
 	LASSERT(d);
 
 	size = sizeof(*idarray) * count;
@@ -1186,7 +1154,7 @@
 
 	o = dt_locate(env, d, &lgi->lgi_fid);
 	if (IS_ERR(o))
-		RETURN(PTR_ERR(o));
+		return PTR_ERR(o);
 
 	if (!dt_object_exists(o)) {
 		th = dt_trans_create(env, d);
@@ -1253,10 +1221,9 @@
 		GOTO(out, rc);
 	}
 
-	EXIT;
 out:
 	lu_object_put(env, &o->do_lu);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_osd_get_cat_list);
 
@@ -1270,7 +1237,7 @@
 	int			 rc, size;
 
 	if (!count)
-		RETURN(0);
+		return 0;
 
 	LASSERT(d);
 
@@ -1281,7 +1248,7 @@
 
 	o = dt_locate(env, d, &lgi->lgi_fid);
 	if (IS_ERR(o))
-		RETURN(PTR_ERR(o));
+		return PTR_ERR(o);
 
 	if (!dt_object_exists(o))
 		GOTO(out, rc = -ENOENT);
@@ -1318,6 +1285,6 @@
 	dt_trans_stop(env, d, th);
 out:
 	lu_object_put(env, &o->do_lu);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_osd_put_cat_list);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
index dedfecf..24ca099 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
@@ -88,7 +88,6 @@
 
 void lustre_swab_llogd_body (struct llogd_body *d)
 {
-	ENTRY;
 	print_llogd_body(d);
 	lustre_swab_llog_id(&d->lgd_logid);
 	__swab32s (&d->lgd_ctxt_idx);
@@ -98,7 +97,6 @@
 	__swab32s (&d->lgd_len);
 	__swab64s (&d->lgd_cur_offset);
 	print_llogd_body(d);
-	EXIT;
 }
 EXPORT_SYMBOL(lustre_swab_llogd_body);
 
@@ -203,6 +201,23 @@
 		break;
 	}
 
+	case HSM_AGENT_REC: {
+		struct llog_agent_req_rec *arr =
+			(struct llog_agent_req_rec *)rec;
+
+		__swab32s(&arr->arr_hai.hai_len);
+		__swab32s(&arr->arr_hai.hai_action);
+		lustre_swab_lu_fid(&arr->arr_hai.hai_fid);
+		lustre_swab_lu_fid(&arr->arr_hai.hai_dfid);
+		__swab64s(&arr->arr_hai.hai_cookie);
+		__swab64s(&arr->arr_hai.hai_extent.offset);
+		__swab64s(&arr->arr_hai.hai_extent.length);
+		__swab64s(&arr->arr_hai.hai_gid);
+		/* no swabing for opaque data */
+		/* hai_data[0]; */
+		break;
+	}
+
 	case MDS_SETATTR64_REC:
 	{
 		struct llog_setattr64_rec *lsr =
@@ -281,20 +296,17 @@
 
 void lustre_swab_llog_hdr (struct llog_log_hdr *h)
 {
-	ENTRY;
 	print_llog_hdr(h);
 
 	lustre_swab_llog_rec(&h->llh_hdr);
 
 	print_llog_hdr(h);
-	EXIT;
 }
 EXPORT_SYMBOL(lustre_swab_llog_hdr);
 
 static void print_lustre_cfg(struct lustre_cfg *lcfg)
 {
 	int i;
-	ENTRY;
 
 	if (!(libcfs_debug & D_OTHER)) /* don't loop on nothing */
 		return;
@@ -311,20 +323,17 @@
 		for (i = 0; i < lcfg->lcfg_bufcount; i++)
 			CDEBUG(D_OTHER, "\tlcfg->lcfg_buflens[%d]: %d\n",
 			       i, lcfg->lcfg_buflens[i]);
-	EXIT;
 }
 
 void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg)
 {
 	int i;
-	ENTRY;
 
 	__swab32s(&lcfg->lcfg_version);
 
 	if (lcfg->lcfg_version != LUSTRE_CFG_VERSION) {
 		CERROR("not swabbing lustre_cfg version %#x (expecting %#x)\n",
 		       lcfg->lcfg_version, LUSTRE_CFG_VERSION);
-		EXIT;
 		return;
 	}
 
@@ -337,7 +346,6 @@
 		__swab32s(&lcfg->lcfg_buflens[i]);
 
 	print_lustre_cfg(lcfg);
-	EXIT;
 	return;
 }
 EXPORT_SYMBOL(lustre_swab_lustre_cfg);
@@ -360,7 +368,6 @@
 void lustre_swab_cfg_marker(struct cfg_marker *marker, int swab, int size)
 {
 	struct cfg_marker32 *cm32 = (struct cfg_marker32*)marker;
-	ENTRY;
 
 	if (swab) {
 		__swab32s(&marker->cm_step);
@@ -401,7 +408,6 @@
 		__swab64s(&marker->cm_canceltime);
 	}
 
-	EXIT;
 	return;
 }
 EXPORT_SYMBOL(lustre_swab_cfg_marker);
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_test.c b/drivers/staging/lustre/lustre/obdclass/llog_test.c
index d397f78..d9e6d12 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_test.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_test.c
@@ -78,22 +78,22 @@
 	if (active_recs != num_recs) {
 		CERROR("%s: expected %d active recs after write, found %d\n",
 		       test, num_recs, active_recs);
-		RETURN(-ERANGE);
+		return -ERANGE;
 	}
 
 	if (llh->lgh_hdr->llh_count != num_recs) {
 		CERROR("%s: handle->count is %d, expected %d after write\n",
 		       test, llh->lgh_hdr->llh_count, num_recs);
-		RETURN(-ERANGE);
+		return -ERANGE;
 	}
 
 	if (llh->lgh_last_idx < last_idx) {
 		CERROR("%s: handle->last_idx is %d, expected %d after write\n",
 		       test, llh->lgh_last_idx, last_idx);
-		RETURN(-ERANGE);
+		return -ERANGE;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 /* Test named-log create/open, close */
@@ -105,8 +105,6 @@
 	int rc;
 	int rc2;
 
-	ENTRY;
-
 	CWARN("1a: create a log with name: %s\n", name);
 	ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
 	LASSERT(ctxt);
@@ -134,7 +132,7 @@
 	}
 out:
 	llog_ctxt_put(ctxt);
-	RETURN(rc);
+	return rc;
 }
 
 /* Test named-log reopen; returns opened log on success */
@@ -146,8 +144,6 @@
 	struct llog_logid	 logid;
 	int			 rc;
 
-	ENTRY;
-
 	CWARN("2a: re-open a log with name: %s\n", name);
 	ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
 	LASSERT(ctxt);
@@ -213,7 +209,7 @@
 out_put:
 	llog_ctxt_put(ctxt);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Test record writing, single and in bulk */
@@ -224,8 +220,6 @@
 	int			 rc, i;
 	int			 num_recs = 1; /* 1 for the header */
 
-	ENTRY;
-
 	lgr.lgr_hdr.lrh_len = lgr.lgr_tail.lrt_len = sizeof(lgr);
 	lgr.lgr_hdr.lrh_type = LLOG_GEN_REC;
 
@@ -234,12 +228,12 @@
 	num_recs++;
 	if (rc < 0) {
 		CERROR("3a: write one log record failed: %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = verify_handle("3a", llh, num_recs);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CWARN("3b: write 10 cfg log records with 8 bytes bufs\n");
 	for (i = 0; i < 10; i++) {
@@ -253,14 +247,14 @@
 		if (rc < 0) {
 			CERROR("3b: write 10 records failed at #%d: %d\n",
 			       i + 1, rc);
-			RETURN(rc);
+			return rc;
 		}
 		num_recs++;
 	}
 
 	rc = verify_handle("3b", llh, num_recs);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CWARN("3c: write 1000 more log records\n");
 	for (i = 0; i < 1000; i++) {
@@ -268,14 +262,14 @@
 		if (rc < 0) {
 			CERROR("3c: write 1000 records failed at #%d: %d\n",
 			       i + 1, rc);
-			RETURN(rc);
+			return rc;
 		}
 		num_recs++;
 	}
 
 	rc = verify_handle("3c", llh, num_recs);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	CWARN("3d: write log more than BITMAP_SIZE, return -ENOSPC\n");
 	for (i = 0; i < LLOG_BITMAP_SIZE(llh->lgh_hdr) + 1; i++) {
@@ -299,20 +293,20 @@
 		} else if (rc < 0) {
 			CERROR("3d: write recs failed at #%d: %d\n",
 			       i + 1, rc);
-			RETURN(rc);
+			return rc;
 		}
 		num_recs++;
 	}
 	if (rc != -ENOSPC) {
 		CWARN("3d: write record more than BITMAP size!\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	CWARN("3d: wrote %d more records before end of llog is reached\n",
 	      num_recs);
 
 	rc = verify_handle("3d", llh, num_recs);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Test catalogue additions */
@@ -328,8 +322,6 @@
 	char			*buf;
 	struct llog_rec_hdr	 rec;
 
-	ENTRY;
-
 	ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
 	LASSERT(ctxt);
 
@@ -424,7 +416,7 @@
 	}
 ctxt_release:
 	llog_ctxt_put(ctxt);
-	RETURN(rc);
+	return rc;
 }
 
 static int cat_counter;
@@ -437,7 +429,7 @@
 
 	if (rec->lrh_type != LLOG_LOGID_MAGIC) {
 		CERROR("invalid record in catalog\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	logid_to_fid(&lir->lid_id, &fid);
@@ -448,7 +440,7 @@
 
 	cat_counter++;
 
-	RETURN(0);
+	return 0;
 }
 
 static int plain_counter;
@@ -460,7 +452,7 @@
 
 	if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) {
 		CERROR("log is not plain\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	logid_to_fid(&llh->lgh_id, &fid);
@@ -470,7 +462,7 @@
 
 	plain_counter++;
 
-	RETURN(0);
+	return 0;
 }
 
 static int cancel_count;
@@ -483,7 +475,7 @@
 
 	if (!(llh->lgh_hdr->llh_flags & LLOG_F_IS_PLAIN)) {
 		CERROR("log is not plain\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	cookie.lgc_lgl = llh->lgh_id;
@@ -492,8 +484,8 @@
 	llog_cat_cancel_records(env, llh->u.phd.phd_cat_handle, 1, &cookie);
 	cancel_count++;
 	if (cancel_count == LLOG_TEST_RECNUM)
-		RETURN(-LLOG_EEMPTY);
-	RETURN(0);
+		return -LLOG_EEMPTY;
+	return 0;
 }
 
 /* Test log and catalogue processing */
@@ -505,8 +497,6 @@
 	struct llog_mini_rec	 lmr;
 	struct llog_ctxt	*ctxt;
 
-	ENTRY;
-
 	ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
 	LASSERT(ctxt);
 
@@ -602,7 +592,7 @@
 out_put:
 	llog_ctxt_put(ctxt);
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Test client api; open log by name and process */
@@ -686,7 +676,7 @@
 	llog_ctxt_put(nctxt);
 ctxt_release:
 	llog_ctxt_put(ctxt);
-	RETURN(rc);
+	return rc;
 }
 
 static union {
@@ -728,12 +718,10 @@
 	int			 rc = 0, i, process_count;
 	int			 num_recs = 0;
 
-	ENTRY;
-
 	rc = llog_open_create(env, ctxt, &llh, NULL, NULL);
 	if (rc) {
 		CERROR("7_sub: create log failed\n");
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = llog_init_handle(env, llh,
@@ -804,7 +792,7 @@
 	if (rc)
 		llog_destroy(env, llh);
 	llog_close(env, llh);
-	RETURN(rc);
+	return rc;
 }
 
 /* Test all llog records writing and processing */
@@ -813,8 +801,6 @@
 	struct llog_ctxt	*ctxt;
 	int			 rc;
 
-	ENTRY;
-
 	ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
 
 	CWARN("7a: test llog_logid_rec\n");
@@ -895,7 +881,7 @@
 	}
 out:
 	llog_ctxt_put(ctxt);
-	RETURN(rc);
+	return rc;
 }
 
 /* -------------------------------------------------------------------------
@@ -908,7 +894,6 @@
 	int			 rc, err;
 	char			 name[10];
 
-	ENTRY;
 	ctxt = llog_get_context(obd, LLOG_TEST_ORIG_CTXT);
 	LASSERT(ctxt);
 
@@ -970,18 +955,16 @@
 	struct lu_env		 env;
 	int			 rc;
 
-	ENTRY;
-
 	rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	tgt = obd->obd_lvfs_ctxt.dt->dd_lu_dev.ld_obd;
 	rc = llog_cleanup(&env, llog_get_context(tgt, LLOG_TEST_ORIG_CTXT));
 	if (rc)
 		CERROR("failed to llog_test_llog_finish: %d\n", rc);
 	lu_env_fini(&env);
-	RETURN(rc);
+	return rc;
 }
 
 static int llog_test_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -993,16 +976,14 @@
 	struct lu_context	 test_session;
 	int			 rc;
 
-	ENTRY;
-
 	if (lcfg->lcfg_bufcount < 2) {
 		CERROR("requires a TARGET OBD name\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (lcfg->lcfg_buflens[1] < 1) {
 		CERROR("requires a TARGET OBD name\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* disk obd */
@@ -1010,12 +991,12 @@
 	if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
 		CERROR("target device not attached or not set up (%s)\n",
 		       lustre_cfg_string(lcfg, 1));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = lu_env_init(&env, LCT_LOCAL | LCT_MG_THREAD);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = lu_context_init(&test_session, LCT_SESSION);
 	if (rc)
@@ -1056,7 +1037,7 @@
 	lu_context_fini(&test_session);
 cleanup_env:
 	lu_env_fini(&env);
-	RETURN(rc);
+	return rc;
 }
 
 static struct obd_ops llog_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/obdclass/local_storage.c b/drivers/staging/lustre/lustre/obdclass/local_storage.c
index 3be35a8..cc19fba 100644
--- a/drivers/staging/lustre/lustre/obdclass/local_storage.c
+++ b/drivers/staging/lustre/lustre/obdclass/local_storage.c
@@ -45,17 +45,15 @@
 	struct lu_object	*below;
 	struct lu_device	*under;
 
-	ENTRY;
-
 	ls = container_of0(o->lo_dev, struct ls_device, ls_top_dev.dd_lu_dev);
 	under = &ls->ls_osd->dd_lu_dev;
 	below = under->ld_ops->ldo_object_alloc(env, o->lo_header, under);
 	if (below == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	lu_object_add(o, below);
 
-	RETURN(0);
+	return 0;
 }
 
 static void ls_object_free(const struct lu_env *env, struct lu_object *o)
@@ -143,8 +141,6 @@
 {
 	struct ls_device *ls;
 
-	ENTRY;
-
 	mutex_lock(&ls_list_mutex);
 	ls = __ls_find_dev(dev);
 	if (ls)
@@ -170,7 +166,7 @@
 	list_add(&ls->ls_linkage, &ls_list_head);
 out_ls:
 	mutex_unlock(&ls_list_mutex);
-	RETURN(ls);
+	return ls;
 }
 
 void ls_device_put(const struct lu_env *env, struct ls_device *ls)
@@ -224,26 +220,24 @@
 	struct dt_thread_info	*dti = dt_info(env);
 	int			 rc;
 
-	ENTRY;
-
 	/* update fid generation file */
 	if (los != NULL) {
 		LASSERT(dt_object_exists(los->los_obj));
 		rc = dt_declare_record_write(env, los->los_obj,
 					     sizeof(struct los_ondisk), 0, th);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
 	rc = dt_declare_create(env, o, attr, NULL, dof, th);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	dti->dti_lb.lb_buf = NULL;
 	dti->dti_lb.lb_len = sizeof(dti->dti_lma);
 	rc = dt_declare_xattr_set(env, o, &dti->dti_lb, XATTR_NAME_LMA, 0, th);
 
-	RETURN(rc);
+	return rc;
 }
 
 int local_object_create(const struct lu_env *env,
@@ -255,14 +249,12 @@
 	obd_id			 lastid;
 	int			 rc;
 
-	ENTRY;
-
 	rc = dt_create(env, o, attr, NULL, dof, th);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (los == NULL)
-		RETURN(rc);
+		return rc;
 
 	LASSERT(los->los_obj);
 	LASSERT(dt_object_exists(los->los_obj));
@@ -283,7 +275,7 @@
 			     th);
 	mutex_unlock(&los->los_id_lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -304,7 +296,7 @@
 
 	dto = ls_locate(env, ls, fid);
 	if (unlikely(IS_ERR(dto)))
-		RETURN(dto);
+		return dto;
 
 	LASSERT(dto != NULL);
 	if (dt_object_exists(dto))
@@ -377,7 +369,7 @@
 		lu_object_put_nocache(env, &dto->do_lu);
 		dto = ERR_PTR(rc);
 	}
-	RETURN(dto);
+	return dto;
 }
 
 /*
@@ -443,7 +435,7 @@
 
 		ls = ls_device_get(dt);
 		if (IS_ERR(ls)) {
-			dto = ERR_PTR(PTR_ERR(ls));
+			dto = ERR_CAST(ls);
 		} else {
 			/* create the object */
 			dti->dti_attr.la_valid	= LA_MODE;
@@ -537,7 +529,7 @@
 
 		ls = ls_device_get(dt);
 		if (IS_ERR(ls)) {
-			dto = ERR_PTR(PTR_ERR(ls));
+			dto = ERR_CAST(ls);
 		} else {
 			/* create the object */
 			dti->dti_attr.la_valid		= LA_MODE;
@@ -588,17 +580,15 @@
 	struct thandle		*th;
 	int			 rc;
 
-	ENTRY;
-
 	rc = dt_lookup_dir(env, parent, name, &dti->dti_fid);
 	if (rc == -ENOENT)
-		RETURN(0);
+		return 0;
 	else if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	dto = dt_locate(env, dt, &dti->dti_fid);
 	if (unlikely(IS_ERR(dto)))
-		RETURN(PTR_ERR(dto));
+		return PTR_ERR(dto);
 
 	th = dt_trans_create(env, dt);
 	if (IS_ERR(th))
@@ -761,11 +751,9 @@
 	__u32			 first_oid = fid_oid(first_fid);
 	int			 rc = 0;
 
-	ENTRY;
-
 	ls = ls_device_get(dev);
 	if (IS_ERR(ls))
-		RETURN(PTR_ERR(ls));
+		return PTR_ERR(ls);
 
 	mutex_lock(&ls->ls_los_mutex);
 	*los = dt_los_find(ls, fid_seq(first_fid));
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c
deleted file mode 100644
index e2d57fe..0000000
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_jobstats.c
+++ /dev/null
@@ -1,562 +0,0 @@
-/* GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * 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 version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2011, 2012, Intel Corporation.
- * Use is subject to license terms.
- *
- * Author: Niu Yawei <niu@whamcloud.com>
- */
-/*
- * lustre/obdclass/lprocfs_jobstats.c
- */
-
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-#define DEBUG_SUBSYSTEM S_CLASS
-
-
-#include <obd_class.h>
-#include <lprocfs_status.h>
-#include <lustre/lustre_idl.h>
-
-#if defined(LPROCFS)
-
-/*
- * JobID formats & JobID environment variable names for supported
- * job schedulers:
- *
- * SLURM:
- *   JobID format:  32 bit integer.
- *   JobID env var: SLURM_JOB_ID.
- * SGE:
- *   JobID format:  Decimal integer range to 99999.
- *   JobID env var: JOB_ID.
- * LSF:
- *   JobID format:  6 digit integer by default (up to 999999), can be
- *		  increased to 10 digit (up to 2147483646).
- *   JobID env var: LSB_JOBID.
- * Loadleveler:
- *   JobID format:  String of machine_name.cluster_id.process_id, for
- *		  example: fr2n02.32.0
- *   JobID env var: LOADL_STEP_ID.
- * PBS:
- *   JobID format:  String of sequence_number[.server_name][@server].
- *   JobID env var: PBS_JOBID.
- * Maui/MOAB:
- *   JobID format:  Same as PBS.
- *   JobID env var: Same as PBS.
- */
-
-struct job_stat {
-	struct hlist_node      js_hash;
-	struct list_head	    js_list;
-	atomic_t	  js_refcount;
-	char		  js_jobid[JOBSTATS_JOBID_SIZE];
-	time_t		js_timestamp; /* seconds */
-	struct lprocfs_stats *js_stats;
-	struct obd_job_stats *js_jobstats;
-};
-
-static unsigned job_stat_hash(cfs_hash_t *hs, const void *key, unsigned mask)
-{
-	return cfs_hash_djb2_hash(key, strlen(key), mask);
-}
-
-static void *job_stat_key(struct hlist_node *hnode)
-{
-	struct job_stat *job;
-	job = hlist_entry(hnode, struct job_stat, js_hash);
-	return job->js_jobid;
-}
-
-static int job_stat_keycmp(const void *key, struct hlist_node *hnode)
-{
-	struct job_stat *job;
-	job = hlist_entry(hnode, struct job_stat, js_hash);
-	return (strlen(job->js_jobid) == strlen(key)) &&
-	       !strncmp(job->js_jobid, key, strlen(key));
-}
-
-static void *job_stat_object(struct hlist_node *hnode)
-{
-	return hlist_entry(hnode, struct job_stat, js_hash);
-}
-
-static void job_stat_get(cfs_hash_t *hs, struct hlist_node *hnode)
-{
-	struct job_stat *job;
-	job = hlist_entry(hnode, struct job_stat, js_hash);
-	atomic_inc(&job->js_refcount);
-}
-
-static void job_free(struct job_stat *job)
-{
-	LASSERT(atomic_read(&job->js_refcount) == 0);
-	LASSERT(job->js_jobstats);
-
-	write_lock(&job->js_jobstats->ojs_lock);
-	list_del_init(&job->js_list);
-	write_unlock(&job->js_jobstats->ojs_lock);
-
-	lprocfs_free_stats(&job->js_stats);
-	OBD_FREE_PTR(job);
-}
-
-static void job_putref(struct job_stat *job)
-{
-	LASSERT(atomic_read(&job->js_refcount) > 0);
-	if (atomic_dec_and_test(&job->js_refcount))
-		job_free(job);
-}
-
-static void job_stat_put_locked(cfs_hash_t *hs, struct hlist_node *hnode)
-{
-	struct job_stat *job;
-	job = hlist_entry(hnode, struct job_stat, js_hash);
-	job_putref(job);
-}
-
-static void job_stat_exit(cfs_hash_t *hs, struct hlist_node *hnode)
-{
-	CERROR("Should not have any items!");
-}
-
-static cfs_hash_ops_t job_stats_hash_ops = {
-	.hs_hash       = job_stat_hash,
-	.hs_key	= job_stat_key,
-	.hs_keycmp     = job_stat_keycmp,
-	.hs_object     = job_stat_object,
-	.hs_get	= job_stat_get,
-	.hs_put_locked = job_stat_put_locked,
-	.hs_exit       = job_stat_exit,
-};
-
-static int job_iter_callback(cfs_hash_t *hs, cfs_hash_bd_t *bd,
-			     struct hlist_node *hnode, void *data)
-{
-	time_t oldest = *((time_t *)data);
-	struct job_stat *job;
-
-	job = hlist_entry(hnode, struct job_stat, js_hash);
-	if (!oldest || job->js_timestamp < oldest)
-		cfs_hash_bd_del_locked(hs, bd, hnode);
-
-	return 0;
-}
-
-static void lprocfs_job_cleanup(struct obd_job_stats *stats, bool force)
-{
-	time_t oldest, now;
-
-	if (stats->ojs_cleanup_interval == 0)
-		return;
-
-	now = cfs_time_current_sec();
-	if (!force && now < stats->ojs_last_cleanup +
-			    stats->ojs_cleanup_interval)
-		return;
-
-	oldest = now - stats->ojs_cleanup_interval;
-	cfs_hash_for_each_safe(stats->ojs_hash, job_iter_callback,
-			       &oldest);
-	stats->ojs_last_cleanup = cfs_time_current_sec();
-}
-
-static struct job_stat *job_alloc(char *jobid, struct obd_job_stats *jobs)
-{
-	struct job_stat *job;
-
-	LASSERT(jobs->ojs_cntr_num && jobs->ojs_cntr_init_fn);
-
-	OBD_ALLOC_PTR(job);
-	if (job == NULL)
-		return NULL;
-
-	job->js_stats = lprocfs_alloc_stats(jobs->ojs_cntr_num, 0);
-	if (job->js_stats == NULL) {
-		OBD_FREE_PTR(job);
-		return NULL;
-	}
-
-	jobs->ojs_cntr_init_fn(job->js_stats);
-
-	memcpy(job->js_jobid, jobid, JOBSTATS_JOBID_SIZE);
-	job->js_timestamp = cfs_time_current_sec();
-	job->js_jobstats = jobs;
-	INIT_HLIST_NODE(&job->js_hash);
-	INIT_LIST_HEAD(&job->js_list);
-	atomic_set(&job->js_refcount, 1);
-
-	return job;
-}
-
-int lprocfs_job_stats_log(struct obd_device *obd, char *jobid,
-			  int event, long amount)
-{
-	struct obd_job_stats *stats = &obd->u.obt.obt_jobstats;
-	struct job_stat *job, *job2;
-	ENTRY;
-
-	LASSERT(stats && stats->ojs_hash);
-
-	lprocfs_job_cleanup(stats, false);
-
-	if (!jobid || !strlen(jobid))
-		RETURN(-EINVAL);
-
-	if (strlen(jobid) >= JOBSTATS_JOBID_SIZE) {
-		CERROR("Invalid jobid size (%lu), expect(%d)\n",
-		       (unsigned long)strlen(jobid) + 1, JOBSTATS_JOBID_SIZE);
-		RETURN(-EINVAL);
-	}
-
-	job = cfs_hash_lookup(stats->ojs_hash, jobid);
-	if (job)
-		goto found;
-
-	job = job_alloc(jobid, stats);
-	if (job == NULL)
-		RETURN(-ENOMEM);
-
-	job2 = cfs_hash_findadd_unique(stats->ojs_hash, job->js_jobid,
-				       &job->js_hash);
-	if (job2 != job) {
-		job_putref(job);
-		job = job2;
-		/* We cannot LASSERT(!list_empty(&job->js_list)) here,
-		 * since we just lost the race for inserting "job" into the
-		 * ojs_list, and some other thread is doing it _right_now_.
-		 * Instead, be content the other thread is doing this, since
-		 * "job2" was initialized in job_alloc() already. LU-2163 */
-	} else {
-		LASSERT(list_empty(&job->js_list));
-		write_lock(&stats->ojs_lock);
-		list_add_tail(&job->js_list, &stats->ojs_list);
-		write_unlock(&stats->ojs_lock);
-	}
-
-found:
-	LASSERT(stats == job->js_jobstats);
-	LASSERT(stats->ojs_cntr_num > event);
-	job->js_timestamp = cfs_time_current_sec();
-	lprocfs_counter_add(job->js_stats, event, amount);
-
-	job_putref(job);
-	RETURN(0);
-}
-EXPORT_SYMBOL(lprocfs_job_stats_log);
-
-void lprocfs_job_stats_fini(struct obd_device *obd)
-{
-	struct obd_job_stats *stats = &obd->u.obt.obt_jobstats;
-	time_t oldest = 0;
-
-	if (stats->ojs_hash == NULL)
-		return;
-	cfs_hash_for_each_safe(stats->ojs_hash, job_iter_callback, &oldest);
-	cfs_hash_putref(stats->ojs_hash);
-	stats->ojs_hash = NULL;
-	LASSERT(list_empty(&stats->ojs_list));
-}
-EXPORT_SYMBOL(lprocfs_job_stats_fini);
-
-static void *lprocfs_jobstats_seq_start(struct seq_file *p, loff_t *pos)
-{
-	struct obd_job_stats *stats = p->private;
-	loff_t off = *pos;
-	struct job_stat *job;
-
-	read_lock(&stats->ojs_lock);
-	if (off == 0)
-		return SEQ_START_TOKEN;
-	off--;
-	list_for_each_entry(job, &stats->ojs_list, js_list) {
-		if (!off--)
-			return job;
-	}
-	return NULL;
-}
-
-static void lprocfs_jobstats_seq_stop(struct seq_file *p, void *v)
-{
-	struct obd_job_stats *stats = p->private;
-
-	read_unlock(&stats->ojs_lock);
-}
-
-static void *lprocfs_jobstats_seq_next(struct seq_file *p, void *v, loff_t *pos)
-{
-	struct obd_job_stats *stats = p->private;
-	struct job_stat *job;
-	struct list_head *next;
-
-	++*pos;
-	if (v == SEQ_START_TOKEN) {
-		next = stats->ojs_list.next;
-	} else {
-		job = (struct job_stat *)v;
-		next = job->js_list.next;
-	}
-
-	return next == &stats->ojs_list ? NULL :
-		list_entry(next, struct job_stat, js_list);
-}
-
-/*
- * Example of output on MDT:
- *
- * job_stats:
- * - job_id:	test_id.222.25844
- *   snapshot_time: 1322494486
- *   open:	  { samples:	       3, unit: reqs }
- *   close:	 { samples:	       3, unit: reqs }
- *   mknod:	 { samples:	       0, unit: reqs }
- *   link:	  { samples:	       0, unit: reqs }
- *   unlink:	{ samples:	       0, unit: reqs }
- *   mkdir:	 { samples:	       0, unit: reqs }
- *   rmdir:	 { samples:	       0, unit: reqs }
- *   rename:	{ samples:	       1, unit: reqs }
- *   getattr:       { samples:	       7, unit: reqs }
- *   setattr:       { samples:	       0, unit: reqs }
- *   getxattr:      { samples:	       0, unit: reqs }
- *   setxattr:      { samples:	       0, unit: reqs }
- *   statfs:	{ samples:	       0, unit: reqs }
- *   sync:	  { samples:	       0, unit: reqs }
- *
- * Example of output on OST:
- *
- * job_stats:
- * - job_id	 4854
- *   snapshot_time: 1322494602
- *   read:	  { samples:  0, unit: bytes, min:  0, max:  0, sum:  0 }
- *   write:	 { samples:  1, unit: bytes, min: 10, max: 10, sum: 10 }
- *   setattr:       { samples:  0, unit: reqs }
- *   punch:	 { samples:  0, unit: reqs }
- *   sync:	  { samples:  0, unit: reqs }
- */
-
-static const char spaces[] = "		    ";
-
-static int inline width(const char *str, int len)
-{
-	return len - min((int)strlen(str), 15);
-}
-
-static int lprocfs_jobstats_seq_show(struct seq_file *p, void *v)
-{
-	struct job_stat			*job = v;
-	struct lprocfs_stats		*s;
-	struct lprocfs_counter		ret;
-	struct lprocfs_counter		*cntr;
-	struct lprocfs_counter_header	*cntr_header;
-	int				i;
-
-	if (v == SEQ_START_TOKEN) {
-		seq_printf(p, "job_stats:\n");
-		return 0;
-	}
-
-	seq_printf(p, "- %-16s %s\n", "job_id:", job->js_jobid);
-	seq_printf(p, "  %-16s %ld\n", "snapshot_time:", job->js_timestamp);
-
-	s = job->js_stats;
-	for (i = 0; i < s->ls_num; i++) {
-		cntr = lprocfs_stats_counter_get(s, 0, i);
-		cntr_header = &s->ls_cnt_header[i];
-		lprocfs_stats_collect(s, i, &ret);
-
-		seq_printf(p, "  %s:%.*s { samples: %11"LPF64"u",
-			   cntr_header->lc_name,
-			   width(cntr_header->lc_name, 15), spaces,
-			   ret.lc_count);
-		if (cntr_header->lc_units[0] != '\0')
-			seq_printf(p, ", unit: %5s", cntr_header->lc_units);
-
-		if (cntr_header->lc_config & LPROCFS_CNTR_AVGMINMAX) {
-			seq_printf(p, ", min:%8"LPF64"u, max:%8"LPF64"u,"
-				   " sum:%16"LPF64"u",
-				   ret.lc_count ? ret.lc_min : 0,
-				   ret.lc_count ? ret.lc_max : 0,
-				   ret.lc_count ? ret.lc_sum : 0);
-		}
-		if (cntr_header->lc_config & LPROCFS_CNTR_STDDEV) {
-			seq_printf(p, ", sumsq: %18"LPF64"u",
-				   ret.lc_count ? ret.lc_sumsquare : 0);
-		}
-
-		seq_printf(p, " }\n");
-
-	}
-	return 0;
-}
-
-struct seq_operations lprocfs_jobstats_seq_sops = {
-	start: lprocfs_jobstats_seq_start,
-	stop:  lprocfs_jobstats_seq_stop,
-	next:  lprocfs_jobstats_seq_next,
-	show:  lprocfs_jobstats_seq_show,
-};
-
-static int lprocfs_jobstats_seq_open(struct inode *inode, struct file *file)
-{
-	struct seq_file *seq;
-	int rc;
-
-	rc = seq_open(file, &lprocfs_jobstats_seq_sops);
-	if (rc)
-		return rc;
-	seq = file->private_data;
-	seq->private = PDE_DATA(inode);
-	return 0;
-}
-
-static ssize_t lprocfs_jobstats_seq_write(struct file *file, const char *buf,
-					  size_t len, loff_t *off)
-{
-	struct seq_file *seq = file->private_data;
-	struct obd_job_stats *stats = seq->private;
-	char jobid[JOBSTATS_JOBID_SIZE];
-	int all = 0;
-	struct job_stat *job;
-
-	if (!memcmp(buf, "clear", strlen("clear"))) {
-		all = 1;
-	} else if (len < JOBSTATS_JOBID_SIZE) {
-		memset(jobid, 0, JOBSTATS_JOBID_SIZE);
-		/* Trim '\n' if any */
-		if (buf[len - 1] == '\n')
-			memcpy(jobid, buf, len - 1);
-		else
-			memcpy(jobid, buf, len);
-	} else {
-		return -EINVAL;
-	}
-
-	LASSERT(stats->ojs_hash);
-	if (all) {
-		time_t oldest = 0;
-		cfs_hash_for_each_safe(stats->ojs_hash, job_iter_callback,
-				       &oldest);
-		return len;
-	}
-
-	if (!strlen(jobid))
-		return -EINVAL;
-
-	job = cfs_hash_lookup(stats->ojs_hash, jobid);
-	if (!job)
-		return -EINVAL;
-
-	cfs_hash_del_key(stats->ojs_hash, jobid);
-
-	job_putref(job);
-	return len;
-}
-
-struct file_operations lprocfs_jobstats_seq_fops = {
-	.owner   = THIS_MODULE,
-	.open    = lprocfs_jobstats_seq_open,
-	.read    = seq_read,
-	.write   = lprocfs_jobstats_seq_write,
-	.llseek  = seq_lseek,
-	.release = lprocfs_seq_release,
-};
-
-int lprocfs_job_stats_init(struct obd_device *obd, int cntr_num,
-			   cntr_init_callback init_fn)
-{
-	struct proc_dir_entry *entry;
-	struct obd_job_stats *stats;
-	ENTRY;
-
-	LASSERT(obd->obd_proc_entry != NULL);
-	LASSERT(obd->obd_type->typ_name);
-
-	if (strcmp(obd->obd_type->typ_name, LUSTRE_MDT_NAME) &&
-	    strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME)) {
-		CERROR("Invalid obd device type.\n");
-		RETURN(-EINVAL);
-	}
-	stats = &obd->u.obt.obt_jobstats;
-
-	LASSERT(stats->ojs_hash == NULL);
-	stats->ojs_hash = cfs_hash_create("JOB_STATS",
-					  HASH_JOB_STATS_CUR_BITS,
-					  HASH_JOB_STATS_MAX_BITS,
-					  HASH_JOB_STATS_BKT_BITS, 0,
-					  CFS_HASH_MIN_THETA,
-					  CFS_HASH_MAX_THETA,
-					  &job_stats_hash_ops,
-					  CFS_HASH_DEFAULT);
-	if (stats->ojs_hash == NULL)
-		RETURN(-ENOMEM);
-
-	INIT_LIST_HEAD(&stats->ojs_list);
-	rwlock_init(&stats->ojs_lock);
-	stats->ojs_cntr_num = cntr_num;
-	stats->ojs_cntr_init_fn = init_fn;
-	stats->ojs_cleanup_interval = 600; /* 10 mins by default */
-	stats->ojs_last_cleanup = cfs_time_current_sec();
-
-	entry = proc_create_data("job_stats", 0644, obd->obd_proc_entry,
-				 &lprocfs_jobstats_seq_fops, stats);
-	if (entry)
-		RETURN(0);
-	else
-		RETURN(-ENOMEM);
-}
-EXPORT_SYMBOL(lprocfs_job_stats_init);
-
-int lprocfs_rd_job_interval(struct seq_file *m, void *data)
-{
-	struct obd_device *obd = (struct obd_device *)data;
-	struct obd_job_stats *stats;
-
-	LASSERT(obd != NULL);
-	stats = &obd->u.obt.obt_jobstats;
-	return seq_printf(m, "%d\n", stats->ojs_cleanup_interval);
-}
-EXPORT_SYMBOL(lprocfs_rd_job_interval);
-
-int lprocfs_wr_job_interval(struct file *file, const char *buffer,
-			    unsigned long count, void *data)
-{
-	struct obd_device *obd = (struct obd_device *)data;
-	struct obd_job_stats *stats;
-	int val, rc;
-
-	LASSERT(obd != NULL);
-	stats = &obd->u.obt.obt_jobstats;
-
-	rc = lprocfs_write_helper(buffer, count, &val);
-	if (rc)
-		return rc;
-
-	stats->ojs_cleanup_interval = val;
-	lprocfs_job_cleanup(stats, true);
-
-	return count;
-
-}
-EXPORT_SYMBOL(lprocfs_wr_job_interval);
-
-#endif /* LPROCFS*/
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index f7af3d6..a95f60a 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -68,11 +68,11 @@
 
 /* lprocfs API calls */
 
-proc_dir_entry_t *lprocfs_add_simple(struct proc_dir_entry *root,
+struct proc_dir_entry *lprocfs_add_simple(struct proc_dir_entry *root,
 				     char *name, void *data,
 				     struct file_operations *fops)
 {
-	proc_dir_entry_t *proc;
+	struct proc_dir_entry *proc;
 	umode_t mode = 0;
 
 	if (root == NULL || name == NULL || fops == NULL)
@@ -179,17 +179,21 @@
 					struct proc_dir_entry *parent,
 					struct lprocfs_vars *list, void *data)
 {
-	struct proc_dir_entry *newchild;
+	struct proc_dir_entry *entry;
 
-	newchild = proc_mkdir(name, parent);
-	if (newchild != NULL && list != NULL) {
-		int rc = lprocfs_add_vars(newchild, list, data);
-		if (rc) {
-			lprocfs_remove(&newchild);
-			return ERR_PTR(rc);
+	entry = proc_mkdir(name, parent);
+	if (entry == NULL)
+		GOTO(out, entry = ERR_PTR(-ENOMEM));
+
+	if (list != NULL) {
+		int rc = lprocfs_add_vars(entry, list, data);
+		if (rc != 0) {
+			lprocfs_remove(&entry);
+			entry = ERR_PTR(rc);
 		}
 	}
-	return newchild;
+out:
+	return entry;
 }
 EXPORT_SYMBOL(lprocfs_register);
 
@@ -896,7 +900,6 @@
 {
 	cfs_hash_t *hash = obd->obd_nid_stats_hash;
 	struct nid_stat *stat;
-	ENTRY;
 
 	/* we need extra list - because hash_exit called to early */
 	/* not need locking because all clients is died */
@@ -907,7 +910,6 @@
 		cfs_hash_del(hash, &stat->nid, &stat->nid_hash);
 		lprocfs_free_client_stats(stat);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(lprocfs_free_per_client_stats);
 
@@ -1494,7 +1496,6 @@
 static int lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
 {
 	struct nid_stat *stat = obj;
-	ENTRY;
 
 	CDEBUG(D_INFO,"refcnt %d\n", atomic_read(&stat->nid_exp_ref_count));
 	if (atomic_read(&stat->nid_exp_ref_count) == 1) {
@@ -1502,13 +1503,13 @@
 		spin_lock(&stat->nid_obd->obd_nid_lock);
 		list_move(&stat->nid_list, data);
 		spin_unlock(&stat->nid_obd->obd_nid_lock);
-		RETURN(1);
+		return 1;
 	}
 	/* we has reference to object - only clear data*/
 	if (stat->nid_stats)
 		lprocfs_clear_stats(stat->nid_stats);
 
-	RETURN(0);
+	return 0;
 }
 
 int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
@@ -1536,22 +1537,21 @@
 {
 	struct nid_stat *new_stat, *old_stat;
 	struct obd_device *obd = NULL;
-	proc_dir_entry_t *entry;
+	struct proc_dir_entry *entry;
 	char *buffer = NULL;
 	int rc = 0;
-	ENTRY;
 
 	*newnid = 0;
 
 	if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
 	    !exp->exp_obd->obd_nid_stats_hash)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* not test against zero because eric say:
 	 * You may only test nid against another nid, or LNET_NID_ANY.
 	 * Anything else is nonsense.*/
 	if (!nid || *nid == LNET_NID_ANY)
-		RETURN(0);
+		return 0;
 
 	obd = exp->exp_obd;
 
@@ -1559,7 +1559,7 @@
 
 	OBD_ALLOC_PTR(new_stat);
 	if (new_stat == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	new_stat->nid	       = *nid;
 	new_stat->nid_obd	   = exp->exp_obd;
@@ -1596,10 +1596,12 @@
 					      NULL, NULL);
 	OBD_FREE(buffer, LNET_NIDSTR_SIZE);
 
-	if (new_stat->nid_proc == NULL) {
+	if (IS_ERR(new_stat->nid_proc)) {
 		CERROR("Error making export directory for nid %s\n",
 		       libcfs_nid2str(*nid));
-		GOTO(destroy_new_ns, rc = -ENOMEM);
+		rc = PTR_ERR(new_stat->nid_proc);
+		new_stat->nid_proc = NULL;
+		GOTO(destroy_new_ns, rc);
 	}
 
 	entry = lprocfs_add_simple(new_stat->nid_proc, "uuid",
@@ -1625,7 +1627,7 @@
 	list_add(&new_stat->nid_list, &obd->obd_nid_stats);
 	spin_unlock(&obd->obd_nid_lock);
 
-	RETURN(rc);
+	return rc;
 
 destroy_new_ns:
 	if (new_stat->nid_proc != NULL)
@@ -1635,7 +1637,7 @@
 destroy_new:
 	nidstat_putref(new_stat);
 	OBD_FREE_PTR(new_stat);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(lprocfs_exp_setup);
 
@@ -1644,7 +1646,7 @@
 	struct nid_stat *stat = exp->exp_nid_stats;
 
 	if(!stat || !exp->exp_obd)
-		RETURN(0);
+		return 0;
 
 	nidstat_putref(exp->exp_nid_stats);
 	exp->exp_nid_stats = NULL;
@@ -1873,7 +1875,7 @@
  * If \a name is not found the original \a buffer is returned.
  */
 char *lprocfs_find_named_value(const char *buffer, const char *name,
-				unsigned long *count)
+			       size_t *count)
 {
 	char *val;
 	size_t buflen = *count;
@@ -1897,23 +1899,22 @@
 }
 EXPORT_SYMBOL(lprocfs_find_named_value);
 
-int lprocfs_seq_create(proc_dir_entry_t *parent,
+int lprocfs_seq_create(struct proc_dir_entry *parent,
 		       const char *name,
 		       umode_t mode,
 		       const struct file_operations *seq_fops,
 		       void *data)
 {
 	struct proc_dir_entry *entry;
-	ENTRY;
 
 	/* Disallow secretly (un)writable entries. */
 	LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0));
 	entry = proc_create_data(name, mode, parent, seq_fops, data);
 
 	if (entry == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(lprocfs_seq_create);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c
index fdf0ed3..c29ac1c 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c
@@ -202,7 +202,6 @@
 	struct list_head *layers;
 	int clean;
 	int result;
-	ENTRY;
 
 	/*
 	 * Create top-level object slice. This will also create
@@ -210,9 +209,9 @@
 	 */
 	top = dev->ld_ops->ldo_object_alloc(env, NULL, dev);
 	if (top == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 	if (IS_ERR(top))
-		RETURN(top);
+		return top;
 	/*
 	 * This is the only place where object fid is assigned. It's constant
 	 * after this point.
@@ -233,7 +232,7 @@
 			result = scan->lo_ops->loo_object_init(env, scan, conf);
 			if (result != 0) {
 				lu_object_free(env, top);
-				RETURN(ERR_PTR(result));
+				return ERR_PTR(result);
 			}
 			scan->lo_flags |= LU_OBJECT_ALLOCATED;
 		}
@@ -244,13 +243,13 @@
 			result = scan->lo_ops->loo_object_start(env, scan);
 			if (result != 0) {
 				lu_object_free(env, top);
-				RETURN(ERR_PTR(result));
+				return ERR_PTR(result);
 			}
 		}
 	}
 
 	lprocfs_counter_incr(dev->ld_site->ls_stats, LU_SS_CREATED);
-	RETURN(top);
+	return top;
 }
 
 /**
@@ -317,7 +316,7 @@
 	int		      i;
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_OBD_NO_LRU))
-		RETURN(0);
+		return 0;
 
 	INIT_LIST_HEAD(&dispose);
 	/*
@@ -538,7 +537,7 @@
 	__u64  ver = cfs_hash_bd_version_get(bd);
 
 	if (*version == ver)
-		return NULL;
+		return ERR_PTR(-ENOENT);
 
 	*version = ver;
 	bkt = cfs_hash_bd_extra_get(s->ls_obj_hash, bd);
@@ -547,7 +546,7 @@
 	hnode = cfs_hash_bd_peek_locked(s->ls_obj_hash, bd, (void *)f);
 	if (hnode == NULL) {
 		lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_MISS);
-		return NULL;
+		return ERR_PTR(-ENOENT);
 	}
 
 	h = container_of0(hnode, struct lu_object_header, loh_hash);
@@ -651,7 +650,7 @@
 	cfs_hash_bd_get_and_lock(hs, (void *)f, &bd, 1);
 	o = htable_lookup(s, &bd, f, waiter, &version);
 	cfs_hash_bd_unlock(hs, &bd, 1);
-	if (o != NULL)
+	if (!IS_ERR(o) || PTR_ERR(o) != -ENOENT)
 		return o;
 
 	/*
@@ -667,7 +666,7 @@
 	cfs_hash_bd_lock(hs, &bd, 1);
 
 	shadow = htable_lookup(s, &bd, f, waiter, &version);
-	if (likely(shadow == NULL)) {
+	if (likely(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT)) {
 		struct lu_site_bkt_data *bkt;
 
 		bkt = cfs_hash_bd_extra_get(hs, &bd);
@@ -849,7 +848,7 @@
 	 *
 	 * Size of lu_object is (arbitrary) taken as 1K (together with inode).
 	 */
-	cache_size = num_physpages;
+	cache_size = totalram_pages;
 
 #if BITS_PER_LONG == 32
 	/* limit hashtable size for lowmem systems to low RAM */
@@ -980,7 +979,6 @@
 	char name[16];
 	int bits;
 	int i;
-	ENTRY;
 
 	memset(s, 0, sizeof *s);
 	bits = lu_htable_order();
@@ -1041,7 +1039,7 @@
 
 	lu_dev_add_linkage(s, top);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(lu_site_init);
 
@@ -1147,15 +1145,16 @@
  * Initialize object \a o that is part of compound object \a h and was created
  * by device \a d.
  */
-int lu_object_init(struct lu_object *o,
-		   struct lu_object_header *h, struct lu_device *d)
+int lu_object_init(struct lu_object *o, struct lu_object_header *h,
+		   struct lu_device *d)
 {
-	memset(o, 0, sizeof *o);
+	memset(o, 0, sizeof(*o));
 	o->lo_header = h;
-	o->lo_dev    = d;
+	o->lo_dev = d;
 	lu_device_get(d);
-	o->lo_dev_ref = lu_ref_add(&d->ld_reference, "lu_object", o);
+	lu_ref_add_at(&d->ld_reference, &o->lo_dev_ref, "lu_object", o);
 	INIT_LIST_HEAD(&o->lo_linkage);
+
 	return 0;
 }
 EXPORT_SYMBOL(lu_object_init);
@@ -1170,8 +1169,8 @@
 	LASSERT(list_empty(&o->lo_linkage));
 
 	if (dev != NULL) {
-		lu_ref_del_at(&dev->ld_reference,
-			      o->lo_dev_ref , "lu_object", o);
+		lu_ref_del_at(&dev->ld_reference, &o->lo_dev_ref,
+			      "lu_object", o);
 		lu_device_put(dev);
 		o->lo_dev = NULL;
 	}
@@ -1315,7 +1314,6 @@
 	LASSERT(key->lct_init != NULL);
 	LASSERT(key->lct_fini != NULL);
 	LASSERT(key->lct_tags != 0);
-	LASSERT(key->lct_owner != NULL);
 
 	result = -ENFILE;
 	spin_lock(&lu_keys_guard);
@@ -1349,7 +1347,6 @@
 		lu_ref_del(&key->lct_reference, "ctx", ctx);
 		atomic_dec(&key->lct_used);
 
-		LASSERT(key->lct_owner != NULL);
 		if ((ctx->lc_tags & LCT_NOREF) == 0) {
 #ifdef CONFIG_MODULE_UNLOAD
 			LINVRNT(module_refcount(key->lct_owner) > 0);
@@ -1557,7 +1554,6 @@
 			if (unlikely(IS_ERR(value)))
 				return PTR_ERR(value);
 
-			LASSERT(key->lct_owner != NULL);
 			if (!(ctx->lc_tags & LCT_NOREF))
 				try_module_get(key->lct_owner);
 			lu_ref_add_atomic(&key->lct_reference, "ctx", ctx);
@@ -2079,7 +2075,7 @@
 	cfs_hash_bd_get_and_lock(hs, (void *)fid, &bd, 1);
 	shadow = htable_lookup(s, &bd, fid, &waiter, &version);
 	/* supposed to be unique */
-	LASSERT(shadow == NULL);
+	LASSERT(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT);
 	*old = *fid;
 	bkt = cfs_hash_bd_extra_get(hs, &bd);
 	cfs_hash_bd_add_locked(hs, &bd, &o->lo_header->loh_hash);
diff --git a/drivers/staging/lustre/lustre/obdclass/lu_ucred.c b/drivers/staging/lustre/lustre/obdclass/lu_ucred.c
index 229db6c..e23e545 100644
--- a/drivers/staging/lustre/lustre/obdclass/lu_ucred.c
+++ b/drivers/staging/lustre/lustre/obdclass/lu_ucred.c
@@ -33,13 +33,13 @@
  * This file is part of Lustre, http://www.lustre.org/
  * Lustre is a trademark of Sun Microsystems, Inc.
  *
- * lustre/obdclass/lu_object.c
+ * lustre/obdclass/lu_ucred.c
  *
- * Lustre Object.
- * These are the only exported functions, they provide some generic
- * infrastructure for managing object devices
+ * Lustre user credentials context infrastructure.
  *
  *   Author: Nikita Danilov <nikita.danilov@sun.com>
+ *   Author: Fan Yong <fan.yong@intel.com>
+ *   Author: Vitaly Fertman <vitaly_fertman@xyratex.com>
  */
 
 #define DEBUG_SUBSYSTEM S_CLASS
diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
index 69d6499..be31d32 100644
--- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
+++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c
@@ -65,7 +65,6 @@
 		       struct portals_handle_ops *ops)
 {
 	struct handle_bucket *bucket;
-	ENTRY;
 
 	LASSERT(h != NULL);
 	LASSERT(list_empty(&h->h_link));
@@ -100,7 +99,6 @@
 
 	CDEBUG(D_INFO, "added object %p with handle "LPX64" to hash\n",
 	       h, h->h_cookie);
-	EXIT;
 }
 EXPORT_SYMBOL(class_handle_hash);
 
@@ -139,7 +137,6 @@
 void class_handle_hash_back(struct portals_handle *h)
 {
 	struct handle_bucket *bucket;
-	ENTRY;
 
 	bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK);
 
@@ -147,8 +144,6 @@
 	list_add_rcu(&h->h_link, &bucket->head);
 	h->h_in = 1;
 	spin_unlock(&bucket->lock);
-
-	EXIT;
 }
 EXPORT_SYMBOL(class_handle_hash_back);
 
@@ -157,7 +152,6 @@
 	struct handle_bucket *bucket;
 	struct portals_handle *h;
 	void *retval = NULL;
-	ENTRY;
 
 	LASSERT(handle_hash != NULL);
 
@@ -180,7 +174,7 @@
 	}
 	rcu_read_unlock();
 
-	RETURN(retval);
+	return retval;
 }
 EXPORT_SYMBOL(class_handle2object);
 
diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c
index 2fa2589..df4936a 100644
--- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c
+++ b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c
@@ -191,7 +191,6 @@
 {
 	struct uuid_nid_data *entry;
 	int found = 0;
-	ENTRY;
 
 	CDEBUG(D_INFO, "check if uuid %s has %s.\n",
 	       obd_uuid2str(uuid), libcfs_nid2str(nid));
@@ -213,6 +212,6 @@
 		break;
 	}
 	spin_unlock(&g_uuid_lock);
-	RETURN(found);
+	return found;
 }
 EXPORT_SYMBOL(class_check_uuid);
diff --git a/drivers/staging/lustre/lustre/obdclass/md_attrs.c b/drivers/staging/lustre/lustre/obdclass/md_attrs.c
index b71344a..f718782 100644
--- a/drivers/staging/lustre/lustre/obdclass/md_attrs.c
+++ b/drivers/staging/lustre/lustre/obdclass/md_attrs.c
@@ -99,19 +99,18 @@
 int lustre_buf2som(void *buf, int rc, struct md_som_data *msd)
 {
 	struct som_attrs *attrs = (struct som_attrs *)buf;
-	ENTRY;
 
 	if (rc == 0 ||  rc == -ENODATA)
 		/* no SOM attributes */
-		RETURN(-ENODATA);
+		return -ENODATA;
 
 	if (rc < 0)
 		/* error hit while fetching xattr */
-		RETURN(rc);
+		return rc;
 
 	/* check SOM compatibility */
 	if (attrs->som_incompat & ~cpu_to_le32(SOM_INCOMPAT_SUPP))
-		RETURN(-ENODATA);
+		return -ENODATA;
 
 	/* unpack SOM attributes */
 	lustre_som_swab(attrs);
@@ -124,7 +123,7 @@
 	msd->msd_blocks   = attrs->som_blocks;
 	msd->msd_mountid  = attrs->som_mountid;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(lustre_buf2som);
 
@@ -156,15 +155,14 @@
 int lustre_buf2hsm(void *buf, int rc, struct md_hsm *mh)
 {
 	struct hsm_attrs *attrs = (struct hsm_attrs *)buf;
-	ENTRY;
 
 	if (rc == 0 ||  rc == -ENODATA)
 		/* no HSM attributes */
-		RETURN(-ENODATA);
+		return -ENODATA;
 
 	if (rc < 0)
 		/* error hit while fetching xattr */
-		RETURN(rc);
+		return rc;
 
 	/* unpack HSM attributes */
 	lustre_hsm_swab(attrs);
@@ -175,7 +173,7 @@
 	mh->mh_arch_id  = attrs->hsm_arch_id;
 	mh->mh_arch_ver = attrs->hsm_arch_ver;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(lustre_buf2hsm);
 
@@ -188,7 +186,6 @@
 void lustre_hsm2buf(void *buf, struct md_hsm *mh)
 {
 	struct hsm_attrs *attrs = (struct hsm_attrs *)buf;
-	ENTRY;
 
 	/* copy HSM attributes */
 	attrs->hsm_compat   = mh->mh_compat;
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c
index bbf06d0..d0a64ff 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_config.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c
@@ -93,7 +93,7 @@
 	int   name_len = 0;
 
 	if (param == NULL || ptr == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	value = strchr(param, '=');
 	if (value == NULL)
@@ -104,11 +104,11 @@
 	while (ptr->old_param != NULL) {
 		if (strncmp(param, ptr->old_param, name_len) == 0 &&
 		    name_len == strlen(ptr->old_param))
-			RETURN(ptr);
+			return ptr;
 		ptr++;
 	}
 
-	RETURN(NULL);
+	return NULL;
 }
 EXPORT_SYMBOL(class_find_old_param);
 
@@ -335,23 +335,22 @@
 	struct obd_device *obd = NULL;
 	char *typename, *name, *uuid;
 	int rc, len;
-	ENTRY;
 
 	if (!LUSTRE_CFG_BUFLEN(lcfg, 1)) {
 		CERROR("No type passed!\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	typename = lustre_cfg_string(lcfg, 1);
 
 	if (!LUSTRE_CFG_BUFLEN(lcfg, 0)) {
 		CERROR("No name passed!\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	name = lustre_cfg_string(lcfg, 0);
 
 	if (!LUSTRE_CFG_BUFLEN(lcfg, 2)) {
 		CERROR("No UUID passed!\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	uuid = lustre_cfg_string(lcfg, 2);
 
@@ -433,7 +432,7 @@
 	obd->obd_attached = 1;
 	CDEBUG(D_IOCTL, "OBD: dev %d attached type %s with refcount %d\n",
 	       obd->obd_minor, typename, atomic_read(&obd->obd_refcount));
-	RETURN(0);
+	return 0;
  out:
 	if (obd != NULL) {
 		class_release_dev(obd);
@@ -449,7 +448,6 @@
 {
 	int err = 0;
 	struct obd_export *exp;
-	ENTRY;
 
 	LASSERT(obd != NULL);
 	LASSERTF(obd == class_num2obd(obd->obd_minor),
@@ -462,13 +460,13 @@
 	/* have we attached a type to this device? */
 	if (!obd->obd_attached) {
 		CERROR("Device %d not attached\n", obd->obd_minor);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	if (obd->obd_set_up) {
 		CERROR("Device %d already setup (type %s)\n",
 		       obd->obd_minor, obd->obd_type->typ_name);
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 
 	/* is someone else setting us up right now? (attach inits spinlock) */
@@ -477,7 +475,7 @@
 		spin_unlock(&obd->obd_dev_lock);
 		CERROR("Device %d setup in progress (type %s)\n",
 		       obd->obd_minor, obd->obd_type->typ_name);
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 	/* just leave this on forever.  I can't use obd_set_up here because
 	   other fns check that status, and we're not actually set up yet. */
@@ -542,7 +540,7 @@
 	CDEBUG(D_IOCTL, "finished setup of obd %s (uuid %s)\n",
 	       obd->obd_name, obd->obd_uuid.uuid);
 
-	RETURN(0);
+	return 0;
 err_exp:
 	if (obd->obd_self_export) {
 		class_unlink_export(obd->obd_self_export);
@@ -572,18 +570,16 @@
  */
 int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
 {
-	ENTRY;
-
 	if (obd->obd_set_up) {
 		CERROR("OBD device %d still set up\n", obd->obd_minor);
-		RETURN(-EBUSY);
+		return -EBUSY;
 	}
 
 	spin_lock(&obd->obd_dev_lock);
 	if (!obd->obd_attached) {
 		spin_unlock(&obd->obd_dev_lock);
 		CERROR("OBD device %d not attached\n", obd->obd_minor);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 	obd->obd_attached = 0;
 	spin_unlock(&obd->obd_dev_lock);
@@ -592,7 +588,7 @@
 	       obd->obd_name, obd->obd_uuid.uuid);
 
 	class_decref(obd, "attach", obd);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(class_detach);
 
@@ -604,20 +600,19 @@
 {
 	int err = 0;
 	char *flag;
-	ENTRY;
 
 	OBD_RACE(OBD_FAIL_LDLM_RECOV_CLIENTS);
 
 	if (!obd->obd_set_up) {
 		CERROR("Device %d not setup\n", obd->obd_minor);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	spin_lock(&obd->obd_dev_lock);
 	if (obd->obd_stopping) {
 		spin_unlock(&obd->obd_dev_lock);
 		CERROR("OBD %d already stopping\n", obd->obd_minor);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 	/* Leave this on forever */
 	obd->obd_stopping = 1;
@@ -696,7 +691,7 @@
 	class_decref(obd, "setup", obd);
 	obd->obd_set_up = 0;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(class_cleanup);
 
@@ -767,12 +762,11 @@
 	struct obd_import *imp;
 	struct obd_uuid uuid;
 	int rc;
-	ENTRY;
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1 ||
 	    LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(struct obd_uuid)) {
 		CERROR("invalid conn_uuid\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
 	    strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) &&
@@ -780,19 +774,19 @@
 	    strcmp(obd->obd_type->typ_name, LUSTRE_LWP_NAME) &&
 	    strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) {
 		CERROR("can't add connection on non-client dev\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	imp = obd->u.cli.cl_import;
 	if (!imp) {
 		CERROR("try to add conn on immature client dev\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	obd_str2uuid(&uuid, lustre_cfg_string(lcfg, 1));
 	rc = obd_add_conn(imp, &uuid, lcfg->lcfg_num);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_add_conn);
 
@@ -803,29 +797,28 @@
 	struct obd_import *imp;
 	struct obd_uuid uuid;
 	int rc;
-	ENTRY;
 
 	if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1 ||
 	    LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(struct obd_uuid)) {
 		CERROR("invalid conn_uuid\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
 	    strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME)) {
 		CERROR("can't del connection on non-client dev\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	imp = obd->u.cli.cl_import;
 	if (!imp) {
 		CERROR("try to del conn on immature client dev\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	obd_str2uuid(&uuid, lustre_cfg_string(lcfg, 1));
 	rc = obd_del_conn(imp, &uuid);
 
-	RETURN(rc);
+	return rc;
 }
 
 LIST_HEAD(lustre_profile_list);
@@ -834,13 +827,12 @@
 {
 	struct lustre_profile *lprof;
 
-	ENTRY;
 	list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
 		if (!strcmp(lprof->lp_profile, prof)) {
-			RETURN(lprof);
+			return lprof;
 		}
 	}
-	RETURN(NULL);
+	return NULL;
 }
 EXPORT_SYMBOL(class_get_profile);
 
@@ -853,13 +845,12 @@
 {
 	struct lustre_profile *lprof;
 	int err = 0;
-	ENTRY;
 
 	CDEBUG(D_CONFIG, "Add profile %s\n", prof);
 
 	OBD_ALLOC(lprof, sizeof(*lprof));
 	if (lprof == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	INIT_LIST_HEAD(&lprof->lp_list);
 
 	LASSERT(proflen == (strlen(prof) + 1));
@@ -883,7 +874,7 @@
 	}
 
 	list_add(&lprof->lp_list, &lustre_profile_list);
-	RETURN(err);
+	return err;
 
 out:
 	if (lprof->lp_md)
@@ -893,13 +884,12 @@
 	if (lprof->lp_profile)
 		OBD_FREE(lprof->lp_profile, proflen);
 	OBD_FREE(lprof, sizeof(*lprof));
-	RETURN(err);
+	return err;
 }
 
 void class_del_profile(const char *prof)
 {
 	struct lustre_profile *lprof;
-	ENTRY;
 
 	CDEBUG(D_CONFIG, "Del profile %s\n", prof);
 
@@ -912,7 +902,6 @@
 			OBD_FREE(lprof->lp_md, strlen(lprof->lp_md) + 1);
 		OBD_FREE(lprof, sizeof *lprof);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(class_del_profile);
 
@@ -920,7 +909,6 @@
 void class_del_profiles(void)
 {
 	struct lustre_profile *lprof, *n;
-	ENTRY;
 
 	list_for_each_entry_safe(lprof, n, &lustre_profile_list, lp_list) {
 		list_del(&lprof->lp_list);
@@ -930,13 +918,11 @@
 			OBD_FREE(lprof->lp_md, strlen(lprof->lp_md) + 1);
 		OBD_FREE(lprof, sizeof *lprof);
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(class_del_profiles);
 
 static int class_set_global(char *ptr, int val, struct lustre_cfg *lcfg)
 {
-	ENTRY;
 	if (class_match_param(ptr, PARAM_AT_MIN, NULL) == 0)
 		at_min = val;
 	else if (class_match_param(ptr, PARAM_AT_MAX, NULL) == 0)
@@ -951,10 +937,10 @@
 		strlcpy(obd_jobid_var, lustre_cfg_string(lcfg, 2),
 			JOBSTATS_JOBID_VAR_MAX_LEN + 1);
 	else
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	CDEBUG(D_IOCTL, "global %s = %d\n", ptr, val);
-	RETURN(0);
+	return 0;
 }
 
 
@@ -991,14 +977,13 @@
 	char			*value = NULL;
 	int			 name_len = 0;
 	int			 new_len = 0;
-	ENTRY;
 
 	if (cfg == NULL || new_name == NULL)
-		RETURN(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	param = lustre_cfg_string(cfg, 1);
 	if (param == NULL)
-		RETURN(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	value = strchr(param, '=');
 	if (value == NULL)
@@ -1010,7 +995,7 @@
 
 	OBD_ALLOC(new_param, new_len);
 	if (new_param == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	strcpy(new_param, new_name);
 	if (value != NULL)
@@ -1019,7 +1004,7 @@
 	OBD_ALLOC_PTR(bufs);
 	if (bufs == NULL) {
 		OBD_FREE(new_param, new_len);
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 	}
 
 	lustre_cfg_bufs_reset(bufs, NULL);
@@ -1031,14 +1016,14 @@
 	OBD_FREE(new_param, new_len);
 	OBD_FREE_PTR(bufs);
 	if (new_cfg == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	new_cfg->lcfg_num = cfg->lcfg_num;
 	new_cfg->lcfg_flags = cfg->lcfg_flags;
 	new_cfg->lcfg_nid = cfg->lcfg_nid;
 	new_cfg->lcfg_nal = cfg->lcfg_nal;
 
-	RETURN(new_cfg);
+	return new_cfg;
 }
 EXPORT_SYMBOL(lustre_cfg_rename);
 
@@ -1244,11 +1229,10 @@
 	int matched = 0, j = 0;
 	int rc = 0;
 	int skip = 0;
-	ENTRY;
 
 	if (lcfg->lcfg_command != LCFG_PARAM) {
 		CERROR("Unknown command: %d\n", lcfg->lcfg_command);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* fake a seq file so that var->fops->write can work... */
@@ -1295,7 +1279,7 @@
 			/* If the prefix doesn't match, return error so we
 			   can pass it down the stack */
 			if (strnchr(key, keylen, '.'))
-			    RETURN(-ENOSYS);
+			    return -ENOSYS;
 			CERROR("%s: unknown param %s\n",
 			       (char *)lustre_cfg_string(lcfg, 0), key);
 			/* rc = -EINVAL;	continue parsing other params */
@@ -1316,7 +1300,7 @@
 		rc = 0;
 	if (!rc && skip)
 		rc = skip;
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_process_proc_param);
 
@@ -1335,7 +1319,6 @@
 	int cfg_len = rec->lrh_len;
 	char *cfg_buf = (char*) (rec + 1);
 	int rc = 0;
-	ENTRY;
 
 	//class_config_dump_handler(handle, rec, data);
 
@@ -1426,10 +1409,13 @@
 		}
 
 
-		if ((clli->cfg_flags & CFG_F_EXCLUDE) &&
-		    (lcfg->lcfg_command == LCFG_LOV_ADD_OBD))
-			/* Add inactive instead */
-			lcfg->lcfg_command = LCFG_LOV_ADD_INA;
+		if (clli->cfg_flags & CFG_F_EXCLUDE) {
+			CDEBUG(D_CONFIG, "cmd: %x marked EXCLUDED\n",
+			       lcfg->lcfg_command);
+			if (lcfg->lcfg_command == LCFG_LOV_ADD_OBD)
+				/* Add inactive instead */
+				lcfg->lcfg_command = LCFG_LOV_ADD_INA;
+		}
 
 		lustre_cfg_bufs_init(&bufs, lcfg);
 
@@ -1513,7 +1499,7 @@
 		       handle->lgh_ctxt->loc_obd->obd_name, rc);
 		class_config_dump_handler(NULL, handle, rec, data);
 	}
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_config_llog_handler);
 
@@ -1524,12 +1510,11 @@
 	struct llog_handle		*llh;
 	llog_cb_t			 callback;
 	int				 rc;
-	ENTRY;
 
 	CDEBUG(D_INFO, "looking up llog %s\n", name);
 	rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
 	if (rc)
@@ -1555,7 +1540,7 @@
 
 parse_out:
 	llog_close(env, llh);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_config_parse_llog);
 
@@ -1571,12 +1556,10 @@
 	char			*end = buf + size;
 	int			 rc = 0;
 
-	ENTRY;
-
 	LASSERT(rec->lrh_type == OBD_CFG_REC);
 	rc = lustre_cfg_sanity_check(lcfg, rec->lrh_len);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	ptr += snprintf(ptr, end-ptr, "cmd=%05x ", lcfg->lcfg_command);
 	if (lcfg->lcfg_flags)
@@ -1607,7 +1590,7 @@
 	}
 	/* return consumed bytes */
 	rc = ptr - buf;
-	RETURN(rc);
+	return rc;
 }
 
 int class_config_dump_handler(const struct lu_env *env,
@@ -1617,11 +1600,9 @@
 	char	*outstr;
 	int	 rc = 0;
 
-	ENTRY;
-
 	OBD_ALLOC(outstr, 256);
 	if (outstr == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (rec->lrh_type == OBD_CFG_REC) {
 		class_config_parse_rec(rec, outstr, 256);
@@ -1632,7 +1613,7 @@
 	}
 
 	OBD_FREE(outstr, 256);
-	RETURN(rc);
+	return rc;
 }
 
 int class_config_dump_llog(const struct lu_env *env, struct llog_ctxt *ctxt,
@@ -1641,13 +1622,11 @@
 	struct llog_handle	*llh;
 	int			 rc;
 
-	ENTRY;
-
 	LCONSOLE_INFO("Dumping config log %s\n", name);
 
 	rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = llog_init_handle(env, llh, LLOG_F_IS_PLAIN, NULL);
 	if (rc)
@@ -1658,7 +1637,7 @@
 	llog_close(env, llh);
 
 	LCONSOLE_INFO("End config log %s\n", name);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_config_dump_llog);
 
@@ -1671,11 +1650,10 @@
 	struct lustre_cfg      *lcfg;
 	struct lustre_cfg_bufs  bufs;
 	int		     rc;
-	ENTRY;
 
 	if (!obd) {
 		CERROR("empty cleanup\n");
-		RETURN(-EALREADY);
+		return -EALREADY;
 	}
 
 	if (obd->obd_force)
@@ -1690,7 +1668,7 @@
 	lustre_cfg_bufs_set_string(&bufs, 1, flags);
 	lcfg = lustre_cfg_new(LCFG_CLEANUP, &bufs);
 	if (!lcfg)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = class_process_config(lcfg);
 	if (rc) {
@@ -1705,7 +1683,7 @@
 		CERROR("detach failed %d: %s\n", rc, obd->obd_name);
 out:
 	lustre_cfg_free(lcfg);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(class_manual_cleanup);
 
@@ -1797,7 +1775,7 @@
 
 	exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
 
-	RETURN(&exp->exp_connection->c_peer.nid);
+	return &exp->exp_connection->c_peer.nid;
 }
 
 /*
@@ -1812,8 +1790,8 @@
 	LASSERT(key);
 	exp = hlist_entry(hnode, struct obd_export, exp_nid_hash);
 
-	RETURN(exp->exp_connection->c_peer.nid == *(lnet_nid_t *)key &&
-	       !exp->exp_failed);
+	return exp->exp_connection->c_peer.nid == *(lnet_nid_t *)key &&
+	       !exp->exp_failed;
 }
 
 static void *
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index 99adad9..68a4d6a 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -47,10 +47,8 @@
 
 #include <obd.h>
 #include <lvfs.h>
-#include <lustre_fsfilt.h>
 #include <obd_class.h>
 #include <lustre/lustre_user.h>
-#include <linux/version.h>
 #include <lustre_log.h>
 #include <lustre_disk.h>
 #include <lustre_param.h>
@@ -82,14 +80,13 @@
 	struct lustre_sb_info *lsi = s2lsi(sb);
 	struct obd_device *mgc = lsi->lsi_mgc;
 	int rc;
-	ENTRY;
 
 	LASSERT(mgc);
 	LASSERT(cfg);
 
 	OBD_ALLOC_PTR(bufs);
 	if (bufs == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* mgc_process_config */
 	lustre_cfg_bufs_reset(bufs, mgc->obd_name);
@@ -119,7 +116,7 @@
 				   rc);
 
 	/* class_obd_list(); */
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(lustre_process_log);
 
@@ -132,10 +129,9 @@
 	struct lustre_sb_info *lsi = s2lsi(sb);
 	struct obd_device *mgc = lsi->lsi_mgc;
 	int rc;
-	ENTRY;
 
 	if (!mgc)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	/* mgc_process_config */
 	lustre_cfg_bufs_reset(&bufs, mgc->obd_name);
@@ -145,7 +141,7 @@
 	lcfg = lustre_cfg_new(LCFG_LOG_END, &bufs);
 	rc = obd_process_config(mgc, sizeof(*lcfg), lcfg);
 	lustre_cfg_free(lcfg);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(lustre_end_log);
 
@@ -225,7 +221,6 @@
 	char *ptr;
 	int recov_bk;
 	int rc = 0, i = 0, j, len;
-	ENTRY;
 
 	LASSERT(lsi->lsi_lmd);
 
@@ -254,7 +249,7 @@
 	}
 	if (i == 0) {
 		CERROR("No valid MGS nids found.\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	mutex_lock(&mgc_start_lock);
@@ -478,7 +473,7 @@
 		OBD_FREE(mgcname, len);
 	if (niduuid)
 		OBD_FREE(niduuid, len + 2);
-	RETURN(rc);
+	return rc;
 }
 
 static int lustre_stop_mgc(struct super_block *sb)
@@ -487,13 +482,12 @@
 	struct obd_device *obd;
 	char *niduuid = 0, *ptr = 0;
 	int i, rc = 0, len = 0;
-	ENTRY;
 
 	if (!lsi)
-		RETURN(-ENOENT);
+		return -ENOENT;
 	obd = lsi->lsi_mgc;
 	if (!obd)
-		RETURN(-ENOENT);
+		return -ENOENT;
 	lsi->lsi_mgc = NULL;
 
 	mutex_lock(&mgc_start_lock);
@@ -549,7 +543,7 @@
 
 	/* class_import_put will get rid of the additional connections */
 	mutex_unlock(&mgc_start_lock);
-	RETURN(rc);
+	return rc;
 }
 
 /***************** lustre superblock **************/
@@ -557,15 +551,14 @@
 struct lustre_sb_info *lustre_init_lsi(struct super_block *sb)
 {
 	struct lustre_sb_info *lsi;
-	ENTRY;
 
 	OBD_ALLOC_PTR(lsi);
 	if (!lsi)
-		RETURN(NULL);
+		return NULL;
 	OBD_ALLOC_PTR(lsi->lsi_lmd);
 	if (!lsi->lsi_lmd) {
 		OBD_FREE_PTR(lsi);
-		RETURN(NULL);
+		return NULL;
 	}
 
 	lsi->lsi_lmd->lmd_exclude_count = 0;
@@ -578,13 +571,12 @@
 	/* Default umount style */
 	lsi->lsi_flags = LSI_UMOUNT_FAILOVER;
 
-	RETURN(lsi);
+	return lsi;
 }
 
 static int lustre_free_lsi(struct super_block *sb)
 {
 	struct lustre_sb_info *lsi = s2lsi(sb);
-	ENTRY;
 
 	LASSERT(lsi != NULL);
 	CDEBUG(D_MOUNT, "Freeing lsi %p\n", lsi);
@@ -625,7 +617,7 @@
 	OBD_FREE(lsi, sizeof(*lsi));
 	s2lsi_nocast(sb) = NULL;
 
-	RETURN(0);
+	return 0;
 }
 
 /* The lsi has one reference for every server that is using the disk -
@@ -633,7 +625,6 @@
 int lustre_put_lsi(struct super_block *sb)
 {
 	struct lustre_sb_info *lsi = s2lsi(sb);
-	ENTRY;
 
 	LASSERT(lsi != NULL);
 
@@ -645,11 +636,20 @@
 			obd_zombie_barrier();
 		}
 		lustre_free_lsi(sb);
-		RETURN(1);
+		return 1;
 	}
-	RETURN(0);
+	return 0;
 }
 
+/*** SERVER NAME ***
+ * <FSNAME><SEPERATOR><TYPE><INDEX>
+ * FSNAME is between 1 and 8 characters (inclusive).
+ *	Excluded characters are '/' and ':'
+ * SEPERATOR is either ':' or '-'
+ * TYPE: "OST", "MDT", etc.
+ * INDEX: Hex representation of the index
+ */
+
 /** Get the fsname ("lustre") from the server name ("lustre-OST003F").
  * @param [in] svname server name including type and index
  * @param [out] fsname Buffer to copy filesystem name prefix into.
@@ -659,22 +659,13 @@
  */
 int server_name2fsname(const char *svname, char *fsname, const char **endptr)
 {
-	const char *dash = strrchr(svname, '-');
-	if (!dash) {
-		dash = strrchr(svname, ':');
-		if (!dash)
-			return -EINVAL;
-	}
+	const char *dash;
 
-	/* interpret <fsname>-MDTXXXXX-mdc as mdt, the better way is to pass
-	 * in the fsname, then determine the server index */
-	if (!strcmp(LUSTRE_MDC_NAME, dash + 1)) {
-		dash--;
-		for (; dash > svname && *dash != '-' && *dash != ':'; dash--)
-			;
-		if (dash == svname)
-			return -EINVAL;
-	}
+	dash = svname + strnlen(svname, 8); /* max fsname length is 8 */
+	for (; dash > svname && *dash != '-' && *dash != ':'; dash--)
+		;
+	if (dash == svname)
+		return -EINVAL;
 
 	if (fsname != NULL) {
 		strncpy(fsname, svname, dash - svname);
@@ -697,15 +688,15 @@
 		       size_t svsize)
 {
 	int rc;
-	const const char *dash;
+	const char *dash;
 
 	/* We use server_name2fsname() just for parsing */
 	rc = server_name2fsname(label, NULL, &dash);
 	if (rc != 0)
 		return rc;
 
-	if (*dash != '-')
-		return -1;
+	if (endptr != NULL)
+		*endptr = dash;
 
 	if (strlcpy(svname, dash + 1, svsize) >= svsize)
 		return -E2BIG;
@@ -730,9 +721,6 @@
 	if (rc != 0)
 		return rc;
 
-	if (*dash != '-')
-		return -EINVAL;
-
 	dash++;
 
 	if (strncmp(dash, "MDT", 3) == 0)
@@ -744,11 +732,20 @@
 
 	dash += 3;
 
-	if (strcmp(dash, "all") == 0)
+	if (strncmp(dash, "all", 3) == 0) {
+		if (endptr != NULL)
+			*endptr = dash + 3;
 		return rc | LDD_F_SV_ALL;
+	}
 
 	index = simple_strtoul(dash, (char **)endptr, 16);
-	*idx = index;
+	if (idx != NULL)
+		*idx = index;
+
+	/* Account for -mdc after index that is possible when specifying mdt */
+	if (endptr != NULL && strncmp(LUSTRE_MDC_NAME, *endptr + 1,
+				      sizeof(LUSTRE_MDC_NAME)-1) == 0)
+		*endptr += sizeof(LUSTRE_MDC_NAME);
 
 	return rc;
 }
@@ -760,7 +757,6 @@
 int lustre_common_put_super(struct super_block *sb)
 {
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_MOUNT, "dropping sb %p\n", sb);
 
@@ -769,7 +765,7 @@
 	if (rc && (rc != -ENOENT)) {
 		if (rc != -EBUSY) {
 			CERROR("Can't stop MGC: %d\n", rc);
-			RETURN(rc);
+			return rc;
 		}
 		/* BUSY just means that there's some other obd that
 		   needs the mgc.  Let him clean it up. */
@@ -778,7 +774,7 @@
 	/* Drop a ref to the mounted disk */
 	lustre_put_lsi(sb);
 	lu_types_stop();
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(lustre_common_put_super);
 
@@ -816,12 +812,11 @@
 	struct lustre_mount_data *lmd = lsi->lsi_lmd;
 	__u32 index;
 	int i, rc;
-	ENTRY;
 
 	rc = server_name2index(svname, &index, NULL);
 	if (rc != LDD_F_SV_TYPE_OST)
 		/* Only exclude OSTs */
-		RETURN(0);
+		return 0;
 
 	CDEBUG(D_MOUNT, "Check exclusion %s (%d) in %d of %s\n", svname,
 	       index, lmd->lmd_exclude_count, lmd->lmd_dev);
@@ -829,10 +824,10 @@
 	for(i = 0; i < lmd->lmd_exclude_count; i++) {
 		if (index == lmd->lmd_exclude[i]) {
 			CWARN("Excluding %s (on exclusion list)\n", svname);
-			RETURN(1);
+			return 1;
 		}
 	}
-	RETURN(0);
+	return 0;
 }
 
 /* mount -v  -o exclude=lustre-OST0001:lustre-OST0002 -t lustre ... */
@@ -841,7 +836,6 @@
 	const char *s1 = ptr, *s2;
 	__u32 index, *exclude_list;
 	int rc = 0, devmax;
-	ENTRY;
 
 	/* The shortest an ost name can be is 8 chars: -OST0000.
 	   We don't actually know the fsname at this time, so in fact
@@ -851,20 +845,22 @@
 	/* temp storage until we figure out how many we have */
 	OBD_ALLOC(exclude_list, sizeof(index) * devmax);
 	if (!exclude_list)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* we enter this fn pointing at the '=' */
 	while (*s1 && *s1 != ' ' && *s1 != ',') {
 		s1++;
 		rc = server_name2index(s1, &index, &s2);
 		if (rc < 0) {
-			CERROR("Can't parse server name '%s'\n", s1);
+			CERROR("Can't parse server name '%s': rc = %d\n",
+			       s1, rc);
 			break;
 		}
 		if (rc == LDD_F_SV_TYPE_OST)
 			exclude_list[lmd->lmd_exclude_count++] = index;
 		else
-			CDEBUG(D_MOUNT, "ignoring exclude %.7s\n", s1);
+			CDEBUG(D_MOUNT, "ignoring exclude %.*s: type = %#x\n",
+			       (uint)(s2-s1), s1, rc);
 		s1 = s2;
 		/* now we are pointing at ':' (next exclude)
 		   or ',' (end of excludes) */
@@ -887,7 +883,7 @@
 		}
 	}
 	OBD_FREE(exclude_list, sizeof(index) * devmax);
-	RETURN(rc);
+	return rc;
 }
 
 static int lmd_parse_mgssec(struct lustre_mount_data *lmd, char *ptr)
@@ -991,13 +987,12 @@
 	char *s1, *s2, *devname = NULL;
 	struct lustre_mount_data *raw = (struct lustre_mount_data *)options;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(lmd);
 	if (!options) {
 		LCONSOLE_ERROR_MSG(0x162, "Missing mount data: check that "
 				   "/sbin/mount.lustre is installed.\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* Options should be a string - try to detect old lmd data */
@@ -1005,13 +1000,13 @@
 		LCONSOLE_ERROR_MSG(0x163, "You're using an old version of "
 				   "/sbin/mount.lustre.  Please install "
 				   "version %s\n", LUSTRE_VERSION_STRING);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	lmd->lmd_magic = LMD_MAGIC;
 
 	OBD_ALLOC(lmd->lmd_params, 4096);
 	if (lmd->lmd_params == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lmd->lmd_params[0] = '\0';
 
 	/* Set default flags here */
@@ -1150,14 +1145,14 @@
 		/* Freed in lustre_free_lsi */
 		OBD_ALLOC(lmd->lmd_profile, strlen(s1) + 8);
 		if (!lmd->lmd_profile)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		sprintf(lmd->lmd_profile, "%s-client", s1);
 	}
 
 	/* Freed in lustre_free_lsi */
 	OBD_ALLOC(lmd->lmd_dev, strlen(devname) + 1);
 	if (!lmd->lmd_dev)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	strcpy(lmd->lmd_dev, devname);
 
 	/* Save mount options */
@@ -1168,18 +1163,18 @@
 		/* Freed in lustre_free_lsi */
 		OBD_ALLOC(lmd->lmd_opts, strlen(options) + 1);
 		if (!lmd->lmd_opts)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		strcpy(lmd->lmd_opts, options);
 	}
 
 	lmd_print(lmd);
 	lmd->lmd_magic = LMD_MAGIC;
 
-	RETURN(rc);
+	return rc;
 
 invalid:
 	CERROR("Bad mount options %s\n", options);
-	RETURN(-EINVAL);
+	return -EINVAL;
 }
 
 struct lustre_mount_data2 {
@@ -1198,13 +1193,12 @@
 	struct lustre_mount_data2 *lmd2 = data;
 	struct lustre_sb_info *lsi;
 	int rc;
-	ENTRY;
 
 	CDEBUG(D_MOUNT|D_VFSTRACE, "VFS Op: sb %p\n", sb);
 
 	lsi = lustre_init_lsi(sb);
 	if (!lsi)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	lmd = lsi->lsi_lmd;
 
 	/*
diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c
index 01a0e1f..7099764 100644
--- a/drivers/staging/lustre/lustre/obdclass/obdo.c
+++ b/drivers/staging/lustre/lustre/obdclass/obdo.c
@@ -100,11 +100,11 @@
 		newvalid |= OBD_MD_FLMODE;
 	}
 	if (valid & OBD_MD_FLUID) {
-		dst->o_uid = src->i_uid;
+		dst->o_uid = from_kuid(&init_user_ns, src->i_uid);
 		newvalid |= OBD_MD_FLUID;
 	}
 	if (valid & OBD_MD_FLGID) {
-		dst->o_gid = src->i_gid;
+		dst->o_gid = from_kgid(&init_user_ns, src->i_gid);
 		newvalid |= OBD_MD_FLGID;
 	}
 	if (valid & OBD_MD_FLFLAGS) {
@@ -232,16 +232,16 @@
 	if (ia_valid & ATTR_MODE) {
 		oa->o_mode = attr->ia_mode;
 		oa->o_valid |= OBD_MD_FLTYPE | OBD_MD_FLMODE;
-		if (!current_is_in_group(oa->o_gid) &&
+		if (!in_group_p(make_kgid(&init_user_ns, oa->o_gid)) &&
 		    !cfs_capable(CFS_CAP_FSETID))
 			oa->o_mode &= ~S_ISGID;
 	}
 	if (ia_valid & ATTR_UID) {
-		oa->o_uid = attr->ia_uid;
+		oa->o_uid = from_kuid(&init_user_ns, attr->ia_uid);
 		oa->o_valid |= OBD_MD_FLUID;
 	}
 	if (ia_valid & ATTR_GID) {
-		oa->o_gid = attr->ia_gid;
+		oa->o_gid = from_kgid(&init_user_ns, attr->ia_gid);
 		oa->o_valid |= OBD_MD_FLGID;
 	}
 }
@@ -281,16 +281,16 @@
 	if (valid & OBD_MD_FLMODE) {
 		attr->ia_mode = (attr->ia_mode & S_IFMT)|(oa->o_mode & ~S_IFMT);
 		attr->ia_valid |= ATTR_MODE;
-		if (!current_is_in_group(oa->o_gid) &&
+		if (!in_group_p(make_kgid(&init_user_ns, oa->o_gid)) &&
 		    !cfs_capable(CFS_CAP_FSETID))
 			attr->ia_mode &= ~S_ISGID;
 	}
 	if (valid & OBD_MD_FLUID) {
-		attr->ia_uid = oa->o_uid;
+		attr->ia_uid = make_kuid(&init_user_ns, oa->o_uid);
 		attr->ia_valid |= ATTR_UID;
 	}
 	if (valid & OBD_MD_FLGID) {
-		attr->ia_gid = oa->o_gid;
+		attr->ia_gid = make_kgid(&init_user_ns, oa->o_gid);
 		attr->ia_valid |= ATTR_GID;
 	}
 }
diff --git a/drivers/staging/lustre/lustre/obdecho/echo.c b/drivers/staging/lustre/lustre/obdecho/echo.c
index 9e64939..debb9ce 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo.c
@@ -96,12 +96,10 @@
 
 static int echo_destroy_export(struct obd_export *exp)
 {
-	ENTRY;
-
 	target_destroy_export(exp);
 	ldlm_destroy_export(exp);
 
-	RETURN(0);
+	return 0;
 }
 
  static __u64 echo_next_id(struct obd_device *obddev)
@@ -151,25 +149,24 @@
 {
 	struct obd_device *obd = class_exp2obd(exp);
 
-	ENTRY;
 	if (!obd) {
 		CERROR("invalid client cookie "LPX64"\n",
 		       exp->exp_handle.h_cookie);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (!(oa->o_valid & OBD_MD_FLID)) {
 		CERROR("obdo missing FLID valid flag: "LPX64"\n", oa->o_valid);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (ostid_id(&oa->o_oi) > obd->u.echo.eo_lastino ||
 	    ostid_id(&oa->o_oi) < ECHO_INIT_OID) {
 		CERROR("bad destroy objid: "DOSTID"\n", POSTID(&oa->o_oi));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static int echo_getattr(const struct lu_env *env, struct obd_export *exp,
@@ -178,24 +175,23 @@
 	struct obd_device *obd = class_exp2obd(exp);
 	obd_id id = ostid_id(&oinfo->oi_oa->o_oi);
 
-	ENTRY;
 	if (!obd) {
 		CERROR("invalid client cookie "LPX64"\n",
 		       exp->exp_handle.h_cookie);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (!(oinfo->oi_oa->o_valid & OBD_MD_FLID)) {
 		CERROR("obdo missing FLID valid flag: "LPX64"\n",
 		       oinfo->oi_oa->o_valid);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	obdo_cpy_md(oinfo->oi_oa, &obd->u.echo.eo_oa, oinfo->oi_oa->o_valid);
 	ostid_set_seq_echo(&oinfo->oi_oa->o_oi);
 	ostid_set_id(&oinfo->oi_oa->o_oi, id);
 
-	RETURN(0);
+	return 0;
 }
 
 static int echo_setattr(const struct lu_env *env, struct obd_export *exp,
@@ -203,17 +199,16 @@
 {
 	struct obd_device *obd = class_exp2obd(exp);
 
-	ENTRY;
 	if (!obd) {
 		CERROR("invalid client cookie "LPX64"\n",
 		       exp->exp_handle.h_cookie);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (!(oinfo->oi_oa->o_valid & OBD_MD_FLID)) {
 		CERROR("obdo missing FLID valid flag: "LPX64"\n",
 		       oinfo->oi_oa->o_valid);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	memcpy(&obd->u.echo.eo_oa, oinfo->oi_oa, sizeof(*oinfo->oi_oa));
@@ -225,7 +220,7 @@
 		oti->oti_ack_locks[0].lock = obd->u.echo.eo_nl_lock;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static void
@@ -410,11 +405,10 @@
 	int tot_bytes = 0;
 	int rc = 0;
 	int i, left;
-	ENTRY;
 
 	obd = export->exp_obd;
 	if (obd == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* Temp fix to stop falling foul of osc_announce_cached() */
 	oa->o_valid &= ~(OBD_MD_FLBLOCKS | OBD_MD_FLGRANT);
@@ -456,7 +450,7 @@
 	CDEBUG(D_PAGE, "%d pages allocated after prep\n",
 	       atomic_read(&obd->u.echo.eo_prep));
 
-	RETURN(0);
+	return 0;
 
 preprw_cleanup:
 	/* It is possible that we would rather handle errors by  allow
@@ -487,11 +481,10 @@
 	struct obd_device *obd;
 	int pgs = 0;
 	int i;
-	ENTRY;
 
 	obd = export->exp_obd;
 	if (obd == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if (rc)
 		GOTO(commitrw_cleanup, rc);
@@ -506,7 +499,7 @@
 
 	if (niocount && res == NULL) {
 		CERROR("NULL res niobuf with niocount %d\n", niocount);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	LASSERT(oti == NULL || oti->oti_handle == (void *)DESC_PRIV);
@@ -537,7 +530,7 @@
 
 	CDEBUG(D_PAGE, "%d pages remain after commit\n",
 	       atomic_read(&obd->u.echo.eo_prep));
-	RETURN(rc);
+	return rc;
 
 commitrw_cleanup:
 	atomic_sub(pgs, &obd->u.echo.eo_prep);
@@ -565,7 +558,6 @@
 	__u64		      lock_flags = 0;
 	struct ldlm_res_id	 res_id = {.name = {1}};
 	char		       ns_name[48];
-	ENTRY;
 
 	obd->u.echo.eo_obt.obt_magic = OBT_MAGIC;
 	spin_lock_init(&obd->u.echo.eo_lock);
@@ -578,7 +570,7 @@
 						LDLM_NS_TYPE_OST);
 	if (obd->obd_namespace == NULL) {
 		LBUG();
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	rc = ldlm_cli_enqueue_local(obd->obd_namespace, &res_id, LDLM_PLAIN,
@@ -600,13 +592,12 @@
 
 	ptlrpc_init_client (LDLM_CB_REQUEST_PORTAL, LDLM_CB_REPLY_PORTAL,
 			    "echo_ldlm_cb_client", &obd->obd_ldlm_client);
-	RETURN(0);
+	return 0;
 }
 
 static int echo_cleanup(struct obd_device *obd)
 {
 	int leaked;
-	ENTRY;
 
 	lprocfs_obd_cleanup(obd);
 	lprocfs_free_obd_stats(obd);
@@ -624,7 +615,7 @@
 	if (leaked != 0)
 		CERROR("%d prep/commitrw pages leaked\n", leaked);
 
-	RETURN(0);
+	return 0;
 }
 
 struct obd_ops echo_obd_ops = {
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index 184195f..2644edf 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -43,6 +43,7 @@
 #include <lustre_debug.h>
 #include <lprocfs_status.h>
 #include <cl_object.h>
+#include <md_object.h>
 #include <lustre_fid.h>
 #include <lustre_acl.h>
 #include <lustre_net.h>
@@ -312,11 +313,9 @@
 	struct echo_page *ep    = cl2echo_page(slice);
 	struct echo_object *eco = cl2echo_obj(slice->cpl_obj);
 	struct page *vmpage      = ep->ep_vmpage;
-	ENTRY;
 
 	atomic_dec(&eco->eo_npages);
 	page_cache_release(vmpage);
-	EXIT;
 }
 
 static int echo_page_prep(const struct lu_env *env,
@@ -408,14 +407,13 @@
 {
 	struct echo_page *ep = cl_object_page_slice(obj, page);
 	struct echo_object *eco = cl2echo_obj(obj);
-	ENTRY;
 
 	ep->ep_vmpage = vmpage;
 	page_cache_get(vmpage);
 	mutex_init(&ep->ep_lock);
 	cl_page_slice_add(page, &ep->ep_cl, obj, &echo_page_ops);
 	atomic_inc(&eco->eo_npages);
-	RETURN(0);
+	return 0;
 }
 
 static int echo_io_init(const struct lu_env *env, struct cl_object *obj,
@@ -429,7 +427,6 @@
 			  const struct cl_io *unused)
 {
 	struct echo_lock *el;
-	ENTRY;
 
 	OBD_SLAB_ALLOC_PTR_GFP(el, echo_lock_kmem, __GFP_IO);
 	if (el != NULL) {
@@ -438,7 +435,7 @@
 		INIT_LIST_HEAD(&el->el_chain);
 		atomic_set(&el->el_refcount, 0);
 	}
-	RETURN(el == NULL ? -ENOMEM : 0);
+	return el == NULL ? -ENOMEM : 0;
 }
 
 static int echo_conf_set(const struct lu_env *env, struct cl_object *obj,
@@ -467,7 +464,6 @@
 	struct echo_device *ed	 = cl2echo_dev(lu2cl_dev(obj->lo_dev));
 	struct echo_client_obd *ec     = ed->ed_ec;
 	struct echo_object *eco	= cl2echo_obj(lu2cl(obj));
-	ENTRY;
 
 	if (ed->ed_next) {
 		struct lu_object  *below;
@@ -477,7 +473,7 @@
 		below = under->ld_ops->ldo_object_alloc(env, obj->lo_header,
 							under);
 		if (below == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		lu_object_add(obj, below);
 	}
 
@@ -501,7 +497,7 @@
 	list_add_tail(&eco->eo_obj_chain, &ec->ec_objects);
 	spin_unlock(&ec->ec_lock);
 
-	RETURN(0);
+	return 0;
 }
 
 /* taken from osc_unpackmd() */
@@ -510,8 +506,6 @@
 {
 	int lsm_size;
 
-	ENTRY;
-
 	/* If export is lov/osc then use their obd method */
 	if (ed->ed_next != NULL)
 		return obd_alloc_memmd(ed->ed_ec->ec_exp, lsmp);
@@ -521,27 +515,25 @@
 	LASSERT(*lsmp == NULL);
 	OBD_ALLOC(*lsmp, lsm_size);
 	if (*lsmp == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	OBD_ALLOC((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
 	if ((*lsmp)->lsm_oinfo[0] == NULL) {
 		OBD_FREE(*lsmp, lsm_size);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	loi_init((*lsmp)->lsm_oinfo[0]);
 	(*lsmp)->lsm_maxbytes = LUSTRE_STRIPE_MAXBYTES;
 	ostid_set_seq_echo(&(*lsmp)->lsm_oi);
 
-	RETURN(lsm_size);
+	return lsm_size;
 }
 
 static int echo_free_memmd(struct echo_device *ed, struct lov_stripe_md **lsmp)
 {
 	int lsm_size;
 
-	ENTRY;
-
 	/* If export is lov/osc then use their obd method */
 	if (ed->ed_next != NULL)
 		return obd_free_memmd(ed->ed_ec->ec_exp, lsmp);
@@ -552,14 +544,13 @@
 	OBD_FREE((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
 	OBD_FREE(*lsmp, lsm_size);
 	*lsmp = NULL;
-	RETURN(0);
+	return 0;
 }
 
 static void echo_object_free(const struct lu_env *env, struct lu_object *obj)
 {
 	struct echo_object *eco    = cl2echo_obj(lu2cl(obj));
 	struct echo_client_obd *ec = eco->eo_dev->ed_ec;
-	ENTRY;
 
 	LASSERT(atomic_read(&eco->eo_npages) == 0);
 
@@ -573,7 +564,6 @@
 	if (eco->eo_lsm)
 		echo_free_memmd(eco->eo_dev, &eco->eo_lsm);
 	OBD_SLAB_FREE_PTR(eco, echo_object_kmem);
-	EXIT;
 }
 
 static int echo_object_print(const struct lu_env *env, void *cookie,
@@ -606,7 +596,6 @@
 {
 	struct echo_object *eco;
 	struct lu_object *obj = NULL;
-	ENTRY;
 
 	/* we're the top dev. */
 	LASSERT(hdr == NULL);
@@ -622,7 +611,7 @@
 		eco->eo_cl.co_ops = &echo_cl_obj_ops;
 		obj->lo_ops       = &echo_lu_obj_ops;
 	}
-	RETURN(obj);
+	return obj;
 }
 
 static struct lu_device_operations echo_device_lu_ops = {
@@ -648,7 +637,7 @@
 	/* initialize site */
 	rc = cl_site_init(site, &ed->ed_cl);
 	if (rc) {
-		CERROR("Cannot initilize site for echo client(%d)\n", rc);
+		CERROR("Cannot initialize site for echo client(%d)\n", rc);
 		return rc;
 	}
 
@@ -737,11 +726,10 @@
 {
 	char *prefix;
 	int rc;
-	ENTRY;
 
 	OBD_ALLOC_PTR(ed->ed_cl_seq);
 	if (ed->ed_cl_seq == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	OBD_ALLOC(prefix, MAX_OBD_NAME + 5);
 	if (prefix == NULL)
@@ -758,18 +746,17 @@
 	if (rc)
 		GOTO(out_free_seq, rc);
 
-	RETURN(0);
+	return 0;
 
 out_free_seq:
 	OBD_FREE_PTR(ed->ed_cl_seq);
 	ed->ed_cl_seq = NULL;
-	RETURN(rc);
+	return rc;
 }
 
 static int echo_fid_fini(struct obd_device *obddev)
 {
 	struct echo_device *ed = obd2echo_dev(obddev);
-	ENTRY;
 
 	if (ed->ed_cl_seq != NULL) {
 		seq_client_fini(ed->ed_cl_seq);
@@ -777,7 +764,7 @@
 		ed->ed_cl_seq = NULL;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static struct lu_device *echo_device_alloc(const struct lu_env *env,
@@ -792,7 +779,6 @@
 	const char *tgt_type_name;
 	int rc;
 	int cleanup = 0;
-	ENTRY;
 
 	OBD_ALLOC_PTR(ed);
 	if (ed == NULL)
@@ -916,7 +902,7 @@
 	}
 
 	ed->ed_next = next;
-	RETURN(&cd->cd_lu_dev);
+	return &cd->cd_lu_dev;
 out:
 	switch(cleanup) {
 	case 4: {
@@ -1076,7 +1062,6 @@
 	struct lu_fid *fid;
 	int refcheck;
 	int rc;
-	ENTRY;
 
 	LASSERT(lsmp);
 	lsm = *lsmp;
@@ -1087,11 +1072,11 @@
 
 	/* Never return an object if the obd is to be freed. */
 	if (echo_dev2cl(d)->cd_lu_dev.ld_obd->obd_stopping)
-		RETURN(ERR_PTR(-ENODEV));
+		return ERR_PTR(-ENODEV);
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN((void *)env);
+		return (void *)env;
 
 	info = echo_env_info(env);
 	conf = &info->eti_conf;
@@ -1131,7 +1116,7 @@
 
 out:
 	cl_env_put(env, &refcheck);
-	RETURN(eco);
+	return eco;
 }
 
 static int cl_echo_object_put(struct echo_object *eco)
@@ -1139,11 +1124,10 @@
 	struct lu_env *env;
 	struct cl_object *obj = echo_obj2cl(eco);
 	int refcheck;
-	ENTRY;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	/* an external function to kill an object? */
 	if (eco->eo_deleted) {
@@ -1154,7 +1138,7 @@
 
 	cl_object_put(env, obj);
 	cl_env_put(env, &refcheck);
-	RETURN(0);
+	return 0;
 }
 
 static int cl_echo_enqueue0(struct lu_env *env, struct echo_object *eco,
@@ -1167,7 +1151,6 @@
 	struct cl_lock_descr *descr;
 	struct echo_thread_info *info;
 	int rc = -ENOMEM;
-	ENTRY;
 
 	info = echo_env_info(env);
 	io = &info->eti_io;
@@ -1201,7 +1184,7 @@
 			cl_lock_release(env, lck, "ec enqueue", current);
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int cl_echo_enqueue(struct echo_object *eco, obd_off start, obd_off end,
@@ -1212,11 +1195,10 @@
 	struct cl_io *io;
 	int refcheck;
 	int result;
-	ENTRY;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	info = echo_env_info(env);
 	io = &info->eti_io;
@@ -1230,7 +1212,6 @@
 	result = cl_echo_enqueue0(env, eco, start, end, mode, cookie, 0);
 	cl_io_fini(env, io);
 
-	EXIT;
 out:
 	cl_env_put(env, &refcheck);
 	return result;
@@ -1243,7 +1224,6 @@
 	struct echo_lock       *ecl = NULL;
 	struct list_head	     *el;
 	int found = 0, still_used = 0;
-	ENTRY;
 
 	LASSERT(ec != NULL);
 	spin_lock(&ec->ec_lock);
@@ -1262,10 +1242,10 @@
 	spin_unlock(&ec->ec_lock);
 
 	if (!found)
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	echo_lock_release(env, ecl, still_used);
-	RETURN(0);
+	return 0;
 }
 
 static int cl_echo_cancel(struct echo_device *ed, __u64 cookie)
@@ -1273,16 +1253,15 @@
 	struct lu_env *env;
 	int refcheck;
 	int rc;
-	ENTRY;
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	rc = cl_echo_cancel0(env, ed, cookie);
 
 	cl_env_put(env, &refcheck);
-	RETURN(rc);
+	return rc;
 }
 
 static int cl_echo_async_brw(const struct lu_env *env, struct cl_io *io,
@@ -1291,7 +1270,6 @@
 	struct cl_page *clp;
 	struct cl_page *temp;
 	int result = 0;
-	ENTRY;
 
 	cl_page_list_for_each_safe(clp, temp, &queue->c2_qin) {
 		int rc;
@@ -1300,7 +1278,7 @@
 			continue;
 		result = result ?: rc;
 	}
-	RETURN(result);
+	return result;
 }
 
 static int cl_echo_object_brw(struct echo_object *eco, int rw, obd_off offset,
@@ -1318,13 +1296,12 @@
 	int refcheck;
 	int rc;
 	int i;
-	ENTRY;
 
 	LASSERT((offset & ~CFS_PAGE_MASK) == 0);
 	LASSERT(ed->ed_next != NULL);
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	info    = echo_env_info(env);
 	io      = &info->eti_io;
@@ -1386,7 +1363,6 @@
 	}
 
 	cl_echo_cancel0(env, ed, lh.cookie);
-	EXIT;
 error_lock:
 	cl_2queue_discard(env, io, queue);
 	cl_2queue_disown(env, io, queue);
@@ -1467,13 +1443,11 @@
 	struct echo_thread_info	*info = echo_env_info(env);
 	int			 rc;
 
-	ENTRY;
-
 	LASSERT(ma->ma_lmm_size > 0);
 
 	rc = mo_xattr_get(env, o, &LU_BUF_NULL, XATTR_NAME_LOV);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	/* big_lmm may need to be grown */
 	if (info->eti_big_lmmsize < rc) {
@@ -1490,7 +1464,7 @@
 
 		OBD_ALLOC_LARGE(info->eti_big_lmm, size);
 		if (info->eti_big_lmm == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		info->eti_big_lmmsize = size;
 	}
 	LASSERT(info->eti_big_lmmsize >= rc);
@@ -1499,13 +1473,13 @@
 	info->eti_buf.lb_len = info->eti_big_lmmsize;
 	rc = mo_xattr_get(env, o, &info->eti_buf, XATTR_NAME_LOV);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	ma->ma_valid |= MA_LOV;
 	ma->ma_lmm = info->eti_big_lmm;
 	ma->ma_lmm_size = rc;
 
-	RETURN(0);
+	return 0;
 }
 
 int echo_attr_get_complex(const struct lu_env *env, struct md_object *next,
@@ -1517,8 +1491,6 @@
 	int			 need = ma->ma_need;
 	int			 rc = 0, rc2;
 
-	ENTRY;
-
 	ma->ma_valid = 0;
 
 	if (need & MA_INODE) {
@@ -1571,7 +1543,7 @@
 	ma->ma_need = need;
 	CDEBUG(D_INODE, "after getattr rc = %d, ma_valid = "LPX64" ma_lmm=%p\n",
 	       rc, ma->ma_valid, ma->ma_lmm);
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -1587,8 +1559,6 @@
 	struct lu_object_conf    conf = { .loc_flags = LOC_F_NEW };
 	int			 rc;
 
-	ENTRY;
-
 	rc = mdo_lookup(env, parent, lname, fid2, spec);
 	if (rc == 0)
 		return -EEXIST;
@@ -1600,7 +1570,7 @@
 	if (IS_ERR(ec_child)) {
 		CERROR("Can not find the child "DFID": rc = %ld\n", PFID(fid),
 			PTR_ERR(ec_child));
-		RETURN(PTR_ERR(ec_child));
+		return PTR_ERR(ec_child);
 	}
 
 	child = lu_object_locate(ec_child->lo_header, ld->ld_type);
@@ -1623,7 +1593,6 @@
 	}
 	CDEBUG(D_RPCTRACE, "End creating object "DFID" %s %p rc  = %d\n",
 	       PFID(lu_object_fid(&parent->mo_lu)), lname->ln_name, parent, rc);
-	EXIT;
 out_put:
 	lu_object_put(env, ec_child);
 	return rc;
@@ -1663,13 +1632,11 @@
 	int		      rc = 0;
 	int		      i;
 
-	ENTRY;
-
 	if (ec_parent == NULL)
 		return -1;
 	parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
 	if (parent == NULL)
-		RETURN(-ENXIO);
+		return -ENXIO;
 
 	memset(ma, 0, sizeof(*ma));
 	memset(spec, 0, sizeof(*spec));
@@ -1699,7 +1666,7 @@
 		/* If name is specified, only create one object by name */
 		rc = echo_md_create_internal(env, ed, lu2md(parent), fid, lname,
 					     spec, ma);
-		RETURN(rc);
+		return rc;
 	}
 
 	/* Create multiple object sequenced by id */
@@ -1719,7 +1686,7 @@
 		fid->f_oid++;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static struct lu_object *echo_md_lookup(const struct lu_env *env,
@@ -1731,14 +1698,13 @@
 	struct lu_fid	   *fid = &info->eti_fid;
 	struct lu_object	*child;
 	int    rc;
-	ENTRY;
 
 	CDEBUG(D_INFO, "lookup %s in parent "DFID" %p\n", lname->ln_name,
 	       PFID(fid), parent);
 	rc = mdo_lookup(env, parent, lname, fid, NULL);
 	if (rc) {
 		CERROR("lookup %s: rc = %d\n", lname->ln_name, rc);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	/* In the function below, .hs_keycmp resolves to
@@ -1746,7 +1712,7 @@
 	/* coverity[overrun-buffer-val] */
 	child = lu_object_find_at(env, &ed->ed_cl.cd_lu_dev, fid, NULL);
 
-	RETURN(child);
+	return child;
 }
 
 static int echo_setattr_object(const struct lu_env *env,
@@ -1763,13 +1729,11 @@
 	int		      rc = 0;
 	int		      i;
 
-	ENTRY;
-
 	if (ec_parent == NULL)
 		return -1;
 	parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
 	if (parent == NULL)
-		RETURN(-ENXIO);
+		return -ENXIO;
 
 	for (i = 0; i < count; i++) {
 		struct lu_object *ec_child, *child;
@@ -1780,7 +1744,7 @@
 		if (IS_ERR(ec_child)) {
 			CERROR("Can't find child %s: rc = %ld\n",
 				lname->ln_name, PTR_ERR(ec_child));
-			RETURN(PTR_ERR(ec_child));
+			return PTR_ERR(ec_child);
 		}
 
 		child = lu_object_locate(ec_child->lo_header, ld->ld_type);
@@ -1811,7 +1775,7 @@
 		id++;
 		lu_object_put(env, ec_child);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int echo_getattr_object(const struct lu_env *env,
@@ -1828,13 +1792,11 @@
 	int		      rc = 0;
 	int		      i;
 
-	ENTRY;
-
 	if (ec_parent == NULL)
 		return -1;
 	parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
 	if (parent == NULL)
-		RETURN(-ENXIO);
+		return -ENXIO;
 
 	memset(ma, 0, sizeof(*ma));
 	ma->ma_need |= MA_INODE | MA_LOV | MA_PFID | MA_HSM | MA_ACL_DEF;
@@ -1852,14 +1814,14 @@
 		if (IS_ERR(ec_child)) {
 			CERROR("Can't find child %s: rc = %ld\n",
 			       lname->ln_name, PTR_ERR(ec_child));
-			RETURN(PTR_ERR(ec_child));
+			return PTR_ERR(ec_child);
 		}
 
 		child = lu_object_locate(ec_child->lo_header, ld->ld_type);
 		if (child == NULL) {
 			CERROR("Can not locate the child %s\n", lname->ln_name);
 			lu_object_put(env, ec_child);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		CDEBUG(D_RPCTRACE, "Start getattr object "DFID"\n",
@@ -1877,7 +1839,7 @@
 		lu_object_put(env, ec_child);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static int echo_lookup_object(const struct lu_env *env,
@@ -1931,13 +1893,11 @@
 	struct lu_object   *child;
 	int		 rc;
 
-	ENTRY;
-
 	ec_child = echo_md_lookup(env, ed, parent, lname);
 	if (IS_ERR(ec_child)) {
 		CERROR("Can't find child %s: rc = %ld\n", lname->ln_name,
 			PTR_ERR(ec_child));
-		RETURN(PTR_ERR(ec_child));
+		return PTR_ERR(ec_child);
 	}
 
 	child = lu_object_locate(ec_child->lo_header, ld->ld_type);
@@ -1976,11 +1936,10 @@
 	struct lu_object	*parent;
 	int		      rc = 0;
 	int		      i;
-	ENTRY;
 
 	parent = lu_object_locate(ec_parent->lo_header, ld->ld_type);
 	if (parent == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	memset(ma, 0, sizeof(*ma));
 	ma->ma_attr.la_mode = mode;
@@ -1994,7 +1953,7 @@
 		lname->ln_namelen = namelen;
 		rc = echo_md_destroy_internal(env, ed, lu2md(parent), lname,
 					      ma);
-		RETURN(rc);
+		return rc;
 	}
 
 	/*prepare the requests*/
@@ -2013,7 +1972,7 @@
 		id++;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static struct lu_object *echo_resolve_path(const struct lu_env *env,
@@ -2028,13 +1987,12 @@
 	struct lu_object	*parent = NULL;
 	struct lu_object	*child = NULL;
 	int rc = 0;
-	ENTRY;
 
 	/*Only support MDD layer right now*/
 	rc = md->md_ops->mdo_root_get(env, md, fid);
 	if (rc) {
 		CERROR("get root error: rc = %d\n", rc);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 
 	/* In the function below, .hs_keycmp resolves to
@@ -2044,7 +2002,7 @@
 	if (IS_ERR(parent)) {
 		CERROR("Can not find the parent "DFID": rc = %ld\n",
 			PFID(fid), PTR_ERR(parent));
-		RETURN(parent);
+		return parent;
 	}
 
 	while (1) {
@@ -2083,9 +2041,9 @@
 		parent = child;
 	}
 	if (rc)
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 
-	RETURN(parent);
+	return parent;
 }
 
 static void echo_ucred_init(struct lu_env *env)
@@ -2097,10 +2055,14 @@
 	ucred->uc_suppgids[0] = -1;
 	ucred->uc_suppgids[1] = -1;
 
-	ucred->uc_uid   = ucred->uc_o_uid   = current_uid();
-	ucred->uc_gid   = ucred->uc_o_gid   = current_gid();
-	ucred->uc_fsuid = ucred->uc_o_fsuid = current_fsuid();
-	ucred->uc_fsgid = ucred->uc_o_fsgid = current_fsgid();
+	ucred->uc_uid   = ucred->uc_o_uid   =
+				from_kuid(&init_user_ns, current_uid());
+	ucred->uc_gid   = ucred->uc_o_gid   =
+				from_kgid(&init_user_ns, current_gid());
+	ucred->uc_fsuid = ucred->uc_o_fsuid =
+				from_kuid(&init_user_ns, current_fsuid());
+	ucred->uc_fsgid = ucred->uc_o_fsgid =
+				from_kgid(&init_user_ns, current_fsgid());
 	ucred->uc_cap   = cfs_curproc_cap_pack();
 
 	/* remove fs privilege for non-root user. */
@@ -2129,21 +2091,20 @@
 	char		  *name = NULL;
 	int		    namelen = data->ioc_plen2;
 	int		    rc = 0;
-	ENTRY;
 
 	if (ld == NULL) {
 		CERROR("MD echo client is not being initialized properly\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (strcmp(ld->ld_type->ldt_name, LUSTRE_MDD_NAME)) {
 		CERROR("Only support MDD layer right now!\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	env = cl_env_get(&refcheck);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	rc = lu_env_refill_by_tags(env, ECHO_MD_CTX_TAG, ECHO_MD_SES_TAG);
 	if (rc != 0)
@@ -2243,13 +2204,12 @@
 	struct lov_stripe_md   *lsm = NULL;
 	int		     rc;
 	int		     created = 0;
-	ENTRY;
 
 	if ((oa->o_valid & OBD_MD_FLID) == 0 && /* no obj id */
 	    (on_target ||		       /* set_stripe */
 	     ec->ec_nstripes != 0)) {	   /* LOV */
 		CERROR ("No valid oid\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = echo_alloc_memmd(ed, &lsm);
@@ -2315,7 +2275,6 @@
 	cl_echo_object_put(eco);
 
 	CDEBUG(D_INFO, "oa oid "DOSTID"\n", POSTID(&oa->o_oi));
-	EXIT;
 
  failed:
 	if (created && rc)
@@ -2333,17 +2292,16 @@
 	struct lov_stripe_md   *lsm = NULL;
 	struct echo_object     *eco;
 	int		     rc;
-	ENTRY;
 
 	if ((oa->o_valid & OBD_MD_FLID) == 0 || ostid_id(&oa->o_oi) == 0) {
 		/* disallow use of object id 0 */
 		CERROR ("No valid oid\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = echo_alloc_memmd(ed, &lsm);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	lsm->lsm_oi = oa->o_oi;
 	if (!(oa->o_valid & OBD_MD_FLGROUP))
@@ -2357,7 +2315,7 @@
 		rc = PTR_ERR(eco);
 	if (lsm)
 		echo_free_memmd(ed, &lsm);
-	RETURN(rc);
+	return rc;
 }
 
 static void echo_put_object(struct echo_object *eco)
@@ -2476,7 +2434,6 @@
 	int		     verify;
 	int		     gfp_mask;
 	int		     brw_flags = 0;
-	ENTRY;
 
 	verify = (ostid_id(&oa->o_oi) != ECHO_PERSISTENT_OBJID &&
 		  (oa->o_valid & OBD_MD_FLFLAGS) != 0 &&
@@ -2490,7 +2447,7 @@
 
 	if (count <= 0 ||
 	    (count & (~CFS_PAGE_MASK)) != 0)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* XXX think again with misaligned I/O */
 	npages = count >> PAGE_CACHE_SHIFT;
@@ -2500,12 +2457,12 @@
 
 	OBD_ALLOC(pga, npages * sizeof(*pga));
 	if (pga == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	OBD_ALLOC(pages, npages * sizeof(*pages));
 	if (pages == NULL) {
 		OBD_FREE(pga, npages * sizeof(*pga));
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	for (i = 0, pgp = pga, off = offset;
@@ -2554,7 +2511,7 @@
 	}
 	OBD_FREE(pga, npages * sizeof(*pga));
 	OBD_FREE(pages, npages * sizeof(*pages));
-	RETURN(rc);
+	return rc;
 }
 
 static int echo_client_prep_commit(const struct lu_env *env,
@@ -2572,11 +2529,9 @@
 	obd_size npages, tot_pages;
 	int i, ret = 0, brw_flags = 0;
 
-	ENTRY;
-
 	if (count <= 0 || (count & (~CFS_PAGE_MASK)) != 0 ||
 	    (lsm != NULL && ostid_id(&lsm->lsm_oi) != ostid_id(&oa->o_oi)))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	npages = batch >> PAGE_CACHE_SHIFT;
 	tot_pages = count >> PAGE_CACHE_SHIFT;
@@ -2661,7 +2616,7 @@
 		OBD_FREE(lnb, npages * sizeof(struct niobuf_local));
 	if (rnb)
 		OBD_FREE(rnb, npages * sizeof(struct niobuf_remote));
-	RETURN(ret);
+	return ret;
 }
 
 static int echo_client_brw_ioctl(const struct lu_env *env, int rw,
@@ -2677,13 +2632,12 @@
 	int rc;
 	int async = 1;
 	long test_mode;
-	ENTRY;
 
 	LASSERT(oa->o_valid & OBD_MD_FLGROUP);
 
 	rc = echo_get_object(&eco, ed, oa);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	oa->o_valid &= ~OBD_MD_FLHANDLE;
 
@@ -2719,7 +2673,7 @@
 		rc = -EINVAL;
 	}
 	echo_put_object(eco);
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -2731,21 +2685,20 @@
 	struct echo_object     *eco;
 	obd_off		 end;
 	int		     rc;
-	ENTRY;
 
 	if (ed->ed_next == NULL)
-		RETURN(-EOPNOTSUPP);
+		return -EOPNOTSUPP;
 
 	if (!(mode == LCK_PR || mode == LCK_PW))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if ((offset & (~CFS_PAGE_MASK)) != 0 ||
 	    (nob & (~CFS_PAGE_MASK)) != 0)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	rc = echo_get_object (&eco, ed, oa);
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	end = (nob == 0) ? ((obd_off) -1) : (offset + nob - 1);
 	rc = cl_echo_enqueue(eco, offset, end, mode, &ulh->cookie);
@@ -2754,7 +2707,7 @@
 		CDEBUG(D_INFO, "Cookie is "LPX64"\n", ulh->cookie);
 	}
 	echo_put_object(eco);
-	RETURN(rc);
+	return rc;
 }
 
 static int
@@ -2787,7 +2740,6 @@
 	int		     rw = OBD_BRW_READ;
 	int		     rc = 0;
 	int		     i;
-	ENTRY;
 
 	memset(&dummy_oti, 0, sizeof(dummy_oti));
 
@@ -2800,11 +2752,11 @@
 	/* This FID is unpacked just for validation at this point */
 	rc = ostid_to_fid(&fid, &oa->o_oi, 0);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	OBD_ALLOC_PTR(env);
 	if (env == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = lu_env_init(env, LCT_DT_THREAD);
 	if (rc)
@@ -2980,7 +2932,6 @@
 		GOTO (out, rc = -ENOTTY);
 	}
 
-	EXIT;
 out:
 	lu_env_fini(env);
 	OBD_FREE_PTR(env);
@@ -3004,18 +2955,17 @@
 	struct obd_uuid echo_uuid = { "ECHO_UUID" };
 	struct obd_connect_data *ocd = NULL;
 	int rc;
-	ENTRY;
 
 	if (lcfg->lcfg_bufcount < 2 || LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) {
 		CERROR("requires a TARGET OBD name\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	tgt = class_name2obd(lustre_cfg_string(lcfg, 1));
 	if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
 		CERROR("device not attached or not set up (%s)\n",
 		       lustre_cfg_string(lcfg, 1));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	spin_lock_init(&ec->ec_lock);
@@ -3027,7 +2977,7 @@
 	if (!strcmp(tgt->obd_type->typ_name, LUSTRE_MDT_NAME)) {
 		lu_context_tags_update(ECHO_MD_CTX_TAG);
 		lu_session_tags_update(ECHO_MD_SES_TAG);
-		RETURN(0);
+		return 0;
 	}
 
 	OBD_ALLOC(ocd, sizeof(*ocd));
@@ -3062,7 +3012,7 @@
 		return (rc);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static int echo_client_cleanup(struct obd_device *obddev)
@@ -3070,21 +3020,20 @@
 	struct echo_device *ed = obd2echo_dev(obddev);
 	struct echo_client_obd *ec = &obddev->u.echo_client;
 	int rc;
-	ENTRY;
 
 	/*Do nothing for Metadata echo client*/
 	if (ed == NULL )
-		RETURN(0);
+		return 0;
 
 	if (ed->ed_next_ismd) {
 		lu_context_tags_clear(ECHO_MD_CTX_TAG);
 		lu_session_tags_clear(ECHO_MD_SES_TAG);
-		RETURN(0);
+		return 0;
 	}
 
 	if (!list_empty(&obddev->obd_exports)) {
 		CERROR("still has clients!\n");
-		RETURN(-EBUSY);
+		return -EBUSY;
 	}
 
 	LASSERT(atomic_read(&ec->ec_exp->exp_refcount) > 0);
@@ -3092,7 +3041,7 @@
 	if (rc != 0)
 		CERROR("fail to disconnect device: %d\n", rc);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int echo_client_connect(const struct lu_env *env,
@@ -3103,13 +3052,12 @@
 	int		rc;
 	struct lustre_handle conn = { 0 };
 
-	ENTRY;
 	rc = class_connect(&conn, src, cluuid);
 	if (rc == 0) {
 		*exp = class_conn2export(&conn);
 	}
 
-	RETURN (rc);
+	return rc;
 }
 
 static int echo_client_disconnect(struct obd_export *exp)
@@ -3120,7 +3068,6 @@
 	struct ec_lock	 *ecl;
 #endif
 	int		     rc;
-	ENTRY;
 
 	if (exp == NULL)
 		GOTO(out, rc = -EINVAL);
@@ -3195,7 +3142,6 @@
 	struct lprocfs_static_vars lvars;
 	int rc;
 
-	ENTRY;
 	LCONSOLE_INFO("Echo OBD driver; http://www.lustre.org/\n");
 
 	LASSERT(PAGE_CACHE_SIZE % OBD_ECHO_BLOCK_SIZE == 0);
@@ -3205,7 +3151,7 @@
 
 	rc = echo_client_init();
 
-	RETURN(rc);
+	return rc;
 }
 
 static void /*__exit*/ obdecho_exit(void)
@@ -3217,7 +3163,9 @@
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Lustre Testing Echo OBD driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
 
-cfs_module(obdecho, LUSTRE_VERSION_STRING, obdecho_init, obdecho_exit);
+module_init(obdecho_init);
+module_exit(obdecho_exit);
 
 /** @} echo_client */
diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c
index 198cf3b..90d24d8 100644
--- a/drivers/staging/lustre/lustre/osc/lproc_osc.c
+++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c
@@ -35,7 +35,6 @@
  */
 #define DEBUG_SUBSYSTEM S_CLASS
 
-#include <linux/version.h>
 #include <asm/statfs.h>
 #include <obd_cksum.h>
 #include <obd_class.h>
@@ -146,7 +145,7 @@
 
 	if (pages_number <= 0 ||
 	    pages_number > OSC_MAX_DIRTY_MB_MAX << (20 - PAGE_CACHE_SHIFT) ||
-	    pages_number > num_physpages / 4) /* 1/4 of RAM */
+	    pages_number > totalram_pages / 4) /* 1/4 of RAM */
 		return -ERANGE;
 
 	client_obd_list_lock(&cli->cl_loi_list_lock);
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index 0a0ec6f..00295da 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -540,7 +540,6 @@
 {
 	struct osc_object *obj = ext->oe_obj;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(atomic_read(&ext->oe_users) > 0);
 	LASSERT(sanity_check(ext) == 0);
@@ -572,7 +571,7 @@
 		osc_io_unplug_async(env, osc_cli(obj), obj);
 	}
 	osc_extent_put(env, ext);
-	RETURN(rc);
+	return rc;
 }
 
 static inline int overlapped(struct osc_extent *ex1, struct osc_extent *ex2)
@@ -602,11 +601,10 @@
 	int	ppc_bits; /* pages per chunk bits */
 	int	chunk_mask;
 	int	rc;
-	ENTRY;
 
 	cur = osc_extent_alloc(obj);
 	if (cur == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	lock = cl_lock_at_pgoff(env, osc2cl(obj), index, NULL, 1, 0);
 	LASSERT(lock != NULL);
@@ -783,7 +781,6 @@
 
 		goto restart;
 	}
-	EXIT;
 
 out:
 	osc_extent_put(env, cur);
@@ -805,7 +802,6 @@
 	int blocksize = cli->cl_import->imp_obd->obd_osfs.os_bsize ? : 4096;
 	__u64 last_off = 0;
 	int last_count = -1;
-	ENTRY;
 
 	OSC_EXTENT_DUMP(D_CACHE, ext, "extent finished.\n");
 
@@ -846,7 +842,7 @@
 	osc_extent_remove(ext);
 	/* put the refcount for RPC */
 	osc_extent_put(env, ext);
-	RETURN(0);
+	return 0;
 }
 
 static int extent_wait_cb(struct osc_extent *ext, int state)
@@ -870,7 +866,6 @@
 	struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(600), NULL,
 						  LWI_ON_SIGNAL_NOOP, NULL);
 	int rc = 0;
-	ENTRY;
 
 	osc_object_lock(obj);
 	LASSERT(sanity_check_nolock(ext) == 0);
@@ -902,7 +897,7 @@
 	}
 	if (rc == 0 && ext->oe_rc < 0)
 		rc = ext->oe_rc;
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -925,7 +920,6 @@
 	int		    grants   = 0;
 	int		    nr_pages = 0;
 	int		    rc       = 0;
-	ENTRY;
 
 	LASSERT(sanity_check(ext) == 0);
 	LASSERT(ext->oe_state == OES_TRUNC);
@@ -1021,7 +1015,7 @@
 out:
 	cl_io_fini(env, io);
 	cl_env_nested_put(&nest, env);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1036,7 +1030,6 @@
 	struct osc_object *obj = ext->oe_obj;
 	int page_count = 0;
 	int rc;
-	ENTRY;
 
 	/* we're going to grab page lock, so object lock must not be taken. */
 	LASSERT(sanity_check(ext) == 0);
@@ -1096,7 +1089,7 @@
 	/* get a refcount for RPC. */
 	osc_extent_get(ext);
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1115,7 +1108,6 @@
 	pgoff_t end_index;
 	int chunksize = 1 << cli->cl_chunkbits;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(ext->oe_max_end >= index && ext->oe_start <= index);
 	osc_object_lock(obj);
@@ -1143,11 +1135,10 @@
 	LASSERT(*grants >= 0);
 	EASSERTF(osc_extent_is_overlapped(obj, ext) == 0, ext,
 		 "overlapped after expanding for %lu.\n", index);
-	EXIT;
 
 out:
 	osc_object_unlock(obj);
-	RETURN(rc);
+	return rc;
 }
 
 static void osc_extent_tree_dump0(int level, struct osc_object *obj,
@@ -1207,11 +1198,10 @@
 
 	LASSERT(cmd == OBD_BRW_WRITE); /* no cached reads */
 
-	ENTRY;
 	result = cl_page_make_ready(env, page, CRT_WRITE);
 	if (result == 0)
 		opg->ops_submit_time = cfs_time_current();
-	RETURN(result);
+	return result;
 }
 
 static int osc_refresh_count(const struct lu_env *env,
@@ -1255,8 +1245,6 @@
 	enum cl_req_type   crt;
 	int srvlock;
 
-	ENTRY;
-
 	cmd &= ~OBD_BRW_NOQUOTA;
 	LASSERT(equi(page->cp_state == CPS_PAGEIN,  cmd == OBD_BRW_READ));
 	LASSERT(equi(page->cp_state == CPS_PAGEOUT, cmd == OBD_BRW_WRITE));
@@ -1305,7 +1293,7 @@
 
 	cl_page_completion(env, page, crt, rc);
 
-	RETURN(0);
+	return 0;
 }
 
 #define OSC_DUMP_GRANT(cli, fmt, args...) do {				      \
@@ -1338,11 +1326,8 @@
 static void osc_release_write_grant(struct client_obd *cli,
 				    struct brw_page *pga)
 {
-	ENTRY;
-
 	LASSERT(spin_is_locked(&cli->cl_loi_list_lock.lock));
 	if (!(pga->flag & OBD_BRW_FROM_GRANT)) {
-		EXIT;
 		return;
 	}
 
@@ -1354,7 +1339,6 @@
 		atomic_dec(&obd_dirty_transit_pages);
 		cli->cl_dirty_transit -= PAGE_CACHE_SIZE;
 	}
-	EXIT;
 }
 
 /**
@@ -1503,7 +1487,6 @@
 	struct osc_cache_waiter ocw;
 	struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 	int rc = -EDQUOT;
-	ENTRY;
 
 	OSC_DUMP_GRANT(cli, "need:%d.\n", bytes);
 
@@ -1557,11 +1540,10 @@
 		if (osc_enter_cache_try(cli, oap, bytes, 0))
 			GOTO(out, rc = 0);
 	}
-	EXIT;
 out:
 	client_obd_list_unlock(&cli->cl_loi_list_lock);
 	OSC_DUMP_GRANT(cli, "returned %d.\n", rc);
-	RETURN(rc);
+	return rc;
 }
 
 /* caller must hold loi_list_lock */
@@ -1570,7 +1552,6 @@
 	struct list_head *l, *tmp;
 	struct osc_cache_waiter *ocw;
 
-	ENTRY;
 	list_for_each_safe(l, tmp, &cli->cl_cache_waiters) {
 		ocw = list_entry(l, struct osc_cache_waiter, ocw_entry);
 		list_del_init(&ocw->ocw_entry);
@@ -1596,8 +1577,6 @@
 
 		wake_up(&ocw->ocw_waitq);
 	}
-
-	EXIT;
 }
 
 static int osc_max_rpc_in_flight(struct client_obd *cli, struct osc_object *osc)
@@ -1613,7 +1592,6 @@
 			 int cmd)
 {
 	int invalid_import = 0;
-	ENTRY;
 
 	/* if we have an invalid import we want to drain the queued pages
 	 * by forcing them through rpcs that immediately fail and complete
@@ -1624,42 +1602,42 @@
 
 	if (cmd & OBD_BRW_WRITE) {
 		if (atomic_read(&osc->oo_nr_writes) == 0)
-			RETURN(0);
+			return 0;
 		if (invalid_import) {
 			CDEBUG(D_CACHE, "invalid import forcing RPC\n");
-			RETURN(1);
+			return 1;
 		}
 		if (!list_empty(&osc->oo_hp_exts)) {
 			CDEBUG(D_CACHE, "high prio request forcing RPC\n");
-			RETURN(1);
+			return 1;
 		}
 		if (!list_empty(&osc->oo_urgent_exts)) {
 			CDEBUG(D_CACHE, "urgent request forcing RPC\n");
-			RETURN(1);
+			return 1;
 		}
 		/* trigger a write rpc stream as long as there are dirtiers
 		 * waiting for space.  as they're waiting, they're not going to
 		 * create more pages to coalesce with what's waiting.. */
 		if (!list_empty(&cli->cl_cache_waiters)) {
 			CDEBUG(D_CACHE, "cache waiters forcing RPC\n");
-			RETURN(1);
+			return 1;
 		}
 		if (atomic_read(&osc->oo_nr_writes) >=
 		    cli->cl_max_pages_per_rpc)
-			RETURN(1);
+			return 1;
 	} else {
 		if (atomic_read(&osc->oo_nr_reads) == 0)
-			RETURN(0);
+			return 0;
 		if (invalid_import) {
 			CDEBUG(D_CACHE, "invalid import forcing RPC\n");
-			RETURN(1);
+			return 1;
 		}
 		/* all read are urgent. */
 		if (!list_empty(&osc->oo_reading_exts))
-			RETURN(1);
+			return 1;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static void osc_update_pending(struct osc_object *obj, int cmd, int delta)
@@ -1757,7 +1735,6 @@
 	struct lov_oinfo  *loi = osc->oo_oinfo;
 	__u64 xid = 0;
 
-	ENTRY;
 	if (oap->oap_request != NULL) {
 		xid = ptlrpc_req_xid(oap->oap_request);
 		ptlrpc_req_finished(oap->oap_request);
@@ -1781,8 +1758,6 @@
 	if (rc)
 		CERROR("completion on oap %p obj %p returns %d.\n",
 		       oap, osc, rc);
-
-	EXIT;
 }
 
 /**
@@ -1795,14 +1770,13 @@
 				    int *pc, unsigned int *max_pages)
 {
 	struct osc_extent *tmp;
-	ENTRY;
 
 	EASSERT((ext->oe_state == OES_CACHE || ext->oe_state == OES_LOCK_DONE),
 		ext);
 
 	*max_pages = max(ext->oe_mppr, *max_pages);
 	if (*pc + ext->oe_nr_pages > *max_pages)
-		RETURN(0);
+		return 0;
 
 	list_for_each_entry(tmp, rpclist, oe_link) {
 		EASSERT(tmp->oe_owner == current, tmp);
@@ -1815,7 +1789,7 @@
 
 		if (tmp->oe_srvlock != ext->oe_srvlock ||
 		    !tmp->oe_grants != !ext->oe_grants)
-			RETURN(0);
+			return 0;
 
 		/* remove break for strict check */
 		break;
@@ -1824,7 +1798,7 @@
 	*pc += ext->oe_nr_pages;
 	list_move_tail(&ext->oe_link, rpclist);
 	ext->oe_owner = current;
-	RETURN(1);
+	return 1;
 }
 
 /**
@@ -1913,7 +1887,6 @@
 	obd_count page_count = 0;
 	int srvlock = 0;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(osc_object_is_locked(osc));
 
@@ -1921,7 +1894,7 @@
 	LASSERT(equi(page_count == 0, list_empty(&rpclist)));
 
 	if (list_empty(&rpclist))
-		RETURN(0);
+		return 0;
 
 	osc_update_pending(osc, OBD_BRW_WRITE, -page_count);
 
@@ -1962,7 +1935,7 @@
 	}
 
 	osc_object_lock(osc);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1985,7 +1958,6 @@
 	int page_count = 0;
 	unsigned int max_pages = cli->cl_max_pages_per_rpc;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(osc_object_is_locked(osc));
 	list_for_each_entry_safe(ext, next,
@@ -2010,7 +1982,7 @@
 
 		osc_object_lock(osc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 #define list_to_obj(list, item) ({					      \
@@ -2023,15 +1995,13 @@
  * we could be sending.  These lists are maintained by osc_makes_rpc(). */
 static struct osc_object *osc_next_obj(struct client_obd *cli)
 {
-	ENTRY;
-
 	/* First return objects that have blocked locks so that they
 	 * will be flushed quickly and other clients can get the lock,
 	 * then objects which have pages ready to be stuffed into RPCs */
 	if (!list_empty(&cli->cl_loi_hp_ready_list))
-		RETURN(list_to_obj(&cli->cl_loi_hp_ready_list, hp_ready_item));
+		return list_to_obj(&cli->cl_loi_hp_ready_list, hp_ready_item);
 	if (!list_empty(&cli->cl_loi_ready_list))
-		RETURN(list_to_obj(&cli->cl_loi_ready_list, ready_item));
+		return list_to_obj(&cli->cl_loi_ready_list, ready_item);
 
 	/* then if we have cache waiters, return all objects with queued
 	 * writes.  This is especially important when many small files
@@ -2039,19 +2009,17 @@
 	 * they don't pass the nr_pending/object threshhold */
 	if (!list_empty(&cli->cl_cache_waiters) &&
 	    !list_empty(&cli->cl_loi_write_list))
-		RETURN(list_to_obj(&cli->cl_loi_write_list, write_item));
+		return list_to_obj(&cli->cl_loi_write_list, write_item);
 
 	/* then return all queued objects when we have an invalid import
 	 * so that they get flushed */
 	if (cli->cl_import == NULL || cli->cl_import->imp_invalid) {
 		if (!list_empty(&cli->cl_loi_write_list))
-			RETURN(list_to_obj(&cli->cl_loi_write_list,
-					   write_item));
+			return list_to_obj(&cli->cl_loi_write_list, write_item);
 		if (!list_empty(&cli->cl_loi_read_list))
-			RETURN(list_to_obj(&cli->cl_loi_read_list,
-					   read_item));
+			return list_to_obj(&cli->cl_loi_read_list, read_item);
 	}
-	RETURN(NULL);
+	return NULL;
 }
 
 /* called with the loi list lock held */
@@ -2060,11 +2028,10 @@
 {
 	struct osc_object *osc;
 	int rc = 0;
-	ENTRY;
 
 	while ((osc = osc_next_obj(cli)) != NULL) {
 		struct cl_object *obj = osc2cl(osc);
-		struct lu_ref_link *link;
+		struct lu_ref_link link;
 
 		OSC_IO_DEBUG(osc, "%lu in flight\n", rpcs_in_flight(cli));
 
@@ -2075,7 +2042,8 @@
 
 		cl_object_get(obj);
 		client_obd_list_unlock(&cli->cl_loi_list_lock);
-		link = lu_object_ref_add(&obj->co_lu, "check", current);
+		lu_object_ref_add_at(&obj->co_lu, &link, "check",
+				     current);
 
 		/* attempt some read/write balancing by alternating between
 		 * reads and writes in an object.  The makes_rpc checks here
@@ -2116,7 +2084,8 @@
 		osc_object_unlock(osc);
 
 		osc_list_maint(cli, osc);
-		lu_object_ref_del_at(&obj->co_lu, link, "check", current);
+		lu_object_ref_del_at(&obj->co_lu, &link, "check",
+				     current);
 		cl_object_put(env, obj);
 
 		client_obd_list_lock(&cli->cl_loi_list_lock);
@@ -2165,7 +2134,6 @@
 {
 	struct obd_export     *exp = osc_export(osc);
 	struct osc_async_page *oap = &ops->ops_oap;
-	ENTRY;
 
 	if (!page)
 		return cfs_size_round(sizeof(*oap));
@@ -2187,7 +2155,7 @@
 	spin_lock_init(&oap->oap_lock);
 	CDEBUG(D_INFO, "oap %p page %p obj off "LPU64"\n",
 	       oap, page, oap->oap_obj_off);
-	RETURN(0);
+	return 0;
 }
 
 int osc_queue_async_io(const struct lu_env *env, struct cl_io *io,
@@ -2204,17 +2172,16 @@
 	int    cmd = OBD_BRW_WRITE;
 	int    need_release = 0;
 	int    rc = 0;
-	ENTRY;
 
 	if (oap->oap_magic != OAP_MAGIC)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if (cli->cl_import == NULL || cli->cl_import->imp_invalid)
-		RETURN(-EIO);
+		return -EIO;
 
 	if (!list_empty(&oap->oap_pending_item) ||
 	    !list_empty(&oap->oap_rpc_item))
-		RETURN(-EBUSY);
+		return -EBUSY;
 
 	/* Set the OBD_BRW_SRVLOCK before the page is queued. */
 	brw_flags |= ops->ops_srvlock ? OBD_BRW_SRVLOCK : 0;
@@ -2242,7 +2209,7 @@
 		if (rc == 0 && osc_quota_chkdq(cli, qid) == NO_QUOTA)
 			rc = -EDQUOT;
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
 	oap->oap_cmd = cmd;
@@ -2350,7 +2317,7 @@
 		list_add_tail(&oap->oap_pending_item, &ext->oe_pages);
 		osc_object_unlock(osc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int osc_teardown_async_page(const struct lu_env *env,
@@ -2359,7 +2326,6 @@
 	struct osc_async_page *oap = &ops->ops_oap;
 	struct osc_extent     *ext = NULL;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(oap->oap_magic == OAP_MAGIC);
 
@@ -2384,7 +2350,7 @@
 	osc_object_unlock(obj);
 	if (ext != NULL)
 		osc_extent_put(env, ext);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2404,7 +2370,6 @@
 	struct osc_async_page *oap = &ops->ops_oap;
 	bool unplug = false;
 	int rc = 0;
-	ENTRY;
 
 	osc_object_lock(obj);
 	ext = osc_extent_lookup(obj, index);
@@ -2454,7 +2419,6 @@
 		unplug = true;
 	}
 	rc = 0;
-	EXIT;
 
 out:
 	osc_object_unlock(obj);
@@ -2482,7 +2446,6 @@
 	pgoff_t index = oap2cl_page(oap)->cp_index;
 	int     rc = -EBUSY;
 	int     cmd;
-	ENTRY;
 
 	LASSERT(!oap->oap_interrupted);
 	oap->oap_interrupted = 1;
@@ -2526,7 +2489,7 @@
 	}
 
 	osc_list_maint(cli, obj);
-	RETURN(rc);
+	return rc;
 }
 
 int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj,
@@ -2539,7 +2502,6 @@
 	int     mppr       = cli->cl_max_pages_per_rpc;
 	pgoff_t start      = CL_PAGE_EOF;
 	pgoff_t end	= 0;
-	ENTRY;
 
 	list_for_each_entry(oap, list, oap_pending_item) {
 		struct cl_page *cp = oap2cl_page(oap);
@@ -2557,7 +2519,7 @@
 			list_del_init(&oap->oap_pending_item);
 			osc_ap_completion(env, cli, oap, 0, -ENOMEM);
 		}
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	ext->oe_rw = !!(cmd & OBD_BRW_READ);
@@ -2583,7 +2545,7 @@
 	osc_object_unlock(obj);
 
 	osc_io_unplug(env, cli, obj, PDL_POLICY_ROUND);
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -2599,7 +2561,6 @@
 	LIST_HEAD(list);
 	int result = 0;
 	bool partial;
-	ENTRY;
 
 	/* pages with index greater or equal to index will be truncated. */
 	index = cl_index(osc2cl(obj), size);
@@ -2705,7 +2666,7 @@
 		waiting = NULL;
 		goto again;
 	}
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -2756,7 +2717,6 @@
 	struct osc_extent *ext;
 	pgoff_t index = start;
 	int     result = 0;
-	ENTRY;
 
 again:
 	osc_object_lock(obj);
@@ -2794,7 +2754,7 @@
 	osc_object_unlock(obj);
 
 	OSC_IO_DEBUG(obj, "sync file range.\n");
-	RETURN(result);
+	return result;
 }
 
 /**
@@ -2813,7 +2773,6 @@
 	LIST_HEAD(discard_list);
 	bool unplug = false;
 	int result = 0;
-	ENTRY;
 
 	osc_object_lock(obj);
 	ext = osc_extent_search(obj, start);
@@ -2910,7 +2869,7 @@
 	}
 
 	OSC_IO_DEBUG(obj, "cache page out.\n");
-	RETURN(result);
+	return result;
 }
 
 /** @} osc */
diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
index 158e8ff..a3aa9b6 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
+++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h
@@ -374,7 +374,7 @@
 	/**
 	 * Thread that submitted this page for transfer. For debugging.
 	 */
-	task_t	   *ops_submitter;
+	struct task_struct	*ops_submitter;
 	/**
 	 * Submit time - the time when the page is starting RPC. For debugging.
 	 */
@@ -660,7 +660,7 @@
 	/** lock covering this extent */
 	struct cl_lock    *oe_osclock;
 	/** terminator of this extent. Must be true if this extent is in IO. */
-	task_t	*oe_owner;
+	struct task_struct	*oe_owner;
 	/** return value of writeback. If somebody is waiting for this extent,
 	 * this value can be known by outside world. */
 	int		oe_rc;
diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c
index 4208ddf..35f2578 100644
--- a/drivers/staging/lustre/lustre/osc/osc_dev.c
+++ b/drivers/staging/lustre/lustre/osc/osc_dev.c
@@ -171,8 +171,7 @@
 static int osc_cl_process_config(const struct lu_env *env,
 				 struct lu_device *d, struct lustre_cfg *cfg)
 {
-	ENTRY;
-	RETURN(osc_process_config_base(d->ld_obd, cfg));
+	return osc_process_config_base(d->ld_obd, cfg);
 }
 
 static const struct lu_device_operations osc_lu_ops = {
@@ -188,7 +187,7 @@
 static int osc_device_init(const struct lu_env *env, struct lu_device *d,
 			   const char *name, struct lu_device *next)
 {
-	RETURN(0);
+	return 0;
 }
 
 static struct lu_device *osc_device_fini(const struct lu_env *env,
@@ -218,7 +217,7 @@
 
 	OBD_ALLOC_PTR(od);
 	if (od == NULL)
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 
 	cl_device_init(&od->od_cl, t);
 	d = osc2lu_dev(od);
@@ -231,10 +230,10 @@
 	rc = osc_setup(obd, cfg);
 	if (rc) {
 		osc_device_free(env, d);
-		RETURN(ERR_PTR(rc));
+		return ERR_PTR(rc);
 	}
 	od->od_exp = obd->obd_self_export;
-	RETURN(d);
+	return d;
 }
 
 static const struct lu_device_type_operations osc_device_type_ops = {
diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c
index 1b27704..3aeaf84 100644
--- a/drivers/staging/lustre/lustre/osc/osc_io.c
+++ b/drivers/staging/lustre/lustre/osc/osc_io.c
@@ -261,7 +261,6 @@
 	struct obd_import *imp = class_exp2cliimp(dev->od_exp);
 	struct osc_io     *oio = cl2osc_io(env, ios);
 	int result = 0;
-	ENTRY;
 
 	/*
 	 * This implements OBD_BRW_CHECK logic from old client.
@@ -276,7 +275,7 @@
 		 * [from, to) bytes of this page to OST. -jay */
 		cl_page_export(env, slice->cpl_page, 1);
 
-	RETURN(result);
+	return result;
 }
 
 static int osc_io_commit_write(const struct lu_env *env,
@@ -288,7 +287,6 @@
 	struct osc_page       *opg = cl2osc_page(slice);
 	struct osc_object     *obj = cl2osc(opg->ops_cl.cpl_obj);
 	struct osc_async_page *oap = &opg->ops_oap;
-	ENTRY;
 
 	LASSERT(to > 0);
 	/*
@@ -306,7 +304,7 @@
 		/* see osc_io_prepare_write() for lockless io handling. */
 		cl_page_clip(env, slice->cpl_page, from, to);
 
-	RETURN(0);
+	return 0;
 }
 
 static int osc_io_fault_start(const struct lu_env *env,
@@ -315,8 +313,6 @@
 	struct cl_io       *io;
 	struct cl_fault_io *fio;
 
-	ENTRY;
-
 	io  = ios->cis_io;
 	fio = &io->u.ci_fault;
 	CDEBUG(D_INFO, "%lu %d %d\n",
@@ -329,7 +325,7 @@
 	if (fio->ft_writable)
 		osc_page_touch_at(env, ios->cis_obj,
 				  fio->ft_index, fio->ft_nob);
-	RETURN(0);
+	return 0;
 }
 
 static int osc_async_upcall(void *a, int rc)
@@ -517,19 +513,18 @@
 	struct cl_object *obj   = slice->cis_obj;
 	struct cl_attr   *attr  = &osc_env_info(env)->oti_attr;
 	int	      result = 0;
-	ENTRY;
 
 	if (oio->oi_lockless == 0) {
 		cl_object_attr_lock(obj);
 		result = cl_object_attr_get(env, obj, attr);
 		if (result == 0) {
-			attr->cat_atime = LTIME_S(CFS_CURRENT_TIME);
+			attr->cat_atime = LTIME_S(CURRENT_TIME);
 			result = cl_object_attr_set(env, obj, attr,
 						    CAT_ATIME);
 		}
 		cl_object_attr_unlock(obj);
 	}
-	RETURN(result);
+	return result;
 }
 
 static int osc_io_write_start(const struct lu_env *env,
@@ -539,7 +534,6 @@
 	struct cl_object *obj   = slice->cis_obj;
 	struct cl_attr   *attr  = &osc_env_info(env)->oti_attr;
 	int	      result = 0;
-	ENTRY;
 
 	if (oio->oi_lockless == 0) {
 		OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_DELAY_SETTIME, 1);
@@ -547,13 +541,13 @@
 		result = cl_object_attr_get(env, obj, attr);
 		if (result == 0) {
 			attr->cat_mtime = attr->cat_ctime =
-				LTIME_S(CFS_CURRENT_TIME);
+				LTIME_S(CURRENT_TIME);
 			result = cl_object_attr_set(env, obj, attr,
 						    CAT_MTIME | CAT_CTIME);
 		}
 		cl_object_attr_unlock(obj);
 	}
-	RETURN(result);
+	return result;
 }
 
 static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj,
@@ -565,7 +559,6 @@
 	struct lov_oinfo *loi   = obj->oo_oinfo;
 	struct osc_async_cbargs *cbargs = &oio->oi_cbarg;
 	int rc = 0;
-	ENTRY;
 
 	memset(oa, 0, sizeof(*oa));
 	oa->o_oi = loi->loi_oi;
@@ -585,7 +578,7 @@
 
 	rc = osc_sync_base(osc_export(obj), oinfo, osc_async_upcall, cbargs,
 			   PTLRPCD_SET);
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_io_fsync_start(const struct lu_env *env,
@@ -598,7 +591,6 @@
 	pgoff_t start  = cl_index(obj, fio->fi_start);
 	pgoff_t end    = cl_index(obj, fio->fi_end);
 	int     result = 0;
-	ENTRY;
 
 	if (fio->fi_end == OBD_OBJECT_EOF)
 		end = CL_PAGE_EOF;
@@ -625,7 +617,7 @@
 			result = rc;
 	}
 
-	RETURN(result);
+	return result;
 }
 
 static void osc_io_fsync_end(const struct lu_env *env,
@@ -785,7 +777,7 @@
 					      "no cover page!\n");
 			CL_PAGE_DEBUG(D_ERROR, env, apage,
 				      "dump uncover page!\n");
-			libcfs_debug_dumpstack(NULL);
+			dump_stack();
 			LBUG();
 		}
 
diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c
index 640bc3d..5d7bdbf 100644
--- a/drivers/staging/lustre/lustre/osc/osc_lock.c
+++ b/drivers/staging/lustre/lustre/osc/osc_lock.c
@@ -89,35 +89,49 @@
  */
 static int osc_lock_invariant(struct osc_lock *ols)
 {
-	struct ldlm_lock *lock	= osc_handle_ptr(&ols->ols_handle);
-	struct ldlm_lock *olock       = ols->ols_lock;
-	int	       handle_used = lustre_handle_is_used(&ols->ols_handle);
+	struct ldlm_lock *lock	      = osc_handle_ptr(&ols->ols_handle);
+	struct ldlm_lock *olock	      = ols->ols_lock;
+	int		  handle_used = lustre_handle_is_used(&ols->ols_handle);
 
-	return
-		ergo(osc_lock_is_lockless(ols),
-		     ols->ols_locklessable && ols->ols_lock == NULL)  ||
-		(ergo(olock != NULL, handle_used) &&
-		 ergo(olock != NULL,
-		      olock->l_handle.h_cookie == ols->ols_handle.cookie) &&
-		 /*
-		  * Check that ->ols_handle and ->ols_lock are consistent, but
-		  * take into account that they are set at the different time.
-		  */
-		 ergo(handle_used,
-		      ergo(lock != NULL && olock != NULL, lock == olock) &&
-		      ergo(lock == NULL, olock == NULL)) &&
-		 ergo(ols->ols_state == OLS_CANCELLED,
-		      olock == NULL && !handle_used) &&
-		 /*
-		  * DLM lock is destroyed only after we have seen cancellation
-		  * ast.
-		  */
-		 ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
-		      !olock->l_destroyed) &&
-		 ergo(ols->ols_state == OLS_GRANTED,
-		      olock != NULL &&
-		      olock->l_req_mode == olock->l_granted_mode &&
-		      ols->ols_hold));
+	if (ergo(osc_lock_is_lockless(ols),
+		 ols->ols_locklessable && ols->ols_lock == NULL))
+		return 1;
+
+	/*
+	 * If all the following "ergo"s are true, return 1, otherwise 0
+	 */
+	if (! ergo(olock != NULL, handle_used))
+		return 0;
+
+	if (! ergo(olock != NULL,
+		   olock->l_handle.h_cookie == ols->ols_handle.cookie))
+		return 0;
+
+	if (! ergo(handle_used,
+		   ergo(lock != NULL && olock != NULL, lock == olock) &&
+		   ergo(lock == NULL, olock == NULL)))
+		return 0;
+	/*
+	 * Check that ->ols_handle and ->ols_lock are consistent, but
+	 * take into account that they are set at the different time.
+	 */
+	if (! ergo(ols->ols_state == OLS_CANCELLED,
+		   olock == NULL && !handle_used))
+		return 0;
+	/*
+	 * DLM lock is destroyed only after we have seen cancellation
+	 * ast.
+	 */
+	if (! ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
+		   ((olock->l_flags & LDLM_FL_DESTROYED) == 0)))
+		return 0;
+
+	if (! ergo(ols->ols_state == OLS_GRANTED,
+		   olock != NULL &&
+		   olock->l_req_mode == olock->l_granted_mode &&
+		   ols->ols_hold))
+		return 0;
+	return 1;
 }
 
 /*****************************************************************************
@@ -261,7 +275,7 @@
 	if (enqflags & CEF_ASYNC)
 		result |= LDLM_FL_HAS_INTENT;
 	if (enqflags & CEF_DISCARD_DATA)
-		result |= LDLM_AST_DISCARD_DATA;
+		result |= LDLM_FL_AST_DISCARD_DATA;
 	return result;
 }
 
@@ -329,10 +343,8 @@
 	struct cl_attr    *attr;
 	unsigned	   valid;
 
-	ENTRY;
-
 	if (!(olck->ols_flags & LDLM_FL_LVB_READY))
-		RETURN_EXIT;
+		return;
 
 	lvb   = &olck->ols_lvb;
 	obj   = olck->ols_cl.cls_obj;
@@ -378,8 +390,6 @@
 		cl_object_attr_set(env, obj, attr, valid);
 
 	cl_object_attr_unlock(obj);
-
-	EXIT;
 }
 
 /**
@@ -398,7 +408,6 @@
 
 	LASSERT(dlmlock->l_granted_mode == dlmlock->l_req_mode);
 
-	ENTRY;
 	if (olck->ols_state < OLS_GRANTED) {
 		lock  = olck->ols_cl.cls_lock;
 		ext   = &dlmlock->l_policy_data.l_extent;
@@ -428,7 +437,6 @@
 		LINVRNT(osc_lock_invariant(olck));
 		lock_res_and_lock(dlmlock);
 	}
-	EXIT;
 }
 
 static void osc_lock_upcall0(const struct lu_env *env, struct osc_lock *olck)
@@ -436,8 +444,6 @@
 {
 	struct ldlm_lock *dlmlock;
 
-	ENTRY;
-
 	dlmlock = ldlm_handle2lock_long(&olck->ols_handle, 0);
 	LASSERT(dlmlock != NULL);
 
@@ -483,7 +489,6 @@
 	struct lu_env	   *env;
 	struct cl_env_nest       nest;
 
-	ENTRY;
 	env = cl_env_nested_get(&nest);
 	if (!IS_ERR(env)) {
 		int rc;
@@ -575,7 +580,7 @@
 		/* should never happen, similar to osc_ldlm_blocking_ast(). */
 		LBUG();
 	}
-	RETURN(errcode);
+	return errcode;
 }
 
 /**
@@ -896,55 +901,6 @@
 	return cl_object_header(slice->cls_obj)->coh_pages;
 }
 
-/**
- * Get the weight of dlm lock for early cancellation.
- *
- * XXX: it should return the pages covered by this \a dlmlock.
- */
-static unsigned long osc_ldlm_weigh_ast(struct ldlm_lock *dlmlock)
-{
-	struct cl_env_nest       nest;
-	struct lu_env	   *env;
-	struct osc_lock	 *lock;
-	struct cl_lock	  *cll;
-	unsigned long	    weight;
-	ENTRY;
-
-	might_sleep();
-	/*
-	 * osc_ldlm_weigh_ast has a complex context since it might be called
-	 * because of lock canceling, or from user's input. We have to make
-	 * a new environment for it. Probably it is implementation safe to use
-	 * the upper context because cl_lock_put don't modify environment
-	 * variables. But in case of ..
-	 */
-	env = cl_env_nested_get(&nest);
-	if (IS_ERR(env))
-		/* Mostly because lack of memory, tend to eliminate this lock*/
-		RETURN(0);
-
-	LASSERT(dlmlock->l_resource->lr_type == LDLM_EXTENT);
-	lock = osc_ast_data_get(dlmlock);
-	if (lock == NULL) {
-		/* cl_lock was destroyed because of memory pressure.
-		 * It is much reasonable to assign this type of lock
-		 * a lower cost.
-		 */
-		GOTO(out, weight = 0);
-	}
-
-	cll = lock->ols_cl.cls_lock;
-	cl_lock_mutex_get(env, cll);
-	weight = cl_lock_weigh(env, cll);
-	cl_lock_mutex_put(env, cll);
-	osc_ast_data_put(env, lock);
-	EXIT;
-
-out:
-	cl_env_nested_put(&nest, env);
-	return weight;
-}
-
 static void osc_lock_build_einfo(const struct lu_env *env,
 				 const struct cl_lock *clock,
 				 struct osc_lock *lock,
@@ -966,7 +922,6 @@
 	einfo->ei_cb_bl  = osc_ldlm_blocking_ast;
 	einfo->ei_cb_cp  = osc_ldlm_completion_ast;
 	einfo->ei_cb_gl  = osc_ldlm_glimpse_ast;
-	einfo->ei_cb_wg  = osc_ldlm_weigh_ast;
 	einfo->ei_cbdata = lock; /* value to be put into ->l_ast_data */
 }
 
@@ -1059,7 +1014,6 @@
 	struct cl_lock	  *conflict= NULL;
 	int lockless		     = osc_lock_is_lockless(olck);
 	int rc			   = 0;
-	ENTRY;
 
 	LASSERT(cl_lock_is_mutexed(lock));
 
@@ -1130,7 +1084,7 @@
 			rc = CLO_WAIT;
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1154,7 +1108,6 @@
 	struct osc_lock	  *ols     = cl2osc_lock(slice);
 	struct cl_lock	   *lock    = ols->ols_cl.cls_lock;
 	int result;
-	ENTRY;
 
 	LASSERT(cl_lock_is_mutexed(lock));
 	LASSERTF(ols->ols_state == OLS_NEW,
@@ -1207,7 +1160,7 @@
 		}
 	}
 	LASSERT(ergo(ols->ols_glimpse, !osc_lock_is_lockless(ols)));
-	RETURN(result);
+	return result;
 }
 
 static int osc_lock_wait(const struct lu_env *env,
@@ -1298,7 +1251,6 @@
 	struct cl_env_nest    nest;
 	struct lu_env	*env;
 	int result = 0;
-	ENTRY;
 
 	env = cl_env_nested_get(&nest);
 	if (!IS_ERR(env)) {
@@ -1328,7 +1280,7 @@
 		ols->ols_flush = 1;
 		LINVRNT(!osc_lock_has_pages(ols));
 	}
-	RETURN(result);
+	return result;
 }
 
 /**
diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c
index ca94e63..9d34de8 100644
--- a/drivers/staging/lustre/lustre/osc/osc_object.c
+++ b/drivers/staging/lustre/lustre/osc/osc_object.c
@@ -191,10 +191,9 @@
 {
 	struct lov_oinfo *oinfo = cl2osc(obj)->oo_oinfo;
 
-	ENTRY;
 	lvb->lvb_size   = oinfo->loi_kms;
 	lvb->lvb_blocks = oinfo->loi_lvb.lvb_blocks;
-	RETURN(0);
+	return 0;
 }
 
 
diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c
index baba959..d272322 100644
--- a/drivers/staging/lustre/lustre/osc/osc_page.c
+++ b/drivers/staging/lustre/lustre/osc/osc_page.c
@@ -219,7 +219,6 @@
 	struct osc_io   *oio = osc_env_io(env);
 	struct osc_page *opg = cl2osc_page(slice);
 	int result;
-	ENTRY;
 
 	LINVRNT(osc_page_protected(env, opg, CLM_WRITE, 0));
 
@@ -240,7 +239,7 @@
 		}
 	}
 
-	RETURN(result);
+	return result;
 }
 
 void osc_index2policy(ldlm_policy_data_t *policy, const struct cl_object *obj,
@@ -294,7 +293,6 @@
 	struct cl_lock *lock;
 	int	     result = -ENODATA;
 
-	ENTRY;
 	lock = cl_lock_at_page(env, slice->cpl_obj, slice->cpl_page,
 			       NULL, 1, 0);
 	if (lock != NULL) {
@@ -302,7 +300,7 @@
 			result = -EBUSY;
 		cl_lock_put(env, lock);
 	}
-	RETURN(result);
+	return result;
 }
 
 static void osc_page_disown(const struct lu_env *env,
@@ -421,7 +419,6 @@
 
 	LINVRNT(opg->ops_temp || osc_page_protected(env, opg, CLM_READ, 1));
 
-	ENTRY;
 	CDEBUG(D_TRACE, "%p\n", opg);
 	osc_page_transfer_put(env, opg);
 	rc = osc_teardown_async_page(env, obj, opg);
@@ -440,7 +437,6 @@
 	spin_unlock(&obj->oo_seatbelt);
 
 	osc_lru_del(osc_cli(obj), opg, true);
-	EXIT;
 }
 
 void osc_page_clip(const struct lu_env *env, const struct cl_page_slice *slice,
@@ -481,9 +477,9 @@
 {
 	struct osc_page *opg = cl2osc_page(slice);
 	int rc = 0;
-	ENTRY;
+
 	rc = osc_flush_async_page(env, io, opg);
-	RETURN(rc);
+	return rc;
 }
 
 static const struct cl_page_operations osc_page_ops = {
@@ -586,7 +582,7 @@
  * at any time.
  */
 
-static CFS_DECL_WAITQ(osc_lru_waitq);
+static DECLARE_WAIT_QUEUE_HEAD(osc_lru_waitq);
 static atomic_t osc_lru_waiters = ATOMIC_INIT(0);
 /* LRU pages are freed in batch mode. OSC should at least free this
  * number of pages to avoid running out of LRU budget, and.. */
@@ -666,15 +662,14 @@
 	int count = 0;
 	int index = 0;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(atomic_read(&cli->cl_lru_in_list) >= 0);
 	if (atomic_read(&cli->cl_lru_in_list) == 0 || target <= 0)
-		RETURN(0);
+		return 0;
 
 	env = cl_env_nested_get(&nest);
 	if (IS_ERR(env))
-		RETURN(PTR_ERR(env));
+		return PTR_ERR(env);
 
 	pvec = osc_env_info(env)->oti_pvec;
 	io = &osc_env_info(env)->oti_io;
@@ -757,7 +752,7 @@
 	cl_env_nested_put(&nest, env);
 
 	atomic_dec(&cli->cl_lru_shrinkers);
-	RETURN(count > 0 ? count : rc);
+	return count > 0 ? count : rc;
 }
 
 static void osc_lru_add(struct client_obd *cli, struct osc_page *opg)
@@ -881,13 +876,12 @@
 	struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
 	struct client_obd *cli = osc_cli(obj);
 	int rc = 0;
-	ENTRY;
 
 	if (cli->cl_cache == NULL) /* shall not be in LRU */
-		RETURN(0);
+		return 0;
 
 	LASSERT(atomic_read(cli->cl_lru_left) >= 0);
-	while (!cfs_atomic_add_unless(cli->cl_lru_left, -1, 0)) {
+	while (!atomic_add_unless(cli->cl_lru_left, -1, 0)) {
 		int gen;
 
 		/* run out of LRU spaces, try to drop some by itself */
@@ -921,7 +915,7 @@
 		rc = 0;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /** @} osc */
diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c
index 69caab7..9720c0e 100644
--- a/drivers/staging/lustre/lustre/osc/osc_quota.c
+++ b/drivers/staging/lustre/lustre/osc/osc_quota.c
@@ -45,7 +45,6 @@
 int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
 {
 	int type;
-	ENTRY;
 
 	for (type = 0; type < MAXQUOTAS; type++) {
 		struct osc_quota_info *oqi;
@@ -62,11 +61,11 @@
 			 * quota space on this OST */
 			CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
 			       type == USRQUOTA ? "user" : "grout", qid[type]);
-			RETURN(NO_QUOTA);
+			return NO_QUOTA;
 		}
 	}
 
-	RETURN(QUOTA_OK);
+	return QUOTA_OK;
 }
 
 #define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \
@@ -79,10 +78,9 @@
 {
 	int type;
 	int rc = 0;
-	ENTRY;
 
 	if ((valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) == 0)
-		RETURN(0);
+		return 0;
 
 	for (type = 0; type < MAXQUOTAS; type++) {
 		struct osc_quota_info *oqi;
@@ -134,7 +132,7 @@
 		}
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -211,7 +209,6 @@
 {
 	struct client_obd *cli = &obd->u.cli;
 	int i, type;
-	ENTRY;
 
 	for (type = 0; type < MAXQUOTAS; type++) {
 		cli->cl_quota_hash[type] = cfs_hash_create("QUOTA_HASH",
@@ -228,24 +225,23 @@
 	}
 
 	if (type == MAXQUOTAS)
-		RETURN(0);
+		return 0;
 
 	for (i = 0; i < type; i++)
 		cfs_hash_putref(cli->cl_quota_hash[i]);
 
-	RETURN(-ENOMEM);
+	return -ENOMEM;
 }
 
 int osc_quota_cleanup(struct obd_device *obd)
 {
 	struct client_obd     *cli = &obd->u.cli;
 	int type;
-	ENTRY;
 
 	for (type = 0; type < MAXQUOTAS; type++)
 		cfs_hash_putref(cli->cl_quota_hash[type]);
 
-	RETURN(0);
+	return 0;
 }
 
 int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
@@ -254,13 +250,12 @@
 	struct ptlrpc_request *req;
 	struct obd_quotactl   *oqc;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
 					OST_QUOTACTL);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
 	*oqc = *oqctl;
@@ -282,7 +277,7 @@
 	}
 	ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 int osc_quotacheck(struct obd_device *unused, struct obd_export *exp,
@@ -292,13 +287,12 @@
 	struct ptlrpc_request   *req;
 	struct obd_quotactl     *body;
 	int		      rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
 					&RQF_OST_QUOTACHECK, LUSTRE_OST_VERSION,
 					OST_QUOTACHECK);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	body = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
 	*body = *oqctl;
@@ -312,14 +306,13 @@
 	if (rc)
 		cli->cl_qchk_stat = rc;
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 int osc_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk)
 {
 	struct client_obd *cli = &exp->exp_obd->u.cli;
 	int rc;
-	ENTRY;
 
 	qchk->obd_uuid = cli->cl_target_uuid;
 	memcpy(qchk->obd_type, LUSTRE_OST_NAME, strlen(LUSTRE_OST_NAME));
@@ -328,5 +321,5 @@
 	/* the client is not the previous one */
 	if (rc == CL_NOT_QUOTACHECKED)
 		rc = -EINTR;
-	RETURN(rc);
+	return rc;
 }
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index 53d6a35..ee6707a 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -69,30 +69,29 @@
 		      struct lov_stripe_md *lsm)
 {
 	int lmm_size;
-	ENTRY;
 
 	lmm_size = sizeof(**lmmp);
 	if (lmmp == NULL)
-		RETURN(lmm_size);
+		return lmm_size;
 
 	if (*lmmp != NULL && lsm == NULL) {
 		OBD_FREE(*lmmp, lmm_size);
 		*lmmp = NULL;
-		RETURN(0);
+		return 0;
 	} else if (unlikely(lsm != NULL && ostid_id(&lsm->lsm_oi) == 0)) {
-		RETURN(-EBADF);
+		return -EBADF;
 	}
 
 	if (*lmmp == NULL) {
 		OBD_ALLOC(*lmmp, lmm_size);
 		if (*lmmp == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 	}
 
 	if (lsm)
 		ostid_cpu_to_le(&lsm->lsm_oi, &(*lmmp)->lmm_oi);
 
-	RETURN(lmm_size);
+	return lmm_size;
 }
 
 /* Unpack OSC object metadata from disk storage (LE byte order). */
@@ -101,47 +100,46 @@
 {
 	int lsm_size;
 	struct obd_import *imp = class_exp2cliimp(exp);
-	ENTRY;
 
 	if (lmm != NULL) {
 		if (lmm_bytes < sizeof(*lmm)) {
 			CERROR("%s: lov_mds_md too small: %d, need %d\n",
 			       exp->exp_obd->obd_name, lmm_bytes,
 			       (int)sizeof(*lmm));
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 		/* XXX LOV_MAGIC etc check? */
 
 		if (unlikely(ostid_id(&lmm->lmm_oi) == 0)) {
 			CERROR("%s: zero lmm_object_id: rc = %d\n",
 			       exp->exp_obd->obd_name, -EINVAL);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	}
 
 	lsm_size = lov_stripe_md_size(1);
 	if (lsmp == NULL)
-		RETURN(lsm_size);
+		return lsm_size;
 
 	if (*lsmp != NULL && lmm == NULL) {
 		OBD_FREE((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
 		OBD_FREE(*lsmp, lsm_size);
 		*lsmp = NULL;
-		RETURN(0);
+		return 0;
 	}
 
 	if (*lsmp == NULL) {
 		OBD_ALLOC(*lsmp, lsm_size);
 		if (unlikely(*lsmp == NULL))
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		OBD_ALLOC((*lsmp)->lsm_oinfo[0], sizeof(struct lov_oinfo));
 		if (unlikely((*lsmp)->lsm_oinfo[0] == NULL)) {
 			OBD_FREE(*lsmp, lsm_size);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		loi_init((*lsmp)->lsm_oinfo[0]);
 	} else if (unlikely(ostid_id(&(*lsmp)->lsm_oi) == 0)) {
-		RETURN(-EBADF);
+		return -EBADF;
 	}
 
 	if (lmm != NULL)
@@ -154,7 +152,7 @@
 	else
 		(*lsmp)->lsm_maxbytes = LUSTRE_STRIPE_MAXBYTES;
 
-	RETURN(lsm_size);
+	return lsm_size;
 }
 
 static inline void osc_pack_capa(struct ptlrpc_request *req,
@@ -202,7 +200,6 @@
 				 struct osc_async_args *aa, int rc)
 {
 	struct ost_body *body;
-	ENTRY;
 
 	if (rc != 0)
 		GOTO(out, rc);
@@ -223,7 +220,7 @@
 	}
 out:
 	rc = aa->aa_oi->oi_cb_up(aa->aa_oi, rc);
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_getattr_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -232,17 +229,16 @@
 	struct ptlrpc_request *req;
 	struct osc_async_args *aa;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_GETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GETATTR);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	osc_pack_req_body(req, oinfo);
@@ -255,7 +251,7 @@
 	aa->aa_oi = oinfo;
 
 	ptlrpc_set_add_req(set, req);
-	RETURN(0);
+	return 0;
 }
 
 static int osc_getattr(const struct lu_env *env, struct obd_export *exp,
@@ -264,17 +260,16 @@
 	struct ptlrpc_request *req;
 	struct ost_body       *body;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_GETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GETATTR);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	osc_pack_req_body(req, oinfo);
@@ -296,7 +291,6 @@
 	oinfo->oi_oa->o_blksize = cli_brw_size(exp->exp_obd);
 	oinfo->oi_oa->o_valid |= OBD_MD_FLBLKSZ;
 
-	EXIT;
  out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -308,19 +302,18 @@
 	struct ptlrpc_request *req;
 	struct ost_body       *body;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(oinfo->oi_oa->o_valid & OBD_MD_FLGROUP);
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_SETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SETATTR);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	osc_pack_req_body(req, oinfo);
@@ -338,10 +331,9 @@
 	lustre_get_wire_obdo(&req->rq_import->imp_connect_data, oinfo->oi_oa,
 			     &body->oa);
 
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_setattr_interpret(const struct lu_env *env,
@@ -349,7 +341,6 @@
 				 struct osc_setattr_args *sa, int rc)
 {
 	struct ost_body *body;
-	ENTRY;
 
 	if (rc != 0)
 		GOTO(out, rc);
@@ -362,7 +353,7 @@
 			     &body->oa);
 out:
 	rc = sa->sa_upcall(sa->sa_cookie, rc);
-	RETURN(rc);
+	return rc;
 }
 
 int osc_setattr_async_base(struct obd_export *exp, struct obd_info *oinfo,
@@ -373,17 +364,16 @@
 	struct ptlrpc_request   *req;
 	struct osc_setattr_args *sa;
 	int		      rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_SETATTR);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SETATTR);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (oti && oinfo->oi_oa->o_valid & OBD_MD_FLCOOKIE)
@@ -413,7 +403,7 @@
 			ptlrpc_set_add_req(rqset, req);
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static int osc_setattr_async(struct obd_export *exp, struct obd_info *oinfo,
@@ -431,7 +421,6 @@
 	struct ost_body       *body;
 	struct lov_stripe_md  *lsm;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(oa);
 	LASSERT(ea);
@@ -440,7 +429,7 @@
 	if (!lsm) {
 		rc = obd_alloc_memmd(exp, &lsm);
 		if (rc < 0)
-			RETURN(rc);
+			return rc;
 	}
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_CREATE);
@@ -506,7 +495,7 @@
 out:
 	if (rc && !*ea)
 		obd_free_memmd(exp, &lsm);
-	RETURN(rc);
+	return rc;
 }
 
 int osc_punch_base(struct obd_export *exp, struct obd_info *oinfo,
@@ -517,17 +506,16 @@
 	struct osc_setattr_args *sa;
 	struct ost_body	 *body;
 	int		      rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_PUNCH);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_PUNCH);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 	req->rq_request_portal = OST_IO_PORTAL; /* bug 7198 */
 	ptlrpc_at_set_req_timeout(req);
@@ -551,7 +539,7 @@
 	else
 		ptlrpc_set_add_req(rqset, req);
 
-	RETURN(0);
+	return 0;
 }
 
 static int osc_punch(const struct lu_env *env, struct obd_export *exp,
@@ -571,7 +559,6 @@
 {
 	struct osc_fsync_args *fa = arg;
 	struct ost_body *body;
-	ENTRY;
 
 	if (rc)
 		GOTO(out, rc);
@@ -585,7 +572,7 @@
 	*fa->fa_oi->oi_oa = body->oa;
 out:
 	rc = fa->fa_upcall(fa->fa_cookie, rc);
-	RETURN(rc);
+	return rc;
 }
 
 int osc_sync_base(struct obd_export *exp, struct obd_info *oinfo,
@@ -596,17 +583,16 @@
 	struct ost_body       *body;
 	struct osc_fsync_args *fa;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_SYNC);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_set_capa_size(req, &RMF_CAPA1, oinfo->oi_capa);
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SYNC);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	/* overload the size and blocks fields in the oa with start/end */
@@ -630,25 +616,23 @@
 	else
 		ptlrpc_set_add_req(rqset, req);
 
-	RETURN (0);
+	return 0;
 }
 
 static int osc_sync(const struct lu_env *env, struct obd_export *exp,
 		    struct obd_info *oinfo, obd_size start, obd_size end,
 		    struct ptlrpc_request_set *set)
 {
-	ENTRY;
-
 	if (!oinfo->oi_oa) {
 		CDEBUG(D_INFO, "oa NULL\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	oinfo->oi_oa->o_size = start;
 	oinfo->oi_oa->o_blocks = end;
 	oinfo->oi_oa->o_valid |= (OBD_MD_FLSIZE | OBD_MD_FLBLOCKS);
 
-	RETURN(osc_sync_base(exp, oinfo, oinfo->oi_cb_up, oinfo, set));
+	return osc_sync_base(exp, oinfo, oinfo->oi_cb_up, oinfo, set);
 }
 
 /* Find and cancel locally locks matched by @mode in the resource found by
@@ -662,7 +646,6 @@
 	struct ldlm_res_id res_id;
 	struct ldlm_resource *res;
 	int count;
-	ENTRY;
 
 	/* Return, i.e. cancel nothing, only if ELC is supported (flag in
 	 * export) but disabled through procfs (flag in NS).
@@ -671,19 +654,19 @@
 	 * when we still want to cancel locks in advance and just cancel them
 	 * locally, without sending any RPC. */
 	if (exp_connect_cancelset(exp) && !ns_connect_cancelset(ns))
-		RETURN(0);
+		return 0;
 
 	ostid_build_res_name(&oa->o_oi, &res_id);
 	res = ldlm_resource_get(ns, NULL, &res_id, 0, 0);
 	if (res == NULL)
-		RETURN(0);
+		return 0;
 
 	LDLM_RESOURCE_ADDREF(res);
 	count = ldlm_cancel_resource_local(res, cancels, NULL, mode,
 					   lock_flags, 0, NULL);
 	LDLM_RESOURCE_DELREF(res);
 	ldlm_resource_putref(res);
-	RETURN(count);
+	return count;
 }
 
 static int osc_destroy_interpret(const struct lu_env *env,
@@ -720,7 +703,6 @@
 	       struct obd_trans_info *oti)
 {
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(oa);
 	LASSERT(ea);
@@ -728,16 +710,16 @@
 
 	if ((oa->o_valid & OBD_MD_FLFLAGS) &&
 	    oa->o_flags == OBD_FL_RECREATE_OBJS) {
-		RETURN(osc_real_create(exp, oa, ea, oti));
+		return osc_real_create(exp, oa, ea, oti);
 	}
 
 	if (!fid_seq_is_mdt(ostid_seq(&oa->o_oi)))
-		RETURN(osc_real_create(exp, oa, ea, oti));
+		return osc_real_create(exp, oa, ea, oti);
 
 	/* we should not get here anymore */
 	LBUG();
 
-	RETURN(rc);
+	return rc;
 }
 
 /* Destroy requests can be async always on the client, and we don't even really
@@ -760,11 +742,10 @@
 	struct ost_body       *body;
 	LIST_HEAD(cancels);
 	int rc, count;
-	ENTRY;
 
 	if (!oa) {
 		CDEBUG(D_INFO, "oa NULL\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	count = osc_resource_get_unused(exp, oa, &cancels, LCK_PW,
@@ -773,7 +754,7 @@
 	req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_OST_DESTROY);
 	if (req == NULL) {
 		ldlm_lock_list_put(&cancels, l_bl_ast, count);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	osc_set_capa_size(req, &RMF_CAPA1, (struct obd_capa *)capa);
@@ -781,7 +762,7 @@
 			       0, &cancels, count);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	req->rq_request_portal = OST_IO_PORTAL; /* bug 7198 */
@@ -817,7 +798,7 @@
 
 	/* Do not wait for response */
 	ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
-	RETURN(0);
+	return 0;
 }
 
 static void osc_announce_cached(struct client_obd *cli, struct obdo *oa,
@@ -948,7 +929,6 @@
 {
 	int			rc = 0;
 	struct ost_body	*body;
-	ENTRY;
 
 	client_obd_list_lock(&cli->cl_loi_list_lock);
 	/* Don't shrink if we are already above or below the desired limit
@@ -959,13 +939,13 @@
 
 	if (target_bytes >= cli->cl_avail_grant) {
 		client_obd_list_unlock(&cli->cl_loi_list_lock);
-		RETURN(0);
+		return 0;
 	}
 	client_obd_list_unlock(&cli->cl_loi_list_lock);
 
 	OBD_ALLOC_PTR(body);
 	if (!body)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	osc_announce_cached(cli, &body->oa, 0);
 
@@ -986,7 +966,7 @@
 	if (rc != 0)
 		__osc_update_grant(cli, body->oa.o_grant);
 	OBD_FREE_PTR(body);
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_should_shrink_grant(struct client_obd *client)
@@ -1256,11 +1236,10 @@
 	struct req_capsule      *pill;
 	struct brw_page *pg_prev;
 
-	ENTRY;
 	if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ))
-		RETURN(-ENOMEM); /* Recoverable */
+		return -ENOMEM; /* Recoverable */
 	if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ2))
-		RETURN(-EINVAL); /* Fatal */
+		return -EINVAL; /* Fatal */
 
 	if ((cmd & OBD_BRW_WRITE) != 0) {
 		opc = OST_WRITE;
@@ -1272,7 +1251,7 @@
 		req = ptlrpc_request_alloc(cli->cl_import, &RQF_OST_BRW_READ);
 	}
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	for (niocount = i = 1; i < page_count; i++) {
 		if (!can_merge_pages(pga[i - 1], pga[i]))
@@ -1289,7 +1268,7 @@
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, opc);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 	req->rq_request_portal = OST_IO_PORTAL; /* bug 7198 */
 	ptlrpc_at_set_req_timeout(req);
@@ -1435,11 +1414,11 @@
 		aa->aa_ocapa = capa_get(ocapa);
 
 	*reqp = req;
-	RETURN(0);
+	return 0;
 
  out:
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 static int check_write_checksum(struct obdo *oa, const lnet_process_id_t *peer,
@@ -1496,18 +1475,17 @@
 	struct client_obd *cli = aa->aa_cli;
 	struct ost_body *body;
 	__u32 client_cksum = 0;
-	ENTRY;
 
 	if (rc < 0 && rc != -EDQUOT) {
 		DEBUG_REQ(D_INFO, req, "Failed request with rc = %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	LASSERTF(req->rq_repmsg != NULL, "rc = %d\n", rc);
 	body = req_capsule_server_get(&req->rq_pill, &RMF_OST_BODY);
 	if (body == NULL) {
 		DEBUG_REQ(D_INFO, req, "Can't unpack body\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	/* set/clear over quota flag for a uid/gid */
@@ -1524,7 +1502,7 @@
 	osc_update_grant(cli, body);
 
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	if (aa->aa_oa->o_valid & OBD_MD_FLCKSUM)
 		client_cksum = aa->aa_oa->o_cksum; /* save for later */
@@ -1532,19 +1510,19 @@
 	if (lustre_msg_get_opc(req->rq_reqmsg) == OST_WRITE) {
 		if (rc > 0) {
 			CERROR("Unexpected +ve rc %d\n", rc);
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 		LASSERT(req->rq_bulk->bd_nob == aa->aa_requested_nob);
 
 		if (sptlrpc_cli_unwrap_bulk_write(req, req->rq_bulk))
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 
 		if ((aa->aa_oa->o_valid & OBD_MD_FLCKSUM) && client_cksum &&
 		    check_write_checksum(&body->oa, peer, client_cksum,
 					 body->oa.o_cksum, aa->aa_requested_nob,
 					 aa->aa_page_count, aa->aa_ppga,
 					 cksum_type_unpack(aa->aa_oa->o_flags)))
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 
 		rc = check_write_rcs(req, aa->aa_requested_nob,aa->aa_nio_count,
 				     aa->aa_page_count, aa->aa_ppga);
@@ -1561,7 +1539,7 @@
 	if (rc > aa->aa_requested_nob) {
 		CERROR("Unexpected rc %d (%d requested)\n", rc,
 		       aa->aa_requested_nob);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (rc != req->rq_bulk->bd_nob_transferred) {
@@ -1641,7 +1619,7 @@
 		lustre_get_wire_obdo(&req->rq_import->imp_connect_data,
 				     aa->aa_oa, &body->oa);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_brw_internal(int cmd, struct obd_export *exp, struct obdo *oa,
@@ -1655,8 +1633,6 @@
 	int		    generation, resends = 0;
 	struct l_wait_info     lwi;
 
-	ENTRY;
-
 	init_waitqueue_head(&waitq);
 	generation = exp->exp_obd->u.cli.cl_import->imp_generation;
 
@@ -1711,7 +1687,7 @@
 out:
 	if (rc == -EAGAIN || rc == -EINPROGRESS)
 		rc = -EIO;
-	RETURN (rc);
+	return rc;
 }
 
 static int osc_brw_redo_request(struct ptlrpc_request *request,
@@ -1720,7 +1696,6 @@
 	struct ptlrpc_request *new_req;
 	struct osc_brw_async_args *new_aa;
 	struct osc_async_page *oap;
-	ENTRY;
 
 	DEBUG_REQ(rc == -EINPROGRESS ? D_RPCTRACE : D_ERROR, request,
 		  "redo for recoverable error %d", rc);
@@ -1732,7 +1707,7 @@
 				  aa->aa_page_count, aa->aa_ppga,
 				  &new_req, aa->aa_ocapa, 0, 1);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	list_for_each_entry(oap, &aa->aa_oaps, oap_rpc_item) {
 		if (oap->oap_request != NULL) {
@@ -1741,7 +1716,7 @@
 				 request, oap->oap_request);
 			if (oap->oap_interrupted) {
 				ptlrpc_req_finished(new_req);
-				RETURN(-EINTR);
+				return -EINTR;
 			}
 		}
 	}
@@ -1784,7 +1759,7 @@
 	ptlrpcd_add_req(new_req, PDL_POLICY_SAME, -1);
 
 	DEBUG_REQ(D_INFO, new_req, "new request");
-	RETURN(0);
+	return 0;
 }
 
 /*
@@ -1873,7 +1848,6 @@
 	struct obd_import *imp = class_exp2cliimp(exp);
 	struct client_obd *cli;
 	int rc, page_count_orig;
-	ENTRY;
 
 	LASSERT((imp != NULL) && (imp->imp_obd != NULL));
 	cli = &imp->imp_obd->u.cli;
@@ -1883,8 +1857,8 @@
 		 * I/O can succeed */
 
 		if (imp->imp_invalid)
-			RETURN(-EIO);
-		RETURN(0);
+			return -EIO;
+		return 0;
 	}
 
 	/* test_brw with a failed create can trip this, maybe others. */
@@ -1894,7 +1868,7 @@
 
 	orig = ppga = osc_build_ppga(pga, page_count);
 	if (ppga == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	page_count_orig = page_count;
 
 	sort_brw_pages(ppga, page_count);
@@ -1935,7 +1909,7 @@
 	if (saved_oa != NULL)
 		OBDO_FREE(saved_oa);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int brw_interpret(const struct lu_env *env,
@@ -1946,7 +1920,6 @@
 	struct osc_extent *tmp;
 	struct cl_object  *obj = NULL;
 	struct client_obd *cli = aa->aa_cli;
-	ENTRY;
 
 	rc = osc_brw_fini_request(req, rc);
 	CDEBUG(D_INODE, "request %p aa %p rc %d\n", req, aa, rc);
@@ -1970,7 +1943,7 @@
 		}
 
 		if (rc == 0)
-			RETURN(0);
+			return 0;
 		else if (rc == -EAGAIN || rc == -EINPROGRESS)
 			rc = -EIO;
 	}
@@ -2040,7 +2013,7 @@
 	client_obd_list_unlock(&cli->cl_loi_list_lock);
 
 	osc_io_unplug(env, cli, NULL, PDL_POLICY_SAME);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2072,7 +2045,6 @@
 	int				rc;
 	LIST_HEAD(rpc_list);
 
-	ENTRY;
 	LASSERT(!list_empty(ext_list));
 
 	/* add pages into rpc_list to build BRW rpc */
@@ -2228,7 +2200,6 @@
 	 */
 	ptlrpcd_add_req(req, pol, -1);
 	rc = 0;
-	EXIT;
 
 out:
 	if (mem_tight != 0)
@@ -2257,7 +2228,7 @@
 		if (clerq && !IS_ERR(clerq))
 			cl_req_completion(env, clerq, rc);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_set_lock_data_with_check(struct ldlm_lock *lock,
@@ -2337,7 +2308,6 @@
 			    __u64 *flags, int agl, int rc)
 {
 	int intent = *flags & LDLM_FL_HAS_INTENT;
-	ENTRY;
 
 	if (intent) {
 		/* The request was created before ldlm_cli_enqueue call. */
@@ -2347,6 +2317,8 @@
 						     &RMF_DLM_REP);
 
 			LASSERT(rep != NULL);
+			rep->lock_policy_res1 =
+				ptlrpc_status_ntoh(rep->lock_policy_res1);
 			if (rep->lock_policy_res1)
 				rc = rep->lock_policy_res1;
 		}
@@ -2361,7 +2333,7 @@
 
 	/* Call the update callback. */
 	rc = (*upcall)(cookie, rc);
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_enqueue_interpret(const struct lu_env *env,
@@ -2494,7 +2466,6 @@
 	int match_lvb = (agl != 0 ? 0 : LDLM_FL_LVB_READY);
 	ldlm_mode_t mode;
 	int rc;
-	ENTRY;
 
 	/* Filesystem lock extents are extended to page boundaries so that
 	 * dealing with the page cache is a little smoother.  */
@@ -2536,7 +2507,7 @@
 			 * Return -ECANCELED to tell the caller. */
 			ldlm_lock_decref(lockh, mode);
 			LDLM_LOCK_PUT(matched);
-			RETURN(-ECANCELED);
+			return -ECANCELED;
 		} else if (osc_set_lock_data_with_check(matched, einfo)) {
 			*flags |= LDLM_FL_LVB_READY;
 			/* addref the lock only if not async requests and PW
@@ -2561,7 +2532,7 @@
 				/* For async requests, decref the lock. */
 				ldlm_lock_decref(lockh, einfo->ei_mode);
 			LDLM_LOCK_PUT(matched);
-			RETURN(ELDLM_OK);
+			return ELDLM_OK;
 		} else {
 			ldlm_lock_decref(lockh, mode);
 			LDLM_LOCK_PUT(matched);
@@ -2574,12 +2545,12 @@
 		req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 					   &RQF_LDLM_ENQUEUE_LVB);
 		if (req == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		rc = ldlm_prep_enqueue_req(exp, req, &cancels, 0);
 		if (rc) {
 			ptlrpc_request_free(req);
-			RETURN(rc);
+			return rc;
 		}
 
 		req_capsule_set_size(&req->rq_pill, &RMF_DLM_LVB, RCL_SERVER,
@@ -2615,14 +2586,14 @@
 		} else if (intent) {
 			ptlrpc_req_finished(req);
 		}
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = osc_enqueue_fini(req, lvb, upcall, cookie, flags, agl, rc);
 	if (intent)
 		ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_enqueue(struct obd_export *exp, struct obd_info *oinfo,
@@ -2631,7 +2602,6 @@
 {
 	struct ldlm_res_id res_id;
 	int rc;
-	ENTRY;
 
 	ostid_build_res_name(&oinfo->oi_md->lsm_oi, &res_id);
 	rc = osc_enqueue_base(exp, &res_id, &oinfo->oi_flags, &oinfo->oi_policy,
@@ -2639,7 +2609,7 @@
 			      oinfo->oi_md->lsm_oinfo[0]->loi_kms_valid,
 			      oinfo->oi_cb_up, oinfo, einfo, oinfo->oi_lockh,
 			      rqset, rqset != NULL, 0);
-	RETURN(rc);
+	return rc;
 }
 
 int osc_match_base(struct obd_export *exp, struct ldlm_res_id *res_id,
@@ -2650,10 +2620,9 @@
 	struct obd_device *obd = exp->exp_obd;
 	int lflags = *flags;
 	ldlm_mode_t rc;
-	ENTRY;
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_OSC_MATCH))
-		RETURN(-EIO);
+		return -EIO;
 
 	/* Filesystem lock extents are extended to page boundaries so that
 	 * dealing with the page cache is a little smoother */
@@ -2674,35 +2643,32 @@
 			if (!osc_set_data_with_check(lockh, data)) {
 				if (!(lflags & LDLM_FL_TEST_LOCK))
 					ldlm_lock_decref(lockh, rc);
-				RETURN(0);
+				return 0;
 			}
 		}
 		if (!(lflags & LDLM_FL_TEST_LOCK) && mode != rc) {
 			ldlm_lock_addref(lockh, LCK_PR);
 			ldlm_lock_decref(lockh, LCK_PW);
 		}
-		RETURN(rc);
+		return rc;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int osc_cancel_base(struct lustre_handle *lockh, __u32 mode)
 {
-	ENTRY;
-
 	if (unlikely(mode == LCK_GROUP))
 		ldlm_lock_decref_and_cancel(lockh, mode);
 	else
 		ldlm_lock_decref(lockh, mode);
 
-	RETURN(0);
+	return 0;
 }
 
 static int osc_cancel(struct obd_export *exp, struct lov_stripe_md *md,
 		      __u32 mode, struct lustre_handle *lockh)
 {
-	ENTRY;
-	RETURN(osc_cancel_base(lockh, mode));
+	return osc_cancel_base(lockh, mode);
 }
 
 static int osc_cancel_unused(struct obd_export *exp,
@@ -2726,7 +2692,6 @@
 				struct osc_async_args *aa, int rc)
 {
 	struct obd_statfs *msfs;
-	ENTRY;
 
 	if (rc == -EBADR)
 		/* The request has in fact never been sent
@@ -2734,7 +2699,7 @@
 		 * Exit immediately since the caller is
 		 * aware of the problem and takes care
 		 * of the clean up */
-		 RETURN(rc);
+		 return rc;
 
 	if ((rc == -ENOTCONN || rc == -EAGAIN) &&
 	    (aa->aa_oi->oi_flags & OBD_STATFS_NODELAY))
@@ -2751,7 +2716,7 @@
 	*aa->aa_oi->oi_osfs = *msfs;
 out:
 	rc = aa->aa_oi->oi_cb_up(aa->aa_oi, rc);
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_statfs_async(struct obd_export *exp,
@@ -2762,7 +2727,6 @@
 	struct ptlrpc_request *req;
 	struct osc_async_args *aa;
 	int		    rc;
-	ENTRY;
 
 	/* We could possibly pass max_age in the request (as an absolute
 	 * timestamp or a "seconds.usec ago") so the target can avoid doing
@@ -2772,12 +2736,12 @@
 	 * timestamps are not ideal because they need time synchronization. */
 	req = ptlrpc_request_alloc(obd->u.cli.cl_import, &RQF_OST_STATFS);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_STATFS);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 	ptlrpc_request_set_replen(req);
 	req->rq_request_portal = OST_CREATE_PORTAL;
@@ -2795,7 +2759,7 @@
 	aa->aa_oi = oinfo;
 
 	ptlrpc_set_add_req(rqset, req);
-	RETURN(0);
+	return 0;
 }
 
 static int osc_statfs(const struct lu_env *env, struct obd_export *exp,
@@ -2806,7 +2770,6 @@
 	struct ptlrpc_request *req;
 	struct obd_import     *imp = NULL;
 	int rc;
-	ENTRY;
 
 	/*Since the request might also come from lprocfs, so we need
 	 *sync this with client_disconnect_export Bug15684*/
@@ -2815,7 +2778,7 @@
 		imp = class_import_get(obd->u.cli.cl_import);
 	up_read(&obd->u.cli.cl_sem);
 	if (!imp)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	/* We could possibly pass max_age in the request (as an absolute
 	 * timestamp or a "seconds.usec ago") so the target can avoid doing
@@ -2828,12 +2791,12 @@
 	class_import_put(imp);
 
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_STATFS);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 	ptlrpc_request_set_replen(req);
 	req->rq_request_portal = OST_CREATE_PORTAL;
@@ -2856,7 +2819,6 @@
 
 	*osfs = *msfs;
 
-	EXIT;
  out:
 	ptlrpc_req_finished(req);
 	return rc;
@@ -2874,20 +2836,19 @@
 	struct lov_user_md_v3 lum, *lumk;
 	struct lov_user_ost_data_v1 *lmm_objects;
 	int rc = 0, lum_size;
-	ENTRY;
 
 	if (!lsm)
-		RETURN(-ENODATA);
+		return -ENODATA;
 
 	/* we only need the header part from user space to get lmm_magic and
 	 * lmm_stripe_count, (the header part is common to v1 and v3) */
 	lum_size = sizeof(struct lov_user_md_v1);
 	if (copy_from_user(&lum, lump, lum_size))
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	if ((lum.lmm_magic != LOV_USER_MAGIC_V1) &&
 	    (lum.lmm_magic != LOV_USER_MAGIC_V3))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* lov_user_md_vX and lov_mds_md_vX must have the same size */
 	LASSERT(sizeof(struct lov_user_md_v1) == sizeof(struct lov_mds_md_v1));
@@ -2900,7 +2861,7 @@
 		lum_size = lov_mds_md_size(lum.lmm_stripe_count, lum.lmm_magic);
 		OBD_ALLOC(lumk, lum_size);
 		if (!lumk)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		if (lum.lmm_magic == LOV_USER_MAGIC_V1)
 			lmm_objects =
@@ -2922,7 +2883,7 @@
 	if (lumk != &lum)
 		OBD_FREE(lumk, lum_size);
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -2932,7 +2893,6 @@
 	struct obd_device *obd = exp->exp_obd;
 	struct obd_ioctl_data *data = karg;
 	int err = 0;
-	ENTRY;
 
 	if (!try_module_get(THIS_MODULE)) {
 		CERROR("Can't get module. Is it alive?");
@@ -3016,15 +2976,14 @@
 			obd_count keylen, void *key, __u32 *vallen, void *val,
 			struct lov_stripe_md *lsm)
 {
-	ENTRY;
 	if (!vallen || !val)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	if (KEY_IS(KEY_LOCK_TO_STRIPE)) {
 		__u32 *stripe = val;
 		*vallen = sizeof(*stripe);
 		*stripe = 0;
-		RETURN(0);
+		return 0;
 	} else if (KEY_IS(KEY_LAST_ID)) {
 		struct ptlrpc_request *req;
 		obd_id		*reply;
@@ -3034,14 +2993,14 @@
 		req = ptlrpc_request_alloc(class_exp2cliimp(exp),
 					   &RQF_OST_GET_INFO_LAST_ID);
 		if (req == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		req_capsule_set_size(&req->rq_pill, &RMF_SETINFO_KEY,
 				     RCL_CLIENT, keylen);
 		rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GET_INFO);
 		if (rc) {
 			ptlrpc_request_free(req);
-			RETURN(rc);
+			return rc;
 		}
 
 		tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
@@ -3060,7 +3019,7 @@
 		*((obd_id *)val) = *reply;
 	out:
 		ptlrpc_req_finished(req);
-		RETURN(rc);
+		return rc;
 	} else if (KEY_IS(KEY_FIEMAP)) {
 		struct ll_fiemap_info_key *fm_key =
 				(struct ll_fiemap_info_key *)key;
@@ -3142,10 +3101,10 @@
 drop_lock:
 		if (mode)
 			ldlm_lock_decref(&lockh, LCK_PR);
-		RETURN(rc);
+		return rc;
 	}
 
-	RETURN(-EINVAL);
+	return -EINVAL;
 }
 
 static int osc_set_info_async(const struct lu_env *env, struct obd_export *exp,
@@ -3157,25 +3116,24 @@
 	struct obd_import     *imp = class_exp2cliimp(exp);
 	char		  *tmp;
 	int		    rc;
-	ENTRY;
 
 	OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_SHUTDOWN, 10);
 
 	if (KEY_IS(KEY_CHECKSUM)) {
 		if (vallen != sizeof(int))
-			RETURN(-EINVAL);
+			return -EINVAL;
 		exp->exp_obd->u.cli.cl_checksum = (*(int *)val) ? 1 : 0;
-		RETURN(0);
+		return 0;
 	}
 
 	if (KEY_IS(KEY_SPTLRPC_CONF)) {
 		sptlrpc_conf_client_adapt(obd);
-		RETURN(0);
+		return 0;
 	}
 
 	if (KEY_IS(KEY_FLUSH_CTX)) {
 		sptlrpc_import_flush_my_ctx(imp);
-		RETURN(0);
+		return 0;
 	}
 
 	if (KEY_IS(KEY_CACHE_SET)) {
@@ -3192,7 +3150,7 @@
 		list_add(&cli->cl_lru_osc, &cli->cl_cache->ccc_lru);
 		spin_unlock(&cli->cl_cache->ccc_lru_lock);
 
-		RETURN(0);
+		return 0;
 	}
 
 	if (KEY_IS(KEY_CACHE_LRU_SHRINK)) {
@@ -3202,11 +3160,11 @@
 
 		nr = osc_lru_shrink(cli, min(nr, target));
 		*(int *)val -= nr;
-		RETURN(0);
+		return 0;
 	}
 
 	if (!set && !KEY_IS(KEY_GRANT_SHRINK))
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	/* We pass all other commands directly to OST. Since nobody calls osc
 	   methods directly and everybody is supposed to go through LOV, we
@@ -3219,7 +3177,7 @@
 						&RQF_OST_SET_GRANT_INFO :
 						&RQF_OBD_SET_INFO);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req_capsule_set_size(&req->rq_pill, &RMF_SETINFO_KEY,
 			     RCL_CLIENT, keylen);
@@ -3229,7 +3187,7 @@
 	rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_SET_INFO);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
@@ -3248,7 +3206,7 @@
 		OBDO_ALLOC(oa);
 		if (!oa) {
 			ptlrpc_req_finished(req);
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		*oa = ((struct ost_body *)val)->oa;
 		aa->aa_oa = oa;
@@ -3263,7 +3221,7 @@
 	} else
 		ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
 
-	RETURN(0);
+	return 0;
 }
 
 
@@ -3280,8 +3238,6 @@
 {
 	struct llog_ctxt *ctxt;
 
-	ENTRY;
-
 	ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
 	if (ctxt) {
 		llog_cat_close(NULL, ctxt->loc_handle);
@@ -3291,7 +3247,7 @@
 	ctxt = llog_get_context(obd, LLOG_SIZE_REPL_CTXT);
 	if (ctxt)
 		llog_cleanup(NULL, ctxt);
-	RETURN(0);
+	return 0;
 }
 
 static int osc_reconnect(const struct lu_env *env,
@@ -3317,7 +3273,7 @@
 		       data->ocd_version, data->ocd_grant, lost_grant);
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static int osc_disconnect(struct obd_export *exp)
@@ -3369,7 +3325,6 @@
 	struct client_obd *cli;
 	int rc = 0;
 
-	ENTRY;
 	LASSERT(imp->imp_obd == obd);
 
 	switch (event) {
@@ -3433,7 +3388,7 @@
 		CERROR("Unknown import event %d\n", event);
 		LBUG();
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -3457,9 +3412,9 @@
 	    (lock->l_granted_mode == LCK_PR ||
 	     lock->l_granted_mode == LCK_CR) &&
 	    (osc_dlm_lock_pageref(lock) == 0))
-		RETURN(1);
+		return 1;
 
-	RETURN(0);
+	return 0;
 }
 
 static int brw_queue_work(const struct lu_env *env, void *data)
@@ -3469,7 +3424,7 @@
 	CDEBUG(D_CACHE, "Run writeback work for client obd %p.\n", cli);
 
 	osc_io_unplug(env, cli, NULL, PDL_POLICY_SAME);
-	RETURN(0);
+	return 0;
 }
 
 int osc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -3478,11 +3433,10 @@
 	struct client_obd	  *cli = &obd->u.cli;
 	void		       *handler;
 	int			rc;
-	ENTRY;
 
 	rc = ptlrpcd_addref();
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = client_obd_setup(obd, lcfg);
 	if (rc)
@@ -3517,7 +3471,7 @@
 
 	INIT_LIST_HEAD(&cli->cl_grant_shrink_list);
 	ns_register_cancel(obd->obd_namespace, osc_cancel_for_recovery);
-	RETURN(rc);
+	return rc;
 
 out_ptlrpcd_work:
 	ptlrpcd_destroy_work(handler);
@@ -3525,13 +3479,12 @@
 	client_obd_cleanup(obd);
 out_ptlrpcd:
 	ptlrpcd_decref();
-	RETURN(rc);
+	return rc;
 }
 
 static int osc_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage)
 {
 	int rc = 0;
-	ENTRY;
 
 	switch (stage) {
 	case OBD_CLEANUP_EARLY: {
@@ -3570,7 +3523,7 @@
 		break;
 		}
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int osc_cleanup(struct obd_device *obd)
@@ -3578,8 +3531,6 @@
 	struct client_obd *cli = &obd->u.cli;
 	int rc;
 
-	ENTRY;
-
 	/* lru cleanup */
 	if (cli->cl_cache != NULL) {
 		LASSERT(atomic_read(&cli->cl_cache->ccc_users) > 0);
@@ -3597,7 +3548,7 @@
 	rc = client_obd_cleanup(obd);
 
 	ptlrpcd_decref();
-	RETURN(rc);
+	return rc;
 }
 
 int osc_process_config_base(struct obd_device *obd, struct lustre_cfg *lcfg)
@@ -3671,7 +3622,6 @@
 {
 	struct lprocfs_static_vars lvars = { 0 };
 	int rc;
-	ENTRY;
 
 	/* print an address of _any_ initialized kernel symbol from this
 	 * module, to allow debugging with gdb that doesn't support data
@@ -3679,6 +3629,8 @@
 	CDEBUG(D_INFO, "Lustre OSC module (%p).\n", &osc_caches);
 
 	rc = lu_kmem_init(osc_caches);
+	if (rc)
+		return rc;
 
 	lprocfs_osc_init_vars(&lvars);
 
@@ -3686,13 +3638,13 @@
 				 LUSTRE_OSC_NAME, &osc_device_type);
 	if (rc) {
 		lu_kmem_fini(osc_caches);
-		RETURN(rc);
+		return rc;
 	}
 
 	spin_lock_init(&osc_ast_guard);
 	lockdep_set_class(&osc_ast_guard, &osc_ast_guard_class);
 
-	RETURN(rc);
+	return rc;
 }
 
 static void /*__exit*/ osc_exit(void)
@@ -3704,5 +3656,7 @@
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Lustre Object Storage Client (OSC)");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(LUSTRE_VERSION_STRING);
 
-cfs_module(osc, LUSTRE_VERSION_STRING, osc_init, osc_exit);
+module_init(osc_init);
+module_exit(osc_exit);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/Makefile b/drivers/staging/lustre/lustre/ptlrpc/Makefile
index 983eb66..6d78b80 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/Makefile
+++ b/drivers/staging/lustre/lustre/ptlrpc/Makefile
@@ -16,6 +16,7 @@
 ptlrpc_objs += sec_null.o sec_plain.o nrs.o nrs_fifo.o
 
 ptlrpc-y := $(ldlm_objs) $(ptlrpc_objs)
+ptlrpc-$(CONFIG_LUSTRE_TRANSLATE_ERRNOS) += errno.o
 
 obj-$(CONFIG_PTLRPC_GSS) += gss/
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index 22f7e65..810a458 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -137,11 +137,10 @@
 	struct obd_import *imp = req->rq_import;
 	struct ptlrpc_bulk_desc *desc;
 
-	ENTRY;
 	LASSERT(type == BULK_PUT_SINK || type == BULK_GET_SOURCE);
 	desc = ptlrpc_new_bulk(npages, max_brw, type, portal);
 	if (desc == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	desc->bd_import_generation = req->rq_import_generation;
 	desc->bd_import = class_import_get(imp);
@@ -187,7 +186,6 @@
 void __ptlrpc_free_bulk(struct ptlrpc_bulk_desc *desc, int unpin)
 {
 	int i;
-	ENTRY;
 
 	LASSERT(desc != NULL);
 	LASSERT(desc->bd_iov_count != LI_POISON); /* not freed already */
@@ -208,7 +206,6 @@
 
 	OBD_FREE(desc, offsetof(struct ptlrpc_bulk_desc,
 				bd_iov[desc->bd_max_iov]));
-	EXIT;
 }
 EXPORT_SYMBOL(__ptlrpc_free_bulk);
 
@@ -336,7 +333,6 @@
 	struct ptlrpc_request *early_req;
 	time_t		 olddl;
 	int		    rc;
-	ENTRY;
 
 	req->rq_early = 0;
 	spin_unlock(&req->rq_lock);
@@ -344,7 +340,7 @@
 	rc = sptlrpc_cli_unwrap_early_reply(req, &early_req);
 	if (rc) {
 		spin_lock(&req->rq_lock);
-		RETURN(rc);
+		return rc;
 	}
 
 	rc = unpack_reply(early_req);
@@ -360,7 +356,7 @@
 
 	if (rc != 0) {
 		spin_lock(&req->rq_lock);
-		RETURN(rc);
+		return rc;
 	}
 
 	/* Adjust the local timeout for this req */
@@ -379,7 +375,7 @@
 		  cfs_time_sub(req->rq_deadline, cfs_time_current_sec()),
 		  cfs_time_sub(req->rq_deadline, olddl));
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -547,7 +543,6 @@
 {
 	struct obd_import  *imp = request->rq_import;
 	int		 rc;
-	ENTRY;
 
 	if (unlikely(ctx))
 		request->rq_cli_ctx = sptlrpc_cli_ctx_get(ctx);
@@ -601,7 +596,7 @@
 
 	lustre_msg_set_opc(request->rq_reqmsg, opcode);
 
-	RETURN(0);
+	return 0;
 out_ctx:
 	sptlrpc_cli_ctx_put(request->rq_cli_ctx, 1);
 out_free:
@@ -822,10 +817,9 @@
 {
 	struct ptlrpc_request_set *set;
 
-	ENTRY;
 	OBD_ALLOC(set, sizeof *set);
 	if (!set)
-		RETURN(NULL);
+		return NULL;
 	atomic_set(&set->set_refcount, 1);
 	INIT_LIST_HEAD(&set->set_requests);
 	init_waitqueue_head(&set->set_waitq);
@@ -839,7 +833,7 @@
 	set->set_producer_arg = NULL;
 	set->set_rc	   = 0;
 
-	RETURN(set);
+	return set;
 }
 EXPORT_SYMBOL(ptlrpc_prep_set);
 
@@ -859,13 +853,13 @@
 
 	set = ptlrpc_prep_set();
 	if (!set)
-		RETURN(NULL);
+		return NULL;
 
 	set->set_max_inflight  = max;
 	set->set_producer      = func;
 	set->set_producer_arg  = arg;
 
-	RETURN(set);
+	return set;
 }
 EXPORT_SYMBOL(ptlrpc_prep_fcset);
 
@@ -883,7 +877,6 @@
 	struct list_head       *next;
 	int	       expected_phase;
 	int	       n = 0;
-	ENTRY;
 
 	/* Requests on the set should either all be completed, or all be new */
 	expected_phase = (atomic_read(&set->set_remaining) == 0) ?
@@ -925,7 +918,6 @@
 	LASSERT(atomic_read(&set->set_remaining) == 0);
 
 	ptlrpc_reqset_put(set);
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_set_destroy);
 
@@ -941,13 +933,13 @@
 
 	OBD_ALLOC_PTR(cbdata);
 	if (cbdata == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	cbdata->psc_interpret = fn;
 	cbdata->psc_data = data;
 	list_add_tail(&cbdata->psc_item, &set->set_cblist);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_set_add_cb);
 
@@ -1027,7 +1019,6 @@
 				   struct ptlrpc_request *req, int *status)
 {
 	int delay = 0;
-	ENTRY;
 
 	LASSERT (status != NULL);
 	*status = 0;
@@ -1078,7 +1069,7 @@
 		}
 	}
 
-	RETURN(delay);
+	return delay;
 }
 
 /**
@@ -1120,7 +1111,6 @@
 static int ptlrpc_check_status(struct ptlrpc_request *req)
 {
 	int err;
-	ENTRY;
 
 	err = lustre_msg_get_status(req->rq_repmsg);
 	if (lustre_msg_get_type(req->rq_repmsg) == PTL_RPC_MSG_ERR) {
@@ -1133,7 +1123,7 @@
 					   libcfs_nid2str(
 					   imp->imp_connection->c_peer.nid),
 					   ll_opcode2str(opc), err);
-		RETURN(err < 0 ? err : -EINVAL);
+		return err < 0 ? err : -EINVAL;
 	}
 
 	if (err < 0) {
@@ -1143,7 +1133,7 @@
 		DEBUG_REQ(D_INFO, req, "status is %d", err);
 	}
 
-	RETURN(err);
+	return err;
 }
 
 /**
@@ -1156,7 +1146,6 @@
 	struct lustre_msg *repmsg = req->rq_repmsg;
 	struct lustre_msg *reqmsg = req->rq_reqmsg;
 	__u64 *versions = lustre_msg_get_versions(repmsg);
-	ENTRY;
 
 	if (lustre_msg_get_flags(req->rq_reqmsg) & MSG_REPLAY)
 		return;
@@ -1165,8 +1154,6 @@
 	lustre_msg_set_versions(reqmsg, versions);
 	CDEBUG(D_INFO, "Client save versions ["LPX64"/"LPX64"]\n",
 	       versions[0], versions[1]);
-
-	EXIT;
 }
 
 /**
@@ -1183,7 +1170,6 @@
 	int rc;
 	struct timeval work_start;
 	long timediff;
-	ENTRY;
 
 	LASSERT(obd != NULL);
 	/* repbuf must be unlinked */
@@ -1194,7 +1180,7 @@
 			DEBUG_REQ(D_ERROR, req, "reply buffer overflow,"
 				  " expected: %d, actual size: %d",
 				  req->rq_nob_received, req->rq_repbuf_len);
-			RETURN(-EOVERFLOW);
+			return -EOVERFLOW;
 		}
 
 		sptlrpc_cli_free_repbuf(req);
@@ -1205,7 +1191,7 @@
 		req->rq_replen       = req->rq_nob_received;
 		req->rq_nob_received = 0;
 		req->rq_resend       = 1;
-		RETURN(0);
+		return 0;
 	}
 
 	/*
@@ -1215,18 +1201,18 @@
 	rc = sptlrpc_cli_unwrap_reply(req);
 	if (rc) {
 		DEBUG_REQ(D_ERROR, req, "unwrap reply failed (%d):", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	/*
 	 * Security layer unwrap might ask resend this request.
 	 */
 	if (req->rq_resend)
-		RETURN(0);
+		return 0;
 
 	rc = unpack_reply(req);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	/* retry indefinitely on EINPROGRESS */
 	if (lustre_msg_get_status(req->rq_repmsg) == -EINPROGRESS &&
@@ -1257,7 +1243,7 @@
 		else
 			req->rq_sent = now + req->rq_nr_resend;
 
-		RETURN(0);
+		return 0;
 	}
 
 	do_gettimeofday(&work_start);
@@ -1272,7 +1258,7 @@
 	    lustre_msg_get_type(req->rq_repmsg) != PTL_RPC_MSG_ERR) {
 		DEBUG_REQ(D_ERROR, req, "invalid packet received (type=%u)",
 			  lustre_msg_get_type(req->rq_repmsg));
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (lustre_msg_get_opc(req->rq_reqmsg) != OBD_PING)
@@ -1293,10 +1279,10 @@
 		if (ll_rpc_recoverable_error(rc)) {
 			if (req->rq_send_state != LUSTRE_IMP_FULL ||
 			    imp->imp_obd->obd_no_recov || imp->imp_dlm_fake) {
-				RETURN(rc);
+				return rc;
 			}
 			ptlrpc_request_handle_notconn(req);
-			RETURN(rc);
+			return rc;
 		}
 	} else {
 		/*
@@ -1360,7 +1346,7 @@
 		spin_unlock(&imp->imp_lock);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1372,13 +1358,12 @@
 {
 	struct obd_import     *imp = req->rq_import;
 	int rc;
-	ENTRY;
 
 	LASSERT(req->rq_phase == RQ_PHASE_NEW);
 	if (req->rq_sent && (req->rq_sent > cfs_time_current_sec()) &&
 	    (!req->rq_generation_set ||
 	     req->rq_import_generation == imp->imp_generation))
-		RETURN (0);
+		return 0;
 
 	ptlrpc_rqphase_move(req, RQ_PHASE_RPC);
 
@@ -1400,14 +1385,14 @@
 		list_add_tail(&req->rq_list, &imp->imp_delayed_list);
 		atomic_inc(&req->rq_import->imp_inflight);
 		spin_unlock(&imp->imp_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	if (rc != 0) {
 		spin_unlock(&imp->imp_lock);
 		req->rq_status = rc;
 		ptlrpc_rqphase_move(req, RQ_PHASE_INTERPRET);
-		RETURN(rc);
+		return rc;
 	}
 
 	LASSERT(list_empty(&req->rq_list));
@@ -1421,10 +1406,10 @@
 	if (rc) {
 		if (req->rq_err) {
 			req->rq_status = rc;
-			RETURN(1);
+			return 1;
 		} else {
 			req->rq_wait_ctx = 1;
-			RETURN(0);
+			return 0;
 		}
 	}
 
@@ -1439,15 +1424,14 @@
 	if (rc) {
 		DEBUG_REQ(D_HA, req, "send failed (%d); expect timeout", rc);
 		req->rq_net_err = 1;
-		RETURN(rc);
+		return rc;
 	}
-	RETURN(0);
+	return 0;
 }
 
 static inline int ptlrpc_set_producer(struct ptlrpc_request_set *set)
 {
 	int remaining, rc;
-	ENTRY;
 
 	LASSERT(set->set_producer != NULL);
 
@@ -1461,11 +1445,11 @@
 			/* no more RPC to produce */
 			set->set_producer     = NULL;
 			set->set_producer_arg = NULL;
-			RETURN(0);
+			return 0;
 		}
 	}
 
-	RETURN((atomic_read(&set->set_remaining) - remaining));
+	return (atomic_read(&set->set_remaining) - remaining);
 }
 
 /**
@@ -1478,10 +1462,9 @@
 {
 	struct list_head *tmp, *next;
 	int force_timer_recalc = 0;
-	ENTRY;
 
 	if (atomic_read(&set->set_remaining) == 0)
-		RETURN(1);
+		return 1;
 
 	list_for_each_safe(tmp, next, &set->set_requests) {
 		struct ptlrpc_request *req =
@@ -1834,7 +1817,7 @@
 	}
 
 	/* If we hit an error, we want to recover promptly. */
-	RETURN(atomic_read(&set->set_remaining) == 0 || force_timer_recalc);
+	return atomic_read(&set->set_remaining) == 0 || force_timer_recalc;
 }
 EXPORT_SYMBOL(ptlrpc_check_set);
 
@@ -1847,7 +1830,6 @@
 {
 	struct obd_import *imp = req->rq_import;
 	int rc = 0;
-	ENTRY;
 
 	spin_lock(&req->rq_lock);
 	req->rq_timedout = 1;
@@ -1873,14 +1855,14 @@
 
 	if (imp == NULL) {
 		DEBUG_REQ(D_HA, req, "NULL import: already cleaned up?");
-		RETURN(1);
+		return 1;
 	}
 
 	atomic_inc(&imp->imp_timeouts);
 
 	/* The DLM server doesn't want recovery run on its imports. */
 	if (imp->imp_dlm_fake)
-		RETURN(1);
+		return 1;
 
 	/* If this request is for recovery or other primordial tasks,
 	 * then error it out here. */
@@ -1894,7 +1876,7 @@
 		req->rq_status = -ETIMEDOUT;
 		req->rq_err = 1;
 		spin_unlock(&req->rq_lock);
-		RETURN(1);
+		return 1;
 	}
 
 	/* if a request can't be resent we can't wait for an answer after
@@ -1906,7 +1888,7 @@
 
 	ptlrpc_fail_import(imp, lustre_msg_get_conn_cnt(req->rq_reqmsg));
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1919,7 +1901,6 @@
 	struct ptlrpc_request_set *set = data;
 	struct list_head		*tmp;
 	time_t		     now = cfs_time_current_sec();
-	ENTRY;
 
 	LASSERT(set != NULL);
 
@@ -1955,7 +1936,7 @@
 	 * sleep so we can recalculate the timeout, or enable interrupts
 	 * if everyone's timed out.
 	 */
-	RETURN(1);
+	return 1;
 }
 EXPORT_SYMBOL(ptlrpc_expired_set);
 
@@ -2006,7 +1987,6 @@
 	int		    timeout = 0;
 	struct ptlrpc_request *req;
 	int		    deadline;
-	ENTRY;
 
 	SIGNAL_MASK_ASSERT(); /* XXX BUG 1511 */
 
@@ -2045,7 +2025,7 @@
 		else if (timeout == 0 || timeout > deadline - now)
 			timeout = deadline - now;
 	}
-	RETURN(timeout);
+	return timeout;
 }
 EXPORT_SYMBOL(ptlrpc_set_next_timeout);
 
@@ -2061,7 +2041,6 @@
 	struct ptlrpc_request *req;
 	struct l_wait_info     lwi;
 	int		    rc, timeout;
-	ENTRY;
 
 	if (set->set_producer)
 		(void)ptlrpc_set_producer(set);
@@ -2074,7 +2053,7 @@
 		}
 
 	if (list_empty(&set->set_requests))
-		RETURN(0);
+		return 0;
 
 	do {
 		timeout = ptlrpc_set_next_timeout(set);
@@ -2171,7 +2150,7 @@
 		}
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_set_wait);
 
@@ -2185,9 +2164,7 @@
  */
 static void __ptlrpc_free_req(struct ptlrpc_request *request, int locked)
 {
-	ENTRY;
 	if (request == NULL) {
-		EXIT;
 		return;
 	}
 
@@ -2240,7 +2217,6 @@
 		__ptlrpc_free_req_to_pool(request);
 	else
 		OBD_FREE(request, sizeof(*request));
-	EXIT;
 }
 
 static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked);
@@ -2263,15 +2239,14 @@
  */
 static int __ptlrpc_req_finished(struct ptlrpc_request *request, int locked)
 {
-	ENTRY;
 	if (request == NULL)
-		RETURN(1);
+		return 1;
 
 	if (request == LP_POISON ||
 	    request->rq_reqmsg == LP_POISON) {
 		CERROR("dereferencing freed request (bug 575)\n");
 		LBUG();
-		RETURN(1);
+		return 1;
 	}
 
 	DEBUG_REQ(D_INFO, request, "refcount now %u",
@@ -2279,10 +2254,10 @@
 
 	if (atomic_dec_and_test(&request->rq_refcount)) {
 		__ptlrpc_free_req(request, locked);
-		RETURN(1);
+		return 1;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -2332,7 +2307,7 @@
 	 * Nothing left to do.
 	 */
 	if (!ptlrpc_client_recv_or_unlink(request))
-		RETURN(1);
+		return 1;
 
 	LNetMDUnlink(request->rq_reply_md_h);
 
@@ -2340,7 +2315,7 @@
 	 * Let's check it once again.
 	 */
 	if (!ptlrpc_client_recv_or_unlink(request))
-		RETURN(1);
+		return 1;
 
 	/*
 	 * Move to "Unregistering" phase as reply was not unlinked yet.
@@ -2351,7 +2326,7 @@
 	 * Do not wait for unlink to finish.
 	 */
 	if (async)
-		RETURN(0);
+		return 0;
 
 	/*
 	 * We have to l_wait_event() whatever the result, to give liblustre
@@ -2372,7 +2347,7 @@
 				  &lwi);
 		if (rc == 0) {
 			ptlrpc_rqphase_move(request, request->rq_next_phase);
-			RETURN(1);
+			return 1;
 		}
 
 		LASSERT(rc == -ETIMEDOUT);
@@ -2380,7 +2355,7 @@
 			  "rvcng=%d unlnk=%d", request->rq_receiving_reply,
 			  request->rq_must_unlink);
 	}
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_unregister_reply);
 
@@ -2397,7 +2372,6 @@
 	struct list_head *tmp, *saved;
 	struct ptlrpc_request *req;
 	struct ptlrpc_request *last_req = NULL; /* temporary fire escape */
-	ENTRY;
 
 	LASSERT(imp != NULL);
 
@@ -2408,7 +2382,6 @@
 	    imp->imp_generation == imp->imp_last_generation_checked) {
 		CDEBUG(D_INFO, "%s: skip recheck: last_committed "LPU64"\n",
 		       imp->imp_obd->obd_name, imp->imp_peer_committed_transno);
-		EXIT;
 		return;
 	}
 	CDEBUG(D_RPCTRACE, "%s: committing for last_committed "LPU64" gen %d\n",
@@ -2456,16 +2429,10 @@
 		list_del_init(&req->rq_replay_list);
 		__ptlrpc_req_finished(req, 1);
 	}
-
-	EXIT;
-	return;
 }
 
 void ptlrpc_cleanup_client(struct obd_import *imp)
 {
-	ENTRY;
-	EXIT;
-	return;
 }
 EXPORT_SYMBOL(ptlrpc_cleanup_client);
 
@@ -2517,9 +2484,8 @@
  */
 struct ptlrpc_request *ptlrpc_request_addref(struct ptlrpc_request *req)
 {
-	ENTRY;
 	atomic_inc(&req->rq_refcount);
-	RETURN(req);
+	return req;
 }
 EXPORT_SYMBOL(ptlrpc_request_addref);
 
@@ -2588,7 +2554,6 @@
 {
 	struct ptlrpc_request_set *set;
 	int rc;
-	ENTRY;
 
 	LASSERT(req->rq_set == NULL);
 	LASSERT(!req->rq_receiving_reply);
@@ -2596,7 +2561,7 @@
 	set = ptlrpc_prep_set();
 	if (set == NULL) {
 		CERROR("Unable to allocate ptlrpc set.");
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	/* for distributed debugging */
@@ -2608,7 +2573,7 @@
 	rc = ptlrpc_set_wait(set);
 	ptlrpc_set_destroy(set);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_queue_wait);
 
@@ -2629,7 +2594,6 @@
 	struct ptlrpc_replay_async_args *aa = data;
 	struct obd_import *imp = req->rq_import;
 
-	ENTRY;
 	atomic_dec(&imp->imp_replay_inflight);
 
 	if (!ptlrpc_client_replied(req)) {
@@ -2710,7 +2674,7 @@
 		/* this replay failed, so restart recovery */
 		ptlrpc_connect_import(imp);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2721,7 +2685,6 @@
 int ptlrpc_replay_req(struct ptlrpc_request *req)
 {
 	struct ptlrpc_replay_async_args *aa;
-	ENTRY;
 
 	LASSERT(req->rq_import->imp_state == LUSTRE_IMP_REPLAY);
 
@@ -2751,7 +2714,7 @@
 	ptlrpc_request_addref(req); /* ptlrpcd needs a ref */
 
 	ptlrpcd_add_req(req, PDL_POLICY_LOCAL, -1);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_replay_req);
 
@@ -2761,7 +2724,6 @@
 void ptlrpc_abort_inflight(struct obd_import *imp)
 {
 	struct list_head *tmp, *n;
-	ENTRY;
 
 	/* Make sure that no new requests get processed for this import.
 	 * ptlrpc_{queue,set}_wait must (and does) hold imp_lock while testing
@@ -2809,8 +2771,6 @@
 		ptlrpc_free_committed(imp);
 
 	spin_unlock(&imp->imp_lock);
-
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_abort_inflight);
 
@@ -2969,18 +2929,17 @@
 {
 	struct ptlrpc_request	 *req = NULL;
 	struct ptlrpc_work_async_args *args;
-	ENTRY;
 
 	might_sleep();
 
 	if (cb == NULL)
-		RETURN(ERR_PTR(-EINVAL));
+		return ERR_PTR(-EINVAL);
 
 	/* copy some code from deprecated fakereq. */
 	OBD_ALLOC_PTR(req);
 	if (req == NULL) {
 		CERROR("ptlrpc: run out of memory!\n");
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 	}
 
 	req->rq_send_state = LUSTRE_IMP_FULL;
@@ -3009,7 +2968,7 @@
 	args->cb     = cb;
 	args->cbdata = cbdata;
 
-	RETURN(req);
+	return req;
 }
 EXPORT_SYMBOL(ptlrpcd_alloc_work);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/connection.c b/drivers/staging/lustre/lustre/ptlrpc/connection.c
index a0757f3..17ca842 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/connection.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/connection.c
@@ -49,7 +49,6 @@
 		      struct obd_uuid *uuid)
 {
 	struct ptlrpc_connection *conn, *conn2;
-	ENTRY;
 
 	conn = cfs_hash_lookup(conn_hash, &peer);
 	if (conn)
@@ -57,7 +56,7 @@
 
 	OBD_ALLOC_PTR(conn);
 	if (!conn)
-		RETURN(NULL);
+		return NULL;
 
 	conn->c_peer = peer;
 	conn->c_self = self;
@@ -80,7 +79,6 @@
 		OBD_FREE_PTR(conn);
 		conn = conn2;
 	}
-	EXIT;
 out:
 	CDEBUG(D_INFO, "conn=%p refcount %d to %s\n",
 	       conn, atomic_read(&conn->c_refcount),
@@ -92,10 +90,9 @@
 int ptlrpc_connection_put(struct ptlrpc_connection *conn)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (!conn)
-		RETURN(rc);
+		return rc;
 
 	LASSERT(atomic_read(&conn->c_refcount) > 1);
 
@@ -122,28 +119,24 @@
 	       conn, atomic_read(&conn->c_refcount),
 	       libcfs_nid2str(conn->c_peer.nid));
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_connection_put);
 
 struct ptlrpc_connection *
 ptlrpc_connection_addref(struct ptlrpc_connection *conn)
 {
-	ENTRY;
-
 	atomic_inc(&conn->c_refcount);
 	CDEBUG(D_INFO, "conn=%p refcount %d to %s\n",
 	       conn, atomic_read(&conn->c_refcount),
 	       libcfs_nid2str(conn->c_peer.nid));
 
-	RETURN(conn);
+	return conn;
 }
 EXPORT_SYMBOL(ptlrpc_connection_addref);
 
 int ptlrpc_connection_init(void)
 {
-	ENTRY;
-
 	conn_hash = cfs_hash_create("CONN_HASH",
 				    HASH_CONN_CUR_BITS,
 				    HASH_CONN_MAX_BITS,
@@ -152,16 +145,15 @@
 				    CFS_HASH_MAX_THETA,
 				    &conn_hash_ops, CFS_HASH_DEFAULT);
 	if (!conn_hash)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_connection_init);
 
-void ptlrpc_connection_fini(void) {
-	ENTRY;
+void ptlrpc_connection_fini(void)
+{
 	cfs_hash_putref(conn_hash);
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_connection_fini);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/errno.c b/drivers/staging/lustre/lustre/ptlrpc/errno.c
new file mode 100644
index 0000000..1c10063
--- /dev/null
+++ b/drivers/staging/lustre/lustre/ptlrpc/errno.c
@@ -0,0 +1,380 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * 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 version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.txt
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (C) 2011 FUJITSU LIMITED.  All rights reserved.
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ */
+
+#include <linux/libcfs/libcfs.h>
+#include <lustre/lustre_errno.h>
+
+/*
+ * The two translation tables below must define a one-to-one mapping between
+ * host and network errnos.
+ *
+ * EWOULDBLOCK is equal to EAGAIN on all architectures except for parisc, which
+ * appears irrelevant.  Thus, existing references to EWOULDBLOCK are fine.
+ *
+ * EDEADLOCK is equal to EDEADLK on x86 but not on sparc, at least.  A sparc
+ * host has no context-free way to determine if a LUSTRE_EDEADLK represents an
+ * EDEADLK or an EDEADLOCK.  Therefore, all existing references to EDEADLOCK
+ * that need to be transferred on wire have been replaced with EDEADLK.
+ */
+static int lustre_errno_hton_mapping[] = {
+	[EPERM]			= LUSTRE_EPERM,
+	[ENOENT]		= LUSTRE_ENOENT,
+	[ESRCH]			= LUSTRE_ESRCH,
+	[EINTR]			= LUSTRE_EINTR,
+	[EIO]			= LUSTRE_EIO,
+	[ENXIO]			= LUSTRE_ENXIO,
+	[E2BIG]			= LUSTRE_E2BIG,
+	[ENOEXEC]		= LUSTRE_ENOEXEC,
+	[EBADF]			= LUSTRE_EBADF,
+	[ECHILD]		= LUSTRE_ECHILD,
+	[EAGAIN]		= LUSTRE_EAGAIN,
+	[ENOMEM]		= LUSTRE_ENOMEM,
+	[EACCES]		= LUSTRE_EACCES,
+	[EFAULT]		= LUSTRE_EFAULT,
+	[ENOTBLK]		= LUSTRE_ENOTBLK,
+	[EBUSY]			= LUSTRE_EBUSY,
+	[EEXIST]		= LUSTRE_EEXIST,
+	[EXDEV]			= LUSTRE_EXDEV,
+	[ENODEV]		= LUSTRE_ENODEV,
+	[ENOTDIR]		= LUSTRE_ENOTDIR,
+	[EISDIR]		= LUSTRE_EISDIR,
+	[EINVAL]		= LUSTRE_EINVAL,
+	[ENFILE]		= LUSTRE_ENFILE,
+	[EMFILE]		= LUSTRE_EMFILE,
+	[ENOTTY]		= LUSTRE_ENOTTY,
+	[ETXTBSY]		= LUSTRE_ETXTBSY,
+	[EFBIG]			= LUSTRE_EFBIG,
+	[ENOSPC]		= LUSTRE_ENOSPC,
+	[ESPIPE]		= LUSTRE_ESPIPE,
+	[EROFS]			= LUSTRE_EROFS,
+	[EMLINK]		= LUSTRE_EMLINK,
+	[EPIPE]			= LUSTRE_EPIPE,
+	[EDOM]			= LUSTRE_EDOM,
+	[ERANGE]		= LUSTRE_ERANGE,
+	[EDEADLK]		= LUSTRE_EDEADLK,
+	[ENAMETOOLONG]		= LUSTRE_ENAMETOOLONG,
+	[ENOLCK]		= LUSTRE_ENOLCK,
+	[ENOSYS]		= LUSTRE_ENOSYS,
+	[ENOTEMPTY]		= LUSTRE_ENOTEMPTY,
+	[ELOOP]			= LUSTRE_ELOOP,
+	[ENOMSG]		= LUSTRE_ENOMSG,
+	[EIDRM]			= LUSTRE_EIDRM,
+	[ECHRNG]		= LUSTRE_ECHRNG,
+	[EL2NSYNC]		= LUSTRE_EL2NSYNC,
+	[EL3HLT]		= LUSTRE_EL3HLT,
+	[EL3RST]		= LUSTRE_EL3RST,
+	[ELNRNG]		= LUSTRE_ELNRNG,
+	[EUNATCH]		= LUSTRE_EUNATCH,
+	[ENOCSI]		= LUSTRE_ENOCSI,
+	[EL2HLT]		= LUSTRE_EL2HLT,
+	[EBADE]			= LUSTRE_EBADE,
+	[EBADR]			= LUSTRE_EBADR,
+	[EXFULL]		= LUSTRE_EXFULL,
+	[ENOANO]		= LUSTRE_ENOANO,
+	[EBADRQC]		= LUSTRE_EBADRQC,
+	[EBADSLT]		= LUSTRE_EBADSLT,
+	[EBFONT]		= LUSTRE_EBFONT,
+	[ENOSTR]		= LUSTRE_ENOSTR,
+	[ENODATA]		= LUSTRE_ENODATA,
+	[ETIME]			= LUSTRE_ETIME,
+	[ENOSR]			= LUSTRE_ENOSR,
+	[ENONET]		= LUSTRE_ENONET,
+	[ENOPKG]		= LUSTRE_ENOPKG,
+	[EREMOTE]		= LUSTRE_EREMOTE,
+	[ENOLINK]		= LUSTRE_ENOLINK,
+	[EADV]			= LUSTRE_EADV,
+	[ESRMNT]		= LUSTRE_ESRMNT,
+	[ECOMM]			= LUSTRE_ECOMM,
+	[EPROTO]		= LUSTRE_EPROTO,
+	[EMULTIHOP]		= LUSTRE_EMULTIHOP,
+	[EDOTDOT]		= LUSTRE_EDOTDOT,
+	[EBADMSG]		= LUSTRE_EBADMSG,
+	[EOVERFLOW]		= LUSTRE_EOVERFLOW,
+	[ENOTUNIQ]		= LUSTRE_ENOTUNIQ,
+	[EBADFD]		= LUSTRE_EBADFD,
+	[EREMCHG]		= LUSTRE_EREMCHG,
+	[ELIBACC]		= LUSTRE_ELIBACC,
+	[ELIBBAD]		= LUSTRE_ELIBBAD,
+	[ELIBSCN]		= LUSTRE_ELIBSCN,
+	[ELIBMAX]		= LUSTRE_ELIBMAX,
+	[ELIBEXEC]		= LUSTRE_ELIBEXEC,
+	[EILSEQ]		= LUSTRE_EILSEQ,
+	[ERESTART]		= LUSTRE_ERESTART,
+	[ESTRPIPE]		= LUSTRE_ESTRPIPE,
+	[EUSERS]		= LUSTRE_EUSERS,
+	[ENOTSOCK]		= LUSTRE_ENOTSOCK,
+	[EDESTADDRREQ]		= LUSTRE_EDESTADDRREQ,
+	[EMSGSIZE]		= LUSTRE_EMSGSIZE,
+	[EPROTOTYPE]		= LUSTRE_EPROTOTYPE,
+	[ENOPROTOOPT]		= LUSTRE_ENOPROTOOPT,
+	[EPROTONOSUPPORT]	= LUSTRE_EPROTONOSUPPORT,
+	[ESOCKTNOSUPPORT]	= LUSTRE_ESOCKTNOSUPPORT,
+	[EOPNOTSUPP]		= LUSTRE_EOPNOTSUPP,
+	[EPFNOSUPPORT]		= LUSTRE_EPFNOSUPPORT,
+	[EAFNOSUPPORT]		= LUSTRE_EAFNOSUPPORT,
+	[EADDRINUSE]		= LUSTRE_EADDRINUSE,
+	[EADDRNOTAVAIL]		= LUSTRE_EADDRNOTAVAIL,
+	[ENETDOWN]		= LUSTRE_ENETDOWN,
+	[ENETUNREACH]		= LUSTRE_ENETUNREACH,
+	[ENETRESET]		= LUSTRE_ENETRESET,
+	[ECONNABORTED]		= LUSTRE_ECONNABORTED,
+	[ECONNRESET]		= LUSTRE_ECONNRESET,
+	[ENOBUFS]		= LUSTRE_ENOBUFS,
+	[EISCONN]		= LUSTRE_EISCONN,
+	[ENOTCONN]		= LUSTRE_ENOTCONN,
+	[ESHUTDOWN]		= LUSTRE_ESHUTDOWN,
+	[ETOOMANYREFS]		= LUSTRE_ETOOMANYREFS,
+	[ETIMEDOUT]		= LUSTRE_ETIMEDOUT,
+	[ECONNREFUSED]		= LUSTRE_ECONNREFUSED,
+	[EHOSTDOWN]		= LUSTRE_EHOSTDOWN,
+	[EHOSTUNREACH]		= LUSTRE_EHOSTUNREACH,
+	[EALREADY]		= LUSTRE_EALREADY,
+	[EINPROGRESS]		= LUSTRE_EINPROGRESS,
+	[ESTALE]		= LUSTRE_ESTALE,
+	[EUCLEAN]		= LUSTRE_EUCLEAN,
+	[ENOTNAM]		= LUSTRE_ENOTNAM,
+	[ENAVAIL]		= LUSTRE_ENAVAIL,
+	[EISNAM]		= LUSTRE_EISNAM,
+	[EREMOTEIO]		= LUSTRE_EREMOTEIO,
+	[EDQUOT]		= LUSTRE_EDQUOT,
+	[ENOMEDIUM]		= LUSTRE_ENOMEDIUM,
+	[EMEDIUMTYPE]		= LUSTRE_EMEDIUMTYPE,
+	[ECANCELED]		= LUSTRE_ECANCELED,
+	[ENOKEY]		= LUSTRE_ENOKEY,
+	[EKEYEXPIRED]		= LUSTRE_EKEYEXPIRED,
+	[EKEYREVOKED]		= LUSTRE_EKEYREVOKED,
+	[EKEYREJECTED]		= LUSTRE_EKEYREJECTED,
+	[EOWNERDEAD]		= LUSTRE_EOWNERDEAD,
+	[ENOTRECOVERABLE]	= LUSTRE_ENOTRECOVERABLE,
+	[ERESTARTSYS]		= LUSTRE_ERESTARTSYS,
+	[ERESTARTNOINTR]	= LUSTRE_ERESTARTNOINTR,
+	[ERESTARTNOHAND]	= LUSTRE_ERESTARTNOHAND,
+	[ENOIOCTLCMD]		= LUSTRE_ENOIOCTLCMD,
+	[ERESTART_RESTARTBLOCK]	= LUSTRE_ERESTART_RESTARTBLOCK,
+	[EBADHANDLE]		= LUSTRE_EBADHANDLE,
+	[ENOTSYNC]		= LUSTRE_ENOTSYNC,
+	[EBADCOOKIE]		= LUSTRE_EBADCOOKIE,
+	[ENOTSUPP]		= LUSTRE_ENOTSUPP,
+	[ETOOSMALL]		= LUSTRE_ETOOSMALL,
+	[ESERVERFAULT]		= LUSTRE_ESERVERFAULT,
+	[EBADTYPE]		= LUSTRE_EBADTYPE,
+	[EJUKEBOX]		= LUSTRE_EJUKEBOX,
+	[EIOCBQUEUED]		= LUSTRE_EIOCBQUEUED,
+};
+
+static int lustre_errno_ntoh_mapping[] = {
+	[LUSTRE_EPERM]			= EPERM,
+	[LUSTRE_ENOENT]			= ENOENT,
+	[LUSTRE_ESRCH]			= ESRCH,
+	[LUSTRE_EINTR]			= EINTR,
+	[LUSTRE_EIO]			= EIO,
+	[LUSTRE_ENXIO]			= ENXIO,
+	[LUSTRE_E2BIG]			= E2BIG,
+	[LUSTRE_ENOEXEC]		= ENOEXEC,
+	[LUSTRE_EBADF]			= EBADF,
+	[LUSTRE_ECHILD]			= ECHILD,
+	[LUSTRE_EAGAIN]			= EAGAIN,
+	[LUSTRE_ENOMEM]			= ENOMEM,
+	[LUSTRE_EACCES]			= EACCES,
+	[LUSTRE_EFAULT]			= EFAULT,
+	[LUSTRE_ENOTBLK]		= ENOTBLK,
+	[LUSTRE_EBUSY]			= EBUSY,
+	[LUSTRE_EEXIST]			= EEXIST,
+	[LUSTRE_EXDEV]			= EXDEV,
+	[LUSTRE_ENODEV]			= ENODEV,
+	[LUSTRE_ENOTDIR]		= ENOTDIR,
+	[LUSTRE_EISDIR]			= EISDIR,
+	[LUSTRE_EINVAL]			= EINVAL,
+	[LUSTRE_ENFILE]			= ENFILE,
+	[LUSTRE_EMFILE]			= EMFILE,
+	[LUSTRE_ENOTTY]			= ENOTTY,
+	[LUSTRE_ETXTBSY]		= ETXTBSY,
+	[LUSTRE_EFBIG]			= EFBIG,
+	[LUSTRE_ENOSPC]			= ENOSPC,
+	[LUSTRE_ESPIPE]			= ESPIPE,
+	[LUSTRE_EROFS]			= EROFS,
+	[LUSTRE_EMLINK]			= EMLINK,
+	[LUSTRE_EPIPE]			= EPIPE,
+	[LUSTRE_EDOM]			= EDOM,
+	[LUSTRE_ERANGE]			= ERANGE,
+	[LUSTRE_EDEADLK]		= EDEADLK,
+	[LUSTRE_ENAMETOOLONG]		= ENAMETOOLONG,
+	[LUSTRE_ENOLCK]			= ENOLCK,
+	[LUSTRE_ENOSYS]			= ENOSYS,
+	[LUSTRE_ENOTEMPTY]		= ENOTEMPTY,
+	[LUSTRE_ELOOP]			= ELOOP,
+	[LUSTRE_ENOMSG]			= ENOMSG,
+	[LUSTRE_EIDRM]			= EIDRM,
+	[LUSTRE_ECHRNG]			= ECHRNG,
+	[LUSTRE_EL2NSYNC]		= EL2NSYNC,
+	[LUSTRE_EL3HLT]			= EL3HLT,
+	[LUSTRE_EL3RST]			= EL3RST,
+	[LUSTRE_ELNRNG]			= ELNRNG,
+	[LUSTRE_EUNATCH]		= EUNATCH,
+	[LUSTRE_ENOCSI]			= ENOCSI,
+	[LUSTRE_EL2HLT]			= EL2HLT,
+	[LUSTRE_EBADE]			= EBADE,
+	[LUSTRE_EBADR]			= EBADR,
+	[LUSTRE_EXFULL]			= EXFULL,
+	[LUSTRE_ENOANO]			= ENOANO,
+	[LUSTRE_EBADRQC]		= EBADRQC,
+	[LUSTRE_EBADSLT]		= EBADSLT,
+	[LUSTRE_EBFONT]			= EBFONT,
+	[LUSTRE_ENOSTR]			= ENOSTR,
+	[LUSTRE_ENODATA]		= ENODATA,
+	[LUSTRE_ETIME]			= ETIME,
+	[LUSTRE_ENOSR]			= ENOSR,
+	[LUSTRE_ENONET]			= ENONET,
+	[LUSTRE_ENOPKG]			= ENOPKG,
+	[LUSTRE_EREMOTE]		= EREMOTE,
+	[LUSTRE_ENOLINK]		= ENOLINK,
+	[LUSTRE_EADV]			= EADV,
+	[LUSTRE_ESRMNT]			= ESRMNT,
+	[LUSTRE_ECOMM]			= ECOMM,
+	[LUSTRE_EPROTO]			= EPROTO,
+	[LUSTRE_EMULTIHOP]		= EMULTIHOP,
+	[LUSTRE_EDOTDOT]		= EDOTDOT,
+	[LUSTRE_EBADMSG]		= EBADMSG,
+	[LUSTRE_EOVERFLOW]		= EOVERFLOW,
+	[LUSTRE_ENOTUNIQ]		= ENOTUNIQ,
+	[LUSTRE_EBADFD]			= EBADFD,
+	[LUSTRE_EREMCHG]		= EREMCHG,
+	[LUSTRE_ELIBACC]		= ELIBACC,
+	[LUSTRE_ELIBBAD]		= ELIBBAD,
+	[LUSTRE_ELIBSCN]		= ELIBSCN,
+	[LUSTRE_ELIBMAX]		= ELIBMAX,
+	[LUSTRE_ELIBEXEC]		= ELIBEXEC,
+	[LUSTRE_EILSEQ]			= EILSEQ,
+	[LUSTRE_ERESTART]		= ERESTART,
+	[LUSTRE_ESTRPIPE]		= ESTRPIPE,
+	[LUSTRE_EUSERS]			= EUSERS,
+	[LUSTRE_ENOTSOCK]		= ENOTSOCK,
+	[LUSTRE_EDESTADDRREQ]		= EDESTADDRREQ,
+	[LUSTRE_EMSGSIZE]		= EMSGSIZE,
+	[LUSTRE_EPROTOTYPE]		= EPROTOTYPE,
+	[LUSTRE_ENOPROTOOPT]		= ENOPROTOOPT,
+	[LUSTRE_EPROTONOSUPPORT]	= EPROTONOSUPPORT,
+	[LUSTRE_ESOCKTNOSUPPORT]	= ESOCKTNOSUPPORT,
+	[LUSTRE_EOPNOTSUPP]		= EOPNOTSUPP,
+	[LUSTRE_EPFNOSUPPORT]		= EPFNOSUPPORT,
+	[LUSTRE_EAFNOSUPPORT]		= EAFNOSUPPORT,
+	[LUSTRE_EADDRINUSE]		= EADDRINUSE,
+	[LUSTRE_EADDRNOTAVAIL]		= EADDRNOTAVAIL,
+	[LUSTRE_ENETDOWN]		= ENETDOWN,
+	[LUSTRE_ENETUNREACH]		= ENETUNREACH,
+	[LUSTRE_ENETRESET]		= ENETRESET,
+	[LUSTRE_ECONNABORTED]		= ECONNABORTED,
+	[LUSTRE_ECONNRESET]		= ECONNRESET,
+	[LUSTRE_ENOBUFS]		= ENOBUFS,
+	[LUSTRE_EISCONN]		= EISCONN,
+	[LUSTRE_ENOTCONN]		= ENOTCONN,
+	[LUSTRE_ESHUTDOWN]		= ESHUTDOWN,
+	[LUSTRE_ETOOMANYREFS]		= ETOOMANYREFS,
+	[LUSTRE_ETIMEDOUT]		= ETIMEDOUT,
+	[LUSTRE_ECONNREFUSED]		= ECONNREFUSED,
+	[LUSTRE_EHOSTDOWN]		= EHOSTDOWN,
+	[LUSTRE_EHOSTUNREACH]		= EHOSTUNREACH,
+	[LUSTRE_EALREADY]		= EALREADY,
+	[LUSTRE_EINPROGRESS]		= EINPROGRESS,
+	[LUSTRE_ESTALE]			= ESTALE,
+	[LUSTRE_EUCLEAN]		= EUCLEAN,
+	[LUSTRE_ENOTNAM]		= ENOTNAM,
+	[LUSTRE_ENAVAIL]		= ENAVAIL,
+	[LUSTRE_EISNAM]			= EISNAM,
+	[LUSTRE_EREMOTEIO]		= EREMOTEIO,
+	[LUSTRE_EDQUOT]			= EDQUOT,
+	[LUSTRE_ENOMEDIUM]		= ENOMEDIUM,
+	[LUSTRE_EMEDIUMTYPE]		= EMEDIUMTYPE,
+	[LUSTRE_ECANCELED]		= ECANCELED,
+	[LUSTRE_ENOKEY]			= ENOKEY,
+	[LUSTRE_EKEYEXPIRED]		= EKEYEXPIRED,
+	[LUSTRE_EKEYREVOKED]		= EKEYREVOKED,
+	[LUSTRE_EKEYREJECTED]		= EKEYREJECTED,
+	[LUSTRE_EOWNERDEAD]		= EOWNERDEAD,
+	[LUSTRE_ENOTRECOVERABLE]	= ENOTRECOVERABLE,
+	[LUSTRE_ERESTARTSYS]		= ERESTARTSYS,
+	[LUSTRE_ERESTARTNOINTR]		= ERESTARTNOINTR,
+	[LUSTRE_ERESTARTNOHAND]		= ERESTARTNOHAND,
+	[LUSTRE_ENOIOCTLCMD]		= ENOIOCTLCMD,
+	[LUSTRE_ERESTART_RESTARTBLOCK]	= ERESTART_RESTARTBLOCK,
+	[LUSTRE_EBADHANDLE]		= EBADHANDLE,
+	[LUSTRE_ENOTSYNC]		= ENOTSYNC,
+	[LUSTRE_EBADCOOKIE]		= EBADCOOKIE,
+	[LUSTRE_ENOTSUPP]		= ENOTSUPP,
+	[LUSTRE_ETOOSMALL]		= ETOOSMALL,
+	[LUSTRE_ESERVERFAULT]		= ESERVERFAULT,
+	[LUSTRE_EBADTYPE]		= EBADTYPE,
+	[LUSTRE_EJUKEBOX]		= EJUKEBOX,
+	[LUSTRE_EIOCBQUEUED]		= EIOCBQUEUED,
+};
+
+unsigned int lustre_errno_hton(unsigned int h)
+{
+	unsigned int n;
+
+	if (h == 0) {
+		n = 0;
+	} else if (h < ARRAY_SIZE(lustre_errno_hton_mapping)) {
+		n = lustre_errno_hton_mapping[h];
+		if (n == 0)
+			goto generic;
+	} else {
+generic:
+		/*
+		 * A generic errno is better than the unknown one that could
+		 * mean anything to a different host.
+		 */
+		n = LUSTRE_EIO;
+	}
+
+	return n;
+}
+EXPORT_SYMBOL(lustre_errno_hton);
+
+unsigned int lustre_errno_ntoh(unsigned int n)
+{
+	unsigned int h;
+
+	if (n == 0) {
+		h = 0;
+	} else if (n < ARRAY_SIZE(lustre_errno_ntoh_mapping)) {
+		h = lustre_errno_ntoh_mapping[n];
+		if (h == 0)
+			goto generic;
+	} else {
+generic:
+		/*
+		 * Similar to the situation in lustre_errno_hton(), an unknown
+		 * network errno could coincide with anything.  Hence, it is
+		 * better to return a generic errno.
+		 */
+		h = EIO;
+	}
+
+	return h;
+}
+EXPORT_SYMBOL(lustre_errno_ntoh);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c
index 0264c10..58d089c 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/events.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/events.c
@@ -55,7 +55,6 @@
 {
 	struct ptlrpc_cb_id   *cbid = ev->md.user_ptr;
 	struct ptlrpc_request *req = cbid->cbid_arg;
-	ENTRY;
 
 	LASSERT (ev->type == LNET_EVENT_SEND ||
 		 ev->type == LNET_EVENT_UNLINK);
@@ -79,8 +78,6 @@
 	}
 
 	ptlrpc_req_finished(req);
-
-	EXIT;
 }
 
 /*
@@ -90,7 +87,6 @@
 {
 	struct ptlrpc_cb_id   *cbid = ev->md.user_ptr;
 	struct ptlrpc_request *req = cbid->cbid_arg;
-	ENTRY;
 
 	DEBUG_REQ(D_NET, req, "type %d, status %d", ev->type, ev->status);
 
@@ -166,7 +162,6 @@
 	 * since we don't have our own ref */
 	ptlrpc_client_wake_req(req);
 	spin_unlock(&req->rq_lock);
-	EXIT;
 }
 
 /*
@@ -177,7 +172,6 @@
 	struct ptlrpc_cb_id     *cbid = ev->md.user_ptr;
 	struct ptlrpc_bulk_desc *desc = cbid->cbid_arg;
 	struct ptlrpc_request   *req;
-	ENTRY;
 
 	LASSERT ((desc->bd_type == BULK_PUT_SINK &&
 		  ev->type == LNET_EVENT_PUT) ||
@@ -220,7 +214,6 @@
 		ptlrpc_client_wake_req(desc->bd_req);
 
 	spin_unlock(&desc->bd_lock);
-	EXIT;
 }
 
 /*
@@ -289,7 +282,6 @@
 	struct ptlrpc_service_part	  *svcpt = rqbd->rqbd_svcpt;
 	struct ptlrpc_service	     *service = svcpt->scp_service;
 	struct ptlrpc_request	     *req;
-	ENTRY;
 
 	LASSERT (ev->type == LNET_EVENT_PUT ||
 		 ev->type == LNET_EVENT_UNLINK);
@@ -378,7 +370,6 @@
 	wake_up(&svcpt->scp_waitq);
 
 	spin_unlock(&svcpt->scp_lock);
-	EXIT;
 }
 
 /*
@@ -389,7 +380,6 @@
 	struct ptlrpc_cb_id	  *cbid = ev->md.user_ptr;
 	struct ptlrpc_reply_state *rs = cbid->cbid_arg;
 	struct ptlrpc_service_part *svcpt = rs->rs_svcpt;
-	ENTRY;
 
 	LASSERT (ev->type == LNET_EVENT_SEND ||
 		 ev->type == LNET_EVENT_ACK ||
@@ -400,7 +390,6 @@
 		 * net's ref on 'rs' */
 		LASSERT (ev->unlinked);
 		ptlrpc_rs_decref(rs);
-		EXIT;
 		return;
 	}
 
@@ -421,7 +410,6 @@
 		spin_unlock(&rs->rs_lock);
 		spin_unlock(&svcpt->scp_rep_lock);
 	}
-	EXIT;
 }
 
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h
index feac604..0e9f6c4 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_api.h
@@ -100,7 +100,7 @@
 /* Each mechanism is described by the following struct: */
 struct gss_api_mech {
 	struct list_head	      gm_list;
-	module_t	   *gm_owner;
+	struct module	   *gm_owner;
 	char		   *gm_name;
 	rawobj_t		gm_oid;
 	atomic_t	    gm_count;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c
index ed95bbb..b518d8a 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_bulk.c
@@ -68,7 +68,6 @@
 	__u32			    maj;
 	int			      offset;
 	int			      rc;
-	ENTRY;
 
 	LASSERT(req->rq_pack_bulk);
 	LASSERT(req->rq_bulk_read || req->rq_bulk_write);
@@ -104,7 +103,7 @@
 	bsd->bsd_svc = SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc);
 
 	if (bsd->bsd_svc == SPTLRPC_BULK_SVC_NULL)
-		RETURN(0);
+		return 0;
 
 	LASSERT(bsd->bsd_svc == SPTLRPC_BULK_SVC_INTG ||
 		bsd->bsd_svc == SPTLRPC_BULK_SVC_PRIV);
@@ -132,18 +131,18 @@
 					   &token);
 			if (maj != GSS_S_COMPLETE) {
 				CWARN("failed to sign bulk data: %x\n", maj);
-				RETURN(-EACCES);
+				return -EACCES;
 			}
 		} else {
 			/* privacy mode */
 			if (desc->bd_iov_count == 0)
-				RETURN(0);
+				return 0;
 
 			rc = sptlrpc_enc_pool_get_pages(desc);
 			if (rc) {
 				CERROR("bulk write: failed to allocate "
 				       "encryption pages: %d\n", rc);
-				RETURN(rc);
+				return rc;
 			}
 
 			token.data = bsd->bsd_data;
@@ -153,12 +152,12 @@
 			maj = lgss_wrap_bulk(gctx->gc_mechctx, desc, &token, 0);
 			if (maj != GSS_S_COMPLETE) {
 				CWARN("fail to encrypt bulk data: %x\n", maj);
-				RETURN(-EACCES);
+				return -EACCES;
 			}
 		}
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
@@ -171,7 +170,6 @@
 	rawobj_t			 token;
 	__u32			    maj;
 	int			      roff, voff;
-	ENTRY;
 
 	LASSERT(req->rq_pack_bulk);
 	LASSERT(req->rq_bulk_read || req->rq_bulk_write);
@@ -220,7 +218,7 @@
 		       "(%u,%u,%u) != (%u,%u,%u)\n",
 		       bsdr->bsd_version, bsdr->bsd_type, bsdr->bsd_svc,
 		       bsdv->bsd_version, bsdv->bsd_type, bsdv->bsd_svc);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	LASSERT(bsdv->bsd_svc == SPTLRPC_BULK_SVC_NULL ||
@@ -235,7 +233,7 @@
 	if (req->rq_bulk_write) {
 		if (bsdv->bsd_flags & BSD_FL_ERR) {
 			CERROR("server reported bulk i/o failure\n");
-			RETURN(-EIO);
+			return -EIO;
 		}
 
 		if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV)
@@ -270,12 +268,12 @@
 					      &token);
 			if (maj != GSS_S_COMPLETE) {
 				CERROR("failed to verify bulk read: %x\n", maj);
-				RETURN(-EACCES);
+				return -EACCES;
 			}
 		} else if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV) {
 			desc->bd_nob = bsdv->bsd_nob;
 			if (desc->bd_nob == 0)
-				RETURN(0);
+				return 0;
 
 			token.data = bsdv->bsd_data;
 			token.len = lustre_msg_buflen(vmsg, voff) -
@@ -286,14 +284,14 @@
 			if (maj != GSS_S_COMPLETE) {
 				CERROR("failed to decrypt bulk read: %x\n",
 				       maj);
-				RETURN(-EACCES);
+				return -EACCES;
 			}
 
 			desc->bd_nob_transferred = desc->bd_nob;
 		}
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static int gss_prep_bulk(struct ptlrpc_bulk_desc *desc,
@@ -318,21 +316,20 @@
 		      struct ptlrpc_bulk_desc *desc)
 {
 	int	     rc;
-	ENTRY;
 
 	LASSERT(req->rq_cli_ctx);
 	LASSERT(req->rq_pack_bulk);
 	LASSERT(req->rq_bulk_read);
 
 	if (SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc) != SPTLRPC_BULK_SVC_PRIV)
-		RETURN(0);
+		return 0;
 
 	rc = gss_prep_bulk(desc, ctx2gctx(req->rq_cli_ctx)->gc_mechctx);
 	if (rc)
 		CERROR("bulk read: failed to prepare encryption "
 		       "pages: %d\n", rc);
 
-	RETURN(rc);
+	return rc;
 }
 
 int gss_svc_prep_bulk(struct ptlrpc_request *req,
@@ -341,7 +338,6 @@
 	struct gss_svc_reqctx	*grctx;
 	struct ptlrpc_bulk_sec_desc  *bsd;
 	int			   rc;
-	ENTRY;
 
 	LASSERT(req->rq_svc_ctx);
 	LASSERT(req->rq_pack_bulk);
@@ -355,14 +351,14 @@
 
 	bsd = grctx->src_reqbsd;
 	if (bsd->bsd_svc != SPTLRPC_BULK_SVC_PRIV)
-		RETURN(0);
+		return 0;
 
 	rc = gss_prep_bulk(desc, grctx->src_ctx->gsc_mechctx);
 	if (rc)
 		CERROR("bulk write: failed to prepare encryption "
 		       "pages: %d\n", rc);
 
-	RETURN(rc);
+	return rc;
 }
 
 int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
@@ -372,7 +368,6 @@
 	struct ptlrpc_bulk_sec_desc  *bsdr, *bsdv;
 	rawobj_t		      token;
 	__u32			 maj;
-	ENTRY;
 
 	LASSERT(req->rq_svc_ctx);
 	LASSERT(req->rq_pack_bulk);
@@ -404,7 +399,7 @@
 		if (maj != GSS_S_COMPLETE) {
 			bsdv->bsd_flags |= BSD_FL_ERR;
 			CERROR("failed to verify bulk signature: %x\n", maj);
-			RETURN(-EACCES);
+			return -EACCES;
 		}
 		break;
 	case SPTLRPC_BULK_SVC_PRIV:
@@ -412,7 +407,7 @@
 			bsdv->bsd_flags |= BSD_FL_ERR;
 			CERROR("prepared nob %d doesn't match the actual "
 			       "nob %d\n", desc->bd_nob, bsdr->bsd_nob);
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (desc->bd_iov_count == 0) {
@@ -428,12 +423,12 @@
 		if (maj != GSS_S_COMPLETE) {
 			bsdv->bsd_flags |= BSD_FL_ERR;
 			CERROR("failed decrypt bulk data: %x\n", maj);
-			RETURN(-EACCES);
+			return -EACCES;
 		}
 		break;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int gss_svc_wrap_bulk(struct ptlrpc_request *req,
@@ -444,7 +439,6 @@
 	rawobj_t		      token;
 	__u32			 maj;
 	int			   rc;
-	ENTRY;
 
 	LASSERT(req->rq_svc_ctx);
 	LASSERT(req->rq_pack_bulk);
@@ -476,7 +470,7 @@
 		if (maj != GSS_S_COMPLETE) {
 			bsdv->bsd_flags |= BSD_FL_ERR;
 			CERROR("failed to sign bulk data: %x\n", maj);
-			RETURN(-EACCES);
+			return -EACCES;
 		}
 		break;
 	case SPTLRPC_BULK_SVC_PRIV:
@@ -492,7 +486,7 @@
 			bsdv->bsd_flags |= BSD_FL_ERR;
 			CERROR("bulk read: failed to allocate encryption "
 			       "pages: %d\n", rc);
-			RETURN(rc);
+			return rc;
 		}
 
 		token.data = bsdv->bsd_data;
@@ -503,10 +497,10 @@
 		if (maj != GSS_S_COMPLETE) {
 			bsdv->bsd_flags |= BSD_FL_ERR;
 			CERROR("failed to encrypt bulk data: %x\n", maj);
-			RETURN(-EACCES);
+			return -EACCES;
 		}
 		break;
 	}
 
-	RETURN(0);
+	return 0;
 }
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
index 142c789..55247af 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_cli_upcall.c
@@ -243,41 +243,41 @@
 	if (count != sizeof(param)) {
 		CERROR("ioctl size %lu, expect %lu, please check lgss_keyring "
 		       "version\n", count, (unsigned long) sizeof(param));
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	if (copy_from_user(&param, buffer, sizeof(param))) {
 		CERROR("failed copy data from lgssd\n");
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 
 	if (param.version != GSSD_INTERFACE_VERSION) {
 		CERROR("gssd interface version %d (expect %d)\n",
 			param.version, GSSD_INTERFACE_VERSION);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* take name */
 	if (strncpy_from_user(obdname, param.uuid, sizeof(obdname)) <= 0) {
 		CERROR("Invalid obdname pointer\n");
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 
 	obd = class_name2obd(obdname);
 	if (!obd) {
 		CERROR("no such obd %s\n", obdname);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (unlikely(!obd->obd_set_up)) {
 		CERROR("obd %s not setup\n", obdname);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	spin_lock(&obd->obd_dev_lock);
 	if (obd->obd_stopping) {
 		CERROR("obd %s has stopped\n", obdname);
 		spin_unlock(&obd->obd_dev_lock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
@@ -285,7 +285,7 @@
 	    strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME)) {
 		CERROR("obd %s is not a client device\n", obdname);
 		spin_unlock(&obd->obd_dev_lock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	spin_unlock(&obd->obd_dev_lock);
 
@@ -293,7 +293,7 @@
 	if (obd->u.cli.cl_import == NULL) {
 		CERROR("obd %s: import has gone\n", obd->obd_name);
 		up_read(&obd->u.cli.cl_sem);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	imp = class_import_get(obd->u.cli.cl_import);
 	up_read(&obd->u.cli.cl_sem);
@@ -301,7 +301,7 @@
 	if (imp->imp_deactive) {
 		CERROR("import has been deactivated\n");
 		class_import_put(imp);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	req = ptlrpc_request_alloc_pack(imp, &RQF_SEC_CTX, LUSTRE_OBD_VERSION,
@@ -368,7 +368,7 @@
 
 	class_import_put(imp);
 	ptlrpc_req_finished(req);
-	RETURN(rc);
+	return rc;
 }
 
 int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
@@ -378,7 +378,6 @@
 	struct ptlrpc_request   *req;
 	struct ptlrpc_user_desc *pud;
 	int		      rc;
-	ENTRY;
 
 	LASSERT(atomic_read(&ctx->cc_refcount) > 0);
 
@@ -386,7 +385,7 @@
 		CDEBUG(D_SEC, "ctx %p(%u->%s) not uptodate, "
 		       "don't send destroy rpc\n", ctx,
 		       ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
-		RETURN(0);
+		return 0;
 	}
 
 	might_sleep();
@@ -434,7 +433,7 @@
 out_ref:
 	ptlrpc_req_finished(req);
 out:
-	RETURN(rc);
+	return rc;
 }
 
 int __init gss_init_cli_upcall(void)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
index bb571ae..188dbbf 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_keyring.c
@@ -524,7 +524,6 @@
 	struct gss_sec_keyring *gsec_kr = sec2gsec_keyring(sec);
 	struct ptlrpc_cli_ctx  *ctx;
 	cfs_time_t	      now;
-	ENTRY;
 
 	LASSERT(sec_is_reverse(sec));
 
@@ -569,11 +568,10 @@
 				      struct sptlrpc_flavor *sf)
 {
 	struct gss_sec_keyring  *gsec_kr;
-	ENTRY;
 
 	OBD_ALLOC(gsec_kr, sizeof(*gsec_kr));
 	if (gsec_kr == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	INIT_HLIST_HEAD(&gsec_kr->gsk_clist);
 	gsec_kr->gsk_root_ctx = NULL;
@@ -592,11 +590,11 @@
 		goto err_free;
 	}
 
-	RETURN(&gsec_kr->gsk_base.gs_base);
+	return &gsec_kr->gsk_base.gs_base;
 
 err_free:
 	OBD_FREE(gsec_kr, sizeof(*gsec_kr));
-	RETURN(NULL);
+	return NULL;
 }
 
 static
@@ -683,7 +681,6 @@
 	char		    *coinfo;
 	int		      coinfo_size;
 	char		    *co_flags = "";
-	ENTRY;
 
 	LASSERT(imp != NULL);
 
@@ -697,7 +694,7 @@
 		 * always succeed.
 		 */
 		if (ctx || sec_is_reverse(sec))
-			RETURN(ctx);
+			return ctx;
 	}
 
 	LASSERT(create != 0);
@@ -821,7 +818,7 @@
 out:
 	if (is_root)
 		mutex_unlock(&gsec_kr->gsk_root_uc_lock);
-	RETURN(ctx);
+	return ctx;
 }
 
 static
@@ -891,7 +888,6 @@
 	struct hlist_head	freelist = HLIST_HEAD_INIT;
 	struct hlist_node      *next;
 	struct ptlrpc_cli_ctx  *ctx;
-	ENTRY;
 
 	gsec_kr = sec2gsec_keyring(sec);
 
@@ -930,15 +926,12 @@
 	spin_unlock(&sec->ps_lock);
 
 	dispose_ctx_list_kr(&freelist);
-	EXIT;
 }
 
 static
 int gss_sec_flush_ctx_cache_kr(struct ptlrpc_sec *sec,
 			       uid_t uid, int grace, int force)
 {
-	ENTRY;
-
 	CDEBUG(D_SEC, "sec %p(%d, nctx %d), uid %d, grace %d, force %d\n",
 	       sec, atomic_read(&sec->ps_refcount),
 	       atomic_read(&sec->ps_nctx),
@@ -949,7 +942,7 @@
 	else
 		flush_spec_ctx_cache_kr(sec, uid, grace, force);
 
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -959,7 +952,6 @@
 	struct hlist_head	freelist = HLIST_HEAD_INIT;
 	struct hlist_node      *next;
 	struct ptlrpc_cli_ctx  *ctx;
-	ENTRY;
 
 	CWARN("running gc\n");
 
@@ -981,8 +973,6 @@
 	spin_unlock(&sec->ps_lock);
 
 	dispose_ctx_list_kr(&freelist);
-	EXIT;
-	return;
 }
 
 static
@@ -993,7 +983,6 @@
 	struct ptlrpc_cli_ctx  *ctx;
 	struct gss_cli_ctx     *gctx;
 	time_t		  now = cfs_time_current_sec();
-	ENTRY;
 
 	spin_lock(&sec->ps_lock);
 	hlist_for_each_entry_safe(ctx, next,
@@ -1032,7 +1021,7 @@
 	}
 	spin_unlock(&sec->ps_lock);
 
-	RETURN(0);
+	return 0;
 }
 
 /****************************************
@@ -1148,16 +1137,15 @@
 int gss_kt_instantiate(struct key *key, const void *data, size_t datalen)
 {
 	int	     rc;
-	ENTRY;
 
 	if (data != NULL || datalen != 0) {
 		CERROR("invalid: data %p, len %lu\n", data, (long)datalen);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (key->payload.data != 0) {
 		CERROR("key already have payload\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* link the key to session keyring, so following context negotiation
@@ -1179,11 +1167,11 @@
 		CERROR("failed to link key %08x to keyring %08x: %d\n",
 		       key->serial,
 		       key_tgcred(current)->session_keyring->serial, rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	CDEBUG(D_SEC, "key %p instantiated, ctx %p\n", key, key->payload.data);
-	RETURN(0);
+	return 0;
 }
 
 /*
@@ -1198,11 +1186,10 @@
 	rawobj_t		 tmpobj = RAWOBJ_EMPTY;
 	__u32		    datalen32 = (__u32) datalen;
 	int		      rc;
-	ENTRY;
 
 	if (data == NULL || datalen == 0) {
 		CWARN("invalid: data %p, len %lu\n", data, (long)datalen);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	/* if upcall finished negotiation too fast (mostly likely because
@@ -1216,9 +1203,9 @@
 
 		rc = key_validate(key);
 		if (rc == 0)
-			RETURN(-EAGAIN);
+			return -EAGAIN;
 		else
-			RETURN(rc);
+			return rc;
 	}
 
 	LASSERT(atomic_read(&ctx->cc_refcount) > 0);
@@ -1229,7 +1216,7 @@
 	/* don't proceed if already refreshed */
 	if (cli_ctx_is_refreshed(ctx)) {
 		CWARN("ctx already done refresh\n");
-		RETURN(0);
+		return 0;
 	}
 
 	sptlrpc_cli_ctx_get(ctx);
@@ -1304,7 +1291,7 @@
 
 	/* let user space think it's a success */
 	sptlrpc_cli_ctx_put(ctx, 1);
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -1316,10 +1303,8 @@
 static
 void gss_kt_destroy(struct key *key)
 {
-	ENTRY;
 	LASSERT(key->payload.data == NULL);
 	CDEBUG(D_SEC, "destroy key %p\n", key);
-	EXIT;
 }
 
 static
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
index 4b28931..c106a9e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_krb5_mech.c
@@ -54,6 +54,7 @@
 #include <linux/slab.h>
 #include <linux/crypto.h>
 #include <linux/mutex.h>
+#include <linux/crypto.h>
 
 #include <obd.h>
 #include <obd_class.h>
@@ -147,14 +148,14 @@
 static
 int keyblock_init(struct krb5_keyblock *kb, char *alg_name, int alg_mode)
 {
-	kb->kb_tfm = ll_crypto_alloc_blkcipher(alg_name, alg_mode, 0);
+	kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
 	if (IS_ERR(kb->kb_tfm)) {
 		CERROR("failed to alloc tfm: %s, mode %d\n",
 		       alg_name, alg_mode);
 		return -1;
 	}
 
-	if (ll_crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
+	if (crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
 		CERROR("failed to set %s key, len %d\n",
 		       alg_name, kb->kb_key.len);
 		return -1;
@@ -197,7 +198,7 @@
 {
 	rawobj_free(&kb->kb_key);
 	if (kb->kb_tfm)
-		ll_crypto_free_blkcipher(kb->kb_tfm);
+		crypto_free_blkcipher(kb->kb_tfm);
 }
 
 static
@@ -341,7 +342,7 @@
 	if (p != end)
 		goto out_err;
 
-	CDEBUG(D_SEC, "succesfully imported rfc1964 context\n");
+	CDEBUG(D_SEC, "successfully imported rfc1964 context\n");
 	return 0;
 out_err:
 	return GSS_S_FAILURE;
@@ -403,7 +404,7 @@
 	if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
 		goto out_err;
 
-	CDEBUG(D_SEC, "succesfully imported v2 context\n");
+	CDEBUG(D_SEC, "successfully imported v2 context\n");
 	return 0;
 out_err:
 	return GSS_S_FAILURE;
@@ -494,7 +495,7 @@
 		goto out_err;
 
 	gctx_new->internal_ctx_id = knew;
-	CDEBUG(D_SEC, "succesfully copied reverse context\n");
+	CDEBUG(D_SEC, "successfully copied reverse context\n");
 	return GSS_S_COMPLETE;
 
 out_err:
@@ -529,7 +530,7 @@
 }
 
 static
-__u32 krb5_encrypt(struct ll_crypto_cipher *tfm,
+__u32 krb5_encrypt(struct crypto_blkcipher *tfm,
 		   int decrypt,
 		   void * iv,
 		   void * in,
@@ -546,27 +547,27 @@
 	desc.info = local_iv;
 	desc.flags= 0;
 
-	if (length % ll_crypto_blkcipher_blocksize(tfm) != 0) {
+	if (length % crypto_blkcipher_blocksize(tfm) != 0) {
 		CERROR("output length %d mismatch blocksize %d\n",
-		       length, ll_crypto_blkcipher_blocksize(tfm));
+		       length, crypto_blkcipher_blocksize(tfm));
 		goto out;
 	}
 
-	if (ll_crypto_blkcipher_ivsize(tfm) > 16) {
-		CERROR("iv size too large %d\n", ll_crypto_blkcipher_ivsize(tfm));
+	if (crypto_blkcipher_ivsize(tfm) > 16) {
+		CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
 		goto out;
 	}
 
 	if (iv)
-		memcpy(local_iv, iv, ll_crypto_blkcipher_ivsize(tfm));
+		memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
 
 	memcpy(out, in, length);
 	buf_to_sg(&sg, out, length);
 
 	if (decrypt)
-		ret = ll_crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
+		ret = crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
 	else
-		ret = ll_crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
+		ret = crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
 
 out:
 	return(ret);
@@ -574,7 +575,7 @@
 
 
 static inline
-int krb5_digest_hmac(struct ll_crypto_hash *tfm,
+int krb5_digest_hmac(struct crypto_hash *tfm,
 		     rawobj_t *key,
 		     struct krb5_header *khdr,
 		     int msgcnt, rawobj_t *msgs,
@@ -585,17 +586,17 @@
 	struct scatterlist sg[1];
 	int		i;
 
-	ll_crypto_hash_setkey(tfm, key->data, key->len);
+	crypto_hash_setkey(tfm, key->data, key->len);
 	desc.tfm  = tfm;
 	desc.flags= 0;
 
-	ll_crypto_hash_init(&desc);
+	crypto_hash_init(&desc);
 
 	for (i = 0; i < msgcnt; i++) {
 		if (msgs[i].len == 0)
 			continue;
 		buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
-		ll_crypto_hash_update(&desc, sg, msgs[i].len);
+		crypto_hash_update(&desc, sg, msgs[i].len);
 	}
 
 	for (i = 0; i < iovcnt; i++) {
@@ -604,20 +605,20 @@
 
 		sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
 			    iovs[i].kiov_offset);
-		ll_crypto_hash_update(&desc, sg, iovs[i].kiov_len);
+		crypto_hash_update(&desc, sg, iovs[i].kiov_len);
 	}
 
 	if (khdr) {
 		buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
-		ll_crypto_hash_update(&desc, sg, sizeof(*khdr));
+		crypto_hash_update(&desc, sg, sizeof(*khdr));
 	}
 
-	return ll_crypto_hash_final(&desc, cksum->data);
+	return crypto_hash_final(&desc, cksum->data);
 }
 
 
 static inline
-int krb5_digest_norm(struct ll_crypto_hash *tfm,
+int krb5_digest_norm(struct crypto_hash *tfm,
 		     struct krb5_keyblock *kb,
 		     struct krb5_header *khdr,
 		     int msgcnt, rawobj_t *msgs,
@@ -632,13 +633,13 @@
 	desc.tfm  = tfm;
 	desc.flags= 0;
 
-	ll_crypto_hash_init(&desc);
+	crypto_hash_init(&desc);
 
 	for (i = 0; i < msgcnt; i++) {
 		if (msgs[i].len == 0)
 			continue;
 		buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
-		ll_crypto_hash_update(&desc, sg, msgs[i].len);
+		crypto_hash_update(&desc, sg, msgs[i].len);
 	}
 
 	for (i = 0; i < iovcnt; i++) {
@@ -647,15 +648,15 @@
 
 		sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
 			    iovs[i].kiov_offset);
-		ll_crypto_hash_update(&desc, sg, iovs[i].kiov_len);
+		crypto_hash_update(&desc, sg, iovs[i].kiov_len);
 	}
 
 	if (khdr) {
 		buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
-		ll_crypto_hash_update(&desc, sg, sizeof(*khdr));
+		crypto_hash_update(&desc, sg, sizeof(*khdr));
 	}
 
-	ll_crypto_hash_final(&desc, cksum->data);
+	crypto_hash_final(&desc, cksum->data);
 
 	return krb5_encrypt(kb->kb_tfm, 0, NULL, cksum->data,
 			    cksum->data, cksum->len);
@@ -674,7 +675,7 @@
 			 rawobj_t *cksum)
 {
 	struct krb5_enctype   *ke = &enctypes[enctype];
-	struct ll_crypto_hash *tfm;
+	struct crypto_hash *tfm;
 	__u32		  code = GSS_S_FAILURE;
 	int		    rc;
 
@@ -683,7 +684,7 @@
 		return GSS_S_FAILURE;
 	}
 
-	cksum->len = ll_crypto_hash_digestsize(tfm);
+	cksum->len = crypto_hash_digestsize(tfm);
 	OBD_ALLOC_LARGE(cksum->data, cksum->len);
 	if (!cksum->data) {
 		cksum->len = 0;
@@ -700,7 +701,7 @@
 	if (rc == 0)
 		code = GSS_S_COMPLETE;
 out_tfm:
-	ll_crypto_free_hash(tfm);
+	crypto_free_hash(tfm);
 	return code;
 }
 
@@ -878,7 +879,7 @@
 }
 
 static
-int krb5_encrypt_rawobjs(struct ll_crypto_cipher *tfm,
+int krb5_encrypt_rawobjs(struct crypto_blkcipher *tfm,
 			 int mode_ecb,
 			 int inobj_cnt,
 			 rawobj_t *inobjs,
@@ -890,7 +891,6 @@
 	__u8		  local_iv[16] = {0}, *buf;
 	__u32		 datalen = 0;
 	int		   i, rc;
-	ENTRY;
 
 	buf = outobj->data;
 	desc.tfm  = tfm;
@@ -905,23 +905,23 @@
 
 		if (mode_ecb) {
 			if (enc)
-				rc = ll_crypto_blkcipher_encrypt(
+				rc = crypto_blkcipher_encrypt(
 					&desc, &dst, &src, src.length);
 			else
-				rc = ll_crypto_blkcipher_decrypt(
+				rc = crypto_blkcipher_decrypt(
 					&desc, &dst, &src, src.length);
 		} else {
 			if (enc)
-				rc = ll_crypto_blkcipher_encrypt_iv(
+				rc = crypto_blkcipher_encrypt_iv(
 					&desc, &dst, &src, src.length);
 			else
-				rc = ll_crypto_blkcipher_decrypt_iv(
+				rc = crypto_blkcipher_decrypt_iv(
 					&desc, &dst, &src, src.length);
 		}
 
 		if (rc) {
 			CERROR("encrypt error %d\n", rc);
-			RETURN(rc);
+			return rc;
 		}
 
 		datalen += inobjs[i].len;
@@ -929,14 +929,14 @@
 	}
 
 	outobj->len = datalen;
-	RETURN(0);
+	return 0;
 }
 
 /*
  * if adj_nob != 0, we adjust desc->bd_nob to the actual cipher text size.
  */
 static
-int krb5_encrypt_bulk(struct ll_crypto_cipher *tfm,
+int krb5_encrypt_bulk(struct crypto_blkcipher *tfm,
 		      struct krb5_header *khdr,
 		      char *confounder,
 		      struct ptlrpc_bulk_desc *desc,
@@ -951,7 +951,7 @@
 	LASSERT(desc->bd_iov_count);
 	LASSERT(desc->bd_enc_iov);
 
-	blocksize = ll_crypto_blkcipher_blocksize(tfm);
+	blocksize = crypto_blkcipher_blocksize(tfm);
 	LASSERT(blocksize > 1);
 	LASSERT(cipher->len == blocksize + sizeof(*khdr));
 
@@ -963,7 +963,7 @@
 	buf_to_sg(&src, confounder, blocksize);
 	buf_to_sg(&dst, cipher->data, blocksize);
 
-	rc = ll_crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src, blocksize);
+	rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src, blocksize);
 	if (rc) {
 		CERROR("error to encrypt confounder: %d\n", rc);
 		return rc;
@@ -983,7 +983,7 @@
 		desc->bd_enc_iov[i].kiov_offset = dst.offset;
 		desc->bd_enc_iov[i].kiov_len = dst.length;
 
-		rc = ll_crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
+		rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
 						    src.length);
 		if (rc) {
 			CERROR("error to encrypt page: %d\n", rc);
@@ -995,7 +995,7 @@
 	buf_to_sg(&src, khdr, sizeof(*khdr));
 	buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
 
-	rc = ll_crypto_blkcipher_encrypt_iv(&ciph_desc,
+	rc = crypto_blkcipher_encrypt_iv(&ciph_desc,
 					    &dst, &src, sizeof(*khdr));
 	if (rc) {
 		CERROR("error to encrypt krb5 header: %d\n", rc);
@@ -1025,7 +1025,7 @@
  *   should have been done by prep_bulk().
  */
 static
-int krb5_decrypt_bulk(struct ll_crypto_cipher *tfm,
+int krb5_decrypt_bulk(struct crypto_blkcipher *tfm,
 		      struct krb5_header *khdr,
 		      struct ptlrpc_bulk_desc *desc,
 		      rawobj_t *cipher,
@@ -1042,7 +1042,7 @@
 	LASSERT(desc->bd_enc_iov);
 	LASSERT(desc->bd_nob_transferred);
 
-	blocksize = ll_crypto_blkcipher_blocksize(tfm);
+	blocksize = crypto_blkcipher_blocksize(tfm);
 	LASSERT(blocksize > 1);
 	LASSERT(cipher->len == blocksize + sizeof(*khdr));
 
@@ -1059,7 +1059,7 @@
 	buf_to_sg(&src, cipher->data, blocksize);
 	buf_to_sg(&dst, plain->data, blocksize);
 
-	rc = ll_crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src, blocksize);
+	rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src, blocksize);
 	if (rc) {
 		CERROR("error to decrypt confounder: %d\n", rc);
 		return rc;
@@ -1102,7 +1102,7 @@
 		if (desc->bd_iov[i].kiov_len % blocksize == 0)
 			sg_assign_page(&dst, desc->bd_iov[i].kiov_page);
 
-		rc = ll_crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
+		rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
 						    src.length);
 		if (rc) {
 			CERROR("error to decrypt page: %d\n", rc);
@@ -1142,7 +1142,7 @@
 	buf_to_sg(&src, cipher->data + blocksize, sizeof(*khdr));
 	buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
 
-	rc = ll_crypto_blkcipher_decrypt_iv(&ciph_desc,
+	rc = crypto_blkcipher_decrypt_iv(&ciph_desc,
 					    &dst, &src, sizeof(*khdr));
 	if (rc) {
 		CERROR("error to decrypt tail: %d\n", rc);
@@ -1177,7 +1177,7 @@
 	LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
 	LASSERT(kctx->kc_keye.kb_tfm == NULL ||
 		ke->ke_conf_size >=
-		ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
+		crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
 
 	/*
 	 * final token format:
@@ -1201,7 +1201,7 @@
 		blocksize = 1;
 	} else {
 		LASSERT(kctx->kc_keye.kb_tfm);
-		blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+		blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
 	}
 	LASSERT(blocksize <= ke->ke_conf_size);
 
@@ -1248,7 +1248,7 @@
 
 	if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
 		rawobj_t		 arc4_keye;
-		struct ll_crypto_cipher *arc4_tfm;
+		struct crypto_blkcipher *arc4_tfm;
 
 		if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
 				       NULL, 1, &cksum, 0, NULL, &arc4_keye)) {
@@ -1256,13 +1256,13 @@
 			GOTO(arc4_out, rc = -EACCES);
 		}
 
-		arc4_tfm = ll_crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
+		arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
 		if (IS_ERR(arc4_tfm)) {
 			CERROR("failed to alloc tfm arc4 in ECB mode\n");
 			GOTO(arc4_out_key, rc = -EACCES);
 		}
 
-		if (ll_crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
+		if (crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
 					       arc4_keye.len)) {
 			CERROR("failed to set arc4 key, len %d\n",
 			       arc4_keye.len);
@@ -1272,7 +1272,7 @@
 		rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
 					  3, data_desc, &cipher, 1);
 arc4_out_tfm:
-		ll_crypto_free_blkcipher(arc4_tfm);
+		crypto_free_blkcipher(arc4_tfm);
 arc4_out_key:
 		rawobj_free(&arc4_keye);
 arc4_out:
@@ -1310,7 +1310,7 @@
 	LASSERT(desc->bd_enc_iov);
 	LASSERT(kctx->kc_keye.kb_tfm);
 
-	blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+	blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
 
 	for (i = 0; i < desc->bd_iov_count; i++) {
 		LASSERT(desc->bd_enc_iov[i].kiov_page);
@@ -1371,7 +1371,7 @@
 		blocksize = 1;
 	} else {
 		LASSERT(kctx->kc_keye.kb_tfm);
-		blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+		blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
 	}
 
 	/*
@@ -1481,7 +1481,7 @@
 		blocksize = 1;
 	} else {
 		LASSERT(kctx->kc_keye.kb_tfm);
-		blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+		blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
 	}
 
 	/* expected token layout:
@@ -1521,7 +1521,7 @@
 
 	if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
 		rawobj_t		 arc4_keye;
-		struct ll_crypto_cipher *arc4_tfm;
+		struct crypto_blkcipher *arc4_tfm;
 
 		cksum.data = token->data + token->len - ke->ke_hash_size;
 		cksum.len = ke->ke_hash_size;
@@ -1532,13 +1532,13 @@
 			GOTO(arc4_out, rc = -EACCES);
 		}
 
-		arc4_tfm = ll_crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
+		arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
 		if (IS_ERR(arc4_tfm)) {
 			CERROR("failed to alloc tfm arc4 in ECB mode\n");
 			GOTO(arc4_out_key, rc = -EACCES);
 		}
 
-		if (ll_crypto_blkcipher_setkey(arc4_tfm,
+		if (crypto_blkcipher_setkey(arc4_tfm,
 					 arc4_keye.data, arc4_keye.len)) {
 			CERROR("failed to set arc4 key, len %d\n",
 			       arc4_keye.len);
@@ -1548,7 +1548,7 @@
 		rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
 					  1, &cipher_in, &plain_out, 0);
 arc4_out_tfm:
-		ll_crypto_free_blkcipher(arc4_tfm);
+		crypto_free_blkcipher(arc4_tfm);
 arc4_out_key:
 		rawobj_free(&arc4_keye);
 arc4_out:
@@ -1647,7 +1647,7 @@
 		LBUG();
 	} else {
 		LASSERT(kctx->kc_keye.kb_tfm);
-		blocksize = ll_crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
+		blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
 	}
 	LASSERT(sizeof(*khdr) >= blocksize && sizeof(*khdr) % blocksize == 0);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
index 3df7257..c624518 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_pipefs.c
@@ -262,7 +262,6 @@
 	struct hlist_node     *next;
 	HLIST_HEAD(freelist);
 	unsigned int hash;
-	ENTRY;
 
 	gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base);
 
@@ -287,7 +286,6 @@
 	spin_unlock(&gsec->gs_base.ps_lock);
 
 	ctx_list_destroy_pf(&freelist);
-	EXIT;
 }
 
 static
@@ -297,23 +295,22 @@
 	struct vfs_cred	  vcred;
 	struct ptlrpc_cli_ctx   *cli_ctx;
 	int		      rc;
-	ENTRY;
 
 	vcred.vc_uid = 0;
 	vcred.vc_gid = 0;
 
 	cli_ctx = ctx_create_pf(&gsec->gs_base, &vcred);
 	if (!cli_ctx)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	rc = gss_copy_rvc_cli_ctx(cli_ctx, svc_ctx);
 	if (rc) {
 		ctx_destroy_pf(cli_ctx->cc_sec, cli_ctx);
-		RETURN(rc);
+		return rc;
 	}
 
 	gss_sec_ctx_replace_pf(gsec, cli_ctx);
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -324,7 +321,6 @@
 	struct ptlrpc_cli_ctx   *ctx;
 	struct hlist_node       *next;
 	int i;
-	ENTRY;
 
 	sec = &gsec_pf->gsp_base.gs_base;
 
@@ -337,7 +333,6 @@
 	}
 
 	sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
-	EXIT;
 }
 
 static
@@ -347,7 +342,6 @@
 {
 	struct gss_sec_pipefs   *gsec_pf;
 	int		      alloc_size, hash_size, i;
-	ENTRY;
 
 #define GSS_SEC_PIPEFS_CTX_HASH_SIZE    (32)
 
@@ -362,7 +356,7 @@
 
 	OBD_ALLOC(gsec_pf, alloc_size);
 	if (!gsec_pf)
-		RETURN(NULL);
+		return NULL;
 
 	gsec_pf->gsp_chash_size = hash_size;
 	for (i = 0; i < hash_size; i++)
@@ -380,13 +374,13 @@
 			goto err_destroy;
 	}
 
-	RETURN(&gsec_pf->gsp_base.gs_base);
+	return &gsec_pf->gsp_base.gs_base;
 
 err_destroy:
 	gss_sec_destroy_common(&gsec_pf->gsp_base);
 err_free:
 	OBD_FREE(gsec_pf, alloc_size);
-	RETURN(NULL);
+	return NULL;
 }
 
 static
@@ -423,7 +417,6 @@
 	struct hlist_node       *next;
 	HLIST_HEAD(freelist);
 	unsigned int	    hash, gc = 0, found = 0;
-	ENTRY;
 
 	might_sleep();
 
@@ -473,7 +466,7 @@
 		/* don't allocate for reverse sec */
 		if (sec_is_reverse(sec)) {
 			spin_unlock(&sec->ps_lock);
-			RETURN(NULL);
+			return NULL;
 		}
 
 		if (new) {
@@ -504,7 +497,7 @@
 	}
 
 	ctx_list_destroy_pf(&freelist);
-	RETURN(ctx);
+	return ctx;
 }
 
 static
@@ -545,7 +538,6 @@
 	struct hlist_node       *next;
 	HLIST_HEAD(freelist);
 	int i, busy = 0;
-	ENTRY;
 
 	might_sleep_if(grace);
 
@@ -584,7 +576,7 @@
 	spin_unlock(&sec->ps_lock);
 
 	ctx_list_destroy_pf(&freelist);
-	RETURN(busy);
+	return busy;
 }
 
 /****************************************
@@ -704,11 +696,9 @@
 static
 void gss_release_msg(struct gss_upcall_msg *gmsg)
 {
-	ENTRY;
 	LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
 
 	if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
-		EXIT;
 		return;
 	}
 
@@ -721,7 +711,6 @@
 	LASSERT(list_empty(&gmsg->gum_list));
 	LASSERT(list_empty(&gmsg->gum_base.list));
 	OBD_FREE_PTR(gmsg);
-	EXIT;
 }
 
 static
@@ -809,19 +798,18 @@
 	char *data = (char *)msg->data + msg->copied;
 	ssize_t mlen = msg->len;
 	ssize_t left;
-	ENTRY;
 
 	if (mlen > buflen)
 		mlen = buflen;
 	left = copy_to_user(dst, data, mlen);
 	if (left < 0) {
 		msg->errno = left;
-		RETURN(left);
+		return left;
 	}
 	mlen -= left;
 	msg->copied += mlen;
 	msg->errno = 0;
-	RETURN(mlen);
+	return mlen;
 }
 
 static
@@ -835,14 +823,13 @@
 	int		      datalen;
 	int		      timeout, rc;
 	__u32		    mechidx, seq, gss_err;
-	ENTRY;
 
 	mechidx = (__u32) (long) rpci->private;
 	LASSERT(mechidx < MECH_MAX);
 
 	OBD_ALLOC(buf, mlen);
 	if (!buf)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (copy_from_user(buf, src, mlen)) {
 		CERROR("failed copy user space data\n");
@@ -940,7 +927,7 @@
 	 * hack pipefs: always return asked length unless all following
 	 * downcalls might be messed up. */
 	rc = mlen;
-	RETURN(rc);
+	return rc;
 }
 
 static
@@ -949,13 +936,11 @@
 	struct gss_upcall_msg	  *gmsg;
 	struct gss_upcall_msg_data     *gumd;
 	static cfs_time_t	       ratelimit = 0;
-	ENTRY;
 
 	LASSERT(list_empty(&msg->list));
 
 	/* normally errno is >= 0 */
 	if (msg->errno >= 0) {
-		EXIT;
 		return;
 	}
 
@@ -980,7 +965,6 @@
 	}
 	gss_msg_fail_ctx(gmsg);
 	gss_release_msg(gmsg);
-	EXIT;
 }
 
 static
@@ -988,7 +972,6 @@
 {
 	struct rpc_inode *rpci = RPC_I(inode);
 	__u32	     idx;
-	ENTRY;
 
 	idx = (__u32) (long) rpci->private;
 	LASSERT(idx < MECH_MAX);
@@ -1020,7 +1003,6 @@
 		upcall_list_lock(idx);
 	}
 	upcall_list_unlock(idx);
-	EXIT;
 }
 
 static struct rpc_pipe_ops gss_upcall_ops = {
@@ -1041,7 +1023,6 @@
 	struct gss_sec	     *gsec;
 	struct gss_upcall_msg      *gmsg;
 	int			 rc = 0;
-	ENTRY;
 
 	might_sleep();
 
@@ -1052,14 +1033,14 @@
 	imp = ctx->cc_sec->ps_import;
 	if (!imp->imp_connection) {
 		CERROR("import has no connection set\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base);
 
 	OBD_ALLOC_PTR(gmsg);
 	if (!gmsg)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	/* initialize pipefs base msg */
 	INIT_LIST_HEAD(&gmsg->gum_base.list);
@@ -1107,10 +1088,10 @@
 		goto err_free;
 	}
 
-	RETURN(0);
+	return 0;
 err_free:
 	OBD_FREE_PTR(gmsg);
-	RETURN(rc);
+	return rc;
 }
 
 static
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c
index 474ecf8..fb298aef6 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_rawobj.c
@@ -65,7 +65,7 @@
 		OBD_ALLOC_LARGE(obj->data, len);
 		if (!obj->data) {
 			obj->len = 0;
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		}
 		memcpy(obj->data, buf, len);
 	} else
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
index 31b50ea..5b5365b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/gss_svc_upcall.c
@@ -259,8 +259,6 @@
 	struct rsi      rsii, *rsip = NULL;
 	time_t	  expiry;
 	int	     status = -EINVAL;
-	ENTRY;
-
 
 	memset(&rsii, 0, sizeof(rsii));
 
@@ -341,7 +339,7 @@
 
 	if (status)
 		CERROR("rsi parse error %d\n", status);
-	RETURN(status);
+	return status;
 }
 
 static struct cache_detail rsi_cache = {
@@ -662,7 +660,6 @@
 	struct cache_head **ch;
 	struct rsc *rscp;
 	int n;
-	ENTRY;
 
 	write_lock(&rsc_cache.hash_lock);
 	for (n = 0; n < RSC_HASHMAX; n++) {
@@ -684,7 +681,6 @@
 		}
 	}
 	write_unlock(&rsc_cache.hash_lock);
-	EXIT;
 }
 
 static int match_uid(struct rsc *rscp, long uid)
@@ -744,7 +740,6 @@
 	unsigned long   ctx_expiry;
 	__u32	   major;
 	int	     rc;
-	ENTRY;
 
 	memset(&rsci, 0, sizeof(rsci));
 
@@ -792,7 +787,7 @@
 	if (rc)
 		CERROR("create reverse svc ctx: idx "LPX64", rc %d\n",
 		       gsec->gs_rvs_hdl, rc);
-	RETURN(rc);
+	return rc;
 }
 
 int gss_svc_upcall_expire_rvs_ctx(rawobj_t *handle)
@@ -855,7 +850,6 @@
 	struct gss_rep_header     *rephdr;
 	int			first_check = 1;
 	int			rc = SECSVC_DROP;
-	ENTRY;
 
 	memset(&rsikey, 0, sizeof(rsikey));
 	rsikey.lustre_svc = lustre_svc;
@@ -1016,7 +1010,7 @@
 
 		COMPAT_RSC_PUT(&rsci->h, &rsc_cache);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 struct gss_svc_ctx *gss_svc_upcall_get_ctx(struct ptlrpc_request *req,
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c b/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c
index 3404000..de100a1 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/lproc_gss.c
@@ -199,15 +199,17 @@
 	gss_proc_root = lprocfs_register("gss", sptlrpc_proc_root,
 					 gss_lprocfs_vars, NULL);
 	if (IS_ERR(gss_proc_root)) {
+		rc = PTR_ERR(gss_proc_root);
 		gss_proc_root = NULL;
-		GOTO(err_out, rc = PTR_ERR(gss_proc_root));
+		GOTO(err_out, rc);
 	}
 
 	gss_proc_lk = lprocfs_register("lgss_keyring", gss_proc_root,
 				       gss_lk_lprocfs_vars, NULL);
 	if (IS_ERR(gss_proc_lk)) {
+		rc = PTR_ERR(gss_proc_lk);
 		gss_proc_lk = NULL;
-		GOTO(err_out, rc = PTR_ERR(gss_proc_root));
+		GOTO(err_out, rc);
 	}
 
 	return 0;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c b/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
index ebca858..b42ddda 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/gss/sec_gss.c
@@ -280,11 +280,10 @@
 	__u8		    *clear_buf;
 	int		      clear_buflen;
 	__u32		    major;
-	ENTRY;
 
 	if (msgbuf->lm_bufcount != 2) {
 		CERROR("invalid bufcount %d\n", msgbuf->lm_bufcount);
-		RETURN(GSS_S_FAILURE);
+		return GSS_S_FAILURE;
 	}
 
 	/* allocate a temporary clear text buffer, same sized as token,
@@ -292,7 +291,7 @@
 	clear_buflen = lustre_msg_buflen(msgbuf, 1);
 	OBD_ALLOC_LARGE(clear_buf, clear_buflen);
 	if (!clear_buf)
-		RETURN(GSS_S_FAILURE);
+		return GSS_S_FAILURE;
 
 	/* buffer objects */
 	hdrobj.len = lustre_msg_buflen(msgbuf, 0);
@@ -317,7 +316,7 @@
 	major = GSS_S_COMPLETE;
 out_free:
 	OBD_FREE_LARGE(clear_buf, clear_buflen);
-	RETURN(major);
+	return major;
 }
 
 /********************************************
@@ -646,7 +645,6 @@
 	struct gss_cli_ctx      *gctx = ctx2gctx(ctx);
 	__u32		    flags = 0, seq, svc;
 	int		      rc;
-	ENTRY;
 
 	LASSERT(req->rq_reqbuf);
 	LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
@@ -654,7 +652,7 @@
 
 	/* nothing to do for context negotiation RPCs */
 	if (req->rq_ctx_init)
-		RETURN(0);
+		return 0;
 
 	svc = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc);
 	if (req->rq_pack_bulk)
@@ -670,7 +668,7 @@
 			  flags, gctx->gc_proc, seq, svc,
 			  &gctx->gc_handle);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	/* gss_sign_msg() msg might take long time to finish, in which period
 	 * more rpcs could be wrapped up and sent out. if we found too many
@@ -689,7 +687,7 @@
 	}
 
 	req->rq_reqdata_len = rc;
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -765,7 +763,6 @@
 	struct lustre_msg      *msg = req->rq_repdata;
 	__u32		   major;
 	int		     pack_bulk, swabbed, rc = 0;
-	ENTRY;
 
 	LASSERT(req->rq_cli_ctx == ctx);
 	LASSERT(msg);
@@ -777,12 +774,12 @@
 	if (req->rq_ctx_init && !req->rq_early) {
 		req->rq_repmsg = lustre_msg_buf(msg, 1, 0);
 		req->rq_replen = msg->lm_buflens[1];
-		RETURN(0);
+		return 0;
 	}
 
 	if (msg->lm_bufcount < 2 || msg->lm_bufcount > 4) {
 		CERROR("unexpected bufcount %u\n", msg->lm_bufcount);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	swabbed = ptlrpc_rep_need_swab(req);
@@ -790,7 +787,7 @@
 	ghdr = gss_swab_header(msg, 0, swabbed);
 	if (ghdr == NULL) {
 		CERROR("can't decode gss header\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	/* sanity checks */
@@ -800,7 +797,7 @@
 	if (ghdr->gh_version != reqhdr->gh_version) {
 		CERROR("gss version %u mismatch, expect %u\n",
 		       ghdr->gh_version, reqhdr->gh_version);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	switch (ghdr->gh_proc) {
@@ -810,19 +807,19 @@
 		if (!req->rq_early && !equi(req->rq_pack_bulk == 1, pack_bulk)){
 			CERROR("%s bulk flag in reply\n",
 			       req->rq_pack_bulk ? "missing" : "unexpected");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (ghdr->gh_seq != reqhdr->gh_seq) {
 			CERROR("seqnum %u mismatch, expect %u\n",
 			       ghdr->gh_seq, reqhdr->gh_seq);
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (ghdr->gh_svc != reqhdr->gh_svc) {
 			CERROR("svc %u mismatch, expect %u\n",
 			       ghdr->gh_svc, reqhdr->gh_svc);
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (swabbed)
@@ -831,7 +828,7 @@
 		major = gss_verify_msg(msg, gctx->gc_mechctx, reqhdr->gh_svc);
 		if (major != GSS_S_COMPLETE) {
 			CERROR("failed to verify reply: %x\n", major);
-			RETURN(-EPERM);
+			return -EPERM;
 		}
 
 		if (req->rq_early && reqhdr->gh_svc == SPTLRPC_SVC_NULL) {
@@ -843,7 +840,7 @@
 			if (cksum != msg->lm_cksum) {
 				CWARN("early reply checksum mismatch: "
 				      "%08x != %08x\n", cksum, msg->lm_cksum);
-				RETURN(-EPROTO);
+				return -EPROTO;
 			}
 		}
 
@@ -852,13 +849,13 @@
 			if (msg->lm_bufcount < 3) {
 				CERROR("Invalid reply bufcount %u\n",
 				       msg->lm_bufcount);
-				RETURN(-EPROTO);
+				return -EPROTO;
 			}
 
 			rc = bulk_sec_desc_unpack(msg, 2, swabbed);
 			if (rc) {
 				CERROR("unpack bulk desc: %d\n", rc);
-				RETURN(rc);
+				return rc;
 			}
 		}
 
@@ -878,7 +875,7 @@
 		rc = -EPROTO;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 int gss_cli_ctx_seal(struct ptlrpc_cli_ctx *ctx,
@@ -889,7 +886,6 @@
 	struct gss_header       *ghdr;
 	__u32		    buflens[2], major;
 	int		      wiresize, rc;
-	ENTRY;
 
 	LASSERT(req->rq_clrbuf);
 	LASSERT(req->rq_cli_ctx == ctx);
@@ -915,7 +911,7 @@
 	} else {
 		OBD_ALLOC_LARGE(req->rq_reqbuf, wiresize);
 		if (!req->rq_reqbuf)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 		req->rq_reqbuf_len = wiresize;
 	}
 
@@ -969,7 +965,7 @@
 
 	/* now set the final wire data length */
 	req->rq_reqdata_len = lustre_shrink_msg(req->rq_reqbuf, 1, token.len,0);
-	RETURN(0);
+	return 0;
 
 err_free:
 	if (!req->rq_pool) {
@@ -977,7 +973,7 @@
 		req->rq_reqbuf = NULL;
 		req->rq_reqbuf_len = 0;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 int gss_cli_ctx_unseal(struct ptlrpc_cli_ctx *ctx,
@@ -988,7 +984,6 @@
 	struct lustre_msg       *msg = req->rq_repdata;
 	int		      msglen, pack_bulk, swabbed, rc;
 	__u32		    major;
-	ENTRY;
 
 	LASSERT(req->rq_cli_ctx == ctx);
 	LASSERT(req->rq_ctx_init == 0);
@@ -1000,14 +995,14 @@
 	ghdr = gss_swab_header(msg, 0, swabbed);
 	if (ghdr == NULL) {
 		CERROR("can't decode gss header\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	/* sanity checks */
 	if (ghdr->gh_version != PTLRPC_GSS_VERSION) {
 		CERROR("gss version %u mismatch, expect %u\n",
 		       ghdr->gh_version, PTLRPC_GSS_VERSION);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	switch (ghdr->gh_proc) {
@@ -1017,7 +1012,7 @@
 		if (!req->rq_early && !equi(req->rq_pack_bulk == 1, pack_bulk)){
 			CERROR("%s bulk flag in reply\n",
 			       req->rq_pack_bulk ? "missing" : "unexpected");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (swabbed)
@@ -1038,25 +1033,25 @@
 		swabbed = __lustre_unpack_msg(msg, msglen);
 		if (swabbed < 0) {
 			CERROR("Failed to unpack after decryption\n");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (msg->lm_bufcount < 1) {
 			CERROR("Invalid reply buffer: empty\n");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (pack_bulk) {
 			if (msg->lm_bufcount < 2) {
 				CERROR("bufcount %u: missing bulk sec desc\n",
 				       msg->lm_bufcount);
-				RETURN(-EPROTO);
+				return -EPROTO;
 			}
 
 			/* bulk checksum is the last segment */
 			if (bulk_sec_desc_unpack(msg, msg->lm_bufcount - 1,
 						 swabbed))
-				RETURN(-EPROTO);
+				return -EPROTO;
 		}
 
 		req->rq_repmsg = lustre_msg_buf(msg, 0, 0);
@@ -1077,7 +1072,7 @@
 		rc = -EPERM;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /*********************************************
@@ -1148,7 +1143,6 @@
 void gss_sec_destroy_common(struct gss_sec *gsec)
 {
 	struct ptlrpc_sec      *sec = &gsec->gs_base;
-	ENTRY;
 
 	LASSERT(sec->ps_import);
 	LASSERT(atomic_read(&sec->ps_refcount) == 0);
@@ -1163,8 +1157,6 @@
 
 	if (SPTLRPC_FLVR_BULK_SVC(sec->ps_flvr.sf_rpc) == SPTLRPC_BULK_SVC_PRIV)
 		sptlrpc_enc_pool_del_user();
-
-	EXIT;
 }
 
 void gss_sec_kill(struct ptlrpc_sec *sec)
@@ -1260,7 +1252,6 @@
 	int		       bufsize, txtsize;
 	int		       bufcnt = 2;
 	__u32		     buflens[5];
-	ENTRY;
 
 	/*
 	 * on-wire data layout:
@@ -1312,7 +1303,7 @@
 
 		OBD_ALLOC_LARGE(req->rq_reqbuf, bufsize);
 		if (!req->rq_reqbuf)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		req->rq_reqbuf_len = bufsize;
 	} else {
@@ -1331,7 +1322,7 @@
 	if (req->rq_pack_udesc)
 		sptlrpc_pack_user_desc(req->rq_reqbuf, 2);
 
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -1342,7 +1333,6 @@
 	__u32		     ibuflens[3], wbuflens[2];
 	int		       ibufcnt;
 	int		       clearsize, wiresize;
-	ENTRY;
 
 	LASSERT(req->rq_clrbuf == NULL);
 	LASSERT(req->rq_clrbuf_len == 0);
@@ -1399,7 +1389,7 @@
 
 		OBD_ALLOC_LARGE(req->rq_clrbuf, clearsize);
 		if (!req->rq_clrbuf)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 	}
 	req->rq_clrbuf_len = clearsize;
 
@@ -1409,7 +1399,7 @@
 	if (req->rq_pack_udesc)
 		sptlrpc_pack_user_desc(req->rq_clrbuf, 1);
 
-	RETURN(0);
+	return 0;
 }
 
 /*
@@ -1442,7 +1432,6 @@
 		     struct ptlrpc_request *req)
 {
 	int     privacy;
-	ENTRY;
 
 	LASSERT(!req->rq_pool || req->rq_reqbuf);
 	privacy = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc) == SPTLRPC_SVC_PRIV;
@@ -1471,8 +1460,6 @@
 		req->rq_reqbuf = NULL;
 		req->rq_reqbuf_len = 0;
 	}
-
-	EXIT;
 }
 
 static int do_alloc_repbuf(struct ptlrpc_request *req, int bufsize)
@@ -1578,7 +1565,6 @@
 		     int msgsize)
 {
 	int     svc = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc);
-	ENTRY;
 
 	LASSERT(!req->rq_pack_bulk ||
 		(req->rq_bulk_read || req->rq_bulk_write));
@@ -1697,7 +1683,7 @@
 
 		OBD_ALLOC_LARGE(newbuf, newbuf_size);
 		if (newbuf == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		memcpy(newbuf, req->rq_reqbuf, req->rq_reqbuf_len);
 
@@ -1717,7 +1703,7 @@
 	_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
 
 	req->rq_reqlen = newmsg_size;
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -1786,7 +1772,7 @@
 
 		OBD_ALLOC_LARGE(newclrbuf, newclrbuf_size);
 		if (newclrbuf == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		memcpy(newclrbuf, req->rq_clrbuf, req->rq_clrbuf_len);
 
@@ -1806,7 +1792,7 @@
 	_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
 	req->rq_reqlen = newmsg_size;
 
-	RETURN(0);
+	return 0;
 }
 
 int gss_enlarge_reqbuf(struct ptlrpc_sec *sec,
@@ -1891,7 +1877,6 @@
 {
 	__u32   flags = 0;
 	int     rc;
-	ENTRY;
 
 	LASSERT(rs->rs_msg == lustre_msg_buf(rs->rs_repbuf, 1, 0));
 
@@ -1906,7 +1891,7 @@
 			  LUSTRE_SP_ANY, flags, PTLRPC_GSS_PROC_DATA,
 			  grctx->src_wirectx.gw_seq, svc, NULL);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	rs->rs_repdata_len = rc;
 
@@ -1923,7 +1908,7 @@
 		req->rq_reply_off = 0;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int gss_pack_err_notify(struct ptlrpc_request *req, __u32 major, __u32 minor)
@@ -1933,10 +1918,9 @@
 	struct gss_err_header     *ghdr;
 	int			replen = sizeof(struct ptlrpc_body);
 	int			rc;
-	ENTRY;
 
 	//if (OBD_FAIL_CHECK_ORSET(OBD_FAIL_SVCGSS_ERR_NOTIFY, OBD_FAIL_ONCE))
-	//      RETURN(-EINVAL);
+	//      return -EINVAL;
 
 	grctx->src_err_notify = 1;
 	grctx->src_reserve_len = 0;
@@ -1944,7 +1928,7 @@
 	rc = lustre_pack_reply_v2(req, 1, &replen, NULL, 0);
 	if (rc) {
 		CERROR("could not pack reply, err %d\n", rc);
-		RETURN(rc);
+		return rc;
 	}
 
 	/* gss hdr */
@@ -1963,7 +1947,7 @@
 
 	CDEBUG(D_SEC, "prepare gss error notify(0x%x/0x%x) to %s\n",
 	       major, minor, libcfs_nid2str(req->rq_peer.nid));
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -1978,7 +1962,6 @@
 	__u32		      lustre_svc;
 	__u32		     *secdata, seclen;
 	int			swabbed, rc;
-	ENTRY;
 
 	CDEBUG(D_SEC, "processing gss init(%d) request from %s\n", gw->gw_proc,
 	       libcfs_nid2str(req->rq_peer.nid));
@@ -1987,18 +1970,18 @@
 
 	if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
 		CERROR("unexpected bulk flag\n");
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	if (gw->gw_proc == PTLRPC_GSS_PROC_INIT && gw->gw_handle.len != 0) {
 		CERROR("proc %u: invalid handle length %u\n",
 		       gw->gw_proc, gw->gw_handle.len);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	if (reqbuf->lm_bufcount < 3 || reqbuf->lm_bufcount > 4){
 		CERROR("Invalid bufcount %d\n", reqbuf->lm_bufcount);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	swabbed = ptlrpc_req_need_swab(req);
@@ -2009,7 +1992,7 @@
 
 	if (seclen < 4 + 4) {
 		CERROR("sec size %d too small\n", seclen);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	/* lustre svc type */
@@ -2020,7 +2003,7 @@
 	 * because touched internal structure of obd_uuid */
 	if (rawobj_extract(&uuid_obj, &secdata, &seclen)) {
 		CERROR("failed to extract target uuid\n");
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 	uuid_obj.data[uuid_obj.len - 1] = '\0';
 
@@ -2030,25 +2013,25 @@
 		CERROR("target '%s' is not available for context init (%s)\n",
 		       uuid->uuid, target == NULL ? "no target" :
 		       (target->obd_stopping ? "stopping" : "not set up"));
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	/* extract reverse handle */
 	if (rawobj_extract(&rvs_hdl, &secdata, &seclen)) {
 		CERROR("failed extract reverse handle\n");
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	/* extract token */
 	if (rawobj_extract(&in_token, &secdata, &seclen)) {
 		CERROR("can't extract token\n");
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	rc = gss_svc_upcall_handle_init(req, grctx, gw, target, lustre_svc,
 					&rvs_hdl, &in_token);
 	if (rc != SECSVC_OK)
-		RETURN(rc);
+		return rc;
 
 	if (grctx->src_ctx->gsc_usr_mds || grctx->src_ctx->gsc_usr_oss ||
 	    grctx->src_ctx->gsc_usr_root)
@@ -2064,11 +2047,11 @@
 	if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
 		if (reqbuf->lm_bufcount < 4) {
 			CERROR("missing user descriptor\n");
-			RETURN(SECSVC_DROP);
+			return SECSVC_DROP;
 		}
 		if (sptlrpc_unpack_user_desc(reqbuf, 2, swabbed)) {
 			CERROR("Mal-formed user descriptor\n");
-			RETURN(SECSVC_DROP);
+			return SECSVC_DROP;
 		}
 
 		req->rq_pack_udesc = 1;
@@ -2078,7 +2061,7 @@
 	req->rq_reqmsg = lustre_msg_buf(reqbuf, 1, 0);
 	req->rq_reqlen = lustre_msg_buflen(reqbuf, 1);
 
-	RETURN(rc);
+	return rc;
 }
 
 /*
@@ -2094,13 +2077,12 @@
 	struct lustre_msg  *msg = req->rq_reqbuf;
 	int		 offset = 2;
 	int		 swabbed;
-	ENTRY;
 
 	*major = GSS_S_COMPLETE;
 
 	if (msg->lm_bufcount < 2) {
 		CERROR("Too few segments (%u) in request\n", msg->lm_bufcount);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (gw->gw_svc == SPTLRPC_SVC_NULL)
@@ -2109,20 +2091,20 @@
 	if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 0)) {
 		CERROR("phase 0: discard replayed req: seq %u\n", gw->gw_seq);
 		*major = GSS_S_DUPLICATE_TOKEN;
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 	*major = gss_verify_msg(msg, gctx->gsc_mechctx, gw->gw_svc);
 	if (*major != GSS_S_COMPLETE) {
 		CERROR("failed to verify request: %x\n", *major);
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 	if (gctx->gsc_reverse == 0 &&
 	    gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) {
 		CERROR("phase 1+: discard replayed req: seq %u\n", gw->gw_seq);
 		*major = GSS_S_DUPLICATE_TOKEN;
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 verified:
@@ -2132,12 +2114,12 @@
 	if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
 		if (msg->lm_bufcount < (offset + 1)) {
 			CERROR("no user desc included\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (sptlrpc_unpack_user_desc(msg, offset, swabbed)) {
 			CERROR("Mal-formed user descriptor\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		req->rq_pack_udesc = 1;
@@ -2149,11 +2131,11 @@
 	if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
 		if (msg->lm_bufcount < (offset + 1)) {
 			CERROR("missing bulk sec descriptor\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (bulk_sec_desc_unpack(msg, offset, swabbed))
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		req->rq_pack_bulk = 1;
 		grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
@@ -2162,7 +2144,7 @@
 
 	req->rq_reqmsg = lustre_msg_buf(msg, 1, 0);
 	req->rq_reqlen = msg->lm_buflens[1];
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -2174,48 +2156,47 @@
 	struct gss_svc_ctx *gctx = grctx->src_ctx;
 	struct lustre_msg  *msg = req->rq_reqbuf;
 	int		 swabbed, msglen, offset = 1;
-	ENTRY;
 
 	if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 0)) {
 		CERROR("phase 0: discard replayed req: seq %u\n", gw->gw_seq);
 		*major = GSS_S_DUPLICATE_TOKEN;
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 	*major = gss_unseal_msg(gctx->gsc_mechctx, msg,
 			       &msglen, req->rq_reqdata_len);
 	if (*major != GSS_S_COMPLETE) {
 		CERROR("failed to unwrap request: %x\n", *major);
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 	if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 1)) {
 		CERROR("phase 1+: discard replayed req: seq %u\n", gw->gw_seq);
 		*major = GSS_S_DUPLICATE_TOKEN;
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 	swabbed = __lustre_unpack_msg(msg, msglen);
 	if (swabbed < 0) {
 		CERROR("Failed to unpack after decryption\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	req->rq_reqdata_len = msglen;
 
 	if (msg->lm_bufcount < 1) {
 		CERROR("Invalid buffer: is empty\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
 		if (msg->lm_bufcount < offset + 1) {
 			CERROR("no user descriptor included\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (sptlrpc_unpack_user_desc(msg, offset, swabbed)) {
 			CERROR("Mal-formed user descriptor\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		req->rq_pack_udesc = 1;
@@ -2226,11 +2207,11 @@
 	if (gw->gw_flags & LUSTRE_GSS_PACK_BULK) {
 		if (msg->lm_bufcount < offset + 1) {
 			CERROR("no bulk checksum included\n");
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 
 		if (bulk_sec_desc_unpack(msg, offset, swabbed))
-			RETURN(-EINVAL);
+			return -EINVAL;
 
 		req->rq_pack_bulk = 1;
 		grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
@@ -2239,7 +2220,7 @@
 
 	req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 0, 0);
 	req->rq_reqlen = req->rq_reqbuf->lm_buflens[0];
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -2249,7 +2230,6 @@
 	struct gss_svc_reqctx *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
 	__u32		  major = 0;
 	int		    rc = 0;
-	ENTRY;
 
 	grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw);
 	if (!grctx->src_ctx) {
@@ -2272,7 +2252,7 @@
 	}
 
 	if (rc == 0)
-		RETURN(SECSVC_OK);
+		return SECSVC_OK;
 
 	CERROR("svc %u failed: major 0x%08x: req xid "LPU64" ctx %p idx "
 	       LPX64"(%u->%s)\n", gw->gw_svc, major, req->rq_xid,
@@ -2283,9 +2263,9 @@
 	 * might happen after server reboot, to allow recovery. */
 	if ((major == GSS_S_NO_CONTEXT || major == GSS_S_BAD_SIG) &&
 	    gss_pack_err_notify(req, major, 0) == 0)
-		RETURN(SECSVC_COMPLETE);
+		return SECSVC_COMPLETE;
 
-	RETURN(SECSVC_DROP);
+	return SECSVC_DROP;
 }
 
 static
@@ -2294,7 +2274,6 @@
 {
 	struct gss_svc_reqctx  *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
 	__u32		   major;
-	ENTRY;
 
 	req->rq_ctx_fini = 1;
 	req->rq_no_reply = 1;
@@ -2302,16 +2281,16 @@
 	grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw);
 	if (!grctx->src_ctx) {
 		CDEBUG(D_SEC, "invalid gss context handle for destroy.\n");
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	if (gw->gw_svc != SPTLRPC_SVC_INTG) {
 		CERROR("svc %u is not supported in destroy.\n", gw->gw_svc);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	if (gss_svc_verify_request(req, grctx, gw, &major))
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 
 	CWARN("destroy svc ctx %p idx "LPX64" (%u->%s)\n",
 	      grctx->src_ctx, gss_handle_to_u64(&gw->gw_handle),
@@ -2322,19 +2301,19 @@
 	if (gw->gw_flags & LUSTRE_GSS_PACK_USER) {
 		if (req->rq_reqbuf->lm_bufcount < 4) {
 			CERROR("missing user descriptor, ignore it\n");
-			RETURN(SECSVC_OK);
+			return SECSVC_OK;
 		}
 		if (sptlrpc_unpack_user_desc(req->rq_reqbuf, 2,
 					     ptlrpc_req_need_swab(req))) {
 			CERROR("Mal-formed user descriptor, ignore it\n");
-			RETURN(SECSVC_OK);
+			return SECSVC_OK;
 		}
 
 		req->rq_pack_udesc = 1;
 		req->rq_user_desc = lustre_msg_buf(req->rq_reqbuf, 2, 0);
 	}
 
-	RETURN(SECSVC_OK);
+	return SECSVC_OK;
 }
 
 int gss_svc_accept(struct ptlrpc_sec_policy *policy, struct ptlrpc_request *req)
@@ -2343,14 +2322,13 @@
 	struct gss_svc_reqctx  *grctx;
 	struct gss_wire_ctx    *gw;
 	int		     swabbed, rc;
-	ENTRY;
 
 	LASSERT(req->rq_reqbuf);
 	LASSERT(req->rq_svc_ctx == NULL);
 
 	if (req->rq_reqbuf->lm_bufcount < 2) {
 		CERROR("buf count only %d\n", req->rq_reqbuf->lm_bufcount);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	swabbed = ptlrpc_req_need_swab(req);
@@ -2358,14 +2336,14 @@
 	ghdr = gss_swab_header(req->rq_reqbuf, 0, swabbed);
 	if (ghdr == NULL) {
 		CERROR("can't decode gss header\n");
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	/* sanity checks */
 	if (ghdr->gh_version != PTLRPC_GSS_VERSION) {
 		CERROR("gss version %u, expect %u\n", ghdr->gh_version,
 		       PTLRPC_GSS_VERSION);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	req->rq_sp_from = ghdr->gh_sp;
@@ -2373,7 +2351,7 @@
 	/* alloc grctx data */
 	OBD_ALLOC_PTR(grctx);
 	if (!grctx)
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 
 	grctx->src_base.sc_policy = sptlrpc_policy_get(policy);
 	atomic_set(&grctx->src_base.sc_refcount, 1);
@@ -2428,16 +2406,14 @@
 		break;
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 void gss_svc_invalidate_ctx(struct ptlrpc_svc_ctx *svc_ctx)
 {
 	struct gss_svc_reqctx  *grctx;
-	ENTRY;
 
 	if (svc_ctx == NULL) {
-		EXIT;
 		return;
 	}
 
@@ -2446,8 +2422,6 @@
 	CWARN("gss svc invalidate ctx %p(%u)\n",
 	      grctx->src_ctx, grctx->src_ctx->gsc_uid);
 	gss_svc_upcall_destroy_ctx(grctx->src_ctx);
-
-	EXIT;
 }
 
 static inline
@@ -2496,13 +2470,12 @@
 	__u32			ibuflens[2], buflens[4];
 	int			  ibufcnt = 0, bufcnt;
 	int			  txtsize, wmsg_size, rs_size;
-	ENTRY;
 
 	LASSERT(msglen % 8 == 0);
 
 	if (req->rq_pack_bulk && !req->rq_bulk_read && !req->rq_bulk_write) {
 		CERROR("client request bulk sec on non-bulk rpc\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	svc = SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc);
@@ -2575,7 +2548,7 @@
 	} else {
 		OBD_ALLOC_LARGE(rs, rs_size);
 		if (rs == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		rs->rs_size = rs_size;
 	}
@@ -2605,7 +2578,7 @@
 
 	LASSERT(rs->rs_msg);
 	req->rq_reply_state = rs;
-	RETURN(0);
+	return 0;
 }
 
 static int gss_svc_seal(struct ptlrpc_request *req,
@@ -2619,7 +2592,6 @@
 	int		      token_buflen;
 	__u32		    buflens[2], major;
 	int		      msglen, rc;
-	ENTRY;
 
 	/* get clear data length. note embedded lustre_msg might
 	 * have been shrinked */
@@ -2647,7 +2619,7 @@
 	token_buflen = gss_mech_payload(gctx->gsc_mechctx, msglen, 1);
 	OBD_ALLOC_LARGE(token_buf, token_buflen);
 	if (token_buf == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	hdrobj.len = PTLRPC_GSS_HEADER_SIZE;
 	hdrobj.data = (__u8 *) ghdr;
@@ -2703,7 +2675,7 @@
 	rc = 0;
 out_free:
 	OBD_FREE_LARGE(token_buf, token_buflen);
-	RETURN(rc);
+	return rc;
 }
 
 int gss_svc_authorize(struct ptlrpc_request *req)
@@ -2712,7 +2684,6 @@
 	struct gss_svc_reqctx     *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
 	struct gss_wire_ctx       *gw = &grctx->src_wirectx;
 	int			early, rc;
-	ENTRY;
 
 	early = (req->rq_packed_final == 0);
 
@@ -2720,7 +2691,7 @@
 		LASSERT(rs->rs_repdata_len != 0);
 
 		req->rq_reply_off = gss_at_reply_off_integ;
-		RETURN(0);
+		return 0;
 	}
 
 	/* early reply could happen in many cases */
@@ -2728,7 +2699,7 @@
 	    gw->gw_proc != PTLRPC_GSS_PROC_DATA &&
 	    gw->gw_proc != PTLRPC_GSS_PROC_DESTROY) {
 		CERROR("proc %d not support\n", gw->gw_proc);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	LASSERT(grctx->src_ctx);
@@ -2749,7 +2720,7 @@
 	rc = 0;
 
 out:
-	RETURN(rc);
+	return rc;
 }
 
 void gss_svc_free_rs(struct ptlrpc_reply_state *rs)
diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c
index 47a3c05..5ca69ae 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/import.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/import.c
@@ -195,7 +195,6 @@
 /* Must be called with imp_lock held! */
 static void ptlrpc_deactivate_and_unlock_import(struct obd_import *imp)
 {
-	ENTRY;
 	LASSERT(spin_is_locked(&imp->imp_lock));
 
 	CDEBUG(D_HA, "setting import %s INVALID\n", obd2cli_tgt(imp->imp_obd));
@@ -205,8 +204,6 @@
 
 	ptlrpc_abort_inflight(imp);
 	obd_import_event(imp->imp_obd, imp, IMP_EVENT_INACTIVE);
-
-	EXIT;
 }
 
 /*
@@ -394,8 +391,6 @@
 
 void ptlrpc_fail_import(struct obd_import *imp, __u32 conn_cnt)
 {
-	ENTRY;
-
 	LASSERT(!imp->imp_dlm_fake);
 
 	if (ptlrpc_set_import_discon(imp, conn_cnt)) {
@@ -417,7 +412,6 @@
 
 		ptlrpc_pinger_wake_up();
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_fail_import);
 
@@ -461,7 +455,6 @@
 	struct obd_export *dlmexp;
 	char *target_start;
 	int target_len, tried_all = 1;
-	ENTRY;
 
 	spin_lock(&imp->imp_lock);
 
@@ -469,7 +462,7 @@
 		CERROR("%s: no connections available\n",
 		       imp->imp_obd->obd_name);
 		spin_unlock(&imp->imp_lock);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	list_for_each_entry(conn, &imp->imp_conn_list, oic_item) {
@@ -558,7 +551,7 @@
 
 	spin_unlock(&imp->imp_lock);
 
-	RETURN(0);
+	return 0;
 }
 
 /*
@@ -602,21 +595,20 @@
 			 (char *)&imp->imp_connect_data };
 	struct ptlrpc_connect_async_args *aa;
 	int rc;
-	ENTRY;
 
 	spin_lock(&imp->imp_lock);
 	if (imp->imp_state == LUSTRE_IMP_CLOSED) {
 		spin_unlock(&imp->imp_lock);
 		CERROR("can't connect to a closed import\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	} else if (imp->imp_state == LUSTRE_IMP_FULL) {
 		spin_unlock(&imp->imp_lock);
 		CERROR("already connected\n");
-		RETURN(0);
+		return 0;
 	} else if (imp->imp_state == LUSTRE_IMP_CONNECTING) {
 		spin_unlock(&imp->imp_lock);
 		CERROR("already connecting\n");
-		RETURN(-EALREADY);
+		return -EALREADY;
 	}
 
 	IMPORT_SET_STATE_NOLOCK(imp, LUSTRE_IMP_CONNECTING);
@@ -716,7 +708,7 @@
 		IMPORT_SET_STATE(imp, LUSTRE_IMP_DISCON);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_connect_import);
 
@@ -756,13 +748,12 @@
 	struct obd_connect_data *ocd;
 	struct obd_export *exp;
 	int ret;
-	ENTRY;
 
 	spin_lock(&imp->imp_lock);
 	if (imp->imp_state == LUSTRE_IMP_CLOSED) {
 		imp->imp_connect_tried = 1;
 		spin_unlock(&imp->imp_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	if (rc) {
@@ -984,7 +975,7 @@
 			       imp->imp_connection->c_remote_uuid.uuid);
 			ptlrpc_connect_import(imp);
 			imp->imp_connect_tried = 1;
-			RETURN(0);
+			return 0;
 		}
 	} else {
 
@@ -1137,7 +1128,7 @@
 
 			/* reply message might not be ready */
 			if (request->rq_repmsg == NULL)
-				RETURN(-EPROTO);
+				return -EPROTO;
 
 			ocd = req_capsule_server_get(&request->rq_pill,
 						     &RMF_CONNECT_DATA);
@@ -1161,7 +1152,7 @@
 				ptlrpc_deactivate_import(imp);
 				IMPORT_SET_STATE(imp, LUSTRE_IMP_CLOSED);
 			}
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		ptlrpc_maybe_ping_import_soon(imp);
@@ -1172,7 +1163,7 @@
 	}
 
 	wake_up_all(&imp->imp_recovery_waitq);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1183,7 +1174,6 @@
 				      struct ptlrpc_request *req,
 				      void * data, int rc)
 {
-	ENTRY;
 	atomic_dec(&req->rq_import->imp_replay_inflight);
 	if (req->rq_status == 0 &&
 	    !req->rq_import->imp_vbr_failed) {
@@ -1202,7 +1192,7 @@
 		ptlrpc_connect_import(req->rq_import);
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1212,10 +1202,9 @@
 static int signal_completed_replay(struct obd_import *imp)
 {
 	struct ptlrpc_request *req;
-	ENTRY;
 
 	if (unlikely(OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_FINISH_REPLAY)))
-		RETURN(0);
+		return 0;
 
 	LASSERT(atomic_read(&imp->imp_replay_inflight) == 0);
 	atomic_inc(&imp->imp_replay_inflight);
@@ -1224,7 +1213,7 @@
 					OBD_PING);
 	if (req == NULL) {
 		atomic_dec(&imp->imp_replay_inflight);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	ptlrpc_request_set_replen(req);
@@ -1236,7 +1225,7 @@
 	req->rq_interpret_reply = completed_replay_interpret;
 
 	ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1248,8 +1237,6 @@
 {
 	struct obd_import *imp = data;
 
-	ENTRY;
-
 	unshare_fs_struct();
 
 	CDEBUG(D_HA, "thread invalidate import %s to %s@%s\n",
@@ -1267,7 +1254,7 @@
 	ptlrpc_import_recovery_state_machine(imp);
 
 	class_import_put(imp);
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1297,7 +1284,6 @@
 	char *target_start;
 	int target_len;
 
-	ENTRY;
 	if (imp->imp_state == LUSTRE_IMP_EVICTED) {
 		deuuidify(obd2cli_tgt(imp->imp_obd), NULL,
 			  &target_start, &target_len);
@@ -1319,7 +1305,7 @@
 		spin_unlock(&imp->imp_lock);
 
 		{
-		task_t *task;
+		struct task_struct *task;
 		/* bug 17802:  XXX client_disconnect_export vs connect request
 		 * race. if client will evicted at this time, we start
 		 * invalidate thread without reference to import and import can
@@ -1334,7 +1320,7 @@
 		} else {
 			rc = 0;
 		}
-		RETURN(rc);
+		return rc;
 		}
 	}
 
@@ -1393,7 +1379,7 @@
 	}
 
 out:
-	RETURN(rc);
+	return rc;
 }
 
 int ptlrpc_disconnect_import(struct obd_import *imp, int noclose)
@@ -1401,7 +1387,6 @@
 	struct ptlrpc_request *req;
 	int rq_opc, rc = 0;
 	int nowait = imp->imp_obd->obd_force;
-	ENTRY;
 
 	if (nowait)
 		GOTO(set_state, rc);
@@ -1413,7 +1398,7 @@
 	default:
 		CERROR("don't know how to disconnect from %s (connect_op %d)\n",
 		       obd2cli_tgt(imp->imp_obd), imp->imp_connect_op);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	if (ptlrpc_import_in_recovery(imp)) {
@@ -1476,21 +1461,17 @@
 	memset(&imp->imp_remote_handle, 0, sizeof(imp->imp_remote_handle));
 	spin_unlock(&imp->imp_lock);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_disconnect_import);
 
 void ptlrpc_cleanup_imp(struct obd_import *imp)
 {
-	ENTRY;
-
 	spin_lock(&imp->imp_lock);
 	IMPORT_SET_STATE_NOLOCK(imp, LUSTRE_IMP_CLOSED);
 	imp->imp_generation++;
 	spin_unlock(&imp->imp_lock);
 	ptlrpc_abort_inflight(imp);
-
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_cleanup_imp);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
index 367ca8e..379e594 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c
@@ -85,7 +85,6 @@
 	struct llog_ctxt      *ctxt = lgh->lgh_ctxt;
 	struct ptlrpc_request *req = NULL;
 	int		    rc;
-	ENTRY;
 
 	LLOG_CLIENT_ENTRY(ctxt, imp);
 
@@ -133,7 +132,6 @@
 
 	lgh->lgh_id = body->lgd_logid;
 	lgh->lgh_ctxt = ctxt;
-	EXIT;
 out:
 	LLOG_CLIENT_EXIT(ctxt, imp);
 	ptlrpc_req_finished(req);
@@ -147,7 +145,6 @@
 	struct ptlrpc_request *req = NULL;
 	struct llogd_body     *body;
 	int		    rc;
-	ENTRY;
 
 	LLOG_CLIENT_ENTRY(loghandle->lgh_ctxt, imp);
 	req = ptlrpc_request_alloc_pack(imp, &RQF_LLOG_ORIGIN_HANDLE_DESTROY,
@@ -170,7 +167,7 @@
 	ptlrpc_req_finished(req);
 err_exit:
 	LLOG_CLIENT_EXIT(loghandle->lgh_ctxt, imp);
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -184,7 +181,6 @@
 	struct llogd_body     *body;
 	void		  *ptr;
 	int		    rc;
-	ENTRY;
 
 	LLOG_CLIENT_ENTRY(loghandle->lgh_ctxt, imp);
 	req = ptlrpc_request_alloc_pack(imp, &RQF_LLOG_ORIGIN_HANDLE_NEXT_BLOCK,
@@ -221,7 +217,6 @@
 	*cur_offset = body->lgd_cur_offset;
 
 	memcpy(buf, ptr, len);
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 err_exit:
@@ -238,7 +233,6 @@
 	struct llogd_body     *body;
 	void		  *ptr;
 	int		    rc;
-	ENTRY;
 
 	LLOG_CLIENT_ENTRY(loghandle->lgh_ctxt, imp);
 	req = ptlrpc_request_alloc_pack(imp, &RQF_LLOG_ORIGIN_HANDLE_PREV_BLOCK,
@@ -270,7 +264,6 @@
 		GOTO(out, rc =-EFAULT);
 
 	memcpy(buf, ptr, len);
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 err_exit:
@@ -287,7 +280,6 @@
 	struct llog_log_hdr   *hdr;
 	struct llog_rec_hdr   *llh_hdr;
 	int		    rc;
-	ENTRY;
 
 	LLOG_CLIENT_ENTRY(handle->lgh_ctxt, imp);
 	req = ptlrpc_request_alloc_pack(imp,&RQF_LLOG_ORIGIN_HANDLE_READ_HEADER,
@@ -326,7 +318,6 @@
 		CERROR("you may need to re-run lconf --write_conf.\n");
 		rc = -EIO;
 	}
-	EXIT;
 out:
 	ptlrpc_req_finished(req);
 err_exit:
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c
index a81f557..17c06a3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_net.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_net.c
@@ -57,7 +57,6 @@
 int llog_initiator_connect(struct llog_ctxt *ctxt)
 {
 	struct obd_import *new_imp;
-	ENTRY;
 
 	LASSERT(ctxt);
 	new_imp = ctxt->loc_obd->u.cli.cl_import;
@@ -70,6 +69,6 @@
 		ctxt->loc_imp = class_import_get(new_imp);
 	}
 	mutex_unlock(&ctxt->loc_mutex);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(llog_initiator_connect);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_server.c b/drivers/staging/lustre/lustre/ptlrpc/llog_server.c
index bc1fcd8..af9d2ac 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/llog_server.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/llog_server.c
@@ -71,11 +71,9 @@
 	char			*name = NULL;
 	int			 rc;
 
-	ENTRY;
-
 	body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
 	if (body == NULL)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	if (ostid_id(&body->lgd_logid.lgl_oi) > 0)
 		logid = &body->lgd_logid;
@@ -83,7 +81,7 @@
 	if (req_capsule_field_present(&req->rq_pill, &RMF_NAME, RCL_CLIENT)) {
 		name = req_capsule_client_get(&req->rq_pill, &RMF_NAME);
 		if (name == NULL)
-			RETURN(-EFAULT);
+			return -EFAULT;
 		CDEBUG(D_INFO, "%s: opening log %s\n", obd->obd_name, name);
 	}
 
@@ -91,7 +89,7 @@
 	if (ctxt == NULL) {
 		CDEBUG(D_WARNING, "%s: no ctxt. group=%p idx=%d name=%s\n",
 		       obd->obd_name, &obd->obd_olg, body->lgd_ctxt_idx, name);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 	disk_obd = ctxt->loc_exp->exp_obd;
 	push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -108,7 +106,6 @@
 	body = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY);
 	body->lgd_logid = loghandle->lgh_id;
 
-	EXIT;
 out_close:
 	llog_origin_close(req->rq_svc_thread->t_env, loghandle);
 out_pop:
@@ -127,11 +124,9 @@
 	struct llog_ctxt	*ctxt;
 	int			 rc;
 
-	ENTRY;
-
 	body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
 	if (body == NULL)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	if (ostid_id(&body->lgd_logid.lgl_oi) > 0)
 		logid = &body->lgd_logid;
@@ -142,7 +137,7 @@
 
 	ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
 	if (ctxt == NULL)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	disk_obd = ctxt->loc_exp->exp_obd;
 	push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -153,7 +148,7 @@
 		rc = llog_erase(req->rq_svc_thread->t_env, ctxt, logid, NULL);
 	pop_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
 	llog_ctxt_put(ctxt);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(llog_origin_handle_destroy);
 
@@ -169,15 +164,13 @@
 	void		*ptr;
 	int		  rc;
 
-	ENTRY;
-
 	body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
 	if (body == NULL)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
 	if (ctxt == NULL)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	disk_obd = ctxt->loc_exp->exp_obd;
 	push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -208,7 +201,6 @@
 			     &repbody->lgd_cur_offset, ptr, LLOG_CHUNK_SIZE);
 	if (rc)
 		GOTO(out_close, rc);
-	EXIT;
 out_close:
 	llog_origin_close(req->rq_svc_thread->t_env, loghandle);
 out_pop:
@@ -230,15 +222,13 @@
 	void		 *ptr;
 	int		   rc;
 
-	ENTRY;
-
 	body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
 	if (body == NULL)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
 	if (ctxt == NULL)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	disk_obd = ctxt->loc_exp->exp_obd;
 	push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -269,7 +259,6 @@
 	if (rc)
 		GOTO(out_close, rc);
 
-	EXIT;
 out_close:
 	llog_origin_close(req->rq_svc_thread->t_env, loghandle);
 out_pop:
@@ -290,15 +279,13 @@
 	__u32		 flags;
 	int		   rc;
 
-	ENTRY;
-
 	body = req_capsule_client_get(&req->rq_pill, &RMF_LLOGD_BODY);
 	if (body == NULL)
-		RETURN(-EFAULT);
+		return -EFAULT;
 
 	ctxt = llog_get_context(req->rq_export->exp_obd, body->lgd_ctxt_idx);
 	if (ctxt == NULL)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	disk_obd = ctxt->loc_exp->exp_obd;
 	push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
@@ -324,7 +311,6 @@
 
 	hdr = req_capsule_server_get(&req->rq_pill, &RMF_LLOG_LOG_HDR);
 	*hdr = *loghandle->lgh_hdr;
-	EXIT;
 out_close:
 	llog_origin_close(req->rq_svc_thread->t_env, loghandle);
 out_pop:
@@ -336,9 +322,8 @@
 
 int llog_origin_handle_close(struct ptlrpc_request *req)
 {
-	ENTRY;
 	/* Nothing to do */
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(llog_origin_handle_close);
 
@@ -352,20 +337,19 @@
 	struct llog_handle *cathandle;
 	struct inode *inode;
 	void *handle;
-	ENTRY;
 
 	logcookies = req_capsule_client_get(&req->rq_pill, &RMF_LOGCOOKIES);
 	num_cookies = req_capsule_get_size(&req->rq_pill, &RMF_LOGCOOKIES,
 					   RCL_CLIENT) / sizeof(*logcookies);
 	if (logcookies == NULL || num_cookies == 0) {
 		DEBUG_REQ(D_HA, req, "No llog cookies sent");
-		RETURN(-EFAULT);
+		return -EFAULT;
 	}
 
 	ctxt = llog_get_context(req->rq_export->exp_obd,
 				logcookies->lgc_subsys);
 	if (ctxt == NULL)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
 	disk_obd = ctxt->loc_exp->exp_obd;
 	push_ctxt(&saved, &disk_obd->obd_lvfs_ctxt, NULL);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
index 3e73254..bea44a3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
@@ -302,7 +302,7 @@
 	 * hose a kernel by allowing the request history to grow too
 	 * far. */
 	bufpages = (svc->srv_buf_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if (val > num_physpages/(2 * bufpages))
+	if (val > totalram_pages / (2 * bufpages))
 		return -ERANGE;
 
 	spin_lock(&svc->srv_lock);
@@ -480,7 +480,6 @@
 	bool				hp = false;
 	int				i;
 	int				rc = 0;
-	ENTRY;
 
 	/**
 	 * Serialize NRS core lprocfs operations with policy registration/
@@ -613,7 +612,7 @@
 
 	mutex_unlock(&nrs_core.nrs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -638,7 +637,6 @@
 	char			       *cmd_copy = NULL;
 	char			       *token;
 	int				rc = 0;
-	ENTRY;
 
 	if (count >= LPROCFS_NRS_WR_MAX_CMD)
 		GOTO(out, rc = -EINVAL);
@@ -698,7 +696,7 @@
 	if (cmd_copy)
 		OBD_FREE(cmd_copy, LPROCFS_NRS_WR_MAX_CMD);
 
-	RETURN(rc < 0 ? rc : count);
+	return rc < 0 ? rc : count;
 }
 LPROC_SEQ_FOPS(ptlrpc_lprocfs_nrs);
 
@@ -1217,13 +1215,12 @@
 	struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
 	struct ptlrpc_request *req;
 	int		    rc;
-	ENTRY;
 
 	LPROCFS_CLIMP_CHECK(obd);
 	req = ptlrpc_prep_ping(obd->u.cli.cl_import);
 	LPROCFS_CLIMP_EXIT(obd);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req->rq_send_state = LUSTRE_IMP_FULL;
 
@@ -1231,8 +1228,8 @@
 
 	ptlrpc_req_finished(req);
 	if (rc >= 0)
-		RETURN(count);
-	RETURN(rc);
+		return count;
+	return rc;
 }
 EXPORT_SYMBOL(lprocfs_wr_ping);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
index de3f0db..a0e0097 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c
@@ -54,7 +54,6 @@
 {
 	int	      rc;
 	lnet_md_t	 md;
-	ENTRY;
 
 	LASSERT (portal != 0);
 	LASSERT (conn != NULL);
@@ -76,7 +75,7 @@
 	if (unlikely(rc != 0)) {
 		CERROR ("LNetMDBind failed: %d\n", rc);
 		LASSERT (rc == -ENOMEM);
-		RETURN (-ENOMEM);
+		return -ENOMEM;
 	}
 
 	CDEBUG(D_NET, "Sending %d bytes to portal %d, xid "LPD64", offset %u\n",
@@ -95,7 +94,7 @@
 		LASSERTF(rc2 == 0, "rc2 = %d\n", rc2);
 	}
 
-	RETURN (0);
+	return 0;
 }
 
 static void mdunlink_iterate_helper(lnet_handle_md_t *bd_mds, int count)
@@ -122,10 +121,9 @@
 	__u64 xid;
 	lnet_handle_me_t  me_h;
 	lnet_md_t	 md;
-	ENTRY;
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_BULK_GET_NET))
-		RETURN(0);
+		return 0;
 
 	/* NB no locking required until desc is on the network */
 	LASSERT(desc->bd_nob > 0);
@@ -207,7 +205,7 @@
 		LASSERT(desc->bd_md_count >= 0);
 		mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw);
 		req->rq_status = -ENOMEM;
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	/* Set rq_xid to matchbits of the final bulk so that server can
@@ -231,7 +229,7 @@
 	       desc->bd_iov_count, desc->bd_nob,
 	       desc->bd_last_xid, req->rq_xid, desc->bd_portal);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_register_bulk);
 
@@ -247,7 +245,6 @@
 	wait_queue_head_t	     *wq;
 	struct l_wait_info       lwi;
 	int		      rc;
-	ENTRY;
 
 	LASSERT(!in_interrupt());     /* might sleep */
 
@@ -257,7 +254,7 @@
 		req->rq_bulk_deadline = cfs_time_current_sec() + LONG_UNLINK;
 
 	if (ptlrpc_client_bulk_active(req) == 0)	/* completed or */
-		RETURN(1);				/* never registered */
+		return 1;				/* never registered */
 
 	LASSERT(desc->bd_req == req);  /* bd_req NULL until registered */
 
@@ -268,14 +265,14 @@
 	mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw);
 
 	if (ptlrpc_client_bulk_active(req) == 0)	/* completed or */
-		RETURN(1);				/* never registered */
+		return 1;				/* never registered */
 
 	/* Move to "Unregistering" phase as bulk was not unlinked yet. */
 	ptlrpc_rqphase_move(req, RQ_PHASE_UNREGISTERING);
 
 	/* Do not wait for unlink to finish. */
 	if (async)
-		RETURN(0);
+		return 0;
 
 	if (req->rq_set != NULL)
 		wq = &req->rq_set->set_waitq;
@@ -290,14 +287,14 @@
 		rc = l_wait_event(*wq, !ptlrpc_client_bulk_active(req), &lwi);
 		if (rc == 0) {
 			ptlrpc_rqphase_move(req, req->rq_next_phase);
-			RETURN(1);
+			return 1;
 		}
 
 		LASSERT(rc == -ETIMEDOUT);
 		DEBUG_REQ(D_WARNING, req, "Unexpectedly long timeout: desc %p",
 			  desc);
 	}
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_unregister_bulk);
 
@@ -400,7 +397,8 @@
 		req->rq_type = PTL_RPC_MSG_REPLY;
 
 	lustre_msg_set_type(req->rq_repmsg, req->rq_type);
-	lustre_msg_set_status(req->rq_repmsg, req->rq_status);
+	lustre_msg_set_status(req->rq_repmsg,
+			      ptlrpc_status_hton(req->rq_status));
 	lustre_msg_set_opc(req->rq_repmsg,
 		req->rq_reqmsg ? lustre_msg_get_opc(req->rq_reqmsg) : 0);
 
@@ -455,15 +453,14 @@
 int ptlrpc_send_error(struct ptlrpc_request *req, int may_be_difficult)
 {
 	int rc;
-	ENTRY;
 
 	if (req->rq_no_reply)
-		RETURN(0);
+		return 0;
 
 	if (!req->rq_repmsg) {
 		rc = lustre_pack_reply(req, 1, NULL, NULL);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
 	if (req->rq_status != -ENOSPC && req->rq_status != -EACCES &&
@@ -472,7 +469,7 @@
 		req->rq_type = PTL_RPC_MSG_ERR;
 
 	rc = ptlrpc_send_reply(req, may_be_difficult);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_send_error);
 
@@ -497,10 +494,9 @@
 	lnet_handle_me_t  reply_me_h;
 	lnet_md_t	 reply_md;
 	struct obd_device *obd = request->rq_import->imp_obd;
-	ENTRY;
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_DROP_RPC))
-		RETURN(0);
+		return 0;
 
 	LASSERT(request->rq_type == PTL_RPC_MSG_REQUEST);
 	LASSERT(request->rq_wait_ctx == 0);
@@ -516,7 +512,7 @@
 		/* this prevents us from waiting in ptlrpc_queue_wait */
 		request->rq_err = 1;
 		request->rq_status = -ENODEV;
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	connection = request->rq_import->imp_connection;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c
index 1996431..0abcd6d 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c
@@ -81,17 +81,16 @@
 	 * policy->pol_private will be NULL in such a case.
 	 */
 	if (policy->pol_state == NRS_POL_STATE_STOPPED)
-		RETURN(-ENODEV);
+		return -ENODEV;
 
-	RETURN(policy->pol_desc->pd_ops->op_policy_ctl != NULL ?
+	return policy->pol_desc->pd_ops->op_policy_ctl != NULL ?
 	       policy->pol_desc->pd_ops->op_policy_ctl(policy, opc, arg) :
-	       -ENOSYS);
+	       -ENOSYS;
 }
 
 static void nrs_policy_stop0(struct ptlrpc_nrs_policy *policy)
 {
 	struct ptlrpc_nrs *nrs = policy->pol_nrs;
-	ENTRY;
 
 	if (policy->pol_desc->pd_ops->op_policy_stop != NULL) {
 		spin_unlock(&nrs->nrs_lock);
@@ -111,24 +110,21 @@
 
 	if (atomic_dec_and_test(&policy->pol_desc->pd_refs))
 		module_put(policy->pol_desc->pd_owner);
-
-	EXIT;
 }
 
 static int nrs_policy_stop_locked(struct ptlrpc_nrs_policy *policy)
 {
 	struct ptlrpc_nrs *nrs = policy->pol_nrs;
-	ENTRY;
 
 	if (nrs->nrs_policy_fallback == policy && !nrs->nrs_stopping)
-		RETURN(-EPERM);
+		return -EPERM;
 
 	if (policy->pol_state == NRS_POL_STATE_STARTING)
-		RETURN(-EAGAIN);
+		return -EAGAIN;
 
 	/* In progress or already stopped */
 	if (policy->pol_state != NRS_POL_STATE_STARTED)
-		RETURN(0);
+		return 0;
 
 	policy->pol_state = NRS_POL_STATE_STOPPING;
 
@@ -145,7 +141,7 @@
 	if (policy->pol_ref == 1)
 		nrs_policy_stop0(policy);
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -158,15 +154,8 @@
 static void nrs_policy_stop_primary(struct ptlrpc_nrs *nrs)
 {
 	struct ptlrpc_nrs_policy *tmp = nrs->nrs_policy_primary;
-	ENTRY;
 
 	if (tmp == NULL) {
-		/**
-		 * XXX: This should really be RETURN_EXIT, but the latter does
-		 * not currently print anything out, and possibly should be
-		 * fixed to do so.
-		 */
-		EXIT;
 		return;
 	}
 
@@ -177,7 +166,6 @@
 
 	if (tmp->pol_ref == 0)
 		nrs_policy_stop0(tmp);
-	EXIT;
 }
 
 /**
@@ -203,19 +191,18 @@
 {
 	struct ptlrpc_nrs      *nrs = policy->pol_nrs;
 	int			rc = 0;
-	ENTRY;
 
 	/**
 	 * Don't allow multiple starting which is too complex, and has no real
 	 * benefit.
 	 */
 	if (nrs->nrs_policy_starting)
-		RETURN(-EAGAIN);
+		return -EAGAIN;
 
 	LASSERT(policy->pol_state != NRS_POL_STATE_STARTING);
 
 	if (policy->pol_state == NRS_POL_STATE_STOPPING)
-		RETURN(-EAGAIN);
+		return -EAGAIN;
 
 	if (policy->pol_flags & PTLRPC_NRS_FL_FALLBACK) {
 		/**
@@ -226,7 +213,7 @@
 		 */
 		if (policy == nrs->nrs_policy_fallback) {
 			nrs_policy_stop_primary(nrs);
-			RETURN(0);
+			return 0;
 		}
 
 		/**
@@ -241,10 +228,10 @@
 		 * Shouldn't start primary policy if w/o fallback policy.
 		 */
 		if (nrs->nrs_policy_fallback == NULL)
-			RETURN(-EPERM);
+			return -EPERM;
 
 		if (policy->pol_state == NRS_POL_STATE_STARTED)
-			RETURN(0);
+			return 0;
 	}
 
 	/**
@@ -256,7 +243,7 @@
 		atomic_dec(&policy->pol_desc->pd_refs);
 		CERROR("NRS: cannot get module for policy %s; is it alive?\n",
 		       policy->pol_desc->pd_name);
-		RETURN(-ENODEV);
+		return -ENODEV;
 	}
 
 	/**
@@ -303,7 +290,7 @@
 out:
 	nrs->nrs_policy_starting = 0;
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -644,7 +631,6 @@
 {
 	struct ptlrpc_nrs_policy       *policy;
 	int				rc = 0;
-	ENTRY;
 
 	spin_lock(&nrs->nrs_lock);
 
@@ -674,7 +660,7 @@
 
 	spin_unlock(&nrs->nrs_lock);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -690,7 +676,6 @@
 static int nrs_policy_unregister(struct ptlrpc_nrs *nrs, char *name)
 {
 	struct ptlrpc_nrs_policy *policy = NULL;
-	ENTRY;
 
 	spin_lock(&nrs->nrs_lock);
 
@@ -699,7 +684,7 @@
 		spin_unlock(&nrs->nrs_lock);
 
 		CERROR("Can't find NRS policy %s\n", name);
-		RETURN(-ENOENT);
+		return -ENOENT;
 	}
 
 	if (policy->pol_ref > 1) {
@@ -708,7 +693,7 @@
 		nrs_policy_put_locked(policy);
 
 		spin_unlock(&nrs->nrs_lock);
-		RETURN(-EBUSY);
+		return -EBUSY;
 	}
 
 	LASSERT(policy->pol_req_queued == 0);
@@ -731,7 +716,7 @@
 	LASSERT(policy->pol_private == NULL);
 	OBD_FREE_PTR(policy);
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -751,7 +736,6 @@
 	struct ptlrpc_nrs_policy       *tmp;
 	struct ptlrpc_service_part     *svcpt = nrs->nrs_svcpt;
 	int				rc;
-	ENTRY;
 
 	LASSERT(svcpt != NULL);
 	LASSERT(desc->pd_ops != NULL);
@@ -764,7 +748,7 @@
 	OBD_CPT_ALLOC_GFP(policy, svcpt->scp_service->srv_cptable,
 			  svcpt->scp_cpt, sizeof(*policy), __GFP_IO);
 	if (policy == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	policy->pol_nrs     = nrs;
 	policy->pol_desc    = desc;
@@ -777,7 +761,7 @@
 	rc = nrs_policy_init(policy);
 	if (rc != 0) {
 		OBD_FREE_PTR(policy);
-		RETURN(rc);
+		return rc;
 	}
 
 	spin_lock(&nrs->nrs_lock);
@@ -793,7 +777,7 @@
 		nrs_policy_fini(policy);
 		OBD_FREE_PTR(policy);
 
-		RETURN(-EEXIST);
+		return -EEXIST;
 	}
 
 	list_add_tail(&policy->pol_list, &nrs->nrs_policy_list);
@@ -807,7 +791,7 @@
 	if (rc != 0)
 		(void) nrs_policy_unregister(nrs, policy->pol_desc->pd_name);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -844,7 +828,6 @@
 static void ptlrpc_nrs_hpreq_add_nolock(struct ptlrpc_request *req)
 {
 	int	opc = lustre_msg_get_opc(req->rq_reqmsg);
-	ENTRY;
 
 	spin_lock(&req->rq_lock);
 	req->rq_hp = 1;
@@ -852,7 +835,6 @@
 	if (opc != OBD_PING)
 		DEBUG_REQ(D_NET, req, "high priority req");
 	spin_unlock(&req->rq_lock);
-	EXIT;
 }
 
 /**
@@ -891,7 +873,6 @@
 	struct ptlrpc_service_part	 *svcpt = nrs->nrs_svcpt;
 	struct ptlrpc_service		 *svc = svcpt->scp_service;
 	int				  rc = -EINVAL;
-	ENTRY;
 
 	LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
 
@@ -912,7 +893,7 @@
 		}
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -950,7 +931,7 @@
 
 	rc = nrs_register_policies_locked(nrs);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -966,7 +947,6 @@
 {
 	struct ptlrpc_nrs	       *nrs;
 	int				rc;
-	ENTRY;
 
 	LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
 
@@ -994,7 +974,7 @@
 	rc = nrs_svcpt_setup_locked0(nrs, svcpt);
 
 out:
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1012,7 +992,6 @@
 	struct ptlrpc_nrs_policy       *tmp;
 	int				rc;
 	bool				hp = false;
-	ENTRY;
 
 	LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
 
@@ -1036,8 +1015,6 @@
 
 	if (hp)
 		OBD_FREE_PTR(nrs);
-
-	EXIT;
 }
 
 /**
@@ -1051,13 +1028,12 @@
 static struct ptlrpc_nrs_pol_desc *nrs_policy_find_desc_locked(const char *name)
 {
 	struct ptlrpc_nrs_pol_desc     *tmp;
-	ENTRY;
 
 	list_for_each_entry(tmp, &nrs_core.nrs_policies, pd_list) {
 		if (strncmp(tmp->pd_name, name, NRS_POL_NAME_MAX) == 0)
-			RETURN(tmp);
+			return tmp;
 	}
-	RETURN(NULL);
+	return NULL;
 }
 
 /**
@@ -1079,7 +1055,6 @@
 	struct ptlrpc_service_part     *svcpt;
 	int				i;
 	int				rc = 0;
-	ENTRY;
 
 	LASSERT(mutex_is_locked(&nrs_core.nrs_mutex));
 	LASSERT(mutex_is_locked(&ptlrpc_all_services_mutex));
@@ -1107,7 +1082,7 @@
 				       "partition %d of service %s: %d\n",
 				       desc->pd_name, svcpt->scp_cpt,
 				       svcpt->scp_service->srv_name, rc);
-				RETURN(rc);
+				return rc;
 			}
 
 			if (!hp && nrs_svc_has_hp(svc)) {
@@ -1120,7 +1095,7 @@
 			desc->pd_ops->op_lprocfs_fini(svc);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1143,7 +1118,6 @@
 	struct ptlrpc_service	       *svc;
 	struct ptlrpc_nrs_pol_desc     *desc;
 	int				rc = 0;
-	ENTRY;
 
 	LASSERT(conf != NULL);
 	LASSERT(conf->nc_ops != NULL);
@@ -1171,7 +1145,7 @@
 		       "policy flags; external policies cannot act as fallback "
 		       "policies, or be started immediately upon registration "
 		       "without interaction with lprocfs\n", conf->nc_name);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	mutex_lock(&nrs_core.nrs_mutex);
@@ -1274,7 +1248,7 @@
 fail:
 	mutex_unlock(&nrs_core.nrs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_nrs_policy_register);
 
@@ -1296,14 +1270,13 @@
 {
 	struct ptlrpc_nrs_pol_desc	*desc;
 	int				 rc;
-	ENTRY;
 
 	LASSERT(conf != NULL);
 
 	if (conf->nc_flags & PTLRPC_NRS_FL_FALLBACK) {
 		CERROR("Unable to unregister a fallback policy, unless the "
 		       "PTLRPC service is stopping.\n");
-		RETURN(-EPERM);
+		return -EPERM;
 	}
 
 	conf->nc_name[NRS_POL_NAME_MAX - 1] = '\0';
@@ -1341,7 +1314,7 @@
 not_exist:
 	mutex_unlock(&nrs_core.nrs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_nrs_policy_unregister);
 
@@ -1396,7 +1369,7 @@
 
 	mutex_unlock(&nrs_core.nrs_mutex);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1630,7 +1603,6 @@
 	struct ptlrpc_nrs_request	*nrq = &req->rq_nrq;
 	struct ptlrpc_nrs_resource	*res1[NRS_RES_MAX];
 	struct ptlrpc_nrs_resource	*res2[NRS_RES_MAX];
-	ENTRY;
 
 	/**
 	 * Obtain the high-priority NRS head resources.
@@ -1660,7 +1632,6 @@
 	 * returned false.
 	 */
 	nrs_resource_put_safe(res1);
-	EXIT;
 }
 
 /**
@@ -1696,7 +1667,6 @@
 	struct ptlrpc_service_part     *svcpt;
 	int				i;
 	int				rc = 0;
-	ENTRY;
 
 	LASSERT(opc != PTLRPC_NRS_CTL_INVALID);
 
@@ -1728,7 +1698,7 @@
 		}
 	}
 out:
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1745,7 +1715,6 @@
 int ptlrpc_nrs_init(void)
 {
 	int	rc;
-	ENTRY;
 
 	mutex_init(&nrs_core.nrs_mutex);
 	INIT_LIST_HEAD(&nrs_core.nrs_policies);
@@ -1755,7 +1724,7 @@
 		GOTO(fail, rc);
 
 
-	RETURN(rc);
+	return rc;
 fail:
 	/**
 	 * Since no PTLRPC services have been started at this point, all we need
@@ -1763,7 +1732,7 @@
 	 */
 	ptlrpc_nrs_fini();
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
index 1437636..cd2611a3 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c
@@ -115,7 +115,7 @@
 EXPORT_SYMBOL(lustre_msg_check_version);
 
 /* early reply size */
-int lustre_msg_early_size()
+int lustre_msg_early_size(void)
 {
 	static int size = 0;
 	if (!size) {
@@ -329,7 +329,6 @@
 {
 	struct ptlrpc_reply_state *rs;
 	int			msg_len, rc;
-	ENTRY;
 
 	LASSERT(req->rq_reply_state == NULL);
 
@@ -342,7 +341,7 @@
 	msg_len = lustre_msg_size_v2(count, lens);
 	rc = sptlrpc_svc_alloc_rs(req, msg_len);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rs = req->rq_reply_state;
 	atomic_set(&rs->rs_refcount, 1);    /* 1 ref for rq_reply_state */
@@ -363,7 +362,7 @@
 
 	PTLRPC_RS_DEBUG_LRU_ADD(rs);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(lustre_pack_reply_v2);
 
@@ -574,7 +573,6 @@
 int __lustre_unpack_msg(struct lustre_msg *m, int len)
 {
 	int required_len, rc;
-	ENTRY;
 
 	/* We can provide a slightly better error log, if we check the
 	 * message magic and version first.  In the future, struct
@@ -588,12 +586,12 @@
 		/* can't even look inside the message */
 		CERROR("message length %d too small for magic/version check\n",
 		       len);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	rc = lustre_unpack_msg_v2(m, len);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(__lustre_unpack_msg);
 
@@ -642,6 +640,9 @@
 		 return -EINVAL;
 	}
 
+	if (!inout)
+		pb->pb_status = ptlrpc_status_ntoh(pb->pb_status);
+
 	return 0;
 }
 
@@ -1613,11 +1614,10 @@
 	struct ptlrpc_request *req;
 	char		  *tmp;
 	int		    rc;
-	ENTRY;
 
 	req = ptlrpc_request_alloc(imp, &RQF_OBD_SET_INFO);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req_capsule_set_size(&req->rq_pill, &RMF_SETINFO_KEY,
 			     RCL_CLIENT, keylen);
@@ -1626,7 +1626,7 @@
 	rc = ptlrpc_request_pack(req, version, opcode);
 	if (rc) {
 		ptlrpc_request_free(req);
-		RETURN(rc);
+		return rc;
 	}
 
 	tmp = req_capsule_client_get(&req->rq_pill, &RMF_SETINFO_KEY);
@@ -1644,7 +1644,7 @@
 		ptlrpc_req_finished(req);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(do_set_info_async);
 
@@ -2163,7 +2163,6 @@
 
 static void lustre_swab_lov_user_md_common(struct lov_user_md_v1 *lum)
 {
-	ENTRY;
 	__swab32s(&lum->lmm_magic);
 	__swab32s(&lum->lmm_pattern);
 	lustre_swab_lmm_oi(&lum->lmm_oi);
@@ -2171,31 +2170,25 @@
 	__swab16s(&lum->lmm_stripe_count);
 	__swab16s(&lum->lmm_stripe_offset);
 	print_lum(lum);
-	EXIT;
 }
 
 void lustre_swab_lov_user_md_v1(struct lov_user_md_v1 *lum)
 {
-	ENTRY;
 	CDEBUG(D_IOCTL, "swabbing lov_user_md v1\n");
 	lustre_swab_lov_user_md_common(lum);
-	EXIT;
 }
 EXPORT_SYMBOL(lustre_swab_lov_user_md_v1);
 
 void lustre_swab_lov_user_md_v3(struct lov_user_md_v3 *lum)
 {
-	ENTRY;
 	CDEBUG(D_IOCTL, "swabbing lov_user_md v3\n");
 	lustre_swab_lov_user_md_common((struct lov_user_md_v1 *)lum);
 	/* lmm_pool_name nothing to do with char */
-	EXIT;
 }
 EXPORT_SYMBOL(lustre_swab_lov_user_md_v3);
 
 void lustre_swab_lov_mds_md(struct lov_mds_md *lmm)
 {
-	ENTRY;
 	CDEBUG(D_IOCTL, "swabbing lov_mds_md\n");
 	__swab32s(&lmm->lmm_magic);
 	__swab32s(&lmm->lmm_pattern);
@@ -2203,7 +2196,6 @@
 	__swab32s(&lmm->lmm_stripe_size);
 	__swab16s(&lmm->lmm_stripe_count);
 	__swab16s(&lmm->lmm_layout_gen);
-	EXIT;
 }
 EXPORT_SYMBOL(lustre_swab_lov_mds_md);
 
@@ -2211,13 +2203,12 @@
 				     int stripe_count)
 {
 	int i;
-	ENTRY;
+
 	for (i = 0; i < stripe_count; i++) {
 		lustre_swab_ost_id(&(lod[i].l_ost_oi));
 		__swab32s(&(lod[i].l_ost_gen));
 		__swab32s(&(lod[i].l_ost_idx));
 	}
-	EXIT;
 }
 EXPORT_SYMBOL(lustre_swab_lov_user_md_objects);
 
@@ -2459,6 +2450,7 @@
 			   rep_ok ? lustre_msg_get_flags(req->rq_repmsg) : -1,
 			   req->rq_status,
 			   rep_ok ? lustre_msg_get_status(req->rq_repmsg) : -1);
+	va_end(args);
 }
 EXPORT_SYMBOL(_debug_req);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
index ef5269a..227a0ae 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
@@ -51,7 +51,7 @@
 static LIST_HEAD(pinger_imports);
 static struct list_head timeout_list = LIST_HEAD_INIT(timeout_list);
 
-int ptlrpc_pinger_suppress_pings()
+int ptlrpc_pinger_suppress_pings(void)
 {
 	return suppress_pings;
 }
@@ -75,11 +75,10 @@
 {
 	int rc;
 	struct ptlrpc_request *req;
-	ENTRY;
 
 	req = ptlrpc_prep_ping(obd->u.cli.cl_import);
 	if (req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req->rq_send_state = LUSTRE_IMP_FULL;
 
@@ -87,28 +86,27 @@
 
 	ptlrpc_req_finished(req);
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_obd_ping);
 
 int ptlrpc_ping(struct obd_import *imp)
 {
 	struct ptlrpc_request *req;
-	ENTRY;
 
 	req = ptlrpc_prep_ping(imp);
 	if (req == NULL) {
 		CERROR("OOM trying to ping %s->%s\n",
 		       imp->imp_obd->obd_uuid.uuid,
 		       obd2cli_tgt(imp->imp_obd));
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	DEBUG_REQ(D_INFO, req, "pinging %s->%s",
 		  imp->imp_obd->obd_uuid.uuid, obd2cli_tgt(imp->imp_obd));
 	ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1);
 
-	RETURN(0);
+	return 0;
 }
 
 void ptlrpc_update_next_ping(struct obd_import *imp, int soon)
@@ -297,7 +295,6 @@
 static int ptlrpc_pinger_main(void *arg)
 {
 	struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg;
-	ENTRY;
 
 	/* Record that the thread is running */
 	thread_set_flags(thread, SVC_RUNNING);
@@ -353,7 +350,6 @@
 				     thread_is_event(thread),
 				     &lwi);
 			if (thread_test_and_clear_flags(thread, SVC_STOPPING)) {
-				EXIT;
 				break;
 			} else {
 				/* woken after adding import to reset timer */
@@ -369,37 +365,32 @@
 	return 0;
 }
 
-static struct ptlrpc_thread *pinger_thread = NULL;
+static struct ptlrpc_thread pinger_thread;
 
 int ptlrpc_start_pinger(void)
 {
 	struct l_wait_info lwi = { 0 };
 	int rc;
-	ENTRY;
 
-	if (pinger_thread != NULL)
-		RETURN(-EALREADY);
+	if (!thread_is_init(&pinger_thread) &&
+	    !thread_is_stopped(&pinger_thread))
+		return -EALREADY;
 
-	OBD_ALLOC_PTR(pinger_thread);
-	if (pinger_thread == NULL)
-		RETURN(-ENOMEM);
-	init_waitqueue_head(&pinger_thread->t_ctl_waitq);
+	init_waitqueue_head(&pinger_thread.t_ctl_waitq);
 	init_waitqueue_head(&suspend_timeouts_waitq);
 
-	strcpy(pinger_thread->t_name, "ll_ping");
+	strcpy(pinger_thread.t_name, "ll_ping");
 
 	/* CLONE_VM and CLONE_FILES just avoid a needless copy, because we
 	 * just drop the VM and FILES in cfs_daemonize_ctxt() right away. */
 	rc = PTR_ERR(kthread_run(ptlrpc_pinger_main,
-				 pinger_thread, pinger_thread->t_name));
+				 &pinger_thread, pinger_thread.t_name));
 	if (IS_ERR_VALUE(rc)) {
 		CERROR("cannot start thread: %d\n", rc);
-		OBD_FREE(pinger_thread, sizeof(*pinger_thread));
-		pinger_thread = NULL;
-		RETURN(rc);
+		return rc;
 	}
-	l_wait_event(pinger_thread->t_ctl_waitq,
-		     thread_is_running(pinger_thread), &lwi);
+	l_wait_event(pinger_thread.t_ctl_waitq,
+		     thread_is_running(&pinger_thread), &lwi);
 
 	if (suppress_pings)
 		CWARN("Pings will be suppressed at the request of the "
@@ -408,7 +399,7 @@
 		      "(Search for the \"suppress_pings\" kernel module "
 		      "parameter.)\n");
 
-	RETURN(0);
+	return 0;
 }
 
 int ptlrpc_pinger_remove_timeouts(void);
@@ -417,23 +408,19 @@
 {
 	struct l_wait_info lwi = { 0 };
 	int rc = 0;
-	ENTRY;
 
-	if (pinger_thread == NULL)
-		RETURN(-EALREADY);
+	if (!thread_is_init(&pinger_thread) &&
+	    !thread_is_stopped(&pinger_thread))
+		return -EALREADY;
 
 	ptlrpc_pinger_remove_timeouts();
-	mutex_lock(&pinger_mutex);
-	thread_set_flags(pinger_thread, SVC_STOPPING);
-	wake_up(&pinger_thread->t_ctl_waitq);
-	mutex_unlock(&pinger_mutex);
+	thread_set_flags(&pinger_thread, SVC_STOPPING);
+	wake_up(&pinger_thread.t_ctl_waitq);
 
-	l_wait_event(pinger_thread->t_ctl_waitq,
-		     thread_is_stopped(pinger_thread), &lwi);
+	l_wait_event(pinger_thread.t_ctl_waitq,
+		     thread_is_stopped(&pinger_thread), &lwi);
 
-	OBD_FREE_PTR(pinger_thread);
-	pinger_thread = NULL;
-	RETURN(rc);
+	return rc;
 }
 
 void ptlrpc_pinger_sending_on_import(struct obd_import *imp)
@@ -459,9 +446,8 @@
 
 int ptlrpc_pinger_add_import(struct obd_import *imp)
 {
-	ENTRY;
 	if (!list_empty(&imp->imp_pinger_chain))
-		RETURN(-EALREADY);
+		return -EALREADY;
 
 	mutex_lock(&pinger_mutex);
 	CDEBUG(D_HA, "adding pingable import %s->%s\n",
@@ -476,15 +462,14 @@
 	ptlrpc_pinger_wake_up();
 	mutex_unlock(&pinger_mutex);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_pinger_add_import);
 
 int ptlrpc_pinger_del_import(struct obd_import *imp)
 {
-	ENTRY;
 	if (list_empty(&imp->imp_pinger_chain))
-		RETURN(-ENOENT);
+		return -ENOENT;
 
 	mutex_lock(&pinger_mutex);
 	list_del_init(&imp->imp_pinger_chain);
@@ -494,7 +479,7 @@
 	imp->imp_obd->obd_no_recov = 1;
 	class_import_put(imp);
 	mutex_unlock(&pinger_mutex);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_pinger_del_import);
 
@@ -615,10 +600,10 @@
 	return 0;
 }
 
-void ptlrpc_pinger_wake_up()
+void ptlrpc_pinger_wake_up(void)
 {
-	thread_add_flags(pinger_thread, SVC_EVENT);
-	wake_up(&pinger_thread->t_ctl_waitq);
+	thread_add_flags(&pinger_thread, SVC_EVENT);
+	wake_up(&pinger_thread.t_ctl_waitq);
 }
 
 /* Ping evictor thread */
@@ -659,7 +644,6 @@
 	struct obd_export *exp;
 	struct l_wait_info lwi = { 0 };
 	time_t expire_time;
-	ENTRY;
 
 	unshare_fs_struct();
 
@@ -731,12 +715,12 @@
 	}
 	CDEBUG(D_HA, "Exiting Ping Evictor\n");
 
-	RETURN(0);
+	return 0;
 }
 
 void ping_evictor_start(void)
 {
-	task_t *task;
+	struct task_struct *task;
 
 	if (++pet_refcount > 1)
 		return;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
index f6ea80f..419e634 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c
@@ -54,7 +54,6 @@
 __init int ptlrpc_init(void)
 {
 	int rc, cleanup_phase = 0;
-	ENTRY;
 
 	lustre_assert_wire_constants();
 #if RS_DEBUG
@@ -67,11 +66,11 @@
 
 	rc = req_layout_init();
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	rc = ptlrpc_hr_init();
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	cleanup_phase = 1;
 
@@ -110,7 +109,7 @@
 	rc = tgt_mod_init();
 	if (rc)
 		GOTO(cleanup, rc);
-	RETURN(0);
+	return 0;
 
 cleanup:
 	switch(cleanup_phase) {
@@ -150,5 +149,7 @@
 MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
 MODULE_DESCRIPTION("Lustre Request Processor and Lock Management");
 MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0.0");
 
-cfs_module(ptlrpc, "1.0.0", ptlrpc_init, ptlrpc_exit);
+module_init(ptlrpc_init);
+module_exit(ptlrpc_exit);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index 5a66a1b..fbdeff6 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -268,7 +268,6 @@
 	struct ptlrpc_request_set *set = pc->pc_set;
 	int rc = 0;
 	int rc2;
-	ENTRY;
 
 	if (atomic_read(&set->set_new_count)) {
 		spin_lock(&set->set_new_req_lock);
@@ -302,7 +301,7 @@
 		 * new modules are loaded, i.e., early during boot up.
 		 */
 		CERROR("Failure to refill session: %d\n", rc2);
-		RETURN(rc);
+		return rc;
 	}
 
 	if (atomic_read(&set->set_remaining))
@@ -368,7 +367,7 @@
 		}
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -383,7 +382,6 @@
 	struct ptlrpc_request_set *set = pc->pc_set;
 	struct lu_env env = { .le_ses = NULL };
 	int rc, exit = 0;
-	ENTRY;
 
 	unshare_fs_struct();
 #if defined(CONFIG_SMP)
@@ -410,7 +408,7 @@
 	complete(&pc->pc_starting);
 
 	if (rc != 0)
-		RETURN(rc);
+		return rc;
 
 	/*
 	 * This mainloop strongly resembles ptlrpc_set_wait() except that our
@@ -501,7 +499,6 @@
 #if defined(CONFIG_NUMA)
 	cpumask_t mask;
 #endif
-	ENTRY;
 
 	LASSERT(index <= max - 1);
 	pc = &ptlrpcds->pd_threads[index];
@@ -596,7 +593,7 @@
 		}
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -604,7 +601,6 @@
 {
 	int rc;
 	int env = 0;
-	ENTRY;
 
 	/*
 	 * Do not allow start second thread for one pc.
@@ -612,7 +608,7 @@
 	if (test_and_set_bit(LIOD_START, &pc->pc_flags)) {
 		CWARN("Starting second thread (%s) for same pc %p\n",
 		      name, pc);
-		RETURN(0);
+		return 0;
 	}
 
 	pc->pc_index = index;
@@ -634,7 +630,8 @@
 
 	env = 1;
 	{
-		task_t *task;
+		struct task_struct *task;
+
 		if (index >= 0) {
 			rc = ptlrpcd_bind(index, max);
 			if (rc < 0)
@@ -663,31 +660,25 @@
 		clear_bit(LIOD_BIND, &pc->pc_flags);
 		clear_bit(LIOD_START, &pc->pc_flags);
 	}
-	RETURN(rc);
+	return rc;
 }
 
 void ptlrpcd_stop(struct ptlrpcd_ctl *pc, int force)
 {
-	ENTRY;
-
 	if (!test_bit(LIOD_START, &pc->pc_flags)) {
 		CWARN("Thread for pc %p was not started\n", pc);
-		goto out;
+		return;
 	}
 
 	set_bit(LIOD_STOP, &pc->pc_flags);
 	if (force)
 		set_bit(LIOD_FORCE, &pc->pc_flags);
 	wake_up(&pc->pc_set->set_waitq);
-
-out:
-	EXIT;
 }
 
 void ptlrpcd_free(struct ptlrpcd_ctl *pc)
 {
 	struct ptlrpc_request_set *set = pc->pc_set;
-	ENTRY;
 
 	if (!test_bit(LIOD_START, &pc->pc_flags)) {
 		CWARN("Thread for pc %p was not started\n", pc);
@@ -716,13 +707,11 @@
 		pc->pc_partners = NULL;
 	}
 	pc->pc_npartners = 0;
-	EXIT;
 }
 
 static void ptlrpcd_fini(void)
 {
 	int i;
-	ENTRY;
 
 	if (ptlrpcds != NULL) {
 		for (i = 0; i < ptlrpcds->pd_nthreads; i++)
@@ -734,8 +723,6 @@
 		OBD_FREE(ptlrpcds, ptlrpcds->pd_size);
 		ptlrpcds = NULL;
 	}
-
-	EXIT;
 }
 
 static int ptlrpcd_init(void)
@@ -743,7 +730,6 @@
 	int nthreads = num_online_cpus();
 	char name[16];
 	int size, i = -1, j, rc = 0;
-	ENTRY;
 
 	if (max_ptlrpcds > 0 && max_ptlrpcds < nthreads)
 		nthreads = max_ptlrpcds;
@@ -800,19 +786,18 @@
 		ptlrpcds = NULL;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 int ptlrpcd_addref(void)
 {
 	int rc = 0;
-	ENTRY;
 
 	mutex_lock(&ptlrpcd_mutex);
 	if (++ptlrpcd_users == 1)
 		rc = ptlrpcd_init();
 	mutex_unlock(&ptlrpcd_mutex);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpcd_addref);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c
index 2960889..84c39e0 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/recover.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c
@@ -60,12 +60,8 @@
  */
 void ptlrpc_initiate_recovery(struct obd_import *imp)
 {
-	ENTRY;
-
 	CDEBUG(D_HA, "%s: starting recovery\n", obd2cli_tgt(imp->imp_obd));
 	ptlrpc_connect_import(imp);
-
-	EXIT;
 }
 
 /**
@@ -78,7 +74,6 @@
 	struct list_head *tmp, *pos;
 	struct ptlrpc_request *req = NULL;
 	__u64 last_transno;
-	ENTRY;
 
 	*inflight = 0;
 
@@ -137,11 +132,11 @@
 		if (rc) {
 			CERROR("recovery replay error %d for req "
 			       LPU64"\n", rc, req->rq_xid);
-			RETURN(rc);
+			return rc;
 		}
 		*inflight = 1;
 	}
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -152,8 +147,6 @@
 {
 	struct ptlrpc_request *req, *next;
 
-	ENTRY;
-
 	/* As long as we're in recovery, nothing should be added to the sending
 	 * list, so we don't need to hold the lock during this iteration and
 	 * resend process.
@@ -163,7 +156,7 @@
 	spin_lock(&imp->imp_lock);
 	if (imp->imp_state != LUSTRE_IMP_RECOVER) {
 		spin_unlock(&imp->imp_lock);
-		RETURN(-1);
+		return -1;
 	}
 
 	list_for_each_entry_safe(req, next, &imp->imp_sending_list,
@@ -176,7 +169,7 @@
 	}
 	spin_unlock(&imp->imp_lock);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_resend);
 
@@ -203,7 +196,6 @@
 void ptlrpc_request_handle_notconn(struct ptlrpc_request *failed_req)
 {
 	struct obd_import *imp = failed_req->rq_import;
-	ENTRY;
 
 	CDEBUG(D_HA, "import %s of %s@%s abruptly disconnected: reconnecting\n",
 	       imp->imp_obd->obd_name, obd2cli_tgt(imp->imp_obd),
@@ -230,8 +222,6 @@
 	if (!failed_req->rq_no_resend)
 		failed_req->rq_resend = 1;
 	spin_unlock(&failed_req->rq_lock);
-
-	EXIT;
 }
 
 /**
@@ -246,7 +236,6 @@
 	struct obd_device *obd = imp->imp_obd;
 	int rc = 0;
 
-	ENTRY;
 	LASSERT(obd);
 
 	/* When deactivating, mark import invalid, and abort in-flight
@@ -279,7 +268,7 @@
 		rc = ptlrpc_recover_import(imp, NULL, 0);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_set_import_active);
 
@@ -287,7 +276,6 @@
 int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid, int async)
 {
 	int rc = 0;
-	ENTRY;
 
 	spin_lock(&imp->imp_lock);
 	if (imp->imp_state == LUSTRE_IMP_NEW || imp->imp_deactive ||
@@ -337,7 +325,6 @@
 		CDEBUG(D_HA, "%s: recovery finished\n",
 		       obd2cli_tgt(imp->imp_obd));
 	}
-	EXIT;
 
 out:
 	return rc;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c
index 36e8bed5..962b31d 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c
@@ -269,8 +269,8 @@
 			remove_dead = 0;
 		}
 	} else {
-		vcred.vc_uid = current_uid();
-		vcred.vc_gid = current_gid();
+		vcred.vc_uid = from_kuid(&init_user_ns, current_uid());
+		vcred.vc_gid = from_kgid(&init_user_ns, current_gid());
 	}
 
 	return sec->ps_policy->sp_cops->lookup_ctx(sec, &vcred,
@@ -396,14 +396,13 @@
 	struct obd_import *imp = req->rq_import;
 	struct ptlrpc_sec *sec;
 	int		rc;
-	ENTRY;
 
 	LASSERT(!req->rq_cli_ctx);
 	LASSERT(imp);
 
 	rc = import_sec_validate_get(imp, &sec);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	req->rq_cli_ctx = get_my_ctx(sec);
 
@@ -411,10 +410,10 @@
 
 	if (!req->rq_cli_ctx) {
 		CERROR("req %p: fail to get context\n", req);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -428,8 +427,6 @@
  */
 void sptlrpc_req_put_ctx(struct ptlrpc_request *req, int sync)
 {
-	ENTRY;
-
 	LASSERT(req);
 	LASSERT(req->rq_cli_ctx);
 
@@ -444,7 +441,6 @@
 
 	sptlrpc_cli_ctx_put(req->rq_cli_ctx, sync);
 	req->rq_cli_ctx = NULL;
-	EXIT;
 }
 
 static
@@ -520,7 +516,6 @@
 	struct ptlrpc_cli_ctx *oldctx = req->rq_cli_ctx;
 	struct ptlrpc_cli_ctx *newctx;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(oldctx);
 
@@ -533,7 +528,7 @@
 
 		/* restore old ctx */
 		req->rq_cli_ctx = oldctx;
-		RETURN(rc);
+		return rc;
 	}
 
 	newctx = req->rq_cli_ctx;
@@ -560,14 +555,14 @@
 			/* restore old ctx */
 			sptlrpc_req_put_ctx(req, 0);
 			req->rq_cli_ctx = oldctx;
-			RETURN(rc);
+			return rc;
 		}
 
 		LASSERT(req->rq_cli_ctx == newctx);
 	}
 
 	sptlrpc_cli_ctx_put(oldctx, 1);
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(sptlrpc_req_replace_dead_ctx);
 
@@ -639,12 +634,11 @@
 	struct ptlrpc_sec      *sec;
 	struct l_wait_info      lwi;
 	int		     rc;
-	ENTRY;
 
 	LASSERT(ctx);
 
 	if (req->rq_ctx_init || req->rq_ctx_fini)
-		RETURN(0);
+		return 0;
 
 	/*
 	 * during the process a request's context might change type even
@@ -654,7 +648,7 @@
 again:
 	rc = import_sec_validate_get(req->rq_import, &sec);
 	if (rc)
-		RETURN(rc);
+		return rc;
 
 	if (sec->ps_flvr.sf_rpc != req->rq_flvr.sf_rpc) {
 		CDEBUG(D_SEC, "req %p: flavor has changed %x -> %x\n",
@@ -666,7 +660,7 @@
 	sptlrpc_sec_put(sec);
 
 	if (cli_ctx_is_eternal(ctx))
-		RETURN(0);
+		return 0;
 
 	if (unlikely(test_bit(PTLRPC_CTX_NEW_BIT, &ctx->cc_flags))) {
 		LASSERT(ctx->cc_ops->refresh);
@@ -677,7 +671,7 @@
 	LASSERT(ctx->cc_ops->validate);
 	if (ctx->cc_ops->validate(ctx) == 0) {
 		req_off_ctx_list(req, ctx);
-		RETURN(0);
+		return 0;
 	}
 
 	if (unlikely(test_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags))) {
@@ -685,7 +679,7 @@
 		req->rq_err = 1;
 		spin_unlock(&req->rq_lock);
 		req_off_ctx_list(req, ctx);
-		RETURN(-EPERM);
+		return -EPERM;
 	}
 
 	/*
@@ -719,7 +713,7 @@
 	    unlikely(req->rq_reqmsg) &&
 	    lustre_msg_get_flags(req->rq_reqmsg) & MSG_RESENT) {
 		req_off_ctx_list(req, ctx);
-		RETURN(0);
+		return 0;
 	}
 
 	if (unlikely(test_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags))) {
@@ -731,7 +725,7 @@
 			spin_lock(&req->rq_lock);
 			req->rq_err = 1;
 			spin_unlock(&req->rq_lock);
-			RETURN(-EINTR);
+			return -EINTR;
 		}
 
 		rc = sptlrpc_req_replace_dead_ctx(req);
@@ -742,7 +736,7 @@
 			spin_lock(&req->rq_lock);
 			req->rq_err = 1;
 			spin_unlock(&req->rq_lock);
-			RETURN(rc);
+			return rc;
 		}
 
 		ctx = req->rq_cli_ctx;
@@ -759,7 +753,7 @@
 	spin_unlock(&ctx->cc_lock);
 
 	if (timeout < 0)
-		RETURN(-EWOULDBLOCK);
+		return -EWOULDBLOCK;
 
 	/* Clear any flags that may be present from previous sends */
 	LASSERT(req->rq_receiving_reply == 0);
@@ -789,7 +783,7 @@
 		req_off_ctx_list(req, ctx);
 
 		LASSERT(rc != 0);
-		RETURN(rc);
+		return rc;
 	}
 
 	goto again;
@@ -889,7 +883,6 @@
 	struct ptlrpc_cli_ctx *ctx;
 	struct ptlrpc_request *req = NULL;
 	int rc;
-	ENTRY;
 
 	might_sleep();
 
@@ -898,22 +891,22 @@
 	sptlrpc_sec_put(sec);
 
 	if (!ctx)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	if (cli_ctx_is_eternal(ctx) ||
 	    ctx->cc_ops->validate(ctx) == 0) {
 		sptlrpc_cli_ctx_put(ctx, 1);
-		RETURN(0);
+		return 0;
 	}
 
 	if (cli_ctx_is_error(ctx)) {
 		sptlrpc_cli_ctx_put(ctx, 1);
-		RETURN(-EACCES);
+		return -EACCES;
 	}
 
 	OBD_ALLOC_PTR(req);
 	if (!req)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	spin_lock_init(&req->rq_lock);
 	atomic_set(&req->rq_refcount, 10000);
@@ -929,7 +922,7 @@
 	sptlrpc_cli_ctx_put(req->rq_cli_ctx, 1);
 	OBD_FREE_PTR(req);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -941,7 +934,6 @@
 {
 	struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
 	int rc = 0;
-	ENTRY;
 
 	LASSERT(ctx);
 	LASSERT(ctx->cc_sec);
@@ -953,7 +945,7 @@
 	if (req->rq_bulk) {
 		rc = sptlrpc_cli_wrap_bulk(req, req->rq_bulk);
 		if (rc)
-			RETURN(rc);
+			return rc;
 	}
 
 	switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
@@ -977,14 +969,13 @@
 		LASSERT(req->rq_reqdata_len <= req->rq_reqbuf_len);
 	}
 
-	RETURN(rc);
+	return rc;
 }
 
 static int do_cli_unwrap_reply(struct ptlrpc_request *req)
 {
 	struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(ctx);
 	LASSERT(ctx->cc_sec);
@@ -1002,13 +993,13 @@
 		break;
 	default:
 		CERROR("failed unpack reply: x"LPU64"\n", req->rq_xid);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (req->rq_repdata_len < sizeof(struct lustre_msg)) {
 		CERROR("replied data length %d too small\n",
 		       req->rq_repdata_len);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (SPTLRPC_FLVR_POLICY(req->rq_repdata->lm_secflvr) !=
@@ -1016,7 +1007,7 @@
 		CERROR("reply policy %u doesn't match request policy %u\n",
 		       SPTLRPC_FLVR_POLICY(req->rq_repdata->lm_secflvr),
 		       SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc));
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) {
@@ -1038,7 +1029,7 @@
 	if (SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) != SPTLRPC_POLICY_NULL &&
 	    !req->rq_ctx_init)
 		req->rq_rep_swab_mask = 0;
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1096,11 +1087,10 @@
 	char		   *early_buf;
 	int		     early_bufsz, early_size;
 	int		     rc;
-	ENTRY;
 
 	OBD_ALLOC_PTR(early_req);
 	if (early_req == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	early_size = req->rq_nob_received;
 	early_bufsz = size_roundup_power2(early_size);
@@ -1163,7 +1153,7 @@
 
 	LASSERT(early_req->rq_repmsg);
 	*req_ret = early_req;
-	RETURN(0);
+	return 0;
 
 err_ctx:
 	sptlrpc_cli_ctx_put(early_req->rq_cli_ctx, 1);
@@ -1171,7 +1161,7 @@
 	OBD_FREE_LARGE(early_buf, early_bufsz);
 err_req:
 	OBD_FREE_PTR(early_req);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -1285,7 +1275,6 @@
 	struct ptlrpc_sec_policy *policy;
 	struct ptlrpc_sec	*sec;
 	char		      str[32];
-	ENTRY;
 
 	if (svc_ctx) {
 		LASSERT(imp->imp_dlm_fake == 1);
@@ -1308,7 +1297,7 @@
 		policy = sptlrpc_wireflavor2policy(sf->sf_rpc);
 		if (!policy) {
 			CERROR("invalid flavor 0x%x\n", sf->sf_rpc);
-			RETURN(NULL);
+			return NULL;
 		}
 	}
 
@@ -1324,7 +1313,7 @@
 		sptlrpc_policy_put(policy);
 	}
 
-	RETURN(sec);
+	return sec;
 }
 
 struct ptlrpc_sec *sptlrpc_import_sec_ref(struct obd_import *imp)
@@ -1406,12 +1395,11 @@
 	enum lustre_sec_part	sp;
 	char			str[24];
 	int			 rc = 0;
-	ENTRY;
 
 	might_sleep();
 
 	if (imp == NULL)
-		RETURN(0);
+		return 0;
 
 	conn = imp->imp_connection;
 
@@ -1485,7 +1473,7 @@
 	mutex_unlock(&imp->imp_sec_mutex);
 out:
 	sptlrpc_sec_put(sec);
-	RETURN(rc);
+	return rc;
 }
 
 void sptlrpc_import_sec_put(struct obd_import *imp)
@@ -1523,7 +1511,8 @@
 
 void sptlrpc_import_flush_my_ctx(struct obd_import *imp)
 {
-	import_flush_ctx_common(imp, current_uid(), 1, 1);
+	import_flush_ctx_common(imp, from_kuid(&init_user_ns, current_uid()),
+				1, 1);
 }
 EXPORT_SYMBOL(sptlrpc_import_flush_my_ctx);
 
@@ -1668,17 +1657,16 @@
 {
 	struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
 	struct ptlrpc_sec_policy *policy;
-	ENTRY;
 
 	LASSERT(ctx);
 	LASSERT(ctx->cc_sec);
 	LASSERT(ctx->cc_sec->ps_policy);
 
 	if (req->rq_repbuf)
-		RETURN(0);
+		return 0;
 
 	policy = ctx->cc_sec->ps_policy;
-	RETURN(policy->sp_cops->alloc_repbuf(ctx->cc_sec, req, msgsize));
+	return policy->sp_cops->alloc_repbuf(ctx->cc_sec, req, msgsize);
 }
 
 /**
@@ -1689,7 +1677,6 @@
 {
 	struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx;
 	struct ptlrpc_sec_policy *policy;
-	ENTRY;
 
 	LASSERT(ctx);
 	LASSERT(ctx->cc_sec);
@@ -1703,7 +1690,6 @@
 	policy = ctx->cc_sec->ps_policy;
 	policy->sp_cops->free_repbuf(ctx->cc_sec, req);
 	req->rq_repmsg = NULL;
-	EXIT;
 }
 
 int sptlrpc_cli_install_rvs_ctx(struct obd_import *imp,
@@ -2032,7 +2018,6 @@
 	struct ptlrpc_sec_policy *policy;
 	struct lustre_msg	*msg = req->rq_reqbuf;
 	int		       rc;
-	ENTRY;
 
 	LASSERT(msg);
 	LASSERT(req->rq_reqmsg == NULL);
@@ -2050,18 +2035,18 @@
 	default:
 		CERROR("error unpacking request from %s x"LPU64"\n",
 		       libcfs_id2str(req->rq_peer), req->rq_xid);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	req->rq_flvr.sf_rpc = WIRE_FLVR(msg->lm_secflvr);
 	req->rq_sp_from = LUSTRE_SP_ANY;
-	req->rq_auth_uid = INVALID_UID;
-	req->rq_auth_mapped_uid = INVALID_UID;
+	req->rq_auth_uid = -1;
+	req->rq_auth_mapped_uid = -1;
 
 	policy = sptlrpc_wireflavor2policy(req->rq_flvr.sf_rpc);
 	if (!policy) {
 		CERROR("unsupported rpc flavor %x\n", req->rq_flvr.sf_rpc);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	LASSERT(policy->sp_sops->accept);
@@ -2079,7 +2064,7 @@
 
 	/* sanity check for the request source */
 	rc = sptlrpc_svc_check_from(req, rc);
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2092,7 +2077,6 @@
 	struct ptlrpc_sec_policy *policy;
 	struct ptlrpc_reply_state *rs;
 	int rc;
-	ENTRY;
 
 	LASSERT(req->rq_svc_ctx);
 	LASSERT(req->rq_svc_ctx->sc_policy);
@@ -2105,7 +2089,7 @@
 		/* failed alloc, try emergency pool */
 		rs = lustre_get_emerg_rs(req->rq_rqbd->rqbd_svcpt);
 		if (rs == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		req->rq_reply_state = rs;
 		rc = policy->sp_sops->alloc_rs(req, msglen);
@@ -2118,7 +2102,7 @@
 	LASSERT(rc != 0 ||
 		(req->rq_reply_state && req->rq_reply_state->rs_msg));
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2131,7 +2115,6 @@
 {
 	struct ptlrpc_sec_policy *policy;
 	int rc;
-	ENTRY;
 
 	LASSERT(req->rq_svc_ctx);
 	LASSERT(req->rq_svc_ctx->sc_policy);
@@ -2142,7 +2125,7 @@
 	rc = policy->sp_sops->authorize(req);
 	LASSERT(rc || req->rq_reply_state->rs_repdata_len);
 
-	RETURN(rc);
+	return rc;
 }
 
 /**
@@ -2152,7 +2135,6 @@
 {
 	struct ptlrpc_sec_policy *policy;
 	unsigned int prealloc;
-	ENTRY;
 
 	LASSERT(rs->rs_svc_ctx);
 	LASSERT(rs->rs_svc_ctx->sc_policy);
@@ -2165,7 +2147,6 @@
 
 	if (prealloc)
 		lustre_put_emerg_rs(rs);
-	EXIT;
 }
 
 void sptlrpc_svc_ctx_addref(struct ptlrpc_request *req)
@@ -2314,10 +2295,10 @@
 
 	pud = lustre_msg_buf(msg, offset, 0);
 
-	pud->pud_uid = current_uid();
-	pud->pud_gid = current_gid();
-	pud->pud_fsuid = current_fsuid();
-	pud->pud_fsgid = current_fsgid();
+	pud->pud_uid = from_kuid(&init_user_ns, current_uid());
+	pud->pud_gid = from_kgid(&init_user_ns, current_gid());
+	pud->pud_fsuid = from_kuid(&init_user_ns, current_fsuid());
+	pud->pud_fsgid = from_kgid(&init_user_ns, current_fsgid());
 	pud->pud_cap = cfs_curproc_cap_pack();
 	pud->pud_ngroups = (msg->lm_buflens[offset] - sizeof(*pud)) / 4;
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
index bf53f1b..9013745 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
@@ -156,7 +156,7 @@
 		      "max waitqueue depth:     %u\n"
 		      "max wait time:	   "CFS_TIME_T"/%u\n"
 		      ,
-		      num_physpages,
+		      totalram_pages,
 		      PAGES_PER_POOL,
 		      page_pools.epp_max_pages,
 		      page_pools.epp_max_pools,
@@ -705,7 +705,7 @@
 	 * maximum capacity is 1/8 of total physical memory.
 	 * is the 1/8 a good number?
 	 */
-	page_pools.epp_max_pages = num_physpages / 8;
+	page_pools.epp_max_pages = totalram_pages / 8;
 	page_pools.epp_max_pools = npages_to_npools(page_pools.epp_max_pages);
 
 	init_waitqueue_head(&page_pools.epp_waitq);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
index a45a392..6cc3f23 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c
@@ -195,7 +195,7 @@
 	flavor = strchr(param, '=');
 	if (flavor == NULL) {
 		CERROR("invalid param, no '='\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	*flavor++ = '\0';
 
@@ -208,7 +208,7 @@
 		rule->sr_netid = libcfs_str2net(param);
 		if (rule->sr_netid == LNET_NIDNET(LNET_NID_ANY)) {
 			CERROR("invalid network name: %s\n", param);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	}
 
@@ -228,16 +228,16 @@
 			rule->sr_to = LUSTRE_SP_MDT;
 		} else {
 			CERROR("invalid rule dir segment: %s\n", dir);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	}
 
 	/* 2.1 flavor */
 	rc = sptlrpc_parse_flavor(flavor, &rule->sr_flvr);
 	if (rc)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(sptlrpc_parse_rule);
 
@@ -661,18 +661,17 @@
 	char		    fsname[MTI_NAME_MAXLEN];
 	struct sptlrpc_rule     rule;
 	int		     rc;
-	ENTRY;
 
 	target = lustre_cfg_string(lcfg, 1);
 	if (target == NULL) {
 		CERROR("missing target name\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	param = lustre_cfg_string(lcfg, 2);
 	if (param == NULL) {
 		CERROR("missing parameter\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	CDEBUG(D_SEC, "processing rule: %s.%s\n", target, param);
@@ -680,13 +679,13 @@
 	/* parse rule to make sure the format is correct */
 	if (strncmp(param, PARAM_SRPC_FLVR, sizeof(PARAM_SRPC_FLVR) - 1) != 0) {
 		CERROR("Invalid sptlrpc parameter: %s\n", param);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	param += sizeof(PARAM_SRPC_FLVR) - 1;
 
 	rc = sptlrpc_parse_rule(param, &rule);
 	if (rc)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	if (conf == NULL) {
 		target2fsname(target, fsname, sizeof(fsname));
@@ -708,7 +707,7 @@
 	if (rc == 0)
 		conf->sc_modified++;
 
-	RETURN(rc);
+	return rc;
 }
 
 int sptlrpc_process_config(struct lustre_cfg *lcfg)
@@ -905,7 +904,6 @@
 void sptlrpc_conf_client_adapt(struct obd_device *obd)
 {
 	struct obd_import  *imp;
-	ENTRY;
 
 	LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0 ||
 		strcmp(obd->obd_type->typ_name, LUSTRE_OSC_NAME) ==0);
@@ -924,7 +922,6 @@
 	}
 
 	up_read(&obd->u.cli.cl_sem);
-	EXIT;
 }
 EXPORT_SYMBOL(sptlrpc_conf_client_adapt);
 
@@ -1011,11 +1008,10 @@
 	struct lvfs_run_ctxt  saved;
 	struct dentry	*dentry;
 	int		   rc;
-	ENTRY;
 
 	ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
 	if (ctxt == NULL)
-		RETURN(-EINVAL);
+		return -EINVAL;
 
 	push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
 
@@ -1058,7 +1054,7 @@
 	llog_ctxt_put(ctxt);
 	CDEBUG(D_SEC, "target %s: write local sptlrpc conf: rc = %d\n",
 	       obd->obd_name, rc);
-	RETURN(rc);
+	return rc;
 }
 
 static int local_read_handler(const struct lu_env *env,
@@ -1068,11 +1064,10 @@
 	struct sptlrpc_conf  *conf = (struct sptlrpc_conf *) data;
 	struct lustre_cfg    *lcfg = (struct lustre_cfg *)(rec + 1);
 	int		   cfg_len, rc;
-	ENTRY;
 
 	if (rec->lrh_type != OBD_CFG_REC) {
 		CERROR("unhandled lrh_type: %#x\n", rec->lrh_type);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	cfg_len = rec->lrh_len - sizeof(struct llog_rec_hdr) -
@@ -1081,15 +1076,15 @@
 	rc = lustre_cfg_sanity_check(lcfg, cfg_len);
 	if (rc) {
 		CERROR("Insane cfg\n");
-		RETURN(rc);
+		return rc;
 	}
 
 	if (lcfg->lcfg_command != LCFG_SPTLRPC_CONF) {
 		CERROR("invalid command (%x)\n", lcfg->lcfg_command);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
-	RETURN(__sptlrpc_process_config(lcfg, conf));
+	return __sptlrpc_process_config(lcfg, conf);
 }
 
 static
@@ -1100,14 +1095,13 @@
 	struct llog_ctxt      *ctxt;
 	struct lvfs_run_ctxt   saved;
 	int		    rc;
-	ENTRY;
 
 	LASSERT(conf->sc_updated == 0 && conf->sc_local == 0);
 
 	ctxt = llog_get_context(obd, LLOG_CONFIG_ORIG_CTXT);
 	if (ctxt == NULL) {
 		CERROR("missing llog context\n");
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 
 	push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
@@ -1143,7 +1137,7 @@
 	llog_ctxt_put(ctxt);
 	CDEBUG(D_SEC, "target %s: read local sptlrpc conf: rc = %d\n",
 	       obd->obd_name, rc);
-	RETURN(rc);
+	return rc;
 }
 
 
@@ -1160,7 +1154,6 @@
 	enum lustre_sec_part      sp_dst;
 	char		      fsname[MTI_NAME_MAXLEN];
 	int		       rc = 0;
-	ENTRY;
 
 	if (strcmp(obd->obd_type->typ_name, LUSTRE_MDT_NAME) == 0) {
 		sp_dst = LUSTRE_SP_MDT;
@@ -1168,7 +1161,7 @@
 		sp_dst = LUSTRE_SP_OST;
 	} else {
 		CERROR("unexpected obd type %s\n", obd->obd_type->typ_name);
-		RETURN(-EINVAL);
+		return -EINVAL;
 	}
 	CDEBUG(D_SEC, "get rules for target %s\n", obd->obd_uuid.uuid);
 
@@ -1210,7 +1203,7 @@
 				      LUSTRE_SP_ANY, sp_dst, rset);
 out:
 	mutex_unlock(&sptlrpc_conf_lock);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(sptlrpc_conf_target_get_rules);
 
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
index 4c96a14a..d2eb20e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
@@ -217,7 +217,7 @@
 int sptlrpc_gc_init(void)
 {
 	struct l_wait_info lwi = { 0 };
-	task_t *task;
+	struct task_struct *task;
 
 	mutex_init(&sec_gc_mutex);
 	spin_lock_init(&sec_gc_list_lock);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
index f552d2f..416401b 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c
@@ -192,7 +192,6 @@
 {
 	struct lustre_msg   *msg = req->rq_reqbuf;
 	struct plain_header *phdr;
-	ENTRY;
 
 	msg->lm_secflvr = req->rq_flvr.sf_rpc;
 
@@ -209,7 +208,7 @@
 
 	req->rq_reqdata_len = lustre_msg_size_v2(msg->lm_bufcount,
 						 msg->lm_buflens);
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -219,11 +218,10 @@
 	struct plain_header *phdr;
 	__u32		cksum;
 	int		  swabbed;
-	ENTRY;
 
 	if (msg->lm_bufcount != PLAIN_PACK_SEGMENTS) {
 		CERROR("unexpected reply buf count %u\n", msg->lm_bufcount);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	swabbed = ptlrpc_rep_need_swab(req);
@@ -231,24 +229,24 @@
 	phdr = lustre_msg_buf(msg, PLAIN_PACK_HDR_OFF, sizeof(*phdr));
 	if (phdr == NULL) {
 		CERROR("missing plain header\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (phdr->ph_ver != 0) {
 		CERROR("Invalid header version\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	/* expect no user desc in reply */
 	if (phdr->ph_flags & PLAIN_FL_USER) {
 		CERROR("Unexpected udesc flag in reply\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (phdr->ph_bulk_hash_alg != req->rq_flvr.u_bulk.hash.hash_alg) {
 		CERROR("reply bulk flavor %u != %u\n", phdr->ph_bulk_hash_alg,
 		       req->rq_flvr.u_bulk.hash.hash_alg);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (unlikely(req->rq_early)) {
@@ -262,7 +260,7 @@
 			CDEBUG(D_SEC,
 			       "early reply checksum mismatch: %08x != %08x\n",
 			       cpu_to_le32(cksum), msg->lm_cksum);
-			RETURN(-EINVAL);
+			return -EINVAL;
 		}
 	} else {
 		/* whether we sent with bulk or not, we expect the same
@@ -272,18 +270,18 @@
 			  phdr->ph_flags & PLAIN_FL_BULK)) {
 			CERROR("%s bulk checksum in reply\n",
 			       req->rq_pack_bulk ? "Missing" : "Unexpected");
-			RETURN(-EPROTO);
+			return -EPROTO;
 		}
 
 		if (phdr->ph_flags & PLAIN_FL_BULK) {
 			if (plain_unpack_bsd(msg, swabbed))
-				RETURN(-EPROTO);
+				return -EPROTO;
 		}
 	}
 
 	req->rq_repmsg = lustre_msg_buf(msg, PLAIN_PACK_MSG_OFF, 0);
 	req->rq_replen = lustre_msg_buflen(msg, PLAIN_PACK_MSG_OFF);
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -307,10 +305,10 @@
 	bsd->bsd_svc = SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc);
 
 	if (bsd->bsd_svc == SPTLRPC_BULK_SVC_NULL)
-		RETURN(0);
+		return 0;
 
 	if (req->rq_bulk_read)
-		RETURN(0);
+		return 0;
 
 	rc = plain_generate_bulk_csum(desc, req->rq_flvr.u_bulk.hash.hash_alg,
 				      token);
@@ -417,7 +415,6 @@
 void plain_destroy_sec(struct ptlrpc_sec *sec)
 {
 	struct plain_sec       *plsec = sec2plsec(sec);
-	ENTRY;
 
 	LASSERT(sec->ps_policy == &plain_policy);
 	LASSERT(sec->ps_import);
@@ -428,7 +425,6 @@
 	class_import_put(sec->ps_import);
 
 	OBD_FREE_PTR(plsec);
-	EXIT;
 }
 
 static
@@ -445,13 +441,12 @@
 	struct plain_sec       *plsec;
 	struct ptlrpc_sec      *sec;
 	struct ptlrpc_cli_ctx  *ctx;
-	ENTRY;
 
 	LASSERT(SPTLRPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_PLAIN);
 
 	OBD_ALLOC_PTR(plsec);
 	if (plsec == NULL)
-		RETURN(NULL);
+		return NULL;
 
 	/*
 	 * initialize plain_sec
@@ -476,12 +471,12 @@
 		ctx = plain_sec_install_ctx(plsec);
 		if (ctx == NULL) {
 			plain_destroy_sec(sec);
-			RETURN(NULL);
+			return NULL;
 		}
 		sptlrpc_cli_ctx_put(ctx, 1);
 	}
 
-	RETURN(sec);
+	return sec;
 }
 
 static
@@ -491,7 +486,6 @@
 {
 	struct plain_sec       *plsec = sec2plsec(sec);
 	struct ptlrpc_cli_ctx  *ctx;
-	ENTRY;
 
 	read_lock(&plsec->pls_lock);
 	ctx = plsec->pls_ctx;
@@ -502,7 +496,7 @@
 	if (unlikely(ctx == NULL))
 		ctx = plain_sec_install_ctx(plsec);
 
-	RETURN(ctx);
+	return ctx;
 }
 
 static
@@ -526,11 +520,10 @@
 {
 	struct plain_sec       *plsec = sec2plsec(sec);
 	struct ptlrpc_cli_ctx  *ctx;
-	ENTRY;
 
 	/* do nothing unless caller want to flush for 'all' */
 	if (uid != -1)
-		RETURN(0);
+		return 0;
 
 	write_lock(&plsec->pls_lock);
 	ctx = plsec->pls_ctx;
@@ -539,7 +532,7 @@
 
 	if (ctx)
 		sptlrpc_cli_ctx_put(ctx, 1);
-	RETURN(0);
+	return 0;
 }
 
 static
@@ -549,7 +542,6 @@
 {
 	__u32 buflens[PLAIN_PACK_SEGMENTS] = { 0, };
 	int   alloc_len;
-	ENTRY;
 
 	buflens[PLAIN_PACK_HDR_OFF] = sizeof(struct plain_header);
 	buflens[PLAIN_PACK_MSG_OFF] = msgsize;
@@ -570,7 +562,7 @@
 		alloc_len = size_roundup_power2(alloc_len);
 		OBD_ALLOC_LARGE(req->rq_reqbuf, alloc_len);
 		if (!req->rq_reqbuf)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		req->rq_reqbuf_len = alloc_len;
 	} else {
@@ -585,20 +577,18 @@
 	if (req->rq_pack_udesc)
 		sptlrpc_pack_user_desc(req->rq_reqbuf, PLAIN_PACK_USER_OFF);
 
-	RETURN(0);
+	return 0;
 }
 
 static
 void plain_free_reqbuf(struct ptlrpc_sec *sec,
 		       struct ptlrpc_request *req)
 {
-	ENTRY;
 	if (!req->rq_pool) {
 		OBD_FREE_LARGE(req->rq_reqbuf, req->rq_reqbuf_len);
 		req->rq_reqbuf = NULL;
 		req->rq_reqbuf_len = 0;
 	}
-	EXIT;
 }
 
 static
@@ -608,7 +598,6 @@
 {
 	__u32 buflens[PLAIN_PACK_SEGMENTS] = { 0, };
 	int alloc_len;
-	ENTRY;
 
 	buflens[PLAIN_PACK_HDR_OFF] = sizeof(struct plain_header);
 	buflens[PLAIN_PACK_MSG_OFF] = msgsize;
@@ -627,21 +616,19 @@
 
 	OBD_ALLOC_LARGE(req->rq_repbuf, alloc_len);
 	if (!req->rq_repbuf)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	req->rq_repbuf_len = alloc_len;
-	RETURN(0);
+	return 0;
 }
 
 static
 void plain_free_repbuf(struct ptlrpc_sec *sec,
 		       struct ptlrpc_request *req)
 {
-	ENTRY;
 	OBD_FREE_LARGE(req->rq_repbuf, req->rq_repbuf_len);
 	req->rq_repbuf = NULL;
 	req->rq_repbuf_len = 0;
-	EXIT;
 }
 
 static
@@ -652,7 +639,6 @@
 	struct lustre_msg      *newbuf;
 	int		     oldsize;
 	int		     newmsg_size, newbuf_size;
-	ENTRY;
 
 	LASSERT(req->rq_reqbuf);
 	LASSERT(req->rq_reqbuf_len >= req->rq_reqlen);
@@ -681,7 +667,7 @@
 
 		OBD_ALLOC_LARGE(newbuf, newbuf_size);
 		if (newbuf == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		memcpy(newbuf, req->rq_reqbuf, req->rq_reqbuf_len);
 
@@ -697,7 +683,7 @@
 	_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
 
 	req->rq_reqlen = newmsg_size;
-	RETURN(0);
+	return 0;
 }
 
 /****************************************
@@ -715,7 +701,6 @@
 	struct lustre_msg   *msg = req->rq_reqbuf;
 	struct plain_header *phdr;
 	int		  swabbed;
-	ENTRY;
 
 	LASSERT(SPTLRPC_FLVR_POLICY(req->rq_flvr.sf_rpc) ==
 		SPTLRPC_POLICY_PLAIN);
@@ -725,12 +710,12 @@
 	    SPTLRPC_FLVR_BULK_TYPE(req->rq_flvr.sf_rpc) !=
 	    SPTLRPC_FLVR_BULK_TYPE(SPTLRPC_FLVR_PLAIN)) {
 		CERROR("Invalid rpc flavor %x\n", req->rq_flvr.sf_rpc);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	if (msg->lm_bufcount < PLAIN_PACK_SEGMENTS) {
 		CERROR("unexpected request buf count %u\n", msg->lm_bufcount);
-		RETURN(SECSVC_DROP);
+		return SECSVC_DROP;
 	}
 
 	swabbed = ptlrpc_req_need_swab(req);
@@ -738,17 +723,17 @@
 	phdr = lustre_msg_buf(msg, PLAIN_PACK_HDR_OFF, sizeof(*phdr));
 	if (phdr == NULL) {
 		CERROR("missing plain header\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (phdr->ph_ver != 0) {
 		CERROR("Invalid header version\n");
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	if (phdr->ph_bulk_hash_alg >= BULK_HASH_ALG_MAX) {
 		CERROR("invalid hash algorithm: %u\n", phdr->ph_bulk_hash_alg);
-		RETURN(-EPROTO);
+		return -EPROTO;
 	}
 
 	req->rq_sp_from = phdr->ph_sp;
@@ -758,7 +743,7 @@
 		if (sptlrpc_unpack_user_desc(msg, PLAIN_PACK_USER_OFF,
 					     swabbed)) {
 			CERROR("Mal-formed user descriptor\n");
-			RETURN(SECSVC_DROP);
+			return SECSVC_DROP;
 		}
 
 		req->rq_pack_udesc = 1;
@@ -767,7 +752,7 @@
 
 	if (phdr->ph_flags & PLAIN_FL_BULK) {
 		if (plain_unpack_bsd(msg, swabbed))
-			RETURN(SECSVC_DROP);
+			return SECSVC_DROP;
 
 		req->rq_pack_bulk = 1;
 	}
@@ -778,7 +763,7 @@
 	req->rq_svc_ctx = &plain_svc_ctx;
 	atomic_inc(&req->rq_svc_ctx->sc_refcount);
 
-	RETURN(SECSVC_OK);
+	return SECSVC_OK;
 }
 
 static
@@ -787,7 +772,6 @@
 	struct ptlrpc_reply_state   *rs;
 	__u32			buflens[PLAIN_PACK_SEGMENTS] = { 0, };
 	int			  rs_size = sizeof(*rs);
-	ENTRY;
 
 	LASSERT(msgsize % 8 == 0);
 
@@ -807,7 +791,7 @@
 	} else {
 		OBD_ALLOC_LARGE(rs, rs_size);
 		if (rs == NULL)
-			RETURN(-ENOMEM);
+			return -ENOMEM;
 
 		rs->rs_size = rs_size;
 	}
@@ -821,20 +805,17 @@
 	rs->rs_msg = lustre_msg_buf_v2(rs->rs_repbuf, PLAIN_PACK_MSG_OFF, 0);
 
 	req->rq_reply_state = rs;
-	RETURN(0);
+	return 0;
 }
 
 static
 void plain_free_rs(struct ptlrpc_reply_state *rs)
 {
-	ENTRY;
-
 	LASSERT(atomic_read(&rs->rs_svc_ctx->sc_refcount) > 1);
 	atomic_dec(&rs->rs_svc_ctx->sc_refcount);
 
 	if (!rs->rs_prealloc)
 		OBD_FREE_LARGE(rs, rs->rs_size);
-	EXIT;
 }
 
 static
@@ -844,7 +825,6 @@
 	struct lustre_msg_v2      *msg = rs->rs_repbuf;
 	struct plain_header       *phdr;
 	int			len;
-	ENTRY;
 
 	LASSERT(rs);
 	LASSERT(msg);
@@ -882,7 +862,7 @@
 			req->rq_reply_off = 0;
 	}
 
-	RETURN(0);
+	return 0;
 }
 
 static
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index 1667b8e..ac8b5fd 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -369,7 +369,6 @@
 void ptlrpc_dispatch_difficult_reply(struct ptlrpc_reply_state *rs)
 {
 	struct ptlrpc_hr_thread *hrt;
-	ENTRY;
 
 	LASSERT(list_empty(&rs->rs_list));
 
@@ -380,28 +379,23 @@
 	spin_unlock(&hrt->hrt_lock);
 
 	wake_up(&hrt->hrt_waitq);
-	EXIT;
 }
 
 void
 ptlrpc_schedule_difficult_reply(struct ptlrpc_reply_state *rs)
 {
-	ENTRY;
-
 	LASSERT(spin_is_locked(&rs->rs_svcpt->scp_rep_lock));
 	LASSERT(spin_is_locked(&rs->rs_lock));
 	LASSERT (rs->rs_difficult);
 	rs->rs_scheduled_ever = 1;  /* flag any notification attempt */
 
 	if (rs->rs_scheduled) {     /* being set up or already notified */
-		EXIT;
 		return;
 	}
 
 	rs->rs_scheduled = 1;
 	list_del_init(&rs->rs_list);
 	ptlrpc_dispatch_difficult_reply(rs);
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_schedule_difficult_reply);
 
@@ -409,7 +403,6 @@
 {
 	struct ptlrpc_reply_state *rs, *nxt;
 	DECLARE_RS_BATCH(batch);
-	ENTRY;
 
 	rs_batch_init(&batch);
 	/* Find any replies that have been committed and get their service
@@ -429,7 +422,6 @@
 	}
 	spin_unlock(&exp->exp_uncommitted_replies_lock);
 	rs_batch_fini(&batch);
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_commit_replies);
 
@@ -551,6 +543,7 @@
 	if (tc->tc_thr_factor != 0) {
 		int	  factor = tc->tc_thr_factor;
 		const int fade = 4;
+		cpumask_t mask;
 
 		/*
 		 * User wants to increase number of threads with for
@@ -564,7 +557,8 @@
 		 * have too many threads no matter how many cores/HTs
 		 * there are.
 		 */
-		if (cfs_cpu_ht_nsiblings(0) > 1) { /* weight is # of HTs */
+		cpumask_copy(&mask, topology_thread_cpumask(0));
+		if (cpus_weight(mask) > 1) { /* weight is # of HTs */
 			/* depress thread factor for hyper-thread */
 			factor = factor - (factor >> 1) + (factor >> 3);
 		}
@@ -689,7 +683,7 @@
  */
 struct ptlrpc_service *
 ptlrpc_register_service(struct ptlrpc_service_conf *conf,
-			proc_dir_entry_t *proc_entry)
+			struct proc_dir_entry *proc_entry)
 {
 	struct ptlrpc_service_cpt_conf	*cconf = &conf->psc_cpt;
 	struct ptlrpc_service		*service;
@@ -700,7 +694,6 @@
 	int				cpt;
 	int				rc;
 	int				i;
-	ENTRY;
 
 	LASSERT(conf->psc_buf.bc_nbufs > 0);
 	LASSERT(conf->psc_buf.bc_buf_size >=
@@ -724,7 +717,7 @@
 			if (rc != 0) {
 				CERROR("%s: invalid CPT pattern string: %s",
 				       conf->psc_name, cconf->cc_pattern);
-				RETURN(ERR_PTR(-EINVAL));
+				return ERR_PTR(-EINVAL);
 			}
 
 			rc = cfs_expr_list_values(el, ncpts, &cpts);
@@ -734,7 +727,7 @@
 				       conf->psc_name, cconf->cc_pattern, rc);
 				if (cpts != NULL)
 					OBD_FREE(cpts, sizeof(*cpts) * ncpts);
-				RETURN(ERR_PTR(rc < 0 ? rc : -EINVAL));
+				return ERR_PTR(rc < 0 ? rc : -EINVAL);
 			}
 			ncpts = rc;
 		}
@@ -744,7 +737,7 @@
 	if (service == NULL) {
 		if (cpts != NULL)
 			OBD_FREE(cpts, sizeof(*cpts) * ncpts);
-		RETURN(ERR_PTR(-ENOMEM));
+		return ERR_PTR(-ENOMEM);
 	}
 
 	service->srv_cptable		= cptable;
@@ -823,10 +816,10 @@
 		GOTO(failed, rc);
 	}
 
-	RETURN(service);
+	return service;
 failed:
 	ptlrpc_unregister_service(service);
-	RETURN(ERR_PTR(rc));
+	return ERR_PTR(rc);
 }
 EXPORT_SYMBOL(ptlrpc_register_service);
 
@@ -1035,8 +1028,6 @@
 	struct obd_export *oldest_exp;
 	time_t oldest_time, new_time;
 
-	ENTRY;
-
 	LASSERT(exp);
 
 	/* Compensate for slow machines, etc, by faking our request time
@@ -1048,7 +1039,7 @@
 	/* Do not pay attention on 1sec or smaller renewals. */
 	new_time = cfs_time_current_sec() + extra_delay;
 	if (exp->exp_last_request_time + 1 /*second */ >= new_time)
-		RETURN_EXIT;
+		return;
 
 	exp->exp_last_request_time = new_time;
 	CDEBUG(D_HA, "updating export %s at "CFS_TIME_T" exp %p\n",
@@ -1063,7 +1054,7 @@
 	if (list_empty(&exp->exp_obd_chain_timed)) {
 		/* this one is not timed */
 		spin_unlock(&exp->exp_obd->obd_dev_lock);
-		RETURN_EXIT;
+		return;
 	}
 
 	list_move_tail(&exp->exp_obd_chain_timed,
@@ -1076,7 +1067,6 @@
 
 	if (exp->exp_obd->obd_recovering) {
 		/* be nice to everyone during recovery */
-		EXIT;
 		return;
 	}
 
@@ -1105,8 +1095,6 @@
 				exp->exp_obd->obd_eviction_timer = 0;
 		}
 	}
-
-	EXIT;
 }
 
 /**
@@ -1259,7 +1247,6 @@
 	cfs_duration_t olddl = req->rq_deadline - cfs_time_current_sec();
 	time_t newdl;
 	int rc;
-	ENTRY;
 
 	/* deadline is when the client expects us to reply, margin is the
 	   difference between clients' and servers' expectations */
@@ -1270,7 +1257,7 @@
 		  at_get(&svcpt->scp_at_estimate), at_extra);
 
 	if (AT_OFF)
-		RETURN(0);
+		return 0;
 
 	if (olddl < 0) {
 		DEBUG_REQ(D_WARNING, req, "Already past deadline (%+lds), "
@@ -1278,13 +1265,13 @@
 			  "at_early_margin (%d)?", olddl, at_early_margin);
 
 		/* Return an error so we're not re-added to the timed list. */
-		RETURN(-ETIMEDOUT);
+		return -ETIMEDOUT;
 	}
 
 	if ((lustre_msghdr_get_flags(req->rq_reqmsg) & MSGHDR_AT_SUPPORT) == 0){
 		DEBUG_REQ(D_INFO, req, "Wanted to ask client for more time, "
 			  "but no AT support");
-		RETURN(-ENOSYS);
+		return -ENOSYS;
 	}
 
 	if (req->rq_export &&
@@ -1314,18 +1301,18 @@
 				  olddl, req->rq_arrival_time.tv_sec +
 				  at_get(&svcpt->scp_at_estimate) -
 				  cfs_time_current_sec());
-			RETURN(-ETIMEDOUT);
+			return -ETIMEDOUT;
 		}
 	}
 	newdl = cfs_time_current_sec() + at_get(&svcpt->scp_at_estimate);
 
 	OBD_ALLOC(reqcopy, sizeof *reqcopy);
 	if (reqcopy == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	OBD_ALLOC_LARGE(reqmsg, req->rq_reqlen);
 	if (!reqmsg) {
 		OBD_FREE(reqcopy, sizeof *reqcopy);
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	}
 
 	*reqcopy = *req;
@@ -1384,7 +1371,7 @@
 	sptlrpc_svc_ctx_decref(reqcopy);
 	OBD_FREE_LARGE(reqmsg, req->rq_reqlen);
 	OBD_FREE(reqcopy, sizeof *reqcopy);
-	RETURN(rc);
+	return rc;
 }
 
 /* Send early replies to everybody expiring within at_early_margin
@@ -1399,19 +1386,18 @@
 	time_t now = cfs_time_current_sec();
 	cfs_duration_t delay;
 	int first, counter = 0;
-	ENTRY;
 
 	spin_lock(&svcpt->scp_at_lock);
 	if (svcpt->scp_at_check == 0) {
 		spin_unlock(&svcpt->scp_at_lock);
-		RETURN(0);
+		return 0;
 	}
 	delay = cfs_time_sub(cfs_time_current(), svcpt->scp_at_checktime);
 	svcpt->scp_at_check = 0;
 
 	if (array->paa_count == 0) {
 		spin_unlock(&svcpt->scp_at_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	/* The timer went off, but maybe the nearest rpc already completed. */
@@ -1420,7 +1406,7 @@
 		/* We've still got plenty of time.  Reset the timer. */
 		ptlrpc_at_set_timer(svcpt);
 		spin_unlock(&svcpt->scp_at_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	/* We're close to a timeout, and we don't know how much longer the
@@ -1490,7 +1476,7 @@
 		ptlrpc_server_drop_request(rq);
 	}
 
-	RETURN(1); /* return "did_something" for liblustre */
+	return 1; /* return "did_something" for liblustre */
 }
 
 /**
@@ -1501,12 +1487,11 @@
 				    struct ptlrpc_request *req)
 {
 	int rc = 0;
-	ENTRY;
 
 	if (svcpt->scp_service->srv_ops.so_hpreq_handler) {
 		rc = svcpt->scp_service->srv_ops.so_hpreq_handler(req);
 		if (rc < 0)
-			RETURN(rc);
+			return rc;
 		LASSERT(rc == 0);
 	}
 	if (req->rq_export && req->rq_ops) {
@@ -1527,7 +1512,7 @@
 			 * ost_brw_write().
 			 */
 			if (rc < 0)
-				RETURN(rc);
+				return rc;
 			LASSERT(rc == 0 || rc == 1);
 		}
 
@@ -1539,13 +1524,12 @@
 
 	ptlrpc_nrs_req_initialize(svcpt, req, rc);
 
-	RETURN(rc);
+	return rc;
 }
 
 /** Remove the request from the export list. */
 static void ptlrpc_server_hpreq_fini(struct ptlrpc_request *req)
 {
-	ENTRY;
 	if (req->rq_export && req->rq_ops) {
 		/* refresh lock timeout again so that client has more
 		 * room to send lock cancel RPC. */
@@ -1556,7 +1540,6 @@
 		list_del_init(&req->rq_exp_list);
 		spin_unlock_bh(&req->rq_export->exp_rpc_lock);
 	}
-	EXIT;
 }
 
 static int ptlrpc_hpreq_check(struct ptlrpc_request *req)
@@ -1587,15 +1570,14 @@
 				     struct ptlrpc_request *req)
 {
 	int	rc;
-	ENTRY;
 
 	rc = ptlrpc_server_hpreq_init(svcpt, req);
 	if (rc < 0)
-		RETURN(rc);
+		return rc;
 
 	ptlrpc_nrs_req_add(svcpt, req, !!rc);
 
-	RETURN(0);
+	return 0;
 }
 
 /**
@@ -1701,7 +1683,6 @@
 ptlrpc_server_request_get(struct ptlrpc_service_part *svcpt, bool force)
 {
 	struct ptlrpc_request *req = NULL;
-	ENTRY;
 
 	spin_lock(&svcpt->scp_req_lock);
 
@@ -1722,7 +1703,7 @@
 	}
 
 	spin_unlock(&svcpt->scp_req_lock);
-	RETURN(NULL);
+	return NULL;
 
 got_request:
 	svcpt->scp_nreqs_active++;
@@ -1734,7 +1715,7 @@
 	if (likely(req->rq_export))
 		class_export_rpc_inc(req->rq_export);
 
-	RETURN(req);
+	return req;
 }
 
 /**
@@ -1751,12 +1732,11 @@
 	struct ptlrpc_request	*req;
 	__u32			deadline;
 	int			rc;
-	ENTRY;
 
 	spin_lock(&svcpt->scp_lock);
 	if (list_empty(&svcpt->scp_req_incoming)) {
 		spin_unlock(&svcpt->scp_lock);
-		RETURN(0);
+		return 0;
 	}
 
 	req = list_entry(svcpt->scp_req_incoming.next,
@@ -1875,12 +1855,12 @@
 		GOTO(err_req, rc);
 
 	wake_up(&svcpt->scp_waitq);
-	RETURN(1);
+	return 1;
 
 err_req:
 	ptlrpc_server_finish_request(svcpt, req);
 
-	RETURN(1);
+	return 1;
 }
 
 /**
@@ -1898,11 +1878,10 @@
 	long		   timediff;
 	int		    rc;
 	int		    fail_opc = 0;
-	ENTRY;
 
 	request = ptlrpc_server_request_get(svcpt, false);
 	if (request == NULL)
-		RETURN(0);
+		return 0;
 
 	if (OBD_FAIL_CHECK(OBD_FAIL_PTLRPC_HPREQ_NOTIMEOUT))
 		fail_opc = OBD_FAIL_PTLRPC_HPREQ_NOTIMEOUT;
@@ -2041,7 +2020,7 @@
 out_req:
 	ptlrpc_server_finish_active_request(svcpt, request);
 
-	RETURN(1);
+	return 1;
 }
 
 /**
@@ -2055,7 +2034,6 @@
 	struct obd_export	 *exp;
 	int			nlocks;
 	int			been_handled;
-	ENTRY;
 
 	exp = rs->rs_export;
 
@@ -2141,12 +2119,12 @@
 		if (atomic_dec_and_test(&svcpt->scp_nreps_difficult) &&
 		    svc->srv_is_stopping)
 			wake_up_all(&svcpt->scp_waitq);
-		RETURN(1);
+		return 1;
 	}
 
 	/* still on the net; callback will schedule */
 	spin_unlock(&rs->rs_lock);
-	RETURN(1);
+	return 1;
 }
 
 
@@ -2252,7 +2230,9 @@
 	struct l_wait_info lwi = LWI_TIMEOUT(svcpt->scp_rqbd_timeout,
 					     ptlrpc_retry_rqbds, svcpt);
 
+	/* XXX: Add this back when libcfs watchdog is merged upstream
 	lc_watchdog_disable(thread->t_watchdog);
+	 */
 
 	cond_resched();
 
@@ -2266,8 +2246,10 @@
 	if (ptlrpc_thread_stopping(thread))
 		return -EINTR;
 
+	/*
 	lc_watchdog_touch(thread->t_watchdog,
 			  ptlrpc_server_get_timeout(svcpt));
+	 */
 	return 0;
 }
 
@@ -2284,11 +2266,10 @@
 	struct ptlrpc_service		*svc = svcpt->scp_service;
 	struct ptlrpc_reply_state	*rs;
 #ifdef WITH_GROUP_INFO
-	group_info_t *ginfo = NULL;
+	struct group_info *ginfo = NULL;
 #endif
 	struct lu_env *env;
 	int counter = 0, rc = 0;
-	ENTRY;
 
 	thread->t_pid = current_pid();
 	unshare_fs_struct();
@@ -2370,8 +2351,10 @@
 	/* wake up our creator in case he's still waiting. */
 	wake_up(&thread->t_ctl_waitq);
 
+	/*
 	thread->t_watchdog = lc_watchdog_add(ptlrpc_server_get_timeout(svcpt),
 					     NULL, NULL);
+	 */
 
 	spin_lock(&svcpt->scp_rep_lock);
 	list_add(&rs->rs_list, &svcpt->scp_rep_idle);
@@ -2426,8 +2409,10 @@
 		}
 	}
 
+	/*
 	lc_watchdog_delete(thread->t_watchdog);
 	thread->t_watchdog = NULL;
+	*/
 
 out_srv_fini:
 	/*
@@ -2550,7 +2535,6 @@
 	struct ptlrpc_hr_partition	*hrp;
 	int				i;
 	int				j;
-	ENTRY;
 
 	cfs_percpt_for_each(hrp, i, ptlrpc_hr.hr_partitions) {
 		int	rc = 0;
@@ -2573,9 +2557,9 @@
 		CERROR("Reply handling thread %d:%d Failed on starting: "
 		       "rc = %d\n", i, j, rc);
 		ptlrpc_stop_hr_threads();
-		RETURN(rc);
+		return rc;
 	}
-	RETURN(0);
+	return 0;
 }
 
 static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt)
@@ -2584,8 +2568,6 @@
 	struct ptlrpc_thread	*thread;
 	LIST_HEAD		(zombie);
 
-	ENTRY;
-
 	CDEBUG(D_INFO, "Stopping threads for service %s\n",
 	       svcpt->scp_service->srv_name);
 
@@ -2625,7 +2607,6 @@
 		list_del(&thread->t_link);
 		OBD_FREE_PTR(thread);
 	}
-	EXIT;
 }
 
 /**
@@ -2635,14 +2616,11 @@
 {
 	struct ptlrpc_service_part *svcpt;
 	int			   i;
-	ENTRY;
 
 	ptlrpc_service_for_each_part(svcpt, i, svc) {
 		if (svcpt->scp_service != NULL)
 			ptlrpc_svcpt_stop_threads(svcpt);
 	}
-
-	EXIT;
 }
 EXPORT_SYMBOL(ptlrpc_stop_all_threads);
 
@@ -2651,7 +2629,6 @@
 	int	rc = 0;
 	int	i;
 	int	j;
-	ENTRY;
 
 	/* We require 2 threads min, see note in ptlrpc_server_handle_request */
 	LASSERT(svc->srv_nthrs_cpt_init >= PTLRPC_NTHRS_INIT);
@@ -2669,12 +2646,12 @@
 		}
 	}
 
-	RETURN(0);
+	return 0;
  failed:
 	CERROR("cannot start %s thread #%d_%d: rc %d\n",
 	       svc->srv_thread_name, i, j, rc);
 	ptlrpc_stop_all_threads(svc);
-	RETURN(rc);
+	return rc;
 }
 EXPORT_SYMBOL(ptlrpc_start_threads);
 
@@ -2684,7 +2661,6 @@
 	struct ptlrpc_thread	*thread;
 	struct ptlrpc_service	*svc;
 	int			rc;
-	ENTRY;
 
 	LASSERT(svcpt != NULL);
 
@@ -2696,23 +2672,23 @@
 
  again:
 	if (unlikely(svc->srv_is_stopping))
-		RETURN(-ESRCH);
+		return -ESRCH;
 
 	if (!ptlrpc_threads_increasable(svcpt) ||
 	    (OBD_FAIL_CHECK(OBD_FAIL_TGT_TOOMANY_THREADS) &&
 	     svcpt->scp_nthrs_running == svc->srv_nthrs_cpt_init - 1))
-		RETURN(-EMFILE);
+		return -EMFILE;
 
 	OBD_CPT_ALLOC_PTR(thread, svc->srv_cptable, svcpt->scp_cpt);
 	if (thread == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 	init_waitqueue_head(&thread->t_ctl_waitq);
 
 	spin_lock(&svcpt->scp_lock);
 	if (!ptlrpc_threads_increasable(svcpt)) {
 		spin_unlock(&svcpt->scp_lock);
 		OBD_FREE_PTR(thread);
-		RETURN(-EMFILE);
+		return -EMFILE;
 	}
 
 	if (svcpt->scp_nthrs_starting != 0) {
@@ -2730,7 +2706,7 @@
 
 		CDEBUG(D_INFO, "Creating thread %s #%d race, retry later\n",
 		       svc->srv_thread_name, svcpt->scp_thr_nextid);
-		RETURN(-EAGAIN);
+		return -EAGAIN;
 	}
 
 	svcpt->scp_nthrs_starting++;
@@ -2755,33 +2731,42 @@
 		CERROR("cannot start thread '%s': rc %d\n",
 		       thread->t_name, rc);
 		spin_lock(&svcpt->scp_lock);
-		list_del(&thread->t_link);
 		--svcpt->scp_nthrs_starting;
-		spin_unlock(&svcpt->scp_lock);
-
-		OBD_FREE(thread, sizeof(*thread));
-		RETURN(rc);
+		if (thread_is_stopping(thread)) {
+			/* this ptlrpc_thread is being hanled
+			 * by ptlrpc_svcpt_stop_threads now
+			 */
+			thread_add_flags(thread, SVC_STOPPED);
+			wake_up(&thread->t_ctl_waitq);
+			spin_unlock(&svcpt->scp_lock);
+		} else {
+			list_del(&thread->t_link);
+			spin_unlock(&svcpt->scp_lock);
+			OBD_FREE_PTR(thread);
+		}
+		return rc;
 	}
 
 	if (!wait)
-		RETURN(0);
+		return 0;
 
 	l_wait_event(thread->t_ctl_waitq,
 		     thread_is_running(thread) || thread_is_stopped(thread),
 		     &lwi);
 
 	rc = thread_is_stopped(thread) ? thread->t_id : 0;
-	RETURN(rc);
+	return rc;
 }
 
 int ptlrpc_hr_init(void)
 {
+	cpumask_t			mask;
 	struct ptlrpc_hr_partition	*hrp;
 	struct ptlrpc_hr_thread		*hrt;
 	int				rc;
 	int				i;
 	int				j;
-	ENTRY;
+	int				weight;
 
 	memset(&ptlrpc_hr, 0, sizeof(ptlrpc_hr));
 	ptlrpc_hr.hr_cpt_table = cfs_cpt_table;
@@ -2789,10 +2774,13 @@
 	ptlrpc_hr.hr_partitions = cfs_percpt_alloc(ptlrpc_hr.hr_cpt_table,
 						   sizeof(*hrp));
 	if (ptlrpc_hr.hr_partitions == NULL)
-		RETURN(-ENOMEM);
+		return -ENOMEM;
 
 	init_waitqueue_head(&ptlrpc_hr.hr_waitq);
 
+	cpumask_copy(&mask, topology_thread_cpumask(0));
+	weight = cpus_weight(mask);
+
 	cfs_percpt_for_each(hrp, i, ptlrpc_hr.hr_partitions) {
 		hrp->hrp_cpt = i;
 
@@ -2800,7 +2788,7 @@
 		atomic_set(&hrp->hrp_nstopped, 0);
 
 		hrp->hrp_nthrs = cfs_cpt_weight(ptlrpc_hr.hr_cpt_table, i);
-		hrp->hrp_nthrs /= cfs_cpu_ht_nsiblings(0);
+		hrp->hrp_nthrs /= weight;
 
 		LASSERT(hrp->hrp_nthrs > 0);
 		OBD_CPT_ALLOC(hrp->hrp_thrs, ptlrpc_hr.hr_cpt_table, i,
@@ -2823,7 +2811,7 @@
 out:
 	if (rc != 0)
 		ptlrpc_hr_fini();
-	RETURN(rc);
+	return rc;
 }
 
 void ptlrpc_hr_fini(void)
@@ -3045,8 +3033,6 @@
 
 int ptlrpc_unregister_service(struct ptlrpc_service *service)
 {
-	ENTRY;
-
 	CDEBUG(D_NET, "%s: tearing down\n", service->srv_name);
 
 	service->srv_is_stopping = 1;
@@ -3066,7 +3052,7 @@
 
 	ptlrpc_service_free(service);
 
-	RETURN(0);
+	return 0;
 }
 EXPORT_SYMBOL(ptlrpc_unregister_service);
 
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 10393da..5a5c639 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -750,8 +750,6 @@
 	writel(0, nvec->base + I2C_SL_ADDR2);
 
 	enable_irq(nvec->irq);
-
-	clk_disable_unprepare(nvec->i2c_clk);
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -872,9 +870,6 @@
 
 	tegra_init_i2c_slave(nvec);
 
-	clk_prepare_enable(i2c_clk);
-
-
 	/* enable event reporting */
 	nvec_toggle_global_events(nvec, true);
 
diff --git a/drivers/staging/octeon-usb/Kconfig b/drivers/staging/octeon-usb/Kconfig
index 018af6d..16ea17f 100644
--- a/drivers/staging/octeon-usb/Kconfig
+++ b/drivers/staging/octeon-usb/Kconfig
@@ -1,6 +1,6 @@
 config OCTEON_USB
 	tristate "Cavium Networks Octeon USB support"
-	depends on CPU_CAVIUM_OCTEON && USB
+	depends on CAVIUM_OCTEON_SOC && USB
 	help
 	  This driver supports USB host controller on some Cavium
 	  Networks' products in the Octeon family.
diff --git a/drivers/staging/octeon-usb/cvmx-usb.c b/drivers/staging/octeon-usb/cvmx-usb.c
index bf36649..d7b3c82 100644
--- a/drivers/staging/octeon-usb/cvmx-usb.c
+++ b/drivers/staging/octeon-usb/cvmx-usb.c
@@ -46,8 +46,6 @@
  * systems. These functions provide a generic API to the Octeon
  * USB blocks, hiding the internal hardware specific
  * operations.
- *
- * <hr>$Revision: 32636 $<hr>
  */
 #include <linux/delay.h>
 #include <asm/octeon/cvmx.h>
@@ -68,30 +66,27 @@
 #define CVMX_PREFETCH_PREF0(address, offset) CVMX_PREFETCH_PREFX(0, address, offset)
 #define CVMX_CLZ(result, input) asm ("clz %[rd],%[rs]" : [rd] "=d" (result) : [rs] "d" (input))
 
-#define cvmx_likely likely
-#define cvmx_wait_usec udelay
-#define cvmx_unlikely unlikely
-#define cvmx_le16_to_cpu le16_to_cpu
+#define MAX_RETRIES		3		/* Maximum number of times to retry failed transactions */
+#define MAX_PIPES		32		/* Maximum number of pipes that can be open at once */
+#define MAX_TRANSACTIONS	256		/* Maximum number of outstanding transactions across all pipes */
+#define MAX_CHANNELS		8		/* Maximum number of hardware channels supported by the USB block */
+#define MAX_USB_ADDRESS		127		/* The highest valid USB device address */
+#define MAX_USB_ENDPOINT	15		/* The highest valid USB endpoint number */
+#define MAX_USB_HUB_PORT	15		/* The highest valid port number on a hub */
+#define MAX_TRANSFER_BYTES	((1<<19)-1)	/* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */
+#define MAX_TRANSFER_PACKETS	((1<<10)-1)	/* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */
 
-#define MAX_RETRIES         3   /* Maximum number of times to retry failed transactions */
-#define MAX_PIPES           32  /* Maximum number of pipes that can be open at once */
-#define MAX_TRANSACTIONS    256 /* Maximum number of outstanding transactions across all pipes */
-#define MAX_CHANNELS        8   /* Maximum number of hardware channels supported by the USB block */
-#define MAX_USB_ADDRESS     127 /* The highest valid USB device address */
-#define MAX_USB_ENDPOINT    15  /* The highest valid USB endpoint number */
-#define MAX_USB_HUB_PORT    15  /* The highest valid port number on a hub */
-#define MAX_TRANSFER_BYTES  ((1<<19)-1) /* The low level hardware can transfer a maximum of this number of bytes in each transfer. The field is 19 bits wide */
-#define MAX_TRANSFER_PACKETS ((1<<10)-1) /* The low level hardware can transfer a maximum of this number of packets in each transfer. The field is 10 bits wide */
-
-/* These defines disable the normal read and write csr. This is so I can add
-    extra debug stuff to the usb specific version and I won't use the normal
-    version by mistake */
+/*
+ * These defines disable the normal read and write csr. This is so I can add
+ * extra debug stuff to the usb specific version and I won't use the normal
+ * version by mistake
+ */
 #define cvmx_read_csr use_cvmx_usb_read_csr64_instead_of_cvmx_read_csr
 #define cvmx_write_csr use_cvmx_usb_write_csr64_instead_of_cvmx_write_csr
 
-typedef enum {
-    __CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16,
-} cvmx_usb_transaction_flags_t;
+enum cvmx_usb_transaction_flags {
+	__CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16,
+};
 
 enum {
 	USB_CLOCK_TYPE_REF_12,
@@ -108,167 +103,208 @@
  * the NAK handler can backup to the previous low level
  * transaction with a simple clearing of bit 0.
  */
-typedef enum {
-    CVMX_USB_STAGE_NON_CONTROL,
-    CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE,
-    CVMX_USB_STAGE_SETUP,
-    CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE,
-    CVMX_USB_STAGE_DATA,
-    CVMX_USB_STAGE_DATA_SPLIT_COMPLETE,
-    CVMX_USB_STAGE_STATUS,
-    CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE,
-} cvmx_usb_stage_t;
+enum cvmx_usb_stage {
+	CVMX_USB_STAGE_NON_CONTROL,
+	CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE,
+	CVMX_USB_STAGE_SETUP,
+	CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE,
+	CVMX_USB_STAGE_DATA,
+	CVMX_USB_STAGE_DATA_SPLIT_COMPLETE,
+	CVMX_USB_STAGE_STATUS,
+	CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE,
+};
 
 /**
- * This structure describes each pending USB transaction
- * regardless of type. These are linked together to form a list
- * of pending requests for a pipe.
+ * struct cvmx_usb_transaction - describes each pending USB transaction
+ *				 regardless of type. These are linked together
+ *				 to form a list of pending requests for a pipe.
+ *
+ * @prev:		Transaction before this one in the pipe.
+ * @next:		Transaction after this one in the pipe.
+ * @type:		Type of transaction, duplicated of the pipe.
+ * @flags:		State flags for this transaction.
+ * @buffer:		User's physical buffer address to read/write.
+ * @buffer_length:	Size of the user's buffer in bytes.
+ * @control_header:	For control transactions, physical address of the 8
+ *			byte standard header.
+ * @iso_start_frame:	For ISO transactions, the starting frame number.
+ * @iso_number_packets:	For ISO transactions, the number of packets in the
+ *			request.
+ * @iso_packets:	For ISO transactions, the sub packets in the request.
+ * @actual_bytes:	Actual bytes transfer for this transaction.
+ * @stage:		For control transactions, the current stage.
+ * @callback:		User's callback function when complete.
+ * @callback_data:	User's data.
  */
-typedef struct cvmx_usb_transaction {
-    struct cvmx_usb_transaction *prev;  /**< Transaction before this one in the pipe */
-    struct cvmx_usb_transaction *next;  /**< Transaction after this one in the pipe */
-    cvmx_usb_transfer_t type;           /**< Type of transaction, duplicated of the pipe */
-    cvmx_usb_transaction_flags_t flags; /**< State flags for this transaction */
-    uint64_t buffer;                    /**< User's physical buffer address to read/write */
-    int buffer_length;                  /**< Size of the user's buffer in bytes */
-    uint64_t control_header;            /**< For control transactions, physical address of the 8 byte standard header */
-    int iso_start_frame;                /**< For ISO transactions, the starting frame number */
-    int iso_number_packets;             /**< For ISO transactions, the number of packets in the request */
-    cvmx_usb_iso_packet_t *iso_packets; /**< For ISO transactions, the sub packets in the request */
-    int xfersize;
-    int pktcnt;
-    int retries;
-    int actual_bytes;                   /**< Actual bytes transfer for this transaction */
-    cvmx_usb_stage_t stage;             /**< For control transactions, the current stage */
-    cvmx_usb_callback_func_t callback;  /**< User's callback function when complete */
-    void *callback_data;                /**< User's data */
-} cvmx_usb_transaction_t;
+struct cvmx_usb_transaction {
+	struct cvmx_usb_transaction *prev;
+	struct cvmx_usb_transaction *next;
+	enum cvmx_usb_transfer type;
+	enum cvmx_usb_transaction_flags flags;
+	uint64_t buffer;
+	int buffer_length;
+	uint64_t control_header;
+	int iso_start_frame;
+	int iso_number_packets;
+	struct cvmx_usb_iso_packet *iso_packets;
+	int xfersize;
+	int pktcnt;
+	int retries;
+	int actual_bytes;
+	enum cvmx_usb_stage stage;
+	cvmx_usb_callback_func_t callback;
+	void *callback_data;
+};
 
 /**
- * A pipe represents a virtual connection between Octeon and some
- * USB device. It contains a list of pending request to the device.
+ * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon
+ *			  and some USB device. It contains a list of pending
+ *			  request to the device.
+ *
+ * @prev:		Pipe before this one in the list
+ * @next:		Pipe after this one in the list
+ * @head:		The first pending transaction
+ * @tail:		The last pending transaction
+ * @interval:		For periodic pipes, the interval between packets in
+ *			frames
+ * @next_tx_frame:	The next frame this pipe is allowed to transmit on
+ * @flags:		State flags for this pipe
+ * @device_speed:	Speed of device connected to this pipe
+ * @transfer_type:	Type of transaction supported by this pipe
+ * @transfer_dir:	IN or OUT. Ignored for Control
+ * @multi_count:	Max packet in a row for the device
+ * @max_packet:		The device's maximum packet size in bytes
+ * @device_addr:	USB device address at other end of pipe
+ * @endpoint_num:	USB endpoint number at other end of pipe
+ * @hub_device_addr:	Hub address this device is connected to
+ * @hub_port:		Hub port this device is connected to
+ * @pid_toggle:		This toggles between 0/1 on every packet send to track
+ *			the data pid needed
+ * @channel:		Hardware DMA channel for this pipe
+ * @split_sc_frame:	The low order bits of the frame number the split
+ *			complete should be sent on
  */
-typedef struct cvmx_usb_pipe {
-    struct cvmx_usb_pipe *prev;         /**< Pipe before this one in the list */
-    struct cvmx_usb_pipe *next;         /**< Pipe after this one in the list */
-    cvmx_usb_transaction_t *head;       /**< The first pending transaction */
-    cvmx_usb_transaction_t *tail;       /**< The last pending transaction */
-    uint64_t interval;                  /**< For periodic pipes, the interval between packets in frames */
-    uint64_t next_tx_frame;             /**< The next frame this pipe is allowed to transmit on */
-    cvmx_usb_pipe_flags_t flags;        /**< State flags for this pipe */
-    cvmx_usb_speed_t device_speed;      /**< Speed of device connected to this pipe */
-    cvmx_usb_transfer_t transfer_type;  /**< Type of transaction supported by this pipe */
-    cvmx_usb_direction_t transfer_dir;  /**< IN or OUT. Ignored for Control */
-    int multi_count;                    /**< Max packet in a row for the device */
-    uint16_t max_packet;                /**< The device's maximum packet size in bytes */
-    uint8_t device_addr;                /**< USB device address at other end of pipe */
-    uint8_t endpoint_num;               /**< USB endpoint number at other end of pipe */
-    uint8_t hub_device_addr;            /**< Hub address this device is connected to */
-    uint8_t hub_port;                   /**< Hub port this device is connected to */
-    uint8_t pid_toggle;                 /**< This toggles between 0/1 on every packet send to track the data pid needed */
-    uint8_t channel;                    /**< Hardware DMA channel for this pipe */
-    int8_t  split_sc_frame;             /**< The low order bits of the frame number the split complete should be sent on */
-} cvmx_usb_pipe_t;
-
-typedef struct {
-    cvmx_usb_pipe_t *head;              /**< Head of the list, or NULL if empty */
-    cvmx_usb_pipe_t *tail;              /**< Tail if the list, or NULL if empty */
-} cvmx_usb_pipe_list_t;
-
-typedef struct {
-    struct {
-        int channel;
-        int size;
-        uint64_t address;
-    } entry[MAX_CHANNELS+1];
-    int head;
-    int tail;
-} cvmx_usb_tx_fifo_t;
+struct cvmx_usb_pipe {
+	struct cvmx_usb_pipe *prev;
+	struct cvmx_usb_pipe *next;
+	struct cvmx_usb_transaction *head;
+	struct cvmx_usb_transaction *tail;
+	uint64_t interval;
+	uint64_t next_tx_frame;
+	enum cvmx_usb_pipe_flags flags;
+	enum cvmx_usb_speed device_speed;
+	enum cvmx_usb_transfer transfer_type;
+	enum cvmx_usb_direction transfer_dir;
+	int multi_count;
+	uint16_t max_packet;
+	uint8_t device_addr;
+	uint8_t endpoint_num;
+	uint8_t hub_device_addr;
+	uint8_t hub_port;
+	uint8_t pid_toggle;
+	uint8_t channel;
+	int8_t split_sc_frame;
+};
 
 /**
- * The state of the USB block is stored in this structure
+ * struct cvmx_usb_pipe_list
+ *
+ * @head: Head of the list, or NULL if empty.
+ * @tail: Tail if the list, or NULL if empty.
  */
-typedef struct {
-    int init_flags;                     /**< Flags passed to initialize */
-    int index;                          /**< Which USB block this is for */
-    int idle_hardware_channels;         /**< Bit set for every idle hardware channel */
-    cvmx_usbcx_hprt_t usbcx_hprt;       /**< Stored port status so we don't need to read a CSR to determine splits */
-    cvmx_usb_pipe_t *pipe_for_channel[MAX_CHANNELS];    /**< Map channels to pipes */
-    cvmx_usb_transaction_t *free_transaction_head;      /**< List of free transactions head */
-    cvmx_usb_transaction_t *free_transaction_tail;      /**< List of free transactions tail */
-    cvmx_usb_pipe_t pipe[MAX_PIPES];                    /**< Storage for pipes */
-    cvmx_usb_transaction_t transaction[MAX_TRANSACTIONS];       /**< Storage for transactions */
-    cvmx_usb_callback_func_t callback[__CVMX_USB_CALLBACK_END]; /**< User global callbacks */
-    void *callback_data[__CVMX_USB_CALLBACK_END];               /**< User data for each callback */
-    int indent;                         /**< Used by debug output to indent functions */
-    cvmx_usb_port_status_t port_status; /**< Last port status used for change notification */
-    cvmx_usb_pipe_list_t free_pipes;    /**< List of all pipes that are currently closed */
-    cvmx_usb_pipe_list_t idle_pipes;    /**< List of open pipes that have no transactions */
-    cvmx_usb_pipe_list_t active_pipes[4]; /**< Active pipes indexed by transfer type */
-    uint64_t frame_number;              /**< Increments every SOF interrupt for time keeping */
-    cvmx_usb_transaction_t *active_split; /**< Points to the current active split, or NULL */
-    cvmx_usb_tx_fifo_t periodic;
-    cvmx_usb_tx_fifo_t nonperiodic;
-} cvmx_usb_internal_state_t;
+struct cvmx_usb_pipe_list {
+	struct cvmx_usb_pipe *head;
+	struct cvmx_usb_pipe *tail;
+};
 
-/* This macro logs out whenever a function is called if debugging is on */
-#define CVMX_USB_LOG_CALLED() \
-    if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS)) \
-        cvmx_dprintf("%*s%s: called\n", 2*usb->indent++, "", __FUNCTION__);
+struct cvmx_usb_tx_fifo {
+	struct {
+		int channel;
+		int size;
+		uint64_t address;
+	} entry[MAX_CHANNELS+1];
+	int head;
+	int tail;
+};
 
-/* This macro logs out each function parameter if debugging is on */
-#define CVMX_USB_LOG_PARAM(format, param) \
-    if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS)) \
-        cvmx_dprintf("%*s%s: param %s = " format "\n", 2*usb->indent, "", __FUNCTION__, #param, param);
-
-/* This macro logs out when a function returns a value */
-#define CVMX_USB_RETURN(v)                                              \
-    do {                                                                \
-        typeof(v) r = v;                                                \
-        if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS))    \
-            cvmx_dprintf("%*s%s: returned %s(%d)\n", 2*--usb->indent, "", __FUNCTION__, #v, r); \
-        return r;                                                       \
-    } while (0);
-
-/* This macro logs out when a function doesn't return a value */
-#define CVMX_USB_RETURN_NOTHING()                                       \
-    do {                                                                \
-        if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS))    \
-            cvmx_dprintf("%*s%s: returned\n", 2*--usb->indent, "", __FUNCTION__); \
-        return;                                                         \
-    } while (0);
+/**
+ * struct cvmx_usb_internal_state - the state of the USB block
+ *
+ * init_flags:		   Flags passed to initialize.
+ * index:		   Which USB block this is for.
+ * idle_hardware_channels: Bit set for every idle hardware channel.
+ * usbcx_hprt:		   Stored port status so we don't need to read a CSR to
+ *			   determine splits.
+ * pipe_for_channel:	   Map channels to pipes.
+ * free_transaction_head:  List of free transactions head.
+ * free_transaction_tail:  List of free transactions tail.
+ * pipe:		   Storage for pipes.
+ * transaction:		   Storage for transactions.
+ * callback:		   User global callbacks.
+ * callback_data:	   User data for each callback.
+ * indent:		   Used by debug output to indent functions.
+ * port_status:		   Last port status used for change notification.
+ * free_pipes:		   List of all pipes that are currently closed.
+ * idle_pipes:		   List of open pipes that have no transactions.
+ * active_pipes:	   Active pipes indexed by transfer type.
+ * frame_number:	   Increments every SOF interrupt for time keeping.
+ * active_split:	   Points to the current active split, or NULL.
+ */
+struct cvmx_usb_internal_state {
+	int init_flags;
+	int index;
+	int idle_hardware_channels;
+	union cvmx_usbcx_hprt usbcx_hprt;
+	struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS];
+	struct cvmx_usb_transaction *free_transaction_head;
+	struct cvmx_usb_transaction *free_transaction_tail;
+	struct cvmx_usb_pipe pipe[MAX_PIPES];
+	struct cvmx_usb_transaction transaction[MAX_TRANSACTIONS];
+	cvmx_usb_callback_func_t callback[__CVMX_USB_CALLBACK_END];
+	void *callback_data[__CVMX_USB_CALLBACK_END];
+	int indent;
+	struct cvmx_usb_port_status port_status;
+	struct cvmx_usb_pipe_list free_pipes;
+	struct cvmx_usb_pipe_list idle_pipes;
+	struct cvmx_usb_pipe_list active_pipes[4];
+	uint64_t frame_number;
+	struct cvmx_usb_transaction *active_split;
+	struct cvmx_usb_tx_fifo periodic;
+	struct cvmx_usb_tx_fifo nonperiodic;
+};
 
 /* This macro spins on a field waiting for it to reach a value */
 #define CVMX_WAIT_FOR_FIELD32(address, type, field, op, value, timeout_usec)\
-    ({int result;                                                       \
-    do {                                                                \
-        uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec *     \
-			octeon_get_clock_rate() / 1000000;		\
-        type c;                                                         \
-        while (1)                                                       \
-        {                                                               \
-            c.u32 = __cvmx_usb_read_csr32(usb, address);                \
-            if (c.s.field op (value)) {                                 \
-                result = 0;                                             \
-                break;                                                  \
-            } else if (cvmx_get_cycle() > done) {                       \
-                result = -1;                                            \
-                break;                                                  \
-            } else                                                      \
-                cvmx_wait(100);                                         \
-        }                                                               \
-    } while (0);                                                        \
-    result;})
+	({int result;							    \
+	do {								    \
+		uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \
+			octeon_get_clock_rate() / 1000000;		    \
+		type c;							    \
+		while (1) {						    \
+			c.u32 = __cvmx_usb_read_csr32(usb, address);	    \
+			if (c.s.field op (value)) {			    \
+				result = 0;				    \
+				break;					    \
+			} else if (cvmx_get_cycle() > done) {		    \
+				result = -1;				    \
+				break;					    \
+			} else						    \
+				cvmx_wait(100);				    \
+		}							    \
+	} while (0);							    \
+	result; })
 
-/* This macro logically sets a single field in a CSR. It does the sequence
-    read, modify, and write */
-#define USB_SET_FIELD32(address, type, field, value)\
-    do {                                            \
-        type c;                                     \
-        c.u32 = __cvmx_usb_read_csr32(usb, address);\
-        c.s.field = value;                          \
-        __cvmx_usb_write_csr32(usb, address, c.u32);\
-    } while (0)
+/*
+ * This macro logically sets a single field in a CSR. It does the sequence
+ * read, modify, and write
+ */
+#define USB_SET_FIELD32(address, type, field, value)		\
+	do {							\
+		type c;						\
+		c.u32 = __cvmx_usb_read_csr32(usb, address);	\
+		c.s.field = value;				\
+		__cvmx_usb_write_csr32(usb, address, c.u32);	\
+	} while (0)
 
 /* Returns the IO address to push/pop stuff data from the FIFOs */
 #define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
@@ -280,145 +316,106 @@
 	case CVMX_BOARD_TYPE_LANAI2_A:
 	case CVMX_BOARD_TYPE_LANAI2_U:
 	case CVMX_BOARD_TYPE_LANAI2_G:
+	case CVMX_BOARD_TYPE_UBNT_E100:
 		return USB_CLOCK_TYPE_CRYSTAL_12;
 	}
-
-	/* FIXME: This should use CVMX_BOARD_TYPE_UBNT_E100 */
-	if (OCTEON_IS_MODEL(OCTEON_CN50XX) &&
-	    cvmx_sysinfo_get()->board_type == 20002)
-		return USB_CLOCK_TYPE_CRYSTAL_12;
-
 	return USB_CLOCK_TYPE_REF_48;
 }
 
 /**
- * @INTERNAL
  * Read a USB 32bit CSR. It performs the necessary address swizzle
  * for 32bit CSRs and logs the value in a readable format if
  * debugging is on.
  *
- * @param usb     USB block this access is for
- * @param address 64bit address to read
+ * @usb:     USB block this access is for
+ * @address: 64bit address to read
  *
- * @return Result of the read
+ * Returns: Result of the read
  */
-static inline uint32_t __cvmx_usb_read_csr32(cvmx_usb_internal_state_t *usb,
-                                             uint64_t address)
+static inline uint32_t __cvmx_usb_read_csr32(struct cvmx_usb_internal_state *usb,
+					     uint64_t address)
 {
-    uint32_t result = cvmx_read64_uint32(address ^ 4);
-    return result;
+	uint32_t result = cvmx_read64_uint32(address ^ 4);
+	return result;
 }
 
 
 /**
- * @INTERNAL
  * Write a USB 32bit CSR. It performs the necessary address
  * swizzle for 32bit CSRs and logs the value in a readable format
  * if debugging is on.
  *
- * @param usb     USB block this access is for
- * @param address 64bit address to write
- * @param value   Value to write
+ * @usb:     USB block this access is for
+ * @address: 64bit address to write
+ * @value:   Value to write
  */
-static inline void __cvmx_usb_write_csr32(cvmx_usb_internal_state_t *usb,
-                                          uint64_t address, uint32_t value)
+static inline void __cvmx_usb_write_csr32(struct cvmx_usb_internal_state *usb,
+					  uint64_t address, uint32_t value)
 {
-    cvmx_write64_uint32(address ^ 4, value);
-    cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+	cvmx_write64_uint32(address ^ 4, value);
+	cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
 }
 
 
 /**
- * @INTERNAL
  * Read a USB 64bit CSR. It logs the value in a readable format if
  * debugging is on.
  *
- * @param usb     USB block this access is for
- * @param address 64bit address to read
+ * @usb:     USB block this access is for
+ * @address: 64bit address to read
  *
- * @return Result of the read
+ * Returns: Result of the read
  */
-static inline uint64_t __cvmx_usb_read_csr64(cvmx_usb_internal_state_t *usb,
-                                             uint64_t address)
+static inline uint64_t __cvmx_usb_read_csr64(struct cvmx_usb_internal_state *usb,
+					     uint64_t address)
 {
-    uint64_t result = cvmx_read64_uint64(address);
-    return result;
+	uint64_t result = cvmx_read64_uint64(address);
+	return result;
 }
 
 
 /**
- * @INTERNAL
  * Write a USB 64bit CSR. It logs the value in a readable format
  * if debugging is on.
  *
- * @param usb     USB block this access is for
- * @param address 64bit address to write
- * @param value   Value to write
+ * @usb:     USB block this access is for
+ * @address: 64bit address to write
+ * @value:   Value to write
  */
-static inline void __cvmx_usb_write_csr64(cvmx_usb_internal_state_t *usb,
-                                          uint64_t address, uint64_t value)
+static inline void __cvmx_usb_write_csr64(struct cvmx_usb_internal_state *usb,
+					  uint64_t address, uint64_t value)
 {
-    cvmx_write64_uint64(address, value);
+	cvmx_write64_uint64(address, value);
 }
 
-
 /**
- * @INTERNAL
- * Utility function to convert complete codes into strings
- *
- * @param complete_code
- *               Code to convert
- *
- * @return Human readable string
- */
-static const char *__cvmx_usb_complete_to_string(cvmx_usb_complete_t complete_code)
-{
-    switch (complete_code)
-    {
-        case CVMX_USB_COMPLETE_SUCCESS: return "SUCCESS";
-        case CVMX_USB_COMPLETE_SHORT:   return "SHORT";
-        case CVMX_USB_COMPLETE_CANCEL:  return "CANCEL";
-        case CVMX_USB_COMPLETE_ERROR:   return "ERROR";
-        case CVMX_USB_COMPLETE_STALL:   return "STALL";
-        case CVMX_USB_COMPLETE_XACTERR: return "XACTERR";
-        case CVMX_USB_COMPLETE_DATATGLERR: return "DATATGLERR";
-        case CVMX_USB_COMPLETE_BABBLEERR: return "BABBLEERR";
-        case CVMX_USB_COMPLETE_FRAMEERR: return "FRAMEERR";
-    }
-    return "Update __cvmx_usb_complete_to_string";
-}
-
-
-/**
- * @INTERNAL
  * Return non zero if this pipe connects to a non HIGH speed
  * device through a high speed hub.
  *
- * @param usb    USB block this access is for
- * @param pipe   Pipe to check
+ * @usb:    USB block this access is for
+ * @pipe:   Pipe to check
  *
- * @return Non zero if we need to do split transactions
+ * Returns: Non zero if we need to do split transactions
  */
-static inline int __cvmx_usb_pipe_needs_split(cvmx_usb_internal_state_t *usb, cvmx_usb_pipe_t *pipe)
+static inline int __cvmx_usb_pipe_needs_split(struct cvmx_usb_internal_state *usb, struct cvmx_usb_pipe *pipe)
 {
-    return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH));
+	return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH));
 }
 
 
 /**
- * @INTERNAL
  * Trivial utility function to return the correct PID for a pipe
  *
- * @param pipe   pipe to check
+ * @pipe:   pipe to check
  *
- * @return PID for pipe
+ * Returns: PID for pipe
  */
-static inline int __cvmx_usb_get_data_pid(cvmx_usb_pipe_t *pipe)
+static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
 {
-    if (pipe->pid_toggle)
-        return 2; /* Data1 */
-    else
-        return 0; /* Data0 */
+	if (pipe->pid_toggle)
+		return 2; /* Data1 */
+	else
+		return 0; /* Data0 */
 }
 
 
@@ -428,127 +425,119 @@
  * by this API, a zero will be returned. Most Octeon chips
  * support one usb port, but some support two ports.
  * cvmx_usb_initialize() must be called on independent
- * cvmx_usb_state_t structures.
+ * struct cvmx_usb_state.
  *
- * @return Number of port, zero if usb isn't supported
+ * Returns: Number of port, zero if usb isn't supported
  */
 int cvmx_usb_get_num_ports(void)
 {
-    int arch_ports = 0;
+	int arch_ports = 0;
 
-    if (OCTEON_IS_MODEL(OCTEON_CN56XX))
-        arch_ports = 1;
-    else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
-        arch_ports = 2;
-    else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
-        arch_ports = 1;
-    else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
-        arch_ports = 1;
-    else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
-        arch_ports = 1;
-    else
-        arch_ports = 0;
+	if (OCTEON_IS_MODEL(OCTEON_CN56XX))
+		arch_ports = 1;
+	else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
+		arch_ports = 2;
+	else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
+		arch_ports = 1;
+	else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
+		arch_ports = 1;
+	else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
+		arch_ports = 1;
+	else
+		arch_ports = 0;
 
-    return arch_ports;
+	return arch_ports;
 }
 
 
 /**
- * @INTERNAL
  * Allocate a usb transaction for use
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
  *
- * @return Transaction or NULL
+ * Returns: Transaction or NULL
  */
-static inline cvmx_usb_transaction_t *__cvmx_usb_alloc_transaction(cvmx_usb_internal_state_t *usb)
+static inline struct cvmx_usb_transaction *__cvmx_usb_alloc_transaction(struct cvmx_usb_internal_state *usb)
 {
-    cvmx_usb_transaction_t *t;
-    t = usb->free_transaction_head;
-    if (t) {
-        usb->free_transaction_head = t->next;
-        if (!usb->free_transaction_head)
-            usb->free_transaction_tail = NULL;
-    }
-    else if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
-        cvmx_dprintf("%s: Failed to allocate a transaction\n", __FUNCTION__);
-    if (t) {
-        memset(t, 0, sizeof(*t));
-        t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE;
-    }
-    return t;
+	struct cvmx_usb_transaction *t;
+	t = usb->free_transaction_head;
+	if (t) {
+		usb->free_transaction_head = t->next;
+		if (!usb->free_transaction_head)
+			usb->free_transaction_tail = NULL;
+	}
+	if (t) {
+		memset(t, 0, sizeof(*t));
+		t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE;
+	}
+	return t;
 }
 
 
 /**
- * @INTERNAL
  * Free a usb transaction
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param transaction
- *               Transaction to free
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @transaction:
+ *		 Transaction to free
  */
-static inline void __cvmx_usb_free_transaction(cvmx_usb_internal_state_t *usb,
-                                        cvmx_usb_transaction_t *transaction)
+static inline void __cvmx_usb_free_transaction(struct cvmx_usb_internal_state *usb,
+					       struct cvmx_usb_transaction *transaction)
 {
-    transaction->flags = 0;
-    transaction->prev = NULL;
-    transaction->next = NULL;
-    if (usb->free_transaction_tail)
-        usb->free_transaction_tail->next = transaction;
-    else
-        usb->free_transaction_head = transaction;
-    usb->free_transaction_tail = transaction;
+	transaction->flags = 0;
+	transaction->prev = NULL;
+	transaction->next = NULL;
+	if (usb->free_transaction_tail)
+		usb->free_transaction_tail->next = transaction;
+	else
+		usb->free_transaction_head = transaction;
+	usb->free_transaction_tail = transaction;
 }
 
 
 /**
- * @INTERNAL
  * Add a pipe to the tail of a list
- * @param list   List to add pipe to
- * @param pipe   Pipe to add
+ * @list:   List to add pipe to
+ * @pipe:   Pipe to add
  */
-static inline void __cvmx_usb_append_pipe(cvmx_usb_pipe_list_t *list, cvmx_usb_pipe_t *pipe)
+static inline void __cvmx_usb_append_pipe(struct cvmx_usb_pipe_list *list, struct cvmx_usb_pipe *pipe)
 {
-    pipe->next = NULL;
-    pipe->prev = list->tail;
-    if (list->tail)
-        list->tail->next = pipe;
-    else
-        list->head = pipe;
-    list->tail = pipe;
+	pipe->next = NULL;
+	pipe->prev = list->tail;
+	if (list->tail)
+		list->tail->next = pipe;
+	else
+		list->head = pipe;
+	list->tail = pipe;
 }
 
 
 /**
- * @INTERNAL
  * Remove a pipe from a list
- * @param list   List to remove pipe from
- * @param pipe   Pipe to remove
+ * @list:   List to remove pipe from
+ * @pipe:   Pipe to remove
  */
-static inline void __cvmx_usb_remove_pipe(cvmx_usb_pipe_list_t *list, cvmx_usb_pipe_t *pipe)
+static inline void __cvmx_usb_remove_pipe(struct cvmx_usb_pipe_list *list, struct cvmx_usb_pipe *pipe)
 {
-    if (list->head == pipe) {
-        list->head = pipe->next;
-        pipe->next = NULL;
-        if (list->head)
-            list->head->prev = NULL;
-        else
-            list->tail = NULL;
-    }
-    else if (list->tail == pipe) {
-        list->tail = pipe->prev;
-        list->tail->next = NULL;
-        pipe->prev = NULL;
-    }
-    else {
-        pipe->prev->next = pipe->next;
-        pipe->next->prev = pipe->prev;
-        pipe->prev = NULL;
-        pipe->next = NULL;
-    }
+	if (list->head == pipe) {
+		list->head = pipe->next;
+		pipe->next = NULL;
+		if (list->head)
+			list->head->prev = NULL;
+		else
+			list->tail = NULL;
+	} else if (list->tail == pipe) {
+		list->tail = pipe->prev;
+		list->tail->next = NULL;
+		pipe->prev = NULL;
+	} else {
+		pipe->prev->next = pipe->next;
+		pipe->next->prev = pipe->prev;
+		pipe->prev = NULL;
+		pipe->next = NULL;
+	}
 }
 
 
@@ -557,302 +546,332 @@
  * other access to the Octeon USB port is made. The port starts
  * off in the disabled state.
  *
- * @param state  Pointer to an empty cvmx_usb_state_t structure
- *               that will be populated by the initialize call.
- *               This structure is then passed to all other USB
- *               functions.
- * @param usb_port_number
- *               Which Octeon USB port to initialize.
- * @param flags  Flags to control hardware initialization. See
- *               cvmx_usb_initialize_flags_t for the flag
- *               definitions. Some flags are mandatory.
+ * @state:	 Pointer to an empty struct cvmx_usb_state
+ *		 that will be populated by the initialize call.
+ *		 This structure is then passed to all other USB
+ *		 functions.
+ * @usb_port_number:
+ *		 Which Octeon USB port to initialize.
+ * @flags:	 Flags to control hardware initialization. See
+ *		 enum cvmx_usb_initialize_flags for the flag
+ *		 definitions. Some flags are mandatory.
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_initialize(cvmx_usb_state_t *state,
-                                      int usb_port_number,
-                                      cvmx_usb_initialize_flags_t flags)
+int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number,
+			enum cvmx_usb_initialize_flags flags)
 {
-    cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
-    cvmx_usbnx_usbp_ctl_status_t usbn_usbp_ctl_status;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+	union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    usb->init_flags = flags;
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", usb_port_number);
-    CVMX_USB_LOG_PARAM("0x%x", flags);
+	usb->init_flags = flags;
 
-    /* Make sure that state is large enough to store the internal state */
-    if (sizeof(*state) < sizeof(*usb))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    /* At first allow 0-1 for the usb port number */
-    if ((usb_port_number < 0) || (usb_port_number > 1))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    /* For all chips except 52XX there is only one port */
-    if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    /* Try to determine clock type automatically */
-    if ((flags & (CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI |
-                  CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0) {
-        if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12)
-            flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;  /* Only 12 MHZ crystals are supported */
-        else
-            flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
-    }
+	/* Make sure that state is large enough to store the internal state */
+	if (sizeof(*state) < sizeof(*usb))
+		return -EINVAL;
+	/* At first allow 0-1 for the usb port number */
+	if ((usb_port_number < 0) || (usb_port_number > 1))
+		return -EINVAL;
+	/* For all chips except 52XX there is only one port */
+	if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0))
+		return -EINVAL;
+	/* Try to determine clock type automatically */
+	if ((flags & (CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI |
+		      CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND)) == 0) {
+		if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12)
+			flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;  /* Only 12 MHZ crystals are supported */
+		else
+			flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
+	}
 
-    if (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
-        /* Check for auto ref clock frequency */
-        if (!(flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK))
-            switch (octeon_usb_get_clock_type()) {
-                case USB_CLOCK_TYPE_REF_12:
-                    flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
-                    break;
-                case USB_CLOCK_TYPE_REF_24:
-                    flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
-                    break;
-                case USB_CLOCK_TYPE_REF_48:
-                    flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
-                    break;
-                default:
-                    CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-                    break;
-            }
-    }
+	if (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
+		/* Check for auto ref clock frequency */
+		if (!(flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK))
+			switch (octeon_usb_get_clock_type()) {
+			case USB_CLOCK_TYPE_REF_12:
+				flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
+				break;
+			case USB_CLOCK_TYPE_REF_24:
+				flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
+				break;
+			case USB_CLOCK_TYPE_REF_48:
+				flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+	}
 
-    memset(usb, 0, sizeof(usb));
-    usb->init_flags = flags;
+	memset(usb, 0, sizeof(usb));
+	usb->init_flags = flags;
 
-    /* Initialize the USB state structure */
-    {
-        int i;
-        usb->index = usb_port_number;
+	/* Initialize the USB state structure */
+	{
+		int i;
+		usb->index = usb_port_number;
 
-        /* Initialize the transaction double linked list */
-        usb->free_transaction_head = NULL;
-        usb->free_transaction_tail = NULL;
-        for (i=0; i<MAX_TRANSACTIONS; i++)
-            __cvmx_usb_free_transaction(usb, usb->transaction + i);
-        for (i=0; i<MAX_PIPES; i++)
-            __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
-    }
+		/* Initialize the transaction double linked list */
+		usb->free_transaction_head = NULL;
+		usb->free_transaction_tail = NULL;
+		for (i = 0; i < MAX_TRANSACTIONS; i++)
+			__cvmx_usb_free_transaction(usb, usb->transaction + i);
+		for (i = 0; i < MAX_PIPES; i++)
+			__cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
+	}
 
-    /* Power On Reset and PHY Initialization */
+	/*
+	 * Power On Reset and PHY Initialization
+	 *
+	 * 1. Wait for DCOK to assert (nothing to do)
+	 *
+	 * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
+	 *     USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0
+	 */
+	usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
+	usbn_clk_ctl.s.por = 1;
+	usbn_clk_ctl.s.hrst = 0;
+	usbn_clk_ctl.s.prst = 0;
+	usbn_clk_ctl.s.hclk_rst = 0;
+	usbn_clk_ctl.s.enable = 0;
+	/*
+	 * 2b. Select the USB reference clock/crystal parameters by writing
+	 *     appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON]
+	 */
+	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
+		/*
+		 * The USB port uses 12/24/48MHz 2.5V board clock
+		 * source at USB_XO. USB_XI should be tied to GND.
+		 * Most Octeon evaluation boards require this setting
+		 */
+		if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+			usbn_clk_ctl.cn31xx.p_rclk  = 1; /* From CN31XX,CN30XX manual */
+			usbn_clk_ctl.cn31xx.p_xenbn = 0;
+		} else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
+			usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */
+		else
+			usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */
 
-    /* 1. Wait for DCOK to assert (nothing to do) */
-    /* 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
-        USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0 */
-    usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
-    usbn_clk_ctl.s.por = 1;
-    usbn_clk_ctl.s.hrst = 0;
-    usbn_clk_ctl.s.prst = 0;
-    usbn_clk_ctl.s.hclk_rst = 0;
-    usbn_clk_ctl.s.enable = 0;
-    /* 2b. Select the USB reference clock/crystal parameters by writing
-        appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON] */
-    if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
-        /* The USB port uses 12/24/48MHz 2.5V board clock
-            source at USB_XO. USB_XI should be tied to GND.
-            Most Octeon evaluation boards require this setting */
-        if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
-            usbn_clk_ctl.cn31xx.p_rclk  = 1; /* From CN31XX,CN30XX manual */
-            usbn_clk_ctl.cn31xx.p_xenbn = 0;
-        }
-        else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
-            usbn_clk_ctl.cn56xx.p_rtype = 2; /* From CN56XX,CN50XX manual */
-        else
-            usbn_clk_ctl.cn52xx.p_rtype = 1; /* From CN52XX manual */
+		switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
+		case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
+			usbn_clk_ctl.s.p_c_sel = 0;
+			break;
+		case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:
+			usbn_clk_ctl.s.p_c_sel = 1;
+			break;
+		case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:
+			usbn_clk_ctl.s.p_c_sel = 2;
+			break;
+		}
+	} else {
+		/*
+		 * The USB port uses a 12MHz crystal as clock source
+		 * at USB_XO and USB_XI
+		 */
+		if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+			usbn_clk_ctl.cn31xx.p_rclk  = 1; /* From CN31XX,CN30XX manual */
+			usbn_clk_ctl.cn31xx.p_xenbn = 1;
+		} else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
+			usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */
+		else
+			usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */
 
-        switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
-            case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
-                usbn_clk_ctl.s.p_c_sel = 0;
-                break;
-            case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:
-                usbn_clk_ctl.s.p_c_sel = 1;
-                break;
-            case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:
-                usbn_clk_ctl.s.p_c_sel = 2;
-                break;
-        }
-    }
-    else {
-        /* The USB port uses a 12MHz crystal as clock source
-            at USB_XO and USB_XI */
-        if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
-            usbn_clk_ctl.cn31xx.p_rclk  = 1; /* From CN31XX,CN30XX manual */
-            usbn_clk_ctl.cn31xx.p_xenbn = 1;
-        }
-        else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
-            usbn_clk_ctl.cn56xx.p_rtype = 0; /* From CN56XX,CN50XX manual */
-        else
-            usbn_clk_ctl.cn52xx.p_rtype = 0; /* From CN52XX manual */
+		usbn_clk_ctl.s.p_c_sel = 0;
+	}
+	/*
+	 * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
+	 *     setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down
+	 *     such that USB is as close as possible to 125Mhz
+	 */
+	{
+		int divisor = (octeon_get_clock_rate()+125000000-1)/125000000;
+		if (divisor < 4)  /* Lower than 4 doesn't seem to work properly */
+			divisor = 4;
+		usbn_clk_ctl.s.divide = divisor;
+		usbn_clk_ctl.s.divide2 = 0;
+	}
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	/* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
+	usbn_clk_ctl.s.hclk_rst = 1;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	/* 2e.  Wait 64 core-clock cycles for HCLK to stabilize */
+	cvmx_wait(64);
+	/*
+	 * 3. Program the power-on reset field in the USBN clock-control
+	 *    register:
+	 *    USBN_CLK_CTL[POR] = 0
+	 */
+	usbn_clk_ctl.s.por = 0;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	/* 4. Wait 1 ms for PHY clock to start */
+	mdelay(1);
+	/*
+	 * 5. Program the Reset input from automatic test equipment field in the
+	 *    USBP control and status register:
+	 *    USBN_USBP_CTL_STATUS[ATE_RESET] = 1
+	 */
+	usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index));
+	usbn_usbp_ctl_status.s.ate_reset = 1;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+			       usbn_usbp_ctl_status.u64);
+	/* 6. Wait 10 cycles */
+	cvmx_wait(10);
+	/*
+	 * 7. Clear ATE_RESET field in the USBN clock-control register:
+	 *    USBN_USBP_CTL_STATUS[ATE_RESET] = 0
+	 */
+	usbn_usbp_ctl_status.s.ate_reset = 0;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+			       usbn_usbp_ctl_status.u64);
+	/*
+	 * 8. Program the PHY reset field in the USBN clock-control register:
+	 *    USBN_CLK_CTL[PRST] = 1
+	 */
+	usbn_clk_ctl.s.prst = 1;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	/*
+	 * 9. Program the USBP control and status register to select host or
+	 *    device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
+	 *    device
+	 */
+	usbn_usbp_ctl_status.s.hst_mode = 0;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+			       usbn_usbp_ctl_status.u64);
+	/* 10. Wait 1 us */
+	udelay(1);
+	/*
+	 * 11. Program the hreset_n field in the USBN clock-control register:
+	 *     USBN_CLK_CTL[HRST] = 1
+	 */
+	usbn_clk_ctl.s.hrst = 1;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	/* 12. Proceed to USB core initialization */
+	usbn_clk_ctl.s.enable = 1;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	udelay(1);
 
-        usbn_clk_ctl.s.p_c_sel = 0;
-    }
-    /* 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
-        setting USBN0/1_CLK_CTL[ENABLE] = 1.  Divide the core clock down such
-        that USB is as close as possible to 125Mhz */
-    {
-        int divisor = (octeon_get_clock_rate()+125000000-1)/125000000;
-        if (divisor < 4)  /* Lower than 4 doesn't seem to work properly */
-            divisor = 4;
-        usbn_clk_ctl.s.divide = divisor;
-        usbn_clk_ctl.s.divide2 = 0;
-    }
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
-    usbn_clk_ctl.s.hclk_rst = 1;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    /* 2e.  Wait 64 core-clock cycles for HCLK to stabilize */
-    cvmx_wait(64);
-    /* 3. Program the power-on reset field in the USBN clock-control register:
-        USBN_CLK_CTL[POR] = 0 */
-    usbn_clk_ctl.s.por = 0;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    /* 4. Wait 1 ms for PHY clock to start */
-    cvmx_wait_usec(1000);
-    /* 5. Program the Reset input from automatic test equipment field in the
-        USBP control and status register: USBN_USBP_CTL_STATUS[ATE_RESET] = 1 */
-    usbn_usbp_ctl_status.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index));
-    usbn_usbp_ctl_status.s.ate_reset = 1;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
-                           usbn_usbp_ctl_status.u64);
-    /* 6. Wait 10 cycles */
-    cvmx_wait(10);
-    /* 7. Clear ATE_RESET field in the USBN clock-control register:
-        USBN_USBP_CTL_STATUS[ATE_RESET] = 0 */
-    usbn_usbp_ctl_status.s.ate_reset = 0;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
-                           usbn_usbp_ctl_status.u64);
-    /* 8. Program the PHY reset field in the USBN clock-control register:
-        USBN_CLK_CTL[PRST] = 1 */
-    usbn_clk_ctl.s.prst = 1;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    /* 9. Program the USBP control and status register to select host or
-        device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
-        device */
-    usbn_usbp_ctl_status.s.hst_mode = 0;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_USBP_CTL_STATUS(usb->index),
-                           usbn_usbp_ctl_status.u64);
-    /* 10. Wait 1 us */
-    cvmx_wait_usec(1);
-    /* 11. Program the hreset_n field in the USBN clock-control register:
-        USBN_CLK_CTL[HRST] = 1 */
-    usbn_clk_ctl.s.hrst = 1;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    /* 12. Proceed to USB core initialization */
-    usbn_clk_ctl.s.enable = 1;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    cvmx_wait_usec(1);
+	/*
+	 * USB Core Initialization
+	 *
+	 * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
+	 *    determine USB core configuration parameters.
+	 *
+	 *    Nothing needed
+	 *
+	 * 2. Program the following fields in the global AHB configuration
+	 *    register (USBC_GAHBCFG)
+	 *    DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
+	 *    Burst length, USBC_GAHBCFG[HBSTLEN] = 0
+	 *    Nonperiodic TxFIFO empty level (slave mode only),
+	 *    USBC_GAHBCFG[NPTXFEMPLVL]
+	 *    Periodic TxFIFO empty level (slave mode only),
+	 *    USBC_GAHBCFG[PTXFEMPLVL]
+	 *    Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1
+	 */
+	{
+		union cvmx_usbcx_gahbcfg usbcx_gahbcfg;
+		/* Due to an errata, CN31XX doesn't support DMA */
+		if (OCTEON_IS_MODEL(OCTEON_CN31XX))
+			usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
+		usbcx_gahbcfg.u32 = 0;
+		usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
+		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+			usb->idle_hardware_channels = 0x1;  /* Only use one channel with non DMA */
+		else if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
+			usb->idle_hardware_channels = 0xf7; /* CN5XXX have an errata with channel 3 */
+		else
+			usb->idle_hardware_channels = 0xff;
+		usbcx_gahbcfg.s.hbstlen = 0;
+		usbcx_gahbcfg.s.nptxfemplvl = 1;
+		usbcx_gahbcfg.s.ptxfemplvl = 1;
+		usbcx_gahbcfg.s.glblintrmsk = 1;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
+				       usbcx_gahbcfg.u32);
+	}
+	/*
+	 * 3. Program the following fields in USBC_GUSBCFG register.
+	 *    HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
+	 *    ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
+	 *    USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
+	 *    PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0
+	 */
+	{
+		union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
+		usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
+		usbcx_gusbcfg.s.toutcal = 0;
+		usbcx_gusbcfg.s.ddrsel = 0;
+		usbcx_gusbcfg.s.usbtrdtim = 0x5;
+		usbcx_gusbcfg.s.phylpwrclksel = 0;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
+				       usbcx_gusbcfg.u32);
+	}
+	/*
+	 * 4. The software must unmask the following bits in the USBC_GINTMSK
+	 *    register.
+	 *    OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
+	 *    Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1
+	 */
+	{
+		union cvmx_usbcx_gintmsk usbcx_gintmsk;
+		int channel;
 
-    /* USB Core Initialization */
+		usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
+		usbcx_gintmsk.s.otgintmsk = 1;
+		usbcx_gintmsk.s.modemismsk = 1;
+		usbcx_gintmsk.s.hchintmsk = 1;
+		usbcx_gintmsk.s.sofmsk = 0;
+		/* We need RX FIFO interrupts if we don't have DMA */
+		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+			usbcx_gintmsk.s.rxflvlmsk = 1;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
+				       usbcx_gintmsk.u32);
 
-    /* 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
-        determine USB core configuration parameters. */
-    /* Nothing needed */
-    /* 2. Program the following fields in the global AHB configuration
-        register (USBC_GAHBCFG)
-        DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
-        Burst length, USBC_GAHBCFG[HBSTLEN] = 0
-        Nonperiodic TxFIFO empty level (slave mode only),
-        USBC_GAHBCFG[NPTXFEMPLVL]
-        Periodic TxFIFO empty level (slave mode only),
-        USBC_GAHBCFG[PTXFEMPLVL]
-        Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1 */
-    {
-        cvmx_usbcx_gahbcfg_t usbcx_gahbcfg;
-        /* Due to an errata, CN31XX doesn't support DMA */
-        if (OCTEON_IS_MODEL(OCTEON_CN31XX))
-            usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
-        usbcx_gahbcfg.u32 = 0;
-        usbcx_gahbcfg.s.dmaen = !(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
-        if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
-            usb->idle_hardware_channels = 0x1;  /* Only use one channel with non DMA */
-        else if (OCTEON_IS_MODEL(OCTEON_CN5XXX))
-            usb->idle_hardware_channels = 0xf7; /* CN5XXX have an errata with channel 3 */
-        else
-            usb->idle_hardware_channels = 0xff;
-        usbcx_gahbcfg.s.hbstlen = 0;
-        usbcx_gahbcfg.s.nptxfemplvl = 1;
-        usbcx_gahbcfg.s.ptxfemplvl = 1;
-        usbcx_gahbcfg.s.glblintrmsk = 1;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
-                               usbcx_gahbcfg.u32);
-    }
-    /* 3. Program the following fields in USBC_GUSBCFG register.
-        HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
-        ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
-        USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
-        PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0 */
-    {
-        cvmx_usbcx_gusbcfg_t usbcx_gusbcfg;
-        usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index));
-        usbcx_gusbcfg.s.toutcal = 0;
-        usbcx_gusbcfg.s.ddrsel = 0;
-        usbcx_gusbcfg.s.usbtrdtim = 0x5;
-        usbcx_gusbcfg.s.phylpwrclksel = 0;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
-                               usbcx_gusbcfg.u32);
-    }
-    /* 4. The software must unmask the following bits in the USBC_GINTMSK
-        register.
-        OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
-        Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1 */
-    {
-        cvmx_usbcx_gintmsk_t usbcx_gintmsk;
-        int channel;
+		/* Disable all channel interrupts. We'll enable them per channel later */
+		for (channel = 0; channel < 8; channel++)
+			__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+	}
 
-        usbcx_gintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTMSK(usb->index));
-        usbcx_gintmsk.s.otgintmsk = 1;
-        usbcx_gintmsk.s.modemismsk = 1;
-        usbcx_gintmsk.s.hchintmsk = 1;
-        usbcx_gintmsk.s.sofmsk = 0;
-        /* We need RX FIFO interrupts if we don't have DMA */
-        if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
-            usbcx_gintmsk.s.rxflvlmsk = 1;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
-                               usbcx_gintmsk.u32);
+	{
+		/*
+		 * Host Port Initialization
+		 *
+		 * 1. Program the host-port interrupt-mask field to unmask,
+		 *    USBC_GINTMSK[PRTINT] = 1
+		 */
+		USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk,
+				prtintmsk, 1);
+		USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk,
+				disconnintmsk, 1);
+		/*
+		 * 2. Program the USBC_HCFG register to select full-speed host
+		 *    or high-speed host.
+		 */
+		{
+			union cvmx_usbcx_hcfg usbcx_hcfg;
+			usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
+			usbcx_hcfg.s.fslssupp = 0;
+			usbcx_hcfg.s.fslspclksel = 0;
+			__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
+		}
+		/*
+		 * 3. Program the port power bit to drive VBUS on the USB,
+		 *    USBC_HPRT[PRTPWR] = 1
+		 */
+		USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtpwr, 1);
 
-        /* Disable all channel interrupts. We'll enable them per channel later */
-        for (channel=0; channel<8; channel++)
-            __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
-    }
+		/*
+		 * Steps 4-15 from the manual are done later in the port enable
+		 */
+	}
 
-    {
-        /* Host Port Initialization */
-        if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
-            cvmx_dprintf("%s: USB%d is in host mode\n", __FUNCTION__, usb->index);
-
-        /* 1. Program the host-port interrupt-mask field to unmask,
-            USBC_GINTMSK[PRTINT] = 1 */
-        USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t,
-                        prtintmsk, 1);
-        USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t,
-                        disconnintmsk, 1);
-        /* 2. Program the USBC_HCFG register to select full-speed host or
-            high-speed host. */
-        {
-            cvmx_usbcx_hcfg_t usbcx_hcfg;
-            usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
-            usbcx_hcfg.s.fslssupp = 0;
-            usbcx_hcfg.s.fslspclksel = 0;
-            __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
-        }
-        /* 3. Program the port power bit to drive VBUS on the USB,
-            USBC_HPRT[PRTPWR] = 1 */
-        USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtpwr, 1);
-
-        /* Steps 4-15 from the manual are done later in the port enable */
-    }
-
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	return 0;
 }
 
 
@@ -861,38 +880,34 @@
  * The port should be disabled with all pipes closed when this
  * function is called.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
+ * @state: USB device state populated by
+ *	   cvmx_usb_initialize().
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_shutdown(cvmx_usb_state_t *state)
+int cvmx_usb_shutdown(struct cvmx_usb_state *state)
 {
-    cvmx_usbnx_clk_ctl_t usbn_clk_ctl;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
+	/* Make sure all pipes are closed */
+	if (usb->idle_pipes.head ||
+		usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS].head ||
+		usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT].head ||
+		usb->active_pipes[CVMX_USB_TRANSFER_CONTROL].head ||
+		usb->active_pipes[CVMX_USB_TRANSFER_BULK].head)
+		return -EBUSY;
 
-    /* Make sure all pipes are closed */
-    if (usb->idle_pipes.head ||
-        usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS].head ||
-        usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT].head ||
-        usb->active_pipes[CVMX_USB_TRANSFER_CONTROL].head ||
-        usb->active_pipes[CVMX_USB_TRANSFER_BULK].head)
-        CVMX_USB_RETURN(CVMX_USB_BUSY);
-
-    /* Disable the clocks and put them in power on reset */
-    usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
-    usbn_clk_ctl.s.enable = 1;
-    usbn_clk_ctl.s.por = 1;
-    usbn_clk_ctl.s.hclk_rst = 1;
-    usbn_clk_ctl.s.prst = 0;
-    usbn_clk_ctl.s.hrst = 0;
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
-                           usbn_clk_ctl.u64);
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	/* Disable the clocks and put them in power on reset */
+	usbn_clk_ctl.u64 = __cvmx_usb_read_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index));
+	usbn_clk_ctl.s.enable = 1;
+	usbn_clk_ctl.s.por = 1;
+	usbn_clk_ctl.s.hclk_rst = 1;
+	usbn_clk_ctl.s.prst = 0;
+	usbn_clk_ctl.s.hrst = 0;
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_CLK_CTL(usb->index),
+			       usbn_clk_ctl.u64);
+	return 0;
 }
 
 
@@ -900,96 +915,91 @@
  * Enable a USB port. After this call succeeds, the USB port is
  * online and servicing requests.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
+ * @state: USB device state populated by
+ *	   cvmx_usb_initialize().
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_enable(cvmx_usb_state_t *state)
+int cvmx_usb_enable(struct cvmx_usb_state *state)
 {
-    cvmx_usbcx_ghwcfg3_t usbcx_ghwcfg3;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
+	usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
 
-    usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+	/*
+	 * If the port is already enabled the just return. We don't need to do
+	 * anything
+	 */
+	if (usb->usbcx_hprt.s.prtena)
+		return 0;
 
-    /* If the port is already enabled the just return. We don't need to do
-        anything */
-    if (usb->usbcx_hprt.s.prtena)
-        CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	/* If there is nothing plugged into the port then fail immediately */
+	if (!usb->usbcx_hprt.s.prtconnsts) {
+		return -ETIMEDOUT;
+	}
 
-    /* If there is nothing plugged into the port then fail immediately */
-    if (!usb->usbcx_hprt.s.prtconnsts) {
-        if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
-            cvmx_dprintf("%s: USB%d Nothing plugged into the port\n", __FUNCTION__, usb->index);
-        CVMX_USB_RETURN(CVMX_USB_TIMEOUT);
-    }
+	/* Program the port reset bit to start the reset process */
+	USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 1);
 
-    /* Program the port reset bit to start the reset process */
-    USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtrst, 1);
+	/*
+	 * Wait at least 50ms (high speed), or 10ms (full speed) for the reset
+	 * process to complete.
+	 */
+	mdelay(50);
 
-    /* Wait at least 50ms (high speed), or 10ms (full speed) for the reset
-        process to complete. */
-    cvmx_wait_usec(50000);
+	/* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
+	USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtrst, 0);
 
-    /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
-    USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtrst, 0);
+	/* Wait for the USBC_HPRT[PRTENA]. */
+	if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt,
+				  prtena, ==, 1, 100000))
+		return -ETIMEDOUT;
 
-    /* Wait for the USBC_HPRT[PRTENA]. */
-    if (CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t,
-                              prtena, ==, 1, 100000)) {
-        if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
-            cvmx_dprintf("%s: Timeout waiting for the port to finish reset\n",
-                         __FUNCTION__);
-        CVMX_USB_RETURN(CVMX_USB_TIMEOUT);
-    }
+	/* Read the port speed field to get the enumerated speed, USBC_HPRT[PRTSPD]. */
+	usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+	usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
 
-    /* Read the port speed field to get the enumerated speed, USBC_HPRT[PRTSPD]. */
-    usb->usbcx_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
-    if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
-        cvmx_dprintf("%s: USB%d is in %s speed mode\n", __FUNCTION__, usb->index,
-                     (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH) ? "high" :
-                     (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_FULL) ? "full" :
-                     "low");
+	/*
+	 * 13. Program the USBC_GRXFSIZ register to select the size of the
+	 *     receive FIFO (25%).
+	 */
+	USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), union cvmx_usbcx_grxfsiz,
+			rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
+	/*
+	 * 14. Program the USBC_GNPTXFSIZ register to select the size and the
+	 *     start address of the non- periodic transmit FIFO for nonperiodic
+	 *     transactions (50%).
+	 */
+	{
+		union cvmx_usbcx_gnptxfsiz siz;
+		siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
+		siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
+		siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32);
+	}
+	/*
+	 * 15. Program the USBC_HPTXFSIZ register to select the size and start
+	 *     address of the periodic transmit FIFO for periodic transactions
+	 *     (25%).
+	 */
+	{
+		union cvmx_usbcx_hptxfsiz siz;
+		siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
+		siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
+		siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32);
+	}
+	/* Flush all FIFOs */
+	USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfnum, 0x10);
+	USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, txfflsh, 1);
+	CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl,
+			      txfflsh, ==, 0, 100);
+	USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl, rxfflsh, 1);
+	CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), union cvmx_usbcx_grstctl,
+			      rxfflsh, ==, 0, 100);
 
-    usbcx_ghwcfg3.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GHWCFG3(usb->index));
-
-    /* 13. Program the USBC_GRXFSIZ register to select the size of the receive
-        FIFO (25%). */
-    USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz_t,
-                    rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
-    /* 14. Program the USBC_GNPTXFSIZ register to select the size and the
-        start address of the non- periodic transmit FIFO for nonperiodic
-        transactions (50%). */
-    {
-        cvmx_usbcx_gnptxfsiz_t siz;
-        siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
-        siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
-        siz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), siz.u32);
-    }
-    /* 15. Program the USBC_HPTXFSIZ register to select the size and start
-        address of the periodic transmit FIFO for periodic transactions (25%). */
-    {
-        cvmx_usbcx_hptxfsiz_t siz;
-        siz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
-        siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
-        siz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), siz.u32);
-    }
-    /* Flush all FIFOs */
-    USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t, txfnum, 0x10);
-    USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t, txfflsh, 1);
-    CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t,
-                          txfflsh, ==, 0, 100);
-    USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t, rxfflsh, 1);
-    CVMX_WAIT_FOR_FIELD32(CVMX_USBCX_GRSTCTL(usb->index), cvmx_usbcx_grstctl_t,
-                          rxfflsh, ==, 0, 100);
-
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	return 0;
 }
 
 
@@ -999,22 +1009,18 @@
  * Transactions in process will fail and call their
  * associated callbacks.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
+ * @state: USB device state populated by
+ *	   cvmx_usb_initialize().
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_disable(cvmx_usb_state_t *state)
+int cvmx_usb_disable(struct cvmx_usb_state *state)
 {
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-
-    /* Disable the port */
-    USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt_t, prtena, 1);
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	/* Disable the port */
+	USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), union cvmx_usbcx_hprt, prtena, 1);
+	return 0;
 }
 
 
@@ -1027,40 +1033,28 @@
  * on the last call to cvmx_usb_set_status(). In order to clear
  * them, you must update the status through cvmx_usb_set_status().
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
+ * @state: USB device state populated by
+ *	   cvmx_usb_initialize().
  *
- * @return Port status information
+ * Returns: Port status information
  */
-cvmx_usb_port_status_t cvmx_usb_get_status(cvmx_usb_state_t *state)
+struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *state)
 {
-    cvmx_usbcx_hprt_t usbc_hprt;
-    cvmx_usb_port_status_t result;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	union cvmx_usbcx_hprt usbc_hprt;
+	struct cvmx_usb_port_status result;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    memset(&result, 0, sizeof(result));
+	memset(&result, 0, sizeof(result));
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
+	usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+	result.port_enabled = usbc_hprt.s.prtena;
+	result.port_over_current = usbc_hprt.s.prtovrcurract;
+	result.port_powered = usbc_hprt.s.prtpwr;
+	result.port_speed = usbc_hprt.s.prtspd;
+	result.connected = usbc_hprt.s.prtconnsts;
+	result.connect_change = (result.connected != usb->port_status.connected);
 
-    usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
-    result.port_enabled = usbc_hprt.s.prtena;
-    result.port_over_current = usbc_hprt.s.prtovrcurract;
-    result.port_powered = usbc_hprt.s.prtpwr;
-    result.port_speed = usbc_hprt.s.prtspd;
-    result.connected = usbc_hprt.s.prtconnsts;
-    result.connect_change = (result.connected != usb->port_status.connected);
-
-    if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS))
-        cvmx_dprintf("%*s%s: returned port enabled=%d, over_current=%d, powered=%d, speed=%d, connected=%d, connect_change=%d\n",
-                     2*(--usb->indent), "", __FUNCTION__,
-                     result.port_enabled,
-                     result.port_over_current,
-                     result.port_powered,
-                     result.port_speed,
-                     result.connected,
-                     result.connect_change);
-    return result;
+	return result;
 }
 
 
@@ -1071,54 +1065,50 @@
  * status passed to this function is not used. No fields can be
  * changed through this call.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param port_status
- *               Port status to set, most like returned by cvmx_usb_get_status()
+ * @state:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @port_status:
+ *		 Port status to set, most like returned by cvmx_usb_get_status()
  */
-void cvmx_usb_set_status(cvmx_usb_state_t *state, cvmx_usb_port_status_t port_status)
+void cvmx_usb_set_status(struct cvmx_usb_state *state, struct cvmx_usb_port_status port_status)
 {
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    usb->port_status = port_status;
-    CVMX_USB_RETURN_NOTHING();
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+	usb->port_status = port_status;
+	return;
 }
 
 
 /**
- * @INTERNAL
  * Convert a USB transaction into a handle
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param transaction
- *               Transaction to get handle for
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @transaction:
+ *		 Transaction to get handle for
  *
- * @return Handle
+ * Returns: Handle
  */
-static inline int __cvmx_usb_get_submit_handle(cvmx_usb_internal_state_t *usb,
-                                        cvmx_usb_transaction_t *transaction)
+static inline int __cvmx_usb_get_submit_handle(struct cvmx_usb_internal_state *usb,
+					       struct cvmx_usb_transaction *transaction)
 {
-    return ((unsigned long)transaction - (unsigned long)usb->transaction) /
-            sizeof(*transaction);
+	return ((unsigned long)transaction - (unsigned long)usb->transaction) /
+			sizeof(*transaction);
 }
 
 
 /**
- * @INTERNAL
  * Convert a USB pipe into a handle
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe   Pipe to get handle for
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @pipe:	 Pipe to get handle for
  *
- * @return Handle
+ * Returns: Handle
  */
-static inline int __cvmx_usb_get_pipe_handle(cvmx_usb_internal_state_t *usb,
-                                        cvmx_usb_pipe_t *pipe)
+static inline int __cvmx_usb_get_pipe_handle(struct cvmx_usb_internal_state *usb,
+					     struct cvmx_usb_pipe *pipe)
 {
-    return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe);
+	return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe);
 }
 
 
@@ -1127,197 +1117,182 @@
  * must be opened before data can be transferred between a device
  * and Octeon.
  *
- * @param state      USB device state populated by
- *                   cvmx_usb_initialize().
- * @param flags      Optional pipe flags defined in
- *                   cvmx_usb_pipe_flags_t.
- * @param device_addr
- *                   USB device address to open the pipe to
- *                   (0-127).
- * @param endpoint_num
- *                   USB endpoint number to open the pipe to
- *                   (0-15).
- * @param device_speed
- *                   The speed of the device the pipe is going
- *                   to. This must match the device's speed,
- *                   which may be different than the port speed.
- * @param max_packet The maximum packet length the device can
- *                   transmit/receive (low speed=0-8, full
- *                   speed=0-1023, high speed=0-1024). This value
- *                   comes from the standard endpoint descriptor
- *                   field wMaxPacketSize bits <10:0>.
- * @param transfer_type
- *                   The type of transfer this pipe is for.
- * @param transfer_dir
- *                   The direction the pipe is in. This is not
- *                   used for control pipes.
- * @param interval   For ISOCHRONOUS and INTERRUPT transfers,
- *                   this is how often the transfer is scheduled
- *                   for. All other transfers should specify
- *                   zero. The units are in frames (8000/sec at
- *                   high speed, 1000/sec for full speed).
- * @param multi_count
- *                   For high speed devices, this is the maximum
- *                   allowed number of packet per microframe.
- *                   Specify zero for non high speed devices. This
- *                   value comes from the standard endpoint descriptor
- *                   field wMaxPacketSize bits <12:11>.
- * @param hub_device_addr
- *                   Hub device address this device is connected
- *                   to. Devices connected directly to Octeon
- *                   use zero. This is only used when the device
- *                   is full/low speed behind a high speed hub.
- *                   The address will be of the high speed hub,
- *                   not and full speed hubs after it.
- * @param hub_port   Which port on the hub the device is
- *                   connected. Use zero for devices connected
- *                   directly to Octeon. Like hub_device_addr,
- *                   this is only used for full/low speed
- *                   devices behind a high speed hub.
+ * @state:	     USB device state populated by
+ *		     cvmx_usb_initialize().
+ * @flags:	     Optional pipe flags defined in
+ *		     enum cvmx_usb_pipe_flags.
+ * @device_addr:
+ *		     USB device address to open the pipe to
+ *		     (0-127).
+ * @endpoint_num:
+ *		     USB endpoint number to open the pipe to
+ *		     (0-15).
+ * @device_speed:
+ *		     The speed of the device the pipe is going
+ *		     to. This must match the device's speed,
+ *		     which may be different than the port speed.
+ * @max_packet:	     The maximum packet length the device can
+ *		     transmit/receive (low speed=0-8, full
+ *		     speed=0-1023, high speed=0-1024). This value
+ *		     comes from the standard endpoint descriptor
+ *		     field wMaxPacketSize bits <10:0>.
+ * @transfer_type:
+ *		     The type of transfer this pipe is for.
+ * @transfer_dir:
+ *		     The direction the pipe is in. This is not
+ *		     used for control pipes.
+ * @interval:	     For ISOCHRONOUS and INTERRUPT transfers,
+ *		     this is how often the transfer is scheduled
+ *		     for. All other transfers should specify
+ *		     zero. The units are in frames (8000/sec at
+ *		     high speed, 1000/sec for full speed).
+ * @multi_count:
+ *		     For high speed devices, this is the maximum
+ *		     allowed number of packet per microframe.
+ *		     Specify zero for non high speed devices. This
+ *		     value comes from the standard endpoint descriptor
+ *		     field wMaxPacketSize bits <12:11>.
+ * @hub_device_addr:
+ *		     Hub device address this device is connected
+ *		     to. Devices connected directly to Octeon
+ *		     use zero. This is only used when the device
+ *		     is full/low speed behind a high speed hub.
+ *		     The address will be of the high speed hub,
+ *		     not and full speed hubs after it.
+ * @hub_port:	     Which port on the hub the device is
+ *		     connected. Use zero for devices connected
+ *		     directly to Octeon. Like hub_device_addr,
+ *		     this is only used for full/low speed
+ *		     devices behind a high speed hub.
  *
- * @return A non negative value is a pipe handle. Negative
- *         values are failure codes from cvmx_usb_status_t.
+ * Returns: A non negative value is a pipe handle. Negative
+ *	    values are error codes.
  */
-int cvmx_usb_open_pipe(cvmx_usb_state_t *state, cvmx_usb_pipe_flags_t flags,
-                       int device_addr, int endpoint_num,
-                       cvmx_usb_speed_t device_speed, int max_packet,
-                       cvmx_usb_transfer_t transfer_type,
-                       cvmx_usb_direction_t transfer_dir, int interval,
-                       int multi_count, int hub_device_addr, int hub_port)
+int cvmx_usb_open_pipe(struct cvmx_usb_state *state, enum cvmx_usb_pipe_flags flags,
+		       int device_addr, int endpoint_num,
+		       enum cvmx_usb_speed device_speed, int max_packet,
+		       enum cvmx_usb_transfer transfer_type,
+		       enum cvmx_usb_direction transfer_dir, int interval,
+		       int multi_count, int hub_device_addr, int hub_port)
 {
-    cvmx_usb_pipe_t *pipe;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	struct cvmx_usb_pipe *pipe;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("0x%x", flags);
-    CVMX_USB_LOG_PARAM("%d", device_addr);
-    CVMX_USB_LOG_PARAM("%d", endpoint_num);
-    CVMX_USB_LOG_PARAM("%d", device_speed);
-    CVMX_USB_LOG_PARAM("%d", max_packet);
-    CVMX_USB_LOG_PARAM("%d", transfer_type);
-    CVMX_USB_LOG_PARAM("%d", transfer_dir);
-    CVMX_USB_LOG_PARAM("%d", interval);
-    CVMX_USB_LOG_PARAM("%d", multi_count);
-    CVMX_USB_LOG_PARAM("%d", hub_device_addr);
-    CVMX_USB_LOG_PARAM("%d", hub_port);
+	if (unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS)))
+		return -EINVAL;
+	if (unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT)))
+		return -EINVAL;
+	if (unlikely(device_speed > CVMX_USB_SPEED_LOW))
+		return -EINVAL;
+	if (unlikely((max_packet <= 0) || (max_packet > 1024)))
+		return -EINVAL;
+	if (unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT))
+		return -EINVAL;
+	if (unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) &&
+		(transfer_dir != CVMX_USB_DIRECTION_IN)))
+		return -EINVAL;
+	if (unlikely(interval < 0))
+		return -EINVAL;
+	if (unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval))
+		return -EINVAL;
+	if (unlikely(multi_count < 0))
+		return -EINVAL;
+	if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
+		(multi_count != 0)))
+		return -EINVAL;
+	if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
+		return -EINVAL;
+	if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
+		return -EINVAL;
 
-    if (cvmx_unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(device_speed > CVMX_USB_SPEED_LOW))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((max_packet <= 0) || (max_packet > 1024)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) &&
-        (transfer_dir != CVMX_USB_DIRECTION_IN)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(interval < 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(multi_count < 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
-        (multi_count != 0)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	/* Find a free pipe */
+	pipe = usb->free_pipes.head;
+	if (!pipe)
+		return -ENOMEM;
+	__cvmx_usb_remove_pipe(&usb->free_pipes, pipe);
+	pipe->flags = flags | __CVMX_USB_PIPE_FLAGS_OPEN;
+	if ((device_speed == CVMX_USB_SPEED_HIGH) &&
+		(transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+		(transfer_type == CVMX_USB_TRANSFER_BULK))
+		pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
+	pipe->device_addr = device_addr;
+	pipe->endpoint_num = endpoint_num;
+	pipe->device_speed = device_speed;
+	pipe->max_packet = max_packet;
+	pipe->transfer_type = transfer_type;
+	pipe->transfer_dir = transfer_dir;
+	/*
+	 * All pipes use interval to rate limit NAK processing. Force an
+	 * interval if one wasn't supplied
+	 */
+	if (!interval)
+		interval = 1;
+	if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+		pipe->interval = interval*8;
+		/* Force start splits to be schedule on uFrame 0 */
+		pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval;
+	} else {
+		pipe->interval = interval;
+		pipe->next_tx_frame = usb->frame_number + pipe->interval;
+	}
+	pipe->multi_count = multi_count;
+	pipe->hub_device_addr = hub_device_addr;
+	pipe->hub_port = hub_port;
+	pipe->pid_toggle = 0;
+	pipe->split_sc_frame = -1;
+	__cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
 
-    /* Find a free pipe */
-    pipe = usb->free_pipes.head;
-    if (!pipe)
-        CVMX_USB_RETURN(CVMX_USB_NO_MEMORY);
-    __cvmx_usb_remove_pipe(&usb->free_pipes, pipe);
-    pipe->flags = flags | __CVMX_USB_PIPE_FLAGS_OPEN;
-    if ((device_speed == CVMX_USB_SPEED_HIGH) &&
-        (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
-        (transfer_type == CVMX_USB_TRANSFER_BULK))
-        pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
-    pipe->device_addr = device_addr;
-    pipe->endpoint_num = endpoint_num;
-    pipe->device_speed = device_speed;
-    pipe->max_packet = max_packet;
-    pipe->transfer_type = transfer_type;
-    pipe->transfer_dir = transfer_dir;
-    /* All pipes use interval to rate limit NAK processing. Force an interval
-        if one wasn't supplied */
-    if (!interval)
-        interval = 1;
-    if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-        pipe->interval = interval*8;
-        /* Force start splits to be schedule on uFrame 0 */
-        pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval;
-    }
-    else {
-        pipe->interval = interval;
-        pipe->next_tx_frame = usb->frame_number + pipe->interval;
-    }
-    pipe->multi_count = multi_count;
-    pipe->hub_device_addr = hub_device_addr;
-    pipe->hub_port = hub_port;
-    pipe->pid_toggle = 0;
-    pipe->split_sc_frame = -1;
-    __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
+	/*
+	 * We don't need to tell the hardware about this pipe yet since
+	 * it doesn't have any submitted requests
+	 */
 
-    /* We don't need to tell the hardware about this pipe yet since
-        it doesn't have any submitted requests */
-
-    CVMX_USB_RETURN(__cvmx_usb_get_pipe_handle(usb, pipe));
+	return __cvmx_usb_get_pipe_handle(usb, pipe);
 }
 
 
 /**
- * @INTERNAL
  * Poll the RX FIFOs and remove data as needed. This function is only used
  * in non DMA mode. It is very important that this function be called quickly
  * enough to prevent FIFO overflow.
  *
- * @param usb     USB device state populated by
- *                cvmx_usb_initialize().
+ * @usb:	USB device state populated by
+ *		cvmx_usb_initialize().
  */
-static void __cvmx_usb_poll_rx_fifo(cvmx_usb_internal_state_t *usb)
+static void __cvmx_usb_poll_rx_fifo(struct cvmx_usb_internal_state *usb)
 {
-    cvmx_usbcx_grxstsph_t rx_status;
-    int channel;
-    int bytes;
-    uint64_t address;
-    uint32_t *ptr;
+	union cvmx_usbcx_grxstsph rx_status;
+	int channel;
+	int bytes;
+	uint64_t address;
+	uint32_t *ptr;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
+	rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index));
+	/* Only read data if IN data is there */
+	if (rx_status.s.pktsts != 2)
+		return;
+	/* Check if no data is available */
+	if (!rx_status.s.bcnt)
+		return;
 
-    rx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GRXSTSPH(usb->index));
-    /* Only read data if IN data is there */
-    if (rx_status.s.pktsts != 2)
-        CVMX_USB_RETURN_NOTHING();
-    /* Check if no data is available */
-    if (!rx_status.s.bcnt)
-        CVMX_USB_RETURN_NOTHING();
+	channel = rx_status.s.chnum;
+	bytes = rx_status.s.bcnt;
+	if (!bytes)
+		return;
 
-    channel = rx_status.s.chnum;
-    bytes = rx_status.s.bcnt;
-    if (!bytes)
-        CVMX_USB_RETURN_NOTHING();
+	/* Get where the DMA engine would have written this data */
+	address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8);
+	ptr = cvmx_phys_to_ptr(address);
+	__cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes);
 
-    /* Get where the DMA engine would have written this data */
-    address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8);
-    ptr = cvmx_phys_to_ptr(address);
-    __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes);
+	/* Loop writing the FIFO data for this packet into memory */
+	while (bytes > 0) {
+		*ptr++ = __cvmx_usb_read_csr32(usb, USB_FIFO_ADDRESS(channel, usb->index));
+		bytes -= 4;
+	}
+	CVMX_SYNCW;
 
-    /* Loop writing the FIFO data for this packet into memory */
-    while (bytes > 0) {
-        *ptr++ = __cvmx_usb_read_csr32(usb, USB_FIFO_ADDRESS(channel, usb->index));
-        bytes -= 4;
-    }
-    CVMX_SYNCW;
-
-    CVMX_USB_RETURN_NOTHING();
+	return;
 }
 
 
@@ -1325,1196 +1300,1136 @@
  * Fill the TX hardware fifo with data out of the software
  * fifos
  *
- * @param usb       USB device state populated by
- *                  cvmx_usb_initialize().
- * @param fifo      Software fifo to use
- * @param available Amount of space in the hardware fifo
+ * @usb:	    USB device state populated by
+ *		    cvmx_usb_initialize().
+ * @fifo:	    Software fifo to use
+ * @available:	    Amount of space in the hardware fifo
  *
- * @return Non zero if the hardware fifo was too small and needs
- *         to be serviced again.
+ * Returns: Non zero if the hardware fifo was too small and needs
+ *	    to be serviced again.
  */
-static int __cvmx_usb_fill_tx_hw(cvmx_usb_internal_state_t *usb, cvmx_usb_tx_fifo_t *fifo, int available)
+static int __cvmx_usb_fill_tx_hw(struct cvmx_usb_internal_state *usb, struct cvmx_usb_tx_fifo *fifo, int available)
 {
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
-    CVMX_USB_LOG_PARAM("%p", fifo);
-    CVMX_USB_LOG_PARAM("%d", available);
+	/*
+	 * We're done either when there isn't anymore space or the software FIFO
+	 * is empty
+	 */
+	while (available && (fifo->head != fifo->tail)) {
+		int i = fifo->tail;
+		const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
+		uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4;
+		int words = available;
 
-    /* We're done either when there isn't anymore space or the software FIFO
-        is empty */
-    while (available && (fifo->head != fifo->tail)) {
-        int i = fifo->tail;
-        const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
-        uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel, usb->index) ^ 4;
-        int words = available;
+		/* Limit the amount of data to waht the SW fifo has */
+		if (fifo->entry[i].size <= available) {
+			words = fifo->entry[i].size;
+			fifo->tail++;
+			if (fifo->tail > MAX_CHANNELS)
+				fifo->tail = 0;
+		}
 
-        /* Limit the amount of data to waht the SW fifo has */
-        if (fifo->entry[i].size <= available) {
-            words = fifo->entry[i].size;
-            fifo->tail++;
-            if (fifo->tail > MAX_CHANNELS)
-                fifo->tail = 0;
-        }
+		/* Update the next locations and counts */
+		available -= words;
+		fifo->entry[i].address += words * 4;
+		fifo->entry[i].size -= words;
 
-        /* Update the next locations and counts */
-        available -= words;
-        fifo->entry[i].address += words * 4;
-        fifo->entry[i].size -= words;
-
-        /* Write the HW fifo data. The read every three writes is due
-            to an errata on CN3XXX chips */
-        while (words > 3) {
-            cvmx_write64_uint32(csr_address, *ptr++);
-            cvmx_write64_uint32(csr_address, *ptr++);
-            cvmx_write64_uint32(csr_address, *ptr++);
-            cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
-            words -= 3;
-        }
-        cvmx_write64_uint32(csr_address, *ptr++);
-        if (--words) {
-            cvmx_write64_uint32(csr_address, *ptr++);
-            if (--words)
-                cvmx_write64_uint32(csr_address, *ptr++);
-        }
-        cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
-    }
-    CVMX_USB_RETURN(fifo->head != fifo->tail);
+		/*
+		 * Write the HW fifo data. The read every three writes is due
+		 * to an errata on CN3XXX chips
+		 */
+		while (words > 3) {
+			cvmx_write64_uint32(csr_address, *ptr++);
+			cvmx_write64_uint32(csr_address, *ptr++);
+			cvmx_write64_uint32(csr_address, *ptr++);
+			cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+			words -= 3;
+		}
+		cvmx_write64_uint32(csr_address, *ptr++);
+		if (--words) {
+			cvmx_write64_uint32(csr_address, *ptr++);
+			if (--words)
+				cvmx_write64_uint32(csr_address, *ptr++);
+		}
+		cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+	}
+	return fifo->head != fifo->tail;
 }
 
 
 /**
  * Check the hardware FIFOs and fill them as needed
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
+ * @usb:	USB device state populated by
+ *		cvmx_usb_initialize().
  */
-static void __cvmx_usb_poll_tx_fifo(cvmx_usb_internal_state_t *usb)
+static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_internal_state *usb)
 {
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
+	if (usb->periodic.head != usb->periodic.tail) {
+		union cvmx_usbcx_hptxsts tx_status;
+		tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index));
+		if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail))
+			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 1);
+		else
+			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, ptxfempmsk, 0);
+	}
 
-    if (usb->periodic.head != usb->periodic.tail) {
-        cvmx_usbcx_hptxsts_t tx_status;
-        tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXSTS(usb->index));
-        if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic, tx_status.s.ptxfspcavail))
-            USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, ptxfempmsk, 1);
-        else
-            USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, ptxfempmsk, 0);
-    }
+	if (usb->nonperiodic.head != usb->nonperiodic.tail) {
+		union cvmx_usbcx_gnptxsts tx_status;
+		tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index));
+		if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail))
+			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 1);
+		else
+			USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, nptxfempmsk, 0);
+	}
 
-    if (usb->nonperiodic.head != usb->nonperiodic.tail) {
-        cvmx_usbcx_gnptxsts_t tx_status;
-        tx_status.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXSTS(usb->index));
-        if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic, tx_status.s.nptxfspcavail))
-            USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, nptxfempmsk, 1);
-        else
-            USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, nptxfempmsk, 0);
-    }
-
-    CVMX_USB_RETURN_NOTHING();
+	return;
 }
 
 
 /**
- * @INTERNAL
  * Fill the TX FIFO with an outgoing packet
  *
- * @param usb     USB device state populated by
- *                cvmx_usb_initialize().
- * @param channel Channel number to get packet from
+ * @usb:	  USB device state populated by
+ *		  cvmx_usb_initialize().
+ * @channel:	  Channel number to get packet from
  */
-static void __cvmx_usb_fill_tx_fifo(cvmx_usb_internal_state_t *usb, int channel)
+static void __cvmx_usb_fill_tx_fifo(struct cvmx_usb_internal_state *usb, int channel)
 {
-    cvmx_usbcx_hccharx_t hcchar;
-    cvmx_usbcx_hcspltx_t usbc_hcsplt;
-    cvmx_usbcx_hctsizx_t usbc_hctsiz;
-    cvmx_usb_tx_fifo_t *fifo;
+	union cvmx_usbcx_hccharx hcchar;
+	union cvmx_usbcx_hcspltx usbc_hcsplt;
+	union cvmx_usbcx_hctsizx usbc_hctsiz;
+	struct cvmx_usb_tx_fifo *fifo;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
-    CVMX_USB_LOG_PARAM("%d", channel);
+	/* We only need to fill data on outbound channels */
+	hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+	if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
+		return;
 
-    /* We only need to fill data on outbound channels */
-    hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
-    if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
-        CVMX_USB_RETURN_NOTHING();
+	/* OUT Splits only have data on the start and not the complete */
+	usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index));
+	if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
+		return;
 
-    /* OUT Splits only have data on the start and not the complete */
-    usbc_hcsplt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index));
-    if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
-        CVMX_USB_RETURN_NOTHING();
+	/* Find out how many bytes we need to fill and convert it into 32bit words */
+	usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+	if (!usbc_hctsiz.s.xfersize)
+		return;
 
-    /* Find out how many bytes we need to fill and convert it into 32bit words */
-    usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
-    if (!usbc_hctsiz.s.xfersize)
-        CVMX_USB_RETURN_NOTHING();
+	if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
+		(hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
+		fifo = &usb->periodic;
+	else
+		fifo = &usb->nonperiodic;
 
-    if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
-        (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
-        fifo = &usb->periodic;
-    else
-        fifo = &usb->nonperiodic;
+	fifo->entry[fifo->head].channel = channel;
+	fifo->entry[fifo->head].address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8);
+	fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2;
+	fifo->head++;
+	if (fifo->head > MAX_CHANNELS)
+		fifo->head = 0;
 
-    fifo->entry[fifo->head].channel = channel;
-    fifo->entry[fifo->head].address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8);
-    fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2;
-    fifo->head++;
-    if (fifo->head > MAX_CHANNELS)
-        fifo->head = 0;
+	__cvmx_usb_poll_tx_fifo(usb);
 
-    __cvmx_usb_poll_tx_fifo(usb);
-
-    CVMX_USB_RETURN_NOTHING();
+	return;
 }
 
 /**
- * @INTERNAL
  * Perform channel specific setup for Control transactions. All
  * the generic stuff will already have been done in
  * __cvmx_usb_start_channel()
  *
- * @param usb     USB device state populated by
- *                cvmx_usb_initialize().
- * @param channel Channel to setup
- * @param pipe    Pipe for control transaction
+ * @usb:	  USB device state populated by
+ *		  cvmx_usb_initialize().
+ * @channel:	  Channel to setup
+ * @pipe:	  Pipe for control transaction
  */
-static void __cvmx_usb_start_channel_control(cvmx_usb_internal_state_t *usb,
-                                             int channel,
-                                             cvmx_usb_pipe_t *pipe)
+static void __cvmx_usb_start_channel_control(struct cvmx_usb_internal_state *usb,
+					     int channel,
+					     struct cvmx_usb_pipe *pipe)
 {
-    cvmx_usb_transaction_t *transaction = pipe->head;
-    cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(transaction->control_header);
-    int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
-    int packets_to_transfer;
-    cvmx_usbcx_hctsizx_t usbc_hctsiz;
+	struct cvmx_usb_transaction *transaction = pipe->head;
+	union cvmx_usb_control_header *header =
+		cvmx_phys_to_ptr(transaction->control_header);
+	int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
+	int packets_to_transfer;
+	union cvmx_usbcx_hctsizx usbc_hctsiz;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
-    CVMX_USB_LOG_PARAM("%d", channel);
-    CVMX_USB_LOG_PARAM("%p", pipe);
+	usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
 
-    usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+	switch (transaction->stage) {
+	case CVMX_USB_STAGE_NON_CONTROL:
+	case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+		cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__);
+		break;
+	case CVMX_USB_STAGE_SETUP:
+		usbc_hctsiz.s.pid = 3; /* Setup */
+		bytes_to_transfer = sizeof(*header);
+		/* All Control operations start with a setup going OUT */
+		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT);
+		/*
+		 * Setup send the control header instead of the buffer data. The
+		 * buffer data will be used in the next stage
+		 */
+		__cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header);
+		break;
+	case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+		usbc_hctsiz.s.pid = 3; /* Setup */
+		bytes_to_transfer = 0;
+		/* All Control operations start with a setup going OUT */
+		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT);
+		USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+		break;
+	case CVMX_USB_STAGE_DATA:
+		usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+		if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+			if (header->s.request_type & 0x80)
+				bytes_to_transfer = 0;
+			else if (bytes_to_transfer > pipe->max_packet)
+				bytes_to_transfer = pipe->max_packet;
+		}
+		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+				union cvmx_usbcx_hccharx, epdir,
+				((header->s.request_type & 0x80) ?
+					CVMX_USB_DIRECTION_IN :
+					CVMX_USB_DIRECTION_OUT));
+		break;
+	case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+		usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+		if (!(header->s.request_type & 0x80))
+			bytes_to_transfer = 0;
+		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+				union cvmx_usbcx_hccharx, epdir,
+				((header->s.request_type & 0x80) ?
+					CVMX_USB_DIRECTION_IN :
+					CVMX_USB_DIRECTION_OUT));
+		USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+		break;
+	case CVMX_USB_STAGE_STATUS:
+		usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+		bytes_to_transfer = 0;
+		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir,
+				((header->s.request_type & 0x80) ?
+					CVMX_USB_DIRECTION_OUT :
+					CVMX_USB_DIRECTION_IN));
+		break;
+	case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+		usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+		bytes_to_transfer = 0;
+		USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir,
+				((header->s.request_type & 0x80) ?
+					CVMX_USB_DIRECTION_OUT :
+					CVMX_USB_DIRECTION_IN));
+		USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+		break;
+	}
 
-    switch (transaction->stage) {
-        case CVMX_USB_STAGE_NON_CONTROL:
-        case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
-            cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__);
-            break;
-        case CVMX_USB_STAGE_SETUP:
-            usbc_hctsiz.s.pid = 3; /* Setup */
-            bytes_to_transfer = sizeof(*header);
-            /* All Control operations start with a setup going OUT */
-            USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir, CVMX_USB_DIRECTION_OUT);
-            /* Setup send the control header instead of the buffer data. The
-                buffer data will be used in the next stage */
-            __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header);
-            break;
-        case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
-            usbc_hctsiz.s.pid = 3; /* Setup */
-            bytes_to_transfer = 0;
-            /* All Control operations start with a setup going OUT */
-            USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir, CVMX_USB_DIRECTION_OUT);
-            USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), cvmx_usbcx_hcspltx_t, compsplt, 1);
-            break;
-        case CVMX_USB_STAGE_DATA:
-            usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
-            if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-                if (header->s.request_type & 0x80)
-                    bytes_to_transfer = 0;
-                else if (bytes_to_transfer > pipe->max_packet)
-                    bytes_to_transfer = pipe->max_packet;
-            }
-            USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
-                            cvmx_usbcx_hccharx_t, epdir,
-                            ((header->s.request_type & 0x80) ?
-                             CVMX_USB_DIRECTION_IN :
-                             CVMX_USB_DIRECTION_OUT));
-            break;
-        case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
-            usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
-            if (!(header->s.request_type & 0x80))
-                bytes_to_transfer = 0;
-            USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
-                            cvmx_usbcx_hccharx_t, epdir,
-                            ((header->s.request_type & 0x80) ?
-                             CVMX_USB_DIRECTION_IN :
-                             CVMX_USB_DIRECTION_OUT));
-            USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), cvmx_usbcx_hcspltx_t, compsplt, 1);
-            break;
-        case CVMX_USB_STAGE_STATUS:
-            usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
-            bytes_to_transfer = 0;
-            USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir,
-                            ((header->s.request_type & 0x80) ?
-                             CVMX_USB_DIRECTION_OUT :
-                             CVMX_USB_DIRECTION_IN));
-            break;
-        case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
-            usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
-            bytes_to_transfer = 0;
-            USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, epdir,
-                            ((header->s.request_type & 0x80) ?
-                             CVMX_USB_DIRECTION_OUT :
-                             CVMX_USB_DIRECTION_IN));
-            USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), cvmx_usbcx_hcspltx_t, compsplt, 1);
-            break;
-    }
+	/*
+	 * Make sure the transfer never exceeds the byte limit of the hardware.
+	 * Further bytes will be sent as continued transactions
+	 */
+	if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
+		/* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
+		bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
+		bytes_to_transfer *= pipe->max_packet;
+	}
 
-    /* Make sure the transfer never exceeds the byte limit of the hardware.
-        Further bytes will be sent as continued transactions */
-    if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
-        /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
-        bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
-        bytes_to_transfer *= pipe->max_packet;
-    }
+	/*
+	 * Calculate the number of packets to transfer. If the length is zero
+	 * we still need to transfer one packet
+	 */
+	packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
+	if (packets_to_transfer == 0)
+		packets_to_transfer = 1;
+	else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+		/*
+		 * Limit to one packet when not using DMA. Channels must be
+		 * restarted between every packet for IN transactions, so there
+		 * is no reason to do multiple packets in a row
+		 */
+		packets_to_transfer = 1;
+		bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+	} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
+		/*
+		 * Limit the number of packet and data transferred to what the
+		 * hardware can handle
+		 */
+		packets_to_transfer = MAX_TRANSFER_PACKETS;
+		bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+	}
 
-    /* Calculate the number of packets to transfer. If the length is zero
-        we still need to transfer one packet */
-    packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
-    if (packets_to_transfer == 0)
-        packets_to_transfer = 1;
-    else if ((packets_to_transfer>1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
-        /* Limit to one packet when not using DMA. Channels must be restarted
-            between every packet for IN transactions, so there is no reason to
-            do multiple packets in a row */
-        packets_to_transfer = 1;
-        bytes_to_transfer = packets_to_transfer * pipe->max_packet;
-    }
-    else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
-        /* Limit the number of packet and data transferred to what the
-            hardware can handle */
-        packets_to_transfer = MAX_TRANSFER_PACKETS;
-        bytes_to_transfer = packets_to_transfer * pipe->max_packet;
-    }
+	usbc_hctsiz.s.xfersize = bytes_to_transfer;
+	usbc_hctsiz.s.pktcnt = packets_to_transfer;
 
-    usbc_hctsiz.s.xfersize = bytes_to_transfer;
-    usbc_hctsiz.s.pktcnt = packets_to_transfer;
-
-    __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
-    CVMX_USB_RETURN_NOTHING();
+	__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
+	return;
 }
 
 
 /**
- * @INTERNAL
  * Start a channel to perform the pipe's head transaction
  *
- * @param usb     USB device state populated by
- *                cvmx_usb_initialize().
- * @param channel Channel to setup
- * @param pipe    Pipe to start
+ * @usb:	  USB device state populated by
+ *		  cvmx_usb_initialize().
+ * @channel:	  Channel to setup
+ * @pipe:	  Pipe to start
  */
-static void __cvmx_usb_start_channel(cvmx_usb_internal_state_t *usb,
-                                     int channel,
-                                     cvmx_usb_pipe_t *pipe)
+static void __cvmx_usb_start_channel(struct cvmx_usb_internal_state *usb,
+				     int channel,
+				     struct cvmx_usb_pipe *pipe)
 {
-    cvmx_usb_transaction_t *transaction = pipe->head;
+	struct cvmx_usb_transaction *transaction = pipe->head;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
-    CVMX_USB_LOG_PARAM("%d", channel);
-    CVMX_USB_LOG_PARAM("%p", pipe);
+	/* Make sure all writes to the DMA region get flushed */
+	CVMX_SYNCW;
 
-    if (cvmx_unlikely((usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS) ||
-        (pipe->flags & CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS)))
-        cvmx_dprintf("%s: Channel %d started. Pipe %d transaction %d stage %d\n",
-                     __FUNCTION__, channel, __cvmx_usb_get_pipe_handle(usb, pipe),
-                     __cvmx_usb_get_submit_handle(usb, transaction),
-                     transaction->stage);
+	/* Attach the channel to the pipe */
+	usb->pipe_for_channel[channel] = pipe;
+	pipe->channel = channel;
+	pipe->flags |= __CVMX_USB_PIPE_FLAGS_SCHEDULED;
 
-    /* Make sure all writes to the DMA region get flushed */
-    CVMX_SYNCW;
+	/* Mark this channel as in use */
+	usb->idle_hardware_channels &= ~(1<<channel);
 
-    /* Attach the channel to the pipe */
-    usb->pipe_for_channel[channel] = pipe;
-    pipe->channel = channel;
-    pipe->flags |= __CVMX_USB_PIPE_FLAGS_SCHEDULED;
+	/* Enable the channel interrupt bits */
+	{
+		union cvmx_usbcx_hcintx usbc_hcint;
+		union cvmx_usbcx_hcintmskx usbc_hcintmsk;
+		union cvmx_usbcx_haintmsk usbc_haintmsk;
 
-    /* Mark this channel as in use */
-    usb->idle_hardware_channels &= ~(1<<channel);
+		/* Clear all channel status bits */
+		usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32);
 
-    /* Enable the channel interrupt bits */
-    {
-        cvmx_usbcx_hcintx_t usbc_hcint;
-        cvmx_usbcx_hcintmskx_t usbc_hcintmsk;
-        cvmx_usbcx_haintmsk_t usbc_haintmsk;
+		usbc_hcintmsk.u32 = 0;
+		usbc_hcintmsk.s.chhltdmsk = 1;
+		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+			/* Channels need these extra interrupts when we aren't in DMA mode */
+			usbc_hcintmsk.s.datatglerrmsk = 1;
+			usbc_hcintmsk.s.frmovrunmsk = 1;
+			usbc_hcintmsk.s.bblerrmsk = 1;
+			usbc_hcintmsk.s.xacterrmsk = 1;
+			if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+				/* Splits don't generate xfercompl, so we need ACK and NYET */
+				usbc_hcintmsk.s.nyetmsk = 1;
+				usbc_hcintmsk.s.ackmsk = 1;
+			}
+			usbc_hcintmsk.s.nakmsk = 1;
+			usbc_hcintmsk.s.stallmsk = 1;
+			usbc_hcintmsk.s.xfercomplmsk = 1;
+		}
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32);
 
-        /* Clear all channel status bits */
-        usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index), usbc_hcint.u32);
+		/* Enable the channel interrupt to propagate */
+		usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index));
+		usbc_haintmsk.s.haintmsk |= 1<<channel;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32);
+	}
 
-        usbc_hcintmsk.u32 = 0;
-        usbc_hcintmsk.s.chhltdmsk = 1;
-        if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
-            /* Channels need these extra interrupts when we aren't in DMA mode */
-            usbc_hcintmsk.s.datatglerrmsk = 1;
-            usbc_hcintmsk.s.frmovrunmsk = 1;
-            usbc_hcintmsk.s.bblerrmsk = 1;
-            usbc_hcintmsk.s.xacterrmsk = 1;
-            if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-                /* Splits don't generate xfercompl, so we need ACK and NYET */
-                usbc_hcintmsk.s.nyetmsk = 1;
-                usbc_hcintmsk.s.ackmsk = 1;
-            }
-            usbc_hcintmsk.s.nakmsk = 1;
-            usbc_hcintmsk.s.stallmsk = 1;
-            usbc_hcintmsk.s.xfercomplmsk = 1;
-        }
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32);
+	/* Setup the locations the DMA engines use  */
+	{
+		uint64_t dma_address = transaction->buffer + transaction->actual_bytes;
+		if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+			dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes;
+		__cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address);
+		__cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address);
+	}
 
-        /* Enable the channel interrupt to propagate */
-        usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index));
-        usbc_haintmsk.s.haintmsk |= 1<<channel;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32);
-    }
+	/* Setup both the size of the transfer and the SPLIT characteristics */
+	{
+		union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0};
+		union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0};
+		int packets_to_transfer;
+		int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
 
-    /* Setup the locations the DMA engines use  */
-    {
-        uint64_t dma_address = transaction->buffer + transaction->actual_bytes;
-        if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
-            dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes;
-        __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address);
-        __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address);
-    }
+		/*
+		 * ISOCHRONOUS transactions store each individual transfer size
+		 * in the packet structure, not the global buffer_length
+		 */
+		if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+			bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes;
 
-    /* Setup both the size of the transfer and the SPLIT characteristics */
-    {
-        cvmx_usbcx_hcspltx_t usbc_hcsplt = {.u32 = 0};
-        cvmx_usbcx_hctsizx_t usbc_hctsiz = {.u32 = 0};
-        int packets_to_transfer;
-        int bytes_to_transfer = transaction->buffer_length - transaction->actual_bytes;
+		/*
+		 * We need to do split transactions when we are talking to non
+		 * high speed devices that are behind a high speed hub
+		 */
+		if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+			/*
+			 * On the start split phase (stage is even) record the
+			 * frame number we will need to send the split complete.
+			 * We only store the lower two bits since the time ahead
+			 * can only be two frames
+			 */
+			if ((transaction->stage&1) == 0) {
+				if (transaction->type == CVMX_USB_TRANSFER_BULK)
+					pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f;
+				else
+					pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f;
+			} else
+				pipe->split_sc_frame = -1;
 
-        /* ISOCHRONOUS transactions store each individual transfer size in the
-            packet structure, not the global buffer_length */
-        if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
-            bytes_to_transfer = transaction->iso_packets[0].length - transaction->actual_bytes;
+			usbc_hcsplt.s.spltena = 1;
+			usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
+			usbc_hcsplt.s.prtaddr = pipe->hub_port;
+			usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
 
-        /* We need to do split transactions when we are talking to non high
-            speed devices that are behind a high speed hub */
-        if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-            /* On the start split phase (stage is even) record the frame number we
-                will need to send the split complete. We only store the lower two bits
-                since the time ahead can only be two frames */
-            if ((transaction->stage&1) == 0) {
-                if (transaction->type == CVMX_USB_TRANSFER_BULK)
-                    pipe->split_sc_frame = (usb->frame_number + 1) & 0x7f;
-                else
-                    pipe->split_sc_frame = (usb->frame_number + 2) & 0x7f;
-            }
-            else
-                pipe->split_sc_frame = -1;
+			/*
+			 * SPLIT transactions can only ever transmit one data
+			 * packet so limit the transfer size to the max packet
+			 * size
+			 */
+			if (bytes_to_transfer > pipe->max_packet)
+				bytes_to_transfer = pipe->max_packet;
 
-            usbc_hcsplt.s.spltena = 1;
-            usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
-            usbc_hcsplt.s.prtaddr = pipe->hub_port;
-            usbc_hcsplt.s.compsplt = (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
+			/*
+			 * ISOCHRONOUS OUT splits are unique in that they limit
+			 * data transfers to 188 byte chunks representing the
+			 * begin/middle/end of the data or all
+			 */
+			if (!usbc_hcsplt.s.compsplt &&
+				(pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+				(pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+				/*
+				 * Clear the split complete frame number as
+				 * there isn't going to be a split complete
+				 */
+				pipe->split_sc_frame = -1;
+				/*
+				 * See if we've started this transfer and sent
+				 * data
+				 */
+				if (transaction->actual_bytes == 0) {
+					/*
+					 * Nothing sent yet, this is either a
+					 * begin or the entire payload
+					 */
+					if (bytes_to_transfer <= 188)
+						usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */
+					else
+						usbc_hcsplt.s.xactpos = 2; /* First part of payload */
+				} else {
+					/*
+					 * Continuing the previous data, we must
+					 * either be in the middle or at the end
+					 */
+					if (bytes_to_transfer <= 188)
+						usbc_hcsplt.s.xactpos = 1; /* End of payload */
+					else
+						usbc_hcsplt.s.xactpos = 0; /* Middle of payload */
+				}
+				/*
+				 * Again, the transfer size is limited to 188
+				 * bytes
+				 */
+				if (bytes_to_transfer > 188)
+					bytes_to_transfer = 188;
+			}
+		}
 
-            /* SPLIT transactions can only ever transmit one data packet so
-                limit the transfer size to the max packet size */
-            if (bytes_to_transfer > pipe->max_packet)
-                bytes_to_transfer = pipe->max_packet;
+		/*
+		 * Make sure the transfer never exceeds the byte limit of the
+		 * hardware. Further bytes will be sent as continued
+		 * transactions
+		 */
+		if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
+			/*
+			 * Round MAX_TRANSFER_BYTES to a multiple of out packet
+			 * size
+			 */
+			bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
+			bytes_to_transfer *= pipe->max_packet;
+		}
 
-            /* ISOCHRONOUS OUT splits are unique in that they limit
-                data transfers to 188 byte chunks representing the
-                begin/middle/end of the data or all */
-            if (!usbc_hcsplt.s.compsplt &&
-                (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
-                (pipe->transfer_type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
-                /* Clear the split complete frame number as there isn't going
-                    to be a split complete */
-                pipe->split_sc_frame = -1;
-                /* See if we've started this transfer and sent data */
-                if (transaction->actual_bytes == 0) {
-                    /* Nothing sent yet, this is either a begin or the
-                        entire payload */
-                    if (bytes_to_transfer <= 188)
-                        usbc_hcsplt.s.xactpos = 3; /* Entire payload in one go */
-                    else
-                        usbc_hcsplt.s.xactpos = 2; /* First part of payload */
-                }
-                else {
-                    /* Continuing the previous data, we must either be
-                        in the middle or at the end */
-                    if (bytes_to_transfer <= 188)
-                        usbc_hcsplt.s.xactpos = 1; /* End of payload */
-                    else
-                        usbc_hcsplt.s.xactpos = 0; /* Middle of payload */
-                }
-                /* Again, the transfer size is limited to 188 bytes */
-                if (bytes_to_transfer > 188)
-                    bytes_to_transfer = 188;
-            }
-        }
+		/*
+		 * Calculate the number of packets to transfer. If the length is
+		 * zero we still need to transfer one packet
+		 */
+		packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
+		if (packets_to_transfer == 0)
+			packets_to_transfer = 1;
+		else if ((packets_to_transfer > 1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+			/*
+			 * Limit to one packet when not using DMA. Channels must
+			 * be restarted between every packet for IN
+			 * transactions, so there is no reason to do multiple
+			 * packets in a row
+			 */
+			packets_to_transfer = 1;
+			bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+		} else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
+			/*
+			 * Limit the number of packet and data transferred to
+			 * what the hardware can handle
+			 */
+			packets_to_transfer = MAX_TRANSFER_PACKETS;
+			bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+		}
 
-        /* Make sure the transfer never exceeds the byte limit of the hardware.
-            Further bytes will be sent as continued transactions */
-        if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
-            /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
-            bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
-            bytes_to_transfer *= pipe->max_packet;
-        }
+		usbc_hctsiz.s.xfersize = bytes_to_transfer;
+		usbc_hctsiz.s.pktcnt = packets_to_transfer;
 
-        /* Calculate the number of packets to transfer. If the length is zero
-            we still need to transfer one packet */
-        packets_to_transfer = (bytes_to_transfer + pipe->max_packet - 1) / pipe->max_packet;
-        if (packets_to_transfer == 0)
-            packets_to_transfer = 1;
-        else if ((packets_to_transfer>1) && (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
-            /* Limit to one packet when not using DMA. Channels must be restarted
-                between every packet for IN transactions, so there is no reason to
-                do multiple packets in a row */
-            packets_to_transfer = 1;
-            bytes_to_transfer = packets_to_transfer * pipe->max_packet;
-        }
-        else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
-            /* Limit the number of packet and data transferred to what the
-                hardware can handle */
-            packets_to_transfer = MAX_TRANSFER_PACKETS;
-            bytes_to_transfer = packets_to_transfer * pipe->max_packet;
-        }
+		/* Update the DATA0/DATA1 toggle */
+		usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
+		/*
+		 * High speed pipes may need a hardware ping before they start
+		 */
+		if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING)
+			usbc_hctsiz.s.dopng = 1;
 
-        usbc_hctsiz.s.xfersize = bytes_to_transfer;
-        usbc_hctsiz.s.pktcnt = packets_to_transfer;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32);
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
+	}
 
-        /* Update the DATA0/DATA1 toggle */
-        usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
-        /* High speed pipes may need a hardware ping before they start */
-        if (pipe->flags & __CVMX_USB_PIPE_FLAGS_NEED_PING)
-            usbc_hctsiz.s.dopng = 1;
+	/* Setup the Host Channel Characteristics Register */
+	{
+		union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0};
 
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCSPLTX(channel, usb->index), usbc_hcsplt.u32);
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index), usbc_hctsiz.u32);
-    }
+		/*
+		 * Set the startframe odd/even properly. This is only used for
+		 * periodic
+		 */
+		usbc_hcchar.s.oddfrm = usb->frame_number&1;
 
-    /* Setup the Host Channel Characteristics Register */
-    {
-        cvmx_usbcx_hccharx_t usbc_hcchar = {.u32 = 0};
+		/*
+		 * Set the number of back to back packets allowed by this
+		 * endpoint. Split transactions interpret "ec" as the number of
+		 * immediate retries of failure. These retries happen too
+		 * quickly, so we disable these entirely for splits
+		 */
+		if (__cvmx_usb_pipe_needs_split(usb, pipe))
+			usbc_hcchar.s.ec = 1;
+		else if (pipe->multi_count < 1)
+			usbc_hcchar.s.ec = 1;
+		else if (pipe->multi_count > 3)
+			usbc_hcchar.s.ec = 3;
+		else
+			usbc_hcchar.s.ec = pipe->multi_count;
 
-        /* Set the startframe odd/even properly. This is only used for periodic */
-        usbc_hcchar.s.oddfrm = usb->frame_number&1;
+		/* Set the rest of the endpoint specific settings */
+		usbc_hcchar.s.devaddr = pipe->device_addr;
+		usbc_hcchar.s.eptype = transaction->type;
+		usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW);
+		usbc_hcchar.s.epdir = pipe->transfer_dir;
+		usbc_hcchar.s.epnum = pipe->endpoint_num;
+		usbc_hcchar.s.mps = pipe->max_packet;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+	}
 
-        /* Set the number of back to back packets allowed by this endpoint.
-            Split transactions interpret "ec" as the number of immediate
-            retries of failure. These retries happen too quickly, so we
-            disable these entirely for splits */
-        if (__cvmx_usb_pipe_needs_split(usb, pipe))
-            usbc_hcchar.s.ec = 1;
-        else if (pipe->multi_count < 1)
-            usbc_hcchar.s.ec = 1;
-        else if (pipe->multi_count > 3)
-            usbc_hcchar.s.ec = 3;
-        else
-            usbc_hcchar.s.ec = pipe->multi_count;
-
-        /* Set the rest of the endpoint specific settings */
-        usbc_hcchar.s.devaddr = pipe->device_addr;
-        usbc_hcchar.s.eptype = transaction->type;
-        usbc_hcchar.s.lspddev = (pipe->device_speed == CVMX_USB_SPEED_LOW);
-        usbc_hcchar.s.epdir = pipe->transfer_dir;
-        usbc_hcchar.s.epnum = pipe->endpoint_num;
-        usbc_hcchar.s.mps = pipe->max_packet;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
-    }
-
-    /* Do transaction type specific fixups as needed */
-    switch (transaction->type) {
-        case CVMX_USB_TRANSFER_CONTROL:
-            __cvmx_usb_start_channel_control(usb, channel, pipe);
-            break;
-        case CVMX_USB_TRANSFER_BULK:
-        case CVMX_USB_TRANSFER_INTERRUPT:
-            break;
-        case CVMX_USB_TRANSFER_ISOCHRONOUS:
-            if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
-                /* ISO transactions require different PIDs depending on direction
-                    and how many packets are needed */
-                if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
-                    if (pipe->multi_count < 2) /* Need DATA0 */
-                        USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), cvmx_usbcx_hctsizx_t, pid, 0);
-                    else /* Need MDATA */
-                        USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), cvmx_usbcx_hctsizx_t, pid, 3);
-                }
-            }
-            break;
-    }
-    {
-        cvmx_usbcx_hctsizx_t usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))};
-        transaction->xfersize = usbc_hctsiz.s.xfersize;
-        transaction->pktcnt = usbc_hctsiz.s.pktcnt;
-    }
-    /* Remeber when we start a split transaction */
-    if (__cvmx_usb_pipe_needs_split(usb, pipe))
-        usb->active_split = transaction;
-    USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), cvmx_usbcx_hccharx_t, chena, 1);
-    if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
-        __cvmx_usb_fill_tx_fifo(usb, channel);
-    CVMX_USB_RETURN_NOTHING();
+	/* Do transaction type specific fixups as needed */
+	switch (transaction->type) {
+	case CVMX_USB_TRANSFER_CONTROL:
+		__cvmx_usb_start_channel_control(usb, channel, pipe);
+		break;
+	case CVMX_USB_TRANSFER_BULK:
+	case CVMX_USB_TRANSFER_INTERRUPT:
+		break;
+	case CVMX_USB_TRANSFER_ISOCHRONOUS:
+		if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
+			/*
+			 * ISO transactions require different PIDs depending on
+			 * direction and how many packets are needed
+			 */
+			if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+				if (pipe->multi_count < 2) /* Need DATA0 */
+					USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 0);
+				else /* Need MDATA */
+					USB_SET_FIELD32(CVMX_USBCX_HCTSIZX(channel, usb->index), union cvmx_usbcx_hctsizx, pid, 3);
+			}
+		}
+		break;
+	}
+	{
+		union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index))};
+		transaction->xfersize = usbc_hctsiz.s.xfersize;
+		transaction->pktcnt = usbc_hctsiz.s.pktcnt;
+	}
+	/* Remeber when we start a split transaction */
+	if (__cvmx_usb_pipe_needs_split(usb, pipe))
+		usb->active_split = transaction;
+	USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, chena, 1);
+	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+		__cvmx_usb_fill_tx_fifo(usb, channel);
+	return;
 }
 
 
 /**
- * @INTERNAL
  * Find a pipe that is ready to be scheduled to hardware.
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param list   Pipe list to search
- * @param current_frame
- *               Frame counter to use as a time reference.
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @list:	 Pipe list to search
+ * @current_frame:
+ *		 Frame counter to use as a time reference.
  *
- * @return Pipe or NULL if none are ready
+ * Returns: Pipe or NULL if none are ready
  */
-static cvmx_usb_pipe_t *__cvmx_usb_find_ready_pipe(cvmx_usb_internal_state_t *usb, cvmx_usb_pipe_list_t *list, uint64_t current_frame)
+static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(struct cvmx_usb_internal_state *usb, struct cvmx_usb_pipe_list *list, uint64_t current_frame)
 {
-    cvmx_usb_pipe_t *pipe = list->head;
-    while (pipe) {
-        if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && pipe->head &&
-            (pipe->next_tx_frame <= current_frame) &&
-            ((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) &&
-            (!usb->active_split || (usb->active_split == pipe->head))) {
-            CVMX_PREFETCH(pipe, 128);
-            CVMX_PREFETCH(pipe->head, 0);
-            return pipe;
-        }
-        pipe = pipe->next;
-    }
-    return NULL;
+	struct cvmx_usb_pipe *pipe = list->head;
+	while (pipe) {
+		if (!(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED) && pipe->head &&
+			(pipe->next_tx_frame <= current_frame) &&
+			((pipe->split_sc_frame == -1) || ((((int)current_frame - (int)pipe->split_sc_frame) & 0x7f) < 0x40)) &&
+			(!usb->active_split || (usb->active_split == pipe->head))) {
+			CVMX_PREFETCH(pipe, 128);
+			CVMX_PREFETCH(pipe->head, 0);
+			return pipe;
+		}
+		pipe = pipe->next;
+	}
+	return NULL;
 }
 
 
 /**
- * @INTERNAL
  * Called whenever a pipe might need to be scheduled to the
  * hardware.
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param is_sof True if this schedule was called on a SOF interrupt.
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @is_sof:	 True if this schedule was called on a SOF interrupt.
  */
-static void __cvmx_usb_schedule(cvmx_usb_internal_state_t *usb, int is_sof)
+static void __cvmx_usb_schedule(struct cvmx_usb_internal_state *usb, int is_sof)
 {
-    int channel;
-    cvmx_usb_pipe_t *pipe;
-    int need_sof;
-    cvmx_usb_transfer_t ttype;
+	int channel;
+	struct cvmx_usb_pipe *pipe;
+	int need_sof;
+	enum cvmx_usb_transfer ttype;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
+	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+		/* Without DMA we need to be careful to not schedule something at the end of a frame and cause an overrun */
+		union cvmx_usbcx_hfnum hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))};
+		union cvmx_usbcx_hfir hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))};
+		if (hfnum.s.frrem < hfir.s.frint/4)
+			goto done;
+	}
 
-    if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
-        /* Without DMA we need to be careful to not schedule something at the end of a frame and cause an overrun */
-        cvmx_usbcx_hfnum_t hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))};
-        cvmx_usbcx_hfir_t hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))};
-        if (hfnum.s.frrem < hfir.s.frint/4)
-            goto done;
-    }
+	while (usb->idle_hardware_channels) {
+		/* Find an idle channel */
+		CVMX_CLZ(channel, usb->idle_hardware_channels);
+		channel = 31 - channel;
+		if (unlikely(channel > 7))
+			break;
 
-    while (usb->idle_hardware_channels) {
-        /* Find an idle channel */
-        CVMX_CLZ(channel, usb->idle_hardware_channels);
-        channel = 31 - channel;
-        if (cvmx_unlikely(channel > 7)) {
-            if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO))
-                cvmx_dprintf("%s: Idle hardware channels has a channel higher than 7. This is wrong\n", __FUNCTION__);
-            break;
-        }
+		/* Find a pipe needing service */
+		pipe = NULL;
+		if (is_sof) {
+			/*
+			 * Only process periodic pipes on SOF interrupts. This
+			 * way we are sure that the periodic data is sent in the
+			 * beginning of the frame
+			 */
+			pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number);
+			if (likely(!pipe))
+				pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number);
+		}
+		if (likely(!pipe)) {
+			pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number);
+			if (likely(!pipe))
+				pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number);
+		}
+		if (!pipe)
+			break;
 
-        /* Find a pipe needing service */
-        pipe = NULL;
-        if (is_sof) {
-            /* Only process periodic pipes on SOF interrupts. This way we are
-                sure that the periodic data is sent in the beginning of the
-                frame */
-            pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_ISOCHRONOUS, usb->frame_number);
-            if (cvmx_likely(!pipe))
-                pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_INTERRUPT, usb->frame_number);
-        }
-        if (cvmx_likely(!pipe)) {
-            pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_CONTROL, usb->frame_number);
-            if (cvmx_likely(!pipe))
-                pipe = __cvmx_usb_find_ready_pipe(usb, usb->active_pipes + CVMX_USB_TRANSFER_BULK, usb->frame_number);
-        }
-        if (!pipe)
-            break;
-
-        CVMX_USB_LOG_PARAM("%d", channel);
-        CVMX_USB_LOG_PARAM("%p", pipe);
-
-        if (cvmx_unlikely((usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS) ||
-            (pipe->flags & CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS))) {
-            cvmx_usb_transaction_t *transaction = pipe->head;
-            const cvmx_usb_control_header_t *header = (transaction->control_header) ? cvmx_phys_to_ptr(transaction->control_header) : NULL;
-            const char *dir = (pipe->transfer_dir == CVMX_USB_DIRECTION_IN) ? "IN" : "OUT";
-            const char *type;
-            switch (pipe->transfer_type) {
-                case CVMX_USB_TRANSFER_CONTROL:
-                    type = "SETUP";
-                    dir = (header->s.request_type & 0x80) ? "IN" : "OUT";
-                    break;
-                case CVMX_USB_TRANSFER_ISOCHRONOUS:
-                    type = "ISOCHRONOUS";
-                    break;
-                case CVMX_USB_TRANSFER_BULK:
-                    type = "BULK";
-                    break;
-                default: /* CVMX_USB_TRANSFER_INTERRUPT */
-                    type = "INTERRUPT";
-                    break;
-            }
-            cvmx_dprintf("%s: Starting pipe %d, transaction %d on channel %d. %s %s len=%d header=0x%llx\n",
-                         __FUNCTION__, __cvmx_usb_get_pipe_handle(usb, pipe),
-                         __cvmx_usb_get_submit_handle(usb, transaction),
-                         channel, type, dir,
-                         transaction->buffer_length,
-                         (header) ? (unsigned long long)header->u64 : 0ull);
-        }
-        __cvmx_usb_start_channel(usb, channel, pipe);
-    }
+		__cvmx_usb_start_channel(usb, channel, pipe);
+	}
 
 done:
-    /* Only enable SOF interrupts when we have transactions pending in the
-        future that might need to be scheduled */
-    need_sof = 0;
-    for (ttype=CVMX_USB_TRANSFER_CONTROL; ttype<=CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
-        pipe = usb->active_pipes[ttype].head;
-        while (pipe) {
-            if (pipe->next_tx_frame > usb->frame_number) {
-                need_sof = 1;
-                break;
-            }
-            pipe=pipe->next;
-        }
-    }
-    USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), cvmx_usbcx_gintmsk_t, sofmsk, need_sof);
-    CVMX_USB_RETURN_NOTHING();
+	/*
+	 * Only enable SOF interrupts when we have transactions pending in the
+	 * future that might need to be scheduled
+	 */
+	need_sof = 0;
+	for (ttype = CVMX_USB_TRANSFER_CONTROL; ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
+		pipe = usb->active_pipes[ttype].head;
+		while (pipe) {
+			if (pipe->next_tx_frame > usb->frame_number) {
+				need_sof = 1;
+				break;
+			}
+			pipe = pipe->next;
+		}
+	}
+	USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index), union cvmx_usbcx_gintmsk, sofmsk, need_sof);
+	return;
 }
 
 
 /**
- * @INTERNAL
  * Call a user's callback for a specific reason.
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe   Pipe the callback is for or NULL
- * @param transaction
- *               Transaction the callback is for or NULL
- * @param reason Reason this callback is being called
- * @param complete_code
- *               Completion code for the transaction, if any
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @pipe:	 Pipe the callback is for or NULL
+ * @transaction:
+ *		 Transaction the callback is for or NULL
+ * @reason:	 Reason this callback is being called
+ * @complete_code:
+ *		 Completion code for the transaction, if any
  */
-static void __cvmx_usb_perform_callback(cvmx_usb_internal_state_t *usb,
-                                        cvmx_usb_pipe_t *pipe,
-                                        cvmx_usb_transaction_t *transaction,
-                                        cvmx_usb_callback_t reason,
-                                        cvmx_usb_complete_t complete_code)
+static void __cvmx_usb_perform_callback(struct cvmx_usb_internal_state *usb,
+					struct cvmx_usb_pipe *pipe,
+					struct cvmx_usb_transaction *transaction,
+					enum cvmx_usb_callback reason,
+					enum cvmx_usb_complete complete_code)
 {
-    cvmx_usb_callback_func_t callback = usb->callback[reason];
-    void *user_data = usb->callback_data[reason];
-    int submit_handle = -1;
-    int pipe_handle = -1;
-    int bytes_transferred = 0;
+	cvmx_usb_callback_func_t callback = usb->callback[reason];
+	void *user_data = usb->callback_data[reason];
+	int submit_handle = -1;
+	int pipe_handle = -1;
+	int bytes_transferred = 0;
 
-    if (pipe)
-        pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe);
+	if (pipe)
+		pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe);
 
-    if (transaction) {
-        submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
-        bytes_transferred = transaction->actual_bytes;
-        /* Transactions are allowed to override the default callback */
-        if ((reason == CVMX_USB_CALLBACK_TRANSFER_COMPLETE) && transaction->callback) {
-            callback = transaction->callback;
-            user_data = transaction->callback_data;
-        }
-    }
+	if (transaction) {
+		submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
+		bytes_transferred = transaction->actual_bytes;
+		/* Transactions are allowed to override the default callback */
+		if ((reason == CVMX_USB_CALLBACK_TRANSFER_COMPLETE) && transaction->callback) {
+			callback = transaction->callback;
+			user_data = transaction->callback_data;
+		}
+	}
 
-    if (!callback)
-        return;
+	if (!callback)
+		return;
 
-    if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS))
-        cvmx_dprintf("%*s%s: calling callback %p(usb=%p, complete_code=%s, "
-                     "pipe_handle=%d, submit_handle=%d, bytes_transferred=%d, user_data=%p);\n",
-                     2*usb->indent, "", __FUNCTION__, callback, usb,
-                     __cvmx_usb_complete_to_string(complete_code),
-                     pipe_handle, submit_handle, bytes_transferred, user_data);
-
-    callback((cvmx_usb_state_t *)usb, reason, complete_code, pipe_handle, submit_handle,
-             bytes_transferred, user_data);
-
-    if (cvmx_unlikely(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS))
-        cvmx_dprintf("%*s%s: callback %p complete\n", 2*usb->indent, "",
-                      __FUNCTION__, callback);
+	callback((struct cvmx_usb_state *)usb, reason, complete_code, pipe_handle, submit_handle,
+		 bytes_transferred, user_data);
 }
 
 
 /**
- * @INTERNAL
  * Signal the completion of a transaction and free it. The
  * transaction will be removed from the pipe transaction list.
  *
- * @param usb    USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe   Pipe the transaction is on
- * @param transaction
- *               Transaction that completed
- * @param complete_code
- *               Completion code
+ * @usb:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @pipe:	 Pipe the transaction is on
+ * @transaction:
+ *		 Transaction that completed
+ * @complete_code:
+ *		 Completion code
  */
-static void __cvmx_usb_perform_complete(cvmx_usb_internal_state_t * usb,
-                                        cvmx_usb_pipe_t *pipe,
-                                        cvmx_usb_transaction_t *transaction,
-                                        cvmx_usb_complete_t complete_code)
+static void __cvmx_usb_perform_complete(struct cvmx_usb_internal_state *usb,
+					struct cvmx_usb_pipe *pipe,
+					struct cvmx_usb_transaction *transaction,
+					enum cvmx_usb_complete complete_code)
 {
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
-    CVMX_USB_LOG_PARAM("%p", pipe);
-    CVMX_USB_LOG_PARAM("%p", transaction);
-    CVMX_USB_LOG_PARAM("%d", complete_code);
+	/* If this was a split then clear our split in progress marker */
+	if (usb->active_split == transaction)
+		usb->active_split = NULL;
 
-    /* If this was a split then clear our split in progress marker */
-    if (usb->active_split == transaction)
-        usb->active_split = NULL;
+	/*
+	 * Isochronous transactions need extra processing as they might not be
+	 * done after a single data transfer
+	 */
+	if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+		/* Update the number of bytes transferred in this ISO packet */
+		transaction->iso_packets[0].length = transaction->actual_bytes;
+		transaction->iso_packets[0].status = complete_code;
 
-    /* Isochronous transactions need extra processing as they might not be done
-        after a single data transfer */
-    if (cvmx_unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
-        /* Update the number of bytes transferred in this ISO packet */
-        transaction->iso_packets[0].length = transaction->actual_bytes;
-        transaction->iso_packets[0].status = complete_code;
+		/*
+		 * If there are more ISOs pending and we succeeded, schedule the
+		 * next one
+		 */
+		if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
+			transaction->actual_bytes = 0;	   /* No bytes transferred for this packet as of yet */
+			transaction->iso_number_packets--; /* One less ISO waiting to transfer */
+			transaction->iso_packets++;	   /* Increment to the next location in our packet array */
+			transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+			goto done;
+		}
+	}
 
-        /* If there are more ISOs pending and we succeeded, schedule the next
-            one */
-        if ((transaction->iso_number_packets > 1) && (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
-            transaction->actual_bytes = 0;      /* No bytes transferred for this packet as of yet */
-            transaction->iso_number_packets--;  /* One less ISO waiting to transfer */
-            transaction->iso_packets++;         /* Increment to the next location in our packet array */
-            transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
-            goto done;
-        }
-    }
+	/* Remove the transaction from the pipe list */
+	if (transaction->next)
+		transaction->next->prev = transaction->prev;
+	else
+		pipe->tail = transaction->prev;
+	if (transaction->prev)
+		transaction->prev->next = transaction->next;
+	else
+		pipe->head = transaction->next;
+	if (!pipe->head) {
+		__cvmx_usb_remove_pipe(usb->active_pipes + pipe->transfer_type, pipe);
+		__cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
 
-    /* Remove the transaction from the pipe list */
-    if (transaction->next)
-        transaction->next->prev = transaction->prev;
-    else
-        pipe->tail = transaction->prev;
-    if (transaction->prev)
-        transaction->prev->next = transaction->next;
-    else
-        pipe->head = transaction->next;
-    if (!pipe->head) {
-        __cvmx_usb_remove_pipe(usb->active_pipes + pipe->transfer_type, pipe);
-        __cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
-
-    }
-    __cvmx_usb_perform_callback(usb, pipe, transaction,
-                                CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
-                                complete_code);
-    __cvmx_usb_free_transaction(usb, transaction);
+	}
+	__cvmx_usb_perform_callback(usb, pipe, transaction,
+				    CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
+				    complete_code);
+	__cvmx_usb_free_transaction(usb, transaction);
 done:
-    CVMX_USB_RETURN_NOTHING();
+	return;
 }
 
 
 /**
- * @INTERNAL
  * Submit a usb transaction to a pipe. Called for all types
  * of transactions.
  *
- * @param usb
- * @param pipe_handle
- *                  Which pipe to submit to. Will be validated in this function.
- * @param type      Transaction type
- * @param flags     Flags for the transaction
- * @param buffer    User buffer for the transaction
- * @param buffer_length
- *                  User buffer's length in bytes
- * @param control_header
- *                  For control transactions, the 8 byte standard header
- * @param iso_start_frame
- *                  For ISO transactions, the start frame
- * @param iso_number_packets
- *                  For ISO, the number of packet in the transaction.
- * @param iso_packets
- *                  A description of each ISO packet
- * @param callback  User callback to call when the transaction completes
- * @param user_data User's data for the callback
+ * @usb:
+ * @pipe_handle:
+ *		    Which pipe to submit to. Will be validated in this function.
+ * @type:	    Transaction type
+ * @flags:	    Flags for the transaction
+ * @buffer:	    User buffer for the transaction
+ * @buffer_length:
+ *		    User buffer's length in bytes
+ * @control_header:
+ *		    For control transactions, the 8 byte standard header
+ * @iso_start_frame:
+ *		    For ISO transactions, the start frame
+ * @iso_number_packets:
+ *		    For ISO, the number of packet in the transaction.
+ * @iso_packets:
+ *		    A description of each ISO packet
+ * @callback:	    User callback to call when the transaction completes
+ * @user_data:	    User's data for the callback
  *
- * @return Submit handle or negative on failure. Matches the result
- *         in the external API.
+ * Returns: Submit handle or negative on failure. Matches the result
+ *	    in the external API.
  */
-static int __cvmx_usb_submit_transaction(cvmx_usb_internal_state_t *usb,
-                                         int pipe_handle,
-                                         cvmx_usb_transfer_t type,
-                                         int flags,
-                                         uint64_t buffer,
-                                         int buffer_length,
-                                         uint64_t control_header,
-                                         int iso_start_frame,
-                                         int iso_number_packets,
-                                         cvmx_usb_iso_packet_t *iso_packets,
-                                         cvmx_usb_callback_func_t callback,
-                                         void *user_data)
+static int __cvmx_usb_submit_transaction(struct cvmx_usb_internal_state *usb,
+					 int pipe_handle,
+					 enum cvmx_usb_transfer type,
+					 int flags,
+					 uint64_t buffer,
+					 int buffer_length,
+					 uint64_t control_header,
+					 int iso_start_frame,
+					 int iso_number_packets,
+					 struct cvmx_usb_iso_packet *iso_packets,
+					 cvmx_usb_callback_func_t callback,
+					 void *user_data)
 {
-    int submit_handle;
-    cvmx_usb_transaction_t *transaction;
-    cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
+	int submit_handle;
+	struct cvmx_usb_transaction *transaction;
+	struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
 
-    CVMX_USB_LOG_CALLED();
-    if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    /* Fail if the pipe isn't open */
-    if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(pipe->transfer_type != type))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+		return -EINVAL;
+	/* Fail if the pipe isn't open */
+	if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+		return -EINVAL;
+	if (unlikely(pipe->transfer_type != type))
+		return -EINVAL;
 
-    transaction = __cvmx_usb_alloc_transaction(usb);
-    if (cvmx_unlikely(!transaction))
-        CVMX_USB_RETURN(CVMX_USB_NO_MEMORY);
+	transaction = __cvmx_usb_alloc_transaction(usb);
+	if (unlikely(!transaction))
+		return -ENOMEM;
 
-    transaction->type = type;
-    transaction->flags |= flags;
-    transaction->buffer = buffer;
-    transaction->buffer_length = buffer_length;
-    transaction->control_header = control_header;
-    transaction->iso_start_frame = iso_start_frame; // FIXME: This is not used, implement it
-    transaction->iso_number_packets = iso_number_packets;
-    transaction->iso_packets = iso_packets;
-    transaction->callback = callback;
-    transaction->callback_data = user_data;
-    if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
-        transaction->stage = CVMX_USB_STAGE_SETUP;
-    else
-        transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+	transaction->type = type;
+	transaction->flags |= flags;
+	transaction->buffer = buffer;
+	transaction->buffer_length = buffer_length;
+	transaction->control_header = control_header;
+	transaction->iso_start_frame = iso_start_frame; // FIXME: This is not used, implement it
+	transaction->iso_number_packets = iso_number_packets;
+	transaction->iso_packets = iso_packets;
+	transaction->callback = callback;
+	transaction->callback_data = user_data;
+	if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
+		transaction->stage = CVMX_USB_STAGE_SETUP;
+	else
+		transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
 
-    transaction->next = NULL;
-    if (pipe->tail) {
-        transaction->prev = pipe->tail;
-        transaction->prev->next = transaction;
-    }
-    else {
-        if (pipe->next_tx_frame < usb->frame_number)
-            pipe->next_tx_frame = usb->frame_number + pipe->interval -
-                (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
-        transaction->prev = NULL;
-        pipe->head = transaction;
-        __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
-        __cvmx_usb_append_pipe(usb->active_pipes + pipe->transfer_type, pipe);
-    }
-    pipe->tail = transaction;
+	transaction->next = NULL;
+	if (pipe->tail) {
+		transaction->prev = pipe->tail;
+		transaction->prev->next = transaction;
+	} else {
+		if (pipe->next_tx_frame < usb->frame_number)
+			pipe->next_tx_frame = usb->frame_number + pipe->interval -
+				(usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+		transaction->prev = NULL;
+		pipe->head = transaction;
+		__cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
+		__cvmx_usb_append_pipe(usb->active_pipes + pipe->transfer_type, pipe);
+	}
+	pipe->tail = transaction;
 
-    submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
+	submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
 
-    /* We may need to schedule the pipe if this was the head of the pipe */
-    if (!transaction->prev)
-        __cvmx_usb_schedule(usb, 0);
+	/* We may need to schedule the pipe if this was the head of the pipe */
+	if (!transaction->prev)
+		__cvmx_usb_schedule(usb, 0);
 
-    CVMX_USB_RETURN(submit_handle);
+	return submit_handle;
 }
 
 
 /**
  * Call to submit a USB Bulk transfer to a pipe.
  *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
+ * @state:	    USB device state populated by
+ *		    cvmx_usb_initialize().
+ * @pipe_handle:
+ *		    Handle to the pipe for the transfer.
+ * @buffer:	    Physical address of the data buffer in
+ *		    memory. Note that this is NOT A POINTER, but
+ *		    the full 64bit physical address of the
+ *		    buffer. This may be zero if buffer_length is
+ *		    zero.
+ * @buffer_length:
+ *		    Length of buffer in bytes.
+ * @callback:	    Function to call when this transaction
+ *		    completes. If the return value of this
+ *		    function isn't an error, then this function
+ *		    is guaranteed to be called when the
+ *		    transaction completes. If this parameter is
+ *		    NULL, then the generic callback registered
+ *		    through cvmx_usb_register_callback is
+ *		    called. If both are NULL, then there is no
+ *		    way to know when a transaction completes.
+ * @user_data:	    User supplied data returned when the
+ *		    callback is called. This is only used if
+ *		    callback in not NULL.
  *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
+ * Returns: A submitted transaction handle or negative on
+ *	    failure. Negative values are error codes.
  */
-int cvmx_usb_submit_bulk(cvmx_usb_state_t *state, int pipe_handle,
-                                uint64_t buffer, int buffer_length,
-                                cvmx_usb_callback_func_t callback,
-                                void *user_data)
+int cvmx_usb_submit_bulk(struct cvmx_usb_state *state, int pipe_handle,
+			 uint64_t buffer, int buffer_length,
+			 cvmx_usb_callback_func_t callback,
+			 void *user_data)
 {
-    int submit_handle;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	int submit_handle;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
-    CVMX_USB_LOG_PARAM("%d", buffer_length);
+	/* Pipe handle checking is done later in a common place */
+	if (unlikely(!buffer))
+		return -EINVAL;
+	if (unlikely(buffer_length < 0))
+		return -EINVAL;
 
-    /* Pipe handle checking is done later in a common place */
-    if (cvmx_unlikely(!buffer))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(buffer_length < 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
-    submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                         CVMX_USB_TRANSFER_BULK,
-                                         0, /* flags */
-                                         buffer,
-                                         buffer_length,
-                                         0, /* control_header */
-                                         0, /* iso_start_frame */
-                                         0, /* iso_number_packets */
-                                         NULL, /* iso_packets */
-                                         callback,
-                                         user_data);
-    CVMX_USB_RETURN(submit_handle);
+	submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+						      CVMX_USB_TRANSFER_BULK,
+						      0, /* flags */
+						      buffer,
+						      buffer_length,
+						      0, /* control_header */
+						      0, /* iso_start_frame */
+						      0, /* iso_number_packets */
+						      NULL, /* iso_packets */
+						      callback,
+						      user_data);
+	return submit_handle;
 }
 
 
 /**
  * Call to submit a USB Interrupt transfer to a pipe.
  *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
+ * @state:	    USB device state populated by
+ *		    cvmx_usb_initialize().
+ * @pipe_handle:
+ *		    Handle to the pipe for the transfer.
+ * @buffer:	    Physical address of the data buffer in
+ *		    memory. Note that this is NOT A POINTER, but
+ *		    the full 64bit physical address of the
+ *		    buffer. This may be zero if buffer_length is
+ *		    zero.
+ * @buffer_length:
+ *		    Length of buffer in bytes.
+ * @callback:	    Function to call when this transaction
+ *		    completes. If the return value of this
+ *		    function isn't an error, then this function
+ *		    is guaranteed to be called when the
+ *		    transaction completes. If this parameter is
+ *		    NULL, then the generic callback registered
+ *		    through cvmx_usb_register_callback is
+ *		    called. If both are NULL, then there is no
+ *		    way to know when a transaction completes.
+ * @user_data:	    User supplied data returned when the
+ *		    callback is called. This is only used if
+ *		    callback in not NULL.
  *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
+ * Returns: A submitted transaction handle or negative on
+ *	    failure. Negative values are error codes.
  */
-int cvmx_usb_submit_interrupt(cvmx_usb_state_t *state, int pipe_handle,
-                              uint64_t buffer, int buffer_length,
-                              cvmx_usb_callback_func_t callback,
-                              void *user_data)
+int cvmx_usb_submit_interrupt(struct cvmx_usb_state *state, int pipe_handle,
+			      uint64_t buffer, int buffer_length,
+			      cvmx_usb_callback_func_t callback,
+			      void *user_data)
 {
-    int submit_handle;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	int submit_handle;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
-    CVMX_USB_LOG_PARAM("%d", buffer_length);
+	/* Pipe handle checking is done later in a common place */
+	if (unlikely(!buffer))
+		return -EINVAL;
+	if (unlikely(buffer_length < 0))
+		return -EINVAL;
 
-    /* Pipe handle checking is done later in a common place */
-    if (cvmx_unlikely(!buffer))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(buffer_length < 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
-    submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                         CVMX_USB_TRANSFER_INTERRUPT,
-                                         0, /* flags */
-                                         buffer,
-                                         buffer_length,
-                                         0, /* control_header */
-                                         0, /* iso_start_frame */
-                                         0, /* iso_number_packets */
-                                         NULL, /* iso_packets */
-                                         callback,
-                                         user_data);
-    CVMX_USB_RETURN(submit_handle);
+	submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+						      CVMX_USB_TRANSFER_INTERRUPT,
+						      0, /* flags */
+						      buffer,
+						      buffer_length,
+						      0, /* control_header */
+						      0, /* iso_start_frame */
+						      0, /* iso_number_packets */
+						      NULL, /* iso_packets */
+						      callback,
+						      user_data);
+	return submit_handle;
 }
 
 
 /**
  * Call to submit a USB Control transfer to a pipe.
  *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param control_header
- *                  USB 8 byte control header physical address.
- *                  Note that this is NOT A POINTER, but the
- *                  full 64bit physical address of the buffer.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
+ * @state:	    USB device state populated by
+ *		    cvmx_usb_initialize().
+ * @pipe_handle:
+ *		    Handle to the pipe for the transfer.
+ * @control_header:
+ *		    USB 8 byte control header physical address.
+ *		    Note that this is NOT A POINTER, but the
+ *		    full 64bit physical address of the buffer.
+ * @buffer:	    Physical address of the data buffer in
+ *		    memory. Note that this is NOT A POINTER, but
+ *		    the full 64bit physical address of the
+ *		    buffer. This may be zero if buffer_length is
+ *		    zero.
+ * @buffer_length:
+ *		    Length of buffer in bytes.
+ * @callback:	    Function to call when this transaction
+ *		    completes. If the return value of this
+ *		    function isn't an error, then this function
+ *		    is guaranteed to be called when the
+ *		    transaction completes. If this parameter is
+ *		    NULL, then the generic callback registered
+ *		    through cvmx_usb_register_callback is
+ *		    called. If both are NULL, then there is no
+ *		    way to know when a transaction completes.
+ * @user_data:	    User supplied data returned when the
+ *		    callback is called. This is only used if
+ *		    callback in not NULL.
  *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
+ * Returns: A submitted transaction handle or negative on
+ *	    failure. Negative values are error codes.
  */
-int cvmx_usb_submit_control(cvmx_usb_state_t *state, int pipe_handle,
-                            uint64_t control_header,
-                            uint64_t buffer, int buffer_length,
-                            cvmx_usb_callback_func_t callback,
-                            void *user_data)
+int cvmx_usb_submit_control(struct cvmx_usb_state *state, int pipe_handle,
+			    uint64_t control_header,
+			    uint64_t buffer, int buffer_length,
+			    cvmx_usb_callback_func_t callback,
+			    void *user_data)
 {
-    int submit_handle;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-    cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(control_header);
+	int submit_handle;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+	union cvmx_usb_control_header *header =
+		cvmx_phys_to_ptr(control_header);
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)control_header);
-    CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
-    CVMX_USB_LOG_PARAM("%d", buffer_length);
+	/* Pipe handle checking is done later in a common place */
+	if (unlikely(!control_header))
+		return -EINVAL;
+	/* Some drivers send a buffer with a zero length. God only knows why */
+	if (unlikely(buffer && (buffer_length < 0)))
+		return -EINVAL;
+	if (unlikely(!buffer && (buffer_length != 0)))
+		return -EINVAL;
+	if ((header->s.request_type & 0x80) == 0)
+		buffer_length = le16_to_cpu(header->s.length);
 
-    /* Pipe handle checking is done later in a common place */
-    if (cvmx_unlikely(!control_header))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    /* Some drivers send a buffer with a zero length. God only knows why */
-    if (cvmx_unlikely(buffer && (buffer_length < 0)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(!buffer && (buffer_length != 0)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if ((header->s.request_type & 0x80) == 0)
-        buffer_length = cvmx_le16_to_cpu(header->s.length);
-
-    submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                         CVMX_USB_TRANSFER_CONTROL,
-                                         0, /* flags */
-                                         buffer,
-                                         buffer_length,
-                                         control_header,
-                                         0, /* iso_start_frame */
-                                         0, /* iso_number_packets */
-                                         NULL, /* iso_packets */
-                                         callback,
-                                         user_data);
-    CVMX_USB_RETURN(submit_handle);
+	submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+						      CVMX_USB_TRANSFER_CONTROL,
+						      0, /* flags */
+						      buffer,
+						      buffer_length,
+						      control_header,
+						      0, /* iso_start_frame */
+						      0, /* iso_number_packets */
+						      NULL, /* iso_packets */
+						      callback,
+						      user_data);
+	return submit_handle;
 }
 
 
 /**
  * Call to submit a USB Isochronous transfer to a pipe.
  *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param start_frame
- *                  Number of frames into the future to schedule
- *                  this transaction.
- * @param flags     Flags to control the transfer. See
- *                  cvmx_usb_isochronous_flags_t for the flag
- *                  definitions.
- * @param number_packets
- *                  Number of sequential packets to transfer.
- *                  "packets" is a pointer to an array of this
- *                  many packet structures.
- * @param packets   Description of each transfer packet as
- *                  defined by cvmx_usb_iso_packet_t. The array
- *                  pointed to here must stay valid until the
- *                  complete callback is called.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
+ * @state:	    USB device state populated by
+ *		    cvmx_usb_initialize().
+ * @pipe_handle:
+ *		    Handle to the pipe for the transfer.
+ * @start_frame:
+ *		    Number of frames into the future to schedule
+ *		    this transaction.
+ * @flags:	    Flags to control the transfer. See
+ *		    enum cvmx_usb_isochronous_flags for the flag
+ *		    definitions.
+ * @number_packets:
+ *		    Number of sequential packets to transfer.
+ *		    "packets" is a pointer to an array of this
+ *		    many packet structures.
+ * @packets:	    Description of each transfer packet as
+ *		    defined by struct cvmx_usb_iso_packet. The array
+ *		    pointed to here must stay valid until the
+ *		    complete callback is called.
+ * @buffer:	    Physical address of the data buffer in
+ *		    memory. Note that this is NOT A POINTER, but
+ *		    the full 64bit physical address of the
+ *		    buffer. This may be zero if buffer_length is
+ *		    zero.
+ * @buffer_length:
+ *		    Length of buffer in bytes.
+ * @callback:	    Function to call when this transaction
+ *		    completes. If the return value of this
+ *		    function isn't an error, then this function
+ *		    is guaranteed to be called when the
+ *		    transaction completes. If this parameter is
+ *		    NULL, then the generic callback registered
+ *		    through cvmx_usb_register_callback is
+ *		    called. If both are NULL, then there is no
+ *		    way to know when a transaction completes.
+ * @user_data:	    User supplied data returned when the
+ *		    callback is called. This is only used if
+ *		    callback in not NULL.
  *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
+ * Returns: A submitted transaction handle or negative on
+ *	    failure. Negative values are error codes.
  */
-int cvmx_usb_submit_isochronous(cvmx_usb_state_t *state, int pipe_handle,
-                                int start_frame, int flags,
-                                int number_packets,
-                                cvmx_usb_iso_packet_t packets[],
-                                uint64_t buffer, int buffer_length,
-                                cvmx_usb_callback_func_t callback,
-                                void *user_data)
+int cvmx_usb_submit_isochronous(struct cvmx_usb_state *state, int pipe_handle,
+				int start_frame, int flags,
+				int number_packets,
+				struct cvmx_usb_iso_packet packets[],
+				uint64_t buffer, int buffer_length,
+				cvmx_usb_callback_func_t callback,
+				void *user_data)
 {
-    int submit_handle;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	int submit_handle;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    CVMX_USB_LOG_PARAM("%d", start_frame);
-    CVMX_USB_LOG_PARAM("0x%x", flags);
-    CVMX_USB_LOG_PARAM("%d", number_packets);
-    CVMX_USB_LOG_PARAM("%p", packets);
-    CVMX_USB_LOG_PARAM("0x%llx", (unsigned long long)buffer);
-    CVMX_USB_LOG_PARAM("%d", buffer_length);
+	/* Pipe handle checking is done later in a common place */
+	if (unlikely(start_frame < 0))
+		return -EINVAL;
+	if (unlikely(flags & ~(CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP)))
+		return -EINVAL;
+	if (unlikely(number_packets < 1))
+		return -EINVAL;
+	if (unlikely(!packets))
+		return -EINVAL;
+	if (unlikely(!buffer))
+		return -EINVAL;
+	if (unlikely(buffer_length < 0))
+		return -EINVAL;
 
-    /* Pipe handle checking is done later in a common place */
-    if (cvmx_unlikely(start_frame < 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(flags & ~(CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(number_packets < 1))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(!packets))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(!buffer))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(buffer_length < 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-
-    submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
-                                         CVMX_USB_TRANSFER_ISOCHRONOUS,
-                                         flags,
-                                         buffer,
-                                         buffer_length,
-                                         0, /* control_header */
-                                         start_frame,
-                                         number_packets,
-                                         packets,
-                                         callback,
-                                         user_data);
-    CVMX_USB_RETURN(submit_handle);
+	submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
+						      CVMX_USB_TRANSFER_ISOCHRONOUS,
+						      flags,
+						      buffer,
+						      buffer_length,
+						      0, /* control_header */
+						      start_frame,
+						      number_packets,
+						      packets,
+						      callback,
+						      user_data);
+	return submit_handle;
 }
 
 
@@ -2525,63 +2440,58 @@
  * a frame or two for the cvmx_usb_poll() function to call the
  * associated callback.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe_handle
- *               Pipe handle to cancel requests in.
- * @param submit_handle
- *               Handle to transaction to cancel, returned by the submit function.
+ * @state:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @pipe_handle:
+ *		 Pipe handle to cancel requests in.
+ * @submit_handle:
+ *		 Handle to transaction to cancel, returned by the submit function.
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_cancel(cvmx_usb_state_t *state, int pipe_handle,
-                                  int submit_handle)
+int cvmx_usb_cancel(struct cvmx_usb_state *state, int pipe_handle, int submit_handle)
 {
-    cvmx_usb_transaction_t *transaction;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-    cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
+	struct cvmx_usb_transaction *transaction;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+	struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    CVMX_USB_LOG_PARAM("%d", submit_handle);
+	if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+		return -EINVAL;
+	if (unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS)))
+		return -EINVAL;
 
-    if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	/* Fail if the pipe isn't open */
+	if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+		return -EINVAL;
 
-    /* Fail if the pipe isn't open */
-    if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	transaction = usb->transaction + submit_handle;
 
-    transaction = usb->transaction + submit_handle;
+	/* Fail if this transaction already completed */
+	if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
+		return -EINVAL;
 
-    /* Fail if this transaction already completed */
-    if (cvmx_unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	/*
+	 * If the transaction is the HEAD of the queue and scheduled. We need to
+	 * treat it special
+	 */
+	if ((pipe->head == transaction) &&
+		(pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
+		union cvmx_usbcx_hccharx usbc_hcchar;
 
-    /* If the transaction is the HEAD of the queue and scheduled. We need to
-        treat it special */
-    if ((pipe->head == transaction) &&
-        (pipe->flags & __CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
-        cvmx_usbcx_hccharx_t usbc_hcchar;
+		usb->pipe_for_channel[pipe->channel] = NULL;
+		pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
 
-        usb->pipe_for_channel[pipe->channel] = NULL;
-        pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
+		CVMX_SYNCW;
 
-        CVMX_SYNCW;
-
-        usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
-        /* If the channel isn't enabled then the transaction already completed */
-        if (usbc_hcchar.s.chena) {
-            usbc_hcchar.s.chdis = 1;
-            __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32);
-        }
-    }
-    __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL);
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+		usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
+		/* If the channel isn't enabled then the transaction already completed */
+		if (usbc_hcchar.s.chena) {
+			usbc_hcchar.s.chdis = 1;
+			__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(pipe->channel, usb->index), usbc_hcchar.u32);
+		}
+	}
+	__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_CANCEL);
+	return 0;
 }
 
 
@@ -2589,112 +2499,98 @@
  * Cancel all outstanding requests in a pipe. Logically all this
  * does is call cvmx_usb_cancel() in a loop.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe_handle
- *               Pipe handle to cancel requests in.
+ * @state:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @pipe_handle:
+ *		 Pipe handle to cancel requests in.
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_cancel_all(cvmx_usb_state_t *state, int pipe_handle)
+int cvmx_usb_cancel_all(struct cvmx_usb_state *state, int pipe_handle)
 {
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-    cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+	struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+		return -EINVAL;
 
-    /* Fail if the pipe isn't open */
-    if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	/* Fail if the pipe isn't open */
+	if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+		return -EINVAL;
 
-    /* Simply loop through and attempt to cancel each transaction */
-    while (pipe->head) {
-        cvmx_usb_status_t result = cvmx_usb_cancel(state, pipe_handle,
-            __cvmx_usb_get_submit_handle(usb, pipe->head));
-        if (cvmx_unlikely(result != CVMX_USB_SUCCESS))
-            CVMX_USB_RETURN(result);
-    }
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	/* Simply loop through and attempt to cancel each transaction */
+	while (pipe->head) {
+		int result = cvmx_usb_cancel(state, pipe_handle,
+			__cvmx_usb_get_submit_handle(usb, pipe->head));
+		if (unlikely(result != 0))
+			return result;
+	}
+	return 0;
 }
 
 
 /**
  * Close a pipe created with cvmx_usb_open_pipe().
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe_handle
- *               Pipe handle to close.
+ * @state:	 USB device state populated by
+ *		 cvmx_usb_initialize().
+ * @pipe_handle:
+ *		 Pipe handle to close.
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t. CVMX_USB_BUSY is returned if the
- *         pipe has outstanding transfers.
+ * Returns: 0 or a negative error code. EBUSY is returned if the pipe has
+ *	    outstanding transfers.
  */
-cvmx_usb_status_t cvmx_usb_close_pipe(cvmx_usb_state_t *state, int pipe_handle)
+int cvmx_usb_close_pipe(struct cvmx_usb_state *state, int pipe_handle)
 {
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-    cvmx_usb_pipe_t *pipe = usb->pipe + pipe_handle;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+	struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", pipe_handle);
-    if (cvmx_unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
+		return -EINVAL;
 
-    /* Fail if the pipe isn't open */
-    if (cvmx_unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	/* Fail if the pipe isn't open */
+	if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
+		return -EINVAL;
 
-    /* Fail if the pipe has pending transactions */
-    if (cvmx_unlikely(pipe->head))
-        CVMX_USB_RETURN(CVMX_USB_BUSY);
+	/* Fail if the pipe has pending transactions */
+	if (unlikely(pipe->head))
+		return -EBUSY;
 
-    pipe->flags = 0;
-    __cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
-    __cvmx_usb_append_pipe(&usb->free_pipes, pipe);
+	pipe->flags = 0;
+	__cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
+	__cvmx_usb_append_pipe(&usb->free_pipes, pipe);
 
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	return 0;
 }
 
 
 /**
  * Register a function to be called when various USB events occur.
  *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param reason    Which event to register for.
- * @param callback  Function to call when the event occurs.
- * @param user_data User data parameter to the function.
+ * @state:     USB device state populated by
+ *	       cvmx_usb_initialize().
+ * @reason:    Which event to register for.
+ * @callback:  Function to call when the event occurs.
+ * @user_data: User data parameter to the function.
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_register_callback(cvmx_usb_state_t *state,
-                                             cvmx_usb_callback_t reason,
-                                             cvmx_usb_callback_func_t callback,
-                                             void *user_data)
+int cvmx_usb_register_callback(struct cvmx_usb_state *state,
+			       enum cvmx_usb_callback reason,
+			       cvmx_usb_callback_func_t callback,
+			       void *user_data)
 {
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
-    CVMX_USB_LOG_PARAM("%d", reason);
-    CVMX_USB_LOG_PARAM("%p", callback);
-    CVMX_USB_LOG_PARAM("%p", user_data);
-    if (cvmx_unlikely(reason >= __CVMX_USB_CALLBACK_END))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
-    if (cvmx_unlikely(!callback))
-        CVMX_USB_RETURN(CVMX_USB_INVALID_PARAM);
+	if (unlikely(reason >= __CVMX_USB_CALLBACK_END))
+		return -EINVAL;
+	if (unlikely(!callback))
+		return -EINVAL;
 
-    usb->callback[reason] = callback;
-    usb->callback_data[reason] = user_data;
+	usb->callback[reason] = callback;
+	usb->callback_data[reason] = user_data;
 
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	return 0;
 }
 
 
@@ -2702,428 +2598,457 @@
  * Get the current USB protocol level frame number. The frame
  * number is always in the range of 0-0x7ff.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
+ * @state: USB device state populated by
+ *	   cvmx_usb_initialize().
  *
- * @return USB frame number
+ * Returns: USB frame number
  */
-int cvmx_usb_get_frame_number(cvmx_usb_state_t *state)
+int cvmx_usb_get_frame_number(struct cvmx_usb_state *state)
 {
-    int frame_number;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
-    cvmx_usbcx_hfnum_t usbc_hfnum;
+	int frame_number;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
+	union cvmx_usbcx_hfnum usbc_hfnum;
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
+	usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+	frame_number = usbc_hfnum.s.frnum;
 
-    usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
-    frame_number = usbc_hfnum.s.frnum;
-
-    CVMX_USB_RETURN(frame_number);
+	return frame_number;
 }
 
 
 /**
- * @INTERNAL
  * Poll a channel for status
  *
- * @param usb     USB device
- * @param channel Channel to poll
+ * @usb:     USB device
+ * @channel: Channel to poll
  *
- * @return Zero on success
+ * Returns: Zero on success
  */
-static int __cvmx_usb_poll_channel(cvmx_usb_internal_state_t *usb, int channel)
+static int __cvmx_usb_poll_channel(struct cvmx_usb_internal_state *usb, int channel)
 {
-    cvmx_usbcx_hcintx_t usbc_hcint;
-    cvmx_usbcx_hctsizx_t usbc_hctsiz;
-    cvmx_usbcx_hccharx_t usbc_hcchar;
-    cvmx_usb_pipe_t *pipe;
-    cvmx_usb_transaction_t *transaction;
-    int bytes_this_transfer;
-    int bytes_in_last_packet;
-    int packets_processed;
-    int buffer_space_left;
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", usb);
-    CVMX_USB_LOG_PARAM("%d", channel);
+	union cvmx_usbcx_hcintx usbc_hcint;
+	union cvmx_usbcx_hctsizx usbc_hctsiz;
+	union cvmx_usbcx_hccharx usbc_hcchar;
+	struct cvmx_usb_pipe *pipe;
+	struct cvmx_usb_transaction *transaction;
+	int bytes_this_transfer;
+	int bytes_in_last_packet;
+	int packets_processed;
+	int buffer_space_left;
 
-    /* Read the interrupt status bits for the channel */
-    usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
+	/* Read the interrupt status bits for the channel */
+	usbc_hcint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCINTX(channel, usb->index));
 
-    if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
-        usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+	if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+		usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
 
-        if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
-            /* There seems to be a bug in CN31XX which can cause interrupt
-                IN transfers to get stuck until we do a write of HCCHARX
-                without changing things */
-            __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
-            CVMX_USB_RETURN(0);
-        }
+		if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
+			/*
+			 * There seems to be a bug in CN31XX which can cause
+			 * interrupt IN transfers to get stuck until we do a
+			 * write of HCCHARX without changing things
+			 */
+			__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+			return 0;
+		}
 
-        /* In non DMA mode the channels don't halt themselves. We need to
-            manually disable channels that are left running */
-        if (!usbc_hcint.s.chhltd) {
-            if (usbc_hcchar.s.chena) {
-                cvmx_usbcx_hcintmskx_t hcintmsk;
-                /* Disable all interrupts except CHHLTD */
-                hcintmsk.u32 = 0;
-                hcintmsk.s.chhltdmsk = 1;
-                __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32);
-                usbc_hcchar.s.chdis = 1;
-                __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
-                CVMX_USB_RETURN(0);
-            }
-            else if (usbc_hcint.s.xfercompl) {
-                /* Successful IN/OUT with transfer complete. Channel halt isn't needed */
-            }
-            else {
-                cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel);
-                CVMX_USB_RETURN(0);
-            }
-        }
-    }
-    else {
-        /* There is are no interrupts that we need to process when the channel is
-            still running */
-        if (!usbc_hcint.s.chhltd)
-            CVMX_USB_RETURN(0);
-    }
+		/*
+		 * In non DMA mode the channels don't halt themselves. We need
+		 * to manually disable channels that are left running
+		 */
+		if (!usbc_hcint.s.chhltd) {
+			if (usbc_hcchar.s.chena) {
+				union cvmx_usbcx_hcintmskx hcintmsk;
+				/* Disable all interrupts except CHHLTD */
+				hcintmsk.u32 = 0;
+				hcintmsk.s.chhltdmsk = 1;
+				__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), hcintmsk.u32);
+				usbc_hcchar.s.chdis = 1;
+				__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index), usbc_hcchar.u32);
+				return 0;
+			} else if (usbc_hcint.s.xfercompl) {
+				/* Successful IN/OUT with transfer complete. Channel halt isn't needed */
+			} else {
+				cvmx_dprintf("USB%d: Channel %d interrupt without halt\n", usb->index, channel);
+				return 0;
+			}
+		}
+	} else {
+		/*
+		 * There is are no interrupts that we need to process when the
+		 * channel is still running
+		 */
+		if (!usbc_hcint.s.chhltd)
+			return 0;
+	}
 
-    /* Disable the channel interrupts now that it is done */
-    __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
-    usb->idle_hardware_channels |= (1<<channel);
+	/* Disable the channel interrupts now that it is done */
+	__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+	usb->idle_hardware_channels |= (1<<channel);
 
-    /* Make sure this channel is tied to a valid pipe */
-    pipe = usb->pipe_for_channel[channel];
-    CVMX_PREFETCH(pipe, 0);
-    CVMX_PREFETCH(pipe, 128);
-    if (!pipe)
-        CVMX_USB_RETURN(0);
-    transaction = pipe->head;
-    CVMX_PREFETCH0(transaction);
+	/* Make sure this channel is tied to a valid pipe */
+	pipe = usb->pipe_for_channel[channel];
+	CVMX_PREFETCH(pipe, 0);
+	CVMX_PREFETCH(pipe, 128);
+	if (!pipe)
+		return 0;
+	transaction = pipe->head;
+	CVMX_PREFETCH0(transaction);
 
-    /* Disconnect this pipe from the HW channel. Later the schedule function will
-        figure out which pipe needs to go */
-    usb->pipe_for_channel[channel] = NULL;
-    pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
+	/*
+	 * Disconnect this pipe from the HW channel. Later the schedule
+	 * function will figure out which pipe needs to go
+	 */
+	usb->pipe_for_channel[channel] = NULL;
+	pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_SCHEDULED;
 
-    /* Read the channel config info so we can figure out how much data
-        transfered */
-    usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
-    usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
+	/*
+	 * Read the channel config info so we can figure out how much data
+	 * transfered
+	 */
+	usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCCHARX(channel, usb->index));
+	usbc_hctsiz.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index));
 
-    /* Calculating the number of bytes successfully transferred is dependent on
-        the transfer direction */
-    packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
-    if (usbc_hcchar.s.epdir) {
-        /* IN transactions are easy. For every byte received the hardware
-            decrements xfersize. All we need to do is subtract the current
-            value of xfersize from its starting value and we know how many
-            bytes were written to the buffer */
-        bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize;
-    }
-    else {
-        /* OUT transaction don't decrement xfersize. Instead pktcnt is
-            decremented on every successful packet send. The hardware does
-            this when it receives an ACK, or NYET. If it doesn't
-            receive one of these responses pktcnt doesn't change */
-        bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
-        /* The last packet may not be a full transfer if we didn't have
-            enough data */
-        if (bytes_this_transfer > transaction->xfersize)
-            bytes_this_transfer = transaction->xfersize;
-    }
-    /* Figure out how many bytes were in the last packet of the transfer */
-    if (packets_processed)
-        bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps;
-    else
-        bytes_in_last_packet = bytes_this_transfer;
+	/*
+	 * Calculating the number of bytes successfully transferred is dependent
+	 * on the transfer direction
+	 */
+	packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
+	if (usbc_hcchar.s.epdir) {
+		/*
+		 * IN transactions are easy. For every byte received the
+		 * hardware decrements xfersize. All we need to do is subtract
+		 * the current value of xfersize from its starting value and we
+		 * know how many bytes were written to the buffer
+		 */
+		bytes_this_transfer = transaction->xfersize - usbc_hctsiz.s.xfersize;
+	} else {
+		/*
+		 * OUT transaction don't decrement xfersize. Instead pktcnt is
+		 * decremented on every successful packet send. The hardware
+		 * does this when it receives an ACK, or NYET. If it doesn't
+		 * receive one of these responses pktcnt doesn't change
+		 */
+		bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
+		/*
+		 * The last packet may not be a full transfer if we didn't have
+		 * enough data
+		 */
+		if (bytes_this_transfer > transaction->xfersize)
+			bytes_this_transfer = transaction->xfersize;
+	}
+	/* Figure out how many bytes were in the last packet of the transfer */
+	if (packets_processed)
+		bytes_in_last_packet = bytes_this_transfer - (packets_processed-1) * usbc_hcchar.s.mps;
+	else
+		bytes_in_last_packet = bytes_this_transfer;
 
-    /* As a special case, setup transactions output the setup header, not
-        the user's data. For this reason we don't count setup data as bytes
-        transferred */
-    if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
-        (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
-        bytes_this_transfer = 0;
+	/*
+	 * As a special case, setup transactions output the setup header, not
+	 * the user's data. For this reason we don't count setup data as bytes
+	 * transferred
+	 */
+	if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
+		(transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
+		bytes_this_transfer = 0;
 
-    /* Optional debug output */
-    if (cvmx_unlikely((usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS) ||
-        (pipe->flags & CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS)))
-        cvmx_dprintf("%s: Channel %d halted. Pipe %d transaction %d stage %d bytes=%d\n",
-                     __FUNCTION__, channel,
-                     __cvmx_usb_get_pipe_handle(usb, pipe),
-                     __cvmx_usb_get_submit_handle(usb, transaction),
-                     transaction->stage, bytes_this_transfer);
+	/*
+	 * Add the bytes transferred to the running total. It is important that
+	 * bytes_this_transfer doesn't count any data that needs to be
+	 * retransmitted
+	 */
+	transaction->actual_bytes += bytes_this_transfer;
+	if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+		buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes;
+	else
+		buffer_space_left = transaction->buffer_length - transaction->actual_bytes;
 
-    /* Add the bytes transferred to the running total. It is important that
-        bytes_this_transfer doesn't count any data that needs to be
-        retransmitted */
-    transaction->actual_bytes += bytes_this_transfer;
-    if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
-        buffer_space_left = transaction->iso_packets[0].length - transaction->actual_bytes;
-    else
-        buffer_space_left = transaction->buffer_length - transaction->actual_bytes;
+	/*
+	 * We need to remember the PID toggle state for the next transaction.
+	 * The hardware already updated it for the next transaction
+	 */
+	pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
 
-    /* We need to remember the PID toggle state for the next transaction. The
-        hardware already updated it for the next transaction */
-    pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
+	/*
+	 * For high speed bulk out, assume the next transaction will need to do
+	 * a ping before proceeding. If this isn't true the ACK processing below
+	 * will clear this flag
+	 */
+	if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+		(pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
+		(pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
+		pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
 
-    /* For high speed bulk out, assume the next transaction will need to do a
-        ping before proceeding. If this isn't true the ACK processing below
-        will clear this flag */
-    if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
-        (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
-        (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
-        pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
+	if (usbc_hcint.s.stall) {
+		/*
+		 * STALL as a response means this transaction cannot be
+		 * completed because the device can't process transactions. Tell
+		 * the user. Any data that was transferred will be counted on
+		 * the actual bytes transferred
+		 */
+		pipe->pid_toggle = 0;
+		__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL);
+	} else if (usbc_hcint.s.xacterr) {
+		/*
+		 * We know at least one packet worked if we get a ACK or NAK.
+		 * Reset the retry counter
+		 */
+		if (usbc_hcint.s.nak || usbc_hcint.s.ack)
+			transaction->retries = 0;
+		transaction->retries++;
+		if (transaction->retries > MAX_RETRIES) {
+			/*
+			 * XactErr as a response means the device signaled
+			 * something wrong with the transfer. For example, PID
+			 * toggle errors cause these
+			 */
+			__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR);
+		} else {
+			/*
+			 * If this was a split then clear our split in progress
+			 * marker
+			 */
+			if (usb->active_split == transaction)
+				usb->active_split = NULL;
+			/*
+			 * Rewind to the beginning of the transaction by anding
+			 * off the split complete bit
+			 */
+			transaction->stage &= ~1;
+			pipe->split_sc_frame = -1;
+			pipe->next_tx_frame += pipe->interval;
+			if (pipe->next_tx_frame < usb->frame_number)
+				pipe->next_tx_frame = usb->frame_number + pipe->interval -
+						      (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+		}
+	} else if (usbc_hcint.s.bblerr) {
+		/* Babble Error (BblErr) */
+		__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR);
+	} else if (usbc_hcint.s.datatglerr) {
+		/* We'll retry the exact same transaction again */
+		transaction->retries++;
+	} else if (usbc_hcint.s.nyet) {
+		/*
+		 * NYET as a response is only allowed in three cases: as a
+		 * response to a ping, as a response to a split transaction, and
+		 * as a response to a bulk out. The ping case is handled by
+		 * hardware, so we only have splits and bulk out
+		 */
+		if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
+			transaction->retries = 0;
+			/*
+			 * If there is more data to go then we need to try
+			 * again. Otherwise this transaction is complete
+			 */
+			if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet))
+				__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+		} else {
+			/*
+			 * Split transactions retry the split complete 4 times
+			 * then rewind to the start split and do the entire
+			 * transactions again
+			 */
+			transaction->retries++;
+			if ((transaction->retries & 0x3) == 0) {
+				/*
+				 * Rewind to the beginning of the transaction by
+				 * anding off the split complete bit
+				 */
+				transaction->stage &= ~1;
+				pipe->split_sc_frame = -1;
+			}
+		}
+	} else if (usbc_hcint.s.ack) {
+		transaction->retries = 0;
+		/*
+		 * The ACK bit can only be checked after the other error bits.
+		 * This is because a multi packet transfer may succeed in a
+		 * number of packets and then get a different response on the
+		 * last packet. In this case both ACK and the last response bit
+		 * will be set. If none of the other response bits is set, then
+		 * the last packet must have been an ACK
+		 *
+		 * Since we got an ACK, we know we don't need to do a ping on
+		 * this pipe
+		 */
+		pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING;
 
-    if (usbc_hcint.s.stall) {
-        /* STALL as a response means this transaction cannot be completed
-            because the device can't process transactions. Tell the user. Any
-            data that was transferred will be counted on the actual bytes
-            transferred */
-        pipe->pid_toggle = 0;
-        __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_STALL);
-    }
-    else if (usbc_hcint.s.xacterr) {
-        /* We know at least one packet worked if we get a ACK or NAK. Reset the retry counter */
-        if (usbc_hcint.s.nak || usbc_hcint.s.ack)
-            transaction->retries = 0;
-        transaction->retries++;
-        if (transaction->retries > MAX_RETRIES) {
-            /* XactErr as a response means the device signaled something wrong with
-                the transfer. For example, PID toggle errors cause these */
-            __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_XACTERR);
-        }
-        else {
-            /* If this was a split then clear our split in progress marker */
-            if (usb->active_split == transaction)
-                usb->active_split = NULL;
-            /* Rewind to the beginning of the transaction by anding off the
-                split complete bit */
-            transaction->stage &= ~1;
-            pipe->split_sc_frame = -1;
-            pipe->next_tx_frame += pipe->interval;
-            if (pipe->next_tx_frame < usb->frame_number)
-                pipe->next_tx_frame = usb->frame_number + pipe->interval -
-                    (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
-        }
-    }
-    else if (usbc_hcint.s.bblerr)
-    {
-        /* Babble Error (BblErr) */
-        __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_BABBLEERR);
-    }
-    else if (usbc_hcint.s.datatglerr)
-    {
-        /* We'll retry the exact same transaction again */
-        transaction->retries++;
-    }
-    else if (usbc_hcint.s.nyet) {
-        /* NYET as a response is only allowed in three cases: as a response to
-            a ping, as a response to a split transaction, and as a response to
-            a bulk out. The ping case is handled by hardware, so we only have
-            splits and bulk out */
-        if (!__cvmx_usb_pipe_needs_split(usb, pipe)) {
-            transaction->retries = 0;
-            /* If there is more data to go then we need to try again. Otherwise
-                this transaction is complete */
-            if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet))
-                __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-        }
-        else {
-            /* Split transactions retry the split complete 4 times then rewind
-                to the start split and do the entire transactions again */
-            transaction->retries++;
-            if ((transaction->retries & 0x3) == 0) {
-                /* Rewind to the beginning of the transaction by anding off the
-                    split complete bit */
-                transaction->stage &= ~1;
-                pipe->split_sc_frame = -1;
-            }
-        }
-    }
-    else if (usbc_hcint.s.ack) {
-        transaction->retries = 0;
-        /* The ACK bit can only be checked after the other error bits. This is
-            because a multi packet transfer may succeed in a number of packets
-            and then get a different response on the last packet. In this case
-            both ACK and the last response bit will be set. If none of the
-            other response bits is set, then the last packet must have been an
-            ACK */
-
-        /* Since we got an ACK, we know we don't need to do a ping on this
-            pipe */
-        pipe->flags &= ~__CVMX_USB_PIPE_FLAGS_NEED_PING;
-
-        switch (transaction->type)
-        {
-            case CVMX_USB_TRANSFER_CONTROL:
-                switch (transaction->stage)
-                {
-                    case CVMX_USB_STAGE_NON_CONTROL:
-                    case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
-                        /* This should be impossible */
-                        __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
-                        break;
-                    case CVMX_USB_STAGE_SETUP:
-                        pipe->pid_toggle = 1;
-                        if (__cvmx_usb_pipe_needs_split(usb, pipe))
-                            transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
-                        else {
-                            cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(transaction->control_header);
-                            if (header->s.length)
-                                transaction->stage = CVMX_USB_STAGE_DATA;
-                            else
-                                transaction->stage = CVMX_USB_STAGE_STATUS;
-                        }
-                        break;
-                    case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
-                        {
-                            cvmx_usb_control_header_t *header = cvmx_phys_to_ptr(transaction->control_header);
-                            if (header->s.length)
-                                transaction->stage = CVMX_USB_STAGE_DATA;
-                            else
-                                transaction->stage = CVMX_USB_STAGE_STATUS;
-                        }
-                        break;
-                    case CVMX_USB_STAGE_DATA:
-                        if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-                            transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
-                            /* For setup OUT data that are splits, the hardware
-                                doesn't appear to count transferred data. Here
-                                we manually update the data transferred */
-                            if (!usbc_hcchar.s.epdir) {
-                                if (buffer_space_left < pipe->max_packet)
-                                    transaction->actual_bytes += buffer_space_left;
-                                else
-                                    transaction->actual_bytes += pipe->max_packet;
-                            }
-                        }
-                        else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
-                            pipe->pid_toggle = 1;
-                            transaction->stage = CVMX_USB_STAGE_STATUS;
-                        }
-                        break;
-                    case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
-                        if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
-                            pipe->pid_toggle = 1;
-                            transaction->stage = CVMX_USB_STAGE_STATUS;
-                        }
-                        else {
-                            transaction->stage = CVMX_USB_STAGE_DATA;
-                        }
-                        break;
-                    case CVMX_USB_STAGE_STATUS:
-                        if (__cvmx_usb_pipe_needs_split(usb, pipe))
-                            transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
-                        else
-                            __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                        break;
-                    case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
-                        __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                        break;
-                }
-                break;
-            case CVMX_USB_TRANSFER_BULK:
-            case CVMX_USB_TRANSFER_INTERRUPT:
-                /* The only time a bulk transfer isn't complete when
-                    it finishes with an ACK is during a split transaction. For
-                    splits we need to continue the transfer if more data is
-                    needed */
-                if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-                    if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
-                        transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
-                    else {
-                        if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet))
-                            transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
-                        else {
-                            if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
-                                pipe->next_tx_frame += pipe->interval;
-                            __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                        }
-                    }
-                }
-                else {
-                    if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
-                        (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
-                        (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
-                        (usbc_hcint.s.nak))
-                        pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
-                    if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) {
-                        if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
-                            pipe->next_tx_frame += pipe->interval;
-                        __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                    }
-                }
-                break;
-            case CVMX_USB_TRANSFER_ISOCHRONOUS:
-                if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
-                    /* ISOCHRONOUS OUT splits don't require a complete split stage.
-                        Instead they use a sequence of begin OUT splits to transfer
-                        the data 188 bytes at a time. Once the transfer is complete,
-                        the pipe sleeps until the next schedule interval */
-                    if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
-                        /* If no space left or this wasn't a max size packet then
-                            this transfer is complete. Otherwise start it again
-                            to send the next 188 bytes */
-                        if (!buffer_space_left || (bytes_this_transfer < 188)) {
-                            pipe->next_tx_frame += pipe->interval;
-                            __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                        }
-                    }
-                    else {
-                        if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
-                            /* We are in the incoming data phase. Keep getting
-                                data until we run out of space or get a small
-                                packet */
-                            if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
-                                pipe->next_tx_frame += pipe->interval;
-                                __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                            }
-                        }
-                        else
-                            transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
-                    }
-                }
-                else {
-                    pipe->next_tx_frame += pipe->interval;
-                    __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
-                }
-                break;
-        }
-    }
-    else if (usbc_hcint.s.nak) {
-        /* If this was a split then clear our split in progress marker */
-        if (usb->active_split == transaction)
-            usb->active_split = NULL;
-        /* NAK as a response means the device couldn't accept the transaction,
-            but it should be retried in the future. Rewind to the beginning of
-            the transaction by anding off the split complete bit. Retry in the
-            next interval */
-        transaction->retries = 0;
-        transaction->stage &= ~1;
-        pipe->next_tx_frame += pipe->interval;
-        if (pipe->next_tx_frame < usb->frame_number)
-            pipe->next_tx_frame = usb->frame_number + pipe->interval -
-                (usb->frame_number - pipe->next_tx_frame) % pipe->interval;
-    }
-    else {
-        cvmx_usb_port_status_t port;
-        port = cvmx_usb_get_status((cvmx_usb_state_t *)usb);
-        if (port.port_enabled)
-        {
-            /* We'll retry the exact same transaction again */
-            transaction->retries++;
-        }
-        else
-        {
-            /* We get channel halted interrupts with no result bits sets when the
-                cable is unplugged */
-            __cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
-        }
-    }
-    CVMX_USB_RETURN(0);
+		switch (transaction->type) {
+		case CVMX_USB_TRANSFER_CONTROL:
+			switch (transaction->stage) {
+			case CVMX_USB_STAGE_NON_CONTROL:
+			case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+				/* This should be impossible */
+				__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
+				break;
+			case CVMX_USB_STAGE_SETUP:
+				pipe->pid_toggle = 1;
+				if (__cvmx_usb_pipe_needs_split(usb, pipe))
+					transaction->stage = CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
+				else {
+					union cvmx_usb_control_header *header =
+						cvmx_phys_to_ptr(transaction->control_header);
+					if (header->s.length)
+						transaction->stage = CVMX_USB_STAGE_DATA;
+					else
+						transaction->stage = CVMX_USB_STAGE_STATUS;
+				}
+				break;
+			case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+				{
+					union cvmx_usb_control_header *header =
+						cvmx_phys_to_ptr(transaction->control_header);
+					if (header->s.length)
+						transaction->stage = CVMX_USB_STAGE_DATA;
+					else
+						transaction->stage = CVMX_USB_STAGE_STATUS;
+				}
+				break;
+			case CVMX_USB_STAGE_DATA:
+				if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+					transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
+					/*
+					 * For setup OUT data that are splits,
+					 * the hardware doesn't appear to count
+					 * transferred data. Here we manually
+					 * update the data transferred
+					 */
+					if (!usbc_hcchar.s.epdir) {
+						if (buffer_space_left < pipe->max_packet)
+							transaction->actual_bytes += buffer_space_left;
+						else
+							transaction->actual_bytes += pipe->max_packet;
+					}
+				} else if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+					pipe->pid_toggle = 1;
+					transaction->stage = CVMX_USB_STAGE_STATUS;
+				}
+				break;
+			case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+				if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+					pipe->pid_toggle = 1;
+					transaction->stage = CVMX_USB_STAGE_STATUS;
+				} else {
+					transaction->stage = CVMX_USB_STAGE_DATA;
+				}
+				break;
+			case CVMX_USB_STAGE_STATUS:
+				if (__cvmx_usb_pipe_needs_split(usb, pipe))
+					transaction->stage = CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
+				else
+					__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+				break;
+			case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+				__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+				break;
+			}
+			break;
+		case CVMX_USB_TRANSFER_BULK:
+		case CVMX_USB_TRANSFER_INTERRUPT:
+			/*
+			 * The only time a bulk transfer isn't complete when it
+			 * finishes with an ACK is during a split transaction.
+			 * For splits we need to continue the transfer if more
+			 * data is needed
+			 */
+			if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+				if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
+					transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+				else {
+					if (buffer_space_left && (bytes_in_last_packet == pipe->max_packet))
+						transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+					else {
+						if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
+							pipe->next_tx_frame += pipe->interval;
+							__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+					}
+				}
+			} else {
+				if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+				    (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
+				    (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+				    (usbc_hcint.s.nak))
+					pipe->flags |= __CVMX_USB_PIPE_FLAGS_NEED_PING;
+				if (!buffer_space_left || (bytes_in_last_packet < pipe->max_packet)) {
+					if (transaction->type == CVMX_USB_TRANSFER_INTERRUPT)
+						pipe->next_tx_frame += pipe->interval;
+					__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+				}
+			}
+			break;
+		case CVMX_USB_TRANSFER_ISOCHRONOUS:
+			if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
+				/*
+				 * ISOCHRONOUS OUT splits don't require a
+				 * complete split stage. Instead they use a
+				 * sequence of begin OUT splits to transfer the
+				 * data 188 bytes at a time. Once the transfer
+				 * is complete, the pipe sleeps until the next
+				 * schedule interval
+				 */
+				if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+					/*
+					 * If no space left or this wasn't a max
+					 * size packet then this transfer is
+					 * complete. Otherwise start it again to
+					 * send the next 188 bytes
+					 */
+					if (!buffer_space_left || (bytes_this_transfer < 188)) {
+						pipe->next_tx_frame += pipe->interval;
+						__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+					}
+				} else {
+					if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
+						/*
+						 * We are in the incoming data
+						 * phase. Keep getting data
+						 * until we run out of space or
+						 * get a small packet
+						 */
+						if ((buffer_space_left == 0) || (bytes_in_last_packet < pipe->max_packet)) {
+							pipe->next_tx_frame += pipe->interval;
+							__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+						}
+					} else
+						transaction->stage = CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+				}
+			} else {
+				pipe->next_tx_frame += pipe->interval;
+				__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_SUCCESS);
+			}
+			break;
+		}
+	} else if (usbc_hcint.s.nak) {
+		/* If this was a split then clear our split in progress marker */
+		if (usb->active_split == transaction)
+			usb->active_split = NULL;
+		/*
+		 * NAK as a response means the device couldn't accept the
+		 * transaction, but it should be retried in the future. Rewind
+		 * to the beginning of the transaction by anding off the split
+		 * complete bit. Retry in the next interval
+		 */
+		transaction->retries = 0;
+		transaction->stage &= ~1;
+		pipe->next_tx_frame += pipe->interval;
+		if (pipe->next_tx_frame < usb->frame_number)
+			pipe->next_tx_frame = usb->frame_number + pipe->interval -
+				(usb->frame_number - pipe->next_tx_frame) % pipe->interval;
+	} else {
+		struct cvmx_usb_port_status port;
+		port = cvmx_usb_get_status((struct cvmx_usb_state *)usb);
+		if (port.port_enabled) {
+			/* We'll retry the exact same transaction again */
+			transaction->retries++;
+		} else {
+			/*
+			 * We get channel halted interrupts with no result bits
+			 * sets when the cable is unplugged
+			 */
+			__cvmx_usb_perform_complete(usb, pipe, transaction, CVMX_USB_COMPLETE_ERROR);
+		}
+	}
+	return 0;
 }
 
 
@@ -3133,97 +3058,101 @@
  * handler for the USB controller. It can also be called
  * periodically in a loop for non-interrupt based operation.
  *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
+ * @state:	USB device state populated by
+ *		cvmx_usb_initialize().
  *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
+ * Returns: 0 or a negative error code.
  */
-cvmx_usb_status_t cvmx_usb_poll(cvmx_usb_state_t *state)
+int cvmx_usb_poll(struct cvmx_usb_state *state)
 {
-    cvmx_usbcx_hfnum_t usbc_hfnum;
-    cvmx_usbcx_gintsts_t usbc_gintsts;
-    cvmx_usb_internal_state_t *usb = (cvmx_usb_internal_state_t*)state;
+	union cvmx_usbcx_hfnum usbc_hfnum;
+	union cvmx_usbcx_gintsts usbc_gintsts;
+	struct cvmx_usb_internal_state *usb = (struct cvmx_usb_internal_state *)state;
 
-    CVMX_PREFETCH(usb, 0);
-    CVMX_PREFETCH(usb, 1*128);
-    CVMX_PREFETCH(usb, 2*128);
-    CVMX_PREFETCH(usb, 3*128);
-    CVMX_PREFETCH(usb, 4*128);
+	CVMX_PREFETCH(usb, 0);
+	CVMX_PREFETCH(usb, 1*128);
+	CVMX_PREFETCH(usb, 2*128);
+	CVMX_PREFETCH(usb, 3*128);
+	CVMX_PREFETCH(usb, 4*128);
 
-    CVMX_USB_LOG_CALLED();
-    CVMX_USB_LOG_PARAM("%p", state);
+	/* Update the frame counter */
+	usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+	if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum)
+		usb->frame_number += 0x4000;
+	usb->frame_number &= ~0x3fffull;
+	usb->frame_number |= usbc_hfnum.s.frnum;
 
-    /* Update the frame counter */
-    usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
-    if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum)
-        usb->frame_number += 0x4000;
-    usb->frame_number &= ~0x3fffull;
-    usb->frame_number |= usbc_hfnum.s.frnum;
+	/* Read the pending interrupts */
+	usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index));
 
-    /* Read the pending interrupts */
-    usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index));
+	/* Clear the interrupts now that we know about them */
+	__cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
 
-    /* Clear the interrupts now that we know about them */
-    __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
+	if (usbc_gintsts.s.rxflvl) {
+		/*
+		 * RxFIFO Non-Empty (RxFLvl)
+		 * Indicates that there is at least one packet pending to be
+		 * read from the RxFIFO.
+		 *
+		 * In DMA mode this is handled by hardware
+		 */
+		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+			__cvmx_usb_poll_rx_fifo(usb);
+	}
+	if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) {
+		/* Fill the Tx FIFOs when not in DMA mode */
+		if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+			__cvmx_usb_poll_tx_fifo(usb);
+	}
+	if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
+		union cvmx_usbcx_hprt usbc_hprt;
+		/*
+		 * Disconnect Detected Interrupt (DisconnInt)
+		 * Asserted when a device disconnect is detected.
+		 *
+		 * Host Port Interrupt (PrtInt)
+		 * The core sets this bit to indicate a change in port status of
+		 * one of the O2P USB core ports in Host mode. The application
+		 * must read the Host Port Control and Status (HPRT) register to
+		 * determine the exact event that caused this interrupt. The
+		 * application must clear the appropriate status bit in the Host
+		 * Port Control and Status register to clear this bit.
+		 *
+		 * Call the user's port callback
+		 */
+		__cvmx_usb_perform_callback(usb, NULL, NULL,
+					    CVMX_USB_CALLBACK_PORT_CHANGED,
+					    CVMX_USB_COMPLETE_SUCCESS);
+		/* Clear the port change bits */
+		usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+		usbc_hprt.s.prtena = 0;
+		__cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32);
+	}
+	if (usbc_gintsts.s.hchint) {
+		/*
+		 * Host Channels Interrupt (HChInt)
+		 * The core sets this bit to indicate that an interrupt is
+		 * pending on one of the channels of the core (in Host mode).
+		 * The application must read the Host All Channels Interrupt
+		 * (HAINT) register to determine the exact number of the channel
+		 * on which the interrupt occurred, and then read the
+		 * corresponding Host Channel-n Interrupt (HCINTn) register to
+		 * determine the exact cause of the interrupt. The application
+		 * must clear the appropriate status bit in the HCINTn register
+		 * to clear this bit.
+		 */
+		union cvmx_usbcx_haint usbc_haint;
+		usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index));
+		while (usbc_haint.u32) {
+			int channel;
+			CVMX_CLZ(channel, usbc_haint.u32);
+			channel = 31 - channel;
+			__cvmx_usb_poll_channel(usb, channel);
+			usbc_haint.u32 ^= 1<<channel;
+		}
+	}
 
-    if (usbc_gintsts.s.rxflvl) {
-        /* RxFIFO Non-Empty (RxFLvl)
-            Indicates that there is at least one packet pending to be read
-            from the RxFIFO. */
-        /* In DMA mode this is handled by hardware */
-        if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
-            __cvmx_usb_poll_rx_fifo(usb);
-    }
-    if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) {
-        /* Fill the Tx FIFOs when not in DMA mode */
-        if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
-            __cvmx_usb_poll_tx_fifo(usb);
-    }
-    if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
-        cvmx_usbcx_hprt_t usbc_hprt;
-        /* Disconnect Detected Interrupt (DisconnInt)
-            Asserted when a device disconnect is detected. */
+	__cvmx_usb_schedule(usb, usbc_gintsts.s.sof);
 
-        /* Host Port Interrupt (PrtInt)
-            The core sets this bit to indicate a change in port status of one
-            of the O2P USB core ports in Host mode. The application must
-            read the Host Port Control and Status (HPRT) register to
-            determine the exact event that caused this interrupt. The
-            application must clear the appropriate status bit in the Host Port
-            Control and Status register to clear this bit. */
-
-        /* Call the user's port callback */
-        __cvmx_usb_perform_callback(usb, NULL, NULL,
-                                    CVMX_USB_CALLBACK_PORT_CHANGED,
-                                    CVMX_USB_COMPLETE_SUCCESS);
-        /* Clear the port change bits */
-        usbc_hprt.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
-        usbc_hprt.s.prtena = 0;
-        __cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index), usbc_hprt.u32);
-    }
-    if (usbc_gintsts.s.hchint) {
-        /* Host Channels Interrupt (HChInt)
-            The core sets this bit to indicate that an interrupt is pending on
-            one of the channels of the core (in Host mode). The application
-            must read the Host All Channels Interrupt (HAINT) register to
-            determine the exact number of the channel on which the
-            interrupt occurred, and then read the corresponding Host
-            Channel-n Interrupt (HCINTn) register to determine the exact
-            cause of the interrupt. The application must clear the
-            appropriate status bit in the HCINTn register to clear this bit. */
-        cvmx_usbcx_haint_t usbc_haint;
-        usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index));
-        while (usbc_haint.u32) {
-            int channel;
-            CVMX_CLZ(channel, usbc_haint.u32);
-            channel = 31 - channel;
-            __cvmx_usb_poll_channel(usb, channel);
-            usbc_haint.u32 ^= 1<<channel;
-        }
-    }
-
-    __cvmx_usb_schedule(usb, usbc_gintsts.s.sof);
-
-    CVMX_USB_RETURN(CVMX_USB_SUCCESS);
+	return 0;
 }
diff --git a/drivers/staging/octeon-usb/cvmx-usb.h b/drivers/staging/octeon-usb/cvmx-usb.h
index db9cc05..8bf3696 100644
--- a/drivers/staging/octeon-usb/cvmx-usb.h
+++ b/drivers/staging/octeon-usb/cvmx-usb.h
@@ -39,8 +39,6 @@
 
 
 /**
- * @file
- *
  * "cvmx-usb.h" defines a set of low level USB functions to help
  * developers create Octeon USB drivers for various operating
  * systems. These functions provide a generic API to the Octeon
@@ -49,24 +47,24 @@
  *
  * At a high level the device driver needs to:
  *
- * -# Call cvmx_usb_get_num_ports() to get the number of
- *  supported ports.
- * -# Call cvmx_usb_initialize() for each Octeon USB port.
- * -# Enable the port using cvmx_usb_enable().
- * -# Either periodically, or in an interrupt handler, call
- *  cvmx_usb_poll() to service USB events.
- * -# Manage pipes using cvmx_usb_open_pipe() and
- *  cvmx_usb_close_pipe().
- * -# Manage transfers using cvmx_usb_submit_*() and
- *  cvmx_usb_cancel*().
- * -# Shutdown USB on unload using cvmx_usb_shutdown().
+ * - Call cvmx_usb_get_num_ports() to get the number of
+ *   supported ports.
+ * - Call cvmx_usb_initialize() for each Octeon USB port.
+ * - Enable the port using cvmx_usb_enable().
+ * - Either periodically, or in an interrupt handler, call
+ *   cvmx_usb_poll() to service USB events.
+ * - Manage pipes using cvmx_usb_open_pipe() and
+ *   cvmx_usb_close_pipe().
+ * - Manage transfers using cvmx_usb_submit_*() and
+ *   cvmx_usb_cancel*().
+ * - Shutdown USB on unload using cvmx_usb_shutdown().
  *
  * To monitor USB status changes, the device driver must use
  * cvmx_usb_register_callback() to register for events that it
  * is interested in. Below are a few hints on successfully
  * implementing a driver on top of this API.
  *
- * <h2>Initialization</h2>
+ * == Initialization ==
  *
  * When a driver is first loaded, it is normally not necessary
  * to bring up the USB port completely. Most operating systems
@@ -75,24 +73,24 @@
  * initialize anything found, and then enable the hardware.
  *
  * In the probe phase you should:
- * -# Use cvmx_usb_get_num_ports() to determine the number of
- *  USB port to be supported.
- * -# Allocate space for a cvmx_usb_state_t structure for each
- *  port.
- * -# Tell the operating system about each port
+ * - Use cvmx_usb_get_num_ports() to determine the number of
+ *   USB port to be supported.
+ * - Allocate space for a struct cvmx_usb_state for each
+ *   port.
+ * - Tell the operating system about each port
  *
  * In the initialization phase you should:
- * -# Use cvmx_usb_initialize() on each port.
- * -# Do not call cvmx_usb_enable(). This leaves the USB port in
- *  the disabled state until the operating system is ready.
+ * - Use cvmx_usb_initialize() on each port.
+ * - Do not call cvmx_usb_enable(). This leaves the USB port in
+ *   the disabled state until the operating system is ready.
  *
  * Finally, in the enable phase you should:
- * -# Call cvmx_usb_enable() on the appropriate port.
- * -# Note that some operating system use a RESET instead of an
- *  enable call. To implement RESET, you should call
- *  cvmx_usb_disable() followed by cvmx_usb_enable().
+ * - Call cvmx_usb_enable() on the appropriate port.
+ * - Note that some operating system use a RESET instead of an
+ *   enable call. To implement RESET, you should call
+ *   cvmx_usb_disable() followed by cvmx_usb_enable().
  *
- * <h2>Locking</h2>
+ * == Locking ==
  *
  * All of the functions in the cvmx-usb API assume exclusive
  * access to the USB hardware and internal data structures. This
@@ -112,25 +110,24 @@
  * take a lock to make sure that another core cannot call
  * cvmx-usb.
  *
- * <h2>Port callback</h2>
+ * == Port callback ==
  *
  * The port callback prototype needs to look as follows:
  *
- * void port_callback(cvmx_usb_state_t *usb,
- *                    cvmx_usb_callback_t reason,
- *                    cvmx_usb_complete_t status,
+ * void port_callback(struct cvmx_usb_state *usb,
+ *                    enum cvmx_usb_callback reason,
+ *                    enum cvmx_usb_complete status,
  *                    int pipe_handle,
  *                    int submit_handle,
  *                    int bytes_transferred,
  *                    void *user_data);
- * - @b usb is the cvmx_usb_state_t for the port.
- * - @b reason will always be
- *   CVMX_USB_CALLBACK_PORT_CHANGED.
- * - @b status will always be CVMX_USB_COMPLETE_SUCCESS.
- * - @b pipe_handle will always be -1.
- * - @b submit_handle will always be -1.
- * - @b bytes_transferred will always be 0.
- * - @b user_data is the void pointer originally passed along
+ * - "usb" is the struct cvmx_usb_state for the port.
+ * - "reason" will always be CVMX_USB_CALLBACK_PORT_CHANGED.
+ * - "status" will always be CVMX_USB_COMPLETE_SUCCESS.
+ * - "pipe_handle" will always be -1.
+ * - "submit_handle" will always be -1.
+ * - "bytes_transferred" will always be 0.
+ * - "user_data" is the void pointer originally passed along
  *   with the callback. Use this for any state information you
  *   need.
  *
@@ -140,45 +137,43 @@
  * root port. Normally all the callback needs to do is tell the
  * operating system to poll the root hub for status. Under
  * Linux, this is performed by calling usb_hcd_poll_rh_status().
- * In the Linux driver we use @b user_data. to pass around the
+ * In the Linux driver we use "user_data". to pass around the
  * Linux "hcd" structure. Once the port callback completes,
  * Linux automatically calls octeon_usb_hub_status_data() which
  * uses cvmx_usb_get_status() to determine the root port status.
  *
- * <h2>Complete callback</h2>
+ * == Complete callback ==
  *
  * The completion callback prototype needs to look as follows:
  *
- * void complete_callback(cvmx_usb_state_t *usb,
- *                        cvmx_usb_callback_t reason,
- *                        cvmx_usb_complete_t status,
+ * void complete_callback(struct cvmx_usb_state *usb,
+ *                        enum cvmx_usb_callback reason,
+ *                        enum cvmx_usb_complete status,
  *                        int pipe_handle,
  *                        int submit_handle,
  *                        int bytes_transferred,
  *                        void *user_data);
- * - @b usb is the cvmx_usb_state_t for the port.
- * - @b reason will always be
- *   CVMX_USB_CALLBACK_TRANSFER_COMPLETE.
- * - @b status will be one of the cvmx_usb_complete_t
- *   enumerations.
- * - @b pipe_handle is the handle to the pipe the transaction
+ * - "usb" is the struct cvmx_usb_state for the port.
+ * - "reason" will always be CVMX_USB_CALLBACK_TRANSFER_COMPLETE.
+ * - "status" will be one of the cvmx_usb_complete enumerations.
+ * - "pipe_handle" is the handle to the pipe the transaction
  *   was originally submitted on.
- * - @b submit_handle is the handle returned by the original
+ * - "submit_handle" is the handle returned by the original
  *   cvmx_usb_submit_* call.
- * - @b bytes_transferred is the number of bytes successfully
+ * - "bytes_transferred" is the number of bytes successfully
  *   transferred in the transaction. This will be zero on most
  *   error conditions.
- * - @b user_data is the void pointer originally passed along
+ * - "user_data" is the void pointer originally passed along
  *   with the callback. Use this for any state information you
  *   need. For example, the Linux "urb" is stored in here in the
  *   Linux driver.
  *
- * In general your callback handler should use @b status and @b
- * bytes_transferred to tell the operating system the how the
+ * In general your callback handler should use "status" and
+ * "bytes_transferred" to tell the operating system the how the
  * transaction completed. Normally the pipe is not changed in
  * this callback.
  *
- * <h2>Canceling transactions</h2>
+ * == Canceling transactions ==
  *
  * When a transaction is cancelled using cvmx_usb_cancel*(), the
  * actual length of time until the complete callback is called
@@ -188,7 +183,7 @@
  * these cases, the complete handler will receive
  * CVMX_USB_COMPLETE_CANCEL.
  *
- * <h2>Handling pipes</h2>
+ * == Handling pipes ==
  *
  * USB "pipes" is a software construct created by this API to
  * enable the ordering of usb transactions to a device endpoint.
@@ -210,223 +205,16 @@
  * destroy a pipe for every transaction. A sequence of
  * transaction to the same endpoint must use the same pipe.
  *
- * <h2>Root Hub</h2>
+ * == Root Hub ==
  *
  * Some operating systems view the usb root port as a normal usb
  * hub. These systems attempt to control the root hub with
  * messages similar to the usb 2.0 spec for hub control and
  * status. For these systems it may be necessary to write
  * function to decode standard usb control messages into
- * equivalent cvmx-usb API calls. As an example, the following
- * code is used under Linux for some of the basic hub control
- * messages.
+ * equivalent cvmx-usb API calls.
  *
- * @code
- * static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
- * {
- *     cvmx_usb_state_t *usb = (cvmx_usb_state_t *)hcd->hcd_priv;
- *     cvmx_usb_port_status_t usb_port_status;
- *     int port_status;
- *     struct usb_hub_descriptor *desc;
- *     unsigned long flags;
- *
- *     switch (typeReq)
- *     {
- *         case ClearHubFeature:
- *             DEBUG_ROOT_HUB("OcteonUSB: ClearHubFeature\n");
- *             switch (wValue)
- *             {
- *                 case C_HUB_LOCAL_POWER:
- *                 case C_HUB_OVER_CURRENT:
- *                     // Nothing required here
- *                     break;
- *                 default:
- *                     return -EINVAL;
- *             }
- *             break;
- *         case ClearPortFeature:
- *             DEBUG_ROOT_HUB("OcteonUSB: ClearPortFeature");
- *             if (wIndex != 1)
- *             {
- *                 DEBUG_ROOT_HUB(" INVALID\n");
- *                 return -EINVAL;
- *             }
- *
- *             switch (wValue)
- *             {
- *                 case USB_PORT_FEAT_ENABLE:
- *                     DEBUG_ROOT_HUB(" ENABLE");
- *                     local_irq_save(flags);
- *                     cvmx_usb_disable(usb);
- *                     local_irq_restore(flags);
- *                     break;
- *                 case USB_PORT_FEAT_SUSPEND:
- *                     DEBUG_ROOT_HUB(" SUSPEND");
- *                     // Not supported on Octeon
- *                     break;
- *                 case USB_PORT_FEAT_POWER:
- *                     DEBUG_ROOT_HUB(" POWER");
- *                     // Not supported on Octeon
- *                     break;
- *                 case USB_PORT_FEAT_INDICATOR:
- *                     DEBUG_ROOT_HUB(" INDICATOR");
- *                     // Port inidicator not supported
- *                     break;
- *                 case USB_PORT_FEAT_C_CONNECTION:
- *                     DEBUG_ROOT_HUB(" C_CONNECTION");
- *                     // Clears drivers internal connect status change flag
- *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- *                     break;
- *                 case USB_PORT_FEAT_C_RESET:
- *                     DEBUG_ROOT_HUB(" C_RESET");
- *                     // Clears the driver's internal Port Reset Change flag
- *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- *                     break;
- *                 case USB_PORT_FEAT_C_ENABLE:
- *                     DEBUG_ROOT_HUB(" C_ENABLE");
- *                     // Clears the driver's internal Port Enable/Disable Change flag
- *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- *                     break;
- *                 case USB_PORT_FEAT_C_SUSPEND:
- *                     DEBUG_ROOT_HUB(" C_SUSPEND");
- *                     // Clears the driver's internal Port Suspend Change flag,
- *                         which is set when resume signaling on the host port is
- *                         complete
- *                     break;
- *                 case USB_PORT_FEAT_C_OVER_CURRENT:
- *                     DEBUG_ROOT_HUB(" C_OVER_CURRENT");
- *                     // Clears the driver's overcurrent Change flag
- *                     cvmx_usb_set_status(usb, cvmx_usb_get_status(usb));
- *                     break;
- *                 default:
- *                     DEBUG_ROOT_HUB(" UNKNOWN\n");
- *                     return -EINVAL;
- *             }
- *             DEBUG_ROOT_HUB("\n");
- *             break;
- *         case GetHubDescriptor:
- *             DEBUG_ROOT_HUB("OcteonUSB: GetHubDescriptor\n");
- *             desc = (struct usb_hub_descriptor *)buf;
- *             desc->bDescLength = 9;
- *             desc->bDescriptorType = 0x29;
- *             desc->bNbrPorts = 1;
- *             desc->wHubCharacteristics = 0x08;
- *             desc->bPwrOn2PwrGood = 1;
- *             desc->bHubContrCurrent = 0;
- *             desc->bitmap[0] = 0;
- *             desc->bitmap[1] = 0xff;
- *             break;
- *         case GetHubStatus:
- *             DEBUG_ROOT_HUB("OcteonUSB: GetHubStatus\n");
- *             *(__le32 *)buf = 0;
- *             break;
- *         case GetPortStatus:
- *             DEBUG_ROOT_HUB("OcteonUSB: GetPortStatus");
- *             if (wIndex != 1)
- *             {
- *                 DEBUG_ROOT_HUB(" INVALID\n");
- *                 return -EINVAL;
- *             }
- *
- *             usb_port_status = cvmx_usb_get_status(usb);
- *             port_status = 0;
- *
- *             if (usb_port_status.connect_change)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
- *                 DEBUG_ROOT_HUB(" C_CONNECTION");
- *             }
- *
- *             if (usb_port_status.port_enabled)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
- *                 DEBUG_ROOT_HUB(" C_ENABLE");
- *             }
- *
- *             if (usb_port_status.connected)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_CONNECTION);
- *                 DEBUG_ROOT_HUB(" CONNECTION");
- *             }
- *
- *             if (usb_port_status.port_enabled)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_ENABLE);
- *                 DEBUG_ROOT_HUB(" ENABLE");
- *             }
- *
- *             if (usb_port_status.port_over_current)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
- *                 DEBUG_ROOT_HUB(" OVER_CURRENT");
- *             }
- *
- *             if (usb_port_status.port_powered)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_POWER);
- *                 DEBUG_ROOT_HUB(" POWER");
- *             }
- *
- *             if (usb_port_status.port_speed == CVMX_USB_SPEED_HIGH)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
- *                 DEBUG_ROOT_HUB(" HIGHSPEED");
- *             }
- *             else if (usb_port_status.port_speed == CVMX_USB_SPEED_LOW)
- *             {
- *                 port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
- *                 DEBUG_ROOT_HUB(" LOWSPEED");
- *             }
- *
- *             *((__le32 *)buf) = cpu_to_le32(port_status);
- *             DEBUG_ROOT_HUB("\n");
- *             break;
- *         case SetHubFeature:
- *             DEBUG_ROOT_HUB("OcteonUSB: SetHubFeature\n");
- *             // No HUB features supported
- *             break;
- *         case SetPortFeature:
- *             DEBUG_ROOT_HUB("OcteonUSB: SetPortFeature");
- *             if (wIndex != 1)
- *             {
- *                 DEBUG_ROOT_HUB(" INVALID\n");
- *                 return -EINVAL;
- *             }
- *
- *             switch (wValue)
- *             {
- *                 case USB_PORT_FEAT_SUSPEND:
- *                     DEBUG_ROOT_HUB(" SUSPEND\n");
- *                     return -EINVAL;
- *                 case USB_PORT_FEAT_POWER:
- *                     DEBUG_ROOT_HUB(" POWER\n");
- *                     return -EINVAL;
- *                 case USB_PORT_FEAT_RESET:
- *                     DEBUG_ROOT_HUB(" RESET\n");
- *                     local_irq_save(flags);
- *                     cvmx_usb_disable(usb);
- *                     if (cvmx_usb_enable(usb))
- *                         DEBUG_ERROR("Failed to enable the port\n");
- *                     local_irq_restore(flags);
- *                     return 0;
- *                 case USB_PORT_FEAT_INDICATOR:
- *                     DEBUG_ROOT_HUB(" INDICATOR\n");
- *                     // Not supported
- *                     break;
- *                 default:
- *                     DEBUG_ROOT_HUB(" UNKNOWN\n");
- *                     return -EINVAL;
- *             }
- *             break;
- *         default:
- *             DEBUG_ROOT_HUB("OcteonUSB: Unknown root hub request\n");
- *             return -EINVAL;
- *     }
- *     return 0;
- * }
- * @endcode
- *
- * <h2>Interrupts</h2>
+ * == Interrupts ==
  *
  * If you plan on using usb interrupts, cvmx_usb_poll() must be
  * called on every usb interrupt. It will read the usb state,
@@ -441,154 +229,187 @@
  *
  * If you aren't using interrupts, simple call cvmx_usb_poll()
  * in your main processing loop.
- *
- * <hr>$Revision: 32636 $<hr>
  */
 
 #ifndef __CVMX_USB_H__
 #define __CVMX_USB_H__
 
-#ifdef	__cplusplus
-extern "C" {
-#endif
+/**
+ * enum cvmx_usb_speed - the possible USB device speeds
+ *
+ * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps
+ * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps
+ * @CVMX_USB_SPEED_LOW:  Device is operation at 1.5Mbps
+ */
+enum cvmx_usb_speed {
+	CVMX_USB_SPEED_HIGH = 0,
+	CVMX_USB_SPEED_FULL = 1,
+	CVMX_USB_SPEED_LOW = 2,
+};
 
 /**
- * Enumerations representing the status of function calls.
+ * enum cvmx_usb_transfer - the possible USB transfer types
+ *
+ * @CVMX_USB_TRANSFER_CONTROL:	   USB transfer type control for hub and status
+ *				   transfers
+ * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low
+ *				   priority periodic transfers
+ * @CVMX_USB_TRANSFER_BULK:	   USB transfer type bulk for large low priority
+ *				   transfers
+ * @CVMX_USB_TRANSFER_INTERRUPT:   USB transfer type interrupt for high priority
+ *				   periodic transfers
  */
-typedef enum
-{
-    CVMX_USB_SUCCESS = 0,           /**< There were no errors */
-    CVMX_USB_INVALID_PARAM = -1,    /**< A parameter to the function was invalid */
-    CVMX_USB_NO_MEMORY = -2,        /**< Insufficient resources were available for the request */
-    CVMX_USB_BUSY = -3,             /**< The resource is busy and cannot service the request */
-    CVMX_USB_TIMEOUT = -4,          /**< Waiting for an action timed out */
-    CVMX_USB_INCORRECT_MODE = -5,   /**< The function call doesn't work in the current USB
-                                         mode. This happens when host only functions are
-                                         called in device mode or vice versa */
-} cvmx_usb_status_t;
+enum cvmx_usb_transfer {
+	CVMX_USB_TRANSFER_CONTROL = 0,
+	CVMX_USB_TRANSFER_ISOCHRONOUS = 1,
+	CVMX_USB_TRANSFER_BULK = 2,
+	CVMX_USB_TRANSFER_INTERRUPT = 3,
+};
 
 /**
- * Enumerations representing the possible USB device speeds
+ * enum cvmx_usb_direction - the transfer directions
+ *
+ * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host
+ * @CVMX_USB_DIRECTION_IN:  Data is transferring from the device/host to Octeon
  */
-typedef enum
-{
-    CVMX_USB_SPEED_HIGH = 0,        /**< Device is operation at 480Mbps */
-    CVMX_USB_SPEED_FULL = 1,        /**< Device is operation at 12Mbps */
-    CVMX_USB_SPEED_LOW = 2,         /**< Device is operation at 1.5Mbps */
-} cvmx_usb_speed_t;
+enum cvmx_usb_direction {
+	CVMX_USB_DIRECTION_OUT,
+	CVMX_USB_DIRECTION_IN,
+};
 
 /**
- * Enumeration representing the possible USB transfer types.
+ * enum cvmx_usb_complete - possible callback function status codes
+ *
+ * @CVMX_USB_COMPLETE_SUCCESS:	  The transaction / operation finished without
+ *				  any errors
+ * @CVMX_USB_COMPLETE_SHORT:	  FIXME: This is currently not implemented
+ * @CVMX_USB_COMPLETE_CANCEL:	  The transaction was canceled while in flight by
+ *				  a user call to cvmx_usb_cancel
+ * @CVMX_USB_COMPLETE_ERROR:	  The transaction aborted with an unexpected
+ *				  error status
+ * @CVMX_USB_COMPLETE_STALL:	  The transaction received a USB STALL response
+ *				  from the device
+ * @CVMX_USB_COMPLETE_XACTERR:	  The transaction failed with an error from the
+ *				  device even after a number of retries
+ * @CVMX_USB_COMPLETE_DATATGLERR: The transaction failed with a data toggle
+ *				  error even after a number of retries
+ * @CVMX_USB_COMPLETE_BABBLEERR:  The transaction failed with a babble error
+ * @CVMX_USB_COMPLETE_FRAMEERR:	  The transaction failed with a frame error
+ *				  even after a number of retries
  */
-typedef enum
-{
-    CVMX_USB_TRANSFER_CONTROL = 0,      /**< USB transfer type control for hub and status transfers */
-    CVMX_USB_TRANSFER_ISOCHRONOUS = 1,  /**< USB transfer type isochronous for low priority periodic transfers */
-    CVMX_USB_TRANSFER_BULK = 2,         /**< USB transfer type bulk for large low priority transfers */
-    CVMX_USB_TRANSFER_INTERRUPT = 3,    /**< USB transfer type interrupt for high priority periodic transfers */
-} cvmx_usb_transfer_t;
+enum cvmx_usb_complete {
+	CVMX_USB_COMPLETE_SUCCESS,
+	CVMX_USB_COMPLETE_SHORT,
+	CVMX_USB_COMPLETE_CANCEL,
+	CVMX_USB_COMPLETE_ERROR,
+	CVMX_USB_COMPLETE_STALL,
+	CVMX_USB_COMPLETE_XACTERR,
+	CVMX_USB_COMPLETE_DATATGLERR,
+	CVMX_USB_COMPLETE_BABBLEERR,
+	CVMX_USB_COMPLETE_FRAMEERR,
+};
 
 /**
- * Enumeration of the transfer directions
+ * struct cvmx_usb_port_status - the USB port status information
+ *
+ * @port_enabled:	1 = Usb port is enabled, 0 = disabled
+ * @port_over_current:	1 = Over current detected, 0 = Over current not
+ *			detected. Octeon doesn't support over current detection.
+ * @port_powered:	1 = Port power is being supplied to the device, 0 =
+ *			power is off. Octeon doesn't support turning port power
+ *			off.
+ * @port_speed:		Current port speed.
+ * @connected:		1 = A device is connected to the port, 0 = No device is
+ *			connected.
+ * @connect_change:	1 = Device connected state changed since the last set
+ *			status call.
  */
-typedef enum
-{
-    CVMX_USB_DIRECTION_OUT,         /**< Data is transferring from Octeon to the device/host */
-    CVMX_USB_DIRECTION_IN,          /**< Data is transferring from the device/host to Octeon */
-} cvmx_usb_direction_t;
+struct cvmx_usb_port_status {
+	uint32_t reserved		: 25;
+	uint32_t port_enabled		: 1;
+	uint32_t port_over_current	: 1;
+	uint32_t port_powered		: 1;
+	enum cvmx_usb_speed port_speed	: 2;
+	uint32_t connected		: 1;
+	uint32_t connect_change		: 1;
+};
 
 /**
- * Enumeration of all possible status codes passed to callback
- * functions.
+ * union cvmx_usb_control_header - the structure of a Control packet header
+ *
+ * @s.request_type:	Bit 7 tells the direction: 1=IN, 0=OUT
+ * @s.request		The standard usb request to make
+ * @s.value		Value parameter for the request in little endian format
+ * @s.index		Index for the request in little endian format
+ * @s.length		Length of the data associated with this request in
+ *			little endian format
  */
-typedef enum
-{
-    CVMX_USB_COMPLETE_SUCCESS,      /**< The transaction / operation finished without any errors */
-    CVMX_USB_COMPLETE_SHORT,        /**< FIXME: This is currently not implemented */
-    CVMX_USB_COMPLETE_CANCEL,       /**< The transaction was canceled while in flight by a user call to cvmx_usb_cancel* */
-    CVMX_USB_COMPLETE_ERROR,        /**< The transaction aborted with an unexpected error status */
-    CVMX_USB_COMPLETE_STALL,        /**< The transaction received a USB STALL response from the device */
-    CVMX_USB_COMPLETE_XACTERR,      /**< The transaction failed with an error from the device even after a number of retries */
-    CVMX_USB_COMPLETE_DATATGLERR,   /**< The transaction failed with a data toggle error even after a number of retries */
-    CVMX_USB_COMPLETE_BABBLEERR,    /**< The transaction failed with a babble error */
-    CVMX_USB_COMPLETE_FRAMEERR,     /**< The transaction failed with a frame error even after a number of retries */
-} cvmx_usb_complete_t;
+union cvmx_usb_control_header {
+	uint64_t u64;
+	struct {
+		uint64_t request_type   : 8;
+		uint64_t request        : 8;
+		uint64_t value          : 16;
+		uint64_t index          : 16;
+		uint64_t length         : 16;
+	} s;
+};
 
 /**
- * Structure returned containing the USB port status information.
+ * struct cvmx_usb_iso_packet - descriptor for Isochronous packets
+ *
+ * @offset:	This is the offset in bytes into the main buffer where this data
+ *		is stored.
+ * @length:	This is the length in bytes of the data.
+ * @status:	This is the status of this individual packet transfer.
  */
-typedef struct
-{
-    uint32_t reserved           : 25;
-    uint32_t port_enabled       : 1; /**< 1 = Usb port is enabled, 0 = disabled */
-    uint32_t port_over_current  : 1; /**< 1 = Over current detected, 0 = Over current not detected. Octeon doesn't support over current detection */
-    uint32_t port_powered       : 1; /**< 1 = Port power is being supplied to the device, 0 = power is off. Octeon doesn't support turning port power off */
-    cvmx_usb_speed_t port_speed : 2; /**< Current port speed */
-    uint32_t connected          : 1; /**< 1 = A device is connected to the port, 0 = No device is connected */
-    uint32_t connect_change     : 1; /**< 1 = Device connected state changed since the last set status call */
-} cvmx_usb_port_status_t;
+struct cvmx_usb_iso_packet {
+	int offset;
+	int length;
+	enum cvmx_usb_complete status;
+};
 
 /**
- * This is the structure of a Control packet header
+ * enum cvmx_usb_callback - possible callback reasons for the USB API
+ *
+ * @CVMX_USB_CALLBACK_TRANSFER_COMPLETE: A callback of this type is called when
+ *					 a submitted transfer completes. The
+ *					 completion callback will be called even
+ *					 if the transfer fails or is canceled.
+ *					 The status parameter will contain
+ *					 details of why he callback was called.
+ * @CVMX_USB_CALLBACK_PORT_CHANGED:	 The status of the port changed. For
+ *					 example, someone may have plugged a
+ *					 device in. The status parameter
+ *					 contains CVMX_USB_COMPLETE_SUCCESS. Use
+ *					 cvmx_usb_get_status() to get the new
+ *					 port status.
+ * @__CVMX_USB_CALLBACK_END:		 Do not use. Used internally for array
+ *					 bounds.
  */
-typedef union
-{
-    uint64_t u64;
-    struct
-    {
-        uint64_t request_type   : 8;  /**< Bit 7 tells the direction: 1=IN, 0=OUT */
-        uint64_t request        : 8;  /**< The standard usb request to make */
-        uint64_t value          : 16; /**< Value parameter for the request in little endian format */
-        uint64_t index          : 16; /**< Index for the request in little endian format */
-        uint64_t length         : 16; /**< Length of the data associated with this request in little endian format */
-    } s;
-} cvmx_usb_control_header_t;
-
-/**
- * Descriptor for Isochronous packets
- */
-typedef struct
-{
-    int offset;                     /**< This is the offset in bytes into the main buffer where this data is stored */
-    int length;                     /**< This is the length in bytes of the data */
-    cvmx_usb_complete_t status;     /**< This is the status of this individual packet transfer */
-} cvmx_usb_iso_packet_t;
-
-/**
- * Possible callback reasons for the USB API.
- */
-typedef enum
-{
-    CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
-                                    /**< A callback of this type is called when a submitted transfer
-                                        completes. The completion callback will be called even if the
-                                        transfer fails or is canceled. The status parameter will
-                                        contain details of why he callback was called. */
-    CVMX_USB_CALLBACK_PORT_CHANGED, /**< The status of the port changed. For example, someone may have
-                                        plugged a device in. The status parameter contains
-                                        CVMX_USB_COMPLETE_SUCCESS. Use cvmx_usb_get_status() to get
-                                        the new port status. */
-    __CVMX_USB_CALLBACK_END         /**< Do not use. Used internally for array bounds */
-} cvmx_usb_callback_t;
+enum cvmx_usb_callback {
+	CVMX_USB_CALLBACK_TRANSFER_COMPLETE,
+	CVMX_USB_CALLBACK_PORT_CHANGED,
+	__CVMX_USB_CALLBACK_END
+};
 
 /**
  * USB state internal data. The contents of this structure
  * may change in future SDKs. No data in it should be referenced
  * by user's of this API.
  */
-typedef struct
-{
-    char data[65536];
-} cvmx_usb_state_t;
+struct cvmx_usb_state {
+	char data[65536];
+};
 
 /**
  * USB callback functions are always of the following type.
  * The parameters are as follows:
  *      - state = USB device state populated by
  *        cvmx_usb_initialize().
- *      - reason = The cvmx_usb_callback_t used to register
+ *      - reason = The enum cvmx_usb_callback used to register
  *        the callback.
- *      - status = The cvmx_usb_complete_t representing the
+ *      - status = The enum cvmx_usb_complete representing the
  *        status code of a transaction.
  *      - pipe_handle = The Pipe that caused this callback, or
  *        -1 if this callback wasn't associated with a pipe.
@@ -599,487 +420,123 @@
  *      - user_data = The user pointer supplied to the
  *        function cvmx_usb_submit() or
  *        cvmx_usb_register_callback() */
-typedef void (*cvmx_usb_callback_func_t)(cvmx_usb_state_t *state,
-                                         cvmx_usb_callback_t reason,
-                                         cvmx_usb_complete_t status,
+typedef void (*cvmx_usb_callback_func_t)(struct cvmx_usb_state *state,
+                                         enum cvmx_usb_callback reason,
+                                         enum cvmx_usb_complete status,
                                          int pipe_handle, int submit_handle,
                                          int bytes_transferred, void *user_data);
 
 /**
- * Flags to pass the initialization function.
- */
-typedef enum
-{
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI = 1<<0,       /**< The USB port uses a 12MHz crystal as clock source
-                                                            at USB_XO and USB_XI. */
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND = 1<<1,      /**< The USB port uses 12/24/48MHz 2.5V board clock
-                                                            source at USB_XO. USB_XI should be tied to GND.*/
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO = 0,           /**< Automatically determine clock type based on function
-                                                             in cvmx-helper-board.c. */
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK  = 3<<3,       /**< Mask for clock speed field */
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ = 1<<3,       /**< Speed of reference clock or crystal */
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ = 2<<3,       /**< Speed of reference clock */
-    CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ = 3<<3,       /**< Speed of reference clock */
-    /* Bits 3-4 used to encode the clock frequency */
-    CVMX_USB_INITIALIZE_FLAGS_NO_DMA = 1<<5,            /**< Disable DMA and used polled IO for data transfer use for the USB  */
-    CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS = 1<<16,  /**< Enable extra console output for debugging USB transfers */
-    CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLBACKS = 1<<17,  /**< Enable extra console output for debugging USB callbacks */
-    CVMX_USB_INITIALIZE_FLAGS_DEBUG_INFO = 1<<18,       /**< Enable extra console output for USB informational data */
-    CVMX_USB_INITIALIZE_FLAGS_DEBUG_CALLS = 1<<19,      /**< Enable extra console output for every function call */
-    CVMX_USB_INITIALIZE_FLAGS_DEBUG_CSRS = 1<<20,       /**< Enable extra console output for every CSR access */
-    CVMX_USB_INITIALIZE_FLAGS_DEBUG_ALL = ((CVMX_USB_INITIALIZE_FLAGS_DEBUG_CSRS<<1)-1) - (CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS-1),
-} cvmx_usb_initialize_flags_t;
-
-/**
- * Flags for passing when a pipe is created. Currently no flags
- * need to be passed.
- */
-typedef enum
-{
-    CVMX_USB_PIPE_FLAGS_DEBUG_TRANSFERS = 1<<15,/**< Used to display CVMX_USB_INITIALIZE_FLAGS_DEBUG_TRANSFERS for a specific pipe only */
-    __CVMX_USB_PIPE_FLAGS_OPEN = 1<<16,         /**< Used internally to determine if a pipe is open. Do not use */
-    __CVMX_USB_PIPE_FLAGS_SCHEDULED = 1<<17,    /**< Used internally to determine if a pipe is actively using hardware. Do not use */
-    __CVMX_USB_PIPE_FLAGS_NEED_PING = 1<<18,    /**< Used internally to determine if a high speed pipe is in the ping state. Do not use */
-} cvmx_usb_pipe_flags_t;
-
-/**
- * Return the number of USB ports supported by this Octeon
- * chip. If the chip doesn't support USB, or is not supported
- * by this API, a zero will be returned. Most Octeon chips
- * support one usb port, but some support two ports.
- * cvmx_usb_initialize() must be called on independent
- * cvmx_usb_state_t structures.
+ * enum cvmx_usb_initialize_flags - flags to pass the initialization function
  *
- * @return Number of port, zero if usb isn't supported
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI:    The USB port uses a 12MHz crystal
+ *					      as clock source at USB_XO and
+ *					      USB_XI.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND:   The USB port uses 12/24/48MHz 2.5V
+ *					      board clock source at USB_XO.
+ *					      USB_XI should be tied to GND.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO:     Automatically determine clock type
+ *					      based on function in
+ *					      cvmx-helper-board.c.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:    Speed of reference clock or
+ *					      crystal
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:    Speed of reference clock
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:    Speed of reference clock
+ * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA:	      Disable DMA and used polled IO for
+ *					      data transfer use for the USB
  */
+enum cvmx_usb_initialize_flags {
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI		= 1 << 0,
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND		= 1 << 1,
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO		= 0,
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK	= 3 << 3,
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ		= 1 << 3,
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ		= 2 << 3,
+	CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ		= 3 << 3,
+	/* Bits 3-4 used to encode the clock frequency */
+	CVMX_USB_INITIALIZE_FLAGS_NO_DMA		= 1 << 5,
+};
+
+/**
+ * enum cvmx_usb_pipe_flags - flags for passing when a pipe is created.
+ *			      Currently no flags need to be passed.
+ *
+ * @__CVMX_USB_PIPE_FLAGS_OPEN:	     Used internally to determine if a pipe is
+ *				     open. Do not use.
+ * @__CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is
+ *				     actively using hardware. Do not use.
+ * @__CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high
+ *				     speed pipe is in the ping state. Do not
+ *				     use.
+ */
+enum cvmx_usb_pipe_flags {
+	__CVMX_USB_PIPE_FLAGS_OPEN	= 1 << 16,
+	__CVMX_USB_PIPE_FLAGS_SCHEDULED	= 1 << 17,
+	__CVMX_USB_PIPE_FLAGS_NEED_PING	= 1 << 18,
+};
+
 extern int cvmx_usb_get_num_ports(void);
-
-/**
- * Initialize a USB port for use. This must be called before any
- * other access to the Octeon USB port is made. The port starts
- * off in the disabled state.
- *
- * @param state  Pointer to an empty cvmx_usb_state_t structure
- *               that will be populated by the initialize call.
- *               This structure is then passed to all other USB
- *               functions.
- * @param usb_port_number
- *               Which Octeon USB port to initialize.
- * @param flags  Flags to control hardware initialization. See
- *               cvmx_usb_initialize_flags_t for the flag
- *               definitions. Some flags are mandatory.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_initialize(cvmx_usb_state_t *state,
-                                             int usb_port_number,
-                                             cvmx_usb_initialize_flags_t flags);
-
-/**
- * Shutdown a USB port after a call to cvmx_usb_initialize().
- * The port should be disabled with all pipes closed when this
- * function is called.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_shutdown(cvmx_usb_state_t *state);
-
-/**
- * Enable a USB port. After this call succeeds, the USB port is
- * online and servicing requests.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_enable(cvmx_usb_state_t *state);
-
-/**
- * Disable a USB port. After this call the USB port will not
- * generate data transfers and will not generate events.
- * Transactions in process will fail and call their
- * associated callbacks.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_disable(cvmx_usb_state_t *state);
-
-/**
- * Get the current state of the USB port. Use this call to
- * determine if the usb port has anything connected, is enabled,
- * or has some sort of error condition. The return value of this
- * call has "changed" bits to signal of the value of some fields
- * have changed between calls. These "changed" fields are based
- * on the last call to cvmx_usb_set_status(). In order to clear
- * them, you must update the status through cvmx_usb_set_status().
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- *
- * @return Port status information
- */
-extern cvmx_usb_port_status_t cvmx_usb_get_status(cvmx_usb_state_t *state);
-
-/**
- * Set the current state of the USB port. The status is used as
- * a reference for the "changed" bits returned by
- * cvmx_usb_get_status(). Other than serving as a reference, the
- * status passed to this function is not used. No fields can be
- * changed through this call.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param port_status
- *               Port status to set, most like returned by cvmx_usb_get_status()
- */
-extern void cvmx_usb_set_status(cvmx_usb_state_t *state, cvmx_usb_port_status_t port_status);
-
-/**
- * Open a virtual pipe between the host and a USB device. A pipe
- * must be opened before data can be transferred between a device
- * and Octeon.
- *
- * @param state      USB device state populated by
- *                   cvmx_usb_initialize().
- * @param flags      Optional pipe flags defined in
- *                   cvmx_usb_pipe_flags_t.
- * @param device_addr
- *                   USB device address to open the pipe to
- *                   (0-127).
- * @param endpoint_num
- *                   USB endpoint number to open the pipe to
- *                   (0-15).
- * @param device_speed
- *                   The speed of the device the pipe is going
- *                   to. This must match the device's speed,
- *                   which may be different than the port speed.
- * @param max_packet The maximum packet length the device can
- *                   transmit/receive (low speed=0-8, full
- *                   speed=0-1023, high speed=0-1024). This value
- *                   comes from the standard endpoint descriptor
- *                   field wMaxPacketSize bits <10:0>.
- * @param transfer_type
- *                   The type of transfer this pipe is for.
- * @param transfer_dir
- *                   The direction the pipe is in. This is not
- *                   used for control pipes.
- * @param interval   For ISOCHRONOUS and INTERRUPT transfers,
- *                   this is how often the transfer is scheduled
- *                   for. All other transfers should specify
- *                   zero. The units are in frames (8000/sec at
- *                   high speed, 1000/sec for full speed).
- * @param multi_count
- *                   For high speed devices, this is the maximum
- *                   allowed number of packet per microframe.
- *                   Specify zero for non high speed devices. This
- *                   value comes from the standard endpoint descriptor
- *                   field wMaxPacketSize bits <12:11>.
- * @param hub_device_addr
- *                   Hub device address this device is connected
- *                   to. Devices connected directly to Octeon
- *                   use zero. This is only used when the device
- *                   is full/low speed behind a high speed hub.
- *                   The address will be of the high speed hub,
- *                   not and full speed hubs after it.
- * @param hub_port   Which port on the hub the device is
- *                   connected. Use zero for devices connected
- *                   directly to Octeon. Like hub_device_addr,
- *                   this is only used for full/low speed
- *                   devices behind a high speed hub.
- *
- * @return A non negative value is a pipe handle. Negative
- *         values are failure codes from cvmx_usb_status_t.
- */
-extern int cvmx_usb_open_pipe(cvmx_usb_state_t *state,
-                              cvmx_usb_pipe_flags_t flags,
+extern int cvmx_usb_initialize(struct cvmx_usb_state *state, int usb_port_number,
+			       enum cvmx_usb_initialize_flags flags);
+extern int cvmx_usb_shutdown(struct cvmx_usb_state *state);
+extern int cvmx_usb_enable(struct cvmx_usb_state *state);
+extern int cvmx_usb_disable(struct cvmx_usb_state *state);
+extern struct cvmx_usb_port_status cvmx_usb_get_status(struct cvmx_usb_state *state);
+extern void cvmx_usb_set_status(struct cvmx_usb_state *state, struct cvmx_usb_port_status port_status);
+extern int cvmx_usb_open_pipe(struct cvmx_usb_state *state,
+                              enum cvmx_usb_pipe_flags flags,
                               int device_addr, int endpoint_num,
-                              cvmx_usb_speed_t device_speed, int max_packet,
-                              cvmx_usb_transfer_t transfer_type,
-                              cvmx_usb_direction_t transfer_dir, int interval,
+                              enum cvmx_usb_speed device_speed, int max_packet,
+                              enum cvmx_usb_transfer transfer_type,
+                              enum cvmx_usb_direction transfer_dir, int interval,
                               int multi_count, int hub_device_addr,
                               int hub_port);
-
-/**
- * Call to submit a USB Bulk transfer to a pipe.
- *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_bulk(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_bulk(struct cvmx_usb_state *state, int pipe_handle,
                                 uint64_t buffer, int buffer_length,
                                 cvmx_usb_callback_func_t callback,
                                 void *user_data);
-
-/**
- * Call to submit a USB Interrupt transfer to a pipe.
- *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_interrupt(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_interrupt(struct cvmx_usb_state *state, int pipe_handle,
                                      uint64_t buffer, int buffer_length,
                                      cvmx_usb_callback_func_t callback,
                                      void *user_data);
-
-/**
- * Call to submit a USB Control transfer to a pipe.
- *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param control_header
- *                  USB 8 byte control header physical address.
- *                  Note that this is NOT A POINTER, but the
- *                  full 64bit physical address of the buffer.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_control(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_control(struct cvmx_usb_state *state, int pipe_handle,
                                    uint64_t control_header,
                                    uint64_t buffer, int buffer_length,
                                    cvmx_usb_callback_func_t callback,
                                    void *user_data);
 
 /**
- * Flags to pass the cvmx_usb_submit_isochronous() function.
+ * enum cvmx_usb_isochronous_flags - flags to pass the
+ *				     cvmx_usb_submit_isochronous() function.
+ *
+ * @CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT: Do not return an error if a transfer
+ *					    is less than the maximum packet size
+ *					    of the device.
+ * @CVMX_USB_ISOCHRONOUS_FLAGS_ASAP:	    Schedule the transaction as soon as
+ *					    possible.
  */
-typedef enum
-{
-    CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT = 1<<0,  /**< Do not return an error if a transfer is less than the maximum packet size of the device */
-    CVMX_USB_ISOCHRONOUS_FLAGS_ASAP = 1<<1,         /**< Schedule the transaction as soon as possible */
-} cvmx_usb_isochronous_flags_t;
+enum cvmx_usb_isochronous_flags {
+	CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT	= 1 << 0,
+	CVMX_USB_ISOCHRONOUS_FLAGS_ASAP		= 1 << 1,
+};
 
-/**
- * Call to submit a USB Isochronous transfer to a pipe.
- *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param pipe_handle
- *                  Handle to the pipe for the transfer.
- * @param start_frame
- *                  Number of frames into the future to schedule
- *                  this transaction.
- * @param flags     Flags to control the transfer. See
- *                  cvmx_usb_isochronous_flags_t for the flag
- *                  definitions.
- * @param number_packets
- *                  Number of sequential packets to transfer.
- *                  "packets" is a pointer to an array of this
- *                  many packet structures.
- * @param packets   Description of each transfer packet as
- *                  defined by cvmx_usb_iso_packet_t. The array
- *                  pointed to here must stay valid until the
- *                  complete callback is called.
- * @param buffer    Physical address of the data buffer in
- *                  memory. Note that this is NOT A POINTER, but
- *                  the full 64bit physical address of the
- *                  buffer. This may be zero if buffer_length is
- *                  zero.
- * @param buffer_length
- *                  Length of buffer in bytes.
- * @param callback  Function to call when this transaction
- *                  completes. If the return value of this
- *                  function isn't an error, then this function
- *                  is guaranteed to be called when the
- *                  transaction completes. If this parameter is
- *                  NULL, then the generic callback registered
- *                  through cvmx_usb_register_callback is
- *                  called. If both are NULL, then there is no
- *                  way to know when a transaction completes.
- * @param user_data User supplied data returned when the
- *                  callback is called. This is only used if
- *                  callback in not NULL.
- *
- * @return A submitted transaction handle or negative on
- *         failure. Negative values are failure codes from
- *         cvmx_usb_status_t.
- */
-extern int cvmx_usb_submit_isochronous(cvmx_usb_state_t *state, int pipe_handle,
+extern int cvmx_usb_submit_isochronous(struct cvmx_usb_state *state, int pipe_handle,
                                        int start_frame, int flags,
                                        int number_packets,
-                                       cvmx_usb_iso_packet_t packets[],
+                                       struct cvmx_usb_iso_packet packets[],
                                        uint64_t buffer, int buffer_length,
                                        cvmx_usb_callback_func_t callback,
                                        void *user_data);
-
-/**
- * Cancel one outstanding request in a pipe. Canceling a request
- * can fail if the transaction has already completed before cancel
- * is called. Even after a successful cancel call, it may take
- * a frame or two for the cvmx_usb_poll() function to call the
- * associated callback.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe_handle
- *               Pipe handle to cancel requests in.
- * @param submit_handle
- *               Handle to transaction to cancel, returned by the submit function.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_cancel(cvmx_usb_state_t *state,
-                                         int pipe_handle, int submit_handle);
-
-
-/**
- * Cancel all outstanding requests in a pipe. Logically all this
- * does is call cvmx_usb_cancel() in a loop.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe_handle
- *               Pipe handle to cancel requests in.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_cancel_all(cvmx_usb_state_t *state,
-                                             int pipe_handle);
-
-/**
- * Close a pipe created with cvmx_usb_open_pipe().
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- * @param pipe_handle
- *               Pipe handle to close.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t. CVMX_USB_BUSY is returned if the
- *         pipe has outstanding transfers.
- */
-extern cvmx_usb_status_t cvmx_usb_close_pipe(cvmx_usb_state_t *state,
-                                             int pipe_handle);
-
-/**
- * Register a function to be called when various USB events occur.
- *
- * @param state     USB device state populated by
- *                  cvmx_usb_initialize().
- * @param reason    Which event to register for.
- * @param callback  Function to call when the event occurs.
- * @param user_data User data parameter to the function.
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_register_callback(cvmx_usb_state_t *state,
-                                                    cvmx_usb_callback_t reason,
-                                                    cvmx_usb_callback_func_t callback,
-                                                    void *user_data);
-
-/**
- * Get the current USB protocol level frame number. The frame
- * number is always in the range of 0-0x7ff.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- *
- * @return USB frame number
- */
-extern int cvmx_usb_get_frame_number(cvmx_usb_state_t *state);
-
-/**
- * Poll the USB block for status and call all needed callback
- * handlers. This function is meant to be called in the interrupt
- * handler for the USB controller. It can also be called
- * periodically in a loop for non-interrupt based operation.
- *
- * @param state  USB device state populated by
- *               cvmx_usb_initialize().
- *
- * @return CVMX_USB_SUCCESS or a negative error code defined in
- *         cvmx_usb_status_t.
- */
-extern cvmx_usb_status_t cvmx_usb_poll(cvmx_usb_state_t *state);
-
-#ifdef	__cplusplus
-}
-#endif
+extern int cvmx_usb_cancel(struct cvmx_usb_state *state, int pipe_handle,
+			   int submit_handle);
+extern int cvmx_usb_cancel_all(struct cvmx_usb_state *state, int pipe_handle);
+extern int cvmx_usb_close_pipe(struct cvmx_usb_state *state, int pipe_handle);
+extern int cvmx_usb_register_callback(struct cvmx_usb_state *state,
+				      enum cvmx_usb_callback reason,
+				      cvmx_usb_callback_func_t callback,
+				      void *user_data);
+extern int cvmx_usb_get_frame_number(struct cvmx_usb_state *state);
+extern int cvmx_usb_poll(struct cvmx_usb_state *state);
 
 #endif  /* __CVMX_USB_H__ */
diff --git a/drivers/staging/octeon-usb/cvmx-usbcx-defs.h b/drivers/staging/octeon-usb/cvmx-usbcx-defs.h
index 394e846..d349d77 100644
--- a/drivers/staging/octeon-usb/cvmx-usbcx-defs.h
+++ b/drivers/staging/octeon-usb/cvmx-usbcx-defs.h
@@ -140,7 +140,6 @@
 		uint32_t glblintrmsk	: 1;
 	} s;
 };
-typedef union cvmx_usbcx_gahbcfg cvmx_usbcx_gahbcfg_t;
 
 /**
  * cvmx_usbc#_ghwcfg3
@@ -210,7 +209,6 @@
 		uint32_t xfersizewidth				: 4;
 	} s;
 };
-typedef union cvmx_usbcx_ghwcfg3 cvmx_usbcx_ghwcfg3_t;
 
 /**
  * cvmx_usbc#_gintmsk
@@ -299,7 +297,6 @@
 		uint32_t reserved_0_0		: 1;
 	} s;
 };
-typedef union cvmx_usbcx_gintmsk cvmx_usbcx_gintmsk_t;
 
 /**
  * cvmx_usbc#_gintsts
@@ -529,7 +526,6 @@
 		uint32_t curmod		: 1;
 	} s;
 };
-typedef union cvmx_usbcx_gintsts cvmx_usbcx_gintsts_t;
 
 /**
  * cvmx_usbc#_gnptxfsiz
@@ -556,7 +552,6 @@
 		uint32_t nptxfstaddr	: 16;
 	} s;
 };
-typedef union cvmx_usbcx_gnptxfsiz cvmx_usbcx_gnptxfsiz_t;
 
 /**
  * cvmx_usbc#_gnptxsts
@@ -609,7 +604,6 @@
 		uint32_t nptxfspcavail	: 16;
 	} s;
 };
-typedef union cvmx_usbcx_gnptxsts cvmx_usbcx_gnptxsts_t;
 
 /**
  * cvmx_usbc#_grstctl
@@ -737,7 +731,6 @@
 		uint32_t csftrst	: 1;
 	} s;
 };
-typedef union cvmx_usbcx_grstctl cvmx_usbcx_grstctl_t;
 
 /**
  * cvmx_usbc#_grxfsiz
@@ -761,7 +754,6 @@
 		uint32_t rxfdep		: 16;
 	} s;
 };
-typedef union cvmx_usbcx_grxfsiz cvmx_usbcx_grxfsiz_t;
 
 /**
  * cvmx_usbc#_grxstsph
@@ -807,7 +799,6 @@
 		uint32_t chnum		: 4;
 	} s;
 };
-typedef union cvmx_usbcx_grxstsph cvmx_usbcx_grxstsph_t;
 
 /**
  * cvmx_usbc#_gusbcfg
@@ -896,7 +887,6 @@
 		uint32_t toutcal	: 3;
 	} s;
 };
-typedef union cvmx_usbcx_gusbcfg cvmx_usbcx_gusbcfg_t;
 
 /**
  * cvmx_usbc#_haint
@@ -922,7 +912,6 @@
 		uint32_t haint		: 16;
 	} s;
 };
-typedef union cvmx_usbcx_haint cvmx_usbcx_haint_t;
 
 /**
  * cvmx_usbc#_haintmsk
@@ -947,7 +936,6 @@
 		uint32_t haintmsk	: 16;
 	} s;
 };
-typedef union cvmx_usbcx_haintmsk cvmx_usbcx_haintmsk_t;
 
 /**
  * cvmx_usbc#_hcchar#
@@ -1027,7 +1015,6 @@
 		uint32_t mps		: 11;
 	} s;
 };
-typedef union cvmx_usbcx_hccharx cvmx_usbcx_hccharx_t;
 
 /**
  * cvmx_usbc#_hcfg
@@ -1075,7 +1062,6 @@
 		uint32_t fslspclksel	: 2;
 	} s;
 };
-typedef union cvmx_usbcx_hcfg cvmx_usbcx_hcfg_t;
 
 /**
  * cvmx_usbc#_hcint#
@@ -1126,7 +1112,6 @@
 		uint32_t xfercompl	: 1;
 	} s;
 };
-typedef union cvmx_usbcx_hcintx cvmx_usbcx_hcintx_t;
 
 /**
  * cvmx_usbc#_hcintmsk#
@@ -1168,7 +1153,6 @@
 		uint32_t xfercomplmsk	: 1;
 	} s;
 };
-typedef union cvmx_usbcx_hcintmskx cvmx_usbcx_hcintmskx_t;
 
 /**
  * cvmx_usbc#_hcsplt#
@@ -1213,7 +1197,6 @@
 		uint32_t prtaddr	: 7;
 	} s;
 };
-typedef union cvmx_usbcx_hcspltx cvmx_usbcx_hcspltx_t;
 
 /**
  * cvmx_usbc#_hctsiz#
@@ -1257,7 +1240,6 @@
 		uint32_t xfersize	: 19;
 	} s;
 };
-typedef union cvmx_usbcx_hctsizx cvmx_usbcx_hctsizx_t;
 
 /**
  * cvmx_usbc#_hfir
@@ -1293,7 +1275,6 @@
 		uint32_t frint		: 16;
 	} s;
 };
-typedef union cvmx_usbcx_hfir cvmx_usbcx_hfir_t;
 
 /**
  * cvmx_usbc#_hfnum
@@ -1323,7 +1304,6 @@
 		uint32_t frnum	: 16;
 	} s;
 };
-typedef union cvmx_usbcx_hfnum cvmx_usbcx_hfnum_t;
 
 /**
  * cvmx_usbc#_hprt
@@ -1464,7 +1444,6 @@
 		uint32_t prtconnsts	: 1;
 	} s;
 };
-typedef union cvmx_usbcx_hprt cvmx_usbcx_hprt_t;
 
 /**
  * cvmx_usbc#_hptxfsiz
@@ -1489,7 +1468,6 @@
 		uint32_t ptxfstaddr	: 16;
 	} s;
 };
-typedef union cvmx_usbcx_hptxfsiz cvmx_usbcx_hptxfsiz_t;
 
 /**
  * cvmx_usbc#_hptxsts
@@ -1546,6 +1524,5 @@
 		uint32_t ptxfspcavail	: 16;
 	} s;
 };
-typedef union cvmx_usbcx_hptxsts cvmx_usbcx_hptxsts_t;
 
 #endif
diff --git a/drivers/staging/octeon-usb/cvmx-usbnx-defs.h b/drivers/staging/octeon-usb/cvmx-usbnx-defs.h
index 96d7067..e06aafa 100644
--- a/drivers/staging/octeon-usb/cvmx-usbnx-defs.h
+++ b/drivers/staging/octeon-usb/cvmx-usbnx-defs.h
@@ -337,7 +337,6 @@
 	struct cvmx_usbnx_clk_ctl_cn50xx cn52xx;
 	struct cvmx_usbnx_clk_ctl_cn50xx cn56xx;
 };
-typedef union cvmx_usbnx_clk_ctl cvmx_usbnx_clk_ctl_t;
 
 /**
  * cvmx_usbn#_usbp_ctl_status
@@ -882,6 +881,5 @@
 		uint64_t ate_reset		: 1;
 	} cn52xx;
 };
-typedef union cvmx_usbnx_usbp_ctl_status cvmx_usbnx_usbp_ctl_status_t;
 
 #endif
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index d156b60..5dbbd14 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -26,7 +26,7 @@
 
 struct octeon_hcd {
 	spinlock_t lock;
-	cvmx_usb_state_t usb;
+	struct cvmx_usb_state usb;
 	struct tasklet_struct dequeue_tasklet;
 	struct list_head dequeue_list;
 };
@@ -42,7 +42,7 @@
 	return container_of((void *)p, struct usb_hcd, hcd_priv);
 }
 
-static inline struct octeon_hcd *cvmx_usb_to_octeon(cvmx_usb_state_t *p)
+static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p)
 {
 	return container_of(p, struct octeon_hcd, usb);
 }
@@ -58,9 +58,9 @@
 	return IRQ_HANDLED;
 }
 
-static void octeon_usb_port_callback(cvmx_usb_state_t *usb,
-				     cvmx_usb_callback_t reason,
-				     cvmx_usb_complete_t status,
+static void octeon_usb_port_callback(struct cvmx_usb_state *usb,
+				     enum cvmx_usb_callback reason,
+				     enum cvmx_usb_complete status,
 				     int pipe_handle,
 				     int submit_handle,
 				     int bytes_transferred,
@@ -105,9 +105,9 @@
 	return cvmx_usb_get_frame_number(&priv->usb);
 }
 
-static void octeon_usb_urb_complete_callback(cvmx_usb_state_t *usb,
-					     cvmx_usb_callback_t reason,
-					     cvmx_usb_complete_t status,
+static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
+					     enum cvmx_usb_callback reason,
+					     enum cvmx_usb_complete status,
 					     int pipe_handle,
 					     int submit_handle,
 					     int bytes_transferred,
@@ -141,7 +141,8 @@
 		 * The pointer to the private list is stored in the setup_packet
 		 * field.
 		 */
-		cvmx_usb_iso_packet_t *iso_packet = (cvmx_usb_iso_packet_t *) urb->setup_packet;
+		struct cvmx_usb_iso_packet *iso_packet =
+			(struct cvmx_usb_iso_packet *) urb->setup_packet;
 		/* Recalculate the transfer size by adding up each packet */
 		urb->actual_length = 0;
 		for (i = 0; i < urb->number_of_packets; i++) {
@@ -208,7 +209,7 @@
 	int submit_handle = -1;
 	int pipe_handle;
 	unsigned long flags;
-	cvmx_usb_iso_packet_t *iso_packet;
+	struct cvmx_usb_iso_packet *iso_packet;
 	struct usb_host_endpoint *ep = urb->ep;
 
 	urb->status = 0;
@@ -216,8 +217,8 @@
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if (!ep->hcpriv) {
-		cvmx_usb_transfer_t transfer_type;
-		cvmx_usb_speed_t speed;
+		enum cvmx_usb_transfer transfer_type;
+		enum cvmx_usb_speed speed;
 		int split_device = 0;
 		int split_port = 0;
 		switch (usb_pipetype(urb->pipe)) {
@@ -305,7 +306,9 @@
 		 * Allocate a structure to use for our private list of
 		 * isochronous packets.
 		 */
-		iso_packet = kmalloc(urb->number_of_packets * sizeof(cvmx_usb_iso_packet_t), GFP_ATOMIC);
+		iso_packet = kmalloc(urb->number_of_packets *
+				     sizeof(struct cvmx_usb_iso_packet),
+				     GFP_ATOMIC);
 		if (iso_packet) {
 			int i;
 			/* Fill the list with the data from the URB */
@@ -440,7 +443,7 @@
 static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
 	struct octeon_hcd *priv = hcd_to_octeon(hcd);
-	cvmx_usb_port_status_t port_status;
+	struct cvmx_usb_port_status port_status;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -456,7 +459,7 @@
 {
 	struct octeon_hcd *priv = hcd_to_octeon(hcd);
 	struct device *dev = hcd->self.controller;
-	cvmx_usb_port_status_t usb_port_status;
+	struct cvmx_usb_port_status usb_port_status;
 	int port_status;
 	struct usb_hub_descriptor *desc;
 	unsigned long flags;
diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig
index fe40e0b..2ff015d 100644
--- a/drivers/staging/olpc_dcon/Kconfig
+++ b/drivers/staging/olpc_dcon/Kconfig
@@ -4,9 +4,14 @@
 	select I2C
 	select BACKLIGHT_CLASS_DEVICE
 	---help---
-	  Add support for the OLPC XO DCON controller.  This controller is
-	  only available on OLPC platforms.   Unless you have one of these
-	  platforms, you will want to say 'N'.
+	  In order to support very low power operation, the XO laptop uses a
+	  secondary Display CONtroller, or DCON.  This secondary controller
+	  is present in the video pipeline between the primary display
+	  controller (integrate into the processor or chipset) and the LCD
+	  panel.  It allows the main processor/display controller to be
+	  completely powered off while still retaining an image on the display.
+	  This controller is only available on OLPC platforms.  Unless you have
+	  one of these platforms, you will want to say 'N'.
 
 config FB_OLPC_DCON_1
 	bool "OLPC XO-1 DCON support"
diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO
index 35f9cda..61c2e65 100644
--- a/drivers/staging/olpc_dcon/TODO
+++ b/drivers/staging/olpc_dcon/TODO
@@ -1,16 +1,9 @@
 TODO:
-	- checkpatch.pl cleanups
 	- see if vx855 gpio API can be made similar enough to cs5535 so we can
 	  share more code
 	- allow simultaneous XO-1 and XO-1.5 support
-	- console event notifier support
-	- drop global variables, use a proper olpc_dcon_priv struct
-	- audit code for unnecessary code; old unsupported prototype
-	  workarounds, ancient variables (noaa?), etc
-	- verify sane i2c API usage, update to new stuff if necessary
 
 Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
 copy:
-	Andres Salomon <dilinger@queued.net>
-	Chris Ball <cjb@laptop.org>
-	Jon Nettleton <jon.nettleton@gmail.com>
+	Daniel Drake <dsd@laptop.org>
+	Jens Frederich <jfrederich@gmail.com>
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 193e1c6..198595e 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -90,9 +90,10 @@
 
 	/* SDRAM setup/hold time */
 	dcon_write(dcon, 0x3a, 0xc040);
-	dcon_write(dcon, 0x41, 0x0000);
-	dcon_write(dcon, 0x41, 0x0101);
-	dcon_write(dcon, 0x42, 0x0101);
+	dcon_write(dcon, DCON_REG_MEM_OPT_A, 0x0000);  /* clear option bits */
+	dcon_write(dcon, DCON_REG_MEM_OPT_A,
+				MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN);
+	dcon_write(dcon, DCON_REG_MEM_OPT_B, MEM_SOFT_RESET);
 
 	/* Colour swizzle, AA, no passthrough, backlight */
 	if (is_init) {
@@ -121,30 +122,31 @@
 static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down)
 {
 	unsigned long timeout;
+	u8 pm;
 	int x;
 
 power_up:
 	if (is_powered_down) {
-		x = 1;
-		x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
+		pm = 1;
+		x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0);
 		if (x) {
 			pr_warn("unable to force dcon to power up: %d!\n", x);
 			return x;
 		}
-		msleep(10); /* we'll be conservative */
+		usleep_range(10000, 11000);  /* we'll be conservative */
 	}
 
 	pdata->bus_stabilize_wiggle();
 
 	for (x = -1, timeout = 50; timeout && x < 0; timeout--) {
-		msleep(1);
+		usleep_range(1000, 1100);
 		x = dcon_read(dcon, DCON_REG_ID);
 	}
 	if (x < 0) {
 		pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n");
 		BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
-		x = 0;
-		olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
+		pm = 0;
+		olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0);
 		msleep(100);
 		is_powered_down = 1;
 		goto power_up;	/* argh, stupid hardware.. */
@@ -207,8 +209,8 @@
 		return;
 
 	if (sleep) {
-		x = 0;
-		x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
+		u8 pm = 0;
+		x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0);
 		if (x)
 			pr_warn("unable to force dcon to power down: %d!\n", x);
 		else
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h
index 997bded..e2663b1 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.h
+++ b/drivers/staging/olpc_dcon/olpc_dcon.h
@@ -22,15 +22,24 @@
 #define MODE_DEBUG	(1<<14)
 #define MODE_SELFTEST	(1<<15)
 
-#define DCON_REG_HRES		2
-#define DCON_REG_HTOTAL		3
-#define DCON_REG_HSYNC_WIDTH	4
-#define DCON_REG_VRES		5
-#define DCON_REG_VTOTAL		6
-#define DCON_REG_VSYNC_WIDTH	7
-#define DCON_REG_TIMEOUT	8
-#define DCON_REG_SCAN_INT	9
-#define DCON_REG_BRIGHT		10
+#define DCON_REG_HRES		0x2
+#define DCON_REG_HTOTAL		0x3
+#define DCON_REG_HSYNC_WIDTH	0x4
+#define DCON_REG_VRES		0x5
+#define DCON_REG_VTOTAL		0x6
+#define DCON_REG_VSYNC_WIDTH	0x7
+#define DCON_REG_TIMEOUT	0x8
+#define DCON_REG_SCAN_INT	0x9
+#define DCON_REG_BRIGHT		0xa
+#define DCON_REG_MEM_OPT_A	0x41
+#define DCON_REG_MEM_OPT_B	0x42
+
+/* Load Delay Locked Loop (DLL) settings for clock delay */
+#define MEM_DLL_CLOCK_DELAY	(1<<0)
+/* Memory controller power down function */
+#define MEM_POWER_DOWN  	(1<<8)
+/* Memory controller software reset */
+#define MEM_SOFT_RESET		(1<<0)
 
 /* Status values */
 
diff --git a/drivers/staging/ozwpan/Kbuild b/drivers/staging/ozwpan/Makefile
similarity index 92%
rename from drivers/staging/ozwpan/Kbuild
rename to drivers/staging/ozwpan/Makefile
index 1766a26..29529c1 100644
--- a/drivers/staging/ozwpan/Kbuild
+++ b/drivers/staging/ozwpan/Makefile
@@ -2,6 +2,7 @@
 # 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 \
@@ -12,7 +13,4 @@
 	ozeltbuf.o \
 	ozproto.o \
 	ozcdev.o \
-	ozurbparanoia.o \
-	oztrace.o
-
-
+	ozurbparanoia.o
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 374fdc3..6ccb64f 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -11,16 +11,14 @@
 #include <linux/etherdevice.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
 #include "ozprotocol.h"
-#include "oztrace.h"
 #include "ozappif.h"
 #include "ozeltbuf.h"
 #include "ozpd.h"
 #include "ozproto.h"
 #include "ozcdev.h"
-/*------------------------------------------------------------------------------
- */
+
 #define OZ_RD_BUF_SZ	256
 struct oz_cdev {
 	dev_t devnum;
@@ -40,16 +38,17 @@
 	int rd_in;
 	int rd_out;
 };
-/*------------------------------------------------------------------------------
- */
+
 static struct oz_cdev g_cdev;
 static struct class *g_oz_class;
-/*------------------------------------------------------------------------------
+
+/*
  * 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)
@@ -57,37 +56,40 @@
 	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");
+		oz_dbg(ON, "Dealloc serial context\n");
 		kfree(ctx);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static 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);
+	struct oz_cdev *dev = container_of(inode->i_cdev, struct oz_cdev, cdev);
+
+	oz_dbg(ON, "major = %d minor = %d\n", imajor(inode), iminor(inode));
+
 	filp->private_data = dev;
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static int oz_cdev_release(struct inode *inode, struct file *filp)
 {
-	oz_trace("oz_cdev_release()\n");
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count,
@@ -139,7 +141,8 @@
 	oz_pd_put(pd);
 	return count;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static ssize_t oz_cdev_write(struct file *filp, const char __user *buf,
@@ -158,7 +161,9 @@
 		oz_pd_get(pd);
 	spin_unlock_bh(&g_cdev.lock);
 	if (pd == NULL)
-		return -1;
+		return -ENXIO;
+	if (!(pd->state & OZ_PD_S_CONNECTED))
+		return -EAGAIN;
 	eb = &pd->elt_buff;
 	ei = oz_elt_info_alloc(eb);
 	if (ei == NULL) {
@@ -196,7 +201,8 @@
 	oz_pd_put(pd);
 	return count;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static int oz_set_active_pd(const u8 *addr)
@@ -204,6 +210,7 @@
 	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);
@@ -229,13 +236,15 @@
 	}
 	return rc;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static 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)
@@ -251,7 +260,7 @@
 	switch (cmd) {
 	case OZ_IOCTL_GET_PD_LIST: {
 			struct oz_pd_list list;
-			oz_trace("OZ_IOCTL_GET_PD_LIST\n");
+			oz_dbg(ON, "OZ_IOCTL_GET_PD_LIST\n");
 			memset(&list, 0, sizeof(list));
 			list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS);
 			if (copy_to_user((void __user *)arg, &list,
@@ -261,7 +270,7 @@
 		break;
 	case OZ_IOCTL_SET_ACTIVE_PD: {
 			u8 addr[ETH_ALEN];
-			oz_trace("OZ_IOCTL_SET_ACTIVE_PD\n");
+			oz_dbg(ON, "OZ_IOCTL_SET_ACTIVE_PD\n");
 			if (copy_from_user(addr, (void __user *)arg, ETH_ALEN))
 				return -EFAULT;
 			rc = oz_set_active_pd(addr);
@@ -269,7 +278,7 @@
 		break;
 	case OZ_IOCTL_GET_ACTIVE_PD: {
 			u8 addr[ETH_ALEN];
-			oz_trace("OZ_IOCTL_GET_ACTIVE_PD\n");
+			oz_dbg(ON, "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);
@@ -295,14 +304,16 @@
 	}
 	return rc;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static 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);
+
+	oz_dbg(ON, "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);
@@ -317,7 +328,8 @@
 		poll_wait(filp, &dev->rdq, wait);
 	return ret;
 }
-/*------------------------------------------------------------------------------
+
+/*
  */
 static const struct file_operations oz_fops = {
 	.owner =	THIS_MODULE,
@@ -328,19 +340,21 @@
 	.unlocked_ioctl = oz_cdev_ioctl,
 	.poll =		oz_cdev_poll
 };
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 int oz_cdev_register(void)
 {
 	int err;
 	struct device *dev;
+
 	memset(&g_cdev, 0, sizeof(g_cdev));
 	err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan");
 	if (err < 0)
-		goto out3;
-	oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum),
-			MINOR(g_cdev.devnum));
+		return err;
+	oz_dbg(ON, "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;
@@ -348,30 +362,31 @@
 	init_waitqueue_head(&g_cdev.rdq);
 	err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
 	if (err < 0) {
-		oz_trace("Failed to add cdev\n");
-		goto out2;
+		oz_dbg(ON, "Failed to add cdev\n");
+		goto unregister;
 	}
 	g_oz_class = class_create(THIS_MODULE, "ozmo_wpan");
 	if (IS_ERR(g_oz_class)) {
-		oz_trace("Failed to register ozmo_wpan class\n");
+		oz_dbg(ON, "Failed to register ozmo_wpan class\n");
 		err = PTR_ERR(g_oz_class);
-		goto out1;
+		goto delete;
 	}
 	dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan");
 	if (IS_ERR(dev)) {
-		oz_trace("Failed to create sysfs entry for cdev\n");
+		oz_dbg(ON, "Failed to create sysfs entry for cdev\n");
 		err = PTR_ERR(dev);
-		goto out1;
+		goto delete;
 	}
 	return 0;
-out1:
+
+delete:
 	cdev_del(&g_cdev.cdev);
-out2:
+unregister:
 	unregister_chrdev_region(g_cdev.devnum, 1);
-out3:
 	return err;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 int oz_cdev_deregister(void)
@@ -384,7 +399,8 @@
 	}
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 int oz_cdev_init(void)
@@ -392,22 +408,25 @@
 	oz_app_enable(OZ_APPID_SERIAL, 1);
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 void oz_cdev_term(void)
 {
 	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;
+
 	if (resume) {
-		oz_trace("Serial service resumed.\n");
+		oz_dbg(ON, "Serial service resumed\n");
 		return 0;
 	}
 	ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
@@ -429,20 +448,22 @@
 		(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");
+		oz_dbg(ON, "Active PD arrived\n");
 	}
 	spin_unlock(&g_cdev.lock);
-	oz_trace("Serial service started.\n");
+	oz_dbg(ON, "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;
+
 	if (pause) {
-		oz_trace("Serial service paused.\n");
+		oz_dbg(ON, "Serial service paused\n");
 		return;
 	}
 	spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]);
@@ -459,11 +480,12 @@
 	spin_unlock(&g_cdev.lock);
 	if (pd) {
 		oz_pd_put(pd);
-		oz_trace("Active PD departed.\n");
+		oz_dbg(ON, "Active PD departed\n");
 	}
-	oz_trace("Serial service stopped.\n");
+	oz_dbg(ON, "Serial service stopped\n");
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
@@ -478,7 +500,7 @@
 
 	ctx = oz_cdev_claim_ctx(pd);
 	if (ctx == NULL) {
-		oz_trace("Cannot claim serial context.\n");
+		oz_dbg(ON, "Cannot claim serial context\n");
 		return;
 	}
 
@@ -488,8 +510,8 @@
 	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);
+			oz_dbg(ON, "Duplicate element:%02x %02x\n",
+			       app_hdr->elt_seq_num, ctx->rx_seq_num);
 			goto out;
 		}
 	}
@@ -502,7 +524,7 @@
 	if (space < 0)
 		space += OZ_RD_BUF_SZ;
 	if (len > space) {
-		oz_trace("Not enough space:%d %d\n", len, space);
+		oz_dbg(ON, "Not enough space:%d %d\n", len, space);
 		len = space;
 	}
 	ix = ctx->rd_in;
diff --git a/drivers/staging/ozwpan/ozconfig.h b/drivers/staging/ozwpan/ozconfig.h
deleted file mode 100644
index 087c322..0000000
--- a/drivers/staging/ozwpan/ozconfig.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -----------------------------------------------------------------------------
- * 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 */
-
-/* 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/ozdbg.h b/drivers/staging/ozwpan/ozdbg.h
new file mode 100644
index 0000000..b86a2b7
--- /dev/null
+++ b/drivers/staging/ozwpan/ozdbg.h
@@ -0,0 +1,54 @@
+/* -----------------------------------------------------------------------------
+ * Copyright (c) 2011 Ozmo Inc
+ * Released under the GNU General Public License Version 2 (GPLv2).
+ * ---------------------------------------------------------------------------*/
+
+#ifndef _OZDBG_H
+#define _OZDBG_H
+
+#define OZ_WANT_DBG 0
+#define OZ_WANT_VERBOSE_DBG 1
+
+#define OZ_DBG_ON		0x0
+#define OZ_DBG_STREAM		0x1
+#define OZ_DBG_URB		0x2
+#define OZ_DBG_CTRL_DETAIL	0x4
+#define OZ_DBG_HUB		0x8
+#define OZ_DBG_RX_FRAMES	0x10
+#define OZ_DBG_TX_FRAMES	0x20
+
+#define OZ_DEFAULT_DBG_MASK			\
+	(					\
+	/* OZ_DBG_STREAM | */			\
+	/* OZ_DBG_URB | */			\
+	/* OZ_DBG_CTRL_DETAIL | */		\
+	OZ_DBG_HUB |				\
+	/* OZ_DBG_RX_FRAMES | */		\
+	/* OZ_DBG_TX_FRAMES | */		\
+	0)
+
+extern unsigned int oz_dbg_mask;
+
+#define oz_want_dbg(mask)						\
+	((OZ_WANT_DBG && (OZ_DBG_##mask == OZ_DBG_ON)) ||		\
+	 (OZ_WANT_VERBOSE_DBG && (OZ_DBG_##mask & oz_dbg_mask)))
+
+#define oz_dbg(mask, fmt, ...)						\
+do {									\
+	if (oz_want_dbg(mask))						\
+		pr_debug(fmt, ##__VA_ARGS__);				\
+} while (0)
+
+#define oz_cdev_dbg(cdev, mask, fmt, ...)				\
+do {									\
+	if (oz_want_dbg(mask))						\
+		netdev_dbg((cdev)->dev, fmt, ##__VA_ARGS__);		\
+} while (0)
+
+#define oz_pd_dbg(pd, mask, fmt, ...)					\
+do {									\
+	if (oz_want_dbg(mask))						\
+		pr_debug(fmt, ##__VA_ARGS__);				\
+} while (0)
+
+#endif /* _OZDBG_H */
diff --git a/drivers/staging/ozwpan/ozeltbuf.c b/drivers/staging/ozwpan/ozeltbuf.c
index ac90fc7..9b86486 100644
--- a/drivers/staging/ozwpan/ozeltbuf.c
+++ b/drivers/staging/ozwpan/ozeltbuf.c
@@ -6,16 +6,15 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
-#include "ozconfig.h"
+#include "ozdbg.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)
@@ -28,13 +27,15 @@
 	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;
@@ -59,12 +60,14 @@
 	}
 	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 = NULL;
+	struct oz_elt_info *ei;
+
 	spin_lock_bh(&buf->lock);
 	if (buf->free_elts && buf->elt_pool) {
 		ei = container_of(buf->elt_pool, struct oz_elt_info, link);
@@ -72,8 +75,8 @@
 		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);
+			oz_dbg(ON, "%s: ei with bad magic: 0x%x\n",
+			       __func__, ei->magic);
 		}
 	} else {
 		spin_unlock_bh(&buf->lock);
@@ -91,7 +94,8 @@
 	}
 	return ei;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Precondition: oz_elt_buf.lock must be held.
  * Context: softirq or process
  */
@@ -104,18 +108,19 @@
 			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);
+			oz_dbg(ON, "%s: bad magic ei: %p magic: 0x%x\n",
+			       __func__, 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) {
@@ -126,13 +131,12 @@
 	}
 	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);
+	oz_dbg(ON, "%s: (0x%x)\n", __func__, id);
 
 	st = kzalloc(sizeof(struct oz_elt_stream), GFP_ATOMIC | __GFP_ZERO);
 	if (st == NULL)
@@ -146,13 +150,13 @@
 	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 = NULL;
-	oz_trace("oz_elt_stream_delete(0x%x)\n", id);
+
+	oz_dbg(ON, "%s: (0x%x)\n", __func__, id);
 	spin_lock_bh(&buf->lock);
 	e = buf->stream_list.next;
 	while (e != &buf->stream_list) {
@@ -175,9 +179,8 @@
 		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_dbg(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);
 	}
@@ -185,22 +188,21 @@
 	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");
+		oz_dbg(ON, "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.
@@ -210,6 +212,7 @@
 {
 	struct oz_elt_stream *st = NULL;
 	struct list_head *e;
+
 	if (id) {
 		list_for_each(e, &buf->stream_list) {
 			st = container_of(e, struct oz_elt_stream, link);
@@ -242,8 +245,7 @@
 		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);
+		oz_dbg(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.
 		 */
@@ -263,8 +265,7 @@
 		&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)
 {
@@ -272,6 +273,7 @@
 	struct list_head *e;
 	struct list_head *el;
 	struct oz_elt_info *ei;
+
 	spin_lock_bh(&buf->lock);
 	if (isoc)
 		el = &buf->isoc_list;
@@ -293,9 +295,8 @@
 			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_dbg(STREAM, "Stream down: %d %d\n",
+				       ei->stream->buf_count, ei->length);
 				oz_elt_stream_put(ei->stream);
 				ei->stream = NULL;
 			}
@@ -309,18 +310,17 @@
 	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 = NULL;
 	struct list_head *e;
+
 	spin_lock_bh(&buf->lock);
 	while (buf->free_elts > buf->max_free_elts) {
 		e = buf->elt_pool;
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index d68d63a..d9c43c3 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -26,31 +26,42 @@
  */
 #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 "ozdbg.h"
 #include "ozusbif.h"
-#include "oztrace.h"
 #include "ozurbparanoia.h"
 #include "ozhcd.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
+#define OZ_IN_BUFFERING_UNITS	100
+
 /* 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)
-/*------------------------------------------------------------------------------
+
+/*EP0 timeout before ep0 request is again added to TX queue. (13*8 = 98mSec)
+ */
+#define EP0_TIMEOUT_COUNTER 13
+
+/* Debounce time HCD driver should wait before unregistering.
+ */
+#define OZ_HUB_DEBOUNCE_TIMEOUT 1500
+
+/*
  * 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.
@@ -61,16 +72,18 @@
 	struct oz_port *port;
 	u8 req_id;
 	u8 ep_num;
-	unsigned long submit_jiffies;
+	unsigned submit_counter;
 };
 
 /* Holds state information about a USB endpoint.
  */
+#define OZ_EP_BUFFER_SIZE_ISOC  (1024 * 24)
+#define OZ_EP_BUFFER_SIZE_INT   512
 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;
+	struct timespec timestamp;
 	int credit;
 	int credit_ceiling;
 	u8 ep_num;
@@ -83,6 +96,7 @@
 	unsigned flags;
 	int start_frame;
 };
+
 /* Bits in the flags field. */
 #define OZ_F_EP_BUFFERING	0x1
 #define OZ_F_EP_HAVE_STREAM	0x2
@@ -113,6 +127,7 @@
 	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
@@ -130,11 +145,12 @@
 	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);
@@ -174,7 +190,8 @@
 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;
@@ -188,6 +205,7 @@
 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 atomic_t g_usb_frame_number = ATOMIC_INIT(0);
 static const struct hc_driver g_oz_hc_drv = {
 	.description =		g_hcd_name,
 	.product_desc =		"Ozmo Devices WPAN",
@@ -218,7 +236,8 @@
 		.owner = THIS_MODULE,
 	},
 };
-/*------------------------------------------------------------------------------
+
+/*
  * Gets our private context area (which is of type struct oz_hcd) from the
  * usb_hcd structure.
  * Context: any
@@ -227,7 +246,8 @@
 {
 	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.
@@ -236,13 +256,15 @@
 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
  */
@@ -250,6 +272,7 @@
 {
 	struct oz_urb_link *urbl = NULL;
 	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);
@@ -261,7 +284,8 @@
 		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
@@ -281,7 +305,8 @@
 		kfree(urbl);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Deallocates all the urb links in the pool.
  * Context: unknown
  */
@@ -289,6 +314,7 @@
 {
 	struct list_head *e;
 	unsigned long irq_state;
+
 	spin_lock_irqsave(&g_link_lock, irq_state);
 	e = g_link_pool;
 	g_link_pool = NULL;
@@ -301,12 +327,13 @@
 		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)
+static struct oz_endpoint *oz_ep_alloc(int buffer_size, gfp_t mem_flags)
 {
 	struct oz_endpoint *ep =
 		kzalloc(sizeof(struct oz_endpoint)+buffer_size, mem_flags);
@@ -321,7 +348,8 @@
 	}
 	return ep;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Pre-condition: Must be called with g_tasklet_lock held and interrupts
  * disabled.
  * Context: softirq or process
@@ -330,6 +358,7 @@
 {
 	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) {
@@ -339,17 +368,19 @@
 	}
 	return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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)
+		int status)
 {
 	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
 	unsigned long irq_state;
-	struct oz_urb_link *cancel_urbl = NULL;
+	struct oz_urb_link *cancel_urbl;
+
 	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
@@ -371,15 +402,9 @@
 	 */
 	spin_unlock(&g_tasklet_lock);
 	if (oz_forget_urb(urb)) {
-		oz_trace("OZWPAN: ERROR Unknown URB %p\n", urb);
+		oz_dbg(ON, "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;
 		usb_hcd_giveback_urb(hcd, urb, status);
 	}
 	spin_lock(&g_tasklet_lock);
@@ -387,14 +412,14 @@
 	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;
@@ -409,19 +434,20 @@
 		list_splice_tail(&list, &ozhcd->orphanage);
 		spin_unlock_bh(&ozhcd->hcd_lock);
 	}
-	oz_trace("Freeing endpoint memory\n");
+	oz_dbg(ON, "Freeing endpoint memory\n");
 	kfree(ep);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static void oz_complete_buffered_urb(struct oz_port *port,
 			struct oz_endpoint *ep,
 			struct urb *urb)
 {
-	u8 data_len, available_space, copy_len;
+	int data_len, available_space, copy_len;
 
-	memcpy(&data_len, &ep->buffer[ep->out_ix], sizeof(u8));
+	data_len = ep->buffer[ep->out_ix];
 	if (data_len <= urb->transfer_buffer_length)
 		available_space = data_len;
 	else
@@ -446,28 +472,29 @@
 		ep->out_ix = 0;
 
 	ep->buffered_units--;
-	oz_trace("Trying to give back buffered frame of size=%d\n",
-						available_space);
-	oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+	oz_dbg(ON, "Trying to give back buffered frame of size=%d\n",
+	       available_space);
+	oz_complete_urb(port->ozhcd->hcd, urb, 0);
 }
 
-/*------------------------------------------------------------------------------
+/*
  * 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;
+	struct oz_endpoint *ep = NULL;
 	int err = 0;
+
 	if (ep_addr >= OZ_NB_ENDPOINTS) {
-		oz_trace("Invalid endpoint number in oz_enqueue_ep_urb().\n");
+		oz_dbg(ON, "%s: Invalid endpoint number\n", __func__);
 		return -EINVAL;
 	}
 	urbl = oz_alloc_urb_link();
 	if (!urbl)
 		return -ENOMEM;
-	urbl->submit_jiffies = jiffies;
+	urbl->submit_counter = 0;
 	urbl->urb = urb;
 	urbl->req_id = req_id;
 	urbl->ep_num = ep_addr;
@@ -480,15 +507,20 @@
 	 */
 	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_dbg(ON, "urb %p unlinked so complete immediately\n", urb);
+		oz_complete_urb(port->ozhcd->hcd, urb, 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) {
+		err = -ENOMEM;
+		goto out;
+	}
 
 	/*For interrupt endpoint check for buffered data
 	* & complete urb
@@ -501,21 +533,23 @@
 		return 0;
 	}
 
-	if (ep && port->hpd) {
+	if (port->hpd) {
 		list_add_tail(&urbl->link, &ep->urb_list);
 		if (!in_dir && ep_addr && (ep->credit < 0)) {
-			ep->last_jiffies = jiffies;
+			getrawmonotonic(&ep->timestamp);
 			ep->credit = 0;
 		}
 	} else {
 		err = -EPIPE;
 	}
+out:
 	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
@@ -525,6 +559,7 @@
 {
 	struct oz_urb_link *urbl = NULL;
 	struct oz_endpoint *ep;
+
 	spin_lock_bh(&port->ozhcd->hcd_lock);
 	if (in_dir)
 		ep = port->in_ep[ep_addr];
@@ -546,7 +581,8 @@
 		oz_free_urb_link(urbl);
 	return urbl ? 0 : -EIDRM;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Finds an urb given its request id.
  * Context: softirq
  */
@@ -555,7 +591,7 @@
 {
 	struct oz_hcd *ozhcd = port->ozhcd;
 	struct urb *urb = NULL;
-	struct oz_urb_link *urbl = NULL;
+	struct oz_urb_link *urbl;
 	struct oz_endpoint *ep;
 
 	spin_lock_bh(&ozhcd->hcd_lock);
@@ -578,7 +614,8 @@
 		oz_free_urb_link(urbl);
 	return urb;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Pre-condition: Port lock must be held.
  * Context: softirq
  */
@@ -592,12 +629,14 @@
 	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)
@@ -605,7 +644,8 @@
 	spin_unlock_bh(&g_hcdlock);
 	return ozhcd;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static inline void oz_hcd_put(struct oz_hcd *ozhcd)
@@ -613,7 +653,8 @@
 	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.
@@ -625,75 +666,74 @@
  * probably very rare indeed.
  * Context: softirq
  */
-void *oz_hcd_pd_arrived(void *hpd)
+struct oz_port *oz_hcd_pd_arrived(void *hpd)
 {
 	int i;
-	void *hport = NULL;
-	struct oz_hcd *ozhcd = NULL;
+	struct oz_port *hport;
+	struct oz_hcd *ozhcd;
 	struct oz_endpoint *ep;
-	oz_trace("oz_hcd_pd_arrived()\n");
+
 	ozhcd = oz_hcd_claim();
-	if (ozhcd == NULL)
+	if (!ozhcd)
 		return NULL;
 	/* Allocate an endpoint object in advance (before holding hcd lock) to
 	 * use for out endpoint 0.
 	 */
-	ep = oz_ep_alloc(GFP_ATOMIC, 0);
+	ep = oz_ep_alloc(0, GFP_ATOMIC);
+	if (!ep)
+		goto err_put;
+
 	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;
-	}
+	if (ozhcd->conn_port >= 0)
+		goto err_unlock;
+
 	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) {
+		if (!(port->flags & (OZ_PORT_F_PRESENT | OZ_PORT_F_CHANGED))) {
 			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 = NULL;
-		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(NULL, ep);
+	if (i == OZ_NB_PORTS)
+		goto err_unlock;
+
+	ozhcd->conn_port = i;
+	hport = &ozhcd->ports[i];
+	hport->out_ep[0] = ep;
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	if (ozhcd->flags & OZ_HDC_F_SUSPENDED)
+		usb_hcd_resume_root_hub(ozhcd->hcd);
+	usb_hcd_poll_rh_status(ozhcd->hcd);
 	oz_hcd_put(ozhcd);
+
 	return hport;
+
+err_unlock:
+	spin_unlock_bh(&ozhcd->hcd_lock);
+	oz_ep_free(NULL, ep);
+err_put:
+	oz_hcd_put(ozhcd);
+	return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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)
+void oz_hcd_pd_departed(struct oz_port *port)
 {
-	struct oz_port *port = (struct oz_port *)hport;
 	struct oz_hcd *ozhcd;
 	void *hpd;
 	struct oz_endpoint *ep = NULL;
 
-	oz_trace("oz_hcd_pd_departed()\n");
 	if (port == NULL) {
-		oz_trace("oz_hcd_pd_departed() port = 0\n");
+		oz_dbg(ON, "%s: port = 0\n", __func__);
 		return;
 	}
 	ozhcd = port->ozhcd;
@@ -704,7 +744,7 @@
 	spin_lock_bh(&ozhcd->hcd_lock);
 	if ((ozhcd->conn_port >= 0) &&
 		(port == &ozhcd->ports[ozhcd->conn_port])) {
-		oz_trace("Clearing conn_port\n");
+		oz_dbg(ON, "Clearing conn_port\n");
 		ozhcd->conn_port = -1;
 	}
 	spin_lock(&port->port_lock);
@@ -717,9 +757,10 @@
 	hpd = port->hpd;
 	port->hpd = NULL;
 	port->bus_addr = 0xff;
+	port->config_num = 0;
 	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_CONNECTION | USB_PORT_STAT_ENABLE);
 	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.
@@ -734,7 +775,8 @@
 	usb_hcd_poll_rh_status(ozhcd->hcd);
 	oz_usb_put(hpd);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 void oz_hcd_pd_reset(void *hpd, void *hport)
@@ -743,7 +785,8 @@
 	 */
 	struct oz_port *port = (struct oz_port *)hport;
 	struct oz_hcd *ozhcd = port->ozhcd;
-	oz_trace("PD Reset\n");
+
+	oz_dbg(ON, "PD Reset\n");
 	spin_lock_bh(&port->port_lock);
 	port->flags |= OZ_PORT_F_CHANGED;
 	port->status |= USB_PORT_STAT_RESET;
@@ -752,7 +795,8 @@
 	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, const u8 *desc,
@@ -762,8 +806,8 @@
 	struct urb *urb;
 	int err = 0;
 
-	oz_trace("oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n",
-			length, offset, total_size);
+	oz_dbg(ON, "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;
@@ -795,54 +839,52 @@
 		}
 	}
 	urb->actual_length = total_size;
-	oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+	oz_complete_urb(port->ozhcd->hcd, urb, 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");
+		oz_dbg(ON, "USB_REQ_GET_STATUS - cnf\n");
 		break;
 	case USB_REQ_CLEAR_FEATURE:
-		oz_trace("USB_REQ_CLEAR_FEATURE - cnf\n");
+		oz_dbg(ON, "USB_REQ_CLEAR_FEATURE - cnf\n");
 		break;
 	case USB_REQ_SET_FEATURE:
-		oz_trace("USB_REQ_SET_FEATURE - cnf\n");
+		oz_dbg(ON, "USB_REQ_SET_FEATURE - cnf\n");
 		break;
 	case USB_REQ_SET_ADDRESS:
-		oz_trace("USB_REQ_SET_ADDRESS - cnf\n");
+		oz_dbg(ON, "USB_REQ_SET_ADDRESS - cnf\n");
 		break;
 	case USB_REQ_GET_DESCRIPTOR:
-		oz_trace("USB_REQ_GET_DESCRIPTOR - cnf\n");
+		oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n");
 		break;
 	case USB_REQ_SET_DESCRIPTOR:
-		oz_trace("USB_REQ_SET_DESCRIPTOR - cnf\n");
+		oz_dbg(ON, "USB_REQ_SET_DESCRIPTOR - cnf\n");
 		break;
 	case USB_REQ_GET_CONFIGURATION:
-		oz_trace("USB_REQ_GET_CONFIGURATION - cnf\n");
+		oz_dbg(ON, "USB_REQ_GET_CONFIGURATION - cnf\n");
 		break;
 	case USB_REQ_SET_CONFIGURATION:
-		oz_trace("USB_REQ_SET_CONFIGURATION - cnf\n");
+		oz_dbg(ON, "USB_REQ_SET_CONFIGURATION - cnf\n");
 		break;
 	case USB_REQ_GET_INTERFACE:
-		oz_trace("USB_REQ_GET_INTERFACE - cnf\n");
+		oz_dbg(ON, "USB_REQ_GET_INTERFACE - cnf\n");
 		break;
 	case USB_REQ_SET_INTERFACE:
-		oz_trace("USB_REQ_SET_INTERFACE - cnf\n");
+		oz_dbg(ON, "USB_REQ_SET_INTERFACE - cnf\n");
 		break;
 	case USB_REQ_SYNCH_FRAME:
-		oz_trace("USB_REQ_SYNCH_FRAME - cnf\n");
+		oz_dbg(ON, "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,
@@ -850,6 +892,7 @@
 {
 	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);
@@ -860,9 +903,10 @@
 	} else {
 		rc = -ENOMEM;
 	}
-	oz_complete_urb(hcd, urb, rc, 0);
+	oz_complete_urb(hcd, urb, rc);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb,
@@ -870,10 +914,11 @@
 {
 	struct usb_hcd *hcd = port->ozhcd->hcd;
 	int rc = 0;
-	if (rcode == 0) {
+
+	if ((rcode == 0) && (port->config_num > 0)) {
 		struct usb_host_config *config;
 		struct usb_host_interface *intf;
-		oz_trace("Set interface %d alt %d\n", if_num, alt);
+		oz_dbg(ON, "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];
@@ -885,9 +930,10 @@
 	} else {
 		rc = -ENOMEM;
 	}
-	oz_complete_urb(hcd, urb, rc, 0);
+	oz_complete_urb(hcd, urb, rc);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data,
@@ -900,10 +946,10 @@
 	unsigned windex;
 	unsigned wvalue;
 
-	oz_trace("oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len);
+	oz_dbg(ON, "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");
+		oz_dbg(ON, "URB not found\n");
 		return;
 	}
 	setup = (struct usb_ctrlrequest *)urb->setup_packet;
@@ -922,12 +968,12 @@
 				(u8)windex, (u8)wvalue);
 			break;
 		default:
-			oz_complete_urb(hcd, urb, 0, 0);
+			oz_complete_urb(hcd, urb, 0);
 		}
 
 	} else {
 		int copy_len;
-		oz_trace("VENDOR-CLASS - cnf\n");
+		oz_dbg(ON, "VENDOR-CLASS - cnf\n");
 		if (data_len) {
 			if (data_len <= urb->transfer_buffer_length)
 				copy_len = data_len;
@@ -936,10 +982,11 @@
 			memcpy(urb->transfer_buffer, data, copy_len);
 			urb->actual_length = copy_len;
 		}
-		oz_complete_urb(hcd, urb, 0, 0);
+		oz_complete_urb(hcd, urb, 0);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static int oz_hcd_buffer_data(struct oz_endpoint *ep, const u8 *data,
@@ -947,13 +994,14 @@
 {
 	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");
+		oz_dbg(ON, "Buffer full\n");
 		return -1;
 	}
 	ep->buffer[ep->in_ix] = (u8)data_len;
@@ -975,7 +1023,8 @@
 	ep->buffered_units++;
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len)
@@ -983,6 +1032,7 @@
 	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 == NULL)
@@ -1006,10 +1056,10 @@
 				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);
+			oz_complete_urb(port->ozhcd->hcd, urb, 0);
 			return;
 		} else {
-			oz_trace("buffering frame as URB is not available\n");
+			oz_dbg(ON, "buffering frame as URB is not available\n");
 			oz_hcd_buffer_data(ep, data, data_len);
 		}
 		break;
@@ -1020,14 +1070,16 @@
 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());
+	return atomic_inc_return(&g_usb_frame_number);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_hcd_heartbeat(void *hport)
@@ -1041,7 +1093,9 @@
 	struct list_head *n;
 	struct urb *urb;
 	struct oz_endpoint *ep;
-	unsigned long now = jiffies;
+	struct timespec ts, delta;
+
+	getrawmonotonic(&ts);
 	INIT_LIST_HEAD(&xfr_list);
 	/* Check the OUT isoc endpoints to see if any URB data can be sent.
 	 */
@@ -1050,10 +1104,11 @@
 		ep = ep_from_link(e);
 		if (ep->credit < 0)
 			continue;
-		ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
+		delta = timespec_sub(ts, ep->timestamp);
+		ep->credit += div_u64(timespec_to_ns(&delta), NSEC_PER_MSEC);
 		if (ep->credit > ep->credit_ceiling)
 			ep->credit = ep->credit_ceiling;
-		ep->last_jiffies = now;
+		ep->timestamp = ts;
 		while (ep->credit && !list_empty(&ep->urb_list)) {
 			urbl = list_first_entry(&ep->urb_list,
 				struct oz_urb_link, link);
@@ -1061,6 +1116,8 @@
 			if ((ep->credit + 1) < urb->number_of_packets)
 				break;
 			ep->credit -= urb->number_of_packets;
+			if (ep->credit < 0)
+				ep->credit = 0;
 			list_move_tail(&urbl->link, &xfr_list);
 		}
 	}
@@ -1068,16 +1125,14 @@
 	/* 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);
+		oz_complete_urb(port->ozhcd->hcd, urb, 0);
 	}
 	/* Check the IN isoc endpoints to see if any URBs can be completed.
 	 */
@@ -1088,13 +1143,14 @@
 			if (ep->buffered_units >= OZ_IN_BUFFERING_UNITS) {
 				ep->flags &= ~OZ_F_EP_BUFFERING;
 				ep->credit = 0;
-				ep->last_jiffies = now;
+				ep->timestamp = ts;
 				ep->start_frame = 0;
 			}
 			continue;
 		}
-		ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
-		ep->last_jiffies = now;
+		delta = timespec_sub(ts, ep->timestamp);
+		ep->credit += div_u64(timespec_to_ns(&delta), NSEC_PER_MSEC);
+		ep->timestamp = ts;
 		while (!list_empty(&ep->urb_list)) {
 			struct oz_urb_link *urbl =
 				list_first_entry(&ep->urb_list,
@@ -1103,7 +1159,7 @@
 			int len = 0;
 			int copy_len;
 			int i;
-			if ((ep->credit + 1) < urb->number_of_packets)
+			if (ep->credit  < urb->number_of_packets)
 				break;
 			if (ep->buffered_units < urb->number_of_packets)
 				break;
@@ -1149,7 +1205,7 @@
 		urb = urbl->urb;
 		list_del_init(e);
 		oz_free_urb_link(urbl);
-		oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+		oz_complete_urb(port->ozhcd->hcd, urb, 0);
 	}
 	/* Check if there are any ep0 requests that have timed out.
 	 * If so resent to PD.
@@ -1161,11 +1217,12 @@
 		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;
+			if (urbl->submit_counter > EP0_TIMEOUT_COUNTER) {
+				oz_dbg(ON, "Request 0x%p timeout\n", urbl->urb);
 				list_move_tail(e, &xfr_list);
+				urbl->submit_counter = 0;
+			} else {
+				urbl->submit_counter++;
 			}
 		}
 		if (!list_empty(&ep->urb_list))
@@ -1175,14 +1232,15 @@
 		while (e != &xfr_list) {
 			urbl = container_of(e, struct oz_urb_link, link);
 			e = e->next;
-			oz_trace("Resending request to PD.\n");
+			oz_dbg(ON, "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,
@@ -1193,7 +1251,10 @@
 	int i;
 	int if_ix = intf->desc.bInterfaceNumber;
 	int request_heartbeat = 0;
-	oz_trace("interface[%d] = %p\n", if_ix, intf);
+
+	oz_dbg(ON, "interface[%d] = %p\n", if_ix, intf);
+	if (if_ix >= port->num_iface || port->iface == NULL)
+		return -ENOMEM;
 	for (i = 0; i < intf->desc.bNumEndpoints; i++) {
 		struct usb_host_endpoint *hep = &intf->endpoint[i];
 		u8 ep_addr = hep->desc.bEndpointAddress;
@@ -1201,20 +1262,20 @@
 		struct oz_endpoint *ep;
 		int buffer_size = 0;
 
-		oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
+		oz_dbg(ON, "%d bEndpointAddress = %x\n", i, ep_addr);
 		if (ep_addr & USB_ENDPOINT_DIR_MASK) {
 			switch (hep->desc.bmAttributes &
 						USB_ENDPOINT_XFERTYPE_MASK) {
 			case USB_ENDPOINT_XFER_ISOC:
-				buffer_size = 24*1024;
+				buffer_size = OZ_EP_BUFFER_SIZE_ISOC;
 				break;
 			case USB_ENDPOINT_XFER_INT:
-				buffer_size = 128;
+				buffer_size = OZ_EP_BUFFER_SIZE_INT;
 				break;
 			}
 		}
 
-		ep = oz_ep_alloc(mem_flags, buffer_size);
+		ep = oz_ep_alloc(buffer_size, mem_flags);
 		if (!ep) {
 			oz_clean_endpoints_for_interface(hcd, port, if_ix);
 			return -ENOMEM;
@@ -1223,8 +1284,8 @@
 		ep->ep_num = ep_num;
 		if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK)
 			== USB_ENDPOINT_XFER_ISOC) {
-			oz_trace("wMaxPacketSize = %d\n",
-				usb_endpoint_maxp(&hep->desc));
+			oz_dbg(ON, "wMaxPacketSize = %d\n",
+			       usb_endpoint_maxp(&hep->desc));
 			ep->credit_ceiling = 200;
 			if (ep_addr & USB_ENDPOINT_DIR_MASK) {
 				ep->flags |= OZ_F_EP_BUFFERING;
@@ -1259,7 +1320,8 @@
 	}
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd,
@@ -1270,7 +1332,7 @@
 	int i;
 	struct list_head ep_list;
 
-	oz_trace("Deleting endpoints for interface %d\n", if_ix);
+	oz_dbg(ON, "Deleting endpoints for interface %d\n", if_ix);
 	if (if_ix >= port->num_iface)
 		return;
 	INIT_LIST_HEAD(&ep_list);
@@ -1304,7 +1366,8 @@
 		oz_ep_free(port, ep);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static int oz_build_endpoints_for_config(struct usb_hcd *hcd,
@@ -1314,6 +1377,7 @@
 	struct oz_hcd *ozhcd = port->ozhcd;
 	int i;
 	int num_iface = config->desc.bNumInterfaces;
+
 	if (num_iface) {
 		struct oz_interface *iface;
 
@@ -1338,7 +1402,8 @@
 	oz_clean_endpoints_for_config(hcd, port);
 	return -1;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static void oz_clean_endpoints_for_config(struct usb_hcd *hcd,
@@ -1346,25 +1411,28 @@
 {
 	struct oz_hcd *ozhcd = port->ozhcd;
 	int i;
-	oz_trace("Deleting endpoints for configuration.\n");
+
+	oz_dbg(ON, "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");
+		oz_dbg(ON, "Freeing interfaces object\n");
 		kfree(port->iface);
 		port->iface = NULL;
 	}
 	port->num_iface = 0;
 	spin_unlock_bh(&ozhcd->hcd_lock);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: tasklet
  */
 static void *oz_claim_hpd(struct oz_port *port)
 {
-	void *hpd = NULL;
+	void *hpd;
 	struct oz_hcd *ozhcd = port->ozhcd;
+
 	spin_lock_bh(&ozhcd->hcd_lock);
 	hpd = port->hpd;
 	if (hpd)
@@ -1372,7 +1440,8 @@
 	spin_unlock_bh(&ozhcd->hcd_lock);
 	return hpd;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: tasklet
  */
 static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
@@ -1382,7 +1451,7 @@
 	unsigned windex;
 	unsigned wvalue;
 	unsigned wlength;
-	void *hpd = NULL;
+	void *hpd;
 	u8 req_id;
 	int rc = 0;
 	unsigned complete = 0;
@@ -1390,7 +1459,7 @@
 	int port_ix = -1;
 	struct oz_port *port = NULL;
 
-	oz_trace2(OZ_TRACE_URB, "%lu: oz_process_ep0_urb(%p)\n", jiffies, urb);
+	oz_dbg(URB, "[%s]:(%p)\n", __func__, urb);
 	port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
 	if (port_ix < 0) {
 		rc = -EPIPE;
@@ -1399,8 +1468,8 @@
 	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);
+		oz_dbg(ON, "Refusing URB port_ix = %d devnum = %d\n",
+		       port_ix, urb->dev->devnum);
 		rc = -EPIPE;
 		goto out;
 	}
@@ -1411,17 +1480,16 @@
 	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);
+	oz_dbg(CTRL_DETAIL, "bRequestType = %x\n", setup->bRequestType);
+	oz_dbg(CTRL_DETAIL, "bRequest = %x\n", setup->bRequest);
+	oz_dbg(CTRL_DETAIL, "wValue = %x\n", wvalue);
+	oz_dbg(CTRL_DETAIL, "wIndex = %x\n", windex);
+	oz_dbg(CTRL_DETAIL, "wLength = %x\n", wlength);
 
 	req_id = port->next_req_id++;
 	hpd = oz_claim_hpd(port);
 	if (hpd == NULL) {
-		oz_trace("Cannot claim port\n");
+		oz_dbg(ON, "Cannot claim port\n");
 		rc = -EPIPE;
 		goto out;
 	}
@@ -1431,30 +1499,31 @@
 		 */
 		switch (setup->bRequest) {
 		case USB_REQ_GET_DESCRIPTOR:
-			oz_trace("USB_REQ_GET_DESCRIPTOR - req\n");
+			oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - req\n");
 			break;
 		case USB_REQ_SET_ADDRESS:
-			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));
+			oz_dbg(ON, "USB_REQ_SET_ADDRESS - req\n");
+			oz_dbg(ON, "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");
+				oz_dbg(ON, "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");
+			oz_dbg(ON, "USB_REQ_SET_CONFIGURATION - req\n");
 			break;
 		case USB_REQ_GET_CONFIGURATION:
 			/* We short circuit this case and reply directly since
 			 * we have the selected configuration number cached.
 			 */
-			oz_trace("USB_REQ_GET_CONFIGURATION - reply now\n");
+			oz_dbg(ON, "USB_REQ_GET_CONFIGURATION - reply now\n");
 			if (urb->transfer_buffer_length >= 1) {
 				urb->actual_length = 1;
 				*((u8 *)urb->transfer_buffer) =
@@ -1468,20 +1537,20 @@
 			/* We short circuit this case and reply directly since
 			 * we have the selected interface alternative cached.
 			 */
-			oz_trace("USB_REQ_GET_INTERFACE - reply now\n");
+			oz_dbg(ON, "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);
+				oz_dbg(ON, "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");
+			oz_dbg(ON, "USB_REQ_SET_INTERFACE - req\n");
 			break;
 		}
 	}
@@ -1512,13 +1581,14 @@
 	oz_usb_put(hpd);
 out:
 	if (rc || complete) {
-		oz_trace("Completing request locally\n");
-		oz_complete_urb(ozhcd->hcd, urb, rc, 0);
+		oz_dbg(ON, "Completing request locally\n");
+		oz_complete_urb(ozhcd->hcd, urb, rc);
 	} else {
 		oz_usb_request_heartbeat(port->hpd);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: tasklet
  */
 static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb)
@@ -1526,6 +1596,7 @@
 	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.
@@ -1551,7 +1622,8 @@
 	}
 	return rc;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: tasklet
  */
 static void oz_urb_process_tasklet(unsigned long unused)
@@ -1560,6 +1632,7 @@
 	struct urb *urb;
 	struct oz_hcd *ozhcd = oz_hcd_claim();
 	int rc = 0;
+
 	if (ozhcd == NULL)
 		return;
 	/* This is called from a tasklet so is in softirq context but the urb
@@ -1577,13 +1650,14 @@
 		oz_free_urb_link(urbl);
 		rc = oz_urb_process(ozhcd, urb);
 		if (rc)
-			oz_complete_urb(ozhcd->hcd, urb, rc, 0);
+			oz_complete_urb(ozhcd->hcd, urb, rc);
 		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
@@ -1599,13 +1673,14 @@
 	struct oz_hcd *ozhcd;
 	unsigned long irq_state;
 	u8 ix;
+
 	if (port == NULL) {
-		oz_trace("ERRORERROR: oz_urb_cancel(%p) port is null\n", urb);
+		oz_dbg(ON, "%s: ERROR: (%p) port is null\n", __func__, urb);
 		return;
 	}
 	ozhcd = port->ozhcd;
 	if (ozhcd == NULL) {
-		oz_trace("ERRORERROR: oz_urb_cancel(%p) ozhcd is null\n", urb);
+		oz_dbg(ON, "%s; ERROR: (%p) ozhcd is null\n", __func__, urb);
 		return;
 	}
 
@@ -1630,7 +1705,7 @@
 		urbl = container_of(e, struct oz_urb_link, link);
 		if (urbl->urb == urb) {
 			list_del(e);
-			oz_trace("Found urb in orphanage\n");
+			oz_dbg(ON, "Found urb in orphanage\n");
 			goto out;
 		}
 	}
@@ -1646,10 +1721,11 @@
 	if (urbl) {
 		urb->actual_length = 0;
 		oz_free_urb_link(urbl);
-		oz_complete_urb(ozhcd->hcd, urb, -EPIPE, 0);
+		oz_complete_urb(ozhcd->hcd, urb, -EPIPE);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: tasklet
  */
 static void oz_urb_cancel_tasklet(unsigned long unused)
@@ -1657,6 +1733,7 @@
 	unsigned long irq_state;
 	struct urb *urb;
 	struct oz_hcd *ozhcd = oz_hcd_claim();
+
 	if (ozhcd == NULL)
 		return;
 	spin_lock_irqsave(&g_tasklet_lock, irq_state);
@@ -1675,7 +1752,8 @@
 	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)
@@ -1686,37 +1764,38 @@
 			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_complete_urb(ozhcd->hcd, urbl->urb, status);
 			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");
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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().
@@ -1726,21 +1805,19 @@
 				gfp_t mem_flags)
 {
 	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
-	int rc = 0;
+	int rc;
 	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_dbg(URB, "%s: (%p)\n",  __func__, urb);
 	if (unlikely(ozhcd == NULL)) {
-		oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not ozhcd.\n",
-			jiffies, urb);
+		oz_dbg(URB, "Refused urb(%p) not ozhcd\n", urb);
 		return -EPIPE;
 	}
 	if (unlikely(hcd->state != HC_STATE_RUNNING)) {
-		oz_trace2(OZ_TRACE_URB, "%lu: Refused urb(%p) not running.\n",
-			jiffies, urb);
+		oz_dbg(URB, "Refused urb(%p) not running\n", urb);
 		return -EPIPE;
 	}
 	port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum);
@@ -1749,9 +1826,10 @@
 	port =  &ozhcd->ports[port_ix];
 	if (port == NULL)
 		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);
+	if (!(port->flags & OZ_PORT_F_PRESENT) ||
+				(port->flags & OZ_PORT_F_CHANGED)) {
+		oz_dbg(ON, "Refusing URB port_ix = %d devnum = %d\n",
+		       port_ix, urb->dev->devnum);
 		return -EPIPE;
 	}
 	urb->hcpriv = port;
@@ -1774,14 +1852,16 @@
 	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 = NULL;
+	struct oz_urb_link *urbl;
 	struct list_head *e;
+
 	if (unlikely(ep == NULL))
 		return NULL;
 	list_for_each(e, &ep->urb_list) {
@@ -1798,17 +1878,19 @@
 	}
 	return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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 = NULL;
+	struct oz_urb_link *urbl;
 	int rc;
 	unsigned long irq_state;
-	oz_trace2(OZ_TRACE_URB, "%lu: oz_hcd_urb_dequeue(%p)\n", jiffies, urb);
+
+	oz_dbg(URB, "%s: (%p)\n",  __func__, urb);
 	urbl = oz_alloc_urb_link();
 	if (unlikely(urbl == NULL))
 		return -ENOMEM;
@@ -1838,31 +1920,33 @@
 	}
 	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");
+	oz_dbg(ON, "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.
@@ -1872,27 +1956,33 @@
 	struct oz_hcd *ozhcd = oz_hcd_private(hcd);
 	int i;
 
-	oz_trace2(OZ_TRACE_HUB, "oz_hcd_hub_status_data()\n");
 	buf[0] = 0;
+	buf[1] = 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);
+			oz_dbg(HUB, "Port %d changed\n", i);
 			ozhcd->ports[i].flags &= ~OZ_PORT_F_CHANGED;
-			buf[0] |= 1<<(i+1);
+			if (i < 7)
+				buf[0] |= 1 << (i + 1);
+			else
+				buf[1] |= 1 << (i - 7);
 		}
 	}
 	spin_unlock_bh(&ozhcd->hcd_lock);
-	return buf[0] ? 1 : 0;
+	if (buf[0] != 0 || buf[1] != 0)
+		return 2;
+	else
+		return 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;
@@ -1900,7 +1990,8 @@
 			__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)
@@ -1911,59 +2002,59 @@
 	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");
+		oz_dbg(HUB, "USB_PORT_FEAT_CONNECTION\n");
 		break;
 	case USB_PORT_FEAT_ENABLE:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_ENABLE\n");
 		break;
 	case USB_PORT_FEAT_SUSPEND:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_SUSPEND\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_SUSPEND\n");
 		break;
 	case USB_PORT_FEAT_OVER_CURRENT:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
 		break;
 	case USB_PORT_FEAT_RESET:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(HUB, "USB_PORT_FEAT_LOWSPEED\n");
 		break;
 	case USB_PORT_FEAT_C_CONNECTION:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(HUB, "USB_PORT_FEAT_C_RESET\n");
 		break;
 	case USB_PORT_FEAT_TEST:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_TEST\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_TEST\n");
 		break;
 	case USB_PORT_FEAT_INDICATOR:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_INDICATOR\n");
 		break;
 	default:
-		oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
+		oz_dbg(HUB, "Other %d\n", wvalue);
 		break;
 	}
 	if (set_bits || clear_bits) {
@@ -1972,11 +2063,11 @@
 		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);
+	oz_dbg(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)
@@ -1986,60 +2077,60 @@
 	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");
+		oz_dbg(HUB, "USB_PORT_FEAT_CONNECTION\n");
 		break;
 	case USB_PORT_FEAT_ENABLE:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_ENABLE\n");
+		oz_dbg(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");
+		oz_dbg(HUB, "USB_PORT_FEAT_SUSPEND\n");
 		break;
 	case USB_PORT_FEAT_OVER_CURRENT:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_OVER_CURRENT\n");
 		break;
 	case USB_PORT_FEAT_RESET:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_RESET\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_RESET\n");
 		break;
 	case USB_PORT_FEAT_POWER:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_POWER\n");
+		oz_dbg(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");
+		oz_dbg(HUB, "USB_PORT_FEAT_LOWSPEED\n");
 		break;
 	case USB_PORT_FEAT_C_CONNECTION:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_C_CONNECTION\n");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(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");
+		oz_dbg(HUB, "USB_PORT_FEAT_TEST\n");
 		break;
 	case USB_PORT_FEAT_INDICATOR:
-		oz_trace2(OZ_TRACE_HUB, "USB_PORT_FEAT_INDICATOR\n");
+		oz_dbg(HUB, "USB_PORT_FEAT_INDICATOR\n");
 		break;
 	default:
-		oz_trace2(OZ_TRACE_HUB, "Other %d\n", wvalue);
+		oz_dbg(HUB, "Other %d\n", wvalue);
 		break;
 	}
 	if (clear_bits) {
@@ -2047,37 +2138,40 @@
 		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);
+	oz_dbg(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;
+	u32 status;
+
 	if ((windex < 1) || (windex > OZ_NB_PORTS))
 		return -EPIPE;
 	ozhcd = oz_hcd_private(hcd);
-	oz_trace2(OZ_TRACE_HUB, "GetPortStatus windex = %d\n", windex);
+	oz_dbg(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);
+	oz_dbg(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);
+		oz_dbg(HUB, "ClearHubFeature: %d\n", req_type);
 		break;
 	case ClearPortFeature:
 		err = oz_clear_port_feature(hcd, wvalue, windex);
@@ -2086,32 +2180,32 @@
 		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);
+		oz_dbg(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);
+		oz_dbg(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);
+		oz_dbg(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;
@@ -2119,13 +2213,14 @@
 	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;
@@ -2133,13 +2228,12 @@
 	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)
@@ -2148,10 +2242,10 @@
 	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 == NULL) {
-		oz_trace("Failed to created hcd object OK\n");
+		oz_dbg(ON, "Failed to created hcd object OK\n");
 		return -ENOMEM;
 	}
 	ozhcd = oz_hcd_private(hcd);
@@ -2172,7 +2266,7 @@
 	}
 	err = usb_add_hcd(hcd, 0, 0);
 	if (err) {
-		oz_trace("Failed to add hcd object OK\n");
+		oz_dbg(ON, "Failed to add hcd object OK\n");
 		usb_put_hcd(hcd);
 		return -1;
 	}
@@ -2181,14 +2275,15 @@
 	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 == NULL)
 		return -1;
 	ozhcd = oz_hcd_private(hcd);
@@ -2196,42 +2291,45 @@
 	if (ozhcd == g_ozhcd)
 		g_ozhcd = NULL;
 	spin_unlock_bh(&g_hcdlock);
-	oz_trace("Clearing orphanage\n");
+	oz_dbg(ON, "Clearing orphanage\n");
 	oz_hcd_clear_orphanage(ozhcd, -EPIPE);
-	oz_trace("Removing hcd\n");
+	oz_dbg(ON, "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);
+	oz_dbg(ON, "platform_driver_register() returned %d\n", err);
 	if (err)
 		goto error;
 	g_plat_dev = platform_device_alloc(OZ_PLAT_DEV_NAME, -1);
@@ -2239,11 +2337,11 @@
 		err = -ENOMEM;
 		goto error1;
 	}
-	oz_trace("platform_device_alloc() succeeded\n");
+	oz_dbg(ON, "platform_device_alloc() succeeded\n");
 	err = platform_device_add(g_plat_dev);
 	if (err)
 		goto error2;
-	oz_trace("platform_device_add() succeeded\n");
+	oz_dbg(ON, "platform_device_add() succeeded\n");
 	return 0;
 error2:
 	platform_device_put(g_plat_dev);
@@ -2252,17 +2350,19 @@
 error:
 	tasklet_disable(&g_urb_process_tasklet);
 	tasklet_disable(&g_urb_cancel_tasklet);
-	oz_trace("oz_hcd_init() failed %d\n", err);
+	oz_dbg(ON, "oz_hcd_init() failed %d\n", err);
 	return err;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 void oz_hcd_term(void)
 {
+	msleep(OZ_HUB_DEBOUNCE_TIMEOUT);
 	tasklet_kill(&g_urb_process_tasklet);
 	tasklet_kill(&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));
+	oz_dbg(ON, "Pending urbs:%d\n", atomic_read(&g_pending_urbs));
 }
diff --git a/drivers/staging/ozwpan/ozhcd.h b/drivers/staging/ozwpan/ozhcd.h
index 9b30dfd..55e97b1 100644
--- a/drivers/staging/ozwpan/ozhcd.h
+++ b/drivers/staging/ozwpan/ozhcd.h
@@ -7,8 +7,8 @@
 
 int oz_hcd_init(void);
 void oz_hcd_term(void);
-void *oz_hcd_pd_arrived(void *ctx);
-void oz_hcd_pd_departed(void *ctx);
+struct oz_port *oz_hcd_pd_arrived(void *ctx);
+void oz_hcd_pd_departed(struct oz_port *hport);
 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
index 51fe9e9..d1a5b7a 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -3,6 +3,7 @@
  * Released under the GNU General Public License Version 2 (GPLv2).
  * -----------------------------------------------------------------------------
  */
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/timer.h>
@@ -10,19 +11,22 @@
 #include <linux/netdevice.h>
 #include <linux/errno.h>
 #include <linux/ieee80211.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
 #include "ozpd.h"
 #include "ozproto.h"
 #include "ozcdev.h"
-#include "oztrace.h"
-/*------------------------------------------------------------------------------
+
+unsigned int oz_dbg_mask = OZ_DEFAULT_DBG_MASK;
+
+/*
  * 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.
  */
 static char *g_net_dev = "";
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static int __init ozwpan_init(void)
@@ -33,7 +37,8 @@
 	oz_apps_init();
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static void __exit ozwpan_exit(void)
@@ -42,8 +47,7 @@
 	oz_apps_term();
 	oz_cdev_deregister();
 }
-/*------------------------------------------------------------------------------
- */
+
 module_param(g_net_dev, charp, S_IRUGO);
 module_init(ozwpan_init);
 module_exit(ozwpan_exit);
diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c
index d67dff2..ab85a72 100644
--- a/drivers/staging/ozwpan/ozpd.c
+++ b/drivers/staging/ozwpan/ozpd.c
@@ -3,28 +3,26 @@
  * 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 "ozdbg.h"
 #include "ozprotocol.h"
 #include "ozeltbuf.h"
 #include "ozpd.h"
 #include "ozproto.h"
-#include "oztrace.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
-/*------------------------------------------------------------------------------
- */
+
 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 void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f);
@@ -39,10 +37,12 @@
 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 const struct oz_app_if g_app_if[OZ_APPID_MAX] = {
@@ -82,69 +82,75 @@
 	NULL,
 	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;
-#ifdef WANT_TRACE
 	switch (state) {
 	case OZ_PD_S_IDLE:
-		oz_trace("PD State: OZ_PD_S_IDLE\n");
+		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n");
 		break;
 	case OZ_PD_S_CONNECTED:
-		oz_trace("PD State: OZ_PD_S_CONNECTED\n");
+		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n");
 		break;
 	case OZ_PD_S_STOPPED:
-		oz_trace("PD State: OZ_PD_S_STOPPED\n");
+		oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n");
 		break;
 	case OZ_PD_S_SLEEP:
-		oz_trace("PD State: OZ_PD_S_SLEEP\n");
+		oz_pd_dbg(pd, ON, "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)
@@ -152,12 +158,14 @@
 	if (atomic_dec_and_test(&pd->ref_count))
 		oz_pd_destroy(pd);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 struct oz_pd *oz_pd_alloc(const u8 *mac_addr)
 {
 	struct oz_pd *pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC);
+
 	if (pd) {
 		int i;
 		atomic_set(&pd->ref_count, 2);
@@ -177,19 +185,34 @@
 		pd->last_sent_frame = &pd->tx_queue;
 		spin_lock_init(&pd->stream_lock);
 		INIT_LIST_HEAD(&pd->stream_list);
+		tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler,
+							(unsigned long)pd);
+		tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler,
+							(unsigned long)pd);
+		hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		pd->heartbeat.function = oz_pd_heartbeat_event;
+		pd->timeout.function = oz_pd_timeout_event;
 	}
 	return pd;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
-void oz_pd_destroy(struct oz_pd *pd)
+static void oz_pd_free(struct work_struct *work)
 {
 	struct list_head *e;
 	struct oz_tx_frame *f;
 	struct oz_isoc_stream *st;
 	struct oz_farewell *fwell;
-	oz_trace("Destroying PD\n");
+	struct oz_pd *pd;
+
+	oz_pd_dbg(pd, ON, "Destroying PD\n");
+	pd = container_of(work, struct oz_pd, workitem);
+	/*Disable timer tasklets*/
+	tasklet_kill(&pd->heartbeat_tasklet);
+	tasklet_kill(&pd->timeout_tasklet);
 	/* Delete any streams.
 	 */
 	e = pd->stream_list.next;
@@ -228,20 +251,38 @@
 		dev_put(pd->net_dev);
 	kfree(pd);
 }
-/*------------------------------------------------------------------------------
+
+/*
+ * Context: softirq or Process
+ */
+void oz_pd_destroy(struct oz_pd *pd)
+{
+	if (hrtimer_active(&pd->timeout))
+		hrtimer_cancel(&pd->timeout);
+	if (hrtimer_active(&pd->heartbeat))
+		hrtimer_cancel(&pd->heartbeat);
+
+	INIT_WORK(&pd->workitem, oz_pd_free);
+	if (!schedule_work(&pd->workitem))
+		oz_pd_dbg(pd, ON, "failed to schedule workitem\n");
+}
+
+/*
  * Context: softirq-serialized
  */
 int oz_services_start(struct oz_pd *pd, u16 apps, int resume)
 {
 	const struct oz_app_if *ai;
 	int rc = 0;
-	oz_trace("oz_services_start(0x%x) resume(%d)\n", apps, resume);
+
+	oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, 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);
+				oz_pd_dbg(pd, ON,
+					  "Unable to start service %d\n",
+					  ai->app_id);
 				break;
 			}
 			oz_polling_lock_bh();
@@ -253,13 +294,15 @@
 	}
 	return rc;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 void oz_services_stop(struct oz_pd *pd, u16 apps, int pause)
 {
 	const struct oz_app_if *ai;
-	oz_trace("oz_stop_services(0x%x) pause(%d)\n", apps, pause);
+
+	oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, 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();
@@ -274,34 +317,38 @@
 		}
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 void oz_pd_heartbeat(struct oz_pd *pd, u16 apps)
 {
 	const 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 ((!more) && (hrtimer_active(&pd->heartbeat)))
+		hrtimer_cancel(&pd->heartbeat);
 	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);
+	u16 stop_apps;
+
+	oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state);
 	oz_pd_indicate_farewells(pd);
 	oz_polling_lock_bh();
 	stop_apps = pd->total_apps;
@@ -314,46 +361,46 @@
 	/* 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_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count));
 	oz_pd_put(pd);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_pd_sleep(struct oz_pd *pd)
 {
 	int do_stop = 0;
-	u16 stop_apps = 0;
+	u16 stop_apps;
+
 	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) {
+	if (pd->keep_alive && 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 {
+	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);
+		oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive);
 	}
 	return do_stop;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd)
 {
 	struct oz_tx_frame *f = NULL;
+
 	spin_lock_bh(&pd->tx_frame_lock);
 	if (pd->tx_pool) {
 		f = container_of(pd->tx_pool, struct oz_tx_frame, link);
@@ -370,7 +417,8 @@
 	}
 	return f;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -384,10 +432,11 @@
 	} else {
 		kfree(f);
 	}
-	oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
-						pd->nb_queued_isoc_frames);
+	oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n",
+	       pd->nb_queued_isoc_frames);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f)
@@ -402,28 +451,34 @@
 	spin_unlock_bh(&pd->tx_frame_lock);
 	kfree(f);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_set_more_bit(struct sk_buff *skb)
 {
 	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+
 	oz_hdr->control |= OZ_F_MORE_DATA;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb)
 {
 	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+
 	oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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)
@@ -448,7 +503,8 @@
 	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)
@@ -458,6 +514,7 @@
 	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.
 	 */
@@ -492,13 +549,15 @@
 	kfree_skb(skb);
 	return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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);
@@ -514,7 +573,8 @@
 	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)
@@ -522,6 +582,7 @@
 	struct sk_buff *skb;
 	struct oz_tx_frame *f;
 	struct list_head *e;
+
 	spin_lock(&pd->tx_frame_lock);
 	e = pd->last_sent_frame->next;
 	if (e == &pd->tx_queue) {
@@ -540,18 +601,16 @@
 		if ((int)atomic_read(&g_submitted_isoc) <
 							OZ_MAX_SUBMITTED_ISOC) {
 			if (dev_queue_xmit(skb) < 0) {
-				oz_trace2(OZ_TRACE_TX_FRAMES,
-						"Dropping ISOC Frame\n");
+				oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n");
 				return -1;
 			}
 			atomic_inc(&g_submitted_isoc);
-			oz_trace2(OZ_TRACE_TX_FRAMES,
-					"Sending ISOC Frame, nb_isoc= %d\n",
-						pd->nb_queued_isoc_frames);
+			oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n",
+			       pd->nb_queued_isoc_frames);
 			return 0;
 		} else {
 			kfree_skb(skb);
-			oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Frame>\n");
+			oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n");
 			return -1;
 		}
 	}
@@ -559,17 +618,18 @@
 	pd->last_sent_frame = e;
 	skb = oz_build_frame(pd, f);
 	spin_unlock(&pd->tx_frame_lock);
+	if (!skb)
+		return -1;
 	if (more_data)
 		oz_set_more_bit(skb);
-	oz_trace2(OZ_TRACE_TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num);
-	if (skb) {
-		if (dev_queue_xmit(skb) < 0)
-			return -1;
+	oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", 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)
@@ -607,7 +667,8 @@
 out:	oz_prepare_frame(pd, 1);
 	oz_send_next_queued_frame(pd, 0);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static int oz_send_isoc_frame(struct oz_pd *pd)
@@ -619,6 +680,7 @@
 	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,
@@ -627,7 +689,7 @@
 		return 0;
 	skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL) {
-		oz_trace("Cannot alloc skb\n");
+		oz_dbg(ON, "Cannot alloc skb\n");
 		oz_elt_info_free_chain(&pd->elt_buff, &list);
 		return -1;
 	}
@@ -655,7 +717,8 @@
 	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)
@@ -675,8 +738,8 @@
 		diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK;
 		if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0))
 			break;
-		oz_trace2(OZ_TRACE_TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
-						 pkt_num, pd->nb_queued_frames);
+		oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n",
+		       pkt_num, pd->nb_queued_frames);
 		if (first == NULL)
 			first = e;
 		last = e;
@@ -696,7 +759,8 @@
 		oz_retire_frame(pd, f);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Precondition: stream_lock must be held.
  * Context: softirq
  */
@@ -704,6 +768,7 @@
 {
 	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)
@@ -711,7 +776,8 @@
 	}
 	return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num)
@@ -730,7 +796,8 @@
 	kfree(st);
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 static void oz_isoc_stream_free(struct oz_isoc_stream *st)
@@ -738,12 +805,14 @@
 	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)
@@ -753,14 +822,16 @@
 		oz_isoc_stream_free(st);
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: any
  */
 static void oz_isoc_destructor(struct sk_buff *skb)
 {
 	atomic_dec(&g_submitted_isoc);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len)
@@ -771,6 +842,7 @@
 	struct sk_buff *skb = NULL;
 	struct oz_hdr *oz_hdr = NULL;
 	int size = 0;
+
 	spin_lock_bh(&pd->stream_lock);
 	st = pd_stream_find(pd, ep_num);
 	if (st) {
@@ -835,10 +907,20 @@
 			struct oz_tx_frame *isoc_unit = NULL;
 			int nb = pd->nb_queued_isoc_frames;
 			if (nb >= pd->isoc_latency) {
-				oz_trace2(OZ_TRACE_TX_FRAMES,
-						"Dropping ISOC Unit nb= %d\n",
-									nb);
-				goto out;
+				struct list_head *e;
+				struct oz_tx_frame *f;
+				oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n",
+				       nb);
+				spin_lock(&pd->tx_frame_lock);
+				list_for_each(e, &pd->tx_queue) {
+					f = container_of(e, struct oz_tx_frame,
+									link);
+					if (f->skb != NULL) {
+						oz_tx_isoc_free(pd, f);
+						break;
+					}
+				}
+				spin_unlock(&pd->tx_frame_lock);
 			}
 			isoc_unit = oz_tx_frame_alloc(pd);
 			if (isoc_unit == NULL)
@@ -849,9 +931,9 @@
 			list_add_tail(&isoc_unit->link, &pd->tx_queue);
 			pd->nb_queued_isoc_frames++;
 			spin_unlock_bh(&pd->tx_frame_lock);
-			oz_trace2(OZ_TRACE_TX_FRAMES,
-			"Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
-			pd->nb_queued_isoc_frames, pd->nb_queued_frames);
+			oz_dbg(TX_FRAMES,
+			       "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n",
+			       pd->nb_queued_isoc_frames, pd->nb_queued_frames);
 			return 0;
 		}
 
@@ -870,45 +952,53 @@
 	}
 	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)
 {
 	const 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;
 	const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1];
+
 	while (1) {
 		oz_polling_lock_bh();
 		if (list_empty(&pd->farewell_list)) {
diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h
index fbf47cb..12c7129 100644
--- a/drivers/staging/ozwpan/ozpd.h
+++ b/drivers/staging/ozwpan/ozpd.h
@@ -6,6 +6,7 @@
 #ifndef _OZPD_H_
 #define _OZPD_H_
 
+#include <linux/interrupt.h>
 #include "ozeltbuf.h"
 
 /* PD state
@@ -47,8 +48,8 @@
 	struct list_head link;
 	u8 ep_num;
 	u8 index;
-	u8 report[1];
 	u8 len;
+	u8 report[0];
 };
 
 /* Data structure that holds information on a specific peripheral device (PD).
@@ -68,18 +69,16 @@
 	u8		isoc_sent;
 	u32		last_rx_pkt_num;
 	u32		last_tx_pkt_num;
+	struct timespec last_rx_timestamp;
 	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;
+	unsigned long	pulse_time;
+	unsigned long	pulse_period;
+	unsigned long	presleep;
+	unsigned long	keep_alive;
 	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	isoc_latency;
@@ -95,6 +94,12 @@
 	spinlock_t	stream_lock;
 	struct list_head stream_list;
 	struct net_device *net_dev;
+	struct hrtimer  heartbeat;
+	struct hrtimer  timeout;
+	u8      timeout_type;
+	struct tasklet_struct   heartbeat_tasklet;
+	struct tasklet_struct   timeout_tasklet;
+	struct work_struct workitem;
 };
 
 #define OZ_MAX_QUEUED_FRAMES	4
diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c
index 79ac7b5..88714ec 100644
--- a/drivers/staging/ozwpan/ozproto.c
+++ b/drivers/staging/ozwpan/ozproto.c
@@ -3,6 +3,7 @@
  * Released under the GNU General Public License Version 2 (GPLv2).
  * -----------------------------------------------------------------------------
  */
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/timer.h>
@@ -10,68 +11,45 @@
 #include <linux/netdevice.h>
 #include <linux/errno.h>
 #include <linux/ieee80211.h>
-#include "ozconfig.h"
+#include "ozdbg.h"
 #include "ozprotocol.h"
 #include "ozeltbuf.h"
 #include "ozpd.h"
 #include "ozproto.h"
 #include "ozusbsvc.h"
-#include "oztrace.h"
+
 #include "ozappif.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 list_head link;
 };
 
-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 LIST_HEAD(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)
@@ -84,7 +62,8 @@
 	}
 	return g_session_id;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_send_conn_rsp(struct oz_pd *pd, u8 status)
@@ -94,6 +73,7 @@
 	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);
@@ -124,11 +104,12 @@
 		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);
+	oz_dbg(ON, "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)
@@ -137,35 +118,41 @@
 
 	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);
+		pd->keep_alive = keep_alive * 1000*60*60*24*20;
 		break;
 	case OZ_KALIVE_SECS:
-		pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000);
+		pd->keep_alive = keep_alive*1000;
 		break;
 	case OZ_KALIVE_MINS:
-		pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60);
+		pd->keep_alive = keep_alive*1000*60;
 		break;
 	case OZ_KALIVE_HOURS:
-		pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60*60);
+		pd->keep_alive = keep_alive*1000*60*60;
 		break;
 	default:
-		pd->keep_alive_j = 0;
+		pd->keep_alive = 0;
 	}
-	oz_trace("Keepalive = %lu jiffies\n", pd->keep_alive_j);
+	oz_dbg(ON, "Keepalive = %lu mSec\n", pd->keep_alive);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
-static void pd_set_presleep(struct oz_pd *pd, u8 presleep)
+static void pd_set_presleep(struct oz_pd *pd, u8 presleep, u8 start_timer)
 {
 	if (presleep)
-		pd->presleep_j = oz_ms_to_jiffies(presleep*100);
+		pd->presleep = presleep*100;
 	else
-		pd->presleep_j = OZ_PRESLEEP_TOUT_J;
-	oz_trace("Presleep time = %lu jiffies\n", pd->presleep_j);
+		pd->presleep = OZ_PRESLEEP_TOUT;
+	if (start_timer) {
+		spin_unlock(&g_polling_lock);
+		oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
+		spin_lock(&g_polling_lock);
+	}
+	oz_dbg(ON, "Presleep time = %lu mSec\n", pd->presleep);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
@@ -179,6 +166,7 @@
 	u16 new_apps = g_apps;
 	struct net_device *old_net_dev = NULL;
 	struct oz_pd *free_pd = NULL;
+
 	if (cur_pd) {
 		pd = cur_pd;
 		spin_lock_bh(&g_polling_lock);
@@ -188,7 +176,7 @@
 		pd = oz_pd_alloc(pd_addr);
 		if (pd == NULL)
 			return NULL;
-		pd->last_rx_time_j = jiffies;
+		getnstimeofday(&pd->last_rx_timestamp);
 		spin_lock_bh(&g_polling_lock);
 		list_for_each(e, &g_pd_list) {
 			pd2 = container_of(e, struct oz_pd, link);
@@ -210,7 +198,7 @@
 		dev_hold(net_dev);
 		pd->net_dev = net_dev;
 	}
-	oz_trace("Host vendor: %d\n", body->host_vendor);
+	oz_dbg(ON, "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;
@@ -234,12 +222,11 @@
 	}
 	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);
+	oz_dbg(ON, "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->pulse_period = OZ_QUANTUM;
+	pd_set_presleep(pd, body->presleep, 0);
 	pd_set_keepalive(pd, body->keep_alive);
 
 	new_apps &= le16_to_cpu(get_unaligned(&body->apps));
@@ -271,9 +258,8 @@
 		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);
+		oz_dbg(ON, "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;
@@ -300,7 +286,8 @@
 		oz_pd_destroy(free_pd);
 	return pd;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
@@ -309,13 +296,15 @@
 	struct oz_farewell *f;
 	struct oz_farewell *f2;
 	int found = 0;
-	f = kmalloc(sizeof(struct oz_farewell) + len - 1, GFP_ATOMIC);
+
+	f = kmalloc(sizeof(struct oz_farewell) + len, GFP_ATOMIC);
 	if (!f)
 		return;
 	f->ep_num = ep_num;
 	f->index = index;
+	f->len = len;
 	memcpy(f->report, report, len);
-	oz_trace("RX: Adding farewell report\n");
+	oz_dbg(ON, "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)) {
@@ -329,7 +318,8 @@
 	if (found)
 		kfree(f2);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static void oz_rx_frame(struct sk_buff *skb)
@@ -340,20 +330,20 @@
 	int length;
 	struct oz_pd *pd = NULL;
 	struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
+	struct timespec current_time;
 	int dup = 0;
 	u32 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);
+	oz_dbg(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));
+		oz_dbg(ON, "Incorrect protocol version: %d\n",
+		       oz_get_prot_ver(oz_hdr->control));
 		goto done;
 	}
 
@@ -361,19 +351,24 @@
 
 	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 (!(pd->state & OZ_PD_S_CONNECTED))
+			oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
+		getnstimeofday(&current_time);
+		if ((current_time.tv_sec != pd->last_rx_timestamp.tv_sec) ||
+			(pd->presleep < MSEC_PER_SEC))  {
+			oz_timer_add(pd, OZ_TIMER_TOUT,	pd->presleep);
+			pd->last_rx_timestamp = current_time;
+		}
 		if (pkt_num != pd->last_rx_pkt_num) {
 			pd->last_rx_pkt_num = pkt_num;
 		} else {
 			dup = 1;
-			oz_trace("Duplicate frame\n");
+			oz_dbg(ON, "Duplicate frame\n");
 		}
 	}
 
 	if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
-		oz_trace2(OZ_TRACE_RX_FRAMES, "Received TRIGGER Frame\n");
+		oz_dbg(RX_FRAMES, "Received TRIGGER Frame\n");
 		pd->last_sent_frame = &pd->tx_queue;
 		if (oz_hdr->control & OZ_F_ACK) {
 			/* Retire completed frames */
@@ -397,22 +392,22 @@
 			break;
 		switch (elt->type) {
 		case OZ_ELT_CONNECT_REQ:
-			oz_trace("RX: OZ_ELT_CONNECT_REQ\n");
+			oz_dbg(ON, "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");
+			oz_dbg(ON, "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");
+				oz_dbg(ON, "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);
+					pd_set_presleep(pd, body->presleep, 1);
 					spin_unlock(&g_polling_lock);
 				}
 			}
@@ -420,7 +415,7 @@
 		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_dbg(ON, "RX: OZ_ELT_FAREWELL_REQ\n");
 				oz_add_farewell(pd, body->ep_num,
 					body->index, body->report,
 					elt->length + 1 - sizeof(*body));
@@ -436,7 +431,7 @@
 			}
 			break;
 		default:
-			oz_trace("RX: Unknown elt %02x\n", elt->type);
+			oz_dbg(ON, "RX: Unknown elt %02x\n", elt->type);
 		}
 		elt = oz_next_elt(elt);
 	}
@@ -445,19 +440,19 @@
 		oz_pd_put(pd);
 	consume_skb(skb);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 void oz_protocol_term(void)
 {
-	struct list_head *chain;
-	del_timer_sync(&g_timer);
+	struct oz_binding *b, *t;
+
 	/* 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;
+	list_for_each_entry_safe(b, t, &g_binding, link) {
+		list_del(&b->link);
 		spin_unlock_bh(&g_binding_lock);
 		dev_remove_pack(&b->ptype);
 		if (b->ptype.dev)
@@ -480,21 +475,38 @@
 		oz_pd_put(pd);
 		spin_lock_bh(&g_polling_lock);
 	}
-	chain = g_timer_pool;
-	g_timer_pool = NULL;
 	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");
+	oz_dbg(ON, "Protocol stopped\n");
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
-static void oz_pd_handle_timer(struct oz_pd *pd, int type)
+void oz_pd_heartbeat_handler(unsigned long data)
 {
+	struct oz_pd *pd = (struct oz_pd *)data;
+	u16 apps = 0;
+
+	spin_lock_bh(&g_polling_lock);
+	if (pd->state & OZ_PD_S_CONNECTED)
+		apps = pd->total_apps;
+	spin_unlock_bh(&g_polling_lock);
+	if (apps)
+		oz_pd_heartbeat(pd, apps);
+	oz_pd_put(pd);
+}
+
+/*
+ * Context: softirq
+ */
+void oz_pd_timeout_handler(unsigned long data)
+{
+	int type;
+	struct oz_pd *pd = (struct oz_pd *)data;
+
+	spin_lock_bh(&g_polling_lock);
+	type = pd->timeout_type;
+	spin_unlock_bh(&g_polling_lock);
 	switch (type) {
 	case OZ_TIMER_TOUT:
 		oz_pd_sleep(pd);
@@ -502,226 +514,86 @@
 	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);
+	}
+	oz_pd_put(pd);
+}
+
+/*
+ * Context: Interrupt
+ */
+enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer)
+{
+	struct oz_pd *pd;
+
+	pd = container_of(timer, struct oz_pd, heartbeat);
+	hrtimer_forward_now(timer, ktime_set(pd->pulse_period /
+	MSEC_PER_SEC, (pd->pulse_period % MSEC_PER_SEC) * NSEC_PER_MSEC));
+	oz_pd_get(pd);
+	tasklet_schedule(&pd->heartbeat_tasklet);
+	return HRTIMER_RESTART;
+}
+
+/*
+ * Context: Interrupt
+ */
+enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer)
+{
+	struct oz_pd *pd;
+
+	pd = container_of(timer, struct oz_pd, timeout);
+	oz_pd_get(pd);
+	tasklet_schedule(&pd->timeout_tasklet);
+	return HRTIMER_NORESTART;
+}
+
+/*
+ * Context: softirq or process
+ */
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time)
+{
+	spin_lock_bh(&g_polling_lock);
+	switch (type) {
+	case OZ_TIMER_TOUT:
+	case OZ_TIMER_STOP:
+		if (hrtimer_active(&pd->timeout)) {
+			hrtimer_set_expires(&pd->timeout, ktime_set(due_time /
+			MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+							NSEC_PER_MSEC));
+			hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL);
+		} else {
+			hrtimer_start(&pd->timeout, ktime_set(due_time /
+			MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+					NSEC_PER_MSEC), HRTIMER_MODE_REL);
 		}
+		pd->timeout_type = type;
+		break;
+	case OZ_TIMER_HEARTBEAT:
+		if (!hrtimer_active(&pd->heartbeat))
+			hrtimer_start(&pd->heartbeat, ktime_set(due_time /
+			MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
+					NSEC_PER_MSEC), HRTIMER_MODE_REL);
 		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.
-		 */
-		spin_unlock_bh(&g_polling_lock);
-		return;
-	}
-	g_timer_state = OZ_TIMER_IN_HANDLER;
-	t = g_cur_timer;
-	g_cur_timer = NULL;
-	list_del(&t->link);
-	spin_unlock_bh(&g_polling_lock);
-	do {
-		pd = t->pd;
-		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 = NULL;
-		}
-		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 = NULL;
-		} else {
-			t2 = NULL;
-		}
-		spin_unlock_bh(&g_polling_lock);
-		oz_pd_put(pd);
-		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) {
-			mod_timer(&g_timer, g_cur_timer->due_time);
-		} else {
-			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 = NULL;
-	int restart_needed = 0;
-	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 = NULL;
-				}
-				list_del(e);
-				break;
-			}
-			t = NULL;
-		}
-	}
-	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 = NULL;
-					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 = NULL;
-	struct oz_timer *t;
-	struct oz_timer *n;
-	int restart_needed = 0;
-	int release = 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 = NULL;
-				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);
+	oz_timer_add(pd, OZ_TIMER_HEARTBEAT, pd->pulse_period > 0 ?
+					pd->pulse_period : OZ_QUANTUM);
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq or process
  */
 struct oz_pd *oz_pd_find(const 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);
@@ -734,7 +606,8 @@
 	spin_unlock_bh(&g_polling_lock);
 	return NULL;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 void oz_app_enable(int app_id, int enable)
@@ -748,7 +621,8 @@
 		spin_unlock_bh(&g_polling_lock);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev,
@@ -782,10 +656,11 @@
 	}
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
-void oz_binding_add(char *net_dev)
+void oz_binding_add(const char *net_dev)
 {
 	struct oz_binding *binding;
 
@@ -795,43 +670,28 @@
 		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);
+			oz_dbg(ON, "Adding binding: %s\n", net_dev);
 			binding->ptype.dev =
 				dev_get_by_name(&init_net, net_dev);
 			if (binding->ptype.dev == NULL) {
-				oz_trace("Netdev %s not found\n", net_dev);
+				oz_dbg(ON, "Netdev %s not found\n", net_dev);
 				kfree(binding);
 				binding = NULL;
 			}
 		} else {
-			oz_trace("Binding to all netcards\n");
+			oz_dbg(ON, "Binding to all netcards\n");
 			binding->ptype.dev = NULL;
 		}
 		if (binding) {
 			dev_add_pack(&binding->ptype);
 			spin_lock_bh(&g_binding_lock);
-			binding->next = g_binding;
-			g_binding = binding;
+			list_add_tail(&binding->link, &g_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)
@@ -839,6 +699,7 @@
 	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) {
@@ -854,38 +715,37 @@
 		oz_pd_put(pd);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
-void oz_binding_remove(char *net_dev)
+void oz_binding_remove(const char *net_dev)
 {
 	struct oz_binding *binding;
-	struct oz_binding **link;
-	oz_trace("Removing binding: %s\n", net_dev);
+	int found = 0;
+
+	oz_dbg(ON, "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;
+	list_for_each_entry(binding, &g_binding, link) {
+		if (strncmp(binding->name, net_dev, OZ_MAX_BINDING_LEN) == 0) {
+			oz_dbg(ON, "Binding '%s' found\n", net_dev);
+			found = 1;
 			break;
-		} else {
-			link = &binding;
-			binding = binding->next;
 		}
 	}
 	spin_unlock_bh(&g_binding_lock);
-	if (binding) {
+	if (found) {
 		dev_remove_pack(&binding->ptype);
 		if (binding->ptype.dev) {
 			dev_put(binding->ptype.dev);
 			pd_stop_all_for_device(binding->ptype.dev);
 		}
+		list_del(&binding->link);
 		kfree(binding);
 	}
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 static char *oz_get_next_device_name(char *s, char *dname, int max_size)
@@ -899,7 +759,8 @@
 	*dname = 0;
 	return s;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: process
  */
 int oz_protocol_init(char *devs)
@@ -915,10 +776,10 @@
 				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)
@@ -926,6 +787,7 @@
 	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)
@@ -936,14 +798,12 @@
 	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
index 93bb4c0..0c49c8a 100644
--- a/drivers/staging/ozwpan/ozproto.h
+++ b/drivers/staging/ozwpan/ozproto.h
@@ -7,28 +7,19 @@
 #define _OZPROTO_H
 
 #include <asm/byteorder.h>
-#include "ozconfig.h"
+#include "ozdbg.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)	msecs_to_jiffies(__x)
-
-/* Quantum milliseconds.
- */
-#define OZ_QUANTUM_MS		8
-/* Quantum jiffies
- */
-#define OZ_QUANTUM_J		(oz_ms_to_jiffies(OZ_QUANTUM_MS))
+/* Quantum in MS */
+#define OZ_QUANTUM		8
 /* Default timeouts.
  */
-#define OZ_CONNECTION_TOUT_J	(2*HZ)
-#define OZ_PRESLEEP_TOUT_J	(11*HZ)
+#define OZ_PRESLEEP_TOUT	11
 
 /* Maximun sizes of tx frames. */
-#define OZ_MAX_TX_SIZE		1514
+#define OZ_MAX_TX_SIZE		760
 
 /* Maximum number of uncompleted isoc frames that can be pending in network. */
 #define OZ_MAX_SUBMITTED_ISOC	16
@@ -63,13 +54,18 @@
 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(const 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_binding_add(const char *net_dev);
+void oz_binding_remove(const char *net_dev);
+void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time);
 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);
+void oz_pd_heartbeat_handler(unsigned long data);
+void oz_pd_timeout_handler(unsigned long data);
+enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer);
+enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer);
+int oz_get_pd_status_list(char *pd_list, int max_count);
+int oz_get_binding_list(char *buf, int max_if);
 
 #endif /* _OZPROTO_H */
diff --git a/drivers/staging/ozwpan/oztrace.c b/drivers/staging/ozwpan/oztrace.c
deleted file mode 100644
index 353ead2..0000000
--- a/drivers/staging/ozwpan/oztrace.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -----------------------------------------------------------------------------
- * 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
deleted file mode 100644
index 8293b24..0000000
--- a/drivers/staging/ozwpan/oztrace.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -----------------------------------------------------------------------------
- * 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
index 55b9afb..cf6278a 100644
--- a/drivers/staging/ozwpan/ozurbparanoia.c
+++ b/drivers/staging/ozwpan/ozurbparanoia.c
@@ -4,37 +4,39 @@
  * -----------------------------------------------------------------------------
  */
 #include <linux/usb.h>
-#include "ozconfig.h"
+#include "ozdbg.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);
+		oz_dbg(ON, "urb up = %d %p\n", g_nb_urbs, urb);
 	} else {
-		oz_trace("ERROR urb buffer full\n");
+		oz_dbg(ON, "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) {
@@ -42,8 +44,7 @@
 			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);
+			oz_dbg(ON, "urb down = %d %p\n", g_nb_urbs, urb);
 		}
 	}
 	spin_unlock_irqrestore(&g_urb_mem_lock, irq_state);
diff --git a/drivers/staging/ozwpan/ozurbparanoia.h b/drivers/staging/ozwpan/ozurbparanoia.h
index 00f5a3a..5080ea7 100644
--- a/drivers/staging/ozwpan/ozurbparanoia.h
+++ b/drivers/staging/ozwpan/ozurbparanoia.h
@@ -10,8 +10,8 @@
 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
+static inline void oz_remember_urb(struct urb *urb) {}
+static inline int oz_forget_urb(struct urb *urb) { return 0; }
 #endif /* WANT_URB_PARANOIA */
 
 
diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c
index 1676328..cf26379 100644
--- a/drivers/staging/ozwpan/ozusbsvc.c
+++ b/drivers/staging/ozwpan/ozusbsvc.c
@@ -10,6 +10,7 @@
  * The implementation of this service uses ozhcd.c to implement a USB HCD.
  * -----------------------------------------------------------------------------
  */
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/timer.h>
@@ -18,16 +19,16 @@
 #include <linux/errno.h>
 #include <linux/input.h>
 #include <asm/unaligned.h>
-#include "ozconfig.h"
+#include "ozdbg.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"
-/*------------------------------------------------------------------------------
+
+/*
  * This is called once when the driver is loaded to initialise the USB service.
  * Context: process
  */
@@ -35,7 +36,8 @@
 {
 	return oz_hcd_init();
 }
-/*------------------------------------------------------------------------------
+
+/*
  * This is called once when the driver is unloaded to terminate the USB service.
  * Context: process
  */
@@ -43,7 +45,8 @@
 {
 	oz_hcd_term();
 }
-/*------------------------------------------------------------------------------
+
+/*
  * This is called when the USB service is started or resumed for a PD.
  * Context: softirq
  */
@@ -52,11 +55,12 @@
 	int rc = 0;
 	struct oz_usb_ctx *usb_ctx;
 	struct oz_usb_ctx *old_ctx;
+
 	if (resume) {
-		oz_trace("USB service resumed.\n");
+		oz_dbg(ON, "USB service resumed\n");
 		return 0;
 	}
-	oz_trace("USB service started.\n");
+	oz_dbg(ON, "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.
 	 */
@@ -77,7 +81,7 @@
 	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");
+		oz_dbg(ON, "Already have USB context\n");
 		kfree(usb_ctx);
 		usb_ctx = old_ctx;
 	} else if (usb_ctx) {
@@ -95,7 +99,7 @@
 	} else {
 		usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx);
 		if (usb_ctx->hport == NULL) {
-			oz_trace("USB hub returned null port.\n");
+			oz_dbg(ON, "USB hub returned null port\n");
 			spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
 			pd->app_ctx[OZ_APPID_USB-1] = NULL;
 			spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
@@ -106,15 +110,17 @@
 	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;
+
 	if (pause) {
-		oz_trace("USB service paused.\n");
+		oz_dbg(ON, "USB service paused\n");
 		return;
 	}
 	spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]);
@@ -122,8 +128,9 @@
 	pd->app_ctx[OZ_APPID_USB-1] = NULL;
 	spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]);
 	if (usb_ctx) {
-		unsigned long tout = jiffies + HZ;
-		oz_trace("USB service stopping...\n");
+		struct timespec ts, now;
+		getnstimeofday(&ts);
+		oz_dbg(ON, "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
@@ -131,17 +138,21 @@
 		 * 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");
+		while ((atomic_read(&usb_ctx->ref_count) > 2)) {
+			getnstimeofday(&now);
+			/*Approx 1 Sec. this is not perfect calculation*/
+			if (now.tv_sec != ts.tv_sec)
+				break;
+		}
+		oz_dbg(ON, "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
@@ -149,29 +160,34 @@
 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
+ * Context: irq 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_dbg(ON, "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)
@@ -188,14 +204,16 @@
 	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);
+
+	oz_dbg(ON, "%s: (0x%x)\n", __func__, ep_num);
 	if (pd->mode & OZ_F_ISOC_NO_ELTS) {
 		oz_isoc_stream_create(pd, ep_num);
 	} else {
@@ -208,16 +226,18 @@
 	}
 	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);
+			oz_dbg(ON, "%s: (0x%x)\n", __func__, ep_num);
 			if (pd->mode & OZ_F_ISOC_NO_ELTS) {
 				oz_isoc_stream_delete(pd, ep_num);
 			} else {
@@ -229,12 +249,14 @@
 	}
 	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/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c
index 16e6078..228bffa 100644
--- a/drivers/staging/ozwpan/ozusbsvc1.c
+++ b/drivers/staging/ozwpan/ozusbsvc1.c
@@ -13,19 +13,18 @@
 #include <linux/errno.h>
 #include <linux/input.h>
 #include <asm/unaligned.h>
-#include "ozconfig.h"
+#include "ozdbg.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"
-/*------------------------------------------------------------------------------
- */
+
 #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,
@@ -34,6 +33,7 @@
 	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);
@@ -50,7 +50,8 @@
 	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,
@@ -62,12 +63,13 @@
 	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);
+
+	oz_dbg(ON, "    req_type = 0x%x\n", req_type);
+	oz_dbg(ON, "    desc_type = 0x%x\n", desc_type);
+	oz_dbg(ON, "    index = 0x%x\n", index);
+	oz_dbg(ON, "    windex = 0x%x\n", windex);
+	oz_dbg(ON, "    offset = 0x%x\n", offset);
+	oz_dbg(ON, "    len = 0x%x\n", len);
 	if (len > 200)
 		len = 200;
 	if (ei == NULL)
@@ -85,7 +87,8 @@
 	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)
@@ -96,6 +99,7 @@
 	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 == NULL)
 		return -1;
 	elt = (struct oz_elt *)ei->data;
@@ -106,7 +110,8 @@
 	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)
@@ -117,6 +122,7 @@
 	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 == NULL)
 		return -1;
 	elt = (struct oz_elt *)ei->data;
@@ -128,7 +134,8 @@
 	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,
@@ -140,6 +147,7 @@
 	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 == NULL)
 		return -1;
 	elt = (struct oz_elt *)ei->data;
@@ -152,7 +160,8 @@
 	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,
@@ -164,6 +173,7 @@
 	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 == NULL)
 		return -1;
 	elt = (struct oz_elt *)ei->data;
@@ -179,7 +189,8 @@
 		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,
@@ -189,6 +200,7 @@
 	unsigned windex = le16_to_cpu(setup->wIndex);
 	unsigned wlength = le16_to_cpu(setup->wLength);
 	int rc = 0;
+
 	if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
 		switch (setup->bRequest) {
 		case USB_REQ_GET_DESCRIPTOR:
@@ -226,7 +238,8 @@
 	}
 	return rc;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq
  */
 int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb)
@@ -297,13 +310,15 @@
 	}
 	return 0;
 }
-/*------------------------------------------------------------------------------
+
+/*
  * Context: softirq-serialized
  */
 static 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 =
@@ -339,7 +354,8 @@
 	}
 
 }
-/*------------------------------------------------------------------------------
+
+/*
  * 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
@@ -376,7 +392,7 @@
 			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_dbg(ON, "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);
@@ -411,12 +427,14 @@
 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)
@@ -425,7 +443,7 @@
 	if (usb_ctx == NULL)
 		return; /* Context has gone so nothing to do. */
 	if (!usb_ctx->stopped) {
-		oz_trace("Farewell indicated ep = 0x%x\n", ep_num);
+		oz_dbg(ON, "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/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c
index adb8da5..4247d60 100644
--- a/drivers/staging/quickstart/quickstart.c
+++ b/drivers/staging/quickstart/quickstart.c
@@ -71,9 +71,8 @@
 static struct input_dev *quickstart_input;
 
 /* Platform driver functions */
-static ssize_t quickstart_buttons_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
+static ssize_t buttons_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	int count = 0;
 	struct quickstart_button *b;
@@ -94,18 +93,17 @@
 	return count;
 }
 
-static ssize_t quickstart_pressed_button_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)
 {
 	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)
+static ssize_t pressed_button_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
 {
 	if (count < 2)
 		return -EINVAL;
@@ -319,9 +317,8 @@
 }
 
 /* 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 DEVICE_ATTR_RW(pressed_button);
+static DEVICE_ATTR_RO(buttons);
 static struct platform_device *pf_device;
 static struct platform_driver pf_driver = {
 	.driver = {
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 8fc9f58..7f01549 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -14,7 +14,7 @@
  * Copyright (c) 2004, Intel Corporation
  *
  * Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
+ * <andrea.merello@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
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
index d5df0d6..10b2210 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
@@ -14,7 +14,7 @@
  ******************************************************************************
 
   Few modifications for Realtek's Wi-Fi drivers by
-  Andrea Merello <andreamrl@tiscali.it>
+  Andrea Merello <andrea.merello@gmail.com>
 
   A special thanks goes to Realtek for their support !
 
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 00f9af0..b65db54 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -1,5 +1,5 @@
 /* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * Mostly extracted from the rtl8180-sa2400 driver for the
  * in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index d9add53..e528206 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -1,5 +1,5 @@
 /* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * Mostly extracted from the rtl8180-sa2400 driver for the
  * in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 89ed86e..b346653 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -25,7 +25,7 @@
 ******************************************************************************
 
   Few modifications for Realtek's Wi-Fi drivers by
-  Andrea Merello <andreamrl@tiscali.it>
+  Andrea Merello <andrea.merello@gmail.com>
 
   A special thanks goes to Realtek for their support !
 
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index edacc80..d052f4a 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -1,6 +1,6 @@
 /*
    This is part of rtl8180 OpenSource driver.
-   Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+   Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
    Released under the terms of GPL (General Public Licence)
 
    Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8187se/r8180_93cx6.h b/drivers/staging/rtl8187se/r8180_93cx6.h
index 79e7391..b52b5b0 100644
--- a/drivers/staging/rtl8187se/r8180_93cx6.h
+++ b/drivers/staging/rtl8187se/r8180_93cx6.h
@@ -1,6 +1,6 @@
 /*
 	This is part of rtl8180 OpenSource driver
-	Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index ca69155..5947a6f8 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1,6 +1,6 @@
 /*
    This is part of rtl818x pci OpenSource driver - v 0.1
-   Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+   Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
    Released under the terms of GPL (General Public License)
 
    Parts of this driver are based on the GPL part of the official
@@ -70,7 +70,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl);
-MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>");
 MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards");
 
 module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
@@ -197,7 +197,7 @@
 	mb();
 }
 
-irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs);
+static irqreturn_t rtl8180_interrupt(int irq, void *netdev);
 void set_nic_rxring(struct net_device *dev);
 void set_nic_txring(struct net_device *dev);
 static struct net_device_stats *rtl8180_stats(struct net_device *dev);
@@ -2666,7 +2666,7 @@
 				  TX_BEACON_RING_ADDR))
 		return -ENOMEM;
 
-	if (request_irq(dev->irq, (void *)rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
+	if (request_irq(dev->irq, rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) {
 		DMESGE("Error allocating IRQ %d", dev->irq);
 		return -1;
 	} else {
@@ -3537,7 +3537,7 @@
 	spin_unlock_irqrestore(&priv->tx_lock, flag);
 }
 
-irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs)
+irqreturn_t rtl8180_interrupt(int irq, void *netdev)
 {
 	struct net_device *dev = (struct net_device *) netdev;
 	struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h
index 5339381..92c05af 100644
--- a/drivers/staging/rtl8187se/r8180_hw.h
+++ b/drivers/staging/rtl8187se/r8180_hw.h
@@ -1,6 +1,6 @@
 /*
 	This is part of rtl8180 OpenSource driver.
-	Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.h b/drivers/staging/rtl8187se/r8180_rtl8225.h
index c6f2128..c94ca07 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225.h
+++ b/drivers/staging/rtl8187se/r8180_rtl8225.h
@@ -1,7 +1,7 @@
 /*
 	This is part of the rtl8180-sa2400 driver
 	released under the GPL (See file COPYING for details).
-	Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+	Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
 
 	This files contains programming code for the rtl8225
 	radio frontend.
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index c592f79..9ae96b7 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -1,7 +1,7 @@
 /*
  * This is part of the rtl8180-sa2400 driver
  * released under the GPL (See file COPYING for details).
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * This files contains programming code for the rtl8225
  * radio frontend.
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 156b758..dab7875 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -2,7 +2,7 @@
 	This file contains wireless extension handlers.
 
 	This is part of rtl8180 OpenSource driver.
-	Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part
diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h
index 4081914..d471520 100644
--- a/drivers/staging/rtl8187se/r8180_wx.h
+++ b/drivers/staging/rtl8187se/r8180_wx.h
@@ -1,6 +1,6 @@
 /*
 	This is part of rtl8180 OpenSource driver - v 0.3
-	Copyright (C) Andrea Merello 2004  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig
new file mode 100644
index 0000000..c9c548f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/Kconfig
@@ -0,0 +1,29 @@
+config R8188EU
+	tristate "Realtek RTL8188EU Wireless LAN NIC driver"
+	depends on WLAN && USB
+	select WIRELESS_EXT
+	select WEXT_PRIV
+	default N
+	---help---
+	This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N.
+	If built as a module, it will be called r8188eu.
+
+if R8188EU
+
+config 88EU_AP_MODE
+	bool "Realtek RTL8188EU AP mode"
+	default Y
+	---help---
+	This option enables Access Point mode. Unless you know that your system
+	will never be used as an AP, or the target system has limited memory,
+	"Y" should be selected.
+
+config 88EU_P2P
+	bool "Realtek RTL8188EU Peer-to-peer mode"
+	default Y
+	---help---
+	This option enables peer-to-peer mode for the r8188eu driver. Unless you
+	know that peer-to-peer (P2P) mode will never be used, or the target system has
+	limited memory, "Y" should be selected.
+
+endif
diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile
new file mode 100644
index 0000000..1639a45
--- /dev/null
+++ b/drivers/staging/rtl8188eu/Makefile
@@ -0,0 +1,70 @@
+EXTRA_CFLAGS += -I$(src)/include
+
+r8188eu-y :=				\
+		core/rtw_ap.o		\
+		core/rtw_br_ext.o	\
+		core/rtw_cmd.o		\
+		core/rtw_debug.o	\
+		core/rtw_efuse.o	\
+		core/rtw_ieee80211.o	\
+		core/rtw_io.o		\
+		core/rtw_ioctl_set.o	\
+		core/rtw_iol.o		\
+		core/rtw_led.o		\
+		core/rtw_mlme.o		\
+		core/rtw_mlme_ext.o	\
+		core/rtw_mp.o		\
+		core/rtw_mp_ioctl.o	\
+		core/rtw_pwrctrl.o	\
+		core/rtw_p2p.o		\
+		core/rtw_recv.o		\
+		core/rtw_rf.o		\
+		core/rtw_security.o	\
+		core/rtw_sreset.o	\
+		core/rtw_sta_mgt.o	\
+		core/rtw_wlan_util.o	\
+		core/rtw_xmit.o		\
+		hal/HalHWImg8188E_MAC.o	\
+		hal/HalHWImg8188E_BB.o	\
+		hal/HalHWImg8188E_RF.o	\
+		hal/HalPhyRf.o		\
+		hal/HalPhyRf_8188e.o	\
+		hal/HalPwrSeqCmd.o	\
+		hal/Hal8188EFWImg_CE.o	\
+		hal/Hal8188EPwrSeq.o	\
+		hal/Hal8188ERateAdaptive.o\
+		hal/hal_intf.o		\
+		hal/hal_com.o		\
+		hal/odm.o		\
+		hal/odm_debug.o		\
+		hal/odm_interface.o	\
+		hal/odm_HWConfig.o	\
+		hal/odm_RegConfig8188E.o\
+		hal/odm_RTL8188E.o	\
+		hal/rtl8188e_cmd.o	\
+		hal/rtl8188e_dm.o	\
+		hal/rtl8188e_hal_init.o	\
+		hal/rtl8188e_mp.o	\
+		hal/rtl8188e_phycfg.o	\
+		hal/rtl8188e_rf6052.o	\
+		hal/rtl8188e_rxdesc.o	\
+		hal/rtl8188e_sreset.o	\
+		hal/rtl8188e_xmit.o	\
+		hal/rtl8188eu_led.o	\
+		hal/rtl8188eu_recv.o	\
+		hal/rtl8188eu_xmit.o	\
+		hal/usb_halinit.o	\
+		hal/usb_ops_linux.o	\
+		os_dep/ioctl_linux.o	\
+		os_dep/mlme_linux.o	\
+		os_dep/os_intfs.o	\
+		os_dep/osdep_service.o	\
+		os_dep/recv_linux.o	\
+		os_dep/rtw_android.o	\
+		os_dep/usb_intf.o	\
+		os_dep/usb_ops_linux.o	\
+		os_dep/xmit_linux.o
+
+obj-$(CONFIG_R8188EU)	:= r8188eu.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/staging/rtl8188eu/TODO b/drivers/staging/rtl8188eu/TODO
new file mode 100644
index 0000000..e50aa50
--- /dev/null
+++ b/drivers/staging/rtl8188eu/TODO
@@ -0,0 +1,15 @@
+TODO:
+- find and remove remaining code valid only for 5 HGz. Most of the obvious
+  ones have been removed, but things like channel > 14 still exist.
+- find and remove any code for other chips that is left over
+- convert to external firmware
+- convert any remaining unusual variable types
+- find codes that can use %pM and %Nph formatting
+- checkpatch.pl fixes - most of the remaining ones are lines too long. Many
+  of them will require refactoring
+- merge Realtek's bugfixes and new features into the driver
+- switch to use LIB80211
+- switch to use MAC80211
+
+Please send any patches to Greg Kroah-Hartman <gregkh@linux.com>,
+and Larry Finger <Larry.Finger@lwfinger.net>.
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
new file mode 100644
index 0000000..2c73823
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -0,0 +1,1988 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_AP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <ieee80211.h>
+
+#ifdef CONFIG_88EU_AP_MODE
+
+void init_mlme_ap_info(struct adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+
+	_rtw_spinlock_init(&pmlmepriv->bcn_update_lock);
+
+	/* for ACL */
+	_rtw_init_queue(&pacl_list->acl_node_q);
+
+	start_ap_mode(padapter);
+}
+
+void free_mlme_ap_info(struct adapter *padapter)
+{
+	unsigned long irqL;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	pmlmepriv->update_bcn = false;
+	pmlmeext->bstart_bss = false;
+
+	rtw_sta_flush(padapter);
+
+	pmlmeinfo->state = _HW_STATE_NOLINK_;
+
+	/* free_assoc_sta_resources */
+	rtw_free_all_stainfo(padapter);
+
+	/* free bc/mc sta_info */
+	psta = rtw_get_bcmc_stainfo(padapter);
+	_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+	rtw_free_stainfo(padapter, psta);
+	_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+	_rtw_spinlock_free(&pmlmepriv->bcn_update_lock);
+}
+
+static void update_BCNTIM(struct adapter *padapter)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+	unsigned char *pie = pnetwork_mlmeext->IEs;
+
+	/* update TIM IE */
+	if (true) {
+		u8 *p, *dst_ie, *premainder_ie = NULL;
+		u8 *pbackup_remainder_ie = NULL;
+		__le16 tim_bitmap_le;
+		uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+
+		tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+		p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+		if (p != NULL && tim_ielen > 0) {
+			tim_ielen += 2;
+			premainder_ie = p+tim_ielen;
+			tim_ie_offset = (int)(p - pie);
+			remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+			/* append TIM IE from dst_ie offset */
+			dst_ie = p;
+		} else {
+			tim_ielen = 0;
+
+			/* calucate head_len */
+			offset = _FIXED_IE_LENGTH_;
+			offset += pnetwork_mlmeext->Ssid.SsidLength + 2;
+
+			/*  get supported rates len */
+			p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+			if (p !=  NULL)
+				offset += tmp_len+2;
+
+			/* DS Parameter Set IE, len = 3 */
+			offset += 3;
+
+			premainder_ie = pie + offset;
+
+			remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
+
+			/* append TIM IE from offset */
+			dst_ie = pie + offset;
+		}
+
+		if (remainder_ielen > 0) {
+			pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+			if (pbackup_remainder_ie && premainder_ie)
+				memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+		}
+		*dst_ie++ = _TIM_IE_;
+
+		if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc))
+			tim_ielen = 5;
+		else
+			tim_ielen = 4;
+
+		*dst_ie++ = tim_ielen;
+
+		*dst_ie++ = 0;/* DTIM count */
+		*dst_ie++ = 1;/* DTIM peroid */
+
+		if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */
+			*dst_ie++ = BIT(0);/* bitmap ctrl */
+		else
+			*dst_ie++ = 0;
+
+		if (tim_ielen == 4) {
+			*dst_ie++ = *(u8 *)&tim_bitmap_le;
+		} else if (tim_ielen == 5) {
+			memcpy(dst_ie, &tim_bitmap_le, 2);
+			dst_ie += 2;
+		}
+
+		/* copy remainder IE */
+		if (pbackup_remainder_ie) {
+			memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+			kfree(pbackup_remainder_ie);
+		}
+		offset =  (uint)(dst_ie - pie);
+		pnetwork_mlmeext->IELength = offset + remainder_ielen;
+	}
+
+	set_tx_beacon_cmd(padapter);
+}
+
+void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index, u8 *data, u8 len)
+{
+	struct ndis_802_11_var_ie *pIE;
+	u8 bmatch = false;
+	u8 *pie = pnetwork->IEs;
+	u8 *p = NULL, *dst_ie = NULL, *premainder_ie = NULL;
+	u8 *pbackup_remainder_ie = NULL;
+	u32 i, offset, ielen = 0, ie_offset, remainder_ielen = 0;
+
+	for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) {
+		pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i);
+
+		if (pIE->ElementID > index) {
+			break;
+		} else if (pIE->ElementID == index) { /*  already exist the same IE */
+			p = (u8 *)pIE;
+			ielen = pIE->Length;
+			bmatch = true;
+			break;
+		}
+		p = (u8 *)pIE;
+		ielen = pIE->Length;
+		i += (pIE->Length + 2);
+	}
+
+	if (p != NULL && ielen > 0) {
+		ielen += 2;
+
+		premainder_ie = p+ielen;
+
+		ie_offset = (int)(p - pie);
+
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		if (bmatch)
+			dst_ie = p;
+		else
+			dst_ie = (p+ielen);
+	}
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie && premainder_ie)
+			memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	*dst_ie++ = index;
+	*dst_ie++ = len;
+
+	memcpy(dst_ie, data, len);
+	dst_ie += len;
+
+	/* copy remainder IE */
+	if (pbackup_remainder_ie) {
+		memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		kfree(pbackup_remainder_ie);
+	}
+
+	offset =  (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+void rtw_remove_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index)
+{
+	u8 *p, *dst_ie = NULL, *premainder_ie = NULL;
+	u8 *pbackup_remainder_ie = NULL;
+	uint offset, ielen, ie_offset, remainder_ielen = 0;
+	u8	*pie = pnetwork->IEs;
+
+	p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen,
+		       pnetwork->IELength - _FIXED_IE_LENGTH_);
+	if (p != NULL && ielen > 0) {
+		ielen += 2;
+
+		premainder_ie = p+ielen;
+
+		ie_offset = (int)(p - pie);
+
+		remainder_ielen = pnetwork->IELength - ie_offset - ielen;
+
+		dst_ie = p;
+	}
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie && premainder_ie)
+			memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	/* copy remainder IE */
+	if (pbackup_remainder_ie) {
+		memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+		kfree(pbackup_remainder_ie);
+	}
+
+	offset =  (uint)(dst_ie - pie);
+	pnetwork->IELength = offset + remainder_ielen;
+}
+
+static u8 chk_sta_is_alive(struct sta_info *psta)
+{
+	u8 ret = false;
+
+	if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) ==
+	    (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts))
+		;
+	else
+		ret = true;
+
+	sta_update_last_rx_pkts(psta);
+
+	return ret;
+}
+
+void	expire_timeout_chk(struct adapter *padapter)
+{
+	unsigned long irqL;
+	struct list_head *phead, *plist;
+	u8 updated = 0;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 chk_alive_num = 0;
+	char chk_alive_list[NUM_STA];
+	int i;
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+	phead = &pstapriv->auth_list;
+	plist = get_next(phead);
+
+	/* check auth_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == false) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, auth_list);
+		plist = get_next(plist);
+
+		if (psta->expire_to > 0) {
+			psta->expire_to--;
+			if (psta->expire_to == 0) {
+				rtw_list_delete(&psta->auth_list);
+				pstapriv->auth_list_cnt--;
+
+				DBG_88E("auth expire %6ph\n",
+					psta->hwaddr);
+
+				_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+				_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+				rtw_free_stainfo(padapter, psta);
+				_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+				_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+			}
+		}
+
+	}
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+	psta = NULL;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* check asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == false) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		if (chk_sta_is_alive(psta) || !psta->expire_to) {
+			psta->expire_to = pstapriv->expire_to;
+			psta->keep_alive_trycnt = 0;
+			psta->under_exist_checking = 0;
+		} else {
+			psta->expire_to--;
+		}
+
+		if (psta->expire_to <= 0) {
+			struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+			if (padapter->registrypriv.wifi_spec == 1) {
+				psta->expire_to = pstapriv->expire_to;
+				continue;
+			}
+
+			if (psta->state & WIFI_SLEEP_STATE) {
+				if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
+					/* to check if alive by another methods if staion is at ps mode. */
+					psta->expire_to = pstapriv->expire_to;
+					psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+					/* to update bcn with tim_bitmap for this station */
+					pstapriv->tim_bitmap |= BIT(psta->aid);
+					update_beacon(padapter, _TIM_IE_, NULL, false);
+
+					if (!pmlmeext->active_keep_alive_check)
+						continue;
+				}
+			}
+			if (pmlmeext->active_keep_alive_check) {
+				int stainfo_offset;
+
+				stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+				if (stainfo_offset_valid(stainfo_offset))
+					chk_alive_list[chk_alive_num++] = stainfo_offset;
+				continue;
+			}
+
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+
+			DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+			updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+		} else {
+			/* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
+			if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt) &&
+			    padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME/pstapriv->asoc_list_cnt/2)) {
+				DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__,
+					(psta->hwaddr), psta->sleepq_len,
+					padapter->xmitpriv.free_xmitframe_cnt,
+					pstapriv->asoc_list_cnt);
+				wakeup_sta_to_xmit(padapter, psta);
+			}
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	if (chk_alive_num) {
+		u8 backup_oper_channel = 0;
+		struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+		/* switch to correct channel of current network  before issue keep-alive frames */
+		if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+			backup_oper_channel = rtw_get_oper_ch(padapter);
+			SelectChannel(padapter, pmlmeext->cur_channel);
+		}
+
+		/* issue null data to check sta alive*/
+		for (i = 0; i < chk_alive_num; i++) {
+			int ret = _FAIL;
+
+			psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+
+			if (psta->state & WIFI_SLEEP_STATE)
+				ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50);
+			else
+				ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50);
+
+			psta->keep_alive_trycnt++;
+			if (ret == _SUCCESS) {
+				DBG_88E("asoc check, sta(%pM) is alive\n", (psta->hwaddr));
+				psta->expire_to = pstapriv->expire_to;
+				psta->keep_alive_trycnt = 0;
+				continue;
+			} else if (psta->keep_alive_trycnt <= 3) {
+				DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt);
+				psta->expire_to = 1;
+				continue;
+			}
+
+			psta->keep_alive_trycnt = 0;
+
+			DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state);
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		}
+
+		if (backup_oper_channel > 0) /* back to the original operation channel */
+			SelectChannel(padapter, backup_oper_channel);
+	}
+
+	associated_clients_update(padapter, updated);
+}
+
+void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
+{
+	int i;
+	u8 rf_type;
+	u32 init_rate = 0;
+	unsigned char sta_band = 0, raid, shortGIrate = false;
+	unsigned char limit;
+	unsigned int tx_ra_bitmap = 0;
+	struct ht_priv	*psta_ht = NULL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+
+	if (psta)
+		psta_ht = &psta->htpriv;
+	else
+		return;
+
+	if (!(psta->state & _FW_LINKED))
+		return;
+
+	/* b/g mode ra_bitmap */
+	for (i = 0; i < sizeof(psta->bssrateset); i++) {
+		if (psta->bssrateset[i])
+			tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
+	}
+	/* n mode ra_bitmap */
+	if (psta_ht->ht_option) {
+		rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+		if (rf_type == RF_2T2R)
+			limit = 16;/*  2R */
+		else
+			limit = 8;/*   1R */
+
+		for (i = 0; i < limit; i++) {
+			if (psta_ht->ht_cap.supp_mcs_set[i/8] & BIT(i%8))
+				tx_ra_bitmap |= BIT(i+12);
+		}
+
+		/* max short GI rate */
+		shortGIrate = psta_ht->sgi;
+	}
+
+	if (pcur_network->Configuration.DSConfig > 14) {
+		/*  5G band */
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_5N | WIRELESS_11A;
+		else
+			sta_band |= WIRELESS_11A;
+	} else {
+		if (tx_ra_bitmap & 0xffff000)
+			sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
+		else if (tx_ra_bitmap & 0xff0)
+			sta_band |= WIRELESS_11G | WIRELESS_11B;
+		else
+			sta_band |= WIRELESS_11B;
+	}
+
+	psta->wireless_mode = sta_band;
+
+	raid = networktype_to_raid(sta_band);
+	init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+	if (psta->aid < NUM_STA) {
+		u8 arg = 0;
+
+		arg = psta->mac_id&0x1f;
+
+		arg |= BIT(7);/* support entry 2~31 */
+
+		if (shortGIrate)
+			arg |= BIT(5);
+
+		tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+
+		DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
+			__func__ , psta->mac_id, raid , tx_ra_bitmap, arg);
+
+		/* bitmap[0:27] = tx_rate_bitmap */
+		/* bitmap[28:31]= Rate Adaptive id */
+		/* arg[0:4] = macid */
+		/* arg[5] = Short GI */
+		rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level);
+
+		if (shortGIrate)
+			init_rate |= BIT(6);
+
+		/* set ra_id, init_rate */
+		psta->raid = raid;
+		psta->init_rate = init_rate;
+
+	} else {
+		DBG_88E("station aid %d exceed the max number\n", psta->aid);
+	}
+}
+
+static void update_bmc_sta(struct adapter *padapter)
+{
+	unsigned long	irqL;
+	u32 init_rate = 0;
+	unsigned char	network_type, raid;
+	int i, supportRateNum = 0;
+	unsigned int tx_ra_bitmap = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+	struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
+
+	if (psta) {
+		psta->aid = 0;/* default set to 0 */
+		psta->mac_id = psta->aid + 1;
+
+		psta->qos_option = 0;
+		psta->htpriv.ht_option = false;
+
+		psta->ieee8021x_blocked = 0;
+
+		_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+		/* prepare for add_RATid */
+		supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates);
+		network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, 1);
+
+		memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
+		psta->bssratelen = supportRateNum;
+
+		/* b/g mode ra_bitmap */
+		for (i = 0; i < supportRateNum; i++) {
+			if (psta->bssrateset[i])
+				tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i]&0x7f);
+		}
+
+		if (pcur_network->Configuration.DSConfig > 14) {
+			/* force to A mode. 5G doesn't support CCK rates */
+			network_type = WIRELESS_11A;
+			tx_ra_bitmap = 0x150; /*  6, 12, 24 Mbps */
+		} else {
+			/* force to b mode */
+			network_type = WIRELESS_11B;
+			tx_ra_bitmap = 0xf;
+		}
+
+		raid = networktype_to_raid(network_type);
+		init_rate = get_highest_rate_idx(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+		/* ap mode */
+		rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+
+		{
+			u8 arg = 0;
+
+			arg = psta->mac_id&0x1f;
+			arg |= BIT(7);
+			tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+			DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg);
+
+			/* bitmap[0:27] = tx_rate_bitmap */
+			/* bitmap[28:31]= Rate Adaptive id */
+			/* arg[0:4] = macid */
+			/* arg[5] = Short GI */
+			rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0);
+		}
+		/* set ra_id, init_rate */
+		psta->raid = raid;
+		psta->init_rate = init_rate;
+
+		rtw_stassoc_hw_rpt(padapter, psta);
+
+		_enter_critical_bh(&psta->lock, &irqL);
+		psta->state = _FW_LINKED;
+		_exit_critical_bh(&psta->lock, &irqL);
+
+	} else {
+		DBG_88E("add_RATid_bmc_sta error!\n");
+	}
+}
+
+/* notes: */
+/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */
+/* MAC_ID = AID+1 for sta in ap/adhoc mode */
+/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */
+/* MAC_ID = 0 for bssid for sta/ap/adhoc */
+/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
+{
+	unsigned long	irqL;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+	struct ht_priv	*phtpriv_sta = &psta->htpriv;
+
+	psta->mac_id = psta->aid+1;
+	DBG_88E("%s\n", __func__);
+
+	/* ap mode */
+	rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+
+	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+		psta->ieee8021x_blocked = true;
+	else
+		psta->ieee8021x_blocked = false;
+
+
+	/* update sta's cap */
+
+	/* ERP */
+	VCS_update(padapter, psta);
+	/* HT related cap */
+	if (phtpriv_sta->ht_option) {
+		/* check if sta supports rx ampdu */
+		phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+		/* check if sta support s Short GI */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40))
+			phtpriv_sta->sgi = true;
+
+		/*  bwmode */
+		if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) {
+			phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+			phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+		}
+		psta->qos_option = true;
+	} else {
+		phtpriv_sta->ampdu_enable = false;
+		phtpriv_sta->sgi = false;
+		phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+		phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	}
+
+	/* Rx AMPDU */
+	send_delba(padapter, 0, psta->hwaddr);/*  recipient */
+
+	/* TX AMPDU */
+	send_delba(padapter, 1, psta->hwaddr);/* originator */
+	phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */
+	phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */
+
+	/* todo: init other variables */
+
+	_rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state |= _FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+}
+
+static void update_hw_ht_param(struct adapter *padapter)
+{
+	unsigned char		max_AMPDU_len;
+	unsigned char		min_MPDU_spacing;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	DBG_88E("%s\n", __func__);
+
+	/* handle A-MPDU parameter field */
+	/*
+		AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+		AMPDU_para [4:2]:Min MPDU Start Spacing
+	*/
+	max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+	min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+	/*  */
+	/*  Config SM Power Save setting */
+	/*  */
+	pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2;
+	if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+		DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+}
+
+static void start_bss_network(struct adapter *padapter, u8 *pbuf)
+{
+	u8 *p;
+	u8 val8, cur_channel, cur_bwmode, cur_ch_offset;
+	u16 bcn_interval;
+	u32	acparm;
+	int	ie_len;
+	struct registry_priv	 *pregpriv = &padapter->registrypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+	struct HT_info_element *pht_info = NULL;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+	bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
+	cur_channel = pnetwork->Configuration.DSConfig;
+	cur_bwmode = HT_CHANNEL_WIDTH_20;
+	cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+
+	/* check if there is wps ie, */
+	/* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
+	/* and at first time the security ie (RSN/WPA IE) will not include in beacon. */
+	if (!rtw_get_wps_ie(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL))
+		pmlmeext->bstart_bss = true;
+
+	/* todo: update wmm, ht cap */
+	if (pmlmepriv->qospriv.qos_option)
+		pmlmeinfo->WMM_enable = true;
+	if (pmlmepriv->htpriv.ht_option) {
+		pmlmeinfo->WMM_enable = true;
+		pmlmeinfo->HT_enable = true;
+
+		update_hw_ht_param(padapter);
+	}
+
+	if (pmlmepriv->cur_network.join_res != true) { /* setting only at  first time */
+		/* WEP Key will be set before this function, do not clear CAM. */
+		if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) &&
+		    (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
+			flush_all_cam_entry(padapter);	/* clear CAM */
+	}
+
+	/* set MSR to AP_Mode */
+	Set_MSR(padapter, _HW_STATE_AP_);
+
+	/* Set BSSID REG */
+	rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress);
+
+	/* Set EDCA param reg */
+	acparm = 0x002F3217; /*  VO */
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
+	acparm = 0x005E4317; /*  VI */
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
+	acparm = 0x005ea42b;
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
+	acparm = 0x0000A444; /*  BK */
+	rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
+
+	/* Set Security */
+	val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
+	rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+	/* Beacon Control related register */
+	rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
+
+	UpdateBrateTbl(padapter, pnetwork->SupportedRates);
+	rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+	if (!pmlmepriv->cur_network.join_res) { /* setting only at  first time */
+		/* turn on all dynamic functions */
+		Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+	}
+	/* set channel, bwmode */
+	p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fixed_ie)));
+	if (p && ie_len) {
+		pht_info = (struct HT_info_element *)(p+2);
+
+		if ((pregpriv->cbw40_enable) &&	 (pht_info->infos[0] & BIT(2))) {
+			/* switch to the 40M Hz mode */
+			cur_bwmode = HT_CHANNEL_WIDTH_40;
+			switch (pht_info->infos[0] & 0x3) {
+			case 1:
+				cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+				break;
+			case 3:
+				cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+				break;
+			default:
+				cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+				break;
+			}
+		}
+	}
+	/* TODO: need to judge the phy parameters on concurrent mode for single phy */
+	set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode);
+
+	DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset);
+
+	/*  */
+	pmlmeext->cur_channel = cur_channel;
+	pmlmeext->cur_bwmode = cur_bwmode;
+	pmlmeext->cur_ch_offset = cur_ch_offset;
+	pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type;
+
+	/* update cur_wireless_mode */
+	update_wireless_mode(padapter);
+
+	/* udpate capability after cur_wireless_mode updated */
+	update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork));
+
+	/* let pnetwork_mlmeext == pnetwork_mlme. */
+	memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+
+#ifdef CONFIG_88EU_P2P
+	memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength);
+	pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength;
+#endif /* CONFIG_88EU_P2P */
+
+	if (pmlmeext->bstart_bss) {
+		update_beacon(padapter, _TIM_IE_, NULL, false);
+
+		/* issue beacon frame */
+		if (send_beacon(padapter) == _FAIL)
+			DBG_88E("issue_beacon, fail!\n");
+	}
+
+	/* update bc/mc sta_info */
+	update_bmc_sta(padapter);
+}
+
+int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len)
+{
+	int ret = _SUCCESS;
+	u8 *p;
+	u8 *pHT_caps_ie = NULL;
+	u8 *pHT_info_ie = NULL;
+	struct sta_info *psta = NULL;
+	u16 cap, ht_cap = false;
+	uint ie_len = 0;
+	int group_cipher, pairwise_cipher;
+	u8	channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX];
+	int supportRateNum = 0;
+	u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01};
+	u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+	u8 *ie = pbss_network->IEs;
+
+	/* SSID */
+	/* Supported rates */
+	/* DS Params */
+	/* WLAN_EID_COUNTRY */
+	/* ERP Information element */
+	/* Extended supported rates */
+	/* WPA/WPA2 */
+	/* Wi-Fi Wireless Multimedia Extensions */
+	/* ht_capab, ht_oper */
+	/* WPS IE */
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return _FAIL;
+
+
+	if (len > MAX_IE_SZ)
+		return _FAIL;
+
+	pbss_network->IELength = len;
+
+	_rtw_memset(ie, 0, MAX_IE_SZ);
+
+	memcpy(ie, pbuf, pbss_network->IELength);
+
+
+	if (pbss_network->InfrastructureMode != Ndis802_11APMode)
+		return _FAIL;
+
+	pbss_network->Rssi = 0;
+
+	memcpy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+	/* beacon interval */
+	p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+	pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p);
+
+	/* capability */
+	cap = RTW_GET_LE16(ie);
+
+	/* SSID */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		_rtw_memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+		memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len);
+		pbss_network->Ssid.SsidLength = ie_len;
+	}
+
+	/* channel */
+	channel = 0;
+	pbss_network->Configuration.Length = 0;
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		channel = *(p + 2);
+
+	pbss_network->Configuration.DSConfig = channel;
+
+	_rtw_memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX);
+	/*  get supported rates */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p !=  NULL) {
+		memcpy(supportRate, p+2, ie_len);
+		supportRateNum = ie_len;
+	}
+
+	/* get ext_supported rates */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
+	if (p !=  NULL) {
+		memcpy(supportRate+supportRateNum, p+2, ie_len);
+		supportRateNum += ie_len;
+	}
+
+	network_type = rtw_check_network_type(supportRate, supportRateNum, channel);
+
+	rtw_set_supported_rate(pbss_network->SupportedRates, network_type);
+
+	/* parsing ERP_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		ERP_IE_handler(padapter, (struct ndis_802_11_var_ie *)p);
+
+	/* update privacy/security */
+	if (cap & BIT(4))
+		pbss_network->Privacy = 1;
+	else
+		pbss_network->Privacy = 0;
+
+	psecuritypriv->wpa_psk = 0;
+
+	/* wpa2 */
+	group_cipher = 0;
+	pairwise_cipher = 0;
+	psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+	psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		if (rtw_parse_wpa2_ie(p, ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+			psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
+			psecuritypriv->wpa_psk |= BIT(1);
+
+			psecuritypriv->wpa2_group_cipher = group_cipher;
+			psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;
+		}
+	}
+	/* wpa */
+	ie_len = 0;
+	group_cipher = 0;
+	pairwise_cipher = 0;
+	psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+	psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+	for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
+		p = rtw_get_ie(p, _SSN_IE_1_, &ie_len,
+			       (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+		if ((p) && (_rtw_memcmp(p+2, OUI1, 4))) {
+			if (rtw_parse_wpa_ie(p, ie_len+2, &group_cipher,
+					     &pairwise_cipher, NULL) == _SUCCESS) {
+				psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+				psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
+
+				psecuritypriv->wpa_psk |= BIT(0);
+
+				psecuritypriv->wpa_group_cipher = group_cipher;
+				psecuritypriv->wpa_pairwise_cipher = pairwise_cipher;
+			}
+			break;
+		}
+		if ((p == NULL) || (ie_len == 0))
+			break;
+	}
+
+	/* wmm */
+	ie_len = 0;
+	pmlmepriv->qospriv.qos_option = 0;
+	if (pregistrypriv->wmm_enable) {
+		for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) {
+			p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len,
+				       (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+			if ((p) && _rtw_memcmp(p+2, WMM_PARA_IE, 6)) {
+				pmlmepriv->qospriv.qos_option = 1;
+
+				*(p+8) |= BIT(7);/* QoS Info, support U-APSD */
+
+				/* disable all ACM bits since the WMM admission control is not supported */
+				*(p + 10) &= ~BIT(4); /* BE */
+				*(p + 14) &= ~BIT(4); /* BK */
+				*(p + 18) &= ~BIT(4); /* VI */
+				*(p + 22) &= ~BIT(4); /* VO */
+				break;
+			}
+
+			if ((p == NULL) || (ie_len == 0))
+				break;
+		}
+	}
+	/* parsing HT_CAP_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len,
+		       (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0) {
+		u8 rf_type;
+		struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p+2);
+
+		pHT_caps_ie = p;
+		ht_cap = true;
+		network_type |= WIRELESS_11_24N;
+
+		rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+		if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
+		    (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
+			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+		else
+			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
+
+		/* set  Max Rx AMPDU size  to 64K */
+		pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & 0x03);
+
+		if (rf_type == RF_1T1R) {
+			pht_cap->supp_mcs_set[0] = 0xff;
+			pht_cap->supp_mcs_set[1] = 0x0;
+		}
+		memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
+	}
+
+	/* parsing HT_INFO_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len,
+		       (pbss_network->IELength - _BEACON_IE_OFFSET_));
+	if (p && ie_len > 0)
+		pHT_info_ie = p;
+	switch (network_type) {
+	case WIRELESS_11B:
+		pbss_network->NetworkTypeInUse = Ndis802_11DS;
+		break;
+	case WIRELESS_11G:
+	case WIRELESS_11BG:
+	case WIRELESS_11G_24N:
+	case WIRELESS_11BG_24N:
+		pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+		break;
+	case WIRELESS_11A:
+		pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
+		break;
+	default:
+		pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+		break;
+	}
+
+	pmlmepriv->cur_network.network_type = network_type;
+
+	pmlmepriv->htpriv.ht_option = false;
+
+	if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
+	    (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
+		/* todo: */
+		/* ht_cap = false; */
+	}
+
+	/* ht_cap */
+	if (pregistrypriv->ht_enable && ht_cap) {
+		pmlmepriv->htpriv.ht_option = true;
+		pmlmepriv->qospriv.qos_option = 1;
+
+		if (pregistrypriv->ampdu_enable == 1)
+			pmlmepriv->htpriv.ampdu_enable = true;
+		HT_caps_handler(padapter, (struct ndis_802_11_var_ie *)pHT_caps_ie);
+
+		HT_info_handler(padapter, (struct ndis_802_11_var_ie *)pHT_info_ie);
+	}
+
+	pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex  *)pbss_network);
+
+	/* issue beacon to start bss network */
+	start_bss_network(padapter, (u8 *)pbss_network);
+
+	/* alloc sta_info for ap itself */
+	psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+	if (!psta) {
+		psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
+		if (psta == NULL)
+			return _FAIL;
+	}
+
+	pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */
+	return ret;
+}
+
+void rtw_set_macaddr_acl(struct adapter *padapter, int mode)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+	DBG_88E("%s, mode =%d\n", __func__, mode);
+
+	pacl_list->mode = mode;
+}
+
+int rtw_acl_add_sta(struct adapter *padapter, u8 *addr)
+{
+	unsigned long irqL;
+	struct list_head *plist, *phead;
+	u8 added = false;
+	int i, ret = 0;
+	struct rtw_wlan_acl_node *paclnode;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+	DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
+	if ((NUM_ACL-1) < pacl_list->num)
+		return -1;
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);
+
+	while (!rtw_end_of_queue_search(phead, plist)) {
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+			if (paclnode->valid) {
+				added = true;
+				DBG_88E("%s, sta has been added\n", __func__);
+				break;
+			}
+		}
+	}
+
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	if (added)
+		return ret;
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	for (i = 0; i < NUM_ACL; i++) {
+		paclnode = &pacl_list->aclnode[i];
+
+		if (!paclnode->valid) {
+			_rtw_init_listhead(&paclnode->list);
+
+			memcpy(paclnode->addr, addr, ETH_ALEN);
+
+			paclnode->valid = true;
+
+			rtw_list_insert_tail(&paclnode->list, get_list_head(pacl_node_q));
+
+			pacl_list->num++;
+
+			break;
+		}
+	}
+
+	DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	return ret;
+}
+
+int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr)
+{
+	unsigned long irqL;
+	struct list_head *plist, *phead;
+	int ret = 0;
+	struct rtw_wlan_acl_node *paclnode;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+	DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);
+
+	while (!rtw_end_of_queue_search(phead, plist)) {
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if (_rtw_memcmp(paclnode->addr, addr, ETH_ALEN)) {
+			if (paclnode->valid) {
+				paclnode->valid = false;
+
+				rtw_list_delete(&paclnode->list);
+
+				pacl_list->num--;
+			}
+		}
+	}
+
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
+	return ret;
+}
+
+static void update_bcn_fixed_ie(struct adapter *padapter)
+{
+	DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_erpinfo_ie(struct adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+	unsigned char *p, *ie = pnetwork->IEs;
+	u32 len = 0;
+
+	DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable);
+
+	if (!pmlmeinfo->ERP_enable)
+		return;
+
+	/* parsing ERP_IE */
+	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len,
+		       (pnetwork->IELength - _BEACON_IE_OFFSET_));
+	if (p && len > 0) {
+		struct ndis_802_11_var_ie *pIE = (struct ndis_802_11_var_ie *)p;
+
+		if (pmlmepriv->num_sta_non_erp == 1)
+			pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION;
+		else
+			pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT|RTW_ERP_INFO_USE_PROTECTION);
+
+		if (pmlmepriv->num_sta_no_short_preamble > 0)
+			pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE;
+		else
+			pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE);
+
+		ERP_IE_handler(padapter, pIE);
+	}
+}
+
+static void update_bcn_htcap_ie(struct adapter *padapter)
+{
+	DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_htinfo_ie(struct adapter *padapter)
+{
+	DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_rsn_ie(struct adapter *padapter)
+{
+	DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wpa_ie(struct adapter *padapter)
+{
+	DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wmm_ie(struct adapter *padapter)
+{
+	DBG_88E("%s\n", __func__);
+}
+
+static void update_bcn_wps_ie(struct adapter *padapter)
+{
+	u8 *pwps_ie = NULL, *pwps_ie_src;
+	u8 *premainder_ie, *pbackup_remainder_ie = NULL;
+	uint wps_ielen = 0, wps_offset, remainder_ielen;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+	unsigned char *ie = pnetwork->IEs;
+	u32 ielen = pnetwork->IELength;
+
+	DBG_88E("%s\n", __func__);
+
+	pwps_ie = rtw_get_wps_ie(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+	if (pwps_ie == NULL || wps_ielen == 0)
+		return;
+
+	wps_offset = (uint)(pwps_ie-ie);
+
+	premainder_ie = pwps_ie + wps_ielen;
+
+	remainder_ielen = ielen - wps_offset - wps_ielen;
+
+	if (remainder_ielen > 0) {
+		pbackup_remainder_ie = rtw_malloc(remainder_ielen);
+		if (pbackup_remainder_ie)
+			memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+	}
+
+	pwps_ie_src = pmlmepriv->wps_beacon_ie;
+	if (pwps_ie_src == NULL)
+		return;
+
+	wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
+	if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) {
+		memcpy(pwps_ie, pwps_ie_src, wps_ielen+2);
+		pwps_ie += (wps_ielen+2);
+
+		if (pbackup_remainder_ie)
+			memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+		/* update IELength */
+		pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
+	}
+
+	if (pbackup_remainder_ie)
+		kfree(pbackup_remainder_ie);
+}
+
+static void update_bcn_p2p_ie(struct adapter *padapter)
+{
+}
+
+static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui)
+{
+	DBG_88E("%s\n", __func__);
+
+	if (_rtw_memcmp(RTW_WPA_OUI, oui, 4))
+		update_bcn_wpa_ie(padapter);
+	else if (_rtw_memcmp(WMM_OUI, oui, 4))
+		update_bcn_wmm_ie(padapter);
+	else if (_rtw_memcmp(WPS_OUI, oui, 4))
+		update_bcn_wps_ie(padapter);
+	else if (_rtw_memcmp(P2P_OUI, oui, 4))
+		update_bcn_p2p_ie(padapter);
+	else
+		DBG_88E("unknown OUI type!\n");
+}
+
+void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
+{
+	unsigned long irqL;
+	struct mlme_priv *pmlmepriv;
+	struct mlme_ext_priv	*pmlmeext;
+
+	if (!padapter)
+		return;
+
+	pmlmepriv = &(padapter->mlmepriv);
+	pmlmeext = &(padapter->mlmeextpriv);
+
+	if (!pmlmeext->bstart_bss)
+		return;
+
+	_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	switch (ie_id) {
+	case 0xFF:
+		update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+		break;
+	case _TIM_IE_:
+		update_BCNTIM(padapter);
+		break;
+	case _ERPINFO_IE_:
+		update_bcn_erpinfo_ie(padapter);
+		break;
+	case _HT_CAPABILITY_IE_:
+		update_bcn_htcap_ie(padapter);
+		break;
+	case _RSN_IE_2_:
+		update_bcn_rsn_ie(padapter);
+		break;
+	case _HT_ADD_INFO_IE_:
+		update_bcn_htinfo_ie(padapter);
+		break;
+	case _VENDOR_SPECIFIC_IE_:
+		update_bcn_vendor_spec_ie(padapter, oui);
+		break;
+	default:
+		break;
+	}
+
+	pmlmepriv->update_bcn = true;
+
+	_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+
+	if (tx)
+		set_tx_beacon_cmd(padapter);
+}
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+	in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+	however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+	(currently non-GF HT station is considered as non-HT STA also)
+*/
+static int rtw_ht_operation_update(struct adapter *padapter)
+{
+	u16 cur_op_mode, new_op_mode;
+	int op_mode_changes = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct ht_priv	*phtpriv_ap = &pmlmepriv->htpriv;
+
+	if (pmlmepriv->htpriv.ht_option)
+		return 0;
+
+	DBG_88E("%s current operation mode = 0x%X\n",
+		__func__, pmlmepriv->ht_op_mode);
+
+	if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+	    pmlmepriv->num_sta_ht_no_gf) {
+		pmlmepriv->ht_op_mode |=
+			HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	} else if ((pmlmepriv->ht_op_mode &
+		   HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+		   pmlmepriv->num_sta_ht_no_gf == 0) {
+		pmlmepriv->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	}
+
+	if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+	    (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) {
+		pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	} else if ((pmlmepriv->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+		   (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) {
+		pmlmepriv->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	}
+
+	/* Note: currently we switch to the MIXED op mode if HT non-greenfield
+	 * station is associated. Probably it's a theoretical case, since
+	 * it looks like all known HT STAs support greenfield.
+	 */
+	new_op_mode = 0;
+	if (pmlmepriv->num_sta_no_ht ||
+	    (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+		new_op_mode = OP_MODE_MIXED;
+	else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH) &&
+		 pmlmepriv->num_sta_ht_20mhz)
+		new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+	else if (pmlmepriv->olbc_ht)
+		new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+	else
+		new_op_mode = OP_MODE_PURE;
+
+	cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+	if (cur_op_mode != new_op_mode) {
+		pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+		pmlmepriv->ht_op_mode |= new_op_mode;
+		op_mode_changes++;
+	}
+
+	DBG_88E("%s new operation mode = 0x%X changes =%d\n",
+		__func__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+	return op_mode_changes;
+}
+
+void associated_clients_update(struct adapter *padapter, u8 updated)
+{
+	/* update associcated stations cap. */
+	if (updated) {
+		unsigned long irqL;
+		struct list_head *phead, *plist;
+		struct sta_info *psta = NULL;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		phead = &pstapriv->asoc_list;
+		plist = get_next(phead);
+
+		/* check asoc_queue */
+		while ((rtw_end_of_queue_search(phead, plist)) == false) {
+			psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+			plist = get_next(plist);
+
+			VCS_update(padapter, psta);
+		}
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	}
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
+{
+	u8 beacon_updated = false;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+	if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) {
+		if (!psta->no_short_preamble_set) {
+			psta->no_short_preamble_set = 1;
+
+			pmlmepriv->num_sta_no_short_preamble++;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_preamble == 1)) {
+				beacon_updated = true;
+				update_beacon(padapter, 0xFF, NULL, true);
+			}
+		}
+	} else {
+		if (psta->no_short_preamble_set) {
+			psta->no_short_preamble_set = 0;
+
+			pmlmepriv->num_sta_no_short_preamble--;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_preamble == 0)) {
+				beacon_updated = true;
+				update_beacon(padapter, 0xFF, NULL, true);
+			}
+		}
+	}
+
+	if (psta->flags & WLAN_STA_NONERP) {
+		if (!psta->nonerp_set) {
+			psta->nonerp_set = 1;
+
+			pmlmepriv->num_sta_non_erp++;
+
+			if (pmlmepriv->num_sta_non_erp == 1) {
+				beacon_updated = true;
+				update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+			}
+		}
+	} else {
+		if (psta->nonerp_set) {
+			psta->nonerp_set = 0;
+
+			pmlmepriv->num_sta_non_erp--;
+
+			if (pmlmepriv->num_sta_non_erp == 0) {
+				beacon_updated = true;
+				update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+			}
+		}
+	}
+
+	if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) {
+		if (!psta->no_short_slot_time_set) {
+			psta->no_short_slot_time_set = 1;
+
+			pmlmepriv->num_sta_no_short_slot_time++;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_slot_time == 1)) {
+				beacon_updated = true;
+				update_beacon(padapter, 0xFF, NULL, true);
+			}
+		}
+	} else {
+		if (psta->no_short_slot_time_set) {
+			psta->no_short_slot_time_set = 0;
+
+			pmlmepriv->num_sta_no_short_slot_time--;
+
+			if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+			    (pmlmepriv->num_sta_no_short_slot_time == 0)) {
+				beacon_updated = true;
+				update_beacon(padapter, 0xFF, NULL, true);
+			}
+		}
+	}
+
+	if (psta->flags & WLAN_STA_HT) {
+		u16 ht_capab = psta->htpriv.ht_cap.cap_info;
+
+		DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n",
+			(psta->hwaddr), ht_capab);
+
+		if (psta->no_ht_set) {
+			psta->no_ht_set = 0;
+			pmlmepriv->num_sta_no_ht--;
+		}
+
+		if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) {
+			if (!psta->no_ht_gf_set) {
+				psta->no_ht_gf_set = 1;
+				pmlmepriv->num_sta_ht_no_gf++;
+			}
+			DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n",
+				   __func__, (psta->hwaddr),
+				   pmlmepriv->num_sta_ht_no_gf);
+		}
+
+		if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) {
+			if (!psta->ht_20mhz_set) {
+				psta->ht_20mhz_set = 1;
+				pmlmepriv->num_sta_ht_20mhz++;
+			}
+			DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n",
+				   __func__, (psta->hwaddr),
+				   pmlmepriv->num_sta_ht_20mhz);
+		}
+	} else {
+		if (!psta->no_ht_set) {
+			psta->no_ht_set = 1;
+			pmlmepriv->num_sta_no_ht++;
+		}
+		if (pmlmepriv->htpriv.ht_option) {
+			DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n",
+				__func__, (psta->hwaddr),
+				pmlmepriv->num_sta_no_ht);
+		}
+	}
+
+	if (rtw_ht_operation_update(padapter) > 0) {
+		update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
+	}
+
+	/* update associcated stations cap. */
+	associated_clients_update(padapter,  beacon_updated);
+
+	DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
+}
+
+u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
+{
+	u8 beacon_updated = false;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+	if (!psta)
+		return beacon_updated;
+
+	if (psta->no_short_preamble_set) {
+		psta->no_short_preamble_set = 0;
+		pmlmepriv->num_sta_no_short_preamble--;
+		if (pmlmeext->cur_wireless_mode > WIRELESS_11B &&
+		    pmlmepriv->num_sta_no_short_preamble == 0) {
+			beacon_updated = true;
+			update_beacon(padapter, 0xFF, NULL, true);
+		}
+	}
+
+	if (psta->nonerp_set) {
+		psta->nonerp_set = 0;
+		pmlmepriv->num_sta_non_erp--;
+		if (pmlmepriv->num_sta_non_erp == 0) {
+			beacon_updated = true;
+			update_beacon(padapter, _ERPINFO_IE_, NULL, true);
+		}
+	}
+
+	if (psta->no_short_slot_time_set) {
+		psta->no_short_slot_time_set = 0;
+		pmlmepriv->num_sta_no_short_slot_time--;
+		if (pmlmeext->cur_wireless_mode > WIRELESS_11B &&
+		    pmlmepriv->num_sta_no_short_slot_time == 0) {
+			beacon_updated = true;
+			update_beacon(padapter, 0xFF, NULL, true);
+		}
+	}
+
+	if (psta->no_ht_gf_set) {
+		psta->no_ht_gf_set = 0;
+		pmlmepriv->num_sta_ht_no_gf--;
+	}
+
+	if (psta->no_ht_set) {
+		psta->no_ht_set = 0;
+		pmlmepriv->num_sta_no_ht--;
+	}
+
+	if (psta->ht_20mhz_set) {
+		psta->ht_20mhz_set = 0;
+		pmlmepriv->num_sta_ht_20mhz--;
+	}
+
+	if (rtw_ht_operation_update(padapter) > 0) {
+		update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false);
+		update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true);
+	}
+
+	/* update associcated stations cap. */
+
+	DBG_88E("%s, updated =%d\n", __func__, beacon_updated);
+
+	return beacon_updated;
+}
+
+u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
+	       bool active, u16 reason)
+{
+	unsigned long irqL;
+	u8 beacon_updated = false;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	if (!psta)
+		return beacon_updated;
+
+	/* tear down Rx AMPDU */
+	send_delba(padapter, 0, psta->hwaddr);/*  recipient */
+
+	/* tear down TX AMPDU */
+	send_delba(padapter, 1, psta->hwaddr);/*  originator */
+	psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+	psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+	if (active)
+		issue_deauth(padapter, psta->hwaddr, reason);
+
+	/* clear cam entry / key */
+	rtw_clearstakey_cmd(padapter, (u8 *)psta, (u8)(psta->mac_id + 3), true);
+
+
+	_enter_critical_bh(&psta->lock, &irqL);
+	psta->state &= ~_FW_LINKED;
+	_exit_critical_bh(&psta->lock, &irqL);
+
+	rtw_indicate_sta_disassoc_event(padapter, psta);
+
+	report_del_sta_event(padapter, psta->hwaddr, reason);
+
+	beacon_updated = bss_cap_update_on_sta_leave(padapter, psta);
+
+	_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+	rtw_free_stainfo(padapter, psta);
+	_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+	return beacon_updated;
+}
+
+int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+	unsigned long irqL;
+	struct list_head *phead, *plist;
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		return ret;
+
+	DBG_88E(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* for each sta in asoc_queue */
+	while (!rtw_end_of_queue_search(phead, plist)) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+		plist = get_next(plist);
+
+		issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset);
+		psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset);
+
+	return ret;
+}
+
+int rtw_sta_flush(struct adapter *padapter)
+{
+	unsigned long irqL;
+	struct list_head *phead, *plist;
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		return ret;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* free sta asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == false) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+		plist = get_next(plist);
+
+		rtw_list_delete(&psta->asoc_list);
+		pstapriv->asoc_list_cnt--;
+
+		ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+
+	issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+	associated_clients_update(padapter, true);
+
+	return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update(struct adapter *padapter, struct sta_info *psta)
+{
+	int flags = psta->flags;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	/* update wmm cap. */
+	if (WLAN_STA_WME&flags)
+		psta->qos_option = 1;
+	else
+		psta->qos_option = 0;
+
+	if (pmlmepriv->qospriv.qos_option == 0)
+		psta->qos_option = 0;
+
+	/* update 802.11n ht cap. */
+	if (WLAN_STA_HT&flags) {
+		psta->htpriv.ht_option = true;
+		psta->qos_option = 1;
+	} else {
+		psta->htpriv.ht_option = false;
+	}
+
+	if (!pmlmepriv->htpriv.ht_option)
+		psta->htpriv.ht_option = false;
+
+	update_sta_info_apmode(padapter, psta);
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta)
+{
+	if (psta->state & _FW_LINKED) {
+		/* add ratid */
+		add_RATid(padapter, psta, 0);/* DM_RATR_STA_INIT */
+	}
+}
+
+void start_ap_mode(struct adapter *padapter)
+{
+	int i;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+	pmlmepriv->update_bcn = false;
+
+	pmlmeext->bstart_bss = false;
+
+	pmlmepriv->num_sta_non_erp = 0;
+
+	pmlmepriv->num_sta_no_short_slot_time = 0;
+
+	pmlmepriv->num_sta_no_short_preamble = 0;
+
+	pmlmepriv->num_sta_ht_no_gf = 0;
+	pmlmepriv->num_sta_no_ht = 0;
+	pmlmepriv->num_sta_ht_20mhz = 0;
+
+	pmlmepriv->olbc = false;
+
+	pmlmepriv->olbc_ht = false;
+
+	pmlmepriv->ht_op_mode = 0;
+
+	for (i = 0; i < NUM_STA; i++)
+		pstapriv->sta_aid[i] = NULL;
+
+	pmlmepriv->wps_beacon_ie = NULL;
+	pmlmepriv->wps_probe_resp_ie = NULL;
+	pmlmepriv->wps_assoc_resp_ie = NULL;
+
+	pmlmepriv->p2p_beacon_ie = NULL;
+	pmlmepriv->p2p_probe_resp_ie = NULL;
+
+	/* for ACL */
+	_rtw_init_listhead(&(pacl_list->acl_node_q.queue));
+	pacl_list->num = 0;
+	pacl_list->mode = 0;
+	for (i = 0; i < NUM_ACL; i++) {
+		_rtw_init_listhead(&pacl_list->aclnode[i].list);
+		pacl_list->aclnode[i].valid = false;
+	}
+}
+
+void stop_ap_mode(struct adapter *padapter)
+{
+	unsigned long irqL;
+	struct list_head *phead, *plist;
+	struct rtw_wlan_acl_node *paclnode;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+	pmlmepriv->update_bcn = false;
+	pmlmeext->bstart_bss = false;
+
+	/* reset and init security priv , this can refine with rtw_reset_securitypriv */
+	_rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv));
+	padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+	padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+	/* for ACL */
+	_enter_critical_bh(&(pacl_node_q->lock), &irqL);
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);
+	while ((rtw_end_of_queue_search(phead, plist)) == false) {
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if (paclnode->valid) {
+			paclnode->valid = false;
+
+			rtw_list_delete(&paclnode->list);
+
+			pacl_list->num--;
+		}
+	}
+	_exit_critical_bh(&(pacl_node_q->lock), &irqL);
+
+	DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
+
+	rtw_sta_flush(padapter);
+
+	/* free_assoc_sta_resources */
+	rtw_free_all_stainfo(padapter);
+
+	psta = rtw_get_bcmc_stainfo(padapter);
+	_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+	rtw_free_stainfo(padapter, psta);
+	_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);
+
+	rtw_init_bcmc_stainfo(padapter);
+
+	rtw_free_mlme_priv_ie_data(pmlmepriv);
+}
+
+#endif /* CONFIG_88EU_AP_MODE */
diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
new file mode 100644
index 0000000..fbca394
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_br_ext.c
@@ -0,0 +1,1199 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_BR_EXT_C_
+
+#include <linux/if_arp.h>
+#include <net/ip.h>
+#include <net/ipx.h>
+#include <linux/atalk.h>
+#include <linux/udp.h>
+#include <linux/if_pppox.h>
+
+#include <drv_types.h>
+#include "rtw_br_ext.h"
+#include <usb_osintf.h>
+#include <recv_osdep.h>
+
+#ifndef csum_ipv6_magic
+#include <net/ip6_checksum.h>
+#endif
+
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <net/ndisc.h>
+#include <net/checksum.h>
+
+#define NAT25_IPV4		01
+#define NAT25_IPV6		02
+#define NAT25_IPX		03
+#define NAT25_APPLE		04
+#define NAT25_PPPOE		05
+
+#define RTL_RELAY_TAG_LEN (ETH_ALEN)
+#define TAG_HDR_LEN		4
+
+#define MAGIC_CODE		0x8186
+#define MAGIC_CODE_LEN	2
+#define WAIT_TIME_PPPOE	5	/*  waiting time for pppoe server in sec */
+
+/*-----------------------------------------------------------------
+  How database records network address:
+	   0    1    2    3    4    5    6    7    8    9   10
+	|----|----|----|----|----|----|----|----|----|----|----|
+  IPv4  |type|                             |      IP addr      |
+  IPX   |type|      Net addr     |          Node addr          |
+  IPX   |type|      Net addr     |Sckt addr|
+  Apple |type| Network |node|
+  PPPoE |type|   SID   |           AC MAC            |
+-----------------------------------------------------------------*/
+
+
+/* Find a tag in pppoe frame and return the pointer */
+static inline unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
+{
+	unsigned char *cur_ptr, *start_ptr;
+	unsigned short tagLen, tagType;
+
+	start_ptr = cur_ptr = (unsigned char *)ph->tag;
+	while ((cur_ptr - start_ptr) < ntohs(ph->length)) {
+		/*  prevent un-alignment access */
+		tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
+		tagLen  = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
+		if (tagType == type)
+			return cur_ptr;
+		cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
+	}
+	return NULL;
+}
+
+
+static inline int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
+{
+	struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+	int data_len;
+
+	data_len = tag->tag_len + TAG_HDR_LEN;
+	if (skb_tailroom(skb) < data_len) {
+		_DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
+		return -1;
+	}
+
+	skb_put(skb, data_len);
+	/*  have a room for new tag */
+	memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
+	ph->length = htons(ntohs(ph->length) + data_len);
+	memcpy((unsigned char *)ph->tag, tag, data_len);
+	return data_len;
+}
+
+static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
+{
+	int tail_len;
+	unsigned long end, tail;
+
+	if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
+		return -1;
+
+	tail = (unsigned long)skb_tail_pointer(skb);
+	end = (unsigned long)src+len;
+	if (tail < end)
+		return -1;
+
+	tail_len = (int)(tail-end);
+	if (tail_len > 0)
+		memmove(src, src+len, tail_len);
+
+	skb_trim(skb, skb->len-len);
+	return 0;
+}
+
+static inline unsigned long __nat25_timeout(struct adapter *priv)
+{
+	unsigned long timeout;
+
+	timeout = jiffies - NAT25_AGEING_TIME*HZ;
+
+	return timeout;
+}
+
+
+static inline int  __nat25_has_expired(struct adapter *priv,
+				struct nat25_network_db_entry *fdb)
+{
+	if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
+		return 1;
+
+	return 0;
+}
+
+
+static inline void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
+				unsigned int *ipAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPV4;
+	memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
+}
+
+
+static inline void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr,
+				unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPX;
+	memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+	memcpy(networkAddr+5, ipxNodeAddr, 6);
+}
+
+
+static inline void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr,
+				unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPX;
+	memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
+	memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2);
+}
+
+
+static inline void __nat25_generate_apple_network_addr(unsigned char *networkAddr,
+				unsigned short *network, unsigned char *node)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_APPLE;
+	memcpy(networkAddr+1, (unsigned char *)network, 2);
+	networkAddr[3] = *node;
+}
+
+static inline void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
+				unsigned char *ac_mac, unsigned short *sid)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_PPPOE;
+	memcpy(networkAddr+1, (unsigned char *)sid, 2);
+	memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
+}
+
+static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
+				unsigned int *ipAddr)
+{
+	memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
+
+	networkAddr[0] = NAT25_IPV6;
+	memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
+}
+
+static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
+{
+	while (len > 0) {
+		if (*data == tag && *(data+1) == len8b && len >= len8b*8)
+			return data+2;
+
+		len -= (*(data+1))*8;
+		data += (*(data+1))*8;
+	}
+	return NULL;
+}
+
+static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
+{
+	struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
+	unsigned char *mac;
+
+	if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
+		if (len >= 8) {
+			mac = scan_tlv(&data[8], len-8, 1, 1);
+			if (mac) {
+				_DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
+		if (len >= 16) {
+			mac = scan_tlv(&data[16], len-16, 1, 1);
+			if (mac) {
+				_DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
+		if (len >= 24) {
+			mac = scan_tlv(&data[24], len-24, 1, 1);
+			if (mac) {
+				_DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
+		if (len >= 24) {
+			mac = scan_tlv(&data[24], len-24, 2, 1);
+			if (mac) {
+				_DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	} else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
+		if (len >= 40) {
+			mac = scan_tlv(&data[40], len-40, 2, 1);
+			if (mac) {
+				_DEBUG_INFO("Redirect,  replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+					replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
+				memcpy(mac, replace_mac, 6);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static inline int __nat25_network_hash(unsigned char *networkAddr)
+{
+	if (networkAddr[0] == NAT25_IPV4) {
+		unsigned long x;
+
+		x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_IPX) {
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+			networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_APPLE) {
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_PPPOE) {
+		unsigned long x;
+
+		x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else if (networkAddr[0] == NAT25_IPV6) {
+		unsigned long x;
+
+		x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
+			networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
+			networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
+			networkAddr[16];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	} else {
+		unsigned long x = 0;
+		int i;
+
+		for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
+			x ^= networkAddr[i];
+
+		return x & (NAT25_HASH_SIZE - 1);
+	}
+}
+
+static inline void __network_hash_link(struct adapter *priv,
+				struct nat25_network_db_entry *ent, int hash)
+{
+	/*  Caller must _enter_critical_bh already! */
+	ent->next_hash = priv->nethash[hash];
+	if (ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = &ent->next_hash;
+	priv->nethash[hash] = ent;
+	ent->pprev_hash = &priv->nethash[hash];
+}
+
+static inline void __network_hash_unlink(struct nat25_network_db_entry *ent)
+{
+	/*  Caller must _enter_critical_bh already! */
+	*(ent->pprev_hash) = ent->next_hash;
+	if (ent->next_hash != NULL)
+		ent->next_hash->pprev_hash = ent->pprev_hash;
+	ent->next_hash = NULL;
+	ent->pprev_hash = NULL;
+}
+
+static int __nat25_db_network_lookup_and_replace(struct adapter *priv,
+				struct sk_buff *skb, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	unsigned long irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	db = priv->nethash[__nat25_network_hash(networkAddr)];
+	while (db != NULL) {
+		if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			if (!__nat25_has_expired(priv, db)) {
+				/*  replace the destination mac address */
+				memcpy(skb->data, db->macAddr, ETH_ALEN);
+				atomic_inc(&db->use_count);
+
+				DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+							"%02x%02x%02x%02x%02x%02x\n",
+					db->macAddr[0],
+					db->macAddr[1],
+					db->macAddr[2],
+					db->macAddr[3],
+					db->macAddr[4],
+					db->macAddr[5],
+					db->networkAddr[0],
+					db->networkAddr[1],
+					db->networkAddr[2],
+					db->networkAddr[3],
+					db->networkAddr[4],
+					db->networkAddr[5],
+					db->networkAddr[6],
+					db->networkAddr[7],
+					db->networkAddr[8],
+					db->networkAddr[9],
+					db->networkAddr[10],
+					db->networkAddr[11],
+					db->networkAddr[12],
+					db->networkAddr[13],
+					db->networkAddr[14],
+					db->networkAddr[15],
+					db->networkAddr[16]);
+			}
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return 1;
+		}
+		db = db->next_hash;
+	}
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+	return 0;
+}
+
+static void __nat25_db_network_insert(struct adapter *priv,
+				unsigned char *macAddr, unsigned char *networkAddr)
+{
+	struct nat25_network_db_entry *db;
+	int hash;
+	unsigned long irqL;
+
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+	hash = __nat25_network_hash(networkAddr);
+	db = priv->nethash[hash];
+	while (db != NULL) {
+		if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			memcpy(db->macAddr, macAddr, ETH_ALEN);
+			db->ageing_timer = jiffies;
+			_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			return;
+		}
+		db = db->next_hash;
+	}
+	db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db));
+	if (db == NULL) {
+		_exit_critical_bh(&priv->br_ext_lock, &irqL);
+		return;
+	}
+	memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
+	memcpy(db->macAddr, macAddr, ETH_ALEN);
+	atomic_set(&db->use_count, 1);
+	db->ageing_timer = jiffies;
+
+	__network_hash_link(priv, db, hash);
+
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+static void __nat25_db_print(struct adapter *priv)
+{
+}
+
+/*
+ *	NAT2.5 interface
+ */
+
+void nat25_db_cleanup(struct adapter *priv)
+{
+	int i;
+	unsigned long irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	for (i = 0; i < NAT25_HASH_SIZE; i++) {
+		struct nat25_network_db_entry *f;
+		f = priv->nethash[i];
+		while (f != NULL) {
+			struct nat25_network_db_entry *g;
+
+			g = f->next_hash;
+			if (priv->scdb_entry == f) {
+				memset(priv->scdb_mac, 0, ETH_ALEN);
+				memset(priv->scdb_ip, 0, 4);
+				priv->scdb_entry = NULL;
+			}
+			__network_hash_unlink(f);
+			kfree(f);
+			f = g;
+		}
+	}
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+void nat25_db_expire(struct adapter *priv)
+{
+	int i;
+	unsigned long irqL;
+	_enter_critical_bh(&priv->br_ext_lock, &irqL);
+
+	for (i = 0; i < NAT25_HASH_SIZE; i++) {
+		struct nat25_network_db_entry *f;
+		f = priv->nethash[i];
+
+		while (f != NULL) {
+			struct nat25_network_db_entry *g;
+			g = f->next_hash;
+
+			if (__nat25_has_expired(priv, f)) {
+				if (atomic_dec_and_test(&f->use_count)) {
+					if (priv->scdb_entry == f) {
+						memset(priv->scdb_mac, 0, ETH_ALEN);
+						memset(priv->scdb_ip, 0, 4);
+						priv->scdb_entry = NULL;
+					}
+					__network_hash_unlink(f);
+					kfree(f);
+				}
+			}
+			f = g;
+		}
+	}
+	_exit_critical_bh(&priv->br_ext_lock, &irqL);
+}
+
+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
+{
+	unsigned short protocol;
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+	unsigned int tmp;
+
+	if (skb == NULL)
+		return -1;
+
+	if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
+		return -1;
+
+	protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+
+	/*---------------------------------------------------*/
+	/*                 Handle IP frame                   */
+	/*---------------------------------------------------*/
+	if (protocol == ETH_P_IP) {
+		struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+		if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) {
+			DEBUG_WARN("NAT25: malformed IP packet !\n");
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+		case NAT25_INSERT:
+			/* some muticast with source IP is all zero, maybe other case is illegal */
+			/* in class A, B, C, host address is all zero or all one is illegal */
+			if (iph->saddr == 0)
+				return 0;
+			tmp = be32_to_cpu(iph->saddr);
+			DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr);
+			__nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+			/* record source IP address and , source mac address into db */
+			__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+			__nat25_db_print(priv);
+			return 0;
+		case NAT25_LOOKUP:
+			DEBUG_INFO("NAT25: Lookup IP, SA =%08x, DA =%08x\n", iph->saddr, iph->daddr);
+			tmp = be32_to_cpu(iph->daddr);
+			__nat25_generate_ipv4_network_addr(networkAddr, &tmp);
+
+			if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
+				if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
+					/*  L2 is unicast but L3 is broadcast, make L2 bacome broadcast */
+					DEBUG_INFO("NAT25: Set DA as boardcast\n");
+					memset(skb->data, 0xff, ETH_ALEN);
+				} else {
+					/*  forward unknow IP packet to upper TCP/IP */
+					DEBUG_INFO("NAT25: Replace DA with BR's MAC\n");
+					if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) {
+						printk("Re-init netdev_br_init() due to br_mac == 0!\n");
+						netdev_br_init(priv->pnetdev);
+					}
+					memcpy(skb->data, priv->br_mac, ETH_ALEN);
+				}
+			}
+			return 0;
+		default:
+			return -1;
+		}
+	} else if (protocol == ETH_P_ARP) {
+		/*---------------------------------------------------*/
+		/*                 Handle ARP frame                  */
+		/*---------------------------------------------------*/
+		struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
+		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
+		unsigned int *sender, *target;
+
+		if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
+			DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro));
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			return 0;	/*  skb_copy for all ARP frame */
+		case NAT25_INSERT:
+			DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
+				arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
+
+			/*  change to ARP sender mac address to wlan STA address */
+			memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
+			arp_ptr += arp->ar_hln;
+			sender = (unsigned int *)arp_ptr;
+			__nat25_generate_ipv4_network_addr(networkAddr, sender);
+			__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+			__nat25_db_print(priv);
+			return 0;
+		case NAT25_LOOKUP:
+			DEBUG_INFO("NAT25: Lookup ARP\n");
+
+			arp_ptr += arp->ar_hln;
+			sender = (unsigned int *)arp_ptr;
+			arp_ptr += (arp->ar_hln + arp->ar_pln);
+			target = (unsigned int *)arp_ptr;
+			__nat25_generate_ipv4_network_addr(networkAddr, target);
+			__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+			/*  change to ARP target mac address to Lookup result */
+			arp_ptr = (unsigned char *)(arp + 1);
+			arp_ptr += (arp->ar_hln + arp->ar_pln);
+			memcpy(arp_ptr, skb->data, ETH_ALEN);
+			return 0;
+		default:
+			return -1;
+		}
+	} else if ((protocol == ETH_P_IPX) ||
+		   (protocol <= ETH_FRAME_LEN)) {
+		/*---------------------------------------------------*/
+		/*         Handle IPX and Apple Talk frame           */
+		/*---------------------------------------------------*/
+		unsigned char ipx_header[2] = {0xFF, 0xFF};
+		struct ipxhdr	*ipx = NULL;
+		struct elapaarp	*ea = NULL;
+		struct ddpehdr	*ddp = NULL;
+		unsigned char *framePtr = skb->data + ETH_HLEN;
+
+		if (protocol == ETH_P_IPX) {
+			DEBUG_INFO("NAT25: Protocol = IPX (Ethernet II)\n");
+			ipx = (struct ipxhdr *)framePtr;
+		} else if (protocol <= ETH_FRAME_LEN) {
+			if (!memcmp(ipx_header, framePtr, 2)) {
+				DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.3)\n");
+				ipx = (struct ipxhdr *)framePtr;
+			} else {
+				unsigned char ipx_8022_type =  0xE0;
+				unsigned char snap_8022_type = 0xAA;
+
+				if (*framePtr == snap_8022_type) {
+					unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37};		/*  IPX SNAP ID */
+					unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3};	/*  Apple Talk AARP SNAP ID */
+					unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B};	/*  Apple Talk DDP SNAP ID */
+
+					framePtr += 3;	/*  eliminate the 802.2 header */
+
+					if (!memcmp(ipx_snap_id, framePtr, 5)) {
+						framePtr += 5;	/*  eliminate the SNAP header */
+
+						DEBUG_INFO("NAT25: Protocol = IPX (Ethernet SNAP)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					} else if (!memcmp(aarp_snap_id, framePtr, 5)) {
+						framePtr += 5;	/*  eliminate the SNAP header */
+
+						ea = (struct elapaarp *)framePtr;
+					} else if (!memcmp(ddp_snap_id, framePtr, 5)) {
+						framePtr += 5;	/*  eliminate the SNAP header */
+
+						ddp = (struct ddpehdr *)framePtr;
+					} else {
+						DEBUG_WARN("NAT25: Protocol = Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0],
+							framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
+						return -1;
+					}
+				} else if (*framePtr == ipx_8022_type) {
+					framePtr += 3;	/*  eliminate the 802.2 header */
+
+					if (!memcmp(ipx_header, framePtr, 2)) {
+						DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.2)\n");
+						ipx = (struct ipxhdr *)framePtr;
+					} else {
+						return -1;
+					}
+				} else {
+					return -1;
+				}
+			}
+		} else {
+			return -1;
+		}
+
+		/*   IPX   */
+		if (ipx != NULL) {
+			switch (method) {
+			case NAT25_CHECK:
+				if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN))
+				DEBUG_INFO("NAT25: Check IPX skb_copy\n");
+				return 0;
+				return -1;
+			case NAT25_INSERT:
+				DEBUG_INFO("NAT25: Insert IPX, Dest =%08x,%02x%02x%02x%02x%02x%02x,%04x Source =%08x,%02x%02x%02x%02x%02x%02x,%04x\n",
+					ipx->ipx_dest.net,
+					ipx->ipx_dest.node[0],
+					ipx->ipx_dest.node[1],
+					ipx->ipx_dest.node[2],
+					ipx->ipx_dest.node[3],
+					ipx->ipx_dest.node[4],
+					ipx->ipx_dest.node[5],
+					ipx->ipx_dest.sock,
+					ipx->ipx_source.net,
+					ipx->ipx_source.node[0],
+					ipx->ipx_source.node[1],
+					ipx->ipx_source.node[2],
+					ipx->ipx_source.node[3],
+					ipx->ipx_source.node[4],
+					ipx->ipx_source.node[5],
+					ipx->ipx_source.sock);
+
+				if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
+					DEBUG_INFO("NAT25: Use IPX Net, and Socket as network addr\n");
+
+					__nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock);
+
+					/*  change IPX source node addr to wlan STA address */
+					memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN);
+				} else {
+					__nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node);
+				}
+				__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+				__nat25_db_print(priv);
+				return 0;
+			case NAT25_LOOKUP:
+				if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) {
+					DEBUG_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n");
+
+					__nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock);
+
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+					/*  replace IPX destination node addr with Lookup destination MAC addr */
+					memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN);
+				} else {
+					__nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node);
+
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+				}
+				return 0;
+			default:
+				return -1;
+			}
+		} else if (ea != NULL) {
+			/* Sanity check fields. */
+			if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) {
+				DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n");
+				return -1;
+			}
+
+			switch (method) {
+			case NAT25_CHECK:
+				return 0;
+			case NAT25_INSERT:
+				/*  change to AARP source mac address to wlan STA address */
+				memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN);
+
+				DEBUG_INFO("NAT25: Insert AARP, Source =%d,%d Destination =%d,%d\n",
+					ea->pa_src_net,
+					ea->pa_src_node,
+					ea->pa_dst_net,
+					ea->pa_dst_node);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node);
+
+				__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+				return 0;
+			case NAT25_LOOKUP:
+				DEBUG_INFO("NAT25: Lookup AARP, Source =%d,%d Destination =%d,%d\n",
+					ea->pa_src_net,
+					ea->pa_src_node,
+					ea->pa_dst_net,
+					ea->pa_dst_node);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node);
+
+				__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+
+				/*  change to AARP destination mac address to Lookup result */
+				memcpy(ea->hw_dst, skb->data, ETH_ALEN);
+				return 0;
+			default:
+				return -1;
+			}
+		} else if (ddp != NULL) {
+			switch (method) {
+			case NAT25_CHECK:
+				return -1;
+			case NAT25_INSERT:
+				DEBUG_INFO("NAT25: Insert DDP, Source =%d,%d Destination =%d,%d\n",
+					ddp->deh_snet,
+					ddp->deh_snode,
+					ddp->deh_dnet,
+					ddp->deh_dnode);
+
+				__nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode);
+
+				__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+				return 0;
+			case NAT25_LOOKUP:
+				DEBUG_INFO("NAT25: Lookup DDP, Source =%d,%d Destination =%d,%d\n",
+					ddp->deh_snet,
+					ddp->deh_snode,
+					ddp->deh_dnet,
+					ddp->deh_dnode);
+				__nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode);
+				__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+				return 0;
+			default:
+				return -1;
+			}
+		}
+
+		return -1;
+	} else if ((protocol == ETH_P_PPP_DISC) ||
+		   (protocol == ETH_P_PPP_SES)) {
+		/*---------------------------------------------------*/
+		/*                Handle PPPoE frame                 */
+		/*---------------------------------------------------*/
+		struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
+		unsigned short *pMagic;
+
+		switch (method) {
+		case NAT25_CHECK:
+			if (ph->sid == 0)
+				return 0;
+			return 1;
+		case NAT25_INSERT:
+			if (ph->sid == 0) {	/*  Discovery phase according to tag */
+				if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
+					if (priv->ethBrExtInfo.addPPPoETag) {
+						struct pppoe_tag *tag, *pOldTag;
+						unsigned char tag_buf[40];
+						int old_tag_len = 0;
+
+						tag = (struct pppoe_tag *)tag_buf;
+						pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+						if (pOldTag) { /*  if SID existed, copy old value and delete it */
+							old_tag_len = ntohs(pOldTag->tag_len);
+							if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
+								DEBUG_ERR("SID tag length too long!\n");
+								return -1;
+							}
+
+							memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
+								pOldTag->tag_data, old_tag_len);
+
+							if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
+								DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
+								return -1;
+							}
+							ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
+						}
+
+						tag->tag_type = PTT_RELAY_SID;
+						tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
+
+						/*  insert the magic_code+client mac in relay tag */
+						pMagic = (unsigned short *)tag->tag_data;
+						*pMagic = htons(MAGIC_CODE);
+						memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
+
+						/* Add relay tag */
+						if (__nat25_add_pppoe_tag(skb, tag) < 0)
+							return -1;
+
+						DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n",
+										(ph->code == PADI_CODE ? "PADI" : "PADR"));
+					} else { /*  not add relay tag */
+						if (priv->pppoe_connection_in_progress &&
+								memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))	 {
+							DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
+							return -2;
+						}
+
+						if (priv->pppoe_connection_in_progress == 0)
+							memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
+
+						priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+					}
+				} else {
+					return -1;
+				}
+			} else {	/*  session phase */
+				DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
+
+				__nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid));
+
+				__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+
+				__nat25_db_print(priv);
+
+				if (!priv->ethBrExtInfo.addPPPoETag &&
+				    priv->pppoe_connection_in_progress &&
+				    !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
+					priv->pppoe_connection_in_progress = 0;
+			}
+			return 0;
+		case NAT25_LOOKUP:
+			if (ph->code == PADO_CODE || ph->code == PADS_CODE) {
+				if (priv->ethBrExtInfo.addPPPoETag) {
+					struct pppoe_tag *tag;
+					unsigned char *ptr;
+					unsigned short tagType, tagLen;
+					int offset = 0;
+
+					ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
+					if (ptr == NULL) {
+						DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n");
+						return -1;
+					}
+
+					tag = (struct pppoe_tag *)ptr;
+					tagType = (unsigned short)((ptr[0] << 8) + ptr[1]);
+					tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]);
+
+					if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) {
+						DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen);
+						return -1;
+					}
+
+					pMagic = (unsigned short *)tag->tag_data;
+					if (ntohs(*pMagic) != MAGIC_CODE) {
+						DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n",
+							(ph->code == PADO_CODE ? "PADO" : "PADS"));
+						return -1;
+					}
+
+					memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN);
+
+					if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN)
+						offset = TAG_HDR_LEN;
+
+					if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) {
+						DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n");
+						return -1;
+					}
+					ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset));
+					if (offset > 0)
+						tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN);
+
+					DEBUG_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n",
+						(ph->code == PADO_CODE ? "PADO" : "PADS"),	skb->dev->name);
+				} else { /*  not add relay tag */
+					if (!priv->pppoe_connection_in_progress) {
+						DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
+						return -1;
+					}
+					memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
+					priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
+				}
+			} else {
+				if (ph->sid != 0) {
+					DEBUG_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name);
+					__nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid));
+					__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+					__nat25_db_print(priv);
+				} else {
+					return -1;
+				}
+			}
+			return 0;
+		default:
+			return -1;
+		}
+	} else if (protocol == 0x888e) {
+		/*---------------------------------------------------*/
+		/*                 Handle EAP frame                  */
+		/*---------------------------------------------------*/
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+		case NAT25_INSERT:
+			return 0;
+		case NAT25_LOOKUP:
+			return 0;
+		default:
+			return -1;
+		}
+	} else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
+		/*---------------------------------------------------*/
+		/*         Handle C-Media proprietary frame          */
+		/*---------------------------------------------------*/
+		switch (method) {
+		case NAT25_CHECK:
+			return -1;
+		case NAT25_INSERT:
+			return 0;
+		case NAT25_LOOKUP:
+			return 0;
+		default:
+			return -1;
+		}
+	} else if (protocol == ETH_P_IPV6) {
+		/*------------------------------------------------*/
+		/*         Handle IPV6 frame			  */
+		/*------------------------------------------------*/
+		struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
+
+		if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
+			DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
+			return -1;
+		}
+
+		switch (method) {
+		case NAT25_CHECK:
+			if (skb->data[0] & 1)
+				return 0;
+			return -1;
+		case NAT25_INSERT:
+			DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
+							" DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+				iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+				iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+				iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+				iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+
+			if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
+				__nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
+				__nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
+				__nat25_db_print(priv);
+
+				if (iph->nexthdr == IPPROTO_ICMPV6 &&
+						skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
+					if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
+								      skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
+						struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
+						hdr->icmp6_cksum = 0;
+						hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
+										iph->payload_len,
+										IPPROTO_ICMPV6,
+										csum_partial((__u8 *)hdr, iph->payload_len, 0));
+					}
+				}
+			}
+			return 0;
+		case NAT25_LOOKUP:
+			DEBUG_INFO("NAT25: Lookup IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x, DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
+				   iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
+				   iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
+				   iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
+				   iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
+			__nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr);
+			__nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
+			return 0;
+		default:
+			return -1;
+		}
+	}
+	return -1;
+}
+
+int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb)
+{
+	if (!(skb->data[0] & 1)) {
+		int is_vlan_tag = 0, i, retval = 0;
+		unsigned short vlan_hdr = 0;
+		unsigned short protocol;
+
+		protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
+		if (protocol == ETH_P_8021Q) {
+			is_vlan_tag = 1;
+			vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2));
+			for (i = 0; i < 6; i++)
+				*((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2));
+			skb_pull(skb, 4);
+		}
+
+		if (!priv->ethBrExtInfo.nat25_disable) {
+			unsigned long irqL;
+			_enter_critical_bh(&priv->br_ext_lock, &irqL);
+			/*
+			 *	This function look up the destination network address from
+			 *	the NAT2.5 database. Return value = -1 means that the
+			 *	corresponding network protocol is NOT support.
+			 */
+			if (!priv->ethBrExtInfo.nat25sc_disable &&
+			    (be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
+			    !memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) {
+				memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
+
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+			} else {
+				_exit_critical_bh(&priv->br_ext_lock, &irqL);
+
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		} else {
+			if (((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
+			    !memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) ||
+			    ((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_ARP) &&
+			    !memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) {
+				/*  for traffic to upper TCP/IP */
+				retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
+			}
+		}
+
+		if (is_vlan_tag) {
+			skb_push(skb, 4);
+			for (i = 0; i < 6; i++)
+				*((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+			*((__be16 *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q);
+			*((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr;
+		}
+
+		if (retval == -1) {
+			/* DEBUG_ERR("NAT25: Lookup fail!\n"); */
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+#define SERVER_PORT			67
+#define CLIENT_PORT			68
+#define DHCP_MAGIC			0x63825363
+#define BROADCAST_FLAG		0x8000
+
+struct dhcpMessage {
+	u_int8_t op;
+	u_int8_t htype;
+	u_int8_t hlen;
+	u_int8_t hops;
+	u_int32_t xid;
+	u_int16_t secs;
+	u_int16_t flags;
+	u_int32_t ciaddr;
+	u_int32_t yiaddr;
+	u_int32_t siaddr;
+	u_int32_t giaddr;
+	u_int8_t chaddr[16];
+	u_int8_t sname[64];
+	u_int8_t file[128];
+	u_int32_t cookie;
+	u_int8_t options[308]; /* 312 - cookie */
+};
+
+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
+{
+	if (skb == NULL)
+		return;
+
+	if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
+		__be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
+
+		if (protocol == __constant_htons(ETH_P_IP)) { /*  IP */
+			struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
+
+			if (iph->protocol == IPPROTO_UDP) { /*  UDP */
+				struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
+
+				if ((udph->source == __constant_htons(CLIENT_PORT)) &&
+				    (udph->dest == __constant_htons(SERVER_PORT))) { /*  DHCP request */
+					struct dhcpMessage *dhcph =
+						(struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
+					u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
+
+					if (cookie == DHCP_MAGIC) { /*  match magic word */
+						if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
+							/*  if not broadcast */
+							register int sum = 0;
+
+							DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n");
+							/*  or BROADCAST flag */
+							dhcph->flags |= htons(BROADCAST_FLAG);
+							/*  recalculate checksum */
+							sum = ~(udph->check) & 0xffff;
+							sum += be16_to_cpu(dhcph->flags);
+							while (sum >> 16)
+								sum = (sum & 0xffff) + (sum >> 16);
+							udph->check = ~sum;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
+				unsigned char *ipAddr)
+{
+	unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
+	struct nat25_network_db_entry *db;
+	int hash;
+	/* unsigned long irqL; */
+	/* _enter_critical_bh(&priv->br_ext_lock, &irqL); */
+
+	__nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
+	hash = __nat25_network_hash(networkAddr);
+	db = priv->nethash[hash];
+	while (db != NULL) {
+		if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
+			/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+			return (void *)db;
+		}
+
+		db = db->next_hash;
+	}
+
+	/* _exit_critical_bh(&priv->br_ext_lock, &irqL); */
+	return NULL;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c
new file mode 100644
index 0000000..9632ef4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c
@@ -0,0 +1,2364 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+#include <rtw_br_ext.h>
+#include <rtw_mlme_ext.h>
+
+/*
+Caller and the rtw_cmd_thread can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+int	_rtw_init_cmd_priv (struct	cmd_priv *pcmdpriv)
+{
+	int res = _SUCCESS;
+
+_func_enter_;
+
+	_rtw_init_sema(&(pcmdpriv->cmd_queue_sema), 0);
+	/* _rtw_init_sema(&(pcmdpriv->cmd_done_sema), 0); */
+	_rtw_init_sema(&(pcmdpriv->terminate_cmdthread_sema), 0);
+
+
+	_rtw_init_queue(&(pcmdpriv->cmd_queue));
+
+	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+
+	pcmdpriv->cmd_seq = 1;
+
+	pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ);
+
+	if (pcmdpriv->cmd_allocated_buf == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf  +  CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ-1));
+
+	pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4);
+
+	if (pcmdpriv->rsp_allocated_buf == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3);
+
+	pcmdpriv->cmd_issued_cnt = 0;
+	pcmdpriv->cmd_done_cnt = 0;
+	pcmdpriv->rsp_cnt = 0;
+exit:
+_func_exit_;
+	return res;
+}
+
+static void c2h_wk_callback(struct work_struct *work);
+
+int _rtw_init_evt_priv(struct evt_priv *pevtpriv)
+{
+	int res = _SUCCESS;
+
+_func_enter_;
+
+	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+	ATOMIC_SET(&pevtpriv->event_seq, 0);
+	pevtpriv->evt_done_cnt = 0;
+
+	_init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL);
+	pevtpriv->c2h_wk_alive = false;
+	pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN+1);
+
+_func_exit_;
+
+	return res;
+}
+
+void rtw_free_evt_priv(struct	evt_priv *pevtpriv)
+{
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+rtw_free_evt_priv\n"));
+
+	_cancel_workitem_sync(&pevtpriv->c2h_wk);
+	while (pevtpriv->c2h_wk_alive)
+		rtw_msleep_os(10);
+
+	while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) {
+		void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue);
+		if (c2h != NULL && c2h != (void *)pevtpriv)
+			kfree(c2h);
+	}
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("-rtw_free_evt_priv\n"));
+
+_func_exit_;
+}
+
+void _rtw_free_cmd_priv (struct	cmd_priv *pcmdpriv)
+{
+_func_enter_;
+
+	if (pcmdpriv) {
+		_rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock));
+		_rtw_free_sema(&(pcmdpriv->cmd_queue_sema));
+		_rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema));
+
+		if (pcmdpriv->cmd_allocated_buf)
+			kfree(pcmdpriv->cmd_allocated_buf);
+
+		if (pcmdpriv->rsp_allocated_buf)
+			kfree(pcmdpriv->rsp_allocated_buf);
+	}
+_func_exit_;
+}
+
+/*
+Calling Context:
+
+rtw_enqueue_cmd can only be called between kernel thread,
+since only spin_lock is used.
+
+ISR/Call-Back functions can't call this sub-function.
+
+*/
+
+int	_rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj)
+{
+	unsigned long irqL;
+
+_func_enter_;
+
+	if (obj == NULL)
+		goto exit;
+
+	/* _enter_critical_bh(&queue->lock, &irqL); */
+	_enter_critical(&queue->lock, &irqL);
+
+	rtw_list_insert_tail(&obj->list, &queue->queue);
+
+	/* _exit_critical_bh(&queue->lock, &irqL); */
+	_exit_critical(&queue->lock, &irqL);
+
+exit:
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+struct	cmd_obj	*_rtw_dequeue_cmd(struct __queue *queue)
+{
+	unsigned long irqL;
+	struct cmd_obj *obj;
+
+_func_enter_;
+
+	/* _enter_critical_bh(&(queue->lock), &irqL); */
+	_enter_critical(&queue->lock, &irqL);
+	if (rtw_is_list_empty(&(queue->queue))) {
+		obj = NULL;
+	} else {
+		obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list);
+		rtw_list_delete(&obj->list);
+	}
+
+	/* _exit_critical_bh(&(queue->lock), &irqL); */
+	_exit_critical(&queue->lock, &irqL);
+
+_func_exit_;
+
+	return obj;
+}
+
+u32	rtw_init_cmd_priv(struct cmd_priv *pcmdpriv)
+{
+	u32	res;
+_func_enter_;
+	res = _rtw_init_cmd_priv (pcmdpriv);
+_func_exit_;
+	return res;
+}
+
+u32	rtw_init_evt_priv (struct	evt_priv *pevtpriv)
+{
+	int	res;
+_func_enter_;
+	res = _rtw_init_evt_priv(pevtpriv);
+_func_exit_;
+	return res;
+}
+
+void rtw_free_cmd_priv(struct	cmd_priv *pcmdpriv)
+{
+_func_enter_;
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("rtw_free_cmd_priv\n"));
+	_rtw_free_cmd_priv(pcmdpriv);
+_func_exit_;
+}
+
+int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+	u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */
+
+	/* To decide allow or not */
+	if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) &&
+	    (!pcmdpriv->padapter->registrypriv.usbss_enable)) {
+		if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+			struct drvextra_cmd_parm	*pdrvextra_cmd_parm = (struct drvextra_cmd_parm	*)cmd_obj->parmbuf;
+			if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID)
+				bAllow = true;
+		}
+	}
+
+	if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+		bAllow = true;
+
+	if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) ||
+	    !pcmdpriv->cmdthd_running)	/* com_thread not running */
+		return _FAIL;
+	return _SUCCESS;
+}
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+	int res = _FAIL;
+	struct adapter *padapter = pcmdpriv->padapter;
+
+_func_enter_;
+
+	if (cmd_obj == NULL)
+		goto exit;
+
+	cmd_obj->padapter = padapter;
+
+	res = rtw_cmd_filter(pcmdpriv, cmd_obj);
+	if (_FAIL == res) {
+		rtw_free_cmd_obj(cmd_obj);
+		goto exit;
+	}
+
+	res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj);
+
+	if (res == _SUCCESS)
+		_rtw_up_sema(&pcmdpriv->cmd_queue_sema);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+struct	cmd_obj	*rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+{
+	struct cmd_obj *cmd_obj;
+
+_func_enter_;
+
+	cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
+
+_func_exit_;
+	return cmd_obj;
+}
+
+void rtw_cmd_clr_isr(struct	cmd_priv *pcmdpriv)
+{
+_func_enter_;
+	pcmdpriv->cmd_done_cnt++;
+	/* _rtw_up_sema(&(pcmdpriv->cmd_done_sema)); */
+_func_exit_;
+}
+
+void rtw_free_cmd_obj(struct cmd_obj *pcmd)
+{
+_func_enter_;
+
+	if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) {
+		/* free parmbuf in cmd_obj */
+		kfree(pcmd->parmbuf);
+	}
+
+	if (pcmd->rsp != NULL) {
+		if (pcmd->rspsz != 0) {
+			/* free rsp in cmd_obj */
+			kfree(pcmd->rsp);
+		}
+	}
+
+	/* free cmd_obj */
+	kfree(pcmd);
+
+_func_exit_;
+}
+
+int rtw_cmd_thread(void *context)
+{
+	u8 ret;
+	struct cmd_obj *pcmd;
+	u8 *pcmdbuf;
+	u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf);
+	void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd);
+	struct adapter *padapter = (struct adapter *)context;
+	struct cmd_priv *pcmdpriv = &(padapter->cmdpriv);
+
+_func_enter_;
+
+	thread_enter("RTW_CMD_THREAD");
+
+	pcmdbuf = pcmdpriv->cmd_buf;
+
+	pcmdpriv->cmdthd_running = true;
+	_rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("start r871x rtw_cmd_thread !!!!\n"));
+
+	while (1) {
+		if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL)
+			break;
+
+		if (padapter->bDriverStopped ||
+		    padapter->bSurpriseRemoved) {
+			DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+				__func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+			break;
+		}
+_next:
+		if (padapter->bDriverStopped ||
+		    padapter->bSurpriseRemoved) {
+			DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n",
+				__func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__);
+			break;
+		}
+
+		pcmd = rtw_dequeue_cmd(pcmdpriv);
+		if (!pcmd)
+			continue;
+
+		if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) {
+			pcmd->res = H2C_DROPPED;
+			goto post_process;
+		}
+
+		pcmdpriv->cmd_issued_cnt++;
+
+		pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */
+
+		memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+
+		if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) {
+			cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+
+			if (cmd_hdl) {
+				ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+				pcmd->res = ret;
+			}
+
+			pcmdpriv->cmd_seq++;
+		} else {
+			pcmd->res = H2C_PARAMETERS_ERROR;
+		}
+
+		cmd_hdl = NULL;
+
+post_process:
+
+		/* call callback function for post-processed */
+		if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) {
+			pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback;
+			if (pcmd_callback == NULL) {
+				RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("mlme_cmd_hdl(): pcmd_callback = 0x%p, cmdcode = 0x%x\n", pcmd_callback, pcmd->cmdcode));
+				rtw_free_cmd_obj(pcmd);
+			} else {
+				/* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
+				pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
+			}
+		} else {
+			RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode));
+			rtw_free_cmd_obj(pcmd);
+		}
+
+		flush_signals_thread();
+
+		goto _next;
+	}
+	pcmdpriv->cmdthd_running = false;
+
+	/*  free all cmd_obj resources */
+	do {
+		pcmd = rtw_dequeue_cmd(pcmdpriv);
+		if (pcmd == NULL)
+			break;
+
+		/* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */
+
+		rtw_free_cmd_obj(pcmd);
+	} while (1);
+
+	_rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema);
+
+_func_exit_;
+
+	thread_exit();
+}
+
+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action)
+{
+	struct cmd_obj *ph2c;
+	struct usb_suspend_parm *psetusbsuspend;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+
+	u8 ret = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		ret = _FAIL;
+		goto exit;
+	}
+
+	psetusbsuspend = (struct usb_suspend_parm *)rtw_zmalloc(sizeof(struct usb_suspend_parm));
+	if (psetusbsuspend == NULL) {
+		kfree(ph2c);
+		ret = _FAIL;
+		goto exit;
+	}
+
+	psetusbsuspend->action = action;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend));
+
+	ret = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+/*
+rtw_sitesurvey_cmd(~)
+	### NOTE:#### (!!!!)
+	MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+*/
+u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid, int ssid_num,
+	struct rtw_ieee80211_channel *ch, int ch_num)
+{
+	u8 res = _FAIL;
+	struct cmd_obj		*ph2c;
+	struct sitesurvey_parm	*psurveyPara;
+	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+		rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1);
+	}
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+		p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1);
+	}
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL)
+		return _FAIL;
+
+	psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
+	if (psurveyPara == NULL) {
+		kfree(ph2c);
+		return _FAIL;
+	}
+
+	rtw_free_network_queue(padapter, false);
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("%s: flush network queue\n", __func__));
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+
+	/* psurveyPara->bsslimit = 48; */
+	psurveyPara->scan_mode = pmlmepriv->scan_mode;
+
+	/* prepare ssid list */
+	if (ssid) {
+		int i;
+		for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
+			if (ssid[i].SsidLength) {
+				memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid));
+				psurveyPara->ssid_num++;
+				if (0)
+				DBG_88E(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter),
+					psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength);
+			}
+		}
+	}
+
+	/* prepare channel list */
+	if (ch) {
+		int i;
+		for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+			if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) {
+				memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel));
+				psurveyPara->ch_num++;
+				if (0)
+				DBG_88E(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter),
+					psurveyPara->ch[i].hw_value);
+			}
+		}
+	}
+
+	set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+	if (res == _SUCCESS) {
+		pmlmepriv->scan_start_time = rtw_get_current_time();
+
+		_set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT);
+
+		rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+
+		pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+	} else {
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+	}
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset)
+{
+	struct cmd_obj *ph2c;
+	struct setdatarate_parm *pbsetdataratepara;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pbsetdataratepara = (struct setdatarate_parm *)rtw_zmalloc(sizeof(struct setdatarate_parm));
+	if (pbsetdataratepara == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate));
+	pbsetdataratepara->mac_id = 5;
+	memcpy(pbsetdataratepara->datarates, rateset, NumRates);
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset)
+{
+	struct cmd_obj *ph2c;
+	struct setbasicrate_parm *pssetbasicratepara;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	pssetbasicratepara = (struct setbasicrate_parm *)rtw_zmalloc(sizeof(struct setbasicrate_parm));
+
+	if (pssetbasicratepara == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_);
+
+	memcpy(pssetbasicratepara->basicrates, rateset, NumRates);
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+
+/*
+unsigned char rtw_setphy_cmd(unsigned char  *adapter)
+
+1.  be called only after rtw_update_registrypriv_dev_network(~) or mp testing program
+2.  for AdHoc/Ap mode or mp mode?
+
+*/
+u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch)
+{
+	struct cmd_obj *ph2c;
+	struct setphy_parm *psetphypara;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+		}
+	psetphypara = (struct setphy_parm *)rtw_zmalloc(sizeof(struct setphy_parm));
+
+	if (psetphypara == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_);
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("CH =%d, modem =%d", ch, modem));
+
+	psetphypara->modem = modem;
+	psetphypara->rfchannel = ch;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val)
+{
+	struct cmd_obj *ph2c;
+	struct writeBB_parm *pwritebbparm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+		}
+	pwritebbparm = (struct writeBB_parm *)rtw_zmalloc(sizeof(struct writeBB_parm));
+
+	if (pwritebbparm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg));
+
+	pwritebbparm->offset = offset;
+	pwritebbparm->value = val;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_getbbreg_cmd(struct adapter  *padapter, u8 offset, u8 *pval)
+{
+	struct cmd_obj *ph2c;
+	struct readBB_parm *prdbbparm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+		}
+	prdbbparm = (struct readBB_parm *)rtw_zmalloc(sizeof(struct readBB_parm));
+
+	if (prdbbparm == NULL) {
+		kfree(ph2c);
+		return _FAIL;
+	}
+
+	_rtw_init_listhead(&ph2c->list);
+	ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg);
+	ph2c->parmbuf = (unsigned char *)prdbbparm;
+	ph2c->cmdsz =  sizeof(struct readBB_parm);
+	ph2c->rsp = pval;
+	ph2c->rspsz = sizeof(struct readBB_rsp);
+
+	prdbbparm->offset = offset;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_setrfreg_cmd(struct adapter  *padapter, u8 offset, u32 val)
+{
+	struct cmd_obj *ph2c;
+	struct writeRF_parm *pwriterfparm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+_func_enter_;
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	pwriterfparm = (struct writeRF_parm *)rtw_zmalloc(sizeof(struct writeRF_parm));
+
+	if (pwriterfparm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg));
+
+	pwriterfparm->offset = offset;
+	pwriterfparm->value = val;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_getrfreg_cmd(struct adapter  *padapter, u8 offset, u8 *pval)
+{
+	struct cmd_obj *ph2c;
+	struct readRF_parm *prdrfparm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	prdrfparm = (struct readRF_parm *)rtw_zmalloc(sizeof(struct readRF_parm));
+	if (prdrfparm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_init_listhead(&ph2c->list);
+	ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg);
+	ph2c->parmbuf = (unsigned char *)prdrfparm;
+	ph2c->cmdsz =  sizeof(struct readRF_parm);
+	ph2c->rsp = pval;
+	ph2c->rspsz = sizeof(struct readRF_rsp);
+
+	prdrfparm->offset = offset;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+ _func_enter_;
+
+	kfree(pcmd->parmbuf);
+	kfree(pcmd);
+
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.workparam.bcompleted = true;
+_func_exit_;
+}
+
+void rtw_readtssi_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+ _func_enter_;
+
+	kfree(pcmd->parmbuf);
+	kfree(pcmd);
+
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.workparam.bcompleted = true;
+_func_exit_;
+}
+
+u8 rtw_createbss_cmd(struct adapter  *padapter)
+{
+	struct cmd_obj *pcmd;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+	if (pmlmepriv->assoc_ssid.SsidLength == 0)
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for Any SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+	else
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, (" createbss for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_init_listhead(&pcmd->list);
+	pcmd->cmdcode = _CreateBss_CMD_;
+	pcmd->parmbuf = (unsigned char *)pdev_network;
+	pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+	pdev_network->Length = pcmd->cmdsz;
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_createbss_cmd_ex(struct adapter  *padapter, unsigned char *pbss, unsigned int sz)
+{
+	struct cmd_obj *pcmd;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_init_listhead(&pcmd->list);
+	pcmd->cmdcode = GEN_CMD_CODE(_CreateBss);
+	pcmd->parmbuf = pbss;
+	pcmd->cmdsz =  sz;
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network *pnetwork)
+{
+	u8	res = _SUCCESS;
+	uint	t_len = 0;
+	struct wlan_bssid_ex		*psecnetwork;
+	struct cmd_obj		*pcmd;
+	struct cmd_priv		*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct qos_priv		*pqospriv = &pmlmepriv->qospriv;
+	struct security_priv	*psecuritypriv = &padapter->securitypriv;
+	struct registry_priv	*pregistrypriv = &padapter->registrypriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+_func_enter_;
+
+	rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+	if (pmlmepriv->assoc_ssid.SsidLength == 0) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n"));
+	} else {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid));
+	}
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n"));
+		goto exit;
+	}
+	/* for IEs is fix buf size */
+	t_len = sizeof(struct wlan_bssid_ex);
+
+
+	/* for hidden ap to set fw_state here */
+	if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
+		switch (ndis_network_mode) {
+		case Ndis802_11IBSS:
+			set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+			break;
+		case Ndis802_11Infrastructure:
+			set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+			break;
+		case Ndis802_11APMode:
+		case Ndis802_11AutoUnknown:
+		case Ndis802_11InfrastructureMax:
+			break;
+		}
+	}
+
+	psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
+	if (psecnetwork == NULL) {
+		if (pcmd != NULL)
+			kfree(pcmd);
+
+		res = _FAIL;
+
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd :psecnetwork == NULL!!!\n"));
+
+		goto exit;
+	}
+
+	_rtw_memset(psecnetwork, 0, t_len);
+
+	memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network));
+
+	psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength;
+
+	if ((psecnetwork->IELength-12) < (256-1)) {
+		memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength-12);
+	} else {
+		memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256-1));
+	}
+
+	psecnetwork->IELength = 0;
+	/*  Added by Albert 2009/02/18 */
+	/*  If the the driver wants to use the bssid to create the connection. */
+	/*  If not,  we have to copy the connecting AP's MAC address to it so that */
+	/*  the driver just has the bssid information for PMKIDList searching. */
+
+	if (!pmlmepriv->assoc_by_bssid)
+		memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN);
+
+	psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength);
+
+
+	pqospriv->qos_option = 0;
+
+	if (pregistrypriv->wmm_enable) {
+		u32 tmp_len;
+
+		tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength);
+
+		if (psecnetwork->IELength != tmp_len) {
+			psecnetwork->IELength = tmp_len;
+			pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */
+		} else {
+			pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */
+		}
+	}
+
+	phtpriv->ht_option = false;
+	if (pregistrypriv->ht_enable) {
+		/* 	Added by Albert 2010/06/23 */
+		/* 	For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */
+		/* 	Especially for Realtek 8192u SoftAP. */
+		if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
+		    (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
+		    (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
+			/* rtw_restructure_ht_ie */
+			rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0],
+									pnetwork->network.IELength, &psecnetwork->IELength);
+		}
+	}
+
+	pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength);
+
+	if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
+		padapter->pwrctrlpriv.smart_ps = 0;
+	else
+		padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps;
+
+	DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps);
+
+	pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */
+
+	_rtw_init_listhead(&pcmd->list);
+	pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
+	pcmd->parmbuf = (unsigned char *)psecnetwork;
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */
+{
+	struct cmd_obj *cmdobj = NULL;
+	struct disconnect_parm *param = NULL;
+	struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+	u8 res = _SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_disassoc_cmd\n"));
+
+	/* prepare cmd parameter */
+	param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param));
+	if (param == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	param->deauth_timeout_ms = deauth_timeout_ms;
+
+	if (enqueue) {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj));
+		if (cmdobj == NULL) {
+			res = _FAIL;
+			kfree(param);
+			goto exit;
+		}
+		init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+		res = rtw_enqueue_cmd(cmdpriv, cmdobj);
+	} else {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param))
+			res = _FAIL;
+		kfree(param);
+	}
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_setopmode_cmd(struct adapter  *padapter, enum ndis_802_11_network_infra networktype)
+{
+	struct	cmd_obj *ph2c;
+	struct	setopmode_parm *psetop;
+
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = false;
+		goto exit;
+	}
+	psetop = (struct setopmode_parm *)rtw_zmalloc(sizeof(struct setopmode_parm));
+
+	if (psetop == NULL) {
+		kfree(ph2c);
+		res = false;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+	psetop->mode = (u8)networktype;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key)
+{
+	struct cmd_obj *ph2c;
+	struct set_stakey_parm *psetstakey_para;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct set_stakey_rsp *psetstakey_rsp = NULL;
+
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct sta_info *sta = (struct sta_info *)psta;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if (psetstakey_para == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+	if (psetstakey_rsp == NULL) {
+		kfree(ph2c);
+		kfree(psetstakey_para);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+	ph2c->rsp = (u8 *)psetstakey_rsp;
+	ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+	memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+		psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm;
+	else
+		GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
+
+	if (unicast_key)
+		memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+	else
+		memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
+
+	/* jeff: set this becasue at least sw key is ready */
+	padapter->securitypriv.busetkipkey = true;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue)
+{
+	struct cmd_obj *ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct set_stakey_rsp *psetstakey_rsp = NULL;
+	struct sta_info *sta = (struct sta_info *)psta;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	if (!enqueue) {
+		clear_cam_entry(padapter, entry);
+	} else {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+		if (psetstakey_para == NULL) {
+			kfree(ph2c);
+			res = _FAIL;
+			goto exit;
+		}
+
+		psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp));
+		if (psetstakey_rsp == NULL) {
+			kfree(ph2c);
+			kfree(psetstakey_para);
+			res = _FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+		ph2c->rsp = (u8 *)psetstakey_rsp;
+		ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+		memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN);
+
+		psetstakey_para->algorithm = _NO_PRIVACY_;
+
+		psetstakey_para->id = entry;
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_setrttbl_cmd(struct adapter  *padapter, struct setratable_parm *prate_table)
+{
+	struct cmd_obj *ph2c;
+	struct setratable_parm *psetrttblparm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	psetrttblparm = (struct setratable_parm *)rtw_zmalloc(sizeof(struct setratable_parm));
+
+	if (psetrttblparm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable));
+
+	memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_getrttbl_cmd(struct adapter  *padapter, struct getratable_rsp *pval)
+{
+	struct cmd_obj *ph2c;
+	struct getratable_parm *pgetrttblparm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	pgetrttblparm = (struct getratable_parm *)rtw_zmalloc(sizeof(struct getratable_parm));
+
+	if (pgetrttblparm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+/* 	init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */
+
+	_rtw_init_listhead(&ph2c->list);
+	ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable);
+	ph2c->parmbuf = (unsigned char *)pgetrttblparm;
+	ph2c->cmdsz =  sizeof(struct getratable_parm);
+	ph2c->rsp = (u8 *)pval;
+	ph2c->rspsz = sizeof(struct getratable_rsp);
+
+	pgetrttblparm->rsvd = 0x0;
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_setassocsta_cmd(struct adapter  *padapter, u8 *mac_addr)
+{
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct cmd_obj *ph2c;
+	struct set_assocsta_parm *psetassocsta_para;
+	struct set_stakey_rsp *psetassocsta_rsp = NULL;
+
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetassocsta_para = (struct set_assocsta_parm *)rtw_zmalloc(sizeof(struct set_assocsta_parm));
+	if (psetassocsta_para == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetassocsta_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_assocsta_rsp));
+	if (psetassocsta_rsp == NULL) {
+		kfree(ph2c);
+		kfree(psetassocsta_para);
+		return _FAIL;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_);
+	ph2c->rsp = (u8 *)psetassocsta_rsp;
+	ph2c->rspsz = sizeof(struct set_assocsta_rsp);
+
+	memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN);
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return res;
+ }
+
+u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr)
+{
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+	struct cmd_obj *ph2c;
+	struct addBaReq_parm *paddbareq_parm;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	paddbareq_parm = (struct addBaReq_parm *)rtw_zmalloc(sizeof(struct addBaReq_parm));
+	if (paddbareq_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	paddbareq_parm->tid = tid;
+	memcpy(paddbareq_parm->addr, addr, ETH_ALEN);
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
+
+	/* DBG_88E("rtw_addbareq_cmd, tid =%d\n", tid); */
+
+	/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+	pdrvextra_cmd_parm->type_size = 0;
+	pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+
+	/* rtw_enqueue_cmd(pcmdpriv, ph2c); */
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+_func_exit_;
+	return res;
+}
+
+u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue)
+{
+	struct cmd_obj *pcmdobj;
+	struct set_ch_parm *set_ch_parm;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+	u8 res = _SUCCESS;
+
+_func_enter_;
+
+	DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
+
+	/* check input parameter */
+
+	/* prepare cmd parameter */
+	set_ch_parm = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm));
+	if (set_ch_parm == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	set_ch_parm->ch = ch;
+	set_ch_parm->bw = bw;
+	set_ch_parm->ch_offset = ch_offset;
+
+	if (enqueue) {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+		if (pcmdobj == NULL) {
+			kfree(set_ch_parm);
+			res = _FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel));
+		res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+	} else {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm))
+			res = _FAIL;
+
+		kfree(set_ch_parm);
+	}
+
+	/* do something based on res... */
+
+exit:
+
+	DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res);
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue)
+{
+	struct	cmd_obj *pcmdobj;
+	struct	SetChannelPlan_param *setChannelPlan_param;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_chplan_cmd\n"));
+
+	/* check input parameter */
+	if (!rtw_is_channel_plan_valid(chplan)) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	/* prepare cmd parameter */
+	setChannelPlan_param = (struct	SetChannelPlan_param *)rtw_zmalloc(sizeof(struct SetChannelPlan_param));
+	if (setChannelPlan_param == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	setChannelPlan_param->channel_plan = chplan;
+
+	if (enqueue) {
+		/* need enqueue, prepare cmd_obj and enqueue */
+		pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+		if (pcmdobj == NULL) {
+			kfree(setChannelPlan_param);
+			res = _FAIL;
+			goto exit;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan));
+		res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+	} else {
+		/* no need to enqueue, do the cmd hdl directly and free cmd parameter */
+		if (H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param))
+			res = _FAIL;
+
+		kfree(setChannelPlan_param);
+	}
+
+	/* do something based on res... */
+	if (res == _SUCCESS)
+		padapter->mlmepriv.ChannelPlan = chplan;
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed)
+{
+	struct	cmd_obj *pcmdobj;
+	struct	LedBlink_param *ledBlink_param;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n"));
+
+	pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if (pcmdobj == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	ledBlink_param = (struct	LedBlink_param *)rtw_zmalloc(sizeof(struct	LedBlink_param));
+	if (ledBlink_param == NULL) {
+		kfree(pcmdobj);
+		res = _FAIL;
+		goto exit;
+	}
+
+	ledBlink_param->pLed = pLed;
+
+	init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no)
+{
+	struct	cmd_obj *pcmdobj;
+	struct	SetChannelSwitch_param *setChannelSwitch_param;
+	struct	cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n"));
+
+	pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if (pcmdobj == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct	SetChannelSwitch_param));
+	if (setChannelSwitch_param == NULL) {
+		kfree(pcmdobj);
+		res = _FAIL;
+		goto exit;
+	}
+
+	setChannelSwitch_param->new_ch_no = new_ch_no;
+
+	init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmdobj);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option)
+{
+	return _SUCCESS;
+}
+
+static void traffic_status_watchdog(struct adapter *padapter)
+{
+	u8	bEnterPS;
+	u8	bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
+	u8	bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false;
+	struct mlme_priv		*pmlmepriv = &(padapter->mlmepriv);
+
+	/*  */
+	/*  Determine if our traffic is busy now */
+	/*  */
+	if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+		if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 ||
+		    pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) {
+			bBusyTraffic = true;
+
+			if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+				bRxBusyTraffic = true;
+			else
+				bTxBusyTraffic = true;
+		}
+
+		/*  Higher Tx/Rx data. */
+		if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
+		    pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
+			bHigherBusyTraffic = true;
+
+			if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+				bHigherBusyRxTraffic = true;
+			else
+				bHigherBusyTxTraffic = true;
+		}
+
+		/*  check traffic for  powersaving. */
+		if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
+		    (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
+			bEnterPS = false;
+		else
+			bEnterPS = true;
+
+		/*  LeisurePS only work in infra mode. */
+		if (bEnterPS)
+			LPS_Enter(padapter);
+		else
+			LPS_Leave(padapter);
+	} else {
+		LPS_Leave(padapter);
+	}
+
+	pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
+	pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
+	pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
+	pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
+	pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
+}
+
+void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+	struct mlme_priv *pmlmepriv;
+
+	padapter = (struct adapter *)pbuf;
+	pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_88EU_AP_MODE
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+		expire_timeout_chk(padapter);
+#endif
+
+	rtw_hal_sreset_xmit_status_check(padapter);
+
+	linked_status_chk(padapter);
+	traffic_status_watchdog(padapter);
+
+	rtw_hal_dm_watchdog(padapter);
+}
+
+static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8	mstatus;
+
+_func_enter_;
+
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+		return;
+
+	switch (lps_ctrl_type) {
+	case LPS_CTRL_SCAN:
+		if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+			/* connect */
+			LPS_Leave(padapter);
+		}
+		break;
+	case LPS_CTRL_JOINBSS:
+		LPS_Leave(padapter);
+		break;
+	case LPS_CTRL_CONNECT:
+		mstatus = 1;/* connect */
+		/*  Reset LPS Setting */
+		padapter->pwrctrlpriv.LpsIdleCount = 0;
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+		break;
+	case LPS_CTRL_DISCONNECT:
+		mstatus = 0;/* disconnect */
+		LPS_Leave(padapter);
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus));
+		break;
+	case LPS_CTRL_SPECIAL_PACKET:
+		/* DBG_88E("LPS_CTRL_SPECIAL_PACKET\n"); */
+		pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time();
+		LPS_Leave(padapter);
+		break;
+	case LPS_CTRL_LEAVE:
+		LPS_Leave(padapter);
+		break;
+	default:
+		break;
+	}
+
+_func_exit_;
+}
+
+u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	/* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	/* if (!pwrctrlpriv->bLeisurePs) */
+	/* 	return res; */
+
+	if (enqueue) {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+		if (pdrvextra_cmd_parm == NULL) {
+			kfree(ph2c);
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+		pdrvextra_cmd_parm->type_size = lps_ctrl_type;
+		pdrvextra_cmd_parm->pbuf = NULL;
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	} else {
+		lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+	}
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time));
+}
+
+u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+
+_func_enter_;
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID;
+	pdrvextra_cmd_parm->type_size = min_time;
+	pdrvextra_cmd_parm->pbuf = NULL;
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna));
+}
+
+u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue)
+{
+	struct cmd_obj		*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	support_ant_div;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+	rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div);
+	if (!support_ant_div)
+		return res;
+
+	if (enqueue) {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+		if (pdrvextra_cmd_parm == NULL) {
+			kfree(ph2c);
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID;
+		pdrvextra_cmd_parm->type_size = antenna;
+		pdrvextra_cmd_parm->pbuf = NULL;
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	} else {
+		antenna_select_wk_hdl(padapter, antenna);
+	}
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void power_saving_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz)
+{
+	 rtw_ps_processor(padapter);
+}
+
+#ifdef CONFIG_88EU_P2P
+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return res;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+	pdrvextra_cmd_parm->type_size = intCmdType;	/* 	As the command tppe. */
+	pdrvextra_cmd_parm->pbuf = NULL;		/* 	Must be NULL here */
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+#endif /* CONFIG_88EU_P2P */
+
+u8 rtw_ps_cmd(struct adapter *padapter)
+{
+	struct cmd_obj		*ppscmd;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+
+	u8	res = _SUCCESS;
+_func_enter_;
+
+	ppscmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ppscmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		kfree(ppscmd);
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+	pdrvextra_cmd_parm->pbuf = NULL;
+	init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ppscmd);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+static void rtw_chk_hi_queue_hdl(struct adapter *padapter)
+{
+	int cnt = 0;
+	struct sta_info *psta_bmc;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+	if (!psta_bmc)
+		return;
+
+	if (psta_bmc->sleepq_len == 0) {
+		u8 val = 0;
+
+		/* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */
+		/* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */
+
+		rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+
+		while (!val) {
+			rtw_msleep_os(100);
+
+			cnt++;
+
+			if (cnt > 10)
+				break;
+
+			rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+		}
+
+		if (cnt <= 10) {
+			pstapriv->tim_bitmap &= ~BIT(0);
+			pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+			update_beacon(padapter, _TIM_IE_, NULL, false);
+		} else { /* re check again */
+			rtw_chk_hi_queue_cmd(padapter);
+		}
+	}
+}
+
+u8 rtw_chk_hi_queue_cmd(struct adapter *padapter)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+	pdrvextra_cmd_parm->type_size = 0;
+	pdrvextra_cmd_parm->pbuf = NULL;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+exit:
+	return res;
+}
+#endif
+
+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt)
+{
+	struct cmd_obj *ph2c;
+	struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+	if (pdrvextra_cmd_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+	pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0;
+	pdrvextra_cmd_parm->pbuf = c2h_evt;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+}
+
+static s32 c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter)
+{
+	s32 ret = _FAIL;
+	u8 buf[16];
+
+	if (!c2h_evt) {
+		/* No c2h event in cmd_obj, read c2h event before handling*/
+		if (c2h_evt_read(adapter, buf) == _SUCCESS) {
+			c2h_evt = (struct c2h_evt_hdr *)buf;
+
+			if (filter && filter(c2h_evt->id) == false)
+				goto exit;
+
+			ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+		}
+	} else {
+		if (filter && filter(c2h_evt->id) == false)
+			goto exit;
+
+		ret = rtw_hal_c2h_handler(adapter, c2h_evt);
+	}
+exit:
+	return ret;
+}
+
+static void c2h_wk_callback(struct work_struct *work)
+{
+	struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk);
+	struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv);
+	struct c2h_evt_hdr *c2h_evt;
+	c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter);
+
+	evtpriv->c2h_wk_alive = true;
+
+	while (!rtw_cbuf_empty(evtpriv->c2h_queue)) {
+		if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) {
+			/* This C2H event is read, clear it */
+			c2h_evt_clear(adapter);
+		} else if ((c2h_evt = (struct c2h_evt_hdr *)rtw_malloc(16)) != NULL) {
+			/* This C2H event is not read, read & clear now */
+			if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS)
+				continue;
+		}
+
+		/* Special pointer to trigger c2h_evt_clear only */
+		if ((void *)c2h_evt == (void *)evtpriv)
+			continue;
+
+		if (!c2h_evt_exist(c2h_evt)) {
+			kfree(c2h_evt);
+			continue;
+		}
+
+		if (ccx_id_filter(c2h_evt->id) == true) {
+			/* Handle CCX report here */
+			rtw_hal_c2h_handler(adapter, c2h_evt);
+			kfree(c2h_evt);
+		} else {
+#ifdef CONFIG_88EU_P2P
+			/* Enqueue into cmd_thread for others */
+			rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt);
+#endif
+		}
+	}
+
+	evtpriv->c2h_wk_alive = false;
+}
+
+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	struct drvextra_cmd_parm *pdrvextra_cmd;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
+
+	switch (pdrvextra_cmd->ec_id) {
+	case DYNAMIC_CHK_WK_CID:
+		dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+		break;
+	case POWER_SAVING_CTRL_WK_CID:
+		power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size);
+		break;
+	case LPS_CTRL_WK_CID:
+		lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
+		break;
+	case RTP_TIMER_CFG_WK_CID:
+		rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size);
+		break;
+	case ANT_SELECT_WK_CID:
+		antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size);
+		break;
+#ifdef CONFIG_88EU_P2P
+	case P2P_PS_WK_CID:
+		p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size);
+		break;
+	case P2P_PROTO_WK_CID:
+		/* 	Commented by Albert 2011/07/01 */
+		/* 	I used the type_size as the type command */
+		p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size);
+		break;
+#endif
+#ifdef CONFIG_88EU_AP_MODE
+	case CHECK_HIQ_WK_CID:
+		rtw_chk_hi_queue_hdl(padapter);
+		break;
+#endif /* CONFIG_88EU_AP_MODE */
+	case C2H_WK_CID:
+		c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
+		break;
+	default:
+		break;
+	}
+
+	if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0)
+		kfree(pdrvextra_cmd->pbuf);
+
+	return H2C_SUCCESS;
+}
+
+void rtw_survey_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	if (pcmd->res == H2C_DROPPED) {
+		/* TODO: cancel timer and do timeout handler directly... */
+		/* need to make timeout handlerOS independent */
+		_set_timer(&pmlmepriv->scan_to_timer, 1);
+		} else if (pcmd->res != H2C_SUCCESS) {
+		_set_timer(&pmlmepriv->scan_to_timer, 1);
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: MgntActrtw_set_802_11_bssid_LIST_SCAN Fail ************\n\n."));
+	}
+
+	/*  free cmd */
+	rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+	unsigned long	irqL;
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	if (pcmd->res != H2C_SUCCESS) {
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+		set_fwstate(pmlmepriv, _FW_LINKED);
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
+
+		goto exit;
+	} else /* clear bridge database */
+		nat25_db_cleanup(padapter);
+
+	/*  free cmd */
+	rtw_free_cmd_obj(pcmd);
+
+exit:
+
+_func_exit_;
+}
+
+void rtw_joinbss_cmd_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	if (pcmd->res == H2C_DROPPED) {
+		/* TODO: cancel timer and do timeout handler directly... */
+		/* need to make timeout handlerOS independent */
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+	} else if (pcmd->res != H2C_SUCCESS) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("********Error:rtw_select_and_join_from_scanned_queue Wait Sema  Fail ************\n"));
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+	}
+
+	rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd)
+{
+	unsigned long irqL;
+	u8 timer_cancelled;
+	struct sta_info *psta = NULL;
+	struct wlan_network *pwlan = NULL;
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
+	struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
+
+_func_enter_;
+
+	if ((pcmd->res != H2C_SUCCESS)) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n ********Error: rtw_createbss_cmd_callback  Fail ************\n\n."));
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+	}
+
+	_cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+		if (!psta) {
+			psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
+			if (psta == NULL) {
+				RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nCan't alloc sta_info when createbss_cmd_callback\n"));
+				goto createbss_cmd_fail ;
+			}
+		}
+
+		rtw_indicate_connect(padapter);
+	} else {
+		unsigned long	irqL;
+
+		pwlan = _rtw_alloc_network(pmlmepriv);
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		if (pwlan == NULL) {
+			pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
+			if (pwlan == NULL) {
+				RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\n Error:  can't get pwlan in rtw_joinbss_event_callback\n"));
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+				goto createbss_cmd_fail;
+			}
+			pwlan->last_scanned = rtw_get_current_time();
+		} else {
+			rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
+		}
+
+		pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
+		memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
+
+		memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork)));
+
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		/*  we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */
+	}
+
+createbss_cmd_fail:
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
+
+void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp);
+	struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr);
+
+_func_enter_;
+
+	if (psta == NULL) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: rtw_setstaKey_cmdrsp_callback => can't get sta_info\n\n"));
+		goto exit;
+	}
+exit:
+	rtw_free_cmd_obj(pcmd);
+_func_exit_;
+}
+
+void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *pcmd)
+{
+	unsigned long	irqL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
+	struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp);
+	struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr);
+
+_func_enter_;
+
+	if (psta == NULL) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nERROR: setassocsta_cmdrsp_callbac => can't get sta_info\n\n"));
+		goto exit;
+	}
+
+	psta->aid = passocsta_rsp->cam_id;
+	psta->mac_id = passocsta_rsp->cam_id;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true))
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+	set_fwstate(pmlmepriv, _FW_LINKED);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+	rtw_free_cmd_obj(pcmd);
+
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c
new file mode 100644
index 0000000..0fe5f5d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_debug.c
@@ -0,0 +1,948 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_DEBUG_C_
+
+#include <rtw_debug.h>
+#include <rtw_version.h>
+
+int proc_get_drv_version(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_write_reg(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	*eof = 1;
+	return 0;
+}
+
+int proc_set_write_reg(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 addr, val, len;
+
+	if (count < 3) {
+		DBG_88E("argument size is less than 3\n");
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		int num = sscanf(tmp, "%x %x %x", &addr, &val, &len);
+
+		if (num !=  3) {
+			DBG_88E("invalid write_reg parameter!\n");
+			return count;
+		}
+		switch (len) {
+		case 1:
+			rtw_write8(padapter, addr, (u8)val);
+			break;
+		case 2:
+			rtw_write16(padapter, addr, (u16)val);
+			break;
+		case 4:
+			rtw_write32(padapter, addr, val);
+			break;
+		default:
+			DBG_88E("error write length =%d", len);
+			break;
+		}
+	}
+	return count;
+}
+
+static u32 proc_get_read_addr = 0xeeeeeeee;
+static u32 proc_get_read_len = 0x4;
+
+int proc_get_read_reg(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	int len = 0;
+
+	if (proc_get_read_addr == 0xeeeeeeee) {
+		*eof = 1;
+		return len;
+	}
+
+	switch (proc_get_read_len) {
+	case 1:
+		len += snprintf(page + len, count - len, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr));
+		break;
+	case 2:
+		len += snprintf(page + len, count - len, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr));
+		break;
+	case 4:
+		len += snprintf(page + len, count - len, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr));
+		break;
+	default:
+		len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len);
+		break;
+	}
+
+	*eof = 1;
+	return len;
+}
+
+int proc_set_read_reg(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	char tmp[16];
+	u32 addr, len;
+
+	if (count < 2) {
+		DBG_88E("argument size is less than 2\n");
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		int num = sscanf(tmp, "%x %x", &addr, &len);
+
+		if (num !=  2) {
+			DBG_88E("invalid read_reg parameter!\n");
+			return count;
+		}
+
+		proc_get_read_addr = addr;
+
+		proc_get_read_len = len;
+	}
+
+	return count;
+}
+
+int proc_get_fwstate(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "fwstate=0x%x\n", get_fwstate(pmlmepriv));
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_sec_info(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n",
+						psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+						psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_mlmext_state(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_qos_option(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "qos_option=%d\n", pmlmepriv->qospriv.qos_option);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_ht_option(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	int len = 0;
+	len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option);
+	*eof = 1;
+	return len;
+}
+
+int proc_get_rf_info(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n",
+					pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+	*eof = 1;
+	return len;
+}
+
+int proc_get_ap_info(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct sta_info *psta;
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	int len = 0;
+
+	psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+	if (psta) {
+		int i;
+		struct recv_reorder_ctrl *preorder_ctrl;
+
+		len += snprintf(page + len, count - len, "SSID=%s\n", cur_network->network.Ssid.Ssid);
+		len += snprintf(page + len, count - len, "sta's macaddr:%pM\n", psta->hwaddr);
+		len += snprintf(page + len, count - len, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+		len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+		len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+		len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+		len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+		len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+		len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+		for (i = 0; i < 16; i++) {
+			preorder_ctrl = &psta->recvreorder_ctrl[i];
+			if (preorder_ctrl->enable)
+				len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq);
+		}
+	} else {
+		len += snprintf(page + len, count - len, "can't get sta's macaddr, cur_network's macaddr: %pM\n", cur_network->network.MacAddress);
+	}
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_adapter_state(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n",
+						padapter->bSurpriseRemoved, padapter->bDriverStopped);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_trx_info(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct recv_priv  *precvpriv = &padapter->recvpriv;
+	int len = 0;
+
+	len += snprintf(page + len, count - len, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d, free_ext_xmitbuf_cnt=%d, free_recvframe_cnt=%d\n",
+				pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt, precvpriv->free_recvframe_cnt);
+	len += snprintf(page + len, count - len, "rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_mac_reg_dump1(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1;
+
+	len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+
+	for (i = 0x0; i < 0x300; i += 4) {
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_mac_reg_dump2(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1;
+
+	len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+	memset(page, 0, count);
+	for (i = 0x300; i < 0x600; i += 4) {
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_mac_reg_dump3(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1;
+
+	len += snprintf(page + len, count - len, "\n======= MAC REG =======\n");
+
+	for (i = 0x600; i < 0x800; i += 4) {
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_bb_reg_dump1(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1;
+
+	len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+	for (i = 0x800; i < 0xB00; i += 4) {
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+	*eof = 1;
+	return len;
+}
+
+int proc_get_bb_reg_dump2(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1;
+
+	len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+	for (i = 0xB00; i < 0xE00; i += 4) {
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+	*eof = 1;
+	return len;
+}
+
+int proc_get_bb_reg_dump3(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1;
+
+	len += snprintf(page + len, count - len, "\n======= BB REG =======\n");
+	for (i = 0xE00; i < 0x1000; i += 4) {
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+	*eof = 1;
+	return len;
+}
+
+int proc_get_rf_reg_dump1(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1, path;
+	u32 value;
+
+	len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+	path = 1;
+	len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+	for (i = 0; i < 0xC0; i++) {
+		value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x ", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", value);
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+	*eof = 1;
+	return len;
+}
+
+int proc_get_rf_reg_dump2(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1, path;
+	u32 value;
+
+	len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+	path = 1;
+	len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+	for (i = 0xC0; i < 0x100; i++) {
+		value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x ", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", value);
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+	*eof = 1;
+	return len;
+}
+
+int proc_get_rf_reg_dump3(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1, path;
+	u32 value;
+
+	len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+	path = 2;
+	len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+	for (i = 0; i < 0xC0; i++) {
+		value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x ", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", value);
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+
+	*eof = 1;
+	return len;
+}
+
+
+int proc_get_rf_reg_dump4(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+	int i, j = 1, path;
+	u32 value;
+
+	len += snprintf(page + len, count - len, "\n======= RF REG =======\n");
+	path = 2;
+	len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path);
+	for (i = 0xC0; i < 0x100; i++) {
+		value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+		if (j%4 == 1)
+			len += snprintf(page + len, count - len, "0x%02x ", i);
+		len += snprintf(page + len, count - len, " 0x%08x ", value);
+		if ((j++)%4 == 0)
+			len += snprintf(page + len, count - len, "\n");
+	}
+	*eof = 1;
+	return len;
+}
+
+
+
+int proc_get_rx_signal(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int len = 0;
+
+	len = snprintf(page + len, count,
+		"rssi:%d\n"
+		"rxpwdb:%d\n"
+		"signal_strength:%u\n"
+		"signal_qual:%u\n"
+		"noise:%u\n",
+		padapter->recvpriv.rssi,
+		padapter->recvpriv.rxpwdb,
+		padapter->recvpriv.signal_strength,
+		padapter->recvpriv.signal_qual,
+		padapter->recvpriv.noise
+		);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_set_rx_signal(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 is_signal_dbg;
+	s32 signal_strength;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength);
+		is_signal_dbg = is_signal_dbg == 0 ? 0 : 1;
+		if (is_signal_dbg && num != 2)
+			return count;
+
+		signal_strength = signal_strength > 100 ? 100 : signal_strength;
+		signal_strength = signal_strength < 0 ? 0 : signal_strength;
+
+		padapter->recvpriv.is_signal_dbg = is_signal_dbg;
+		padapter->recvpriv.signal_strength_dbg = signal_strength;
+
+		if (is_signal_dbg)
+			DBG_88E("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength);
+		else
+			DBG_88E("set %s\n", "HW_SIGNAL_STRENGTH");
+	}
+	return count;
+}
+
+int proc_get_ht_enable(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	int len = 0;
+
+	if (pregpriv)
+		len += snprintf(page + len, count - len,
+			"%d\n",
+			pregpriv->ht_enable
+			);
+	*eof = 1;
+	return len;
+}
+
+int proc_set_ht_enable(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	s32 mode = 0;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		if (pregpriv) {
+			pregpriv->ht_enable = mode;
+			pr_info("ht_enable=%d\n", pregpriv->ht_enable);
+		}
+	}
+
+	return count;
+}
+
+int proc_get_cbw40_enable(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	int len = 0;
+
+	if (pregpriv)
+		len += snprintf(page + len, count - len,
+			"%d\n",
+			pregpriv->cbw40_enable
+			);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_set_cbw40_enable(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	s32 mode = 0;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		if (pregpriv) {
+			pregpriv->cbw40_enable = mode;
+			pr_info("cbw40_enable=%d\n", mode);
+		}
+	}
+	return count;
+}
+
+int proc_get_ampdu_enable(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	int len = 0;
+
+	if (pregpriv)
+		len += snprintf(page + len, count - len,
+			"%d\n",
+			pregpriv->ampdu_enable
+			);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_set_ampdu_enable(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	s32 mode = 0;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		if (pregpriv) {
+			pregpriv->ampdu_enable = mode;
+			pr_info("ampdu_enable=%d\n", mode);
+		}
+	}
+	return count;
+}
+
+int proc_get_two_path_rssi(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	int len = 0;
+
+	if (padapter)
+		len += snprintf(page + len, count - len,
+			"%d %d\n",
+			padapter->recvpriv.RxRssi[0],
+			padapter->recvpriv.RxRssi[1]
+			);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_get_rx_stbc(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	int len = 0;
+
+	if (pregpriv)
+		len += snprintf(page + len, count - len,
+			"%d\n",
+			pregpriv->rx_stbc
+			);
+
+	*eof = 1;
+	return len;
+}
+
+int proc_set_rx_stbc(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	char tmp[32];
+	u32 mode = 0;
+
+	if (count < 1)
+		return -EFAULT;
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		if (pregpriv) {
+			pregpriv->rx_stbc = mode;
+			printk("rx_stbc=%d\n", mode);
+		}
+	}
+	return count;
+}
+
+int proc_get_rssi_disp(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	*eof = 1;
+	return 0;
+}
+
+int proc_set_rssi_disp(struct file *file, const char __user *buffer,
+		unsigned long count, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	char tmp[32];
+	u32 enable = 0;
+
+	if (count < 1) {
+		DBG_88E("argument size is less than 1\n");
+		return -EFAULT;
+	}
+
+	if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
+		int num = sscanf(tmp, "%x", &enable);
+
+		if (num !=  1) {
+			DBG_88E("invalid set_rssi_disp parameter!\n");
+			return count;
+		}
+
+		if (enable) {
+			DBG_88E("Turn On Rx RSSI Display Function\n");
+			padapter->bRxRSSIDisplay = enable ;
+		} else {
+			DBG_88E("Turn Off Rx RSSI Display Function\n");
+			padapter->bRxRSSIDisplay = 0;
+		}
+	}
+	return count;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+int proc_get_all_sta_info(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	unsigned long irqL;
+	struct sta_info *psta;
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	int i, j;
+	struct list_head *plist, *phead;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	int len = 0;
+
+
+	len += snprintf(page + len, count - len, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+	for (i = 0; i < NUM_STA; i++) {
+		phead = &(pstapriv->sta_hash[i]);
+		plist = get_next(phead);
+
+		while ((rtw_end_of_queue_search(phead, plist)) == false) {
+			psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+			plist = get_next(plist);
+
+			len += snprintf(page + len, count - len, "sta's macaddr: %pM\n", psta->hwaddr);
+			len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+			len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+			len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+			len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+			len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+			len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+			len += snprintf(page + len, count - len, "sleepq_len=%d\n", psta->sleepq_len);
+			len += snprintf(page + len, count - len, "capability=0x%x\n", psta->capability);
+			len += snprintf(page + len, count - len, "flags=0x%x\n", psta->flags);
+			len += snprintf(page + len, count - len, "wpa_psk=0x%x\n", psta->wpa_psk);
+			len += snprintf(page + len, count - len, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher);
+			len += snprintf(page + len, count - len, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher);
+			len += snprintf(page + len, count - len, "qos_info=0x%x\n", psta->qos_info);
+			len += snprintf(page + len, count - len, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy);
+
+			for (j = 0; j < 16; j++) {
+				preorder_ctrl = &psta->recvreorder_ctrl[j];
+				if (preorder_ctrl->enable)
+					len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq);
+			}
+		}
+	}
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+	*eof = 1;
+	return len;
+}
+#endif
+
+int proc_get_best_channel(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data)
+{
+	struct net_device *dev = data;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	int len = 0;
+	u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0;
+
+	for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+		if (pmlmeext->channel_set[i].ChannelNum == 1)
+			index_24G = i;
+		if (pmlmeext->channel_set[i].ChannelNum == 36)
+			index_5G = i;
+	}
+
+	for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+		/*  2.4G */
+		if (pmlmeext->channel_set[i].ChannelNum == 6) {
+			if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) {
+				index_24G = i;
+				best_channel_24G = pmlmeext->channel_set[i].ChannelNum;
+			}
+		}
+
+		/*  5G */
+		if (pmlmeext->channel_set[i].ChannelNum >= 36 &&
+		    pmlmeext->channel_set[i].ChannelNum < 140) {
+			 /*  Find primary channel */
+			if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) &&
+			    (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
+				index_5G = i;
+				best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+			}
+		}
+
+		if (pmlmeext->channel_set[i].ChannelNum >= 149 &&
+		    pmlmeext->channel_set[i].ChannelNum < 165) {
+			 /*  find primary channel */
+			if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) &&
+			    (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
+				index_5G = i;
+				best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+			}
+		}
+		/*  debug */
+		len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
+					pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count);
+	}
+
+	len += snprintf(page + len, count - len, "best_channel_5G = %d\n", best_channel_5G);
+	len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
+
+	*eof = 1;
+	return len;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c
new file mode 100644
index 0000000..869434c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c
@@ -0,0 +1,875 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_EFUSE_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+
+
+/*------------------------Define local variable------------------------------*/
+u8 fakeEfuseBank;
+u32 fakeEfuseUsedBytes;
+u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0};
+u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0};
+u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0};
+
+u32 BTEfuseUsedBytes;
+u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+
+u32 fakeBTEfuseUsedBytes;
+u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0};
+/*------------------------Define local variable------------------------------*/
+
+/*  */
+#define REG_EFUSE_CTRL		0x0030
+#define EFUSE_CTRL			REG_EFUSE_CTRL		/*  E-Fuse Control. */
+/*  */
+
+bool
+Efuse_Read1ByteFromFakeContent(
+			struct adapter *pAdapter,
+			u16 Offset,
+		u8 *Value);
+bool
+Efuse_Read1ByteFromFakeContent(
+			struct adapter *pAdapter,
+			u16 Offset,
+		u8 *Value)
+{
+	if (Offset >= EFUSE_MAX_HW_SIZE)
+		return false;
+	if (fakeEfuseBank == 0)
+		*Value = fakeEfuseContent[Offset];
+	else
+		*Value = fakeBTEfuseContent[fakeEfuseBank-1][Offset];
+	return true;
+}
+
+static bool
+Efuse_Write1ByteToFakeContent(
+			struct adapter *pAdapter,
+			u16 Offset,
+			u8 Value)
+{
+	if (Offset >= EFUSE_MAX_HW_SIZE)
+		return false;
+	if (fakeEfuseBank == 0) {
+		fakeEfuseContent[Offset] = Value;
+	} else {
+		fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value;
+	}
+	return true;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	Efuse_PowerSwitch
+ *
+ * Overview:	When we want to enable write operation, we should change to
+ *				pwr on state. When we stop write, we should switch to 500k mode
+ *				and disable LDO 2.5V.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/17/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+Efuse_PowerSwitch(
+		struct adapter *pAdapter,
+		u8 write,
+		u8 PwrState)
+{
+	pAdapter->HalFunc.EfusePowerSwitch(pAdapter, write, PwrState);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_GetCurrentSize
+ *
+ * Overview:	Get current efuse size!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/16/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+u16
+Efuse_GetCurrentSize(
+	struct adapter *pAdapter,
+	u8 efuseType,
+	bool pseudo)
+{
+	u16 ret = 0;
+
+	ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, pseudo);
+
+	return ret;
+}
+
+/*  11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts(u8 word_en)
+{
+	u8 word_cnts = 0;
+	if (!(word_en & BIT(0)))
+		word_cnts++; /*  0 : write enable */
+	if (!(word_en & BIT(1)))
+		word_cnts++;
+	if (!(word_en & BIT(2)))
+		word_cnts++;
+	if (!(word_en & BIT(3)))
+		word_cnts++;
+	return word_cnts;
+}
+
+/*  */
+/* 	Description: */
+/* 		Execute E-Fuse read byte operation. */
+/* 		Refered from SD1 Richard. */
+/*  */
+/* 	Assumption: */
+/* 		1. Boot from E-Fuse and successfully auto-load. */
+/* 		2. PASSIVE_LEVEL (USB interface) */
+/*  */
+/* 	Created by Roger, 2008.10.21. */
+/*  */
+void
+ReadEFuseByte(
+		struct adapter *Adapter,
+		u16 _offset,
+		u8 *pbuf,
+		bool pseudo)
+{
+	u32 value32;
+	u8 readbyte;
+	u16 retry;
+
+	if (pseudo) {
+		Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf);
+		return;
+	}
+
+	/* Write Address */
+	rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff));
+	readbyte = rtw_read8(Adapter, EFUSE_CTRL+2);
+	rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+	/* Write bit 32 0 */
+	readbyte = rtw_read8(Adapter, EFUSE_CTRL+3);
+	rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f));
+
+	/* Check bit 32 read-ready */
+	retry = 0;
+	value32 = rtw_read32(Adapter, EFUSE_CTRL);
+	while (!(((value32 >> 24) & 0xff) & 0x80)  && (retry < 10000)) {
+		value32 = rtw_read32(Adapter, EFUSE_CTRL);
+		retry++;
+	}
+
+	/*  20100205 Joseph: Add delay suggested by SD1 Victor. */
+	/*  This fix the problem that Efuse read error in high temperature condition. */
+	/*  Designer says that there shall be some delay after ready bit is set, or the */
+	/*  result will always stay on last data we read. */
+	rtw_udelay_os(50);
+	value32 = rtw_read32(Adapter, EFUSE_CTRL);
+
+	*pbuf = (u8)(value32 & 0xff);
+}
+
+/*  */
+/* 	Description: */
+/* 		1. Execute E-Fuse read byte operation according as map offset and */
+/* 		    save to E-Fuse table. */
+/* 		2. Refered from SD1 Richard. */
+/*  */
+/* 	Assumption: */
+/* 		1. Boot from E-Fuse and successfully auto-load. */
+/* 		2. PASSIVE_LEVEL (USB interface) */
+/*  */
+/* 	Created by Roger, 2008.10.21. */
+/*  */
+/* 	2008/12/12 MH	1. Reorganize code flow and reserve bytes. and add description. */
+/* 					2. Add efuse utilization collect. */
+/* 	2008/12/22 MH	Read Efuse must check if we write section 1 data again!!! Sec1 */
+/* 					write addr must be after sec5. */
+/*  */
+
+static void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool pseudo)
+{
+	Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, pseudo);
+}
+
+void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool pseudo
+	)
+{
+	pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, pseudo);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_Read1Byte
+ *
+ * Overview:	Copy from WMAC fot EFUSE read 1 byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 09/23/2008	MHC		Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+u8 EFUSE_Read1Byte(struct adapter *Adapter, u16 Address)
+{
+	u8 data;
+	u8 Bytetemp = {0x00};
+	u8 temp = {0x00};
+	u32 k = 0;
+	u16 contentLen = 0;
+
+	EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false);
+
+	if (Address < contentLen) {	/* E-fuse 512Byte */
+		/* Write E-fuse Register address bit0~7 */
+		temp = Address & 0xFF;
+		rtw_write8(Adapter, EFUSE_CTRL+1, temp);
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);
+		/* Write E-fuse Register address bit8~9 */
+		temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
+		rtw_write8(Adapter, EFUSE_CTRL+2, temp);
+
+		/* Write 0x30[31]= 0 */
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+		temp = Bytetemp & 0x7F;
+		rtw_write8(Adapter, EFUSE_CTRL+3, temp);
+
+		/* Wait Write-ready (0x30[31]= 1) */
+		Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+		while (!(Bytetemp & 0x80)) {
+			Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+			k++;
+			if (k == 1000) {
+				k = 0;
+				break;
+			}
+		}
+		data = rtw_read8(Adapter, EFUSE_CTRL);
+		return data;
+	} else {
+		return 0xFF;
+	}
+
+} /* EFUSE_Read1Byte */
+
+/*  11/16/2008 MH Read one byte from real Efuse. */
+u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data, bool pseudo)
+{
+	u8 tmpidx = 0;
+	u8 result;
+
+	if (pseudo) {
+		result = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data);
+		return result;
+	}
+	/*  -----------------e-fuse reg ctrl --------------------------------- */
+	/* address */
+	rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr & 0xff));
+	rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) & 0x03)) |
+		   (rtw_read8(pAdapter, EFUSE_CTRL+2) & 0xFC));
+
+	rtw_write8(pAdapter, EFUSE_CTRL+3,  0x72);/* read cmd */
+
+	while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
+		tmpidx++;
+	if (tmpidx < 100) {
+		*data = rtw_read8(pAdapter, EFUSE_CTRL);
+		result = true;
+	} else {
+		*data = 0xff;
+		result = false;
+	}
+	return result;
+}
+
+/*  11/16/2008 MH Write one byte to reald Efuse. */
+u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data, bool pseudo)
+{
+	u8 tmpidx = 0;
+	u8 result;
+
+	if (pseudo) {
+		result = Efuse_Write1ByteToFakeContent(pAdapter, addr, data);
+		return result;
+	}
+
+	/*  -----------------e-fuse reg ctrl --------------------------------- */
+	/* address */
+	rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
+	rtw_write8(pAdapter, EFUSE_CTRL+2,
+		   (rtw_read8(pAdapter, EFUSE_CTRL+2) & 0xFC) |
+		   (u8)((addr>>8) & 0x03));
+	rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */
+
+	rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */
+
+	while ((0x80 &  rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx < 100))
+		tmpidx++;
+
+	if (tmpidx < 100)
+		result = true;
+	else
+		result = false;
+
+	return result;
+}
+
+int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool pseudo)
+{
+	int	ret = 0;
+
+	ret =  pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, pseudo);
+
+	return ret;
+}
+
+int Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo)
+{
+	int ret;
+
+	ret =  pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, pseudo);
+
+	return ret;
+}
+
+
+static int Efuse_PgPacketWrite_BT(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo)
+{
+	int ret;
+
+	ret =  pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, pseudo);
+
+	return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_WordEnableDataRead
+ *
+ * Overview:	Read allowed word in current efuse section data.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/16/2008	MHC		Create Version 0.
+ * 11/21/2008	MHC		Fix Write bug when we only enable late word.
+ *
+ *---------------------------------------------------------------------------*/
+void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata)
+{
+	if (!(word_en&BIT(0))) {
+		targetdata[0] = sourdata[0];
+		targetdata[1] = sourdata[1];
+	}
+	if (!(word_en&BIT(1))) {
+		targetdata[2] = sourdata[2];
+		targetdata[3] = sourdata[3];
+	}
+	if (!(word_en&BIT(2))) {
+		targetdata[4] = sourdata[4];
+		targetdata[5] = sourdata[5];
+	}
+	if (!(word_en&BIT(3))) {
+		targetdata[6] = sourdata[6];
+		targetdata[7] = sourdata[7];
+	}
+}
+
+u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool pseudo)
+{
+	u8 ret = 0;
+
+	ret =  pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, pseudo);
+
+	return ret;
+}
+
+static u8 efuse_read8(struct adapter *padapter, u16 address, u8 *value)
+{
+	return efuse_OneByteRead(padapter, address, value, false);
+}
+
+static u8 efuse_write8(struct adapter *padapter, u16 address, u8 *value)
+{
+	return efuse_OneByteWrite(padapter, address, *value, false);
+}
+
+/*
+ * read/wirte raw efuse data
+ */
+u8 rtw_efuse_access(struct adapter *padapter, u8 write, u16 start_addr, u16 cnts, u8 *data)
+{
+	int i = 0;
+	u16 real_content_len = 0, max_available_size = 0;
+	u8 res = _FAIL ;
+	u8 (*rw8)(struct adapter *, u16, u8*);
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&real_content_len, false);
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+
+	if (start_addr > real_content_len)
+		return _FAIL;
+
+	if (write) {
+		if ((start_addr + cnts) > max_available_size)
+			return _FAIL;
+		rw8 = &efuse_write8;
+	} else {
+		rw8 = &efuse_read8;
+	}
+
+	Efuse_PowerSwitch(padapter, write, true);
+
+	/*  e-fuse one byte read / write */
+	for (i = 0; i < cnts; i++) {
+		if (start_addr >= real_content_len) {
+			res = _FAIL;
+			break;
+		}
+
+		res = rw8(padapter, start_addr++, data++);
+		if (_FAIL == res)
+			break;
+	}
+
+	Efuse_PowerSwitch(padapter, write, false);
+
+	return res;
+}
+/*  */
+u16 efuse_GetMaxSize(struct adapter *padapter)
+{
+	u16 max_size;
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_size, false);
+	return max_size;
+}
+/*  */
+u8 efuse_GetCurrentSize(struct adapter *padapter, u16 *size)
+{
+	Efuse_PowerSwitch(padapter, false, true);
+	*size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, false);
+	Efuse_PowerSwitch(padapter, false, false);
+
+	return _SUCCESS;
+}
+/*  */
+u8 rtw_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16 mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	Efuse_PowerSwitch(padapter, false, true);
+
+	efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, false);
+
+	Efuse_PowerSwitch(padapter, false, false);
+
+	return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u16 mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	Efuse_PowerSwitch(padapter, false, true);
+
+	efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, false);
+
+	Efuse_PowerSwitch(padapter, false, false);
+
+	return _SUCCESS;
+}
+/*  */
+u8 rtw_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u8 offset, word_en;
+	u8 *map;
+	u8 newdata[PGPKT_DATA_SIZE];
+	s32	i, idx;
+	u8 ret = _SUCCESS;
+	u16 mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	map = rtw_zmalloc(mapLen);
+	if (map == NULL)
+		return _FAIL;
+
+	ret = rtw_efuse_map_read(padapter, 0, mapLen, map);
+	if (ret == _FAIL)
+		goto exit;
+
+	Efuse_PowerSwitch(padapter, true, true);
+
+	offset = (addr >> 3);
+	word_en = 0xF;
+	_rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+	i = addr & 0x7;	/*  index of one package */
+	idx = 0;	/*  data index */
+
+	if (i & 0x1) {
+		/*  odd start */
+		if (data[idx] != map[addr+idx]) {
+			word_en &= ~BIT(i >> 1);
+			newdata[i-1] = map[addr+idx-1];
+			newdata[i] = data[idx];
+		}
+		i++;
+		idx++;
+	}
+	do {
+		for (; i < PGPKT_DATA_SIZE; i += 2) {
+			if (cnts == idx)
+				break;
+			if ((cnts - idx) == 1) {
+				if (data[idx] != map[addr+idx]) {
+					word_en &= ~BIT(i >> 1);
+					newdata[i] = data[idx];
+					newdata[i+1] = map[addr+idx+1];
+				}
+				idx++;
+				break;
+			} else {
+				if ((data[idx] != map[addr+idx]) ||
+				    (data[idx+1] != map[addr+idx+1])) {
+					word_en &= ~BIT(i >> 1);
+					newdata[i] = data[idx];
+					newdata[i+1] = data[idx + 1];
+				}
+				idx += 2;
+			}
+			if (idx == cnts)
+				break;
+		}
+
+		if (word_en != 0xF) {
+			ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, false);
+			DBG_88E("offset=%x\n", offset);
+			DBG_88E("word_en=%x\n", word_en);
+
+			for (i = 0; i < PGPKT_DATA_SIZE; i++)
+				DBG_88E("data=%x \t", newdata[i]);
+			if (ret == _FAIL)
+				break;
+		}
+
+		if (idx == cnts)
+			break;
+
+		offset++;
+		i = 0;
+		word_en = 0xF;
+		_rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+	} while (1);
+
+	Efuse_PowerSwitch(padapter, true, false);
+exit:
+	kfree(map);
+	return ret;
+}
+
+/*  */
+u8 rtw_BT_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+	u8 offset, word_en;
+	u8 *map;
+	u8 newdata[PGPKT_DATA_SIZE];
+	s32	i, idx;
+	u8 ret = _SUCCESS;
+	u16 mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+	if ((addr + cnts) > mapLen)
+		return _FAIL;
+
+	map = rtw_zmalloc(mapLen);
+	if (map == NULL)
+		return _FAIL;
+
+	ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map);
+	if (ret == _FAIL)
+		goto exit;
+
+	Efuse_PowerSwitch(padapter, true, true);
+
+	offset = (addr >> 3);
+	word_en = 0xF;
+	_rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+	i = addr & 0x7;	/*  index of one package */
+	idx = 0;	/*  data index */
+
+	if (i & 0x1) {
+		/*  odd start */
+		if (data[idx] != map[addr+idx]) {
+			word_en &= ~BIT(i >> 1);
+			newdata[i-1] = map[addr+idx-1];
+			newdata[i] = data[idx];
+		}
+		i++;
+		idx++;
+	}
+	do {
+		for (; i < PGPKT_DATA_SIZE; i += 2) {
+			if (cnts == idx)
+				break;
+			if ((cnts - idx) == 1) {
+				if (data[idx] != map[addr+idx]) {
+					word_en &= ~BIT(i >> 1);
+					newdata[i] = data[idx];
+					newdata[i+1] = map[addr+idx+1];
+				}
+				idx++;
+				break;
+			} else {
+				if ((data[idx] != map[addr+idx]) ||
+				    (data[idx+1] != map[addr+idx+1])) {
+					word_en &= ~BIT(i >> 1);
+					newdata[i] = data[idx];
+					newdata[i+1] = data[idx + 1];
+				}
+				idx += 2;
+			}
+			if (idx == cnts)
+				break;
+		}
+
+		if (word_en != 0xF) {
+			DBG_88E("%s: offset=%#X\n", __func__, offset);
+			DBG_88E("%s: word_en=%#X\n", __func__, word_en);
+			DBG_88E("%s: data=", __func__);
+			for (i = 0; i < PGPKT_DATA_SIZE; i++)
+				DBG_88E("0x%02X ", newdata[i]);
+			DBG_88E("\n");
+
+			ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, false);
+			if (ret == _FAIL)
+				break;
+		}
+
+		if (idx == cnts)
+			break;
+
+		offset++;
+		i = 0;
+		word_en = 0xF;
+		_rtw_memset(newdata, 0xFF, PGPKT_DATA_SIZE);
+	} while (1);
+
+	Efuse_PowerSwitch(padapter, true, false);
+
+exit:
+
+	kfree(map);
+
+	return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	efuse_ShadowRead1Byte
+ *			efuse_ShadowRead2Byte
+ *			efuse_ShadowRead4Byte
+ *
+ * Overview:	Read from efuse init map by one/two/four bytes !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void
+efuse_ShadowRead1Byte(
+		struct adapter *pAdapter,
+		u16 Offset,
+		u8 *Value)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+	*Value = pEEPROM->efuse_eeprom_data[Offset];
+
+}	/*  EFUSE_ShadowRead1Byte */
+
+/* Read Two Bytes */
+static void
+efuse_ShadowRead2Byte(
+		struct adapter *pAdapter,
+		u16 Offset,
+		u16 *Value)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+	*Value = pEEPROM->efuse_eeprom_data[Offset];
+	*Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
+
+}	/*  EFUSE_ShadowRead2Byte */
+
+/* Read Four Bytes */
+static void
+efuse_ShadowRead4Byte(
+		struct adapter *pAdapter,
+		u16 Offset,
+		u32 *Value)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+	*Value = pEEPROM->efuse_eeprom_data[Offset];
+	*Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
+	*Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16;
+	*Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24;
+
+}	/*  efuse_ShadowRead4Byte */
+
+/*-----------------------------------------------------------------------------
+ * Function:	Efuse_ReadAllMap
+ *
+ * Overview:	Read All Efuse content
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/11/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse, bool pseudo)
+{
+	u16 mapLen = 0;
+
+	Efuse_PowerSwitch(pAdapter, false, true);
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo);
+
+	efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, pseudo);
+
+	Efuse_PowerSwitch(pAdapter, false, false);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowMapUpdate
+ *
+ * Overview:	Transfer current EFUSE content to shadow init and modify map.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/13/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowMapUpdate(
+	struct adapter *pAdapter,
+	u8 efuseType,
+	bool pseudo)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+	u16 mapLen = 0;
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo);
+
+	if (pEEPROM->bautoload_fail_flag)
+		_rtw_memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen);
+	else
+		Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data, pseudo);
+} /*  EFUSE_ShadowMapUpdate */
+
+/*-----------------------------------------------------------------------------
+ * Function:	EFUSE_ShadowRead
+ *
+ * Overview:	Read from efuse init map !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/12/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowRead(struct adapter *pAdapter, u8 Type, u16 Offset, u32 *Value)
+{
+	if (Type == 1)
+		efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
+	else if (Type == 2)
+		efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value);
+	else if (Type == 4)
+		efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value);
+
+}	/*  EFUSE_ShadowRead */
diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
new file mode 100644
index 0000000..3605c5d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c
@@ -0,0 +1,1640 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _IEEE80211_C
+
+#include <drv_types.h>
+#include <ieee80211.h>
+#include <wifi.h>
+#include <osdep_service.h>
+#include <wlan_bssdef.h>
+#include <usb_osintf.h>
+
+u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
+u16 RTW_WPA_VERSION = 1;
+u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
+u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
+u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
+
+u16 RSN_VERSION_BSD = 1;
+u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
+u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
+u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
+u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
+/*  */
+/*  for adhoc-master to generate ie and provide supported-rate to fw */
+/*  */
+
+static u8	WIFI_CCKRATES[] = {
+	(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
+	(IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
+	(IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
+	(IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)
+	};
+
+static u8	WIFI_OFDMRATES[] = {
+	 (IEEE80211_OFDM_RATE_6MB),
+	 (IEEE80211_OFDM_RATE_9MB),
+	 (IEEE80211_OFDM_RATE_12MB),
+	 (IEEE80211_OFDM_RATE_18MB),
+	 (IEEE80211_OFDM_RATE_24MB),
+	 IEEE80211_OFDM_RATE_36MB,
+	 IEEE80211_OFDM_RATE_48MB,
+	 IEEE80211_OFDM_RATE_54MB
+	};
+
+
+int rtw_get_bit_value_from_ieee_value(u8 val)
+{
+	unsigned char dot11_rate_table[] = {
+		2, 4, 11, 22, 12, 18, 24, 36, 48,
+		72, 96, 108, 0}; /*  last element must be zero!! */
+
+	int i = 0;
+	while (dot11_rate_table[i] != 0) {
+		if (dot11_rate_table[i] == val)
+			return BIT(i);
+		i++;
+	}
+	return 0;
+}
+
+uint	rtw_is_cckrates_included(u8 *rate)
+{
+	u32	i = 0;
+
+	while (rate[i] != 0) {
+		if  ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
+		     (((rate[i]) & 0x7f) == 11)  || (((rate[i]) & 0x7f) == 22))
+			return true;
+		i++;
+	}
+	return false;
+}
+
+uint	rtw_is_cckratesonly_included(u8 *rate)
+{
+	u32 i = 0;
+
+	while (rate[i] != 0) {
+		if  ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+		     (((rate[i]) & 0x7f) != 11)  && (((rate[i]) & 0x7f) != 22))
+			return false;
+		i++;
+	}
+
+	return true;
+}
+
+int rtw_check_network_type(unsigned char *rate, int ratelen, int channel)
+{
+	if (channel > 14) {
+		if ((rtw_is_cckrates_included(rate)) == true)
+			return WIRELESS_INVALID;
+		else
+			return WIRELESS_11A;
+	} else {  /*  could be pure B, pure G, or B/G */
+		if ((rtw_is_cckratesonly_included(rate)) == true)
+			return WIRELESS_11B;
+		else if ((rtw_is_cckrates_included(rate)) == true)
+			return	WIRELESS_11BG;
+		else
+			return WIRELESS_11G;
+	}
+}
+
+u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source,
+				unsigned int *frlen)
+{
+	memcpy((void *)pbuf, (void *)source, len);
+	*frlen = *frlen + len;
+	return pbuf + len;
+}
+
+/*  rtw_set_ie will update frame length */
+u8 *rtw_set_ie
+(
+	u8 *pbuf,
+	int index,
+	uint len,
+	u8 *source,
+	uint *frlen /* frame length */
+)
+{
+_func_enter_;
+	*pbuf = (u8)index;
+
+	*(pbuf + 1) = (u8)len;
+
+	if (len > 0)
+		memcpy((void *)(pbuf + 2), (void *)source, len);
+
+	*frlen = *frlen + (len + 2);
+
+	return pbuf + len + 2;
+_func_exit_;
+}
+
+inline u8 *rtw_set_ie_ch_switch (u8 *buf, u32 *buf_len, u8 ch_switch_mode,
+	u8 new_ch, u8 ch_switch_cnt)
+{
+	u8 ie_data[3];
+
+	ie_data[0] = ch_switch_mode;
+	ie_data[1] = new_ch;
+	ie_data[2] = ch_switch_cnt;
+	return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH,  3, ie_data, buf_len);
+}
+
+inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset)
+{
+	if (ch_offset == SCN)
+		return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	else if (ch_offset == SCA)
+		return HAL_PRIME_CHNL_OFFSET_UPPER;
+	else if (ch_offset == SCB)
+		return HAL_PRIME_CHNL_OFFSET_LOWER;
+
+	return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+}
+
+inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset)
+{
+	if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+		return SCN;
+	else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+		return SCB;
+	else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+		return SCA;
+
+	return SCN;
+}
+
+inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset)
+{
+	return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET,  1, &secondary_ch_offset, buf_len);
+}
+
+inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
+	u8 flags, u16 reason, u16 precedence)
+{
+	u8 ie_data[6];
+
+	ie_data[0] = ttl;
+	ie_data[1] = flags;
+	RTW_PUT_LE16((u8 *)&ie_data[2], reason);
+	RTW_PUT_LE16((u8 *)&ie_data[4], precedence);
+
+	return rtw_set_ie(buf, 0x118,  6, ie_data, buf_len);
+}
+
+/*----------------------------------------------------------------------------
+index: the information element id index, limit is the limit for search
+-----------------------------------------------------------------------------*/
+u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit)
+{
+	int tmp, i;
+	u8 *p;
+_func_enter_;
+	if (limit < 1) {
+		_func_exit_;
+		return NULL;
+	}
+
+	p = pbuf;
+	i = 0;
+	*len = 0;
+	while (1) {
+		if (*p == index) {
+			*len = *(p + 1);
+			return p;
+		} else {
+			tmp = *(p + 1);
+			p += (tmp + 2);
+			i += (tmp + 2);
+		}
+		if (i >= limit)
+			break;
+	}
+_func_exit_;
+	return NULL;
+}
+
+/**
+ * rtw_get_ie_ex - Search specific IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE
+ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE
+ *
+ * Returns: The address of the specific IE found, or NULL
+ */
+u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen)
+{
+	uint cnt;
+	u8 *target_ie = NULL;
+
+
+	if (ielen)
+		*ielen = 0;
+
+	if (!in_ie || in_len <= 0)
+		return target_ie;
+
+	cnt = 0;
+
+	while (cnt < in_len) {
+		if (eid == in_ie[cnt] && (!oui || _rtw_memcmp(&in_ie[cnt+2], oui, oui_len))) {
+			target_ie = &in_ie[cnt];
+
+			if (ie)
+				memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+			if (ielen)
+				*ielen = in_ie[cnt+1]+2;
+
+			break;
+		} else {
+			cnt += in_ie[cnt+1]+2; /* goto next */
+		}
+	}
+	return target_ie;
+}
+
+/**
+ * rtw_ies_remove_ie - Find matching IEs and remove
+ * @ies: Address of IEs to search
+ * @ies_len: Pointer of length of ies, will update to new length
+ * @offset: The offset to start scarch
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ *
+ * Returns: _SUCCESS: ies is updated, _FAIL: not updated
+ */
+int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len)
+{
+	int ret = _FAIL;
+	u8 *target_ie;
+	u32 target_ielen;
+	u8 *start;
+	uint search_len;
+
+	if (!ies || !ies_len || *ies_len <= offset)
+		goto exit;
+
+	start = ies + offset;
+	search_len = *ies_len - offset;
+
+	while (1) {
+		target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen);
+		if (target_ie && target_ielen) {
+			u8 buf[MAX_IE_SZ] = {0};
+			u8 *remain_ies = target_ie + target_ielen;
+			uint remain_len = search_len - (remain_ies - start);
+
+			memcpy(buf, remain_ies, remain_len);
+			memcpy(target_ie, buf, remain_len);
+			*ies_len = *ies_len - target_ielen;
+			ret = _SUCCESS;
+
+			start = target_ie;
+			search_len = remain_len;
+		} else {
+			break;
+		}
+	}
+exit:
+	return ret;
+}
+
+void rtw_set_supported_rate(u8 *SupportedRates, uint mode)
+{
+_func_enter_;
+
+	_rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+	switch (mode) {
+	case WIRELESS_11B:
+		memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+		break;
+	case WIRELESS_11G:
+	case WIRELESS_11A:
+	case WIRELESS_11_5N:
+	case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */
+		memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+		break;
+	case WIRELESS_11BG:
+	case WIRELESS_11G_24N:
+	case WIRELESS_11_24N:
+	case WIRELESS_11BG_24N:
+		memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+		memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN);
+		break;
+	}
+_func_exit_;
+}
+
+uint	rtw_get_rateset_len(u8	*rateset)
+{
+	uint i = 0;
+_func_enter_;
+	while (1) {
+		if ((rateset[i]) == 0)
+			break;
+		if (i > 12)
+			break;
+		i++;
+	}
+_func_exit_;
+	return i;
+}
+
+int rtw_generate_ie(struct registry_priv *pregistrypriv)
+{
+	u8	wireless_mode;
+	int	sz = 0, rateLen;
+	struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
+	u8 *ie = pdev_network->IEs;
+
+_func_enter_;
+
+	/* timestamp will be inserted by hardware */
+	sz += 8;
+	ie += sz;
+
+	/* beacon interval : 2bytes */
+	*(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */
+	sz += 2;
+	ie += 2;
+
+	/* capability info */
+	*(u16 *)ie = 0;
+
+	*(__le16 *)ie |= cpu_to_le16(cap_IBSS);
+
+	if (pregistrypriv->preamble == PREAMBLE_SHORT)
+		*(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
+
+	if (pdev_network->Privacy)
+		*(__le16 *)ie |= cpu_to_le16(cap_Privacy);
+
+	sz += 2;
+	ie += 2;
+
+	/* SSID */
+	ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz);
+
+	/* supported rates */
+	if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) {
+		if (pdev_network->Configuration.DSConfig > 14)
+			wireless_mode = WIRELESS_11A_5N;
+		else
+			wireless_mode = WIRELESS_11BG_24N;
+	} else {
+		wireless_mode = pregistrypriv->wireless_mode;
+	}
+
+		rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
+
+	rateLen = rtw_get_rateset_len(pdev_network->SupportedRates);
+
+	if (rateLen > 8) {
+		ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz);
+		/* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */
+	} else {
+		ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz);
+	}
+
+	/* DS parameter set */
+	ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz);
+
+	/* IBSS Parameter Set */
+
+	ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz);
+
+	if (rateLen > 8)
+		ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz);
+_func_exit_;
+
+	return sz;
+}
+
+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit)
+{
+	int len;
+	u16 val16;
+	__le16 le_tmp;
+	unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
+	u8 *pbuf = pie;
+	int limit_new = limit;
+
+	while (1) {
+		pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
+
+		if (pbuf) {
+			/* check if oui matches... */
+			if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof (wpa_oui_type)) == false)
+				goto check_next_ie;
+
+			/* check version... */
+			memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16));
+
+			val16 = le16_to_cpu(le_tmp);
+			if (val16 != 0x0001)
+				goto check_next_ie;
+			*wpa_ie_len = *(pbuf + 1);
+			return pbuf;
+		} else {
+			*wpa_ie_len = 0;
+			return NULL;
+		}
+
+check_next_ie:
+		limit_new = limit - (pbuf - pie) - 2 - len;
+		if (limit_new <= 0)
+			break;
+		pbuf += (2 + len);
+	}
+	*wpa_ie_len = 0;
+	return NULL;
+}
+
+unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit)
+{
+
+	return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit);
+}
+
+int rtw_get_wpa_cipher_suite(u8 *s)
+{
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == true)
+		return WPA_CIPHER_NONE;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == true)
+		return WPA_CIPHER_WEP40;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == true)
+		return WPA_CIPHER_TKIP;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == true)
+		return WPA_CIPHER_CCMP;
+	if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == true)
+		return WPA_CIPHER_WEP104;
+
+	return 0;
+}
+
+int rtw_get_wpa2_cipher_suite(u8 *s)
+{
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == true)
+		return WPA_CIPHER_NONE;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == true)
+		return WPA_CIPHER_WEP40;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == true)
+		return WPA_CIPHER_TKIP;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == true)
+		return WPA_CIPHER_CCMP;
+	if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == true)
+		return WPA_CIPHER_WEP104;
+
+	return 0;
+}
+
+
+int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+	int i, ret = _SUCCESS;
+	int left, count;
+	u8 *pos;
+	u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
+
+	if (wpa_ie_len <= 0) {
+		/* No WPA IE - fail silently */
+		return _FAIL;
+	}
+
+
+	if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) ||
+	    (_rtw_memcmp(wpa_ie+2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != true))
+		return _FAIL;
+
+	pos = wpa_ie;
+
+	pos += 8;
+	left = wpa_ie_len - 8;
+
+
+	/* group_cipher */
+	if (left >= WPA_SELECTOR_LEN) {
+		*group_cipher = rtw_get_wpa_cipher_suite(pos);
+		pos += WPA_SELECTOR_LEN;
+		left -= WPA_SELECTOR_LEN;
+	} else if (left > 0) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
+		return _FAIL;
+	}
+
+	/* pairwise_cipher */
+	if (left >= 2) {
+		count = RTW_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), "
+						"count %u left %u", __func__, count, left));
+			return _FAIL;
+		}
+
+		for (i = 0; i < count; i++) {
+			*pairwise_cipher |= rtw_get_wpa_cipher_suite(pos);
+
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)",   __func__));
+		return _FAIL;
+	}
+
+	if (is_8021x) {
+		if (left >= 6) {
+			pos += 2;
+			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s : there has 802.1x auth\n", __func__));
+				*is_8021x = 1;
+			}
+		}
+	}
+
+	return ret;
+}
+
+int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+	int i, ret = _SUCCESS;
+	int left, count;
+	u8 *pos;
+	u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
+
+	if (rsn_ie_len <= 0) {
+		/* No RSN IE - fail silently */
+		return _FAIL;
+	}
+
+
+	if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2)))
+		return _FAIL;
+
+	pos = rsn_ie;
+	pos += 4;
+	left = rsn_ie_len - 4;
+
+	/* group_cipher */
+	if (left >= RSN_SELECTOR_LEN) {
+		*group_cipher = rtw_get_wpa2_cipher_suite(pos);
+
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+
+	} else if (left > 0) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie length mismatch, %u too much", __func__, left));
+		return _FAIL;
+	}
+
+	/* pairwise_cipher */
+	if (left >= 2) {
+		count = RTW_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie count botch (pairwise), "
+						 "count %u left %u", __func__, count, left));
+			return _FAIL;
+		}
+
+		for (i = 0; i < count; i++) {
+			*pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos);
+
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+
+	} else if (left == 1) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s: ie too short (for key mgmt)",  __func__));
+
+		return _FAIL;
+	}
+
+	if (is_8021x) {
+		if (left >= 6) {
+			pos += 2;
+			if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s (): there has 802.1x auth\n", __func__));
+				*is_8021x = 1;
+			}
+		}
+	}
+	return ret;
+}
+
+int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len)
+{
+	u8 authmode, sec_idx, i;
+	u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
+	uint	cnt;
+
+_func_enter_;
+
+	/* Search required WPA or WPA2 IE and copy to sec_ie[] */
+
+	cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
+
+	sec_idx = 0;
+
+	while (cnt < in_len) {
+		authmode = in_ie[cnt];
+
+		if ((authmode == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt+2], &wpa_oui[0], 4))) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+					 ("\n rtw_get_wpa_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
+					 sec_idx, in_ie[cnt+1]+2));
+
+				if (wpa_ie) {
+					memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+					for (i = 0; i < (in_ie[cnt+1]+2); i += 8) {
+						RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+							 ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+							 wpa_ie[i], wpa_ie[i+1], wpa_ie[i+2], wpa_ie[i+3], wpa_ie[i+4],
+							 wpa_ie[i+5], wpa_ie[i+6], wpa_ie[i+7]));
+					}
+				}
+
+				*wpa_len = in_ie[cnt+1]+2;
+				cnt += in_ie[cnt+1]+2;  /* get next */
+		} else {
+			if (authmode == _WPA2_IE_ID_) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+					 ("\n get_rsn_ie: sec_idx =%d in_ie[cnt+1]+2 =%d\n",
+					 sec_idx, in_ie[cnt+1]+2));
+
+				if (rsn_ie) {
+					memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+					for (i = 0; i < (in_ie[cnt+1]+2); i += 8) {
+						RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+							 ("\n %2x,%2x,%2x,%2x,%2x,%2x,%2x,%2x\n",
+							 rsn_ie[i], rsn_ie[i+1], rsn_ie[i+2], rsn_ie[i+3], rsn_ie[i+4],
+							 rsn_ie[i+5], rsn_ie[i+6], rsn_ie[i+7]));
+						}
+				}
+
+				*rsn_len = in_ie[cnt+1]+2;
+				cnt += in_ie[cnt+1]+2;  /* get next */
+			} else {
+				cnt += in_ie[cnt+1]+2;   /* get next */
+			}
+		}
+	}
+
+_func_exit_;
+
+	return *rsn_len + *wpa_len;
+}
+
+u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen)
+{
+	u8 match = false;
+	u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+	if (ie_ptr == NULL)
+		return match;
+
+	eid = ie_ptr[0];
+
+	if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&ie_ptr[2], wps_oui, 4))) {
+		*wps_ielen = ie_ptr[1]+2;
+		match = true;
+	}
+	return match;
+}
+
+/**
+ * rtw_get_wps_ie - Search WPS IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie
+ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE
+ *
+ * Returns: The address of the WPS IE found, or NULL
+ */
+u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
+{
+	uint cnt;
+	u8 *wpsie_ptr = NULL;
+	u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+	if (wps_ielen)
+		*wps_ielen = 0;
+
+	if (!in_ie || in_len <= 0)
+		return wpsie_ptr;
+
+	cnt = 0;
+
+	while (cnt < in_len) {
+		eid = in_ie[cnt];
+
+		if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt+2], wps_oui, 4))) {
+			wpsie_ptr = &in_ie[cnt];
+
+			if (wps_ie)
+				memcpy(wps_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+			if (wps_ielen)
+				*wps_ielen = in_ie[cnt+1]+2;
+
+			cnt += in_ie[cnt+1]+2;
+
+			break;
+		} else {
+			cnt += in_ie[cnt+1]+2; /* goto next */
+		}
+	}
+	return wpsie_ptr;
+}
+
+/**
+ * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE
+ * @wps_ie: Address of WPS IE to search
+ * @wps_ielen: Length limit from wps_ie
+ * @target_attr_id: The attribute ID of WPS attribute to search
+ * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_attr, u32 *len_attr)
+{
+	u8 *attr_ptr = NULL;
+	u8 *target_attr_ptr = NULL;
+	u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04};
+
+	if (len_attr)
+		*len_attr = 0;
+
+	if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+	    (_rtw_memcmp(wps_ie + 2, wps_oui , 4) != true))
+		return attr_ptr;
+
+	/*  6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
+	attr_ptr = wps_ie + 6; /* goto first attr */
+
+	while (attr_ptr - wps_ie < wps_ielen) {
+		/*  4 = 2(Attribute ID) + 2(Length) */
+		u16 attr_id = RTW_GET_BE16(attr_ptr);
+		u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2);
+		u16 attr_len = attr_data_len + 4;
+
+		if (attr_id == target_attr_id) {
+			target_attr_ptr = attr_ptr;
+			if (buf_attr)
+				memcpy(buf_attr, attr_ptr, attr_len);
+			if (len_attr)
+				*len_attr = attr_len;
+			break;
+		} else {
+			attr_ptr += attr_len; /* goto next */
+		}
+	}
+	return target_attr_ptr;
+}
+
+/**
+ * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE
+ * @wps_ie: Address of WPS IE to search
+ * @wps_ielen: Length limit from wps_ie
+ * @target_attr_id: The attribute ID of WPS attribute to search
+ * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content
+ *
+ * Returns: the address of the specific WPS attribute content found, or NULL
+ */
+u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_content, uint *len_content)
+{
+	u8 *attr_ptr;
+	u32 attr_len;
+
+	if (len_content)
+		*len_content = 0;
+
+	attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len);
+
+	if (attr_ptr && attr_len) {
+		if (buf_content)
+			memcpy(buf_content, attr_ptr+4, attr_len-4);
+
+		if (len_content)
+			*len_content = attr_len-4;
+
+		return attr_ptr+4;
+	}
+
+	return NULL;
+}
+
+static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
+					    struct rtw_ieee802_11_elems *elems,
+					    int show_errors)
+{
+	unsigned int oui;
+
+	/* first 3 bytes in vendor specific information element are the IEEE
+	 * OUI of the vendor. The following byte is used a vendor specific
+	 * sub-type. */
+	if (elen < 4) {
+		if (show_errors) {
+			DBG_88E("short vendor specific information element ignored (len=%lu)\n",
+				(unsigned long) elen);
+		}
+		return -1;
+	}
+
+	oui = RTW_GET_BE24(pos);
+	switch (oui) {
+	case OUI_MICROSOFT:
+		/* Microsoft/Wi-Fi information elements are further typed and
+		 * subtyped */
+		switch (pos[3]) {
+		case 1:
+			/* Microsoft OUI (00:50:F2) with OUI Type 1:
+			 * real WPA information element */
+			elems->wpa_ie = pos;
+			elems->wpa_ie_len = elen;
+			break;
+		case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
+			if (elen < 5) {
+				DBG_88E("short WME information element ignored (len=%lu)\n",
+					(unsigned long) elen);
+				return -1;
+			}
+			switch (pos[4]) {
+			case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
+			case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
+				elems->wme = pos;
+				elems->wme_len = elen;
+				break;
+			case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
+				elems->wme_tspec = pos;
+				elems->wme_tspec_len = elen;
+				break;
+			default:
+				DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n",
+					pos[4], (unsigned long) elen);
+				return -1;
+			}
+			break;
+		case 4:
+			/* Wi-Fi Protected Setup (WPS) IE */
+			elems->wps_ie = pos;
+			elems->wps_ie_len = elen;
+			break;
+		default:
+			DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n",
+				pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_BROADCOM:
+		switch (pos[3]) {
+		case VENDOR_HT_CAPAB_OUI_TYPE:
+			elems->vendor_ht_cap = pos;
+			elems->vendor_ht_cap_len = elen;
+			break;
+		default:
+			DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n",
+				pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+	default:
+		DBG_88E("unknown vendor specific information element ignored (vendor OUI %02x:%02x:%02x len=%lu)\n",
+			pos[0], pos[1], pos[2], (unsigned long) elen);
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
+				struct rtw_ieee802_11_elems *elems,
+				int show_errors)
+{
+	uint left = len;
+	u8 *pos = start;
+	int unknown = 0;
+
+	_rtw_memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left) {
+			if (show_errors) {
+				DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n",
+					id, elen, (unsigned long) left);
+			}
+			return ParseFailed;
+		}
+
+		switch (id) {
+		case WLAN_EID_SSID:
+			elems->ssid = pos;
+			elems->ssid_len = elen;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			elems->supp_rates = pos;
+			elems->supp_rates_len = elen;
+			break;
+		case WLAN_EID_FH_PARAMS:
+			elems->fh_params = pos;
+			elems->fh_params_len = elen;
+			break;
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_CF_PARAMS:
+			elems->cf_params = pos;
+			elems->cf_params_len = elen;
+			break;
+		case WLAN_EID_TIM:
+			elems->tim = pos;
+			elems->tim_len = elen;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			elems->ibss_params = pos;
+			elems->ibss_params_len = elen;
+			break;
+		case WLAN_EID_CHALLENGE:
+			elems->challenge = pos;
+			elems->challenge_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		case WLAN_EID_VENDOR_SPECIFIC:
+			if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors))
+				unknown++;
+			break;
+		case WLAN_EID_RSN:
+			elems->rsn_ie = pos;
+			elems->rsn_ie_len = elen;
+			break;
+		case WLAN_EID_PWR_CAPABILITY:
+			elems->power_cap = pos;
+			elems->power_cap_len = elen;
+			break;
+		case WLAN_EID_SUPPORTED_CHANNELS:
+			elems->supp_channels = pos;
+			elems->supp_channels_len = elen;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			elems->mdie = pos;
+			elems->mdie_len = elen;
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			elems->ftie = pos;
+			elems->ftie_len = elen;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			elems->timeout_int = pos;
+			elems->timeout_int_len = elen;
+			break;
+		case WLAN_EID_HT_CAP:
+			elems->ht_capabilities = pos;
+			elems->ht_capabilities_len = elen;
+			break;
+		case WLAN_EID_HT_OPERATION:
+			elems->ht_operation = pos;
+			elems->ht_operation_len = elen;
+			break;
+		default:
+			unknown++;
+			if (!show_errors)
+				break;
+			DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n",
+				id, elen);
+			break;
+		}
+		left -= elen;
+		pos += elen;
+	}
+	if (left)
+		return ParseFailed;
+	return unknown ? ParseUnknown : ParseOK;
+}
+
+u8 key_char2num(u8 ch)
+{
+	if ((ch >= '0') && (ch <= '9'))
+		return ch - '0';
+	else if ((ch >= 'a') && (ch <= 'f'))
+		return ch - 'a' + 10;
+	else if ((ch >= 'A') && (ch <= 'F'))
+		return ch - 'A' + 10;
+	else
+		return 0xff;
+}
+
+u8 str_2char2num(u8 hch, u8 lch)
+{
+    return (key_char2num(hch) * 10) + key_char2num(lch);
+}
+
+u8 key_2char2num(u8 hch, u8 lch)
+{
+    return (key_char2num(hch) << 4) | key_char2num(lch);
+}
+
+void rtw_macaddr_cfg(u8 *mac_addr)
+{
+	u8 mac[ETH_ALEN];
+	if (mac_addr == NULL)
+		return;
+
+	if (rtw_initmac) {	/* Users specify the mac address */
+		int jj, kk;
+
+		for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+			mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]);
+		memcpy(mac_addr, mac, ETH_ALEN);
+	} else {	/* Use the mac address stored in the Efuse */
+		memcpy(mac, mac_addr, ETH_ALEN);
+	}
+
+	if (((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) &&
+	     (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff)) ||
+	    ((mac[0] == 0x0) && (mac[1] == 0x0) && (mac[2] == 0x0) &&
+	     (mac[3] == 0x0) && (mac[4] == 0x0) && (mac[5] == 0x0))) {
+		mac[0] = 0x00;
+		mac[1] = 0xe0;
+		mac[2] = 0x4c;
+		mac[3] = 0x87;
+		mac[4] = 0x00;
+		mac[5] = 0x00;
+		/*  use default mac addresss */
+		memcpy(mac_addr, mac, ETH_ALEN);
+		DBG_88E("MAC Address from efuse error, assign default one !!!\n");
+	}
+
+	DBG_88E("rtw_macaddr_cfg MAC Address  = %pM\n", (mac_addr));
+}
+
+void dump_ies(u8 *buf, u32 buf_len)
+{
+	u8 *pos = (u8 *)buf;
+	u8 id, len;
+
+	while (pos-buf <= buf_len) {
+		id = *pos;
+		len = *(pos+1);
+
+		DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len);
+		#ifdef CONFIG_88EU_P2P
+		dump_p2p_ie(pos, len);
+		#endif
+		dump_wps_ie(pos, len);
+
+		pos += (2 + len);
+	}
+}
+
+void dump_wps_ie(u8 *ie, u32 ie_len)
+{
+	u8 *pos = (u8 *)ie;
+	u16 id;
+	u16 len;
+	u8 *wps_ie;
+	uint wps_ielen;
+
+	wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen);
+	if (wps_ie != ie || wps_ielen == 0)
+		return;
+
+	pos += 6;
+	while (pos-ie < ie_len) {
+		id = RTW_GET_BE16(pos);
+		len = RTW_GET_BE16(pos + 2);
+		DBG_88E("%s ID:0x%04x, LEN:%u\n", __func__, id, len);
+		pos += (4+len);
+	}
+}
+
+#ifdef CONFIG_88EU_P2P
+void dump_p2p_ie(u8 *ie, u32 ie_len)
+{
+	u8 *pos = (u8 *)ie;
+	u8 id;
+	u16 len;
+	u8 *p2p_ie;
+	uint p2p_ielen;
+
+	p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen);
+	if (p2p_ie != ie || p2p_ielen == 0)
+		return;
+
+	pos += 6;
+	while (pos-ie < ie_len) {
+		id = *pos;
+		len = RTW_GET_LE16(pos+1);
+		DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len);
+		pos += (3+len);
+	}
+}
+
+/**
+ * rtw_get_p2p_ie - Search P2P IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie
+ * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE
+ *
+ * Returns: The address of the P2P IE found, or NULL
+ */
+u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
+{
+	uint cnt = 0;
+	u8 *p2p_ie_ptr;
+	u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
+
+	if (p2p_ielen != NULL)
+		*p2p_ielen = 0;
+
+	while (cnt < in_len) {
+		eid = in_ie[cnt];
+		if ((in_len < 0) || (cnt > MAX_IE_SZ)) {
+			dump_stack();
+			return NULL;
+		}
+		if ((eid == _VENDOR_SPECIFIC_IE_) && (_rtw_memcmp(&in_ie[cnt+2], p2p_oui, 4) == true)) {
+			p2p_ie_ptr = in_ie + cnt;
+
+			if (p2p_ie != NULL)
+				memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+			if (p2p_ielen != NULL)
+				*p2p_ielen = in_ie[cnt + 1] + 2;
+			return p2p_ie_ptr;
+		} else {
+			cnt += in_ie[cnt + 1] + 2; /* goto next */
+		}
+	}
+	return NULL;
+}
+
+/**
+ * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE
+ * @p2p_ie: Address of P2P IE to search
+ * @p2p_ielen: Length limit from p2p_ie
+ * @target_attr_id: The attribute ID of P2P attribute to search
+ * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_attr, u32 *len_attr)
+{
+	u8 *attr_ptr = NULL;
+	u8 *target_attr_ptr = NULL;
+	u8 p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09};
+
+	if (len_attr)
+		*len_attr = 0;
+
+	if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+	    (_rtw_memcmp(p2p_ie + 2, p2p_oui , 4) != true))
+		return attr_ptr;
+
+	/*  6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */
+	attr_ptr = p2p_ie + 6; /* goto first attr */
+
+	while (attr_ptr - p2p_ie < p2p_ielen) {
+		/*  3 = 1(Attribute ID) + 2(Length) */
+		u8 attr_id = *attr_ptr;
+		u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1);
+		u16 attr_len = attr_data_len + 3;
+
+		if (attr_id == target_attr_id) {
+			target_attr_ptr = attr_ptr;
+
+			if (buf_attr)
+				memcpy(buf_attr, attr_ptr, attr_len);
+			if (len_attr)
+				*len_attr = attr_len;
+			break;
+		} else {
+			attr_ptr += attr_len; /* goto next */
+		}
+	}
+	return target_attr_ptr;
+}
+
+/**
+ * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE
+ * @p2p_ie: Address of P2P IE to search
+ * @p2p_ielen: Length limit from p2p_ie
+ * @target_attr_id: The attribute ID of P2P attribute to search
+ * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content
+ *
+ * Returns: the address of the specific P2P attribute content found, or NULL
+ */
+u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_content, uint *len_content)
+{
+	u8 *attr_ptr;
+	u32 attr_len;
+
+	if (len_content)
+		*len_content = 0;
+
+	attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len);
+
+	if (attr_ptr && attr_len) {
+		if (buf_content)
+			memcpy(buf_content, attr_ptr+3, attr_len-3);
+
+		if (len_content)
+			*len_content = attr_len-3;
+
+		return attr_ptr+3;
+	}
+
+	return NULL;
+}
+
+u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr)
+{
+	u32 a_len;
+
+	*pbuf = attr_id;
+
+	/* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */
+	RTW_PUT_LE16(pbuf + 1, attr_len);
+
+	if (pdata_attr)
+		memcpy(pbuf + 3, pdata_attr, attr_len);
+
+	a_len = attr_len + 3;
+
+	return a_len;
+}
+
+static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id)
+{
+	u8 *target_attr;
+	u32 target_attr_len;
+	uint ielen = ielen_ori;
+
+	while (1) {
+		target_attr = rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len);
+		if (target_attr && target_attr_len) {
+			u8 *next_attr = target_attr+target_attr_len;
+			uint remain_len = ielen-(next_attr-ie);
+
+			_rtw_memset(target_attr, 0, target_attr_len);
+			memcpy(target_attr, next_attr, remain_len);
+			_rtw_memset(target_attr+remain_len, 0, target_attr_len);
+			*(ie+1) -= target_attr_len;
+			ielen -= target_attr_len;
+		} else {
+			break;
+		}
+	}
+	return ielen;
+}
+
+void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex, u8 attr_id)
+{
+	u8 *p2p_ie;
+	uint p2p_ielen, p2p_ielen_ori;
+
+	p2p_ie = rtw_get_p2p_ie(bss_ex->IEs+_FIXED_IE_LENGTH_, bss_ex->IELength-_FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori);
+	if (p2p_ie) {
+		p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id);
+		if (p2p_ielen != p2p_ielen_ori) {
+			u8 *next_ie_ori = p2p_ie+p2p_ielen_ori;
+			u8 *next_ie = p2p_ie+p2p_ielen;
+			uint remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs);
+
+			memcpy(next_ie, next_ie_ori, remain_len);
+			_rtw_memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen);
+			bss_ex->IELength -= p2p_ielen_ori-p2p_ielen;
+		}
+	}
+}
+
+#endif /* CONFIG_88EU_P2P */
+
+/* Baron adds to avoid FreeBSD warning */
+int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+	/* Single white space is for Linksys APs */
+	if (essid_len == 1 && essid[0] == ' ')
+		return 1;
+
+	/* Otherwise, if the entire essid is 0, we assume it is hidden */
+	while (essid_len) {
+		essid_len--;
+		if (essid[essid_len] != '\0')
+			return 0;
+	}
+
+	return 1;
+}
+
+int ieee80211_get_hdrlen(u16 fc)
+{
+	int hdrlen = 24;
+
+	switch (WLAN_FC_GET_TYPE(fc)) {
+	case RTW_IEEE80211_FTYPE_DATA:
+		if (fc & RTW_IEEE80211_STYPE_QOS_DATA)
+			hdrlen += 2;
+		if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS))
+			hdrlen += 6; /* Addr4 */
+		break;
+	case RTW_IEEE80211_FTYPE_CTL:
+		switch (WLAN_FC_GET_STYPE(fc)) {
+		case RTW_IEEE80211_STYPE_CTS:
+		case RTW_IEEE80211_STYPE_ACK:
+			hdrlen = 10;
+			break;
+		default:
+			hdrlen = 16;
+			break;
+		}
+		break;
+	}
+
+	return hdrlen;
+}
+
+static int rtw_get_cipher_info(struct wlan_network *pnetwork)
+{
+	u32 wpa_ielen;
+	unsigned char *pbuf;
+	int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
+	int ret = _FAIL;
+	pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+
+	if (pbuf && (wpa_ielen > 0)) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen));
+		if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) {
+			pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
+			pnetwork->BcnInfo.group_cipher = group_cipher;
+			pnetwork->BcnInfo.is_8021x = is8021x;
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d, is_8021x is %d",
+				 __func__, pnetwork->BcnInfo.pairwise_cipher, pnetwork->BcnInfo.is_8021x));
+			ret = _SUCCESS;
+		}
+	} else {
+		pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+
+		if (pbuf && (wpa_ielen > 0)) {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE\n"));
+			if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is8021x)) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("get RSN IE  OK!!!\n"));
+				pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
+				pnetwork->BcnInfo.group_cipher = group_cipher;
+				pnetwork->BcnInfo.is_8021x = is8021x;
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: pnetwork->pairwise_cipher: %d,"
+							"pnetwork->group_cipher is %d, is_8021x is %d",	__func__, pnetwork->BcnInfo.pairwise_cipher,
+							pnetwork->BcnInfo.group_cipher, pnetwork->BcnInfo.is_8021x));
+				ret = _SUCCESS;
+			}
+		}
+	}
+
+	return ret;
+}
+
+void rtw_get_bcn_info(struct wlan_network *pnetwork)
+{
+	unsigned short cap = 0;
+	u8 bencrypt = 0;
+	__le16 le_tmp;
+	u16 wpa_len = 0, rsn_len = 0;
+	struct HT_info_element *pht_info = NULL;
+	struct rtw_ieee80211_ht_cap *pht_cap = NULL;
+	unsigned int		len;
+	unsigned char		*p;
+
+	memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
+	cap = le16_to_cpu(le_tmp);
+	if (cap & WLAN_CAPABILITY_PRIVACY) {
+		bencrypt = 1;
+		pnetwork->network.Privacy = 1;
+	} else {
+		pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
+	}
+	rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len);
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid));
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+
+	if (rsn_len > 0) {
+		pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
+	} else if (wpa_len > 0) {
+		pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
+	} else {
+		if (bencrypt)
+			pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
+	}
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
+		 pnetwork->BcnInfo.encryp_protocol));
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: pnetwork->encryp_protocol is %x\n",
+		 pnetwork->BcnInfo.encryp_protocol));
+	rtw_get_cipher_info(pnetwork);
+
+	/* get bwmode and ch_offset */
+	/* parsing HT_CAP_IE */
+	p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
+	if (p && len > 0) {
+			pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
+			pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info;
+	} else {
+			pnetwork->BcnInfo.ht_cap_info = 0;
+	}
+	/* parsing HT_INFO_IE */
+	p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_);
+	if (p && len > 0) {
+			pht_info = (struct HT_info_element *)(p + 2);
+			pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
+	} else {
+			pnetwork->BcnInfo.ht_info_infos_0 = 0;
+	}
+}
+
+/* show MCS rate, unit: 100Kbps */
+u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate)
+{
+	u16 max_rate = 0;
+
+	if (rf_type == RF_1T1R) {
+		if (MCS_rate[0] & BIT(7))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
+		else if (MCS_rate[0] & BIT(6))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
+		else if (MCS_rate[0] & BIT(5))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
+		else if (MCS_rate[0] & BIT(4))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
+		else if (MCS_rate[0] & BIT(3))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
+		else if (MCS_rate[0] & BIT(2))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
+		else if (MCS_rate[0] & BIT(1))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
+		else if (MCS_rate[0] & BIT(0))
+			max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
+	} else {
+		if (MCS_rate[1]) {
+			if (MCS_rate[1] & BIT(7))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300);
+			else if (MCS_rate[1] & BIT(6))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170);
+			else if (MCS_rate[1] & BIT(5))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040);
+			else if (MCS_rate[1] & BIT(4))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780);
+			else if (MCS_rate[1] & BIT(3))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
+			else if (MCS_rate[1] & BIT(2))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
+			else if (MCS_rate[1] & BIT(1))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
+			else if (MCS_rate[1] & BIT(0))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
+		} else {
+			if (MCS_rate[0] & BIT(7))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650);
+			else if (MCS_rate[0] & BIT(6))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585);
+			else if (MCS_rate[0] & BIT(5))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520);
+			else if (MCS_rate[0] & BIT(4))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390);
+			else if (MCS_rate[0] & BIT(3))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260);
+			else if (MCS_rate[0] & BIT(2))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195);
+			else if (MCS_rate[0] & BIT(1))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130);
+			else if (MCS_rate[0] & BIT(0))
+				max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65);
+		}
+	}
+	return max_rate;
+}
+
+int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action)
+{
+	const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u16 fc;
+	u8 c, a = 0;
+
+	fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl);
+
+	if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) !=
+	    (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION))
+		return false;
+
+	c = frame_body[0];
+
+	switch (c) {
+	case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */
+		break;
+	default:
+		a = frame_body[1];
+	}
+
+	if (category)
+		*category = c;
+	if (action)
+		*action = a;
+
+	return true;
+}
+
+static const char *_action_public_str[] = {
+	"ACT_PUB_BSSCOEXIST",
+	"ACT_PUB_DSE_ENABLE",
+	"ACT_PUB_DSE_DEENABLE",
+	"ACT_PUB_DSE_REG_LOCATION",
+	"ACT_PUB_EXT_CHL_SWITCH",
+	"ACT_PUB_DSE_MSR_REQ",
+	"ACT_PUB_DSE_MSR_RPRT",
+	"ACT_PUB_MP",
+	"ACT_PUB_DSE_PWR_CONSTRAINT",
+	"ACT_PUB_VENDOR",
+	"ACT_PUB_GAS_INITIAL_REQ",
+	"ACT_PUB_GAS_INITIAL_RSP",
+	"ACT_PUB_GAS_COMEBACK_REQ",
+	"ACT_PUB_GAS_COMEBACK_RSP",
+	"ACT_PUB_TDLS_DISCOVERY_RSP",
+	"ACT_PUB_LOCATION_TRACK",
+	"ACT_PUB_RSVD",
+};
+
+const char *action_public_str(u8 action)
+{
+	action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action;
+	return _action_public_str[action];
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_io.c b/drivers/staging/rtl8188eu/core/rtw_io.c
new file mode 100644
index 0000000..10c9c65
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_io.c
@@ -0,0 +1,329 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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 purpose of rtw_io.c
+
+a. provides the API
+
+b. provides the protocol engine
+
+c. provides the software interface between caller and the hardware interface
+
+
+Compiler Flag Option:
+
+USB:
+   a. USE_ASYNC_IRP: Both sync/async operations are provided.
+
+Only sync read/rtw_write_mem operations are provided.
+
+jackson@realtek.com.tw
+
+*/
+
+#define _RTW_IO_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_io.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+
+#define rtw_le16_to_cpu(val)		le16_to_cpu(val)
+#define rtw_le32_to_cpu(val)		le32_to_cpu(val)
+#define rtw_cpu_to_le16(val)		cpu_to_le16(val)
+#define rtw_cpu_to_le32(val)		cpu_to_le32(val)
+
+
+u8 _rtw_read8(struct adapter *adapter, u32 addr)
+{
+	u8 r_val;
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl *pintfhdl = &(pio_priv->intf);
+	u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
+
+	_func_enter_;
+	_read8 = pintfhdl->io_ops._read8;
+	r_val = _read8(pintfhdl, addr);
+	_func_exit_;
+	return r_val;
+}
+
+u16 _rtw_read16(struct adapter *adapter, u32 addr)
+{
+	u16 r_val;
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr);
+_func_enter_;
+	_read16 = pintfhdl->io_ops._read16;
+
+	r_val = _read16(pintfhdl, addr);
+_func_exit_;
+	return r_val;
+}
+
+u32 _rtw_read32(struct adapter *adapter, u32 addr)
+{
+	u32 r_val;
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	u32	(*_read32)(struct intf_hdl *pintfhdl, u32 addr);
+_func_enter_;
+	_read32 = pintfhdl->io_ops._read32;
+
+	r_val = _read32(pintfhdl, addr);
+_func_exit_;
+	return r_val;
+}
+
+int _rtw_write8(struct adapter *adapter, u32 addr, u8 val)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+	int ret;
+	_func_enter_;
+	_write8 = pintfhdl->io_ops._write8;
+
+	ret = _write8(pintfhdl, addr, val);
+	_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write16(struct adapter *adapter, u32 addr, u16 val)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+	int ret;
+	_func_enter_;
+	_write16 = pintfhdl->io_ops._write16;
+
+	ret = _write16(pintfhdl, addr, val);
+	_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+int _rtw_write32(struct adapter *adapter, u32 addr, u32 val)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+	int ret;
+	_func_enter_;
+	_write32 = pintfhdl->io_ops._write32;
+
+	ret = _write32(pintfhdl, addr, val);
+	_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_writeN(struct adapter *adapter, u32 addr , u32 length , u8 *pdata)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl *pintfhdl = (struct intf_hdl *)(&(pio_priv->intf));
+	int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata);
+	int ret;
+	_func_enter_;
+	_writeN = pintfhdl->io_ops._writeN;
+
+	ret = _writeN(pintfhdl, addr, length, pdata);
+	_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+	int ret;
+	_func_enter_;
+	_write8_async = pintfhdl->io_ops._write8_async;
+
+	ret = _write8_async(pintfhdl, addr, val);
+	_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+	int ret;
+
+_func_enter_;
+	_write16_async = pintfhdl->io_ops._write16_async;
+	ret = _write16_async(pintfhdl, addr, val);
+_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+
+int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val)
+{
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+	int ret;
+
+_func_enter_;
+	_write32_async = pintfhdl->io_ops._write32_async;
+	ret = _write32_async(pintfhdl, addr, val);
+_func_exit_;
+
+	return RTW_STATUS_CODE(ret);
+}
+
+void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+	void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+
+	_func_enter_;
+	if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
+	     RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
+		      ("rtw_read_mem:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+		      adapter->bDriverStopped, adapter->bSurpriseRemoved));
+	     return;
+	}
+	_read_mem = pintfhdl->io_ops._read_mem;
+	_read_mem(pintfhdl, addr, cnt, pmem);
+	_func_exit_;
+}
+
+void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+	void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+
+	_func_enter_;
+
+	_write_mem = pintfhdl->io_ops._write_mem;
+
+	_write_mem(pintfhdl, addr, cnt, pmem);
+
+	_func_exit_;
+}
+
+void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+	u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+
+	_func_enter_;
+
+	if (adapter->bDriverStopped || adapter->bSurpriseRemoved) {
+	     RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
+		      ("rtw_read_port:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+		      adapter->bDriverStopped, adapter->bSurpriseRemoved));
+	     return;
+	}
+
+	_read_port = pintfhdl->io_ops._read_port;
+
+	_read_port(pintfhdl, addr, cnt, pmem);
+
+	_func_exit_;
+}
+
+void _rtw_read_port_cancel(struct adapter *adapter)
+{
+	void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+	_read_port_cancel = pintfhdl->io_ops._read_port_cancel;
+
+	if (_read_port_cancel)
+		_read_port_cancel(pintfhdl);
+}
+
+u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+	u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct	intf_hdl		*pintfhdl = &(pio_priv->intf);
+	u32 ret = _SUCCESS;
+
+	_func_enter_;
+
+	_write_port = pintfhdl->io_ops._write_port;
+
+	ret = _write_port(pintfhdl, addr, cnt, pmem);
+
+	 _func_exit_;
+
+	return ret;
+}
+
+u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms)
+{
+	int ret = _SUCCESS;
+	struct xmit_buf *pxmitbuf = (struct xmit_buf *)pmem;
+	struct submit_ctx sctx;
+
+	rtw_sctx_init(&sctx, timeout_ms);
+	pxmitbuf->sctx = &sctx;
+
+	ret = _rtw_write_port(adapter, addr, cnt, pmem);
+
+	if (ret == _SUCCESS)
+		ret = rtw_sctx_wait(&sctx);
+
+	 return ret;
+}
+
+void _rtw_write_port_cancel(struct adapter *adapter)
+{
+	void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
+	struct io_priv *pio_priv = &adapter->iopriv;
+	struct intf_hdl *pintfhdl = &(pio_priv->intf);
+
+	_write_port_cancel = pintfhdl->io_ops._write_port_cancel;
+
+	if (_write_port_cancel)
+		_write_port_cancel(pintfhdl);
+}
+
+int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops))
+{
+	struct io_priv	*piopriv = &padapter->iopriv;
+	struct intf_hdl *pintf = &piopriv->intf;
+
+	if (set_intf_ops == NULL)
+		return _FAIL;
+
+	piopriv->padapter = padapter;
+	pintf->padapter = padapter;
+	pintf->pintf_dev = adapter_to_dvobj(padapter);
+
+	set_intf_ops(&pintf->io_ops);
+
+	return _SUCCESS;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
new file mode 100644
index 0000000..193f641
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c
@@ -0,0 +1,1169 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_IOCTL_SET_C_
+
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_ioctl_set.h>
+#include <hal_intf.h>
+
+#include <usb_osintf.h>
+#include <usb_ops.h>
+
+extern void indicate_wx_scan_complete_event(struct adapter *padapter);
+
+#define IS_MAC_ADDRESS_BROADCAST(addr) \
+(\
+	((addr[0] == 0xff) && (addr[1] == 0xff) && \
+		(addr[2] == 0xff) && (addr[3] == 0xff) && \
+		(addr[4] == 0xff) && (addr[5] == 0xff))  ? true : false \
+)
+
+u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid)
+{
+	u8	 i;
+	u8	ret = true;
+
+_func_enter_;
+
+	if (ssid->SsidLength > 32) {
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid length >32\n"));
+		ret = false;
+		goto exit;
+	}
+
+	for (i = 0; i < ssid->SsidLength; i++) {
+		/* wifi, printable ascii code must be supported */
+		if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("ssid has nonprintabl ascii\n"));
+			ret = false;
+			break;
+		}
+	}
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+u8 rtw_do_join(struct adapter *padapter)
+{
+	unsigned long	irqL;
+	struct list_head *plist, *phead;
+	u8 *pibss = NULL;
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	u8 ret = _SUCCESS;
+
+_func_enter_;
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("\n rtw_do_join: phead = %p; plist = %p\n\n\n", phead, plist));
+
+	pmlmepriv->cur_network.join_res = -2;
+
+	set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+	pmlmepriv->pscanned = plist;
+
+	pmlmepriv->to_join = true;
+
+	if (_rtw_queue_empty(queue)) {
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+		/* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */
+		/* we try to issue sitesurvey firstly */
+
+		if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
+		    pmlmepriv->to_roaming > 0) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("rtw_do_join(): site survey if scanned_queue is empty\n."));
+			/*  submit site_survey_cmd */
+			ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+			if (_SUCCESS != ret) {
+				pmlmepriv->to_join = false;
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_do_join(): site survey return error\n."));
+			}
+		} else {
+			pmlmepriv->to_join = false;
+			ret = _FAIL;
+		}
+
+		goto exit;
+	} else {
+		int select_ret;
+
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+		select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
+		if (select_ret == _SUCCESS) {
+			pmlmepriv->to_join = false;
+			_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+		} else {
+			if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+				/*  submit createbss_cmd to change to a ADHOC_MASTER */
+
+				/* pmlmepriv->lock has been acquired by caller... */
+				struct wlan_bssid_ex    *pdev_network = &(padapter->registrypriv.dev_network);
+
+				pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
+
+				pibss = padapter->registrypriv.dev_network.MacAddress;
+
+				_rtw_memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+				memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
+
+				rtw_update_registrypriv_dev_network(padapter);
+
+				rtw_generate_random_ibss(pibss);
+
+				if (rtw_createbss_cmd(padapter) != _SUCCESS) {
+					RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>do_goin: rtw_createbss_cmd status FAIL***\n "));
+					ret =  false;
+					goto exit;
+				}
+				pmlmepriv->to_join = false;
+
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+					 ("***Error => rtw_select_and_join_from_scanned_queue FAIL under STA_Mode***\n "));
+			} else {
+				/*  can't associate ; reset under-linking */
+				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+				/* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
+				/* we try to issue sitesurvey firstly */
+				if (!pmlmepriv->LinkDetectInfo.bBusyTraffic ||
+				    pmlmepriv->to_roaming > 0) {
+					ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+					if (_SUCCESS != ret) {
+						pmlmepriv->to_join = false;
+						RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n."));
+					}
+				} else {
+					ret = _FAIL;
+					pmlmepriv->to_join = false;
+				}
+			}
+		}
+	}
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid)
+{
+	unsigned long irqL;
+	u8 status = _SUCCESS;
+	u32 cur_time = 0;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid);
+
+	if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 &&
+	     bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) ||
+	    (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF &&
+	     bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) {
+		status = _FAIL;
+		goto exit;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+
+	DBG_88E("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true)
+		goto handle_tkip_countermeasure;
+	else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+		goto release_mlme_lock;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
+
+		if (_rtw_memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) {
+			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)
+				goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
+		} else {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n"));
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid =%pM\n", (bssid)));
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid =%pM\n", (pmlmepriv->cur_network.network.MacAddress)));
+
+			rtw_disassoc_cmd(padapter, 0, true);
+
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+				rtw_indicate_disconnect(padapter);
+
+			rtw_free_assoc_resources(padapter, 1);
+
+			if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+			}
+		}
+	}
+
+handle_tkip_countermeasure:
+	/* should we add something here...? */
+
+	if (padapter->securitypriv.btkip_countermeasure) {
+		cur_time = rtw_get_current_time();
+
+		if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
+			padapter->securitypriv.btkip_countermeasure = false;
+			padapter->securitypriv.btkip_countermeasure_time = 0;
+		} else {
+			status = _FAIL;
+			goto release_mlme_lock;
+		}
+	}
+
+	memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN);
+	pmlmepriv->assoc_by_bssid = true;
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+		pmlmepriv->to_join = true;
+	else
+		status = rtw_do_join(padapter);
+
+release_mlme_lock:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+		 ("rtw_set_802_11_bssid: status=%d\n", status));
+
+_func_exit_;
+
+	return status;
+}
+
+u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid)
+{
+	unsigned long irqL;
+	u8 status = _SUCCESS;
+	u32 cur_time = 0;
+
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_network *pnetwork = &pmlmepriv->cur_network;
+
+_func_enter_;
+
+	DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n",
+		      ssid->Ssid, get_fwstate(pmlmepriv));
+
+	if (!padapter->hw_init_completed) {
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+			 ("set_ssid: hw_init_completed == false =>exit!!!\n"));
+		status = _FAIL;
+		goto exit;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+		goto handle_tkip_countermeasure;
+	} else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) {
+		goto release_mlme_lock;
+	}
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) {
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+			 ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
+
+		if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) &&
+		    (_rtw_memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) {
+			if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false)) {
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+					 ("Set SSID is the same ssid, fw_state = 0x%08x\n",
+					  get_fwstate(pmlmepriv)));
+
+				if (!rtw_is_same_ibss(padapter, pnetwork)) {
+					/* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
+					rtw_disassoc_cmd(padapter, 0, true);
+
+					if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+						rtw_indicate_disconnect(padapter);
+
+					rtw_free_assoc_resources(padapter, 1);
+
+					if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+						_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+						set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+					}
+				} else {
+					goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
+				}
+			} else {
+				rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1);
+			}
+		} else {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set SSID not the same ssid\n"));
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_ssid =[%s] len = 0x%x\n", ssid->Ssid, (unsigned int)ssid->SsidLength));
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("assoc_ssid =[%s] len = 0x%x\n", pmlmepriv->assoc_ssid.Ssid, (unsigned int)pmlmepriv->assoc_ssid.SsidLength));
+
+			rtw_disassoc_cmd(padapter, 0, true);
+
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+				rtw_indicate_disconnect(padapter);
+
+			rtw_free_assoc_resources(padapter, 1);
+
+			if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+				set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+			}
+		}
+	}
+
+handle_tkip_countermeasure:
+
+	if (padapter->securitypriv.btkip_countermeasure) {
+		cur_time = rtw_get_current_time();
+
+		if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) {
+			padapter->securitypriv.btkip_countermeasure = false;
+			padapter->securitypriv.btkip_countermeasure_time = 0;
+		} else {
+			status = _FAIL;
+			goto release_mlme_lock;
+		}
+	}
+
+	memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid));
+	pmlmepriv->assoc_by_bssid = false;
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+		pmlmepriv->to_join = true;
+	} else {
+		status = rtw_do_join(padapter);
+	}
+
+release_mlme_lock:
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+exit:
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+		 ("-rtw_set_802_11_ssid: status =%d\n", status));
+_func_exit_;
+	return status;
+}
+
+u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
+	enum ndis_802_11_network_infra networktype)
+{
+	unsigned long irqL;
+	struct	mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct	wlan_network	*cur_network = &pmlmepriv->cur_network;
+	enum ndis_802_11_network_infra *pold_state = &(cur_network->network.InfrastructureMode);
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
+		 ("+rtw_set_802_11_infrastructure_mode: old =%d new =%d fw_state = 0x%08x\n",
+		  *pold_state, networktype, get_fwstate(pmlmepriv)));
+
+	if (*pold_state != networktype) {
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!"));
+		/* DBG_88E("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
+
+		if (*pold_state == Ndis802_11APMode) {
+			/* change to other mode from Ndis802_11APMode */
+			cur_network->join_res = -1;
+
+#ifdef CONFIG_88EU_AP_MODE
+			stop_ap_mode(padapter);
+#endif
+		}
+
+		if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
+		    (*pold_state == Ndis802_11IBSS))
+			rtw_disassoc_cmd(padapter, 0, true);
+
+		if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
+		    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+			rtw_free_assoc_resources(padapter, 1);
+
+		if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+				rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether  issue dis-assoc_cmd or not */
+	       }
+
+		*pold_state = networktype;
+
+		_clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
+
+		switch (networktype) {
+		case Ndis802_11IBSS:
+			set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+			break;
+		case Ndis802_11Infrastructure:
+			set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+			break;
+		case Ndis802_11APMode:
+			set_fwstate(pmlmepriv, WIFI_AP_STATE);
+#ifdef CONFIG_88EU_AP_MODE
+			start_ap_mode(padapter);
+#endif
+			break;
+		case Ndis802_11AutoUnknown:
+		case Ndis802_11InfrastructureMax:
+			break;
+		}
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+	}
+
+_func_exit_;
+
+	return true;
+}
+
+
+u8 rtw_set_802_11_disassociate(struct adapter *padapter)
+{
+	unsigned long irqL;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+			 ("MgntActrtw_set_802_11_disassociate: rtw_indicate_disconnect\n"));
+
+		rtw_disassoc_cmd(padapter, 0, true);
+		rtw_indicate_disconnect(padapter);
+		rtw_free_assoc_resources(padapter, 1);
+		rtw_pwr_wakeup(padapter);
+	}
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+_func_exit_;
+
+	return true;
+}
+
+u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num)
+{
+	unsigned long	irqL;
+	struct	mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	u8	res = true;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv)));
+
+	if (padapter == NULL) {
+		res = false;
+		goto exit;
+	}
+	if (!padapter->hw_init_completed) {
+		res = false;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === rtw_set_802_11_bssid_list_scan:hw_init_completed == false ===\n"));
+		goto exit;
+	}
+
+	if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) ||
+	    (pmlmepriv->LinkDetectInfo.bBusyTraffic)) {
+		/*  Scan or linking is in progress, do nothing. */
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv)));
+		res = true;
+
+		if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)) == true) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n\n"));
+		} else {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n###pmlmepriv->sitesurveyctrl.traffic_busy == true\n\n"));
+		}
+	} else {
+		if (rtw_is_scan_deny(padapter)) {
+			DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter));
+			indicate_wx_scan_complete_event(padapter);
+			return _SUCCESS;
+		}
+
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+		res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0);
+
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+	}
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_auth_mode authmode)
+{
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	int res;
+	u8 ret;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_802_11_auth.mode(): mode =%x\n", authmode));
+
+	psecuritypriv->ndisauthtype = authmode;
+
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+		 ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype=%d",
+		 psecuritypriv->ndisauthtype));
+
+	if (psecuritypriv->ndisauthtype > 3)
+		psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+	res = rtw_set_auth(padapter, psecuritypriv);
+
+	if (res == _SUCCESS)
+		ret = true;
+	else
+		ret = false;
+
+_func_exit_;
+
+	return ret;
+}
+
+u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep)
+{
+	int		keyid, res;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	u8		ret = _SUCCESS;
+
+_func_enter_;
+
+	keyid = wep->KeyIndex & 0x3fffffff;
+
+	if (keyid >= 4) {
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MgntActrtw_set_802_11_add_wep:keyid>4 =>fail\n"));
+		ret = false;
+		goto exit;
+	}
+
+	switch (wep->KeyLength) {
+	case 5:
+		psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 5\n"));
+		break;
+	case 13:
+		psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength = 13\n"));
+		break;
+	default:
+		psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("MgntActrtw_set_802_11_add_wep:wep->KeyLength!= 5 or 13\n"));
+		break;
+	}
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+		 ("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x  keyid =%x\n",
+		 wep->KeyLength, wep->KeyIndex, keyid));
+
+	memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength);
+
+	psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
+
+	psecuritypriv->dot11PrivacyKeyIndex = keyid;
+
+	RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+		 ("rtw_set_802_11_add_wep:security key material : %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
+		 psecuritypriv->dot11DefKey[keyid].skey[0],
+		 psecuritypriv->dot11DefKey[keyid].skey[1],
+		 psecuritypriv->dot11DefKey[keyid].skey[2],
+		 psecuritypriv->dot11DefKey[keyid].skey[3],
+		 psecuritypriv->dot11DefKey[keyid].skey[4],
+		 psecuritypriv->dot11DefKey[keyid].skey[5],
+		 psecuritypriv->dot11DefKey[keyid].skey[6],
+		 psecuritypriv->dot11DefKey[keyid].skey[7],
+		 psecuritypriv->dot11DefKey[keyid].skey[8],
+		 psecuritypriv->dot11DefKey[keyid].skey[9],
+		 psecuritypriv->dot11DefKey[keyid].skey[10],
+		 psecuritypriv->dot11DefKey[keyid].skey[11],
+		 psecuritypriv->dot11DefKey[keyid].skey[12]));
+
+	res = rtw_set_key(padapter, psecuritypriv, keyid, 1);
+
+	if (res == _FAIL)
+		ret = false;
+exit:
+_func_exit_;
+	return ret;
+}
+
+u8 rtw_set_802_11_remove_wep(struct adapter *padapter, u32 keyindex)
+{
+	u8 ret = _SUCCESS;
+
+_func_enter_;
+	if (keyindex >= 0x80000000 || padapter == NULL) {
+		ret = false;
+		goto exit;
+	} else {
+		int res;
+		struct security_priv *psecuritypriv = &(padapter->securitypriv);
+		if (keyindex < 4) {
+			_rtw_memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16);
+			res = rtw_set_key(padapter, psecuritypriv, keyindex, 0);
+			psecuritypriv->dot11DefKeylen[keyindex] = 0;
+			if (res == _FAIL)
+				ret = _FAIL;
+		} else {
+			ret = _FAIL;
+		}
+	}
+exit:
+
+_func_exit_;
+	return ret;
+}
+
+u8 rtw_set_802_11_add_key(struct adapter *padapter, struct ndis_802_11_key *key)
+{
+	uint	encryptionalgo;
+	u8 *pbssid;
+	struct sta_info *stainfo;
+	u8	bgroup = false;
+	u8	bgrouptkey = false;/* can be removed later */
+	u8	ret = _SUCCESS;
+
+_func_enter_;
+
+	if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) {
+		/*  It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */
+		/*  it must fail the request and return NDIS_STATUS_INVALID_DATA. */
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+			 ("rtw_set_802_11_add_key: ((key->KeyIndex & 0x80000000)==0)[=%d]",
+			 (int)(key->KeyIndex & 0x80000000) == 0));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+			 ("rtw_set_802_11_add_key:((key->KeyIndex & 0x40000000)>0)[=%d]",
+			 (int)(key->KeyIndex & 0x40000000) > 0));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+			 ("rtw_set_802_11_add_key: key->KeyIndex=%d\n",
+			 (int)key->KeyIndex));
+		ret = _FAIL;
+		goto exit;
+	}
+
+	if (key->KeyIndex & 0x40000000) {
+		/*  Pairwise key */
+
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ Pairwise key +++++\n"));
+
+		pbssid = get_bssid(&padapter->mlmepriv);
+		stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
+
+		if ((stainfo != NULL) && (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("OID_802_11_ADD_KEY:(stainfo!=NULL)&&(Adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)\n"));
+			encryptionalgo = stainfo->dot118021XPrivacy;
+		} else {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: stainfo == NULL)||(Adapter->securitypriv.dot11AuthAlgrthm!= dot11AuthAlgrthm_8021X)\n"));
+			encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
+		}
+
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+			 ("rtw_set_802_11_add_key: (encryptionalgo==%d)!\n",
+			 encryptionalgo));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+			 ("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11PrivacyAlgrthm==%d)!\n",
+			 padapter->securitypriv.dot11PrivacyAlgrthm));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+			 ("rtw_set_802_11_add_key: (Adapter->securitypriv.dot11AuthAlgrthm==%d)!\n",
+			 padapter->securitypriv.dot11AuthAlgrthm));
+
+		if ((stainfo != NULL))
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("rtw_set_802_11_add_key: (stainfo->dot118021XPrivacy==%d)!\n",
+				 stainfo->dot118021XPrivacy));
+
+		if (key->KeyIndex & 0x000000FF) {
+			/*  The key index is specified in the lower 8 bits by values of zero to 255. */
+			/*  The key index should be set to zero for a Pairwise key, and the driver should fail with */
+			/*  NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, (" key->KeyIndex & 0x000000FF.\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*  check BSSID */
+		if (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == true) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("MacAddr_isBcst(key->BSSID)\n"));
+			ret = false;
+			goto exit;
+		}
+
+		/*  Check key length for TKIP. */
+		if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("TKIP KeyLength:0x%x != 32\n", key->KeyLength));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*  Check key length for AES. */
+		if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) {
+			/*  For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */
+			if (key->KeyLength == 32) {
+				key->KeyLength = 16;
+			} else {
+				ret = _FAIL;
+				goto exit;
+			}
+		}
+
+		/*  Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. */
+		if ((encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_) &&
+		    (key->KeyLength != 5 && key->KeyLength != 13)) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("WEP KeyLength:0x%x != 5 or 13\n", key->KeyLength));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		bgroup = false;
+
+		/*  Check the pairwise key. Added by Annie, 2005-07-06. */
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("[Pairwise Key set]\n"));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key index: 0x%8x(0x%8x)\n", key->KeyIndex, (key->KeyIndex&0x3)));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key Length: %d\n", key->KeyLength));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+
+	} else {
+		/*  Group key - KeyIndex(BIT30 == 0) */
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ Group key +++++\n"));
+
+
+		/*  when add wep key through add key and didn't assigned encryption type before */
+		if ((padapter->securitypriv.ndisauthtype <= 3) &&
+		    (padapter->securitypriv.dot118021XGrpPrivacy == 0)) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("keylen =%d(Adapter->securitypriv.dot11PrivacyAlgrthm=%x )padapter->securitypriv.dot118021XGrpPrivacy(%x)\n",
+				 key->KeyLength, padapter->securitypriv.dot11PrivacyAlgrthm,
+				 padapter->securitypriv.dot118021XGrpPrivacy));
+			switch (key->KeyLength) {
+			case 5:
+				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+					 ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n",
+					 padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength));
+				break;
+			case 13:
+				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+					 ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n",
+					 padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength));
+				break;
+			default:
+				padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+					 ("Adapter->securitypriv.dot11PrivacyAlgrthm=%x key->KeyLength=%u\n",
+					 padapter->securitypriv.dot11PrivacyAlgrthm, key->KeyLength));
+				break;
+			}
+
+			encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 (" Adapter->securitypriv.dot11PrivacyAlgrthm=%x\n",
+				 padapter->securitypriv.dot11PrivacyAlgrthm));
+
+		} else {
+			encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy;
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("(Adapter->securitypriv.dot11PrivacyAlgrthm=%x)encryptionalgo(%x)=padapter->securitypriv.dot118021XGrpPrivacy(%x)keylen=%d\n",
+				 padapter->securitypriv.dot11PrivacyAlgrthm, encryptionalgo,
+				 padapter->securitypriv.dot118021XGrpPrivacy, key->KeyLength));
+		}
+
+		if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == true) && (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == false)) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 (" IBSS but BSSID is not Broadcast Address.\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*  Check key length for TKIP */
+		if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) {
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 (" TKIP GTK KeyLength:%u != 32\n", key->KeyLength));
+			ret = _FAIL;
+			goto exit;
+		} else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) {
+			/*  Check key length for AES */
+			/*  For NDTEST, we allow keylen = 32 in this case. 2005.01.27, by rcnjko. */
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("<=== SetInfo, OID_802_11_ADD_KEY: AES GTK KeyLength:%u != 16 or 32\n",
+				 key->KeyLength));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*  Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */
+		if ((encryptionalgo ==  _AES_) && (key->KeyLength == 32)) {
+			key->KeyLength = 16;
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("AES key length changed: %u\n", key->KeyLength));
+		}
+
+		if (key->KeyIndex & 0x8000000) {/* error ??? 0x8000_0000 */
+			bgrouptkey = true;
+		}
+
+		if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)) &&
+		    (check_fwstate(&padapter->mlmepriv, _FW_LINKED)))
+			bgrouptkey = true;
+		bgroup = true;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("[Group Key set]\n"));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n")) ;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key index: 0x%8x(0x%8x)\n", key->KeyIndex, (key->KeyIndex&0x3)));
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("key Length: %d\n", key->KeyLength)) ;
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("------------------------------------------\n"));
+	}
+
+	/*  If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */
+	if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) &&
+	    (encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_)) {
+		u32 keyindex;
+		u32 len = FIELD_OFFSET(struct ndis_802_11_key, KeyMaterial) + key->KeyLength;
+		struct ndis_802_11_wep *wep = &padapter->securitypriv.ndiswep;
+
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ WEP key +++++\n"));
+
+		wep->Length = len;
+		keyindex = key->KeyIndex&0x7fffffff;
+		wep->KeyIndex = keyindex ;
+		wep->KeyLength = key->KeyLength;
+
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY:Before memcpy\n"));
+
+		memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength);
+		memcpy(&(padapter->securitypriv.dot11DefKey[keyindex].skey[0]), key->KeyMaterial, key->KeyLength);
+
+		padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength;
+		padapter->securitypriv.dot11PrivacyKeyIndex = keyindex;
+
+		ret = rtw_set_802_11_add_wep(padapter, wep);
+		goto exit;
+	}
+	if (key->KeyIndex & 0x20000000) {
+		/*  SetRSC */
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("OID_802_11_ADD_KEY: +++++ SetRSC+++++\n"));
+		if (bgroup) {
+			unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
+			memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8);
+		} else {
+			unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL;
+			memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8);
+		}
+	}
+
+	/*  Indicate this key idx is used for TX */
+	/*  Save the key in KeyMaterial */
+	if (bgroup) { /*  Group transmit key */
+		int res;
+
+		if (bgrouptkey)
+			padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex;
+		if ((key->KeyIndex&0x3) == 0) {
+			ret = _FAIL;
+			goto exit;
+		}
+		_rtw_memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
+		_rtw_memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
+		_rtw_memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16);
+
+		if ((key->KeyIndex & 0x10000000)) {
+			memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
+			memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
+
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7]));
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n"));
+		} else {
+			memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8);
+			memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8);
+
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("\n rtw_set_802_11_add_key:rx mic :0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[0],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[1],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[2],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[3],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[4],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[5],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)].skey[6],
+				 padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex-1) & 0x03)].skey[7]));
+			RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+				 ("\n rtw_set_802_11_add_key:set Group mic key!!!!!!!!\n"));
+		}
+
+		/* set group key by index */
+		memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength);
+
+		key->KeyIndex = key->KeyIndex & 0x03;
+
+		padapter->securitypriv.binstallGrpkey = true;
+
+		padapter->securitypriv.bcheck_grpkey = false;
+
+		RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("reset group key"));
+
+		res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1);
+
+		if (res == _FAIL)
+			ret = _FAIL;
+
+		goto exit;
+
+	} else { /*  Pairwise Key */
+		u8 res;
+
+		pbssid = get_bssid(&padapter->mlmepriv);
+		stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
+
+		if (stainfo != NULL) {
+			_rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16);/*  clear keybuffer */
+
+			memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16);
+
+			if (encryptionalgo == _TKIP_) {
+				padapter->securitypriv.busetkipkey = false;
+
+				/* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
+
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n========== _set_timer\n"));
+
+				/*  if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */
+				if ((key->KeyIndex & 0x10000000)) {
+					memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8);
+					memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8);
+
+				} else {
+					memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8);
+					memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8);
+				}
+			}
+
+
+			/* Set key to CAM through H2C command */
+			if (bgrouptkey) { /* never go to here */
+				res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, false);
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(group)\n"));
+			} else {
+				res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, true);
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n rtw_set_802_11_add_key:rtw_setstakey_cmd(unicast)\n"));
+			}
+			if (!res)
+				ret = _FAIL;
+		}
+	}
+exit:
+
+_func_exit_;
+	return ret;
+}
+
+u8 rtw_set_802_11_remove_key(struct adapter *padapter, struct ndis_802_11_remove_key *key)
+{
+	u8 *pbssid;
+	struct sta_info *stainfo;
+	u8	bgroup = (key->KeyIndex & 0x4000000) > 0 ? false : true;
+	u8	keyIndex = (u8)key->KeyIndex & 0x03;
+	u8	ret = _SUCCESS;
+
+_func_enter_;
+
+	if ((key->KeyIndex & 0xbffffffc) > 0) {
+		ret = _FAIL;
+		goto exit;
+	}
+
+	if (bgroup) {
+		/*  clear group key by index */
+
+		_rtw_memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16);
+
+		/*  \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */
+	} else {
+		pbssid = get_bssid(&padapter->mlmepriv);
+		stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid);
+		if (stainfo) {
+			/*  clear key by BSSID */
+			_rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16);
+
+			/*  \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */
+		} else {
+			ret = _FAIL;
+			goto exit;
+		}
+	}
+exit:
+
+_func_exit_;
+	return ret;
+}
+
+/*
+* rtw_get_cur_max_rate -
+* @adapter: pointer to struct adapter structure
+*
+* Return 0 or 100Kbps
+*/
+u16 rtw_get_cur_max_rate(struct adapter *adapter)
+{
+	int	i = 0;
+	u8	*p;
+	u16	rate = 0, max_rate = 0;
+	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	struct mlme_priv	*pmlmepriv = &adapter->mlmepriv;
+	struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
+	struct rtw_ieee80211_ht_cap *pht_capie;
+	u8	rf_type = 0;
+	u8	bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
+	u16	mcs_rate = 0;
+	u32	ht_ielen = 0;
+
+	if (adapter->registrypriv.mp_mode == 1) {
+		if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
+			return 0;
+	}
+
+	if ((!check_fwstate(pmlmepriv, _FW_LINKED)) &&
+	    (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+		return 0;
+
+	if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) {
+		p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12);
+		if (p && ht_ielen > 0) {
+			pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
+
+			memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
+
+			/* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */
+			bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0;
+
+			short_GI_20 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
+			short_GI_40 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
+
+			rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+			max_rate = rtw_mcs_rate(
+				rf_type,
+				bw_40MHz & (pregistrypriv->cbw40_enable),
+				short_GI_20,
+				short_GI_40,
+				pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate
+			);
+		}
+	} else {
+		while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) {
+			rate = pcur_bss->SupportedRates[i]&0x7F;
+			if (rate > max_rate)
+				max_rate = rate;
+			i++;
+		}
+
+		max_rate = max_rate*10/2;
+	}
+
+	return max_rate;
+}
+
+/*
+* rtw_set_scan_mode -
+* @adapter: pointer to struct adapter structure
+* @scan_mode:
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode)
+{
+	if (scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE)
+		return _FAIL;
+
+	adapter->mlmepriv.scan_mode = scan_mode;
+
+	return _SUCCESS;
+}
+
+/*
+* rtw_set_channel_plan -
+* @adapter: pointer to struct adapter structure
+* @channel_plan:
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan)
+{
+	/* handle by cmd_thread to sync with scan operation */
+	return rtw_set_chplan_cmd(adapter, channel_plan, 1);
+}
+
+/*
+* rtw_set_country -
+* @adapter: pointer to struct adapter structure
+* @country_code: string of country code
+*
+* Return _SUCCESS or _FAIL
+*/
+int rtw_set_country(struct adapter *adapter, const char *country_code)
+{
+	int channel_plan = RT_CHANNEL_DOMAIN_WORLD_WIDE_5G;
+
+	DBG_88E("%s country_code:%s\n", __func__, country_code);
+
+	/* TODO: should have a table to match country code and RT_CHANNEL_DOMAIN */
+	/* TODO: should consider 2-character and 3-character country code */
+	if (0 == strcmp(country_code, "US"))
+		channel_plan = RT_CHANNEL_DOMAIN_FCC;
+	else if (0 == strcmp(country_code, "EU"))
+		channel_plan = RT_CHANNEL_DOMAIN_ETSI;
+	else if (0 == strcmp(country_code, "JP"))
+		channel_plan = RT_CHANNEL_DOMAIN_MKK;
+	else if (0 == strcmp(country_code, "CN"))
+		channel_plan = RT_CHANNEL_DOMAIN_CHINA;
+	else
+		DBG_88E("%s unknown country_code:%s\n", __func__, country_code);
+
+	return rtw_set_channel_plan(adapter, channel_plan);
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_iol.c b/drivers/staging/rtl8188eu/core/rtw_iol.c
new file mode 100644
index 0000000..e6fdd32
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_iol.c
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include<rtw_iol.h>
+
+struct xmit_frame	*rtw_IOL_accquire_xmit_frame(struct adapter  *adapter)
+{
+	struct xmit_frame	*xmit_frame;
+	struct xmit_buf	*xmitbuf;
+	struct pkt_attrib	*pattrib;
+	struct xmit_priv	*pxmitpriv = &(adapter->xmitpriv);
+
+	xmit_frame = rtw_alloc_xmitframe(pxmitpriv);
+	if (xmit_frame == NULL) {
+		DBG_88E("%s rtw_alloc_xmitframe return null\n", __func__);
+		goto exit;
+	}
+
+	xmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+	if (xmitbuf == NULL) {
+		DBG_88E("%s rtw_alloc_xmitbuf return null\n", __func__);
+		rtw_free_xmitframe(pxmitpriv, xmit_frame);
+		xmit_frame = NULL;
+		goto exit;
+	}
+
+	xmit_frame->frame_tag = MGNT_FRAMETAG;
+	xmit_frame->pxmitbuf = xmitbuf;
+	xmit_frame->buf_addr = xmitbuf->pbuf;
+	xmitbuf->priv_data = xmit_frame;
+
+	pattrib = &xmit_frame->attrib;
+	update_mgntframe_attrib(adapter, pattrib);
+	pattrib->qsel = 0x10;/* Beacon */
+	pattrib->subtype = WIFI_BEACON;
+	pattrib->pktlen = 0;
+	pattrib->last_txcmdsz = 0;
+exit:
+	return xmit_frame;
+}
+
+int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len)
+{
+	struct pkt_attrib	*pattrib = &xmit_frame->attrib;
+	u16 buf_offset;
+	u32 ori_len;
+
+	buf_offset = TXDESC_OFFSET;
+	ori_len = buf_offset+pattrib->pktlen;
+
+	/* check if the io_buf can accommodate new cmds */
+	if (ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) {
+		DBG_88E("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n",
+			__func__ , ori_len + cmd_len + 8, MAX_XMITBUF_SZ);
+		return _FAIL;
+	}
+
+	memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len);
+	pattrib->pktlen += cmd_len;
+	pattrib->last_txcmdsz += cmd_len;
+
+	return _SUCCESS;
+}
+
+bool rtw_IOL_applied(struct adapter  *adapter)
+{
+	if (1 == adapter->registrypriv.fw_iol)
+		return true;
+
+	if ((2 == adapter->registrypriv.fw_iol) && (!adapter_to_dvobj(adapter)->ishighspeed))
+		return true;
+	return false;
+}
+
+int rtw_IOL_exec_cmds_sync(struct adapter  *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt)
+{
+	return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms, bndy_cnt);
+}
+
+int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary)
+{
+	return _SUCCESS;
+}
+
+int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask)
+{
+	struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0};
+
+	cmd.address = cpu_to_le16(addr);
+	cmd.data = cpu_to_le32(value);
+
+	if (mask != 0xFF) {
+		cmd.length = 12;
+		cmd.mask = cpu_to_le32(mask);
+	}
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask)
+{
+	struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0};
+
+	cmd.address = cpu_to_le16(addr);
+	cmd.data = cpu_to_le32(value);
+
+	if (mask != 0xFFFF) {
+		cmd.length = 12;
+		cmd.mask =  cpu_to_le32(mask);
+	}
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask)
+{
+	struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0};
+
+	cmd.address = cpu_to_le16(addr);
+	cmd.data = cpu_to_le32(value);
+
+	if (mask != 0xFFFFFFFF) {
+		cmd.length = 12;
+		cmd.mask =  cpu_to_le32(mask);
+	}
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask)
+{
+	struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0};
+
+	cmd.address = cpu_to_le16((rf_path<<8) | ((addr) & 0xFF));
+	cmd.data = cpu_to_le32(value);
+
+	if (mask != 0x000FFFFF) {
+		cmd.length = 12;
+		cmd.mask =  cpu_to_le32(mask);
+	}
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length);
+}
+
+int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us)
+{
+	struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0};
+	cmd.address = cpu_to_le16(us);
+
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4);
+}
+
+int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms)
+{
+	struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0};
+
+	cmd.address = cpu_to_le16(ms);
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4);
+}
+
+int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame)
+{
+	struct ioreg_cfg cmd = {4, IOREG_CMD_END, cpu_to_le16(0xFFFF), cpu_to_le32(0xFF), 0x0};
+
+	return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4);
+}
+
+u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame)
+{
+	u8 is_cmd_bndy = false;
+	if (((pxmit_frame->attrib.pktlen+32)%256) + 8 >= 256) {
+		rtw_IOL_append_END_cmd(pxmit_frame);
+		pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen+32)/256)+1)*256);
+
+		pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen;
+		is_cmd_bndy = true;
+	}
+	return is_cmd_bndy;
+}
+
+void rtw_IOL_cmd_buf_dump(struct adapter  *Adapter, int buf_len, u8 *pbuf)
+{
+	int i;
+	int j = 1;
+
+	pr_info("###### %s ######\n", __func__);
+	for (i = 0; i < buf_len; i++) {
+		printk("%02x-", *(pbuf+i));
+
+		if (j%32 == 0)
+			printk("\n");
+		j++;
+	}
+	printk("\n");
+	pr_info("=============ioreg_cmd len=%d===============\n", buf_len);
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_led.c b/drivers/staging/rtl8188eu/core/rtw_led.c
new file mode 100644
index 0000000..afac537
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_led.c
@@ -0,0 +1,1692 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include <drv_types.h>
+#include "rtw_led.h"
+
+/*  */
+/*	Description: */
+/*		Callback function of LED BlinkTimer, */
+/*		it just schedules to corresponding BlinkWorkItem/led_blink_hdl */
+/*  */
+void BlinkTimerCallback(void *data)
+{
+	struct LED_871x *pLed = (struct LED_871x *)data;
+	struct adapter *padapter = pLed->padapter;
+
+	if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+		return;
+
+	_set_workitem(&(pLed->BlinkWorkItem));
+}
+
+/*  */
+/*	Description: */
+/*		Callback function of LED BlinkWorkItem. */
+/*		We dispatch acture LED blink action according to LedStrategy. */
+/*  */
+void BlinkWorkItemCallback(struct work_struct *work)
+{
+	struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem);
+	BlinkHandler(pLed);
+}
+
+/*  */
+/*	Description: */
+/*		Reset status of LED_871x object. */
+/*  */
+void ResetLedStatus(struct LED_871x *pLed)
+{
+	pLed->CurrLedState = RTW_LED_OFF; /*  Current LED state. */
+	pLed->bLedOn = false; /*  true if LED is ON, false if LED is OFF. */
+
+	pLed->bLedBlinkInProgress = false; /*  true if it is blinking, false o.w.. */
+	pLed->bLedWPSBlinkInProgress = false;
+
+	pLed->BlinkTimes = 0; /*  Number of times to toggle led state for blinking. */
+	pLed->BlinkingLedState = LED_UNKNOWN; /*  Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
+
+	pLed->bLedNoLinkBlinkInProgress = false;
+	pLed->bLedLinkBlinkInProgress = false;
+	pLed->bLedStartToLinkBlinkInProgress = false;
+	pLed->bLedScanBlinkInProgress = false;
+}
+
+/*Description: */
+/*		Initialize an LED_871x object. */
+void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, enum LED_PIN_871x LedPin)
+{
+	pLed->padapter = padapter;
+	pLed->LedPin = LedPin;
+
+	ResetLedStatus(pLed);
+
+	_init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed);
+
+	_init_workitem(&(pLed->BlinkWorkItem), BlinkWorkItemCallback, pLed);
+}
+
+
+/*  */
+/*	Description: */
+/*		DeInitialize an LED_871x object. */
+/*  */
+void DeInitLed871x(struct LED_871x *pLed)
+{
+	_cancel_workitem_sync(&(pLed->BlinkWorkItem));
+	_cancel_timer_ex(&(pLed->BlinkTimer));
+	ResetLedStatus(pLed);
+}
+
+/*  */
+/*	Description: */
+/*		Implementation of LED blinking behavior. */
+/*		It toggle off LED and schedule corresponding timer if necessary. */
+/*  */
+
+static void SwLedBlink(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 bStopBlinking = false;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	/*  Determine if we shall change LED state again. */
+	pLed->BlinkTimes--;
+	switch (pLed->CurrLedState) {
+	case LED_BLINK_NORMAL:
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		break;
+	case LED_BLINK_StartToBlink:
+		if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+			bStopBlinking = true;
+		if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+		    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+		    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+			bStopBlinking = true;
+		else if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		break;
+	case LED_BLINK_WPS:
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		break;
+	default:
+		bStopBlinking = true;
+		break;
+	}
+
+	if (bStopBlinking) {
+		/* if (padapter->pwrctrlpriv.cpwm >= PS_STATE_S2) */
+		if (0) {
+			SwLedOff(padapter, pLed);
+		} else if ((check_fwstate(pmlmepriv, _FW_LINKED)) && (!pLed->bLedOn)) {
+			SwLedOn(padapter, pLed);
+		} else if ((check_fwstate(pmlmepriv, _FW_LINKED)) &&  pLed->bLedOn) {
+			SwLedOff(padapter, pLed);
+		}
+		pLed->BlinkTimes = 0;
+		pLed->bLedBlinkInProgress = false;
+	} else {
+		/*  Assign LED state to toggle. */
+		if (pLed->BlinkingLedState == RTW_LED_ON)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+
+		/*  Schedule a timer to toggle LED state. */
+		switch (pLed->CurrLedState) {
+		case LED_BLINK_NORMAL:
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+			break;
+		case LED_BLINK_SLOWLY:
+		case LED_BLINK_StartToBlink:
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+			break;
+		case LED_BLINK_WPS:
+			if (pLed->BlinkingLedState == RTW_LED_ON)
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL);
+			else
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL);
+			break;
+		default:
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+			break;
+		}
+	}
+}
+
+static void SwLedBlink1(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 bStopBlinking = false;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+		SwLedOff(padapter, pLed);
+		ResetLedStatus(pLed);
+		return;
+	}
+
+	switch (pLed->CurrLedState) {
+	case LED_BLINK_SLOWLY:
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+		break;
+	case LED_BLINK_NORMAL:
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+		break;
+	case LED_BLINK_SCAN:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->bLedLinkBlinkInProgress = true;
+				pLed->CurrLedState = LED_BLINK_NORMAL;
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->bLedNoLinkBlinkInProgress = true;
+				pLed->CurrLedState = LED_BLINK_SLOWLY;
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->bLedScanBlinkInProgress = false;
+		} else {
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_BLINK_TXRX:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->bLedLinkBlinkInProgress = true;
+				pLed->CurrLedState = LED_BLINK_NORMAL;
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->bLedNoLinkBlinkInProgress = true;
+				pLed->CurrLedState = LED_BLINK_SLOWLY;
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->BlinkTimes = 0;
+			pLed->bLedBlinkInProgress = false;
+		} else {
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_BLINK_WPS:
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		break;
+	case LED_BLINK_WPS_STOP:	/* WPS success */
+		if (pLed->BlinkingLedState == RTW_LED_ON)
+			bStopBlinking = false;
+		else
+			bStopBlinking = true;
+
+		if (bStopBlinking) {
+			pLed->bLedLinkBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_NORMAL;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+			RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+
+			pLed->bLedWPSBlinkInProgress = false;
+		} else {
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void SwLedBlink2(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 bStopBlinking = false;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	switch (pLed->CurrLedState) {
+	case LED_BLINK_SCAN:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_ON;
+				pLed->BlinkingLedState = RTW_LED_ON;
+				SwLedOn(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState));
+
+			} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_OFF;
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				SwLedOff(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop scan blink CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->bLedScanBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else {
+				 if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	case LED_BLINK_TXRX:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_ON;
+				pLed->BlinkingLedState = RTW_LED_ON;
+				SwLedOn(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState));
+			} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_OFF;
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				SwLedOff(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("stop CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->bLedBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else {
+				 if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void SwLedBlink3(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	u8 bStopBlinking = false;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		if (pLed->CurrLedState != LED_BLINK_WPS_STOP)
+			SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	switch (pLed->CurrLedState) {
+	case LED_BLINK_SCAN:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_ON;
+				pLed->BlinkingLedState = RTW_LED_ON;
+				if (!pLed->bLedOn)
+					SwLedOn(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_OFF;
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				if (pLed->bLedOn)
+					SwLedOff(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->bLedScanBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else {
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	case LED_BLINK_TXRX:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_ON;
+				pLed->BlinkingLedState = RTW_LED_ON;
+				if (!pLed->bLedOn)
+					SwLedOn(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			} else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+				pLed->CurrLedState = RTW_LED_OFF;
+				pLed->BlinkingLedState = RTW_LED_OFF;
+
+				if (pLed->bLedOn)
+					SwLedOff(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->bLedBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else {
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	case LED_BLINK_WPS:
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		break;
+	case LED_BLINK_WPS_STOP:	/* WPS success */
+		if (pLed->BlinkingLedState == RTW_LED_ON) {
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+			bStopBlinking = false;
+		} else {
+			bStopBlinking = true;
+		}
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+				SwLedOff(padapter, pLed);
+			} else {
+				pLed->CurrLedState = RTW_LED_ON;
+				pLed->BlinkingLedState = RTW_LED_ON;
+				SwLedOn(padapter, pLed);
+				RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+			}
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void SwLedBlink4(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+	u8 bStopBlinking = false;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) {
+		pLed1->BlinkingLedState = RTW_LED_OFF;
+		pLed1->CurrLedState = RTW_LED_OFF;
+		SwLedOff(padapter, pLed1);
+	}
+
+	switch (pLed->CurrLedState) {
+	case LED_BLINK_SLOWLY:
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+		break;
+	case LED_BLINK_StartToBlink:
+		if (pLed->bLedOn) {
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+		} else {
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+		}
+		break;
+	case LED_BLINK_SCAN:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = false;
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				SwLedOff(padapter, pLed);
+			} else {
+				pLed->bLedNoLinkBlinkInProgress = false;
+				pLed->CurrLedState = LED_BLINK_SLOWLY;
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+			}
+			pLed->bLedScanBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				SwLedOff(padapter, pLed);
+			} else {
+				 if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	case LED_BLINK_TXRX:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				SwLedOff(padapter, pLed);
+			} else {
+				pLed->bLedNoLinkBlinkInProgress = true;
+				pLed->CurrLedState = LED_BLINK_SLOWLY;
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+			}
+			pLed->bLedBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				SwLedOff(padapter, pLed);
+			} else {
+				 if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	case LED_BLINK_WPS:
+		if (pLed->bLedOn) {
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+		} else {
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+		}
+		break;
+	case LED_BLINK_WPS_STOP:	/* WPS authentication fail */
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+		break;
+	case LED_BLINK_WPS_STOP_OVERLAP:	/* WPS session overlap */
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0) {
+			if (pLed->bLedOn)
+				pLed->BlinkTimes = 1;
+			else
+				bStopBlinking = true;
+		}
+
+		if (bStopBlinking) {
+			pLed->BlinkTimes = 10;
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+		} else {
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+		}
+		break;
+	default:
+		break;
+	}
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState));
+}
+
+static void SwLedBlink5(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	u8 bStopBlinking = false;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	switch (pLed->CurrLedState) {
+	case LED_BLINK_SCAN:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				pLed->CurrLedState = RTW_LED_OFF;
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				if (pLed->bLedOn)
+					SwLedOff(padapter, pLed);
+			} else {
+					pLed->CurrLedState = RTW_LED_ON;
+					pLed->BlinkingLedState = RTW_LED_ON;
+					if (!pLed->bLedOn)
+						_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+			}
+
+			pLed->bLedScanBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				SwLedOff(padapter, pLed);
+			} else {
+				if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+			}
+		}
+		break;
+	case LED_BLINK_TXRX:
+		pLed->BlinkTimes--;
+		if (pLed->BlinkTimes == 0)
+			bStopBlinking = true;
+
+		if (bStopBlinking) {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				pLed->CurrLedState = RTW_LED_OFF;
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				if (pLed->bLedOn)
+					SwLedOff(padapter, pLed);
+			} else {
+				pLed->CurrLedState = RTW_LED_ON;
+				pLed->BlinkingLedState = RTW_LED_ON;
+				if (!pLed->bLedOn)
+					_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+			}
+
+			pLed->bLedBlinkInProgress = false;
+		} else {
+			if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+				SwLedOff(padapter, pLed);
+			} else {
+				 if (pLed->bLedOn)
+					pLed->BlinkingLedState = RTW_LED_OFF;
+				else
+					pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState));
+}
+
+static void SwLedBlink6(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+
+	/*  Change LED according to BlinkingLedState specified. */
+	if (pLed->BlinkingLedState == RTW_LED_ON) {
+		SwLedOn(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+	} else {
+		SwLedOff(padapter, pLed);
+		RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("<==== blink6\n"));
+}
+
+ /* ALPHA, added by chiyoko, 20090106 */
+static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct LED_871x *pLed = &(ledpriv->SwLed0);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	switch (LedAction) {
+	case LED_CTL_POWER_ON:
+	case LED_CTL_START_TO_LINK:
+	case LED_CTL_NO_LINK:
+		if (!pLed->bLedNoLinkBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+
+			pLed->bLedNoLinkBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SLOWLY;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_LINK:
+		if (!pLed->bLedLinkBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			pLed->bLedLinkBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_NORMAL;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_SITE_SURVEY:
+		if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+			;
+		} else if (!pLed->bLedScanBlinkInProgress) {
+			if (IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				 pLed->bLedLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			pLed->bLedScanBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SCAN;
+			pLed->BlinkTimes = 24;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		 }
+		break;
+	case LED_CTL_TX:
+	case LED_CTL_RX:
+		if (!pLed->bLedBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedLinkBlinkInProgress = false;
+			}
+			pLed->bLedBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_TXRX;
+			pLed->BlinkTimes = 2;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_START_WPS: /* wait until xinpin finish */
+	case LED_CTL_START_WPS_BOTTON:
+		 if (!pLed->bLedWPSBlinkInProgress) {
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				 pLed->bLedLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			if (pLed->bLedScanBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedScanBlinkInProgress = false;
+			}
+			pLed->bLedWPSBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_WPS;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		 }
+		break;
+	case LED_CTL_STOP_WPS:
+		if (pLed->bLedNoLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedNoLinkBlinkInProgress = false;
+		}
+		if (pLed->bLedLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			 pLed->bLedLinkBlinkInProgress = false;
+		}
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+		if (pLed->bLedWPSBlinkInProgress)
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+		else
+			pLed->bLedWPSBlinkInProgress = true;
+		pLed->CurrLedState = LED_BLINK_WPS_STOP;
+		if (pLed->bLedOn) {
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+		} else {
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), 0);
+		}
+		break;
+	case LED_CTL_STOP_WPS_FAIL:
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		pLed->bLedNoLinkBlinkInProgress = true;
+		pLed->CurrLedState = LED_BLINK_SLOWLY;
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+		break;
+	case LED_CTL_POWER_OFF:
+		pLed->CurrLedState = RTW_LED_OFF;
+		pLed->BlinkingLedState = RTW_LED_OFF;
+		if (pLed->bLedNoLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedNoLinkBlinkInProgress = false;
+		}
+		if (pLed->bLedLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedLinkBlinkInProgress = false;
+		}
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+		SwLedOff(padapter, pLed);
+		break;
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* Arcadyan/Sitecom , added by chiyoko, 20090216 */
+static void SwLedControlMode2(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct LED_871x *pLed = &(ledpriv->SwLed0);
+
+	switch (LedAction) {
+	case LED_CTL_SITE_SURVEY:
+		if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+		} else if (!pLed->bLedScanBlinkInProgress) {
+			if (IS_LED_WPS_BLINKING(pLed))
+				return;
+
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			pLed->bLedScanBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SCAN;
+			pLed->BlinkTimes = 24;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		 }
+		break;
+	case LED_CTL_TX:
+	case LED_CTL_RX:
+		if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			pLed->bLedBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_TXRX;
+			pLed->BlinkTimes = 2;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_LINK:
+		pLed->CurrLedState = RTW_LED_ON;
+		pLed->BlinkingLedState = RTW_LED_ON;
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+		_set_timer(&(pLed->BlinkTimer), 0);
+		break;
+	case LED_CTL_START_WPS: /* wait until xinpin finish */
+	case LED_CTL_START_WPS_BOTTON:
+		if (!pLed->bLedWPSBlinkInProgress) {
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			if (pLed->bLedScanBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedScanBlinkInProgress = false;
+			}
+			pLed->bLedWPSBlinkInProgress = true;
+			pLed->CurrLedState = RTW_LED_ON;
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), 0);
+		 }
+		break;
+	case LED_CTL_STOP_WPS:
+		pLed->bLedWPSBlinkInProgress = false;
+		if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+			SwLedOff(padapter, pLed);
+		} else {
+			pLed->CurrLedState = RTW_LED_ON;
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), 0);
+			RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+		}
+		break;
+	case LED_CTL_STOP_WPS_FAIL:
+		pLed->bLedWPSBlinkInProgress = false;
+		if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+			SwLedOff(padapter, pLed);
+		} else {
+			pLed->CurrLedState = RTW_LED_OFF;
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), 0);
+			RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+		}
+		break;
+	case LED_CTL_START_TO_LINK:
+	case LED_CTL_NO_LINK:
+		if (!IS_LED_BLINKING(pLed)) {
+			pLed->CurrLedState = RTW_LED_OFF;
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), 0);
+		}
+		break;
+	case LED_CTL_POWER_OFF:
+		pLed->CurrLedState = RTW_LED_OFF;
+		pLed->BlinkingLedState = RTW_LED_OFF;
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+
+		_set_timer(&(pLed->BlinkTimer), 0);
+		break;
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+}
+
+  /* COREGA, added by chiyoko, 20090316 */
+ static void SwLedControlMode3(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct LED_871x *pLed = &(ledpriv->SwLed0);
+
+	switch (LedAction) {
+	case LED_CTL_SITE_SURVEY:
+		if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+		} else if (!pLed->bLedScanBlinkInProgress) {
+			if (IS_LED_WPS_BLINKING(pLed))
+				return;
+
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			pLed->bLedScanBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SCAN;
+			pLed->BlinkTimes = 24;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_TX:
+	case LED_CTL_RX:
+		if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			pLed->bLedBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_TXRX;
+			pLed->BlinkTimes = 2;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_LINK:
+		if (IS_LED_WPS_BLINKING(pLed))
+			return;
+		pLed->CurrLedState = RTW_LED_ON;
+		pLed->BlinkingLedState = RTW_LED_ON;
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+
+		_set_timer(&(pLed->BlinkTimer), 0);
+		break;
+	case LED_CTL_START_WPS: /* wait until xinpin finish */
+	case LED_CTL_START_WPS_BOTTON:
+		if (!pLed->bLedWPSBlinkInProgress) {
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			if (pLed->bLedScanBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedScanBlinkInProgress = false;
+			}
+			pLed->bLedWPSBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_WPS;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_STOP_WPS:
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		} else {
+			pLed->bLedWPSBlinkInProgress = true;
+		}
+
+		pLed->CurrLedState = LED_BLINK_WPS_STOP;
+		if (pLed->bLedOn) {
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA);
+		} else {
+			pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), 0);
+		}
+		break;
+	case LED_CTL_STOP_WPS_FAIL:
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		pLed->CurrLedState = RTW_LED_OFF;
+		pLed->BlinkingLedState = RTW_LED_OFF;
+		_set_timer(&(pLed->BlinkTimer), 0);
+		break;
+	case LED_CTL_START_TO_LINK:
+	case LED_CTL_NO_LINK:
+		if (!IS_LED_BLINKING(pLed)) {
+			pLed->CurrLedState = RTW_LED_OFF;
+			pLed->BlinkingLedState = RTW_LED_OFF;
+			_set_timer(&(pLed->BlinkTimer), 0);
+		}
+		break;
+	case LED_CTL_POWER_OFF:
+		pLed->CurrLedState = RTW_LED_OFF;
+		pLed->BlinkingLedState = RTW_LED_OFF;
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+
+		_set_timer(&(pLed->BlinkTimer), 0);
+		break;
+	default:
+		break;
+	}
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+		 ("CurrLedState %d\n", pLed->CurrLedState));
+}
+
+ /* Edimax-Belkin, added by chiyoko, 20090413 */
+static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct LED_871x *pLed = &(ledpriv->SwLed0);
+	struct LED_871x *pLed1 = &(ledpriv->SwLed1);
+
+	switch (LedAction) {
+	case LED_CTL_START_TO_LINK:
+		if (pLed1->bLedWPSBlinkInProgress) {
+			pLed1->bLedWPSBlinkInProgress = false;
+			_cancel_timer_ex(&(pLed1->BlinkTimer));
+
+			pLed1->BlinkingLedState = RTW_LED_OFF;
+			pLed1->CurrLedState = RTW_LED_OFF;
+
+			if (pLed1->bLedOn)
+				_set_timer(&(pLed->BlinkTimer), 0);
+		}
+
+		if (!pLed->bLedStartToLinkBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+
+			pLed->bLedStartToLinkBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_StartToBlink;
+			if (pLed->bLedOn) {
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+			} else {
+				pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+			}
+		}
+		break;
+	case LED_CTL_LINK:
+	case LED_CTL_NO_LINK:
+		/* LED1 settings */
+		if (LedAction == LED_CTL_LINK) {
+			if (pLed1->bLedWPSBlinkInProgress) {
+				pLed1->bLedWPSBlinkInProgress = false;
+				_cancel_timer_ex(&(pLed1->BlinkTimer));
+
+				pLed1->BlinkingLedState = RTW_LED_OFF;
+				pLed1->CurrLedState = RTW_LED_OFF;
+
+				if (pLed1->bLedOn)
+					_set_timer(&(pLed->BlinkTimer), 0);
+			}
+		}
+
+		if (!pLed->bLedNoLinkBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+
+			pLed->bLedNoLinkBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SLOWLY;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_SITE_SURVEY:
+		if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+		} else if (!pLed->bLedScanBlinkInProgress) {
+			if (IS_LED_WPS_BLINKING(pLed))
+				return;
+
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			pLed->bLedScanBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SCAN;
+			pLed->BlinkTimes = 24;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_TX:
+	case LED_CTL_RX:
+		if (!pLed->bLedBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed))
+				return;
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			pLed->bLedBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_TXRX;
+			pLed->BlinkTimes = 2;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_START_WPS: /* wait until xinpin finish */
+	case LED_CTL_START_WPS_BOTTON:
+		if (pLed1->bLedWPSBlinkInProgress) {
+			pLed1->bLedWPSBlinkInProgress = false;
+			_cancel_timer_ex(&(pLed1->BlinkTimer));
+
+			pLed1->BlinkingLedState = RTW_LED_OFF;
+			pLed1->CurrLedState = RTW_LED_OFF;
+
+			if (pLed1->bLedOn)
+				_set_timer(&(pLed->BlinkTimer), 0);
+		}
+
+		if (!pLed->bLedWPSBlinkInProgress) {
+			if (pLed->bLedNoLinkBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedNoLinkBlinkInProgress = false;
+			}
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			if (pLed->bLedScanBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedScanBlinkInProgress = false;
+			}
+			pLed->bLedWPSBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_WPS;
+			if (pLed->bLedOn) {
+				pLed->BlinkingLedState = RTW_LED_OFF;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL);
+			} else {
+				pLed->BlinkingLedState = RTW_LED_ON;
+				_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+			}
+		}
+		break;
+	case LED_CTL_STOP_WPS:	/* WPS connect success */
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+
+		pLed->bLedNoLinkBlinkInProgress = true;
+		pLed->CurrLedState = LED_BLINK_SLOWLY;
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+
+		break;
+	case LED_CTL_STOP_WPS_FAIL:		/* WPS authentication fail */
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		pLed->bLedNoLinkBlinkInProgress = true;
+		pLed->CurrLedState = LED_BLINK_SLOWLY;
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+
+		/* LED1 settings */
+		if (pLed1->bLedWPSBlinkInProgress)
+			_cancel_timer_ex(&(pLed1->BlinkTimer));
+		else
+			pLed1->bLedWPSBlinkInProgress = true;
+		pLed1->CurrLedState = LED_BLINK_WPS_STOP;
+		if (pLed1->bLedOn)
+			pLed1->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed1->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+		break;
+	case LED_CTL_STOP_WPS_FAIL_OVERLAP:	/* WPS session overlap */
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		pLed->bLedNoLinkBlinkInProgress = true;
+		pLed->CurrLedState = LED_BLINK_SLOWLY;
+		if (pLed->bLedOn)
+			pLed->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA);
+
+		/* LED1 settings */
+		if (pLed1->bLedWPSBlinkInProgress)
+			_cancel_timer_ex(&(pLed1->BlinkTimer));
+		else
+			pLed1->bLedWPSBlinkInProgress = true;
+		pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP;
+		pLed1->BlinkTimes = 10;
+		if (pLed1->bLedOn)
+			pLed1->BlinkingLedState = RTW_LED_OFF;
+		else
+			pLed1->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL);
+		break;
+	case LED_CTL_POWER_OFF:
+		pLed->CurrLedState = RTW_LED_OFF;
+		pLed->BlinkingLedState = RTW_LED_OFF;
+
+		if (pLed->bLedNoLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedNoLinkBlinkInProgress = false;
+		}
+		if (pLed->bLedLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedLinkBlinkInProgress = false;
+		}
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		if (pLed->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedWPSBlinkInProgress = false;
+		}
+		if (pLed->bLedScanBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedScanBlinkInProgress = false;
+		}
+		if (pLed->bLedStartToLinkBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedStartToLinkBlinkInProgress = false;
+		}
+		if (pLed1->bLedWPSBlinkInProgress) {
+			_cancel_timer_ex(&(pLed1->BlinkTimer));
+			pLed1->bLedWPSBlinkInProgress = false;
+		}
+		pLed1->BlinkingLedState = LED_UNKNOWN;
+		SwLedOff(padapter, pLed);
+		SwLedOff(padapter, pLed1);
+		break;
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+
+
+ /* Sercomm-Belkin, added by chiyoko, 20090415 */
+static void
+SwLedControlMode5(
+	struct adapter *padapter,
+	enum LED_CTL_MODE LedAction
+)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct LED_871x *pLed = &(ledpriv->SwLed0);
+
+	switch (LedAction) {
+	case LED_CTL_POWER_ON:
+	case LED_CTL_NO_LINK:
+	case LED_CTL_LINK:	/* solid blue */
+		pLed->CurrLedState = RTW_LED_ON;
+		pLed->BlinkingLedState = RTW_LED_ON;
+
+		_set_timer(&(pLed->BlinkTimer), 0);
+		break;
+	case LED_CTL_SITE_SURVEY:
+		if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) {
+		} else if (!pLed->bLedScanBlinkInProgress) {
+			if (pLed->bLedBlinkInProgress) {
+				_cancel_timer_ex(&(pLed->BlinkTimer));
+				pLed->bLedBlinkInProgress = false;
+			}
+			pLed->bLedScanBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_SCAN;
+			pLed->BlinkTimes = 24;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_TX:
+	case LED_CTL_RX:
+		if (!pLed->bLedBlinkInProgress) {
+			if (pLed->CurrLedState == LED_BLINK_SCAN)
+				return;
+			pLed->bLedBlinkInProgress = true;
+			pLed->CurrLedState = LED_BLINK_TXRX;
+			pLed->BlinkTimes = 2;
+			if (pLed->bLedOn)
+				pLed->BlinkingLedState = RTW_LED_OFF;
+			else
+				pLed->BlinkingLedState = RTW_LED_ON;
+			_set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA);
+		}
+		break;
+	case LED_CTL_POWER_OFF:
+		pLed->CurrLedState = RTW_LED_OFF;
+		pLed->BlinkingLedState = RTW_LED_OFF;
+
+		if (pLed->bLedBlinkInProgress) {
+			_cancel_timer_ex(&(pLed->BlinkTimer));
+			pLed->bLedBlinkInProgress = false;
+		}
+		SwLedOff(padapter, pLed);
+		break;
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* WNC-Corega, added by chiyoko, 20090902 */
+static void
+SwLedControlMode6(
+	struct adapter *padapter,
+	enum LED_CTL_MODE LedAction
+)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+	struct LED_871x *pLed0 = &(ledpriv->SwLed0);
+
+	switch (LedAction) {
+	case LED_CTL_POWER_ON:
+	case LED_CTL_LINK:
+	case LED_CTL_NO_LINK:
+		_cancel_timer_ex(&(pLed0->BlinkTimer));
+		pLed0->CurrLedState = RTW_LED_ON;
+		pLed0->BlinkingLedState = RTW_LED_ON;
+		_set_timer(&(pLed0->BlinkTimer), 0);
+		break;
+	case LED_CTL_POWER_OFF:
+		SwLedOff(padapter, pLed0);
+		break;
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("ledcontrol 6 Led %d\n", pLed0->CurrLedState));
+}
+
+/*  */
+/*	Description: */
+/*		Handler function of LED Blinking. */
+/*		We dispatch acture LED blink action according to LedStrategy. */
+/*  */
+void BlinkHandler(struct LED_871x *pLed)
+{
+	struct adapter *padapter = pLed->padapter;
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+
+	if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+		return;
+
+	switch (ledpriv->LedStrategy) {
+	case SW_LED_MODE0:
+		SwLedBlink(pLed);
+		break;
+	case SW_LED_MODE1:
+		SwLedBlink1(pLed);
+		break;
+	case SW_LED_MODE2:
+		SwLedBlink2(pLed);
+		break;
+	case SW_LED_MODE3:
+		SwLedBlink3(pLed);
+		break;
+	case SW_LED_MODE4:
+		SwLedBlink4(pLed);
+		break;
+	case SW_LED_MODE5:
+		SwLedBlink5(pLed);
+		break;
+	case SW_LED_MODE6:
+		SwLedBlink6(pLed);
+		break;
+	default:
+		break;
+	}
+}
+
+void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction)
+{
+	struct led_priv *ledpriv = &(padapter->ledpriv);
+
+       if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) ||
+	   (!padapter->hw_init_completed))
+		return;
+
+	if (!ledpriv->bRegUseLed)
+		return;
+
+	if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
+	     padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
+	    (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
+	     LedAction == LED_CTL_SITE_SURVEY ||
+	     LedAction == LED_CTL_LINK ||
+	     LedAction == LED_CTL_NO_LINK ||
+	     LedAction == LED_CTL_POWER_ON))
+		return;
+
+	switch (ledpriv->LedStrategy) {
+	case SW_LED_MODE0:
+		break;
+	case SW_LED_MODE1:
+		SwLedControlMode1(padapter, LedAction);
+		break;
+	case SW_LED_MODE2:
+		SwLedControlMode2(padapter, LedAction);
+		break;
+	case SW_LED_MODE3:
+		SwLedControlMode3(padapter, LedAction);
+		break;
+	case SW_LED_MODE4:
+		SwLedControlMode4(padapter, LedAction);
+		break;
+	case SW_LED_MODE5:
+		SwLedControlMode5(padapter, LedAction);
+		break;
+	case SW_LED_MODE6:
+		SwLedControlMode6(padapter, LedAction);
+		break;
+	default:
+		break;
+	}
+
+	RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+		 ("LedStrategy:%d, LedAction %d\n",
+		 ledpriv->LedStrategy, LedAction));
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c
new file mode 100644
index 0000000..ea66071
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c
@@ -0,0 +1,2442 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MLME_C_
+
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <hal_intf.h>
+#include <mlme_osdep.h>
+#include <sta_info.h>
+#include <wifi.h>
+#include <wlan_bssdef.h>
+#include <rtw_ioctl_set.h>
+#include <usb_osintf.h>
+
+extern unsigned char	MCS_rate_2R[16];
+extern unsigned char	MCS_rate_1R[16];
+
+int	_rtw_init_mlme_priv (struct adapter *padapter)
+{
+	int	i;
+	u8	*pbuf;
+	struct wlan_network	*pnetwork;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	int	res = _SUCCESS;
+
+_func_enter_;
+
+	/*  We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+
+	pmlmepriv->nic_hdl = (u8 *)padapter;
+
+	pmlmepriv->pscanned = NULL;
+	pmlmepriv->fw_state = 0;
+	pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown;
+	pmlmepriv->scan_mode = SCAN_ACTIVE;/*  1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */
+
+	_rtw_spinlock_init(&(pmlmepriv->lock));
+	_rtw_init_queue(&(pmlmepriv->free_bss_pool));
+	_rtw_init_queue(&(pmlmepriv->scanned_queue));
+
+	set_scanned_network_val(pmlmepriv, 0);
+
+	_rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid));
+
+	pbuf = rtw_zvmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network)));
+
+	if (pbuf == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	pmlmepriv->free_bss_buf = pbuf;
+
+	pnetwork = (struct wlan_network *)pbuf;
+
+	for (i = 0; i < MAX_BSS_CNT; i++) {
+		_rtw_init_listhead(&(pnetwork->list));
+
+		rtw_list_insert_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue));
+
+		pnetwork++;
+	}
+
+	/* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+
+	rtw_clear_scan_deny(padapter);
+
+	rtw_init_mlme_timer(padapter);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void rtw_mfree_mlme_priv_lock (struct mlme_priv *pmlmepriv)
+{
+	_rtw_spinlock_free(&pmlmepriv->lock);
+	_rtw_spinlock_free(&(pmlmepriv->free_bss_pool.lock));
+	_rtw_spinlock_free(&(pmlmepriv->scanned_queue.lock));
+}
+
+#if defined (CONFIG_88EU_AP_MODE)
+static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
+{
+	kfree(*ppie);
+	*plen = 0;
+	*ppie = NULL;
+}
+
+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
+{
+	rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len);
+	rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len);
+
+	rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len);
+	rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len);
+}
+#else
+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
+{
+}
+#endif
+
+void _rtw_free_mlme_priv (struct mlme_priv *pmlmepriv)
+{
+_func_enter_;
+
+	rtw_free_mlme_priv_ie_data(pmlmepriv);
+
+	if (pmlmepriv) {
+		rtw_mfree_mlme_priv_lock (pmlmepriv);
+
+		if (pmlmepriv->free_bss_buf) {
+			rtw_vmfree(pmlmepriv->free_bss_buf, MAX_BSS_CNT * sizeof(struct wlan_network));
+		}
+	}
+_func_exit_;
+}
+
+int	_rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork)
+{
+	unsigned long irql;
+
+_func_enter_;
+
+	if (pnetwork == NULL)
+		goto exit;
+
+	_enter_critical_bh(&queue->lock, &irql);
+
+	rtw_list_insert_tail(&pnetwork->list, &queue->queue);
+
+	_exit_critical_bh(&queue->lock, &irql);
+
+exit:
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+struct	wlan_network *_rtw_dequeue_network(struct __queue *queue)
+{
+	unsigned long irql;
+
+	struct wlan_network *pnetwork;
+
+_func_enter_;
+
+	_enter_critical_bh(&queue->lock, &irql);
+
+	if (_rtw_queue_empty(queue)) {
+		pnetwork = NULL;
+	} else {
+		pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list);
+
+		rtw_list_delete(&(pnetwork->list));
+	}
+
+	_exit_critical_bh(&queue->lock, &irql);
+
+_func_exit_;
+
+	return pnetwork;
+}
+
+struct	wlan_network *_rtw_alloc_network(struct	mlme_priv *pmlmepriv)/* _queue *free_queue) */
+{
+	unsigned long	irql;
+	struct	wlan_network	*pnetwork;
+	struct __queue *free_queue = &pmlmepriv->free_bss_pool;
+	struct list_head *plist = NULL;
+
+_func_enter_;
+
+	_enter_critical_bh(&free_queue->lock, &irql);
+
+	if (_rtw_queue_empty(free_queue) == true) {
+		pnetwork = NULL;
+		goto exit;
+	}
+	plist = get_next(&(free_queue->queue));
+
+	pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
+
+	rtw_list_delete(&pnetwork->list);
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("_rtw_alloc_network: ptr=%p\n", plist));
+	pnetwork->network_type = 0;
+	pnetwork->fixed = false;
+	pnetwork->last_scanned = rtw_get_current_time();
+	pnetwork->aid = 0;
+	pnetwork->join_res = 0;
+
+	pmlmepriv->num_of_scanned++;
+
+exit:
+	_exit_critical_bh(&free_queue->lock, &irql);
+
+_func_exit_;
+
+	return pnetwork;
+}
+
+void _rtw_free_network(struct	mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall)
+{
+	u32 curr_time, delta_time;
+	u32 lifetime = SCANQUEUE_LIFETIME;
+	unsigned long irql;
+	struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
+
+_func_enter_;
+
+	if (pnetwork == NULL)
+		goto exit;
+
+	if (pnetwork->fixed)
+		goto exit;
+	curr_time = rtw_get_current_time();
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
+		lifetime = 1;
+	if (!isfreeall) {
+		delta_time = (curr_time - pnetwork->last_scanned)/HZ;
+		if (delta_time < lifetime)/*  unit:sec */
+			goto exit;
+	}
+	_enter_critical_bh(&free_queue->lock, &irql);
+	rtw_list_delete(&(pnetwork->list));
+	rtw_list_insert_tail(&(pnetwork->list), &(free_queue->queue));
+	pmlmepriv->num_of_scanned--;
+	_exit_critical_bh(&free_queue->lock, &irql);
+
+exit:
+_func_exit_;
+}
+
+void _rtw_free_network_nolock(struct	mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
+{
+	struct __queue *free_queue = &(pmlmepriv->free_bss_pool);
+
+_func_enter_;
+	if (pnetwork == NULL)
+		goto exit;
+	if (pnetwork->fixed)
+		goto exit;
+	rtw_list_delete(&(pnetwork->list));
+	rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue));
+	pmlmepriv->num_of_scanned--;
+exit:
+
+_func_exit_;
+}
+
+/*
+	return the wlan_network with the matching addr
+
+	Shall be calle under atomic context... to avoid possible racing condition...
+*/
+struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr)
+{
+	struct list_head *phead, *plist;
+	struct	wlan_network *pnetwork = NULL;
+	u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+_func_enter_;
+	if (_rtw_memcmp(zero_addr, addr, ETH_ALEN)) {
+		pnetwork = NULL;
+		goto exit;
+	}
+	phead = get_list_head(scanned_queue);
+	plist = get_next(phead);
+
+	while (plist != phead) {
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list);
+		if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == true)
+			break;
+		plist = get_next(plist);
+	}
+	if (plist == phead)
+		pnetwork = NULL;
+exit:
+_func_exit_;
+	return pnetwork;
+}
+
+
+void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall)
+{
+	unsigned long irql;
+	struct list_head *phead, *plist;
+	struct wlan_network *pnetwork;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct __queue *scanned_queue = &pmlmepriv->scanned_queue;
+
+_func_enter_;
+
+
+	_enter_critical_bh(&scanned_queue->lock, &irql);
+
+	phead = get_list_head(scanned_queue);
+	plist = get_next(phead);
+
+	while (rtw_end_of_queue_search(phead, plist) == false) {
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		plist = get_next(plist);
+
+		_rtw_free_network(pmlmepriv, pnetwork, isfreeall);
+	}
+	_exit_critical_bh(&scanned_queue->lock, &irql);
+_func_exit_;
+}
+
+int rtw_if_up(struct adapter *padapter)
+{
+	int res;
+_func_enter_;
+
+	if (padapter->bDriverStopped || padapter->bSurpriseRemoved ||
+	    (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == false)) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+			 ("rtw_if_up:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+			 padapter->bDriverStopped, padapter->bSurpriseRemoved));
+		res = false;
+	} else {
+		res =  true;
+	}
+
+_func_exit_;
+	return res;
+}
+
+void rtw_generate_random_ibss(u8 *pibss)
+{
+	u32	curtime = rtw_get_current_time();
+
+_func_enter_;
+	pibss[0] = 0x02;  /* in ad-hoc mode bit1 must set to 1 */
+	pibss[1] = 0x11;
+	pibss[2] = 0x87;
+	pibss[3] = (u8)(curtime & 0xff);/* p[0]; */
+	pibss[4] = (u8)((curtime>>8) & 0xff);/* p[1]; */
+	pibss[5] = (u8)((curtime>>16) & 0xff);/* p[2]; */
+_func_exit_;
+	return;
+}
+
+u8 *rtw_get_capability_from_ie(u8 *ie)
+{
+	return ie + 8 + 2;
+}
+
+
+u16 rtw_get_capability(struct wlan_bssid_ex *bss)
+{
+	__le16	val;
+_func_enter_;
+
+	memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2);
+
+_func_exit_;
+	return le16_to_cpu(val);
+}
+
+u8 *rtw_get_timestampe_from_ie(u8 *ie)
+{
+	return ie + 0;
+}
+
+u8 *rtw_get_beacon_interval_from_ie(u8 *ie)
+{
+	return ie + 8;
+}
+
+int	rtw_init_mlme_priv (struct adapter *padapter)/* struct	mlme_priv *pmlmepriv) */
+{
+	int	res;
+_func_enter_;
+	res = _rtw_init_mlme_priv(padapter);/*  (pmlmepriv); */
+_func_exit_;
+	return res;
+}
+
+void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv)
+{
+_func_enter_;
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv\n"));
+	_rtw_free_mlme_priv (pmlmepriv);
+_func_exit_;
+}
+
+static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
+{
+	struct	wlan_network	*pnetwork;
+_func_enter_;
+	pnetwork = _rtw_alloc_network(pmlmepriv);
+_func_exit_;
+	return pnetwork;
+}
+
+static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
+				    struct wlan_network *pnetwork)
+{
+_func_enter_;
+	_rtw_free_network_nolock(pmlmepriv, pnetwork);
+_func_exit_;
+}
+
+
+void rtw_free_network_queue(struct adapter *dev, u8 isfreeall)
+{
+_func_enter_;
+	_rtw_free_network_queue(dev, isfreeall);
+_func_exit_;
+}
+
+/*
+	return the wlan_network with the matching addr
+
+	Shall be calle under atomic context... to avoid possible racing condition...
+*/
+struct	wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr)
+{
+	struct	wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr);
+
+	return pnetwork;
+}
+
+int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork)
+{
+	int ret = true;
+	struct security_priv *psecuritypriv = &adapter->securitypriv;
+
+	if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) &&
+	    (pnetwork->network.Privacy == 0))
+		ret = false;
+	else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) &&
+		 (pnetwork->network.Privacy == 1))
+		ret = false;
+	else
+		ret = true;
+	return ret;
+}
+
+static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b)
+{
+	return (a->Ssid.SsidLength == b->Ssid.SsidLength) &&
+	       _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength);
+}
+
+int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
+{
+	 u16 s_cap, d_cap;
+	__le16 le_scap, le_dcap;
+
+_func_enter_;
+	memcpy((u8 *)&le_scap, rtw_get_capability_from_ie(src->IEs), 2);
+	memcpy((u8 *)&le_dcap, rtw_get_capability_from_ie(dst->IEs), 2);
+
+
+	s_cap = le16_to_cpu(le_scap);
+	d_cap = le16_to_cpu(le_dcap);
+
+_func_exit_;
+
+	return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) &&
+		((_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == true) &&
+		((_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == true) &&
+		((s_cap & WLAN_CAPABILITY_IBSS) ==
+		(d_cap & WLAN_CAPABILITY_IBSS)) &&
+		((s_cap & WLAN_CAPABILITY_BSS) ==
+		(d_cap & WLAN_CAPABILITY_BSS)));
+}
+
+struct	wlan_network	*rtw_get_oldest_wlan_network(struct __queue *scanned_queue)
+{
+	struct list_head *plist, *phead;
+	struct	wlan_network	*pwlan = NULL;
+	struct	wlan_network	*oldest = NULL;
+
+_func_enter_;
+	phead = get_list_head(scanned_queue);
+
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pwlan = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		if (!pwlan->fixed) {
+			if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned))
+				oldest = pwlan;
+		}
+
+		plist = get_next(plist);
+	}
+_func_exit_;
+	return oldest;
+}
+
+void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
+	struct adapter *padapter, bool update_ie)
+{
+	long rssi_ori = dst->Rssi;
+	u8 sq_smp = src->PhyInfo.SignalQuality;
+	u8 ss_final;
+	u8 sq_final;
+	long rssi_final;
+
+_func_enter_;
+	rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */
+
+	/* The rule below is 1/5 for sample value, 4/5 for history value */
+	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src)) {
+		/* Take the recvpriv's value for the connected AP*/
+		ss_final = padapter->recvpriv.signal_strength;
+		sq_final = padapter->recvpriv.signal_qual;
+		/* the rssi value here is undecorated, and will be used for antenna diversity */
+		if (sq_smp != 101) /* from the right channel */
+			rssi_final = (src->Rssi+dst->Rssi*4)/5;
+		else
+			rssi_final = rssi_ori;
+	} else {
+		if (sq_smp != 101) { /* from the right channel */
+			ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5;
+			sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5;
+			rssi_final = (src->Rssi+dst->Rssi*4)/5;
+		} else {
+			/* bss info not receving from the right channel, use the original RX signal infos */
+			ss_final = dst->PhyInfo.SignalStrength;
+			sq_final = dst->PhyInfo.SignalQuality;
+			rssi_final = dst->Rssi;
+		}
+	}
+	if (update_ie)
+		memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src));
+	dst->PhyInfo.SignalStrength = ss_final;
+	dst->PhyInfo.SignalQuality = sq_final;
+	dst->Rssi = rssi_final;
+
+_func_exit_;
+}
+
+static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork)
+{
+	struct	mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+
+_func_enter_;
+
+	if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) &&
+	    (is_same_network(&(pmlmepriv->cur_network.network), pnetwork))) {
+		update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, true);
+		rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(struct ndis_802_11_fixed_ie),
+				      pmlmepriv->cur_network.network.IELength);
+	}
+_func_exit_;
+}
+
+/*
+Caller must hold pmlmepriv->lock first.
+*/
+void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target)
+{
+	unsigned long irql;
+	struct list_head *plist, *phead;
+	u32	bssid_ex_sz;
+	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct wlan_network	*pnetwork = NULL;
+	struct wlan_network	*oldest = NULL;
+
+_func_enter_;
+
+	_enter_critical_bh(&queue->lock, &irql);
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork	= LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		if (is_same_network(&(pnetwork->network), target))
+			break;
+		if ((oldest == ((struct wlan_network *)0)) ||
+		    time_after(oldest->last_scanned, pnetwork->last_scanned))
+			oldest = pnetwork;
+		plist = get_next(plist);
+	}
+	/* If we didn't find a match, then get a new network slot to initialize
+	 * with this beacon's information */
+	if (rtw_end_of_queue_search(phead, plist) == true) {
+		if (_rtw_queue_empty(&(pmlmepriv->free_bss_pool)) == true) {
+			/* If there are no more slots, expire the oldest */
+			pnetwork = oldest;
+
+			rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna));
+			memcpy(&(pnetwork->network), target,  get_wlan_bssid_ex_sz(target));
+			/*  variable initialize */
+			pnetwork->fixed = false;
+			pnetwork->last_scanned = rtw_get_current_time();
+
+			pnetwork->network_type = 0;
+			pnetwork->aid = 0;
+			pnetwork->join_res = 0;
+
+			/* bss info not receving from the right channel */
+			if (pnetwork->network.PhyInfo.SignalQuality == 101)
+				pnetwork->network.PhyInfo.SignalQuality = 0;
+		} else {
+			/* Otherwise just pull from the free list */
+
+			pnetwork = rtw_alloc_network(pmlmepriv); /*  will update scan_time */
+
+			if (pnetwork == NULL) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n"));
+				goto exit;
+			}
+
+			bssid_ex_sz = get_wlan_bssid_ex_sz(target);
+			target->Length = bssid_ex_sz;
+			rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(target->PhyInfo.Optimum_antenna));
+			memcpy(&(pnetwork->network), target, bssid_ex_sz);
+
+			pnetwork->last_scanned = rtw_get_current_time();
+
+			/* bss info not receving from the right channel */
+			if (pnetwork->network.PhyInfo.SignalQuality == 101)
+				pnetwork->network.PhyInfo.SignalQuality = 0;
+			rtw_list_insert_tail(&(pnetwork->list), &(queue->queue));
+		}
+	} else {
+		/* we have an entry and we are going to update it. But this entry may
+		 * be already expired. In this case we do the same as we found a new
+		 * net and call the new_net handler
+		 */
+		bool update_ie = true;
+
+		pnetwork->last_scanned = rtw_get_current_time();
+
+		/* target.Reserved[0]== 1, means that scaned network is a bcn frame. */
+		if ((pnetwork->network.IELength > target->IELength) && (target->Reserved[0] == 1))
+			update_ie = false;
+
+		update_network(&(pnetwork->network), target, adapter, update_ie);
+	}
+
+exit:
+	_exit_critical_bh(&queue->lock, &irql);
+
+_func_exit_;
+}
+
+static void rtw_add_network(struct adapter *adapter,
+			    struct wlan_bssid_ex *pnetwork)
+{
+_func_enter_;
+#if defined(CONFIG_88EU_P2P)
+	rtw_wlan_bssid_ex_remove_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO);
+#endif
+	update_current_network(adapter, pnetwork);
+	rtw_update_scanned_network(adapter, pnetwork);
+_func_exit_;
+}
+
+/* select the desired network based on the capability of the (i)bss. */
+/*  check items:	(1) security */
+/* 			(2) network_type */
+/* 			(3) WMM */
+/*			(4) HT */
+/*			(5) others */
+static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork)
+{
+	struct security_priv *psecuritypriv = &adapter->securitypriv;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	u32 desired_encmode;
+	u32 privacy;
+
+	/* u8 wps_ie[512]; */
+	uint wps_ielen;
+
+	int bselected = true;
+
+	desired_encmode = psecuritypriv->ndisencryptstatus;
+	privacy = pnetwork->network.Privacy;
+
+	if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+		if (rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen) != NULL)
+			return true;
+		else
+			return false;
+	}
+	if (adapter->registrypriv.wifi_spec == 1) { /* for  correct flow of 8021X  to do.... */
+		if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0))
+			bselected = false;
+	}
+
+
+	if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) {
+		DBG_88E("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy);
+		bselected = false;
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+		if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
+			bselected = false;
+	}
+
+
+	return bselected;
+}
+
+/* TODO: Perry: For Power Management */
+void rtw_atimdone_event_callback(struct adapter	*adapter , u8 *pbuf)
+{
+_func_enter_;
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_evet\n"));
+_func_exit_;
+	return;
+}
+
+
+void rtw_survey_event_callback(struct adapter	*adapter, u8 *pbuf)
+{
+	unsigned long  irql;
+	u32 len;
+	struct wlan_bssid_ex *pnetwork;
+	struct	mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+
+_func_enter_;
+
+	pnetwork = (struct wlan_bssid_ex *)pbuf;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_survey_event_callback, ssid=%s\n",  pnetwork->Ssid.Ssid));
+
+	len = get_wlan_bssid_ex_sz(pnetwork);
+	if (len > (sizeof(struct wlan_bssid_ex))) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n****rtw_survey_event_callback: return a wrong bss ***\n"));
+		return;
+	}
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+
+	/*  update IBSS_network 's timestamp */
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) {
+		if (_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) {
+			struct wlan_network *ibss_wlan = NULL;
+			unsigned long	irql;
+
+			memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8);
+			_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+			ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue,  pnetwork->MacAddress);
+			if (ibss_wlan) {
+				memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8);
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+				goto exit;
+			}
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+		}
+	}
+
+	/*  lock pmlmepriv->lock when you accessing network_q */
+	if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) {
+		if (pnetwork->Ssid.Ssid[0] == 0)
+			pnetwork->Ssid.SsidLength = 0;
+		rtw_add_network(adapter, pnetwork);
+	}
+
+exit:
+
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+
+_func_exit_;
+
+	return;
+}
+
+
+
+void rtw_surveydone_event_callback(struct adapter	*adapter, u8 *pbuf)
+{
+	unsigned long  irql;
+	struct	mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext;
+
+_func_enter_;
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+
+	if (pmlmepriv->wps_probe_req_ie) {
+		pmlmepriv->wps_probe_req_ie_len = 0;
+		kfree(pmlmepriv->wps_probe_req_ie);
+		pmlmepriv->wps_probe_req_ie = NULL;
+	}
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback: fw_state:%x\n\n", get_fwstate(pmlmepriv)));
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+		u8 timer_cancelled;
+
+		_cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled);
+
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+	} else {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status=%x, survey done event comes too late!\n", get_fwstate(pmlmepriv)));
+	}
+
+	rtw_set_signal_stat_timer(&adapter->recvpriv);
+
+	if (pmlmepriv->to_join) {
+		if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
+			if (check_fwstate(pmlmepriv, _FW_LINKED) == false) {
+				set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+				if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) {
+					_set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+				} else {
+					struct wlan_bssid_ex    *pdev_network = &(adapter->registrypriv.dev_network);
+					u8 *pibss = adapter->registrypriv.dev_network.MacAddress;
+
+					_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+					RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n"));
+
+					_rtw_memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+					memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
+
+					rtw_update_registrypriv_dev_network(adapter);
+					rtw_generate_random_ibss(pibss);
+
+					pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
+
+					if (rtw_createbss_cmd(adapter) != _SUCCESS)
+						RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error=>rtw_createbss_cmd status FAIL\n"));
+					pmlmepriv->to_join = false;
+				}
+			}
+		} else {
+			int s_ret;
+			set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+			pmlmepriv->to_join = false;
+			s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
+			if (_SUCCESS == s_ret) {
+			     _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT);
+			} else if (s_ret == 2) { /* there is no need to wait for join */
+				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+				rtw_indicate_connect(adapter);
+			} else {
+				DBG_88E("try_to_join, but select scanning queue fail, to_roaming:%d\n", pmlmepriv->to_roaming);
+				if (pmlmepriv->to_roaming != 0) {
+					if (--pmlmepriv->to_roaming == 0 ||
+					    _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) {
+						pmlmepriv->to_roaming = 0;
+						rtw_free_assoc_resources(adapter, 1);
+						rtw_indicate_disconnect(adapter);
+					} else {
+						pmlmepriv->to_join = true;
+					}
+				}
+				_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+			}
+		}
+	}
+
+	indicate_wx_scan_complete_event(adapter);
+
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+		p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0);
+
+	rtw_os_xmit_schedule(adapter);
+
+	pmlmeext = &adapter->mlmeextpriv;
+	if (pmlmeext->sitesurvey_res.bss_cnt == 0)
+		rtw_hal_sreset_reset(adapter);
+_func_exit_;
+}
+
+void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf)
+{
+}
+
+void rtw_fwdbg_event_callback(struct adapter *adapter , u8 *pbuf)
+{
+}
+
+static void free_scanqueue(struct	mlme_priv *pmlmepriv)
+{
+	unsigned long irql, irql0;
+	struct __queue *free_queue = &pmlmepriv->free_bss_pool;
+	struct __queue *scan_queue = &pmlmepriv->scanned_queue;
+	struct list_head *plist, *phead, *ptemp;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n"));
+	_enter_critical_bh(&scan_queue->lock, &irql0);
+	_enter_critical_bh(&free_queue->lock, &irql);
+
+	phead = get_list_head(scan_queue);
+	plist = get_next(phead);
+
+	while (plist != phead) {
+		ptemp = get_next(plist);
+		rtw_list_delete(plist);
+		rtw_list_insert_tail(plist, &free_queue->queue);
+		plist = ptemp;
+		pmlmepriv->num_of_scanned--;
+	}
+
+	_exit_critical_bh(&free_queue->lock, &irql);
+	_exit_critical_bh(&scan_queue->lock, &irql0);
+
+_func_exit_;
+}
+
+/*
+*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock
+*/
+void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue)
+{
+	unsigned long irql;
+	struct wlan_network *pwlan = NULL;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct	sta_priv *pstapriv = &adapter->stapriv;
+	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n"));
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+		 ("tgt_network->network.MacAddress=%pM ssid=%s\n",
+		 tgt_network->network.MacAddress, tgt_network->network.Ssid.Ssid));
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) {
+		struct sta_info *psta;
+
+		psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress);
+
+		_enter_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+		rtw_free_stainfo(adapter,  psta);
+		_exit_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) {
+		struct sta_info *psta;
+
+		rtw_free_all_stainfo(adapter);
+
+		psta = rtw_get_bcmc_stainfo(adapter);
+		_enter_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+		rtw_free_stainfo(adapter, psta);
+		_exit_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+
+		rtw_init_bcmc_stainfo(adapter);
+	}
+
+	if (lock_scanned_queue)
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+
+	pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+	if (pwlan)
+		pwlan->fixed = false;
+	else
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources:pwlan==NULL\n\n"));
+
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)))
+		rtw_free_network_nolock(pmlmepriv, pwlan);
+
+	if (lock_scanned_queue)
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+	pmlmepriv->key_mask = 0;
+_func_exit_;
+}
+
+/*
+*rtw_indicate_connect: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_connect(struct adapter *padapter)
+{
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n"));
+
+	pmlmepriv->to_join = false;
+
+	if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+		set_fwstate(pmlmepriv, _FW_LINKED);
+
+		rtw_led_control(padapter, LED_CTL_LINK);
+
+		rtw_os_indicate_connect(padapter);
+	}
+
+	pmlmepriv->to_roaming = 0;
+
+	rtw_set_scan_deny(padapter, 3000);
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv)));
+_func_exit_;
+}
+
+/*
+*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_disconnect(struct adapter *padapter)
+{
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect\n"));
+
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS);
+
+
+	if (pmlmepriv->to_roaming > 0)
+		_clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+	if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) ||
+	    (pmlmepriv->to_roaming <= 0)) {
+		rtw_os_indicate_disconnect(padapter);
+
+		_clr_fwstate_(pmlmepriv, _FW_LINKED);
+		rtw_led_control(padapter, LED_CTL_NO_LINK);
+		rtw_clear_scan_deny(padapter);
+	}
+	p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
+
+	rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1);
+
+_func_exit_;
+}
+
+inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted)
+{
+	rtw_os_indicate_scan_done(padapter, aborted);
+}
+
+void rtw_scan_abort(struct adapter *adapter)
+{
+	u32 start;
+	struct mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(adapter->mlmeextpriv);
+
+	start = rtw_get_current_time();
+	pmlmeext->scan_abort = true;
+	while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) &&
+	       rtw_get_passing_time_ms(start) <= 200) {
+		if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+			break;
+		DBG_88E(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+		rtw_msleep_os(20);
+	}
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+		if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved)
+			DBG_88E(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+		rtw_indicate_scan_done(adapter, true);
+	}
+	pmlmeext->scan_abort = false;
+}
+
+static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork)
+{
+	int i;
+	struct sta_info *bmc_sta, *psta = NULL;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress);
+	if (psta == NULL)
+		psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress);
+
+	if (psta) { /* update ptarget_sta */
+		DBG_88E("%s\n", __func__);
+		psta->aid  = pnetwork->join_res;
+			psta->mac_id = 0;
+		/* sta mode */
+		rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true);
+		/* security related */
+		if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+			padapter->securitypriv.binstallGrpkey = false;
+			padapter->securitypriv.busetkipkey = false;
+			padapter->securitypriv.bgrpkey_handshake = false;
+			psta->ieee8021x_blocked = true;
+			psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+			_rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype));
+			_rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype));
+			_rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype));
+			_rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48));
+			_rtw_memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48));
+		}
+		/* 	Commented by Albert 2012/07/21 */
+		/* 	When doing the WPS, the wps_ie_len won't equal to 0 */
+		/* 	And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */
+		if (padapter->securitypriv.wps_ie_len != 0) {
+			psta->ieee8021x_blocked = true;
+			padapter->securitypriv.wps_ie_len = 0;
+		}
+		/* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */
+		/* if A-MPDU Rx is enabled, reseting  rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */
+		/* todo: check if AP can send A-MPDU packets */
+		for (i = 0; i < 16; i++) {
+			/* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
+			preorder_ctrl = &psta->recvreorder_ctrl[i];
+			preorder_ctrl->enable = false;
+			preorder_ctrl->indicate_seq = 0xffff;
+			preorder_ctrl->wend_b = 0xffff;
+			preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
+		}
+		bmc_sta = rtw_get_bcmc_stainfo(padapter);
+		if (bmc_sta) {
+			for (i = 0; i < 16; i++) {
+				/* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
+				preorder_ctrl = &bmc_sta->recvreorder_ctrl[i];
+				preorder_ctrl->enable = false;
+				preorder_ctrl->indicate_seq = 0xffff;
+				preorder_ctrl->wend_b = 0xffff;
+				preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
+			}
+		}
+		/* misc. */
+		update_sta_info(padapter, psta);
+	}
+	return psta;
+}
+
+/* pnetwork: returns from rtw_joinbss_event_callback */
+/* ptarget_wlan: found from scanned_queue */
+static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network  *pnetwork)
+{
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_network  *cur_network = &(pmlmepriv->cur_network);
+
+	DBG_88E("%s\n", __func__);
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+		 ("\nfw_state:%x, BSSID:%pM\n",
+		 get_fwstate(pmlmepriv), pnetwork->network.MacAddress));
+
+
+	/*  why not use ptarget_wlan?? */
+	memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length);
+	/*  some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */
+	cur_network->network.IELength = ptarget_wlan->network.IELength;
+	memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ);
+
+	cur_network->aid = pnetwork->join_res;
+
+
+	rtw_set_signal_stat_timer(&padapter->recvpriv);
+	padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength;
+	padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality;
+	/* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */
+	padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength);
+	rtw_set_signal_stat_timer(&padapter->recvpriv);
+
+	/* update fw_state will clr _FW_UNDER_LINKING here indirectly */
+	switch (pnetwork->network.InfrastructureMode) {
+	case Ndis802_11Infrastructure:
+		if (pmlmepriv->fw_state&WIFI_UNDER_WPS)
+			pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS;
+		else
+			pmlmepriv->fw_state = WIFI_STATION_STATE;
+		break;
+	case Ndis802_11IBSS:
+		pmlmepriv->fw_state = WIFI_ADHOC_STATE;
+		break;
+	default:
+		pmlmepriv->fw_state = WIFI_NULL_STATE;
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n"));
+		break;
+	}
+
+	rtw_update_protection(padapter, (cur_network->network.IEs) +
+			      sizeof(struct ndis_802_11_fixed_ie),
+			      (cur_network->network.IELength));
+	rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength);
+}
+
+/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */
+/* pnetwork: returns from rtw_joinbss_event_callback */
+/* ptarget_wlan: found from scanned_queue */
+/* if join_res > 0, for (fw_state == WIFI_STATION_STATE), we check if  "ptarget_sta" & "ptarget_wlan" exist. */
+/* if join_res > 0, for (fw_state == WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */
+/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan != NULL). */
+
+void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf)
+{
+	unsigned long irql, irql2;
+	u8 timer_cancelled;
+	struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL;
+	struct	sta_priv *pstapriv = &adapter->stapriv;
+	struct	mlme_priv	*pmlmepriv = &(adapter->mlmepriv);
+	struct wlan_network	*pnetwork	= (struct wlan_network *)pbuf;
+	struct wlan_network	*cur_network = &(pmlmepriv->cur_network);
+	struct wlan_network	*pcur_wlan = NULL, *ptarget_wlan = NULL;
+	unsigned int		the_same_macaddr = false;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("joinbss event call back received with res=%d\n", pnetwork->join_res));
+
+	rtw_get_encrypt_decrypt_from_registrypriv(adapter);
+
+
+	if (pmlmepriv->assoc_ssid.SsidLength == 0)
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@   joinbss event call back  for Any SSid\n"));
+	else
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@   rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid));
+
+	the_same_macaddr = _rtw_memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN);
+
+	pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network);
+	if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n"));
+		goto ignore_nolock;
+	}
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nrtw_joinbss_event_callback!! _enter_critical\n"));
+
+	if (pnetwork->join_res > 0) {
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+		if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
+			/* s1. find ptarget_wlan */
+			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				if (the_same_macaddr) {
+					ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+				} else {
+					pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+					if (pcur_wlan)
+						pcur_wlan->fixed = false;
+
+					pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+					if (pcur_sta) {
+						_enter_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+						rtw_free_stainfo(adapter,  pcur_sta);
+						_exit_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+					}
+
+					ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
+					if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+						if (ptarget_wlan)
+							ptarget_wlan->fixed = true;
+					}
+				}
+			} else {
+				ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
+				if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+					if (ptarget_wlan)
+						ptarget_wlan->fixed = true;
+				}
+			}
+
+			/* s2. update cur_network */
+			if (ptarget_wlan) {
+				rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork);
+			} else {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't find ptarget_wlan when joinbss_event callback\n"));
+				_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+				goto ignore_joinbss_callback;
+			}
+
+
+			/* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */
+			if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+				ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork);
+				if (ptarget_sta == NULL) {
+					RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n"));
+					_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+					goto ignore_joinbss_callback;
+				}
+			}
+
+			/* s4. indicate connect */
+				if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+					rtw_indicate_connect(adapter);
+				} else {
+					/* adhoc mode will rtw_indicate_connect when rtw_stassoc_event_callback */
+					RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv)));
+				}
+
+			/* s5. Cancle assoc_timer */
+			_cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled);
+
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("Cancle assoc_timer\n"));
+
+		} else {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_joinbss_event_callback err: fw_state:%x", get_fwstate(pmlmepriv)));
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+			goto ignore_joinbss_callback;
+		}
+
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+
+	} else if (pnetwork->join_res == -4) {
+		rtw_reset_securitypriv(adapter);
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+
+		if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == true) {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n", get_fwstate(pmlmepriv)));
+			_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+		}
+	} else { /* if join_res < 0 (join fails), then try again */
+		_set_timer(&pmlmepriv->assoc_timer, 1);
+		_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+	}
+
+ignore_joinbss_callback:
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+ignore_nolock:
+_func_exit_;
+}
+
+void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+	struct wlan_network	*pnetwork	= (struct wlan_network *)pbuf;
+
+_func_enter_;
+
+	mlmeext_joinbss_event_callback(adapter, pnetwork->join_res);
+
+	rtw_os_xmit_schedule(adapter);
+
+_func_exit_;
+}
+
+static u8 search_max_mac_id(struct adapter *padapter)
+{
+	u8 mac_id;
+#if defined (CONFIG_88EU_AP_MODE)
+	u8 aid;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+#endif
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+#if defined (CONFIG_88EU_AP_MODE)
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		for (aid = (pstapriv->max_num_sta); aid > 0; aid--) {
+			if (pstapriv->sta_aid[aid-1] != NULL)
+				break;
+		}
+		mac_id = aid + 1;
+	} else
+#endif
+	{/* adhoc  id =  31~2 */
+		for (mac_id = (NUM_STA-1); mac_id >= IBSS_START_MAC_ID; mac_id--) {
+			if (pmlmeinfo->FW_sta_info[mac_id].status == 1)
+				break;
+		}
+	}
+	return mac_id;
+}
+
+/* FOR AP , AD-HOC mode */
+void rtw_stassoc_hw_rpt(struct adapter *adapter, struct sta_info *psta)
+{
+	u16 media_status;
+	u8 macid;
+
+	if (psta == NULL)
+		return;
+
+	macid = search_max_mac_id(adapter);
+	rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&macid);
+	media_status = (psta->mac_id<<8)|1; /*   MACID|OPMODE:1 connect */
+	rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+}
+
+void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+	unsigned long irql;
+	struct sta_info *psta;
+	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+	struct stassoc_event	*pstassoc = (struct stassoc_event *)pbuf;
+	struct wlan_network	*cur_network = &(pmlmepriv->cur_network);
+	struct wlan_network	*ptarget_wlan = NULL;
+
+_func_enter_;
+
+	if (rtw_access_ctrl(adapter, pstassoc->macaddr) == false)
+		return;
+
+#if defined (CONFIG_88EU_AP_MODE)
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
+		if (psta) {
+			ap_sta_info_defer_update(adapter, psta);
+			rtw_stassoc_hw_rpt(adapter, psta);
+		}
+		goto exit;
+	}
+#endif
+	/* for AD-HOC mode */
+	psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr);
+	if (psta != NULL) {
+		/* the sta have been in sta_info_queue => do nothing */
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n"));
+		goto exit; /* between drv has received this event before and  fw have not yet to set key to CAM_ENTRY) */
+	}
+	psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr);
+	if (psta == NULL) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n"));
+		goto exit;
+	}
+	/* to do: init sta_info variable */
+	psta->qos_option = 0;
+	psta->mac_id = (uint)pstassoc->cam_id;
+	DBG_88E("%s\n", __func__);
+	/* for ad-hoc mode */
+	rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true);
+	rtw_stassoc_hw_rpt(adapter, psta);
+	if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+		psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm;
+	psta->ieee8021x_blocked = false;
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) {
+		if (adapter->stapriv.asoc_sta_count == 2) {
+			_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+			ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+			if (ptarget_wlan)
+				ptarget_wlan->fixed = true;
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+			/*  a sta + bc/mc_stainfo (not Ibss_stainfo) */
+			rtw_indicate_connect(adapter);
+		}
+	}
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+	mlmeext_sta_add_event_callback(adapter, psta);
+exit:
+_func_exit_;
+}
+
+void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
+{
+	unsigned long irql, irql2;
+	int mac_id = -1;
+	struct sta_info *psta;
+	struct wlan_network *pwlan = NULL;
+	struct wlan_bssid_ex *pdev_network = NULL;
+	u8 *pibss = NULL;
+	struct	mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+	struct	stadel_event *pstadel = (struct stadel_event *)pbuf;
+	struct	sta_priv *pstapriv = &adapter->stapriv;
+	struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
+
+_func_enter_;
+
+	psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr);
+	if (psta)
+		mac_id = psta->mac_id;
+	else
+		mac_id = pstadel->mac_id;
+
+	DBG_88E("%s(mac_id=%d)=%pM\n", __func__, mac_id, pstadel->macaddr);
+
+	if (mac_id >= 0) {
+		u16 media_status;
+		media_status = (mac_id<<8)|0; /*   MACID|OPMODE:0 means disconnect */
+		/* for STA, AP, ADHOC mode, report disconnect stauts to FW */
+		rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+		return;
+
+	mlmeext_sta_del_event_callback(adapter);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql2);
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+		if (pmlmepriv->to_roaming > 0)
+			pmlmepriv->to_roaming--; /*  this stadel_event is caused by roaming, decrease to_roaming */
+		else if (pmlmepriv->to_roaming == 0)
+			pmlmepriv->to_roaming = adapter->registrypriv.max_roaming_times;
+
+		if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK)
+			pmlmepriv->to_roaming = 0; /*  don't roam */
+
+		rtw_free_uc_swdec_pending_queue(adapter);
+
+		rtw_free_assoc_resources(adapter, 1);
+		rtw_indicate_disconnect(adapter);
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+		/*  remove the network entry in scanned_queue */
+		pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+		if (pwlan) {
+			pwlan->fixed = false;
+			rtw_free_network_nolock(pmlmepriv, pwlan);
+		}
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+		_rtw_roaming(adapter, tgt_network);
+	}
+	if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
+	    check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
+		_enter_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+		rtw_free_stainfo(adapter,  psta);
+		_exit_critical_bh(&(pstapriv->sta_hash_lock), &irql);
+
+		if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */
+			_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+			/* free old ibss network */
+			pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+			if (pwlan) {
+				pwlan->fixed = false;
+				rtw_free_network_nolock(pmlmepriv, pwlan);
+			}
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+			/* re-create ibss */
+			pdev_network = &(adapter->registrypriv.dev_network);
+			pibss = adapter->registrypriv.dev_network.MacAddress;
+
+			memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network));
+
+			_rtw_memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid));
+			memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid));
+
+			rtw_update_registrypriv_dev_network(adapter);
+
+			rtw_generate_random_ibss(pibss);
+
+			if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
+				set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+				_clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE);
+			}
+
+			if (rtw_createbss_cmd(adapter) != _SUCCESS)
+				RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error=>stadel_event_callback: rtw_createbss_cmd status FAIL***\n "));
+		}
+	}
+	_exit_critical_bh(&pmlmepriv->lock, &irql2);
+_func_exit_;
+}
+
+void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf)
+{
+_func_enter_;
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_cpwm_event_callback !!!\n"));
+_func_exit_;
+}
+
+/*
+* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss
+* @adapter: pointer to struct adapter structure
+*/
+void _rtw_join_timeout_handler (struct adapter *adapter)
+{
+	unsigned long irql;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	int do_join_r;
+
+_func_enter_;
+
+	DBG_88E("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv));
+
+	if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+		return;
+
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+
+	if (pmlmepriv->to_roaming > 0) { /*  join timeout caused by roaming */
+		while (1) {
+			pmlmepriv->to_roaming--;
+			if (pmlmepriv->to_roaming != 0) { /* try another , */
+				DBG_88E("%s try another roaming\n", __func__);
+				do_join_r = rtw_do_join(adapter);
+				if (_SUCCESS != do_join_r) {
+					DBG_88E("%s roaming do_join return %d\n", __func__ , do_join_r);
+					continue;
+				}
+				break;
+			} else {
+				DBG_88E("%s We've try roaming but fail\n", __func__);
+				rtw_indicate_disconnect(adapter);
+				break;
+			}
+		}
+	} else {
+		rtw_indicate_disconnect(adapter);
+		free_scanqueue(pmlmepriv);/*  */
+	}
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+_func_exit_;
+}
+
+/*
+* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey
+* @adapter: pointer to struct adapter structure
+*/
+void rtw_scan_timeout_handler (struct adapter *adapter)
+{
+	unsigned long irql;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+	DBG_88E(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+	rtw_indicate_scan_done(adapter, true);
+}
+
+static void rtw_auto_scan_handler(struct adapter *padapter)
+{
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	/* auto site survey per 60sec */
+	if (pmlmepriv->scan_interval > 0) {
+		pmlmepriv->scan_interval--;
+		if (pmlmepriv->scan_interval == 0) {
+			DBG_88E("%s\n", __func__);
+			rtw_set_802_11_bssid_list_scan(padapter, NULL, 0);
+			pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+		}
+	}
+}
+
+void rtw_dynamic_check_timer_handlder(struct adapter *adapter)
+{
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+
+	if (!adapter)
+		return;
+	if (!adapter->hw_init_completed)
+		return;
+	if ((adapter->bDriverStopped) || (adapter->bSurpriseRemoved))
+		return;
+	if (adapter->net_closed)
+		return;
+	rtw_dynamic_chk_wk_cmd(adapter);
+
+	if (pregistrypriv->wifi_spec == 1) {
+#ifdef CONFIG_88EU_P2P
+		struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+#endif
+		{
+			/* auto site survey */
+			rtw_auto_scan_handler(adapter);
+		}
+	}
+
+	rcu_read_lock();
+
+	if (rcu_dereference(adapter->pnetdev->rx_handler_data) &&
+	    (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == true)) {
+		/*  expire NAT2.5 entry */
+		nat25_db_expire(adapter);
+
+		if (adapter->pppoe_connection_in_progress > 0) {
+			adapter->pppoe_connection_in_progress--;
+		}
+
+		/*  due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */
+		if (adapter->pppoe_connection_in_progress > 0) {
+			adapter->pppoe_connection_in_progress--;
+		}
+	}
+
+	rcu_read_unlock();
+}
+
+#define RTW_SCAN_RESULT_EXPIRE 2000
+
+/*
+* Select a new join candidate from the original @param candidate and @param competitor
+* @return true: candidate is updated
+* @return false: candidate is not updated
+*/
+static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
+	, struct wlan_network **candidate, struct wlan_network *competitor)
+{
+	int updated = false;
+	struct adapter *adapter = container_of(pmlmepriv, struct adapter, mlmepriv);
+
+
+	/* check bssid, if needed */
+	if (pmlmepriv->assoc_by_bssid) {
+		if (!_rtw_memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN))
+			goto exit;
+	}
+
+	/* check ssid, if needed */
+	if (pmlmepriv->assoc_ssid.Ssid && pmlmepriv->assoc_ssid.SsidLength) {
+		if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength ||
+		    _rtw_memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength) == false)
+			goto exit;
+	}
+
+	if (rtw_is_desired_network(adapter, competitor)  == false)
+		goto exit;
+
+	if (pmlmepriv->to_roaming) {
+		if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= RTW_SCAN_RESULT_EXPIRE ||
+		    is_same_ess(&competitor->network, &pmlmepriv->cur_network.network) == false)
+			goto exit;
+	}
+
+	if (*candidate == NULL || (*candidate)->network.Rssi < competitor->network.Rssi) {
+		*candidate = competitor;
+		updated = true;
+	}
+	if (updated) {
+		DBG_88E("[by_bssid:%u][assoc_ssid:%s]new candidate: %s(%pM rssi:%d\n",
+			pmlmepriv->assoc_by_bssid,
+			pmlmepriv->assoc_ssid.Ssid,
+			(*candidate)->network.Ssid.Ssid,
+			(*candidate)->network.MacAddress,
+			(int)(*candidate)->network.Rssi);
+		DBG_88E("[to_roaming:%u]\n", pmlmepriv->to_roaming);
+	}
+
+exit:
+	return updated;
+}
+
+/*
+Calling context:
+The caller of the sub-routine will be in critical section...
+The caller must hold the following spinlock
+pmlmepriv->lock
+*/
+
+int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv)
+{
+	unsigned long	irql;
+	int ret;
+	struct list_head *phead;
+	struct adapter *adapter;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	struct	wlan_network	*candidate = NULL;
+	u8	supp_ant_div = false;
+
+_func_enter_;
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+	phead = get_list_head(queue);
+	adapter = (struct adapter *)pmlmepriv->nic_hdl;
+	pmlmepriv->pscanned = get_next(phead);
+	while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) {
+		pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+		if (pnetwork == NULL) {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork==NULL)\n", __func__));
+			ret = _FAIL;
+			goto exit;
+		}
+		pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+		rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
+	}
+	if (candidate == NULL) {
+		DBG_88E("%s: return _FAIL(candidate==NULL)\n", __func__);
+		ret = _FAIL;
+		goto exit;
+	} else {
+		DBG_88E("%s: candidate: %s(%pM ch:%u)\n", __func__,
+			candidate->network.Ssid.Ssid, candidate->network.MacAddress,
+			candidate->network.Configuration.DSConfig);
+	}
+
+
+	/*  check for situation of  _FW_LINKED */
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+		DBG_88E("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__);
+
+		rtw_disassoc_cmd(adapter, 0, true);
+		rtw_indicate_disconnect(adapter);
+		rtw_free_assoc_resources(adapter, 0);
+	}
+
+	rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(supp_ant_div));
+	if (supp_ant_div) {
+		u8 cur_ant;
+		rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(cur_ant));
+		DBG_88E("#### Opt_Ant_(%s), cur_Ant(%s)\n",
+			(2 == candidate->network.PhyInfo.Optimum_antenna) ? "A" : "B",
+			(2 == cur_ant) ? "A" : "B"
+		);
+	}
+
+	ret = rtw_joinbss_cmd(adapter, candidate);
+
+exit:
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irql);
+
+_func_exit_;
+
+	return ret;
+}
+
+int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv)
+{
+	struct	cmd_obj *pcmd;
+	struct	setauth_parm *psetauthparm;
+	struct	cmd_priv *pcmdpriv = &(adapter->cmdpriv);
+	int		res = _SUCCESS;
+
+_func_enter_;
+
+	pcmd = (struct	cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;  /* try again */
+		goto exit;
+	}
+
+	psetauthparm = (struct setauth_parm *)rtw_zmalloc(sizeof(struct setauth_parm));
+	if (psetauthparm == NULL) {
+		kfree(pcmd);
+		res = _FAIL;
+		goto exit;
+	}
+	_rtw_memset(psetauthparm, 0, sizeof(struct setauth_parm));
+	psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
+	pcmd->cmdcode = _SetAuth_CMD_;
+	pcmd->parmbuf = (unsigned char *)psetauthparm;
+	pcmd->cmdsz =  (sizeof(struct setauth_parm));
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+	_rtw_init_listhead(&pcmd->list);
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+		 ("after enqueue set_auth_cmd, auth_mode=%x\n",
+		 psecuritypriv->dot11AuthAlgrthm));
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+_func_exit_;
+	return res;
+}
+
+int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, int keyid, u8 set_tx)
+{
+	u8	keylen;
+	struct cmd_obj		*pcmd;
+	struct setkey_parm	*psetkeyparm;
+	struct cmd_priv		*pcmdpriv = &(adapter->cmdpriv);
+	struct mlme_priv		*pmlmepriv = &(adapter->mlmepriv);
+	int	res = _SUCCESS;
+
+_func_enter_;
+	pcmd = (struct	cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;  /* try again */
+		goto exit;
+	}
+	psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+	if (psetkeyparm == NULL) {
+		kfree(pcmd);
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+		psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy;
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+			 ("\n rtw_set_key: psetkeyparm->algorithm=(unsigned char)psecuritypriv->dot118021XGrpPrivacy=%d\n",
+			 psetkeyparm->algorithm));
+	} else {
+		psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+			 ("\n rtw_set_key: psetkeyparm->algorithm=(u8)psecuritypriv->dot11PrivacyAlgrthm=%d\n",
+			 psetkeyparm->algorithm));
+	}
+	psetkeyparm->keyid = (u8)keyid;/* 0~3 */
+	psetkeyparm->set_tx = set_tx;
+	pmlmepriv->key_mask |= BIT(psetkeyparm->keyid);
+	DBG_88E("==> rtw_set_key algorithm(%x), keyid(%x), key_mask(%x)\n",
+		psetkeyparm->algorithm, psetkeyparm->keyid, pmlmepriv->key_mask);
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+		 ("\n rtw_set_key: psetkeyparm->algorithm=%d psetkeyparm->keyid=(u8)keyid=%d\n",
+		 psetkeyparm->algorithm, keyid));
+
+	switch (psetkeyparm->algorithm) {
+	case _WEP40_:
+		keylen = 5;
+		memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
+		break;
+	case _WEP104_:
+		keylen = 13;
+		memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen);
+		break;
+	case _TKIP_:
+		keylen = 16;
+		memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+		psetkeyparm->grpkey = 1;
+		break;
+	case _AES_:
+		keylen = 16;
+		memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+		psetkeyparm->grpkey = 1;
+		break;
+	default:
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+			 ("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm=%x (must be 1 or 2 or 4 or 5)\n",
+			 psecuritypriv->dot11PrivacyAlgrthm));
+		res = _FAIL;
+		goto exit;
+	}
+	pcmd->cmdcode = _SetKey_CMD_;
+	pcmd->parmbuf = (u8 *)psetkeyparm;
+	pcmd->cmdsz =  (sizeof(struct setkey_parm));
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+	_rtw_init_listhead(&pcmd->list);
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+exit:
+_func_exit_;
+	return res;
+}
+
+/* adjust IEs for rtw_joinbss_cmd in WMM */
+int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len)
+{
+	unsigned	int ielength = 0;
+	unsigned int i, j;
+
+	i = 12; /* after the fixed IE */
+	while (i < in_len) {
+		ielength = initial_out_len;
+
+		if (in_ie[i] == 0xDD && in_ie[i+2] == 0x00 && in_ie[i+3] == 0x50  && in_ie[i+4] == 0xF2 && in_ie[i+5] == 0x02 && i+5 < in_len) {
+			/* WMM element ID and OUI */
+			/* Append WMM IE to the last index of out_ie */
+
+			for (j = i; j < i + 9; j++) {
+				out_ie[ielength] = in_ie[j];
+				ielength++;
+			}
+			out_ie[initial_out_len + 1] = 0x07;
+			out_ie[initial_out_len + 6] = 0x00;
+			out_ie[initial_out_len + 8] = 0x00;
+			break;
+		}
+		i += (in_ie[i+1]+2); /*  to the next IE element */
+	}
+	return ielength;
+}
+
+/*  */
+/*  Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */
+/*  Added by Annie, 2006-05-07. */
+/*  */
+/*  Search by BSSID, */
+/*  Return Value: */
+/* 		-1		:if there is no pre-auth key in the  table */
+/* 		>= 0		:if there is pre-auth key, and   return the entry id */
+/*  */
+/*  */
+
+static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid)
+{
+	struct security_priv *psecuritypriv = &Adapter->securitypriv;
+	int i = 0;
+
+	do {
+		if ((psecuritypriv->PMKIDList[i].bUsed) &&
+		    (_rtw_memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN) == true)) {
+			break;
+		} else {
+			i++;
+			/* continue; */
+		}
+
+	} while (i < NUM_PMKID_CACHE);
+
+	if (i == NUM_PMKID_CACHE) {
+		i = -1;/*  Could not find. */
+	} else {
+		/*  There is one Pre-Authentication Key for the specific BSSID. */
+	}
+	return i;
+}
+
+/*  */
+/*  Check the RSN IE length */
+/*  If the RSN IE length <= 20, the RSN IE didn't include the PMKID information */
+/*  0-11th element in the array are the fixed IE */
+/*  12th element in the array is the IE */
+/*  13th element in the array is the IE length */
+/*  */
+
+static int rtw_append_pmkid(struct adapter *Adapter, int iEntry, u8 *ie, uint ie_len)
+{
+	struct security_priv *psecuritypriv = &Adapter->securitypriv;
+
+	if (ie[13] <= 20) {
+		/*  The RSN IE didn't include the PMK ID, append the PMK information */
+		ie[ie_len] = 1;
+		ie_len++;
+		ie[ie_len] = 0;	/* PMKID count = 0x0100 */
+		ie_len++;
+		memcpy(&ie[ie_len], &psecuritypriv->PMKIDList[iEntry].PMKID, 16);
+
+		ie_len += 16;
+		ie[13] += 18;/* PMKID length = 2+16 */
+	}
+	return ie_len;
+}
+
+int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len)
+{
+	u8 authmode;
+	uint	ielength;
+	int iEntry;
+
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	struct security_priv *psecuritypriv = &adapter->securitypriv;
+	uint	ndisauthmode = psecuritypriv->ndisauthtype;
+	uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+		 ("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n",
+		  ndisauthmode, ndissecuritytype));
+
+	/* copy fixed ie only */
+	memcpy(out_ie, in_ie, 12);
+	ielength = 12;
+	if ((ndisauthmode == Ndis802_11AuthModeWPA) ||
+	    (ndisauthmode == Ndis802_11AuthModeWPAPSK))
+			authmode = _WPA_IE_ID_;
+	if ((ndisauthmode == Ndis802_11AuthModeWPA2) ||
+	    (ndisauthmode == Ndis802_11AuthModeWPA2PSK))
+		authmode = _WPA2_IE_ID_;
+
+	if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+		memcpy(out_ie+ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len);
+
+		ielength += psecuritypriv->wps_ie_len;
+	} else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) {
+		/* copy RSN or SSN */
+		memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2);
+		ielength += psecuritypriv->supplicant_ie[1]+2;
+		rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie);
+	}
+
+	iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
+	if (iEntry < 0) {
+		return ielength;
+	} else {
+		if (authmode == _WPA2_IE_ID_)
+			ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength);
+	}
+
+_func_exit_;
+
+	return ielength;
+}
+
+void rtw_init_registrypriv_dev_network(struct adapter *adapter)
+{
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	struct eeprom_priv *peepriv = &adapter->eeprompriv;
+	struct wlan_bssid_ex    *pdev_network = &pregistrypriv->dev_network;
+	u8 *myhwaddr = myid(peepriv);
+
+_func_enter_;
+
+	memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN);
+
+	memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid));
+
+	pdev_network->Configuration.Length = sizeof(struct ndis_802_11_config);
+	pdev_network->Configuration.BeaconPeriod = 100;
+	pdev_network->Configuration.FHConfig.Length = 0;
+	pdev_network->Configuration.FHConfig.HopPattern = 0;
+	pdev_network->Configuration.FHConfig.HopSet = 0;
+	pdev_network->Configuration.FHConfig.DwellTime = 0;
+
+_func_exit_;
+}
+
+void rtw_update_registrypriv_dev_network(struct adapter *adapter)
+{
+	int sz = 0;
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	struct wlan_bssid_ex    *pdev_network = &pregistrypriv->dev_network;
+	struct	security_priv *psecuritypriv = &adapter->securitypriv;
+	struct	wlan_network	*cur_network = &adapter->mlmepriv.cur_network;
+
+_func_enter_;
+
+	pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0); /*  adhoc no 802.1x */
+
+	pdev_network->Rssi = 0;
+
+	switch (pregistrypriv->wireless_mode) {
+	case WIRELESS_11B:
+		pdev_network->NetworkTypeInUse = (Ndis802_11DS);
+		break;
+	case WIRELESS_11G:
+	case WIRELESS_11BG:
+	case WIRELESS_11_24N:
+	case WIRELESS_11G_24N:
+	case WIRELESS_11BG_24N:
+		pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
+		break;
+	case WIRELESS_11A:
+	case WIRELESS_11A_5N:
+		pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
+		break;
+	case WIRELESS_11ABGN:
+		if (pregistrypriv->channel > 14)
+			pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5);
+		else
+			pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24);
+		break;
+	default:
+		/*  TODO */
+		break;
+	}
+
+	pdev_network->Configuration.DSConfig = (pregistrypriv->channel);
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+		 ("pregistrypriv->channel=%d, pdev_network->Configuration.DSConfig=0x%x\n",
+		 pregistrypriv->channel, pdev_network->Configuration.DSConfig));
+
+	if (cur_network->network.InfrastructureMode == Ndis802_11IBSS)
+		pdev_network->Configuration.ATIMWindow = (0);
+
+	pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode);
+
+	/*  1. Supported rates */
+	/*  2. IE */
+
+	sz = rtw_generate_ie(pregistrypriv);
+	pdev_network->IELength = sz;
+	pdev_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex  *)pdev_network);
+
+	/* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */
+	/* pdev_network->IELength = cpu_to_le32(sz); */
+_func_exit_;
+}
+
+void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter)
+{
+_func_enter_;
+_func_exit_;
+}
+
+/* the fucntion is at passive_level */
+void rtw_joinbss_reset(struct adapter *padapter)
+{
+	u8	threshold;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+
+	/* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */
+	pmlmepriv->num_FortyMHzIntolerant = 0;
+
+	pmlmepriv->num_sta_no_ht = 0;
+
+	phtpriv->ampdu_enable = false;/* reset to disabled */
+
+	/*  TH = 1 => means that invalidate usb rx aggregation */
+	/*  TH = 0 => means that validate usb rx aggregation, use init value. */
+	if (phtpriv->ht_option) {
+		if (padapter->registrypriv.wifi_spec == 1)
+			threshold = 1;
+		else
+			threshold = 0;
+		rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
+	} else {
+		threshold = 1;
+		rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
+	}
+}
+
+/* the fucntion is >= passive_level */
+unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len)
+{
+	u32 ielen, out_len;
+	enum ht_cap_ampdu_factor max_rx_ampdu_factor;
+	unsigned char *p;
+	struct rtw_ieee80211_ht_cap ht_capie;
+	unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct qos_priv		*pqospriv = &pmlmepriv->qospriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	u32 rx_packet_offset, max_recvbuf_sz;
+
+
+	phtpriv->ht_option = false;
+
+	p = rtw_get_ie(in_ie+12, _HT_CAPABILITY_IE_, &ielen, in_len-12);
+
+	if (p && ielen > 0) {
+		if (pqospriv->qos_option == 0) {
+			out_len = *pout_len;
+			rtw_set_ie(out_ie+out_len, _VENDOR_SPECIFIC_IE_,
+				   _WMM_IE_Length_, WMM_IE, pout_len);
+
+			pqospriv->qos_option = 1;
+		}
+
+		out_len = *pout_len;
+
+		_rtw_memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap));
+
+		ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH |
+				    IEEE80211_HT_CAP_SGI_20 |
+				    IEEE80211_HT_CAP_SGI_40 |
+				    IEEE80211_HT_CAP_TX_STBC |
+				    IEEE80211_HT_CAP_DSSSCCK40;
+
+		rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset);
+		rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz);
+
+		/*
+		AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+		AMPDU_para [4:2]:Min MPDU Start Spacing
+		*/
+
+		rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+		ht_capie.ampdu_params_info = (max_rx_ampdu_factor&0x03);
+
+		if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
+			ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&(0x07<<2));
+		else
+			ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00);
+
+
+		rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_,
+			   sizeof(struct rtw_ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len);
+
+		phtpriv->ht_option = true;
+
+		p = rtw_get_ie(in_ie+12, _HT_ADD_INFO_IE_, &ielen, in_len-12);
+		if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
+			out_len = *pout_len;
+			rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2 , pout_len);
+		}
+	}
+	return phtpriv->ht_option;
+}
+
+/* the fucntion is > passive_level (in critical_section) */
+void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len)
+{
+	u8 *p, max_ampdu_sz;
+	int len;
+	struct rtw_ieee80211_ht_cap *pht_capie;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv		*phtpriv = &pmlmepriv->htpriv;
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (!phtpriv->ht_option)
+		return;
+
+	if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
+		return;
+
+	DBG_88E("+rtw_update_ht_cap()\n");
+
+	/* maybe needs check if ap supports rx ampdu. */
+	if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) {
+		if (pregistrypriv->wifi_spec == 1)
+			phtpriv->ampdu_enable = false;
+		else
+			phtpriv->ampdu_enable = true;
+	} else if (pregistrypriv->ampdu_enable == 2) {
+		phtpriv->ampdu_enable = true;
+	}
+
+
+	/* check Max Rx A-MPDU Size */
+	len = 0;
+	p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fixed_ie), _HT_CAPABILITY_IE_, &len, ie_len-sizeof(struct ndis_802_11_fixed_ie));
+	if (p && len > 0) {
+		pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
+		max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR);
+		max_ampdu_sz = 1 << (max_ampdu_sz+3); /*  max_ampdu_sz (kbytes); */
+		phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
+	}
+	len = 0;
+	p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fixed_ie), _HT_ADD_INFO_IE_, &len, ie_len-sizeof(struct ndis_802_11_fixed_ie));
+
+	/* update cur_bwmode & cur_ch_offset */
+	if ((pregistrypriv->cbw40_enable) &&
+	    (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & BIT(1)) &&
+	    (pmlmeinfo->HT_info.infos[0] & BIT(2))) {
+		int i;
+		u8	rf_type;
+
+		padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+		/* update the MCS rates */
+		for (i = 0; i < 16; i++) {
+			if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R))
+				pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
+			else
+				pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i];
+		}
+		/* switch to the 40M Hz mode accoring to the AP */
+		pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
+		switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) {
+		case HT_EXTCHNL_OFFSET_UPPER:
+			pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+			break;
+		case HT_EXTCHNL_OFFSET_LOWER:
+			pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+			break;
+		default:
+			pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+			break;
+		}
+	}
+
+	/*  Config SM Power Save setting */
+	pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2;
+	if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+		DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+
+	/*  Config current HT Protection mode. */
+	pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
+}
+
+void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	u8 issued;
+	int priority;
+	struct sta_info *psta = NULL;
+	struct ht_priv	*phtpriv;
+	struct pkt_attrib *pattrib = &pxmitframe->attrib;
+	s32 bmcst = IS_MCAST(pattrib->ra);
+
+	if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100))
+		return;
+
+	priority = pattrib->priority;
+
+	if (pattrib->psta)
+		psta = pattrib->psta;
+	else
+		psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+
+	if (psta == NULL)
+		return;
+
+	phtpriv = &psta->htpriv;
+
+	if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) {
+		issued = (phtpriv->agg_enable_bitmap>>priority)&0x1;
+		issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1;
+
+		if (0 == issued) {
+			DBG_88E("rtw_issue_addbareq_cmd, p=%d\n", priority);
+			psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority);
+			rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra);
+		}
+	}
+}
+
+void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
+{
+	unsigned long irql;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	_rtw_roaming(padapter, tgt_network);
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network)
+{
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	int do_join_r;
+
+	struct wlan_network *pnetwork;
+
+	if (tgt_network != NULL)
+		pnetwork = tgt_network;
+	else
+		pnetwork = &pmlmepriv->cur_network;
+
+	if (0 < pmlmepriv->to_roaming) {
+		DBG_88E("roaming from %s(%pM length:%d\n",
+			pnetwork->network.Ssid.Ssid, pnetwork->network.MacAddress,
+			pnetwork->network.Ssid.SsidLength);
+		memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid));
+
+		pmlmepriv->assoc_by_bssid = false;
+
+		while (1) {
+			do_join_r = rtw_do_join(padapter);
+			if (_SUCCESS == do_join_r) {
+				break;
+			} else {
+				DBG_88E("roaming do_join return %d\n", do_join_r);
+				pmlmepriv->to_roaming--;
+
+				if (0 < pmlmepriv->to_roaming) {
+					continue;
+				} else {
+					DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
+					rtw_indicate_disconnect(padapter);
+					break;
+				}
+			}
+		}
+	}
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
new file mode 100644
index 0000000..8b2ba26
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -0,0 +1,8481 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MLME_EXT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <rtw_mlme_ext.h>
+#include <wlan_bssdef.h>
+#include <mlme_osdep.h>
+#include <recv_osdep.h>
+
+static struct mlme_handler mlme_sta_tbl[] = {
+	{WIFI_ASSOCREQ,		"OnAssocReq",	&OnAssocReq},
+	{WIFI_ASSOCRSP,		"OnAssocRsp",	&OnAssocRsp},
+	{WIFI_REASSOCREQ,	"OnReAssocReq",	&OnAssocReq},
+	{WIFI_REASSOCRSP,	"OnReAssocRsp",	&OnAssocRsp},
+	{WIFI_PROBEREQ,		"OnProbeReq",	&OnProbeReq},
+	{WIFI_PROBERSP,		"OnProbeRsp",		&OnProbeRsp},
+
+	/*----------------------------------------------------------
+					below 2 are reserved
+	-----------------------------------------------------------*/
+	{0,					"DoReserved",		&DoReserved},
+	{0,					"DoReserved",		&DoReserved},
+	{WIFI_BEACON,		"OnBeacon",		&OnBeacon},
+	{WIFI_ATIM,			"OnATIM",		&OnAtim},
+	{WIFI_DISASSOC,		"OnDisassoc",		&OnDisassoc},
+	{WIFI_AUTH,			"OnAuth",		&OnAuthClient},
+	{WIFI_DEAUTH,		"OnDeAuth",		&OnDeAuth},
+	{WIFI_ACTION,		"OnAction",		&OnAction},
+};
+
+static struct action_handler OnAction_tbl[] = {
+	{RTW_WLAN_CATEGORY_SPECTRUM_MGMT,	 "ACTION_SPECTRUM_MGMT", on_action_spct},
+	{RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos},
+	{RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls},
+	{RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back},
+	{RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public},
+	{RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved},
+	{RTW_WLAN_CATEGORY_FT, "ACTION_FT",	&DoReserved},
+	{RTW_WLAN_CATEGORY_HT,	"ACTION_HT",	&OnAction_ht},
+	{RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved},
+	{RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm},
+	{RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p},
+};
+
+
+static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+/**************************************************
+OUI definitions for the vendor specific IE
+***************************************************/
+unsigned char	RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01};
+unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02};
+unsigned char	WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04};
+unsigned char	P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09};
+unsigned char	WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A};
+
+unsigned char	WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+unsigned char	WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+
+unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02};
+unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02};
+
+extern unsigned char REALTEK_96B_IE[];
+
+/********************************************************
+MCS rate definitions
+*********************************************************/
+unsigned char	MCS_rate_2R[16] = {0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+unsigned char	MCS_rate_1R[16] = {0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+/********************************************************
+ChannelPlan definitions
+*********************************************************/
+static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = {
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},		/*  0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},		/*  0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},			/*  0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */
+	{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},	/*  0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */
+	{{10, 11, 12, 13}, 4},					/*  0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */
+	{{}, 0},									/*  0x05, RT_CHANNEL_DOMAIN_2G_NULL */
+};
+
+static struct rt_channel_plan_map	RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
+	/*  0x00 ~ 0x1F , Old Define ===== */
+	{0x02},	/* 0x00, RT_CHANNEL_DOMAIN_FCC */
+	{0x02},	/* 0x01, RT_CHANNEL_DOMAIN_IC */
+	{0x01},	/* 0x02, RT_CHANNEL_DOMAIN_ETSI */
+	{0x01},	/* 0x03, RT_CHANNEL_DOMAIN_SPAIN */
+	{0x01},	/* 0x04, RT_CHANNEL_DOMAIN_FRANCE */
+	{0x03},	/* 0x05, RT_CHANNEL_DOMAIN_MKK */
+	{0x03},	/* 0x06, RT_CHANNEL_DOMAIN_MKK1 */
+	{0x01},	/* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */
+	{0x03},	/* 0x08, RT_CHANNEL_DOMAIN_TELEC */
+	{0x03},	/* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */
+	{0x00},	/* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */
+	{0x02},	/* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */
+	{0x01},	/* 0x0C, RT_CHANNEL_DOMAIN_CHINA */
+	{0x02},	/* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */
+	{0x02},	/* 0x0E, RT_CHANNEL_DOMAIN_KOREA */
+	{0x02},	/* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */
+	{0x01},	/* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
+	{0x02},	/* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
+	{0x01},	/* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+	{0x00},	/* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */
+	{0x02},	/* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
+	{0x00},	/* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
+	{0x00},	/* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
+	{0x03},	/* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+	{0x05},	/* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */
+	{0x02},	/* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */
+	{0x00},	/* 0x1A, */
+	{0x00},	/* 0x1B, */
+	{0x00},	/* 0x1C, */
+	{0x00},	/* 0x1D, */
+	{0x00},	/* 0x1E, */
+	{0x05},	/* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */
+	/*  0x20 ~ 0x7F , New Define ===== */
+	{0x00},	/* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
+	{0x01},	/* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
+	{0x02},	/* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */
+	{0x03},	/* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */
+	{0x04},	/* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */
+	{0x02},	/* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */
+	{0x00},	/* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */
+	{0x03},	/* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */
+	{0x00},	/* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */
+	{0x00},	/* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */
+	{0x00},	/* 0x2A, */
+	{0x00},	/* 0x2B, */
+	{0x00},	/* 0x2C, */
+	{0x00},	/* 0x2D, */
+	{0x00},	/* 0x2E, */
+	{0x00},	/* 0x2F, */
+	{0x00},	/* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */
+	{0x00},	/* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */
+	{0x00},	/* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */
+	{0x00},	/* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */
+	{0x02},	/* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */
+	{0x00},	/* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */
+	{0x00},	/* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */
+	{0x03},	/* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */
+	{0x03},	/* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */
+	{0x02},	/* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */
+	{0x00},	/* 0x3A, */
+	{0x00},	/* 0x3B, */
+	{0x00},	/* 0x3C, */
+	{0x00},	/* 0x3D, */
+	{0x00},	/* 0x3E, */
+	{0x00},	/* 0x3F, */
+	{0x02},	/* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */
+	{0x03},	/* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */
+};
+
+static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the conbination for max channel numbers */
+
+/*
+ * Search the @param channel_num in given @param channel_set
+ * @ch_set: the given channel set
+ * @ch: the given channel number
+ *
+ * return the index of channel_num in channel_set, -1 if not found
+ */
+int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch)
+{
+	int i;
+	for (i = 0; ch_set[i].ChannelNum != 0; i++) {
+		if (ch == ch_set[i].ChannelNum)
+			break;
+	}
+
+	if (i >= ch_set[i].ChannelNum)
+		return -1;
+	return i;
+}
+
+/****************************************************************************
+
+Following are the initialization functions for WiFi MLME
+
+*****************************************************************************/
+
+int init_hw_mlme_ext(struct adapter *padapter)
+{
+	struct	mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+	return _SUCCESS;
+}
+
+static void init_mlme_ext_priv_value(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	unsigned char	mixed_datarate[NumRates] = {
+		_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
+		_9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_,
+		 _48M_RATE_, _54M_RATE_, 0xff
+	};
+	unsigned char	mixed_basicrate[NumRates] = {
+		_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
+		_12M_RATE_, _24M_RATE_, 0xff,
+	};
+
+	ATOMIC_SET(&pmlmeext->event_seq, 0);
+	pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */
+
+	pmlmeext->cur_channel = padapter->registrypriv.channel;
+	pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+	pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pmlmeext->oper_channel = pmlmeext->cur_channel ;
+	pmlmeext->oper_bwmode = pmlmeext->cur_bwmode;
+	pmlmeext->oper_ch_offset = pmlmeext->cur_ch_offset;
+	pmlmeext->retry = 0;
+
+	pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode;
+
+	memcpy(pmlmeext->datarate, mixed_datarate, NumRates);
+	memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates);
+
+	pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
+
+	pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+	pmlmeext->sitesurvey_res.channel_idx = 0;
+	pmlmeext->sitesurvey_res.bss_cnt = 0;
+	pmlmeext->scan_abort = false;
+
+	pmlmeinfo->state = WIFI_FW_NULL_STATE;
+	pmlmeinfo->reauth_count = 0;
+	pmlmeinfo->reassoc_count = 0;
+	pmlmeinfo->link_count = 0;
+	pmlmeinfo->auth_seq = 0;
+	pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
+	pmlmeinfo->key_index = 0;
+	pmlmeinfo->iv = 0;
+
+	pmlmeinfo->enc_algo = _NO_PRIVACY_;
+	pmlmeinfo->authModeToggle = 0;
+
+	_rtw_memset(pmlmeinfo->chg_txt, 0, 128);
+
+	pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+	pmlmeinfo->preamble_mode = PREAMBLE_AUTO;
+
+	pmlmeinfo->dialogToken = 0;
+
+	pmlmeext->action_public_rxseq = 0xffff;
+	pmlmeext->action_public_dialog_token = 0xff;
+}
+
+static int has_channel(struct rt_channel_info *channel_set,
+					   u8 chanset_size,
+					   u8 chan) {
+	int i;
+
+	for (i = 0; i < chanset_size; i++) {
+		if (channel_set[i].ChannelNum == chan)
+			return 1;
+	}
+	return 0;
+}
+
+static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set,
+							  u8 chanset_size,
+							  struct p2p_channels *channel_list) {
+	struct p2p_oper_class_map op_class[] = {
+		{ IEEE80211G,  81,   1,  13,  1, BW20 },
+		{ IEEE80211G,  82,  14,  14,  1, BW20 },
+		{ -1, 0, 0, 0, 0, BW20 }
+	};
+
+	int cla, op;
+
+	cla = 0;
+
+	for (op = 0; op_class[op].op_class; op++) {
+		u8 ch;
+		struct p2p_oper_class_map *o = &op_class[op];
+		struct p2p_reg_class *reg = NULL;
+
+		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+			if (!has_channel(channel_set, chanset_size, ch)) {
+				continue;
+			}
+
+			if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
+				continue;
+
+			if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) &&
+			    ((BW40MINUS == o->bw) || (BW40PLUS == o->bw)))
+				continue;
+
+			if (reg == NULL) {
+				reg = &channel_list->reg_class[cla];
+				cla++;
+				reg->reg_class = o->op_class;
+				reg->channels = 0;
+			}
+			reg->channel[reg->channels] = ch;
+			reg->channels++;
+		}
+	}
+	channel_list->reg_classes = cla;
+}
+
+static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set)
+{
+	u8 index, chanset_size = 0;
+	u8 b2_4GBand = false;
+	u8 Index2G = 0;
+
+	_rtw_memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM);
+
+	if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) {
+		DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan);
+		return chanset_size;
+	}
+
+	if (padapter->registrypriv.wireless_mode & WIRELESS_11G) {
+		b2_4GBand = true;
+		if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan)
+			Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G;
+		else
+			Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G;
+	}
+
+	if (b2_4GBand) {
+		for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) {
+			channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index];
+
+			if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||/* Channel 1~11 is active, and 12~14 is passive */
+			    (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)) {
+				if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11)
+					channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+				else if ((channel_set[chanset_size].ChannelNum  >= 12 && channel_set[chanset_size].ChannelNum  <= 14))
+					channel_set[chanset_size].ScanType  = SCAN_PASSIVE;
+			} else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan ||
+				   RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {/*  channel 12~13, passive scan */
+				if (channel_set[chanset_size].ChannelNum <= 11)
+					channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+				else
+					channel_set[chanset_size].ScanType = SCAN_PASSIVE;
+			} else {
+				channel_set[chanset_size].ScanType = SCAN_ACTIVE;
+			}
+
+			chanset_size++;
+		}
+	}
+	return chanset_size;
+}
+
+int	init_mlme_ext_priv(struct adapter *padapter)
+{
+	int	res = _SUCCESS;
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	pmlmeext->padapter = padapter;
+
+	init_mlme_ext_priv_value(padapter);
+	pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq;
+
+	init_mlme_ext_timer(padapter);
+
+#ifdef CONFIG_88EU_AP_MODE
+	init_mlme_ap_info(padapter);
+#endif
+
+	pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set);
+	init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list);
+
+	pmlmeext->chan_scan_time = SURVEY_TO;
+	pmlmeext->mlmeext_init = true;
+
+
+	pmlmeext->active_keep_alive_check = true;
+
+	return res;
+}
+
+void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext)
+{
+	struct adapter *padapter = pmlmeext->padapter;
+
+	if (!padapter)
+		return;
+
+	if (padapter->bDriverStopped) {
+		_cancel_timer_ex(&pmlmeext->survey_timer);
+		_cancel_timer_ex(&pmlmeext->link_timer);
+		/* _cancel_timer_ex(&pmlmeext->ADDBA_timer); */
+	}
+}
+
+static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame)
+{
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+
+	  if (ptable->func) {
+	 /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
+		if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
+		    !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+			return;
+		ptable->func(padapter, precv_frame);
+	}
+}
+
+void mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	int index;
+	struct mlme_handler *ptable;
+#ifdef CONFIG_88EU_AP_MODE
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif /* CONFIG_88EU_AP_MODE */
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe));
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+		 ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n",
+		  GetFrameType(pframe), GetFrameSubType(pframe)));
+
+	if (GetFrameType(pframe) != WIFI_MGT_TYPE) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("mgt_dispatcher: type(0x%x) error!\n", GetFrameType(pframe)));
+		return;
+	}
+
+	/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
+	if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) &&
+	    !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN))
+		return;
+
+	ptable = mlme_sta_tbl;
+
+	index = GetFrameSubType(pframe) >> 4;
+
+	if (index > 13) {
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Currently we do not support reserved sub-fr-type=%d\n", index));
+		return;
+	}
+	ptable += index;
+
+	if (psta != NULL) {
+		if (GetRetry(pframe)) {
+			if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) {
+				/* drop the duplicate management frame */
+				DBG_88E("Drop duplicate management frame with seq_num=%d.\n", precv_frame->u.hdr.attrib.seq_num);
+				return;
+			}
+		}
+		psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num;
+	}
+
+#ifdef CONFIG_88EU_AP_MODE
+	switch (GetFrameSubType(pframe)) {
+	case WIFI_AUTH:
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+			ptable->func = &OnAuth;
+		else
+			ptable->func = &OnAuthClient;
+		/* fall through */
+	case WIFI_ASSOCREQ:
+	case WIFI_REASSOCREQ:
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		break;
+	case WIFI_PROBEREQ:
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+			_mgt_dispatcher(padapter, ptable, precv_frame);
+		else
+			_mgt_dispatcher(padapter, ptable, precv_frame);
+		break;
+	case WIFI_BEACON:
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		break;
+	case WIFI_ACTION:
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		break;
+	default:
+		_mgt_dispatcher(padapter, ptable, precv_frame);
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+			rtw_hostapd_mlme_rx(padapter, precv_frame);
+		break;
+	}
+#else
+	_mgt_dispatcher(padapter, ptable, precv_frame);
+#endif
+}
+
+#ifdef CONFIG_88EU_P2P
+static u32 p2p_listen_state_process(struct adapter *padapter, unsigned char *da)
+{
+	bool response = true;
+
+	/*	do nothing if the device name is empty */
+	if (!padapter->wdinfo.device_name_len)
+		response = false;
+
+	if (response)
+		issue_probersp_p2p(padapter, da);
+
+	return _SUCCESS;
+}
+#endif /* CONFIG_88EU_P2P */
+
+
+/****************************************************************************
+
+Following are the callback functions for each subtype of the management frames
+
+*****************************************************************************/
+
+unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int	ielen;
+	unsigned char	*p;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	u8 is_valid_p2p_probereq = false;
+
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8 wifi_test_chk_rate = 1;
+
+	if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
+	    !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) &&
+	    !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) &&
+	    !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) &&
+	    !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) {
+		/*	mcs_rate = 0 -> CCK 1M rate */
+		/*	mcs_rate = 1 -> CCK 2M rate */
+		/*	mcs_rate = 2 -> CCK 5.5M rate */
+		/*	mcs_rate = 3 -> CCK 11M rate */
+		/*	In the P2P mode, the driver should not support the CCK rate */
+
+		/*	Commented by Kurt 2012/10/16 */
+		/*	IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client */
+		if (wifi_test_chk_rate == 1) {
+			is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len);
+			if (is_valid_p2p_probereq) {
+				if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+					/*  FIXME */
+					report_survey_event(padapter, precv_frame);
+					p2p_listen_state_process(padapter,  get_sa(pframe));
+
+					return _SUCCESS;
+				}
+
+				if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+					goto _continue;
+			}
+		}
+	}
+
+_continue:
+#endif /* CONFIG_88EU_P2P */
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+		return _SUCCESS;
+
+	if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
+	    !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE))
+		return _SUCCESS;
+
+	p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen,
+			len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
+
+	/* check (wildcard) SSID */
+	if (p != NULL) {
+		if (is_valid_p2p_probereq)
+			goto _issue_probersp;
+
+		if ((ielen != 0 && !_rtw_memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) ||
+		    (ielen == 0 && pmlmeinfo->hidden_ssid_mode))
+			return _SUCCESS;
+
+_issue_probersp:
+
+		if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+		    pmlmepriv->cur_network.join_res)
+			issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq);
+	}
+	return _SUCCESS;
+}
+
+unsigned int OnProbeRsp(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &padapter->wdinfo;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+#endif
+
+#ifdef CONFIG_88EU_P2P
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+		if (pwdinfo->tx_prov_disc_info.benable) {
+			if (_rtw_memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+				if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+					pwdinfo->tx_prov_disc_info.benable = false;
+					issue_p2p_provision_request(padapter,
+								    pwdinfo->tx_prov_disc_info.ssid.Ssid,
+								    pwdinfo->tx_prov_disc_info.ssid.SsidLength,
+								    pwdinfo->tx_prov_disc_info.peerDevAddr);
+				} else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+					pwdinfo->tx_prov_disc_info.benable = false;
+					issue_p2p_provision_request(padapter, NULL, 0,
+								    pwdinfo->tx_prov_disc_info.peerDevAddr);
+				}
+			}
+		}
+		return _SUCCESS;
+	} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+		if (pwdinfo->nego_req_info.benable) {
+			DBG_88E("[%s] P2P State is GONEGO ING!\n", __func__);
+			if (_rtw_memcmp(pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+				pwdinfo->nego_req_info.benable = false;
+				issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr);
+			}
+		}
+	} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
+		if (pwdinfo->invitereq_info.benable) {
+			DBG_88E("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__);
+			if (_rtw_memcmp(pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN)) {
+				pwdinfo->invitereq_info.benable = false;
+				issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr);
+			}
+		}
+	}
+#endif
+
+
+	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+		report_survey_event(padapter, precv_frame);
+		return _SUCCESS;
+	}
+
+	return _SUCCESS;
+}
+
+unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	int cam_idx;
+	struct sta_info	*psta;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct sta_priv	*pstapriv = &padapter->stapriv;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	struct wlan_bssid_ex *pbss;
+	int ret = _SUCCESS;
+
+	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+		report_survey_event(padapter, precv_frame);
+		return _SUCCESS;
+	}
+
+	if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
+		if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
+			/* we should update current network before auth, or some IE is wrong */
+			pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex));
+			if (pbss) {
+				if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) {
+					update_network(&(pmlmepriv->cur_network.network), pbss, padapter, true);
+					rtw_get_bcn_info(&(pmlmepriv->cur_network));
+				}
+				kfree(pbss);
+			}
+
+			/* check the vendor of the assoc AP */
+			pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe+sizeof(struct rtw_ieee80211_hdr_3addr), len-sizeof(struct rtw_ieee80211_hdr_3addr));
+
+			/* update TSF Value */
+			update_TSF(pmlmeext, pframe, len);
+
+			/* start auth */
+			start_clnt_auth(padapter);
+
+			return _SUCCESS;
+		}
+
+		if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
+			psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+			if (psta != NULL) {
+				ret = rtw_check_bcn_info(padapter, pframe, len);
+				if (!ret) {
+						DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n ");
+						receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 65535);
+						return _SUCCESS;
+				}
+				/* update WMM, ERP in the beacon */
+				/* todo: the timer is used instead of the number of the beacon received */
+				if ((sta_rx_pkts(psta) & 0xf) == 0)
+					update_beacon_info(padapter, pframe, len, psta);
+				process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN));
+			}
+		} else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+			psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+			if (psta != NULL) {
+				/* update WMM, ERP in the beacon */
+				/* todo: the timer is used instead of the number of the beacon received */
+				if ((sta_rx_pkts(psta) & 0xf) == 0)
+					update_beacon_info(padapter, pframe, len, psta);
+			} else {
+				/* allocate a new CAM entry for IBSS station */
+				cam_idx = allocate_fw_sta_entry(padapter);
+				if (cam_idx == NUM_STA)
+					goto _END_ONBEACON_;
+
+				/* get supported rate */
+				if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) {
+					pmlmeinfo->FW_sta_info[cam_idx].status = 0;
+					goto _END_ONBEACON_;
+				}
+
+				/* update TSF Value */
+				update_TSF(pmlmeext, pframe, len);
+
+				/* report sta add event */
+				report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx);
+			}
+		}
+	}
+
+_END_ONBEACON_:
+
+	return _SUCCESS;
+}
+
+unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	unsigned long irqL;
+	unsigned int	auth_mode, ie_len;
+	u16 seq;
+	unsigned char	*sa, *p;
+	u16 algorithm;
+	int	status;
+	static struct sta_info stat;
+	struct	sta_info	*pstat = NULL;
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		return _FAIL;
+
+	DBG_88E("+OnAuth\n");
+
+	sa = GetAddr2Ptr(pframe);
+
+	auth_mode = psecuritypriv->dot11AuthAlgrthm;
+	seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2));
+	algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN));
+
+	DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq);
+
+	if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ &&
+	    psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)
+		auth_mode = 0;
+
+	if ((algorithm > 0 && auth_mode == 0) ||	/*  rx a shared-key auth but shared not enabled */
+	    (algorithm == 0 && auth_mode == 1)) {	/*  rx a open-system auth but shared-key is enabled */
+		DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n",
+			algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
+
+		status = _STATS_NO_SUPP_ALG_;
+
+		goto auth_fail;
+	}
+
+	if (!rtw_access_ctrl(padapter, sa)) {
+		status = _STATS_UNABLE_HANDLE_STA_;
+		goto auth_fail;
+	}
+
+	pstat = rtw_get_stainfo(pstapriv, sa);
+	if (pstat == NULL) {
+		/*  allocate a new one */
+		DBG_88E("going to alloc stainfo for sa=%pM\n", sa);
+		pstat = rtw_alloc_stainfo(pstapriv, sa);
+		if (pstat == NULL) {
+			DBG_88E(" Exceed the upper limit of supported clients...\n");
+			status = _STATS_UNABLE_HANDLE_STA_;
+			goto auth_fail;
+		}
+
+		pstat->state = WIFI_FW_AUTH_NULL;
+		pstat->auth_seq = 0;
+	} else {
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		if (!rtw_is_list_empty(&pstat->asoc_list)) {
+			rtw_list_delete(&pstat->asoc_list);
+			pstapriv->asoc_list_cnt--;
+		}
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+		if (seq == 1) {
+			/* TODO: STA re_auth and auth timeout */
+		}
+	}
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	if (rtw_is_list_empty(&pstat->auth_list)) {
+		rtw_list_insert_tail(&pstat->auth_list, &pstapriv->auth_list);
+		pstapriv->auth_list_cnt++;
+	}
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+	if (pstat->auth_seq == 0)
+		pstat->expire_to = pstapriv->auth_to;
+
+	if ((pstat->auth_seq + 1) != seq) {
+		DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
+			seq, pstat->auth_seq+1);
+		status = _STATS_OUT_OF_AUTH_SEQ_;
+		goto auth_fail;
+	}
+
+	if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) {
+		if (seq == 1) {
+			pstat->state &= ~WIFI_FW_AUTH_NULL;
+			pstat->state |= WIFI_FW_AUTH_SUCCESS;
+			pstat->expire_to = pstapriv->assoc_to;
+			pstat->authalg = algorithm;
+		} else {
+			DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
+				seq, pstat->auth_seq+1);
+			status = _STATS_OUT_OF_AUTH_SEQ_;
+			goto auth_fail;
+		}
+	} else { /*  shared system or auto authentication */
+		if (seq == 1) {
+			/* prepare for the challenging txt... */
+
+			pstat->state &= ~WIFI_FW_AUTH_NULL;
+			pstat->state |= WIFI_FW_AUTH_STATE;
+			pstat->authalg = algorithm;
+			pstat->auth_seq = 2;
+		} else if (seq == 3) {
+			/* checking for challenging txt... */
+			DBG_88E("checking for challenging txt...\n");
+
+			p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len,
+					len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4);
+
+			if ((p == NULL) || (ie_len <= 0)) {
+				DBG_88E("auth rejected because challenge failure!(1)\n");
+				status = _STATS_CHALLENGE_FAIL_;
+				goto auth_fail;
+			}
+
+			if (_rtw_memcmp((void *)(p + 2), pstat->chg_txt, 128)) {
+				pstat->state &= (~WIFI_FW_AUTH_STATE);
+				pstat->state |= WIFI_FW_AUTH_SUCCESS;
+				/*  challenging txt is correct... */
+				pstat->expire_to =  pstapriv->assoc_to;
+			} else {
+				DBG_88E("auth rejected because challenge failure!\n");
+				status = _STATS_CHALLENGE_FAIL_;
+				goto auth_fail;
+			}
+		} else {
+			DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n",
+				seq, pstat->auth_seq+1);
+			status = _STATS_OUT_OF_AUTH_SEQ_;
+			goto auth_fail;
+		}
+	}
+
+	/*  Now, we are going to issue_auth... */
+	pstat->auth_seq = seq + 1;
+
+#ifdef CONFIG_88EU_AP_MODE
+	issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_));
+#endif
+
+	if (pstat->state & WIFI_FW_AUTH_SUCCESS)
+		pstat->auth_seq = 0;
+
+	return _SUCCESS;
+
+auth_fail:
+
+	if (pstat)
+		rtw_free_stainfo(padapter , pstat);
+
+	pstat = &stat;
+	_rtw_memset((char *)pstat, '\0', sizeof(stat));
+	pstat->auth_seq = 2;
+	memcpy(pstat->hwaddr, sa, 6);
+
+#ifdef CONFIG_88EU_AP_MODE
+	issue_auth(padapter, pstat, (unsigned short)status);
+#endif
+
+#endif
+	return _FAIL;
+}
+
+unsigned int OnAuthClient(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int	seq, len, status, offset;
+	unsigned char	*p;
+	unsigned int	go2asoc = 0;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint pkt_len = precv_frame->u.hdr.len;
+
+	DBG_88E("%s\n", __func__);
+
+	/* check A1 matches or not */
+	if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
+		return _SUCCESS;
+
+	if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE))
+		return _SUCCESS;
+
+	offset = (GetPrivacy(pframe)) ? 4 : 0;
+
+	seq	= le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 2));
+	status	= le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4));
+
+	if (status != 0) {
+		DBG_88E("clnt auth fail, status: %d\n", status);
+		if (status == 13) { /*  pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */
+			if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+				pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
+			else
+				pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared;
+		}
+
+		set_link_timer(pmlmeext, 1);
+		goto authclnt_fail;
+	}
+
+	if (seq == 2) {
+		if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) {
+			 /*  legendary shared system */
+			p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len,
+				pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_);
+
+			if (p == NULL)
+				goto authclnt_fail;
+
+			memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len);
+			pmlmeinfo->auth_seq = 3;
+			issue_auth(padapter, NULL, 0);
+			set_link_timer(pmlmeext, REAUTH_TO);
+
+			return _SUCCESS;
+		} else {
+			/*  open system */
+			go2asoc = 1;
+		}
+	} else if (seq == 4) {
+		if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+			go2asoc = 1;
+		else
+			goto authclnt_fail;
+	} else {
+		/*  this is also illegal */
+		goto authclnt_fail;
+	}
+
+	if (go2asoc) {
+		DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n");
+		start_clnt_assoc(padapter);
+		return _SUCCESS;
+	}
+authclnt_fail:
+	return _FAIL;
+}
+
+unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	unsigned long irqL;
+	u16 capab_info;
+	struct rtw_ieee802_11_elems elems;
+	struct sta_info	*pstat;
+	unsigned char		reassoc, *p, *pos, *wpa_ie;
+	unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+	int		i, ie_len, wpa_ie_len, left;
+	unsigned char		supportRate[16];
+	int					supportRateNum;
+	unsigned short		status = _STATS_SUCCESSFUL_;
+	unsigned short		frame_type, ie_offset = 0;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint pkt_len = precv_frame->u.hdr.len;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8 p2p_status_code = P2P_STATUS_SUCCESS;
+	u8 *p2pie;
+	u32 p2pielen = 0;
+#endif /* CONFIG_88EU_P2P */
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		return _FAIL;
+
+	frame_type = GetFrameSubType(pframe);
+	if (frame_type == WIFI_ASSOCREQ) {
+		reassoc = 0;
+		ie_offset = _ASOCREQ_IE_OFFSET_;
+	} else { /*  WIFI_REASSOCREQ */
+		reassoc = 1;
+		ie_offset = _REASOCREQ_IE_OFFSET_;
+	}
+
+
+	if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) {
+		DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+		       "\n", reassoc, (unsigned long)pkt_len);
+		return _FAIL;
+	}
+
+	pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+	if (pstat == (struct sta_info *)NULL) {
+		status = _RSON_CLS2_;
+		goto asoc_class2_error;
+	}
+
+	capab_info = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN);
+
+	left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset);
+	pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset);
+
+
+	DBG_88E("%s\n", __func__);
+
+	/*  check if this stat has been successfully authenticated/assocated */
+	if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) {
+		if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) {
+			status = _RSON_CLS2_;
+			goto asoc_class2_error;
+		} else {
+			pstat->state &= (~WIFI_FW_ASSOC_SUCCESS);
+			pstat->state |= WIFI_FW_ASSOC_STATE;
+		}
+	} else {
+		pstat->state &= (~WIFI_FW_AUTH_SUCCESS);
+		pstat->state |= WIFI_FW_ASSOC_STATE;
+	}
+	pstat->capability = capab_info;
+	/* now parse all ieee802_11 ie to point to elems */
+	if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed ||
+	    !elems.ssid) {
+		DBG_88E("STA %pM sent invalid association request\n",
+			pstat->hwaddr);
+		status = _STATS_FAILURE_;
+		goto OnAssocReqFail;
+	}
+
+
+	/*  now we should check all the fields... */
+	/*  checking SSID */
+	p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len,
+		pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+	if (p == NULL)
+		status = _STATS_FAILURE_;
+
+	if (ie_len == 0) { /*  broadcast ssid, however it is not allowed in assocreq */
+		status = _STATS_FAILURE_;
+	} else {
+		/*  check if ssid match */
+		if (!_rtw_memcmp((void *)(p+2), cur->Ssid.Ssid, cur->Ssid.SsidLength))
+			status = _STATS_FAILURE_;
+
+		if (ie_len != cur->Ssid.SsidLength)
+			status = _STATS_FAILURE_;
+	}
+
+	if (_STATS_SUCCESSFUL_ != status)
+		goto OnAssocReqFail;
+
+	/*  check if the supported rate is ok */
+	p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+	if (p == NULL) {
+		DBG_88E("Rx a sta assoc-req which supported rate is empty!\n");
+		/*  use our own rate set as statoin used */
+		/* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */
+		/* supportRateNum = AP_BSSRATE_LEN; */
+
+		status = _STATS_FAILURE_;
+		goto OnAssocReqFail;
+	} else {
+		memcpy(supportRate, p+2, ie_len);
+		supportRateNum = ie_len;
+
+		p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_ , &ie_len,
+				pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+		if (p !=  NULL) {
+			if (supportRateNum <= sizeof(supportRate)) {
+				memcpy(supportRate+supportRateNum, p+2, ie_len);
+				supportRateNum += ie_len;
+			}
+		}
+	}
+
+	/* todo: mask supportRate between AP & STA -> move to update raid */
+	/* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */
+
+	/* update station supportRate */
+	pstat->bssratelen = supportRateNum;
+	memcpy(pstat->bssrateset, supportRate, supportRateNum);
+	UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen);
+
+	/* check RSN/WPA/WPS */
+	pstat->dot8021xalg = 0;
+	pstat->wpa_psk = 0;
+	pstat->wpa_group_cipher = 0;
+	pstat->wpa2_group_cipher = 0;
+	pstat->wpa_pairwise_cipher = 0;
+	pstat->wpa2_pairwise_cipher = 0;
+	_rtw_memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie));
+	if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) {
+		int group_cipher = 0, pairwise_cipher = 0;
+
+		wpa_ie = elems.rsn_ie;
+		wpa_ie_len = elems.rsn_ie_len;
+
+		if (rtw_parse_wpa2_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			pstat->dot8021xalg = 1;/* psk,  todo:802.1x */
+			pstat->wpa_psk |= BIT(1);
+
+			pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher;
+			pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher;
+
+			if (!pstat->wpa2_group_cipher)
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+
+			if (!pstat->wpa2_pairwise_cipher)
+				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		} else {
+			status = WLAN_STATUS_INVALID_IE;
+		}
+	} else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) {
+		int group_cipher = 0, pairwise_cipher = 0;
+
+		wpa_ie = elems.wpa_ie;
+		wpa_ie_len = elems.wpa_ie_len;
+
+		if (rtw_parse_wpa_ie(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			pstat->dot8021xalg = 1;/* psk,  todo:802.1x */
+			pstat->wpa_psk |= BIT(0);
+
+			pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher;
+			pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher;
+
+			if (!pstat->wpa_group_cipher)
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+
+			if (!pstat->wpa_pairwise_cipher)
+				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		} else {
+			status = WLAN_STATUS_INVALID_IE;
+		}
+	} else {
+		wpa_ie = NULL;
+		wpa_ie_len = 0;
+	}
+
+	if (_STATS_SUCCESSFUL_ != status)
+		goto OnAssocReqFail;
+
+	pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	if (wpa_ie == NULL) {
+		if (elems.wps_ie) {
+			DBG_88E("STA included WPS IE in "
+				   "(Re)Association Request - assume WPS is "
+				   "used\n");
+			pstat->flags |= WLAN_STA_WPS;
+			/* wpabuf_free(sta->wps_ie); */
+			/* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */
+			/*				elems.wps_ie_len - 4); */
+		} else {
+			DBG_88E("STA did not include WPA/RSN IE "
+				   "in (Re)Association Request - possible WPS "
+				   "use\n");
+			pstat->flags |= WLAN_STA_MAYBE_WPS;
+		}
+
+
+		/*  AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */
+		/*  that the selected registrar of AP is _FLASE */
+		if ((psecuritypriv->wpa_psk > 0) && (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) {
+			if (pmlmepriv->wps_beacon_ie) {
+				u8 selected_registrar = 0;
+
+				rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL);
+
+				if (!selected_registrar) {
+					DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n");
+
+					status = _STATS_UNABLE_HANDLE_STA_;
+
+					goto OnAssocReqFail;
+				}
+			}
+		}
+	} else {
+		int copy_len;
+
+		if (psecuritypriv->wpa_psk == 0) {
+			DBG_88E("STA %pM: WPA/RSN IE in association "
+			"request, but AP don't support WPA/RSN\n", pstat->hwaddr);
+
+			status = WLAN_STATUS_INVALID_IE;
+
+			goto OnAssocReqFail;
+		}
+
+		if (elems.wps_ie) {
+			DBG_88E("STA included WPS IE in "
+				   "(Re)Association Request - WPS is "
+				   "used\n");
+			pstat->flags |= WLAN_STA_WPS;
+			copy_len = 0;
+		} else {
+			copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len+2);
+		}
+		if (copy_len > 0)
+			memcpy(pstat->wpa_ie, wpa_ie-2, copy_len);
+	}
+	/*  check if there is WMM IE & support WWM-PS */
+	pstat->flags &= ~WLAN_STA_WME;
+	pstat->qos_option = 0;
+	pstat->qos_info = 0;
+	pstat->has_legacy_ac = true;
+	pstat->uapsd_vo = 0;
+	pstat->uapsd_vi = 0;
+	pstat->uapsd_be = 0;
+	pstat->uapsd_bk = 0;
+	if (pmlmepriv->qospriv.qos_option) {
+		p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0;
+		for (;;) {
+			p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset);
+			if (p != NULL) {
+				if (_rtw_memcmp(p+2, WMM_IE, 6)) {
+					pstat->flags |= WLAN_STA_WME;
+
+					pstat->qos_option = 1;
+					pstat->qos_info = *(p+8);
+
+					pstat->max_sp_len = (pstat->qos_info>>5)&0x3;
+
+					if ((pstat->qos_info&0xf) != 0xf)
+						pstat->has_legacy_ac = true;
+					else
+						pstat->has_legacy_ac = false;
+
+					if (pstat->qos_info&0xf) {
+						if (pstat->qos_info&BIT(0))
+							pstat->uapsd_vo = BIT(0)|BIT(1);
+						else
+							pstat->uapsd_vo = 0;
+
+						if (pstat->qos_info&BIT(1))
+							pstat->uapsd_vi = BIT(0)|BIT(1);
+						else
+							pstat->uapsd_vi = 0;
+
+						if (pstat->qos_info&BIT(2))
+							pstat->uapsd_bk = BIT(0)|BIT(1);
+						else
+							pstat->uapsd_bk = 0;
+
+						if (pstat->qos_info&BIT(3))
+							pstat->uapsd_be = BIT(0)|BIT(1);
+						else
+							pstat->uapsd_be = 0;
+					}
+					break;
+				}
+			} else {
+				break;
+			}
+			p = p + ie_len + 2;
+		}
+	}
+
+	/* save HT capabilities in the sta object */
+	_rtw_memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap));
+	if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) {
+		pstat->flags |= WLAN_STA_HT;
+
+		pstat->flags |= WLAN_STA_WME;
+
+		memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap));
+	} else {
+		pstat->flags &= ~WLAN_STA_HT;
+	}
+	if ((!pmlmepriv->htpriv.ht_option) && (pstat->flags&WLAN_STA_HT)) {
+		status = _STATS_FAILURE_;
+		goto OnAssocReqFail;
+	}
+
+	if ((pstat->flags & WLAN_STA_HT) &&
+	    ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) ||
+	    (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) {
+		DBG_88E("HT: %pM tried to "
+			"use TKIP with HT association\n", pstat->hwaddr);
+
+		/* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */
+		/* goto OnAssocReqFail; */
+	}
+
+	pstat->flags |= WLAN_STA_NONERP;
+	for (i = 0; i < pstat->bssratelen; i++) {
+		if ((pstat->bssrateset[i] & 0x7f) > 22) {
+			pstat->flags &= ~WLAN_STA_NONERP;
+			break;
+		}
+	}
+
+	if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		pstat->flags |= WLAN_STA_SHORT_PREAMBLE;
+	else
+		pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+
+
+	if (status != _STATS_SUCCESSFUL_)
+		goto OnAssocReqFail;
+
+#ifdef CONFIG_88EU_P2P
+	pstat->is_p2p_device = false;
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , NULL, &p2pielen);
+		if (p2pie) {
+			pstat->is_p2p_device = true;
+			p2p_status_code = (u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat);
+			if (p2p_status_code > 0) {
+				pstat->p2p_status_code = p2p_status_code;
+				status = _STATS_CAP_FAIL_;
+				goto OnAssocReqFail;
+			}
+		}
+	}
+	pstat->p2p_status_code = p2p_status_code;
+#endif /* CONFIG_88EU_P2P */
+
+	/* TODO: identify_proprietary_vendor_ie(); */
+	/*  Realtek proprietary IE */
+	/*  identify if this is Broadcom sta */
+	/*  identify if this is ralink sta */
+	/*  Customer proprietary IE */
+
+	/* get a unique AID */
+	if (pstat->aid > 0) {
+		DBG_88E("  old AID %d\n", pstat->aid);
+	} else {
+		for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++)
+			if (pstapriv->sta_aid[pstat->aid - 1] == NULL)
+				break;
+
+		/* if (pstat->aid > NUM_STA) { */
+		if (pstat->aid > pstapriv->max_num_sta) {
+			pstat->aid = 0;
+
+			DBG_88E("  no room for more AIDs\n");
+
+			status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+			goto OnAssocReqFail;
+		} else {
+			pstapriv->sta_aid[pstat->aid - 1] = pstat;
+			DBG_88E("allocate new AID=(%d)\n", pstat->aid);
+		}
+	}
+
+	pstat->state &= (~WIFI_FW_ASSOC_STATE);
+	pstat->state |= WIFI_FW_ASSOC_SUCCESS;
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irqL);
+	if (!rtw_is_list_empty(&pstat->auth_list)) {
+		rtw_list_delete(&pstat->auth_list);
+		pstapriv->auth_list_cnt--;
+	}
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irqL);
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	if (rtw_is_list_empty(&pstat->asoc_list)) {
+		pstat->expire_to = pstapriv->expire_to;
+		rtw_list_insert_tail(&pstat->asoc_list, &pstapriv->asoc_list);
+		pstapriv->asoc_list_cnt++;
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	/*  now the station is qualified to join our BSS... */
+	if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) {
+#ifdef CONFIG_88EU_AP_MODE
+		/* 1 bss_cap_update & sta_info_update */
+		bss_cap_update_on_sta_join(padapter, pstat);
+		sta_info_update(padapter, pstat);
+
+		/* issue assoc rsp before notify station join event. */
+		if (frame_type == WIFI_ASSOCREQ)
+			issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+		else
+			issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+
+		/* 2 - report to upper layer */
+		DBG_88E("indicate_sta_join_event to upper layer - hostapd\n");
+		rtw_indicate_sta_assoc_event(padapter, pstat);
+
+		/* 3-(1) report sta add event */
+		report_add_sta_event(padapter, pstat->hwaddr, pstat->aid);
+#endif
+	}
+
+	return _SUCCESS;
+
+asoc_class2_error:
+
+#ifdef CONFIG_88EU_AP_MODE
+	issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status);
+#endif
+
+	return _FAIL;
+
+OnAssocReqFail:
+
+
+#ifdef CONFIG_88EU_AP_MODE
+	pstat->aid = 0;
+	if (frame_type == WIFI_ASSOCREQ)
+		issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP);
+	else
+		issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP);
+#endif
+
+
+#endif /* CONFIG_88EU_AP_MODE */
+
+	return _FAIL;
+}
+
+unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	uint i;
+	int res;
+	unsigned short	status;
+	struct ndis_802_11_var_ie *pIE;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	/* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint pkt_len = precv_frame->u.hdr.len;
+
+	DBG_88E("%s\n", __func__);
+
+	/* check A1 matches or not */
+	if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), get_da(pframe), ETH_ALEN))
+		return _SUCCESS;
+
+	if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)))
+		return _SUCCESS;
+
+	if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
+		return _SUCCESS;
+
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	/* status */
+	status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2));
+	if (status > 0) {
+		DBG_88E("assoc reject, status code: %d\n", status);
+		pmlmeinfo->state = WIFI_FW_NULL_STATE;
+		res = -4;
+		goto report_assoc_result;
+	}
+
+	/* get capabilities */
+	pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
+
+	/* set slot time */
+	pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20;
+
+	/* AID */
+	pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4))&0x3fff);
+	res = pmlmeinfo->aid;
+
+	/* following are moved to join event callback function */
+	/* to handle HT, WMM, rate adaptive, update MAC reg */
+	/* for not to handle the synchronous IO in the tasklet */
+	for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) {
+		pIE = (struct ndis_802_11_var_ie *)(pframe + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_:
+			if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6))	/* WMM */
+				WMM_param_handler(padapter, pIE);
+			break;
+		case _HT_CAPABILITY_IE_:	/* HT caps */
+			HT_caps_handler(padapter, pIE);
+			break;
+		case _HT_EXTRA_INFO_IE_:	/* HT info */
+			HT_info_handler(padapter, pIE);
+			break;
+		case _ERPINFO_IE_:
+			ERP_IE_handler(padapter, pIE);
+		default:
+			break;
+		}
+
+		i += (pIE->Length + 2);
+	}
+
+	pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE);
+	pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+
+	/* Update Basic Rate Table for spec, 2010-12-28 , by thomas */
+	UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates);
+
+report_assoc_result:
+	if (res > 0) {
+		rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len);
+	} else {
+		rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
+	}
+
+	report_join_res(padapter, res);
+
+	return _SUCCESS;
+}
+
+unsigned int OnDeAuth(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned short	reason;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+	/* check A3 */
+	if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+		return _SUCCESS;
+
+#ifdef CONFIG_88EU_P2P
+	if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+		_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+		_set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
+
+	DBG_88E("%s Reason code(%d)\n", __func__, reason);
+
+#ifdef CONFIG_88EU_AP_MODE
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		unsigned long irqL;
+		struct sta_info *psta;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n",
+			      reason, GetAddr2Ptr(pframe));
+
+		psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+		if (psta) {
+			u8 updated = 0;
+
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (!rtw_is_list_empty(&psta->asoc_list)) {
+				rtw_list_delete(&psta->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				updated = ap_free_sta(padapter, psta, false, reason);
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+			associated_clients_update(padapter, updated);
+		}
+
+
+		return _SUCCESS;
+	} else
+#endif
+	{
+		DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM\n",
+			      reason, GetAddr3Ptr(pframe));
+
+		receive_disconnect(padapter, GetAddr3Ptr(pframe) , reason);
+	}
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+	return _SUCCESS;
+}
+
+unsigned int OnDisassoc(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	u16 reason;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+	/* check A3 */
+	if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+		return _SUCCESS;
+
+#ifdef CONFIG_88EU_P2P
+	if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+		_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+		_set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
+
+	DBG_88E("%s Reason code(%d)\n", __func__, reason);
+
+#ifdef CONFIG_88EU_AP_MODE
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		unsigned long irqL;
+		struct sta_info *psta;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		/* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+		/* rtw_free_stainfo(padapter, psta); */
+		/* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */
+
+		DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n",
+			      reason, GetAddr2Ptr(pframe));
+
+		psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+		if (psta) {
+			u8 updated = 0;
+
+			_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+			if (!rtw_is_list_empty(&psta->asoc_list)) {
+				rtw_list_delete(&psta->asoc_list);
+				pstapriv->asoc_list_cnt--;
+				updated = ap_free_sta(padapter, psta, false, reason);
+			}
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+			associated_clients_update(padapter, updated);
+		}
+
+		return _SUCCESS;
+	} else
+#endif
+	{
+		DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n",
+			      reason, GetAddr3Ptr(pframe));
+
+		receive_disconnect(padapter, GetAddr3Ptr(pframe), reason);
+	}
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+	return _SUCCESS;
+}
+
+unsigned int OnAtim(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	DBG_88E("%s\n", __func__);
+	return _SUCCESS;
+}
+
+unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int ret = _FAIL;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+	u8 category;
+	u8 action;
+
+	DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+	psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+
+	if (!psta)
+		goto exit;
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT)
+		goto exit;
+
+	action = frame_body[1];
+	switch (action) {
+	case RTW_WLAN_ACTION_SPCT_MSR_REQ:
+	case RTW_WLAN_ACTION_SPCT_MSR_RPRT:
+	case RTW_WLAN_ACTION_SPCT_TPC_REQ:
+	case RTW_WLAN_ACTION_SPCT_TPC_RPRT:
+		break;
+	case RTW_WLAN_ACTION_SPCT_CHL_SWITCH:
+		break;
+	default:
+		break;
+	}
+
+exit:
+	return ret;
+}
+
+unsigned int OnAction_qos(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_dls(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	u8 *addr;
+	struct sta_info *psta = NULL;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	unsigned char		*frame_body;
+	unsigned char		category, action;
+	unsigned short	tid, status, reason_code = 0;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	/* check RA matches or not */
+	if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
+		return _SUCCESS;
+
+	DBG_88E("%s\n", __func__);
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+			return _SUCCESS;
+
+	addr = GetAddr2Ptr(pframe);
+	psta = rtw_get_stainfo(pstapriv, addr);
+
+	if (psta == NULL)
+		return _SUCCESS;
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	category = frame_body[0];
+	if (category == RTW_WLAN_CATEGORY_BACK) { /*  representing Block Ack */
+		if (!pmlmeinfo->HT_enable)
+			return _SUCCESS;
+		action = frame_body[1];
+		DBG_88E("%s, action=%d\n", __func__, action);
+		switch (action) {
+		case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
+			memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request));
+			process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr);
+
+			if (pmlmeinfo->bAcceptAddbaReq)
+				issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0);
+			else
+				issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */
+			break;
+		case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
+			status = RTW_GET_LE16(&frame_body[3]);
+			tid = ((frame_body[5] >> 2) & 0x7);
+			if (status == 0) {	/* successful */
+				DBG_88E("agg_enable for TID=%d\n", tid);
+				psta->htpriv.agg_enable_bitmap |= 1 << tid;
+				psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+			} else {
+				psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+			}
+			break;
+		case RTW_WLAN_ACTION_DELBA: /* DELBA */
+			if ((frame_body[3] & BIT(3)) == 0) {
+				psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf));
+				psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf));
+				reason_code = RTW_GET_LE16(&frame_body[4]);
+			} else if ((frame_body[3] & BIT(3)) == BIT(3)) {
+				tid = (frame_body[3] >> 4) & 0x0F;
+				preorder_ctrl =  &psta->recvreorder_ctrl[tid];
+				preorder_ctrl->enable = false;
+				preorder_ctrl->indicate_seq = 0xffff;
+			}
+			DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code);
+			/* todo: how to notify the host while receiving DELETE BA */
+			break;
+		default:
+			break;
+		}
+	}
+	return _SUCCESS;
+}
+
+#ifdef CONFIG_88EU_P2P
+
+static int get_reg_classes_full_count(struct p2p_channels channel_list)
+{
+	int cnt = 0;
+	int i;
+
+	for (i = 0; i < channel_list.reg_classes; i++) {
+		cnt += channel_list.reg_class[i].channels;
+	}
+
+	return cnt;
+}
+
+void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr)
+{
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8 action = P2P_PUB_ACTION_ACTION;
+	__be32 p2poui = cpu_to_be32(P2POUI);
+	u8 oui_subtype = P2P_GO_NEGO_REQ;
+	u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+	u8 wpsielen = 0, p2pielen = 0;
+	u16 len_channellist_attr = 0;
+	struct xmit_frame *pmgntframe;
+	struct pkt_attrib *pattrib;
+	unsigned char *pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short *fctrl;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	DBG_88E("[%s] In\n", __func__);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pwdinfo->negotiation_dialog_token = 1;	/*	Initialize the dialog value */
+	pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &(pattrib->pktlen));
+
+
+
+	/*	WPS Section */
+	wpsielen = 0;
+	/*	WPS OUI */
+	*(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	Device Password ID */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+
+	if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN)
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+	else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+	else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC)
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
+
+	wpsielen += 2;
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+
+	/*	P2P IE Section. */
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20110306 */
+	/*	According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */
+	/*	1. P2P Capability */
+	/*	2. Group Owner Intent */
+	/*	3. Configuration Timeout */
+	/*	4. Listen Channel */
+	/*	5. Extended Listen Timing */
+	/*	6. Intended P2P Interface Address */
+	/*	7. Channel List */
+	/*	8. P2P Device Info */
+	/*	9. Operating Channel */
+
+
+	/*	P2P Capability */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+	p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+	/*	Group Capability Bitmap, 1 byte */
+	if (pwdinfo->persistent_supported)
+		p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+	else
+		p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+
+	/*	Group Owner Intent */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Todo the tie breaker bit. */
+	p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+
+	/*	Configuration Timeout */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P GO */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P Client */
+
+
+	/*	Listen Channel */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Operating Class */
+	p2pie[p2pielen++] = 0x51;	/*	Copy from SD7 */
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->listen_channel;	/*	listening channel number */
+
+
+	/*	Extended Listen Timing ATTR */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Availability Period */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+	p2pielen += 2;
+
+	/*	Availability Interval */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+	p2pielen += 2;
+
+
+	/*	Intended P2P Interface Address */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+
+	/*	Channel List */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+	/*  Length: */
+	/*  Country String(3) */
+	/*  + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+	/*  + number of channels in all classes */
+	len_channellist_attr = 3
+	   + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes)
+	   + get_reg_classes_full_count(pmlmeext->channel_list);
+
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Channel Entry List */
+
+	{
+		int i, j;
+		for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+			/*	Number of Channels */
+			p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+			/*	Channel List */
+			for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+				p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+			}
+		}
+	}
+
+	/*	Device Info */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+	/*	Length: */
+	/*	21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+	/*	+ NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Config Method */
+	/*	This field should be big endian. Noted by P2P specification. */
+
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	*(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+	p2pielen += 2;
+
+	/*	Number of Secondary Device Types */
+	p2pie[p2pielen++] = 0x00;	/*	No Secondary Device Type List */
+
+	/*	Device Name */
+	/*	Type: */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len);
+	p2pielen += pwdinfo->device_name_len;
+
+
+	/*	Operating Channel */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Operating Class */
+	p2pie[p2pielen++] = 0x51;
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->operating_channel;	/*	operating channel number */
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result)
+{
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8 action = P2P_PUB_ACTION_ACTION;
+	__be32			p2poui = cpu_to_be32(P2POUI);
+	u8 oui_subtype = P2P_GO_NEGO_RESP;
+	u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+	u8 p2pielen = 0;
+	uint			wpsielen = 0;
+	u16 wps_devicepassword_id = 0x0000;
+	__be16			be_tmp;
+	uint			wps_devicepassword_id_len = 0;
+	u16 len_channellist_attr = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	DBG_88E("[%s] In, result=%d\n", __func__,  result);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pwdinfo->negotiation_dialog_token = frame_body[7];	/*	The Dialog Token of provisioning discovery request frame. */
+	pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen));
+
+	/*	Commented by Albert 20110328 */
+	/*	Try to get the device password ID from the WPS IE of group negotiation request frame */
+	/*	WiFi Direct test plan 5.1.15 */
+	rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen);
+	rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len);
+	wps_devicepassword_id = be16_to_cpu(be_tmp);
+
+	_rtw_memset(wpsie, 0x00, 255);
+	wpsielen = 0;
+
+	/*	WPS Section */
+	wpsielen = 0;
+	/*	WPS OUI */
+	*(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	Device Password ID */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+	else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+	else
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
+	wpsielen += 2;
+
+	/*	Commented by Kurt 20120113 */
+	/*	If some device wants to do p2p handshake without sending prov_disc_req */
+	/*	We have to get peer_req_cm from here. */
+	if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+		if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+			memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+		else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+			memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+		else
+			memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+	}
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+
+	/*	P2P IE Section. */
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20100908 */
+	/*	According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */
+	/*	1. Status */
+	/*	2. P2P Capability */
+	/*	3. Group Owner Intent */
+	/*	4. Configuration Timeout */
+	/*	5. Operating Channel */
+	/*	6. Intended P2P Interface Address */
+	/*	7. Channel List */
+	/*	8. Device Info */
+	/*	9. Group ID	(Only GO) */
+
+
+	/*	ToDo: */
+
+	/*	P2P Status */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = result;
+
+	/*	P2P Capability */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+		/*	Commented by Albert 2011/03/08 */
+		/*	According to the P2P specification */
+		/*	if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */
+		p2pie[p2pielen++] = 0;
+	} else {
+		/*	Be group owner or meet the error case */
+		p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+	}
+
+	/*	Group Capability Bitmap, 1 byte */
+	if (pwdinfo->persistent_supported) {
+		p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+	} else {
+		p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+	}
+
+	/*	Group Owner Intent */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	if (pwdinfo->peer_intent & 0x01) {
+		/*	Peer's tie breaker bit is 1, our tie breaker bit should be 0 */
+		p2pie[p2pielen++] = (pwdinfo->intent << 1);
+	} else {
+		/*	Peer's tie breaker bit is 0, our tie breaker bit should be 1 */
+		p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+	}
+
+
+	/*	Configuration Timeout */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P GO */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P Client */
+
+	/*	Operating Channel */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Operating Class */
+	p2pie[p2pielen++] = 0x51;
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->operating_channel;	/*	operating channel number */
+
+	/*	Intended P2P Interface Address */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Channel List */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+	/*  Country String(3) */
+	/*  + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+	/*  + number of channels in all classes */
+	len_channellist_attr = 3
+	   + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
+	   + get_reg_classes_full_count(pmlmeext->channel_list);
+
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Channel Entry List */
+
+	{
+		int i, j;
+		for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+			/*	Number of Channels */
+			p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+			/*	Channel List */
+			for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+				p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+			}
+		}
+	}
+
+	/*	Device Info */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+	/*	Length: */
+	/*	21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+	/*	+ NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Config Method */
+	/*	This field should be big endian. Noted by P2P specification. */
+
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	*(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+	p2pielen += 2;
+
+	/*	Number of Secondary Device Types */
+	p2pie[p2pielen++] = 0x00;	/*	No Secondary Device Type List */
+
+	/*	Device Name */
+	/*	Type: */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len);
+	p2pielen += pwdinfo->device_name_len;
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		/*	Group ID Attribute */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	p2P Device Address */
+		memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
+		p2pielen += ETH_ALEN;
+
+		/*	SSID */
+		memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+		p2pielen += pwdinfo->nego_ssidlen;
+	}
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+	return;
+}
+
+static void issue_p2p_GO_confirm(struct adapter *padapter, u8 *raddr, u8 result)
+{
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8 action = P2P_PUB_ACTION_ACTION;
+	__be32			p2poui = cpu_to_be32(P2POUI);
+	u8 oui_subtype = P2P_GO_NEGO_CONF;
+	u8 p2pie[255] = { 0x00 };
+	u8 p2pielen = 0;
+
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	DBG_88E("[%s] In\n", __func__);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen));
+
+
+
+	/*	P2P IE Section. */
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20110306 */
+	/*	According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */
+	/*	1. Status */
+	/*	2. P2P Capability */
+	/*	3. Operating Channel */
+	/*	4. Channel List */
+	/*	5. Group ID	(if this WiFi is GO) */
+
+	/*	P2P Status */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = result;
+
+	/*	P2P Capability */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+	p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+	/*	Group Capability Bitmap, 1 byte */
+	if (pwdinfo->persistent_supported)
+		p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+	else
+		p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+
+	/*	Operating Channel */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x51;
+		p2pie[p2pielen++] = pwdinfo->peer_operating_ch;
+	} else {
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x51;
+
+		/*	Channel Number */
+		p2pie[p2pielen++] = pwdinfo->operating_channel;		/*	Use the listen channel as the operating channel */
+	}
+
+
+	/*	Channel List */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(pwdinfo->channel_list_attr_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len);
+	p2pielen += pwdinfo->channel_list_attr_len;
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		/*	Group ID Attribute */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	p2P Device Address */
+		memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN);
+		p2pielen += ETH_ALEN;
+
+		/*	SSID */
+		memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+		p2pielen += pwdinfo->nego_ssidlen;
+	}
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+	pattrib->last_txcmdsz = pattrib->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+	return;
+}
+
+void issue_p2p_invitation_request(struct adapter *padapter, u8 *raddr)
+{
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8 action = P2P_PUB_ACTION_ACTION;
+	__be32			p2poui = cpu_to_be32(P2POUI);
+	u8 oui_subtype = P2P_INVIT_REQ;
+	u8 p2pie[255] = { 0x00 };
+	u8 p2pielen = 0;
+	u8 dialogToken = 3;
+	u16 len_channellist_attr = 0;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, raddr,  ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+	/*	P2P IE Section. */
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20101011 */
+	/*	According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes */
+	/*	1. Configuration Timeout */
+	/*	2. Invitation Flags */
+	/*	3. Operating Channel	(Only GO) */
+	/*	4. P2P Group BSSID	(Should be included if I am the GO) */
+	/*	5. Channel List */
+	/*	6. P2P Group ID */
+	/*	7. P2P Device Info */
+
+	/*	Configuration Timeout */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P GO */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P Client */
+
+	/*	Invitation Flags */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT;
+
+
+	/*	Operating Channel */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Operating Class */
+	p2pie[p2pielen++] = 0x51;
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch;	/*	operating channel number */
+
+	if (_rtw_memcmp(myid(&padapter->eeprompriv), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) {
+		/*	P2P Group BSSID */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	P2P Device Address for GO */
+		memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
+		p2pielen += ETH_ALEN;
+	}
+
+	/*	Channel List */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+
+	/*	Length: */
+	/*  Country String(3) */
+	/*  + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+	/*  + number of channels in all classes */
+	len_channellist_attr = 3
+	   + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
+	   + get_reg_classes_full_count(pmlmeext->channel_list);
+
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Channel Entry List */
+	{
+		int i, j;
+		for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+			/*	Operating Class */
+			p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+			/*	Number of Channels */
+			p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+			/*	Channel List */
+			for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+				p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+			}
+		}
+	}
+
+
+	/*	P2P Group ID */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address for GO */
+	memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	SSID */
+	memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen);
+	p2pielen += pwdinfo->invitereq_info.ssidlen;
+
+
+	/*	Device Info */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+	/*	Length: */
+	/*	21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+	/*	+ NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Config Method */
+	/*	This field should be big endian. Noted by P2P specification. */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	*(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+	p2pielen  += 4;
+
+	/*	Sub Category ID */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+	p2pielen += 2;
+
+	/*	Number of Secondary Device Types */
+	p2pie[p2pielen++] = 0x00;	/*	No Secondary Device Type List */
+
+	/*	Device Name */
+	/*	Type: */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+	p2pielen += pwdinfo->device_name_len;
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code)
+{
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8 action = P2P_PUB_ACTION_ACTION;
+	__be32			p2poui = cpu_to_be32(P2POUI);
+	u8 oui_subtype = P2P_INVIT_RESP;
+	u8 p2pie[255] = { 0x00 };
+	u8 p2pielen = 0;
+	u16 len_channellist_attr = 0;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, raddr,  ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+	/*	P2P IE Section. */
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20101005 */
+	/*	According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */
+	/*	1. Status */
+	/*	2. Configuration Timeout */
+	/*	3. Operating Channel	(Only GO) */
+	/*	4. P2P Group BSSID	(Only GO) */
+	/*	5. Channel List */
+
+	/*	P2P Status */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+	/*	Length: */
+	*(__le16  *)(p2pie + p2pielen) = cpu_to_le16(0x0001);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */
+	/*	Sent the event receiving the P2P Invitation Req frame to DMP UI. */
+	/*	DMP had to compare the MAC address to find out the profile. */
+	/*	So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */
+	/*	If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req */
+	/*	to NB to rebuild the persistent group. */
+	p2pie[p2pielen++] = status_code;
+
+	/*	Configuration Timeout */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P GO */
+	p2pie[p2pielen++] = 200;	/*	2 seconds needed to be the P2P Client */
+
+	if (status_code == P2P_STATUS_SUCCESS) {
+		if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+			/*	The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */
+			/*	In this case, the P2P Invitation response frame should carry the two more P2P attributes. */
+			/*	First one is operating channel attribute. */
+			/*	Second one is P2P Group BSSID attribute. */
+
+			/*	Operating Channel */
+			/*	Type: */
+			p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+			/*	Length: */
+			*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+			p2pielen += 2;
+
+			/*	Value: */
+			/*	Country String */
+			p2pie[p2pielen++] = 'X';
+			p2pie[p2pielen++] = 'X';
+
+			/*	The third byte should be set to 0x04. */
+			/*	Described in the "Operating Channel Attribute" section. */
+			p2pie[p2pielen++] = 0x04;
+
+			/*	Operating Class */
+			p2pie[p2pielen++] = 0x51;	/*	Copy from SD7 */
+
+			/*	Channel Number */
+			p2pie[p2pielen++] = pwdinfo->operating_channel;	/*	operating channel number */
+
+
+			/*	P2P Group BSSID */
+			/*	Type: */
+			p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+			/*	Length: */
+			*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+			p2pielen += 2;
+
+			/*	Value: */
+			/*	P2P Device Address for GO */
+			memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+			p2pielen += ETH_ALEN;
+		}
+
+		/*	Channel List */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+		/*	Length: */
+		/*  Country String(3) */
+		/*  + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+		/*  + number of channels in all classes */
+		len_channellist_attr = 3
+			+ (1 + 1) * (u16)pmlmeext->channel_list.reg_classes
+			+ get_reg_classes_full_count(pmlmeext->channel_list);
+
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	Country String */
+		p2pie[p2pielen++] = 'X';
+		p2pie[p2pielen++] = 'X';
+
+		/*	The third byte should be set to 0x04. */
+		/*	Described in the "Operating Channel Attribute" section. */
+		p2pie[p2pielen++] = 0x04;
+
+		/*	Channel Entry List */
+		{
+			int i, j;
+			for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+				/*	Operating Class */
+				p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+				/*	Number of Channels */
+				p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+				/*	Channel List */
+				for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+					p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+				}
+			}
+		}
+	}
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr)
+{
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8 action = P2P_PUB_ACTION_ACTION;
+	u8 dialogToken = 1;
+	u8 oui_subtype = P2P_PROVISION_DISC_REQ;
+	u8 wpsie[100] = { 0x00 };
+	u8 wpsielen = 0;
+	__be32 p2poui = cpu_to_be32(P2POUI);
+	u32			p2pielen = 0;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	DBG_88E("[%s] In\n", __func__);
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+	p2pielen = build_prov_disc_request_p2p_ie(pwdinfo, pframe, pssid, ussidlen, pdev_raddr);
+
+	pframe += p2pielen;
+	pattrib->pktlen += p2pielen;
+
+	wpsielen = 0;
+	/*	WPS OUI */
+	*(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	Config Method */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request);
+	wpsielen += 2;
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+static u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo)
+{
+	u8 i, match_result = 0;
+
+	DBG_88E("[%s] peermac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+		peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]);
+
+	for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) {
+	       DBG_88E("[%s] profileinfo_mac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+			    profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]);
+		if (_rtw_memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) {
+			match_result = 1;
+			DBG_88E("[%s] Match!\n", __func__);
+			break;
+		}
+	}
+	return match_result;
+}
+
+void issue_probersp_p2p(struct adapter *padapter, unsigned char *da)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	unsigned char					*mac;
+	struct xmit_priv	*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	u16 beacon_interval = 100;
+	u16 capInfo = 0;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8 wpsie[255] = { 0x00 };
+	u32					wpsielen = 0, p2pielen = 0;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = myid(&(padapter->eeprompriv));
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+	/*	Use the device address for BSSID field. */
+	memcpy(pwlanhdr->addr3, mac, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+	pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = pattrib->hdrlen;
+	pframe += pattrib->hdrlen;
+
+	/* timestamp will be inserted by hardware */
+	pframe += 8;
+	pattrib->pktlen += 8;
+
+	/*  beacon interval: 2 bytes */
+	memcpy(pframe, (unsigned char *)&beacon_interval, 2);
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/*	capability info: 2 bytes */
+	/*	ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */
+	capInfo |= cap_ShortPremble;
+	capInfo |= cap_ShortSlot;
+
+	memcpy(pframe, (unsigned char *)&capInfo, 2);
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+
+	/*  SSID */
+	pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen);
+
+	/*  supported rates... */
+	/*	Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */
+	pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen);
+
+	/*  DS parameter set */
+	pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen);
+
+	/*	Todo: WPS IE */
+	/*	Noted by Albert 20100907 */
+	/*	According to the WPS specification, all the WPS attribute is presented by Big Endian. */
+
+	wpsielen = 0;
+	/*	WPS OUI */
+	*(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	/*	WiFi Simple Config State */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG;	/*	Not Configured. */
+
+	/*	Response Type */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X;
+
+	/*	UUID-E */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
+	wpsielen += 2;
+
+	/*	Value: */
+	memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN);
+	wpsielen += 0x10;
+
+	/*	Manufacturer */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007);
+	wpsielen += 2;
+
+	/*	Value: */
+	memcpy(wpsie + wpsielen, "Realtek", 7);
+	wpsielen += 7;
+
+	/*	Model Name */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006);
+	wpsielen += 2;
+
+	/*	Value: */
+	memcpy(wpsie + wpsielen, "8188EU", 6);
+	wpsielen += 6;
+
+	/*	Model Number */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = 0x31;		/*	character 1 */
+
+	/*	Serial Number */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN);
+	wpsielen += 2;
+
+	/*	Value: */
+	memcpy(wpsie + wpsielen, "123456" , ETH_ALEN);
+	wpsielen += ETH_ALEN;
+
+	/*	Primary Device Type */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
+	wpsielen += 2;
+
+	/*	Value: */
+	/*	Category ID */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+	wpsielen += 2;
+
+	/*	OUI */
+	*(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	Sub Category ID */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+	wpsielen += 2;
+
+	/*	Device Name */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
+	wpsielen += 2;
+
+	/*	Value: */
+	if (pwdinfo->device_name_len) {
+		memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
+		wpsielen += pwdinfo->device_name_len;
+	}
+
+	/*	Config Method */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+	wpsielen += 2;
+
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+
+	p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe);
+	pframe += p2pielen;
+	pattrib->pktlen += p2pielen;
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+static int _issue_probereq_p2p(struct adapter *padapter, u8 *da, int wait_ack)
+{
+	int ret = _FAIL;
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	unsigned char			*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short		*fctrl;
+	unsigned char			*mac;
+	struct xmit_priv		*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+	u16 wpsielen = 0, p2pielen = 0;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = myid(&(padapter->eeprompriv));
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	if (da) {
+		memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+		memcpy(pwlanhdr->addr3, da, ETH_ALEN);
+	} else {
+		if ((pwdinfo->p2p_info.scan_op_ch_only) || (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
+			/*	This two flags will be set when this is only the P2P client mode. */
+			memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
+			memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN);
+		} else {
+			/*	broadcast probe request frame */
+			memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+			memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+		}
+	}
+	memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_PROBEREQ);
+
+	pframe += sizeof (struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ))
+		pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &(pattrib->pktlen));
+	else
+		pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &(pattrib->pktlen));
+
+	/*	Use the OFDM rate in the P2P probe request frame. (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */
+	pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen);
+
+
+	/*	WPS IE */
+	/*	Noted by Albert 20110221 */
+	/*	According to the WPS specification, all the WPS attribute is presented by Big Endian. */
+
+	wpsielen = 0;
+	/*	WPS OUI */
+	*(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	WPS version */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+	wpsielen += 2;
+
+	/*	Value: */
+	wpsie[wpsielen++] = WPS_VERSION_1;	/*	Version 1.0 */
+
+	if (pmlmepriv->wps_probe_req_ie == NULL) {
+		/*	UUID-E */
+		/*	Type: */
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010);
+		wpsielen += 2;
+
+		/*	Value: */
+		memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN);
+		wpsielen += 0x10;
+
+		/*	Config Method */
+		/*	Type: */
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+		wpsielen += 2;
+
+		/*	Length: */
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+		wpsielen += 2;
+
+		/*	Value: */
+		*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+		wpsielen += 2;
+	}
+
+	/*	Device Name */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len);
+	wpsielen += 2;
+
+	/*	Value: */
+	memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len);
+	wpsielen += pwdinfo->device_name_len;
+
+	/*	Primary Device Type */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008);
+	wpsielen += 2;
+
+	/*	Value: */
+	/*	Category ID */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI);
+	wpsielen += 2;
+
+	/*	OUI */
+	*(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+	wpsielen += 4;
+
+	/*	Sub Category ID */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP);
+	wpsielen += 2;
+
+	/*	Device Password ID */
+	/*	Type: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+	wpsielen += 2;
+
+	/*	Length: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	*(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);	/*	Registrar-specified */
+	wpsielen += 2;
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20110221 */
+	/*	According to the P2P Specification, the probe request frame should contain 5 P2P attributes */
+	/*	1. P2P Capability */
+	/*	2. P2P Device ID if this probe request wants to find the specific P2P device */
+	/*	3. Listen Channel */
+	/*	4. Extended Listen Timing */
+	/*	5. Operating Channel if this WiFi is working as the group owner now */
+
+	/*	P2P Capability */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+	p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+	/*	Group Capability Bitmap, 1 byte */
+	if (pwdinfo->persistent_supported)
+		p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+	else
+		p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+	/*	Listen Channel */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Country String */
+	p2pie[p2pielen++] = 'X';
+	p2pie[p2pielen++] = 'X';
+
+	/*	The third byte should be set to 0x04. */
+	/*	Described in the "Operating Channel Attribute" section. */
+	p2pie[p2pielen++] = 0x04;
+
+	/*	Operating Class */
+	p2pie[p2pielen++] = 0x51;	/*	Copy from SD7 */
+
+	/*	Channel Number */
+	p2pie[p2pielen++] = pwdinfo->listen_channel;	/*	listen channel */
+
+
+	/*	Extended Listen Timing */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+	/*	Length: */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Availability Period */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+	p2pielen += 2;
+
+	/*	Availability Interval */
+	*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+	p2pielen += 2;
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		/*	Operating Channel (if this WiFi is working as the group owner now) */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	Country String */
+		p2pie[p2pielen++] = 'X';
+		p2pie[p2pielen++] = 'X';
+
+		/*	The third byte should be set to 0x04. */
+		/*	Described in the "Operating Channel Attribute" section. */
+		p2pie[p2pielen++] = 0x04;
+
+		/*	Operating Class */
+		p2pie[p2pielen++] = 0x51;	/*	Copy from SD7 */
+
+		/*	Channel Number */
+		p2pie[p2pielen++] = pwdinfo->operating_channel;	/*	operating channel number */
+	}
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+
+	if (pmlmepriv->wps_probe_req_ie != NULL) {
+		/* WPS IE */
+		memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len);
+		pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+		pframe += pmlmepriv->wps_probe_req_ie_len;
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz));
+
+	if (wait_ack) {
+		ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+	} else {
+		dump_mgntframe(padapter, pmgntframe);
+		ret = _SUCCESS;
+	}
+
+exit:
+	return ret;
+}
+
+inline void issue_probereq_p2p(struct adapter *adapter, u8 *da)
+{
+	_issue_probereq_p2p(adapter, da, false);
+}
+
+int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt, int wait_ms)
+{
+	int ret;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	do {
+		ret = _issue_probereq_p2p(adapter, da, wait_ms > 0 ? true : false);
+
+		i++;
+
+		if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	if (ret != _FAIL) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+
+	if (try_cnt && wait_ms) {
+		if (da)
+			DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(adapter), da, rtw_get_oper_ch(adapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+		else
+			DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(adapter), rtw_get_oper_ch(adapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+	}
+exit:
+	return ret;
+}
+
+#endif /* CONFIG_88EU_P2P */
+
+static s32 rtw_action_public_decache(union recv_frame *recv_frame, s32 token)
+{
+	struct adapter *adapter = recv_frame->u.hdr.adapter;
+	struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+	u8 *frame = recv_frame->u.hdr.rx_data;
+	u16 seq_ctrl = ((recv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
+		(recv_frame->u.hdr.attrib.frag_num & 0xf);
+
+	if (GetRetry(frame)) {
+		if (token >= 0) {
+			if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) {
+				DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n",
+					FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token);
+				return _FAIL;
+			}
+		} else {
+			if (seq_ctrl == mlmeext->action_public_rxseq) {
+				DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n",
+					FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq);
+				return _FAIL;
+			}
+		}
+	}
+
+	mlmeext->action_public_rxseq = seq_ctrl;
+
+	if (token >= 0)
+		mlmeext->action_public_dialog_token = token;
+
+	return _SUCCESS;
+}
+
+static unsigned int on_action_public_p2p(union recv_frame *precv_frame)
+{
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	u8 *frame_body;
+	u8 dialogToken = 0;
+#ifdef CONFIG_88EU_P2P
+	struct adapter *padapter = precv_frame->u.hdr.adapter;
+	uint len = precv_frame->u.hdr.len;
+	u8 *p2p_ie;
+	u32	p2p_ielen;
+	struct	wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8	result = P2P_STATUS_SUCCESS;
+	u8	empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+#endif /* CONFIG_88EU_P2P */
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	dialogToken = frame_body[7];
+
+	if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL)
+		return _FAIL;
+
+#ifdef CONFIG_88EU_P2P
+	_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+	/*	Do nothing if the driver doesn't enable the P2P function. */
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE))
+		return _SUCCESS;
+
+	len -= sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	switch (frame_body[6]) { /* OUI Subtype */
+	case P2P_GO_NEGO_REQ:
+		DBG_88E("[%s] Got GO Nego Req Frame\n", __func__);
+		_rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
+			rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) {
+			/*	Commented by Albert 20110526 */
+			/*	In this case, this means the previous nego fail doesn't be reset yet. */
+			_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+			/*	Restore the previous p2p state */
+			rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+			DBG_88E("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo));
+		}
+
+		/*	Commented by Kurt 20110902 */
+		/* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING))
+			rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+
+		/*	Commented by Kurt 20120113 */
+		/*	Get peer_dev_addr here if peer doesn't issue prov_disc frame. */
+		if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN))
+			memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN);
+
+		result = process_p2p_group_negotation_req(pwdinfo, frame_body, len);
+		issue_p2p_GO_response(padapter, GetAddr2Ptr(pframe), frame_body, len, result);
+
+		/*	Commented by Albert 20110718 */
+		/*	No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */
+		_set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
+		break;
+	case P2P_GO_NEGO_RESP:
+		DBG_88E("[%s] Got GO Nego Resp Frame\n", __func__);
+
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+			/*	Commented by Albert 20110425 */
+			/*	The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */
+			_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+			pwdinfo->nego_req_info.benable = false;
+			result = process_p2p_group_negotation_resp(pwdinfo, frame_body, len);
+			issue_p2p_GO_confirm(pwdinfo->padapter, GetAddr2Ptr(pframe), result);
+			if (P2P_STATUS_SUCCESS == result) {
+				if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) {
+					pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch;
+					pwdinfo->p2p_info.scan_op_ch_only = 1;
+					_set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH);
+				}
+			}
+			/*	Reset the dialog token for group negotiation frames. */
+			pwdinfo->negotiation_dialog_token = 1;
+			if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+				_set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
+		} else {
+			DBG_88E("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__);
+		}
+		break;
+	case P2P_GO_NEGO_CONF:
+		DBG_88E("[%s] Got GO Nego Confirm Frame\n", __func__);
+		result = process_p2p_group_negotation_confirm(pwdinfo, frame_body, len);
+		if (P2P_STATUS_SUCCESS == result) {
+			if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) {
+				pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch;
+				pwdinfo->p2p_info.scan_op_ch_only = 1;
+				_set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH);
+			}
+		}
+		break;
+	case P2P_INVIT_REQ:
+		/*	Added by Albert 2010/10/05 */
+		/*	Received the P2P Invite Request frame. */
+
+		DBG_88E("[%s] Got invite request frame!\n", __func__);
+		p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
+		if (p2p_ie) {
+			/*	Parse the necessary information from the P2P Invitation Request frame. */
+			/*	For example: The MAC address of sending this P2P Invitation Request frame. */
+			u32	attr_contentlen = 0;
+			u8	status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+			struct group_id_info group_id;
+			u8	invitation_flag = 0;
+
+			rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen);
+			if (attr_contentlen) {
+				rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen);
+				/*	Commented by Albert 20120510 */
+				/*	Copy to the pwdinfo->p2p_peer_interface_addr. */
+				/*	So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */
+				/*	#> iwpriv wlan0 p2p_get peer_ifa */
+				/*	After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */
+
+				if (attr_contentlen) {
+					DBG_88E("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+						pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1],
+						pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3],
+						pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+				}
+
+				if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) {
+					/*	Re-invoke the persistent group. */
+
+					_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
+					rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen);
+					if (attr_contentlen) {
+						if (_rtw_memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
+							/*	The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */
+							rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO);
+							rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+							status_code = P2P_STATUS_SUCCESS;
+						} else {
+							/*	The p2p device sending this p2p invitation request wants to be the persistent GO. */
+							if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[0])) {
+								u8 operatingch_info[5] = { 0x00 };
+								if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
+									if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4])) {
+										/*	The operating channel is acceptable for this device. */
+										pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4];
+										pwdinfo->rx_invitereq_info.scan_op_ch_only = 1;
+										_set_timer(&pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH);
+										rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
+										rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+										status_code = P2P_STATUS_SUCCESS;
+									} else {
+										/*	The operating channel isn't supported by this device. */
+										rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+										rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+										status_code = P2P_STATUS_FAIL_NO_COMMON_CH;
+										_set_timer(&pwdinfo->restore_p2p_state_timer, 3000);
+									}
+								} else {
+									/*	Commented by Albert 20121130 */
+									/*	Intel will use the different P2P IE to store the operating channel information */
+									/*	Workaround for Intel WiDi 3.5 */
+									rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
+									rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+									status_code = P2P_STATUS_SUCCESS;
+								}
+							} else {
+								rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+								status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
+							}
+						}
+					} else {
+						DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__);
+						status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+					}
+				} else {
+					/*	Received the invitation to join a P2P group. */
+
+					_rtw_memset(&group_id, 0x00, sizeof(struct group_id_info));
+					rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen);
+					if (attr_contentlen) {
+						if (_rtw_memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) {
+							/*	In this case, the GO can't be myself. */
+							rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+							status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+						} else {
+							/*	The p2p device sending this p2p invitation request wants to join an existing P2P group */
+							/*	Commented by Albert 2012/06/28 */
+							/*	In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */
+							/*	The peer device address should be the destination address for the provisioning discovery request. */
+							/*	Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */
+							/*	The peer interface address should be the address for WPS mac address */
+							memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN);
+							rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+							rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN);
+							status_code = P2P_STATUS_SUCCESS;
+						}
+					} else {
+						DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__);
+						status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+					}
+				}
+			} else {
+				DBG_88E("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__);
+				status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+			}
+
+			DBG_88E("[%s] status_code = %d\n", __func__, status_code);
+
+			pwdinfo->inviteresp_info.token = frame_body[7];
+			issue_p2p_invitation_response(padapter, GetAddr2Ptr(pframe), pwdinfo->inviteresp_info.token, status_code);
+		}
+		break;
+	case P2P_INVIT_RESP: {
+		u8	attr_content = 0x00;
+		u32	attr_contentlen = 0;
+
+		DBG_88E("[%s] Got invite response frame!\n", __func__);
+		_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+		p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
+		if (p2p_ie) {
+			rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+
+			if (attr_contentlen == 1) {
+				DBG_88E("[%s] Status = %d\n", __func__, attr_content);
+				pwdinfo->invitereq_info.benable = false;
+
+				if (attr_content == P2P_STATUS_SUCCESS) {
+					if (_rtw_memcmp(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv), ETH_ALEN)) {
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+					} else {
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+					}
+					rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK);
+				} else {
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+					rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+				}
+			} else {
+				rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+				rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+			}
+		} else {
+			rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+			rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+		}
+
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL))
+			_set_timer(&pwdinfo->restore_p2p_state_timer, 5000);
+		break;
+	}
+	case P2P_DEVDISC_REQ:
+		process_p2p_devdisc_req(pwdinfo, pframe, len);
+		break;
+	case P2P_DEVDISC_RESP:
+		process_p2p_devdisc_resp(pwdinfo, pframe, len);
+		break;
+	case P2P_PROVISION_DISC_REQ:
+		DBG_88E("[%s] Got Provisioning Discovery Request Frame\n", __func__);
+		process_p2p_provdisc_req(pwdinfo, pframe, len);
+		memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN);
+
+		/* 20110902 Kurt */
+		/* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
+			rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ);
+		_set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+		break;
+	case P2P_PROVISION_DISC_RESP:
+		/*	Commented by Albert 20110707 */
+		/*	Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */
+		DBG_88E("[%s] Got Provisioning Discovery Response Frame\n", __func__);
+		/*	Commented by Albert 20110426 */
+		/*	The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */
+		_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP);
+		process_p2p_provdisc_resp(pwdinfo, pframe);
+		_set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+		break;
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	return _SUCCESS;
+}
+
+static unsigned int on_action_public_vendor(union recv_frame *precv_frame)
+{
+	unsigned int ret = _FAIL;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == true) {
+		ret = on_action_public_p2p(precv_frame);
+	}
+
+	return ret;
+}
+
+static unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action)
+{
+	unsigned int ret = _FAIL;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 token;
+
+	token = frame_body[2];
+
+	if (rtw_action_public_decache(precv_frame, token) == _FAIL)
+		goto exit;
+
+	ret = _SUCCESS;
+
+exit:
+	return ret;
+}
+
+unsigned int on_action_public(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	unsigned int ret = _FAIL;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	u8 category, action;
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))
+		goto exit;
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_PUBLIC)
+		goto exit;
+
+	action = frame_body[1];
+	switch (action) {
+	case ACT_PUBLIC_VENDOR:
+		ret = on_action_public_vendor(precv_frame);
+		break;
+	default:
+		ret = on_action_public_default(precv_frame, action);
+		break;
+	}
+
+exit:
+	return ret;
+}
+
+unsigned int OnAction_ht(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_wmm(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+unsigned int OnAction_p2p(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_P2P
+	u8 *frame_body;
+	u8 category, OUI_Subtype;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	uint len = precv_frame->u.hdr.len;
+	struct	wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+
+	DBG_88E("%s\n", __func__);
+
+	/* check RA matches or not */
+	if (!_rtw_memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */
+		return _SUCCESS;
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	category = frame_body[0];
+	if (category != RTW_WLAN_CATEGORY_P2P)
+		return _SUCCESS;
+
+	if (be32_to_cpu(*((__be32 *)(frame_body + 1))) != P2POUI)
+		return _SUCCESS;
+
+	len -= sizeof(struct rtw_ieee80211_hdr_3addr);
+	OUI_Subtype = frame_body[5];
+
+	switch (OUI_Subtype) {
+	case P2P_NOTICE_OF_ABSENCE:
+		break;
+	case P2P_PRESENCE_REQUEST:
+		process_p2p_presence_req(pwdinfo, pframe, len);
+		break;
+	case P2P_PRESENCE_RESPONSE:
+		break;
+	case P2P_GO_DISC_REQUEST:
+		break;
+	default:
+		break;
+	}
+#endif /* CONFIG_88EU_P2P */
+	return _SUCCESS;
+}
+
+unsigned int OnAction(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	int i;
+	unsigned char	category;
+	struct action_handler *ptable;
+	unsigned char	*frame_body;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	category = frame_body[0];
+
+	for (i = 0; i < sizeof(OnAction_tbl)/sizeof(struct action_handler); i++) {
+		ptable = &OnAction_tbl[i];
+		if (category == ptable->num)
+			ptable->func(padapter, precv_frame);
+	}
+	return _SUCCESS;
+}
+
+unsigned int DoReserved(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	return _SUCCESS;
+}
+
+struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv)
+{
+	struct xmit_frame			*pmgntframe;
+	struct xmit_buf				*pxmitbuf;
+
+	pmgntframe = rtw_alloc_xmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		DBG_88E("%s, alloc xmitframe fail\n", __func__);
+		return NULL;
+	}
+
+	pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv);
+	if (pxmitbuf == NULL) {
+		DBG_88E("%s, alloc xmitbuf fail\n", __func__);
+		rtw_free_xmitframe(pxmitpriv, pmgntframe);
+		return NULL;
+	}
+	pmgntframe->frame_tag = MGNT_FRAMETAG;
+	pmgntframe->pxmitbuf = pxmitbuf;
+	pmgntframe->buf_addr = pxmitbuf->pbuf;
+	pxmitbuf->priv_data = pmgntframe;
+	return pmgntframe;
+}
+
+/****************************************************************************
+
+Following are some TX fuctions for WiFi MLME
+
+*****************************************************************************/
+
+void update_mgnt_tx_rate(struct adapter *padapter, u8 rate)
+{
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+
+	pmlmeext->tx_rate = rate;
+	DBG_88E("%s(): rate = %x\n", __func__, rate);
+}
+
+void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib)
+{
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+
+	_rtw_memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib));
+
+	pattrib->hdrlen = 24;
+	pattrib->nr_frags = 1;
+	pattrib->priority = 7;
+	pattrib->mac_id = 0;
+	pattrib->qsel = 0x12;
+
+	pattrib->pktlen = 0;
+
+	if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+		pattrib->raid = 6;/* b mode */
+	else
+		pattrib->raid = 5;/* a/g mode */
+
+	pattrib->encrypt = _NO_PRIVACY_;
+	pattrib->bswenc = false;
+
+	pattrib->qos_en = false;
+	pattrib->ht_en = false;
+	pattrib->bwmode = HT_CHANNEL_WIDTH_20;
+	pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pattrib->sgi = false;
+
+	pattrib->seqnum = pmlmeext->mgnt_seq;
+
+	pattrib->retry_ctrl = true;
+}
+
+void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe)
+{
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+		return;
+
+	rtw_hal_mgnt_xmit(padapter, pmgntframe);
+}
+
+s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms)
+{
+	s32 ret = _FAIL;
+	struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
+	struct submit_ctx sctx;
+
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+		return ret;
+
+	rtw_sctx_init(&sctx, timeout_ms);
+	pxmitbuf->sctx = &sctx;
+
+	ret = rtw_hal_mgnt_xmit(padapter, pmgntframe);
+
+	if (ret == _SUCCESS)
+		ret = rtw_sctx_wait(&sctx);
+
+	 return ret;
+}
+
+s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe)
+{
+	s32 ret = _FAIL;
+	u32 timeout_ms = 500;/*   500ms */
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+		return -1;
+
+	_enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+	pxmitpriv->ack_tx = true;
+
+	pmgntframe->ack_report = 1;
+	if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) {
+		ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms);
+	}
+
+	pxmitpriv->ack_tx = false;
+	_exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL);
+
+	 return ret;
+}
+
+static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode)
+{
+	u8 *ssid_ie;
+	int ssid_len_ori;
+	int len_diff = 0;
+
+	ssid_ie = rtw_get_ie(ies,  WLAN_EID_SSID, &ssid_len_ori, ies_len);
+
+	if (ssid_ie && ssid_len_ori > 0) {
+		switch (hidden_ssid_mode) {
+		case 1: {
+			u8 *next_ie = ssid_ie + 2 + ssid_len_ori;
+			u32 remain_len = 0;
+
+			remain_len = ies_len - (next_ie - ies);
+
+			ssid_ie[1] = 0;
+			memcpy(ssid_ie+2, next_ie, remain_len);
+			len_diff -= ssid_len_ori;
+
+			break;
+		}
+		case 2:
+			_rtw_memset(&ssid_ie[2], 0, ssid_len_ori);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return len_diff;
+}
+
+void issue_beacon(struct adapter *padapter, int timeout_ms)
+{
+	struct xmit_frame	*pmgntframe;
+	struct pkt_attrib	*pattrib;
+	unsigned char	*pframe;
+	struct rtw_ieee80211_hdr *pwlanhdr;
+	unsigned short *fctrl;
+	unsigned int	rate_len;
+	struct xmit_priv	*pxmitpriv = &(padapter->xmitpriv);
+#if defined(CONFIG_88EU_AP_MODE)
+	unsigned long irqL;
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex		*cur_network = &(pmlmeinfo->network);
+	u8	bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		DBG_88E("%s, alloc mgnt frame fail\n", __func__);
+		return;
+	}
+#if defined (CONFIG_88EU_AP_MODE)
+	_enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+	pattrib->qsel = 0x10;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+	/* pmlmeext->mgnt_seq++; */
+	SetFrameSubType(pframe, WIFI_BEACON);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+#ifdef CONFIG_88EU_P2P
+		/*  for P2P : Primary Device Type & Device Name */
+		u32 wpsielen = 0, insert_len = 0;
+		u8 *wpsie = NULL;
+		wpsie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen);
+
+		if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) {
+			uint wps_offset, remainder_ielen;
+			u8 *premainder_ie, *pframe_wscie;
+
+			wps_offset = (uint)(wpsie - cur_network->IEs);
+			premainder_ie = wpsie + wpsielen;
+			remainder_ielen = cur_network->IELength - wps_offset - wpsielen;
+			pframe_wscie = pframe + wps_offset;
+			memcpy(pframe, cur_network->IEs, wps_offset+wpsielen);
+			pframe += (wps_offset + wpsielen);
+			pattrib->pktlen += (wps_offset + wpsielen);
+
+			/* now pframe is end of wsc ie, insert Primary Device Type & Device Name */
+			/*	Primary Device Type */
+			/*	Type: */
+			*(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+			insert_len += 2;
+
+			/*	Length: */
+			*(__be16 *)(pframe + insert_len) = cpu_to_be16(0x0008);
+			insert_len += 2;
+
+			/*	Value: */
+			/*	Category ID */
+			*(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+			insert_len += 2;
+
+			/*	OUI */
+			*(__be32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI);
+			insert_len += 4;
+
+			/*	Sub Category ID */
+			*(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+			insert_len += 2;
+
+			/*	Device Name */
+			/*	Type: */
+			*(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+			insert_len += 2;
+
+			/*	Length: */
+			*(__be16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len);
+			insert_len += 2;
+
+			/*	Value: */
+			memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len);
+			insert_len += pwdinfo->device_name_len;
+
+			/* update wsc ie length */
+			*(pframe_wscie+1) = (wpsielen-2) + insert_len;
+
+			/* pframe move to end */
+			pframe += insert_len;
+			pattrib->pktlen += insert_len;
+
+			/* copy remainder_ie to pframe */
+			memcpy(pframe, premainder_ie, remainder_ielen);
+			pframe += remainder_ielen;
+			pattrib->pktlen += remainder_ielen;
+		} else
+#endif /* CONFIG_88EU_P2P */
+		{
+			int len_diff;
+			memcpy(pframe, cur_network->IEs, cur_network->IELength);
+			len_diff = update_hidden_ssid(
+				pframe+_BEACON_IE_OFFSET_
+				, cur_network->IELength-_BEACON_IE_OFFSET_
+				, pmlmeinfo->hidden_ssid_mode
+			);
+			pframe += (cur_network->IELength+len_diff);
+			pattrib->pktlen += (cur_network->IELength+len_diff);
+		}
+
+		{
+			u8 *wps_ie;
+			uint wps_ielen;
+			u8 sr = 0;
+			wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof (struct rtw_ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_,
+				pattrib->pktlen-sizeof (struct rtw_ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen);
+			if (wps_ie && wps_ielen > 0)
+				rtw_get_wps_attr_content(wps_ie,  wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL);
+			if (sr != 0)
+				set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+			else
+				_clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS);
+		}
+
+#ifdef CONFIG_88EU_P2P
+		if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+			u32 len;
+			len = build_beacon_p2p_ie(pwdinfo, pframe);
+
+			pframe += len;
+			pattrib->pktlen += len;
+		}
+#endif /* CONFIG_88EU_P2P */
+
+		goto _issue_bcn;
+	}
+
+	/* below for ad-hoc mode */
+
+	/* timestamp will be inserted by hardware */
+	pframe += 8;
+	pattrib->pktlen += 8;
+
+	/*  beacon interval: 2 bytes */
+
+	memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/*  capability info: 2 bytes */
+
+	memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
+
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/*  SSID */
+	pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen);
+
+	/*  supported rates... */
+	rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
+	pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen);
+
+	/*  DS parameter set */
+	pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen);
+
+	{
+		u8 erpinfo = 0;
+		u32 ATIMWindow;
+		/*  IBSS Parameter Set... */
+		ATIMWindow = 0;
+		pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen);
+
+		/* ERP IE */
+		pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen);
+	}
+
+	/*  EXTERNDED SUPPORTED RATE */
+	if (rate_len > 8)
+		pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen);
+	/* todo:HT for adhoc */
+_issue_bcn:
+
+#if defined (CONFIG_88EU_AP_MODE)
+	pmlmepriv->update_bcn = false;
+
+	_exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL);
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+
+	if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
+		DBG_88E("beacon frame too large\n");
+		return;
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	/* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */
+	if (timeout_ms > 0)
+		dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms);
+	else
+		dump_mgntframe(padapter, pmgntframe);
+}
+
+void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	unsigned char					*mac, *bssid;
+	struct xmit_priv	*pxmitpriv = &(padapter->xmitpriv);
+#if defined (CONFIG_88EU_AP_MODE)
+	u8 *pwps_ie;
+	uint wps_ielen;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex		*cur_network = &(pmlmeinfo->network);
+	unsigned int	rate_len;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL) {
+		DBG_88E("%s, alloc mgnt frame fail\n", __func__);
+		return;
+	}
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = myid(&(padapter->eeprompriv));
+	bssid = cur_network->MacAddress;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+	memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+	pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = pattrib->hdrlen;
+	pframe += pattrib->hdrlen;
+
+	if (cur_network->IELength > MAX_IE_SZ)
+		return;
+
+#if defined(CONFIG_88EU_AP_MODE)
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+		pwps_ie = rtw_get_wps_ie(cur_network->IEs+_FIXED_IE_LENGTH_, cur_network->IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+		/* inerset & update wps_probe_resp_ie */
+		if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) {
+			uint wps_offset, remainder_ielen;
+			u8 *premainder_ie;
+
+			wps_offset = (uint)(pwps_ie - cur_network->IEs);
+
+			premainder_ie = pwps_ie + wps_ielen;
+
+			remainder_ielen = cur_network->IELength - wps_offset - wps_ielen;
+
+			memcpy(pframe, cur_network->IEs, wps_offset);
+			pframe += wps_offset;
+			pattrib->pktlen += wps_offset;
+
+			wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */
+			if ((wps_offset+wps_ielen+2) <= MAX_IE_SZ) {
+				memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen+2);
+				pframe += wps_ielen+2;
+				pattrib->pktlen += wps_ielen+2;
+			}
+
+			if ((wps_offset+wps_ielen+2+remainder_ielen) <= MAX_IE_SZ) {
+				memcpy(pframe, premainder_ie, remainder_ielen);
+				pframe += remainder_ielen;
+				pattrib->pktlen += remainder_ielen;
+			}
+		} else {
+			memcpy(pframe, cur_network->IEs, cur_network->IELength);
+			pframe += cur_network->IELength;
+			pattrib->pktlen += cur_network->IELength;
+		}
+	} else
+#endif
+	{
+		/* timestamp will be inserted by hardware */
+		pframe += 8;
+		pattrib->pktlen += 8;
+
+		/*  beacon interval: 2 bytes */
+
+		memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+		pframe += 2;
+		pattrib->pktlen += 2;
+
+		/*  capability info: 2 bytes */
+
+		memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
+
+		pframe += 2;
+		pattrib->pktlen += 2;
+
+		/* below for ad-hoc mode */
+
+		/*  SSID */
+		pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen);
+
+		/*  supported rates... */
+		rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen);
+
+		/*  DS parameter set */
+		pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen);
+
+		if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+			u8 erpinfo = 0;
+			u32 ATIMWindow;
+			/*  IBSS Parameter Set... */
+			/* ATIMWindow = cur->Configuration.ATIMWindow; */
+			ATIMWindow = 0;
+			pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen);
+
+			/* ERP IE */
+			pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen);
+		}
+
+
+		/*  EXTERNDED SUPPORTED RATE */
+		if (rate_len > 8)
+			pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen);
+		/* todo:HT for adhoc */
+	}
+
+#ifdef CONFIG_88EU_P2P
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) {
+		u32 len;
+		len = build_probe_resp_p2p_ie(pwdinfo, pframe);
+
+		pframe += len;
+		pattrib->pktlen += len;
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack)
+{
+	int ret = _FAIL;
+	struct xmit_frame		*pmgntframe;
+	struct pkt_attrib		*pattrib;
+	unsigned char			*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short		*fctrl;
+	unsigned char			*mac;
+	unsigned char			bssrate[NumRates];
+	struct xmit_priv		*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	int	bssrate_len = 0;
+	u8	bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n"));
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = myid(&(padapter->eeprompriv));
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	if (da) {
+		/*	unicast probe request frame */
+		memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+		memcpy(pwlanhdr->addr3, da, ETH_ALEN);
+	} else {
+		/*	broadcast probe request frame */
+		memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+		memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN);
+	}
+
+	memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_PROBEREQ);
+
+	pframe += sizeof (struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof (struct rtw_ieee80211_hdr_3addr);
+
+	if (pssid)
+		pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen));
+	else
+		pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen));
+
+	get_rate_set(padapter, bssrate, &bssrate_len);
+
+	if (bssrate_len > 8) {
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen));
+		pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen));
+	} else {
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));
+	}
+
+	/* add wps_ie for wps2.0 */
+	if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) {
+		memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len);
+		pframe += pmlmepriv->wps_probe_req_ie_len;
+		pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+		 ("issuing probe_req, tx_len=%d\n", pattrib->last_txcmdsz));
+
+	if (wait_ack) {
+		ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+	} else {
+		dump_mgntframe(padapter, pmgntframe);
+		ret = _SUCCESS;
+	}
+
+exit:
+	return ret;
+}
+
+inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da)
+{
+	_issue_probereq(padapter, pssid, da, false);
+}
+
+int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da,
+	int try_cnt, int wait_ms)
+{
+	int ret;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	do {
+		ret = _issue_probereq(padapter, pssid, da, wait_ms > 0 ? true : false);
+
+		i++;
+
+		if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	if (ret != _FAIL) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+
+	if (try_cnt && wait_ms) {
+		if (da)
+			DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+		else
+			DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+	}
+exit:
+	return ret;
+}
+
+/*  if psta == NULL, indiate we are station(client) now... */
+void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status)
+{
+	struct xmit_frame *pmgntframe;
+	struct pkt_attrib *pattrib;
+	unsigned char *pframe;
+	struct rtw_ieee80211_hdr *pwlanhdr;
+	unsigned short *fctrl;
+	unsigned int val32;
+	u16 val16;
+#ifdef CONFIG_88EU_AP_MODE
+	__le16 le_val16;
+#endif
+	int use_shared_key = 0;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_AUTH);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+
+	if (psta) {/*  for AP mode */
+#ifdef CONFIG_88EU_AP_MODE
+
+		memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN);
+		memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+
+		/*  setting auth algo number */
+		val16 = (u16)psta->authalg;
+
+		if (status != _STATS_SUCCESSFUL_)
+			val16 = 0;
+
+		if (val16) {
+			le_val16 = cpu_to_le16(val16);
+			use_shared_key = 1;
+		} else {
+			le_val16 = 0;
+		}
+
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen));
+
+		/*  setting auth seq number */
+		val16 = (u16)psta->auth_seq;
+		le_val16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_val16, &(pattrib->pktlen));
+
+		/*  setting status code... */
+		val16 = status;
+		le_val16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_val16, &(pattrib->pktlen));
+
+		/*  added challenging text... */
+		if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1))
+			pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen));
+#endif
+	} else {
+		__le32 le_tmp32;
+		__le16 le_tmp16;
+		memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+		memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+
+		/*  setting auth algo number */
+		val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/*  0:OPEN System, 1:Shared key */
+		if (val16)
+			use_shared_key = 1;
+
+		/* setting IV for auth seq #3 */
+		if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) {
+			val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30));
+			le_tmp32 = cpu_to_le32(val32);
+			pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &(pattrib->pktlen));
+
+			pattrib->iv_len = 4;
+		}
+
+		le_tmp16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen));
+
+		/*  setting auth seq number */
+		val16 = pmlmeinfo->auth_seq;
+		le_tmp16 = cpu_to_le16(val16);
+		pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp16, &(pattrib->pktlen));
+
+
+		/*  setting status code... */
+		le_tmp16 = cpu_to_le16(status);
+		pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp16, &(pattrib->pktlen));
+
+		/*  then checking to see if sending challenging text... */
+		if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) {
+			pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen));
+
+			SetPrivacy(fctrl);
+
+			pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+			pattrib->encrypt = _WEP40_;
+
+			pattrib->icv_len = 4;
+
+			pattrib->pktlen += pattrib->icv_len;
+		}
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	rtw_wep_encrypt(padapter, (u8 *)pmgntframe);
+	DBG_88E("%s\n", __func__);
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+
+void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	struct xmit_frame	*pmgntframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct pkt_attrib *pattrib;
+	unsigned char	*pbuf, *pframe;
+	unsigned short val;
+	unsigned short *fctrl;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+	u8 *ie = pnetwork->IEs;
+	__le16 lestatus, leval;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+	DBG_88E("%s\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN);
+	memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP))
+		SetFrameSubType(pwlanhdr, pkt_type);
+	else
+		return;
+
+	pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen += pattrib->hdrlen;
+	pframe += pattrib->hdrlen;
+
+	/* capability */
+	val = *(unsigned short *)rtw_get_capability_from_ie(ie);
+
+	pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen));
+
+	lestatus = cpu_to_le16(status);
+	pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&lestatus, &(pattrib->pktlen));
+
+	leval = cpu_to_le16(pstat->aid | BIT(14) | BIT(15));
+	pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&leval, &(pattrib->pktlen));
+
+	if (pstat->bssratelen <= 8) {
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen));
+	} else {
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen));
+		pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen-8), pstat->bssrateset+8, &(pattrib->pktlen));
+	}
+
+	if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) {
+		uint ie_len = 0;
+
+		/* FILL HT CAP INFO IE */
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			memcpy(pframe, pbuf, ie_len+2);
+			pframe += (ie_len+2);
+			pattrib->pktlen += (ie_len+2);
+		}
+
+		/* FILL HT ADD INFO IE */
+		pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+		if (pbuf && ie_len > 0) {
+			memcpy(pframe, pbuf, ie_len+2);
+			pframe += (ie_len+2);
+			pattrib->pktlen += (ie_len+2);
+		}
+	}
+
+	/* FILL WMM IE */
+	if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) {
+		uint ie_len = 0;
+		unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+
+		for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) {
+			pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
+			if (pbuf && _rtw_memcmp(pbuf+2, WMM_PARA_IE, 6)) {
+				memcpy(pframe, pbuf, ie_len+2);
+				pframe += (ie_len+2);
+				pattrib->pktlen += (ie_len+2);
+				break;
+			}
+
+			if ((pbuf == NULL) || (ie_len == 0))
+				break;
+		}
+	}
+
+	if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
+		pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen));
+
+	/* add WPS IE ie for wps 2.0 */
+	if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) {
+		memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len);
+
+		pframe += pmlmepriv->wps_assoc_resp_ie_len;
+		pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len;
+	}
+
+#ifdef CONFIG_88EU_P2P
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device)) {
+		u32 len;
+
+		len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code);
+
+		pframe += len;
+		pattrib->pktlen += len;
+	}
+#endif /* CONFIG_88EU_P2P */
+	pattrib->last_txcmdsz = pattrib->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+#endif
+}
+
+void issue_assocreq(struct adapter *padapter)
+{
+	int ret = _FAIL;
+	struct xmit_frame	*pmgntframe;
+	struct pkt_attrib	*pattrib;
+	unsigned char		*pframe, *p;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short	*fctrl;
+	__le16		le_tmp;
+	unsigned int	i, j, ie_len, index = 0;
+	unsigned char	rf_type, bssrate[NumRates], sta_bssrate[NumRates];
+	struct ndis_802_11_var_ie *pIE;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct xmit_priv		*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	int	bssrate_len = 0, sta_bssrate_len = 0;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8 p2pie[255] = { 0x00 };
+	u16 p2pielen = 0;
+#endif /* CONFIG_88EU_P2P */
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ASSOCREQ);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* caps */
+
+	memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2);
+
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/* listen interval */
+	/* todo: listen interval for power saving */
+	le_tmp = cpu_to_le16(3);
+	memcpy(pframe , (unsigned char *)&le_tmp, 2);
+	pframe += 2;
+	pattrib->pktlen += 2;
+
+	/* SSID */
+	pframe = rtw_set_ie(pframe, _SSID_IE_,  pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen));
+
+	/* supported rate & extended supported rate */
+
+	/*  Check if the AP's supported rates are also supported by STA. */
+	get_rate_set(padapter, sta_bssrate, &sta_bssrate_len);
+
+	if (pmlmeext->cur_channel == 14)/*  for JAPAN, channel 14 can only uses B Mode(CCK) */
+		sta_bssrate_len = 4;
+
+	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+		if (pmlmeinfo->network.SupportedRates[i] == 0)
+			break;
+		DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]);
+	}
+
+	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+		if (pmlmeinfo->network.SupportedRates[i] == 0)
+			break;
+
+		/*  Check if the AP's supported rates are also supported by STA. */
+		for (j = 0; j < sta_bssrate_len; j++) {
+			 /*  Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */
+			if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK)
+					== (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK))
+				break;
+		}
+
+		if (j == sta_bssrate_len) {
+			/*  the rate is not supported by STA */
+			DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]);
+		} else {
+			/*  the rate is supported by STA */
+			bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
+		}
+	}
+
+	bssrate_len = index;
+	DBG_88E("bssrate_len=%d\n", bssrate_len);
+
+	if (bssrate_len == 0) {
+		rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf);
+		rtw_free_xmitframe(pxmitpriv, pmgntframe);
+		goto exit; /* don't connect to AP if no joint supported rate */
+	}
+
+
+	if (bssrate_len > 8) {
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen));
+		pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen));
+	} else {
+		pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen));
+	}
+
+	/* RSN */
+	p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie)));
+	if (p != NULL)
+		pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen));
+
+	/* HT caps */
+	if (padapter->mlmepriv.htpriv.ht_option) {
+		p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie)));
+		if ((p != NULL) && (!(is_ap_in_tkip(padapter)))) {
+			memcpy(&(pmlmeinfo->HT_caps), (p + 2), sizeof(struct HT_caps_element));
+
+			/* to disable 40M Hz support while gd_bw_40MHz_en = 0 */
+			if (pregpriv->cbw40_enable == 0)
+				pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= cpu_to_le16(~(BIT(6) | BIT(1)));
+			else
+				pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(BIT(1));
+
+			/* todo: disable SM power save mode */
+			pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x000c);
+
+			rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+			switch (rf_type) {
+			case RF_1T1R:
+				if (pregpriv->rx_stbc)
+					pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */
+				memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16);
+				break;
+			case RF_2T2R:
+			case RF_1T2R:
+			default:
+				if ((pregpriv->rx_stbc == 0x3) ||/* enable for 2.4/5 GHz */
+				    ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */
+				    (pregpriv->wifi_spec == 1)) {
+					DBG_88E("declare supporting RX STBC\n");
+					pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */
+				}
+				memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16);
+				break;
+			}
+			pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen));
+		}
+	}
+
+	/* vendor specific IE, such as WPA, WMM, WPS */
+	for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) {
+		pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_:
+			if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) ||
+			    (_rtw_memcmp(pIE->data, WMM_OUI, 4)) ||
+			    (_rtw_memcmp(pIE->data, WPS_OUI, 4))) {
+				if (!padapter->registrypriv.wifi_spec) {
+					/* Commented by Kurt 20110629 */
+					/* In some older APs, WPS handshake */
+					/* would be fail if we append vender extensions informations to AP */
+					if (_rtw_memcmp(pIE->data, WPS_OUI, 4))
+						pIE->Length = 14;
+				}
+				pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &(pattrib->pktlen));
+			}
+			break;
+		default:
+			break;
+		}
+		i += (pIE->Length + 2);
+	}
+
+	if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
+		pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen));
+
+#ifdef CONFIG_88EU_P2P
+
+	if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
+		/*	Should add the P2P IE in the association request frame. */
+		/*	P2P OUI */
+
+		p2pielen = 0;
+		p2pie[p2pielen++] = 0x50;
+		p2pie[p2pielen++] = 0x6F;
+		p2pie[p2pielen++] = 0x9A;
+		p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+		/*	Commented by Albert 20101109 */
+		/*	According to the P2P Specification, the association request frame should contain 3 P2P attributes */
+		/*	1. P2P Capability */
+		/*	2. Extended Listen Timing */
+		/*	3. Device Info */
+		/*	Commented by Albert 20110516 */
+		/*	4. P2P Interface */
+
+		/*	P2P Capability */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	Device Capability Bitmap, 1 byte */
+		p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+		/*	Group Capability Bitmap, 1 byte */
+		if (pwdinfo->persistent_supported)
+			p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+		else
+			p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+		/*	Extended Listen Timing */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	Availability Period */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+		p2pielen += 2;
+
+		/*	Availability Interval */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+		p2pielen += 2;
+
+		/*	Device Info */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+		/*	Length: */
+		/*	21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+		/*	+ NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+		p2pielen += 2;
+
+		/*	Value: */
+		/*	P2P Device Address */
+		memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+		p2pielen += ETH_ALEN;
+
+		/*	Config Method */
+		/*	This field should be big endian. Noted by P2P specification. */
+		if ((pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) ||
+		    (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN))
+			*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+		else
+			*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC);
+
+		p2pielen += 2;
+
+		/*	Primary Device Type */
+		/*	Category ID */
+		*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+		p2pielen += 2;
+
+		/*	OUI */
+		*(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+		p2pielen += 4;
+
+		/*	Sub Category ID */
+		*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+		p2pielen += 2;
+
+		/*	Number of Secondary Device Types */
+		p2pie[p2pielen++] = 0x00;	/*	No Secondary Device Type List */
+
+		/*	Device Name */
+		/*	Type: */
+		*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+		p2pielen += 2;
+
+		/*	Length: */
+		*(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+		p2pielen += 2;
+
+		/*	Value: */
+		memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+		p2pielen += pwdinfo->device_name_len;
+
+		/*	P2P Interface */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_INTERFACE;
+
+		/*	Length: */
+		*(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D);
+		p2pielen += 2;
+
+		/*	Value: */
+		memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);	/*	P2P Device Address */
+		p2pielen += ETH_ALEN;
+
+		p2pie[p2pielen++] = 1;	/*	P2P Interface Address Count */
+
+		memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);	/*	P2P Interface Address List */
+		p2pielen += ETH_ALEN;
+
+		pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen);
+	}
+
+#endif /* CONFIG_88EU_P2P */
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+	dump_mgntframe(padapter, pmgntframe);
+
+	ret = _SUCCESS;
+
+exit:
+	if (ret == _SUCCESS)
+		rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen);
+	else
+		rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len);
+
+	return;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack)
+{
+	int ret = _FAIL;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv	*pxmitpriv;
+	struct mlme_ext_priv	*pmlmeext;
+	struct mlme_ext_info	*pmlmeinfo;
+
+	if (!padapter)
+		goto exit;
+
+	pxmitpriv = &(padapter->xmitpriv);
+	pmlmeext = &(padapter->mlmeextpriv);
+	pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+	pattrib->retry_ctrl = false;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+		SetFrDs(fctrl);
+	else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+		SetToDs(fctrl);
+
+	if (power_mode)
+		SetPwrMgt(fctrl);
+
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_DATA_NULL);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	if (wait_ack) {
+		ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+	} else {
+		dump_mgntframe(padapter, pmgntframe);
+		ret = _SUCCESS;
+	}
+
+exit:
+	return ret;
+}
+
+
+/* when wait_ms > 0 , this function shoule be called at process context */
+/* da == NULL for station mode */
+int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms)
+{
+	int ret;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	/* da == NULL, assum it's null data for sta to ap*/
+	if (da == NULL)
+		da = get_my_bssid(&(pmlmeinfo->network));
+
+	do {
+		ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false);
+
+		i++;
+
+		if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	if (ret != _FAIL) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+
+	if (try_cnt && wait_ms) {
+		if (da)
+			DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+		else
+			DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+	}
+exit:
+	return ret;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack)
+{
+	int ret = _FAIL;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl, *qc;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	DBG_88E("%s\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	pattrib->hdrlen += 2;
+	pattrib->qos_en = true;
+	pattrib->eosp = 1;
+	pattrib->ack_policy = 0;
+	pattrib->mdata = 0;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+		SetFrDs(fctrl);
+	else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+		SetToDs(fctrl);
+
+	if (pattrib->mdata)
+		SetMData(fctrl);
+
+	qc = (unsigned short *)(pframe + pattrib->hdrlen - 2);
+
+	SetPriority(qc, tid);
+
+	SetEOSP(qc, pattrib->eosp);
+
+	SetAckpolicy(qc, pattrib->ack_policy);
+
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	if (wait_ack) {
+		ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+	} else {
+		dump_mgntframe(padapter, pmgntframe);
+		ret = _SUCCESS;
+	}
+
+exit:
+	return ret;
+}
+
+/* when wait_ms > 0 , this function shoule be called at process context */
+/* da == NULL for station mode */
+int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms)
+{
+	int ret;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	/* da == NULL, assum it's null data for sta to ap*/
+	if (da == NULL)
+		da = get_my_bssid(&(pmlmeinfo->network));
+
+	do {
+		ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false);
+
+		i++;
+
+		if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	if (ret != _FAIL) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+
+	if (try_cnt && wait_ms) {
+		if (da)
+			DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+		else
+			DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+	}
+exit:
+	return ret;
+}
+
+static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	int ret = _FAIL;
+	__le16 le_tmp;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+#ifdef CONFIG_88EU_P2P
+	if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
+		_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+		_set_timer(&pwdinfo->reset_ch_sitesurvey, 10);
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+	pattrib->retry_ctrl = false;
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_DEAUTH);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	le_tmp = cpu_to_le16(reason);
+	pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&le_tmp, &(pattrib->pktlen));
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+
+	if (wait_ack) {
+		ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe);
+	} else {
+		dump_mgntframe(padapter, pmgntframe);
+		ret = _SUCCESS;
+	}
+
+exit:
+	return ret;
+}
+
+int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason)
+{
+	DBG_88E("%s to %pM\n", __func__, da);
+	return _issue_deauth(padapter, da, reason, false);
+}
+
+int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt,
+	int wait_ms)
+{
+	int ret;
+	int i = 0;
+	u32 start = rtw_get_current_time();
+
+	do {
+		ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? true : false);
+
+		i++;
+
+		if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+			break;
+
+		if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+			rtw_msleep_os(wait_ms);
+	} while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+	if (ret != _FAIL) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+
+	if (try_cnt && wait_ms) {
+		if (da)
+			DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+		else
+			DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+				FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter),
+				ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start));
+	}
+exit:
+	return ret;
+}
+
+void issue_action_spct_ch_switch (struct adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char				*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short			*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+
+
+	DBG_88E(FUNC_NDEV_FMT" ra =%pM, ch:%u, offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev), ra, new_ch, ch_offset);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN); /* TA */
+	memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* category, action */
+	{
+		u8 category, action;
+		category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT;
+		action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH;
+
+		pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+		pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	}
+
+	pframe = rtw_set_ie_ch_switch (pframe, &(pattrib->pktlen), 0, new_ch, 0);
+	pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen),
+		hal_ch_offset_to_secondary_ch_offset(ch_offset));
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+}
+
+void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status)
+{
+	u8 category = RTW_WLAN_CATEGORY_BACK;
+	u16 start_seq;
+	u16 BA_para_set;
+	u16 reason_code;
+	u16 BA_timeout_value;
+	__le16	le_tmp;
+	u16 BA_starting_seqctrl = 0;
+	enum ht_cap_ampdu_factor max_rx_ampdu_factor;
+	struct xmit_frame *pmgntframe;
+	struct pkt_attrib *pattrib;
+	u8 *pframe;
+	struct rtw_ieee80211_hdr *pwlanhdr;
+	u16 *fctrl;
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_info *psta;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct registry_priv *pregpriv = &padapter->registrypriv;
+
+	DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	/* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+
+	if (category == 3) {
+		switch (action) {
+		case 0: /* ADDBA req */
+			do {
+				pmlmeinfo->dialogToken++;
+			} while (pmlmeinfo->dialogToken == 0);
+			pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen));
+
+			BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */
+			le_tmp = cpu_to_le16(BA_para_set);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+
+			BA_timeout_value = 5000;/*  5ms */
+			le_tmp = cpu_to_le16(BA_timeout_value);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+
+			psta = rtw_get_stainfo(pstapriv, raddr);
+			if (psta != NULL) {
+				start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1;
+
+				DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07);
+
+				psta->BA_starting_seqctrl[status & 0x07] = start_seq;
+
+				BA_starting_seqctrl = start_seq << 4;
+			}
+			le_tmp = cpu_to_le16(BA_starting_seqctrl);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+			break;
+		case 1: /* ADDBA rsp */
+			pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen));
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen));
+			rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
+			if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor)
+				BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+			else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor)
+				BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */
+			else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor)
+				BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */
+			else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor)
+				BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */
+			else
+				BA_para_set = (((pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+
+			if (pregpriv->ampdu_amsdu == 0)/* disabled */
+				BA_para_set = BA_para_set & ~BIT(0);
+			else if (pregpriv->ampdu_amsdu == 1)/* enabled */
+				BA_para_set = BA_para_set | BIT(0);
+			le_tmp = cpu_to_le16(BA_para_set);
+
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen));
+			break;
+		case 2:/* DELBA */
+			BA_para_set = (status & 0x1F) << 3;
+			le_tmp = cpu_to_le16(BA_para_set);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+
+			reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */
+			le_tmp = cpu_to_le16(reason_code);
+			pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(le_tmp)), &(pattrib->pktlen));
+			break;
+		default:
+			break;
+		}
+	}
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+}
+
+static void issue_action_BSSCoexistPacket(struct adapter *padapter)
+{
+	unsigned long	irqL;
+	struct list_head *plist, *phead;
+	unsigned char category, action;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char				*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short			*fctrl;
+	struct	wlan_network	*pnetwork = NULL;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	u8 InfoContent[16] = {0};
+	u8 ICS[8][15];
+	if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0))
+		return;
+
+	if (pmlmeinfo->bwmode_updated)
+		return;
+
+
+	DBG_88E("%s\n", __func__);
+
+
+	category = RTW_WLAN_CATEGORY_PUBLIC;
+	action = ACT_PUBLIC_BSSCOEXIST;
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+
+
+	/*  */
+	if (pmlmepriv->num_FortyMHzIntolerant > 0) {
+		u8 iedata = 0;
+
+		iedata |= BIT(2);/* 20 MHz BSS Width Request */
+
+		pframe = rtw_set_ie(pframe, EID_BSSCoexistence,  1, &iedata, &(pattrib->pktlen));
+	}
+
+
+	/*  */
+	_rtw_memset(ICS, 0, sizeof(ICS));
+	if (pmlmepriv->num_sta_no_ht > 0) {
+		int i;
+
+		_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+		phead = get_list_head(queue);
+		plist = get_next(phead);
+
+		while (1) {
+			int len;
+			u8 *p;
+			struct wlan_bssid_ex *pbss_network;
+
+			if (rtw_end_of_queue_search(phead, plist))
+				break;
+
+			pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+			plist = get_next(plist);
+
+			pbss_network = (struct wlan_bssid_ex *)&pnetwork->network;
+
+			p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_);
+			if ((p == NULL) || (len == 0)) { /* non-HT */
+				if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14))
+					continue;
+
+				ICS[0][pbss_network->Configuration.DSConfig] = 1;
+
+				if (ICS[0][0] == 0)
+					ICS[0][0] = 1;
+			}
+		}
+		_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+		for (i = 0; i < 8; i++) {
+			if (ICS[i][0] == 1) {
+				int j, k = 0;
+
+				InfoContent[k] = i;
+				/* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */
+				k++;
+
+				for (j = 1; j <= 14; j++) {
+					if (ICS[i][j] == 1) {
+						if (k < 16) {
+							InfoContent[k] = j; /* channel number */
+							/* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */
+							k++;
+						}
+					}
+				}
+
+				pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen));
+			}
+		}
+	}
+
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+}
+
+unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr)
+{
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta = NULL;
+	/* struct recv_reorder_ctrl *preorder_ctrl; */
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u16 tid;
+
+	if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+		if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+			return _SUCCESS;
+
+	psta = rtw_get_stainfo(pstapriv, addr);
+	if (psta == NULL)
+		return _SUCCESS;
+
+	if (initiator == 0) { /*  recipient */
+		for (tid = 0; tid < MAXTID; tid++) {
+			if (psta->recvreorder_ctrl[tid].enable) {
+				DBG_88E("rx agg disable tid(%d)\n", tid);
+				issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F));
+				psta->recvreorder_ctrl[tid].enable = false;
+				psta->recvreorder_ctrl[tid].indicate_seq = 0xffff;
+			}
+		}
+	} else if (initiator == 1) { /*  originator */
+		for (tid = 0; tid < MAXTID; tid++) {
+			if (psta->htpriv.agg_enable_bitmap & BIT(tid)) {
+				DBG_88E("tx agg disable tid(%d)\n", tid);
+				issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F));
+				psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+				psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+			}
+		}
+	}
+
+	return _SUCCESS;
+}
+
+unsigned int send_beacon(struct adapter *padapter)
+{
+	u8 bxmitok = false;
+	int	issue = 0;
+	int poll = 0;
+
+	u32 start = rtw_get_current_time();
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL);
+	do {
+		issue_beacon(padapter, 100);
+		issue++;
+		do {
+			rtw_yield_os();
+			rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok));
+			poll++;
+		} while ((poll%10) != 0 && !bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
+	} while (!bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped);
+
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+		return _FAIL;
+	if (!bxmitok) {
+		DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start));
+		return _FAIL;
+	} else {
+		u32 passing_time = rtw_get_passing_time_ms(start);
+
+		if (passing_time > 100 || issue > 3)
+			DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start));
+		return _SUCCESS;
+	}
+}
+
+/****************************************************************************
+
+Following are some utitity fuctions for WiFi MLME
+
+*****************************************************************************/
+
+void site_survey(struct adapter *padapter)
+{
+	unsigned char		survey_channel = 0, val8;
+	enum rt_scan_type ScanType = SCAN_PASSIVE;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u32 initialgain = 0;
+
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) {
+		if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+			survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx];
+		} else {
+			survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx];
+		}
+		ScanType = SCAN_ACTIVE;
+	} else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) {
+		/*	Commented by Albert 2011/06/03 */
+		/*	The driver is in the find phase, it should go through the social channel. */
+		int ch_set_idx;
+		survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx];
+		ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, survey_channel);
+		if (ch_set_idx >= 0)
+			ScanType = pmlmeext->channel_set[ch_set_idx].ScanType;
+		else
+			ScanType = SCAN_ACTIVE;
+	} else
+#endif /* CONFIG_88EU_P2P */
+	{
+		struct rtw_ieee80211_channel *ch;
+		if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) {
+			ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx];
+			survey_channel = ch->hw_value;
+			ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE;
+		}
+	}
+
+	if (survey_channel != 0) {
+		/* PAUSE 4-AC Queue when site_survey */
+		/* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+		/* val8 |= 0x0f; */
+		/* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+		if (pmlmeext->sitesurvey_res.channel_idx == 0)
+			set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+		else
+			SelectChannel(padapter, survey_channel);
+
+		if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */
+			#ifdef CONFIG_88EU_P2P
+			if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) ||
+			    rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) {
+				issue_probereq_p2p(padapter, NULL);
+				issue_probereq_p2p(padapter, NULL);
+				issue_probereq_p2p(padapter, NULL);
+			} else
+			#endif /* CONFIG_88EU_P2P */
+			{
+				int i;
+				for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+					if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
+						/* todo: to issue two probe req??? */
+						issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+						/* rtw_msleep_os(SURVEY_TO>>1); */
+						issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL);
+					}
+				}
+
+				if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
+					/* todo: to issue two probe req??? */
+					issue_probereq(padapter, NULL, NULL);
+					/* rtw_msleep_os(SURVEY_TO>>1); */
+					issue_probereq(padapter, NULL, NULL);
+				}
+			}
+		}
+
+		set_survey_timer(pmlmeext, pmlmeext->chan_scan_time);
+	} else {
+		/*	channel number is 0 or this channel is not valid. */
+
+#ifdef CONFIG_88EU_P2P
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) {
+			if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) {
+				/*	Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */
+				/*	This will let the following flow to run the scanning end. */
+				rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+			}
+		}
+
+		if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) {
+			/*	Set the P2P State to the listen state of find phase and set the current channel to the listen channel */
+			set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+			rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN);
+			pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+
+			initialgain = 0xff; /* restore RX GAIN */
+			rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+			/* turn on dynamic functions */
+			Restore_DM_Func_Flag(padapter);
+			/* Switch_DM_Func(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */
+
+			_set_timer(&pwdinfo->find_phase_timer, (u32)((u32)(pwdinfo->listen_dwell) * 100));
+		} else
+#endif /* CONFIG_88EU_P2P */
+		{
+			/*  20100721:Interrupt scan operation here. */
+			/*  For SW antenna diversity before link, it needs to switch to another antenna and scan again. */
+			/*  It compares the scan result and select beter one to do connection. */
+			if (rtw_hal_antdiv_before_linked(padapter)) {
+				pmlmeext->sitesurvey_res.bss_cnt = 0;
+				pmlmeext->sitesurvey_res.channel_idx = -1;
+				pmlmeext->chan_scan_time = SURVEY_TO / 2;
+				set_survey_timer(pmlmeext, pmlmeext->chan_scan_time);
+				return;
+			}
+#ifdef CONFIG_88EU_P2P
+			if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH))
+				rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+			rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+#endif /* CONFIG_88EU_P2P */
+
+			pmlmeext->sitesurvey_res.state = SCAN_COMPLETE;
+
+			/* switch back to the original channel */
+
+#ifdef CONFIG_88EU_P2P
+			if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN))
+				set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+			else
+				set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+#endif /* CONFIG_88EU_P2P */
+
+			/* flush 4-AC Queue after site_survey */
+			/* val8 = 0; */
+			/* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+
+			/* config MSR */
+			Set_MSR(padapter, (pmlmeinfo->state & 0x3));
+
+			initialgain = 0xff; /* restore RX GAIN */
+			rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+			/* turn on dynamic functions */
+			Restore_DM_Func_Flag(padapter);
+			/* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */
+
+			if (is_client_associated_to_ap(padapter))
+				issue_nulldata(padapter, NULL, 0, 3, 500);
+
+			val8 = 0; /* survey done */
+			rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+			report_surveydone_event(padapter);
+
+			pmlmeext->chan_scan_time = SURVEY_TO;
+			pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+
+			issue_action_BSSCoexistPacket(padapter);
+			issue_action_BSSCoexistPacket(padapter);
+			issue_action_BSSCoexistPacket(padapter);
+		}
+	}
+	return;
+}
+
+/* collect bss info from Beacon and Probe request/response frames. */
+u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, struct wlan_bssid_ex *bssid)
+{
+	int	i;
+	u32	len;
+	u8 *p;
+	u16 val16, subtype;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	u32	packet_len = precv_frame->u.hdr.len;
+	u8 ie_offset;
+	struct registry_priv	*pregistrypriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	__le32 le32_tmp;
+
+	len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	if (len > MAX_IE_SZ)
+		return _FAIL;
+
+	_rtw_memset(bssid, 0, sizeof(struct wlan_bssid_ex));
+
+	subtype = GetFrameSubType(pframe);
+
+	if (subtype == WIFI_BEACON) {
+		bssid->Reserved[0] = 1;
+		ie_offset = _BEACON_IE_OFFSET_;
+	} else {
+		/*  FIXME : more type */
+		if (subtype == WIFI_PROBEREQ) {
+			ie_offset = _PROBEREQ_IE_OFFSET_;
+			bssid->Reserved[0] = 2;
+		} else if (subtype == WIFI_PROBERSP) {
+			ie_offset = _PROBERSP_IE_OFFSET_;
+			bssid->Reserved[0] = 3;
+		} else {
+			bssid->Reserved[0] = 0;
+			ie_offset = _FIXED_IE_LENGTH_;
+		}
+	}
+
+	bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
+
+	/* below is to copy the information element */
+	bssid->IELength = len;
+	memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
+
+	/* get the signal strength */
+	bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.recvpower; /*  in dBM.raw data */
+	bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */
+	bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */
+	rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA,  &bssid->PhyInfo.Optimum_antenna);
+
+	/*  checking SSID */
+	p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset);
+	if (p == NULL) {
+		DBG_88E("marc: cannot find SSID for survey event\n");
+		return _FAIL;
+	}
+
+	if (*(p + 1)) {
+		if (len > NDIS_802_11_LENGTH_SSID) {
+			DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+			return _FAIL;
+		}
+		memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
+		bssid->Ssid.SsidLength = *(p + 1);
+	} else {
+		bssid->Ssid.SsidLength = 0;
+	}
+
+	_rtw_memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+	/* checking rate info... */
+	i = 0;
+	p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
+	if (p != NULL) {
+		if (len > NDIS_802_11_LENGTH_RATES_EX) {
+			DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+			return _FAIL;
+		}
+		memcpy(bssid->SupportedRates, (p + 2), len);
+		i = len;
+	}
+
+	p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
+	if (p != NULL) {
+		if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) {
+			DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+			return _FAIL;
+		}
+		memcpy(bssid->SupportedRates + i, (p + 2), len);
+	}
+
+	/* todo: */
+	bssid->NetworkTypeInUse = Ndis802_11OFDM24;
+
+	if (bssid->IELength < 12)
+		return _FAIL;
+
+	/*  Checking for DSConfig */
+	p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset);
+
+	bssid->Configuration.DSConfig = 0;
+	bssid->Configuration.Length = 0;
+
+	if (p) {
+		bssid->Configuration.DSConfig = *(p + 2);
+	} else {/*  In 5G, some ap do not have DSSET IE */
+		/*  checking HT info for channel */
+		p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset);
+		if (p) {
+			struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2);
+			bssid->Configuration.DSConfig = HT_info->primary_channel;
+		} else { /*  use current channel */
+			bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter);
+		}
+	}
+
+	if (subtype == WIFI_PROBEREQ) {
+		/*  FIXME */
+		bssid->InfrastructureMode = Ndis802_11Infrastructure;
+		memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN);
+		bssid->Privacy = 1;
+		return _SUCCESS;
+	}
+
+	memcpy(&le32_tmp, rtw_get_beacon_interval_from_ie(bssid->IEs), 2);
+	bssid->Configuration.BeaconPeriod = le32_to_cpu(le32_tmp);
+
+	val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid);
+
+	if (val16 & BIT(0)) {
+		bssid->InfrastructureMode = Ndis802_11Infrastructure;
+		memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN);
+	} else {
+		bssid->InfrastructureMode = Ndis802_11IBSS;
+		memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN);
+	}
+
+	if (val16 & BIT(4))
+		bssid->Privacy = 1;
+	else
+		bssid->Privacy = 0;
+
+	bssid->Configuration.ATIMWindow = 0;
+
+	/* 20/40 BSS Coexistence check */
+	if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) {
+		struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+		p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset);
+		if (p && len > 0) {
+			struct HT_caps_element	*pHT_caps;
+			pHT_caps = (struct HT_caps_element *)(p + 2);
+
+			if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info)&BIT(14))
+				pmlmepriv->num_FortyMHzIntolerant++;
+		} else {
+			pmlmepriv->num_sta_no_ht++;
+		}
+	}
+
+	/*  mark bss info receving from nearby channel as SignalQuality 101 */
+	if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter))
+		bssid->PhyInfo.SignalQuality = 101;
+	return _SUCCESS;
+}
+
+void start_create_ibss(struct adapter *padapter)
+{
+	unsigned short	caps;
+	u8 val8;
+	u8 join_type;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+	pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
+	pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
+
+	/* update wireless mode */
+	update_wireless_mode(padapter);
+
+	/* udpate capability */
+	caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork);
+	update_capinfo(padapter, caps);
+	if (caps&cap_IBSS) {/* adhoc master */
+		val8 = 0xcf;
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+		/* switch channel */
+		/* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */
+		set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+		beacon_timing_control(padapter);
+
+		/* set msr to WIFI_FW_ADHOC_STATE */
+		pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+		Set_MSR(padapter, (pmlmeinfo->state & 0x3));
+
+		/* issue beacon */
+		if (send_beacon(padapter) == _FAIL) {
+			RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n"));
+
+			report_join_res(padapter, -1);
+			pmlmeinfo->state = WIFI_FW_NULL_STATE;
+		} else {
+			rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress);
+			join_type = 0;
+			rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+			report_join_res(padapter, 1);
+			pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+		}
+	} else {
+		DBG_88E("start_create_ibss, invalid cap:%x\n", caps);
+		return;
+	}
+}
+
+void start_clnt_join(struct adapter *padapter)
+{
+	unsigned short	caps;
+	u8 val8;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+	int beacon_timeout;
+
+	pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
+	pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
+
+	/* update wireless mode */
+	update_wireless_mode(padapter);
+
+	/* udpate capability */
+	caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork);
+	update_capinfo(padapter, caps);
+	if (caps&cap_ESS) {
+		Set_MSR(padapter, WIFI_FW_STATION_STATE);
+
+		val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf;
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+		/* switch channel */
+		set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+		/* here wait for receiving the beacon to start auth */
+		/* and enable a timer */
+		beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval);
+		set_link_timer(pmlmeext, beacon_timeout);
+		_set_timer(&padapter->mlmepriv.assoc_timer,
+			   (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout);
+
+		pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE;
+	} else if (caps&cap_IBSS) { /* adhoc client */
+		Set_MSR(padapter, WIFI_FW_ADHOC_STATE);
+
+		val8 = 0xcf;
+		rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+		/* switch channel */
+		set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+		beacon_timing_control(padapter);
+
+		pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+
+		report_join_res(padapter, 1);
+	} else {
+		return;
+	}
+}
+
+void start_clnt_auth(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL);
+	pmlmeinfo->state |= WIFI_FW_AUTH_STATE;
+
+	pmlmeinfo->auth_seq = 1;
+	pmlmeinfo->reauth_count = 0;
+	pmlmeinfo->reassoc_count = 0;
+	pmlmeinfo->link_count = 0;
+	pmlmeext->retry = 0;
+
+
+	/*  Because of AP's not receiving deauth before */
+	/*  AP may: 1)not response auth or 2)deauth us after link is complete */
+	/*  issue deauth before issuing auth to deal with the situation */
+	/*	Commented by Albert 2012/07/21 */
+	/*	For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */
+	issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING);
+
+	DBG_88E_LEVEL(_drv_info_, "start auth\n");
+	issue_auth(padapter, NULL, 0);
+
+	set_link_timer(pmlmeext, REAUTH_TO);
+}
+
+
+void start_clnt_assoc(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE));
+	pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE);
+
+	issue_assocreq(padapter);
+
+	set_link_timer(pmlmeext, REASSOC_TO);
+}
+
+unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	/* check A3 */
+	if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN)))
+		return _SUCCESS;
+
+	DBG_88E("%s\n", __func__);
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) {
+		if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
+			pmlmeinfo->state = WIFI_FW_NULL_STATE;
+			report_del_sta_event(padapter, MacAddr, reason);
+		} else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) {
+			pmlmeinfo->state = WIFI_FW_NULL_STATE;
+			report_join_res(padapter, -2);
+		}
+	}
+	return _SUCCESS;
+}
+
+static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid)
+{
+	struct registry_priv *pregistrypriv;
+	struct mlme_ext_priv *pmlmeext;
+	struct rt_channel_info *chplan_new;
+	u8 channel;
+	u8 i;
+
+	pregistrypriv = &padapter->registrypriv;
+	pmlmeext = &padapter->mlmeextpriv;
+
+	/*  Adjust channel plan by AP Country IE */
+	if (pregistrypriv->enable80211d &&
+	    (!pmlmeext->update_channel_plan_by_ap_done)) {
+		u8 *ie, *p;
+		u32 len;
+		struct rt_channel_plan chplan_ap;
+		struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM];
+		u8 country[4];
+		u8 fcn; /*  first channel number */
+		u8 noc; /*  number of channel */
+		u8 j, k;
+
+		ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+		if (!ie)
+			return;
+		if (len < 6)
+			return;
+		ie += 2;
+		p = ie;
+		ie += len;
+
+		_rtw_memset(country, 0, 4);
+		memcpy(country, p, 3);
+		p += 3;
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+			 ("%s: 802.11d country =%s\n", __func__, country));
+
+		i = 0;
+		while ((ie - p) >= 3) {
+			fcn = *(p++);
+			noc = *(p++);
+			p++;
+
+			for (j = 0; j < noc; j++) {
+				if (fcn <= 14)
+					channel = fcn + j; /*  2.4 GHz */
+				else
+					channel = fcn + j*4; /*  5 GHz */
+
+				chplan_ap.Channel[i++] = channel;
+			}
+		}
+		chplan_ap.Len = i;
+
+		memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta));
+
+		_rtw_memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set));
+		chplan_new = pmlmeext->channel_set;
+
+		i = 0;
+		j = 0;
+		k = 0;
+		if (pregistrypriv->wireless_mode & WIRELESS_11G) {
+			do {
+				if ((i == MAX_CHANNEL_NUM) ||
+				    (chplan_sta[i].ChannelNum == 0) ||
+				    (chplan_sta[i].ChannelNum > 14))
+					break;
+
+				if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14))
+					break;
+
+				if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) {
+					chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+					chplan_new[k].ScanType = SCAN_ACTIVE;
+					i++;
+					j++;
+					k++;
+				} else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) {
+					chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+					chplan_new[k].ScanType = SCAN_PASSIVE;
+					i++;
+					k++;
+				} else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) {
+					chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+					chplan_new[k].ScanType = SCAN_ACTIVE;
+					j++;
+					k++;
+				}
+			} while (1);
+
+			/*  change AP not support channel to Passive scan */
+			while ((i < MAX_CHANNEL_NUM) &&
+			       (chplan_sta[i].ChannelNum != 0) &&
+			       (chplan_sta[i].ChannelNum <= 14)) {
+				chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+				chplan_new[k].ScanType = SCAN_PASSIVE;
+				i++;
+				k++;
+			}
+
+			/*  add channel AP supported */
+			while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) {
+				chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+				chplan_new[k].ScanType = SCAN_ACTIVE;
+				j++;
+				k++;
+			}
+		} else {
+			/*  keep original STA 2.4G channel plan */
+			while ((i < MAX_CHANNEL_NUM) &&
+			       (chplan_sta[i].ChannelNum != 0) &&
+			       (chplan_sta[i].ChannelNum <= 14)) {
+				chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+				chplan_new[k].ScanType = chplan_sta[i].ScanType;
+				i++;
+				k++;
+			}
+
+			/*  skip AP 2.4G channel plan */
+			while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14))
+				j++;
+		}
+
+		/*  keep original STA 5G channel plan */
+		while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
+			chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+			chplan_new[k].ScanType = chplan_sta[i].ScanType;
+			i++;
+			k++;
+		}
+
+		pmlmeext->update_channel_plan_by_ap_done = 1;
+	}
+
+	/*  If channel is used by AP, set channel scan type to active */
+	channel = bssid->Configuration.DSConfig;
+	chplan_new = pmlmeext->channel_set;
+	i = 0;
+	while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) {
+		if (chplan_new[i].ChannelNum == channel) {
+			if (chplan_new[i].ScanType == SCAN_PASSIVE) {
+				chplan_new[i].ScanType = SCAN_ACTIVE;
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+					 ("%s: change channel %d scan type from passive to active\n",
+					 __func__, channel));
+			}
+			break;
+		}
+		i++;
+	}
+}
+
+/****************************************************************************
+
+Following are the functions to report events
+
+*****************************************************************************/
+
+void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	struct cmd_obj *pcmd_obj;
+	u8 *pevtcmd;
+	u32 cmdsz;
+	struct survey_event	*psurvey_evt;
+	struct C2HEvent_Header *pc2h_evt_hdr;
+	struct mlme_ext_priv *pmlmeext;
+	struct cmd_priv *pcmdpriv;
+	/* u8 *pframe = precv_frame->u.hdr.rx_data; */
+	/* uint len = precv_frame->u.hdr.len; */
+
+	if (!padapter)
+		return;
+
+	pmlmeext = &padapter->mlmeextpriv;
+	pcmdpriv = &padapter->cmdpriv;
+
+
+	pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd_obj == NULL)
+		return;
+
+	cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		kfree(pcmd_obj);
+		return;
+	}
+
+	_rtw_init_listhead(&pcmd_obj->list);
+
+	pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+	pcmd_obj->cmdsz = cmdsz;
+	pcmd_obj->parmbuf = pevtcmd;
+
+	pcmd_obj->rsp = NULL;
+	pcmd_obj->rspsz  = 0;
+
+	pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+	pc2h_evt_hdr->len = sizeof(struct survey_event);
+	pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey);
+	pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+	psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+
+	if (collect_bss_info(padapter, precv_frame, (struct wlan_bssid_ex *)&psurvey_evt->bss) == _FAIL) {
+		kfree(pcmd_obj);
+		kfree(pevtcmd);
+		return;
+	}
+
+	process_80211d(padapter, &psurvey_evt->bss);
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	pmlmeext->sitesurvey_res.bss_cnt++;
+
+	return;
+}
+
+void report_surveydone_event(struct adapter *padapter)
+{
+	struct cmd_obj *pcmd_obj;
+	u8 *pevtcmd;
+	u32 cmdsz;
+	struct surveydone_event *psurveydone_evt;
+	struct C2HEvent_Header	*pc2h_evt_hdr;
+	struct mlme_ext_priv		*pmlmeext = &padapter->mlmeextpriv;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+	pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd_obj == NULL)
+		return;
+
+	cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		kfree(pcmd_obj);
+		return;
+	}
+
+	_rtw_init_listhead(&pcmd_obj->list);
+
+	pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+	pcmd_obj->cmdsz = cmdsz;
+	pcmd_obj->parmbuf = pevtcmd;
+
+	pcmd_obj->rsp = NULL;
+	pcmd_obj->rspsz  = 0;
+
+	pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+	pc2h_evt_hdr->len = sizeof(struct surveydone_event);
+	pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone);
+	pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+	psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+	psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt;
+
+	DBG_88E("survey done event(%x)\n", psurveydone_evt->bss_cnt);
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+}
+
+void report_join_res(struct adapter *padapter, int res)
+{
+	struct cmd_obj *pcmd_obj;
+	u8 *pevtcmd;
+	u32 cmdsz;
+	struct joinbss_event		*pjoinbss_evt;
+	struct C2HEvent_Header	*pc2h_evt_hdr;
+	struct mlme_ext_priv		*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+	pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd_obj == NULL)
+		return;
+
+	cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		kfree(pcmd_obj);
+		return;
+	}
+
+	_rtw_init_listhead(&pcmd_obj->list);
+
+	pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+	pcmd_obj->cmdsz = cmdsz;
+	pcmd_obj->parmbuf = pevtcmd;
+
+	pcmd_obj->rsp = NULL;
+	pcmd_obj->rspsz  = 0;
+
+	pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+	pc2h_evt_hdr->len = sizeof(struct joinbss_event);
+	pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss);
+	pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+	pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+	memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex));
+	pjoinbss_evt->network.join_res	= res;
+	pjoinbss_evt->network.aid = res;
+
+	DBG_88E("report_join_res(%d)\n", res);
+
+
+	rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network);
+
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+}
+
+void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason)
+{
+	struct cmd_obj *pcmd_obj;
+	u8 *pevtcmd;
+	u32 cmdsz;
+	struct sta_info *psta;
+	int	mac_id;
+	struct stadel_event			*pdel_sta_evt;
+	struct C2HEvent_Header	*pc2h_evt_hdr;
+	struct mlme_ext_priv		*pmlmeext = &padapter->mlmeextpriv;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+	pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd_obj == NULL)
+		return;
+
+	cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		kfree(pcmd_obj);
+		return;
+	}
+
+	_rtw_init_listhead(&pcmd_obj->list);
+
+	pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+	pcmd_obj->cmdsz = cmdsz;
+	pcmd_obj->parmbuf = pevtcmd;
+
+	pcmd_obj->rsp = NULL;
+	pcmd_obj->rspsz  = 0;
+
+	pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+	pc2h_evt_hdr->len = sizeof(struct stadel_event);
+	pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA);
+	pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+	pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+	memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN);
+	memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2);
+
+
+	psta = rtw_get_stainfo(&padapter->stapriv, MacAddr);
+	if (psta)
+		mac_id = (int)psta->mac_id;
+	else
+		mac_id = (-1);
+
+	pdel_sta_evt->mac_id = mac_id;
+
+	DBG_88E("report_del_sta_event: delete STA, mac_id =%d\n", mac_id);
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+}
+
+void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx)
+{
+	struct cmd_obj *pcmd_obj;
+	u8 *pevtcmd;
+	u32 cmdsz;
+	struct stassoc_event		*padd_sta_evt;
+	struct C2HEvent_Header	*pc2h_evt_hdr;
+	struct mlme_ext_priv		*pmlmeext = &padapter->mlmeextpriv;
+	struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+	pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (pcmd_obj == NULL)
+		return;
+
+	cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header));
+	pevtcmd = (u8 *)rtw_zmalloc(cmdsz);
+	if (pevtcmd == NULL) {
+		kfree(pcmd_obj);
+		return;
+	}
+
+	_rtw_init_listhead(&pcmd_obj->list);
+
+	pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+	pcmd_obj->cmdsz = cmdsz;
+	pcmd_obj->parmbuf = pevtcmd;
+
+	pcmd_obj->rsp = NULL;
+	pcmd_obj->rspsz  = 0;
+
+	pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd);
+	pc2h_evt_hdr->len = sizeof(struct stassoc_event);
+	pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA);
+	pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq);
+
+	padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header));
+	memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN);
+	padd_sta_evt->cam_id = cam_idx;
+
+	DBG_88E("report_add_sta_event: add STA\n");
+
+	rtw_enqueue_cmd(pcmdpriv, pcmd_obj);
+
+	return;
+}
+
+
+/****************************************************************************
+
+Following are the event callback functions
+
+*****************************************************************************/
+
+/* for sta/adhoc mode */
+void update_sta_info(struct adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	/* ERP */
+	VCS_update(padapter, psta);
+
+	/* HT */
+	if (pmlmepriv->htpriv.ht_option) {
+		psta->htpriv.ht_option = true;
+
+		psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable;
+
+		if (support_short_GI(padapter, &(pmlmeinfo->HT_caps)))
+			psta->htpriv.sgi = true;
+
+		psta->qos_option = true;
+	} else {
+		psta->htpriv.ht_option = false;
+
+		psta->htpriv.ampdu_enable = false;
+
+		psta->htpriv.sgi = false;
+		psta->qos_option = false;
+	}
+	psta->htpriv.bwmode = pmlmeext->cur_bwmode;
+	psta->htpriv.ch_offset = pmlmeext->cur_ch_offset;
+
+	psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+	psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+	/* QoS */
+	if (pmlmepriv->qospriv.qos_option)
+		psta->qos_option = true;
+
+
+	psta->state = _FW_LINKED;
+}
+
+void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
+{
+	struct sta_info		*psta, *psta_bmc;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+	u8 join_type;
+	u16 media_status;
+
+	if (join_res < 0) {
+		join_type = 1;
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+		rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+		/* restore to initial setting. */
+		update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+
+		goto exit_mlmeext_joinbss_event_callback;
+	}
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+		/* for bc/mc */
+		psta_bmc = rtw_get_bcmc_stainfo(padapter);
+		if (psta_bmc) {
+			pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc;
+			update_bmc_sta_support_rate(padapter, psta_bmc->mac_id);
+			Update_RA_Entry(padapter, psta_bmc->mac_id);
+		}
+	}
+
+
+	/* turn on dynamic functions */
+	Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+
+	/*  update IOT-releated issue */
+	update_IOT_info(padapter);
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates);
+
+	/* BCN interval */
+	rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval));
+
+	/* udpate capability */
+	update_capinfo(padapter, pmlmeinfo->capability);
+
+	/* WMM, Update EDCA param */
+	WMMOnAssocRsp(padapter);
+
+	/* HT */
+	HTOnAssocRsp(padapter);
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+	psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
+	if (psta) { /* only for infra. mode */
+		pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+		psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+		/* set per sta rate after updating HT cap. */
+		set_sta_rate(padapter, psta);
+		rtw_hal_set_hwreg(padapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&psta->mac_id);
+		media_status = (psta->mac_id<<8)|1; /*   MACID|OPMODE: 1 means connect */
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+	}
+
+	join_type = 2;
+	rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) {
+		/*  correcting TSF */
+		correct_TSF(padapter, pmlmeext);
+	}
+	rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0);
+
+exit_mlmeext_joinbss_event_callback:
+
+	DBG_88E("=>%s\n", __func__);
+}
+
+void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta)
+{
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 join_type;
+
+	DBG_88E("%s\n", __func__);
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+		if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {/* adhoc master or sta_count>1 */
+			/* nothing to do */
+		} else { /* adhoc client */
+			/*  correcting TSF */
+			correct_TSF(padapter, pmlmeext);
+
+			/* start beacon */
+			if (send_beacon(padapter) == _FAIL) {
+				pmlmeinfo->FW_sta_info[psta->mac_id].status = 0;
+				pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE;
+				return;
+			}
+			pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+		}
+
+		join_type = 2;
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+	}
+
+	pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+	/* rate radaptive */
+	Update_RA_Entry(padapter, psta->mac_id);
+
+	/* update adhoc sta_info */
+	update_sta_info(padapter, psta);
+}
+
+void mlmeext_sta_del_event_callback(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) {
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+		rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+		/* restore to initial setting. */
+		update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+
+		/* switch to the 20M Hz mode after disconnect */
+		pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+		pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+		/* SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */
+		set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+
+		flush_all_cam_entry(padapter);
+
+		pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+		/* set MSR to no link state -> infra. mode */
+		Set_MSR(padapter, _HW_STATE_STATION_);
+
+		_cancel_timer_ex(&pmlmeext->link_timer);
+	}
+}
+
+/****************************************************************************
+
+Following are the functions for the timer handlers
+
+*****************************************************************************/
+void _linked_rx_signal_strehgth_display(struct adapter *padapter);
+void _linked_rx_signal_strehgth_display(struct adapter *padapter)
+{
+	struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+      struct mlme_ext_info    *pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 mac_id;
+	int UndecoratedSmoothedPWDB;
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+		mac_id = 0;
+	else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_)
+		mac_id = 2;
+
+	rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, &mac_id);
+
+	rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB);
+	DBG_88E("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB);
+}
+
+static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta)
+{
+	u8 ret = false;
+
+	if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) &&
+	    sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) &&
+	    sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta))
+		ret = false;
+	else
+		ret = true;
+
+	sta_update_last_rx_pkts(psta);
+
+	return ret;
+}
+
+void linked_status_chk(struct adapter *padapter)
+{
+	u32	i;
+	struct sta_info		*psta;
+	struct xmit_priv		*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+
+	if (padapter->bRxRSSIDisplay)
+		_linked_rx_signal_strehgth_display(padapter);
+
+	rtw_hal_sreset_linked_status_check(padapter);
+
+	if (is_client_associated_to_ap(padapter)) {
+		/* linked infrastructure client mode */
+
+		int tx_chk = _SUCCESS, rx_chk = _SUCCESS;
+		int rx_chk_limit;
+
+		rx_chk_limit = 4;
+		psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress);
+		if (psta != NULL) {
+			bool is_p2p_enable = false;
+			#ifdef CONFIG_88EU_P2P
+			is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE);
+			#endif
+
+			if (!chk_ap_is_alive(padapter, psta))
+				rx_chk = _FAIL;
+
+			if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts)
+				tx_chk = _FAIL;
+
+			if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) {
+				u8 backup_oper_channel = 0;
+
+				/* switch to correct channel of current network  before issue keep-alive frames */
+				if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) {
+					backup_oper_channel = rtw_get_oper_ch(padapter);
+					SelectChannel(padapter, pmlmeext->cur_channel);
+				}
+
+				if (rx_chk != _SUCCESS)
+					issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1);
+
+				if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) {
+					tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1);
+					/* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */
+					if (tx_chk == _SUCCESS && !is_p2p_enable)
+						rx_chk = _SUCCESS;
+				}
+
+				/* back to the original operation channel */
+				if (backup_oper_channel > 0)
+					SelectChannel(padapter, backup_oper_channel);
+			} else {
+				if (rx_chk != _SUCCESS) {
+					if (pmlmeext->retry == 0) {
+						issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+						issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+						issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+					}
+				}
+
+				if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) {
+					tx_chk = issue_nulldata(padapter, NULL, 0, 1, 0);
+				}
+			}
+
+			if (rx_chk == _FAIL) {
+				pmlmeext->retry++;
+				if (pmlmeext->retry > rx_chk_limit) {
+					DBG_88E_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n",
+						      FUNC_ADPT_ARG(padapter));
+					receive_disconnect(padapter, pmlmeinfo->network.MacAddress,
+							   WLAN_REASON_EXPIRATION_CHK);
+					return;
+				}
+			} else {
+				pmlmeext->retry = 0;
+			}
+
+			if (tx_chk == _FAIL) {
+				pmlmeinfo->link_count &= 0xf;
+			} else {
+				pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts;
+				pmlmeinfo->link_count = 0;
+			}
+		} /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */
+	} else if (is_client_associated_to_ibss(padapter)) {
+		/* linked IBSS mode */
+		/* for each assoc list entry to check the rx pkt counter */
+		for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) {
+			if (pmlmeinfo->FW_sta_info[i].status == 1) {
+				psta = pmlmeinfo->FW_sta_info[i].psta;
+
+				if (NULL == psta)
+					continue;
+				if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) {
+					if (pmlmeinfo->FW_sta_info[i].retry < 3) {
+						pmlmeinfo->FW_sta_info[i].retry++;
+					} else {
+						pmlmeinfo->FW_sta_info[i].retry = 0;
+						pmlmeinfo->FW_sta_info[i].status = 0;
+						report_del_sta_event(padapter, psta->hwaddr
+							, 65535/*  indicate disconnect caused by no rx */
+					);
+					}
+				} else {
+					pmlmeinfo->FW_sta_info[i].retry = 0;
+					pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta);
+				}
+			}
+		}
+	}
+}
+
+void survey_timer_hdl(struct adapter *padapter)
+{
+	struct cmd_obj	*ph2c;
+	struct sitesurvey_parm	*psurveyPara;
+	struct cmd_priv					*pcmdpriv = &padapter->cmdpriv;
+	struct mlme_ext_priv		*pmlmeext = &padapter->mlmeextpriv;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif
+
+	/* issue rtw_sitesurvey_cmd */
+	if (pmlmeext->sitesurvey_res.state > SCAN_START) {
+		if (pmlmeext->sitesurvey_res.state ==  SCAN_PROCESS)
+			pmlmeext->sitesurvey_res.channel_idx++;
+
+		if (pmlmeext->scan_abort) {
+			#ifdef CONFIG_88EU_P2P
+			if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) {
+				rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+				pmlmeext->sitesurvey_res.channel_idx = 3;
+				DBG_88E("%s idx:%d, cnt:%u\n", __func__
+					, pmlmeext->sitesurvey_res.channel_idx
+					, pwdinfo->find_phase_state_exchange_cnt
+			);
+			} else
+			#endif
+			{
+				pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num;
+				DBG_88E("%s idx:%d\n", __func__
+					, pmlmeext->sitesurvey_res.channel_idx
+			);
+			}
+
+			pmlmeext->scan_abort = false;/* reset */
+		}
+
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL)
+			goto exit_survey_timer_hdl;
+
+		psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm));
+		if (psurveyPara == NULL) {
+			kfree(ph2c);
+			goto exit_survey_timer_hdl;
+		}
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+		rtw_enqueue_cmd(pcmdpriv, ph2c);
+	}
+
+
+exit_survey_timer_hdl:
+	return;
+}
+
+void link_timer_hdl(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
+		DBG_88E("link_timer_hdl:no beacon while connecting\n");
+		pmlmeinfo->state = WIFI_FW_NULL_STATE;
+		report_join_res(padapter, -3);
+	} else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) {
+		/* re-auth timer */
+		if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) {
+			pmlmeinfo->state = 0;
+			report_join_res(padapter, -1);
+			return;
+		}
+
+		DBG_88E("link_timer_hdl: auth timeout and try again\n");
+		pmlmeinfo->auth_seq = 1;
+		issue_auth(padapter, NULL, 0);
+		set_link_timer(pmlmeext, REAUTH_TO);
+	} else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) {
+		/* re-assoc timer */
+		if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) {
+			pmlmeinfo->state = WIFI_FW_NULL_STATE;
+			report_join_res(padapter, -2);
+			return;
+		}
+
+		DBG_88E("link_timer_hdl: assoc timeout and try again\n");
+		issue_assocreq(padapter);
+		set_link_timer(pmlmeext, REASSOC_TO);
+	}
+	return;
+}
+
+void addba_timer_hdl(struct sta_info *psta)
+{
+	struct ht_priv	*phtpriv;
+
+	if (!psta)
+		return;
+
+	phtpriv = &psta->htpriv;
+
+	if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) {
+		if (phtpriv->candidate_tid_bitmap)
+			phtpriv->candidate_tid_bitmap = 0x0;
+	}
+}
+
+u8 NULL_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	return H2C_SUCCESS;
+}
+
+u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	u8 type;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf;
+
+	if (psetop->mode == Ndis802_11APMode) {
+		pmlmeinfo->state = WIFI_FW_AP_STATE;
+		type = _HW_STATE_AP_;
+	} else if (psetop->mode == Ndis802_11Infrastructure) {
+		pmlmeinfo->state &= ~(BIT(0)|BIT(1));/*  clear state */
+		pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to	STATION_STATE */
+		type = _HW_STATE_STATION_;
+	} else if (psetop->mode == Ndis802_11IBSS) {
+		type = _HW_STATE_ADHOC_;
+	} else {
+		type = _HW_STATE_NOLINK_;
+	}
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
+	/* Set_NETYPE0_MSR(padapter, type); */
+
+	return H2C_SUCCESS;
+}
+
+u8 createbss_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+	struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf;
+	/* u32	initialgain; */
+
+
+	if (pparm->network.InfrastructureMode == Ndis802_11APMode) {
+#ifdef CONFIG_88EU_AP_MODE
+
+		if (pmlmeinfo->state == WIFI_FW_AP_STATE) {
+			/* todo: */
+			return H2C_SUCCESS;
+		}
+#endif
+	}
+
+	/* below is for ad-hoc master */
+	if (pparm->network.InfrastructureMode == Ndis802_11IBSS) {
+		rtw_joinbss_reset(padapter);
+
+		pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+		pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+		pmlmeinfo->ERP_enable = 0;
+		pmlmeinfo->WMM_enable = 0;
+		pmlmeinfo->HT_enable = 0;
+		pmlmeinfo->HT_caps_enable = 0;
+		pmlmeinfo->HT_info_enable = 0;
+		pmlmeinfo->agg_enable_bitmap = 0;
+		pmlmeinfo->candidate_tid_bitmap = 0;
+
+		/* disable dynamic functions, such as high power, DIG */
+		Save_DM_Func_Flag(padapter);
+		Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+		/* config the initial gain under linking, need to write the BB registers */
+		/* initialgain = 0x1E; */
+		/* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */
+
+		/* cancel link timer */
+		_cancel_timer_ex(&pmlmeext->link_timer);
+
+		/* clear CAM */
+		flush_all_cam_entry(padapter);
+
+		memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength));
+		pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength;
+
+		if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
+			return H2C_PARAMETERS_ERROR;
+
+		memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength);
+
+		start_create_ibss(padapter);
+	}
+
+	return H2C_SUCCESS;
+}
+
+u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	u8 join_type;
+	struct ndis_802_11_var_ie *pIE;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+	struct joinbss_parm	*pparm = (struct joinbss_parm *)pbuf;
+	u32 i;
+
+	/* check already connecting to AP or not */
+	if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {
+		if (pmlmeinfo->state & WIFI_FW_STATION_STATE)
+			issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 5, 100);
+
+		pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+		/* clear CAM */
+		flush_all_cam_entry(padapter);
+
+		_cancel_timer_ex(&pmlmeext->link_timer);
+
+		/* set MSR to nolink -> infra. mode */
+		Set_MSR(padapter, _HW_STATE_STATION_);
+
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+	}
+
+	rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, false);
+
+	rtw_joinbss_reset(padapter);
+
+	pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+	pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pmlmeinfo->ERP_enable = 0;
+	pmlmeinfo->WMM_enable = 0;
+	pmlmeinfo->HT_enable = 0;
+	pmlmeinfo->HT_caps_enable = 0;
+	pmlmeinfo->HT_info_enable = 0;
+	pmlmeinfo->agg_enable_bitmap = 0;
+	pmlmeinfo->candidate_tid_bitmap = 0;
+	pmlmeinfo->bwmode_updated = false;
+
+	memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength));
+	pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength;
+
+	if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
+		return H2C_PARAMETERS_ERROR;
+
+	memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength);
+
+	/* Check AP vendor to move rtw_joinbss_cmd() */
+
+	for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) {
+		pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */
+			if (_rtw_memcmp(pIE->data, WMM_OUI, 4))
+				pmlmeinfo->WMM_enable = 1;
+			break;
+		case _HT_CAPABILITY_IE_:	/* Get HT Cap IE. */
+			pmlmeinfo->HT_caps_enable = 1;
+			break;
+		case _HT_EXTRA_INFO_IE_:	/* Get HT Info IE. */
+			pmlmeinfo->HT_info_enable = 1;
+
+			/* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */
+			{
+				struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data);
+
+				if ((pregpriv->cbw40_enable) &&	 (pht_info->infos[0] & BIT(2))) {
+					/* switch to the 40M Hz mode according to the AP */
+					pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
+					switch (pht_info->infos[0] & 0x3) {
+					case 1:
+						pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+						break;
+					case 3:
+						pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+						break;
+					default:
+						pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+						break;
+				}
+
+					DBG_88E("set ch/bw before connected\n");
+				}
+			}
+			break;
+		default:
+			break;
+		}
+
+		i += (pIE->Length + 2);
+	}
+	/* disable dynamic functions, such as high power, DIG */
+
+	/* config the initial gain under linking, need to write the BB registers */
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress);
+	join_type = 0;
+	rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+	/* cancel link timer */
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	start_clnt_join(padapter);
+
+	return H2C_SUCCESS;
+}
+
+u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	struct disconnect_parm *param = (struct disconnect_parm *)pbuf;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+	u8 val8;
+
+	if (is_client_associated_to_ap(padapter))
+		issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100);
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+	rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr);
+
+	/* restore to initial setting. */
+	update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+
+	if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) {
+		/* Stop BCN */
+		val8 = 0;
+		rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8));
+	}
+
+
+	/* set MSR to no link state -> infra. mode */
+	Set_MSR(padapter, _HW_STATE_STATION_);
+
+	pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+	/* switch to the 20M Hz mode after disconnect */
+	pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+	pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+	set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+	flush_all_cam_entry(padapter);
+
+	_cancel_timer_ex(&pmlmeext->link_timer);
+
+	rtw_free_uc_swdec_pending_queue(padapter);
+
+	return	H2C_SUCCESS;
+}
+
+static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_channel *out,
+	u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num)
+{
+	int i, j;
+	int set_idx;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	/* clear out first */
+	_rtw_memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num);
+
+	/* acquire channels from in */
+	j = 0;
+	for (i = 0; i < in_num; i++) {
+		set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value);
+		if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) &&
+		    set_idx >= 0) {
+			memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel));
+
+			if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE)
+				out[j].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
+
+			j++;
+		}
+		if (j >= out_num)
+			break;
+	}
+
+	/* if out is empty, use channel_set as default */
+	if (j == 0) {
+		for (i = 0; i < pmlmeext->max_chan_nums; i++) {
+			out[i].hw_value = pmlmeext->channel_set[i].ChannelNum;
+
+			if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
+				out[i].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN;
+
+			j++;
+		}
+	}
+
+	return j;
+}
+
+u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct sitesurvey_parm	*pparm = (struct sitesurvey_parm *)pbuf;
+	u8 bdelayscan = false;
+	u8 val8;
+	u32	initialgain;
+	u32	i;
+
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif
+
+	if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) {
+		/* for first time sitesurvey_cmd */
+		rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, NULL);
+
+		pmlmeext->sitesurvey_res.state = SCAN_START;
+		pmlmeext->sitesurvey_res.bss_cnt = 0;
+		pmlmeext->sitesurvey_res.channel_idx = 0;
+
+		for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+			if (pparm->ssid[i].SsidLength) {
+				memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE);
+				pmlmeext->sitesurvey_res.ssid[i].SsidLength = pparm->ssid[i].SsidLength;
+			} else {
+				pmlmeext->sitesurvey_res.ssid[i].SsidLength = 0;
+			}
+		}
+
+		pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter
+			, pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT
+			, pparm->ch, pparm->ch_num
+	);
+
+		pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode;
+
+		/* issue null data if associating to the AP */
+		if (is_client_associated_to_ap(padapter)) {
+			pmlmeext->sitesurvey_res.state = SCAN_TXNULL;
+
+			issue_nulldata(padapter, NULL, 1, 3, 500);
+
+			bdelayscan = true;
+		}
+		if (bdelayscan) {
+			/* delay 50ms to protect nulldata(1). */
+			set_survey_timer(pmlmeext, 50);
+			return H2C_SUCCESS;
+		}
+	}
+
+	if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) {
+		/* disable dynamic functions, such as high power, DIG */
+		Save_DM_Func_Flag(padapter);
+		Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+		/* config the initial gain under scaning, need to write the BB registers */
+#ifdef CONFIG_88EU_P2P
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+			initialgain = 0x1E;
+		else
+			initialgain = 0x28;
+#else	/*  CONFIG_88EU_P2P */
+		initialgain = 0x1E;
+#endif /*  CONFIG_88EU_P2P */
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+
+		/* set MSR to no link state */
+		Set_MSR(padapter, _HW_STATE_NOLINK_);
+
+		val8 = 1; /* under site survey */
+		rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+		pmlmeext->sitesurvey_res.state = SCAN_PROCESS;
+	}
+
+	site_survey(padapter);
+
+	return H2C_SUCCESS;
+}
+
+u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	struct setauth_parm		*pparm = (struct setauth_parm *)pbuf;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pparm->mode < 4)
+		pmlmeinfo->auth_algo = pparm->mode;
+	return	H2C_SUCCESS;
+}
+
+u8 setkey_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	unsigned short				ctrl;
+	struct setkey_parm		*pparm = (struct setkey_parm *)pbuf;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	unsigned char					null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+	/* main tx key for wep. */
+	if (pparm->set_tx)
+		pmlmeinfo->key_index = pparm->keyid;
+
+	/* write cam */
+	ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid;
+
+	DBG_88E_LEVEL(_drv_info_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) "
+			"keyid:%d\n", pparm->algorithm, pparm->keyid);
+	write_cam(padapter, pparm->keyid, ctrl, null_sta, pparm->key);
+
+	return H2C_SUCCESS;
+}
+
+u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	u16 ctrl = 0;
+	u8 cam_id;/* cam_entry */
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct set_stakey_parm	*pparm = (struct set_stakey_parm *)pbuf;
+
+	/* cam_entry: */
+	/* 0~3 for default key */
+
+	/* for concurrent mode (ap+sta): */
+	/* default key is disable, using sw encrypt/decrypt */
+	/* cam_entry = 4 for sta mode (macid = 0) */
+	/* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */
+
+	/* for concurrent mode (sta+sta): */
+	/* default key is disable, using sw encrypt/decrypt */
+	/* cam_entry = 4 mapping to macid = 0 */
+	/* cam_entry = 5 mapping to macid = 2 */
+
+	cam_id = 4;
+
+	DBG_88E_LEVEL(_drv_info_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n",
+		      pparm->algorithm, cam_id);
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+		struct sta_info *psta;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		if (pparm->algorithm == _NO_PRIVACY_)	/*  clear cam entry */ {
+			clear_cam_entry(padapter, pparm->id);
+			return H2C_SUCCESS_RSP;
+		}
+
+		psta = rtw_get_stainfo(pstapriv, pparm->addr);
+		if (psta) {
+			ctrl = (BIT(15) | ((pparm->algorithm) << 2));
+
+			DBG_88E("r871x_set_stakey_hdl(): enc_algorithm=%d\n", pparm->algorithm);
+
+			if ((psta->mac_id < 1) || (psta->mac_id > (NUM_STA-4))) {
+				DBG_88E("r871x_set_stakey_hdl():set_stakey failed, mac_id(aid)=%d\n", psta->mac_id);
+				return H2C_REJECTED;
+			}
+
+			cam_id = (psta->mac_id + 3);/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+			DBG_88E("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, cam_entry=%d\n", pparm->addr[0],
+				pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4],
+				pparm->addr[5], cam_id);
+
+			write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+
+			return H2C_SUCCESS_RSP;
+		} else {
+			DBG_88E("r871x_set_stakey_hdl(): sta has been free\n");
+			return H2C_REJECTED;
+		}
+	}
+
+	/* below for sta mode */
+
+	if (pparm->algorithm == _NO_PRIVACY_) {	/*  clear cam entry */
+		clear_cam_entry(padapter, pparm->id);
+		return H2C_SUCCESS;
+	}
+	ctrl = BIT(15) | ((pparm->algorithm) << 2);
+	write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+	pmlmeinfo->enc_algo = pparm->algorithm;
+	return H2C_SUCCESS;
+}
+
+u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	struct addBaReq_parm	*pparm = (struct addBaReq_parm *)pbuf;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr);
+
+	if (!psta)
+		return	H2C_SUCCESS;
+
+	if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) ||
+	    ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)) {
+		issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid);
+		_set_timer(&psta->addba_retry_timer, ADDBA_TO);
+	} else {
+		psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid);
+	}
+	return	H2C_SUCCESS;
+}
+
+u8 set_tx_beacon_cmd(struct adapter *padapter)
+{
+	struct cmd_obj	*ph2c;
+	struct Tx_Beacon_param	*ptxBeacon_parm;
+	struct cmd_priv	*pcmdpriv = &(padapter->cmdpriv);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u8 res = _SUCCESS;
+	int len_diff = 0;
+
+_func_enter_;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param));
+	if (ptxBeacon_parm == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex));
+
+	len_diff = update_hidden_ssid(ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_,
+				      ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_,
+				      pmlmeinfo->hidden_ssid_mode);
+	ptxBeacon_parm->network.IELength += len_diff;
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon));
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	u8 evt_code;
+	u16 evt_sz;
+	uint	*peventbuf;
+	void (*event_callback)(struct adapter *dev, u8 *pbuf);
+	struct evt_priv *pevt_priv = &(padapter->evtpriv);
+
+	peventbuf = (uint *)pbuf;
+	evt_sz = (u16)(*peventbuf&0xffff);
+	evt_code = (u8)((*peventbuf>>16)&0xff);
+
+	/*  checking if event code is valid */
+	if (evt_code >= MAX_C2HEVT) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code));
+		goto _abort_event_;
+	}
+
+	/*  checking if event size match the event parm size */
+	if ((wlanevents[evt_code].parmsize != 0) &&
+	    (wlanevents[evt_code].parmsize != evt_sz)) {
+		RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+			 ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n",
+			 evt_code, wlanevents[evt_code].parmsize, evt_sz));
+		goto _abort_event_;
+	}
+
+	ATOMIC_INC(&pevt_priv->event_seq);
+
+	peventbuf += 2;
+
+	if (peventbuf) {
+		event_callback = wlanevents[evt_code].event_callback;
+		event_callback(padapter, (u8 *)peventbuf);
+
+		pevt_priv->evt_done_cnt++;
+	}
+
+_abort_event_:
+	return H2C_SUCCESS;
+}
+
+u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	return H2C_SUCCESS;
+}
+
+u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	if (send_beacon(padapter) == _FAIL) {
+		DBG_88E("issue_beacon, fail!\n");
+		return H2C_PARAMETERS_ERROR;
+	}
+#ifdef CONFIG_88EU_AP_MODE
+	else { /* tx bc/mc frames after update TIM */
+		unsigned long irqL;
+		struct sta_info *psta_bmc;
+		struct list_head *xmitframe_plist, *xmitframe_phead;
+		struct xmit_frame *pxmitframe = NULL;
+		struct sta_priv  *pstapriv = &padapter->stapriv;
+
+		/* for BC/MC Frames */
+		psta_bmc = rtw_get_bcmc_stainfo(padapter);
+		if (!psta_bmc)
+			return H2C_SUCCESS;
+
+		if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len > 0)) {
+			rtw_msleep_os(10);/*  10ms, ATIM(HIQ) Windows */
+			_enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+
+			xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+			xmitframe_plist = get_next(xmitframe_phead);
+
+			while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+				pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+				xmitframe_plist = get_next(xmitframe_plist);
+
+				rtw_list_delete(&pxmitframe->list);
+
+				psta_bmc->sleepq_len--;
+				if (psta_bmc->sleepq_len > 0)
+					pxmitframe->attrib.mdata = 1;
+				else
+					pxmitframe->attrib.mdata = 0;
+
+				pxmitframe->attrib.triggered = 1;
+
+				pxmitframe->attrib.qsel = 0x11;/* HIQ */
+
+				_exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+				if (rtw_hal_xmit(padapter, pxmitframe))
+					rtw_os_xmit_complete(padapter, pxmitframe);
+				_enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+			}
+			_exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL);
+		}
+	}
+#endif
+	return H2C_SUCCESS;
+}
+
+u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf)
+{
+	struct set_ch_parm *set_ch_parm;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	set_ch_parm = (struct set_ch_parm *)pbuf;
+
+	DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+		FUNC_NDEV_ARG(padapter->pnetdev),
+		set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset);
+
+	pmlmeext->cur_channel = set_ch_parm->ch;
+	pmlmeext->cur_ch_offset = set_ch_parm->ch_offset;
+	pmlmeext->cur_bwmode = set_ch_parm->bw;
+
+	set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw);
+
+	return	H2C_SUCCESS;
+}
+
+u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	struct SetChannelPlan_param *setChannelPlan_param;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+
+	setChannelPlan_param = (struct SetChannelPlan_param *)pbuf;
+
+	pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set);
+	init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list);
+
+	return	H2C_SUCCESS;
+}
+
+u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	if (!pbuf)
+		return H2C_PARAMETERS_ERROR;
+	return	H2C_SUCCESS;
+}
+
+u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	return	H2C_REJECTED;
+}
+
+/*  TDLS_WRCR		: write RCR DATA BIT */
+/*  TDLS_SD_PTI		: issue peer traffic indication */
+/*  TDLS_CS_OFF		: go back to the channel linked with AP, terminating channel switch procedure */
+/*  TDLS_INIT_CH_SEN	: init channel sensing, receive all data and mgnt frame */
+/*  TDLS_DONE_CH_SEN: channel sensing and report candidate channel */
+/*  TDLS_OFF_CH		: first time set channel to off channel */
+/*  TDLS_BASE_CH		: go back tp the channel linked with AP when set base channel as target channel */
+/*  TDLS_P_OFF_CH	: periodically go to off channel */
+/*  TDLS_P_BASE_CH	: periodically go back to base channel */
+/*  TDLS_RS_RCR		: restore RCR */
+/*  TDLS_CKALV_PH1	: check alive timer phase1 */
+/*  TDLS_CKALV_PH2	: check alive timer phase2 */
+/*  TDLS_FREE_STA	: free tdls sta */
+u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf)
+{
+	return H2C_REJECTED;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mp.c b/drivers/staging/rtl8188eu/core/rtw_mp.c
new file mode 100644
index 0000000..c7ff2e4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mp.c
@@ -0,0 +1,997 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MP_C_
+
+#include <drv_types.h>
+
+#include "odm_precomp.h"
+#include "rtl8188e_hal.h"
+
+u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz)
+{
+	u32 val = 0;
+
+	switch (sz) {
+	case 1:
+		val = rtw_read8(padapter, addr);
+		break;
+	case 2:
+		val = rtw_read16(padapter, addr);
+		break;
+	case 4:
+		val = rtw_read32(padapter, addr);
+		break;
+	default:
+		val = 0xffffffff;
+		break;
+	}
+
+	return val;
+}
+
+void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz)
+{
+	switch (sz) {
+	case 1:
+		rtw_write8(padapter, addr, (u8)val);
+		break;
+	case 2:
+		rtw_write16(padapter, addr, (u16)val);
+		break;
+	case 4:
+		rtw_write32(padapter, addr, val);
+		break;
+	default:
+		break;
+	}
+}
+
+u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask)
+{
+	return rtw_hal_read_bbreg(padapter, addr, bitmask);
+}
+
+void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val)
+{
+	rtw_hal_write_bbreg(padapter, addr, bitmask, val);
+}
+
+u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask)
+{
+	return rtw_hal_read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask);
+}
+
+void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val)
+{
+	rtw_hal_write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask, val);
+}
+
+u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr)
+{
+	return _read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask);
+}
+
+void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val)
+{
+	_write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask, val);
+}
+
+static void _init_mp_priv_(struct mp_priv *pmp_priv)
+{
+	struct wlan_bssid_ex *pnetwork;
+
+	_rtw_memset(pmp_priv, 0, sizeof(struct mp_priv));
+
+	pmp_priv->mode = MP_OFF;
+
+	pmp_priv->channel = 1;
+	pmp_priv->bandwidth = HT_CHANNEL_WIDTH_20;
+	pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	pmp_priv->rateidx = MPT_RATE_1M;
+	pmp_priv->txpoweridx = 0x2A;
+
+	pmp_priv->antenna_tx = ANTENNA_A;
+	pmp_priv->antenna_rx = ANTENNA_AB;
+
+	pmp_priv->check_mp_pkt = 0;
+
+	pmp_priv->tx_pktcount = 0;
+
+	pmp_priv->rx_pktcount = 0;
+	pmp_priv->rx_crcerrpktcount = 0;
+
+	pmp_priv->network_macaddr[0] = 0x00;
+	pmp_priv->network_macaddr[1] = 0xE0;
+	pmp_priv->network_macaddr[2] = 0x4C;
+	pmp_priv->network_macaddr[3] = 0x87;
+	pmp_priv->network_macaddr[4] = 0x66;
+	pmp_priv->network_macaddr[5] = 0x55;
+
+	pnetwork = &pmp_priv->mp_network.network;
+	memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN);
+
+	pnetwork->Ssid.SsidLength = 8;
+	memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength);
+}
+
+static void mp_init_xmit_attrib(struct mp_tx *pmptx, struct adapter *padapter)
+{
+	struct pkt_attrib *pattrib;
+	struct tx_desc *desc;
+
+	/*  init xmitframe attribute */
+	pattrib = &pmptx->attrib;
+	_rtw_memset(pattrib, 0, sizeof(struct pkt_attrib));
+	desc = &pmptx->desc;
+	_rtw_memset(desc, 0, TXDESC_SIZE);
+
+	pattrib->ether_type = 0x8712;
+	_rtw_memset(pattrib->dst, 0xFF, ETH_ALEN);
+	pattrib->ack_policy = 0;
+	pattrib->hdrlen = WLAN_HDR_A3_LEN;
+	pattrib->subtype = WIFI_DATA;
+	pattrib->priority = 0;
+	pattrib->qsel = pattrib->priority;
+	pattrib->nr_frags = 1;
+	pattrib->encrypt = 0;
+	pattrib->bswenc = false;
+	pattrib->qos_en = false;
+}
+
+s32 init_mp_priv(struct adapter *padapter)
+{
+	struct mp_priv *pmppriv = &padapter->mppriv;
+
+	_init_mp_priv_(pmppriv);
+	pmppriv->papdater = padapter;
+
+	pmppriv->tx.stop = 1;
+	mp_init_xmit_attrib(&pmppriv->tx, padapter);
+
+	switch (padapter->registrypriv.rf_config) {
+	case RF_1T1R:
+		pmppriv->antenna_tx = ANTENNA_A;
+		pmppriv->antenna_rx = ANTENNA_A;
+		break;
+	case RF_1T2R:
+	default:
+		pmppriv->antenna_tx = ANTENNA_A;
+		pmppriv->antenna_rx = ANTENNA_AB;
+		break;
+	case RF_2T2R:
+	case RF_2T2R_GREEN:
+		pmppriv->antenna_tx = ANTENNA_AB;
+		pmppriv->antenna_rx = ANTENNA_AB;
+		break;
+	case RF_2T4R:
+		pmppriv->antenna_tx = ANTENNA_AB;
+		pmppriv->antenna_rx = ANTENNA_ABCD;
+		break;
+	}
+
+	return _SUCCESS;
+}
+
+void free_mp_priv(struct mp_priv *pmp_priv)
+{
+	kfree(pmp_priv->pallocated_mp_xmitframe_buf);
+	pmp_priv->pallocated_mp_xmitframe_buf = NULL;
+	pmp_priv->pmp_xmtframe_buf = NULL;
+}
+
+#define PHY_IQCalibrate(a, b)	PHY_IQCalibrate_8188E(a, b)
+#define PHY_LCCalibrate(a)	PHY_LCCalibrate_8188E(a)
+#define PHY_SetRFPathSwitch(a, b) PHY_SetRFPathSwitch_8188E(a, b)
+
+s32 MPT_InitializeAdapter(struct adapter *pAdapter, u8 Channel)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+	s32		rtStatus = _SUCCESS;
+	struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
+	struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv;
+
+	/*  HW Initialization for 8190 MPT. */
+	/*  SW Initialization for 8190 MP. */
+	pMptCtx->bMptDrvUnload = false;
+	pMptCtx->bMassProdTest = false;
+	pMptCtx->bMptIndexEven = true;	/* default gain index is -6.0db */
+	pMptCtx->h2cReqNum = 0x0;
+	/* Init mpt event. */
+	/* init for BT MP */
+
+	pMptCtx->bMptWorkItemInProgress = false;
+	pMptCtx->CurrMptAct = NULL;
+	/*  */
+
+	/*  Don't accept any packets */
+	rtw_write32(pAdapter, REG_RCR, 0);
+
+	PHY_IQCalibrate(pAdapter, false);
+	dm_CheckTXPowerTracking(&pHalData->odmpriv);	/* trigger thermal meter */
+	PHY_LCCalibrate(pAdapter);
+
+	pMptCtx->backup0xc50 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0);
+	pMptCtx->backup0xc58 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0);
+	pMptCtx->backup0xc30 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_RxDetector1, bMaskByte0);
+	pMptCtx->backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+	pMptCtx->backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+
+	/* set ant to wifi side in mp mode */
+	rtw_write16(pAdapter, 0x870, 0x300);
+	rtw_write16(pAdapter, 0x860, 0x110);
+
+	if (pAdapter->registrypriv.mp_mode == 1)
+		pmlmepriv->fw_state = WIFI_MP_STATE;
+
+	return	rtStatus;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	MPT_DeInitAdapter()
+ *
+ * Overview:	Extra DeInitialization for Mass Production Test.
+ *
+ * Input:		struct adapter *	pAdapter
+ *
+ * Output:		NONE
+ *
+ * Return:		NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	05/08/2007	MHC		Create Version 0.
+ *	05/18/2007	MHC		Add normal driver MPHalt code.
+ *
+ *---------------------------------------------------------------------------*/
+void MPT_DeInitAdapter(struct adapter *pAdapter)
+{
+	struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
+
+	pMptCtx->bMptDrvUnload = true;
+}
+
+static u8 mpt_ProStartTest(struct adapter *padapter)
+{
+	struct mpt_context *pMptCtx = &padapter->mppriv.MptCtx;
+
+	pMptCtx->bMassProdTest = true;
+	pMptCtx->bStartContTx = false;
+	pMptCtx->bCckContTx = false;
+	pMptCtx->bOfdmContTx = false;
+	pMptCtx->bSingleCarrier = false;
+	pMptCtx->bCarrierSuppression = false;
+	pMptCtx->bSingleTone = false;
+
+	return _SUCCESS;
+}
+
+/*
+ * General use
+ */
+s32 SetPowerTracking(struct adapter *padapter, u8 enable)
+{
+	Hal_SetPowerTracking(padapter, enable);
+	return 0;
+}
+
+void GetPowerTracking(struct adapter *padapter, u8 *enable)
+{
+	Hal_GetPowerTracking(padapter, enable);
+}
+
+static void disable_dm(struct adapter *padapter)
+{
+	u8 v8;
+
+	/* 3 1. disable firmware dynamic mechanism */
+	/*  disable Power Training, Rate Adaptive */
+	v8 = rtw_read8(padapter, REG_BCN_CTRL);
+	v8 &= ~EN_BCN_FUNCTION;
+	rtw_write8(padapter, REG_BCN_CTRL, v8);
+
+	/* 3 2. disable driver dynamic mechanism */
+	/*  disable Dynamic Initial Gain */
+	/*  disable High Power */
+	/*  disable Power Tracking */
+	Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+	/*  enable APK, LCK and IQK but disable power tracking */
+	Switch_DM_Func(padapter, DYNAMIC_RF_CALIBRATION, true);
+}
+
+/* This function initializes the DUT to the MP test mode */
+s32 mp_start_test(struct adapter *padapter)
+{
+	struct wlan_bssid_ex bssid;
+	struct sta_info *psta;
+	u32 length;
+	u8 val8;
+
+	unsigned long irqL;
+	s32 res = _SUCCESS;
+
+	struct mp_priv *pmppriv = &padapter->mppriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+	padapter->registrypriv.mp_mode = 1;
+	pmppriv->bSetTxPower = 0;		/* for  manually set tx power */
+
+	/* 3 disable dynamic mechanism */
+	disable_dm(padapter);
+
+	/* 3 0. update mp_priv */
+
+	if (padapter->registrypriv.rf_config == RF_819X_MAX_TYPE) {
+		switch (GET_RF_TYPE(padapter)) {
+		case RF_1T1R:
+			pmppriv->antenna_tx = ANTENNA_A;
+			pmppriv->antenna_rx = ANTENNA_A;
+			break;
+		case RF_1T2R:
+		default:
+			pmppriv->antenna_tx = ANTENNA_A;
+			pmppriv->antenna_rx = ANTENNA_AB;
+			break;
+		case RF_2T2R:
+		case RF_2T2R_GREEN:
+			pmppriv->antenna_tx = ANTENNA_AB;
+			pmppriv->antenna_rx = ANTENNA_AB;
+			break;
+		case RF_2T4R:
+			pmppriv->antenna_tx = ANTENNA_AB;
+			pmppriv->antenna_rx = ANTENNA_ABCD;
+			break;
+		}
+	}
+
+	mpt_ProStartTest(padapter);
+
+	/* 3 1. initialize a new struct wlan_bssid_ex */
+/*	_rtw_memset(&bssid, 0, sizeof(struct wlan_bssid_ex)); */
+	memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN);
+	bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc");
+	memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_adhoc", bssid.Ssid.SsidLength);
+	bssid.InfrastructureMode = Ndis802_11IBSS;
+	bssid.NetworkTypeInUse = Ndis802_11DS;
+	bssid.IELength = 0;
+
+	length = get_wlan_bssid_ex_sz(&bssid);
+	if (length % 4)
+		bssid.Length = ((length >> 2) + 1) << 2; /* round up to multiple of 4 bytes. */
+	else
+		bssid.Length = length;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
+		goto end_of_mp_start_test;
+
+	/* init mp_start_test status */
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+		rtw_disassoc_cmd(padapter, 500, true);
+		rtw_indicate_disconnect(padapter);
+		rtw_free_assoc_resources(padapter, 1);
+	}
+	pmppriv->prev_fw_state = get_fwstate(pmlmepriv);
+	if (padapter->registrypriv.mp_mode == 1)
+		pmlmepriv->fw_state = WIFI_MP_STATE;
+	set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+	/* 3 2. create a new psta for mp driver */
+	/* clear psta in the cur_network, if any */
+	psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress);
+	if (psta)
+		rtw_free_stainfo(padapter, psta);
+
+	psta = rtw_alloc_stainfo(&padapter->stapriv, bssid.MacAddress);
+	if (psta == NULL) {
+		RT_TRACE(_module_mp_, _drv_err_, ("mp_start_test: Can't alloc sta_info!\n"));
+		pmlmepriv->fw_state = pmppriv->prev_fw_state;
+		res = _FAIL;
+		goto end_of_mp_start_test;
+	}
+
+	/* 3 3. join psudo AdHoc */
+	tgt_network->join_res = 1;
+	tgt_network->aid = 1;
+	psta->aid = 1;
+	memcpy(&tgt_network->network, &bssid, length);
+
+	rtw_indicate_connect(padapter);
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+end_of_mp_start_test:
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (res == _SUCCESS) {
+		/*  set MSR to WIFI_FW_ADHOC_STATE */
+		val8 = rtw_read8(padapter, MSR) & 0xFC; /*  0x0102 */
+		val8 |= WIFI_FW_ADHOC_STATE;
+		rtw_write8(padapter, MSR, val8); /*  Link in ad hoc network */
+	}
+	return res;
+}
+/*  */
+/* This function change the DUT from the MP test mode into normal mode */
+void mp_stop_test(struct adapter *padapter)
+{
+	struct mp_priv *pmppriv = &padapter->mppriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+	struct sta_info *psta;
+
+	unsigned long irqL;
+
+	if (pmppriv->mode == MP_ON) {
+		pmppriv->bSetTxPower = 0;
+		_enter_critical_bh(&pmlmepriv->lock, &irqL);
+		if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)
+			goto end_of_mp_stop_test;
+
+		/* 3 1. disconnect psudo AdHoc */
+		rtw_indicate_disconnect(padapter);
+
+		/* 3 2. clear psta used in mp test mode. */
+		psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress);
+		if (psta)
+			rtw_free_stainfo(padapter, psta);
+
+		/* 3 3. return to normal state (default:station mode) */
+		pmlmepriv->fw_state = pmppriv->prev_fw_state; /*  WIFI_STATION_STATE; */
+
+		/* flush the cur_network */
+		_rtw_memset(tgt_network, 0, sizeof(struct wlan_network));
+
+		_clr_fwstate_(pmlmepriv, WIFI_MP_STATE);
+
+end_of_mp_stop_test:
+
+		_exit_critical_bh(&pmlmepriv->lock, &irqL);
+	}
+}
+
+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
+/*
+ * SetChannel
+ * Description
+ *	Use H2C command to change channel,
+ *	not only modify rf register, but also other setting need to be done.
+ */
+void SetChannel(struct adapter *pAdapter)
+{
+	Hal_SetChannel(pAdapter);
+}
+
+/*
+ * Notice
+ *	Switch bandwitdth may change center frequency(channel)
+ */
+void SetBandwidth(struct adapter *pAdapter)
+{
+	Hal_SetBandwidth(pAdapter);
+}
+
+void SetAntenna(struct adapter *pAdapter)
+{
+	Hal_SetAntenna(pAdapter);
+}
+
+void	SetAntennaPathPower(struct adapter *pAdapter)
+{
+	Hal_SetAntennaPathPower(pAdapter);
+}
+
+void SetTxPower(struct adapter *pAdapter)
+{
+	Hal_SetTxPower(pAdapter);
+	}
+
+void SetDataRate(struct adapter *pAdapter)
+{
+	Hal_SetDataRate(pAdapter);
+}
+
+void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter , bool bMain)
+{
+	PHY_SetRFPathSwitch(pAdapter, bMain);
+}
+
+s32 SetThermalMeter(struct adapter *pAdapter, u8 target_ther)
+{
+	return Hal_SetThermalMeter(pAdapter, target_ther);
+}
+
+void GetThermalMeter(struct adapter *pAdapter, u8 *value)
+{
+	Hal_GetThermalMeter(pAdapter, value);
+}
+
+void SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	Hal_SetSingleCarrierTx(pAdapter, bStart);
+}
+
+void SetSingleToneTx(struct adapter *pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	Hal_SetSingleToneTx(pAdapter, bStart);
+}
+
+void SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	Hal_SetCarrierSuppressionTx(pAdapter, bStart);
+}
+
+void SetContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+	PhySetTxPowerLevel(pAdapter);
+	Hal_SetContinuousTx(pAdapter, bStart);
+}
+
+
+void PhySetTxPowerLevel(struct adapter *pAdapter)
+{
+	struct mp_priv *pmp_priv = &pAdapter->mppriv;
+
+	if (pmp_priv->bSetTxPower == 0) /*  for NO manually set power index */
+		PHY_SetTxPowerLevel8188E(pAdapter, pmp_priv->channel);
+}
+
+/*  */
+static void dump_mpframe(struct adapter *padapter, struct xmit_frame *pmpframe)
+{
+	rtw_hal_mgnt_xmit(padapter, pmpframe);
+}
+
+static struct xmit_frame *alloc_mp_xmitframe(struct xmit_priv *pxmitpriv)
+{
+	struct xmit_frame	*pmpframe;
+	struct xmit_buf	*pxmitbuf;
+
+	pmpframe = rtw_alloc_xmitframe(pxmitpriv);
+	if (pmpframe == NULL)
+		return NULL;
+
+	pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+	if (pxmitbuf == NULL) {
+		rtw_free_xmitframe(pxmitpriv, pmpframe);
+		return NULL;
+	}
+
+	pmpframe->frame_tag = MP_FRAMETAG;
+
+	pmpframe->pxmitbuf = pxmitbuf;
+
+	pmpframe->buf_addr = pxmitbuf->pbuf;
+
+	pxmitbuf->priv_data = pmpframe;
+
+	return pmpframe;
+}
+
+static int mp_xmit_packet_thread(void *context)
+{
+	struct xmit_frame	*pxmitframe;
+	struct mp_tx		*pmptx;
+	struct mp_priv	*pmp_priv;
+	struct xmit_priv	*pxmitpriv;
+	struct adapter *padapter;
+
+	pmp_priv = (struct mp_priv *)context;
+	pmptx = &pmp_priv->tx;
+	padapter = pmp_priv->papdater;
+	pxmitpriv = &(padapter->xmitpriv);
+
+	thread_enter("RTW_MP_THREAD");
+
+	/* DBG_88E("%s:pkTx Start\n", __func__); */
+	while (1) {
+		pxmitframe = alloc_mp_xmitframe(pxmitpriv);
+		if (pxmitframe == NULL) {
+			if (pmptx->stop ||
+			    padapter->bSurpriseRemoved ||
+			    padapter->bDriverStopped) {
+				goto exit;
+			} else {
+				rtw_msleep_os(1);
+				continue;
+			}
+		}
+
+		memcpy((u8 *)(pxmitframe->buf_addr+TXDESC_OFFSET), pmptx->buf, pmptx->write_size);
+		memcpy(&(pxmitframe->attrib), &(pmptx->attrib), sizeof(struct pkt_attrib));
+
+		dump_mpframe(padapter, pxmitframe);
+
+		pmptx->sended++;
+		pmp_priv->tx_pktcount++;
+
+		if (pmptx->stop ||
+		    padapter->bSurpriseRemoved ||
+		    padapter->bDriverStopped)
+			goto exit;
+		if ((pmptx->count != 0) &&
+		    (pmptx->count == pmptx->sended))
+			goto exit;
+
+		flush_signals_thread();
+	}
+
+exit:
+	kfree(pmptx->pallocated_buf);
+	pmptx->pallocated_buf = NULL;
+	pmptx->stop = 1;
+
+	thread_exit();
+}
+
+void fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc)
+{
+	struct mp_priv *pmp_priv = &padapter->mppriv;
+	memcpy(ptxdesc, &(pmp_priv->tx.desc), TXDESC_SIZE);
+}
+
+void SetPacketTx(struct adapter *padapter)
+{
+	u8 *ptr, *pkt_start, *pkt_end;
+	u32 pkt_size;
+	struct tx_desc *desc;
+	struct rtw_ieee80211_hdr *hdr;
+	u8 payload;
+	s32 bmcast;
+	struct pkt_attrib *pattrib;
+	struct mp_priv *pmp_priv;
+
+
+	pmp_priv = &padapter->mppriv;
+	if (pmp_priv->tx.stop)
+		return;
+	pmp_priv->tx.sended = 0;
+	pmp_priv->tx.stop = 0;
+	pmp_priv->tx_pktcount = 0;
+
+	/* 3 1. update_attrib() */
+	pattrib = &pmp_priv->tx.attrib;
+	memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN);
+	memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+	memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+	bmcast = IS_MCAST(pattrib->ra);
+	if (bmcast) {
+		pattrib->mac_id = 1;
+		pattrib->psta = rtw_get_bcmc_stainfo(padapter);
+	} else {
+		pattrib->mac_id = 0;
+		pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv));
+	}
+
+	pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen;
+
+	/* 3 2. allocate xmit buffer */
+	pkt_size = pattrib->last_txcmdsz;
+
+	kfree(pmp_priv->tx.pallocated_buf);
+	pmp_priv->tx.write_size = pkt_size;
+	pmp_priv->tx.buf_size = pkt_size + XMITBUF_ALIGN_SZ;
+	pmp_priv->tx.pallocated_buf = rtw_zmalloc(pmp_priv->tx.buf_size);
+	if (pmp_priv->tx.pallocated_buf == NULL) {
+		DBG_88E("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size);
+		return;
+	}
+	pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ);
+	ptr = pmp_priv->tx.buf;
+
+	desc = &(pmp_priv->tx.desc);
+	_rtw_memset(desc, 0, TXDESC_SIZE);
+	pkt_start = ptr;
+	pkt_end = pkt_start + pkt_size;
+
+	/* 3 3. init TX descriptor */
+	/*  offset 0 */
+	desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+	desc->txdw0 |= cpu_to_le32(pkt_size & 0x0000FFFF); /*  packet size */
+	desc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00FF0000); /* 32 bytes for TX Desc */
+	if (bmcast)
+		desc->txdw0 |= cpu_to_le32(BMC); /*  broadcast packet */
+
+	desc->txdw1 |= cpu_to_le32((0x01 << 26) & 0xff000000);
+	/*  offset 4 */
+		desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x3F); /* CAM_ID(MAC_ID) */
+	desc->txdw1 |= cpu_to_le32((pattrib->qsel << QSEL_SHT) & 0x00001F00); /*  Queue Select, TID */
+
+	desc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); /*  Rate Adaptive ID */
+	/*  offset 8 */
+	/*  offset 12 */
+
+	desc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0x0fff0000);
+
+	/*  offset 16 */
+	desc->txdw4 |= cpu_to_le32(HW_SSN);
+	desc->txdw4 |= cpu_to_le32(USERATE);
+	desc->txdw4 |= cpu_to_le32(DISDATAFB);
+
+	if (pmp_priv->preamble) {
+		if (pmp_priv->rateidx <=  MPT_RATE_54M)
+			desc->txdw4 |= cpu_to_le32(DATA_SHORT); /*  CCK Short Preamble */
+	}
+	if (pmp_priv->bandwidth == HT_CHANNEL_WIDTH_40)
+		desc->txdw4 |= cpu_to_le32(DATA_BW);
+
+	/*  offset 20 */
+	desc->txdw5 |= cpu_to_le32(pmp_priv->rateidx & 0x0000001F);
+
+	if (pmp_priv->preamble) {
+		if (pmp_priv->rateidx > MPT_RATE_54M)
+			desc->txdw5 |= cpu_to_le32(SGI); /*  MCS Short Guard Interval */
+	}
+	desc->txdw5 |= cpu_to_le32(RTY_LMT_EN); /*  retry limit enable */
+	desc->txdw5 |= cpu_to_le32(0x00180000); /*  DATA/RTS Rate Fallback Limit */
+
+	/* 3 4. make wlan header, make_wlanhdr() */
+	hdr = (struct rtw_ieee80211_hdr *)pkt_start;
+	SetFrameSubType(&hdr->frame_ctl, pattrib->subtype);
+	memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /*  DA */
+	memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /*  SA */
+	memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); /*  RA, BSSID */
+
+	/* 3 5. make payload */
+	ptr = pkt_start + pattrib->hdrlen;
+
+	switch (pmp_priv->tx.payload) {
+	case 0:
+		payload = 0x00;
+		break;
+	case 1:
+		payload = 0x5a;
+		break;
+	case 2:
+		payload = 0xa5;
+		break;
+	case 3:
+		payload = 0xff;
+		break;
+	default:
+		payload = 0x00;
+		break;
+	}
+
+	_rtw_memset(ptr, payload, pkt_end - ptr);
+
+	/* 3 6. start thread */
+	pmp_priv->tx.PktTxThread = kthread_run(mp_xmit_packet_thread, pmp_priv, "RTW_MP_THREAD");
+	if (IS_ERR(pmp_priv->tx.PktTxThread))
+		DBG_88E("Create PktTx Thread Fail !!!!!\n");
+}
+
+void SetPacketRx(struct adapter *pAdapter, u8 bStartRx)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+
+	if (bStartRx) {
+		/*  Accept CRC error and destination address */
+		pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | ADF | AMF | HTC_LOC_CTRL | APP_MIC | APP_PHYSTS;
+
+		pHalData->ReceiveConfig |= ACRC32;
+
+		rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig);
+
+		/*  Accept all data frames */
+		rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF);
+	} else {
+		rtw_write32(pAdapter, REG_RCR, 0);
+	}
+}
+
+void ResetPhyRxPktCount(struct adapter *pAdapter)
+{
+	u32 i, phyrx_set = 0;
+
+	for (i = 0; i <= 0xF; i++) {
+		phyrx_set = 0;
+		phyrx_set |= _RXERR_RPT_SEL(i);	/* select */
+		phyrx_set |= RXERR_RPT_RST;	/*  set counter to zero */
+		rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set);
+	}
+}
+
+static u32 GetPhyRxPktCounts(struct adapter *pAdapter, u32 selbit)
+{
+	/* selection */
+	u32 phyrx_set = 0, count = 0;
+
+	phyrx_set = _RXERR_RPT_SEL(selbit & 0xF);
+	rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set);
+
+	/* Read packet count */
+	count = rtw_read32(pAdapter, REG_RXERR_RPT) & RXERR_COUNTER_MASK;
+
+	return count;
+}
+
+u32 GetPhyRxPktReceived(struct adapter *pAdapter)
+{
+	u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+
+	OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_OK);
+	CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_OK);
+	HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_OK);
+
+	return OFDM_cnt + CCK_cnt + HT_cnt;
+}
+
+u32 GetPhyRxPktCRC32Error(struct adapter *pAdapter)
+{
+	u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0;
+
+	OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_FAIL);
+	CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_FAIL);
+	HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_FAIL);
+
+	return OFDM_cnt + CCK_cnt + HT_cnt;
+}
+
+/* reg 0x808[9:0]: FFT data x */
+/* reg 0x808[22]:  0  -->  1  to get 1 FFT data y */
+/* reg 0x8B4[15:0]: FFT data y report */
+static u32 rtw_GetPSDData(struct adapter *pAdapter, u32 point)
+{
+	int psd_val;
+
+
+	psd_val = rtw_read32(pAdapter, 0x808);
+	psd_val &= 0xFFBFFC00;
+	psd_val |= point;
+
+	rtw_write32(pAdapter, 0x808, psd_val);
+	rtw_mdelay_os(1);
+	psd_val |= 0x00400000;
+
+	rtw_write32(pAdapter, 0x808, psd_val);
+	rtw_mdelay_os(1);
+	psd_val = rtw_read32(pAdapter, 0x8B4);
+
+	psd_val &= 0x0000FFFF;
+
+	return psd_val;
+}
+
+/*
+ *pts	start_point_min		stop_point_max
+ * 128	64			64 + 128 = 192
+ * 256	128			128 + 256 = 384
+ * 512	256			256 + 512 = 768
+ * 1024	512			512 + 1024 = 1536
+ *
+ */
+u32 mp_query_psd(struct adapter *pAdapter, u8 *data)
+{
+	u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0;
+	u32 psd_data = 0;
+
+
+	if (!netif_running(pAdapter->pnetdev)) {
+		RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! interface not opened!\n"));
+		return 0;
+	}
+
+	if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) {
+		RT_TRACE(_module_mp_, _drv_warning_, ("mp_query_psd: Fail! not in MP mode!\n"));
+		return 0;
+	}
+
+	if (strlen(data) == 0) { /* default value */
+		psd_pts = 128;
+		psd_start = 64;
+		psd_stop = 128;
+	} else {
+		sscanf(data, "pts =%d, start =%d, stop =%d", &psd_pts, &psd_start, &psd_stop);
+	}
+
+	_rtw_memset(data, '\0', sizeof(data));
+
+	i = psd_start;
+	while (i < psd_stop) {
+		if (i >= psd_pts) {
+			psd_data = rtw_GetPSDData(pAdapter, i-psd_pts);
+		} else {
+			psd_data = rtw_GetPSDData(pAdapter, i);
+		}
+		sprintf(data, "%s%x ", data, psd_data);
+		i++;
+	}
+
+	rtw_msleep_os(100);
+	return strlen(data)+1;
+}
+
+void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv)
+{
+	   int i, res;
+	  struct adapter *padapter = pxmitpriv->adapter;
+	struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
+
+	u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+	u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+	if (padapter->registrypriv.mp_mode == 0) {
+		max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+		num_xmit_extbuf = NR_XMIT_EXTBUFF;
+	} else {
+		max_xmit_extbuf_size = 20000;
+		num_xmit_extbuf = 1;
+	}
+
+	pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+	for (i = 0; i < num_xmit_extbuf; i++) {
+		rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ));
+
+		pxmitbuf++;
+	}
+
+	if (pxmitpriv->pallocated_xmit_extbuf)
+		rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+
+	if (padapter->registrypriv.mp_mode == 0) {
+		max_xmit_extbuf_size = 20000;
+		num_xmit_extbuf = 1;
+	} else {
+		max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+		num_xmit_extbuf = NR_XMIT_EXTBUFF;
+	}
+
+	/*  Init xmit extension buff */
+	_rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue);
+
+	pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+
+	if (pxmitpriv->pallocated_xmit_extbuf  == NULL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4);
+
+	pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+
+	for (i = 0; i < num_xmit_extbuf; i++) {
+		_rtw_init_listhead(&pxmitbuf->list);
+
+		pxmitbuf->priv_data = NULL;
+		pxmitbuf->padapter = padapter;
+		pxmitbuf->ext_tag = true;
+
+		res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ);
+		if (res == _FAIL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue));
+		pxmitbuf++;
+	}
+
+	pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf;
+
+exit:
+	;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c b/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
new file mode 100644
index 0000000..f06312c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_mp_ioctl.c
@@ -0,0 +1,1508 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_MP_IOCTL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <mlme_osdep.h>
+
+/* include <rtw_mp.h> */
+#include <rtw_mp_ioctl.h>
+
+
+/*   rtl8188eu_oid_rtl_seg_81_85   section start **************** */
+int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->information_buf_len < sizeof(u8))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	if (poid_par_priv->type_of_oid == SET_OID) {
+		Adapter->registrypriv.wireless_mode = *(u8 *)poid_par_priv->information_buf;
+	} else if (poid_par_priv->type_of_oid == QUERY_OID) {
+		*(u8 *)poid_par_priv->information_buf = Adapter->registrypriv.wireless_mode;
+		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+		 RT_TRACE(_module_mp_, _drv_info_, ("-query Wireless Mode=%d\n", Adapter->registrypriv.wireless_mode));
+	} else {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+	}
+
+_func_exit_;
+
+	return status;
+}
+/*   rtl8188eu_oid_rtl_seg_81_87_80   section start **************** */
+int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct bb_reg_param *pbbreg;
+	u16 offset;
+	u32 value;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_bb_reg_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf);
+
+	offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */
+	if (offset < BB_REG_BASE_ADDR)
+		offset |= BB_REG_BASE_ADDR;
+
+	value = pbbreg->value;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("rtl8188eu_oid_rt_pro_write_bb_reg_hdl: offset=0x%03X value=0x%08X\n",
+		  offset, value));
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	write_bbreg(Adapter, offset, 0xFFFFFFFF, value);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct bb_reg_param *pbbreg;
+	u16 offset;
+	u32 value;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_bb_reg_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf);
+
+	offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */
+	if (offset < BB_REG_BASE_ADDR)
+		offset |= BB_REG_BASE_ADDR;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	value = read_bbreg(Adapter, offset, 0xFFFFFFFF);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	pbbreg->value = value;
+	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("-rtl8188eu_oid_rt_pro_read_bb_reg_hdl: offset=0x%03X value:0x%08X\n",
+		  offset, value));
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct rf_reg_param *pbbreg;
+	u8 path;
+	u8 offset;
+	u32 value;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_write_rf_reg_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf);
+
+	if (pbbreg->path >= MAX_RF_PATH_NUMS)
+		return NDIS_STATUS_NOT_ACCEPTED;
+	if (pbbreg->offset > 0xFF)
+		return NDIS_STATUS_NOT_ACCEPTED;
+	if (pbbreg->value > 0xFFFFF)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	path = (u8)pbbreg->path;
+	offset = (u8)pbbreg->offset;
+	value = pbbreg->value;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("rtl8188eu_oid_rt_pro_write_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n",
+		  path, offset, value));
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	write_rfreg(Adapter, path, offset, value);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct rf_reg_param *pbbreg;
+	u8 path;
+	u8 offset;
+	u32 value;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+	int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_read_rf_reg_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf);
+
+	if (pbbreg->path >= MAX_RF_PATH_NUMS)
+		return NDIS_STATUS_NOT_ACCEPTED;
+	if (pbbreg->offset > 0xFF)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	path = (u8)pbbreg->path;
+	offset = (u8)pbbreg->offset;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	value = read_rfreg(Adapter, path, offset);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	pbbreg->value = value;
+
+	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("-rtl8188eu_oid_rt_pro_read_rf_reg_hdl: path=%d offset=0x%02X value=0x%05X\n",
+		  path, offset, value));
+
+_func_exit_;
+
+	return status;
+}
+/*   rtl8188eu_oid_rtl_seg_81_87_00   section end**************** */
+/*  */
+
+/*   rtl8188eu_oid_rtl_seg_81_80_00   section start **************** */
+/*  */
+int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		ratevalue;/* 4 */
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("+rtl8188eu_oid_rt_pro_set_data_rate_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len != sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	ratevalue = *((u32 *)poid_par_priv->information_buf);/* 4 */
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("rtl8188eu_oid_rt_pro_set_data_rate_hdl: data rate idx=%d\n", ratevalue));
+	if (ratevalue >= MPT_RATE_LAST)
+		return NDIS_STATUS_INVALID_DATA;
+
+	Adapter->mppriv.rateidx = ratevalue;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetDataRate(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		mode;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_start_test_hdl\n"));
+
+	if (Adapter->registrypriv.mp_mode == 0)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	/* IQCalibrateBcut(Adapter); */
+
+	mode = *((u32 *)poid_par_priv->information_buf);
+	Adapter->mppriv.mode = mode;/*  1 for loopback */
+
+	if (mp_start_test(Adapter) == _FAIL) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		goto exit;
+	}
+
+exit:
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_pro_start_test_hdl: mp_mode=%d\n", Adapter->mppriv.mode));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+Set OID_RT_PRO_STOP_TEST\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	mp_stop_test(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("-Set OID_RT_PRO_STOP_TEST\n"));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		Channel;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl\n"));
+
+	if (poid_par_priv->information_buf_len != sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	if (poid_par_priv->type_of_oid == QUERY_OID) {
+		*((u32 *)poid_par_priv->information_buf) = Adapter->mppriv.channel;
+		return NDIS_STATUS_SUCCESS;
+	}
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	Channel = *((u32 *)poid_par_priv->information_buf);
+	RT_TRACE(_module_mp_, _drv_notice_, ("rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl: Channel=%d\n", Channel));
+	if (Channel > 14)
+		return NDIS_STATUS_NOT_ACCEPTED;
+	Adapter->mppriv.channel = Channel;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetChannel(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u16		bandwidth;
+	u16		channel_offset;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("+rtl8188eu_oid_rt_set_bandwidth_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	bandwidth = *((u32 *)poid_par_priv->information_buf);/* 4 */
+	channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+	if (bandwidth != HT_CHANNEL_WIDTH_40)
+		bandwidth = HT_CHANNEL_WIDTH_20;
+	padapter->mppriv.bandwidth = (u8)bandwidth;
+	padapter->mppriv.prime_channel_offset = (u8)channel_offset;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetBandwidth(padapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("-rtl8188eu_oid_rt_set_bandwidth_hdl: bandwidth=%d channel_offset=%d\n",
+		  bandwidth, channel_offset));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		antenna;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_antenna_bb_hdl\n"));
+
+	if (poid_par_priv->information_buf_len != sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	if (poid_par_priv->type_of_oid == SET_OID) {
+		antenna = *(u32 *)poid_par_priv->information_buf;
+
+		Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16);
+		Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF);
+		RT_TRACE(_module_mp_, _drv_notice_,
+			 ("rtl8188eu_oid_rt_pro_set_antenna_bb_hdl: tx_ant=0x%04x rx_ant=0x%04x\n",
+			  Adapter->mppriv.antenna_tx, Adapter->mppriv.antenna_rx));
+
+		_irqlevel_changed_(&oldirql, LOWER);
+		SetAntenna(Adapter);
+		_irqlevel_changed_(&oldirql, RAISE);
+	} else {
+		antenna = (Adapter->mppriv.antenna_tx << 16)|Adapter->mppriv.antenna_rx;
+		*(u32 *)poid_par_priv->information_buf = antenna;
+	}
+
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		tx_pwr_idx;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_set_tx_power_control_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len != sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	tx_pwr_idx = *((u32 *)poid_par_priv->information_buf);
+	if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	Adapter->mppriv.txpoweridx = (u8)tx_pwr_idx;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("rtl8188eu_oid_rt_pro_set_tx_power_control_hdl: idx=0x%2x\n",
+		  Adapter->mppriv.txpoweridx));
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetTxPower(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+
+/*  */
+/*   rtl8188eu_oid_rtl_seg_81_80_20   section start **************** */
+/*  */
+int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != QUERY_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+
+	if (poid_par_priv->information_buf_len == sizeof(u32)) {
+		*(u32 *)poid_par_priv->information_buf =  Adapter->mppriv.tx_pktcount;
+		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+	} else {
+		status = NDIS_STATUS_INVALID_LENGTH;
+	}
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != QUERY_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+	RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl.\n"));
+	if (poid_par_priv->information_buf_len == sizeof(u32)) {
+		*(u32 *)poid_par_priv->information_buf =  Adapter->mppriv.rx_pktcount;
+		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+		RT_TRACE(_module_mp_, _drv_alert_, ("recv_ok:%d\n", Adapter->mppriv.rx_pktcount));
+	} else {
+		status = NDIS_STATUS_INVALID_LENGTH;
+	}
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != QUERY_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+	RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl.\n"));
+	if (poid_par_priv->information_buf_len == sizeof(u32)) {
+		*(u32 *)poid_par_priv->information_buf =  Adapter->mppriv.rx_crcerrpktcount;
+		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+		RT_TRACE(_module_mp_, _drv_alert_, ("recv_err:%d\n", Adapter->mppriv.rx_crcerrpktcount));
+	} else {
+		status = NDIS_STATUS_INVALID_LENGTH;
+	}
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+
+int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != SET_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+
+	RT_TRACE(_module_mp_, _drv_alert_, ("===> rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl.\n"));
+	Adapter->mppriv.tx_pktcount = 0;
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != SET_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+
+	if (poid_par_priv->information_buf_len == sizeof(u32)) {
+		Adapter->mppriv.rx_pktcount = 0;
+		Adapter->mppriv.rx_crcerrpktcount = 0;
+	} else {
+		status = NDIS_STATUS_INVALID_LENGTH;
+	}
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != SET_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	ResetPhyRxPktCount(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len != sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	*(u32 *)poid_par_priv->information_buf = GetPhyRxPktReceived(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("-rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl: recv_ok=%d\n", *(u32 *)poid_par_priv->information_buf));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+
+	if (poid_par_priv->information_buf_len != sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	*(u32 *)poid_par_priv->information_buf = GetPhyRxPktCRC32Error(Adapter);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("-rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl: recv_err =%d\n",
+		 *(u32 *)poid_par_priv->information_buf));
+
+_func_exit_;
+
+	return status;
+}
+/*   rtl8188eu_oid_rtl_seg_81_80_20   section end **************** */
+int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		bStartTest;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_continuous_tx_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetContinuousTx(Adapter, (u8)bStartTest);
+	if (bStartTest) {
+		struct mp_priv *pmp_priv = &Adapter->mppriv;
+		if (pmp_priv->tx.stop == 0) {
+			pmp_priv->tx.stop = 1;
+			DBG_88E("%s: pkt tx is running...\n", __func__);
+			rtw_msleep_os(5);
+		}
+		pmp_priv->tx.stop = 0;
+		pmp_priv->tx.count = 1;
+		SetPacketTx(Adapter);
+	}
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		bStartTest;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetSingleCarrierTx(Adapter, (u8)bStartTest);
+	if (bStartTest) {
+		struct mp_priv *pmp_priv = &Adapter->mppriv;
+		if (pmp_priv->tx.stop == 0) {
+			pmp_priv->tx.stop = 1;
+			DBG_88E("%s: pkt tx is running...\n", __func__);
+			rtw_msleep_os(5);
+		}
+		pmp_priv->tx.stop = 0;
+		pmp_priv->tx.count = 1;
+		SetPacketTx(Adapter);
+	}
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		bStartTest;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetCarrierSuppressionTx(Adapter, (u8)bStartTest);
+	if (bStartTest) {
+		struct mp_priv *pmp_priv = &Adapter->mppriv;
+		if (pmp_priv->tx.stop == 0) {
+			pmp_priv->tx.stop = 1;
+			DBG_88E("%s: pkt tx is running...\n", __func__);
+			rtw_msleep_os(5);
+		}
+		pmp_priv->tx.stop = 0;
+		pmp_priv->tx.count = 1;
+		SetPacketTx(Adapter);
+	}
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u32		bStartTest;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_alert_, ("+rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	bStartTest = *((u32 *)poid_par_priv->information_buf);
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	SetSingleToneTx(Adapter, (u8)bStartTest);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+	int status = NDIS_STATUS_SUCCESS;
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, NULL);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*   rtl8188eu_oid_rtl_seg_81_80_00   section end **************** */
+/*  */
+int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct mp_rw_reg *RegRWStruct;
+	u32		offset, width;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("+rtl8188eu_oid_rt_pro_read_register_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf;
+	offset = RegRWStruct->offset;
+	width = RegRWStruct->width;
+
+	if (offset > 0xFFF)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	switch (width) {
+	case 1:
+		RegRWStruct->value = rtw_read8(Adapter, offset);
+		break;
+	case 2:
+		RegRWStruct->value = rtw_read16(Adapter, offset);
+		break;
+	default:
+		width = 4;
+		RegRWStruct->value = rtw_read32(Adapter, offset);
+		break;
+	}
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("rtl8188eu_oid_rt_pro_read_register_hdl: offset:0x%04X value:0x%X\n",
+		  offset, RegRWStruct->value));
+
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	*poid_par_priv->bytes_rw = width;
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct mp_rw_reg *RegRWStruct;
+	u32		offset, width, value;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("+rtl8188eu_oid_rt_pro_write_register_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf;
+	offset = RegRWStruct->offset;
+	width = RegRWStruct->width;
+	value = RegRWStruct->value;
+
+	if (offset > 0xFFF)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	switch (RegRWStruct->width) {
+	case 1:
+		if (value > 0xFF) {
+			status = NDIS_STATUS_NOT_ACCEPTED;
+			break;
+		}
+		rtw_write8(padapter, offset, (u8)value);
+		break;
+	case 2:
+		if (value > 0xFFFF) {
+			status = NDIS_STATUS_NOT_ACCEPTED;
+			break;
+		}
+		rtw_write16(padapter, offset, (u16)value);
+		break;
+	case 4:
+		rtw_write32(padapter, offset, value);
+		break;
+	default:
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		break;
+	}
+
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("-rtl8188eu_oid_rt_pro_write_register_hdl: offset=0x%08X width=%d value=0x%X\n",
+		  offset, width, value));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+/*  */
+int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+/*  */
+int rtl8188eu_oid_rt_pro_write16_eeprom_hdl (struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int  rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+	int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+OID_RT_PRO_SET_DATA_RATE_EX\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	if (rtw_setdatarate_cmd(Adapter, poid_par_priv->information_buf) != _SUCCESS)
+		status = NDIS_STATUS_NOT_ACCEPTED;
+
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	u8 thermal = 0;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_get_thermal_meter_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	GetThermalMeter(Adapter, &thermal);
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	*(u32 *)poid_par_priv->information_buf = (u32)thermal;
+	*poid_par_priv->bytes_rw = sizeof(u32);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+
+_func_enter_;
+
+	if (poid_par_priv->information_buf_len < sizeof(u8))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	if (poid_par_priv->type_of_oid == SET_OID) {
+		u8 enable;
+
+		enable = *(u8 *)poid_par_priv->information_buf;
+		RT_TRACE(_module_mp_, _drv_notice_,
+			 ("+rtl8188eu_oid_rt_pro_set_power_tracking_hdl: enable =%d\n", enable));
+
+		SetPowerTracking(Adapter, enable);
+	} else {
+		GetPowerTracking(Adapter, (u8 *)poid_par_priv->information_buf);
+	}
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+/*   rtl8188eu_oid_rtl_seg_87_12_00   section start **************** */
+int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return NDIS_STATUS_SUCCESS;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct efuse_access_struct *pefuse;
+	u8 *data;
+	u16 addr = 0, cnts = 0, max_available_size = 0;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(struct efuse_access_struct))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf;
+	addr = pefuse->start_addr;
+	cnts = pefuse->cnts;
+	data = pefuse->data;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("+rtl8188eu_oid_rt_pro_read_efuse_hd: buf_len=%d addr=%d cnts=%d\n",
+		  poid_par_priv->information_buf_len, addr, cnts));
+
+	EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+
+	if ((addr + cnts) > max_available_size) {
+		RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_read_efuse_hdl: parameter error!\n"));
+		return NDIS_STATUS_NOT_ACCEPTED;
+	}
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	if (rtw_efuse_access(Adapter, false, addr, cnts, data) == _FAIL) {
+		RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_read_efuse_hdl: rtw_efuse_access FAIL!\n"));
+		status = NDIS_STATUS_FAILURE;
+	} else {
+		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+	}
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct efuse_access_struct *pefuse;
+	u8 *data;
+	u16 addr = 0, cnts = 0, max_available_size = 0;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf;
+	addr = pefuse->start_addr;
+	cnts = pefuse->cnts;
+	data = pefuse->data;
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("+rtl8188eu_oid_rt_pro_write_efuse_hdl: buf_len=%d addr=0x%04x cnts=%d\n",
+		  poid_par_priv->information_buf_len, addr, cnts));
+
+	EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+
+	if ((addr + cnts) > max_available_size) {
+		RT_TRACE(_module_mp_, _drv_err_, ("!rtl8188eu_oid_rt_pro_write_efuse_hdl: parameter error"));
+		return NDIS_STATUS_NOT_ACCEPTED;
+	}
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	if (rtw_efuse_access(Adapter, true, addr, cnts, data) == _FAIL)
+		status = NDIS_STATUS_FAILURE;
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct pgpkt *ppgpkt;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	*poid_par_priv->bytes_rw = 0;
+
+	if (poid_par_priv->information_buf_len < sizeof(struct pgpkt *))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	ppgpkt = (struct pgpkt *)poid_par_priv->information_buf;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	if (poid_par_priv->type_of_oid == QUERY_OID) {
+		RT_TRACE(_module_mp_, _drv_notice_,
+			 ("rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: Read offset=0x%x\n",\
+			 ppgpkt->offset));
+
+		Efuse_PowerSwitch(Adapter, false, true);
+		if (Efuse_PgPacketRead(Adapter, ppgpkt->offset, ppgpkt->data, false) == true)
+			*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+		else
+			status = NDIS_STATUS_FAILURE;
+		Efuse_PowerSwitch(Adapter, false, false);
+	} else {
+		RT_TRACE(_module_mp_, _drv_notice_,
+			 ("rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: Write offset=0x%x word_en=0x%x\n",\
+			 ppgpkt->offset, ppgpkt->word_en));
+
+		Efuse_PowerSwitch(Adapter, true, true);
+		if (Efuse_PgPacketWrite(Adapter, ppgpkt->offset, ppgpkt->word_en, ppgpkt->data, false) == true)
+			*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+		else
+			status = NDIS_STATUS_FAILURE;
+		Efuse_PowerSwitch(Adapter, true, false);
+	}
+
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("-rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl: status=0x%08X\n", status));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u16 size;
+	u8 ret;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+	ret = efuse_GetCurrentSize(Adapter, &size);
+	_irqlevel_changed_(&oldirql, RAISE);
+	if (ret == _SUCCESS) {
+		*(u32 *)poid_par_priv->information_buf = size;
+		*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+	} else {
+		status = NDIS_STATUS_FAILURE;
+	}
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != QUERY_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(u32))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	*(u32 *)poid_par_priv->information_buf = efuse_GetMaxSize(Adapter);
+	*poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("-rtl8188eu_oid_rt_get_efuse_max_size_hdl: size=%d status=0x%08X\n",
+		  *(int *)poid_par_priv->information_buf, status));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status;
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_info_, ("+rtl8188eu_oid_rt_pro_efuse_hdl\n"));
+
+	if (poid_par_priv->type_of_oid == QUERY_OID)
+		status = rtl8188eu_oid_rt_pro_read_efuse_hdl(poid_par_priv);
+	else
+		status = rtl8188eu_oid_rt_pro_write_efuse_hdl(poid_par_priv);
+
+	RT_TRACE(_module_mp_, _drv_info_, ("-rtl8188eu_oid_rt_pro_efuse_hdl: status=0x%08X\n", status));
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u8		*data;
+	int status = NDIS_STATUS_SUCCESS;
+	struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context);
+	u16	maplen = 0;
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_pro_efuse_map_hdl\n"));
+
+	EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&maplen, false);
+
+	*poid_par_priv->bytes_rw = 0;
+
+	if (poid_par_priv->information_buf_len < maplen)
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	data = (u8 *)poid_par_priv->information_buf;
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	if (poid_par_priv->type_of_oid == QUERY_OID) {
+		RT_TRACE(_module_mp_, _drv_info_,
+			 ("rtl8188eu_oid_rt_pro_efuse_map_hdl: READ\n"));
+
+		if (rtw_efuse_map_read(Adapter, 0, maplen, data) == _SUCCESS) {
+			*poid_par_priv->bytes_rw = maplen;
+		} else {
+			RT_TRACE(_module_mp_, _drv_err_,
+				 ("rtl8188eu_oid_rt_pro_efuse_map_hdl: READ fail\n"));
+			status = NDIS_STATUS_FAILURE;
+		}
+	} else {
+		/*  SET_OID */
+		RT_TRACE(_module_mp_, _drv_info_,
+			 ("rtl8188eu_oid_rt_pro_efuse_map_hdl: WRITE\n"));
+
+		if (rtw_efuse_map_write(Adapter, 0, maplen, data) == _SUCCESS) {
+			*poid_par_priv->bytes_rw = maplen;
+		} else {
+			RT_TRACE(_module_mp_, _drv_err_,
+				 ("rtl8188eu_oid_rt_pro_efuse_map_hdl: WRITE fail\n"));
+			status = NDIS_STATUS_FAILURE;
+		}
+	}
+
+	_irqlevel_changed_(&oldirql, RAISE);
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("-rtl8188eu_oid_rt_pro_efuse_map_hdl: status=0x%08X\n", status));
+
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+	return status;
+}
+
+int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
+{
+	u8		rx_pkt_type;
+	int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+rtl8188eu_oid_rt_set_rx_packet_type_hdl\n"));
+
+	if (poid_par_priv->type_of_oid != SET_OID)
+		return NDIS_STATUS_NOT_ACCEPTED;
+
+	if (poid_par_priv->information_buf_len < sizeof(u8))
+		return NDIS_STATUS_INVALID_LENGTH;
+
+	rx_pkt_type = *((u8 *)poid_par_priv->information_buf);/* 4 */
+
+	RT_TRACE(_module_mp_, _drv_info_, ("rx_pkt_type: %x\n", rx_pkt_type));
+_func_exit_;
+
+	return status;
+}
+
+int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
+
+int rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv)
+{
+	struct mp_xmit_parm *pparm;
+	struct adapter *padapter;
+	struct mp_priv *pmp_priv;
+	struct pkt_attrib *pattrib;
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("+%s\n", __func__));
+
+	pparm = (struct mp_xmit_parm *)poid_par_priv->information_buf;
+	padapter = (struct adapter *)poid_par_priv->adapter_context;
+	pmp_priv = &padapter->mppriv;
+
+	if (poid_par_priv->type_of_oid == QUERY_OID) {
+		pparm->enable = !pmp_priv->tx.stop;
+		pparm->count = pmp_priv->tx.sended;
+	} else {
+		if (pparm->enable == 0) {
+			pmp_priv->tx.stop = 1;
+		} else if (pmp_priv->tx.stop == 1) {
+			pmp_priv->tx.stop = 0;
+			pmp_priv->tx.count = pparm->count;
+			pmp_priv->tx.payload = pparm->payload_type;
+			pattrib = &pmp_priv->tx.attrib;
+			pattrib->pktlen = pparm->length;
+			memcpy(pattrib->dst, pparm->da, ETH_ALEN);
+			SetPacketTx(padapter);
+		} else {
+			return NDIS_STATUS_FAILURE;
+		}
+	}
+
+	return NDIS_STATUS_SUCCESS;
+}
+
+/*  */
+int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv)
+{
+	int status = NDIS_STATUS_SUCCESS;
+
+_func_enter_;
+
+	if (poid_par_priv->type_of_oid != SET_OID) {
+		status = NDIS_STATUS_NOT_ACCEPTED;
+		return status;
+	}
+
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("\n ===> Setrtl8188eu_oid_rt_set_power_down_hdl.\n"));
+
+	_irqlevel_changed_(&oldirql, LOWER);
+
+	/* CALL  the power_down function */
+	_irqlevel_changed_(&oldirql, RAISE);
+
+_func_exit_;
+
+	return status;
+}
+/*  */
+int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv)
+{
+	return 0;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_p2p.c b/drivers/staging/rtl8188eu/core/rtw_p2p.c
new file mode 100644
index 0000000..8cf915f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_p2p.c
@@ -0,0 +1,2064 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_P2P_C_
+
+#include <drv_types.h>
+#include <rtw_p2p.h>
+#include <wifi.h>
+
+#ifdef CONFIG_88EU_P2P
+
+static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt)
+{
+	int found = 0, i = 0;
+
+	for (i = 0; i < ch_cnt; i++) {
+		if (ch_list[i] == desired_ch) {
+			found = 1;
+			break;
+		}
+	}
+	return found;
+}
+
+static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+	unsigned long irqL;
+	struct list_head *phead, *plist;
+	u32 len = 0;
+	u16 attr_len = 0;
+	u8 tmplen, *pdata_attr, *pstart, *pcur;
+	struct sta_info *psta = NULL;
+	struct adapter *padapter = pwdinfo->padapter;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	DBG_88E("%s\n", __func__);
+
+	pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN);
+
+	pstart = pdata_attr;
+	pcur = pdata_attr;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* look up sta asoc_queue */
+	while ((rtw_end_of_queue_search(phead, plist)) == false) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+		plist = get_next(plist);
+
+
+		if (psta->is_p2p_device) {
+			tmplen = 0;
+
+			pcur++;
+
+			/* P2P device address */
+			memcpy(pcur, psta->dev_addr, ETH_ALEN);
+			pcur += ETH_ALEN;
+
+			/* P2P interface address */
+			memcpy(pcur, psta->hwaddr, ETH_ALEN);
+			pcur += ETH_ALEN;
+
+			*pcur = psta->dev_cap;
+			pcur++;
+
+			/* u16*)(pcur) = cpu_to_be16(psta->config_methods); */
+			RTW_PUT_BE16(pcur, psta->config_methods);
+			pcur += 2;
+
+			memcpy(pcur, psta->primary_dev_type, 8);
+			pcur += 8;
+
+			*pcur = psta->num_of_secdev_type;
+			pcur++;
+
+			memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8);
+			pcur += psta->num_of_secdev_type*8;
+
+			if (psta->dev_name_len > 0) {
+				/* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+				RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME);
+				pcur += 2;
+
+				/* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */
+				RTW_PUT_BE16(pcur, psta->dev_name_len);
+				pcur += 2;
+
+				memcpy(pcur, psta->dev_name, psta->dev_name_len);
+				pcur += psta->dev_name_len;
+			}
+
+
+			tmplen = (u8)(pcur-pstart);
+
+			*pstart = (tmplen-1);
+
+			attr_len += tmplen;
+
+			/* pstart += tmplen; */
+			pstart = pcur;
+		}
+	}
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+	if (attr_len > 0)
+		len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr);
+
+	kfree(pdata_attr);
+	return len;
+}
+
+static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct adapter *padapter = pwdinfo->padapter;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */
+	__be32	p2poui = cpu_to_be32(P2POUI);
+	u8	oui_subtype = P2P_GO_DISC_REQUEST;
+	u8	dialogToken = 0;
+
+	DBG_88E("[%s]\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* Build P2P action frame header */
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+	/* there is no IE in this P2P action frame */
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+}
+
+static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct adapter *padapter = pwdinfo->padapter;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	__be32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_DEVDISC_RESP;
+	u8 p2pie[8] = { 0x00 };
+	u32 p2pielen = 0;
+
+	DBG_88E("[%s]\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* Build P2P public action frame header */
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+
+	/* Build P2P IE */
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*  P2P_ATTR_STATUS */
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+}
+
+static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr, u8 *frame_body, u16 config_method)
+{
+	struct adapter *padapter = pwdinfo->padapter;
+	unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+	u8			action = P2P_PUB_ACTION_ACTION;
+	u8			dialogToken = frame_body[7];	/*	The Dialog Token of provisioning discovery request frame. */
+	__be32			p2poui = cpu_to_be32(P2POUI);
+	u8			oui_subtype = P2P_PROVISION_DISC_RESP;
+	u8			wpsie[100] = { 0x00 };
+	u8			wpsielen = 0;
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, myid(&(padapter->eeprompriv)), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+	wpsielen = 0;
+	/*	WPS OUI */
+	RTW_PUT_BE32(wpsie, WPSOUI);
+	wpsielen += 4;
+
+	/*	Config Method */
+	/*	Type: */
+	RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD);
+	wpsielen += 2;
+
+	/*	Length: */
+	RTW_PUT_BE16(wpsie + wpsielen, 0x0002);
+	wpsielen += 2;
+
+	/*	Value: */
+	RTW_PUT_BE16(wpsie + wpsielen, config_method);
+	wpsielen += 2;
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen);
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+
+	return;
+}
+
+static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
+{
+	struct xmit_frame			*pmgntframe;
+	struct pkt_attrib			*pattrib;
+	unsigned char					*pframe;
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	unsigned short				*fctrl;
+	struct adapter *padapter = pwdinfo->padapter;
+	struct xmit_priv			*pxmitpriv = &(padapter->xmitpriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */
+	__be32	p2poui = cpu_to_be32(P2POUI);
+	u8	oui_subtype = P2P_PRESENCE_RESPONSE;
+	u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+	u8 noa_attr_content[32] = { 0x00 };
+	u32 p2pielen = 0;
+
+	DBG_88E("[%s]\n", __func__);
+
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		return;
+
+	/* update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(padapter, pattrib);
+
+	_rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+	pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+	memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+	pmlmeext->mgnt_seq++;
+	SetFrameSubType(pframe, WIFI_ACTION);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* Build P2P action frame header */
+	pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&(p2poui), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+	pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+
+	/* Add P2P IE header */
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/* Add Status attribute in P2P IE */
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
+
+	/* Add NoA attribute in P2P IE */
+	noa_attr_content[0] = 0x1;/* index */
+	noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */
+
+	/* todo: Notice of Absence Descriptor(s) */
+
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content);
+
+
+
+	pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &(pattrib->pktlen));
+
+
+	pattrib->last_txcmdsz = pattrib->pktlen;
+
+	dump_mgntframe(padapter, pmgntframe);
+}
+
+u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+	u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+	u16 capability = 0;
+	u32 len = 0, p2pielen = 0;
+	__le16 le_tmp;
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+
+	/*	According to the P2P Specification, the beacon frame should contain 3 P2P attributes */
+	/*	1. P2P Capability */
+	/*	2. P2P Device ID */
+	/*	3. Notice of Absence (NOA) */
+
+	/*	P2P Capability ATTR */
+	/*	Type: */
+	/*	Length: */
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+	/*	Be able to participate in additional P2P Groups and */
+	/*	support the P2P Invitation Procedure */
+	/*	Group Capability Bitmap, 1 byte */
+	capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY;
+	capability |=  ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8);
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+		capability |= (P2P_GRPCAP_GROUP_FORMATION<<8);
+
+	le_tmp = cpu_to_le16(capability);
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&le_tmp);
+
+	/*  P2P Device ID ATTR */
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr);
+
+	/*  Notice of Absence ATTR */
+	/*	Type: */
+	/*	Length: */
+	/*	Value: */
+
+	pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+	return len;
+}
+
+u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+	u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+	u32 len = 0, p2pielen = 0;
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20100907 */
+	/*	According to the P2P Specification, the probe response frame should contain 5 P2P attributes */
+	/*	1. P2P Capability */
+	/*	2. Extended Listen Timing */
+	/*	3. Notice of Absence (NOA)	(Only GO needs this) */
+	/*	4. Device Info */
+	/*	5. Group Info	(Only GO need this) */
+
+	/*	P2P Capability ATTR */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */
+	RTW_PUT_LE16(p2pie + p2pielen, 0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+	p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+	/*	Group Capability Bitmap, 1 byte */
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		p2pie[p2pielen] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS);
+
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+			p2pie[p2pielen] |= P2P_GRPCAP_GROUP_FORMATION;
+
+		p2pielen++;
+	} else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+		/*	Group Capability Bitmap, 1 byte */
+		if (pwdinfo->persistent_supported)
+			p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+		else
+			p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+	}
+
+	/*	Extended Listen Timing ATTR */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+	/*	Length: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */
+	RTW_PUT_LE16(p2pie + p2pielen, 0x0004);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Availability Period */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */
+	RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF);
+	p2pielen += 2;
+
+	/*	Availability Interval */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */
+	RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF);
+	p2pielen += 2;
+
+
+	/*  Notice of Absence ATTR */
+	/*	Type: */
+	/*	Length: */
+	/*	Value: */
+
+	/*	Device Info ATTR */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+	/*	Length: */
+	/*	21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+	/*	+ NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */
+	RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Config Method */
+	/*	This field should be big endian. Noted by P2P specification. */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */
+	RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm);
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */
+	RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	/* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */
+	RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */
+	RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER);
+	p2pielen += 2;
+
+	/*	Number of Secondary Device Types */
+	p2pie[p2pielen++] = 0x00;	/*	No Secondary Device Type List */
+
+	/*	Device Name */
+	/*	Type: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+	RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */
+	RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+	p2pielen += pwdinfo->device_name_len;
+
+	/*  Group Info ATTR */
+	/*	Type: */
+	/*	Length: */
+	/*	Value: */
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+		p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen);
+
+
+	pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+
+
+	return len;
+}
+
+u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 *pssid, u8 ussidlen, u8 *pdev_raddr)
+{
+	u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+	u32 len = 0, p2pielen = 0;
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*	Commented by Albert 20110301 */
+	/*	According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */
+	/*	1. P2P Capability */
+	/*	2. Device Info */
+	/*	3. Group ID (When joining an operating P2P Group) */
+
+	/*	P2P Capability ATTR */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+	/*	Length: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */
+	RTW_PUT_LE16(p2pie + p2pielen, 0x0002);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	Device Capability Bitmap, 1 byte */
+	p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+	/*	Group Capability Bitmap, 1 byte */
+	if (pwdinfo->persistent_supported)
+		p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+	else
+		p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+
+	/*	Device Info ATTR */
+	/*	Type: */
+	p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+	/*	Length: */
+	/*	21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+	/*	+ NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+	/* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */
+	RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	/*	P2P Device Address */
+	memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+	p2pielen += ETH_ALEN;
+
+	/*	Config Method */
+	/*	This field should be big endian. Noted by P2P specification. */
+	if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) {
+		/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */
+		RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC);
+	} else {
+		/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */
+		RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY);
+	}
+
+	p2pielen += 2;
+
+	/*	Primary Device Type */
+	/*	Category ID */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */
+	RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA);
+	p2pielen += 2;
+
+	/*	OUI */
+	/* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */
+	RTW_PUT_BE32(p2pie + p2pielen, WPSOUI);
+	p2pielen += 4;
+
+	/*	Sub Category ID */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */
+	RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER);
+	p2pielen += 2;
+
+	/*	Number of Secondary Device Types */
+	p2pie[p2pielen++] = 0x00;	/*	No Secondary Device Type List */
+
+	/*	Device Name */
+	/*	Type: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+	RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME);
+	p2pielen += 2;
+
+	/*	Length: */
+	/* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */
+	RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len);
+	p2pielen += 2;
+
+	/*	Value: */
+	memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+	p2pielen += pwdinfo->device_name_len;
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+		/*	Added by Albert 2011/05/19 */
+		/*	In this case, the pdev_raddr is the device address of the group owner. */
+
+		/*	P2P Group ID ATTR */
+		/*	Type: */
+		p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+		/*	Length: */
+		/* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */
+		RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen);
+		p2pielen += 2;
+
+		/*	Value: */
+		memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN);
+		p2pielen += ETH_ALEN;
+
+		memcpy(p2pie + p2pielen, pssid, ussidlen);
+		p2pielen += ussidlen;
+	}
+
+	pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+
+
+	return len;
+}
+
+
+u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code)
+{
+	u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 };
+	u32 len = 0, p2pielen = 0;
+
+	/*	P2P OUI */
+	p2pielen = 0;
+	p2pie[p2pielen++] = 0x50;
+	p2pie[p2pielen++] = 0x6F;
+	p2pie[p2pielen++] = 0x9A;
+	p2pie[p2pielen++] = 0x09;	/*	WFA P2P v1.0 */
+
+	/*  According to the P2P Specification, the Association response frame should contain 2 P2P attributes */
+	/*	1. Status */
+	/*	2. Extended Listen Timing (optional) */
+
+
+	/*	Status ATTR */
+	p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code);
+
+
+	/*  Extended Listen Timing ATTR */
+	/*	Type: */
+	/*	Length: */
+	/*	Value: */
+
+	pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len);
+
+	return len;
+}
+
+u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+	u32 len = 0;
+
+	return len;
+}
+
+u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	u8 *p;
+	u32 ret = false;
+	u8 *p2pie;
+	u32	p2pielen = 0;
+	int ssid_len = 0, rate_cnt = 0;
+
+	p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt,
+			len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
+
+	if (rate_cnt <= 4) {
+		int i, g_rate = 0;
+
+		for (i = 0; i < rate_cnt; i++) {
+			if (((*(p + 2 + i) & 0xff) != 0x02) &&
+			    ((*(p + 2 + i) & 0xff) != 0x04) &&
+			    ((*(p + 2 + i) & 0xff) != 0x0B) &&
+			    ((*(p + 2 + i) & 0xff) != 0x16))
+				g_rate = 1;
+		}
+
+		if (g_rate == 0) {
+			/*	There is no OFDM rate included in SupportedRates IE of this probe request frame */
+			/*	The driver should response this probe request. */
+			return ret;
+		}
+	} else {
+		/*	rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */
+		/*	We should proceed the following check for this probe request. */
+	}
+
+	/*	Added comments by Albert 20100906 */
+	/*	There are several items we should check here. */
+	/*	1. This probe request frame must contain the P2P IE. (Done) */
+	/*	2. This probe request frame must contain the wildcard SSID. (Done) */
+	/*	3. Wildcard BSSID. (Todo) */
+	/*	4. Destination Address. (Done in mgt_dispatcher function) */
+	/*	5. Requested Device Type in WSC IE. (Todo) */
+	/*	6. Device ID attribute in P2P IE. (Todo) */
+
+	p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len,
+			len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_);
+
+	ssid_len &= 0xff;	/*	Just last 1 byte is valid for ssid len of the probe request */
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+		p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen);
+		if (p2pie) {
+			if ((p != NULL) && _rtw_memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid , 7)) {
+				/* todo: */
+				/* Check Requested Device Type attributes in WSC IE. */
+				/* Check Device ID attribute in P2P IE */
+
+				ret = true;
+			} else if ((p != NULL) && (ssid_len == 0)) {
+				ret = true;
+			}
+		} else {
+			/* non -p2p device */
+		}
+	}
+
+
+	return ret;
+}
+
+u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta)
+{
+	u8 status_code = P2P_STATUS_SUCCESS;
+	u8 *pbuf, *pattr_content = NULL;
+	u32 attr_contentlen = 0;
+	u16 cap_attr = 0;
+	unsigned short	frame_type, ie_offset = 0;
+	u8 *ies;
+	u32 ies_len;
+	u8 *p2p_ie;
+	u32	p2p_ielen = 0;
+	__be16 be_tmp;
+	__le16 le_tmp;
+
+	if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+		return P2P_STATUS_FAIL_REQUEST_UNABLE;
+
+	frame_type = GetFrameSubType(pframe);
+	if (frame_type == WIFI_ASSOCREQ)
+		ie_offset = _ASOCREQ_IE_OFFSET_;
+	else /*  WIFI_REASSOCREQ */
+		ie_offset = _REASOCREQ_IE_OFFSET_;
+
+	ies = pframe + WLAN_HDR_A3_LEN + ie_offset;
+	ies_len = len - WLAN_HDR_A3_LEN - ie_offset;
+
+	p2p_ie = rtw_get_p2p_ie(ies , ies_len , NULL, &p2p_ielen);
+
+	if (!p2p_ie) {
+		DBG_88E("[%s] P2P IE not Found!!\n", __func__);
+		status_code =  P2P_STATUS_FAIL_INVALID_PARAM;
+	} else {
+		DBG_88E("[%s] P2P IE Found!!\n", __func__);
+	}
+
+	while (p2p_ie) {
+		/* Check P2P Capability ATTR */
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&le_tmp, (uint *)&attr_contentlen)) {
+			DBG_88E("[%s] Got P2P Capability Attr!!\n", __func__);
+			cap_attr = le16_to_cpu(le_tmp);
+			psta->dev_cap = cap_attr&0xff;
+		}
+
+		/* Check Extended Listen Timing ATTR */
+
+
+		/* Check P2P Device Info ATTR */
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint *)&attr_contentlen)) {
+			DBG_88E("[%s] Got P2P DEVICE INFO Attr!!\n", __func__);
+			pattr_content = rtw_zmalloc(attr_contentlen);
+			pbuf = pattr_content;
+			if (pattr_content) {
+				u8 num_of_secdev_type;
+				u16 dev_name_len;
+
+				rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO , pattr_content, (uint *)&attr_contentlen);
+
+				memcpy(psta->dev_addr,	pattr_content, ETH_ALEN);/* P2P Device Address */
+
+				pattr_content += ETH_ALEN;
+
+				memcpy(&be_tmp, pattr_content, 2);/* Config Methods */
+				psta->config_methods = be16_to_cpu(be_tmp);
+
+				pattr_content += 2;
+
+				memcpy(psta->primary_dev_type, pattr_content, 8);
+
+				pattr_content += 8;
+
+				num_of_secdev_type = *pattr_content;
+				pattr_content += 1;
+
+				if (num_of_secdev_type == 0) {
+					psta->num_of_secdev_type = 0;
+				} else {
+					u32 len;
+
+					psta->num_of_secdev_type = num_of_secdev_type;
+
+					len = (sizeof(psta->secdev_types_list) < (num_of_secdev_type*8)) ?
+					      (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8);
+
+					memcpy(psta->secdev_types_list, pattr_content, len);
+
+					pattr_content += (num_of_secdev_type*8);
+				}
+
+
+				psta->dev_name_len = 0;
+				if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(__be16 *)pattr_content)) {
+					dev_name_len = be16_to_cpu(*(__be16 *)(pattr_content+2));
+
+					psta->dev_name_len = (sizeof(psta->dev_name) < dev_name_len) ? sizeof(psta->dev_name) : dev_name_len;
+
+					memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len);
+				}
+				kfree(pbuf);
+			}
+		}
+
+		/* Get the next P2P IE */
+		p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+	}
+
+	return status_code;
+}
+
+u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	u8 *frame_body;
+	u8 status, dialogToken;
+	struct sta_info *psta = NULL;
+	struct adapter *padapter = pwdinfo->padapter;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *p2p_ie;
+	u32	p2p_ielen = 0;
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	dialogToken = frame_body[7];
+	status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
+
+	p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen);
+	if (p2p_ie) {
+		u8 groupid[38] = { 0x00 };
+		u8 dev_addr[ETH_ALEN] = { 0x00 };
+		u32	attr_contentlen = 0;
+
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
+			if (_rtw_memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) &&
+			    _rtw_memcmp(pwdinfo->p2p_group_ssid, groupid+ETH_ALEN, pwdinfo->p2p_group_ssid_len)) {
+				attr_contentlen = 0;
+				if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) {
+					unsigned long irqL;
+					struct list_head *phead, *plist;
+
+					_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+					phead = &pstapriv->asoc_list;
+					plist = get_next(phead);
+
+					/* look up sta asoc_queue */
+					while ((rtw_end_of_queue_search(phead, plist)) == false) {
+						psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+						plist = get_next(plist);
+
+						if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) &&
+						    _rtw_memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) {
+							/* issue GO Discoverability Request */
+							issue_group_disc_req(pwdinfo, psta->hwaddr);
+							status = P2P_STATUS_SUCCESS;
+							break;
+						} else {
+							status = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+						}
+					}
+					_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+				} else {
+					status = P2P_STATUS_FAIL_INVALID_PARAM;
+				}
+			} else {
+				status = P2P_STATUS_FAIL_INVALID_PARAM;
+			}
+		}
+	}
+
+
+	/* issue Device Discoverability Response */
+	issue_p2p_devdisc_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken);
+
+	return (status == P2P_STATUS_SUCCESS) ? true : false;
+}
+
+u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	return true;
+}
+
+u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo,  u8 *pframe, uint len)
+{
+	u8 *frame_body;
+	u8 *wpsie;
+	uint	wps_ielen = 0, attr_contentlen = 0;
+	u16	uconfig_method = 0;
+	__be16 be_tmp;
+
+	frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	wpsie = rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen);
+	if (wpsie) {
+		if (rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD, (u8 *)&be_tmp, &attr_contentlen)) {
+			uconfig_method = be16_to_cpu(be_tmp);
+			switch (uconfig_method) {
+			case WPS_CM_DISPLYA:
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+				break;
+			case WPS_CM_LABEL:
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3);
+				break;
+			case WPS_CM_PUSH_BUTTON:
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+				break;
+			case WPS_CM_KEYPAD:
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+				break;
+			}
+			issue_p2p_provision_resp(pwdinfo, GetAddr2Ptr(pframe), frame_body, uconfig_method);
+		}
+	}
+	DBG_88E("[%s] config method = %s\n", __func__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req);
+	return true;
+}
+
+u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo,  u8 *pframe)
+{
+	return true;
+}
+
+static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list)
+{
+	u8 i = 0, j = 0;
+	u8 temp = 0;
+	u8 ch_no = 0;
+	ch_content += 3;
+	ch_cnt -= 3;
+
+	while (ch_cnt > 0) {
+		ch_content += 1;
+		ch_cnt -= 1;
+		temp = *ch_content;
+		for (i = 0 ; i < temp ; i++, j++)
+			peer_ch_list[j] = *(ch_content + 1 + i);
+		ch_content += (temp + 1);
+		ch_cnt -= (temp + 1);
+		ch_no += temp ;
+	}
+
+	return ch_no;
+}
+
+static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned)
+{
+	int	i = 0, j = 0, temp = 0;
+	u8 ch_no = 0;
+
+	for (i = 0; i < peer_ch_num; i++) {
+		for (j = temp; j < pmlmeext->max_chan_nums; j++) {
+			if (*(peer_ch_list + i) == pmlmeext->channel_set[j].ChannelNum) {
+				ch_list_inclusioned[ch_no++] = *(peer_ch_list + i);
+				temp = j;
+				break;
+			}
+		}
+	}
+
+	return ch_no;
+}
+
+u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	struct adapter *padapter = pwdinfo->padapter;
+	u8	result = P2P_STATUS_SUCCESS;
+	u32	p2p_ielen = 0, wps_ielen = 0;
+	u8 *ies;
+	u32 ies_len;
+	u8 *p2p_ie;
+	u8 *wpsie;
+	u16		wps_devicepassword_id = 0x0000;
+	uint	wps_devicepassword_id_len = 0;
+	__be16 be_tmp;
+
+	wpsie = rtw_get_wps_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen);
+	if (wpsie) {
+		/*	Commented by Kurt 20120113 */
+		/*	If some device wants to do p2p handshake without sending prov_disc_req */
+		/*	We have to get peer_req_cm from here. */
+		if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+			rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len);
+			wps_devicepassword_id = be16_to_cpu(be_tmp);
+
+			if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+			else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+			else
+				memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+		}
+	} else {
+		DBG_88E("[%s] WPS IE not Found!!\n", __func__);
+		result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+		return result;
+	}
+
+	if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) {
+		result = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY);
+		return result;
+	}
+
+	ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+	ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+	p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+
+	if (!p2p_ie) {
+		DBG_88E("[%s] P2P IE not Found!!\n", __func__);
+		result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+	}
+
+	while (p2p_ie) {
+		u8	attr_content = 0x00;
+		u32	attr_contentlen = 0;
+		u8	ch_content[50] = { 0x00 };
+		uint	ch_cnt = 0;
+		u8	peer_ch_list[50] = { 0x00 };
+		u8	peer_ch_num = 0;
+		u8	ch_list_inclusioned[50] = { 0x00 };
+		u8	ch_num_inclusioned = 0;
+
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
+
+			if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) {
+			DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01);
+			pwdinfo->peer_intent = attr_content;	/*	include both intent and tie breaker values. */
+
+			if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) {
+				/*	Try to match the tie breaker value */
+				if (pwdinfo->intent == P2P_MAX_INTENT) {
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+					result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
+				} else {
+					if (attr_content & 0x01)
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+					else
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+				}
+			} else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) {
+				rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+			} else {
+				rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+			}
+
+			if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+				/*	Store the group id information. */
+				memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
+				memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+			}
+		}
+
+
+		attr_contentlen = 0;
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) {
+			if (attr_contentlen != ETH_ALEN)
+				_rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+		}
+
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) {
+			peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list);
+			ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+
+			if (ch_num_inclusioned == 0) {
+				DBG_88E("[%s] No common channel in channel list!\n", __func__);
+				result = P2P_STATUS_FAIL_NO_COMMON_CH;
+				rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+				break;
+			}
+
+			if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+				if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
+				    ch_list_inclusioned, ch_num_inclusioned)) {
+					u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
+					attr_contentlen = 0;
+
+					if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+						peer_operating_ch = operatingch_info[4];
+
+					if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
+								       ch_list_inclusioned, ch_num_inclusioned)) {
+						/**
+						 *	Change our operating channel as peer's for compatibility.
+						 */
+						pwdinfo->operating_channel = peer_operating_ch;
+						DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel);
+					} else {
+						/*  Take first channel of ch_list_inclusioned as operating channel */
+						pwdinfo->operating_channel = ch_list_inclusioned[0];
+						DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel);
+					}
+				}
+			}
+		}
+
+		/* Get the next P2P IE */
+		p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+	}
+	return result;
+}
+
+u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	struct adapter *padapter = pwdinfo->padapter;
+	u8	result = P2P_STATUS_SUCCESS;
+	u32	p2p_ielen, wps_ielen;
+	u8 *ies;
+	u32 ies_len;
+	u8 *p2p_ie;
+
+	ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+	ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+	/*	Be able to know which one is the P2P GO and which one is P2P client. */
+
+	if (rtw_get_wps_ie(ies, ies_len, NULL, &wps_ielen)) {
+	} else {
+		DBG_88E("[%s] WPS IE not Found!!\n", __func__);
+		result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+	}
+
+	p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+	if (!p2p_ie) {
+		rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+		result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+	} else {
+		u8	attr_content = 0x00;
+		u32	attr_contentlen = 0;
+		u8	operatingch_info[5] = { 0x00 };
+		u8	groupid[38];
+		u8	peer_ch_list[50] = { 0x00 };
+		u8	peer_ch_num = 0;
+		u8	ch_list_inclusioned[50] = { 0x00 };
+		u8	ch_num_inclusioned = 0;
+
+		while (p2p_ie) {	/*	Found the P2P IE. */
+			rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+			if (attr_contentlen == 1) {
+				DBG_88E("[%s] Status = %d\n", __func__, attr_content);
+				if (attr_content == P2P_STATUS_SUCCESS) {
+					/*	Do nothing. */
+				} else {
+					if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) {
+						rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY);
+					} else {
+						rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+					}
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+					result = attr_content;
+					break;
+				}
+			}
+
+			/*	Try to get the peer's interface address */
+			attr_contentlen = 0;
+			if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) {
+				if (attr_contentlen != ETH_ALEN)
+					_rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+			}
+
+			/*	Try to get the peer's intent and tie breaker value. */
+			attr_content = 0x00;
+			attr_contentlen = 0;
+			if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) {
+				DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01);
+				pwdinfo->peer_intent = attr_content;	/*	include both intent and tie breaker values. */
+
+				if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) {
+					/*	Try to match the tie breaker value */
+					if (pwdinfo->intent == P2P_MAX_INTENT) {
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+						result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
+						rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+					} else {
+						rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+						rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+						if (attr_content & 0x01)
+							rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+						else
+							rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+					}
+				} else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) {
+					rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+					rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+				} else {
+					rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+					rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+				}
+
+				if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+					/*	Store the group id information. */
+					memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
+					memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+				}
+			}
+
+			/*	Try to get the operation channel information */
+
+			attr_contentlen = 0;
+			if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
+				DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]);
+				pwdinfo->peer_operating_ch = operatingch_info[4];
+			}
+
+			/*	Try to get the channel list information */
+			if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) {
+				DBG_88E("[%s] channel list attribute found, len = %d\n", __func__,  pwdinfo->channel_list_attr_len);
+
+				peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list);
+				ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+
+				if (ch_num_inclusioned == 0) {
+					DBG_88E("[%s] No common channel in channel list!\n", __func__);
+					result = P2P_STATUS_FAIL_NO_COMMON_CH;
+					rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+					break;
+				}
+
+				if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+					if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
+					    ch_list_inclusioned, ch_num_inclusioned)) {
+						u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
+						attr_contentlen = 0;
+
+						if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+							peer_operating_ch = operatingch_info[4];
+
+						if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
+						    ch_list_inclusioned, ch_num_inclusioned)) {
+							/**
+							 *	Change our operating channel as peer's for compatibility.
+							 */
+							pwdinfo->operating_channel = peer_operating_ch;
+							DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel);
+						} else {
+							/*  Take first channel of ch_list_inclusioned as operating channel */
+							pwdinfo->operating_channel = ch_list_inclusioned[0];
+							DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel);
+						}
+					}
+				}
+			} else {
+				DBG_88E("[%s] channel list attribute not found!\n", __func__);
+			}
+
+			/*	Try to get the group id information if peer is GO */
+			attr_contentlen = 0;
+			_rtw_memset(groupid, 0x00, 38);
+			if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
+				memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
+				memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
+			}
+
+			/* Get the next P2P IE */
+			p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+		}
+	}
+	return result;
+}
+
+u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	u8 *ies;
+	u32 ies_len;
+	u8 *p2p_ie;
+	u32	p2p_ielen = 0;
+	u8	result = P2P_STATUS_SUCCESS;
+	ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+	ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+	p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+	while (p2p_ie) {	/*	Found the P2P IE. */
+		u8	attr_content = 0x00, operatingch_info[5] = { 0x00 };
+		u8	groupid[38] = { 0x00 };
+		u32	attr_contentlen = 0;
+
+		pwdinfo->negotiation_dialog_token = 1;
+		rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+		if (attr_contentlen == 1) {
+			DBG_88E("[%s] Status = %d\n", __func__, attr_content);
+			result = attr_content;
+
+			if (attr_content == P2P_STATUS_SUCCESS) {
+				u8	bcancelled = 0;
+
+				_cancel_timer(&pwdinfo->restore_p2p_state_timer, &bcancelled);
+
+				/*	Commented by Albert 20100911 */
+				/*	Todo: Need to handle the case which both Intents are the same. */
+				rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+				rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+				if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) {
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+				} else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) {
+					rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+				} else {
+					/*	Have to compare the Tie Breaker */
+					if (pwdinfo->peer_intent & 0x01)
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+					else
+						rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+				}
+			} else {
+				rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+				rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+				break;
+			}
+		}
+
+		/*	Try to get the group id information */
+		attr_contentlen = 0;
+		_rtw_memset(groupid, 0x00, 38);
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) {
+			DBG_88E("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN]));
+			memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
+			memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
+		}
+
+		attr_contentlen = 0;
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) {
+			DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]);
+			pwdinfo->peer_operating_ch = operatingch_info[4];
+		}
+
+		/* Get the next P2P IE */
+		p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+	}
+	return result;
+}
+
+u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+	u8 *frame_body;
+	u8 dialogToken = 0;
+	u8 status = P2P_STATUS_SUCCESS;
+
+	frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr));
+
+	dialogToken = frame_body[6];
+
+	/* todo: check NoA attribute */
+
+	issue_p2p_presence_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken);
+
+	return true;
+}
+
+static void find_phase_handler(struct adapter *padapter)
+{
+	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct ndis_802_11_ssid	ssid;
+	unsigned long				irqL;
+
+_func_enter_;
+
+	_rtw_memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid));
+	memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+	ssid.SsidLength = P2P_WILDCARD_SSID_LEN;
+
+	rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+
+
+_func_exit_;
+}
+
+void p2p_concurrent_handler(struct adapter *padapter);
+
+static void restore_p2p_state_handler(struct adapter *padapter)
+{
+	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+
+_func_enter_;
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+		rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+	rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+	if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+		/*	In the P2P client mode, the driver should not switch back to its listen channel */
+		/*	because this P2P client should stay at the operating channel of P2P GO. */
+		set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+	}
+_func_exit_;
+}
+
+static void pre_tx_invitereq_handler(struct adapter *padapter)
+{
+	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+	u8	val8 = 1;
+_func_enter_;
+
+	set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+	padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+	issue_probereq_p2p(padapter, NULL);
+	_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+_func_exit_;
+}
+
+static void pre_tx_provdisc_handler(struct adapter *padapter)
+{
+	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+	u8	val8 = 1;
+_func_enter_;
+
+	set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+	rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+	issue_probereq_p2p(padapter, NULL);
+	_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+_func_exit_;
+}
+
+static void pre_tx_negoreq_handler(struct adapter *padapter)
+{
+	struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+	u8	val8 = 1;
+_func_enter_;
+
+	set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+	rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+	issue_probereq_p2p(padapter, NULL);
+	_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+_func_exit_;
+}
+
+void p2p_protocol_wk_hdl(struct adapter *padapter, int intCmdType)
+{
+_func_enter_;
+	switch (intCmdType) {
+	case P2P_FIND_PHASE_WK:
+		find_phase_handler(padapter);
+		break;
+	case P2P_RESTORE_STATE_WK:
+		restore_p2p_state_handler(padapter);
+		break;
+	case P2P_PRE_TX_PROVDISC_PROCESS_WK:
+		pre_tx_provdisc_handler(padapter);
+		break;
+	case P2P_PRE_TX_INVITEREQ_PROCESS_WK:
+		pre_tx_invitereq_handler(padapter);
+		break;
+	case P2P_PRE_TX_NEGOREQ_PROCESS_WK:
+		pre_tx_negoreq_handler(padapter);
+		break;
+	}
+
+_func_exit_;
+}
+
+void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength)
+{
+	u8 *ies;
+	u32 ies_len;
+	u8 *p2p_ie;
+	u32	p2p_ielen = 0;
+	u8	noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/*  NoA length should be n*(13) + 2 */
+	u32	attr_contentlen = 0;
+
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	u8	find_p2p = false, find_p2p_ps = false;
+	u8	noa_offset, noa_num, noa_index;
+
+_func_enter_;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+	if (IELength <= _BEACON_IE_OFFSET_)
+		return;
+
+	ies = IEs + _BEACON_IE_OFFSET_;
+	ies_len = IELength - _BEACON_IE_OFFSET_;
+
+	p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen);
+
+	while (p2p_ie) {
+		find_p2p = true;
+		/*  Get Notice of Absence IE. */
+		if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) {
+			find_p2p_ps = true;
+			noa_index = noa_attr[0];
+
+			if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) ||
+			    (noa_index != pwdinfo->noa_index)) { /*  if index change, driver should reconfigure related setting. */
+				pwdinfo->noa_index = noa_index;
+				pwdinfo->opp_ps = noa_attr[1] >> 7;
+				pwdinfo->ctwindow = noa_attr[1] & 0x7F;
+
+				noa_offset = 2;
+				noa_num = 0;
+				/*  NoA length should be n*(13) + 2 */
+				if (attr_contentlen > 2) {
+					while (noa_offset < attr_contentlen) {
+						/* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */
+						pwdinfo->noa_count[noa_num] = noa_attr[noa_offset];
+						noa_offset += 1;
+
+						memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4);
+						noa_offset += 4;
+
+						memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4);
+						noa_offset += 4;
+
+						memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4);
+						noa_offset += 4;
+
+						noa_num++;
+					}
+				}
+				pwdinfo->noa_num = noa_num;
+
+				if (pwdinfo->opp_ps == 1) {
+					pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+					/*  driver should wait LPS for entering CTWindow */
+					if (padapter->pwrctrlpriv.bFwCurrentInPSMode)
+						p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1);
+				} else if (pwdinfo->noa_num > 0) {
+					pwdinfo->p2p_ps_mode = P2P_PS_NOA;
+					p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1);
+				} else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+					p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
+				}
+			}
+
+			break; /*  find target, just break. */
+		}
+
+		/* Get the next P2P IE */
+		p2p_ie = rtw_get_p2p_ie(p2p_ie+p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen);
+	}
+
+	if (find_p2p) {
+		if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && !find_p2p_ps)
+			p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1);
+	}
+
+_func_exit_;
+}
+
+void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state)
+{
+	struct pwrctrl_priv		*pwrpriv = &padapter->pwrctrlpriv;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+
+_func_enter_;
+
+	/*  Pre action for p2p state */
+	switch (p2p_ps_state) {
+	case P2P_PS_DISABLE:
+		pwdinfo->p2p_ps_state = p2p_ps_state;
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+
+		pwdinfo->noa_index = 0;
+		pwdinfo->ctwindow = 0;
+		pwdinfo->opp_ps = 0;
+		pwdinfo->noa_num = 0;
+		pwdinfo->p2p_ps_mode = P2P_PS_NONE;
+		if (padapter->pwrctrlpriv.bFwCurrentInPSMode) {
+			if (pwrpriv->smart_ps == 0) {
+				pwrpriv->smart_ps = 2;
+				rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(padapter->pwrctrlpriv.pwr_mode)));
+			}
+		}
+		break;
+	case P2P_PS_ENABLE:
+		if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+			pwdinfo->p2p_ps_state = p2p_ps_state;
+
+			if (pwdinfo->ctwindow > 0) {
+				if (pwrpriv->smart_ps != 0) {
+					pwrpriv->smart_ps = 0;
+					DBG_88E("%s(): Enter CTW, change SmartPS\n", __func__);
+					rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(padapter->pwrctrlpriv.pwr_mode)));
+				}
+			}
+			rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+		}
+		break;
+	case P2P_PS_SCAN:
+	case P2P_PS_SCAN_DONE:
+	case P2P_PS_ALLSTASLEEP:
+		if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+			pwdinfo->p2p_ps_state = p2p_ps_state;
+			rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+		}
+		break;
+	default:
+		break;
+	}
+
+_func_exit_;
+}
+
+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue)
+{
+	struct cmd_obj	*ph2c;
+	struct drvextra_cmd_parm	*pdrvextra_cmd_parm;
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8	res = _SUCCESS;
+
+_func_enter_;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return res;
+
+	if (enqueue) {
+		ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+		if (ph2c == NULL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm));
+		if (pdrvextra_cmd_parm == NULL) {
+			kfree(ph2c);
+			res = _FAIL;
+			goto exit;
+		}
+
+		pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID;
+		pdrvextra_cmd_parm->type_size = p2p_ps_state;
+		pdrvextra_cmd_parm->pbuf = NULL;
+
+		init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+		res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+	} else {
+		p2p_ps_wk_hdl(padapter, p2p_ps_state);
+	}
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void reset_ch_sitesurvey_timer_process (void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+
+	DBG_88E("[%s] In\n", __func__);
+	/*	Reset the operation channel information */
+	pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
+	pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
+}
+
+static void reset_ch_sitesurvey_timer_process2 (void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+
+	DBG_88E("[%s] In\n", __func__);
+	/*	Reset the operation channel information */
+	pwdinfo->p2p_info.operation_ch[0] = 0;
+	pwdinfo->p2p_info.scan_op_ch_only = 0;
+}
+
+static void restore_p2p_state_timer_process (void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+
+	p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK);
+}
+
+static void pre_tx_scan_timer_process(void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+	struct	wifidirect_info *pwdinfo = &adapter->wdinfo;
+	unsigned long irqL;
+	struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+		if (pwdinfo->tx_prov_disc_info.benable) {	/*	the provision discovery request frame is trigger to send or not */
+			p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK);
+			/* issue_probereq_p2p(adapter, NULL); */
+			/* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */
+		}
+	} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+		if (pwdinfo->nego_req_info.benable)
+			p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK);
+	} else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
+		if (pwdinfo->invitereq_info.benable)
+			p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK);
+	} else {
+		DBG_88E("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo));
+	}
+
+	_exit_critical_bh(&pmlmepriv->lock, &irqL);
+}
+
+static void find_phase_timer_process(void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+	struct	wifidirect_info		*pwdinfo = &adapter->wdinfo;
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+
+	adapter->wdinfo.find_phase_state_exchange_cnt++;
+
+	p2p_protocol_wk_cmd(adapter, P2P_FIND_PHASE_WK);
+}
+
+void reset_global_wifidirect_info(struct adapter *padapter)
+{
+	struct wifidirect_info	*pwdinfo;
+
+	pwdinfo = &padapter->wdinfo;
+	pwdinfo->persistent_supported = 0;
+	pwdinfo->session_available = true;
+	pwdinfo->wfd_tdls_enable = 0;
+	pwdinfo->wfd_tdls_weaksec = 0;
+}
+
+void rtw_init_wifidirect_timers(struct adapter *padapter)
+{
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+	_init_timer(&pwdinfo->find_phase_timer, padapter->pnetdev, find_phase_timer_process, padapter);
+	_init_timer(&pwdinfo->restore_p2p_state_timer, padapter->pnetdev, restore_p2p_state_timer_process, padapter);
+	_init_timer(&pwdinfo->pre_tx_scan_timer, padapter->pnetdev, pre_tx_scan_timer_process, padapter);
+	_init_timer(&pwdinfo->reset_ch_sitesurvey, padapter->pnetdev, reset_ch_sitesurvey_timer_process, padapter);
+	_init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter->pnetdev, reset_ch_sitesurvey_timer_process2, padapter);
+}
+
+void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr, u8 *iface_addr)
+{
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+	/*init device&interface address */
+	if (dev_addr)
+		memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN);
+	if (iface_addr)
+		memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN);
+#endif
+}
+
+void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role)
+{
+	struct wifidirect_info	*pwdinfo;
+
+	pwdinfo = &padapter->wdinfo;
+	pwdinfo->padapter = padapter;
+
+	/*	1, 6, 11 are the social channel defined in the WiFi Direct specification. */
+	pwdinfo->social_chan[0] = 1;
+	pwdinfo->social_chan[1] = 6;
+	pwdinfo->social_chan[2] = 11;
+	pwdinfo->social_chan[3] = 0;	/*	channel 0 for scanning ending in site survey function. */
+
+	/*	Use the channel 11 as the listen channel */
+	pwdinfo->listen_channel = 11;
+
+	if (role == P2P_ROLE_DEVICE) {
+		rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+		pwdinfo->intent = 1;
+		rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN);
+	} else if (role == P2P_ROLE_CLIENT) {
+		rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+		pwdinfo->intent = 1;
+		rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+	} else if (role == P2P_ROLE_GO) {
+		rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+		pwdinfo->intent = 15;
+		rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+	}
+
+/*	Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */
+	pwdinfo->support_rate[0] = 0x8c;	/*	6(B) */
+	pwdinfo->support_rate[1] = 0x92;	/*	9(B) */
+	pwdinfo->support_rate[2] = 0x18;	/*	12 */
+	pwdinfo->support_rate[3] = 0x24;	/*	18 */
+	pwdinfo->support_rate[4] = 0x30;	/*	24 */
+	pwdinfo->support_rate[5] = 0x48;	/*	36 */
+	pwdinfo->support_rate[6] = 0x60;	/*	48 */
+	pwdinfo->support_rate[7] = 0x6c;	/*	54 */
+
+	memcpy(pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7);
+
+	_rtw_memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
+	pwdinfo->device_name_len = 0;
+
+	_rtw_memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info));
+	pwdinfo->invitereq_info.token = 3;	/*	Token used for P2P invitation request frame. */
+
+	_rtw_memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info));
+	pwdinfo->inviteresp_info.token = 0;
+
+	pwdinfo->profileindex = 0;
+	_rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
+
+	rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+
+	pwdinfo->listen_dwell = (u8) ((rtw_get_current_time() % 3) + 1);
+
+	_rtw_memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info));
+	pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE;
+
+	_rtw_memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
+
+	pwdinfo->device_password_id_for_nego = WPS_DPID_PBC;
+	pwdinfo->negotiation_dialog_token = 1;
+
+	_rtw_memset(pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN);
+	pwdinfo->nego_ssidlen = 0;
+
+	pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+	pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD;
+	pwdinfo->channel_list_attr_len = 0;
+	_rtw_memset(pwdinfo->channel_list_attr, 0x00, 100);
+
+	_rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4);
+	_rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3);
+	_rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+	pwdinfo->wfd_tdls_enable = 0;
+	_rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+	_rtw_memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN);
+
+	pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
+	pwdinfo->rx_invitereq_info.operation_ch[1] = 0;	/*	Used to indicate the scan end in site survey function */
+	pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
+	pwdinfo->p2p_info.operation_ch[0] = 0;
+	pwdinfo->p2p_info.operation_ch[1] = 0;			/*	Used to indicate the scan end in site survey function */
+	pwdinfo->p2p_info.scan_op_ch_only = 0;
+}
+
+int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role)
+{
+	int ret = _SUCCESS;
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) {
+		/* leave IPS/Autosuspend */
+		if (_FAIL == rtw_pwr_wakeup(padapter)) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*	Added by Albert 2011/03/22 */
+		/*	In the P2P mode, the driver should not support the b mode. */
+		/*	So, the Tx packet shouldn't use the CCK rate */
+		update_tx_basic_rate(padapter, WIRELESS_11AGN);
+
+		/* Enable P2P function */
+		init_wifidirect_info(padapter, role);
+
+		rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, true);
+	} else if (role == P2P_ROLE_DISABLE) {
+		if (_FAIL == rtw_pwr_wakeup(padapter)) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/* Disable P2P function */
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+			_cancel_timer_ex(&pwdinfo->find_phase_timer);
+			_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+			_cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
+			_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey);
+			_cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2);
+			reset_ch_sitesurvey_timer_process(padapter);
+			reset_ch_sitesurvey_timer_process2(padapter);
+			rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+			rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE);
+			_rtw_memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info));
+		}
+
+		rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, false);
+
+		/* Restore to initial setting. */
+		update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode);
+	}
+
+exit:
+	return ret;
+}
+
+#else
+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue)
+{
+	return _FAIL;
+}
+
+void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength)
+{
+}
+
+#endif /* CONFIG_88EU_P2P */
diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
new file mode 100644
index 0000000..58a1661
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c
@@ -0,0 +1,662 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_PWRCTRL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+#include <linux/usb.h>
+
+void ips_enter(struct adapter *padapter)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct xmit_priv *pxmit_priv = &padapter->xmitpriv;
+
+	if (padapter->registrypriv.mp_mode == 1)
+		return;
+
+	if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
+	    pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
+		DBG_88E_LEVEL(_drv_info_, "There are some pkts to transmit\n");
+		DBG_88E_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
+			      pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt);
+		return;
+	}
+
+	_enter_pwrlock(&pwrpriv->lock);
+
+	pwrpriv->bips_processing = true;
+
+	/*  syn ips_mode with request */
+	pwrpriv->ips_mode = pwrpriv->ips_mode_req;
+
+	pwrpriv->ips_enter_cnts++;
+	DBG_88E("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts);
+	if (rf_off == pwrpriv->change_rfpwrstate) {
+		pwrpriv->bpower_saving = true;
+		DBG_88E_LEVEL(_drv_info_, "nolinked power save enter\n");
+
+		if (pwrpriv->ips_mode == IPS_LEVEL_2)
+			pwrpriv->bkeepfwalive = true;
+
+		rtw_ips_pwr_down(padapter);
+		pwrpriv->rf_pwrstate = rf_off;
+	}
+	pwrpriv->bips_processing = false;
+
+	_exit_pwrlock(&pwrpriv->lock);
+}
+
+int ips_leave(struct adapter *padapter)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	int result = _SUCCESS;
+	int keyid;
+
+
+	_enter_pwrlock(&pwrpriv->lock);
+
+	if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) {
+		pwrpriv->bips_processing = true;
+		pwrpriv->change_rfpwrstate = rf_on;
+		pwrpriv->ips_leave_cnts++;
+		DBG_88E("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts);
+
+		result = rtw_ips_pwr_up(padapter);
+		if (result == _SUCCESS) {
+			pwrpriv->rf_pwrstate = rf_on;
+		}
+		DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n");
+
+		if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) || (_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) {
+			DBG_88E("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing);
+			set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+			for (keyid = 0; keyid < 4; keyid++) {
+				if (pmlmepriv->key_mask & BIT(keyid)) {
+					if (keyid == psecuritypriv->dot11PrivacyKeyIndex)
+						result = rtw_set_key(padapter, psecuritypriv, keyid, 1);
+					else
+						result = rtw_set_key(padapter, psecuritypriv, keyid, 0);
+				}
+			}
+		}
+
+		DBG_88E("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c));
+		pwrpriv->bips_processing = false;
+
+		pwrpriv->bkeepfwalive = false;
+		pwrpriv->bpower_saving = false;
+	}
+
+	_exit_pwrlock(&pwrpriv->lock);
+
+	return result;
+}
+
+static bool rtw_pwr_unassociated_idle(struct adapter *adapter)
+{
+	struct adapter *buddy = adapter->pbuddy_adapter;
+	struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(adapter->wdinfo);
+#endif
+
+	bool ret = false;
+
+	if (adapter->pwrctrlpriv.ips_deny_time >= rtw_get_current_time())
+		goto exit;
+
+	if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ||
+	    check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ||
+	    check_fwstate(pmlmepriv, WIFI_AP_STATE) ||
+	    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ||
+#if defined(CONFIG_88EU_P2P)
+	    !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+#else
+	    0)
+#endif
+		goto exit;
+
+	/* consider buddy, if exist */
+	if (buddy) {
+		struct mlme_priv *b_pmlmepriv = &(buddy->mlmepriv);
+		#ifdef CONFIG_88EU_P2P
+		struct wifidirect_info *b_pwdinfo = &(buddy->wdinfo);
+		#endif
+
+		if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR) ||
+		    check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS) ||
+		    check_fwstate(b_pmlmepriv, WIFI_AP_STATE) ||
+		    check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE) ||
+#if defined(CONFIG_88EU_P2P)
+		    !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE))
+#else
+		    0)
+#endif
+			goto exit;
+	}
+	ret = true;
+
+exit:
+	return ret;
+}
+
+void rtw_ps_processor(struct adapter *padapter)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	enum rt_rf_power_state rfpwrstate;
+
+	pwrpriv->ps_processing = true;
+
+	if (pwrpriv->bips_processing)
+		goto exit;
+
+	if (padapter->pwrctrlpriv.bHWPwrPindetect) {
+		rfpwrstate = RfOnOffDetect(padapter);
+		DBG_88E("@@@@- #2  %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off");
+
+		if (rfpwrstate != pwrpriv->rf_pwrstate) {
+			if (rfpwrstate == rf_off) {
+				pwrpriv->change_rfpwrstate = rf_off;
+				pwrpriv->brfoffbyhw = true;
+				padapter->bCardDisableWOHSM = true;
+				rtw_hw_suspend(padapter);
+			} else {
+				pwrpriv->change_rfpwrstate = rf_on;
+				rtw_hw_resume(padapter);
+			}
+			DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on");
+		}
+		pwrpriv->pwr_state_check_cnts++;
+	}
+
+	if (pwrpriv->ips_mode_req == IPS_NONE)
+		goto exit;
+
+	if (rtw_pwr_unassociated_idle(padapter) == false)
+		goto exit;
+
+	if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0)) {
+		DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv));
+		pwrpriv->change_rfpwrstate = rf_off;
+
+		ips_enter(padapter);
+	}
+exit:
+	rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+	pwrpriv->ps_processing = false;
+	return;
+}
+
+static void pwr_state_check_handler(void *FunctionContext)
+{
+	struct adapter *padapter = (struct adapter *)FunctionContext;
+	rtw_ps_cmd(padapter);
+}
+
+/*
+ *
+ * Parameters
+ *	padapter
+ *	pslv			power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
+ *
+ */
+void rtw_set_rpwm(struct adapter *padapter, u8 pslv)
+{
+	u8	rpwm;
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+	pslv = PS_STATE(pslv);
+
+
+	if (pwrpriv->btcoex_rfon) {
+		if (pslv < PS_STATE_S4)
+			pslv = PS_STATE_S3;
+	}
+
+	if ((pwrpriv->rpwm == pslv)) {
+		RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+			 ("%s: Already set rpwm[0x%02X], new=0x%02X!\n", __func__, pwrpriv->rpwm, pslv));
+		return;
+	}
+
+	if ((padapter->bSurpriseRemoved) ||
+	    (!padapter->hw_init_completed)) {
+		RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+			 ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
+			 __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
+
+		pwrpriv->cpwm = PS_STATE_S4;
+
+		return;
+	}
+
+	if (padapter->bDriverStopped) {
+		RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+			 ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
+
+		if (pslv < PS_STATE_S2) {
+			RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+				 ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv));
+			return;
+		}
+	}
+
+	rpwm = pslv | pwrpriv->tog;
+	RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+		 ("rtw_set_rpwm: rpwm=0x%02x cpwm=0x%02x\n", rpwm, pwrpriv->cpwm));
+
+	pwrpriv->rpwm = pslv;
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
+
+	pwrpriv->tog += 0x80;
+	pwrpriv->cpwm = pslv;
+
+_func_exit_;
+}
+
+static u8 PS_RDY_CHECK(struct adapter *padapter)
+{
+	u32 curr_time, delta_time;
+	struct pwrctrl_priv	*pwrpriv = &padapter->pwrctrlpriv;
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+
+
+	curr_time = rtw_get_current_time();
+	delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp;
+
+	if (delta_time < LPS_DELAY_TIME)
+		return false;
+
+	if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) ||
+	    (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ||
+	    (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
+		return false;
+	if (pwrpriv->bInSuspend)
+		return false;
+	if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false)) {
+		DBG_88E("Group handshake still in progress !!!\n");
+		return false;
+	}
+	return true;
+}
+
+void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info	*pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+		 ("%s: PowerMode=%d Smart_PS=%d\n",
+		  __func__, ps_mode, smart_ps));
+
+	if (ps_mode > PM_Card_Disable) {
+		RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode));
+		return;
+	}
+
+	if (pwrpriv->pwr_mode == ps_mode) {
+		if (PS_MODE_ACTIVE == ps_mode)
+			return;
+
+		if ((pwrpriv->smart_ps == smart_ps) &&
+		    (pwrpriv->bcn_ant_mode == bcn_ant_mode))
+			return;
+	}
+
+	/* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */
+	if (ps_mode == PS_MODE_ACTIVE) {
+#ifdef CONFIG_88EU_P2P
+		if (pwdinfo->opp_ps == 0) {
+			DBG_88E("rtw_set_ps_mode: Leave 802.11 power save\n");
+			pwrpriv->pwr_mode = ps_mode;
+			rtw_set_rpwm(padapter, PS_STATE_S4);
+			rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+			pwrpriv->bFwCurrentInPSMode = false;
+		}
+	} else {
+#endif /* CONFIG_88EU_P2P */
+		if (PS_RDY_CHECK(padapter)) {
+			DBG_88E("%s: Enter 802.11 power save\n", __func__);
+			pwrpriv->bFwCurrentInPSMode = true;
+			pwrpriv->pwr_mode = ps_mode;
+			pwrpriv->smart_ps = smart_ps;
+			pwrpriv->bcn_ant_mode = bcn_ant_mode;
+			rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+
+#ifdef CONFIG_88EU_P2P
+			/*  Set CTWindow after LPS */
+			if (pwdinfo->opp_ps == 1)
+				p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0);
+#endif /* CONFIG_88EU_P2P */
+
+			rtw_set_rpwm(padapter, PS_STATE_S2);
+		}
+	}
+
+_func_exit_;
+}
+
+/*
+ * Return:
+ *	0:	Leave OK
+ *	-1:	Timeout
+ *	-2:	Other error
+ */
+s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms)
+{
+	u32 start_time;
+	u8 bAwake = false;
+	s32 err = 0;
+
+
+	start_time = rtw_get_current_time();
+	while (1) {
+		rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
+		if (bAwake)
+			break;
+
+		if (padapter->bSurpriseRemoved) {
+			err = -2;
+			DBG_88E("%s: device surprise removed!!\n", __func__);
+			break;
+		}
+
+		if (rtw_get_passing_time_ms(start_time) > delay_ms) {
+			err = -1;
+			DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
+			break;
+		}
+		rtw_usleep_os(100);
+	}
+
+	return err;
+}
+
+/*  */
+/*	Description: */
+/*		Enter the leisure power save mode. */
+/*  */
+void LPS_Enter(struct adapter *padapter)
+{
+	struct pwrctrl_priv	*pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+	if (PS_RDY_CHECK(padapter) == false)
+		return;
+
+	if (pwrpriv->bLeisurePs) {
+		/*  Idle for a while if we connect to AP a while ago. */
+		if (pwrpriv->LpsIdleCount >= 2) { /*   4 Sec */
+			if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
+				pwrpriv->bpower_saving = true;
+				DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps);
+				/* For Tenda W311R IOT issue */
+				rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0);
+			}
+		} else {
+			pwrpriv->LpsIdleCount++;
+		}
+	}
+
+_func_exit_;
+}
+
+#define LPS_LEAVE_TIMEOUT_MS 100
+
+/*	Description: */
+/*		Leave the leisure power save mode. */
+void LPS_Leave(struct adapter *padapter)
+{
+	struct pwrctrl_priv	*pwrpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+	if (pwrpriv->bLeisurePs) {
+		if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
+			rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0);
+
+			if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
+				LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS);
+		}
+	}
+
+	pwrpriv->bpower_saving = false;
+
+_func_exit_;
+}
+
+/*  */
+/*  Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */
+/*  Move code to function by tynli. 2010.03.26. */
+/*  */
+void LeaveAllPowerSaveMode(struct adapter *Adapter)
+{
+	struct mlme_priv	*pmlmepriv = &(Adapter->mlmepriv);
+	u8	enqueue = 0;
+
+_func_enter_;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */
+		p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue);
+
+		rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue);
+	}
+
+_func_exit_;
+}
+
+void rtw_init_pwrctrl_priv(struct adapter *padapter)
+{
+	struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+_func_enter_;
+
+	_init_pwrlock(&pwrctrlpriv->lock);
+	pwrctrlpriv->rf_pwrstate = rf_on;
+	pwrctrlpriv->ips_enter_cnts = 0;
+	pwrctrlpriv->ips_leave_cnts = 0;
+	pwrctrlpriv->bips_processing = false;
+
+	pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
+	pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
+
+	pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL;
+	pwrctrlpriv->pwr_state_check_cnts = 0;
+	pwrctrlpriv->bInternalAutoSuspend = false;
+	pwrctrlpriv->bInSuspend = false;
+	pwrctrlpriv->bkeepfwalive = false;
+
+	pwrctrlpriv->LpsIdleCount = 0;
+	if (padapter->registrypriv.mp_mode == 1)
+		pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE ;
+	else
+		pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/*  PS_MODE_MIN; */
+	pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false;
+
+	pwrctrlpriv->bFwCurrentInPSMode = false;
+
+	pwrctrlpriv->rpwm = 0;
+	pwrctrlpriv->cpwm = PS_STATE_S4;
+
+	pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
+	pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps;
+	pwrctrlpriv->bcn_ant_mode = 0;
+
+	pwrctrlpriv->tog = 0x80;
+
+	pwrctrlpriv->btcoex_rfon = false;
+
+	_init_timer(&(pwrctrlpriv->pwr_state_check_timer), padapter->pnetdev, pwr_state_check_handler, (u8 *)padapter);
+
+_func_exit_;
+}
+
+void rtw_free_pwrctrl_priv(struct adapter *adapter)
+{
+	struct pwrctrl_priv *pwrctrlpriv = &adapter->pwrctrlpriv;
+
+_func_enter_;
+
+	_free_pwrlock(&pwrctrlpriv->lock);
+
+_func_exit_;
+}
+
+u8 rtw_interface_ps_func(struct adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val)
+{
+	u8 bResult = true;
+	rtw_hal_intf_ps_func(padapter, efunc_id, val);
+
+	return bResult;
+}
+
+
+inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ms);
+}
+
+/*
+* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
+* @adapter: pointer to struct adapter structure
+* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
+* Return _SUCCESS or _FAIL
+*/
+
+int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	int ret = _SUCCESS;
+
+	if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms))
+		pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms);
+
+{
+	u32 start = rtw_get_current_time();
+	if (pwrpriv->ps_processing) {
+		DBG_88E("%s wait ps_processing...\n", __func__);
+		while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000)
+			rtw_msleep_os(10);
+		if (pwrpriv->ps_processing)
+			DBG_88E("%s wait ps_processing timeout\n", __func__);
+		else
+			DBG_88E("%s wait ps_processing done\n", __func__);
+	}
+}
+
+	/* System suspend is not allowed to wakeup */
+	if ((!pwrpriv->bInternalAutoSuspend) && (pwrpriv->bInSuspend)) {
+		ret = _FAIL;
+		goto exit;
+	}
+
+	/* block??? */
+	if ((pwrpriv->bInternalAutoSuspend)  && (padapter->net_closed)) {
+		ret = _FAIL;
+		goto exit;
+	}
+
+	/* I think this should be check in IPS, LPS, autosuspend functions... */
+	if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+		ret = _SUCCESS;
+		goto exit;
+	}
+	if (rf_off == pwrpriv->rf_pwrstate) {
+		DBG_88E("%s call ips_leave....\n", __func__);
+		if (_FAIL ==  ips_leave(padapter)) {
+			DBG_88E("======> ips_leave fail.............\n");
+			ret = _FAIL;
+			goto exit;
+		}
+	}
+
+	/* TODO: the following checking need to be merged... */
+	if (padapter->bDriverStopped || !padapter->bup ||
+	    !padapter->hw_init_completed) {
+		DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n"
+			, caller
+			, padapter->bDriverStopped
+			, padapter->bup
+			, padapter->hw_init_completed);
+		ret = false;
+		goto exit;
+	}
+
+exit:
+	if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms))
+		pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms);
+	return ret;
+}
+
+int rtw_pm_set_lps(struct adapter *padapter, u8 mode)
+{
+	int	ret = 0;
+	struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+	if (mode < PS_MODE_NUM) {
+		if (pwrctrlpriv->power_mgnt != mode) {
+			if (PS_MODE_ACTIVE == mode)
+				LeaveAllPowerSaveMode(padapter);
+			else
+				pwrctrlpriv->LpsIdleCount = 2;
+			pwrctrlpriv->power_mgnt = mode;
+			pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false;
+		}
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int rtw_pm_set_ips(struct adapter *padapter, u8 mode)
+{
+	struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+	if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
+		rtw_ips_mode_req(pwrctrlpriv, mode);
+		DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2");
+		return 0;
+	} else if (mode == IPS_NONE) {
+		rtw_ips_mode_req(pwrctrlpriv, mode);
+		DBG_88E("%s %s\n", __func__, "IPS_NONE");
+		if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter)))
+			return -EFAULT;
+	} else {
+		return -EINVAL;
+	}
+	return 0;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
new file mode 100644
index 0000000..2011657
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -0,0 +1,2299 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_RECV_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <mlme_osdep.h>
+#include <ip.h>
+#include <if_ether.h>
+#include <ethernet.h>
+#include <usb_ops.h>
+#include <wifi.h>
+
+static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37};
+static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3};
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static u8 rtw_bridge_tunnel_header[] = {
+       0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8
+};
+
+static u8 rtw_rfc1042_header[] = {
+       0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
+};
+
+void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS);
+
+void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv)
+{
+_func_enter_;
+
+	_rtw_memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv));
+
+	_rtw_spinlock_init(&psta_recvpriv->lock);
+
+	_rtw_init_queue(&psta_recvpriv->defrag_q);
+
+_func_exit_;
+}
+
+int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter)
+{
+	int i;
+
+	union recv_frame *precvframe;
+
+	int	res = _SUCCESS;
+
+_func_enter_;
+	_rtw_spinlock_init(&precvpriv->lock);
+
+	_rtw_init_queue(&precvpriv->free_recv_queue);
+	_rtw_init_queue(&precvpriv->recv_pending_queue);
+	_rtw_init_queue(&precvpriv->uc_swdec_pending_queue);
+
+	precvpriv->adapter = padapter;
+
+	precvpriv->free_recvframe_cnt = NR_RECVFRAME;
+
+	rtw_os_recv_resource_init(precvpriv, padapter);
+
+	precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
+
+	if (precvpriv->pallocated_frame_buf == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ);
+
+	precvframe = (union recv_frame *)precvpriv->precv_frame_buf;
+
+	for (i = 0; i < NR_RECVFRAME; i++) {
+		_rtw_init_listhead(&(precvframe->u.list));
+
+		rtw_list_insert_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue));
+
+		res = rtw_os_recv_resource_alloc(padapter, precvframe);
+
+		precvframe->u.hdr.len = 0;
+
+		precvframe->u.hdr.adapter = padapter;
+		precvframe++;
+	}
+	precvpriv->rx_pending_cnt = 1;
+
+	_rtw_init_sema(&precvpriv->allrxreturnevt, 0);
+
+	res = rtw_hal_init_recv_priv(padapter);
+
+	_init_timer(&precvpriv->signal_stat_timer, padapter->pnetdev, RTW_TIMER_HDL_NAME(signal_stat), padapter);
+
+	precvpriv->signal_stat_sampling_interval = 1000; /* ms */
+
+	rtw_set_signal_stat_timer(precvpriv);
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv)
+{
+	_rtw_spinlock_free(&precvpriv->lock);
+	_rtw_spinlock_free(&precvpriv->free_recv_queue.lock);
+	_rtw_spinlock_free(&precvpriv->recv_pending_queue.lock);
+
+	_rtw_spinlock_free(&precvpriv->free_recv_buf_queue.lock);
+}
+
+void _rtw_free_recv_priv (struct recv_priv *precvpriv)
+{
+	struct adapter	*padapter = precvpriv->adapter;
+
+_func_enter_;
+
+	rtw_free_uc_swdec_pending_queue(padapter);
+
+	rtw_mfree_recv_priv_lock(precvpriv);
+
+	rtw_os_recv_resource_free(precvpriv);
+
+	if (precvpriv->pallocated_frame_buf) {
+		rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ);
+	}
+
+	rtw_hal_free_recv_priv(padapter);
+
+_func_exit_;
+}
+
+union recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
+{
+	union recv_frame  *precvframe;
+	struct list_head *plist, *phead;
+	struct adapter *padapter;
+	struct recv_priv *precvpriv;
+_func_enter_;
+
+	if (_rtw_queue_empty(pfree_recv_queue)) {
+		precvframe = NULL;
+	} else {
+		phead = get_list_head(pfree_recv_queue);
+
+		plist = get_next(phead);
+
+		precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
+
+		rtw_list_delete(&precvframe->u.hdr.list);
+		padapter = precvframe->u.hdr.adapter;
+		if (padapter != NULL) {
+			precvpriv = &padapter->recvpriv;
+			if (pfree_recv_queue == &precvpriv->free_recv_queue)
+				precvpriv->free_recvframe_cnt--;
+		}
+	}
+
+_func_exit_;
+
+	return precvframe;
+}
+
+union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue)
+{
+	unsigned long irqL;
+	union recv_frame  *precvframe;
+
+	_enter_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+	precvframe = _rtw_alloc_recvframe(pfree_recv_queue);
+
+	_exit_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+	return precvframe;
+}
+
+void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpriv)
+{
+	/* Perry: This can be removed */
+	_rtw_init_listhead(&precvframe->u.hdr.list);
+
+	precvframe->u.hdr.len = 0;
+}
+
+int rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue)
+{
+	unsigned long irqL;
+	struct adapter *padapter = precvframe->u.hdr.adapter;
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+
+_func_enter_;
+
+	if (precvframe->u.hdr.pkt) {
+		dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
+		precvframe->u.hdr.pkt = NULL;
+	}
+
+	_enter_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+	rtw_list_delete(&(precvframe->u.hdr.list));
+
+	precvframe->u.hdr.len = 0;
+
+	rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue));
+
+	if (padapter != NULL) {
+		if (pfree_recv_queue == &precvpriv->free_recv_queue)
+				precvpriv->free_recvframe_cnt++;
+	}
+
+      _exit_critical_bh(&pfree_recv_queue->lock, &irqL);
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
+{
+	struct adapter *padapter = precvframe->u.hdr.adapter;
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+
+_func_enter_;
+
+	rtw_list_delete(&(precvframe->u.hdr.list));
+	rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(queue));
+
+	if (padapter != NULL) {
+		if (queue == &precvpriv->free_recv_queue)
+			precvpriv->free_recvframe_cnt++;
+	}
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue)
+{
+	int ret;
+	unsigned long irqL;
+
+	_enter_critical_bh(&queue->lock, &irqL);
+	ret = _rtw_enqueue_recvframe(precvframe, queue);
+	_exit_critical_bh(&queue->lock, &irqL);
+
+	return ret;
+}
+
+/*
+caller : defrag ; recvframe_chk_defrag in recv_thread  (passive)
+pframequeue: defrag_queue : will be accessed in recv_thread  (passive)
+
+using spinlock to protect
+
+*/
+
+void rtw_free_recvframe_queue(struct __queue *pframequeue,  struct __queue *pfree_recv_queue)
+{
+	union	recv_frame	*precvframe;
+	struct list_head *plist, *phead;
+
+_func_enter_;
+	spin_lock(&pframequeue->lock);
+
+	phead = get_list_head(pframequeue);
+	plist = get_next(phead);
+
+	while (rtw_end_of_queue_search(phead, plist) == false) {
+		precvframe = LIST_CONTAINOR(plist, union recv_frame, u);
+
+		plist = get_next(plist);
+
+		rtw_free_recvframe(precvframe, pfree_recv_queue);
+	}
+
+	spin_unlock(&pframequeue->lock);
+
+_func_exit_;
+}
+
+u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter)
+{
+	u32 cnt = 0;
+	union recv_frame *pending_frame;
+	while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) {
+		rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue);
+		DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
+		cnt++;
+	}
+
+	return cnt;
+}
+
+int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue)
+{
+	unsigned long irqL;
+
+	_enter_critical_bh(&queue->lock, &irqL);
+
+	rtw_list_delete(&precvbuf->list);
+	rtw_list_insert_head(&precvbuf->list, get_list_head(queue));
+
+	_exit_critical_bh(&queue->lock, &irqL);
+
+	return _SUCCESS;
+}
+
+int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue)
+{
+	unsigned long irqL;
+	_enter_critical_ex(&queue->lock, &irqL);
+
+	rtw_list_delete(&precvbuf->list);
+
+	rtw_list_insert_tail(&precvbuf->list, get_list_head(queue));
+	_exit_critical_ex(&queue->lock, &irqL);
+	return _SUCCESS;
+}
+
+struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue)
+{
+	unsigned long irqL;
+	struct recv_buf *precvbuf;
+	struct list_head *plist, *phead;
+
+	_enter_critical_ex(&queue->lock, &irqL);
+
+	if (_rtw_queue_empty(queue)) {
+		precvbuf = NULL;
+	} else {
+		phead = get_list_head(queue);
+
+		plist = get_next(phead);
+
+		precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list);
+
+		rtw_list_delete(&precvbuf->list);
+	}
+
+	_exit_critical_ex(&queue->lock, &irqL);
+
+	return precvbuf;
+}
+
+static int recvframe_chkmic(struct adapter *adapter,  union recv_frame *precvframe)
+{
+	int	i, res = _SUCCESS;
+	u32	datalen;
+	u8	miccode[8];
+	u8	bmic_err = false, brpt_micerror = true;
+	u8	*pframe, *payload, *pframemic;
+	u8	*mickey;
+	struct	sta_info		*stainfo;
+	struct	rx_pkt_attrib	*prxattrib = &precvframe->u.hdr.attrib;
+	struct	security_priv	*psecuritypriv = &adapter->securitypriv;
+
+	struct mlme_ext_priv	*pmlmeext = &adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+_func_enter_;
+
+	stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]);
+
+	if (prxattrib->encrypt == _TKIP_) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:prxattrib->encrypt==_TKIP_\n"));
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+			 prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5]));
+
+		/* calculate mic code */
+		if (stainfo != NULL) {
+			if (IS_MCAST(prxattrib->ra)) {
+				mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
+
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n"));
+
+				if (!psecuritypriv) {
+					res = _FAIL;
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"));
+					DBG_88E("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n");
+					goto exit;
+				}
+			} else {
+				mickey = &stainfo->dot11tkiprxmickey.skey[0];
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n"));
+			}
+
+			datalen = precvframe->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */
+			pframe = precvframe->u.hdr.rx_data;
+			payload = pframe+prxattrib->hdrlen+prxattrib->iv_len;
+
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len));
+			rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0],
+					   (unsigned char)prxattrib->priority); /* care the length of the data */
+
+			pframemic = payload+datalen;
+
+			bmic_err = false;
+
+			for (i = 0; i < 8; i++) {
+				if (miccode[i] != *(pframemic+i)) {
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+						 ("recvframe_chkmic:miccode[%d](%02x)!=*(pframemic+%d)(%02x) ",
+						 i, miccode[i], i, *(pframemic+i)));
+					bmic_err = true;
+				}
+			}
+
+			if (bmic_err) {
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+					 ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+					 *(pframemic-8), *(pframemic-7), *(pframemic-6),
+					 *(pframemic-5), *(pframemic-4), *(pframemic-3),
+					 *(pframemic-2), *(pframemic-1)));
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+					 ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+					 *(pframemic-16), *(pframemic-15), *(pframemic-14),
+					 *(pframemic-13), *(pframemic-12), *(pframemic-11),
+					 *(pframemic-10), *(pframemic-9)));
+				{
+					uint i;
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len=%d)======\n", precvframe->u.hdr.len));
+					for (i = 0; i < precvframe->u.hdr.len; i = i+8) {
+						RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
+							 *(precvframe->u.hdr.rx_data+i), *(precvframe->u.hdr.rx_data+i+1),
+							 *(precvframe->u.hdr.rx_data+i+2), *(precvframe->u.hdr.rx_data+i+3),
+							 *(precvframe->u.hdr.rx_data+i+4), *(precvframe->u.hdr.rx_data+i+5),
+							 *(precvframe->u.hdr.rx_data+i+6), *(precvframe->u.hdr.rx_data+i+7)));
+					}
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ====== demp packet end [len=%d]======\n", precvframe->u.hdr.len));
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen=%d,\n", prxattrib->hdrlen));
+				}
+
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+					 ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ",
+					 prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2],
+					 prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey));
+
+				/*  double check key_index for some timing issue , */
+				/*  cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */
+				if ((IS_MCAST(prxattrib->ra) == true)  && (prxattrib->key_index != pmlmeinfo->key_index))
+					brpt_micerror = false;
+
+				if ((prxattrib->bdecrypted) && (brpt_micerror)) {
+					rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra));
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
+					DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
+				} else {
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted));
+					DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted);
+				}
+				res = _FAIL;
+			} else {
+				/* mic checked ok */
+				if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) {
+					psecuritypriv->bcheck_grpkey = true;
+					RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true"));
+				}
+			}
+		} else {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo==NULL!!!\n"));
+		}
+
+		recvframe_pull_tail(precvframe, 8);
+	}
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+/* decrypt and set the ivlen, icvlen of the recv_frame */
+static union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	union recv_frame *return_packet = precv_frame;
+	u32	 res = _SUCCESS;
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt));
+
+	if (prxattrib->encrypt > 0) {
+		u8 *iv = precv_frame->u.hdr.rx_data+prxattrib->hdrlen;
+		prxattrib->key_index = (((iv[3])>>6)&0x3);
+
+		if (prxattrib->key_index > WEP_KEYS) {
+			DBG_88E("prxattrib->key_index(%d)>WEP_KEYS\n", prxattrib->key_index);
+
+			switch (prxattrib->encrypt) {
+			case _WEP40_:
+			case _WEP104_:
+				prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex;
+				break;
+			case _TKIP_:
+			case _AES_:
+			default:
+				prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid;
+				break;
+			}
+		}
+	}
+
+	if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt))) {
+		psecuritypriv->hw_decrypted = false;
+
+		switch (prxattrib->encrypt) {
+		case _WEP40_:
+		case _WEP104_:
+			rtw_wep_decrypt(padapter, (u8 *)precv_frame);
+			break;
+		case _TKIP_:
+			res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame);
+			break;
+		case _AES_:
+			res = rtw_aes_decrypt(padapter, (u8 *)precv_frame);
+			break;
+		default:
+			break;
+		}
+	} else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 &&
+		   (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_))
+			psecuritypriv->hw_decrypted = true;
+
+	if (res == _FAIL) {
+		rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue);
+		return_packet = NULL;
+	}
+
+_func_exit_;
+
+	return return_packet;
+}
+
+/* set the security information in the recv_frame */
+static union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_frame)
+{
+	u8   *psta_addr = NULL, *ptr;
+	uint  auth_alg;
+	struct recv_frame_hdr *pfhdr;
+	struct sta_info *psta;
+	struct sta_priv *pstapriv;
+	union recv_frame *prtnframe;
+	u16	ether_type = 0;
+	u16  eapol_type = 0x888e;/* for Funia BD's WPA issue */
+	struct rx_pkt_attrib *pattrib;
+	__be16 be_tmp;
+
+_func_enter_;
+
+	pstapriv = &adapter->stapriv;
+	psta = rtw_get_stainfo(pstapriv, psta_addr);
+
+	auth_alg = adapter->securitypriv.dot11AuthAlgrthm;
+
+	ptr = get_recvframe_data(precv_frame);
+	pfhdr = &precv_frame->u.hdr;
+	pattrib = &pfhdr->attrib;
+	psta_addr = pattrib->ta;
+
+	prtnframe = NULL;
+
+	RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", adapter->securitypriv.dot11AuthAlgrthm));
+
+	if (auth_alg == 2) {
+		if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+			/* blocked */
+			/* only accept EAPOL frame */
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n"));
+
+			prtnframe = precv_frame;
+
+			/* get ether_type */
+			ptr = ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE;
+			memcpy(&be_tmp, ptr, 2);
+			ether_type = ntohs(be_tmp);
+
+			if (ether_type == eapol_type) {
+				prtnframe = precv_frame;
+			} else {
+				/* free this frame */
+				rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue);
+				prtnframe = NULL;
+			}
+		} else {
+			/* allowed */
+			/* check decryption status, and decrypt the frame if needed */
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n"));
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy=%x\n", precv_frame->u.hdr.attrib.privacy));
+
+			if (pattrib->bdecrypted == 0)
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted));
+
+			prtnframe = precv_frame;
+			/* check is the EAPOL frame or not (Rekey) */
+			if (ether_type == eapol_type) {
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type==0x888e\n"));
+				/* check Rekey */
+
+				prtnframe = precv_frame;
+			} else {
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type=0x%04x\n", ether_type));
+			}
+		}
+	} else {
+		prtnframe = precv_frame;
+	}
+
+_func_exit_;
+
+		return prtnframe;
+}
+
+static int recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache)
+{
+	int tid = precv_frame->u.hdr.attrib.priority;
+
+	u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num&0xffff) << 4) |
+		(precv_frame->u.hdr.attrib.frag_num & 0xf);
+
+_func_enter_;
+
+	if (tid > 15) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid));
+
+		return _FAIL;
+	}
+
+	if (1) {/* if (bretry) */
+		if (seq_ctrl == prxcache->tid_rxseq[tid]) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid]));
+
+			return _FAIL;
+		}
+	}
+
+	prxcache->tid_rxseq[tid] = seq_ctrl;
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame);
+void process_pwrbit_data(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	unsigned char pwrbit;
+	u8 *ptr = precv_frame->u.hdr.rx_data;
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta = NULL;
+
+	psta = rtw_get_stainfo(pstapriv, pattrib->src);
+
+	pwrbit = GetPwrMgt(ptr);
+
+	if (psta) {
+		if (pwrbit) {
+			if (!(psta->state & WIFI_SLEEP_STATE))
+				stop_sta_xmit(padapter, psta);
+		} else {
+			if (psta->state & WIFI_SLEEP_STATE)
+				wakeup_sta_to_xmit(padapter, psta);
+		}
+	}
+
+#endif
+}
+
+static void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *psta = NULL;
+
+	psta = rtw_get_stainfo(pstapriv, pattrib->src);
+
+	if (!psta)
+		return;
+
+	if (!psta->qos_option)
+		return;
+
+	if (!(psta->qos_info&0xf))
+		return;
+
+	if (psta->state&WIFI_SLEEP_STATE) {
+		u8 wmmps_ac = 0;
+
+		switch (pattrib->priority) {
+		case 1:
+		case 2:
+			wmmps_ac = psta->uapsd_bk&BIT(1);
+			break;
+		case 4:
+		case 5:
+			wmmps_ac = psta->uapsd_vi&BIT(1);
+			break;
+		case 6:
+		case 7:
+			wmmps_ac = psta->uapsd_vo&BIT(1);
+			break;
+		case 0:
+		case 3:
+		default:
+			wmmps_ac = psta->uapsd_be&BIT(1);
+			break;
+		}
+
+		if (wmmps_ac) {
+			if (psta->sleepq_ac_len > 0) {
+				/* process received triggered frame */
+				xmit_delivery_enabled_frames(padapter, psta);
+			} else {
+				/* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */
+				issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0);
+			}
+		}
+	}
+
+#endif
+}
+
+static void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta)
+{
+	int	sz;
+	struct sta_info		*psta = NULL;
+	struct stainfo_stats	*pstats = NULL;
+	struct rx_pkt_attrib	*pattrib = &prframe->u.hdr.attrib;
+	struct recv_priv	*precvpriv = &padapter->recvpriv;
+
+	sz = get_recvframe_len(prframe);
+	precvpriv->rx_bytes += sz;
+
+	padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++;
+
+	if ((!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst)))
+		padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++;
+
+	if (sta)
+		psta = sta;
+	else
+		psta = prframe->u.hdr.psta;
+
+	if (psta) {
+		pstats = &psta->sta_stats;
+
+		pstats->rx_data_pkts++;
+		pstats->rx_bytes += sz;
+	}
+}
+
+int sta2sta_data_frame(
+	struct adapter *adapter,
+	union recv_frame *precv_frame,
+	struct sta_info **psta
+);
+
+int sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, struct sta_info **psta)
+{
+	u8 *ptr = precv_frame->u.hdr.rx_data;
+	int ret = _SUCCESS;
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	struct	sta_priv *pstapriv = &adapter->stapriv;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	u8 *mybssid  = get_bssid(pmlmepriv);
+	u8 *myhwaddr = myid(&adapter->eeprompriv);
+	u8 *sta_addr = NULL;
+	int bmcast = IS_MCAST(pattrib->dst);
+
+_func_enter_;
+
+	if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+		/*  filter packets that SA is myself or multicast or broadcast */
+		if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN))	&& (!bmcast)) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+		    _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+		    !_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		sta_addr = pattrib->src;
+	} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+		/*  For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */
+		if (!_rtw_memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid!=TA under STATION_MODE; drop pkt\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+		sta_addr = pattrib->bssid;
+	} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		if (bmcast) {
+			/*  For AP mode, if DA == MCAST, then BSSID should be also MCAST */
+			if (!IS_MCAST(pattrib->bssid)) {
+					ret = _FAIL;
+					goto exit;
+			}
+		} else { /*  not mc-frame */
+			/*  For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */
+			if (!_rtw_memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) {
+				ret = _FAIL;
+				goto exit;
+			}
+
+			sta_addr = pattrib->src;
+		}
+	} else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+		memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+		memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+
+		sta_addr = mybssid;
+	} else {
+		ret  = _FAIL;
+	}
+
+	if (bmcast)
+		*psta = rtw_get_bcmc_stainfo(adapter);
+	else
+		*psta = rtw_get_stainfo(pstapriv, sta_addr); /*  get ap_info */
+
+	if (*psta == NULL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n"));
+		if (adapter->registrypriv.mp_mode == 1) {
+			if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)
+			adapter->mppriv.rx_pktloss++;
+		}
+		ret = _FAIL;
+		goto exit;
+	}
+
+exit:
+_func_exit_;
+	return ret;
+}
+
+static int ap2sta_data_frame (
+	struct adapter *adapter,
+	union recv_frame *precv_frame,
+	struct sta_info **psta)
+{
+	u8 *ptr = precv_frame->u.hdr.rx_data;
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	int ret = _SUCCESS;
+	struct	sta_priv *pstapriv = &adapter->stapriv;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	u8 *mybssid  = get_bssid(pmlmepriv);
+	u8 *myhwaddr = myid(&adapter->eeprompriv);
+	int bmcast = IS_MCAST(pattrib->dst);
+
+_func_enter_;
+
+	if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) &&
+	    (check_fwstate(pmlmepriv, _FW_LINKED) == true ||
+	    check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) {
+		/*  filter packets that SA is myself or multicast or broadcast */
+		if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*  da should be for me */
+		if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+				 (" ap2sta_data_frame:  compare DA fail; DA=%pM\n", (pattrib->dst)));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/*  check BSSID */
+		if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+		    _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) ||
+		     (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+				 (" ap2sta_data_frame:  compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid)));
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid)));
+
+			if (!bmcast) {
+				DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid));
+				issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+			}
+
+			ret = _FAIL;
+			goto exit;
+		}
+
+		if (bmcast)
+			*psta = rtw_get_bcmc_stainfo(adapter);
+		else
+			*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get ap_info */
+
+		if (*psta == NULL) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+
+		/* if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { */
+		/*  */
+
+		if (GetFrameSubType(ptr) & BIT(6)) {
+			/* No data, will not indicate to upper layer, temporily count it here */
+			count_rx_stats(adapter, precv_frame, *psta);
+			ret = RTW_RX_HANDLED;
+			goto exit;
+		}
+	} else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
+		   (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
+		memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+		memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+
+		/*  */
+		memcpy(pattrib->bssid,  mybssid, ETH_ALEN);
+
+		*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get sta_info */
+		if (*psta == NULL) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n"));
+			ret = _FAIL;
+			goto exit;
+		}
+	} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		/* Special case */
+		ret = RTW_RX_HANDLED;
+		goto exit;
+	} else {
+		if (_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) {
+			*psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /*  get sta_info */
+			if (*psta == NULL) {
+				DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid));
+
+				issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+			}
+		}
+
+		ret = _FAIL;
+	}
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+static int sta2ap_data_frame(struct adapter *adapter,
+			     union recv_frame *precv_frame,
+			     struct sta_info **psta)
+{
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	struct	sta_priv *pstapriv = &adapter->stapriv;
+	struct	mlme_priv *pmlmepriv = &adapter->mlmepriv;
+	u8 *ptr = precv_frame->u.hdr.rx_data;
+	unsigned char *mybssid  = get_bssid(pmlmepriv);
+	int ret = _SUCCESS;
+
+_func_enter_;
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+		/* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */
+		if (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) {
+			ret = _FAIL;
+			goto exit;
+		}
+
+		*psta = rtw_get_stainfo(pstapriv, pattrib->src);
+		if (*psta == NULL) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n"));
+			DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
+
+			issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+
+			ret = RTW_RX_HANDLED;
+			goto exit;
+		}
+
+		process_pwrbit_data(adapter, precv_frame);
+
+		if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) {
+			process_wmmps_data(adapter, precv_frame);
+		}
+
+		if (GetFrameSubType(ptr) & BIT(6)) {
+			/* No data, will not indicate to upper layer, temporily count it here */
+			count_rx_stats(adapter, precv_frame, *psta);
+			ret = RTW_RX_HANDLED;
+			goto exit;
+		}
+	} else {
+		u8 *myhwaddr = myid(&adapter->eeprompriv);
+		if (!_rtw_memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) {
+			ret = RTW_RX_HANDLED;
+			goto exit;
+		}
+		DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src));
+		issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+		ret = RTW_RX_HANDLED;
+		goto exit;
+	}
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+static int validate_recv_ctrl_frame(struct adapter *padapter,
+				    union recv_frame *precv_frame)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	u8 *pframe = precv_frame->u.hdr.rx_data;
+	/* uint len = precv_frame->u.hdr.len; */
+
+	if (GetFrameType(pframe) != WIFI_CTRL_TYPE)
+		return _FAIL;
+
+	/* receive the frames that ra(a1) is my address */
+	if (!_rtw_memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN))
+		return _FAIL;
+
+	/* only handle ps-poll */
+	if (GetFrameSubType(pframe) == WIFI_PSPOLL) {
+		u16 aid;
+		u8 wmmps_ac = 0;
+		struct sta_info *psta = NULL;
+
+		aid = GetAid(pframe);
+		psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe));
+
+		if ((psta == NULL) || (psta->aid != aid))
+			return _FAIL;
+
+		/* for rx pkt statistics */
+		psta->sta_stats.rx_ctrl_pkts++;
+
+		switch (pattrib->priority) {
+		case 1:
+		case 2:
+			wmmps_ac = psta->uapsd_bk&BIT(0);
+			break;
+		case 4:
+		case 5:
+			wmmps_ac = psta->uapsd_vi&BIT(0);
+			break;
+		case 6:
+		case 7:
+			wmmps_ac = psta->uapsd_vo&BIT(0);
+			break;
+		case 0:
+		case 3:
+		default:
+			wmmps_ac = psta->uapsd_be&BIT(0);
+			break;
+		}
+
+		if (wmmps_ac)
+			return _FAIL;
+
+		if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+			DBG_88E("%s alive check-rx ps-poll\n", __func__);
+			psta->expire_to = pstapriv->expire_to;
+			psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+		}
+
+		if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) {
+			unsigned long irqL;
+			struct list_head *xmitframe_plist, *xmitframe_phead;
+			struct xmit_frame *pxmitframe = NULL;
+
+			_enter_critical_bh(&psta->sleep_q.lock, &irqL);
+
+			xmitframe_phead = get_list_head(&psta->sleep_q);
+			xmitframe_plist = get_next(xmitframe_phead);
+
+			if ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == false) {
+				pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+				xmitframe_plist = get_next(xmitframe_plist);
+
+				rtw_list_delete(&pxmitframe->list);
+
+				psta->sleepq_len--;
+
+				if (psta->sleepq_len > 0)
+					pxmitframe->attrib.mdata = 1;
+				else
+					pxmitframe->attrib.mdata = 0;
+
+				pxmitframe->attrib.triggered = 1;
+
+				_exit_critical_bh(&psta->sleep_q.lock, &irqL);
+				if (rtw_hal_xmit(padapter, pxmitframe) == true)
+					rtw_os_xmit_complete(padapter, pxmitframe);
+				_enter_critical_bh(&psta->sleep_q.lock, &irqL);
+
+				if (psta->sleepq_len == 0) {
+					pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+					/* upate BCN for TIM IE */
+					/* update_BCNTIM(padapter); */
+					update_beacon(padapter, _TIM_IE_, NULL, false);
+				}
+			} else {
+				if (pstapriv->tim_bitmap&BIT(psta->aid)) {
+					if (psta->sleepq_len == 0) {
+						DBG_88E("no buffered packets to xmit\n");
+
+						/* issue nulldata with More data bit = 0 to indicate we have no buffered packets */
+						issue_nulldata(padapter, psta->hwaddr, 0, 0, 0);
+					} else {
+						DBG_88E("error!psta->sleepq_len=%d\n", psta->sleepq_len);
+						psta->sleepq_len = 0;
+					}
+
+					pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+					/* upate BCN for TIM IE */
+					/* update_BCNTIM(padapter); */
+					update_beacon(padapter, _TIM_IE_, NULL, false);
+				}
+			}
+
+			_exit_critical_bh(&psta->sleep_q.lock, &irqL);
+		}
+	}
+
+#endif
+
+	return _FAIL;
+}
+
+union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame);
+
+static int validate_recv_mgnt_frame(struct adapter *padapter,
+				    union recv_frame *precv_frame)
+{
+	struct sta_info *psta;
+
+	RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n"));
+
+	precv_frame = recvframe_chk_defrag(padapter, precv_frame);
+	if (precv_frame == NULL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__));
+		return _SUCCESS;
+	}
+
+	/* for rx pkt statistics */
+	psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->u.hdr.rx_data));
+	if (psta) {
+		psta->sta_stats.rx_mgnt_pkts++;
+		if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_BEACON) {
+			psta->sta_stats.rx_beacon_pkts++;
+		} else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ) {
+			psta->sta_stats.rx_probereq_pkts++;
+		} else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) {
+			if (_rtw_memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN) == true)
+				psta->sta_stats.rx_probersp_pkts++;
+			else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) ||
+				 is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)))
+				psta->sta_stats.rx_probersp_bm_pkts++;
+			else
+				psta->sta_stats.rx_probersp_uo_pkts++;
+		}
+	}
+
+	mgt_dispatcher(padapter, precv_frame);
+
+	return _SUCCESS;
+}
+
+static int validate_recv_data_frame(struct adapter *adapter,
+				    union recv_frame *precv_frame)
+{
+	u8 bretry;
+	u8 *psa, *pda, *pbssid;
+	struct sta_info *psta = NULL;
+	u8 *ptr = precv_frame->u.hdr.rx_data;
+	struct rx_pkt_attrib	*pattrib = &precv_frame->u.hdr.attrib;
+	struct security_priv	*psecuritypriv = &adapter->securitypriv;
+	int ret = _SUCCESS;
+
+_func_enter_;
+
+	bretry = GetRetry(ptr);
+	pda = get_da(ptr);
+	psa = get_sa(ptr);
+	pbssid = get_hdr_bssid(ptr);
+
+	if (pbssid == NULL) {
+		ret = _FAIL;
+		goto exit;
+	}
+
+	memcpy(pattrib->dst, pda, ETH_ALEN);
+	memcpy(pattrib->src, psa, ETH_ALEN);
+
+	memcpy(pattrib->bssid, pbssid, ETH_ALEN);
+
+	switch (pattrib->to_fr_ds) {
+	case 0:
+		memcpy(pattrib->ra, pda, ETH_ALEN);
+		memcpy(pattrib->ta, psa, ETH_ALEN);
+		ret = sta2sta_data_frame(adapter, precv_frame, &psta);
+		break;
+	case 1:
+		memcpy(pattrib->ra, pda, ETH_ALEN);
+		memcpy(pattrib->ta, pbssid, ETH_ALEN);
+		ret = ap2sta_data_frame(adapter, precv_frame, &psta);
+		break;
+	case 2:
+		memcpy(pattrib->ra, pbssid, ETH_ALEN);
+		memcpy(pattrib->ta, psa, ETH_ALEN);
+		ret = sta2ap_data_frame(adapter, precv_frame, &psta);
+		break;
+	case 3:
+		memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN);
+		memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN);
+		ret = _FAIL;
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n"));
+		break;
+	default:
+		ret = _FAIL;
+		break;
+	}
+
+	if (ret == _FAIL) {
+		goto exit;
+	} else if (ret == RTW_RX_HANDLED) {
+		goto exit;
+	}
+
+	if (psta == NULL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n"));
+		ret = _FAIL;
+		goto exit;
+	}
+
+	/* psta->rssi = prxcmd->rssi; */
+	/* psta->signal_quality = prxcmd->sq; */
+	precv_frame->u.hdr.psta = psta;
+
+	pattrib->amsdu = 0;
+	pattrib->ack_policy = 0;
+	/* parsing QC field */
+	if (pattrib->qos == 1) {
+		pattrib->priority = GetPriority((ptr + 24));
+		pattrib->ack_policy = GetAckpolicy((ptr + 24));
+		pattrib->amsdu = GetAMsdu((ptr + 24));
+		pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26;
+
+		if (pattrib->priority != 0 && pattrib->priority != 3)
+			adapter->recvpriv.bIsAnyNonBEPkts = true;
+	} else {
+		pattrib->priority = 0;
+		pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24;
+	}
+
+	if (pattrib->order)/* HT-CTRL 11n */
+		pattrib->hdrlen += 4;
+
+	precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority];
+
+	/*  decache, drop duplicate recv packets */
+	if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n"));
+		ret = _FAIL;
+		goto exit;
+	}
+
+	if (pattrib->privacy) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy));
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra)));
+
+		GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra));
+
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt=%d\n", pattrib->encrypt));
+
+		SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt);
+	} else {
+		pattrib->encrypt = 0;
+		pattrib->iv_len = 0;
+		pattrib->icv_len = 0;
+	}
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+static int validate_recv_frame(struct adapter *adapter, union recv_frame *precv_frame)
+{
+	/* shall check frame subtype, to / from ds, da, bssid */
+
+	/* then call check if rx seq/frag. duplicated. */
+
+	u8 type;
+	u8 subtype;
+	int retval = _SUCCESS;
+	u8 bDumpRxPkt;
+	struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+	u8 *ptr = precv_frame->u.hdr.rx_data;
+	u8  ver = (unsigned char) (*ptr)&0x3;
+	struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+
+_func_enter_;
+
+	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+		int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter));
+		if (ch_set_idx >= 0)
+			pmlmeext->channel_set[ch_set_idx].rx_count++;
+	}
+
+	/* add version chk */
+	if (ver != 0) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!=0)\n"));
+		retval = _FAIL;
+		goto exit;
+	}
+
+	type =  GetFrameType(ptr);
+	subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */
+
+	pattrib->to_fr_ds = get_tofr_ds(ptr);
+
+	pattrib->frag_num = GetFragNum(ptr);
+	pattrib->seq_num = GetSequence(ptr);
+
+	pattrib->pw_save = GetPwrMgt(ptr);
+	pattrib->mfrag = GetMFrag(ptr);
+	pattrib->mdata = GetMData(ptr);
+	pattrib->privacy = GetPrivacy(ptr);
+	pattrib->order = GetOrder(ptr);
+
+	/* Dump rx packets */
+	rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt));
+	if (bDumpRxPkt == 1) {/* dump all rx packets */
+		int i;
+		DBG_88E("#############################\n");
+
+		for (i = 0; i < 64; i = i+8)
+			DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i),
+				*(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7));
+		DBG_88E("#############################\n");
+	} else if (bDumpRxPkt == 2) {
+		if (type == WIFI_MGT_TYPE) {
+			int i;
+			DBG_88E("#############################\n");
+
+			for (i = 0; i < 64; i = i+8)
+				DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i),
+					*(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7));
+			DBG_88E("#############################\n");
+		}
+	} else if (bDumpRxPkt == 3) {
+		if (type == WIFI_DATA_TYPE) {
+			int i;
+			DBG_88E("#############################\n");
+
+			for (i = 0; i < 64; i = i+8)
+				DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i),
+					*(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7));
+			DBG_88E("#############################\n");
+		}
+	}
+	switch (type) {
+	case WIFI_MGT_TYPE: /* mgnt */
+		retval = validate_recv_mgnt_frame(adapter, precv_frame);
+		if (retval == _FAIL)
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n"));
+		retval = _FAIL; /*  only data frame return _SUCCESS */
+		break;
+	case WIFI_CTRL_TYPE: /* ctrl */
+		retval = validate_recv_ctrl_frame(adapter, precv_frame);
+		if (retval == _FAIL)
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n"));
+		retval = _FAIL; /*  only data frame return _SUCCESS */
+		break;
+	case WIFI_DATA_TYPE: /* data */
+		rtw_led_control(adapter, LED_CTL_RX);
+		pattrib->qos = (subtype & BIT(7)) ? 1 : 0;
+		retval = validate_recv_data_frame(adapter, precv_frame);
+		if (retval == _FAIL) {
+			struct recv_priv *precvpriv = &adapter->recvpriv;
+			precvpriv->rx_drop++;
+		}
+		break;
+	default:
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type= 0x%x\n", type));
+		retval = _FAIL;
+		break;
+	}
+
+exit:
+
+_func_exit_;
+
+	return retval;
+}
+
+/* remove the wlanhdr and add the eth_hdr */
+
+static int wlanhdr_to_ethhdr (union recv_frame *precvframe)
+{
+	int	rmv_len;
+	u16	eth_type, len;
+	__be16 be_tmp;
+	u8	bsnaphdr;
+	u8	*psnap_type;
+	struct ieee80211_snap_hdr	*psnap;
+
+	int ret = _SUCCESS;
+	struct adapter			*adapter = precvframe->u.hdr.adapter;
+	struct mlme_priv	*pmlmepriv = &adapter->mlmepriv;
+
+	u8	*ptr = get_recvframe_data(precvframe); /*  point to frame_ctrl field */
+	struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
+
+_func_enter_;
+
+	if (pattrib->encrypt)
+		recvframe_pull_tail(precvframe, pattrib->icv_len);
+
+	psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len);
+	psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE;
+	/* convert hdr + possible LLC headers into Ethernet header */
+	if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) &&
+	     (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == false) &&
+	     (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == false)) ||
+	    _rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) {
+		/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
+		bsnaphdr = true;
+	} else {
+		/* Leave Ethernet header part of hdr and full payload */
+		bsnaphdr = false;
+	}
+
+	rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
+	len = precvframe->u.hdr.len - rmv_len;
+
+	RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+		 ("\n===pattrib->hdrlen: %x,  pattrib->iv_len:%x===\n\n", pattrib->hdrlen,  pattrib->iv_len));
+
+	memcpy(&be_tmp, ptr+rmv_len, 2);
+	eth_type = ntohs(be_tmp); /* pattrib->ether_type */
+	pattrib->eth_type = eth_type;
+
+	if ((check_fwstate(pmlmepriv, WIFI_MP_STATE))) {
+		ptr += rmv_len;
+		*ptr = 0x87;
+		*(ptr+1) = 0x12;
+
+		eth_type = 0x8712;
+		/*  append rx status for mp test packets */
+		ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24);
+		memcpy(ptr, get_rxmem(precvframe), 24);
+		ptr += 24;
+	} else {
+		ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
+	}
+
+	memcpy(ptr, pattrib->dst, ETH_ALEN);
+	memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
+
+	if (!bsnaphdr) {
+		be_tmp = htons(len);
+		memcpy(ptr+12, &be_tmp, 2);
+	}
+
+_func_exit_;
+	return ret;
+}
+
+/* perform defrag */
+static union recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q)
+{
+	struct list_head *plist, *phead;
+	u8 wlanhdr_offset;
+	u8	curfragnum;
+	struct recv_frame_hdr *pfhdr, *pnfhdr;
+	union recv_frame *prframe, *pnextrframe;
+	struct __queue *pfree_recv_queue;
+
+_func_enter_;
+
+	curfragnum = 0;
+	pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
+
+	phead = get_list_head(defrag_q);
+	plist = get_next(phead);
+	prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+	pfhdr = &prframe->u.hdr;
+	rtw_list_delete(&(prframe->u.list));
+
+	if (curfragnum != pfhdr->attrib.frag_num) {
+		/* the first fragment number must be 0 */
+		/* free the whole queue */
+		rtw_free_recvframe(prframe, pfree_recv_queue);
+		rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
+
+		return NULL;
+	}
+
+	curfragnum++;
+
+	plist = get_list_head(defrag_q);
+
+	plist = get_next(plist);
+
+	while (rtw_end_of_queue_search(phead, plist) == false) {
+		pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u);
+		pnfhdr = &pnextrframe->u.hdr;
+
+		/* check the fragment sequence  (2nd ~n fragment frame) */
+
+		if (curfragnum != pnfhdr->attrib.frag_num) {
+			/* the fragment number must be increasing  (after decache) */
+			/* release the defrag_q & prframe */
+			rtw_free_recvframe(prframe, pfree_recv_queue);
+			rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
+			return NULL;
+		}
+
+		curfragnum++;
+
+		/* copy the 2nd~n fragment frame's payload to the first fragment */
+		/* get the 2nd~last fragment frame's payload */
+
+		wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
+
+		recvframe_pull(pnextrframe, wlanhdr_offset);
+
+		/* append  to first fragment frame's tail (if privacy frame, pull the ICV) */
+		recvframe_pull_tail(prframe, pfhdr->attrib.icv_len);
+
+		/* memcpy */
+		memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len);
+
+		recvframe_put(prframe, pnfhdr->len);
+
+		pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
+		plist = get_next(plist);
+	};
+
+	/* free the defrag_q queue and return the prframe */
+	rtw_free_recvframe_queue(defrag_q, pfree_recv_queue);
+
+	RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n"));
+
+_func_exit_;
+
+	return prframe;
+}
+
+/* check if need to defrag, if needed queue the frame to defrag_q */
+union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union recv_frame *precv_frame)
+{
+	u8	ismfrag;
+	u8	fragnum;
+	u8	*psta_addr;
+	struct recv_frame_hdr *pfhdr;
+	struct sta_info *psta;
+	struct sta_priv *pstapriv;
+	struct list_head *phead;
+	union recv_frame *prtnframe = NULL;
+	struct __queue *pfree_recv_queue, *pdefrag_q;
+
+_func_enter_;
+
+	pstapriv = &padapter->stapriv;
+
+	pfhdr = &precv_frame->u.hdr;
+
+	pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+	/* need to define struct of wlan header frame ctrl */
+	ismfrag = pfhdr->attrib.mfrag;
+	fragnum = pfhdr->attrib.frag_num;
+
+	psta_addr = pfhdr->attrib.ta;
+	psta = rtw_get_stainfo(pstapriv, psta_addr);
+	if (psta == NULL) {
+		u8 type = GetFrameType(pfhdr->rx_data);
+		if (type != WIFI_DATA_TYPE) {
+			psta = rtw_get_bcmc_stainfo(padapter);
+			pdefrag_q = &psta->sta_recvpriv.defrag_q;
+		} else {
+			pdefrag_q = NULL;
+		}
+	} else {
+		pdefrag_q = &psta->sta_recvpriv.defrag_q;
+	}
+
+	if ((ismfrag == 0) && (fragnum == 0))
+		prtnframe = precv_frame;/* isn't a fragment frame */
+
+	if (ismfrag == 1) {
+		/* 0~(n-1) fragment frame */
+		/* enqueue to defraf_g */
+		if (pdefrag_q != NULL) {
+			if (fragnum == 0) {
+				/* the first fragment */
+				if (_rtw_queue_empty(pdefrag_q) == false) {
+					/* free current defrag_q */
+					rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue);
+				}
+			}
+
+			/* Then enqueue the 0~(n-1) fragment into the defrag_q */
+
+			phead = get_list_head(pdefrag_q);
+			rtw_list_insert_tail(&pfhdr->list, phead);
+
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+
+			prtnframe = NULL;
+		} else {
+			/* can't find this ta's defrag_queue, so free this recv_frame */
+			rtw_free_recvframe(precv_frame, pfree_recv_queue);
+			prtnframe = NULL;
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+		}
+	}
+
+	if ((ismfrag == 0) && (fragnum != 0)) {
+		/* the last fragment frame */
+		/* enqueue the last fragment */
+		if (pdefrag_q != NULL) {
+			phead = get_list_head(pdefrag_q);
+			rtw_list_insert_tail(&pfhdr->list, phead);
+
+			/* call recvframe_defrag to defrag */
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+			precv_frame = recvframe_defrag(padapter, pdefrag_q);
+			prtnframe = precv_frame;
+		} else {
+			/* can't find this ta's defrag_queue, so free this recv_frame */
+			rtw_free_recvframe(precv_frame, pfree_recv_queue);
+			prtnframe = NULL;
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum));
+		}
+	}
+
+	if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) {
+		/* after defrag we must check tkip mic code */
+		if (recvframe_chkmic(padapter,  prtnframe) == _FAIL) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter,  prtnframe)==_FAIL\n"));
+			rtw_free_recvframe(prtnframe, pfree_recv_queue);
+			prtnframe = NULL;
+		}
+	}
+
+_func_exit_;
+
+	return prtnframe;
+}
+
+static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
+{
+	int	a_len, padding_len;
+	u16	eth_type, nSubframe_Length;
+	u8	nr_subframes, i;
+	unsigned char *pdata;
+	struct rx_pkt_attrib *pattrib;
+	unsigned char *data_ptr;
+	struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT];
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+	struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
+	int	ret = _SUCCESS;
+	nr_subframes = 0;
+
+	pattrib = &prframe->u.hdr.attrib;
+
+	recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen);
+
+	if (prframe->u.hdr.attrib.iv_len > 0)
+		recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len);
+
+	a_len = prframe->u.hdr.len;
+
+	pdata = prframe->u.hdr.rx_data;
+
+	while (a_len > ETH_HLEN) {
+		/* Offset 12 denote 2 mac address */
+		nSubframe_Length = RTW_GET_BE16(pdata + 12);
+
+		if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
+			DBG_88E("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length);
+			goto exit;
+		}
+
+		/* move the data point to data content */
+		pdata += ETH_HLEN;
+		a_len -= ETH_HLEN;
+
+		/* Allocate new skb for releasing to upper layer */
+		sub_skb = dev_alloc_skb(nSubframe_Length + 12);
+		if (sub_skb) {
+			skb_reserve(sub_skb, 12);
+			data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
+			memcpy(data_ptr, pdata, nSubframe_Length);
+		} else {
+			sub_skb = skb_clone(prframe->u.hdr.pkt, GFP_ATOMIC);
+			if (sub_skb) {
+				sub_skb->data = pdata;
+				sub_skb->len = nSubframe_Length;
+				skb_set_tail_pointer(sub_skb, nSubframe_Length);
+			} else {
+				DBG_88E("skb_clone() Fail!!! , nr_subframes=%d\n", nr_subframes);
+				break;
+			}
+		}
+
+		subframes[nr_subframes++] = sub_skb;
+
+		if (nr_subframes >= MAX_SUBFRAME_COUNT) {
+			DBG_88E("ParseSubframe(): Too many Subframes! Packets dropped!\n");
+			break;
+		}
+
+		pdata += nSubframe_Length;
+		a_len -= nSubframe_Length;
+		if (a_len != 0) {
+			padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1));
+			if (padding_len == 4) {
+				padding_len = 0;
+			}
+
+			if (a_len < padding_len) {
+				goto exit;
+			}
+			pdata += padding_len;
+			a_len -= padding_len;
+		}
+	}
+
+	for (i = 0; i < nr_subframes; i++) {
+		sub_skb = subframes[i];
+		/* convert hdr + possible LLC headers into Ethernet header */
+		eth_type = RTW_GET_BE16(&sub_skb->data[6]);
+		if (sub_skb->len >= 8 &&
+		    ((_rtw_memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) &&
+			  eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
+			 _rtw_memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) {
+			/* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
+			skb_pull(sub_skb, SNAP_SIZE);
+			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
+			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
+		} else {
+			__be16 len;
+			/* Leave Ethernet header part of hdr and full payload */
+			len = htons(sub_skb->len);
+			memcpy(skb_push(sub_skb, 2), &len, 2);
+			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
+			memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
+		}
+
+		/* Indicat the packets to upper layer */
+		if (sub_skb) {
+			/*  Insert NAT2.5 RX here! */
+			sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev);
+			sub_skb->dev = padapter->pnetdev;
+
+			sub_skb->ip_summed = CHECKSUM_NONE;
+
+			netif_rx(sub_skb);
+		}
+	}
+
+exit:
+
+	prframe->u.hdr.len = 0;
+	rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
+
+	return ret;
+}
+
+static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num)
+{
+	u8	wsize = preorder_ctrl->wsize_b;
+	u16	wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/*  4096; */
+
+	/*  Rx Reorder initialize condition. */
+	if (preorder_ctrl->indicate_seq == 0xFFFF)
+		preorder_ctrl->indicate_seq = seq_num;
+
+	/*  Drop out the packet which SeqNum is smaller than WinStart */
+	if (SN_LESS(seq_num, preorder_ctrl->indicate_seq))
+		return false;
+
+	/*  */
+	/*  Sliding window manipulation. Conditions includes: */
+	/*  1. Incoming SeqNum is equal to WinStart =>Window shift 1 */
+	/*  2. Incoming SeqNum is larger than the WinEnd => Window shift N */
+	/*  */
+	if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) {
+		preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+	} else if (SN_LESS(wend, seq_num)) {
+		if (seq_num >= (wsize - 1))
+			preorder_ctrl->indicate_seq = seq_num + 1 - wsize;
+		else
+			preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1;
+	}
+
+	return true;
+}
+
+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe);
+int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe)
+{
+	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+	struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+	struct list_head *phead, *plist;
+	union recv_frame *pnextrframe;
+	struct rx_pkt_attrib *pnextattrib;
+
+	phead = get_list_head(ppending_recvframe_queue);
+	plist = get_next(phead);
+
+	while (rtw_end_of_queue_search(phead, plist) == false) {
+		pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u);
+		pnextattrib = &pnextrframe->u.hdr.attrib;
+
+		if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num))
+			plist = get_next(plist);
+		else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num))
+			return false;
+		else
+			break;
+	}
+
+	rtw_list_delete(&(prframe->u.hdr.list));
+
+	rtw_list_insert_tail(&(prframe->u.hdr.list), plist);
+	return true;
+}
+
+static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced)
+{
+	struct list_head *phead, *plist;
+	union recv_frame *prframe;
+	struct rx_pkt_attrib *pattrib;
+	int bPktInBuf = false;
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+	struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+	phead =		get_list_head(ppending_recvframe_queue);
+	plist = get_next(phead);
+
+	/*  Handling some condition for forced indicate case. */
+	if (bforced) {
+		if (rtw_is_list_empty(phead))
+			return true;
+
+		prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+		pattrib = &prframe->u.hdr.attrib;
+		preorder_ctrl->indicate_seq = pattrib->seq_num;
+	}
+
+	/*  Prepare indication list and indication. */
+	/*  Check if there is any packet need indicate. */
+	while (!rtw_is_list_empty(phead)) {
+		prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+		pattrib = &prframe->u.hdr.attrib;
+
+		if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+				 ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n",
+				  preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu));
+			plist = get_next(plist);
+			rtw_list_delete(&(prframe->u.hdr.list));
+
+			if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num))
+				preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+
+			/* Set this as a lock to make sure that only one thread is indicating packet. */
+
+			/* indicate this recv_frame */
+			if (!pattrib->amsdu) {
+				if ((!padapter->bDriverStopped) &&
+				    (!padapter->bSurpriseRemoved))
+					rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */
+			} else if (pattrib->amsdu == 1) {
+				if (amsdu_to_msdu(padapter, prframe) != _SUCCESS)
+					rtw_free_recvframe(prframe, &precvpriv->free_recv_queue);
+			} else {
+				/* error condition; */
+			}
+
+			/* Update local variables. */
+			bPktInBuf = false;
+		} else {
+			bPktInBuf = true;
+			break;
+		}
+	}
+	return bPktInBuf;
+}
+
+static int recv_indicatepkt_reorder(struct adapter *padapter, union recv_frame *prframe)
+{
+	unsigned long irql;
+	int retval = _SUCCESS;
+	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+	struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl;
+	struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+	if (!pattrib->amsdu) {
+		/* s1. */
+		wlanhdr_to_ethhdr(prframe);
+
+		if ((pattrib->qos != 1) || (pattrib->eth_type == 0x0806) ||
+		    (pattrib->ack_policy != 0)) {
+			if ((!padapter->bDriverStopped) &&
+			    (!padapter->bSurpriseRemoved)) {
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@  recv_indicatepkt_reorder -recv_func recv_indicatepkt\n"));
+
+				rtw_recv_indicatepkt(padapter, prframe);
+				return _SUCCESS;
+			}
+
+			return _FAIL;
+		}
+
+		if (!preorder_ctrl->enable) {
+			/* indicate this recv_frame */
+			preorder_ctrl->indicate_seq = pattrib->seq_num;
+			rtw_recv_indicatepkt(padapter, prframe);
+
+			preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096;
+			return _SUCCESS;
+		}
+	} else if (pattrib->amsdu == 1) { /* temp filter -> means didn't support A-MSDUs in a A-MPDU */
+		if (!preorder_ctrl->enable) {
+			preorder_ctrl->indicate_seq = pattrib->seq_num;
+			retval = amsdu_to_msdu(padapter, prframe);
+
+			preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096;
+			return retval;
+		}
+	}
+
+	_enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+	RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+		 ("recv_indicatepkt_reorder: indicate=%d seq=%d\n",
+		  preorder_ctrl->indicate_seq, pattrib->seq_num));
+
+	/* s2. check if winstart_b(indicate_seq) needs to been updated */
+	if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) {
+		rtw_recv_indicatepkt(padapter, prframe);
+
+		_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+		goto _success_exit;
+	}
+
+	/* s3. Insert all packet into Reorder Queue to maintain its ordering. */
+	if (!enqueue_reorder_recvframe(preorder_ctrl, prframe))
+		goto _err_exit;
+
+	/* s4. */
+	/*  Indication process. */
+	/*  After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */
+	/*  with the SeqNum smaller than latest WinStart and buffer other packets. */
+	/*  */
+	/*  For Rx Reorder condition: */
+	/*  1. All packets with SeqNum smaller than WinStart => Indicate */
+	/*  2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */
+	/*  */
+
+	/* recv_indicatepkts_in_order(padapter, preorder_ctrl, true); */
+	if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) {
+		_set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
+		_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+	} else {
+		_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+		_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+	}
+
+_success_exit:
+
+	return _SUCCESS;
+
+_err_exit:
+
+	_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+	return _FAIL;
+}
+
+void rtw_reordering_ctrl_timeout_handler(void *pcontext)
+{
+	unsigned long irql;
+	struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext;
+	struct adapter *padapter = preorder_ctrl->padapter;
+	struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+	if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+		return;
+
+	_enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+	if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true)
+		_set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME);
+
+	_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+}
+
+static int process_recv_indicatepkts(struct adapter *padapter, union recv_frame *prframe)
+{
+	int retval = _SUCCESS;
+	/* struct recv_priv *precvpriv = &padapter->recvpriv; */
+	/* struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; */
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv	*phtpriv = &pmlmepriv->htpriv;
+
+	if (phtpriv->ht_option) {  /* B/G/N Mode */
+		/* prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */
+
+		if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) {
+			/*  including perform A-MPDU Rx Ordering Buffer Control */
+			if ((!padapter->bDriverStopped) &&
+			    (!padapter->bSurpriseRemoved)) {
+				retval = _FAIL;
+				return retval;
+			}
+		}
+	} else { /* B/G mode */
+		retval = wlanhdr_to_ethhdr (prframe);
+		if (retval != _SUCCESS) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n"));
+			return retval;
+		}
+
+		if ((!padapter->bDriverStopped) &&
+		    (!padapter->bSurpriseRemoved)) {
+			/* indicate this recv_frame */
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n"));
+			rtw_recv_indicatepkt(padapter, prframe);
+		} else {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n"));
+
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
+			retval = _FAIL;
+			return retval;
+		}
+	}
+
+	return retval;
+}
+
+static int recv_func_prehandle(struct adapter *padapter, union recv_frame *rframe)
+{
+	int ret = _SUCCESS;
+	struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib;
+	struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	if (padapter->registrypriv.mp_mode == 1) {
+		if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) { /* padapter->mppriv.check_mp_pkt == 0)) */
+			if (pattrib->crc_err == 1)
+				padapter->mppriv.rx_crcerrpktcount++;
+			else
+				padapter->mppriv.rx_pktcount++;
+
+			if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == false) {
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("MP - Not in loopback mode , drop pkt\n"));
+				ret = _FAIL;
+				rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
+				goto exit;
+			}
+		}
+	}
+
+	/* check the frame crtl field and decache */
+	ret = validate_recv_frame(padapter, rframe);
+	if (ret != _SUCCESS) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n"));
+		rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
+static int recv_func_posthandle(struct adapter *padapter, union recv_frame *prframe)
+{
+	int ret = _SUCCESS;
+	union recv_frame *orig_prframe = prframe;
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+	struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+	/*  DATA FRAME */
+	rtw_led_control(padapter, LED_CTL_RX);
+
+	prframe = decryptor(padapter, prframe);
+	if (prframe == NULL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n"));
+		ret = _FAIL;
+		goto _recv_data_drop;
+	}
+
+	prframe = recvframe_chk_defrag(padapter, prframe);
+	if (prframe == NULL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n"));
+		goto _recv_data_drop;
+	}
+
+	prframe = portctrl(padapter, prframe);
+	if (prframe == NULL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n"));
+		ret = _FAIL;
+		goto _recv_data_drop;
+	}
+
+	count_rx_stats(padapter, prframe, NULL);
+
+	ret = process_recv_indicatepkts(padapter, prframe);
+	if (ret != _SUCCESS) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n"));
+		rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */
+		goto _recv_data_drop;
+	}
+	return ret;
+
+_recv_data_drop:
+	precvpriv->rx_drop++;
+	return ret;
+}
+
+static int recv_func(struct adapter *padapter, union recv_frame *rframe)
+{
+	int ret;
+	struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+
+	/* check if need to handle uc_swdec_pending_queue*/
+	if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) {
+		union recv_frame *pending_frame;
+
+		while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) {
+			if (recv_func_posthandle(padapter, pending_frame) == _SUCCESS)
+				DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
+		}
+	}
+
+	ret = recv_func_prehandle(padapter, rframe);
+
+	if (ret == _SUCCESS) {
+		/* check if need to enqueue into uc_swdec_pending_queue*/
+		if (check_fwstate(mlmepriv, WIFI_STATION_STATE) &&
+		    !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 &&
+		    (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt) &&
+		    !is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm) &&
+		    !psecuritypriv->busetkipkey) {
+			rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue);
+			DBG_88E("%s: no key, enqueue uc_swdec_pending_queue\n", __func__);
+			goto exit;
+		}
+
+		ret = recv_func_posthandle(padapter, rframe);
+	}
+
+exit:
+	return ret;
+}
+
+s32 rtw_recv_entry(union recv_frame *precvframe)
+{
+	struct adapter *padapter;
+	struct recv_priv *precvpriv;
+	s32 ret = _SUCCESS;
+
+_func_enter_;
+
+	padapter = precvframe->u.hdr.adapter;
+
+	precvpriv = &padapter->recvpriv;
+
+	ret = recv_func(padapter, precvframe);
+	if (ret == _FAIL) {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n"));
+		goto _recv_entry_drop;
+	}
+
+	precvpriv->rx_pkts++;
+
+_func_exit_;
+
+	return ret;
+
+_recv_entry_drop:
+
+	if (padapter->registrypriv.mp_mode == 1)
+		padapter->mppriv.rx_pktloss = precvpriv->rx_drop;
+
+_func_exit_;
+
+	return ret;
+}
+
+void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+	struct recv_priv *recvpriv = &adapter->recvpriv;
+
+	u32 tmp_s, tmp_q;
+	u8 avg_signal_strength = 0;
+	u8 avg_signal_qual = 0;
+	u8 _alpha = 3; /*  this value is based on converging_constant = 5000 and sampling_interval = 1000 */
+
+	if (adapter->recvpriv.is_signal_dbg) {
+		/* update the user specific value, signal_strength_dbg, to signal_strength, rssi */
+		adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg;
+		adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg);
+	} else {
+		if (recvpriv->signal_strength_data.update_req == 0) {/*  update_req is clear, means we got rx */
+			avg_signal_strength = recvpriv->signal_strength_data.avg_val;
+			/*  after avg_vals are accquired, we can re-stat the signal values */
+			recvpriv->signal_strength_data.update_req = 1;
+		}
+
+		if (recvpriv->signal_qual_data.update_req == 0) {/*  update_req is clear, means we got rx */
+			avg_signal_qual = recvpriv->signal_qual_data.avg_val;
+			/*  after avg_vals are accquired, we can re-stat the signal values */
+			recvpriv->signal_qual_data.update_req = 1;
+		}
+
+		/* update value of signal_strength, rssi, signal_qual */
+		if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) {
+			tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength);
+			if (tmp_s % _alpha)
+				tmp_s = tmp_s/_alpha + 1;
+			else
+				tmp_s = tmp_s/_alpha;
+			if (tmp_s > 100)
+				tmp_s = 100;
+
+			tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual);
+			if (tmp_q % _alpha)
+				tmp_q = tmp_q/_alpha + 1;
+			else
+				tmp_q = tmp_q/_alpha;
+			if (tmp_q > 100)
+				tmp_q = 100;
+
+			recvpriv->signal_strength = tmp_s;
+			recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s);
+			recvpriv->signal_qual = tmp_q;
+		}
+	}
+	rtw_set_signal_stat_timer(recvpriv);
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_rf.c b/drivers/staging/rtl8188eu/core/rtw_rf.c
new file mode 100644
index 0000000..1170dd0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_rf.c
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_RF_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+
+
+struct ch_freq {
+	u32 channel;
+	u32 frequency;
+};
+
+static struct ch_freq ch_freq_map[] = {
+	{1, 2412}, {2, 2417}, {3, 2422}, {4, 2427}, {5, 2432},
+	{6, 2437}, {7, 2442}, {8, 2447}, {9, 2452}, {10, 2457},
+	{11, 2462}, {12, 2467}, {13, 2472}, {14, 2484},
+	/*  UNII */
+	{36, 5180}, {40, 5200}, {44, 5220}, {48, 5240}, {52, 5260},
+	{56, 5280}, {60, 5300}, {64, 5320}, {149, 5745}, {153, 5765},
+	{157, 5785}, {161, 5805}, {165, 5825}, {167, 5835}, {169, 5845},
+	{171, 5855}, {173, 5865},
+	/* HiperLAN2 */
+	{100, 5500}, {104, 5520}, {108, 5540}, {112, 5560}, {116, 5580},
+	{120, 5600}, {124, 5620}, {128, 5640}, {132, 5660}, {136, 5680},
+	{140, 5700},
+	/* Japan MMAC */
+	{34, 5170}, {38, 5190}, {42, 5210}, {46, 5230},
+	/*  Japan */
+	{184, 4920}, {188, 4940}, {192, 4960}, {196, 4980},
+	{208, 5040},/* Japan, means J08 */
+	{212, 5060},/* Japan, means J12 */
+	{216, 5080},/* Japan, means J16 */
+};
+
+static int ch_freq_map_num = (sizeof(ch_freq_map) / sizeof(struct ch_freq));
+
+u32 rtw_ch2freq(u32 channel)
+{
+	u8	i;
+	u32	freq = 0;
+
+	for (i = 0; i < ch_freq_map_num; i++) {
+		if (channel == ch_freq_map[i].channel) {
+			freq = ch_freq_map[i].frequency;
+				break;
+		}
+	}
+	if (i == ch_freq_map_num)
+		freq = 2412;
+
+	return freq;
+}
+
+u32 rtw_freq2ch(u32 freq)
+{
+	u8	i;
+	u32	ch = 0;
+
+	for (i = 0; i < ch_freq_map_num; i++) {
+		if (freq == ch_freq_map[i].frequency) {
+			ch = ch_freq_map[i].channel;
+				break;
+		}
+	}
+	if (i == ch_freq_map_num)
+		ch = 1;
+
+	return ch;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c
new file mode 100644
index 0000000..0f076d0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_security.c
@@ -0,0 +1,1779 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define  _RTW_SECURITY_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+
+/* WEP related ===== */
+
+#define CRC32_POLY 0x04c11db7
+
+struct arc4context {
+	u32 x;
+	u32 y;
+	u8 state[256];
+};
+
+static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32	key_len)
+{
+	u32	t, u;
+	u32	keyindex;
+	u32	stateindex;
+	u8 *state;
+	u32	counter;
+_func_enter_;
+	state = parc4ctx->state;
+	parc4ctx->x = 0;
+	parc4ctx->y = 0;
+	for (counter = 0; counter < 256; counter++)
+		state[counter] = (u8)counter;
+	keyindex = 0;
+	stateindex = 0;
+	for (counter = 0; counter < 256; counter++) {
+		t = state[counter];
+		stateindex = (stateindex + key[keyindex] + t) & 0xff;
+		u = state[stateindex];
+		state[stateindex] = (u8)t;
+		state[counter] = (u8)u;
+		if (++keyindex >= key_len)
+			keyindex = 0;
+	}
+_func_exit_;
+}
+
+static u32 arcfour_byte(struct arc4context *parc4ctx)
+{
+	u32 x;
+	u32 y;
+	u32 sx, sy;
+	u8 *state;
+_func_enter_;
+	state = parc4ctx->state;
+	x = (parc4ctx->x + 1) & 0xff;
+	sx = state[x];
+	y = (sx + parc4ctx->y) & 0xff;
+	sy = state[y];
+	parc4ctx->x = x;
+	parc4ctx->y = y;
+	state[y] = (u8)sx;
+	state[x] = (u8)sy;
+_func_exit_;
+	return state[(sx + sy) & 0xff];
+}
+
+static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len)
+{
+	u32	i;
+_func_enter_;
+	for (i = 0; i < len; i++)
+		dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx);
+_func_exit_;
+}
+
+static int bcrc32initialized;
+static u32 crc32_table[256];
+
+static u8 crc32_reverseBit(u8 data)
+{
+	return (u8)((data<<7)&0x80) | ((data<<5)&0x40) | ((data<<3)&0x20) |
+		   ((data<<1)&0x10) | ((data>>1)&0x08) | ((data>>3)&0x04) |
+		   ((data>>5)&0x02) | ((data>>7)&0x01);
+}
+
+static void crc32_init(void)
+{
+_func_enter_;
+	if (bcrc32initialized == 1) {
+		goto exit;
+	} else {
+		int i, j;
+		u32 c;
+		u8 *p = (u8 *)&c, *p1;
+		u8 k;
+
+		c = 0x12340000;
+
+		for (i = 0; i < 256; ++i) {
+			k = crc32_reverseBit((u8)i);
+			for (c = ((u32)k) << 24, j = 8; j > 0; --j)
+				c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
+			p1 = (u8 *)&crc32_table[i];
+
+			p1[0] = crc32_reverseBit(p[3]);
+			p1[1] = crc32_reverseBit(p[2]);
+			p1[2] = crc32_reverseBit(p[1]);
+			p1[3] = crc32_reverseBit(p[0]);
+		}
+		bcrc32initialized = 1;
+	}
+exit:
+_func_exit_;
+}
+
+static __le32 getcrc32(u8 *buf, int len)
+{
+	u8 *p;
+	u32  crc;
+_func_enter_;
+	if (bcrc32initialized == 0)
+		crc32_init();
+
+	crc = 0xffffffff;       /* preload shift register, per CRC-32 spec */
+
+	for (p = buf; len > 0; ++p, --len)
+		crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8);
+_func_exit_;
+	return cpu_to_le32(~crc);    /* transmit complement, per CRC-32 spec */
+}
+
+/*
+	Need to consider the fragment  situation
+*/
+void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe)
+{	/*  exclude ICV */
+
+	unsigned char	crc[4];
+	struct arc4context	 mycontext;
+
+	int	curfragnum, length;
+	u32	keylength;
+
+	u8	*pframe, *payload, *iv;    /* wepkey */
+	u8	wepkey[16];
+	u8   hw_hdr_offset = 0;
+	struct	pkt_attrib	 *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+	struct	xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+
+_func_enter_;
+
+	if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
+		return;
+
+	hw_hdr_offset = TXDESC_SIZE +
+		 (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ);
+
+	pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
+
+	/* start to encrypt each fragment */
+	if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) {
+		keylength = psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex];
+
+		for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+			iv = pframe+pattrib->hdrlen;
+			memcpy(&wepkey[0], iv, 3);
+			memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength);
+			payload = pframe+pattrib->iv_len+pattrib->hdrlen;
+
+			if ((curfragnum+1) == pattrib->nr_frags) {	/* the last fragment */
+				length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+
+				*((__le32 *)crc) = getcrc32(payload, length);
+
+				arcfour_init(&mycontext, wepkey, 3+keylength);
+				arcfour_encrypt(&mycontext, payload, payload, length);
+				arcfour_encrypt(&mycontext, payload+length, crc, 4);
+			} else {
+				length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+				*((__le32 *)crc) = getcrc32(payload, length);
+				arcfour_init(&mycontext, wepkey, 3+keylength);
+				arcfour_encrypt(&mycontext, payload, payload, length);
+				arcfour_encrypt(&mycontext, payload+length, crc, 4);
+
+				pframe += pxmitpriv->frag_len;
+				pframe = (u8 *)RND4((size_t)(pframe));
+			}
+		}
+	}
+
+_func_exit_;
+}
+
+void rtw_wep_decrypt(struct adapter  *padapter, u8 *precvframe)
+{
+	/*  exclude ICV */
+	u8	crc[4];
+	struct arc4context	 mycontext;
+	int	length;
+	u32	keylength;
+	u8	*pframe, *payload, *iv, wepkey[16];
+	u8	 keyindex;
+	struct	rx_pkt_attrib	 *prxattrib = &(((union recv_frame *)precvframe)->u.hdr.attrib);
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+
+_func_enter_;
+
+	pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+
+	/* start to decrypt recvframe */
+	if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
+		iv = pframe+prxattrib->hdrlen;
+		keyindex = prxattrib->key_index;
+		keylength = psecuritypriv->dot11DefKeylen[keyindex];
+		memcpy(&wepkey[0], iv, 3);
+		memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength);
+		length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+
+		payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
+
+		/* decrypt payload include icv */
+		arcfour_init(&mycontext, wepkey, 3+keylength);
+		arcfour_encrypt(&mycontext, payload, payload,  length);
+
+		/* calculate icv and compare the icv */
+		*((__le32 *)crc) = getcrc32(payload, length - 4);
+
+		if (crc[3] != payload[length-1] ||
+		    crc[2] != payload[length-2] ||
+		    crc[1] != payload[length-3] ||
+		    crc[0] != payload[length-4]) {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+				 ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
+				 &crc, &payload[length-4]));
+		}
+	}
+_func_exit_;
+	return;
+}
+
+/* 3		===== TKIP related ===== */
+
+static u32 secmicgetuint32(u8 *p)
+/*  Convert from Byte[] to Us3232 in a portable way */
+{
+	s32 i;
+	u32 res = 0;
+_func_enter_;
+	for (i = 0; i < 4; i++)
+		res |= ((u32)(*p++)) << (8*i);
+_func_exit_;
+	return res;
+}
+
+static void secmicputuint32(u8 *p, u32 val)
+/*  Convert from Us3232 to Byte[] in a portable way */
+{
+	long i;
+_func_enter_;
+	for (i = 0; i < 4; i++) {
+		*p++ = (u8) (val & 0xff);
+		val >>= 8;
+	}
+_func_exit_;
+}
+
+static void secmicclear(struct mic_data *pmicdata)
+{
+/*  Reset the state to the empty message. */
+_func_enter_;
+	pmicdata->L = pmicdata->K0;
+	pmicdata->R = pmicdata->K1;
+	pmicdata->nBytesInM = 0;
+	pmicdata->M = 0;
+_func_exit_;
+}
+
+void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key)
+{
+	/*  Set the key */
+_func_enter_;
+	pmicdata->K0 = secmicgetuint32(key);
+	pmicdata->K1 = secmicgetuint32(key + 4);
+	/*  and reset the message */
+	secmicclear(pmicdata);
+_func_exit_;
+}
+
+void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b)
+{
+_func_enter_;
+	/*  Append the byte to our word-sized buffer */
+	pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM);
+	pmicdata->nBytesInM++;
+	/*  Process the word if it is full. */
+	if (pmicdata->nBytesInM >= 4) {
+		pmicdata->L ^= pmicdata->M;
+		pmicdata->R ^= ROL32(pmicdata->L, 17);
+		pmicdata->L += pmicdata->R;
+		pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8);
+		pmicdata->L += pmicdata->R;
+		pmicdata->R ^= ROL32(pmicdata->L, 3);
+		pmicdata->L += pmicdata->R;
+		pmicdata->R ^= ROR32(pmicdata->L, 2);
+		pmicdata->L += pmicdata->R;
+		/*  Clear the buffer */
+		pmicdata->M = 0;
+		pmicdata->nBytesInM = 0;
+	}
+_func_exit_;
+}
+
+void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes)
+{
+_func_enter_;
+	/*  This is simple */
+	while (nbytes > 0) {
+		rtw_secmicappendbyte(pmicdata, *src++);
+		nbytes--;
+	}
+_func_exit_;
+}
+
+void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst)
+{
+_func_enter_;
+	/*  Append the minimum padding */
+	rtw_secmicappendbyte(pmicdata, 0x5a);
+	rtw_secmicappendbyte(pmicdata, 0);
+	rtw_secmicappendbyte(pmicdata, 0);
+	rtw_secmicappendbyte(pmicdata, 0);
+	rtw_secmicappendbyte(pmicdata, 0);
+	/*  and then zeroes until the length is a multiple of 4 */
+	while (pmicdata->nBytesInM != 0)
+		rtw_secmicappendbyte(pmicdata, 0);
+	/*  The appendByte function has already computed the result. */
+	secmicputuint32(dst, pmicdata->L);
+	secmicputuint32(dst+4, pmicdata->R);
+	/*  Reset to the empty message. */
+	secmicclear(pmicdata);
+_func_exit_;
+}
+
+void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri)
+{
+	struct mic_data	micdata;
+	u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
+_func_enter_;
+	rtw_secmicsetkey(&micdata, key);
+	priority[0] = pri;
+
+	/* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
+	if (header[1]&1) {   /* ToDS == 1 */
+			rtw_secmicappend(&micdata, &header[16], 6);  /* DA */
+		if (header[1]&2)  /* From Ds == 1 */
+			rtw_secmicappend(&micdata, &header[24], 6);
+		else
+			rtw_secmicappend(&micdata, &header[10], 6);
+	} else {	/* ToDS == 0 */
+		rtw_secmicappend(&micdata, &header[4], 6);   /* DA */
+		if (header[1]&2)  /* From Ds == 1 */
+			rtw_secmicappend(&micdata, &header[16], 6);
+		else
+			rtw_secmicappend(&micdata, &header[10], 6);
+	}
+	rtw_secmicappend(&micdata, &priority[0], 4);
+
+	rtw_secmicappend(&micdata, data, data_len);
+
+	rtw_secgetmic(&micdata, mic_code);
+_func_exit_;
+}
+
+
+
+/* macros for extraction/creation of unsigned char/unsigned short values  */
+#define RotR1(v16)   ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15))
+#define   Lo8(v16)   ((u8)((v16)       & 0x00FF))
+#define   Hi8(v16)   ((u8)(((v16) >> 8) & 0x00FF))
+#define  Lo16(v32)   ((u16)((v32)       & 0xFFFF))
+#define  Hi16(v32)   ((u16)(((v32) >> 16) & 0xFFFF))
+#define  Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8))
+
+/* select the Nth 16-bit word of the temporal key unsigned char array TK[]   */
+#define  TK16(N)     Mk16(tk[2*(N)+1], tk[2*(N)])
+
+/* S-box lookup: 16 bits --> 16 bits */
+#define _S_(v16)     (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)])
+
+/* fixed algorithm "parameters" */
+#define PHASE1_LOOP_CNT   8    /* this needs to be "big enough"     */
+#define TA_SIZE	   6    /*  48-bit transmitter address       */
+#define TK_SIZE	  16    /* 128-bit temporal key	      */
+#define P1K_SIZE	 10    /*  80-bit Phase1 key		*/
+#define RC4_KEY_SIZE     16    /* 128-bit RC4KEY (104 bits unknown) */
+
+/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */
+static const unsigned short Sbox1[2][256] = {  /* Sbox for hash (can be in ROM)     */
+{
+   0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+   0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+   0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+   0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+   0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+   0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+   0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+   0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+   0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+   0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+   0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+   0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+   0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+   0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+   0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+   0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+   0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+   0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+   0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+   0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+   0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+   0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+   0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+   0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+   0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+   0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+   0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+   0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+   0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+   0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+   0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+   0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+  },
+
+  {  /* second half of table is unsigned char-reversed version of first! */
+   0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491,
+   0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC,
+   0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB,
+   0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B,
+   0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83,
+   0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A,
+   0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F,
+   0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA,
+   0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B,
+   0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713,
+   0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6,
+   0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85,
+   0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411,
+   0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B,
+   0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1,
+   0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF,
+   0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E,
+   0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6,
+   0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B,
+   0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD,
+   0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8,
+   0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2,
+   0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049,
+   0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810,
+   0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197,
+   0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F,
+   0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C,
+   0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927,
+   0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733,
+   0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5,
+   0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0,
+   0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C,
+  }
+};
+
+ /*
+**********************************************************************
+* Routine: Phase 1 -- generate P1K, given TA, TK, IV32
+*
+* Inputs:
+*     tk[]      = temporal key			 [128 bits]
+*     ta[]      = transmitter's MAC address	    [ 48 bits]
+*     iv32      = upper 32 bits of IV		  [ 32 bits]
+* Output:
+*     p1k[]     = Phase 1 key			  [ 80 bits]
+*
+* Note:
+*     This function only needs to be called every 2**16 packets,
+*     although in theory it could be called every packet.
+*
+**********************************************************************
+*/
+static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32)
+{
+	int  i;
+_func_enter_;
+	/* Initialize the 80 bits of P1K[] from IV32 and TA[0..5]     */
+	p1k[0]      = Lo16(iv32);
+	p1k[1]      = Hi16(iv32);
+	p1k[2]      = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */
+	p1k[3]      = Mk16(ta[3], ta[2]);
+	p1k[4]      = Mk16(ta[5], ta[4]);
+
+	/* Now compute an unbalanced Feistel cipher with 80-bit block */
+	/* size on the 80-bit block P1K[], using the 128-bit key TK[] */
+	for (i = 0; i < PHASE1_LOOP_CNT; i++) { /* Each add operation here is mod 2**16 */
+		p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0));
+		p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2));
+		p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4));
+		p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6));
+		p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0));
+		p1k[4] +=  (unsigned short)i;   /* avoid "slide attacks" */
+	}
+_func_exit_;
+}
+
+/*
+**********************************************************************
+* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16
+*
+* Inputs:
+*     tk[]      = Temporal key			 [128 bits]
+*     p1k[]     = Phase 1 output key		   [ 80 bits]
+*     iv16      = low 16 bits of IV counter	    [ 16 bits]
+* Output:
+*     rc4key[]  = the key used to encrypt the packet   [128 bits]
+*
+* Note:
+*     The value {TA, IV32, IV16} for Phase1/Phase2 must be unique
+*     across all packets using the same key TK value. Then, for a
+*     given value of TK[], this TKIP48 construction guarantees that
+*     the final RC4KEY value is unique across all packets.
+*
+* Suggested implementation optimization: if PPK[] is "overlaid"
+*     appropriately on RC4KEY[], there is no need for the final
+*     for loop below that copies the PPK[] result into RC4KEY[].
+*
+**********************************************************************
+*/
+static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16)
+{
+	int  i;
+	u16 PPK[6];			/* temporary key for mixing    */
+_func_enter_;
+	/* Note: all adds in the PPK[] equations below are mod 2**16	 */
+	for (i = 0; i < 5; i++)
+		PPK[i] = p1k[i];	/* first, copy P1K to PPK      */
+	PPK[5]  =  p1k[4] + iv16;	/* next,  add in IV16	  */
+
+	/* Bijective non-linear mixing of the 96 bits of PPK[0..5]	   */
+	PPK[0] +=    _S_(PPK[5] ^ TK16(0));   /* Mix key in each "round"     */
+	PPK[1] +=    _S_(PPK[0] ^ TK16(1));
+	PPK[2] +=    _S_(PPK[1] ^ TK16(2));
+	PPK[3] +=    _S_(PPK[2] ^ TK16(3));
+	PPK[4] +=    _S_(PPK[3] ^ TK16(4));
+	PPK[5] +=    _S_(PPK[4] ^ TK16(5));   /* Total # S-box lookups == 6  */
+
+	/* Final sweep: bijective, "linear". Rotates kill LSB correlations   */
+	PPK[0] +=  RotR1(PPK[5] ^ TK16(6));
+	PPK[1] +=  RotR1(PPK[0] ^ TK16(7));   /* Use all of TK[] in Phase2   */
+	PPK[2] +=  RotR1(PPK[1]);
+	PPK[3] +=  RotR1(PPK[2]);
+	PPK[4] +=  RotR1(PPK[3]);
+	PPK[5] +=  RotR1(PPK[4]);
+	/* Note: At this point, for a given key TK[0..15], the 96-bit output */
+	/*       value PPK[0..5] is guaranteed to be unique, as a function   */
+	/*       of the 96-bit "input" value   {TA, IV32, IV16}. That is, P1K  */
+	/*       is now a keyed permutation of {TA, IV32, IV16}.	       */
+
+	/* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key   */
+	rc4key[0] = Hi8(iv16);		/* RC4KEY[0..2] is the WEP IV  */
+	rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys  */
+	rc4key[2] = Lo8(iv16);
+	rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1);
+
+	/* Copy 96 bits of PPK[0..5] to RC4KEY[4..15]  (little-endian)       */
+	for (i = 0; i < 6; i++) {
+		rc4key[4+2*i] = Lo8(PPK[i]);
+		rc4key[5+2*i] = Hi8(PPK[i]);
+	}
+_func_exit_;
+}
+
+/* The hlen isn't include the IV */
+u32	rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
+{																	/*  exclude ICV */
+	u16	pnl;
+	u32	pnh;
+	u8	rc4key[16];
+	u8   ttkey[16];
+	u8	crc[4];
+	u8   hw_hdr_offset = 0;
+	struct arc4context mycontext;
+	int			curfragnum, length;
+
+	u8	*pframe, *payload, *iv, *prwskey;
+	union pn48 dot11txpn;
+	struct	sta_info		*stainfo;
+	struct	pkt_attrib	 *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+	struct	xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+	u32	res = _SUCCESS;
+_func_enter_;
+
+	if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
+		return _FAIL;
+
+	hw_hdr_offset = TXDESC_SIZE +
+		 (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ);
+	pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
+	/* 4 start to encrypt each fragment */
+	if (pattrib->encrypt == _TKIP_) {
+		if (pattrib->psta)
+			stainfo = pattrib->psta;
+		else
+			stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
+
+		if (stainfo != NULL) {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n"));
+
+			if (IS_MCAST(pattrib->ra))
+				prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
+			else
+				prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+
+			for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+				iv = pframe+pattrib->hdrlen;
+				payload = pframe+pattrib->iv_len+pattrib->hdrlen;
+
+				GET_TKIP_PN(iv, dot11txpn);
+
+				pnl = (u16)(dot11txpn.val);
+				pnh = (u32)(dot11txpn.val>>16);
+				phase1((u16 *)&ttkey[0], prwskey, &pattrib->ta[0], pnh);
+				phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl);
+
+				if ((curfragnum+1) == pattrib->nr_frags) {	/* 4 the last fragment */
+					length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+					RT_TRACE(_module_rtl871x_security_c_, _drv_info_,
+						 ("pattrib->iv_len=%x, pattrib->icv_len=%x\n",
+						 pattrib->iv_len, pattrib->icv_len));
+					*((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
+
+					arcfour_init(&mycontext, rc4key, 16);
+					arcfour_encrypt(&mycontext, payload, payload, length);
+					arcfour_encrypt(&mycontext, payload+length, crc, 4);
+				} else {
+					length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ;
+					*((__le32 *)crc) = getcrc32(payload, length);/* modified by Amy*/
+					arcfour_init(&mycontext, rc4key, 16);
+					arcfour_encrypt(&mycontext, payload, payload, length);
+					arcfour_encrypt(&mycontext, payload+length, crc, 4);
+
+					pframe += pxmitpriv->frag_len;
+					pframe = (u8 *)RND4((size_t)(pframe));
+				}
+			}
+		} else {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo==NULL!!!\n"));
+			res = _FAIL;
+		}
+	}
+_func_exit_;
+	return res;
+}
+
+/* The hlen isn't include the IV */
+u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
+{																	/*  exclude ICV */
+	u16 pnl;
+	u32 pnh;
+	u8   rc4key[16];
+	u8   ttkey[16];
+	u8	crc[4];
+	struct arc4context mycontext;
+	int			length;
+
+	u8	*pframe, *payload, *iv, *prwskey;
+	union pn48 dot11txpn;
+	struct	sta_info		*stainfo;
+	struct	rx_pkt_attrib	 *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+	u32		res = _SUCCESS;
+
+_func_enter_;
+
+	pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+
+	/* 4 start to decrypt recvframe */
+	if (prxattrib->encrypt == _TKIP_) {
+		stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
+		if (stainfo != NULL) {
+			if (IS_MCAST(prxattrib->ra)) {
+				if (!psecuritypriv->binstallGrpkey) {
+					res = _FAIL;
+					DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
+					goto exit;
+				}
+				prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+			} else {
+				RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo!= NULL!!!\n"));
+				prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+			}
+
+			iv = pframe+prxattrib->hdrlen;
+			payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
+			length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+
+			GET_TKIP_PN(iv, dot11txpn);
+
+			pnl = (u16)(dot11txpn.val);
+			pnh = (u32)(dot11txpn.val>>16);
+
+			phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh);
+			phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl);
+
+			/* 4 decrypt payload include icv */
+
+			arcfour_init(&mycontext, rc4key, 16);
+			arcfour_encrypt(&mycontext, payload, payload, length);
+
+			*((__le32 *)crc) = getcrc32(payload, length-4);
+
+			if (crc[3] != payload[length-1] ||
+			    crc[2] != payload[length-2] ||
+			    crc[1] != payload[length-3] ||
+			    crc[0] != payload[length-4]) {
+				RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+					 ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n",
+					 &crc, &payload[length-4]));
+				res = _FAIL;
+			}
+		} else {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo==NULL!!!\n"));
+			res = _FAIL;
+		}
+	}
+_func_exit_;
+exit:
+	return res;
+}
+
+/* 3			===== AES related ===== */
+
+
+#define MAX_MSG_SIZE	2048
+/*****************************/
+/******** SBOX Table *********/
+/*****************************/
+
+static  u8 sbox_table[256] = {
+	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+	0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+	0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+	0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+	0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+	0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+	0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+	0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+	0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+	0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+	0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+	0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+	0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+	0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+	0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+	0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+	0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+	0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+	0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+	0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+/*****************************/
+/**** Function Prototypes ****/
+/*****************************/
+
+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out);
+static void construct_mic_iv(u8 *mic_header1, int qc_exists, int a4_exists, u8 *mpdu, uint payload_length, u8 *pn_vector);
+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu);
+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists);
+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c);
+static void xor_128(u8 *a, u8 *b, u8 *out);
+static void xor_32(u8 *a, u8 *b, u8 *out);
+static u8 sbox(u8 a);
+static void next_key(u8 *key, int round);
+static void byte_sub(u8 *in, u8 *out);
+static void shift_row(u8 *in, u8 *out);
+static void mix_column(u8 *in, u8 *out);
+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext);
+
+/****************************************/
+/* aes128k128d()			*/
+/* Performs a 128 bit AES encrypt with  */
+/* 128 bit data.			*/
+/****************************************/
+static void xor_128(u8 *a, u8 *b, u8 *out)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < 16; i++)
+		out[i] = a[i] ^ b[i];
+_func_exit_;
+}
+
+static void xor_32(u8 *a, u8 *b, u8 *out)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < 4; i++)
+		out[i] = a[i] ^ b[i];
+_func_exit_;
+}
+
+static u8 sbox(u8 a)
+{
+	return sbox_table[(int)a];
+}
+
+static void next_key(u8 *key, int round)
+{
+	u8 rcon;
+	u8 sbox_key[4];
+	u8 rcon_table[12] = {
+		0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+		0x1b, 0x36, 0x36, 0x36
+	};
+_func_enter_;
+	sbox_key[0] = sbox(key[13]);
+	sbox_key[1] = sbox(key[14]);
+	sbox_key[2] = sbox(key[15]);
+	sbox_key[3] = sbox(key[12]);
+
+	rcon = rcon_table[round];
+
+	xor_32(&key[0], sbox_key, &key[0]);
+	key[0] = key[0] ^ rcon;
+
+	xor_32(&key[4], &key[0], &key[4]);
+	xor_32(&key[8], &key[4], &key[8]);
+	xor_32(&key[12], &key[8], &key[12]);
+_func_exit_;
+}
+
+static void byte_sub(u8 *in, u8 *out)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < 16; i++)
+		out[i] = sbox(in[i]);
+_func_exit_;
+}
+
+static void shift_row(u8 *in, u8 *out)
+{
+_func_enter_;
+	out[0] =  in[0];
+	out[1] =  in[5];
+	out[2] =  in[10];
+	out[3] =  in[15];
+	out[4] =  in[4];
+	out[5] =  in[9];
+	out[6] =  in[14];
+	out[7] =  in[3];
+	out[8] =  in[8];
+	out[9] =  in[13];
+	out[10] = in[2];
+	out[11] = in[7];
+	out[12] = in[12];
+	out[13] = in[1];
+	out[14] = in[6];
+	out[15] = in[11];
+_func_exit_;
+}
+
+static void mix_column(u8 *in, u8 *out)
+{
+	int i;
+	u8 add1b[4];
+	u8 add1bf7[4];
+	u8 rotl[4];
+	u8 swap_halfs[4];
+	u8 andf7[4];
+	u8 rotr[4];
+	u8 temp[4];
+	u8 tempb[4];
+_func_enter_;
+	for (i = 0 ; i < 4; i++) {
+		if ((in[i] & 0x80) == 0x80)
+			add1b[i] = 0x1b;
+		else
+			add1b[i] = 0x00;
+	}
+
+	swap_halfs[0] = in[2];    /* Swap halfs */
+	swap_halfs[1] = in[3];
+	swap_halfs[2] = in[0];
+	swap_halfs[3] = in[1];
+
+	rotl[0] = in[3];	/* Rotate left 8 bits */
+	rotl[1] = in[0];
+	rotl[2] = in[1];
+	rotl[3] = in[2];
+
+	andf7[0] = in[0] & 0x7f;
+	andf7[1] = in[1] & 0x7f;
+	andf7[2] = in[2] & 0x7f;
+	andf7[3] = in[3] & 0x7f;
+
+	for (i = 3; i > 0; i--) {    /* logical shift left 1 bit */
+		andf7[i] = andf7[i] << 1;
+		if ((andf7[i-1] & 0x80) == 0x80)
+			andf7[i] = (andf7[i] | 0x01);
+	}
+	andf7[0] = andf7[0] << 1;
+	andf7[0] = andf7[0] & 0xfe;
+
+	xor_32(add1b, andf7, add1bf7);
+
+	xor_32(in, add1bf7, rotr);
+
+	temp[0] = rotr[0];	 /* Rotate right 8 bits */
+	rotr[0] = rotr[1];
+	rotr[1] = rotr[2];
+	rotr[2] = rotr[3];
+	rotr[3] = temp[0];
+
+	xor_32(add1bf7, rotr, temp);
+	xor_32(swap_halfs, rotl, tempb);
+	xor_32(temp, tempb, out);
+_func_exit_;
+}
+
+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
+{
+	int round;
+	int i;
+	u8 intermediatea[16];
+	u8 intermediateb[16];
+	u8 round_key[16];
+_func_enter_;
+	for (i = 0; i < 16; i++)
+		round_key[i] = key[i];
+	for (round = 0; round < 11; round++) {
+		if (round == 0) {
+			xor_128(round_key, data, ciphertext);
+			next_key(round_key, round);
+		} else if (round == 10) {
+			byte_sub(ciphertext, intermediatea);
+			shift_row(intermediatea, intermediateb);
+			xor_128(intermediateb, round_key, ciphertext);
+		} else {    /* 1 - 9 */
+			byte_sub(ciphertext, intermediatea);
+			shift_row(intermediatea, intermediateb);
+			mix_column(&intermediateb[0], &intermediatea[0]);
+			mix_column(&intermediateb[4], &intermediatea[4]);
+			mix_column(&intermediateb[8], &intermediatea[8]);
+			mix_column(&intermediateb[12], &intermediatea[12]);
+			xor_128(intermediatea, round_key, ciphertext);
+			next_key(round_key, round);
+		}
+	}
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_iv()			   */
+/* Builds the MIC IV from header fields and PN  */
+/************************************************/
+static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu,
+			     uint payload_length, u8 *pn_vector)
+{
+	int i;
+_func_enter_;
+	mic_iv[0] = 0x59;
+	if (qc_exists && a4_exists)
+		mic_iv[1] = mpdu[30] & 0x0f;    /* QoS_TC	   */
+	if (qc_exists && !a4_exists)
+		mic_iv[1] = mpdu[24] & 0x0f;	/* mute bits 7-4    */
+	if (!qc_exists)
+		mic_iv[1] = 0x00;
+	for (i = 2; i < 8; i++)
+		mic_iv[i] = mpdu[i + 8];	/* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */
+	for (i = 8; i < 14; i++)
+		mic_iv[i] = pn_vector[13 - i];	/* mic_iv[8:13] = PN[5:0] */
+	mic_iv[14] = (unsigned char) (payload_length / 256);
+	mic_iv[15] = (unsigned char) (payload_length % 256);
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_header1()		      */
+/* Builds the first MIC header block from       */
+/* header fields.			       */
+/************************************************/
+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu)
+{
+_func_enter_;
+	mic_header1[0] = (u8)((header_length - 2) / 256);
+	mic_header1[1] = (u8)((header_length - 2) % 256);
+	mic_header1[2] = mpdu[0] & 0xcf;    /* Mute CF poll & CF ack bits */
+	mic_header1[3] = mpdu[1] & 0xc7;    /* Mute retry, more data and pwr mgt bits */
+	mic_header1[4] = mpdu[4];       /* A1 */
+	mic_header1[5] = mpdu[5];
+	mic_header1[6] = mpdu[6];
+	mic_header1[7] = mpdu[7];
+	mic_header1[8] = mpdu[8];
+	mic_header1[9] = mpdu[9];
+	mic_header1[10] = mpdu[10];     /* A2 */
+	mic_header1[11] = mpdu[11];
+	mic_header1[12] = mpdu[12];
+	mic_header1[13] = mpdu[13];
+	mic_header1[14] = mpdu[14];
+	mic_header1[15] = mpdu[15];
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_header2()		      */
+/* Builds the last MIC header block from	*/
+/* header fields.			       */
+/************************************************/
+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < 16; i++)
+		mic_header2[i] = 0x00;
+
+	mic_header2[0] = mpdu[16];    /* A3 */
+	mic_header2[1] = mpdu[17];
+	mic_header2[2] = mpdu[18];
+	mic_header2[3] = mpdu[19];
+	mic_header2[4] = mpdu[20];
+	mic_header2[5] = mpdu[21];
+
+	mic_header2[6] = 0x00;
+	mic_header2[7] = 0x00; /* mpdu[23]; */
+
+	if (!qc_exists && a4_exists) {
+		for (i = 0; i < 6; i++)
+			mic_header2[8+i] = mpdu[24+i];   /* A4 */
+	}
+
+	if (qc_exists && !a4_exists) {
+		mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */
+		mic_header2[9] = mpdu[25] & 0x00;
+	}
+
+	if (qc_exists && a4_exists) {
+		for (i = 0; i < 6; i++)
+			mic_header2[8+i] = mpdu[24+i];   /* A4 */
+
+		mic_header2[14] = mpdu[30] & 0x0f;
+		mic_header2[15] = mpdu[31] & 0x00;
+	}
+
+_func_exit_;
+}
+
+/************************************************/
+/* construct_mic_header2()		      */
+/* Builds the last MIC header block from	*/
+/* header fields.			       */
+/************************************************/
+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < 16; i++)
+		ctr_preload[i] = 0x00;
+	i = 0;
+
+	ctr_preload[0] = 0x01;				  /* flag */
+	if (qc_exists && a4_exists)
+		ctr_preload[1] = mpdu[30] & 0x0f;   /* QoC_Control */
+	if (qc_exists && !a4_exists)
+		ctr_preload[1] = mpdu[24] & 0x0f;
+
+	for (i = 2; i < 8; i++)
+		ctr_preload[i] = mpdu[i + 8];		       /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */
+	for (i = 8; i < 14; i++)
+		ctr_preload[i] =    pn_vector[13 - i];	  /* ctr_preload[8:13] = PN[5:0] */
+	ctr_preload[14] =  (unsigned char) (c / 256); /* Ctr */
+	ctr_preload[15] =  (unsigned char) (c % 256);
+_func_exit_;
+}
+
+/************************************/
+/* bitwise_xor()		    */
+/* A 128 bit, bitwise exclusive or  */
+/************************************/
+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < 16; i++)
+		out[i] = ina[i] ^ inb[i];
+_func_exit_;
+}
+
+static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen)
+{
+	uint	qc_exists, a4_exists, i, j, payload_remainder,
+		num_blocks, payload_index;
+
+	u8 pn_vector[6];
+	u8 mic_iv[16];
+	u8 mic_header1[16];
+	u8 mic_header2[16];
+	u8 ctr_preload[16];
+
+	/* Intermediate Buffers */
+	u8 chain_buffer[16];
+	u8 aes_out[16];
+	u8 padded_buffer[16];
+	u8 mic[8];
+	uint	frtype  = GetFrameType(pframe);
+	uint	frsubtype  = GetFrameSubType(pframe);
+
+_func_enter_;
+	frsubtype = frsubtype>>4;
+
+	_rtw_memset((void *)mic_iv, 0, 16);
+	_rtw_memset((void *)mic_header1, 0, 16);
+	_rtw_memset((void *)mic_header2, 0, 16);
+	_rtw_memset((void *)ctr_preload, 0, 16);
+	_rtw_memset((void *)chain_buffer, 0, 16);
+	_rtw_memset((void *)aes_out, 0, 16);
+	_rtw_memset((void *)padded_buffer, 0, 16);
+
+	if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen ==  WLAN_HDR_A3_QOS_LEN))
+		a4_exists = 0;
+	else
+		a4_exists = 1;
+
+	if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || (frtype == WIFI_DATA_CFACKPOLL)) {
+		qc_exists = 1;
+		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
+			hdrlen += 2;
+	} else if ((frsubtype == 0x08) || (frsubtype == 0x09) || (frsubtype == 0x0a) || (frsubtype == 0x0b)) {
+		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
+			hdrlen += 2;
+		qc_exists = 1;
+	} else {
+		qc_exists = 0;
+	}
+
+	pn_vector[0] = pframe[hdrlen];
+	pn_vector[1] = pframe[hdrlen+1];
+	pn_vector[2] = pframe[hdrlen+4];
+	pn_vector[3] = pframe[hdrlen+5];
+	pn_vector[4] = pframe[hdrlen+6];
+	pn_vector[5] = pframe[hdrlen+7];
+
+	construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector);
+
+	construct_mic_header1(mic_header1, hdrlen, pframe);
+	construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists);
+
+	payload_remainder = plen % 16;
+	num_blocks = plen / 16;
+
+	/* Find start of payload */
+	payload_index = (hdrlen + 8);
+
+	/* Calculate MIC */
+	aes128k128d(key, mic_iv, aes_out);
+	bitwise_xor(aes_out, mic_header1, chain_buffer);
+	aes128k128d(key, chain_buffer, aes_out);
+	bitwise_xor(aes_out, mic_header2, chain_buffer);
+	aes128k128d(key, chain_buffer, aes_out);
+
+	for (i = 0; i < num_blocks; i++) {
+		bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */
+
+		payload_index += 16;
+		aes128k128d(key, chain_buffer, aes_out);
+	}
+
+	/* Add on the final payload block if it needs padding */
+	if (payload_remainder > 0) {
+		for (j = 0; j < 16; j++)
+			padded_buffer[j] = 0x00;
+		for (j = 0; j < payload_remainder; j++)
+			padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */
+		bitwise_xor(aes_out, padded_buffer, chain_buffer);
+		aes128k128d(key, chain_buffer, aes_out);
+	}
+
+	for (j = 0; j < 8; j++)
+		mic[j] = aes_out[j];
+
+	/* Insert MIC into payload */
+	for (j = 0; j < 8; j++)
+	pframe[payload_index+j] = mic[j];	/* message[payload_index+j] = mic[j]; */
+
+	payload_index = hdrlen + 8;
+	for (i = 0; i < num_blocks; i++) {
+		construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1);
+		aes128k128d(key, ctr_preload, aes_out);
+		bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+		for (j = 0; j < 16; j++)
+			pframe[payload_index++] = chain_buffer[j];
+	}
+
+	if (payload_remainder > 0) {    /* If there is a short final block, then pad it,*/
+					/* encrypt it and copy the unpadded part back   */
+		construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1);
+
+		for (j = 0; j < 16; j++)
+			padded_buffer[j] = 0x00;
+		for (j = 0; j < payload_remainder; j++)
+			padded_buffer[j] = pframe[payload_index+j];
+		aes128k128d(key, ctr_preload, aes_out);
+		bitwise_xor(aes_out, padded_buffer, chain_buffer);
+		for (j = 0; j < payload_remainder; j++)
+			pframe[payload_index++] = chain_buffer[j];
+	}
+	/* Encrypt the MIC */
+	construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, 0);
+
+	for (j = 0; j < 16; j++)
+		padded_buffer[j] = 0x00;
+	for (j = 0; j < 8; j++)
+		padded_buffer[j] = pframe[j+hdrlen+8+plen];
+
+	aes128k128d(key, ctr_preload, aes_out);
+	bitwise_xor(aes_out, padded_buffer, chain_buffer);
+	for (j = 0; j < 8; j++)
+		pframe[payload_index++] = chain_buffer[j];
+_func_exit_;
+	return _SUCCESS;
+}
+
+u32	rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe)
+{	/*  exclude ICV */
+
+	/*static*/
+/*	unsigned char	message[MAX_MSG_SIZE]; */
+
+	/* Intermediate Buffers */
+	int	curfragnum, length;
+	u8	*pframe, *prwskey;	/*  *payload,*iv */
+	u8   hw_hdr_offset = 0;
+	struct	sta_info		*stainfo;
+	struct	pkt_attrib	 *pattrib = &((struct xmit_frame *)pxmitframe)->attrib;
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+	struct	xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+
+/*	uint	offset = 0; */
+	u32 res = _SUCCESS;
+_func_enter_;
+
+	if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL)
+		return _FAIL;
+
+	hw_hdr_offset = TXDESC_SIZE +
+		 (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ);
+
+	pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset;
+
+	/* 4 start to encrypt each fragment */
+	if ((pattrib->encrypt == _AES_)) {
+		if (pattrib->psta)
+			stainfo = pattrib->psta;
+		else
+			stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]);
+
+		if (stainfo != NULL) {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n"));
+
+			if (IS_MCAST(pattrib->ra))
+				prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
+			else
+				prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+			for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+				if ((curfragnum+1) == pattrib->nr_frags) {	/* 4 the last fragment */
+					length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len;
+
+					aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
+				} else{
+					length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ;
+
+					aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
+					pframe += pxmitpriv->frag_len;
+					pframe = (u8 *)RND4((size_t)(pframe));
+				}
+			}
+		} else{
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
+			res = _FAIL;
+		}
+	}
+
+
+_func_exit_;
+		return res;
+}
+
+static int aes_decipher(u8 *key, uint	hdrlen,
+			u8 *pframe, uint plen)
+{
+	static u8	message[MAX_MSG_SIZE];
+	uint	qc_exists, a4_exists, i, j, payload_remainder,
+			num_blocks, payload_index;
+	int res = _SUCCESS;
+	u8 pn_vector[6];
+	u8 mic_iv[16];
+	u8 mic_header1[16];
+	u8 mic_header2[16];
+	u8 ctr_preload[16];
+
+	/* Intermediate Buffers */
+	u8 chain_buffer[16];
+	u8 aes_out[16];
+	u8 padded_buffer[16];
+	u8 mic[8];
+
+/*	uint	offset = 0; */
+	uint	frtype  = GetFrameType(pframe);
+	uint	frsubtype  = GetFrameSubType(pframe);
+_func_enter_;
+	frsubtype = frsubtype>>4;
+
+	_rtw_memset((void *)mic_iv, 0, 16);
+	_rtw_memset((void *)mic_header1, 0, 16);
+	_rtw_memset((void *)mic_header2, 0, 16);
+	_rtw_memset((void *)ctr_preload, 0, 16);
+	_rtw_memset((void *)chain_buffer, 0, 16);
+	_rtw_memset((void *)aes_out, 0, 16);
+	_rtw_memset((void *)padded_buffer, 0, 16);
+
+	/* start to decrypt the payload */
+
+	num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */
+
+	payload_remainder = (plen-8) % 16;
+
+	pn_vector[0]  = pframe[hdrlen];
+	pn_vector[1]  = pframe[hdrlen+1];
+	pn_vector[2]  = pframe[hdrlen+4];
+	pn_vector[3]  = pframe[hdrlen+5];
+	pn_vector[4]  = pframe[hdrlen+6];
+	pn_vector[5]  = pframe[hdrlen+7];
+
+	if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen ==  WLAN_HDR_A3_QOS_LEN))
+		a4_exists = 0;
+	else
+		a4_exists = 1;
+
+	if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) ||
+	    (frtype == WIFI_DATA_CFACKPOLL)) {
+			qc_exists = 1;
+			if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
+				hdrlen += 2;
+	} else if ((frsubtype == 0x08) || (frsubtype == 0x09) ||
+		   (frsubtype == 0x0a) || (frsubtype == 0x0b)) {
+		if (hdrlen !=  WLAN_HDR_A3_QOS_LEN)
+			hdrlen += 2;
+		qc_exists = 1;
+	} else {
+		qc_exists = 0;
+	}
+
+	/*  now, decrypt pframe with hdrlen offset and plen long */
+
+	payload_index = hdrlen + 8; /*  8 is for extiv */
+
+	for (i = 0; i < num_blocks; i++) {
+		construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1);
+
+		aes128k128d(key, ctr_preload, aes_out);
+		bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+
+		for (j = 0; j < 16; j++)
+			 pframe[payload_index++] = chain_buffer[j];
+	}
+
+	if (payload_remainder > 0) {    /* If there is a short final block, then pad it,*/
+					/* encrypt it and copy the unpadded part back   */
+		construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1);
+
+		for (j = 0; j < 16; j++)
+			padded_buffer[j] = 0x00;
+		for (j = 0; j < payload_remainder; j++)
+			padded_buffer[j] = pframe[payload_index+j];
+		aes128k128d(key, ctr_preload, aes_out);
+		bitwise_xor(aes_out, padded_buffer, chain_buffer);
+		for (j = 0; j < payload_remainder; j++)
+			pframe[payload_index++] = chain_buffer[j];
+	}
+
+	/* start to calculate the mic */
+	if ((hdrlen+plen+8) <= MAX_MSG_SIZE)
+		memcpy(message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */
+
+	pn_vector[0] = pframe[hdrlen];
+	pn_vector[1] = pframe[hdrlen+1];
+	pn_vector[2] = pframe[hdrlen+4];
+	pn_vector[3] = pframe[hdrlen+5];
+	pn_vector[4] = pframe[hdrlen+6];
+	pn_vector[5] = pframe[hdrlen+7];
+	construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector);
+
+	construct_mic_header1(mic_header1, hdrlen, message);
+	construct_mic_header2(mic_header2, message, a4_exists, qc_exists);
+
+	payload_remainder = (plen-8) % 16;
+	num_blocks = (plen-8) / 16;
+
+	/* Find start of payload */
+	payload_index = (hdrlen + 8);
+
+	/* Calculate MIC */
+	aes128k128d(key, mic_iv, aes_out);
+	bitwise_xor(aes_out, mic_header1, chain_buffer);
+	aes128k128d(key, chain_buffer, aes_out);
+	bitwise_xor(aes_out, mic_header2, chain_buffer);
+	aes128k128d(key, chain_buffer, aes_out);
+
+	for (i = 0; i < num_blocks; i++) {
+		bitwise_xor(aes_out, &message[payload_index], chain_buffer);
+
+		payload_index += 16;
+		aes128k128d(key, chain_buffer, aes_out);
+	}
+
+	/* Add on the final payload block if it needs padding */
+	if (payload_remainder > 0) {
+		for (j = 0; j < 16; j++)
+			padded_buffer[j] = 0x00;
+		for (j = 0; j < payload_remainder; j++)
+			padded_buffer[j] = message[payload_index++];
+		bitwise_xor(aes_out, padded_buffer, chain_buffer);
+		aes128k128d(key, chain_buffer, aes_out);
+	}
+
+	for (j = 0 ; j < 8; j++)
+		mic[j] = aes_out[j];
+
+	/* Insert MIC into payload */
+	for (j = 0; j < 8; j++)
+		message[payload_index+j] = mic[j];
+
+	payload_index = hdrlen + 8;
+	for (i = 0; i < num_blocks; i++) {
+		construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1);
+		aes128k128d(key, ctr_preload, aes_out);
+		bitwise_xor(aes_out, &message[payload_index], chain_buffer);
+		for (j = 0; j < 16; j++)
+			message[payload_index++] = chain_buffer[j];
+	}
+
+	if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/
+		/* encrypt it and copy the unpadded part back   */
+		construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks+1);
+
+		for (j = 0; j < 16; j++)
+			padded_buffer[j] = 0x00;
+		for (j = 0; j < payload_remainder; j++)
+			padded_buffer[j] = message[payload_index+j];
+		aes128k128d(key, ctr_preload, aes_out);
+		bitwise_xor(aes_out, padded_buffer, chain_buffer);
+		for (j = 0; j < payload_remainder; j++)
+			message[payload_index++] = chain_buffer[j];
+	}
+
+	/* Encrypt the MIC */
+	construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0);
+
+	for (j = 0; j < 16; j++)
+		padded_buffer[j] = 0x00;
+	for (j = 0; j < 8; j++)
+		padded_buffer[j] = message[j+hdrlen+8+plen-8];
+
+	aes128k128d(key, ctr_preload, aes_out);
+	bitwise_xor(aes_out, padded_buffer, chain_buffer);
+	for (j = 0; j < 8; j++)
+		message[payload_index++] = chain_buffer[j];
+
+	/* compare the mic */
+	for (i = 0; i < 8; i++) {
+		if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+				 ("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n",
+				 i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]));
+			DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n",
+				i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]);
+			res = _FAIL;
+		}
+	}
+_func_exit_;
+	return res;
+}
+
+u32	rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe)
+{	/*  exclude ICV */
+	/* Intermediate Buffers */
+	int		length;
+	u8	*pframe, *prwskey;	/*  *payload,*iv */
+	struct	sta_info		*stainfo;
+	struct	rx_pkt_attrib	 *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib;
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+	u32	res = _SUCCESS;
+_func_enter_;
+	pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data;
+	/* 4 start to encrypt each fragment */
+	if ((prxattrib->encrypt == _AES_)) {
+		stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
+		if (stainfo != NULL) {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n"));
+
+			if (IS_MCAST(prxattrib->ra)) {
+				/* in concurrent we should use sw descrypt in group key, so we remove this message */
+				if (!psecuritypriv->binstallGrpkey) {
+					res = _FAIL;
+					DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
+					goto exit;
+				}
+				prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+				if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
+					DBG_88E("not match packet_index=%d, install_index=%d\n",
+						prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid);
+					res = _FAIL;
+					goto exit;
+				}
+			} else {
+				prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+			}
+			length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len;
+			res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
+		} else {
+			RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
+			res = _FAIL;
+		}
+	}
+_func_exit_;
+exit:
+	return res;
+}
+
+/* AES tables*/
+const u32 Te0[256] = {
+	0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+	0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+	0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+	0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+	0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+	0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+	0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+	0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+	0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+	0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+	0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+	0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+	0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+	0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+	0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+	0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+	0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+	0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+	0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+	0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+	0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+	0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+	0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+	0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+	0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+	0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+	0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+	0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+	0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+	0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+	0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+	0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+	0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+	0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+	0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+	0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+	0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+	0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+	0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+	0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+	0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+	0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+	0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+	0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+	0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+	0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+	0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+	0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+	0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+	0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+	0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+	0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+	0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+	0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+	0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+	0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+	0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+	0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+	0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+	0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+	0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+	0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+	0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+	0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+
+const u32 Td0[256] = {
+	0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+	0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+	0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+	0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+	0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+	0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+	0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+	0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+	0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+	0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+	0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+	0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+	0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+	0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+	0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+	0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+	0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+	0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+	0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+	0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+	0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+	0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+	0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+	0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+	0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+	0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+	0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+	0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+	0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+	0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+	0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+	0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+	0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+	0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+	0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+	0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+	0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+	0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+	0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+	0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+	0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+	0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+	0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+	0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+	0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+	0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+	0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+	0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+	0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+	0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+	0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+	0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+	0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+	0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+	0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+	0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+	0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+	0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+	0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+	0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+	0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+	0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+	0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+	0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+
+const u8 Td4s[256] = {
+	0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
+	0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
+	0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
+	0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+	0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
+	0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
+	0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
+	0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
+	0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
+	0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
+	0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+	0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
+	0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+	0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
+	0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
+	0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
+	0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
+	0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
+	0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
+	0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
+	0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
+	0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+	0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
+	0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
+	0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
+	0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
+	0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
+	0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
+	0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+	0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
+	0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
+	0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+const u8 rcons[] = {
+	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+	/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+#define ROUND(i, d, s) \
+do {									\
+	d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
+	d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
+	d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
+	d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \
+} while (0);
+
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+void rtw_use_tkipkey_handler(void *FunctionContext)
+{
+	struct adapter *padapter = (struct adapter *)FunctionContext;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler ^^^\n"));
+
+	padapter->securitypriv.busetkipkey = true;
+
+	RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler padapter->securitypriv.busetkipkey=%d^^^\n", padapter->securitypriv.busetkipkey));
+
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_sreset.c b/drivers/staging/rtl8188eu/core/rtw_sreset.c
new file mode 100644
index 0000000..298f754
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_sreset.c
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include <rtw_sreset.h>
+
+void sreset_init_value(struct adapter *padapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+	_rtw_mutex_init(&psrtpriv->silentreset_mutex);
+	psrtpriv->silent_reset_inprogress = false;
+	psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+	psrtpriv->last_tx_time = 0;
+	psrtpriv->last_tx_complete_time = 0;
+}
+void sreset_reset_value(struct adapter *padapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+	psrtpriv->silent_reset_inprogress = false;
+	psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+	psrtpriv->last_tx_time = 0;
+	psrtpriv->last_tx_complete_time = 0;
+}
+
+u8 sreset_get_wifi_status(struct adapter *padapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+	u8 status = WIFI_STATUS_SUCCESS;
+	u32 val32 = 0;
+
+	if (psrtpriv->silent_reset_inprogress)
+		return status;
+	val32 = rtw_read32(padapter, REG_TXDMA_STATUS);
+	if (val32 == 0xeaeaeaea) {
+		psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST;
+	} else if (val32 != 0) {
+		DBG_88E("txdmastatu(%x)\n", val32);
+		psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR;
+	}
+
+	if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) {
+		DBG_88E("==>%s error_status(0x%x)\n", __func__, psrtpriv->Wifi_Error_Status);
+		status = (psrtpriv->Wifi_Error_Status & (~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL)));
+	}
+	DBG_88E("==> %s wifi_status(0x%x)\n", __func__, status);
+
+	/* status restore */
+	psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+
+	return status;
+}
+
+void sreset_set_wifi_error_status(struct adapter *padapter, u32 status)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	pHalData->srestpriv.Wifi_Error_Status = status;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
new file mode 100644
index 0000000..c2977be
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c
@@ -0,0 +1,655 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_STA_MGT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <mlme_osdep.h>
+#include <sta_info.h>
+
+static void _rtw_init_stainfo(struct sta_info *psta)
+{
+_func_enter_;
+	_rtw_memset((u8 *)psta, 0, sizeof (struct sta_info));
+
+	 _rtw_spinlock_init(&psta->lock);
+	_rtw_init_listhead(&psta->list);
+	_rtw_init_listhead(&psta->hash_list);
+	_rtw_init_queue(&psta->sleep_q);
+	psta->sleepq_len = 0;
+
+	_rtw_init_sta_xmit_priv(&psta->sta_xmitpriv);
+	_rtw_init_sta_recv_priv(&psta->sta_recvpriv);
+
+#ifdef CONFIG_88EU_AP_MODE
+
+	_rtw_init_listhead(&psta->asoc_list);
+
+	_rtw_init_listhead(&psta->auth_list);
+
+	psta->expire_to = 0;
+
+	psta->flags = 0;
+
+	psta->capability = 0;
+
+	psta->bpairwise_key_installed = false;
+
+#ifdef CONFIG_88EU_AP_MODE
+	psta->nonerp_set = 0;
+	psta->no_short_slot_time_set = 0;
+	psta->no_short_preamble_set = 0;
+	psta->no_ht_gf_set = 0;
+	psta->no_ht_set = 0;
+	psta->ht_20mhz_set = 0;
+#endif
+
+	psta->under_exist_checking = 0;
+
+	psta->keep_alive_trycnt = 0;
+
+#endif	/*  CONFIG_88EU_AP_MODE */
+
+_func_exit_;
+}
+
+u32	_rtw_init_sta_priv(struct	sta_priv *pstapriv)
+{
+	struct sta_info *psta;
+	s32 i;
+
+_func_enter_;
+
+	pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA + 4);
+
+	if (!pstapriv->pallocated_stainfo_buf)
+		return _FAIL;
+
+	pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
+		((size_t)(pstapriv->pallocated_stainfo_buf) & 3);
+
+	_rtw_init_queue(&pstapriv->free_sta_queue);
+
+	_rtw_spinlock_init(&pstapriv->sta_hash_lock);
+
+	pstapriv->asoc_sta_count = 0;
+	_rtw_init_queue(&pstapriv->sleep_q);
+	_rtw_init_queue(&pstapriv->wakeup_q);
+
+	psta = (struct sta_info *)(pstapriv->pstainfo_buf);
+
+	for (i = 0; i < NUM_STA; i++) {
+		_rtw_init_stainfo(psta);
+
+		_rtw_init_listhead(&(pstapriv->sta_hash[i]));
+
+		rtw_list_insert_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue));
+
+		psta++;
+	}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+	pstapriv->sta_dz_bitmap = 0;
+	pstapriv->tim_bitmap = 0;
+
+	_rtw_init_listhead(&pstapriv->asoc_list);
+	_rtw_init_listhead(&pstapriv->auth_list);
+	_rtw_spinlock_init(&pstapriv->asoc_list_lock);
+	_rtw_spinlock_init(&pstapriv->auth_list_lock);
+	pstapriv->asoc_list_cnt = 0;
+	pstapriv->auth_list_cnt = 0;
+
+	pstapriv->auth_to = 3; /*  3*2 = 6 sec */
+	pstapriv->assoc_to = 3;
+	pstapriv->expire_to = 3; /*  3*2 = 6 sec */
+	pstapriv->max_num_sta = NUM_STA;
+#endif
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta)
+{
+	int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info);
+
+	if (!stainfo_offset_valid(offset))
+		DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset);
+
+	return offset;
+}
+
+inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset)
+{
+	if (!stainfo_offset_valid(offset))
+		DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset);
+
+	return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info));
+}
+
+void	_rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv);
+void	_rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv)
+{
+_func_enter_;
+
+	_rtw_spinlock_free(&psta_xmitpriv->lock);
+
+	_rtw_spinlock_free(&(psta_xmitpriv->be_q.sta_pending.lock));
+	_rtw_spinlock_free(&(psta_xmitpriv->bk_q.sta_pending.lock));
+	_rtw_spinlock_free(&(psta_xmitpriv->vi_q.sta_pending.lock));
+	_rtw_spinlock_free(&(psta_xmitpriv->vo_q.sta_pending.lock));
+_func_exit_;
+}
+
+static void	_rtw_free_sta_recv_priv_lock(struct sta_recv_priv *psta_recvpriv)
+{
+_func_enter_;
+
+	_rtw_spinlock_free(&psta_recvpriv->lock);
+
+	_rtw_spinlock_free(&(psta_recvpriv->defrag_q.lock));
+
+_func_exit_;
+}
+
+void rtw_mfree_stainfo(struct sta_info *psta);
+void rtw_mfree_stainfo(struct sta_info *psta)
+{
+_func_enter_;
+
+	if (&psta->lock != NULL)
+		 _rtw_spinlock_free(&psta->lock);
+
+	_rtw_free_sta_xmit_priv_lock(&psta->sta_xmitpriv);
+	_rtw_free_sta_recv_priv_lock(&psta->sta_recvpriv);
+
+_func_exit_;
+}
+
+/*  this function is used to free the memory of lock || sema for all stainfos */
+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv);
+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv)
+{
+	unsigned long	 irql;
+	struct list_head *plist, *phead;
+	struct sta_info *psta = NULL;
+
+_func_enter_;
+
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+	phead = get_list_head(&pstapriv->free_sta_queue);
+	plist = get_next(phead);
+
+	while ((rtw_end_of_queue_search(phead, plist)) == false) {
+		psta = LIST_CONTAINOR(plist, struct sta_info , list);
+		plist = get_next(plist);
+
+		rtw_mfree_stainfo(psta);
+	}
+
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+_func_exit_;
+}
+
+static void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+#endif
+
+	 rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */
+
+	_rtw_spinlock_free(&pstapriv->free_sta_queue.lock);
+
+	_rtw_spinlock_free(&pstapriv->sta_hash_lock);
+	_rtw_spinlock_free(&pstapriv->wakeup_q.lock);
+	_rtw_spinlock_free(&pstapriv->sleep_q.lock);
+
+#ifdef CONFIG_88EU_AP_MODE
+	_rtw_spinlock_free(&pstapriv->asoc_list_lock);
+	_rtw_spinlock_free(&pstapriv->auth_list_lock);
+	_rtw_spinlock_free(&pacl_list->acl_node_q.lock);
+#endif
+}
+
+u32	_rtw_free_sta_priv(struct	sta_priv *pstapriv)
+{
+	unsigned long	irql;
+	struct list_head *phead, *plist;
+	struct sta_info *psta = NULL;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	int	index;
+
+_func_enter_;
+	if (pstapriv) {
+		/*	delete all reordering_ctrl_timer		*/
+		_enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+		for (index = 0; index < NUM_STA; index++) {
+			phead = &(pstapriv->sta_hash[index]);
+			plist = get_next(phead);
+
+			while ((rtw_end_of_queue_search(phead, plist)) == false) {
+				int i;
+				psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
+				plist = get_next(plist);
+
+				for (i = 0; i < 16; i++) {
+					preorder_ctrl = &psta->recvreorder_ctrl[i];
+					_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+				}
+			}
+		}
+		_exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+		/*===============================*/
+
+		rtw_mfree_sta_priv_lock(pstapriv);
+
+		if (pstapriv->pallocated_stainfo_buf) {
+			rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4);
+		}
+	}
+
+_func_exit_;
+	return _SUCCESS;
+}
+
+struct	sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
+{
+	unsigned long irql, irql2;
+	s32	index;
+	struct list_head *phash_list;
+	struct sta_info	*psta;
+	struct __queue *pfree_sta_queue;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	int i = 0;
+	u16  wRxSeqInitialValue = 0xffff;
+
+_func_enter_;
+
+	pfree_sta_queue = &pstapriv->free_sta_queue;
+
+	_enter_critical_bh(&(pfree_sta_queue->lock), &irql);
+
+	if (_rtw_queue_empty(pfree_sta_queue) == true) {
+		_exit_critical_bh(&(pfree_sta_queue->lock), &irql);
+		psta = NULL;
+	} else {
+		psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), struct sta_info, list);
+		rtw_list_delete(&(psta->list));
+		_exit_critical_bh(&(pfree_sta_queue->lock), &irql);
+		_rtw_init_stainfo(psta);
+		memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
+		index = wifi_mac_hash(hwaddr);
+		RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index=%x", index));
+		if (index >= NUM_STA) {
+			RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA"));
+			psta = NULL;
+			goto exit;
+		}
+		phash_list = &(pstapriv->sta_hash[index]);
+
+		_enter_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+
+		rtw_list_insert_tail(&psta->hash_list, phash_list);
+
+		pstapriv->asoc_sta_count++ ;
+
+		_exit_critical_bh(&(pstapriv->sta_hash_lock), &irql2);
+
+/*  Commented by Albert 2009/08/13 */
+/*  For the SMC router, the sequence number of first packet of WPS handshake will be 0. */
+/*  In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */
+/*  So, we initialize the tid_rxseq variable as the 0xffff. */
+
+		for (i = 0; i < 16; i++)
+			memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2);
+
+		RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
+			 ("alloc number_%d stainfo  with hwaddr = %pM\n",
+			 pstapriv->asoc_sta_count , hwaddr));
+
+		init_addba_retry_timer(pstapriv->padapter, psta);
+
+		/* for A-MPDU Rx reordering buffer control */
+		for (i = 0; i < 16; i++) {
+			preorder_ctrl = &psta->recvreorder_ctrl[i];
+
+			preorder_ctrl->padapter = pstapriv->padapter;
+
+			preorder_ctrl->enable = false;
+
+			preorder_ctrl->indicate_seq = 0xffff;
+			preorder_ctrl->wend_b = 0xffff;
+			preorder_ctrl->wsize_b = 64;/* 64; */
+
+			_rtw_init_queue(&preorder_ctrl->pending_recvframe_queue);
+
+			rtw_init_recv_timer(preorder_ctrl);
+		}
+
+		/* init for DM */
+		psta->rssi_stat.UndecoratedSmoothedPWDB = (-1);
+		psta->rssi_stat.UndecoratedSmoothedCCK = (-1);
+
+		/* init for the sequence number of received management frame */
+		psta->RxMgmtFrameSeqNum = 0xffff;
+	}
+
+exit:
+
+_func_exit_;
+
+	return psta;
+}
+
+/*  using pstapriv->sta_hash_lock to protect */
+u32	rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta)
+{
+	int i;
+	unsigned long irql0;
+	struct __queue *pfree_sta_queue;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	struct	sta_xmit_priv	*pstaxmitpriv;
+	struct	xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+
+_func_enter_;
+
+	if (psta == NULL)
+		goto exit;
+
+	pfree_sta_queue = &pstapriv->free_sta_queue;
+
+	pstaxmitpriv = &psta->sta_xmitpriv;
+
+	_enter_critical_bh(&pxmitpriv->lock, &irql0);
+
+	rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q);
+	psta->sleepq_len = 0;
+
+	rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
+
+	rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending));
+
+	rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
+
+	rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending));
+
+	rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
+
+	rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending));
+
+	rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
+
+	rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending));
+
+	_exit_critical_bh(&pxmitpriv->lock, &irql0);
+
+	rtw_list_delete(&psta->hash_list);
+	RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo  with hwaddr=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", pstapriv->asoc_sta_count , psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]));
+	pstapriv->asoc_sta_count--;
+
+	/*  re-init sta_info; 20061114 */
+	_rtw_init_sta_xmit_priv(&psta->sta_xmitpriv);
+	_rtw_init_sta_recv_priv(&psta->sta_recvpriv);
+
+	_cancel_timer_ex(&psta->addba_retry_timer);
+
+	/* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */
+	for (i = 0; i < 16 ; i++) {
+		unsigned long irql;
+		struct list_head *phead, *plist;
+		union recv_frame *prframe;
+		struct __queue *ppending_recvframe_queue;
+		struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+		preorder_ctrl = &psta->recvreorder_ctrl[i];
+
+		_cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer);
+
+		ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+		_enter_critical_bh(&ppending_recvframe_queue->lock, &irql);
+
+		phead =		get_list_head(ppending_recvframe_queue);
+		plist = get_next(phead);
+
+		while (!rtw_is_list_empty(phead)) {
+			prframe = LIST_CONTAINOR(plist, union recv_frame, u);
+
+			plist = get_next(plist);
+
+			rtw_list_delete(&(prframe->u.hdr.list));
+
+			rtw_free_recvframe(prframe, pfree_recv_queue);
+		}
+
+		_exit_critical_bh(&ppending_recvframe_queue->lock, &irql);
+	}
+
+	if (!(psta->state & WIFI_AP_STATE))
+		rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, false);
+
+#ifdef CONFIG_88EU_AP_MODE
+
+	_enter_critical_bh(&pstapriv->auth_list_lock, &irql0);
+	if (!rtw_is_list_empty(&psta->auth_list)) {
+		rtw_list_delete(&psta->auth_list);
+		pstapriv->auth_list_cnt--;
+	}
+	_exit_critical_bh(&pstapriv->auth_list_lock, &irql0);
+
+	psta->expire_to = 0;
+
+	psta->sleepq_ac_len = 0;
+	psta->qos_info = 0;
+
+	psta->max_sp_len = 0;
+	psta->uapsd_bk = 0;
+	psta->uapsd_be = 0;
+	psta->uapsd_vi = 0;
+	psta->uapsd_vo = 0;
+	psta->has_legacy_ac = 0;
+
+	pstapriv->sta_dz_bitmap &= ~BIT(psta->aid);
+	pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+	if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) {
+		pstapriv->sta_aid[psta->aid - 1] = NULL;
+		psta->aid = 0;
+	}
+
+	psta->under_exist_checking = 0;
+
+#endif	/*  CONFIG_88EU_AP_MODE */
+
+	_enter_critical_bh(&(pfree_sta_queue->lock), &irql0);
+	rtw_list_insert_tail(&psta->list, get_list_head(pfree_sta_queue));
+	_exit_critical_bh(&(pfree_sta_queue->lock), &irql0);
+
+exit:
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+/*  free all stainfo which in sta_hash[all] */
+void rtw_free_all_stainfo(struct adapter *padapter)
+{
+	unsigned long	 irql;
+	struct list_head *plist, *phead;
+	s32	index;
+	struct sta_info *psta = NULL;
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+	struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter);
+
+_func_enter_;
+
+	if (pstapriv->asoc_sta_count == 1)
+		goto exit;
+
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+	for (index = 0; index < NUM_STA; index++) {
+		phead = &(pstapriv->sta_hash[index]);
+		plist = get_next(phead);
+
+		while ((!rtw_end_of_queue_search(phead, plist))) {
+			psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
+
+			plist = get_next(plist);
+
+			if (pbcmc_stainfo != psta)
+				rtw_free_stainfo(padapter , psta);
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+exit:
+
+_func_exit_;
+}
+
+/* any station allocated can be searched by hash list */
+struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr)
+{
+	unsigned long	 irql;
+	struct list_head *plist, *phead;
+	struct sta_info *psta = NULL;
+	u32	index;
+	u8 *addr;
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+_func_enter_;
+
+	if (hwaddr == NULL)
+		return NULL;
+
+	if (IS_MCAST(hwaddr))
+		addr = bc_addr;
+	else
+		addr = hwaddr;
+
+	index = wifi_mac_hash(addr);
+
+	_enter_critical_bh(&pstapriv->sta_hash_lock, &irql);
+
+	phead = &(pstapriv->sta_hash[index]);
+	plist = get_next(phead);
+
+	while ((!rtw_end_of_queue_search(phead, plist))) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+		if ((_rtw_memcmp(psta->hwaddr, addr, ETH_ALEN)) == true) {
+			/*  if found the matched address */
+			break;
+		}
+		psta = NULL;
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&pstapriv->sta_hash_lock, &irql);
+_func_exit_;
+	return psta;
+}
+
+u32 rtw_init_bcmc_stainfo(struct adapter *padapter)
+{
+	struct sta_info		*psta;
+	u32 res = _SUCCESS;
+	unsigned char bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+
+_func_enter_;
+
+	psta = rtw_alloc_stainfo(pstapriv, bcast_addr);
+
+	if (psta == NULL) {
+		res = _FAIL;
+		RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("rtw_alloc_stainfo fail"));
+		goto exit;
+	}
+
+	/*  default broadcast & multicast use macid 1 */
+	psta->mac_id = 1;
+
+exit:
+_func_exit_;
+	return res;
+}
+
+struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter)
+{
+	struct sta_info		*psta;
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+	u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+_func_enter_;
+	 psta = rtw_get_stainfo(pstapriv, bc_addr);
+_func_exit_;
+	return psta;
+}
+
+u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr)
+{
+	u8 res = true;
+#ifdef CONFIG_88EU_AP_MODE
+	unsigned long irql;
+	struct list_head *plist, *phead;
+	struct rtw_wlan_acl_node *paclnode;
+	u8 match = false;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+	struct __queue *pacl_node_q = &pacl_list->acl_node_q;
+
+	_enter_critical_bh(&(pacl_node_q->lock), &irql);
+	phead = get_list_head(pacl_node_q);
+	plist = get_next(phead);
+	while ((!rtw_end_of_queue_search(phead, plist))) {
+		paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
+		plist = get_next(plist);
+
+		if (_rtw_memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
+			if (paclnode->valid) {
+				match = true;
+				break;
+			}
+		}
+	}
+	_exit_critical_bh(&(pacl_node_q->lock), &irql);
+
+	if (pacl_list->mode == 1)/* accept unless in deny list */
+		res = (match) ? false : true;
+	else if (pacl_list->mode == 2)/* deny unless in accept list */
+		res = (match) ? true : false;
+	else
+		 res = true;
+
+#endif
+
+	return res;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
new file mode 100644
index 0000000..013ea48
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -0,0 +1,1689 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_WLAN_UTIL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+
+static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f};
+static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74};
+
+static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18};
+static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7};
+
+static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96};
+static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43};
+static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43};
+static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c};
+static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5};
+static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c};
+
+unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20};
+
+#define R2T_PHY_DELAY	(0)
+
+/* define WAIT_FOR_BCN_TO_M	(3000) */
+#define WAIT_FOR_BCN_TO_MIN	(6000)
+#define WAIT_FOR_BCN_TO_MAX	(20000)
+
+static u8 rtw_basic_rate_cck[4] = {
+	IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK,
+	IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK
+};
+
+static u8 rtw_basic_rate_ofdm[3] = {
+	IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK,
+	IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK
+};
+
+static u8 rtw_basic_rate_mix[7] = {
+	IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK,
+	IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK,
+	IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK,
+	IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK
+};
+
+int cckrates_included(unsigned char *rate, int ratelen)
+{
+	int	i;
+
+	for (i = 0; i < ratelen; i++) {
+		if  ((((rate[i]) & 0x7f) == 2)	|| (((rate[i]) & 0x7f) == 4) ||
+		     (((rate[i]) & 0x7f) == 11)  || (((rate[i]) & 0x7f) == 22))
+			return true;
+	}
+	return false;
+}
+
+int cckratesonly_included(unsigned char *rate, int ratelen)
+{
+	int	i;
+
+	for (i = 0; i < ratelen; i++) {
+		if  ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+			   (((rate[i]) & 0x7f) != 11)  && (((rate[i]) & 0x7f) != 22))
+		return false;
+	}
+
+	return true;
+}
+
+unsigned char networktype_to_raid(unsigned char network_type)
+{
+	unsigned char raid;
+
+	switch (network_type) {
+	case WIRELESS_11B:
+		raid = RATR_INX_WIRELESS_B;
+		break;
+	case WIRELESS_11A:
+	case WIRELESS_11G:
+		raid = RATR_INX_WIRELESS_G;
+		break;
+	case WIRELESS_11BG:
+		raid = RATR_INX_WIRELESS_GB;
+		break;
+	case WIRELESS_11_24N:
+	case WIRELESS_11_5N:
+		raid = RATR_INX_WIRELESS_N;
+		break;
+	case WIRELESS_11A_5N:
+	case WIRELESS_11G_24N:
+		raid = RATR_INX_WIRELESS_NG;
+		break;
+	case WIRELESS_11BG_24N:
+		raid = RATR_INX_WIRELESS_NGB;
+		break;
+	default:
+		raid = RATR_INX_WIRELESS_GB;
+		break;
+	}
+	return raid;
+}
+
+u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int ratelen)
+{
+	u8 network_type = 0;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pmlmeext->cur_channel > 14) {
+		if (pmlmeinfo->HT_enable)
+			network_type = WIRELESS_11_5N;
+
+		network_type |= WIRELESS_11A;
+	} else {
+		if (pmlmeinfo->HT_enable)
+			network_type = WIRELESS_11_24N;
+
+		if ((cckratesonly_included(rate, ratelen)) == true)
+			network_type |= WIRELESS_11B;
+		else if ((cckrates_included(rate, ratelen)) == true)
+			network_type |= WIRELESS_11BG;
+		else
+			network_type |= WIRELESS_11G;
+	}
+	return	network_type;
+}
+
+static unsigned char ratetbl_val_2wifirate(unsigned char rate)
+{
+	unsigned char val = 0;
+
+	switch (rate & 0x7f) {
+	case 0:
+		val = IEEE80211_CCK_RATE_1MB;
+		break;
+	case 1:
+		val = IEEE80211_CCK_RATE_2MB;
+		break;
+	case 2:
+		val = IEEE80211_CCK_RATE_5MB;
+		break;
+	case 3:
+		val = IEEE80211_CCK_RATE_11MB;
+		break;
+	case 4:
+		val = IEEE80211_OFDM_RATE_6MB;
+		break;
+	case 5:
+		val = IEEE80211_OFDM_RATE_9MB;
+		break;
+	case 6:
+		val = IEEE80211_OFDM_RATE_12MB;
+		break;
+	case 7:
+		val = IEEE80211_OFDM_RATE_18MB;
+		break;
+	case 8:
+		val = IEEE80211_OFDM_RATE_24MB;
+		break;
+	case 9:
+		val = IEEE80211_OFDM_RATE_36MB;
+		break;
+	case 10:
+		val = IEEE80211_OFDM_RATE_48MB;
+		break;
+	case 11:
+		val = IEEE80211_OFDM_RATE_54MB;
+		break;
+	}
+	return val;
+}
+
+static int is_basicrate(struct adapter *padapter, unsigned char rate)
+{
+	int i;
+	unsigned char val;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	for (i = 0; i < NumRates; i++) {
+		val = pmlmeext->basicrate[i];
+
+		if ((val != 0xff) && (val != 0xfe)) {
+			if (rate == ratetbl_val_2wifirate(val))
+				return true;
+		}
+	}
+	return false;
+}
+
+static unsigned int ratetbl2rateset(struct adapter *padapter, unsigned char *rateset)
+{
+	int i;
+	unsigned char rate;
+	unsigned int	len = 0;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	for (i = 0; i < NumRates; i++) {
+		rate = pmlmeext->datarate[i];
+
+		switch (rate) {
+		case 0xff:
+			return len;
+		case 0xfe:
+			continue;
+		default:
+			rate = ratetbl_val_2wifirate(rate);
+
+			if (is_basicrate(padapter, rate) == true)
+				rate |= IEEE80211_BASIC_RATE_MASK;
+
+			rateset[len] = rate;
+			len++;
+			break;
+		}
+	}
+	return len;
+}
+
+void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len)
+{
+	unsigned char supportedrates[NumRates];
+
+	_rtw_memset(supportedrates, 0, NumRates);
+	*bssrate_len = ratetbl2rateset(padapter, supportedrates);
+	memcpy(pbssrate, supportedrates, *bssrate_len);
+}
+
+void UpdateBrateTbl(struct adapter *Adapter, u8 *mbrate)
+{
+	u8	i;
+	u8	rate;
+
+	/*  1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */
+	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+		rate = mbrate[i] & 0x7f;
+		switch (rate) {
+		case IEEE80211_CCK_RATE_1MB:
+		case IEEE80211_CCK_RATE_2MB:
+		case IEEE80211_CCK_RATE_5MB:
+		case IEEE80211_CCK_RATE_11MB:
+		case IEEE80211_OFDM_RATE_6MB:
+		case IEEE80211_OFDM_RATE_12MB:
+		case IEEE80211_OFDM_RATE_24MB:
+			mbrate[i] |= IEEE80211_BASIC_RATE_MASK;
+			break;
+		}
+	}
+}
+
+void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen)
+{
+	u8	i;
+	u8	rate;
+
+	for (i = 0; i < bssratelen; i++) {
+		rate = bssrateset[i] & 0x7f;
+		switch (rate) {
+		case IEEE80211_CCK_RATE_1MB:
+		case IEEE80211_CCK_RATE_2MB:
+		case IEEE80211_CCK_RATE_5MB:
+		case IEEE80211_CCK_RATE_11MB:
+			bssrateset[i] |= IEEE80211_BASIC_RATE_MASK;
+			break;
+		}
+	}
+}
+
+void Save_DM_Func_Flag(struct adapter *padapter)
+{
+	u8	saveflag = true;
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag));
+}
+
+void Restore_DM_Func_Flag(struct adapter *padapter)
+{
+	u8	saveflag = false;
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag));
+}
+
+void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable)
+{
+	if (enable)
+		rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode));
+	else
+		rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode));
+}
+
+static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
+}
+
+void Set_MSR(struct adapter *padapter, u8 type)
+{
+	Set_NETYPE0_MSR(padapter, type);
+}
+
+inline u8 rtw_get_oper_ch(struct adapter *adapter)
+{
+	return adapter->mlmeextpriv.oper_channel;
+}
+
+inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch)
+{
+	adapter->mlmeextpriv.oper_channel = ch;
+}
+
+inline u8 rtw_get_oper_bw(struct adapter *adapter)
+{
+	return adapter->mlmeextpriv.oper_bwmode;
+}
+
+inline void rtw_set_oper_bw(struct adapter *adapter, u8 bw)
+{
+	adapter->mlmeextpriv.oper_bwmode = bw;
+}
+
+inline u8 rtw_get_oper_choffset(struct adapter *adapter)
+{
+	return adapter->mlmeextpriv.oper_ch_offset;
+}
+
+inline void rtw_set_oper_choffset(struct adapter *adapter, u8 offset)
+{
+	adapter->mlmeextpriv.oper_ch_offset = offset;
+}
+
+void SelectChannel(struct adapter *padapter, unsigned char channel)
+{
+	/* saved channel info */
+	rtw_set_oper_ch(padapter, channel);
+	rtw_hal_set_chan(padapter, channel);
+}
+
+void SetBWMode(struct adapter *padapter, unsigned short bwmode,
+	       unsigned char channel_offset)
+{
+	/* saved bw info */
+	rtw_set_oper_bw(padapter, bwmode);
+	rtw_set_oper_choffset(padapter, channel_offset);
+
+	rtw_hal_set_bwmode(padapter, (enum ht_channel_width)bwmode, channel_offset);
+}
+
+void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode)
+{
+	u8 center_ch;
+
+	if (padapter->bNotifyChannelChange)
+		DBG_88E("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode);
+
+	if ((bwmode == HT_CHANNEL_WIDTH_20) ||
+	    (channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) {
+		/* SelectChannel(padapter, channel); */
+		center_ch = channel;
+	} else {
+		/* switch to the proper channel */
+		if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) {
+			/* SelectChannel(padapter, channel + 2); */
+			center_ch = channel + 2;
+		} else {
+			/* SelectChannel(padapter, channel - 2); */
+			center_ch = channel - 2;
+		}
+	}
+
+	/* set Channel */
+	/* saved channel/bw info */
+	rtw_set_oper_ch(padapter, channel);
+	rtw_set_oper_bw(padapter, bwmode);
+	rtw_set_oper_choffset(padapter, channel_offset);
+
+	rtw_hal_set_chan(padapter, center_ch); /*  set center channel */
+	SetBWMode(padapter, bwmode, channel_offset);
+}
+
+int get_bsstype(unsigned short capability)
+{
+	if (capability & BIT(0))
+		return WIFI_FW_AP_STATE;
+	else if (capability & BIT(1))
+		return WIFI_FW_ADHOC_STATE;
+	else
+		return 0;
+}
+
+__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork)
+{
+	return pnetwork->MacAddress;
+}
+
+u16 get_beacon_interval(struct wlan_bssid_ex *bss)
+{
+	__le16 val;
+	memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2);
+
+	return le16_to_cpu(val);
+}
+
+int is_client_associated_to_ap(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext;
+	struct mlme_ext_info	*pmlmeinfo;
+
+	if (!padapter)
+		return _FAIL;
+
+	pmlmeext = &padapter->mlmeextpriv;
+	pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE))
+		return true;
+	else
+		return _FAIL;
+}
+
+int is_client_associated_to_ibss(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE))
+		return true;
+	else
+		return _FAIL;
+}
+
+int is_IBSS_empty(struct adapter *padapter)
+{
+	unsigned int i;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) {
+		if (pmlmeinfo->FW_sta_info[i].status == 1)
+			return _FAIL;
+	}
+	return true;
+}
+
+unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval)
+{
+	if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN)
+		return WAIT_FOR_BCN_TO_MIN;
+	else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX)
+		return WAIT_FOR_BCN_TO_MAX;
+	else
+		return bcn_interval << 2;
+}
+
+void CAM_empty_entry(struct adapter *Adapter, u8 ucIndex)
+{
+	rtw_hal_set_hwreg(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex));
+}
+
+void invalidate_cam_all(struct adapter *padapter)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL);
+}
+
+void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key)
+{
+	unsigned int	i, val, addr;
+	int j;
+	u32	cam_val[2];
+
+	addr = entry << 3;
+
+	for (j = 5; j >= 0; j--) {
+		switch (j) {
+		case 0:
+			val = (ctrl | (mac[0] << 16) | (mac[1] << 24));
+			break;
+		case 1:
+			val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24));
+			break;
+		default:
+			i = (j - 2) << 2;
+			val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24));
+			break;
+		}
+
+		cam_val[0] = val;
+		cam_val[1] = addr + (unsigned int)j;
+
+		rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val);
+	}
+}
+
+void clear_cam_entry(struct adapter *padapter, u8 entry)
+{
+	unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+	write_cam(padapter, entry, 0, null_sta, null_key);
+}
+
+int allocate_fw_sta_entry(struct adapter *padapter)
+{
+	unsigned int mac_id;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) {
+		if (pmlmeinfo->FW_sta_info[mac_id].status == 0) {
+			pmlmeinfo->FW_sta_info[mac_id].status = 1;
+			pmlmeinfo->FW_sta_info[mac_id].retry = 0;
+			break;
+		}
+	}
+
+	return mac_id;
+}
+
+void flush_all_cam_entry(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL);
+
+	_rtw_memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info));
+}
+
+int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+	/* struct registry_priv	*pregpriv = &padapter->registrypriv; */
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pmlmepriv->qospriv.qos_option == 0) {
+		pmlmeinfo->WMM_enable = 0;
+		return _FAIL;
+	}
+
+	pmlmeinfo->WMM_enable = 1;
+	memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element));
+	return true;
+}
+
+void WMMOnAssocRsp(struct adapter *padapter)
+{
+	u8	ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime;
+	u8	acm_mask;
+	u16	TXOP;
+	u32	acParm, i;
+	u32	edca[4], inx[4];
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct xmit_priv		*pxmitpriv = &padapter->xmitpriv;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+
+	if (pmlmeinfo->WMM_enable == 0) {
+		padapter->mlmepriv.acm_mask = 0;
+		return;
+	}
+
+	acm_mask = 0;
+
+	if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+		aSifsTime = 10;
+	else
+		aSifsTime = 16;
+
+	for (i = 0; i < 4; i++) {
+		ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03;
+		ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01;
+
+		/* AIFS = AIFSN * slot time + SIFS - r2t phy delay */
+		AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime;
+
+		ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f);
+		ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4;
+		TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit);
+
+		acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+
+		switch (ACI) {
+		case 0x0:
+			rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+			acm_mask |= (ACM ? BIT(1) : 0);
+			edca[XMIT_BE_QUEUE] = acParm;
+			break;
+		case 0x1:
+			rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+			edca[XMIT_BK_QUEUE] = acParm;
+			break;
+		case 0x2:
+			rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+			acm_mask |= (ACM ? BIT(2) : 0);
+			edca[XMIT_VI_QUEUE] = acParm;
+			break;
+		case 0x3:
+			rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+			acm_mask |= (ACM ? BIT(3) : 0);
+			edca[XMIT_VO_QUEUE] = acParm;
+			break;
+		}
+
+		DBG_88E("WMM(%x): %x, %x\n", ACI, ACM, acParm);
+	}
+
+	if (padapter->registrypriv.acm_method == 1)
+		rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask));
+	else
+		padapter->mlmepriv.acm_mask = acm_mask;
+
+	inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+
+	if (pregpriv->wifi_spec == 1) {
+		u32	j, tmp, change_inx;
+
+		/* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
+		for (i = 0; i < 4; i++) {
+			for (j = i+1; j < 4; j++) {
+				/* compare CW and AIFS */
+				if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) {
+					change_inx = true;
+				} else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
+					/* compare TXOP */
+					if ((edca[j] >> 16) > (edca[i] >> 16))
+						change_inx = true;
+				}
+
+				if (change_inx) {
+					tmp = edca[i];
+					edca[i] = edca[j];
+					edca[j] = tmp;
+
+					tmp = inx[i];
+					inx[i] = inx[j];
+					inx[j] = tmp;
+
+					change_inx = false;
+				}
+			}
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		pxmitpriv->wmm_para_seq[i] = inx[i];
+		DBG_88E("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
+	}
+
+	return;
+}
+
+static void bwmode_update_check(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+	unsigned char	 new_bwmode;
+	unsigned char  new_ch_offset;
+	struct HT_info_element	 *pHT_info;
+	struct mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct ht_priv			*phtpriv = &pmlmepriv->htpriv;
+
+	if (!pIE)
+		return;
+
+	if (!phtpriv)
+		return;
+
+	if (pIE->Length > sizeof(struct HT_info_element))
+		return;
+
+	pHT_info = (struct HT_info_element *)pIE->data;
+
+	if ((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable) {
+		new_bwmode = HT_CHANNEL_WIDTH_40;
+
+		switch (pHT_info->infos[0] & 0x3) {
+		case 1:
+			new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+			break;
+		case 3:
+			new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+			break;
+		default:
+			new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+			break;
+		}
+	} else {
+		new_bwmode = HT_CHANNEL_WIDTH_20;
+		new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+	}
+
+	if ((new_bwmode != pmlmeext->cur_bwmode) ||
+	    (new_ch_offset != pmlmeext->cur_ch_offset)) {
+		pmlmeinfo->bwmode_updated = true;
+
+		pmlmeext->cur_bwmode = new_bwmode;
+		pmlmeext->cur_ch_offset = new_ch_offset;
+
+		/* update HT info also */
+		HT_info_handler(padapter, pIE);
+	} else {
+		pmlmeinfo->bwmode_updated = false;
+	}
+
+	if (pmlmeinfo->bwmode_updated) {
+		struct sta_info *psta;
+		struct wlan_bssid_ex	*cur_network = &(pmlmeinfo->network);
+		struct sta_priv	*pstapriv = &padapter->stapriv;
+
+		/* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */
+
+		/* update ap's stainfo */
+		psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress);
+		if (psta) {
+			struct ht_priv	*phtpriv_sta = &psta->htpriv;
+
+			if (phtpriv_sta->ht_option) {
+				/*  bwmode */
+				phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+				phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+			} else {
+				phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+				phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+			}
+		}
+	}
+}
+
+void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+	unsigned int	i;
+	u8	rf_type;
+	u8	max_AMPDU_len, min_MPDU_spacing;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv			*phtpriv = &pmlmepriv->htpriv;
+
+	if (pIE == NULL)
+		return;
+
+	if (!phtpriv->ht_option)
+		return;
+
+	pmlmeinfo->HT_caps_enable = 1;
+
+	for (i = 0; i < (pIE->Length); i++) {
+		if (i != 2) {
+			/* 	Got the endian issue here. */
+			pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]);
+		} else {
+			/* modify from  fw by Thomas 2010/11/17 */
+			if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3))
+				max_AMPDU_len = (pIE->data[i] & 0x3);
+			else
+				max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3);
+
+			if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c))
+				min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c);
+			else
+				min_MPDU_spacing = (pIE->data[i] & 0x1c);
+
+			pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing;
+		}
+	}
+
+	rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+	/* update the MCS rates */
+	for (i = 0; i < 16; i++) {
+		if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R))
+			pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i];
+		else
+			pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i];
+	}
+	return;
+}
+
+void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct ht_priv			*phtpriv = &pmlmepriv->htpriv;
+
+	if (pIE == NULL)
+		return;
+
+	if (!phtpriv->ht_option)
+		return;
+
+	if (pIE->Length > sizeof(struct HT_info_element))
+		return;
+
+	pmlmeinfo->HT_info_enable = 1;
+	memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length);
+	return;
+}
+
+void HTOnAssocRsp(struct adapter *padapter)
+{
+	unsigned char		max_AMPDU_len;
+	unsigned char		min_MPDU_spacing;
+	/* struct registry_priv	 *pregpriv = &padapter->registrypriv; */
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	DBG_88E("%s\n", __func__);
+
+	if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) {
+		pmlmeinfo->HT_enable = 1;
+	} else {
+		pmlmeinfo->HT_enable = 0;
+		return;
+	}
+
+	/* handle A-MPDU parameter field */
+	/*
+		AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+		AMPDU_para [4:2]:Min MPDU Start Spacing
+	*/
+	max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+	min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+}
+
+void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pIE->Length > 1)
+		return;
+
+	pmlmeinfo->ERP_enable = 1;
+	memcpy(&(pmlmeinfo->ERP_IE), pIE->data, pIE->Length);
+}
+
+void VCS_update(struct adapter *padapter, struct sta_info *psta)
+{
+	struct registry_priv	 *pregpriv = &padapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */
+	case 0: /* off */
+		psta->rtsen = 0;
+		psta->cts2self = 0;
+		break;
+	case 1: /* on */
+		if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */
+			psta->rtsen = 1;
+			psta->cts2self = 0;
+		} else {
+			psta->rtsen = 0;
+			psta->cts2self = 1;
+		}
+		break;
+	case 2: /* auto */
+	default:
+		if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) {
+			if (pregpriv->vcs_type == 1) {
+				psta->rtsen = 1;
+				psta->cts2self = 0;
+			} else {
+				psta->rtsen = 0;
+				psta->cts2self = 1;
+			}
+		} else {
+			psta->rtsen = 0;
+			psta->cts2self = 0;
+		}
+		break;
+	}
+}
+
+int rtw_check_bcn_info(struct adapter  *Adapter, u8 *pframe, u32 packet_len)
+{
+	unsigned int		len;
+	unsigned char		*p;
+	unsigned short	val16, subtype;
+	struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network);
+	/* u8 wpa_ie[255], rsn_ie[255]; */
+	u16 wpa_len = 0, rsn_len = 0;
+	u8 encryp_protocol = 0;
+	struct wlan_bssid_ex *bssid;
+	int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0;
+	unsigned char *pbuf;
+	u32 wpa_ielen = 0;
+	u8 *pbssid = GetAddr3Ptr(pframe);
+	u32 hidden_ssid = 0;
+	struct HT_info_element *pht_info = NULL;
+	struct rtw_ieee80211_ht_cap *pht_cap = NULL;
+	u32 bcn_channel;
+	unsigned short	ht_cap_info;
+	unsigned char	ht_info_infos_0;
+
+	if (is_client_associated_to_ap(Adapter) == false)
+		return true;
+
+	len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	if (len > MAX_IE_SZ) {
+		DBG_88E("%s IE too long for survey event\n", __func__);
+		return _FAIL;
+	}
+
+	if (_rtw_memcmp(cur_network->network.MacAddress, pbssid, 6) == false) {
+		DBG_88E("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n%pM %pM\n",
+			(pbssid), (cur_network->network.MacAddress));
+		return true;
+	}
+
+	bssid = (struct wlan_bssid_ex *)rtw_zmalloc(sizeof(struct wlan_bssid_ex));
+
+	subtype = GetFrameSubType(pframe) >> 4;
+
+	if (subtype == WIFI_BEACON)
+		bssid->Reserved[0] = 1;
+
+	bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
+
+	/* below is to copy the information element */
+	bssid->IELength = len;
+	memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength);
+
+	/* check bw and channel offset */
+	/* parsing HT_CAP_IE */
+	p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+	if (p && len > 0) {
+		pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);
+		ht_cap_info = pht_cap->cap_info;
+	} else {
+		ht_cap_info = 0;
+	}
+	/* parsing HT_INFO_IE */
+	p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+	if (p && len > 0) {
+			pht_info = (struct HT_info_element *)(p + 2);
+			ht_info_infos_0 = pht_info->infos[0];
+	} else {
+			ht_info_infos_0 = 0;
+	}
+	if (ht_cap_info != cur_network->BcnInfo.ht_cap_info ||
+	    ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) {
+			DBG_88E("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
+				ht_cap_info, ht_info_infos_0);
+			DBG_88E("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
+				cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0);
+			DBG_88E("%s bw mode change, disconnect\n", __func__);
+			/* bcn_info_update */
+			cur_network->BcnInfo.ht_cap_info = ht_cap_info;
+			cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0;
+			/* to do : need to check that whether modify related register of BB or not */
+			/* goto _mismatch; */
+	}
+
+	/* Checking for channel */
+	p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+	if (p) {
+			bcn_channel = *(p + 2);
+	} else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */
+			p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+			if (pht_info) {
+					bcn_channel = pht_info->primary_channel;
+			} else { /* we don't find channel IE, so don't check it */
+					DBG_88E("Oops: %s we don't find channel IE, so don't check it\n", __func__);
+					bcn_channel = Adapter->mlmeextpriv.cur_channel;
+			}
+	}
+	if (bcn_channel != Adapter->mlmeextpriv.cur_channel) {
+			DBG_88E("%s beacon channel:%d cur channel:%d disconnect\n", __func__,
+				bcn_channel, Adapter->mlmeextpriv.cur_channel);
+			goto _mismatch;
+	}
+
+	/* checking SSID */
+	p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+	if (p == NULL) {
+		DBG_88E("%s marc: cannot find SSID for survey event\n", __func__);
+		hidden_ssid = true;
+	} else {
+		hidden_ssid = false;
+	}
+
+	if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) {
+		memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
+		bssid->Ssid.SsidLength = *(p + 1);
+	} else {
+		bssid->Ssid.SsidLength = 0;
+		bssid->Ssid.Ssid[0] = '\0';
+	}
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d "
+				"cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid,
+				bssid->Ssid.SsidLength, cur_network->network.Ssid.Ssid,
+				cur_network->network.Ssid.SsidLength));
+
+	if (!_rtw_memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) ||
+	    bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) {
+		if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */
+			DBG_88E("%s(), SSID is not match return FAIL\n", __func__);
+			goto _mismatch;
+		}
+	}
+
+	/* check encryption info */
+	val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid);
+
+	if (val16 & BIT(4))
+		bssid->Privacy = 1;
+	else
+		bssid->Privacy = 0;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+		 ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n",
+		 __func__, cur_network->network.Privacy, bssid->Privacy));
+	if (cur_network->network.Privacy != bssid->Privacy) {
+		DBG_88E("%s(), privacy is not match return FAIL\n", __func__);
+		goto _mismatch;
+	}
+
+	rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, &wpa_len);
+
+	if (rsn_len > 0) {
+		encryp_protocol = ENCRYP_PROTOCOL_WPA2;
+	} else if (wpa_len > 0) {
+		encryp_protocol = ENCRYP_PROTOCOL_WPA;
+	} else {
+		if (bssid->Privacy)
+			encryp_protocol = ENCRYP_PROTOCOL_WEP;
+	}
+
+	if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) {
+		DBG_88E("%s(): enctyp is not match , return FAIL\n", __func__);
+		goto _mismatch;
+	}
+
+	if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) {
+		pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12);
+		if (pbuf && (wpa_ielen > 0)) {
+			if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) {
+				RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+					 ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__,
+					 pairwise_cipher, group_cipher, is_8021x));
+			}
+		} else {
+			pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12);
+
+			if (pbuf && (wpa_ielen > 0)) {
+				if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) {
+					RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+						 ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n",
+						  __func__, pairwise_cipher, group_cipher, is_8021x));
+				}
+			}
+		}
+
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+			 ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher));
+		if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) {
+			DBG_88E("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__,
+				pairwise_cipher, cur_network->BcnInfo.pairwise_cipher,
+				group_cipher, cur_network->BcnInfo.group_cipher);
+			goto _mismatch;
+		}
+
+		if (is_8021x != cur_network->BcnInfo.is_8021x) {
+			DBG_88E("%s authentication is not match , return FAIL\n", __func__);
+			goto _mismatch;
+		}
+	}
+
+	kfree(bssid);
+	return _SUCCESS;
+
+_mismatch:
+	kfree(bssid);
+	return _FAIL;
+
+	_func_exit_;
+}
+
+void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta)
+{
+	unsigned int i;
+	unsigned int len;
+	struct ndis_802_11_var_ie *pIE;
+
+	len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN);
+
+	for (i = 0; i < len;) {
+		pIE = (struct ndis_802_11_var_ie *)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i);
+
+		switch (pIE->ElementID) {
+		case _HT_EXTRA_INFO_IE_:	/* HT info */
+			/* HT_info_handler(padapter, pIE); */
+			bwmode_update_check(padapter, pIE);
+			break;
+		case _ERPINFO_IE_:
+			ERP_IE_handler(padapter, pIE);
+			VCS_update(padapter, psta);
+			break;
+		default:
+			break;
+		}
+
+		i += (pIE->Length + 2);
+	}
+}
+
+unsigned int is_ap_in_tkip(struct adapter *padapter)
+{
+	u32 i;
+	struct ndis_802_11_var_ie *pIE;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex		*cur_network = &(pmlmeinfo->network);
+
+	if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+		for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) {
+			pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i);
+
+			switch (pIE->ElementID) {
+			case _VENDOR_SPECIFIC_IE_:
+				if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) && (_rtw_memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4)))
+					return true;
+				break;
+			case _RSN_IE_2_:
+				if (_rtw_memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4))
+					return true;
+			default:
+				break;
+			}
+
+			i += (pIE->Length + 2);
+		}
+		return false;
+	} else {
+		return false;
+	}
+}
+
+unsigned int should_forbid_n_rate(struct adapter *padapter)
+{
+	u32 i;
+	struct ndis_802_11_var_ie *pIE;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct wlan_bssid_ex  *cur_network = &pmlmepriv->cur_network.network;
+
+	if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+		for (i = sizeof(struct ndis_802_11_fixed_ie); i < cur_network->IELength;) {
+			pIE = (struct ndis_802_11_var_ie *)(cur_network->IEs + i);
+
+			switch (pIE->ElementID) {
+			case _VENDOR_SPECIFIC_IE_:
+				if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4) &&
+				    ((_rtw_memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) ||
+				    (_rtw_memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4))))
+					return false;
+				break;
+			case _RSN_IE_2_:
+				if  ((_rtw_memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4))  ||
+				       (_rtw_memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4)))
+				return false;
+			default:
+				break;
+			}
+
+			i += (pIE->Length + 2);
+		}
+
+		return true;
+	} else {
+		return false;
+	}
+}
+
+unsigned int is_ap_in_wep(struct adapter *padapter)
+{
+	u32 i;
+	struct ndis_802_11_var_ie *pIE;
+	struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex		*cur_network = &(pmlmeinfo->network);
+
+	if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+		for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) {
+			pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i);
+
+			switch (pIE->ElementID) {
+			case _VENDOR_SPECIFIC_IE_:
+				if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4))
+					return false;
+				break;
+			case _RSN_IE_2_:
+				return false;
+			default:
+				break;
+			}
+			i += (pIE->Length + 2);
+		}
+		return true;
+	} else {
+		return false;
+	}
+}
+
+int wifirate2_ratetbl_inx(unsigned char rate)
+{
+	int	inx = 0;
+	rate = rate & 0x7f;
+
+	switch (rate) {
+	case 54*2:
+		inx = 11;
+		break;
+	case 48*2:
+		inx = 10;
+		break;
+	case 36*2:
+		inx = 9;
+		break;
+	case 24*2:
+		inx = 8;
+		break;
+	case 18*2:
+		inx = 7;
+		break;
+	case 12*2:
+		inx = 6;
+		break;
+	case 9*2:
+		inx = 5;
+		break;
+	case 6*2:
+		inx = 4;
+		break;
+	case 11*2:
+		inx = 3;
+		break;
+	case 11:
+		inx = 2;
+		break;
+	case 2*2:
+		inx = 1;
+		break;
+	case 1*2:
+		inx = 0;
+		break;
+	}
+	return inx;
+}
+
+unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz)
+{
+	unsigned int i, num_of_rate;
+	unsigned int mask = 0;
+
+	num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz;
+
+	for (i = 0; i < num_of_rate; i++) {
+		if ((*(ptn + i)) & 0x80)
+			mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i));
+	}
+	return mask;
+}
+
+unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz)
+{
+	unsigned int i, num_of_rate;
+	unsigned int mask = 0;
+
+	num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz;
+
+	for (i = 0; i < num_of_rate; i++)
+		mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i));
+	return mask;
+}
+
+unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps)
+{
+	unsigned int mask = 0;
+
+	mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20));
+
+	return mask;
+}
+
+int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps)
+{
+	unsigned char					bit_offset;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (!(pmlmeinfo->HT_enable))
+		return _FAIL;
+
+	if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK))
+		return _FAIL;
+
+	bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40) ? 6 : 5;
+
+	if (__le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & (0x1 << bit_offset))
+		return _SUCCESS;
+	else
+		return _FAIL;
+}
+
+unsigned char get_highest_rate_idx(u32 mask)
+{
+	int i;
+	unsigned char rate_idx = 0;
+
+	for (i = 27; i >= 0; i--) {
+		if (mask & BIT(i)) {
+			rate_idx = i;
+			break;
+		}
+	}
+	return rate_idx;
+}
+
+void Update_RA_Entry(struct adapter *padapter, u32 mac_id)
+{
+	rtw_hal_update_ra_mask(padapter, mac_id, 0);
+}
+
+static void enable_rate_adaptive(struct adapter *padapter, u32 mac_id)
+{
+	Update_RA_Entry(padapter, mac_id);
+}
+
+void set_sta_rate(struct adapter *padapter, struct sta_info *psta)
+{
+	/* rate adaptive */
+	enable_rate_adaptive(padapter, psta->mac_id);
+}
+
+/*  Update RRSR and Rate for USERATE */
+void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode)
+{
+	unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX];
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+	/* 	Added by Albert 2011/03/22 */
+	/* 	In the P2P mode, the driver should not support the b mode. */
+	/* 	So, the Tx packet shouldn't use the CCK rate */
+	if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+		return;
+#endif /* CONFIG_88EU_P2P */
+	_rtw_memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+	if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) {
+		memcpy(supported_rates, rtw_basic_rate_cck, 4);
+	} else if (wirelessmode & WIRELESS_11B) {
+		memcpy(supported_rates, rtw_basic_rate_mix, 7);
+	} else {
+		memcpy(supported_rates, rtw_basic_rate_ofdm, 3);
+	}
+
+	if (wirelessmode & WIRELESS_11B)
+		update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB);
+	else
+		update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB);
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, supported_rates);
+}
+
+unsigned char check_assoc_AP(u8 *pframe, uint len)
+{
+	unsigned int i;
+	struct ndis_802_11_var_ie *pIE;
+	u8	epigram_vendor_flag;
+	u8	ralink_vendor_flag;
+	epigram_vendor_flag = 0;
+	ralink_vendor_flag = 0;
+
+	for (i = sizeof(struct ndis_802_11_fixed_ie); i < len;) {
+		pIE = (struct ndis_802_11_var_ie *)(pframe + i);
+
+		switch (pIE->ElementID) {
+		case _VENDOR_SPECIFIC_IE_:
+			if ((_rtw_memcmp(pIE->data, ARTHEROS_OUI1, 3)) ||
+			    (_rtw_memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
+				DBG_88E("link to Artheros AP\n");
+				return HT_IOT_PEER_ATHEROS;
+			} else if ((_rtw_memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
+				   (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3)) ||
+				   (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3))) {
+				DBG_88E("link to Broadcom AP\n");
+				return HT_IOT_PEER_BROADCOM;
+			} else if (_rtw_memcmp(pIE->data, MARVELL_OUI, 3)) {
+				DBG_88E("link to Marvell AP\n");
+				return HT_IOT_PEER_MARVELL;
+			} else if (_rtw_memcmp(pIE->data, RALINK_OUI, 3)) {
+				if (!ralink_vendor_flag) {
+					ralink_vendor_flag = 1;
+				} else {
+					DBG_88E("link to Ralink AP\n");
+					return HT_IOT_PEER_RALINK;
+				}
+			} else if (_rtw_memcmp(pIE->data, CISCO_OUI, 3)) {
+				DBG_88E("link to Cisco AP\n");
+				return HT_IOT_PEER_CISCO;
+			} else if (_rtw_memcmp(pIE->data, REALTEK_OUI, 3)) {
+				DBG_88E("link to Realtek 96B\n");
+				return HT_IOT_PEER_REALTEK;
+			} else if (_rtw_memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
+				DBG_88E("link to Airgo Cap\n");
+				return HT_IOT_PEER_AIRGO;
+			} else if (_rtw_memcmp(pIE->data, EPIGRAM_OUI, 3)) {
+				 epigram_vendor_flag = 1;
+				if (ralink_vendor_flag) {
+					DBG_88E("link to Tenda W311R AP\n");
+					 return HT_IOT_PEER_TENDA;
+				} else {
+					DBG_88E("Capture EPIGRAM_OUI\n");
+				}
+			} else {
+				break;
+			}
+
+		default:
+			break;
+		}
+		i += (pIE->Length + 2);
+	}
+
+	if (ralink_vendor_flag && !epigram_vendor_flag) {
+		DBG_88E("link to Ralink AP\n");
+		return HT_IOT_PEER_RALINK;
+	} else if (ralink_vendor_flag && epigram_vendor_flag) {
+		DBG_88E("link to Tenda W311R AP\n");
+		return HT_IOT_PEER_TENDA;
+	} else {
+		DBG_88E("link to new AP\n");
+		return HT_IOT_PEER_UNKNOWN;
+	}
+}
+
+void update_IOT_info(struct adapter *padapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	switch (pmlmeinfo->assoc_AP_vendor) {
+	case HT_IOT_PEER_MARVELL:
+		pmlmeinfo->turboMode_cts2self = 1;
+		pmlmeinfo->turboMode_rtsen = 0;
+		break;
+	case HT_IOT_PEER_RALINK:
+		pmlmeinfo->turboMode_cts2self = 0;
+		pmlmeinfo->turboMode_rtsen = 1;
+		/* disable high power */
+		Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false);
+		break;
+	case HT_IOT_PEER_REALTEK:
+		/* rtw_write16(padapter, 0x4cc, 0xffff); */
+		/* rtw_write16(padapter, 0x546, 0x01c0); */
+		/* disable high power */
+		Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false);
+		break;
+	default:
+		pmlmeinfo->turboMode_cts2self = 0;
+		pmlmeinfo->turboMode_rtsen = 1;
+		break;
+	}
+}
+
+void update_capinfo(struct adapter *Adapter, u16 updateCap)
+{
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	bool		ShortPreamble;
+
+	/*  Check preamble mode, 2005.01.06, by rcnjko. */
+	/*  Mark to update preamble value forever, 2008.03.18 by lanhsin */
+
+	if (updateCap & cShortPreamble) { /*  Short Preamble */
+		if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { /*  PREAMBLE_LONG or PREAMBLE_AUTO */
+			ShortPreamble = true;
+			pmlmeinfo->preamble_mode = PREAMBLE_SHORT;
+			rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble);
+		}
+	} else { /*  Long Preamble */
+		if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) {  /*  PREAMBLE_SHORT or PREAMBLE_AUTO */
+			ShortPreamble = false;
+			pmlmeinfo->preamble_mode = PREAMBLE_LONG;
+			rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble);
+		}
+	}
+
+	if (updateCap & cIBSS) {
+		/* Filen: See 802.11-2007 p.91 */
+		pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+	} else { /* Filen: See 802.11-2007 p.90 */
+		if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) {
+			if (updateCap & cShortSlotTime) { /*  Short Slot Time */
+				if (pmlmeinfo->slotTime != SHORT_SLOT_TIME)
+					pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+			} else { /*  Long Slot Time */
+				if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME)
+					pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+			}
+		} else if (pmlmeext->cur_wireless_mode & (WIRELESS_11A | WIRELESS_11_5N)) {
+			pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+		} else {
+			/* B Mode */
+			pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+		}
+	}
+
+	rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime);
+}
+
+void update_wireless_mode(struct adapter *padapter)
+{
+	int ratelen, network_type = 0;
+	u32 SIFS_Timer;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex	*cur_network = &(pmlmeinfo->network);
+	unsigned char		*rate = cur_network->SupportedRates;
+
+	ratelen = rtw_get_rateset_len(cur_network->SupportedRates);
+
+	if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable))
+		pmlmeinfo->HT_enable = 1;
+
+	if (pmlmeext->cur_channel > 14) {
+		if (pmlmeinfo->HT_enable)
+			network_type = WIRELESS_11_5N;
+
+		network_type |= WIRELESS_11A;
+	} else {
+		if (pmlmeinfo->HT_enable)
+			network_type = WIRELESS_11_24N;
+
+		if ((cckratesonly_included(rate, ratelen)) == true)
+			network_type |= WIRELESS_11B;
+		else if ((cckrates_included(rate, ratelen)) == true)
+			network_type |= WIRELESS_11BG;
+		else
+			network_type |= WIRELESS_11G;
+	}
+
+	pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode;
+
+	SIFS_Timer = 0x0a0a0808;/* 0x0808 -> for CCK, 0x0a0a -> for OFDM */
+				/* change this value if having IOT issues. */
+
+	padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS,  (u8 *)&SIFS_Timer);
+
+	if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+		update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB);
+	 else
+		update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB);
+}
+
+void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id)
+{
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
+		/*  Only B, B/G, and B/G/N AP could use CCK rate */
+		memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4);
+	} else {
+		memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 3);
+	}
+}
+
+int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx)
+{
+	unsigned int	ie_len;
+	struct ndis_802_11_var_ie *pIE;
+	int	supportRateNum = 0;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
+	if (pIE == NULL)
+		return _FAIL;
+
+	memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len);
+	supportRateNum = ie_len;
+
+	pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
+	if (pIE)
+		memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len);
+
+	return _SUCCESS;
+}
+
+void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr)
+{
+	struct sta_info *psta;
+	u16 tid;
+	u16 param;
+	struct recv_reorder_ctrl *preorder_ctrl;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct ADDBA_request	*preq = (struct ADDBA_request *)paddba_req;
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	psta = rtw_get_stainfo(pstapriv, addr);
+
+	if (psta) {
+		param = le16_to_cpu(preq->BA_para_set);
+		tid = (param>>2)&0x0f;
+		preorder_ctrl = &psta->recvreorder_ctrl[tid];
+		preorder_ctrl->indicate_seq = 0xffff;
+		preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq) ? true : false;
+	}
+}
+
+void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len)
+{
+	u8 *pIE;
+	__le32 *pbuf;
+
+	pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr);
+	pbuf = (__le32 *)pIE;
+
+	pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1));
+
+	pmlmeext->TSFValue = pmlmeext->TSFValue << 32;
+
+	pmlmeext->TSFValue |= le32_to_cpu(*pbuf);
+}
+
+void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext)
+{
+	rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, NULL);
+}
+
+void beacon_timing_control(struct adapter *padapter)
+{
+	rtw_hal_bcn_related_reg_setting(padapter);
+}
+
+static struct adapter *pbuddy_padapter;
+
+int rtw_handle_dualmac(struct adapter *adapter, bool init)
+{
+	int status = _SUCCESS;
+
+	if (init) {
+		if (pbuddy_padapter == NULL) {
+			pbuddy_padapter = adapter;
+			DBG_88E("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n", __func__);
+		} else {
+			adapter->pbuddy_adapter = pbuddy_padapter;
+			pbuddy_padapter->pbuddy_adapter = adapter;
+			/*  clear global value */
+			pbuddy_padapter = NULL;
+			DBG_88E("%s(): pbuddy_padapter exist, Exchange Information\n", __func__);
+		}
+	} else {
+		pbuddy_padapter = NULL;
+	}
+	return status;
+}
diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c
new file mode 100644
index 0000000..bb5cd95
--- /dev/null
+++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c
@@ -0,0 +1,2447 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTW_XMIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+#include <ip.h>
+#include <usb_ops.h>
+#include <usb_osintf.h>
+
+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+
+static void _init_txservq(struct tx_servq *ptxservq)
+{
+_func_enter_;
+	_rtw_init_listhead(&ptxservq->tx_pending);
+	_rtw_init_queue(&ptxservq->sta_pending);
+	ptxservq->qcnt = 0;
+_func_exit_;
+}
+
+void	_rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv)
+{
+_func_enter_;
+	_rtw_memset((unsigned char *)psta_xmitpriv, 0, sizeof (struct sta_xmit_priv));
+	_rtw_spinlock_init(&psta_xmitpriv->lock);
+	_init_txservq(&psta_xmitpriv->be_q);
+	_init_txservq(&psta_xmitpriv->bk_q);
+	_init_txservq(&psta_xmitpriv->vi_q);
+	_init_txservq(&psta_xmitpriv->vo_q);
+	_rtw_init_listhead(&psta_xmitpriv->legacy_dz);
+	_rtw_init_listhead(&psta_xmitpriv->apsd);
+
+_func_exit_;
+}
+
+s32	_rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter)
+{
+	int i;
+	struct xmit_buf *pxmitbuf;
+	struct xmit_frame *pxframe;
+	int	res = _SUCCESS;
+	u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+	u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+
+_func_enter_;
+
+	/*  We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+
+	_rtw_spinlock_init(&pxmitpriv->lock);
+	_rtw_init_sema(&pxmitpriv->xmit_sema, 0);
+	_rtw_init_sema(&pxmitpriv->terminate_xmitthread_sema, 0);
+
+	/*
+	Please insert all the queue initializaiton using _rtw_init_queue below
+	*/
+
+	pxmitpriv->adapter = padapter;
+
+	_rtw_init_queue(&pxmitpriv->be_pending);
+	_rtw_init_queue(&pxmitpriv->bk_pending);
+	_rtw_init_queue(&pxmitpriv->vi_pending);
+	_rtw_init_queue(&pxmitpriv->vo_pending);
+	_rtw_init_queue(&pxmitpriv->bm_pending);
+
+	_rtw_init_queue(&pxmitpriv->free_xmit_queue);
+
+	/*
+	Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME,
+	and initialize free_xmit_frame below.
+	Please also apply  free_txobj to link_up all the xmit_frames...
+	*/
+
+	pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+
+	if (pxmitpriv->pallocated_frame_buf  == NULL) {
+		pxmitpriv->pxmit_frame_buf = NULL;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n"));
+		res = _FAIL;
+		goto exit;
+	}
+	pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_frame_buf), 4);
+	/* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */
+	/* 						((size_t) (pxmitpriv->pallocated_frame_buf) &3); */
+
+	pxframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf;
+
+	for (i = 0; i < NR_XMITFRAME; i++) {
+		_rtw_init_listhead(&(pxframe->list));
+
+		pxframe->padapter = padapter;
+		pxframe->frame_tag = NULL_FRAMETAG;
+
+		pxframe->pkt = NULL;
+
+		pxframe->buf_addr = NULL;
+		pxframe->pxmitbuf = NULL;
+
+		rtw_list_insert_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue));
+
+		pxframe++;
+	}
+
+	pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME;
+
+	pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
+
+	/* init xmit_buf */
+	_rtw_init_queue(&pxmitpriv->free_xmitbuf_queue);
+	_rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue);
+
+	pxmitpriv->pallocated_xmitbuf = rtw_zvmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
+
+	if (pxmitpriv->pallocated_xmitbuf  == NULL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_buf fail!\n"));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmitbuf), 4);
+	/* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */
+	/* 						((size_t) (pxmitpriv->pallocated_xmitbuf) &3); */
+
+	pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
+
+	for (i = 0; i < NR_XMITBUFF; i++) {
+		_rtw_init_listhead(&pxmitbuf->list);
+
+		pxmitbuf->priv_data = NULL;
+		pxmitbuf->padapter = padapter;
+		pxmitbuf->ext_tag = false;
+
+		/* Tx buf allocation may fail sometimes, so sleep and retry. */
+		res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+		if (res == _FAIL) {
+			rtw_msleep_os(10);
+			res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+			if (res == _FAIL) {
+				goto exit;
+			}
+		}
+
+		pxmitbuf->flags = XMIT_VO_QUEUE;
+
+		rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue));
+		pxmitbuf++;
+	}
+
+	pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
+
+	/*  Init xmit extension buff */
+	_rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue);
+
+	pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+
+	if (pxmitpriv->pallocated_xmit_extbuf  == NULL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_extbuf fail!\n"));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4);
+
+	pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+
+	for (i = 0; i < num_xmit_extbuf; i++) {
+		_rtw_init_listhead(&pxmitbuf->list);
+
+		pxmitbuf->priv_data = NULL;
+		pxmitbuf->padapter = padapter;
+		pxmitbuf->ext_tag = true;
+
+		res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ);
+		if (res == _FAIL) {
+			res = _FAIL;
+			goto exit;
+		}
+
+		rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue));
+		pxmitbuf++;
+	}
+
+	pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf;
+
+	rtw_alloc_hwxmits(padapter);
+	rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+
+	for (i = 0; i < 4; i++)
+		pxmitpriv->wmm_para_seq[i] = i;
+
+	pxmitpriv->txirp_cnt = 1;
+
+	_rtw_init_sema(&(pxmitpriv->tx_retevt), 0);
+
+	/* per AC pending irp */
+	pxmitpriv->beq_cnt = 0;
+	pxmitpriv->bkq_cnt = 0;
+	pxmitpriv->viq_cnt = 0;
+	pxmitpriv->voq_cnt = 0;
+
+	pxmitpriv->ack_tx = false;
+	_rtw_mutex_init(&pxmitpriv->ack_tx_mutex);
+	rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0);
+
+	rtw_hal_init_xmit_priv(padapter);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static void  rtw_mfree_xmit_priv_lock (struct xmit_priv *pxmitpriv)
+{
+	_rtw_spinlock_free(&pxmitpriv->lock);
+	_rtw_free_sema(&pxmitpriv->xmit_sema);
+	_rtw_free_sema(&pxmitpriv->terminate_xmitthread_sema);
+
+	_rtw_spinlock_free(&pxmitpriv->be_pending.lock);
+	_rtw_spinlock_free(&pxmitpriv->bk_pending.lock);
+	_rtw_spinlock_free(&pxmitpriv->vi_pending.lock);
+	_rtw_spinlock_free(&pxmitpriv->vo_pending.lock);
+	_rtw_spinlock_free(&pxmitpriv->bm_pending.lock);
+
+	_rtw_spinlock_free(&pxmitpriv->free_xmit_queue.lock);
+	_rtw_spinlock_free(&pxmitpriv->free_xmitbuf_queue.lock);
+	_rtw_spinlock_free(&pxmitpriv->pending_xmitbuf_queue.lock);
+}
+
+void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv)
+{
+	int i;
+	struct adapter *padapter = pxmitpriv->adapter;
+	struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf;
+	struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
+	u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+	u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+
+ _func_enter_;
+
+	rtw_hal_free_xmit_priv(padapter);
+
+	rtw_mfree_xmit_priv_lock(pxmitpriv);
+
+	if (pxmitpriv->pxmit_frame_buf == NULL)
+		goto out;
+
+	for (i = 0; i < NR_XMITFRAME; i++) {
+		rtw_os_xmit_complete(padapter, pxmitframe);
+
+		pxmitframe++;
+	}
+
+	for (i = 0; i < NR_XMITBUFF; i++) {
+		rtw_os_xmit_resource_free(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+		pxmitbuf++;
+	}
+
+	if (pxmitpriv->pallocated_frame_buf)
+		rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+
+	if (pxmitpriv->pallocated_xmitbuf)
+		rtw_vmfree(pxmitpriv->pallocated_xmitbuf, NR_XMITBUFF * sizeof(struct xmit_buf) + 4);
+
+	/*  free xmit extension buff */
+	_rtw_spinlock_free(&pxmitpriv->free_xmit_extbuf_queue.lock);
+
+	pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf;
+	for (i = 0; i < num_xmit_extbuf; i++) {
+		rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ));
+		pxmitbuf++;
+	}
+
+	if (pxmitpriv->pallocated_xmit_extbuf) {
+		rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4);
+	}
+
+	rtw_free_hwxmits(padapter);
+
+	_rtw_mutex_free(&pxmitpriv->ack_tx_mutex);
+
+out:
+
+_func_exit_;
+}
+
+static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	u32	sz;
+	struct pkt_attrib	*pattrib = &pxmitframe->attrib;
+	struct sta_info	*psta = pattrib->psta;
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if (pattrib->nr_frags != 1)
+		sz = padapter->xmitpriv.frag_len;
+	else /* no frag */
+		sz = pattrib->last_txcmdsz;
+
+	/*  (1) RTS_Threshold is compared to the MPDU, not MSDU. */
+	/*  (2) If there are more than one frag in  this MSDU, only the first frag uses protection frame. */
+	/* 		Other fragments are protected by previous fragment. */
+	/* 		So we only need to check the length of first fragment. */
+	if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N  || padapter->registrypriv.wifi_spec) {
+		if (sz > padapter->registrypriv.rts_thresh) {
+			pattrib->vcs_mode = RTS_CTS;
+		} else {
+			if (psta->rtsen)
+				pattrib->vcs_mode = RTS_CTS;
+			else if (psta->cts2self)
+				pattrib->vcs_mode = CTS_TO_SELF;
+			else
+				pattrib->vcs_mode = NONE_VCS;
+		}
+	} else {
+		while (true) {
+			/* IOT action */
+			if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && pattrib->ampdu_en &&
+			    (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+				pattrib->vcs_mode = CTS_TO_SELF;
+				break;
+			}
+
+			/* check ERP protection */
+			if (psta->rtsen || psta->cts2self) {
+				if (psta->rtsen)
+					pattrib->vcs_mode = RTS_CTS;
+				else if (psta->cts2self)
+					pattrib->vcs_mode = CTS_TO_SELF;
+
+				break;
+			}
+
+			/* check HT op mode */
+			if (pattrib->ht_en) {
+				u8 htopmode = pmlmeinfo->HT_protection;
+				if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) ||
+				    (!pmlmeext->cur_bwmode && htopmode == 3)) {
+					pattrib->vcs_mode = RTS_CTS;
+					break;
+				}
+			}
+
+			/* check rts */
+			if (sz > padapter->registrypriv.rts_thresh) {
+				pattrib->vcs_mode = RTS_CTS;
+				break;
+			}
+
+			/* to do list: check MIMO power save condition. */
+
+			/* check AMPDU aggregation for TXOP */
+			if (pattrib->ampdu_en) {
+				pattrib->vcs_mode = RTS_CTS;
+				break;
+			}
+
+			pattrib->vcs_mode = NONE_VCS;
+			break;
+		}
+	}
+}
+
+static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta)
+{
+	/*if (psta->rtsen)
+		pattrib->vcs_mode = RTS_CTS;
+	else if (psta->cts2self)
+		pattrib->vcs_mode = CTS_TO_SELF;
+	else
+		pattrib->vcs_mode = NONE_VCS;*/
+
+	pattrib->mdata = 0;
+	pattrib->eosp = 0;
+	pattrib->triggered = 0;
+
+	/* qos_en, ht_en, init rate, , bw, ch_offset, sgi */
+	pattrib->qos_en = psta->qos_option;
+
+	pattrib->raid = psta->raid;
+	pattrib->ht_en = psta->htpriv.ht_option;
+	pattrib->bwmode = psta->htpriv.bwmode;
+	pattrib->ch_offset = psta->htpriv.ch_offset;
+	pattrib->sgi = psta->htpriv.sgi;
+	pattrib->ampdu_en = false;
+	pattrib->retry_ctrl = false;
+}
+
+u8	qos_acm(u8 acm_mask, u8 priority)
+{
+	u8	change_priority = priority;
+
+	switch (priority) {
+	case 0:
+	case 3:
+		if (acm_mask & BIT(1))
+			change_priority = 1;
+		break;
+	case 1:
+	case 2:
+		break;
+	case 4:
+	case 5:
+		if (acm_mask & BIT(2))
+			change_priority = 0;
+		break;
+	case 6:
+	case 7:
+		if (acm_mask & BIT(3))
+			change_priority = 5;
+		break;
+	default:
+		DBG_88E("qos_acm(): invalid pattrib->priority: %d!!!\n", priority);
+		break;
+	}
+
+	return change_priority;
+}
+
+static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
+{
+	struct ethhdr etherhdr;
+	struct iphdr ip_hdr;
+	s32 user_prio = 0;
+
+	_rtw_open_pktfile(ppktfile->pkt, ppktfile);
+	_rtw_pktfile_read(ppktfile, (unsigned char *)&etherhdr, ETH_HLEN);
+
+	/*  get user_prio from IP hdr */
+	if (pattrib->ether_type == 0x0800) {
+		_rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr));
+/* 		user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */
+		user_prio = ip_hdr.tos >> 5;
+	} else if (pattrib->ether_type == 0x888e) {
+		/*  "When priority processing of data frames is supported, */
+		/*  a STA's SME should send EAPOL-Key frames at the highest priority." */
+		user_prio = 7;
+	}
+
+	pattrib->priority = user_prio;
+	pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN;
+	pattrib->subtype = WIFI_QOS_DATA_TYPE;
+}
+
+static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib)
+{
+	struct pkt_file pktfile;
+	struct sta_info *psta = NULL;
+	struct ethhdr etherhdr;
+
+	int bmcast;
+	struct sta_priv		*pstapriv = &padapter->stapriv;
+	struct security_priv	*psecuritypriv = &padapter->securitypriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct qos_priv		*pqospriv = &pmlmepriv->qospriv;
+	int res = _SUCCESS;
+
+ _func_enter_;
+
+	_rtw_open_pktfile(pkt, &pktfile);
+	_rtw_pktfile_read(&pktfile, (u8 *)&etherhdr, ETH_HLEN);
+
+	pattrib->ether_type = ntohs(etherhdr.h_proto);
+
+	memcpy(pattrib->dst, &etherhdr.h_dest, ETH_ALEN);
+	memcpy(pattrib->src, &etherhdr.h_source, ETH_ALEN);
+
+	pattrib->pctrl = 0;
+
+	if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+	    check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+		memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+		memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+	} else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+		memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN);
+		memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+	} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+		memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN);
+	}
+
+	pattrib->pktlen = pktfile.pkt_len;
+
+	if (ETH_P_IP == pattrib->ether_type) {
+		/*  The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */
+		/*  to prevent DHCP protocol fail */
+		u8 tmp[24];
+		_rtw_pktfile_read(&pktfile, &tmp[0], 24);
+		pattrib->dhcp_pkt = 0;
+		if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
+			if (ETH_P_IP == pattrib->ether_type) {/*  IP header */
+				if (((tmp[21] == 68) && (tmp[23] == 67)) ||
+				    ((tmp[21] == 67) && (tmp[23] == 68))) {
+					/*  68 : UDP BOOTP client */
+					/*  67 : UDP BOOTP server */
+					RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== update_attrib: get DHCP Packet\n"));
+					/*  Use low rate to send DHCP packet. */
+					pattrib->dhcp_pkt = 1;
+				}
+			}
+		}
+	} else if (0x888e == pattrib->ether_type) {
+		DBG_88E_LEVEL(_drv_info_, "send eapol packet\n");
+	}
+
+	if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1))
+		rtw_set_scan_deny(padapter, 3000);
+
+	/*  If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */
+	if ((pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1))
+		rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1);
+
+	bmcast = IS_MCAST(pattrib->ra);
+
+	/*  get sta_info */
+	if (bmcast) {
+		psta = rtw_get_bcmc_stainfo(padapter);
+	} else {
+		psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+		if (psta == NULL) { /*  if we cannot get psta => drrp the pkt */
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra)));
+			res = _FAIL;
+			goto exit;
+		} else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) && (!(psta->state & _FW_LINKED))) {
+			res = _FAIL;
+			goto exit;
+		}
+	}
+
+	if (psta) {
+		pattrib->mac_id = psta->mac_id;
+		/* DBG_88E("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */
+		pattrib->psta = psta;
+	} else {
+		/*  if we cannot get psta => drop the pkt */
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", (pattrib->ra)));
+		res = _FAIL;
+		goto exit;
+	}
+
+	pattrib->ack_policy = 0;
+	/*  get ether_hdr_len */
+	pattrib->pkt_hdrlen = ETH_HLEN;/* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */
+
+	pattrib->hdrlen = WLAN_HDR_A3_LEN;
+	pattrib->subtype = WIFI_DATA_TYPE;
+	pattrib->priority = 0;
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
+		if (psta->qos_option)
+			set_qos(&pktfile, pattrib);
+	} else {
+		if (pqospriv->qos_option) {
+			set_qos(&pktfile, pattrib);
+
+			if (pmlmepriv->acm_mask != 0)
+				pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority);
+		}
+	}
+
+	if (psta->ieee8021x_blocked) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\n psta->ieee8021x_blocked == true\n"));
+
+		pattrib->encrypt = 0;
+
+		if ((pattrib->ether_type != 0x888e) && !check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true,  pattrib->ether_type(%.4x) != 0x888e\n", pattrib->ether_type));
+			res = _FAIL;
+			goto exit;
+		}
+	} else {
+		GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
+
+		switch (psecuritypriv->dot11AuthAlgrthm) {
+		case dot11AuthAlgrthm_Open:
+		case dot11AuthAlgrthm_Shared:
+		case dot11AuthAlgrthm_Auto:
+			pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex;
+			break;
+		case dot11AuthAlgrthm_8021X:
+			if (bmcast)
+				pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid;
+			else
+				pattrib->key_idx = 0;
+			break;
+		default:
+			pattrib->key_idx = 0;
+			break;
+		}
+	}
+
+	switch (pattrib->encrypt) {
+	case _WEP40_:
+	case _WEP104_:
+		pattrib->iv_len = 4;
+		pattrib->icv_len = 4;
+		break;
+	case _TKIP_:
+		pattrib->iv_len = 8;
+		pattrib->icv_len = 4;
+
+		if (padapter->securitypriv.busetkipkey == _FAIL) {
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+				 ("\npadapter->securitypriv.busetkipkey(%d) == _FAIL drop packet\n",
+				 padapter->securitypriv.busetkipkey));
+			res = _FAIL;
+			goto exit;
+		}
+		break;
+	case _AES_:
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("pattrib->encrypt=%d (_AES_)\n", pattrib->encrypt));
+		pattrib->iv_len = 8;
+		pattrib->icv_len = 8;
+		break;
+	default:
+		pattrib->iv_len = 0;
+		pattrib->icv_len = 0;
+		break;
+	}
+
+	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+		 ("update_attrib: encrypt=%d  securitypriv.sw_encrypt=%d\n",
+		  pattrib->encrypt, padapter->securitypriv.sw_encrypt));
+
+	if (pattrib->encrypt &&
+	    (padapter->securitypriv.sw_encrypt || !psecuritypriv->hw_decrypted)) {
+		pattrib->bswenc = true;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+			 ("update_attrib: encrypt=%d securitypriv.hw_decrypted=%d bswenc = true\n",
+			  pattrib->encrypt, padapter->securitypriv.sw_encrypt));
+	} else {
+		pattrib->bswenc = false;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc = false\n"));
+	}
+
+	rtw_set_tx_chksum_offload(pkt, pattrib);
+
+	update_attrib_phy_info(pattrib, psta);
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	int curfragnum, length;
+	u8	*pframe, *payload, mic[8];
+	struct	mic_data micdata;
+	struct	sta_info *stainfo;
+	struct	pkt_attrib *pattrib = &pxmitframe->attrib;
+	struct	security_priv	*psecuritypriv = &padapter->securitypriv;
+	struct	xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
+	u8 hw_hdr_offset = 0;
+	int bmcst = IS_MCAST(pattrib->ra);
+
+	if (pattrib->psta)
+		stainfo = pattrib->psta;
+	else
+		stainfo = rtw_get_stainfo(&padapter->stapriv , &pattrib->ra[0]);
+
+_func_enter_;
+
+	hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);;
+
+	if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */
+		/* encode mic code */
+		if (stainfo != NULL) {
+			u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+					   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+					   0x0, 0x0};
+
+			pframe = pxmitframe->buf_addr + hw_hdr_offset;
+
+			if (bmcst) {
+				if (_rtw_memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16))
+					return _FAIL;
+				/* start to calculate the mic code */
+				rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey);
+			} else {
+				if (_rtw_memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16) == true) {
+					/* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey == 0\n"); */
+					/* rtw_msleep_os(10); */
+					return _FAIL;
+				}
+				/* start to calculate the mic code */
+				rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]);
+			}
+
+			if (pframe[1]&1) {   /* ToDS == 1 */
+				rtw_secmicappend(&micdata, &pframe[16], 6);  /* DA */
+				if (pframe[1]&2)  /* From Ds == 1 */
+					rtw_secmicappend(&micdata, &pframe[24], 6);
+				else
+				rtw_secmicappend(&micdata, &pframe[10], 6);
+			} else {	/* ToDS == 0 */
+				rtw_secmicappend(&micdata, &pframe[4], 6);   /* DA */
+				if (pframe[1]&2)  /* From Ds == 1 */
+					rtw_secmicappend(&micdata, &pframe[16], 6);
+				else
+					rtw_secmicappend(&micdata, &pframe[10], 6);
+			}
+
+			if (pattrib->qos_en)
+				priority[0] = (u8)pxmitframe->attrib.priority;
+
+			rtw_secmicappend(&micdata, &priority[0], 4);
+
+			payload = pframe;
+
+			for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+				payload = (u8 *)RND4((size_t)(payload));
+				RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+					 ("=== curfragnum=%d, pframe = 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x,!!!\n",
+					 curfragnum, *payload, *(payload+1),
+					 *(payload+2), *(payload+3),
+					 *(payload+4), *(payload+5),
+					 *(payload+6), *(payload+7)));
+
+				payload = payload+pattrib->hdrlen+pattrib->iv_len;
+				RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+					 ("curfragnum=%d pattrib->hdrlen=%d pattrib->iv_len=%d",
+					 curfragnum, pattrib->hdrlen, pattrib->iv_len));
+				if ((curfragnum+1) == pattrib->nr_frags) {
+					length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0);
+					rtw_secmicappend(&micdata, payload, length);
+					payload = payload+length;
+				} else {
+					length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-((pattrib->bswenc) ? pattrib->icv_len : 0);
+					rtw_secmicappend(&micdata, payload, length);
+					payload = payload+length+pattrib->icv_len;
+					RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum=%d length=%d pattrib->icv_len=%d", curfragnum, length, pattrib->icv_len));
+				}
+			}
+			rtw_secgetmic(&micdata, &(mic[0]));
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n"));
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz=%d!!!\n", pattrib->last_txcmdsz));
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\
+  mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n",
+				mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7]));
+			/* add mic code  and add the mic code length in last_txcmdsz */
+
+			memcpy(payload, &(mic[0]), 8);
+			pattrib->last_txcmdsz += 8;
+
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ======== last pkt ========\n"));
+			payload = payload-pattrib->last_txcmdsz+8;
+			for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz; curfragnum = curfragnum+8)
+					RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+						 (" %.2x,  %.2x,  %.2x,  %.2x,  %.2x,  %.2x,  %.2x,  %.2x ",
+						 *(payload+curfragnum), *(payload+curfragnum+1),
+						 *(payload+curfragnum+2), *(payload+curfragnum+3),
+						 *(payload+curfragnum+4), *(payload+curfragnum+5),
+						 *(payload+curfragnum+6), *(payload+curfragnum+7)));
+			} else {
+				RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: rtw_get_stainfo==NULL!!!\n"));
+			}
+	}
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	struct	pkt_attrib	 *pattrib = &pxmitframe->attrib;
+
+_func_enter_;
+
+	if (pattrib->bswenc) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n"));
+		switch (pattrib->encrypt) {
+		case _WEP40_:
+		case _WEP104_:
+			rtw_wep_encrypt(padapter, (u8 *)pxmitframe);
+			break;
+		case _TKIP_:
+			rtw_tkip_encrypt(padapter, (u8 *)pxmitframe);
+			break;
+		case _AES_:
+			rtw_aes_encrypt(padapter, (u8 *)pxmitframe);
+			break;
+		default:
+			break;
+		}
+	} else {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n"));
+	}
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+s32 rtw_make_wlanhdr (struct adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib)
+{
+	u16 *qc;
+
+	struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+	u8 qos_option = false;
+
+	int res = _SUCCESS;
+	u16 *fctrl = &pwlanhdr->frame_ctl;
+
+	struct sta_info *psta;
+
+	int bmcst = IS_MCAST(pattrib->ra);
+
+_func_enter_;
+
+	if (pattrib->psta) {
+		psta = pattrib->psta;
+	} else {
+		if (bmcst) {
+			psta = rtw_get_bcmc_stainfo(padapter);
+		} else {
+			psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+		}
+	}
+
+	_rtw_memset(hdr, 0, WLANHDR_OFFSET);
+
+	SetFrameSubType(fctrl, pattrib->subtype);
+
+	if (pattrib->subtype & WIFI_DATA_TYPE) {
+		if ((check_fwstate(pmlmepriv,  WIFI_STATION_STATE) == true)) {
+			/* to_ds = 1, fr_ds = 0; */
+			/* Data transfer to AP */
+			SetToDs(fctrl);
+			memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN);
+			memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+			memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN);
+
+			if (pqospriv->qos_option)
+				qos_option = true;
+		} else if (check_fwstate(pmlmepriv,  WIFI_AP_STATE)) {
+			/* to_ds = 0, fr_ds = 1; */
+			SetFrDs(fctrl);
+			memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+			memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
+			memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
+
+			if (psta->qos_option)
+				qos_option = true;
+		} else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+			   check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+			memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+			memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+			memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
+
+			if (psta->qos_option)
+				qos_option = true;
+		} else {
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
+			res = _FAIL;
+			goto exit;
+		}
+
+		if (pattrib->mdata)
+			SetMData(fctrl);
+
+		if (pattrib->encrypt)
+			SetPrivacy(fctrl);
+
+		if (qos_option) {
+			qc = (unsigned short *)(hdr + pattrib->hdrlen - 2);
+
+			if (pattrib->priority)
+				SetPriority(qc, pattrib->priority);
+
+			SetEOSP(qc, pattrib->eosp);
+
+			SetAckpolicy(qc, pattrib->ack_policy);
+		}
+
+		/* TODO: fill HT Control Field */
+
+		/* Update Seq Num will be handled by f/w */
+		if (psta) {
+			psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
+			psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
+
+			pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
+
+			SetSeqNum(hdr, pattrib->seqnum);
+
+			/* check if enable ampdu */
+			if (pattrib->ht_en && psta->htpriv.ampdu_enable) {
+				if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority))
+				pattrib->ampdu_en = true;
+			}
+
+			/* re-check if enable ampdu by BA_starting_seqctrl */
+			if (pattrib->ampdu_en) {
+				u16 tx_seq;
+
+				tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f];
+
+				/* check BA_starting_seqctrl */
+				if (SN_LESS(pattrib->seqnum, tx_seq)) {
+					pattrib->ampdu_en = false;/* AGG BK */
+				} else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
+					psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff;
+
+					pattrib->ampdu_en = true;/* AGG EN */
+				} else {
+					psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff;
+					pattrib->ampdu_en = true;/* AGG EN */
+				}
+			}
+		}
+	}
+exit:
+
+_func_exit_;
+	return res;
+}
+
+s32 rtw_txframes_pending(struct adapter *padapter)
+{
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+	return ((_rtw_queue_empty(&pxmitpriv->be_pending) == false) ||
+			 (_rtw_queue_empty(&pxmitpriv->bk_pending) == false) ||
+			 (_rtw_queue_empty(&pxmitpriv->vi_pending) == false) ||
+			 (_rtw_queue_empty(&pxmitpriv->vo_pending) == false));
+}
+
+s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib)
+{
+	struct sta_info *psta;
+	struct tx_servq *ptxservq;
+	int priority = pattrib->priority;
+
+	psta = pattrib->psta;
+
+	switch (priority) {
+	case 1:
+	case 2:
+		ptxservq = &(psta->sta_xmitpriv.bk_q);
+		break;
+	case 4:
+	case 5:
+		ptxservq = &(psta->sta_xmitpriv.vi_q);
+		break;
+	case 6:
+	case 7:
+		ptxservq = &(psta->sta_xmitpriv.vo_q);
+		break;
+	case 0:
+	case 3:
+	default:
+		ptxservq = &(psta->sta_xmitpriv.be_q);
+		break;
+	}
+
+	return ptxservq->qcnt;
+}
+
+/*
+ * Calculate wlan 802.11 packet MAX size from pkt_attrib
+ * This function doesn't consider fragment case
+ */
+u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib)
+{
+	u32	len = 0;
+
+	len = pattrib->hdrlen + pattrib->iv_len; /*  WLAN Header and IV */
+	len += SNAP_SIZE + sizeof(u16); /*  LLC */
+	len += pattrib->pktlen;
+	if (pattrib->encrypt == _TKIP_)
+		len += 8; /*  MIC */
+	len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /*  ICV */
+
+	return len;
+}
+
+/*
+
+This sub-routine will perform all the following:
+
+1. remove 802.3 header.
+2. create wlan_header, based on the info in pxmitframe
+3. append sta's iv/ext-iv
+4. append LLC
+5. move frag chunk from pframe to pxmitframe->mem
+6. apply sw-encrypt, if necessary.
+
+*/
+s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe)
+{
+	struct pkt_file pktfile;
+	s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz;
+	size_t addr;
+	u8 *pframe, *mem_start;
+	u8 hw_hdr_offset;
+	struct sta_info		*psta;
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	struct pkt_attrib	*pattrib = &pxmitframe->attrib;
+	u8 *pbuf_start;
+	s32 bmcst = IS_MCAST(pattrib->ra);
+	s32 res = _SUCCESS;
+
+_func_enter_;
+
+	psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra);
+
+	if (psta == NULL)
+		return _FAIL;
+
+	if (pxmitframe->buf_addr == NULL) {
+		DBG_88E("==> %s buf_addr == NULL\n", __func__);
+		return _FAIL;
+	}
+
+	pbuf_start = pxmitframe->buf_addr;
+
+	hw_hdr_offset =  TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);
+
+	mem_start = pbuf_start +	hw_hdr_offset;
+
+	if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"));
+		DBG_88E("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n");
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_open_pktfile(pkt, &pktfile);
+	_rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen);
+
+	frg_inx = 0;
+	frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */
+
+	while (1) {
+		llc_sz = 0;
+
+		mpdu_len = frg_len;
+
+		pframe = mem_start;
+
+		SetMFrag(mem_start);
+
+		pframe += pattrib->hdrlen;
+		mpdu_len -= pattrib->hdrlen;
+
+		/* adding icv, if necessary... */
+		if (pattrib->iv_len) {
+			if (psta != NULL) {
+				switch (pattrib->encrypt) {
+				case _WEP40_:
+				case _WEP104_:
+					WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+					break;
+				case _TKIP_:
+					if (bmcst)
+						TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+					else
+						TKIP_IV(pattrib->iv, psta->dot11txpn, 0);
+					break;
+				case _AES_:
+					if (bmcst)
+						AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+					else
+						AES_IV(pattrib->iv, psta->dot11txpn, 0);
+					break;
+				}
+			}
+
+			memcpy(pframe, pattrib->iv, pattrib->iv_len);
+
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
+				 ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n",
+				  padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3)));
+
+			pframe += pattrib->iv_len;
+
+			mpdu_len -= pattrib->iv_len;
+		}
+
+		if (frg_inx == 0) {
+			llc_sz = rtw_put_snap(pframe, pattrib->ether_type);
+			pframe += llc_sz;
+			mpdu_len -= llc_sz;
+		}
+
+		if ((pattrib->icv_len > 0) && (pattrib->bswenc)) {
+			mpdu_len -= pattrib->icv_len;
+		}
+
+		if (bmcst) {
+			/*  don't do fragment to broadcat/multicast packets */
+			mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen);
+		} else {
+			mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len);
+		}
+
+		pframe += mem_sz;
+
+		if ((pattrib->icv_len > 0) && (pattrib->bswenc)) {
+			memcpy(pframe, pattrib->icv, pattrib->icv_len);
+			pframe += pattrib->icv_len;
+		}
+
+		frg_inx++;
+
+		if (bmcst || rtw_endofpktfile(&pktfile)) {
+			pattrib->nr_frags = frg_inx;
+
+			pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) +
+						((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz;
+
+			ClearMFrag(mem_start);
+
+			break;
+		} else {
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__));
+		}
+
+		addr = (size_t)(pframe);
+
+		mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset;
+		memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen);
+	}
+
+	if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"));
+		DBG_88E("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n");
+		res = _FAIL;
+		goto exit;
+	}
+
+	xmitframe_swencrypt(padapter, pxmitframe);
+
+	if (!bmcst)
+		update_attrib_vcs_info(padapter, pxmitframe);
+	else
+		pattrib->vcs_mode = NONE_VCS;
+
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header
+ * IEEE LLC/SNAP header contains 8 octets
+ * First 3 octets comprise the LLC portion
+ * SNAP portion, 5 octets, is divided into two fields:
+ *	Organizationally Unique Identifier(OUI), 3 octets,
+ *	type, defined by that organization, 2 octets.
+ */
+s32 rtw_put_snap(u8 *data, u16 h_proto)
+{
+	struct ieee80211_snap_hdr *snap;
+	u8 *oui;
+
+_func_enter_;
+
+	snap = (struct ieee80211_snap_hdr *)data;
+	snap->dsap = 0xaa;
+	snap->ssap = 0xaa;
+	snap->ctrl = 0x03;
+
+	if (h_proto == 0x8137 || h_proto == 0x80f3)
+		oui = P802_1H_OUI;
+	else
+		oui = RFC1042_OUI;
+
+	snap->oui[0] = oui[0];
+	snap->oui[1] = oui[1];
+	snap->oui[2] = oui[2];
+
+	*(__be16 *)(data + SNAP_SIZE) = htons(h_proto);
+
+_func_exit_;
+
+	return SNAP_SIZE + sizeof(u16);
+}
+
+void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len)
+{
+	uint	protection;
+	u8	*perp;
+	int	 erp_len;
+	struct	xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct	registry_priv *pregistrypriv = &padapter->registrypriv;
+
+_func_enter_;
+
+	switch (pxmitpriv->vcs_setting) {
+	case DISABLE_VCS:
+		pxmitpriv->vcs = NONE_VCS;
+		break;
+	case ENABLE_VCS:
+		break;
+	case AUTO_VCS:
+	default:
+		perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len);
+		if (perp == NULL) {
+			pxmitpriv->vcs = NONE_VCS;
+		} else {
+			protection = (*(perp + 2)) & BIT(1);
+			if (protection) {
+				if (pregistrypriv->vcs_type == RTS_CTS)
+					pxmitpriv->vcs = RTS_CTS;
+				else
+					pxmitpriv->vcs = CTS_TO_SELF;
+			} else {
+				pxmitpriv->vcs = NONE_VCS;
+			}
+		}
+		break;
+	}
+
+_func_exit_;
+}
+
+void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz)
+{
+	struct sta_info *psta = NULL;
+	struct stainfo_stats *pstats = NULL;
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+
+	if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
+		pxmitpriv->tx_bytes += sz;
+		pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num;
+
+		psta = pxmitframe->attrib.psta;
+		if (psta) {
+			pstats = &psta->sta_stats;
+			pstats->tx_pkts += pxmitframe->agg_num;
+			pstats->tx_bytes += sz;
+		}
+	}
+}
+
+struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv)
+{
+	unsigned long irql;
+	struct xmit_buf *pxmitbuf =  NULL;
+	struct list_head *plist, *phead;
+	struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
+
+_func_enter_;
+
+	_enter_critical(&pfree_queue->lock, &irql);
+
+	if (_rtw_queue_empty(pfree_queue) == true) {
+		pxmitbuf = NULL;
+	} else {
+		phead = get_list_head(pfree_queue);
+
+		plist = get_next(phead);
+
+		pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+
+		rtw_list_delete(&(pxmitbuf->list));
+	}
+
+	if (pxmitbuf !=  NULL) {
+		pxmitpriv->free_xmit_extbuf_cnt--;
+
+		pxmitbuf->priv_data = NULL;
+		/* pxmitbuf->ext_tag = true; */
+
+		if (pxmitbuf->sctx) {
+			DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+			rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
+		}
+	}
+
+	_exit_critical(&pfree_queue->lock, &irql);
+
+_func_exit_;
+
+	return pxmitbuf;
+}
+
+s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+	unsigned long irql;
+	struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
+
+_func_enter_;
+
+	if (pxmitbuf == NULL)
+		return _FAIL;
+
+	_enter_critical(&pfree_queue->lock, &irql);
+
+	rtw_list_delete(&pxmitbuf->list);
+
+	rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_queue));
+	pxmitpriv->free_xmit_extbuf_cnt++;
+
+	_exit_critical(&pfree_queue->lock, &irql);
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv)
+{
+	unsigned long irql;
+	struct xmit_buf *pxmitbuf =  NULL;
+	struct list_head *plist, *phead;
+	struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
+
+_func_enter_;
+
+	/* DBG_88E("+rtw_alloc_xmitbuf\n"); */
+
+	_enter_critical(&pfree_xmitbuf_queue->lock, &irql);
+
+	if (_rtw_queue_empty(pfree_xmitbuf_queue) == true) {
+		pxmitbuf = NULL;
+	} else {
+		phead = get_list_head(pfree_xmitbuf_queue);
+
+		plist = get_next(phead);
+
+		pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
+
+		rtw_list_delete(&(pxmitbuf->list));
+	}
+
+	if (pxmitbuf !=  NULL) {
+		pxmitpriv->free_xmitbuf_cnt--;
+		pxmitbuf->priv_data = NULL;
+		if (pxmitbuf->sctx) {
+			DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+			rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
+		}
+	}
+	_exit_critical(&pfree_xmitbuf_queue->lock, &irql);
+
+_func_exit_;
+
+	return pxmitbuf;
+}
+
+s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+	unsigned long irql;
+	struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
+
+_func_enter_;
+	if (pxmitbuf == NULL)
+		return _FAIL;
+
+	if (pxmitbuf->sctx) {
+		DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__);
+		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE);
+	}
+
+	if (pxmitbuf->ext_tag) {
+		rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf);
+	} else {
+		_enter_critical(&pfree_xmitbuf_queue->lock, &irql);
+
+		rtw_list_delete(&pxmitbuf->list);
+
+		rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue));
+
+		pxmitpriv->free_xmitbuf_cnt++;
+		_exit_critical(&pfree_xmitbuf_queue->lock, &irql);
+	}
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+/*
+Calling context:
+1. OS_TXENTRY
+2. RXENTRY (rx_thread or RX_ISR/RX_CallBack)
+
+If we turn on USE_RXTHREAD, then, no need for critical section.
+Otherwise, we must use _enter/_exit critical to protect free_xmit_queue...
+
+Must be very very cautious...
+
+*/
+
+struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */
+{
+	/*
+		Please remember to use all the osdep_service api,
+		and lock/unlock or _enter/_exit critical to protect
+		pfree_xmit_queue
+	*/
+
+	unsigned long irql;
+	struct xmit_frame *pxframe = NULL;
+	struct list_head *plist, *phead;
+	struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
+
+_func_enter_;
+
+	_enter_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+	if (_rtw_queue_empty(pfree_xmit_queue) == true) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe:%d\n", pxmitpriv->free_xmitframe_cnt));
+		pxframe =  NULL;
+	} else {
+		phead = get_list_head(pfree_xmit_queue);
+
+		plist = get_next(phead);
+
+		pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+
+		rtw_list_delete(&(pxframe->list));
+	}
+
+	if (pxframe !=  NULL) { /* default value setting */
+		pxmitpriv->free_xmitframe_cnt--;
+
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt));
+
+		pxframe->buf_addr = NULL;
+		pxframe->pxmitbuf = NULL;
+
+		_rtw_memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
+		/* pxframe->attrib.psta = NULL; */
+
+		pxframe->frame_tag = DATA_FRAMETAG;
+
+		pxframe->pkt = NULL;
+		pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */
+
+		pxframe->agg_num = 1;
+		pxframe->ack_report = 0;
+	}
+
+	_exit_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+_func_exit_;
+
+	return pxframe;
+}
+
+s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe)
+{
+	unsigned long irql;
+	struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
+	struct adapter *padapter = pxmitpriv->adapter;
+	struct sk_buff *pndis_pkt = NULL;
+
+_func_enter_;
+
+	if (pxmitframe == NULL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n"));
+		goto exit;
+	}
+
+	_enter_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+	rtw_list_delete(&pxmitframe->list);
+
+	if (pxmitframe->pkt) {
+		pndis_pkt = pxmitframe->pkt;
+		pxmitframe->pkt = NULL;
+	}
+
+	rtw_list_insert_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue));
+
+	pxmitpriv->free_xmitframe_cnt++;
+	RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt));
+
+	_exit_critical_bh(&pfree_xmit_queue->lock, &irql);
+
+	if (pndis_pkt)
+		rtw_os_pkt_complete(padapter, pndis_pkt);
+
+exit:
+
+_func_exit_;
+
+	return _SUCCESS;
+}
+
+void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue)
+{
+	unsigned long irql;
+	struct list_head *plist, *phead;
+	struct	xmit_frame	*pxmitframe;
+
+_func_enter_;
+
+	_enter_critical_bh(&(pframequeue->lock), &irql);
+
+	phead = get_list_head(pframequeue);
+	plist = get_next(phead);
+
+	while (!rtw_end_of_queue_search(phead, plist)) {
+		pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+
+		plist = get_next(plist);
+
+		rtw_free_xmitframe(pxmitpriv, pxmitframe);
+	}
+	_exit_critical_bh(&(pframequeue->lock), &irql);
+
+_func_exit_;
+}
+
+s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) {
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+			 ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n"));
+/* 		pxmitframe->pkt = NULL; */
+		return _FAIL;
+	}
+
+	return _SUCCESS;
+}
+
+static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, struct __queue *pframe_queue)
+{
+	struct list_head *xmitframe_plist, *xmitframe_phead;
+	struct	xmit_frame	*pxmitframe = NULL;
+
+	xmitframe_phead = get_list_head(pframe_queue);
+	xmitframe_plist = get_next(xmitframe_phead);
+
+	while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+		pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+		xmitframe_plist = get_next(xmitframe_plist);
+
+		rtw_list_delete(&pxmitframe->list);
+
+		ptxservq->qcnt--;
+
+		break;
+
+		pxmitframe = NULL;
+	}
+
+	return pxmitframe;
+}
+
+struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, int entry)
+{
+	unsigned long irql0;
+	struct list_head *sta_plist, *sta_phead;
+	struct hw_xmit *phwxmit;
+	struct tx_servq *ptxservq = NULL;
+	struct __queue *pframe_queue = NULL;
+	struct xmit_frame *pxmitframe = NULL;
+	struct adapter *padapter = pxmitpriv->adapter;
+	struct registry_priv	*pregpriv = &padapter->registrypriv;
+	int i, inx[4];
+
+_func_enter_;
+
+	inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+
+	if (pregpriv->wifi_spec == 1) {
+		int j;
+
+		for (j = 0; j < 4; j++)
+			inx[j] = pxmitpriv->wmm_para_seq[j];
+	}
+
+	_enter_critical_bh(&pxmitpriv->lock, &irql0);
+
+	for (i = 0; i < entry; i++) {
+		phwxmit = phwxmit_i + inx[i];
+
+		sta_phead = get_list_head(phwxmit->sta_queue);
+		sta_plist = get_next(sta_phead);
+
+		while (!rtw_end_of_queue_search(sta_phead, sta_plist)) {
+			ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
+
+			pframe_queue = &ptxservq->sta_pending;
+
+			pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue);
+
+			if (pxmitframe) {
+				phwxmit->accnt--;
+
+				/* Remove sta node when there are no pending packets. */
+				if (_rtw_queue_empty(pframe_queue)) /* must be done after get_next and before break */
+					rtw_list_delete(&ptxservq->tx_pending);
+				goto exit;
+			}
+
+			sta_plist = get_next(sta_plist);
+		}
+	}
+exit:
+	_exit_critical_bh(&pxmitpriv->lock, &irql0);
+_func_exit_;
+	return pxmitframe;
+}
+
+struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, int up, u8 *ac)
+{
+	struct tx_servq *ptxservq;
+
+_func_enter_;
+	switch (up) {
+	case 1:
+	case 2:
+		ptxservq = &(psta->sta_xmitpriv.bk_q);
+		*(ac) = 3;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n"));
+		break;
+	case 4:
+	case 5:
+		ptxservq = &(psta->sta_xmitpriv.vi_q);
+		*(ac) = 1;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n"));
+		break;
+	case 6:
+	case 7:
+		ptxservq = &(psta->sta_xmitpriv.vo_q);
+		*(ac) = 0;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n"));
+		break;
+	case 0:
+	case 3:
+	default:
+		ptxservq = &(psta->sta_xmitpriv.be_q);
+		*(ac) = 2;
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n"));
+	break;
+	}
+
+_func_exit_;
+
+	return ptxservq;
+}
+
+/*
+ * Will enqueue pxmitframe to the proper queue,
+ * and indicate it to xx_pending list.....
+ */
+s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	/* unsigned long irql0; */
+	u8	ac_index;
+	struct sta_info	*psta;
+	struct tx_servq	*ptxservq;
+	struct pkt_attrib	*pattrib = &pxmitframe->attrib;
+	struct sta_priv	*pstapriv = &padapter->stapriv;
+	struct hw_xmit	*phwxmits =  padapter->xmitpriv.hwxmits;
+	int res = _SUCCESS;
+
+_func_enter_;
+
+	if (pattrib->psta) {
+		psta = pattrib->psta;
+	} else {
+		psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+	}
+
+	if (psta == NULL) {
+		res = _FAIL;
+		DBG_88E("rtw_xmit_classifier: psta == NULL\n");
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n"));
+		goto exit;
+	}
+
+	ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
+
+	if (rtw_is_list_empty(&ptxservq->tx_pending))
+		rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue));
+
+	rtw_list_insert_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending));
+	ptxservq->qcnt++;
+	phwxmits[ac_index].accnt++;
+exit:
+
+_func_exit_;
+
+	return res;
+}
+
+void rtw_alloc_hwxmits(struct adapter *padapter)
+{
+	struct hw_xmit *hwxmits;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+	pxmitpriv->hwxmit_entry = HWXMIT_ENTRY;
+
+	pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry);
+
+	hwxmits = pxmitpriv->hwxmits;
+
+	if (pxmitpriv->hwxmit_entry == 5) {
+		hwxmits[0] .sta_queue = &pxmitpriv->bm_pending;
+		hwxmits[1] .sta_queue = &pxmitpriv->vo_pending;
+		hwxmits[2] .sta_queue = &pxmitpriv->vi_pending;
+		hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
+		hwxmits[4] .sta_queue = &pxmitpriv->be_pending;
+	} else if (pxmitpriv->hwxmit_entry == 4) {
+		hwxmits[0] .sta_queue = &pxmitpriv->vo_pending;
+		hwxmits[1] .sta_queue = &pxmitpriv->vi_pending;
+		hwxmits[2] .sta_queue = &pxmitpriv->be_pending;
+		hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
+	} else {
+	}
+}
+
+void rtw_free_hwxmits(struct adapter *padapter)
+{
+	struct hw_xmit *hwxmits;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+	hwxmits = pxmitpriv->hwxmits;
+	kfree(hwxmits);
+}
+
+void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry)
+{
+	int i;
+_func_enter_;
+	for (i = 0; i < entry; i++, phwxmit++)
+		phwxmit->accnt = 0;
+_func_exit_;
+}
+
+static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb)
+{
+	struct sk_buff *skb = *pskb;
+	unsigned long irql;
+	int res, is_vlan_tag = 0, i, do_nat25 = 1;
+	unsigned short vlan_hdr = 0;
+	void *br_port = NULL;
+
+	rcu_read_lock();
+	br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
+	rcu_read_unlock();
+	_enter_critical_bh(&padapter->br_ext_lock, &irql);
+	if (!(skb->data[0] & 1) && br_port &&
+	    memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) &&
+	    *((__be16 *)(skb->data+MACADDRLEN*2)) != __constant_htons(ETH_P_8021Q) &&
+	    *((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP) &&
+	    !memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN) && padapter->scdb_entry) {
+		memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN);
+		padapter->scdb_entry->ageing_timer = jiffies;
+		_exit_critical_bh(&padapter->br_ext_lock, &irql);
+	} else {
+		if (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_8021Q)) {
+			is_vlan_tag = 1;
+			vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2));
+			for (i = 0; i < 6; i++)
+				*((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2));
+			skb_pull(skb, 4);
+		}
+		if (!memcmp(skb->data+MACADDRLEN, padapter->br_mac, MACADDRLEN) &&
+		    (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP)))
+			memcpy(padapter->br_ip, skb->data+WLAN_ETHHDR_LEN+12, 4);
+
+		if (*((__be16 *)(skb->data+MACADDRLEN*2)) == __constant_htons(ETH_P_IP)) {
+			if (memcmp(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN)) {
+				padapter->scdb_entry = (struct nat25_network_db_entry *)scdb_findEntry(padapter,
+							skb->data+MACADDRLEN, skb->data+WLAN_ETHHDR_LEN+12);
+				if (padapter->scdb_entry) {
+					memcpy(padapter->scdb_mac, skb->data+MACADDRLEN, MACADDRLEN);
+					memcpy(padapter->scdb_ip, skb->data+WLAN_ETHHDR_LEN+12, 4);
+					padapter->scdb_entry->ageing_timer = jiffies;
+					do_nat25 = 0;
+				}
+			} else {
+				if (padapter->scdb_entry) {
+					padapter->scdb_entry->ageing_timer = jiffies;
+					do_nat25 = 0;
+				} else {
+					memset(padapter->scdb_mac, 0, MACADDRLEN);
+					memset(padapter->scdb_ip, 0, 4);
+				}
+			}
+		}
+		_exit_critical_bh(&padapter->br_ext_lock, &irql);
+		if (do_nat25) {
+			if (nat25_db_handle(padapter, skb, NAT25_CHECK) == 0) {
+				struct sk_buff *newskb;
+
+				if (is_vlan_tag) {
+					skb_push(skb, 4);
+					for (i = 0; i < 6; i++)
+						*((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+					*((__be16 *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q);
+					*((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr;
+				}
+
+				newskb = skb_copy(skb, GFP_ATOMIC);
+				if (newskb == NULL) {
+					DEBUG_ERR("TX DROP: skb_copy fail!\n");
+					return -1;
+				}
+				dev_kfree_skb_any(skb);
+
+				*pskb = skb = newskb;
+				if (is_vlan_tag) {
+					vlan_hdr = *((unsigned short *)(skb->data+MACADDRLEN*2+2));
+					for (i = 0; i < 6; i++)
+						*((unsigned short *)(skb->data+MACADDRLEN*2+2-i*2)) = *((unsigned short *)(skb->data+MACADDRLEN*2-2-i*2));
+					skb_pull(skb, 4);
+				}
+			}
+
+			if (skb_is_nonlinear(skb))
+				DEBUG_ERR("%s(): skb_is_nonlinear!!\n", __func__);
+
+			res = skb_linearize(skb);
+			if (res < 0) {
+					DEBUG_ERR("TX DROP: skb_linearize fail!\n");
+					return -1;
+			}
+
+			res = nat25_db_handle(padapter, skb, NAT25_INSERT);
+			if (res < 0) {
+				if (res == -2) {
+					DEBUG_ERR("TX DROP: nat25_db_handle fail!\n");
+					return -1;
+				}
+				return 0;
+			}
+		}
+
+		memcpy(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN);
+
+		dhcp_flag_bcast(padapter, skb);
+
+		if (is_vlan_tag) {
+			skb_push(skb, 4);
+			for (i = 0; i < 6; i++)
+				*((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
+			*((__be16 *)(skb->data+MACADDRLEN*2)) = __constant_htons(ETH_P_8021Q);
+			*((unsigned short *)(skb->data+MACADDRLEN*2+2)) = vlan_hdr;
+		}
+	}
+
+	/*  check if SA is equal to our MAC */
+	if (memcmp(skb->data+MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN)) {
+		DEBUG_ERR("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n",
+			  skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11]);
+			return -1;
+	}
+	return 0;
+}
+
+u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe)
+{
+	u32 addr;
+	struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+	switch (pattrib->qsel) {
+	case 0:
+	case 3:
+		addr = BE_QUEUE_INX;
+		break;
+	case 1:
+	case 2:
+		addr = BK_QUEUE_INX;
+		break;
+	case 4:
+	case 5:
+		addr = VI_QUEUE_INX;
+		break;
+	case 6:
+	case 7:
+		addr = VO_QUEUE_INX;
+		break;
+	case 0x10:
+		addr = BCN_QUEUE_INX;
+		break;
+	case 0x11:/* BC/MC in PS (HIQ) */
+		addr = HIGH_QUEUE_INX;
+		break;
+	case 0x12:
+	default:
+		addr = MGT_QUEUE_INX;
+		break;
+	}
+
+	return addr;
+}
+
+static void do_queue_select(struct adapter	*padapter, struct pkt_attrib *pattrib)
+{
+	u8 qsel;
+
+	qsel = pattrib->priority;
+	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("### do_queue_select priority=%d , qsel = %d\n", pattrib->priority , qsel));
+
+	pattrib->qsel = qsel;
+}
+
+/*
+ * The main transmit(tx) entry
+ *
+ * Return
+ *	1	enqueue
+ *	0	success, hardware will handle this xmit frame(packet)
+ *	<0	fail
+ */
+s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt)
+{
+#ifdef CONFIG_88EU_AP_MODE
+	unsigned long irql0;
+#endif
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct xmit_frame *pxmitframe = NULL;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	void *br_port = NULL;
+	s32 res;
+
+	pxmitframe = rtw_alloc_xmitframe(pxmitpriv);
+	if (pxmitframe == NULL) {
+		RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n"));
+		DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__);
+		return -1;
+	}
+
+	rcu_read_lock();
+	br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
+	rcu_read_unlock();
+
+	if (br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
+		res = rtw_br_client_tx(padapter, ppkt);
+		if (res == -1) {
+			rtw_free_xmitframe(pxmitpriv, pxmitframe);
+			return -1;
+		}
+	}
+
+	res = update_attrib(padapter, *ppkt, &pxmitframe->attrib);
+
+	if (res == _FAIL) {
+		RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n"));
+		rtw_free_xmitframe(pxmitpriv, pxmitframe);
+		return -1;
+	}
+	pxmitframe->pkt = *ppkt;
+
+	rtw_led_control(padapter, LED_CTL_TX);
+
+	do_queue_select(padapter, &pxmitframe->attrib);
+
+#ifdef CONFIG_88EU_AP_MODE
+	_enter_critical_bh(&pxmitpriv->lock, &irql0);
+	if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe)) {
+		_exit_critical_bh(&pxmitpriv->lock, &irql0);
+		return 1;
+	}
+	_exit_critical_bh(&pxmitpriv->lock, &irql0);
+#endif
+
+	if (rtw_hal_xmit(padapter, pxmitframe) == false)
+		return 1;
+
+	return 0;
+}
+
+#if defined(CONFIG_88EU_AP_MODE)
+
+int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe)
+{
+	unsigned long irql;
+	int ret = false;
+	struct sta_info *psta = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct pkt_attrib *pattrib = &pxmitframe->attrib;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	int bmcst = IS_MCAST(pattrib->ra);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false)
+	    return ret;
+
+	if (pattrib->psta)
+		psta = pattrib->psta;
+	else
+		psta = rtw_get_stainfo(pstapriv, pattrib->ra);
+
+	if (psta == NULL)
+		return ret;
+
+	if (pattrib->triggered == 1) {
+		if (bmcst)
+			pattrib->qsel = 0x11;/* HIQ */
+		return ret;
+	}
+
+	if (bmcst) {
+		_enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+		if (pstapriv->sta_dz_bitmap) {/* if any one sta is in ps mode */
+			rtw_list_delete(&pxmitframe->list);
+
+			rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
+
+			psta->sleepq_len++;
+
+			pstapriv->tim_bitmap |= BIT(0);/*  */
+			pstapriv->sta_dz_bitmap |= BIT(0);
+
+			update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */
+
+			ret = true;
+		}
+
+		_exit_critical_bh(&psta->sleep_q.lock, &irql);
+
+		return ret;
+	}
+
+	_enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+	if (psta->state&WIFI_SLEEP_STATE) {
+		u8 wmmps_ac = 0;
+
+		if (pstapriv->sta_dz_bitmap&BIT(psta->aid)) {
+			rtw_list_delete(&pxmitframe->list);
+
+			rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
+
+			psta->sleepq_len++;
+
+			switch (pattrib->priority) {
+			case 1:
+			case 2:
+				wmmps_ac = psta->uapsd_bk&BIT(0);
+				break;
+			case 4:
+			case 5:
+				wmmps_ac = psta->uapsd_vi&BIT(0);
+				break;
+			case 6:
+			case 7:
+				wmmps_ac = psta->uapsd_vo&BIT(0);
+				break;
+			case 0:
+			case 3:
+			default:
+				wmmps_ac = psta->uapsd_be&BIT(0);
+				break;
+			}
+
+			if (wmmps_ac)
+				psta->sleepq_ac_len++;
+
+			if (((psta->has_legacy_ac) && (!wmmps_ac)) ||
+			    ((!psta->has_legacy_ac) && (wmmps_ac))) {
+				pstapriv->tim_bitmap |= BIT(psta->aid);
+
+				if (psta->sleepq_len == 1) {
+					/* upate BCN for TIM IE */
+					update_beacon(padapter, _TIM_IE_, NULL, false);
+				}
+			}
+			ret = true;
+		}
+	}
+
+	_exit_critical_bh(&psta->sleep_q.lock, &irql);
+
+	return ret;
+}
+
+static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue)
+{
+	struct list_head *plist, *phead;
+	u8	ac_index;
+	struct tx_servq	*ptxservq;
+	struct pkt_attrib	*pattrib;
+	struct xmit_frame	*pxmitframe;
+	struct hw_xmit *phwxmits =  padapter->xmitpriv.hwxmits;
+
+	phead = get_list_head(pframequeue);
+	plist = get_next(phead);
+
+	while (!rtw_end_of_queue_search(phead, plist)) {
+		pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
+
+		plist = get_next(plist);
+
+		xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe);
+
+		pattrib = &pxmitframe->attrib;
+
+		ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
+
+		ptxservq->qcnt--;
+		phwxmits[ac_index].accnt--;
+	}
+}
+
+void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta)
+{
+	unsigned long irql0;
+	struct sta_info *psta_bmc;
+	struct sta_xmit_priv *pstaxmitpriv;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+	pstaxmitpriv = &psta->sta_xmitpriv;
+
+	/* for BC/MC Frames */
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+
+	_enter_critical_bh(&pxmitpriv->lock, &irql0);
+
+	psta->state |= WIFI_SLEEP_STATE;
+
+	pstapriv->sta_dz_bitmap |= BIT(psta->aid);
+
+	dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending);
+	rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending));
+
+	dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending);
+	rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending));
+
+	dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending);
+	rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending));
+
+	dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending);
+	rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending));
+
+	/* for BC/MC Frames */
+	pstaxmitpriv = &psta_bmc->sta_xmitpriv;
+	dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending);
+	rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending));
+
+	_exit_critical_bh(&pxmitpriv->lock, &irql0);
+}
+
+void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta)
+{
+	unsigned long irql;
+	u8 update_mask = 0, wmmps_ac = 0;
+	struct sta_info *psta_bmc;
+	struct list_head *xmitframe_plist, *xmitframe_phead;
+	struct xmit_frame *pxmitframe = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	_enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+	xmitframe_phead = get_list_head(&psta->sleep_q);
+	xmitframe_plist = get_next(xmitframe_phead);
+
+	while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+		pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+		xmitframe_plist = get_next(xmitframe_plist);
+
+		rtw_list_delete(&pxmitframe->list);
+
+		switch (pxmitframe->attrib.priority) {
+		case 1:
+		case 2:
+			wmmps_ac = psta->uapsd_bk&BIT(1);
+			break;
+		case 4:
+		case 5:
+			wmmps_ac = psta->uapsd_vi&BIT(1);
+			break;
+		case 6:
+		case 7:
+			wmmps_ac = psta->uapsd_vo&BIT(1);
+			break;
+		case 0:
+		case 3:
+		default:
+			wmmps_ac = psta->uapsd_be&BIT(1);
+			break;
+		}
+
+		psta->sleepq_len--;
+		if (psta->sleepq_len > 0)
+			pxmitframe->attrib.mdata = 1;
+		else
+			pxmitframe->attrib.mdata = 0;
+
+		if (wmmps_ac) {
+			psta->sleepq_ac_len--;
+			if (psta->sleepq_ac_len > 0) {
+				pxmitframe->attrib.mdata = 1;
+				pxmitframe->attrib.eosp = 0;
+			} else {
+				pxmitframe->attrib.mdata = 0;
+				pxmitframe->attrib.eosp = 1;
+			}
+		}
+
+		pxmitframe->attrib.triggered = 1;
+
+		_exit_critical_bh(&psta->sleep_q.lock, &irql);
+		if (rtw_hal_xmit(padapter, pxmitframe))
+			rtw_os_xmit_complete(padapter, pxmitframe);
+		_enter_critical_bh(&psta->sleep_q.lock, &irql);
+	}
+
+	if (psta->sleepq_len == 0) {
+		pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+		update_mask = BIT(0);
+
+		if (psta->state&WIFI_SLEEP_STATE)
+			psta->state ^= WIFI_SLEEP_STATE;
+
+		if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+			psta->expire_to = pstapriv->expire_to;
+			psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+		}
+
+		pstapriv->sta_dz_bitmap &= ~BIT(psta->aid);
+	}
+
+	_exit_critical_bh(&psta->sleep_q.lock, &irql);
+
+	/* for BC/MC Frames */
+	psta_bmc = rtw_get_bcmc_stainfo(padapter);
+	if (!psta_bmc)
+		return;
+
+	if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) { /* no any sta in ps mode */
+		_enter_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+
+		xmitframe_phead = get_list_head(&psta_bmc->sleep_q);
+		xmitframe_plist = get_next(xmitframe_phead);
+
+		while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+			pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+			xmitframe_plist = get_next(xmitframe_plist);
+
+			rtw_list_delete(&pxmitframe->list);
+
+			psta_bmc->sleepq_len--;
+			if (psta_bmc->sleepq_len > 0)
+				pxmitframe->attrib.mdata = 1;
+			else
+				pxmitframe->attrib.mdata = 0;
+
+			pxmitframe->attrib.triggered = 1;
+
+			_exit_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+			if (rtw_hal_xmit(padapter, pxmitframe))
+				rtw_os_xmit_complete(padapter, pxmitframe);
+			_enter_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+		}
+
+		if (psta_bmc->sleepq_len == 0) {
+			pstapriv->tim_bitmap &= ~BIT(0);
+			pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+			update_mask |= BIT(1);
+		}
+
+		_exit_critical_bh(&psta_bmc->sleep_q.lock, &irql);
+	}
+
+	if (update_mask)
+		update_beacon(padapter, _TIM_IE_, NULL, false);
+}
+
+void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta)
+{
+	unsigned long irql;
+	u8 wmmps_ac = 0;
+	struct list_head *xmitframe_plist, *xmitframe_phead;
+	struct xmit_frame *pxmitframe = NULL;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	_enter_critical_bh(&psta->sleep_q.lock, &irql);
+
+	xmitframe_phead = get_list_head(&psta->sleep_q);
+	xmitframe_plist = get_next(xmitframe_phead);
+
+	while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+		pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+
+		xmitframe_plist = get_next(xmitframe_plist);
+
+		switch (pxmitframe->attrib.priority) {
+		case 1:
+		case 2:
+			wmmps_ac = psta->uapsd_bk&BIT(1);
+			break;
+		case 4:
+		case 5:
+			wmmps_ac = psta->uapsd_vi&BIT(1);
+			break;
+		case 6:
+		case 7:
+			wmmps_ac = psta->uapsd_vo&BIT(1);
+			break;
+		case 0:
+		case 3:
+		default:
+			wmmps_ac = psta->uapsd_be&BIT(1);
+			break;
+		}
+
+		if (!wmmps_ac)
+			continue;
+
+		rtw_list_delete(&pxmitframe->list);
+
+		psta->sleepq_len--;
+		psta->sleepq_ac_len--;
+
+		if (psta->sleepq_ac_len > 0) {
+			pxmitframe->attrib.mdata = 1;
+			pxmitframe->attrib.eosp = 0;
+		} else {
+			pxmitframe->attrib.mdata = 0;
+			pxmitframe->attrib.eosp = 1;
+		}
+
+		pxmitframe->attrib.triggered = 1;
+
+		if (rtw_hal_xmit(padapter, pxmitframe) == true)
+			rtw_os_xmit_complete(padapter, pxmitframe);
+
+		if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) {
+			pstapriv->tim_bitmap &= ~BIT(psta->aid);
+
+			/* upate BCN for TIM IE */
+			update_beacon(padapter, _TIM_IE_, NULL, false);
+		}
+	}
+
+	_exit_critical_bh(&psta->sleep_q.lock, &irql);
+}
+
+#endif
+
+void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms)
+{
+	sctx->timeout_ms = timeout_ms;
+	sctx->submit_time = rtw_get_current_time();
+	init_completion(&sctx->done);
+	sctx->status = RTW_SCTX_SUBMITTED;
+}
+
+int rtw_sctx_wait(struct submit_ctx *sctx)
+{
+	int ret = _FAIL;
+	unsigned long expire;
+	int status = 0;
+
+	expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT;
+	if (!wait_for_completion_timeout(&sctx->done, expire)) {
+		/* timeout, do something?? */
+		status = RTW_SCTX_DONE_TIMEOUT;
+		DBG_88E("%s timeout\n", __func__);
+	} else {
+		status = sctx->status;
+	}
+
+	if (status == RTW_SCTX_DONE_SUCCESS)
+		ret = _SUCCESS;
+
+	return ret;
+}
+
+static bool rtw_sctx_chk_waring_status(int status)
+{
+	switch (status) {
+	case RTW_SCTX_DONE_UNKNOWN:
+	case RTW_SCTX_DONE_BUF_ALLOC:
+	case RTW_SCTX_DONE_BUF_FREE:
+
+	case RTW_SCTX_DONE_DRV_STOP:
+	case RTW_SCTX_DONE_DEV_REMOVE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+void rtw_sctx_done_err(struct submit_ctx **sctx, int status)
+{
+	if (*sctx) {
+		if (rtw_sctx_chk_waring_status(status))
+			DBG_88E("%s status:%d\n", __func__, status);
+		(*sctx)->status = status;
+		complete(&((*sctx)->done));
+		*sctx = NULL;
+	}
+}
+
+void rtw_sctx_done(struct submit_ctx **sctx)
+{
+	rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS);
+}
+
+int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms)
+{
+	struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
+
+	pack_tx_ops->submit_time = rtw_get_current_time();
+	pack_tx_ops->timeout_ms = timeout_ms;
+	pack_tx_ops->status = RTW_SCTX_SUBMITTED;
+
+	return rtw_sctx_wait(pack_tx_ops);
+}
+
+void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status)
+{
+	struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
+
+	if (pxmitpriv->ack_tx)
+		rtw_sctx_done_err(&pack_tx_ops, status);
+	else
+		DBG_88E("%s ack_tx not set\n", __func__);
+}
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c b/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c
new file mode 100644
index 0000000..95759be
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/Hal8188EFWImg_CE.c
@@ -0,0 +1,1761 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+#include "odm_precomp.h"
+
+const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength] = {
+	0xE1, 0x88, 0x10, 0x00, 0x0B, 0x00, 0x01, 0x00,
+	0x01, 0x21, 0x11, 0x27, 0x30, 0x36, 0x00, 0x00,
+	0x2D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x02, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xC1, 0x6F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xA1, 0xE6, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x02, 0x56, 0xF7, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x42, 0x04,
+	0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0,
+	0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A,
+	0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C,
+	0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02,
+	0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00,
+	0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6,
+	0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1,
+	0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9,
+	0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF,
+	0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF,
+	0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30,
+	0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50,
+	0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8,
+	0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C,
+	0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8,
+	0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80,
+	0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5,
+	0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE,
+	0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD,
+	0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0,
+	0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88,
+	0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C,
+	0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF,
+	0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F,
+	0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F,
+	0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF,
+	0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6,
+	0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76,
+	0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80,
+	0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81,
+	0x76, 0x30, 0x90, 0x45, 0xDE, 0x74, 0x01, 0x93,
+	0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89,
+	0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2,
+	0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94,
+	0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81,
+	0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2,
+	0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE,
+	0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74,
+	0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18,
+	0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69,
+	0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09,
+	0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE,
+	0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81,
+	0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E,
+	0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02,
+	0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED,
+	0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09,
+	0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF,
+	0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F,
+	0x04, 0x90, 0x45, 0xDE, 0x93, 0xF6, 0x08, 0xEF,
+	0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3,
+	0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF,
+	0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4,
+	0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF,
+	0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F,
+	0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x42, 0x4D, 0x50,
+	0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03,
+	0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74,
+	0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C,
+	0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19,
+	0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5,
+	0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74,
+	0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01,
+	0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08,
+	0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC,
+	0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8,
+	0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5,
+	0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF,
+	0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22,
+	0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6,
+	0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4,
+	0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30,
+	0xE2, 0x01, 0x0F, 0x02, 0x42, 0x4C, 0x8F, 0xF0,
+	0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80,
+	0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08,
+	0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50,
+	0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6,
+	0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10,
+	0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30,
+	0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12,
+	0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC,
+	0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x42, 0x4D, 0x7F,
+	0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF,
+	0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF,
+	0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0,
+	0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70,
+	0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF,
+	0x5B, 0xFF, 0xEE, 0x5A, 0xFE, 0xED, 0x59, 0xFD,
+	0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE,
+	0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC,
+	0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0,
+	0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xE2, 0xFC, 0x08,
+	0xE2, 0xFD, 0x08, 0xE2, 0xFE, 0x08, 0xE2, 0xFF,
+	0x22, 0xE2, 0xFB, 0x08, 0xE2, 0xF9, 0x08, 0xE2,
+	0xFA, 0x08, 0xE2, 0xCB, 0xF8, 0x22, 0xEC, 0xF2,
+	0x08, 0xED, 0xF2, 0x08, 0xEE, 0xF2, 0x08, 0xEF,
+	0xF2, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5,
+	0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB,
+	0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB,
+	0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22,
+	0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70,
+	0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3,
+	0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88,
+	0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60,
+	0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x45,
+	0x8C, 0x02, 0x42, 0xDD, 0xE4, 0x93, 0xA3, 0xF8,
+	0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01,
+	0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93,
+	0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3,
+	0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83,
+	0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6,
+	0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08,
+	0x10, 0x20, 0x40, 0x80, 0x90, 0x45, 0xD1, 0xE4,
+	0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54,
+	0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4,
+	0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0,
+	0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93,
+	0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93,
+	0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83,
+	0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA,
+	0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80,
+	0xBE, 0x00, 0x41, 0x82, 0x09, 0x00, 0x41, 0x82,
+	0x0A, 0x00, 0x41, 0x82, 0x17, 0x00, 0x59, 0xE2,
+	0x5C, 0x24, 0x5E, 0x5D, 0x5F, 0xA1, 0xC0, 0xE0,
+	0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0,
+	0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0,
+	0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0,
+	0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE6,
+	0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD1, 0x35, 0x74,
+	0xE6, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x45,
+	0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05,
+	0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01,
+	0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83,
+	0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54,
+	0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55,
+	0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5,
+	0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD,
+	0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A,
+	0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F,
+	0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57,
+	0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0,
+	0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0,
+	0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01,
+	0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05,
+	0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74,
+	0x6F, 0xF0, 0x74, 0x46, 0xA3, 0xF0, 0x12, 0x6C,
+	0x78, 0xE5, 0x41, 0x30, 0xE4, 0x04, 0x7F, 0x02,
+	0x91, 0x27, 0xE5, 0x41, 0x30, 0xE6, 0x03, 0x12,
+	0x6C, 0xD5, 0xE5, 0x43, 0x30, 0xE0, 0x03, 0x12,
+	0x51, 0xC2, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12,
+	0x4D, 0x0C, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12,
+	0x4C, 0xC1, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12,
+	0x6C, 0xE2, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12,
+	0x6D, 0x04, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12,
+	0x6D, 0x33, 0xE5, 0x43, 0x30, 0xE6, 0x02, 0xF1,
+	0x0F, 0xE5, 0x44, 0x30, 0xE1, 0x03, 0x12, 0x51,
+	0x7F, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0,
+	0x74, 0x46, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06,
+	0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02,
+	0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82,
+	0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90,
+	0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x81,
+	0x27, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x2B, 0xE0,
+	0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xF1,
+	0x2A, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x90, 0x81,
+	0x29, 0x30, 0xE0, 0x05, 0xE0, 0xFF, 0x02, 0x74,
+	0x8F, 0xE0, 0xFF, 0x7D, 0x01, 0xD3, 0x10, 0xAF,
+	0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x13, 0xED,
+	0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x82, 0x14,
+	0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFE, 0xC4, 0x13,
+	0x13, 0x54, 0x03, 0x30, 0xE0, 0x03, 0x02, 0x48,
+	0xA0, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01,
+	0x30, 0xE0, 0x03, 0x02, 0x48, 0xA0, 0x90, 0x82,
+	0x14, 0xE0, 0xFE, 0x6F, 0x70, 0x03, 0x02, 0x48,
+	0xA0, 0xEF, 0x70, 0x03, 0x02, 0x48, 0x17, 0x24,
+	0xFE, 0x70, 0x03, 0x02, 0x48, 0x50, 0x24, 0xFE,
+	0x60, 0x51, 0x24, 0xFC, 0x70, 0x03, 0x02, 0x48,
+	0x8B, 0x24, 0xFC, 0x60, 0x03, 0x02, 0x48, 0xA0,
+	0xEE, 0xB4, 0x0E, 0x03, 0x12, 0x49, 0x5E, 0x90,
+	0x82, 0x14, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12,
+	0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06,
+	0x03, 0x12, 0x49, 0x34, 0x90, 0x82, 0x14, 0xE0,
+	0xB4, 0x04, 0x0F, 0x90, 0x82, 0x13, 0xE0, 0xFF,
+	0x60, 0x05, 0x12, 0x73, 0x75, 0x80, 0x03, 0x12,
+	0x66, 0x26, 0x90, 0x82, 0x14, 0xE0, 0x64, 0x08,
+	0x60, 0x03, 0x02, 0x48, 0xA0, 0x12, 0x73, 0xD3,
+	0x02, 0x48, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0x70,
+	0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82,
+	0x14, 0xE0, 0xB4, 0x06, 0x03, 0x12, 0x49, 0x34,
+	0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x09, 0x12,
+	0x48, 0xA5, 0xBF, 0x01, 0x03, 0x12, 0x49, 0x5E,
+	0x90, 0x82, 0x14, 0xE0, 0x64, 0x0C, 0x60, 0x02,
+	0x01, 0xA0, 0x11, 0xA5, 0xEF, 0x64, 0x01, 0x60,
+	0x02, 0x01, 0xA0, 0x11, 0xFA, 0x01, 0xA0, 0x90,
+	0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5,
+	0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, 0x14,
+	0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82,
+	0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, 0xBF,
+	0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0,
+	0x64, 0x04, 0x70, 0x5C, 0x12, 0x72, 0xF5, 0xEF,
+	0x64, 0x01, 0x70, 0x54, 0x31, 0xBE, 0x80, 0x50,
+	0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11,
+	0xA5, 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82,
+	0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90,
+	0x82, 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5,
+	0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14,
+	0xE0, 0x70, 0x04, 0x7F, 0x01, 0x31, 0x93, 0x90,
+	0x82, 0x14, 0xE0, 0xB4, 0x04, 0x1A, 0x12, 0x73,
+	0xBB, 0x80, 0x15, 0x90, 0x82, 0x14, 0xE0, 0xB4,
+	0x0C, 0x0E, 0x90, 0x81, 0x25, 0xE0, 0xFF, 0x13,
+	0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x31, 0xB1,
+	0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD1, 0xAB, 0xEF,
+	0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74,
+	0x01, 0xF0, 0x80, 0x3D, 0x90, 0x81, 0x24, 0xE0,
+	0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0,
+	0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80,
+	0x28, 0xEF, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x08,
+	0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x19,
+	0x90, 0x81, 0x29, 0xE0, 0xD3, 0x94, 0x04, 0x40,
+	0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80,
+	0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01,
+	0x22, 0x90, 0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F,
+	0x00, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01,
+	0x70, 0x31, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFD,
+	0xF0, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x7F,
+	0x01, 0xF1, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81,
+	0x24, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A,
+	0x74, 0x0E, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22,
+	0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01,
+	0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x25, 0xE0,
+	0x90, 0x06, 0x04, 0x20, 0xE0, 0x0C, 0xE0, 0x44,
+	0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0,
+	0x80, 0x0E, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81,
+	0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0,
+	0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x81,
+	0x25, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90,
+	0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x80, 0x1E, 0x90,
+	0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44,
+	0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0,
+	0x90, 0x05, 0x27, 0xE0, 0x44, 0x80, 0xF0, 0x90,
+	0x81, 0x23, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x22,
+	0xE4, 0xF0, 0x22, 0x90, 0x82, 0x15, 0xEF, 0xF0,
+	0x12, 0x54, 0x65, 0x90, 0x82, 0x15, 0xE0, 0x60,
+	0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81,
+	0x2A, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x23, 0xF0,
+	0x22, 0x31, 0xE3, 0x90, 0x81, 0x2A, 0x74, 0x08,
+	0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05,
+	0x22, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x01,
+	0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x51,
+	0x57, 0x31, 0xE3, 0xE4, 0x90, 0x81, 0x2A, 0xF0,
+	0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, 0x22,
+	0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x85, 0xBB,
+	0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F,
+	0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85,
+	0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14,
+	0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90,
+	0x81, 0xF9, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00,
+	0x00, 0xE4, 0xFD, 0xFF, 0x12, 0x55, 0x1C, 0x7F,
+	0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44,
+	0x80, 0xFC, 0x90, 0x82, 0x05, 0x12, 0x20, 0xCE,
+	0x90, 0x82, 0x05, 0x12, 0x44, 0xD9, 0x90, 0x85,
+	0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08,
+	0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F,
+	0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05,
+	0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x01,
+	0x34, 0x74, 0x40, 0xF0, 0xFD, 0xE4, 0xFF, 0x74,
+	0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74,
+	0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5,
+	0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01,
+	0xC3, 0xC0, 0xD0, 0xE4, 0x90, 0x81, 0xCB, 0xF0,
+	0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90,
+	0x81, 0x1F, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0,
+	0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F,
+	0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04,
+	0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81,
+	0x1F, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54,
+	0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE,
+	0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF,
+	0x90, 0x81, 0x1F, 0xF0, 0xEE, 0x54, 0x20, 0xFE,
+	0xEF, 0x54, 0xDF, 0x4E, 0xF0, 0x12, 0x1F, 0xA4,
+	0xC3, 0x13, 0x20, 0xE0, 0x02, 0x61, 0x5E, 0x90,
+	0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x6D, 0x90,
+	0x81, 0xCB, 0x74, 0x21, 0xF0, 0xEF, 0x13, 0x13,
+	0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90,
+	0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x0C,
+	0xE4, 0x90, 0x81, 0x20, 0xF0, 0xA3, 0xF0, 0x7D,
+	0x40, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0,
+	0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0,
+	0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x12, 0xF0,
+	0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x07, 0x90,
+	0x81, 0xCB, 0xE0, 0x44, 0x14, 0xF0, 0x90, 0x81,
+	0x1F, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0,
+	0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x80, 0xF0,
+	0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, 0xF0,
+	0x90, 0x81, 0x22, 0xE0, 0x60, 0x02, 0x81, 0x17,
+	0x7F, 0x01, 0x80, 0x15, 0x90, 0x81, 0xCB, 0x74,
+	0x01, 0xF0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81,
+	0x22, 0xE0, 0x64, 0x04, 0x60, 0x02, 0x81, 0x17,
+	0xFF, 0x12, 0x53, 0x0E, 0x81, 0x17, 0x90, 0x81,
+	0x1F, 0xE0, 0xFF, 0x20, 0xE0, 0x02, 0x61, 0xE7,
+	0x90, 0x81, 0xCB, 0x74, 0x31, 0xF0, 0xEF, 0x13,
+	0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E,
+	0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80,
+	0x06, 0x7D, 0x40, 0xE4, 0xFF, 0x91, 0x26, 0x90,
+	0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54,
+	0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0,
+	0x44, 0x02, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30,
+	0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x04,
+	0xF0, 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27,
+	0xF0, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x70,
+	0x1D, 0xFD, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x12,
+	0x51, 0x73, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x29,
+	0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x03, 0xE4, 0xFD,
+	0xFF, 0x12, 0x47, 0x3D, 0x80, 0x41, 0x90, 0x81,
+	0x2A, 0xE0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05,
+	0x27, 0xE0, 0x44, 0x40, 0xF0, 0x80, 0x30, 0x90,
+	0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27,
+	0xF0, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x06,
+	0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0B, 0x90, 0x81,
+	0x23, 0xE0, 0xB4, 0x08, 0x07, 0x7D, 0x01, 0x7F,
+	0x0C, 0x12, 0x47, 0x3D, 0xD1, 0x34, 0x90, 0x81,
+	0x29, 0x12, 0x47, 0x39, 0x12, 0x5A, 0xA7, 0xD0,
+	0xD0, 0x92, 0xAF, 0x22, 0x7D, 0x02, 0x7F, 0x02,
+	0x91, 0x26, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D,
+	0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE,
+	0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34,
+	0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xEF, 0x70,
+	0x37, 0x7D, 0x78, 0x7F, 0x02, 0x91, 0x26, 0x7D,
+	0x02, 0x7F, 0x03, 0x91, 0x26, 0x7D, 0xC8, 0x7F,
+	0x02, 0x12, 0x71, 0x8F, 0x90, 0x01, 0x57, 0xE4,
+	0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D,
+	0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x90, 0x81,
+	0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0,
+	0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22,
+	0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74,
+	0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x51, 0x57, 0x7D,
+	0x02, 0x7F, 0x03, 0x51, 0x57, 0x90, 0x06, 0x0A,
+	0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3,
+	0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x80, 0xDE,
+	0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x25, 0xE0,
+	0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20,
+	0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x47,
+	0x3D, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0,
+	0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0,
+	0x08, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60,
+	0x3A, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x04, 0xEF,
+	0x30, 0xE0, 0x0A, 0x90, 0x81, 0x2A, 0xE0, 0x64,
+	0x02, 0x60, 0x28, 0xB1, 0x83, 0x90, 0x81, 0x25,
+	0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0,
+	0x14, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0,
+	0x6F, 0x70, 0x0A, 0xF1, 0xCD, 0x91, 0x1C, 0x90,
+	0x81, 0x2E, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6,
+	0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0,
+	0x30, 0xE0, 0x06, 0x90, 0x81, 0x21, 0x74, 0x01,
+	0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x45, 0x90,
+	0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54,
+	0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0,
+	0x30, 0xE4, 0x0B, 0x91, 0x1C, 0x90, 0x81, 0x2D,
+	0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x82,
+	0x0B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9,
+	0xC3, 0x90, 0x82, 0x0C, 0xE0, 0x94, 0x80, 0x90,
+	0x82, 0x0B, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40,
+	0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0,
+	0xE0, 0x44, 0x01, 0xF0, 0x12, 0x75, 0xF8, 0xD1,
+	0xD6, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x0C,
+	0xE4, 0xF5, 0x1D, 0xA3, 0xF1, 0xFB, 0x90, 0x01,
+	0x57, 0x74, 0x05, 0xF0, 0x90, 0x01, 0xBE, 0xE0,
+	0x04, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64,
+	0x01, 0x60, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x27,
+	0xE0, 0x70, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x26,
+	0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22,
+	0x90, 0x06, 0xAB, 0xE0, 0x90, 0x81, 0x2E, 0xF0,
+	0x90, 0x06, 0xAA, 0xE0, 0x90, 0x81, 0x2D, 0xF0,
+	0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x81, 0x2D,
+	0xE0, 0xFE, 0xFF, 0x80, 0x00, 0x90, 0x81, 0x2E,
+	0xEF, 0xF0, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04,
+	0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81,
+	0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90,
+	0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74,
+	0x02, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD,
+	0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x26, 0xE0,
+	0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02,
+	0x80, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0,
+	0x05, 0x12, 0x6D, 0xF2, 0x80, 0x03, 0x12, 0x6E,
+	0xC9, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13,
+	0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x2D,
+	0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0xF1,
+	0xCD, 0x91, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xC3,
+	0x13, 0x20, 0xE0, 0x07, 0x90, 0x81, 0x25, 0xE0,
+	0x44, 0x04, 0xF0, 0x22, 0xD1, 0xAB, 0xEF, 0x70,
+	0x02, 0xD1, 0x3C, 0x22, 0x90, 0x81, 0x27, 0xE0,
+	0x64, 0x01, 0x70, 0x66, 0x90, 0x81, 0x26, 0xE0,
+	0x54, 0x0F, 0x60, 0x51, 0x90, 0x81, 0x2A, 0xE0,
+	0x70, 0x03, 0xFF, 0x31, 0x93, 0x90, 0x81, 0x2A,
+	0xE0, 0x64, 0x0C, 0x60, 0x03, 0x12, 0x66, 0x26,
+	0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x01, 0x3C,
+	0x74, 0x04, 0xF0, 0xD1, 0xAB, 0xEF, 0x64, 0x01,
+	0x60, 0x38, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+	0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+	0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x50,
+	0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90,
+	0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x24,
+	0xE0, 0x44, 0x08, 0xF0, 0x22, 0x90, 0x81, 0x2A,
+	0xE0, 0x70, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12,
+	0x47, 0x3D, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4,
+	0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B,
+	0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60,
+	0x02, 0x7F, 0x00, 0x22, 0x12, 0x50, 0x60, 0x90,
+	0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0,
+	0x7D, 0x02, 0x7F, 0x02, 0x51, 0x57, 0x90, 0x81,
+	0x42, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x80, 0xDE,
+	0xE0, 0xB4, 0x01, 0x26, 0x90, 0x82, 0x17, 0xE0,
+	0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x81,
+	0x44, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x82, 0x17,
+	0xF0, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0x90, 0x81,
+	0x43, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0,
+	0xF1, 0x0B, 0x22, 0xE4, 0xFF, 0x8F, 0x53, 0x90,
+	0x04, 0x1D, 0xE0, 0x60, 0x19, 0x90, 0x05, 0x22,
+	0xE0, 0xF5, 0x56, 0x74, 0xFF, 0xF0, 0xF1, 0x3A,
+	0xBF, 0x01, 0x03, 0x12, 0x74, 0xFB, 0x90, 0x05,
+	0x22, 0xE5, 0x56, 0xF0, 0x80, 0x03, 0x12, 0x74,
+	0xFB, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F,
+	0x01, 0x22, 0xE4, 0x90, 0x82, 0x0F, 0xF0, 0xA3,
+	0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3,
+	0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3,
+	0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90,
+	0x82, 0x10, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x0F,
+	0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0,
+	0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F,
+	0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82,
+	0x0F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9,
+	0x80, 0xBF, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4,
+	0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0,
+	0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82,
+	0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10,
+	0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34,
+	0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22,
+	0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC,
+	0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x1F,
+	0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83,
+	0xE0, 0x44, 0x40, 0xF0, 0x22, 0xEF, 0x14, 0x90,
+	0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10,
+	0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8,
+	0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5,
+	0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0,
+	0x22, 0xE0, 0x44, 0x02, 0xF0, 0xE4, 0xF5, 0x1D,
+	0x90, 0x81, 0x39, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB,
+	0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F,
+	0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54,
+	0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0,
+	0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0,
+	0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F,
+	0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33,
+	0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13,
+	0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19,
+	0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85,
+	0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74,
+	0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19,
+	0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22,
+	0xE4, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x27,
+	0xE0, 0x60, 0x58, 0x90, 0x80, 0xDE, 0xE0, 0x64,
+	0x01, 0x70, 0x50, 0x90, 0x81, 0x4D, 0x04, 0xF0,
+	0xE4, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x81, 0x1F,
+	0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0,
+	0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4D, 0xF0,
+	0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4D,
+	0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x60, 0x24, 0x90,
+	0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5,
+	0x1D, 0x90, 0x81, 0x2F, 0x12, 0x4F, 0xFB, 0x90,
+	0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A,
+	0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04,
+	0x12, 0x47, 0x3D, 0x22, 0xE4, 0x90, 0x81, 0x4C,
+	0xF0, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x02, 0x21,
+	0x72, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60,
+	0x02, 0x21, 0x72, 0x90, 0x81, 0x26, 0xE0, 0xFF,
+	0xC4, 0x54, 0x0F, 0x60, 0x22, 0x24, 0xFE, 0x60,
+	0x03, 0x04, 0x70, 0x21, 0x90, 0x81, 0x2E, 0xE0,
+	0x14, 0xF0, 0xE0, 0xFF, 0x60, 0x06, 0x90, 0x81,
+	0x30, 0xE0, 0x60, 0x11, 0xEF, 0x70, 0x08, 0x90,
+	0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x80, 0x00, 0x90,
+	0x81, 0x4C, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x1F,
+	0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0,
+	0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4C, 0xF0,
+	0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4C,
+	0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x60, 0x43, 0x90,
+	0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81,
+	0x30, 0xE0, 0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4,
+	0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x80, 0x0D,
+	0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x75,
+	0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81,
+	0x2F, 0xE0, 0x2F, 0x12, 0x4F, 0xFC, 0x90, 0x01,
+	0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0,
+	0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12,
+	0x47, 0x3D, 0x22, 0x90, 0x05, 0x43, 0xE0, 0x7F,
+	0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90,
+	0x81, 0x27, 0xE0, 0x70, 0x07, 0x90, 0x81, 0x1F,
+	0xE0, 0x30, 0xE0, 0x11, 0x90, 0x81, 0x1F, 0xE0,
+	0x30, 0xE0, 0x07, 0x31, 0x73, 0xBF, 0x01, 0x05,
+	0x41, 0x5B, 0x12, 0x4E, 0x3C, 0x22, 0xD3, 0x10,
+	0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x1E,
+	0xE0, 0xB4, 0x01, 0x04, 0x7F, 0x04, 0x80, 0x0B,
+	0x31, 0x73, 0xBF, 0x01, 0x04, 0x7F, 0x01, 0x80,
+	0x02, 0x7F, 0x02, 0x71, 0x0E, 0xD0, 0xD0, 0x92,
+	0xAF, 0x22, 0x90, 0x81, 0x4B, 0xE0, 0x60, 0x0F,
+	0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x02,
+	0xF0, 0x90, 0x05, 0xFC, 0xE0, 0x04, 0xF0, 0x90,
+	0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x10, 0xA3, 0x74,
+	0x01, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0xC3,
+	0x13, 0x30, 0xE0, 0x02, 0x31, 0x9E, 0x11, 0xC4,
+	0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x07, 0x91,
+	0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90,
+	0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3D, 0x90,
+	0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02,
+	0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, 0x00,
+	0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70,
+	0x23, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x21,
+	0x9E, 0x51, 0x45, 0x90, 0x81, 0x23, 0xE0, 0xB4,
+	0x08, 0x06, 0xE4, 0xFD, 0x7F, 0x0C, 0x80, 0x09,
+	0x90, 0x81, 0x23, 0xE0, 0x70, 0x06, 0xFD, 0x7F,
+	0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1E,
+	0xE0, 0xB4, 0x01, 0x0F, 0x90, 0x81, 0x23, 0xE0,
+	0x64, 0x02, 0x60, 0x07, 0x7D, 0x01, 0x7F, 0x02,
+	0x12, 0x47, 0x3D, 0x90, 0x81, 0x27, 0xE0, 0x64,
+	0x02, 0x60, 0x14, 0x90, 0x81, 0x26, 0xE0, 0x54,
+	0x0F, 0x60, 0x0C, 0x12, 0x4E, 0xAB, 0xEF, 0x70,
+	0x06, 0xFD, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x22,
+	0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3F,
+	0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02,
+	0x02, 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D,
+	0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E,
+	0x70, 0x25, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02,
+	0x21, 0x9E, 0x12, 0x74, 0xAC, 0x90, 0x81, 0x23,
+	0xE0, 0xB4, 0x0C, 0x06, 0xE4, 0xFD, 0x7F, 0x08,
+	0x80, 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x04,
+	0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x47, 0x3D, 0x22,
+	0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90,
+	0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x1F, 0xA4,
+	0xFF, 0x90, 0x81, 0x1E, 0xF0, 0xBF, 0x01, 0x12,
+	0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00,
+	0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x21,
+	0x80, 0x1D, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16,
+	0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01,
+	0x60, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x20, 0xE0,
+	0x06, 0xE4, 0xFF, 0x71, 0x0E, 0x80, 0x02, 0x31,
+	0x9E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10,
+	0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x22,
+	0xE0, 0x90, 0x82, 0x16, 0xF0, 0x6F, 0x70, 0x02,
+	0x81, 0x04, 0xEF, 0x14, 0x60, 0x3E, 0x14, 0x60,
+	0x62, 0x14, 0x70, 0x02, 0x61, 0xB8, 0x14, 0x70,
+	0x02, 0x61, 0xDF, 0x24, 0x04, 0x60, 0x02, 0x81,
+	0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04,
+	0x04, 0x91, 0x41, 0x81, 0x04, 0xEF, 0xB4, 0x02,
+	0x04, 0x91, 0x50, 0x81, 0x04, 0x90, 0x82, 0x16,
+	0xE0, 0xFF, 0xB4, 0x03, 0x04, 0x91, 0x54, 0x81,
+	0x04, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x81, 0x04,
+	0x91, 0x43, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0,
+	0xFF, 0xB4, 0x04, 0x04, 0x91, 0xF3, 0x81, 0x04,
+	0xEF, 0xB4, 0x02, 0x04, 0x91, 0x58, 0x81, 0x04,
+	0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x04,
+	0x91, 0xE8, 0x81, 0x04, 0xEF, 0x70, 0x7D, 0x91,
+	0x2B, 0x80, 0x79, 0x90, 0x82, 0x16, 0xE0, 0xB4,
+	0x04, 0x05, 0x12, 0x74, 0x60, 0x80, 0x6D, 0x90,
+	0x82, 0x16, 0xE0, 0xB4, 0x01, 0x04, 0x91, 0x21,
+	0x80, 0x62, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x03,
+	0x05, 0x12, 0x74, 0x71, 0x80, 0x56, 0x90, 0x82,
+	0x16, 0xE0, 0x70, 0x50, 0x91, 0x1F, 0x80, 0x4C,
+	0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x05,
+	0x12, 0x74, 0x4C, 0x80, 0x3F, 0xEF, 0xB4, 0x01,
+	0x04, 0x91, 0x34, 0x80, 0x37, 0xEF, 0xB4, 0x02,
+	0x04, 0x91, 0xDF, 0x80, 0x2F, 0x90, 0x82, 0x16,
+	0xE0, 0x70, 0x29, 0x91, 0x32, 0x80, 0x25, 0x90,
+	0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12,
+	0x74, 0x7B, 0x80, 0x18, 0xEF, 0xB4, 0x01, 0x04,
+	0x91, 0x0B, 0x80, 0x10, 0xEF, 0xB4, 0x02, 0x04,
+	0xB1, 0x06, 0x80, 0x08, 0x90, 0x82, 0x16, 0xE0,
+	0x70, 0x02, 0x91, 0x09, 0xD0, 0xD0, 0x92, 0xAF,
+	0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0x6F,
+	0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0,
+	0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0x91,
+	0x2B, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74,
+	0x02, 0xF0, 0x22, 0x90, 0x81, 0x22, 0x74, 0x01,
+	0xF0, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74,
+	0xFF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0,
+	0x22, 0x91, 0xF3, 0x90, 0x05, 0x27, 0xE0, 0x54,
+	0xBF, 0xF0, 0xE4, 0x90, 0x81, 0x22, 0xF0, 0x22,
+	0x91, 0x58, 0x80, 0xEF, 0x91, 0xE8, 0x80, 0xEB,
+	0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90,
+	0x81, 0x22, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF,
+	0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0x01, 0xE0,
+	0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF,
+	0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90,
+	0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E,
+	0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, 0x7F, 0xFC,
+	0x90, 0x82, 0x01, 0x12, 0x20, 0xCE, 0x90, 0x82,
+	0x01, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12,
+	0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E,
+	0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC,
+	0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12,
+	0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA,
+	0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E,
+	0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20,
+	0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF,
+	0xB1, 0x1C, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91,
+	0x65, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22,
+	0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22,
+	0x04, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0,
+	0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90,
+	0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, 0x91, 0x65,
+	0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05,
+	0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22,
+	0x74, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01,
+	0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, 0x05, 0x90,
+	0x81, 0xF9, 0x12, 0x44, 0xD9, 0x90, 0x81, 0xE5,
+	0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, 0x07, 0x12,
+	0x60, 0xF5, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90,
+	0x81, 0xC8, 0x12, 0x45, 0x1F, 0xEF, 0x12, 0x45,
+	0x28, 0x55, 0x71, 0x00, 0x55, 0x7A, 0x01, 0x55,
+	0x83, 0x02, 0x55, 0x8B, 0x03, 0x55, 0x94, 0x04,
+	0x55, 0x9C, 0x20, 0x55, 0xA4, 0x21, 0x55, 0xAD,
+	0x23, 0x55, 0xB5, 0x24, 0x55, 0xBE, 0x25, 0x55,
+	0xC7, 0x26, 0x55, 0xCF, 0xC0, 0x00, 0x00, 0x55,
+	0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02,
+	0x6A, 0xB0, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16,
+	0x02, 0x65, 0x81, 0x90, 0x81, 0xC8, 0x12, 0x45,
+	0x16, 0x41, 0xC0, 0x90, 0x81, 0xC8, 0x12, 0x45,
+	0x16, 0x02, 0x75, 0xD8, 0x90, 0x81, 0xC8, 0x12,
+	0x45, 0x16, 0x80, 0x44, 0x90, 0x81, 0xC8, 0x12,
+	0x45, 0x16, 0xC1, 0x4B, 0x90, 0x81, 0xC8, 0x12,
+	0x45, 0x16, 0x02, 0x6A, 0xF8, 0x90, 0x81, 0xC8,
+	0x12, 0x45, 0x16, 0xE1, 0xE1, 0x90, 0x81, 0xC8,
+	0x12, 0x45, 0x16, 0x02, 0x4A, 0x6C, 0x90, 0x81,
+	0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x3E, 0x90,
+	0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x3E, 0x90,
+	0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x4E,
+	0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22,
+	0x12, 0x5A, 0x4B, 0x12, 0x1F, 0xA4, 0xFF, 0x54,
+	0x01, 0xFE, 0x90, 0x81, 0x45, 0xE0, 0x54, 0xFE,
+	0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14,
+	0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81,
+	0x46, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD,
+	0x90, 0x81, 0x47, 0xF0, 0x22, 0x12, 0x1F, 0xA4,
+	0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x3F, 0xE0,
+	0x54, 0xFE, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12,
+	0x1F, 0xBD, 0xFE, 0x90, 0x05, 0x54, 0xE0, 0xC3,
+	0x9E, 0x90, 0x81, 0x40, 0xF0, 0xEF, 0x20, 0xE0,
+	0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0,
+	0x90, 0x81, 0x3F, 0xE0, 0x54, 0x01, 0x90, 0x01,
+	0xBC, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01,
+	0xBD, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54,
+	0x7F, 0x90, 0x81, 0x27, 0xF0, 0xEF, 0xC4, 0x13,
+	0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00,
+	0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4,
+	0x54, 0x0F, 0xFE, 0x90, 0x81, 0x26, 0xE0, 0x54,
+	0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F,
+	0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81,
+	0x24, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54,
+	0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x26,
+	0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04,
+	0x12, 0x1F, 0xBD, 0x90, 0x81, 0x29, 0xF0, 0xD1,
+	0xC6, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90,
+	0x01, 0xB8, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x90,
+	0x01, 0xBA, 0xF0, 0x90, 0x81, 0x29, 0xE0, 0x90,
+	0x01, 0xBB, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54,
+	0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x81,
+	0xCB, 0x12, 0x45, 0x1F, 0x12, 0x72, 0xB3, 0x90,
+	0x81, 0x27, 0xE0, 0xFF, 0x12, 0x4C, 0x3E, 0x90,
+	0x81, 0x27, 0xE0, 0x60, 0x19, 0x90, 0x81, 0xCB,
+	0x12, 0x45, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F,
+	0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12,
+	0x1F, 0xBD, 0xFD, 0x12, 0x72, 0xC4, 0x22, 0xC0,
+	0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0,
+	0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01,
+	0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05,
+	0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74,
+	0xF7, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0x12, 0x6C,
+	0xA5, 0xE5, 0x49, 0x30, 0xE1, 0x03, 0x12, 0x6F,
+	0x79, 0xE5, 0x49, 0x30, 0xE2, 0x02, 0xF1, 0xA5,
+	0xE5, 0x49, 0x30, 0xE3, 0x03, 0x12, 0x6F, 0x8D,
+	0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x6F, 0xC9,
+	0xE5, 0x4A, 0x30, 0xE4, 0x03, 0x12, 0x70, 0x22,
+	0xE5, 0x4B, 0x30, 0xE1, 0x02, 0x51, 0x78, 0xE5,
+	0x4B, 0x30, 0xE0, 0x02, 0x31, 0xFF, 0xE5, 0x4B,
+	0x30, 0xE3, 0x02, 0xF1, 0xE0, 0xE5, 0x4C, 0x30,
+	0xE1, 0x05, 0x7F, 0x03, 0x12, 0x44, 0x27, 0xE5,
+	0x4C, 0x30, 0xE4, 0x03, 0x12, 0x4E, 0xC4, 0xE5,
+	0x4C, 0x30, 0xE5, 0x03, 0x12, 0x70, 0x38, 0xE5,
+	0x4C, 0x30, 0xE6, 0x03, 0x12, 0x70, 0xCE, 0x74,
+	0xF7, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x56,
+	0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05,
+	0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01,
+	0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83,
+	0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x27,
+	0xE0, 0x60, 0x34, 0x90, 0x06, 0x92, 0xE0, 0x30,
+	0xE0, 0x23, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+	0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+	0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x11, 0x05,
+	0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, 0x06,
+	0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24,
+	0xE0, 0x54, 0xF7, 0xF0, 0x12, 0x47, 0x2A, 0x22,
+	0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x31, 0xF0,
+	0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0,
+	0xA3, 0xF0, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x51,
+	0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01,
+	0x09, 0x90, 0x81, 0x51, 0xE0, 0x64, 0x03, 0x60,
+	0x03, 0x22, 0x01, 0xAB, 0xE4, 0x90, 0x81, 0x56,
+	0xF0, 0x90, 0x81, 0x56, 0xE0, 0xFF, 0xC3, 0x94,
+	0x02, 0x40, 0x02, 0x01, 0xE6, 0xC3, 0x74, 0xFE,
+	0x9F, 0xFF, 0xE4, 0x94, 0x00, 0xFE, 0x7B, 0x01,
+	0x7A, 0x81, 0x79, 0x52, 0x12, 0x2B, 0x27, 0xEF,
+	0x64, 0x01, 0x70, 0x77, 0x90, 0x81, 0x52, 0xE0,
+	0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54,
+	0x0C, 0x70, 0x16, 0x90, 0x81, 0x52, 0xE0, 0xFF,
+	0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60,
+	0x62, 0x90, 0x81, 0x53, 0x74, 0x01, 0xF0, 0x80,
+	0x05, 0xE4, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81,
+	0x53, 0xE0, 0x90, 0x81, 0x52, 0x70, 0x16, 0xE0,
+	0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x81,
+	0x54, 0xF0, 0xEF, 0x54, 0x0C, 0x13, 0x13, 0x54,
+	0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54,
+	0x30, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x03,
+	0xA3, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0x64, 0x30,
+	0x70, 0x54, 0xA3, 0xE0, 0x64, 0x02, 0x70, 0x4E,
+	0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x81,
+	0x57, 0xF0, 0xE0, 0x70, 0x41, 0xA3, 0x74, 0x02,
+	0xF0, 0x80, 0x10, 0x90, 0x81, 0x58, 0x74, 0x01,
+	0xF0, 0x80, 0x08, 0x90, 0x81, 0x56, 0xE0, 0x04,
+	0xF0, 0x01, 0x11, 0x90, 0x01, 0xC4, 0x74, 0xE9,
+	0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x90, 0x81, 0x58,
+	0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x81, 0x52,
+	0xE0, 0x90, 0x01, 0xC9, 0xF0, 0x90, 0x81, 0x53,
+	0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F,
+	0x1F, 0x12, 0x32, 0x1E, 0x80, 0xD5, 0x22, 0x90,
+	0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F,
+	0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90,
+	0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03,
+	0x22, 0x11, 0xE7, 0x90, 0x80, 0x3C, 0xEF, 0xF0,
+	0x31, 0x13, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0,
+	0x02, 0x2D, 0xA7, 0x31, 0x81, 0x31, 0xB1, 0x31,
+	0x40, 0x31, 0x5F, 0xE4, 0xF5, 0x35, 0xF5, 0x36,
+	0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50,
+	0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12,
+	0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32,
+	0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E,
+	0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F,
+	0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5,
+	0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5,
+	0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75,
+	0x45, 0x0E, 0x75, 0x46, 0x01, 0x43, 0x46, 0x10,
+	0x75, 0x47, 0x03, 0x75, 0x48, 0x62, 0x90, 0x01,
+	0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0,
+	0xA3, 0xE5, 0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0,
+	0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0,
+	0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0,
+	0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F,
+	0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51,
+	0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12,
+	0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32,
+	0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3,
+	0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C,
+	0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD,
+	0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F,
+	0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56,
+	0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02,
+	0x32, 0x1E, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80,
+	0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD,
+	0x00, 0xE0, 0x54, 0xBF, 0xF0, 0x12, 0x57, 0xE9,
+	0x51, 0x77, 0x12, 0x32, 0x77, 0x51, 0xC9, 0x51,
+	0x5E, 0x7F, 0x01, 0x12, 0x43, 0x15, 0x90, 0x81,
+	0x41, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x43, 0x15,
+	0x90, 0x81, 0x41, 0xE0, 0x04, 0xF0, 0x7F, 0x03,
+	0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0xE0, 0x04,
+	0xF0, 0x31, 0x01, 0x51, 0x3F, 0x90, 0x00, 0x80,
+	0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32,
+	0x1E, 0x75, 0x20, 0xFF, 0x51, 0x68, 0x51, 0xF9,
+	0x51, 0x7F, 0xE4, 0xFF, 0x02, 0x43, 0x9E, 0x51,
+	0x62, 0x51, 0x6F, 0x51, 0xA7, 0x71, 0x4F, 0x51,
+	0x8A, 0x51, 0x95, 0x90, 0x81, 0x45, 0xE0, 0x54,
+	0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0,
+	0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0xF5,
+	0x4D, 0x22, 0xE4, 0x90, 0x80, 0xDE, 0xF0, 0x22,
+	0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0xE4,
+	0x90, 0x80, 0xD8, 0xF0, 0xA3, 0xF0, 0x22, 0x90,
+	0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90,
+	0x01, 0xE4, 0x74, 0x0B, 0xF0, 0xA3, 0x74, 0x01,
+	0xF0, 0x22, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE,
+	0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x42,
+	0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3,
+	0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90,
+	0x81, 0x1F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD,
+	0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54,
+	0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0xE4, 0xA3, 0xF0,
+	0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0x74, 0x0C, 0xF0,
+	0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0,
+	0x90, 0x01, 0x9C, 0x74, 0x7E, 0xF0, 0xA3, 0x74,
+	0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74,
+	0x24, 0xF0, 0x90, 0x01, 0x9B, 0x74, 0x49, 0xF0,
+	0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01,
+	0x99, 0xE4, 0xF0, 0x90, 0x01, 0x98, 0x04, 0xF0,
+	0x22, 0xE4, 0x90, 0x81, 0x51, 0xF0, 0xA3, 0xF0,
+	0x90, 0x01, 0x98, 0xE0, 0x7F, 0x00, 0x30, 0xE4,
+	0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E,
+	0xC3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x88, 0x90,
+	0x81, 0x51, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90,
+	0x01, 0xC1, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90,
+	0x81, 0x51, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44,
+	0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA,
+	0xD3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x32, 0x90,
+	0x81, 0x51, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90,
+	0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0xE4,
+	0x90, 0x81, 0x27, 0xF0, 0xA3, 0xF0, 0x90, 0x81,
+	0x26, 0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0,
+	0x90, 0x81, 0x24, 0xE0, 0x54, 0xFD, 0xF0, 0x54,
+	0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x2D,
+	0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x24,
+	0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB,
+	0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81,
+	0x2F, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xE4,
+	0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81,
+	0x2B, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFE,
+	0xF0, 0x90, 0x81, 0x29, 0x74, 0x0C, 0xF0, 0x90,
+	0x81, 0x24, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81,
+	0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0,
+	0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0,
+	0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7,
+	0xF0, 0x90, 0x81, 0x34, 0x12, 0x20, 0xDA, 0x00,
+	0x00, 0x00, 0x00, 0x90, 0x80, 0x3C, 0xE0, 0xB4,
+	0x01, 0x08, 0x90, 0x81, 0x31, 0x74, 0x99, 0xF0,
+	0x80, 0x12, 0x90, 0x80, 0x3C, 0xE0, 0x90, 0x81,
+	0x31, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80,
+	0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, 0x38, 0x74,
+	0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0,
+	0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05,
+	0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD,
+	0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54,
+	0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0,
+	0xE4, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x59,
+	0xF0, 0x90, 0x81, 0x59, 0xE0, 0x64, 0x01, 0xF0,
+	0x24, 0x24, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5C,
+	0xA3, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0xFF, 0x90,
+	0x81, 0x29, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x47,
+	0x2A, 0xD1, 0x08, 0xBF, 0x01, 0x02, 0x91, 0x5F,
+	0xB1, 0xF2, 0x12, 0x32, 0x9E, 0xBF, 0x01, 0x02,
+	0xB1, 0x67, 0x12, 0x42, 0x4D, 0x80, 0xCA, 0xD3,
+	0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81,
+	0x24, 0xE0, 0x30, 0xE0, 0x24, 0x90, 0x81, 0x1F,
+	0xE0, 0xFF, 0x30, 0xE0, 0x1A, 0xC3, 0x13, 0x30,
+	0xE0, 0x07, 0xB1, 0xFB, 0xBF, 0x01, 0x12, 0x80,
+	0x0A, 0x90, 0x81, 0x23, 0xE0, 0xFF, 0x60, 0x03,
+	0xB4, 0x08, 0x06, 0x91, 0x96, 0x80, 0x02, 0x91,
+	0xA6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10,
+	0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xB1, 0x22, 0x91,
+	0xBA, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81,
+	0x2A, 0xE0, 0x70, 0x0D, 0xD1, 0x2F, 0xBF, 0x01,
+	0x08, 0x91, 0x96, 0x90, 0x01, 0xE5, 0xE0, 0x04,
+	0xF0, 0x22, 0xB1, 0xF3, 0x90, 0x00, 0x08, 0xE0,
+	0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E,
+	0xE4, 0xFF, 0x8F, 0x50, 0xE4, 0x90, 0x81, 0x5A,
+	0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F,
+	0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65,
+	0x50, 0x60, 0x3E, 0xC3, 0x90, 0x81, 0x5B, 0xE0,
+	0x94, 0x88, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x13,
+	0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10,
+	0xF0, 0x22, 0x90, 0x81, 0x5A, 0xE4, 0x75, 0xF0,
+	0x01, 0x12, 0x44, 0xA9, 0x7F, 0x14, 0x7E, 0x00,
+	0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x5B, 0xE0,
+	0x94, 0x32, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x00,
+	0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0,
+	0xB2, 0x22, 0x90, 0x81, 0x31, 0xE0, 0xFD, 0x7F,
+	0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x28, 0xE0,
+	0x60, 0x12, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7,
+	0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01,
+	0x2F, 0x74, 0x90, 0xF0, 0x90, 0x00, 0x08, 0xE0,
+	0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E,
+	0x7F, 0x01, 0x91, 0xCA, 0x90, 0x00, 0x90, 0xE0,
+	0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E,
+	0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0xAA, 0xD3,
+	0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x2D,
+	0xA7, 0xE4, 0xF5, 0x52, 0x12, 0x32, 0x9E, 0xEF,
+	0x60, 0x73, 0x63, 0x52, 0x01, 0xE5, 0x52, 0x24,
+	0x67, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5D, 0xA3,
+	0xF0, 0x90, 0x00, 0x88, 0xE0, 0xF5, 0x50, 0xF5,
+	0x51, 0x54, 0x0F, 0x60, 0xDF, 0xE5, 0x50, 0x30,
+	0xE0, 0x0B, 0x20, 0xE4, 0x03, 0x12, 0x29, 0xC5,
+	0x53, 0x51, 0xEE, 0x80, 0x3F, 0xE5, 0x50, 0x30,
+	0xE1, 0x16, 0x20, 0xE5, 0x0E, 0x12, 0x11, 0xBD,
+	0xEF, 0x70, 0x03, 0x43, 0x51, 0x20, 0x90, 0x01,
+	0x06, 0xE4, 0xF0, 0x53, 0x51, 0xFD, 0x80, 0x24,
+	0xE5, 0x50, 0x30, 0xE2, 0x0B, 0x20, 0xE6, 0x03,
+	0x12, 0x67, 0x06, 0x53, 0x51, 0xFB, 0x80, 0x14,
+	0xE5, 0x50, 0x30, 0xE3, 0x0F, 0x20, 0xE7, 0x09,
+	0x12, 0x61, 0x6E, 0xEF, 0x70, 0x03, 0x43, 0x51,
+	0x80, 0x53, 0x51, 0xF7, 0xAD, 0x51, 0x7F, 0x88,
+	0x12, 0x32, 0x1E, 0x80, 0x87, 0xD0, 0xD0, 0x92,
+	0xAF, 0x22, 0x22, 0x90, 0x00, 0x90, 0xE0, 0x20,
+	0xE0, 0xF9, 0x22, 0x90, 0x81, 0x22, 0xE0, 0x64,
+	0x02, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22,
+	0x7F, 0x02, 0x90, 0x81, 0x41, 0xE0, 0xFE, 0xEF,
+	0xC3, 0x9E, 0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24,
+	0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, 0x90, 0x01,
+	0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00,
+	0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, 0x22, 0x90,
+	0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8,
+	0x74, 0x01, 0xF0, 0x80, 0x17, 0x90, 0x02, 0x86,
+	0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74,
+	0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4,
+	0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74,
+	0x08, 0xF0, 0x7F, 0x00, 0x22, 0xE4, 0xFB, 0xFA,
+	0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81,
+	0xBD, 0xEF, 0xF0, 0x60, 0xF0, 0xD1, 0x71, 0x80,
+	0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0,
+	0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x81,
+	0xBE, 0xF0, 0x90, 0x81, 0xBE, 0xE0, 0xFD, 0x70,
+	0x02, 0xE1, 0x9C, 0x90, 0x82, 0x09, 0xE0, 0xFF,
+	0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80,
+	0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9,
+	0xFF, 0xEF, 0x5D, 0x70, 0x02, 0xE1, 0x95, 0x90,
+	0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01,
+	0xD0, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xBF,
+	0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, 0x75,
+	0x15, 0xBF, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A,
+	0x81, 0x79, 0xC0, 0x12, 0x2B, 0xED, 0x90, 0x82,
+	0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1,
+	0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC1, 0xF0,
+	0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90,
+	0x01, 0xD2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81,
+	0xC2, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0,
+	0x04, 0x90, 0x01, 0xD3, 0x12, 0x45, 0x0A, 0xE0,
+	0x90, 0x81, 0xC3, 0xF0, 0x90, 0x82, 0x09, 0xE0,
+	0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x45,
+	0x0A, 0xE0, 0x90, 0x81, 0xC4, 0xF0, 0x90, 0x82,
+	0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1,
+	0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC5, 0xF0,
+	0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90,
+	0x01, 0xF2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81,
+	0xC6, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0,
+	0x04, 0x90, 0x01, 0xF3, 0x12, 0x45, 0x0A, 0xE0,
+	0x90, 0x81, 0xC7, 0xF0, 0x90, 0x81, 0xBE, 0xE0,
+	0xFF, 0x90, 0x82, 0x09, 0xE0, 0xFE, 0x74, 0x01,
+	0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+	0xFC, 0xF4, 0x5F, 0x90, 0x81, 0xBE, 0xF0, 0x90,
+	0x82, 0x09, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07,
+	0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90,
+	0x01, 0xCC, 0xF0, 0x90, 0x81, 0xC0, 0xE0, 0xFF,
+	0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC1, 0x12, 0x55,
+	0x3F, 0x90, 0x82, 0x09, 0xE0, 0x04, 0xF0, 0xE0,
+	0x54, 0x03, 0xF0, 0xC1, 0x82, 0x90, 0x01, 0xC0,
+	0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF,
+	0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12,
+	0x44, 0x4E, 0x90, 0x81, 0xD0, 0xEF, 0xF0, 0x60,
+	0xF0, 0x12, 0x6C, 0x19, 0x80, 0xEB, 0x90, 0x81,
+	0xD4, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12,
+	0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90,
+	0x81, 0xE2, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12,
+	0x2D, 0x5C, 0x90, 0x81, 0xDA, 0x12, 0x20, 0xCE,
+	0x90, 0x81, 0xD4, 0xE0, 0xFB, 0x70, 0x08, 0x90,
+	0x81, 0xDA, 0x12, 0x44, 0xD9, 0x80, 0x16, 0xEB,
+	0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82,
+	0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3,
+	0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x81, 0xDE,
+	0x12, 0x20, 0xCE, 0x90, 0x81, 0xD5, 0xE0, 0xFF,
+	0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20,
+	0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB,
+	0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0xED,
+	0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12,
+	0x44, 0xCC, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x81,
+	0xDE, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDA, 0x12,
+	0x44, 0xD9, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85,
+	0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08,
+	0x12, 0x2E, 0xA2, 0x90, 0x81, 0xD4, 0xE0, 0x75,
+	0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4,
+	0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0,
+	0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xDE,
+	0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20,
+	0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2,
+	0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x44,
+	0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE,
+	0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90,
+	0x81, 0xD4, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80,
+	0x09, 0x90, 0x81, 0xD4, 0xE0, 0xB4, 0x01, 0x16,
+	0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78,
+	0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF,
+	0xE4, 0x90, 0x81, 0xE2, 0xEF, 0xF0, 0x90, 0x81,
+	0xE2, 0xE0, 0x90, 0x81, 0xD4, 0x60, 0x0E, 0xE0,
+	0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82,
+	0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0,
+	0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34,
+	0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF,
+	0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4,
+	0xFC, 0x90, 0x81, 0xD6, 0x12, 0x20, 0xCE, 0x90,
+	0x81, 0xD6, 0x02, 0x44, 0xD9, 0x90, 0x81, 0xE3,
+	0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x81, 0xE9, 0x12,
+	0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03,
+	0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20,
+	0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB,
+	0x07, 0x90, 0x81, 0xE5, 0x12, 0x44, 0xD9, 0xED,
+	0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x44, 0xCC,
+	0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x81, 0xE9, 0x12,
+	0x20, 0xCE, 0x90, 0x81, 0xE3, 0xE0, 0x75, 0xF0,
+	0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34,
+	0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF,
+	0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xE9, 0x12,
+	0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE,
+	0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3,
+	0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x5F,
+	0xB6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x78, 0x10,
+	0x74, 0x01, 0xF2, 0x90, 0x02, 0x09, 0xE0, 0x78,
+	0x00, 0xF2, 0x08, 0x74, 0x20, 0xF2, 0x18, 0xE2,
+	0xFF, 0x30, 0xE0, 0x05, 0x08, 0xE2, 0x24, 0x80,
+	0xF2, 0xEF, 0xC3, 0x13, 0x90, 0xFD, 0x10, 0xF0,
+	0x78, 0x01, 0xE2, 0x24, 0x00, 0xF5, 0x82, 0xE4,
+	0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x78, 0x03, 0xF2,
+	0x64, 0x04, 0x60, 0x0D, 0xE2, 0xFF, 0x64, 0x08,
+	0x60, 0x07, 0xEF, 0x64, 0x0C, 0x60, 0x02, 0x61,
+	0xDE, 0xE4, 0x78, 0x02, 0xF2, 0x78, 0x03, 0xE2,
+	0xFF, 0x18, 0xE2, 0xC3, 0x9F, 0x50, 0x2D, 0xE2,
+	0xFD, 0x18, 0xE2, 0x2D, 0x90, 0x81, 0x5A, 0xF0,
+	0xE0, 0xFF, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34,
+	0xFC, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x04, 0x2D,
+	0xF8, 0xEE, 0xF2, 0xEF, 0xB4, 0xFF, 0x06, 0x90,
+	0xFD, 0x10, 0xE0, 0x04, 0xF0, 0x78, 0x02, 0xE2,
+	0x04, 0xF2, 0x80, 0xC9, 0x78, 0x04, 0xE2, 0x78,
+	0x12, 0xF2, 0xFF, 0x78, 0x05, 0xE2, 0x78, 0x11,
+	0xF2, 0x78, 0x06, 0xE2, 0x78, 0x13, 0xF2, 0x78,
+	0x07, 0xE2, 0x78, 0x14, 0xF2, 0x78, 0x08, 0xE2,
+	0x78, 0x33, 0xF2, 0x78, 0x09, 0xE2, 0x78, 0x34,
+	0xF2, 0x78, 0x0A, 0xE2, 0x78, 0x35, 0xF2, 0x78,
+	0x0B, 0xE2, 0x78, 0x36, 0xF2, 0x78, 0x0C, 0xE2,
+	0x78, 0x37, 0xF2, 0x78, 0x0D, 0xE2, 0x78, 0x38,
+	0xF2, 0x78, 0x0E, 0xE2, 0x78, 0x39, 0xF2, 0x78,
+	0x0F, 0xE2, 0x78, 0x3A, 0xF2, 0xE4, 0x78, 0x15,
+	0xF2, 0xEF, 0x24, 0xF8, 0x60, 0x75, 0x24, 0xFC,
+	0x60, 0x6C, 0x24, 0x08, 0x60, 0x02, 0x61, 0xC0,
+	0x78, 0x11, 0xE2, 0xB4, 0x01, 0x05, 0x12, 0x29,
+	0xC5, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x02,
+	0x05, 0x12, 0x11, 0xBD, 0x61, 0xC5, 0x78, 0x11,
+	0xE2, 0xB4, 0x03, 0x04, 0xF1, 0x06, 0x61, 0xC5,
+	0x78, 0x11, 0xE2, 0xB4, 0x10, 0x17, 0x78, 0x14,
+	0xE2, 0xFE, 0x18, 0xE2, 0xFD, 0xED, 0xFF, 0x78,
+	0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF,
+	0x12, 0x32, 0xAA, 0x61, 0xC5, 0x78, 0x11, 0xE2,
+	0xB4, 0x11, 0x17, 0x78, 0x14, 0xE2, 0xFE, 0x18,
+	0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2,
+	0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, 0x32, 0x06,
+	0x61, 0xC5, 0x78, 0x11, 0xE2, 0xF4, 0x60, 0x02,
+	0x61, 0xC5, 0x18, 0xF2, 0x61, 0xC5, 0x78, 0x15,
+	0x74, 0x01, 0xF2, 0x78, 0x11, 0xE2, 0x64, 0x07,
+	0x60, 0x02, 0x61, 0xAA, 0x78, 0x34, 0xE2, 0xFF,
+	0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20,
+	0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB,
+	0x07, 0x78, 0x33, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD,
+	0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04,
+	0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x35,
+	0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10,
+	0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0,
+	0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18,
+	0x12, 0x44, 0xFE, 0x78, 0x15, 0xE2, 0x70, 0x02,
+	0x61, 0x93, 0x18, 0xE2, 0xFF, 0x18, 0xE2, 0xFD,
+	0x31, 0x5F, 0x78, 0x1C, 0x12, 0x44, 0xFE, 0x78,
+	0x38, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78,
+	0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05,
+	0xAA, 0x06, 0xAB, 0x07, 0x78, 0x37, 0xE2, 0xFF,
+	0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44,
+	0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0,
+	0x07, 0x78, 0x39, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD,
+	0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03,
+	0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44,
+	0xCC, 0x78, 0x20, 0x12, 0x44, 0xFE, 0x78, 0x20,
+	0x12, 0x44, 0xE5, 0x12, 0x20, 0x9B, 0x78, 0x1C,
+	0x12, 0x44, 0xF1, 0x12, 0x44, 0xBF, 0xC0, 0x04,
+	0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x18,
+	0x12, 0x44, 0xE5, 0x78, 0x20, 0x12, 0x44, 0xF1,
+	0x12, 0x44, 0xBF, 0xD0, 0x03, 0xD0, 0x02, 0xD0,
+	0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18,
+	0x12, 0x44, 0xFE, 0x78, 0x18, 0x12, 0x44, 0xE5,
+	0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x78, 0x13,
+	0xE2, 0xFD, 0x08, 0xE2, 0xFF, 0x12, 0x55, 0x1C,
+	0x80, 0x1B, 0x78, 0x13, 0xE2, 0xFF, 0x08, 0xE2,
+	0xFD, 0x78, 0x11, 0xE2, 0xFB, 0x78, 0x15, 0xE2,
+	0x90, 0x81, 0xBC, 0xF0, 0x71, 0xE1, 0x80, 0x05,
+	0x78, 0x10, 0x74, 0x02, 0xF2, 0x78, 0x10, 0xE2,
+	0xFF, 0xC3, 0x94, 0x02, 0x50, 0x10, 0xEF, 0x60,
+	0x0A, 0x78, 0x02, 0xE2, 0xFF, 0x18, 0xE2, 0x2F,
+	0xF2, 0x21, 0x90, 0x7F, 0x01, 0x22, 0x7F, 0x00,
+	0x22, 0xAC, 0x07, 0xED, 0xAD, 0x04, 0x78, 0x24,
+	0xF2, 0xED, 0x08, 0xF2, 0xEB, 0xB4, 0x04, 0x07,
+	0x78, 0x27, 0x74, 0x01, 0xF2, 0x80, 0x0E, 0xEB,
+	0x78, 0x27, 0xB4, 0x05, 0x05, 0x74, 0x02, 0xF2,
+	0x80, 0x03, 0x74, 0x04, 0xF2, 0xD3, 0x78, 0x25,
+	0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x00, 0x50,
+	0x63, 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2,
+	0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02,
+	0xA1, 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78,
+	0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D,
+	0x74, 0x37, 0x2E, 0xF8, 0xE2, 0x78, 0x32, 0xF2,
+	0xEE, 0xFF, 0x78, 0x25, 0xE2, 0x2F, 0xFF, 0x18,
+	0xE2, 0x34, 0x00, 0x8F, 0x82, 0xF5, 0x83, 0xE0,
+	0x78, 0x29, 0xF2, 0x78, 0x32, 0xE2, 0xFF, 0xF4,
+	0xFE, 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2,
+	0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x24, 0x08,
+	0xE2, 0xFF, 0x08, 0xE2, 0x2F, 0xFF, 0x78, 0x28,
+	0xE2, 0xFD, 0x12, 0x32, 0x1E, 0x78, 0x26, 0xE2,
+	0x04, 0xF2, 0x80, 0xA1, 0xD3, 0x78, 0x25, 0xE2,
+	0x94, 0xFF, 0x18, 0xE2, 0x94, 0x07, 0x50, 0x69,
+	0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF,
+	0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0xA1,
+	0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28,
+	0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, 0x78,
+	0x26, 0xE2, 0xFF, 0xFD, 0x18, 0xE2, 0x2D, 0xFD,
+	0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83,
+	0xE0, 0x78, 0x29, 0xF2, 0x74, 0x37, 0x2F, 0xF8,
+	0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFF, 0xF4, 0xFE,
+	0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD,
+	0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x28, 0xE2, 0xFF,
+	0x78, 0x26, 0xE2, 0xFD, 0x18, 0xE2, 0x2D, 0xFD,
+	0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83,
+	0xEF, 0xF0, 0x78, 0x26, 0xE2, 0x04, 0xF2, 0x80,
+	0x9B, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x0F, 0x78,
+	0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2D,
+	0x5C, 0x78, 0x2E, 0x12, 0x44, 0xFE, 0xE4, 0x78,
+	0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2,
+	0xFE, 0xC3, 0x9F, 0x50, 0x5D, 0x74, 0x33, 0x2E,
+	0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC,
+	0xE0, 0x60, 0x2B, 0x78, 0x2E, 0x12, 0x44, 0xE5,
+	0x78, 0x26, 0xE2, 0xFB, 0x75, 0xF0, 0x08, 0xA4,
+	0xF9, 0xF8, 0x12, 0x20, 0xA8, 0x78, 0x29, 0xEF,
+	0xF2, 0x74, 0x37, 0x2B, 0xF8, 0xE2, 0x78, 0x32,
+	0xF2, 0xE2, 0xFE, 0xF4, 0x5F, 0xFF, 0x78, 0x28,
+	0xE2, 0xFD, 0xEE, 0x5D, 0x4F, 0xF2, 0x78, 0x28,
+	0xE2, 0xFF, 0x78, 0x26, 0xE2, 0xFD, 0xC3, 0x74,
+	0x03, 0x9D, 0xFD, 0xE4, 0x94, 0x00, 0xFC, 0x7B,
+	0xFE, 0x74, 0x2A, 0x2D, 0xF9, 0x74, 0x80, 0x3C,
+	0xFA, 0xEF, 0x12, 0x1F, 0xEA, 0xE2, 0x04, 0xF2,
+	0x80, 0x98, 0x78, 0x2A, 0x12, 0x44, 0xE5, 0x90,
+	0x85, 0xBB, 0x12, 0x20, 0xCE, 0x78, 0x24, 0xE2,
+	0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2E, 0xA2, 0x22,
+	0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x90,
+	0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xFE, 0x12,
+	0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12,
+	0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00,
+	0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xCF, 0xF0,
+	0x80, 0x05, 0x90, 0x81, 0xCF, 0xEF, 0xF0, 0x90,
+	0x81, 0xCE, 0xEE, 0xF0, 0x90, 0x81, 0xCF, 0xE0,
+	0xFE, 0x90, 0x81, 0xCE, 0xE0, 0xFF, 0xD3, 0x9E,
+	0x50, 0x38, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16,
+	0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, 0x74, 0xDE,
+	0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83,
+	0xEE, 0xF0, 0x74, 0xDE, 0x2F, 0xF5, 0x82, 0xE4,
+	0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xD1,
+	0x25, 0x80, 0x07, 0x90, 0x81, 0xCE, 0xE0, 0xFF,
+	0xB1, 0x80, 0x90, 0x81, 0xCE, 0xE0, 0x04, 0xF0,
+	0x80, 0xBA, 0x90, 0x80, 0xDE, 0xE0, 0x70, 0x24,
+	0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0xFF, 0x12,
+	0x49, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C,
+	0x60, 0x02, 0xD1, 0x26, 0x90, 0x81, 0x24, 0xE0,
+	0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xBF,
+	0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x90, 0x06,
+	0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22,
+	0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0,
+	0x22, 0x90, 0x81, 0xED, 0xEF, 0xF0, 0xA3, 0xED,
+	0xF0, 0xAD, 0x03, 0xAC, 0x02, 0xE4, 0x90, 0x81,
+	0xF5, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74,
+	0x39, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0xEC, 0x54,
+	0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE,
+	0x04, 0xEE, 0xA3, 0xF0, 0x90, 0x81, 0xED, 0xE0,
+	0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C,
+	0x24, 0x3C, 0x70, 0x41, 0x90, 0x81, 0xEE, 0xE0,
+	0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x81,
+	0xF2, 0xF0, 0xA3, 0x74, 0x69, 0xF0, 0xA3, 0x74,
+	0x80, 0xF0, 0x80, 0x2C, 0x90, 0x81, 0xEE, 0xE0,
+	0x54, 0x01, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74,
+	0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18,
+	0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x54, 0x10, 0x90,
+	0x81, 0xF2, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3,
+	0x74, 0x10, 0xF0, 0x80, 0x03, 0x7F, 0x00, 0x22,
+	0x90, 0x81, 0xF3, 0xE0, 0x90, 0x01, 0x06, 0xF0,
+	0x90, 0x81, 0xF2, 0xE0, 0x60, 0x0E, 0x90, 0x01,
+	0x42, 0xF0, 0x90, 0x81, 0xF1, 0xE0, 0x90, 0x01,
+	0x43, 0xF0, 0x80, 0x0D, 0x90, 0x01, 0x43, 0xE4,
+	0xF0, 0x90, 0x81, 0xF2, 0xE0, 0x90, 0x01, 0x42,
+	0xF0, 0x90, 0x81, 0xF4, 0xE0, 0xFF, 0x90, 0x01,
+	0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x81, 0xF2, 0xE0,
+	0x6F, 0x60, 0xEE, 0x74, 0x39, 0x04, 0x90, 0x01,
+	0xC4, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0x90, 0x01,
+	0x43, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90,
+	0x81, 0x6A, 0xF0, 0x90, 0x87, 0x5F, 0xE0, 0x90,
+	0x81, 0x69, 0xF0, 0xE4, 0x90, 0x81, 0x76, 0xF0,
+	0x90, 0x81, 0x66, 0xF0, 0x90, 0x81, 0x66, 0xE0,
+	0xFF, 0xC3, 0x94, 0x40, 0x50, 0x15, 0x74, 0x79,
+	0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83,
+	0x74, 0xFF, 0xF0, 0x90, 0x81, 0x66, 0xE0, 0x04,
+	0xF0, 0x80, 0xE1, 0xE4, 0x90, 0x81, 0x66, 0xF0,
+	0x90, 0x81, 0x69, 0xE0, 0xFF, 0x90, 0x81, 0x66,
+	0xE0, 0xFE, 0xC3, 0x9F, 0x40, 0x03, 0x02, 0x68,
+	0x12, 0x74, 0xDF, 0x2E, 0xF9, 0xE4, 0x34, 0x86,
+	0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75,
+	0x16, 0x0A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5B,
+	0x12, 0x2B, 0xED, 0x90, 0x81, 0x5C, 0xE0, 0xFF,
+	0x12, 0x2F, 0x27, 0xEF, 0x04, 0x90, 0x81, 0x76,
+	0xF0, 0x90, 0x81, 0x5B, 0xE0, 0xFF, 0xA3, 0xE0,
+	0xFD, 0x12, 0x31, 0xEA, 0xEF, 0x24, 0xC8, 0x90,
+	0x81, 0x78, 0xF0, 0x75, 0xF0, 0x08, 0xA4, 0xF0,
+	0x90, 0x81, 0x5C, 0xE0, 0x54, 0x0F, 0x90, 0x81,
+	0x77, 0xF0, 0xE4, 0x90, 0x81, 0x65, 0xF0, 0x90,
+	0x81, 0x67, 0xF0, 0x90, 0x81, 0x67, 0xE0, 0xFF,
+	0xC3, 0x94, 0x04, 0x50, 0x57, 0x90, 0x81, 0x77,
+	0xE0, 0xFE, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3,
+	0x13, 0xD8, 0xFC, 0x20, 0xE0, 0x3E, 0x90, 0x81,
+	0x67, 0xE0, 0x25, 0xE0, 0xFF, 0x90, 0x81, 0x78,
+	0xE0, 0x2F, 0x24, 0x79, 0xF9, 0xE4, 0x34, 0x81,
+	0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0x90,
+	0x81, 0x65, 0xE0, 0x75, 0xF0, 0x02, 0xA4, 0x24,
+	0x5D, 0xF9, 0x74, 0x81, 0x35, 0xF0, 0x8B, 0x13,
+	0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0xD0,
+	0x01, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x81,
+	0x65, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x67, 0xE0,
+	0x04, 0xF0, 0x80, 0x9F, 0x90, 0x81, 0x76, 0xE0,
+	0xFF, 0x90, 0x81, 0x66, 0xE0, 0x2F, 0xF0, 0x02,
+	0x67, 0x40, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90,
+	0x81, 0x6A, 0xE0, 0xC3, 0x94, 0x40, 0x40, 0x02,
+	0x41, 0xAF, 0xE0, 0xFF, 0x24, 0x79, 0xF5, 0x82,
+	0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81,
+	0x6C, 0xF0, 0xE0, 0xFE, 0x54, 0xF0, 0xC4, 0x54,
+	0x0F, 0xFD, 0x90, 0x81, 0x6B, 0xF0, 0xEE, 0x54,
+	0x0F, 0xFE, 0xA3, 0xF0, 0x74, 0x7A, 0x2F, 0xF5,
+	0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90,
+	0x81, 0x6D, 0xF0, 0xFC, 0xEE, 0xFE, 0xEC, 0xFB,
+	0xEB, 0xFF, 0x90, 0x81, 0x72, 0xEE, 0xF0, 0xA3,
+	0xEF, 0xF0, 0xED, 0x12, 0x45, 0x28, 0x68, 0x8B,
+	0x00, 0x68, 0xC2, 0x01, 0x69, 0x73, 0x02, 0x6A,
+	0xA0, 0x03, 0x69, 0x8E, 0x04, 0x69, 0xAF, 0x05,
+	0x69, 0xAF, 0x06, 0x69, 0xAF, 0x07, 0x69, 0xAF,
+	0x08, 0x6A, 0x33, 0x09, 0x6A, 0x69, 0x0A, 0x00,
+	0x00, 0x6A, 0xAF, 0x90, 0x81, 0x6A, 0xE0, 0xFD,
+	0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5,
+	0x83, 0xE0, 0xFE, 0x74, 0x7B, 0x2D, 0xF5, 0x82,
+	0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFD, 0xED,
+	0xFF, 0x90, 0x81, 0x74, 0xEE, 0xF0, 0xFC, 0xA3,
+	0xEF, 0xF0, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x12,
+	0x2F, 0x96, 0x90, 0x81, 0x68, 0x74, 0x02, 0xF0,
+	0x41, 0xA0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C,
+	0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0,
+	0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12,
+	0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06,
+	0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B,
+	0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0,
+	0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC,
+	0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07,
+	0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7D, 0xF5, 0x82,
+	0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4,
+	0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB,
+	0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00,
+	0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0,
+	0x06, 0xC0, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24,
+	0x7E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83,
+	0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x18,
+	0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0,
+	0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81,
+	0x6E, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6E, 0x12,
+	0x44, 0xD9, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE,
+	0x90, 0x81, 0x72, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF,
+	0x12, 0x2E, 0xE4, 0x90, 0x81, 0x68, 0x74, 0x04,
+	0xF0, 0x41, 0xA0, 0x90, 0x81, 0x6D, 0xE0, 0xFD,
+	0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82,
+	0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4,
+	0xFF, 0x12, 0x30, 0xC7, 0x80, 0x19, 0x90, 0x81,
+	0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24,
+	0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83,
+	0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0x6A, 0x90,
+	0x81, 0x68, 0x74, 0x01, 0xF0, 0x41, 0xA0, 0x90,
+	0x81, 0x68, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x6A,
+	0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81,
+	0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE,
+	0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9,
+	0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6A,
+	0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81,
+	0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE,
+	0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0,
+	0x06, 0xC0, 0x07, 0x90, 0x81, 0x6C, 0xE0, 0xFF,
+	0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20,
+	0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0,
+	0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, 0x6E, 0x12,
+	0x20, 0xCE, 0x90, 0x81, 0x6B, 0xE0, 0x24, 0xFB,
+	0xFF, 0xC0, 0x07, 0x90, 0x81, 0x6E, 0x12, 0x44,
+	0xD9, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x90,
+	0x81, 0x6D, 0xE0, 0xFD, 0xD0, 0x07, 0x12, 0x55,
+	0x1C, 0x80, 0x6D, 0x90, 0x81, 0x68, 0x74, 0x01,
+	0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9,
+	0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14,
+	0x89, 0x15, 0x75, 0x16, 0x01, 0x7B, 0xFE, 0x7A,
+	0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81,
+	0x6D, 0xE0, 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD,
+	0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x04, 0x80,
+	0x34, 0x90, 0x81, 0x68, 0x74, 0x04, 0xF0, 0x90,
+	0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, 0xE4, 0x34,
+	0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15,
+	0x75, 0x16, 0x04, 0x7B, 0xFE, 0x7A, 0x80, 0x79,
+	0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0,
+	0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, 0xE4, 0x90,
+	0x81, 0xBC, 0xF0, 0x7B, 0x06, 0x12, 0x63, 0xE1,
+	0x90, 0x81, 0x68, 0xE0, 0x24, 0x02, 0xFF, 0x90,
+	0x81, 0x6A, 0xE0, 0x2F, 0xF0, 0x01, 0x17, 0x22,
+	0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4,
+	0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x3D,
+	0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF,
+	0xED, 0x2F, 0x90, 0x80, 0x3E, 0xF0, 0x90, 0x00,
+	0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90,
+	0x80, 0x3F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F,
+	0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x40, 0xF0,
+	0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE,
+	0x05, 0xED, 0x2F, 0x90, 0x80, 0x41, 0xF0, 0x22,
+	0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x30,
+	0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x38,
+	0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90,
+	0x81, 0x39, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3,
+	0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03,
+	0x12, 0x1F, 0xBD, 0x90, 0x81, 0x3B, 0xF0, 0x22,
+	0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74,
+	0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28,
+	0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x12, 0x1F,
+	0xA4, 0x90, 0x81, 0x3E, 0xF0, 0x90, 0x81, 0x3E,
+	0xE0, 0x90, 0x01, 0xE7, 0xF0, 0x22, 0x12, 0x1F,
+	0xA4, 0x90, 0x81, 0x4A, 0xF0, 0x90, 0x00, 0x01,
+	0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4B, 0xF0, 0x22,
+	0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90,
+	0x81, 0xFD, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4,
+	0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0xFD, 0xE0,
+	0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0,
+	0x60, 0x2D, 0xC3, 0x90, 0x82, 0x00, 0xE0, 0x94,
+	0xE8, 0x90, 0x81, 0xFF, 0xE0, 0x94, 0x03, 0x40,
+	0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0,
+	0x7F, 0x00, 0x80, 0x15, 0x90, 0x81, 0xFF, 0xE4,
+	0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x0A,
+	0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F,
+	0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10,
+	0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xD1,
+	0x12, 0x45, 0x1F, 0x90, 0x82, 0x0A, 0xE0, 0xFF,
+	0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F,
+	0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x60, 0xEF,
+	0x60, 0x3A, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16,
+	0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00,
+	0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16,
+	0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B,
+	0xED, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, 0x90,
+	0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE,
+	0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB,
+	0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF,
+	0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0,
+	0xE4, 0xFF, 0x90, 0x80, 0xD9, 0xE0, 0xFE, 0x90,
+	0x80, 0xD8, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E,
+	0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01,
+	0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13,
+	0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x42, 0xF9,
+	0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x71,
+	0xB6, 0x7F, 0x01, 0xEF, 0x60, 0x16, 0x90, 0x80,
+	0xD8, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4,
+	0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4,
+	0x90, 0x80, 0xD8, 0xF0, 0xD0, 0xD0, 0x92, 0xAF,
+	0x22, 0x8F, 0x0D, 0x22, 0x8F, 0x0E, 0x22, 0x22,
+	0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41,
+	0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, 0xE0,
+	0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40,
+	0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, 0xF0,
+	0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0,
+	0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, 0x3C,
+	0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55,
+	0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, 0xF5,
+	0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90,
+	0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, 0x4A,
+	0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C,
+	0xF0, 0x53, 0x91, 0xDF, 0x22, 0x90, 0x81, 0x1F,
+	0xE0, 0x30, 0xE0, 0x05, 0xE4, 0xA3, 0xF0, 0xA3,
+	0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01,
+	0x70, 0x19, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x13,
+	0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C,
+	0x74, 0x02, 0x12, 0x4F, 0xF4, 0x90, 0x01, 0x57,
+	0x74, 0x05, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0,
+	0x64, 0x01, 0x70, 0x26, 0x90, 0x81, 0x27, 0xE0,
+	0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90,
+	0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24,
+	0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0,
+	0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x03, 0x12,
+	0x47, 0x2A, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0xB4,
+	0x01, 0x14, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0E,
+	0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02,
+	0x60, 0x02, 0x80, 0x03, 0xD1, 0x7F, 0x22, 0x90,
+	0x04, 0x1D, 0xE0, 0x70, 0x13, 0x90, 0x80, 0x3E,
+	0xE0, 0xFF, 0xE4, 0xFD, 0xB1, 0x69, 0x8E, 0x4E,
+	0x8F, 0x4F, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0,
+	0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0,
+	0x90, 0x82, 0x0E, 0xED, 0xF0, 0x90, 0x82, 0x0D,
+	0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0xF1, 0x37, 0x7C,
+	0x00, 0xAD, 0x07, 0x90, 0x82, 0x0D, 0xE0, 0x90,
+	0x04, 0x25, 0xF0, 0x90, 0x82, 0x0E, 0xE0, 0x60,
+	0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34,
+	0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF,
+	0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34,
+	0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F,
+	0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0,
+	0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82,
+	0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7,
+	0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92,
+	0xAF, 0x22, 0x8F, 0x4E, 0xF1, 0x4B, 0xBF, 0x01,
+	0x18, 0x90, 0x80, 0x40, 0xE0, 0xFF, 0x7D, 0x01,
+	0xB1, 0x69, 0xAD, 0x07, 0xAC, 0x06, 0xAF, 0x4E,
+	0x12, 0x4F, 0x82, 0x90, 0x04, 0x1F, 0x74, 0x20,
+	0xF0, 0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81,
+	0x4C, 0xF0, 0xE0, 0xFD, 0x54, 0xC0, 0x70, 0x09,
+	0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x80,
+	0x72, 0xED, 0x30, 0xE6, 0x4B, 0x90, 0x81, 0x27,
+	0xE0, 0x64, 0x02, 0x70, 0x2A, 0x90, 0x81, 0x24,
+	0xE0, 0xFF, 0xC3, 0x13, 0x20, 0xE0, 0x09, 0x90,
+	0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x28,
+	0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x01,
+	0x70, 0x2D, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x04,
+	0xF0, 0x7F, 0x01, 0xB1, 0xD2, 0x80, 0x20, 0x90,
+	0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81,
+	0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04,
+	0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07,
+	0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90,
+	0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7,
+	0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74,
+	0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04,
+	0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90,
+	0x01, 0x5F, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74,
+	0x08, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+	0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+	0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50,
+	0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90,
+	0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24,
+	0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x2A, 0xE0,
+	0x64, 0x0C, 0x60, 0x0C, 0xE4, 0xFD, 0x7F, 0x0C,
+	0x12, 0x47, 0x3D, 0xE4, 0xFF, 0x12, 0x4F, 0x0D,
+	0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x06,
+	0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0x54,
+	0xC0, 0x70, 0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54,
+	0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x47, 0x2A,
+	0x90, 0x81, 0x4C, 0xE0, 0x30, 0xE6, 0x21, 0x90,
+	0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90,
+	0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81,
+	0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04,
+	0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07,
+	0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90,
+	0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7,
+	0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74,
+	0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04,
+	0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0xE4,
+	0xFE, 0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0,
+	0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0,
+	0xAF, 0x06, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3,
+	0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A,
+	0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07,
+	0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90,
+	0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00,
+	0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF,
+	0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12,
+	0x73, 0xE1, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0,
+	0x03, 0x12, 0x49, 0xDD, 0x22, 0x90, 0x81, 0x27,
+	0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30,
+	0xE1, 0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A,
+	0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4,
+	0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50,
+	0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90,
+	0x06, 0x92, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81,
+	0x24, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x47, 0x2A,
+	0x22, 0x12, 0x71, 0x48, 0x90, 0x81, 0x4D, 0xEF,
+	0xF0, 0x90, 0x81, 0x24, 0x30, 0xE0, 0x06, 0xE0,
+	0x44, 0x01, 0xF0, 0x80, 0x04, 0xE0, 0x54, 0xFE,
+	0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x30, 0xE6, 0x11,
+	0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4,
+	0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80,
+	0xF0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x1A,
+	0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x07,
+	0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05,
+	0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD,
+	0xF0, 0x22, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22,
+	0xF0, 0x22, 0x90, 0x81, 0x4A, 0xE0, 0x60, 0x0F,
+	0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x01,
+	0xF0, 0x90, 0x05, 0xFD, 0xE0, 0x04, 0xF0, 0x22,
+	0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13,
+	0x54, 0x03, 0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF,
+	0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25,
+	0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80,
+	0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9,
+	0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04,
+	0xF0, 0x12, 0x47, 0x2A, 0xE4, 0xFF, 0x90, 0x81,
+	0x45, 0xE0, 0x30, 0xE0, 0x48, 0x90, 0x81, 0x49,
+	0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00,
+	0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE,
+	0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0,
+	0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90,
+	0x81, 0x49, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0,
+	0xD3, 0x9D, 0x50, 0x10, 0x90, 0x01, 0xC7, 0x74,
+	0x10, 0xF0, 0x11, 0xBE, 0x90, 0x81, 0x45, 0xE0,
+	0x54, 0xFE, 0xF0, 0x22, 0x12, 0x4F, 0x0B, 0x90,
+	0x81, 0x49, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80,
+	0x3C, 0xE0, 0x64, 0x02, 0x60, 0x07, 0x90, 0x06,
+	0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x81,
+	0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54,
+	0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0,
+	0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30,
+	0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F,
+	0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74,
+	0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90,
+	0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, 0x47, 0x2A,
+	0x7F, 0x01, 0x01, 0x6E, 0xC3, 0xEE, 0x94, 0x01,
+	0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10,
+	0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94,
+	0x01, 0x40, 0x24, 0x90, 0xFD, 0x11, 0xE0, 0x6D,
+	0x70, 0x1A, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05,
+	0x0D, 0x90, 0x01, 0xE4, 0x74, 0x77, 0xF0, 0x90,
+	0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04,
+	0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22,
+	0xE4, 0x90, 0x81, 0x4E, 0xF0, 0xA3, 0xF0, 0xA3,
+	0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x81, 0x4E,
+	0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x81,
+	0x4E, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3,
+	0x90, 0x81, 0x50, 0xE0, 0x94, 0x64, 0x90, 0x81,
+	0x4F, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01,
+	0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x4E,
+	0xE0, 0xFF, 0x22, 0x90, 0x81, 0x4F, 0xE4, 0x75,
+	0xF0, 0x01, 0x12, 0x44, 0xA9, 0x80, 0xC2, 0x74,
+	0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E,
+	0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4,
+	0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3,
+	0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82,
+	0x12, 0xED, 0xF0, 0x90, 0x82, 0x11, 0xEF, 0xF0,
+	0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74,
+	0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33,
+	0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0,
+	0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90,
+	0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07,
+	0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF,
+	0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46,
+	0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, 0x60,
+	0x18, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01,
+	0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+	0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80,
+	0x17, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01,
+	0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+	0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F,
+	0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x82, 0x11,
+	0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF,
+	0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3,
+	0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43,
+	0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E,
+	0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8,
+	0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC,
+	0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F,
+	0x43, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0,
+	0x60, 0x1D, 0x90, 0x82, 0x11, 0xE0, 0x24, 0x04,
+	0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02,
+	0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42,
+	0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90,
+	0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01,
+	0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8,
+	0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F,
+	0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0,
+	0x92, 0xAF, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54,
+	0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90,
+	0x81, 0x2B, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60,
+	0x0C, 0x04, 0x70, 0x28, 0x90, 0x81, 0x2D, 0x74,
+	0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A,
+	0x90, 0x81, 0x3B, 0xE0, 0x90, 0x81, 0x2D, 0xF0,
+	0x80, 0x05, 0x90, 0x81, 0x2D, 0xED, 0xF0, 0x90,
+	0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x25,
+	0xE0, 0x44, 0x08, 0xF0, 0x22, 0x12, 0x4E, 0xAB,
+	0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8,
+	0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x2B,
+	0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01,
+	0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81,
+	0x29, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08,
+	0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44,
+	0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74,
+	0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x2B, 0xE0,
+	0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10,
+	0xF0, 0x80, 0x29, 0x90, 0x81, 0x25, 0xE0, 0x13,
+	0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01,
+	0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81,
+	0x3E, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74,
+	0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4,
+	0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74,
+	0x04, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x60, 0x42,
+	0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x3A,
+	0x90, 0x81, 0x25, 0xE0, 0x54, 0xFE, 0xF0, 0x90,
+	0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04,
+	0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x4F,
+	0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0,
+	0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x06,
+	0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01,
+	0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74,
+	0x08, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F,
+	0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0,
+	0x90, 0x81, 0x2A, 0x74, 0x02, 0xF0, 0x90, 0x81,
+	0x23, 0xF0, 0x22, 0x12, 0x54, 0x65, 0x90, 0x81,
+	0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0,
+	0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13,
+	0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB,
+	0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0,
+	0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81,
+	0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0,
+	0x54, 0xEF, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0xFF,
+	0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02,
+	0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90,
+	0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0,
+	0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, 0xDE, 0xE0,
+	0xB4, 0x01, 0x0B, 0x90, 0x81, 0x25, 0xE0, 0x54,
+	0xFB, 0xF0, 0x22, 0x12, 0x47, 0x2A, 0x22, 0x22,
+	0x90, 0x05, 0x2B, 0xE0, 0x7F, 0x00, 0x30, 0xE7,
+	0x02, 0x7F, 0x01, 0x22, 0x90, 0x05, 0x22, 0x74,
+	0xFF, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40,
+	0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22,
+	0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x12,
+	0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0,
+	0x22, 0x12, 0x49, 0xE3, 0x90, 0x81, 0x22, 0x74,
+	0x02, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F,
+	0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0,
+	0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xAE,
+	0x07, 0x12, 0x51, 0x73, 0xBF, 0x01, 0x12, 0x90,
+	0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x0A, 0xAF,
+	0x06, 0x7D, 0x01, 0x12, 0x47, 0x3D, 0x7F, 0x01,
+	0x22, 0x7F, 0x00, 0x22, 0x90, 0x01, 0x57, 0xE0,
+	0x60, 0x48, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74,
+	0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13,
+	0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0C, 0xEF, 0x54,
+	0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD,
+	0xF0, 0x22, 0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0,
+	0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90,
+	0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0,
+	0xD3, 0x9F, 0x40, 0x0E, 0x90, 0x80, 0xDE, 0xE0,
+	0xB4, 0x01, 0x07, 0x90, 0x81, 0x25, 0xE0, 0x54,
+	0xFB, 0xF0, 0x22, 0x90, 0x80, 0x3F, 0xE0, 0xFF,
+	0x7D, 0x01, 0x12, 0x6D, 0x69, 0x8E, 0x54, 0x8F,
+	0x55, 0xAD, 0x55, 0xAC, 0x54, 0xAF, 0x53, 0x12,
+	0x4F, 0x82, 0xAF, 0x55, 0xAE, 0x54, 0x90, 0x04,
+	0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74,
+	0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5,
+	0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C,
+	0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0,
+	0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C,
+	0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0,
+	0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82,
+	0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F,
+	0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82,
+	0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F,
+	0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04,
+	0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0,
+	0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14,
+	0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83,
+	0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F,
+	0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED,
+	0xF0, 0x22, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B,
+	0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xDB,
+	0xE0, 0x9B, 0x90, 0x80, 0xDA, 0xE0, 0x9A, 0x50,
+	0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80,
+	0xDA, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F,
+	0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11,
+	0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82,
+	0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22,
+	0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90,
+	0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF,
+	0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01,
+	0x12, 0x1F, 0xBD, 0x90, 0x81, 0x43, 0xF0, 0x22,
+	0x90, 0x81, 0x45, 0xE0, 0x30, 0xE0, 0x2D, 0x90,
+	0x81, 0x48, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90,
+	0x81, 0x46, 0xE0, 0xB5, 0x07, 0x1E, 0x90, 0x06,
+	0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0B, 0x12, 0x4F,
+	0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x80,
+	0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4,
+	0x90, 0x81, 0x48, 0xF0, 0x22, 0x00, 0xBB, 0x8E,
+};
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c b/drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c
new file mode 100644
index 0000000..fc23bf1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/Hal8188EPwrSeq.c
@@ -0,0 +1,86 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include "Hal8188EPwrSeq.h"
+#include <rtl8188e_hal.h>
+
+/*
+    drivers should parse below arrays and do the corresponding actions
+*/
+/* 3 Power on  Array */
+struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_CARDEMU_TO_ACT
+	RTL8188E_TRANS_END
+};
+
+/* 3Radio off Array */
+struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_ACT_TO_CARDEMU
+	RTL8188E_TRANS_END
+};
+
+/* 3Card Disable Array */
+struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_ACT_TO_CARDEMU
+	RTL8188E_TRANS_CARDEMU_TO_CARDDIS
+	RTL8188E_TRANS_END
+};
+
+/* 3 Card Enable Array */
+struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_CARDDIS_TO_CARDEMU
+	RTL8188E_TRANS_CARDEMU_TO_ACT
+	RTL8188E_TRANS_END
+};
+
+/* 3Suspend Array */
+struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_ACT_TO_CARDEMU
+	RTL8188E_TRANS_CARDEMU_TO_SUS
+	RTL8188E_TRANS_END
+};
+
+/* 3 Resume Array */
+struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_SUS_TO_CARDEMU
+	RTL8188E_TRANS_CARDEMU_TO_ACT
+	RTL8188E_TRANS_END
+};
+
+/* 3HWPDN Array */
+struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	RTL8188E_TRANS_ACT_TO_CARDEMU
+	RTL8188E_TRANS_CARDEMU_TO_PDN
+	RTL8188E_TRANS_END
+};
+
+/* 3 Enter LPS */
+struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	/* FW behavior */
+	RTL8188E_TRANS_ACT_TO_LPS
+	RTL8188E_TRANS_END
+};
+
+/* 3 Leave LPS */
+struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = {
+	/* FW behavior */
+	RTL8188E_TRANS_LPS_TO_ACT
+	RTL8188E_TRANS_END
+};
diff --git a/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c b/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
new file mode 100644
index 0000000..aaa2617
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/Hal8188ERateAdaptive.c
@@ -0,0 +1,760 @@
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+	RateAdaptive.c
+
+Abstract:
+	Implement Rate Adaptive functions for common operations.
+
+Major Change History:
+	When       Who               What
+	---------- ---------------   -------------------------------
+	2011-08-12 Page            Create.
+
+--*/
+#include "odm_precomp.h"
+
+/*  Rate adaptive parameters */
+
+static u8 RETRY_PENALTY[PERENTRY][RETRYSIZE+1] = {
+		{5, 4, 3, 2, 0, 3},      /* 92 , idx = 0 */
+		{6, 5, 4, 3, 0, 4},      /* 86 , idx = 1 */
+		{6, 5, 4, 2, 0, 4},      /* 81 , idx = 2 */
+		{8, 7, 6, 4, 0, 6},      /* 75 , idx = 3 */
+		{10, 9, 8, 6, 0, 8},     /* 71	, idx = 4 */
+		{10, 9, 8, 4, 0, 8},     /* 66	, idx = 5 */
+		{10, 9, 8, 2, 0, 8},     /* 62	, idx = 6 */
+		{10, 9, 8, 0, 0, 8},     /* 59	, idx = 7 */
+		{18, 17, 16, 8, 0, 16},  /* 53 , idx = 8 */
+		{26, 25, 24, 16, 0, 24}, /* 50	, idx = 9 */
+		{34, 33, 32, 24, 0, 32}, /* 47	, idx = 0x0a */
+		{34, 31, 28, 20, 0, 32}, /* 43	, idx = 0x0b */
+		{34, 31, 27, 18, 0, 32}, /* 40 , idx = 0x0c */
+		{34, 31, 26, 16, 0, 32}, /* 37 , idx = 0x0d */
+		{34, 30, 22, 16, 0, 32}, /* 32 , idx = 0x0e */
+		{34, 30, 24, 16, 0, 32}, /* 26 , idx = 0x0f */
+		{49, 46, 40, 16, 0, 48}, /* 20	, idx = 0x10 */
+		{49, 45, 32, 0, 0, 48},  /* 17 , idx = 0x11 */
+		{49, 45, 22, 18, 0, 48}, /* 15	, idx = 0x12 */
+		{49, 40, 24, 16, 0, 48}, /* 12	, idx = 0x13 */
+		{49, 32, 18, 12, 0, 48}, /* 9 , idx = 0x14 */
+		{49, 22, 18, 14, 0, 48}, /* 6 , idx = 0x15 */
+		{49, 16, 16, 0, 0, 48}
+	}; /* 3, idx = 0x16 */
+
+static u8 PT_PENALTY[RETRYSIZE+1] = {34, 31, 30, 24, 0, 32};
+
+/*  wilson modify */
+static u8 RETRY_PENALTY_IDX[2][RATESIZE] = {
+		{4, 4, 4, 5, 4, 4, 5, 7, 7, 7, 8, 0x0a,	       /*  SS>TH */
+		4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d,
+		5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f},			   /*  0329 R01 */
+		{0x0a, 0x0a, 0x0b, 0x0c, 0x0a,
+		0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x14,	   /*  SS<TH */
+		0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x15,
+		9, 9, 9, 9, 0x0c, 0x0e, 0x11, 0x13}
+	};
+
+static u8 RETRY_PENALTY_UP_IDX[RATESIZE] = {
+		0x0c, 0x0d, 0x0d, 0x0f, 0x0d, 0x0e,
+		0x0f, 0x0f, 0x10, 0x12, 0x13, 0x14,	       /*  SS>TH */
+		0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15,
+		0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15};
+
+static u8 RSSI_THRESHOLD[RATESIZE] = {
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0x24, 0x26, 0x2a,
+		0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a,
+		0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c};
+
+static u16 N_THRESHOLD_HIGH[RATESIZE] = {
+		4, 4, 8, 16,
+		24, 36, 48, 72, 96, 144, 192, 216,
+		60, 80, 100, 160, 240, 400, 560, 640,
+		300, 320, 480, 720, 1000, 1200, 1600, 2000};
+static u16 N_THRESHOLD_LOW[RATESIZE] = {
+		2, 2, 4, 8,
+		12, 18, 24, 36, 48, 72, 96, 108,
+		30, 40, 50, 80, 120, 200, 280, 320,
+		150, 160, 240, 360, 500, 600, 800, 1000};
+
+static u8 DROPING_NECESSARY[RATESIZE] = {
+		1, 1, 1, 1,
+		1, 2, 3, 4, 5, 6, 7, 8,
+		1, 2, 3, 4, 5, 6, 7, 8,
+		5, 6, 7, 8, 9, 10, 11, 12};
+
+static u8 PendingForRateUpFail[5] = {2, 10, 24, 40, 60};
+static u16 DynamicTxRPTTiming[6] = {
+	0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12 , 0x927c}; /*  200ms-1200ms */
+
+/*  End Rate adaptive parameters */
+
+static void odm_SetTxRPTTiming_8188E(
+		struct odm_dm_struct *dm_odm,
+		struct odm_ra_info *pRaInfo,
+		u8 extend
+	)
+{
+	u8 idx = 0;
+
+	for (idx = 0; idx < 5; idx++)
+		if (DynamicTxRPTTiming[idx] == pRaInfo->RptTime)
+			break;
+
+	if (extend == 0) { /*  back to default timing */
+		idx = 0;  /* 200ms */
+	} else if (extend == 1) {/*  increase the timing */
+		idx += 1;
+		if (idx > 5)
+			idx = 5;
+	} else if (extend == 2) {/*  decrease the timing */
+		if (idx != 0)
+			idx -= 1;
+	}
+	pRaInfo->RptTime = DynamicTxRPTTiming[idx];
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("pRaInfo->RptTime = 0x%x\n", pRaInfo->RptTime));
+}
+
+static int odm_RateDown_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo)
+{
+	u8 RateID, LowestRate, HighestRate;
+	u8 i;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDown_8188E()\n"));
+	if (NULL == pRaInfo) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateDown_8188E(): pRaInfo is NULL\n"));
+		return -1;
+	}
+	RateID = pRaInfo->PreRate;
+	LowestRate = pRaInfo->LowestRate;
+	HighestRate = pRaInfo->HighestRate;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+		     (" RateID =%d LowestRate =%d HighestRate =%d RateSGI =%d\n",
+		     RateID, LowestRate, HighestRate, pRaInfo->RateSGI));
+	if (RateID > HighestRate) {
+		RateID = HighestRate;
+	} else if (pRaInfo->RateSGI) {
+		pRaInfo->RateSGI = 0;
+	} else if (RateID > LowestRate) {
+		if (RateID > 0) {
+			for (i = RateID-1; i > LowestRate; i--) {
+				if (pRaInfo->RAUseRate & BIT(i)) {
+					RateID = i;
+					goto RateDownFinish;
+				}
+			}
+		}
+	} else if (RateID <= LowestRate) {
+		RateID = LowestRate;
+	}
+RateDownFinish:
+	if (pRaInfo->RAWaitingCounter == 1) {
+		pRaInfo->RAWaitingCounter += 1;
+		pRaInfo->RAPendingCounter += 1;
+	} else if (pRaInfo->RAWaitingCounter == 0) {
+		;
+	} else {
+		pRaInfo->RAWaitingCounter = 0;
+		pRaInfo->RAPendingCounter = 0;
+	}
+
+	if (pRaInfo->RAPendingCounter >= 4)
+		pRaInfo->RAPendingCounter = 4;
+
+	pRaInfo->DecisionRate = RateID;
+	odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 2);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down, RPT Timing default\n"));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d", pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateDown_8188E()\n"));
+	return 0;
+}
+
+static int odm_RateUp_8188E(
+		struct odm_dm_struct *dm_odm,
+		struct odm_ra_info *pRaInfo
+	)
+{
+	u8 RateID, HighestRate;
+	u8 i;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateUp_8188E()\n"));
+	if (NULL == pRaInfo) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E(): pRaInfo is NULL\n"));
+		return -1;
+	}
+	RateID = pRaInfo->PreRate;
+	HighestRate = pRaInfo->HighestRate;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+		     (" RateID =%d HighestRate =%d\n",
+		     RateID, HighestRate));
+	if (pRaInfo->RAWaitingCounter == 1) {
+		pRaInfo->RAWaitingCounter = 0;
+		pRaInfo->RAPendingCounter = 0;
+	} else if (pRaInfo->RAWaitingCounter > 1) {
+		pRaInfo->PreRssiStaRA = pRaInfo->RssiStaRA;
+		goto RateUpfinish;
+	}
+	odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 0);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E():Decrease RPT Timing\n"));
+
+	if (RateID < HighestRate) {
+		for (i = RateID+1; i <= HighestRate; i++) {
+			if (pRaInfo->RAUseRate & BIT(i)) {
+				RateID = i;
+				goto RateUpfinish;
+			}
+		}
+	} else if (RateID == HighestRate) {
+		if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1))
+			pRaInfo->RateSGI = 1;
+		else if ((pRaInfo->SGIEnable) != 1)
+			pRaInfo->RateSGI = 0;
+	} else {
+		RateID = HighestRate;
+	}
+RateUpfinish:
+	if (pRaInfo->RAWaitingCounter == (4+PendingForRateUpFail[pRaInfo->RAPendingCounter]))
+		pRaInfo->RAWaitingCounter = 0;
+	else
+		pRaInfo->RAWaitingCounter++;
+
+	pRaInfo->DecisionRate = RateID;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate up to RateID %d\n", RateID));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d", pRaInfo->RAWaitingCounter, pRaInfo->RAPendingCounter));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateUp_8188E()\n"));
+	return 0;
+}
+
+static void odm_ResetRaCounter_8188E(struct odm_ra_info *pRaInfo)
+{
+	u8 RateID;
+
+	RateID = pRaInfo->DecisionRate;
+	pRaInfo->NscUp = (N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1;
+	pRaInfo->NscDown = (N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1;
+}
+
+static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm,
+		struct odm_ra_info *pRaInfo
+	)
+{
+	u8 RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0;
+	/* u32 pool_retry; */
+	static u8 DynamicTxRPTTimingCounter;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDecision_8188E()\n"));
+
+	if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) { /*  STA used and data packet exits */
+		if ((pRaInfo->RssiStaRA < (pRaInfo->PreRssiStaRA - 3)) ||
+		    (pRaInfo->RssiStaRA > (pRaInfo->PreRssiStaRA + 3))) {
+			pRaInfo->RAWaitingCounter = 0;
+			pRaInfo->RAPendingCounter = 0;
+		}
+		/*  Start RA decision */
+		if (pRaInfo->PreRate > pRaInfo->HighestRate)
+			RateID = pRaInfo->HighestRate;
+		else
+			RateID = pRaInfo->PreRate;
+		if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID])
+			RtyPtID = 0;
+		else
+			RtyPtID = 1;
+		PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; /* TODO by page */
+
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+			     (" NscDown init is %d\n", pRaInfo->NscDown));
+		pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0];
+		pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1];
+		pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2];
+		pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3];
+		pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4];
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+			     (" NscDown is %d, total*penalty[5] is %d\n",
+			     pRaInfo->NscDown, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])));
+		if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))
+			pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5];
+		else
+			pRaInfo->NscDown = 0;
+
+		/*  rate up */
+		PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID];
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+			     (" NscUp init is %d\n", pRaInfo->NscUp));
+		pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0];
+		pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1];
+		pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2];
+		pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3];
+		pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4];
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+			     ("NscUp is %d, total*up[5] is %d\n",
+			     pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])));
+		if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))
+			pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5];
+		else
+			pRaInfo->NscUp = 0;
+
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE|ODM_COMP_INIT, ODM_DBG_LOUD,
+			     (" RssiStaRa = %d RtyPtID =%d PenaltyID1 = 0x%x  PenaltyID2 = 0x%x RateID =%d NscDown =%d NscUp =%d SGI =%d\n",
+			     pRaInfo->RssiStaRA, RtyPtID, PenaltyID1, PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI));
+		if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) ||
+		    (pRaInfo->DROP > DROPING_NECESSARY[RateID]))
+			odm_RateDown_8188E(dm_odm, pRaInfo);
+		else if (pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID])
+			odm_RateUp_8188E(dm_odm, pRaInfo);
+
+		if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
+			pRaInfo->DecisionRate = pRaInfo->HighestRate;
+
+		if ((pRaInfo->DecisionRate) == (pRaInfo->PreRate))
+			DynamicTxRPTTimingCounter += 1;
+		else
+			DynamicTxRPTTimingCounter = 0;
+
+		if (DynamicTxRPTTimingCounter >= 4) {
+			odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 1);
+			ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE,
+				     ODM_DBG_LOUD, ("<===== Rate don't change 4 times, Extend RPT Timing\n"));
+			DynamicTxRPTTimingCounter = 0;
+		}
+
+		pRaInfo->PreRate = pRaInfo->DecisionRate;  /* YJ, add, 120120 */
+
+		odm_ResetRaCounter_8188E(pRaInfo);
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<===== odm_RateDecision_8188E()\n"));
+}
+
+static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo)
+{  /*  Wilson 2011/10/26 */
+	u32 MaskFromReg;
+	s8 i;
+
+	switch (pRaInfo->RateID) {
+	case RATR_INX_WIRELESS_NGB:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff015;
+		break;
+	case RATR_INX_WIRELESS_NG:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff010;
+		break;
+	case RATR_INX_WIRELESS_NB:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff005;
+		break;
+	case RATR_INX_WIRELESS_N:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0f8ff000;
+		break;
+	case RATR_INX_WIRELESS_GB:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x00000ff5;
+		break;
+	case RATR_INX_WIRELESS_G:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x00000ff0;
+		break;
+	case RATR_INX_WIRELESS_B:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&0x0000000d;
+		break;
+	case 12:
+		MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR0);
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+		break;
+	case 13:
+		MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR1);
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+		break;
+	case 14:
+		MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR2);
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+		break;
+	case 15:
+		MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR3);
+		pRaInfo->RAUseRate = (pRaInfo->RateMask)&MaskFromReg;
+		break;
+	default:
+		pRaInfo->RAUseRate = (pRaInfo->RateMask);
+		break;
+	}
+	/*  Highest rate */
+	if (pRaInfo->RAUseRate) {
+		for (i = RATESIZE; i >= 0; i--) {
+			if ((pRaInfo->RAUseRate)&BIT(i)) {
+				pRaInfo->HighestRate = i;
+				break;
+			}
+		}
+	} else {
+		pRaInfo->HighestRate = 0;
+	}
+	/*  Lowest rate */
+	if (pRaInfo->RAUseRate) {
+		for (i = 0; i < RATESIZE; i++) {
+			if ((pRaInfo->RAUseRate) & BIT(i)) {
+				pRaInfo->LowestRate = i;
+				break;
+			}
+		}
+	} else {
+		pRaInfo->LowestRate = 0;
+	}
+		if (pRaInfo->HighestRate > 0x13)
+			pRaInfo->PTModeSS = 3;
+		else if (pRaInfo->HighestRate > 0x0b)
+			pRaInfo->PTModeSS = 2;
+		else if (pRaInfo->HighestRate > 0x0b)
+			pRaInfo->PTModeSS = 1;
+		else
+			pRaInfo->PTModeSS = 0;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+		     ("ODM_ARFBRefresh_8188E(): PTModeSS =%d\n", pRaInfo->PTModeSS));
+
+	if (pRaInfo->DecisionRate > pRaInfo->HighestRate)
+		pRaInfo->DecisionRate = pRaInfo->HighestRate;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+		     ("ODM_ARFBRefresh_8188E(): RateID =%d RateMask =%8.8x RAUseRate =%8.8x HighestRate =%d, DecisionRate =%d\n",
+		     pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate, pRaInfo->DecisionRate));
+	return 0;
+}
+
+static void odm_PTTryState_8188E(struct odm_ra_info *pRaInfo)
+{
+	pRaInfo->PTTryState = 0;
+	switch (pRaInfo->PTModeSS) {
+	case 3:
+		if (pRaInfo->DecisionRate >= 0x19)
+			pRaInfo->PTTryState = 1;
+		break;
+	case 2:
+		if (pRaInfo->DecisionRate >= 0x11)
+			pRaInfo->PTTryState = 1;
+		break;
+	case 1:
+		if (pRaInfo->DecisionRate >= 0x0a)
+			pRaInfo->PTTryState = 1;
+		break;
+	case 0:
+		if (pRaInfo->DecisionRate >= 0x03)
+			pRaInfo->PTTryState = 1;
+		break;
+	default:
+		pRaInfo->PTTryState = 0;
+		break;
+	}
+
+	if (pRaInfo->RssiStaRA < 48) {
+		pRaInfo->PTStage = 0;
+	} else if (pRaInfo->PTTryState == 1) {
+		if ((pRaInfo->PTStopCount >= 10) ||
+		    (pRaInfo->PTPreRssi > pRaInfo->RssiStaRA + 5) ||
+		    (pRaInfo->PTPreRssi < pRaInfo->RssiStaRA - 5) ||
+		    (pRaInfo->DecisionRate != pRaInfo->PTPreRate)) {
+			if (pRaInfo->PTStage == 0)
+				pRaInfo->PTStage = 1;
+			else if (pRaInfo->PTStage == 1)
+				pRaInfo->PTStage = 3;
+			else
+				pRaInfo->PTStage = 5;
+
+			pRaInfo->PTPreRssi = pRaInfo->RssiStaRA;
+			pRaInfo->PTStopCount = 0;
+		} else {
+			pRaInfo->RAstage = 0;
+			pRaInfo->PTStopCount++;
+		}
+	} else {
+		pRaInfo->PTStage = 0;
+		pRaInfo->RAstage = 0;
+	}
+	pRaInfo->PTPreRate = pRaInfo->DecisionRate;
+}
+
+static void odm_PTDecision_8188E(struct odm_ra_info *pRaInfo)
+{
+	u8 j;
+	u8 temp_stage;
+	u32 numsc;
+	u32 num_total;
+	u8 stage_id;
+
+	numsc  = 0;
+	num_total = pRaInfo->TOTAL * PT_PENALTY[5];
+	for (j = 0; j <= 4; j++) {
+		numsc += pRaInfo->RTY[j] * PT_PENALTY[j];
+		if (numsc > num_total)
+			break;
+	}
+
+	j = j >> 1;
+	temp_stage = (pRaInfo->PTStage + 1) >> 1;
+	if (temp_stage > j)
+		stage_id = temp_stage-j;
+	else
+		stage_id = 0;
+
+	pRaInfo->PTSmoothFactor = (pRaInfo->PTSmoothFactor>>1) + (pRaInfo->PTSmoothFactor>>2) + stage_id*16+2;
+	if (pRaInfo->PTSmoothFactor > 192)
+		pRaInfo->PTSmoothFactor = 192;
+	stage_id = pRaInfo->PTSmoothFactor >> 6;
+	temp_stage = stage_id*2;
+	if (temp_stage != 0)
+		temp_stage -= 1;
+	if (pRaInfo->DROP > 3)
+		temp_stage = 0;
+	pRaInfo->PTStage = temp_stage;
+}
+
+static void
+odm_RATxRPTTimerSetting(
+		struct odm_dm_struct *dm_odm,
+		u16 minRptTime
+)
+{
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, (" =====>odm_RATxRPTTimerSetting()\n"));
+
+	if (dm_odm->CurrminRptTime != minRptTime) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+			     (" CurrminRptTime = 0x%04x minRptTime = 0x%04x\n", dm_odm->CurrminRptTime, minRptTime));
+		rtw_rpt_timer_cfg_cmd(dm_odm->Adapter, minRptTime);
+		dm_odm->CurrminRptTime = minRptTime;
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, (" <===== odm_RATxRPTTimerSetting()\n"));
+}
+
+void
+ODM_RASupport_Init(
+		struct odm_dm_struct *dm_odm
+	)
+{
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RASupport_Init()\n"));
+
+	/*  2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! */
+	if (dm_odm->SupportICType == ODM_RTL8188E)
+		dm_odm->RaSupport88E = true;
+}
+
+int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 macid)
+{
+	struct odm_ra_info *pRaInfo = &dm_odm->RAInfo[macid];
+	u8 WirelessMode = 0xFF; /* invalid value */
+	u8 max_rate_idx = 0x13; /* MCS7 */
+	if (dm_odm->pWirelessMode != NULL)
+		WirelessMode = *(dm_odm->pWirelessMode);
+
+	if (WirelessMode != 0xFF) {
+		if (WirelessMode & ODM_WM_N24G)
+			max_rate_idx = 0x13;
+		else if (WirelessMode & ODM_WM_G)
+			max_rate_idx = 0x0b;
+		else if (WirelessMode & ODM_WM_B)
+			max_rate_idx = 0x03;
+	}
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+		     ("ODM_RAInfo_Init(): WirelessMode:0x%08x , max_raid_idx:0x%02x\n",
+		     WirelessMode, max_rate_idx));
+
+	pRaInfo->DecisionRate = max_rate_idx;
+	pRaInfo->PreRate = max_rate_idx;
+	pRaInfo->HighestRate = max_rate_idx;
+	pRaInfo->LowestRate = 0;
+	pRaInfo->RateID = 0;
+	pRaInfo->RateMask = 0xffffffff;
+	pRaInfo->RssiStaRA = 0;
+	pRaInfo->PreRssiStaRA = 0;
+	pRaInfo->SGIEnable = 0;
+	pRaInfo->RAUseRate = 0xffffffff;
+	pRaInfo->NscDown = (N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2;
+	pRaInfo->NscUp = (N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2;
+	pRaInfo->RateSGI = 0;
+	pRaInfo->Active = 1;	/* Active is not used at present. by page, 110819 */
+	pRaInfo->RptTime = 0x927c;
+	pRaInfo->DROP = 0;
+	pRaInfo->RTY[0] = 0;
+	pRaInfo->RTY[1] = 0;
+	pRaInfo->RTY[2] = 0;
+	pRaInfo->RTY[3] = 0;
+	pRaInfo->RTY[4] = 0;
+	pRaInfo->TOTAL = 0;
+	pRaInfo->RAWaitingCounter = 0;
+	pRaInfo->RAPendingCounter = 0;
+	pRaInfo->PTActive = 1;   /*  Active when this STA is use */
+	pRaInfo->PTTryState = 0;
+	pRaInfo->PTStage = 5; /*  Need to fill into HW_PWR_STATUS */
+	pRaInfo->PTSmoothFactor = 192;
+	pRaInfo->PTStopCount = 0;
+	pRaInfo->PTPreRate = 0;
+	pRaInfo->PTPreRssi = 0;
+	pRaInfo->PTModeSS = 0;
+	pRaInfo->RAstage = 0;
+	return 0;
+}
+
+int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm)
+{
+	u8 macid = 0;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n"));
+	dm_odm->CurrminRptTime = 0;
+
+	for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++)
+		ODM_RAInfo_Init(dm_odm, macid);
+
+	return 0;
+}
+
+u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 macid)
+{
+	if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+		return 0;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+		     ("macid =%d SGI =%d\n", macid, dm_odm->RAInfo[macid].RateSGI));
+	return dm_odm->RAInfo[macid].RateSGI;
+}
+
+u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 macid)
+{
+	u8 DecisionRate = 0;
+
+	if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+		return 0;
+	DecisionRate = (dm_odm->RAInfo[macid].DecisionRate);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+		(" macid =%d DecisionRate = 0x%x\n", macid, DecisionRate));
+	return DecisionRate;
+}
+
+u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 macid)
+{
+	u8 PTStage = 5;
+
+	if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+		return 0;
+	PTStage = (dm_odm->RAInfo[macid].PTStage);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+		     ("macid =%d PTStage = 0x%x\n", macid, PTStage));
+	return PTStage;
+}
+
+void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 RateID, u32 RateMask, u8 SGIEnable)
+{
+	struct odm_ra_info *pRaInfo = NULL;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+		     ("macid =%d RateID = 0x%x RateMask = 0x%x SGIEnable =%d\n",
+		     macid, RateID, RateMask, SGIEnable));
+	if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+		return;
+
+	pRaInfo = &(dm_odm->RAInfo[macid]);
+	pRaInfo->RateID = RateID;
+	pRaInfo->RateMask = RateMask;
+	pRaInfo->SGIEnable = SGIEnable;
+	odm_ARFBRefresh_8188E(dm_odm, pRaInfo);
+}
+
+void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rssi)
+{
+	struct odm_ra_info *pRaInfo = NULL;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,
+		     (" macid =%d Rssi =%d\n", macid, Rssi));
+	if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM))
+		return;
+
+	pRaInfo = &(dm_odm->RAInfo[macid]);
+	pRaInfo->RssiStaRA = Rssi;
+}
+
+void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime)
+{
+	ODM_Write2Byte(dm_odm, REG_TX_RPT_TIME, minRptTime);
+}
+
+void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16 TxRPT_Len, u32 macid_entry0, u32 macid_entry1)
+{
+	struct odm_ra_info *pRAInfo = NULL;
+	u8 MacId = 0;
+	u8 *pBuffer = NULL;
+	u32 valid = 0, ItemNum = 0;
+	u16 minRptTime = 0x927c;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+		     ("=====>ODM_RA_TxRPT2Handle_8188E(): valid0 =%d valid1 =%d BufferLength =%d\n",
+		     macid_entry0, macid_entry1, TxRPT_Len));
+
+	ItemNum = TxRPT_Len >> 3;
+	pBuffer = TxRPT_Buf;
+
+	do {
+		if (MacId >= ASSOCIATE_ENTRY_NUM)
+			valid = 0;
+		else if (MacId >= 32)
+			valid = (1 << (MacId - 32)) & macid_entry1;
+		else
+			valid = (1 << MacId) & macid_entry0;
+
+		pRAInfo = &(dm_odm->RAInfo[MacId]);
+		if (valid) {
+			pRAInfo->RTY[0] = (u16)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer);
+			pRAInfo->RTY[1] = (u16)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer);
+			pRAInfo->RTY[2] = (u16)GET_TX_REPORT_TYPE1_RERTY_2(pBuffer);
+			pRAInfo->RTY[3] = (u16)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer);
+			pRAInfo->RTY[4] = (u16)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer);
+			pRAInfo->DROP =   (u16)GET_TX_REPORT_TYPE1_DROP_0(pBuffer);
+			pRAInfo->TOTAL = pRAInfo->RTY[0] + pRAInfo->RTY[1] +
+					 pRAInfo->RTY[2] + pRAInfo->RTY[3] +
+					 pRAInfo->RTY[4] + pRAInfo->DROP;
+			if (pRAInfo->TOTAL != 0) {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD,
+					     ("macid =%d Total =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d D0 =%d valid0 =%x valid1 =%x\n",
+					     MacId, pRAInfo->TOTAL,
+					     pRAInfo->RTY[0], pRAInfo->RTY[1],
+					     pRAInfo->RTY[2], pRAInfo->RTY[3],
+					     pRAInfo->RTY[4], pRAInfo->DROP,
+					     macid_entry0 , macid_entry1));
+				if (pRAInfo->PTActive) {
+					if (pRAInfo->RAstage < 5)
+						odm_RateDecision_8188E(dm_odm, pRAInfo);
+					else if (pRAInfo->RAstage == 5) /*  Power training try state */
+						odm_PTTryState_8188E(pRAInfo);
+					else /*  RAstage == 6 */
+						odm_PTDecision_8188E(pRAInfo);
+
+					/*  Stage_RA counter */
+					if (pRAInfo->RAstage <= 5)
+						pRAInfo->RAstage++;
+					else
+						pRAInfo->RAstage = 0;
+				} else {
+					odm_RateDecision_8188E(dm_odm, pRAInfo);
+				}
+				ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+					     ("macid =%d R0 =%d R1 =%d R2 =%d R3 =%d R4 =%d drop =%d valid0 =%x RateID =%d SGI =%d\n",
+					     MacId,
+					     pRAInfo->RTY[0],
+					     pRAInfo->RTY[1],
+					     pRAInfo->RTY[2],
+					     pRAInfo->RTY[3],
+					     pRAInfo->RTY[4],
+					     pRAInfo->DROP,
+					     macid_entry0,
+					     pRAInfo->DecisionRate,
+					     pRAInfo->RateSGI));
+			} else {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL = 0!!!!\n"));
+			}
+		}
+
+		if (minRptTime > pRAInfo->RptTime)
+			minRptTime = pRAInfo->RptTime;
+
+		pBuffer += TX_RPT2_ITEM_SIZE;
+		MacId++;
+	} while (MacId < ItemNum);
+
+	odm_RATxRPTTimerSetting(dm_odm, minRptTime);
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<===== ODM_RA_TxRPT2Handle_8188E()\n"));
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c
new file mode 100644
index 0000000..787e8f1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_BB.c
@@ -0,0 +1,721 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#include "odm_precomp.h"
+
+#include <rtw_iol.h>
+
+#define read_next_pair(array, v1, v2, i)		\
+	 do {						\
+		 i += 2;				\
+		 v1 = array[i];				\
+		 v2 = array[i+1];			\
+	 } while (0)
+
+static bool CheckCondition(const u32  condition, const u32  hex)
+{
+	u32 _board     = (hex & 0x000000FF);
+	u32 _interface = (hex & 0x0000FF00) >> 8;
+	u32 _platform  = (hex & 0x00FF0000) >> 16;
+	u32 cond = condition;
+
+	if (condition == 0xCDCDCDCD)
+		return true;
+
+	cond = condition & 0x000000FF;
+	if ((_board == cond) && cond != 0x00)
+		return false;
+
+	cond = condition & 0x0000FF00;
+	cond = cond >> 8;
+	if ((_interface & cond) == 0 && cond != 0x07)
+		return false;
+
+	cond = condition & 0x00FF0000;
+	cond = cond >> 16;
+	if ((_platform & cond) == 0 && cond != 0x0F)
+		return false;
+	return true;
+}
+
+
+/******************************************************************************
+*                           AGC_TAB_1T.TXT
+******************************************************************************/
+
+static u32 array_agc_tab_1t_8188e[] = {
+		0xC78, 0xFB000001,
+		0xC78, 0xFB010001,
+		0xC78, 0xFB020001,
+		0xC78, 0xFB030001,
+		0xC78, 0xFB040001,
+		0xC78, 0xFB050001,
+		0xC78, 0xFA060001,
+		0xC78, 0xF9070001,
+		0xC78, 0xF8080001,
+		0xC78, 0xF7090001,
+		0xC78, 0xF60A0001,
+		0xC78, 0xF50B0001,
+		0xC78, 0xF40C0001,
+		0xC78, 0xF30D0001,
+		0xC78, 0xF20E0001,
+		0xC78, 0xF10F0001,
+		0xC78, 0xF0100001,
+		0xC78, 0xEF110001,
+		0xC78, 0xEE120001,
+		0xC78, 0xED130001,
+		0xC78, 0xEC140001,
+		0xC78, 0xEB150001,
+		0xC78, 0xEA160001,
+		0xC78, 0xE9170001,
+		0xC78, 0xE8180001,
+		0xC78, 0xE7190001,
+		0xC78, 0xE61A0001,
+		0xC78, 0xE51B0001,
+		0xC78, 0xE41C0001,
+		0xC78, 0xE31D0001,
+		0xC78, 0xE21E0001,
+		0xC78, 0xE11F0001,
+		0xC78, 0x8A200001,
+		0xC78, 0x89210001,
+		0xC78, 0x88220001,
+		0xC78, 0x87230001,
+		0xC78, 0x86240001,
+		0xC78, 0x85250001,
+		0xC78, 0x84260001,
+		0xC78, 0x83270001,
+		0xC78, 0x82280001,
+		0xC78, 0x6B290001,
+		0xC78, 0x6A2A0001,
+		0xC78, 0x692B0001,
+		0xC78, 0x682C0001,
+		0xC78, 0x672D0001,
+		0xC78, 0x662E0001,
+		0xC78, 0x652F0001,
+		0xC78, 0x64300001,
+		0xC78, 0x63310001,
+		0xC78, 0x62320001,
+		0xC78, 0x61330001,
+		0xC78, 0x46340001,
+		0xC78, 0x45350001,
+		0xC78, 0x44360001,
+		0xC78, 0x43370001,
+		0xC78, 0x42380001,
+		0xC78, 0x41390001,
+		0xC78, 0x403A0001,
+		0xC78, 0x403B0001,
+		0xC78, 0x403C0001,
+		0xC78, 0x403D0001,
+		0xC78, 0x403E0001,
+		0xC78, 0x403F0001,
+		0xC78, 0xFB400001,
+		0xC78, 0xFB410001,
+		0xC78, 0xFB420001,
+		0xC78, 0xFB430001,
+		0xC78, 0xFB440001,
+		0xC78, 0xFB450001,
+		0xC78, 0xFB460001,
+		0xC78, 0xFB470001,
+		0xC78, 0xFB480001,
+		0xC78, 0xFA490001,
+		0xC78, 0xF94A0001,
+		0xC78, 0xF84B0001,
+		0xC78, 0xF74C0001,
+		0xC78, 0xF64D0001,
+		0xC78, 0xF54E0001,
+		0xC78, 0xF44F0001,
+		0xC78, 0xF3500001,
+		0xC78, 0xF2510001,
+		0xC78, 0xF1520001,
+		0xC78, 0xF0530001,
+		0xC78, 0xEF540001,
+		0xC78, 0xEE550001,
+		0xC78, 0xED560001,
+		0xC78, 0xEC570001,
+		0xC78, 0xEB580001,
+		0xC78, 0xEA590001,
+		0xC78, 0xE95A0001,
+		0xC78, 0xE85B0001,
+		0xC78, 0xE75C0001,
+		0xC78, 0xE65D0001,
+		0xC78, 0xE55E0001,
+		0xC78, 0xE45F0001,
+		0xC78, 0xE3600001,
+		0xC78, 0xE2610001,
+		0xC78, 0xC3620001,
+		0xC78, 0xC2630001,
+		0xC78, 0xC1640001,
+		0xC78, 0x8B650001,
+		0xC78, 0x8A660001,
+		0xC78, 0x89670001,
+		0xC78, 0x88680001,
+		0xC78, 0x87690001,
+		0xC78, 0x866A0001,
+		0xC78, 0x856B0001,
+		0xC78, 0x846C0001,
+		0xC78, 0x676D0001,
+		0xC78, 0x666E0001,
+		0xC78, 0x656F0001,
+		0xC78, 0x64700001,
+		0xC78, 0x63710001,
+		0xC78, 0x62720001,
+		0xC78, 0x61730001,
+		0xC78, 0x60740001,
+		0xC78, 0x46750001,
+		0xC78, 0x45760001,
+		0xC78, 0x44770001,
+		0xC78, 0x43780001,
+		0xC78, 0x42790001,
+		0xC78, 0x417A0001,
+		0xC78, 0x407B0001,
+		0xC78, 0x407C0001,
+		0xC78, 0x407D0001,
+		0xC78, 0x407E0001,
+		0xC78, 0x407F0001,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *dm_odm)
+{
+	u32     hex         = 0;
+	u32     i           = 0;
+	u8     platform    = dm_odm->SupportPlatform;
+	u8     interfaceValue   = dm_odm->SupportInterface;
+	u8     board       = dm_odm->BoardType;
+	u32     arraylen    = sizeof(array_agc_tab_1t_8188e)/sizeof(u32);
+	u32    *array       = array_agc_tab_1t_8188e;
+	bool		biol = false;
+	struct adapter *adapter =  dm_odm->Adapter;
+	struct xmit_frame *pxmit_frame = NULL;
+	u8 bndy_cnt = 1;
+	enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+
+	hex += board;
+	hex += interfaceValue << 8;
+	hex += platform << 16;
+	hex += 0xFF000000;
+	biol = rtw_IOL_applied(adapter);
+
+	if (biol) {
+		pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter);
+		if (pxmit_frame == NULL) {
+			pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+			return HAL_STATUS_FAILURE;
+		}
+	}
+
+	for (i = 0; i < arraylen; i += 2) {
+		u32 v1 = array[i];
+		u32 v2 = array[i+1];
+
+		/*  This (offset, data) pair meets the condition. */
+		if (v1 < 0xCDCDCDCD) {
+			if (biol) {
+				if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+					bndy_cnt++;
+				rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+			} else {
+				odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2);
+			}
+			continue;
+		} else {
+			/*  This line is the start line of branch. */
+			if (!CheckCondition(array[i], hex)) {
+				/*  Discard the following (offset, data) pairs. */
+				read_next_pair(array, v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2)
+					read_next_pair(array, v1, v2, i);
+				i -= 2; /*  prevent from for-loop += 2 */
+			} else { /*  Configure matched pairs and skip to end of if-else. */
+				read_next_pair(array, v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2) {
+					if (biol) {
+						if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+							bndy_cnt++;
+						rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+					} else {
+						odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2);
+					}
+					read_next_pair(array, v1, v2, i);
+				}
+
+				while (v2 != 0xDEAD && i < arraylen - 2)
+					read_next_pair(array, v1, v2, i);
+			}
+		}
+	}
+	if (biol) {
+		if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+			printk("~~~ %s IOL_exec_cmds Failed !!!\n", __func__);
+			rst = HAL_STATUS_FAILURE;
+		}
+	}
+	return rst;
+}
+
+/******************************************************************************
+*                           PHY_REG_1T.TXT
+******************************************************************************/
+
+static u32 array_phy_reg_1t_8188e[] = {
+		0x800, 0x80040000,
+		0x804, 0x00000003,
+		0x808, 0x0000FC00,
+		0x80C, 0x0000000A,
+		0x810, 0x10001331,
+		0x814, 0x020C3D10,
+		0x818, 0x02200385,
+		0x81C, 0x00000000,
+		0x820, 0x01000100,
+		0x824, 0x00390204,
+		0x828, 0x00000000,
+		0x82C, 0x00000000,
+		0x830, 0x00000000,
+		0x834, 0x00000000,
+		0x838, 0x00000000,
+		0x83C, 0x00000000,
+		0x840, 0x00010000,
+		0x844, 0x00000000,
+		0x848, 0x00000000,
+		0x84C, 0x00000000,
+		0x850, 0x00000000,
+		0x854, 0x00000000,
+		0x858, 0x569A11A9,
+		0x85C, 0x01000014,
+		0x860, 0x66F60110,
+		0x864, 0x061F0649,
+		0x868, 0x00000000,
+		0x86C, 0x27272700,
+		0x870, 0x07000760,
+		0x874, 0x25004000,
+		0x878, 0x00000808,
+		0x87C, 0x00000000,
+		0x880, 0xB0000C1C,
+		0x884, 0x00000001,
+		0x888, 0x00000000,
+		0x88C, 0xCCC000C0,
+		0x890, 0x00000800,
+		0x894, 0xFFFFFFFE,
+		0x898, 0x40302010,
+		0x89C, 0x00706050,
+		0x900, 0x00000000,
+		0x904, 0x00000023,
+		0x908, 0x00000000,
+		0x90C, 0x81121111,
+		0x910, 0x00000002,
+		0x914, 0x00000201,
+		0xA00, 0x00D047C8,
+		0xA04, 0x80FF000C,
+		0xA08, 0x8C838300,
+		0xA0C, 0x2E7F120F,
+		0xA10, 0x9500BB78,
+		0xA14, 0x1114D028,
+		0xA18, 0x00881117,
+		0xA1C, 0x89140F00,
+		0xA20, 0x1A1B0000,
+		0xA24, 0x090E1317,
+		0xA28, 0x00000204,
+		0xA2C, 0x00D30000,
+		0xA70, 0x101FBF00,
+		0xA74, 0x00000007,
+		0xA78, 0x00000900,
+		0xA7C, 0x225B0606,
+		0xA80, 0x218075B1,
+		0xB2C, 0x80000000,
+		0xC00, 0x48071D40,
+		0xC04, 0x03A05611,
+		0xC08, 0x000000E4,
+		0xC0C, 0x6C6C6C6C,
+		0xC10, 0x08800000,
+		0xC14, 0x40000100,
+		0xC18, 0x08800000,
+		0xC1C, 0x40000100,
+		0xC20, 0x00000000,
+		0xC24, 0x00000000,
+		0xC28, 0x00000000,
+		0xC2C, 0x00000000,
+		0xC30, 0x69E9AC47,
+		0xC34, 0x469652AF,
+		0xC38, 0x49795994,
+		0xC3C, 0x0A97971C,
+		0xC40, 0x1F7C403F,
+		0xC44, 0x000100B7,
+		0xC48, 0xEC020107,
+		0xC4C, 0x007F037F,
+		0xC50, 0x69553420,
+		0xC54, 0x43BC0094,
+		0xC58, 0x00013169,
+		0xC5C, 0x00250492,
+		0xC60, 0x00000000,
+		0xC64, 0x7112848B,
+		0xC68, 0x47C00BFF,
+		0xC6C, 0x00000036,
+		0xC70, 0x2C7F000D,
+		0xC74, 0x020610DB,
+		0xC78, 0x0000001F,
+		0xC7C, 0x00B91612,
+		0xC80, 0x390000E4,
+		0xC84, 0x20F60000,
+		0xC88, 0x40000100,
+		0xC8C, 0x20200000,
+		0xC90, 0x00091521,
+		0xC94, 0x00000000,
+		0xC98, 0x00121820,
+		0xC9C, 0x00007F7F,
+		0xCA0, 0x00000000,
+		0xCA4, 0x000300A0,
+		0xCA8, 0x00000000,
+		0xCAC, 0x00000000,
+		0xCB0, 0x00000000,
+		0xCB4, 0x00000000,
+		0xCB8, 0x00000000,
+		0xCBC, 0x28000000,
+		0xCC0, 0x00000000,
+		0xCC4, 0x00000000,
+		0xCC8, 0x00000000,
+		0xCCC, 0x00000000,
+		0xCD0, 0x00000000,
+		0xCD4, 0x00000000,
+		0xCD8, 0x64B22427,
+		0xCDC, 0x00766932,
+		0xCE0, 0x00222222,
+		0xCE4, 0x00000000,
+		0xCE8, 0x37644302,
+		0xCEC, 0x2F97D40C,
+		0xD00, 0x00000740,
+		0xD04, 0x00020401,
+		0xD08, 0x0000907F,
+		0xD0C, 0x20010201,
+		0xD10, 0xA0633333,
+		0xD14, 0x3333BC43,
+		0xD18, 0x7A8F5B6F,
+		0xD2C, 0xCC979975,
+		0xD30, 0x00000000,
+		0xD34, 0x80608000,
+		0xD38, 0x00000000,
+		0xD3C, 0x00127353,
+		0xD40, 0x00000000,
+		0xD44, 0x00000000,
+		0xD48, 0x00000000,
+		0xD4C, 0x00000000,
+		0xD50, 0x6437140A,
+		0xD54, 0x00000000,
+		0xD58, 0x00000282,
+		0xD5C, 0x30032064,
+		0xD60, 0x4653DE68,
+		0xD64, 0x04518A3C,
+		0xD68, 0x00002101,
+		0xD6C, 0x2A201C16,
+		0xD70, 0x1812362E,
+		0xD74, 0x322C2220,
+		0xD78, 0x000E3C24,
+		0xE00, 0x2D2D2D2D,
+		0xE04, 0x2D2D2D2D,
+		0xE08, 0x0390272D,
+		0xE10, 0x2D2D2D2D,
+		0xE14, 0x2D2D2D2D,
+		0xE18, 0x2D2D2D2D,
+		0xE1C, 0x2D2D2D2D,
+		0xE28, 0x00000000,
+		0xE30, 0x1000DC1F,
+		0xE34, 0x10008C1F,
+		0xE38, 0x02140102,
+		0xE3C, 0x681604C2,
+		0xE40, 0x01007C00,
+		0xE44, 0x01004800,
+		0xE48, 0xFB000000,
+		0xE4C, 0x000028D1,
+		0xE50, 0x1000DC1F,
+		0xE54, 0x10008C1F,
+		0xE58, 0x02140102,
+		0xE5C, 0x28160D05,
+		0xE60, 0x00000008,
+		0xE68, 0x001B25A4,
+		0xE6C, 0x00C00014,
+		0xE70, 0x00C00014,
+		0xE74, 0x01000014,
+		0xE78, 0x01000014,
+		0xE7C, 0x01000014,
+		0xE80, 0x01000014,
+		0xE84, 0x00C00014,
+		0xE88, 0x01000014,
+		0xE8C, 0x00C00014,
+		0xED0, 0x00C00014,
+		0xED4, 0x00C00014,
+		0xED8, 0x00C00014,
+		0xEDC, 0x00000014,
+		0xEE0, 0x00000014,
+		0xEEC, 0x01C00014,
+		0xF14, 0x00000003,
+		0xF4C, 0x00000000,
+		0xF00, 0x00000300,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *dm_odm)
+{
+	u32     hex         = 0;
+	u32     i           = 0;
+	u8     platform    = dm_odm->SupportPlatform;
+	u8     interfaceValue   = dm_odm->SupportInterface;
+	u8     board       = dm_odm->BoardType;
+	u32     arraylen    = sizeof(array_phy_reg_1t_8188e)/sizeof(u32);
+	u32    *array       = array_phy_reg_1t_8188e;
+	bool	biol = false;
+	struct adapter *adapter =  dm_odm->Adapter;
+	struct xmit_frame *pxmit_frame = NULL;
+	u8 bndy_cnt = 1;
+	enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+	hex += board;
+	hex += interfaceValue << 8;
+	hex += platform << 16;
+	hex += 0xFF000000;
+	biol = rtw_IOL_applied(adapter);
+
+	if (biol) {
+		pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter);
+		if (pxmit_frame == NULL) {
+			pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+			return HAL_STATUS_FAILURE;
+		}
+	}
+
+	for (i = 0; i < arraylen; i += 2) {
+		u32 v1 = array[i];
+		u32 v2 = array[i+1];
+
+		/*  This (offset, data) pair meets the condition. */
+		if (v1 < 0xCDCDCDCD) {
+			if (biol) {
+				if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+					bndy_cnt++;
+				if (v1 == 0xfe) {
+					rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+				} else if (v1 == 0xfd) {
+					rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+				} else if (v1 == 0xfc) {
+					rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+				} else if (v1 == 0xfb) {
+					rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+				} else if (v1 == 0xfa) {
+					rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+				} else if (v1 == 0xf9) {
+					rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+				} else {
+					if (v1 == 0xa24)
+						dm_odm->RFCalibrateInfo.RegA24 = v2;
+					rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+				}
+			} else {
+				odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2);
+			}
+			continue;
+		} else { /*  This line is the start line of branch. */
+			if (!CheckCondition(array[i], hex)) {
+				/*  Discard the following (offset, data) pairs. */
+				read_next_pair(array, v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2)
+					read_next_pair(array, v1, v2, i);
+				i -= 2; /*  prevent from for-loop += 2 */
+			} else { /*  Configure matched pairs and skip to end of if-else. */
+				read_next_pair(array, v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < arraylen - 2) {
+					if (biol) {
+						if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+							bndy_cnt++;
+						if (v1 == 0xfe) {
+							rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+						} else if (v1 == 0xfd) {
+							rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+						} else if (v1 == 0xfc) {
+							rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+						} else if (v1 == 0xfb) {
+							rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+						} else if (v1 == 0xfa) {
+							rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+						} else if (v1 == 0xf9) {
+							rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+						} else{
+							if (v1 == 0xa24)
+								dm_odm->RFCalibrateInfo.RegA24 = v2;
+
+							rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord);
+						}
+					} else {
+						odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2);
+					}
+					read_next_pair(array, v1, v2, i);
+				}
+
+				while (v2 != 0xDEAD && i < arraylen - 2)
+					read_next_pair(array, v1, v2, i);
+			}
+		}
+	}
+	if (biol) {
+		if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+			rst = HAL_STATUS_FAILURE;
+			pr_info("~~~ IOL Config %s Failed !!!\n", __func__);
+		}
+	}
+	return rst;
+}
+
+/******************************************************************************
+*                           PHY_REG_PG.TXT
+******************************************************************************/
+
+static u32 array_phy_reg_pg_8188e[] = {
+		0xE00, 0xFFFFFFFF, 0x06070809,
+		0xE04, 0xFFFFFFFF, 0x02020405,
+		0xE08, 0x0000FF00, 0x00000006,
+		0x86C, 0xFFFFFF00, 0x00020400,
+		0xE10, 0xFFFFFFFF, 0x08090A0B,
+		0xE14, 0xFFFFFFFF, 0x01030607,
+		0xE18, 0xFFFFFFFF, 0x08090A0B,
+		0xE1C, 0xFFFFFFFF, 0x01030607,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x02020202,
+		0xE04, 0xFFFFFFFF, 0x00020202,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x04040404,
+		0xE14, 0xFFFFFFFF, 0x00020404,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x02020202,
+		0xE04, 0xFFFFFFFF, 0x00020202,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x04040404,
+		0xE14, 0xFFFFFFFF, 0x00020404,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x02020202,
+		0xE04, 0xFFFFFFFF, 0x00020202,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x04040404,
+		0xE14, 0xFFFFFFFF, 0x00020404,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+		0xE00, 0xFFFFFFFF, 0x00000000,
+		0xE04, 0xFFFFFFFF, 0x00000000,
+		0xE08, 0x0000FF00, 0x00000000,
+		0x86C, 0xFFFFFF00, 0x00000000,
+		0xE10, 0xFFFFFFFF, 0x00000000,
+		0xE14, 0xFFFFFFFF, 0x00000000,
+		0xE18, 0xFFFFFFFF, 0x00000000,
+		0xE1C, 0xFFFFFFFF, 0x00000000,
+
+};
+
+void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm)
+{
+	u32  hex;
+	u32  i           = 0;
+	u8  platform    = dm_odm->SupportPlatform;
+	u8  interfaceValue   = dm_odm->SupportInterface;
+	u8  board       = dm_odm->BoardType;
+	u32  arraylen    = sizeof(array_phy_reg_pg_8188e) / sizeof(u32);
+	u32 *array       = array_phy_reg_pg_8188e;
+
+	hex = board + (interfaceValue << 8);
+	hex += (platform << 16) + 0xFF000000;
+
+	for (i = 0; i < arraylen; i += 3) {
+		u32 v1 = array[i];
+		u32 v2 = array[i+1];
+		u32 v3 = array[i+2];
+
+		/*  this line is a line of pure_body */
+		if (v1 < 0xCDCDCDCD) {
+			odm_ConfigBB_PHY_REG_PG_8188E(dm_odm, v1, v2, v3);
+			continue;
+		} else { /*  this line is the start of branch */
+			if (!CheckCondition(array[i], hex)) {
+				/*  don't need the hw_body */
+				i += 2; /*  skip the pair of expression */
+				v1 = array[i];
+				v2 = array[i+1];
+				v3 = array[i+2];
+				while (v2 != 0xDEAD) {
+					i += 3;
+					v1 = array[i];
+					v2 = array[i+1];
+					v3 = array[i+1];
+				}
+			}
+		}
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c
new file mode 100644
index 0000000..b49b5ab
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_MAC.c
@@ -0,0 +1,231 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#include "odm_precomp.h"
+#include <rtw_iol.h>
+
+static bool Checkcondition(const u32  condition, const u32  hex)
+{
+	u32 _board     = (hex & 0x000000FF);
+	u32 _interface = (hex & 0x0000FF00) >> 8;
+	u32 _platform  = (hex & 0x00FF0000) >> 16;
+	u32 cond = condition;
+
+	if (condition == 0xCDCDCDCD)
+		return true;
+
+	cond = condition & 0x000000FF;
+	if ((_board == cond) && cond != 0x00)
+		return false;
+
+	cond = condition & 0x0000FF00;
+	cond = cond >> 8;
+	if ((_interface & cond) == 0 && cond != 0x07)
+		return false;
+
+	cond = condition & 0x00FF0000;
+	cond = cond >> 16;
+	if ((_platform & cond) == 0 && cond != 0x0F)
+		return false;
+	return true;
+}
+
+
+/******************************************************************************
+*                           MAC_REG.TXT
+******************************************************************************/
+
+static u32 array_MAC_REG_8188E[] = {
+		0x026, 0x00000041,
+		0x027, 0x00000035,
+		0x428, 0x0000000A,
+		0x429, 0x00000010,
+		0x430, 0x00000000,
+		0x431, 0x00000001,
+		0x432, 0x00000002,
+		0x433, 0x00000004,
+		0x434, 0x00000005,
+		0x435, 0x00000006,
+		0x436, 0x00000007,
+		0x437, 0x00000008,
+		0x438, 0x00000000,
+		0x439, 0x00000000,
+		0x43A, 0x00000001,
+		0x43B, 0x00000002,
+		0x43C, 0x00000004,
+		0x43D, 0x00000005,
+		0x43E, 0x00000006,
+		0x43F, 0x00000007,
+		0x440, 0x0000005D,
+		0x441, 0x00000001,
+		0x442, 0x00000000,
+		0x444, 0x00000015,
+		0x445, 0x000000F0,
+		0x446, 0x0000000F,
+		0x447, 0x00000000,
+		0x458, 0x00000041,
+		0x459, 0x000000A8,
+		0x45A, 0x00000072,
+		0x45B, 0x000000B9,
+		0x460, 0x00000066,
+		0x461, 0x00000066,
+		0x480, 0x00000008,
+		0x4C8, 0x000000FF,
+		0x4C9, 0x00000008,
+		0x4CC, 0x000000FF,
+		0x4CD, 0x000000FF,
+		0x4CE, 0x00000001,
+		0x4D3, 0x00000001,
+		0x500, 0x00000026,
+		0x501, 0x000000A2,
+		0x502, 0x0000002F,
+		0x503, 0x00000000,
+		0x504, 0x00000028,
+		0x505, 0x000000A3,
+		0x506, 0x0000005E,
+		0x507, 0x00000000,
+		0x508, 0x0000002B,
+		0x509, 0x000000A4,
+		0x50A, 0x0000005E,
+		0x50B, 0x00000000,
+		0x50C, 0x0000004F,
+		0x50D, 0x000000A4,
+		0x50E, 0x00000000,
+		0x50F, 0x00000000,
+		0x512, 0x0000001C,
+		0x514, 0x0000000A,
+		0x516, 0x0000000A,
+		0x525, 0x0000004F,
+		0x550, 0x00000010,
+		0x551, 0x00000010,
+		0x559, 0x00000002,
+		0x55D, 0x000000FF,
+		0x605, 0x00000030,
+		0x608, 0x0000000E,
+		0x609, 0x0000002A,
+		0x620, 0x000000FF,
+		0x621, 0x000000FF,
+		0x622, 0x000000FF,
+		0x623, 0x000000FF,
+		0x624, 0x000000FF,
+		0x625, 0x000000FF,
+		0x626, 0x000000FF,
+		0x627, 0x000000FF,
+		0x652, 0x00000020,
+		0x63C, 0x0000000A,
+		0x63D, 0x0000000A,
+		0x63E, 0x0000000E,
+		0x63F, 0x0000000E,
+		0x640, 0x00000040,
+		0x66E, 0x00000005,
+		0x700, 0x00000021,
+		0x701, 0x00000043,
+		0x702, 0x00000065,
+		0x703, 0x00000087,
+		0x708, 0x00000021,
+		0x709, 0x00000043,
+		0x70A, 0x00000065,
+		0x70B, 0x00000087,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *dm_odm)
+{
+	#define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = array[i]; v2 = array[i+1]; } while (0)
+
+	u32     hex         = 0;
+	u32     i;
+	u8     platform    = dm_odm->SupportPlatform;
+	u8     interface_val   = dm_odm->SupportInterface;
+	u8     board       = dm_odm->BoardType;
+	u32     array_len    = sizeof(array_MAC_REG_8188E)/sizeof(u32);
+	u32    *array       = array_MAC_REG_8188E;
+	bool	biol = false;
+
+	struct adapter *adapt =  dm_odm->Adapter;
+	struct xmit_frame	*pxmit_frame = NULL;
+	u8 bndy_cnt = 1;
+	enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+	hex += board;
+	hex += interface_val << 8;
+	hex += platform << 16;
+	hex += 0xFF000000;
+
+	biol = rtw_IOL_applied(adapt);
+
+	if (biol) {
+		pxmit_frame = rtw_IOL_accquire_xmit_frame(adapt);
+		if (pxmit_frame == NULL) {
+			pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+			return HAL_STATUS_FAILURE;
+		}
+	}
+
+	for (i = 0; i < array_len; i += 2) {
+		u32 v1 = array[i];
+		u32 v2 = array[i+1];
+
+		/*  This (offset, data) pair meets the condition. */
+		if (v1 < 0xCDCDCDCD) {
+				if (biol) {
+					if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+						bndy_cnt++;
+					rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF);
+				} else {
+					odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2);
+				}
+				continue;
+		} else { /*  This line is the start line of branch. */
+			if (!Checkcondition(array[i], hex)) {
+				/*  Discard the following (offset, data) pairs. */
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < array_len - 2) {
+					READ_NEXT_PAIR(v1, v2, i);
+				}
+				i -= 2; /*  prevent from for-loop += 2 */
+			} else { /*  Configure matched pairs and skip to end of if-else. */
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < array_len - 2) {
+					if (biol) {
+						if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+							bndy_cnt++;
+						rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF);
+					} else {
+						odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2);
+					}
+
+					READ_NEXT_PAIR(v1, v2, i);
+				}
+				while (v2 != 0xDEAD && i < array_len - 2)
+					READ_NEXT_PAIR(v1, v2, i);
+			}
+		}
+	}
+	if (biol) {
+		if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+			pr_info("~~~ MAC IOL_exec_cmds Failed !!!\n");
+			rst = HAL_STATUS_FAILURE;
+		}
+	}
+	return rst;
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c
new file mode 100644
index 0000000..480c810
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalHWImg8188E_RF.c
@@ -0,0 +1,269 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#include "odm_precomp.h"
+
+#include <rtw_iol.h>
+
+static bool CheckCondition(const u32  Condition, const u32  Hex)
+{
+	u32 _board     = (Hex & 0x000000FF);
+	u32 _interface = (Hex & 0x0000FF00) >> 8;
+	u32 _platform  = (Hex & 0x00FF0000) >> 16;
+	u32 cond = Condition;
+
+	if (Condition == 0xCDCDCDCD)
+		return true;
+
+	cond = Condition & 0x000000FF;
+	if ((_board == cond) && cond != 0x00)
+		return false;
+
+	cond = Condition & 0x0000FF00;
+	cond = cond >> 8;
+	if ((_interface & cond) == 0 && cond != 0x07)
+		return false;
+
+	cond = Condition & 0x00FF0000;
+	cond = cond >> 16;
+	if ((_platform & cond) == 0 && cond != 0x0F)
+		return false;
+	return true;
+}
+
+
+/******************************************************************************
+*                           RadioA_1T.TXT
+******************************************************************************/
+
+static u32 Array_RadioA_1T_8188E[] = {
+		0x000, 0x00030000,
+		0x008, 0x00084000,
+		0x018, 0x00000407,
+		0x019, 0x00000012,
+		0x01E, 0x00080009,
+		0x01F, 0x00000880,
+		0x02F, 0x0001A060,
+		0x03F, 0x00000000,
+		0x042, 0x000060C0,
+		0x057, 0x000D0000,
+		0x058, 0x000BE180,
+		0x067, 0x00001552,
+		0x083, 0x00000000,
+		0x0B0, 0x000FF8FC,
+		0x0B1, 0x00054400,
+		0x0B2, 0x000CCC19,
+		0x0B4, 0x00043003,
+		0x0B6, 0x0004953E,
+		0x0B7, 0x0001C718,
+		0x0B8, 0x000060FF,
+		0x0B9, 0x00080001,
+		0x0BA, 0x00040000,
+		0x0BB, 0x00000400,
+		0x0BF, 0x000C0000,
+		0x0C2, 0x00002400,
+		0x0C3, 0x00000009,
+		0x0C4, 0x00040C91,
+		0x0C5, 0x00099999,
+		0x0C6, 0x000000A3,
+		0x0C7, 0x00088820,
+		0x0C8, 0x00076C06,
+		0x0C9, 0x00000000,
+		0x0CA, 0x00080000,
+		0x0DF, 0x00000180,
+		0x0EF, 0x000001A0,
+		0x051, 0x0006B27D,
+		0xFF0F041F, 0xABCD,
+		0x052, 0x0007E4DD,
+		0xCDCDCDCD, 0xCDCD,
+		0x052, 0x0007E49D,
+		0xFF0F041F, 0xDEAD,
+		0x053, 0x00000073,
+		0x056, 0x00051FF3,
+		0x035, 0x00000086,
+		0x035, 0x00000186,
+		0x035, 0x00000286,
+		0x036, 0x00001C25,
+		0x036, 0x00009C25,
+		0x036, 0x00011C25,
+		0x036, 0x00019C25,
+		0x0B6, 0x00048538,
+		0x018, 0x00000C07,
+		0x05A, 0x0004BD00,
+		0x019, 0x000739D0,
+		0x034, 0x0000ADF3,
+		0x034, 0x00009DF0,
+		0x034, 0x00008DED,
+		0x034, 0x00007DEA,
+		0x034, 0x00006DE7,
+		0x034, 0x000054EE,
+		0x034, 0x000044EB,
+		0x034, 0x000034E8,
+		0x034, 0x0000246B,
+		0x034, 0x00001468,
+		0x034, 0x0000006D,
+		0x000, 0x00030159,
+		0x084, 0x00068200,
+		0x086, 0x000000CE,
+		0x087, 0x00048A00,
+		0x08E, 0x00065540,
+		0x08F, 0x00088000,
+		0x0EF, 0x000020A0,
+		0x03B, 0x000F02B0,
+		0x03B, 0x000EF7B0,
+		0x03B, 0x000D4FB0,
+		0x03B, 0x000CF060,
+		0x03B, 0x000B0090,
+		0x03B, 0x000A0080,
+		0x03B, 0x00090080,
+		0x03B, 0x0008F780,
+		0x03B, 0x000722B0,
+		0x03B, 0x0006F7B0,
+		0x03B, 0x00054FB0,
+		0x03B, 0x0004F060,
+		0x03B, 0x00030090,
+		0x03B, 0x00020080,
+		0x03B, 0x00010080,
+		0x03B, 0x0000F780,
+		0x0EF, 0x000000A0,
+		0x000, 0x00010159,
+		0x018, 0x0000F407,
+		0xFFE, 0x00000000,
+		0xFFE, 0x00000000,
+		0x01F, 0x00080003,
+		0xFFE, 0x00000000,
+		0xFFE, 0x00000000,
+		0x01E, 0x00000001,
+		0x01F, 0x00080000,
+		0x000, 0x00033E60,
+};
+
+enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *pDM_Odm)
+{
+	#define READ_NEXT_PAIR(v1, v2, i) do	\
+		 { i += 2; v1 = Array[i];	\
+		 v2 = Array[i+1]; } while (0)
+
+	u32     hex         = 0;
+	u32     i           = 0;
+	u8     platform    = pDM_Odm->SupportPlatform;
+	u8     interfaceValue   = pDM_Odm->SupportInterface;
+	u8     board       = pDM_Odm->BoardType;
+	u32     ArrayLen    = sizeof(Array_RadioA_1T_8188E)/sizeof(u32);
+	u32    *Array       = Array_RadioA_1T_8188E;
+	bool		biol = false;
+	struct adapter *Adapter =  pDM_Odm->Adapter;
+	struct xmit_frame *pxmit_frame = NULL;
+	u8 bndy_cnt = 1;
+	enum HAL_STATUS rst = HAL_STATUS_SUCCESS;
+
+	hex += board;
+	hex += interfaceValue << 8;
+	hex += platform << 16;
+	hex += 0xFF000000;
+	biol = rtw_IOL_applied(Adapter);
+
+	if (biol) {
+		pxmit_frame = rtw_IOL_accquire_xmit_frame(Adapter);
+		if (pxmit_frame == NULL) {
+			pr_info("rtw_IOL_accquire_xmit_frame failed\n");
+			return HAL_STATUS_FAILURE;
+		}
+	}
+
+	for (i = 0; i < ArrayLen; i += 2) {
+		u32 v1 = Array[i];
+		u32 v2 = Array[i+1];
+
+		/*  This (offset, data) pair meets the condition. */
+		if (v1 < 0xCDCDCDCD) {
+			if (biol) {
+				if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+					bndy_cnt++;
+
+				if (v1 == 0xffe)
+					rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+				else if (v1 == 0xfd)
+					rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+				else if (v1 == 0xfc)
+					rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+				else if (v1 == 0xfb)
+					rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+				else if (v1 == 0xfa)
+					rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+				else if (v1 == 0xf9)
+					rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+				else
+					rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask);
+			} else {
+				odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2);
+			}
+		    continue;
+		} else { /*  This line is the start line of branch. */
+			if (!CheckCondition(Array[i], hex)) {
+				/*  Discard the following (offset, data) pairs. */
+				READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < ArrayLen - 2)
+					READ_NEXT_PAIR(v1, v2, i);
+				i -= 2; /*  prevent from for-loop += 2 */
+			} else { /*  Configure matched pairs and skip to end of if-else. */
+			READ_NEXT_PAIR(v1, v2, i);
+				while (v2 != 0xDEAD &&
+				       v2 != 0xCDEF &&
+				       v2 != 0xCDCD && i < ArrayLen - 2) {
+					if (biol) {
+						if (rtw_IOL_cmd_boundary_handle(pxmit_frame))
+							bndy_cnt++;
+
+						if (v1 == 0xffe)
+							rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50);
+						else if (v1 == 0xfd)
+							rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5);
+						else if (v1 == 0xfc)
+							rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1);
+						else if (v1 == 0xfb)
+							rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50);
+						else if (v1 == 0xfa)
+							rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5);
+						else if (v1 == 0xf9)
+							rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1);
+						else
+							rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask);
+					} else {
+						odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2);
+					}
+					READ_NEXT_PAIR(v1, v2, i);
+				}
+
+				while (v2 != 0xDEAD && i < ArrayLen - 2)
+					READ_NEXT_PAIR(v1, v2, i);
+			}
+		}
+	}
+	if (biol) {
+		if (!rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) {
+			rst = HAL_STATUS_FAILURE;
+			pr_info("~~~ IOL Config %s Failed !!!\n", __func__);
+		}
+	}
+	return rst;
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalPhyRf.c b/drivers/staging/rtl8188eu/hal/HalPhyRf.c
new file mode 100644
index 0000000..980f7da
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalPhyRf.c
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+ #include "odm_precomp.h"
+
+/* 3============================================================ */
+/* 3 IQ Calibration */
+/* 3============================================================ */
+
+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+u8 ODM_GetRightChnlPlaceforIQK(u8 chnl)
+{
+	u8	channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = {
+		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+		36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64,
+		100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122,
+		124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153,
+		155, 157, 159, 161, 163, 165
+	};
+	u8	place = chnl;
+
+	if (chnl > 14) {
+		for (place = 14; place < sizeof(channel_all); place++) {
+			if (channel_all[place] == chnl)
+				return place-13;
+		}
+	}
+	return 0;
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
new file mode 100644
index 0000000..e4f20da
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalPhyRf_8188e.c
@@ -0,0 +1,1928 @@
+
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+
+/*---------------------------Define Local Constant---------------------------*/
+/*  2010/04/25 MH Define the max tx power tracking tx agc power. */
+#define		ODM_TXPWRTRACK_MAX_IDX_88E		6
+
+/*---------------------------Define Local Constant---------------------------*/
+
+/* 3============================================================ */
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+/*-----------------------------------------------------------------------------
+ * Function:	ODM_TxPwrTrackAdjust88E()
+ *
+ * Overview:	88E we can not write 0xc80/c94/c4c/ 0xa2x. Instead of write TX agc.
+ *				No matter OFDM & CCK use the same method.
+ *
+ * Input:		NONE
+ *
+ * Output:		NONE
+ *
+ * Return:		NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	04/23/2012	MHC		Create Version 0.
+ *	04/23/2012	MHC		Adjust TX agc directly not throughput BB digital.
+ *
+ *---------------------------------------------------------------------------*/
+void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *dm_odm, u8 Type,/*  0 = OFDM, 1 = CCK */
+	u8 *pDirection, 		/*  1 = +(increase) 2 = -(decrease) */
+	u32 *pOutWriteVal		/*  Tx tracking CCK/OFDM BB swing index adjust */
+	)
+{
+	u8 pwr_value = 0;
+	/*  Tx power tracking BB swing table. */
+	/*  The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */
+	if (Type == 0) {		/*  For OFDM afjust */
+		ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
+			     ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n",
+			     dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm));
+
+		if (dm_odm->BbSwingIdxOfdm <= dm_odm->BbSwingIdxOfdmBase) {
+			*pDirection	= 1;
+			pwr_value		= (dm_odm->BbSwingIdxOfdmBase - dm_odm->BbSwingIdxOfdm);
+		} else {
+			*pDirection	= 2;
+			pwr_value		= (dm_odm->BbSwingIdxOfdm - dm_odm->BbSwingIdxOfdmBase);
+		}
+
+		ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
+			     ("BbSwingIdxOfdm = %d BbSwingFlagOfdm=%d\n",
+			     dm_odm->BbSwingIdxOfdm, dm_odm->BbSwingFlagOfdm));
+	} else if (Type == 1) {	/*  For CCK adjust. */
+		ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,
+			     ("dm_odm->BbSwingIdxCck = %d dm_odm->BbSwingIdxCckBase = %d\n",
+			     dm_odm->BbSwingIdxCck, dm_odm->BbSwingIdxCckBase));
+
+		if (dm_odm->BbSwingIdxCck <= dm_odm->BbSwingIdxCckBase) {
+			*pDirection	= 1;
+			pwr_value		= (dm_odm->BbSwingIdxCckBase - dm_odm->BbSwingIdxCck);
+		} else {
+			*pDirection	= 2;
+			pwr_value		= (dm_odm->BbSwingIdxCck - dm_odm->BbSwingIdxCckBase);
+		}
+	}
+
+	/*  */
+	/*  2012/04/25 MH According to Ed/Luke.Lees estimate for EVM the max tx power tracking */
+	/*  need to be less than 6 power index for 88E. */
+	/*  */
+	if (pwr_value >= ODM_TXPWRTRACK_MAX_IDX_88E && *pDirection == 1)
+		pwr_value = ODM_TXPWRTRACK_MAX_IDX_88E;
+
+	*pOutWriteVal = pwr_value | (pwr_value<<8) | (pwr_value<<16) | (pwr_value<<24);
+}	/*  ODM_TxPwrTrackAdjust88E */
+
+/*-----------------------------------------------------------------------------
+ * Function:	odm_TxPwrTrackSetPwr88E()
+ *
+ * Overview:	88E change all channel tx power accordign to flag.
+ *				OFDM & CCK are all different.
+ *
+ * Input:		NONE
+ *
+ * Output:		NONE
+ *
+ * Return:		NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	04/23/2012	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void odm_TxPwrTrackSetPwr88E(struct odm_dm_struct *dm_odm)
+{
+	if (dm_odm->BbSwingFlagOfdm || dm_odm->BbSwingFlagCck) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr88E CH=%d\n", *(dm_odm->pChannel)));
+		PHY_SetTxPowerLevel8188E(dm_odm->Adapter, *(dm_odm->pChannel));
+		dm_odm->BbSwingFlagOfdm = false;
+		dm_odm->BbSwingFlagCck	= false;
+	}
+}	/*  odm_TxPwrTrackSetPwr88E */
+
+/* 091212 chiyokolin */
+void
+odm_TXPowerTrackingCallback_ThermalMeter_8188E(
+	struct adapter *Adapter
+	)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, offset;
+	u8 ThermalValue_AVG_count = 0;
+	u32 ThermalValue_AVG = 0;
+	s32 ele_A = 0, ele_D, TempCCk, X, value32;
+	s32 Y, ele_C = 0;
+	s8 OFDM_index[2], CCK_index = 0;
+	s8 OFDM_index_old[2] = {0, 0}, CCK_index_old = 0;
+	u32 i = 0, j = 0;
+	bool is2t = false;
+
+	u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */
+	u8 Indexforchannel = 0/*GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/;
+	s8 OFDM_index_mapping[2][index_mapping_NUM_88E] = {
+		{0, 0, 2, 3, 4, 4, 		/* 2.4G, decrease power */
+		5, 6, 7, 7, 8, 9,
+		10, 10, 11}, /*  For lower temperature, 20120220 updated on 20120220. */
+		{0, 0, -1, -2, -3, -4, 		/* 2.4G, increase power */
+		-4, -4, -4, -5, -7, -8,
+		-9, -9, -10},
+	};
+	u8 Thermal_mapping[2][index_mapping_NUM_88E] = {
+		{0, 2, 4, 6, 8, 10, 		/* 2.4G, decrease power */
+		12, 14, 16, 18, 20, 22,
+		24, 26, 27},
+		{0, 2, 4, 6, 8, 10, 		/* 2.4G,, increase power */
+		12, 14, 16, 18, 20, 22,
+		25, 25, 25},
+	};
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	/*  2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */
+	odm_TxPwrTrackSetPwr88E(dm_odm);
+
+	dm_odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; /* cosa add for debug */
+	dm_odm->RFCalibrateInfo.bTXPowerTrackingInit = true;
+
+	/*  <Kordan> RFCalibrateInfo.RegA24 will be initialized when ODM HW configuring, but MP configures with para files. */
+	dm_odm->RFCalibrateInfo.RegA24 = 0x090e1317;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("===>dm_TXPowerTrackingCallback_ThermalMeter_8188E txpowercontrol %d\n",
+		     dm_odm->RFCalibrateInfo.TxPowerTrackControl));
+
+	ThermalValue = (u8)ODM_GetRFReg(dm_odm, RF_PATH_A, RF_T_METER_88E, 0xfc00);	/* 0x42: RF Reg[15:10] 88E */
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n",
+		     ThermalValue, dm_odm->RFCalibrateInfo.ThermalValue, pHalData->EEPROMThermalMeter));
+
+	if (is2t)
+		rf = 2;
+	else
+		rf = 1;
+
+	if (ThermalValue) {
+		/* Query OFDM path A default setting */
+		ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord)&bMaskOFDM_D;
+		for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {	/* find the index */
+			if (ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) {
+				OFDM_index_old[0] = (u8)i;
+				dm_odm->BbSwingIdxOfdmBase = (u8)i;
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("Initial pathA ele_D reg0x%x = 0x%x, OFDM_index=0x%x\n",
+					     rOFDM0_XATxIQImbalance, ele_D, OFDM_index_old[0]));
+				break;
+			}
+		}
+
+		/* Query OFDM path B default setting */
+		if (is2t) {
+			ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord)&bMaskOFDM_D;
+			for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {	/* find the index */
+				if (ele_D == (OFDMSwingTable[i]&bMaskOFDM_D)) {
+					OFDM_index_old[1] = (u8)i;
+					ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+						     ("Initial pathB ele_D reg0x%x = 0x%x, OFDM_index=0x%x\n",
+						rOFDM0_XBTxIQImbalance, ele_D, OFDM_index_old[1]));
+					break;
+				}
+			}
+		}
+
+		/* Query CCK default setting From 0xa24 */
+		TempCCk = dm_odm->RFCalibrateInfo.RegA24;
+
+		for (i = 0; i < CCK_TABLE_SIZE; i++) {
+			if (dm_odm->RFCalibrateInfo.bCCKinCH14) {
+				if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4) == 0) {
+					CCK_index_old = (u8)i;
+					dm_odm->BbSwingIdxCckBase = (u8)i;
+					ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+						     ("Initial reg0x%x = 0x%x, CCK_index=0x%x, ch 14 %d\n",
+						     rCCK0_TxFilter2, TempCCk, CCK_index_old, dm_odm->RFCalibrateInfo.bCCKinCH14));
+					break;
+				}
+			} else {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("RegA24: 0x%X, CCKSwingTable_Ch1_Ch13[%d][2]: CCKSwingTable_Ch1_Ch13[i][2]: 0x%X\n",
+					     TempCCk, i, CCKSwingTable_Ch1_Ch13[i][2]));
+				if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4) == 0) {
+					CCK_index_old = (u8)i;
+					dm_odm->BbSwingIdxCckBase = (u8)i;
+					ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+						     ("Initial reg0x%x = 0x%x, CCK_index=0x%x, ch14 %d\n",
+						     rCCK0_TxFilter2, TempCCk, CCK_index_old, dm_odm->RFCalibrateInfo.bCCKinCH14));
+					break;
+				}
+			}
+		}
+
+		if (!dm_odm->RFCalibrateInfo.ThermalValue) {
+			dm_odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter;
+			dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
+			dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue;
+
+			for (i = 0; i < rf; i++)
+				dm_odm->RFCalibrateInfo.OFDM_index[i] = OFDM_index_old[i];
+			dm_odm->RFCalibrateInfo.CCK_index = CCK_index_old;
+		}
+
+		if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex)
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+				     ("reload ofdm index for band switch\n"));
+
+		/* calculate average thermal meter */
+		dm_odm->RFCalibrateInfo.ThermalValue_AVG[dm_odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue;
+		dm_odm->RFCalibrateInfo.ThermalValue_AVG_index++;
+		if (dm_odm->RFCalibrateInfo.ThermalValue_AVG_index == AVG_THERMAL_NUM_88E)
+			dm_odm->RFCalibrateInfo.ThermalValue_AVG_index = 0;
+
+		for (i = 0; i < AVG_THERMAL_NUM_88E; i++) {
+			if (dm_odm->RFCalibrateInfo.ThermalValue_AVG[i]) {
+				ThermalValue_AVG += dm_odm->RFCalibrateInfo.ThermalValue_AVG[i];
+				ThermalValue_AVG_count++;
+			}
+		}
+
+		if (ThermalValue_AVG_count) {
+			ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count);
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+				     ("AVG Thermal Meter = 0x%x\n", ThermalValue));
+		}
+
+		if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex) {
+			delta = ThermalValue > pHalData->EEPROMThermalMeter ?
+				(ThermalValue - pHalData->EEPROMThermalMeter) :
+				(pHalData->EEPROMThermalMeter - ThermalValue);
+			dm_odm->RFCalibrateInfo.bReloadtxpowerindex = false;
+			dm_odm->RFCalibrateInfo.bDoneTxpower = false;
+		} else if (dm_odm->RFCalibrateInfo.bDoneTxpower) {
+			delta = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue) ?
+				(ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue) :
+				(dm_odm->RFCalibrateInfo.ThermalValue - ThermalValue);
+		} else {
+			delta = ThermalValue > pHalData->EEPROMThermalMeter ?
+				(ThermalValue - pHalData->EEPROMThermalMeter) :
+				(pHalData->EEPROMThermalMeter - ThermalValue);
+		}
+		delta_LCK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_LCK) ?
+			    (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_LCK) :
+			    (dm_odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue);
+		delta_IQK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_IQK) ?
+			    (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_IQK) :
+			    (dm_odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue);
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x delta 0x%x delta_LCK 0x%x delta_IQK 0x%x\n",
+			     ThermalValue, dm_odm->RFCalibrateInfo.ThermalValue,
+			     pHalData->EEPROMThermalMeter, delta, delta_LCK, delta_IQK));
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("pre thermal meter LCK 0x%x pre thermal meter IQK 0x%x delta_LCK_bound 0x%x delta_IQK_bound 0x%x\n",
+			     dm_odm->RFCalibrateInfo.ThermalValue_LCK,
+			     dm_odm->RFCalibrateInfo.ThermalValue_IQK,
+			     dm_odm->RFCalibrateInfo.Delta_LCK,
+			     dm_odm->RFCalibrateInfo.Delta_IQK));
+
+		if ((delta_LCK >= 8)) { /*  Delta temperature is equal to or larger than 20 centigrade. */
+			dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue;
+			PHY_LCCalibrate_8188E(Adapter);
+		}
+
+		if (delta > 0 && dm_odm->RFCalibrateInfo.TxPowerTrackControl) {
+			delta = ThermalValue > pHalData->EEPROMThermalMeter ?
+				(ThermalValue - pHalData->EEPROMThermalMeter) :
+				(pHalData->EEPROMThermalMeter - ThermalValue);
+			/* calculate new OFDM / CCK offset */
+			if (ThermalValue > pHalData->EEPROMThermalMeter)
+				j = 1;
+			else
+				j = 0;
+			for (offset = 0; offset < index_mapping_NUM_88E; offset++) {
+				if (delta < Thermal_mapping[j][offset]) {
+					if (offset != 0)
+						offset--;
+					break;
+				}
+			}
+			if (offset >= index_mapping_NUM_88E)
+				offset = index_mapping_NUM_88E-1;
+			for (i = 0; i < rf; i++)
+				OFDM_index[i] = dm_odm->RFCalibrateInfo.OFDM_index[i] + OFDM_index_mapping[j][offset];
+			CCK_index = dm_odm->RFCalibrateInfo.CCK_index + OFDM_index_mapping[j][offset];
+
+			if (is2t) {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("temp OFDM_A_index=0x%x, OFDM_B_index=0x%x, CCK_index=0x%x\n",
+					     dm_odm->RFCalibrateInfo.OFDM_index[0],
+					     dm_odm->RFCalibrateInfo.OFDM_index[1],
+					     dm_odm->RFCalibrateInfo.CCK_index));
+			} else {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("temp OFDM_A_index=0x%x, CCK_index=0x%x\n",
+					     dm_odm->RFCalibrateInfo.OFDM_index[0],
+					     dm_odm->RFCalibrateInfo.CCK_index));
+			}
+
+			for (i = 0; i < rf; i++) {
+				if (OFDM_index[i] > OFDM_TABLE_SIZE_92D-1)
+					OFDM_index[i] = OFDM_TABLE_SIZE_92D-1;
+				else if (OFDM_index[i] < OFDM_min_index)
+					OFDM_index[i] = OFDM_min_index;
+			}
+
+			if (CCK_index > CCK_TABLE_SIZE-1)
+				CCK_index = CCK_TABLE_SIZE-1;
+			else if (CCK_index < 0)
+				CCK_index = 0;
+
+			if (is2t) {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("new OFDM_A_index=0x%x, OFDM_B_index=0x%x, CCK_index=0x%x\n",
+					     OFDM_index[0], OFDM_index[1], CCK_index));
+			} else {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("new OFDM_A_index=0x%x, CCK_index=0x%x\n",
+					     OFDM_index[0], CCK_index));
+			}
+
+			/* 2 temporarily remove bNOPG */
+			/* Config by SwingTable */
+			if (dm_odm->RFCalibrateInfo.TxPowerTrackControl) {
+				dm_odm->RFCalibrateInfo.bDoneTxpower = true;
+
+				/* Adujst OFDM Ant_A according to IQK result */
+				ele_D = (OFDMSwingTable[(u8)OFDM_index[0]] & 0xFFC00000)>>22;
+				X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][0];
+				Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][1];
+
+				/*  Revse TX power table. */
+				dm_odm->BbSwingIdxOfdm		= (u8)OFDM_index[0];
+				dm_odm->BbSwingIdxCck		= (u8)CCK_index;
+
+				if (dm_odm->BbSwingIdxOfdmCurrent != dm_odm->BbSwingIdxOfdm) {
+					dm_odm->BbSwingIdxOfdmCurrent = dm_odm->BbSwingIdxOfdm;
+					dm_odm->BbSwingFlagOfdm = true;
+				}
+
+				if (dm_odm->BbSwingIdxCckCurrent != dm_odm->BbSwingIdxCck) {
+					dm_odm->BbSwingIdxCckCurrent = dm_odm->BbSwingIdxCck;
+					dm_odm->BbSwingFlagCck = true;
+				}
+
+				if (X != 0) {
+					if ((X & 0x00000200) != 0)
+						X = X | 0xFFFFFC00;
+					ele_A = ((X * ele_D)>>8)&0x000003FF;
+
+					/* new element C = element D x Y */
+					if ((Y & 0x00000200) != 0)
+						Y = Y | 0xFFFFFC00;
+					ele_C = ((Y * ele_D)>>8)&0x000003FF;
+
+					/*  2012/04/23 MH According to Luke's suggestion, we can not write BB digital */
+					/*  to increase TX power. Otherwise, EVM will be bad. */
+				}
+
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("TxPwrTracking for path A: X=0x%x, Y=0x%x ele_A=0x%x ele_C=0x%x ele_D=0x%x 0xe94=0x%x 0xe9c=0x%x\n",
+					     (u32)X, (u32)Y, (u32)ele_A, (u32)ele_C, (u32)ele_D, (u32)X, (u32)Y));
+
+				if (is2t) {
+					ele_D = (OFDMSwingTable[(u8)OFDM_index[1]] & 0xFFC00000)>>22;
+
+					/* new element A = element D x X */
+					X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][4];
+					Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][5];
+
+					if ((X != 0) && (*(dm_odm->pBandType) == ODM_BAND_2_4G)) {
+						if ((X & 0x00000200) != 0)	/* consider minus */
+							X = X | 0xFFFFFC00;
+						ele_A = ((X * ele_D)>>8)&0x000003FF;
+
+						/* new element C = element D x Y */
+						if ((Y & 0x00000200) != 0)
+							Y = Y | 0xFFFFFC00;
+						ele_C = ((Y * ele_D)>>8)&0x00003FF;
+
+						/* wtite new elements A, C, D to regC88 and regC9C, element B is always 0 */
+						value32 = (ele_D<<22) | ((ele_C&0x3F)<<16) | ele_A;
+						ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, value32);
+
+						value32 = (ele_C&0x000003C0)>>6;
+						ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, value32);
+
+						value32 = ((X * ele_D)>>7)&0x01;
+						ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT28, value32);
+					} else {
+						ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable[(u8)OFDM_index[1]]);
+						ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00);
+						ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT28, 0x00);
+					}
+
+					ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+						     ("TxPwrTracking path B: X=0x%x, Y=0x%x ele_A=0x%x ele_C=0x%x ele_D=0x%x 0xeb4=0x%x 0xebc=0x%x\n",
+						     (u32)X, (u32)Y, (u32)ele_A,
+						     (u32)ele_C, (u32)ele_D, (u32)X, (u32)Y));
+				}
+
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("TxPwrTracking 0xc80 = 0x%x, 0xc94 = 0x%x RF 0x24 = 0x%x\n",
+					     ODM_GetBBReg(dm_odm, 0xc80, bMaskDWord), ODM_GetBBReg(dm_odm,
+					     0xc94, bMaskDWord), ODM_GetRFReg(dm_odm, RF_PATH_A, 0x24, bRFRegOffsetMask)));
+			}
+		}
+
+		if (delta_IQK >= 8) { /*  Delta temperature is equal to or larger than 20 centigrade. */
+			ODM_ResetIQKResult(dm_odm);
+
+			dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue;
+			PHY_IQCalibrate_8188E(Adapter, false);
+		}
+		/* update thermal meter value */
+		if (dm_odm->RFCalibrateInfo.TxPowerTrackControl)
+			dm_odm->RFCalibrateInfo.ThermalValue = ThermalValue;
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("<===dm_TXPowerTrackingCallback_ThermalMeter_8188E\n"));
+	dm_odm->RFCalibrateInfo.TXPowercount = 0;
+}
+
+/* 1 7.	IQK */
+#define MAX_TOLERANCE		5
+#define IQK_DELAY_TIME		1		/* ms */
+
+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+phy_PathA_IQK_8188E(struct adapter *adapt, bool configPathB)
+{
+	u32 regeac, regE94, regE9C, regEA4;
+	u8 result = 0x00;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n"));
+
+	/* 1 Tx IQK */
+	/* path-A IQK setting */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n"));
+	ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c);
+	ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c);
+	ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x8214032a);
+	ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000);
+
+	/* LO calibration setting */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x00462911);
+
+	/* One shot, path A LOK & IQK */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+	/*  delay x ms */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E));
+	/* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
+	ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+	/*  Check failed */
+	regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regeac));
+	regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94));
+	regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("0xe9c = 0x%x\n", regE9C));
+	regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4));
+
+	if (!(regeac & BIT28) &&
+	    (((regE94 & 0x03FF0000)>>16) != 0x142) &&
+	    (((regE9C & 0x03FF0000)>>16) != 0x42))
+		result |= 0x01;
+	return result;
+}
+
+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+phy_PathA_RxIQK(struct adapter *adapt, bool configPathB)
+{
+	u32 regeac, regE94, regE9C, regEA4, u4tmp;
+	u8 result = 0x00;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n"));
+
+	/* 1 Get TXIMR setting */
+	/* modify RXIQK mode table */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n"));
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf117B);
+
+	/* PA,PAD off */
+	ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x980);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, 0x56, bRFRegOffsetMask, 0x51000);
+
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+
+	/* IQK setting */
+	ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00);
+	ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800);
+
+	/* path-A IQK setting */
+	ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c);
+	ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c);
+	ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f);
+	ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000);
+
+	/* LO calibration setting */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911);
+
+	/* One shot, path A LOK & IQK */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+	/*  delay x ms */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("Delay %d ms for One shot, path A LOK & IQK.\n",
+		     IQK_DELAY_TIME_88E));
+	ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+	/*  Check failed */
+	regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xeac = 0x%x\n", regeac));
+	regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xe94 = 0x%x\n", regE94));
+	regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xe9c = 0x%x\n", regE9C));
+
+	if (!(regeac & BIT28) &&
+	    (((regE94 & 0x03FF0000)>>16) != 0x142) &&
+	    (((regE9C & 0x03FF0000)>>16) != 0x42))
+		result |= 0x01;
+	else							/* if Tx not OK, ignore Rx */
+		return result;
+
+	u4tmp = 0x80007C00 | (regE94&0x3FF0000)  | ((regE9C&0x3FF0000) >> 16);
+	ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, u4tmp);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x\n", ODM_GetBBReg(dm_odm, rTx_IQK, bMaskDWord), u4tmp));
+
+	/* 1 RX IQK */
+	/* modify RXIQK mode table */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n"));
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7ffa);
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+
+	/* IQK setting */
+	ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x01004800);
+
+	/* path-A IQK setting */
+	ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c);
+	ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c);
+	ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c05);
+	ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160c1f);
+
+	/* LO calibration setting */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911);
+
+	/* One shot, path A LOK & IQK */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+	/*  delay x ms */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E));
+	/* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */
+	ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+	/*  Check failed */
+	regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("0xeac = 0x%x\n", regeac));
+	regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("0xe94 = 0x%x\n", regE94));
+	regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("0xe9c = 0x%x\n", regE9C));
+	regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("0xea4 = 0x%x\n", regEA4));
+
+	/* reload RF 0xdf */
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+	ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180);
+
+	if (!(regeac & BIT27) &&		/* if Tx is OK, check whether Rx is OK */
+	    (((regEA4 & 0x03FF0000)>>16) != 0x132) &&
+	    (((regeac & 0x03FF0000)>>16) != 0x36))
+		result |= 0x02;
+	else
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Path A Rx IQK fail!!\n"));
+
+	return result;
+}
+
+static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */
+phy_PathB_IQK_8188E(struct adapter *adapt)
+{
+	u32 regeac, regeb4, regebc, regec4, regecc;
+	u8 result = 0x00;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Path B IQK!\n"));
+
+	/* One shot, path B LOK & IQK */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n"));
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000002);
+	ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000000);
+
+	/*  delay x ms */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("Delay %d ms for One shot, path B LOK & IQK.\n",
+		     IQK_DELAY_TIME_88E));
+	ODM_delay_ms(IQK_DELAY_TIME_88E);
+
+	/*  Check failed */
+	regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xeac = 0x%x\n", regeac));
+	regeb4 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xeb4 = 0x%x\n", regeb4));
+	regebc = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xebc = 0x%x\n", regebc));
+	regec4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xec4 = 0x%x\n", regec4));
+	regecc = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord);
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("0xecc = 0x%x\n", regecc));
+
+	if (!(regeac & BIT31) &&
+	    (((regeb4 & 0x03FF0000)>>16) != 0x142) &&
+	    (((regebc & 0x03FF0000)>>16) != 0x42))
+		result |= 0x01;
+	else
+		return result;
+
+	if (!(regeac & BIT30) &&
+	    (((regec4 & 0x03FF0000)>>16) != 0x132) &&
+	    (((regecc & 0x03FF0000)>>16) != 0x36))
+		result |= 0x02;
+	else
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Path B Rx IQK fail!!\n"));
+	return result;
+}
+
+static void patha_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly)
+{
+	u32 Oldval_0, X, TX0_A, reg;
+	s32 Y, TX0_C;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("Path A IQ Calibration %s !\n",
+		     (iqkok) ? "Success" : "Failed"));
+
+	if (final_candidate == 0xFF) {
+		return;
+	} else if (iqkok) {
+		Oldval_0 = (ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF;
+
+		X = result[final_candidate][0];
+		if ((X & 0x00000200) != 0)
+			X = X | 0xFFFFFC00;
+		TX0_A = (X * Oldval_0) >> 8;
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n",
+			     X, TX0_A, Oldval_0));
+		ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A);
+
+		ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(31), ((X * Oldval_0>>7) & 0x1));
+
+		Y = result[final_candidate][1];
+		if ((Y & 0x00000200) != 0)
+			Y = Y | 0xFFFFFC00;
+
+		TX0_C = (Y * Oldval_0) >> 8;
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C));
+		ODM_SetBBReg(dm_odm, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6));
+		ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F));
+
+		ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(29), ((Y * Oldval_0>>7) & 0x1));
+
+		if (txonly) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("patha_fill_iqk only Tx OK\n"));
+			return;
+		}
+
+		reg = result[final_candidate][2];
+		ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0x3FF, reg);
+
+		reg = result[final_candidate][3] & 0x3F;
+		ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0xFC00, reg);
+
+		reg = (result[final_candidate][3] >> 6) & 0xF;
+		ODM_SetBBReg(dm_odm, rOFDM0_RxIQExtAnta, 0xF0000000, reg);
+	}
+}
+
+static void pathb_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly)
+{
+	u32 Oldval_1, X, TX1_A, reg;
+	s32 Y, TX1_C;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("Path B IQ Calibration %s !\n",
+		     (iqkok) ? "Success" : "Failed"));
+
+	if (final_candidate == 0xFF) {
+		return;
+	} else if (iqkok) {
+		Oldval_1 = (ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF;
+
+		X = result[final_candidate][4];
+		if ((X & 0x00000200) != 0)
+			X = X | 0xFFFFFC00;
+		TX1_A = (X * Oldval_1) >> 8;
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A));
+		ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A);
+
+		ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(27), ((X * Oldval_1>>7) & 0x1));
+
+		Y = result[final_candidate][5];
+		if ((Y & 0x00000200) != 0)
+			Y = Y | 0xFFFFFC00;
+
+		TX1_C = (Y * Oldval_1) >> 8;
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C));
+		ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6));
+		ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F));
+
+		ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(25), ((Y * Oldval_1>>7) & 0x1));
+
+		if (txonly)
+			return;
+
+		reg = result[final_candidate][6];
+		ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0x3FF, reg);
+
+		reg = result[final_candidate][7] & 0x3F;
+		ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0xFC00, reg);
+
+		reg = (result[final_candidate][7] >> 6) & 0xF;
+		ODM_SetBBReg(dm_odm, rOFDM0_AGCRSSITable, 0x0000F000, reg);
+	}
+}
+
+/*  */
+/*  2011/07/26 MH Add an API for testing IQK fail case. */
+/*  */
+/*  MP Already declare in odm.c */
+static bool ODM_CheckPowerStatus(struct adapter *Adapter)
+{
+	return	true;
+}
+
+void _PHY_SaveADDARegisters(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum)
+{
+	u32 i;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	if (ODM_CheckPowerStatus(adapt) == false)
+		return;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n"));
+	for (i = 0; i < RegisterNum; i++) {
+		ADDABackup[i] = ODM_GetBBReg(dm_odm, ADDAReg[i], bMaskDWord);
+	}
+}
+
+static void _PHY_SaveMACRegisters(
+		struct adapter *adapt,
+		u32 *MACReg,
+		u32 *MACBackup
+	)
+{
+	u32 i;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n"));
+	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) {
+		MACBackup[i] = ODM_Read1Byte(dm_odm, MACReg[i]);
+	}
+	MACBackup[i] = ODM_Read4Byte(dm_odm, MACReg[i]);
+}
+
+static void reload_adda_reg(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum)
+{
+	u32 i;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n"));
+	for (i = 0; i < RegiesterNum; i++)
+		ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, ADDABackup[i]);
+}
+
+static void
+_PHY_ReloadMACRegisters(
+		struct adapter *adapt,
+		u32 *MACReg,
+		u32 *MACBackup
+	)
+{
+	u32 i;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Reload MAC parameters !\n"));
+	for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) {
+		ODM_Write1Byte(dm_odm, MACReg[i], (u8)MACBackup[i]);
+	}
+	ODM_Write4Byte(dm_odm, MACReg[i], MACBackup[i]);
+}
+
+void
+_PHY_PathADDAOn(
+		struct adapter *adapt,
+		u32 *ADDAReg,
+		bool isPathAOn,
+		bool is2t
+	)
+{
+	u32 pathOn;
+	u32 i;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n"));
+
+	pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4;
+	if (false == is2t) {
+		pathOn = 0x0bdb25a0;
+		ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, 0x0b1b25a0);
+	} else {
+		ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, pathOn);
+	}
+
+	for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+		ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, pathOn);
+}
+
+void
+_PHY_MACSettingCalibration(
+		struct adapter *adapt,
+		u32 *MACReg,
+		u32 *MACBackup
+	)
+{
+	u32 i = 0;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n"));
+
+	ODM_Write1Byte(dm_odm, MACReg[i], 0x3F);
+
+	for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) {
+		ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT3)));
+	}
+	ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i]&(~BIT5)));
+}
+
+void
+_PHY_PathAStandBy(
+	struct adapter *adapt
+	)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Path-A standby mode!\n"));
+
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x0);
+	ODM_SetBBReg(dm_odm, 0x840, bMaskDWord, 0x00010000);
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+}
+
+static void _PHY_PIModeSwitch(
+		struct adapter *adapt,
+		bool PIMode
+	)
+{
+	u32 mode;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("BB Switch to %s mode!\n", (PIMode ? "PI" : "SI")));
+
+	mode = PIMode ? 0x01000100 : 0x01000000;
+	ODM_SetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, bMaskDWord, mode);
+	ODM_SetBBReg(dm_odm, rFPGA0_XB_HSSIParameter1, bMaskDWord, mode);
+}
+
+static bool phy_SimularityCompare_8188E(
+		struct adapter *adapt,
+		s32 resulta[][8],
+		u8  c1,
+		u8  c2
+	)
+{
+	u32 i, j, diff, sim_bitmap, bound = 0;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	u8 final_candidate[2] = {0xFF, 0xFF};	/* for path A and path B */
+	bool result = true;
+	bool is2t;
+	s32 tmp1 = 0, tmp2 = 0;
+
+	if ((dm_odm->RFType == ODM_2T2R) || (dm_odm->RFType == ODM_2T3R) || (dm_odm->RFType == ODM_2T4R))
+		is2t = true;
+	else
+		is2t = false;
+
+	if (is2t)
+		bound = 8;
+	else
+		bound = 4;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("===> IQK:phy_SimularityCompare_8188E c1 %d c2 %d!!!\n", c1, c2));
+
+	sim_bitmap = 0;
+
+	for (i = 0; i < bound; i++) {
+		if ((i == 1) || (i == 3) || (i == 5) || (i == 7)) {
+			if ((resulta[c1][i] & 0x00000200) != 0)
+				tmp1 = resulta[c1][i] | 0xFFFFFC00;
+			else
+				tmp1 = resulta[c1][i];
+
+			if ((resulta[c2][i] & 0x00000200) != 0)
+				tmp2 = resulta[c2][i] | 0xFFFFFC00;
+			else
+				tmp2 = resulta[c2][i];
+		} else {
+			tmp1 = resulta[c1][i];
+			tmp2 = resulta[c2][i];
+		}
+
+		diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1);
+
+		if (diff > MAX_TOLERANCE) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+				     ("IQK:phy_SimularityCompare_8188E differnece overflow index %d compare1 0x%x compare2 0x%x!!!\n",
+				     i, resulta[c1][i], resulta[c2][i]));
+
+			if ((i == 2 || i == 6) && !sim_bitmap) {
+				if (resulta[c1][i] + resulta[c1][i+1] == 0)
+					final_candidate[(i/4)] = c2;
+				else if (resulta[c2][i] + resulta[c2][i+1] == 0)
+					final_candidate[(i/4)] = c1;
+				else
+					sim_bitmap = sim_bitmap | (1<<i);
+			} else {
+				sim_bitmap = sim_bitmap | (1<<i);
+			}
+		}
+	}
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:phy_SimularityCompare_8188E sim_bitmap   %d !!!\n", sim_bitmap));
+
+	if (sim_bitmap == 0) {
+		for (i = 0; i < (bound/4); i++) {
+			if (final_candidate[i] != 0xFF) {
+				for (j = i*4; j < (i+1)*4-2; j++)
+					resulta[3][j] = resulta[final_candidate[i]][j];
+				result = false;
+			}
+		}
+		return result;
+	} else {
+		if (!(sim_bitmap & 0x03)) {		   /* path A TX OK */
+			for (i = 0; i < 2; i++)
+				resulta[3][i] = resulta[c1][i];
+		}
+		if (!(sim_bitmap & 0x0c)) {		   /* path A RX OK */
+			for (i = 2; i < 4; i++)
+				resulta[3][i] = resulta[c1][i];
+		}
+
+		if (!(sim_bitmap & 0x30)) { /* path B TX OK */
+			for (i = 4; i < 6; i++)
+				resulta[3][i] = resulta[c1][i];
+		}
+
+		if (!(sim_bitmap & 0xc0)) { /* path B RX OK */
+			for (i = 6; i < 8; i++)
+				resulta[3][i] = resulta[c1][i];
+		}
+		return false;
+	}
+}
+
+static void phy_IQCalibrate_8188E(struct adapter *adapt, s32 result[][8], u8 t, bool is2t)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	u32 i;
+	u8 PathAOK, PathBOK;
+	u32 ADDA_REG[IQK_ADDA_REG_NUM] = {
+						rFPGA0_XCD_SwitchControl, rBlue_Tooth,
+						rRx_Wait_CCA, 	rTx_CCK_RFON,
+						rTx_CCK_BBON, rTx_OFDM_RFON,
+						rTx_OFDM_BBON, rTx_To_Rx,
+						rTx_To_Tx, 	rRx_CCK,
+						rRx_OFDM, 	rRx_Wait_RIFS,
+						rRx_TO_Rx, 	rStandby,
+						rSleep, 			rPMPD_ANAEN };
+	u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = {
+						REG_TXPAUSE, 	REG_BCN_CTRL,
+						REG_BCN_CTRL_1, REG_GPIO_MUXCFG};
+
+	/* since 92C & 92D have the different define in IQK_BB_REG */
+	u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
+							rOFDM0_TRxPathEnable, 	rOFDM0_TRMuxPar,
+							rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB,
+							rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE,
+							rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD
+							};
+
+	u32 retryCount = 9;
+	if (*(dm_odm->mp_mode) == 1)
+		retryCount = 9;
+	else
+		retryCount = 2;
+	/*  Note: IQ calibration must be performed after loading */
+	/* 		PHY_REG.txt , and radio_a, radio_b.txt */
+
+	if (t == 0) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2t ? "2T2R" : "1T1R"), t));
+
+		/*  Save ADDA parameters, turn Path A ADDA on */
+		_PHY_SaveADDARegisters(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM);
+		_PHY_SaveMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup);
+		_PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM);
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2t ? "2T2R" : "1T1R"), t));
+
+	_PHY_PathADDAOn(adapt, ADDA_REG, true, is2t);
+	if (t == 0)
+		dm_odm->RFCalibrateInfo.bRfPiEnable = (u8)ODM_GetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, BIT(8));
+
+	if (!dm_odm->RFCalibrateInfo.bRfPiEnable) {
+		/*  Switch BB to PI mode to do IQ Calibration. */
+		_PHY_PIModeSwitch(adapt, true);
+	}
+
+	/* BB setting */
+	ODM_SetBBReg(dm_odm, rFPGA0_RFMOD, BIT24, 0x00);
+	ODM_SetBBReg(dm_odm, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600);
+	ODM_SetBBReg(dm_odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4);
+	ODM_SetBBReg(dm_odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000);
+
+	ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01);
+	ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01);
+	ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00);
+	ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00);
+
+	if (is2t) {
+		ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000);
+		ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000);
+	}
+
+	/* MAC settings */
+	_PHY_MACSettingCalibration(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup);
+
+	/* Page B init */
+	/* AP or IQK */
+	ODM_SetBBReg(dm_odm, rConfig_AntA, bMaskDWord, 0x0f600000);
+
+	if (is2t)
+		ODM_SetBBReg(dm_odm, rConfig_AntB, bMaskDWord, 0x0f600000);
+
+	/*  IQ calibration setting */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK setting!\n"));
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+	ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00);
+	ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800);
+
+	for (i = 0; i < retryCount; i++) {
+		PathAOK = phy_PathA_IQK_8188E(adapt, is2t);
+		if (PathAOK == 0x01) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n"));
+				result[t][0] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+				result[t][1] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+			break;
+		}
+	}
+
+	for (i = 0; i < retryCount; i++) {
+		PathAOK = phy_PathA_RxIQK(adapt, is2t);
+		if (PathAOK == 0x03) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("Path A Rx IQK Success!!\n"));
+				result[t][2] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
+				result[t][3] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
+			break;
+		} else {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n"));
+		}
+	}
+
+	if (0x00 == PathAOK) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n"));
+	}
+
+	if (is2t) {
+		_PHY_PathAStandBy(adapt);
+
+		/*  Turn Path B ADDA on */
+		_PHY_PathADDAOn(adapt, ADDA_REG, false, is2t);
+
+		for (i = 0; i < retryCount; i++) {
+			PathBOK = phy_PathB_IQK_8188E(adapt);
+			if (PathBOK == 0x03) {
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK Success!!\n"));
+				result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+				result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+				result[t][6] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16;
+				result[t][7] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16;
+				break;
+			} else if (i == (retryCount - 1) && PathBOK == 0x01) {	/* Tx IQK OK */
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Only Tx IQK Success!!\n"));
+				result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+				result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+			}
+		}
+
+		if (0x00 == PathBOK) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n"));
+		}
+	}
+
+	/* Back to BB mode, load original value */
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n"));
+	ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0);
+
+	if (t != 0) {
+		if (!dm_odm->RFCalibrateInfo.bRfPiEnable) {
+			/*  Switch back BB to SI mode after finish IQ Calibration. */
+			_PHY_PIModeSwitch(adapt, false);
+		}
+
+		/*  Reload ADDA power saving parameters */
+		reload_adda_reg(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM);
+
+		/*  Reload MAC parameters */
+		_PHY_ReloadMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup);
+
+		reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM);
+
+		/*  Restore RX initial gain */
+		ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3);
+		if (is2t)
+			ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3);
+
+		/* load 0xe30 IQC default value */
+		ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+		ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8188E() <==\n"));
+}
+
+static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t)
+{
+	u8 tmpreg;
+	u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	/* Check continuous TX and Packet TX */
+	tmpreg = ODM_Read1Byte(dm_odm, 0xd03);
+
+	if ((tmpreg&0x70) != 0)			/* Deal with contisuous TX case */
+		ODM_Write1Byte(dm_odm, 0xd03, tmpreg&0x8F);	/* disable all continuous TX */
+	else							/*  Deal with Packet TX case */
+		ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0xFF);			/*  block all queues */
+
+	if ((tmpreg&0x70) != 0) {
+		/* 1. Read original RF mode */
+		/* Path-A */
+		RF_Amode = PHY_QueryRFReg(adapt, RF_PATH_A, RF_AC, bMask12Bits);
+
+		/* Path-B */
+		if (is2t)
+			RF_Bmode = PHY_QueryRFReg(adapt, RF_PATH_B, RF_AC, bMask12Bits);
+
+		/* 2. Set RF mode = standby mode */
+		/* Path-A */
+		ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000);
+
+		/* Path-B */
+		if (is2t)
+			ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000);
+	}
+
+	/* 3. Read RF reg18 */
+	LC_Cal = PHY_QueryRFReg(adapt, RF_PATH_A, RF_CHNLBW, bMask12Bits);
+
+	/* 4. Set LC calibration begin	bit15 */
+	ODM_SetRFReg(dm_odm, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000);
+
+	ODM_sleep_ms(100);
+
+	/* Restore original situation */
+	if ((tmpreg&0x70) != 0) {
+		/* Deal with continuous TX case */
+		/* Path-A */
+		ODM_Write1Byte(dm_odm, 0xd03, tmpreg);
+		ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode);
+
+		/* Path-B */
+		if (is2t)
+			ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode);
+	} else {
+		/*  Deal with Packet TX case */
+		ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0x00);
+	}
+}
+
+/* Analog Pre-distortion calibration */
+#define		APK_BB_REG_NUM	8
+#define		APK_CURVE_REG_NUM 4
+#define		PATH_NUM		2
+
+static void phy_APCalibrate_8188E(struct adapter *adapt, s8 delta, bool is2t)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	u32 regD[PATH_NUM];
+	u32 tmpreg, index, offset,  apkbound;
+	u8 path, i, pathbound = PATH_NUM;
+	u32 BB_backup[APK_BB_REG_NUM];
+	u32 BB_REG[APK_BB_REG_NUM] = {
+		rFPGA1_TxBlock, 	rOFDM0_TRxPathEnable,
+		rFPGA0_RFMOD, rOFDM0_TRMuxPar,
+		rFPGA0_XCD_RFInterfaceSW, rFPGA0_XAB_RFInterfaceSW,
+		rFPGA0_XA_RFInterfaceOE, rFPGA0_XB_RFInterfaceOE	};
+	u32 BB_AP_MODE[APK_BB_REG_NUM] = {
+		0x00000020, 0x00a05430, 0x02040000,
+		0x000800e4, 0x00204000 };
+	u32 BB_normal_AP_MODE[APK_BB_REG_NUM] = {
+		0x00000020, 0x00a05430, 0x02040000,
+		0x000800e4, 0x22204000 };
+
+	u32 AFE_backup[IQK_ADDA_REG_NUM];
+	u32 AFE_REG[IQK_ADDA_REG_NUM] = {
+		rFPGA0_XCD_SwitchControl, rBlue_Tooth,
+		rRx_Wait_CCA, 	rTx_CCK_RFON,
+		rTx_CCK_BBON, rTx_OFDM_RFON,
+		rTx_OFDM_BBON, rTx_To_Rx,
+		rTx_To_Tx, 	rRx_CCK,
+		rRx_OFDM, 	rRx_Wait_RIFS,
+		rRx_TO_Rx, 	rStandby,
+		rSleep, 			rPMPD_ANAEN };
+
+	u32 MAC_backup[IQK_MAC_REG_NUM];
+	u32 MAC_REG[IQK_MAC_REG_NUM] = {
+		REG_TXPAUSE, 	REG_BCN_CTRL,
+		REG_BCN_CTRL_1, REG_GPIO_MUXCFG};
+
+	u32 APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = {
+		{0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c},
+		{0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e}
+	};
+
+	u32 APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = {
+		{0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, /* path settings equal to path b settings */
+		{0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c}
+	};
+
+	u32 APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = {
+		{0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d},
+		{0x5201a, 0x52019, 0x52016, 0x52033, 0x52050}
+	};
+
+	u32 APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = {
+		{0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, /* path settings equal to path b settings */
+		{0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}
+	};
+
+	u32 AFE_on_off[PATH_NUM] = {
+		0x04db25a4, 0x0b1b25a4};	/* path A on path B off / path A off path B on */
+
+	u32 APK_offset[PATH_NUM] = {
+		rConfig_AntA, rConfig_AntB};
+
+	u32 APK_normal_offset[PATH_NUM] = {
+		rConfig_Pmpd_AntA, rConfig_Pmpd_AntB};
+
+	u32 APK_value[PATH_NUM] = {
+		0x92fc0000, 0x12fc0000};
+
+	u32 APK_normal_value[PATH_NUM] = {
+		0x92680000, 0x12680000};
+
+	s8 APK_delta_mapping[APK_BB_REG_NUM][13] = {
+		{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+		{-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+		{-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+		{-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6},
+		{-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0}
+	};
+
+	u32 APK_normal_setting_value_1[13] = {
+		0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28,
+		0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3,
+		0x12680000, 0x00880000, 0x00880000
+	};
+
+	u32 APK_normal_setting_value_2[16] = {
+		0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3,
+		0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025,
+		0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008,
+		0x00050006
+	};
+
+	u32 APK_result[PATH_NUM][APK_BB_REG_NUM];	/* val_1_1a, val_1_2a, val_2a, val_3a, val_4a */
+	s32 BB_offset, delta_V, delta_offset;
+
+	if (*(dm_odm->mp_mode) == 1) {
+		struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx);
+		pMptCtx->APK_bound[0] = 45;
+		pMptCtx->APK_bound[1] = 52;
+	}
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_APCalibrate_8188E() delta %d\n", delta));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("AP Calibration for %s\n", (is2t ? "2T2R" : "1T1R")));
+	if (!is2t)
+		pathbound = 1;
+
+	/* 2 FOR NORMAL CHIP SETTINGS */
+
+/*  Temporarily do not allow normal driver to do the following settings
+ *  because these offset and value will cause RF internal PA to be
+ *  unpredictably disabled by HW, such that RF Tx signal  will disappear
+ *  after disable/enable card many times on 88CU. RF SD and DD have not
+ *  find the root cause, so we remove these actions temporarily.
+ */
+	if (*(dm_odm->mp_mode) != 1)
+		return;
+	/* settings adjust for normal chip */
+	for (index = 0; index < PATH_NUM; index++) {
+		APK_offset[index] = APK_normal_offset[index];
+		APK_value[index] = APK_normal_value[index];
+		AFE_on_off[index] = 0x6fdb25a4;
+	}
+
+	for (index = 0; index < APK_BB_REG_NUM; index++) {
+		for (path = 0; path < pathbound; path++) {
+			APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index];
+			APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index];
+		}
+		BB_AP_MODE[index] = BB_normal_AP_MODE[index];
+	}
+
+	apkbound = 6;
+
+	/* save BB default value */
+	for (index = 0; index < APK_BB_REG_NUM; index++) {
+		if (index == 0)		/* skip */
+			continue;
+		BB_backup[index] = ODM_GetBBReg(dm_odm, BB_REG[index], bMaskDWord);
+	}
+
+	/* save MAC default value */
+	_PHY_SaveMACRegisters(adapt, MAC_REG, MAC_backup);
+
+	/* save AFE default value */
+	_PHY_SaveADDARegisters(adapt, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM);
+
+	for (path = 0; path < pathbound; path++) {
+		if (path == RF_PATH_A) {
+			/* path A APK */
+			/* load APK setting */
+			/* path-A */
+			offset = rPdp_AntA;
+			for (index = 0; index < 11; index++) {
+				ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+					     offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+				offset += 0x04;
+			}
+
+			ODM_SetBBReg(dm_odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000);
+
+			offset = rConfig_AntA;
+			for (; index < 13; index++) {
+				ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+					     offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+				offset += 0x04;
+			}
+
+			/* page-B1 */
+			ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x40000000);
+
+			/* path A */
+			offset = rPdp_AntA;
+			for (index = 0; index < 16; index++) {
+				ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_2[index]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+					     offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+
+				offset += 0x04;
+			}
+			ODM_SetBBReg(dm_odm,  rFPGA0_IQK, bMaskDWord, 0x00000000);
+		} else if (path == RF_PATH_B) {
+			/* path B APK */
+			/* load APK setting */
+			/* path-B */
+			offset = rPdp_AntB;
+			for (index = 0; index < 10; index++) {
+				ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+					     offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+
+				offset += 0x04;
+			}
+			ODM_SetBBReg(dm_odm, rConfig_Pmpd_AntA, bMaskDWord, 0x12680000);
+			PHY_SetBBReg(adapt, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000);
+
+			offset = rConfig_AntA;
+			index = 11;
+			for (; index < 13; index++) { /* offset 0xb68, 0xb6c */
+				ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_1[index]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+					     offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+				offset += 0x04;
+			}
+
+			/* page-B1 */
+			ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x40000000);
+
+			/* path B */
+			offset = 0xb60;
+			for (index = 0; index < 16; index++) {
+				ODM_SetBBReg(dm_odm, offset, bMaskDWord, APK_normal_setting_value_2[index]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n",
+					     offset, ODM_GetBBReg(dm_odm, offset, bMaskDWord)));
+
+				offset += 0x04;
+			}
+			ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0);
+		}
+
+		/* save RF default value */
+		regD[path] = PHY_QueryRFReg(adapt, path, RF_TXBIAS_A, bMaskDWord);
+
+		/* Path A AFE all on, path B AFE All off or vise versa */
+		for (index = 0; index < IQK_ADDA_REG_NUM; index++)
+			ODM_SetBBReg(dm_odm, AFE_REG[index], bMaskDWord, AFE_on_off[path]);
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("phy_APCalibrate_8188E() offset 0xe70 %x\n",
+			     ODM_GetBBReg(dm_odm, rRx_Wait_CCA, bMaskDWord)));
+
+		/* BB to AP mode */
+		if (path == 0) {
+			for (index = 0; index < APK_BB_REG_NUM; index++) {
+				if (index == 0)		/* skip */
+					continue;
+				else if (index < 5)
+				ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_AP_MODE[index]);
+				else if (BB_REG[index] == 0x870)
+					ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26);
+				else
+					ODM_SetBBReg(dm_odm, BB_REG[index], BIT10, 0x0);
+			}
+
+			ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+			ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+		} else {
+			/* path B */
+			ODM_SetBBReg(dm_odm, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00);
+			ODM_SetBBReg(dm_odm, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00);
+		}
+
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("phy_APCalibrate_8188E() offset 0x800 %x\n",
+			     ODM_GetBBReg(dm_odm, 0x800, bMaskDWord)));
+
+		/* MAC settings */
+		_PHY_MACSettingCalibration(adapt, MAC_REG, MAC_backup);
+
+		if (path == RF_PATH_A) {
+			/* Path B to standby mode */
+			ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMaskDWord, 0x10000);
+		} else {
+			/* Path A to standby mode */
+			ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMaskDWord, 0x10000);
+			ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f);
+			ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20103);
+		}
+
+		delta_offset = ((delta+14)/2);
+		if (delta_offset < 0)
+			delta_offset = 0;
+		else if (delta_offset > 12)
+			delta_offset = 12;
+
+		/* AP calibration */
+		for (index = 0; index < APK_BB_REG_NUM; index++) {
+			if (index != 1)	/* only DO PA11+PAD01001, AP RF setting */
+				continue;
+
+			tmpreg = APK_RF_init_value[path][index];
+			if (!dm_odm->RFCalibrateInfo.bAPKThermalMeterIgnore) {
+				BB_offset = (tmpreg & 0xF0000) >> 16;
+
+				if (!(tmpreg & BIT15)) /* sign bit 0 */
+					BB_offset = -BB_offset;
+
+				delta_V = APK_delta_mapping[index][delta_offset];
+
+				BB_offset += delta_V;
+
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+					     ("phy_APCalibrate_8188E() APK index %d tmpreg 0x%x delta_V %d delta_offset %d\n",
+					     index, tmpreg, delta_V, delta_offset));
+
+				if (BB_offset < 0) {
+					tmpreg = tmpreg & (~BIT15);
+					BB_offset = -BB_offset;
+				} else {
+					tmpreg = tmpreg | BIT15;
+				}
+				tmpreg = (tmpreg & 0xFFF0FFFF) | (BB_offset << 16);
+			}
+
+			ODM_SetRFReg(dm_odm, path, RF_IPA_A, bMaskDWord, 0x8992e);
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", PHY_QueryRFReg(adapt, path, RF_IPA_A, bMaskDWord)));
+			ODM_SetRFReg(dm_odm, path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]);
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("phy_APCalibrate_8188E() offset 0x0 %x\n", PHY_QueryRFReg(adapt, path, RF_AC, bMaskDWord)));
+			ODM_SetRFReg(dm_odm, path, RF_TXBIAS_A, bMaskDWord, tmpreg);
+			ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", PHY_QueryRFReg(adapt, path, RF_TXBIAS_A, bMaskDWord)));
+			/*  PA11+PAD01111, one shot */
+			i = 0;
+			do {
+				ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80000000);
+				ODM_SetBBReg(dm_odm, APK_offset[path], bMaskDWord, APK_value[0]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(dm_odm, APK_offset[path], bMaskDWord)));
+				ODM_delay_ms(3);
+				ODM_SetBBReg(dm_odm, APK_offset[path], bMaskDWord, APK_value[1]);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(dm_odm, APK_offset[path], bMaskDWord)));
+
+				ODM_delay_ms(20);
+				ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+
+				if (path == RF_PATH_A)
+					tmpreg = ODM_GetBBReg(dm_odm, rAPK, 0x03E00000);
+				else
+					tmpreg = ODM_GetBBReg(dm_odm, rAPK, 0xF8000000);
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xbd8[25:21] %x\n", tmpreg));
+
+				i++;
+			} while (tmpreg > apkbound && i < 4);
+
+			APK_result[path][index] = tmpreg;
+		}
+	}
+
+	/* reload MAC default value */
+	_PHY_ReloadMACRegisters(adapt, MAC_REG, MAC_backup);
+
+	/* reload BB default value */
+	for (index = 0; index < APK_BB_REG_NUM; index++) {
+		if (index == 0)		/* skip */
+			continue;
+		ODM_SetBBReg(dm_odm, BB_REG[index], bMaskDWord, BB_backup[index]);
+	}
+
+	/* reload AFE default value */
+	reload_adda_reg(adapt, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM);
+
+	/* reload RF path default value */
+	for (path = 0; path < pathbound; path++) {
+		ODM_SetRFReg(dm_odm, path, 0xd, bMaskDWord, regD[path]);
+		if (path == RF_PATH_B) {
+			ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f);
+			ODM_SetRFReg(dm_odm, RF_PATH_A, RF_MODE2, bMaskDWord, 0x20101);
+		}
+
+		/* note no index == 0 */
+		if (APK_result[path][1] > 6)
+			APK_result[path][1] = 6;
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1]));
+	}
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("\n"));
+
+	for (path = 0; path < pathbound; path++) {
+		ODM_SetRFReg(dm_odm, path, 0x3, bMaskDWord,
+			     ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1]));
+		if (path == RF_PATH_A)
+			ODM_SetRFReg(dm_odm, path, 0x4, bMaskDWord,
+				     ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05));
+		else
+			ODM_SetRFReg(dm_odm, path, 0x4, bMaskDWord,
+				     ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05));
+		ODM_SetRFReg(dm_odm, path, RF_BS_PA_APSET_G9_G11, bMaskDWord,
+			     ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08));
+	}
+
+	dm_odm->RFCalibrateInfo.bAPKdone = true;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_APCalibrate_8188E()\n"));
+}
+
+#define		DP_BB_REG_NUM		7
+#define		DP_RF_REG_NUM		1
+#define		DP_RETRY_LIMIT		10
+#define		DP_PATH_NUM		2
+#define		DP_DPK_NUM			3
+#define		DP_DPK_VALUE_NUM	2
+
+void PHY_IQCalibrate_8188E(struct adapter *adapt, bool recovery)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx);
+	s32 result[4][8];	/* last is final result */
+	u8 i, final_candidate, Indexforchannel;
+	bool pathaok, pathbok;
+	s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC;
+	bool is12simular, is13simular, is23simular;
+	bool singletone = false, carrier_sup = false;
+	u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
+		rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance,
+		rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable,
+		rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance,
+		rOFDM0_XCTxAFE, rOFDM0_XDTxAFE,
+		rOFDM0_RxIQExtAnta};
+	bool is2t;
+
+	is2t = (dm_odm->RFType == ODM_2T2R) ? true : false;
+	if (ODM_CheckPowerStatus(adapt) == false)
+		return;
+
+	if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION))
+		return;
+
+	if (*(dm_odm->mp_mode) == 1) {
+		singletone = pMptCtx->bSingleTone;
+		carrier_sup = pMptCtx->bCarrierSuppression;
+	}
+
+	/*  20120213<Kordan> Turn on when continuous Tx to pass lab testing. (required by Edlu) */
+	if (singletone || carrier_sup)
+		return;
+
+	if (recovery) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8188E: Return due to recovery!\n"));
+		reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
+		return;
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("IQK:Start!!!\n"));
+
+	for (i = 0; i < 8; i++) {
+		result[0][i] = 0;
+		result[1][i] = 0;
+		result[2][i] = 0;
+		if ((i == 0) || (i == 2) || (i == 4)  || (i == 6))
+			result[3][i] = 0x100;
+		else
+			result[3][i] = 0;
+	}
+	final_candidate = 0xff;
+	pathaok = false;
+	pathbok = false;
+	is12simular = false;
+	is23simular = false;
+	is13simular = false;
+
+	for (i = 0; i < 3; i++) {
+		phy_IQCalibrate_8188E(adapt, result, i, is2t);
+
+		if (i == 1) {
+			is12simular = phy_SimularityCompare_8188E(adapt, result, 0, 1);
+			if (is12simular) {
+				final_candidate = 0;
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n", final_candidate));
+				break;
+			}
+		}
+
+		if (i == 2) {
+			is13simular = phy_SimularityCompare_8188E(adapt, result, 0, 2);
+			if (is13simular) {
+				final_candidate = 0;
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n", final_candidate));
+
+				break;
+			}
+			is23simular = phy_SimularityCompare_8188E(adapt, result, 1, 2);
+			if (is23simular) {
+				final_candidate = 1;
+				ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n", final_candidate));
+			} else {
+				final_candidate = 3;
+			}
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		RegE94 = result[i][0];
+		RegE9C = result[i][1];
+		RegEA4 = result[i][2];
+		RegEAC = result[i][3];
+		RegEB4 = result[i][4];
+		RegEBC = result[i][5];
+		RegEC4 = result[i][6];
+		RegECC = result[i][7];
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n",
+			     RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC));
+	}
+
+	if (final_candidate != 0xff) {
+		RegE94 = result[final_candidate][0];
+		RegE9C = result[final_candidate][1];
+		RegEA4 = result[final_candidate][2];
+		RegEAC = result[final_candidate][3];
+		RegEB4 = result[final_candidate][4];
+		RegEBC = result[final_candidate][5];
+		dm_odm->RFCalibrateInfo.RegE94 = RegE94;
+		dm_odm->RFCalibrateInfo.RegE9C = RegE9C;
+		dm_odm->RFCalibrateInfo.RegEB4 = RegEB4;
+		dm_odm->RFCalibrateInfo.RegEBC = RegEBC;
+		RegEC4 = result[final_candidate][6];
+		RegECC = result[final_candidate][7];
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("IQK: final_candidate is %x\n", final_candidate));
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+			     ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n",
+			     RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC));
+		pathaok = true;
+		pathbok = true;
+	} else {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("IQK: FAIL use default value\n"));
+		dm_odm->RFCalibrateInfo.RegE94 = 0x100;
+		dm_odm->RFCalibrateInfo.RegEB4 = 0x100;	/* X default value */
+		dm_odm->RFCalibrateInfo.RegE9C = 0x0;
+		dm_odm->RFCalibrateInfo.RegEBC = 0x0;	/* Y default value */
+	}
+	if (RegE94 != 0)
+		patha_fill_iqk(adapt, pathaok, result, final_candidate, (RegEA4 == 0));
+	if (is2t) {
+		if (RegEB4 != 0)
+			pathb_fill_iqk(adapt, pathbok, result, final_candidate, (RegEC4 == 0));
+	}
+
+	Indexforchannel = ODM_GetRightChnlPlaceforIQK(pHalData->CurrentChannel);
+
+/* To Fix BSOD when final_candidate is 0xff */
+/* by sherry 20120321 */
+	if (final_candidate < 4) {
+		for (i = 0; i < IQK_Matrix_REG_NUM; i++)
+			dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][i] = result[final_candidate][i];
+		dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].bIQKDone = true;
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("\nIQK OK Indexforchannel %d.\n", Indexforchannel));
+
+	_PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9);
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,  ("IQK finished\n"));
+}
+
+void PHY_LCCalibrate_8188E(struct adapter *adapt)
+{
+	bool singletone = false, carrier_sup = false;
+	u32 timeout = 2000, timecount = 0;
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+	struct mpt_context *pMptCtx = &(adapt->mppriv.MptCtx);
+
+	if (*(dm_odm->mp_mode) == 1) {
+		singletone = pMptCtx->bSingleTone;
+		carrier_sup = pMptCtx->bCarrierSuppression;
+	}
+	if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION))
+		return;
+	/*  20120213<Kordan> Turn on when continuous Tx to pass lab testing. (required by Edlu) */
+	if (singletone || carrier_sup)
+		return;
+
+	while (*(dm_odm->pbScanInProcess) && timecount < timeout) {
+		ODM_delay_ms(50);
+		timecount += 50;
+	}
+
+	dm_odm->RFCalibrateInfo.bLCKInProgress = true;
+
+	if (dm_odm->RFType == ODM_2T2R) {
+		phy_LCCalibrate_8188E(adapt, true);
+	} else {
+		/*  For 88C 1T1R */
+		phy_LCCalibrate_8188E(adapt, false);
+	}
+
+	dm_odm->RFCalibrateInfo.bLCKInProgress = false;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
+		     ("LCK:Finish!!!interface %d\n", dm_odm->InterfaceIndex));
+}
+
+void PHY_APCalibrate_8188E(struct adapter *adapt, s8 delta)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	return;
+	if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION))
+		return;
+
+#if FOR_BRAZIL_PRETEST != 1
+	if (dm_odm->RFCalibrateInfo.bAPKdone)
+#endif
+		return;
+
+	if (dm_odm->RFType == ODM_2T2R) {
+		phy_APCalibrate_8188E(adapt, delta, true);
+	} else {
+		/*  For 88C 1T1R */
+		phy_APCalibrate_8188E(adapt, delta, false);
+	}
+}
+
+static void phy_setrfpathswitch_8188e(struct adapter *adapt, bool main, bool is2t)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	if (!adapt->hw_init_completed) {
+		u8 u1btmp;
+		u1btmp = ODM_Read1Byte(dm_odm, REG_LEDCFG2) | BIT7;
+		ODM_Write1Byte(dm_odm, REG_LEDCFG2, u1btmp);
+		ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFParameter, BIT13, 0x01);
+	}
+
+	if (is2t) {	/* 92C */
+		if (main)
+			ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x1);	/* 92C_Path_A */
+		else
+			ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x2);	/* BT */
+	} else {			/* 88C */
+		if (main)
+			ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x2);	/* Main */
+		else
+			ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x1);	/* Aux */
+	}
+}
+
+void PHY_SetRFPathSwitch_8188E(struct adapter *adapt, bool main)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(adapt);
+	struct odm_dm_struct *dm_odm = &pHalData->odmpriv;
+
+	if (dm_odm->RFType == ODM_2T2R) {
+		phy_setrfpathswitch_8188e(adapt, main, true);
+	} else {
+		/*  For 88C 1T1R */
+		phy_setrfpathswitch_8188e(adapt, main, false);
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c
new file mode 100644
index 0000000..e913a22
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/HalPwrSeqCmd.c
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+	HalPwrSeqCmd.c
+
+Abstract:
+	Implement HW Power sequence configuration CMD handling routine for Realtek devices.
+
+Major Change History:
+	When       Who               What
+	---------- ---------------   -------------------------------
+	2011-10-26 Lucas            Modify to be compatible with SD4-CE driver.
+	2011-07-07 Roger            Create.
+
+--*/
+
+#include <HalPwrSeqCmd.h>
+
+/*	Description: */
+/*		This routine deals with the Power Configuration CMDs parsing
+ *		for RTL8723/RTL8188E Series IC.
+ *	Assumption:
+ *		We should follow specific format which was released from HW SD.
+ */
+u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 cut_vers, u8 fab_vers,
+		       u8 ifacetype, struct wl_pwr_cfg pwrseqcmd[])
+{
+	struct wl_pwr_cfg pwrcfgcmd = {0};
+	u8 poll_bit = false;
+	u32 aryidx = 0;
+	u8 value = 0;
+	u32 offset = 0;
+	u32 poll_count = 0; /*  polling autoload done. */
+	u32 max_poll_count = 5000;
+
+	do {
+		pwrcfgcmd = pwrseqcmd[aryidx];
+
+		RT_TRACE(_module_hal_init_c_ , _drv_info_,
+			 ("HalPwrSeqCmdParsing: offset(%#x) cut_msk(%#x) fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) msk(%#x) value(%#x)\n",
+			 GET_PWR_CFG_OFFSET(pwrcfgcmd),
+			 GET_PWR_CFG_CUT_MASK(pwrcfgcmd),
+			 GET_PWR_CFG_FAB_MASK(pwrcfgcmd),
+			 GET_PWR_CFG_INTF_MASK(pwrcfgcmd),
+			 GET_PWR_CFG_BASE(pwrcfgcmd),
+			 GET_PWR_CFG_CMD(pwrcfgcmd),
+			 GET_PWR_CFG_MASK(pwrcfgcmd),
+			 GET_PWR_CFG_VALUE(pwrcfgcmd)));
+
+		/* 2 Only Handle the command whose FAB, CUT, and Interface are matched */
+		if ((GET_PWR_CFG_FAB_MASK(pwrcfgcmd) & fab_vers) &&
+		    (GET_PWR_CFG_CUT_MASK(pwrcfgcmd) & cut_vers) &&
+		    (GET_PWR_CFG_INTF_MASK(pwrcfgcmd) & ifacetype)) {
+			switch (GET_PWR_CFG_CMD(pwrcfgcmd)) {
+			case PWR_CMD_READ:
+				RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_READ\n"));
+				break;
+			case PWR_CMD_WRITE:
+				RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_WRITE\n"));
+				offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
+
+				/*  Read the value from system register */
+				value = rtw_read8(padapter, offset);
+
+				value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd));
+				value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd));
+
+				/*  Write the value back to sytem register */
+				rtw_write8(padapter, offset, value);
+				break;
+			case PWR_CMD_POLLING:
+				RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_POLLING\n"));
+
+				poll_bit = false;
+				offset = GET_PWR_CFG_OFFSET(pwrcfgcmd);
+				do {
+						value = rtw_read8(padapter, offset);
+
+					value &= GET_PWR_CFG_MASK(pwrcfgcmd);
+					if (value == (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)))
+						poll_bit = true;
+					else
+						rtw_udelay_os(10);
+
+					if (poll_count++ > max_poll_count) {
+						DBG_88E("Fail to polling Offset[%#x]\n", offset);
+						return false;
+					}
+				} while (!poll_bit);
+				break;
+			case PWR_CMD_DELAY:
+				RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_DELAY\n"));
+				if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US)
+					rtw_udelay_os(GET_PWR_CFG_OFFSET(pwrcfgcmd));
+				else
+					rtw_udelay_os(GET_PWR_CFG_OFFSET(pwrcfgcmd)*1000);
+				break;
+			case PWR_CMD_END:
+				/*  When this command is parsed, end the process */
+				RT_TRACE(_module_hal_init_c_ , _drv_info_, ("HalPwrSeqCmdParsing: PWR_CMD_END\n"));
+				return true;
+				break;
+			default:
+				RT_TRACE(_module_hal_init_c_ , _drv_err_, ("HalPwrSeqCmdParsing: Unknown CMD!!\n"));
+				break;
+			}
+		}
+
+		aryidx++;/* Add Array Index */
+	} while (1);
+	return true;
+}
diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c
new file mode 100644
index 0000000..829b900
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/hal_com.c
@@ -0,0 +1,381 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <hal_intf.h>
+#include <hal_com.h>
+#include <rtl8188e_hal.h>
+
+#define _HAL_INIT_C_
+
+void dump_chip_info(struct HAL_VERSION	chip_vers)
+{
+	uint cnt = 0;
+	char buf[128];
+
+	if (IS_81XXC(chip_vers)) {
+		cnt += sprintf((buf+cnt), "Chip Version Info: %s_",
+			       IS_92C_SERIAL(chip_vers) ?
+			       "CHIP_8192C" : "CHIP_8188C");
+	} else if (IS_92D(chip_vers)) {
+		cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8192D_");
+	} else if (IS_8723_SERIES(chip_vers)) {
+		cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723A_");
+	} else if (IS_8188E(chip_vers)) {
+		cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_");
+	}
+
+	cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ?
+		       "Normal_Chip" : "Test_Chip");
+	cnt += sprintf((buf+cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ?
+		       "TSMC" : "UMC");
+	if (IS_A_CUT(chip_vers))
+		cnt += sprintf((buf+cnt), "A_CUT_");
+	else if (IS_B_CUT(chip_vers))
+		cnt += sprintf((buf+cnt), "B_CUT_");
+	else if (IS_C_CUT(chip_vers))
+		cnt += sprintf((buf+cnt), "C_CUT_");
+	else if (IS_D_CUT(chip_vers))
+		cnt += sprintf((buf+cnt), "D_CUT_");
+	else if (IS_E_CUT(chip_vers))
+		cnt += sprintf((buf+cnt), "E_CUT_");
+	else
+		cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_",
+			       chip_vers.CUTVersion);
+
+	if (IS_1T1R(chip_vers))
+		cnt += sprintf((buf+cnt), "1T1R_");
+	else if (IS_1T2R(chip_vers))
+		cnt += sprintf((buf+cnt), "1T2R_");
+	else if (IS_2T2R(chip_vers))
+		cnt += sprintf((buf+cnt), "2T2R_");
+	else
+		cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_",
+			       chip_vers.RFType);
+
+	cnt += sprintf((buf+cnt), "RomVer(%d)\n", chip_vers.ROMVer);
+
+	pr_info("%s", buf);
+}
+
+#define	CHAN_PLAN_HW	0x80
+
+u8 /* return the final channel plan decision */
+hal_com_get_channel_plan(struct adapter *padapter, u8 hw_channel_plan,
+			 u8 sw_channel_plan, u8 def_channel_plan,
+			 bool load_fail)
+{
+	u8 sw_cfg;
+	u8 chnlplan;
+
+	sw_cfg = true;
+	if (!load_fail) {
+		if (!rtw_is_channel_plan_valid(sw_channel_plan))
+			sw_cfg = false;
+		if (hw_channel_plan & CHAN_PLAN_HW)
+			sw_cfg = false;
+	}
+
+	if (sw_cfg)
+		chnlplan = sw_channel_plan;
+	else
+		chnlplan = hw_channel_plan & (~CHAN_PLAN_HW);
+
+	if (!rtw_is_channel_plan_valid(chnlplan))
+		chnlplan = def_channel_plan;
+
+	return chnlplan;
+}
+
+u8 MRateToHwRate(u8 rate)
+{
+	u8 ret = DESC_RATE1M;
+
+	switch (rate) {
+		/*  CCK and OFDM non-HT rates */
+	case IEEE80211_CCK_RATE_1MB:
+		ret = DESC_RATE1M;
+		break;
+	case IEEE80211_CCK_RATE_2MB:
+		ret = DESC_RATE2M;
+		break;
+	case IEEE80211_CCK_RATE_5MB:
+		ret = DESC_RATE5_5M;
+		break;
+	case IEEE80211_CCK_RATE_11MB:
+		ret = DESC_RATE11M;
+		break;
+	case IEEE80211_OFDM_RATE_6MB:
+		ret = DESC_RATE6M;
+		break;
+	case IEEE80211_OFDM_RATE_9MB:
+		ret = DESC_RATE9M;
+		break;
+	case IEEE80211_OFDM_RATE_12MB:
+		ret = DESC_RATE12M;
+		break;
+	case IEEE80211_OFDM_RATE_18MB:
+		ret = DESC_RATE18M;
+		break;
+	case IEEE80211_OFDM_RATE_24MB:
+		ret = DESC_RATE24M;
+		break;
+	case IEEE80211_OFDM_RATE_36MB:
+		ret = DESC_RATE36M;
+		break;
+	case IEEE80211_OFDM_RATE_48MB:
+		ret = DESC_RATE48M;
+		break;
+	case IEEE80211_OFDM_RATE_54MB:
+		ret = DESC_RATE54M;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+void HalSetBrateCfg(struct adapter *adapt, u8 *brates, u16 *rate_cfg)
+{
+	u8 i, is_brate, brate;
+
+	for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+		is_brate = brates[i] & IEEE80211_BASIC_RATE_MASK;
+		brate = brates[i] & 0x7f;
+
+		if (is_brate) {
+			switch (brate) {
+			case IEEE80211_CCK_RATE_1MB:
+				*rate_cfg |= RATE_1M;
+				break;
+			case IEEE80211_CCK_RATE_2MB:
+				*rate_cfg |= RATE_2M;
+				break;
+			case IEEE80211_CCK_RATE_5MB:
+				*rate_cfg |= RATE_5_5M;
+				break;
+			case IEEE80211_CCK_RATE_11MB:
+				*rate_cfg |= RATE_11M;
+				break;
+			case IEEE80211_OFDM_RATE_6MB:
+				*rate_cfg |= RATE_6M;
+				break;
+			case IEEE80211_OFDM_RATE_9MB:
+				*rate_cfg |= RATE_9M;
+				break;
+			case IEEE80211_OFDM_RATE_12MB:
+				*rate_cfg |= RATE_12M;
+				break;
+			case IEEE80211_OFDM_RATE_18MB:
+				*rate_cfg |= RATE_18M;
+				break;
+			case IEEE80211_OFDM_RATE_24MB:
+				*rate_cfg |= RATE_24M;
+				break;
+			case IEEE80211_OFDM_RATE_36MB:
+				*rate_cfg |= RATE_36M;
+				break;
+			case IEEE80211_OFDM_RATE_48MB:
+				*rate_cfg |= RATE_48M;
+				break;
+			case IEEE80211_OFDM_RATE_54MB:
+				*rate_cfg |= RATE_54M;
+				break;
+			}
+		}
+	}
+}
+
+static void one_out_pipe(struct adapter *adapter)
+{
+	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter);
+
+	pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+	pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
+	pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */
+	pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */
+
+	pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+	pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+	pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+	pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+}
+
+static void two_out_pipe(struct adapter *adapter, bool wifi_cfg)
+{
+	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter);
+
+	if (wifi_cfg) { /* WMM */
+		/* BK, BE, VI, VO, BCN,	CMD, MGT, HIGH, HCCA */
+		/*  0,  1,  0,  1,   0,   0,   0,    0,    0}; */
+		/* 0:H, 1:L */
+
+		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */
+		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
+		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */
+		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */
+
+		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+
+	} else {/* typical setting */
+		/* BK, BE, VI, VO, BCN,	CMD, MGT, HIGH, HCCA */
+		/*  1,	1,  0,  0,   0,   0,   0,    0,    0}; */
+		/* 0:H, 1:L */
+
+		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */
+		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */
+		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */
+
+		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+	}
+}
+
+static void three_out_pipe(struct adapter *adapter, bool wifi_cfg)
+{
+	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter);
+
+	if (wifi_cfg) {/* for WMM */
+		/* BK, BE, VI, VO, BCN,	CMD, MGT, HIGH, HCCA */
+		/*  1,	2,  1,  0,   0,   0,   0,    0,    0}; */
+		/* 0:H, 1:N, 2:L */
+
+		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */
+		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */
+		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */
+
+		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+
+	} else {/* typical setting */
+		/* BK, BE, VI, VO, BCN,	CMD, MGT, HIGH, HCCA */
+		/*  2,  2,  1,  0,   0,   0,   0,    0,    0}; */
+		/* 0:H, 1:N, 2:L */
+
+		pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */
+		pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */
+		pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */
+		pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */
+
+		pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */
+		pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */
+		pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */
+		pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */
+	}
+}
+
+bool Hal_MappingOutPipe(struct adapter *adapter, u8 numoutpipe)
+{
+	struct registry_priv *pregistrypriv = &adapter->registrypriv;
+	bool  wifi_cfg = (pregistrypriv->wifi_spec) ? true : false;
+	bool result = true;
+
+	switch (numoutpipe) {
+	case 2:
+		two_out_pipe(adapter, wifi_cfg);
+		break;
+	case 3:
+		three_out_pipe(adapter, wifi_cfg);
+		break;
+	case 1:
+		one_out_pipe(adapter);
+		break;
+	default:
+		result = false;
+		break;
+	}
+	return result;
+}
+
+void hal_init_macaddr(struct adapter *adapter)
+{
+	rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR,
+			  adapter->eeprompriv.mac_addr);
+}
+
+/*
+* C2H event format:
+* Field	 TRIGGER		CONTENT	   CMD_SEQ	CMD_LEN		 CMD_ID
+* BITS	 [127:120]	[119:16]      [15:8]		  [7:4]		   [3:0]
+*/
+
+void c2h_evt_clear(struct adapter *adapter)
+{
+	rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
+}
+
+s32 c2h_evt_read(struct adapter *adapter, u8 *buf)
+{
+	s32 ret = _FAIL;
+	struct c2h_evt_hdr *c2h_evt;
+	int i;
+	u8 trigger;
+
+	if (buf == NULL)
+		goto exit;
+
+	trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR);
+
+	if (trigger == C2H_EVT_HOST_CLOSE)
+		goto exit; /* Not ready */
+	else if (trigger != C2H_EVT_FW_CLOSE)
+		goto clear_evt; /* Not a valid value */
+
+	c2h_evt = (struct c2h_evt_hdr *)buf;
+
+	_rtw_memset(c2h_evt, 0, 16);
+
+	*buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL);
+	*(buf+1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1);
+
+	RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read(): ",
+		      &c2h_evt , sizeof(c2h_evt));
+
+	/* Read the content */
+	for (i = 0; i < c2h_evt->plen; i++)
+		c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL +
+						sizeof(*c2h_evt) + i);
+
+	RT_PRINT_DATA(_module_hal_init_c_, _drv_info_,
+		      "c2h_evt_read(): Command Content:\n",
+		      c2h_evt->payload, c2h_evt->plen);
+
+	ret = _SUCCESS;
+
+clear_evt:
+	/*
+	* Clear event to notify FW we have read the command.
+	* If this field isn't clear, the FW won't update the next
+	* command message.
+	*/
+	c2h_evt_clear(adapter);
+exit:
+	return ret;
+}
diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c
new file mode 100644
index 0000000..5981404
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/hal_intf.c
@@ -0,0 +1,464 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#define _HAL_INTF_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <hal_intf.h>
+#include <usb_hal.h>
+
+void rtw_hal_chip_configure(struct adapter *adapt)
+{
+	if (adapt->HalFunc.intf_chip_configure)
+		adapt->HalFunc.intf_chip_configure(adapt);
+}
+
+void rtw_hal_read_chip_info(struct adapter *adapt)
+{
+	if (adapt->HalFunc.read_adapter_info)
+		adapt->HalFunc.read_adapter_info(adapt);
+}
+
+void rtw_hal_read_chip_version(struct adapter *adapt)
+{
+	if (adapt->HalFunc.read_chip_version)
+		adapt->HalFunc.read_chip_version(adapt);
+}
+
+void rtw_hal_def_value_init(struct adapter *adapt)
+{
+	if (adapt->HalFunc.init_default_value)
+		adapt->HalFunc.init_default_value(adapt);
+}
+
+void rtw_hal_free_data(struct adapter *adapt)
+{
+	if (adapt->HalFunc.free_hal_data)
+		adapt->HalFunc.free_hal_data(adapt);
+}
+
+void rtw_hal_dm_init(struct adapter *adapt)
+{
+	if (adapt->HalFunc.dm_init)
+		adapt->HalFunc.dm_init(adapt);
+}
+
+void rtw_hal_dm_deinit(struct adapter *adapt)
+{
+	/*  cancel dm  timer */
+	if (adapt->HalFunc.dm_deinit)
+		adapt->HalFunc.dm_deinit(adapt);
+}
+
+void rtw_hal_sw_led_init(struct adapter *adapt)
+{
+	if (adapt->HalFunc.InitSwLeds)
+		adapt->HalFunc.InitSwLeds(adapt);
+}
+
+void rtw_hal_sw_led_deinit(struct adapter *adapt)
+{
+	if (adapt->HalFunc.DeInitSwLeds)
+		adapt->HalFunc.DeInitSwLeds(adapt);
+}
+
+u32 rtw_hal_power_on(struct adapter *adapt)
+{
+	if (adapt->HalFunc.hal_power_on)
+		return adapt->HalFunc.hal_power_on(adapt);
+	return _FAIL;
+}
+
+uint	 rtw_hal_init(struct adapter *adapt)
+{
+	uint	status = _SUCCESS;
+
+	adapt->hw_init_completed = false;
+
+	status = adapt->HalFunc.hal_init(adapt);
+
+	if (status == _SUCCESS) {
+		adapt->hw_init_completed = true;
+
+		if (adapt->registrypriv.notch_filter == 1)
+			rtw_hal_notch_filter(adapt, 1);
+
+		rtw_hal_reset_security_engine(adapt);
+	} else {
+		adapt->hw_init_completed = false;
+		DBG_88E("rtw_hal_init: hal__init fail\n");
+	}
+
+	RT_TRACE(_module_hal_init_c_, _drv_err_,
+		 ("-rtl871x_hal_init:status=0x%x\n", status));
+
+	return status;
+}
+
+uint rtw_hal_deinit(struct adapter *adapt)
+{
+	uint	status = _SUCCESS;
+
+_func_enter_;
+
+	status = adapt->HalFunc.hal_deinit(adapt);
+
+	if (status == _SUCCESS)
+		adapt->hw_init_completed = false;
+	else
+		DBG_88E("\n rtw_hal_deinit: hal_init fail\n");
+
+_func_exit_;
+
+	return status;
+}
+
+void rtw_hal_set_hwreg(struct adapter *adapt, u8 variable, u8 *val)
+{
+	if (adapt->HalFunc.SetHwRegHandler)
+		adapt->HalFunc.SetHwRegHandler(adapt, variable, val);
+}
+
+void rtw_hal_get_hwreg(struct adapter *adapt, u8 variable, u8 *val)
+{
+	if (adapt->HalFunc.GetHwRegHandler)
+		adapt->HalFunc.GetHwRegHandler(adapt, variable, val);
+}
+
+u8 rtw_hal_set_def_var(struct adapter *adapt, enum hal_def_variable var,
+		      void *val)
+{
+	if (adapt->HalFunc.SetHalDefVarHandler)
+		return adapt->HalFunc.SetHalDefVarHandler(adapt, var, val);
+	return _FAIL;
+}
+
+u8 rtw_hal_get_def_var(struct adapter *adapt,
+		       enum hal_def_variable var, void *val)
+{
+	if (adapt->HalFunc.GetHalDefVarHandler)
+		return adapt->HalFunc.GetHalDefVarHandler(adapt, var, val);
+	return _FAIL;
+}
+
+void rtw_hal_set_odm_var(struct adapter *adapt,
+			 enum hal_odm_variable var, void *val1,
+			 bool set)
+{
+	if (adapt->HalFunc.SetHalODMVarHandler)
+		adapt->HalFunc.SetHalODMVarHandler(adapt, var,
+						      val1, set);
+}
+
+void rtw_hal_get_odm_var(struct adapter *adapt,
+			 enum hal_odm_variable var, void *val1,
+			 bool set)
+{
+	if (adapt->HalFunc.GetHalODMVarHandler)
+		adapt->HalFunc.GetHalODMVarHandler(adapt, var,
+						      val1, set);
+}
+
+void rtw_hal_enable_interrupt(struct adapter *adapt)
+{
+	if (adapt->HalFunc.enable_interrupt)
+		adapt->HalFunc.enable_interrupt(adapt);
+	else
+		DBG_88E("%s: HalFunc.enable_interrupt is NULL!\n", __func__);
+}
+
+void rtw_hal_disable_interrupt(struct adapter *adapt)
+{
+	if (adapt->HalFunc.disable_interrupt)
+		adapt->HalFunc.disable_interrupt(adapt);
+	else
+		DBG_88E("%s: HalFunc.disable_interrupt is NULL!\n", __func__);
+}
+
+u32 rtw_hal_inirp_init(struct adapter *adapt)
+{
+	u32 rst = _FAIL;
+
+	if (adapt->HalFunc.inirp_init)
+		rst = adapt->HalFunc.inirp_init(adapt);
+	else
+		DBG_88E(" %s HalFunc.inirp_init is NULL!!!\n", __func__);
+	return rst;
+}
+
+u32 rtw_hal_inirp_deinit(struct adapter *adapt)
+{
+	if (adapt->HalFunc.inirp_deinit)
+		return adapt->HalFunc.inirp_deinit(adapt);
+
+	return _FAIL;
+}
+
+u8 rtw_hal_intf_ps_func(struct adapter *adapt,
+			enum hal_intf_ps_func efunc_id, u8 *val)
+{
+	if (adapt->HalFunc.interface_ps_func)
+		return adapt->HalFunc.interface_ps_func(adapt, efunc_id,
+							   val);
+	return _FAIL;
+}
+
+s32 rtw_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+	if (adapt->HalFunc.hal_xmit)
+		return adapt->HalFunc.hal_xmit(adapt, pxmitframe);
+
+	return false;
+}
+
+s32 rtw_hal_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe)
+{
+	s32 ret = _FAIL;
+	if (adapt->HalFunc.mgnt_xmit)
+		ret = adapt->HalFunc.mgnt_xmit(adapt, pmgntframe);
+	return ret;
+}
+
+s32 rtw_hal_init_xmit_priv(struct adapter *adapt)
+{
+	if (adapt->HalFunc.init_xmit_priv != NULL)
+		return adapt->HalFunc.init_xmit_priv(adapt);
+	return _FAIL;
+}
+
+void rtw_hal_free_xmit_priv(struct adapter *adapt)
+{
+	if (adapt->HalFunc.free_xmit_priv != NULL)
+		adapt->HalFunc.free_xmit_priv(adapt);
+}
+
+s32 rtw_hal_init_recv_priv(struct adapter *adapt)
+{
+	if (adapt->HalFunc.init_recv_priv)
+		return adapt->HalFunc.init_recv_priv(adapt);
+
+	return _FAIL;
+}
+
+void rtw_hal_free_recv_priv(struct adapter *adapt)
+{
+	if (adapt->HalFunc.free_recv_priv)
+		adapt->HalFunc.free_recv_priv(adapt);
+}
+
+void rtw_hal_update_ra_mask(struct adapter *adapt, u32 mac_id, u8 rssi_level)
+{
+	struct mlme_priv *pmlmepriv = &(adapt->mlmepriv);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+#ifdef CONFIG_88EU_AP_MODE
+		struct sta_info *psta = NULL;
+		struct sta_priv *pstapriv = &adapt->stapriv;
+		if ((mac_id-1) > 0)
+			psta = pstapriv->sta_aid[(mac_id-1) - 1];
+		if (psta)
+			add_RATid(adapt, psta, 0);/* todo: based on rssi_level*/
+#endif
+	} else {
+		if (adapt->HalFunc.UpdateRAMaskHandler)
+			adapt->HalFunc.UpdateRAMaskHandler(adapt, mac_id,
+							      rssi_level);
+	}
+}
+
+void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg,
+			u8 rssi_level)
+{
+	if (adapt->HalFunc.Add_RateATid)
+		adapt->HalFunc.Add_RateATid(adapt, bitmap, arg,
+					       rssi_level);
+}
+
+/*	Start specifical interface thread		*/
+void rtw_hal_start_thread(struct adapter *adapt)
+{
+	if (adapt->HalFunc.run_thread)
+		adapt->HalFunc.run_thread(adapt);
+}
+
+/*	Start specifical interface thread		*/
+void rtw_hal_stop_thread(struct adapter *adapt)
+{
+	if (adapt->HalFunc.cancel_thread)
+		adapt->HalFunc.cancel_thread(adapt);
+}
+
+u32 rtw_hal_read_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask)
+{
+	u32 data = 0;
+
+	if (adapt->HalFunc.read_bbreg)
+		data = adapt->HalFunc.read_bbreg(adapt, regaddr, bitmask);
+	return data;
+}
+
+void rtw_hal_write_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask,
+			 u32 data)
+{
+	if (adapt->HalFunc.write_bbreg)
+		adapt->HalFunc.write_bbreg(adapt, regaddr, bitmask, data);
+}
+
+u32 rtw_hal_read_rfreg(struct adapter *adapt, enum rf_radio_path rfpath,
+		       u32 regaddr, u32 bitmask)
+{
+	u32 data = 0;
+
+	if (adapt->HalFunc.read_rfreg)
+		data = adapt->HalFunc.read_rfreg(adapt, rfpath, regaddr,
+						    bitmask);
+	return data;
+}
+
+void rtw_hal_write_rfreg(struct adapter *adapt, enum rf_radio_path rfpath,
+			 u32 regaddr, u32 bitmask, u32 data)
+{
+	if (adapt->HalFunc.write_rfreg)
+		adapt->HalFunc.write_rfreg(adapt, rfpath, regaddr,
+					      bitmask, data);
+}
+
+s32 rtw_hal_interrupt_handler(struct adapter *adapt)
+{
+	if (adapt->HalFunc.interrupt_handler)
+		return adapt->HalFunc.interrupt_handler(adapt);
+	return _FAIL;
+}
+
+void rtw_hal_set_bwmode(struct adapter *adapt,
+			enum ht_channel_width bandwidth, u8 offset)
+{
+	if (adapt->HalFunc.set_bwmode_handler)
+		adapt->HalFunc.set_bwmode_handler(adapt, bandwidth,
+						     offset);
+}
+
+void rtw_hal_set_chan(struct adapter *adapt, u8 channel)
+{
+	if (adapt->HalFunc.set_channel_handler)
+		adapt->HalFunc.set_channel_handler(adapt, channel);
+}
+
+void rtw_hal_dm_watchdog(struct adapter *adapt)
+{
+	if (adapt->HalFunc.hal_dm_watchdog)
+		adapt->HalFunc.hal_dm_watchdog(adapt);
+}
+
+void rtw_hal_bcn_related_reg_setting(struct adapter *adapt)
+{
+	if (adapt->HalFunc.SetBeaconRelatedRegistersHandler)
+		adapt->HalFunc.SetBeaconRelatedRegistersHandler(adapt);
+}
+
+u8 rtw_hal_antdiv_before_linked(struct adapter *adapt)
+{
+	if (adapt->HalFunc.AntDivBeforeLinkHandler)
+		return adapt->HalFunc.AntDivBeforeLinkHandler(adapt);
+	return false;
+}
+
+void rtw_hal_antdiv_rssi_compared(struct adapter *adapt,
+				  struct wlan_bssid_ex *dst,
+				  struct wlan_bssid_ex *src)
+{
+	if (adapt->HalFunc.AntDivCompareHandler)
+		adapt->HalFunc.AntDivCompareHandler(adapt, dst, src);
+}
+
+void rtw_hal_sreset_init(struct adapter *adapt)
+{
+	if (adapt->HalFunc.sreset_init_value)
+		adapt->HalFunc.sreset_init_value(adapt);
+}
+
+void rtw_hal_sreset_reset(struct adapter *adapt)
+{
+	if (adapt->HalFunc.silentreset)
+		adapt->HalFunc.silentreset(adapt);
+}
+
+void rtw_hal_sreset_reset_value(struct adapter *adapt)
+{
+	if (adapt->HalFunc.sreset_reset_value)
+		adapt->HalFunc.sreset_reset_value(adapt);
+}
+
+void rtw_hal_sreset_xmit_status_check(struct adapter *adapt)
+{
+	if (adapt->HalFunc.sreset_xmit_status_check)
+		adapt->HalFunc.sreset_xmit_status_check(adapt);
+}
+
+void rtw_hal_sreset_linked_status_check(struct adapter *adapt)
+{
+	if (adapt->HalFunc.sreset_linked_status_check)
+		adapt->HalFunc.sreset_linked_status_check(adapt);
+}
+
+u8   rtw_hal_sreset_get_wifi_status(struct adapter *adapt)
+{
+	u8 status = 0;
+
+	if (adapt->HalFunc.sreset_get_wifi_status)
+		status = adapt->HalFunc.sreset_get_wifi_status(adapt);
+	return status;
+}
+
+int rtw_hal_iol_cmd(struct adapter  *adapter, struct xmit_frame *xmit_frame,
+		    u32 max_wating_ms, u32 bndy_cnt)
+{
+	if (adapter->HalFunc.IOL_exec_cmds_sync)
+		return adapter->HalFunc.IOL_exec_cmds_sync(adapter, xmit_frame,
+							   max_wating_ms,
+							   bndy_cnt);
+	return _FAIL;
+}
+
+void rtw_hal_notch_filter(struct adapter *adapter, bool enable)
+{
+	if (adapter->HalFunc.hal_notch_filter)
+		adapter->HalFunc.hal_notch_filter(adapter, enable);
+}
+
+void rtw_hal_reset_security_engine(struct adapter *adapter)
+{
+	if (adapter->HalFunc.hal_reset_security_engine)
+		adapter->HalFunc.hal_reset_security_engine(adapter);
+}
+
+s32 rtw_hal_c2h_handler(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt)
+{
+	s32 ret = _FAIL;
+
+	if (adapter->HalFunc.c2h_handler)
+		ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt);
+	return ret;
+}
+
+c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter)
+{
+	return adapter->HalFunc.c2h_id_filter_ccx;
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
new file mode 100644
index 0000000..285475f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -0,0 +1,2171 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+/*  include files */
+
+#include "odm_precomp.h"
+
+static const u16 dB_Invert_Table[8][12] = {
+	{1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4},
+	{4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16},
+	{18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63},
+	{71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251},
+	{282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000},
+	{1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981},
+	{4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849},
+	{17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535}
+};
+
+/* avoid to warn in FreeBSD ==> To DO modify */
+static u32 EDCAParam[HT_IOT_PEER_MAX][3] = {
+	/*  UL			DL */
+	{0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 0:unknown AP */
+	{0xa44f, 0x5ea44f, 0x5e431c}, /*  1:realtek AP */
+	{0x5ea42b, 0x5ea42b, 0x5ea42b}, /*  2:unknown AP => realtek_92SE */
+	{0x5ea32b, 0x5ea42b, 0x5e4322}, /*  3:broadcom AP */
+	{0x5ea422, 0x00a44f, 0x00a44f}, /*  4:ralink AP */
+	{0x5ea322, 0x00a630, 0x00a44f}, /*  5:atheros AP */
+	{0x5e4322, 0x5e4322, 0x5e4322},/*  6:cisco AP */
+	{0x5ea44f, 0x00a44f, 0x5ea42b}, /*  8:marvell AP */
+	{0x5ea42b, 0x5ea42b, 0x5ea42b}, /*  10:unknown AP=> 92U AP */
+	{0x5ea42b, 0xa630, 0x5e431c}, /*  11:airgocap AP */
+};
+
+/*  Global var */
+u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D] = {
+	0x7f8001fe, /*  0, +6.0dB */
+	0x788001e2, /*  1, +5.5dB */
+	0x71c001c7, /*  2, +5.0dB */
+	0x6b8001ae, /*  3, +4.5dB */
+	0x65400195, /*  4, +4.0dB */
+	0x5fc0017f, /*  5, +3.5dB */
+	0x5a400169, /*  6, +3.0dB */
+	0x55400155, /*  7, +2.5dB */
+	0x50800142, /*  8, +2.0dB */
+	0x4c000130, /*  9, +1.5dB */
+	0x47c0011f, /*  10, +1.0dB */
+	0x43c0010f, /*  11, +0.5dB */
+	0x40000100, /*  12, +0dB */
+	0x3c8000f2, /*  13, -0.5dB */
+	0x390000e4, /*  14, -1.0dB */
+	0x35c000d7, /*  15, -1.5dB */
+	0x32c000cb, /*  16, -2.0dB */
+	0x300000c0, /*  17, -2.5dB */
+	0x2d4000b5, /*  18, -3.0dB */
+	0x2ac000ab, /*  19, -3.5dB */
+	0x288000a2, /*  20, -4.0dB */
+	0x26000098, /*  21, -4.5dB */
+	0x24000090, /*  22, -5.0dB */
+	0x22000088, /*  23, -5.5dB */
+	0x20000080, /*  24, -6.0dB */
+	0x1e400079, /*  25, -6.5dB */
+	0x1c800072, /*  26, -7.0dB */
+	0x1b00006c, /*  27. -7.5dB */
+	0x19800066, /*  28, -8.0dB */
+	0x18000060, /*  29, -8.5dB */
+	0x16c0005b, /*  30, -9.0dB */
+	0x15800056, /*  31, -9.5dB */
+	0x14400051, /*  32, -10.0dB */
+	0x1300004c, /*  33, -10.5dB */
+	0x12000048, /*  34, -11.0dB */
+	0x11000044, /*  35, -11.5dB */
+	0x10000040, /*  36, -12.0dB */
+	0x0f00003c,/*  37, -12.5dB */
+	0x0e400039,/*  38, -13.0dB */
+	0x0d800036,/*  39, -13.5dB */
+	0x0cc00033,/*  40, -14.0dB */
+	0x0c000030,/*  41, -14.5dB */
+	0x0b40002d,/*  42, -15.0dB */
+};
+
+u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = {
+	{0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /*  0, +0dB */
+	{0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /*  1, -0.5dB */
+	{0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /*  2, -1.0dB */
+	{0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /*  3, -1.5dB */
+	{0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /*  4, -2.0dB */
+	{0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /*  5, -2.5dB */
+	{0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /*  6, -3.0dB */
+	{0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /*  7, -3.5dB */
+	{0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /*  8, -4.0dB */
+	{0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /*  9, -4.5dB */
+	{0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /*  10, -5.0dB */
+	{0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /*  11, -5.5dB */
+	{0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /*  12, -6.0dB */
+	{0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /*  13, -6.5dB */
+	{0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /*  14, -7.0dB */
+	{0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /*  15, -7.5dB */
+	{0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /*  16, -8.0dB */
+	{0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /*  17, -8.5dB */
+	{0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /*  18, -9.0dB */
+	{0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /*  19, -9.5dB */
+	{0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /*  20, -10.0dB */
+	{0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /*  21, -10.5dB */
+	{0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /*  22, -11.0dB */
+	{0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /*  23, -11.5dB */
+	{0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /*  24, -12.0dB */
+	{0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /*  25, -12.5dB */
+	{0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /*  26, -13.0dB */
+	{0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  27, -13.5dB */
+	{0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  28, -14.0dB */
+	{0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  29, -14.5dB */
+	{0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  30, -15.0dB */
+	{0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /*  31, -15.5dB */
+	{0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}	/*  32, -16.0dB */
+};
+
+u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = {
+	{0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /*  0, +0dB */
+	{0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /*  1, -0.5dB */
+	{0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /*  2, -1.0dB */
+	{0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /*  3, -1.5dB */
+	{0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /*  4, -2.0dB */
+	{0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /*  5, -2.5dB */
+	{0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /*  6, -3.0dB */
+	{0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /*  7, -3.5dB */
+	{0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /*  8, -4.0dB */
+	{0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /*  9, -4.5dB */
+	{0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /*  10, -5.0dB */
+	{0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /*  11, -5.5dB */
+	{0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /*  12, -6.0dB */
+	{0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /*  13, -6.5dB */
+	{0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /*  14, -7.0dB */
+	{0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /*  15, -7.5dB */
+	{0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /*  16, -8.0dB */
+	{0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /*  17, -8.5dB */
+	{0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /*  18, -9.0dB */
+	{0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /*  19, -9.5dB */
+	{0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /*  20, -10.0dB */
+	{0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /*  21, -10.5dB */
+	{0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /*  22, -11.0dB */
+	{0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  23, -11.5dB */
+	{0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  24, -12.0dB */
+	{0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  25, -12.5dB */
+	{0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  26, -13.0dB */
+	{0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  27, -13.5dB */
+	{0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  28, -14.0dB */
+	{0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  29, -14.5dB */
+	{0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  30, -15.0dB */
+	{0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  31, -15.5dB */
+	{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}  /*  32, -16.0dB */
+};
+
+
+#define		RxDefaultAnt1		0x65a9
+#define	RxDefaultAnt2		0x569a
+
+/* 3 Export Interface */
+
+/*  2011/09/21 MH Add to describe different team necessary resource allocate?? */
+void ODM_DMInit(struct odm_dm_struct *pDM_Odm)
+{
+	/* 2012.05.03 Luke: For all IC series */
+	odm_CommonInfoSelfInit(pDM_Odm);
+	odm_CmnInfoInit_Debug(pDM_Odm);
+	odm_DIGInit(pDM_Odm);
+	odm_RateAdaptiveMaskInit(pDM_Odm);
+
+	if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) {
+		;
+	} else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+		odm_PrimaryCCA_Init(pDM_Odm);    /*  Gary */
+		odm_DynamicBBPowerSavingInit(pDM_Odm);
+		odm_DynamicTxPowerInit(pDM_Odm);
+		odm_TXPowerTrackingInit(pDM_Odm);
+		ODM_EdcaTurboInit(pDM_Odm);
+		ODM_RAInfo_Init_all(pDM_Odm);
+		if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)	||
+		    (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ||
+		    (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV))
+			odm_InitHybridAntDiv(pDM_Odm);
+		else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV)
+			odm_SwAntDivInit(pDM_Odm);
+	}
+}
+
+/*  2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */
+/*  You can not add any dummy function here, be care, you can only use DM structure */
+/*  to perform any new ODM_DM. */
+void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm)
+{
+	/* 2012.05.03 Luke: For all IC series */
+	odm_GlobalAdapterCheck();
+	odm_CmnInfoHook_Debug(pDM_Odm);
+	odm_CmnInfoUpdate_Debug(pDM_Odm);
+	odm_CommonInfoSelfUpdate(pDM_Odm);
+	odm_FalseAlarmCounterStatistics(pDM_Odm);
+	odm_RSSIMonitorCheck(pDM_Odm);
+
+	/* For CE Platform(SPRD or Tablet) */
+	/* 8723A or 8189ES platform */
+	/* NeilChen--2012--08--24-- */
+	/* Fix Leave LPS issue */
+	if ((pDM_Odm->Adapter->pwrctrlpriv.pwr_mode != PS_MODE_ACTIVE) &&/*  in LPS mode */
+	    ((pDM_Odm->SupportICType & (ODM_RTL8723A)) ||
+	    (pDM_Odm->SupportICType & (ODM_RTL8188E) &&
+	    ((pDM_Odm->SupportInterface  == ODM_ITRF_SDIO))))) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n"));
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n"));
+		odm_DIGbyRSSI_LPS(pDM_Odm);
+	} else {
+		odm_DIG(pDM_Odm);
+	}
+	odm_CCKPacketDetectionThresh(pDM_Odm);
+
+	if (*(pDM_Odm->pbPowerSaving))
+		return;
+
+	odm_RefreshRateAdaptiveMask(pDM_Odm);
+
+	odm_DynamicBBPowerSaving(pDM_Odm);
+	odm_DynamicPrimaryCCA(pDM_Odm);
+	if ((pDM_Odm->AntDivType ==  CG_TRX_HW_ANTDIV)	||
+	    (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV)	||
+	    (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV))
+		odm_HwAntDiv(pDM_Odm);
+	else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV)
+		odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK);
+
+	if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) {
+		;
+	} else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+		ODM_TXPowerTrackingCheck(pDM_Odm);
+	      odm_EdcaTurboCheck(pDM_Odm);
+		odm_DynamicTxPower(pDM_Odm);
+	}
+	odm_dtc(pDM_Odm);
+}
+
+/*  Init /.. Fixed HW value. Only init time. */
+void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u32 Value)
+{
+	/*  This section is used for init value */
+	switch	(CmnInfo) {
+	/*  Fixed ODM value. */
+	case	ODM_CMNINFO_ABILITY:
+		pDM_Odm->SupportAbility = (u32)Value;
+		break;
+	case	ODM_CMNINFO_PLATFORM:
+		pDM_Odm->SupportPlatform = (u8)Value;
+		break;
+	case	ODM_CMNINFO_INTERFACE:
+		pDM_Odm->SupportInterface = (u8)Value;
+		break;
+	case	ODM_CMNINFO_MP_TEST_CHIP:
+		pDM_Odm->bIsMPChip = (u8)Value;
+		break;
+	case	ODM_CMNINFO_IC_TYPE:
+		pDM_Odm->SupportICType = Value;
+		break;
+	case	ODM_CMNINFO_CUT_VER:
+		pDM_Odm->CutVersion = (u8)Value;
+		break;
+	case	ODM_CMNINFO_FAB_VER:
+		pDM_Odm->FabVersion = (u8)Value;
+		break;
+	case	ODM_CMNINFO_RF_TYPE:
+		pDM_Odm->RFType = (u8)Value;
+		break;
+	case    ODM_CMNINFO_RF_ANTENNA_TYPE:
+		pDM_Odm->AntDivType = (u8)Value;
+		break;
+	case	ODM_CMNINFO_BOARD_TYPE:
+		pDM_Odm->BoardType = (u8)Value;
+		break;
+	case	ODM_CMNINFO_EXT_LNA:
+		pDM_Odm->ExtLNA = (u8)Value;
+		break;
+	case	ODM_CMNINFO_EXT_PA:
+		pDM_Odm->ExtPA = (u8)Value;
+		break;
+	case	ODM_CMNINFO_EXT_TRSW:
+		pDM_Odm->ExtTRSW = (u8)Value;
+		break;
+	case	ODM_CMNINFO_PATCH_ID:
+		pDM_Odm->PatchID = (u8)Value;
+		break;
+	case	ODM_CMNINFO_BINHCT_TEST:
+		pDM_Odm->bInHctTest = (bool)Value;
+		break;
+	case	ODM_CMNINFO_BWIFI_TEST:
+		pDM_Odm->bWIFITest = (bool)Value;
+		break;
+	case	ODM_CMNINFO_SMART_CONCURRENT:
+		pDM_Odm->bDualMacSmartConcurrent = (bool)Value;
+		break;
+	/* To remove the compiler warning, must add an empty default statement to handle the other values. */
+	default:
+		/* do nothing */
+		break;
+	}
+
+	/*  Tx power tracking BB swing table. */
+	/*  The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */
+	pDM_Odm->BbSwingIdxOfdm			= 12; /*  Set defalut value as index 12. */
+	pDM_Odm->BbSwingIdxOfdmCurrent	= 12;
+	pDM_Odm->BbSwingFlagOfdm		= false;
+}
+
+void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, void *pValue)
+{
+	/*  */
+	/*  Hook call by reference pointer. */
+	/*  */
+	switch	(CmnInfo) {
+	/*  Dynamic call by reference pointer. */
+	case	ODM_CMNINFO_MAC_PHY_MODE:
+		pDM_Odm->pMacPhyMode = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_TX_UNI:
+		pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue;
+		break;
+	case	ODM_CMNINFO_RX_UNI:
+		pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue;
+		break;
+	case	ODM_CMNINFO_WM_MODE:
+		pDM_Odm->pWirelessMode = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_BAND:
+		pDM_Odm->pBandType = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_SEC_CHNL_OFFSET:
+		pDM_Odm->pSecChOffset = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_SEC_MODE:
+		pDM_Odm->pSecurity = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_BW:
+		pDM_Odm->pBandWidth = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_CHNL:
+		pDM_Odm->pChannel = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_DMSP_GET_VALUE:
+		pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_BUDDY_ADAPTOR:
+		pDM_Odm->pBuddyAdapter = (struct adapter **)pValue;
+		break;
+	case	ODM_CMNINFO_DMSP_IS_MASTER:
+		pDM_Odm->pbMasterOfDMSP = (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_SCAN:
+		pDM_Odm->pbScanInProcess = (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_POWER_SAVING:
+		pDM_Odm->pbPowerSaving = (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_ONE_PATH_CCA:
+		pDM_Odm->pOnePathCCA = (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_DRV_STOP:
+		pDM_Odm->pbDriverStopped =  (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_PNP_IN:
+		pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep =  (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_INIT_ON:
+		pDM_Odm->pinit_adpt_in_progress =  (bool *)pValue;
+		break;
+	case	ODM_CMNINFO_ANT_TEST:
+		pDM_Odm->pAntennaTest =  (u8 *)pValue;
+		break;
+	case	ODM_CMNINFO_NET_CLOSED:
+		pDM_Odm->pbNet_closed = (bool *)pValue;
+		break;
+	case    ODM_CMNINFO_MP_MODE:
+		pDM_Odm->mp_mode = (u8 *)pValue;
+		break;
+	/* To remove the compiler warning, must add an empty default statement to handle the other values. */
+	default:
+		/* do nothing */
+		break;
+	}
+}
+
+void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u16 Index, void *pValue)
+{
+	/*  Hook call by reference pointer. */
+	switch	(CmnInfo) {
+	/*  Dynamic call by reference pointer. */
+	case	ODM_CMNINFO_STA_STATUS:
+		pDM_Odm->pODM_StaInfo[Index] = (struct sta_info *)pValue;
+		break;
+	/* To remove the compiler warning, must add an empty default statement to handle the other values. */
+	default:
+		/* do nothing */
+		break;
+	}
+}
+
+/*  Update Band/CHannel/.. The values are dynamic but non-per-packet. */
+void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value)
+{
+	/*  */
+	/*  This init variable may be changed in run time. */
+	/*  */
+	switch	(CmnInfo) {
+	case	ODM_CMNINFO_ABILITY:
+		pDM_Odm->SupportAbility = (u32)Value;
+		break;
+	case	ODM_CMNINFO_RF_TYPE:
+		pDM_Odm->RFType = (u8)Value;
+		break;
+	case	ODM_CMNINFO_WIFI_DIRECT:
+		pDM_Odm->bWIFI_Direct = (bool)Value;
+		break;
+	case	ODM_CMNINFO_WIFI_DISPLAY:
+		pDM_Odm->bWIFI_Display = (bool)Value;
+		break;
+	case	ODM_CMNINFO_LINK:
+		pDM_Odm->bLinked = (bool)Value;
+		break;
+	case	ODM_CMNINFO_RSSI_MIN:
+		pDM_Odm->RSSI_Min = (u8)Value;
+		break;
+	case	ODM_CMNINFO_DBG_COMP:
+		pDM_Odm->DebugComponents = Value;
+		break;
+	case	ODM_CMNINFO_DBG_LEVEL:
+		pDM_Odm->DebugLevel = (u32)Value;
+		break;
+	case	ODM_CMNINFO_RA_THRESHOLD_HIGH:
+		pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value;
+		break;
+	case	ODM_CMNINFO_RA_THRESHOLD_LOW:
+		pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value;
+		break;
+	}
+}
+
+void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm)
+{
+	pDM_Odm->bCckHighPower = (bool) ODM_GetBBReg(pDM_Odm, 0x824, BIT9);
+	pDM_Odm->RFPathRxEnable = (u8) ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F);
+	if (pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D))
+		pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV;
+	if (pDM_Odm->SupportICType & (ODM_RTL8723A))
+		pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV;
+
+	ODM_InitDebugSetting(pDM_Odm);
+}
+
+void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm)
+{
+	u8 EntryCnt = 0;
+	u8 i;
+	struct sta_info *pEntry;
+
+	if (*(pDM_Odm->pBandWidth) == ODM_BW40M) {
+		if (*(pDM_Odm->pSecChOffset) == 1)
+			pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) - 2;
+		else if (*(pDM_Odm->pSecChOffset) == 2)
+			pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) + 2;
+	} else {
+		pDM_Odm->ControlChannel = *(pDM_Odm->pChannel);
+	}
+
+	for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+		pEntry = pDM_Odm->pODM_StaInfo[i];
+		if (IS_STA_VALID(pEntry))
+			EntryCnt++;
+	}
+	if (EntryCnt == 1)
+		pDM_Odm->bOneEntryOnly = true;
+	else
+		pDM_Odm->bOneEntryOnly = false;
+}
+
+void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm)
+{
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug==>\n"));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform=%d\n", pDM_Odm->SupportPlatform));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility=0x%x\n", pDM_Odm->SupportAbility));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface=%d\n", pDM_Odm->SupportInterface));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType=0x%x\n", pDM_Odm->SupportICType));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion=%d\n", pDM_Odm->CutVersion));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion=%d\n", pDM_Odm->FabVersion));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType=%d\n", pDM_Odm->RFType));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType=%d\n", pDM_Odm->BoardType));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA=%d\n", pDM_Odm->ExtLNA));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA=%d\n", pDM_Odm->ExtPA));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW=%d\n", pDM_Odm->ExtTRSW));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID=%d\n", pDM_Odm->PatchID));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest=%d\n", pDM_Odm->bInHctTest));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest=%d\n", pDM_Odm->bWIFITest));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent=%d\n", pDM_Odm->bDualMacSmartConcurrent));
+}
+
+void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm)
+{
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug==>\n"));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast=%llu\n", *(pDM_Odm->pNumTxBytesUnicast)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast=%llu\n", *(pDM_Odm->pNumRxBytesUnicast)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode=0x%x\n", *(pDM_Odm->pWirelessMode)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset=%d\n", *(pDM_Odm->pSecChOffset)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity=%d\n", *(pDM_Odm->pSecurity)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth=%d\n", *(pDM_Odm->pBandWidth)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel=%d\n", *(pDM_Odm->pChannel)));
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess=%d\n", *(pDM_Odm->pbScanInProcess)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving=%d\n", *(pDM_Odm->pbPowerSaving)));
+
+	if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL))
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pOnePathCCA=%d\n", *(pDM_Odm->pOnePathCCA)));
+}
+
+void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm)
+{
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug==>\n"));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct=%d\n", pDM_Odm->bWIFI_Direct));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display=%d\n", pDM_Odm->bWIFI_Display));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked=%d\n", pDM_Odm->bLinked));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min=%d\n", pDM_Odm->RSSI_Min));
+}
+
+static int getIGIForDiff(int value_IGI)
+{
+	#define ONERCCA_LOW_TH		0x30
+	#define ONERCCA_LOW_DIFF	8
+
+	if (value_IGI < ONERCCA_LOW_TH) {
+		if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF)
+			return ONERCCA_LOW_TH;
+		else
+			return value_IGI + ONERCCA_LOW_DIFF;
+	} else {
+		return value_IGI;
+	}
+}
+
+void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI)
+{
+	struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+		     ("ODM_REG(IGI_A,pDM_Odm)=0x%x, ODM_BIT(IGI,pDM_Odm)=0x%x\n",
+		     ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)));
+
+	if (pDM_DigTable->CurIGValue != CurrentIGI) {
+		if (pDM_Odm->SupportPlatform & (ODM_CE|ODM_MP)) {
+			ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+				if (pDM_Odm->SupportICType != ODM_RTL8188E)
+				ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+		} else if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) {
+			switch (*(pDM_Odm->pOnePathCCA)) {
+			case ODM_CCA_2R:
+				ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+					if (pDM_Odm->SupportICType != ODM_RTL8188E)
+					ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+				break;
+			case ODM_CCA_1R_A:
+				ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+					if (pDM_Odm->SupportICType != ODM_RTL8188E)
+					ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI));
+				break;
+			case ODM_CCA_1R_B:
+				ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI));
+					if (pDM_Odm->SupportICType != ODM_RTL8188E)
+					ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+					break;
+				}
+		}
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x).\n", CurrentIGI));
+		/* pDM_DigTable->PreIGValue = pDM_DigTable->CurIGValue; */
+		pDM_DigTable->CurIGValue = CurrentIGI;
+	}
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_Write_DIG():CurrentIGI=0x%x\n", CurrentIGI));
+
+/*  Add by Neil Chen to enable edcca to MP Platform */
+}
+
+/* Need LPS mode for CE platform --2012--08--24--- */
+/* 8723AS/8189ES */
+void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm)
+{
+	struct adapter *pAdapter = pDM_Odm->Adapter;
+	struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+
+	u8 RSSI_Lower = DM_DIG_MIN_NIC;   /* 0x1E or 0x1C */
+	u8 bFwCurrentInPSMode = false;
+	u8 CurrentIGI = pDM_Odm->RSSI_Min;
+
+	if (!(pDM_Odm->SupportICType & (ODM_RTL8723A | ODM_RTL8188E)))
+		return;
+
+	CurrentIGI = CurrentIGI + RSSI_OFFSET_DIG;
+	bFwCurrentInPSMode = pAdapter->pwrctrlpriv.bFwCurrentInPSMode;
+
+	/*  Using FW PS mode to make IGI */
+	if (bFwCurrentInPSMode) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG is in LPS mode\n"));
+		/* Adjust by  FA in LPS MODE */
+		if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS)
+			CurrentIGI = CurrentIGI+2;
+		else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS)
+			CurrentIGI = CurrentIGI+1;
+		else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS)
+			CurrentIGI = CurrentIGI-1;
+	} else {
+		CurrentIGI = RSSI_Lower;
+	}
+
+	/* Lower bound checking */
+
+	/* RSSI Lower bound check */
+	if ((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC)
+		RSSI_Lower = (pDM_Odm->RSSI_Min-10);
+	else
+		RSSI_Lower = DM_DIG_MIN_NIC;
+
+	/* Upper and Lower Bound checking */
+	 if (CurrentIGI > DM_DIG_MAX_NIC)
+		CurrentIGI = DM_DIG_MAX_NIC;
+	 else if (CurrentIGI < RSSI_Lower)
+		CurrentIGI = RSSI_Lower;
+
+	ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */
+}
+
+void odm_DIGInit(struct odm_dm_struct *pDM_Odm)
+{
+	struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+	pDM_DigTable->CurIGValue = (u8) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm));
+	pDM_DigTable->RssiLowThresh	= DM_DIG_THRESH_LOW;
+	pDM_DigTable->RssiHighThresh	= DM_DIG_THRESH_HIGH;
+	pDM_DigTable->FALowThresh	= DM_false_ALARM_THRESH_LOW;
+	pDM_DigTable->FAHighThresh	= DM_false_ALARM_THRESH_HIGH;
+	if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
+		pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+		pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
+	} else {
+		pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+		pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
+	}
+	pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT;
+	pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX;
+	pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN;
+	pDM_DigTable->PreCCK_CCAThres = 0xFF;
+	pDM_DigTable->CurCCK_CCAThres = 0x83;
+	pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC;
+	pDM_DigTable->LargeFAHit = 0;
+	pDM_DigTable->Recover_cnt = 0;
+	pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC;
+	pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC;
+	pDM_DigTable->bMediaConnect_0 = false;
+	pDM_DigTable->bMediaConnect_1 = false;
+
+	/* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */
+	pDM_Odm->bDMInitialGainEnable = true;
+}
+
+void odm_DIG(struct odm_dm_struct *pDM_Odm)
+{
+	struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+	struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+	u8 DIG_Dynamic_MIN;
+	u8 DIG_MaxOfMin;
+	bool FirstConnect, FirstDisConnect;
+	u8 dm_dig_max, dm_dig_min;
+	u8 CurrentIGI = pDM_DigTable->CurIGValue;
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n"));
+	if ((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+			     ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n"));
+		return;
+	}
+
+	if (*(pDM_Odm->pbScanInProcess)) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In Scan Progress\n"));
+		return;
+	}
+
+	/* add by Neil Chen to avoid PSD is processing */
+	if (pDM_Odm->bDMInitialGainEnable == false) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: PSD is Processing\n"));
+		return;
+	}
+
+	if (pDM_Odm->SupportICType == ODM_RTL8192D) {
+		if (*(pDM_Odm->pMacPhyMode) == ODM_DMSP) {
+			if (*(pDM_Odm->pbMasterOfDMSP)) {
+				DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+				FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+				FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+			} else {
+				DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1;
+				FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1);
+				FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1);
+			}
+		} else {
+			if (*(pDM_Odm->pBandType) == ODM_BAND_5G) {
+				DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+				FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+				FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+			} else {
+				DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1;
+				FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1);
+				FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1);
+			}
+		}
+	} else {
+		DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+		FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+		FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+	}
+
+	/* 1 Boundary Decision */
+	if ((pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8723A)) &&
+	    ((pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) || pDM_Odm->ExtLNA)) {
+		if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) {
+			dm_dig_max = DM_DIG_MAX_AP_HP;
+			dm_dig_min = DM_DIG_MIN_AP_HP;
+		} else {
+			dm_dig_max = DM_DIG_MAX_NIC_HP;
+			dm_dig_min = DM_DIG_MIN_NIC_HP;
+		}
+		DIG_MaxOfMin = DM_DIG_MAX_AP_HP;
+	} else {
+		if (pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) {
+			dm_dig_max = DM_DIG_MAX_AP;
+			dm_dig_min = DM_DIG_MIN_AP;
+			DIG_MaxOfMin = dm_dig_max;
+		} else {
+			dm_dig_max = DM_DIG_MAX_NIC;
+			dm_dig_min = DM_DIG_MIN_NIC;
+			DIG_MaxOfMin = DM_DIG_MAX_AP;
+		}
+	}
+	if (pDM_Odm->bLinked) {
+	      /* 2 8723A Series, offset need to be 10 */
+		if (pDM_Odm->SupportICType == (ODM_RTL8723A)) {
+			/* 2 Upper Bound */
+			if ((pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC)
+				pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+			else if ((pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC)
+				pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC;
+			else
+				pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10;
+			/* 2 If BT is Concurrent, need to set Lower Bound */
+			DIG_Dynamic_MIN = DM_DIG_MIN_NIC;
+		} else {
+			/* 2 Modify DIG upper bound */
+			if ((pDM_Odm->RSSI_Min + 20) > dm_dig_max)
+				pDM_DigTable->rx_gain_range_max = dm_dig_max;
+			else if ((pDM_Odm->RSSI_Min + 20) < dm_dig_min)
+				pDM_DigTable->rx_gain_range_max = dm_dig_min;
+			else
+				pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20;
+			/* 2 Modify DIG lower bound */
+			if (pDM_Odm->bOneEntryOnly) {
+				if (pDM_Odm->RSSI_Min < dm_dig_min)
+					DIG_Dynamic_MIN = dm_dig_min;
+				else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin)
+					DIG_Dynamic_MIN = DIG_MaxOfMin;
+				else
+					DIG_Dynamic_MIN = pDM_Odm->RSSI_Min;
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+					     ("odm_DIG() : bOneEntryOnly=true,  DIG_Dynamic_MIN=0x%x\n",
+					     DIG_Dynamic_MIN));
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+					     ("odm_DIG() : pDM_Odm->RSSI_Min=%d\n",
+					     pDM_Odm->RSSI_Min));
+			} else if ((pDM_Odm->SupportICType == ODM_RTL8188E) &&
+				   (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
+				/* 1 Lower Bound for 88E AntDiv */
+				if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) {
+					DIG_Dynamic_MIN = (u8) pDM_DigTable->AntDiv_RSSI_max;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+						     ("odm_DIG(): pDM_DigTable->AntDiv_RSSI_max=%d\n",
+						     pDM_DigTable->AntDiv_RSSI_max));
+				}
+			} else {
+				DIG_Dynamic_MIN = dm_dig_min;
+			}
+		}
+	} else {
+		pDM_DigTable->rx_gain_range_max = dm_dig_max;
+		DIG_Dynamic_MIN = dm_dig_min;
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : No Link\n"));
+	}
+
+	/* 1 Modify DIG lower bound, deal with abnormally large false alarm */
+	if (pFalseAlmCnt->Cnt_all > 10000) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnornally false alarm case.\n"));
+
+		if (pDM_DigTable->LargeFAHit != 3)
+			pDM_DigTable->LargeFAHit++;
+		if (pDM_DigTable->ForbiddenIGI < CurrentIGI) {
+			pDM_DigTable->ForbiddenIGI = CurrentIGI;
+			pDM_DigTable->LargeFAHit = 1;
+		}
+
+		if (pDM_DigTable->LargeFAHit >= 3) {
+			if ((pDM_DigTable->ForbiddenIGI+1) > pDM_DigTable->rx_gain_range_max)
+				pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max;
+			else
+				pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
+			pDM_DigTable->Recover_cnt = 3600; /* 3600=2hr */
+		}
+
+	} else {
+		/* Recovery mechanism for IGI lower bound */
+		if (pDM_DigTable->Recover_cnt != 0) {
+			pDM_DigTable->Recover_cnt--;
+		} else {
+			if (pDM_DigTable->LargeFAHit < 3) {
+				if ((pDM_DigTable->ForbiddenIGI-1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */
+					pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
+					pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n"));
+				} else {
+					pDM_DigTable->ForbiddenIGI--;
+					pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n"));
+				}
+			} else {
+				pDM_DigTable->LargeFAHit = 0;
+			}
+		}
+	}
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+		     ("odm_DIG(): pDM_DigTable->LargeFAHit=%d\n",
+		     pDM_DigTable->LargeFAHit));
+
+	/* 1 Adjust initial gain by false alarm */
+	if (pDM_Odm->bLinked) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG AfterLink\n"));
+		if (FirstConnect) {
+			CurrentIGI = pDM_Odm->RSSI_Min;
+			ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n"));
+		} else {
+			if (pDM_Odm->SupportICType == ODM_RTL8192D) {
+				if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D)
+					CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+				else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D)
+					CurrentIGI = CurrentIGI + 1; /* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+				else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D)
+					CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
+			} else {
+				if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2)
+						CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+				else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1)
+						CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+				else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0)
+						CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
+			}
+		}
+	} else {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG BeforeLink\n"));
+		if (FirstDisConnect) {
+			CurrentIGI = pDM_DigTable->rx_gain_range_min;
+			ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First DisConnect\n"));
+		} else {
+			/* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */
+			if (pFalseAlmCnt->Cnt_all > 10000)
+				CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+			else if (pFalseAlmCnt->Cnt_all > 8000)
+				CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+			else if (pFalseAlmCnt->Cnt_all < 500)
+				CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */
+			ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): England DIG\n"));
+		}
+	}
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG End Adjust IGI\n"));
+	/* 1 Check initial gain by upper/lower bound */
+	if (CurrentIGI > pDM_DigTable->rx_gain_range_max)
+		CurrentIGI = pDM_DigTable->rx_gain_range_max;
+	if (CurrentIGI < pDM_DigTable->rx_gain_range_min)
+		CurrentIGI = pDM_DigTable->rx_gain_range_min;
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+		     ("odm_DIG(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n",
+		     pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): TotalFA=%d\n", pFalseAlmCnt->Cnt_all));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue=0x%x\n", CurrentIGI));
+
+	/* 2 High power RSSI threshold */
+
+	ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */
+	pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked;
+	pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN;
+}
+
+/* 3============================================================ */
+/* 3 FASLE ALARM CHECK */
+/* 3============================================================ */
+
+void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm)
+{
+	u32 ret_value;
+	struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt);
+
+	if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))
+		return;
+
+	if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+		/* hold ofdm counter */
+		ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); /* hold page C counter */
+		ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); /* hold page D counter */
+
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord);
+		FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff);
+		FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16);
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord);
+		FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff);
+		FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16);
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord);
+		FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff);
+		FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16);
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord);
+		FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff);
+
+		FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal +
+					     FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail +
+					     FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail;
+
+		if (pDM_Odm->SupportICType == ODM_RTL8188E) {
+			ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_SC_CNT_11N, bMaskDWord);
+			FalseAlmCnt->Cnt_BW_LSC = (ret_value&0xffff);
+			FalseAlmCnt->Cnt_BW_USC = ((ret_value&0xffff0000)>>16);
+		}
+
+		/* hold cck counter */
+		ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1);
+		ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1);
+
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0);
+		FalseAlmCnt->Cnt_Cck_fail = ret_value;
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3);
+		FalseAlmCnt->Cnt_Cck_fail +=  (ret_value & 0xff)<<8;
+
+		ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord);
+		FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) | ((ret_value&0xFF00)>>8);
+
+		FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync +
+					FalseAlmCnt->Cnt_SB_Search_fail +
+					FalseAlmCnt->Cnt_Parity_Fail +
+					FalseAlmCnt->Cnt_Rate_Illegal +
+					FalseAlmCnt->Cnt_Crc8_fail +
+					FalseAlmCnt->Cnt_Mcs_fail +
+					FalseAlmCnt->Cnt_Cck_fail);
+
+		FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA;
+
+		if (pDM_Odm->SupportICType >= ODM_RTL8723A) {
+			/* reset false alarm counter registers */
+			ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1);
+			ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0);
+			ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1);
+			ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0);
+			/* update ofdm counter */
+			ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); /* update page C counter */
+			ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); /* update page D counter */
+
+			/* reset CCK CCA counter */
+			ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0);
+			ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2);
+			/* reset CCK FA counter */
+			ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0);
+			ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2);
+		}
+
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics\n"));
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
+			     ("Cnt_Fast_Fsync=%d, Cnt_SB_Search_fail=%d\n",
+			     FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail));
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
+			     ("Cnt_Parity_Fail=%d, Cnt_Rate_Illegal=%d\n",
+			     FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal));
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD,
+			     ("Cnt_Crc8_fail=%d, Cnt_Mcs_fail=%d\n",
+			     FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail));
+	} else { /* FOR ODM_IC_11AC_SERIES */
+		/* read OFDM FA counter */
+		FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord);
+		FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord);
+		FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail;
+
+		/*  reset OFDM FA coutner */
+		ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1);
+		ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0);
+		/*  reset CCK FA counter */
+		ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0);
+		ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1);
+	}
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail=%d\n", FalseAlmCnt->Cnt_Cck_fail));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail=%d\n", FalseAlmCnt->Cnt_Ofdm_fail));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm=%d\n", FalseAlmCnt->Cnt_all));
+}
+
+/* 3============================================================ */
+/* 3 CCK Packet Detect Threshold */
+/* 3============================================================ */
+
+void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm)
+{
+	u8 CurCCK_CCAThres;
+	struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt);
+
+	if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT)))
+		return;
+	if (pDM_Odm->ExtLNA)
+		return;
+	if (pDM_Odm->bLinked) {
+		if (pDM_Odm->RSSI_Min > 25) {
+			CurCCK_CCAThres = 0xcd;
+		} else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) {
+			CurCCK_CCAThres = 0x83;
+		} else {
+			if (FalseAlmCnt->Cnt_Cck_fail > 1000)
+				CurCCK_CCAThres = 0x83;
+			else
+				CurCCK_CCAThres = 0x40;
+		}
+	} else {
+		if (FalseAlmCnt->Cnt_Cck_fail > 1000)
+			CurCCK_CCAThres = 0x83;
+		else
+			CurCCK_CCAThres = 0x40;
+	}
+	ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres);
+}
+
+void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres)
+{
+	struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+	if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres)		/* modify by Guo.Mingzhi 2012-01-03 */
+		ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres);
+	pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres;
+	pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres;
+}
+
+/* 3============================================================ */
+/* 3 BB Power Save */
+/* 3============================================================ */
+void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm)
+{
+	struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable;
+
+	pDM_PSTable->PreCCAState = CCA_MAX;
+	pDM_PSTable->CurCCAState = CCA_MAX;
+	pDM_PSTable->PreRFState = RF_MAX;
+	pDM_PSTable->CurRFState = RF_MAX;
+	pDM_PSTable->Rssi_val_min = 0;
+	pDM_PSTable->initialize = 0;
+}
+
+void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm)
+{
+	if ((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8723A))
+		return;
+	if (!(pDM_Odm->SupportAbility & ODM_BB_PWR_SAVE))
+		return;
+	if (!(pDM_Odm->SupportPlatform & (ODM_MP|ODM_CE)))
+		return;
+
+	/* 1 2.Power Saving for 92C */
+	if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->RFType == ODM_2T2R)) {
+		odm_1R_CCA(pDM_Odm);
+	} else {
+	/*  20100628 Joseph: Turn off BB power save for 88CE because it makesthroughput unstable. */
+	/*  20100831 Joseph: Turn ON BB power save again after modifying AGC delay from 900ns ot 600ns. */
+	/* 1 3.Power Saving for 88C */
+		ODM_RF_Saving(pDM_Odm, false);
+	}
+}
+
+void odm_1R_CCA(struct odm_dm_struct *pDM_Odm)
+{
+	struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable;
+
+	if (pDM_Odm->RSSI_Min != 0xFF) {
+		if (pDM_PSTable->PreCCAState == CCA_2R) {
+			if (pDM_Odm->RSSI_Min >= 35)
+				pDM_PSTable->CurCCAState = CCA_1R;
+			else
+				pDM_PSTable->CurCCAState = CCA_2R;
+		} else {
+			if (pDM_Odm->RSSI_Min <= 30)
+				pDM_PSTable->CurCCAState = CCA_2R;
+			else
+				pDM_PSTable->CurCCAState = CCA_1R;
+		}
+	} else {
+		pDM_PSTable->CurCCAState = CCA_MAX;
+	}
+
+	if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) {
+		if (pDM_PSTable->CurCCAState == CCA_1R) {
+			if (pDM_Odm->RFType == ODM_2T2R)
+				ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13);
+			else
+				ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23);
+		} else {
+			ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33);
+		}
+		pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState;
+	}
+}
+
+void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal)
+{
+	struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable;
+	u8 Rssi_Up_bound = 30;
+	u8 Rssi_Low_bound = 25;
+
+	if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */
+		Rssi_Up_bound = 50;
+		Rssi_Low_bound = 45;
+	}
+	if (pDM_PSTable->initialize == 0) {
+		pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14;
+		pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3;
+		pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24;
+		pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12;
+		pDM_PSTable->initialize = 1;
+	}
+
+	if (!bForceInNormal) {
+		if (pDM_Odm->RSSI_Min != 0xFF) {
+			if (pDM_PSTable->PreRFState == RF_Normal) {
+				if (pDM_Odm->RSSI_Min >= Rssi_Up_bound)
+					pDM_PSTable->CurRFState = RF_Save;
+				else
+					pDM_PSTable->CurRFState = RF_Normal;
+			} else {
+				if (pDM_Odm->RSSI_Min <= Rssi_Low_bound)
+					pDM_PSTable->CurRFState = RF_Normal;
+				else
+					pDM_PSTable->CurRFState = RF_Save;
+			}
+		} else {
+			pDM_PSTable->CurRFState = RF_MAX;
+		}
+	} else {
+		pDM_PSTable->CurRFState = RF_Normal;
+	}
+
+	if (pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) {
+		if (pDM_PSTable->CurRFState == RF_Save) {
+			/*  <tynli_note> 8723 RSSI report will be wrong. Set 0x874[5]=1 when enter BB power saving mode. */
+			/*  Suggested by SD3 Yu-Nan. 2011.01.20. */
+			if (pDM_Odm->SupportICType == ODM_RTL8723A)
+				ODM_SetBBReg(pDM_Odm, 0x874  , BIT5, 0x1); /* Reg874[5]=1b'1 */
+			ODM_SetBBReg(pDM_Odm, 0x874  , 0x1C0000, 0x2); /* Reg874[20:18]=3'b010 */
+			ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); /* RegC70[3]=1'b0 */
+			ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]=0x63 */
+			ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); /* Reg874[15:14]=2'b10 */
+			ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); /* RegA75[7:4]=0x3 */
+			ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); /* Reg818[28]=1'b0 */
+			ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); /* Reg818[28]=1'b1 */
+		} else {
+			ODM_SetBBReg(pDM_Odm, 0x874  , 0x1CC000, pDM_PSTable->Reg874);
+			ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70);
+			ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C);
+			ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74);
+			ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0);
+
+			if (pDM_Odm->SupportICType == ODM_RTL8723A)
+				ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x0); /* Reg874[5]=1b'0 */
+		}
+		pDM_PSTable->PreRFState = pDM_PSTable->CurRFState;
+	}
+}
+
+/* 3============================================================ */
+/* 3 RATR MASK */
+/* 3============================================================ */
+/* 3============================================================ */
+/* 3 Rate Adaptive */
+/* 3============================================================ */
+
+void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm)
+{
+	struct odm_rate_adapt *pOdmRA = &pDM_Odm->RateAdaptive;
+
+	pOdmRA->Type = DM_Type_ByDriver;
+	if (pOdmRA->Type == DM_Type_ByDriver)
+		pDM_Odm->bUseRAMask = true;
+	else
+		pDM_Odm->bUseRAMask = false;
+
+	pOdmRA->RATRState = DM_RATR_STA_INIT;
+	pOdmRA->HighRSSIThresh = 50;
+	pOdmRA->LowRSSIThresh = 20;
+}
+
+u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level)
+{
+	struct sta_info *pEntry;
+	u32 rate_bitmap = 0x0fffffff;
+	u8 WirelessMode;
+
+	pEntry = pDM_Odm->pODM_StaInfo[macid];
+	if (!IS_STA_VALID(pEntry))
+		return ra_mask;
+
+	WirelessMode = pEntry->wireless_mode;
+
+	switch (WirelessMode) {
+	case ODM_WM_B:
+		if (ra_mask & 0x0000000c)		/* 11M or 5.5M enable */
+			rate_bitmap = 0x0000000d;
+		else
+			rate_bitmap = 0x0000000f;
+		break;
+	case (ODM_WM_A|ODM_WM_G):
+		if (rssi_level == DM_RATR_STA_HIGH)
+			rate_bitmap = 0x00000f00;
+		else
+			rate_bitmap = 0x00000ff0;
+		break;
+	case (ODM_WM_B|ODM_WM_G):
+		if (rssi_level == DM_RATR_STA_HIGH)
+			rate_bitmap = 0x00000f00;
+		else if (rssi_level == DM_RATR_STA_MIDDLE)
+			rate_bitmap = 0x00000ff0;
+		else
+			rate_bitmap = 0x00000ff5;
+		break;
+	case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+	case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+		if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) {
+			if (rssi_level == DM_RATR_STA_HIGH) {
+				rate_bitmap = 0x000f0000;
+			} else if (rssi_level == DM_RATR_STA_MIDDLE) {
+				rate_bitmap = 0x000ff000;
+			} else {
+				if (*(pDM_Odm->pBandWidth) == ODM_BW40M)
+					rate_bitmap = 0x000ff015;
+				else
+					rate_bitmap = 0x000ff005;
+			}
+		} else {
+			if (rssi_level == DM_RATR_STA_HIGH) {
+				rate_bitmap = 0x0f8f0000;
+			} else if (rssi_level == DM_RATR_STA_MIDDLE) {
+				rate_bitmap = 0x0f8ff000;
+			} else {
+				if (*(pDM_Odm->pBandWidth) == ODM_BW40M)
+					rate_bitmap = 0x0f8ff015;
+				else
+					rate_bitmap = 0x0f8ff005;
+			}
+		}
+		break;
+	default:
+		/* case WIRELESS_11_24N: */
+		/* case WIRELESS_11_5N: */
+		if (pDM_Odm->RFType == RF_1T2R)
+			rate_bitmap = 0x000fffff;
+		else
+			rate_bitmap = 0x0fffffff;
+		break;
+	}
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+		     (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x\n",
+		     rssi_level, WirelessMode, rate_bitmap));
+
+	return rate_bitmap;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	odm_RefreshRateAdaptiveMask()
+ *
+ * Overview:	Update rate table mask according to rssi
+ *
+ * Input:		NONE
+ *
+ * Output:		NONE
+ *
+ * Return:		NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	05/27/2009	hpfan	Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm)
+{
+	if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK))
+		return;
+	/*  */
+	/*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+	/*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+	/*  HW dynamic mechanism. */
+	/*  */
+	switch	(pDM_Odm->SupportPlatform) {
+	case	ODM_MP:
+		odm_RefreshRateAdaptiveMaskMP(pDM_Odm);
+		break;
+	case	ODM_CE:
+		odm_RefreshRateAdaptiveMaskCE(pDM_Odm);
+		break;
+	case	ODM_AP:
+	case	ODM_ADSL:
+		odm_RefreshRateAdaptiveMaskAPADSL(pDM_Odm);
+		break;
+	}
+}
+
+void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm)
+{
+	u8 i;
+	struct adapter *pAdapter = pDM_Odm->Adapter;
+
+	if (pAdapter->bDriverStopped) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n"));
+		return;
+	}
+
+	if (!pDM_Odm->bUseRAMask) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n"));
+		return;
+	}
+
+	for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+		struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i];
+		if (IS_STA_VALID(pstat)) {
+			if (ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false , &pstat->rssi_level)) {
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+					     ("RSSI:%d, RSSI_LEVEL:%d\n",
+					     pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level));
+				rtw_hal_update_ra_mask(pAdapter, i, pstat->rssi_level);
+			}
+		}
+	}
+}
+
+void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+/*  Return Value: bool */
+/*  - true: RATRState is changed. */
+bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate, u8 *pRATRState)
+{
+	struct odm_rate_adapt *pRA = &pDM_Odm->RateAdaptive;
+	const u8 GoUpGap = 5;
+	u8 HighRSSIThreshForRA = pRA->HighRSSIThresh;
+	u8 LowRSSIThreshForRA = pRA->LowRSSIThresh;
+	u8 RATRState;
+
+	/*  Threshold Adjustment: */
+	/*  when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */
+	/*  Here GoUpGap is added to solve the boundary's level alternation issue. */
+	switch (*pRATRState) {
+	case DM_RATR_STA_INIT:
+	case DM_RATR_STA_HIGH:
+		break;
+	case DM_RATR_STA_MIDDLE:
+		HighRSSIThreshForRA += GoUpGap;
+		break;
+	case DM_RATR_STA_LOW:
+		HighRSSIThreshForRA += GoUpGap;
+		LowRSSIThreshForRA += GoUpGap;
+		break;
+	default:
+		ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState));
+		break;
+	}
+
+	/*  Decide RATRState by RSSI. */
+	if (RSSI > HighRSSIThreshForRA)
+		RATRState = DM_RATR_STA_HIGH;
+	else if (RSSI > LowRSSIThreshForRA)
+		RATRState = DM_RATR_STA_MIDDLE;
+	else
+		RATRState = DM_RATR_STA_LOW;
+
+	if (*pRATRState != RATRState || bForceUpdate) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState));
+		*pRATRState = RATRState;
+		return true;
+	}
+	return false;
+}
+
+/* 3============================================================ */
+/* 3 Dynamic Tx Power */
+/* 3============================================================ */
+
+void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
+	pdmpriv->bDynamicTxPowerEnable = false;
+	pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal;
+	pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal;
+}
+
+void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm)
+{
+	/*  For AP/ADSL use struct rtl8192cd_priv * */
+	/*  For CE/NIC use struct adapter * */
+
+	if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR))
+		return;
+
+	/*  2012/01/12 MH According to Luke's suggestion, only high power will support the feature. */
+	if (!pDM_Odm->ExtPA)
+		return;
+
+	/*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+	/*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+	/*  HW dynamic mechanism. */
+	switch	(pDM_Odm->SupportPlatform) {
+	case	ODM_MP:
+	case	ODM_CE:
+		odm_DynamicTxPowerNIC(pDM_Odm);
+		break;
+	case	ODM_AP:
+		odm_DynamicTxPowerAP(pDM_Odm);
+		break;
+	case	ODM_ADSL:
+		break;
+	}
+}
+
+void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm)
+{
+	if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR))
+		return;
+
+	if (pDM_Odm->SupportICType == ODM_RTL8188E) {
+		/*  ??? */
+		/*  This part need to be redefined. */
+	}
+}
+
+void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+/* 3============================================================ */
+/* 3 RSSI Monitor */
+/* 3============================================================ */
+
+void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm)
+{
+	if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR))
+		return;
+
+	/*  */
+	/*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+	/*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+	/*  HW dynamic mechanism. */
+	/*  */
+	switch	(pDM_Odm->SupportPlatform) {
+	case	ODM_MP:
+		odm_RSSIMonitorCheckMP(pDM_Odm);
+		break;
+	case	ODM_CE:
+		odm_RSSIMonitorCheckCE(pDM_Odm);
+		break;
+	case	ODM_AP:
+		odm_RSSIMonitorCheckAP(pDM_Odm);
+		break;
+	case	ODM_ADSL:
+		/* odm_DIGAP(pDM_Odm); */
+		break;
+	}
+
+}	/*  odm_RSSIMonitorCheck */
+
+void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+static void FindMinimumRSSI(struct adapter *pAdapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
+	struct mlme_priv	*pmlmepriv = &pAdapter->mlmepriv;
+
+	/* 1 1.Determine the minimum RSSI */
+	if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) &&
+	    (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0))
+		pdmpriv->MinUndecoratedPWDBForDM = 0;
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true)	/*  Default port */
+		pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+	else /*  associated entry pwdb */
+		pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+}
+
+void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
+	int	i;
+	int	tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff;
+	u8	sta_cnt = 0;
+	u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */
+	struct sta_info *psta;
+	u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	if (!check_fwstate(&Adapter->mlmepriv, _FW_LINKED))
+		return;
+
+	for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+		psta = pDM_Odm->pODM_StaInfo[i];
+		if (IS_STA_VALID(psta) &&
+		    (psta->state & WIFI_ASOC_STATE) &&
+		    !_rtw_memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) &&
+		    !_rtw_memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) {
+			if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB)
+				tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
+
+			if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB)
+				tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
+			if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1))
+				PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16));
+		}
+	}
+
+	for (i = 0; i < sta_cnt; i++) {
+		if (PWDB_rssi[i] != (0)) {
+			if (pHalData->fw_ractrl) {
+				/*  Report every sta's RSSI to FW */
+			} else {
+				ODM_RA_SetRSSI_8188E(
+				&(pHalData->odmpriv), (PWDB_rssi[i]&0xFF), (u8)((PWDB_rssi[i]>>16) & 0xFF));
+			}
+		}
+	}
+
+	if (tmpEntryMaxPWDB != 0)	/*  If associated entry is found */
+		pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB;
+	else
+		pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0;
+
+	if (tmpEntryMinPWDB != 0xff) /*  If associated entry is found */
+		pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB;
+	else
+		pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0;
+
+	FindMinimumRSSI(Adapter);
+	ODM_CmnInfoUpdate(&pHalData->odmpriv , ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM);
+}
+
+void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm)
+{
+	ODM_InitializeTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer,
+			    (void *)odm_SwAntDivChkAntSwitchCallback, NULL, "SwAntennaSwitchTimer");
+}
+
+void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm)
+{
+	ODM_CancelTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer);
+}
+
+void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm)
+{
+	ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer);
+
+	ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->FastAntTrainingTimer);
+}
+
+/* 3============================================================ */
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+
+void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm)
+{
+	odm_TXPowerTrackingThermalMeterInit(pDM_Odm);
+}
+
+void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm)
+{
+	pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
+	pDM_Odm->RFCalibrateInfo.TXPowercount = 0;
+	pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false;
+	if (*(pDM_Odm->mp_mode) != 1)
+		pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
+	MSG_88E("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl);
+
+	pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
+}
+
+void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm)
+{
+	/*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+	/*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+	/*  HW dynamic mechanism. */
+	switch	(pDM_Odm->SupportPlatform) {
+	case	ODM_MP:
+		odm_TXPowerTrackingCheckMP(pDM_Odm);
+		break;
+	case	ODM_CE:
+		odm_TXPowerTrackingCheckCE(pDM_Odm);
+		break;
+	case	ODM_AP:
+		odm_TXPowerTrackingCheckAP(pDM_Odm);
+		break;
+	case	ODM_ADSL:
+		break;
+	}
+}
+
+void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+
+	if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK))
+		return;
+
+	if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) {		/* at least delay 1 sec */
+		PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_88E, BIT17 | BIT16, 0x03);
+
+		pDM_Odm->RFCalibrateInfo.TM_Trigger = 1;
+		return;
+	} else {
+		odm_TXPowerTrackingCallback_ThermalMeter_8188E(Adapter);
+		pDM_Odm->RFCalibrateInfo.TM_Trigger = 0;
+	}
+}
+
+void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+/* antenna mapping info */
+/*  1: right-side antenna */
+/*  2/0: left-side antenna */
+/* PDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt:  for right-side antenna:   Ant:1    RxDefaultAnt1 */
+/* PDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt:  for left-side antenna:     Ant:0    RxDefaultAnt2 */
+/*  We select left antenna as default antenna in initial process, modify it as needed */
+/*  */
+
+/* 3============================================================ */
+/* 3 SW Antenna Diversity */
+/* 3============================================================ */
+void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID, struct odm_phy_status_info *pPhyInfo)
+{
+}
+
+void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step)
+{
+}
+
+void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm)
+{
+}
+
+void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext)
+{
+}
+
+/* 3============================================================ */
+/* 3 SW Antenna Diversity */
+/* 3============================================================ */
+
+void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm)
+{
+	if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n"));
+		return;
+	}
+
+	if (pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D))
+		;
+	else if (pDM_Odm->SupportICType == ODM_RTL8188E)
+		ODM_AntennaDiversityInit_88E(pDM_Odm);
+}
+
+void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate)
+{
+	struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
+	if (pDM_SWAT_Table->antsel == 1) {
+		if (isCCKrate) {
+			pDM_SWAT_Table->CCK_Ant1_Cnt[MacId]++;
+		} else {
+			pDM_SWAT_Table->OFDM_Ant1_Cnt[MacId]++;
+			pDM_SWAT_Table->RSSI_Ant1_Sum[MacId] += PWDBAll;
+		}
+	} else {
+		if (isCCKrate) {
+			pDM_SWAT_Table->CCK_Ant2_Cnt[MacId]++;
+		} else {
+			pDM_SWAT_Table->OFDM_Ant2_Cnt[MacId]++;
+			pDM_SWAT_Table->RSSI_Ant2_Sum[MacId] += PWDBAll;
+		}
+	}
+}
+
+void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm)
+{
+	if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) {
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Return: Not Support HW AntDiv\n"));
+		return;
+	}
+
+	if (pDM_Odm->SupportICType == ODM_RTL8188E)
+		ODM_AntennaDiversity_88E(pDM_Odm);
+}
+
+/* EDCA Turbo */
+void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
+	pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
+	Adapter->recvpriv.bIsAnyNonBEPkts = false;
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VO_PARAM)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VI_PARAM)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM)));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BK_PARAM)));
+}	/*  ODM_InitEdcaTurbo */
+
+void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm)
+{
+	/*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+	/*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+	/*  HW dynamic mechanism. */
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("odm_EdcaTurboCheck========================>\n"));
+
+	if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO))
+		return;
+
+	switch	(pDM_Odm->SupportPlatform) {
+	case	ODM_MP:
+		break;
+	case	ODM_CE:
+		odm_EdcaTurboCheckCE(pDM_Odm);
+		break;
+	case	ODM_AP:
+	case	ODM_ADSL:
+		break;
+	}
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("<========================odm_EdcaTurboCheck\n"));
+}	/*  odm_CheckEdcaTurbo */
+
+void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	u32	trafficIndex;
+	u32	edca_param;
+	u64	cur_tx_bytes = 0;
+	u64	cur_rx_bytes = 0;
+	u8	bbtchange = false;
+	struct hal_data_8188e		*pHalData = GET_HAL_DATA(Adapter);
+	struct xmit_priv		*pxmitpriv = &(Adapter->xmitpriv);
+	struct recv_priv		*precvpriv = &(Adapter->recvpriv);
+	struct registry_priv	*pregpriv = &Adapter->registrypriv;
+	struct mlme_ext_priv	*pmlmeext = &(Adapter->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	if ((pregpriv->wifi_spec == 1))/*  (pmlmeinfo->HT_enable == 0)) */
+		goto dm_CheckEdcaTurbo_EXIT;
+
+	if (pmlmeinfo->assoc_AP_vendor >=  HT_IOT_PEER_MAX)
+		goto dm_CheckEdcaTurbo_EXIT;
+
+	/*  Check if the status needs to be changed. */
+	if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) {
+		cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes;
+		cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes;
+
+		/* traffic, TX or RX */
+		if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) ||
+		    (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) {
+			if (cur_tx_bytes > (cur_rx_bytes << 2)) {
+				/*  Uplink TP is present. */
+				trafficIndex = UP_LINK;
+			} else {
+				/*  Balance TP is present. */
+				trafficIndex = DOWN_LINK;
+			}
+		} else {
+			if (cur_rx_bytes > (cur_tx_bytes << 2)) {
+				/*  Downlink TP is present. */
+				trafficIndex = DOWN_LINK;
+			} else {
+				/*  Balance TP is present. */
+				trafficIndex = UP_LINK;
+			}
+		}
+
+		if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) {
+			if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) && (pmlmeext->cur_wireless_mode & WIRELESS_11_24N))
+				edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex];
+			else
+				edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex];
+
+			rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param);
+
+			pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex;
+		}
+
+		pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true;
+	} else {
+		/*  Turn Off EDCA turbo here. */
+		/*  Restore original EDCA according to the declaration of AP. */
+		 if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) {
+			rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE);
+			pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
+		}
+	}
+
+dm_CheckEdcaTurbo_EXIT:
+	/*  Set variables for next time. */
+	precvpriv->bIsAnyNonBEPkts = false;
+	pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes;
+	precvpriv->last_rx_bytes = precvpriv->rx_bytes;
+}
+
+/*  need to ODM CE Platform */
+/* move to here for ANT detection mechanism using */
+
+u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point, u8 initial_gain_psd)
+{
+	u32 psd_report;
+
+	/* Set DCO frequency index, offset=(40MHz/SamplePts)*point */
+	ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point);
+
+	/* Start PSD calculation, Reg808[22]=0->1 */
+	ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1);
+	/* Need to wait for HW PSD report */
+	ODM_StallExecution(30);
+	ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0);
+	/* Read PSD report, Reg8B4[15:0] */
+	psd_report = ODM_GetBBReg(pDM_Odm, 0x8B4, bMaskDWord) & 0x0000FFFF;
+
+	psd_report = (u32) (ConvertTo_dB(psd_report))+(u32)(initial_gain_psd-0x1c);
+
+	return psd_report;
+}
+
+u32 ConvertTo_dB(u32 Value)
+{
+	u8 i;
+	u8 j;
+	u32 dB;
+
+	Value = Value & 0xFFFF;
+	for (i = 0; i < 8; i++) {
+		if (Value <= dB_Invert_Table[i][11])
+			break;
+	}
+
+	if (i >= 8)
+		return 96;	/*  maximum 96 dB */
+
+	for (j = 0; j < 12; j++) {
+		if (Value <= dB_Invert_Table[i][j])
+			break;
+	}
+
+	dB = i*12 + j + 1;
+
+	return dB;
+}
+
+/*  2011/09/22 MH Add for 92D global spin lock utilization. */
+void odm_GlobalAdapterCheck(void)
+{
+}	/*  odm_GlobalAdapterCheck */
+
+/*  Description: */
+/* 	Set Single/Dual Antenna default setting for products that do not do detection in advance. */
+/*  Added by Joseph, 2012.03.22 */
+void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm)
+{
+	struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
+	pDM_SWAT_Table->ANTA_ON = true;
+	pDM_SWAT_Table->ANTB_ON = true;
+}
+
+
+/* 2 8723A ANT DETECT */
+
+static void odm_PHY_SaveAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegisterNum)
+{
+	u32 i;
+
+	/* RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); */
+	for (i = 0; i < RegisterNum; i++)
+		AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord);
+}
+
+static void odm_PHY_ReloadAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegiesterNum)
+{
+	u32 i;
+
+	for (i = 0; i < RegiesterNum; i++)
+		ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]);
+}
+
+/* 2 8723A ANT DETECT */
+/*  Description: */
+/* 	Implement IQK single tone for RF DPK loopback and BB PSD scanning. */
+/* 	This function is cooperated with BB team Neil. */
+bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode)
+{
+	struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+	u32 CurrentChannel, RfLoopReg;
+	u8 n;
+	u32 Reg88c, Regc08, Reg874, Regc50;
+	u8 initial_gain = 0x5a;
+	u32 PSD_report_tmp;
+	u32 AntA_report = 0x0, AntB_report = 0x0, AntO_report = 0x0;
+	bool bResult = true;
+	u32 AFE_Backup[16];
+	u32 AFE_REG_8723A[16] = {
+		rRx_Wait_CCA, rTx_CCK_RFON,
+		rTx_CCK_BBON, rTx_OFDM_RFON,
+		rTx_OFDM_BBON, rTx_To_Rx,
+		rTx_To_Tx, rRx_CCK,
+		rRx_OFDM, rRx_Wait_RIFS,
+		rRx_TO_Rx, rStandby,
+		rSleep, rPMPD_ANAEN,
+		rFPGA0_XCD_SwitchControl, rBlue_Tooth};
+
+	if (!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)))
+		return bResult;
+
+	if (!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV))
+		return bResult;
+
+	if (pDM_Odm->SupportICType == ODM_RTL8192C) {
+		/* Which path in ADC/DAC is turnned on for PSD: both I/Q */
+		ODM_SetBBReg(pDM_Odm, 0x808, BIT10|BIT11, 0x3);
+		/* Ageraged number: 8 */
+		ODM_SetBBReg(pDM_Odm, 0x808, BIT12|BIT13, 0x1);
+		/* pts = 128; */
+		ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0);
+	}
+
+	/* 1 Backup Current RF/BB Settings */
+
+	CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask);
+	RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask);
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A);  /*  change to Antenna A */
+	/*  Step 1: USE IQK to transmitter single tone */
+
+	ODM_StallExecution(10);
+
+	/* Store A Path Register 88c, c08, 874, c50 */
+	Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord);
+	Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord);
+	Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord);
+	Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord);
+
+	/*  Store AFE Registers */
+	odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16);
+
+	/* Set PSD 128 pts */
+	ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0);  /* 128 pts */
+
+	/*  To SET CH1 to do */
+	ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01);     /* Channel 1 */
+
+	/*  AFE all on step */
+	ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4);
+	ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4);
+
+	/*  3 wire Disable */
+	ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0);
+
+	/* BB IQK Setting */
+	ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4);
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000);
+
+	/* IQK setting tone@ 4.34Mhz */
+	ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C);
+	ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00);
+
+
+	/* Page B init */
+	ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000);
+	ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000);
+	ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800);
+	ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f);
+	ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008);
+	ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008);
+	ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0);
+
+	/* RF loop Setting */
+	ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008);
+
+	/* IQK Single tone start */
+	ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+	ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+	ODM_StallExecution(1000);
+	PSD_report_tmp = 0x0;
+
+	for (n = 0; n < 2; n++) {
+		PSD_report_tmp =  GetPSDData(pDM_Odm, 14, initial_gain);
+		if (PSD_report_tmp > AntA_report)
+			AntA_report = PSD_report_tmp;
+	}
+
+	PSD_report_tmp = 0x0;
+
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B);  /*  change to Antenna B */
+	ODM_StallExecution(10);
+
+
+	for (n = 0; n < 2; n++) {
+		PSD_report_tmp =  GetPSDData(pDM_Odm, 14, initial_gain);
+		if (PSD_report_tmp > AntB_report)
+			AntB_report = PSD_report_tmp;
+	}
+
+	/*  change to open case */
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0);  /*  change to Ant A and B all open case */
+	ODM_StallExecution(10);
+
+	for (n = 0; n < 2; n++) {
+		PSD_report_tmp =  GetPSDData(pDM_Odm, 14, initial_gain);
+		if (PSD_report_tmp > AntO_report)
+			AntO_report = PSD_report_tmp;
+	}
+
+	/* Close IQK Single Tone function */
+	ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+	PSD_report_tmp = 0x0;
+
+	/* 1 Return to antanna A */
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A);
+	ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c);
+	ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08);
+	ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874);
+	ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40);
+	ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50);
+	ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel);
+	ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask, RfLoopReg);
+
+	/* Reload AFE Registers */
+	odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16);
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d\n", 2416, AntA_report));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d\n", 2416, AntB_report));
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d\n", 2416, AntO_report));
+
+
+	if (pDM_Odm->SupportICType == ODM_RTL8723A) {
+	/* 2 Test Ant B based on Ant A is ON */
+		if (mode == ANTTESTB) {
+			if (AntA_report >= 100) {
+				if (AntB_report > (AntA_report+1)) {
+					pDM_SWAT_Table->ANTB_ON = false;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n"));
+				} else {
+					pDM_SWAT_Table->ANTB_ON = true;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n"));
+				}
+			} else {
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n"));
+				pDM_SWAT_Table->ANTB_ON = false; /*  Set Antenna B off as default */
+				bResult = false;
+			}
+		} else if (mode == ANTTESTALL) {
+			/* 2 Test Ant A and B based on DPDT Open */
+			if ((AntO_report >= 100)&(AntO_report < 118)) {
+				if (AntA_report > (AntO_report+1)) {
+					pDM_SWAT_Table->ANTA_ON = false;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is OFF"));
+				} else {
+					pDM_SWAT_Table->ANTA_ON = true;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is ON"));
+				}
+
+				if (AntB_report > (AntO_report+2)) {
+					pDM_SWAT_Table->ANTB_ON = false;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is OFF"));
+				} else {
+					pDM_SWAT_Table->ANTB_ON = true;
+					ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is ON"));
+				}
+			}
+		}
+	} else if (pDM_Odm->SupportICType == ODM_RTL8192C) {
+		if (AntA_report >= 100) {
+			if (AntB_report > (AntA_report+2)) {
+				pDM_SWAT_Table->ANTA_ON = false;
+				pDM_SWAT_Table->ANTB_ON = true;
+				ODM_SetBBReg(pDM_Odm,  rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B);
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna B\n"));
+			} else if (AntA_report > (AntB_report+2)) {
+				pDM_SWAT_Table->ANTA_ON = true;
+				pDM_SWAT_Table->ANTB_ON = false;
+				ODM_SetBBReg(pDM_Odm,  rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A);
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n"));
+			} else {
+				pDM_SWAT_Table->ANTA_ON = true;
+				pDM_SWAT_Table->ANTB_ON = true;
+				ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+					     ("ODM_SingleDualAntennaDetection(): Dual Antenna\n"));
+			}
+		} else {
+			ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n"));
+			pDM_SWAT_Table->ANTA_ON = true; /*  Set Antenna A on as default */
+			pDM_SWAT_Table->ANTB_ON = false; /*  Set Antenna B off as default */
+			bResult = false;
+		}
+	}
+	return bResult;
+}
+
+/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */
+void odm_dtc(struct odm_dm_struct *pDM_Odm)
+{
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_HWConfig.c b/drivers/staging/rtl8188eu/hal/odm_HWConfig.c
new file mode 100644
index 0000000..19c509a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_HWConfig.c
@@ -0,0 +1,596 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+/*  include files */
+
+#include "odm_precomp.h"
+
+#define READ_AND_CONFIG     READ_AND_CONFIG_MP
+
+#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(dm_odm))
+#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(dm_odm))
+
+static u8 odm_QueryRxPwrPercentage(s8 AntPower)
+{
+	if ((AntPower <= -100) || (AntPower >= 20))
+		return	0;
+	else if (AntPower >= 0)
+		return	100;
+	else
+		return 100+AntPower;
+}
+
+/*  2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. */
+/*  IF other SW team do not support the feature, remove this section.?? */
+static s32 odm_sig_patch_lenove(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+	return 0;
+}
+
+static s32 odm_sig_patch_netcore(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+	return 0;
+}
+
+static s32 odm_SignalScaleMapping_92CSeries(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+	s32 RetSig = 0;
+
+	if ((dm_odm->SupportInterface  == ODM_ITRF_USB) ||
+	    (dm_odm->SupportInterface  == ODM_ITRF_SDIO)) {
+		if (CurrSig >= 51 && CurrSig <= 100)
+			RetSig = 100;
+		else if (CurrSig >= 41 && CurrSig <= 50)
+			RetSig = 80 + ((CurrSig - 40)*2);
+		else if (CurrSig >= 31 && CurrSig <= 40)
+			RetSig = 66 + (CurrSig - 30);
+		else if (CurrSig >= 21 && CurrSig <= 30)
+			RetSig = 54 + (CurrSig - 20);
+		else if (CurrSig >= 10 && CurrSig <= 20)
+			RetSig = 42 + (((CurrSig - 10) * 2) / 3);
+		else if (CurrSig >= 5 && CurrSig <= 9)
+			RetSig = 22 + (((CurrSig - 5) * 3) / 2);
+		else if (CurrSig >= 1 && CurrSig <= 4)
+			RetSig = 6 + (((CurrSig - 1) * 3) / 2);
+		else
+			RetSig = CurrSig;
+	}
+	return RetSig;
+}
+
+static s32 odm_SignalScaleMapping(struct odm_dm_struct *dm_odm, s32 CurrSig)
+{
+	if ((dm_odm->SupportPlatform == ODM_MP) &&
+	    (dm_odm->SupportInterface != ODM_ITRF_PCIE) && /* USB & SDIO */
+	    (dm_odm->PatchID == 10))
+		return odm_sig_patch_netcore(dm_odm, CurrSig);
+	else if ((dm_odm->SupportPlatform == ODM_MP) &&
+		 (dm_odm->SupportInterface == ODM_ITRF_PCIE) &&
+		 (dm_odm->PatchID == 19))
+		return odm_sig_patch_lenove(dm_odm, CurrSig);
+	else
+		return odm_SignalScaleMapping_92CSeries(dm_odm, CurrSig);
+}
+
+/* pMgntInfo->CustomerID == RT_CID_819x_Lenovo */
+static u8 odm_SQ_process_patch_RT_CID_819x_Lenovo(struct odm_dm_struct *dm_odm,
+	u8 isCCKrate, u8 PWDB_ALL, u8 path, u8 RSSI)
+{
+	return 0;
+}
+
+static u8 odm_EVMdbToPercentage(s8 Value)
+{
+	/*  -33dB~0dB to 0%~99% */
+	s8 ret_val;
+
+	ret_val = Value;
+
+	if (ret_val >= 0)
+		ret_val = 0;
+	if (ret_val <= -33)
+		ret_val = -33;
+
+	ret_val = 0 - ret_val;
+	ret_val *= 3;
+
+	if (ret_val == 99)
+		ret_val = 100;
+	return ret_val;
+}
+
+static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
+			struct odm_phy_status_info *pPhyInfo,
+			u8 *pPhyStatus,
+			struct odm_per_pkt_info *pPktinfo)
+{
+	struct sw_ant_switch *pDM_SWAT_Table = &dm_odm->DM_SWAT_Table;
+	u8 i, Max_spatial_stream;
+	s8 rx_pwr[4], rx_pwr_all = 0;
+	u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT;
+	u8 RSSI, total_rssi = 0;
+	u8 isCCKrate = 0;
+	u8 rf_rx_num = 0;
+	u8 cck_highpwr = 0;
+	u8 LNA_idx, VGA_idx;
+
+	struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus;
+
+	isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false;
+
+	pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1;
+	pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1;
+
+	if (isCCKrate) {
+		u8 report;
+		u8 cck_agc_rpt;
+
+		dm_odm->PhyDbgInfo.NumQryPhyStatusCCK++;
+		/*  (1)Hardware does not provide RSSI for CCK */
+		/*  (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+
+		cck_highpwr = dm_odm->bCckHighPower;
+
+		cck_agc_rpt =  pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
+
+		/* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */
+		/* The RSSI formula should be modified according to the gain table */
+		/* In 88E, cck_highpwr is always set to 1 */
+		if (dm_odm->SupportICType & (ODM_RTL8188E|ODM_RTL8812)) {
+			LNA_idx = ((cck_agc_rpt & 0xE0) >> 5);
+			VGA_idx = (cck_agc_rpt & 0x1F);
+			switch (LNA_idx) {
+			case 7:
+				if (VGA_idx <= 27)
+					rx_pwr_all = -100 + 2*(27-VGA_idx); /* VGA_idx = 27~2 */
+				else
+					rx_pwr_all = -100;
+				break;
+			case 6:
+				rx_pwr_all = -48 + 2*(2-VGA_idx); /* VGA_idx = 2~0 */
+				break;
+			case 5:
+				rx_pwr_all = -42 + 2*(7-VGA_idx); /* VGA_idx = 7~5 */
+				break;
+			case 4:
+				rx_pwr_all = -36 + 2*(7-VGA_idx); /* VGA_idx = 7~4 */
+				break;
+			case 3:
+				rx_pwr_all = -24 + 2*(7-VGA_idx); /* VGA_idx = 7~0 */
+				break;
+			case 2:
+				if (cck_highpwr)
+					rx_pwr_all = -12 + 2*(5-VGA_idx); /* VGA_idx = 5~0 */
+				else
+					rx_pwr_all = -6 + 2*(5-VGA_idx);
+				break;
+			case 1:
+					rx_pwr_all = 8-2*VGA_idx;
+				break;
+			case 0:
+					rx_pwr_all = 14-2*VGA_idx;
+				break;
+			default:
+				break;
+			}
+			rx_pwr_all += 6;
+			PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+			if (!cck_highpwr) {
+				if (PWDB_ALL >= 80)
+					PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80;
+				else if ((PWDB_ALL <= 78) && (PWDB_ALL >= 20))
+					PWDB_ALL += 3;
+				if (PWDB_ALL > 100)
+					PWDB_ALL = 100;
+			}
+		} else {
+			if (!cck_highpwr) {
+				report = (cck_agc_rpt & 0xc0)>>6;
+				switch (report) {
+				/*  03312009 modified by cosa */
+				/*  Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */
+				/*  Note: different RF with the different RNA gain. */
+				case 0x3:
+					rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
+					break;
+				case 0x2:
+					rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
+					break;
+				case 0x1:
+					rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
+					break;
+				case 0x0:
+					rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
+					break;
+				}
+			} else {
+				report = (cck_agc_rpt & 0x60)>>5;
+				switch (report) {
+				case 0x3:
+					rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ;
+					break;
+				case 0x2:
+					rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1);
+					break;
+				case 0x1:
+					rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1);
+					break;
+				case 0x0:
+					rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1);
+					break;
+				}
+			}
+
+			PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+
+			/* Modification for ext-LNA board */
+			if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) {
+				if ((cck_agc_rpt>>7) == 0) {
+					PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL+6);
+				} else {
+					if (PWDB_ALL > 38)
+						PWDB_ALL -= 16;
+					else
+						PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL>>2) : (PWDB_ALL-12);
+				}
+
+				/* CCK modification */
+				if (PWDB_ALL > 25 && PWDB_ALL <= 60)
+					PWDB_ALL += 6;
+			} else {/* Modification for int-LNA board */
+				if (PWDB_ALL > 99)
+					PWDB_ALL -= 8;
+				else if (PWDB_ALL > 50 && PWDB_ALL <= 68)
+					PWDB_ALL += 4;
+			}
+		}
+
+		pPhyInfo->RxPWDBAll = PWDB_ALL;
+		pPhyInfo->BTRxRSSIPercentage = PWDB_ALL;
+		pPhyInfo->RecvSignalPower = rx_pwr_all;
+		/*  (3) Get Signal Quality (EVM) */
+		if (pPktinfo->bPacketMatchBSSID) {
+			u8 SQ, SQ_rpt;
+
+			if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) {
+				SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, 0, 0);
+			} else if (pPhyInfo->RxPWDBAll > 40 && !dm_odm->bInHctTest) {
+				SQ = 100;
+			} else {
+				SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all;
+
+				if (SQ_rpt > 64)
+					SQ = 0;
+				else if (SQ_rpt < 20)
+					SQ = 100;
+				else
+					SQ = ((64-SQ_rpt) * 100) / 44;
+			}
+			pPhyInfo->SignalQuality = SQ;
+			pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ;
+			pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1;
+		}
+	} else { /* is OFDM rate */
+		dm_odm->PhyDbgInfo.NumQryPhyStatusOFDM++;
+
+		/*  (1)Get RSSI for HT rate */
+
+		 for (i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) {
+			/*  2008/01/30 MH we will judge RF RX path now. */
+			if (dm_odm->RFPathRxEnable & BIT(i))
+				rf_rx_num++;
+
+			rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110;
+
+			pPhyInfo->RxPwr[i] = rx_pwr[i];
+
+			/* Translate DBM to percentage. */
+			RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]);
+			total_rssi += RSSI;
+
+			/* Modification for ext-LNA board */
+			if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) {
+				if ((pPhyStaRpt->path_agc[i].trsw) == 1)
+					RSSI = (RSSI > 94) ? 100 : (RSSI + 6);
+				else
+					RSSI = (RSSI <= 16) ? (RSSI >> 3) : (RSSI - 16);
+
+				if ((RSSI <= 34) && (RSSI >= 4))
+					RSSI -= 4;
+			}
+
+			pPhyInfo->RxMIMOSignalStrength[i] = (u8)RSSI;
+
+			/* Get Rx snr value in DB */
+			pPhyInfo->RxSNR[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+			dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+
+			/* Record Signal Strength for next packet */
+			if (pPktinfo->bPacketMatchBSSID) {
+				if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) {
+					if (i == ODM_RF_PATH_A)
+						pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, i, RSSI);
+				}
+			}
+		}
+		/*  (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+		rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f) - 110;
+
+		PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+		PWDB_ALL_BT = PWDB_ALL;
+
+		pPhyInfo->RxPWDBAll = PWDB_ALL;
+		pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT;
+		pPhyInfo->RxPower = rx_pwr_all;
+		pPhyInfo->RecvSignalPower = rx_pwr_all;
+
+		if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) {
+			/* do nothing */
+		} else {
+			/*  (3)EVM of HT rate */
+			if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15)
+				Max_spatial_stream = 2; /* both spatial stream make sense */
+			else
+				Max_spatial_stream = 1; /* only spatial stream 1 makes sense */
+
+			for (i = 0; i < Max_spatial_stream; i++) {
+				/*  Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */
+				/*  fill most significant bit to "zero" when doing shifting operation which may change a negative */
+				/*  value to positive one, then the dbm value (which is supposed to be negative)  is not correct anymore. */
+				EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i]));	/* dbm */
+
+				if (pPktinfo->bPacketMatchBSSID) {
+					if (i == ODM_RF_PATH_A) /*  Fill value in RFD, Get the first spatial stream only */
+						pPhyInfo->SignalQuality = (u8)(EVM & 0xff);
+					pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff);
+				}
+			}
+		}
+	}
+	/* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */
+	/* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */
+	if (isCCKrate) {
+		pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, PWDB_ALL));/* PWDB_ALL; */
+	} else {
+		if (rf_rx_num != 0)
+			pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, total_rssi /= rf_rx_num));
+	}
+
+	/* For 92C/92D HW (Hybrid) Antenna Diversity */
+	pDM_SWAT_Table->antsel = pPhyStaRpt->ant_sel;
+	/* For 88E HW Antenna Diversity */
+	dm_odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->ant_sel;
+	dm_odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->ant_sel_b;
+	dm_odm->DM_FatTable.antsel_rx_keep_2 = pPhyStaRpt->antsel_rx_keep_2;
+}
+
+void odm_Init_RSSIForDM(struct odm_dm_struct *dm_odm)
+{
+}
+
+static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
+				  struct odm_phy_status_info *pPhyInfo,
+				  struct odm_per_pkt_info *pPktinfo)
+{
+	s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK;
+	s32 UndecoratedSmoothedOFDM, RSSI_Ave;
+	u8 isCCKrate = 0;
+	u8 RSSI_max, RSSI_min, i;
+	u32 OFDM_pkt = 0;
+	u32 Weighting = 0;
+	struct sta_info *pEntry;
+
+	if (pPktinfo->StationID == 0xFF)
+		return;
+	pEntry = dm_odm->pODM_StaInfo[pPktinfo->StationID];
+	if (!IS_STA_VALID(pEntry))
+		return;
+	if ((!pPktinfo->bPacketMatchBSSID))
+		return;
+
+	isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false;
+
+	/* Smart Antenna Debug Message------------------  */
+	if (dm_odm->SupportICType == ODM_RTL8188E) {
+		u8 antsel_tr_mux;
+		struct fast_ant_train *pDM_FatTable = &dm_odm->DM_FatTable;
+
+		if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) {
+			if (pDM_FatTable->FAT_State == FAT_TRAINING_STATE) {
+				if (pPktinfo->bPacketToSelf) {
+					antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |
+							(pDM_FatTable->antsel_rx_keep_1<<1) |
+							pDM_FatTable->antsel_rx_keep_0;
+					pDM_FatTable->antSumRSSI[antsel_tr_mux] += pPhyInfo->RxPWDBAll;
+					pDM_FatTable->antRSSIcnt[antsel_tr_mux]++;
+				}
+			}
+		} else if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) {
+			if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
+				antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |
+						(pDM_FatTable->antsel_rx_keep_1<<1) | pDM_FatTable->antsel_rx_keep_0;
+				ODM_AntselStatistics_88E(dm_odm, antsel_tr_mux, pPktinfo->StationID, pPhyInfo->RxPWDBAll);
+			}
+		}
+	}
+	/* Smart Antenna Debug Message------------------ */
+
+	UndecoratedSmoothedCCK =  pEntry->rssi_stat.UndecoratedSmoothedCCK;
+	UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM;
+	UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB;
+
+	if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
+		if (!isCCKrate) { /* ofdm rate */
+			if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0) {
+				RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+			} else {
+				if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]) {
+					RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+					RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
+				} else {
+					RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B];
+					RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A];
+				}
+				if ((RSSI_max - RSSI_min) < 3)
+					RSSI_Ave = RSSI_max;
+				else if ((RSSI_max - RSSI_min) < 6)
+					RSSI_Ave = RSSI_max - 1;
+				else if ((RSSI_max - RSSI_min) < 10)
+					RSSI_Ave = RSSI_max - 2;
+				else
+					RSSI_Ave = RSSI_max - 3;
+			}
+
+			/* 1 Process OFDM RSSI */
+			if (UndecoratedSmoothedOFDM <= 0) {	/*  initialize */
+				UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll;
+			} else {
+				if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) {
+					UndecoratedSmoothedOFDM =
+							(((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+							(RSSI_Ave)) / (Rx_Smooth_Factor);
+					UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1;
+				} else {
+					UndecoratedSmoothedOFDM =
+							(((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+							(RSSI_Ave)) / (Rx_Smooth_Factor);
+				}
+			}
+
+			pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0;
+
+		} else {
+			RSSI_Ave = pPhyInfo->RxPWDBAll;
+
+			/* 1 Process CCK RSSI */
+			if (UndecoratedSmoothedCCK <= 0) {	/*  initialize */
+				UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll;
+			} else {
+				if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) {
+					UndecoratedSmoothedCCK =
+							((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) +
+							pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor;
+					UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1;
+				} else {
+					UndecoratedSmoothedCCK =
+							((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) +
+							pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor;
+				}
+			}
+			pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1;
+		}
+		/* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */
+		if (pEntry->rssi_stat.ValidBit >= 64)
+			pEntry->rssi_stat.ValidBit = 64;
+		else
+			pEntry->rssi_stat.ValidBit++;
+
+		for (i = 0; i < pEntry->rssi_stat.ValidBit; i++)
+			OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0;
+
+		if (pEntry->rssi_stat.ValidBit == 64) {
+			Weighting = ((OFDM_pkt<<4) > 64) ? 64 : (OFDM_pkt<<4);
+			UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6;
+		} else {
+			if (pEntry->rssi_stat.ValidBit != 0)
+				UndecoratedSmoothedPWDB = (OFDM_pkt * UndecoratedSmoothedOFDM +
+							  (pEntry->rssi_stat.ValidBit-OFDM_pkt) *
+							  UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit;
+			else
+				UndecoratedSmoothedPWDB = 0;
+		}
+		pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK;
+		pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM;
+		pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB;
+	}
+}
+
+/*  Endianness before calling this API */
+static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm,
+					 struct odm_phy_status_info *pPhyInfo,
+					 u8 *pPhyStatus,
+					 struct odm_per_pkt_info *pPktinfo)
+{
+	odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus,
+					 pPktinfo);
+	if (dm_odm->RSSI_test) {
+		/*  Select the packets to do RSSI checking for antenna switching. */
+		if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon)
+				ODM_SwAntDivChkPerPktRssi(dm_odm, pPktinfo->StationID, pPhyInfo);
+	} else {
+		odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo);
+	}
+}
+
+void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm,
+			struct odm_phy_status_info *pPhyInfo,
+			u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo)
+{
+	ODM_PhyStatusQuery_92CSeries(dm_odm, pPhyInfo, pPhyStatus, pPktinfo);
+}
+
+/*  For future use. */
+void ODM_MacStatusQuery(struct odm_dm_struct *dm_odm, u8 *mac_stat,
+			u8 macid, bool pkt_match_bssid,
+			bool pkttoself, bool pkt_beacon)
+{
+	/*  2011/10/19 Driver team will handle in the future. */
+}
+
+enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *dm_odm,
+					   enum ODM_RF_RADIO_PATH content,
+					   enum ODM_RF_RADIO_PATH rfpath)
+{
+	ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("===>ODM_ConfigRFWithHeaderFile\n"));
+	if (dm_odm->SupportICType == ODM_RTL8188E) {
+		if (rfpath == ODM_RF_PATH_A)
+			READ_AND_CONFIG(8188E, _RadioA_1T_);
+		ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_A:Rtl8188ERadioA_1TArray\n"));
+		ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, (" ===> ODM_ConfigRFWithHeaderFile() Radio_B:Rtl8188ERadioB_1TArray\n"));
+	}
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("ODM_ConfigRFWithHeaderFile: Radio No %x\n", rfpath));
+	return HAL_STATUS_SUCCESS;
+}
+
+enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *dm_odm,
+					   enum odm_bb_config_type config_tp)
+{
+	if (dm_odm->SupportICType == ODM_RTL8188E) {
+		if (config_tp == CONFIG_BB_PHY_REG) {
+			READ_AND_CONFIG(8188E, _PHY_REG_1T_);
+		} else if (config_tp == CONFIG_BB_AGC_TAB) {
+			READ_AND_CONFIG(8188E, _AGC_TAB_1T_);
+		} else if (config_tp == CONFIG_BB_PHY_REG_PG) {
+			READ_AND_CONFIG(8188E, _PHY_REG_PG_);
+			ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+				     (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8188EPHY_REG_PGArray\n"));
+		}
+	}
+	return HAL_STATUS_SUCCESS;
+}
+
+enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *dm_odm)
+{
+	u8 result = HAL_STATUS_SUCCESS;
+	if (dm_odm->SupportICType == ODM_RTL8188E)
+		result = READ_AND_CONFIG(8188E, _MAC_REG_);
+	return result;
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_RTL8188E.c b/drivers/staging/rtl8188eu/hal/odm_RTL8188E.c
new file mode 100644
index 0000000..58410f3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_RTL8188E.c
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+
+void ODM_DIG_LowerBound_88E(struct odm_dm_struct *dm_odm)
+{
+	struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable;
+
+	if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) {
+		pDM_DigTable->rx_gain_range_min = (u8) pDM_DigTable->AntDiv_RSSI_max;
+		ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+			     ("ODM_DIG_LowerBound_88E(): pDM_DigTable->AntDiv_RSSI_max=%d\n", pDM_DigTable->AntDiv_RSSI_max));
+	}
+	/* If only one Entry connected */
+}
+
+static void odm_RX_HWAntDivInit(struct odm_dm_struct *dm_odm)
+{
+	u32	value32;
+
+	if (*(dm_odm->mp_mode) == 1) {
+		dm_odm->AntDivType = CGCS_RX_SW_ANTDIV;
+		ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /*  disable HW AntDiv */
+		ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1);  /*  1:CG, 0:CS */
+		return;
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_RX_HWAntDivInit()\n"));
+
+	/* MAC Setting */
+	value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord);
+	ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */
+	/* Pin Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0	antsel antselb by HW */
+	ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT10, 0);	/* Reg864[10]=1'b0	antsel2 by HW */
+	ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT22, 1);	/* Regb2c[22]=1'b0	disable CS/CG switch */
+	ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1);	/* Regb2c[31]=1'b1	output at CG only */
+	/* OFDM Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0);
+	/* CCK Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT7, 1); /* Fix CCK PHY status report issue */
+	ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 1); /* CCK complete HW AntDiv within 64 samples */
+	ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT);
+	ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, 0xFFFF, 0x0201);	/* antenna mapping table */
+}
+
+static void odm_TRX_HWAntDivInit(struct odm_dm_struct *dm_odm)
+{
+	u32	value32;
+
+	if (*(dm_odm->mp_mode) == 1) {
+		dm_odm->AntDivType = CGCS_RX_SW_ANTDIV;
+		ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0); /*  disable HW AntDiv */
+		ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, 0); /* Default RX   (0/1) */
+		return;
+	}
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_TRX_HWAntDivInit()\n"));
+
+	/* MAC Setting */
+	value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord);
+	ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */
+	/* Pin Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0		antsel antselb by HW */
+	ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT10, 0);	/* Reg864[10]=1'b0	antsel2 by HW */
+	ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT22, 0);	/* Regb2c[22]=1'b0	disable CS/CG switch */
+	ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT31, 1);	/* Regb2c[31]=1'b1	output at CG only */
+	/* OFDM Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0);
+	/* CCK Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT7, 1); /* Fix CCK PHY status report issue */
+	ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 1); /* CCK complete HW AntDiv within 64 samples */
+	/* Tx Settings */
+	ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 0); /* Reg80c[21]=1'b0		from TX Reg */
+	ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT);
+
+	/* antenna mapping table */
+	if (!dm_odm->bIsMPChip) { /* testchip */
+		ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT10|BIT9|BIT8, 1);	/* Reg858[10:8]=3'b001 */
+		ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT13|BIT12|BIT11, 2);	/* Reg858[13:11]=3'b010 */
+	} else { /* MPchip */
+		ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, bMaskDWord, 0x0201);	/* Reg914=3'b010, Reg915=3'b001 */
+	}
+}
+
+static void odm_FastAntTrainingInit(struct odm_dm_struct *dm_odm)
+{
+	u32	value32, i;
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+	u32	AntCombination = 2;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_FastAntTrainingInit()\n"));
+
+	if (*(dm_odm->mp_mode) == 1) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("dm_odm->AntDivType: %d\n", dm_odm->AntDivType));
+		return;
+	}
+
+	for (i = 0; i < 6; i++) {
+		dm_fat_tbl->Bssid[i] = 0;
+		dm_fat_tbl->antSumRSSI[i] = 0;
+		dm_fat_tbl->antRSSIcnt[i] = 0;
+		dm_fat_tbl->antAveRSSI[i] = 0;
+	}
+	dm_fat_tbl->TrainIdx = 0;
+	dm_fat_tbl->FAT_State = FAT_NORMAL_STATE;
+
+	/* MAC Setting */
+	value32 = ODM_GetMACReg(dm_odm, 0x4c, bMaskDWord);
+	ODM_SetMACReg(dm_odm, 0x4c, bMaskDWord, value32|(BIT23|BIT25)); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */
+	value32 = ODM_GetMACReg(dm_odm,  0x7B4, bMaskDWord);
+	ODM_SetMACReg(dm_odm, 0x7b4, bMaskDWord, value32|(BIT16|BIT17)); /* Reg7B4[16]=1 enable antenna training, Reg7B4[17]=1 enable A2 match */
+
+	/* Match MAC ADDR */
+	ODM_SetMACReg(dm_odm, 0x7b4, 0xFFFF, 0);
+	ODM_SetMACReg(dm_odm, 0x7b0, bMaskDWord, 0);
+
+	ODM_SetBBReg(dm_odm, 0x870, BIT9|BIT8, 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0		antsel antselb by HW */
+	ODM_SetBBReg(dm_odm, 0x864, BIT10, 0);	/* Reg864[10]=1'b0	antsel2 by HW */
+	ODM_SetBBReg(dm_odm, 0xb2c, BIT22, 0);	/* Regb2c[22]=1'b0	disable CS/CG switch */
+	ODM_SetBBReg(dm_odm, 0xb2c, BIT31, 1);	/* Regb2c[31]=1'b1	output at CG only */
+	ODM_SetBBReg(dm_odm, 0xca4, bMaskDWord, 0x000000a0);
+
+	/* antenna mapping table */
+	if (AntCombination == 2) {
+		if (!dm_odm->bIsMPChip) { /* testchip */
+			ODM_SetBBReg(dm_odm, 0x858, BIT10|BIT9|BIT8, 1);	/* Reg858[10:8]=3'b001 */
+			ODM_SetBBReg(dm_odm, 0x858, BIT13|BIT12|BIT11, 2);	/* Reg858[13:11]=3'b010 */
+		} else { /* MPchip */
+			ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 1);
+			ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 2);
+		}
+	} else if (AntCombination == 7) {
+		if (!dm_odm->bIsMPChip) { /* testchip */
+			ODM_SetBBReg(dm_odm, 0x858, BIT10|BIT9|BIT8, 0);	/* Reg858[10:8]=3'b000 */
+			ODM_SetBBReg(dm_odm, 0x858, BIT13|BIT12|BIT11, 1);	/* Reg858[13:11]=3'b001 */
+			ODM_SetBBReg(dm_odm, 0x878, BIT16, 0);
+			ODM_SetBBReg(dm_odm, 0x858, BIT15|BIT14, 2);	/* Reg878[0],Reg858[14:15])=3'b010 */
+			ODM_SetBBReg(dm_odm, 0x878, BIT19|BIT18|BIT17, 3);/* Reg878[3:1]=3b'011 */
+			ODM_SetBBReg(dm_odm, 0x878, BIT22|BIT21|BIT20, 4);/* Reg878[6:4]=3b'100 */
+			ODM_SetBBReg(dm_odm, 0x878, BIT25|BIT24|BIT23, 5);/* Reg878[9:7]=3b'101 */
+			ODM_SetBBReg(dm_odm, 0x878, BIT28|BIT27|BIT26, 6);/* Reg878[12:10]=3b'110 */
+			ODM_SetBBReg(dm_odm, 0x878, BIT31|BIT30|BIT29, 7);/* Reg878[15:13]=3b'111 */
+		} else { /* MPchip */
+			ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 0);
+			ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 1);
+			ODM_SetBBReg(dm_odm, 0x914, bMaskByte2, 2);
+			ODM_SetBBReg(dm_odm, 0x914, bMaskByte3, 3);
+			ODM_SetBBReg(dm_odm, 0x918, bMaskByte0, 4);
+			ODM_SetBBReg(dm_odm, 0x918, bMaskByte1, 5);
+			ODM_SetBBReg(dm_odm, 0x918, bMaskByte2, 6);
+			ODM_SetBBReg(dm_odm, 0x918, bMaskByte3, 7);
+		}
+	}
+
+	/* Default Ant Setting when no fast training */
+	ODM_SetBBReg(dm_odm, 0x80c, BIT21, 1); /* Reg80c[21]=1'b1		from TX Info */
+	ODM_SetBBReg(dm_odm, 0x864, BIT5|BIT4|BIT3, 0);	/* Default RX */
+	ODM_SetBBReg(dm_odm, 0x864, BIT8|BIT7|BIT6, 1);	/* Optional RX */
+
+	/* Enter Traing state */
+	ODM_SetBBReg(dm_odm, 0x864, BIT2|BIT1|BIT0, (AntCombination-1));	/* Reg864[2:0]=3'd6	ant combination=reg864[2:0]+1 */
+	ODM_SetBBReg(dm_odm, 0xc50, BIT7, 1);	/* RegC50[7]=1'b1		enable HW AntDiv */
+}
+
+void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *dm_odm)
+{
+	if (dm_odm->SupportICType != ODM_RTL8188E)
+		return;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_odm->AntDivType=%d\n", dm_odm->AntDivType));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_odm->bIsMPChip=%s\n", (dm_odm->bIsMPChip ? "true" : "false")));
+
+	if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)
+		odm_RX_HWAntDivInit(dm_odm);
+	else if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+		odm_TRX_HWAntDivInit(dm_odm);
+	else if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV)
+		odm_FastAntTrainingInit(dm_odm);
+}
+
+void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant)
+{
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+	u32	DefaultAnt, OptionalAnt;
+
+	if (dm_fat_tbl->RxIdleAnt != Ant) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Update Rx Idle Ant\n"));
+		if (Ant == MAIN_ANT) {
+			DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+			OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+		} else {
+			DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+			OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+		}
+
+		if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) {
+			ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, DefaultAnt);	/* Default RX */
+			ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT8|BIT7|BIT6, OptionalAnt);		/* Optional RX */
+			ODM_SetBBReg(dm_odm, ODM_REG_ANTSEL_CTRL_11N, BIT14|BIT13|BIT12, DefaultAnt);	/* Default TX */
+			ODM_SetMACReg(dm_odm, ODM_REG_RESP_TX_11N, BIT6|BIT7, DefaultAnt);	/* Resp Tx */
+		} else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) {
+			ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT5|BIT4|BIT3, DefaultAnt);	/* Default RX */
+			ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT8|BIT7|BIT6, OptionalAnt);		/* Optional RX */
+		}
+	}
+	dm_fat_tbl->RxIdleAnt = Ant;
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RxIdleAnt=%s\n", (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT"));
+	pr_info("RxIdleAnt=%s\n", (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT");
+}
+
+static void odm_UpdateTxAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant, u32 MacId)
+{
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+	u8	TargetAnt;
+
+	if (Ant == MAIN_ANT)
+		TargetAnt = MAIN_ANT_CG_TRX;
+	else
+		TargetAnt = AUX_ANT_CG_TRX;
+	dm_fat_tbl->antsel_a[MacId] = TargetAnt&BIT0;
+	dm_fat_tbl->antsel_b[MacId] = (TargetAnt&BIT1)>>1;
+	dm_fat_tbl->antsel_c[MacId] = (TargetAnt&BIT2)>>2;
+
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+		     ("Tx from TxInfo, TargetAnt=%s\n",
+		     (Ant == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT"));
+	ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+		     ("antsel_tr_mux=3'b%d%d%d\n",
+		     dm_fat_tbl->antsel_c[MacId], dm_fat_tbl->antsel_b[MacId], dm_fat_tbl->antsel_a[MacId]));
+}
+
+void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *dm_odm, u8 *pDesc, u8 macId)
+{
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+
+	if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV)) {
+		SET_TX_DESC_ANTSEL_A_88E(pDesc, dm_fat_tbl->antsel_a[macId]);
+		SET_TX_DESC_ANTSEL_B_88E(pDesc, dm_fat_tbl->antsel_b[macId]);
+		SET_TX_DESC_ANTSEL_C_88E(pDesc, dm_fat_tbl->antsel_c[macId]);
+	}
+}
+
+void ODM_AntselStatistics_88E(struct odm_dm_struct *dm_odm, u8 antsel_tr_mux, u32 MacId, u8 RxPWDBAll)
+{
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+	if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) {
+		if (antsel_tr_mux == MAIN_ANT_CG_TRX) {
+			dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll;
+			dm_fat_tbl->MainAnt_Cnt[MacId]++;
+		} else {
+			dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll;
+			dm_fat_tbl->AuxAnt_Cnt[MacId]++;
+		}
+	} else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) {
+		if (antsel_tr_mux == MAIN_ANT_CGCS_RX) {
+			dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll;
+			dm_fat_tbl->MainAnt_Cnt[MacId]++;
+		} else {
+			dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll;
+			dm_fat_tbl->AuxAnt_Cnt[MacId]++;
+		}
+	}
+}
+
+static void odm_HWAntDiv(struct odm_dm_struct *dm_odm)
+{
+	u32	i, MinRSSI = 0xFF, AntDivMaxRSSI = 0, MaxRSSI = 0, LocalMinRSSI, LocalMaxRSSI;
+	u32	Main_RSSI, Aux_RSSI;
+	u8	RxIdleAnt = 0, TargetAnt = 7;
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+	struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable;
+	struct sta_info *pEntry;
+
+	for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+		pEntry = dm_odm->pODM_StaInfo[i];
+		if (IS_STA_VALID(pEntry)) {
+			/* 2 Caculate RSSI per Antenna */
+			Main_RSSI = (dm_fat_tbl->MainAnt_Cnt[i] != 0) ? (dm_fat_tbl->MainAnt_Sum[i]/dm_fat_tbl->MainAnt_Cnt[i]) : 0;
+			Aux_RSSI = (dm_fat_tbl->AuxAnt_Cnt[i] != 0) ? (dm_fat_tbl->AuxAnt_Sum[i]/dm_fat_tbl->AuxAnt_Cnt[i]) : 0;
+			TargetAnt = (Main_RSSI >= Aux_RSSI) ? MAIN_ANT : AUX_ANT;
+			ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+				     ("MacID=%d, MainAnt_Sum=%d, MainAnt_Cnt=%d\n",
+				     i, dm_fat_tbl->MainAnt_Sum[i],
+				     dm_fat_tbl->MainAnt_Cnt[i]));
+			ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+				     ("MacID=%d, AuxAnt_Sum=%d, AuxAnt_Cnt=%d\n",
+				     i, dm_fat_tbl->AuxAnt_Sum[i], dm_fat_tbl->AuxAnt_Cnt[i]));
+			ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,
+				     ("MacID=%d, Main_RSSI= %d, Aux_RSSI= %d\n",
+				     i, Main_RSSI, Aux_RSSI));
+			/* 2 Select MaxRSSI for DIG */
+			LocalMaxRSSI = (Main_RSSI > Aux_RSSI) ? Main_RSSI : Aux_RSSI;
+			if ((LocalMaxRSSI > AntDivMaxRSSI) && (LocalMaxRSSI < 40))
+				AntDivMaxRSSI = LocalMaxRSSI;
+			if (LocalMaxRSSI > MaxRSSI)
+				MaxRSSI = LocalMaxRSSI;
+
+			/* 2 Select RX Idle Antenna */
+			if ((dm_fat_tbl->RxIdleAnt == MAIN_ANT) && (Main_RSSI == 0))
+				Main_RSSI = Aux_RSSI;
+			else if ((dm_fat_tbl->RxIdleAnt == AUX_ANT) && (Aux_RSSI == 0))
+				Aux_RSSI = Main_RSSI;
+
+			LocalMinRSSI = (Main_RSSI > Aux_RSSI) ? Aux_RSSI : Main_RSSI;
+			if (LocalMinRSSI < MinRSSI) {
+				MinRSSI = LocalMinRSSI;
+				RxIdleAnt = TargetAnt;
+			}
+			/* 2 Select TRX Antenna */
+			if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+				odm_UpdateTxAnt_88E(dm_odm, TargetAnt, i);
+		}
+		dm_fat_tbl->MainAnt_Sum[i] = 0;
+		dm_fat_tbl->AuxAnt_Sum[i] = 0;
+		dm_fat_tbl->MainAnt_Cnt[i] = 0;
+		dm_fat_tbl->AuxAnt_Cnt[i] = 0;
+	}
+
+	/* 2 Set RX Idle Antenna */
+	ODM_UpdateRxIdleAnt_88E(dm_odm, RxIdleAnt);
+
+	pDM_DigTable->AntDiv_RSSI_max = AntDivMaxRSSI;
+	pDM_DigTable->RSSI_max = MaxRSSI;
+}
+
+void ODM_AntennaDiversity_88E(struct odm_dm_struct *dm_odm)
+{
+	struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable;
+	if ((dm_odm->SupportICType != ODM_RTL8188E) || (!(dm_odm->SupportAbility & ODM_BB_ANT_DIV)))
+		return;
+	if (!dm_odm->bLinked) {
+		ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_AntennaDiversity_88E(): No Link.\n"));
+		if (dm_fat_tbl->bBecomeLinked) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn off HW AntDiv\n"));
+			ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 0);	/* RegC50[7]=1'b1		enable HW AntDiv */
+			ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 0); /* Enable CCK AntDiv */
+			if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+				ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 0); /* Reg80c[21]=1'b0		from TX Reg */
+			dm_fat_tbl->bBecomeLinked = dm_odm->bLinked;
+		}
+		return;
+	} else {
+		if (!dm_fat_tbl->bBecomeLinked) {
+			ODM_RT_TRACE(dm_odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Need to Turn on HW AntDiv\n"));
+			/* Because HW AntDiv is disabled before Link, we enable HW AntDiv after link */
+			ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT7, 1);	/* RegC50[7]=1'b1		enable HW AntDiv */
+			ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 1); /* Enable CCK AntDiv */
+			if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV)
+				ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT21, 1); /* Reg80c[21]=1'b1		from TX Info */
+			dm_fat_tbl->bBecomeLinked = dm_odm->bLinked;
+		}
+	}
+	if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV))
+		odm_HWAntDiv(dm_odm);
+}
+
+/* 3============================================================ */
+/* 3 Dynamic Primary CCA */
+/* 3============================================================ */
+
+void odm_PrimaryCCA_Init(struct odm_dm_struct *dm_odm)
+{
+	struct dyn_primary_cca *PrimaryCCA = &(dm_odm->DM_PriCCA);
+
+	PrimaryCCA->DupRTS_flag = 0;
+	PrimaryCCA->intf_flag = 0;
+	PrimaryCCA->intf_type = 0;
+	PrimaryCCA->Monitor_flag = 0;
+	PrimaryCCA->PriCCA_flag = 0;
+}
+
+bool ODM_DynamicPrimaryCCA_DupRTS(struct odm_dm_struct *dm_odm)
+{
+	struct dyn_primary_cca *PrimaryCCA = &(dm_odm->DM_PriCCA);
+
+	return	PrimaryCCA->DupRTS_flag;
+}
+
+void odm_DynamicPrimaryCCA(struct odm_dm_struct *dm_odm)
+{
+	return;
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c b/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
new file mode 100644
index 0000000..18c0533
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_RegConfig8188E.c
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+
+void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+			   u32 Data, enum ODM_RF_RADIO_PATH RF_PATH,
+			   u32 RegAddr)
+{
+    if (Addr == 0xffe) {
+		ODM_sleep_ms(50);
+	} else if (Addr == 0xfd) {
+		ODM_delay_ms(5);
+	} else if (Addr == 0xfc) {
+		ODM_delay_ms(1);
+	} else if (Addr == 0xfb) {
+		ODM_delay_us(50);
+	} else if (Addr == 0xfa) {
+		ODM_delay_us(5);
+	} else if (Addr == 0xf9) {
+		ODM_delay_us(1);
+	} else {
+		ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data);
+		/*  Add 1us delay between BB/RF register setting. */
+		ODM_delay_us(1);
+	}
+}
+
+void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data)
+{
+	u32  content = 0x1000; /*  RF_Content: radioa_txt */
+	u32 maskforPhySet = (u32)(content&0xE000);
+
+	odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_A, Addr|maskforPhySet);
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n", Addr, Data));
+}
+
+void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data)
+{
+	u32  content = 0x1001; /*  RF_Content: radiob_txt */
+	u32 maskforPhySet = (u32)(content&0xE000);
+
+	odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_B, Addr|maskforPhySet);
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioB] %08X %08X\n", Addr, Data));
+}
+
+void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data)
+{
+	ODM_Write1Byte(pDM_Odm, Addr, Data);
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data));
+}
+
+void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data)
+{
+	ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data);
+	/*  Add 1us delay between BB/RF register setting. */
+	ODM_delay_us(1);
+
+	ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE,
+		     ("===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n",
+		     Addr, Data));
+}
+
+void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+				   u32 Bitmask, u32 Data)
+{
+	if (Addr == 0xfe) {
+		ODM_sleep_ms(50);
+	} else if (Addr == 0xfd) {
+		ODM_delay_ms(5);
+	} else if (Addr == 0xfc) {
+		ODM_delay_ms(1);
+	} else if (Addr == 0xfb) {
+		ODM_delay_us(50);
+	} else if (Addr == 0xfa) {
+		ODM_delay_us(5);
+	} else if (Addr == 0xf9) {
+		ODM_delay_us(1);
+	} else{
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+			     ("===> @@@@@@@ ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n",
+			     Addr, Bitmask, Data));
+		storePwrIndexDiffRateOffset(pDM_Odm->Adapter, Addr, Bitmask, Data);
+	}
+}
+
+void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data)
+{
+	if (Addr == 0xfe) {
+		ODM_sleep_ms(50);
+	} else if (Addr == 0xfd) {
+		ODM_delay_ms(5);
+	} else if (Addr == 0xfc) {
+		ODM_delay_ms(1);
+	} else if (Addr == 0xfb) {
+		ODM_delay_us(50);
+	} else if (Addr == 0xfa) {
+		ODM_delay_us(5);
+	} else if (Addr == 0xf9) {
+		ODM_delay_us(1);
+	} else {
+		if (Addr == 0xa24)
+			pDM_Odm->RFCalibrateInfo.RegA24 = Data;
+		ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data);
+
+		/*  Add 1us delay between BB/RF register setting. */
+		ODM_delay_us(1);
+		ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE,
+			     ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n",
+			     Addr, Data));
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/odm_debug.c b/drivers/staging/rtl8188eu/hal/odm_debug.c
new file mode 100644
index 0000000..84caadd
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_debug.c
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+/*  include files */
+
+#include "odm_precomp.h"
+
+void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm)
+{
+	pDM_Odm->DebugLevel = ODM_DBG_TRACE;
+
+	pDM_Odm->DebugComponents = 0;
+}
+
+u32 GlobalDebugLevel;
diff --git a/drivers/staging/rtl8188eu/hal/odm_interface.c b/drivers/staging/rtl8188eu/hal/odm_interface.c
new file mode 100644
index 0000000..59ad5bf
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/odm_interface.c
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include "odm_precomp.h"
+/*  ODM IO Relative API. */
+
+u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	return rtw_read8(Adapter, RegAddr);
+}
+
+u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	return rtw_read16(Adapter, RegAddr);
+}
+
+u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	return rtw_read32(Adapter, RegAddr);
+}
+
+void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	rtw_write8(Adapter, RegAddr, Data);
+}
+
+void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	rtw_write16(Adapter, RegAddr, Data);
+}
+
+void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	rtw_write32(Adapter, RegAddr, Data);
+}
+
+void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	PHY_SetBBReg(Adapter, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	return PHY_QueryBBReg(Adapter, RegAddr, BitMask);
+}
+
+void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	PHY_SetBBReg(Adapter, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	return PHY_QueryBBReg(Adapter, RegAddr, BitMask);
+}
+
+void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH	eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH	eRFPath, u32 RegAddr, u32 BitMask)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	return PHY_QueryRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask);
+}
+
+/*  ODM Memory relative API. */
+void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length)
+{
+	*pPtr = rtw_zvmalloc(length);
+}
+
+/*  length could be ignored, used to detect memory leakage. */
+void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length)
+{
+	rtw_vmfree(pPtr, length);
+}
+
+s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2, u32 length)
+{
+	return _rtw_memcmp(pBuf1, pBuf2, length);
+}
+
+/*  ODM MISC relative API. */
+void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type)
+{
+}
+
+void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type)
+{
+}
+
+/*  Work item relative API. FOr MP driver only~! */
+void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem,
+			    RT_WORKITEM_CALL_BACK RtWorkItemCallback,
+			    void *pContext, const char *szID)
+{
+}
+
+void ODM_StartWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_StopWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_FreeWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_ScheduleWorkItem(void *pRtWorkItem)
+{
+}
+
+void ODM_IsWorkItemScheduled(void *pRtWorkItem)
+{
+}
+
+/*  ODM Timer relative API. */
+void ODM_StallExecution(u32 usDelay)
+{
+	rtw_udelay_os(usDelay);
+}
+
+void ODM_delay_ms(u32 ms)
+{
+	rtw_mdelay_os(ms);
+}
+
+void ODM_delay_us(u32 us)
+{
+	rtw_udelay_os(us);
+}
+
+void ODM_sleep_ms(u32 ms)
+{
+	rtw_msleep_os(ms);
+}
+
+void ODM_sleep_us(u32 us)
+{
+	rtw_usleep_os(us);
+}
+
+void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, u32 msDelay)
+{
+	_set_timer(pTimer, msDelay); /* ms */
+}
+
+void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer,
+			 void *CallBackFunc, void *pContext,
+			 const char *szID)
+{
+	struct adapter *Adapter = pDM_Odm->Adapter;
+	_init_timer(pTimer, Adapter->pnetdev, CallBackFunc, pDM_Odm);
+}
+
+void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer)
+{
+	_cancel_timer_ex(pTimer);
+}
+
+void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer)
+{
+}
+
+/*  ODM FW relative API. */
+u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum,
+		      u32 *pElementID, u32 *pCmdLen,
+		      u8 **pCmbBuffer, u8 *CmdStartSeq)
+{
+	return	true;
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
new file mode 100644
index 0000000..8c858775
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -0,0 +1,779 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+#include <rtw_ioctl_set.h>
+
+#include <rtl8188e_hal.h>
+
+#define RTL88E_MAX_H2C_BOX_NUMS		4
+#define RTL88E_MAX_CMD_LEN		7
+#define RTL88E_MESSAGE_BOX_SIZE		4
+#define RTL88E_EX_MESSAGE_BOX_SIZE	4
+
+static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num)
+{
+	u8 read_down = false;
+	int	retry_cnts = 100;
+
+	u8 valid;
+
+	do {
+		valid = rtw_read8(adapt, REG_HMETFR) & BIT(msgbox_num);
+		if (0 == valid)
+			read_down = true;
+	} while ((!read_down) && (retry_cnts--));
+
+	return read_down;
+}
+
+/*****************************************
+* H2C Msg format :
+* 0x1DF - 0x1D0
+*| 31 - 8	| 7-5	 4 - 0	|
+*| h2c_msg	|Class_ID CMD_ID	|
+*
+* Extend 0x1FF - 0x1F0
+*|31 - 0	  |
+*|ext_msg|
+******************************************/
+static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
+{
+	u8 bcmd_down = false;
+	s32 retry_cnts = 100;
+	u8 h2c_box_num;
+	u32 msgbox_addr;
+	u32 msgbox_ex_addr;
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+	u8 cmd_idx, ext_cmd_len;
+	u32 h2c_cmd = 0;
+	u32 h2c_cmd_ex = 0;
+	s32 ret = _FAIL;
+
+_func_enter_;
+
+	if (!adapt->bFWReady) {
+		DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n");
+		return ret;
+	}
+
+	if (!pCmdBuffer)
+		goto exit;
+	if (CmdLen > RTL88E_MAX_CMD_LEN)
+		goto exit;
+	if (adapt->bSurpriseRemoved)
+		goto exit;
+
+	/* pay attention to if  race condition happened in  H2C cmd setting. */
+	do {
+		h2c_box_num = haldata->LastHMEBoxNum;
+
+		if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) {
+			DBG_88E(" fw read cmd failed...\n");
+			goto exit;
+		}
+
+		*(u8 *)(&h2c_cmd) = ElementID;
+
+		if (CmdLen <= 3) {
+			memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
+		} else {
+			memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3);
+			ext_cmd_len = CmdLen-3;
+			memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, ext_cmd_len);
+
+			/* Write Ext command */
+			msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE);
+			for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) {
+				rtw_write8(adapt, msgbox_ex_addr+cmd_idx, *((u8 *)(&h2c_cmd_ex)+cmd_idx));
+			}
+		}
+		/*  Write command */
+		msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE);
+		for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) {
+			rtw_write8(adapt, msgbox_addr+cmd_idx, *((u8 *)(&h2c_cmd)+cmd_idx));
+		}
+		bcmd_down = true;
+
+		haldata->LastHMEBoxNum = (h2c_box_num+1) % RTL88E_MAX_H2C_BOX_NUMS;
+
+	} while ((!bcmd_down) && (retry_cnts--));
+
+	ret = _SUCCESS;
+
+exit:
+
+_func_exit_;
+
+	return ret;
+}
+
+u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param)
+{
+	u8 res = _SUCCESS;
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+_func_enter_;
+
+	if (haldata->fw_ractrl) {
+		;
+	} else {
+		DBG_88E("==>%s fw dont support RA\n", __func__);
+		res = _FAIL;
+	}
+
+_func_exit_;
+
+	return res;
+}
+
+u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask)
+{
+	u8 buf[3];
+	u8 res = _SUCCESS;
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+_func_enter_;
+	if (haldata->fw_ractrl) {
+		__le32 lmask;
+
+		_rtw_memset(buf, 0, 3);
+		lmask = cpu_to_le32(mask);
+		memcpy(buf, &lmask, 3);
+
+		FillH2CCmd_88E(adapt, H2C_DM_MACID_CFG, 3, buf);
+	} else {
+		DBG_88E("==>%s fw dont support RA\n", __func__);
+		res = _FAIL;
+	}
+
+_func_exit_;
+
+	return res;
+}
+
+/* bitmap[0:27] = tx_rate_bitmap */
+/* bitmap[28:31]= Rate Adaptive id */
+/* arg[0:4] = macid */
+/* arg[5] = Short GI */
+void rtl8188e_Add_RateATid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
+{
+	struct hal_data_8188e *haldata = GET_HAL_DATA(pAdapter);
+
+	u8 macid, init_rate, raid, shortGIrate = false;
+
+	macid = arg&0x1f;
+
+	raid = (bitmap>>28) & 0x0f;
+	bitmap &= 0x0fffffff;
+
+	if (rssi_level != DM_RATR_STA_INIT)
+		bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, macid, bitmap, rssi_level);
+
+	bitmap |= ((raid<<28)&0xf0000000);
+
+	init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f;
+
+	shortGIrate = (arg&BIT(5)) ? true : false;
+
+	if (shortGIrate)
+		init_rate |= BIT(6);
+
+	raid = (bitmap>>28) & 0x0f;
+
+	bitmap &= 0x0fffffff;
+
+	DBG_88E("%s=> mac_id:%d, raid:%d, ra_bitmap=0x%x, shortGIrate=0x%02x\n",
+		__func__, macid, raid, bitmap, shortGIrate);
+
+	ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv), macid, raid, bitmap, shortGIrate);
+}
+
+void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
+{
+	struct setpwrmode_parm H2CSetPwrMode;
+	struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv;
+	u8 RLBM = 0; /*  0:Min, 1:Max, 2:User define */
+_func_enter_;
+
+	DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__,
+		Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable);
+
+	switch (Mode) {
+	case PS_MODE_ACTIVE:
+		H2CSetPwrMode.Mode = 0;
+		break;
+	case PS_MODE_MIN:
+		H2CSetPwrMode.Mode = 1;
+		break;
+	case PS_MODE_MAX:
+		RLBM = 1;
+		H2CSetPwrMode.Mode = 1;
+		break;
+	case PS_MODE_DTIM:
+		RLBM = 2;
+		H2CSetPwrMode.Mode = 1;
+		break;
+	case PS_MODE_UAPSD_WMM:
+		H2CSetPwrMode.Mode = 2;
+		break;
+	default:
+		H2CSetPwrMode.Mode = 0;
+		break;
+	}
+
+	H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps<<4)&0xf0) | (RLBM & 0x0f));
+
+	H2CSetPwrMode.AwakeInterval = 1;
+
+	H2CSetPwrMode.bAllQueueUAPSD = adapt->registrypriv.uapsd_enable;
+
+	if (Mode > 0)
+		H2CSetPwrMode.PwrState = 0x00;/*  AllON(0x0C), RFON(0x04), RFOFF(0x00) */
+	else
+		H2CSetPwrMode.PwrState = 0x0C;/*  AllON(0x0C), RFON(0x04), RFOFF(0x00) */
+
+	FillH2CCmd_88E(adapt, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
+
+_func_exit_;
+}
+
+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt)
+{
+	u8 opmode, macid;
+	u16 mst_rpt = le16_to_cpu(mstatus_rpt);
+	opmode = (u8) mst_rpt;
+	macid = (u8)(mst_rpt >> 8);
+
+	DBG_88E("### %s: MStatus=%x MACID=%d\n", __func__, opmode, macid);
+	FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt);
+}
+
+static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
+{
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	u16 *fctrl;
+	u32 rate_len, pktlen;
+	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex		*cur_network = &(pmlmeinfo->network);
+	u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+
+	memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+	memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+	SetFrameSubType(pframe, WIFI_BEACON);
+
+	pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+	pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+	/* timestamp will be inserted by hardware */
+	pframe += 8;
+	pktlen += 8;
+
+	/*  beacon interval: 2 bytes */
+	memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2);
+
+	pframe += 2;
+	pktlen += 2;
+
+	/*  capability info: 2 bytes */
+	memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2);
+
+	pframe += 2;
+	pktlen += 2;
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+		pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ie);
+		memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ie), pktlen);
+
+		goto _ConstructBeacon;
+	}
+
+	/* below for ad-hoc mode */
+
+	/*  SSID */
+	pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen);
+
+	/*  supported rates... */
+	rate_len = rtw_get_rateset_len(cur_network->SupportedRates);
+	pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen);
+
+	/*  DS parameter set */
+	pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen);
+
+	if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+		u32 ATIMWindow;
+		/*  IBSS Parameter Set... */
+		ATIMWindow = 0;
+		pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen);
+	}
+
+	/* todo: ERP IE */
+
+	/*  EXTERNDED SUPPORTED RATE */
+	if (rate_len > 8)
+		pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
+
+	/* todo:HT for adhoc */
+
+_ConstructBeacon:
+
+	if ((pktlen + TXDESC_SIZE) > 512) {
+		DBG_88E("beacon frame too large\n");
+		return;
+	}
+
+	*pLength = pktlen;
+}
+
+static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength)
+{
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u16 *fctrl;
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	/*  Frame control. */
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	SetPwrMgt(fctrl);
+	SetFrameSubType(pframe, WIFI_PSPOLL);
+
+	/*  AID. */
+	SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
+
+	/*  BSSID. */
+	memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+	/*  TA. */
+	memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+
+	*pLength = 16;
+}
+
+static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
+	u32 *pLength,
+	u8 *StaAddr,
+	u8 bQoS,
+	u8 AC,
+	u8 bEosp,
+	u8 bForcePowerSave)
+{
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	u16 *fctrl;
+	u32 pktlen;
+	struct mlme_priv *pmlmepriv = &adapt->mlmepriv;
+	struct wlan_network		*cur_network = &pmlmepriv->cur_network;
+	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	fctrl = &pwlanhdr->frame_ctl;
+	*(fctrl) = 0;
+	if (bForcePowerSave)
+		SetPwrMgt(fctrl);
+
+	switch (cur_network->network.InfrastructureMode) {
+	case Ndis802_11Infrastructure:
+		SetToDs(fctrl);
+		memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
+		break;
+	case Ndis802_11APMode:
+		SetFrDs(fctrl);
+		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+		memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, myid(&(adapt->eeprompriv)), ETH_ALEN);
+		break;
+	case Ndis802_11IBSS:
+	default:
+		memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+		memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
+		memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+		break;
+	}
+
+	SetSeqNum(pwlanhdr, 0);
+
+	if (bQoS) {
+		struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr;
+
+		SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+
+		pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe;
+		SetPriority(&pwlanqoshdr->qc, AC);
+		SetEOSP(&pwlanqoshdr->qc, bEosp);
+
+		pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos);
+	} else {
+		SetFrameSubType(pframe, WIFI_DATA_NULL);
+
+		pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+	}
+
+	*pLength = pktlen;
+}
+
+static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID)
+{
+	struct rtw_ieee80211_hdr	*pwlanhdr;
+	u16 *fctrl;
+	u8 *mac, *bssid;
+	u32 pktlen;
+	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex	*cur_network = &(pmlmeinfo->network);
+
+	pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+	mac = myid(&(adapt->eeprompriv));
+	bssid = cur_network->MacAddress;
+
+	fctrl = &(pwlanhdr->frame_ctl);
+	*(fctrl) = 0;
+	memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+	memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+	memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
+
+	SetSeqNum(pwlanhdr, 0);
+	SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+	pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+	pframe += pktlen;
+
+	if (cur_network->IELength > MAX_IE_SZ)
+		return;
+
+	memcpy(pframe, cur_network->IEs, cur_network->IELength);
+	pframe += cur_network->IELength;
+	pktlen += cur_network->IELength;
+
+	*pLength = pktlen;
+}
+
+/*  To check if reserved page content is destroyed by beacon beacuse beacon is too large. */
+/*  2010.06.23. Added by tynli. */
+void CheckFwRsvdPageContent(struct adapter *Adapter)
+{
+}
+
+/*  */
+/*  Description: Fill the reserved packets that FW will use to RSVD page. */
+/*			Now we just send 4 types packet to rsvd page. */
+/*			(1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
+/*	Input: */
+/*	    bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
+/*						so we need to set the packet length to total lengh. */
+/*			      true: At the second time, we should send the first packet (default:beacon) */
+/*						to Hw again and set the lengh in descriptor to the real beacon lengh. */
+/*  2009.10.15 by tynli. */
+static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
+{
+	struct hal_data_8188e *haldata;
+	struct xmit_frame	*pmgntframe;
+	struct pkt_attrib	*pattrib;
+	struct xmit_priv *pxmitpriv;
+	struct mlme_ext_priv *pmlmeext;
+	struct mlme_ext_info	*pmlmeinfo;
+	u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
+	u32 NullDataLength, QosNullLength;
+	u8 *ReservedPagePacket;
+	u8 PageNum, PageNeed, TxDescLen;
+	u16 BufIndex;
+	u32 TotalPacketLen;
+	struct rsvdpage_loc RsvdPageLoc;
+
+	DBG_88E("%s\n", __func__);
+	ReservedPagePacket = (u8 *)rtw_zmalloc(1000);
+	if (ReservedPagePacket == NULL) {
+		DBG_88E("%s: alloc ReservedPagePacket fail!\n", __func__);
+		return;
+	}
+
+	haldata = GET_HAL_DATA(adapt);
+	pxmitpriv = &adapt->xmitpriv;
+	pmlmeext = &adapt->mlmeextpriv;
+	pmlmeinfo = &pmlmeext->mlmext_info;
+
+	TxDescLen = TXDESC_SIZE;
+	PageNum = 0;
+
+	/* 3 (1) beacon * 2 pages */
+	BufIndex = TXDESC_OFFSET;
+	ConstructBeacon(adapt, &ReservedPagePacket[BufIndex], &BeaconLength);
+
+	/*  When we count the first page size, we need to reserve description size for the RSVD */
+	/*  packet, it will be filled in front of the packet in TXPKTBUF. */
+	PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
+	/*  To reserved 2 pages for beacon buffer. 2010.06.24. */
+	if (PageNeed == 1)
+		PageNeed += 1;
+	PageNum += PageNeed;
+	haldata->FwRsvdPageStartOffset = PageNum;
+
+	BufIndex += PageNeed*128;
+
+	/* 3 (2) ps-poll *1 page */
+	RsvdPageLoc.LocPsPoll = PageNum;
+	ConstructPSPoll(adapt, &ReservedPagePacket[BufIndex], &PSPollLength);
+	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
+
+	PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
+	PageNum += PageNeed;
+
+	BufIndex += PageNeed*128;
+
+	/* 3 (3) null data * 1 page */
+	RsvdPageLoc.LocNullData = PageNum;
+	ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), false, 0, 0, false);
+	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
+
+	PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
+	PageNum += PageNeed;
+
+	BufIndex += PageNeed*128;
+
+	/* 3 (4) probe response * 1page */
+	RsvdPageLoc.LocProbeRsp = PageNum;
+	ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), false);
+	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
+
+	PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
+	PageNum += PageNeed;
+
+	BufIndex += PageNeed*128;
+
+	/* 3 (5) Qos null data */
+	RsvdPageLoc.LocQosNull = PageNum;
+	ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex],
+				  &QosNullLength, get_my_bssid(&pmlmeinfo->network), true, 0, 0, false);
+	rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
+
+	PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
+	PageNum += PageNeed;
+
+	TotalPacketLen = BufIndex + QosNullLength;
+	pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+	if (pmgntframe == NULL)
+		goto exit;
+
+	/*  update attribute */
+	pattrib = &pmgntframe->attrib;
+	update_mgntframe_attrib(adapt, pattrib);
+	pattrib->qsel = 0x10;
+	pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
+	pattrib->pktlen = pattrib->last_txcmdsz;
+	memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
+
+	rtw_hal_mgnt_xmit(adapt, pmgntframe);
+
+	DBG_88E("%s: Set RSVD page location to Fw\n", __func__);
+	FillH2CCmd_88E(adapt, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
+
+exit:
+	kfree(ReservedPagePacket);
+}
+
+void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
+{
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+	struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	bool	bSendBeacon = false;
+	bool	bcn_valid = false;
+	u8 DLBcnCount = 0;
+	u32 poll = 0;
+
+_func_enter_;
+
+	DBG_88E("%s mstatus(%x)\n", __func__, mstatus);
+
+	if (mstatus == 1) {
+		/*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
+		/*  Suggested by filen. Added by tynli. */
+		rtw_write16(adapt, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
+		/*  Do not set TSF again here or vWiFi beacon DMA INT will not work. */
+
+		/* Set REG_CR bit 8. DMA beacon by SW. */
+		haldata->RegCR_1 |= BIT0;
+		rtw_write8(adapt,  REG_CR+1, haldata->RegCR_1);
+
+		/*  Disable Hw protection for a time which revserd for Hw sending beacon. */
+		/*  Fix download reserved page packet fail that access collision with the protection time. */
+		/*  2010.05.11. Added by tynli. */
+		rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)&(~BIT(3)));
+		rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)|BIT(4));
+
+		if (haldata->RegFwHwTxQCtrl&BIT6) {
+			DBG_88E("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n");
+			bSendBeacon = true;
+		}
+
+		/*  Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */
+		rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl&(~BIT6)));
+		haldata->RegFwHwTxQCtrl &= (~BIT6);
+
+		/*  Clear beacon valid check bit. */
+		rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
+		DLBcnCount = 0;
+		poll = 0;
+		do {
+			/*  download rsvd page. */
+			SetFwRsvdPagePkt(adapt, false);
+			DLBcnCount++;
+			do {
+				rtw_yield_os();
+				/* rtw_mdelay_os(10); */
+				/*  check rsvd page download OK. */
+				rtw_hal_get_hwreg(adapt, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid));
+				poll++;
+			} while (!bcn_valid && (poll%10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
+		} while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
+
+		if (adapt->bSurpriseRemoved || adapt->bDriverStopped)
+			;
+		else if (!bcn_valid)
+			DBG_88E("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
+		else
+			DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll);
+		/*  */
+		/*  We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */
+		/*  becuase we need to free the Tx BCN Desc which is used by the first reserved page packet. */
+		/*  At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return */
+		/*  the beacon TCB in the following code. 2011.11.23. by tynli. */
+		/*  */
+
+		/*  Enable Bcn */
+		rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)|BIT(3));
+		rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL)&(~BIT(4)));
+
+		/*  To make sure that if there exists an adapter which would like to send beacon. */
+		/*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
+		/*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
+		/*  the beacon cannot be sent by HW. */
+		/*  2010.06.23. Added by tynli. */
+		if (bSendBeacon) {
+			rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl|BIT6));
+			haldata->RegFwHwTxQCtrl |= BIT6;
+		}
+
+		/*  Update RSVD page location H2C to Fw. */
+		if (bcn_valid) {
+			rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL);
+			DBG_88E("Set RSVD page location to Fw.\n");
+		}
+
+		/*  Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */
+		/*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
+		haldata->RegCR_1 &= (~BIT0);
+		rtw_write8(adapt,  REG_CR+1, haldata->RegCR_1);
+	}
+_func_exit_;
+}
+
+void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state)
+{
+#ifdef CONFIG_88EU_P2P
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+	struct wifidirect_info	*pwdinfo = &(adapt->wdinfo);
+	struct P2P_PS_Offload_t	*p2p_ps_offload = &haldata->p2p_ps_offload;
+	u8 i;
+
+_func_enter_;
+
+	switch (p2p_ps_state) {
+	case P2P_PS_DISABLE:
+		DBG_88E("P2P_PS_DISABLE\n");
+		_rtw_memset(p2p_ps_offload, 0, 1);
+		break;
+	case P2P_PS_ENABLE:
+		DBG_88E("P2P_PS_ENABLE\n");
+		/*  update CTWindow value. */
+		if (pwdinfo->ctwindow > 0) {
+			p2p_ps_offload->CTWindow_En = 1;
+			rtw_write8(adapt, REG_P2P_CTWIN, pwdinfo->ctwindow);
+		}
+
+		/*  hw only support 2 set of NoA */
+		for (i = 0; i < pwdinfo->noa_num; i++) {
+			/*  To control the register setting for which NOA */
+			rtw_write8(adapt, REG_NOA_DESC_SEL, (i << 4));
+			if (i == 0)
+				p2p_ps_offload->NoA0_En = 1;
+			else
+				p2p_ps_offload->NoA1_En = 1;
+
+			/*  config P2P NoA Descriptor Register */
+			rtw_write32(adapt, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]);
+			rtw_write32(adapt, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]);
+			rtw_write32(adapt, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]);
+			rtw_write8(adapt, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]);
+		}
+
+		if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) {
+			/*  rst p2p circuit */
+			rtw_write8(adapt, REG_DUAL_TSF_RST, BIT(4));
+
+			p2p_ps_offload->Offload_En = 1;
+
+			if (pwdinfo->role == P2P_ROLE_GO) {
+				p2p_ps_offload->role = 1;
+				p2p_ps_offload->AllStaSleep = 0;
+			} else {
+				p2p_ps_offload->role = 0;
+			}
+
+			p2p_ps_offload->discovery = 0;
+		}
+		break;
+	case P2P_PS_SCAN:
+		DBG_88E("P2P_PS_SCAN\n");
+		p2p_ps_offload->discovery = 1;
+		break;
+	case P2P_PS_SCAN_DONE:
+		DBG_88E("P2P_PS_SCAN_DONE\n");
+		p2p_ps_offload->discovery = 0;
+		pwdinfo->p2p_ps_state = P2P_PS_ENABLE;
+		break;
+	default:
+		break;
+	}
+
+	FillH2CCmd_88E(adapt, H2C_PS_P2P_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+#endif
+
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
new file mode 100644
index 0000000..9c2e7a2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*  */
+/*  Description: */
+/*  */
+/*  This file is for 92CE/92CU dynamic mechanism only */
+/*  */
+/*  */
+/*  */
+#define _RTL8188E_DM_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8188e_hal.h>
+
+static void dm_CheckStatistics(struct adapter *Adapter)
+{
+}
+
+/*  Initialize GPIO setting registers */
+static void dm_InitGPIOSetting(struct adapter *Adapter)
+{
+	u8	tmp1byte;
+
+	tmp1byte = rtw_read8(Adapter, REG_GPIO_MUXCFG);
+	tmp1byte &= (GPIOSEL_GPIO | ~GPIOSEL_ENBT);
+
+	rtw_write8(Adapter, REG_GPIO_MUXCFG, tmp1byte);
+}
+
+/*  */
+/*  functions */
+/*  */
+static void Init_ODM_ComInfo_88E(struct adapter *Adapter)
+{
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &hal_data->dmpriv;
+	struct odm_dm_struct *dm_odm = &(hal_data->odmpriv);
+	u8 cut_ver, fab_ver;
+
+	/*  Init Value */
+	_rtw_memset(dm_odm, 0, sizeof(dm_odm));
+
+	dm_odm->Adapter = Adapter;
+
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PLATFORM, ODM_CE);
+
+	if (Adapter->interface_type == RTW_GSPI)
+		ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, ODM_ITRF_SDIO);
+	else
+		ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, Adapter->interface_type);/* RTL871X_HCI_TYPE */
+
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8188E);
+
+	fab_ver = ODM_TSMC;
+	cut_ver = ODM_CUT_A;
+
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_FAB_VER, fab_ver);
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_CUT_VER, cut_ver);
+
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(hal_data->VersionID));
+
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PATCH_ID, hal_data->CustomerID);
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec);
+
+
+	if (hal_data->rf_type == RF_1T1R)
+		ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R);
+	else if (hal_data->rf_type == RF_2T2R)
+		ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R);
+	else if (hal_data->rf_type == RF_1T2R)
+		ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R);
+
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType);
+
+	pdmpriv->InitODMFlag =	ODM_RF_CALIBRATION |
+				ODM_RF_TX_PWR_TRACK;
+
+	ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag);
+}
+
+static void Update_ODM_ComInfo_88E(struct adapter *Adapter)
+{
+	struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+	struct mlme_priv	*pmlmepriv = &Adapter->mlmepriv;
+	struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+	struct odm_dm_struct *dm_odm = &(hal_data->odmpriv);
+	struct dm_priv	*pdmpriv = &hal_data->dmpriv;
+	int i;
+
+	pdmpriv->InitODMFlag =	ODM_BB_DIG |
+				ODM_BB_RA_MASK |
+				ODM_BB_DYNAMIC_TXPWR |
+				ODM_BB_FA_CNT |
+				ODM_BB_RSSI_MONITOR |
+				ODM_BB_CCK_PD |
+				ODM_BB_PWR_SAVE |
+				ODM_MAC_EDCA_TURBO |
+				ODM_RF_CALIBRATION |
+				ODM_RF_TX_PWR_TRACK;
+	if (hal_data->AntDivCfg)
+		pdmpriv->InitODMFlag |= ODM_BB_ANT_DIV;
+
+	if (Adapter->registrypriv.mp_mode == 1) {
+		pdmpriv->InitODMFlag =	ODM_RF_CALIBRATION |
+					ODM_RF_TX_PWR_TRACK;
+	}
+
+	ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag);
+
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_TX_UNI, &(Adapter->xmitpriv.tx_bytes));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_RX_UNI, &(Adapter->recvpriv.rx_bytes));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_WM_MODE, &(pmlmeext->cur_wireless_mode));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_CHNL_OFFSET, &(hal_data->nCur40MhzPrimeSC));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_MODE, &(Adapter->securitypriv.dot11PrivacyAlgrthm));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_BW, &(hal_data->CurrentChannelBW));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_CHNL, &(hal_data->CurrentChannel));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_NET_CLOSED, &(Adapter->net_closed));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_MP_MODE, &(Adapter->registrypriv.mp_mode));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SCAN, &(pmlmepriv->bScanInProcess));
+	ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_POWER_SAVING, &(pwrctrlpriv->bpower_saving));
+	ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType);
+
+	for (i = 0; i < NUM_STA; i++)
+		ODM_CmnInfoPtrArrayHook(dm_odm, ODM_CMNINFO_STA_STATUS, i, NULL);
+}
+
+void rtl8188e_InitHalDm(struct adapter *Adapter)
+{
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &hal_data->dmpriv;
+	struct odm_dm_struct *dm_odm = &(hal_data->odmpriv);
+
+	dm_InitGPIOSetting(Adapter);
+	pdmpriv->DM_Type = DM_Type_ByDriver;
+	pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE;
+	Update_ODM_ComInfo_88E(Adapter);
+	ODM_DMInit(dm_odm);
+	Adapter->fix_rate = 0xFF;
+}
+
+void rtl8188e_HalDmWatchDog(struct adapter *Adapter)
+{
+	bool fw_cur_in_ps = false;
+	bool fw_ps_awake = true;
+	u8 hw_init_completed = false;
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+
+	_func_enter_;
+	hw_init_completed = Adapter->hw_init_completed;
+
+	if (!hw_init_completed)
+		goto skip_dm;
+
+	fw_cur_in_ps = Adapter->pwrctrlpriv.bFwCurrentInPSMode;
+	rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&fw_ps_awake));
+
+	/*  Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */
+	/*  modifed by thomas. 2011.06.11. */
+	if (Adapter->wdinfo.p2p_ps_mode)
+		fw_ps_awake = false;
+
+	if (hw_init_completed && ((!fw_cur_in_ps) && fw_ps_awake)) {
+		/*  Calculate Tx/Rx statistics. */
+		dm_CheckStatistics(Adapter);
+
+	_func_exit_;
+	}
+
+	/* ODM */
+	if (hw_init_completed) {
+		struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+		u8 bLinked = false;
+
+		if ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) ||
+		    (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE))) {
+			if (Adapter->stapriv.asoc_sta_count > 2)
+				bLinked = true;
+		} else {/* Station mode */
+			if (check_fwstate(pmlmepriv, _FW_LINKED))
+				bLinked = true;
+		}
+
+		ODM_CmnInfoUpdate(&hal_data->odmpriv, ODM_CMNINFO_LINK, bLinked);
+		ODM_DMWatchdog(&hal_data->odmpriv);
+	}
+skip_dm:
+	/*  Check GPIO to determine current RF on/off and Pbc status. */
+	/*  Check Hardware Radio ON/OFF or not */
+	return;
+}
+
+void rtl8188e_init_dm_priv(struct adapter *Adapter)
+{
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &hal_data->dmpriv;
+	struct odm_dm_struct *podmpriv = &hal_data->odmpriv;
+
+	_rtw_memset(pdmpriv, 0, sizeof(struct dm_priv));
+	Init_ODM_ComInfo_88E(Adapter);
+	ODM_InitDebugSetting(podmpriv);
+}
+
+void rtl8188e_deinit_dm_priv(struct adapter *Adapter)
+{
+}
+
+/*  Add new function to reset the state of antenna diversity before link. */
+/*  Compare RSSI for deciding antenna */
+void AntDivCompare8188E(struct adapter *Adapter, struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src)
+{
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+
+	if (0 != hal_data->AntDivCfg) {
+		/* select optimum_antenna for before linked =>For antenna diversity */
+		if (dst->Rssi >=  src->Rssi) {/* keep org parameter */
+			src->Rssi = dst->Rssi;
+			src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna;
+		}
+	}
+}
+
+/*  Add new function to reset the state of antenna diversity before link. */
+u8 AntDivBeforeLink8188E(struct adapter *Adapter)
+{
+	struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter);
+	struct odm_dm_struct *dm_odm = &hal_data->odmpriv;
+	struct sw_ant_switch *dm_swat_tbl = &dm_odm->DM_SWAT_Table;
+	struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv);
+
+	/*  Condition that does not need to use antenna diversity. */
+	if (hal_data->AntDivCfg == 0)
+		return false;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED))
+		return false;
+
+	if (dm_swat_tbl->SWAS_NoLink_State == 0) {
+		/* switch channel */
+		dm_swat_tbl->SWAS_NoLink_State = 1;
+		dm_swat_tbl->CurAntenna = (dm_swat_tbl->CurAntenna == Antenna_A) ? Antenna_B : Antenna_A;
+
+		rtw_antenna_select_cmd(Adapter, dm_swat_tbl->CurAntenna, false);
+		return true;
+	} else {
+		dm_swat_tbl->SWAS_NoLink_State = 0;
+		return false;
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
new file mode 100644
index 0000000..292ba62
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -0,0 +1,2378 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _HAL_INIT_C_
+
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+#include <rtl8188e_hal.h>
+
+#include <rtw_iol.h>
+
+#include <usb_ops.h>
+
+static void iol_mode_enable(struct adapter *padapter, u8 enable)
+{
+	u8 reg_0xf0 = 0;
+
+	if (enable) {
+		/* Enable initial offload */
+		reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG);
+		rtw_write8(padapter, REG_SYS_CFG, reg_0xf0|SW_OFFLOAD_EN);
+
+		if (!padapter->bFWReady) {
+			DBG_88E("bFWReady == false call reset 8051...\n");
+			_8051Reset88E(padapter);
+		}
+
+	} else {
+		/* disable initial offload */
+		reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG);
+		rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN);
+	}
+}
+
+static s32 iol_execute(struct adapter *padapter, u8 control)
+{
+	s32 status = _FAIL;
+	u8 reg_0x88 = 0;
+	u32 start = 0, passing_time = 0;
+
+	control = control&0x0f;
+	reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0);
+	rtw_write8(padapter, REG_HMEBOX_E0,  reg_0x88|control);
+
+	start = rtw_get_current_time();
+	while ((reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0)) & control &&
+	       (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
+		;
+	}
+
+	reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0);
+	status = (reg_0x88 & control) ? _FAIL : _SUCCESS;
+	if (reg_0x88 & control<<4)
+		status = _FAIL;
+	return status;
+}
+
+static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
+{
+	s32 rst = _SUCCESS;
+	iol_mode_enable(padapter, 1);
+	rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+	rst = iol_execute(padapter, CMD_INIT_LLT);
+	iol_mode_enable(padapter, 0);
+	return rst;
+}
+
+static void
+efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8  *pbuf)
+{
+	u8 *efuseTbl = NULL;
+	u8 rtemp8;
+	u16	eFuse_Addr = 0;
+	u8 offset, wren;
+	u16	i, j;
+	u16	**eFuseWord = NULL;
+	u16	efuse_utilized = 0;
+	u8 u1temp = 0;
+
+	efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E);
+	if (efuseTbl == NULL) {
+		DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
+		goto exit;
+	}
+
+	eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+	if (eFuseWord == NULL) {
+		DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
+		goto exit;
+	}
+
+	/*  0. Refresh efuse init map as all oxFF. */
+	for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
+		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+			eFuseWord[i][j] = 0xFFFF;
+
+	/*  */
+	/*  1. Read the first byte to check if efuse is empty!!! */
+	/*  */
+	/*  */
+	rtemp8 = *(phymap+eFuse_Addr);
+	if (rtemp8 != 0xFF) {
+		efuse_utilized++;
+		eFuse_Addr++;
+	} else {
+		DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8);
+		goto exit;
+	}
+
+	/*  */
+	/*  2. Read real efuse content. Filter PG header and every section data. */
+	/*  */
+	while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+		/*  Check PG header for section num. */
+		if ((rtemp8 & 0x1F) == 0x0F) {		/* extended header */
+			u1temp = ((rtemp8 & 0xE0) >> 5);
+			rtemp8 = *(phymap+eFuse_Addr);
+			if ((rtemp8 & 0x0F) == 0x0F) {
+				eFuse_Addr++;
+				rtemp8 = *(phymap+eFuse_Addr);
+
+				if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
+					eFuse_Addr++;
+				continue;
+			} else {
+				offset = ((rtemp8 & 0xF0) >> 1) | u1temp;
+				wren = (rtemp8 & 0x0F);
+				eFuse_Addr++;
+			}
+		} else {
+			offset = ((rtemp8 >> 4) & 0x0f);
+			wren = (rtemp8 & 0x0f);
+		}
+
+		if (offset < EFUSE_MAX_SECTION_88E) {
+			/*  Get word enable value from PG header */
+			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+				/*  Check word enable condition in the section */
+				if (!(wren & 0x01)) {
+					rtemp8 = *(phymap+eFuse_Addr);
+					eFuse_Addr++;
+					efuse_utilized++;
+					eFuseWord[offset][i] = (rtemp8 & 0xff);
+					if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+						break;
+					rtemp8 = *(phymap+eFuse_Addr);
+					eFuse_Addr++;
+					efuse_utilized++;
+					eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00);
+
+					if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+						break;
+				}
+				wren >>= 1;
+			}
+		}
+		/*  Read next PG header */
+		rtemp8 = *(phymap+eFuse_Addr);
+
+		if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+			efuse_utilized++;
+			eFuse_Addr++;
+		}
+	}
+
+	/*  */
+	/*  3. Collect 16 sections and 4 word unit into Efuse map. */
+	/*  */
+	for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
+		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+			efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
+			efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
+		}
+	}
+
+	/*  */
+	/*  4. Copy from Efuse map to output pointer memory!!! */
+	/*  */
+	for (i = 0; i < _size_byte; i++)
+		pbuf[i] = efuseTbl[_offset+i];
+
+	/*  */
+	/*  5. Calculate Efuse utilization. */
+	/*  */
+
+exit:
+	kfree(efuseTbl);
+
+	if (eFuseWord)
+		rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+}
+
+static void efuse_read_phymap_from_txpktbuf(
+	struct adapter  *adapter,
+	int bcnhead,	/* beacon head, where FW store len(2-byte) and efuse physical map. */
+	u8 *content,	/* buffer to store efuse physical map */
+	u16 *size	/* for efuse content: the max byte to read. will update to byte read */
+	)
+{
+	u16 dbg_addr = 0;
+	u32 start  = 0, passing_time = 0;
+	u8 reg_0x143 = 0;
+	u32 lo32 = 0, hi32 = 0;
+	u16 len = 0, count = 0;
+	int i = 0;
+	u16 limit = *size;
+
+	u8 *pos = content;
+
+	if (bcnhead < 0) /* if not valid */
+		bcnhead = rtw_read8(adapter, REG_TDECTRL+1);
+
+	DBG_88E("%s bcnhead:%d\n", __func__, bcnhead);
+
+	rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
+
+	dbg_addr = bcnhead*128/8; /* 8-bytes addressing */
+
+	while (1) {
+		rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr+i);
+
+		rtw_write8(adapter, REG_TXPKTBUF_DBG, 0);
+		start = rtw_get_current_time();
+		while (!(reg_0x143 = rtw_read8(adapter, REG_TXPKTBUF_DBG)) &&
+		       (passing_time = rtw_get_passing_time_ms(start)) < 1000) {
+			DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, rtw_read8(adapter, 0x106));
+			rtw_usleep_os(100);
+		}
+
+		lo32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L);
+		hi32 = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H);
+
+		if (i == 0) {
+			u8 lenc[2];
+			u16 lenbak, aaabak;
+			u16 aaa;
+			lenc[0] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L);
+			lenc[1] = rtw_read8(adapter, REG_PKTBUF_DBG_DATA_L+1);
+
+			aaabak = le16_to_cpup((__le16 *)lenc);
+			lenbak = le16_to_cpu(*((__le16 *)lenc));
+			aaa = le16_to_cpup((__le16 *)&lo32);
+			len = le16_to_cpu(*((__le16 *)&lo32));
+
+			limit = (len-2 < limit) ? len-2 : limit;
+
+			DBG_88E("%s len:%u, lenbak:%u, aaa:%u, aaabak:%u\n", __func__, len, lenbak, aaa, aaabak);
+
+			memcpy(pos, ((u8 *)&lo32)+2, (limit >= count+2) ? 2 : limit-count);
+			count += (limit >= count+2) ? 2 : limit-count;
+			pos = content+count;
+
+		} else {
+			memcpy(pos, ((u8 *)&lo32), (limit >= count+4) ? 4 : limit-count);
+			count += (limit >= count+4) ? 4 : limit-count;
+			pos = content+count;
+		}
+
+		if (limit > count && len-2 > count) {
+			memcpy(pos, (u8 *)&hi32, (limit >= count+4) ? 4 : limit-count);
+			count += (limit >= count+4) ? 4 : limit-count;
+			pos = content+count;
+		}
+
+		if (limit <= count || len-2 <= count)
+			break;
+		i++;
+	}
+	rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS);
+	DBG_88E("%s read count:%u\n", __func__, count);
+	*size = count;
+}
+
+static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map)
+{
+	s32 status = _FAIL;
+	u8 physical_map[512];
+	u16 size = 512;
+
+	rtw_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+	_rtw_memset(physical_map, 0xFF, 512);
+	rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
+	status = iol_execute(padapter, CMD_READ_EFUSE_MAP);
+	if (status == _SUCCESS)
+		efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size);
+	efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map);
+	return status;
+}
+
+s32 rtl8188e_iol_efuse_patch(struct adapter *padapter)
+{
+	s32	result = _SUCCESS;
+
+	DBG_88E("==> %s\n", __func__);
+	if (rtw_IOL_applied(padapter)) {
+		iol_mode_enable(padapter, 1);
+		result = iol_execute(padapter, CMD_READ_EFUSE_MAP);
+		if (result == _SUCCESS)
+			result = iol_execute(padapter, CMD_EFUSE_PATCH);
+
+		iol_mode_enable(padapter, 0);
+	}
+	return result;
+}
+
+static s32 iol_ioconfig(struct adapter *padapter, u8 iocfg_bndy)
+{
+	s32 rst = _SUCCESS;
+
+	rtw_write8(padapter, REG_TDECTRL+1, iocfg_bndy);
+	rst = iol_execute(padapter, CMD_IOCONFIG);
+	return rst;
+}
+
+static int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt)
+{
+	struct pkt_attrib *pattrib = &xmit_frame->attrib;
+	u8 i;
+	int ret = _FAIL;
+
+	if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS)
+		goto exit;
+	if (rtw_usb_bulk_size_boundary(adapter, TXDESC_SIZE+pattrib->last_txcmdsz)) {
+		if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS)
+			goto exit;
+	}
+
+	dump_mgntframe_and_wait(adapter, xmit_frame, max_wating_ms);
+
+	iol_mode_enable(adapter, 1);
+	for (i = 0; i < bndy_cnt; i++) {
+		u8 page_no = 0;
+		page_no = i*2;
+		ret = iol_ioconfig(adapter, page_no);
+		if (ret != _SUCCESS)
+			break;
+	}
+	iol_mode_enable(adapter, 0);
+exit:
+	/* restore BCN_HEAD */
+	rtw_write8(adapter, REG_TDECTRL+1, 0);
+	return ret;
+}
+
+void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len)
+{
+	u32 fifo_data, reg_140;
+	u32 addr, rstatus, loop = 0;
+	u16 data_cnts = (data_len/8)+1;
+	u8 *pbuf = rtw_zvmalloc(data_len+10);
+	DBG_88E("###### %s ######\n", __func__);
+
+	rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT);
+	if (pbuf) {
+		for (addr = 0; addr < data_cnts; addr++) {
+			rtw_write32(Adapter, 0x140, addr);
+			rtw_usleep_os(2);
+			loop = 0;
+			do {
+				rstatus = (reg_140 = rtw_read32(Adapter, REG_PKTBUF_DBG_CTRL)&BIT24);
+				if (rstatus) {
+					fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_L);
+					memcpy(pbuf+(addr*8), &fifo_data, 4);
+
+					fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_H);
+					memcpy(pbuf+(addr*8+4), &fifo_data, 4);
+				}
+				rtw_usleep_os(2);
+			} while (!rstatus && (loop++ < 10));
+		}
+		rtw_IOL_cmd_buf_dump(Adapter, data_len, pbuf);
+		rtw_vmfree(pbuf, data_len+10);
+	}
+	DBG_88E("###### %s ######\n", __func__);
+}
+
+static void _FWDownloadEnable(struct adapter *padapter, bool enable)
+{
+	u8 tmp;
+
+	if (enable) {
+		/*  MCU firmware download enable. */
+		tmp = rtw_read8(padapter, REG_MCUFWDL);
+		rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01);
+
+		/*  8051 reset */
+		tmp = rtw_read8(padapter, REG_MCUFWDL+2);
+		rtw_write8(padapter, REG_MCUFWDL+2, tmp&0xf7);
+	} else {
+		/*  MCU firmware download disable. */
+		tmp = rtw_read8(padapter, REG_MCUFWDL);
+		rtw_write8(padapter, REG_MCUFWDL, tmp&0xfe);
+
+		/*  Reserved for fw extension. */
+		rtw_write8(padapter, REG_MCUFWDL+1, 0x00);
+	}
+}
+
+#define MAX_REG_BOLCK_SIZE	196
+
+static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize)
+{
+	int ret = _SUCCESS;
+	u32	blockSize_p1 = 4;	/*  (Default) Phase #1 : PCI muse use 4-byte write to download FW */
+	u32	blockSize_p2 = 8;	/*  Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */
+	u32	blockSize_p3 = 1;	/*  Phase #3 : Use 1-byte, the remnant of FW image. */
+	u32	blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0;
+	u32	remainSize_p1 = 0, remainSize_p2 = 0;
+	u8 *bufferPtr	= (u8 *)buffer;
+	u32	i = 0, offset = 0;
+
+	blockSize_p1 = MAX_REG_BOLCK_SIZE;
+
+	/* 3 Phase #1 */
+	blockCount_p1 = buffSize / blockSize_p1;
+	remainSize_p1 = buffSize % blockSize_p1;
+
+	if (blockCount_p1) {
+		RT_TRACE(_module_hal_init_c_, _drv_notice_,
+			 ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) blockCount_p1(%d) remainSize_p1(%d)\n",
+			 buffSize, blockSize_p1, blockCount_p1, remainSize_p1));
+	}
+
+	for (i = 0; i < blockCount_p1; i++) {
+		ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1));
+		if (ret == _FAIL)
+			goto exit;
+	}
+
+	/* 3 Phase #2 */
+	if (remainSize_p1) {
+		offset = blockCount_p1 * blockSize_p1;
+
+		blockCount_p2 = remainSize_p1/blockSize_p2;
+		remainSize_p2 = remainSize_p1%blockSize_p2;
+
+		if (blockCount_p2) {
+				RT_TRACE(_module_hal_init_c_, _drv_notice_,
+					 ("_BlockWrite: [P2] buffSize_p2(%d) blockSize_p2(%d) blockCount_p2(%d) remainSize_p2(%d)\n",
+					 (buffSize-offset), blockSize_p2 , blockCount_p2, remainSize_p2));
+		}
+
+		for (i = 0; i < blockCount_p2; i++) {
+			ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i*blockSize_p2), blockSize_p2, (bufferPtr + offset + i*blockSize_p2));
+
+			if (ret == _FAIL)
+				goto exit;
+		}
+	}
+
+	/* 3 Phase #3 */
+	if (remainSize_p2) {
+		offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2);
+
+		blockCount_p3 = remainSize_p2 / blockSize_p3;
+
+		RT_TRACE(_module_hal_init_c_, _drv_notice_,
+			 ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) blockCount_p3(%d)\n",
+			 (buffSize-offset), blockSize_p3, blockCount_p3));
+
+		for (i = 0; i < blockCount_p3; i++) {
+			ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i));
+
+			if (ret == _FAIL)
+				goto exit;
+		}
+	}
+
+exit:
+	return ret;
+}
+
+static int _PageWrite(struct adapter *padapter, u32 page, void *buffer, u32 size)
+{
+	u8 value8;
+	u8 u8Page = (u8)(page & 0x07);
+
+	value8 = (rtw_read8(padapter, REG_MCUFWDL+2) & 0xF8) | u8Page;
+	rtw_write8(padapter, REG_MCUFWDL+2, value8);
+
+	return _BlockWrite(padapter, buffer, size);
+}
+
+static int _WriteFW(struct adapter *padapter, void *buffer, u32 size)
+{
+	/*  Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */
+	/*  We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */
+	int ret = _SUCCESS;
+	u32	pageNums, remainSize;
+	u32	page, offset;
+	u8 *bufferPtr = (u8 *)buffer;
+
+	pageNums = size / MAX_PAGE_SIZE;
+	remainSize = size % MAX_PAGE_SIZE;
+
+	for (page = 0; page < pageNums; page++) {
+		offset = page * MAX_PAGE_SIZE;
+		ret = _PageWrite(padapter, page, bufferPtr+offset, MAX_PAGE_SIZE);
+
+		if (ret == _FAIL)
+			goto exit;
+	}
+	if (remainSize) {
+		offset = pageNums * MAX_PAGE_SIZE;
+		page = pageNums;
+		ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize);
+
+		if (ret == _FAIL)
+			goto exit;
+	}
+	RT_TRACE(_module_hal_init_c_, _drv_info_, ("_WriteFW Done- for Normal chip.\n"));
+exit:
+	return ret;
+}
+
+void _8051Reset88E(struct adapter *padapter)
+{
+	u8 u1bTmp;
+
+	u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN+1);
+	rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT2));
+	rtw_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp|(BIT2));
+	DBG_88E("=====> _8051Reset88E(): 8051 reset success .\n");
+}
+
+static s32 _FWFreeToGo(struct adapter *padapter)
+{
+	u32	counter = 0;
+	u32	value32;
+
+	/*  polling CheckSum report */
+	do {
+		value32 = rtw_read32(padapter, REG_MCUFWDL);
+		if (value32 & FWDL_ChkSum_rpt)
+			break;
+	} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
+
+	if (counter >= POLLING_READY_TIMEOUT_COUNT) {
+		DBG_88E("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __func__, value32);
+		return _FAIL;
+	}
+	DBG_88E("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, value32);
+
+	value32 = rtw_read32(padapter, REG_MCUFWDL);
+	value32 |= MCUFWDL_RDY;
+	value32 &= ~WINTINI_RDY;
+	rtw_write32(padapter, REG_MCUFWDL, value32);
+
+	_8051Reset88E(padapter);
+
+	/*  polling for FW ready */
+	counter = 0;
+	do {
+		value32 = rtw_read32(padapter, REG_MCUFWDL);
+		if (value32 & WINTINI_RDY) {
+			DBG_88E("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __func__, value32);
+			return _SUCCESS;
+		}
+		rtw_udelay_os(5);
+	} while (counter++ < POLLING_READY_TIMEOUT_COUNT);
+
+	DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32);
+	return _FAIL;
+}
+
+#define IS_FW_81xxC(padapter)	(((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0)
+
+s32 rtl8188e_FirmwareDownload(struct adapter *padapter)
+{
+	s32	rtStatus = _SUCCESS;
+	u8 writeFW_retry = 0;
+	u32 fwdl_start_time;
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+	u8 *FwImage;
+	u32			FwImageLen;
+	struct rt_firmware *pFirmware = NULL;
+	struct rt_firmware_hdr *pFwHdr = NULL;
+	u8 *pFirmwareBuf;
+	u32			FirmwareLen;
+
+	RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__));
+	pFirmware = (struct rt_firmware *)rtw_zmalloc(sizeof(struct rt_firmware));
+	if (!pFirmware) {
+		rtStatus = _FAIL;
+		goto Exit;
+	}
+
+	FwImage = (u8 *)Rtl8188E_FwImageArray;
+	FwImageLen = Rtl8188E_FWImgArrayLength;
+
+	pFirmware->eFWSource = FW_SOURCE_HEADER_FILE;
+
+	switch (pFirmware->eFWSource) {
+	case FW_SOURCE_IMG_FILE:
+		break;
+	case FW_SOURCE_HEADER_FILE:
+		if (FwImageLen > FW_8188E_SIZE) {
+			rtStatus = _FAIL;
+			RT_TRACE(_module_hal_init_c_, _drv_err_, ("Firmware size exceed 0x%X. Check it.\n", FW_8188E_SIZE));
+			goto Exit;
+		}
+
+		pFirmware->szFwBuffer = FwImage;
+		pFirmware->ulFwLength = FwImageLen;
+		break;
+	}
+	pFirmwareBuf = pFirmware->szFwBuffer;
+	FirmwareLen = pFirmware->ulFwLength;
+	DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, FirmwareLen);
+
+	/*  To Check Fw header. Added by tynli. 2009.12.04. */
+	pFwHdr = (struct rt_firmware_hdr *)pFirmware->szFwBuffer;
+
+	pHalData->FirmwareVersion =  le16_to_cpu(pFwHdr->Version);
+	pHalData->FirmwareSubVersion = pFwHdr->Subversion;
+	pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature);
+
+	DBG_88E("%s: fw_ver =%d fw_subver =%d sig = 0x%x\n",
+		__func__, pHalData->FirmwareVersion, pHalData->FirmwareSubVersion, pHalData->FirmwareSignature);
+
+	if (IS_FW_HEADER_EXIST(pFwHdr)) {
+		/*  Shift 32 bytes for FW header */
+		pFirmwareBuf = pFirmwareBuf + 32;
+		FirmwareLen = FirmwareLen - 32;
+	}
+
+	/*  Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */
+	/*  or it will cause download Fw fail. 2010.02.01. by tynli. */
+	if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */
+		rtw_write8(padapter, REG_MCUFWDL, 0x00);
+		_8051Reset88E(padapter);
+	}
+
+	_FWDownloadEnable(padapter, true);
+	fwdl_start_time = rtw_get_current_time();
+	while (1) {
+		/* reset the FWDL chksum */
+		rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt);
+
+		rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen);
+
+		if (rtStatus == _SUCCESS ||
+		    (rtw_get_passing_time_ms(fwdl_start_time) > 500 && writeFW_retry++ >= 3))
+			break;
+
+		DBG_88E("%s writeFW_retry:%u, time after fwdl_start_time:%ums\n",
+			__func__, writeFW_retry, rtw_get_passing_time_ms(fwdl_start_time)
+		);
+	}
+	_FWDownloadEnable(padapter, false);
+	if (_SUCCESS != rtStatus) {
+		DBG_88E("DL Firmware failed!\n");
+		goto Exit;
+	}
+
+	rtStatus = _FWFreeToGo(padapter);
+	if (_SUCCESS != rtStatus) {
+		DBG_88E("DL Firmware failed!\n");
+		goto Exit;
+	}
+	RT_TRACE(_module_hal_init_c_, _drv_info_, ("Firmware is ready to run!\n"));
+
+Exit:
+
+	kfree(pFirmware);
+	return rtStatus;
+}
+
+void rtl8188e_InitializeFirmwareVars(struct adapter *padapter)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+	/*  Init Fw LPS related. */
+	padapter->pwrctrlpriv.bFwCurrentInPSMode = false;
+
+	/*  Init H2C counter. by tynli. 2009.12.09. */
+	pHalData->LastHMEBoxNum = 0;
+}
+
+static void rtl8188e_free_hal_data(struct adapter *padapter)
+{
+_func_enter_;
+	kfree(padapter->HalData);
+	padapter->HalData = NULL;
+_func_exit_;
+}
+
+/*  */
+/*			Efuse related code */
+/*  */
+enum{
+		VOLTAGE_V25						= 0x03,
+		LDOE25_SHIFT						= 28 ,
+	};
+
+static bool
+hal_EfusePgPacketWrite2ByteHeader(
+		struct adapter *pAdapter,
+		u8 efuseType,
+		u16				*pAddr,
+		struct pgpkt *pTargetPkt,
+		bool bPseudoTest);
+static bool
+hal_EfusePgPacketWrite1ByteHeader(
+		struct adapter *pAdapter,
+		u8 efuseType,
+		u16				*pAddr,
+		struct pgpkt *pTargetPkt,
+		bool bPseudoTest);
+static bool
+hal_EfusePgPacketWriteData(
+		struct adapter *pAdapter,
+		u8 efuseType,
+		u16				*pAddr,
+		struct pgpkt *pTargetPkt,
+		bool bPseudoTest);
+
+static void
+hal_EfusePowerSwitch_RTL8188E(
+		struct adapter *pAdapter,
+		u8 bWrite,
+		u8 PwrState)
+{
+	u8 tempval;
+	u16	tmpV16;
+
+	if (PwrState) {
+		rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
+
+		/*  1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */
+		tmpV16 = rtw_read16(pAdapter, REG_SYS_ISO_CTRL);
+		if (!(tmpV16 & PWC_EV12V)) {
+			tmpV16 |= PWC_EV12V;
+			 rtw_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16);
+		}
+		/*  Reset: 0x0000h[28], default valid */
+		tmpV16 =  rtw_read16(pAdapter, REG_SYS_FUNC_EN);
+		if (!(tmpV16 & FEN_ELDR)) {
+			tmpV16 |= FEN_ELDR;
+			rtw_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16);
+		}
+
+		/*  Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */
+		tmpV16 = rtw_read16(pAdapter, REG_SYS_CLKR);
+		if ((!(tmpV16 & LOADER_CLK_EN))  || (!(tmpV16 & ANA8M))) {
+			tmpV16 |= (LOADER_CLK_EN | ANA8M);
+			rtw_write16(pAdapter, REG_SYS_CLKR, tmpV16);
+		}
+
+		if (bWrite) {
+			/*  Enable LDO 2.5V before read/write action */
+			tempval = rtw_read8(pAdapter, EFUSE_TEST+3);
+			tempval &= 0x0F;
+			tempval |= (VOLTAGE_V25 << 4);
+			rtw_write8(pAdapter, EFUSE_TEST+3, (tempval | 0x80));
+		}
+	} else {
+		rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
+
+		if (bWrite) {
+			/*  Disable LDO 2.5V after read/write action */
+			tempval = rtw_read8(pAdapter, EFUSE_TEST+3);
+			rtw_write8(pAdapter, EFUSE_TEST+3, (tempval & 0x7F));
+		}
+	}
+}
+
+static void
+rtl8188e_EfusePowerSwitch(
+		struct adapter *pAdapter,
+		u8 bWrite,
+		u8 PwrState)
+{
+	hal_EfusePowerSwitch_RTL8188E(pAdapter, bWrite, PwrState);
+}
+
+
+static void Hal_EfuseReadEFuse88E(struct adapter *Adapter,
+	u16			_offset,
+	u16			_size_byte,
+	u8 *pbuf,
+		bool bPseudoTest
+	)
+{
+	u8 *efuseTbl = NULL;
+	u8 rtemp8[1];
+	u16	eFuse_Addr = 0;
+	u8 offset, wren;
+	u16	i, j;
+	u16	**eFuseWord = NULL;
+	u16	efuse_utilized = 0;
+	u8 u1temp = 0;
+
+	/*  */
+	/*  Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */
+	/*  */
+	if ((_offset + _size_byte) > EFUSE_MAP_LEN_88E) {/*  total E-Fuse table is 512bytes */
+		DBG_88E("Hal_EfuseReadEFuse88E(): Invalid offset(%#x) with read bytes(%#x)!!\n", _offset, _size_byte);
+		goto exit;
+	}
+
+	efuseTbl = (u8 *)rtw_zmalloc(EFUSE_MAP_LEN_88E);
+	if (efuseTbl == NULL) {
+		DBG_88E("%s: alloc efuseTbl fail!\n", __func__);
+		goto exit;
+	}
+
+	eFuseWord = (u16 **)rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+	if (eFuseWord == NULL) {
+		DBG_88E("%s: alloc eFuseWord fail!\n", __func__);
+		goto exit;
+	}
+
+	/*  0. Refresh efuse init map as all oxFF. */
+	for (i = 0; i < EFUSE_MAX_SECTION_88E; i++)
+		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
+			eFuseWord[i][j] = 0xFFFF;
+
+	/*  */
+	/*  1. Read the first byte to check if efuse is empty!!! */
+	/*  */
+	/*  */
+	ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+	if (*rtemp8 != 0xFF) {
+		efuse_utilized++;
+		eFuse_Addr++;
+	} else {
+		DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, *rtemp8);
+		goto exit;
+	}
+
+	/*  */
+	/*  2. Read real efuse content. Filter PG header and every section data. */
+	/*  */
+	while ((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+		/*  Check PG header for section num. */
+		if ((*rtemp8 & 0x1F) == 0x0F) {		/* extended header */
+			u1temp = ((*rtemp8 & 0xE0) >> 5);
+
+			ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+
+			if ((*rtemp8 & 0x0F) == 0x0F) {
+				eFuse_Addr++;
+				ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+
+				if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E))
+					eFuse_Addr++;
+				continue;
+			} else {
+				offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
+				wren = (*rtemp8 & 0x0F);
+				eFuse_Addr++;
+			}
+		} else {
+			offset = ((*rtemp8 >> 4) & 0x0f);
+			wren = (*rtemp8 & 0x0f);
+		}
+
+		if (offset < EFUSE_MAX_SECTION_88E) {
+			/*  Get word enable value from PG header */
+
+			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+				/*  Check word enable condition in the section */
+				if (!(wren & 0x01)) {
+					ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+					eFuse_Addr++;
+					efuse_utilized++;
+					eFuseWord[offset][i] = (*rtemp8 & 0xff);
+					if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+						break;
+					ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+					eFuse_Addr++;
+					efuse_utilized++;
+					eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00);
+					if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E)
+						break;
+				}
+				wren >>= 1;
+			}
+		}
+
+		/*  Read next PG header */
+		ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest);
+
+		if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) {
+			efuse_utilized++;
+			eFuse_Addr++;
+		}
+	}
+
+	/*  3. Collect 16 sections and 4 word unit into Efuse map. */
+	for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) {
+		for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
+			efuseTbl[(i*8)+(j*2)] = (eFuseWord[i][j] & 0xff);
+			efuseTbl[(i*8)+((j*2)+1)] = ((eFuseWord[i][j] >> 8) & 0xff);
+		}
+	}
+
+	/*  4. Copy from Efuse map to output pointer memory!!! */
+	for (i = 0; i < _size_byte; i++)
+		pbuf[i] = efuseTbl[_offset+i];
+
+	/*  5. Calculate Efuse utilization. */
+	rtw_hal_set_hwreg(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&eFuse_Addr);
+
+exit:
+	kfree(efuseTbl);
+
+	if (eFuseWord)
+		rtw_mfree2d((void *)eFuseWord, EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16));
+}
+
+static void ReadEFuseByIC(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest)
+{
+	if (!bPseudoTest) {
+		int ret = _FAIL;
+		if (rtw_IOL_applied(Adapter)) {
+			rtw_hal_power_on(Adapter);
+
+			iol_mode_enable(Adapter, 1);
+			ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf);
+			iol_mode_enable(Adapter, 0);
+
+			if (_SUCCESS == ret)
+				goto exit;
+		}
+	}
+	Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest);
+
+exit:
+	return;
+}
+
+static void ReadEFuse_Pseudo(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest)
+{
+	Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest);
+}
+
+static void rtl8188e_ReadEFuse(struct adapter *Adapter, u8 efuseType,
+			       u16 _offset, u16 _size_byte, u8 *pbuf,
+			       bool bPseudoTest)
+{
+	if (bPseudoTest)
+		ReadEFuse_Pseudo (Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
+	else
+		ReadEFuseByIC(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest);
+}
+
+/* Do not support BT */
+static void Hal_EFUSEGetEfuseDefinition88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
+{
+	switch (type) {
+	case TYPE_EFUSE_MAX_SECTION:
+		{
+			u8 *pMax_section;
+			pMax_section = (u8 *)pOut;
+			*pMax_section = EFUSE_MAX_SECTION_88E;
+		}
+		break;
+	case TYPE_EFUSE_REAL_CONTENT_LEN:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+		}
+		break;
+	case TYPE_EFUSE_CONTENT_LEN_BANK:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+		}
+		break;
+	case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+		}
+		break;
+	case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+		}
+		break;
+	case TYPE_EFUSE_MAP_LEN:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
+		}
+		break;
+	case TYPE_EFUSE_PROTECT_BYTES_BANK:
+		{
+			u8 *pu1Tmp;
+			pu1Tmp = (u8 *)pOut;
+			*pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
+		}
+		break;
+	default:
+		{
+			u8 *pu1Tmp;
+			pu1Tmp = (u8 *)pOut;
+			*pu1Tmp = 0;
+		}
+		break;
+	}
+}
+
+static void Hal_EFUSEGetEfuseDefinition_Pseudo88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut)
+{
+	switch (type) {
+	case TYPE_EFUSE_MAX_SECTION:
+		{
+			u8 *pMax_section;
+			pMax_section = (u8 *)pOut;
+			*pMax_section = EFUSE_MAX_SECTION_88E;
+		}
+		break;
+	case TYPE_EFUSE_REAL_CONTENT_LEN:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+		}
+		break;
+	case TYPE_EFUSE_CONTENT_LEN_BANK:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E;
+		}
+		break;
+	case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+		}
+		break;
+	case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E-EFUSE_OOB_PROTECT_BYTES_88E);
+		}
+		break;
+	case TYPE_EFUSE_MAP_LEN:
+		{
+			u16 *pu2Tmp;
+			pu2Tmp = (u16 *)pOut;
+			*pu2Tmp = (u16)EFUSE_MAP_LEN_88E;
+		}
+		break;
+	case TYPE_EFUSE_PROTECT_BYTES_BANK:
+		{
+			u8 *pu1Tmp;
+			pu1Tmp = (u8 *)pOut;
+			*pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E);
+		}
+		break;
+	default:
+		{
+			u8 *pu1Tmp;
+			pu1Tmp = (u8 *)pOut;
+			*pu1Tmp = 0;
+		}
+		break;
+	}
+}
+
+static void rtl8188e_EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest)
+{
+	if (bPseudoTest)
+		Hal_EFUSEGetEfuseDefinition_Pseudo88E(pAdapter, efuseType, type, pOut);
+	else
+		Hal_EFUSEGetEfuseDefinition88E(pAdapter, efuseType, type, pOut);
+}
+
+static u8 Hal_EfuseWordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
+{
+	u16	tmpaddr = 0;
+	u16	start_addr = efuse_addr;
+	u8 badworden = 0x0F;
+	u8 tmpdata[8];
+
+	_rtw_memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE);
+
+	if (!(word_en&BIT0)) {
+		tmpaddr = start_addr;
+		efuse_OneByteWrite(pAdapter, start_addr++, data[0], bPseudoTest);
+		efuse_OneByteWrite(pAdapter, start_addr++, data[1], bPseudoTest);
+
+		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0], bPseudoTest);
+		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[1], bPseudoTest);
+		if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1]))
+			badworden &= (~BIT0);
+	}
+	if (!(word_en&BIT1)) {
+		tmpaddr = start_addr;
+		efuse_OneByteWrite(pAdapter, start_addr++, data[2], bPseudoTest);
+		efuse_OneByteWrite(pAdapter, start_addr++, data[3], bPseudoTest);
+
+		efuse_OneByteRead(pAdapter, tmpaddr    , &tmpdata[2], bPseudoTest);
+		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[3], bPseudoTest);
+		if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3]))
+			badworden &= (~BIT1);
+	}
+	if (!(word_en&BIT2)) {
+		tmpaddr = start_addr;
+		efuse_OneByteWrite(pAdapter, start_addr++, data[4], bPseudoTest);
+		efuse_OneByteWrite(pAdapter, start_addr++, data[5], bPseudoTest);
+
+		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4], bPseudoTest);
+		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[5], bPseudoTest);
+		if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5]))
+			badworden &= (~BIT2);
+	}
+	if (!(word_en&BIT3)) {
+		tmpaddr = start_addr;
+		efuse_OneByteWrite(pAdapter, start_addr++, data[6], bPseudoTest);
+		efuse_OneByteWrite(pAdapter, start_addr++, data[7], bPseudoTest);
+
+		efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6], bPseudoTest);
+		efuse_OneByteRead(pAdapter, tmpaddr+1, &tmpdata[7], bPseudoTest);
+		if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7]))
+			badworden &= (~BIT3);
+	}
+	return badworden;
+}
+
+static u8 Hal_EfuseWordEnableDataWrite_Pseudo(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
+{
+	u8 ret;
+
+	ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
+	return ret;
+}
+
+static u8 rtl8188e_Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest)
+{
+	u8 ret = 0;
+
+	if (bPseudoTest)
+		ret = Hal_EfuseWordEnableDataWrite_Pseudo (pAdapter, efuse_addr, word_en, data, bPseudoTest);
+	else
+		ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest);
+	return ret;
+}
+
+static u16 hal_EfuseGetCurrentSize_8188e(struct adapter *pAdapter, bool bPseudoTest)
+{
+	int	bContinual = true;
+	u16	efuse_addr = 0;
+	u8 hoffset = 0, hworden = 0;
+	u8 efuse_data, word_cnts = 0;
+
+	if (bPseudoTest)
+		efuse_addr = (u16)(fakeEfuseUsedBytes);
+	else
+		rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
+
+	while (bContinual &&
+	       efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) &&
+	       AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+		if (efuse_data != 0xFF) {
+			if ((efuse_data&0x1F) == 0x0F) {		/* extended header */
+				hoffset = efuse_data;
+				efuse_addr++;
+				efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest);
+				if ((efuse_data & 0x0F) == 0x0F) {
+					efuse_addr++;
+					continue;
+				} else {
+					hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
+					hworden = efuse_data & 0x0F;
+				}
+			} else {
+				hoffset = (efuse_data>>4) & 0x0F;
+				hworden =  efuse_data & 0x0F;
+			}
+			word_cnts = Efuse_CalculateWordCnts(hworden);
+			/* read next header */
+			efuse_addr = efuse_addr + (word_cnts*2)+1;
+		} else {
+			bContinual = false;
+		}
+	}
+
+	if (bPseudoTest)
+		fakeEfuseUsedBytes = efuse_addr;
+	else
+		rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr);
+
+	return efuse_addr;
+}
+
+static u16 Hal_EfuseGetCurrentSize_Pseudo(struct adapter *pAdapter, bool bPseudoTest)
+{
+	u16	ret = 0;
+
+	ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest);
+	return ret;
+}
+
+static u16 rtl8188e_EfuseGetCurrentSize(struct adapter *pAdapter, u8 efuseType, bool bPseudoTest)
+{
+	u16	ret = 0;
+
+	if (bPseudoTest)
+		ret = Hal_EfuseGetCurrentSize_Pseudo(pAdapter, bPseudoTest);
+	else
+		ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest);
+	return ret;
+}
+
+static int hal_EfusePgPacketRead_8188e(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+	u8 ReadState = PG_STATE_HEADER;
+	int	bContinual = true;
+	int	bDataEmpty = true;
+	u8 efuse_data, word_cnts = 0;
+	u16	efuse_addr = 0;
+	u8 hoffset = 0, hworden = 0;
+	u8 tmpidx = 0;
+	u8 tmpdata[8];
+	u8 max_section = 0;
+	u8 tmp_header = 0;
+
+	EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section, bPseudoTest);
+
+	if (data == NULL)
+		return false;
+	if (offset > max_section)
+		return false;
+
+	_rtw_memset((void *)data, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
+	_rtw_memset((void *)tmpdata, 0xff, sizeof(u8)*PGPKT_DATA_SIZE);
+
+	/*  <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */
+	/*  Skip dummy parts to prevent unexpected data read from Efuse. */
+	/*  By pass right now. 2009.02.19. */
+	while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+		/*   Header Read ------------- */
+		if (ReadState & PG_STATE_HEADER) {
+			if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) {
+				if (EXT_HEADER(efuse_data)) {
+					tmp_header = efuse_data;
+					efuse_addr++;
+					efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest);
+					if (!ALL_WORDS_DISABLED(efuse_data)) {
+						hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
+						hworden = efuse_data & 0x0F;
+					} else {
+						DBG_88E("Error, All words disabled\n");
+						efuse_addr++;
+						continue;
+					}
+				} else {
+					hoffset = (efuse_data>>4) & 0x0F;
+					hworden =  efuse_data & 0x0F;
+				}
+				word_cnts = Efuse_CalculateWordCnts(hworden);
+				bDataEmpty = true;
+
+				if (hoffset == offset) {
+					for (tmpidx = 0; tmpidx < word_cnts*2; tmpidx++) {
+						if (efuse_OneByteRead(pAdapter, efuse_addr+1+tmpidx, &efuse_data, bPseudoTest)) {
+							tmpdata[tmpidx] = efuse_data;
+							if (efuse_data != 0xff)
+								bDataEmpty = false;
+						}
+					}
+					if (bDataEmpty == false) {
+						ReadState = PG_STATE_DATA;
+					} else {/* read next header */
+						efuse_addr = efuse_addr + (word_cnts*2)+1;
+						ReadState = PG_STATE_HEADER;
+					}
+				} else {/* read next header */
+					efuse_addr = efuse_addr + (word_cnts*2)+1;
+					ReadState = PG_STATE_HEADER;
+				}
+			} else {
+				bContinual = false;
+			}
+		} else if (ReadState & PG_STATE_DATA) {
+		/*   Data section Read ------------- */
+			efuse_WordEnableDataRead(hworden, tmpdata, data);
+			efuse_addr = efuse_addr + (word_cnts*2)+1;
+			ReadState = PG_STATE_HEADER;
+		}
+
+	}
+
+	if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff)  && (data[3] == 0xff) &&
+	    (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff)  && (data[7] == 0xff))
+		return false;
+	else
+		return true;
+}
+
+static int Hal_EfusePgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+	int	ret;
+
+	ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest);
+	return ret;
+}
+
+static int Hal_EfusePgPacketRead_Pseudo(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+	int	ret;
+
+	ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest);
+	return ret;
+}
+
+static int rtl8188e_Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest)
+{
+	int	ret;
+
+	if (bPseudoTest)
+		ret = Hal_EfusePgPacketRead_Pseudo (pAdapter, offset, data, bPseudoTest);
+	else
+		ret = Hal_EfusePgPacketRead(pAdapter, offset, data, bPseudoTest);
+	return ret;
+}
+
+static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr, bool bPseudoTest)
+{
+	u8 originaldata[8], badworden = 0;
+	u16	efuse_addr = *pAddr;
+	u32	PgWriteSuccess = 0;
+
+	_rtw_memset((void *)originaldata, 0xff, 8);
+
+	if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata, bPseudoTest)) {
+		/* check if data exist */
+		badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pFixPkt->word_en, originaldata, bPseudoTest);
+
+		if (badworden != 0xf) {	/*  write fail */
+			PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata, bPseudoTest);
+
+			if (!PgWriteSuccess)
+				return false;
+			else
+				efuse_addr = Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest);
+		} else {
+			efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
+		}
+	} else {
+		efuse_addr = efuse_addr + (pFixPkt->word_cnts*2) + 1;
+	}
+	*pAddr = efuse_addr;
+	return true;
+}
+
+static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+	bool bRet = false;
+	u16	efuse_addr = *pAddr, efuse_max_available_len = 0;
+	u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0;
+	u8 repeatcnt = 0;
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest);
+
+	while (efuse_addr < efuse_max_available_len) {
+		pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
+		efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+		efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+
+		while (tmp_header == 0xFF) {
+			if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
+				return false;
+
+			efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+			efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+		}
+
+		/* to write ext_header */
+		if (tmp_header == pg_header) {
+			efuse_addr++;
+			pg_header_temp = pg_header;
+			pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
+
+			efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+			efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+
+			while (tmp_header == 0xFF) {
+				if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
+					return false;
+
+				efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+				efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+			}
+
+			if ((tmp_header & 0x0F) == 0x0F) {	/* word_en PG fail */
+				if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+					return false;
+				} else {
+					efuse_addr++;
+					continue;
+				}
+			} else if (pg_header != tmp_header) {	/* offset PG fail */
+				struct pgpkt	fixPkt;
+				fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1);
+				fixPkt.word_en = tmp_header & 0x0F;
+				fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
+				if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest))
+					return false;
+			} else {
+				bRet = true;
+				break;
+			}
+		} else if ((tmp_header & 0x1F) == 0x0F) {		/* wrong extended header */
+			efuse_addr += 2;
+			continue;
+		}
+	}
+
+	*pAddr = efuse_addr;
+	return bRet;
+}
+
+static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+	bool bRet = false;
+	u8 pg_header = 0, tmp_header = 0;
+	u16	efuse_addr = *pAddr;
+	u8 repeatcnt = 0;
+
+	pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
+
+	efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+	efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+
+	while (tmp_header == 0xFF) {
+		if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
+			return false;
+		efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest);
+		efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest);
+	}
+
+	if (pg_header == tmp_header) {
+		bRet = true;
+	} else {
+		struct pgpkt	fixPkt;
+		fixPkt.offset = (tmp_header>>4) & 0x0F;
+		fixPkt.word_en = tmp_header & 0x0F;
+		fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
+		if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest))
+			return false;
+	}
+
+	*pAddr = efuse_addr;
+	return bRet;
+}
+
+static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+	bool bRet = false;
+	u16	efuse_addr = *pAddr;
+	u8 badworden = 0;
+	u32	PgWriteSuccess = 0;
+
+	badworden = 0x0f;
+	badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest);
+	if (badworden == 0x0F) {
+		/*  write ok */
+		return true;
+	} else {
+		/* reorganize other pg packet */
+		PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest);
+		if (!PgWriteSuccess)
+			return false;
+		else
+			return true;
+	}
+	return bRet;
+}
+
+static bool
+hal_EfusePgPacketWriteHeader(
+				struct adapter *pAdapter,
+				u8 efuseType,
+				u16				*pAddr,
+				struct pgpkt *pTargetPkt,
+				bool bPseudoTest)
+{
+	bool bRet = false;
+
+	if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE)
+		bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
+	else
+		bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest);
+
+	return bRet;
+}
+
+static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt,
+			  u8 *pWden)
+{
+	u8 match_word_en = 0x0F;	/*  default all words are disabled */
+
+	/*  check if the same words are enabled both target and current PG packet */
+	if (((pTargetPkt->word_en & BIT0) == 0) &&
+	    ((pCurPkt->word_en & BIT0) == 0))
+		match_word_en &= ~BIT0;				/*  enable word 0 */
+	if (((pTargetPkt->word_en & BIT1) == 0) &&
+	    ((pCurPkt->word_en & BIT1) == 0))
+		match_word_en &= ~BIT1;				/*  enable word 1 */
+	if (((pTargetPkt->word_en & BIT2) == 0) &&
+	    ((pCurPkt->word_en & BIT2) == 0))
+		match_word_en &= ~BIT2;				/*  enable word 2 */
+	if (((pTargetPkt->word_en & BIT3) == 0) &&
+	    ((pCurPkt->word_en & BIT3) == 0))
+		match_word_en &= ~BIT3;				/*  enable word 3 */
+
+	*pWden = match_word_en;
+
+	if (match_word_en != 0xf)
+		return true;
+	else
+		return false;
+}
+
+static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr, bool bPseudoTest)
+{
+	bool bRet = false;
+	u8 i, efuse_data;
+
+	for (i = 0; i < (word_cnts*2); i++) {
+		if (efuse_OneByteRead(pAdapter, (startAddr+i), &efuse_data, bPseudoTest) && (efuse_data != 0xFF))
+			bRet = true;
+	}
+	return bRet;
+}
+
+static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest)
+{
+	bool bRet = false;
+	u8 i, efuse_data = 0, cur_header = 0;
+	u8 matched_wden = 0, badworden = 0;
+	u16	startAddr = 0, efuse_max_available_len = 0, efuse_max = 0;
+	struct pgpkt curPkt;
+
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest);
+	EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max, bPseudoTest);
+
+	if (efuseType == EFUSE_WIFI) {
+		if (bPseudoTest) {
+			startAddr = (u16)(fakeEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
+		} else {
+			rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr);
+			startAddr %= EFUSE_REAL_CONTENT_LEN;
+		}
+	} else {
+		if (bPseudoTest)
+			startAddr = (u16)(fakeBTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
+		else
+			startAddr = (u16)(BTEfuseUsedBytes%EFUSE_REAL_CONTENT_LEN);
+	}
+
+	while (1) {
+		if (startAddr >= efuse_max_available_len) {
+			bRet = false;
+			break;
+		}
+
+		if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) {
+			if (EXT_HEADER(efuse_data)) {
+				cur_header = efuse_data;
+				startAddr++;
+				efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest);
+				if (ALL_WORDS_DISABLED(efuse_data)) {
+					bRet = false;
+					break;
+				} else {
+					curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1);
+					curPkt.word_en = efuse_data & 0x0F;
+				}
+			} else {
+				cur_header  =  efuse_data;
+				curPkt.offset = (cur_header>>4) & 0x0F;
+				curPkt.word_en = cur_header & 0x0F;
+			}
+
+			curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en);
+			/*  if same header is found but no data followed */
+			/*  write some part of data followed by the header. */
+			if ((curPkt.offset == pTargetPkt->offset) &&
+			    (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr+1, bPseudoTest)) &&
+			    wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) {
+				/*  Here to write partial data */
+				badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest);
+				if (badworden != 0x0F) {
+					u32	PgWriteSuccess = 0;
+					/*  if write fail on some words, write these bad words again */
+
+					PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest);
+
+					if (!PgWriteSuccess) {
+						bRet = false;	/*  write fail, return */
+						break;
+					}
+				}
+				/*  partial write ok, update the target packet for later use */
+				for (i = 0; i < 4; i++) {
+					if ((matched_wden & (0x1<<i)) == 0)	/*  this word has been written */
+						pTargetPkt->word_en |= (0x1<<i);	/*  disable the word */
+				}
+				pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
+			}
+			/*  read from next header */
+			startAddr = startAddr + (curPkt.word_cnts*2) + 1;
+		} else {
+			/*  not used header, 0xff */
+			*pAddr = startAddr;
+			bRet = true;
+			break;
+		}
+	}
+	return bRet;
+}
+
+static bool
+hal_EfusePgCheckAvailableAddr(
+		struct adapter *pAdapter,
+		u8 efuseType,
+		bool bPseudoTest
+	)
+{
+	u16	efuse_max_available_len = 0;
+
+	/* Change to check TYPE_EFUSE_MAP_LEN , beacuse 8188E raw 256, logic map over 256. */
+	EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len, false);
+
+	if (Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len)
+		return false;
+	return true;
+}
+
+static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt)
+{
+	_rtw_memset((void *)pTargetPkt->data, 0xFF, sizeof(u8)*8);
+	pTargetPkt->offset = offset;
+	pTargetPkt->word_en = word_en;
+	efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data);
+	pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en);
+}
+
+static bool hal_EfusePgPacketWrite_8188e(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData, bool bPseudoTest)
+{
+	struct pgpkt	targetPkt;
+	u16			startAddr = 0;
+	u8 efuseType = EFUSE_WIFI;
+
+	if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest))
+		return false;
+
+	hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
+
+	if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+		return false;
+
+	if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+		return false;
+
+	if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest))
+		return false;
+
+	return true;
+}
+
+static int Hal_EfusePgPacketWrite_Pseudo(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
+{
+	int ret;
+
+	ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest);
+	return ret;
+}
+
+static int Hal_EfusePgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
+{
+	int	ret = 0;
+	ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest);
+
+	return ret;
+}
+
+static int rtl8188e_Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest)
+{
+	int	ret;
+
+	if (bPseudoTest)
+		ret = Hal_EfusePgPacketWrite_Pseudo (pAdapter, offset, word_en, data, bPseudoTest);
+	else
+		ret = Hal_EfusePgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest);
+	return ret;
+}
+
+static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter)
+{
+	u32				value32;
+	struct HAL_VERSION		ChipVersion;
+	struct hal_data_8188e	*pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+
+	value32 = rtw_read32(padapter, REG_SYS_CFG);
+	ChipVersion.ICType = CHIP_8188E;
+	ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP);
+
+	ChipVersion.RFType = RF_TYPE_1T1R;
+	ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC);
+	ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /*  IC version (CUT) */
+
+	/*  For regulator mode. by tynli. 2011.01.14 */
+	pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR);
+
+	ChipVersion.ROMVer = 0;	/*  ROM code version. */
+	pHalData->MultiFunc = RT_MULTI_FUNC_NONE;
+
+	dump_chip_info(ChipVersion);
+
+	pHalData->VersionID = ChipVersion;
+
+	if (IS_1T2R(ChipVersion)) {
+		pHalData->rf_type = RF_1T2R;
+		pHalData->NumTotalRFPath = 2;
+	} else if (IS_2T2R(ChipVersion)) {
+		pHalData->rf_type = RF_2T2R;
+		pHalData->NumTotalRFPath = 2;
+	} else{
+		pHalData->rf_type = RF_1T1R;
+		pHalData->NumTotalRFPath = 1;
+	}
+
+	MSG_88E("RF_Type is %x!!\n", pHalData->rf_type);
+
+	return ChipVersion;
+}
+
+static void rtl8188e_read_chip_version(struct adapter *padapter)
+{
+	ReadChipVersion8188E(padapter);
+}
+
+static void rtl8188e_GetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
+{
+}
+
+static void rtl8188e_SetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	struct odm_dm_struct *podmpriv = &pHalData->odmpriv;
+	switch (eVariable) {
+	case HAL_ODM_STA_INFO:
+		{
+			struct sta_info *psta = (struct sta_info *)pValue1;
+			if (bSet) {
+				DBG_88E("### Set STA_(%d) info\n", psta->mac_id);
+				ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta);
+				ODM_RAInfo_Init(podmpriv, psta->mac_id);
+			} else {
+				DBG_88E("### Clean STA_(%d) info\n", psta->mac_id);
+				ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL);
+		       }
+		}
+		break;
+	case HAL_ODM_P2P_STATE:
+			ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet);
+		break;
+	case HAL_ODM_WIFI_DISPLAY_STATE:
+			ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet);
+		break;
+	default:
+		break;
+	}
+}
+
+void rtl8188e_clone_haldata(struct adapter *dst_adapter, struct adapter *src_adapter)
+{
+	memcpy(dst_adapter->HalData, src_adapter->HalData, dst_adapter->hal_data_sz);
+}
+
+void rtl8188e_start_thread(struct adapter *padapter)
+{
+}
+
+void rtl8188e_stop_thread(struct adapter *padapter)
+{
+}
+
+static void hal_notch_filter_8188e(struct adapter *adapter, bool enable)
+{
+	if (enable) {
+		DBG_88E("Enable notch filter\n");
+		rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) | BIT1);
+	} else {
+		DBG_88E("Disable notch filter\n");
+		rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1);
+	}
+}
+void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc)
+{
+	pHalFunc->free_hal_data = &rtl8188e_free_hal_data;
+
+	pHalFunc->dm_init = &rtl8188e_init_dm_priv;
+	pHalFunc->dm_deinit = &rtl8188e_deinit_dm_priv;
+
+	pHalFunc->read_chip_version = &rtl8188e_read_chip_version;
+
+	pHalFunc->set_bwmode_handler = &PHY_SetBWMode8188E;
+	pHalFunc->set_channel_handler = &PHY_SwChnl8188E;
+
+	pHalFunc->hal_dm_watchdog = &rtl8188e_HalDmWatchDog;
+
+	pHalFunc->Add_RateATid = &rtl8188e_Add_RateATid;
+	pHalFunc->run_thread = &rtl8188e_start_thread;
+	pHalFunc->cancel_thread = &rtl8188e_stop_thread;
+
+	pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E;
+	pHalFunc->AntDivCompareHandler = &AntDivCompare8188E;
+	pHalFunc->read_bbreg = &rtl8188e_PHY_QueryBBReg;
+	pHalFunc->write_bbreg = &rtl8188e_PHY_SetBBReg;
+	pHalFunc->read_rfreg = &rtl8188e_PHY_QueryRFReg;
+	pHalFunc->write_rfreg = &rtl8188e_PHY_SetRFReg;
+
+	/*  Efuse related function */
+	pHalFunc->EfusePowerSwitch = &rtl8188e_EfusePowerSwitch;
+	pHalFunc->ReadEFuse = &rtl8188e_ReadEFuse;
+	pHalFunc->EFUSEGetEfuseDefinition = &rtl8188e_EFUSE_GetEfuseDefinition;
+	pHalFunc->EfuseGetCurrentSize = &rtl8188e_EfuseGetCurrentSize;
+	pHalFunc->Efuse_PgPacketRead = &rtl8188e_Efuse_PgPacketRead;
+	pHalFunc->Efuse_PgPacketWrite = &rtl8188e_Efuse_PgPacketWrite;
+	pHalFunc->Efuse_WordEnableDataWrite = &rtl8188e_Efuse_WordEnableDataWrite;
+
+	pHalFunc->sreset_init_value = &sreset_init_value;
+	pHalFunc->sreset_reset_value = &sreset_reset_value;
+	pHalFunc->silentreset = &rtl8188e_silentreset_for_specific_platform;
+	pHalFunc->sreset_xmit_status_check = &rtl8188e_sreset_xmit_status_check;
+	pHalFunc->sreset_linked_status_check  = &rtl8188e_sreset_linked_status_check;
+	pHalFunc->sreset_get_wifi_status  = &sreset_get_wifi_status;
+
+	pHalFunc->GetHalODMVarHandler = &rtl8188e_GetHalODMVar;
+	pHalFunc->SetHalODMVarHandler = &rtl8188e_SetHalODMVar;
+
+	pHalFunc->IOL_exec_cmds_sync = &rtl8188e_IOL_exec_cmds_sync;
+
+	pHalFunc->hal_notch_filter = &hal_notch_filter_8188e;
+}
+
+u8 GetEEPROMSize8188E(struct adapter *padapter)
+{
+	u8 size = 0;
+	u32	cr;
+
+	cr = rtw_read16(padapter, REG_9346CR);
+	/*  6: EEPROM used is 93C46, 4: boot from E-Fuse. */
+	size = (cr & BOOT_FROM_EEPROM) ? 6 : 4;
+
+	MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46");
+
+	return size;
+}
+
+/*  */
+/*  */
+/*  LLT R/W/Init function */
+/*  */
+/*  */
+static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data)
+{
+	s32	status = _SUCCESS;
+	s32	count = 0;
+	u32	value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS);
+	u16	LLTReg = REG_LLT_INIT;
+
+	rtw_write32(padapter, LLTReg, value);
+
+	/* polling */
+	do {
+		value = rtw_read32(padapter, LLTReg);
+		if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+			break;
+
+		if (count > POLLING_LLT_THRESHOLD) {
+			RT_TRACE(_module_hal_init_c_, _drv_err_, ("Failed to polling write LLT done at address %d!\n", address));
+			status = _FAIL;
+			break;
+		}
+	} while (count++);
+
+	return status;
+}
+
+s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
+{
+	s32	status = _FAIL;
+	u32	i;
+	u32	Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;/*  176, 22k */
+
+	if (rtw_IOL_applied(padapter)) {
+		status = iol_InitLLTTable(padapter, txpktbuf_bndy);
+	} else {
+		for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+			status = _LLTWrite(padapter, i, i + 1);
+			if (_SUCCESS != status)
+				return status;
+		}
+
+		/*  end of list */
+		status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF);
+		if (_SUCCESS != status)
+			return status;
+
+		/*  Make the other pages as ring buffer */
+		/*  This ring buffer is used as beacon buffer if we config this MAC as two MAC transfer. */
+		/*  Otherwise used as local loopback buffer. */
+		for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) {
+			status = _LLTWrite(padapter, i, (i + 1));
+			if (_SUCCESS != status)
+				return status;
+		}
+
+		/*  Let last entry point to the start entry of ring buffer */
+		status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy);
+		if (_SUCCESS != status) {
+			return status;
+		}
+	}
+
+	return status;
+}
+
+void
+Hal_InitPGData88E(struct adapter *padapter)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+
+	if (!pEEPROM->bautoload_fail_flag) { /*  autoload OK. */
+		if (!is_boot_from_eeprom(padapter)) {
+			/*  Read EFUSE real map to shadow. */
+			EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
+		}
+	} else {/* autoload fail */
+		RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, ("AutoLoad Fail reported from CR9346!!\n"));
+		/* update to default value 0xFF */
+		if (!is_boot_from_eeprom(padapter))
+			EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false);
+	}
+}
+
+void
+Hal_EfuseParseIDCode88E(
+		struct adapter *padapter,
+		u8 *hwinfo
+	)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+	u16			EEPROMId;
+
+	/*  Checl 0x8129 again for making sure autoload status!! */
+	EEPROMId = le16_to_cpu(*((__le16 *)hwinfo));
+	if (EEPROMId != RTL_EEPROM_ID) {
+		DBG_88E("EEPROM ID(%#x) is invalid!!\n", EEPROMId);
+		pEEPROM->bautoload_fail_flag = true;
+	} else {
+		pEEPROM->bautoload_fail_flag = false;
+	}
+
+	DBG_88E("EEPROM ID = 0x%04x\n", EEPROMId);
+}
+
+static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G, u8 *PROMContent, bool AutoLoadFail)
+{
+	u32 rfPath, eeAddr = EEPROM_TX_PWR_INX_88E, group, TxCount = 0;
+
+	_rtw_memset(pwrInfo24G, 0, sizeof(struct txpowerinfo24g));
+
+	if (AutoLoadFail) {
+		for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) {
+			/* 2.4G default value */
+			for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+				pwrInfo24G->IndexCCK_Base[rfPath][group] =	EEPROM_DEFAULT_24G_INDEX;
+				pwrInfo24G->IndexBW40_Base[rfPath][group] =	EEPROM_DEFAULT_24G_INDEX;
+			}
+			for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+				if (TxCount == 0) {
+					pwrInfo24G->BW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF;
+					pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF;
+				} else {
+					pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+					pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+					pwrInfo24G->CCK_Diff[rfPath][TxCount] =	EEPROM_DEFAULT_DIFF;
+					pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+				}
+			}
+		}
+		return;
+	}
+
+	for (rfPath = 0; rfPath < MAX_RF_PATH; rfPath++) {
+		/* 2.4G default value */
+		for (group = 0; group < MAX_CHNL_GROUP_24G; group++) {
+			pwrInfo24G->IndexCCK_Base[rfPath][group] =	PROMContent[eeAddr++];
+			if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF)
+				pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
+		}
+		for (group = 0; group < MAX_CHNL_GROUP_24G-1; group++) {
+			pwrInfo24G->IndexBW40_Base[rfPath][group] =	PROMContent[eeAddr++];
+			if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF)
+				pwrInfo24G->IndexBW40_Base[rfPath][group] =	EEPROM_DEFAULT_24G_INDEX;
+		}
+		for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+			if (TxCount == 0) {
+				pwrInfo24G->BW40_Diff[rfPath][TxCount] = 0;
+				if (PROMContent[eeAddr] == 0xFF) {
+					pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF;
+				} else {
+					pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
+					if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3)		/* 4bit sign number to 8 bit sign number */
+						pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
+				}
+
+				if (PROMContent[eeAddr] == 0xFF) {
+					pwrInfo24G->OFDM_Diff[rfPath][TxCount] =	EEPROM_DEFAULT_24G_OFDM_DIFF;
+				} else {
+					pwrInfo24G->OFDM_Diff[rfPath][TxCount] =	(PROMContent[eeAddr]&0x0f);
+					if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3)		/* 4bit sign number to 8 bit sign number */
+						pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
+				}
+				pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0;
+				eeAddr++;
+			} else {
+				if (PROMContent[eeAddr] == 0xFF) {
+					pwrInfo24G->BW40_Diff[rfPath][TxCount] =	EEPROM_DEFAULT_DIFF;
+				} else {
+					pwrInfo24G->BW40_Diff[rfPath][TxCount] =	(PROMContent[eeAddr]&0xf0)>>4;
+					if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT3)		/* 4bit sign number to 8 bit sign number */
+						pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0;
+				}
+
+				if (PROMContent[eeAddr] == 0xFF) {
+					pwrInfo24G->BW20_Diff[rfPath][TxCount] =	EEPROM_DEFAULT_DIFF;
+				} else {
+					pwrInfo24G->BW20_Diff[rfPath][TxCount] =	(PROMContent[eeAddr]&0x0f);
+					if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT3)		/* 4bit sign number to 8 bit sign number */
+						pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
+				}
+				eeAddr++;
+
+				if (PROMContent[eeAddr] == 0xFF) {
+					pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
+				} else {
+					pwrInfo24G->OFDM_Diff[rfPath][TxCount] =	(PROMContent[eeAddr]&0xf0)>>4;
+					if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT3)		/* 4bit sign number to 8 bit sign number */
+						pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
+				}
+
+				if (PROMContent[eeAddr] == 0xFF) {
+					pwrInfo24G->CCK_Diff[rfPath][TxCount] =	EEPROM_DEFAULT_DIFF;
+				} else {
+					pwrInfo24G->CCK_Diff[rfPath][TxCount] =	(PROMContent[eeAddr]&0x0f);
+					if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT3)		/* 4bit sign number to 8 bit sign number */
+						pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0;
+				}
+				eeAddr++;
+			}
+		}
+	}
+}
+
+static u8 Hal_GetChnlGroup88E(u8 chnl, u8 *pGroup)
+{
+	u8 bIn24G = true;
+
+	if (chnl <= 14) {
+		bIn24G = true;
+
+		if (chnl < 3)			/*  Chanel 1-2 */
+			*pGroup = 0;
+		else if (chnl < 6)		/*  Channel 3-5 */
+			*pGroup = 1;
+		else	 if (chnl < 9)		/*  Channel 6-8 */
+			*pGroup = 2;
+		else if (chnl < 12)		/*  Channel 9-11 */
+			*pGroup = 3;
+		else if (chnl < 14)		/*  Channel 12-13 */
+			*pGroup = 4;
+		else if (chnl == 14)		/*  Channel 14 */
+			*pGroup = 5;
+	} else {
+		bIn24G = false;
+
+		if (chnl <= 40)
+			*pGroup = 0;
+		else if (chnl <= 48)
+			*pGroup = 1;
+		else	 if (chnl <= 56)
+			*pGroup = 2;
+		else if (chnl <= 64)
+			*pGroup = 3;
+		else if (chnl <= 104)
+			*pGroup = 4;
+		else if (chnl <= 112)
+			*pGroup = 5;
+		else if (chnl <= 120)
+			*pGroup = 5;
+		else if (chnl <= 128)
+			*pGroup = 6;
+		else if (chnl <= 136)
+			*pGroup = 7;
+		else if (chnl <= 144)
+			*pGroup = 8;
+		else if (chnl <= 153)
+			*pGroup = 9;
+		else if (chnl <= 161)
+			*pGroup = 10;
+		else if (chnl <= 177)
+			*pGroup = 11;
+	}
+	return bIn24G;
+}
+
+void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+	if (AutoLoadFail) {
+		padapter->pwrctrlpriv.bHWPowerdown = false;
+		padapter->pwrctrlpriv.bSupportRemoteWakeup = false;
+	} else {
+		/* hw power down mode selection , 0:rf-off / 1:power down */
+
+		if (padapter->registrypriv.hwpdn_mode == 2)
+			padapter->pwrctrlpriv.bHWPowerdown = (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & BIT4);
+		else
+			padapter->pwrctrlpriv.bHWPowerdown = padapter->registrypriv.hwpdn_mode;
+
+		/*  decide hw if support remote wakeup function */
+		/*  if hw supported, 8051 (SIE) will generate WeakUP signal(D+/D- toggle) when autoresume */
+		padapter->pwrctrlpriv.bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT1) ? true : false;
+
+		DBG_88E("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) , bSupportRemoteWakeup(%x)\n", __func__,
+		padapter->pwrctrlpriv.bHWPwrPindetect, padapter->pwrctrlpriv.bHWPowerdown , padapter->pwrctrlpriv.bSupportRemoteWakeup);
+
+		DBG_88E("### PS params =>  power_mgnt(%x), usbss_enable(%x) ###\n", padapter->registrypriv.power_mgnt, padapter->registrypriv.usbss_enable);
+	}
+}
+
+void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct txpowerinfo24g pwrInfo24G;
+	u8 rfPath, ch, group;
+	u8 bIn24G, TxCount;
+
+	Hal_ReadPowerValueFromPROM_8188E(&pwrInfo24G, PROMContent, AutoLoadFail);
+
+	if (!AutoLoadFail)
+		pHalData->bTXPowerDataReadFromEEPORM = true;
+
+	for (rfPath = 0; rfPath < pHalData->NumTotalRFPath; rfPath++) {
+		for (ch = 0; ch <= CHANNEL_MAX_NUMBER; ch++) {
+			bIn24G = Hal_GetChnlGroup88E(ch, &group);
+			if (bIn24G) {
+				pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group];
+				if (ch == 14)
+					pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][4];
+				else
+					pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group];
+			}
+			if (bIn24G) {
+				DBG_88E("======= Path %d, Channel %d =======\n", rfPath, ch);
+				DBG_88E("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_CCK_Base[rfPath][ch]);
+				DBG_88E("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch , pHalData->Index24G_BW40_Base[rfPath][ch]);
+			}
+		}
+		for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) {
+			pHalData->CCK_24G_Diff[rfPath][TxCount] = pwrInfo24G.CCK_Diff[rfPath][TxCount];
+			pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount];
+			pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount];
+			pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount];
+			DBG_88E("======= TxCount %d =======\n", TxCount);
+			DBG_88E("CCK_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount]);
+			DBG_88E("OFDM_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount]);
+			DBG_88E("BW20_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount]);
+			DBG_88E("BW40_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount]);
+		}
+	}
+
+	/*  2010/10/19 MH Add Regulator recognize for CU. */
+	if (!AutoLoadFail) {
+		pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x7);	/* bit0~2 */
+		if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
+			pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7);	/* bit0~2 */
+	} else {
+		pHalData->EEPROMRegulatory = 0;
+	}
+	DBG_88E("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory);
+}
+
+void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+
+	if (!AutoLoadFail) {
+		pHalData->CrystalCap = hwinfo[EEPROM_XTAL_88E];
+		if (pHalData->CrystalCap == 0xFF)
+			pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
+	} else {
+		pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E;
+	}
+	DBG_88E("CrystalCap: 0x%2x\n", pHalData->CrystalCap);
+}
+
+void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+	if (!AutoLoadFail)
+		pHalData->BoardType = ((hwinfo[EEPROM_RF_BOARD_OPTION_88E]&0xE0)>>5);
+	else
+		pHalData->BoardType = 0;
+	DBG_88E("Board Type: 0x%2x\n", pHalData->BoardType);
+}
+
+void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+
+	if (!AutoLoadFail) {
+		pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_88E];
+		if (pHalData->EEPROMVersion == 0xFF)
+			pHalData->EEPROMVersion = EEPROM_Default_Version;
+	} else {
+		pHalData->EEPROMVersion = 1;
+	}
+	RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+		 ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n",
+		 pHalData->EEPROMVersion));
+}
+
+void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+	padapter->mlmepriv.ChannelPlan =
+		 hal_com_get_channel_plan(padapter,
+					  hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF,
+					  padapter->registrypriv.channel_plan,
+					  RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail);
+
+	DBG_88E("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan);
+}
+
+void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+
+	if (!AutoLoadFail) {
+		pHalData->EEPROMCustomerID = hwinfo[EEPROM_CUSTOMERID_88E];
+	} else {
+		pHalData->EEPROMCustomerID = 0;
+		pHalData->EEPROMSubCustomerID = 0;
+	}
+	DBG_88E("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID);
+}
+
+void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool AutoLoadFail)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+	struct registry_priv	*registry_par = &pAdapter->registrypriv;
+
+	if (!AutoLoadFail) {
+		/*  Antenna Diversity setting. */
+		if (registry_par->antdiv_cfg == 2) { /*  2:By EFUSE */
+			pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x18)>>3;
+			if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
+				pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION&0x18)>>3;;
+		} else {
+			pHalData->AntDivCfg = registry_par->antdiv_cfg;  /*  0:OFF , 1:ON, 2:By EFUSE */
+		}
+
+		if (registry_par->antdiv_type == 0) {
+			/* If TRxAntDivType is AUTO in advanced setting, use EFUSE value instead. */
+			pHalData->TRxAntDivType = PROMContent[EEPROM_RF_ANTENNA_OPT_88E];
+			if (pHalData->TRxAntDivType == 0xFF)
+				pHalData->TRxAntDivType = CG_TRX_HW_ANTDIV; /*  For 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */
+		} else {
+			pHalData->TRxAntDivType = registry_par->antdiv_type;
+		}
+
+		if (pHalData->TRxAntDivType == CG_TRX_HW_ANTDIV || pHalData->TRxAntDivType == CGCS_RX_HW_ANTDIV)
+			pHalData->AntDivCfg = 1; /*  0xC1[3] is ignored. */
+	} else {
+		pHalData->AntDivCfg = 0;
+		pHalData->TRxAntDivType = pHalData->TRxAntDivType; /*  The value in the driver setting of device manager. */
+	}
+	DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType);
+}
+
+void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+
+	/*  ThermalMeter from EEPROM */
+	if (!AutoloadFail)
+		pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_88E];
+	else
+		pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
+
+	if (pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) {
+		pHalData->bAPKThermalMeterIgnore = true;
+		pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E;
+	}
+	DBG_88E("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter);
+}
+
+void Hal_InitChannelPlan(struct adapter *padapter)
+{
+}
+
+bool HalDetectPwrDownMode88E(struct adapter *Adapter)
+{
+	u8 tmpvalue = 0;
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+
+	EFUSE_ShadowRead(Adapter, 1, EEPROM_RF_FEATURE_OPTION_88E, (u32 *)&tmpvalue);
+
+	/*  2010/08/25 MH INF priority > PDN Efuse value. */
+	if (tmpvalue & BIT(4) && pwrctrlpriv->reg_pdnmode)
+		pHalData->pwrdown = true;
+	else
+		pHalData->pwrdown = false;
+
+	DBG_88E("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown);
+
+	return pHalData->pwrdown;
+}	/*  HalDetectPwrDownMode */
+
+/*  This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */
+/*  We just reserve the value of the register in variable pHalData->RegBcnCtrlVal and then operate */
+/*  the value of the register via atomic operation. */
+/*  This prevents from race condition when setting this register. */
+/*  The value of pHalData->RegBcnCtrlVal is initialized in HwConfigureRTL8192CE() function. */
+
+void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits)
+{
+	struct hal_data_8188e *pHalData;
+
+	pHalData = GET_HAL_DATA(padapter);
+
+	pHalData->RegBcnCtrlVal |= SetBits;
+	pHalData->RegBcnCtrlVal &= ~ClearBits;
+
+	rtw_write8(padapter, REG_BCN_CTRL, (u8)pHalData->RegBcnCtrlVal);
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c b/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
new file mode 100644
index 0000000..e97ba02
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_mp.c
@@ -0,0 +1,860 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_MP_C_
+
+#include <drv_types.h>
+#include <rtw_mp.h>
+#include <rtl8188e_hal.h>
+#include <rtl8188e_dm.h>
+
+s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+
+	if (!netif_running(padapter->pnetdev)) {
+		RT_TRACE(_module_mp_, _drv_warning_,
+			 ("SetPowerTracking! Fail: interface not opened!\n"));
+		return _FAIL;
+	}
+
+	if (!check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE)) {
+		RT_TRACE(_module_mp_, _drv_warning_,
+			 ("SetPowerTracking! Fail: not in MP mode!\n"));
+		return _FAIL;
+	}
+
+	if (enable)
+		pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true;
+	else
+		pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false;
+
+	return _SUCCESS;
+}
+
+void Hal_GetPowerTracking(struct adapter *padapter, u8 *enable)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+
+	*enable = pDM_Odm->RFCalibrateInfo.TxPowerTrackControl;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	mpt_SwitchRfSetting
+ *
+ * Overview:	Change RF Setting when we siwthc channel/rate/BW for MP.
+ *
+ * Input:	struct adapter *				pAdapter
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 01/08/2009	MHC		Suggestion from SD3 Willis for 92S series.
+ * 01/09/2009	MHC		Add CCK modification for 40MHZ. Suggestion from SD3.
+ *
+ *---------------------------------------------------------------------------*/
+void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter)
+{
+	struct mp_priv	*pmp = &pAdapter->mppriv;
+
+	/*  <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. */
+		pmp->MptCtx.backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0);
+		pmp->MptCtx.backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0);
+		PHY_SetRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0, 0xD);
+		PHY_SetRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0, 0xD);
+
+	return;
+}
+/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/
+
+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
+void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14)
+{
+	u32		TempVal = 0, TempVal2 = 0, TempVal3 = 0;
+	u32		CurrCCKSwingVal = 0, CCKSwingIndex = 12;
+	u8		i;
+
+	/*  get current cck swing value and check 0xa22 & 0xa23 later to match the table. */
+	CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord);
+
+	if (!bInCH14) {
+		/*  Readback the current bb cck swing value and compare with the table to */
+		/*  get the current swing index */
+		for (i = 0; i < CCK_TABLE_SIZE; i++) {
+			if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch1_Ch13[i][0]) &&
+			    (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch1_Ch13[i][1])) {
+				CCKSwingIndex = i;
+				break;
+			}
+		}
+
+		/* Write 0xa22 0xa23 */
+		TempVal = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][0] +
+				(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][1]<<8);
+
+
+		/* Write 0xa24 ~ 0xa27 */
+		TempVal2 = 0;
+		TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] +
+				(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3]<<8) +
+				(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4]<<16)+
+				(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5]<<24);
+
+		/* Write 0xa28  0xa29 */
+		TempVal3 = 0;
+		TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] +
+				(CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7]<<8);
+	} else {
+		for (i = 0; i < CCK_TABLE_SIZE; i++) {
+			if (((CurrCCKSwingVal&0xff) == (u32)CCKSwingTable_Ch14[i][0]) &&
+			    (((CurrCCKSwingVal&0xff00)>>8) == (u32)CCKSwingTable_Ch14[i][1])) {
+				CCKSwingIndex = i;
+				break;
+			}
+		}
+
+		/* Write 0xa22 0xa23 */
+		TempVal = CCKSwingTable_Ch14[CCKSwingIndex][0] +
+				(CCKSwingTable_Ch14[CCKSwingIndex][1]<<8);
+
+		/* Write 0xa24 ~ 0xa27 */
+		TempVal2 = 0;
+		TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] +
+				(CCKSwingTable_Ch14[CCKSwingIndex][3]<<8) +
+				(CCKSwingTable_Ch14[CCKSwingIndex][4]<<16)+
+				(CCKSwingTable_Ch14[CCKSwingIndex][5]<<24);
+
+		/* Write 0xa28  0xa29 */
+		TempVal3 = 0;
+		TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] +
+				(CCKSwingTable_Ch14[CCKSwingIndex][7]<<8);
+	}
+
+	write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal);
+	write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2);
+	write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3);
+}
+
+void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+	struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx;
+	struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+	s32		TempCCk;
+	u8		CCK_index, CCK_index_old = 0;
+	u8		Action = 0;	/* 0: no action, 1: even->odd, 2:odd->even */
+	s32		i = 0;
+
+
+	if (!IS_92C_SERIAL(pHalData->VersionID))
+		return;
+	if (beven && !pMptCtx->bMptIndexEven) {
+		/* odd->even */
+		Action = 2;
+		pMptCtx->bMptIndexEven = true;
+	} else if (!beven && pMptCtx->bMptIndexEven) {
+		/* even->odd */
+		Action = 1;
+		pMptCtx->bMptIndexEven = false;
+	}
+
+	if (Action != 0) {
+		/* Query CCK default setting From 0xa24 */
+		TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK;
+		for (i = 0; i < CCK_TABLE_SIZE; i++) {
+			if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+				if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) {
+					CCK_index_old = (u8)i;
+					break;
+				}
+			} else {
+				if (_rtw_memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) {
+					CCK_index_old = (u8)i;
+					break;
+				}
+			}
+		}
+
+		if (Action == 1)
+			CCK_index = CCK_index_old - 1;
+		else
+			CCK_index = CCK_index_old + 1;
+
+		/* Adjust CCK according to gain index */
+		if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+			rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]);
+			rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]);
+			rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]);
+			rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]);
+			rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]);
+			rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]);
+			rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]);
+			rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]);
+		} else {
+			rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch14[CCK_index][0]);
+			rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch14[CCK_index][1]);
+			rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch14[CCK_index][2]);
+			rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch14[CCK_index][3]);
+			rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch14[CCK_index][4]);
+			rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch14[CCK_index][5]);
+			rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch14[CCK_index][6]);
+			rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch14[CCK_index][7]);
+		}
+	}
+}
+/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/
+
+/*
+ * SetChannel
+ * Description
+ *	Use H2C command to change channel,
+ *	not only modify rf register, but also other setting need to be done.
+ */
+void Hal_SetChannel(struct adapter *pAdapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+	struct mp_priv	*pmp = &pAdapter->mppriv;
+	struct odm_dm_struct *pDM_Odm = &(pHalData->odmpriv);
+	u8		eRFPath;
+	u8		channel = pmp->channel;
+
+	/*  set RF channel register */
+	for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++)
+		_write_rfreg(pAdapter, eRFPath, ODM_CHANNEL, 0x3FF, channel);
+	Hal_mpt_SwitchRfSetting(pAdapter);
+
+	SelectChannel(pAdapter, channel);
+
+	if (pHalData->CurrentChannel == 14 && !pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+		pDM_Odm->RFCalibrateInfo.bCCKinCH14 = true;
+		Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14);
+	} else if (pHalData->CurrentChannel != 14 && pDM_Odm->RFCalibrateInfo.bCCKinCH14) {
+		pDM_Odm->RFCalibrateInfo.bCCKinCH14 = false;
+		Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14);
+	}
+}
+
+/*
+ * Notice
+ *	Switch bandwitdth may change center frequency(channel)
+ */
+void Hal_SetBandwidth(struct adapter *pAdapter)
+{
+	struct mp_priv *pmp = &pAdapter->mppriv;
+
+
+	SetBWMode(pAdapter, pmp->bandwidth, pmp->prime_channel_offset);
+	Hal_mpt_SwitchRfSetting(pAdapter);
+}
+
+void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 *TxPower)
+{
+	u32 tmpval = 0;
+
+
+	/*  rf-A cck tx power */
+	write_bbreg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, TxPower[RF_PATH_A]);
+	tmpval = (TxPower[RF_PATH_A]<<16) | (TxPower[RF_PATH_A]<<8) | TxPower[RF_PATH_A];
+	write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+	/*  rf-B cck tx power */
+	write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, TxPower[RF_PATH_B]);
+	tmpval = (TxPower[RF_PATH_B]<<16) | (TxPower[RF_PATH_B]<<8) | TxPower[RF_PATH_B];
+	write_bbreg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
+
+	RT_TRACE(_module_mp_, _drv_notice_,
+		 ("-SetCCKTxPower: A[0x%02x] B[0x%02x]\n",
+		  TxPower[RF_PATH_A], TxPower[RF_PATH_B]));
+}
+
+void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 *TxPower)
+{
+	u32 TxAGC = 0;
+	u8 tmpval = 0;
+
+	/*  HT Tx-rf(A) */
+	tmpval = TxPower[RF_PATH_A];
+	TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval;
+
+	write_bbreg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC);
+
+	/*  HT Tx-rf(B) */
+	tmpval = TxPower[RF_PATH_B];
+	TxAGC = (tmpval<<24) | (tmpval<<16) | (tmpval<<8) | tmpval;
+
+	write_bbreg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC);
+	write_bbreg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC);
+}
+
+void Hal_SetAntennaPathPower(struct adapter *pAdapter)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+	u8 TxPowerLevel[MAX_RF_PATH_NUMS];
+	u8 rfPath;
+
+	TxPowerLevel[RF_PATH_A] = pAdapter->mppriv.txpoweridx;
+	TxPowerLevel[RF_PATH_B] = pAdapter->mppriv.txpoweridx_b;
+
+	switch (pAdapter->mppriv.antenna_tx) {
+	case ANTENNA_A:
+	default:
+		rfPath = RF_PATH_A;
+		break;
+	case ANTENNA_B:
+		rfPath = RF_PATH_B;
+		break;
+	case ANTENNA_C:
+		rfPath = RF_PATH_C;
+		break;
+	}
+
+	switch (pHalData->rf_chip) {
+	case RF_8225:
+	case RF_8256:
+	case RF_6052:
+		Hal_SetCCKTxPower(pAdapter, TxPowerLevel);
+		if (pAdapter->mppriv.rateidx < MPT_RATE_6M)	/*  CCK rate */
+			Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0);
+		Hal_SetOFDMTxPower(pAdapter, TxPowerLevel);
+		break;
+	default:
+		break;
+	}
+}
+
+void Hal_SetTxPower(struct adapter *pAdapter)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+	u8 TxPower = pAdapter->mppriv.txpoweridx;
+	u8 TxPowerLevel[MAX_RF_PATH_NUMS];
+	u8 rf, rfPath;
+
+	for (rf = 0; rf < MAX_RF_PATH_NUMS; rf++)
+		TxPowerLevel[rf] = TxPower;
+
+	switch (pAdapter->mppriv.antenna_tx) {
+	case ANTENNA_A:
+	default:
+		rfPath = RF_PATH_A;
+		break;
+	case ANTENNA_B:
+		rfPath = RF_PATH_B;
+		break;
+	case ANTENNA_C:
+		rfPath = RF_PATH_C;
+		break;
+	}
+
+	switch (pHalData->rf_chip) {
+	/*  2008/09/12 MH Test only !! We enable the TX power tracking for MP!!!!! */
+	/*  We should call normal driver API later!! */
+	case RF_8225:
+	case RF_8256:
+	case RF_6052:
+		Hal_SetCCKTxPower(pAdapter, TxPowerLevel);
+		if (pAdapter->mppriv.rateidx < MPT_RATE_6M)	/*  CCK rate */
+			Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath]%2 == 0);
+		Hal_SetOFDMTxPower(pAdapter, TxPowerLevel);
+		break;
+	default:
+		break;
+	}
+}
+
+void Hal_SetDataRate(struct adapter *pAdapter)
+{
+	Hal_mpt_SwitchRfSetting(pAdapter);
+}
+
+void Hal_SetAntenna(struct adapter *pAdapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+
+	struct ant_sel_ofdm *p_ofdm_tx;	/* OFDM Tx register */
+	struct ant_sel_cck *p_cck_txrx;
+	u8	r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0;
+	u8	chgTx = 0, chgRx = 0;
+	u32	r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0;
+
+
+	p_ofdm_tx = (struct ant_sel_ofdm *)&r_ant_select_ofdm_val;
+	p_cck_txrx = (struct ant_sel_cck *)&r_ant_select_cck_val;
+
+	p_ofdm_tx->r_ant_ht1	= 0x1;
+	p_ofdm_tx->r_ant_ht2	= 0x2;	/*  Second TX RF path is A */
+	p_ofdm_tx->r_ant_non_ht = 0x3;	/*  0x1+0x2=0x3 */
+
+	switch (pAdapter->mppriv.antenna_tx) {
+	case ANTENNA_A:
+		p_ofdm_tx->r_tx_antenna		= 0x1;
+		r_ofdm_tx_en_val		= 0x1;
+		p_ofdm_tx->r_ant_l		= 0x1;
+		p_ofdm_tx->r_ant_ht_s1		= 0x1;
+		p_ofdm_tx->r_ant_non_ht_s1	= 0x1;
+		p_cck_txrx->r_ccktx_enable	= 0x8;
+		chgTx = 1;
+
+		/*  From SD3 Willis suggestion !!! Set RF A=TX and B as standby */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1);
+		r_ofdm_tx_en_val		= 0x3;
+
+		/*  Power save */
+
+		/*  We need to close RFB by SW control */
+		if (pHalData->rf_type == RF_2T2R) {
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 1);
+			PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 0);
+		}
+		break;
+	case ANTENNA_B:
+		p_ofdm_tx->r_tx_antenna		= 0x2;
+		r_ofdm_tx_en_val		= 0x2;
+		p_ofdm_tx->r_ant_l		= 0x2;
+		p_ofdm_tx->r_ant_ht_s1		= 0x2;
+		p_ofdm_tx->r_ant_non_ht_s1	= 0x2;
+		p_cck_txrx->r_ccktx_enable	= 0x4;
+		chgTx = 1;
+		/*  From SD3 Willis suggestion !!! Set RF A as standby */
+		PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1);
+		PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2);
+
+		/*  Power save */
+		/* cosa r_ant_select_ofdm_val = 0x22222222; */
+
+		/*  2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table. */
+		/*  2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control */
+		if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) {
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 1);
+			PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1);
+		}
+		break;
+	case ANTENNA_AB:	/*  For 8192S */
+		p_ofdm_tx->r_tx_antenna		= 0x3;
+		r_ofdm_tx_en_val		= 0x3;
+		p_ofdm_tx->r_ant_l		= 0x3;
+		p_ofdm_tx->r_ant_ht_s1		= 0x3;
+		p_ofdm_tx->r_ant_non_ht_s1	= 0x3;
+		p_cck_txrx->r_ccktx_enable	= 0xC;
+		chgTx = 1;
+
+		/*  From SD3 Willis suggestion !!! Set RF B as standby */
+		PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2);
+		PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2);
+
+		/*  Disable Power save */
+		/* cosa r_ant_select_ofdm_val = 0x3321333; */
+		/*  2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control */
+		if (pHalData->rf_type == RF_2T2R) {
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1);
+			PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1);
+		}
+		break;
+	default:
+		break;
+	}
+
+	/*  r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D */
+	/*  r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D */
+	/*  r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D */
+	switch (pAdapter->mppriv.antenna_rx) {
+	case ANTENNA_A:
+		r_rx_antenna_ofdm		= 0x1;	/*  A */
+		p_cck_txrx->r_cckrx_enable	= 0x0;	/*  default: A */
+		p_cck_txrx->r_cckrx_enable_2	= 0x0;	/*  option: A */
+		chgRx = 1;
+		break;
+	case ANTENNA_B:
+		r_rx_antenna_ofdm		= 0x2;	/*  B */
+		p_cck_txrx->r_cckrx_enable	= 0x1;	/*  default: B */
+		p_cck_txrx->r_cckrx_enable_2	= 0x1;	/*  option: B */
+		chgRx = 1;
+		break;
+	case ANTENNA_AB:
+		r_rx_antenna_ofdm		= 0x3;	/*  AB */
+		p_cck_txrx->r_cckrx_enable	= 0x0;	/*  default:A */
+		p_cck_txrx->r_cckrx_enable_2	= 0x1;	/*  option:B */
+		chgRx = 1;
+		break;
+	default:
+		break;
+	}
+
+	if (chgTx && chgRx) {
+		switch (pHalData->rf_chip) {
+		case RF_8225:
+		case RF_8256:
+		case RF_6052:
+			/* r_ant_sel_cck_val = r_ant_select_cck_val; */
+			PHY_SetBBReg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val);	/* OFDM Tx */
+			PHY_SetBBReg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val);		/* OFDM Tx */
+			PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm);	/* OFDM Rx */
+			PHY_SetBBReg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm);	/* OFDM Rx */
+			PHY_SetBBReg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val);	/* CCK TxRx */
+
+			break;
+		default:
+			break;
+		}
+	}
+
+	RT_TRACE(_module_mp_, _drv_notice_, ("-SwitchAntenna: finished\n"));
+}
+
+s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
+
+
+	if (!netif_running(pAdapter->pnetdev)) {
+		RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter! Fail: interface not opened!\n"));
+		return _FAIL;
+	}
+
+	if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == false) {
+		RT_TRACE(_module_mp_, _drv_warning_, ("SetThermalMeter: Fail! not in MP mode!\n"));
+		return _FAIL;
+	}
+
+	target_ther &= 0xff;
+	if (target_ther < 0x07)
+		target_ther = 0x07;
+	else if (target_ther > 0x1d)
+		target_ther = 0x1d;
+
+	pHalData->EEPROMThermalMeter = target_ther;
+
+	return _SUCCESS;
+}
+
+void Hal_TriggerRFThermalMeter(struct adapter *pAdapter)
+{
+	_write_rfreg(pAdapter, RF_PATH_A , RF_T_METER_88E , BIT17 | BIT16 , 0x03);
+}
+
+u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter)
+{
+	u32 ThermalValue = 0;
+
+	ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, 0xfc00);
+	return (u8)ThermalValue;
+}
+
+void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value)
+{
+	Hal_TriggerRFThermalMeter(pAdapter);
+	rtw_msleep_os(1000);
+	*value = Hal_ReadRFThermalMeter(pAdapter);
+}
+
+void Hal_SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart)
+{
+	pAdapter->mppriv.MptCtx.bSingleCarrier = bStart;
+	if (bStart) {
+		/*  Start Single Carrier. */
+		RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test start\n"));
+		/*  1. if OFDM block on? */
+		if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn))
+			write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */
+
+		/*  2. set CCK test mode off, set to CCK normal mode */
+		write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable);
+		/*  3. turn on scramble setting */
+		write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);
+		/*  4. Turn On Single Carrier Tx and turn off the other test modes. */
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+		/* for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+	} else {
+		/*  Stop Single Carrier. */
+		RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleCarrierTx: test stop\n"));
+
+		/*  Turn off all test modes. */
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+		rtw_msleep_os(10);
+
+		/* BB Reset */
+		write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+		write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+
+		/* Stop for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+	}
+}
+
+
+void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(pAdapter);
+	bool		is92C = IS_92C_SERIAL(pHalData->VersionID);
+
+	u8 rfPath;
+	u32              reg58 = 0x0;
+	switch (pAdapter->mppriv.antenna_tx) {
+	case ANTENNA_A:
+	default:
+		rfPath = RF_PATH_A;
+		break;
+	case ANTENNA_B:
+		rfPath = RF_PATH_B;
+		break;
+	case ANTENNA_C:
+		rfPath = RF_PATH_C;
+		break;
+	}
+
+	pAdapter->mppriv.MptCtx.bSingleTone = bStart;
+	if (bStart) {
+		/*  Start Single Tone. */
+		RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test start\n"));
+		/*  <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */
+		if (IS_HARDWARE_TYPE_8188E(pAdapter)) {
+			reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask);
+			reg58 &= 0xFFFFFFF0;
+			reg58 += 2;
+			PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58);
+		}
+		PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0);
+		PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0);
+
+		if (is92C) {
+			_write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x01);
+			rtw_usleep_os(100);
+			if (rfPath == RF_PATH_A)
+				write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x10000); /*  PAD all on. */
+			else if (rfPath == RF_PATH_B)
+				write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x10000); /*  PAD all on. */
+			write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /*  PAD all on. */
+			rtw_usleep_os(100);
+		} else {
+			write_rfreg(pAdapter, rfPath, 0x21, 0xd4000);
+			rtw_usleep_os(100);
+			write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /*  PAD all on. */
+			rtw_usleep_os(100);
+		}
+
+		/* for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+
+	} else {
+		/*  Stop Single Tone. */
+		RT_TRACE(_module_mp_, _drv_alert_, ("SetSingleToneTx: test stop\n"));
+
+		/*  <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */
+		/*  <20120326, Kordan> Only in single tone mode. (asked by Edlu) */
+		if (IS_HARDWARE_TYPE_8188E(pAdapter)) {
+			reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask);
+			reg58 &= 0xFFFFFFF0;
+			PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58);
+		}
+		write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1);
+		write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1);
+		if (is92C) {
+			_write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT19, 0x00);
+			rtw_usleep_os(100);
+			write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x32d75); /*  PAD all on. */
+			write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x32d75); /*  PAD all on. */
+			rtw_usleep_os(100);
+		} else {
+			write_rfreg(pAdapter, rfPath, 0x21, 0x54000);
+			rtw_usleep_os(100);
+			write_rfreg(pAdapter, rfPath, 0x00, 0x30000); /*  PAD all on. */
+			rtw_usleep_os(100);
+		}
+
+		/* Stop for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+	}
+}
+
+
+
+void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart)
+{
+	pAdapter->mppriv.MptCtx.bCarrierSuppression = bStart;
+	if (bStart) {
+		/*  Start Carrier Suppression. */
+		RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test start\n"));
+		if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) {
+			/*  1. if CCK block on? */
+			if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn))
+				write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */
+
+			/* Turn Off All Test Mode */
+			write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+			write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+			write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+
+			write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2);    /* transmit mode */
+			write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0);  /* turn off scramble setting */
+
+			/* Set CCK Tx Test Rate */
+			write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0);    /* Set FTxRate to 1Mbps */
+		}
+
+		/* for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+	} else {
+		/*  Stop Carrier Suppression. */
+		RT_TRACE(_module_mp_, _drv_alert_, ("SetCarrierSuppressionTx: test stop\n"));
+		if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) {
+			write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0);    /* normal mode */
+			write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1);  /* turn on scramble setting */
+
+			/* BB Reset */
+			write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+			write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+		}
+
+		/* Stop for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+	}
+}
+
+void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+	u32 cckrate;
+
+	if (bStart) {
+		RT_TRACE(_module_mp_, _drv_alert_,
+			 ("SetCCKContinuousTx: test start\n"));
+
+		/*  1. if CCK block on? */
+		if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn))
+			write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */
+
+		/* Turn Off All Test Mode */
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+		/* Set CCK Tx Test Rate */
+		cckrate  = pAdapter->mppriv.rateidx;
+		write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, cckrate);
+		write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2);	/* transmit mode */
+		write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);	/* turn on scramble setting */
+
+		/* for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+	} else {
+		RT_TRACE(_module_mp_, _drv_info_,
+			 ("SetCCKContinuousTx: test stop\n"));
+
+		write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0);	/* normal mode */
+		write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);	/* turn on scramble setting */
+
+		/* BB Reset */
+		write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+		write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+
+		/* Stop for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+	}
+
+	pAdapter->mppriv.MptCtx.bCckContTx = bStart;
+	pAdapter->mppriv.MptCtx.bOfdmContTx = false;
+} /* mpt_StartCckContTx */
+
+void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+	if (bStart) {
+		RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test start\n"));
+		/*  1. if OFDM block on? */
+		if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn))
+			write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */
+
+		/*  2. set CCK test mode off, set to CCK normal mode */
+		write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable);
+
+		/*  3. turn on scramble setting */
+		write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable);
+		/*  4. Turn On Continue Tx and turn off the other test modes. */
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+
+		/* for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500);
+
+	} else {
+		RT_TRACE(_module_mp_, _drv_info_, ("SetOFDMContinuousTx: test stop\n"));
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable);
+		write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable);
+		/* Delay 10 ms */
+		rtw_msleep_os(10);
+		/* BB Reset */
+		write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0);
+		write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1);
+
+		/* Stop for dynamic set Power index. */
+		write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100);
+		write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100);
+	}
+
+	pAdapter->mppriv.MptCtx.bCckContTx = false;
+	pAdapter->mppriv.MptCtx.bOfdmContTx = bStart;
+} /* mpt_StartOfdmContTx */
+
+void Hal_SetContinuousTx(struct adapter *pAdapter, u8 bStart)
+{
+	RT_TRACE(_module_mp_, _drv_info_,
+		 ("SetContinuousTx: rate:%d\n", pAdapter->mppriv.rateidx));
+
+	pAdapter->mppriv.MptCtx.bStartContTx = bStart;
+	if (pAdapter->mppriv.rateidx <= MPT_RATE_11M)
+		Hal_SetCCKContinuousTx(pAdapter, bStart);
+	else if ((pAdapter->mppriv.rateidx >= MPT_RATE_6M) &&
+		 (pAdapter->mppriv.rateidx <= MPT_RATE_MCS15))
+		Hal_SetOFDMContinuousTx(pAdapter, bStart);
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c
new file mode 100644
index 0000000..ff468a68
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_phycfg.c
@@ -0,0 +1,1144 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_PHYCFG_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_iol.h>
+#include <rtl8188e_hal.h>
+
+/*---------------------------Define Local Constant---------------------------*/
+/* Channel switch:The size of command tables for switch channel*/
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+/*---------------------------Define Local Constant---------------------------*/
+
+
+/*------------------------Define global variable-----------------------------*/
+
+/*------------------------Define local variable------------------------------*/
+
+
+/*--------------------Define export function prototype-----------------------*/
+/*  Please refer to header file */
+/*--------------------Define export function prototype-----------------------*/
+
+/*----------------------------Function Body----------------------------------*/
+/*  */
+/*  1. BB register R/W API */
+/*  */
+
+/**
+* Function:	phy_CalculateBitShift
+*
+* OverView:	Get shifted position of the BitMask
+*
+* Input:
+*			u32		BitMask,
+*
+* Output:	none
+* Return:		u32		Return the shift bit bit position of the mask
+*/
+static	u32 phy_CalculateBitShift(u32 BitMask)
+{
+	u32 i;
+
+	for (i = 0; i <= 31; i++) {
+		if (((BitMask>>i) &  0x1) == 1)
+			break;
+	}
+	return i;
+}
+
+/**
+* Function:	PHY_QueryBBReg
+*
+* OverView:	Read "sepcific bits" from BB register
+*
+* Input:
+*			struct adapter *Adapter,
+*			u32			RegAddr,	The target address to be readback
+*			u32			BitMask		The target bit position in the target address
+*								to be readback
+* Output:	None
+* Return:		u32			Data		The readback register value
+* Note:		This function is equal to "GetRegSetting" in PHY programming guide
+*/
+u32
+rtl8188e_PHY_QueryBBReg(
+		struct adapter *Adapter,
+		u32 RegAddr,
+		u32 BitMask
+	)
+{
+	u32 ReturnValue = 0, OriginalValue, BitShift;
+
+	OriginalValue = rtw_read32(Adapter, RegAddr);
+	BitShift = phy_CalculateBitShift(BitMask);
+	ReturnValue = (OriginalValue & BitMask) >> BitShift;
+	return ReturnValue;
+}
+
+
+/**
+* Function:	PHY_SetBBReg
+*
+* OverView:	Write "Specific bits" to BB register (page 8~)
+*
+* Input:
+*			struct adapter *Adapter,
+*			u32			RegAddr,	The target address to be modified
+*			u32			BitMask		The target bit position in the target address
+*									to be modified
+*			u32			Data		The new register value in the target bit position
+*									of the target address
+*
+* Output:	None
+* Return:		None
+* Note:		This function is equal to "PutRegSetting" in PHY programming guide
+*/
+
+void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data)
+{
+	u32 OriginalValue, BitShift;
+
+	if (BitMask != bMaskDWord) { /* if not "double word" write */
+		OriginalValue = rtw_read32(Adapter, RegAddr);
+		BitShift = phy_CalculateBitShift(BitMask);
+		Data = ((OriginalValue & (~BitMask)) | (Data << BitShift));
+	}
+
+	rtw_write32(Adapter, RegAddr, Data);
+}
+
+
+/*  */
+/*  2. RF register R/W API */
+/*  */
+/**
+* Function:	phy_RFSerialRead
+*
+* OverView:	Read regster from RF chips
+*
+* Input:
+*			struct adapter *Adapter,
+*			enum rf_radio_path eRFPath,	Radio path of A/B/C/D
+*			u32			Offset,		The target address to be read
+*
+* Output:	None
+* Return:		u32			reback value
+* Note:		Threre are three types of serial operations:
+*			1. Software serial write
+*			2. Hardware LSSI-Low Speed Serial Interface
+*			3. Hardware HSSI-High speed
+*			serial write. Driver need to implement (1) and (2).
+*			This function is equal to the combination of RF_ReadReg() and  RFLSSIRead()
+*/
+static	u32
+phy_RFSerialRead(
+		struct adapter *Adapter,
+		enum rf_radio_path eRFPath,
+		u32 Offset
+	)
+{
+	u32 retValue = 0;
+	struct hal_data_8188e				*pHalData = GET_HAL_DATA(Adapter);
+	struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath];
+	u32 NewOffset;
+	u32 tmplong, tmplong2;
+	u8 	RfPiEnable = 0;
+	/*  */
+	/*  Make sure RF register offset is correct */
+	/*  */
+	Offset &= 0xff;
+
+	/*  */
+	/*  Switch page for 8256 RF IC */
+	/*  */
+	NewOffset = Offset;
+
+	/*  For 92S LSSI Read RFLSSIRead */
+	/*  For RF A/B write 0x824/82c(does not work in the future) */
+	/*  We must use 0x824 for RF A and B to execute read trigger */
+	tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord);
+	if (eRFPath == RF_PATH_A)
+		tmplong2 = tmplong;
+	else
+		tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord);
+
+	tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset<<23) | bLSSIReadEdge;	/* T65 RF */
+
+	PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong&(~bLSSIReadEdge));
+	rtw_udelay_os(10);/*  PlatformStallExecution(10); */
+
+	PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2);
+	rtw_udelay_os(100);/* PlatformStallExecution(100); */
+
+	rtw_udelay_os(10);/* PlatformStallExecution(10); */
+
+	if (eRFPath == RF_PATH_A)
+		RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1, BIT8);
+	else if (eRFPath == RF_PATH_B)
+		RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1, BIT8);
+
+	if (RfPiEnable) {	/*  Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */
+		retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData);
+	} else {	/* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */
+		retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
+	}
+	return retValue;
+}
+
+/**
+* Function:	phy_RFSerialWrite
+*
+* OverView:	Write data to RF register (page 8~)
+*
+* Input:
+*			struct adapter *Adapter,
+*			enum rf_radio_path eRFPath,	Radio path of A/B/C/D
+*			u32			Offset,		The target address to be read
+*			u32			Data		The new register Data in the target bit position
+*									of the target to be read
+*
+* Output:	None
+* Return:		None
+* Note:		Threre are three types of serial operations:
+*			1. Software serial write
+*			2. Hardware LSSI-Low Speed Serial Interface
+*			3. Hardware HSSI-High speed
+*			serial write. Driver need to implement (1) and (2).
+*			This function is equal to the combination of RF_ReadReg() and  RFLSSIRead()
+ *
+ * Note:		  For RF8256 only
+ *			 The total count of RTL8256(Zebra4) register is around 36 bit it only employs
+ *			 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10])
+ *			 to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration
+ *			 programming guide" for more details.
+ *			 Thus, we define a sub-finction for RTL8526 register address conversion
+ *		       ===========================================================
+ *			 Register Mode		RegCTL[1]		RegCTL[0]		Note
+ *								(Reg00[12])		(Reg00[10])
+ *		       ===========================================================
+ *			 Reg_Mode0				0				x			Reg 0 ~15(0x0 ~ 0xf)
+ *		       ------------------------------------------------------------------
+ *			 Reg_Mode1				1				0			Reg 16 ~30(0x1 ~ 0xf)
+ *		       ------------------------------------------------------------------
+ *			 Reg_Mode2				1				1			Reg 31 ~ 45(0x1 ~ 0xf)
+ *		       ------------------------------------------------------------------
+ *
+ *	2008/09/02	MH	Add 92S RF definition
+ *
+ *
+ *
+*/
+static	void
+phy_RFSerialWrite(
+		struct adapter *Adapter,
+		enum rf_radio_path eRFPath,
+		u32 Offset,
+		u32 Data
+	)
+{
+	u32 DataAndAddr = 0;
+	struct hal_data_8188e				*pHalData = GET_HAL_DATA(Adapter);
+	struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath];
+	u32 NewOffset;
+
+
+	/*  2009/06/17 MH We can not execute IO for power save or other accident mode. */
+
+	Offset &= 0xff;
+
+	/*  */
+	/*  Switch page for 8256 RF IC */
+	/*  */
+	NewOffset = Offset;
+
+	/*  */
+	/*  Put write addr in [5:0]  and write data in [31:16] */
+	/*  */
+	DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff;	/*  T65 RF */
+
+	/*  */
+	/*  Write Operation */
+	/*  */
+	PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
+}
+
+/**
+* Function:	PHY_QueryRFReg
+*
+* OverView:	Query "Specific bits" to RF register (page 8~)
+*
+* Input:
+*			struct adapter *Adapter,
+*			enum rf_radio_path eRFPath,	Radio path of A/B/C/D
+*			u32			RegAddr,	The target address to be read
+*			u32			BitMask		The target bit position in the target address
+*									to be read
+*
+* Output:	None
+* Return:		u32			Readback value
+* Note:		This function is equal to "GetRFRegSetting" in PHY programming guide
+*/
+u32 rtl8188e_PHY_QueryRFReg(struct adapter *Adapter, enum rf_radio_path eRFPath,
+			    u32 RegAddr, u32 BitMask)
+{
+	u32 Original_Value, Readback_Value, BitShift;
+
+	Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
+
+	BitShift =  phy_CalculateBitShift(BitMask);
+	Readback_Value = (Original_Value & BitMask) >> BitShift;
+	return Readback_Value;
+}
+
+/**
+* Function:	PHY_SetRFReg
+*
+* OverView:	Write "Specific bits" to RF register (page 8~)
+*
+* Input:
+*			struct adapter *Adapter,
+*			enum rf_radio_path eRFPath,	Radio path of A/B/C/D
+*			u32			RegAddr,	The target address to be modified
+*			u32			BitMask		The target bit position in the target address
+*									to be modified
+*			u32			Data		The new register Data in the target bit position
+*									of the target address
+*
+* Output:	None
+* Return:		None
+* Note:		This function is equal to "PutRFRegSetting" in PHY programming guide
+*/
+void
+rtl8188e_PHY_SetRFReg(
+		struct adapter *Adapter,
+		enum rf_radio_path eRFPath,
+		u32 RegAddr,
+		u32 BitMask,
+		u32 Data
+	)
+{
+	u32 Original_Value, BitShift;
+
+	/*  RF data is 12 bits only */
+	if (BitMask != bRFRegOffsetMask) {
+		Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
+		BitShift =  phy_CalculateBitShift(BitMask);
+		Data = ((Original_Value & (~BitMask)) | (Data << BitShift));
+	}
+
+	phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data);
+}
+
+/*  */
+/*  3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */
+/*  */
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_MACConfig8192C
+ *
+ * Overview:	Condig MAC by header file or parameter file.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ *  When		Who		Remark
+ *  08/12/2008	MHC		Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+s32 PHY_MACConfig8188E(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	int rtStatus = _SUCCESS;
+
+	/*  */
+	/*  Config MAC */
+	/*  */
+	if (HAL_STATUS_FAILURE == ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv))
+		rtStatus = _FAIL;
+
+	/*  2010.07.13 AMPDU aggregation number B */
+	rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM);
+
+	return rtStatus;
+}
+
+/**
+* Function:	phy_InitBBRFRegisterDefinition
+*
+* OverView:	Initialize Register definition offset for Radio Path A/B/C/D
+*
+* Input:
+*			struct adapter *Adapter,
+*
+* Output:	None
+* Return:		None
+* Note:		The initialization value is constant and it should never be changes
+*/
+static	void
+phy_InitBBRFRegisterDefinition(
+		struct adapter *Adapter
+)
+{
+	struct hal_data_8188e		*pHalData = GET_HAL_DATA(Adapter);
+
+	/*  RF Interface Sowrtware Control */
+	pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /*  16 LSBs if read 32-bit from 0x870 */
+	pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; /*  16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */
+	pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;/*  16 LSBs if read 32-bit from 0x874 */
+	pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;/*  16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */
+
+	/*  RF Interface Readback Value */
+	pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; /*  16 LSBs if read 32-bit from 0x8E0 */
+	pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;/*  16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */
+	pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;/*  16 LSBs if read 32-bit from 0x8E4 */
+	pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;/*  16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */
+
+	/*  RF Interface Output (and Enable) */
+	pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; /*  16 LSBs if read 32-bit from 0x860 */
+	pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; /*  16 LSBs if read 32-bit from 0x864 */
+
+	/*  RF Interface (Output and)  Enable */
+	pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; /*  16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */
+	pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; /*  16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */
+
+	/* Addr of LSSI. Wirte RF register by driver */
+	pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; /* LSSI Parameter */
+	pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
+
+	/*  RF parameter */
+	pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter;  /* BB Band Select */
+	pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
+	pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter;
+	pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter;
+
+	/*  Tx AGC Gain Stage (same for all path. Should we remove this?) */
+	pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+	pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+	pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+	pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */
+
+	/*  Tranceiver A~D HSSI Parameter-1 */
+	pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1;  /* wire control parameter1 */
+	pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1;  /* wire control parameter1 */
+
+	/*  Tranceiver A~D HSSI Parameter-2 */
+	pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2;  /* wire control parameter2 */
+	pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2;  /* wire control parameter2 */
+
+	/*  RF switch Control */
+	pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */
+	pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl;
+	pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl;
+	pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl;
+
+	/*  AGC control 1 */
+	pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
+	pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
+	pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1;
+	pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1;
+
+	/*  AGC control 2 */
+	pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
+	pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
+	pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2;
+	pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2;
+
+	/*  RX AFE control 1 */
+	pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
+	pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
+	pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance;
+	pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance;
+
+	/*  RX AFE control 1 */
+	pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
+	pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
+	pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE;
+	pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE;
+
+	/*  Tx AFE control 1 */
+	pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
+	pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
+	pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance;
+	pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance;
+
+	/*  Tx AFE control 2 */
+	pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
+	pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
+	pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE;
+	pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE;
+
+	/*  Tranceiver LSSI Readback SI mode */
+	pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
+	pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
+	pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack;
+	pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack;
+
+	/*  Tranceiver LSSI Readback PI mode */
+	pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback;
+	pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback;
+}
+
+void storePwrIndexDiffRateOffset(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+
+	if (RegAddr == rTxAGC_A_Rate18_06)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data;
+	if (RegAddr == rTxAGC_A_Rate54_24)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data;
+	if (RegAddr == rTxAGC_A_CCK1_Mcs32)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data;
+	if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data;
+	if (RegAddr == rTxAGC_A_Mcs03_Mcs00)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data;
+	if (RegAddr == rTxAGC_A_Mcs07_Mcs04)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data;
+	if (RegAddr == rTxAGC_A_Mcs11_Mcs08)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data;
+	if (RegAddr == rTxAGC_A_Mcs15_Mcs12) {
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data;
+		if (pHalData->rf_type == RF_1T1R)
+			pHalData->pwrGroupCnt++;
+	}
+	if (RegAddr == rTxAGC_B_Rate18_06)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data;
+	if (RegAddr == rTxAGC_B_Rate54_24)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data;
+	if (RegAddr == rTxAGC_B_CCK1_55_Mcs32)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data;
+	if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data;
+	if (RegAddr == rTxAGC_B_Mcs03_Mcs00)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data;
+	if (RegAddr == rTxAGC_B_Mcs07_Mcs04)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data;
+	if (RegAddr == rTxAGC_B_Mcs11_Mcs08)
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data;
+	if (RegAddr == rTxAGC_B_Mcs15_Mcs12) {
+		pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data;
+		if (pHalData->rf_type != RF_1T1R)
+			pHalData->pwrGroupCnt++;
+	}
+}
+
+static	int phy_BB8188E_Config_ParaFile(struct adapter *Adapter)
+{
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter);
+	struct hal_data_8188e		*pHalData = GET_HAL_DATA(Adapter);
+	int			rtStatus = _SUCCESS;
+
+	/*  */
+	/*  1. Read PHY_REG.TXT BB INIT!! */
+	/*  We will seperate as 88C / 92C according to chip version */
+	/*  */
+	if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG))
+		rtStatus = _FAIL;
+	if (rtStatus != _SUCCESS)
+		goto phy_BB8190_Config_ParaFile_Fail;
+
+	/*  2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */
+	if (!pEEPROM->bautoload_fail_flag) {
+		pHalData->pwrGroupCnt = 0;
+
+		if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG))
+			rtStatus = _FAIL;
+	}
+
+	if (rtStatus != _SUCCESS)
+		goto phy_BB8190_Config_ParaFile_Fail;
+
+	/*  3. BB AGC table Initialization */
+	if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv,  CONFIG_BB_AGC_TAB))
+		rtStatus = _FAIL;
+
+	if (rtStatus != _SUCCESS)
+		goto phy_BB8190_Config_ParaFile_Fail;
+
+phy_BB8190_Config_ParaFile_Fail:
+
+	return rtStatus;
+}
+
+int
+PHY_BBConfig8188E(
+		struct adapter *Adapter
+	)
+{
+	int	rtStatus = _SUCCESS;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	u32 RegVal;
+	u8 CrystalCap;
+
+	phy_InitBBRFRegisterDefinition(Adapter);
+
+
+	/*  Enable BB and RF */
+	RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN);
+	rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal|BIT13|BIT0|BIT1));
+
+	/*  20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. */
+
+	rtw_write8(Adapter, REG_RF_CTRL, RF_EN|RF_RSTB|RF_SDMRSTB);
+
+	rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB);
+
+	/*  Config BB and AGC */
+	rtStatus = phy_BB8188E_Config_ParaFile(Adapter);
+
+	/*  write 0x24[16:11] = 0x24[22:17] = CrystalCap */
+	CrystalCap = pHalData->CrystalCap & 0x3F;
+	PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6)));
+
+	return rtStatus;
+}
+
+int PHY_RFConfig8188E(struct adapter *Adapter)
+{
+	int		rtStatus = _SUCCESS;
+
+	/*  RF config */
+	rtStatus = PHY_RF6052_Config8188E(Adapter);
+	return rtStatus;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_ConfigRFWithParaFile()
+ *
+ * Overview:    This function read RF parameters from general file format, and do RF 3-wire
+ *
+ * Input:	struct adapter *Adapter
+ *			ps8					pFileName
+ *			enum rf_radio_path eRFPath
+ *
+ * Output:      NONE
+ *
+ * Return:      RT_STATUS_SUCCESS: configuration file exist
+ *
+ * Note:		Delay may be required for RF configuration
+ *---------------------------------------------------------------------------*/
+int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *Adapter, u8 *pFileName, enum rf_radio_path eRFPath)
+{
+	return _SUCCESS;
+}
+
+void
+rtl8192c_PHY_GetHWRegOriginalValue(
+		struct adapter *Adapter
+	)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+
+	/*  read rx initial gain */
+	pHalData->DefaultInitialGain[0] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XAAGCCore1, bMaskByte0);
+	pHalData->DefaultInitialGain[1] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XBAGCCore1, bMaskByte0);
+	pHalData->DefaultInitialGain[2] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XCAGCCore1, bMaskByte0);
+	pHalData->DefaultInitialGain[3] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XDAGCCore1, bMaskByte0);
+
+	/*  read framesync */
+	pHalData->framesync = (u8)PHY_QueryBBReg(Adapter, rOFDM0_RxDetector3, bMaskByte0);
+	pHalData->framesyncC34 = PHY_QueryBBReg(Adapter, rOFDM0_RxDetector2, bMaskDWord);
+}
+
+/*  */
+/*	Description: */
+/*		Map dBm into Tx power index according to */
+/*		current HW model, for example, RF and PA, and */
+/*		current wireless mode. */
+/*	By Bruce, 2008-01-29. */
+/*  */
+static	u8 phy_DbmToTxPwrIdx(struct adapter *Adapter, enum wireless_mode WirelessMode, int PowerInDbm)
+{
+	u8 TxPwrIdx = 0;
+	int				Offset = 0;
+
+
+	/*  */
+	/*  Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to */
+	/*  3dbm, and OFDM HT equals to 0dbm repectively. */
+	/*  Note: */
+	/*	The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */
+	/*  By Bruce, 2008-01-29. */
+	/*  */
+	switch (WirelessMode) {
+	case WIRELESS_MODE_B:
+		Offset = -7;
+		break;
+
+	case WIRELESS_MODE_G:
+	case WIRELESS_MODE_N_24G:
+	default:
+		Offset = -8;
+		break;
+	}
+
+	if ((PowerInDbm - Offset) > 0)
+		TxPwrIdx = (u8)((PowerInDbm - Offset) * 2);
+	else
+		TxPwrIdx = 0;
+
+	/*  Tx Power Index is too large. */
+	if (TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S)
+		TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S;
+
+	return TxPwrIdx;
+}
+
+/*  */
+/*	Description: */
+/*		Map Tx power index into dBm according to */
+/*		current HW model, for example, RF and PA, and */
+/*		current wireless mode. */
+/*	By Bruce, 2008-01-29. */
+/*  */
+static int phy_TxPwrIdxToDbm(struct adapter *Adapter, enum wireless_mode WirelessMode, u8 TxPwrIdx)
+{
+	int				Offset = 0;
+	int				PwrOutDbm = 0;
+
+	/*  */
+	/*  Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to -8dbm. */
+	/*  Note: */
+	/*	The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */
+	/*  By Bruce, 2008-01-29. */
+	/*  */
+	switch (WirelessMode) {
+	case WIRELESS_MODE_B:
+		Offset = -7;
+		break;
+	case WIRELESS_MODE_G:
+	case WIRELESS_MODE_N_24G:
+	default:
+		Offset = -8;
+		break;
+	}
+
+	PwrOutDbm = TxPwrIdx / 2 + Offset; /*  Discard the decimal part. */
+
+	return PwrOutDbm;
+}
+
+
+/*-----------------------------------------------------------------------------
+ * Function:    GetTxPowerLevel8190()
+ *
+ * Overview:    This function is export to "common" moudule
+ *
+ * Input:       struct adapter *Adapter
+ *			psByte			Power Level
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ *---------------------------------------------------------------------------*/
+void PHY_GetTxPowerLevel8188E(struct adapter *Adapter, u32 *powerlevel)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	u8 TxPwrLevel = 0;
+	int			TxPwrDbm;
+
+	/*  */
+	/*  Because the Tx power indexes are different, we report the maximum of them to */
+	/*  meet the CCX TPC request. By Bruce, 2008-01-31. */
+	/*  */
+
+	/*  CCK */
+	TxPwrLevel = pHalData->CurrentCckTxPwrIdx;
+	TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_B, TxPwrLevel);
+
+	/*  Legacy OFDM */
+	TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx + pHalData->LegacyHTTxPowerDiff;
+
+	/*  Compare with Legacy OFDM Tx power. */
+	if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm)
+		TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel);
+
+	/*  HT OFDM */
+	TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx;
+
+	/*  Compare with HT OFDM Tx power. */
+	if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm)
+		TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel);
+
+	*powerlevel = TxPwrDbm;
+}
+
+static void getTxPowerIndex88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
+			       u8 *ofdmPowerLevel, u8 *BW20PowerLevel,
+			       u8 *BW40PowerLevel)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	u8 index = (channel - 1);
+	u8 TxCount = 0, path_nums;
+
+	if ((RF_1T2R == pHalData->rf_type) || (RF_1T1R == pHalData->rf_type))
+		path_nums = 1;
+	else
+		path_nums = 2;
+
+	for (TxCount = 0; TxCount < path_nums; TxCount++) {
+		if (TxCount == RF_PATH_A) {
+			/*  1. CCK */
+			cckPowerLevel[TxCount]	= pHalData->Index24G_CCK_Base[TxCount][index];
+			/* 2. OFDM */
+			ofdmPowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+				pHalData->OFDM_24G_Diff[TxCount][RF_PATH_A];
+			/*  1. BW20 */
+			BW20PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+				pHalData->BW20_24G_Diff[TxCount][RF_PATH_A];
+			/* 2. BW40 */
+			BW40PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[TxCount][index];
+		} else if (TxCount == RF_PATH_B) {
+			/*  1. CCK */
+			cckPowerLevel[TxCount]	= pHalData->Index24G_CCK_Base[TxCount][index];
+			/* 2. OFDM */
+			ofdmPowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[TxCount][index];
+			/*  1. BW20 */
+			BW20PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]+
+			pHalData->BW20_24G_Diff[TxCount][index];
+			/* 2. BW40 */
+			BW40PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[TxCount][index];
+		} else if (TxCount == RF_PATH_C) {
+			/*  1. CCK */
+			cckPowerLevel[TxCount]	= pHalData->Index24G_CCK_Base[TxCount][index];
+			/* 2. OFDM */
+			ofdmPowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+			pHalData->BW20_24G_Diff[TxCount][index];
+			/*  1. BW20 */
+			BW20PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+			pHalData->BW20_24G_Diff[TxCount][index];
+			/* 2. BW40 */
+			BW40PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[TxCount][index];
+		} else if (TxCount == RF_PATH_D) {
+			/*  1. CCK */
+			cckPowerLevel[TxCount]	= pHalData->Index24G_CCK_Base[TxCount][index];
+			/* 2. OFDM */
+			ofdmPowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_C][index]+
+			pHalData->BW20_24G_Diff[TxCount][index];
+
+			/*  1. BW20 */
+			BW20PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_A][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_B][index]+
+			pHalData->BW20_24G_Diff[RF_PATH_C][index]+
+			pHalData->BW20_24G_Diff[TxCount][index];
+
+			/* 2. BW40 */
+			BW40PowerLevel[TxCount]	= pHalData->Index24G_BW40_Base[TxCount][index];
+		}
+	}
+}
+
+static void phy_PowerIndexCheck88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel,
+				   u8 *ofdmPowerLevel, u8 *BW20PowerLevel, u8 *BW40PowerLevel)
+{
+	struct hal_data_8188e		*pHalData = GET_HAL_DATA(Adapter);
+
+	pHalData->CurrentCckTxPwrIdx = cckPowerLevel[0];
+	pHalData->CurrentOfdm24GTxPwrIdx = ofdmPowerLevel[0];
+	pHalData->CurrentBW2024GTxPwrIdx = BW20PowerLevel[0];
+	pHalData->CurrentBW4024GTxPwrIdx = BW40PowerLevel[0];
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:    SetTxPowerLevel8190()
+ *
+ * Overview:    This function is export to "HalCommon" moudule
+ *			We must consider RF path later!!!!!!!
+ *
+ * Input:       struct adapter *Adapter
+ *			u8		channel
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *	2008/11/04	MHC		We remove EEPROM_93C56.
+ *						We need to move CCX relative code to independet file.
+ *	2009/01/21	MHC		Support new EEPROM format from SD3 requirement.
+ *
+ *---------------------------------------------------------------------------*/
+void
+PHY_SetTxPowerLevel8188E(
+		struct adapter *Adapter,
+		u8 channel
+	)
+{
+	u8 cckPowerLevel[MAX_TX_COUNT] = {0};
+	u8 ofdmPowerLevel[MAX_TX_COUNT] = {0};/*  [0]:RF-A, [1]:RF-B */
+	u8 BW20PowerLevel[MAX_TX_COUNT] = {0};
+	u8 BW40PowerLevel[MAX_TX_COUNT] = {0};
+
+	getTxPowerIndex88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]);
+
+	phy_PowerIndexCheck88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]);
+
+	rtl8188e_PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]);
+	rtl8188e_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0], channel);
+}
+
+/*  */
+/*	Description: */
+/*		Update transmit power level of all channel supported. */
+/*  */
+/*	TODO: */
+/*		A mode. */
+/*	By Bruce, 2008-02-04. */
+/*  */
+bool
+PHY_UpdateTxPowerDbm8188E(
+		struct adapter *Adapter,
+		int		powerInDbm
+	)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	u8 idx;
+	u8 rf_path;
+
+	/*  TODO: A mode Tx power. */
+	u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, powerInDbm);
+	u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, powerInDbm);
+
+	if (OfdmTxPwrIdx - pHalData->LegacyHTTxPowerDiff > 0)
+		OfdmTxPwrIdx -= pHalData->LegacyHTTxPowerDiff;
+	else
+		OfdmTxPwrIdx = 0;
+
+	for (idx = 0; idx < 14; idx++) {
+		for (rf_path = 0; rf_path < 2; rf_path++) {
+			pHalData->TxPwrLevelCck[rf_path][idx] = CckTxPwrIdx;
+			pHalData->TxPwrLevelHT40_1S[rf_path][idx] =
+			pHalData->TxPwrLevelHT40_2S[rf_path][idx] = OfdmTxPwrIdx;
+		}
+	}
+	return true;
+}
+
+void
+PHY_ScanOperationBackup8188E(
+		struct adapter *Adapter,
+		u8 Operation
+	)
+{
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_SetBWModeCallback8192C()
+ *
+ * Overview:    Timer callback function for SetSetBWMode
+ *
+ * Input:		PRT_TIMER		pTimer
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Note:		(1) We do not take j mode into consideration now
+ *			(2) Will two workitem of "switch channel" and "switch channel bandwidth" run
+ *			     concurrently?
+ *---------------------------------------------------------------------------*/
+static void
+_PHY_SetBWMode92C(
+		struct adapter *Adapter
+)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	u8 regBwOpMode;
+	u8 regRRSR_RSC;
+
+	if (pHalData->rf_chip == RF_PSEUDO_11N)
+		return;
+
+	/*  There is no 40MHz mode in RF_8225. */
+	if (pHalData->rf_chip == RF_8225)
+		return;
+
+	if (Adapter->bDriverStopped)
+		return;
+
+	/* 3 */
+	/* 3<1>Set MAC register */
+	/* 3 */
+
+	regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE);
+	regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2);
+
+	switch (pHalData->CurrentChannelBW) {
+	case HT_CHANNEL_WIDTH_20:
+		regBwOpMode |= BW_OPMODE_20MHZ;
+		/*  2007/02/07 Mark by Emily becasue we have not verify whether this register works */
+		rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
+		break;
+	case HT_CHANNEL_WIDTH_40:
+		regBwOpMode &= ~BW_OPMODE_20MHZ;
+		/*  2007/02/07 Mark by Emily becasue we have not verify whether this register works */
+		rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
+		regRRSR_RSC = (regRRSR_RSC&0x90) | (pHalData->nCur40MhzPrimeSC<<5);
+		rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC);
+		break;
+	default:
+		break;
+	}
+
+	/* 3  */
+	/* 3 <2>Set PHY related register */
+	/* 3 */
+	switch (pHalData->CurrentChannelBW) {
+	/* 20 MHz channel*/
+	case HT_CHANNEL_WIDTH_20:
+		PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0);
+		PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0);
+		break;
+	/* 40 MHz channel*/
+	case HT_CHANNEL_WIDTH_40:
+		PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1);
+		PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1);
+		/*  Set Control channel to upper or lower. These settings are required only for 40MHz */
+		PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC>>1));
+		PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC);
+		PHY_SetBBReg(Adapter, 0x818, (BIT26 | BIT27),
+			     (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+		break;
+	default:
+		break;
+	}
+	/* Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 */
+
+	/* 3<3>Set RF related register */
+	switch (pHalData->rf_chip) {
+	case RF_8225:
+		break;
+	case RF_8256:
+		/*  Please implement this function in Hal8190PciPhy8256.c */
+		break;
+	case RF_8258:
+		/*  Please implement this function in Hal8190PciPhy8258.c */
+		break;
+	case RF_PSEUDO_11N:
+		break;
+	case RF_6052:
+		rtl8188e_PHY_RF6052SetBandwidth(Adapter, pHalData->CurrentChannelBW);
+		break;
+	default:
+		break;
+	}
+}
+
+ /*-----------------------------------------------------------------------------
+ * Function:   SetBWMode8190Pci()
+ *
+ * Overview:  This function is export to "HalCommon" moudule
+ *
+ * Input:		struct adapter *Adapter
+ *			enum ht_channel_width Bandwidth	20M or 40M
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Note:		We do not take j mode into consideration now
+ *---------------------------------------------------------------------------*/
+void PHY_SetBWMode8188E(struct adapter *Adapter, enum ht_channel_width Bandwidth,	/*  20M or 40M */
+			unsigned char	Offset)		/*  Upper, Lower, or Don't care */
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	enum ht_channel_width tmpBW = pHalData->CurrentChannelBW;
+
+	pHalData->CurrentChannelBW = Bandwidth;
+
+	pHalData->nCur40MhzPrimeSC = Offset;
+
+	if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved))
+		_PHY_SetBWMode92C(Adapter);
+	else
+		pHalData->CurrentChannelBW = tmpBW;
+}
+
+static void _PHY_SwChnl8192C(struct adapter *Adapter, u8 channel)
+{
+	u8 eRFPath;
+	u32 param1, param2;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+
+	if (Adapter->bNotifyChannelChange)
+		DBG_88E("[%s] ch = %d\n", __func__, channel);
+
+	/* s1. pre common command - CmdID_SetTxPowerLevel */
+	PHY_SetTxPowerLevel8188E(Adapter, channel);
+
+	/* s2. RF dependent command - CmdID_RF_WriteReg, param1=RF_CHNLBW, param2=channel */
+	param1 = RF_CHNLBW;
+	param2 = channel;
+	for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
+		pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2);
+		PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, param1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]);
+	}
+}
+
+void PHY_SwChnl8188E(struct adapter *Adapter, u8 channel)
+{
+	/*  Call after initialization */
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(Adapter);
+	u8 tmpchannel = pHalData->CurrentChannel;
+	bool  bResult = true;
+
+	if (pHalData->rf_chip == RF_PSEUDO_11N)
+		return;		/* return immediately if it is peudo-phy */
+
+	if (channel == 0)
+		channel = 1;
+
+	pHalData->CurrentChannel = channel;
+
+	if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) {
+		_PHY_SwChnl8192C(Adapter, channel);
+
+		if (bResult)
+			;
+		else
+			pHalData->CurrentChannel = tmpchannel;
+
+	} else {
+		pHalData->CurrentChannel = tmpchannel;
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c
new file mode 100644
index 0000000..bfdf9b3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rf6052.c
@@ -0,0 +1,572 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *
+ * Module:	rtl8192c_rf6052.c	( Source C File)
+ *
+ * Note:	Provide RF 6052 series relative API.
+ *
+ * Function:
+ *
+ * Export:
+ *
+ * Abbrev:
+ *
+ * History:
+ * Data			Who		Remark
+ *
+ * 09/25/2008	MHC		Create initial version.
+ * 11/05/2008	MHC		Add API for tw power setting.
+ *
+ *
+******************************************************************************/
+
+#define _RTL8188E_RF6052_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8188e_hal.h>
+
+/*---------------------------Define Local Constant---------------------------*/
+/*  Define local structure for debug!!!!! */
+struct rf_shadow {
+	/*  Shadow register value */
+	u32 Value;
+	/*  Compare or not flag */
+	u8 Compare;
+	/*  Record If it had ever modified unpredicted */
+	u8 ErrorOrNot;
+	/*  Recorver Flag */
+	u8 Recorver;
+	/*  */
+	u8 Driver_Write;
+};
+
+/*---------------------------Define Local Constant---------------------------*/
+
+
+/*------------------------Define global variable-----------------------------*/
+
+/*------------------------Define local variable------------------------------*/
+
+/*-----------------------------------------------------------------------------
+ * Function:	RF_ChangeTxPath
+ *
+ * Overview:	For RL6052, we must change some RF settign for 1T or 2T.
+ *
+ * Input:		u16 DataRate		0x80-8f, 0x90-9f
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 09/25/2008	MHC		Create Version 0.
+ *						Firmwaer support the utility later.
+ *
+ *---------------------------------------------------------------------------*/
+void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate)
+{
+/*  We do not support gain table change inACUT now !!!! Delete later !!! */
+}	/* RF_ChangeTxPath */
+
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_RF6052SetBandwidth()
+ *
+ * Overview:    This function is called by SetBWModeCallback8190Pci() only
+ *
+ * Input:       struct adapter *Adapter
+ *			WIRELESS_BANDWIDTH_E	Bandwidth	20M or 40M
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Note:		For RF type 0222D
+ *---------------------------------------------------------------------------*/
+void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
+				     enum ht_channel_width Bandwidth)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+
+	switch (Bandwidth) {
+	case HT_CHANNEL_WIDTH_20:
+		pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11));
+		PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
+		break;
+	case HT_CHANNEL_WIDTH_40:
+		pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10));
+		PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
+		break;
+	default:
+		break;
+	}
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	PHY_RF6052SetCckTxPower
+ *
+ * Overview:
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/05/2008	MHC		Simulate 8192series..
+ *
+ *---------------------------------------------------------------------------*/
+
+void
+rtl8188e_PHY_RF6052SetCckTxPower(
+		struct adapter *Adapter,
+		u8 *pPowerlevel)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	struct dm_priv *pdmpriv = &pHalData->dmpriv;
+	struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+	u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value;
+	bool TurboScanOff = false;
+	u8 idx1, idx2;
+	u8 *ptr;
+	u8 direction;
+	/* FOR CE ,must disable turbo scan */
+	TurboScanOff = true;
+
+
+	if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+		TxAGC[RF_PATH_A] = 0x3f3f3f3f;
+		TxAGC[RF_PATH_B] = 0x3f3f3f3f;
+
+		TurboScanOff = true;/* disable turbo scan */
+
+		if (TurboScanOff) {
+			for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+				TxAGC[idx1] =
+					pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
+					(pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
+				/*  2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */
+				if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
+					TxAGC[idx1] = 0x20;
+			}
+		}
+	} else {
+		/* Driver dynamic Tx power shall not affect Tx power.
+		 * It shall be determined by power training mechanism.
+i		 *  Currently, we cannot fully disable driver dynamic
+		 * tx power mechanism because it is referenced by BT
+		 * coexist mechanism.
+		 * In the future, two mechanism shall be separated from
+		 * each other and maintained independantly. */
+		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
+			TxAGC[RF_PATH_A] = 0x10101010;
+			TxAGC[RF_PATH_B] = 0x10101010;
+		} else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
+			TxAGC[RF_PATH_A] = 0x00000000;
+			TxAGC[RF_PATH_B] = 0x00000000;
+		} else {
+			for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+				TxAGC[idx1] =
+					pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
+					(pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
+			}
+			if (pHalData->EEPROMRegulatory == 0) {
+				tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
+						(pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
+				TxAGC[RF_PATH_A] += tmpval;
+
+				tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
+						(pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
+				TxAGC[RF_PATH_B] += tmpval;
+			}
+		}
+	}
+	for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+		ptr = (u8 *)(&(TxAGC[idx1]));
+		for (idx2 = 0; idx2 < 4; idx2++) {
+			if (*ptr > RF6052_MAX_TX_PWR)
+				*ptr = RF6052_MAX_TX_PWR;
+			ptr++;
+		}
+	}
+	ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value);
+
+	if (direction == 1) {
+		/*  Increase TX pwoer */
+		TxAGC[0] += pwrtrac_value;
+		TxAGC[1] += pwrtrac_value;
+	} else if (direction == 2) {
+		/*  Decrease TX pwoer */
+		TxAGC[0] -=  pwrtrac_value;
+		TxAGC[1] -=  pwrtrac_value;
+	}
+
+	/*  rf-A cck tx power */
+	tmpval = TxAGC[RF_PATH_A]&0xff;
+	PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
+	tmpval = TxAGC[RF_PATH_A]>>8;
+	PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+	/*  rf-B cck tx power */
+	tmpval = TxAGC[RF_PATH_B]>>24;
+	PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
+	tmpval = TxAGC[RF_PATH_B]&0x00ffffff;
+	PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
+}	/* PHY_RF6052SetCckTxPower */
+
+/*  */
+/*  powerbase0 for OFDM rates */
+/*  powerbase1 for HT MCS rates */
+/*  */
+static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM,
+			    u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	u32 powerBase0, powerBase1;
+	u8 i, powerlevel[2];
+
+	for (i = 0; i < 2; i++) {
+		powerBase0 = pPowerLevelOFDM[i];
+
+		powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0;
+		*(OfdmBase+i) = powerBase0;
+	}
+	for (i = 0; i < pHalData->NumTotalRFPath; i++) {
+		/* Check HT20 to HT40 diff */
+		if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+			powerlevel[i] = pPowerLevelBW20[i];
+		else
+			powerlevel[i] = pPowerLevelBW40[i];
+		powerBase1 = powerlevel[i];
+		powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1;
+		*(MCSBase+i) = powerBase1;
+	}
+}
+static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel,
+				    u8 index, u32 *powerBase0, u32 *powerBase1,
+				    u32 *pOutWriteVal)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &pHalData->dmpriv;
+	u8	i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit;
+	s8	pwr_diff = 0;
+	u32	writeVal, customer_limit, rf;
+	u8	Regulatory = pHalData->EEPROMRegulatory;
+
+	/*  Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
+
+	for (rf = 0; rf < 2; rf++) {
+		switch (Regulatory) {
+		case 0:	/*  Realtek better performance */
+				/*  increase power diff defined by Realtek for large power */
+			chnlGroup = 0;
+			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+				((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			break;
+		case 1:	/*  Realtek regulatory */
+			/*  increase power diff defined by Realtek for regulatory */
+			if (pHalData->pwrGroupCnt == 1)
+				chnlGroup = 0;
+			if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) {
+				if (Channel < 3)			/*  Chanel 1-2 */
+					chnlGroup = 0;
+				else if (Channel < 6)		/*  Channel 3-5 */
+					chnlGroup = 1;
+				else	 if (Channel < 9)		/*  Channel 6-8 */
+					chnlGroup = 2;
+				else if (Channel < 12)		/*  Channel 9-11 */
+					chnlGroup = 3;
+				else if (Channel < 14)		/*  Channel 12-13 */
+					chnlGroup = 4;
+				else if (Channel == 14)		/*  Channel 14 */
+					chnlGroup = 5;
+			}
+			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+					((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			break;
+		case 2:	/*  Better regulatory */
+				/*  don't increase any power diff */
+			writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			break;
+		case 3:	/*  Customer defined power diff. */
+				/*  increase power diff defined by customer. */
+			chnlGroup = 0;
+
+			if (index < 2)
+				pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel-1];
+			else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+				pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel-1];
+
+			if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
+				customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel-1];
+			else
+				customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel-1];
+
+			if (pwr_diff >= customer_pwr_limit)
+				pwr_diff = 0;
+			else
+				pwr_diff = customer_pwr_limit - pwr_diff;
+
+			for (i = 0; i < 4; i++) {
+				pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)]&(0x7f<<(i*8)))>>(i*8));
+
+				if (pwr_diff_limit[i] > pwr_diff)
+					pwr_diff_limit[i] = pwr_diff;
+			}
+			customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
+					 (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
+			writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			break;
+		default:
+			chnlGroup = 0;
+			writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+					((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+			break;
+		}
+/*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
+/*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
+/*  In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */
+		/* 92d do not need this */
+		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
+			writeVal = 0x14141414;
+		else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
+			writeVal = 0x00000000;
+
+		/*  20100628 Joseph: High power mode for BT-Coexist mechanism. */
+		/*  This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */
+		if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
+			writeVal = writeVal - 0x06060606;
+		else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
+			writeVal = writeVal;
+		*(pOutWriteVal+rf) = writeVal;
+	}
+}
+static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	u16 regoffset_a[6] = {
+		rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
+		rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
+		rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12};
+	u16 regoffset_b[6] = {
+		rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
+		rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
+		rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12};
+	u8 i, rf, pwr_val[4];
+	u32 writeVal;
+	u16 regoffset;
+
+	for (rf = 0; rf < 2; rf++) {
+		writeVal = pValue[rf];
+		for (i = 0; i < 4; i++) {
+			pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8));
+			if (pwr_val[i]  > RF6052_MAX_TX_PWR)
+				pwr_val[i]  = RF6052_MAX_TX_PWR;
+		}
+		writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) | (pwr_val[1]<<8) | pwr_val[0];
+
+		if (rf == 0)
+			regoffset = regoffset_a[index];
+		else
+			regoffset = regoffset_b[index];
+
+		PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal);
+
+		/*  201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */
+		if (((pHalData->rf_type == RF_2T2R) &&
+		     (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs15_Mcs12)) ||
+		    ((pHalData->rf_type != RF_2T2R) &&
+		     (regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04))) {
+			writeVal = pwr_val[3];
+			if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04)
+				regoffset = 0xc90;
+			if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04)
+				regoffset = 0xc98;
+			for (i = 0; i < 3; i++) {
+				if (i != 2)
+					writeVal = (writeVal > 8) ? (writeVal-8) : 0;
+				else
+					writeVal = (writeVal > 6) ? (writeVal-6) : 0;
+				rtw_write8(Adapter, (u32)(regoffset+i), (u8)writeVal);
+			}
+		}
+	}
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	PHY_RF6052SetOFDMTxPower
+ *
+ * Overview:	For legacy and HY OFDM, we must read EEPROM TX power index for
+ *			different channel and read original value in TX power register area from
+ *			0xe00. We increase offset and original value to be correct tx pwr.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When			Who		Remark
+ * 11/05/2008	MHC		Simulate 8192 series method.
+ * 01/06/2009	MHC		1. Prevent Path B tx power overflow or underflow dure to
+ *						A/B pwr difference or legacy/HT pwr diff.
+ *						2. We concern with path B legacy/HT OFDM difference.
+ * 01/22/2009	MHC		Support new EPRO format from SD3.
+ *
+ *---------------------------------------------------------------------------*/
+
+void
+rtl8188e_PHY_RF6052SetOFDMTxPower(
+		struct adapter *Adapter,
+		u8 *pPowerLevelOFDM,
+		u8 *pPowerLevelBW20,
+		u8 *pPowerLevelBW40,
+		u8 Channel)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value;
+	u8 direction;
+	u8 index = 0;
+
+	getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]);
+
+	/*  2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */
+	/*  This is ued to fix unstable power tracking mode. */
+	ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value);
+
+	for (index = 0; index < 6; index++) {
+		get_rx_power_val_by_reg(Adapter, Channel, index,
+					&powerBase0[0], &powerBase1[0],
+					&writeVal[0]);
+
+		if (direction == 1) {
+			writeVal[0] += pwrtrac_value;
+			writeVal[1] += pwrtrac_value;
+		} else if (direction == 2) {
+			writeVal[0] -= pwrtrac_value;
+			writeVal[1] -= pwrtrac_value;
+		}
+		writeOFDMPowerReg88E(Adapter, index, &writeVal[0]);
+	}
+}
+
+static int phy_RF6052_Config_ParaFile(struct adapter *Adapter)
+{
+	struct bb_reg_def *pPhyReg;
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	u32 u4RegValue = 0;
+	u8 eRFPath;
+	int rtStatus = _SUCCESS;
+
+	/* 3----------------------------------------------------------------- */
+	/* 3 <2> Initialize RF */
+	/* 3----------------------------------------------------------------- */
+	for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
+		pPhyReg = &pHalData->PHYRegDef[eRFPath];
+
+		/*----Store original RFENV control type----*/
+		switch (eRFPath) {
+		case RF_PATH_A:
+		case RF_PATH_C:
+			u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV);
+			break;
+		case RF_PATH_B:
+		case RF_PATH_D:
+			u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16);
+			break;
+		}
+		/*----Set RF_ENV enable----*/
+		PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
+		rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+		/*----Set RF_ENV output high----*/
+		PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
+		rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+		/* Set bit number of Address and Data for RF register */
+		PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0);	/*  Set 1 to 4 bits for 8255 */
+		rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+		PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0);	/*  Set 0 to 12  bits for 8255 */
+		rtw_udelay_os(1);/* PlatformStallExecution(1); */
+
+		/*----Initialize RF fom connfiguration file----*/
+		switch (eRFPath) {
+		case RF_PATH_A:
+			if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum ODM_RF_RADIO_PATH)eRFPath, (enum ODM_RF_RADIO_PATH)eRFPath))
+				rtStatus = _FAIL;
+			break;
+		case RF_PATH_B:
+		if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum ODM_RF_RADIO_PATH)eRFPath, (enum ODM_RF_RADIO_PATH)eRFPath))
+				rtStatus = _FAIL;
+			break;
+		case RF_PATH_C:
+			break;
+		case RF_PATH_D:
+			break;
+		}
+		/*----Restore RFENV control type----*/;
+		switch (eRFPath) {
+		case RF_PATH_A:
+		case RF_PATH_C:
+			PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
+			break;
+		case RF_PATH_B:
+		case RF_PATH_D:
+			PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
+			break;
+		}
+		if (rtStatus != _SUCCESS)
+			goto phy_RF6052_Config_ParaFile_Fail;
+	}
+	return rtStatus;
+
+phy_RF6052_Config_ParaFile_Fail:
+	return rtStatus;
+}
+
+int PHY_RF6052_Config8188E(struct adapter *Adapter)
+{
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter);
+	int rtStatus = _SUCCESS;
+
+	/*  */
+	/*  Initialize general global value */
+	/*  */
+	/*  TODO: Extend RF_PATH_C and RF_PATH_D in the future */
+	if (pHalData->rf_type == RF_1T1R)
+		pHalData->NumTotalRFPath = 1;
+	else
+		pHalData->NumTotalRFPath = 2;
+
+	/*  */
+	/*  Config BB and RF */
+	/*  */
+	rtStatus = phy_RF6052_Config_ParaFile(Adapter);
+	return rtStatus;
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
new file mode 100644
index 0000000..05e2475
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
@@ -0,0 +1,202 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_REDESC_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8188e_hal.h>
+
+static void process_rssi(struct adapter *padapter, union recv_frame *prframe)
+{
+	struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib;
+	struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data;
+
+	if (signal_stat->update_req) {
+		signal_stat->total_num = 0;
+		signal_stat->total_val = 0;
+		signal_stat->update_req = 0;
+	}
+
+	signal_stat->total_num++;
+	signal_stat->total_val  += pattrib->phy_info.SignalStrength;
+	signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
+} /*  Process_UI_RSSI_8192C */
+
+static void process_link_qual(struct adapter *padapter, union recv_frame *prframe)
+{
+	struct rx_pkt_attrib *pattrib;
+	struct signal_stat *signal_stat;
+
+	if (prframe == NULL || padapter == NULL)
+		return;
+
+	pattrib = &prframe->u.hdr.attrib;
+	signal_stat = &padapter->recvpriv.signal_qual_data;
+
+	if (signal_stat->update_req) {
+		signal_stat->total_num = 0;
+		signal_stat->total_val = 0;
+		signal_stat->update_req = 0;
+	}
+
+	signal_stat->total_num++;
+	signal_stat->total_val  += pattrib->phy_info.SignalQuality;
+	signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
+}
+
+void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe)
+{
+	union recv_frame *precvframe = (union recv_frame *)prframe;
+
+	/*  Check RSSI */
+	process_rssi(padapter, precvframe);
+	/*  Check EVM */
+	process_link_qual(padapter,  precvframe);
+}
+
+void update_recvframe_attrib_88e(union recv_frame *precvframe, struct recv_stat *prxstat)
+{
+	struct rx_pkt_attrib	*pattrib;
+	struct recv_stat	report;
+
+	report.rxdw0 = prxstat->rxdw0;
+	report.rxdw1 = prxstat->rxdw1;
+	report.rxdw2 = prxstat->rxdw2;
+	report.rxdw3 = prxstat->rxdw3;
+	report.rxdw4 = prxstat->rxdw4;
+	report.rxdw5 = prxstat->rxdw5;
+
+	pattrib = &precvframe->u.hdr.attrib;
+	_rtw_memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
+
+	pattrib->crc_err = (u8)((le32_to_cpu(report.rxdw0) >> 14) & 0x1);;/* u8)prxreport->crc32; */
+
+	/*  update rx report to recv_frame attribute */
+	pattrib->pkt_rpt_type = (u8)((le32_to_cpu(report.rxdw3) >> 14) & 0x3);/* prxreport->rpt_sel; */
+
+	if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */
+		pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */
+		pattrib->drvinfo_sz = (u8)((le32_to_cpu(report.rxdw0) >> 16) & 0xf) * 8;/* u8)(prxreport->drvinfosize << 3); */
+
+		pattrib->physt =  (u8)((le32_to_cpu(report.rxdw0) >> 26) & 0x1);/* u8)prxreport->physt; */
+
+		pattrib->bdecrypted = (le32_to_cpu(report.rxdw0) & BIT(27)) ? 0 : 1;/* u8)(prxreport->swdec ? 0 : 1); */
+		pattrib->encrypt = (u8)((le32_to_cpu(report.rxdw0) >> 20) & 0x7);/* u8)prxreport->security; */
+
+		pattrib->qos = (u8)((le32_to_cpu(report.rxdw0) >> 23) & 0x1);/* u8)prxreport->qos; */
+		pattrib->priority = (u8)((le32_to_cpu(report.rxdw1) >> 8) & 0xf);/* u8)prxreport->tid; */
+
+		pattrib->amsdu = (u8)((le32_to_cpu(report.rxdw1) >> 13) & 0x1);/* u8)prxreport->amsdu; */
+
+		pattrib->seq_num = (u16)(le32_to_cpu(report.rxdw2) & 0x00000fff);/* u16)prxreport->seq; */
+		pattrib->frag_num = (u8)((le32_to_cpu(report.rxdw2) >> 12) & 0xf);/* u8)prxreport->frag; */
+		pattrib->mfrag = (u8)((le32_to_cpu(report.rxdw1) >> 27) & 0x1);/* u8)prxreport->mf; */
+		pattrib->mdata = (u8)((le32_to_cpu(report.rxdw1) >> 26) & 0x1);/* u8)prxreport->md; */
+
+		pattrib->mcs_rate = (u8)(le32_to_cpu(report.rxdw3) & 0x3f);/* u8)prxreport->rxmcs; */
+		pattrib->rxht = (u8)((le32_to_cpu(report.rxdw3) >> 6) & 0x1);/* u8)prxreport->rxht; */
+
+		pattrib->icv_err = (u8)((le32_to_cpu(report.rxdw0) >> 15) & 0x1);/* u8)prxreport->icverr; */
+		pattrib->shift_sz = (u8)((le32_to_cpu(report.rxdw0) >> 24) & 0x3);
+	} else if (pattrib->pkt_rpt_type == TX_REPORT1) { /* CCX */
+		pattrib->pkt_len = TX_RPT1_PKT_LEN;
+		pattrib->drvinfo_sz = 0;
+	} else if (pattrib->pkt_rpt_type == TX_REPORT2) { /*  TX RPT */
+		pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x3FF);/* Rx length[9:0] */
+		pattrib->drvinfo_sz = 0;
+
+		/*  */
+		/*  Get TX report MAC ID valid. */
+		/*  */
+		pattrib->MacIDValidEntry[0] = le32_to_cpu(report.rxdw4);
+		pattrib->MacIDValidEntry[1] = le32_to_cpu(report.rxdw5);
+
+	} else if (pattrib->pkt_rpt_type == HIS_REPORT) { /*  USB HISR RPT */
+		pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */
+	}
+}
+
+/*
+ * Notice:
+ *	Before calling this function,
+ *	precvframe->u.hdr.rx_data should be ready!
+ */
+void update_recvframe_phyinfo_88e(union recv_frame *precvframe, struct phy_stat *pphy_status)
+{
+	struct adapter *padapter = precvframe->u.hdr.adapter;
+	struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
+	struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter);
+	struct odm_phy_status_info *pPHYInfo  = (struct odm_phy_status_info *)(&pattrib->phy_info);
+	u8 *wlanhdr;
+	struct odm_per_pkt_info	pkt_info;
+	u8 *sa = NULL;
+	struct sta_priv *pstapriv;
+	struct sta_info *psta;
+
+	pkt_info.bPacketMatchBSSID = false;
+	pkt_info.bPacketToSelf = false;
+	pkt_info.bPacketBeacon = false;
+
+	wlanhdr = get_recvframe_data(precvframe);
+
+	pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) &&
+		!pattrib->icv_err && !pattrib->crc_err &&
+		_rtw_memcmp(get_hdr_bssid(wlanhdr),
+		 get_bssid(&padapter->mlmepriv), ETH_ALEN));
+
+	pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID &&
+				 (_rtw_memcmp(get_da(wlanhdr),
+				  myid(&padapter->eeprompriv), ETH_ALEN));
+
+	pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
+				 (GetFrameSubType(wlanhdr) == WIFI_BEACON);
+
+	if (pkt_info.bPacketBeacon) {
+		if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE))
+			sa = padapter->mlmepriv.cur_network.network.MacAddress;
+		/* to do Ad-hoc */
+	} else {
+		sa = get_sa(wlanhdr);
+	}
+
+	pstapriv = &padapter->stapriv;
+	pkt_info.StationID = 0xFF;
+	psta = rtw_get_stainfo(pstapriv, sa);
+	if (psta)
+		pkt_info.StationID = psta->mac_id;
+	pkt_info.Rate = pattrib->mcs_rate;
+
+	ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info));
+
+	precvframe->u.hdr.psta = NULL;
+	if (pkt_info.bPacketMatchBSSID &&
+	    (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))) {
+		if (psta) {
+			precvframe->u.hdr.psta = psta;
+			rtl8188e_process_phy_info(padapter, precvframe);
+		}
+	} else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
+		if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
+			if (psta)
+				precvframe->u.hdr.psta = psta;
+		}
+		rtl8188e_process_phy_info(padapter, precvframe);
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c b/drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c
new file mode 100644
index 0000000..96d698e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_sreset.c
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_SRESET_C_
+
+#include <rtl8188e_sreset.h>
+#include <rtl8188e_hal.h>
+
+void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter)
+{
+}
+
+void rtl8188e_sreset_xmit_status_check(struct adapter *padapter)
+{
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+	struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+	unsigned long current_time;
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	unsigned int diff_time;
+	u32 txdma_status;
+
+	txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS);
+	if (txdma_status != 0x00) {
+		DBG_88E("%s REG_TXDMA_STATUS:0x%08x\n", __func__, txdma_status);
+		rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status);
+		rtl8188e_silentreset_for_specific_platform(padapter);
+	}
+	/* total xmit irp = 4 */
+	current_time = rtw_get_current_time();
+	if (0 == pxmitpriv->free_xmitbuf_cnt) {
+		diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_time);
+
+		if (diff_time > 2000) {
+			if (psrtpriv->last_tx_complete_time == 0) {
+				psrtpriv->last_tx_complete_time = current_time;
+			} else {
+				diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_complete_time);
+				if (diff_time > 4000) {
+					DBG_88E("%s tx hang\n", __func__);
+					rtl8188e_silentreset_for_specific_platform(padapter);
+				}
+			}
+		}
+	}
+}
+
+void rtl8188e_sreset_linked_status_check(struct adapter *padapter)
+{
+	u32 rx_dma_status = 0;
+	u8 fw_status = 0;
+	rx_dma_status = rtw_read32(padapter, REG_RXDMA_STATUS);
+	if (rx_dma_status != 0x00) {
+		DBG_88E("%s REG_RXDMA_STATUS:0x%08x\n", __func__, rx_dma_status);
+		rtw_write32(padapter, REG_RXDMA_STATUS, rx_dma_status);
+	}
+	fw_status = rtw_read8(padapter, REG_FMETHR);
+	if (fw_status != 0x00) {
+		if (fw_status == 1)
+			DBG_88E("%s REG_FW_STATUS (0x%02x), Read_Efuse_Fail !!\n", __func__, fw_status);
+		else if (fw_status == 2)
+			DBG_88E("%s REG_FW_STATUS (0x%02x), Condition_No_Match !!\n", __func__, fw_status);
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
new file mode 100644
index 0000000..7ecbcf7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_xmit.c
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_XMIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8188e_hal.h>
+
+void dump_txrpt_ccx_88e(void *buf)
+{
+	struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf;
+
+	DBG_88E("%s:\n"
+		"tag1:%u, pkt_num:%u, txdma_underflow:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n"
+		"mac_id:%u, pkt_ok:%u, bmc:%u\n"
+		"retry_cnt:%u, lifetime_over:%u, retry_over:%u\n"
+		"ccx_qtime:%u\n"
+		"final_data_rate:0x%02x\n"
+		"qsel:%u, sw:0x%03x\n",
+		__func__, txrpt_ccx->tag1, txrpt_ccx->pkt_num,
+		txrpt_ccx->txdma_underflow, txrpt_ccx->int_bt,
+		txrpt_ccx->int_tri, txrpt_ccx->int_ccx,
+		txrpt_ccx->mac_id, txrpt_ccx->pkt_ok, txrpt_ccx->bmc,
+		txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over,
+		txrpt_ccx->retry_over, txrpt_ccx_qtime_88e(txrpt_ccx),
+		txrpt_ccx->final_data_rate, txrpt_ccx->qsel,
+		txrpt_ccx_sw_88e(txrpt_ccx)
+	);
+}
+
+void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf)
+{
+	struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf;
+
+	if (txrpt_ccx->int_ccx) {
+		if (txrpt_ccx->pkt_ok)
+			rtw_ack_tx_done(&adapter->xmitpriv,
+					RTW_SCTX_DONE_SUCCESS);
+		else
+			rtw_ack_tx_done(&adapter->xmitpriv,
+					RTW_SCTX_DONE_CCX_PKT_FAIL);
+	}
+}
+
+void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag,
+		       struct tx_desc *ptxdesc)
+{
+	u8 dmp_txpkt;
+	bool dump_txdesc = false;
+	rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(dmp_txpkt));
+
+	if (dmp_txpkt == 1) {/* dump txdesc for data frame */
+		DBG_88E("dump tx_desc for data frame\n");
+		if ((frame_tag & 0x0f) == DATA_FRAMETAG)
+			dump_txdesc = true;
+	} else if (dmp_txpkt == 2) {/* dump txdesc for mgnt frame */
+		DBG_88E("dump tx_desc for mgnt frame\n");
+		if ((frame_tag & 0x0f) == MGNT_FRAMETAG)
+			dump_txdesc = true;
+	}
+
+	if (dump_txdesc) {
+		DBG_88E("=====================================\n");
+		DBG_88E("txdw0(0x%08x)\n", ptxdesc->txdw0);
+		DBG_88E("txdw1(0x%08x)\n", ptxdesc->txdw1);
+		DBG_88E("txdw2(0x%08x)\n", ptxdesc->txdw2);
+		DBG_88E("txdw3(0x%08x)\n", ptxdesc->txdw3);
+		DBG_88E("txdw4(0x%08x)\n", ptxdesc->txdw4);
+		DBG_88E("txdw5(0x%08x)\n", ptxdesc->txdw5);
+		DBG_88E("txdw6(0x%08x)\n", ptxdesc->txdw6);
+		DBG_88E("txdw7(0x%08x)\n", ptxdesc->txdw7);
+		DBG_88E("=====================================\n");
+	}
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
new file mode 100644
index 0000000..08dfd94
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_led.c
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8188e_hal.h>
+#include <rtl8188e_led.h>
+
+/*  LED object. */
+
+/*  LED_819xUsb routines. */
+/*	Description: */
+/*		Turn on LED according to LedPin specified. */
+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed)
+{
+	u8	LedCfg;
+
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+		return;
+	LedCfg = rtw_read8(padapter, REG_LEDCFG2);
+	switch (pLed->LedPin) {
+	case LED_PIN_LED0:
+		rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0xf0)|BIT5|BIT6); /*  SW control led0 on. */
+		break;
+	case LED_PIN_LED1:
+		rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x0f)|BIT5); /*  SW control led1 on. */
+		break;
+	default:
+		break;
+	}
+	pLed->bLedOn = true;
+}
+
+/*	Description: */
+/*		Turn off LED according to LedPin specified. */
+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed)
+{
+	u8	LedCfg;
+	struct hal_data_8188e	*pHalData = GET_HAL_DATA(padapter);
+
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+		goto exit;
+
+	LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */
+
+	switch (pLed->LedPin) {
+	case LED_PIN_LED0:
+		if (pHalData->bLedOpenDrain) {
+			/*  Open-drain arrangement for controlling the LED) */
+			LedCfg &= 0x90; /*  Set to software control. */
+			rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3));
+			LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG);
+			LedCfg &= 0xFE;
+			rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg);
+		} else {
+			rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3|BIT5|BIT6));
+		}
+		break;
+	case LED_PIN_LED1:
+		LedCfg &= 0x0f; /*  Set to software control. */
+		rtw_write8(padapter, REG_LEDCFG2, (LedCfg|BIT3));
+		break;
+	default:
+		break;
+	}
+exit:
+	pLed->bLedOn = false;
+}
+
+/*  Interface to manipulate LED objects. */
+/*  Default LED behavior. */
+
+/*	Description: */
+/*		Initialize all LED_871x objects. */
+void rtl8188eu_InitSwLeds(struct adapter *padapter)
+{
+	struct led_priv *pledpriv = &(padapter->ledpriv);
+
+	pledpriv->LedControlHandler = LedControl8188eu;
+
+	InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0);
+
+	InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1);
+}
+
+/*	Description: */
+/*		DeInitialize all LED_819xUsb objects. */
+void rtl8188eu_DeInitSwLeds(struct adapter *padapter)
+{
+	struct led_priv	*ledpriv = &(padapter->ledpriv);
+
+	DeInitLed871x(&(ledpriv->SwLed0));
+	DeInitLed871x(&(ledpriv->SwLed1));
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
new file mode 100644
index 0000000..0f47b89
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_recv.c
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188EU_RECV_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <mlme_osdep.h>
+#include <ip.h>
+#include <if_ether.h>
+#include <ethernet.h>
+
+#include <usb_ops.h>
+#include <wifi.h>
+
+#include <rtl8188e_hal.h>
+
+void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *precvbuf)
+{
+	precvbuf->transfer_len = 0;
+
+	precvbuf->len = 0;
+
+	precvbuf->ref_cnt = 0;
+
+	if (precvbuf->pbuf) {
+		precvbuf->pdata = precvbuf->pbuf;
+		precvbuf->phead = precvbuf->pbuf;
+		precvbuf->ptail = precvbuf->pbuf;
+		precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ;
+	}
+}
+
+int	rtl8188eu_init_recv_priv(struct adapter *padapter)
+{
+	struct recv_priv	*precvpriv = &padapter->recvpriv;
+	int	i, res = _SUCCESS;
+	struct recv_buf *precvbuf;
+
+	tasklet_init(&precvpriv->recv_tasklet,
+		     (void(*)(unsigned long))rtl8188eu_recv_tasklet,
+		     (unsigned long)padapter);
+
+	/* init recv_buf */
+	_rtw_init_queue(&precvpriv->free_recv_buf_queue);
+
+	precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4);
+	if (precvpriv->pallocated_recv_buf == NULL) {
+		res = _FAIL;
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n"));
+		goto exit;
+	}
+	_rtw_memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF * sizeof(struct recv_buf) + 4);
+
+	precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_recv_buf), 4);
+
+
+	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+	for (i = 0; i < NR_RECVBUFF; i++) {
+		_rtw_init_listhead(&precvbuf->list);
+		_rtw_spinlock_init(&precvbuf->recvbuf_lock);
+		precvbuf->alloc_sz = MAX_RECVBUF_SZ;
+		res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf);
+		if (res == _FAIL)
+			break;
+		precvbuf->ref_cnt = 0;
+		precvbuf->adapter = padapter;
+		precvbuf++;
+	}
+	precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
+	skb_queue_head_init(&precvpriv->rx_skb_queue);
+	{
+		int i;
+		size_t tmpaddr = 0;
+		size_t alignment = 0;
+		struct sk_buff *pskb = NULL;
+
+		skb_queue_head_init(&precvpriv->free_recv_skb_queue);
+
+		for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
+			pskb = __netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ, GFP_KERNEL);
+			if (pskb) {
+				pskb->dev = padapter->pnetdev;
+				tmpaddr = (size_t)pskb->data;
+				alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+				skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
+
+				skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+			}
+			pskb = NULL;
+		}
+	}
+exit:
+	return res;
+}
+
+void rtl8188eu_free_recv_priv(struct adapter *padapter)
+{
+	int	i;
+	struct recv_buf	*precvbuf;
+	struct recv_priv	*precvpriv = &padapter->recvpriv;
+
+	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+	for (i = 0; i < NR_RECVBUFF; i++) {
+		rtw_os_recvbuf_resource_free(padapter, precvbuf);
+		precvbuf++;
+	}
+
+	kfree(precvpriv->pallocated_recv_buf);
+
+	if (skb_queue_len(&precvpriv->rx_skb_queue))
+		DBG_88E(KERN_WARNING "rx_skb_queue not empty\n");
+	skb_queue_purge(&precvpriv->rx_skb_queue);
+
+
+	if (skb_queue_len(&precvpriv->free_recv_skb_queue))
+		DBG_88E(KERN_WARNING "free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue));
+
+	skb_queue_purge(&precvpriv->free_recv_skb_queue);
+}
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
new file mode 100644
index 0000000..bd8a9ae
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
@@ -0,0 +1,706 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RTL8188E_XMIT_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+#include <rtl8188e_hal.h>
+
+s32	rtl8188eu_init_xmit_priv(struct adapter *adapt)
+{
+	struct xmit_priv	*pxmitpriv = &adapt->xmitpriv;
+
+	tasklet_init(&pxmitpriv->xmit_tasklet,
+		     (void(*)(unsigned long))rtl8188eu_xmit_tasklet,
+		     (unsigned long)adapt);
+	return _SUCCESS;
+}
+
+void	rtl8188eu_free_xmit_priv(struct adapter *adapt)
+{
+}
+
+static u8 urb_zero_packet_chk(struct adapter *adapt, int sz)
+{
+	u8 set_tx_desc_offset;
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+	set_tx_desc_offset = (((sz + TXDESC_SIZE) %  haldata->UsbBulkOutSize) == 0) ? 1 : 0;
+
+	return set_tx_desc_offset;
+}
+
+static void rtl8188eu_cal_txdesc_chksum(struct tx_desc	*ptxdesc)
+{
+	u16	*usptr = (u16 *)ptxdesc;
+	u32 count = 16;		/*  (32 bytes / 2 bytes per XOR) => 16 times */
+	u32 index;
+	u16 checksum = 0;
+
+	/* Clear first */
+	ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
+
+	for (index = 0; index < count; index++)
+		checksum = checksum ^ le16_to_cpu(*(__le16 *)(usptr + index));
+	ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff & checksum);
+}
+
+/*  Description: In normal chip, we should send some packet to Hw which will be used by Fw */
+/*			in FW LPS mode. The function is to fill the Tx descriptor of this packets, then */
+/*			Fw can tell Hw to send these packet derectly. */
+void rtl8188e_fill_fake_txdesc(struct adapter *adapt, u8 *desc, u32 BufferLen, u8  ispspoll, u8  is_btqosnull)
+{
+	struct tx_desc *ptxdesc;
+
+	/*  Clear all status */
+	ptxdesc = (struct tx_desc *)desc;
+	_rtw_memset(desc, 0, TXDESC_SIZE);
+
+	/* offset 0 */
+	ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); /* own, bFirstSeg, bLastSeg; */
+
+	ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); /* 32 bytes for TX Desc */
+
+	ptxdesc->txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); /*  Buffer size + command header */
+
+	/* offset 4 */
+	ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<<QSEL_SHT)&0x00001f00); /*  Fixed queue of Mgnt queue */
+
+	/* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */
+	if (ispspoll) {
+		ptxdesc->txdw1 |= cpu_to_le32(NAVUSEHDR);
+	} else {
+		ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); /*  Hw set sequence number */
+		ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); /* set bit3 to 1. Suugested by TimChen. 2009.12.29. */
+	}
+
+	if (is_btqosnull)
+		ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); /*  BT NULL */
+
+	/* offset 16 */
+	ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
+
+	/*  USB interface drop packet if the checksum of descriptor isn't correct. */
+	/*  Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). */
+	rtl8188eu_cal_txdesc_chksum(ptxdesc);
+}
+
+static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc)
+{
+	if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
+		switch (pattrib->encrypt) {
+		/* SEC_TYPE : 0:NO_ENC,1:WEP40/TKIP,2:WAPI,3:AES */
+		case _WEP40_:
+		case _WEP104_:
+			ptxdesc->txdw1 |= cpu_to_le32((0x01<<SEC_TYPE_SHT)&0x00c00000);
+			ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
+			break;
+		case _TKIP_:
+		case _TKIP_WTMIC_:
+			ptxdesc->txdw1 |= cpu_to_le32((0x01<<SEC_TYPE_SHT)&0x00c00000);
+			ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
+			break;
+		case _AES_:
+			ptxdesc->txdw1 |= cpu_to_le32((0x03<<SEC_TYPE_SHT)&0x00c00000);
+			ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
+			break;
+		case _NO_PRIVACY_:
+		default:
+			break;
+		}
+	}
+}
+
+static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
+{
+	switch (pattrib->vcs_mode) {
+	case RTS_CTS:
+		*pdw |= cpu_to_le32(RTS_EN);
+		break;
+	case CTS_TO_SELF:
+		*pdw |= cpu_to_le32(CTS_2_SELF);
+		break;
+	case NONE_VCS:
+	default:
+		break;
+	}
+	if (pattrib->vcs_mode) {
+		*pdw |= cpu_to_le32(HW_RTS_EN);
+		/*  Set RTS BW */
+		if (pattrib->ht_en) {
+			*pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ?	cpu_to_le32(BIT(27)) : 0;
+
+			if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+				*pdw |= cpu_to_le32((0x01 << 28) & 0x30000000);
+			else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+				*pdw |= cpu_to_le32((0x02 << 28) & 0x30000000);
+			else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+				*pdw |= 0;
+			else
+				*pdw |= cpu_to_le32((0x03 << 28) & 0x30000000);
+		}
+	}
+}
+
+static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
+{
+	if (pattrib->ht_en) {
+		*pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ?	cpu_to_le32(BIT(25)) : 0;
+
+		if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+			*pdw |= cpu_to_le32((0x01 << DATA_SC_SHT) & 0x003f0000);
+		else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+			*pdw |= cpu_to_le32((0x02 << DATA_SC_SHT) & 0x003f0000);
+		else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+			*pdw |= 0;
+		else
+			*pdw |= cpu_to_le32((0x03 << DATA_SC_SHT) & 0x003f0000);
+	}
+}
+
+static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt)
+{
+	int	pull = 0;
+	uint	qsel;
+	u8 data_rate, pwr_status, offset;
+	struct adapter		*adapt = pxmitframe->padapter;
+	struct pkt_attrib	*pattrib = &pxmitframe->attrib;
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+	struct tx_desc	*ptxdesc = (struct tx_desc *)pmem;
+	struct mlme_ext_priv	*pmlmeext = &adapt->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	int	bmcst = IS_MCAST(pattrib->ra);
+
+	if (adapt->registrypriv.mp_mode == 0) {
+		if ((!bagg_pkt) && (urb_zero_packet_chk(adapt, sz) == 0)) {
+			ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ);
+			pull = 1;
+		}
+	}
+
+	_rtw_memset(ptxdesc, 0, sizeof(struct tx_desc));
+
+	/* 4 offset 0 */
+	ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+	ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff);/* update TXPKTSIZE */
+
+	offset = TXDESC_SIZE + OFFSET_SZ;
+
+	ptxdesc->txdw0 |= cpu_to_le32(((offset) << OFFSET_SHT) & 0x00ff0000);/* 32 bytes for TX Desc */
+
+	if (bmcst)
+		ptxdesc->txdw0 |= cpu_to_le32(BMC);
+
+	if (adapt->registrypriv.mp_mode == 0) {
+		if (!bagg_pkt) {
+			if ((pull) && (pxmitframe->pkt_offset > 0))
+				pxmitframe->pkt_offset = pxmitframe->pkt_offset - 1;
+		}
+	}
+
+	/*  pkt_offset, unit:8 bytes padding */
+	if (pxmitframe->pkt_offset > 0)
+		ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000);
+
+	/* driver uses rate */
+	ptxdesc->txdw4 |= cpu_to_le32(USERATE);/* rate control always by driver */
+
+	if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) {
+		/* offset 4 */
+		ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3F);
+
+		qsel = (uint)(pattrib->qsel & 0x0000001f);
+		ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
+
+		ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000);
+
+		fill_txdesc_sectype(pattrib, ptxdesc);
+
+		if (pattrib->ampdu_en) {
+			ptxdesc->txdw2 |= cpu_to_le32(AGG_EN);/* AGG EN */
+			ptxdesc->txdw6 = cpu_to_le32(0x6666f800);
+		} else {
+			ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */
+		}
+
+		/* offset 8 */
+
+		/* offset 12 */
+		ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0FFF0000);
+
+		/* offset 16 , offset 20 */
+		if (pattrib->qos_en)
+			ptxdesc->txdw4 |= cpu_to_le32(QOS);/* QoS */
+
+		/* offset 20 */
+		if (pxmitframe->agg_num > 1)
+			ptxdesc->txdw5 |= cpu_to_le32((pxmitframe->agg_num << USB_TXAGG_NUM_SHT) & 0xFF000000);
+
+		if ((pattrib->ether_type != 0x888e) &&
+		    (pattrib->ether_type != 0x0806) &&
+		    (pattrib->ether_type != 0x88b4) &&
+		    (pattrib->dhcp_pkt != 1)) {
+			/* Non EAP & ARP & DHCP type data packet */
+
+			fill_txdesc_vcs(pattrib, &ptxdesc->txdw4);
+			fill_txdesc_phy(pattrib, &ptxdesc->txdw4);
+
+			ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate=24M */
+			ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* DATA/RTS  Rate FB LMT */
+
+			if (pattrib->ht_en) {
+				if (ODM_RA_GetShortGI_8188E(&haldata->odmpriv, pattrib->mac_id))
+					ptxdesc->txdw5 |= cpu_to_le32(SGI);/* SGI */
+			}
+			data_rate = ODM_RA_GetDecisionRate_8188E(&haldata->odmpriv, pattrib->mac_id);
+			ptxdesc->txdw5 |= cpu_to_le32(data_rate & 0x3F);
+			pwr_status = ODM_RA_GetHwPwrStatus_8188E(&haldata->odmpriv, pattrib->mac_id);
+			ptxdesc->txdw4 |= cpu_to_le32((pwr_status & 0x7) << PWR_STATUS_SHT);
+		} else {
+			/*  EAP data packet and ARP packet and DHCP. */
+			/*  Use the 1M data rate to send the EAP/ARP packet. */
+			/*  This will maybe make the handshake smooth. */
+			ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */
+			if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
+				ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/*  DATA_SHORT */
+			ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
+		}
+	} else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) {
+		/* offset 4 */
+		ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3f);
+
+		qsel = (uint)(pattrib->qsel&0x0000001f);
+		ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
+
+		ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000f0000);
+
+		/* offset 8 */
+		/* CCX-TXRPT ack for xmit mgmt frames. */
+		if (pxmitframe->ack_report)
+			ptxdesc->txdw2 |= cpu_to_le32(BIT(19));
+
+		/* offset 12 */
+		ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<SEQ_SHT)&0x0FFF0000);
+
+		/* offset 20 */
+		ptxdesc->txdw5 |= cpu_to_le32(RTY_LMT_EN);/* retry limit enable */
+		if (pattrib->retry_ctrl)
+			ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */
+		else
+			ptxdesc->txdw5 |= cpu_to_le32(0x00300000);/* retry limit = 12 */
+
+		ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
+	} else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) {
+		DBG_88E("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
+	} else if (((pxmitframe->frame_tag&0x0f) == MP_FRAMETAG) &&
+		   (adapt->registrypriv.mp_mode == 1)) {
+		fill_txdesc_for_mp(adapt, ptxdesc);
+	} else {
+		DBG_88E("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag);
+
+		/* offset 4 */
+		ptxdesc->txdw1 |= cpu_to_le32((4) & 0x3f);/* CAM_ID(MAC_ID) */
+
+		ptxdesc->txdw1 |= cpu_to_le32((6 << RATE_ID_SHT) & 0x000f0000);/* raid */
+
+		/* offset 8 */
+
+		/* offset 12 */
+		ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<SEQ_SHT)&0x0fff0000);
+
+		/* offset 20 */
+		ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
+	}
+
+	/*  2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */
+	/*  (1) The sequence number of each non-Qos frame / broadcast / multicast / */
+	/*  mgnt frame should be controled by Hw because Fw will also send null data */
+	/*  which we cannot control when Fw LPS enable. */
+	/*  --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */
+	/*  (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */
+	/*  (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */
+	/*  2010.06.23. Added by tynli. */
+	if (!pattrib->qos_en) {
+		ptxdesc->txdw3 |= cpu_to_le32(EN_HWSEQ); /*  Hw set sequence number */
+		ptxdesc->txdw4 |= cpu_to_le32(HW_SSN);	/*  Hw set sequence number */
+	}
+
+	ODM_SetTxAntByTxInfo_88E(&haldata->odmpriv, pmem, pattrib->mac_id);
+
+	rtl8188eu_cal_txdesc_chksum(ptxdesc);
+	_dbg_dump_tx_info(adapt, pxmitframe->frame_tag, ptxdesc);
+	return pull;
+}
+
+/* for non-agg data frame or  management frame */
+static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+	s32 ret = _SUCCESS;
+	s32 inner_ret = _SUCCESS;
+	int t, sz, w_sz, pull = 0;
+	u8 *mem_addr;
+	u32 ff_hwaddr;
+	struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
+	struct pkt_attrib *pattrib = &pxmitframe->attrib;
+	struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+	struct security_priv *psecuritypriv = &adapt->securitypriv;
+	if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
+	    (pxmitframe->attrib.ether_type != 0x0806) &&
+	    (pxmitframe->attrib.ether_type != 0x888e) &&
+	    (pxmitframe->attrib.ether_type != 0x88b4) &&
+	    (pxmitframe->attrib.dhcp_pkt != 1))
+		rtw_issue_addbareq_cmd(adapt, pxmitframe);
+	mem_addr = pxmitframe->buf_addr;
+
+	RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n"));
+
+	for (t = 0; t < pattrib->nr_frags; t++) {
+		if (inner_ret != _SUCCESS && ret == _SUCCESS)
+			ret = _FAIL;
+
+		if (t != (pattrib->nr_frags - 1)) {
+			RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("pattrib->nr_frags=%d\n", pattrib->nr_frags));
+
+			sz = pxmitpriv->frag_len;
+			sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : pattrib->icv_len);
+		} else {
+			/* no frag */
+			sz = pattrib->last_txcmdsz;
+		}
+
+		pull = update_txdesc(pxmitframe, mem_addr, sz, false);
+
+		if (pull) {
+			mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */
+			pxmitframe->buf_addr = mem_addr;
+			w_sz = sz + TXDESC_SIZE;
+		} else {
+			w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ;
+		}
+		ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
+
+		inner_ret = rtw_write_port(adapt, ff_hwaddr, w_sz, (unsigned char *)pxmitbuf);
+
+		rtw_count_tx_stats(adapt, pxmitframe, sz);
+
+		RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_write_port, w_sz=%d\n", w_sz));
+
+		mem_addr += w_sz;
+
+		mem_addr = (u8 *)RND4(((size_t)(mem_addr)));
+	}
+
+	rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+	if  (ret != _SUCCESS)
+		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
+
+	return ret;
+}
+
+static u32 xmitframe_need_length(struct xmit_frame *pxmitframe)
+{
+	struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+	u32 len = 0;
+
+	/*  no consider fragement */
+	len = pattrib->hdrlen + pattrib->iv_len +
+		SNAP_SIZE + sizeof(u16) +
+		pattrib->pktlen +
+		((pattrib->bswenc) ? pattrib->icv_len : 0);
+
+	if (pattrib->encrypt == _TKIP_)
+		len += 8;
+
+	return len;
+}
+
+s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+	struct xmit_frame *pxmitframe = NULL;
+	struct xmit_frame *pfirstframe = NULL;
+
+	/*  aggregate variable */
+	struct hw_xmit *phwxmit;
+	struct sta_info *psta = NULL;
+	struct tx_servq *ptxservq = NULL;
+
+	unsigned long irql;
+	struct list_head *xmitframe_plist = NULL, *xmitframe_phead = NULL;
+
+	u32 pbuf;	/*  next pkt address */
+	u32 pbuf_tail;	/*  last pkt tail */
+	u32 len;	/*  packet length, except TXDESC_SIZE and PKT_OFFSET */
+
+	u32 bulksize = haldata->UsbBulkOutSize;
+	u8 desc_cnt;
+	u32 bulkptr;
+
+	/*  dump frame variable */
+	u32 ff_hwaddr;
+
+	RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n"));
+
+	/*  check xmitbuffer is ok */
+	if (pxmitbuf == NULL) {
+		pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+		if (pxmitbuf == NULL)
+			return false;
+	}
+
+	/* 3 1. pick up first frame */
+	do {
+		rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+		pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+		if (pxmitframe == NULL) {
+			/*  no more xmit frame, release xmit buffer */
+			rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+			return false;
+		}
+
+		pxmitframe->pxmitbuf = pxmitbuf;
+		pxmitframe->buf_addr = pxmitbuf->pbuf;
+		pxmitbuf->priv_data = pxmitframe;
+
+		pxmitframe->agg_num = 1; /*  alloc xmitframe should assign to 1. */
+		pxmitframe->pkt_offset = 1; /*  first frame of aggregation, reserve offset */
+
+		rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+
+		/*  always return ndis_packet after rtw_xmitframe_coalesce */
+		rtw_os_xmit_complete(adapt, pxmitframe);
+
+		break;
+	} while (1);
+
+	/* 3 2. aggregate same priority and same DA(AP or STA) frames */
+	pfirstframe = pxmitframe;
+	len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset*PACKET_OFFSET_SZ);
+	pbuf_tail = len;
+	pbuf = _RND8(pbuf_tail);
+
+	/*  check pkt amount in one bulk */
+	desc_cnt = 0;
+	bulkptr = bulksize;
+	if (pbuf < bulkptr) {
+		desc_cnt++;
+	} else {
+		desc_cnt = 0;
+		bulkptr = ((pbuf / bulksize) + 1) * bulksize; /*  round to next bulksize */
+	}
+
+	/*  dequeue same priority packet from station tx queue */
+	psta = pfirstframe->attrib.psta;
+	switch (pfirstframe->attrib.priority) {
+	case 1:
+	case 2:
+		ptxservq = &(psta->sta_xmitpriv.bk_q);
+		phwxmit = pxmitpriv->hwxmits + 3;
+		break;
+	case 4:
+	case 5:
+		ptxservq = &(psta->sta_xmitpriv.vi_q);
+		phwxmit = pxmitpriv->hwxmits + 1;
+		break;
+	case 6:
+	case 7:
+		ptxservq = &(psta->sta_xmitpriv.vo_q);
+		phwxmit = pxmitpriv->hwxmits;
+		break;
+	case 0:
+	case 3:
+	default:
+		ptxservq = &(psta->sta_xmitpriv.be_q);
+		phwxmit = pxmitpriv->hwxmits + 2;
+		break;
+	}
+	_enter_critical_bh(&pxmitpriv->lock, &irql);
+
+	xmitframe_phead = get_list_head(&ptxservq->sta_pending);
+	xmitframe_plist = get_next(xmitframe_phead);
+
+	while (!rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) {
+		pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list);
+		xmitframe_plist = get_next(xmitframe_plist);
+
+		pxmitframe->agg_num = 0; /*  not first frame of aggregation */
+		pxmitframe->pkt_offset = 0; /*  not first frame of aggregation, no need to reserve offset */
+
+		len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset*PACKET_OFFSET_SZ);
+
+		if (_RND8(pbuf + len) > MAX_XMITBUF_SZ) {
+			pxmitframe->agg_num = 1;
+			pxmitframe->pkt_offset = 1;
+			break;
+		}
+		rtw_list_delete(&pxmitframe->list);
+		ptxservq->qcnt--;
+		phwxmit->accnt--;
+
+		pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf;
+
+		rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+		/*  always return ndis_packet after rtw_xmitframe_coalesce */
+		rtw_os_xmit_complete(adapt, pxmitframe);
+
+		/*  (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz */
+		update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, true);
+
+		/*  don't need xmitframe any more */
+		rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+		/*  handle pointer and stop condition */
+		pbuf_tail = pbuf + len;
+		pbuf = _RND8(pbuf_tail);
+
+		pfirstframe->agg_num++;
+		if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num)
+			break;
+
+		if (pbuf < bulkptr) {
+			desc_cnt++;
+			if (desc_cnt == haldata->UsbTxAggDescNum)
+				break;
+		} else {
+			desc_cnt = 0;
+			bulkptr = ((pbuf / bulksize) + 1) * bulksize;
+		}
+	} /* end while (aggregate same priority and same DA(AP or STA) frames) */
+
+	if (_rtw_queue_empty(&ptxservq->sta_pending) == true)
+		rtw_list_delete(&ptxservq->tx_pending);
+
+	_exit_critical_bh(&pxmitpriv->lock, &irql);
+	if ((pfirstframe->attrib.ether_type != 0x0806) &&
+	    (pfirstframe->attrib.ether_type != 0x888e) &&
+	    (pfirstframe->attrib.ether_type != 0x88b4) &&
+	    (pfirstframe->attrib.dhcp_pkt != 1))
+		rtw_issue_addbareq_cmd(adapt, pfirstframe);
+	/* 3 3. update first frame txdesc */
+	if ((pbuf_tail % bulksize) == 0) {
+		/*  remove pkt_offset */
+		pbuf_tail -= PACKET_OFFSET_SZ;
+		pfirstframe->buf_addr += PACKET_OFFSET_SZ;
+		pfirstframe->pkt_offset--;
+	}
+
+	update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, true);
+
+	/* 3 4. write xmit buffer to USB FIFO */
+	ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe);
+	rtw_write_port(adapt, ff_hwaddr, pbuf_tail, (u8 *)pxmitbuf);
+
+	/* 3 5. update statisitc */
+	pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE);
+	pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ);
+
+	rtw_count_tx_stats(adapt, pfirstframe, pbuf_tail);
+
+	rtw_free_xmitframe(pxmitpriv, pfirstframe);
+
+	return true;
+}
+
+static s32 xmitframe_direct(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+	s32 res = _SUCCESS;
+
+	res = rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe);
+	if (res == _SUCCESS)
+		rtw_dump_xframe(adapt, pxmitframe);
+	else
+		DBG_88E("==> %s xmitframe_coalsece failed\n", __func__);
+	return res;
+}
+
+/*
+ * Return
+ *	true	dump packet directly
+ *	false	enqueue packet
+ */
+static s32 pre_xmitframe(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+	unsigned long irql;
+	s32 res;
+	struct xmit_buf *pxmitbuf = NULL;
+	struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+	struct pkt_attrib *pattrib = &pxmitframe->attrib;
+	struct mlme_priv *pmlmepriv = &adapt->mlmepriv;
+
+	_enter_critical_bh(&pxmitpriv->lock, &irql);
+
+	if (rtw_txframes_sta_ac_pending(adapt, pattrib) > 0)
+		goto enqueue;
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true)
+		goto enqueue;
+
+	pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+	if (pxmitbuf == NULL)
+		goto enqueue;
+
+	_exit_critical_bh(&pxmitpriv->lock, &irql);
+
+	pxmitframe->pxmitbuf = pxmitbuf;
+	pxmitframe->buf_addr = pxmitbuf->pbuf;
+	pxmitbuf->priv_data = pxmitframe;
+
+	if (xmitframe_direct(adapt, pxmitframe) != _SUCCESS) {
+		rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+		rtw_free_xmitframe(pxmitpriv, pxmitframe);
+	}
+
+	return true;
+
+enqueue:
+	res = rtw_xmitframe_enqueue(adapt, pxmitframe);
+	_exit_critical_bh(&pxmitpriv->lock, &irql);
+
+	if (res != _SUCCESS) {
+		RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n"));
+		rtw_free_xmitframe(pxmitpriv, pxmitframe);
+
+		/*  Trick, make the statistics correct */
+		pxmitpriv->tx_pkts--;
+		pxmitpriv->tx_drop++;
+		return true;
+	}
+
+	return false;
+}
+
+s32 rtl8188eu_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe)
+{
+	return rtw_dump_xframe(adapt, pmgntframe);
+}
+
+/*
+ * Return
+ *	true	dump packet directly ok
+ *	false	temporary can't transmit packets to hardware
+ */
+s32 rtl8188eu_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe)
+{
+	return pre_xmitframe(adapt, pxmitframe);
+}
diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c
new file mode 100644
index 0000000..5e656ce
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c
@@ -0,0 +1,2346 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _HCI_HAL_INIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+#include <rtl8188e_hal.h>
+#include <rtl8188e_led.h>
+#include <rtw_iol.h>
+#include <usb_ops.h>
+#include <usb_hal.h>
+#include <usb_osintf.h>
+
+#define		HAL_MAC_ENABLE	1
+#define		HAL_BB_ENABLE		1
+#define		HAL_RF_ENABLE		1
+
+static void _ConfigNormalChipOutEP_8188E(struct adapter *adapt, u8 NumOutPipe)
+{
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(adapt);
+
+	switch (NumOutPipe) {
+	case	3:
+		haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ | TX_SELE_NQ;
+		haldata->OutEpNumber = 3;
+		break;
+	case	2:
+		haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_NQ;
+		haldata->OutEpNumber = 2;
+		break;
+	case	1:
+		haldata->OutEpQueueSel = TX_SELE_HQ;
+		haldata->OutEpNumber = 1;
+		break;
+	default:
+		break;
+	}
+	DBG_88E("%s OutEpQueueSel(0x%02x), OutEpNumber(%d)\n", __func__, haldata->OutEpQueueSel, haldata->OutEpNumber);
+}
+
+static bool HalUsbSetQueuePipeMapping8188EUsb(struct adapter *adapt, u8 NumInPipe, u8 NumOutPipe)
+{
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(adapt);
+	bool			result		= false;
+
+	_ConfigNormalChipOutEP_8188E(adapt, NumOutPipe);
+
+	/*  Normal chip with one IN and one OUT doesn't have interrupt IN EP. */
+	if (1 == haldata->OutEpNumber) {
+		if (1 != NumInPipe)
+			return result;
+	}
+
+	/*  All config other than above support one Bulk IN and one Interrupt IN. */
+
+	result = Hal_MappingOutPipe(adapt, NumOutPipe);
+
+	return result;
+}
+
+static void rtl8188eu_interface_configure(struct adapter *adapt)
+{
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(adapt);
+	struct dvobj_priv	*pdvobjpriv = adapter_to_dvobj(adapt);
+
+	if (pdvobjpriv->ishighspeed)
+		haldata->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE;/* 512 bytes */
+	else
+		haldata->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE;/* 64 bytes */
+
+	haldata->interfaceIndex = pdvobjpriv->InterfaceNumber;
+
+	haldata->UsbTxAggMode		= 1;
+	haldata->UsbTxAggDescNum	= 0x6;	/*  only 4 bits */
+
+	haldata->UsbRxAggMode		= USB_RX_AGG_DMA;/*  USB_RX_AGG_DMA; */
+	haldata->UsbRxAggBlockCount	= 8; /* unit : 512b */
+	haldata->UsbRxAggBlockTimeout	= 0x6;
+	haldata->UsbRxAggPageCount	= 48; /* uint :128 b 0x0A;	10 = MAX_RX_DMA_BUFFER_SIZE/2/haldata->UsbBulkOutSize */
+	haldata->UsbRxAggPageTimeout	= 0x4; /* 6, absolute time = 34ms/(2^6) */
+
+	HalUsbSetQueuePipeMapping8188EUsb(adapt,
+				pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes);
+}
+
+static u32 rtl8188eu_InitPowerOn(struct adapter *adapt)
+{
+	u16 value16;
+	/*  HW Power on sequence */
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(adapt);
+	if (haldata->bMacPwrCtrlOn)
+		return _SUCCESS;
+
+	if (!HalPwrSeqCmdParsing(adapt, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_PWR_ON_FLOW)) {
+		DBG_88E(KERN_ERR "%s: run power on flow fail\n", __func__);
+		return _FAIL;
+	}
+
+	/*  Enable MAC DMA/WMAC/SCHEDULE/SEC block */
+	/*  Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */
+	rtw_write16(adapt, REG_CR, 0x00);  /* suggseted by zhouzhou, by page, 20111230 */
+
+		/*  Enable MAC DMA/WMAC/SCHEDULE/SEC block */
+	value16 = rtw_read16(adapt, REG_CR);
+	value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN
+				| PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN);
+	/*  for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */
+
+	rtw_write16(adapt, REG_CR, value16);
+	haldata->bMacPwrCtrlOn = true;
+
+	return _SUCCESS;
+}
+
+/*  Shall USB interface init this? */
+static void _InitInterrupt(struct adapter *Adapter)
+{
+	u32 imr, imr_ex;
+	u8  usb_opt;
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	/* HISR write one to clear */
+	rtw_write32(Adapter, REG_HISR_88E, 0xFFFFFFFF);
+	/*  HIMR - */
+	imr = IMR_PSTIMEOUT_88E | IMR_TBDER_88E | IMR_CPWM_88E | IMR_CPWM2_88E;
+	rtw_write32(Adapter, REG_HIMR_88E, imr);
+	haldata->IntrMask[0] = imr;
+
+	imr_ex = IMR_TXERR_88E | IMR_RXERR_88E | IMR_TXFOVW_88E | IMR_RXFOVW_88E;
+	rtw_write32(Adapter, REG_HIMRE_88E, imr_ex);
+	haldata->IntrMask[1] = imr_ex;
+
+	/*  REG_USB_SPECIAL_OPTION - BIT(4) */
+	/*  0; Use interrupt endpoint to upload interrupt pkt */
+	/*  1; Use bulk endpoint to upload interrupt pkt, */
+	usb_opt = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION);
+
+	if (!adapter_to_dvobj(Adapter)->ishighspeed)
+		usb_opt = usb_opt & (~INT_BULK_SEL);
+	else
+		usb_opt = usb_opt | (INT_BULK_SEL);
+
+	rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, usb_opt);
+}
+
+static void _InitQueueReservedPage(struct adapter *Adapter)
+{
+	struct hal_data_8188e		*haldata = GET_HAL_DATA(Adapter);
+	struct registry_priv	*pregistrypriv = &Adapter->registrypriv;
+	u32 numHQ	= 0;
+	u32 numLQ	= 0;
+	u32 numNQ	= 0;
+	u32 numPubQ;
+	u32 value32;
+	u8 value8;
+	bool bWiFiConfig = pregistrypriv->wifi_spec;
+
+	if (bWiFiConfig) {
+		if (haldata->OutEpQueueSel & TX_SELE_HQ)
+			numHQ =  0x29;
+
+		if (haldata->OutEpQueueSel & TX_SELE_LQ)
+			numLQ = 0x1C;
+
+		/*  NOTE: This step shall be proceed before writting REG_RQPN. */
+		if (haldata->OutEpQueueSel & TX_SELE_NQ)
+			numNQ = 0x1C;
+		value8 = (u8)_NPQ(numNQ);
+		rtw_write8(Adapter, REG_RQPN_NPQ, value8);
+
+		numPubQ = 0xA8 - numHQ - numLQ - numNQ;
+
+		/*  TX DMA */
+		value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN;
+		rtw_write32(Adapter, REG_RQPN, value32);
+	} else {
+		rtw_write16(Adapter, REG_RQPN_NPQ, 0x0000);/* Just follow MP Team,??? Georgia 03/28 */
+		rtw_write16(Adapter, REG_RQPN_NPQ, 0x0d);
+		rtw_write32(Adapter, REG_RQPN, 0x808E000d);/* reserve 7 page for LPS */
+	}
+}
+
+static void _InitTxBufferBoundary(struct adapter *Adapter, u8 txpktbuf_bndy)
+{
+	rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+	rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+	rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy);
+	rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy);
+	rtw_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy);
+}
+
+static void _InitPageBoundary(struct adapter *Adapter)
+{
+	/*  RX Page Boundary */
+	/*  */
+	u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E-1;
+
+	rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy);
+}
+
+static void _InitNormalChipRegPriority(struct adapter *Adapter, u16 beQ,
+				       u16 bkQ, u16 viQ, u16 voQ, u16 mgtQ,
+				       u16 hiQ)
+{
+	u16 value16	= (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7);
+
+	value16 |= _TXDMA_BEQ_MAP(beQ)	| _TXDMA_BKQ_MAP(bkQ) |
+		   _TXDMA_VIQ_MAP(viQ)	| _TXDMA_VOQ_MAP(voQ) |
+		   _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ);
+
+	rtw_write16(Adapter, REG_TRXDMA_CTRL, value16);
+}
+
+static void _InitNormalChipOneOutEpPriority(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(Adapter);
+
+	u16 value = 0;
+	switch (haldata->OutEpQueueSel) {
+	case TX_SELE_HQ:
+		value = QUEUE_HIGH;
+		break;
+	case TX_SELE_LQ:
+		value = QUEUE_LOW;
+		break;
+	case TX_SELE_NQ:
+		value = QUEUE_NORMAL;
+		break;
+	default:
+		break;
+	}
+	_InitNormalChipRegPriority(Adapter, value, value, value, value,
+				   value, value);
+}
+
+static void _InitNormalChipTwoOutEpPriority(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(Adapter);
+	struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+	u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ;
+	u16 valueHi = 0;
+	u16 valueLow = 0;
+
+	switch (haldata->OutEpQueueSel) {
+	case (TX_SELE_HQ | TX_SELE_LQ):
+		valueHi = QUEUE_HIGH;
+		valueLow = QUEUE_LOW;
+		break;
+	case (TX_SELE_NQ | TX_SELE_LQ):
+		valueHi = QUEUE_NORMAL;
+		valueLow = QUEUE_LOW;
+		break;
+	case (TX_SELE_HQ | TX_SELE_NQ):
+		valueHi = QUEUE_HIGH;
+		valueLow = QUEUE_NORMAL;
+		break;
+	default:
+		break;
+	}
+
+	if (!pregistrypriv->wifi_spec) {
+		beQ	= valueLow;
+		bkQ	= valueLow;
+		viQ	= valueHi;
+		voQ	= valueHi;
+		mgtQ	= valueHi;
+		hiQ	= valueHi;
+	} else {/* for WMM ,CONFIG_OUT_EP_WIFI_MODE */
+		beQ	= valueLow;
+		bkQ	= valueHi;
+		viQ	= valueHi;
+		voQ	= valueLow;
+		mgtQ	= valueHi;
+		hiQ	= valueHi;
+	}
+	_InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
+}
+
+static void _InitNormalChipThreeOutEpPriority(struct adapter *Adapter)
+{
+	struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+	u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ;
+
+	if (!pregistrypriv->wifi_spec) {/*  typical setting */
+		beQ	= QUEUE_LOW;
+		bkQ	= QUEUE_LOW;
+		viQ	= QUEUE_NORMAL;
+		voQ	= QUEUE_HIGH;
+		mgtQ	= QUEUE_HIGH;
+		hiQ	= QUEUE_HIGH;
+	} else {/*  for WMM */
+		beQ	= QUEUE_LOW;
+		bkQ	= QUEUE_NORMAL;
+		viQ	= QUEUE_NORMAL;
+		voQ	= QUEUE_HIGH;
+		mgtQ	= QUEUE_HIGH;
+		hiQ	= QUEUE_HIGH;
+	}
+	_InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
+}
+
+static void _InitQueuePriority(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	switch (haldata->OutEpNumber) {
+	case 1:
+		_InitNormalChipOneOutEpPriority(Adapter);
+		break;
+	case 2:
+		_InitNormalChipTwoOutEpPriority(Adapter);
+		break;
+	case 3:
+		_InitNormalChipThreeOutEpPriority(Adapter);
+		break;
+	default:
+		break;
+	}
+}
+
+static void _InitNetworkType(struct adapter *Adapter)
+{
+	u32 value32;
+
+	value32 = rtw_read32(Adapter, REG_CR);
+	/*  TODO: use the other function to set network type */
+	value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP);
+
+	rtw_write32(Adapter, REG_CR, value32);
+}
+
+static void _InitTransferPageSize(struct adapter *Adapter)
+{
+	/*  Tx page size is always 128. */
+
+	u8 value8;
+	value8 = _PSRX(PBP_128) | _PSTX(PBP_128);
+	rtw_write8(Adapter, REG_PBP, value8);
+}
+
+static void _InitDriverInfoSize(struct adapter *Adapter, u8 drvInfoSize)
+{
+	rtw_write8(Adapter, REG_RX_DRVINFO_SZ, drvInfoSize);
+}
+
+static void _InitWMACSetting(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	haldata->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AB |
+				  RCR_CBSSID_DATA | RCR_CBSSID_BCN |
+				  RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL |
+				  RCR_APP_MIC | RCR_APP_PHYSTS;
+
+	/*  some REG_RCR will be modified later by phy_ConfigMACWithHeaderFile() */
+	rtw_write32(Adapter, REG_RCR, haldata->ReceiveConfig);
+
+	/*  Accept all multicast address */
+	rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF);
+	rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF);
+}
+
+static void _InitAdaptiveCtrl(struct adapter *Adapter)
+{
+	u16 value16;
+	u32 value32;
+
+	/*  Response Rate Set */
+	value32 = rtw_read32(Adapter, REG_RRSR);
+	value32 &= ~RATE_BITMAP_ALL;
+	value32 |= RATE_RRSR_CCK_ONLY_1M;
+	rtw_write32(Adapter, REG_RRSR, value32);
+
+	/*  CF-END Threshold */
+
+	/*  SIFS (used in NAV) */
+	value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10);
+	rtw_write16(Adapter, REG_SPEC_SIFS, value16);
+
+	/*  Retry Limit */
+	value16 = _LRL(0x30) | _SRL(0x30);
+	rtw_write16(Adapter, REG_RL, value16);
+}
+
+static void _InitEDCA(struct adapter *Adapter)
+{
+	/*  Set Spec SIFS (used in NAV) */
+	rtw_write16(Adapter, REG_SPEC_SIFS, 0x100a);
+	rtw_write16(Adapter, REG_MAC_SPEC_SIFS, 0x100a);
+
+	/*  Set SIFS for CCK */
+	rtw_write16(Adapter, REG_SIFS_CTX, 0x100a);
+
+	/*  Set SIFS for OFDM */
+	rtw_write16(Adapter, REG_SIFS_TRX, 0x100a);
+
+	/*  TXOP */
+	rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B);
+	rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F);
+	rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324);
+	rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226);
+}
+
+static void _InitBeaconMaxError(struct adapter *Adapter, bool		InfraMode)
+{
+}
+
+static void _InitHWLed(struct adapter *Adapter)
+{
+	struct led_priv *pledpriv = &(Adapter->ledpriv);
+
+	if (pledpriv->LedStrategy != HW_LED)
+		return;
+
+/*  HW led control */
+/*  to do .... */
+/* must consider cases of antenna diversity/ commbo card/solo card/mini card */
+}
+
+static void _InitRDGSetting(struct adapter *Adapter)
+{
+	rtw_write8(Adapter, REG_RD_CTRL, 0xFF);
+	rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200);
+	rtw_write8(Adapter, REG_RD_RESP_PKT_TH, 0x05);
+}
+
+static void _InitRxSetting(struct adapter *Adapter)
+{
+	rtw_write32(Adapter, REG_MACID, 0x87654321);
+	rtw_write32(Adapter, 0x0700, 0x87654321);
+}
+
+static void _InitRetryFunction(struct adapter *Adapter)
+{
+	u8 value8;
+
+	value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL);
+	value8 |= EN_AMPDU_RTY_NEW;
+	rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8);
+
+	/*  Set ACK timeout */
+	rtw_write8(Adapter, REG_ACKTO, 0x40);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	usb_AggSettingTxUpdate()
+ *
+ * Overview:	Seperate TX/RX parameters update independent for TP detection and
+ *			dynamic TX/RX aggreagtion parameters update.
+ *
+ * Input:			struct adapter *
+ *
+ * Output/Return:	NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	12/10/2010	MHC		Seperate to smaller function.
+ *
+ *---------------------------------------------------------------------------*/
+static void usb_AggSettingTxUpdate(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+	u32 value32;
+
+	if (Adapter->registrypriv.wifi_spec)
+		haldata->UsbTxAggMode = false;
+
+	if (haldata->UsbTxAggMode) {
+		value32 = rtw_read32(Adapter, REG_TDECTRL);
+		value32 = value32 & ~(BLK_DESC_NUM_MASK << BLK_DESC_NUM_SHIFT);
+		value32 |= ((haldata->UsbTxAggDescNum & BLK_DESC_NUM_MASK) << BLK_DESC_NUM_SHIFT);
+
+		rtw_write32(Adapter, REG_TDECTRL, value32);
+	}
+}	/*  usb_AggSettingTxUpdate */
+
+/*-----------------------------------------------------------------------------
+ * Function:	usb_AggSettingRxUpdate()
+ *
+ * Overview:	Seperate TX/RX parameters update independent for TP detection and
+ *			dynamic TX/RX aggreagtion parameters update.
+ *
+ * Input:			struct adapter *
+ *
+ * Output/Return:	NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	12/10/2010	MHC		Seperate to smaller function.
+ *
+ *---------------------------------------------------------------------------*/
+static void
+usb_AggSettingRxUpdate(
+		struct adapter *Adapter
+	)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+	u8 valueDMA;
+	u8 valueUSB;
+
+	valueDMA = rtw_read8(Adapter, REG_TRXDMA_CTRL);
+	valueUSB = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION);
+
+	switch (haldata->UsbRxAggMode) {
+	case USB_RX_AGG_DMA:
+		valueDMA |= RXDMA_AGG_EN;
+		valueUSB &= ~USB_AGG_EN;
+		break;
+	case USB_RX_AGG_USB:
+		valueDMA &= ~RXDMA_AGG_EN;
+		valueUSB |= USB_AGG_EN;
+		break;
+	case USB_RX_AGG_MIX:
+		valueDMA |= RXDMA_AGG_EN;
+		valueUSB |= USB_AGG_EN;
+		break;
+	case USB_RX_AGG_DISABLE:
+	default:
+		valueDMA &= ~RXDMA_AGG_EN;
+		valueUSB &= ~USB_AGG_EN;
+		break;
+	}
+
+	rtw_write8(Adapter, REG_TRXDMA_CTRL, valueDMA);
+	rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, valueUSB);
+
+	switch (haldata->UsbRxAggMode) {
+	case USB_RX_AGG_DMA:
+		rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount);
+		rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, haldata->UsbRxAggPageTimeout);
+		break;
+	case USB_RX_AGG_USB:
+		rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount);
+		rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout);
+		break;
+	case USB_RX_AGG_MIX:
+		rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount);
+		rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH+1, (haldata->UsbRxAggPageTimeout & 0x1F));/* 0x280[12:8] */
+		rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount);
+		rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout);
+		break;
+	case USB_RX_AGG_DISABLE:
+	default:
+		/*  TODO: */
+		break;
+	}
+
+	switch (PBP_128) {
+	case PBP_128:
+		haldata->HwRxPageSize = 128;
+		break;
+	case PBP_64:
+		haldata->HwRxPageSize = 64;
+		break;
+	case PBP_256:
+		haldata->HwRxPageSize = 256;
+		break;
+	case PBP_512:
+		haldata->HwRxPageSize = 512;
+		break;
+	case PBP_1024:
+		haldata->HwRxPageSize = 1024;
+		break;
+	default:
+		break;
+	}
+}	/*  usb_AggSettingRxUpdate */
+
+static void InitUsbAggregationSetting(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	/*  Tx aggregation setting */
+	usb_AggSettingTxUpdate(Adapter);
+
+	/*  Rx aggregation setting */
+	usb_AggSettingRxUpdate(Adapter);
+
+	/*  201/12/10 MH Add for USB agg mode dynamic switch. */
+	haldata->UsbRxHighSpeedMode = false;
+}
+
+static void _InitOperationMode(struct adapter *Adapter)
+{
+}
+
+static void _InitBeaconParameters(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	rtw_write16(Adapter, REG_BCN_CTRL, 0x1010);
+
+	/*  TODO: Remove these magic number */
+	rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0x6404);/*  ms */
+	rtw_write8(Adapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/*  5ms */
+	rtw_write8(Adapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); /*  2ms */
+
+	/*  Suggested by designer timchen. Change beacon AIFS to the largest number */
+	/*  beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */
+	rtw_write16(Adapter, REG_BCNTCFG, 0x660F);
+
+	haldata->RegBcnCtrlVal = rtw_read8(Adapter, REG_BCN_CTRL);
+	haldata->RegTxPause = rtw_read8(Adapter, REG_TXPAUSE);
+	haldata->RegFwHwTxQCtrl = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL+2);
+	haldata->RegReg542 = rtw_read8(Adapter, REG_TBTT_PROHIBIT+2);
+	haldata->RegCR_1 = rtw_read8(Adapter, REG_CR+1);
+}
+
+static void _BeaconFunctionEnable(struct adapter *Adapter,
+				  bool Enable, bool Linked)
+{
+	rtw_write8(Adapter, REG_BCN_CTRL, (BIT4 | BIT3 | BIT1));
+
+	rtw_write8(Adapter, REG_RD_CTRL+1, 0x6F);
+}
+
+/*  Set CCK and OFDM Block "ON" */
+static void _BBTurnOnBlock(struct adapter *Adapter)
+{
+	PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1);
+	PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1);
+}
+
+enum {
+	Antenna_Lfet = 1,
+	Antenna_Right = 2,
+};
+
+static void _InitAntenna_Selection(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(Adapter);
+
+	if (haldata->AntDivCfg == 0)
+		return;
+	DBG_88E("==>  %s ....\n", __func__);
+
+	rtw_write32(Adapter, REG_LEDCFG0, rtw_read32(Adapter, REG_LEDCFG0)|BIT23);
+	PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, BIT13, 0x01);
+
+	if (PHY_QueryBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300) == Antenna_A)
+		haldata->CurAntenna = Antenna_A;
+	else
+		haldata->CurAntenna = Antenna_B;
+	DBG_88E("%s,Cur_ant:(%x)%s\n", __func__, haldata->CurAntenna, (haldata->CurAntenna == Antenna_A) ? "Antenna_A" : "Antenna_B");
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:	HwSuspendModeEnable92Cu()
+ *
+ * Overview:	HW suspend mode switch.
+ *
+ * Input:		NONE
+ *
+ * Output:	NONE
+ *
+ * Return:	NONE
+ *
+ * Revised History:
+ *	When		Who		Remark
+ *	08/23/2010	MHC		HW suspend mode switch test..
+ *---------------------------------------------------------------------------*/
+enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt)
+{
+	u8 val8;
+	enum rt_rf_power_state rfpowerstate = rf_off;
+
+	if (adapt->pwrctrlpriv.bHWPowerdown) {
+		val8 = rtw_read8(adapt, REG_HSISR);
+		DBG_88E("pwrdown, 0x5c(BIT7)=%02x\n", val8);
+		rfpowerstate = (val8 & BIT7) ? rf_off : rf_on;
+	} else { /*  rf on/off */
+		rtw_write8(adapt, REG_MAC_PINMUX_CFG, rtw_read8(adapt, REG_MAC_PINMUX_CFG)&~(BIT3));
+		val8 = rtw_read8(adapt, REG_GPIO_IO_SEL);
+		DBG_88E("GPIO_IN=%02x\n", val8);
+		rfpowerstate = (val8 & BIT3) ? rf_on : rf_off;
+	}
+	return rfpowerstate;
+}	/*  HalDetectPwrDownMode */
+
+static u32 rtl8188eu_hal_init(struct adapter *Adapter)
+{
+	u8 value8 = 0;
+	u16  value16;
+	u8 txpktbuf_bndy;
+	u32 status = _SUCCESS;
+	struct hal_data_8188e		*haldata = GET_HAL_DATA(Adapter);
+	struct pwrctrl_priv		*pwrctrlpriv = &Adapter->pwrctrlpriv;
+	struct registry_priv	*pregistrypriv = &Adapter->registrypriv;
+	u32 init_start_time = rtw_get_current_time();
+
+	#define HAL_INIT_PROFILE_TAG(stage) do {} while (0)
+
+_func_enter_;
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN);
+
+	if (Adapter->pwrctrlpriv.bkeepfwalive) {
+		_ps_open_RF(Adapter);
+
+		if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) {
+			PHY_IQCalibrate_8188E(Adapter, true);
+		} else {
+			PHY_IQCalibrate_8188E(Adapter, false);
+			haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
+		}
+
+		ODM_TXPowerTrackingCheck(&haldata->odmpriv);
+		PHY_LCCalibrate_8188E(Adapter);
+
+		goto exit;
+	}
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON);
+	status = rtl8188eu_InitPowerOn(Adapter);
+	if (status == _FAIL) {
+		RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init power on!\n"));
+		goto exit;
+	}
+
+	/*  Save target channel */
+	haldata->CurrentChannel = 6;/* default set to 6 */
+
+	if (pwrctrlpriv->reg_rfoff) {
+		pwrctrlpriv->rf_pwrstate = rf_off;
+	}
+
+	/*  2010/08/09 MH We need to check if we need to turnon or off RF after detecting */
+	/*  HW GPIO pin. Before PHY_RFConfig8192C. */
+	/*  2010/08/26 MH If Efuse does not support sective suspend then disable the function. */
+
+	if (!pregistrypriv->wifi_spec) {
+		txpktbuf_bndy = TX_PAGE_BOUNDARY_88E;
+	} else {
+		/*  for WMM */
+		txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E;
+	}
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01);
+	_InitQueueReservedPage(Adapter);
+	_InitQueuePriority(Adapter);
+	_InitPageBoundary(Adapter);
+	_InitTransferPageSize(Adapter);
+
+	_InitTxBufferBoundary(Adapter, 0);
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW);
+	if (Adapter->registrypriv.mp_mode == 1) {
+		_InitRxSetting(Adapter);
+		Adapter->bFWReady = false;
+		haldata->fw_ractrl = false;
+	} else {
+		status = rtl8188e_FirmwareDownload(Adapter);
+
+		if (status != _SUCCESS) {
+			DBG_88E("%s: Download Firmware failed!!\n", __func__);
+			Adapter->bFWReady = false;
+			haldata->fw_ractrl = false;
+			return status;
+		} else {
+			RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializeadapt8192CSdio(): Download Firmware Success!!\n"));
+			Adapter->bFWReady = true;
+			haldata->fw_ractrl = false;
+		}
+	}
+	rtl8188e_InitializeFirmwareVars(Adapter);
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC);
+#if (HAL_MAC_ENABLE == 1)
+	status = PHY_MACConfig8188E(Adapter);
+	if (status == _FAIL) {
+		DBG_88E(" ### Failed to init MAC ......\n ");
+		goto exit;
+	}
+#endif
+
+	/*  */
+	/* d. Initialize BB related configurations. */
+	/*  */
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB);
+#if (HAL_BB_ENABLE == 1)
+	status = PHY_BBConfig8188E(Adapter);
+	if (status == _FAIL) {
+		DBG_88E(" ### Failed to init BB ......\n ");
+		goto exit;
+	}
+#endif
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF);
+#if (HAL_RF_ENABLE == 1)
+	status = PHY_RFConfig8188E(Adapter);
+	if (status == _FAIL) {
+		DBG_88E(" ### Failed to init RF ......\n ");
+		goto exit;
+	}
+#endif
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH);
+	status = rtl8188e_iol_efuse_patch(Adapter);
+	if (status == _FAIL) {
+		DBG_88E("%s  rtl8188e_iol_efuse_patch failed\n", __func__);
+		goto exit;
+	}
+
+	_InitTxBufferBoundary(Adapter, txpktbuf_bndy);
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT);
+	status =  InitLLTTable(Adapter, txpktbuf_bndy);
+	if (status == _FAIL) {
+		RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("Failed to init LLT table\n"));
+		goto exit;
+	}
+
+	HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02);
+	/*  Get Rx PHY status in order to report RSSI and others. */
+	_InitDriverInfoSize(Adapter, DRVINFO_SZ);
+
+	_InitInterrupt(Adapter);
+	hal_init_macaddr(Adapter);/* set mac_address */
+	_InitNetworkType(Adapter);/* set msr */
+	_InitWMACSetting(Adapter);
+	_InitAdaptiveCtrl(Adapter);
+	_InitEDCA(Adapter);
+	_InitRetryFunction(Adapter);
+	InitUsbAggregationSetting(Adapter);
+	_InitOperationMode(Adapter);/* todo */
+	_InitBeaconParameters(Adapter);
+	_InitBeaconMaxError(Adapter, true);
+
+	/*  */
+	/*  Init CR MACTXEN, MACRXEN after setting RxFF boundary REG_TRXFF_BNDY to patch */
+	/*  Hw bug which Hw initials RxFF boundry size to a value which is larger than the real Rx buffer size in 88E. */
+	/*  */
+	/*  Enable MACTXEN/MACRXEN block */
+	value16 = rtw_read16(Adapter, REG_CR);
+	value16 |= (MACTXEN | MACRXEN);
+	rtw_write8(Adapter, REG_CR, value16);
+
+	if (haldata->bRDGEnable)
+		_InitRDGSetting(Adapter);
+
+	/* Enable TX Report */
+	/* Enable Tx Report Timer */
+	value8 = rtw_read8(Adapter, REG_TX_RPT_CTRL);
+	rtw_write8(Adapter,  REG_TX_RPT_CTRL, (value8|BIT1|BIT0));
+	/* Set MAX RPT MACID */
+	rtw_write8(Adapter,  REG_TX_RPT_CTRL+1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */
+	/* Tx RPT Timer. Unit: 32us */
+	rtw_write16(Adapter, REG_TX_RPT_TIME, 0xCdf0);
+
+	rtw_write8(Adapter, REG_EARLY_MODE_CONTROL, 0);
+
+	rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400);	/*  unit: 256us. 256ms */
+	rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400);	/*  unit: 256us. 256ms */
+
+	_InitHWLed(Adapter);
+
+	/* Keep RfRegChnlVal for later use. */
+	haldata->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)0, RF_CHNLBW, bRFRegOffsetMask);
+	haldata->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)1, RF_CHNLBW, bRFRegOffsetMask);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK);
+	_BBTurnOnBlock(Adapter);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY);
+	invalidate_cam_all(Adapter);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11);
+	/*  2010/12/17 MH We need to set TX power according to EFUSE content at first. */
+	PHY_SetTxPowerLevel8188E(Adapter, haldata->CurrentChannel);
+
+/*  Move by Neo for USB SS to below setp */
+/* _RfPowerSave(Adapter); */
+
+	_InitAntenna_Selection(Adapter);
+
+	/*  */
+	/*  Disable BAR, suggested by Scott */
+	/*  2010.04.09 add by hpfan */
+	/*  */
+	rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+	/*  HW SEQ CTRL */
+	/* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */
+	rtw_write8(Adapter, REG_HWSEQ_CTRL, 0xFF);
+
+	if (pregistrypriv->wifi_spec)
+		rtw_write16(Adapter, REG_FAST_EDCA_CTRL, 0);
+
+	/* Nav limit , suggest by scott */
+	rtw_write8(Adapter, 0x652, 0x0);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM);
+	rtl8188e_InitHalDm(Adapter);
+
+	if (Adapter->registrypriv.mp_mode == 1) {
+		Adapter->mppriv.channel = haldata->CurrentChannel;
+		MPT_InitializeAdapter(Adapter, Adapter->mppriv.channel);
+	} else {
+		/*  2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status */
+		/*  and then decide to enable RF or not.!!!??? For Selective suspend mode. We may not */
+		/*  call initstruct adapter. May cause some problem?? */
+		/*  Fix the bug that Hw/Sw radio off before S3/S4, the RF off action will not be executed */
+		/*  in MgntActSet_RF_State() after wake up, because the value of haldata->eRFPowerState */
+		/*  is the same as eRfOff, we should change it to eRfOn after we config RF parameters. */
+		/*  Added by tynli. 2010.03.30. */
+		pwrctrlpriv->rf_pwrstate = rf_on;
+
+		/*  enable Tx report. */
+		rtw_write8(Adapter,  REG_FWHW_TXQ_CTRL+1, 0x0F);
+
+		/*  Suggested by SD1 pisa. Added by tynli. 2011.10.21. */
+		rtw_write8(Adapter, REG_EARLY_MODE_CONTROL+3, 0x01);/* Pretx_en, for WEP/TKIP SEC */
+
+		/* tynli_test_tx_report. */
+		rtw_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0);
+
+		/* enable tx DMA to drop the redundate data of packet */
+		rtw_write16(Adapter, REG_TXDMA_OFFSET_CHK, (rtw_read16(Adapter, REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN));
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK);
+		/*  2010/08/26 MH Merge from 8192CE. */
+		if (pwrctrlpriv->rf_pwrstate == rf_on) {
+			if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) {
+				PHY_IQCalibrate_8188E(Adapter, true);
+			} else {
+				PHY_IQCalibrate_8188E(Adapter, false);
+				haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true;
+			}
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK);
+
+			ODM_TXPowerTrackingCheck(&haldata->odmpriv);
+
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK);
+			PHY_LCCalibrate_8188E(Adapter);
+		}
+	}
+
+/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */
+/*	_InitPABias(Adapter); */
+	rtw_write8(Adapter, REG_USB_HRPWM, 0);
+
+	/* ack for xmit mgmt frames. */
+	rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL)|BIT(12));
+
+exit:
+HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
+
+	DBG_88E("%s in %dms\n", __func__, rtw_get_passing_time_ms(init_start_time));
+
+_func_exit_;
+
+	return status;
+}
+
+void _ps_open_RF(struct adapter *adapt)
+{
+	/* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */
+	/* phy_SsPwrSwitch92CU(adapt, rf_on, 1); */
+}
+
+static void _ps_close_RF(struct adapter *adapt)
+{
+	/* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */
+	/* phy_SsPwrSwitch92CU(adapt, rf_off, 1); */
+}
+
+static void CardDisableRTL8188EU(struct adapter *Adapter)
+{
+	u8 val8;
+	struct hal_data_8188e	*haldata	= GET_HAL_DATA(Adapter);
+
+	RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("CardDisableRTL8188EU\n"));
+
+	/* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */
+	val8 = rtw_read8(Adapter, REG_TX_RPT_CTRL);
+	rtw_write8(Adapter, REG_TX_RPT_CTRL, val8&(~BIT1));
+
+	/*  stop rx */
+	rtw_write8(Adapter, REG_CR, 0x0);
+
+	/*  Run LPS WL RFOFF flow */
+	HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_LPS_ENTER_FLOW);
+
+	/*  2. 0x1F[7:0] = 0		turn off RF */
+
+	val8 = rtw_read8(Adapter, REG_MCUFWDL);
+	if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) { /* 8051 RAM code */
+		/*  Reset MCU 0x2[10]=0. */
+		val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN+1);
+		val8 &= ~BIT(2);	/*  0x2[10], FEN_CPUEN */
+		rtw_write8(Adapter, REG_SYS_FUNC_EN+1, val8);
+	}
+
+	/*  reset MCU ready status */
+	rtw_write8(Adapter, REG_MCUFWDL, 0);
+
+	/* YJ,add,111212 */
+	/* Disable 32k */
+	val8 = rtw_read8(Adapter, REG_32K_CTRL);
+	rtw_write8(Adapter, REG_32K_CTRL, val8&(~BIT0));
+
+	/*  Card disable power action flow */
+	HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+
+	/*  Reset MCU IO Wrapper */
+	val8 = rtw_read8(Adapter, REG_RSV_CTRL+1);
+	rtw_write8(Adapter, REG_RSV_CTRL+1, (val8&(~BIT3)));
+	val8 = rtw_read8(Adapter, REG_RSV_CTRL+1);
+	rtw_write8(Adapter, REG_RSV_CTRL+1, val8|BIT3);
+
+	/* YJ,test add, 111207. For Power Consumption. */
+	val8 = rtw_read8(Adapter, GPIO_IN);
+	rtw_write8(Adapter, GPIO_OUT, val8);
+	rtw_write8(Adapter, GPIO_IO_SEL, 0xFF);/* Reg0x46 */
+
+	val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL);
+	rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8<<4));
+	val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL+1);
+	rtw_write8(Adapter, REG_GPIO_IO_SEL+1, val8|0x0F);/* Reg0x43 */
+	rtw_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);/* set LNA ,TRSW,EX_PA Pin to output mode */
+	haldata->bMacPwrCtrlOn = false;
+	Adapter->bFWReady = false;
+}
+static void rtl8192cu_hw_power_down(struct adapter *adapt)
+{
+	/*  2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. */
+	/*  Then enable power down control bit of register 0x04 BIT4 and BIT15 as 1. */
+
+	/*  Enable register area 0x0-0xc. */
+	rtw_write8(adapt, REG_RSV_CTRL, 0x0);
+	rtw_write16(adapt, REG_APS_FSMCO, 0x8812);
+}
+
+static u32 rtl8188eu_hal_deinit(struct adapter *Adapter)
+{
+
+	DBG_88E("==> %s\n", __func__);
+
+	rtw_write32(Adapter, REG_HIMR_88E, IMR_DISABLED_88E);
+	rtw_write32(Adapter, REG_HIMRE_88E, IMR_DISABLED_88E);
+
+	DBG_88E("bkeepfwalive(%x)\n", Adapter->pwrctrlpriv.bkeepfwalive);
+	if (Adapter->pwrctrlpriv.bkeepfwalive) {
+		_ps_close_RF(Adapter);
+		if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown))
+			rtl8192cu_hw_power_down(Adapter);
+	} else {
+		if (Adapter->hw_init_completed) {
+			CardDisableRTL8188EU(Adapter);
+
+			if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown))
+				rtl8192cu_hw_power_down(Adapter);
+		}
+	}
+	return _SUCCESS;
+ }
+
+static unsigned int rtl8188eu_inirp_init(struct adapter *Adapter)
+{
+	u8 i;
+	struct recv_buf *precvbuf;
+	uint	status;
+	struct intf_hdl *pintfhdl = &Adapter->iopriv.intf;
+	struct recv_priv *precvpriv = &(Adapter->recvpriv);
+	u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+
+_func_enter_;
+
+	_read_port = pintfhdl->io_ops._read_port;
+
+	status = _SUCCESS;
+
+	RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+		 ("===> usb_inirp_init\n"));
+
+	precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR;
+
+	/* issue Rx irp to receive data */
+	precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+	for (i = 0; i < NR_RECVBUFF; i++) {
+		if (_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf) == false) {
+			RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("usb_rx_init: usb_read_port error\n"));
+			status = _FAIL;
+			goto exit;
+		}
+
+		precvbuf++;
+		precvpriv->free_recv_buf_queue_cnt--;
+	}
+
+exit:
+
+	RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("<=== usb_inirp_init\n"));
+
+_func_exit_;
+
+	return status;
+}
+
+static unsigned int rtl8188eu_inirp_deinit(struct adapter *Adapter)
+{
+	RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("\n ===> usb_rx_deinit\n"));
+
+	rtw_read_port_cancel(Adapter);
+
+	RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("\n <=== usb_rx_deinit\n"));
+
+	return _SUCCESS;
+}
+
+/*  */
+/*  */
+/*	EEPROM/EFUSE Content Parsing */
+/*  */
+/*  */
+static void _ReadLEDSetting(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail)
+{
+	struct led_priv *pledpriv = &(Adapter->ledpriv);
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	pledpriv->bRegUseLed = true;
+	pledpriv->LedStrategy = SW_LED_MODE1;
+	haldata->bLedOpenDrain = true;/*  Support Open-drain arrangement for controlling the LED. */
+}
+
+static void Hal_EfuseParsePIDVID_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+
+	if (!AutoLoadFail) {
+		/*  VID, PID */
+		haldata->EEPROMVID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_VID_88EU]);
+		haldata->EEPROMPID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_PID_88EU]);
+
+		/*  Customer ID, 0x00 and 0xff are reserved for Realtek. */
+		haldata->EEPROMCustomerID = *(u8 *)&hwinfo[EEPROM_CUSTOMERID_88E];
+		haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID;
+	} else {
+		haldata->EEPROMVID			= EEPROM_Default_VID;
+		haldata->EEPROMPID			= EEPROM_Default_PID;
+
+		/*  Customer ID, 0x00 and 0xff are reserved for Realtek. */
+		haldata->EEPROMCustomerID		= EEPROM_Default_CustomerID;
+		haldata->EEPROMSubCustomerID	= EEPROM_Default_SubCustomerID;
+	}
+
+	DBG_88E("VID = 0x%04X, PID = 0x%04X\n", haldata->EEPROMVID, haldata->EEPROMPID);
+	DBG_88E("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", haldata->EEPROMCustomerID, haldata->EEPROMSubCustomerID);
+}
+
+static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail)
+{
+	u16 i;
+	u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02};
+	struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt);
+
+	if (AutoLoadFail) {
+		for (i = 0; i < 6; i++)
+			eeprom->mac_addr[i] = sMacAddr[i];
+	} else {
+		/* Read Permanent MAC address */
+		memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN);
+	}
+	RT_TRACE(_module_hci_hal_init_c_, _drv_notice_,
+		 ("Hal_EfuseParseMACAddr_8188EU: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n",
+		 eeprom->mac_addr[0], eeprom->mac_addr[1],
+		 eeprom->mac_addr[2], eeprom->mac_addr[3],
+		 eeprom->mac_addr[4], eeprom->mac_addr[5]));
+}
+
+static void Hal_CustomizeByCustomerID_8188EU(struct adapter *adapt)
+{
+}
+
+static void
+readAdapterInfo_8188EU(
+		struct adapter *adapt
+	)
+{
+	struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt);
+
+	/* parse the eeprom/efuse content */
+	Hal_EfuseParseIDCode88E(adapt, eeprom->efuse_eeprom_data);
+	Hal_EfuseParsePIDVID_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_EfuseParseMACAddr_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+
+	Hal_ReadPowerSavingMode88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_ReadTxPowerInfo88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_EfuseParseEEPROMVer88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	rtl8188e_EfuseParseChnlPlan(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_EfuseParseXtal_8188E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_EfuseParseCustomerID88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_ReadAntennaDiversity88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_EfuseParseBoardType88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+	Hal_ReadThermalMeter_88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+
+	/*  */
+	/*  The following part initialize some vars by PG info. */
+	/*  */
+	Hal_InitChannelPlan(adapt);
+	Hal_CustomizeByCustomerID_8188EU(adapt);
+
+	_ReadLEDSetting(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag);
+}
+
+static void _ReadPROMContent(
+	struct adapter *Adapter
+	)
+{
+	struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(Adapter);
+	u8 eeValue;
+
+	/* check system boot selection */
+	eeValue = rtw_read8(Adapter, REG_9346CR);
+	eeprom->EepromOrEfuse		= (eeValue & BOOT_FROM_EEPROM) ? true : false;
+	eeprom->bautoload_fail_flag	= (eeValue & EEPROM_EN) ? false : true;
+
+	DBG_88E("Boot from %s, Autoload %s !\n", (eeprom->EepromOrEfuse ? "EEPROM" : "EFUSE"),
+		(eeprom->bautoload_fail_flag ? "Fail" : "OK"));
+
+	Hal_InitPGData88E(Adapter);
+	readAdapterInfo_8188EU(Adapter);
+}
+
+static void _ReadRFType(struct adapter *Adapter)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+
+	haldata->rf_chip = RF_6052;
+}
+
+static int _ReadAdapterInfo8188EU(struct adapter *Adapter)
+{
+	u32 start = rtw_get_current_time();
+
+	MSG_88E("====> %s\n", __func__);
+
+	_ReadRFType(Adapter);/* rf_chip -> _InitRFType() */
+	_ReadPROMContent(Adapter);
+
+	MSG_88E("<==== %s in %d ms\n", __func__, rtw_get_passing_time_ms(start));
+
+	return _SUCCESS;
+}
+
+static void ReadAdapterInfo8188EU(struct adapter *Adapter)
+{
+	/*  Read EEPROM size before call any EEPROM function */
+	Adapter->EepromAddressSize = GetEEPROMSize8188E(Adapter);
+
+	_ReadAdapterInfo8188EU(Adapter);
+}
+
+#define GPIO_DEBUG_PORT_NUM 0
+static void rtl8192cu_trigger_gpio_0(struct adapter *adapt)
+{
+}
+
+static void ResumeTxBeacon(struct adapter *adapt)
+{
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+	/*  2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */
+	/*  which should be read from register to a global variable. */
+
+	rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) | BIT6);
+	haldata->RegFwHwTxQCtrl |= BIT6;
+	rtw_write8(adapt, REG_TBTT_PROHIBIT+1, 0xff);
+	haldata->RegReg542 |= BIT0;
+	rtw_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542);
+}
+
+static void StopTxBeacon(struct adapter *adapt)
+{
+	struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
+
+	/*  2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */
+	/*  which should be read from register to a global variable. */
+
+	rtw_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl) & (~BIT6));
+	haldata->RegFwHwTxQCtrl &= (~BIT6);
+	rtw_write8(adapt, REG_TBTT_PROHIBIT+1, 0x64);
+	haldata->RegReg542 &= ~(BIT0);
+	rtw_write8(adapt, REG_TBTT_PROHIBIT+2, haldata->RegReg542);
+
+	 /* todo: CheckFwRsvdPageContent(Adapter);  2010.06.23. Added by tynli. */
+}
+
+static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val)
+{
+	u8 val8;
+	u8 mode = *((u8 *)val);
+
+	/*  disable Port0 TSF update */
+	rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4));
+
+	/*  set net_type */
+	val8 = rtw_read8(Adapter, MSR)&0x0c;
+	val8 |= mode;
+	rtw_write8(Adapter, MSR, val8);
+
+	DBG_88E("%s()-%d mode = %d\n", __func__, __LINE__, mode);
+
+	if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) {
+		StopTxBeacon(Adapter);
+
+		rtw_write8(Adapter, REG_BCN_CTRL, 0x19);/* disable atim wnd */
+	} else if ((mode == _HW_STATE_ADHOC_)) {
+		ResumeTxBeacon(Adapter);
+		rtw_write8(Adapter, REG_BCN_CTRL, 0x1a);
+	} else if (mode == _HW_STATE_AP_) {
+		ResumeTxBeacon(Adapter);
+
+		rtw_write8(Adapter, REG_BCN_CTRL, 0x12);
+
+		/* Set RCR */
+		rtw_write32(Adapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0,reject ICV_ERR packet */
+		/* enable to rx data frame */
+		rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+		/* enable to rx ps-poll */
+		rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400);
+
+		/* Beacon Control related register for first time */
+		rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /*  2ms */
+
+		rtw_write8(Adapter, REG_ATIMWND, 0x0a); /*  10ms */
+		rtw_write16(Adapter, REG_BCNTCFG, 0x00);
+		rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04);
+		rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/*  +32767 (~32ms) */
+
+		/* reset TSF */
+		rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0));
+
+		/* BIT3 - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */
+		rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM) | BIT(3) | BIT(4));
+
+		/* enable BCN0 Function for if1 */
+		/* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */
+		rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP|EN_BCN_FUNCTION | BIT(1)));
+
+		/* dis BCN1 ATIM  WND if if2 is station */
+		rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1) | BIT(0));
+	}
+}
+
+static void hw_var_set_macaddr(struct adapter *Adapter, u8 variable, u8 *val)
+{
+	u8 idx = 0;
+	u32 reg_macid;
+
+	reg_macid = REG_MACID;
+
+	for (idx = 0; idx < 6; idx++)
+		rtw_write8(Adapter, (reg_macid+idx), val[idx]);
+}
+
+static void hw_var_set_bssid(struct adapter *Adapter, u8 variable, u8 *val)
+{
+	u8 idx = 0;
+	u32 reg_bssid;
+
+	reg_bssid = REG_BSSID;
+
+	for (idx = 0; idx < 6; idx++)
+		rtw_write8(Adapter, (reg_bssid+idx), val[idx]);
+}
+
+static void hw_var_set_bcn_func(struct adapter *Adapter, u8 variable, u8 *val)
+{
+	u32 bcn_ctrl_reg;
+
+	bcn_ctrl_reg = REG_BCN_CTRL;
+
+	if (*((u8 *)val))
+		rtw_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT));
+	else
+		rtw_write8(Adapter, bcn_ctrl_reg, rtw_read8(Adapter, bcn_ctrl_reg)&(~(EN_BCN_FUNCTION | EN_TXBCN_RPT)));
+}
+
+static void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+	struct dm_priv	*pdmpriv = &haldata->dmpriv;
+	struct odm_dm_struct *podmpriv = &haldata->odmpriv;
+_func_enter_;
+
+	switch (variable) {
+	case HW_VAR_MEDIA_STATUS:
+		{
+			u8 val8;
+
+			val8 = rtw_read8(Adapter, MSR)&0x0c;
+			val8 |= *((u8 *)val);
+			rtw_write8(Adapter, MSR, val8);
+		}
+		break;
+	case HW_VAR_MEDIA_STATUS1:
+		{
+			u8 val8;
+
+			val8 = rtw_read8(Adapter, MSR) & 0x03;
+			val8 |= *((u8 *)val) << 2;
+			rtw_write8(Adapter, MSR, val8);
+		}
+		break;
+	case HW_VAR_SET_OPMODE:
+		hw_var_set_opmode(Adapter, variable, val);
+		break;
+	case HW_VAR_MAC_ADDR:
+		hw_var_set_macaddr(Adapter, variable, val);
+		break;
+	case HW_VAR_BSSID:
+		hw_var_set_bssid(Adapter, variable, val);
+		break;
+	case HW_VAR_BASIC_RATE:
+		{
+			u16 BrateCfg = 0;
+			u8 RateIndex = 0;
+
+			/*  2007.01.16, by Emily */
+			/*  Select RRSR (in Legacy-OFDM and CCK) */
+			/*  For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */
+			/*  We do not use other rates. */
+			HalSetBrateCfg(Adapter, val, &BrateCfg);
+			DBG_88E("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg);
+
+			/* 2011.03.30 add by Luke Lee */
+			/* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */
+			/* because CCK 2M has poor TXEVM */
+			/* CCK 5.5M & 11M ACK should be enabled for better performance */
+
+			BrateCfg = (BrateCfg | 0xd) & 0x15d;
+			haldata->BasicRateSet = BrateCfg;
+
+			BrateCfg |= 0x01; /*  default enable 1M ACK rate */
+			/*  Set RRSR rate table. */
+			rtw_write8(Adapter, REG_RRSR, BrateCfg & 0xff);
+			rtw_write8(Adapter, REG_RRSR+1, (BrateCfg >> 8) & 0xff);
+			rtw_write8(Adapter, REG_RRSR+2, rtw_read8(Adapter, REG_RRSR+2)&0xf0);
+
+			/*  Set RTS initial rate */
+			while (BrateCfg > 0x1) {
+				BrateCfg = (BrateCfg >> 1);
+				RateIndex++;
+			}
+			/*  Ziv - Check */
+			rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex);
+		}
+		break;
+	case HW_VAR_TXPAUSE:
+		rtw_write8(Adapter, REG_TXPAUSE, *((u8 *)val));
+		break;
+	case HW_VAR_BCN_FUNC:
+		hw_var_set_bcn_func(Adapter, variable, val);
+		break;
+	case HW_VAR_CORRECT_TSF:
+		{
+			u64	tsf;
+			struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+			struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+			tsf = pmlmeext->TSFValue - rtw_modular64(pmlmeext->TSFValue, (pmlmeinfo->bcn_interval*1024)) - 1024; /* us */
+
+			if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+				StopTxBeacon(Adapter);
+
+			/* disable related TSF function */
+			rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(3)));
+
+			rtw_write32(Adapter, REG_TSFTR, tsf);
+			rtw_write32(Adapter, REG_TSFTR+4, tsf>>32);
+
+			/* enable related TSF function */
+			rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(3));
+
+			if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+				ResumeTxBeacon(Adapter);
+		}
+		break;
+	case HW_VAR_CHECK_BSSID:
+		if (*((u8 *)val)) {
+			rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN);
+		} else {
+			u32 val32;
+
+			val32 = rtw_read32(Adapter, REG_RCR);
+
+			val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+
+			rtw_write32(Adapter, REG_RCR, val32);
+		}
+		break;
+	case HW_VAR_MLME_DISCONNECT:
+		/* Set RCR to not to receive data frame when NO LINK state */
+		/* reject all data frames */
+		rtw_write16(Adapter, REG_RXFLTMAP2, 0x00);
+
+		/* reset TSF */
+		rtw_write8(Adapter, REG_DUAL_TSF_RST, (BIT(0)|BIT(1)));
+
+		/* disable update TSF */
+		rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4));
+		break;
+	case HW_VAR_MLME_SITESURVEY:
+		if (*((u8 *)val)) { /* under sitesurvey */
+			/* config RCR to receive different BSSID & not to receive data frame */
+			u32 v = rtw_read32(Adapter, REG_RCR);
+			v &= ~(RCR_CBSSID_BCN);
+			rtw_write32(Adapter, REG_RCR, v);
+			/* reject all data frame */
+			rtw_write16(Adapter, REG_RXFLTMAP2, 0x00);
+
+			/* disable update TSF */
+			rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)|BIT(4));
+		} else { /* sitesurvey done */
+			struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+			struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+			if ((is_client_associated_to_ap(Adapter)) ||
+			    ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)) {
+				/* enable to rx data frame */
+				rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+
+				/* enable update TSF */
+				rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+			} else if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+				rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+				/* enable update TSF */
+				rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+			}
+			if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+				rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN);
+			} else {
+				if (Adapter->in_cta_test) {
+					u32 v = rtw_read32(Adapter, REG_RCR);
+					v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/*  RCR_ADF */
+					rtw_write32(Adapter, REG_RCR, v);
+				} else {
+					rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_BCN);
+				}
+			}
+		}
+		break;
+	case HW_VAR_MLME_JOIN:
+		{
+			u8 RetryLimit = 0x30;
+			u8 type = *((u8 *)val);
+			struct mlme_priv	*pmlmepriv = &Adapter->mlmepriv;
+
+			if (type == 0) { /*  prepare to join */
+				/* enable to rx data frame.Accept all data frame */
+				rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF);
+
+				if (Adapter->in_cta_test) {
+					u32 v = rtw_read32(Adapter, REG_RCR);
+					v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/*  RCR_ADF */
+					rtw_write32(Adapter, REG_RCR, v);
+				} else {
+					rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR)|RCR_CBSSID_DATA|RCR_CBSSID_BCN);
+				}
+
+				if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+					RetryLimit = (haldata->CustomerID == RT_CID_CCX) ? 7 : 48;
+				else /*  Ad-hoc Mode */
+					RetryLimit = 0x7;
+			} else if (type == 1) {
+				/* joinbss_event call back when join res < 0 */
+				rtw_write16(Adapter, REG_RXFLTMAP2, 0x00);
+			} else if (type == 2) {
+				/* sta add event call back */
+				/* enable update TSF */
+				rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL)&(~BIT(4)));
+
+				if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE))
+					RetryLimit = 0x7;
+			}
+			rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT);
+		}
+		break;
+	case HW_VAR_BEACON_INTERVAL:
+		rtw_write16(Adapter, REG_BCN_INTERVAL, *((u16 *)val));
+		break;
+	case HW_VAR_SLOT_TIME:
+		{
+			u8 u1bAIFS, aSifsTime;
+			struct mlme_ext_priv	*pmlmeext = &Adapter->mlmeextpriv;
+			struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+
+			rtw_write8(Adapter, REG_SLOT, val[0]);
+
+			if (pmlmeinfo->WMM_enable == 0) {
+				if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+					aSifsTime = 10;
+				else
+					aSifsTime = 16;
+
+				u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
+
+				/*  <Roger_EXP> Temporary removed, 2008.06.20. */
+				rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS);
+				rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS);
+				rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS);
+				rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS);
+			}
+		}
+		break;
+	case HW_VAR_RESP_SIFS:
+		/* RESP_SIFS for CCK */
+		rtw_write8(Adapter, REG_R2T_SIFS, val[0]); /*  SIFS_T2T_CCK (0x08) */
+		rtw_write8(Adapter, REG_R2T_SIFS+1, val[1]); /* SIFS_R2T_CCK(0x08) */
+		/* RESP_SIFS for OFDM */
+		rtw_write8(Adapter, REG_T2T_SIFS, val[2]); /* SIFS_T2T_OFDM (0x0a) */
+		rtw_write8(Adapter, REG_T2T_SIFS+1, val[3]); /* SIFS_R2T_OFDM(0x0a) */
+		break;
+	case HW_VAR_ACK_PREAMBLE:
+		{
+			u8 regTmp;
+			u8 bShortPreamble = *((bool *)val);
+			/*  Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */
+			regTmp = (haldata->nCur40MhzPrimeSC)<<5;
+			if (bShortPreamble)
+				regTmp |= 0x80;
+
+			rtw_write8(Adapter, REG_RRSR+2, regTmp);
+		}
+		break;
+	case HW_VAR_SEC_CFG:
+		rtw_write8(Adapter, REG_SECCFG, *((u8 *)val));
+		break;
+	case HW_VAR_DM_FLAG:
+		podmpriv->SupportAbility = *((u8 *)val);
+		break;
+	case HW_VAR_DM_FUNC_OP:
+		if (val[0])
+			podmpriv->BK_SupportAbility = podmpriv->SupportAbility;
+		else
+			podmpriv->SupportAbility = podmpriv->BK_SupportAbility;
+		break;
+	case HW_VAR_DM_FUNC_SET:
+		if (*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE) {
+			pdmpriv->DMFlag = pdmpriv->InitDMFlag;
+			podmpriv->SupportAbility =	pdmpriv->InitODMFlag;
+		} else {
+			podmpriv->SupportAbility |= *((u32 *)val);
+		}
+		break;
+	case HW_VAR_DM_FUNC_CLR:
+		podmpriv->SupportAbility &= *((u32 *)val);
+		break;
+	case HW_VAR_CAM_EMPTY_ENTRY:
+		{
+			u8 ucIndex = *((u8 *)val);
+			u8 i;
+			u32 ulCommand = 0;
+			u32 ulContent = 0;
+			u32 ulEncAlgo = CAM_AES;
+
+			for (i = 0; i < CAM_CONTENT_COUNT; i++) {
+				/*  filled id in CAM config 2 byte */
+				if (i == 0)
+					ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo)<<2);
+				else
+					ulContent = 0;
+				/*  polling bit, and No Write enable, and address */
+				ulCommand = CAM_CONTENT_COUNT*ucIndex+i;
+				ulCommand = ulCommand | CAM_POLLINIG|CAM_WRITE;
+				/*  write content 0 is equall to mark invalid */
+				rtw_write32(Adapter, WCAMI, ulContent);  /* delay_ms(40); */
+				rtw_write32(Adapter, RWCAM, ulCommand);  /* delay_ms(40); */
+			}
+		}
+		break;
+	case HW_VAR_CAM_INVALID_ALL:
+		rtw_write32(Adapter, RWCAM, BIT(31)|BIT(30));
+		break;
+	case HW_VAR_CAM_WRITE:
+		{
+			u32 cmd;
+			u32 *cam_val = (u32 *)val;
+			rtw_write32(Adapter, WCAMI, cam_val[0]);
+
+			cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1];
+			rtw_write32(Adapter, RWCAM, cmd);
+		}
+		break;
+	case HW_VAR_AC_PARAM_VO:
+		rtw_write32(Adapter, REG_EDCA_VO_PARAM, ((u32 *)(val))[0]);
+		break;
+	case HW_VAR_AC_PARAM_VI:
+		rtw_write32(Adapter, REG_EDCA_VI_PARAM, ((u32 *)(val))[0]);
+		break;
+	case HW_VAR_AC_PARAM_BE:
+		haldata->AcParam_BE = ((u32 *)(val))[0];
+		rtw_write32(Adapter, REG_EDCA_BE_PARAM, ((u32 *)(val))[0]);
+		break;
+	case HW_VAR_AC_PARAM_BK:
+		rtw_write32(Adapter, REG_EDCA_BK_PARAM, ((u32 *)(val))[0]);
+		break;
+	case HW_VAR_ACM_CTRL:
+		{
+			u8 acm_ctrl = *((u8 *)val);
+			u8 AcmCtrl = rtw_read8(Adapter, REG_ACMHWCTRL);
+
+			if (acm_ctrl > 1)
+				AcmCtrl = AcmCtrl | 0x1;
+
+			if (acm_ctrl & BIT(3))
+				AcmCtrl |= AcmHw_VoqEn;
+			else
+				AcmCtrl &= (~AcmHw_VoqEn);
+
+			if (acm_ctrl & BIT(2))
+				AcmCtrl |= AcmHw_ViqEn;
+			else
+				AcmCtrl &= (~AcmHw_ViqEn);
+
+			if (acm_ctrl & BIT(1))
+				AcmCtrl |= AcmHw_BeqEn;
+			else
+				AcmCtrl &= (~AcmHw_BeqEn);
+
+			DBG_88E("[HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl);
+			rtw_write8(Adapter, REG_ACMHWCTRL, AcmCtrl);
+		}
+		break;
+	case HW_VAR_AMPDU_MIN_SPACE:
+		{
+			u8 MinSpacingToSet;
+			u8 SecMinSpace;
+
+			MinSpacingToSet = *((u8 *)val);
+			if (MinSpacingToSet <= 7) {
+				switch (Adapter->securitypriv.dot11PrivacyAlgrthm) {
+				case _NO_PRIVACY_:
+				case _AES_:
+					SecMinSpace = 0;
+					break;
+				case _WEP40_:
+				case _WEP104_:
+				case _TKIP_:
+				case _TKIP_WTMIC_:
+					SecMinSpace = 6;
+					break;
+				default:
+					SecMinSpace = 7;
+					break;
+				}
+				if (MinSpacingToSet < SecMinSpace)
+					MinSpacingToSet = SecMinSpace;
+				rtw_write8(Adapter, REG_AMPDU_MIN_SPACE, (rtw_read8(Adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | MinSpacingToSet);
+			}
+		}
+		break;
+	case HW_VAR_AMPDU_FACTOR:
+		{
+			u8 RegToSet_Normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+			u8 FactorToSet;
+			u8 *pRegToSet;
+			u8 index = 0;
+
+			pRegToSet = RegToSet_Normal; /*  0xb972a841; */
+			FactorToSet = *((u8 *)val);
+			if (FactorToSet <= 3) {
+				FactorToSet = (1<<(FactorToSet + 2));
+				if (FactorToSet > 0xf)
+					FactorToSet = 0xf;
+
+				for (index = 0; index < 4; index++) {
+					if ((pRegToSet[index] & 0xf0) > (FactorToSet<<4))
+						pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet<<4);
+
+					if ((pRegToSet[index] & 0x0f) > FactorToSet)
+						pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet);
+
+					rtw_write8(Adapter, (REG_AGGLEN_LMT+index), pRegToSet[index]);
+				}
+			}
+		}
+		break;
+	case HW_VAR_RXDMA_AGG_PG_TH:
+		{
+			u8 threshold = *((u8 *)val);
+			if (threshold == 0)
+				threshold = haldata->UsbRxAggPageCount;
+			rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, threshold);
+		}
+		break;
+	case HW_VAR_SET_RPWM:
+		break;
+	case HW_VAR_H2C_FW_PWRMODE:
+		{
+			u8 psmode = (*(u8 *)val);
+
+			/*  Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */
+			/*  saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */
+			if ((psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(haldata->VersionID)))
+				ODM_RF_Saving(podmpriv, true);
+			rtl8188e_set_FwPwrMode_cmd(Adapter, psmode);
+		}
+		break;
+	case HW_VAR_H2C_FW_JOINBSSRPT:
+		{
+			u8 mstatus = (*(u8 *)val);
+			rtl8188e_set_FwJoinBssReport_cmd(Adapter, mstatus);
+		}
+		break;
+#ifdef CONFIG_88EU_P2P
+	case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+		{
+			u8 p2p_ps_state = (*(u8 *)val);
+			rtl8188e_set_p2p_ps_offload_cmd(Adapter, p2p_ps_state);
+		}
+		break;
+#endif
+	case HW_VAR_INITIAL_GAIN:
+		{
+			struct rtw_dig *pDigTable = &podmpriv->DM_DigTable;
+			u32 rx_gain = ((u32 *)(val))[0];
+
+			if (rx_gain == 0xff) {/* restore rx gain */
+				ODM_Write_DIG(podmpriv, pDigTable->BackupIGValue);
+			} else {
+				pDigTable->BackupIGValue = pDigTable->CurIGValue;
+				ODM_Write_DIG(podmpriv, rx_gain);
+			}
+		}
+		break;
+	case HW_VAR_TRIGGER_GPIO_0:
+		rtl8192cu_trigger_gpio_0(Adapter);
+		break;
+	case HW_VAR_RPT_TIMER_SETTING:
+		{
+			u16 min_rpt_time = (*(u16 *)val);
+			ODM_RA_Set_TxRPT_Time(podmpriv, min_rpt_time);
+		}
+		break;
+	case HW_VAR_ANTENNA_DIVERSITY_SELECT:
+		{
+			u8 Optimum_antenna = (*(u8 *)val);
+			u8 Ant;
+			/* switch antenna to Optimum_antenna */
+			if (haldata->CurAntenna !=  Optimum_antenna) {
+				Ant = (Optimum_antenna == 2) ? MAIN_ANT : AUX_ANT;
+				ODM_UpdateRxIdleAnt_88E(&haldata->odmpriv, Ant);
+
+				haldata->CurAntenna = Optimum_antenna;
+			}
+		}
+		break;
+	case HW_VAR_EFUSE_BYTES: /*  To set EFUE total used bytes, added by Roger, 2008.12.22. */
+		haldata->EfuseUsedBytes = *((u16 *)val);
+		break;
+	case HW_VAR_FIFO_CLEARN_UP:
+		{
+			struct pwrctrl_priv *pwrpriv = &Adapter->pwrctrlpriv;
+			u8 trycnt = 100;
+
+			/* pause tx */
+			rtw_write8(Adapter, REG_TXPAUSE, 0xff);
+
+			/* keep sn */
+			Adapter->xmitpriv.nqos_ssn = rtw_read16(Adapter, REG_NQOS_SEQ);
+
+			if (!pwrpriv->bkeepfwalive) {
+				/* RX DMA stop */
+				rtw_write32(Adapter, REG_RXPKT_NUM, (rtw_read32(Adapter, REG_RXPKT_NUM)|RW_RELEASE_EN));
+				do {
+					if (!(rtw_read32(Adapter, REG_RXPKT_NUM)&RXDMA_IDLE))
+						break;
+				} while (trycnt--);
+				if (trycnt == 0)
+					DBG_88E("Stop RX DMA failed......\n");
+
+				/* RQPN Load 0 */
+				rtw_write16(Adapter, REG_RQPN_NPQ, 0x0);
+				rtw_write32(Adapter, REG_RQPN, 0x80000000);
+				rtw_mdelay_os(10);
+			}
+		}
+		break;
+	case HW_VAR_CHECK_TXBUF:
+		break;
+	case HW_VAR_APFM_ON_MAC:
+		haldata->bMacPwrCtrlOn = *val;
+		DBG_88E("%s: bMacPwrCtrlOn=%d\n", __func__, haldata->bMacPwrCtrlOn);
+		break;
+	case HW_VAR_TX_RPT_MAX_MACID:
+		{
+			u8 maxMacid = *val;
+			DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid+1);
+			rtw_write8(Adapter, REG_TX_RPT_CTRL+1, maxMacid+1);
+		}
+		break;
+	case HW_VAR_H2C_MEDIA_STATUS_RPT:
+		rtl8188e_set_FwMediaStatus_cmd(Adapter , (*(__le16 *)val));
+		break;
+	case HW_VAR_BCN_VALID:
+		/* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2, write 1 to clear, Clear by sw */
+		rtw_write8(Adapter, REG_TDECTRL+2, rtw_read8(Adapter, REG_TDECTRL+2) | BIT0);
+		break;
+	default:
+		break;
+	}
+_func_exit_;
+}
+
+static void GetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+	struct odm_dm_struct *podmpriv = &haldata->odmpriv;
+_func_enter_;
+
+	switch (variable) {
+	case HW_VAR_BASIC_RATE:
+		*((u16 *)(val)) = haldata->BasicRateSet;
+	case HW_VAR_TXPAUSE:
+		val[0] = rtw_read8(Adapter, REG_TXPAUSE);
+		break;
+	case HW_VAR_BCN_VALID:
+		/* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */
+		val[0] = (BIT0 & rtw_read8(Adapter, REG_TDECTRL+2)) ? true : false;
+		break;
+	case HW_VAR_DM_FLAG:
+		val[0] = podmpriv->SupportAbility;
+		break;
+	case HW_VAR_RF_TYPE:
+		val[0] = haldata->rf_type;
+		break;
+	case HW_VAR_FWLPS_RF_ON:
+		{
+			/* When we halt NIC, we should check if FW LPS is leave. */
+			if (Adapter->pwrctrlpriv.rf_pwrstate == rf_off) {
+				/*  If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */
+				/*  because Fw is unload. */
+				val[0] = true;
+			} else {
+				u32 valRCR;
+				valRCR = rtw_read32(Adapter, REG_RCR);
+				valRCR &= 0x00070000;
+				if (valRCR)
+					val[0] = false;
+				else
+					val[0] = true;
+			}
+		}
+		break;
+	case HW_VAR_CURRENT_ANTENNA:
+		val[0] = haldata->CurAntenna;
+		break;
+	case HW_VAR_EFUSE_BYTES: /*  To get EFUE total used bytes, added by Roger, 2008.12.22. */
+		*((u16 *)(val)) = haldata->EfuseUsedBytes;
+		break;
+	case HW_VAR_APFM_ON_MAC:
+		*val = haldata->bMacPwrCtrlOn;
+		break;
+	case HW_VAR_CHK_HI_QUEUE_EMPTY:
+		*val = ((rtw_read32(Adapter, REG_HGQ_INFORMATION)&0x0000ff00) == 0) ? true : false;
+		break;
+	default:
+		break;
+	}
+
+_func_exit_;
+}
+
+/*  */
+/*	Description: */
+/*		Query setting of specified variable. */
+/*  */
+static u8
+GetHalDefVar8188EUsb(
+		struct adapter *Adapter,
+		enum hal_def_variable eVariable,
+		void *pValue
+	)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+	u8 bResult = _SUCCESS;
+
+	switch (eVariable) {
+	case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB:
+		{
+			struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+			struct sta_priv *pstapriv = &Adapter->stapriv;
+			struct sta_info *psta;
+			psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress);
+			if (psta)
+				*((int *)pValue) = psta->rssi_stat.UndecoratedSmoothedPWDB;
+		}
+		break;
+	case HAL_DEF_IS_SUPPORT_ANT_DIV:
+		*((u8 *)pValue) = (haldata->AntDivCfg == 0) ? false : true;
+		break;
+	case HAL_DEF_CURRENT_ANTENNA:
+		*((u8 *)pValue) = haldata->CurAntenna;
+		break;
+	case HAL_DEF_DRVINFO_SZ:
+		*((u32 *)pValue) = DRVINFO_SZ;
+		break;
+	case HAL_DEF_MAX_RECVBUF_SZ:
+		*((u32 *)pValue) = MAX_RECVBUF_SZ;
+		break;
+	case HAL_DEF_RX_PACKET_OFFSET:
+		*((u32 *)pValue) = RXDESC_SIZE + DRVINFO_SZ;
+		break;
+	case HAL_DEF_DBG_DM_FUNC:
+		*((u32 *)pValue) = haldata->odmpriv.SupportAbility;
+		break;
+	case HAL_DEF_RA_DECISION_RATE:
+		{
+			u8 MacID = *((u8 *)pValue);
+			*((u8 *)pValue) = ODM_RA_GetDecisionRate_8188E(&(haldata->odmpriv), MacID);
+		}
+		break;
+	case HAL_DEF_RA_SGI:
+		{
+			u8 MacID = *((u8 *)pValue);
+			*((u8 *)pValue) = ODM_RA_GetShortGI_8188E(&(haldata->odmpriv), MacID);
+		}
+		break;
+	case HAL_DEF_PT_PWR_STATUS:
+		{
+			u8 MacID = *((u8 *)pValue);
+			*((u8 *)pValue) = ODM_RA_GetHwPwrStatus_8188E(&(haldata->odmpriv), MacID);
+		}
+		break;
+	case HW_VAR_MAX_RX_AMPDU_FACTOR:
+		*((u32 *)pValue) = MAX_AMPDU_FACTOR_64K;
+		break;
+	case HW_DEF_RA_INFO_DUMP:
+		{
+			u8 entry_id = *((u8 *)pValue);
+			if (check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) {
+				DBG_88E("============ RA status check ===================\n");
+				DBG_88E("Mac_id:%d , RateID = %d, RAUseRate = 0x%08x, RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d\n",
+					entry_id,
+					haldata->odmpriv.RAInfo[entry_id].RateID,
+					haldata->odmpriv.RAInfo[entry_id].RAUseRate,
+					haldata->odmpriv.RAInfo[entry_id].RateSGI,
+					haldata->odmpriv.RAInfo[entry_id].DecisionRate,
+					haldata->odmpriv.RAInfo[entry_id].PTStage);
+			}
+		}
+		break;
+	case HW_DEF_ODM_DBG_FLAG:
+		{
+			struct odm_dm_struct *dm_ocm = &(haldata->odmpriv);
+			pr_info("dm_ocm->DebugComponents = 0x%llx\n", dm_ocm->DebugComponents);
+		}
+		break;
+	case HAL_DEF_DBG_DUMP_RXPKT:
+		*((u8 *)pValue) = haldata->bDumpRxPkt;
+		break;
+	case HAL_DEF_DBG_DUMP_TXPKT:
+		*((u8 *)pValue) = haldata->bDumpTxPkt;
+		break;
+	default:
+		bResult = _FAIL;
+		break;
+	}
+
+	return bResult;
+}
+
+/*  */
+/*	Description: */
+/*		Change default setting of specified variable. */
+/*  */
+static u8 SetHalDefVar8188EUsb(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(Adapter);
+	u8 bResult = _SUCCESS;
+
+	switch (eVariable) {
+	case HAL_DEF_DBG_DM_FUNC:
+		{
+			u8 dm_func = *((u8 *)pValue);
+			struct odm_dm_struct *podmpriv = &haldata->odmpriv;
+
+			if (dm_func == 0) { /* disable all dynamic func */
+				podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE;
+				DBG_88E("==> Disable all dynamic function...\n");
+			} else if (dm_func == 1) {/* disable DIG */
+				podmpriv->SupportAbility  &= (~DYNAMIC_BB_DIG);
+				DBG_88E("==> Disable DIG...\n");
+			} else if (dm_func == 2) {/* disable High power */
+				podmpriv->SupportAbility  &= (~DYNAMIC_BB_DYNAMIC_TXPWR);
+			} else if (dm_func == 3) {/* disable tx power tracking */
+				podmpriv->SupportAbility  &= (~DYNAMIC_RF_CALIBRATION);
+				DBG_88E("==> Disable tx power tracking...\n");
+			} else if (dm_func == 5) {/* disable antenna diversity */
+				podmpriv->SupportAbility  &= (~DYNAMIC_BB_ANT_DIV);
+			} else if (dm_func == 6) {/* turn on all dynamic func */
+				if (!(podmpriv->SupportAbility  & DYNAMIC_BB_DIG)) {
+					struct rtw_dig *pDigTable = &podmpriv->DM_DigTable;
+					pDigTable->CurIGValue = rtw_read8(Adapter, 0xc50);
+				}
+				podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE;
+				DBG_88E("==> Turn on all dynamic function...\n");
+			}
+		}
+		break;
+	case HAL_DEF_DBG_DUMP_RXPKT:
+		haldata->bDumpRxPkt = *((u8 *)pValue);
+		break;
+	case HAL_DEF_DBG_DUMP_TXPKT:
+		haldata->bDumpTxPkt = *((u8 *)pValue);
+		break;
+	case HW_DEF_FA_CNT_DUMP:
+		{
+			u8 bRSSIDump = *((u8 *)pValue);
+			struct odm_dm_struct *dm_ocm = &(haldata->odmpriv);
+			if (bRSSIDump)
+				dm_ocm->DebugComponents	=	ODM_COMP_DIG|ODM_COMP_FA_CNT	;
+			else
+				dm_ocm->DebugComponents	= 0;
+		}
+		break;
+	case HW_DEF_ODM_DBG_FLAG:
+		{
+			u64	DebugComponents = *((u64 *)pValue);
+			struct odm_dm_struct *dm_ocm = &(haldata->odmpriv);
+			dm_ocm->DebugComponents = DebugComponents;
+		}
+		break;
+	default:
+		bResult = _FAIL;
+		break;
+	}
+
+	return bResult;
+}
+
+static void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level)
+{
+	u8 init_rate = 0;
+	u8 networkType, raid;
+	u32 mask, rate_bitmap;
+	u8 shortGIrate = false;
+	int	supportRateNum = 0;
+	struct sta_info	*psta;
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+	struct mlme_ext_priv	*pmlmeext = &adapt->mlmeextpriv;
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct wlan_bssid_ex	*cur_network = &(pmlmeinfo->network);
+
+	if (mac_id >= NUM_STA) /* CAM_SIZE */
+		return;
+	psta = pmlmeinfo->FW_sta_info[mac_id].psta;
+	if (psta == NULL)
+		return;
+	switch (mac_id) {
+	case 0:/*  for infra mode */
+		supportRateNum = rtw_get_rateset_len(cur_network->SupportedRates);
+		networkType = judge_network_type(adapt, cur_network->SupportedRates, supportRateNum) & 0xf;
+		raid = networktype_to_raid(networkType);
+		mask = update_supported_rate(cur_network->SupportedRates, supportRateNum);
+		mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate(&(pmlmeinfo->HT_caps)) : 0;
+		if (support_short_GI(adapt, &(pmlmeinfo->HT_caps)))
+			shortGIrate = true;
+		break;
+	case 1:/* for broadcast/multicast */
+		supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+		if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+			networkType = WIRELESS_11B;
+		else
+			networkType = WIRELESS_11G;
+		raid = networktype_to_raid(networkType);
+		mask = update_basic_rate(cur_network->SupportedRates, supportRateNum);
+		break;
+	default: /* for each sta in IBSS */
+		supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+		networkType = judge_network_type(adapt, pmlmeinfo->FW_sta_info[mac_id].SupportedRates, supportRateNum) & 0xf;
+		raid = networktype_to_raid(networkType);
+		mask = update_supported_rate(cur_network->SupportedRates, supportRateNum);
+
+		/* todo: support HT in IBSS */
+		break;
+	}
+
+	rate_bitmap = 0x0fffffff;
+	rate_bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, mac_id, mask, rssi_level);
+	DBG_88E("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n",
+		__func__, mac_id, networkType, mask, rssi_level, rate_bitmap);
+
+	mask &= rate_bitmap;
+
+	init_rate = get_highest_rate_idx(mask)&0x3f;
+
+	if (haldata->fw_ractrl) {
+		u8 arg;
+
+		arg = mac_id & 0x1f;/* MACID */
+		arg |= BIT(7);
+		if (shortGIrate)
+			arg |= BIT(5);
+		mask |= ((raid << 28) & 0xf0000000);
+		DBG_88E("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg);
+		psta->ra_mask = mask;
+		mask |= ((raid << 28) & 0xf0000000);
+
+		/* to do ,for 8188E-SMIC */
+		rtl8188e_set_raid_cmd(adapt, mask);
+	} else {
+		ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv),
+				mac_id,
+				raid,
+				mask,
+				shortGIrate
+				);
+	}
+	/* set ra_id */
+	psta->raid = raid;
+	psta->init_rate = init_rate;
+}
+
+static void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt)
+{
+	u32 value32;
+	struct mlme_ext_priv	*pmlmeext = &(adapt->mlmeextpriv);
+	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
+	u32 bcn_ctrl_reg			= REG_BCN_CTRL;
+	/* reset TSF, enable update TSF, correcting TSF On Beacon */
+
+	/* BCN interval */
+	rtw_write16(adapt, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval);
+	rtw_write8(adapt, REG_ATIMWND, 0x02);/*  2ms */
+
+	_InitBeaconParameters(adapt);
+
+	rtw_write8(adapt, REG_SLOT, 0x09);
+
+	value32 = rtw_read32(adapt, REG_TCR);
+	value32 &= ~TSFRST;
+	rtw_write32(adapt,  REG_TCR, value32);
+
+	value32 |= TSFRST;
+	rtw_write32(adapt, REG_TCR, value32);
+
+	/*  NOTE: Fix test chip's bug (about contention windows's randomness) */
+	rtw_write8(adapt,  REG_RXTSF_OFFSET_CCK, 0x50);
+	rtw_write8(adapt, REG_RXTSF_OFFSET_OFDM, 0x50);
+
+	_BeaconFunctionEnable(adapt, true, true);
+
+	ResumeTxBeacon(adapt);
+
+	rtw_write8(adapt, bcn_ctrl_reg, rtw_read8(adapt, bcn_ctrl_reg)|BIT(1));
+}
+
+static void rtl8188eu_init_default_value(struct adapter *adapt)
+{
+	struct hal_data_8188e *haldata;
+	struct pwrctrl_priv *pwrctrlpriv;
+	u8 i;
+
+	haldata = GET_HAL_DATA(adapt);
+	pwrctrlpriv = &adapt->pwrctrlpriv;
+
+	/* init default value */
+	haldata->fw_ractrl = false;
+	if (!pwrctrlpriv->bkeepfwalive)
+		haldata->LastHMEBoxNum = 0;
+
+	/* init dm default value */
+	haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = false;
+	haldata->odmpriv.RFCalibrateInfo.TM_Trigger = 0;/* for IQK */
+	haldata->pwrGroupCnt = 0;
+	haldata->PGMaxGroup = 13;
+	haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP_index = 0;
+	for (i = 0; i < HP_THERMAL_NUM; i++)
+		haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP[i] = 0;
+}
+
+static u8 rtl8188eu_ps_func(struct adapter *Adapter, enum hal_intf_ps_func efunc_id, u8 *val)
+{
+	u8 bResult = true;
+	return bResult;
+}
+
+void rtl8188eu_set_hal_ops(struct adapter *adapt)
+{
+	struct hal_ops	*halfunc = &adapt->HalFunc;
+
+_func_enter_;
+
+	adapt->HalData = rtw_zmalloc(sizeof(struct hal_data_8188e));
+	if (adapt->HalData == NULL)
+		DBG_88E("cant not alloc memory for HAL DATA\n");
+	adapt->hal_data_sz = sizeof(struct hal_data_8188e);
+
+	halfunc->hal_power_on = rtl8188eu_InitPowerOn;
+	halfunc->hal_init = &rtl8188eu_hal_init;
+	halfunc->hal_deinit = &rtl8188eu_hal_deinit;
+
+	halfunc->inirp_init = &rtl8188eu_inirp_init;
+	halfunc->inirp_deinit = &rtl8188eu_inirp_deinit;
+
+	halfunc->init_xmit_priv = &rtl8188eu_init_xmit_priv;
+	halfunc->free_xmit_priv = &rtl8188eu_free_xmit_priv;
+
+	halfunc->init_recv_priv = &rtl8188eu_init_recv_priv;
+	halfunc->free_recv_priv = &rtl8188eu_free_recv_priv;
+	halfunc->InitSwLeds = &rtl8188eu_InitSwLeds;
+	halfunc->DeInitSwLeds = &rtl8188eu_DeInitSwLeds;
+
+	halfunc->init_default_value = &rtl8188eu_init_default_value;
+	halfunc->intf_chip_configure = &rtl8188eu_interface_configure;
+	halfunc->read_adapter_info = &ReadAdapterInfo8188EU;
+
+	halfunc->SetHwRegHandler = &SetHwReg8188EU;
+	halfunc->GetHwRegHandler = &GetHwReg8188EU;
+	halfunc->GetHalDefVarHandler = &GetHalDefVar8188EUsb;
+	halfunc->SetHalDefVarHandler = &SetHalDefVar8188EUsb;
+
+	halfunc->UpdateRAMaskHandler = &UpdateHalRAMask8188EUsb;
+	halfunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188EUsb;
+
+	halfunc->hal_xmit = &rtl8188eu_hal_xmit;
+	halfunc->mgnt_xmit = &rtl8188eu_mgnt_xmit;
+
+	halfunc->interface_ps_func = &rtl8188eu_ps_func;
+
+	rtl8188e_set_hal_ops(halfunc);
+_func_exit_;
+}
diff --git a/drivers/staging/rtl8188eu/hal/usb_ops_linux.c b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
new file mode 100644
index 0000000..bc56416
--- /dev/null
+++ b/drivers/staging/rtl8188eu/hal/usb_ops_linux.c
@@ -0,0 +1,726 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _HCI_OPS_OS_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+#include <recv_osdep.h>
+#include <rtl8188e_hal.h>
+
+static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
+{
+	struct adapter	*adapt = pintfhdl->padapter;
+	struct dvobj_priv  *dvobjpriv = adapter_to_dvobj(adapt);
+	struct usb_device *udev = dvobjpriv->pusbdev;
+	unsigned int pipe;
+	int status = 0;
+	u8 reqtype;
+	u8 *pIo_buf;
+	int vendorreq_times = 0;
+
+	if ((adapt->bSurpriseRemoved) || (adapt->pwrctrlpriv.pnp_bstop_trx)) {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usbctrl_vendorreq:(adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+		status = -EPERM;
+		goto exit;
+	}
+
+	if (len > MAX_VENDOR_REQ_CMD_SIZE) {
+		DBG_88E("[%s] Buffer len error ,vendor request failed\n", __func__);
+		status = -EINVAL;
+		goto exit;
+	}
+
+	_enter_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL);
+
+	/*  Acquire IO memory for vendorreq */
+	pIo_buf = dvobjpriv->usb_vendor_req_buf;
+
+	if (pIo_buf == NULL) {
+		DBG_88E("[%s] pIo_buf == NULL\n", __func__);
+		status = -ENOMEM;
+		goto release_mutex;
+	}
+
+	while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) {
+		_rtw_memset(pIo_buf, 0, len);
+
+		if (requesttype == 0x01) {
+			pipe = usb_rcvctrlpipe(udev, 0);/* read_in */
+			reqtype =  REALTEK_USB_VENQT_READ;
+		} else {
+			pipe = usb_sndctrlpipe(udev, 0);/* write_out */
+			reqtype =  REALTEK_USB_VENQT_WRITE;
+			memcpy(pIo_buf, pdata, len);
+		}
+
+		status = rtw_usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
+
+		if (status == len) {   /*  Success this control transfer. */
+			rtw_reset_continual_urb_error(dvobjpriv);
+			if (requesttype == 0x01)
+				memcpy(pdata, pIo_buf,  len);
+		} else { /*  error cases */
+			DBG_88E("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n",
+				value, (requesttype == 0x01) ? "read" : "write",
+				len, status, *(u32 *)pdata, vendorreq_times);
+
+			if (status < 0) {
+				if (status == (-ESHUTDOWN) || status == -ENODEV) {
+					adapt->bSurpriseRemoved = true;
+				} else {
+					struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+					haldata->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL;
+				}
+			} else { /*  status != len && status >= 0 */
+				if (status > 0) {
+					if (requesttype == 0x01) {
+						/*  For Control read transfer, we have to copy the read data from pIo_buf to pdata. */
+						memcpy(pdata, pIo_buf,  len);
+					}
+				}
+			}
+
+			if (rtw_inc_and_chk_continual_urb_error(dvobjpriv)) {
+				adapt->bSurpriseRemoved = true;
+				break;
+			}
+
+		}
+
+		/*  firmware download is checksumed, don't retry */
+		if ((value >= FW_8188E_START_ADDRESS && value <= FW_8188E_END_ADDRESS) || status == len)
+			break;
+	}
+release_mutex:
+	_exit_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL);
+exit:
+	return status;
+}
+
+static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	u8 data = 0;
+
+	_func_enter_;
+
+	request = 0x05;
+	requesttype = 0x01;/* read_in */
+	index = 0;/* n/a */
+
+	wvalue = (u16)(addr&0x0000ffff);
+	len = 1;
+
+	usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+	_func_exit_;
+
+	return data;
+
+}
+
+static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	__le32 data;
+
+_func_enter_;
+	request = 0x05;
+	requesttype = 0x01;/* read_in */
+	index = 0;/* n/a */
+	wvalue = (u16)(addr&0x0000ffff);
+	len = 2;
+	usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+_func_exit_;
+
+	return (u16)(le32_to_cpu(data)&0xffff);
+}
+
+static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	__le32 data;
+
+_func_enter_;
+
+	request = 0x05;
+	requesttype = 0x01;/* read_in */
+	index = 0;/* n/a */
+
+	wvalue = (u16)(addr&0x0000ffff);
+	len = 4;
+
+	usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+_func_exit_;
+
+	return le32_to_cpu(data);
+}
+
+static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	u8 data;
+	int ret;
+
+	_func_enter_;
+	request = 0x05;
+	requesttype = 0x00;/* write_out */
+	index = 0;/* n/a */
+	wvalue = (u16)(addr&0x0000ffff);
+	len = 1;
+	data = val;
+	ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+	_func_exit_;
+	return ret;
+}
+
+static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	__le32 data;
+	int ret;
+
+	_func_enter_;
+
+	request = 0x05;
+	requesttype = 0x00;/* write_out */
+	index = 0;/* n/a */
+
+	wvalue = (u16)(addr&0x0000ffff);
+	len = 2;
+
+	data = cpu_to_le32(val & 0x0000ffff);
+
+	ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+	_func_exit_;
+
+	return ret;
+}
+
+static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	__le32 data;
+	int ret;
+
+	_func_enter_;
+
+	request = 0x05;
+	requesttype = 0x00;/* write_out */
+	index = 0;/* n/a */
+
+	wvalue = (u16)(addr&0x0000ffff);
+	len = 4;
+	data = cpu_to_le32(val);
+
+	ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+	_func_exit_;
+
+	return ret;
+}
+
+static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata)
+{
+	u8 request;
+	u8 requesttype;
+	u16 wvalue;
+	u16 index;
+	u16 len;
+	u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
+	int ret;
+
+	_func_enter_;
+
+	request = 0x05;
+	requesttype = 0x00;/* write_out */
+	index = 0;/* n/a */
+
+	wvalue = (u16)(addr&0x0000ffff);
+	len = length;
+	 memcpy(buf, pdata, len);
+
+	ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype);
+
+	_func_exit_;
+
+	return ret;
+}
+
+static void interrupt_handler_8188eu(struct adapter *adapt, u16 pkt_len, u8 *pbuf)
+{
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+
+	if (pkt_len != INTERRUPT_MSG_FORMAT_LEN) {
+		DBG_88E("%s Invalid interrupt content length (%d)!\n", __func__, pkt_len);
+		return;
+	}
+
+	/*  HISR */
+	memcpy(&(haldata->IntArray[0]), &(pbuf[USB_INTR_CONTENT_HISR_OFFSET]), 4);
+	memcpy(&(haldata->IntArray[1]), &(pbuf[USB_INTR_CONTENT_HISRE_OFFSET]), 4);
+
+	/*  C2H Event */
+	if (pbuf[0] != 0)
+		memcpy(&(haldata->C2hArray[0]), &(pbuf[USB_INTR_CONTENT_C2H_OFFSET]), 16);
+}
+
+static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb)
+{
+	u8	*pbuf;
+	u8	shift_sz = 0;
+	u16	pkt_cnt;
+	u32	pkt_offset, skb_len, alloc_sz;
+	s32	transfer_len;
+	struct recv_stat	*prxstat;
+	struct phy_stat	*pphy_status = NULL;
+	struct sk_buff *pkt_copy = NULL;
+	union recv_frame	*precvframe = NULL;
+	struct rx_pkt_attrib	*pattrib = NULL;
+	struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+	struct recv_priv	*precvpriv = &adapt->recvpriv;
+	struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue;
+
+	transfer_len = (s32)pskb->len;
+	pbuf = pskb->data;
+
+	prxstat = (struct recv_stat *)pbuf;
+	pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff;
+
+	do {
+		RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+			 ("recvbuf2recvframe: rxdesc=offsset 0:0x%08x, 4:0x%08x, 8:0x%08x, C:0x%08x\n",
+			  prxstat->rxdw0, prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4));
+
+		prxstat = (struct recv_stat *)pbuf;
+
+		precvframe = rtw_alloc_recvframe(pfree_recv_queue);
+		if (precvframe == NULL) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvbuf2recvframe: precvframe==NULL\n"));
+			DBG_88E("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __func__, __LINE__);
+			goto _exit_recvbuf2recvframe;
+		}
+
+		_rtw_init_listhead(&precvframe->u.hdr.list);
+		precvframe->u.hdr.precvbuf = NULL;	/* can't access the precvbuf for new arch. */
+		precvframe->u.hdr.len = 0;
+
+		update_recvframe_attrib_88e(precvframe, prxstat);
+
+		pattrib = &precvframe->u.hdr.attrib;
+
+		if ((pattrib->crc_err) || (pattrib->icv_err)) {
+			DBG_88E("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err);
+
+			rtw_free_recvframe(precvframe, pfree_recv_queue);
+			goto _exit_recvbuf2recvframe;
+		}
+
+		if ((pattrib->physt) && (pattrib->pkt_rpt_type == NORMAL_RX))
+			pphy_status = (struct phy_stat *)(pbuf + RXDESC_OFFSET);
+
+		pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len;
+
+		if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) {
+			RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recvbuf2recvframe: pkt_len<=0\n"));
+			DBG_88E("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfoer_len\n", __func__, __LINE__);
+			rtw_free_recvframe(precvframe, pfree_recv_queue);
+			goto _exit_recvbuf2recvframe;
+		}
+
+		/*	Modified by Albert 20101213 */
+		/*	For 8 bytes IP header alignment. */
+		if (pattrib->qos)	/*	Qos data, wireless lan header length is 26 */
+			shift_sz = 6;
+		else
+			shift_sz = 0;
+
+		skb_len = pattrib->pkt_len;
+
+		/*  for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */
+		/*  modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */
+		if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+			if (skb_len <= 1650)
+				alloc_sz = 1664;
+			else
+				alloc_sz = skb_len + 14;
+		} else {
+			alloc_sz = skb_len;
+			/*	6 is for IP header 8 bytes alignment in QoS packet case. */
+			/*	8 is for skb->data 4 bytes alignment. */
+			alloc_sz += 14;
+		}
+
+		pkt_copy = netdev_alloc_skb(adapt->pnetdev, alloc_sz);
+		if (pkt_copy) {
+			pkt_copy->dev = adapt->pnetdev;
+			precvframe->u.hdr.pkt = pkt_copy;
+			precvframe->u.hdr.rx_head = pkt_copy->data;
+			precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
+			skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
+			skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
+			memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
+			precvframe->u.hdr.rx_tail = pkt_copy->data;
+			precvframe->u.hdr.rx_data = pkt_copy->data;
+		} else {
+			if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+				DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n");
+				rtw_free_recvframe(precvframe, pfree_recv_queue);
+				goto _exit_recvbuf2recvframe;
+			}
+			precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC);
+			if (precvframe->u.hdr.pkt) {
+				precvframe->u.hdr.rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE;
+				precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_tail;
+				precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail;
+				precvframe->u.hdr.rx_end =  pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz;
+			} else {
+				DBG_88E("recvbuf2recvframe: skb_clone fail\n");
+				rtw_free_recvframe(precvframe, pfree_recv_queue);
+				goto _exit_recvbuf2recvframe;
+			}
+		}
+
+		recvframe_put(precvframe, skb_len);
+
+		switch (haldata->UsbRxAggMode) {
+		case USB_RX_AGG_DMA:
+		case USB_RX_AGG_MIX:
+			pkt_offset = (u16)_RND128(pkt_offset);
+			break;
+		case USB_RX_AGG_USB:
+			pkt_offset = (u16)_RND4(pkt_offset);
+			break;
+		case USB_RX_AGG_DISABLE:
+		default:
+			break;
+		}
+		if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */
+			if (pattrib->physt)
+				update_recvframe_phyinfo_88e(precvframe, (struct phy_stat *)pphy_status);
+			if (rtw_recv_entry(precvframe) != _SUCCESS) {
+				RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+					("recvbuf2recvframe: rtw_recv_entry(precvframe) != _SUCCESS\n"));
+			}
+		} else {
+			/* enqueue recvframe to txrtp queue */
+			if (pattrib->pkt_rpt_type == TX_REPORT1) {
+				/* CCX-TXRPT ack for xmit mgmt frames. */
+				handle_txrpt_ccx_88e(adapt, precvframe->u.hdr.rx_data);
+			} else if (pattrib->pkt_rpt_type == TX_REPORT2) {
+				ODM_RA_TxRPT2Handle_8188E(
+							&haldata->odmpriv,
+							precvframe->u.hdr.rx_data,
+							pattrib->pkt_len,
+							pattrib->MacIDValidEntry[0],
+							pattrib->MacIDValidEntry[1]
+							);
+			} else if (pattrib->pkt_rpt_type == HIS_REPORT) {
+				interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->u.hdr.rx_data);
+			}
+			rtw_free_recvframe(precvframe, pfree_recv_queue);
+		}
+		pkt_cnt--;
+		transfer_len -= pkt_offset;
+		pbuf += pkt_offset;
+		precvframe = NULL;
+		pkt_copy = NULL;
+
+		if (transfer_len > 0 && pkt_cnt == 0)
+			pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff;
+
+	} while ((transfer_len > 0) && (pkt_cnt > 0));
+
+_exit_recvbuf2recvframe:
+
+	return _SUCCESS;
+}
+
+void rtl8188eu_recv_tasklet(void *priv)
+{
+	struct sk_buff *pskb;
+	struct adapter *adapt = (struct adapter *)priv;
+	struct recv_priv *precvpriv = &adapt->recvpriv;
+
+	while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
+		if ((adapt->bDriverStopped) || (adapt->bSurpriseRemoved)) {
+			DBG_88E("recv_tasklet => bDriverStopped or bSurpriseRemoved\n");
+			dev_kfree_skb_any(pskb);
+			break;
+		}
+		recvbuf2recvframe(adapt, pskb);
+		skb_reset_tail_pointer(pskb);
+		pskb->len = 0;
+		skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+	}
+}
+
+static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+	struct recv_buf	*precvbuf = (struct recv_buf *)purb->context;
+	struct adapter	*adapt = (struct adapter *)precvbuf->adapter;
+	struct recv_priv *precvpriv = &adapt->recvpriv;
+
+	RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete!!!\n"));
+
+	precvpriv->rx_pending_cnt--;
+
+	if (adapt->bSurpriseRemoved || adapt->bDriverStopped || adapt->bReadPortCancel) {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+			 ("usb_read_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)\n",
+			 adapt->bDriverStopped, adapt->bSurpriseRemoved));
+
+		precvbuf->reuse = true;
+		DBG_88E("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
+			__func__, adapt->bDriverStopped,
+			adapt->bSurpriseRemoved, adapt->bReadPortCancel);
+		goto exit;
+	}
+
+	if (purb->status == 0) { /* SUCCESS */
+		if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) {
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+				 ("usb_read_port_complete: (purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)\n"));
+			precvbuf->reuse = true;
+			rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+			DBG_88E("%s()-%d: RX Warning!\n", __func__, __LINE__);
+		} else {
+			rtw_reset_continual_urb_error(adapter_to_dvobj(adapt));
+
+			precvbuf->transfer_len = purb->actual_length;
+			skb_put(precvbuf->pskb, purb->actual_length);
+			skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb);
+
+			if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1)
+				tasklet_schedule(&precvpriv->recv_tasklet);
+
+			precvbuf->pskb = NULL;
+			precvbuf->reuse = false;
+			rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+		}
+	} else {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete : purb->status(%d) != 0\n", purb->status));
+
+		DBG_88E("###=> usb_read_port_complete => urb status(%d)\n", purb->status);
+
+		if (rtw_inc_and_chk_continual_urb_error(adapter_to_dvobj(adapt)))
+			adapt->bSurpriseRemoved = true;
+
+		switch (purb->status) {
+		case -EINVAL:
+		case -EPIPE:
+		case -ENODEV:
+		case -ESHUTDOWN:
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete:bSurpriseRemoved=true\n"));
+		case -ENOENT:
+			adapt->bDriverStopped = true;
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_read_port_complete:bDriverStopped=true\n"));
+			break;
+		case -EPROTO:
+		case -EOVERFLOW:
+			{
+				struct hal_data_8188e	*haldata = GET_HAL_DATA(adapt);
+				haldata->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL;
+			}
+			precvbuf->reuse = true;
+			rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+			break;
+		case -EINPROGRESS:
+			DBG_88E("ERROR: URB IS IN PROGRESS!/n");
+			break;
+		default:
+			break;
+		}
+	}
+
+exit:
+_func_exit_;
+}
+
+static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+	struct urb *purb = NULL;
+	struct recv_buf	*precvbuf = (struct recv_buf *)rmem;
+	struct adapter		*adapter = pintfhdl->padapter;
+	struct dvobj_priv	*pdvobj = adapter_to_dvobj(adapter);
+	struct recv_priv	*precvpriv = &adapter->recvpriv;
+	struct usb_device	*pusbd = pdvobj->pusbdev;
+	int err;
+	unsigned int pipe;
+	size_t tmpaddr = 0;
+	size_t alignment = 0;
+	u32 ret = _SUCCESS;
+
+_func_enter_;
+
+	if (adapter->bDriverStopped || adapter->bSurpriseRemoved ||
+	    adapter->pwrctrlpriv.pnp_bstop_trx) {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+			 ("usb_read_port:(adapt->bDriverStopped ||adapt->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+		return _FAIL;
+	}
+
+	if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) {
+		precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
+		if (NULL != precvbuf->pskb)
+			precvbuf->reuse = true;
+	}
+
+	if (precvbuf != NULL) {
+		rtl8188eu_init_recvbuf(adapter, precvbuf);
+
+		/* re-assign for linux based on skb */
+		if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) {
+			precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
+			if (precvbuf->pskb == NULL) {
+				RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n"));
+				DBG_88E("#### usb_read_port() alloc_skb fail!#####\n");
+				return _FAIL;
+			}
+
+			tmpaddr = (size_t)precvbuf->pskb->data;
+			alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+			skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
+
+			precvbuf->phead = precvbuf->pskb->head;
+			precvbuf->pdata = precvbuf->pskb->data;
+			precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
+			precvbuf->pend = skb_end_pointer(precvbuf->pskb);
+			precvbuf->pbuf = precvbuf->pskb->data;
+		} else { /* reuse skb */
+			precvbuf->phead = precvbuf->pskb->head;
+			precvbuf->pdata = precvbuf->pskb->data;
+			precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
+			precvbuf->pend = skb_end_pointer(precvbuf->pskb);
+			precvbuf->pbuf = precvbuf->pskb->data;
+
+			precvbuf->reuse = false;
+		}
+
+		precvpriv->rx_pending_cnt++;
+
+		purb = precvbuf->purb;
+
+		/* translate DMA FIFO addr to pipehandle */
+		pipe = ffaddr2pipehdl(pdvobj, addr);
+
+		usb_fill_bulk_urb(purb, pusbd, pipe,
+				  precvbuf->pbuf,
+				  MAX_RECVBUF_SZ,
+				  usb_read_port_complete,
+				  precvbuf);/* context is precvbuf */
+
+		err = usb_submit_urb(purb, GFP_ATOMIC);
+		if ((err) && (err != (-EPERM))) {
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+				 ("cannot submit rx in-token(err=0x%.8x), URB_STATUS =0x%.8x",
+				 err, purb->status));
+			DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n",
+				err, purb->status);
+			ret = _FAIL;
+		}
+	} else {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+			 ("usb_read_port:precvbuf ==NULL\n"));
+		ret = _FAIL;
+	}
+
+_func_exit_;
+	return ret;
+}
+
+void rtl8188eu_xmit_tasklet(void *priv)
+{
+	int ret = false;
+	struct adapter *adapt = (struct adapter *)priv;
+	struct xmit_priv *pxmitpriv = &adapt->xmitpriv;
+
+	if (check_fwstate(&adapt->mlmepriv, _FW_UNDER_SURVEY))
+		return;
+
+	while (1) {
+		if ((adapt->bDriverStopped) ||
+		    (adapt->bSurpriseRemoved) ||
+		    (adapt->bWritePortCancel)) {
+			DBG_88E("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n");
+			break;
+		}
+
+		ret = rtl8188eu_xmitframe_complete(adapt, pxmitpriv, NULL);
+
+		if (!ret)
+			break;
+	}
+}
+
+void rtl8188eu_set_intf_ops(struct _io_ops	*pops)
+{
+	_func_enter_;
+	_rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));
+	pops->_read8 = &usb_read8;
+	pops->_read16 = &usb_read16;
+	pops->_read32 = &usb_read32;
+	pops->_read_mem = &usb_read_mem;
+	pops->_read_port = &usb_read_port;
+	pops->_write8 = &usb_write8;
+	pops->_write16 = &usb_write16;
+	pops->_write32 = &usb_write32;
+	pops->_writeN = &usb_writeN;
+	pops->_write_mem = &usb_write_mem;
+	pops->_write_port = &usb_write_port;
+	pops->_read_port_cancel = &usb_read_port_cancel;
+	pops->_write_port_cancel = &usb_write_port_cancel;
+	_func_exit_;
+}
+
+void rtl8188eu_set_hw_type(struct adapter *adapt)
+{
+	adapt->chip_type = RTL8188E;
+	adapt->HardwareType = HARDWARE_TYPE_RTL8188EU;
+	DBG_88E("CHIP TYPE: RTL8188E\n");
+}
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h b/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h
new file mode 100644
index 0000000..949c33b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EFWImg_CE.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+#ifndef __INC_HAL8188E_FW_IMG_H
+#define __INC_HAL8188E_FW_IMG_H
+
+/* V10(1641) */
+#define Rtl8188EFWImgArrayLength 13904
+
+extern const u8 Rtl8188EFwImgArray[Rtl8188EFWImgArrayLength];
+
+#endif /* __INC_HAL8188E_FW_IMG_H */
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h b/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h
new file mode 100644
index 0000000..c4769e2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EPhyCfg.h
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8188EPHYCFG_H__
+#define __INC_HAL8188EPHYCFG_H__
+
+
+/*--------------------------Define Parameters-------------------------------*/
+#define LOOP_LIMIT			5
+#define MAX_STALL_TIME			50		/* us */
+#define AntennaDiversityValue		0x80
+#define MAX_TXPWR_IDX_NMODE_92S		63
+#define Reset_Cnt_Limit			3
+
+#define IQK_MAC_REG_NUM			4
+#define IQK_ADDA_REG_NUM		16
+#define IQK_BB_REG_NUM			9
+#define HP_THERMAL_NUM			8
+
+#define MAX_AGGR_NUM			0x07
+
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+/*------------------------------Define structure----------------------------*/
+enum sw_chnl_cmd_id {
+	CmdID_End,
+	CmdID_SetTxPowerLevel,
+	CmdID_BBRegWrite10,
+	CmdID_WritePortUlong,
+	CmdID_WritePortUshort,
+	CmdID_WritePortUchar,
+	CmdID_RF_WriteReg,
+};
+
+/* 1. Switch channel related */
+struct sw_chnl_cmd {
+	enum sw_chnl_cmd_id CmdID;
+	u32 Para1;
+	u32 Para2;
+	u32 msDelay;
+};
+
+enum hw90_block {
+	HW90_BLOCK_MAC = 0,
+	HW90_BLOCK_PHY0 = 1,
+	HW90_BLOCK_PHY1 = 2,
+	HW90_BLOCK_RF = 3,
+	HW90_BLOCK_MAXIMUM = 4, /*  Never use this */
+};
+
+enum rf_radio_path {
+	RF_PATH_A = 0,			/* Radio Path A */
+	RF_PATH_B = 1,			/* Radio Path B */
+	RF_PATH_C = 2,			/* Radio Path C */
+	RF_PATH_D = 3,			/* Radio Path D */
+};
+
+#define MAX_PG_GROUP 13
+
+#define	RF_PATH_MAX			2
+#define		MAX_RF_PATH		RF_PATH_MAX
+#define		MAX_TX_COUNT		4 /* path numbers */
+
+#define CHANNEL_MAX_NUMBER		14	/*  14 is the max chnl number */
+#define MAX_CHNL_GROUP_24G		6	/*  ch1~2, ch3~5, ch6~8,
+						 *ch9~11, ch12~13, CH 14
+						 * total three groups */
+#define CHANNEL_GROUP_MAX_88E		6
+
+enum wireless_mode {
+	WIRELESS_MODE_UNKNOWN = 0x00,
+	WIRELESS_MODE_A			= BIT2,
+	WIRELESS_MODE_B			= BIT0,
+	WIRELESS_MODE_G			= BIT1,
+	WIRELESS_MODE_AUTO		= BIT5,
+	WIRELESS_MODE_N_24G		= BIT3,
+	WIRELESS_MODE_N_5G		= BIT4,
+	WIRELESS_MODE_AC		= BIT6
+};
+
+enum phy_rate_tx_offset_area {
+	RA_OFFSET_LEGACY_OFDM1,
+	RA_OFFSET_LEGACY_OFDM2,
+	RA_OFFSET_HT_OFDM1,
+	RA_OFFSET_HT_OFDM2,
+	RA_OFFSET_HT_OFDM3,
+	RA_OFFSET_HT_OFDM4,
+	RA_OFFSET_HT_CCK,
+};
+
+/* BB/RF related */
+enum RF_TYPE_8190P {
+	RF_TYPE_MIN,		/*  0 */
+	RF_8225 = 1,		/*  1 11b/g RF for verification only */
+	RF_8256 = 2,		/*  2 11b/g/n */
+	RF_8258 = 3,		/*  3 11a/b/g/n RF */
+	RF_6052 = 4,		/*  4 11b/g/n RF */
+	/*  TODO: We should remove this psudo PHY RF after we get new RF. */
+	RF_PSEUDO_11N = 5,	/*  5, It is a temporality RF. */
+};
+
+struct bb_reg_def {
+	u32 rfintfs;		/*  set software control: */
+				/*	0x870~0x877[8 bytes] */
+	u32 rfintfi;		/*  readback data: */
+				/*	0x8e0~0x8e7[8 bytes] */
+	u32 rfintfo;		/*  output data: */
+				/*	0x860~0x86f [16 bytes] */
+	u32 rfintfe;		/*  output enable: */
+				/*	0x860~0x86f [16 bytes] */
+	u32 rf3wireOffset;	/*  LSSI data: */
+				/*	0x840~0x84f [16 bytes] */
+	u32 rfLSSI_Select;	/*  BB Band Select: */
+				/*	0x878~0x87f [8 bytes] */
+	u32 rfTxGainStage;	/*  Tx gain stage: */
+				/*	0x80c~0x80f [4 bytes] */
+	u32 rfHSSIPara1;	/*  wire parameter control1 : */
+				/*	0x820~0x823,0x828~0x82b,
+				 *	0x830~0x833, 0x838~0x83b [16 bytes] */
+	u32 rfHSSIPara2;	/*  wire parameter control2 : */
+				/*	0x824~0x827,0x82c~0x82f, 0x834~0x837,
+				 *	0x83c~0x83f [16 bytes] */
+	u32 rfSwitchControl;	/* Tx Rx antenna control : */
+				/*	0x858~0x85f [16 bytes] */
+	u32 rfAGCControl1;	/* AGC parameter control1 : */
+				/*	0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63,
+				 * 0xc68~0xc6b [16 bytes] */
+	u32 rfAGCControl2;	/* AGC parameter control2 : */
+				/*	0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67,
+				 *	0xc6c~0xc6f [16 bytes] */
+	u32 rfRxIQImbalance;	/* OFDM Rx IQ imbalance matrix : */
+				/*	0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27,
+				 *	0xc2c~0xc2f [16 bytes] */
+	u32 rfRxAFE;		/* Rx IQ DC ofset and Rx digital filter,
+				 * Rx DC notch filter : */
+				/*	0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23,
+				 *	0xc28~0xc2b [16 bytes] */
+	u32 rfTxIQImbalance;	/* OFDM Tx IQ imbalance matrix */
+				/*	0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93,
+				 *	 0xc98~0xc9b [16 bytes] */
+	u32 rfTxAFE;		/* Tx IQ DC Offset and Tx DFIR type */
+				/*	0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97,
+				 *	0xc9c~0xc9f [16 bytes] */
+	u32 rfLSSIReadBack;	/* LSSI RF readback data SI mode */
+				/*	0x8a0~0x8af [16 bytes] */
+	u32 rfLSSIReadBackPi;	/* LSSI RF readback data PI mode 0x8b8-8bc for
+				 * Path A and B */
+};
+
+struct ant_sel_ofdm {
+	u32 r_tx_antenna:4;
+	u32 r_ant_l:4;
+	u32 r_ant_non_ht:4;
+	u32 r_ant_ht1:4;
+	u32 r_ant_ht2:4;
+	u32 r_ant_ht_s1:4;
+	u32 r_ant_non_ht_s1:4;
+	u32 OFDM_TXSC:2;
+	u32 reserved:2;
+};
+
+struct ant_sel_cck {
+	u8 r_cckrx_enable_2:2;
+	u8 r_cckrx_enable:2;
+	u8 r_ccktx_enable:4;
+};
+
+/*------------------------------Define structure----------------------------*/
+
+
+/*------------------------Export global variable----------------------------*/
+/*------------------------Export global variable----------------------------*/
+
+
+/*------------------------Export Marco Definition---------------------------*/
+/*------------------------Export Marco Definition---------------------------*/
+
+
+/*--------------------------Exported Function prototype---------------------*/
+/*  */
+/*  BB and RF register read/write */
+/*  */
+u32 rtl8188e_PHY_QueryBBReg(struct adapter *adapter, u32 regaddr, u32 mask);
+void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr,
+			   u32 mask, u32 data);
+u32 rtl8188e_PHY_QueryRFReg(struct adapter *adapter, enum rf_radio_path rfpath,
+			    u32 regaddr, u32 mask);
+void rtl8188e_PHY_SetRFReg(struct adapter *adapter, enum rf_radio_path rfpath,
+			   u32 regaddr, u32 mask, u32 data);
+
+/*  Initialization related function */
+/* MAC/BB/RF HAL config */
+int PHY_MACConfig8188E(struct adapter *adapter);
+int PHY_BBConfig8188E(struct adapter *adapter);
+int PHY_RFConfig8188E(struct adapter *adapter);
+
+/* RF config */
+int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *adapter, u8 *filename,
+				      enum rf_radio_path rfpath);
+int rtl8188e_PHY_ConfigRFWithHeaderFile(struct adapter *adapter,
+					enum rf_radio_path rfpath);
+
+/* Read initi reg value for tx power setting. */
+void rtl8192c_PHY_GetHWRegOriginalValue(struct adapter *adapter);
+
+/*  BB TX Power R/W */
+void PHY_GetTxPowerLevel8188E(struct adapter *adapter, u32 *powerlevel);
+void PHY_SetTxPowerLevel8188E(struct adapter *adapter, u8 channel);
+bool PHY_UpdateTxPowerDbm8188E(struct adapter *adapter, int power);
+
+void PHY_ScanOperationBackup8188E(struct adapter *Adapter, u8 Operation);
+
+/*  Switch bandwidth for 8192S */
+void PHY_SetBWMode8188E(struct adapter *adapter,
+			enum ht_channel_width chnlwidth, unsigned char offset);
+
+/*  channel switch related funciton */
+void PHY_SwChnl8188E(struct adapter *adapter, u8 channel);
+/*  Call after initialization */
+void ChkFwCmdIoDone(struct adapter *adapter);
+
+/*  BB/MAC/RF other monitor API */
+void PHY_SetRFPathSwitch_8188E(struct adapter *adapter,	bool main);
+
+void PHY_SwitchEphyParameter(struct adapter *adapter);
+
+void PHY_EnableHostClkReq(struct adapter *adapter);
+
+bool SetAntennaConfig92C(struct adapter *adapter, u8 defaultant);
+
+void storePwrIndexDiffRateOffset(struct adapter *adapter, u32 regaddr,
+				 u32 mask, u32 data);
+/*--------------------------Exported Function prototype---------------------*/
+
+#define PHY_QueryBBReg(adapt, regaddr, mask)			\
+	 rtl8188e_PHY_QueryBBReg((adapt), (regaddr), (mask))
+#define PHY_SetBBReg(adapt, regaddr, bitmask, data)		\
+	 rtl8188e_PHY_SetBBReg((adapt), (regaddr), (bitmask), (data))
+#define PHY_QueryRFReg(adapt, rfpath, regaddr, bitmask)	\
+	rtl8188e_PHY_QueryRFReg((adapt), (rfpath), (regaddr), (bitmask))
+#define PHY_SetRFReg(adapt, rfpath, regaddr, bitmask, data)	\
+	rtl8188e_PHY_SetRFReg((adapt), (rfpath), (regaddr), (bitmask), (data))
+
+#define PHY_SetMacReg	PHY_SetBBReg
+
+#define	SIC_HW_SUPPORT			0
+
+#define	SIC_MAX_POLL_CNT		5
+
+#define	SIC_CMD_READY			0
+#define	SIC_CMD_WRITE			1
+#define	SIC_CMD_READ			2
+
+#define	SIC_CMD_REG			0x1EB		/*  1byte */
+#define	SIC_ADDR_REG			0x1E8		/*  1b9~1ba, 2 bytes */
+#define	SIC_DATA_REG			0x1EC		/*  1bc~1bf */
+
+#endif	/*  __INC_HAL8192CPHYCFG_H */
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h b/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h
new file mode 100644
index 0000000..0e06d29
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EPhyReg.h
@@ -0,0 +1,1094 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8188EPHYREG_H__
+#define __INC_HAL8188EPHYREG_H__
+/*--------------------------Define Parameters-------------------------------*/
+/*  */
+/*  BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */
+/*  1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/*  2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */
+/*  3. RF register 0x00-2E */
+/*  4. Bit Mask for BB/RF register */
+/*  5. Other defintion for BB/RF R/W */
+/*  */
+
+
+/*  */
+/*  1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/*  1. Page1(0x100) */
+/*  */
+#define	rPMAC_Reset		0x100
+#define	rPMAC_TxStart		0x104
+#define	rPMAC_TxLegacySIG	0x108
+#define	rPMAC_TxHTSIG1		0x10c
+#define	rPMAC_TxHTSIG2		0x110
+#define	rPMAC_PHYDebug		0x114
+#define	rPMAC_TxPacketNum	0x118
+#define	rPMAC_TxIdle		0x11c
+#define	rPMAC_TxMACHeader0	0x120
+#define	rPMAC_TxMACHeader1	0x124
+#define	rPMAC_TxMACHeader2	0x128
+#define	rPMAC_TxMACHeader3	0x12c
+#define	rPMAC_TxMACHeader4	0x130
+#define	rPMAC_TxMACHeader5	0x134
+#define	rPMAC_TxDataType	0x138
+#define	rPMAC_TxRandomSeed	0x13c
+#define	rPMAC_CCKPLCPPreamble	0x140
+#define	rPMAC_CCKPLCPHeader	0x144
+#define	rPMAC_CCKCRC16		0x148
+#define	rPMAC_OFDMRxCRC32OK	0x170
+#define	rPMAC_OFDMRxCRC32Er	0x174
+#define	rPMAC_OFDMRxParityEr	0x178
+#define	rPMAC_OFDMRxCRC8Er	0x17c
+#define	rPMAC_CCKCRxRC16Er	0x180
+#define	rPMAC_CCKCRxRC32Er	0x184
+#define	rPMAC_CCKCRxRC32OK	0x188
+#define	rPMAC_TxStatus		0x18c
+
+/*  2. Page2(0x200) */
+/*  The following two definition are only used for USB interface. */
+#define	RF_BB_CMD_ADDR		0x02c0	/*  RF/BB r/w cmd address. */
+#define	RF_BB_CMD_DATA		0x02c4	/*  RF/BB r/w cmd data. */
+
+/*  3. Page8(0x800) */
+#define	rFPGA0_RFMOD		0x800	/* RF mode & CCK TxSC RF BW Setting */
+
+#define	rFPGA0_TxInfo		0x804	/*  Status report?? */
+#define	rFPGA0_PSDFunction	0x808
+
+#define	rFPGA0_TxGainStage	0x80c	/*  Set TX PWR init gain? */
+
+#define	rFPGA0_RFTiming1	0x810	/*  Useless now */
+#define	rFPGA0_RFTiming2	0x814
+
+#define	rFPGA0_XA_HSSIParameter1	0x820	/*  RF 3 wire register */
+#define	rFPGA0_XA_HSSIParameter2	0x824
+#define	rFPGA0_XB_HSSIParameter1	0x828
+#define	rFPGA0_XB_HSSIParameter2	0x82c
+
+#define	rFPGA0_XA_LSSIParameter		0x840
+#define	rFPGA0_XB_LSSIParameter		0x844
+
+#define	rFPGA0_RFWakeUpParameter	0x850	/*  Useless now */
+#define	rFPGA0_RFSleepUpParameter	0x854
+
+#define	rFPGA0_XAB_SwitchControl	0x858	/*  RF Channel switch */
+#define	rFPGA0_XCD_SwitchControl	0x85c
+
+#define	rFPGA0_XA_RFInterfaceOE		0x860	/*  RF Channel switch */
+#define	rFPGA0_XB_RFInterfaceOE		0x864
+
+#define	rFPGA0_XAB_RFInterfaceSW	0x870	/*  RF Iface Software Control */
+#define	rFPGA0_XCD_RFInterfaceSW	0x874
+
+#define	rFPGA0_XAB_RFParameter		0x878	/*  RF Parameter */
+#define	rFPGA0_XCD_RFParameter		0x87c
+
+/* Crystal cap setting RF-R/W protection for parameter4?? */
+#define	rFPGA0_AnalogParameter1		0x880
+#define	rFPGA0_AnalogParameter2		0x884
+#define	rFPGA0_AnalogParameter3		0x888
+/*  enable ad/da clock1 for dual-phy */
+#define	rFPGA0_AdDaClockEn		0x888
+#define	rFPGA0_AnalogParameter4		0x88c
+
+#define	rFPGA0_XA_LSSIReadBack		0x8a0	/*  Tranceiver LSSI Readback */
+#define	rFPGA0_XB_LSSIReadBack		0x8a4
+#define	rFPGA0_XC_LSSIReadBack		0x8a8
+#define	rFPGA0_XD_LSSIReadBack		0x8ac
+
+#define	rFPGA0_PSDReport		0x8b4	/*  Useless now */
+/*  Transceiver A HSPI Readback */
+#define	TransceiverA_HSPI_Readback	0x8b8
+/*  Transceiver B HSPI Readback */
+#define	TransceiverB_HSPI_Readback	0x8bc
+/*  Useless now RF Interface Readback Value */
+#define	rFPGA0_XAB_RFInterfaceRB	0x8e0
+#define	rFPGA0_XCD_RFInterfaceRB	0x8e4	/*  Useless now */
+
+/*  4. Page9(0x900) */
+/* RF mode & OFDM TxSC RF BW Setting?? */
+#define	rFPGA1_RFMOD			0x900
+
+#define	rFPGA1_TxBlock			0x904	/*  Useless now */
+#define	rFPGA1_DebugSelect		0x908	/*  Useless now */
+#define	rFPGA1_TxInfo			0x90c	/*  Useless now Status report */
+
+/*  5. PageA(0xA00) */
+/*  Set Control channel to upper or lower - required only for 40MHz */
+#define	rCCK0_System			0xa00
+
+/*  Disable init gain now Select RX path by RSSI */
+#define	rCCK0_AFESetting		0xa04
+/*  Disable init gain now Init gain */
+#define	rCCK0_CCA			0xa08
+
+/* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold,
+ * RX LNA Threshold useless now. Not the same as 90 series */
+#define	rCCK0_RxAGC1			0xa0c
+#define	rCCK0_RxAGC2			0xa10	/* AGC & DAGC */
+
+#define	rCCK0_RxHP			0xa14
+
+/* Timing recovery & Channel estimation threshold */
+#define	rCCK0_DSPParameter1		0xa18
+#define	rCCK0_DSPParameter2		0xa1c	/* SQ threshold */
+
+#define	rCCK0_TxFilter1			0xa20
+#define	rCCK0_TxFilter2			0xa24
+#define	rCCK0_DebugPort			0xa28	/* debug port and Tx filter3 */
+#define	rCCK0_FalseAlarmReport		0xa2c	/* 0xa2d useless now */
+#define	rCCK0_TRSSIReport		0xa50
+#define	rCCK0_RxReport			0xa54  /* 0xa57 */
+#define	rCCK0_FACounterLower		0xa5c  /* 0xa5b */
+#define	rCCK0_FACounterUpper		0xa58  /* 0xa5c */
+
+/*  */
+/*  PageB(0xB00) */
+/*  */
+#define	rPdp_AntA			0xb00
+#define	rPdp_AntA_4			0xb04
+#define	rConfig_Pmpd_AntA		0xb28
+#define	rConfig_AntA			0xb68
+#define	rConfig_AntB			0xb6c
+#define	rPdp_AntB			0xb70
+#define	rPdp_AntB_4			0xb74
+#define	rConfig_Pmpd_AntB		0xb98
+#define	rAPK				0xbd8
+
+/*  */
+/*  6. PageC(0xC00) */
+/*  */
+#define	rOFDM0_LSTF			0xc00
+
+#define	rOFDM0_TRxPathEnable		0xc04
+#define	rOFDM0_TRMuxPar			0xc08
+#define	rOFDM0_TRSWIsolation		0xc0c
+
+/* RxIQ DC offset, Rx digital filter, DC notch filter */
+#define	rOFDM0_XARxAFE			0xc10
+#define	rOFDM0_XARxIQImbalance		0xc14  /* RxIQ imblance matrix */
+#define	rOFDM0_XBRxAFE			0xc18
+#define	rOFDM0_XBRxIQImbalance		0xc1c
+#define	rOFDM0_XCRxAFE			0xc20
+#define	rOFDM0_XCRxIQImbalance		0xc24
+#define	rOFDM0_XDRxAFE			0xc28
+#define	rOFDM0_XDRxIQImbalance		0xc2c
+
+#define	rOFDM0_RxDetector1		0xc30  /*PD,BW & SBD DM tune init gain*/
+#define	rOFDM0_RxDetector2		0xc34  /* SBD & Fame Sync. */
+#define	rOFDM0_RxDetector3		0xc38  /* Frame Sync. */
+#define	rOFDM0_RxDetector4		0xc3c  /* PD, SBD, Frame Sync & Short-GI */
+
+#define	rOFDM0_RxDSP			0xc40  /* Rx Sync Path */
+#define	rOFDM0_CFOandDAGC		0xc44  /* CFO & DAGC */
+#define	rOFDM0_CCADropThreshold		0xc48 /* CCA Drop threshold */
+#define	rOFDM0_ECCAThreshold		0xc4c /*  energy CCA */
+
+#define	rOFDM0_XAAGCCore1		0xc50	/*  DIG */
+#define	rOFDM0_XAAGCCore2		0xc54
+#define	rOFDM0_XBAGCCore1		0xc58
+#define	rOFDM0_XBAGCCore2		0xc5c
+#define	rOFDM0_XCAGCCore1		0xc60
+#define	rOFDM0_XCAGCCore2		0xc64
+#define	rOFDM0_XDAGCCore1		0xc68
+#define	rOFDM0_XDAGCCore2		0xc6c
+
+#define	rOFDM0_AGCParameter1		0xc70
+#define	rOFDM0_AGCParameter2		0xc74
+#define	rOFDM0_AGCRSSITable		0xc78
+#define	rOFDM0_HTSTFAGC			0xc7c
+
+#define	rOFDM0_XATxIQImbalance		0xc80	/*  TX PWR TRACK and DIG */
+#define	rOFDM0_XATxAFE			0xc84
+#define	rOFDM0_XBTxIQImbalance		0xc88
+#define	rOFDM0_XBTxAFE			0xc8c
+#define	rOFDM0_XCTxIQImbalance		0xc90
+#define	rOFDM0_XCTxAFE			0xc94
+#define	rOFDM0_XDTxIQImbalance		0xc98
+#define	rOFDM0_XDTxAFE			0xc9c
+
+#define	rOFDM0_RxIQExtAnta		0xca0
+#define	rOFDM0_TxCoeff1			0xca4
+#define	rOFDM0_TxCoeff2			0xca8
+#define	rOFDM0_TxCoeff3			0xcac
+#define	rOFDM0_TxCoeff4			0xcb0
+#define	rOFDM0_TxCoeff5			0xcb4
+#define	rOFDM0_TxCoeff6			0xcb8
+#define	rOFDM0_RxHPParameter		0xce0
+#define	rOFDM0_TxPseudoNoiseWgt		0xce4
+#define	rOFDM0_FrameSync		0xcf0
+#define	rOFDM0_DFSReport		0xcf4
+
+
+/*  */
+/*  7. PageD(0xD00) */
+/*  */
+#define	rOFDM1_LSTF			0xd00
+#define	rOFDM1_TRxPathEnable		0xd04
+
+#define	rOFDM1_CFO			0xd08	/*  No setting now */
+#define	rOFDM1_CSI1			0xd10
+#define	rOFDM1_SBD			0xd14
+#define	rOFDM1_CSI2			0xd18
+#define	rOFDM1_CFOTracking		0xd2c
+#define	rOFDM1_TRxMesaure1		0xd34
+#define	rOFDM1_IntfDet			0xd3c
+#define	rOFDM1_PseudoNoiseStateAB	0xd50
+#define	rOFDM1_PseudoNoiseStateCD	0xd54
+#define	rOFDM1_RxPseudoNoiseWgt		0xd58
+
+#define	rOFDM_PHYCounter1		0xda0  /* cca, parity fail */
+#define	rOFDM_PHYCounter2		0xda4  /* rate illegal, crc8 fail */
+#define	rOFDM_PHYCounter3		0xda8  /* MCS not support */
+
+#define	rOFDM_ShortCFOAB		0xdac	/*  No setting now */
+#define	rOFDM_ShortCFOCD		0xdb0
+#define	rOFDM_LongCFOAB			0xdb4
+#define	rOFDM_LongCFOCD			0xdb8
+#define	rOFDM_TailCFOAB			0xdbc
+#define	rOFDM_TailCFOCD			0xdc0
+#define	rOFDM_PWMeasure1		0xdc4
+#define	rOFDM_PWMeasure2		0xdc8
+#define	rOFDM_BWReport			0xdcc
+#define	rOFDM_AGCReport			0xdd0
+#define	rOFDM_RxSNR			0xdd4
+#define	rOFDM_RxEVMCSI			0xdd8
+#define	rOFDM_SIGReport			0xddc
+
+
+/*  */
+/*  8. PageE(0xE00) */
+/*  */
+#define	rTxAGC_A_Rate18_06		0xe00
+#define	rTxAGC_A_Rate54_24		0xe04
+#define	rTxAGC_A_CCK1_Mcs32		0xe08
+#define	rTxAGC_A_Mcs03_Mcs00		0xe10
+#define	rTxAGC_A_Mcs07_Mcs04		0xe14
+#define	rTxAGC_A_Mcs11_Mcs08		0xe18
+#define	rTxAGC_A_Mcs15_Mcs12		0xe1c
+
+#define	rTxAGC_B_Rate18_06		0x830
+#define	rTxAGC_B_Rate54_24		0x834
+#define	rTxAGC_B_CCK1_55_Mcs32		0x838
+#define	rTxAGC_B_Mcs03_Mcs00		0x83c
+#define	rTxAGC_B_Mcs07_Mcs04		0x848
+#define	rTxAGC_B_Mcs11_Mcs08		0x84c
+#define	rTxAGC_B_Mcs15_Mcs12		0x868
+#define	rTxAGC_B_CCK11_A_CCK2_11	0x86c
+
+#define	rFPGA0_IQK			0xe28
+#define	rTx_IQK_Tone_A			0xe30
+#define	rRx_IQK_Tone_A			0xe34
+#define	rTx_IQK_PI_A			0xe38
+#define	rRx_IQK_PI_A			0xe3c
+
+#define	rTx_IQK				0xe40
+#define	rRx_IQK				0xe44
+#define	rIQK_AGC_Pts			0xe48
+#define	rIQK_AGC_Rsp			0xe4c
+#define	rTx_IQK_Tone_B			0xe50
+#define	rRx_IQK_Tone_B			0xe54
+#define	rTx_IQK_PI_B			0xe58
+#define	rRx_IQK_PI_B			0xe5c
+#define	rIQK_AGC_Cont			0xe60
+
+#define	rBlue_Tooth			0xe6c
+#define	rRx_Wait_CCA			0xe70
+#define	rTx_CCK_RFON			0xe74
+#define	rTx_CCK_BBON			0xe78
+#define	rTx_OFDM_RFON			0xe7c
+#define	rTx_OFDM_BBON			0xe80
+#define	rTx_To_Rx			0xe84
+#define	rTx_To_Tx			0xe88
+#define	rRx_CCK				0xe8c
+
+#define	rTx_Power_Before_IQK_A		0xe94
+#define	rTx_Power_After_IQK_A		0xe9c
+
+#define	rRx_Power_Before_IQK_A		0xea0
+#define	rRx_Power_Before_IQK_A_2	0xea4
+#define	rRx_Power_After_IQK_A		0xea8
+#define	rRx_Power_After_IQK_A_2		0xeac
+
+#define	rTx_Power_Before_IQK_B		0xeb4
+#define	rTx_Power_After_IQK_B		0xebc
+
+#define	rRx_Power_Before_IQK_B		0xec0
+#define	rRx_Power_Before_IQK_B_2	0xec4
+#define	rRx_Power_After_IQK_B		0xec8
+#define	rRx_Power_After_IQK_B_2		0xecc
+
+#define	rRx_OFDM			0xed0
+#define	rRx_Wait_RIFS			0xed4
+#define	rRx_TO_Rx			0xed8
+#define	rStandby			0xedc
+#define	rSleep				0xee0
+#define	rPMPD_ANAEN			0xeec
+
+/*  */
+/*  7. RF Register 0x00-0x2E (RF 8256) */
+/*     RF-0222D 0x00-3F */
+/*  */
+/* Zebra1 */
+#define	rZebra1_HSSIEnable		0x0	/*  Useless now */
+#define	rZebra1_TRxEnable1		0x1
+#define	rZebra1_TRxEnable2		0x2
+#define	rZebra1_AGC			0x4
+#define	rZebra1_ChargePump		0x5
+#define	rZebra1_Channel			0x7	/*  RF channel switch */
+
+/* endif */
+#define	rZebra1_TxGain			0x8	/*  Useless now */
+#define	rZebra1_TxLPF			0x9
+#define	rZebra1_RxLPF			0xb
+#define	rZebra1_RxHPFCorner		0xc
+
+/* Zebra4 */
+#define	rGlobalCtrl		0	/*  Useless now */
+#define	rRTL8256_TxLPF		19
+#define	rRTL8256_RxLPF		11
+
+/* RTL8258 */
+#define	rRTL8258_TxLPF		0x11	/*  Useless now */
+#define	rRTL8258_RxLPF		0x13
+#define	rRTL8258_RSSILPF	0xa
+
+/*  */
+/*  RL6052 Register definition */
+/*  */
+#define	RF_AC			0x00	/*  */
+
+#define	RF_IQADJ_G1		0x01	/*  */
+#define	RF_IQADJ_G2		0x02	/*  */
+
+#define	RF_POW_TRSW		0x05	/*  */
+
+#define	RF_GAIN_RX		0x06	/*  */
+#define	RF_GAIN_TX		0x07	/*  */
+
+#define	RF_TXM_IDAC		0x08	/*  */
+#define	RF_IPA_G		0x09	/*  */
+#define	RF_TXBIAS_G		0x0A
+#define	RF_TXPA_AG		0x0B
+#define	RF_IPA_A		0x0C	/*  */
+#define	RF_TXBIAS_A		0x0D
+#define	RF_BS_PA_APSET_G9_G11	0x0E
+#define	RF_BS_IQGEN		0x0F	/*  */
+
+#define	RF_MODE1		0x10	/*  */
+#define	RF_MODE2		0x11	/*  */
+
+#define	RF_RX_AGC_HP		0x12	/*  */
+#define	RF_TX_AGC		0x13	/*  */
+#define	RF_BIAS			0x14	/*  */
+#define	RF_IPA			0x15	/*  */
+#define	RF_TXBIAS		0x16
+#define	RF_POW_ABILITY		0x17	/*  */
+#define	RF_CHNLBW		0x18	/*  RF channel and BW switch */
+#define	RF_TOP			0x19	/*  */
+
+#define	RF_RX_G1		0x1A	/*  */
+#define	RF_RX_G2		0x1B	/*  */
+
+#define	RF_RX_BB2		0x1C	/*  */
+#define	RF_RX_BB1		0x1D	/*  */
+
+#define	RF_RCK1			0x1E	/*  */
+#define	RF_RCK2			0x1F	/*  */
+
+#define	RF_TX_G1		0x20	/*  */
+#define	RF_TX_G2		0x21	/*  */
+#define	RF_TX_G3		0x22	/*  */
+
+#define	RF_TX_BB1		0x23	/*  */
+
+#define	RF_T_METER_92D		0x42	/*  */
+#define	RF_T_METER_88E		0x42	/*  */
+#define	RF_T_METER		0x24	/*  */
+
+#define	RF_SYN_G1		0x25	/*  RF TX Power control */
+#define	RF_SYN_G2		0x26	/*  RF TX Power control */
+#define	RF_SYN_G3		0x27	/*  RF TX Power control */
+#define	RF_SYN_G4		0x28	/*  RF TX Power control */
+#define	RF_SYN_G5		0x29	/*  RF TX Power control */
+#define	RF_SYN_G6		0x2A	/*  RF TX Power control */
+#define	RF_SYN_G7		0x2B	/*  RF TX Power control */
+#define	RF_SYN_G8		0x2C	/*  RF TX Power control */
+
+#define	RF_RCK_OS		0x30	/*  RF TX PA control */
+#define	RF_TXPA_G1		0x31	/*  RF TX PA control */
+#define	RF_TXPA_G2		0x32	/*  RF TX PA control */
+#define	RF_TXPA_G3		0x33	/*  RF TX PA control */
+#define	RF_TX_BIAS_A		0x35
+#define	RF_TX_BIAS_D		0x36
+#define	RF_LOBF_9		0x38
+#define	RF_RXRF_A3		0x3C	/*  */
+#define	RF_TRSW			0x3F
+
+#define	RF_TXRF_A2		0x41
+#define	RF_TXPA_G4		0x46
+#define	RF_TXPA_A4		0x4B
+#define	RF_0x52			0x52
+#define	RF_WE_LUT		0xEF
+
+
+/*  */
+/* Bit Mask */
+/*  */
+/*  1. Page1(0x100) */
+#define	bBBResetB		0x100	/*  Useless now? */
+#define	bGlobalResetB		0x200
+#define	bOFDMTxStart		0x4
+#define	bCCKTxStart		0x8
+#define	bCRC32Debug		0x100
+#define	bPMACLoopback		0x10
+#define	bTxLSIG			0xffffff
+#define	bOFDMTxRate		0xf
+#define	bOFDMTxReserved		0x10
+#define	bOFDMTxLength		0x1ffe0
+#define	bOFDMTxParity		0x20000
+#define	bTxHTSIG1		0xffffff
+#define	bTxHTMCSRate		0x7f
+#define	bTxHTBW			0x80
+#define	bTxHTLength		0xffff00
+#define	bTxHTSIG2		0xffffff
+#define	bTxHTSmoothing		0x1
+#define	bTxHTSounding		0x2
+#define	bTxHTReserved		0x4
+#define	bTxHTAggreation		0x8
+#define	bTxHTSTBC		0x30
+#define	bTxHTAdvanceCoding	0x40
+#define	bTxHTShortGI		0x80
+#define	bTxHTNumberHT_LTF	0x300
+#define	bTxHTCRC8		0x3fc00
+#define	bCounterReset		0x10000
+#define	bNumOfOFDMTx		0xffff
+#define	bNumOfCCKTx		0xffff0000
+#define	bTxIdleInterval		0xffff
+#define	bOFDMService		0xffff0000
+#define	bTxMACHeader		0xffffffff
+#define	bTxDataInit		0xff
+#define	bTxHTMode		0x100
+#define	bTxDataType		0x30000
+#define	bTxRandomSeed		0xffffffff
+#define	bCCKTxPreamble		0x1
+#define	bCCKTxSFD		0xffff0000
+#define	bCCKTxSIG		0xff
+#define	bCCKTxService		0xff00
+#define	bCCKLengthExt		0x8000
+#define	bCCKTxLength		0xffff0000
+#define	bCCKTxCRC16		0xffff
+#define	bCCKTxStatus		0x1
+#define	bOFDMTxStatus		0x2
+
+#define	IS_BB_REG_OFFSET_92S(_Offset)			\
+	((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+/*  2. Page8(0x800) */
+#define	bRFMOD			0x1	/*  Reg 0x800 rFPGA0_RFMOD */
+#define	bJapanMode		0x2
+#define	bCCKTxSC		0x30
+#define	bCCKEn			0x1000000
+#define	bOFDMEn			0x2000000
+
+#define	bOFDMRxADCPhase		0x10000	/*  Useless now */
+#define	bOFDMTxDACPhase		0x40000
+#define	bXATxAGC		0x3f
+
+#define	bAntennaSelect		0x0300
+
+#define	bXBTxAGC		0xf00	/*  Reg 80c rFPGA0_TxGainStage */
+#define	bXCTxAGC		0xf000
+#define	bXDTxAGC		0xf0000
+
+#define	bPAStart		0xf0000000	/*  Useless now */
+#define	bTRStart		0x00f00000
+#define	bRFStart		0x0000f000
+#define	bBBStart		0x000000f0
+#define	bBBCCKStart		0x0000000f
+#define	bPAEnd			0xf          /* Reg0x814 */
+#define	bTREnd			0x0f000000
+#define	bRFEnd			0x000f0000
+#define	bCCAMask		0x000000f0   /* T2R */
+#define	bR2RCCAMask		0x00000f00
+#define	bHSSI_R2TDelay		0xf8000000
+#define	bHSSI_T2RDelay		0xf80000
+#define	bContTxHSSI		0x400     /* change gain at continue Tx */
+#define	bIGFromCCK		0x200
+#define	bAGCAddress		0x3f
+#define	bRxHPTx			0x7000
+#define	bRxHPT2R		0x38000
+#define	bRxHPCCKIni		0xc0000
+#define	bAGCTxCode		0xc00000
+#define	bAGCRxCode		0x300000
+
+/* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */
+#define	b3WireDataLength	0x800
+#define	b3WireAddressLength	0x400
+
+#define	b3WireRFPowerDown	0x1	/*  Useless now */
+#define	b5GPAPEPolarity		0x40000000
+#define	b2GPAPEPolarity		0x80000000
+#define	bRFSW_TxDefaultAnt	0x3
+#define	bRFSW_TxOptionAnt	0x30
+#define	bRFSW_RxDefaultAnt	0x300
+#define	bRFSW_RxOptionAnt	0x3000
+#define	bRFSI_3WireData		0x1
+#define	bRFSI_3WireClock	0x2
+#define	bRFSI_3WireLoad		0x4
+#define	bRFSI_3WireRW		0x8
+#define	bRFSI_3Wire		0xf
+
+#define	bRFSI_RFENV		0x10	/* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */
+
+#define	bRFSI_TRSW		0x20	/*  Useless now */
+#define	bRFSI_TRSWB		0x40
+#define	bRFSI_ANTSW		0x100
+#define	bRFSI_ANTSWB		0x200
+#define	bRFSI_PAPE		0x400
+#define	bRFSI_PAPE5G		0x800
+#define	bBandSelect		0x1
+#define	bHTSIG2_GI		0x80
+#define	bHTSIG2_Smoothing	0x01
+#define	bHTSIG2_Sounding	0x02
+#define	bHTSIG2_Aggreaton	0x08
+#define	bHTSIG2_STBC		0x30
+#define	bHTSIG2_AdvCoding	0x40
+#define	bHTSIG2_NumOfHTLTF	0x300
+#define	bHTSIG2_CRC8		0x3fc
+#define	bHTSIG1_MCS		0x7f
+#define	bHTSIG1_BandWidth	0x80
+#define	bHTSIG1_HTLength	0xffff
+#define	bLSIG_Rate		0xf
+#define	bLSIG_Reserved		0x10
+#define	bLSIG_Length		0x1fffe
+#define	bLSIG_Parity		0x20
+#define	bCCKRxPhase		0x4
+
+#define	bLSSIReadAddress	0x7f800000   /*  T65 RF */
+
+#define	bLSSIReadEdge		0x80000000   /* LSSI "Read" edge signal */
+
+#define	bLSSIReadBackData	0xfffff		/*  T65 RF */
+
+#define	bLSSIReadOKFlag		0x1000	/*  Useless now */
+#define	bCCKSampleRate		0x8       /* 0: 44MHz, 1:88MHz */
+#define	bRegulator0Standby	0x1
+#define	bRegulatorPLLStandby	0x2
+#define	bRegulator1Standby	0x4
+#define	bPLLPowerUp		0x8
+#define	bDPLLPowerUp		0x10
+#define	bDA10PowerUp		0x20
+#define	bAD7PowerUp		0x200
+#define	bDA6PowerUp		0x2000
+#define	bXtalPowerUp		0x4000
+#define	b40MDClkPowerUP		0x8000
+#define	bDA6DebugMode		0x20000
+#define	bDA6Swing		0x380000
+
+/*  Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */
+#define	bADClkPhase		0x4000000
+
+#define	b80MClkDelay		0x18000000	/*  Useless */
+#define	bAFEWatchDogEnable	0x20000000
+
+/*  Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */
+#define	bXtalCap01		0xc0000000
+#define	bXtalCap23		0x3
+#define	bXtalCap92x		0x0f000000
+#define	bXtalCap		0x0f000000
+
+#define	bIntDifClkEnable	0x400	/*  Useless */
+#define	bExtSigClkEnable	0x800
+#define	bBandgapMbiasPowerUp	0x10000
+#define	bAD11SHGain		0xc0000
+#define	bAD11InputRange		0x700000
+#define	bAD11OPCurrent		0x3800000
+#define	bIPathLoopback		0x4000000
+#define	bQPathLoopback		0x8000000
+#define	bAFELoopback		0x10000000
+#define	bDA10Swing		0x7e0
+#define	bDA10Reverse		0x800
+#define	bDAClkSource		0x1000
+#define	bAD7InputRange		0x6000
+#define	bAD7Gain		0x38000
+#define	bAD7OutputCMMode	0x40000
+#define	bAD7InputCMMode		0x380000
+#define	bAD7Current		0xc00000
+#define	bRegulatorAdjust	0x7000000
+#define	bAD11PowerUpAtTx	0x1
+#define	bDA10PSAtTx		0x10
+#define	bAD11PowerUpAtRx	0x100
+#define	bDA10PSAtRx		0x1000
+#define	bCCKRxAGCFormat		0x200
+#define	bPSDFFTSamplepPoint	0xc000
+#define	bPSDAverageNum		0x3000
+#define	bIQPathControl		0xc00
+#define	bPSDFreq		0x3ff
+#define	bPSDAntennaPath		0x30
+#define	bPSDIQSwitch		0x40
+#define	bPSDRxTrigger		0x400000
+#define	bPSDTxTrigger		0x80000000
+#define	bPSDSineToneScale	0x7f000000
+#define	bPSDReport		0xffff
+
+/*  3. Page9(0x900) */
+#define	bOFDMTxSC		0x30000000	/*  Useless */
+#define	bCCKTxOn		0x1
+#define	bOFDMTxOn		0x2
+#define	bDebugPage		0xfff  /* reset debug page and HWord, LWord */
+#define	bDebugItem		0xff   /* reset debug page and LWord */
+#define	bAntL			0x10
+#define	bAntNonHT		0x100
+#define	bAntHT1			0x1000
+#define	bAntHT2			0x10000
+#define	bAntHT1S1		0x100000
+#define	bAntNonHTS1		0x1000000
+
+/*  4. PageA(0xA00) */
+#define	bCCKBBMode		0x3	/*  Useless */
+#define	bCCKTxPowerSaving	0x80
+#define	bCCKRxPowerSaving	0x40
+
+#define	bCCKSideBand		0x10	/*  Reg 0xa00 rCCK0_System 20/40 */
+
+#define	bCCKScramble		0x8	/*  Useless */
+#define	bCCKAntDiversity	0x8000
+#define	bCCKCarrierRecovery	0x4000
+#define	bCCKTxRate		0x3000
+#define	bCCKDCCancel		0x0800
+#define	bCCKISICancel		0x0400
+#define	bCCKMatchFilter		0x0200
+#define	bCCKEqualizer		0x0100
+#define	bCCKPreambleDetect	0x800000
+#define	bCCKFastFalseCCA	0x400000
+#define	bCCKChEstStart		0x300000
+#define	bCCKCCACount		0x080000
+#define	bCCKcs_lim		0x070000
+#define	bCCKBistMode		0x80000000
+#define	bCCKCCAMask		0x40000000
+#define	bCCKTxDACPhase		0x4
+#define	bCCKRxADCPhase		0x20000000   /* r_rx_clk */
+#define	bCCKr_cp_mode0		0x0100
+#define	bCCKTxDCOffset		0xf0
+#define	bCCKRxDCOffset		0xf
+#define	bCCKCCAMode		0xc000
+#define	bCCKFalseCS_lim		0x3f00
+#define	bCCKCS_ratio		0xc00000
+#define	bCCKCorgBit_sel		0x300000
+#define	bCCKPD_lim		0x0f0000
+#define	bCCKNewCCA		0x80000000
+#define	bCCKRxHPofIG		0x8000
+#define	bCCKRxIG		0x7f00
+#define	bCCKLNAPolarity		0x800000
+#define	bCCKRx1stGain		0x7f0000
+#define	bCCKRFExtend		0x20000000 /* CCK Rx Iinital gain polarity */
+#define	bCCKRxAGCSatLevel	0x1f000000
+#define	bCCKRxAGCSatCount	0xe0
+#define	bCCKRxRFSettle		0x1f       /* AGCsamp_dly */
+#define	bCCKFixedRxAGC		0x8000
+#define	bCCKAntennaPolarity	0x2000
+#define	bCCKTxFilterType	0x0c00
+#define	bCCKRxAGCReportType	0x0300
+#define	bCCKRxDAGCEn		0x80000000
+#define	bCCKRxDAGCPeriod	0x20000000
+#define	bCCKRxDAGCSatLevel	0x1f000000
+#define	bCCKTimingRecovery	0x800000
+#define	bCCKTxC0		0x3f0000
+#define	bCCKTxC1		0x3f000000
+#define	bCCKTxC2		0x3f
+#define	bCCKTxC3		0x3f00
+#define	bCCKTxC4		0x3f0000
+#define	bCCKTxC5		0x3f000000
+#define	bCCKTxC6		0x3f
+#define	bCCKTxC7		0x3f00
+#define	bCCKDebugPort		0xff0000
+#define	bCCKDACDebug		0x0f000000
+#define	bCCKFalseAlarmEnable	0x8000
+#define	bCCKFalseAlarmRead	0x4000
+#define	bCCKTRSSI		0x7f
+#define	bCCKRxAGCReport		0xfe
+#define	bCCKRxReport_AntSel	0x80000000
+#define	bCCKRxReport_MFOff	0x40000000
+#define	bCCKRxRxReport_SQLoss	0x20000000
+#define	bCCKRxReport_Pktloss	0x10000000
+#define	bCCKRxReport_Lockedbit	0x08000000
+#define	bCCKRxReport_RateError	0x04000000
+#define	bCCKRxReport_RxRate	0x03000000
+#define	bCCKRxFACounterLower	0xff
+#define	bCCKRxFACounterUpper	0xff000000
+#define	bCCKRxHPAGCStart	0xe000
+#define	bCCKRxHPAGCFinal	0x1c00
+#define	bCCKRxFalseAlarmEnable	0x8000
+#define	bCCKFACounterFreeze	0x4000
+#define	bCCKTxPathSel		0x10000000
+#define	bCCKDefaultRxPath	0xc000000
+#define	bCCKOptionRxPath	0x3000000
+
+/*  5. PageC(0xC00) */
+#define	bNumOfSTF		0x3	/*  Useless */
+#define	bShift_L		0xc0
+#define	bGI_TH			0xc
+#define	bRxPathA		0x1
+#define	bRxPathB		0x2
+#define	bRxPathC		0x4
+#define	bRxPathD		0x8
+#define	bTxPathA		0x1
+#define	bTxPathB		0x2
+#define	bTxPathC		0x4
+#define	bTxPathD		0x8
+#define	bTRSSIFreq		0x200
+#define	bADCBackoff		0x3000
+#define	bDFIRBackoff		0xc000
+#define	bTRSSILatchPhase	0x10000
+#define	bRxIDCOffset		0xff
+#define	bRxQDCOffset		0xff00
+#define	bRxDFIRMode		0x1800000
+#define	bRxDCNFType		0xe000000
+#define	bRXIQImb_A		0x3ff
+#define	bRXIQImb_B		0xfc00
+#define	bRXIQImb_C		0x3f0000
+#define	bRXIQImb_D		0xffc00000
+#define	bDC_dc_Notch		0x60000
+#define	bRxNBINotch		0x1f000000
+#define	bPD_TH			0xf
+#define	bPD_TH_Opt2		0xc000
+#define	bPWED_TH		0x700
+#define	bIfMF_Win_L		0x800
+#define	bPD_Option		0x1000
+#define	bMF_Win_L		0xe000
+#define	bBW_Search_L		0x30000
+#define	bwin_enh_L		0xc0000
+#define	bBW_TH			0x700000
+#define	bED_TH2			0x3800000
+#define	bBW_option		0x4000000
+#define	bRatio_TH		0x18000000
+#define	bWindow_L		0xe0000000
+#define	bSBD_Option		0x1
+#define	bFrame_TH		0x1c
+#define	bFS_Option		0x60
+#define	bDC_Slope_check		0x80
+#define	bFGuard_Counter_DC_L	0xe00
+#define	bFrame_Weight_Short	0x7000
+#define	bSub_Tune		0xe00000
+#define	bFrame_DC_Length	0xe000000
+#define	bSBD_start_offset	0x30000000
+#define	bFrame_TH_2		0x7
+#define	bFrame_GI2_TH		0x38
+#define	bGI2_Sync_en		0x40
+#define	bSarch_Short_Early	0x300
+#define	bSarch_Short_Late	0xc00
+#define	bSarch_GI2_Late		0x70000
+#define	bCFOAntSum		0x1
+#define	bCFOAcc			0x2
+#define	bCFOStartOffset		0xc
+#define	bCFOLookBack		0x70
+#define	bCFOSumWeight		0x80
+#define	bDAGCEnable		0x10000
+#define	bTXIQImb_A		0x3ff
+#define	bTXIQImb_B		0xfc00
+#define	bTXIQImb_C		0x3f0000
+#define	bTXIQImb_D		0xffc00000
+#define	bTxIDCOffset		0xff
+#define	bTxQDCOffset		0xff00
+#define	bTxDFIRMode		0x10000
+#define	bTxPesudoNoiseOn	0x4000000
+#define	bTxPesudoNoise_A	0xff
+#define	bTxPesudoNoise_B	0xff00
+#define	bTxPesudoNoise_C	0xff0000
+#define	bTxPesudoNoise_D	0xff000000
+#define	bCCADropOption		0x20000
+#define	bCCADropThres		0xfff00000
+#define	bEDCCA_H		0xf
+#define	bEDCCA_L		0xf0
+#define	bLambda_ED		0x300
+#define	bRxInitialGain		0x7f
+#define	bRxAntDivEn		0x80
+#define	bRxAGCAddressForLNA	0x7f00
+#define	bRxHighPowerFlow	0x8000
+#define	bRxAGCFreezeThres	0xc0000
+#define	bRxFreezeStep_AGC1	0x300000
+#define	bRxFreezeStep_AGC2	0xc00000
+#define	bRxFreezeStep_AGC3	0x3000000
+#define	bRxFreezeStep_AGC0	0xc000000
+#define	bRxRssi_Cmp_En		0x10000000
+#define	bRxQuickAGCEn		0x20000000
+#define	bRxAGCFreezeThresMode	0x40000000
+#define	bRxOverFlowCheckType	0x80000000
+#define	bRxAGCShift		0x7f
+#define	bTRSW_Tri_Only		0x80
+#define	bPowerThres		0x300
+#define	bRxAGCEn		0x1
+#define	bRxAGCTogetherEn	0x2
+#define	bRxAGCMin		0x4
+#define	bRxHP_Ini		0x7
+#define	bRxHP_TRLNA		0x70
+#define	bRxHP_RSSI		0x700
+#define	bRxHP_BBP1		0x7000
+#define	bRxHP_BBP2		0x70000
+#define	bRxHP_BBP3		0x700000
+#define	bRSSI_H			0x7f0000     /* threshold for high power */
+#define	bRSSI_Gen		0x7f000000   /* threshold for ant diversity */
+#define	bRxSettle_TRSW		0x7
+#define	bRxSettle_LNA		0x38
+#define	bRxSettle_RSSI		0x1c0
+#define	bRxSettle_BBP		0xe00
+#define	bRxSettle_RxHP		0x7000
+#define	bRxSettle_AntSW_RSSI	0x38000
+#define	bRxSettle_AntSW		0xc0000
+#define	bRxProcessTime_DAGC	0x300000
+#define	bRxSettle_HSSI		0x400000
+#define	bRxProcessTime_BBPPW	0x800000
+#define	bRxAntennaPowerShift	0x3000000
+#define	bRSSITableSelect	0xc000000
+#define	bRxHP_Final		0x7000000
+#define	bRxHTSettle_BBP		0x7
+#define	bRxHTSettle_HSSI	0x8
+#define	bRxHTSettle_RxHP	0x70
+#define	bRxHTSettle_BBPPW	0x80
+#define	bRxHTSettle_Idle	0x300
+#define	bRxHTSettle_Reserved	0x1c00
+#define	bRxHTRxHPEn		0x8000
+#define	bRxHTAGCFreezeThres	0x30000
+#define	bRxHTAGCTogetherEn	0x40000
+#define	bRxHTAGCMin		0x80000
+#define	bRxHTAGCEn		0x100000
+#define	bRxHTDAGCEn		0x200000
+#define	bRxHTRxHP_BBP		0x1c00000
+#define	bRxHTRxHP_Final		0xe0000000
+#define	bRxPWRatioTH		0x3
+#define	bRxPWRatioEn		0x4
+#define	bRxMFHold		0x3800
+#define	bRxPD_Delay_TH1		0x38
+#define	bRxPD_Delay_TH2		0x1c0
+#define	bRxPD_DC_COUNT_MAX	0x600
+#define	bRxPD_Delay_TH		0x8000
+#define	bRxProcess_Delay	0xf0000
+#define	bRxSearchrange_GI2_Early	0x700000
+#define	bRxFrame_Guard_Counter_L	0x3800000
+#define	bRxSGI_Guard_L		0xc000000
+#define	bRxSGI_Search_L		0x30000000
+#define	bRxSGI_TH		0xc0000000
+#define	bDFSCnt0		0xff
+#define	bDFSCnt1		0xff00
+#define	bDFSFlag		0xf0000
+#define	bMFWeightSum		0x300000
+#define	bMinIdxTH		0x7f000000
+#define	bDAFormat		0x40000
+#define	bTxChEmuEnable		0x01000000
+#define	bTRSWIsolation_A	0x7f
+#define	bTRSWIsolation_B	0x7f00
+#define	bTRSWIsolation_C	0x7f0000
+#define	bTRSWIsolation_D	0x7f000000
+#define	bExtLNAGain		0x7c00
+
+/*  6. PageE(0xE00) */
+#define	bSTBCEn			0x4	/*  Useless */
+#define	bAntennaMapping		0x10
+#define	bNss			0x20
+#define	bCFOAntSumD		0x200
+#define	bPHYCounterReset	0x8000000
+#define	bCFOReportGet		0x4000000
+#define	bOFDMContinueTx		0x10000000
+#define	bOFDMSingleCarrier	0x20000000
+#define	bOFDMSingleTone		0x40000000
+#define	bHTDetect		0x100
+#define	bCFOEn			0x10000
+#define	bCFOValue		0xfff00000
+#define	bSigTone_Re		0x3f
+#define	bSigTone_Im		0x7f00
+#define	bCounter_CCA		0xffff
+#define	bCounter_ParityFail	0xffff0000
+#define	bCounter_RateIllegal	0xffff
+#define	bCounter_CRC8Fail	0xffff0000
+#define	bCounter_MCSNoSupport	0xffff
+#define	bCounter_FastSync	0xffff
+#define	bShortCFO		0xfff
+#define	bShortCFOTLength	12   /* total */
+#define	bShortCFOFLength	11   /* fraction */
+#define	bLongCFO		0x7ff
+#define	bLongCFOTLength		11
+#define	bLongCFOFLength		11
+#define	bTailCFO		0x1fff
+#define	bTailCFOTLength		13
+#define	bTailCFOFLength		12
+#define	bmax_en_pwdB		0xffff
+#define	bCC_power_dB		0xffff0000
+#define	bnoise_pwdB		0xffff
+#define	bPowerMeasTLength	10
+#define	bPowerMeasFLength	3
+#define	bRx_HT_BW		0x1
+#define	bRxSC			0x6
+#define	bRx_HT			0x8
+#define	bNB_intf_det_on		0x1
+#define	bIntf_win_len_cfg	0x30
+#define	bNB_Intf_TH_cfg		0x1c0
+#define	bRFGain			0x3f
+#define	bTableSel		0x40
+#define	bTRSW			0x80
+#define	bRxSNR_A		0xff
+#define	bRxSNR_B		0xff00
+#define	bRxSNR_C		0xff0000
+#define	bRxSNR_D		0xff000000
+#define	bSNREVMTLength		8
+#define	bSNREVMFLength		1
+#define	bCSI1st			0xff
+#define	bCSI2nd			0xff00
+#define	bRxEVM1st		0xff0000
+#define	bRxEVM2nd		0xff000000
+#define	bSIGEVM			0xff
+#define	bPWDB			0xff00
+#define	bSGIEN			0x10000
+
+#define	bSFactorQAM1		0xf	/*  Useless */
+#define	bSFactorQAM2		0xf0
+#define	bSFactorQAM3		0xf00
+#define	bSFactorQAM4		0xf000
+#define	bSFactorQAM5		0xf0000
+#define	bSFactorQAM6		0xf0000
+#define	bSFactorQAM7		0xf00000
+#define	bSFactorQAM8		0xf000000
+#define	bSFactorQAM9		0xf0000000
+#define	bCSIScheme		0x100000
+
+#define	bNoiseLvlTopSet		0x3	/*  Useless */
+#define	bChSmooth		0x4
+#define	bChSmoothCfg1		0x38
+#define	bChSmoothCfg2		0x1c0
+#define	bChSmoothCfg3		0xe00
+#define	bChSmoothCfg4		0x7000
+#define	bMRCMode		0x800000
+#define	bTHEVMCfg		0x7000000
+
+#define	bLoopFitType		0x1	/*  Useless */
+#define	bUpdCFO			0x40
+#define	bUpdCFOOffData		0x80
+#define	bAdvUpdCFO		0x100
+#define	bAdvTimeCtrl		0x800
+#define	bUpdClko		0x1000
+#define	bFC			0x6000
+#define	bTrackingMode		0x8000
+#define	bPhCmpEnable		0x10000
+#define	bUpdClkoLTF		0x20000
+#define	bComChCFO		0x40000
+#define	bCSIEstiMode		0x80000
+#define	bAdvUpdEqz		0x100000
+#define	bUChCfg			0x7000000
+#define	bUpdEqz			0x8000000
+
+/* Rx Pseduo noise */
+#define	bRxPesudoNoiseOn	0x20000000	/*  Useless */
+#define	bRxPesudoNoise_A	0xff
+#define	bRxPesudoNoise_B	0xff00
+#define	bRxPesudoNoise_C	0xff0000
+#define	bRxPesudoNoise_D	0xff000000
+#define	bPesudoNoiseState_A	0xffff
+#define	bPesudoNoiseState_B	0xffff0000
+#define	bPesudoNoiseState_C	0xffff
+#define	bPesudoNoiseState_D	0xffff0000
+
+/* 7. RF Register */
+/* Zebra1 */
+#define	bZebra1_HSSIEnable	0x8		/*  Useless */
+#define	bZebra1_TRxControl	0xc00
+#define	bZebra1_TRxGainSetting	0x07f
+#define	bZebra1_RxCorner	0xc00
+#define	bZebra1_TxChargePump	0x38
+#define	bZebra1_RxChargePump	0x7
+#define	bZebra1_ChannelNum	0xf80
+#define	bZebra1_TxLPFBW		0x400
+#define	bZebra1_RxLPFBW		0x600
+
+/* Zebra4 */
+#define	bRTL8256RegModeCtrl1	0x100	/*  Useless */
+#define	bRTL8256RegModeCtrl0	0x40
+#define	bRTL8256_TxLPFBW	0x18
+#define	bRTL8256_RxLPFBW	0x600
+
+/* RTL8258 */
+#define	bRTL8258_TxLPFBW	0xc	/*  Useless */
+#define	bRTL8258_RxLPFBW	0xc00
+#define	bRTL8258_RSSILPFBW	0xc0
+
+
+/*  */
+/*  Other Definition */
+/*  */
+
+/* byte endable for sb_write */
+#define	bByte0			0x1	/*  Useless */
+#define	bByte1			0x2
+#define	bByte2			0x4
+#define	bByte3			0x8
+#define	bWord0			0x3
+#define	bWord1			0xc
+#define	bDWord			0xf
+
+/* for PutRegsetting & GetRegSetting BitMask */
+#define	bMaskByte0		0xff	/*  Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */
+#define	bMaskByte1		0xff00
+#define	bMaskByte2		0xff0000
+#define	bMaskByte3		0xff000000
+#define	bMaskHWord		0xffff0000
+#define	bMaskLWord		0x0000ffff
+#define	bMaskDWord		0xffffffff
+#define	bMask12Bits		0xfff
+#define	bMaskH4Bits		0xf0000000
+#define	bMaskOFDM_D		0xffc00000
+#define	bMaskCCK		0x3f3f3f3f
+
+/* for PutRFRegsetting & GetRFRegSetting BitMask */
+#define	bRFRegOffsetMask	0xfffff
+
+#define	bEnable                 0x1	/*  Useless */
+#define	bDisable                0x0
+
+#define	LeftAntenna		0x0	/*  Useless */
+#define	RightAntenna		0x1
+
+#define	tCheckTxStatus		500   /* 500ms Useless */
+#define	tUpdateRxCounter	100   /* 100ms */
+
+#define	rateCCK			0	/*  Useless */
+#define	rateOFDM		1
+#define	rateHT			2
+
+/* define Register-End */
+#define	bPMAC_End		0x1ff	/*  Useless */
+#define	bFPGAPHY0_End		0x8ff
+#define	bFPGAPHY1_End		0x9ff
+#define	bCCKPHY0_End		0xaff
+#define	bOFDMPHY0_End		0xcff
+#define	bOFDMPHY1_End		0xdff
+
+#define	bPMACControl		0x0	/*  Useless */
+#define	bWMACControl		0x1
+#define	bWNICControl		0x2
+
+#define	PathA			0x0	/*  Useless */
+#define	PathB			0x1
+#define	PathC			0x2
+#define	PathD			0x3
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h b/drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h
new file mode 100644
index 0000000..20d0b3e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EPwrSeq.h
@@ -0,0 +1,176 @@
+
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __HAL8188EPWRSEQ_H__
+#define __HAL8188EPWRSEQ_H__
+
+#include "HalPwrSeqCmd.h"
+
+/*
+	Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
+	There are 6 HW Power States:
+	0: POFF--Power Off
+	1: PDN--Power Down
+	2: CARDEMU--Card Emulation
+	3: ACT--Active Mode
+	4: LPS--Low Power State
+	5: SUS--Suspend
+
+	The transision from different states are defined below
+	TRANS_CARDEMU_TO_ACT
+	TRANS_ACT_TO_CARDEMU
+	TRANS_CARDEMU_TO_SUS
+	TRANS_SUS_TO_CARDEMU
+	TRANS_CARDEMU_TO_PDN
+	TRANS_ACT_TO_LPS
+	TRANS_LPS_TO_ACT
+
+	TRANS_END
+
+    PWR SEQ Version: rtl8188E_PwrSeq_V09.h
+*/
+#define	RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS	10
+#define	RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS	10
+#define	RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS	10
+#define	RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS	10
+#define	RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS	10
+#define	RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS	10
+#define	RTL8188E_TRANS_ACT_TO_LPS_STEPS		15
+#define	RTL8188E_TRANS_LPS_TO_ACT_STEPS		15
+#define	RTL8188E_TRANS_END_STEPS		1
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_ACT														\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/								\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1    power ready*/	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0|BIT1, 0}, /* 0x02[1:0] = 0	reset BB*/			\
+	{0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7}, /*0x24[23] = 2b'01 schmit trigger */	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0}, /* 0x04[15] = 0 disable HWPDN (control by DRV)*/\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4|BIT3, 0}, /*0x04[12:11] = 2b'00 disable WL suspend*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x04[8] = 1 polling until return 0*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0}, /*wait till 0x04[8] = 0*/	\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*LDO normal mode*/	\
+	{0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*SDIO Driving*/	\
+
+#define RTL8188E_TRANS_ACT_TO_CARDEMU													\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/								\
+	{0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/	\
+	{0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*LDO Sleep mode*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/	\
+
+#define RTL8188E_TRANS_CARDEMU_TO_SUS													\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/				\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01enable WL suspend*/	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11enable WL suspend for PCIe*/	\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT7}, /*  0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */	\
+	{0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */	\
+	{0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*Set USB suspend enable local register  0xfe10[4]=1 */	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/
+
+#define RTL8188E_TRANS_SUS_TO_CARDEMU													\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/							\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
+
+#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS													\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },  comments here*/							\
+	{0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7}, /*0x24[23] = 2b'01 schmit trigger */	\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/	\
+	{0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*  0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */	\
+	{0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */	\
+	{0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*Set USB suspend enable local register  0xfe10[4]=1 */	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/
+
+#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU													\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/								\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/	\
+	{0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
+
+#define RTL8188E_TRANS_CARDEMU_TO_PDN												\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/							\
+	{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/
+
+#define RTL8188E_TRANS_PDN_TO_CARDEMU												\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },  comments here					 */ \
+	{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/
+
+/* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */
+#define RTL8188E_TRANS_ACT_TO_LPS														\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here				*/   \
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/	\
+	{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/	\
+	{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/	\
+	{0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/	\
+	{0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled,and clock are gated*/	\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/	\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/	\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/	\
+	{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/	\
+
+
+#define RTL8188E_TRANS_LPS_TO_ACT															\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here				 */ \
+	{0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\
+	{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\
+	{0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\
+	{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*.	0x08[4] = 0		 switch TSF to 40M*/\
+	{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]=0  TSF in 40M*/\
+	{0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0}, /*.	0x29[7:6] = 2b'00	 enable BB clock*/\
+	{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*.	0x101[1] = 1*/\
+	{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*.	0x100[7:0] = 0xFF	 enable WMAC TRX*/\
+	{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*.	0x02[1:0] = 2b'11	 enable BB macro*/\
+	{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*.	0x522 = 0*/
+
+#define RTL8188E_TRANS_END															\
+	/* format */																\
+	/* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },  comments here*/					\
+	{0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,0, PWR_CMD_END, 0, 0}, /*  */
+
+
+extern struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS+RTL8188E_TRANS_END_STEPS];
+extern struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS];
+
+#endif /* __HAL8188EPWRSEQ_H__ */
diff --git a/drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h b/drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h
new file mode 100644
index 0000000..21996a1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188ERateAdaptive.h
@@ -0,0 +1,75 @@
+#ifndef __INC_RA_H
+#define __INC_RA_H
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+	RateAdaptive.h
+
+Abstract:
+	Prototype of RA and related data structure.
+
+Major Change History:
+	When       Who               What
+	---------- ---------------   -------------------------------
+	2011-08-12 Page            Create.
+--*/
+
+/*  Rate adaptive define */
+#define	PERENTRY	23
+#define	RETRYSIZE	5
+#define	RATESIZE	28
+#define	TX_RPT2_ITEM_SIZE	8
+
+/*  */
+/*  TX report 2 format in Rx desc */
+/*  */
+#define GET_TX_RPT2_DESC_PKT_LEN_88E(__pRxStatusDesc)		\
+	LE_BITS_TO_4BYTE(__pRxStatusDesc, 0, 9)
+#define GET_TX_RPT2_DESC_MACID_VALID_1_88E(__pRxStatusDesc)	\
+	LE_BITS_TO_4BYTE(__pRxStatusDesc+16, 0, 32)
+#define GET_TX_RPT2_DESC_MACID_VALID_2_88E(__pRxStatusDesc)	\
+	LE_BITS_TO_4BYTE(__pRxStatusDesc+20, 0, 32)
+
+#define GET_TX_REPORT_TYPE1_RERTY_0(__pAddr)			\
+	LE_BITS_TO_4BYTE(__pAddr, 0, 16)
+#define GET_TX_REPORT_TYPE1_RERTY_1(__pAddr)			\
+	LE_BITS_TO_1BYTE(__pAddr+2, 0, 8)
+#define GET_TX_REPORT_TYPE1_RERTY_2(__pAddr)			\
+	LE_BITS_TO_1BYTE(__pAddr+3, 0, 8)
+#define GET_TX_REPORT_TYPE1_RERTY_3(__pAddr)			\
+	LE_BITS_TO_1BYTE(__pAddr+4, 0, 8)
+#define GET_TX_REPORT_TYPE1_RERTY_4(__pAddr)			\
+	LE_BITS_TO_1BYTE(__pAddr+4+1, 0, 8)
+#define GET_TX_REPORT_TYPE1_DROP_0(__pAddr)			\
+	LE_BITS_TO_1BYTE(__pAddr+4+2, 0, 8)
+#define GET_TX_REPORT_TYPE1_DROP_1(__pAddr)			\
+	LE_BITS_TO_1BYTE(__pAddr+4+3, 0, 8)
+
+/*  End rate adaptive define */
+
+void ODM_RASupport_Init(struct odm_dm_struct *dm_odm);
+
+int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm);
+
+int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 MacID);
+
+u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 MacID);
+
+u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 MacID);
+
+u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 MacID);
+void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 MacID,
+				 u8 RateID, u32 RateMask,
+				 u8 SGIEnable);
+
+void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid,
+			  u8 rssi);
+
+void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm,
+			       u8 *txrpt_buf, u16 txrpt_len,
+			       u32 validentry0, u32 validentry1);
+
+void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/Hal8188EReg.h b/drivers/staging/rtl8188eu/include/Hal8188EReg.h
new file mode 100644
index 0000000..d880b0c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/Hal8188EReg.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*  */
+/*  File Name: Hal8188EReg.h */
+/*  */
+/*  Description: */
+/*  */
+/*  This file is for RTL8188E register definition. */
+/*  */
+/*  */
+/*  */
+#ifndef	__HAL_8188E_REG_H__
+#define __HAL_8188E_REG_H__
+
+/*  */
+/*  Register Definition */
+/*  */
+#define TRX_ANTDIV_PATH             0x860
+#define RX_ANTDIV_PATH              0xb2c
+#define	ODM_R_A_AGC_CORE1_8188E		0xc50
+
+
+/*  */
+/*  Bitmap Definition */
+/*  */
+#define	BIT_FA_RESET_8188E			BIT0
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h
new file mode 100644
index 0000000..e574521
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_BB.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#ifndef __INC_BB_8188E_HW_IMG_H
+#define __INC_BB_8188E_HW_IMG_H
+
+/* static bool CheckCondition(const u32 Condition, const u32 Hex); */
+
+/******************************************************************************
+*                           AGC_TAB_1T.TXT
+******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *odm);
+
+/******************************************************************************
+*                           PHY_REG_1T.TXT
+******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *odm);
+
+/******************************************************************************
+*                           PHY_REG_PG.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h
new file mode 100644
index 0000000..1bf9bc7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_FW.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#ifndef __INC_FW_8188E_HW_IMG_H
+#define __INC_FW_8188E_HW_IMG_H
+
+
+/******************************************************************************
+*                           FW_AP.TXT
+******************************************************************************/
+/******************************************************************************
+*                           FW_WoWLAN.TXT
+******************************************************************************/
+#define ArrayLength_8188E_FW_WoWLAN 15764
+extern const u8 Array_8188E_FW_WoWLAN[ArrayLength_8188E_FW_WoWLAN];
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h
new file mode 100644
index 0000000..acf78b9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_MAC.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#ifndef __INC_MAC_8188E_HW_IMG_H
+#define __INC_MAC_8188E_HW_IMG_H
+
+/******************************************************************************
+*                           MAC_REG.TXT
+******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *pDM_Odm);
+
+#endif /*  end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h b/drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h
new file mode 100644
index 0000000..8ecb40d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalHWImg8188E_RF.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek 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
+*
+*
+******************************************************************************/
+
+#ifndef __INC_RF_8188E_HW_IMG_H
+#define __INC_RF_8188E_HW_IMG_H
+
+/******************************************************************************
+ *                           RadioA_1T.TXT
+ ******************************************************************************/
+
+enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *odm);
+
+#endif /*  end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8188eu/include/HalPhyRf.h b/drivers/staging/rtl8188eu/include/HalPhyRf.h
new file mode 100644
index 0000000..1ec4971
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalPhyRf.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+ #ifndef __HAL_PHY_RF_H__
+ #define __HAL_PHY_RF_H__
+
+#define ODM_TARGET_CHNL_NUM_2G_5G	59
+
+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm);
+
+u8 ODM_GetRightChnlPlaceforIQK(u8 chnl);
+
+#endif	/*  #ifndef __HAL_PHY_RF_H__ */
diff --git a/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h b/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h
new file mode 100644
index 0000000..fa583f2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalPhyRf_8188e.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __HAL_PHY_RF_8188E_H__
+#define __HAL_PHY_RF_8188E_H__
+
+/*--------------------------Define Parameters-------------------------------*/
+#define	IQK_DELAY_TIME_88E		10		/* ms */
+#define	index_mapping_NUM_88E	15
+#define AVG_THERMAL_NUM_88E	4
+
+
+void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *pDM_Odm,
+			     u8 Type,	/* 0 = OFDM, 1 = CCK */
+			     u8 *pDirection,/* 1 = +(incr) 2 = -(decr) */
+			     u32 *pOutWriteVal); /* Tx tracking CCK/OFDM BB
+						     * swing index adjust */
+
+
+void odm_TXPowerTrackingCallback_ThermalMeter_8188E(struct adapter *Adapter);
+
+
+/* 1 7.	IQK */
+
+void PHY_IQCalibrate_8188E(struct adapter *Adapter, bool ReCovery);
+
+/*  LC calibrate */
+void PHY_LCCalibrate_8188E(struct adapter *pAdapter);
+
+/*  AP calibrate */
+void PHY_APCalibrate_8188E(struct adapter *pAdapter, s8 delta);
+
+void PHY_DigitalPredistortion_8188E(struct adapter *pAdapter);
+
+void _PHY_SaveADDARegisters(struct adapter *pAdapter, u32 *ADDAReg,
+			    u32 *ADDABackup, u32 RegisterNum);
+
+void _PHY_PathADDAOn(struct adapter *pAdapter, u32 *ADDAReg,
+		     bool isPathAOn, bool is2T);
+
+void _PHY_MACSettingCalibration(struct adapter *pAdapter, u32 *MACReg,
+				u32 *MACBackup);
+
+void _PHY_PathAStandBy(struct adapter *pAdapter);
+
+#endif	/*  #ifndef __HAL_PHY_RF_8188E_H__ */
diff --git a/drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h b/drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h
new file mode 100644
index 0000000..d945784
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalPwrSeqCmd.h
@@ -0,0 +1,128 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __HALPWRSEQCMD_H__
+#define __HALPWRSEQCMD_H__
+
+#include <drv_types.h>
+
+/*---------------------------------------------*/
+/* 3 The value of cmd: 4 bits */
+/*---------------------------------------------*/
+#define PWR_CMD_READ			0x00
+     /*  offset: the read register offset */
+     /*  msk: the mask of the read value */
+     /*  value: N/A, left by 0 */
+     /*  note: dirver shall implement this function by read & msk */
+
+#define PWR_CMD_WRITE			0x01
+     /*  offset: the read register offset */
+     /*  msk: the mask of the write bits */
+     /*  value: write value */
+     /*  note: driver shall implement this cmd by read & msk after write */
+
+#define PWR_CMD_POLLING			0x02
+     /*  offset: the read register offset */
+     /*  msk: the mask of the polled value */
+     /*  value: the value to be polled, masked by the msd field. */
+     /*  note: driver shall implement this cmd by */
+     /*  do{ */
+     /*  if ( (Read(offset) & msk) == (value & msk) ) */
+     /*  break; */
+     /*  } while (not timeout); */
+
+#define PWR_CMD_DELAY			0x03
+     /*  offset: the value to delay */
+     /*  msk: N/A */
+     /*  value: the unit of delay, 0: us, 1: ms */
+
+#define PWR_CMD_END			0x04
+     /*  offset: N/A */
+     /*  msk: N/A */
+     /*  value: N/A */
+
+/*---------------------------------------------*/
+/* 3 The value of base: 4 bits */
+/*---------------------------------------------*/
+   /*  define the base address of each block */
+#define PWR_BASEADDR_MAC		0x00
+#define PWR_BASEADDR_USB		0x01
+#define PWR_BASEADDR_PCIE		0x02
+#define PWR_BASEADDR_SDIO		0x03
+
+/*---------------------------------------------*/
+/* 3 The value of interface_msk: 4 bits */
+/*---------------------------------------------*/
+#define	PWR_INTF_SDIO_MSK		BIT(0)
+#define	PWR_INTF_USB_MSK		BIT(1)
+#define	PWR_INTF_PCI_MSK		BIT(2)
+#define	PWR_INTF_ALL_MSK		(BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+/*---------------------------------------------*/
+/* 3 The value of fab_msk: 4 bits */
+/*---------------------------------------------*/
+#define	PWR_FAB_TSMC_MSK		BIT(0)
+#define	PWR_FAB_UMC_MSK			BIT(1)
+#define	PWR_FAB_ALL_MSK			(BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+/*---------------------------------------------*/
+/* 3 The value of cut_msk: 8 bits */
+/*---------------------------------------------*/
+#define	PWR_CUT_TESTCHIP_MSK		BIT(0)
+#define	PWR_CUT_A_MSK			BIT(1)
+#define	PWR_CUT_B_MSK			BIT(2)
+#define	PWR_CUT_C_MSK			BIT(3)
+#define	PWR_CUT_D_MSK			BIT(4)
+#define	PWR_CUT_E_MSK			BIT(5)
+#define	PWR_CUT_F_MSK			BIT(6)
+#define	PWR_CUT_G_MSK			BIT(7)
+#define	PWR_CUT_ALL_MSK			0xFF
+
+
+enum pwrseq_cmd_delat_unit {
+	PWRSEQ_DELAY_US,
+	PWRSEQ_DELAY_MS,
+};
+
+struct wl_pwr_cfg {
+	u16 offset;
+	u8 cut_msk;
+	u8 fab_msk:4;
+	u8 interface_msk:4;
+	u8 base:4;
+	u8 cmd:4;
+	u8 msk;
+	u8 value;
+};
+
+#define GET_PWR_CFG_OFFSET(__PWR_CMD)		__PWR_CMD.offset
+#define GET_PWR_CFG_CUT_MASK(__PWR_CMD)		__PWR_CMD.cut_msk
+#define GET_PWR_CFG_FAB_MASK(__PWR_CMD)		__PWR_CMD.fab_msk
+#define GET_PWR_CFG_INTF_MASK(__PWR_CMD)	__PWR_CMD.interface_msk
+#define GET_PWR_CFG_BASE(__PWR_CMD)		__PWR_CMD.base
+#define GET_PWR_CFG_CMD(__PWR_CMD)		__PWR_CMD.cmd
+#define GET_PWR_CFG_MASK(__PWR_CMD)		__PWR_CMD.msk
+#define GET_PWR_CFG_VALUE(__PWR_CMD)		__PWR_CMD.value
+
+
+/*	Prototype of protected function. */
+u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 CutVersion, u8 FabVersion,
+		       u8 InterfaceType, struct wl_pwr_cfg PwrCfgCmd[]);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/HalVerDef.h b/drivers/staging/rtl8188eu/include/HalVerDef.h
new file mode 100644
index 0000000..97047cf
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/HalVerDef.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __HAL_VERSION_DEF_H__
+#define __HAL_VERSION_DEF_H__
+
+enum HAL_IC_TYPE {
+	CHIP_8192S	=	0,
+	CHIP_8188C	=	1,
+	CHIP_8192C	=	2,
+	CHIP_8192D	=	3,
+	CHIP_8723A	=	4,
+	CHIP_8188E	=	5,
+	CHIP_8881A	=	6,
+	CHIP_8812A	=	7,
+	CHIP_8821A	=	8,
+	CHIP_8723B	=	9,
+	CHIP_8192E	=	10,
+};
+
+enum HAL_CHIP_TYPE {
+	TEST_CHIP	=	0,
+	NORMAL_CHIP	=	1,
+	FPGA		=	2,
+};
+
+enum HAL_CUT_VERSION {
+	A_CUT_VERSION	=	0,
+	B_CUT_VERSION	=	1,
+	C_CUT_VERSION	=	2,
+	D_CUT_VERSION	=	3,
+	E_CUT_VERSION	=	4,
+	F_CUT_VERSION	=	5,
+	G_CUT_VERSION	=	6,
+};
+
+enum HAL_VENDOR {
+	CHIP_VENDOR_TSMC	=	0,
+	CHIP_VENDOR_UMC		=	1,
+};
+
+enum HAL_RF_TYPE {
+	RF_TYPE_1T1R	=	0,
+	RF_TYPE_1T2R	=	1,
+	RF_TYPE_2T2R	=	2,
+	RF_TYPE_2T3R	=	3,
+	RF_TYPE_2T4R	=	4,
+	RF_TYPE_3T3R	=	5,
+	RF_TYPE_3T4R	=	6,
+	RF_TYPE_4T4R	=	7,
+};
+
+struct HAL_VERSION {
+	enum HAL_IC_TYPE	ICType;
+	enum HAL_CHIP_TYPE	ChipType;
+	enum HAL_CUT_VERSION	CUTVersion;
+	enum HAL_VENDOR		VendorType;
+	enum HAL_RF_TYPE	RFType;
+	u8			ROMVer;
+};
+
+/*  Get element */
+#define GET_CVID_IC_TYPE(version)	(((version).ICType))
+#define GET_CVID_CHIP_TYPE(version)	(((version).ChipType))
+#define GET_CVID_RF_TYPE(version)	(((version).RFType))
+#define GET_CVID_MANUFACTUER(version)	(((version).VendorType))
+#define GET_CVID_CUT_VERSION(version)	(((version).CUTVersion))
+#define GET_CVID_ROM_VERSION(version)	(((version).ROMVer) & ROM_VERSION_MASK)
+
+/* Common Macro. -- */
+/* HAL_VERSION VersionID */
+
+/*  HAL_IC_TYPE_E */
+#define IS_81XXC(version)				\
+	(((GET_CVID_IC_TYPE(version) == CHIP_8192C) ||	\
+	 (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? true : false)
+#define IS_8723_SERIES(version)				\
+	((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? true : false)
+#define IS_92D(version)					\
+	((GET_CVID_IC_TYPE(version) == CHIP_8192D) ? true : false)
+#define IS_8188E(version)				\
+	((GET_CVID_IC_TYPE(version) == CHIP_8188E) ? true : false)
+
+/* HAL_CHIP_TYPE_E */
+#define IS_TEST_CHIP(version)				\
+	((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false)
+#define IS_NORMAL_CHIP(version)				\
+	((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false)
+
+/* HAL_CUT_VERSION_E */
+#define IS_A_CUT(version)				\
+	((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false)
+#define IS_B_CUT(version)				\
+	((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false)
+#define IS_C_CUT(version)				\
+	((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false)
+#define IS_D_CUT(version)				\
+	((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? true : false)
+#define IS_E_CUT(version)				\
+	((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? true : false)
+
+
+/* HAL_VENDOR_E */
+#define IS_CHIP_VENDOR_TSMC(version)			\
+	((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version)			\
+	((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false)
+
+/* HAL_RF_TYPE_E */
+#define IS_1T1R(version)				\
+	((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false)
+#define IS_1T2R(version)				\
+	((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version)				\
+	((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false)
+
+/* Chip version Macro. -- */
+#define IS_81XXC_TEST_CHIP(version)			\
+	((IS_81XXC(version) && (!IS_NORMAL_CHIP(version))) ? true : false)
+
+#define IS_92C_SERIAL(version)				\
+	((IS_81XXC(version) && IS_2T2R(version)) ? true : false)
+#define IS_81xxC_VENDOR_UMC_A_CUT(version)		\
+	(IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ?	\
+	(IS_A_CUT(version) ? true : false) : false) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version)		\
+	(IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ?	\
+	(IS_B_CUT(version) ? true : false) : false) : false)
+#define IS_81xxC_VENDOR_UMC_C_CUT(version)		\
+	(IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \
+	 (IS_C_CUT(version) ? true : false) : false) : false)
+
+#define IS_NORMAL_CHIP92D(version)			\
+	((IS_92D(version)) ?				\
+	((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false) : false)
+
+#define IS_92D_SINGLEPHY(version)			\
+	((IS_92D(version)) ? (IS_2T2R(version) ? true : false) : false)
+#define IS_92D_C_CUT(version)				\
+	((IS_92D(version)) ? (IS_C_CUT(version) ? true : false) : false)
+#define IS_92D_D_CUT(version)				\
+	((IS_92D(version)) ? (IS_D_CUT(version) ? true : false) : false)
+#define IS_92D_E_CUT(version)				\
+	((IS_92D(version)) ? (IS_E_CUT(version) ? true : false) : false)
+
+#define IS_8723A_A_CUT(version)				\
+	((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? true : false) : false)
+#define IS_8723A_B_CUT(version)				\
+	((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? true : false) : false)
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/basic_types.h b/drivers/staging/rtl8188eu/include/basic_types.h
new file mode 100644
index 0000000..8a7ca99
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/basic_types.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __BASIC_TYPES_H__
+#define __BASIC_TYPES_H__
+
+#define SUCCESS	0
+#define FAIL	(-1)
+
+#include <linux/types.h>
+#define NDIS_OID uint
+
+typedef void (*proc_t)(void *);
+
+#define FIELD_OFFSET(s, field)	((ssize_t)&((s *)(0))->field)
+
+#define MEM_ALIGNMENT_OFFSET	(sizeof(size_t))
+#define MEM_ALIGNMENT_PADDING	(sizeof(size_t) - 1)
+
+/* port from fw */
+/*  TODO: Macros Below are Sync from SD7-Driver. It is necessary
+ * to check correctness */
+
+/*
+ *	Call endian free function when
+ *		1. Read/write packet content.
+ *		2. Before write integer to IO.
+ *		3. After read integer from IO.
+*/
+
+/* Convert little data endian to host ordering */
+#define EF1BYTE(_val)		\
+	((u8)(_val))
+#define EF2BYTE(_val)		\
+	(le16_to_cpu(_val))
+#define EF4BYTE(_val)		\
+	(le32_to_cpu(_val))
+
+/* Read data from memory */
+#define READEF1BYTE(_ptr)	\
+	EF1BYTE(*((u8 *)(_ptr)))
+/* Read le16 data from memory and convert to host ordering */
+#define READEF2BYTE(_ptr)	\
+	EF2BYTE(*(_ptr))
+#define READEF4BYTE(_ptr)	\
+	EF4BYTE(*(_ptr))
+
+/* Write data to memory */
+#define WRITEEF1BYTE(_ptr, _val)			\
+	do {						\
+		(*((u8 *)(_ptr))) = EF1BYTE(_val)	\
+	} while (0)
+/* Write le data to memory in host ordering */
+#define WRITEEF2BYTE(_ptr, _val)			\
+	do {						\
+		(*((u16 *)(_ptr))) = EF2BYTE(_val)	\
+	} while (0)
+
+#define WRITEEF4BYTE(_ptr, _val)			\
+	do {						\
+		(*((u32 *)(_ptr))) = EF2BYTE(_val)	\
+	} while (0)
+
+/* Create a bit mask
+ * Examples:
+ * BIT_LEN_MASK_32(0) => 0x00000000
+ * BIT_LEN_MASK_32(1) => 0x00000001
+ * BIT_LEN_MASK_32(2) => 0x00000003
+ * BIT_LEN_MASK_32(32) => 0xFFFFFFFF
+ */
+#define BIT_LEN_MASK_32(__bitlen)	 \
+	(0xFFFFFFFF >> (32 - (__bitlen)))
+#define BIT_LEN_MASK_16(__bitlen)	 \
+	(0xFFFF >> (16 - (__bitlen)))
+#define BIT_LEN_MASK_8(__bitlen) \
+	(0xFF >> (8 - (__bitlen)))
+
+/* Create an offset bit mask
+ * Examples:
+ * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003
+ * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000
+ */
+#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \
+	(BIT_LEN_MASK_32(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \
+	(BIT_LEN_MASK_16(__bitlen) << (__bitoffset))
+#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \
+	(BIT_LEN_MASK_8(__bitlen) << (__bitoffset))
+
+/*Description:
+ * Return 4-byte value in host byte ordering from
+ * 4-byte pointer in little-endian system.
+ */
+#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \
+	(EF4BYTE(*((__le32 *)(__pstart))))
+#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \
+	(EF2BYTE(*((__le16 *)(__pstart))))
+#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
+	(EF1BYTE(*((u8 *)(__pstart))))
+
+/*Description:
+Translate subfield (continuous bits in little-endian) of 4-byte
+value to host byte ordering.*/
+#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		(LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset))  & \
+		BIT_LEN_MASK_32(__bitlen) \
+	)
+#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		(LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
+		BIT_LEN_MASK_16(__bitlen) \
+	)
+#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		(LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
+		BIT_LEN_MASK_8(__bitlen) \
+	)
+
+/* Description:
+ * Mask subfield (continuous bits in little-endian) of 4-byte value
+ * and return the result in 4-byte value in host byte ordering.
+ */
+#define LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		LE_P4BYTE_TO_HOST_4BYTE(__pstart)  & \
+		(~BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen)) \
+	)
+#define LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		LE_P2BYTE_TO_HOST_2BYTE(__pstart) & \
+		(~BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen)) \
+	)
+#define LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+	( \
+		LE_P1BYTE_TO_HOST_1BYTE(__pstart) & \
+		(~BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen)) \
+	)
+
+/* Description:
+ * Set subfield of little-endian 4-byte value to specified value.
+ */
+#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
+		*((u32 *)(__pstart)) =				\
+		(							\
+		LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
+		((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
+		)
+
+#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
+		*((u16 *)(__pstart)) =				\
+		(						\
+		LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
+		((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
+		);
+
+#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
+		*((u8 *)(__pstart)) = EF1BYTE			\
+		(						\
+		LE_BITS_CLEARED_TO_1BYTE(__pstart, __bitoffset, __bitlen) | \
+		((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
+		)
+
+/*  Get the N-bytes aligment offset from the current length */
+#define	N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \
+	(__value) : (((__value + __aligment - 1) / __aligment) * __aligment))
+
+#endif /* __BASIC_TYPES_H__ */
diff --git a/drivers/staging/rtl8188eu/include/cmd_osdep.h b/drivers/staging/rtl8188eu/include/cmd_osdep.h
new file mode 100644
index 0000000..5a8465e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/cmd_osdep.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __CMD_OSDEP_H_
+#define __CMD_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+extern int _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv);
+extern int _rtw_init_evt_priv(struct evt_priv *pevtpriv);
+extern void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv);
+extern int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj);
+extern struct cmd_obj	*_rtw_dequeue_cmd(struct __queue *queue);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/drv_types.h b/drivers/staging/rtl8188eu/include/drv_types.h
new file mode 100644
index 0000000..ad073c8
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/drv_types.h
@@ -0,0 +1,334 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*-----------------------------------------------------------------------------
+
+	For type defines and data structure defines
+
+------------------------------------------------------------------------------*/
+
+
+#ifndef __DRV_TYPES_H__
+#define __DRV_TYPES_H__
+
+#define DRV_NAME "r8188eu"
+
+#include <osdep_service.h>
+#include <wlan_bssdef.h>
+#include <drv_types_linux.h>
+#include <rtw_ht.h>
+#include <rtw_cmd.h>
+#include <rtw_xmit.h>
+#include <rtw_recv.h>
+#include <hal_intf.h>
+#include <hal_com.h>
+#include <rtw_qos.h>
+#include <rtw_security.h>
+#include <rtw_pwrctrl.h>
+#include <rtw_io.h>
+#include <rtw_eeprom.h>
+#include <sta_info.h>
+#include <rtw_mlme.h>
+#include <rtw_debug.h>
+#include <rtw_rf.h>
+#include <rtw_event.h>
+#include <rtw_led.h>
+#include <rtw_mlme_ext.h>
+#include <rtw_p2p.h>
+#include <rtw_ap.h>
+#include <rtw_mp.h>
+#include <rtw_br_ext.h>
+
+enum _NIC_VERSION {
+	RTL8711_NIC,
+	RTL8712_NIC,
+	RTL8713_NIC,
+	RTL8716_NIC
+};
+
+#define SPEC_DEV_ID_NONE		BIT(0)
+#define SPEC_DEV_ID_DISABLE_HT		BIT(1)
+#define SPEC_DEV_ID_ENABLE_PS		BIT(2)
+#define SPEC_DEV_ID_RF_CONFIG_1T1R	BIT(3)
+#define SPEC_DEV_ID_RF_CONFIG_2T2R	BIT(4)
+#define SPEC_DEV_ID_ASSIGN_IFNAME	BIT(5)
+
+struct specific_device_id {
+	u32		flags;
+	u16		idVendor;
+	u16		idProduct;
+};
+
+struct registry_priv {
+	u8	chip_version;
+	u8	rfintfs;
+	u8	lbkmode;
+	u8	hci;
+	struct ndis_802_11_ssid	ssid;
+	u8	network_mode;	/* infra, ad-hoc, auto */
+	u8	channel;/* ad-hoc support requirement */
+	u8	wireless_mode;/* A, B, G, auto */
+	u8	scan_mode;/* active, passive */
+	u8	radio_enable;
+	u8	preamble;/* long, short, auto */
+	u8	vrtl_carrier_sense;/* Enable, Disable, Auto */
+	u8	vcs_type;/* RTS/CTS, CTS-to-self */
+	u16	rts_thresh;
+	u16	frag_thresh;
+	u8	adhoc_tx_pwr;
+	u8	soft_ap;
+	u8	power_mgnt;
+	u8	ips_mode;
+	u8	smart_ps;
+	u8	long_retry_lmt;
+	u8	short_retry_lmt;
+	u16	busy_thresh;
+	u8	ack_policy;
+	u8	mp_mode;
+	u8	software_encrypt;
+	u8	software_decrypt;
+	u8	acm_method;
+	  /* UAPSD */
+	u8	wmm_enable;
+	u8	uapsd_enable;
+	u8	uapsd_max_sp;
+	u8	uapsd_acbk_en;
+	u8	uapsd_acbe_en;
+	u8	uapsd_acvi_en;
+	u8	uapsd_acvo_en;
+
+	struct wlan_bssid_ex    dev_network;
+
+	u8	ht_enable;
+	u8	cbw40_enable;
+	u8	ampdu_enable;/* for tx */
+	u8	rx_stbc;
+	u8	ampdu_amsdu;/* A-MPDU Supports A-MSDU is permitted */
+	u8	lowrate_two_xmit;
+
+	u8	rf_config;
+	u8	low_power;
+
+	u8	wifi_spec;/*  !turbo_mode */
+
+	u8	channel_plan;
+	bool	bAcceptAddbaReq;
+
+	u8	antdiv_cfg;
+	u8	antdiv_type;
+
+	u8	usbss_enable;/* 0:disable,1:enable */
+	u8	hwpdn_mode;/* 0:disable,1:enable,2:decide by EFUSE config */
+	u8	hwpwrp_detect;/* 0:disable,1:enable */
+
+	u8	hw_wps_pbc;/* 0:disable,1:enable */
+
+	u8	max_roaming_times; /*  the max number driver will try */
+
+	u8	fw_iol; /* enable iol without other concern */
+
+	u8	enable80211d;
+
+	u8	ifname[16];
+	u8	if2name[16];
+
+	u8	notch_filter;
+};
+
+/* For registry parameters */
+#define RGTRY_OFT(field) ((u32)FIELD_OFFSET(struct registry_priv, field))
+#define RGTRY_SZ(field)   sizeof(((struct registry_priv *)0)->field)
+#define BSSID_OFT(field) ((u32)FIELD_OFFSET(struct wlan_bssid_ex, field))
+#define BSSID_SZ(field)   sizeof(((struct wlan_bssid_ex *)0)->field)
+
+#define MAX_CONTINUAL_URB_ERR		4
+
+struct dvobj_priv {
+	struct adapter *if1;
+	struct adapter *if2;
+
+	/* For 92D, DMDP have 2 interface. */
+	u8	InterfaceNumber;
+	u8	NumInterfaces;
+
+	/* In /Out Pipe information */
+	int	RtInPipe[2];
+	int	RtOutPipe[3];
+	u8	Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */
+
+	u8	irq_alloc;
+
+/*-------- below is for USB INTERFACE --------*/
+
+	u8	nr_endpoint;
+	u8	ishighspeed;
+	u8	RtNumInPipes;
+	u8	RtNumOutPipes;
+	int	ep_num[5]; /* endpoint number */
+	int	RegUsbSS;
+	struct semaphore usb_suspend_sema;
+	struct mutex  usb_vendor_req_mutex;
+
+	u8 *usb_alloc_vendor_req_buf;
+	u8 *usb_vendor_req_buf;
+
+	struct usb_interface *pusbintf;
+	struct usb_device *pusbdev;
+
+	ATOMIC_T continual_urb_error;
+};
+
+static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj)
+{
+	/* todo: get interface type from dvobj and the return
+	 * the dev accordingly */
+	return &dvobj->pusbintf->dev;
+};
+
+enum _IFACE_TYPE {
+	IFACE_PORT0, /* mapping to port0 for C/D series chips */
+	IFACE_PORT1, /* mapping to port1 for C/D series chip */
+	MAX_IFACE_PORT,
+};
+
+enum _ADAPTER_TYPE {
+	PRIMARY_ADAPTER,
+	SECONDARY_ADAPTER,
+	MAX_ADAPTER,
+};
+
+enum driver_state {
+	DRIVER_NORMAL = 0,
+	DRIVER_DISAPPEAR = 1,
+	DRIVER_REPLACE_DONGLE = 2,
+};
+
+struct adapter {
+	int	DriverState;/* for disable driver using module, use dongle toi
+			     * replace module. */
+	int	pid[3];/* process id from UI, 0:wps, 1:hostapd, 2:dhcpcd */
+	int	bDongle;/* build-in module or external dongle */
+	u16	chip_type;
+	u16	HardwareType;
+	u16	interface_type;/* USB,SDIO,SPI,PCI */
+
+	struct dvobj_priv *dvobj;
+	struct	mlme_priv mlmepriv;
+	struct	mlme_ext_priv mlmeextpriv;
+	struct	cmd_priv	cmdpriv;
+	struct	evt_priv	evtpriv;
+	struct	io_priv	iopriv;
+	struct	xmit_priv	xmitpriv;
+	struct	recv_priv	recvpriv;
+	struct	sta_priv	stapriv;
+	struct	security_priv	securitypriv;
+	struct	registry_priv	registrypriv;
+	struct	pwrctrl_priv	pwrctrlpriv;
+	struct	eeprom_priv eeprompriv;
+	struct	led_priv	ledpriv;
+	struct	mp_priv	mppriv;
+
+#ifdef CONFIG_88EU_AP_MODE
+	struct	hostapd_priv	*phostapdpriv;
+#endif
+
+	struct wifidirect_info	wdinfo;
+
+	void *HalData;
+	u32 hal_data_sz;
+	struct hal_ops	HalFunc;
+
+	s32	bDriverStopped;
+	s32	bSurpriseRemoved;
+	s32	bCardDisableWOHSM;
+
+	u32	IsrContent;
+	u32	ImrContent;
+
+	u8	EepromAddressSize;
+	u8	hw_init_completed;
+	u8	bDriverIsGoingToUnload;
+	u8	init_adpt_in_progress;
+	u8	bHaltInProgress;
+
+	void *cmdThread;
+	void *evtThread;
+	void *xmitThread;
+	void *recvThread;
+	void (*intf_start)(struct adapter *adapter);
+	void (*intf_stop)(struct adapter *adapter);
+	struct  net_device *pnetdev;
+
+	/*  used by rtw_rereg_nd_name related function */
+	struct rereg_nd_name_data {
+		struct  net_device *old_pnetdev;
+		char old_ifname[IFNAMSIZ];
+		u8 old_ips_mode;
+		u8 old_bRegUseLed;
+	} rereg_nd_name_priv;
+
+	int bup;
+	struct net_device_stats stats;
+	struct iw_statistics iwstats;
+	struct proc_dir_entry *dir_dev;/*  for proc directory */
+
+	int net_closed;
+	u8 bFWReady;
+	u8 bBTFWReady;
+	u8 bReadPortCancel;
+	u8 bWritePortCancel;
+	u8 bRxRSSIDisplay;
+	/* The driver will show up the desired channel number
+	 * when this flag is 1. */
+	u8 bNotifyChannelChange;
+#ifdef CONFIG_88EU_P2P
+	/* The driver will show the current P2P status when the
+	 * upper application reads it. */
+	u8 bShowGetP2PState;
+#endif
+	struct adapter *pbuddy_adapter;
+
+	struct mutex *hw_init_mutex;
+
+	spinlock_t br_ext_lock;
+	struct nat25_network_db_entry	*nethash[NAT25_HASH_SIZE];
+	int				pppoe_connection_in_progress;
+	unsigned char			pppoe_addr[MACADDRLEN];
+	unsigned char			scdb_mac[MACADDRLEN];
+	unsigned char			scdb_ip[4];
+	struct nat25_network_db_entry	*scdb_entry;
+	unsigned char			br_mac[MACADDRLEN];
+	unsigned char			br_ip[4];
+	struct br_ext_info		ethBrExtInfo;
+
+	u8	fix_rate;
+
+	unsigned char     in_cta_test;
+};
+
+#define adapter_to_dvobj(adapter) (adapter->dvobj)
+
+int rtw_handle_dualmac(struct adapter *adapter, bool init);
+
+static inline u8 *myid(struct eeprom_priv *peepriv)
+{
+	return peepriv->mac_addr;
+}
+
+#endif /* __DRV_TYPES_H__ */
diff --git a/drivers/staging/rtl8188eu/include/drv_types_linux.h b/drivers/staging/rtl8188eu/include/drv_types_linux.h
new file mode 100644
index 0000000..812b744
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/drv_types_linux.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __DRV_TYPES_LINUX_H__
+#define __DRV_TYPES_LINUX_H__
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/ethernet.h b/drivers/staging/rtl8188eu/include/ethernet.h
new file mode 100644
index 0000000..a59f912
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ethernet.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*! \file */
+#ifndef __INC_ETHERNET_H
+#define __INC_ETHERNET_H
+
+#define ETHERNET_ADDRESS_LENGTH		6	/*  Ethernet Address Length */
+#define ETHERNET_HEADER_SIZE		14	/*  Ethernet Header Length */
+#define LLC_HEADER_SIZE			6	/*  LLC Header Length */
+#define TYPE_LENGTH_FIELD_SIZE		2	/*  Type/Length Size */
+#define MINIMUM_ETHERNET_PACKET_SIZE	60	/*  Min Ethernet Packet Size */
+#define MAXIMUM_ETHERNET_PACKET_SIZE	1514	/*  Max Ethernet Packet Size */
+
+/*  Is Multicast Address? */
+#define RT_ETH_IS_MULTICAST(_addr)	((((u8 *)(_addr))[0]&0x01) != 0)
+#define RT_ETH_IS_BROADCAST(_addr)	(			\
+		((u8 *)(_addr))[0] == 0xff &&		\
+		((u8 *)(_addr))[1] == 0xff &&		\
+		((u8 *)(_addr))[2] == 0xff &&		\
+		((u8 *)(_addr))[3] == 0xff &&		\
+		((u8 *)(_addr))[4] == 0xff &&		\
+		((u8 *)(_addr))[5] == 0xff)	/*  Is Broadcast Address? */
+
+
+#endif /*  #ifndef __INC_ETHERNET_H */
diff --git a/drivers/staging/rtl8188eu/include/h2clbk.h b/drivers/staging/rtl8188eu/include/h2clbk.h
new file mode 100644
index 0000000..e595030
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/h2clbk.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+
+#define _H2CLBK_H_
+
+
+#include <rtl8711_spec.h>
+#include <TypeDef.h>
+
+
+void _lbk_cmd(struct adapter *adapter);
+
+void _lbk_rsp(struct adapter *adapter);
+
+void _lbk_evt(IN struct adapter *adapter);
+
+void h2c_event_callback(unsigned char *dev, unsigned char *pbuf);
diff --git a/drivers/staging/rtl8188eu/include/hal_com.h b/drivers/staging/rtl8188eu/include/hal_com.h
new file mode 100644
index 0000000..81c2709
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/hal_com.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __HAL_COMMON_H__
+#define __HAL_COMMON_H__
+
+/*  */
+/*        Rate Definition */
+/*  */
+/* CCK */
+#define	RATR_1M					0x00000001
+#define	RATR_2M					0x00000002
+#define	RATR_55M				0x00000004
+#define	RATR_11M				0x00000008
+/* OFDM */
+#define	RATR_6M					0x00000010
+#define	RATR_9M					0x00000020
+#define	RATR_12M				0x00000040
+#define	RATR_18M				0x00000080
+#define	RATR_24M				0x00000100
+#define	RATR_36M				0x00000200
+#define	RATR_48M				0x00000400
+#define	RATR_54M				0x00000800
+/* MCS 1 Spatial Stream */
+#define	RATR_MCS0				0x00001000
+#define	RATR_MCS1				0x00002000
+#define	RATR_MCS2				0x00004000
+#define	RATR_MCS3				0x00008000
+#define	RATR_MCS4				0x00010000
+#define	RATR_MCS5				0x00020000
+#define	RATR_MCS6				0x00040000
+#define	RATR_MCS7				0x00080000
+/* MCS 2 Spatial Stream */
+#define	RATR_MCS8				0x00100000
+#define	RATR_MCS9				0x00200000
+#define	RATR_MCS10				0x00400000
+#define	RATR_MCS11				0x00800000
+#define	RATR_MCS12				0x01000000
+#define	RATR_MCS13				0x02000000
+#define	RATR_MCS14				0x04000000
+#define	RATR_MCS15				0x08000000
+
+/* CCK */
+#define RATE_1M					BIT(0)
+#define RATE_2M					BIT(1)
+#define RATE_5_5M				BIT(2)
+#define RATE_11M				BIT(3)
+/* OFDM */
+#define RATE_6M					BIT(4)
+#define RATE_9M					BIT(5)
+#define RATE_12M				BIT(6)
+#define RATE_18M				BIT(7)
+#define RATE_24M				BIT(8)
+#define RATE_36M				BIT(9)
+#define RATE_48M				BIT(10)
+#define RATE_54M				BIT(11)
+/* MCS 1 Spatial Stream */
+#define RATE_MCS0				BIT(12)
+#define RATE_MCS1				BIT(13)
+#define RATE_MCS2				BIT(14)
+#define RATE_MCS3				BIT(15)
+#define RATE_MCS4				BIT(16)
+#define RATE_MCS5				BIT(17)
+#define RATE_MCS6				BIT(18)
+#define RATE_MCS7				BIT(19)
+/* MCS 2 Spatial Stream */
+#define RATE_MCS8				BIT(20)
+#define RATE_MCS9				BIT(21)
+#define RATE_MCS10				BIT(22)
+#define RATE_MCS11				BIT(23)
+#define RATE_MCS12				BIT(24)
+#define RATE_MCS13				BIT(25)
+#define RATE_MCS14				BIT(26)
+#define RATE_MCS15				BIT(27)
+
+/*  ALL CCK Rate */
+#define	RATE_ALL_CCK		(RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define	RATE_ALL_OFDM_AG	(RATR_6M | RATR_9M | RATR_12M | RATR_18M | \
+				 RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define	RATE_ALL_OFDM_1SS	(RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |	\
+				 RATR_MCS3 | RATR_MCS4 | RATR_MCS5|RATR_MCS6 | \
+				 RATR_MCS7)
+#define	RATE_ALL_OFDM_2SS	(RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
+				 RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
+				 RATR_MCS14 | RATR_MCS15)
+
+/*------------------------------ Tx Desc definition Macro --------------------*/
+/* pragma mark -- Tx Desc related definition. -- */
+/*	Rate */
+/*  CCK Rates, TxHT = 0 */
+#define DESC_RATE1M				0x00
+#define DESC_RATE2M				0x01
+#define DESC_RATE5_5M				0x02
+#define DESC_RATE11M				0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC_RATE6M				0x04
+#define DESC_RATE9M				0x05
+#define DESC_RATE12M				0x06
+#define DESC_RATE18M				0x07
+#define DESC_RATE24M				0x08
+#define DESC_RATE36M				0x09
+#define DESC_RATE48M				0x0a
+#define DESC_RATE54M				0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC_RATEMCS0				0x0c
+#define DESC_RATEMCS1				0x0d
+#define DESC_RATEMCS2				0x0e
+#define DESC_RATEMCS3				0x0f
+#define DESC_RATEMCS4				0x10
+#define DESC_RATEMCS5				0x11
+#define DESC_RATEMCS6				0x12
+#define DESC_RATEMCS7				0x13
+#define DESC_RATEMCS8				0x14
+#define DESC_RATEMCS9				0x15
+#define DESC_RATEMCS10				0x16
+#define DESC_RATEMCS11				0x17
+#define DESC_RATEMCS12				0x18
+#define DESC_RATEMCS13				0x19
+#define DESC_RATEMCS14				0x1a
+#define DESC_RATEMCS15				0x1b
+#define DESC_RATEMCS15_SG			0x1c
+#define DESC_RATEMCS32				0x20
+
+/*  1 Byte long (in unit of TU) */
+#define REG_P2P_CTWIN				0x0572
+#define REG_NOA_DESC_SEL			0x05CF
+#define REG_NOA_DESC_DURATION			0x05E0
+#define REG_NOA_DESC_INTERVAL			0x05E4
+#define REG_NOA_DESC_START			0x05E8
+#define REG_NOA_DESC_COUNT			0x05EC
+
+#include "HalVerDef.h"
+void dump_chip_info(struct HAL_VERSION	ChipVersion);
+
+
+/* return the final channel plan decision */
+u8 hal_com_get_channel_plan(struct adapter *padapter,
+			    u8 hw_channel_plan,
+			    u8 sw_channel_plan,
+			    u8 def_channel_plan,
+			    bool AutoLoadFail
+);
+
+u8 MRateToHwRate(u8 rate);
+
+void HalSetBrateCfg(struct adapter *Adapter, u8 *mBratesOS, u16 *pBrateCfg);
+
+bool Hal_MappingOutPipe(struct adapter *pAdapter, u8 NumOutPipe);
+
+void hal_init_macaddr(struct adapter *adapter);
+
+void c2h_evt_clear(struct adapter *adapter);
+s32 c2h_evt_read(struct adapter *adapter, u8 *buf);
+
+#endif /* __HAL_COMMON_H__ */
diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h
new file mode 100644
index 0000000..439c3c9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/hal_intf.h
@@ -0,0 +1,426 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __HAL_INTF_H__
+#define __HAL_INTF_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <Hal8188EPhyCfg.h>
+
+enum RTL871X_HCI_TYPE {
+	RTW_PCIE	= BIT0,
+	RTW_USB		= BIT1,
+	RTW_SDIO	= BIT2,
+	RTW_GSPI	= BIT3,
+};
+
+enum _CHIP_TYPE {
+	NULL_CHIP_TYPE,
+	RTL8712_8188S_8191S_8192S,
+	RTL8188C_8192C,
+	RTL8192D,
+	RTL8723A,
+	RTL8188E,
+	MAX_CHIP_TYPE
+};
+
+enum hw_variables {
+	HW_VAR_MEDIA_STATUS,
+	HW_VAR_MEDIA_STATUS1,
+	HW_VAR_SET_OPMODE,
+	HW_VAR_MAC_ADDR,
+	HW_VAR_BSSID,
+	HW_VAR_INIT_RTS_RATE,
+	HW_VAR_BASIC_RATE,
+	HW_VAR_TXPAUSE,
+	HW_VAR_BCN_FUNC,
+	HW_VAR_CORRECT_TSF,
+	HW_VAR_CHECK_BSSID,
+	HW_VAR_MLME_DISCONNECT,
+	HW_VAR_MLME_SITESURVEY,
+	HW_VAR_MLME_JOIN,
+	HW_VAR_BEACON_INTERVAL,
+	HW_VAR_SLOT_TIME,
+	HW_VAR_RESP_SIFS,
+	HW_VAR_ACK_PREAMBLE,
+	HW_VAR_SEC_CFG,
+	HW_VAR_BCN_VALID,
+	HW_VAR_RF_TYPE,
+	HW_VAR_DM_FLAG,
+	HW_VAR_DM_FUNC_OP,
+	HW_VAR_DM_FUNC_SET,
+	HW_VAR_DM_FUNC_CLR,
+	HW_VAR_CAM_EMPTY_ENTRY,
+	HW_VAR_CAM_INVALID_ALL,
+	HW_VAR_CAM_WRITE,
+	HW_VAR_CAM_READ,
+	HW_VAR_AC_PARAM_VO,
+	HW_VAR_AC_PARAM_VI,
+	HW_VAR_AC_PARAM_BE,
+	HW_VAR_AC_PARAM_BK,
+	HW_VAR_ACM_CTRL,
+	HW_VAR_AMPDU_MIN_SPACE,
+	HW_VAR_AMPDU_FACTOR,
+	HW_VAR_RXDMA_AGG_PG_TH,
+	HW_VAR_SET_RPWM,
+	HW_VAR_H2C_FW_PWRMODE,
+	HW_VAR_H2C_FW_JOINBSSRPT,
+	HW_VAR_FWLPS_RF_ON,
+	HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+	HW_VAR_TDLS_WRCR,
+	HW_VAR_TDLS_INIT_CH_SEN,
+	HW_VAR_TDLS_RS_RCR,
+	HW_VAR_TDLS_DONE_CH_SEN,
+	HW_VAR_INITIAL_GAIN,
+	HW_VAR_TRIGGER_GPIO_0,
+	HW_VAR_BT_SET_COEXIST,
+	HW_VAR_BT_ISSUE_DELBA,
+	HW_VAR_CURRENT_ANTENNA,
+	HW_VAR_ANTENNA_DIVERSITY_LINK,
+	HW_VAR_ANTENNA_DIVERSITY_SELECT,
+	HW_VAR_SWITCH_EPHY_WoWLAN,
+	HW_VAR_EFUSE_USAGE,
+	HW_VAR_EFUSE_BYTES,
+	HW_VAR_EFUSE_BT_USAGE,
+	HW_VAR_EFUSE_BT_BYTES,
+	HW_VAR_FIFO_CLEARN_UP,
+	HW_VAR_CHECK_TXBUF,
+	HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation,
+			     * power control for MAC only */
+	/*  The valid upper nav range for the HW updating, if the true value is
+	 *  larger than the upper range, the HW won't update it. */
+	/*  Unit in microsecond. 0 means disable this function. */
+	HW_VAR_NAV_UPPER,
+	HW_VAR_RPT_TIMER_SETTING,
+	HW_VAR_TX_RPT_MAX_MACID,
+	HW_VAR_H2C_MEDIA_STATUS_RPT,
+	HW_VAR_CHK_HI_QUEUE_EMPTY,
+};
+
+enum hal_def_variable {
+	HAL_DEF_UNDERCORATEDSMOOTHEDPWDB,
+	HAL_DEF_IS_SUPPORT_ANT_DIV,
+	HAL_DEF_CURRENT_ANTENNA,
+	HAL_DEF_DRVINFO_SZ,
+	HAL_DEF_MAX_RECVBUF_SZ,
+	HAL_DEF_RX_PACKET_OFFSET,
+	HAL_DEF_DBG_DUMP_RXPKT,/* for dbg */
+	HAL_DEF_DBG_DM_FUNC,/* for dbg */
+	HAL_DEF_RA_DECISION_RATE,
+	HAL_DEF_RA_SGI,
+	HAL_DEF_PT_PWR_STATUS,
+	HW_VAR_MAX_RX_AMPDU_FACTOR,
+	HW_DEF_RA_INFO_DUMP,
+	HAL_DEF_DBG_DUMP_TXPKT,
+	HW_DEF_FA_CNT_DUMP,
+	HW_DEF_ODM_DBG_FLAG,
+};
+
+enum hal_odm_variable {
+	HAL_ODM_STA_INFO,
+	HAL_ODM_P2P_STATE,
+	HAL_ODM_WIFI_DISPLAY_STATE,
+};
+
+enum hal_intf_ps_func {
+	HAL_USB_SELECT_SUSPEND,
+	HAL_MAX_ID,
+};
+
+typedef s32 (*c2h_id_filter)(u8 id);
+
+struct hal_ops {
+	u32	(*hal_power_on)(struct adapter *padapter);
+	u32	(*hal_init)(struct adapter *padapter);
+	u32	(*hal_deinit)(struct adapter *padapter);
+
+	void	(*free_hal_data)(struct adapter *padapter);
+
+	u32	(*inirp_init)(struct adapter *padapter);
+	u32	(*inirp_deinit)(struct adapter *padapter);
+
+	s32	(*init_xmit_priv)(struct adapter *padapter);
+	void	(*free_xmit_priv)(struct adapter *padapter);
+
+	s32	(*init_recv_priv)(struct adapter *padapter);
+	void	(*free_recv_priv)(struct adapter *padapter);
+
+	void	(*InitSwLeds)(struct adapter *padapter);
+	void	(*DeInitSwLeds)(struct adapter *padapter);
+
+	void	(*dm_init)(struct adapter *padapter);
+	void	(*dm_deinit)(struct adapter *padapter);
+	void	(*read_chip_version)(struct adapter *padapter);
+
+	void	(*init_default_value)(struct adapter *padapter);
+
+	void	(*intf_chip_configure)(struct adapter *padapter);
+
+	void	(*read_adapter_info)(struct adapter *padapter);
+
+	void	(*enable_interrupt)(struct adapter *padapter);
+	void	(*disable_interrupt)(struct adapter *padapter);
+	s32	(*interrupt_handler)(struct adapter *padapter);
+
+	void	(*set_bwmode_handler)(struct adapter *padapter,
+				      enum ht_channel_width Bandwidth,
+				      u8 Offset);
+	void	(*set_channel_handler)(struct adapter *padapter, u8 channel);
+
+	void	(*hal_dm_watchdog)(struct adapter *padapter);
+
+	void	(*SetHwRegHandler)(struct adapter *padapter, u8	variable,
+				   u8 *val);
+	void	(*GetHwRegHandler)(struct adapter *padapter, u8	variable,
+				   u8 *val);
+
+	u8	(*GetHalDefVarHandler)(struct adapter *padapter,
+				       enum hal_def_variable eVariable,
+				       void *pValue);
+	u8	(*SetHalDefVarHandler)(struct adapter *padapter,
+				       enum hal_def_variable eVariable,
+				       void *pValue);
+
+	void	(*GetHalODMVarHandler)(struct adapter *padapter,
+				       enum hal_odm_variable eVariable,
+				       void *pValue1, bool bSet);
+	void	(*SetHalODMVarHandler)(struct adapter *padapter,
+				       enum hal_odm_variable eVariable,
+				       void *pValue1, bool bSet);
+
+	void	(*UpdateRAMaskHandler)(struct adapter *padapter,
+				       u32 mac_id, u8 rssi_level);
+	void	(*SetBeaconRelatedRegistersHandler)(struct adapter *padapter);
+
+	void	(*Add_RateATid)(struct adapter *adapter, u32 bitmap, u8 arg,
+				u8 rssi_level);
+	void	(*run_thread)(struct adapter *adapter);
+	void	(*cancel_thread)(struct adapter *adapter);
+
+	u8	(*AntDivBeforeLinkHandler)(struct adapter *adapter);
+	void	(*AntDivCompareHandler)(struct adapter *adapter,
+					struct wlan_bssid_ex *dst,
+					struct wlan_bssid_ex *src);
+	u8	(*interface_ps_func)(struct adapter *padapter,
+				     enum hal_intf_ps_func efunc_id, u8 *val);
+
+	s32	(*hal_xmit)(struct adapter *padapter,
+			    struct xmit_frame *pxmitframe);
+	s32 (*mgnt_xmit)(struct adapter *padapter,
+			 struct xmit_frame *pmgntframe);
+
+	u32	(*read_bbreg)(struct adapter *padapter, u32 RegAddr,
+			      u32 BitMask);
+	void	(*write_bbreg)(struct adapter *padapter, u32 RegAddr,
+			       u32 BitMask, u32 Data);
+	u32	(*read_rfreg)(struct adapter *padapter,
+			      enum rf_radio_path eRFPath, u32 RegAddr,
+			      u32 BitMask);
+	void	(*write_rfreg)(struct adapter *padapter,
+			       enum rf_radio_path eRFPath, u32 RegAddr,
+			       u32 BitMask, u32 Data);
+
+	void (*EfusePowerSwitch)(struct adapter *padapter, u8 bWrite,
+				 u8 PwrState);
+	void (*ReadEFuse)(struct adapter *padapter, u8 efuseType, u16 _offset,
+			  u16 _size_byte, u8 *pbuf, bool bPseudoTest);
+	void (*EFUSEGetEfuseDefinition)(struct adapter *padapter, u8 efuseType,
+					u8 type, void *pOut, bool bPseudoTest);
+	u16	(*EfuseGetCurrentSize)(struct adapter *padapter, u8 efuseType,
+				       bool bPseudoTest);
+	int	(*Efuse_PgPacketRead)(struct adapter *adapter, u8 offset,
+				      u8 *data, bool bPseudoTest);
+	int	(*Efuse_PgPacketWrite)(struct adapter *padapter, u8 offset,
+				       u8 word_en, u8 *data, bool bPseudoTest);
+	u8	(*Efuse_WordEnableDataWrite)(struct adapter *padapter,
+					     u16 efuse_addr, u8 word_en,
+					     u8 *data, bool bPseudoTest);
+	bool	(*Efuse_PgPacketWrite_BT)(struct adapter *padapter, u8 offset,
+					  u8 word_en, u8 *data, bool test);
+
+	void (*sreset_init_value)(struct adapter *padapter);
+	void (*sreset_reset_value)(struct adapter *padapter);
+	void (*silentreset)(struct adapter *padapter);
+	void (*sreset_xmit_status_check)(struct adapter *padapter);
+	void (*sreset_linked_status_check) (struct adapter *padapter);
+	u8 (*sreset_get_wifi_status)(struct adapter *padapter);
+
+	int (*IOL_exec_cmds_sync)(struct adapter *padapter,
+				  struct xmit_frame *frame, u32 max_wait,
+				  u32 bndy_cnt);
+
+	void (*hal_notch_filter)(struct adapter *adapter, bool enable);
+	void (*hal_reset_security_engine)(struct adapter *adapter);
+	s32 (*c2h_handler)(struct adapter *padapter,
+			   struct c2h_evt_hdr *c2h_evt);
+	c2h_id_filter c2h_id_filter_ccx;
+};
+
+enum rt_eeprom_type {
+	EEPROM_93C46,
+	EEPROM_93C56,
+	EEPROM_BOOT_EFUSE,
+};
+
+#define RF_CHANGE_BY_INIT	0
+#define RF_CHANGE_BY_IPS	BIT28
+#define RF_CHANGE_BY_PS		BIT29
+#define RF_CHANGE_BY_HW		BIT30
+#define RF_CHANGE_BY_SW		BIT31
+
+enum hardware_type {
+	HARDWARE_TYPE_RTL8180,
+	HARDWARE_TYPE_RTL8185,
+	HARDWARE_TYPE_RTL8187,
+	HARDWARE_TYPE_RTL8188,
+	HARDWARE_TYPE_RTL8190P,
+	HARDWARE_TYPE_RTL8192E,
+	HARDWARE_TYPE_RTL819xU,
+	HARDWARE_TYPE_RTL8192SE,
+	HARDWARE_TYPE_RTL8192SU,
+	HARDWARE_TYPE_RTL8192CE,
+	HARDWARE_TYPE_RTL8192CU,
+	HARDWARE_TYPE_RTL8192DE,
+	HARDWARE_TYPE_RTL8192DU,
+	HARDWARE_TYPE_RTL8723AE,
+	HARDWARE_TYPE_RTL8723AU,
+	HARDWARE_TYPE_RTL8723AS,
+	HARDWARE_TYPE_RTL8188EE,
+	HARDWARE_TYPE_RTL8188EU,
+	HARDWARE_TYPE_RTL8188ES,
+	HARDWARE_TYPE_MAX,
+};
+
+/*  RTL8188E Series */
+#define IS_HARDWARE_TYPE_8188EE(_Adapter)			\
+(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188EE)
+#define IS_HARDWARE_TYPE_8188EU(_Adapter)			\
+(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188EU)
+#define IS_HARDWARE_TYPE_8188ES(_Adapter)			\
+(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188ES)
+#define	IS_HARDWARE_TYPE_8188E(_Adapter)	\
+(IS_HARDWARE_TYPE_8188EE(_Adapter) || IS_HARDWARE_TYPE_8188EU(_Adapter) || \
+ IS_HARDWARE_TYPE_8188ES(_Adapter))
+
+#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv)
+
+#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse)
+
+void rtw_hal_def_value_init(struct adapter *padapter);
+
+void	rtw_hal_free_data(struct adapter *padapter);
+
+void rtw_hal_dm_init(struct adapter *padapter);
+void rtw_hal_dm_deinit(struct adapter *padapter);
+void rtw_hal_sw_led_init(struct adapter *padapter);
+void rtw_hal_sw_led_deinit(struct adapter *padapter);
+
+u32 rtw_hal_power_on(struct adapter *padapter);
+uint rtw_hal_init(struct adapter *padapter);
+uint rtw_hal_deinit(struct adapter *padapter);
+void rtw_hal_stop(struct adapter *padapter);
+void rtw_hal_set_hwreg(struct adapter *padapter, u8 variable, u8 *val);
+void rtw_hal_get_hwreg(struct adapter *padapter, u8 variable, u8 *val);
+
+void rtw_hal_chip_configure(struct adapter *padapter);
+void rtw_hal_read_chip_info(struct adapter *padapter);
+void rtw_hal_read_chip_version(struct adapter *padapter);
+
+u8 rtw_hal_set_def_var(struct adapter *padapter,
+		       enum hal_def_variable eVariable, void *pValue);
+u8 rtw_hal_get_def_var(struct adapter *padapter,
+		       enum hal_def_variable eVariable, void *pValue);
+
+void rtw_hal_set_odm_var(struct adapter *padapter,
+			 enum hal_odm_variable eVariable, void *pValue1,
+			 bool bSet);
+void rtw_hal_get_odm_var(struct adapter *padapter,
+			 enum hal_odm_variable eVariable,
+			 void *pValue1, bool bSet);
+
+void rtw_hal_enable_interrupt(struct adapter *padapter);
+void rtw_hal_disable_interrupt(struct adapter *padapter);
+
+u32	rtw_hal_inirp_init(struct adapter *padapter);
+u32	rtw_hal_inirp_deinit(struct adapter *padapter);
+
+u8	rtw_hal_intf_ps_func(struct adapter *padapter,
+			     enum hal_intf_ps_func efunc_id, u8 *val);
+
+s32	rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe);
+s32	rtw_hal_mgnt_xmit(struct adapter *padapter,
+			  struct xmit_frame *pmgntframe);
+
+s32	rtw_hal_init_xmit_priv(struct adapter *padapter);
+void	rtw_hal_free_xmit_priv(struct adapter *padapter);
+
+s32	rtw_hal_init_recv_priv(struct adapter *padapter);
+void	rtw_hal_free_recv_priv(struct adapter *padapter);
+
+void rtw_hal_update_ra_mask(struct adapter *padapter, u32 mac_id, u8 level);
+void	rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg, u8 level);
+void	rtw_hal_clone_data(struct adapter *dst_adapt,
+			   struct adapter *src_adapt);
+void	rtw_hal_start_thread(struct adapter *padapter);
+void	rtw_hal_stop_thread(struct adapter *padapter);
+
+void rtw_hal_bcn_related_reg_setting(struct adapter *padapter);
+
+u32	rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask);
+void	rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask,
+			    u32 Data);
+u32	rtw_hal_read_rfreg(struct adapter *padapter, enum rf_radio_path eRFPath,
+			   u32 RegAddr, u32 BitMask);
+void	rtw_hal_write_rfreg(struct adapter *padapter,
+			    enum rf_radio_path eRFPath, u32 RegAddr,
+			    u32 BitMask, u32 Data);
+
+s32	rtw_hal_interrupt_handler(struct adapter *padapter);
+
+void	rtw_hal_set_bwmode(struct adapter *padapter,
+			   enum ht_channel_width Bandwidth, u8 Offset);
+void	rtw_hal_set_chan(struct adapter *padapter, u8 channel);
+void	rtw_hal_dm_watchdog(struct adapter *padapter);
+
+u8	rtw_hal_antdiv_before_linked(struct adapter *padapter);
+void	rtw_hal_antdiv_rssi_compared(struct adapter *padapter,
+				     struct wlan_bssid_ex *dst,
+				     struct wlan_bssid_ex *src);
+
+void rtw_hal_sreset_init(struct adapter *padapter);
+void rtw_hal_sreset_reset(struct adapter *padapter);
+void rtw_hal_sreset_reset_value(struct adapter *padapter);
+void rtw_hal_sreset_xmit_status_check(struct adapter *padapter);
+void rtw_hal_sreset_linked_status_check(struct adapter *padapter);
+u8   rtw_hal_sreset_get_wifi_status(struct adapter *padapter);
+
+int rtw_hal_iol_cmd(struct adapter  *adapter, struct xmit_frame *xmit_frame,
+		    u32 max_wating_ms, u32 bndy_cnt);
+
+void rtw_hal_notch_filter(struct adapter *adapter, bool enable);
+void rtw_hal_reset_security_engine(struct adapter *adapter);
+
+s32 rtw_hal_c2h_handler(struct adapter *adapter,
+			struct c2h_evt_hdr *c2h_evt);
+c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter);
+void indicate_wx_scan_complete_event(struct adapter *padapter);
+u8 rtw_do_join(struct adapter *padapter);
+
+#endif /* __HAL_INTF_H__ */
diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h
new file mode 100644
index 0000000..cd37ea4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ieee80211.h
@@ -0,0 +1,1274 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __IEEE80211_H
+#define __IEEE80211_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include "wifi.h"
+#include <linux/wireless.h>
+
+#define MGMT_QUEUE_NUM 5
+
+#define ETH_ALEN	6
+#define ETH_TYPE_LEN		2
+#define PAYLOAD_TYPE_LEN	1
+
+#ifdef CONFIG_88EU_AP_MODE
+
+#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28)
+
+/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+	RTL871X_HOSTAPD_FLUSH = 1,
+	RTL871X_HOSTAPD_ADD_STA = 2,
+	RTL871X_HOSTAPD_REMOVE_STA = 3,
+	RTL871X_HOSTAPD_GET_INFO_STA = 4,
+	/* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+	RTL871X_HOSTAPD_GET_WPAIE_STA = 5,
+	RTL871X_SET_ENCRYPTION = 6,
+	RTL871X_GET_ENCRYPTION = 7,
+	RTL871X_HOSTAPD_SET_FLAGS_STA = 8,
+	RTL871X_HOSTAPD_GET_RID = 9,
+	RTL871X_HOSTAPD_SET_RID = 10,
+	RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+	RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+	RTL871X_HOSTAPD_MLME = 13,
+	RTL871X_HOSTAPD_SCAN_REQ = 14,
+	RTL871X_HOSTAPD_STA_CLEAR_STATS = 15,
+	RTL871X_HOSTAPD_SET_BEACON = 16,
+	RTL871X_HOSTAPD_SET_WPS_BEACON = 17,
+	RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18,
+	RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19,
+	RTL871X_HOSTAPD_SET_HIDDEN_SSID = 20,
+	RTL871X_HOSTAPD_SET_MACADDR_ACL = 21,
+	RTL871X_HOSTAPD_ACL_ADD_STA = 22,
+	RTL871X_HOSTAPD_ACL_REMOVE_STA = 23,
+};
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3)
+#define WLAN_STA_PERM BIT(4)
+#define WLAN_STA_AUTHORIZED BIT(5)
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_MFP BIT(10)
+#define WLAN_STA_HT BIT(11)
+#define WLAN_STA_WPS BIT(12)
+#define WLAN_STA_MAYBE_WPS BIT(13)
+#define WLAN_STA_NONERP BIT(31)
+
+#endif
+
+#define IEEE_CMD_SET_WPA_PARAM			1
+#define IEEE_CMD_SET_WPA_IE				2
+#define IEEE_CMD_SET_ENCRYPTION			3
+#define IEEE_CMD_MLME						4
+
+#define IEEE_PARAM_WPA_ENABLED				1
+#define IEEE_PARAM_TKIP_COUNTERMEASURES		2
+#define IEEE_PARAM_DROP_UNENCRYPTED			3
+#define IEEE_PARAM_PRIVACY_INVOKED			4
+#define IEEE_PARAM_AUTH_ALGS					5
+#define IEEE_PARAM_IEEE_802_1X				6
+#define IEEE_PARAM_WPAX_SELECT				7
+
+#define AUTH_ALG_OPEN_SYSTEM			0x1
+#define AUTH_ALG_SHARED_KEY			0x2
+#define AUTH_ALG_LEAP				0x00000004
+
+#define IEEE_MLME_STA_DEAUTH				1
+#define IEEE_MLME_STA_DISASSOC			2
+
+#define IEEE_CRYPT_ERR_UNKNOWN_ALG			2
+#define IEEE_CRYPT_ERR_UNKNOWN_ADDR			3
+#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED		4
+#define IEEE_CRYPT_ERR_KEY_SET_FAILED			5
+#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED		6
+#define IEEE_CRYPT_ERR_CARD_CONF_FAILED		7
+
+
+#define	IEEE_CRYPT_ALG_NAME_LEN			16
+
+#define WPA_CIPHER_NONE		BIT(0)
+#define WPA_CIPHER_WEP40	BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP		BIT(3)
+#define WPA_CIPHER_CCMP		BIT(4)
+
+
+
+#define WPA_SELECTOR_LEN 4
+extern u8 RTW_WPA_OUI_TYPE[];
+extern u16 RTW_WPA_VERSION;
+extern u8 WPA_AUTH_KEY_MGMT_NONE[];
+extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[];
+extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[];
+extern u8 WPA_CIPHER_SUITE_NONE[];
+extern u8 WPA_CIPHER_SUITE_WEP40[];
+extern u8 WPA_CIPHER_SUITE_TKIP[];
+extern u8 WPA_CIPHER_SUITE_WRAP[];
+extern u8 WPA_CIPHER_SUITE_CCMP[];
+extern u8 WPA_CIPHER_SUITE_WEP104[];
+
+
+#define RSN_HEADER_LEN 4
+#define RSN_SELECTOR_LEN 4
+
+extern u16 RSN_VERSION_BSD;
+extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[];
+extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[];
+extern u8 RSN_CIPHER_SUITE_NONE[];
+extern u8 RSN_CIPHER_SUITE_WEP40[];
+extern u8 RSN_CIPHER_SUITE_TKIP[];
+extern u8 RSN_CIPHER_SUITE_WRAP[];
+extern u8 RSN_CIPHER_SUITE_CCMP[];
+extern u8 RSN_CIPHER_SUITE_WEP104[];
+
+enum ratr_table_mode {
+	RATR_INX_WIRELESS_NGB = 0,	/*  BGN 40 Mhz 2SS 1SS */
+	RATR_INX_WIRELESS_NG = 1,	/*  GN or N */
+	RATR_INX_WIRELESS_NB = 2,	/*  BGN 20 Mhz 2SS 1SS  or BN */
+	RATR_INX_WIRELESS_N = 3,
+	RATR_INX_WIRELESS_GB = 4,
+	RATR_INX_WIRELESS_G = 5,
+	RATR_INX_WIRELESS_B = 6,
+	RATR_INX_WIRELESS_MC = 7,
+	RATR_INX_WIRELESS_AC_N = 8,
+};
+
+enum NETWORK_TYPE {
+	WIRELESS_INVALID = 0,
+	/* Sub-Element */
+	WIRELESS_11B = BIT(0), /* tx:cck only, rx:cck only, hw: cck */
+	WIRELESS_11G = BIT(1), /* tx:ofdm only, rx:ofdm & cck, hw:cck & ofdm*/
+	WIRELESS_11A = BIT(2), /* tx:ofdm only, rx: ofdm only, hw:ofdm only */
+	WIRELESS_11_24N = BIT(3), /* tx:MCS only, rx:MCS & cck, hw:MCS & cck */
+	WIRELESS_11_5N = BIT(4), /* tx:MCS only, rx:MCS & ofdm, hw:ofdm only */
+	WIRELESS_AC		= BIT(6),
+
+	/* Combination */
+	/*  tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */
+	WIRELESS_11BG = (WIRELESS_11B | WIRELESS_11G),
+	/*  tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */
+	WIRELESS_11G_24N = (WIRELESS_11G | WIRELESS_11_24N),
+	/*  tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
+	WIRELESS_11A_5N = (WIRELESS_11A | WIRELESS_11_5N),
+	/*  tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */
+	WIRELESS_11BG_24N = (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N),
+	/*  tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
+	WIRELESS_11AGN = (WIRELESS_11A | WIRELESS_11G | WIRELESS_11_24N |
+			  WIRELESS_11_5N),
+	WIRELESS_11ABGN = (WIRELESS_11A | WIRELESS_11B | WIRELESS_11G |
+			   WIRELESS_11_24N | WIRELESS_11_5N),
+};
+
+#define SUPPORTED_24G_NETTYPE_MSK				\
+	 (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N)
+#define SUPPORTED_5G_NETTYPE_MSK				\
+	 (WIRELESS_11A | WIRELESS_11_5N)
+
+#define IsSupported24G(NetType)					\
+	((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false)
+#define IsSupported5G(NetType)					\
+	((NetType) & SUPPORTED_5G_NETTYPE_MSK ? true : false)
+
+#define IsEnableHWCCK(NetType)					\
+	IsSupported24G(NetType)
+#define IsEnableHWOFDM(NetType)					\
+	((NetType) & (WIRELESS_11G | WIRELESS_11_24N |		\
+	 SUPPORTED_5G_NETTYPE_MSK) ? true : false)
+
+#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType)
+#define IsSupportedRxOFDM(NetType) IsEnableHWOFDM(NetType)
+#define IsSupportedRxMCS(NetType) IsEnableHWOFDM(NetType)
+
+#define IsSupportedTxCCK(NetType)				\
+	((NetType) & (WIRELESS_11B) ? true : false)
+#define IsSupportedTxOFDM(NetType)				\
+	((NetType) & (WIRELESS_11G|WIRELESS_11A) ? true : false)
+#define IsSupportedTxMCS(NetType)				\
+	((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N) ? true : false)
+
+
+struct ieee_param {
+	u32 cmd;
+	u8 sta_addr[ETH_ALEN];
+	union {
+		struct {
+			u8 name;
+			u32 value;
+		} wpa_param;
+		struct {
+			u32 len;
+			u8 reserved[32];
+			u8 data[0];
+		} wpa_ie;
+		struct {
+			int command;
+			int reason_code;
+		} mlme;
+		struct {
+			u8 alg[IEEE_CRYPT_ALG_NAME_LEN];
+			u8 set_tx;
+			u32 err;
+			u8 idx;
+			u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+			u16 key_len;
+			u8 key[0];
+		} crypt;
+#ifdef CONFIG_88EU_AP_MODE
+		struct {
+			u16 aid;
+			u16 capability;
+			int flags;
+			u8 tx_supp_rates[16];
+			struct rtw_ieee80211_ht_cap ht_cap;
+		} add_sta;
+		struct {
+			u8	reserved[2];/* for set max_num_sta */
+			u8	buf[0];
+		} bcn_ie;
+#endif
+
+	} u;
+};
+
+#ifdef CONFIG_88EU_AP_MODE
+struct ieee_param_ex {
+	u32 cmd;
+	u8 sta_addr[ETH_ALEN];
+	u8 data[0];
+};
+
+struct sta_data {
+	u16 aid;
+	u16 capability;
+	int flags;
+	u32 sta_set;
+	u8 tx_supp_rates[16];
+	u32 tx_supp_rates_len;
+	struct rtw_ieee80211_ht_cap ht_cap;
+	u64	rx_pkts;
+	u64	rx_bytes;
+	u64	rx_drops;
+	u64	tx_pkts;
+	u64	tx_bytes;
+	u64	tx_drops;
+};
+#endif
+
+#define IEEE80211_DATA_LEN		2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN			30
+#define IEEE80211_FRAME_LEN		(IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+
+/* this is stolen from ipw2200 driver */
+#define IEEE_IBSS_MAC_HASH_SIZE 31
+
+struct ieee_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+struct rtw_ieee80211_hdr {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+} __packed;
+
+struct rtw_ieee80211_hdr_3addr {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+} __packed;
+
+struct rtw_ieee80211_hdr_qos {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u8 addr4[ETH_ALEN];
+	u16	qc;
+}  __packed;
+
+struct rtw_ieee80211_hdr_3addr_qos {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+	u8 addr3[ETH_ALEN];
+	u16 seq_ctl;
+	u16     qc;
+}  __packed;
+
+struct eapol {
+	u8 snap[6];
+	u16 ethertype;
+	u8 version;
+	u8 type;
+	u16 length;
+} __packed;
+
+enum eap_type {
+	EAP_PACKET = 0,
+	EAPOL_START,
+	EAPOL_LOGOFF,
+	EAPOL_KEY,
+	EAPOL_ENCAP_ASF_ALERT
+};
+
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN    4
+
+#define MIN_FRAG_THRESHOLD     256U
+#define	MAX_FRAG_THRESHOLD     2346U
+
+/* Frame control field constants */
+#define RTW_IEEE80211_FCTL_VERS		0x0003
+#define RTW_IEEE80211_FCTL_FTYPE	0x000c
+#define RTW_IEEE80211_FCTL_STYPE	0x00f0
+#define RTW_IEEE80211_FCTL_TODS		0x0100
+#define RTW_IEEE80211_FCTL_FROMDS	0x0200
+#define RTW_IEEE80211_FCTL_MOREFRAGS	0x0400
+#define RTW_IEEE80211_FCTL_RETRY	0x0800
+#define RTW_IEEE80211_FCTL_PM		0x1000
+#define RTW_IEEE80211_FCTL_MOREDATA	0x2000
+#define RTW_IEEE80211_FCTL_PROTECTED	0x4000
+#define RTW_IEEE80211_FCTL_ORDER	0x8000
+#define RTW_IEEE80211_FCTL_CTL_EXT	0x0f00
+
+#define RTW_IEEE80211_FTYPE_MGMT	0x0000
+#define RTW_IEEE80211_FTYPE_CTL		0x0004
+#define RTW_IEEE80211_FTYPE_DATA	0x0008
+#define RTW_IEEE80211_FTYPE_EXT		0x000c
+
+/* management */
+#define RTW_IEEE80211_STYPE_ASSOC_REQ	0x0000
+#define RTW_IEEE80211_STYPE_ASSOC_RESP	0x0010
+#define RTW_IEEE80211_STYPE_REASSOC_REQ	0x0020
+#define RTW_IEEE80211_STYPE_REASSOC_RESP	0x0030
+#define RTW_IEEE80211_STYPE_PROBE_REQ	0x0040
+#define RTW_IEEE80211_STYPE_PROBE_RESP	0x0050
+#define RTW_IEEE80211_STYPE_BEACON	0x0080
+#define RTW_IEEE80211_STYPE_ATIM	0x0090
+#define RTW_IEEE80211_STYPE_DISASSOC	0x00A0
+#define RTW_IEEE80211_STYPE_AUTH	0x00B0
+#define RTW_IEEE80211_STYPE_DEAUTH	0x00C0
+#define RTW_IEEE80211_STYPE_ACTION	0x00D0
+
+/* control */
+#define RTW_IEEE80211_STYPE_CTL_EXT	0x0060
+#define RTW_IEEE80211_STYPE_BACK_REQ	0x0080
+#define RTW_IEEE80211_STYPE_BACK	0x0090
+#define RTW_IEEE80211_STYPE_PSPOLL	0x00A0
+#define RTW_IEEE80211_STYPE_RTS		0x00B0
+#define RTW_IEEE80211_STYPE_CTS		0x00C0
+#define RTW_IEEE80211_STYPE_ACK		0x00D0
+#define RTW_IEEE80211_STYPE_CFEND	0x00E0
+#define RTW_IEEE80211_STYPE_CFENDACK	0x00F0
+
+/* data */
+#define RTW_IEEE80211_STYPE_DATA	0x0000
+#define RTW_IEEE80211_STYPE_DATA_CFACK	0x0010
+#define RTW_IEEE80211_STYPE_DATA_CFPOLL	0x0020
+#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL	0x0030
+#define RTW_IEEE80211_STYPE_NULLFUNC	0x0040
+#define RTW_IEEE80211_STYPE_CFACK	0x0050
+#define RTW_IEEE80211_STYPE_CFPOLL	0x0060
+#define RTW_IEEE80211_STYPE_CFACKPOLL	0x0070
+#define RTW_IEEE80211_STYPE_QOS_DATA	0x0080
+#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK	0x0090
+#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL	0x00A0
+#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL	0x00B0
+#define RTW_IEEE80211_STYPE_QOS_NULLFUNC	0x00C0
+#define RTW_IEEE80211_STYPE_QOS_CFACK		0x00D0
+#define RTW_IEEE80211_STYPE_QOS_CFPOLL		0x00E0
+#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL	0x00F0
+
+/* sequence control field */
+#define RTW_IEEE80211_SCTL_FRAG	0x000F
+#define RTW_IEEE80211_SCTL_SEQ	0xFFF0
+
+
+#define RTW_ERP_INFO_NON_ERP_PRESENT BIT(0)
+#define RTW_ERP_INFO_USE_PROTECTION BIT(1)
+#define RTW_ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+
+/* QoS, QOS */
+#define NORMAL_ACK			0
+#define NO_ACK				1
+#define NON_EXPLICIT_ACK		2
+#define BLOCK_ACK			3
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#define ETH_P_ECONET	0x0018
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+	u8    dsap;   /* always 0xAA */
+	u8    ssap;   /* always 0xAA */
+	u8    ctrl;   /* always 0x03 */
+	u8    oui[P80211_OUI_LEN];    /* organizational universal id */
+} __packed;
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE)
+
+#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq)  ((seq) & RTW_IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+#define WLAN_CAPABILITY_SHORT_SLOT (1<<10)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+#define WLAN_REASON_JOIN_WRONG_CHANNEL       65534
+#define WLAN_REASON_EXPIRATION_CHK 65535
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_MOBILITY_DOMAIN 54
+#define WLAN_EID_FAST_BSS_TRANSITION 55
+#define WLAN_EID_TIMEOUT_INTERVAL 56
+#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_HT_OPERATION 61
+#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_20_40_BSS_COEXISTENCE 72
+#define WLAN_EID_20_40_BSS_INTOLERANT 73
+#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_MMIE 76
+#define WLAN_EID_VENDOR_SPECIFIC 221
+#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC)
+
+#define IEEE80211_MGMT_HDR_LEN 24
+#define IEEE80211_DATA_HDR3_LEN 24
+#define IEEE80211_DATA_HDR4_LEN 30
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION    (1<<0)
+#define IEEE80211_OFDM_MODULATION   (1<<1)
+
+#define IEEE80211_24GHZ_BAND     (1<<0)
+#define IEEE80211_52GHZ_BAND     (1<<1)
+
+#define IEEE80211_CCK_RATE_LEN			4
+#define IEEE80211_NUM_OFDM_RATESLEN	8
+
+
+#define IEEE80211_CCK_RATE_1MB			0x02
+#define IEEE80211_CCK_RATE_2MB			0x04
+#define IEEE80211_CCK_RATE_5MB			0x0B
+#define IEEE80211_CCK_RATE_11MB			0x16
+#define IEEE80211_OFDM_RATE_LEN			8
+#define IEEE80211_OFDM_RATE_6MB			0x0C
+#define IEEE80211_OFDM_RATE_9MB			0x12
+#define IEEE80211_OFDM_RATE_12MB		0x18
+#define IEEE80211_OFDM_RATE_18MB		0x24
+#define IEEE80211_OFDM_RATE_24MB		0x30
+#define IEEE80211_OFDM_RATE_36MB		0x48
+#define IEEE80211_OFDM_RATE_48MB		0x60
+#define IEEE80211_OFDM_RATE_54MB		0x6C
+#define IEEE80211_BASIC_RATE_MASK		0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK		(1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK		(1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK		(1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK		(1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK		(1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK		(1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK		(1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK		(1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK		(1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK		(1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK		(1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK		(1<<11)
+
+#define IEEE80211_CCK_RATES_MASK		0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK	(IEEE80211_CCK_RATE_1MB_MASK | \
+	IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK				\
+	(IEEE80211_CCK_BASIC_RATES_MASK |				\
+	IEEE80211_CCK_RATE_5MB_MASK |					\
+	IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK		0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK	(IEEE80211_OFDM_RATE_6MB_MASK | \
+	IEEE80211_OFDM_RATE_12MB_MASK |					\
+	IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK				\
+	(IEEE80211_OFDM_BASIC_RATES_MASK |				\
+	IEEE80211_OFDM_RATE_9MB_MASK  |					\
+	IEEE80211_OFDM_RATE_18MB_MASK |					\
+	IEEE80211_OFDM_RATE_36MB_MASK |					\
+	IEEE80211_OFDM_RATE_48MB_MASK |					\
+	IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK					\
+	(IEEE80211_OFDM_DEFAULT_RATES_MASK |				\
+	 IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES	8
+#define IEEE80211_NUM_CCK_RATES		4
+#define IEEE80211_OFDM_SHIFT_MASK_A	4
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ *       information for frames received.  Not setting these will not cause
+ *       any adverse affects. */
+struct ieee80211_rx_stats {
+	/* u32 mac_time[2]; */
+	s8 rssi;
+	u8 signal;
+	u8 noise;
+	u8 received_channel;
+	u16 rate; /* in 100 kbps */
+	/* u8 control; */
+	u8 mask;
+	u8 freq;
+	u16 len;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+	u32 first_frag_time;
+	uint seq;
+	uint last_frag;
+	uint qos;   /* jackson */
+	uint tid;	/* jackson */
+	struct sk_buff *skb;
+	u8 src_addr[ETH_ALEN];
+	u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+	uint tx_unicast_frames;
+	uint tx_multicast_frames;
+	uint tx_fragments;
+	uint tx_unicast_octets;
+	uint tx_multicast_octets;
+	uint tx_deferred_transmissions;
+	uint tx_single_retry_frames;
+	uint tx_multiple_retry_frames;
+	uint tx_retry_limit_exceeded;
+	uint tx_discards;
+	uint rx_unicast_frames;
+	uint rx_multicast_frames;
+	uint rx_fragments;
+	uint rx_unicast_octets;
+	uint rx_multicast_octets;
+	uint rx_fcs_errors;
+	uint rx_discards_no_buffer;
+	uint tx_discards_wrong_sa;
+	uint rx_discards_undecryptable;
+	uint rx_message_in_msg_fragments;
+	uint rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_softmac_stats {
+	uint rx_ass_ok;
+	uint rx_ass_err;
+	uint rx_probe_rq;
+	uint tx_probe_rs;
+	uint tx_beacons;
+	uint rx_auth_rq;
+	uint rx_auth_rs_ok;
+	uint rx_auth_rs_err;
+	uint tx_auth_rq;
+	uint no_auth_rs;
+	uint no_ass_rs;
+	uint tx_ass_rq;
+	uint rx_ass_rq;
+	uint tx_probe_rq;
+	uint reassoc;
+	uint swtxstop;
+	uint swtxawake;
+};
+
+#define SEC_KEY_1	(1<<0)
+#define SEC_KEY_2	(1<<1)
+#define SEC_KEY_3	(1<<2)
+#define SEC_KEY_4	(1<<3)
+#define SEC_ACTIVE_KEY  (1<<4)
+#define SEC_AUTH_MODE   (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL	(1<<7)
+#define SEC_ENABLED     (1<<8)
+
+#define SEC_LEVEL_0      0 /* None */
+#define SEC_LEVEL_1      1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2      2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3      4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+struct ieee80211_security {
+	u16 active_key:2,
+	enabled:1,
+	auth_mode:2,
+	auth_algo:4,
+	unicast_uses_group:1;
+	u8 key_sizes[WEP_KEYS];
+	u8 keys[WEP_KEYS][WEP_KEY_LEN];
+	u8 level;
+	u16 flags;
+} __packed;
+
+/*
+
+ 802.11 data frame from AP
+
+      ,-------------------------------------------------------------------.
+Bytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
+      |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  frame  |  fcs |
+      |      | tion | (BSSID) |	 |	 | ence |  data   |      |
+      `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+struct ieee80211_header_data {
+	u16 frame_ctl;
+	u16 duration_id;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	u16 seq_ctrl;
+};
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID		0
+#define MFIE_TYPE_RATES		1
+#define MFIE_TYPE_FH_SET	2
+#define MFIE_TYPE_DS_SET	3
+#define MFIE_TYPE_CF_SET	4
+#define MFIE_TYPE_TIM		5
+#define MFIE_TYPE_IBSS_SET	6
+#define MFIE_TYPE_CHALLENGE	16
+#define MFIE_TYPE_ERP		42
+#define MFIE_TYPE_RSN		48
+#define MFIE_TYPE_RATES_EX	50
+#define MFIE_TYPE_GENERIC	221
+
+struct ieee80211_info_element_hdr {
+	u8 id;
+	u8 len;
+} __packed;
+
+struct ieee80211_info_element {
+	u8 id;
+	u8 len;
+	u8 data[0];
+} __packed;
+
+/*
+ * These are the data types that can make up management packets
+ *
+	u16 auth_algorithm;
+	u16 auth_sequence;
+	u16 beacon_interval;
+	u16 capability;
+	u8 current_ap[ETH_ALEN];
+	u16 listen_interval;
+	struct {
+		u16 association_id:14, reserved:2;
+	} __packed;
+	u32 time_stamp[2];
+	u16 reason;
+	u16 status;
+*/
+
+#define IEEE80211_DEFAULT_TX_ESSID "Penguin"
+#define IEEE80211_DEFAULT_BASIC_RATE 10
+
+struct ieee80211_authentication {
+	struct ieee80211_header_data header;
+	u16 algorithm;
+	u16 transaction;
+	u16 status;
+	/* struct ieee80211_info_element_hdr info_element; */
+} __packed;
+
+struct ieee80211_probe_response {
+	struct ieee80211_header_data header;
+	u32 time_stamp[2];
+	u16 beacon_interval;
+	u16 capability;
+	struct ieee80211_info_element info_element;
+} __packed;
+
+struct ieee80211_probe_request {
+	struct ieee80211_header_data header;
+} __packed;
+
+struct ieee80211_assoc_request_frame {
+	struct rtw_ieee80211_hdr_3addr header;
+	u16 capability;
+	u16 listen_interval;
+	struct ieee80211_info_element_hdr info_element;
+} __packed;
+
+struct ieee80211_assoc_response_frame {
+	struct rtw_ieee80211_hdr_3addr header;
+	u16 capability;
+	u16 status;
+	u16 aid;
+} __packed;
+
+struct ieee80211_txb {
+	u8 nr_frags;
+	u8 encrypted;
+	u16 reserved;
+	u16 frag_size;
+	u16 payload_size;
+	struct sk_buff *fragments[0];
+};
+
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES		  42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET  7
+/* MAX_RATES_LENGTH needs to be 12.  The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates.  Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH		((u8)12)
+#define MAX_RATES_EX_LENGTH		((u8)16)
+#define MAX_NETWORK_COUNT		128
+#define MAX_CHANNEL_NUMBER		161
+#define IEEE80211_SOFTMAC_SCAN_TIME	400
+/* HZ / 2) */
+#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2)
+
+#define CRC_LENGTH		 4U
+
+#define MAX_WPA_IE_LEN (256)
+#define MAX_WPS_IE_LEN (512)
+#define MAX_P2P_IE_LEN (256)
+#define MAX_WFD_IE_LEN (128)
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM    (1<<1)
+#define NETWORK_HAS_CCK     (1<<2)
+
+#define IEEE80211_DTIM_MBCAST 4
+#define IEEE80211_DTIM_UCAST 2
+#define IEEE80211_DTIM_VALID 1
+#define IEEE80211_DTIM_INVALID 0
+
+#define IEEE80211_PS_DISABLED 0
+#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST
+#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST
+#define IW_ESSID_MAX_SIZE 32
+/*
+join_res:
+-1: authentication fail
+-2: association fail
+> 0: TID
+*/
+
+enum ieee80211_state {
+	/* the card is not linked at all */
+	IEEE80211_NOLINK = 0,
+
+	/* IEEE80211_ASSOCIATING* are for BSS client mode
+	 * the driver shall not perform RX filtering unless
+	 * the state is LINKED.
+	 * The driver shall just check for the state LINKED and
+	 * defaults to NOLINK for ALL the other states (including
+	 * LINKED_SCANNING)
+	 */
+
+	/* the association procedure will start (wq scheduling)*/
+	IEEE80211_ASSOCIATING,
+	IEEE80211_ASSOCIATING_RETRY,
+
+	/* the association procedure is sending AUTH request*/
+	IEEE80211_ASSOCIATING_AUTHENTICATING,
+
+	/* the association procedure has successfully authentcated
+	 * and is sending association request
+	 */
+	IEEE80211_ASSOCIATING_AUTHENTICATED,
+
+	/* the link is ok. the card associated to a BSS or linked
+	 * to a ibss cell or acting as an AP and creating the bss
+	 */
+	IEEE80211_LINKED,
+
+	/* same as LINKED, but the driver shall apply RX filter
+	 * rules as we are in NO_LINK mode. As the card is still
+	 * logically linked, but it is doing a syncro site survey
+	 * then it will be back to LINKED state.
+	 */
+	IEEE80211_LINKED_SCANNING,
+
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+
+static inline int is_multicast_mac_addr(const u8 *addr)
+{
+	return ((addr[0] != 0xff) && (0x01 & addr[0]));
+}
+
+static inline int is_broadcast_mac_addr(const u8 *addr)
+{
+	return (addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) &&
+	       (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff);
+}
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+struct tx_pending {
+	int frag;
+	struct ieee80211_txb *txb;
+};
+
+#define MAXTID	16
+
+#define IEEE_A	    (1<<0)
+#define IEEE_B	    (1<<1)
+#define IEEE_G	    (1<<2)
+#define IEEE_MODE_MASK    (IEEE_A|IEEE_B|IEEE_G)
+
+/* Baron move to ieee80211.c */
+int ieee80211_is_empty_essid(const char *essid, int essid_len);
+int ieee80211_get_hdrlen(u16 fc);
+
+/* Action category code */
+enum rtw_ieee80211_category {
+	RTW_WLAN_CATEGORY_SPECTRUM_MGMT = 0,
+	RTW_WLAN_CATEGORY_QOS = 1,
+	RTW_WLAN_CATEGORY_DLS = 2,
+	RTW_WLAN_CATEGORY_BACK = 3,
+	RTW_WLAN_CATEGORY_PUBLIC = 4, /* IEEE 802.11 public action frames */
+	RTW_WLAN_CATEGORY_RADIO_MEASUREMENT  = 5,
+	RTW_WLAN_CATEGORY_FT = 6,
+	RTW_WLAN_CATEGORY_HT = 7,
+	RTW_WLAN_CATEGORY_SA_QUERY = 8,
+	RTW_WLAN_CATEGORY_TDLS = 12,
+	RTW_WLAN_CATEGORY_WMM = 17,
+	RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */
+};
+
+/* SPECTRUM_MGMT action code */
+enum rtw_ieee80211_spectrum_mgmt_actioncode {
+	RTW_WLAN_ACTION_SPCT_MSR_REQ = 0,
+	RTW_WLAN_ACTION_SPCT_MSR_RPRT = 1,
+	RTW_WLAN_ACTION_SPCT_TPC_REQ = 2,
+	RTW_WLAN_ACTION_SPCT_TPC_RPRT = 3,
+	RTW_WLAN_ACTION_SPCT_CHL_SWITCH = 4,
+	RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5,
+};
+
+enum _PUBLIC_ACTION {
+	ACT_PUBLIC_BSSCOEXIST = 0, /*  20/40 BSS Coexistence */
+	ACT_PUBLIC_DSE_ENABLE = 1,
+	ACT_PUBLIC_DSE_DEENABLE = 2,
+	ACT_PUBLIC_DSE_REG_LOCATION = 3,
+	ACT_PUBLIC_EXT_CHL_SWITCH = 4,
+	ACT_PUBLIC_DSE_MSR_REQ = 5,
+	ACT_PUBLIC_DSE_MSR_RPRT = 6,
+	ACT_PUBLIC_MP = 7, /*  Measurement Pilot */
+	ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8,
+	ACT_PUBLIC_VENDOR = 9, /*  for WIFI_DIRECT */
+	ACT_PUBLIC_GAS_INITIAL_REQ = 10,
+	ACT_PUBLIC_GAS_INITIAL_RSP = 11,
+	ACT_PUBLIC_GAS_COMEBACK_REQ = 12,
+	ACT_PUBLIC_GAS_COMEBACK_RSP = 13,
+	ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14,
+	ACT_PUBLIC_LOCATION_TRACK = 15,
+	ACT_PUBLIC_MAX
+};
+
+/* BACK action code */
+enum rtw_ieee80211_back_actioncode {
+	RTW_WLAN_ACTION_ADDBA_REQ = 0,
+	RTW_WLAN_ACTION_ADDBA_RESP = 1,
+	RTW_WLAN_ACTION_DELBA = 2,
+};
+
+/* HT features action code */
+enum rtw_ieee80211_ht_actioncode {
+	RTW_WLAN_ACTION_NOTIFY_CH_WIDTH = 0,
+	RTW_WLAN_ACTION_SM_PS = 1,
+	RTW_WLAN_ACTION_PSPM = 2,
+	RTW_WLAN_ACTION_PCO_PHASE = 3,
+	RTW_WLAN_ACTION_MIMO_CSI_MX = 4,
+	RTW_WLAN_ACTION_MIMO_NONCP_BF = 5,
+	RTW_WLAN_ACTION_MIMP_CP_BF = 6,
+	RTW_WLAN_ACTION_ASEL_INDICATES_FB = 7,
+	RTW_WLAN_ACTION_HI_INFO_EXCHG = 8,
+};
+
+/* BACK (block-ack) parties */
+enum rtw_ieee80211_back_parties {
+	RTW_WLAN_BACK_RECIPIENT = 0,
+	RTW_WLAN_BACK_INITIATOR = 1,
+	RTW_WLAN_BACK_TIMER = 2,
+};
+
+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
+				* 00:50:F2 */
+#define WME_OUI_TYPE 2
+#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WME_VERSION 1
+
+#define WME_ACTION_CODE_SETUP_REQUEST 0
+#define WME_ACTION_CODE_SETUP_RESPONSE 1
+#define WME_ACTION_CODE_TEARDOWN 2
+
+#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0
+#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1
+#define WME_SETUP_RESPONSE_STATUS_REFUSED 3
+
+#define WME_TSPEC_DIRECTION_UPLINK 0
+#define WME_TSPEC_DIRECTION_DOWNLINK 1
+#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+/**
+ * enum rtw_ieee80211_channel_flags - channel flags
+ *
+ * Channel flags set by the regulatory control code.
+ *
+ * @RTW_IEEE80211_CHAN_DISABLED: This channel is disabled.
+ * @RTW_IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
+ *      on this channel.
+ * @RTW_IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
+ * @RTW_IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ * @RTW_IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel
+ *      is not permitted.
+ * @RTW_IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel
+ *      is not permitted.
+ */
+enum rtw_ieee80211_channel_flags {
+	RTW_IEEE80211_CHAN_DISABLED	 = 1<<0,
+	RTW_IEEE80211_CHAN_PASSIVE_SCAN     = 1<<1,
+	RTW_IEEE80211_CHAN_NO_IBSS	  = 1<<2,
+	RTW_IEEE80211_CHAN_RADAR	    = 1<<3,
+	RTW_IEEE80211_CHAN_NO_HT40PLUS      = 1<<4,
+	RTW_IEEE80211_CHAN_NO_HT40MINUS     = 1<<5,
+};
+
+#define RTW_IEEE80211_CHAN_NO_HT40 \
+	  (RTW_IEEE80211_CHAN_NO_HT40PLUS | RTW_IEEE80211_CHAN_NO_HT40MINUS)
+
+/* Represent channel details, subset of ieee80211_channel */
+struct rtw_ieee80211_channel {
+	u16 hw_value;
+	u32 flags;
+};
+
+#define CHAN_FMT \
+	"hw_value:%u, " \
+	"flags:0x%08x" \
+
+#define CHAN_ARG(channel) \
+	(channel)->hw_value \
+	, (channel)->flags \
+
+/* Parsed Information Elements */
+struct rtw_ieee802_11_elems {
+	u8 *ssid;
+	u8 ssid_len;
+	u8 *supp_rates;
+	u8 supp_rates_len;
+	u8 *fh_params;
+	u8 fh_params_len;
+	u8 *ds_params;
+	u8 ds_params_len;
+	u8 *cf_params;
+	u8 cf_params_len;
+	u8 *tim;
+	u8 tim_len;
+	u8 *ibss_params;
+	u8 ibss_params_len;
+	u8 *challenge;
+	u8 challenge_len;
+	u8 *erp_info;
+	u8 erp_info_len;
+	u8 *ext_supp_rates;
+	u8 ext_supp_rates_len;
+	u8 *wpa_ie;
+	u8 wpa_ie_len;
+	u8 *rsn_ie;
+	u8 rsn_ie_len;
+	u8 *wme;
+	u8 wme_len;
+	u8 *wme_tspec;
+	u8 wme_tspec_len;
+	u8 *wps_ie;
+	u8 wps_ie_len;
+	u8 *power_cap;
+	u8 power_cap_len;
+	u8 *supp_channels;
+	u8 supp_channels_len;
+	u8 *mdie;
+	u8 mdie_len;
+	u8 *ftie;
+	u8 ftie_len;
+	u8 *timeout_int;
+	u8 timeout_int_len;
+	u8 *ht_capabilities;
+	u8 ht_capabilities_len;
+	u8 *ht_operation;
+	u8 ht_operation_len;
+	u8 *vendor_ht_cap;
+	u8 vendor_ht_cap_len;
+};
+
+enum parse_res {
+	ParseOK = 0,
+	ParseUnknown = 1,
+	ParseFailed = -1
+};
+
+enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len,
+					  struct rtw_ieee802_11_elems *elems,
+					  int show_errors);
+
+u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len,
+		     unsigned char *source, unsigned int *frlen);
+u8 *rtw_set_ie(u8 *pbuf, int index, uint len, u8 *source, uint *frlen);
+
+enum secondary_ch_offset {
+	SCN = 0, /* no secondary channel */
+	SCA = 1, /* secondary channel above */
+	SCB = 3,  /* secondary channel below */
+};
+u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset);
+u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset);
+u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode,
+			 u8 new_ch, u8 ch_switch_cnt);
+u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len,
+				   u8 secondary_ch_offset);
+u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
+				   u8 flags, u16 reason, u16 precedence);
+
+u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit);
+u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui,
+		  u8 oui_len, u8 *ie, uint *ielen);
+int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset,
+		      u8 eid, u8 *oui, u8 oui_len);
+
+void rtw_set_supported_rate(u8 *SupportedRates, uint mode);
+
+unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit);
+unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit);
+int rtw_get_wpa_cipher_suite(u8 *s);
+int rtw_get_wpa2_cipher_suite(u8 *s);
+int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len);
+int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
+		     int *pairwise_cipher, int *is_8021x);
+int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher,
+		      int *pairwise_cipher, int *is_8021x);
+
+int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
+		   u8 *wpa_ie, u16 *wpa_len);
+
+u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
+u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
+u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id,
+		     u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id,
+			     u8 *buf_content, uint *len_content);
+
+/**
+ * for_each_ie - iterate over continuous IEs
+ * @ie:
+ * @buf:
+ * @buf_len:
+ */
+#define for_each_ie(ie, buf, buf_len) \
+	for (ie = (void *)buf; (((u8 *)ie) - ((u8 *)buf) + 1) < buf_len;	\
+		ie = (void *)(((u8 *)ie) + *(((u8 *)ie)+1) + 2))
+
+void dump_ies(u8 *buf, u32 buf_len);
+void dump_wps_ie(u8 *ie, u32 ie_len);
+
+#ifdef CONFIG_88EU_P2P
+void dump_p2p_ie(u8 *ie, u32 ie_len);
+u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen);
+u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id,
+		     u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id,
+			     u8 *buf_content, uint *len_content);
+u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len,
+			     u8 *pdata_attr);
+void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex,
+				       u8 attr_id);
+#endif
+
+uint	rtw_get_rateset_len(u8	*rateset);
+
+struct registry_priv;
+int rtw_generate_ie(struct registry_priv *pregistrypriv);
+
+
+int rtw_get_bit_value_from_ieee_value(u8 val);
+
+uint	rtw_is_cckrates_included(u8 *rate);
+
+uint	rtw_is_cckratesonly_included(u8 *rate);
+
+int rtw_check_network_type(unsigned char *rate, int ratelen, int channel);
+
+void rtw_get_bcn_info(struct wlan_network *pnetwork);
+
+void rtw_macaddr_cfg(u8 *mac_addr);
+
+u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40,
+		 unsigned char *MCS_rate);
+
+int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category,
+			   u8 *action);
+const char *action_public_str(u8 action);
+
+#endif /* IEEE80211_H */
diff --git a/drivers/staging/rtl8188eu/include/ieee80211_ext.h b/drivers/staging/rtl8188eu/include/ieee80211_ext.h
new file mode 100644
index 0000000..1052d18
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ieee80211_ext.h
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __IEEE80211_EXT_H
+#define __IEEE80211_EXT_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define WMM_OUI_TYPE 2
+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WMM_VERSION 1
+
+#define WPA_PROTO_WPA BIT(0)
+#define WPA_PROTO_RSN BIT(1)
+
+#define WPA_KEY_MGMT_IEEE8021X BIT(0)
+#define WPA_KEY_MGMT_PSK BIT(1)
+#define WPA_KEY_MGMT_NONE BIT(2)
+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
+#define WPA_KEY_MGMT_WPA_NONE BIT(4)
+
+
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6)
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
+
+
+#define PMKID_LEN 16
+
+
+struct wpa_ie_hdr {
+	u8 elem_id;
+	u8 len;
+	u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
+	u8 version[2]; /* little endian */
+} __packed;
+
+struct rsn_ie_hdr {
+	u8 elem_id; /* WLAN_EID_RSN */
+	u8 len;
+	u8 version[2]; /* little endian */
+} __packed;
+
+struct wme_ac_parameter {
+#if defined(__LITTLE_ENDIAN)
+	/* byte 1 */
+	u8	aifsn:4,
+		acm:1,
+		aci:2,
+		reserved:1;
+
+	/* byte 2 */
+	u8	eCWmin:4,
+		eCWmax:4;
+#elif defined(__BIG_ENDIAN)
+	/* byte 1 */
+	u8	reserved:1,
+		aci:2,
+		acm:1,
+		aifsn:4;
+
+	/* byte 2 */
+	u8	eCWmax:4,
+		eCWmin:4;
+#else
+#error	"Please fix <endian.h>"
+#endif
+
+	/* bytes 3 & 4 */
+	u16 txopLimit;
+} __packed;
+
+struct wme_parameter_element {
+	/* required fields for WME version 1 */
+	u8 oui[3];
+	u8 oui_type;
+	u8 oui_subtype;
+	u8 version;
+	u8 acInfo;
+	u8 reserved;
+	struct wme_ac_parameter ac[4];
+
+} __packed;
+
+#define WPA_PUT_LE16(a, val)			\
+	do {					\
+		(a)[1] = ((u16) (val)) >> 8;	\
+		(a)[0] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define WPA_PUT_BE32(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[3] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_PUT_LE32(a, val)					\
+	do {							\
+		(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[0] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *)(a), (val))
+
+/* Action category code */
+enum ieee80211_category {
+	WLAN_CATEGORY_SPECTRUM_MGMT = 0,
+	WLAN_CATEGORY_QOS = 1,
+	WLAN_CATEGORY_DLS = 2,
+	WLAN_CATEGORY_BACK = 3,
+	WLAN_CATEGORY_HT = 7,
+	WLAN_CATEGORY_WMM = 17,
+};
+
+/* SPECTRUM_MGMT action code */
+enum ieee80211_spectrum_mgmt_actioncode {
+	WLAN_ACTION_SPCT_MSR_REQ = 0,
+	WLAN_ACTION_SPCT_MSR_RPRT = 1,
+	WLAN_ACTION_SPCT_TPC_REQ = 2,
+	WLAN_ACTION_SPCT_TPC_RPRT = 3,
+	WLAN_ACTION_SPCT_CHL_SWITCH = 4,
+	WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5,
+};
+
+/* BACK action code */
+enum ieee80211_back_actioncode {
+	WLAN_ACTION_ADDBA_REQ = 0,
+	WLAN_ACTION_ADDBA_RESP = 1,
+	WLAN_ACTION_DELBA = 2,
+};
+
+/* HT features action code */
+enum ieee80211_ht_actioncode {
+	WLAN_ACTION_NOTIFY_CH_WIDTH = 0,
+	WLAN_ACTION_SM_PS = 1,
+	WLAN_ACTION_PSPM = 2,
+	WLAN_ACTION_PCO_PHASE = 3,
+	WLAN_ACTION_MIMO_CSI_MX = 4,
+	WLAN_ACTION_MIMO_NONCP_BF = 5,
+	WLAN_ACTION_MIMP_CP_BF = 6,
+	WLAN_ACTION_ASEL_INDICATES_FB = 7,
+	WLAN_ACTION_HI_INFO_EXCHG = 8,
+};
+
+/* BACK (block-ack) parties */
+enum ieee80211_back_parties {
+	WLAN_BACK_RECIPIENT = 0,
+	WLAN_BACK_INITIATOR = 1,
+	WLAN_BACK_TIMER = 2,
+};
+
+struct ieee80211_mgmt {
+	u16 frame_control;
+	u16 duration;
+	u8 da[6];
+	u8 sa[6];
+	u8 bssid[6];
+	u16 seq_ctrl;
+	union {
+		struct {
+			u16 auth_alg;
+			u16 auth_transaction;
+			u16 status_code;
+			/* possibly followed by Challenge text */
+			u8 variable[0];
+		}  __packed auth;
+		struct {
+			u16 reason_code;
+		}  __packed deauth;
+		struct {
+			u16 capab_info;
+			u16 listen_interval;
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		}  __packed assoc_req;
+		struct {
+			u16 capab_info;
+			u16 status_code;
+			u16 aid;
+			/* followed by Supported rates */
+			u8 variable[0];
+		}  __packed assoc_resp, reassoc_resp;
+		struct {
+			u16 capab_info;
+			u16 listen_interval;
+			u8 current_ap[6];
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		}  __packed reassoc_req;
+		struct {
+			u16 reason_code;
+		}  __packed disassoc;
+		struct {
+			__le64 timestamp;
+			u16 beacon_int;
+			u16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
+			u8 variable[0];
+		}  __packed beacon;
+		struct {
+			/* only variable items: SSID, Supported rates */
+			u8 variable[0];
+		}  __packed probe_req;
+		struct {
+			__le64 timestamp;
+			u16 beacon_int;
+			u16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			u8 variable[0];
+		}  __packed probe_resp;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 status_code;
+					u8 variable[0];
+				}  __packed wme_action;
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u16 capab;
+					u16 timeout;
+					u16 start_seq_num;
+				}  __packed addba_req;
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u16 status;
+					u16 capab;
+					u16 timeout;
+				}  __packed addba_resp;
+				struct {
+					u8 action_code;
+					u16 params;
+					u16 reason_code;
+				}  __packed delba;
+				structi {
+					u8 action_code;
+					/* capab_info for open and confirm,
+					 * reason for close
+					 */
+					u16 aux;
+					/* Followed in plink_confirm by status
+					 * code, AID and supported rates,
+					 * and directly by supported rates in
+					 * plink_open and plink_close
+					 */
+					u8 variable[0];
+				}  __packed plink_action;
+				struct{
+					u8 action_code;
+					u8 variable[0];
+				}  __packed mesh_action;
+			} __packed u;
+		}  __packed action;
+	} __packed u;
+} __packed;
+
+/* mgmt header + 1 byte category code */
+#define IEEE80211_MIN_ACTION_SIZE				\
+	 FIELD_OFFSET(struct ieee80211_mgmt, u.action.u)
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/if_ether.h b/drivers/staging/rtl8188eu/include/if_ether.h
new file mode 100644
index 0000000..db15771
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/if_ether.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+/*
+ *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+ *	and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+#define ETH_HLEN	14		/* Total octets in header.	 */
+#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
+#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
+
+/*
+ *	These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
+#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
+#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
+#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+#define ETH_P_X25	0x0805		/* CCITT X.25			*/
+#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+#define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet  */
+#define ETH_P_IEEEPUP	0x0a00		/* Xerox IEEE802.3 PUP packet   */
+#define ETH_P_IEEEPUPAT	0x0a01		/* Xerox IEEE802.3 PUP		*/
+#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
+#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
+#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
+#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
+#define ETH_P_LAT       0x6004          /* DEC LAT                      */
+#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
+#define ETH_P_CUST      0x6006          /* DEC Customer use             */
+#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+#define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
+#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
+#define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
+#define ETH_P_8021Q	0x8100          /* 802.1Q VLAN Extended Header  */
+#define ETH_P_IPX	0x8137		/* IPX over DIX			*/
+#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
+#define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
+#define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
+#define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
+					 * over Ethernet
+					 */
+
+/*
+ *	Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
+#define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
+#define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
+#define ETH_P_802_2	0x0004		/* 802.2 frames			*/
+#define ETH_P_SNAP	0x0005		/* Internal only		*/
+#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
+#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type	*/
+#define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2	0x0011		/* 802.2 frames			*/
+#define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz@cafe.net)	*/
+#define ETH_P_CONTROL	0x0016		/* Card specific control frames */
+#define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
+#define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
+
+/*
+ *	This is an Ethernet frame header.
+ */
+
+struct ethhdr {
+	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+	unsigned short	h_proto;		/* packet type ID field	*/
+};
+
+struct _vlan {
+	unsigned short       h_vlan_TCI;	/*  Encap prio and VLAN ID */
+	unsigned short       h_vlan_encapsulated_proto;
+};
+
+#define get_vlan_id(pvlan)				\
+	((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff)
+#define get_vlan_priority(pvlan)			\
+	((ntohs((unsigned short)pvlan->h_vlan_TCI))>>13)
+#define get_vlan_encap_proto(pvlan)			\
+	 (ntohs((unsigned short)pvlan->h_vlan_encapsulated_proto))
+
+#endif	/* _LINUX_IF_ETHER_H */
diff --git a/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h b/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h
new file mode 100644
index 0000000..037e9a5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ioctl_cfg80211.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __IOCTL_CFG80211_H__
+#define __IOCTL_CFG80211_H__
+
+struct rtw_wdev_invit_info {
+	u8 token;
+	u8 flags;
+	u8 status;
+	u8 req_op_ch;
+	u8 rsp_op_ch;
+};
+
+#define rtw_wdev_invit_info_init(invit_info) \
+	do { \
+		(invit_info)->token = 0; \
+		(invit_info)->flags = 0x00; \
+		(invit_info)->status = 0xff; \
+		(invit_info)->req_op_ch = 0; \
+		(invit_info)->rsp_op_ch = 0; \
+	} while (0)
+
+struct rtw_wdev_priv {
+	struct wireless_dev *rtw_wdev;
+
+	struct adapter *padapter;
+
+	struct cfg80211_scan_request *scan_request;
+	spinlock_t scan_req_lock;
+
+	struct net_device *pmon_ndev;/* for monitor interface */
+	char ifname_mon[IFNAMSIZ + 1]; /* name of monitor interface */
+
+	u8 p2p_enabled;
+
+	u8 provdisc_req_issued;
+
+	struct rtw_wdev_invit_info invit_info;
+
+	u8 bandroid_scan;
+	bool block;
+	bool power_mgmt;
+};
+
+#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w)))
+
+#define wiphy_to_wdev(x)				\
+((struct wireless_dev *)(((struct rtw_wdev_priv *)wiphy_priv(x))->rtw_wdev))
+
+int rtw_wdev_alloc(struct adapter *padapter, struct device *dev);
+void rtw_wdev_free(struct wireless_dev *wdev);
+void rtw_wdev_unregister(struct wireless_dev *wdev);
+
+void rtw_cfg80211_init_wiphy(struct adapter *padapter);
+
+void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter);
+
+void rtw_cfg80211_indicate_connect(struct adapter *padapter);
+void rtw_cfg80211_indicate_disconnect(struct adapter *padapter);
+void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
+				     bool aborted);
+
+#ifdef CONFIG_88EU_AP_MODE
+void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter,
+				     u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter,
+					unsigned char *da,
+					unsigned short reason);
+#endif /* CONFIG_88EU_AP_MODE */
+
+void rtw_cfg80211_issue_p2p_provision_request(struct adapter *padapter,
+					      const u8 *buf, size_t len);
+void rtw_cfg80211_rx_p2p_action_public(struct adapter *padapter,
+				       u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_rx_action_p2p(struct adapter *padapter, u8 *pmgmt_frame,
+				uint frame_len);
+void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame,
+			    uint frame_len, const char *msg);
+
+int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net,
+				   char *buf, int len, int type);
+
+bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter);
+
+#define rtw_cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp)		\
+	cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp)
+#define rtw_cfg80211_send_rx_assoc(dev, bss, buf, len)			\
+	cfg80211_send_rx_assoc(dev, bss, buf, len)
+
+#endif /* __IOCTL_CFG80211_H__ */
diff --git a/drivers/staging/rtl8188eu/include/ip.h b/drivers/staging/rtl8188eu/include/ip.h
new file mode 100644
index 0000000..9fdac6d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/ip.h
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _LINUX_IP_H
+#define _LINUX_IP_H
+
+/* SOL_IP socket options */
+
+#define IPTOS_TOS_MASK		0x1E
+#define IPTOS_TOS(tos)		((tos)&IPTOS_TOS_MASK)
+#define	IPTOS_LOWDELAY		0x10
+#define	IPTOS_THROUGHPUT	0x08
+#define	IPTOS_RELIABILITY	0x04
+#define	IPTOS_MINCOST		0x02
+
+#define IPTOS_PREC_MASK		0xE0
+#define IPTOS_PREC(tos)		((tos)&IPTOS_PREC_MASK)
+#define IPTOS_PREC_NETCONTROL           0xe0
+#define IPTOS_PREC_INTERNETCONTROL      0xc0
+#define IPTOS_PREC_CRITIC_ECP           0xa0
+#define IPTOS_PREC_FLASHOVERRIDE        0x80
+#define IPTOS_PREC_FLASH                0x60
+#define IPTOS_PREC_IMMEDIATE            0x40
+#define IPTOS_PREC_PRIORITY             0x20
+#define IPTOS_PREC_ROUTINE              0x00
+
+
+/* IP options */
+#define IPOPT_COPY		0x80
+#define IPOPT_CLASS_MASK	0x60
+#define IPOPT_NUMBER_MASK	0x1f
+
+#define	IPOPT_COPIED(o)		((o)&IPOPT_COPY)
+#define	IPOPT_CLASS(o)		((o)&IPOPT_CLASS_MASK)
+#define	IPOPT_NUMBER(o)		((o)&IPOPT_NUMBER_MASK)
+
+#define	IPOPT_CONTROL		0x00
+#define	IPOPT_RESERVED1		0x20
+#define	IPOPT_MEASUREMENT	0x40
+#define	IPOPT_RESERVED2		0x60
+
+#define IPOPT_END	(0 | IPOPT_CONTROL)
+#define IPOPT_NOOP	(1 | IPOPT_CONTROL)
+#define IPOPT_SEC	(2 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_LSRR	(3 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_TIMESTAMP	(4 | IPOPT_MEASUREMENT)
+#define IPOPT_RR	(7 | IPOPT_CONTROL)
+#define IPOPT_SID	(8 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_SSRR	(9 | IPOPT_CONTROL | IPOPT_COPY)
+#define IPOPT_RA	(20 | IPOPT_CONTROL | IPOPT_COPY)
+
+#define IPVERSION	4
+#define MAXTTL		255
+#define IPDEFTTL	64
+#define IPOPT_OPTVAL 0
+#define IPOPT_OLEN   1
+#define IPOPT_OFFSET 2
+#define IPOPT_MINOFF 4
+#define MAX_IPOPTLEN 40
+#define IPOPT_NOP IPOPT_NOOP
+#define IPOPT_EOL IPOPT_END
+#define IPOPT_TS  IPOPT_TIMESTAMP
+
+#define	IPOPT_TS_TSONLY		0	/* timestamps only */
+#define	IPOPT_TS_TSANDADDR	1	/* timestamps and addresses */
+#define	IPOPT_TS_PRESPEC	3	/* specified modules only */
+
+struct ip_options {
+	__u32		faddr;			/* Saved first hop address */
+	unsigned char	optlen;
+	unsigned char srr;
+	unsigned char rr;
+	unsigned char ts;
+	unsigned char	is_setbyuser:1,	/* Set by setsockopt?		*/
+			is_data:1,	/* Options in __data, rather than skb*/
+			is_strictroute:1,/* Strict source route		*/
+			srr_is_hit:1,	/* Packet destn addr was ours */
+			is_changed:1,	/* IP checksum more not valid	*/
+			rr_needaddr:1,	/* Need to record addr of out dev*/
+			ts_needtime:1,	/* Need to record timestamp	*/
+			ts_needaddr:1;	/* Need to record addr of out dev  */
+	unsigned char router_alert;
+	unsigned char __pad1;
+	unsigned char __pad2;
+	unsigned char __data[0];
+};
+
+#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
+
+struct iphdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8	ihl:4,
+		version:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	__u8	version:4,
+		ihl:4;
+#endif
+	__u8	tos;
+	__u16	tot_len;
+	__u16	id;
+	__u16	frag_off;
+	__u8	ttl;
+	__u8	protocol;
+	__u16	check;
+	__u32	saddr;
+	__u32	daddr;
+	/*The options start here. */
+};
+
+#endif	/* _LINUX_IP_H */
diff --git a/drivers/staging/rtl8188eu/include/mlme_osdep.h b/drivers/staging/rtl8188eu/include/mlme_osdep.h
new file mode 100644
index 0000000..ae1722c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/mlme_osdep.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef	__MLME_OSDEP_H_
+#define __MLME_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+void rtw_init_mlme_timer(struct adapter *padapter);
+void rtw_os_indicate_disconnect(struct adapter *adapter);
+void rtw_os_indicate_connect(struct adapter *adapter);
+void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted);
+void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie);
+
+void rtw_reset_securitypriv(struct adapter *adapter);
+void indicate_wx_scan_complete_event(struct adapter *padapter);
+
+#endif	/* _MLME_OSDEP_H_ */
diff --git a/drivers/staging/rtl8188eu/include/mp_custom_oid.h b/drivers/staging/rtl8188eu/include/mp_custom_oid.h
new file mode 100644
index 0000000..6fa52cf
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/mp_custom_oid.h
@@ -0,0 +1,352 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef	__CUSTOM_OID_H
+#define __CUSTOM_OID_H
+
+/*  by Owen */
+/*  0xFF818000 - 0xFF81802F		RTL8180 Mass Production Kit */
+/*  0xFF818500 - 0xFF81850F		RTL8185 Setup Utility */
+/*  0xFF818580 - 0xFF81858F		RTL8185 Phy Status Utility */
+
+/*  */
+
+/*  by Owen for Production Kit */
+/*  For Production Kit with Agilent Equipments */
+/*  in order to make our custom oids hopefully somewhat unique */
+/*  we will use 0xFF (indicating implementation specific OID) */
+/*	81(first byte of non zero Realtek unique identifier) */
+/*	80 (second byte of non zero Realtek unique identifier) */
+/*	XX (the custom OID number - providing 255 possible custom oids) */
+
+#define OID_RT_PRO_RESET_DUT				0xFF818000
+#define OID_RT_PRO_SET_DATA_RATE			0xFF818001
+#define OID_RT_PRO_START_TEST				0xFF818002
+#define OID_RT_PRO_STOP_TEST				0xFF818003
+#define OID_RT_PRO_SET_PREAMBLE				0xFF818004
+#define OID_RT_PRO_SET_SCRAMBLER			0xFF818005
+#define OID_RT_PRO_SET_FILTER_BB			0xFF818006
+#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB		0xFF818007
+#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL		0xFF818008
+#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL		0xFF818009
+#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL		0xFF81800A
+
+#define OID_RT_PRO_SET_TX_ANTENNA_BB			0xFF81800D
+#define OID_RT_PRO_SET_ANTENNA_BB			0xFF81800E
+#define OID_RT_PRO_SET_CR_SCRAMBLER			0xFF81800F
+#define OID_RT_PRO_SET_CR_NEW_FILTER			0xFF818010
+#define OID_RT_PRO_SET_TX_POWER_CONTROL			0xFF818011
+#define OID_RT_PRO_SET_CR_TX_CONFIG			0xFF818012
+#define OID_RT_PRO_GET_TX_POWER_CONTROL			0xFF818013
+#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY		0xFF818014
+#define OID_RT_PRO_SET_CR_SETPOINT			0xFF818015
+#define OID_RT_PRO_SET_INTEGRATOR			0xFF818016
+#define OID_RT_PRO_SET_SIGNAL_QUALITY			0xFF818017
+#define OID_RT_PRO_GET_INTEGRATOR			0xFF818018
+#define OID_RT_PRO_GET_SIGNAL_QUALITY			0xFF818019
+#define OID_RT_PRO_QUERY_EEPROM_TYPE			0xFF81801A
+#define OID_RT_PRO_WRITE_MAC_ADDRESS			0xFF81801B
+#define OID_RT_PRO_READ_MAC_ADDRESS			0xFF81801C
+#define OID_RT_PRO_WRITE_CIS_DATA			0xFF81801D
+#define OID_RT_PRO_READ_CIS_DATA			0xFF81801E
+#define OID_RT_PRO_WRITE_POWER_CONTROL			0xFF81801F
+#define OID_RT_PRO_READ_POWER_CONTROL			0xFF818020
+#define OID_RT_PRO_WRITE_EEPROM				0xFF818021
+#define OID_RT_PRO_READ_EEPROM				0xFF818022
+#define OID_RT_PRO_RESET_TX_PACKET_SENT			0xFF818023
+#define OID_RT_PRO_QUERY_TX_PACKET_SENT			0xFF818024
+#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED		0xFF818025
+#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED		0xFF818026
+#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR		0xFF818027
+#define OID_RT_PRO_QUERY_CURRENT_ADDRESS		0xFF818028
+#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS		0xFF818029
+#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS		0xFF81802A
+#define OID_RT_PRO_RECEIVE_PACKET			0xFF81802C
+/*  added by Owen on 04/08/03 for Cameo's request */
+#define OID_RT_PRO_WRITE_EEPROM_BYTE			0xFF81802D
+#define OID_RT_PRO_READ_EEPROM_BYTE			0xFF81802E
+#define OID_RT_PRO_SET_MODULATION			0xFF81802F
+/*  */
+
+/* Sean */
+#define OID_RT_DRIVER_OPTION				0xFF818080
+#define OID_RT_RF_OFF					0xFF818081
+#define OID_RT_AUTH_STATUS				0xFF818082
+
+/*  */
+#define OID_RT_PRO_SET_CONTINUOUS_TX			0xFF81800B
+#define OID_RT_PRO_SET_SINGLE_CARRIER_TX		0xFF81800C
+#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX		0xFF81802B
+#define OID_RT_PRO_SET_SINGLE_TONE_TX			0xFF818043
+/*  */
+
+
+/*  by Owen for RTL8185 Phy Status Report Utility */
+#define OID_RT_UTILITY_false_ALARM_COUNTERS		0xFF818580
+#define OID_RT_UTILITY_SELECT_DEBUG_MODE		0xFF818581
+#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER		0xFF818582
+#define OID_RT_UTILITY_GET_RSSI_STATUS			0xFF818583
+#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS	0xFF818584
+#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS	\
+							0xFF818585
+#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS	0xFF818586
+/*  */
+
+/*  by Owen on 03/09/19-03/09/22 for RTL8185 */
+#define OID_RT_WIRELESS_MODE				0xFF818500
+#define OID_RT_SUPPORTED_RATES				0xFF818501
+#define OID_RT_DESIRED_RATES				0xFF818502
+#define OID_RT_WIRELESS_MODE_STARTING_ADHOC		0xFF818503
+/*  */
+
+#define OID_RT_GET_CONNECT_STATE			0xFF030001
+#define OID_RT_RESCAN					0xFF030002
+#define OID_RT_SET_KEY_LENGTH				0xFF030003
+#define OID_RT_SET_DEFAULT_KEY_ID			0xFF030004
+
+#define OID_RT_SET_CHANNEL				0xFF010182
+#define OID_RT_SET_SNIFFER_MODE				0xFF010183
+#define OID_RT_GET_SIGNAL_QUALITY			0xFF010184
+#define OID_RT_GET_SMALL_PACKET_CRC			0xFF010185
+#define OID_RT_GET_MIDDLE_PACKET_CRC			0xFF010186
+#define OID_RT_GET_LARGE_PACKET_CRC			0xFF010187
+#define OID_RT_GET_TX_RETRY				0xFF010188
+#define OID_RT_GET_RX_RETRY				0xFF010189
+#define OID_RT_PRO_SET_FW_DIG_STATE			0xFF01018A/* S */
+#define OID_RT_PRO_SET_FW_RA_STATE			0xFF01018B/* S */
+
+#define OID_RT_GET_RX_TOTAL_PACKET			0xFF010190
+#define OID_RT_GET_TX_BEACON_OK				0xFF010191
+#define OID_RT_GET_TX_BEACON_ERR			0xFF010192
+#define OID_RT_GET_RX_ICV_ERR				0xFF010193
+#define OID_RT_SET_ENCRYPTION_ALGORITHM			0xFF010194
+#define OID_RT_SET_NO_AUTO_RESCAN			0xFF010195
+#define OID_RT_GET_PREAMBLE_MODE			0xFF010196
+#define OID_RT_GET_DRIVER_UP_DELTA_TIME			0xFF010197
+#define OID_RT_GET_AP_IP				0xFF010198
+#define OID_RT_GET_CHANNELPLAN				0xFF010199
+#define OID_RT_SET_PREAMBLE_MODE			0xFF01019A
+#define OID_RT_SET_BCN_INTVL				0xFF01019B
+#define OID_RT_GET_RF_VENDER				0xFF01019C
+#define OID_RT_DEDICATE_PROBE				0xFF01019D
+#define OID_RT_PRO_RX_FILTER_PATTERN			0xFF01019E
+
+#define OID_RT_GET_DCST_CURRENT_THRESHOLD		0xFF01019F
+
+#define OID_RT_GET_CCA_ERR				0xFF0101A0
+#define OID_RT_GET_CCA_UPGRADE_THRESHOLD		0xFF0101A1
+#define OID_RT_GET_CCA_FALLBACK_THRESHOLD		0xFF0101A2
+
+#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES		0xFF0101A3
+#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES		0xFF0101A4
+
+/*  by Owen on 03/31/03 for Cameo's request */
+#define OID_RT_SET_RATE_ADAPTIVE			0xFF0101A5
+/*  */
+#define OID_RT_GET_DCST_EVALUATE_PERIOD			0xFF0101A5
+#define OID_RT_GET_DCST_TIME_UNIT_INDEX			0xFF0101A6
+#define OID_RT_GET_TOTAL_TX_BYTES			0xFF0101A7
+#define OID_RT_GET_TOTAL_RX_BYTES			0xFF0101A8
+#define OID_RT_CURRENT_TX_POWER_LEVEL			0xFF0101A9
+#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT		0xFF0101AA
+#define OID_RT_GET_ENC_KEY_MATCH_COUNT			0xFF0101AB
+#define OID_RT_GET_CHANNEL				0xFF0101AC
+
+#define OID_RT_SET_CHANNELPLAN				0xFF0101AD
+#define OID_RT_GET_HARDWARE_RADIO_OFF			0xFF0101AE
+#define OID_RT_CHANNELPLAN_BY_COUNTRY			0xFF0101AF
+#define OID_RT_SCAN_AVAILABLE_BSSID			0xFF0101B0
+#define OID_RT_GET_HARDWARE_VERSION			0xFF0101B1
+#define OID_RT_GET_IS_ROAMING				0xFF0101B2
+#define OID_RT_GET_IS_PRIVACY				0xFF0101B3
+#define OID_RT_GET_KEY_MISMATCH				0xFF0101B4
+#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH			0xFF0101B5
+#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH			0xFF0101B6
+#define OID_RT_RESET_LOG				0xFF0101B7
+#define OID_RT_GET_LOG					0xFF0101B8
+#define OID_RT_SET_INDICATE_HIDDEN_AP			0xFF0101B9
+#define OID_RT_GET_HEADER_FAIL				0xFF0101BA
+#define OID_RT_SUPPORTED_WIRELESS_MODE			0xFF0101BB
+#define OID_RT_GET_CHANNEL_LIST				0xFF0101BC
+#define OID_RT_GET_SCAN_IN_PROGRESS			0xFF0101BD
+#define OID_RT_GET_TX_INFO				0xFF0101BE
+#define OID_RT_RF_READ_WRITE_OFFSET			0xFF0101BF
+#define OID_RT_RF_READ_WRITE				0xFF0101C0
+
+/*  For Netgear request. 2005.01.13, by rcnjko. */
+#define OID_RT_FORCED_DATA_RATE				0xFF0101C1
+#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST		0xFF0101C2
+/*  For Netgear request. 2005.02.17, by rcnjko. */
+#define OID_RT_GET_BSS_WIRELESS_MODE			0xFF0101C3
+/*  For AZ project. 2005.06.27, by rcnjko. */
+#define OID_RT_SCAN_WITH_MAGIC_PACKET			0xFF0101C4
+
+/*  Vincent 8185MP */
+#define OID_RT_PRO_RX_FILTER				0xFF0111C0
+
+#define OID_CE_USB_WRITE_REGISTRY			0xFF0111C1
+#define OID_CE_USB_READ_REGISTRY			0xFF0111C2
+
+#define OID_RT_PRO_SET_INITIAL_GA			0xFF0111C3
+#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE		0xFF0111C4
+#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE		0xFF0111C5
+#define OID_RT_PRO_SET_TX_CHARGE_PUMP			0xFF0111C6
+#define OID_RT_PRO_SET_RX_CHARGE_PUMP			0xFF0111C7
+#define OID_RT_PRO_RF_WRITE_REGISTRY			0xFF0111C8
+#define OID_RT_PRO_RF_READ_REGISTRY			0xFF0111C9
+#define OID_RT_PRO_QUERY_RF_TYPE			0xFF0111CA
+
+/*  AP OID */
+#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST		0xFF010300
+#define OID_RT_AP_GET_CURRENT_TIME_STAMP		0xFF010301
+#define OID_RT_AP_SWITCH_INTO_AP_MODE			0xFF010302
+#define OID_RT_AP_SET_DTIM_PERIOD			0xFF010303
+/*  Determine if driver supports AP mode. */
+#define OID_RT_AP_SUPPORTED				0xFF010304
+/*  Set WPA-PSK passphrase into authenticator. */
+#define OID_RT_AP_SET_PASSPHRASE			0xFF010305
+
+/*  8187MP. 2004.09.06, by rcnjko. */
+#define OID_RT_PRO8187_WI_POLL				0xFF818780
+#define OID_RT_PRO_WRITE_BB_REG				0xFF818781
+#define OID_RT_PRO_READ_BB_REG				0xFF818782
+#define OID_RT_PRO_WRITE_RF_REG				0xFF818783
+#define OID_RT_PRO_READ_RF_REG				0xFF818784
+
+/*  Meeting House. added by Annie, 2005-07-20. */
+#define OID_RT_MH_VENDER_ID				0xFFEDC100
+
+/* 8711 MP OID added 20051230. */
+#define OID_RT_PRO8711_JOIN_BSS				0xFF871100/* S */
+
+#define OID_RT_PRO_READ_REGISTER			0xFF871101 /* Q */
+#define OID_RT_PRO_WRITE_REGISTER			0xFF871102 /* S */
+
+#define OID_RT_PRO_BURST_READ_REGISTER			0xFF871103 /* Q */
+#define OID_RT_PRO_BURST_WRITE_REGISTER			0xFF871104 /* S */
+
+#define OID_RT_PRO_WRITE_TXCMD				0xFF871105 /* S */
+
+#define OID_RT_PRO_READ16_EEPROM			0xFF871106 /* Q */
+#define OID_RT_PRO_WRITE16_EEPROM			0xFF871107 /* S */
+
+#define OID_RT_PRO_H2C_SET_COMMAND			0xFF871108 /* S */
+#define OID_RT_PRO_H2C_QUERY_RESULT			0xFF871109 /* Q */
+
+#define OID_RT_PRO8711_WI_POLL				0xFF87110A /* Q */
+#define OID_RT_PRO8711_PKT_LOSS				0xFF87110B /* Q */
+#define OID_RT_RD_ATTRIB_MEM				0xFF87110C/* Q */
+#define OID_RT_WR_ATTRIB_MEM				0xFF87110D/* S */
+
+
+/* Method 2 for H2C/C2H */
+#define OID_RT_PRO_H2C_CMD_MODE				0xFF871110 /* S */
+#define OID_RT_PRO_H2C_CMD_RSP_MODE			0xFF871111 /* Q */
+#define OID_RT_PRO_H2C_CMD_EVENT_MODE			0xFF871112 /* S */
+#define OID_RT_PRO_WAIT_C2H_EVENT			0xFF871113 /* Q */
+#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST		0xFF871114/* Q */
+
+#define OID_RT_PRO_SCSI_ACCESS_TEST			0xFF871115 /* Q, S */
+
+#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT		0xFF871116 /* S */
+#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN			0xFF871117 /* Q,S */
+#define OID_RT_RRO_RX_PKT_VIA_IOCTRL			0xFF871118 /* Q */
+#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL		0xFF871119 /* Q */
+
+#define OID_RT_RPO_SET_PWRMGT_TEST			0xFF87111A /* S */
+#define OID_RT_PRO_QRY_PWRMGT_TEST			0XFF87111B /* Q */
+#define OID_RT_RPO_ASYNC_RWIO_TEST			0xFF87111C /* S */
+#define OID_RT_RPO_ASYNC_RWIO_POLL			0xFF87111D /* Q */
+#define OID_RT_PRO_SET_RF_INTFS				0xFF87111E /* S */
+#define OID_RT_POLL_RX_STATUS				0xFF87111F /* Q */
+
+#define OID_RT_PRO_CFG_DEBUG_MESSAGE			0xFF871120 /* Q,S */
+#define OID_RT_PRO_SET_DATA_RATE_EX			0xFF871121/* S */
+#define OID_RT_PRO_SET_BASIC_RATE			0xFF871122/* S */
+#define OID_RT_PRO_READ_TSSI				0xFF871123/* S */
+#define OID_RT_PRO_SET_POWER_TRACKING			0xFF871124/* S */
+
+
+#define OID_RT_PRO_QRY_PWRSTATE				0xFF871150 /* Q */
+#define OID_RT_PRO_SET_PWRSTATE				0xFF871151 /* S */
+
+/* Method 2 , using workitem */
+#define OID_RT_SET_READ_REG				0xFF871181 /* S */
+#define OID_RT_SET_WRITE_REG				0xFF871182 /* S */
+#define OID_RT_SET_BURST_READ_REG			0xFF871183 /* S */
+#define OID_RT_SET_BURST_WRITE_REG			0xFF871184 /* S */
+#define OID_RT_SET_WRITE_TXCMD				0xFF871185 /* S */
+#define OID_RT_SET_READ16_EEPROM			0xFF871186 /* S */
+#define OID_RT_SET_WRITE16_EEPROM			0xFF871187 /* S */
+#define OID_RT_QRY_POLL_WKITEM				0xFF871188 /* Q */
+
+/* For SDIO INTERFACE only */
+#define OID_RT_PRO_SYNCPAGERW_SRAM			0xFF8711A0 /* Q, S */
+#define OID_RT_PRO_871X_DRV_EXT				0xFF8711A1
+
+/* For USB INTERFACE only */
+#define OID_RT_PRO_USB_VENDOR_REQ			0xFF8711B0 /* Q, S */
+#define OID_RT_PRO_SCSI_AUTO_TEST			0xFF8711B1 /* S */
+#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE		0xFF8711B2 /* S */
+#define OID_RT_PRO_USB_MAC_RX_FIFO_READ			0xFF8711B3 /* Q */
+#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING		0xFF8711B4 /* Q */
+
+#define OID_RT_PRO_H2C_SET_RATE_TABLE			0xFF8711FB /* S */
+#define OID_RT_PRO_H2C_GET_RATE_TABLE			0xFF8711FC /* S */
+#define OID_RT_PRO_H2C_C2H_LBK_TEST			0xFF8711FE
+
+#define OID_RT_PRO_ENCRYPTION_CTRL			0xFF871200 /* Q, S */
+#define OID_RT_PRO_ADD_STA_INFO				0xFF871201 /* S */
+#define OID_RT_PRO_DELE_STA_INFO			0xFF871202 /* S */
+#define OID_RT_PRO_QUERY_DR_VARIABLE			0xFF871203 /* Q */
+
+#define OID_RT_PRO_RX_PACKET_TYPE			0xFF871204 /* Q, S */
+
+#define OID_RT_PRO_READ_EFUSE				0xFF871205 /* Q */
+#define OID_RT_PRO_WRITE_EFUSE				0xFF871206 /* S */
+#define OID_RT_PRO_RW_EFUSE_PGPKT			0xFF871207 /* Q, S */
+#define OID_RT_GET_EFUSE_CURRENT_SIZE			0xFF871208 /* Q */
+
+#define OID_RT_SET_BANDWIDTH				0xFF871209 /* S */
+#define OID_RT_SET_CRYSTAL_CAP				0xFF87120A /* S */
+
+#define OID_RT_SET_RX_PACKET_TYPE			0xFF87120B /* S */
+
+#define OID_RT_GET_EFUSE_MAX_SIZE			0xFF87120C /* Q */
+
+#define OID_RT_PRO_SET_TX_AGC_OFFSET			0xFF87120D /* S */
+
+#define OID_RT_PRO_SET_PKT_TEST_MODE			0xFF87120E /* S */
+
+#define OID_RT_PRO_FOR_EVM_TEST_SETTING			0xFF87120F /* S */
+
+#define OID_RT_PRO_GET_THERMAL_METER			0xFF871210 /* Q */
+
+#define OID_RT_RESET_PHY_RX_PACKET_COUNT		0xFF871211 /* S */
+#define OID_RT_GET_PHY_RX_PACKET_RECEIVED		0xFF871212 /* Q */
+#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR		0xFF871213 /* Q */
+
+#define OID_RT_SET_POWER_DOWN				0xFF871214 /* S */
+
+#define OID_RT_GET_POWER_MODE				0xFF871215 /* Q */
+
+#define OID_RT_PRO_EFUSE				0xFF871216 /* Q, S */
+#define OID_RT_PRO_EFUSE_MAP				0xFF871217 /* Q, S */
+
+#endif /* ifndef	__CUSTOM_OID_H */
diff --git a/drivers/staging/rtl8188eu/include/nic_spec.h b/drivers/staging/rtl8188eu/include/nic_spec.h
new file mode 100644
index 0000000..d422447
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/nic_spec.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+
+#ifndef __NIC_SPEC_H__
+#define __NIC_SPEC_H__
+
+#define RTL8711_MCTRL_		(0x20000)
+#define RTL8711_UART_		(0x30000)
+#define RTL8711_TIMER_		(0x40000)
+#define RTL8711_FINT_		(0x50000)
+#define RTL8711_HINT_		(0x50000)
+#define RTL8711_GPIO_		(0x60000)
+#define RTL8711_WLANCTRL_	(0x200000)
+#define RTL8711_WLANFF_		(0xe00000)
+#define RTL8711_HCICTRL_	(0x600000)
+#define RTL8711_SYSCFG_		(0x620000)
+#define RTL8711_SYSCTRL_	(0x620000)
+#define RTL8711_MCCTRL_		(0x020000)
+
+
+#include <rtl8711_regdef.h>
+
+#include <rtl8711_bitdef.h>
+
+
+#endif /*  __RTL8711_SPEC_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm.h b/drivers/staging/rtl8188eu/include/odm.h
new file mode 100644
index 0000000..2bfe728
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm.h
@@ -0,0 +1,1198 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+
+#ifndef	__HALDMOUTSRC_H__
+#define __HALDMOUTSRC_H__
+
+/*  Definition */
+/*  Define all team support ability. */
+
+/*  Define for all teams. Please Define the constant in your precomp header. */
+
+/* define		DM_ODM_SUPPORT_AP			0 */
+/* define		DM_ODM_SUPPORT_ADSL			0 */
+/* define		DM_ODM_SUPPORT_CE			0 */
+/* define		DM_ODM_SUPPORT_MP			1 */
+
+/*  Define ODM SW team support flag. */
+
+/*  Antenna Switch Relative Definition. */
+
+/*  Add new function SwAntDivCheck8192C(). */
+/*  This is the main function of Antenna diversity function before link. */
+/*  Mainly, it just retains last scan result and scan again. */
+/*  After that, it compares the scan result to see which one gets better
+ *  RSSI. It selects antenna with better receiving power and returns better
+ *  scan result. */
+
+#define	TP_MODE			0
+#define	RSSI_MODE		1
+#define	TRAFFIC_LOW		0
+#define	TRAFFIC_HIGH		1
+
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+#define		DPK_DELTA_MAPPING_NUM	13
+#define		index_mapping_HP_NUM	15
+
+
+/*  */
+/* 3 PSD Handler */
+/* 3============================================================ */
+
+#define	AFH_PSD		1	/* 0:normal PSD scan, 1: only do 20 pts PSD */
+#define	MODE_40M	0	/* 0:20M, 1:40M */
+#define	PSD_TH2		3
+#define	PSD_CHM		20   /*  Minimum channel number for BT AFH */
+#define	SIR_STEP_SIZE	3
+#define Smooth_Size_1	5
+#define	Smooth_TH_1	3
+#define Smooth_Size_2	10
+#define	Smooth_TH_2	4
+#define Smooth_Size_3	20
+#define	Smooth_TH_3	4
+#define Smooth_Step_Size 5
+#define	Adaptive_SIR	1
+#define	PSD_RESCAN	4
+#define	PSD_SCAN_INTERVAL	700 /* ms */
+
+/* 8723A High Power IGI Setting */
+#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND	0x22
+#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28
+#define DM_DIG_HIGH_PWR_THRESHOLD	0x3a
+
+/*  LPS define */
+#define DM_DIG_FA_TH0_LPS		4 /*  4 in lps */
+#define DM_DIG_FA_TH1_LPS		15 /*  15 lps */
+#define DM_DIG_FA_TH2_LPS		30 /*  30 lps */
+#define RSSI_OFFSET_DIG			0x05;
+
+/* ANT Test */
+#define ANTTESTALL		0x00	/* Ant A or B will be Testing */
+#define ANTTESTA		0x01	/* Ant A will be Testing */
+#define ANTTESTB		0x02	/* Ant B will be testing */
+
+/*  structure and define */
+
+/*  Add for AP/ADSLpseudo DM structuer requirement. */
+/*  We need to remove to other position??? */
+struct rtl8192cd_priv {
+	u8		temp;
+};
+
+struct rtw_dig {
+	u8		Dig_Enable_Flag;
+	u8		Dig_Ext_Port_Stage;
+
+	int		RssiLowThresh;
+	int		RssiHighThresh;
+
+	u32		FALowThresh;
+	u32		FAHighThresh;
+
+	u8		CurSTAConnectState;
+	u8		PreSTAConnectState;
+	u8		CurMultiSTAConnectState;
+
+	u8		PreIGValue;
+	u8		CurIGValue;
+	u8		BackupIGValue;
+
+	s8		BackoffVal;
+	s8		BackoffVal_range_max;
+	s8		BackoffVal_range_min;
+	u8		rx_gain_range_max;
+	u8		rx_gain_range_min;
+	u8		Rssi_val_min;
+
+	u8		PreCCK_CCAThres;
+	u8		CurCCK_CCAThres;
+	u8		PreCCKPDState;
+	u8		CurCCKPDState;
+
+	u8		LargeFAHit;
+	u8		ForbiddenIGI;
+	u32		Recover_cnt;
+
+	u8		DIG_Dynamic_MIN_0;
+	u8		DIG_Dynamic_MIN_1;
+	bool		bMediaConnect_0;
+	bool		bMediaConnect_1;
+
+	u32		AntDiv_RSSI_max;
+	u32		RSSI_max;
+};
+
+struct rtl_ps {
+	u8		PreCCAState;
+	u8		CurCCAState;
+
+	u8		PreRFState;
+	u8		CurRFState;
+
+	int		    Rssi_val_min;
+
+	u8		initialize;
+	u32		Reg874,RegC70,Reg85C,RegA74;
+
+};
+
+struct false_alarm_stats {
+	u32	Cnt_Parity_Fail;
+	u32	Cnt_Rate_Illegal;
+	u32	Cnt_Crc8_fail;
+	u32	Cnt_Mcs_fail;
+	u32	Cnt_Ofdm_fail;
+	u32	Cnt_Cck_fail;
+	u32	Cnt_all;
+	u32	Cnt_Fast_Fsync;
+	u32	Cnt_SB_Search_fail;
+	u32	Cnt_OFDM_CCA;
+	u32	Cnt_CCK_CCA;
+	u32	Cnt_CCA_all;
+	u32	Cnt_BW_USC;	/* Gary */
+	u32	Cnt_BW_LSC;	/* Gary */
+};
+
+struct dyn_primary_cca {
+	u8		PriCCA_flag;
+	u8		intf_flag;
+	u8		intf_type;
+	u8		DupRTS_flag;
+	u8		Monitor_flag;
+};
+
+struct rx_hpc {
+	u8		RXHP_flag;
+	u8		PSD_func_trigger;
+	u8		PSD_bitmap_RXHP[80];
+	u8		Pre_IGI;
+	u8		Cur_IGI;
+	u8		Pre_pw_th;
+	u8		Cur_pw_th;
+	bool		First_time_enter;
+	bool		RXHP_enable;
+	u8		TP_Mode;
+	struct timer_list PSDTimer;
+};
+
+#define ASSOCIATE_ENTRY_NUM	32 /*  Max size of AsocEntry[]. */
+#define	ODM_ASSOCIATE_ENTRY_NUM	ASSOCIATE_ENTRY_NUM
+
+/*  This indicates two different steps. */
+/*  In SWAW_STEP_PEAK, driver needs to switch antenna and listen to
+ *  the signal on the air. */
+/*  In SWAW_STEP_DETERMINE, driver just compares the signal captured in
+ *  SWAW_STEP_PEAK with original RSSI to determine if it is necessary to
+ *  switch antenna. */
+
+#define SWAW_STEP_PEAK		0
+#define SWAW_STEP_DETERMINE	1
+
+#define	TP_MODE			0
+#define	RSSI_MODE		1
+#define	TRAFFIC_LOW		0
+#define	TRAFFIC_HIGH		1
+
+struct sw_ant_switch {
+	u8	try_flag;
+	s32	PreRSSI;
+	u8	CurAntenna;
+	u8	PreAntenna;
+	u8	RSSI_Trying;
+	u8	TestMode;
+	u8	bTriggerAntennaSwitch;
+	u8	SelectAntennaMap;
+	u8	RSSI_target;
+
+	/*  Before link Antenna Switch check */
+	u8	SWAS_NoLink_State;
+	u32	SWAS_NoLink_BK_Reg860;
+	bool	ANTA_ON;	/* To indicate Ant A is or not */
+	bool	ANTB_ON;	/* To indicate Ant B is on or not */
+
+	s32	RSSI_sum_A;
+	s32	RSSI_sum_B;
+	s32	RSSI_cnt_A;
+	s32	RSSI_cnt_B;
+	u64	lastTxOkCnt;
+	u64	lastRxOkCnt;
+	u64	TXByteCnt_A;
+	u64	TXByteCnt_B;
+	u64	RXByteCnt_A;
+	u64	RXByteCnt_B;
+	u8	TrafficLoad;
+	struct timer_list SwAntennaSwitchTimer;
+	/* Hybrid Antenna Diversity */
+	u32	CCK_Ant1_Cnt[ASSOCIATE_ENTRY_NUM];
+	u32	CCK_Ant2_Cnt[ASSOCIATE_ENTRY_NUM];
+	u32	OFDM_Ant1_Cnt[ASSOCIATE_ENTRY_NUM];
+	u32	OFDM_Ant2_Cnt[ASSOCIATE_ENTRY_NUM];
+	u32	RSSI_Ant1_Sum[ASSOCIATE_ENTRY_NUM];
+	u32	RSSI_Ant2_Sum[ASSOCIATE_ENTRY_NUM];
+	u8	TxAnt[ASSOCIATE_ENTRY_NUM];
+	u8	TargetSTA;
+	u8	antsel;
+	u8	RxIdleAnt;
+};
+
+struct edca_turbo {
+	bool bCurrentTurboEDCA;
+	bool bIsCurRDLState;
+	u32	prv_traffic_idx; /*  edca turbo */
+};
+
+struct odm_rate_adapt {
+	u8	Type;		/*  DM_Type_ByFW/DM_Type_ByDriver */
+	u8	HighRSSIThresh;	/*  if RSSI > HighRSSIThresh	=> RATRState is DM_RATR_STA_HIGH */
+	u8	LowRSSIThresh;	/*  if RSSI <= LowRSSIThresh	=> RATRState is DM_RATR_STA_LOW */
+	u8	RATRState;	/*  Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */
+	u32	LastRATR;	/*  RATR Register Content */
+};
+
+#define IQK_MAC_REG_NUM		4
+#define IQK_ADDA_REG_NUM	16
+#define IQK_BB_REG_NUM_MAX	10
+#define IQK_BB_REG_NUM		9
+#define HP_THERMAL_NUM		8
+
+#define AVG_THERMAL_NUM		8
+#define IQK_Matrix_REG_NUM	8
+#define IQK_Matrix_Settings_NUM	1+24+21
+
+#define	DM_Type_ByFWi		0
+#define	DM_Type_ByDriver	1
+
+/*  Declare for common info */
+
+#define MAX_PATH_NUM_92CS	2
+
+struct odm_phy_status_info {
+	u8	RxPWDBAll;
+	u8	SignalQuality;	 /*  in 0-100 index. */
+	u8	RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */
+	u8	RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/*  in 0~100 index */
+	s8	RxPower; /*  in dBm Translate from PWdB */
+	s8	RecvSignalPower;/*  Real power in dBm for this packet, no
+				 * beautification and aggregation. Keep this raw
+				 * info to be used for the other procedures. */
+	u8	BTRxRSSIPercentage;
+	u8	SignalStrength; /*  in 0-100 index. */
+	u8	RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */
+	u8	RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */
+};
+
+struct odm_phy_dbg_info {
+	/* ODM Write,debug info */
+	s8	RxSNRdB[MAX_PATH_NUM_92CS];
+	u64	NumQryPhyStatus;
+	u64	NumQryPhyStatusCCK;
+	u64	NumQryPhyStatusOFDM;
+	/* Others */
+	s32	RxEVM[MAX_PATH_NUM_92CS];
+};
+
+struct odm_per_pkt_info {
+	s8	Rate;
+	u8	StationID;
+	bool	bPacketMatchBSSID;
+	bool	bPacketToSelf;
+	bool	bPacketBeacon;
+};
+
+struct odm_mac_status_info {
+	u8	test;
+};
+
+enum odm_ability {
+	/*  BB Team */
+	ODM_DIG			= 0x00000001,
+	ODM_HIGH_POWER		= 0x00000002,
+	ODM_CCK_CCA_TH		= 0x00000004,
+	ODM_FA_STATISTICS	= 0x00000008,
+	ODM_RAMASK		= 0x00000010,
+	ODM_RSSI_MONITOR	= 0x00000020,
+	ODM_SW_ANTDIV		= 0x00000040,
+	ODM_HW_ANTDIV		= 0x00000080,
+	ODM_BB_PWRSV		= 0x00000100,
+	ODM_2TPATHDIV		= 0x00000200,
+	ODM_1TPATHDIV		= 0x00000400,
+	ODM_PSD2AFH		= 0x00000800
+};
+
+/*  2011/20/20 MH For MP driver RT_WLAN_STA =  struct sta_info */
+/*  Please declare below ODM relative info in your STA info structure. */
+
+struct odm_sta_info {
+	/*  Driver Write */
+	bool	bUsed;		/*  record the sta status link or not? */
+	u8	IOTPeer;	/*  Enum value.	HT_IOT_PEER_E */
+
+	/*  ODM Write */
+	/* 1 PHY_STATUS_INFO */
+	u8	RSSI_Path[4];		/*  */
+	u8	RSSI_Ave;
+	u8	RXEVM[4];
+	u8	RXSNR[4];
+};
+
+/*  2011/10/20 MH Define Common info enum for all team. */
+
+enum odm_common_info_def {
+	/*  Fixed value: */
+
+	/* HOOK BEFORE REG INIT----------- */
+	ODM_CMNINFO_PLATFORM = 0,
+	ODM_CMNINFO_ABILITY,		/* ODM_ABILITY_E */
+	ODM_CMNINFO_INTERFACE,		/* ODM_INTERFACE_E */
+	ODM_CMNINFO_MP_TEST_CHIP,
+	ODM_CMNINFO_IC_TYPE,		/* ODM_IC_TYPE_E */
+	ODM_CMNINFO_CUT_VER,		/* ODM_CUT_VERSION_E */
+	ODM_CMNINFO_FAB_VER,		/* ODM_FAB_E */
+	ODM_CMNINFO_RF_TYPE,		/* ODM_RF_PATH_E or ODM_RF_TYPE_E? */
+	ODM_CMNINFO_BOARD_TYPE,		/* ODM_BOARD_TYPE_E */
+	ODM_CMNINFO_EXT_LNA,		/* true */
+	ODM_CMNINFO_EXT_PA,
+	ODM_CMNINFO_EXT_TRSW,
+	ODM_CMNINFO_PATCH_ID,		/* CUSTOMER ID */
+	ODM_CMNINFO_BINHCT_TEST,
+	ODM_CMNINFO_BWIFI_TEST,
+	ODM_CMNINFO_SMART_CONCURRENT,
+	/* HOOK BEFORE REG INIT-----------  */
+
+	/*  Dynamic value: */
+/*  POINTER REFERENCE-----------  */
+	ODM_CMNINFO_MAC_PHY_MODE,	/*  ODM_MAC_PHY_MODE_E */
+	ODM_CMNINFO_TX_UNI,
+	ODM_CMNINFO_RX_UNI,
+	ODM_CMNINFO_WM_MODE,		/*  ODM_WIRELESS_MODE_E */
+	ODM_CMNINFO_BAND,		/*  ODM_BAND_TYPE_E */
+	ODM_CMNINFO_SEC_CHNL_OFFSET,	/*  ODM_SEC_CHNL_OFFSET_E */
+	ODM_CMNINFO_SEC_MODE,		/*  ODM_SECURITY_E */
+	ODM_CMNINFO_BW,			/*  ODM_BW_E */
+	ODM_CMNINFO_CHNL,
+
+	ODM_CMNINFO_DMSP_GET_VALUE,
+	ODM_CMNINFO_BUDDY_ADAPTOR,
+	ODM_CMNINFO_DMSP_IS_MASTER,
+	ODM_CMNINFO_SCAN,
+	ODM_CMNINFO_POWER_SAVING,
+	ODM_CMNINFO_ONE_PATH_CCA,	/*  ODM_CCA_PATH_E */
+	ODM_CMNINFO_DRV_STOP,
+	ODM_CMNINFO_PNP_IN,
+	ODM_CMNINFO_INIT_ON,
+	ODM_CMNINFO_ANT_TEST,
+	ODM_CMNINFO_NET_CLOSED,
+	ODM_CMNINFO_MP_MODE,
+/*  POINTER REFERENCE----------- */
+
+/* CALL BY VALUE------------- */
+	ODM_CMNINFO_WIFI_DIRECT,
+	ODM_CMNINFO_WIFI_DISPLAY,
+	ODM_CMNINFO_LINK,
+	ODM_CMNINFO_RSSI_MIN,
+	ODM_CMNINFO_DBG_COMP,			/*  u64 */
+	ODM_CMNINFO_DBG_LEVEL,			/*  u32 */
+	ODM_CMNINFO_RA_THRESHOLD_HIGH,		/*  u8 */
+	ODM_CMNINFO_RA_THRESHOLD_LOW,		/*  u8 */
+	ODM_CMNINFO_RF_ANTENNA_TYPE,		/*  u8 */
+	ODM_CMNINFO_BT_DISABLED,
+	ODM_CMNINFO_BT_OPERATION,
+	ODM_CMNINFO_BT_DIG,
+	ODM_CMNINFO_BT_BUSY,			/* Check Bt is using or not */
+	ODM_CMNINFO_BT_DISABLE_EDCA,
+/* CALL BY VALUE-------------*/
+
+	/*  Dynamic ptr array hook itms. */
+	ODM_CMNINFO_STA_STATUS,
+	ODM_CMNINFO_PHY_STATUS,
+	ODM_CMNINFO_MAC_STATUS,
+	ODM_CMNINFO_MAX,
+};
+
+/*  2011/10/20 MH Define ODM support ability.  ODM_CMNINFO_ABILITY */
+
+enum odm_ability_def {
+	/*  BB ODM section BIT 0-15 */
+	ODM_BB_DIG			= BIT0,
+	ODM_BB_RA_MASK			= BIT1,
+	ODM_BB_DYNAMIC_TXPWR		= BIT2,
+	ODM_BB_FA_CNT			= BIT3,
+	ODM_BB_RSSI_MONITOR		= BIT4,
+	ODM_BB_CCK_PD			= BIT5,
+	ODM_BB_ANT_DIV			= BIT6,
+	ODM_BB_PWR_SAVE			= BIT7,
+	ODM_BB_PWR_TRA			= BIT8,
+	ODM_BB_RATE_ADAPTIVE		= BIT9,
+	ODM_BB_PATH_DIV			= BIT10,
+	ODM_BB_PSD			= BIT11,
+	ODM_BB_RXHP			= BIT12,
+
+	/*  MAC DM section BIT 16-23 */
+	ODM_MAC_EDCA_TURBO		= BIT16,
+	ODM_MAC_EARLY_MODE		= BIT17,
+
+	/*  RF ODM section BIT 24-31 */
+	ODM_RF_TX_PWR_TRACK		= BIT24,
+	ODM_RF_RX_GAIN_TRACK		= BIT25,
+	ODM_RF_CALIBRATION		= BIT26,
+};
+
+/* 	ODM_CMNINFO_INTERFACE */
+enum odm_interface_def {
+	ODM_ITRF_PCIE	=	0x1,
+	ODM_ITRF_USB	=	0x2,
+	ODM_ITRF_SDIO	=	0x4,
+	ODM_ITRF_ALL	=	0x7,
+};
+
+/*  ODM_CMNINFO_IC_TYPE */
+enum odm_ic_type {
+	ODM_RTL8192S	=	BIT0,
+	ODM_RTL8192C	=	BIT1,
+	ODM_RTL8192D	=	BIT2,
+	ODM_RTL8723A	=	BIT3,
+	ODM_RTL8188E	=	BIT4,
+	ODM_RTL8812	=	BIT5,
+	ODM_RTL8821	=	BIT6,
+};
+
+#define ODM_IC_11N_SERIES						\
+	(ODM_RTL8192S | ODM_RTL8192C | ODM_RTL8192D |			\
+	 ODM_RTL8723A | ODM_RTL8188E)
+#define ODM_IC_11AC_SERIES		(ODM_RTL8812)
+
+/* ODM_CMNINFO_CUT_VER */
+enum odm_cut_version {
+	ODM_CUT_A	=	1,
+	ODM_CUT_B	=	2,
+	ODM_CUT_C	=	3,
+	ODM_CUT_D	=	4,
+	ODM_CUT_E	=	5,
+	ODM_CUT_F	=	6,
+	ODM_CUT_TEST	=	7,
+};
+
+/*  ODM_CMNINFO_FAB_VER */
+enum odm_fab_Version {
+	ODM_TSMC	=	0,
+	ODM_UMC		=	1,
+};
+
+/*  ODM_CMNINFO_RF_TYPE */
+/*  For example 1T2R (A+AB = BIT0|BIT4|BIT5) */
+enum odm_rf_path {
+	ODM_RF_TX_A	=	BIT0,
+	ODM_RF_TX_B	=	BIT1,
+	ODM_RF_TX_C	=	BIT2,
+	ODM_RF_TX_D	=	BIT3,
+	ODM_RF_RX_A	=	BIT4,
+	ODM_RF_RX_B	=	BIT5,
+	ODM_RF_RX_C	=	BIT6,
+	ODM_RF_RX_D	=	BIT7,
+};
+
+enum odm_rf_type {
+	ODM_1T1R	=	0,
+	ODM_1T2R	=	1,
+	ODM_2T2R	=	2,
+	ODM_2T3R	=	3,
+	ODM_2T4R	=	4,
+	ODM_3T3R	=	5,
+	ODM_3T4R	=	6,
+	ODM_4T4R	=	7,
+};
+
+/*  ODM Dynamic common info value definition */
+
+enum odm_mac_phy_mode {
+	ODM_SMSP	= 0,
+	ODM_DMSP	= 1,
+	ODM_DMDP	= 2,
+};
+
+enum odm_bt_coexist {
+	ODM_BT_BUSY		= 1,
+	ODM_BT_ON		= 2,
+	ODM_BT_OFF		= 3,
+	ODM_BT_NONE		= 4,
+};
+
+/*  ODM_CMNINFO_OP_MODE */
+enum odm_operation_mode {
+	ODM_NO_LINK		= BIT0,
+	ODM_LINK		= BIT1,
+	ODM_SCAN		= BIT2,
+	ODM_POWERSAVE		= BIT3,
+	ODM_AP_MODE		= BIT4,
+	ODM_CLIENT_MODE		= BIT5,
+	ODM_AD_HOC		= BIT6,
+	ODM_WIFI_DIRECT		= BIT7,
+	ODM_WIFI_DISPLAY	= BIT8,
+};
+
+/*  ODM_CMNINFO_WM_MODE */
+enum odm_wireless_mode {
+	ODM_WM_UNKNOW	= 0x0,
+	ODM_WM_B	= BIT0,
+	ODM_WM_G	= BIT1,
+	ODM_WM_A	= BIT2,
+	ODM_WM_N24G	= BIT3,
+	ODM_WM_N5G	= BIT4,
+	ODM_WM_AUTO	= BIT5,
+	ODM_WM_AC	= BIT6,
+};
+
+/*  ODM_CMNINFO_BAND */
+enum odm_band_type {
+	ODM_BAND_2_4G	= BIT0,
+	ODM_BAND_5G	= BIT1,
+};
+
+/*  ODM_CMNINFO_SEC_CHNL_OFFSET */
+enum odm_sec_chnl_offset {
+	ODM_DONT_CARE	= 0,
+	ODM_BELOW	= 1,
+	ODM_ABOVE	= 2
+};
+
+/*  ODM_CMNINFO_SEC_MODE */
+enum odm_security {
+	ODM_SEC_OPEN		= 0,
+	ODM_SEC_WEP40		= 1,
+	ODM_SEC_TKIP		= 2,
+	ODM_SEC_RESERVE		= 3,
+	ODM_SEC_AESCCMP		= 4,
+	ODM_SEC_WEP104		= 5,
+	ODM_WEP_WPA_MIXED   	= 6, /*  WEP + WPA */
+	ODM_SEC_SMS4		= 7,
+};
+
+/*  ODM_CMNINFO_BW */
+enum odm_bw {
+	ODM_BW20M		= 0,
+	ODM_BW40M		= 1,
+	ODM_BW80M		= 2,
+	ODM_BW160M		= 3,
+	ODM_BW10M		= 4,
+};
+
+/*  ODM_CMNINFO_BOARD_TYPE */
+enum odm_board_type {
+	ODM_BOARD_NORMAL	= 0,
+	ODM_BOARD_HIGHPWR	= 1,
+	ODM_BOARD_MINICARD	= 2,
+	ODM_BOARD_SLIM		= 3,
+	ODM_BOARD_COMBO		= 4,
+};
+
+/*  ODM_CMNINFO_ONE_PATH_CCA */
+enum odm_cca_path {
+	ODM_CCA_2R		= 0,
+	ODM_CCA_1R_A		= 1,
+	ODM_CCA_1R_B		= 2,
+};
+
+struct odm_ra_info {
+	u8 RateID;
+	u32 RateMask;
+	u32 RAUseRate;
+	u8 RateSGI;
+	u8 RssiStaRA;
+	u8 PreRssiStaRA;
+	u8 SGIEnable;
+	u8 DecisionRate;
+	u8 PreRate;
+	u8 HighestRate;
+	u8 LowestRate;
+	u32 NscUp;
+	u32 NscDown;
+	u16 RTY[5];
+	u32 TOTAL;
+	u16 DROP;
+	u8 Active;
+	u16 RptTime;
+	u8 RAWaitingCounter;
+	u8 RAPendingCounter;
+	u8 PTActive;	/*  on or off */
+	u8 PTTryState;	/*  0 trying state, 1 for decision state */
+	u8 PTStage;	/*  0~6 */
+	u8 PTStopCount;	/* Stop PT counter */
+	u8 PTPreRate;	/*  if rate change do PT */
+	u8 PTPreRssi;	/*  if RSSI change 5% do PT */
+	u8 PTModeSS;	/*  decide whitch rate should do PT */
+	u8 RAstage;	/*  StageRA, decide how many times RA will be done
+			 * between PT */
+	u8 PTSmoothFactor;
+};
+
+struct ijk_matrix_regs_set {
+	bool	bIQKDone;
+	s32	Value[1][IQK_Matrix_REG_NUM];
+};
+
+struct odm_rf_cal {
+	/* for tx power tracking */
+	u32	RegA24; /*  for TempCCK */
+	s32	RegE94;
+	s32	RegE9C;
+	s32	RegEB4;
+	s32	RegEBC;
+
+	u8	TXPowercount;
+	bool	bTXPowerTrackingInit;
+	bool	bTXPowerTracking;
+	u8	TxPowerTrackControl; /* for mp mode, turn off txpwrtracking
+				      * as default */
+	u8	TM_Trigger;
+	u8	InternalPA5G[2];	/* pathA / pathB */
+
+	u8	ThermalMeter[2];    /* ThermalMeter, index 0 for RFIC0,
+				     * and 1 for RFIC1 */
+	u8	ThermalValue;
+	u8	ThermalValue_LCK;
+	u8	ThermalValue_IQK;
+	u8	ThermalValue_DPK;
+	u8	ThermalValue_AVG[AVG_THERMAL_NUM];
+	u8	ThermalValue_AVG_index;
+	u8	ThermalValue_RxGain;
+	u8	ThermalValue_Crystal;
+	u8	ThermalValue_DPKstore;
+	u8	ThermalValue_DPKtrack;
+	bool	TxPowerTrackingInProgress;
+	bool	bDPKenable;
+
+	bool	bReloadtxpowerindex;
+	u8	bRfPiEnable;
+	u32	TXPowerTrackingCallbackCnt; /* cosa add for debug */
+
+	u8	bCCKinCH14;
+	u8	CCK_index;
+	u8	OFDM_index[2];
+	bool bDoneTxpower;
+
+	u8	ThermalValue_HP[HP_THERMAL_NUM];
+	u8	ThermalValue_HP_index;
+	struct ijk_matrix_regs_set IQKMatrixRegSetting[IQK_Matrix_Settings_NUM];
+
+	u8	Delta_IQK;
+	u8	Delta_LCK;
+
+	/* for IQK */
+	u32	RegC04;
+	u32	Reg874;
+	u32	RegC08;
+	u32	RegB68;
+	u32	RegB6C;
+	u32	Reg870;
+	u32	Reg860;
+	u32	Reg864;
+
+	bool	bIQKInitialized;
+	bool	bLCKInProgress;
+	bool	bAntennaDetected;
+	u32	ADDA_backup[IQK_ADDA_REG_NUM];
+	u32	IQK_MAC_backup[IQK_MAC_REG_NUM];
+	u32	IQK_BB_backup_recover[9];
+	u32	IQK_BB_backup[IQK_BB_REG_NUM];
+
+	/* for APK */
+	u32	APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */
+	u8	bAPKdone;
+	u8	bAPKThermalMeterIgnore;
+	u8	bDPdone;
+	u8	bDPPathAOK;
+	u8	bDPPathBOK;
+};
+
+/*  ODM Dynamic common info value definition */
+
+struct fast_ant_train {
+	u8	Bssid[6];
+	u8	antsel_rx_keep_0;
+	u8	antsel_rx_keep_1;
+	u8	antsel_rx_keep_2;
+	u32	antSumRSSI[7];
+	u32	antRSSIcnt[7];
+	u32	antAveRSSI[7];
+	u8	FAT_State;
+	u32	TrainIdx;
+	u8	antsel_a[ODM_ASSOCIATE_ENTRY_NUM];
+	u8	antsel_b[ODM_ASSOCIATE_ENTRY_NUM];
+	u8	antsel_c[ODM_ASSOCIATE_ENTRY_NUM];
+	u32	MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM];
+	u32	AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM];
+	u32	MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
+	u32	AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
+	u8	RxIdleAnt;
+	bool	bBecomeLinked;
+};
+
+enum fat_state {
+	FAT_NORMAL_STATE		= 0,
+	FAT_TRAINING_STATE		= 1,
+};
+
+enum ant_div_type {
+	NO_ANTDIV			= 0xFF,
+	CG_TRX_HW_ANTDIV		= 0x01,
+	CGCS_RX_HW_ANTDIV		= 0x02,
+	FIXED_HW_ANTDIV			= 0x03,
+	CG_TRX_SMART_ANTDIV		= 0x04,
+	CGCS_RX_SW_ANTDIV		= 0x05,
+};
+
+/* Copy from SD4 defined structure. We use to support PHY DM integration. */
+struct odm_dm_struct {
+	/* 	Add for different team use temporarily */
+	struct adapter *Adapter;	/*  For CE/NIC team */
+	struct rtl8192cd_priv *priv;	/*  For AP/ADSL team */
+	/*  WHen you use above pointers, they must be initialized. */
+	bool	odm_ready;
+
+	struct rtl8192cd_priv *fake_priv;
+	u64	DebugComponents;
+	u32	DebugLevel;
+
+/*  ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
+	bool	bCckHighPower;
+	u8	RFPathRxEnable;		/*  ODM_CMNINFO_RFPATH_ENABLE */
+	u8	ControlChannel;
+/*  ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
+
+/* 1  COMMON INFORMATION */
+	/*  Init Value */
+/* HOOK BEFORE REG INIT----------- */
+	/*  ODM Platform info AP/ADSL/CE/MP = 1/2/3/4 */
+	u8	SupportPlatform;
+	/*  ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ¡K¡K = 1/2/3/¡K */
+	u32	SupportAbility;
+	/*  ODM PCIE/USB/SDIO/GSPI = 0/1/2/3 */
+	u8	SupportInterface;
+	/*  ODM composite or independent. Bit oriented/ 92C+92D+ .... or any
+	 *  other type = 1/2/3/... */
+	u32	SupportICType;
+	/*  Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... */
+	u8	CutVersion;
+	/*  Fab Version TSMC/UMC = 0/1 */
+	u8	FabVersion;
+	/*  RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... */
+	u8	RFType;
+	/*  Board Type Normal/HighPower/MiniCard/SLIM/Combo/. = 0/1/2/3/4/. */
+	u8	BoardType;
+	/*  with external LNA  NO/Yes = 0/1 */
+	u8	ExtLNA;
+	/*  with external PA  NO/Yes = 0/1 */
+	u8	ExtPA;
+	/*  with external TRSW  NO/Yes = 0/1 */
+	u8	ExtTRSW;
+	u8	PatchID; /* Customer ID */
+	bool	bInHctTest;
+	bool	bWIFITest;
+
+	bool	bDualMacSmartConcurrent;
+	u32	BK_SupportAbility;
+	u8	AntDivType;
+/* HOOK BEFORE REG INIT----------- */
+
+	/*  Dynamic Value */
+/*  POINTER REFERENCE----------- */
+
+	u8	u8_temp;
+	bool	bool_temp;
+	struct adapter *adapter_temp;
+
+	/*  MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 */
+	u8	*pMacPhyMode;
+	/* TX Unicast byte count */
+	u64	*pNumTxBytesUnicast;
+	/* RX Unicast byte count */
+	u64	*pNumRxBytesUnicast;
+	/*  Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 */
+	u8	*pWirelessMode; /* ODM_WIRELESS_MODE_E */
+	/*  Frequence band 2.4G/5G = 0/1 */
+	u8	*pBandType;
+	/*  Secondary channel offset don't_care/below/above = 0/1/2 */
+	u8	*pSecChOffset;
+	/*  Security mode Open/WEP/AES/TKIP = 0/1/2/3 */
+	u8	*pSecurity;
+	/*  BW info 20M/40M/80M = 0/1/2 */
+	u8	*pBandWidth;
+	/*  Central channel location Ch1/Ch2/.... */
+	u8	*pChannel;	/* central channel number */
+	/*  Common info for 92D DMSP */
+
+	bool	*pbGetValueFromOtherMac;
+	struct adapter **pBuddyAdapter;
+	bool	*pbMasterOfDMSP; /* MAC0: master, MAC1: slave */
+	/*  Common info for Status */
+	bool	*pbScanInProcess;
+	bool	*pbPowerSaving;
+	/*  CCA Path 2-path/path-A/path-B = 0/1/2; using ODM_CCA_PATH_E. */
+	u8	*pOnePathCCA;
+	/* pMgntInfo->AntennaTest */
+	u8	*pAntennaTest;
+	bool	*pbNet_closed;
+/*  POINTER REFERENCE----------- */
+	/*  */
+/* CALL BY VALUE------------- */
+	bool	bWIFI_Direct;
+	bool	bWIFI_Display;
+	bool	bLinked;
+	u8	RSSI_Min;
+	u8	InterfaceIndex; /*  Add for 92D  dual MAC: 0--Mac0 1--Mac1 */
+	bool	bIsMPChip;
+	bool	bOneEntryOnly;
+	/*  Common info for BTDM */
+	bool	bBtDisabled;	/*  BT is disabled */
+	bool	bBtHsOperation;	/*  BT HS mode is under progress */
+	u8	btHsDigVal;	/*  use BT rssi to decide the DIG value */
+	bool	bBtDisableEdcaTurbo;/* Under some condition, don't enable the
+				     * EDCA Turbo */
+	bool	bBtBusy;			/*  BT is busy. */
+/* CALL BY VALUE------------- */
+
+	/* 2 Define STA info. */
+	/*  _ODM_STA_INFO */
+	/*  For MP, we need to reduce one array pointer for default port.?? */
+	struct sta_info *pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM];
+
+	u16	CurrminRptTime;
+	struct odm_ra_info RAInfo[ODM_ASSOCIATE_ENTRY_NUM]; /* Use MacID as
+			* array index. STA MacID=0,
+			* VWiFi Client MacID={1, ODM_ASSOCIATE_ENTRY_NUM-1} */
+	/*  */
+	/*  2012/02/14 MH Add to share 88E ra with other SW team. */
+	/*  We need to colelct all support abilit to a proper area. */
+	/*  */
+	bool	RaSupport88E;
+
+	/*  Define ........... */
+
+	/*  Latest packet phy info (ODM write) */
+	struct odm_phy_dbg_info PhyDbgInfo;
+
+	/*  Latest packet phy info (ODM write) */
+	struct odm_mac_status_info *pMacInfo;
+
+	/*  Different Team independt structure?? */
+
+	/* ODM Structure */
+	struct fast_ant_train DM_FatTable;
+	struct rtw_dig	DM_DigTable;
+	struct rtl_ps	DM_PSTable;
+	struct dyn_primary_cca DM_PriCCA;
+	struct rx_hpc	DM_RXHP_Table;
+	struct false_alarm_stats FalseAlmCnt;
+	struct false_alarm_stats FlaseAlmCntBuddyAdapter;
+	struct sw_ant_switch DM_SWAT_Table;
+	bool		RSSI_test;
+
+	struct edca_turbo DM_EDCA_Table;
+	u32		WMMEDCA_BE;
+	/*  Copy from SD4 structure */
+	/*  */
+	/*  ================================================== */
+	/*  */
+
+	bool	*pbDriverStopped;
+	bool	*pbDriverIsGoingToPnpSetPowerSleep;
+	bool	*pinit_adpt_in_progress;
+
+	/* PSD */
+	bool	bUserAssignLevel;
+	struct timer_list PSDTimer;
+	u8	RSSI_BT;			/* come from BT */
+	bool	bPSDinProcess;
+	bool	bDMInitialGainEnable;
+
+	/* for rate adaptive, in fact,  88c/92c fw will handle this */
+	u8	bUseRAMask;
+
+	struct odm_rate_adapt RateAdaptive;
+
+	struct odm_rf_cal RFCalibrateInfo;
+
+	/*  TX power tracking */
+	u8	BbSwingIdxOfdm;
+	u8	BbSwingIdxOfdmCurrent;
+	u8	BbSwingIdxOfdmBase;
+	bool	BbSwingFlagOfdm;
+	u8	BbSwingIdxCck;
+	u8	BbSwingIdxCckCurrent;
+	u8	BbSwingIdxCckBase;
+	bool	BbSwingFlagCck;
+	u8	*mp_mode;
+	/*  ODM system resource. */
+
+	/*  ODM relative time. */
+	struct timer_list PathDivSwitchTimer;
+	/* 2011.09.27 add for Path Diversity */
+	struct timer_list CCKPathDiversityTimer;
+	struct timer_list FastAntTrainingTimer;
+};		/*  DM_Dynamic_Mechanism_Structure */
+
+#define ODM_RF_PATH_MAX 2
+
+enum ODM_RF_RADIO_PATH {
+	ODM_RF_PATH_A = 0,   /* Radio Path A */
+	ODM_RF_PATH_B = 1,   /* Radio Path B */
+	ODM_RF_PATH_C = 2,   /* Radio Path C */
+	ODM_RF_PATH_D = 3,   /* Radio Path D */
+};
+
+enum ODM_RF_CONTENT {
+	odm_radioa_txt = 0x1000,
+	odm_radiob_txt = 0x1001,
+	odm_radioc_txt = 0x1002,
+	odm_radiod_txt = 0x1003
+};
+
+enum odm_bb_config_type {
+    CONFIG_BB_PHY_REG,
+    CONFIG_BB_AGC_TAB,
+    CONFIG_BB_AGC_TAB_2G,
+    CONFIG_BB_AGC_TAB_5G,
+    CONFIG_BB_PHY_REG_PG,
+};
+
+/*  Status code */
+enum rt_status {
+	RT_STATUS_SUCCESS,
+	RT_STATUS_FAILURE,
+	RT_STATUS_PENDING,
+	RT_STATUS_RESOURCE,
+	RT_STATUS_INVALID_CONTEXT,
+	RT_STATUS_INVALID_PARAMETER,
+	RT_STATUS_NOT_SUPPORT,
+	RT_STATUS_OS_API_FAILED,
+};
+
+/* 3=========================================================== */
+/* 3 DIG */
+/* 3=========================================================== */
+
+enum dm_dig_op {
+	RT_TYPE_THRESH_HIGH	= 0,
+	RT_TYPE_THRESH_LOW	= 1,
+	RT_TYPE_BACKOFF		= 2,
+	RT_TYPE_RX_GAIN_MIN	= 3,
+	RT_TYPE_RX_GAIN_MAX	= 4,
+	RT_TYPE_ENABLE		= 5,
+	RT_TYPE_DISABLE		= 6,
+	DIG_OP_TYPE_MAX
+};
+
+#define		DM_DIG_THRESH_HIGH	40
+#define		DM_DIG_THRESH_LOW	35
+
+#define		DM_SCAN_RSSI_TH		0x14 /* scan return issue for LC */
+
+
+#define		DM_false_ALARM_THRESH_LOW	400
+#define		DM_false_ALARM_THRESH_HIGH	1000
+
+#define		DM_DIG_MAX_NIC			0x3e
+#define		DM_DIG_MIN_NIC			0x1e /* 0x22/0x1c */
+
+#define		DM_DIG_MAX_AP			0x32
+#define		DM_DIG_MIN_AP			0x20
+
+#define		DM_DIG_MAX_NIC_HP		0x46
+#define		DM_DIG_MIN_NIC_HP		0x2e
+
+#define		DM_DIG_MAX_AP_HP		0x42
+#define		DM_DIG_MIN_AP_HP		0x30
+
+/* vivi 92c&92d has different definition, 20110504 */
+/* this is for 92c */
+#define		DM_DIG_FA_TH0			0x200/* 0x20 */
+#define		DM_DIG_FA_TH1			0x300/* 0x100 */
+#define		DM_DIG_FA_TH2			0x400/* 0x200 */
+/* this is for 92d */
+#define		DM_DIG_FA_TH0_92D		0x100
+#define		DM_DIG_FA_TH1_92D		0x400
+#define		DM_DIG_FA_TH2_92D		0x600
+
+#define		DM_DIG_BACKOFF_MAX		12
+#define		DM_DIG_BACKOFF_MIN		-4
+#define		DM_DIG_BACKOFF_DEFAULT		10
+
+/* 3=========================================================== */
+/* 3 AGC RX High Power Mode */
+/* 3=========================================================== */
+#define	  LNA_Low_Gain_1		0x64
+#define	  LNA_Low_Gain_2		0x5A
+#define	  LNA_Low_Gain_3		0x58
+
+#define	  FA_RXHP_TH1			5000
+#define	  FA_RXHP_TH2			1500
+#define	  FA_RXHP_TH3			800
+#define	  FA_RXHP_TH4			600
+#define	  FA_RXHP_TH5			500
+
+/* 3=========================================================== */
+/* 3 EDCA */
+/* 3=========================================================== */
+
+/* 3=========================================================== */
+/* 3 Dynamic Tx Power */
+/* 3=========================================================== */
+/* Dynamic Tx Power Control Threshold */
+#define		TX_POWER_NEAR_FIELD_THRESH_LVL2	74
+#define		TX_POWER_NEAR_FIELD_THRESH_LVL1	67
+#define		TX_POWER_NEAR_FIELD_THRESH_AP		0x3F
+
+#define		TxHighPwrLevel_Normal		0
+#define		TxHighPwrLevel_Level1		1
+#define		TxHighPwrLevel_Level2		2
+#define		TxHighPwrLevel_BT1		3
+#define		TxHighPwrLevel_BT2		4
+#define		TxHighPwrLevel_15		5
+#define		TxHighPwrLevel_35		6
+#define		TxHighPwrLevel_50		7
+#define		TxHighPwrLevel_70		8
+#define		TxHighPwrLevel_100		9
+
+/* 3=========================================================== */
+/* 3 Rate Adaptive */
+/* 3=========================================================== */
+#define		DM_RATR_STA_INIT		0
+#define		DM_RATR_STA_HIGH		1
+#define		DM_RATR_STA_MIDDLE		2
+#define		DM_RATR_STA_LOW			3
+
+/* 3=========================================================== */
+/* 3 BB Power Save */
+/* 3=========================================================== */
+
+
+enum dm_1r_cca {
+	CCA_1R = 0,
+	CCA_2R = 1,
+	CCA_MAX = 2,
+};
+
+enum dm_rf {
+	RF_Save = 0,
+	RF_Normal = 1,
+	RF_MAX = 2,
+};
+
+/* 3=========================================================== */
+/* 3 Antenna Diversity */
+/* 3=========================================================== */
+enum dm_swas {
+	Antenna_A = 1,
+	Antenna_B = 2,
+	Antenna_MAX = 3,
+};
+
+/*  Maximal number of antenna detection mechanism needs to perform. */
+#define	MAX_ANTENNA_DETECTION_CNT	10
+
+/*  Extern Global Variables. */
+#define	OFDM_TABLE_SIZE_92C	37
+#define	OFDM_TABLE_SIZE_92D	43
+#define	CCK_TABLE_SIZE		33
+
+extern	u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D];
+extern	u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8];
+extern	u8 CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8];
+
+/*  check Sta pointer valid or not */
+#define IS_STA_VALID(pSta)		(pSta)
+/*  20100514 Joseph: Add definition for antenna switching test after link. */
+/*  This indicates two different the steps. */
+/*  In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the
+ *  signal on the air. */
+/*  In SWAW_STEP_DETERMINE, driver just compares the signal captured in
+ *  SWAW_STEP_PEAK */
+/*  with original RSSI to determine if it is necessary to switch antenna. */
+#define SWAW_STEP_PEAK		0
+#define SWAW_STEP_DETERMINE	1
+
+void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI);
+void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres);
+
+void ODM_SetAntenna(struct odm_dm_struct *pDM_Odm, u8 Antenna);
+
+
+#define dm_RF_Saving	ODM_RF_Saving
+void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal);
+
+#define SwAntDivRestAfterLink	ODM_SwAntDivRestAfterLink
+void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm);
+
+#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck
+void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm);
+
+bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI,
+		      bool bForceUpdate, u8 *pRATRState);
+
+#define dm_SWAW_RSSI_Check	ODM_SwAntDivChkPerPktRssi
+void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID,
+			       struct odm_phy_status_info *pPhyInfo);
+
+u32 ConvertTo_dB(u32 Value);
+
+u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point,
+	       u8 initial_gain_psd);
+
+void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm);
+
+u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid,
+			u32 ra_mask, u8 rssi_level);
+
+void ODM_DMInit(struct odm_dm_struct *pDM_Odm);
+
+void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm);
+
+void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm,
+		     enum odm_common_info_def CmnInfo, u32 Value);
+
+void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm,
+		     enum odm_common_info_def CmnInfo, void *pValue);
+
+void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm,
+			     enum odm_common_info_def CmnInfo,
+			     u16 Index, void *pValue);
+
+void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value);
+
+void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm);
+
+void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm);
+
+void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm);
+
+void ODM_ResetIQKResult(struct odm_dm_struct *pDM_Odm);
+
+void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId,
+			      u32 PWDBAll, bool isCCKrate);
+
+void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm);
+
+bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode);
+
+void odm_dtc(struct odm_dm_struct *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_HWConfig.h b/drivers/staging/rtl8188eu/include/odm_HWConfig.h
new file mode 100644
index 0000000..63779f5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_HWConfig.h
@@ -0,0 +1,132 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef	__HALHWOUTSRC_H__
+#define __HALHWOUTSRC_H__
+
+/*  Definition */
+/*  CCK Rates, TxHT = 0 */
+#define DESC92C_RATE1M				0x00
+#define DESC92C_RATE2M				0x01
+#define DESC92C_RATE5_5M			0x02
+#define DESC92C_RATE11M				0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC92C_RATE6M				0x04
+#define DESC92C_RATE9M				0x05
+#define DESC92C_RATE12M				0x06
+#define DESC92C_RATE18M				0x07
+#define DESC92C_RATE24M				0x08
+#define DESC92C_RATE36M				0x09
+#define DESC92C_RATE48M				0x0a
+#define DESC92C_RATE54M				0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC92C_RATEMCS0			0x0c
+#define DESC92C_RATEMCS1			0x0d
+#define DESC92C_RATEMCS2			0x0e
+#define DESC92C_RATEMCS3			0x0f
+#define DESC92C_RATEMCS4			0x10
+#define DESC92C_RATEMCS5			0x11
+#define DESC92C_RATEMCS6			0x12
+#define DESC92C_RATEMCS7			0x13
+#define DESC92C_RATEMCS8			0x14
+#define DESC92C_RATEMCS9			0x15
+#define DESC92C_RATEMCS10			0x16
+#define DESC92C_RATEMCS11			0x17
+#define DESC92C_RATEMCS12			0x18
+#define DESC92C_RATEMCS13			0x19
+#define DESC92C_RATEMCS14			0x1a
+#define DESC92C_RATEMCS15			0x1b
+#define DESC92C_RATEMCS15_SG			0x1c
+#define DESC92C_RATEMCS32			0x20
+
+/*  structure and define */
+
+struct phy_rx_agc_info {
+	#ifdef __LITTLE_ENDIAN
+		u8	gain:7, trsw:1;
+	#else
+		u8	trsw:1, gain:7;
+	#endif
+};
+
+struct phy_status_rpt {
+	struct phy_rx_agc_info path_agc[2];
+	u8	ch_corr[2];
+	u8	cck_sig_qual_ofdm_pwdb_all;
+	u8	cck_agc_rpt_ofdm_cfosho_a;
+	u8	cck_rpt_b_ofdm_cfosho_b;
+	u8	rsvd_1;/* ch_corr_msb; */
+	u8	noise_power_db_msb;
+	u8	path_cfotail[2];
+	u8	pcts_mask[2];
+	s8	stream_rxevm[2];
+	u8	path_rxsnr[2];
+	u8	noise_power_db_lsb;
+	u8	rsvd_2[3];
+	u8	stream_csi[2];
+	u8	stream_target_csi[2];
+	s8	sig_evm;
+	u8	rsvd_3;
+
+#ifdef __LITTLE_ENDIAN
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+	u8	sgi_en:1;
+	u8	rxsc:2;
+	u8	idle_long:1;
+	u8	r_ant_train_en:1;
+	u8	ant_sel_b:1;
+	u8	ant_sel:1;
+#else	/*  _BIG_ENDIAN_ */
+	u8	ant_sel:1;
+	u8	ant_sel_b:1;
+	u8	r_ant_train_en:1;
+	u8	idle_long:1;
+	u8	rxsc:2;
+	u8	sgi_en:1;
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+#endif
+};
+
+void odm_Init_RSSIForDM(struct odm_dm_struct *pDM_Odm);
+
+void ODM_PhyStatusQuery(struct odm_dm_struct *pDM_Odm,
+			struct odm_phy_status_info *pPhyInfo,
+			u8 *pPhyStatus,
+			struct odm_per_pkt_info *pPktinfo);
+
+void ODM_MacStatusQuery(struct odm_dm_struct *pDM_Odm,
+			u8 *pMacStatus,
+			u8	MacID,
+			bool	bPacketMatchBSSID,
+			bool	bPacketToSelf,
+			bool	bPacketBeacon);
+
+enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *pDM_Odm,
+					   enum ODM_RF_RADIO_PATH Content,
+					   enum ODM_RF_RADIO_PATH eRFPath);
+
+enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *pDM_Odm,
+					   enum odm_bb_config_type ConfigType);
+
+enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RTL8188E.h b/drivers/staging/rtl8188eu/include/odm_RTL8188E.h
new file mode 100644
index 0000000..f96ad5a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RTL8188E.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef	__ODM_RTL8188E_H__
+#define __ODM_RTL8188E_H__
+
+#define	MAIN_ANT	0
+#define	AUX_ANT	1
+#define	MAIN_ANT_CG_TRX	1
+#define	AUX_ANT_CG_TRX	0
+#define	MAIN_ANT_CGCS_RX	0
+#define	AUX_ANT_CGCS_RX	1
+
+void ODM_DIG_LowerBound_88E(struct odm_dm_struct *pDM_Odm);
+
+void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *pDM_Odm);
+
+void ODM_AntennaDiversity_88E(struct odm_dm_struct *pDM_Odm);
+
+void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *pDM_Odm, u8 *pDesc,
+			      u8 macId);
+
+void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *pDM_Odm, u8 Ant);
+
+void ODM_AntselStatistics_88E(struct odm_dm_struct *pDM_Odm, u8	antsel_tr_mux,
+			      u32 MacId, u8 RxPWDBAll);
+
+void odm_FastAntTraining(struct odm_dm_struct *pDM_Odm);
+
+void odm_FastAntTrainingCallback(struct odm_dm_struct *pDM_Odm);
+
+void odm_FastAntTrainingWorkItemCallback(struct odm_dm_struct *pDM_Odm);
+
+void odm_PrimaryCCA_Init(struct odm_dm_struct *pDM_Odm);
+
+bool ODM_DynamicPrimaryCCA_DupRTS(struct odm_dm_struct *pDM_Odm);
+
+void odm_DynamicPrimaryCCA(struct odm_dm_struct *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h b/drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h
new file mode 100644
index 0000000..727e6b2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RegConfig8188E.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_ODM_REGCONFIG_H_8188E
+#define __INC_ODM_REGCONFIG_H_8188E
+
+void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data,
+			   enum ODM_RF_RADIO_PATH  RF_PATH, u32 RegAddr);
+
+void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm,
+			       u32 Addr, u32 Data);
+
+void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm,
+			       u32 Addr, u32 Data);
+
+void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data);
+
+void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+			    u32 Bitmask, u32 Data);
+
+void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+				   u32 Bitmask, u32 Data);
+
+void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr,
+			    u32 Bitmask, u32 Data);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h b/drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h
new file mode 100644
index 0000000..f08775c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RegDefine11AC.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef	__ODM_REGDEFINE11AC_H__
+#define __ODM_REGDEFINE11AC_H__
+
+/* 2 RF REG LIST */
+
+
+
+/* 2 BB REG LIST */
+/* PAGE 8 */
+/* PAGE 9 */
+#define	ODM_REG_OFDM_FA_RST_11AC		0x9A4
+/* PAGE A */
+#define	ODM_REG_CCK_CCA_11AC				0xA0A
+#define	ODM_REG_CCK_FA_RST_11AC			0xA2C
+#define	ODM_REG_CCK_FA_11AC				0xA5C
+/* PAGE C */
+#define	ODM_REG_IGI_A_11AC				0xC50
+/* PAGE E */
+#define	ODM_REG_IGI_B_11AC				0xE50
+/* PAGE F */
+#define	ODM_REG_OFDM_FA_11AC			0xF48
+
+
+/* 2 MAC REG LIST */
+
+
+
+
+/* DIG Related */
+#define	ODM_BIT_IGI_11AC				0xFFFFFFFF
+
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_RegDefine11N.h b/drivers/staging/rtl8188eu/include/odm_RegDefine11N.h
new file mode 100644
index 0000000..5a61f90
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_RegDefine11N.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef	__ODM_REGDEFINE11N_H__
+#define __ODM_REGDEFINE11N_H__
+
+
+/* 2 RF REG LIST */
+#define	ODM_REG_RF_MODE_11N				0x00
+#define	ODM_REG_RF_0B_11N				0x0B
+#define	ODM_REG_CHNBW_11N				0x18
+#define	ODM_REG_T_METER_11N				0x24
+#define	ODM_REG_RF_25_11N				0x25
+#define	ODM_REG_RF_26_11N				0x26
+#define	ODM_REG_RF_27_11N				0x27
+#define	ODM_REG_RF_2B_11N				0x2B
+#define	ODM_REG_RF_2C_11N				0x2C
+#define	ODM_REG_RXRF_A3_11N				0x3C
+#define	ODM_REG_T_METER_92D_11N			0x42
+#define	ODM_REG_T_METER_88E_11N			0x42
+
+
+
+/* 2 BB REG LIST */
+/* PAGE 8 */
+#define	ODM_REG_BB_CTRL_11N				0x800
+#define	ODM_REG_RF_PIN_11N				0x804
+#define	ODM_REG_PSD_CTRL_11N				0x808
+#define	ODM_REG_TX_ANT_CTRL_11N			0x80C
+#define	ODM_REG_BB_PWR_SAV5_11N			0x818
+#define	ODM_REG_CCK_RPT_FORMAT_11N		0x824
+#define	ODM_REG_RX_DEFUALT_A_11N		0x858
+#define	ODM_REG_RX_DEFUALT_B_11N		0x85A
+#define	ODM_REG_BB_PWR_SAV3_11N			0x85C
+#define	ODM_REG_ANTSEL_CTRL_11N			0x860
+#define	ODM_REG_RX_ANT_CTRL_11N			0x864
+#define	ODM_REG_PIN_CTRL_11N				0x870
+#define	ODM_REG_BB_PWR_SAV1_11N			0x874
+#define	ODM_REG_ANTSEL_PATH_11N			0x878
+#define	ODM_REG_BB_3WIRE_11N			0x88C
+#define	ODM_REG_SC_CNT_11N				0x8C4
+#define	ODM_REG_PSD_DATA_11N			0x8B4
+/* PAGE 9 */
+#define	ODM_REG_ANT_MAPPING1_11N		0x914
+#define	ODM_REG_ANT_MAPPING2_11N		0x918
+/* PAGE A */
+#define	ODM_REG_CCK_ANTDIV_PARA1_11N	0xA00
+#define	ODM_REG_CCK_CCA_11N				0xA0A
+#define	ODM_REG_CCK_ANTDIV_PARA2_11N	0xA0C
+#define	ODM_REG_CCK_ANTDIV_PARA3_11N	0xA10
+#define	ODM_REG_CCK_ANTDIV_PARA4_11N	0xA14
+#define	ODM_REG_CCK_FILTER_PARA1_11N	0xA22
+#define	ODM_REG_CCK_FILTER_PARA2_11N	0xA23
+#define	ODM_REG_CCK_FILTER_PARA3_11N	0xA24
+#define	ODM_REG_CCK_FILTER_PARA4_11N	0xA25
+#define	ODM_REG_CCK_FILTER_PARA5_11N	0xA26
+#define	ODM_REG_CCK_FILTER_PARA6_11N	0xA27
+#define	ODM_REG_CCK_FILTER_PARA7_11N	0xA28
+#define	ODM_REG_CCK_FILTER_PARA8_11N	0xA29
+#define	ODM_REG_CCK_FA_RST_11N			0xA2C
+#define	ODM_REG_CCK_FA_MSB_11N			0xA58
+#define	ODM_REG_CCK_FA_LSB_11N			0xA5C
+#define	ODM_REG_CCK_CCA_CNT_11N			0xA60
+#define	ODM_REG_BB_PWR_SAV4_11N			0xA74
+/* PAGE B */
+#define	ODM_REG_LNA_SWITCH_11N			0xB2C
+#define	ODM_REG_PATH_SWITCH_11N			0xB30
+#define	ODM_REG_RSSI_CTRL_11N			0xB38
+#define	ODM_REG_CONFIG_ANTA_11N			0xB68
+#define	ODM_REG_RSSI_BT_11N				0xB9C
+/* PAGE C */
+#define	ODM_REG_OFDM_FA_HOLDC_11N		0xC00
+#define	ODM_REG_RX_PATH_11N				0xC04
+#define	ODM_REG_TRMUX_11N				0xC08
+#define	ODM_REG_OFDM_FA_RSTC_11N		0xC0C
+#define	ODM_REG_RXIQI_MATRIX_11N		0xC14
+#define	ODM_REG_TXIQK_MATRIX_LSB1_11N	0xC4C
+#define	ODM_REG_IGI_A_11N				0xC50
+#define	ODM_REG_ANTDIV_PARA2_11N		0xC54
+#define	ODM_REG_IGI_B_11N					0xC58
+#define	ODM_REG_ANTDIV_PARA3_11N		0xC5C
+#define	ODM_REG_BB_PWR_SAV2_11N			0xC70
+#define	ODM_REG_RX_OFF_11N				0xC7C
+#define	ODM_REG_TXIQK_MATRIXA_11N		0xC80
+#define	ODM_REG_TXIQK_MATRIXB_11N		0xC88
+#define	ODM_REG_TXIQK_MATRIXA_LSB2_11N	0xC94
+#define	ODM_REG_TXIQK_MATRIXB_LSB2_11N	0xC9C
+#define	ODM_REG_RXIQK_MATRIX_LSB_11N	0xCA0
+#define	ODM_REG_ANTDIV_PARA1_11N		0xCA4
+#define	ODM_REG_OFDM_FA_TYPE1_11N		0xCF0
+/* PAGE D */
+#define	ODM_REG_OFDM_FA_RSTD_11N		0xD00
+#define	ODM_REG_OFDM_FA_TYPE2_11N		0xDA0
+#define	ODM_REG_OFDM_FA_TYPE3_11N		0xDA4
+#define	ODM_REG_OFDM_FA_TYPE4_11N		0xDA8
+/* PAGE E */
+#define	ODM_REG_TXAGC_A_6_18_11N		0xE00
+#define	ODM_REG_TXAGC_A_24_54_11N		0xE04
+#define	ODM_REG_TXAGC_A_1_MCS32_11N	0xE08
+#define	ODM_REG_TXAGC_A_MCS0_3_11N		0xE10
+#define	ODM_REG_TXAGC_A_MCS4_7_11N		0xE14
+#define	ODM_REG_TXAGC_A_MCS8_11_11N	0xE18
+#define	ODM_REG_TXAGC_A_MCS12_15_11N	0xE1C
+#define	ODM_REG_FPGA0_IQK_11N			0xE28
+#define	ODM_REG_TXIQK_TONE_A_11N		0xE30
+#define	ODM_REG_RXIQK_TONE_A_11N		0xE34
+#define	ODM_REG_TXIQK_PI_A_11N			0xE38
+#define	ODM_REG_RXIQK_PI_A_11N			0xE3C
+#define	ODM_REG_TXIQK_11N				0xE40
+#define	ODM_REG_RXIQK_11N				0xE44
+#define	ODM_REG_IQK_AGC_PTS_11N			0xE48
+#define	ODM_REG_IQK_AGC_RSP_11N			0xE4C
+#define	ODM_REG_BLUETOOTH_11N			0xE6C
+#define	ODM_REG_RX_WAIT_CCA_11N			0xE70
+#define	ODM_REG_TX_CCK_RFON_11N			0xE74
+#define	ODM_REG_TX_CCK_BBON_11N			0xE78
+#define	ODM_REG_OFDM_RFON_11N			0xE7C
+#define	ODM_REG_OFDM_BBON_11N			0xE80
+#define		ODM_REG_TX2RX_11N				0xE84
+#define	ODM_REG_TX2TX_11N				0xE88
+#define	ODM_REG_RX_CCK_11N				0xE8C
+#define	ODM_REG_RX_OFDM_11N				0xED0
+#define	ODM_REG_RX_WAIT_RIFS_11N		0xED4
+#define	ODM_REG_RX2RX_11N				0xED8
+#define	ODM_REG_STANDBY_11N				0xEDC
+#define	ODM_REG_SLEEP_11N				0xEE0
+#define	ODM_REG_PMPD_ANAEN_11N			0xEEC
+
+
+
+
+
+
+
+/* 2 MAC REG LIST */
+#define	ODM_REG_BB_RST_11N				0x02
+#define	ODM_REG_ANTSEL_PIN_11N			0x4C
+#define	ODM_REG_EARLY_MODE_11N			0x4D0
+#define	ODM_REG_RSSI_MONITOR_11N		0x4FE
+#define	ODM_REG_EDCA_VO_11N				0x500
+#define	ODM_REG_EDCA_VI_11N				0x504
+#define	ODM_REG_EDCA_BE_11N				0x508
+#define	ODM_REG_EDCA_BK_11N				0x50C
+#define	ODM_REG_TXPAUSE_11N				0x522
+#define	ODM_REG_RESP_TX_11N				0x6D8
+#define	ODM_REG_ANT_TRAIN_PARA1_11N	0x7b0
+#define	ODM_REG_ANT_TRAIN_PARA2_11N	0x7b4
+
+
+/* DIG Related */
+#define	ODM_BIT_IGI_11N					0x0000007F
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_debug.h b/drivers/staging/rtl8188eu/include/odm_debug.h
new file mode 100644
index 0000000..a9ba6df
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_debug.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+
+#ifndef	__ODM_DBG_H__
+#define __ODM_DBG_H__
+
+
+/*  */
+/*	Define the debug levels */
+/*  */
+/*	1. DBG_TRACE and DBG_LOUD are used for normal cases. */
+/*	They can help SW engineer to develope or trace states changed */
+/*	and also help HW enginner to trace every operation to and from HW, */
+/*	e.g IO, Tx, Rx. */
+/*  */
+/*	2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */
+/*	which help us to debug SW or HW. */
+
+/*	Never used in a call to ODM_RT_TRACE()! */
+#define ODM_DBG_OFF				1
+
+/*	Fatal bug. */
+/*	For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */
+/*	resource allocation failed, unexpected HW behavior, HW BUG and so on. */
+#define ODM_DBG_SERIOUS				2
+
+/*	Abnormal, rare, or unexpeted cases. */
+/*	For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. */
+#define ODM_DBG_WARNING				3
+
+/*	Normal case with useful information about current SW or HW state. */
+/*	For example, Tx/Rx descriptor to fill, Tx/Rx descr. completed status, */
+/*	SW protocol state change, dynamic mechanism state change and so on. */
+/*  */
+#define ODM_DBG_LOUD					4
+
+/*	Normal case with detail execution flow or information. */
+#define ODM_DBG_TRACE					5
+
+/*  Define the tracing components */
+/* BB Functions */
+#define ODM_COMP_DIG					BIT0
+#define ODM_COMP_RA_MASK				BIT1
+#define ODM_COMP_DYNAMIC_TXPWR				BIT2
+#define ODM_COMP_FA_CNT					BIT3
+#define ODM_COMP_RSSI_MONITOR				BIT4
+#define ODM_COMP_CCK_PD					BIT5
+#define ODM_COMP_ANT_DIV				BIT6
+#define ODM_COMP_PWR_SAVE				BIT7
+#define ODM_COMP_PWR_TRA				BIT8
+#define ODM_COMP_RATE_ADAPTIVE				BIT9
+#define ODM_COMP_PATH_DIV				BIT10
+#define ODM_COMP_PSD					BIT11
+#define ODM_COMP_DYNAMIC_PRICCA				BIT12
+#define ODM_COMP_RXHP					BIT13
+/* MAC Functions */
+#define ODM_COMP_EDCA_TURBO				BIT16
+#define ODM_COMP_EARLY_MODE				BIT17
+/* RF Functions */
+#define ODM_COMP_TX_PWR_TRACK				BIT24
+#define ODM_COMP_RX_GAIN_TRACK				BIT25
+#define ODM_COMP_CALIBRATION				BIT26
+/* Common Functions */
+#define ODM_COMP_COMMON					BIT30
+#define ODM_COMP_INIT					BIT31
+
+/*------------------------Export Marco Definition---------------------------*/
+#define DbgPrint	pr_info
+#define RT_PRINTK(fmt, args...)				\
+	DbgPrint( "%s(): " fmt, __func__, ## args);
+
+#ifndef ASSERT
+	#define ASSERT(expr)
+#endif
+
+#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt)				\
+	if (((comp) & pDM_Odm->DebugComponents) &&			\
+	    (level <= pDM_Odm->DebugLevel)) {				\
+		if (pDM_Odm->SupportICType == ODM_RTL8192C)		\
+			DbgPrint("[ODM-92C] ");				\
+		else if (pDM_Odm->SupportICType == ODM_RTL8192D)	\
+			DbgPrint("[ODM-92D] ");				\
+		else if (pDM_Odm->SupportICType == ODM_RTL8723A)	\
+			DbgPrint("[ODM-8723A] ");			\
+		else if (pDM_Odm->SupportICType == ODM_RTL8188E)	\
+			DbgPrint("[ODM-8188E] ");			\
+		else if (pDM_Odm->SupportICType == ODM_RTL8812)		\
+			DbgPrint("[ODM-8812] ");			\
+		else if (pDM_Odm->SupportICType == ODM_RTL8821)		\
+			DbgPrint("[ODM-8821] ");			\
+		RT_PRINTK fmt;						\
+	}
+
+#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt)			\
+	if (((comp) & pDM_Odm->DebugComponents) &&			\
+	    (level <= pDM_Odm->DebugLevel)) {				\
+		RT_PRINTK fmt;						\
+	}
+
+#define ODM_RT_ASSERT(pDM_Odm, expr, fmt)				\
+	if (!(expr)) {							\
+		DbgPrint( "Assertion failed! %s at ......\n", #expr);	\
+		DbgPrint( "      ......%s,%s,line=%d\n", __FILE__,	\
+			__func__, __LINE__);				\
+		RT_PRINTK fmt;						\
+		ASSERT(false);						\
+	}
+#define ODM_dbg_enter() { DbgPrint("==> %s\n", __func__); }
+#define ODM_dbg_exit() { DbgPrint("<== %s\n", __func__); }
+#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); }
+
+#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr)		\
+	if (((comp) & pDM_Odm->DebugComponents) &&			\
+	    (level <= pDM_Odm->DebugLevel)) {				\
+		int __i;						\
+		u8 *__ptr = (u8 *)ptr;					\
+		DbgPrint("[ODM] ");					\
+		DbgPrint(title_str);					\
+		DbgPrint(" ");						\
+		for (__i = 0; __i < 6; __i++)				\
+			DbgPrint("%02X%s", __ptr[__i], (__i==5)?"":"-");\
+		DbgPrint("\n");						\
+	}
+
+void ODM_InitDebugSetting(struct odm_dm_struct *pDM_Odm);
+
+#endif	/*  __ODM_DBG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_interface.h b/drivers/staging/rtl8188eu/include/odm_interface.h
new file mode 100644
index 0000000..e5c8704
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_interface.h
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef	__ODM_INTERFACE_H__
+#define __ODM_INTERFACE_H__
+
+/*  */
+/*  =========== Constant/Structure/Enum/... Define */
+/*  */
+
+/*  */
+/*  =========== Macro Define */
+/*  */
+
+#define _reg_all(_name)			ODM_##_name
+#define _reg_ic(_name, _ic)		ODM_##_name##_ic
+#define _bit_all(_name)			BIT_##_name
+#define _bit_ic(_name, _ic)		BIT_##_name##_ic
+
+/*  _cat: implemented by Token-Pasting Operator. */
+
+/*===================================
+
+#define ODM_REG_DIG_11N		0xC50
+#define ODM_REG_DIG_11AC	0xDDD
+
+ODM_REG(DIG,_pDM_Odm)
+=====================================*/
+
+#define _reg_11N(_name)			ODM_REG_##_name##_11N
+#define _reg_11AC(_name)		ODM_REG_##_name##_11AC
+#define _bit_11N(_name)			ODM_BIT_##_name##_11N
+#define _bit_11AC(_name)		ODM_BIT_##_name##_11AC
+
+#define _cat(_name, _ic_type, _func)					\
+	(								\
+		((_ic_type) & ODM_IC_11N_SERIES) ? _func##_11N(_name) :	\
+		_func##_11AC(_name)					\
+	)
+
+/*  _name: name of register or bit. */
+/*  Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" */
+/*         gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C",
+ *	   depends on SupportICType. */
+#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg)
+#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit)
+
+enum odm_h2c_cmd {
+	ODM_H2C_RSSI_REPORT = 0,
+	ODM_H2C_PSD_RESULT= 1,
+	ODM_H2C_PathDiv = 2,
+	ODM_MAX_H2CCMD
+};
+
+/*  2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. */
+/*  Suggest HW team to use thread instead of workitem. Windows also support the feature. */
+typedef void (*RT_WORKITEM_CALL_BACK)(void *pContext);
+
+/*  =========== Extern Variable ??? It should be forbidden. */
+
+/*  =========== EXtern Function Prototype */
+
+u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
+
+u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
+
+u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr);
+
+void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data);
+
+void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data);
+
+void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data);
+
+void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr,
+		   u32 BitMask, u32 Data);
+
+u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask);
+
+void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr,
+		  u32 BitMask, u32 Data);
+
+u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask);
+
+void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH eRFPath,
+		  u32 RegAddr, u32 BitMask, u32 Data);
+
+u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum ODM_RF_RADIO_PATH eRFPath,
+		 u32 RegAddr, u32 BitMask);
+
+/*  Memory Relative Function. */
+void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length);
+void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length);
+
+s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2,
+		      u32 length);
+
+/*  ODM MISC-spin lock relative API. */
+void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm,
+			 enum RT_SPINLOCK_TYPE type);
+
+void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm,
+			 enum RT_SPINLOCK_TYPE type);
+
+/*  ODM MISC-workitem relative API. */
+void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem,
+			    RT_WORKITEM_CALL_BACK RtWorkItemCallback,
+			    void *pContext, const char *szID);
+
+void ODM_StartWorkItem(void *pRtWorkItem);
+
+void ODM_StopWorkItem(void *pRtWorkItem);
+
+void ODM_FreeWorkItem(void *pRtWorkItem);
+
+void ODM_ScheduleWorkItem(void *pRtWorkItem);
+
+void ODM_IsWorkItemScheduled(void *pRtWorkItem);
+
+/*  ODM Timer relative API. */
+void ODM_StallExecution(u32 usDelay);
+
+void ODM_delay_ms(u32 ms);
+
+void ODM_delay_us(u32 us);
+
+void ODM_sleep_ms(u32 ms);
+
+void ODM_sleep_us(u32 us);
+
+void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer,
+		  u32 msDelay);
+
+void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm,
+			 struct timer_list *pTimer, void *CallBackFunc,
+			 void *pContext, const char *szID);
+
+void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer);
+
+void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer);
+
+/*  ODM FW relative API. */
+u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum,
+		   u32 *pElementID, u32 *pCmdLen, u8 **pCmbBuffer,
+		   u8 *CmdStartSeq);
+
+#endif	/*  __ODM_INTERFACE_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_precomp.h b/drivers/staging/rtl8188eu/include/odm_precomp.h
new file mode 100644
index 0000000..520cbba
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_precomp.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef	__ODM_PRECOMP_H__
+#define __ODM_PRECOMP_H__
+
+#include "odm_types.h"
+
+#define		TEST_FALG___		1
+
+/* 2 Config Flags and Structs - defined by each ODM Type */
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <hal_intf.h>
+
+/* 2 Hardware Parameter Files */
+
+#include "Hal8188EFWImg_CE.h"
+
+
+/* 2 OutSrc Header Files */
+
+#include "odm.h"
+#include "odm_HWConfig.h"
+#include "odm_debug.h"
+#include "odm_RegDefine11AC.h"
+#include "odm_RegDefine11N.h"
+
+#include "HalPhyRf.h"
+#include "HalPhyRf_8188e.h"/* for IQK,LCK,Power-tracking */
+#include "Hal8188ERateAdaptive.h"/* for  RA,Power training */
+#include "rtl8188e_hal.h"
+
+#include "odm_interface.h"
+#include "odm_reg.h"
+
+#include "HalHWImg8188E_MAC.h"
+#include "HalHWImg8188E_RF.h"
+#include "HalHWImg8188E_BB.h"
+#include "Hal8188EReg.h"
+
+#include "odm_RegConfig8188E.h"
+#include "odm_RTL8188E.h"
+
+void odm_CmnInfoHook_Debug(struct odm_dm_struct *pDM_Odm);
+void odm_CmnInfoInit_Debug(struct odm_dm_struct *pDM_Odm);
+void odm_DIGInit(struct odm_dm_struct *pDM_Odm);
+void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm);
+void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivInit_NIC(struct odm_dm_struct *pDM_Odm);
+void odm_GlobalAdapterCheck(void);
+void odm_CmnInfoUpdate_Debug(struct odm_dm_struct *pDM_Odm);
+void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm);
+void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm);
+void odm_DIG(struct odm_dm_struct *pDM_Odm);
+void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step);
+void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm);
+void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm);
+void odm_1R_CCA(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm);
+void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm);
+void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm);
+void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm);
+void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm);
+void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm);
+void odm_SwAntDivChkAntSwitchCallback(void *FunctionContext);
+void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm);
+void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm);
+
+#endif	/*  __ODM_PRECOMP_H__ */
diff --git a/drivers/staging/rtl8188eu/include/odm_reg.h b/drivers/staging/rtl8188eu/include/odm_reg.h
new file mode 100644
index 0000000..89bc46b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_reg.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*  */
+/*  File Name: odm_reg.h */
+/*  */
+/*  Description: */
+/*  */
+/*  This file is for general register definition. */
+/*  */
+/*  */
+/*  */
+#ifndef	__HAL_ODM_REG_H__
+#define __HAL_ODM_REG_H__
+
+/*  */
+/*  Register Definition */
+/*  */
+
+/* MAC REG */
+#define	ODM_BB_RESET					0x002
+#define	ODM_DUMMY						0x4fe
+#define	ODM_EDCA_VO_PARAM			0x500
+#define	ODM_EDCA_VI_PARAM			0x504
+#define	ODM_EDCA_BE_PARAM			0x508
+#define	ODM_EDCA_BK_PARAM			0x50C
+#define	ODM_TXPAUSE					0x522
+
+/* BB REG */
+#define	ODM_FPGA_PHY0_PAGE8			0x800
+#define	ODM_PSD_SETTING				0x808
+#define	ODM_AFE_SETTING				0x818
+#define	ODM_TXAGC_B_6_18				0x830
+#define	ODM_TXAGC_B_24_54			0x834
+#define	ODM_TXAGC_B_MCS32_5			0x838
+#define	ODM_TXAGC_B_MCS0_MCS3		0x83c
+#define	ODM_TXAGC_B_MCS4_MCS7		0x848
+#define	ODM_TXAGC_B_MCS8_MCS11		0x84c
+#define	ODM_ANALOG_REGISTER			0x85c
+#define	ODM_RF_INTERFACE_OUTPUT		0x860
+#define	ODM_TXAGC_B_MCS12_MCS15	0x868
+#define	ODM_TXAGC_B_11_A_2_11		0x86c
+#define	ODM_AD_DA_LSB_MASK			0x874
+#define	ODM_ENABLE_3_WIRE			0x88c
+#define	ODM_PSD_REPORT				0x8b4
+#define	ODM_R_ANT_SELECT				0x90c
+#define	ODM_CCK_ANT_SELECT			0xa07
+#define	ODM_CCK_PD_THRESH			0xa0a
+#define	ODM_CCK_RF_REG1				0xa11
+#define	ODM_CCK_MATCH_FILTER			0xa20
+#define	ODM_CCK_RAKE_MAC				0xa2e
+#define	ODM_CCK_CNT_RESET			0xa2d
+#define	ODM_CCK_TX_DIVERSITY			0xa2f
+#define	ODM_CCK_FA_CNT_MSB			0xa5b
+#define	ODM_CCK_FA_CNT_LSB			0xa5c
+#define	ODM_CCK_NEW_FUNCTION		0xa75
+#define	ODM_OFDM_PHY0_PAGE_C		0xc00
+#define	ODM_OFDM_RX_ANT				0xc04
+#define	ODM_R_A_RXIQI					0xc14
+#define	ODM_R_A_AGC_CORE1			0xc50
+#define	ODM_R_A_AGC_CORE2			0xc54
+#define	ODM_R_B_AGC_CORE1			0xc58
+#define	ODM_R_AGC_PAR					0xc70
+#define	ODM_R_HTSTF_AGC_PAR			0xc7c
+#define	ODM_TX_PWR_TRAINING_A		0xc90
+#define	ODM_TX_PWR_TRAINING_B		0xc98
+#define	ODM_OFDM_FA_CNT1				0xcf0
+#define	ODM_OFDM_PHY0_PAGE_D		0xd00
+#define	ODM_OFDM_FA_CNT2				0xda0
+#define	ODM_OFDM_FA_CNT3				0xda4
+#define	ODM_OFDM_FA_CNT4				0xda8
+#define	ODM_TXAGC_A_6_18				0xe00
+#define	ODM_TXAGC_A_24_54			0xe04
+#define	ODM_TXAGC_A_1_MCS32			0xe08
+#define	ODM_TXAGC_A_MCS0_MCS3		0xe10
+#define	ODM_TXAGC_A_MCS4_MCS7		0xe14
+#define	ODM_TXAGC_A_MCS8_MCS11		0xe18
+#define	ODM_TXAGC_A_MCS12_MCS15		0xe1c
+
+/* RF REG */
+#define	ODM_GAIN_SETTING				0x00
+#define	ODM_CHANNEL					0x18
+
+/* Ant Detect Reg */
+#define	ODM_DPDT						0x300
+
+/* PSD Init */
+#define	ODM_PSDREG					0x808
+
+/* 92D Path Div */
+#define	PATHDIV_REG					0xB30
+#define	PATHDIV_TRI					0xBA0
+
+
+/*  */
+/*  Bitmap Definition */
+/*  */
+
+#define	BIT_FA_RESET					BIT0
+
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/odm_types.h b/drivers/staging/rtl8188eu/include/odm_types.h
new file mode 100644
index 0000000..78ee2ba
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/odm_types.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __ODM_TYPES_H__
+#define __ODM_TYPES_H__
+
+/*  */
+/*  Define Different SW team support */
+/*  */
+#define	ODM_AP			0x01	 /* BIT0 */
+#define	ODM_ADSL		0x02	/* BIT1 */
+#define	ODM_CE			0x04	/* BIT2 */
+#define	ODM_MP			0x08	/* BIT3 */
+
+#define		RT_PCI_INTERFACE				1
+#define		RT_USB_INTERFACE				2
+#define		RT_SDIO_INTERFACE				3
+
+enum HAL_STATUS {
+	HAL_STATUS_SUCCESS,
+	HAL_STATUS_FAILURE,
+};
+
+enum RT_SPINLOCK_TYPE {
+	RT_TEMP = 1,
+};
+
+#include <basic_types.h>
+
+#define DEV_BUS_TYPE	RT_USB_INTERFACE
+
+#define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value)
+#define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value)
+#define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value)
+
+/* define useless flag to avoid compile warning */
+#define	USE_WORKITEM			0
+#define		FOR_BRAZIL_PRETEST	0
+#define	BT_30_SUPPORT			0
+#define   FPGA_TWO_MAC_VERIFICATION	0
+
+
+#endif /*  __ODM_TYPES_H__ */
diff --git a/drivers/staging/rtl8188eu/include/osdep_intf.h b/drivers/staging/rtl8188eu/include/osdep_intf.h
new file mode 100644
index 0000000..c4599c5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/osdep_intf.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __OSDEP_INTF_H_
+#define __OSDEP_INTF_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct intf_priv {
+	u8 *intf_dev;
+	u32	max_iosz;	/* USB2.0: 128, USB1.1: 64, SDIO:64 */
+	u32	max_xmitsz; /* USB2.0: unlimited, SDIO:512 */
+	u32	max_recvsz; /* USB2.0: unlimited, SDIO:512 */
+
+	u8 *io_rwmem;
+	u8 *allocated_io_rwmem;
+	u32	io_wsz; /* unit: 4bytes */
+	u32	io_rsz;/* unit: 4bytes */
+	u8 intf_status;
+
+	void (*_bus_io)(u8 *priv);
+
+/*
+Under Sync. IRP (SDIO/USB)
+A protection mechanism is necessary for the io_rwmem(read/write protocol)
+
+Under Async. IRP (SDIO/USB)
+The protection mechanism is through the pending queue.
+*/
+	struct mutex ioctl_mutex;
+	/*  when in USB, IO is through interrupt in/out endpoints */
+	struct usb_device	*udev;
+	struct urb *piorw_urb;
+	u8 io_irp_cnt;
+	u8 bio_irp_pending;
+	struct semaphore  io_retevt;
+	struct timer_list io_timer;
+	u8 bio_irp_timeout;
+	u8 bio_timer_cancel;
+};
+
+u8 rtw_init_drv_sw(struct adapter *padapter);
+u8 rtw_free_drv_sw(struct adapter *padapter);
+u8 rtw_reset_drv_sw(struct adapter *padapter);
+
+u32 rtw_start_drv_threads(struct adapter *padapter);
+void rtw_stop_drv_threads (struct adapter *padapter);
+void rtw_cancel_all_timer(struct adapter *padapter);
+
+int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+
+int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname);
+struct net_device *rtw_init_netdev(struct adapter *padapter);
+u16 rtw_recv_select_queue(struct sk_buff *skb);
+void rtw_proc_init_one(struct net_device *dev);
+void rtw_proc_remove_one(struct net_device *dev);
+
+void rtw_ips_dev_unload(struct adapter *padapter);
+
+int rtw_ips_pwr_up(struct adapter *padapter);
+void rtw_ips_pwr_down(struct adapter *padapter);
+int rtw_hw_suspend(struct adapter *padapter);
+int rtw_hw_resume(struct adapter *padapter);
+
+#endif	/* _OSDEP_INTF_H_ */
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
new file mode 100644
index 0000000..44f24fa
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __OSDEP_SERVICE_H_
+#define __OSDEP_SERVICE_H_
+
+#include <basic_types.h>
+
+#define _FAIL		0
+#define _SUCCESS	1
+#define RTW_RX_HANDLED 2
+
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/circ_buf.h>
+#include <linux/uaccess.h>
+#include <asm/byteorder.h>
+#include <linux/atomic.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <linux/sem.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>	/*  Necessary because we use the proc fs */
+#include <linux/interrupt.h>	/*  for struct tasklet_struct */
+#include <linux/ip.h>
+#include <linux/kthread.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+
+struct	__queue	{
+	struct	list_head	queue;
+	spinlock_t lock;
+};
+
+#define thread_exit() complete_and_exit(NULL, 0)
+
+static inline struct list_head *get_next(struct list_head *list)
+{
+	return list->next;
+}
+
+static inline struct list_head *get_list_head(struct __queue *queue)
+{
+	return (&(queue->queue));
+}
+
+
+#define LIST_CONTAINOR(ptr, type, member) \
+        ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member)))
+
+
+static inline void _enter_critical(spinlock_t *plock, unsigned long *pirqL)
+{
+	spin_lock_irqsave(plock, *pirqL);
+}
+
+static inline void _exit_critical(spinlock_t *plock, unsigned long *pirqL)
+{
+	spin_unlock_irqrestore(plock, *pirqL);
+}
+
+static inline void _enter_critical_ex(spinlock_t *plock, unsigned long *pirqL)
+{
+	spin_lock_irqsave(plock, *pirqL);
+}
+
+static inline void _exit_critical_ex(spinlock_t *plock, unsigned long *pirqL)
+{
+	spin_unlock_irqrestore(plock, *pirqL);
+}
+
+static inline void _enter_critical_bh(spinlock_t *plock, unsigned long *pirqL)
+{
+	spin_lock_bh(plock);
+}
+
+static inline void _exit_critical_bh(spinlock_t *plock, unsigned long *pirqL)
+{
+	spin_unlock_bh(plock);
+}
+
+static inline int _enter_critical_mutex(struct mutex *pmutex, unsigned long *pirqL)
+{
+	int ret;
+
+	ret = mutex_lock_interruptible(pmutex);
+	return ret;
+}
+
+
+static inline void _exit_critical_mutex(struct mutex *pmutex, unsigned long *pirqL)
+{
+		mutex_unlock(pmutex);
+}
+
+static inline void rtw_list_delete(struct list_head *plist)
+{
+	list_del_init(plist);
+}
+
+static inline void _init_timer(struct timer_list *ptimer,struct  net_device *nic_hdl,void *pfunc,void* cntx)
+{
+	ptimer->function = pfunc;
+	ptimer->data = (unsigned long)cntx;
+	init_timer(ptimer);
+}
+
+static inline void _set_timer(struct timer_list *ptimer,u32 delay_time)
+{
+	mod_timer(ptimer , (jiffies+(delay_time*HZ/1000)));
+}
+
+static inline void _cancel_timer(struct timer_list *ptimer,u8 *bcancelled)
+{
+	del_timer_sync(ptimer);
+	*bcancelled=  true;/* true ==1; false==0 */
+}
+
+#define RTW_TIMER_HDL_ARGS void *FunctionContext
+#define RTW_TIMER_HDL_NAME(name) rtw_##name##_timer_hdl
+#define RTW_DECLARE_TIMER_HDL(name) void RTW_TIMER_HDL_NAME(name)(RTW_TIMER_HDL_ARGS)
+
+static inline void _init_workitem(struct work_struct *pwork, void *pfunc, void * cntx)
+{
+	INIT_WORK(pwork, pfunc);
+}
+
+static inline void _set_workitem(struct work_struct *pwork)
+{
+	schedule_work(pwork);
+}
+
+static inline void _cancel_workitem_sync(struct work_struct *pwork)
+{
+	cancel_work_sync(pwork);
+}
+/*  */
+/*  Global Mutex: can only be used at PASSIVE level. */
+/*  */
+
+#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter)                              \
+{                                                               \
+	while (atomic_inc_return((atomic_t *)&(_MutexCounter)) != 1)\
+	{                                                           \
+		atomic_dec((atomic_t *)&(_MutexCounter));        \
+		msleep(10);                          \
+	}                                                           \
+}
+
+#define RELEASE_GLOBAL_MUTEX(_MutexCounter)                              \
+{                                                               \
+	atomic_dec((atomic_t *)&(_MutexCounter));        \
+}
+
+static inline int rtw_netif_queue_stopped(struct net_device *pnetdev)
+{
+	return  netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) &&
+		netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) &&
+		netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) &&
+		netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3));
+}
+
+static inline void rtw_netif_wake_queue(struct net_device *pnetdev)
+{
+	netif_tx_wake_all_queues(pnetdev);
+}
+
+static inline void rtw_netif_start_queue(struct net_device *pnetdev)
+{
+	netif_tx_start_all_queues(pnetdev);
+}
+
+static inline void rtw_netif_stop_queue(struct net_device *pnetdev)
+{
+	netif_tx_stop_all_queues(pnetdev);
+}
+
+#ifndef BIT
+	#define BIT(x)	( 1 << (x))
+#endif
+
+#define BIT0	0x00000001
+#define BIT1	0x00000002
+#define BIT2	0x00000004
+#define BIT3	0x00000008
+#define BIT4	0x00000010
+#define BIT5	0x00000020
+#define BIT6	0x00000040
+#define BIT7	0x00000080
+#define BIT8	0x00000100
+#define BIT9	0x00000200
+#define BIT10	0x00000400
+#define BIT11	0x00000800
+#define BIT12	0x00001000
+#define BIT13	0x00002000
+#define BIT14	0x00004000
+#define BIT15	0x00008000
+#define BIT16	0x00010000
+#define BIT17	0x00020000
+#define BIT18	0x00040000
+#define BIT19	0x00080000
+#define BIT20	0x00100000
+#define BIT21	0x00200000
+#define BIT22	0x00400000
+#define BIT23	0x00800000
+#define BIT24	0x01000000
+#define BIT25	0x02000000
+#define BIT26	0x04000000
+#define BIT27	0x08000000
+#define BIT28	0x10000000
+#define BIT29	0x20000000
+#define BIT30	0x40000000
+#define BIT31	0x80000000
+#define BIT32	0x0100000000
+#define BIT33	0x0200000000
+#define BIT34	0x0400000000
+#define BIT35	0x0800000000
+#define BIT36	0x1000000000
+
+extern int RTW_STATUS_CODE(int error_code);
+
+/* flags used for rtw_update_mem_stat() */
+enum {
+	MEM_STAT_VIR_ALLOC_SUCCESS,
+	MEM_STAT_VIR_ALLOC_FAIL,
+	MEM_STAT_VIR_FREE,
+	MEM_STAT_PHY_ALLOC_SUCCESS,
+	MEM_STAT_PHY_ALLOC_FAIL,
+	MEM_STAT_PHY_FREE,
+	MEM_STAT_TX, /* used to distinguish TX/RX, asigned from caller */
+	MEM_STAT_TX_ALLOC_SUCCESS,
+	MEM_STAT_TX_ALLOC_FAIL,
+	MEM_STAT_TX_FREE,
+	MEM_STAT_RX, /* used to distinguish TX/RX, asigned from caller */
+	MEM_STAT_RX_ALLOC_SUCCESS,
+	MEM_STAT_RX_ALLOC_FAIL,
+	MEM_STAT_RX_FREE
+};
+
+extern unsigned char MCS_rate_2R[16];
+extern unsigned char MCS_rate_1R[16];
+extern unsigned char RTW_WPA_OUI[];
+extern unsigned char WPA_TKIP_CIPHER[4];
+extern unsigned char RSN_TKIP_CIPHER[4];
+
+#define rtw_update_mem_stat(flag, sz) do {} while (0)
+u8 *_rtw_vmalloc(u32 sz);
+u8 *_rtw_zvmalloc(u32 sz);
+void _rtw_vmfree(u8 *pbuf, u32 sz);
+u8 *_rtw_zmalloc(u32 sz);
+u8 *_rtw_malloc(u32 sz);
+void _rtw_mfree(u8 *pbuf, u32 sz);
+#define rtw_vmalloc(sz)			_rtw_vmalloc((sz))
+#define rtw_zvmalloc(sz)			_rtw_zvmalloc((sz))
+#define rtw_vmfree(pbuf, sz)		_rtw_vmfree((pbuf), (sz))
+#define rtw_malloc(sz)			_rtw_malloc((sz))
+#define rtw_zmalloc(sz)			_rtw_zmalloc((sz))
+#define rtw_mfree(pbuf, sz)		_rtw_mfree((pbuf), (sz))
+
+void *rtw_malloc2d(int h, int w, int size);
+void rtw_mfree2d(void *pbuf, int h, int w, int size);
+
+void _rtw_memcpy(void *dec, void *sour, u32 sz);
+int  _rtw_memcmp(void *dst, void *src, u32 sz);
+void _rtw_memset(void *pbuf, int c, u32 sz);
+
+void _rtw_init_listhead(struct list_head *list);
+u32  rtw_is_list_empty(struct list_head *phead);
+void rtw_list_insert_head(struct list_head *plist, struct list_head *phead);
+void rtw_list_insert_tail(struct list_head *plist, struct list_head *phead);
+void rtw_list_delete(struct list_head *plist);
+
+void _rtw_init_sema(struct semaphore *sema, int init_val);
+void _rtw_free_sema(struct semaphore *sema);
+void _rtw_up_sema(struct semaphore *sema);
+u32  _rtw_down_sema(struct semaphore *sema);
+void _rtw_mutex_init(struct mutex *pmutex);
+void _rtw_mutex_free(struct mutex *pmutex);
+void _rtw_spinlock_init(spinlock_t *plock);
+void _rtw_spinlock_free(spinlock_t *plock);
+
+void _rtw_init_queue(struct __queue *pqueue);
+u32  _rtw_queue_empty(struct __queue *pqueue);
+u32  rtw_end_of_queue_search(struct list_head *queue, struct list_head *pelement);
+
+u32  rtw_get_current_time(void);
+u32  rtw_systime_to_ms(u32 systime);
+u32  rtw_ms_to_systime(u32 ms);
+s32  rtw_get_passing_time_ms(u32 start);
+s32  rtw_get_time_interval_ms(u32 start, u32 end);
+
+void rtw_sleep_schedulable(int ms);
+
+void rtw_msleep_os(int ms);
+void rtw_usleep_os(int us);
+
+u32  rtw_atoi(u8 *s);
+
+void rtw_mdelay_os(int ms);
+void rtw_udelay_os(int us);
+
+void rtw_yield_os(void);
+
+static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer)
+{
+	return del_timer_sync(ptimer);
+}
+
+static __inline void thread_enter(char *name)
+{
+#ifdef daemonize
+	daemonize("%s", name);
+#endif
+	allow_signal(SIGTERM);
+}
+
+static inline void flush_signals_thread(void)
+{
+	if (signal_pending (current))
+		flush_signals(current);
+}
+
+static inline int res_to_status(int res)
+{
+	return res;
+}
+
+#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r))
+#define RND4(x)	(((x >> 2) + (((x & 3) == 0) ?  0: 1)) << 2)
+
+static inline u32 _RND4(u32 sz)
+{
+	u32	val;
+
+	val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2;
+	return val;
+}
+
+static inline u32 _RND8(u32 sz)
+{
+	u32	val;
+
+	val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3;
+	return val;
+}
+
+static inline u32 _RND128(u32 sz)
+{
+	u32	val;
+
+	val = ((sz >> 7) + ((sz & 127) ? 1: 0)) << 7;
+	return val;
+}
+
+static inline u32 _RND256(u32 sz)
+{
+	u32	val;
+
+	val = ((sz >> 8) + ((sz & 255) ? 1: 0)) << 8;
+	return val;
+}
+
+static inline u32 _RND512(u32 sz)
+{
+	u32	val;
+
+	val = ((sz >> 9) + ((sz & 511) ? 1: 0)) << 9;
+	return val;
+}
+
+static inline u32 bitshift(u32 bitmask)
+{
+	u32 i;
+
+	for (i = 0; i <= 31; i++)
+		if (((bitmask>>i) &  0x1) == 1) break;
+	return i;
+}
+
+/*  limitation of path length */
+#define PATH_LENGTH_MAX PATH_MAX
+
+void rtw_suspend_lock_init(void);
+void rtw_suspend_lock_uninit(void);
+void rtw_lock_suspend(void);
+void rtw_unlock_suspend(void);
+
+/* Atomic integer operations */
+#define ATOMIC_T atomic_t
+
+void ATOMIC_SET(ATOMIC_T *v, int i);
+int ATOMIC_READ(ATOMIC_T *v);
+void ATOMIC_ADD(ATOMIC_T *v, int i);
+void ATOMIC_SUB(ATOMIC_T *v, int i);
+void ATOMIC_INC(ATOMIC_T *v);
+void ATOMIC_DEC(ATOMIC_T *v);
+int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i);
+int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i);
+int ATOMIC_INC_RETURN(ATOMIC_T *v);
+int ATOMIC_DEC_RETURN(ATOMIC_T *v);
+
+/* File operation APIs, just for linux now */
+int rtw_is_file_readable(char *path);
+int rtw_retrive_from_file(char *path, u8 __user *buf, u32 sz);
+int rtw_store_to_file(char *path, u8 __user *buf, u32 sz);
+
+struct rtw_netdev_priv_indicator {
+	void *priv;
+	u32 sizeof_priv;
+};
+struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv,
+						    void *old_priv);
+struct net_device *rtw_alloc_etherdev(int sizeof_priv);
+
+#define rtw_netdev_priv(netdev)					\
+	(((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv)
+void rtw_free_netdev(struct net_device *netdev);
+
+#define NDEV_FMT "%s"
+#define NDEV_ARG(ndev) ndev->name
+#define ADPT_FMT "%s"
+#define ADPT_ARG(adapter) adapter->pnetdev->name
+#define FUNC_NDEV_FMT "%s(%s)"
+#define FUNC_NDEV_ARG(ndev) __func__, ndev->name
+#define FUNC_ADPT_FMT "%s(%s)"
+#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name
+
+#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1)
+
+u64 rtw_modular64(u64 x, u64 y);
+u64 rtw_division64(u64 x, u64 y);
+
+/* Macros for handling unaligned memory accesses */
+
+#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
+#define RTW_PUT_BE16(a, val)			\
+	do {					\
+		(a)[0] = ((u16) (val)) >> 8;	\
+		(a)[1] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define RTW_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
+#define RTW_PUT_LE16(a, val)			\
+	do {					\
+		(a)[1] = ((u16) (val)) >> 8;	\
+		(a)[0] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+			 ((u32) (a)[2]))
+#define RTW_PUT_BE24(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[2] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define RTW_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+			 (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define RTW_PUT_BE32(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[3] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define RTW_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
+			 (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
+#define RTW_PUT_LE32(a, val)					\
+	do {							\
+		(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[0] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define RTW_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
+			 (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
+			 (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
+			 (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
+#define RTW_PUT_BE64(a, val)				\
+	do {						\
+		(a)[0] = (u8) (((u64) (val)) >> 56);	\
+		(a)[1] = (u8) (((u64) (val)) >> 48);	\
+		(a)[2] = (u8) (((u64) (val)) >> 40);	\
+		(a)[3] = (u8) (((u64) (val)) >> 32);	\
+		(a)[4] = (u8) (((u64) (val)) >> 24);	\
+		(a)[5] = (u8) (((u64) (val)) >> 16);	\
+		(a)[6] = (u8) (((u64) (val)) >> 8);	\
+		(a)[7] = (u8) (((u64) (val)) & 0xff);	\
+	} while (0)
+
+#define RTW_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
+			 (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
+			 (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
+			 (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+
+void rtw_buf_free(u8 **buf, u32 *buf_len);
+void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len);
+
+struct rtw_cbuf {
+	u32 write;
+	u32 read;
+	u32 size;
+	void *bufs[0];
+};
+
+bool rtw_cbuf_full(struct rtw_cbuf *cbuf);
+bool rtw_cbuf_empty(struct rtw_cbuf *cbuf);
+bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf);
+void *rtw_cbuf_pop(struct rtw_cbuf *cbuf);
+struct rtw_cbuf *rtw_cbuf_alloc(u32 size);
+int wifirate2_ratetbl_inx(unsigned char rate);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/recv_osdep.h b/drivers/staging/rtl8188eu/include/recv_osdep.h
new file mode 100644
index 0000000..6912380
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/recv_osdep.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RECV_OSDEP_H_
+#define __RECV_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
+void _rtw_free_recv_priv(struct recv_priv *precvpriv);
+
+
+s32  rtw_recv_entry(union recv_frame *precv_frame);
+int rtw_recv_indicatepkt(struct adapter *adapter, union recv_frame *recv_frame);
+void rtw_recv_returnpacket(struct  net_device *cnxt, struct sk_buff *retpkt);
+
+void rtw_hostapd_mlme_rx(struct adapter *padapter, union recv_frame *recv_fr);
+void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup);
+
+int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
+void rtw_free_recv_priv(struct recv_priv *precvpriv);
+
+int rtw_os_recv_resource_init(struct recv_priv *recvpr, struct adapter *adapt);
+int rtw_os_recv_resource_alloc(struct adapter *adapt, union recv_frame *recvfr);
+void rtw_os_recv_resource_free(struct recv_priv *precvpriv);
+
+int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf);
+int rtw_os_recvbuf_resource_free(struct adapter *adapt, struct recv_buf *buf);
+
+void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf);
+
+void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl);
+int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb);
+int _netdev_open(struct net_device *pnetdev);
+int netdev_open(struct net_device *pnetdev);
+int netdev_close(struct net_device *pnetdev);
+
+#endif /*  */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
new file mode 100644
index 0000000..b32bc28
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_CMD_H__
+#define __RTL8188E_CMD_H__
+
+enum RTL8188E_H2C_CMD_ID {
+	/* Class Common */
+	H2C_COM_RSVD_PAGE		= 0x00,
+	H2C_COM_MEDIA_STATUS_RPT	= 0x01,
+	H2C_COM_SCAN			= 0x02,
+	H2C_COM_KEEP_ALIVE		= 0x03,
+	H2C_COM_DISCNT_DECISION		= 0x04,
+	H2C_COM_INIT_OFFLOAD		= 0x06,
+	H2C_COM_REMOTE_WAKE_CTL		= 0x07,
+	H2C_COM_AP_OFFLOAD		= 0x08,
+	H2C_COM_BCN_RSVD_PAGE		= 0x09,
+	H2C_COM_PROB_RSP_RSVD_PAGE	= 0x0A,
+
+	/* Class PS */
+	H2C_PS_PWR_MODE			= 0x20,
+	H2C_PS_TUNE_PARA		= 0x21,
+	H2C_PS_TUNE_PARA_2		= 0x22,
+	H2C_PS_LPS_PARA			= 0x23,
+	H2C_PS_P2P_OFFLOAD		= 0x24,
+
+	/* Class DM */
+	H2C_DM_MACID_CFG		= 0x40,
+	H2C_DM_TXBF			= 0x41,
+
+	/* Class BT */
+	H2C_BT_COEX_MASK		= 0x60,
+	H2C_BT_COEX_GPIO_MODE		= 0x61,
+	H2C_BT_DAC_SWING_VAL		= 0x62,
+	H2C_BT_PSD_RST			= 0x63,
+
+	/* Class */
+	 H2C_RESET_TSF			= 0xc0,
+};
+
+struct cmd_msg_parm {
+	u8 eid; /* element id */
+	u8 sz; /*  sz */
+	u8 buf[6];
+};
+
+enum {
+	PWRS
+};
+
+struct setpwrmode_parm {
+	u8 Mode;/* 0:Active,1:LPS,2:WMMPS */
+	u8 SmartPS_RLBM;/* LPS= 0:PS_Poll,1:PS_Poll,2:NullData,WMM= 0:PS_Poll,1:NullData */
+	u8 AwakeInterval;	/*  unit: beacon interval */
+	u8 bAllQueueUAPSD;
+	u8 PwrState;/* AllON(0x0c),RFON(0x04),RFOFF(0x00) */
+};
+
+struct H2C_SS_RFOFF_PARAM {
+	u8 ROFOn; /*  1: on, 0:off */
+	u16 gpio_period; /*  unit: 1024 us */
+} __packed;
+
+struct joinbssrpt_parm {
+	u8 OpMode;	/*  RT_MEDIA_STATUS */
+};
+
+struct rsvdpage_loc {
+	u8 LocProbeRsp;
+	u8 LocPsPoll;
+	u8 LocNullData;
+	u8 LocQosNull;
+	u8 LocBTQosNull;
+};
+
+struct P2P_PS_Offload_t {
+	u8 Offload_En:1;
+	u8 role:1; /*  1: Owner, 0: Client */
+	u8 CTWindow_En:1;
+	u8 NoA0_En:1;
+	u8 NoA1_En:1;
+	u8 AllStaSleep:1; /*  Only valid in Owner */
+	u8 discovery:1;
+	u8 rsvd:1;
+};
+
+struct P2P_PS_CTWPeriod_t {
+	u8 CTWPeriod;	/* TU */
+};
+
+/*  host message to firmware cmd */
+void rtl8188e_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode);
+void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *padapter, u8 mstatus);
+u8 rtl8188e_set_rssi_cmd(struct adapter *padapter, u8 *param);
+u8 rtl8188e_set_raid_cmd(struct adapter *padapter, u32 mask);
+void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg,
+			   u8 rssi_level);
+
+#ifdef CONFIG_88EU_P2P
+void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state);
+#endif /* CONFIG_88EU_P2P */
+
+void CheckFwRsvdPageContent(struct adapter *adapt);
+void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt);
+
+#endif/* __RTL8188E_CMD_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_dm.h b/drivers/staging/rtl8188eu/include/rtl8188e_dm.h
new file mode 100644
index 0000000..97a3175
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_dm.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_DM_H__
+#define __RTL8188E_DM_H__
+enum{
+	UP_LINK,
+	DOWN_LINK,
+};
+/*  duplicate code,will move to ODM ######### */
+#define IQK_MAC_REG_NUM		4
+#define IQK_ADDA_REG_NUM		16
+#define IQK_BB_REG_NUM			9
+#define HP_THERMAL_NUM		8
+/*  duplicate code,will move to ODM ######### */
+struct	dm_priv {
+	u8	DM_Type;
+	u8	DMFlag;
+	u8	InitDMFlag;
+	u32	InitODMFlag;
+
+	/*  Upper and Lower Signal threshold for Rate Adaptive*/
+	int	UndecoratedSmoothedPWDB;
+	int	UndecoratedSmoothedCCK;
+	int	EntryMinUndecoratedSmoothedPWDB;
+	int	EntryMaxUndecoratedSmoothedPWDB;
+	int	MinUndecoratedPWDBForDM;
+	int	LastMinUndecoratedPWDBForDM;
+
+	/* for High Power */
+	u8 bDynamicTxPowerEnable;
+	u8 LastDTPLvl;
+	u8 DynamicTxHighPowerLvl;/* Tx Power Control for Near/Far Range */
+	u8	PowerIndex_backup[6];
+};
+
+void rtl8188e_init_dm_priv(struct adapter *adapt);
+void rtl8188e_deinit_dm_priv(struct adapter *adapt);
+void rtl8188e_InitHalDm(struct adapter *adapt);
+void rtl8188e_HalDmWatchDog(struct adapter *adapt);
+
+void AntDivCompare8188E(struct adapter *adapt, struct wlan_bssid_ex *dst,
+			struct wlan_bssid_ex *src);
+u8 AntDivBeforeLink8188E(struct adapter *adapt);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
new file mode 100644
index 0000000..52b2801
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
@@ -0,0 +1,487 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_HAL_H__
+#define __RTL8188E_HAL_H__
+
+
+/* include HAL Related header after HAL Related compiling flags */
+#include "rtl8188e_spec.h"
+#include "Hal8188EPhyReg.h"
+#include "Hal8188EPhyCfg.h"
+#include "rtl8188e_rf.h"
+#include "rtl8188e_dm.h"
+#include "rtl8188e_recv.h"
+#include "rtl8188e_xmit.h"
+#include "rtl8188e_cmd.h"
+#include "Hal8188EPwrSeq.h"
+#include "rtl8188e_sreset.h"
+#include "rtw_efuse.h"
+
+#include "odm_precomp.h"
+
+/*  Fw Array */
+#define Rtl8188E_FwImageArray		Rtl8188EFwImgArray
+#define Rtl8188E_FWImgArrayLength	Rtl8188EFWImgArrayLength
+
+#define RTL8188E_FW_UMC_IMG			"rtl8188E\\rtl8188efw.bin"
+#define RTL8188E_PHY_REG			"rtl8188E\\PHY_REG_1T.txt"
+#define RTL8188E_PHY_RADIO_A			"rtl8188E\\radio_a_1T.txt"
+#define RTL8188E_PHY_RADIO_B			"rtl8188E\\radio_b_1T.txt"
+#define RTL8188E_AGC_TAB			"rtl8188E\\AGC_TAB_1T.txt"
+#define RTL8188E_PHY_MACREG			"rtl8188E\\MAC_REG.txt"
+#define RTL8188E_PHY_REG_PG			"rtl8188E\\PHY_REG_PG.txt"
+#define RTL8188E_PHY_REG_MP			"rtl8188E\\PHY_REG_MP.txt"
+
+/* 		RTL8188E Power Configuration CMDs for USB/SDIO interfaces */
+#define Rtl8188E_NIC_PWR_ON_FLOW		rtl8188E_power_on_flow
+#define Rtl8188E_NIC_RF_OFF_FLOW		rtl8188E_radio_off_flow
+#define Rtl8188E_NIC_DISABLE_FLOW		rtl8188E_card_disable_flow
+#define Rtl8188E_NIC_ENABLE_FLOW		rtl8188E_card_enable_flow
+#define Rtl8188E_NIC_SUSPEND_FLOW		rtl8188E_suspend_flow
+#define Rtl8188E_NIC_RESUME_FLOW		rtl8188E_resume_flow
+#define Rtl8188E_NIC_PDN_FLOW			rtl8188E_hwpdn_flow
+#define Rtl8188E_NIC_LPS_ENTER_FLOW		rtl8188E_enter_lps_flow
+#define Rtl8188E_NIC_LPS_LEAVE_FLOW		rtl8188E_leave_lps_flow
+
+#define DRVINFO_SZ	4 /*  unit is 8bytes */
+#define PageNum_128(_Len)	(u32)(((_Len)>>7) + ((_Len) & 0x7F ? 1 : 0))
+
+/*  download firmware related data structure */
+#define FW_8188E_SIZE			0x4000 /* 16384,16k */
+#define FW_8188E_START_ADDRESS		0x1000
+#define FW_8188E_END_ADDRESS		0x1FFF /* 0x5FFF */
+
+#define MAX_PAGE_SIZE			4096	/*  @ page : 4k bytes */
+
+#define IS_FW_HEADER_EXIST(_pFwHdr)				\
+	((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||	\
+	(le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||	\
+	(le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300 ||	\
+	(le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88E0)
+
+enum firmware_source {
+	FW_SOURCE_IMG_FILE = 0,
+	FW_SOURCE_HEADER_FILE = 1,		/* from header file */
+};
+
+struct rt_firmware {
+	enum firmware_source	eFWSource;
+	u8			*szFwBuffer;
+	u32			ulFwLength;
+};
+
+/*  This structure must be careful with byte-ordering */
+
+struct rt_firmware_hdr {
+	/*  8-byte alinment required */
+	/*  LONG WORD 0 ---- */
+	__le16		Signature;	/* 92C0: test chip; 92C,
+					 * 88C0: test chip; 88C1: MP A-cut;
+					 * 92C1: MP A-cut */
+	u8		Category;	/*  AP/NIC and USB/PCI */
+	u8		Function;	/*  Reserved for different FW function
+					 *  indcation, for further use when
+					 *  driver needs to download different
+					 *  FW for different conditions */
+	__le16		Version;	/*  FW Version */
+	u8		Subversion;	/*  FW Subversion, default 0x00 */
+	u16		Rsvd1;
+
+	/*  LONG WORD 1 ---- */
+	u8		Month;	/*  Release time Month field */
+	u8		Date;	/*  Release time Date field */
+	u8		Hour;	/*  Release time Hour field */
+	u8		Minute;	/*  Release time Minute field */
+	__le16		RamCodeSize;	/*  The size of RAM code */
+	u8		Foundry;
+	u8		Rsvd2;
+
+	/*  LONG WORD 2 ---- */
+	__le32		SvnIdx;	/*  The SVN entry index */
+	u32		Rsvd3;
+
+	/*  LONG WORD 3 ---- */
+	u32		Rsvd4;
+	u32		Rsvd5;
+};
+
+#define DRIVER_EARLY_INT_TIME		0x05
+#define BCN_DMA_ATIME_INT_TIME		0x02
+
+enum usb_rx_agg_mode {
+	USB_RX_AGG_DISABLE,
+	USB_RX_AGG_DMA,
+	USB_RX_AGG_USB,
+	USB_RX_AGG_MIX
+};
+
+#define MAX_RX_DMA_BUFFER_SIZE_88E				\
+      0x2400 /* 9k for 88E nornal chip , MaxRxBuff=10k-max(TxReportSize(64*8),
+	      * WOLPattern(16*24)) */
+
+#define MAX_TX_REPORT_BUFFER_SIZE		0x0400 /*  1k */
+
+
+/*  BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */
+#define MAX_TX_QUEUE			9
+
+#define TX_SELE_HQ			BIT(0)		/*  High Queue */
+#define TX_SELE_LQ			BIT(1)		/*  Low Queue */
+#define TX_SELE_NQ			BIT(2)		/*  Normal Queue */
+
+/*  Note: We will divide number of page equally for each queue other
+ *  than public queue! */
+/*  22k = 22528 bytes = 176 pages (@page =  128 bytes) */
+/*  must reserved about 7 pages for LPS =>  176-7 = 169 (0xA9) */
+/*  2*BCN / 1*ps-poll / 1*null-data /1*prob_rsp /1*QOS null-data /1*BT QOS
+ *  null-data */
+
+#define TX_TOTAL_PAGE_NUMBER_88E		0xA9/*   169 (21632=> 21k) */
+
+#define TX_PAGE_BOUNDARY_88E (TX_TOTAL_PAGE_NUMBER_88E + 1)
+
+/* Note: For Normal Chip Setting ,modify later */
+#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER			\
+	TX_TOTAL_PAGE_NUMBER_88E  /* 0xA9 , 0xb0=>176=>22k */
+#define WMM_NORMAL_TX_PAGE_BOUNDARY_88E			\
+	(WMM_NORMAL_TX_TOTAL_PAGE_NUMBER + 1) /* 0xA9 */
+
+/* 	Chip specific */
+#define CHIP_BONDING_IDENTIFIER(_value)	(((_value)>>22)&0x3)
+#define CHIP_BONDING_92C_1T2R	0x1
+#define CHIP_BONDING_88C_USB_MCARD	0x2
+#define CHIP_BONDING_88C_USB_HP	0x1
+#include "HalVerDef.h"
+#include "hal_com.h"
+
+/* 	Channel Plan */
+enum ChannelPlan {
+	CHPL_FCC	= 0,
+	CHPL_IC		= 1,
+	CHPL_ETSI	= 2,
+	CHPL_SPA	= 3,
+	CHPL_FRANCE	= 4,
+	CHPL_MKK	= 5,
+	CHPL_MKK1	= 6,
+	CHPL_ISRAEL	= 7,
+	CHPL_TELEC	= 8,
+	CHPL_GLOBAL	= 9,
+	CHPL_WORLD	= 10,
+};
+
+struct txpowerinfo24g {
+	u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+	u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G-1];
+	/* If only one tx, only BW20 and OFDM are used. */
+	s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+	s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+	s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+	s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+#define EFUSE_REAL_CONTENT_LEN		512
+#define EFUSE_MAX_SECTION		16
+#define EFUSE_IC_ID_OFFSET		506 /* For some inferior IC purpose*/
+#define AVAILABLE_EFUSE_ADDR(addr)	(addr < EFUSE_REAL_CONTENT_LEN)
+/*  To prevent out of boundary programming case, */
+/*  leave 1byte and program full section */
+/*  9bytes + 1byt + 5bytes and pre 1byte. */
+/*  For worst case: */
+/*  | 1byte|----8bytes----|1byte|--5bytes--| */
+/*  |         |            Reserved(14bytes)	      | */
+
+/*  PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. */
+#define EFUSE_OOB_PROTECT_BYTES			15
+
+#define		HWSET_MAX_SIZE_88E		512
+
+#define		EFUSE_REAL_CONTENT_LEN_88E	256
+#define		EFUSE_MAP_LEN_88E		512
+#define EFUSE_MAP_LEN			EFUSE_MAP_LEN_88E
+#define		EFUSE_MAX_SECTION_88E		64
+#define		EFUSE_MAX_WORD_UNIT_88E		4
+#define		EFUSE_IC_ID_OFFSET_88E		506
+#define		AVAILABLE_EFUSE_ADDR_88E(addr)			\
+	(addr < EFUSE_REAL_CONTENT_LEN_88E)
+/*  To prevent out of boundary programming case, leave 1byte and program
+ *  full section */
+/*  9bytes + 1byt + 5bytes and pre 1byte. */
+/*  For worst case: */
+/*  | 2byte|----8bytes----|1byte|--7bytes--| 92D */
+/*  PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte. */
+#define		EFUSE_OOB_PROTECT_BYTES_88E	18
+#define		EFUSE_PROTECT_BYTES_BANK_88E	16
+
+/* 			EFUSE for BT definition */
+#define EFUSE_BT_REAL_CONTENT_LEN	1536	/*  512*3 */
+#define EFUSE_BT_MAP_LEN		1024	/*  1k bytes */
+#define EFUSE_BT_MAX_SECTION		128	/*  1024/8 */
+
+#define EFUSE_PROTECT_BYTES_BANK	16
+
+/*  For RTL8723 WiFi/BT/GPS multi-function configuration. */
+enum rt_multi_func {
+	RT_MULTI_FUNC_NONE = 0x00,
+	RT_MULTI_FUNC_WIFI = 0x01,
+	RT_MULTI_FUNC_BT = 0x02,
+	RT_MULTI_FUNC_GPS = 0x04,
+};
+
+/*  For RTL8723 regulator mode. */
+enum rt_regulator_mode {
+	RT_SWITCHING_REGULATOR = 0,
+	RT_LDO_REGULATOR = 1,
+};
+
+struct hal_data_8188e {
+	struct HAL_VERSION	VersionID;
+	enum rt_multi_func MultiFunc; /*  For multi-function consideration. */
+	enum rt_regulator_mode RegulatorMode; /*  switching regulator or LDO */
+	u16	CustomerID;
+
+	u16	FirmwareVersion;
+	u16	FirmwareVersionRev;
+	u16	FirmwareSubVersion;
+	u16	FirmwareSignature;
+	u8	PGMaxGroup;
+	/* current WIFI_PHY values */
+	u32	ReceiveConfig;
+	enum wireless_mode CurrentWirelessMode;
+	enum ht_channel_width CurrentChannelBW;
+	u8	CurrentChannel;
+	u8	nCur40MhzPrimeSC;/*  Control channel sub-carrier */
+
+	u16	BasicRateSet;
+
+	/* rf_ctrl */
+	u8	rf_chip;
+	u8	rf_type;
+	u8	NumTotalRFPath;
+
+	u8	BoardType;
+
+	/*  EEPROM setting. */
+	u16	EEPROMVID;
+	u16	EEPROMPID;
+	u16	EEPROMSVID;
+	u16	EEPROMSDID;
+	u8	EEPROMCustomerID;
+	u8	EEPROMSubCustomerID;
+	u8	EEPROMVersion;
+	u8	EEPROMRegulatory;
+
+	u8	bTXPowerDataReadFromEEPORM;
+	u8	EEPROMThermalMeter;
+	u8	bAPKThermalMeterIgnore;
+
+	bool	EepromOrEfuse;
+	/* 92C:256bytes, 88E:512bytes, we use union set (512bytes) */
+	u8	EfuseMap[2][HWSET_MAX_SIZE_512];
+	u8	EfuseUsedPercentage;
+	struct efuse_hal	EfuseHal;
+
+	u8	Index24G_CCK_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+	u8	Index24G_BW40_Base[MAX_RF_PATH][CHANNEL_MAX_NUMBER];
+	/* If only one tx, only BW20 and OFDM are used. */
+	s8	CCK_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+	s8	OFDM_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+	s8	BW20_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+	s8	BW40_24G_Diff[MAX_RF_PATH][MAX_TX_COUNT];
+
+	u8	TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+	/*  For HT 40MHZ pwr */
+	u8	TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+	/*  For HT 40MHZ pwr */
+	u8	TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+	/*  HT 20<->40 Pwr diff */
+	u8	TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+	/*  For HT<->legacy pwr diff */
+	u8	TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+	/*  For power group */
+	u8	PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+	u8	PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+
+	u8	LegacyHTTxPowerDiff;/*  Legacy to HT rate power diff */
+	/*  The current Tx Power Level */
+	u8	CurrentCckTxPwrIdx;
+	u8	CurrentOfdm24GTxPwrIdx;
+	u8	CurrentBW2024GTxPwrIdx;
+	u8	CurrentBW4024GTxPwrIdx;
+
+
+	/*  Read/write are allow for following hardware information variables */
+	u8	framesync;
+	u32	framesyncC34;
+	u8	framesyncMonitor;
+	u8	DefaultInitialGain[4];
+	u8	pwrGroupCnt;
+	u32	MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16];
+	u32	CCKTxPowerLevelOriginalOffset;
+
+	u8	CrystalCap;
+	u32	AntennaTxPath;			/*  Antenna path Tx */
+	u32	AntennaRxPath;			/*  Antenna path Rx */
+	u8	BluetoothCoexist;
+	u8	ExternalPA;
+
+	u8	bLedOpenDrain; /* Open-drain support for controlling the LED.*/
+
+	u8	b1x1RecvCombine;	/*  for 1T1R receive combining */
+
+	u32	AcParam_BE; /* Original parameter for BE, use for EDCA turbo. */
+
+	struct bb_reg_def PHYRegDef[4];	/* Radio A/B/C/D */
+
+	u32	RfRegChnlVal[2];
+
+	/* RDG enable */
+	bool	 bRDGEnable;
+
+	/* for host message to fw */
+	u8	LastHMEBoxNum;
+
+	u8	fw_ractrl;
+	u8	RegTxPause;
+	/*  Beacon function related global variable. */
+	u32	RegBcnCtrlVal;
+	u8	RegFwHwTxQCtrl;
+	u8	RegReg542;
+	u8	RegCR_1;
+
+	struct dm_priv	dmpriv;
+	struct odm_dm_struct odmpriv;
+	struct sreset_priv srestpriv;
+
+	u8	CurAntenna;
+	u8	AntDivCfg;
+	u8	TRxAntDivType;
+
+
+	u8	bDumpRxPkt;/* for debug */
+	u8	bDumpTxPkt;/* for debug */
+	u8	FwRsvdPageStartOffset; /* Reserve page start offset except
+					*  beacon in TxQ. */
+
+	/*  2010/08/09 MH Add CU power down mode. */
+	bool		pwrdown;
+
+	/*  Add for dual MAC  0--Mac0 1--Mac1 */
+	u32	interfaceIndex;
+
+	u8	OutEpQueueSel;
+	u8	OutEpNumber;
+
+	/*  Add for USB aggreation mode dynamic shceme. */
+	bool		UsbRxHighSpeedMode;
+
+	/*  2010/11/22 MH Add for slim combo debug mode selective. */
+	/*  This is used for fix the drawback of CU TSMC-A/UMC-A cut.
+	 * HW auto suspend ability. Close BT clock. */
+	bool		SlimComboDbg;
+
+	u16	EfuseUsedBytes;
+
+#ifdef CONFIG_88EU_P2P
+	struct P2P_PS_Offload_t	p2p_ps_offload;
+#endif
+
+	/*  Auto FSM to Turn On, include clock, isolation, power control
+	 *  for MAC only */
+	u8	bMacPwrCtrlOn;
+
+	u32	UsbBulkOutSize;
+
+	/*  Interrupt relatd register information. */
+	u32	IntArray[3];/* HISR0,HISR1,HSISR */
+	u32	IntrMask[3];
+	u8	C2hArray[16];
+	u8	UsbTxAggMode;
+	u8	UsbTxAggDescNum;
+	u16	HwRxPageSize;		/*  Hardware setting */
+	u32	MaxUsbRxAggBlock;
+
+	enum usb_rx_agg_mode UsbRxAggMode;
+	u8	UsbRxAggBlockCount;	/*  USB Block count. Block size is
+					 * 512-byte in high speed and 64-byte
+					 * in full speed */
+	u8	UsbRxAggBlockTimeout;
+	u8	UsbRxAggPageCount;	/*  8192C DMA page count */
+	u8	UsbRxAggPageTimeout;
+};
+
+#define GET_HAL_DATA(__pAdapter)				\
+	((struct hal_data_8188e *)((__pAdapter)->HalData))
+#define GET_RF_TYPE(priv)		(GET_HAL_DATA(priv)->rf_type)
+
+#define INCLUDE_MULTI_FUNC_BT(_Adapter)				\
+	(GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT)
+#define INCLUDE_MULTI_FUNC_GPS(_Adapter)			\
+	(GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS)
+
+/*  rtl8188e_hal_init.c */
+s32 rtl8188e_FirmwareDownload(struct adapter *padapter);
+void _8051Reset88E(struct adapter *padapter);
+void rtl8188e_InitializeFirmwareVars(struct adapter *padapter);
+
+
+s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy);
+
+/*  EFuse */
+u8 GetEEPROMSize8188E(struct adapter *padapter);
+void Hal_InitPGData88E(struct adapter *padapter);
+void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo);
+void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *hwinfo,
+			    bool AutoLoadFail);
+
+void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo,
+				bool AutoLoadFail);
+void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo,
+				 bool AutoLoadFail);
+void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo,
+				 bool AutoLoadFail);
+void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter,u8 *PROMContent,
+				 bool AutoLoadFail);
+void Hal_ReadThermalMeter_88E(struct adapter *	dapter, u8 *PROMContent,
+			      bool AutoloadFail);
+void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo,
+			      bool AutoLoadFail);
+void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo,
+				bool AutoLoadFail);
+void Hal_ReadPowerSavingMode88E(struct adapter *pAdapter, u8 *hwinfo,
+				bool AutoLoadFail);
+
+bool HalDetectPwrDownMode88E(struct adapter *Adapter);
+
+void Hal_InitChannelPlan(struct adapter *padapter);
+void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc);
+
+/*  register */
+void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits);
+
+void rtl8188e_clone_haldata(struct adapter *dst, struct adapter *src);
+void rtl8188e_start_thread(struct adapter *padapter);
+void rtl8188e_stop_thread(struct adapter *padapter);
+
+void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter  *Adapter, int len);
+s32 rtl8188e_iol_efuse_patch(struct adapter *padapter);
+void rtw_cancel_all_timer(struct adapter *padapter);
+void _ps_open_RF(struct adapter *adapt);
+
+#endif /* __RTL8188E_HAL_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_led.h b/drivers/staging/rtl8188eu/include/rtl8188e_led.h
new file mode 100644
index 0000000..c0147e7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_led.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_LED_H__
+#define __RTL8188E_LED_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+/*  */
+/*  Interface to manipulate LED objects. */
+/*  */
+void rtl8188eu_InitSwLeds(struct adapter *padapter);
+void rtl8188eu_DeInitSwLeds(struct adapter *padapter);
+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed);
+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_recv.h b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
new file mode 100644
index 0000000..02ccb40
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_recv.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_RECV_H__
+#define __RTL8188E_RECV_H__
+
+#define TX_RPT1_PKT_LEN 8
+
+#define RECV_BLK_SZ 512
+#define RECV_BLK_CNT 16
+#define RECV_BLK_TH RECV_BLK_CNT
+#define RECV_BULK_IN_ADDR		0x80
+#define RECV_INT_IN_ADDR		0x81
+
+#define NR_PREALLOC_RECV_SKB (8)
+
+#define NR_RECVBUFF (4)
+
+#define MAX_RECVBUF_SZ (15360) /*  15k < 16k */
+
+struct phy_stat {
+	unsigned int phydw0;
+	unsigned int phydw1;
+	unsigned int phydw2;
+	unsigned int phydw3;
+	unsigned int phydw4;
+	unsigned int phydw5;
+	unsigned int phydw6;
+	unsigned int phydw7;
+};
+
+/*  Rx smooth factor */
+#define	Rx_Smooth_Factor (20)
+
+enum rx_packet_type {
+	NORMAL_RX,/* Normal rx packet */
+	TX_REPORT1,/* CCX */
+	TX_REPORT2,/* TX RPT */
+	HIS_REPORT,/*  USB HISR RPT */
+};
+
+#define INTERRUPT_MSG_FORMAT_LEN 60
+void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *buf);
+s32 rtl8188eu_init_recv_priv(struct adapter *padapter);
+void rtl8188eu_free_recv_priv(struct adapter * padapter);
+void rtl8188eu_recv_hdl(struct adapter * padapter, struct recv_buf *precvbuf);
+void rtl8188eu_recv_tasklet(void *priv);
+void rtl8188e_query_rx_phy_status(union recv_frame *fr, struct phy_stat *phy);
+void rtl8188e_process_phy_info(struct adapter * padapter, void *prframe);
+void update_recvframe_phyinfo_88e(union recv_frame *fra, struct phy_stat *phy);
+void update_recvframe_attrib_88e(union recv_frame *fra, struct recv_stat *stat);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_rf.h b/drivers/staging/rtl8188eu/include/rtl8188e_rf.h
new file mode 100644
index 0000000..10fc356
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_rf.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_RF_H__
+#define __RTL8188E_RF_H__
+
+#define		RF6052_MAX_TX_PWR		0x3F
+#define		RF6052_MAX_REG			0x3F
+#define		RF6052_MAX_PATH			2
+
+
+int	PHY_RF6052_Config8188E(struct adapter *Adapter);
+void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate);
+void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter,
+				     enum ht_channel_width Bandwidth);
+void	rtl8188e_PHY_RF6052SetCckTxPower(struct adapter *Adapter, u8 *level);
+void	rtl8188e_PHY_RF6052SetOFDMTxPower(struct adapter *Adapter, u8 *ofdm,
+					  u8 *pwrbw20, u8 *pwrbw40, u8 channel);
+
+#endif/* __RTL8188E_RF_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_spec.h b/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
new file mode 100644
index 0000000..c12c56b9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_spec.h
@@ -0,0 +1,1439 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *******************************************************************************/
+#ifndef __RTL8188E_SPEC_H__
+#define __RTL8188E_SPEC_H__
+
+#ifndef BIT
+#define BIT(x)		(1 << (x))
+#endif
+
+#define BIT0	0x00000001
+#define BIT1	0x00000002
+#define BIT2	0x00000004
+#define BIT3	0x00000008
+#define BIT4	0x00000010
+#define BIT5	0x00000020
+#define BIT6	0x00000040
+#define BIT7	0x00000080
+#define BIT8	0x00000100
+#define BIT9	0x00000200
+#define BIT10	0x00000400
+#define BIT11	0x00000800
+#define BIT12	0x00001000
+#define BIT13	0x00002000
+#define BIT14	0x00004000
+#define BIT15	0x00008000
+#define BIT16	0x00010000
+#define BIT17	0x00020000
+#define BIT18	0x00040000
+#define BIT19	0x00080000
+#define BIT20	0x00100000
+#define BIT21	0x00200000
+#define BIT22	0x00400000
+#define BIT23	0x00800000
+#define BIT24	0x01000000
+#define BIT25	0x02000000
+#define BIT26	0x04000000
+#define BIT27	0x08000000
+#define BIT28	0x10000000
+#define BIT29	0x20000000
+#define BIT30	0x40000000
+#define BIT31	0x80000000
+
+/*        8192C Regsiter offset definition */
+
+#define		HAL_PS_TIMER_INT_DELAY	50	/*   50 microseconds */
+#define		HAL_92C_NAV_UPPER_UNIT	128	/*  micro-second */
+
+#define MAC_ADDR_LEN			6
+/*  8188E PKT_BUFF_ACCESS_CTRL value */
+#define TXPKT_BUF_SELECT		0x69
+#define RXPKT_BUF_SELECT		0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS	0x0
+
+
+/* 	0x0000h ~ 0x00FFh	System Configuration */
+#define REG_SYS_ISO_CTRL		0x0000
+#define REG_SYS_FUNC_EN			0x0002
+#define REG_APS_FSMCO			0x0004
+#define REG_SYS_CLKR			0x0008
+#define REG_9346CR			0x000A
+#define REG_EE_VPD			0x000C
+#define REG_AFE_MISC			0x0010
+#define REG_SPS0_CTRL			0x0011
+#define REG_SPS_OCP_CFG			0x0018
+#define REG_RSV_CTRL			0x001C
+#define REG_RF_CTRL			0x001F
+#define REG_LDOA15_CTRL			0x0020
+#define REG_LDOV12D_CTRL		0x0021
+#define REG_LDOHCI12_CTRL		0x0022
+#define REG_LPLDO_CTRL			0x0023
+#define REG_AFE_XTAL_CTRL		0x0024
+#define REG_AFE_PLL_CTRL		0x0028
+#define REG_APE_PLL_CTRL_EXT		0x002c
+#define REG_EFUSE_CTRL			0x0030
+#define REG_EFUSE_TEST			0x0034
+#define REG_GPIO_MUXCFG			0x0040
+#define REG_GPIO_IO_SEL			0x0042
+#define REG_MAC_PINMUX_CFG		0x0043
+#define REG_GPIO_PIN_CTRL		0x0044
+#define REG_GPIO_INTM			0x0048
+#define REG_LEDCFG0			0x004C
+#define REG_LEDCFG1			0x004D
+#define REG_LEDCFG2			0x004E
+#define REG_LEDCFG3			0x004F
+#define REG_FSIMR			0x0050
+#define REG_FSISR			0x0054
+#define REG_HSIMR			0x0058
+#define REG_HSISR			0x005c
+#define REG_GPIO_PIN_CTRL_2		0x0060 /*  RTL8723 WIFI/BT/GPS
+				 * Multi-Function GPIO Pin Control. */
+#define REG_GPIO_IO_SEL_2		0x0062 /*  RTL8723 WIFI/BT/GPS
+				 * Multi-Function GPIO Select. */
+#define REG_BB_PAD_CTRL			0x0064
+#define REG_MULTI_FUNC_CTRL		0x0068 /*  RTL8723 WIFI/BT/GPS
+				 * Multi-Function control source. */
+#define REG_GPIO_OUTPUT			0x006c
+#define REG_AFE_XTAL_CTRL_EXT		0x0078 /* RTL8188E */
+#define REG_XCK_OUT_CTRL		0x007c /* RTL8188E */
+#define REG_MCUFWDL			0x0080
+#define REG_WOL_EVENT			0x0081 /* RTL8188E */
+#define REG_MCUTSTCFG			0x0084
+#define REG_HMEBOX_E0			0x0088
+#define REG_HMEBOX_E1			0x008A
+#define REG_HMEBOX_E2			0x008C
+#define REG_HMEBOX_E3			0x008E
+#define REG_HMEBOX_EXT_0		0x01F0
+#define REG_HMEBOX_EXT_1		0x01F4
+#define REG_HMEBOX_EXT_2		0x01F8
+#define REG_HMEBOX_EXT_3		0x01FC
+#define REG_HIMR_88E			0x00B0
+#define REG_HISR_88E			0x00B4
+#define REG_HIMRE_88E			0x00B8
+#define REG_HISRE_88E			0x00BC
+#define REG_EFUSE_ACCESS		0x00CF	/*  Efuse access protection
+						 * for RTL8723 */
+#define REG_BIST_SCAN			0x00D0
+#define REG_BIST_RPT			0x00D4
+#define REG_BIST_ROM_RPT		0x00D8
+#define REG_USB_SIE_INTF		0x00E0
+#define REG_PCIE_MIO_INTF		0x00E4
+#define REG_PCIE_MIO_INTD		0x00E8
+#define REG_HPON_FSM			0x00EC
+#define REG_SYS_CFG			0x00F0
+#define REG_GPIO_OUTSTS			0x00F4	/*  For RTL8723 only. */
+#define REG_TYPE_ID			0x00FC
+
+#define REG_MAC_PHY_CTRL_NORMAL		0x00f8
+
+/* 	0x0100h ~ 0x01FFh	MACTOP General Configuration */
+#define REG_CR				0x0100
+#define REG_PBP				0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL	0x0106
+#define REG_TRXDMA_CTRL			0x010C
+#define REG_TRXFF_BNDY			0x0114
+#define REG_TRXFF_STATUS		0x0118
+#define REG_RXFF_PTR			0x011C
+/* define REG_HIMR			0x0120 */
+/* define REG_HISR			0x0124 */
+#define REG_HIMRE			0x0128
+#define REG_HISRE			0x012C
+#define REG_CPWM			0x012F
+#define REG_FWIMR			0x0130
+#define REG_FTIMR			0x0138
+#define REG_FWISR			0x0134
+#define REG_PKTBUF_DBG_CTRL		0x0140
+#define REG_PKTBUF_DBG_ADDR		(REG_PKTBUF_DBG_CTRL)
+#define REG_RXPKTBUF_DBG		(REG_PKTBUF_DBG_CTRL+2)
+#define REG_TXPKTBUF_DBG		(REG_PKTBUF_DBG_CTRL+3)
+#define REG_RXPKTBUF_CTRL		(REG_PKTBUF_DBG_CTRL+2)
+#define REG_PKTBUF_DBG_DATA_L		0x0144
+#define REG_PKTBUF_DBG_DATA_H		0x0148
+
+#define REG_TC0_CTRL			0x0150
+#define REG_TC1_CTRL			0x0154
+#define REG_TC2_CTRL			0x0158
+#define REG_TC3_CTRL			0x015C
+#define REG_TC4_CTRL			0x0160
+#define REG_TCUNIT_BASE			0x0164
+#define REG_MBIST_START			0x0174
+#define REG_MBIST_DONE			0x0178
+#define REG_MBIST_FAIL			0x017C
+#define REG_32K_CTRL			0x0194 /* RTL8188E */
+#define REG_C2HEVT_MSG_NORMAL		0x01A0
+#define REG_C2HEVT_CLEAR		0x01AF
+#define REG_MCUTST_1			0x01c0
+#define REG_FMETHR			0x01C8
+#define REG_HMETFR			0x01CC
+#define REG_HMEBOX_0			0x01D0
+#define REG_HMEBOX_1			0x01D4
+#define REG_HMEBOX_2			0x01D8
+#define REG_HMEBOX_3			0x01DC
+
+#define REG_LLT_INIT			0x01E0
+
+/* 	0x0200h ~ 0x027Fh	TXDMA Configuration */
+#define REG_RQPN			0x0200
+#define REG_FIFOPAGE			0x0204
+#define REG_TDECTRL			0x0208
+#define REG_TXDMA_OFFSET_CHK		0x020C
+#define REG_TXDMA_STATUS		0x0210
+#define REG_RQPN_NPQ			0x0214
+
+/* 	0x0280h ~ 0x02FFh	RXDMA Configuration */
+#define		REG_RXDMA_AGG_PG_TH	0x0280
+#define	REG_RXPKT_NUM			0x0284
+#define		REG_RXDMA_STATUS	0x0288
+
+/* 	0x0300h ~ 0x03FFh	PCIe */
+#define	REG_PCIE_CTRL_REG		0x0300
+#define	REG_INT_MIG			0x0304	/*  Interrupt Migration */
+#define	REG_BCNQ_DESA			0x0308	/*  TX Beacon Descr Address */
+#define	REG_HQ_DESA			0x0310	/*  TX High Queue Descr Addr */
+#define	REG_MGQ_DESA			0x0318	/*  TX Manage Queue Descr Addr*/
+#define	REG_VOQ_DESA			0x0320	/*  TX VO Queue Descr Addr */
+#define	REG_VIQ_DESA			0x0328	/*  TX VI Queue Descr Addr */
+#define	REG_BEQ_DESA			0x0330	/*  TX BE Queue Descr Addr */
+#define	REG_BKQ_DESA			0x0338	/*  TX BK Queue Descr Addr */
+#define	REG_RX_DESA			0x0340	/*  RX Queue Descr Addr */
+#define	REG_MDIO			0x0354	/*  MDIO for Access PCIE PHY */
+#define	REG_DBG_SEL			0x0360	/*  Debug Selection Register */
+#define	REG_PCIE_HRPWM			0x0361	/* PCIe RPWM */
+#define	REG_PCIE_HCPWM			0x0363	/* PCIe CPWM */
+#define	REG_WATCH_DOG			0x0368
+
+/*  RTL8723 series ------------------------------ */
+#define	REG_PCIE_HISR			0x03A0
+
+/*  spec version 11 */
+/* 	0x0400h ~ 0x047Fh	Protocol Configuration */
+#define REG_VOQ_INFORMATION		0x0400
+#define REG_VIQ_INFORMATION		0x0404
+#define REG_BEQ_INFORMATION		0x0408
+#define REG_BKQ_INFORMATION		0x040C
+#define REG_MGQ_INFORMATION		0x0410
+#define REG_HGQ_INFORMATION		0x0414
+#define REG_BCNQ_INFORMATION		0x0418
+#define REG_TXPKT_EMPTY			0x041A
+
+#define REG_CPU_MGQ_INFORMATION		0x041C
+#define REG_FWHW_TXQ_CTRL		0x0420
+#define REG_HWSEQ_CTRL			0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
+#define REG_TXPKTBUF_MGQ_BDNY		0x0425
+#define REG_LIFETIME_EN			0x0426
+#define REG_MULTI_BCNQ_OFFSET		0x0427
+#define REG_SPEC_SIFS			0x0428
+#define REG_RL				0x042A
+#define REG_DARFRC			0x0430
+#define REG_RARFRC			0x0438
+#define REG_RRSR			0x0440
+#define REG_ARFR0			0x0444
+#define REG_ARFR1			0x0448
+#define REG_ARFR2			0x044C
+#define REG_ARFR3			0x0450
+#define REG_AGGLEN_LMT			0x0458
+#define REG_AMPDU_MIN_SPACE		0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD	0x045D
+#define REG_FAST_EDCA_CTRL		0x0460
+#define REG_RD_RESP_PKT_TH		0x0463
+#define REG_INIRTS_RATE_SEL		0x0480
+/* define REG_INIDATA_RATE_SEL		0x0484 */
+#define REG_POWER_STATUS		0x04A4
+#define REG_POWER_STAGE1		0x04B4
+#define REG_POWER_STAGE2		0x04B8
+#define REG_PKT_VO_VI_LIFE_TIME		0x04C0
+#define REG_PKT_BE_BK_LIFE_TIME		0x04C2
+#define REG_STBC_SETTING		0x04C4
+#define REG_PROT_MODE_CTRL		0x04C8
+#define REG_MAX_AGGR_NUM		0x04CA
+#define REG_RTS_MAX_AGGR_NUM		0x04CB
+#define REG_BAR_MODE_CTRL		0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT		0x04CF
+#define REG_EARLY_MODE_CONTROL		0x4D0
+#define REG_NQOS_SEQ			0x04DC
+#define REG_QOS_SEQ			0x04DE
+#define REG_NEED_CPU_HANDLE		0x04E0
+#define REG_PKT_LOSE_RPT		0x04E1
+#define REG_PTCL_ERR_STATUS		0x04E2
+#define REG_TX_RPT_CTRL			0x04EC
+#define REG_TX_RPT_TIME			0x04F0	/*  2 byte */
+#define REG_DUMMY			0x04FC
+
+/* 	0x0500h ~ 0x05FFh	EDCA Configuration */
+#define REG_EDCA_VO_PARAM		0x0500
+#define REG_EDCA_VI_PARAM		0x0504
+#define REG_EDCA_BE_PARAM		0x0508
+#define REG_EDCA_BK_PARAM		0x050C
+#define REG_BCNTCFG			0x0510
+#define REG_PIFS			0x0512
+#define REG_RDG_PIFS			0x0513
+#define REG_SIFS_CTX			0x0514
+#define REG_SIFS_TRX			0x0516
+#define REG_TSFTR_SYN_OFFSET		0x0518
+#define REG_AGGR_BREAK_TIME		0x051A
+#define REG_SLOT			0x051B
+#define REG_TX_PTCL_CTRL		0x0520
+#define REG_TXPAUSE			0x0522
+#define REG_DIS_TXREQ_CLR		0x0523
+#define REG_RD_CTRL			0x0524
+/*  Format for offset 540h-542h: */
+/* 	[3:0]:   TBTT prohibit setup in unit of 32us. The time for HW getting
+ *		 beacon content before TBTT. */
+/* 	[7:4]:   Reserved. */
+/* 	[19:8]:  TBTT prohibit hold in unit of 32us. The time for HW holding
+ *		 to send the beacon packet. */
+/* 	[23:20]: Reserved */
+/*  Description: */
+/* 	              | */
+/*      |<--Setup--|--Hold------------>| */
+/* 	--------------|---------------------- */
+/*                 | */
+/*                TBTT */
+/*  Note: We cannot update beacon content to HW or send any AC packets during
+ *	  the time between Setup and Hold. */
+#define REG_TBTT_PROHIBIT		0x0540
+#define REG_RD_NAV_NXT			0x0544
+#define REG_NAV_PROT_LEN		0x0546
+#define REG_BCN_CTRL			0x0550
+#define REG_BCN_CTRL_1			0x0551
+#define REG_MBID_NUM			0x0552
+#define REG_DUAL_TSF_RST		0x0553
+#define REG_BCN_INTERVAL		0x0554
+#define REG_DRVERLYINT			0x0558
+#define REG_BCNDMATIM			0x0559
+#define REG_ATIMWND			0x055A
+#define REG_BCN_MAX_ERR			0x055D
+#define REG_RXTSF_OFFSET_CCK		0x055E
+#define REG_RXTSF_OFFSET_OFDM		0x055F
+#define REG_TSFTR			0x0560
+#define REG_TSFTR1			0x0568
+#define REG_ATIMWND_1			0x0570
+#define REG_PSTIMER			0x0580
+#define REG_TIMER0			0x0584
+#define REG_TIMER1			0x0588
+#define REG_ACMHWCTRL			0x05C0
+
+/* define REG_FW_TSF_SYNC_CNT		0x04A0 */
+#define REG_FW_RESET_TSF_CNT_1		0x05FC
+#define REG_FW_RESET_TSF_CNT_0		0x05FD
+#define REG_FW_BCN_DIS_CNT		0x05FE
+
+/* 	0x0600h ~ 0x07FFh	WMAC Configuration */
+#define REG_APSD_CTRL			0x0600
+#define REG_BWOPMODE			0x0603
+#define REG_TCR				0x0604
+#define REG_RCR				0x0608
+#define REG_RX_PKT_LIMIT		0x060C
+#define REG_RX_DLK_TIME			0x060D
+#define REG_RX_DRVINFO_SZ		0x060F
+
+#define REG_MACID			0x0610
+#define REG_BSSID			0x0618
+#define REG_MAR				0x0620
+#define REG_MBIDCAMCFG			0x0628
+
+#define REG_USTIME_EDCA			0x0638
+#define REG_MAC_SPEC_SIFS		0x063A
+
+/*  20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
+/*  [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
+#define REG_R2T_SIFS			0x063C
+/*  [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
+#define REG_T2T_SIFS			0x063E
+#define REG_ACKTO			0x0640
+#define REG_CTS2TO			0x0641
+#define REG_EIFS			0x0642
+
+/* RXERR_RPT */
+#define RXERR_TYPE_OFDM_PPDU		0
+#define RXERR_TYPE_OFDM_false_ALARM	1
+#define RXERR_TYPE_OFDM_MPDU_OK		2
+#define RXERR_TYPE_OFDM_MPDU_FAIL	3
+#define RXERR_TYPE_CCK_PPDU		4
+#define RXERR_TYPE_CCK_false_ALARM	5
+#define RXERR_TYPE_CCK_MPDU_OK		6
+#define RXERR_TYPE_CCK_MPDU_FAIL	7
+#define RXERR_TYPE_HT_PPDU		8
+#define RXERR_TYPE_HT_false_ALARM	9
+#define RXERR_TYPE_HT_MPDU_TOTAL	10
+#define RXERR_TYPE_HT_MPDU_OK		11
+#define RXERR_TYPE_HT_MPDU_FAIL		12
+#define RXERR_TYPE_RX_FULL_DROP		15
+
+#define RXERR_COUNTER_MASK		0xFFFFF
+#define RXERR_RPT_RST			BIT(27)
+#define _RXERR_RPT_SEL(type)		((type) << 28)
+
+/*  Note: */
+/* 	The NAV upper value is very important to WiFi 11n 5.2.3 NAV test.
+ *	The default value is always too small, but the WiFi TestPlan test
+ *	by 25,000 microseconds of NAV through sending CTS in the air.
+ *	We must update this value greater than 25,000 microseconds to pass
+ *	the item. The offset of NAV_UPPER in 8192C Spec is incorrect, and
+ *	the offset should be 0x0652. */
+#define REG_NAV_UPPER			0x0652	/*  unit of 128 */
+
+/* WMA, BA, CCX */
+/* define REG_NAV_CTRL			0x0650 */
+#define REG_BACAMCMD			0x0654
+#define REG_BACAMCONTENT		0x0658
+#define REG_LBDLY			0x0660
+#define REG_FWDLY			0x0661
+#define REG_RXERR_RPT			0x0664
+#define REG_WMAC_TRXPTCL_CTL		0x0668
+
+/*  Security */
+#define REG_CAMCMD			0x0670
+#define REG_CAMWRITE			0x0674
+#define REG_CAMREAD			0x0678
+#define REG_CAMDBG			0x067C
+#define REG_SECCFG			0x0680
+
+/*  Power */
+#define REG_WOW_CTRL			0x0690
+#define REG_PS_RX_INFO			0x0692
+#define REG_UAPSD_TID			0x0693
+#define REG_WKFMCAM_CMD			0x0698
+#define REG_WKFMCAM_NUM_88E		0x698
+#define REG_RXFLTMAP0			0x06A0
+#define REG_RXFLTMAP1			0x06A2
+#define REG_RXFLTMAP2			0x06A4
+#define REG_BCN_PSR_RPT			0x06A8
+#define REG_BT_COEX_TABLE		0x06C0
+
+/*  Hardware Port 2 */
+#define REG_MACID1			0x0700
+#define REG_BSSID1			0x0708
+
+/* 	0xFE00h ~ 0xFE55h	USB Configuration */
+#define REG_USB_INFO			0xFE17
+#define REG_USB_SPECIAL_OPTION		0xFE55
+#define REG_USB_DMA_AGG_TO		0xFE5B
+#define REG_USB_AGG_TO			0xFE5C
+#define REG_USB_AGG_TH			0xFE5D
+
+/*  For normal chip */
+#define REG_NORMAL_SIE_VID		0xFE60		/*  0xFE60~0xFE61 */
+#define REG_NORMAL_SIE_PID		0xFE62		/*  0xFE62~0xFE63 */
+#define REG_NORMAL_SIE_OPTIONAL		0xFE64
+#define REG_NORMAL_SIE_EP		0xFE65		/*  0xFE65~0xFE67 */
+#define REG_NORMAL_SIE_PHY		0xFE68		/*  0xFE68~0xFE6B */
+#define REG_NORMAL_SIE_OPTIONAL2	0xFE6C
+#define REG_NORMAL_SIE_GPS_EP		0xFE6D	/*  0xFE6D, for RTL8723 only. */
+#define REG_NORMAL_SIE_MAC_ADDR		0xFE70		/*  0xFE70~0xFE75 */
+#define REG_NORMAL_SIE_STRING		0xFE80		/*  0xFE80~0xFEDF */
+
+/*  TODO: use these definition when using REG_xxx naming rule. */
+/*  NOTE: DO NOT Remove these definition. Use later. */
+
+#define	EFUSE_CTRL			REG_EFUSE_CTRL	/*  E-Fuse Control. */
+#define	EFUSE_TEST			REG_EFUSE_TEST	/*  E-Fuse Test. */
+#define	MSR				(REG_CR + 2)	/*  Media Status reg */
+#define	ISR				REG_HISR_88E
+/*  Timing Sync Function Timer Register. */
+#define	TSFR				REG_TSFTR
+
+#define		PBP			REG_PBP
+
+/*  Redifine MACID register, to compatible prior ICs. */
+/*  MAC ID Register, Offset 0x0050-0x0053 */
+#define	IDR0				REG_MACID
+/*  MAC ID Register, Offset 0x0054-0x0055 */
+#define	IDR4				(REG_MACID + 4)
+
+/*  9. Security Control Registers	(Offset: ) */
+/* IN 8190 Data Sheet is called CAMcmd */
+#define	RWCAM				REG_CAMCMD
+/*  Software write CAM input content */
+#define	WCAMI				REG_CAMWRITE
+/*  Software read/write CAM config */
+#define	RCAMO				REG_CAMREAD
+#define	CAMDBG				REG_CAMDBG
+/* Security Configuration Register */
+#define	SECR				REG_SECCFG
+
+/*  Unused register */
+#define	UnusedRegister			0x1BF
+#define	DCAM				UnusedRegister
+#define	PSR				UnusedRegister
+#define	BBAddr				UnusedRegister
+#define	PhyDataR			UnusedRegister
+
+/*  Min Spacing related settings. */
+#define	MAX_MSS_DENSITY_2T		0x13
+#define	MAX_MSS_DENSITY_1T		0x0A
+
+/*  EEPROM enable when set 1 */
+#define	CmdEEPROM_En			BIT5
+/*  System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 */
+#define	CmdEERPOMSEL			BIT4
+#define	Cmd9346CR_9356SEL		BIT4
+
+/*        8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */
+#define	GPIOSEL_GPIO			0
+#define	GPIOSEL_ENBT			BIT5
+
+/*        8192C GPIO PIN Control Register (offset 0x44, 4 byte) */
+/*  GPIO pins input value */
+#define	GPIO_IN				REG_GPIO_PIN_CTRL
+/*  GPIO pins output value */
+#define	GPIO_OUT			(REG_GPIO_PIN_CTRL+1)
+/*  GPIO pins output enable when a bit is set to "1"; otherwise,
+ *  input is configured. */
+#define	GPIO_IO_SEL			(REG_GPIO_PIN_CTRL+2)
+#define	GPIO_MOD			(REG_GPIO_PIN_CTRL+3)
+
+/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define	HSIMR_GPIO12_0_INT_EN		BIT0
+#define	HSIMR_SPS_OCP_INT_EN		BIT5
+#define	HSIMR_RON_INT_EN		BIT6
+#define	HSIMR_PDN_INT_EN		BIT7
+#define	HSIMR_GPIO9_INT_EN		BIT25
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+#define	HSISR_GPIO12_0_INT		BIT0
+#define	HSISR_SPS_OCP_INT		BIT5
+#define	HSISR_RON_INT_EN		BIT6
+#define	HSISR_PDNINT			BIT7
+#define	HSISR_GPIO9_INT			BIT25
+
+/*   8192C (MSR) Media Status Register	(Offset 0x4C, 8 bits) */
+/*
+Network Type
+00: No link
+01: Link in ad hoc network
+10: Link in infrastructure network
+11: AP mode
+Default: 00b.
+*/
+#define	MSR_NOLINK			0x00
+#define	MSR_ADHOC			0x01
+#define	MSR_INFRA			0x02
+#define	MSR_AP				0x03
+
+/*   88EU (MSR) Media Status Register	(Offset 0x4C, 8 bits) */
+#define	USB_INTR_CONTENT_C2H_OFFSET	0
+#define	USB_INTR_CONTENT_CPWM1_OFFSET	16
+#define	USB_INTR_CONTENT_CPWM2_OFFSET	20
+#define	USB_INTR_CONTENT_HISR_OFFSET	48
+#define	USB_INTR_CONTENT_HISRE_OFFSET	52
+
+/*  88E Driver Initialization Offload REG_FDHM0(Offset 0x88, 8 bits) */
+/* IOL config for REG_FDHM0(Reg0x88) */
+#define CMD_INIT_LLT			BIT0
+#define CMD_READ_EFUSE_MAP		BIT1
+#define CMD_EFUSE_PATCH			BIT2
+#define CMD_IOCONFIG			BIT3
+#define CMD_INIT_LLT_ERR		BIT4
+#define CMD_READ_EFUSE_MAP_ERR		BIT5
+#define CMD_EFUSE_PATCH_ERR		BIT6
+#define CMD_IOCONFIG_ERR		BIT7
+
+/*  6. Adaptive Control Registers  (Offset: 0x0160 - 0x01CF) */
+/*  8192C Response Rate Set Register	(offset 0x181, 24bits) */
+#define	RRSR_1M				BIT0
+#define	RRSR_2M				BIT1
+#define	RRSR_5_5M			BIT2
+#define	RRSR_11M			BIT3
+#define	RRSR_6M				BIT4
+#define	RRSR_9M				BIT5
+#define	RRSR_12M			BIT6
+#define	RRSR_18M			BIT7
+#define	RRSR_24M			BIT8
+#define	RRSR_36M			BIT9
+#define	RRSR_48M			BIT10
+#define	RRSR_54M			BIT11
+#define	RRSR_MCS0			BIT12
+#define	RRSR_MCS1			BIT13
+#define	RRSR_MCS2			BIT14
+#define	RRSR_MCS3			BIT15
+#define	RRSR_MCS4			BIT16
+#define	RRSR_MCS5			BIT17
+#define	RRSR_MCS6			BIT18
+#define	RRSR_MCS7			BIT19
+
+/*  8192C Response Rate Set Register	(offset 0x1BF, 8bits) */
+/*  WOL bit information */
+#define	HAL92C_WOL_PTK_UPDATE_EVENT	BIT0
+#define	HAL92C_WOL_GTK_UPDATE_EVENT	BIT1
+
+/*        8192C BW_OPMODE bits		(Offset 0x203, 8bit) */
+#define	BW_OPMODE_20MHZ			BIT2
+#define	BW_OPMODE_5G			BIT1
+
+/*        8192C CAM Config Setting (offset 0x250, 1 byte) */
+#define	CAM_VALID			BIT15
+#define	CAM_NOTVALID			0x0000
+#define	CAM_USEDK			BIT5
+
+#define	CAM_CONTENT_COUNT		8
+
+#define	CAM_NONE			0x0
+#define	CAM_WEP40			0x01
+#define	CAM_TKIP			0x02
+#define	CAM_AES				0x04
+#define	CAM_WEP104			0x05
+#define	CAM_SMS4			0x6
+
+#define	TOTAL_CAM_ENTRY			32
+#define	HALF_CAM_ENTRY			16
+
+#define	CAM_CONFIG_USEDK		true
+#define	CAM_CONFIG_NO_USEDK		false
+
+#define	CAM_WRITE			BIT16
+#define	CAM_READ			0x00000000
+#define	CAM_POLLINIG			BIT31
+
+#define	SCR_UseDK			0x01
+#define	SCR_TxSecEnable			0x02
+#define	SCR_RxSecEnable			0x04
+
+/*  10. Power Save Control Registers	 (Offset: 0x0260 - 0x02DF) */
+#define	WOW_PMEN			BIT0 /*  Power management Enable. */
+#define	WOW_WOMEN			BIT1 /*  WoW function on or off. */
+#define	WOW_MAGIC			BIT2 /*  Magic packet */
+#define	WOW_UWF				BIT3 /*  Unicast Wakeup frame. */
+
+/*  12. Host Interrupt Status Registers	 (Offset: 0x0300 - 0x030F) */
+/*        8188 IMR/ISR bits */
+#define	IMR_DISABLED_88E		0x0
+/*  IMR DW0(0x0060-0063) Bit 0-31 */
+#define	IMR_TXCCK_88E			BIT30	/*  TXRPT interrupt when CCX bit of the packet is set */
+#define	IMR_PSTIMEOUT_88E		BIT29	/*  Power Save Time Out Interrupt */
+#define	IMR_GTINT4_88E			BIT28	/*  When GTIMER4 expires, this bit is set to 1 */
+#define	IMR_GTINT3_88E			BIT27	/*  When GTIMER3 expires, this bit is set to 1 */
+#define	IMR_TBDER_88E			BIT26	/*  Transmit Beacon0 Error */
+#define	IMR_TBDOK_88E			BIT25	/*  Transmit Beacon0 OK */
+#define	IMR_TSF_BIT32_TOGGLE_88E	BIT24	/*  TSF Timer BIT32 toggle indication interrupt */
+#define	IMR_BCNDMAINT0_88E		BIT20	/*  Beacon DMA Interrupt 0 */
+#define	IMR_BCNDERR0_88E		BIT16	/*  Beacon Queue DMA Error 0 */
+#define	IMR_HSISR_IND_ON_INT_88E	BIT15	/*  HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */
+#define	IMR_BCNDMAINT_E_88E		BIT14	/*  Beacon DMA Interrupt Extension for Win7 */
+#define	IMR_ATIMEND_88E			BIT12	/*  CTWidnow End or ATIM Window End */
+#define	IMR_HISR1_IND_INT_88E		BIT11	/*  HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1) */
+#define	IMR_C2HCMD_88E			BIT10	/*  CPU to Host Command INT Status, Write 1 clear */
+#define	IMR_CPWM2_88E			BIT9	/*  CPU power Mode exchange INT Status, Write 1 clear */
+#define	IMR_CPWM_88E			BIT8	/*  CPU power Mode exchange INT Status, Write 1 clear */
+#define	IMR_HIGHDOK_88E			BIT7	/*  High Queue DMA OK */
+#define	IMR_MGNTDOK_88E			BIT6	/*  Management Queue DMA OK */
+#define	IMR_BKDOK_88E			BIT5	/*  AC_BK DMA OK */
+#define	IMR_BEDOK_88E			BIT4	/*  AC_BE DMA OK */
+#define	IMR_VIDOK_88E			BIT3	/*  AC_VI DMA OK */
+#define	IMR_VODOK_88E			BIT2	/*  AC_VO DMA OK */
+#define	IMR_RDU_88E			BIT1	/*  Rx Descriptor Unavailable */
+#define	IMR_ROK_88E			BIT0	/*  Receive DMA OK */
+
+/*  IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define	IMR_BCNDMAINT7_88E		BIT27	/*  Beacon DMA Interrupt 7 */
+#define	IMR_BCNDMAINT6_88E		BIT26	/*  Beacon DMA Interrupt 6 */
+#define	IMR_BCNDMAINT5_88E		BIT25	/*  Beacon DMA Interrupt 5 */
+#define	IMR_BCNDMAINT4_88E		BIT24	/*  Beacon DMA Interrupt 4 */
+#define	IMR_BCNDMAINT3_88E		BIT23	/*  Beacon DMA Interrupt 3 */
+#define	IMR_BCNDMAINT2_88E		BIT22	/*  Beacon DMA Interrupt 2 */
+#define	IMR_BCNDMAINT1_88E		BIT21	/*  Beacon DMA Interrupt 1 */
+#define	IMR_BCNDERR7_88E		BIT20	/*  Beacon DMA Error Int 7 */
+#define	IMR_BCNDERR6_88E		BIT19	/*  Beacon DMA Error Int 6 */
+#define	IMR_BCNDERR5_88E		BIT18	/*  Beacon DMA Error Int 5 */
+#define	IMR_BCNDERR4_88E		BIT17	/*  Beacon DMA Error Int 4 */
+#define	IMR_BCNDERR3_88E		BIT16	/*  Beacon DMA Error Int 3 */
+#define	IMR_BCNDERR2_88E		BIT15	/*  Beacon DMA Error Int 2 */
+#define	IMR_BCNDERR1_88E		BIT14	/*  Beacon DMA Error Int 1 */
+#define	IMR_ATIMEND_E_88E		BIT13	/*  ATIM Window End Ext for Win7 */
+#define	IMR_TXERR_88E			BIT11	/*  Tx Err Flag Int Status, write 1 clear. */
+#define	IMR_RXERR_88E			BIT10	/*  Rx Err Flag INT Status, Write 1 clear */
+#define	IMR_TXFOVW_88E			BIT9	/*  Transmit FIFO Overflow */
+#define	IMR_RXFOVW_88E			BIT8	/*  Receive FIFO Overflow */
+
+#define	HAL_NIC_UNPLUG_ISR		0xFFFFFFFF	/*  The value when the NIC is unplugged for PCI. */
+
+/*  8192C EFUSE */
+#define		HWSET_MAX_SIZE			256
+#define		HWSET_MAX_SIZE_88E		512
+
+/*===================================================================
+=====================================================================
+Here the register defines are for 92C. When the define is as same with 92C,
+we will use the 92C's define for the consistency
+So the following defines for 92C is not entire!!!!!!
+=====================================================================
+=====================================================================*/
+/*
+Based on Datasheet V33---090401
+Register Summary
+Current IOREG MAP
+0x0000h ~ 0x00FFh   System Configuration (256 Bytes)
+0x0100h ~ 0x01FFh   MACTOP General Configuration (256 Bytes)
+0x0200h ~ 0x027Fh   TXDMA Configuration (128 Bytes)
+0x0280h ~ 0x02FFh   RXDMA Configuration (128 Bytes)
+0x0300h ~ 0x03FFh   PCIE EMAC Reserved Region (256 Bytes)
+0x0400h ~ 0x04FFh   Protocol Configuration (256 Bytes)
+0x0500h ~ 0x05FFh   EDCA Configuration (256 Bytes)
+0x0600h ~ 0x07FFh   WMAC Configuration (512 Bytes)
+0x2000h ~ 0x3FFFh   8051 FW Download Region (8196 Bytes)
+*/
+/* 		 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) */
+/*  Note: */
+/* 	The bits of stopping AC(VO/VI/BE/BK) queue in datasheet
+ *	RTL8192S/RTL8192C are wrong, */
+/* 	the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2,
+ *	and BK - Bit3. */
+/* 	8723 and 88E may be not correct either in the earlier version. */
+#define		StopBecon			BIT6
+#define		StopHigh			BIT5
+#define		StopMgt				BIT4
+#define		StopBK				BIT3
+#define		StopBE				BIT2
+#define		StopVI				BIT1
+#define		StopVO				BIT0
+
+/*        8192C (RCR) Receive Configuration Register(Offset 0x608, 32 bits) */
+#define	RCR_APPFCS		BIT31	/* WMAC append FCS after payload */
+#define	RCR_APP_MIC		BIT30
+#define	RCR_APP_PHYSTS		BIT28
+#define	RCR_APP_ICV		BIT29
+#define	RCR_APP_PHYST_RXFF	BIT28
+#define	RCR_APP_BA_SSN		BIT27	/* Accept BA SSN */
+#define	RCR_ENMBID		BIT24	/* Enable Multiple BssId. */
+#define	RCR_LSIGEN		BIT23
+#define	RCR_MFBEN		BIT22
+#define	RCR_HTC_LOC_CTRL	BIT14   /* MFC<--HTC=1 MFC-->HTC=0 */
+#define	RCR_AMF			BIT13	/* Accept management type frame */
+#define	RCR_ACF			BIT12	/* Accept control type frame */
+#define	RCR_ADF			BIT11	/* Accept data type frame */
+#define	RCR_AICV		BIT9	/* Accept ICV error packet */
+#define	RCR_ACRC32		BIT8	/* Accept CRC32 error packet */
+#define	RCR_CBSSID_BCN		BIT7	/* Accept BSSID match packet
+					 * (Rx beacon, probe rsp) */
+#define	RCR_CBSSID_DATA		BIT6	/* Accept BSSID match (Data)*/
+#define	RCR_CBSSID		RCR_CBSSID_DATA	/* Accept BSSID match */
+#define	RCR_APWRMGT		BIT5	/* Accept power management pkt*/
+#define	RCR_ADD3		BIT4	/* Accept address 3 match pkt */
+#define	RCR_AB			BIT3	/* Accept broadcast packet */
+#define	RCR_AM			BIT2	/* Accept multicast packet */
+#define	RCR_APM			BIT1	/* Accept physical match pkt */
+#define	RCR_AAP			BIT0	/* Accept all unicast packet */
+#define	RCR_MXDMA_OFFSET	8
+#define	RCR_FIFO_OFFSET		13
+
+/* 	0xFE00h ~ 0xFE55h	USB Configuration */
+#define REG_USB_INFO			0xFE17
+#define REG_USB_SPECIAL_OPTION		0xFE55
+#define REG_USB_DMA_AGG_TO		0xFE5B
+#define REG_USB_AGG_TO			0xFE5C
+#define REG_USB_AGG_TH			0xFE5D
+
+#define REG_USB_HRPWM			0xFE58
+#define REG_USB_HCPWM			0xFE57
+/*        8192C Regsiter Bit and Content definition */
+/* 	0x0000h ~ 0x00FFh	System Configuration */
+
+/* 2 SYS_ISO_CTRL */
+#define ISO_MD2PP			BIT(0)
+#define ISO_UA2USB			BIT(1)
+#define ISO_UD2CORE			BIT(2)
+#define ISO_PA2PCIE			BIT(3)
+#define ISO_PD2CORE			BIT(4)
+#define ISO_IP2MAC			BIT(5)
+#define ISO_DIOP			BIT(6)
+#define ISO_DIOE			BIT(7)
+#define ISO_EB2CORE			BIT(8)
+#define ISO_DIOR			BIT(9)
+#define PWC_EV12V			BIT(15)
+
+/* 2 SYS_FUNC_EN */
+#define FEN_BBRSTB			BIT(0)
+#define FEN_BB_GLB_RSTn			BIT(1)
+#define FEN_USBA			BIT(2)
+#define FEN_UPLL			BIT(3)
+#define FEN_USBD			BIT(4)
+#define FEN_DIO_PCIE			BIT(5)
+#define FEN_PCIEA			BIT(6)
+#define FEN_PPLL			BIT(7)
+#define FEN_PCIED			BIT(8)
+#define FEN_DIOE			BIT(9)
+#define FEN_CPUEN			BIT(10)
+#define FEN_DCORE			BIT(11)
+#define FEN_ELDR			BIT(12)
+#define FEN_DIO_RF			BIT(13)
+#define FEN_HWPDN			BIT(14)
+#define FEN_MREGEN			BIT(15)
+
+/* 2 APS_FSMCO */
+#define PFM_LDALL			BIT(0)
+#define PFM_ALDN			BIT(1)
+#define PFM_LDKP			BIT(2)
+#define PFM_WOWL			BIT(3)
+#define EnPDN				BIT(4)
+#define PDN_PL				BIT(5)
+#define APFM_ONMAC			BIT(8)
+#define APFM_OFF			BIT(9)
+#define APFM_RSM			BIT(10)
+#define AFSM_HSUS			BIT(11)
+#define AFSM_PCIE			BIT(12)
+#define APDM_MAC			BIT(13)
+#define APDM_HOST			BIT(14)
+#define APDM_HPDN			BIT(15)
+#define RDY_MACON			BIT(16)
+#define SUS_HOST			BIT(17)
+#define ROP_ALD				BIT(20)
+#define ROP_PWR				BIT(21)
+#define ROP_SPS				BIT(22)
+#define SOP_MRST			BIT(25)
+#define SOP_FUSE			BIT(26)
+#define SOP_ABG				BIT(27)
+#define SOP_AMB				BIT(28)
+#define SOP_RCK				BIT(29)
+#define SOP_A8M				BIT(30)
+#define XOP_BTCK			BIT(31)
+
+/* 2 SYS_CLKR */
+#define ANAD16V_EN			BIT(0)
+#define ANA8M				BIT(1)
+#define MACSLP				BIT(4)
+#define LOADER_CLK_EN			BIT(5)
+
+/* 2 9346CR */
+
+#define		BOOT_FROM_EEPROM	BIT(4)
+#define		EEPROM_EN		BIT(5)
+
+/* 2 SPS0_CTRL */
+
+/* 2 SPS_OCP_CFG */
+
+/* 2 RF_CTRL */
+#define RF_EN				BIT(0)
+#define RF_RSTB				BIT(1)
+#define RF_SDMRSTB			BIT(2)
+
+/* 2 LDOV12D_CTRL */
+#define LDV12_EN			BIT(0)
+#define LDV12_SDBY			BIT(1)
+#define LPLDO_HSM			BIT(2)
+#define LPLDO_LSM_DIS			BIT(3)
+#define _LDV12_VADJ(x)			(((x) & 0xF) << 4)
+
+/* 2EFUSE_CTRL */
+#define ALD_EN				BIT(18)
+#define EF_PD				BIT(19)
+#define EF_FLAG				BIT(31)
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EF_TRPT				BIT(7)
+/*  00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
+#define EF_CELL_SEL			(BIT(8)|BIT(9))
+#define LDOE25_EN			BIT(31)
+#define EFUSE_SEL(x)			(((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK			0x300
+#define EFUSE_WIFI_SEL_0		0x0
+#define EFUSE_BT_SEL_0			0x1
+#define EFUSE_BT_SEL_1			0x2
+#define EFUSE_BT_SEL_2			0x3
+
+#define EFUSE_ACCESS_ON			0x69	/*  For RTL8723 only. */
+#define EFUSE_ACCESS_OFF		0x00	/*  For RTL8723 only. */
+
+/* 2 8051FWDL */
+/* 2 MCUFWDL */
+#define MCUFWDL_EN			BIT(0)
+#define MCUFWDL_RDY			BIT(1)
+#define FWDL_ChkSum_rpt			BIT(2)
+#define MACINI_RDY			BIT(3)
+#define BBINI_RDY			BIT(4)
+#define RFINI_RDY			BIT(5)
+#define WINTINI_RDY			BIT(6)
+#define RAM_DL_SEL			BIT(7) /*  1:RAM, 0:ROM */
+#define ROM_DLEN			BIT(19)
+#define CPRST				BIT(23)
+
+/* 2 REG_SYS_CFG */
+#define XCLK_VLD			BIT(0)
+#define ACLK_VLD			BIT(1)
+#define UCLK_VLD			BIT(2)
+#define PCLK_VLD			BIT(3)
+#define PCIRSTB				BIT(4)
+#define V15_VLD				BIT(5)
+#define SW_OFFLOAD_EN			BIT(7)
+#define SIC_IDLE			BIT(8)
+#define BD_MAC2				BIT(9)
+#define BD_MAC1				BIT(10)
+#define IC_MACPHY_MODE			BIT(11)
+#define CHIP_VER			(BIT(12)|BIT(13)|BIT(14)|BIT(15))
+#define BT_FUNC				BIT(16)
+#define VENDOR_ID			BIT(19)
+#define PAD_HWPD_IDN			BIT(22)
+#define TRP_VAUX_EN			BIT(23)	/*  RTL ID */
+#define TRP_BT_EN			BIT(24)
+#define BD_PKG_SEL			BIT(25)
+#define BD_HCI_SEL			BIT(26)
+#define TYPE_ID				BIT(27)
+
+#define CHIP_VER_RTL_MASK		0xF000	/* Bit 12 ~ 15 */
+#define CHIP_VER_RTL_SHIFT		12
+
+/* 2REG_GPIO_OUTSTS (For RTL8723 only) */
+#define	EFS_HCI_SEL			(BIT(0)|BIT(1))
+#define	PAD_HCI_SEL			(BIT(2)|BIT(3))
+#define	HCI_SEL				(BIT(4)|BIT(5))
+#define	PKG_SEL_HCI			BIT(6)
+#define	FEN_GPS				BIT(7)
+#define	FEN_BT				BIT(8)
+#define	FEN_WL				BIT(9)
+#define	FEN_PCI				BIT(10)
+#define	FEN_USB				BIT(11)
+#define	BTRF_HWPDN_N			BIT(12)
+#define	WLRF_HWPDN_N			BIT(13)
+#define	PDN_BT_N			BIT(14)
+#define	PDN_GPS_N			BIT(15)
+#define	BT_CTL_HWPDN			BIT(16)
+#define	GPS_CTL_HWPDN			BIT(17)
+#define	PPHY_SUSB			BIT(20)
+#define	UPHY_SUSB			BIT(21)
+#define	PCI_SUSEN			BIT(22)
+#define	USB_SUSEN			BIT(23)
+#define	RF_RL_ID			(BIT(31)|BIT(30)|BIT(29)|BIT(28))
+
+/* 2SYS_CFG */
+#define RTL_ID				BIT(23)	/*  TestChip ID, 1:Test(RLE); 0:MP(RL) */
+
+/* 	0x0100h ~ 0x01FFh	MACTOP General Configuration */
+
+/* 2 Function Enable Registers */
+/* 2 CR */
+
+#define HCI_TXDMA_EN			BIT(0)
+#define HCI_RXDMA_EN			BIT(1)
+#define TXDMA_EN			BIT(2)
+#define RXDMA_EN			BIT(3)
+#define PROTOCOL_EN			BIT(4)
+#define SCHEDULE_EN			BIT(5)
+#define MACTXEN				BIT(6)
+#define MACRXEN				BIT(7)
+#define ENSWBCN				BIT(8)
+#define ENSEC				BIT(9)
+#define CALTMR_EN			BIT(10)	/*  32k CAL TMR enable */
+
+/*  Network type */
+#define _NETTYPE(x)			(((x) & 0x3) << 16)
+#define MASK_NETTYPE			0x30000
+#define NT_NO_LINK			0x0
+#define NT_LINK_AD_HOC			0x1
+#define NT_LINK_AP			0x2
+#define NT_AS_AP			0x3
+
+/* 2 PBP - Page Size Register */
+#define GET_RX_PAGE_SIZE(value)		((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)		(((value) & 0xF0) >> 4)
+#define _PSRX_MASK			0xF
+#define _PSTX_MASK			0xF0
+#define _PSRX(x)			(x)
+#define _PSTX(x)			((x) << 4)
+
+#define PBP_64				0x0
+#define PBP_128				0x1
+#define PBP_256				0x2
+#define PBP_512				0x3
+#define PBP_1024			0x4
+
+/* 2 TX/RXDMA */
+#define RXDMA_ARBBW_EN			BIT(0)
+#define RXSHFT_EN			BIT(1)
+#define RXDMA_AGG_EN			BIT(2)
+#define QS_VO_QUEUE			BIT(8)
+#define QS_VI_QUEUE			BIT(9)
+#define QS_BE_QUEUE			BIT(10)
+#define QS_BK_QUEUE			BIT(11)
+#define QS_MANAGER_QUEUE		BIT(12)
+#define QS_HIGH_QUEUE			BIT(13)
+
+#define HQSEL_VOQ			BIT(0)
+#define HQSEL_VIQ			BIT(1)
+#define HQSEL_BEQ			BIT(2)
+#define HQSEL_BKQ			BIT(3)
+#define HQSEL_MGTQ			BIT(4)
+#define HQSEL_HIQ			BIT(5)
+
+/*  For normal driver, 0x10C */
+#define _TXDMA_HIQ_MAP(x)		(((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x)		(((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x)		(((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x)		(((x)&0x3) << 8 )
+#define _TXDMA_VIQ_MAP(x)		(((x)&0x3) << 6 )
+#define _TXDMA_VOQ_MAP(x)		(((x)&0x3) << 4 )
+
+#define QUEUE_LOW			1
+#define QUEUE_NORMAL			2
+#define QUEUE_HIGH			3
+
+/* 2 TRXFF_BNDY */
+
+/* 2 LLT_INIT */
+#define _LLT_NO_ACTIVE			0x0
+#define _LLT_WRITE_ACCESS		0x1
+#define _LLT_READ_ACCESS		0x2
+
+#define _LLT_INIT_DATA(x)		((x) & 0xFF)
+#define _LLT_INIT_ADDR(x)		(((x) & 0xFF) << 8)
+#define _LLT_OP(x)			(((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x)		(((x) >> 30) & 0x3)
+
+/* 	0x0200h ~ 0x027Fh	TXDMA Configuration */
+/* 2RQPN */
+#define _HPQ(x)				((x) & 0xFF)
+#define _LPQ(x)				(((x) & 0xFF) << 8)
+#define _PUBQ(x)			(((x) & 0xFF) << 16)
+/*  NOTE: in RQPN_NPQ register */
+#define _NPQ(x)				((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS			BIT(24)
+#define LPQ_PUBLIC_DIS			BIT(25)
+#define LD_RQPN				BIT(31)
+
+/* 2TDECTRL */
+#define BCN_VALID			BIT(16)
+#define BCN_HEAD(x)			(((x) & 0xFF) << 8)
+#define	BCN_HEAD_MASK			0xFF00
+
+/* 2 TDECTL */
+#define BLK_DESC_NUM_SHIFT		4
+#define BLK_DESC_NUM_MASK		0xF
+
+/* 2 TXDMA_OFFSET_CHK */
+#define DROP_DATA_EN			BIT(9)
+
+/* 	0x0280h ~ 0x028Bh	RX DMA Configuration */
+
+/*     REG_RXDMA_CONTROL, 0x0286h */
+
+/* 2 REG_RXPKT_NUM, 0x0284 */
+#define		RXPKT_RELEASE_POLL	BIT(16)
+#define	RXDMA_IDLE			BIT(17)
+#define	RW_RELEASE_EN			BIT(18)
+
+/* 	0x0400h ~ 0x047Fh	Protocol Configuration */
+/* 2 FWHW_TXQ_CTRL */
+#define EN_AMPDU_RTY_NEW		BIT(7)
+
+/* 2 SPEC SIFS */
+#define _SPEC_SIFS_CCK(x)		((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x)		(((x) & 0xFF) << 8)
+
+/* 2 RL */
+#define	RETRY_LIMIT_SHORT_SHIFT		8
+#define	RETRY_LIMIT_LONG_SHIFT		0
+
+/* 	0x0500h ~ 0x05FFh	EDCA Configuration */
+
+/* 2 EDCA setting */
+#define AC_PARAM_TXOP_LIMIT_OFFSET	16
+#define AC_PARAM_ECW_MAX_OFFSET		12
+#define AC_PARAM_ECW_MIN_OFFSET		8
+#define AC_PARAM_AIFS_OFFSET		0
+
+#define _LRL(x)			((x) & 0x3F)
+#define _SRL(x)			(((x) & 0x3F) << 8)
+
+/* 2 BCN_CTRL */
+#define EN_MBSSID		BIT(1)
+#define EN_TXBCN_RPT		BIT(2)
+#define EN_BCN_FUNCTION		BIT(3)
+#define DIS_TSF_UPDATE		BIT(3)
+
+/*  The same function but different bit field. */
+#define DIS_TSF_UDT0_NORMAL_CHIP	BIT(4)
+#define DIS_TSF_UDT0_TEST_CHIP	BIT(5)
+#define STOP_BCNQ		BIT(6)
+
+/* 2 ACMHWCTRL */
+#define	AcmHw_HwEn		BIT(0)
+#define	AcmHw_BeqEn		BIT(1)
+#define	AcmHw_ViqEn		BIT(2)
+#define	AcmHw_VoqEn		BIT(3)
+#define	AcmHw_BeqStatus		BIT(4)
+#define	AcmHw_ViqStatus		BIT(5)
+#define	AcmHw_VoqStatus		BIT(6)
+
+/* 	0x0600h ~ 0x07FFh	WMAC Configuration */
+/* 2APSD_CTRL */
+#define APSDOFF			BIT(6)
+#define APSDOFF_STATUS		BIT(7)
+
+#define RATE_BITMAP_ALL		0xFFFFF
+
+/*  Only use CCK 1M rate for ACK */
+#define RATE_RRSR_CCK_ONLY_1M	0xFFFF1
+
+/* 2 TCR */
+#define TSFRST			BIT(0)
+#define DIS_GCLK		BIT(1)
+#define PAD_SEL			BIT(2)
+#define PWR_ST			BIT(6)
+#define PWRBIT_OW_EN		BIT(7)
+#define ACRC			BIT(8)
+#define CFENDFORM		BIT(9)
+#define ICV			BIT(10)
+
+/* 2 RCR */
+#define AAP			BIT(0)
+#define APM			BIT(1)
+#define AM			BIT(2)
+#define AB			BIT(3)
+#define ADD3			BIT(4)
+#define APWRMGT			BIT(5)
+#define CBSSID			BIT(6)
+#define CBSSID_DATA		BIT(6)
+#define CBSSID_BCN		BIT(7)
+#define ACRC32			BIT(8)
+#define AICV			BIT(9)
+#define ADF			BIT(11)
+#define ACF			BIT(12)
+#define AMF			BIT(13)
+#define HTC_LOC_CTRL		BIT(14)
+#define UC_DATA_EN		BIT(16)
+#define BM_DATA_EN		BIT(17)
+#define MFBEN			BIT(22)
+#define LSIGEN			BIT(23)
+#define EnMBID			BIT(24)
+#define APP_BASSN		BIT(27)
+#define APP_PHYSTS		BIT(28)
+#define APP_ICV			BIT(29)
+#define APP_MIC			BIT(30)
+#define APP_FCS			BIT(31)
+
+/* 2 SECCFG */
+#define	SCR_TxUseDK		BIT(0)	/* Force Tx Use Default Key */
+#define	SCR_RxUseDK		BIT(1)	/* Force Rx Use Default Key */
+#define	SCR_TxEncEnable		BIT(2)	/* Enable Tx Encryption */
+#define	SCR_RxDecEnable		BIT(3)	/* Enable Rx Decryption */
+#define	SCR_SKByA2		BIT(4)	/* Search kEY BY A2 */
+#define	SCR_NoSKMC		BIT(5)	/* No Key Search Multicast */
+#define SCR_TXBCUSEDK		BIT(6)	/* Force Tx Bcast pkt Use Default Key */
+#define SCR_RXBCUSEDK		BIT(7)	/* Force Rx Bcast pkt Use Default Key */
+
+/* 	RTL8188E SDIO Configuration */
+
+/*  I/O bus domain address mapping */
+#define SDIO_LOCAL_BASE			0x10250000
+#define WLAN_IOREG_BASE			0x10260000
+#define FIRMWARE_FIFO_BASE		0x10270000
+#define TX_HIQ_BASE			0x10310000
+#define TX_MIQ_BASE			0x10320000
+#define TX_LOQ_BASE			0x10330000
+#define RX_RX0FF_BASE			0x10340000
+
+/*  SDIO host local register space mapping. */
+#define SDIO_LOCAL_MSK			0x0FFF
+#define WLAN_IOREG_MSK			0x7FFF
+#define WLAN_FIFO_MSK			0x1FFF	/*  Aggregation Length[12:0] */
+#define WLAN_RX0FF_MSK			0x0003
+
+/*  Without ref to the SDIO Device ID */
+#define SDIO_WITHOUT_REF_DEVICE_ID	0
+#define SDIO_LOCAL_DEVICE_ID		0	/*  0b[16], 000b[15:13] */
+#define WLAN_TX_HIQ_DEVICE_ID		4	/*  0b[16], 100b[15:13] */
+#define WLAN_TX_MIQ_DEVICE_ID		5	/*  0b[16], 101b[15:13] */
+#define WLAN_TX_LOQ_DEVICE_ID		6	/*  0b[16], 110b[15:13] */
+#define WLAN_RX0FF_DEVICE_ID		7	/*  0b[16], 111b[15:13] */
+#define WLAN_IOREG_DEVICE_ID		8	/*  1b[16] */
+
+/*  SDIO Tx Free Page Index */
+#define HI_QUEUE_IDX			0
+#define MID_QUEUE_IDX			1
+#define LOW_QUEUE_IDX			2
+#define PUBLIC_QUEUE_IDX		3
+
+#define SDIO_MAX_TX_QUEUE		3	/*  HIQ, MIQ and LOQ */
+#define SDIO_MAX_RX_QUEUE		1
+
+/*  SDIO Tx Control */
+#define SDIO_REG_TX_CTRL		0x0000
+/*  SDIO Host Interrupt Mask */
+#define SDIO_REG_HIMR			0x0014
+/*  SDIO Host Interrupt Service Routine */
+#define SDIO_REG_HISR			0x0018
+/*  HCI Current Power Mode */
+#define SDIO_REG_HCPWM			0x0019
+/*  RXDMA Request Length */
+#define SDIO_REG_RX0_REQ_LEN		0x001C
+/*  Free Tx Buffer Page */
+#define SDIO_REG_FREE_TXPG		0x0020
+/*  HCI Current Power Mode 1 */
+#define SDIO_REG_HCPWM1			0x0024
+/*  HCI Current Power Mode 2 */
+#define SDIO_REG_HCPWM2			0x0026
+/*  HTSF Informaion */
+#define SDIO_REG_HTSFR_INFO		0x0030
+/*  HCI Request Power Mode 1 */
+#define SDIO_REG_HRPWM1			0x0080
+/*  HCI Request Power Mode 2 */
+#define SDIO_REG_HRPWM2			0x0082
+/*  HCI Power Save Clock */
+#define SDIO_REG_HPS_CLKR		0x0084
+/*  SDIO HCI Suspend Control */
+#define SDIO_REG_HSUS_CTRL		0x0086
+/*  SDIO Host Extension Interrupt Mask Always */
+#define SDIO_REG_HIMR_ON		0x0090
+/*  SDIO Host Extension Interrupt Status Always */
+#define SDIO_REG_HISR_ON		0x0091
+
+#define SDIO_HIMR_DISABLED			0
+
+/*  RTL8188E SDIO Host Interrupt Mask Register */
+#define SDIO_HIMR_RX_REQUEST_MSK		BIT0
+#define SDIO_HIMR_AVAL_MSK			BIT1
+#define SDIO_HIMR_TXERR_MSK			BIT2
+#define SDIO_HIMR_RXERR_MSK			BIT3
+#define SDIO_HIMR_TXFOVW_MSK			BIT4
+#define SDIO_HIMR_RXFOVW_MSK			BIT5
+#define SDIO_HIMR_TXBCNOK_MSK			BIT6
+#define SDIO_HIMR_TXBCNERR_MSK			BIT7
+#define SDIO_HIMR_BCNERLY_INT_MSK		BIT16
+#define SDIO_HIMR_C2HCMD_MSK			BIT17
+#define SDIO_HIMR_CPWM1_MSK			BIT18
+#define SDIO_HIMR_CPWM2_MSK			BIT19
+#define SDIO_HIMR_HSISR_IND_MSK			BIT20
+#define SDIO_HIMR_GTINT3_IND_MSK		BIT21
+#define SDIO_HIMR_GTINT4_IND_MSK		BIT22
+#define SDIO_HIMR_PSTIMEOUT_MSK			BIT23
+#define SDIO_HIMR_OCPINT_MSK			BIT24
+#define SDIO_HIMR_ATIMEND_MSK			BIT25
+#define SDIO_HIMR_ATIMEND_E_MSK			BIT26
+#define SDIO_HIMR_CTWEND_MSK			BIT27
+
+/* RTL8188E SDIO Specific */
+#define	SDIO_HIMR_MCU_ERR_MSK			BIT28
+#define	SDIO_HIMR_TSF_BIT32_TOGGLE_MSK		BIT29
+
+/*  SDIO Host Interrupt Service Routine */
+#define SDIO_HISR_RX_REQUEST			BIT0
+#define SDIO_HISR_AVAL				BIT1
+#define SDIO_HISR_TXERR				BIT2
+#define SDIO_HISR_RXERR				BIT3
+#define SDIO_HISR_TXFOVW			BIT4
+#define SDIO_HISR_RXFOVW			BIT5
+#define SDIO_HISR_TXBCNOK			BIT6
+#define SDIO_HISR_TXBCNERR			BIT7
+#define SDIO_HISR_BCNERLY_INT			BIT16
+#define SDIO_HISR_C2HCMD			BIT17
+#define SDIO_HISR_CPWM1				BIT18
+#define SDIO_HISR_CPWM2				BIT19
+#define SDIO_HISR_HSISR_IND			BIT20
+#define SDIO_HISR_GTINT3_IND			BIT21
+#define SDIO_HISR_GTINT4_IND			BIT22
+#define SDIO_HISR_PSTIME			BIT23
+#define SDIO_HISR_OCPINT			BIT24
+#define SDIO_HISR_ATIMEND			BIT25
+#define SDIO_HISR_ATIMEND_E			BIT26
+#define SDIO_HISR_CTWEND			BIT27
+
+/* RTL8188E SDIO Specific */
+#define	SDIO_HISR_MCU_ERR			BIT28
+#define	SDIO_HISR_TSF_BIT32_TOGGLE		BIT29
+
+#define MASK_SDIO_HISR_CLEAR				\
+	(SDIO_HISR_TXERR | SDIO_HISR_RXERR | SDIO_HISR_TXFOVW |\
+	 SDIO_HISR_RXFOVW | SDIO_HISR_TXBCNOK | SDIO_HISR_TXBCNERR |\
+	 SDIO_HISR_C2HCMD | SDIO_HISR_CPWM1 | SDIO_HISR_CPWM2 |\
+	 SDIO_HISR_HSISR_IND | SDIO_HISR_GTINT3_IND | SDIO_HISR_GTINT4_IND |\
+	 SDIO_HISR_PSTIMEOUT | SDIO_HISR_OCPINT)
+
+/*  SDIO HCI Suspend Control Register */
+#define HCI_RESUME_PWR_RDY		BIT1
+#define HCI_SUS_CTRL			BIT0
+
+/*  SDIO Tx FIFO related */
+/*  The number of Tx FIFO free page */
+#define SDIO_TX_FREE_PG_QUEUE			4
+#define SDIO_TX_FIFO_PAGE_SZ			128
+
+/* 	0xFE00h ~ 0xFE55h	USB Configuration */
+
+/* 2 USB Information (0xFE17) */
+#define USB_IS_HIGH_SPEED			0
+#define USB_IS_FULL_SPEED			1
+#define USB_SPEED_MASK				BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK			0xF
+#define USB_NORMAL_SIE_EP_SHIFT			4
+
+/* 2 Special Option */
+#define USB_AGG_EN				BIT(3)
+
+/*  0; Use interrupt endpoint to upload interrupt pkt */
+/*  1; Use bulk endpoint to upload interrupt pkt, */
+#define INT_BULK_SEL				BIT(4)
+
+/* 2REG_C2HEVT_CLEAR */
+/*  Set by driver and notify FW that the driver has read
+ *  the C2H command message */
+#define	C2H_EVT_HOST_CLOSE	0x00
+/*  Set by FW indicating that FW had set the C2H command
+ *  message and it's not yet read by driver. */
+#define C2H_EVT_FW_CLOSE	0xFF
+
+/* 2REG_MULTI_FUNC_CTRL(For RTL8723 Only) */
+/*  Enable GPIO[9] as WiFi HW PDn source */
+#define	WL_HWPDN_EN				BIT0
+/*  WiFi HW PDn polarity control */
+#define	WL_HWPDN_SL				BIT1
+/*  WiFi function enable */
+#define	WL_FUNC_EN				BIT2
+/*  Enable GPIO[9] as WiFi RF HW PDn source */
+#define	WL_HWROF_EN				BIT3
+/*  Enable GPIO[11] as BT HW PDn source */
+#define	BT_HWPDN_EN				BIT16
+/*  BT HW PDn polarity control */
+#define	BT_HWPDN_SL				BIT17
+/*  BT function enable */
+#define	BT_FUNC_EN				BIT18
+/*  Enable GPIO[11] as BT/GPS RF HW PDn source */
+#define	BT_HWROF_EN				BIT19
+/*  Enable GPIO[10] as GPS HW PDn source */
+#define	GPS_HWPDN_EN				BIT20
+/*  GPS HW PDn polarity control */
+#define	GPS_HWPDN_SL				BIT21
+/*  GPS function enable */
+#define	GPS_FUNC_EN				BIT22
+
+/* 3 REG_LIFECTRL_CTRL */
+#define	HAL92C_EN_PKT_LIFE_TIME_BK		BIT3
+#define	HAL92C_EN_PKT_LIFE_TIME_BE		BIT2
+#define	HAL92C_EN_PKT_LIFE_TIME_VI		BIT1
+#define	HAL92C_EN_PKT_LIFE_TIME_VO		BIT0
+
+#define	HAL92C_MSDU_LIFE_TIME_UNIT		128	/*  in us */
+
+/*  General definitions */
+#define LAST_ENTRY_OF_TX_PKT_BUFFER		176 /*  22k 22528 bytes */
+
+#define POLLING_LLT_THRESHOLD			20
+#define POLLING_READY_TIMEOUT_COUNT		1000
+/*  GPIO BIT */
+#define	HAL_8192C_HW_GPIO_WPS_BIT		BIT2
+
+/*	8192C EEPROM/EFUSE share register definition. */
+
+/* 	EEPROM/Efuse PG Offset for 88EE/88EU/88ES */
+#define	EEPROM_TX_PWR_INX_88E			0x10
+
+#define	EEPROM_ChannelPlan_88E			0xB8
+#define	EEPROM_XTAL_88E				0xB9
+#define	EEPROM_THERMAL_METER_88E		0xBA
+#define	EEPROM_IQK_LCK_88E			0xBB
+
+#define	EEPROM_RF_BOARD_OPTION_88E		0xC1
+#define	EEPROM_RF_FEATURE_OPTION_88E		0xC2
+#define	EEPROM_RF_BT_SETTING_88E		0xC3
+#define	EEPROM_VERSION_88E			0xC4
+#define	EEPROM_CUSTOMERID_88E			0xC5
+#define	EEPROM_RF_ANTENNA_OPT_88E		0xC9
+
+/*  RTL88EE */
+#define	EEPROM_MAC_ADDR_88EE			0xD0
+#define	EEPROM_VID_88EE				0xD6
+#define	EEPROM_DID_88EE				0xD8
+#define	EEPROM_SVID_88EE			0xDA
+#define	EEPROM_SMID_88EE			0xDC
+
+/* RTL88EU */
+#define	EEPROM_MAC_ADDR_88EU			0xD7
+#define	EEPROM_VID_88EU				0xD0
+#define	EEPROM_PID_88EU				0xD2
+#define EEPROM_USB_OPTIONAL_FUNCTION0		0xD4
+
+/*  RTL88ES */
+#define	EEPROM_MAC_ADDR_88ES			0x11A
+
+/* 		EEPROM/Efuse Value Type */
+#define EETYPE_TX_PWR				0x0
+
+/*  Default Value for EEPROM or EFUSE!!! */
+#define EEPROM_Default_TSSI			0x0
+#define EEPROM_Default_TxPowerDiff		0x0
+#define EEPROM_Default_CrystalCap		0x5
+/*  Default: 2X2, RTL8192CE(QFPN68) */
+#define EEPROM_Default_BoardType		0x02
+#define EEPROM_Default_TxPower			0x1010
+#define EEPROM_Default_HT2T_TxPwr		0x10
+
+#define EEPROM_Default_LegacyHTTxPowerDiff	0x3
+#define EEPROM_Default_ThermalMeter		0x12
+
+#define EEPROM_Default_AntTxPowerDiff		0x0
+#define EEPROM_Default_TxPwDiff_CrystalCap	0x5
+#define EEPROM_Default_TxPowerLevel		0x2A
+
+#define EEPROM_Default_HT40_2SDiff		0x0
+/*  HT20<->40 default Tx Power Index Difference */
+#define EEPROM_Default_HT20_Diff		2
+#define EEPROM_Default_LegacyHTTxPowerDiff	0x3
+#define EEPROM_Default_HT40_PwrMaxOffset	0
+#define EEPROM_Default_HT20_PwrMaxOffset	0
+
+#define EEPROM_Default_CrystalCap_88E		0x20
+#define	EEPROM_Default_ThermalMeter_88E		0x18
+
+/* New EFUSE deafult value */
+#define		EEPROM_DEFAULT_24G_INDEX	0x2D
+#define		EEPROM_DEFAULT_24G_HT20_DIFF	0X02
+#define		EEPROM_DEFAULT_24G_OFDM_DIFF	0X04
+
+#define		EEPROM_DEFAULT_5G_INDEX		0X2A
+#define		EEPROM_DEFAULT_5G_HT20_DIFF	0X00
+#define		EEPROM_DEFAULT_5G_OFDM_DIFF	0X04
+
+#define		EEPROM_DEFAULT_DIFF		0XFE
+#define	EEPROM_DEFAULT_CHANNEL_PLAN		0x7F
+#define	EEPROM_DEFAULT_BOARD_OPTION		0x00
+#define	EEPROM_DEFAULT_FEATURE_OPTION		0x00
+#define	EEPROM_DEFAULT_BT_OPTION		0x10
+
+/*  For debug */
+#define EEPROM_Default_PID			0x1234
+#define EEPROM_Default_VID			0x5678
+#define EEPROM_Default_CustomerID		0xAB
+#define	EEPROM_Default_CustomerID_8188E		0x00
+#define EEPROM_Default_SubCustomerID		0xCD
+#define EEPROM_Default_Version			0
+
+#define EEPROM_CHANNEL_PLAN_FCC			0x0
+#define EEPROM_CHANNEL_PLAN_IC			0x1
+#define EEPROM_CHANNEL_PLAN_ETSI		0x2
+#define EEPROM_CHANNEL_PLAN_SPA			0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE		0x4
+#define EEPROM_CHANNEL_PLAN_MKK			0x5
+#define EEPROM_CHANNEL_PLAN_MKK1		0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL		0x7
+#define EEPROM_CHANNEL_PLAN_TELEC		0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMA		0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13	0xA
+#define EEPROM_CHANNEL_PLAN_NCC			0xB
+#define EEPROM_USB_OPTIONAL1			0xE
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK		0x80
+
+#define EEPROM_CID_DEFAULT		0x0
+#define EEPROM_CID_TOSHIBA		0x4
+#define EEPROM_CID_CCX			0x10 /*  CCX test. */
+#define EEPROM_CID_QMI			0x0D
+#define EEPROM_CID_WHQL			0xFE
+#define	RTL_EEPROM_ID			0x8129
+
+#endif /* __RTL8188E_SPEC_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_sreset.h b/drivers/staging/rtl8188eu/include/rtl8188e_sreset.h
new file mode 100644
index 0000000..a29e695
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_sreset.h
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTL8188E_SRESET_H_
+#define _RTL8188E_SRESET_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_sreset.h>
+
+void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter);
+void rtl8188e_sreset_xmit_status_check(struct adapter *padapter);
+void rtl8188e_sreset_linked_status_check(struct adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h b/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
new file mode 100644
index 0000000..cf7267a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_xmit.h
@@ -0,0 +1,178 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTL8188E_XMIT_H__
+#define __RTL8188E_XMIT_H__
+
+#define		MAX_TX_AGG_PACKET_NUMBER	0xFF
+/*  */
+/*  Queue Select Value in TxDesc */
+/*  */
+#define QSLT_BK							0x2/* 0x01 */
+#define QSLT_BE							0x0
+#define QSLT_VI							0x5/* 0x4 */
+#define QSLT_VO							0x7/* 0x6 */
+#define QSLT_BEACON						0x10
+#define QSLT_HIGH						0x11
+#define QSLT_MGNT						0x12
+#define QSLT_CMD						0x13
+
+/* For 88e early mode */
+#define SET_EARLYMODE_PKTNUM(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr, 0, 3, __Value)
+#define SET_EARLYMODE_LEN0(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr, 4, 12, __Value)
+#define SET_EARLYMODE_LEN1(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr, 16, 12, __Value)
+#define SET_EARLYMODE_LEN2_1(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr, 28, 4, __Value)
+#define SET_EARLYMODE_LEN2_2(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr+4, 0, 8, __Value)
+#define SET_EARLYMODE_LEN3(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr+4, 8, 12, __Value)
+#define SET_EARLYMODE_LEN4(__pAddr, __Value)			\
+	SET_BITS_TO_LE_4BYTE(__pAddr+4, 20, 12, __Value)
+
+/*  */
+/* defined for TX DESC Operation */
+/*  */
+
+#define MAX_TID (15)
+
+/* OFFSET 0 */
+#define OFFSET_SZ	0
+#define OFFSET_SHT	16
+#define BMC		BIT(24)
+#define LSG		BIT(26)
+#define FSG		BIT(27)
+#define OWN		BIT(31)
+
+
+/* OFFSET 4 */
+#define PKT_OFFSET_SZ		0
+#define QSEL_SHT		8
+#define RATE_ID_SHT		16
+#define NAVUSEHDR		BIT(20)
+#define SEC_TYPE_SHT		22
+#define PKT_OFFSET_SHT		26
+
+/* OFFSET 8 */
+#define AGG_EN			BIT(12)
+#define AGG_BK			BIT(16)
+#define AMPDU_DENSITY_SHT	20
+#define ANTSEL_A		BIT(24)
+#define ANTSEL_B		BIT(25)
+#define TX_ANT_CCK_SHT		26
+#define TX_ANTL_SHT		28
+#define TX_ANT_HT_SHT		30
+
+/* OFFSET 12 */
+#define SEQ_SHT			16
+#define EN_HWSEQ		BIT(31)
+
+/* OFFSET 16 */
+#define QOS			BIT(6)
+#define	HW_SSN			BIT(7)
+#define USERATE			BIT(8)
+#define DISDATAFB		BIT(10)
+#define CTS_2_SELF		BIT(11)
+#define	RTS_EN			BIT(12)
+#define	HW_RTS_EN		BIT(13)
+#define DATA_SHORT		BIT(24)
+#define PWR_STATUS_SHT		15
+#define DATA_SC_SHT		20
+#define DATA_BW			BIT(25)
+
+/* OFFSET 20 */
+#define	RTY_LMT_EN		BIT(17)
+
+enum TXDESC_SC {
+	SC_DONT_CARE = 0x00,
+	SC_UPPER = 0x01,
+	SC_LOWER = 0x02,
+	SC_DUPLICATE = 0x03
+};
+/* OFFSET 20 */
+#define SGI			BIT(6)
+#define USB_TXAGG_NUM_SHT	24
+
+#define txdesc_set_ccx_sw_88e(txdesc, value) \
+	do { \
+		((struct txdesc_88e *)(txdesc))->sw1 = (((value)>>8) & 0x0f); \
+		((struct txdesc_88e *)(txdesc))->sw0 = ((value) & 0xff); \
+	} while (0)
+
+struct txrpt_ccx_88e {
+	/* offset 0 */
+	u8 tag1:1;
+	u8 pkt_num:3;
+	u8 txdma_underflow:1;
+	u8 int_bt:1;
+	u8 int_tri:1;
+	u8 int_ccx:1;
+
+	/* offset 1 */
+	u8 mac_id:6;
+	u8 pkt_ok:1;
+	u8 bmc:1;
+
+	/* offset 2 */
+	u8 retry_cnt:6;
+	u8 lifetime_over:1;
+	u8 retry_over:1;
+
+	/* offset 3 */
+	u8 ccx_qtime0;
+	u8 ccx_qtime1;
+
+	/* offset 5 */
+	u8 final_data_rate;
+
+	/* offset 6 */
+	u8 sw1:4;
+	u8 qsel:4;
+
+	/* offset 7 */
+	u8 sw0;
+};
+
+#define txrpt_ccx_sw_88e(txrpt_ccx) ((txrpt_ccx)->sw0 + ((txrpt_ccx)->sw1<<8))
+#define txrpt_ccx_qtime_88e(txrpt_ccx)			\
+	((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8))
+
+void rtl8188e_fill_fake_txdesc(struct adapter *padapter, u8 *pDesc,
+			       u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull);
+s32 rtl8188eu_init_xmit_priv(struct adapter *padapter);
+void rtl8188eu_free_xmit_priv(struct adapter *padapter);
+s32 rtl8188eu_hal_xmit(struct adapter *padapter, struct xmit_frame *frame);
+s32 rtl8188eu_mgnt_xmit(struct adapter *padapter, struct xmit_frame *frame);
+s32 rtl8188eu_xmit_buf_handler(struct adapter *padapter);
+#define hal_xmit_handler rtl8188eu_xmit_buf_handler
+void rtl8188eu_xmit_tasklet(void *priv);
+s32 rtl8188eu_xmitframe_complete(struct adapter *padapter,
+				 struct xmit_priv *pxmitpriv,
+				 struct xmit_buf *pxmitbuf);
+
+void dump_txrpt_ccx_88e(void *buf);
+void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf);
+
+void _dbg_dump_tx_info(struct adapter *padapter, int frame_tag,
+		       struct tx_desc *ptxdesc);
+
+#endif /* __RTL8188E_XMIT_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_android.h b/drivers/staging/rtl8188eu/include/rtw_android.h
new file mode 100644
index 0000000..e85bf1f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_android.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __RTW_ANDROID_H__
+#define __RTW_ANDROID_H__
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+enum ANDROID_WIFI_CMD {
+	ANDROID_WIFI_CMD_START,
+	ANDROID_WIFI_CMD_STOP,
+	ANDROID_WIFI_CMD_SCAN_ACTIVE,
+	ANDROID_WIFI_CMD_SCAN_PASSIVE,
+	ANDROID_WIFI_CMD_RSSI,
+	ANDROID_WIFI_CMD_LINKSPEED,
+	ANDROID_WIFI_CMD_RXFILTER_START,
+	ANDROID_WIFI_CMD_RXFILTER_STOP,
+	ANDROID_WIFI_CMD_RXFILTER_ADD,
+	ANDROID_WIFI_CMD_RXFILTER_REMOVE,
+	ANDROID_WIFI_CMD_BTCOEXSCAN_START,
+	ANDROID_WIFI_CMD_BTCOEXSCAN_STOP,
+	ANDROID_WIFI_CMD_BTCOEXMODE,
+	ANDROID_WIFI_CMD_SETSUSPENDOPT,
+	ANDROID_WIFI_CMD_P2P_DEV_ADDR,
+	ANDROID_WIFI_CMD_SETFWPATH,
+	ANDROID_WIFI_CMD_SETBAND,
+	ANDROID_WIFI_CMD_GETBAND,
+	ANDROID_WIFI_CMD_COUNTRY,
+	ANDROID_WIFI_CMD_P2P_SET_NOA,
+	ANDROID_WIFI_CMD_P2P_GET_NOA,
+	ANDROID_WIFI_CMD_P2P_SET_PS,
+	ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE,
+	ANDROID_WIFI_CMD_MACADDR,
+	ANDROID_WIFI_CMD_BLOCK,
+	ANDROID_WIFI_CMD_WFD_ENABLE,
+	ANDROID_WIFI_CMD_WFD_DISABLE,
+	ANDROID_WIFI_CMD_WFD_SET_TCPPORT,
+	ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT,
+	ANDROID_WIFI_CMD_WFD_SET_DEVTYPE,
+	ANDROID_WIFI_CMD_MAX
+};
+
+int rtw_android_cmdstr_to_num(char *cmdstr);
+int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
+
+#endif /* __RTW_ANDROID_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ap.h b/drivers/staging/rtl8188eu/include/rtw_ap.h
new file mode 100644
index 0000000..9233401
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ap.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_AP_H_
+#define __RTW_AP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#ifdef CONFIG_88EU_AP_MODE
+
+/* external function */
+void rtw_indicate_sta_assoc_event(struct adapter *padapter,
+				  struct sta_info *psta);
+void rtw_indicate_sta_disassoc_event(struct adapter *padapter,
+				     struct sta_info *psta);
+void init_mlme_ap_info(struct adapter *padapter);
+void free_mlme_ap_info(struct adapter *padapter);
+void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork,
+		    u8 index, u8 *data, u8 len);
+void rtw_remove_bcn_ie(struct adapter *padapter,
+		       struct wlan_bssid_ex *pnetwork, u8 index);
+void update_beacon(struct adapter *padapter, u8 ie_id,
+		   u8 *oui, u8 tx);
+void add_RATid(struct adapter *padapter, struct sta_info *psta,
+	       u8 rssi_level);
+void expire_timeout_chk(struct adapter *padapter);
+void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta);
+int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf,  int len);
+void rtw_set_macaddr_acl(struct adapter *padapter, int mode);
+int rtw_acl_add_sta(struct adapter *padapter, u8 *addr);
+int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr);
+
+#ifdef CONFIG_88EU_AP_MODE
+void associated_clients_update(struct adapter *padapter, u8 updated);
+void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta);
+u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta);
+void sta_info_update(struct adapter *padapter, struct sta_info *psta);
+void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta);
+u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta,
+	       bool active, u16 reason);
+int rtw_sta_flush(struct adapter *padapter);
+int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset);
+void start_ap_mode(struct adapter *padapter);
+void stop_ap_mode(struct adapter *padapter);
+#endif
+#endif /* end of CONFIG_88EU_AP_MODE */
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_br_ext.h b/drivers/staging/rtl8188eu/include/rtw_br_ext.h
new file mode 100644
index 0000000..f21e7a4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_br_ext.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_BR_EXT_H_
+#define _RTW_BR_EXT_H_
+
+#define MACADDRLEN		6
+#define _DEBUG_ERR		DBG_88E
+#define _DEBUG_INFO		DBG_88E
+#define DEBUG_WARN		DBG_88E
+#define DEBUG_INFO		DBG_88E
+#define DEBUG_ERR		DBG_88E
+#define GET_MY_HWADDR(padapter)		((padapter)->eeprompriv.mac_addr)
+
+#define NAT25_HASH_BITS		4
+#define NAT25_HASH_SIZE		(1 << NAT25_HASH_BITS)
+#define NAT25_AGEING_TIME	300
+
+#define MAX_NETWORK_ADDR_LEN	17
+
+struct nat25_network_db_entry {
+	struct nat25_network_db_entry	*next_hash;
+	struct nat25_network_db_entry	**pprev_hash;
+	atomic_t	use_count;
+	unsigned char	macAddr[6];
+	unsigned long	ageing_timer;
+	unsigned char	networkAddr[MAX_NETWORK_ADDR_LEN];
+};
+
+enum NAT25_METHOD {
+	NAT25_MIN,
+	NAT25_CHECK,
+	NAT25_INSERT,
+	NAT25_LOOKUP,
+	NAT25_PARSE,
+	NAT25_MAX
+};
+
+struct br_ext_info {
+	unsigned int	nat25_disable;
+	unsigned int	macclone_enable;
+	unsigned int	dhcp_bcst_disable;
+	int	addPPPoETag;		/* 1: Add PPPoE relay-SID, 0: disable */
+	unsigned char	nat25_dmzMac[MACADDRLEN];
+	unsigned int	nat25sc_disable;
+};
+
+void nat25_db_cleanup(struct adapter *priv);
+
+#endif /*  _RTW_BR_EXT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_cmd.h b/drivers/staging/rtl8188eu/include/rtw_cmd.h
new file mode 100644
index 0000000..819285b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_cmd.h
@@ -0,0 +1,991 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_CMD_H_
+#define __RTW_CMD_H_
+
+#include <wlan_bssdef.h>
+#include <rtw_rf.h>
+#include <rtw_led.h>
+
+#define C2H_MEM_SZ (16*1024)
+
+#include <osdep_service.h>
+#include <ieee80211.h> /*  <ieee80211/ieee80211.h> */
+
+#define FREE_CMDOBJ_SZ	128
+
+#define MAX_CMDSZ	1024
+#define MAX_RSPSZ	512
+#define MAX_EVTSZ	1024
+
+#define CMDBUFF_ALIGN_SZ 512
+
+struct cmd_obj {
+	struct adapter *padapter;
+	u16	cmdcode;
+	u8	res;
+	u8	*parmbuf;
+	u32	cmdsz;
+	u8	*rsp;
+	u32	rspsz;
+	struct list_head list;
+};
+
+struct cmd_priv {
+	struct semaphore cmd_queue_sema;
+	struct semaphore terminate_cmdthread_sema;
+	struct __queue cmd_queue;
+	u8	cmd_seq;
+	u8	*cmd_buf;	/* shall be non-paged, and 4 bytes aligned */
+	u8	*cmd_allocated_buf;
+	u8	*rsp_buf;	/* shall be non-paged, and 4 bytes aligned */
+	u8	*rsp_allocated_buf;
+	u32	cmd_issued_cnt;
+	u32	cmd_done_cnt;
+	u32	rsp_cnt;
+	u8 cmdthd_running;
+	struct adapter *padapter;
+};
+
+struct	evt_priv {
+	struct work_struct c2h_wk;
+	bool c2h_wk_alive;
+	struct rtw_cbuf *c2h_queue;
+	#define C2H_QUEUE_MAX_LEN 10
+	ATOMIC_T event_seq;
+	u8	*evt_buf;	/* shall be non-paged, and 4 bytes aligned */
+	u8	*evt_allocated_buf;
+	u32	evt_done_cnt;
+};
+
+#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \
+do {\
+	_rtw_init_listhead(&pcmd->list);\
+	pcmd->cmdcode = code;\
+	pcmd->parmbuf = (u8 *)(pparm);\
+	pcmd->cmdsz = sizeof(*pparm);\
+	pcmd->rsp = NULL;\
+	pcmd->rspsz = 0;\
+} while (0)
+
+struct c2h_evt_hdr {
+	u8 id:4;
+	u8 plen:4;
+	u8 seq;
+	u8 payload[0];
+};
+
+#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen)
+
+u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv);
+void rtw_free_cmd_obj(struct cmd_obj *pcmd);
+
+int rtw_cmd_thread(void *context);
+
+u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv);
+void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv);
+
+u32 rtw_init_evt_priv(struct evt_priv *pevtpriv);
+void rtw_free_evt_priv(struct evt_priv *pevtpriv);
+void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv);
+void rtw_evt_notify_isr(struct evt_priv *pevtpriv);
+#ifdef CONFIG_88EU_P2P
+u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType);
+#endif /* CONFIG_88EU_P2P */
+
+enum rtw_drvextra_cmd_id {
+	NONE_WK_CID,
+	DYNAMIC_CHK_WK_CID,
+	DM_CTRL_WK_CID,
+	PBC_POLLING_WK_CID,
+	POWER_SAVING_CTRL_WK_CID,/* IPS,AUTOSuspend */
+	LPS_CTRL_WK_CID,
+	ANT_SELECT_WK_CID,
+	P2P_PS_WK_CID,
+	P2P_PROTO_WK_CID,
+	CHECK_HIQ_WK_CID,/* for softap mode, check hi queue if empty */
+	INTEl_WIDI_WK_CID,
+	C2H_WK_CID,
+	RTP_TIMER_CFG_WK_CID,
+	MAX_WK_CID
+};
+
+enum LPS_CTRL_TYPE {
+	LPS_CTRL_SCAN = 0,
+	LPS_CTRL_JOINBSS = 1,
+	LPS_CTRL_CONNECT = 2,
+	LPS_CTRL_DISCONNECT = 3,
+	LPS_CTRL_SPECIAL_PACKET = 4,
+	LPS_CTRL_LEAVE = 5,
+};
+
+enum RFINTFS {
+	SWSI,
+	HWSI,
+	HWPI,
+};
+
+/*
+Caller Mode: Infra, Ad-HoC(C)
+
+Notes: To enter USB suspend mode
+
+Command Mode
+
+*/
+struct usb_suspend_parm {
+	u32 action;/*  1: sleep, 0:resume */
+};
+
+/*
+Caller Mode: Infra, Ad-HoC
+
+Notes: To join a known BSS.
+
+Command-Event Mode
+
+*/
+
+/*
+Caller Mode: Infra, Ad-Hoc
+
+Notes: To join the specified bss
+
+Command Event Mode
+
+*/
+struct joinbss_parm {
+	struct wlan_bssid_ex network;
+};
+
+/*
+Caller Mode: Infra, Ad-HoC(C)
+
+Notes: To disconnect the current associated BSS
+
+Command Mode
+
+*/
+struct disconnect_parm {
+	u32 deauth_timeout_ms;
+};
+
+/*
+Caller Mode: AP, Ad-HoC(M)
+
+Notes: To create a BSS
+
+Command Mode
+*/
+struct createbss_parm {
+	struct wlan_bssid_ex network;
+};
+
+struct	setopmode_parm {
+	u8	mode;
+	u8	rsvd[3];
+};
+
+/*
+Caller Mode: AP, Ad-HoC, Infra
+
+Notes: To ask RTL8711 performing site-survey
+
+Command-Event Mode
+
+*/
+
+#define RTW_SSID_SCAN_AMOUNT 9 /*  for WEXT_CSCAN_AMOUNT 9 */
+#define RTW_CHANNEL_SCAN_AMOUNT (14+37)
+struct sitesurvey_parm {
+	int scan_mode;	/* active: 1, passive: 0 */
+	u8 ssid_num;
+	u8 ch_num;
+	struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+	struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To set the auth type of RTL8711. open/shared/802.1x
+
+Command Mode
+
+*/
+struct setauth_parm {
+	u8 mode;  /* 0: legacy open, 1: legacy shared 2: 802.1x */
+	u8 _1x;   /* 0: PSK, 1: TLS */
+	u8 rsvd[2];
+};
+
+/*
+Caller Mode: Infra
+
+a. algorithm: wep40, wep104, tkip & aes
+b. keytype: grp key/unicast key
+c. key contents
+
+when shared key ==> keyid is the camid
+when 802.1x ==> keyid [0:1] ==> grp key
+when 802.1x ==> keyid > 2 ==> unicast key
+
+*/
+struct setkey_parm {
+	u8	algorithm;	/* could be none, wep40, TKIP, CCMP, wep104 */
+	u8	keyid;
+	u8	grpkey;		/* 1: this is the grpkey for 802.1x.
+				 * 0: this is the unicast key for 802.1x */
+	u8	set_tx;		/* 1: main tx key for wep. 0: other key. */
+	u8	key[16];	/* this could be 40 or 104 */
+};
+
+/*
+When in AP or Ad-Hoc mode, this is used to
+allocate an sw/hw entry for a newly associated sta.
+
+Command
+
+when shared key ==> algorithm/keyid
+
+*/
+struct set_stakey_parm {
+	u8	addr[ETH_ALEN];
+	u8	algorithm;
+	u8	id;/* currently for erasing cam entry if
+		    * algorithm == _NO_PRIVACY_ */
+	u8	key[16];
+};
+
+struct set_stakey_rsp {
+	u8	addr[ETH_ALEN];
+	u8	keyid;
+	u8	rsvd;
+};
+
+/*
+Caller Ad-Hoc/AP
+
+Command -Rsp(AID == CAMID) mode
+
+This is to force fw to add an sta_data entry per driver's request.
+
+FW will write an cam entry associated with it.
+
+*/
+struct set_assocsta_parm {
+	u8	addr[ETH_ALEN];
+};
+
+struct set_assocsta_rsp {
+	u8	cam_id;
+	u8	rsvd[3];
+};
+
+/*
+	Caller Ad-Hoc/AP
+
+	Command mode
+
+	This is to force fw to del an sta_data entry per driver's request
+
+	FW will invalidate the cam entry associated with it.
+
+*/
+struct del_assocsta_parm {
+	u8	addr[ETH_ALEN];
+};
+
+/*
+Caller Mode: AP/Ad-HoC(M)
+
+Notes: To notify fw that given staid has changed its power state
+
+Command Mode
+
+*/
+struct setstapwrstate_parm {
+	u8	staid;
+	u8	status;
+	u8	hwaddr[6];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To setup the basic rate of RTL8711
+
+Command Mode
+
+*/
+struct	setbasicrate_parm {
+	u8	basicrates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To read the current basic rate
+
+Command-Rsp Mode
+
+*/
+struct getbasicrate_parm {
+	u32 rsvd;
+};
+
+struct getbasicrate_rsp {
+	u8 basicrates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To setup the data rate of RTL8711
+
+Command Mode
+
+*/
+struct setdatarate_parm {
+	u8	mac_id;
+	u8	datarates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To read the current data rate
+
+Command-Rsp Mode
+
+*/
+struct getdatarate_parm {
+	u32 rsvd;
+
+};
+struct getdatarate_rsp {
+	u8 datarates[NumRates];
+};
+
+/*
+Caller Mode: Any
+AP: AP can use the info for the contents of beacon frame
+Infra: STA can use the info when sitesurveying
+Ad-HoC(M): Like AP
+Ad-HoC(C): Like STA
+
+Notes: To set the phy capability of the NIC
+
+Command Mode
+
+*/
+
+struct	setphyinfo_parm {
+	struct regulatory_class class_sets[NUM_REGULATORYS];
+	u8	status;
+};
+
+struct	getphyinfo_parm {
+	u32 rsvd;
+};
+
+struct	getphyinfo_rsp {
+	struct regulatory_class class_sets[NUM_REGULATORYS];
+	u8	status;
+};
+
+/*
+Caller Mode: Any
+
+Notes: To set the channel/modem/band
+This command will be used when channel/modem/band is changed.
+
+Command Mode
+
+*/
+struct	setphy_parm {
+	u8	rfchannel;
+	u8	modem;
+};
+
+/*
+Caller Mode: Any
+
+Notes: To get the current setting of channel/modem/band
+
+Command-Rsp Mode
+
+*/
+struct	getphy_parm {
+	u32 rsvd;
+
+};
+struct	getphy_rsp {
+	u8	rfchannel;
+	u8	modem;
+};
+
+struct readBB_parm {
+	u8	offset;
+};
+struct readBB_rsp {
+	u8	value;
+};
+
+struct readTSSI_parm {
+	u8	offset;
+};
+struct readTSSI_rsp {
+	u8	value;
+};
+
+struct writeBB_parm {
+	u8	offset;
+	u8	value;
+};
+
+struct readRF_parm {
+	u8	offset;
+};
+struct readRF_rsp {
+	u32	value;
+};
+
+struct writeRF_parm {
+	u32	offset;
+	u32	value;
+};
+
+struct getrfintfs_parm {
+	u8	rfintfs;
+};
+
+struct Tx_Beacon_param
+{
+	struct wlan_bssid_ex network;
+};
+
+/*
+	Notes: This command is used for H2C/C2H loopback testing
+
+	mac[0] == 0
+	==> CMD mode, return H2C_SUCCESS.
+	The following condition must be ture under CMD mode
+		mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0;
+		s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7;
+		s2 == (b1 << 8 | b0);
+
+	mac[0] == 1
+	==> CMD_RSP mode, return H2C_SUCCESS_RSP
+
+	The rsp layout shall be:
+	rsp:			parm:
+		mac[0]  =   mac[5];
+		mac[1]  =   mac[4];
+		mac[2]  =   mac[3];
+		mac[3]  =   mac[2];
+		mac[4]  =   mac[1];
+		mac[5]  =   mac[0];
+		s0		=   s1;
+		s1		=   swap16(s0);
+		w0		=	swap32(w1);
+		b0		=	b1
+		s2		=	s0 + s1
+		b1		=	b0
+		w1		=	w0
+
+	mac[0] ==	2
+	==> CMD_EVENT mode, return	H2C_SUCCESS
+	The event layout shall be:
+	event:			parm:
+		mac[0]  =   mac[5];
+		mac[1]  =   mac[4];
+		mac[2]  =   event's seq no, starting from 1 to parm's marc[3]
+		mac[3]  =   mac[2];
+		mac[4]  =   mac[1];
+		mac[5]  =   mac[0];
+		s0		=   swap16(s0) - event.mac[2];
+		s1		=   s1 + event.mac[2];
+		w0		=	swap32(w0);
+		b0		=	b1
+		s2		=	s0 + event.mac[2]
+		b1		=	b0
+		w1		=	swap32(w1) - event.mac[2];
+
+		parm->mac[3] is the total event counts that host requested.
+	event will be the same with the cmd's param.
+*/
+
+/*  CMD param Format for driver extra cmd handler */
+struct drvextra_cmd_parm {
+	int ec_id; /* extra cmd id */
+	int type_size; /*  Can use this field as the type id or command size */
+	unsigned char *pbuf;
+};
+
+/*------------------- Below are used for RF/BB tunning ---------------------*/
+
+struct	setantenna_parm {
+	u8	tx_antset;
+	u8	rx_antset;
+	u8	tx_antenna;
+	u8	rx_antenna;
+};
+
+struct	enrateadaptive_parm {
+	u32	en;
+};
+
+struct settxagctbl_parm {
+	u32	txagc[MAX_RATES_LENGTH];
+};
+
+struct gettxagctbl_parm {
+	u32 rsvd;
+};
+struct gettxagctbl_rsp {
+	u32	txagc[MAX_RATES_LENGTH];
+};
+
+struct setagcctrl_parm {
+	u32	agcctrl;		/*  0: pure hw, 1: fw */
+};
+
+struct setssup_parm	{
+	u32	ss_ForceUp[MAX_RATES_LENGTH];
+};
+
+struct getssup_parm	{
+	u32 rsvd;
+};
+
+struct getssup_rsp	{
+	u8	ss_ForceUp[MAX_RATES_LENGTH];
+};
+
+struct setssdlevel_parm	{
+	u8	ss_DLevel[MAX_RATES_LENGTH];
+};
+
+struct getssdlevel_parm	{
+	u32 rsvd;
+};
+
+struct getssdlevel_rsp	{
+	u8	ss_DLevel[MAX_RATES_LENGTH];
+};
+
+struct setssulevel_parm	{
+	u8	ss_ULevel[MAX_RATES_LENGTH];
+};
+
+struct getssulevel_parm	{
+	u32 rsvd;
+};
+
+struct getssulevel_rsp	{
+	u8	ss_ULevel[MAX_RATES_LENGTH];
+};
+
+struct	setcountjudge_parm {
+	u8	count_judge[MAX_RATES_LENGTH];
+};
+
+struct	getcountjudge_parm {
+	u32 rsvd;
+};
+
+struct	getcountjudge_rsp {
+	u8	count_judge[MAX_RATES_LENGTH];
+};
+
+struct setratable_parm {
+	u8 ss_ForceUp[NumRates];
+	u8 ss_ULevel[NumRates];
+	u8 ss_DLevel[NumRates];
+	u8 count_judge[NumRates];
+};
+
+struct getratable_parm {
+                uint rsvd;
+};
+
+struct getratable_rsp {
+        u8 ss_ForceUp[NumRates];
+        u8 ss_ULevel[NumRates];
+        u8 ss_DLevel[NumRates];
+        u8 count_judge[NumRates];
+};
+
+/* to get TX,RX retry count */
+
+struct gettxretrycnt_parm {
+	unsigned int rsvd;
+};
+
+struct gettxretrycnt_rsp {
+	unsigned long tx_retrycnt;
+};
+
+struct getrxretrycnt_parm {
+	unsigned int rsvd;
+};
+
+struct getrxretrycnt_rsp {
+	unsigned long rx_retrycnt;
+};
+
+/* to get BCNOK,BCNERR count */
+struct getbcnokcnt_parm {
+	unsigned int rsvd;
+};
+
+struct getbcnokcnt_rsp {
+	unsigned long  bcnokcnt;
+};
+
+struct getbcnerrcnt_parm {
+	unsigned int rsvd;
+};
+
+struct getbcnerrcnt_rsp {
+	unsigned long bcnerrcnt;
+};
+
+/*  to get current TX power level */
+struct getcurtxpwrlevel_parm {
+	unsigned int rsvd;
+};
+struct getcurtxpwrlevel_rspi {
+	unsigned short tx_power;
+};
+
+struct setprobereqextraie_parm {
+	unsigned char e_id;
+	unsigned char ie_len;
+	unsigned char ie[0];
+};
+
+struct setassocreqextraie_parm {
+	unsigned char e_id;
+	unsigned char ie_len;
+	unsigned char ie[0];
+};
+
+struct setproberspextraie_parm {
+	unsigned char e_id;
+	unsigned char ie_len;
+	unsigned char ie[0];
+};
+
+struct setassocrspextraie_parm {
+	unsigned char e_id;
+	unsigned char ie_len;
+	unsigned char ie[0];
+};
+
+struct addBaReq_parm {
+	unsigned int tid;
+	u8	addr[ETH_ALEN];
+};
+
+/*H2C Handler index: 46 */
+struct set_ch_parm {
+	u8 ch;
+	u8 bw;
+	u8 ch_offset;
+};
+
+/*H2C Handler index: 59 */
+struct SetChannelPlan_param
+{
+	u8 channel_plan;
+};
+
+/*H2C Handler index: 60 */
+struct LedBlink_param
+{
+	struct LED_871x *pLed;
+};
+
+/*H2C Handler index: 61 */
+struct SetChannelSwitch_param
+{
+	u8 new_ch_no;
+};
+
+/*H2C Handler index: 62 */
+struct TDLSoption_param
+{
+	u8 addr[ETH_ALEN];
+	u8 option;
+};
+
+#define GEN_CMD_CODE(cmd)	cmd ## _CMD_
+
+/*
+
+Result:
+0x00: success
+0x01: sucess, and check Response.
+0x02: cmd ignored due to duplicated sequcne number
+0x03: cmd dropped due to invalid cmd code
+0x04: reserved.
+
+*/
+
+#define H2C_RSP_OFFSET		512
+
+#define H2C_SUCCESS		0x00
+#define H2C_SUCCESS_RSP		0x01
+#define H2C_DUPLICATED		0x02
+#define H2C_DROPPED		0x03
+#define H2C_PARAMETERS_ERROR	0x04
+#define H2C_REJECTED		0x05
+#define H2C_CMD_OVERFLOW	0x06
+#define H2C_RESERVED		0x07
+
+u8 rtw_setassocsta_cmd(struct adapter  *padapter, u8 *mac_addr);
+u8 rtw_setstandby_cmd(struct adapter *padapter, uint action);
+u8 rtw_sitesurvey_cmd(struct adapter  *padapter, struct ndis_802_11_ssid *ssid,
+		      int ssid_num, struct rtw_ieee80211_channel *ch,
+		      int ch_num);
+u8 rtw_createbss_cmd(struct adapter  *padapter);
+u8 rtw_createbss_cmd_ex(struct adapter  *padapter, unsigned char *pbss,
+			       unsigned int sz);
+u8 rtw_setphy_cmd(struct adapter  *padapter, u8 modem, u8 ch);
+u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key);
+u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue);
+u8 rtw_joinbss_cmd(struct adapter  *padapter, struct wlan_network* pnetwork);
+u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue);
+u8 rtw_setopmode_cmd(struct adapter  *padapter, enum ndis_802_11_network_infra networktype);
+u8 rtw_setdatarate_cmd(struct adapter  *padapter, u8 *rateset);
+u8 rtw_setbasicrate_cmd(struct adapter  *padapter, u8 *rateset);
+u8 rtw_setbbreg_cmd(struct adapter * padapter, u8 offset, u8 val);
+u8 rtw_setrfreg_cmd(struct adapter * padapter, u8 offset, u32 val);
+u8 rtw_getbbreg_cmd(struct adapter * padapter, u8 offset, u8 * pval);
+u8 rtw_getrfreg_cmd(struct adapter * padapter, u8 offset, u8 * pval);
+u8 rtw_setrfintfs_cmd(struct adapter  *padapter, u8 mode);
+u8 rtw_setrttbl_cmd(struct adapter  *padapter, struct setratable_parm *prate_table);
+u8 rtw_getrttbl_cmd(struct adapter  *padapter, struct getratable_rsp *pval);
+
+u8 rtw_gettssi_cmd(struct adapter  *padapter, u8 offset,u8 *pval);
+u8 rtw_setfwdig_cmd(struct adapter*padapter, u8 type);
+u8 rtw_setfwra_cmd(struct adapter*padapter, u8 type);
+
+u8 rtw_addbareq_cmd(struct adapter*padapter, u8 tid, u8 *addr);
+
+u8 rtw_dynamic_chk_wk_cmd(struct adapter *adapter);
+
+u8 rtw_lps_ctrl_wk_cmd(struct adapter*padapter, u8 lps_ctrl_type, u8 enqueue);
+u8 rtw_rpt_timer_cfg_cmd(struct adapter*padapter, u16 minRptTime);
+
+ u8 rtw_antenna_select_cmd(struct adapter*padapter, u8 antenna,u8 enqueue);
+u8 rtw_ps_cmd(struct adapter*padapter);
+
+#ifdef CONFIG_88EU_AP_MODE
+u8 rtw_chk_hi_queue_cmd(struct adapter*padapter);
+#endif
+
+u8 rtw_set_ch_cmd(struct adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue);
+u8 rtw_set_chplan_cmd(struct adapter*padapter, u8 chplan, u8 enqueue);
+u8 rtw_led_blink_cmd(struct adapter*padapter, struct LED_871x * pLed);
+u8 rtw_set_csa_cmd(struct adapter*padapter, u8 new_ch_no);
+u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option);
+
+u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt);
+
+u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf);
+
+void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd);
+void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd);
+void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd);
+void rtw_createbss_cmd_callback(struct adapter *adapt, struct cmd_obj *pcmd);
+void rtw_getbbrfreg_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+void rtw_readtssi_cmdrsp_callback(struct adapter *adapt,  struct cmd_obj *cmd);
+
+void rtw_setstaKey_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+void rtw_setassocsta_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cm);
+void rtw_getrttbl_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd);
+
+struct _cmd_callback {
+	u32	cmd_code;
+	void (*callback)(struct adapter  *padapter, struct cmd_obj *cmd);
+};
+
+enum rtw_h2c_cmd {
+	GEN_CMD_CODE(_Read_MACREG),	/*0*/
+	GEN_CMD_CODE(_Write_MACREG),
+	GEN_CMD_CODE(_Read_BBREG),
+	GEN_CMD_CODE(_Write_BBREG),
+	GEN_CMD_CODE(_Read_RFREG),
+	GEN_CMD_CODE(_Write_RFREG), /*5*/
+	GEN_CMD_CODE(_Read_EEPROM),
+	GEN_CMD_CODE(_Write_EEPROM),
+	GEN_CMD_CODE(_Read_EFUSE),
+	GEN_CMD_CODE(_Write_EFUSE),
+
+	GEN_CMD_CODE(_Read_CAM),	/*10*/
+	GEN_CMD_CODE(_Write_CAM),
+	GEN_CMD_CODE(_setBCNITV),
+	GEN_CMD_CODE(_setMBIDCFG),
+	GEN_CMD_CODE(_JoinBss),   /*14*/
+	GEN_CMD_CODE(_DisConnect), /*15*/
+	GEN_CMD_CODE(_CreateBss),
+	GEN_CMD_CODE(_SetOpMode),
+	GEN_CMD_CODE(_SiteSurvey),  /*18*/
+	GEN_CMD_CODE(_SetAuth),
+
+	GEN_CMD_CODE(_SetKey),	/*20*/
+	GEN_CMD_CODE(_SetStaKey),
+	GEN_CMD_CODE(_SetAssocSta),
+	GEN_CMD_CODE(_DelAssocSta),
+	GEN_CMD_CODE(_SetStaPwrState),
+	GEN_CMD_CODE(_SetBasicRate), /*25*/
+	GEN_CMD_CODE(_GetBasicRate),
+	GEN_CMD_CODE(_SetDataRate),
+	GEN_CMD_CODE(_GetDataRate),
+	GEN_CMD_CODE(_SetPhyInfo),
+
+	GEN_CMD_CODE(_GetPhyInfo),	/*30*/
+	GEN_CMD_CODE(_SetPhy),
+	GEN_CMD_CODE(_GetPhy),
+	GEN_CMD_CODE(_readRssi),
+	GEN_CMD_CODE(_readGain),
+	GEN_CMD_CODE(_SetAtim), /*35*/
+	GEN_CMD_CODE(_SetPwrMode),
+	GEN_CMD_CODE(_JoinbssRpt),
+	GEN_CMD_CODE(_SetRaTable),
+	GEN_CMD_CODE(_GetRaTable),
+
+	GEN_CMD_CODE(_GetCCXReport), /*40*/
+	GEN_CMD_CODE(_GetDTMReport),
+	GEN_CMD_CODE(_GetTXRateStatistics),
+	GEN_CMD_CODE(_SetUsbSuspend),
+	GEN_CMD_CODE(_SetH2cLbk),
+	GEN_CMD_CODE(_AddBAReq), /*45*/
+	GEN_CMD_CODE(_SetChannel), /*46*/
+	GEN_CMD_CODE(_SetTxPower),
+	GEN_CMD_CODE(_SwitchAntenna),
+	GEN_CMD_CODE(_SetCrystalCap),
+	GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/
+
+	GEN_CMD_CODE(_SetSingleToneTx),/*51*/
+	GEN_CMD_CODE(_SetCarrierSuppressionTx),
+	GEN_CMD_CODE(_SetContinuousTx),
+	GEN_CMD_CODE(_SwitchBandwidth), /*54*/
+	GEN_CMD_CODE(_TX_Beacon), /*55*/
+
+	GEN_CMD_CODE(_Set_MLME_EVT), /*56*/
+	GEN_CMD_CODE(_Set_Drv_Extra), /*57*/
+	GEN_CMD_CODE(_Set_H2C_MSG), /*58*/
+
+	GEN_CMD_CODE(_SetChannelPlan), /*59*/
+	GEN_CMD_CODE(_LedBlink), /*60*/
+
+	GEN_CMD_CODE(_SetChannelSwitch), /*61*/
+	GEN_CMD_CODE(_TDLS), /*62*/
+
+	MAX_H2CCMD
+};
+
+#define _GetBBReg_CMD_		_Read_BBREG_CMD_
+#define _SetBBReg_CMD_		_Write_BBREG_CMD_
+#define _GetRFReg_CMD_		_Read_RFREG_CMD_
+#define _SetRFReg_CMD_		_Write_RFREG_CMD_
+
+#ifdef _RTW_CMD_C_
+static struct _cmd_callback	rtw_cmd_callback[] =
+{
+	{GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/
+	{GEN_CMD_CODE(_Write_MACREG), NULL},
+	{GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback},
+	{GEN_CMD_CODE(_Write_BBREG), NULL},
+	{GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback},
+	{GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/
+	{GEN_CMD_CODE(_Read_EEPROM), NULL},
+	{GEN_CMD_CODE(_Write_EEPROM), NULL},
+	{GEN_CMD_CODE(_Read_EFUSE), NULL},
+	{GEN_CMD_CODE(_Write_EFUSE), NULL},
+
+	{GEN_CMD_CODE(_Read_CAM),	NULL},	/*10*/
+	{GEN_CMD_CODE(_Write_CAM),	 NULL},
+	{GEN_CMD_CODE(_setBCNITV), NULL},
+	{GEN_CMD_CODE(_setMBIDCFG), NULL},
+	{GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback},  /*14*/
+	{GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/
+	{GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback},
+	{GEN_CMD_CODE(_SetOpMode), NULL},
+	{GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/
+	{GEN_CMD_CODE(_SetAuth), NULL},
+
+	{GEN_CMD_CODE(_SetKey), NULL},	/*20*/
+	{GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback},
+	{GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback},
+	{GEN_CMD_CODE(_DelAssocSta), NULL},
+	{GEN_CMD_CODE(_SetStaPwrState), NULL},
+	{GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/
+	{GEN_CMD_CODE(_GetBasicRate), NULL},
+	{GEN_CMD_CODE(_SetDataRate), NULL},
+	{GEN_CMD_CODE(_GetDataRate), NULL},
+	{GEN_CMD_CODE(_SetPhyInfo), NULL},
+
+	{GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/
+	{GEN_CMD_CODE(_SetPhy), NULL},
+	{GEN_CMD_CODE(_GetPhy), NULL},
+	{GEN_CMD_CODE(_readRssi), NULL},
+	{GEN_CMD_CODE(_readGain), NULL},
+	{GEN_CMD_CODE(_SetAtim), NULL}, /*35*/
+	{GEN_CMD_CODE(_SetPwrMode), NULL},
+	{GEN_CMD_CODE(_JoinbssRpt), NULL},
+	{GEN_CMD_CODE(_SetRaTable), NULL},
+	{GEN_CMD_CODE(_GetRaTable), NULL},
+
+	{GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/
+	{GEN_CMD_CODE(_GetDTMReport),	NULL},
+	{GEN_CMD_CODE(_GetTXRateStatistics), NULL},
+	{GEN_CMD_CODE(_SetUsbSuspend), NULL},
+	{GEN_CMD_CODE(_SetH2cLbk), NULL},
+	{GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/
+	{GEN_CMD_CODE(_SetChannel), NULL},		/*46*/
+	{GEN_CMD_CODE(_SetTxPower), NULL},
+	{GEN_CMD_CODE(_SwitchAntenna), NULL},
+	{GEN_CMD_CODE(_SetCrystalCap), NULL},
+	{GEN_CMD_CODE(_SetSingleCarrierTx), NULL},	/*50*/
+
+	{GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/
+	{GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL},
+	{GEN_CMD_CODE(_SetContinuousTx), NULL},
+	{GEN_CMD_CODE(_SwitchBandwidth), NULL},		/*54*/
+	{GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/
+
+	{GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/
+	{GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/
+	{GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/
+	{GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/
+	{GEN_CMD_CODE(_LedBlink), NULL},/*60*/
+
+	{GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/
+	{GEN_CMD_CODE(_TDLS), NULL},/*62*/
+};
+#endif
+
+#endif /*  _CMD_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_debug.h b/drivers/staging/rtl8188eu/include/rtw_debug.h
new file mode 100644
index 0000000..c6b193a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_debug.h
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_DEBUG_H__
+#define __RTW_DEBUG_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#define _drv_always_			1
+#define _drv_emerg_			2
+#define _drv_alert_			3
+#define _drv_crit_			4
+#define _drv_err_			5
+#define	_drv_warning_			6
+#define _drv_notice_			7
+#define _drv_info_			8
+#define	_drv_debug_			9
+
+
+#define _module_rtl871x_xmit_c_		BIT(0)
+#define _module_xmit_osdep_c_		BIT(1)
+#define _module_rtl871x_recv_c_		BIT(2)
+#define _module_recv_osdep_c_		BIT(3)
+#define _module_rtl871x_mlme_c_		BIT(4)
+#define _module_mlme_osdep_c_		BIT(5)
+#define _module_rtl871x_sta_mgt_c_	BIT(6)
+#define _module_rtl871x_cmd_c_		BIT(7)
+#define _module_cmd_osdep_c_		BIT(8)
+#define _module_rtl871x_io_c_		BIT(9)
+#define _module_io_osdep_c_		BIT(10)
+#define _module_os_intfs_c_		BIT(11)
+#define _module_rtl871x_security_c_	BIT(12)
+#define _module_rtl871x_eeprom_c_	BIT(13)
+#define _module_hal_init_c_		BIT(14)
+#define _module_hci_hal_init_c_		BIT(15)
+#define _module_rtl871x_ioctl_c_	BIT(16)
+#define _module_rtl871x_ioctl_set_c_	BIT(17)
+#define _module_rtl871x_ioctl_query_c_	BIT(18)
+#define _module_rtl871x_pwrctrl_c_	BIT(19)
+#define _module_hci_intfs_c_		BIT(20)
+#define _module_hci_ops_c_		BIT(21)
+#define _module_osdep_service_c_	BIT(22)
+#define _module_mp_			BIT(23)
+#define _module_hci_ops_os_c_		BIT(24)
+#define _module_rtl871x_ioctl_os_c	BIT(25)
+#define _module_rtl8712_cmd_c_		BIT(26)
+#define	_module_rtl8192c_xmit_c_	BIT(27)
+#define _module_hal_xmit_c_		BIT(28)
+#define _module_efuse_			BIT(29)
+#define _module_rtl8712_recv_c_		BIT(30)
+#define _module_rtl8712_led_c_		BIT(31)
+
+#define DRIVER_PREFIX	"R8188EU: "
+
+extern u32 GlobalDebugLevel;
+
+#define DBG_88E_LEVEL(_level, fmt, arg...)				\
+	do {								\
+		if (_level <= GlobalDebugLevel)				\
+			pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg);	\
+	} while (0)
+
+#define DBG_88E(...)							\
+	do {								\
+		if (_drv_err_ <= GlobalDebugLevel)			\
+			pr_info(DRIVER_PREFIX __VA_ARGS__);		\
+	} while (0)
+
+#define MSG_88E(...)							\
+	do {								\
+		if (_drv_err_ <= GlobalDebugLevel)			\
+			pr_info(DRIVER_PREFIX __VA_ARGS__);			\
+	} while (0)
+
+#define RT_TRACE(_comp, _level, fmt)					\
+	do {								\
+		if (_level <= GlobalDebugLevel) {			\
+			pr_info("%s [0x%08x,%d]", DRIVER_PREFIX,	\
+				 (unsigned int)_comp, _level);		\
+			pr_info fmt;					\
+		}							\
+	} while (0)
+
+#define _func_enter_							\
+	do {								\
+		if (GlobalDebugLevel >= _drv_debug_)			\
+			pr_info("%s : %s enters at %d\n",		\
+				 DRIVER_PREFIX, __func__, __LINE__);	\
+	} while (0)
+
+#define _func_exit_							\
+	do {								\
+		if (GlobalDebugLevel >= _drv_debug_)			\
+			pr_info("%s : %s exits at %d\n",		\
+				 DRIVER_PREFIX, __func__, __LINE__);	\
+	} while (0)
+
+#define RT_PRINT_DATA(_comp, _level, _titlestring, _hexdata, _hexdatalen)\
+	do {								\
+		if (_level <= GlobalDebugLevel) {			\
+			int __i;					\
+			u8	*ptr = (u8 *)_hexdata;			\
+			pr_info("%s", DRIVER_PREFIX);			\
+			pr_info(_titlestring);				\
+			for (__i = 0; __i < (int)_hexdatalen; __i++ ) {	\
+				pr_info("%02X%s", ptr[__i],		\
+					 (((__i + 1) % 4) == 0) ?	\
+					 "  " : " ");	\
+				if (((__i + 1) % 16) == 0)		\
+					printk("\n");			\
+			}						\
+			printk("\n");					\
+		}							\
+	} while (0)
+
+int proc_get_drv_version(char *page, char **start,
+			 off_t offset, int count,
+			 int *eof, void *data);
+
+int proc_get_write_reg(char *page, char **start,
+		       off_t offset, int count,
+		       int *eof, void *data);
+
+int proc_set_write_reg(struct file *file, const char __user *buffer,
+		       unsigned long count, void *data);
+int proc_get_read_reg(char *page, char **start,
+		      off_t offset, int count,
+		      int *eof, void *data);
+
+int proc_set_read_reg(struct file *file, const char __user *buffer,
+		      unsigned long count, void *data);
+
+int proc_get_fwstate(char *page, char **start,
+		     off_t offset, int count,
+		     int *eof, void *data);
+int proc_get_sec_info(char *page, char **start,
+		      off_t offset, int count,
+		      int *eof, void *data);
+int proc_get_mlmext_state(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_qos_option(char *page, char **start,
+			off_t offset, int count,
+			int *eof, void *data);
+int proc_get_ht_option(char *page, char **start,
+		       off_t offset, int count,
+		       int *eof, void *data);
+int proc_get_rf_info(char *page, char **start,
+		     off_t offset, int count,
+		     int *eof, void *data);
+int proc_get_ap_info(char *page, char **start,
+		     off_t offset, int count,
+		     int *eof, void *data);
+
+int proc_get_adapter_state(char *page, char **start,
+			   off_t offset, int count,
+			   int *eof, void *data);
+
+int proc_get_trx_info(char *page, char **start,
+		      off_t offset, int count,
+		      int *eof, void *data);
+
+int proc_get_mac_reg_dump1(char *page, char **start,
+			   off_t offset, int count,
+			   int *eof, void *data);
+
+int proc_get_mac_reg_dump2(char *page, char **start,
+			   off_t offset, int count,
+			   int *eof, void *data);
+
+int proc_get_mac_reg_dump3(char *page, char **start,
+			   off_t offset, int count,
+			   int *eof, void *data);
+
+int proc_get_bb_reg_dump1(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_bb_reg_dump2(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_bb_reg_dump3(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_rf_reg_dump1(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_rf_reg_dump2(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_rf_reg_dump3(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_rf_reg_dump4(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+#ifdef CONFIG_88EU_AP_MODE
+
+int proc_get_all_sta_info(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+#endif
+
+int proc_get_best_channel(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_get_rx_signal(char *page, char **start,
+		       off_t offset, int count,
+		       int *eof, void *data);
+
+int proc_set_rx_signal(struct file *file, const char __user *buffer,
+		       unsigned long count, void *data);
+
+int proc_get_ht_enable(char *page, char **start,
+		       off_t offset, int count,
+		       int *eof, void *data);
+
+int proc_set_ht_enable(struct file *file, const char __user *buffer,
+		       unsigned long count, void *data);
+
+int proc_get_cbw40_enable(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_set_cbw40_enable(struct file *file, const char __user *buffer,
+			  unsigned long count, void *data);
+
+int proc_get_ampdu_enable(char *page, char **start,
+			  off_t offset, int count,
+			  int *eof, void *data);
+
+int proc_set_ampdu_enable(struct file *file, const char __user *buffer,
+			  unsigned long count, void *data);
+
+int proc_get_rx_stbc(char *page, char **start,
+		     off_t offset, int count,
+		     int *eof, void *data);
+
+int proc_set_rx_stbc(struct file *file, const char __user *buffer,
+		     unsigned long count, void *data);
+
+int proc_get_two_path_rssi(char *page, char **start,
+			   off_t offset, int count,
+			   int *eof, void *data);
+
+int proc_get_rssi_disp(char *page, char **start,
+		       off_t offset, int count,
+		       int *eof, void *data);
+
+int proc_set_rssi_disp(struct file *file, const char __user *buffer,
+		       unsigned long count, void *data);
+
+#ifdef CONFIG_BT_COEXIST
+int proc_get_btcoex_dbg(char *page, char **start,
+			off_t offset, int count,
+			int *eof, void *data);
+
+int proc_set_btcoex_dbg(struct file *file, const char *buffer,
+			signed long count, void *data);
+
+#endif /* CONFIG_BT_COEXIST */
+
+#endif	/* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_eeprom.h b/drivers/staging/rtl8188eu/include/rtw_eeprom.h
new file mode 100644
index 0000000..b2672c3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_eeprom.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_EEPROM_H__
+#define __RTW_EEPROM_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define	RTL8712_EEPROM_ID		0x8712
+
+#define	HWSET_MAX_SIZE_512		512
+#define	EEPROM_MAX_SIZE			HWSET_MAX_SIZE_512
+
+#define	CLOCK_RATE			50	/* 100us */
+
+/*  EEPROM opcodes */
+#define EEPROM_READ_OPCODE		06
+#define EEPROM_WRITE_OPCODE		05
+#define EEPROM_ERASE_OPCODE		07
+#define EEPROM_EWEN_OPCODE		19      /*  Erase/write enable */
+#define EEPROM_EWDS_OPCODE		16      /*  Erase/write disable */
+
+/* Country codes */
+#define USA				0x555320
+#define EUROPE				0x1 /* temp, should be provided later */
+#define JAPAN				0x2 /* temp, should be provided later */
+
+#define	EEPROM_CID_DEFAULT		0x0
+#define	EEPROM_CID_ALPHA		0x1
+#define	EEPROM_CID_Senao		0x3
+#define	EEPROM_CID_NetCore		0x5
+#define	EEPROM_CID_CAMEO		0X8
+#define	EEPROM_CID_SITECOM		0x9
+#define	EEPROM_CID_COREGA		0xB
+#define	EEPROM_CID_EDIMAX_BELK		0xC
+#define	EEPROM_CID_SERCOMM_BELK		0xE
+#define	EEPROM_CID_CAMEO1		0xF
+#define	EEPROM_CID_WNC_COREGA		0x12
+#define	EEPROM_CID_CLEVO		0x13
+#define	EEPROM_CID_WHQL			0xFE
+
+/*  Customer ID, note that: */
+/*  This variable is initiailzed through EEPROM or registry, */
+/*  however, its definition may be different with that in EEPROM for */
+/*  EEPROM size consideration. So, we have to perform proper translation
+ *  between them. */
+/*  Besides, CustomerID of registry has precedence of that of EEPROM. */
+/*  defined below. 060703, by rcnjko. */
+enum RT_CUSTOMER_ID {
+	RT_CID_DEFAULT = 0,
+	RT_CID_8187_ALPHA0 = 1,
+	RT_CID_8187_SERCOMM_PS = 2,
+	RT_CID_8187_HW_LED = 3,
+	RT_CID_8187_NETGEAR = 4,
+	RT_CID_WHQL = 5,
+	RT_CID_819x_CAMEO  = 6,
+	RT_CID_819x_RUNTOP = 7,
+	RT_CID_819x_Senao = 8,
+	RT_CID_TOSHIBA = 9,	/*  Merge by Jacken, 2008/01/31. */
+	RT_CID_819x_Netcore = 10,
+	RT_CID_Nettronix = 11,
+	RT_CID_DLINK = 12,
+	RT_CID_PRONET = 13,
+	RT_CID_COREGA = 14,
+	RT_CID_CHINA_MOBILE = 15,
+	RT_CID_819x_ALPHA = 16,
+	RT_CID_819x_Sitecom = 17,
+	RT_CID_CCX = 18, /*  It's set under CCX logo test and isn't demanded
+			  * for CCX functions, but for test behavior like retry
+			  * limit and tx report. By Bruce, 2009-02-17. */
+	RT_CID_819x_Lenovo = 19,
+	RT_CID_819x_QMI = 20,
+	RT_CID_819x_Edimax_Belkin = 21,
+	RT_CID_819x_Sercomm_Belkin = 22,
+	RT_CID_819x_CAMEO1 = 23,
+	RT_CID_819x_MSI = 24,
+	RT_CID_819x_Acer = 25,
+	RT_CID_819x_AzWave_ASUS = 26,
+	RT_CID_819x_AzWave = 27, /*  For AzWave in PCIe,i
+				  * The ID is AzWave use and not only Asus */
+	RT_CID_819x_HP = 28,
+	RT_CID_819x_WNC_COREGA = 29,
+	RT_CID_819x_Arcadyan_Belkin = 30,
+	RT_CID_819x_SAMSUNG = 31,
+	RT_CID_819x_CLEVO = 32,
+	RT_CID_819x_DELL = 33,
+	RT_CID_819x_PRONETS = 34,
+	RT_CID_819x_Edimax_ASUS = 35,
+	RT_CID_819x_CAMEO_NETGEAR = 36,
+	RT_CID_PLANEX = 37,
+	RT_CID_CC_C = 38,
+	RT_CID_819x_Xavi = 39,
+	RT_CID_819x_FUNAI_TV = 40,
+	RT_CID_819x_ALPHA_WD=41,
+};
+
+struct eeprom_priv {
+	u8		bautoload_fail_flag;
+	u8		bloadfile_fail_flag;
+	u8		bloadmac_fail_flag;
+	u8		mac_addr[6];	/* PermanentAddress */
+	u16		channel_plan;
+	u8		EepromOrEfuse;
+	u8		efuse_eeprom_data[HWSET_MAX_SIZE_512];
+};
+
+void eeprom_write16(struct adapter *padapter, u16 reg, u16 data);
+u16 eeprom_read16(struct adapter *padapter, u16 reg);
+void read_eeprom_content(struct adapter *padapter);
+void eeprom_read_sz(struct adapter *adapt, u16 reg, u8 *data, u32 sz);
+void read_eeprom_content_by_attrib(struct adapter *padapter);
+
+#endif  /* __RTL871X_EEPROM_H__ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_efuse.h b/drivers/staging/rtl8188eu/include/rtw_efuse.h
new file mode 100644
index 0000000..cee6b5e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_efuse.h
@@ -0,0 +1,150 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_EFUSE_H__
+#define __RTW_EFUSE_H__
+
+#include <osdep_service.h>
+
+#define	EFUSE_ERROE_HANDLE		1
+
+#define	PG_STATE_HEADER			0x01
+#define	PG_STATE_WORD_0		0x02
+#define	PG_STATE_WORD_1		0x04
+#define	PG_STATE_WORD_2		0x08
+#define	PG_STATE_WORD_3		0x10
+#define	PG_STATE_DATA			0x20
+
+#define	PG_SWBYTE_H			0x01
+#define	PG_SWBYTE_L			0x02
+
+#define	PGPKT_DATA_SIZE		8
+
+#define	EFUSE_WIFI				0
+#define	EFUSE_BT				1
+
+enum _EFUSE_DEF_TYPE {
+	TYPE_EFUSE_MAX_SECTION				= 0,
+	TYPE_EFUSE_REAL_CONTENT_LEN			= 1,
+	TYPE_AVAILABLE_EFUSE_BYTES_BANK		= 2,
+	TYPE_AVAILABLE_EFUSE_BYTES_TOTAL	= 3,
+	TYPE_EFUSE_MAP_LEN					= 4,
+	TYPE_EFUSE_PROTECT_BYTES_BANK		= 5,
+	TYPE_EFUSE_CONTENT_LEN_BANK			= 6,
+};
+
+/* E-Fuse */
+#define EFUSE_MAP_SIZE      512
+#define EFUSE_MAX_SIZE      256
+/* end of E-Fuse */
+
+#define		EFUSE_MAX_MAP_LEN		512
+#define		EFUSE_MAX_HW_SIZE		512
+#define		EFUSE_MAX_SECTION_BASE	16
+
+#define EXT_HEADER(header) ((header & 0x1F) == 0x0F)
+#define ALL_WORDS_DISABLED(wde)	((wde & 0x0F) == 0x0F)
+#define GET_HDR_OFFSET_2_0(header) ((header & 0xE0) >> 5)
+
+#define		EFUSE_REPEAT_THRESHOLD_			3
+
+/*	The following is for BT Efuse definition */
+#define		EFUSE_BT_MAX_MAP_LEN		1024
+#define		EFUSE_MAX_BANK			4
+#define		EFUSE_MAX_BT_BANK		(EFUSE_MAX_BANK-1)
+/*--------------------------Define Parameters-------------------------------*/
+#define		EFUSE_MAX_WORD_UNIT			4
+
+/*------------------------------Define structure----------------------------*/
+struct pgpkt {
+	u8 offset;
+	u8 word_en;
+	u8 data[8];
+	u8 word_cnts;
+};
+
+/*------------------------------Define structure----------------------------*/
+struct efuse_hal {
+	u8 fakeEfuseBank;
+	u32	fakeEfuseUsedBytes;
+	u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE];
+	u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN];
+	u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN];
+
+	u16 BTEfuseUsedBytes;
+	u8 BTEfuseUsedPercentage;
+	u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+	u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN];
+	u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN];
+
+	u16 fakeBTEfuseUsedBytes;
+	u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+	u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN];
+	u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN];
+};
+
+/*------------------------Export global variable----------------------------*/
+extern u8 fakeEfuseBank;
+extern u32 fakeEfuseUsedBytes;
+extern u8 fakeEfuseContent[];
+extern u8 fakeEfuseInitMap[];
+extern u8 fakeEfuseModifiedMap[];
+
+extern u32 BTEfuseUsedBytes;
+extern u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+extern u8 BTEfuseInitMap[];
+extern u8 BTEfuseModifiedMap[];
+
+extern u32 fakeBTEfuseUsedBytes;
+extern u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
+extern u8 fakeBTEfuseInitMap[];
+extern u8 fakeBTEfuseModifiedMap[];
+/*------------------------Export global variable----------------------------*/
+
+u8 efuse_GetCurrentSize(struct adapter *adapter, u16 *size);
+u16 efuse_GetMaxSize(struct adapter *adapter);
+u8 rtw_efuse_access(struct adapter *adapter, u8 read, u16 start_addr,
+		    u16 cnts, u8 *data);
+u8 rtw_efuse_map_read(struct adapter *adapter, u16 addr, u16 cnts, u8 *data);
+u8 rtw_efuse_map_write(struct adapter *adapter, u16 addr, u16 cnts, u8 *data);
+u8 rtw_BT_efuse_map_read(struct adapter *adapter, u16 addr,
+			 u16 cnts, u8 *data);
+u8 rtw_BT_efuse_map_write(struct adapter *adapter, u16 addr,
+			  u16 cnts, u8 *data);
+u16 Efuse_GetCurrentSize(struct adapter *adapter, u8 efusetype, bool test);
+u8 Efuse_CalculateWordCnts(u8 word_en);
+void ReadEFuseByte(struct adapter *adapter, u16 _offset, u8 *pbuf, bool test);
+void EFUSE_GetEfuseDefinition(struct adapter *adapt, u8 type, u8 type1,
+			      void *out, bool bPseudoTest);
+u8 efuse_OneByteRead(struct adapter *adapter, u16 addr, u8 *data, bool test);
+u8 efuse_OneByteWrite(struct adapter *adapter, u16 addr, u8 data, bool	test);
+
+void Efuse_PowerSwitch(struct adapter *adapt,u8 bWrite,u8  PwrState);
+int Efuse_PgPacketRead(struct adapter *adapt, u8 offset, u8 *data, bool test);
+int Efuse_PgPacketWrite(struct adapter *adapter, u8 offset, u8 word, u8 *data,
+			bool test);
+void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata);
+u8 Efuse_WordEnableDataWrite(struct adapter *adapter, u16 efuse_addr,
+			     u8 word_en, u8 *data, bool test);
+
+u8 EFUSE_Read1Byte(struct adapter *adapter, u16 address);
+void EFUSE_ShadowMapUpdate(struct adapter *adapter, u8 efusetype, bool test);
+void EFUSE_ShadowRead(struct adapter *adapt, u8 type, u16 offset, u32 *val);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_event.h b/drivers/staging/rtl8188eu/include/rtw_event.h
new file mode 100644
index 0000000..52151dc
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_event.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_EVENT_H_
+#define _RTW_EVENT_H_
+
+#include <osdep_service.h>
+
+#include <wlan_bssdef.h>
+#include <linux/semaphore.h>
+#include <linux/sem.h>
+
+/*
+Used to report a bss has been scanned
+*/
+struct survey_event	{
+	struct wlan_bssid_ex bss;
+};
+
+/*
+Used to report that the requested site survey has been done.
+
+bss_cnt indicates the number of bss that has been reported.
+
+
+*/
+struct surveydone_event {
+	unsigned int	bss_cnt;
+
+};
+
+/*
+Used to report the link result of joinning the given bss
+
+
+join_res:
+-1: authentication fail
+-2: association fail
+> 0: TID
+
+*/
+struct joinbss_event {
+	struct	wlan_network	network;
+};
+
+/*
+Used to report a given STA has joinned the created BSS.
+It is used in AP/Ad-HoC(M) mode.
+*/
+
+struct stassoc_event {
+	unsigned char macaddr[6];
+	unsigned char rsvd[2];
+	int    cam_id;
+};
+
+struct stadel_event {
+	unsigned char macaddr[6];
+	unsigned char rsvd[2]; /* for reason */
+	int mac_id;
+};
+
+struct addba_event {
+	unsigned int tid;
+};
+
+#define GEN_EVT_CODE(event)	event ## _EVT_
+
+struct fwevent {
+	u32	parmsize;
+	void (*event_callback)(struct adapter *dev, u8 *pbuf);
+};
+
+#define C2HEVENT_SZ			32
+
+struct event_node {
+	unsigned char *node;
+	unsigned char evt_code;
+	unsigned short evt_sz;
+	int	*caller_ff_tail;
+	int	caller_ff_sz;
+};
+
+struct c2hevent_queue {
+	int	head;
+	int	tail;
+	struct	event_node	nodes[C2HEVENT_SZ];
+	unsigned char	seq;
+};
+
+#define NETWORK_QUEUE_SZ	4
+
+struct network_queue {
+	int	head;
+	int	tail;
+	struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ];
+};
+
+#endif /*  _WLANEVENT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ht.h b/drivers/staging/rtl8188eu/include/rtw_ht.h
new file mode 100644
index 0000000..beb210b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ht.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_HT_H_
+#define _RTW_HT_H_
+
+#include <osdep_service.h>
+#include "wifi.h"
+
+struct ht_priv {
+	u32	ht_option;
+	u32	ampdu_enable;/* for enable Tx A-MPDU */
+	u32	tx_amsdu_enable;/* for enable Tx A-MSDU */
+	u32	tx_amdsu_maxlen; /*  1: 8k, 0:4k ; default:8k, for tx */
+	u32	rx_ampdu_maxlen; /* for rx reordering ctrl win_sz,
+				  * updated when join_callback. */
+	u8	bwmode;/*  */
+	u8	ch_offset;/* PRIME_CHNL_OFFSET */
+	u8	sgi;/* short GI */
+
+	/* for processing Tx A-MPDU */
+	u8	agg_enable_bitmap;
+	u8	candidate_tid_bitmap;
+
+	struct rtw_ieee80211_ht_cap ht_cap;
+};
+
+#endif	/* _RTL871X_HT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_io.h b/drivers/staging/rtl8188eu/include/rtw_io.h
new file mode 100644
index 0000000..eb6f0e5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_io.h
@@ -0,0 +1,387 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#ifndef _RTW_IO_H_
+#define _RTW_IO_H_
+
+#include <osdep_service.h>
+#include <osdep_intf.h>
+
+#include <asm/byteorder.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+
+#define rtw_usb_buffer_alloc(dev, size, dma)				\
+	usb_alloc_coherent((dev), (size), (in_interrupt() ?		\
+			   GFP_ATOMIC : GFP_KERNEL), (dma))
+#define rtw_usb_buffer_free(dev, size, addr, dma)			\
+	usb_free_coherent((dev), (size), (addr), (dma))
+
+#define NUM_IOREQ		8
+
+#define MAX_PROT_SZ	(64-16)
+
+#define _IOREADY		0
+#define _IO_WAIT_COMPLETE	1
+#define _IO_WAIT_RSP		2
+
+/*  IO COMMAND TYPE */
+#define _IOSZ_MASK_		(0x7F)
+#define _IO_WRITE_		BIT(7)
+#define _IO_FIXED_		BIT(8)
+#define _IO_BURST_		BIT(9)
+#define _IO_BYTE_		BIT(10)
+#define _IO_HW_			BIT(11)
+#define _IO_WORD_		BIT(12)
+#define _IO_SYNC_		BIT(13)
+#define _IO_CMDMASK_		(0x1F80)
+
+/*
+	For prompt mode accessing, caller shall free io_req
+	Otherwise, io_handler will free io_req
+*/
+
+/*  IO STATUS TYPE */
+#define _IO_ERR_		BIT(2)
+#define _IO_SUCCESS_		BIT(1)
+#define _IO_DONE_		BIT(0)
+
+#define IO_RD32			(_IO_SYNC_ | _IO_WORD_)
+#define IO_RD16			(_IO_SYNC_ | _IO_HW_)
+#define IO_RD8			(_IO_SYNC_ | _IO_BYTE_)
+
+#define IO_RD32_ASYNC		(_IO_WORD_)
+#define IO_RD16_ASYNC		(_IO_HW_)
+#define IO_RD8_ASYNC		(_IO_BYTE_)
+
+#define IO_WR32			(_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_)
+#define IO_WR16			(_IO_WRITE_ | _IO_SYNC_ | _IO_HW_)
+#define IO_WR8			(_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_)
+
+#define IO_WR32_ASYNC		(_IO_WRITE_ | _IO_WORD_)
+#define IO_WR16_ASYNC		(_IO_WRITE_ | _IO_HW_)
+#define IO_WR8_ASYNC		(_IO_WRITE_ | _IO_BYTE_)
+
+/*
+	Only Sync. burst accessing is provided.
+*/
+
+#define IO_WR_BURST(x)						\
+	(_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_))
+#define IO_RD_BURST(x)						\
+	(_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_))
+
+/* below is for the intf_option bit defition... */
+
+#define _INTF_ASYNC_	BIT(0)	/* support async io */
+
+struct intf_priv;
+struct intf_hdl;
+struct io_queue;
+
+struct _io_ops {
+	u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
+	u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr);
+	u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr);
+	int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+	int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+	int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+	int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length,
+		       u8 *pdata);
+	int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+	int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+	int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+	void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+			  u8 *pmem);
+	void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+			   u8 *pmem);
+	void (*_sync_irp_protocol_rw)(struct io_queue *pio_q);
+	u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr);
+	u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+			  u8 *pmem);
+	u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+			   u8 *pmem);
+	u32 (*_write_scsi)(struct intf_hdl *pintfhdl,u32 cnt, u8 *pmem);
+	void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
+	void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
+};
+
+struct io_req {
+	struct list_head list;
+	u32	addr;
+	u32	val;
+	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;
+};
+
+struct	intf_hdl {
+	struct adapter *padapter;
+	struct dvobj_priv *pintf_dev;
+	struct _io_ops	io_ops;
+};
+
+struct reg_protocol_rd {
+#ifdef __LITTLE_ENDIAN
+	/* DW1 */
+	u32		NumOfTrans:4;
+	u32		Reserved1:4;
+	u32		Reserved2:24;
+	/* DW2 */
+	u32		ByteCount:7;
+	u32		WriteEnable:1;		/* 0:read, 1:write */
+	u32		FixOrContinuous:1;	/* 0:continuous, 1: Fix */
+	u32		BurstMode:1;
+	u32		Byte1Access:1;
+	u32		Byte2Access:1;
+	u32		Byte4Access:1;
+	u32		Reserved3:3;
+	u32		Reserved4:16;
+	/* DW3 */
+	u32		BusAddress;
+	/* DW4 */
+	/* u32		Value; */
+#else
+/* DW1 */
+	u32 Reserved1:4;
+	u32 NumOfTrans:4;
+	u32 Reserved2:24;
+	/* DW2 */
+	u32 WriteEnable:1;
+	u32 ByteCount:7;
+	u32 Reserved3:3;
+	u32 Byte4Access:1;
+
+	u32 Byte2Access:1;
+	u32 Byte1Access:1;
+	u32 BurstMode:1;
+	u32 FixOrContinuous:1;
+	u32 Reserved4:16;
+	/* DW3 */
+	u32	BusAddress;
+
+	/* DW4 */
+#endif
+};
+
+struct reg_protocol_wt {
+#ifdef __LITTLE_ENDIAN
+	/* DW1 */
+	u32	NumOfTrans:4;
+	u32	Reserved1:4;
+	u32	Reserved2:24;
+	/* DW2 */
+	u32	ByteCount:7;
+	u32	WriteEnable:1;		/* 0:read, 1:write */
+	u32	FixOrContinuous:1;	/* 0:continuous, 1: Fix */
+	u32	BurstMode:1;
+	u32	Byte1Access:1;
+	u32	Byte2Access:1;
+	u32	Byte4Access:1;
+	u32	Reserved3:3;
+	u32	Reserved4:16;
+	/* DW3 */
+	u32	BusAddress;
+	/* DW4 */
+	u32	Value;
+#else
+	/* DW1 */
+	u32 Reserved1 :4;
+	u32 NumOfTrans:4;
+	u32 Reserved2:24;
+	/* DW2 */
+	u32 WriteEnable:1;
+	u32 ByteCount:7;
+	u32 Reserved3:3;
+	u32 Byte4Access:1;
+	u32 Byte2Access:1;
+	u32 Byte1Access:1;
+	u32 BurstMode:1;
+	u32 FixOrContinuous:1;
+	u32 Reserved4:16;
+	/* DW3 */
+	u32	BusAddress;
+	/* DW4 */
+	u32	Value;
+#endif
+};
+
+/*
+Below is the data structure used by _io_handler
+*/
+
+struct io_queue {
+	spinlock_t lock;
+	struct list_head free_ioreqs;
+	struct list_head pending;	/* The io_req list that will be served
+					 * in the single protocol read/write.*/
+	struct list_head processing;
+	u8	*free_ioreqs_buf; /*  4-byte aligned */
+	u8	*pallocated_free_ioreqs_buf;
+	struct	intf_hdl	intf;
+};
+
+struct io_priv {
+	struct adapter *padapter;
+	struct intf_hdl intf;
+};
+
+uint ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
+void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue);
+uint sync_ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue);
+uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue);
+struct io_req *alloc_ioreq(struct io_queue *pio_q);
+
+uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl);
+void unregister_intf_hdl(struct intf_hdl *pintfhdl);
+
+void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+u8 _rtw_read8(struct adapter *adapter, u32 addr);
+u16 _rtw_read16(struct adapter *adapter, u32 addr);
+u32 _rtw_read32(struct adapter *adapter, u32 addr);
+void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_read_port_cancel(struct adapter *adapter);
+
+int _rtw_write8(struct adapter *adapter, u32 addr, u8 val);
+int _rtw_write16(struct adapter *adapter, u32 addr, u16 val);
+int _rtw_write32(struct adapter *adapter, u32 addr, u32 val);
+int _rtw_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata);
+
+int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val);
+int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val);
+int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val);
+
+void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt,
+			     u8 *pmem, int timeout_ms);
+void _rtw_write_port_cancel(struct adapter *adapter);
+
+#define rtw_read8(adapter, addr) _rtw_read8((adapter), (addr))
+#define rtw_read16(adapter, addr) _rtw_read16((adapter), (addr))
+#define rtw_read32(adapter, addr) _rtw_read32((adapter), (addr))
+#define rtw_read_mem(adapter, addr, cnt, mem)				\
+	_rtw_read_mem((adapter), (addr), (cnt), (mem))
+#define rtw_read_port(adapter, addr, cnt, mem)				\
+	_rtw_read_port((adapter), (addr), (cnt), (mem))
+#define rtw_read_port_cancel(adapter) _rtw_read_port_cancel((adapter))
+
+#define  rtw_write8(adapter, addr, val)					\
+	_rtw_write8((adapter), (addr), (val))
+#define  rtw_write16(adapter, addr, val)				\
+	_rtw_write16((adapter), (addr), (val))
+#define  rtw_write32(adapter, addr, val)				\
+	_rtw_write32((adapter), (addr), (val))
+#define  rtw_writeN(adapter, addr, length, data)			\
+	_rtw_writeN((adapter), (addr), (length), (data))
+#define rtw_write8_async(adapter, addr, val)				\
+	_rtw_write8_async((adapter), (addr), (val))
+#define rtw_write16_async(adapter, addr, val)				\
+	_rtw_write16_async((adapter), (addr), (val))
+#define rtw_write32_async(adapter, addr, val)				\
+	_rtw_write32_async((adapter), (addr), (val))
+#define rtw_write_mem(adapter, addr, cnt, mem)				\
+	_rtw_write_mem((adapter), (addr), (cnt), (mem))
+#define rtw_write_port(adapter, addr, cnt, mem)				\
+	_rtw_write_port((adapter), (addr), (cnt), (mem))
+#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms)	\
+	_rtw_write_port_and_wait((adapter), (addr), (cnt), (mem), (timeout_ms))
+#define rtw_write_port_cancel(adapter) _rtw_write_port_cancel((adapter))
+
+void rtw_write_scsi(struct adapter *adapter, u32 cnt, u8 *pmem);
+
+/* ioreq */
+void ioreq_read8(struct adapter *adapter, u32 addr, u8 *pval);
+void ioreq_read16(struct adapter *adapter, u32 addr, u16 *pval);
+void ioreq_read32(struct adapter *adapter, u32 addr, u32 *pval);
+void ioreq_write8(struct adapter *adapter, u32 addr, u8 val);
+void ioreq_write16(struct adapter *adapter, u32 addr, u16 val);
+void ioreq_write32(struct adapter *adapter, u32 addr, u32 val);
+
+uint async_read8(struct adapter *adapter, u32 addr, u8 *pbuff,
+		 void (*_async_io_callback)(struct adapter *padater,
+					    struct io_req *pio_req,
+					    u8 *cnxt), u8 *cnxt);
+uint async_read16(struct adapter *adapter, u32 addr,  u8 *pbuff,
+		  void (*_async_io_callback)(struct adapter *padater,
+					     struct io_req *pio_req,
+					     u8 *cnxt), u8 *cnxt);
+uint async_read32(struct adapter *adapter, u32 addr,  u8 *pbuff,
+		  void (*_async_io_callback)(struct adapter *padater,
+					     struct io_req *pio_req,
+					     u8 *cnxt), u8 *cnxt);
+
+void async_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void async_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+void async_write8(struct adapter *adapter, u32 addr, u8 val,
+		  void (*_async_io_callback)(struct adapter *padater,
+					     struct io_req *pio_req,
+					     u8 *cnxt), u8 *cnxt);
+void async_write16(struct adapter *adapter, u32 addr, u16 val,
+		   void (*_async_io_callback)(struct adapter *padater,
+					      struct io_req *pio_req,
+					      u8 *cnxt), u8 *cnxt);
+void async_write32(struct adapter *adapter, u32 addr, u32 val,
+		   void (*_async_io_callback)(struct adapter *padater,
+					      struct io_req *pio_req,
+					      u8 *cnxt), u8 *cnxt);
+
+void async_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void async_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+int rtw_init_io_priv(struct adapter *padapter,
+		     void (*set_intf_ops)(struct _io_ops *pops));
+
+uint alloc_io_queue(struct adapter *adapter);
+void free_io_queue(struct adapter *adapter);
+void async_bus_io(struct io_queue *pio_q);
+void bus_sync_io(struct io_queue *pio_q);
+u32 _ioreq2rwmem(struct io_queue *pio_q);
+void dev_power_down(struct adapter * Adapter, u8 bpwrup);
+
+#define PlatformEFIOWrite1Byte(_a,_b,_c)		\
+	rtw_write8(_a,_b,_c)
+#define PlatformEFIOWrite2Byte(_a,_b,_c)		\
+	rtw_write16(_a,_b,_c)
+#define PlatformEFIOWrite4Byte(_a,_b,_c)		\
+	rtw_write32(_a,_b,_c)
+
+#define PlatformEFIORead1Byte(_a,_b)		\
+		rtw_read8(_a,_b)
+#define PlatformEFIORead2Byte(_a,_b)		\
+		rtw_read16(_a,_b)
+#define PlatformEFIORead4Byte(_a,_b)		\
+		rtw_read32(_a,_b)
+
+#endif	/* _RTL8711_IO_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl.h b/drivers/staging/rtl8188eu/include/rtw_ioctl.h
new file mode 100644
index 0000000..8772d1d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl.h
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_IOCTL_H_
+#define _RTW_IOCTL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#ifndef OID_802_11_CAPABILITY
+	#define OID_802_11_CAPABILITY	0x0d010122
+#endif
+
+#ifndef OID_802_11_PMKID
+	#define OID_802_11_PMKID	0x0d010123
+#endif
+
+
+/*  For DDK-defined OIDs */
+#define OID_NDIS_SEG1	0x00010100
+#define OID_NDIS_SEG2	0x00010200
+#define OID_NDIS_SEG3	0x00020100
+#define OID_NDIS_SEG4	0x01010100
+#define OID_NDIS_SEG5	0x01020100
+#define OID_NDIS_SEG6	0x01020200
+#define OID_NDIS_SEG7	0xFD010100
+#define OID_NDIS_SEG8	0x0D010100
+#define OID_NDIS_SEG9	0x0D010200
+#define OID_NDIS_SEG10	0x0D020200
+
+#define SZ_OID_NDIS_SEG1	23
+#define SZ_OID_NDIS_SEG2	3
+#define SZ_OID_NDIS_SEG3	6
+#define SZ_OID_NDIS_SEG4	6
+#define SZ_OID_NDIS_SEG5	4
+#define SZ_OID_NDIS_SEG6	8
+#define SZ_OID_NDIS_SEG7	7
+#define SZ_OID_NDIS_SEG8	36
+#define SZ_OID_NDIS_SEG9	24
+#define SZ_OID_NDIS_SEG10	19
+
+/*  For Realtek-defined OIDs */
+#define OID_MP_SEG1		0xFF871100
+#define OID_MP_SEG2		0xFF818000
+
+#define OID_MP_SEG3		0xFF818700
+#define OID_MP_SEG4		0xFF011100
+
+#define DEBUG_OID(dbg, str)						\
+	if ((!dbg)) {							\
+		RT_TRACE(_module_rtl871x_ioctl_c_, _drv_info_,		\
+			 ("%s(%d): %s", __func__, __line__, str));	\
+	}
+
+enum oid_type {
+	QUERY_OID,
+	SET_OID
+};
+
+struct oid_funs_node {
+	unsigned int oid_start; /* the starting number for OID */
+	unsigned int oid_end; /* the ending number for OID */
+	struct oid_obj_priv *node_array;
+	unsigned int array_sz; /* the size of node_array */
+	int query_counter; /* count the number of query hits for this segment */
+	int set_counter; /* count the number of set hits for this segment */
+};
+
+struct oid_par_priv {
+	void		*adapter_context;
+	NDIS_OID	oid;
+	void		*information_buf;
+	u32		information_buf_len;
+	u32		*bytes_rw;
+	u32		*bytes_needed;
+	enum oid_type	type_of_oid;
+	u32		dbg;
+};
+
+struct oid_obj_priv {
+	unsigned char	dbg; /*  0: without OID debug message
+			      *  1: with OID debug message */
+	int (*oidfuns)(struct oid_par_priv *poid_par_priv);
+};
+
+#if defined(_RTW_MP_IOCTL_C_)
+static int oid_null_function(struct oid_par_priv *poid_par_priv) {
+	_func_enter_;
+	_func_exit_;
+	return NDIS_STATUS_SUCCESS;
+}
+#endif
+
+extern struct iw_handler_def  rtw_handlers_def;
+
+int drv_query_info(struct  net_device *miniportadaptercontext, NDIS_OID oid,
+		   void *informationbuffer, u32 informationbufferlength,
+		   u32 *byteswritten, u32 *bytesneeded);
+
+int drv_set_info(struct  net_device *MiniportAdapterContext,
+		 NDIS_OID oid, void *informationbuffer,
+		 u32 informationbufferlength, u32 *bytesread,
+		 u32 *bytesneeded);
+
+extern int ui_pid[3];
+
+#endif /*  #ifndef __INC_CEINFO_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h b/drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h
new file mode 100644
index 0000000..8fa3858
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl_rtl.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_IOCTL_RTL_H_
+#define _RTW_IOCTL_RTL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+/*  oid_rtl_seg_01_01 ************** */
+int oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv);/* 84 */
+int oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv);
+
+int oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv *poid_par_priv);/* 8a */
+int oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv *poid_par_priv);	/* 8b */
+
+int oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv);/* 93 */
+int oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_preamble_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_dedicate_probe_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_current_tx_power_level_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_supported_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv *poid_par_priv);
+
+/*   oid_rtl_seg_01_03 section start ************** */
+int oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv *priv);
+int oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv);
+
+/*  oid_rtl_seg_01_11 */
+int oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv);
+
+/*   oid_rtl_seg_03_00 section start ************** */
+int oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv);
+int oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_ioctl_set.h b/drivers/staging/rtl8188eu/include/rtw_ioctl_set.h
new file mode 100644
index 0000000..49efb23
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_ioctl_set.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_IOCTL_SET_H_
+#define __RTW_IOCTL_SET_H_
+
+#include <drv_types.h>
+
+
+typedef u8 NDIS_802_11_PMKID_VALUE[16];
+
+u8 rtw_set_802_11_add_key(struct adapter *adapt, struct ndis_802_11_key *key);
+u8 rtw_set_802_11_authentication_mode(struct adapter *adapt,
+				      enum ndis_802_11_auth_mode authmode);
+u8 rtw_set_802_11_bssid(struct adapter*adapter, u8 *bssid);
+u8 rtw_set_802_11_add_wep(struct adapter *adapter, struct ndis_802_11_wep *wep);
+u8 rtw_set_802_11_disassociate(struct adapter *adapter);
+u8 rtw_set_802_11_bssid_list_scan(struct adapter*adapter,
+				  struct ndis_802_11_ssid *pssid,
+				  int ssid_max_num);
+u8 rtw_set_802_11_infrastructure_mode(struct adapter *adapter,
+				      enum ndis_802_11_network_infra type);
+u8 rtw_set_802_11_remove_wep(struct adapter *adapter, u32 keyindex);
+u8 rtw_set_802_11_ssid(struct adapter *adapt, struct ndis_802_11_ssid *ssid);
+u8 rtw_set_802_11_remove_key(struct adapter *adapt,
+			     struct ndis_802_11_remove_key *key);
+u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid);
+u16 rtw_get_cur_max_rate(struct adapter *adapter);
+int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode);
+int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan);
+int rtw_set_country(struct adapter *adapter, const char *country_code);
+int rtw_change_ifname(struct adapter *padapter, const char *ifname);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_iol.h b/drivers/staging/rtl8188eu/include/rtw_iol.h
new file mode 100644
index 0000000..6949922
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_iol.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_IOL_H_
+#define __RTW_IOL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define IOREG_CMD_END_LEN	4
+
+struct ioreg_cfg {
+	u8	length;
+	u8	cmd_id;
+	__le16	address;
+	__le32	data;
+	__le32  mask;
+};
+
+enum ioreg_cmd {
+	IOREG_CMD_LLT		= 0x01,
+	IOREG_CMD_REFUSE	= 0x02,
+	IOREG_CMD_EFUSE_PATH	= 0x03,
+	IOREG_CMD_WB_REG	= 0x04,
+	IOREG_CMD_WW_REG	= 0x05,
+	IOREG_CMD_WD_REG	= 0x06,
+	IOREG_CMD_W_RF		= 0x07,
+	IOREG_CMD_DELAY_US	= 0x10,
+	IOREG_CMD_DELAY_MS	= 0x11,
+	IOREG_CMD_END		= 0xFF,
+};
+
+struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter);
+int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds,
+			u32 cmd_len);
+int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary);
+int rtw_IOL_exec_cmds_sync(struct adapter  *adapter,
+			   struct xmit_frame *xmit_frame, u32 max_wating_ms,
+			   u32 bndy_cnt);
+bool rtw_IOL_applied(struct adapter  *adapter);
+int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us);
+int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms);
+int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame);
+
+void read_efuse_from_txpktbuf(struct adapter *adapter, int bcnhead,
+			      u8 *content, u16 *size);
+
+int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr,
+			   u8 value, u8 mask);
+int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr,
+			   u16 value, u16 mask);
+int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr,
+			   u32 value, u32 mask);
+int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path,
+			    u16 addr, u32 value, u32 mask);
+#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value, mask)		\
+	_rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value) ,(mask))
+#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value, mask)		\
+	_rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value),(mask))
+#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value, mask)		\
+	_rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value), (mask))
+#define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value, mask)	\
+	_rtw_IOL_append_WRF_cmd((xmit_frame),(rf_path), (addr), (value), (mask))
+
+u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame);
+void  rtw_IOL_cmd_buf_dump(struct adapter  *Adapter,int buf_len,u8 *pbuf);
+
+#endif /* __RTW_IOL_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_led.h b/drivers/staging/rtl8188eu/include/rtw_led.h
new file mode 100644
index 0000000..2e61804
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_led.h
@@ -0,0 +1,197 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_LED_H_
+#define __RTW_LED_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define MSECS(t)        (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000)
+
+#define LED_BLINK_NORMAL_INTERVAL		100
+#define LED_BLINK_SLOWLY_INTERVAL		200
+#define LED_BLINK_LONG_INTERVAL			400
+
+#define LED_BLINK_NO_LINK_INTERVAL_ALPHA	1000
+#define LED_BLINK_LINK_INTERVAL_ALPHA		500	/* 500 */
+#define LED_BLINK_SCAN_INTERVAL_ALPHA		180	/* 150 */
+#define LED_BLINK_FASTER_INTERVAL_ALPHA		50
+#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA	5000
+
+#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX	100
+#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX	2000
+
+#define LED_BLINK_SLOWLY_INTERVAL_PORNET	1000
+#define LED_BLINK_NORMAL_INTERVAL_PORNET	100
+
+#define LED_BLINK_FAST_INTERVAL_BITLAND		30
+
+/*  060403, rcnjko: Customized for AzWave. */
+#define LED_CM2_BLINK_ON_INTERVAL		250
+#define LED_CM2_BLINK_OFF_INTERVAL		4750
+
+#define LED_CM8_BLINK_INTERVAL			500	/* for QMI */
+#define LED_CM8_BLINK_OFF_INTERVAL		3750	/* for QMI */
+
+/*  080124, lanhsin: Customized for RunTop */
+#define LED_RunTop_BLINK_INTERVAL		300
+
+/*  060421, rcnjko: Customized for Sercomm Printer Server case. */
+#define LED_CM3_BLINK_INTERVAL			1500
+
+enum LED_CTL_MODE {
+	LED_CTL_POWER_ON = 1,
+	LED_CTL_LINK = 2,
+	LED_CTL_NO_LINK = 3,
+	LED_CTL_TX = 4,
+	LED_CTL_RX = 5,
+	LED_CTL_SITE_SURVEY = 6,
+	LED_CTL_POWER_OFF = 7,
+	LED_CTL_START_TO_LINK = 8,
+	LED_CTL_START_WPS = 9,
+	LED_CTL_STOP_WPS = 10,
+	LED_CTL_START_WPS_BOTTON = 11, /* added for runtop */
+	LED_CTL_STOP_WPS_FAIL = 12, /* added for ALPHA */
+	LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, /* added for BELKIN */
+	LED_CTL_CONNECTION_NO_TRANSFER = 14,
+};
+
+enum LED_STATE_871x {
+	LED_UNKNOWN = 0,
+	RTW_LED_ON = 1,
+	RTW_LED_OFF = 2,
+	LED_BLINK_NORMAL = 3,
+	LED_BLINK_SLOWLY = 4,
+	LED_BLINK_POWER_ON = 5,
+	LED_BLINK_SCAN = 6, /*  LED is blinking during scanning period,
+			     * the # of times to blink is depend on time
+			     * for scanning. */
+	LED_BLINK_NO_LINK = 7, /*  LED is blinking during no link state. */
+	LED_BLINK_StartToBlink = 8,/*  Customzied for Sercomm Printer
+				    * Server case */
+	LED_BLINK_TXRX = 9,
+	LED_BLINK_WPS = 10,	/*  LED is blinkg during WPS communication */
+	LED_BLINK_WPS_STOP = 11,	/* for ALPHA */
+	LED_BLINK_WPS_STOP_OVERLAP = 12,	/* for BELKIN */
+	LED_BLINK_RUNTOP = 13, /*  Customized for RunTop */
+	LED_BLINK_CAMEO = 14,
+	LED_BLINK_XAVI = 15,
+	LED_BLINK_ALWAYS_ON = 16,
+};
+
+enum LED_PIN_871x {
+	LED_PIN_NULL = 0,
+	LED_PIN_LED0 = 1,
+	LED_PIN_LED1 = 2,
+	LED_PIN_LED2 = 3,
+	LED_PIN_GPIO0 = 4,
+};
+
+struct LED_871x {
+	struct adapter *padapter;
+
+	enum LED_PIN_871x	LedPin;	/* Identify how to implement this
+					 * SW led. */
+	enum LED_STATE_871x	CurrLedState; /*  Current LED state. */
+	enum LED_STATE_871x	BlinkingLedState; /*  Next state for blinking,
+				   * either RTW_LED_ON or RTW_LED_OFF are. */
+
+	u8 bLedOn; /*  true if LED is ON, false if LED is OFF. */
+
+	u8 bLedBlinkInProgress; /*  true if it is blinking, false o.w.. */
+
+	u8 bLedWPSBlinkInProgress;
+
+	u32 BlinkTimes; /*  Number of times to toggle led state for blinking. */
+
+	struct timer_list BlinkTimer; /*  Timer object for led blinking. */
+
+	u8 bSWLedCtrl;
+
+	/*  ALPHA, added by chiyoko, 20090106 */
+	u8 bLedNoLinkBlinkInProgress;
+	u8 bLedLinkBlinkInProgress;
+	u8 bLedStartToLinkBlinkInProgress;
+	u8 bLedScanBlinkInProgress;
+	struct work_struct BlinkWorkItem; /* Workitem used by BlinkTimer to
+					   * manipulate H/W to blink LED. */
+};
+
+#define IS_LED_WPS_BLINKING(_LED_871x)					\
+	(((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS || \
+	((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS_STOP || \
+	((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress)
+
+#define IS_LED_BLINKING(_LED_871x)					\
+	(((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress	||	\
+	((struct LED_871x *)_LED_871x)->bLedScanBlinkInProgress)
+
+/*  LED customization. */
+
+enum LED_STRATEGY_871x {
+	SW_LED_MODE0 = 0, /* SW control 1 LED via GPIO0. It is default option.*/
+	SW_LED_MODE1= 1, /*  2 LEDs, through LED0 and LED1. For ALPHA. */
+	SW_LED_MODE2 = 2, /*  SW control 1 LED via GPIO0, customized for AzWave
+			   * 8187 minicard. */
+	SW_LED_MODE3 = 3, /*  SW control 1 LED via GPIO0, customized for Sercomm
+			   * Printer Server case. */
+	SW_LED_MODE4 = 4, /* for Edimax / Belkin */
+	SW_LED_MODE5 = 5, /* for Sercomm / Belkin */
+	SW_LED_MODE6 = 6, /* for 88CU minicard, porting from ce SW_LED_MODE7 */
+	HW_LED = 50, /*  HW control 2 LEDs, LED0 and LED1 (there are 4
+		      * different control modes, see MAC.CONFIG1 for details.)*/
+	LED_ST_NONE = 99,
+};
+
+void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE	LedAction);
+
+struct led_priv{
+	/* add for led controll */
+	struct LED_871x			SwLed0;
+	struct LED_871x			SwLed1;
+	enum LED_STRATEGY_871x	LedStrategy;
+	u8	bRegUseLed;
+	void (*LedControlHandler)(struct adapter *padapter,
+				  enum LED_CTL_MODE LedAction);
+	/* add for led controll */
+};
+
+#define rtw_led_control(adapt, action) \
+	do { \
+		if ((adapt)->ledpriv.LedControlHandler) \
+			(adapt)->ledpriv.LedControlHandler((adapt), (action)); \
+	} while (0)
+
+void BlinkTimerCallback(void *data);
+void BlinkWorkItemCallback(struct work_struct *work);
+
+void ResetLedStatus(struct LED_871x * pLed);
+
+void InitLed871x(struct adapter *padapter, struct LED_871x *pLed,
+		 enum LED_PIN_871x LedPin);
+
+void DeInitLed871x(struct LED_871x *pLed);
+
+/* hal... */
+void BlinkHandler(struct LED_871x * pLed);
+void SwLedOn(struct adapter *padapter, struct LED_871x *pLed);
+void SwLedOff(struct adapter *padapter, struct LED_871x *pLed);
+
+#endif /* __RTW_LED_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h
new file mode 100644
index 0000000..22538e6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h
@@ -0,0 +1,655 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_MLME_H_
+#define __RTW_MLME_H_
+
+#include <osdep_service.h>
+#include <mlme_osdep.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+
+#define	MAX_BSS_CNT	128
+#define   MAX_JOIN_TIMEOUT	6500
+
+/* Increase the scanning timeout because of increasing the SURVEY_TO value. */
+
+#define		SCANNING_TIMEOUT	8000
+
+#define	SCAN_INTERVAL	(30) /*  unit:2sec, 30*2=60sec */
+
+#define	SCANQUEUE_LIFETIME 20 /*  unit:sec */
+
+#define	WIFI_NULL_STATE			0x00000000
+
+#define	WIFI_ASOC_STATE			0x00000001	/* Under Linked state */
+#define	WIFI_REASOC_STATE		0x00000002
+#define	WIFI_SLEEP_STATE		0x00000004
+#define	WIFI_STATION_STATE		0x00000008
+
+#define	WIFI_AP_STATE			0x00000010
+#define	WIFI_ADHOC_STATE		0x00000020
+#define WIFI_ADHOC_MASTER_STATE		0x00000040
+#define WIFI_UNDER_LINKING		0x00000080
+
+#define	WIFI_UNDER_WPS			0x00000100
+#define	WIFI_STA_ALIVE_CHK_STATE	0x00000400
+#define	WIFI_SITE_MONITOR		0x00000800	/* to indicate the station is under site surveying */
+
+#define	WIFI_MP_STATE			0x00010000
+#define	WIFI_MP_CTX_BACKGROUND		0x00020000	/*  in continous tx background */
+#define	WIFI_MP_CTX_ST			0x00040000	/*  in continous tx with single-tone */
+#define	WIFI_MP_CTX_BACKGROUND_PENDING	0x00080000	/*  pending in continous tx background due to out of skb */
+#define	WIFI_MP_CTX_CCK_HW		0x00100000	/*  in continous tx */
+#define	WIFI_MP_CTX_CCK_CS		0x00200000	/*  in continous tx with carrier suppression */
+#define WIFI_MP_LPBK_STATE		0x00400000
+
+#define _FW_UNDER_LINKING	WIFI_UNDER_LINKING
+#define _FW_LINKED			WIFI_ASOC_STATE
+#define _FW_UNDER_SURVEY	WIFI_SITE_MONITOR
+
+enum dot11AuthAlgrthmNum {
+	dot11AuthAlgrthm_Open = 0,
+	dot11AuthAlgrthm_Shared,
+	dot11AuthAlgrthm_8021X,
+	dot11AuthAlgrthm_Auto,
+	dot11AuthAlgrthm_WAPI,
+	dot11AuthAlgrthm_MaxNum
+};
+
+/*  Scan type including active and passive scan. */
+enum rt_scan_type {
+	SCAN_PASSIVE,
+	SCAN_ACTIVE,
+	SCAN_MIX,
+};
+
+enum SCAN_RESULT_TYPE {
+	SCAN_RESULT_P2P_ONLY = 0,	/* Will return all the P2P devices. */
+	SCAN_RESULT_ALL = 1,		/* Will return all the scanned device,
+					 * include AP. */
+	SCAN_RESULT_WFD_TYPE = 2	/* Will just return the correct WFD
+					 * device. */
+					/* If this device is Miracast sink
+					 * device, it will just return all the
+					 * Miracast source devices. */
+};
+
+/*
+there are several "locks" in mlme_priv,
+since mlme_priv is a shared resource between many threads,
+like ISR/Call-Back functions, the OID handlers, and even timer functions.
+
+Each _queue has its own locks, already.
+Other items are protected by mlme_priv.lock.
+
+To avoid possible dead lock, any thread trying to modifiying mlme_priv
+SHALL not lock up more than one lock at a time!
+*/
+
+#define traffic_threshold	10
+#define	traffic_scan_period	500
+
+struct sitesurvey_ctrl {
+	u64	last_tx_pkts;
+	uint	last_rx_pkts;
+	int	traffic_busy;
+	struct timer_list sitesurvey_ctrl_timer;
+};
+
+struct rt_link_detect {
+	u32	NumTxOkInPeriod;
+	u32	NumRxOkInPeriod;
+	u32	NumRxUnicastOkInPeriod;
+	bool	bBusyTraffic;
+	bool	bTxBusyTraffic;
+	bool	bRxBusyTraffic;
+	bool	bHigherBusyTraffic; /*  For interrupt migration purpose. */
+	bool	bHigherBusyRxTraffic; /* We may disable Tx interrupt according
+				       * to Rx traffic. */
+	bool	bHigherBusyTxTraffic; /* We may disable Tx interrupt according
+				       * to Tx traffic. */
+};
+
+struct profile_info {
+	u8	ssidlen;
+	u8	ssid[ WLAN_SSID_MAXLEN ];
+	u8	peermac[ ETH_ALEN ];
+};
+
+struct tx_invite_req_info {
+	u8	token;
+	u8	benable;
+	u8	go_ssid[ WLAN_SSID_MAXLEN ];
+	u8	ssidlen;
+	u8	go_bssid[ ETH_ALEN ];
+	u8	peer_macaddr[ ETH_ALEN ];
+	u8	operating_ch;	/* This information will be set by using the
+				 * p2p_set op_ch=x */
+	u8	peer_ch;	/* The listen channel for peer P2P device */
+};
+
+struct tx_invite_resp_info {
+	u8	token;	/* Used to record the dialog token of p2p invitation
+			 * request frame. */
+};
+
+struct tx_provdisc_req_info {
+	u16	wps_config_method_request;	/* Used when sending the
+						 * provisioning request frame*/
+	u16	peer_channel_num[2];		/* The channel number which the
+						 * receiver stands. */
+	struct ndis_802_11_ssid	ssid;
+	u8	peerDevAddr[ETH_ALEN];		/* Peer device address */
+	u8	peerIFAddr[ETH_ALEN];		/* Peer interface address */
+	u8	benable;			/* This provision discovery
+						 * request frame is trigger
+						 * to send or not */
+};
+
+/* When peer device issue prov_disc_req first, we should store the following
+ * information */
+/* The UI must know this information to know which config method the
+ * remote p2p device needs. */
+struct rx_provdisc_req_info {
+	u8	peerDevAddr[ETH_ALEN];		/* Peer device address */
+	u8	strconfig_method_desc_of_prov_disc_req[4];	/* description
+			* for the config method located in the provisioning
+			* discovery request frame. */
+};
+
+struct tx_nego_req_info {
+	u16	peer_channel_num[2];	/* The channel number. */
+	u8	peerDevAddr[ETH_ALEN];	/* Peer device address */
+	u8	benable;		/* This negotiation request frame is
+					 * trigger to send or not */
+};
+
+struct group_id_info {
+	u8	go_device_addr[ ETH_ALEN ];	/* The GO's device address of
+						 * this P2P group */
+	u8	ssid[ WLAN_SSID_MAXLEN ];	/* The SSID of this P2P group */
+};
+
+struct scan_limit_info {
+	u8	scan_op_ch_only;	/* When this flag is set, the driver
+					 * should only scan the op. channel */
+	u8	operation_ch[2];	/* Store the op. chan of invitation */
+};
+
+struct wifidirect_info {
+	struct adapter *padapter;
+	struct timer_list find_phase_timer;
+	struct timer_list restore_p2p_state_timer;
+
+	/* Used to do the scanning. After confirming the peer is availalble,
+	 * the driver transmits the P2P frame to peer. */
+	struct timer_list pre_tx_scan_timer;
+	struct timer_list reset_ch_sitesurvey;
+	struct timer_list reset_ch_sitesurvey2;	/* Just for resetting the scan
+					 * limit function by using p2p nego */
+	struct tx_provdisc_req_info	tx_prov_disc_info;
+	struct rx_provdisc_req_info rx_prov_disc_info;
+	struct tx_invite_req_info	invitereq_info;
+	/* Store the profile information of persistent group */
+	struct profile_info profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM];
+	struct tx_invite_resp_info	inviteresp_info;
+	struct tx_nego_req_info	nego_req_info;
+	/* Store the group id info when doing the group negot handshake. */
+	struct group_id_info groupid_info;
+	/* Used for get the limit scan channel from the Invitation procedure */
+	struct scan_limit_info rx_invitereq_info;
+	/* Used for get the limit scan chan from the P2P negotiation handshake*/
+	struct scan_limit_info p2p_info;
+	enum P2P_ROLE role;
+	enum P2P_STATE pre_p2p_state;
+	enum P2P_STATE p2p_state;
+	/* The device address should be the mac address of this device. */
+	u8 device_addr[ETH_ALEN];
+	u8 interface_addr[ETH_ALEN];
+	u8 social_chan[4];
+	u8 listen_channel;
+	u8 operating_channel;
+	u8 listen_dwell;	/* This value should be between 1 and 3 */
+	u8 support_rate[8];
+	u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN];
+	u8 intent;	/* should only include the intent value. */
+	u8 p2p_peer_interface_addr[ETH_ALEN];
+	u8 p2p_peer_device_addr[ETH_ALEN];
+	u8 peer_intent;	/* Included the intent value and tie breaker value. */
+	/* Device name for displaying on searching device screen */
+	u8 device_name[WPS_MAX_DEVICE_NAME_LEN];
+	u8 device_name_len;
+	u8 profileindex; /* Used to point to the index of profileinfo array */
+	u8 peer_operating_ch;
+	u8 find_phase_state_exchange_cnt;
+	/* The device password ID for group negotation */
+	u16 device_password_id_for_nego;
+	u8 negotiation_dialog_token;
+	/* SSID information for group negotitation */
+	u8 nego_ssid[WLAN_SSID_MAXLEN];
+	u8 nego_ssidlen;
+	u8 p2p_group_ssid[WLAN_SSID_MAXLEN];
+	u8 p2p_group_ssid_len;
+	/* Flag to know if the persistent function should be supported or not.*/
+	u8 persistent_supported;
+	/* In the Sigma test, the Sigma will provide this enable from the
+	 * sta_set_p2p CAPI. */
+	/*	0: disable */
+	/*	1: enable */
+	u8 session_available;	/* Flag to set the WFD session available to
+				 * enable or disable "by Sigma" */
+	/* In the Sigma test, the Sigma will disable the session available
+	 * by using the sta_preset CAPI. */
+	/*	0: disable */
+	/*	1: enable */
+	u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma*/
+			    /* 0: disable */
+			    /*	1: enable */
+	u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security
+			      * function for TDLS by WFD Sigma */
+			     /* 0: disable */
+			     /* In this case, the driver can't issue the tdsl
+			      * setup request frame. */
+			     /*	1: enable */
+			     /* In this case, the driver can issue the tdls
+			      * setup request frame */
+			     /*	even the current security is weak security. */
+
+	/* This field will store the WPS value (PIN value or PBC) that UI had
+	 * got from the user. */
+	enum	P2P_WPSINFO ui_got_wps_info;
+	u16 supported_wps_cm;	/* This field describes the WPS config method
+				 * which this driver supported. */
+				/* The value should be the combination of config
+				 * method defined in page104 of WPS v2.0 spec.*/
+	/* This field will contain the length of body of P2P Channel List
+	 * attribute of group negotiation response frame. */
+	uint channel_list_attr_len;
+	/* This field will contain the body of P2P Channel List attribute of
+	 * group negotitation response frame. */
+	/* We will use the channel_cnt and channel_list fields when constructing
+	 * the group negotiation confirm frame. */
+	u8 channel_list_attr[100];
+	enum P2P_PS_MODE p2p_ps_mode; /*  indicate p2p ps mode */
+	enum P2P_PS_STATE p2p_ps_state; /*  indicate p2p ps state */
+	u8 noa_index; /*  Identifies and instance of Notice of Absence timing. */
+	u8 ctwindow; /*  Client traffic window. A period of time in TU after TBTT. */
+	u8 opp_ps; /*  opportunistic power save. */
+	u8 noa_num; /*  number of NoA descriptor in P2P IE. */
+	u8 noa_count[P2P_MAX_NOA_NUM]; /*  Count for owner, Type of client. */
+	/* Max duration for owner, preferred or min acceptable duration for
+	 * client. */
+	u32 noa_duration[P2P_MAX_NOA_NUM];
+	/* Length of interval for owner, preferred or max acceptable interval
+	 * of client. */
+	u32 noa_interval[P2P_MAX_NOA_NUM];
+	/* schedule expressed in terms of the lower 4 bytes of the TSF timer. */
+	u32 noa_start_time[P2P_MAX_NOA_NUM];
+};
+
+struct tdls_ss_record {	/* signal strength record */
+	u8 macaddr[ETH_ALEN];
+	u8 RxPWDBAll;
+	u8 is_tdls_sta;	/*  true: direct link sta, false: else */
+};
+
+struct tdls_info {
+	u8 ap_prohibited;
+	uint setup_state;
+	u8 sta_cnt;
+	u8 sta_maximum;	/*  1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; */
+	struct tdls_ss_record	ss_record;
+	u8 macid_index;	/* macid entry that is ready to write */
+	u8 clear_cam;	/* cam entry that is trying to clear, using it in direct link teardown */
+	u8 ch_sensing;
+	u8 cur_channel;
+	u8 candidate_ch;
+	u8 collect_pkt_num[MAX_CHANNEL_NUM];
+	spinlock_t cmd_lock;
+	spinlock_t hdl_lock;
+	u8 watchdog_count;
+	u8 dev_discovered;		/* WFD_TDLS: for sigma test */
+	u8 enable;
+};
+
+struct mlme_priv {
+	spinlock_t lock;
+	int fw_state;	/* shall we protect this variable? maybe not necessarily... */
+	u8 bScanInProcess;
+	u8 to_join; /* flag */
+	u8 to_roaming; /*  roaming trying times */
+
+	u8 *nic_hdl;
+
+	u8 not_indic_disco;
+	struct list_head *pscanned;
+	struct __queue free_bss_pool;
+	struct __queue scanned_queue;
+	u8 *free_bss_buf;
+	u32	num_of_scanned;
+
+	struct ndis_802_11_ssid	assoc_ssid;
+	u8	assoc_bssid[6];
+
+	struct wlan_network	cur_network;
+
+	u32	scan_interval;
+
+	struct timer_list assoc_timer;
+
+	uint assoc_by_bssid;
+	uint assoc_by_rssi;
+
+	struct timer_list scan_to_timer; /*  driver itself handles scan_timeout status. */
+	u32 scan_start_time; /*  used to evaluate the time spent in scanning */
+
+	struct qos_priv qospriv;
+
+	/* Number of non-HT AP/stations */
+	int num_sta_no_ht;
+
+	/* Number of HT AP/stations 20 MHz */
+	/* int num_sta_ht_20mhz; */
+
+	int num_FortyMHzIntolerant;
+	struct ht_priv	htpriv;
+	struct rt_link_detect LinkDetectInfo;
+	struct timer_list dynamic_chk_timer; /* dynamic/periodic check timer */
+
+	u8	key_mask; /* use for ips to set wep key after ips_leave */
+	u8	acm_mask; /*  for wmm acm mask */
+	u8	ChannelPlan;
+	enum rt_scan_type scan_mode; /*  active: 1, passive: 0 */
+
+	/* u8 probereq_wpsie[MAX_WPS_IE_LEN];added in probe req */
+	/* int probereq_wpsie_len; */
+	u8 *wps_probe_req_ie;
+	u32 wps_probe_req_ie_len;
+
+	u8 *assoc_req;
+	u32 assoc_req_len;
+	u8 *assoc_rsp;
+	u32 assoc_rsp_len;
+
+#if defined (CONFIG_88EU_AP_MODE)
+	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
+	 * in 802.11g BSS) */
+	int num_sta_non_erp;
+
+	/* Number of associated stations that do not support Short Slot Time */
+	int num_sta_no_short_slot_time;
+
+	/* Number of associated stations that do not support Short Preamble */
+	int num_sta_no_short_preamble;
+
+	int olbc; /* Overlapping Legacy BSS Condition */
+
+	/* Number of HT assoc sta that do not support greenfield */
+	int num_sta_ht_no_gf;
+
+	/* Number of associated non-HT stations */
+	/* int num_sta_no_ht; */
+
+	/* Number of HT associated stations 20 MHz */
+	int num_sta_ht_20mhz;
+
+	/* Overlapping BSS information */
+	int olbc_ht;
+
+	u16 ht_op_mode;
+
+	u8 *wps_beacon_ie;
+	/* u8 *wps_probe_req_ie; */
+	u8 *wps_probe_resp_ie;
+	u8 *wps_assoc_resp_ie;
+
+	u32 wps_beacon_ie_len;
+	u32 wps_probe_resp_ie_len;
+	u32 wps_assoc_resp_ie_len;
+
+	u8 *p2p_beacon_ie;
+	u8 *p2p_probe_req_ie;
+	u8 *p2p_probe_resp_ie;
+	u8 *p2p_go_probe_resp_ie; /* for GO */
+	u8 *p2p_assoc_req_ie;
+
+	u32 p2p_beacon_ie_len;
+	u32 p2p_probe_req_ie_len;
+	u32 p2p_probe_resp_ie_len;
+	u32 p2p_go_probe_resp_ie_len; /* for GO */
+	u32 p2p_assoc_req_ie_len;
+	spinlock_t bcn_update_lock;
+	u8		update_bcn;
+#endif /* if defined (CONFIG_88EU_AP_MODE) */
+};
+
+#ifdef CONFIG_88EU_AP_MODE
+
+struct hostapd_priv {
+	struct adapter *padapter;
+};
+
+int hostapd_mode_init(struct adapter *padapter);
+void hostapd_mode_unload(struct adapter *padapter);
+#endif
+
+extern unsigned char WPA_TKIP_CIPHER[4];
+extern unsigned char RSN_TKIP_CIPHER[4];
+extern unsigned char REALTEK_96B_IE[];
+extern unsigned char	MCS_rate_2R[16];
+extern unsigned char	MCS_rate_1R[16];
+
+void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf);
+void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_cpwm_event_callback(struct adapter *adapter, u8 *pbuf);
+void indicate_wx_scan_complete_event(struct adapter *padapter);
+void rtw_indicate_wx_assoc_event(struct adapter *padapter);
+void rtw_indicate_wx_disassoc_event(struct adapter *padapter);
+int event_thread(void *context);
+void rtw_join_timeout_handler(void *FunctionContext);
+void _rtw_scan_timeout_handler(void *FunctionContext);
+void rtw_free_network_queue(struct adapter *adapter, u8 isfreeall);
+int rtw_init_mlme_priv(struct adapter *adapter);
+void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv);
+int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv);
+int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv,
+		int keyid, u8 set_tx);
+int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv);
+
+static inline u8 *get_bssid(struct mlme_priv *pmlmepriv)
+{	/* if sta_mode:pmlmepriv->cur_network.network.MacAddress=> bssid */
+	/*  if adhoc_mode:pmlmepriv->cur_network.network.MacAddress=> ibss mac address */
+	return pmlmepriv->cur_network.network.MacAddress;
+}
+
+static inline int check_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+	if (pmlmepriv->fw_state & state)
+		return true;
+
+	return false;
+}
+
+static inline int get_fwstate(struct mlme_priv *pmlmepriv)
+{
+	return pmlmepriv->fw_state;
+}
+
+/*
+ * No Limit on the calling context,
+ * therefore set it to be the critical section...
+ *
+ * ### NOTE:#### (!!!!)
+ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+ */
+static inline void set_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+	pmlmepriv->fw_state |= state;
+	/* FOR HW integration */
+	if (_FW_UNDER_SURVEY==state)
+		pmlmepriv->bScanInProcess = true;
+}
+
+static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, int state)
+{
+	pmlmepriv->fw_state &= ~state;
+	/* FOR HW integration */
+	if (_FW_UNDER_SURVEY==state)
+		pmlmepriv->bScanInProcess = false;
+}
+
+/*
+ * No Limit on the calling context,
+ * therefore set it to be the critical section...
+ */
+static inline void clr_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+	unsigned long irql;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	if (check_fwstate(pmlmepriv, state) == true)
+		pmlmepriv->fw_state ^= state;
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void clr_fwstate_ex(struct mlme_priv *pmlmepriv, int state)
+{
+	unsigned long irql;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	_clr_fwstate_(pmlmepriv, state);
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void up_scanned_network(struct mlme_priv *pmlmepriv)
+{
+	unsigned long irql;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	pmlmepriv->num_of_scanned++;
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void down_scanned_network(struct mlme_priv *pmlmepriv)
+{
+	unsigned long irql;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	pmlmepriv->num_of_scanned--;
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, int val)
+{
+	unsigned long irql;
+
+	_enter_critical_bh(&pmlmepriv->lock, &irql);
+	pmlmepriv->num_of_scanned = val;
+	_exit_critical_bh(&pmlmepriv->lock, &irql);
+}
+
+u16 rtw_get_capability(struct wlan_bssid_ex *bss);
+void rtw_update_scanned_network(struct adapter *adapter,
+				struct wlan_bssid_ex *target);
+void rtw_disconnect_hdl_under_linked(struct adapter *adapter,
+				     struct sta_info *psta, u8 free_assoc);
+void rtw_generate_random_ibss(u8 *pibss);
+struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr);
+struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue);
+
+void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue);
+void rtw_indicate_disconnect(struct adapter *adapter);
+void rtw_indicate_connect(struct adapter *adapter);
+void rtw_indicate_scan_done( struct adapter *padapter, bool aborted);
+void rtw_scan_abort(struct adapter *adapter);
+
+int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie,
+			uint in_len);
+int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie,
+		        uint in_len, uint initial_out_len);
+void rtw_init_registrypriv_dev_network(struct adapter *adapter);
+
+void rtw_update_registrypriv_dev_network(struct adapter *adapter);
+
+void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter);
+
+void _rtw_join_timeout_handler(struct adapter *adapter);
+void rtw_scan_timeout_handler(struct adapter *adapter);
+
+ void rtw_dynamic_check_timer_handlder(struct adapter *adapter);
+#define rtw_is_scan_deny(adapter) false
+#define rtw_clear_scan_deny(adapter) do {} while (0)
+#define rtw_set_scan_deny_timer_hdl(adapter) do {} while (0)
+#define rtw_set_scan_deny(adapter, ms) do {} while (0)
+
+
+int _rtw_init_mlme_priv(struct adapter *padapter);
+
+void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
+
+void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv);
+
+int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork);
+
+struct wlan_network *_rtw_dequeue_network(struct __queue *queue);
+
+ struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv);
+
+
+void _rtw_free_network(struct mlme_priv *pmlmepriv,
+		       struct wlan_network *pnetwork, u8 isfreeall);
+void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv,
+			      struct wlan_network *pnetwork);
+
+
+struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr);
+
+void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall);
+
+int rtw_if_up(struct adapter *padapter);
+
+
+u8 *rtw_get_capability_from_ie(u8 *ie);
+u8 *rtw_get_timestampe_from_ie(u8 *ie);
+u8 *rtw_get_beacon_interval_from_ie(u8 *ie);
+
+
+void rtw_joinbss_reset(struct adapter *padapter);
+
+unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie,
+				   u8 *out_ie, uint in_len, uint *pout_len);
+void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len);
+void rtw_issue_addbareq_cmd(struct adapter *padapter,
+			    struct xmit_frame *pxmitframe);
+
+int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork);
+int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst);
+
+void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network);
+void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network);
+
+void rtw_stassoc_hw_rpt(struct adapter *adapter,struct sta_info *psta);
+
+#endif /* __RTL871X_MLME_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
new file mode 100644
index 0000000..a96b018
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -0,0 +1,877 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_MLME_EXT_H_
+#define __RTW_MLME_EXT_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+
+
+/*	Commented by Albert 20101105 */
+/*	Increase the SURVEY_TO value from 100 to 150  ( 100ms to 150ms ) */
+/*	The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. */
+/*	So, this driver tried to extend the dwell time for each scanning channel. */
+/*	This will increase the chance to receive the probe response from SoftAP. */
+
+#define SURVEY_TO		(100)
+#define REAUTH_TO		(300) /* 50) */
+#define REASSOC_TO		(300) /* 50) */
+/* define DISCONNECT_TO	(3000) */
+#define ADDBA_TO			(2000)
+
+#define LINKED_TO (1) /* unit:2 sec, 1x2=2 sec */
+
+#define REAUTH_LIMIT	(4)
+#define REASSOC_LIMIT	(4)
+#define READDBA_LIMIT	(2)
+
+#define ROAMING_LIMIT	8
+
+#define	DYNAMIC_FUNC_DISABLE			(0x0)
+
+/*  ====== ODM_ABILITY_E ======== */
+/*  BB ODM section BIT 0-15 */
+#define	DYNAMIC_BB_DIG				BIT(0)
+#define	DYNAMIC_BB_RA_MASK			BIT(1)
+#define	DYNAMIC_BB_DYNAMIC_TXPWR	BIT(2)
+#define	DYNAMIC_BB_BB_FA_CNT			BIT(3)
+
+#define		DYNAMIC_BB_RSSI_MONITOR		BIT(4)
+#define		DYNAMIC_BB_CCK_PD			BIT(5)
+#define		DYNAMIC_BB_ANT_DIV			BIT(6)
+#define		DYNAMIC_BB_PWR_SAVE			BIT(7)
+#define		DYNAMIC_BB_PWR_TRA			BIT(8)
+#define		DYNAMIC_BB_RATE_ADAPTIVE		BIT(9)
+#define		DYNAMIC_BB_PATH_DIV			BIT(10)
+#define		DYNAMIC_BB_PSD				BIT(11)
+
+/*  MAC DM section BIT 16-23 */
+#define		DYNAMIC_MAC_EDCA_TURBO		BIT(16)
+#define		DYNAMIC_MAC_EARLY_MODE		BIT(17)
+
+/*  RF ODM section BIT 24-31 */
+#define		DYNAMIC_RF_TX_PWR_TRACK		BIT(24)
+#define		DYNAMIC_RF_RX_GAIN_TRACK		BIT(25)
+#define		DYNAMIC_RF_CALIBRATION		BIT(26)
+
+#define		DYNAMIC_ALL_FUNC_ENABLE		0xFFFFFFF
+
+#define _HW_STATE_NOLINK_		0x00
+#define _HW_STATE_ADHOC_		0x01
+#define _HW_STATE_STATION_	0x02
+#define _HW_STATE_AP_			0x03
+
+
+#define		_1M_RATE_	0
+#define		_2M_RATE_	1
+#define		_5M_RATE_	2
+#define		_11M_RATE_	3
+#define		_6M_RATE_	4
+#define		_9M_RATE_	5
+#define		_12M_RATE_	6
+#define		_18M_RATE_	7
+#define		_24M_RATE_	8
+#define		_36M_RATE_	9
+#define		_48M_RATE_	10
+#define		_54M_RATE_	11
+
+
+extern unsigned char RTW_WPA_OUI[];
+extern unsigned char WMM_OUI[];
+extern unsigned char WPS_OUI[];
+extern unsigned char WFD_OUI[];
+extern unsigned char P2P_OUI[];
+
+extern unsigned char WMM_INFO_OUI[];
+extern unsigned char WMM_PARA_OUI[];
+
+/*  Channel Plan Type. */
+/*  Note: */
+/*	We just add new channel plan when the new channel plan is different
+ *      from any of the following channel plan. */
+/*	If you just wnat to customize the acitions(scan period or join actions)
+ *      about one of the channel plan, */
+/*	customize them in struct rt_channel_info in the RT_CHANNEL_LIST. */
+enum RT_CHANNEL_DOMAIN {
+	/*  old channel plan mapping =====  */
+	RT_CHANNEL_DOMAIN_FCC = 0x00,
+	RT_CHANNEL_DOMAIN_IC = 0x01,
+	RT_CHANNEL_DOMAIN_ETSI = 0x02,
+	RT_CHANNEL_DOMAIN_SPAIN = 0x03,
+	RT_CHANNEL_DOMAIN_FRANCE = 0x04,
+	RT_CHANNEL_DOMAIN_MKK = 0x05,
+	RT_CHANNEL_DOMAIN_MKK1 = 0x06,
+	RT_CHANNEL_DOMAIN_ISRAEL = 0x07,
+	RT_CHANNEL_DOMAIN_TELEC = 0x08,
+	RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09,
+	RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A,
+	RT_CHANNEL_DOMAIN_TAIWAN = 0x0B,
+	RT_CHANNEL_DOMAIN_CHINA = 0x0C,
+	RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D,
+	RT_CHANNEL_DOMAIN_KOREA = 0x0E,
+	RT_CHANNEL_DOMAIN_TURKEY = 0x0F,
+	RT_CHANNEL_DOMAIN_JAPAN = 0x10,
+	RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11,
+	RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12,
+	RT_CHANNEL_DOMAIN_WORLD_WIDE_5G = 0x13,
+	RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14,
+
+	/*  new channel plan mapping, (2GDOMAIN_5GDOMAIN) ===== */
+	RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20,
+	RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21,
+	RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22,
+	RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23,
+	RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24,
+	RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25,
+	RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26,
+	RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27,
+	RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28,
+	RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29,
+	RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30,
+	RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31,
+	RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32,
+	RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33,
+	RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34,
+	RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35,
+	RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36,
+	RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37,
+	RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38,
+	RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39,
+	RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40,
+	RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G = 0x41,
+	/*  Add new channel plan above this line=============== */
+	RT_CHANNEL_DOMAIN_MAX,
+	RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F,
+};
+
+enum RT_CHANNEL_DOMAIN_2G {
+	RT_CHANNEL_DOMAIN_2G_WORLD = 0x00,		/* Worldwide 13 */
+	RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01,		/* Europe */
+	RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02,		/* US */
+	RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03,		/* Japan */
+	RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04,		/* France */
+	RT_CHANNEL_DOMAIN_2G_NULL = 0x05,
+	/*  Add new channel plan above this line=============== */
+	RT_CHANNEL_DOMAIN_2G_MAX,
+};
+
+#define rtw_is_channel_plan_valid(chplan)			\
+	(chplan < RT_CHANNEL_DOMAIN_MAX ||			\
+	 chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
+
+struct rt_channel_plan {
+	unsigned char	Channel[MAX_CHANNEL_NUM];
+	unsigned char	Len;
+};
+
+struct rt_channel_plan_2g {
+	unsigned char	Channel[MAX_CHANNEL_NUM_2G];
+	unsigned char	Len;
+};
+
+struct rt_channel_plan_map {
+	unsigned char	Index2G;
+};
+
+enum Associated_AP {
+	atherosAP	= 0,
+	broadcomAP	= 1,
+	ciscoAP		= 2,
+	marvellAP	= 3,
+	ralinkAP	= 4,
+	realtekAP	= 5,
+	airgocapAP	= 6,
+	unknownAP	= 7,
+	maxAP,
+};
+
+enum HT_IOT_PEER {
+	HT_IOT_PEER_UNKNOWN		= 0,
+	HT_IOT_PEER_REALTEK		= 1,
+	HT_IOT_PEER_REALTEK_92SE	= 2,
+	HT_IOT_PEER_BROADCOM		= 3,
+	HT_IOT_PEER_RALINK		= 4,
+	HT_IOT_PEER_ATHEROS		= 5,
+	HT_IOT_PEER_CISCO		= 6,
+	HT_IOT_PEER_MERU		= 7,
+	HT_IOT_PEER_MARVELL		= 8,
+	HT_IOT_PEER_REALTEK_SOFTAP	= 9,/*  peer is RealTek SOFT_AP */
+	HT_IOT_PEER_SELF_SOFTAP		= 10, /*  Self is SoftAP */
+	HT_IOT_PEER_AIRGO		= 11,
+	HT_IOT_PEER_INTEL		= 12,
+	HT_IOT_PEER_RTK_APCLIENT	= 13,
+	HT_IOT_PEER_REALTEK_81XX	= 14,
+	HT_IOT_PEER_REALTEK_WOW		= 15,
+	HT_IOT_PEER_TENDA		= 16,
+	HT_IOT_PEER_MAX			= 17
+};
+
+enum SCAN_STATE {
+	SCAN_DISABLE = 0,
+	SCAN_START = 1,
+	SCAN_TXNULL = 2,
+	SCAN_PROCESS = 3,
+	SCAN_COMPLETE = 4,
+	SCAN_STATE_MAX,
+};
+
+struct mlme_handler {
+	unsigned int   num;
+	char *str;
+	unsigned int (*func)(struct adapter *adapt, union recv_frame *frame);
+};
+
+struct action_handler {
+	unsigned int   num;
+	char* str;
+	unsigned int (*func)(struct adapter *adapt, union recv_frame *frame);
+};
+
+struct	ss_res {
+	int	state;
+	int	bss_cnt;
+	int	channel_idx;
+	int	scan_mode;
+	u8 ssid_num;
+	u8 ch_num;
+	struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+	struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+};
+
+/* define AP_MODE				0x0C */
+/* define STATION_MODE	0x08 */
+/* define AD_HOC_MODE		0x04 */
+/* define NO_LINK_MODE	0x00 */
+
+#define WIFI_FW_NULL_STATE		_HW_STATE_NOLINK_
+#define	WIFI_FW_STATION_STATE		_HW_STATE_STATION_
+#define	WIFI_FW_AP_STATE		_HW_STATE_AP_
+#define	WIFI_FW_ADHOC_STATE		_HW_STATE_ADHOC_
+
+#define	WIFI_FW_AUTH_NULL		0x00000100
+#define	WIFI_FW_AUTH_STATE		0x00000200
+#define	WIFI_FW_AUTH_SUCCESS		0x00000400
+
+#define	WIFI_FW_ASSOC_STATE		0x00002000
+#define	WIFI_FW_ASSOC_SUCCESS		0x00004000
+
+#define	WIFI_FW_LINKING_STATE		(WIFI_FW_AUTH_NULL |		\
+					WIFI_FW_AUTH_STATE |		\
+					WIFI_FW_AUTH_SUCCESS |		\
+					WIFI_FW_ASSOC_STATE)
+
+struct FW_Sta_Info {
+	struct sta_info	*psta;
+	u32	status;
+	u32	rx_pkt;
+	u32	retry;
+	unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+};
+
+/*
+ * Usage:
+ * When one iface acted as AP mode and the other iface is STA mode and scanning,
+ * it should switch back to AP's operating channel periodically.
+ * Parameters info:
+ * When the driver scanned RTW_SCAN_NUM_OF_CH channels, it would switch back to
+ * AP's operating channel for
+ * RTW_STAY_AP_CH_MILLISECOND * SURVEY_TO milliseconds.
+ * Example:
+ * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1,
+ * RTW_SCAN_NUM_OF_CH is 8, RTW_STAY_AP_CH_MS is 3 and SURVEY_TO is 100.
+ * When it's STA mode gets set_scan command,
+ * it would
+ * 1. Doing the scan on channel 1.2.3.4.5.6.7.8
+ * 2. Back to channel 1 for 300 milliseconds
+ * 3. Go through doing site survey on channel 9.10.11.36.40.44.48.52
+ * 4. Back to channel 1 for 300 milliseconds
+ * 5. ... and so on, till survey done.
+ */
+
+struct mlme_ext_info {
+	u32	state;
+	u32	reauth_count;
+	u32	reassoc_count;
+	u32	link_count;
+	u32	auth_seq;
+	u32	auth_algo;	/*  802.11 auth, could be open, shared, auto */
+	u32	authModeToggle;
+	u32	enc_algo;/* encrypt algorithm; */
+	u32	key_index;	/*  this is only valid for legacy wep,
+				 *  0~3 for key id. */
+	u32	iv;
+	u8	chg_txt[128];
+	u16	aid;
+	u16	bcn_interval;
+	u16	capability;
+	u8	assoc_AP_vendor;
+	u8	slotTime;
+	u8	preamble_mode;
+	u8	WMM_enable;
+	u8	ERP_enable;
+	u8	ERP_IE;
+	u8	HT_enable;
+	u8	HT_caps_enable;
+	u8	HT_info_enable;
+	u8	HT_protection;
+	u8	turboMode_cts2self;
+	u8	turboMode_rtsen;
+	u8	SM_PS;
+	u8	agg_enable_bitmap;
+	u8	ADDBA_retry_count;
+	u8	candidate_tid_bitmap;
+	u8	dialogToken;
+	/*  Accept ADDBA Request */
+	bool bAcceptAddbaReq;
+	u8	bwmode_updated;
+	u8	hidden_ssid_mode;
+
+	struct ADDBA_request	ADDBA_req;
+	struct WMM_para_element	WMM_param;
+	struct HT_caps_element	HT_caps;
+	struct HT_info_element	HT_info;
+	struct wlan_bssid_ex	network;/* join network or bss_network,
+					 * if in ap mode, it is the same
+					 * as cur_network.network */
+	struct FW_Sta_Info	FW_sta_info[NUM_STA];
+};
+
+/*  The channel information about this channel including joining,
+ *  scanning, and power constraints. */
+struct rt_channel_info {
+	u8	ChannelNum;	/*  The channel number. */
+	enum rt_scan_type ScanType;	/*  Scan type such as passive
+					 *  or active scan. */
+	u32	rx_count;
+};
+
+int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch);
+
+/*  P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */
+#define P2P_MAX_REG_CLASSES 10
+
+/*  P2P_MAX_REG_CLASS_CHANNELS - Maximum number of chan per regulatory class */
+#define P2P_MAX_REG_CLASS_CHANNELS 20
+
+/*   struct p2p_channels - List of supported channels */
+struct p2p_channels {
+	/*  struct p2p_reg_class - Supported regulatory class */
+	struct p2p_reg_class {
+		/*  reg_class - Regulatory class (IEEE 802.11-2007, Annex J) */
+		u8 reg_class;
+
+		/*  channel - Supported channels */
+		u8 channel[P2P_MAX_REG_CLASS_CHANNELS];
+
+		/*  channels - Number of channel entries in use */
+		size_t channels;
+	} reg_class[P2P_MAX_REG_CLASSES];
+
+	/*  reg_classes - Number of reg_class entries in use */
+	size_t reg_classes;
+};
+
+struct p2p_oper_class_map {
+	enum hw_mode {IEEE80211G} mode;
+	u8 op_class;
+	u8 min_chan;
+	u8 max_chan;
+	u8 inc;
+	enum {BW20, BW40PLUS, BW40MINUS} bw;
+};
+
+struct mlme_ext_priv {
+	struct adapter	*padapter;
+	u8	mlmeext_init;
+	ATOMIC_T	event_seq;
+	u16	mgnt_seq;
+
+	unsigned char	cur_channel;
+	unsigned char	cur_bwmode;
+	unsigned char	cur_ch_offset;/* PRIME_CHNL_OFFSET */
+	unsigned char	cur_wireless_mode;	/*  NETWORK_TYPE */
+
+	unsigned char	oper_channel; /* saved chan info when call
+				       * set_channel_bw */
+	unsigned char	oper_bwmode;
+	unsigned char	oper_ch_offset;/* PRIME_CHNL_OFFSET */
+
+	unsigned char	max_chan_nums;
+	struct rt_channel_info channel_set[MAX_CHANNEL_NUM];
+	struct p2p_channels channel_list;
+	unsigned char	basicrate[NumRates];
+	unsigned char	datarate[NumRates];
+
+	struct ss_res		sitesurvey_res;
+	struct mlme_ext_info	mlmext_info;/* for sta/adhoc mode, including
+					     * current scan/connecting/connected
+					     * related info. For ap mode,
+					     * network includes ap's cap_info*/
+	struct timer_list survey_timer;
+	struct timer_list link_timer;
+	u16	chan_scan_time;
+
+	u8	scan_abort;
+	u8	tx_rate; /*  TXRATE when USERATE is set. */
+
+	u32	retry; /* retry for issue probereq */
+
+	u64 TSFValue;
+
+#ifdef CONFIG_88EU_AP_MODE
+	unsigned char bstart_bss;
+#endif
+	u8 update_channel_plan_by_ap_done;
+	/* recv_decache check for Action_public frame */
+	u8 action_public_dialog_token;
+	u16	 action_public_rxseq;
+	u8 active_keep_alive_check;
+};
+
+int init_mlme_ext_priv(struct adapter *adapter);
+int init_hw_mlme_ext(struct adapter *padapter);
+void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext);
+extern void init_mlme_ext_timer(struct adapter *padapter);
+extern void init_addba_retry_timer(struct adapter *adapt, struct sta_info *sta);
+extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv);
+
+unsigned char networktype_to_raid(unsigned char network_type);
+u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int len);
+void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *len);
+void UpdateBrateTbl(struct adapter *padapter, u8 *mBratesOS);
+void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen);
+
+void Save_DM_Func_Flag(struct adapter *padapter);
+void Restore_DM_Func_Flag(struct adapter *padapter);
+void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable);
+
+void Set_MSR(struct adapter *padapter, u8 type);
+
+u8 rtw_get_oper_ch(struct adapter *adapter);
+void rtw_set_oper_ch(struct adapter *adapter, u8 ch);
+u8 rtw_get_oper_bw(struct adapter *adapter);
+void rtw_set_oper_bw(struct adapter *adapter, u8 bw);
+u8 rtw_get_oper_choffset(struct adapter *adapter);
+void rtw_set_oper_choffset(struct adapter *adapter, u8 offset);
+
+void set_channel_bwmode(struct adapter *padapter, unsigned char channel,
+			unsigned char channel_offset, unsigned short bwmode);
+void SelectChannel(struct adapter *padapter, unsigned char channel);
+void SetBWMode(struct adapter *padapter, unsigned short bwmode,
+	       unsigned char channel_offset);
+
+unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval);
+
+void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key);
+void clear_cam_entry(struct adapter *padapter, u8 entry);
+
+void invalidate_cam_all(struct adapter *padapter);
+void CAM_empty_entry(struct adapter * Adapter, u8 ucIndex);
+
+int allocate_fw_sta_entry(struct adapter *padapter);
+void flush_all_cam_entry(struct adapter *padapter);
+
+void site_survey(struct adapter *padapter);
+u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame,
+		    struct wlan_bssid_ex *bssid);
+void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
+		    struct adapter *adapter, bool update_ie);
+
+int get_bsstype(unsigned short capability);
+u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork);
+u16 get_beacon_interval(struct wlan_bssid_ex *bss);
+
+int is_client_associated_to_ap(struct adapter *padapter);
+int is_client_associated_to_ibss(struct adapter *padapter);
+int is_IBSS_empty(struct adapter *padapter);
+
+unsigned char check_assoc_AP(u8 *pframe, uint len);
+
+int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void WMMOnAssocRsp(struct adapter *padapter);
+
+void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void HTOnAssocRsp(struct adapter *padapter);
+
+void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
+void VCS_update(struct adapter *padapter, struct sta_info *psta);
+
+void update_beacon_info(struct adapter *padapter, u8 *pframe, uint len,
+		        struct sta_info *psta);
+int rtw_check_bcn_info(struct adapter  *Adapter, u8 *pframe, u32 packet_len);
+void update_IOT_info(struct adapter *padapter);
+void update_capinfo(struct adapter *adapter, u16 updatecap);
+void update_wireless_mode(struct adapter *padapter);
+void update_tx_basic_rate(struct adapter *padapter, u8 modulation);
+void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id);
+int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie,
+			    uint var_ie_len, int cam_idx);
+
+/* for sta/adhoc mode */
+void update_sta_info(struct adapter *padapter, struct sta_info *psta);
+unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz);
+unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz);
+unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps);
+void Update_RA_Entry(struct adapter *padapter, u32 mac_id);
+void set_sta_rate(struct adapter *padapter, struct sta_info *psta);
+
+unsigned int receive_disconnect(struct adapter *padapter,
+				unsigned char *macaddr, unsigned short reason);
+
+unsigned char get_highest_rate_idx(u32 mask);
+int support_short_GI(struct adapter *padapter, struct HT_caps_element *caps);
+unsigned int is_ap_in_tkip(struct adapter *padapter);
+unsigned int is_ap_in_wep(struct adapter *padapter);
+unsigned int should_forbid_n_rate(struct adapter *padapter);
+
+void report_join_res(struct adapter *padapter, int res);
+void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame);
+void report_surveydone_event(struct adapter *padapter);
+void report_del_sta_event(struct adapter *padapter,
+			  unsigned char *addr, unsigned short reason);
+void report_add_sta_event(struct adapter *padapter, unsigned char* addr,
+			  int cam_idx);
+
+void beacon_timing_control(struct adapter *padapter);
+extern u8 set_tx_beacon_cmd(struct adapter*padapter);
+unsigned int setup_beacon_frame(struct adapter *padapter,
+				unsigned char *beacon_frame);
+void update_mgnt_tx_rate(struct adapter *padapter, u8 rate);
+void update_mgntframe_attrib(struct adapter *padapter,
+			     struct pkt_attrib *pattrib);
+void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe);
+s32 dump_mgntframe_and_wait(struct adapter *padapter,
+			    struct xmit_frame *pmgntframe, int timeout_ms);
+s32 dump_mgntframe_and_wait_ack(struct adapter *padapter,
+				struct xmit_frame *pmgntframe);
+
+#ifdef CONFIG_88EU_P2P
+void issue_probersp_p2p(struct adapter *padapter, unsigned char *da);
+void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid,
+				 u8 ussidlen, u8 *pdev_raddr);
+void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr);
+void issue_probereq_p2p(struct adapter *padapter, u8 *da);
+int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt,
+			  int wait_ms);
+void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr,
+				   u8 dialogToken, u8 success);
+void issue_p2p_invitation_request(struct adapter *padapter, u8* raddr);
+#endif /* CONFIG_88EU_P2P */
+void issue_beacon(struct adapter *padapter, int timeout_ms);
+void issue_probersp(struct adapter *padapter, unsigned char *da,
+		    u8 is_valid_p2p_probereq);
+void issue_assocreq(struct adapter *padapter);
+void issue_asocrsp(struct adapter *padapter, unsigned short status,
+		   struct sta_info *pstat, int pkt_type);
+void issue_auth(struct adapter *padapter, struct sta_info *psta,
+		unsigned short status);
+void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid,
+		    u8 *da);
+s32 issue_probereq_ex(struct adapter *adapter, struct ndis_802_11_ssid *pssid,
+		      u8* da, int try_cnt, int wait_ms);
+int issue_nulldata(struct adapter *padapter, unsigned char *da,
+		   unsigned int power_mode, int try_cnt, int wait_ms);
+int issue_qos_nulldata(struct adapter *padapter, unsigned char *da,
+		       u16 tid, int try_cnt, int wait_ms);
+int issue_deauth(struct adapter *padapter, unsigned char *da,
+		 unsigned short reason);
+int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason,
+		    int try_cnt, int wait_ms);
+void issue_action_spct_ch_switch(struct adapter *padapter, u8 *ra, u8 new_ch,
+				 u8 ch_offset);
+void issue_action_BA(struct adapter *padapter, unsigned char *raddr,
+		     unsigned char action, unsigned short status);
+unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr);
+unsigned int send_beacon(struct adapter *padapter);
+
+void start_clnt_assoc(struct adapter *padapter);
+void start_clnt_auth(struct adapter *padapter);
+void start_clnt_join(struct adapter *padapter);
+void start_create_ibss(struct adapter *padapter);
+
+unsigned int OnAssocReq(struct adapter *padapter,
+			union recv_frame *precv_frame);
+unsigned int OnAssocRsp(struct adapter *padapter,
+			union recv_frame *precv_frame);
+unsigned int OnProbeReq(struct adapter *padapter,
+			union recv_frame *precv_frame);
+unsigned int OnProbeRsp(struct adapter *padapter,
+			union recv_frame *precv_frame);
+unsigned int DoReserved(struct adapter *padapter,
+			union recv_frame *precv_frame);
+unsigned int OnBeacon(struct adapter *padapter,
+		      union recv_frame *precv_frame);
+unsigned int OnAtim(struct adapter *padapter,
+		    union recv_frame *precv_frame);
+unsigned int OnDisassoc(struct adapter *padapter,
+			union recv_frame *precv_frame);
+unsigned int OnAuth(struct adapter *padapter,
+		    union recv_frame *precv_frame);
+unsigned int OnAuthClient(struct adapter *padapter,
+			  union recv_frame *precv_frame);
+unsigned int OnDeAuth(struct adapter *padapter,
+		      union recv_frame *precv_frame);
+unsigned int OnAction(struct adapter *padapter,
+		      union recv_frame *precv_frame);
+
+unsigned int on_action_spct(struct adapter *padapter,
+			    union recv_frame *precv_frame);
+unsigned int OnAction_qos(struct adapter *padapter,
+			  union recv_frame *precv_frame);
+unsigned int OnAction_dls(struct adapter *padapter,
+			  union recv_frame *precv_frame);
+unsigned int OnAction_back(struct adapter *padapter,
+			   union recv_frame *precv_frame);
+unsigned int on_action_public(struct adapter *padapter,
+			      union recv_frame *precv_frame);
+unsigned int OnAction_ht(struct adapter *padapter,
+			 union recv_frame *precv_frame);
+unsigned int OnAction_wmm(struct adapter *padapter,
+			  union recv_frame *precv_frame);
+unsigned int OnAction_p2p(struct adapter *padapter,
+			  union recv_frame *precv_frame);
+
+void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res);
+void mlmeext_sta_del_event_callback(struct adapter *padapter);
+void mlmeext_sta_add_event_callback(struct adapter *padapter,
+				    struct sta_info *psta);
+
+void linked_status_chk(struct adapter *padapter);
+
+void survey_timer_hdl (struct adapter *padapter);
+void link_timer_hdl (struct adapter *padapter);
+void addba_timer_hdl(struct sta_info *psta);
+
+#define set_survey_timer(mlmeext, ms) \
+	do { \
+		_set_timer(&(mlmeext)->survey_timer, (ms)); \
+	} while (0)
+
+#define set_link_timer(mlmeext, ms) \
+	do { \
+		_set_timer(&(mlmeext)->link_timer, (ms)); \
+	} while (0)
+
+int cckrates_included(unsigned char *rate, int ratelen);
+int cckratesonly_included(unsigned char *rate, int ratelen);
+
+void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr);
+
+void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len);
+void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext);
+
+struct cmd_hdl {
+	uint	parmsize;
+	u8 (*h2cfuns)(struct adapter  *padapter, u8 *pbuf);
+};
+
+u8 read_macreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 write_macreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 read_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 write_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 read_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 write_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
+u8 NULL_hdl(struct adapter *padapter, u8 *pbuf);
+u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf);
+u8 disconnect_hdl(struct adapter *padapter, u8 *pbuf);
+u8 createbss_hdl(struct adapter *padapter, u8 *pbuf);
+u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf);
+u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf);
+u8 setauth_hdl(struct adapter *padapter, u8 *pbuf);
+u8 setkey_hdl(struct adapter *padapter, u8 *pbuf);
+u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf);
+u8 set_assocsta_hdl(struct adapter *padapter, u8 *pbuf);
+u8 del_assocsta_hdl(struct adapter *padapter, u8 *pbuf);
+u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf);
+
+u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf);
+u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf);
+/* Handling DFS channel switch announcement ie. */
+u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf);
+u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf);
+
+#define GEN_DRV_CMD_HANDLER(size, cmd)	{size, &cmd ## _hdl},
+#define GEN_MLME_EXT_HANDLER(size, cmd)	{size, cmd},
+
+#ifdef _RTW_CMD_C_
+
+static struct cmd_hdl wlancmds[] = {
+	GEN_DRV_CMD_HANDLER(0, NULL) /*0*/
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_DRV_CMD_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL) /*10*/
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct joinbss_parm), join_cmd_hdl) /*14*/
+	GEN_MLME_EXT_HANDLER(sizeof (struct disconnect_parm), disconnect_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof (struct createbss_parm), createbss_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof (struct setopmode_parm), setopmode_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof (struct sitesurvey_parm),
+			     sitesurvey_cmd_hdl) /*18*/
+	GEN_MLME_EXT_HANDLER(sizeof (struct setauth_parm), setauth_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof (struct setkey_parm), setkey_hdl) /*20*/
+	GEN_MLME_EXT_HANDLER(sizeof (struct set_stakey_parm), set_stakey_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof (struct set_assocsta_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct del_assocsta_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct setstapwrstate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct setbasicrate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct getbasicrate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct setdatarate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct getdatarate_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct setphyinfo_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), NULL)  /*30*/
+	GEN_MLME_EXT_HANDLER(sizeof (struct setphy_parm), NULL)
+	GEN_MLME_EXT_HANDLER(sizeof (struct getphy_parm), NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)	/*40*/
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl)
+	GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl) /* 46 */
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL) /*50*/
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(0, NULL)
+	GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param),
+			     tx_beacon_hdl) /*55*/
+
+	GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl) /*56*/
+	GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl) /*57*/
+
+	GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl) /*58*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param),
+			     set_chplan_hdl) /*59*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param),
+			     led_blink_hdl) /*60*/
+
+	GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param),
+			     set_csa_hdl) /*61*/
+	GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param),
+			     tdls_hdl) /*62*/
+};
+
+#endif
+
+struct C2HEvent_Header {
+#ifdef __LITTLE_ENDIAN
+	unsigned int len:16;
+	unsigned int ID:8;
+	unsigned int seq:8;
+#elif defined(__BIG_ENDIAN)
+	unsigned int seq:8;
+	unsigned int ID:8;
+	unsigned int len:16;
+#endif
+	unsigned int rsvd;
+};
+
+void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_fwdbg_event_callback(struct adapter *adapter, u8 *pbuf);
+
+enum rtw_c2h_event {
+	GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/
+	GEN_EVT_CODE(_Read_BBREG),
+	GEN_EVT_CODE(_Read_RFREG),
+	GEN_EVT_CODE(_Read_EEPROM),
+	GEN_EVT_CODE(_Read_EFUSE),
+	GEN_EVT_CODE(_Read_CAM),	/*5*/
+	GEN_EVT_CODE(_Get_BasicRate),
+	GEN_EVT_CODE(_Get_DataRate),
+	GEN_EVT_CODE(_Survey),	 /*8*/
+	GEN_EVT_CODE(_SurveyDone),	 /*9*/
+
+	GEN_EVT_CODE(_JoinBss) , /*10*/
+	GEN_EVT_CODE(_AddSTA),
+	GEN_EVT_CODE(_DelSTA),
+	GEN_EVT_CODE(_AtimDone),
+	GEN_EVT_CODE(_TX_Report),
+	GEN_EVT_CODE(_CCX_Report),		/*15*/
+	GEN_EVT_CODE(_DTM_Report),
+	GEN_EVT_CODE(_TX_Rate_Statistics),
+	GEN_EVT_CODE(_C2HLBK),
+	GEN_EVT_CODE(_FWDBG),
+	GEN_EVT_CODE(_C2HFEEDBACK),             /*20*/
+	GEN_EVT_CODE(_ADDBA),
+	GEN_EVT_CODE(_C2HBCN),
+	GEN_EVT_CODE(_ReportPwrState),	/* filen: only for PCIE, USB */
+	GEN_EVT_CODE(_CloseRF),		/* filen: only for PCIE,
+					 * work around ASPM */
+	MAX_C2HEVT
+};
+
+
+#ifdef _RTW_MLME_EXT_C_
+
+static struct fwevent wlanevents[] = {
+	{0, rtw_dummy_event_callback},	/*0*/
+	{0, NULL},
+	{0, NULL},
+	{0, NULL},
+	{0, NULL},
+	{0, NULL},
+	{0, NULL},
+	{0, NULL},
+	{0, &rtw_survey_event_callback},		/*8*/
+	{sizeof (struct surveydone_event), &rtw_surveydone_event_callback},/*9*/
+	{0, &rtw_joinbss_event_callback},		/*10*/
+	{sizeof(struct stassoc_event), &rtw_stassoc_event_callback},
+	{sizeof(struct stadel_event), &rtw_stadel_event_callback},
+	{0, &rtw_atimdone_event_callback},
+	{0, rtw_dummy_event_callback},
+	{0, NULL},	/*15*/
+	{0, NULL},
+	{0, NULL},
+	{0, NULL},
+	{0, rtw_fwdbg_event_callback},
+	{0, NULL},	 /*20*/
+	{0, NULL},
+	{0, NULL},
+	{0, &rtw_cpwm_event_callback},
+};
+
+#endif/* _RTL_MLME_EXT_C_ */
+
+#endif /* __RTW_MLME_EXT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mp.h b/drivers/staging/rtl8188eu/include/rtw_mp.h
new file mode 100644
index 0000000..59bdbb5
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mp.h
@@ -0,0 +1,495 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_MP_H_
+#define _RTW_MP_H_
+
+/*	00 - Success */
+/*	11 - Error */
+#define STATUS_SUCCESS				(0x00000000L)
+#define STATUS_PENDING				(0x00000103L)
+
+#define STATUS_UNSUCCESSFUL			(0xC0000001L)
+#define STATUS_INSUFFICIENT_RESOURCES		(0xC000009AL)
+#define STATUS_NOT_SUPPORTED			(0xC00000BBL)
+
+#define NDIS_STATUS_SUCCESS			((int)STATUS_SUCCESS)
+#define NDIS_STATUS_PENDING			((int)STATUS_PENDING)
+#define NDIS_STATUS_NOT_RECOGNIZED		((int)0x00010001L)
+#define NDIS_STATUS_NOT_COPIED			((int)0x00010002L)
+#define NDIS_STATUS_NOT_ACCEPTED		((int)0x00010003L)
+#define NDIS_STATUS_CALL_ACTIVE			((int)0x00010007L)
+
+#define NDIS_STATUS_FAILURE			((int)STATUS_UNSUCCESSFUL)
+#define NDIS_STATUS_RESOURCES		((int)STATUS_INSUFFICIENT_RESOURCES)
+#define NDIS_STATUS_CLOSING			((int)0xC0010002L)
+#define NDIS_STATUS_BAD_VERSION			((int)0xC0010004L)
+#define NDIS_STATUS_BAD_CHARACTERISTICS		((int)0xC0010005L)
+#define NDIS_STATUS_ADAPTER_NOT_FOUND		((int)0xC0010006L)
+#define NDIS_STATUS_OPEN_FAILED			((int)0xC0010007L)
+#define NDIS_STATUS_DEVICE_FAILED		((int)0xC0010008L)
+#define NDIS_STATUS_MULTICAST_FULL		((int)0xC0010009L)
+#define NDIS_STATUS_MULTICAST_EXISTS		((int)0xC001000AL)
+#define NDIS_STATUS_MULTICAST_NOT_FOUND		((int)0xC001000BL)
+#define NDIS_STATUS_REQUEST_ABORTED		((int)0xC001000CL)
+#define NDIS_STATUS_RESET_IN_PROGRESS		((int)0xC001000DL)
+#define NDIS_STATUS_CLOSING_INDICATING		((int)0xC001000EL)
+#define NDIS_STATUS_NOT_SUPPORTED		((int)STATUS_NOT_SUPPORTED)
+#define NDIS_STATUS_INVALID_PACKET		((int)0xC001000FL)
+#define NDIS_STATUS_OPEN_LIST_FULL		((int)0xC0010010L)
+#define NDIS_STATUS_ADAPTER_NOT_READY		((int)0xC0010011L)
+#define NDIS_STATUS_ADAPTER_NOT_OPEN		((int)0xC0010012L)
+#define NDIS_STATUS_NOT_INDICATING		((int)0xC0010013L)
+#define NDIS_STATUS_INVALID_LENGTH		((int)0xC0010014L)
+#define NDIS_STATUS_INVALID_DATA		((int)0xC0010015L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT		((int)0xC0010016L)
+#define NDIS_STATUS_INVALID_OID			((int)0xC0010017L)
+#define NDIS_STATUS_ADAPTER_REMOVED		((int)0xC0010018L)
+#define NDIS_STATUS_UNSUPPORTED_MEDIA		((int)0xC0010019L)
+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE	((int)0xC001001AL)
+#define NDIS_STATUS_FILE_NOT_FOUND		((int)0xC001001BL)
+#define NDIS_STATUS_ERROR_READING_FILE		((int)0xC001001CL)
+#define NDIS_STATUS_ALREADY_MAPPED		((int)0xC001001DL)
+#define NDIS_STATUS_RESOURCE_CONFLICT		((int)0xC001001EL)
+#define NDIS_STATUS_NO_CABLE			((int)0xC001001FL)
+
+#define NDIS_STATUS_INVALID_SAP			((int)0xC0010020L)
+#define NDIS_STATUS_SAP_IN_USE			((int)0xC0010021L)
+#define NDIS_STATUS_INVALID_ADDRESS		((int)0xC0010022L)
+#define NDIS_STATUS_VC_NOT_ACTIVATED		((int)0xC0010023L)
+#define NDIS_STATUS_DEST_OUT_OF_ORDER		((int)0xC0010024L)  /*cause 27*/
+#define NDIS_STATUS_VC_NOT_AVAILABLE		((int)0xC0010025L)  /*cause 35,45 */
+#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE	((int)0xC0010026L)  /*cause 37*/
+#define NDIS_STATUS_INCOMPATABLE_QOS		((int)0xC0010027L)  /*cause 49*/
+#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED	((int)0xC0010028L)  /*cause 93*/
+#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION	((int)0xC0010029L)  /*cause 3 */
+
+enum antenna_path {
+	ANTENNA_NONE = 0x00,
+	ANTENNA_D,
+	ANTENNA_C,
+	ANTENNA_CD,
+	ANTENNA_B,
+	ANTENNA_BD,
+	ANTENNA_BC,
+	ANTENNA_BCD,
+	ANTENNA_A,
+	ANTENNA_AD,
+	ANTENNA_AC,
+	ANTENNA_ACD,
+	ANTENNA_AB,
+	ANTENNA_ABD,
+	ANTENNA_ABC,
+	ANTENNA_ABCD
+};
+
+
+#define MAX_MP_XMITBUF_SZ	2048
+#define NR_MP_XMITFRAME		8
+
+struct mp_xmit_frame {
+	struct list_head list;
+	struct pkt_attrib attrib;
+	struct sk_buff *pkt;
+	int frame_tag;
+	struct adapter *padapter;
+	struct urb *pxmit_urb[8];
+	/* insert urb, irp, and irpcnt info below... */
+	u8 *mem_addr;
+	u32 sz[8];
+	u8 bpending[8];
+	int ac_tag[8];
+	int last[8];
+	uint irpcnt;
+	uint fragcnt;
+	uint mem[(MAX_MP_XMITBUF_SZ >> 2)];
+};
+
+struct mp_wiparam {
+	u32 bcompleted;
+	u32 act_type;
+	u32 io_offset;
+	u32 io_value;
+};
+
+typedef void(*wi_act_func)(void *padapter);
+
+struct mp_tx {
+	u8 stop;
+	u32 count, sended;
+	u8 payload;
+	struct pkt_attrib attrib;
+	struct tx_desc desc;
+	u8 *pallocated_buf;
+	u8 *buf;
+	u32 buf_size, write_size;
+	void *PktTxThread;
+};
+
+#include <Hal8188EPhyCfg.h>
+
+#define MP_MAX_LINES		1000
+#define MP_MAX_LINES_BYTES	256
+
+typedef void (*MPT_WORK_ITEM_HANDLER)(void *Adapter);
+
+struct mpt_context {
+	/*  Indicate if we have started Mass Production Test. */
+	bool			bMassProdTest;
+
+	/*  Indicate if the driver is unloading or unloaded. */
+	bool			bMptDrvUnload;
+
+	struct semaphore MPh2c_Sema;
+	struct timer_list MPh2c_timeout_timer;
+/*  Event used to sync H2c for BT control */
+
+	bool		MptH2cRspEvent;
+	bool		MptBtC2hEvent;
+	bool		bMPh2c_timeout;
+
+	/* 8190 PCI does not support NDIS_WORK_ITEM. */
+	/*  Work Item for Mass Production Test. */
+	/*  Event used to sync the case unloading driver and MptWorkItem
+	 *  is still in progress. */
+	/*  Indicate a MptWorkItem is scheduled and not yet finished. */
+	bool			bMptWorkItemInProgress;
+	/*  An instance which implements function and context of MptWorkItem. */
+	MPT_WORK_ITEM_HANDLER	CurrMptAct;
+
+	/*  1=Start, 0=Stop from UI. */
+	u32	MptTestStart;
+	/*  _TEST_MODE, defined in MPT_Req2.h */
+	u32	MptTestItem;
+	/*  Variable needed in each implementation of CurrMptAct. */
+	u32	MptActType;	/*  Type of action performed in CurrMptAct. */
+	/*  The Offset of IO operation is depend of MptActType. */
+	u32	MptIoOffset;
+	/*  The Value of IO operation is depend of MptActType. */
+	u32	MptIoValue;
+	/*  The RfPath of IO operation is depend of MptActType. */
+	u32	MptRfPath;
+
+	enum wireless_mode MptWirelessModeToSw;	/*  Wireless mode to switch. */
+	u8	MptChannelToSw;		/*  Channel to switch. */
+	u8	MptInitGainToSet;	/*  Initial gain to set. */
+	u32	MptBandWidth;		/*  bandwidth to switch. */
+	u32	MptRateIndex;		/*  rate index. */
+	/*  Register value kept for Single Carrier Tx test. */
+	u8	btMpCckTxPower;
+	/*  Register value kept for Single Carrier Tx test. */
+	u8	btMpOfdmTxPower;
+	/*  For MP Tx Power index */
+	u8	TxPwrLevel[2];	/*  rf-A, rf-B */
+
+	/*  Content of RCR Regsiter for Mass Production Test. */
+	u32	MptRCR;
+	/*  true if we only receive packets with specific pattern. */
+	bool	bMptFilterPattern;
+	/*  Rx OK count, statistics used in Mass Production Test. */
+	u32	MptRxOkCnt;
+	/*  Rx CRC32 error count, statistics used in Mass Production Test. */
+	u32	MptRxCrcErrCnt;
+
+	bool	bCckContTx;	/*  true if we are in CCK Continuous Tx test. */
+	bool	bOfdmContTx;	/*  true if we are in OFDM Continuous Tx test. */
+	bool	bStartContTx;	/*  true if we have start Continuous Tx test. */
+	/*  true if we are in Single Carrier Tx test. */
+	bool	bSingleCarrier;
+	/*  true if we are in Carrier Suppression Tx Test. */
+	bool	bCarrierSuppression;
+	/* true if we are in Single Tone Tx test. */
+	bool	bSingleTone;
+
+	/*  ACK counter asked by K.Y.. */
+	bool	bMptEnableAckCounter;
+	u32	MptAckCounter;
+
+	u8	APK_bound[2];	/* for APK	path A/path B */
+	bool	bMptIndexEven;
+
+	u8	backup0xc50;
+	u8	backup0xc58;
+	u8	backup0xc30;
+	u8	backup0x52_RF_A;
+	u8	backup0x52_RF_B;
+
+	u8	h2cReqNum;
+	u8	c2hBuf[20];
+
+	u8	btInBuf[100];
+	u32	mptOutLen;
+	u8	mptOutBuf[100];
+};
+
+enum {
+	WRITE_REG = 1,
+	READ_REG,
+	WRITE_RF,
+	READ_RF,
+	MP_START,
+	MP_STOP,
+	MP_RATE,
+	MP_CHANNEL,
+	MP_BANDWIDTH,
+	MP_TXPOWER,
+	MP_ANT_TX,
+	MP_ANT_RX,
+	MP_CTX,
+	MP_QUERY,
+	MP_ARX,
+	MP_PSD,
+	MP_PWRTRK,
+	MP_THER,
+	MP_IOCTL,
+	EFUSE_GET,
+	EFUSE_SET,
+	MP_RESET_STATS,
+	MP_DUMP,
+	MP_PHYPARA,
+	MP_SetRFPathSwh,
+	MP_QueryDrvStats,
+	MP_SetBT,
+	CTA_TEST,
+	MP_NULL,
+};
+
+struct mp_priv {
+	struct adapter *papdater;
+
+	/* Testing Flag */
+	/* 0 for normal type packet, 1 for loopback packet (16bytes TXCMD) */
+	u32 mode;
+
+	u32 prev_fw_state;
+
+	/* OID cmd handler */
+	struct mp_wiparam workparam;
+
+	/* Tx Section */
+	u8 TID;
+	u32 tx_pktcount;
+	struct mp_tx tx;
+
+	/* Rx Section */
+	u32 rx_pktcount;
+	u32 rx_crcerrpktcount;
+	u32 rx_pktloss;
+
+	struct recv_stat rxstat;
+
+	/* RF/BB relative */
+	u8 channel;
+	u8 bandwidth;
+	u8 prime_channel_offset;
+	u8 txpoweridx;
+	u8 txpoweridx_b;
+	u8 rateidx;
+	u32 preamble;
+	u32 CrystalCap;
+
+	u16 antenna_tx;
+	u16 antenna_rx;
+
+	u8 check_mp_pkt;
+
+	u8 bSetTxPower;
+
+	struct wlan_network mp_network;
+	unsigned char network_macaddr[ETH_ALEN];
+
+	u8 *pallocated_mp_xmitframe_buf;
+	u8 *pmp_xmtframe_buf;
+	struct __queue free_mp_xmitqueue;
+	u32 free_mp_xmitframe_cnt;
+
+	struct mpt_context MptCtx;
+};
+
+struct iocmd_struct {
+	u8	cmdclass;
+	u16	value;
+	u8	index;
+};
+
+struct rf_reg_param {
+	u32 path;
+	u32 offset;
+	u32 value;
+};
+
+struct bb_reg_param {
+	u32 offset;
+	u32 value;
+};
+/*  */
+
+#define LOWER	true
+#define RAISE	false
+
+/* Hardware Registers */
+#define BB_REG_BASE_ADDR		0x800
+
+/* MP variables */
+enum mp_mode_{
+	MP_OFF,
+	MP_ON,
+	MP_ERR,
+	MP_CONTINUOUS_TX,
+	MP_SINGLE_CARRIER_TX,
+	MP_CARRIER_SUPPRISSION_TX,
+	MP_SINGLE_TONE_TX,
+	MP_PACKET_TX,
+	MP_PACKET_RX
+};
+
+#define MAX_RF_PATH_NUMS	RF_PATH_MAX
+
+extern u8 mpdatarate[NumRates];
+
+/* MP set force data rate base on the definition. */
+enum mpt_rate_index {
+	/* CCK rate. */
+	MPT_RATE_1M,	/* 0 */
+	MPT_RATE_2M,
+	MPT_RATE_55M,
+	MPT_RATE_11M,	/* 3 */
+
+	/* OFDM rate. */
+	MPT_RATE_6M,	/* 4 */
+	MPT_RATE_9M,
+	MPT_RATE_12M,
+	MPT_RATE_18M,
+	MPT_RATE_24M,
+	MPT_RATE_36M,
+	MPT_RATE_48M,
+	MPT_RATE_54M,	/* 11 */
+
+	/* HT rate. */
+	MPT_RATE_MCS0,	/* 12 */
+	MPT_RATE_MCS1,
+	MPT_RATE_MCS2,
+	MPT_RATE_MCS3,
+	MPT_RATE_MCS4,
+	MPT_RATE_MCS5,
+	MPT_RATE_MCS6,
+	MPT_RATE_MCS7,	/* 19 */
+	MPT_RATE_MCS8,
+	MPT_RATE_MCS9,
+	MPT_RATE_MCS10,
+	MPT_RATE_MCS11,
+	MPT_RATE_MCS12,
+	MPT_RATE_MCS13,
+	MPT_RATE_MCS14,
+	MPT_RATE_MCS15,	/* 27 */
+	MPT_RATE_LAST
+};
+
+#define MAX_TX_PWR_INDEX_N_MODE 64	/*  0x3F */
+
+enum power_mode {
+	POWER_LOW = 0,
+	POWER_NORMAL
+};
+
+#define RX_PKT_BROADCAST	1
+#define RX_PKT_DEST_ADDR	2
+#define RX_PKT_PHY_MATCH	3
+
+enum encry_ctrl_state {
+	HW_CONTROL,		/* hw encryption& decryption */
+	SW_CONTROL,		/* sw encryption& decryption */
+	HW_ENCRY_SW_DECRY,	/* hw encryption & sw decryption */
+	SW_ENCRY_HW_DECRY	/* sw encryption & hw decryption */
+};
+
+s32 init_mp_priv(struct adapter *padapter);
+void free_mp_priv(struct mp_priv *pmp_priv);
+s32 MPT_InitializeAdapter(struct adapter *padapter, u8 Channel);
+void MPT_DeInitAdapter(struct adapter *padapter);
+s32 mp_start_test(struct adapter *padapter);
+void mp_stop_test(struct adapter *padapter);
+
+u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask);
+void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val);
+
+u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz);
+void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz);
+u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask);
+void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val);
+u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr);
+void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val);
+
+void	SetChannel(struct adapter *pAdapter);
+void	SetBandwidth(struct adapter *pAdapter);
+void	SetTxPower(struct adapter *pAdapter);
+void	SetAntennaPathPower(struct adapter *pAdapter);
+void	SetDataRate(struct adapter *pAdapter);
+
+void	SetAntenna(struct adapter *pAdapter);
+
+s32	SetThermalMeter(struct adapter *pAdapter, u8 target_ther);
+void	GetThermalMeter(struct adapter *pAdapter, u8 *value);
+
+void	SetContinuousTx(struct adapter *pAdapter, u8 bStart);
+void	SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart);
+void	SetSingleToneTx(struct adapter *pAdapter, u8 bStart);
+void	SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart);
+void PhySetTxPowerLevel(struct adapter *pAdapter);
+
+void	fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc);
+void	SetPacketTx(struct adapter *padapter);
+void	SetPacketRx(struct adapter *pAdapter, u8 bStartRx);
+
+void	ResetPhyRxPktCount(struct adapter *pAdapter);
+u32	GetPhyRxPktReceived(struct adapter *pAdapter);
+u32	GetPhyRxPktCRC32Error(struct adapter *pAdapter);
+
+s32	SetPowerTracking(struct adapter *padapter, u8 enable);
+void	GetPowerTracking(struct adapter *padapter, u8 *enable);
+u32	mp_query_psd(struct adapter *pAdapter, u8 *data);
+void Hal_SetAntenna(struct adapter *pAdapter);
+void Hal_SetBandwidth(struct adapter *pAdapter);
+void Hal_SetTxPower(struct adapter *pAdapter);
+void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart);
+void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart);
+void Hal_SetSingleCarrierTx (struct adapter *pAdapter, u8 bStart);
+void Hal_SetContinuousTx (struct adapter *pAdapter, u8 bStart);
+void Hal_SetBandwidth(struct adapter *pAdapter);
+void Hal_SetDataRate(struct adapter *pAdapter);
+void Hal_SetChannel(struct adapter *pAdapter);
+void Hal_SetAntennaPathPower(struct adapter *pAdapter);
+s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther);
+s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable);
+void Hal_GetPowerTracking(struct adapter *padapter, u8 * enable);
+void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value);
+void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter);
+void Hal_MPT_CCKTxPowerAdjust(struct adapter * Adapter, bool bInCH14);
+void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven);
+void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 * TxPower);
+void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 * TxPower);
+void Hal_TriggerRFThermalMeter(struct adapter *pAdapter);
+u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter);
+void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart);
+void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart);
+void Hal_ProSetCrystalCap (struct adapter *pAdapter , u32 CrystalCapVal);
+void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv);
+void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter ,bool bMain);
+
+#endif /* _RTW_MP_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h b/drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h
new file mode 100644
index 0000000..494e90e
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mp_ioctl.h
@@ -0,0 +1,340 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_MP_IOCTL_H_
+#define _RTW_MP_IOCTL_H_
+
+#include <drv_types.h>
+#include <mp_custom_oid.h>
+#include <rtw_ioctl.h>
+#include <rtw_ioctl_rtl.h>
+#include <rtw_efuse.h>
+#include <rtw_mp.h>
+
+/*  */
+struct cfg_dbg_msg_struct {
+	u32 DebugLevel;
+	u32 DebugComponent_H32;
+	u32 DebugComponent_L32;
+};
+
+struct mp_rw_reg {
+	u32 offset;
+	u32 width;
+	u32 value;
+};
+
+struct efuse_access_struct {
+	u16	start_addr;
+	u16	cnts;
+	u8	data[0];
+};
+
+struct burst_rw_reg {
+	u32 offset;
+	u32 len;
+	u8 Data[256];
+};
+
+struct usb_vendor_req {
+	u8	bRequest;
+	u16	wValue;
+	u16	wIndex;
+	u16	wLength;
+	u8	u8Dir;/* 0:OUT, 1:IN */
+	u8	u8InData;
+};
+
+struct dr_variable_struct {
+	u8 offset;
+	u32 variable;
+};
+
+#define _irqlevel_changed_(a, b)
+
+/* rtl8188eu_oid_rtl_seg_81_80_00 */
+int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_81_80_20 */
+int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_81_87 */
+int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_81_85 */
+int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
+
+/*  rtl8188eu_oid_rtl_seg_87_11_00 */
+int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv);
+int  rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv);
+/*  rtl8188eu_oid_rtl_seg_87_11_20 */
+int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv);
+/* rtl8188eu_oid_rtl_seg_87_11_50 */
+int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv);
+/* rtl8188eu_oid_rtl_seg_87_11_F0 */
+int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv);
+
+/* rtl8188eu_oid_rtl_seg_87_12_00 */
+int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *par_priv);
+int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv);
+int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv);
+
+#ifdef _RTW_MP_IOCTL_C_
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_00[] = {
+	{1, &oid_null_function},		/* 0x00	OID_RT_PRO_RESET_DUT */
+	{1, &rtl8188eu_oid_rt_pro_set_data_rate_hdl},	/* 0x01 */
+	{1, &rtl8188eu_oid_rt_pro_start_test_hdl},	/* 0x02 */
+	{1, &rtl8188eu_oid_rt_pro_stop_test_hdl},		/* 0x03 */
+	{1, &oid_null_function},	/* 0x04	OID_RT_PRO_SET_PREAMBLE */
+	{1, &oid_null_function},	/* 0x05	OID_RT_PRO_SET_SCRAMBLER */
+	{1, &oid_null_function},	/* 0x06	OID_RT_PRO_SET_FILTER_BB */
+	{1, &oid_null_function},/* 0x07	OID_RT_PRO_SET_MANUAL_DIVERSITY_BB */
+	{1, &rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl},	/* 0x08 */
+	{1, &oid_null_function},/* 0x09	OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL */
+	{1, &oid_null_function},/* 0x0A	OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL */
+	{1, &rtl8188eu_oid_rt_pro_set_continuous_tx_hdl},	/* 0x0B	OID_RT_PRO_SET_TX_CONTINUOUS_DIRECT_CALL */
+	{1, &rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl},/* 0x0C	OID_RT_PRO_SET_SINGLE_CARRIER_TX_CONTINUOUS */
+	{1, &oid_null_function},	/* 0x0D	OID_RT_PRO_SET_TX_ANTENNA_BB */
+	{1, &rtl8188eu_oid_rt_pro_set_antenna_bb_hdl},	/* 0x0E */
+	{1, &oid_null_function},		/* 0x0F	OID_RT_PRO_SET_CR_SCRAMBLER */
+	{1, &oid_null_function},		/* 0x10	OID_RT_PRO_SET_CR_NEW_FILTER */
+	{1, &rtl8188eu_oid_rt_pro_set_tx_power_control_hdl},/* 0x11 OID_RT_PRO_SET_TX_POWER_CONTROL */
+	{1, &oid_null_function},	/* 0x12	OID_RT_PRO_SET_CR_TX_CONFIG */
+	{1, &oid_null_function},	/* 0x13	OID_RT_PRO_GET_TX_POWER_CONTROL */
+	{1, &oid_null_function},	/* 0x14	OID_RT_PRO_GET_CR_SIGNAL_QUALITY */
+	{1, &oid_null_function},	/* 0x15	OID_RT_PRO_SET_CR_SETPOINT */
+	{1, &oid_null_function},	/* 0x16	OID_RT_PRO_SET_INTEGRATOR */
+	{1, &oid_null_function},	/* 0x17	OID_RT_PRO_SET_SIGNAL_QUALITY */
+	{1, &oid_null_function},	/* 0x18	OID_RT_PRO_GET_INTEGRATOR */
+	{1, &oid_null_function},	/* 0x19	OID_RT_PRO_GET_SIGNAL_QUALITY */
+	{1, &oid_null_function},	/* 0x1A	OID_RT_PRO_QUERY_EEPROM_TYPE */
+	{1, &oid_null_function},	/* 0x1B	OID_RT_PRO_WRITE_MAC_ADDRESS */
+	{1, &oid_null_function},	/* 0x1C	OID_RT_PRO_READ_MAC_ADDRESS */
+	{1, &oid_null_function},	/* 0x1D	OID_RT_PRO_WRITE_CIS_DATA */
+	{1, &oid_null_function},	/* 0x1E	OID_RT_PRO_READ_CIS_DATA */
+	{1, &oid_null_function}		/* 0x1F	OID_RT_PRO_WRITE_POWER_CONTROL */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_20[] = {
+	{1, &oid_null_function},	/* 0x20	OID_RT_PRO_READ_POWER_CONTROL */
+	{1, &oid_null_function},	/* 0x21	OID_RT_PRO_WRITE_EEPROM */
+	{1, &oid_null_function},	/* 0x22	OID_RT_PRO_READ_EEPROM */
+	{1, &rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl},	/* 0x23 */
+	{1, &rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl},	/* 0x24 */
+	{1, &rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl},	/* 0x25 */
+	{1, &rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl},	/* 0x26 */
+	{1, &rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl},	/* 0x27 */
+	{1, &oid_null_function},	/* 0x28	OID_RT_PRO_QUERY_CURRENT_ADDRESS */
+	{1, &oid_null_function},	/* 0x29	OID_RT_PRO_QUERY_PERMANENT_ADDRESS */
+	{1, &oid_null_function},	/* 0x2A	OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS */
+	{1, &rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl},/* 0x2B	OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX */
+	{1, &oid_null_function},	/* 0x2C	OID_RT_PRO_RECEIVE_PACKET */
+	{1, &oid_null_function},	/* 0x2D	OID_RT_PRO_WRITE_EEPROM_BYTE */
+	{1, &oid_null_function},	/* 0x2E	OID_RT_PRO_READ_EEPROM_BYTE */
+	{1, &rtl8188eu_oid_rt_pro_set_modulation_hdl}		/* 0x2F */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_40[] = {
+	{1, &oid_null_function},			/* 0x40 */
+	{1, &oid_null_function},			/* 0x41 */
+	{1, &oid_null_function},			/* 0x42 */
+	{1, &rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl},	/* 0x43 */
+	{1, &oid_null_function},			/* 0x44 */
+	{1, &oid_null_function}				/* 0x45 */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_80_80[] = {
+	{1, &oid_null_function},		/* 0x80	OID_RT_DRIVER_OPTION */
+	{1, &oid_null_function},		/* 0x81	OID_RT_RF_OFF */
+	{1, &oid_null_function}			/* 0x82	OID_RT_AUTH_STATUS */
+};
+
+static const struct oid_obj_priv rtl8188eu_oid_rtl_seg_81_85[] = {
+	{1, &rtl8188eu_oid_rt_wireless_mode_hdl}		/* 0x00	OID_RT_WIRELESS_MODE */
+};
+
+#endif /* _RTL871X_MP_IOCTL_C_ */
+
+struct rwreg_param {
+	u32 offset;
+	u32 width;
+	u32 value;
+};
+
+struct bbreg_param {
+	u32 offset;
+	u32 phymask;
+	u32 value;
+};
+
+struct txpower_param {
+	u32 pwr_index;
+};
+
+struct datarate_param {
+	u32 rate_index;
+};
+
+struct rfintfs_parm {
+	u32 rfintfs;
+};
+
+struct mp_xmit_parm {
+	u8 enable;
+	u32 count;
+	u16 length;
+	u8 payload_type;
+	u8 da[ETH_ALEN];
+};
+
+struct mp_xmit_packet {
+	u32 len;
+	u32 mem[MAX_MP_XMITBUF_SZ >> 2];
+};
+
+struct psmode_param {
+	u32 ps_mode;
+	u32 smart_ps;
+};
+
+/* for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM */
+struct eeprom_rw_param {
+	u32 offset;
+	u16 value;
+};
+
+struct mp_ioctl_handler {
+	u32 paramsize;
+	s32 (*handler)(struct oid_par_priv* poid_par_priv);
+	u32 oid;
+};
+
+struct mp_ioctl_param{
+	u32 subcode;
+	u32 len;
+	u8 data[0];
+};
+
+#define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_
+
+enum RTL871X_MP_IOCTL_SUBCODE {
+	GEN_MP_IOCTL_SUBCODE(MP_START),			/*0*/
+	GEN_MP_IOCTL_SUBCODE(MP_STOP),
+	GEN_MP_IOCTL_SUBCODE(READ_REG),
+	GEN_MP_IOCTL_SUBCODE(WRITE_REG),
+	GEN_MP_IOCTL_SUBCODE(READ_BB_REG),
+	GEN_MP_IOCTL_SUBCODE(WRITE_BB_REG),		/*5*/
+	GEN_MP_IOCTL_SUBCODE(READ_RF_REG),
+	GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG),
+	GEN_MP_IOCTL_SUBCODE(SET_CHANNEL),
+	GEN_MP_IOCTL_SUBCODE(SET_TXPOWER),
+	GEN_MP_IOCTL_SUBCODE(SET_DATARATE),		/*10*/
+	GEN_MP_IOCTL_SUBCODE(SET_BANDWIDTH),
+	GEN_MP_IOCTL_SUBCODE(SET_ANTENNA),
+	GEN_MP_IOCTL_SUBCODE(CNTU_TX),
+	GEN_MP_IOCTL_SUBCODE(SC_TX),
+	GEN_MP_IOCTL_SUBCODE(CS_TX),			/*15*/
+	GEN_MP_IOCTL_SUBCODE(ST_TX),
+	GEN_MP_IOCTL_SUBCODE(IOCTL_XMIT_PACKET),
+	GEN_MP_IOCTL_SUBCODE(SET_RX_PKT_TYPE),
+	GEN_MP_IOCTL_SUBCODE(RESET_PHY_RX_PKT_CNT),
+	GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_RECV),	/*20*/
+	GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_ERROR),
+	GEN_MP_IOCTL_SUBCODE(READ16_EEPROM),
+	GEN_MP_IOCTL_SUBCODE(WRITE16_EEPROM),
+	GEN_MP_IOCTL_SUBCODE(EFUSE),
+	GEN_MP_IOCTL_SUBCODE(EFUSE_MAP),		/*25*/
+	GEN_MP_IOCTL_SUBCODE(GET_EFUSE_MAX_SIZE),
+	GEN_MP_IOCTL_SUBCODE(GET_EFUSE_CURRENT_SIZE),
+	GEN_MP_IOCTL_SUBCODE(GET_THERMAL_METER),
+	GEN_MP_IOCTL_SUBCODE(SET_PTM),
+	GEN_MP_IOCTL_SUBCODE(SET_POWER_DOWN),		/*30*/
+	GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO),
+	GEN_MP_IOCTL_SUBCODE(SET_DM_BT),		/*35*/
+	GEN_MP_IOCTL_SUBCODE(DEL_BA),			/*36*/
+	GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS),	/*37*/
+	MAX_MP_IOCTL_SUBCODE,
+};
+
+s32 rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv);
+
+#define GEN_HANDLER(sz, hdl, oid) {sz, hdl, oid},
+
+#define EXT_MP_IOCTL_HANDLER(sz, subcode, oid)			\
+	 {sz, rtl8188eu_mp_ioctl_##subcode##_hdl, oid},
+
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h b/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h
new file mode 100644
index 0000000..3ad2207
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_mp_phy_regdef.h
@@ -0,0 +1,1084 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+/*****************************************************************************
+ *
+ * Module:	__RTW_MP_PHY_REGDEF_H_
+ *
+ *
+ * Note:	1. Define PMAC/BB register map
+ *			2. Define RF register map
+ *			3. PMAC/BB register bit mask.
+ *			4. RF reg bit mask.
+ *			5. Other BB/RF relative definition.
+ *
+ *
+ * Export:	Constants, macro, functions(API), global variables(None).
+ *
+ * Abbrev:
+ *
+ * History:
+ *	Data			Who		Remark
+ *	08/07/2007	MHC		1. Porting from 9x series PHYCFG.h.
+ *						2. Reorganize code architecture.
+ *	09/25/2008	MH		1. Add RL6052 register definition
+ *
+ *****************************************************************************/
+#ifndef __RTW_MP_PHY_REGDEF_H_
+#define __RTW_MP_PHY_REGDEF_H_
+
+
+/*--------------------------Define Parameters-------------------------------*/
+
+/*  */
+/*	8192S Regsiter offset definition */
+/*  */
+
+/*  */
+/*  BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF */
+/*  1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/*  2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 */
+/*  3. RF register 0x00-2E */
+/*  4. Bit Mask for BB/RF register */
+/*  5. Other defintion for BB/RF R/W */
+/*  */
+
+
+/*  */
+/*  1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/*  1. Page1(0x100) */
+/*  */
+#define	rPMAC_Reset		0x100
+#define	rPMAC_TxStart		0x104
+#define	rPMAC_TxLegacySIG	0x108
+#define	rPMAC_TxHTSIG1		0x10c
+#define	rPMAC_TxHTSIG2		0x110
+#define	rPMAC_PHYDebug		0x114
+#define	rPMAC_TxPacketNum	0x118
+#define	rPMAC_TxIdle		0x11c
+#define	rPMAC_TxMACHeader0	0x120
+#define	rPMAC_TxMACHeader1	0x124
+#define	rPMAC_TxMACHeader2	0x128
+#define	rPMAC_TxMACHeader3	0x12c
+#define	rPMAC_TxMACHeader4	0x130
+#define	rPMAC_TxMACHeader5	0x134
+#define	rPMAC_TxDataType	0x138
+#define	rPMAC_TxRandomSeed	0x13c
+#define	rPMAC_CCKPLCPPreamble	0x140
+#define	rPMAC_CCKPLCPHeader	0x144
+#define	rPMAC_CCKCRC16		0x148
+#define	rPMAC_OFDMRxCRC32OK	0x170
+#define	rPMAC_OFDMRxCRC32Er	0x174
+#define	rPMAC_OFDMRxParityEr	0x178
+#define	rPMAC_OFDMRxCRC8Er	0x17c
+#define	rPMAC_CCKCRxRC16Er	0x180
+#define	rPMAC_CCKCRxRC32Er	0x184
+#define	rPMAC_CCKCRxRC32OK	0x188
+#define	rPMAC_TxStatus		0x18c
+
+/*  */
+/*  2. Page2(0x200) */
+/*  */
+/*  The following two definition are only used for USB interface. */
+/* define	RF_BB_CMD_ADDR	0x02c0	 RF/BB read/write command address. */
+/* define	RF_BB_CMD_DATA	0x02c4	 RF/BB read/write command data. */
+
+/*  */
+/*  3. Page8(0x800) */
+/*  */
+#define	rFPGA0_RFMOD		0x800	/* RF mode & CCK TxSC RF BW Setting?? */
+
+#define	rFPGA0_TxInfo		0x804	/*  Status report?? */
+#define	rFPGA0_PSDFunction	0x808
+
+#define	rFPGA0_TxGainStage	0x80c	/*  Set TX PWR init gain? */
+
+#define	rFPGA0_RFTiming1	0x810	/*  Useless now */
+#define	rFPGA0_RFTiming2	0x814
+/* define rFPGA0_XC_RFTiming		0x818 */
+/* define rFPGA0_XD_RFTiming		0x81c */
+
+#define rFPGA0_XA_HSSIParameter1	0x820	/*  RF 3 wire register */
+#define rFPGA0_XA_HSSIParameter2	0x824
+#define rFPGA0_XB_HSSIParameter1	0x828
+#define rFPGA0_XB_HSSIParameter2	0x82c
+#define rFPGA0_XC_HSSIParameter1	0x830
+#define rFPGA0_XC_HSSIParameter2	0x834
+#define rFPGA0_XD_HSSIParameter1	0x838
+#define rFPGA0_XD_HSSIParameter2	0x83c
+#define	rFPGA0_XA_LSSIParameter		0x840
+#define	rFPGA0_XB_LSSIParameter		0x844
+#define	rFPGA0_XC_LSSIParameter		0x848
+#define	rFPGA0_XD_LSSIParameter		0x84c
+
+#define	rFPGA0_RFWakeUpParameter		0x850	/*  Useless now */
+#define	rFPGA0_RFSleepUpParameter		0x854
+
+#define	rFPGA0_XAB_SwitchControl		0x858	/*  RF Channel switch */
+#define	rFPGA0_XCD_SwitchControl		0x85c
+
+#define	rFPGA0_XA_RFInterfaceOE		0x860	/*  RF Channel switch */
+#define	rFPGA0_XB_RFInterfaceOE		0x864
+#define	rFPGA0_XC_RFInterfaceOE		0x868
+#define	rFPGA0_XD_RFInterfaceOE		0x86c
+
+#define	rFPGA0_XAB_RFInterfaceSW		0x870	/*  RF Interface Software Control */
+#define	rFPGA0_XCD_RFInterfaceSW		0x874
+
+#define	rFPGA0_XAB_RFParameter		0x878	/*  RF Parameter */
+#define	rFPGA0_XCD_RFParameter		0x87c
+
+#define	rFPGA0_AnalogParameter1		0x880	/*  Crystal cap setting RF-R/W protection for parameter4?? */
+#define	rFPGA0_AnalogParameter2		0x884
+#define	rFPGA0_AnalogParameter3		0x888	/*  Useless now */
+#define	rFPGA0_AnalogParameter4		0x88c
+
+#define	rFPGA0_XA_LSSIReadBack		0x8a0	/*  Tranceiver LSSI Readback */
+#define	rFPGA0_XB_LSSIReadBack		0x8a4
+#define	rFPGA0_XC_LSSIReadBack		0x8a8
+#define	rFPGA0_XD_LSSIReadBack		0x8ac
+
+#define	rFPGA0_PSDReport				0x8b4	/*  Useless now */
+#define	rFPGA0_XAB_RFInterfaceRB		0x8e0	/*  Useless now RF Interface Readback Value */
+#define	rFPGA0_XCD_RFInterfaceRB		0x8e4	/*  Useless now */
+
+/*  */
+/*  4. Page9(0x900) */
+/*  */
+#define	rFPGA1_RFMOD				0x900	/* RF mode & OFDM TxSC RF BW Setting?? */
+
+#define	rFPGA1_TxBlock				0x904	/*  Useless now */
+#define	rFPGA1_DebugSelect			0x908	/*  Useless now */
+#define	rFPGA1_TxInfo				0x90c	/*  Useless now Status report?? */
+
+/*  */
+/*  5. PageA(0xA00) */
+/*  */
+/*  Set Control channel to upper or lower. These settings are required only for 40MHz */
+#define	rCCK0_System				0xa00
+
+#define	rCCK0_AFESetting			0xa04	/*  Disable init gain now Select RX path by RSSI */
+#define	rCCK0_CCA					0xa08	/*  Disable init gain now Init gain */
+
+#define	rCCK0_RxAGC1			0xa0c	/* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series */
+#define	rCCK0_RxAGC2			0xa10	/* AGC & DAGC */
+
+#define	rCCK0_RxHP			0xa14
+
+#define	rCCK0_DSPParameter1		0xa18	/* Timing recovery & Channel estimation threshold */
+#define	rCCK0_DSPParameter2		0xa1c	/* SQ threshold */
+
+#define	rCCK0_TxFilter1			0xa20
+#define	rCCK0_TxFilter2			0xa24
+#define	rCCK0_DebugPort			0xa28	/* debug port and Tx filter3 */
+#define	rCCK0_FalseAlarmReport		0xa2c	/* 0xa2d	useless now 0xa30-a4f channel report */
+#define	rCCK0_TRSSIReport		0xa50
+#define	rCCK0_RxReport			0xa54  /* 0xa57 */
+#define	rCCK0_FACounterLower		0xa5c  /* 0xa5b */
+#define	rCCK0_FACounterUpper		0xa58  /* 0xa5c */
+
+/*  */
+/*  6. PageC(0xC00) */
+/*  */
+#define	rOFDM0_LSTF			0xc00
+
+#define	rOFDM0_TRxPathEnable		0xc04
+#define	rOFDM0_TRMuxPar			0xc08
+#define	rOFDM0_TRSWIsolation		0xc0c
+
+#define	rOFDM0_XARxAFE			0xc10  /* RxIQ DC offset, Rx digital filter, DC notch filter */
+#define	rOFDM0_XARxIQImbalance		0xc14  /* RxIQ imblance matrix */
+#define	rOFDM0_XBRxAFE			0xc18
+#define	rOFDM0_XBRxIQImbalance		0xc1c
+#define	rOFDM0_XCRxAFE			0xc20
+#define	rOFDM0_XCRxIQImbalance		0xc24
+#define	rOFDM0_XDRxAFE			0xc28
+#define	rOFDM0_XDRxIQImbalance		0xc2c
+
+#define	rOFDM0_RxDetector1		0xc30  /* PD,BW & SBD	DM tune init gain */
+#define	rOFDM0_RxDetector2		0xc34  /* SBD & Fame Sync. */
+#define	rOFDM0_RxDetector3		0xc38  /* Frame Sync. */
+#define	rOFDM0_RxDetector4		0xc3c  /* PD, SBD, Frame Sync & Short-GI */
+
+#define	rOFDM0_RxDSP			0xc40  /* Rx Sync Path */
+#define	rOFDM0_CFOandDAGC		0xc44  /* CFO & DAGC */
+#define	rOFDM0_CCADropThreshold		0xc48 /* CCA Drop threshold */
+#define	rOFDM0_ECCAThreshold		0xc4c /*  energy CCA */
+
+#define	rOFDM0_XAAGCCore1		0xc50	/*  DIG */
+#define	rOFDM0_XAAGCCore2		0xc54
+#define	rOFDM0_XBAGCCore1		0xc58
+#define	rOFDM0_XBAGCCore2		0xc5c
+#define	rOFDM0_XCAGCCore1		0xc60
+#define	rOFDM0_XCAGCCore2		0xc64
+#define	rOFDM0_XDAGCCore1		0xc68
+#define	rOFDM0_XDAGCCore2		0xc6c
+
+#define	rOFDM0_AGCParameter1		0xc70
+#define	rOFDM0_AGCParameter2		0xc74
+#define	rOFDM0_AGCRSSITable		0xc78
+#define	rOFDM0_HTSTFAGC			0xc7c
+
+#define	rOFDM0_XATxIQImbalance		0xc80	/*  TX PWR TRACK and DIG */
+#define	rOFDM0_XATxAFE			0xc84
+#define	rOFDM0_XBTxIQImbalance		0xc88
+#define	rOFDM0_XBTxAFE			0xc8c
+#define	rOFDM0_XCTxIQImbalance		0xc90
+#define	rOFDM0_XCTxAFE			0xc94
+#define	rOFDM0_XDTxIQImbalance		0xc98
+#define	rOFDM0_XDTxAFE			0xc9c
+#define	rOFDM0_RxIQExtAnta		0xca0
+
+#define	rOFDM0_RxHPParameter		0xce0
+#define	rOFDM0_TxPseudoNoiseWgt		0xce4
+#define	rOFDM0_FrameSync		0xcf0
+#define	rOFDM0_DFSReport		0xcf4
+#define	rOFDM0_TxCoeff1			0xca4
+#define	rOFDM0_TxCoeff2			0xca8
+#define	rOFDM0_TxCoeff3			0xcac
+#define	rOFDM0_TxCoeff4			0xcb0
+#define	rOFDM0_TxCoeff5			0xcb4
+#define	rOFDM0_TxCoeff6			0xcb8
+
+/*  7. PageD(0xD00) */
+#define	rOFDM1_LSTF			0xd00
+#define	rOFDM1_TRxPathEnable		0xd04
+
+#define	rOFDM1_CFO			0xd08	/*  No setting now */
+#define	rOFDM1_CSI1			0xd10
+#define	rOFDM1_SBD			0xd14
+#define	rOFDM1_CSI2			0xd18
+#define	rOFDM1_CFOTracking		0xd2c
+#define	rOFDM1_TRxMesaure1		0xd34
+#define	rOFDM1_IntfDet			0xd3c
+#define	rOFDM1_PseudoNoiseStateAB	0xd50
+#define	rOFDM1_PseudoNoiseStateCD	0xd54
+#define	rOFDM1_RxPseudoNoiseWgt		0xd58
+
+#define	rOFDM_PHYCounter1		0xda0  /* cca, parity fail */
+#define	rOFDM_PHYCounter2		0xda4  /* rate illegal, crc8 fail */
+#define	rOFDM_PHYCounter3		0xda8  /* MCS not support */
+
+#define	rOFDM_ShortCFOAB		0xdac	/*  No setting now */
+#define	rOFDM_ShortCFOCD		0xdb0
+#define	rOFDM_LongCFOAB			0xdb4
+#define	rOFDM_LongCFOCD			0xdb8
+#define	rOFDM_TailCFOAB			0xdbc
+#define	rOFDM_TailCFOCD			0xdc0
+#define	rOFDM_PWMeasure1		0xdc4
+#define	rOFDM_PWMeasure2		0xdc8
+#define	rOFDM_BWReport			0xdcc
+#define	rOFDM_AGCReport			0xdd0
+#define	rOFDM_RxSNR			0xdd4
+#define	rOFDM_RxEVMCSI			0xdd8
+#define	rOFDM_SIGReport			0xddc
+
+
+/*  */
+/*  8. PageE(0xE00) */
+/*  */
+#define	rTxAGC_Rate18_06		0xe00
+#define	rTxAGC_Rate54_24		0xe04
+#define	rTxAGC_CCK_Mcs32		0xe08
+#define	rTxAGC_Mcs03_Mcs00		0xe10
+#define	rTxAGC_Mcs07_Mcs04		0xe14
+#define	rTxAGC_Mcs11_Mcs08		0xe18
+#define	rTxAGC_Mcs15_Mcs12		0xe1c
+
+/*  Analog- control in RX_WAIT_CCA : REG: EE0 [Analog- Power & Control Register] */
+#define		rRx_Wait_CCCA		0xe70
+#define	rAnapar_Ctrl_BB			0xee0
+
+/*  */
+/*  7. RF Register 0x00-0x2E (RF 8256) */
+/*     RF-0222D 0x00-3F */
+/*  */
+/* Zebra1 */
+#define RTL92SE_FPGA_VERIFY 0
+#define	rZebra1_HSSIEnable		0x0	/*  Useless now */
+#define	rZebra1_TRxEnable1		0x1
+#define	rZebra1_TRxEnable2		0x2
+#define	rZebra1_AGC			0x4
+#define	rZebra1_ChargePump		0x5
+/* if (RTL92SE_FPGA_VERIFY == 1) */
+#define	rZebra1_Channel			0x7	/*  RF channel switch */
+/* else */
+
+/* endif */
+#define	rZebra1_TxGain			0x8	/*  Useless now */
+#define	rZebra1_TxLPF			0x9
+#define	rZebra1_RxLPF			0xb
+#define	rZebra1_RxHPFCorner		0xc
+
+/* Zebra4 */
+#define	rGlobalCtrl			0	/*  Useless now */
+#define	rRTL8256_TxLPF			19
+#define	rRTL8256_RxLPF			11
+
+/* RTL8258 */
+#define	rRTL8258_TxLPF			0x11	/*  Useless now */
+#define	rRTL8258_RxLPF			0x13
+#define	rRTL8258_RSSILPF		0xa
+
+/*  */
+/*  RL6052 Register definition */
+#define	RF_AC				0x00	/*  */
+
+#define	RF_IQADJ_G1			0x01	/*  */
+#define	RF_IQADJ_G2			0x02	/*  */
+#define	RF_POW_TRSW			0x05	/*  */
+
+#define	RF_GAIN_RX			0x06	/*  */
+#define	RF_GAIN_TX			0x07	/*  */
+
+#define	RF_TXM_IDAC			0x08	/*  */
+#define	RF_BS_IQGEN			0x0F	/*  */
+
+#define	RF_MODE1			0x10	/*  */
+#define	RF_MODE2			0x11	/*  */
+
+#define	RF_RX_AGC_HP			0x12	/*  */
+#define	RF_TX_AGC			0x13	/*  */
+#define	RF_BIAS				0x14	/*  */
+#define	RF_IPA				0x15	/*  */
+#define	RF_TXBIAS			0x16 /*  */
+#define	RF_POW_ABILITY			0x17	/*  */
+#define	RF_MODE_AG			0x18	/*  */
+#define	rRfChannel			0x18	/*  RF channel and BW switch */
+#define	RF_CHNLBW			0x18	/*  RF channel and BW switch */
+#define	RF_TOP				0x19	/*  */
+
+#define	RF_RX_G1			0x1A	/*  */
+#define	RF_RX_G2			0x1B	/*  */
+
+#define	RF_RX_BB2			0x1C	/*  */
+#define	RF_RX_BB1			0x1D	/*  */
+
+#define	RF_RCK1				0x1E	/*  */
+#define	RF_RCK2				0x1F	/*  */
+
+#define	RF_TX_G1			0x20	/*  */
+#define	RF_TX_G2			0x21	/*  */
+#define	RF_TX_G3			0x22	/*  */
+
+#define	RF_TX_BB1			0x23	/*  */
+
+#define	RF_T_METER			0x24	/*  */
+
+#define	RF_SYN_G1			0x25	/*  RF TX Power control */
+#define	RF_SYN_G2			0x26	/*  RF TX Power control */
+#define	RF_SYN_G3			0x27	/*  RF TX Power control */
+#define	RF_SYN_G4			0x28	/*  RF TX Power control */
+#define	RF_SYN_G5			0x29	/*  RF TX Power control */
+#define	RF_SYN_G6			0x2A	/*  RF TX Power control */
+#define	RF_SYN_G7			0x2B	/*  RF TX Power control */
+#define	RF_SYN_G8			0x2C	/*  RF TX Power control */
+
+#define	RF_RCK_OS			0x30	/*  RF TX PA control */
+#define	RF_TXPA_G1			0x31	/*  RF TX PA control */
+#define	RF_TXPA_G2			0x32	/*  RF TX PA control */
+#define	RF_TXPA_G3			0x33	/*  RF TX PA control */
+
+/*  */
+/* Bit Mask */
+/*  */
+/*  1. Page1(0x100) */
+#define	bBBResetB			0x100	/*  Useless now? */
+#define	bGlobalResetB			0x200
+#define	bOFDMTxStart			0x4
+#define	bCCKTxStart			0x8
+#define	bCRC32Debug			0x100
+#define	bPMACLoopback			0x10
+#define	bTxLSIG				0xffffff
+#define	bOFDMTxRate			0xf
+#define	bOFDMTxReserved			0x10
+#define	bOFDMTxLength			0x1ffe0
+#define	bOFDMTxParity			0x20000
+#define	bTxHTSIG1			0xffffff
+#define	bTxHTMCSRate			0x7f
+#define	bTxHTBW				0x80
+#define	bTxHTLength			0xffff00
+#define	bTxHTSIG2			0xffffff
+#define	bTxHTSmoothing			0x1
+#define	bTxHTSounding			0x2
+#define	bTxHTReserved			0x4
+#define	bTxHTAggreation			0x8
+#define	bTxHTSTBC			0x30
+#define	bTxHTAdvanceCoding		0x40
+#define	bTxHTShortGI			0x80
+#define	bTxHTNumberHT_LTF		0x300
+#define	bTxHTCRC8			0x3fc00
+#define	bCounterReset			0x10000
+#define	bNumOfOFDMTx			0xffff
+#define	bNumOfCCKTx			0xffff0000
+#define	bTxIdleInterval			0xffff
+#define	bOFDMService			0xffff0000
+#define	bTxMACHeader			0xffffffff
+#define	bTxDataInit			0xff
+#define	bTxHTMode			0x100
+#define	bTxDataType			0x30000
+#define	bTxRandomSeed			0xffffffff
+#define	bCCKTxPreamble			0x1
+#define	bCCKTxSFD			0xffff0000
+#define	bCCKTxSIG			0xff
+#define	bCCKTxService			0xff00
+#define	bCCKLengthExt			0x8000
+#define	bCCKTxLength			0xffff0000
+#define	bCCKTxCRC16			0xffff
+#define	bCCKTxStatus			0x1
+#define	bOFDMTxStatus			0x2
+
+#define		IS_BB_REG_OFFSET_92S(_Offset)		((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+/*  2. Page8(0x800) */
+#define	bRFMOD				0x1	/*  Reg 0x800 rFPGA0_RFMOD */
+#define	bJapanMode			0x2
+#define	bCCKTxSC			0x30
+#define	bCCKEn				0x1000000
+#define	bOFDMEn				0x2000000
+
+#define	bOFDMRxADCPhase			0x10000	/*  Useless now */
+#define	bOFDMTxDACPhase			0x40000
+#define	bXATxAGC			0x3f
+
+#define	bXBTxAGC			0xf00	/*  Reg 80c rFPGA0_TxGainStage */
+#define	bXCTxAGC			0xf000
+#define	bXDTxAGC			0xf0000
+
+#define	bPAStart			0xf0000000	/*  Useless now */
+#define	bTRStart			0x00f00000
+#define	bRFStart			0x0000f000
+#define	bBBStart			0x000000f0
+#define	bBBCCKStart			0x0000000f
+#define	bPAEnd				0xf	  /* Reg0x814 */
+#define	bTREnd				0x0f000000
+#define	bRFEnd				0x000f0000
+#define	bCCAMask			0x000000f0   /* T2R */
+#define	bR2RCCAMask			0x00000f00
+#define	bHSSI_R2TDelay			0xf8000000
+#define	bHSSI_T2RDelay			0xf80000
+#define	bContTxHSSI			0x400     /* chane gain at continue Tx */
+#define	bIGFromCCK			0x200
+#define	bAGCAddress			0x3f
+#define	bRxHPTx				0x7000
+#define	bRxHPT2R			0x38000
+#define	bRxHPCCKIni			0xc0000
+#define	bAGCTxCode			0xc00000
+#define	bAGCRxCode			0x300000
+
+#define	b3WireDataLength		0x800	/*  Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */
+#define	b3WireAddressLength		0x400
+
+#define	b3WireRFPowerDown		0x1	/*  Useless now */
+/* define bHWSISelect			0x8 */
+#define	b5GPAPEPolarity			0x40000000
+#define	b2GPAPEPolarity			0x80000000
+#define	bRFSW_TxDefaultAnt		0x3
+#define	bRFSW_TxOptionAnt		0x30
+#define	bRFSW_RxDefaultAnt		0x300
+#define	bRFSW_RxOptionAnt		0x3000
+#define	bRFSI_3WireData			0x1
+#define	bRFSI_3WireClock		0x2
+#define	bRFSI_3WireLoad			0x4
+#define	bRFSI_3WireRW			0x8
+#define	bRFSI_3Wire			0xf
+
+#define	bRFSI_RFENV			0x10	/*  Reg 0x870 rFPGA0_XAB_RFInterfaceSW */
+
+#define	bRFSI_TRSW			0x20	/*  Useless now */
+#define	bRFSI_TRSWB			0x40
+#define	bRFSI_ANTSW			0x100
+#define	bRFSI_ANTSWB			0x200
+#define	bRFSI_PAPE			0x400
+#define	bRFSI_PAPE5G			0x800
+#define	bBandSelect			0x1
+#define	bHTSIG2_GI			0x80
+#define	bHTSIG2_Smoothing		0x01
+#define	bHTSIG2_Sounding		0x02
+#define	bHTSIG2_Aggreaton		0x08
+#define	bHTSIG2_STBC			0x30
+#define	bHTSIG2_AdvCoding		0x40
+#define	bHTSIG2_NumOfHTLTF		0x300
+#define	bHTSIG2_CRC8			0x3fc
+#define	bHTSIG1_MCS			0x7f
+#define	bHTSIG1_BandWidth		0x80
+#define	bHTSIG1_HTLength		0xffff
+#define	bLSIG_Rate			0xf
+#define	bLSIG_Reserved			0x10
+#define	bLSIG_Length			0x1fffe
+#define	bLSIG_Parity			0x20
+#define	bCCKRxPhase			0x4
+#if (RTL92SE_FPGA_VERIFY == 1)
+#define	bLSSIReadAddress		0x3f000000   /* LSSI "Read" Address
+					Reg 0x824 rFPGA0_XA_HSSIParameter2 */
+#else
+#define	bLSSIReadAddress		0x7f800000   /*  T65 RF */
+#endif
+#define	bLSSIReadEdge			0x80000000   /* LSSI "Read" edge signal */
+#if (RTL92SE_FPGA_VERIFY == 1)
+#define	bLSSIReadBackData		0xfff	/*  Reg 0x8a0
+					 rFPGA0_XA_LSSIReadBack */
+#else
+#define	bLSSIReadBackData		0xfffff	/*  T65 RF */
+#endif
+#define	bLSSIReadOKFlag			0x1000	/*  Useless now */
+#define	bCCKSampleRate			0x8       /* 0: 44MHz, 1:88MHz */
+#define	bRegulator0Standby		0x1
+#define	bRegulatorPLLStandby		0x2
+#define	bRegulator1Standby		0x4
+#define	bPLLPowerUp			0x8
+#define	bDPLLPowerUp			0x10
+#define	bDA10PowerUp			0x20
+#define	bAD7PowerUp			0x200
+#define	bDA6PowerUp			0x2000
+#define	bXtalPowerUp			0x4000
+#define	b40MDClkPowerUP			0x8000
+#define	bDA6DebugMode			0x20000
+#define	bDA6Swing			0x380000
+
+#define	bADClkPhase			0x4000000	/*  Reg 0x880
+	 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */
+
+#define	b80MClkDelay			0x18000000	/*  Useless */
+#define	bAFEWatchDogEnable		0x20000000
+
+#define	bXtalCap01			0xc0000000	/*  Reg 0x884
+	 rFPGA0_AnalogParameter2 Crystal cap */
+#define	bXtalCap23			0x3
+#define	bXtalCap92x			0x0f000000
+#define		bXtalCap		0x0f000000
+
+#define	bIntDifClkEnable		0x400	/*  Useless */
+#define	bExtSigClkEnable		0x800
+#define	bBandgapMbiasPowerUp		0x10000
+#define	bAD11SHGain			0xc0000
+#define	bAD11InputRange			0x700000
+#define	bAD11OPCurrent			0x3800000
+#define	bIPathLoopback			0x4000000
+#define	bQPathLoopback			0x8000000
+#define	bAFELoopback			0x10000000
+#define	bDA10Swing			0x7e0
+#define	bDA10Reverse			0x800
+#define	bDAClkSource			0x1000
+#define	bAD7InputRange			0x6000
+#define	bAD7Gain			0x38000
+#define	bAD7OutputCMMode		0x40000
+#define	bAD7InputCMMode			0x380000
+#define	bAD7Current			0xc00000
+#define	bRegulatorAdjust		0x7000000
+#define	bAD11PowerUpAtTx		0x1
+#define	bDA10PSAtTx			0x10
+#define	bAD11PowerUpAtRx		0x100
+#define	bDA10PSAtRx			0x1000
+#define	bCCKRxAGCFormat			0x200
+#define	bPSDFFTSamplepPoint		0xc000
+#define	bPSDAverageNum			0x3000
+#define	bIQPathControl			0xc00
+#define	bPSDFreq			0x3ff
+#define	bPSDAntennaPath			0x30
+#define	bPSDIQSwitch			0x40
+#define	bPSDRxTrigger			0x400000
+#define	bPSDTxTrigger			0x80000000
+#define	bPSDSineToneScale		0x7f000000
+#define	bPSDReport			0xffff
+
+/*  3. Page9(0x900) */
+#define	bOFDMTxSC			0x30000000	/*  Useless */
+#define	bCCKTxOn			0x1
+#define	bOFDMTxOn			0x2
+#define	bDebugPage			0xfff  /* reset debug page and HWord,
+						* LWord */
+#define	bDebugItem			0xff   /* reset debug page and LWord */
+#define	bAntL				0x10
+#define	bAntNonHT			0x100
+#define	bAntHT1				0x1000
+#define	bAntHT2				0x10000
+#define	bAntHT1S1			0x100000
+#define	bAntNonHTS1			0x1000000
+
+/*  4. PageA(0xA00) */
+#define	bCCKBBMode			0x3	/*  Useless */
+#define	bCCKTxPowerSaving		0x80
+#define	bCCKRxPowerSaving		0x40
+
+#define	bCCKSideBand			0x10	/* Reg 0xa00 rCCK0 20/40 sw */
+
+#define	bCCKScramble			0x8	/*  Useless */
+#define	bCCKAntDiversity		0x8000
+#define	bCCKCarrierRecovery		0x4000
+#define	bCCKTxRate			0x3000
+#define	bCCKDCCancel			0x0800
+#define	bCCKISICancel			0x0400
+#define	bCCKMatchFilter			0x0200
+#define	bCCKEqualizer			0x0100
+#define	bCCKPreambleDetect		0x800000
+#define	bCCKFastFalseCCA		0x400000
+#define	bCCKChEstStart			0x300000
+#define	bCCKCCACount			0x080000
+#define	bCCKcs_lim			0x070000
+#define	bCCKBistMode			0x80000000
+#define	bCCKCCAMask			0x40000000
+#define	bCCKTxDACPhase			0x4
+#define	bCCKRxADCPhase			0x20000000   /* r_rx_clk */
+#define	bCCKr_cp_mode0			0x0100
+#define	bCCKTxDCOffset			0xf0
+#define	bCCKRxDCOffset			0xf
+#define	bCCKCCAMode			0xc000
+#define	bCCKFalseCS_lim			0x3f00
+#define	bCCKCS_ratio			0xc00000
+#define	bCCKCorgBit_sel			0x300000
+#define	bCCKPD_lim			0x0f0000
+#define	bCCKNewCCA			0x80000000
+#define	bCCKRxHPofIG			0x8000
+#define	bCCKRxIG			0x7f00
+#define	bCCKLNAPolarity			0x800000
+#define	bCCKRx1stGain			0x7f0000
+#define	bCCKRFExtend			0x20000000 /* CCK Rx init gain polar */
+#define	bCCKRxAGCSatLevel		0x1f000000
+#define	bCCKRxAGCSatCount		0xe0
+#define	bCCKRxRFSettle			0x1f       /* AGCsamp_dly */
+#define	bCCKFixedRxAGC			0x8000
+#define	bCCKAntennaPolarity		0x2000
+#define	bCCKTxFilterType		0x0c00
+#define	bCCKRxAGCReportType		0x0300
+#define	bCCKRxDAGCEn			0x80000000
+#define	bCCKRxDAGCPeriod		0x20000000
+#define	bCCKRxDAGCSatLevel		0x1f000000
+#define	bCCKTimingRecovery		0x800000
+#define	bCCKTxC0			0x3f0000
+#define	bCCKTxC1			0x3f000000
+#define	bCCKTxC2			0x3f
+#define	bCCKTxC3			0x3f00
+#define	bCCKTxC4			0x3f0000
+#define	bCCKTxC5			0x3f000000
+#define	bCCKTxC6			0x3f
+#define	bCCKTxC7			0x3f00
+#define	bCCKDebugPort			0xff0000
+#define	bCCKDACDebug			0x0f000000
+#define	bCCKFalseAlarmEnable		0x8000
+#define	bCCKFalseAlarmRead		0x4000
+#define	bCCKTRSSI			0x7f
+#define	bCCKRxAGCReport			0xfe
+#define	bCCKRxReport_AntSel		0x80000000
+#define	bCCKRxReport_MFOff		0x40000000
+#define	bCCKRxRxReport_SQLoss		0x20000000
+#define	bCCKRxReport_Pktloss		0x10000000
+#define	bCCKRxReport_Lockedbit		0x08000000
+#define	bCCKRxReport_RateError		0x04000000
+#define	bCCKRxReport_RxRate		0x03000000
+#define	bCCKRxFACounterLower		0xff
+#define	bCCKRxFACounterUpper		0xff000000
+#define	bCCKRxHPAGCStart		0xe000
+#define	bCCKRxHPAGCFinal		0x1c00
+#define	bCCKRxFalseAlarmEnable		0x8000
+#define	bCCKFACounterFreeze		0x4000
+#define	bCCKTxPathSel			0x10000000
+#define	bCCKDefaultRxPath		0xc000000
+#define	bCCKOptionRxPath		0x3000000
+
+/*  5. PageC(0xC00) */
+#define	bNumOfSTF			0x3	/*  Useless */
+#define	bShift_L			0xc0
+#define	bGI_TH				0xc
+#define	bRxPathA			0x1
+#define	bRxPathB			0x2
+#define	bRxPathC			0x4
+#define	bRxPathD			0x8
+#define	bTxPathA			0x1
+#define	bTxPathB			0x2
+#define	bTxPathC			0x4
+#define	bTxPathD			0x8
+#define	bTRSSIFreq			0x200
+#define	bADCBackoff			0x3000
+#define	bDFIRBackoff			0xc000
+#define	bTRSSILatchPhase		0x10000
+#define	bRxIDCOffset			0xff
+#define	bRxQDCOffset			0xff00
+#define	bRxDFIRMode			0x1800000
+#define	bRxDCNFType			0xe000000
+#define	bRXIQImb_A			0x3ff
+#define	bRXIQImb_B			0xfc00
+#define	bRXIQImb_C			0x3f0000
+#define	bRXIQImb_D			0xffc00000
+#define	bDC_dc_Notch			0x60000
+#define	bRxNBINotch			0x1f000000
+#define	bPD_TH				0xf
+#define	bPD_TH_Opt2			0xc000
+#define	bPWED_TH			0x700
+#define	bIfMF_Win_L			0x800
+#define	bPD_Option			0x1000
+#define	bMF_Win_L			0xe000
+#define	bBW_Search_L			0x30000
+#define	bwin_enh_L			0xc0000
+#define	bBW_TH				0x700000
+#define	bED_TH2				0x3800000
+#define	bBW_option			0x4000000
+#define	bRatio_TH			0x18000000
+#define	bWindow_L			0xe0000000
+#define	bSBD_Option			0x1
+#define	bFrame_TH			0x1c
+#define	bFS_Option			0x60
+#define	bDC_Slope_check			0x80
+#define	bFGuard_Counter_DC_L		0xe00
+#define	bFrame_Weight_Short		0x7000
+#define	bSub_Tune			0xe00000
+#define	bFrame_DC_Length		0xe000000
+#define	bSBD_start_offset		0x30000000
+#define	bFrame_TH_2			0x7
+#define	bFrame_GI2_TH			0x38
+#define	bGI2_Sync_en			0x40
+#define	bSarch_Short_Early		0x300
+#define	bSarch_Short_Late		0xc00
+#define	bSarch_GI2_Late			0x70000
+#define	bCFOAntSum			0x1
+#define	bCFOAcc				0x2
+#define	bCFOStartOffset			0xc
+#define	bCFOLookBack			0x70
+#define	bCFOSumWeight			0x80
+#define	bDAGCEnable			0x10000
+#define	bTXIQImb_A			0x3ff
+#define	bTXIQImb_B			0xfc00
+#define	bTXIQImb_C			0x3f0000
+#define	bTXIQImb_D			0xffc00000
+#define	bTxIDCOffset			0xff
+#define	bTxQDCOffset			0xff00
+#define	bTxDFIRMode			0x10000
+#define	bTxPesudoNoiseOn		0x4000000
+#define	bTxPesudoNoise_A		0xff
+#define	bTxPesudoNoise_B		0xff00
+#define	bTxPesudoNoise_C		0xff0000
+#define	bTxPesudoNoise_D		0xff000000
+#define	bCCADropOption			0x20000
+#define	bCCADropThres			0xfff00000
+#define	bEDCCA_H			0xf
+#define	bEDCCA_L			0xf0
+#define	bLambda_ED			0x300
+#define	bRxInitialGain			0x7f
+#define	bRxAntDivEn			0x80
+#define	bRxAGCAddressForLNA		0x7f00
+#define	bRxHighPowerFlow		0x8000
+#define	bRxAGCFreezeThres		0xc0000
+#define	bRxFreezeStep_AGC1		0x300000
+#define	bRxFreezeStep_AGC2		0xc00000
+#define	bRxFreezeStep_AGC3		0x3000000
+#define	bRxFreezeStep_AGC0		0xc000000
+#define	bRxRssi_Cmp_En			0x10000000
+#define	bRxQuickAGCEn			0x20000000
+#define	bRxAGCFreezeThresMode		0x40000000
+#define	bRxOverFlowCheckType		0x80000000
+#define	bRxAGCShift			0x7f
+#define	bTRSW_Tri_Only			0x80
+#define	bPowerThres			0x300
+#define	bRxAGCEn			0x1
+#define	bRxAGCTogetherEn		0x2
+#define	bRxAGCMin			0x4
+#define	bRxHP_Ini			0x7
+#define	bRxHP_TRLNA			0x70
+#define	bRxHP_RSSI			0x700
+#define	bRxHP_BBP1			0x7000
+#define	bRxHP_BBP2			0x70000
+#define	bRxHP_BBP3			0x700000
+#define	bRSSI_H				0x7f0000     /* thresh for hi power */
+#define	bRSSI_Gen			0x7f000000   /* thresh for ant div */
+#define	bRxSettle_TRSW			0x7
+#define	bRxSettle_LNA			0x38
+#define	bRxSettle_RSSI			0x1c0
+#define	bRxSettle_BBP			0xe00
+#define	bRxSettle_RxHP			0x7000
+#define	bRxSettle_AntSW_RSSI		0x38000
+#define	bRxSettle_AntSW			0xc0000
+#define	bRxProcessTime_DAGC		0x300000
+#define	bRxSettle_HSSI			0x400000
+#define	bRxProcessTime_BBPPW		0x800000
+#define	bRxAntennaPowerShift    0x3000000
+#define	bRSSITableSelect	0xc000000
+#define	bRxHP_Final	     0x7000000
+#define	bRxHTSettle_BBP	 0x7
+#define	bRxHTSettle_HSSI	0x8
+#define	bRxHTSettle_RxHP	0x70
+#define	bRxHTSettle_BBPPW       0x80
+#define	bRxHTSettle_Idle	0x300
+#define	bRxHTSettle_Reserved    0x1c00
+#define	bRxHTRxHPEn	     0x8000
+#define	bRxHTAGCFreezeThres     0x30000
+#define	bRxHTAGCTogetherEn      0x40000
+#define	bRxHTAGCMin	     0x80000
+#define	bRxHTAGCEn	      0x100000
+#define	bRxHTDAGCEn	     0x200000
+#define	bRxHTRxHP_BBP	   0x1c00000
+#define	bRxHTRxHP_Final	 0xe0000000
+#define	bRxPWRatioTH	    0x3
+#define	bRxPWRatioEn	    0x4
+#define	bRxMFHold	       0x3800
+#define	bRxPD_Delay_TH1	 0x38
+#define	bRxPD_Delay_TH2	 0x1c0
+#define	bRxPD_DC_COUNT_MAX      0x600
+/* define bRxMF_Hold	     0x3800 */
+#define	bRxPD_Delay_TH	  0x8000
+#define	bRxProcess_Delay	0xf0000
+#define	bRxSearchrange_GI2_Early 0x700000
+#define	bRxFrame_Guard_Counter_L 0x3800000
+#define	bRxSGI_Guard_L	  0xc000000
+#define	bRxSGI_Search_L	 0x30000000
+#define	bRxSGI_TH	       0xc0000000
+#define	bDFSCnt0		0xff
+#define	bDFSCnt1		0xff00
+#define	bDFSFlag		0xf0000
+#define	bMFWeightSum	    0x300000
+#define	bMinIdxTH	       0x7f000000
+#define	bDAFormat	       0x40000
+#define	bTxChEmuEnable	  0x01000000
+#define	bTRSWIsolation_A	0x7f
+#define	bTRSWIsolation_B	0x7f00
+#define	bTRSWIsolation_C	0x7f0000
+#define	bTRSWIsolation_D	0x7f000000
+#define	bExtLNAGain	     0x7c00
+
+/*  6. PageE(0xE00) */
+#define	bSTBCEn			0x4	/*  Useless */
+#define	bAntennaMapping	  0x10
+#define	bNss		     0x20
+#define	bCFOAntSumD	      0x200
+#define	bPHYCounterReset	 0x8000000
+#define	bCFOReportGet	    0x4000000
+#define	bOFDMContinueTx	  0x10000000
+#define	bOFDMSingleCarrier       0x20000000
+#define	bOFDMSingleTone	  0x40000000
+/* define bRxPath1		 0x01 */
+/* define bRxPath2		 0x02 */
+/* define bRxPath3		 0x04 */
+/* define bRxPath4		 0x08 */
+/* define bTxPath1		 0x10 */
+/* define bTxPath2		 0x20 */
+#define	bHTDetect		0x100
+#define	bCFOEn		   0x10000
+#define	bCFOValue		0xfff00000
+#define	bSigTone_Re	      0x3f
+#define	bSigTone_Im	      0x7f00
+#define	bCounter_CCA	     0xffff
+#define	bCounter_ParityFail      0xffff0000
+#define	bCounter_RateIllegal     0xffff
+#define	bCounter_CRC8Fail	0xffff0000
+#define	bCounter_MCSNoSupport    0xffff
+#define	bCounter_FastSync	0xffff
+#define	bShortCFO		0xfff
+#define	bShortCFOTLength	 12   /* total */
+#define	bShortCFOFLength	 11   /* fraction */
+#define	bLongCFO		 0x7ff
+#define	bLongCFOTLength	  11
+#define	bLongCFOFLength	  11
+#define	bTailCFO		 0x1fff
+#define	bTailCFOTLength	  13
+#define	bTailCFOFLength	  12
+#define	bmax_en_pwdB	     0xffff
+#define	bCC_power_dB	     0xffff0000
+#define	bnoise_pwdB	      0xffff
+#define	bPowerMeasTLength	10
+#define	bPowerMeasFLength	3
+#define	bRx_HT_BW		0x1
+#define	bRxSC		    0x6
+#define	bRx_HT		   0x8
+#define	bNB_intf_det_on	  0x1
+#define	bIntf_win_len_cfg	0x30
+#define	bNB_Intf_TH_cfg	  0x1c0
+#define	bRFGain		  0x3f
+#define	bTableSel		0x40
+#define	bTRSW		    0x80
+#define	bRxSNR_A		 0xff
+#define	bRxSNR_B		 0xff00
+#define	bRxSNR_C		 0xff0000
+#define	bRxSNR_D		 0xff000000
+#define	bSNREVMTLength	   8
+#define	bSNREVMFLength	   1
+#define	bCSI1st		  0xff
+#define	bCSI2nd		  0xff00
+#define	bRxEVM1st		0xff0000
+#define	bRxEVM2nd		0xff000000
+#define	bSIGEVM		  0xff
+#define	bPWDB		    0xff00
+#define	bSGIEN		   0x10000
+
+#define	bSFactorQAM1	     0xf	/*  Useless */
+#define	bSFactorQAM2	     0xf0
+#define	bSFactorQAM3	     0xf00
+#define	bSFactorQAM4	     0xf000
+#define	bSFactorQAM5	     0xf0000
+#define	bSFactorQAM6	     0xf0000
+#define	bSFactorQAM7	     0xf00000
+#define	bSFactorQAM8	     0xf000000
+#define	bSFactorQAM9	     0xf0000000
+#define	bCSIScheme	       0x100000
+
+#define	bNoiseLvlTopSet	  0x3	/*  Useless */
+#define	bChSmooth		0x4
+#define	bChSmoothCfg1	    0x38
+#define	bChSmoothCfg2	    0x1c0
+#define	bChSmoothCfg3	    0xe00
+#define	bChSmoothCfg4	    0x7000
+#define	bMRCMode		 0x800000
+#define	bTHEVMCfg		0x7000000
+
+#define	bLoopFitType	     0x1	/*  Useless */
+#define	bUpdCFO		  0x40
+#define	bUpdCFOOffData	   0x80
+#define	bAdvUpdCFO	       0x100
+#define	bAdvTimeCtrl	     0x800
+#define	bUpdClko		 0x1000
+#define	bFC		      0x6000
+#define	bTrackingMode	    0x8000
+#define	bPhCmpEnable	     0x10000
+#define	bUpdClkoLTF	      0x20000
+#define	bComChCFO		0x40000
+#define	bCSIEstiMode	     0x80000
+#define	bAdvUpdEqz	       0x100000
+#define	bUChCfg		  0x7000000
+#define	bUpdEqz		  0x8000000
+
+#define	bTxAGCRate18_06			0x7f7f7f7f	/*  Useless */
+#define	bTxAGCRate54_24			0x7f7f7f7f
+#define	bTxAGCRateMCS32			0x7f
+#define	bTxAGCRateCCK			0x7f00
+#define	bTxAGCRateMCS3_MCS0		0x7f7f7f7f
+#define	bTxAGCRateMCS7_MCS4		0x7f7f7f7f
+#define	bTxAGCRateMCS11_MCS8	0x7f7f7f7f
+#define	bTxAGCRateMCS15_MCS12	0x7f7f7f7f
+
+/* Rx Pseduo noise */
+#define	bRxPesudoNoiseOn	 0x20000000	/*  Useless */
+#define	bRxPesudoNoise_A	 0xff
+#define	bRxPesudoNoise_B	 0xff00
+#define	bRxPesudoNoise_C	 0xff0000
+#define	bRxPesudoNoise_D	 0xff000000
+#define	bPesudoNoiseState_A      0xffff
+#define	bPesudoNoiseState_B      0xffff0000
+#define	bPesudoNoiseState_C      0xffff
+#define	bPesudoNoiseState_D      0xffff0000
+
+/* 7. RF Register */
+/* Zebra1 */
+#define	bZebra1_HSSIEnable	0x8		/*  Useless */
+#define	bZebra1_TRxControl	0xc00
+#define	bZebra1_TRxGainSetting    0x07f
+#define	bZebra1_RxCorner	  0xc00
+#define	bZebra1_TxChargePump      0x38
+#define	bZebra1_RxChargePump      0x7
+#define	bZebra1_ChannelNum	0xf80
+#define	bZebra1_TxLPFBW	   0x400
+#define	bZebra1_RxLPFBW	   0x600
+
+/* Zebra4 */
+#define	bRTL8256RegModeCtrl1      0x100	/*  Useless */
+#define	bRTL8256RegModeCtrl0      0x40
+#define	bRTL8256_TxLPFBW	  0x18
+#define	bRTL8256_RxLPFBW	  0x600
+
+/* RTL8258 */
+#define	bRTL8258_TxLPFBW	  0xc	/*  Useless */
+#define	bRTL8258_RxLPFBW	  0xc00
+#define	bRTL8258_RSSILPFBW	0xc0
+
+
+/*  */
+/*  Other Definition */
+/*  */
+
+/* byte endable for sb_write */
+#define	bByte0		    0x1	/*  Useless */
+#define	bByte1		    0x2
+#define	bByte2		    0x4
+#define	bByte3		    0x8
+#define	bWord0		    0x3
+#define	bWord1		    0xc
+#define	bDWord		    0xf
+
+/* for PutRegsetting & GetRegSetting BitMask */
+#define	bMaskByte0		0xff	/*  Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */
+#define	bMaskByte1		0xff00
+#define	bMaskByte2		0xff0000
+#define	bMaskByte3		0xff000000
+#define	bMaskHWord		0xffff0000
+#define	bMaskLWord		0x0000ffff
+#define	bMaskDWord		0xffffffff
+#define	bMaskH4Bits		0xf0000000
+#define	bMaskOFDM_D		0xffc00000
+#define	bMaskCCK		0x3f3f3f3f
+#define	bMask12Bits		0xfff
+
+/* for PutRFRegsetting & GetRFRegSetting BitMask */
+#if (RTL92SE_FPGA_VERIFY == 1)
+#define		bRFRegOffsetMask	0xfff
+#else
+#define		bRFRegOffsetMask	0xfffff
+#endif
+#define	bEnable		0x1	/*  Useless */
+#define	bDisabl		0x0
+
+#define	LeftAntenna	0x0	/*  Useless */
+#define	RightAntenna	0x1
+
+#define	tCheckTxStatus	500   /* 500ms Useless */
+#define	tUpdateRxCounter 100   /* 100ms */
+
+#define	rateCCK     0	/*  Useless */
+#define	rateOFDM    1
+#define	rateHT      2
+
+/* define Register-End */
+#define	bPMAC_End	 0x1ff	/*  Useless */
+#define	bFPGAPHY0_End	 0x8ff
+#define	bFPGAPHY1_End	 0x9ff
+#define	bCCKPHY0_End	 0xaff
+#define	bOFDMPHY0_End	 0xcff
+#define	bOFDMPHY1_End	 0xdff
+
+/* define max debug item in each debug page */
+/* define bMaxItem_FPGA_PHY0	0x9 */
+/* define bMaxItem_FPGA_PHY1	0x3 */
+/* define bMaxItem_PHY_11B	  0x16 */
+/* define bMaxItem_OFDM_PHY0	0x29 */
+/* define bMaxItem_OFDM_PHY1	0x0 */
+
+#define	bPMACControl	0x0		/*  Useless */
+#define	bWMACControl	0x1
+#define	bWNICControl	0x2
+
+#define RCR_AAP		BIT(0)		/*  accept all physical address */
+#define RCR_APM		BIT(1)		/*  accept physical match */
+#define RCR_AM		BIT(2)		/*  accept multicast */
+#define RCR_AB		BIT(3)		/*  accept broadcast */
+#define RCR_ACRC32	BIT(5)		/*  accept error packet */
+#define RCR_9356SEL	BIT(6)
+#define RCR_AICV	BIT(12)		/*  Accept ICV error packet */
+#define RCR_RXFTH0	(BIT(13)|BIT(14)|BIT(15))	/*  Rx FIFO threshold */
+#define RCR_ADF		BIT(18)		/*  Accept Data(frame type) frame */
+#define RCR_ACF		BIT(19)		/*  Accept control frame */
+#define RCR_AMF		BIT(20)		/*  Accept management frame */
+#define RCR_ADD3	BIT(21)
+#define RCR_APWRMGT	BIT(22)		/*  Accept power management packet */
+#define RCR_CBSSID	BIT(23)		/*  Accept BSSID match packet */
+#define RCR_ENMARP	BIT(28)		/*  enable mac auto reset phy */
+#define RCR_EnCS1	BIT(29)		/*  enable carrier sense method 1 */
+#define RCR_EnCS2	BIT(30)		/*  enable carrier sense method 2 */
+#define RCR_OnlyErlPkt	BIT(31)		/*  Rx Early mode is performed for
+					 *  packet size greater than 1536 */
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+#endif	/* __INC_HAL8192SPHYREG_H */
diff --git a/drivers/staging/rtl8188eu/include/rtw_p2p.h b/drivers/staging/rtl8188eu/include/rtw_p2p.h
new file mode 100644
index 0000000..a3e3adc
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_p2p.h
@@ -0,0 +1,135 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_P2P_H_
+#define __RTW_P2P_H_
+
+#include <drv_types.h>
+
+u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo,
+				   u8 *pbuf, u8 *pssid, u8 ussidlen,
+				   u8 *pdev_raddr);
+u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo,
+			    u8 *pbuf, u8 status_code);
+u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo,
+			     u8 *pframe, uint len);
+u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo,
+			     u8 *pframe, uint len, struct sta_info *psta);
+u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo,
+			    u8 *pframe, uint len);
+u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo,
+			     u8 *pframe, uint len);
+u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo,
+			    u8 *pframe, uint len);
+u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo,  u8 *pframe);
+u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo,
+				    u8 *pframe, uint len);
+u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo,
+				     u8 *pframe, uint len);
+u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo,
+					u8 *pframe, uint len);
+u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe,
+			    uint len);
+void p2p_protocol_wk_hdl(struct adapter *padapter, int intcmdtype);
+void process_p2p_ps_ie(struct adapter *padapter, u8 *ies, u32 ielength);
+void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state);
+u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue);
+void reset_global_wifidirect_info(struct adapter *padapter);
+int rtw_init_wifi_display_info(struct adapter *padapter);
+void rtw_init_wifidirect_timers(struct adapter *padapter);
+void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr,
+			       u8 *iface_addr);
+void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role);
+int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role);
+
+static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo,
+				      enum P2P_STATE state)
+{
+	if (wdinfo->p2p_state != state)
+		wdinfo->p2p_state = state;
+}
+
+static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo,
+					  enum P2P_STATE state)
+{
+	if (wdinfo->pre_p2p_state != state)
+		wdinfo->pre_p2p_state = state;
+}
+
+static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo,
+				     enum P2P_ROLE role)
+{
+	if (wdinfo->role != role)
+		wdinfo->role = role;
+}
+
+static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo)
+{
+	return wdinfo->p2p_state;
+}
+
+static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo)
+{
+	return wdinfo->pre_p2p_state;
+}
+
+static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo)
+{
+	return wdinfo->role;
+}
+
+static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo,
+				      enum P2P_STATE state)
+{
+	return wdinfo->p2p_state == state;
+}
+
+static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo,
+				     enum P2P_ROLE role)
+{
+	return wdinfo->role == role;
+}
+
+#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state)
+#define rtw_p2p_set_pre_state(wdinfo, state)				\
+	 _rtw_p2p_set_pre_state(wdinfo, state)
+#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role)
+
+#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo)
+#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo)
+#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo)
+#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state)
+#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role)
+
+#define rtw_p2p_findphase_ex_set(wdinfo, value) \
+	((wdinfo)->find_phase_state_exchange_cnt = (value))
+
+/* is this find phase exchange for social channel scan? */
+#define rtw_p2p_findphase_ex_is_social(wdinfo)   \
+((wdinfo)->find_phase_state_exchange_cnt >= P2P_FINDPHASE_EX_SOCIAL_FIRST)
+
+/* should we need find phase exchange anymore? */
+#define rtw_p2p_findphase_ex_is_needed(wdinfo) \
+	((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \
+	(wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE)
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
new file mode 100644
index 0000000..d4b8acb
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h
@@ -0,0 +1,283 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_PWRCTRL_H_
+#define __RTW_PWRCTRL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define FW_PWR0		0
+#define FW_PWR1		1
+#define FW_PWR2		2
+#define FW_PWR3		3
+#define HW_PWR0		7
+#define HW_PWR1		6
+#define HW_PWR2		2
+#define HW_PWR3		0
+#define HW_PWR4		8
+
+#define FW_PWRMSK	0x7
+
+#define XMIT_ALIVE	BIT(0)
+#define RECV_ALIVE	BIT(1)
+#define CMD_ALIVE	BIT(2)
+#define EVT_ALIVE	BIT(3)
+
+enum power_mgnt {
+	PS_MODE_ACTIVE = 0,
+	PS_MODE_MIN,
+	PS_MODE_MAX,
+	PS_MODE_DTIM,
+	PS_MODE_VOIP,
+	PS_MODE_UAPSD_WMM,
+	PS_MODE_UAPSD,
+	PS_MODE_IBSS,
+	PS_MODE_WWLAN,
+	PM_Radio_Off,
+	PM_Card_Disable,
+	PS_MODE_NUM
+};
+
+/*
+	BIT[2:0] = HW state
+	BIT[3] = Protocol PS state,   0: register active state,
+				      1: register sleep state
+	BIT[4] = sub-state
+*/
+
+#define PS_DPS			BIT(0)
+#define PS_LCLK			(PS_DPS)
+#define PS_RF_OFF		BIT(1)
+#define PS_ALL_ON		BIT(2)
+#define PS_ST_ACTIVE		BIT(3)
+
+#define PS_ISR_ENABLE		BIT(4)
+#define PS_IMR_ENABLE		BIT(5)
+#define PS_ACK			BIT(6)
+#define PS_TOGGLE		BIT(7)
+
+#define PS_STATE_MASK		(0x0F)
+#define PS_STATE_HW_MASK	(0x07)
+#define PS_SEQ_MASK		(0xc0)
+
+#define PS_STATE(x)		(PS_STATE_MASK & (x))
+#define PS_STATE_HW(x)		(PS_STATE_HW_MASK & (x))
+#define PS_SEQ(x)		(PS_SEQ_MASK & (x))
+
+#define PS_STATE_S0		(PS_DPS)
+#define PS_STATE_S1		(PS_LCLK)
+#define PS_STATE_S2		(PS_RF_OFF)
+#define PS_STATE_S3		(PS_ALL_ON)
+#define PS_STATE_S4		((PS_ST_ACTIVE) | (PS_ALL_ON))
+
+#define PS_IS_RF_ON(x)	((x) & (PS_ALL_ON))
+#define PS_IS_ACTIVE(x)	((x) & (PS_ST_ACTIVE))
+#define CLR_PS_STATE(x)	((x) = ((x) & (0xF0)))
+
+struct reportpwrstate_parm {
+	unsigned char mode;
+	unsigned char state; /* the CPWM value */
+	unsigned short rsvd;
+};
+
+static inline void _init_pwrlock(struct semaphore  *plock)
+{
+	_rtw_init_sema(plock, 1);
+}
+
+static inline void _free_pwrlock(struct semaphore  *plock)
+{
+	_rtw_free_sema(plock);
+}
+
+static inline void _enter_pwrlock(struct semaphore  *plock)
+{
+	_rtw_down_sema(plock);
+}
+
+static inline void _exit_pwrlock(struct semaphore  *plock)
+{
+	_rtw_up_sema(plock);
+}
+
+#define LPS_DELAY_TIME	1*HZ /*  1 sec */
+
+#define EXE_PWR_NONE	0x01
+#define EXE_PWR_IPS		0x02
+#define EXE_PWR_LPS		0x04
+
+/*  RF state. */
+enum rt_rf_power_state {
+	rf_on,		/*  RF is on after RFSleep or RFOff */
+	rf_sleep,	/*  802.11 Power Save mode */
+	rf_off,		/*  HW/SW Radio OFF or Inactive Power Save */
+	/* Add the new RF state above this line===== */
+	rf_max
+};
+
+/*  RF Off Level for IPS or HW/SW radio off */
+#define	RT_RF_OFF_LEVL_ASPM		BIT(0)	/* PCI ASPM */
+#define	RT_RF_OFF_LEVL_CLK_REQ		BIT(1)	/* PCI clock request */
+#define	RT_RF_OFF_LEVL_PCI_D3		BIT(2)	/* PCI D3 mode */
+#define	RT_RF_OFF_LEVL_HALT_NIC		BIT(3)	/* NIC halt, re-init hw param*/
+#define	RT_RF_OFF_LEVL_FREE_FW		BIT(4)	/* FW free, re-download the FW*/
+#define	RT_RF_OFF_LEVL_FW_32K		BIT(5)	/* FW in 32k */
+#define	RT_RF_PS_LEVEL_ALWAYS_ASPM	BIT(6)	/* Always enable ASPM and Clock
+						 * Req in initialization. */
+#define	RT_RF_LPS_DISALBE_2R		BIT(30)	/* When LPS is on, disable 2R
+						 * if no packet is RX or TX. */
+#define	RT_RF_LPS_LEVEL_ASPM		BIT(31)	/* LPS with ASPM */
+
+#define	RT_IN_PS_LEVEL(ppsc, _PS_FLAG)				\
+	((ppsc->cur_ps_level & _PS_FLAG) ? true : false)
+#define	RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG)			\
+	(ppsc->cur_ps_level &= (~(_PS_FLAG)))
+#define	RT_SET_PS_LEVEL(ppsc, _PS_FLAG)				\
+	(ppsc->cur_ps_level |= _PS_FLAG)
+
+enum _PS_BBRegBackup_ {
+	PSBBREG_RF0 = 0,
+	PSBBREG_RF1,
+	PSBBREG_RF2,
+	PSBBREG_AFE0,
+	PSBBREG_TOTALCNT
+};
+
+enum { /*  for ips_mode */
+	IPS_NONE = 0,
+	IPS_NORMAL,
+	IPS_LEVEL_2,
+};
+
+struct pwrctrl_priv {
+	struct semaphore lock;
+	volatile u8 rpwm; /*  requested power state for fw */
+	volatile u8 cpwm; /*  fw current power state. updated when
+			   * 1. read from HCPWM 2. driver lowers power level */
+	volatile u8 tog; /*  toggling */
+	volatile u8 cpwm_tog; /*  toggling */
+
+	u8	pwr_mode;
+	u8	smart_ps;
+	u8	bcn_ant_mode;
+
+	u32	alives;
+	struct work_struct cpwm_event;
+	u8	bpower_saving;
+
+	u8	b_hw_radio_off;
+	u8	reg_rfoff;
+	u8	reg_pdnmode; /* powerdown mode */
+	u32	rfoff_reason;
+
+	/* RF OFF Level */
+	u32	cur_ps_level;
+	u32	reg_rfps_level;
+	uint	ips_enter_cnts;
+	uint	ips_leave_cnts;
+
+	u8	ips_mode;
+	u8	ips_mode_req;	/*  used to accept the mode setting request,
+				 *  will update to ipsmode later */
+	uint bips_processing;
+	u32 ips_deny_time; /* will deny IPS when system time less than this */
+	u8 ps_processing; /* temp used to mark whether in rtw_ps_processor */
+
+	u8	bLeisurePs;
+	u8	LpsIdleCount;
+	u8	power_mgnt;
+	u8	bFwCurrentInPSMode;
+	u32	DelayLPSLastTimeStamp;
+	u8	btcoex_rfon;
+	s32		pnp_current_pwr_state;
+	u8		pnp_bstop_trx;
+
+	u8		bInternalAutoSuspend;
+	u8		bInSuspend;
+#ifdef	CONFIG_BT_COEXIST
+	u8		bAutoResume;
+	u8		autopm_cnt;
+#endif
+	u8		bSupportRemoteWakeup;
+	struct timer_list pwr_state_check_timer;
+	int		pwr_state_check_interval;
+	u8		pwr_state_check_cnts;
+
+	int		ps_flag;
+
+	enum rt_rf_power_state	rf_pwrstate;/* cur power state */
+	enum rt_rf_power_state	change_rfpwrstate;
+
+	u8		wepkeymask;
+	u8		bHWPowerdown;/* if support hw power down */
+	u8		bHWPwrPindetect;
+	u8		bkeepfwalive;
+	u8		brfoffbyhw;
+	unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT];
+};
+
+#define rtw_get_ips_mode_req(pwrctrlpriv) \
+	(pwrctrlpriv)->ips_mode_req
+
+#define rtw_ips_mode_req(pwrctrlpriv, ips_mode) \
+	((pwrctrlpriv)->ips_mode_req = (ips_mode))
+
+#define RTW_PWR_STATE_CHK_INTERVAL 2000
+
+#define _rtw_set_pwr_state_check_timer(pwrctrlpriv, ms) \
+	do { \
+		_set_timer(&(pwrctrlpriv)->pwr_state_check_timer, (ms)); \
+	} while (0)
+
+#define rtw_set_pwr_state_check_timer(pwrctrl)			\
+	_rtw_set_pwr_state_check_timer((pwrctrl),		\
+				       (pwrctrl)->pwr_state_check_interval)
+
+void rtw_init_pwrctrl_priv(struct adapter *adapter);
+void rtw_free_pwrctrl_priv(struct adapter *adapter);
+
+void rtw_set_ps_mode(struct adapter *adapter, u8 ps_mode, u8 smart_ps,
+		     u8 bcn_ant_mode);
+void rtw_set_rpwm(struct adapter *adapter, u8 val8);
+void LeaveAllPowerSaveMode(struct adapter *adapter);
+void ips_enter(struct adapter *padapter);
+int ips_leave(struct adapter *padapter);
+
+void rtw_ps_processor(struct adapter *padapter);
+
+enum rt_rf_power_state RfOnOffDetect(struct adapter *iadapter);
+
+s32 LPS_RF_ON_check(struct adapter *adapter, u32 delay_ms);
+void LPS_Enter(struct adapter *adapter);
+void LPS_Leave(struct adapter *adapter);
+
+u8 rtw_interface_ps_func(struct adapter *adapter,
+			 enum hal_intf_ps_func efunc_id, u8 *val);
+void rtw_set_ips_deny(struct adapter *adapter, u32 ms);
+int _rtw_pwr_wakeup(struct adapter *adapter, u32 ips_defer_ms,
+		    const char *caller);
+#define rtw_pwr_wakeup(adapter)						\
+	 _rtw_pwr_wakeup(adapter, RTW_PWR_STATE_CHK_INTERVAL, __func__)
+#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms)			\
+	 _rtw_pwr_wakeup(adapter, ips_deffer_ms, __func__)
+int rtw_pm_set_ips(struct adapter *adapter, u8 mode);
+int rtw_pm_set_lps(struct adapter *adapter, u8 mode);
+
+#endif  /* __RTL871X_PWRCTRL_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_qos.h b/drivers/staging/rtl8188eu/include/rtw_qos.h
new file mode 100644
index 0000000..bbee1dd
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_qos.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_QOS_H_
+#define _RTW_QOS_H_
+
+#include <osdep_service.h>
+
+struct	qos_priv	{
+	unsigned int	  qos_option;	/* bit mask option: u-apsd,
+					 * s-apsd, ts, block ack... */
+};
+
+#endif	/* _RTL871X_QOS_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_recv.h b/drivers/staging/rtl8188eu/include/rtw_recv.h
new file mode 100644
index 0000000..bae8885
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_recv.h
@@ -0,0 +1,485 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_RECV_H_
+#define _RTW_RECV_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#define NR_RECVFRAME 256
+
+#define RXFRAME_ALIGN	8
+#define RXFRAME_ALIGN_SZ	(1<<RXFRAME_ALIGN)
+
+#define MAX_RXFRAME_CNT	512
+#define MAX_RX_NUMBLKS		(32)
+#define RECVFRAME_HDR_ALIGN 128
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define MAX_SUBFRAME_COUNT	64
+
+/* for Rx reordering buffer control */
+struct recv_reorder_ctrl {
+	struct adapter	*padapter;
+	u8 enable;
+	u16 indicate_seq;/* wstart_b, init_value=0xffff */
+	u16 wend_b;
+	u8 wsize_b;
+	struct __queue pending_recvframe_queue;
+	struct timer_list reordering_ctrl_timer;
+};
+
+struct	stainfo_rxcache	{
+	u16	tid_rxseq[16];
+/*
+	unsigned short	tid0_rxseq;
+	unsigned short	tid1_rxseq;
+	unsigned short	tid2_rxseq;
+	unsigned short	tid3_rxseq;
+	unsigned short	tid4_rxseq;
+	unsigned short	tid5_rxseq;
+	unsigned short	tid6_rxseq;
+	unsigned short	tid7_rxseq;
+	unsigned short	tid8_rxseq;
+	unsigned short	tid9_rxseq;
+	unsigned short	tid10_rxseq;
+	unsigned short	tid11_rxseq;
+	unsigned short	tid12_rxseq;
+	unsigned short	tid13_rxseq;
+	unsigned short	tid14_rxseq;
+	unsigned short	tid15_rxseq;
+*/
+};
+
+struct smooth_rssi_data {
+	u32	elements[100];	/* array to store values */
+	u32	index;			/* index to current array to store */
+	u32	total_num;		/* num of valid elements */
+	u32	total_val;		/* sum of valid elements */
+};
+
+struct signal_stat {
+	u8	update_req;		/* used to indicate */
+	u8	avg_val;		/* avg of valid elements */
+	u32	total_num;		/* num of valid elements */
+	u32	total_val;		/* sum of valid elements */
+};
+#define MAX_PATH_NUM_92CS		2
+struct phy_info {
+	u8	RxPWDBAll;
+	u8	SignalQuality;	 /*  in 0-100 index. */
+	u8	RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */
+	u8	RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/*  in 0~100 index */
+	s8	RxPower; /*  in dBm Translate from PWdB */
+/*  Real power in dBm for this packet, no beautification and aggregation.
+ * Keep this raw info to be used for the other procedures. */
+	s8	recvpower;
+	u8	BTRxRSSIPercentage;
+	u8	SignalStrength; /*  in 0-100 index. */
+	u8	RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */
+	u8	RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */
+};
+
+struct rx_pkt_attrib {
+	u16	pkt_len;
+	u8	physt;
+	u8	drvinfo_sz;
+	u8	shift_sz;
+	u8	hdrlen; /* the WLAN Header Len */
+	u8	to_fr_ds;
+	u8	amsdu;
+	u8	qos;
+	u8	priority;
+	u8	pw_save;
+	u8	mdata;
+	u16	seq_num;
+	u8	frag_num;
+	u8	mfrag;
+	u8	order;
+	u8	privacy; /* in frame_ctrl field */
+	u8	bdecrypted;
+	u8	encrypt; /* when 0 indicate no encrypt. when non-zero,
+			  * indicate the encrypt algorith */
+	u8	iv_len;
+	u8	icv_len;
+	u8	crc_err;
+	u8	icv_err;
+
+	u16 eth_type;
+
+	u8	dst[ETH_ALEN];
+	u8	src[ETH_ALEN];
+	u8	ta[ETH_ALEN];
+	u8	ra[ETH_ALEN];
+	u8	bssid[ETH_ALEN];
+
+	u8 ack_policy;
+
+	u8	key_index;
+
+	u8	mcs_rate;
+	u8	rxht;
+	u8	sgi;
+	u8	pkt_rpt_type;
+	u32	MacIDValidEntry[2];	/*  64 bits present 64 entry. */
+
+	struct phy_info phy_info;
+};
+
+
+/* These definition is used for Rx packet reordering. */
+#define SN_LESS(a, b)		(((a - b) & 0x800) != 0)
+#define SN_EQUAL(a, b)	(a == b)
+#define REORDER_WAIT_TIME	(50) /*  (ms) */
+
+#define RECVBUFF_ALIGN_SZ 8
+
+#define RXDESC_SIZE	24
+#define RXDESC_OFFSET RXDESC_SIZE
+
+struct recv_stat {
+	__le32 rxdw0;
+	__le32 rxdw1;
+	__le32 rxdw2;
+	__le32 rxdw3;
+	__le32 rxdw4;
+	__le32 rxdw5;
+};
+
+#define EOR BIT(30)
+
+/*
+accesser of recv_priv: rtw_recv_entry(dispatch / passive level);
+recv_thread(passive) ; returnpkt(dispatch)
+; halt(passive) ;
+
+using enter_critical section to protect
+*/
+struct recv_priv {
+	spinlock_t lock;
+	struct __queue free_recv_queue;
+	struct __queue recv_pending_queue;
+	struct __queue uc_swdec_pending_queue;
+	u8 *pallocated_frame_buf;
+	u8 *precv_frame_buf;
+	uint free_recvframe_cnt;
+	struct adapter	*adapter;
+	u32	bIsAnyNonBEPkts;
+	u64	rx_bytes;
+	u64	rx_pkts;
+	u64	rx_drop;
+	u64	last_rx_bytes;
+
+	uint  rx_icv_err;
+	uint  rx_largepacket_crcerr;
+	uint  rx_smallpacket_crcerr;
+	uint  rx_middlepacket_crcerr;
+	struct semaphore allrxreturnevt;
+	uint	ff_hwaddr;
+	u8	rx_pending_cnt;
+
+	struct tasklet_struct irq_prepare_beacon_tasklet;
+	struct tasklet_struct recv_tasklet;
+	struct sk_buff_head free_recv_skb_queue;
+	struct sk_buff_head rx_skb_queue;
+	u8 *pallocated_recv_buf;
+	u8 *precv_buf;    /*  4 alignment */
+	struct __queue free_recv_buf_queue;
+	u32	free_recv_buf_queue_cnt;
+	/* For display the phy informatiom */
+	u8 is_signal_dbg;	/*  for debug */
+	u8 signal_strength_dbg;	/*  for debug */
+	s8 rssi;
+	s8 rxpwdb;
+	u8 signal_strength;
+	u8 signal_qual;
+	u8 noise;
+	int RxSNRdB[2];
+	s8 RxRssi[2];
+	int FalseAlmCnt_all;
+
+	struct timer_list signal_stat_timer;
+	u32 signal_stat_sampling_interval;
+	struct signal_stat signal_qual_data;
+	struct signal_stat signal_strength_data;
+};
+
+#define rtw_set_signal_stat_timer(recvpriv)			\
+	_set_timer(&(recvpriv)->signal_stat_timer,		\
+		   (recvpriv)->signal_stat_sampling_interval)
+
+struct sta_recv_priv {
+	spinlock_t lock;
+	int	option;
+	struct __queue defrag_q; /* keeping the fragment frame until defrag */
+	struct	stainfo_rxcache rxcache;
+};
+
+struct recv_buf {
+	struct list_head list;
+	spinlock_t recvbuf_lock;
+	u32	ref_cnt;
+	struct adapter *adapter;
+	u8	*pbuf;
+	u8	*pallocated_buf;
+	u32	len;
+	u8	*phead;
+	u8	*pdata;
+	u8	*ptail;
+	u8	*pend;
+	struct urb *purb;
+	dma_addr_t dma_transfer_addr;	/* (in) dma addr for transfer_buffer */
+	u32 alloc_sz;
+	u8  irp_pending;
+	int  transfer_len;
+	struct sk_buff *pskb;
+	u8	reuse;
+};
+
+/*
+	head  ----->
+
+		data  ----->
+
+			payload
+
+		tail  ----->
+
+
+	end   ----->
+
+	len = (unsigned int )(tail - data);
+
+*/
+struct recv_frame_hdr {
+	struct list_head list;
+	struct sk_buff	 *pkt;
+	struct sk_buff	 *pkt_newalloc;
+	struct adapter  *adapter;
+	u8 fragcnt;
+	int frame_tag;
+	struct rx_pkt_attrib attrib;
+	uint  len;
+	u8 *rx_head;
+	u8 *rx_data;
+	u8 *rx_tail;
+	u8 *rx_end;
+	void *precvbuf;
+	struct sta_info *psta;
+	/* for A-MPDU Rx reordering buffer control */
+	struct recv_reorder_ctrl *preorder_ctrl;
+};
+
+union recv_frame {
+	union {
+		struct list_head list;
+		struct recv_frame_hdr hdr;
+		uint mem[RECVFRAME_HDR_ALIGN>>2];
+	} u;
+};
+
+union recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
+union recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue);
+void rtw_init_recvframe(union recv_frame *precvframe,
+			struct recv_priv *precvpriv);
+int  rtw_free_recvframe(union recv_frame *precvframe,
+			struct __queue *pfree_recv_queue);
+#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue)
+int _rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue);
+int rtw_enqueue_recvframe(union recv_frame *precvframe, struct __queue *queue);
+void rtw_free_recvframe_queue(struct __queue *pframequeue,
+			      struct __queue *pfree_recv_queue);
+u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter);
+int rtw_enqueue_recvbuf_to_head(struct recv_buf *buf, struct __queue *queue);
+int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue);
+struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue);
+
+void rtw_reordering_ctrl_timeout_handler(void *pcontext);
+
+static inline u8 *get_rxmem(union recv_frame *precvframe)
+{
+	/* always return rx_head... */
+	if (precvframe == NULL)
+		return NULL;
+	return precvframe->u.hdr.rx_head;
+}
+
+static inline u8 *get_rx_status(union recv_frame *precvframe)
+{
+	return get_rxmem(precvframe);
+}
+
+static inline u8 *get_recvframe_data(union recv_frame *precvframe)
+{
+	/* always return rx_data */
+	if (precvframe == NULL)
+		return NULL;
+
+	return precvframe->u.hdr.rx_data;
+}
+
+static inline u8 *recvframe_push(union recv_frame *precvframe, int sz)
+{
+	/*  append data before rx_data */
+
+	/* add data to the start of recv_frame
+ *
+ *      This function extends the used data area of the recv_frame at the buffer
+ *      start. rx_data must be still larger than rx_head, after pushing.
+ */
+	if (precvframe == NULL)
+		return NULL;
+	precvframe->u.hdr.rx_data -= sz ;
+	if (precvframe->u.hdr.rx_data < precvframe->u.hdr.rx_head) {
+		precvframe->u.hdr.rx_data += sz;
+		return NULL;
+	}
+	precvframe->u.hdr.len += sz;
+	return precvframe->u.hdr.rx_data;
+}
+
+static inline u8 *recvframe_pull(union recv_frame *precvframe, int sz)
+{
+	/*  rx_data += sz; move rx_data sz bytes  hereafter */
+
+	/* used for extract sz bytes from rx_data, update rx_data and return
+	 * the updated rx_data to the caller */
+
+	if (precvframe == NULL)
+		return NULL;
+	precvframe->u.hdr.rx_data += sz;
+	if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) {
+		precvframe->u.hdr.rx_data -= sz;
+		return NULL;
+	}
+	precvframe->u.hdr.len -= sz;
+	return precvframe->u.hdr.rx_data;
+}
+
+static inline u8 *recvframe_put(union recv_frame *precvframe, int sz)
+{
+	/* used for append sz bytes from ptr to rx_tail, update rx_tail
+	 * and return the updated rx_tail to the caller */
+	/* after putting, rx_tail must be still larger than rx_end. */
+
+	if (precvframe == NULL)
+		return NULL;
+
+	precvframe->u.hdr.rx_tail += sz;
+
+	if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) {
+		precvframe->u.hdr.rx_tail -= sz;
+		return NULL;
+	}
+	precvframe->u.hdr.len += sz;
+	return precvframe->u.hdr.rx_tail;
+}
+
+static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, int sz)
+{
+	/*  rmv data from rx_tail (by yitsen) */
+
+	/* used for extract sz bytes from rx_end, update rx_end and return
+	 * the updated rx_end to the caller */
+	/* after pulling, rx_end must be still larger than rx_data. */
+
+	if (precvframe == NULL)
+		return NULL;
+	precvframe->u.hdr.rx_tail -= sz;
+	if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) {
+		precvframe->u.hdr.rx_tail += sz;
+		return NULL;
+	}
+	precvframe->u.hdr.len -= sz;
+	return precvframe->u.hdr.rx_tail;
+}
+
+static inline unsigned char *get_rxbuf_desc(union recv_frame *precvframe)
+{
+	unsigned char *buf_desc;
+
+	if (precvframe == NULL)
+		return NULL;
+	return buf_desc;
+}
+
+static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem)
+{
+	/* due to the design of 2048 bytes alignment of recv_frame,
+	 * we can reference the union recv_frame */
+	/* from any given member of recv_frame. */
+	/*  rxmem indicates the any member/address in recv_frame */
+
+	return (union recv_frame *)(((size_t)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN);
+}
+
+static inline union recv_frame *pkt_to_recvframe(struct sk_buff *pkt)
+{
+	u8 *buf_star;
+	union recv_frame *precv_frame;
+	precv_frame = rxmem_to_recvframe((unsigned char *)buf_star);
+
+	return precv_frame;
+}
+
+static inline u8 *pkt_to_recvmem(struct sk_buff *pkt)
+{
+	/*  return the rx_head */
+
+	union recv_frame *precv_frame = pkt_to_recvframe(pkt);
+
+	return	precv_frame->u.hdr.rx_head;
+}
+
+static inline u8 *pkt_to_recvdata(struct sk_buff *pkt)
+{
+	/*  return the rx_data */
+
+	union recv_frame *precv_frame = pkt_to_recvframe(pkt);
+
+	return	precv_frame->u.hdr.rx_data;
+}
+
+static inline int get_recvframe_len(union recv_frame *precvframe)
+{
+	return precvframe->u.hdr.len;
+}
+
+static inline s32 translate_percentage_to_dbm(u32 sig_stren_index)
+{
+	s32	power; /*  in dBm. */
+
+	/*  Translate to dBm (x=0.5y-95). */
+	power = (s32)((sig_stren_index + 1) >> 1);
+	power -= 95;
+
+	return power;
+}
+
+
+struct sta_info;
+
+void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv);
+
+void  mgt_dispatcher(struct adapter *padapter, union recv_frame *precv_frame);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_rf.h b/drivers/staging/rtl8188eu/include/rtw_rf.h
new file mode 100644
index 0000000..089ecee
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_rf.h
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef	__RTW_RF_H_
+#define __RTW_RF_H_
+
+#include <rtw_cmd.h>
+
+#define OFDM_PHY		1
+#define MIXED_PHY		2
+#define CCK_PHY		3
+
+#define NumRates	(13)
+
+/*  slot time for 11g */
+#define SHORT_SLOT_TIME			9
+#define NON_SHORT_SLOT_TIME		20
+
+#define RTL8711_RF_MAX_SENS		6
+#define RTL8711_RF_DEF_SENS		4
+
+/*  We now define the following channels as the max channels in each
+ * channel plan. */
+/*  2G, total 14 chnls */
+/*  {1,2,3,4,5,6,7,8,9,10,11,12,13,14} */
+#define	MAX_CHANNEL_NUM_2G		14
+#define	MAX_CHANNEL_NUM			14	/* 2.4 GHz only */
+
+#define NUM_REGULATORYS	1
+
+/* Country codes */
+#define USA				0x555320
+#define EUROPE				0x1 /* temp, should be provided later */
+#define JAPAN				0x2 /* temp, should be provided later */
+
+struct	regulatory_class {
+	u32	starting_freq;				/* MHz, */
+	u8	channel_set[MAX_CHANNEL_NUM];
+	u8	channel_cck_power[MAX_CHANNEL_NUM];	/* dbm */
+	u8	channel_ofdm_power[MAX_CHANNEL_NUM];	/* dbm */
+	u8	txpower_limit;				/* dbm */
+	u8	channel_spacing;			/* MHz */
+	u8	modem;
+};
+
+enum capability {
+	cESS		= 0x0001,
+	cIBSS		= 0x0002,
+	cPollable	= 0x0004,
+	cPollReq	= 0x0008,
+	cPrivacy	= 0x0010,
+	cShortPreamble	= 0x0020,
+	cPBCC		= 0x0040,
+	cChannelAgility	= 0x0080,
+	cSpectrumMgnt	= 0x0100,
+	cQos		= 0x0200,	/* For HCCA, use with CF-Pollable
+					 * and CF-PollReq */
+	cShortSlotTime	= 0x0400,
+	cAPSD		= 0x0800,
+	cRM		= 0x1000,	/*  RRM (Radio Request Measurement) */
+	cDSSS_OFDM	= 0x2000,
+	cDelayedBA	= 0x4000,
+	cImmediateBA	= 0x8000,
+};
+
+enum	_REG_PREAMBLE_MODE {
+	PREAMBLE_LONG	= 1,
+	PREAMBLE_AUTO	= 2,
+	PREAMBLE_SHORT	= 3,
+};
+
+enum _RTL8712_RF_MIMO_CONFIG_ {
+	RTL8712_RFCONFIG_1T = 0x10,
+	RTL8712_RFCONFIG_2T = 0x20,
+	RTL8712_RFCONFIG_1R = 0x01,
+	RTL8712_RFCONFIG_2R = 0x02,
+	RTL8712_RFCONFIG_1T1R = 0x11,
+	RTL8712_RFCONFIG_1T2R = 0x12,
+	RTL8712_RFCONFIG_TURBO = 0x92,
+	RTL8712_RFCONFIG_2T2R = 0x22
+};
+
+enum rf90_radio_path {
+	RF90_PATH_A = 0,		/* Radio Path A */
+	RF90_PATH_B = 1,		/* Radio Path B */
+	RF90_PATH_C = 2,		/* Radio Path C */
+	RF90_PATH_D = 3			/* Radio Path D */
+};
+
+/*  Bandwidth Offset */
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE	0
+#define HAL_PRIME_CHNL_OFFSET_LOWER	1
+#define HAL_PRIME_CHNL_OFFSET_UPPER	2
+
+/*  Represent Channel Width in HT Capabilities */
+/*  */
+enum ht_channel_width {
+	HT_CHANNEL_WIDTH_20 = 0,
+	HT_CHANNEL_WIDTH_40 = 1,
+	HT_CHANNEL_WIDTH_80 = 2,
+	HT_CHANNEL_WIDTH_160 = 3,
+	HT_CHANNEL_WIDTH_10 = 4,
+};
+
+/*  */
+/*  Represent Extention Channel Offset in HT Capabilities */
+/*  This is available only in 40Mhz mode. */
+/*  */
+enum ht_extchnl_offset {
+	HT_EXTCHNL_OFFSET_NO_EXT = 0,
+	HT_EXTCHNL_OFFSET_UPPER = 1,
+	HT_EXTCHNL_OFFSET_NO_DEF = 2,
+	HT_EXTCHNL_OFFSET_LOWER = 3,
+};
+
+/* 2007/11/15 MH Define different RF type. */
+enum rt_rf_type_def {
+	RF_1T2R = 0,
+	RF_2T4R = 1,
+	RF_2T2R = 2,
+	RF_1T1R = 3,
+	RF_2T2R_GREEN = 4,
+	RF_819X_MAX_TYPE = 5,
+};
+
+u32 rtw_ch2freq(u32 ch);
+u32 rtw_freq2ch(u32 freq);
+
+
+#endif /* _RTL8711_RF_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_security.h b/drivers/staging/rtl8188eu/include/rtw_security.h
new file mode 100644
index 0000000..23c7814
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_security.h
@@ -0,0 +1,383 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_SECURITY_H_
+#define __RTW_SECURITY_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define _NO_PRIVACY_			0x0
+#define _WEP40_				0x1
+#define _TKIP_				0x2
+#define _TKIP_WTMIC_			0x3
+#define _AES_				0x4
+#define _WEP104_			0x5
+#define _WEP_WPA_MIXED_			0x07  /*  WEP + WPA */
+#define _SMS4_				0x06
+
+#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_))
+
+#define _WPA_IE_ID_	0xdd
+#define _WPA2_IE_ID_	0x30
+
+#define SHA256_MAC_LEN 32
+#define AES_BLOCK_SIZE 16
+#define AES_PRIV_SIZE (4 * 44)
+
+enum {
+	ENCRYP_PROTOCOL_OPENSYS,   /* open system */
+	ENCRYP_PROTOCOL_WEP,       /* WEP */
+	ENCRYP_PROTOCOL_WPA,       /* WPA */
+	ENCRYP_PROTOCOL_WPA2,      /* WPA2 */
+	ENCRYP_PROTOCOL_WAPI,      /* WAPI: Not support in this version */
+	ENCRYP_PROTOCOL_MAX
+};
+
+
+#ifndef Ndis802_11AuthModeWPA2
+#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1)
+#endif
+
+#ifndef Ndis802_11AuthModeWPA2PSK
+#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2)
+#endif
+
+union pn48	{
+	u64	val;
+
+#ifdef __LITTLE_ENDIAN
+	struct {
+		u8 TSC0;
+		u8 TSC1;
+		u8 TSC2;
+		u8 TSC3;
+		u8 TSC4;
+		u8 TSC5;
+		u8 TSC6;
+		u8 TSC7;
+	} _byte_;
+
+#elif defined(__BIG_ENDIAN)
+
+	struct {
+		u8 TSC7;
+		u8 TSC6;
+		u8 TSC5;
+		u8 TSC4;
+		u8 TSC3;
+		u8 TSC2;
+		u8 TSC1;
+		u8 TSC0;
+	} _byte_;
+#endif
+};
+
+union Keytype {
+	u8   skey[16];
+	u32    lkey[4];
+};
+
+struct rt_pmkid_list {
+	u8	bUsed;
+	u8	Bssid[6];
+	u8	PMKID[16];
+	u8	SsidBuf[33];
+	u8	*ssid_octet;
+	u16	ssid_length;
+};
+
+struct security_priv {
+	u32	  dot11AuthAlgrthm;	/*  802.11 auth, could be open,
+					 * shared, 8021x and authswitch */
+	u32	  dot11PrivacyAlgrthm;	/*  This specify the privacy for
+					 * shared auth. algorithm. */
+	/* WEP */
+	u32	  dot11PrivacyKeyIndex;	/*  this is only valid for legendary
+					 * wep, 0~3 for key id.(tx key index) */
+	union Keytype dot11DefKey[4];	/*  this is only valid for def. key */
+	u32	dot11DefKeylen[4];
+	u32 dot118021XGrpPrivacy;	/*  This specify the privacy algthm.
+					 * used for Grp key */
+	u32	dot118021XGrpKeyid;	/*  key id used for Grp Key
+					 * ( tx key index) */
+	union Keytype	dot118021XGrpKey[4];	/*  802.1x Group Key,
+						 * for inx0 and inx1 */
+	union Keytype	dot118021XGrptxmickey[4];
+	union Keytype	dot118021XGrprxmickey[4];
+	union pn48	dot11Grptxpn;		/* PN48 used for Grp Key xmit.*/
+	union pn48	dot11Grprxpn;		/* PN48 used for Grp Key recv.*/
+#ifdef CONFIG_88EU_AP_MODE
+	/* extend security capabilities for AP_MODE */
+	unsigned int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */
+	unsigned int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */
+	unsigned int wpa_group_cipher;
+	unsigned int wpa2_group_cipher;
+	unsigned int wpa_pairwise_cipher;
+	unsigned int wpa2_pairwise_cipher;
+#endif
+	u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */
+	int wps_ie_len;
+	u8	binstallGrpkey;
+	u8	busetkipkey;
+	u8	bcheck_grpkey;
+	u8	bgrpkey_handshake;
+	s32	sw_encrypt;/* from registry_priv */
+	s32	sw_decrypt;/* from registry_priv */
+	s32	hw_decrypted;/* if the rx packets is hw_decrypted==false,i
+			      * it means the hw has not been ready. */
+
+	/* keeps the auth_type & enc_status from upper layer
+	 * ioctl(wpa_supplicant or wzc) */
+	u32 ndisauthtype;	/*  NDIS_802_11_AUTHENTICATION_MODE */
+	u32 ndisencryptstatus;	/*  NDIS_802_11_ENCRYPTION_STATUS */
+	struct wlan_bssid_ex sec_bss;  /* for joinbss (h2c buffer) usage */
+	struct ndis_802_11_wep ndiswep;
+	u8 assoc_info[600];
+	u8 szofcapability[256]; /* for wpa2 usage */
+	u8 oidassociation[512]; /* for wpa/wpa2 usage */
+	u8 authenticator_ie[256];  /* store ap security information element */
+	u8 supplicant_ie[256];  /* store sta security information element */
+
+	/* for tkip countermeasure */
+	u32 last_mic_err_time;
+	u8	btkip_countermeasure;
+	u8	btkip_wait_report;
+	u32 btkip_countermeasure_time;
+
+	/*  */
+	/*  For WPA2 Pre-Authentication. */
+	/*  */
+	struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE];
+	u8	PMKIDIndex;
+	u8 bWepDefaultKeyIdxSet;
+};
+
+struct sha256_state {
+	u64 length;
+	u32 state[8], curlen;
+	u8 buf[64];
+};
+
+#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)		\
+do {									\
+	switch (psecuritypriv->dot11AuthAlgrthm) {			\
+	case dot11AuthAlgrthm_Open:					\
+	case dot11AuthAlgrthm_Shared:					\
+	case dot11AuthAlgrthm_Auto:					\
+		encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;	\
+		break;							\
+	case dot11AuthAlgrthm_8021X:					\
+		if (bmcst)						\
+			encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\
+		else							\
+			encry_algo = (u8)psta->dot118021XPrivacy;	\
+		break;							\
+	case dot11AuthAlgrthm_WAPI:					\
+		encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;	\
+		break;							\
+	}								\
+} while (0)
+
+#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt)			\
+do {									\
+	switch (encrypt) {						\
+	case _WEP40_:							\
+	case _WEP104_:							\
+		iv_len = 4;						\
+		icv_len = 4;						\
+		break;							\
+	case _TKIP_:							\
+		iv_len = 8;						\
+		icv_len = 4;						\
+		break;							\
+	case _AES_:							\
+		iv_len = 8;						\
+		icv_len = 8;						\
+		break;							\
+	case _SMS4_:							\
+		iv_len = 18;						\
+		icv_len = 16;						\
+		break;							\
+	default:							\
+		iv_len = 0;						\
+		icv_len = 0;						\
+		break;							\
+	}								\
+} while (0)
+
+
+#define GET_TKIP_PN(iv, dot11txpn)					\
+do {									\
+	dot11txpn._byte_.TSC0 = iv[2];					\
+	dot11txpn._byte_.TSC1 = iv[0];					\
+	dot11txpn._byte_.TSC2 = iv[4];					\
+	dot11txpn._byte_.TSC3 = iv[5];					\
+	dot11txpn._byte_.TSC4 = iv[6];					\
+	dot11txpn._byte_.TSC5 = iv[7];					\
+} while (0)
+
+
+#define ROL32(A, n)	(((A) << (n)) | (((A)>>(32-(n)))  & ((1UL << (n)) - 1)))
+#define ROR32(A, n)	ROL32((A), 32-(n))
+
+struct mic_data {
+	u32  K0, K1;         /*  Key */
+	u32  L, R;           /*  Current state */
+	u32  M;              /*  Message accumulator (single word) */
+	u32  nBytesInM;      /*  # bytes in M */
+};
+
+extern const u32 Te0[256];
+extern const u32 Te1[256];
+extern const u32 Te2[256];
+extern const u32 Te3[256];
+extern const u32 Te4[256];
+extern const u32 Td0[256];
+extern const u32 Td1[256];
+extern const u32 Td2[256];
+extern const u32 Td3[256];
+extern const u32 Td4[256];
+extern const u32 rcon[10];
+extern const u8 Td4s[256];
+extern const u8 rcons[10];
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+			((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+
+#define WPA_GET_BE32(a) ((((u32)(a)[0]) << 24) | (((u32)(a)[1]) << 16) | \
+			 (((u32)(a)[2]) << 8) | ((u32)(a)[3]))
+
+#define WPA_PUT_LE16(a, val)			\
+	do {					\
+		(a)[1] = ((u16)(val)) >> 8;	\
+		(a)[0] = ((u16)(val)) & 0xff;	\
+	} while (0)
+
+#define WPA_PUT_BE32(a, val)					\
+	do {							\
+		(a)[0] = (u8)((((u32)(val)) >> 24) & 0xff);	\
+		(a)[1] = (u8)((((u32)(val)) >> 16) & 0xff);	\
+		(a)[2] = (u8)((((u32)(val)) >> 8) & 0xff);	\
+		(a)[3] = (u8)(((u32)(val)) & 0xff);		\
+	} while (0)
+
+#define WPA_PUT_BE64(a, val)				\
+	do {						\
+		(a)[0] = (u8)(((u64)(val)) >> 56);	\
+		(a)[1] = (u8)(((u64)(val)) >> 48);	\
+		(a)[2] = (u8)(((u64)(val)) >> 40);	\
+		(a)[3] = (u8)(((u64)(val)) >> 32);	\
+		(a)[4] = (u8)(((u64)(val)) >> 24);	\
+		(a)[5] = (u8)(((u64)(val)) >> 16);	\
+		(a)[6] = (u8)(((u64)(val)) >> 8);	\
+		(a)[7] = (u8)(((u64)(val)) & 0xff);	\
+	} while (0)
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Various logical functions */
+#define RORc(x, y) \
+	(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y)&31)) | \
+	 ((unsigned long)(x) << (unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define Ch(x, y ,z)       (z ^ (x & (y ^ z)))
+#define Maj(x, y, z)      (((x | y) & z) | (x & y))
+#define S(x, n)         RORc((x), (n))
+#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key);
+void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b);
+void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nBytes);
+void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst);
+void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len,
+			u8 *Miccode, u8   priority);
+u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe);
+u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe);
+void rtw_wep_encrypt(struct adapter *padapter, u8  *pxmitframe);
+u32 rtw_aes_decrypt(struct adapter *padapter, u8  *precvframe);
+u32 rtw_tkip_decrypt(struct adapter *padapter, u8  *precvframe);
+void rtw_wep_decrypt(struct adapter *padapter, u8  *precvframe);
+void rtw_use_tkipkey_handler(void *FunctionContext);
+
+#endif	/* __RTL871X_SECURITY_H_ */
diff --git a/drivers/staging/rtl8188eu/include/rtw_sreset.h b/drivers/staging/rtl8188eu/include/rtw_sreset.h
new file mode 100644
index 0000000..2a1244f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_sreset.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_SRESET_C_
+#define _RTW_SRESET_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct sreset_priv {
+	struct mutex	silentreset_mutex;
+	u8	silent_reset_inprogress;
+	u8	Wifi_Error_Status;
+	unsigned long last_tx_time;
+	unsigned long last_tx_complete_time;
+};
+
+#include <rtl8188e_hal.h>
+
+#define	WIFI_STATUS_SUCCESS		0
+#define	USB_VEN_REQ_CMD_FAIL	BIT0
+#define	USB_READ_PORT_FAIL		BIT1
+#define	USB_WRITE_PORT_FAIL		BIT2
+#define	WIFI_MAC_TXDMA_ERROR	BIT3
+#define   WIFI_TX_HANG				BIT4
+#define	WIFI_RX_HANG				BIT5
+#define		WIFI_IF_NOT_EXIST			BIT6
+
+void sreset_init_value(struct adapter *padapter);
+void sreset_reset_value(struct adapter *padapter);
+u8 sreset_get_wifi_status(struct adapter *padapter);
+void sreset_set_wifi_error_status(struct adapter *padapter, u32 status);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/rtw_version.h b/drivers/staging/rtl8188eu/include/rtw_version.h
new file mode 100644
index 0000000..6d2d52c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_version.h
@@ -0,0 +1 @@
+#define DRIVERVERSION	"v4.1.4_6773.20130222"
diff --git a/drivers/staging/rtl8188eu/include/rtw_xmit.h b/drivers/staging/rtl8188eu/include/rtw_xmit.h
new file mode 100644
index 0000000..1ac1dd3
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/rtw_xmit.h
@@ -0,0 +1,384 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _RTW_XMIT_H_
+#define _RTW_XMIT_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define MAX_XMITBUF_SZ	(20480)	/*  20k */
+#define NR_XMITBUFF		(4)
+
+#define XMITBUF_ALIGN_SZ	4
+
+/*  xmit extension buff defination */
+#define MAX_XMIT_EXTBUF_SZ	(1536)
+#define NR_XMIT_EXTBUFF		(32)
+
+#define MAX_NUMBLKS		(1)
+
+#define XMIT_VO_QUEUE		(0)
+#define XMIT_VI_QUEUE		(1)
+#define XMIT_BE_QUEUE		(2)
+#define XMIT_BK_QUEUE		(3)
+
+#define VO_QUEUE_INX		0
+#define VI_QUEUE_INX		1
+#define BE_QUEUE_INX		2
+#define BK_QUEUE_INX		3
+#define BCN_QUEUE_INX		4
+#define MGT_QUEUE_INX		5
+#define HIGH_QUEUE_INX		6
+#define TXCMD_QUEUE_INX		7
+
+#define HW_QUEUE_ENTRY		8
+
+#define WEP_IV(pattrib_iv, dot11txpn, keyidx)\
+do {\
+	pattrib_iv[0] = dot11txpn._byte_.TSC0;\
+	pattrib_iv[1] = dot11txpn._byte_.TSC1;\
+	pattrib_iv[2] = dot11txpn._byte_.TSC2;\
+	pattrib_iv[3] = ((keyidx & 0x3)<<6);\
+	dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0 : (dot11txpn.val+1);\
+} while (0)
+
+
+#define TKIP_IV(pattrib_iv, dot11txpn, keyidx)\
+do {\
+	pattrib_iv[0] = dot11txpn._byte_.TSC1;\
+	pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;\
+	pattrib_iv[2] = dot11txpn._byte_.TSC0;\
+	pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\
+	pattrib_iv[4] = dot11txpn._byte_.TSC2;\
+	pattrib_iv[5] = dot11txpn._byte_.TSC3;\
+	pattrib_iv[6] = dot11txpn._byte_.TSC4;\
+	pattrib_iv[7] = dot11txpn._byte_.TSC5;\
+	dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val+1);\
+} while (0)
+
+#define AES_IV(pattrib_iv, dot11txpn, keyidx)\
+do {							\
+	pattrib_iv[0] = dot11txpn._byte_.TSC0;		\
+	pattrib_iv[1] = dot11txpn._byte_.TSC1;		\
+	pattrib_iv[2] = 0;				\
+	pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);	\
+	pattrib_iv[4] = dot11txpn._byte_.TSC2;		\
+	pattrib_iv[5] = dot11txpn._byte_.TSC3;		\
+	pattrib_iv[6] = dot11txpn._byte_.TSC4;		\
+	pattrib_iv[7] = dot11txpn._byte_.TSC5;		\
+	dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val+1);\
+} while (0)
+
+#define HWXMIT_ENTRY	4
+
+#define TXDESC_SIZE 32
+
+#define PACKET_OFFSET_SZ (8)
+#define TXDESC_OFFSET (TXDESC_SIZE + PACKET_OFFSET_SZ)
+
+struct tx_desc {
+	/* DWORD 0 */
+	__le32 txdw0;
+	__le32 txdw1;
+	__le32 txdw2;
+	__le32 txdw3;
+	__le32 txdw4;
+	__le32 txdw5;
+	__le32 txdw6;
+	__le32 txdw7;
+};
+
+union txdesc {
+	struct tx_desc txdesc;
+	unsigned int value[TXDESC_SIZE>>2];
+};
+
+struct	hw_xmit	{
+	struct __queue *sta_queue;
+	int	accnt;
+};
+
+/* reduce size */
+struct pkt_attrib {
+	u8	type;
+	u8	subtype;
+	u8	bswenc;
+	u8	dhcp_pkt;
+	u16	ether_type;
+	u16	seqnum;
+	u16	pkt_hdrlen;	/* the original 802.3 pkt header len */
+	u16	hdrlen;		/* the WLAN Header Len */
+	u32	pktlen;		/* the original 802.3 pkt raw_data len (not include
+				 * ether_hdr data) */
+	u32	last_txcmdsz;
+	u8	nr_frags;
+	u8	encrypt;	/* when 0 indicate no encrypt. when non-zero,
+				 * indicate the encrypt algorith */
+	u8	iv_len;
+	u8	icv_len;
+	u8	iv[18];
+	u8	icv[16];
+	u8	priority;
+	u8	ack_policy;
+	u8	mac_id;
+	u8	vcs_mode;	/* virtual carrier sense method */
+	u8	dst[ETH_ALEN];
+	u8	src[ETH_ALEN];
+	u8	ta[ETH_ALEN];
+	u8	ra[ETH_ALEN];
+	u8	key_idx;
+	u8	qos_en;
+	u8	ht_en;
+	u8	raid;/* rate adpative id */
+	u8	bwmode;
+	u8	ch_offset;/* PRIME_CHNL_OFFSET */
+	u8	sgi;/* short GI */
+	u8	ampdu_en;/* tx ampdu enable */
+	u8	mdata;/* more data bit */
+	u8	pctrl;/* per packet txdesc control enable */
+	u8	triggered;/* for ap mode handling Power Saving sta */
+	u8	qsel;
+	u8	eosp;
+	u8	rate;
+	u8	intel_proxim;
+	u8	retry_ctrl;
+	struct sta_info *psta;
+};
+
+#define WLANHDR_OFFSET	64
+
+#define NULL_FRAMETAG		(0x0)
+#define DATA_FRAMETAG		0x01
+#define L2_FRAMETAG		0x02
+#define MGNT_FRAMETAG		0x03
+#define AMSDU_FRAMETAG	0x04
+
+#define EII_FRAMETAG		0x05
+#define IEEE8023_FRAMETAG  0x06
+
+#define MP_FRAMETAG		0x07
+
+#define TXAGG_FRAMETAG	0x08
+
+struct  submit_ctx {
+	u32 submit_time; /* */
+	u32 timeout_ms; /* <0: not synchronous, 0: wait forever, >0: up to ms waiting */
+	int status; /* status for operation */
+	struct completion done;
+};
+
+enum {
+	RTW_SCTX_SUBMITTED = -1,
+	RTW_SCTX_DONE_SUCCESS = 0,
+	RTW_SCTX_DONE_UNKNOWN,
+	RTW_SCTX_DONE_TIMEOUT,
+	RTW_SCTX_DONE_BUF_ALLOC,
+	RTW_SCTX_DONE_BUF_FREE,
+	RTW_SCTX_DONE_WRITE_PORT_ERR,
+	RTW_SCTX_DONE_TX_DESC_NA,
+	RTW_SCTX_DONE_TX_DENY,
+	RTW_SCTX_DONE_CCX_PKT_FAIL,
+	RTW_SCTX_DONE_DRV_STOP,
+	RTW_SCTX_DONE_DEV_REMOVE,
+};
+
+void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms);
+int rtw_sctx_wait(struct submit_ctx *sctx);
+void rtw_sctx_done_err(struct submit_ctx **sctx, int status);
+void rtw_sctx_done(struct submit_ctx **sctx);
+
+struct xmit_buf {
+	struct list_head list;
+	struct adapter *padapter;
+	u8 *pallocated_buf;
+	u8 *pbuf;
+	void *priv_data;
+	u16 ext_tag; /*  0: Normal xmitbuf, 1: extension xmitbuf. */
+	u16 flags;
+	u32 alloc_sz;
+	u32  len;
+	struct submit_ctx *sctx;
+	u32	ff_hwaddr;
+	struct urb *pxmit_urb[8];
+	dma_addr_t dma_transfer_addr;	/* (in) dma addr for transfer_buffer */
+	u8 bpending[8];
+	int last[8];
+};
+
+struct xmit_frame {
+	struct list_head list;
+	struct pkt_attrib attrib;
+	struct sk_buff *pkt;
+	int	frame_tag;
+	struct adapter *padapter;
+	u8	*buf_addr;
+	struct xmit_buf *pxmitbuf;
+
+	u8	agg_num;
+	s8	pkt_offset;
+	u8 ack_report;
+};
+
+struct tx_servq {
+	struct list_head tx_pending;
+	struct __queue sta_pending;
+	int qcnt;
+};
+
+struct sta_xmit_priv {
+	spinlock_t lock;
+	int	option;
+	int	apsd_setting;	/* When bit mask is on, the associated edca
+				 * queue supports APSD. */
+	struct tx_servq	be_q;			/* priority == 0,3 */
+	struct tx_servq	bk_q;			/* priority == 1,2 */
+	struct tx_servq	vi_q;			/* priority == 4,5 */
+	struct tx_servq	vo_q;			/* priority == 6,7 */
+	struct list_head legacy_dz;
+	struct list_head apsd;
+	u16 txseq_tid[16];
+};
+
+struct	hw_txqueue {
+	volatile int	head;
+	volatile int	tail;
+	volatile int	free_sz;	/* in units of 64 bytes */
+	volatile int      free_cmdsz;
+	volatile int	 txsz[8];
+	uint	ff_hwaddr;
+	uint	cmd_hwaddr;
+	int	ac_tag;
+};
+
+struct agg_pkt_info {
+	u16 offset;
+	u16 pkt_len;
+};
+
+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;
+	struct __queue vo_pending;
+	struct __queue bm_pending;
+	u8 *pallocated_frame_buf;
+	u8 *pxmit_frame_buf;
+	uint free_xmitframe_cnt;
+	struct __queue free_xmit_queue;
+	uint	frag_len;
+	struct adapter	*adapter;
+	u8   vcs_setting;
+	u8	vcs;
+	u8	vcs_type;
+	u64	tx_bytes;
+	u64	tx_pkts;
+	u64	tx_drop;
+	u64	last_tx_bytes;
+	u64	last_tx_pkts;
+	struct hw_xmit *hwxmits;
+	u8	hwxmit_entry;
+	u8	wmm_para_seq[4];/* sequence for wmm ac parameter strength
+				 * from large to small. it's value is 0->vo,
+				 * 1->vi, 2->be, 3->bk. */
+	struct semaphore tx_retevt;/* all tx return event; */
+	u8		txirp_cnt;/*  */
+	struct tasklet_struct xmit_tasklet;
+	/* per AC pending irp */
+	int beq_cnt;
+	int bkq_cnt;
+	int viq_cnt;
+	int voq_cnt;
+	struct __queue free_xmitbuf_queue;
+	struct __queue pending_xmitbuf_queue;
+	u8 *pallocated_xmitbuf;
+	u8 *pxmitbuf;
+	uint free_xmitbuf_cnt;
+	struct __queue free_xmit_extbuf_queue;
+	u8 *pallocated_xmit_extbuf;
+	u8 *pxmit_extbuf;
+	uint free_xmit_extbuf_cnt;
+	u16	nqos_ssn;
+	int	ack_tx;
+	struct mutex ack_tx_mutex;
+	struct submit_ctx ack_tx_ops;
+};
+
+struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv,
+			 struct xmit_buf *pxmitbuf);
+struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv,
+		     struct xmit_buf *pxmitbuf);
+void rtw_count_tx_stats(struct adapter *padapter,
+			struct xmit_frame *pxmitframe, int sz);
+void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len);
+s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr,
+		     struct pkt_attrib *pattrib);
+s32 rtw_put_snap(u8 *data, u16 h_proto);
+
+struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv,
+		       struct xmit_frame *pxmitframe);
+void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv,
+			      struct __queue *pframequeue);
+struct tx_servq *rtw_get_sta_pending(struct adapter *padapter,
+				     struct sta_info *psta, int up, u8 *ac);
+s32 rtw_xmitframe_enqueue(struct adapter *padapter,
+			  struct xmit_frame *pxmitframe);
+struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv,
+				      struct hw_xmit *phwxmit_i, int entry);
+
+s32 rtw_xmit_classifier(struct adapter *padapter,
+			struct xmit_frame *pxmitframe);
+u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib);
+#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib)
+s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt,
+			   struct xmit_frame *pxmitframe);
+s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag);
+void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv);
+s32 rtw_txframes_pending(struct adapter *padapter);
+s32 rtw_txframes_sta_ac_pending(struct adapter *padapter,
+				struct pkt_attrib *pattrib);
+void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry);
+s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter);
+void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv);
+void rtw_alloc_hwxmits(struct adapter *padapter);
+void rtw_free_hwxmits(struct adapter *padapter);
+s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt);
+
+#if defined(CONFIG_88EU_AP_MODE)
+int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe);
+void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta);
+void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta);
+void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta);
+#endif
+
+u8	qos_acm(u8 acm_mask, u8 priority);
+u32	rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe);
+int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms);
+void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status);
+
+/* include after declaring struct xmit_buf, in order to avoid warning */
+#include <xmit_osdep.h>
+
+#endif	/* _RTL871X_XMIT_H_ */
diff --git a/drivers/staging/rtl8188eu/include/sta_info.h b/drivers/staging/rtl8188eu/include/sta_info.h
new file mode 100644
index 0000000..3ed2a39
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/sta_info.h
@@ -0,0 +1,384 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __STA_INFO_H_
+#define __STA_INFO_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+
+#define IBSS_START_MAC_ID	2
+#define NUM_STA 32
+#define NUM_ACL 16
+
+/* if mode ==0, then the sta is allowed once the addr is hit. */
+/* if mode ==1, then the sta is rejected once the addr is non-hit. */
+struct rtw_wlan_acl_node {
+	struct list_head list;
+	u8       addr[ETH_ALEN];
+	u8       valid;
+};
+
+/* mode=0, disable */
+/* mode=1, accept unless in deny list */
+/* mode=2, deny unless in accept list */
+struct wlan_acl_pool {
+	int mode;
+	int num;
+	struct rtw_wlan_acl_node aclnode[NUM_ACL];
+	struct __queue acl_node_q;
+};
+
+struct rssi_sta {
+	s32	UndecoratedSmoothedPWDB;
+	s32	UndecoratedSmoothedCCK;
+	s32	UndecoratedSmoothedOFDM;
+	u64	PacketMap;
+	u8	ValidBit;
+};
+
+struct	stainfo_stats	{
+	u64 rx_mgnt_pkts;
+	u64 rx_beacon_pkts;
+	u64 rx_probereq_pkts;
+	u64 rx_probersp_pkts;
+	u64 rx_probersp_bm_pkts;
+	u64 rx_probersp_uo_pkts;
+	u64 rx_ctrl_pkts;
+	u64 rx_data_pkts;
+
+	u64	last_rx_mgnt_pkts;
+	u64 last_rx_beacon_pkts;
+	u64 last_rx_probereq_pkts;
+	u64 last_rx_probersp_pkts;
+	u64 last_rx_probersp_bm_pkts;
+	u64 last_rx_probersp_uo_pkts;
+	u64	last_rx_ctrl_pkts;
+	u64	last_rx_data_pkts;
+	u64	rx_bytes;
+	u64	rx_drops;
+	u64	tx_pkts;
+	u64	tx_bytes;
+	u64  tx_drops;
+};
+
+struct sta_info {
+	spinlock_t lock;
+	struct list_head list; /* free_sta_queue */
+	struct list_head hash_list; /* sta_hash */
+
+	struct sta_xmit_priv sta_xmitpriv;
+	struct sta_recv_priv sta_recvpriv;
+
+	struct __queue sleep_q;
+	unsigned int sleepq_len;
+
+	uint state;
+	uint aid;
+	uint mac_id;
+	uint qos_option;
+	u8	hwaddr[ETH_ALEN];
+
+	uint	ieee8021x_blocked;	/* 0: allowed, 1:blocked */
+	uint	dot118021XPrivacy; /* aes, tkip... */
+	union Keytype	dot11tkiptxmickey;
+	union Keytype	dot11tkiprxmickey;
+	union Keytype	dot118021x_UncstKey;
+	union pn48		dot11txpn;			/*  PN48 used for Unicast xmit. */
+	union pn48		dot11rxpn;			/*  PN48 used for Unicast recv. */
+	u8	bssrateset[16];
+	u32	bssratelen;
+	s32  rssi;
+	s32	signal_quality;
+
+	u8	cts2self;
+	u8	rtsen;
+
+	u8	raid;
+	u8	init_rate;
+	u32	ra_mask;
+	u8	wireless_mode;	/*  NETWORK_TYPE */
+	struct stainfo_stats sta_stats;
+
+	/* for A-MPDU TX, ADDBA timeout check */
+	struct timer_list addba_retry_timer;
+
+	/* for A-MPDU Rx reordering buffer control */
+	struct recv_reorder_ctrl recvreorder_ctrl[16];
+
+	/* for A-MPDU Tx */
+	/* unsigned char		ampdu_txen_bitmap; */
+	u16	BA_starting_seqctrl[16];
+
+	struct ht_priv	htpriv;
+
+	/* Notes: */
+	/* STA_Mode: */
+	/* curr_network(mlme_priv/security_priv/qos/ht) +
+	 * sta_info: (STA & AP) CAP/INFO */
+	/* scan_q: AP CAP/INFO */
+
+	/* AP_Mode: */
+	/* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */
+	/* sta_info: (AP & STA) CAP/INFO */
+
+	struct list_head asoc_list;
+#ifdef CONFIG_88EU_AP_MODE
+	struct list_head auth_list;
+
+	unsigned int expire_to;
+	unsigned int auth_seq;
+	unsigned int authalg;
+	unsigned char chg_txt[128];
+
+	u16 capability;
+	int flags;
+
+	int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */
+	int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */
+	int wpa_group_cipher;
+	int wpa2_group_cipher;
+	int wpa_pairwise_cipher;
+	int wpa2_pairwise_cipher;
+
+	u8 bpairwise_key_installed;
+
+	u8 wpa_ie[32];
+
+	u8 nonerp_set;
+	u8 no_short_slot_time_set;
+	u8 no_short_preamble_set;
+	u8 no_ht_gf_set;
+	u8 no_ht_set;
+	u8 ht_20mhz_set;
+
+	unsigned int tx_ra_bitmap;
+	u8 qos_info;
+
+	u8 max_sp_len;
+	u8 uapsd_bk;/* BIT(0): Delivery enabled, BIT(1): Trigger enabled */
+	u8 uapsd_be;
+	u8 uapsd_vi;
+	u8 uapsd_vo;
+
+	u8 has_legacy_ac;
+	unsigned int sleepq_ac_len;
+#endif	/*  CONFIG_88EU_AP_MODE */
+
+#ifdef CONFIG_88EU_P2P
+	/* p2p priv data */
+	u8 is_p2p_device;
+	u8 p2p_status_code;
+
+	/* p2p client info */
+	u8 dev_addr[ETH_ALEN];
+	u8 dev_cap;
+	u16 config_methods;
+	u8 primary_dev_type[8];
+	u8 num_of_secdev_type;
+	u8 secdev_types_list[32];/*  32/8 == 4; */
+	u16 dev_name_len;
+	u8 dev_name[32];
+#endif /* CONFIG_88EU_P2P */
+	u8 under_exist_checking;
+	u8 keep_alive_trycnt;
+
+	/* for DM */
+	struct rssi_sta rssi_stat;
+
+	/*  ================ODM Relative Info======================= */
+	/*  Please be careful, don't declare too much structure here.
+	 *  It will cost memory * STA support num. */
+	/*  2011/10/20 MH Add for ODM STA info. */
+	/*  Driver Write */
+	u8	bValid;		/*  record the sta status link or not? */
+	u8	IOTPeer;	/*  Enum value.	HT_IOT_PEER_E */
+	u8	rssi_level;	/* for Refresh RA mask */
+	/*  ODM Write */
+	/* 1 PHY_STATUS_INFO */
+	u8		RSSI_Path[4];		/*  */
+	u8		RSSI_Ave;
+	u8		RXEVM[4];
+	u8		RXSNR[4];
+
+	/*  ================ODM Relative Info======================= */
+	/*  */
+
+	/* To store the sequence number of received management frame */
+	u16 RxMgmtFrameSeqNum;
+};
+
+#define sta_rx_pkts(sta) \
+	(sta->sta_stats.rx_mgnt_pkts \
+	+ sta->sta_stats.rx_ctrl_pkts \
+	+ sta->sta_stats.rx_data_pkts)
+
+#define sta_last_rx_pkts(sta) \
+	(sta->sta_stats.last_rx_mgnt_pkts \
+	+ sta->sta_stats.last_rx_ctrl_pkts \
+	+ sta->sta_stats.last_rx_data_pkts)
+
+#define sta_rx_data_pkts(sta) \
+	(sta->sta_stats.rx_data_pkts)
+
+#define sta_last_rx_data_pkts(sta) \
+	(sta->sta_stats.last_rx_data_pkts)
+
+#define sta_rx_mgnt_pkts(sta) \
+	(sta->sta_stats.rx_mgnt_pkts)
+
+#define sta_last_rx_mgnt_pkts(sta) \
+	(sta->sta_stats.last_rx_mgnt_pkts)
+
+#define sta_rx_beacon_pkts(sta) \
+	(sta->sta_stats.rx_beacon_pkts)
+
+#define sta_last_rx_beacon_pkts(sta) \
+	(sta->sta_stats.last_rx_beacon_pkts)
+
+#define sta_rx_probereq_pkts(sta) \
+	(sta->sta_stats.rx_probereq_pkts)
+
+#define sta_last_rx_probereq_pkts(sta) \
+	(sta->sta_stats.last_rx_probereq_pkts)
+
+#define sta_rx_probersp_pkts(sta) \
+	(sta->sta_stats.rx_probersp_pkts)
+
+#define sta_last_rx_probersp_pkts(sta) \
+	(sta->sta_stats.last_rx_probersp_pkts)
+
+#define sta_rx_probersp_bm_pkts(sta) \
+	(sta->sta_stats.rx_probersp_bm_pkts)
+
+#define sta_last_rx_probersp_bm_pkts(sta) \
+	(sta->sta_stats.last_rx_probersp_bm_pkts)
+
+#define sta_rx_probersp_uo_pkts(sta) \
+	(sta->sta_stats.rx_probersp_uo_pkts)
+
+#define sta_last_rx_probersp_uo_pkts(sta) \
+	(sta->sta_stats.last_rx_probersp_uo_pkts)
+
+#define sta_update_last_rx_pkts(sta) \
+do { \
+	sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \
+	sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \
+	sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \
+	sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \
+	sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \
+	sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \
+	sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \
+	sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \
+} while (0)
+
+#define STA_RX_PKTS_ARG(sta) \
+	sta->sta_stats.rx_mgnt_pkts \
+	, sta->sta_stats.rx_ctrl_pkts \
+	, sta->sta_stats.rx_data_pkts
+
+#define STA_LAST_RX_PKTS_ARG(sta) \
+	sta->sta_stats.last_rx_mgnt_pkts \
+	, sta->sta_stats.last_rx_ctrl_pkts \
+	, sta->sta_stats.last_rx_data_pkts
+
+#define STA_RX_PKTS_DIFF_ARG(sta) \
+	sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts \
+	, sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts \
+	, sta->sta_stats.rx_data_pkts - sta->sta_stats.last_rx_data_pkts
+
+#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)"
+
+struct	sta_priv {
+	u8 *pallocated_stainfo_buf;
+	u8 *pstainfo_buf;
+	struct __queue free_sta_queue;
+
+	spinlock_t sta_hash_lock;
+	struct list_head sta_hash[NUM_STA];
+	int asoc_sta_count;
+	struct __queue sleep_q;
+	struct __queue wakeup_q;
+
+	struct adapter *padapter;
+
+	spinlock_t asoc_list_lock;
+	struct list_head asoc_list;
+
+#ifdef CONFIG_88EU_AP_MODE
+	struct list_head auth_list;
+	spinlock_t auth_list_lock;
+	u8 asoc_list_cnt;
+	u8 auth_list_cnt;
+
+	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. */
+
+	/* pointers to STA info; based on allocated AID or NULL if AID free
+	 * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+	 * and so on
+	 */
+	struct sta_info *sta_aid[NUM_STA];
+
+	u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap
+			   * for sleeping sta. */
+	u16 tim_bitmap;	/* only support 15 stations, aid=0~15 mapping
+			 * bit0~bit15 */
+
+	u16 max_num_sta;
+
+	struct wlan_acl_pool acl_list;
+#endif
+
+};
+
+static inline u32 wifi_mac_hash(u8 *mac)
+{
+	u32 x;
+
+	x = mac[0];
+	x = (x << 2) ^ mac[1];
+	x = (x << 2) ^ mac[2];
+	x = (x << 2) ^ mac[3];
+	x = (x << 2) ^ mac[4];
+	x = (x << 2) ^ mac[5];
+
+	x ^= x >> 8;
+	x  = x & (NUM_STA - 1);
+	return x;
+}
+
+extern u32	_rtw_init_sta_priv(struct sta_priv *pstapriv);
+extern u32	_rtw_free_sta_priv(struct sta_priv *pstapriv);
+
+#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0)
+int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta);
+struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int off);
+
+extern struct sta_info *rtw_alloc_stainfo(struct sta_priv *stapriv, u8 *hwaddr);
+extern u32	rtw_free_stainfo(struct adapter *adapt, struct sta_info *psta);
+extern void rtw_free_all_stainfo(struct adapter *adapt);
+extern struct sta_info *rtw_get_stainfo(struct sta_priv *stapriv, u8 *hwaddr);
+extern u32 rtw_init_bcmc_stainfo(struct adapter *adapt);
+extern struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter);
+extern u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr);
+
+#endif /* _STA_INFO_H_ */
diff --git a/drivers/staging/rtl8188eu/include/usb_hal.h b/drivers/staging/rtl8188eu/include/usb_hal.h
new file mode 100644
index 0000000..8a65995
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_hal.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_HAL_H__
+#define __USB_HAL_H__
+
+void rtl8188eu_set_hal_ops(struct adapter *padapter);
+#define hal_set_hal_ops	rtl8188eu_set_hal_ops
+
+#endif /* __USB_HAL_H__ */
diff --git a/drivers/staging/rtl8188eu/include/usb_ops.h b/drivers/staging/rtl8188eu/include/usb_ops.h
new file mode 100644
index 0000000..df34237
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_ops.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_OPS_H_
+#define __USB_OPS_H_
+
+#include <linux/version.h>
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+
+#define REALTEK_USB_VENQT_READ		0xC0
+#define REALTEK_USB_VENQT_WRITE		0x40
+#define REALTEK_USB_VENQT_CMD_REQ	0x05
+#define REALTEK_USB_VENQT_CMD_IDX	0x00
+
+enum{
+	VENDOR_WRITE = 0x00,
+	VENDOR_READ = 0x01,
+};
+#define ALIGNMENT_UNIT			16
+#define MAX_VENDOR_REQ_CMD_SIZE	254	/* 8188cu SIE Support */
+#define MAX_USB_IO_CTL_SIZE	(MAX_VENDOR_REQ_CMD_SIZE + ALIGNMENT_UNIT)
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+#define rtw_usb_control_msg(dev, pipe, request, requesttype,		\
+			    value, index, data, size, timeout_ms)	\
+	usb_control_msg((dev), (pipe), (request), (requesttype), (value),\
+			(index), (data), (size), (timeout_ms))
+#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout_ms) \
+	usb_bulk_msg((usb_dev), (pipe), (data), (len),			\
+		     (actual_length), (timeout_ms))
+#else
+#define rtw_usb_control_msg(dev, pipe, request, requesttype,		\
+			    value, index, data, size, timeout_ms)	\
+	usb_control_msg((dev), (pipe), (request), (requesttype),	\
+			(value), (index), (data), (size),		\
+			((timeout_ms) == 0) ||				\
+			((timeout_ms)*HZ/1000 > 0) ?			\
+			((timeout_ms)*HZ/1000) : 1)
+#define rtw_usb_bulk_msg(usb_dev, pipe, data, len,			\
+			 actual_length, timeout_ms) \
+	usb_bulk_msg((usb_dev), (pipe), (data), (len), (actual_length), \
+		     ((timeout_ms) == 0) || ((timeout_ms)*HZ/1000 > 0) ?\
+		     ((timeout_ms)*HZ/1000) : 1)
+#endif
+#include <usb_ops_linux.h>
+
+void rtl8188eu_set_hw_type(struct adapter *padapter);
+#define hal_set_hw_type rtl8188eu_set_hw_type
+void rtl8188eu_set_intf_ops(struct _io_ops *pops);
+#define usb_set_intf_ops rtl8188eu_set_intf_ops
+
+/*
+ * Increase and check if the continual_urb_error of this @param dvobjprivei
+ * is larger than MAX_CONTINUAL_URB_ERR
+ * @return true:
+ * @return false:
+ */
+static inline int rtw_inc_and_chk_continual_urb_error(struct dvobj_priv *dvobj)
+{
+	int ret = false;
+	int value;
+	value = ATOMIC_INC_RETURN(&dvobj->continual_urb_error);
+	if (value > MAX_CONTINUAL_URB_ERR) {
+		DBG_88E("[dvobj:%p][ERROR] continual_urb_error:%d > %d\n",
+			dvobj, value, MAX_CONTINUAL_URB_ERR);
+		ret = true;
+	}
+	return ret;
+}
+
+/*
+* Set the continual_urb_error of this @param dvobjprive to 0
+*/
+static inline void rtw_reset_continual_urb_error(struct dvobj_priv *dvobj)
+{
+	ATOMIC_SET(&dvobj->continual_urb_error, 0);
+}
+
+#define USB_HIGH_SPEED_BULK_SIZE	512
+#define USB_FULL_SPEED_BULK_SIZE	64
+
+static inline u8 rtw_usb_bulk_size_boundary(struct adapter *padapter,
+					    int buf_len)
+{
+	u8 rst = true;
+	struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+	if (pdvobjpriv->ishighspeed)
+		rst = (0 == (buf_len) % USB_HIGH_SPEED_BULK_SIZE) ?
+		      true : false;
+	else
+		rst = (0 == (buf_len) % USB_FULL_SPEED_BULK_SIZE) ?
+		      true : false;
+	return rst;
+}
+
+#endif /* __USB_OPS_H_ */
diff --git a/drivers/staging/rtl8188eu/include/usb_ops_linux.h b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
new file mode 100644
index 0000000..e5b758a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_OPS_LINUX_H__
+#define __USB_OPS_LINUX_H__
+
+#define VENDOR_CMD_MAX_DATA_LEN	254
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST	10/* ms */
+#define RTW_USB_CONTROL_MSG_TIMEOUT	500/* ms */
+
+#define MAX_USBCTRL_VENDORREQ_TIMES	10
+
+#define RTW_USB_BULKOUT_TIME	5000/* ms */
+
+#define _usbctrl_vendorreq_async_callback(urb, regs)	\
+	_usbctrl_vendorreq_async_callback(urb)
+#define usb_bulkout_zero_complete(purb, regs)		\
+	usb_bulkout_zero_complete(purb)
+#define usb_write_mem_complete(purb, regs)		\
+	usb_write_mem_complete(purb)
+#define usb_write_port_complete(purb, regs)		\
+	usb_write_port_complete(purb)
+#define usb_read_port_complete(purb, regs)		\
+	usb_read_port_complete(purb)
+#define usb_read_interrupt_complete(purb, regs)		\
+	usb_read_interrupt_complete(purb)
+
+unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr);
+
+void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem);
+void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem);
+
+void usb_read_port_cancel(struct intf_hdl *pintfhdl);
+
+u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem);
+void usb_write_port_cancel(struct intf_hdl *pintfhdl);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/usb_osintf.h b/drivers/staging/rtl8188eu/include/usb_osintf.h
new file mode 100644
index 0000000..9de99ca
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_osintf.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __USB_OSINTF_H
+#define __USB_OSINTF_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <usb_vendor_req.h>
+
+extern char *rtw_initmac;
+extern int rtw_mc2u_disable;
+
+#define USBD_HALTED(Status) ((u32)(Status) >> 30 == 3)
+
+u8 usbvendorrequest(struct dvobj_priv *pdvobjpriv, enum bt_usb_request brequest,
+		    enum rt_usb_wvalue wvalue, u8 windex, void *data,
+		    u8 datalen, u8 isdirectionin);
+int pm_netdev_open(struct net_device *pnetdev, u8 bnormal);
+void netdev_br_init(struct net_device *netdev);
+void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb);
+void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
+		     unsigned char *ipAddr);
+void nat25_db_expire(struct adapter *priv);
+int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method);
+
+int rtw_resume_process(struct adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/usb_vendor_req.h b/drivers/staging/rtl8188eu/include/usb_vendor_req.h
new file mode 100644
index 0000000..7f26c8f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/usb_vendor_req.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _USB_VENDOR_REQUEST_H_
+#define _USB_VENDOR_REQUEST_H_
+
+/* 4	Set/Get Register related wIndex/Data */
+#define	RT_USB_RESET_MASK_OFF		0
+#define	RT_USB_RESET_MASK_ON		1
+#define	RT_USB_SLEEP_MASK_OFF		0
+#define	RT_USB_SLEEP_MASK_ON		1
+#define	RT_USB_LDO_ON				1
+#define	RT_USB_LDO_OFF				0
+
+/* 4	Set/Get SYSCLK related	wValue or Data */
+#define	RT_USB_SYSCLK_32KHZ		0
+#define	RT_USB_SYSCLK_40MHZ		1
+#define	RT_USB_SYSCLK_60MHZ		2
+
+
+enum bt_usb_request {
+	RT_USB_SET_REGISTER		= 1,
+	RT_USB_SET_SYSCLK		= 2,
+	RT_USB_GET_SYSCLK		= 3,
+	RT_USB_GET_REGISTER		= 4
+};
+
+enum rt_usb_wvalue {
+	RT_USB_RESET_MASK	=	1,
+	RT_USB_SLEEP_MASK	=	2,
+	RT_USB_USB_HRCPWM	=	3,
+	RT_USB_LDO			=	4,
+	RT_USB_BOOT_TYPE	=	5
+};
+
+#endif
diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h
new file mode 100644
index 0000000..a615659
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/wifi.h
@@ -0,0 +1,1127 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef _WIFI_H_
+#define _WIFI_H_
+
+
+#ifdef BIT
+/* error	"BIT define occurred earlier elsewhere!\n" */
+#undef BIT
+#endif
+#define BIT(x)	(1 << (x))
+
+
+#define WLAN_ETHHDR_LEN		14
+#define WLAN_ETHADDR_LEN	6
+#define WLAN_IEEE_OUI_LEN	3
+#define WLAN_ADDR_LEN		6
+#define WLAN_CRC_LEN		4
+#define WLAN_BSSID_LEN		6
+#define WLAN_BSS_TS_LEN		8
+#define WLAN_HDR_A3_LEN		24
+#define WLAN_HDR_A4_LEN		30
+#define WLAN_HDR_A3_QOS_LEN	26
+#define WLAN_HDR_A4_QOS_LEN	32
+#define WLAN_SSID_MAXLEN	32
+#define WLAN_DATA_MAXLEN	2312
+
+#define WLAN_A3_PN_OFFSET	24
+#define WLAN_A4_PN_OFFSET	30
+
+#define WLAN_MIN_ETHFRM_LEN	60
+#define WLAN_MAX_ETHFRM_LEN	1514
+#define WLAN_ETHHDR_LEN		14
+
+#define P80211CAPTURE_VERSION	0x80211001
+
+/*  This value is tested by WiFi 11n Test Plan 5.2.3. */
+/*  This test verifies the WLAN NIC can update the NAV through sending
+ *  the CTS with large duration. */
+#define	WiFiNavUpperUs				30000	/*  30 ms */
+
+enum WIFI_FRAME_TYPE {
+	WIFI_MGT_TYPE  =	(0),
+	WIFI_CTRL_TYPE =	(BIT(2)),
+	WIFI_DATA_TYPE =	(BIT(3)),
+	WIFI_QOS_DATA_TYPE	= (BIT(7)|BIT(3)),	/*  QoS Data */
+};
+
+enum WIFI_FRAME_SUBTYPE {
+	/*  below is for mgt frame */
+	WIFI_ASSOCREQ       = (0 | WIFI_MGT_TYPE),
+	WIFI_ASSOCRSP       = (BIT(4) | WIFI_MGT_TYPE),
+	WIFI_REASSOCREQ     = (BIT(5) | WIFI_MGT_TYPE),
+	WIFI_REASSOCRSP     = (BIT(5) | BIT(4) | WIFI_MGT_TYPE),
+	WIFI_PROBEREQ       = (BIT(6) | WIFI_MGT_TYPE),
+	WIFI_PROBERSP       = (BIT(6) | BIT(4) | WIFI_MGT_TYPE),
+	WIFI_BEACON         = (BIT(7) | WIFI_MGT_TYPE),
+	WIFI_ATIM           = (BIT(7) | BIT(4) | WIFI_MGT_TYPE),
+	WIFI_DISASSOC       = (BIT(7) | BIT(5) | WIFI_MGT_TYPE),
+	WIFI_AUTH           = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE),
+	WIFI_DEAUTH         = (BIT(7) | BIT(6) | WIFI_MGT_TYPE),
+	WIFI_ACTION         = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE),
+
+	/*  below is for control frame */
+	WIFI_PSPOLL         = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE),
+	WIFI_RTS            = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE),
+	WIFI_CTS            = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE),
+	WIFI_ACK            = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE),
+	WIFI_CFEND          = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE),
+	WIFI_CFEND_CFACK    = (BIT(7) | BIT(6) | BIT(5) | BIT(4) |
+	WIFI_CTRL_TYPE),
+
+	/*  below is for data frame */
+	WIFI_DATA           = (0 | WIFI_DATA_TYPE),
+	WIFI_DATA_CFACK     = (BIT(4) | WIFI_DATA_TYPE),
+	WIFI_DATA_CFPOLL    = (BIT(5) | WIFI_DATA_TYPE),
+	WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE),
+	WIFI_DATA_NULL      = (BIT(6) | WIFI_DATA_TYPE),
+	WIFI_CF_ACK         = (BIT(6) | BIT(4) | WIFI_DATA_TYPE),
+	WIFI_CF_POLL        = (BIT(6) | BIT(5) | WIFI_DATA_TYPE),
+	WIFI_CF_ACKPOLL     = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE),
+	WIFI_QOS_DATA_NULL	= (BIT(6) | WIFI_QOS_DATA_TYPE),
+};
+
+enum WIFI_REASON_CODE	{
+	_RSON_RESERVED_			= 0,
+	_RSON_UNSPECIFIED_		= 1,
+	_RSON_AUTH_NO_LONGER_VALID_	= 2,
+	_RSON_DEAUTH_STA_LEAVING_	= 3,
+	_RSON_INACTIVITY_		= 4,
+	_RSON_UNABLE_HANDLE_		= 5,
+	_RSON_CLS2_			= 6,
+	_RSON_CLS3_			= 7,
+	_RSON_DISAOC_STA_LEAVING_	= 8,
+	_RSON_ASOC_NOT_AUTH_		= 9,
+
+	/*  WPA reason */
+	_RSON_INVALID_IE_		= 13,
+	_RSON_MIC_FAILURE_		= 14,
+	_RSON_4WAY_HNDSHK_TIMEOUT_	= 15,
+	_RSON_GROUP_KEY_UPDATE_TIMEOUT_	= 16,
+	_RSON_DIFF_IE_			= 17,
+	_RSON_MLTCST_CIPHER_NOT_VALID_	= 18,
+	_RSON_UNICST_CIPHER_NOT_VALID_	= 19,
+	_RSON_AKMP_NOT_VALID_		= 20,
+	_RSON_UNSUPPORT_RSNE_VER_	= 21,
+	_RSON_INVALID_RSNE_CAP_		= 22,
+	_RSON_IEEE_802DOT1X_AUTH_FAIL_	= 23,
+
+	/* belowing are Realtek definition */
+	_RSON_PMK_NOT_AVAILABLE_	= 24,
+	_RSON_TDLS_TEAR_TOOFAR_		= 25,
+	_RSON_TDLS_TEAR_UN_RSN_		= 26,
+};
+
+/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22)
+
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 */
+/* IEEE 802.11h */
+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
+
+/* IEEE 802.11i
+#define WLAN_REASON_INVALID_IE 13
+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
+#define WLAN_REASON_AKMP_NOT_VALID 20
+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 */
+
+enum WIFI_STATUS_CODE {
+	_STATS_SUCCESSFUL_		= 0,
+	_STATS_FAILURE_			= 1,
+	_STATS_CAP_FAIL_		= 10,
+	_STATS_NO_ASOC_			= 11,
+	_STATS_OTHER_			= 12,
+	_STATS_NO_SUPP_ALG_		= 13,
+	_STATS_OUT_OF_AUTH_SEQ_		= 14,
+	_STATS_CHALLENGE_FAIL_		= 15,
+	_STATS_AUTH_TIMEOUT_		= 16,
+	_STATS_UNABLE_HANDLE_STA_	= 17,
+	_STATS_RATE_FAIL_		= 18,
+};
+
+/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23)
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18 */
+
+/* entended */
+/* IEEE 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* IEEE 802.11g */
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
+/* IEEE 802.11w */
+#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
+/* IEEE 802.11i */
+#define WLAN_STATUS_INVALID_IE 40
+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
+#define WLAN_STATUS_AKMP_NOT_VALID 43
+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
+/* IEEE 802.11r */
+#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
+#define WLAN_STATUS_INVALID_PMKID 53
+#define WLAN_STATUS_INVALID_MDIE 54
+#define WLAN_STATUS_INVALID_FTIE 55
+
+enum WIFI_REG_DOMAIN {
+	DOMAIN_FCC	= 1,
+	DOMAIN_IC	= 2,
+	DOMAIN_ETSI	= 3,
+	DOMAIN_SPA	= 4,
+	DOMAIN_FRANCE	= 5,
+	DOMAIN_MKK	= 6,
+	DOMAIN_ISRAEL	= 7,
+	DOMAIN_MKK1	= 8,
+	DOMAIN_MKK2	= 9,
+	DOMAIN_MKK3	= 10,
+	DOMAIN_MAX
+};
+
+#define _TO_DS_		BIT(8)
+#define _FROM_DS_	BIT(9)
+#define _MORE_FRAG_	BIT(10)
+#define _RETRY_		BIT(11)
+#define _PWRMGT_	BIT(12)
+#define _MORE_DATA_	BIT(13)
+#define _PRIVACY_	BIT(14)
+#define _ORDER_		BIT(15)
+
+#define SetToDs(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_)
+
+#define GetToDs(pbuf)	(((*(__le16 *)(pbuf)) & cpu_to_le16(_TO_DS_)) != 0)
+
+#define ClearToDs(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_TO_DS_))
+
+#define SetFrDs(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_)
+
+#define GetFrDs(pbuf)	(((*(__le16 *)(pbuf)) & cpu_to_le16(_FROM_DS_)) != 0)
+
+#define ClearFrDs(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_FROM_DS_))
+
+#define get_tofr_ds(pframe)	((GetToDs(pframe) << 1) | GetFrDs(pframe))
+
+
+#define SetMFrag(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_)
+
+#define GetMFrag(pbuf)	(((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_FRAG_)) != 0)
+
+#define ClearMFrag(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_))
+
+#define SetRetry(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_RETRY_)
+
+#define GetRetry(pbuf)	(((*(__le16 *)(pbuf)) & cpu_to_le16(_RETRY_)) != 0)
+
+#define ClearRetry(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_))
+
+#define SetPwrMgt(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_)
+
+#define GetPwrMgt(pbuf)	(((*(__le16 *)(pbuf)) & cpu_to_le16(_PWRMGT_)) != 0)
+
+#define ClearPwrMgt(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_))
+
+#define SetMData(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_)
+
+#define GetMData(pbuf)	(((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_DATA_)) != 0)
+
+#define ClearMData(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_))
+
+#define SetPrivacy(pbuf)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_)
+
+#define GetPrivacy(pbuf)					\
+	(((*(__le16 *)(pbuf)) & cpu_to_le16(_PRIVACY_)) != 0)
+
+#define ClearPrivacy(pbuf)	\
+	*(__le16 *)(pbuf) &= (~cpu_to_le16(_PRIVACY_))
+
+
+#define GetOrder(pbuf)					\
+	(((*(__le16 *)(pbuf)) & cpu_to_le16(_ORDER_)) != 0)
+
+#define GetFrameType(pbuf)				\
+	(le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(3) | BIT(2)))
+
+#define SetFrameType(pbuf, type)	\
+	do {	\
+		*(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \
+		*(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \
+	} while (0)
+
+#define GetFrameSubType(pbuf)	(le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(7) |\
+	 BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2)))
+
+#define SetFrameSubType(pbuf, type) \
+	do {    \
+		*(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) |	\
+		 BIT(5) | BIT(4) | BIT(3) | BIT(2))); \
+		*(__le16 *)(pbuf) |= cpu_to_le16(type); \
+	} while (0)
+
+#define GetSequence(pbuf)			\
+	(le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) >> 4)
+
+#define GetFragNum(pbuf)			\
+	(le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) & 0x0f)
+
+#define GetTupleCache(pbuf)			\
+	(cpu_to_le16(*(unsigned short *)((size_t)(pbuf) + 22)))
+
+#define SetFragNum(pbuf, num) \
+	do {    \
+		*(unsigned short *)((size_t)(pbuf) + 22) = \
+			((*(unsigned short *)((size_t)(pbuf) + 22)) &	\
+			le16_to_cpu(~(0x000f))) | \
+			cpu_to_le16(0x0f & (num));     \
+	} while (0)
+
+#define SetSeqNum(pbuf, num) \
+	do {    \
+		*(__le16 *)((size_t)(pbuf) + 22) = \
+			((*(__le16 *)((size_t)(pbuf) + 22)) & cpu_to_le16((unsigned short)0x000f)) | \
+			cpu_to_le16((unsigned short)(0xfff0 & (num << 4))); \
+	} while (0)
+
+#define SetDuration(pbuf, dur) \
+	*(__le16 *)((size_t)(pbuf) + 2) = cpu_to_le16(0xffff & (dur))
+
+
+#define SetPriority(pbuf, tid)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf)
+
+#define GetPriority(pbuf)	((le16_to_cpu(*(__le16 *)(pbuf))) & 0xf)
+
+#define SetEOSP(pbuf, eosp)	\
+		*(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4)
+
+#define SetAckpolicy(pbuf, ack)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5)
+
+#define GetAckpolicy(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 5) & 0x3)
+
+#define GetAMsdu(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 7) & 0x1)
+
+#define SetAMsdu(pbuf, amsdu)	\
+	*(__le16 *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7)
+
+#define GetAid(pbuf)	(le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 2)) & 0x3fff)
+
+#define GetTid(pbuf)	(le16_to_cpu(*(__le16 *)((size_t)(pbuf) +	\
+			(((GetToDs(pbuf)<<1) | GetFrDs(pbuf)) == 3 ?	\
+			30 : 24))) & 0x000f)
+
+#define GetAddr1Ptr(pbuf)	((unsigned char *)((size_t)(pbuf) + 4))
+
+#define GetAddr2Ptr(pbuf)	((unsigned char *)((size_t)(pbuf) + 10))
+
+#define GetAddr3Ptr(pbuf)	((unsigned char *)((size_t)(pbuf) + 16))
+
+#define GetAddr4Ptr(pbuf)	((unsigned char *)((size_t)(pbuf) + 24))
+
+#define MacAddr_isBcst(addr) \
+	( \
+	((addr[0] == 0xff) && (addr[1] == 0xff) && \
+	(addr[2] == 0xff) && (addr[3] == 0xff) && \
+	(addr[4] == 0xff) && (addr[5] == 0xff))  ? true : false \
+)
+
+static inline int IS_MCAST(unsigned char *da)
+{
+	if ((*da) & 0x01)
+		return true;
+	else
+		return false;
+}
+
+static inline unsigned char *get_da(unsigned char *pframe)
+{
+	unsigned char	*da;
+	unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
+
+	switch (to_fr_ds) {
+	case 0x00:	/*  ToDs=0, FromDs=0 */
+		da = GetAddr1Ptr(pframe);
+		break;
+	case 0x01:	/*  ToDs=0, FromDs=1 */
+		da = GetAddr1Ptr(pframe);
+		break;
+	case 0x02:	/*  ToDs=1, FromDs=0 */
+		da = GetAddr3Ptr(pframe);
+		break;
+	default:	/*  ToDs=1, FromDs=1 */
+		da = GetAddr3Ptr(pframe);
+		break;
+	}
+	return da;
+}
+
+static inline unsigned char *get_sa(unsigned char *pframe)
+{
+	unsigned char	*sa;
+	unsigned int	to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
+
+	switch (to_fr_ds) {
+	case 0x00:	/*  ToDs=0, FromDs=0 */
+		sa = GetAddr2Ptr(pframe);
+		break;
+	case 0x01:	/*  ToDs=0, FromDs=1 */
+		sa = GetAddr3Ptr(pframe);
+		break;
+	case 0x02:	/*  ToDs=1, FromDs=0 */
+		sa = GetAddr2Ptr(pframe);
+		break;
+	default:	/*  ToDs=1, FromDs=1 */
+		sa = GetAddr4Ptr(pframe);
+		break;
+	}
+	return sa;
+}
+
+static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
+{
+	unsigned char	*sa;
+	unsigned int	to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe);
+
+	switch (to_fr_ds) {
+	case 0x00:	/*  ToDs=0, FromDs=0 */
+		sa = GetAddr3Ptr(pframe);
+		break;
+	case 0x01:	/*  ToDs=0, FromDs=1 */
+		sa = GetAddr2Ptr(pframe);
+		break;
+	case 0x02:	/*  ToDs=1, FromDs=0 */
+		sa = GetAddr1Ptr(pframe);
+		break;
+	case 0x03:	/*  ToDs=1, FromDs=1 */
+		sa = GetAddr1Ptr(pframe);
+		break;
+	default:
+		sa = NULL; /*  */
+		break;
+	}
+	return sa;
+}
+
+static inline int IsFrameTypeCtrl(unsigned char *pframe)
+{
+	if (WIFI_CTRL_TYPE == GetFrameType(pframe))
+		return true;
+	else
+		return false;
+}
+/*-----------------------------------------------------------------------------
+			Below is for the security related definition
+------------------------------------------------------------------------------*/
+#define _RESERVED_FRAME_TYPE_		0
+#define _SKB_FRAME_TYPE_		2
+#define _PRE_ALLOCMEM_			1
+#define _PRE_ALLOCHDR_			3
+#define _PRE_ALLOCLLCHDR_		4
+#define _PRE_ALLOCICVHDR_		5
+#define _PRE_ALLOCMICHDR_		6
+
+#define _SIFSTIME_				\
+	((priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) ? 16 : 10)
+#define _ACKCTSLNG_		14	/* 14 bytes long, including crclng */
+#define _CRCLNG_		4
+
+#define _ASOCREQ_IE_OFFSET_	4	/*  excluding wlan_hdr */
+#define	_ASOCRSP_IE_OFFSET_	6
+#define _REASOCREQ_IE_OFFSET_	10
+#define _REASOCRSP_IE_OFFSET_	6
+#define _PROBEREQ_IE_OFFSET_	0
+#define	_PROBERSP_IE_OFFSET_	12
+#define _AUTH_IE_OFFSET_	6
+#define _DEAUTH_IE_OFFSET_	0
+#define _BEACON_IE_OFFSET_	12
+#define _PUBLIC_ACTION_IE_OFFSET_	8
+
+#define _FIXED_IE_LENGTH_	_BEACON_IE_OFFSET_
+
+#define _SSID_IE_		0
+#define _SUPPORTEDRATES_IE_	1
+#define _DSSET_IE_		3
+#define _TIM_IE_		5
+#define _IBSS_PARA_IE_		6
+#define _COUNTRY_IE_		7
+#define _CHLGETXT_IE_		16
+#define _SUPPORTED_CH_IE_	36
+#define _CH_SWTICH_ANNOUNCE_	37	/* Secondary Channel Offset */
+#define _RSN_IE_2_		48
+#define _SSN_IE_1_		221
+#define _ERPINFO_IE_		42
+#define _EXT_SUPPORTEDRATES_IE_	50
+
+#define _HT_CAPABILITY_IE_	45
+#define _FTIE_			55
+#define _TIMEOUT_ITVL_IE_	56
+#define _SRC_IE_		59
+#define _HT_EXTRA_INFO_IE_	61
+#define _HT_ADD_INFO_IE_	61 /* _HT_EXTRA_INFO_IE_ */
+#define _WAPI_IE_		68
+
+
+#define	EID_BSSCoexistence	72 /*  20/40 BSS Coexistence */
+#define	EID_BSSIntolerantChlReport	73
+#define _RIC_Descriptor_IE_	75
+
+#define _LINK_ID_IE_		101
+#define _CH_SWITCH_TIMING_	104
+#define _PTI_BUFFER_STATUS_	106
+#define _EXT_CAP_IE_		127
+#define _VENDOR_SPECIFIC_IE_	221
+
+#define	_RESERVED47_		47
+
+/* ---------------------------------------------------------------------------
+					Below is the fixed elements...
+-----------------------------------------------------------------------------*/
+#define _AUTH_ALGM_NUM_		2
+#define _AUTH_SEQ_NUM_		2
+#define _BEACON_ITERVAL_	2
+#define _CAPABILITY_		2
+#define _CURRENT_APADDR_	6
+#define _LISTEN_INTERVAL_	2
+#define _RSON_CODE_		2
+#define _ASOC_ID_		2
+#define _STATUS_CODE_		2
+#define _TIMESTAMP_		8
+
+#define AUTH_ODD_TO		0
+#define AUTH_EVEN_TO		1
+
+#define WLAN_ETHCONV_ENCAP	1
+#define WLAN_ETHCONV_RFC1042	2
+#define WLAN_ETHCONV_8021h	3
+
+#define cap_ESS		BIT(0)
+#define cap_IBSS	BIT(1)
+#define cap_CFPollable	BIT(2)
+#define cap_CFRequest	BIT(3)
+#define cap_Privacy	BIT(4)
+#define cap_ShortPremble BIT(5)
+#define cap_PBCC	BIT(6)
+#define cap_ChAgility	BIT(7)
+#define cap_SpecMgmt	BIT(8)
+#define cap_QoSi	BIT(9)
+#define cap_ShortSlot	BIT(10)
+
+/*-----------------------------------------------------------------------------
+				Below is the definition for 802.11i / 802.1x
+------------------------------------------------------------------------------*/
+#define _IEEE8021X_MGT_			1	/*  WPA */
+#define _IEEE8021X_PSK_			2	/*  WPA with pre-shared key */
+
+/*
+#define _NO_PRIVACY_			0
+#define _WEP_40_PRIVACY_		1
+#define _TKIP_PRIVACY_			2
+#define _WRAP_PRIVACY_			3
+#define _CCMP_PRIVACY_			4
+#define _WEP_104_PRIVACY_		5
+#define _WEP_WPA_MIXED_PRIVACY_ 6	WEP + WPA
+*/
+
+/*-----------------------------------------------------------------------------
+				Below is the definition for WMM
+------------------------------------------------------------------------------*/
+#define _WMM_IE_Length_				7  /*  for WMM STA */
+#define _WMM_Para_Element_Length_		24
+
+
+/*-----------------------------------------------------------------------------
+				Below is the definition for 802.11n
+------------------------------------------------------------------------------*/
+
+#define SetOrderBit(pbuf)	\
+	do	{	\
+		*(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \
+	} while (0)
+
+#define GetOrderBit(pbuf)			\
+	(((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0)
+
+
+/**
+ * struct rtw_ieee80211_bar - HT Block Ack Request
+ *
+ * This structure refers to "HT BlockAckReq" as
+ * described in 802.11n draft section 7.2.1.7.1
+ */
+struct rtw_ieee80211_bar {
+	unsigned short frame_control;
+	unsigned short duration;
+	unsigned char ra[6];
+	unsigned char ta[6];
+	unsigned short control;
+	unsigned short start_seq_num;
+} __packed;
+
+/* 802.11 BAR control masks */
+#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL     0x0000
+#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA  0x0004
+
+ /**
+ * struct rtw_ieee80211_ht_cap - HT capabilities
+ *
+ * This structure refers to "HT capabilities element" as
+ * described in 802.11n draft section 7.3.2.52
+ */
+
+struct rtw_ieee80211_ht_cap {
+	unsigned short	cap_info;
+	unsigned char	ampdu_params_info;
+	unsigned char	supp_mcs_set[16];
+	unsigned short	extended_ht_cap_info;
+	unsigned int	tx_BF_cap_info;
+	unsigned char   antenna_selection_info;
+} __packed;
+
+/**
+ * struct rtw_ieee80211_ht_cap - HT additional information
+ *
+ * This structure refers to "HT information element" as
+ * described in 802.11n draft section 7.3.2.53
+ */
+struct ieee80211_ht_addt_info {
+	unsigned char	control_chan;
+	unsigned char	ht_param;
+	unsigned short	operation_mode;
+	unsigned short	stbc_param;
+	unsigned char	basic_set[16];
+} __packed;
+
+struct HT_caps_element {
+	union {
+		struct {
+			__le16	HT_caps_info;
+			unsigned char	AMPDU_para;
+			unsigned char	MCS_rate[16];
+			unsigned short	HT_ext_caps;
+			unsigned int	Beamforming_caps;
+			unsigned char	ASEL_caps;
+		} HT_cap_element;
+		unsigned char HT_cap[26];
+	} u;
+} __packed;
+
+struct HT_info_element {
+	unsigned char	primary_channel;
+	unsigned char	infos[5];
+	unsigned char	MCS_rate[16];
+} __packed;
+
+struct AC_param {
+	unsigned char		ACI_AIFSN;
+	unsigned char		CW;
+	__le16	TXOP_limit;
+} __packed;
+
+struct WMM_para_element {
+	unsigned char		QoS_info;
+	unsigned char		reserved;
+	struct AC_param	ac_param[4];
+} __packed;
+
+struct ADDBA_request {
+	unsigned char	dialog_token;
+	unsigned short	BA_para_set;
+	unsigned short	BA_timeout_value;
+	unsigned short	BA_starting_seqctrl;
+} __packed;
+
+enum ht_cap_ampdu_factor {
+	MAX_AMPDU_FACTOR_8K	= 0,
+	MAX_AMPDU_FACTOR_16K	= 1,
+	MAX_AMPDU_FACTOR_32K	= 2,
+	MAX_AMPDU_FACTOR_64K	= 3,
+};
+
+/* 802.11n HT capabilities masks */
+#define IEEE80211_HT_CAP_SUP_WIDTH		0x0002
+#define IEEE80211_HT_CAP_SM_PS			0x000C
+#define IEEE80211_HT_CAP_GRN_FLD		0x0010
+#define IEEE80211_HT_CAP_SGI_20			0x0020
+#define IEEE80211_HT_CAP_SGI_40			0x0040
+#define IEEE80211_HT_CAP_TX_STBC		0x0080
+#define IEEE80211_HT_CAP_RX_STBC		0x0300
+#define IEEE80211_HT_CAP_DELAY_BA		0x0400
+#define IEEE80211_HT_CAP_MAX_AMSDU		0x0800
+#define IEEE80211_HT_CAP_DSSSCCK40		0x1000
+/* 802.11n HT capability AMPDU settings */
+#define IEEE80211_HT_CAP_AMPDU_FACTOR		0x03
+#define IEEE80211_HT_CAP_AMPDU_DENSITY		0x1C
+/* 802.11n HT capability MSC set */
+#define IEEE80211_SUPP_MCS_SET_UEQM		4
+#define IEEE80211_HT_CAP_MAX_STREAMS		4
+#define IEEE80211_SUPP_MCS_SET_LEN		10
+/* maximum streams the spec allows */
+#define IEEE80211_HT_CAP_MCS_TX_DEFINED		0x01
+#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF		0x02
+#define IEEE80211_HT_CAP_MCS_TX_STREAMS		0x0C
+#define IEEE80211_HT_CAP_MCS_TX_UEQM		0x10
+/* 802.11n HT IE masks */
+#define IEEE80211_HT_IE_CHA_SEC_OFFSET		0x03
+#define IEEE80211_HT_IE_CHA_SEC_NONE		0x00
+#define IEEE80211_HT_IE_CHA_SEC_ABOVE		0x01
+#define IEEE80211_HT_IE_CHA_SEC_BELOW		0x03
+#define IEEE80211_HT_IE_CHA_WIDTH		0x04
+#define IEEE80211_HT_IE_HT_PROTECTION		0x0003
+#define IEEE80211_HT_IE_NON_GF_STA_PRSNT	0x0004
+#define IEEE80211_HT_IE_NON_HT_STA_PRSNT	0x0010
+
+/* block-ack parameters */
+#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
+#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
+#define RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
+#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
+#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
+
+/*
+ * A-PMDU buffer sizes
+ * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2)
+ */
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+#define IEEE80211_MAX_AMPDU_BUF 0x40
+
+
+/* Spatial Multiplexing Power Save Modes */
+#define WLAN_HT_CAP_SM_PS_STATIC	0
+#define WLAN_HT_CAP_SM_PS_DYNAMIC	1
+#define WLAN_HT_CAP_SM_PS_INVALID	2
+#define WLAN_HT_CAP_SM_PS_DISABLED	3
+
+
+#define OP_MODE_PURE                    0
+#define OP_MODE_MAY_BE_LEGACY_STAS      1
+#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
+#define OP_MODE_MIXED                   3
+
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
+#define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY	((u8) BIT(5))
+
+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
+		((u16) (0x0001 | 0x0002))
+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT	((u8) BIT(4))
+
+#define HT_INFO_STBC_PARAM_DUAL_BEACON		((u16) BIT(6))
+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT	((u16) BIT(7))
+#define HT_INFO_STBC_PARAM_SECONDARY_BC		((u16) BIT(8))
+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED	((u16) BIT(9))
+#define HT_INFO_STBC_PARAM_PCO_ACTIVE		((u16) BIT(10))
+#define HT_INFO_STBC_PARAM_PCO_PHASE		((u16) BIT(11))
+
+/*	===============WPS Section=============== */
+/*	For WPSv1.0 */
+#define WPSOUI					0x0050f204
+/*	WPS attribute ID */
+#define WPS_ATTR_VER1				0x104A
+#define WPS_ATTR_SIMPLE_CONF_STATE		0x1044
+#define WPS_ATTR_RESP_TYPE			0x103B
+#define WPS_ATTR_UUID_E				0x1047
+#define WPS_ATTR_MANUFACTURER			0x1021
+#define WPS_ATTR_MODEL_NAME			0x1023
+#define WPS_ATTR_MODEL_NUMBER			0x1024
+#define WPS_ATTR_SERIAL_NUMBER			0x1042
+#define WPS_ATTR_PRIMARY_DEV_TYPE		0x1054
+#define WPS_ATTR_SEC_DEV_TYPE_LIST		0x1055
+#define WPS_ATTR_DEVICE_NAME			0x1011
+#define WPS_ATTR_CONF_METHOD			0x1008
+#define WPS_ATTR_RF_BANDS			0x103C
+#define WPS_ATTR_DEVICE_PWID			0x1012
+#define WPS_ATTR_REQUEST_TYPE			0x103A
+#define WPS_ATTR_ASSOCIATION_STATE		0x1002
+#define WPS_ATTR_CONFIG_ERROR			0x1009
+#define WPS_ATTR_VENDOR_EXT			0x1049
+#define WPS_ATTR_SELECTED_REGISTRAR		0x1041
+
+/*	Value of WPS attribute "WPS_ATTR_DEVICE_NAME */
+#define WPS_MAX_DEVICE_NAME_LEN			32
+
+/*	Value of WPS Request Type Attribute */
+#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY		0x00
+#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X	0x01
+#define WPS_REQ_TYPE_REGISTRAR			0x02
+#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR	0x03
+
+/*	Value of WPS Response Type Attribute */
+#define WPS_RESPONSE_TYPE_INFO_ONLY	0x00
+#define WPS_RESPONSE_TYPE_8021X		0x01
+#define WPS_RESPONSE_TYPE_REGISTRAR	0x02
+#define WPS_RESPONSE_TYPE_AP		0x03
+
+/*	Value of WPS WiFi Simple Configuration State Attribute */
+#define WPS_WSC_STATE_NOT_CONFIG	0x01
+#define WPS_WSC_STATE_CONFIG		0x02
+
+/*	Value of WPS Version Attribute */
+#define WPS_VERSION_1			0x10
+
+/*	Value of WPS Configuration Method Attribute */
+#define WPS_CONFIG_METHOD_FLASH		0x0001
+#define WPS_CONFIG_METHOD_ETHERNET	0x0002
+#define WPS_CONFIG_METHOD_LABEL		0x0004
+#define WPS_CONFIG_METHOD_DISPLAY	0x0008
+#define WPS_CONFIG_METHOD_E_NFC		0x0010
+#define WPS_CONFIG_METHOD_I_NFC		0x0020
+#define WPS_CONFIG_METHOD_NFC		0x0040
+#define WPS_CONFIG_METHOD_PBC		0x0080
+#define WPS_CONFIG_METHOD_KEYPAD	0x0100
+#define WPS_CONFIG_METHOD_VPBC		0x0280
+#define WPS_CONFIG_METHOD_PPBC		0x0480
+#define WPS_CONFIG_METHOD_VDISPLAY	0x2008
+#define WPS_CONFIG_METHOD_PDISPLAY	0x4008
+
+/*	Value of Category ID of WPS Primary Device Type Attribute */
+#define WPS_PDT_CID_DISPLAYS		0x0007
+#define WPS_PDT_CID_MULIT_MEDIA		0x0008
+#define WPS_PDT_CID_RTK_WIDI		WPS_PDT_CID_MULIT_MEDIA
+
+/*	Value of Sub Category ID of WPS Primary Device Type Attribute */
+#define WPS_PDT_SCID_MEDIA_SERVER	0x0005
+#define WPS_PDT_SCID_RTK_DMP		WPS_PDT_SCID_MEDIA_SERVER
+
+/*	Value of Device Password ID */
+#define WPS_DPID_P			0x0000
+#define WPS_DPID_USER_SPEC		0x0001
+#define WPS_DPID_MACHINE_SPEC		0x0002
+#define WPS_DPID_REKEY			0x0003
+#define WPS_DPID_PBC			0x0004
+#define WPS_DPID_REGISTRAR_SPEC		0x0005
+
+/*	Value of WPS RF Bands Attribute */
+#define WPS_RF_BANDS_2_4_GHZ		0x01
+#define WPS_RF_BANDS_5_GHZ		0x02
+
+/*	Value of WPS Association State Attribute */
+#define WPS_ASSOC_STATE_NOT_ASSOCIATED		0x00
+#define WPS_ASSOC_STATE_CONNECTION_SUCCESS	0x01
+#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE	0x02
+#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE	0x03
+#define WPS_ASSOC_STATE_IP_FAILURE		0x04
+
+/*	=====================P2P Section===================== */
+/*	For P2P */
+#define	P2POUI					0x506F9A09
+
+/*	P2P Attribute ID */
+#define	P2P_ATTR_STATUS				0x00
+#define	P2P_ATTR_MINOR_REASON_CODE		0x01
+#define	P2P_ATTR_CAPABILITY			0x02
+#define	P2P_ATTR_DEVICE_ID			0x03
+#define	P2P_ATTR_GO_INTENT			0x04
+#define	P2P_ATTR_CONF_TIMEOUT			0x05
+#define	P2P_ATTR_LISTEN_CH			0x06
+#define	P2P_ATTR_GROUP_BSSID			0x07
+#define	P2P_ATTR_EX_LISTEN_TIMING		0x08
+#define	P2P_ATTR_INTENTED_IF_ADDR		0x09
+#define	P2P_ATTR_MANAGEABILITY			0x0A
+#define	P2P_ATTR_CH_LIST			0x0B
+#define	P2P_ATTR_NOA				0x0C
+#define	P2P_ATTR_DEVICE_INFO			0x0D
+#define	P2P_ATTR_GROUP_INFO			0x0E
+#define	P2P_ATTR_GROUP_ID			0x0F
+#define	P2P_ATTR_INTERFACE			0x10
+#define	P2P_ATTR_OPERATING_CH			0x11
+#define	P2P_ATTR_INVITATION_FLAGS		0x12
+
+/*	Value of Status Attribute */
+#define	P2P_STATUS_SUCCESS				0x00
+#define	P2P_STATUS_FAIL_INFO_UNAVAILABLE		0x01
+#define	P2P_STATUS_FAIL_INCOMPATIBLE_PARAM		0x02
+#define	P2P_STATUS_FAIL_LIMIT_REACHED			0x03
+#define	P2P_STATUS_FAIL_INVALID_PARAM			0x04
+#define	P2P_STATUS_FAIL_REQUEST_UNABLE			0x05
+#define	P2P_STATUS_FAIL_PREVOUS_PROTO_ERR		0x06
+#define	P2P_STATUS_FAIL_NO_COMMON_CH			0x07
+#define	P2P_STATUS_FAIL_UNKNOWN_P2PGROUP		0x08
+#define	P2P_STATUS_FAIL_BOTH_GOINTENT_15		0x09
+#define	P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION		0x0A
+#define	P2P_STATUS_FAIL_USER_REJECT			0x0B
+
+/*	Value of Inviation Flags Attribute */
+#define	P2P_INVITATION_FLAGS_PERSISTENT			BIT(0)
+
+#define	DMP_P2P_DEVCAP_SUPPORT	(P2P_DEVCAP_SERVICE_DISCOVERY | \
+				P2P_DEVCAP_CLIENT_DISCOVERABILITY | \
+				P2P_DEVCAP_CONCURRENT_OPERATION | \
+				P2P_DEVCAP_INVITATION_PROC)
+
+#define	DMP_P2P_GRPCAP_SUPPORT	(P2P_GRPCAP_INTRABSS)
+
+/*	Value of Device Capability Bitmap */
+#define	P2P_DEVCAP_SERVICE_DISCOVERY		BIT(0)
+#define	P2P_DEVCAP_CLIENT_DISCOVERABILITY	BIT(1)
+#define	P2P_DEVCAP_CONCURRENT_OPERATION		BIT(2)
+#define	P2P_DEVCAP_INFRA_MANAGED		BIT(3)
+#define	P2P_DEVCAP_DEVICE_LIMIT			BIT(4)
+#define	P2P_DEVCAP_INVITATION_PROC		BIT(5)
+
+/*	Value of Group Capability Bitmap */
+#define	P2P_GRPCAP_GO				BIT(0)
+#define	P2P_GRPCAP_PERSISTENT_GROUP		BIT(1)
+#define	P2P_GRPCAP_GROUP_LIMIT			BIT(2)
+#define	P2P_GRPCAP_INTRABSS			BIT(3)
+#define	P2P_GRPCAP_CROSS_CONN			BIT(4)
+#define	P2P_GRPCAP_PERSISTENT_RECONN		BIT(5)
+#define	P2P_GRPCAP_GROUP_FORMATION		BIT(6)
+
+/*	P2P Public Action Frame (Management Frame) */
+#define	P2P_PUB_ACTION_ACTION			0x09
+
+/*	P2P Public Action Frame Type */
+#define	P2P_GO_NEGO_REQ				0
+#define	P2P_GO_NEGO_RESP			1
+#define	P2P_GO_NEGO_CONF			2
+#define	P2P_INVIT_REQ				3
+#define	P2P_INVIT_RESP				4
+#define	P2P_DEVDISC_REQ				5
+#define	P2P_DEVDISC_RESP			6
+#define	P2P_PROVISION_DISC_REQ			7
+#define	P2P_PROVISION_DISC_RESP			8
+
+/*	P2P Action Frame Type */
+#define	P2P_NOTICE_OF_ABSENCE			0
+#define	P2P_PRESENCE_REQUEST			1
+#define	P2P_PRESENCE_RESPONSE			2
+#define	P2P_GO_DISC_REQUEST			3
+
+
+#define	P2P_MAX_PERSISTENT_GROUP_NUM		10
+
+#define	P2P_PROVISIONING_SCAN_CNT		3
+
+#define	P2P_WILDCARD_SSID_LEN			7
+
+/* default value, used when: (1)p2p disabed or (2)p2p enabled
+ * but only do 1 scan phase */
+#define	P2P_FINDPHASE_EX_NONE		0
+/*  used when p2p enabled and want to do 1 scan phase and
+ *  P2P_FINDPHASE_EX_MAX-1 find phase */
+#define	P2P_FINDPHASE_EX_FULL		1
+#define	P2P_FINDPHASE_EX_SOCIAL_FIRST	(P2P_FINDPHASE_EX_FULL+1)
+#define	P2P_FINDPHASE_EX_MAX		4
+#define	P2P_FINDPHASE_EX_SOCIAL_LAST	P2P_FINDPHASE_EX_MAX
+
+/* 5 seconds timeout for sending the provision discovery request */
+#define	P2P_PROVISION_TIMEOUT		5000
+/* 3 seconds timeout for sending the prov disc request concurrent mode */
+#define	P2P_CONCURRENT_PROVISION_TIME	3000
+/* 5 seconds timeout for receiving the group negotation response */
+#define	P2P_GO_NEGO_TIMEOUT		5000
+/* 3 seconds timeout for sending the negotiation request under concurrent mode */
+#define	P2P_CONCURRENT_GO_NEGO_TIME	3000
+/* 100ms */
+#define	P2P_TX_PRESCAN_TIMEOUT		100
+/* 5 seconds timeout for sending the invitation request */
+#define	P2P_INVITE_TIMEOUT		5000
+/* 3 seconds timeout for sending the invitation request under concurrent mode */
+#define	P2P_CONCURRENT_INVITE_TIME	3000
+/* 25 seconds timeout to reset the scan channel (based on channel plan) */
+#define	P2P_RESET_SCAN_CH		25000
+#define	P2P_MAX_INTENT			15
+
+#define	P2P_MAX_NOA_NUM			2
+
+/*	WPS Configuration Method */
+#define	WPS_CM_NONE			0x0000
+#define	WPS_CM_LABEL			0x0004
+#define	WPS_CM_DISPLYA			0x0008
+#define	WPS_CM_EXTERNAL_NFC_TOKEN	0x0010
+#define	WPS_CM_INTEGRATED_NFC_TOKEN	0x0020
+#define	WPS_CM_NFC_INTERFACE		0x0040
+#define	WPS_CM_PUSH_BUTTON		0x0080
+#define	WPS_CM_KEYPAD			0x0100
+#define	WPS_CM_SW_PUHS_BUTTON		0x0280
+#define	WPS_CM_HW_PUHS_BUTTON		0x0480
+#define	WPS_CM_SW_DISPLAY_P		0x2008
+#define	WPS_CM_LCD_DISPLAY_P		0x4008
+
+enum P2P_ROLE {
+	P2P_ROLE_DISABLE = 0,
+	P2P_ROLE_DEVICE = 1,
+	P2P_ROLE_CLIENT = 2,
+	P2P_ROLE_GO = 3
+};
+
+enum P2P_STATE {
+	P2P_STATE_NONE = 0,			/* P2P disable */
+	/* P2P had enabled and do nothing */
+	P2P_STATE_IDLE = 1,
+	P2P_STATE_LISTEN = 2,			/* In pure listen state */
+	P2P_STATE_SCAN = 3,			/* In scan phase */
+	/* In the listen state of find phase */
+	P2P_STATE_FIND_PHASE_LISTEN = 4,
+	/* In the search state of find phase */
+	P2P_STATE_FIND_PHASE_SEARCH = 5,
+	/* In P2P provisioning discovery */
+	P2P_STATE_TX_PROVISION_DIS_REQ = 6,
+	P2P_STATE_RX_PROVISION_DIS_RSP = 7,
+	P2P_STATE_RX_PROVISION_DIS_REQ = 8,
+	/* Doing the group owner negoitation handshake */
+	P2P_STATE_GONEGO_ING = 9,
+	/* finish the group negoitation handshake with success */
+	P2P_STATE_GONEGO_OK = 10,
+	/* finish the group negoitation handshake with failure */
+	P2P_STATE_GONEGO_FAIL = 11,
+	/* receiving the P2P Inviation request and match with the profile. */
+	P2P_STATE_RECV_INVITE_REQ_MATCH = 12,
+	/* Doing the P2P WPS */
+	P2P_STATE_PROVISIONING_ING = 13,
+	/* Finish the P2P WPS */
+	P2P_STATE_PROVISIONING_DONE = 14,
+	/* Transmit the P2P Invitation request */
+	P2P_STATE_TX_INVITE_REQ = 15,
+	/* Receiving the P2P Invitation response */
+	P2P_STATE_RX_INVITE_RESP_OK = 16,
+	/* receiving the P2P Inviation request and dismatch with the profile. */
+	P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17,
+	/* receiving the P2P Inviation request and this wifi is GO. */
+	P2P_STATE_RECV_INVITE_REQ_GO = 18,
+	/* receiving the P2P Inviation request to join an existing P2P Group. */
+	P2P_STATE_RECV_INVITE_REQ_JOIN = 19,
+	/* recveing the P2P Inviation response with failure */
+	P2P_STATE_RX_INVITE_RESP_FAIL = 20,
+	/* receiving p2p negoitation response with information is not available */
+	P2P_STATE_RX_INFOR_NOREADY = 21,
+	/* sending p2p negoitation response with information is not available */
+	P2P_STATE_TX_INFOR_NOREADY = 22,
+};
+
+enum P2P_WPSINFO {
+	P2P_NO_WPSINFO				= 0,
+	P2P_GOT_WPSINFO_PEER_DISPLAY_PIN	= 1,
+	P2P_GOT_WPSINFO_SELF_DISPLAY_PIN	= 2,
+	P2P_GOT_WPSINFO_PBC			= 3,
+};
+
+#define	P2P_PRIVATE_IOCTL_SET_LEN		64
+
+enum P2P_PROTO_WK_ID {
+	P2P_FIND_PHASE_WK = 0,
+	P2P_RESTORE_STATE_WK = 1,
+	P2P_PRE_TX_PROVDISC_PROCESS_WK = 2,
+	P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3,
+	P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4,
+	P2P_AP_P2P_CH_SWITCH_PROCESS_WK =5,
+	P2P_RO_CH_WK = 6,
+};
+
+enum P2P_PS_STATE {
+	P2P_PS_DISABLE = 0,
+	P2P_PS_ENABLE = 1,
+	P2P_PS_SCAN = 2,
+	P2P_PS_SCAN_DONE = 3,
+	P2P_PS_ALLSTASLEEP = 4, /*  for P2P GO */
+};
+
+enum P2P_PS_MODE {
+	P2P_PS_NONE = 0,
+	P2P_PS_CTWINDOW = 1,
+	P2P_PS_NOA	 = 2,
+	P2P_PS_MIX = 3, /*  CTWindow and NoA */
+};
+
+/*	=====================WFD Section===================== */
+/*	For Wi-Fi Display */
+#define	WFD_ATTR_DEVICE_INFO		0x00
+#define	WFD_ATTR_ASSOC_BSSID		0x01
+#define	WFD_ATTR_COUPLED_SINK_INFO	0x06
+#define	WFD_ATTR_LOCAL_IP_ADDR		0x08
+#define	WFD_ATTR_SESSION_INFO		0x09
+#define	WFD_ATTR_ALTER_MAC		0x0a
+
+/*	For WFD Device Information Attribute */
+#define	WFD_DEVINFO_SOURCE			0x0000
+#define	WFD_DEVINFO_PSINK			0x0001
+#define	WFD_DEVINFO_SSINK			0x0002
+#define	WFD_DEVINFO_DUAL			0x0003
+
+#define	WFD_DEVINFO_SESSION_AVAIL		0x0010
+#define	WFD_DEVINFO_WSD				0x0040
+#define	WFD_DEVINFO_PC_TDLS			0x0080
+#define	WFD_DEVINFO_HDCP_SUPPORT		0x0100
+
+#define IP_MCAST_MAC(mac)				\
+	((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x5e))
+#define ICMPV6_MCAST_MAC(mac)				\
+	((mac[0] == 0x33) && (mac[1] == 0x33) && (mac[2] != 0xff))
+
+#endif /*  _WIFI_H_ */
diff --git a/drivers/staging/rtl8188eu/include/wlan_bssdef.h b/drivers/staging/rtl8188eu/include/wlan_bssdef.h
new file mode 100644
index 0000000..e70075d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/wlan_bssdef.h
@@ -0,0 +1,347 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __WLAN_BSSDEF_H__
+#define __WLAN_BSSDEF_H__
+
+
+#define MAX_IE_SZ			768
+
+#define NDIS_802_11_LENGTH_SSID         32
+#define NDIS_802_11_LENGTH_RATES        8
+#define NDIS_802_11_LENGTH_RATES_EX     16
+
+#define NDIS_802_11_RSSI long           /*  in dBm */
+
+struct ndis_802_11_ssid {
+	u32  SsidLength;
+	u8  Ssid[32];
+};
+
+enum NDIS_802_11_NETWORK_TYPE {
+	Ndis802_11FH,
+	Ndis802_11DS,
+	Ndis802_11OFDM5,
+	Ndis802_11OFDM24,
+	Ndis802_11NetworkTypeMax    /*  dummy upper bound */
+};
+
+struct ndis_802_11_config_fh {
+	u32           Length;		/*  Length of structure */
+	u32           HopPattern;	/*  As defined by 802.11, MSB set */
+	u32           HopSet;		/*  to one if non-802.11 */
+	u32           DwellTime;	/*  units are Kusec */
+};
+
+/*
+ *	FW will only save the channel number in DSConfig.
+ *	ODI Handler will convert the channel number to freq. number.
+ */
+struct ndis_802_11_config {
+	u32           Length;             /*  Length of structure */
+	u32           BeaconPeriod;       /*  units are Kusec */
+	u32           ATIMWindow;         /*  units are Kusec */
+	u32           DSConfig;           /*  Frequency, units are kHz */
+	struct ndis_802_11_config_fh    FHConfig;
+};
+
+enum ndis_802_11_network_infra {
+	Ndis802_11IBSS,
+	Ndis802_11Infrastructure,
+	Ndis802_11AutoUnknown,
+	Ndis802_11InfrastructureMax,     /*  dummy upper bound */
+	Ndis802_11APMode
+};
+
+struct ndis_802_11_fixed_ie {
+	u8  Timestamp[8];
+	u16  BeaconInterval;
+	u16  Capabilities;
+};
+
+
+
+struct ndis_802_11_var_ie {
+	u8  ElementID;
+	u8  Length;
+	u8  data[1];
+};
+
+/*
+ * Length is the 4 bytes multiples of the sume of
+ *	[ETH_ALEN] + 2 + sizeof (struct ndis_802_11_ssid) + sizeof (u32)
+ *	+ sizeof (NDIS_802_11_RSSI) + sizeof (enum NDIS_802_11_NETWORK_TYPE)
+ *	+ sizeof (struct ndis_802_11_config)
+ *	+ NDIS_802_11_LENGTH_RATES_EX + IELength
+ *
+ * Except the IELength, all other fields are fixed length.
+ * Therefore, we can define a macro to represent the partial sum. */
+
+enum ndis_802_11_auth_mode {
+	Ndis802_11AuthModeOpen,
+	Ndis802_11AuthModeShared,
+	Ndis802_11AuthModeAutoSwitch,
+	Ndis802_11AuthModeWPA,
+	Ndis802_11AuthModeWPAPSK,
+	Ndis802_11AuthModeWPANone,
+	Ndis802_11AuthModeWAPI,
+	Ndis802_11AuthModeMax	/*  Not a real mode, upper bound */
+};
+
+enum ndis_802_11_wep_status {
+	Ndis802_11WEPEnabled,
+	Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+	Ndis802_11WEPDisabled,
+	Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+	Ndis802_11WEPKeyAbsent,
+	Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+	Ndis802_11WEPNotSupported,
+	Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+	Ndis802_11Encryption2Enabled,
+	Ndis802_11Encryption2KeyAbsent,
+	Ndis802_11Encryption3Enabled,
+	Ndis802_11Encryption3KeyAbsent,
+	Ndis802_11_EncryptionWAPI
+};
+
+#define NDIS_802_11_AI_REQFI_CAPABILITIES      1
+#define NDIS_802_11_AI_REQFI_LISTENINTERVAL    2
+#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS  4
+
+#define NDIS_802_11_AI_RESFI_CAPABILITIES      1
+#define NDIS_802_11_AI_RESFI_STATUSCODE        2
+#define NDIS_802_11_AI_RESFI_ASSOCIATIONID     4
+
+struct ndis_802_11_ai_reqfi {
+    u16 Capabilities;
+    u16 ListenInterval;
+    unsigned char CurrentAPAddress[ETH_ALEN];
+};
+
+struct ndis_802_11_ai_resfi {
+    u16 Capabilities;
+    u16 StatusCode;
+    u16 AssociationId;
+};
+
+struct ndis_802_11_assoc_info {
+	u32  Length;
+	u16 AvailableRequestFixedIEs;
+	struct ndis_802_11_ai_reqfi    RequestFixedIEs;
+	u32  RequestIELength;
+	u32  OffsetRequestIEs;
+	u16 AvailableResponseFixedIEs;
+	struct ndis_802_11_ai_resfi    ResponseFixedIEs;
+	u32  ResponseIELength;
+	u32  OffsetResponseIEs;
+};
+
+enum ndis_802_11_reload_def {
+	Ndis802_11ReloadWEPKeys
+};
+
+/*  Key mapping keys require a BSSID */
+struct ndis_802_11_key {
+	u32           Length;             /*  Length of this structure */
+	u32           KeyIndex;
+	u32           KeyLength;          /*  length of key in bytes */
+	unsigned char BSSID[ETH_ALEN];
+	unsigned long long KeyRSC;
+	u8           KeyMaterial[32];  /* var len depending on above field */
+};
+
+struct ndis_802_11_remove_key {
+	u32                   Length;        /*  Length */
+	u32                   KeyIndex;
+	unsigned char BSSID[ETH_ALEN];
+};
+
+struct ndis_802_11_wep {
+	u32     Length;        /*  Length of this structure */
+	u32     KeyIndex;      /*  0 is the per-client key,
+				  * 1-N are the global keys */
+	u32     KeyLength;     /*  length of key in bytes */
+	u8     KeyMaterial[16];/*  variable len depending on above field */
+};
+
+struct ndis_802_11_auth_req {
+	u32 Length;            /*  Length of structure */
+	unsigned char Bssid[ETH_ALEN];
+	u32 Flags;
+};
+
+enum ndis_802_11_status_type {
+	Ndis802_11StatusType_Authentication,
+	Ndis802_11StatusType_MediaStreamMode,
+	Ndis802_11StatusType_PMKID_CandidateList,
+	Ndis802_11StatusTypeMax    /*  not a real type, defined as
+				    * an upper bound */
+};
+
+struct ndis_802_11_status_ind {
+	enum ndis_802_11_status_type StatusType;
+};
+
+/*  mask for authentication/integrity fields */
+#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS        	0x0f
+#define NDIS_802_11_AUTH_REQUEST_REAUTH			0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE		0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR		0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR		0x0E
+
+/*  MIC check time, 60 seconds. */
+#define MIC_CHECK_TIME	60000000
+
+struct ndis_802_11_auth_evt {
+	struct ndis_802_11_status_ind       Status;
+	struct ndis_802_11_auth_req  Request[1];
+};
+
+struct ndis_802_11_test {
+	u32 Length;
+	u32 Type;
+	union {
+		struct ndis_802_11_auth_evt AuthenticationEvent;
+		NDIS_802_11_RSSI RssiTrigger;
+	} tt;
+};
+
+
+#ifndef Ndis802_11APMode
+#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1)
+#endif
+
+struct wlan_phy_info {
+	u8	SignalStrength;/* in percentage) */
+	u8	SignalQuality;/* in percentage) */
+	u8	Optimum_antenna;  /* for Antenna diversity */
+	u8	Reserved_0;
+};
+
+struct wlan_bcn_info {
+	/* these infor get from rtw_get_encrypt_info when
+	 *	 * translate scan to UI */
+	u8 encryp_protocol;/* ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2/WAPI */
+	int group_cipher; /* WPA/WPA2 group cipher */
+	int pairwise_cipher;/* WPA/WPA2/WEP pairwise cipher */
+	int is_8021x;
+
+	/* bwmode 20/40 and ch_offset UP/LOW */
+	unsigned short	ht_cap_info;
+	unsigned char	ht_info_infos_0;
+};
+
+/* temporally add #pragma pack for structure alignment issue of
+*   struct wlan_bssid_ex and get_struct wlan_bssid_ex_sz()
+*/
+struct wlan_bssid_ex {
+	u32  Length;
+	unsigned char MacAddress[ETH_ALEN];
+	u8  Reserved[2];/* 0]: IS beacon frame */
+	struct ndis_802_11_ssid  Ssid;
+	u32  Privacy;
+	NDIS_802_11_RSSI  Rssi;/* in dBM,raw data ,get from PHY) */
+	enum  NDIS_802_11_NETWORK_TYPE  NetworkTypeInUse;
+	struct ndis_802_11_config  Configuration;
+	enum ndis_802_11_network_infra  InfrastructureMode;
+	unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+	struct wlan_phy_info	PhyInfo;
+	u32  IELength;
+	u8  IEs[MAX_IE_SZ];	/* timestamp, beacon interval, and
+				 * capability information) */
+} __packed;
+
+static inline uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss)
+{
+	return sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength;
+}
+
+struct	wlan_network {
+	struct list_head list;
+	int	network_type;	/* refer to ieee80211.h for WIRELESS_11A/B/G */
+	int	fixed;		/*  set fixed when not to be removed
+				 *  in site-surveying */
+	unsigned long	last_scanned; /* timestamp for the network */
+	int	aid;		/* will only be valid when a BSS is joinned. */
+	int	join_res;
+	struct wlan_bssid_ex	network; /* must be the last item */
+	struct wlan_bcn_info	BcnInfo;
+};
+
+enum VRTL_CARRIER_SENSE {
+	DISABLE_VCS,
+	ENABLE_VCS,
+	AUTO_VCS
+};
+
+enum VCS_TYPE {
+	NONE_VCS,
+	RTS_CTS,
+	CTS_TO_SELF
+};
+
+#define PWR_CAM 0
+#define PWR_MINPS 1
+#define PWR_MAXPS 2
+#define PWR_UAPSD 3
+#define PWR_VOIP 4
+
+enum UAPSD_MAX_SP {
+	NO_LIMIT,
+	TWO_MSDU,
+	FOUR_MSDU,
+	SIX_MSDU
+};
+
+#define NUM_PRE_AUTH_KEY 16
+#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY
+
+/*
+*	WPA2
+*/
+
+struct pmkid_candidate {
+	unsigned char BSSID[ETH_ALEN];
+	u32 Flags;
+};
+
+struct ndis_802_11_pmkid_list {
+	u32 Version;       /*  Version of the structure */
+	u32 NumCandidates; /*  No. of pmkid candidates */
+	struct pmkid_candidate CandidateList[1];
+};
+
+struct ndis_802_11_auth_encrypt {
+	enum ndis_802_11_auth_mode AuthModeSupported;
+	enum ndis_802_11_wep_status EncryptStatusSupported;
+};
+
+struct ndis_802_11_cap {
+	u32  Length;
+	u32  Version;
+	u32  NoOfPMKIDs;
+	u32  NoOfAuthEncryptPairsSupported;
+	struct ndis_802_11_auth_encrypt AuthenticationEncryptionSupported[1];
+};
+
+u8 key_2char2num(u8 hch, u8 lch);
+u8 key_char2num(u8 ch);
+u8 str_2char2num(u8 hch, u8 lch);
+
+#endif /* ifndef WLAN_BSSDEF_H_ */
diff --git a/drivers/staging/rtl8188eu/include/xmit_osdep.h b/drivers/staging/rtl8188eu/include/xmit_osdep.h
new file mode 100644
index 0000000..2ff622b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/include/xmit_osdep.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#ifndef __XMIT_OSDEP_H_
+#define __XMIT_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct pkt_file {
+	struct sk_buff *pkt;
+	size_t pkt_len;	 /* the remainder length of the open_file */
+	unsigned char *cur_buffer;
+	u8 *buf_start;
+	u8 *cur_addr;
+	size_t buf_len;
+};
+
+extern int rtw_ht_enable;
+extern int rtw_cbw40_enable;
+extern int rtw_ampdu_enable;/* for enable tx_ampdu */
+
+#define NR_XMITFRAME	256
+
+struct xmit_priv;
+struct pkt_attrib;
+struct sta_xmit_priv;
+struct xmit_frame;
+struct xmit_buf;
+
+int rtw_xmit_entry(struct sk_buff *pkt, struct  net_device *pnetdev);
+
+void rtw_os_xmit_schedule(struct adapter *padapter);
+
+int rtw_os_xmit_resource_alloc(struct adapter *padapter,
+			       struct xmit_buf *pxmitbuf, u32 alloc_sz);
+void rtw_os_xmit_resource_free(struct adapter *padapter,
+			       struct xmit_buf *pxmitbuf, u32 free_sz);
+
+void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib);
+
+uint rtw_remainder_len(struct pkt_file *pfile);
+void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile);
+uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen);
+int rtw_endofpktfile(struct pkt_file *pfile);
+
+void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt);
+void rtw_os_xmit_complete(struct adapter *padapter,
+			  struct xmit_frame *pxframe);
+
+#endif /* __XMIT_OSDEP_H_ */
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
new file mode 100644
index 0000000..cd4100f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -0,0 +1,8222 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _IOCTL_LINUX_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+#include <rtw_debug.h>
+#include <wifi.h>
+#include <rtw_mlme.h>
+#include <rtw_mlme_ext.h>
+#include <rtw_ioctl.h>
+#include <rtw_ioctl_set.h>
+#include <rtw_mp_ioctl.h>
+#include <usb_ops.h>
+#include <rtw_version.h>
+#include <rtl8188e_hal.h>
+
+#include <rtw_mp.h>
+#include <rtw_iol.h>
+
+#define RTL_IOCTL_WPA_SUPPLICANT	(SIOCIWFIRSTPRIV + 30)
+
+#define SCAN_ITEM_SIZE 768
+#define MAX_CUSTOM_LEN 64
+#define RATE_COUNT 4
+
+/*  combo scan */
+#define WEXT_CSCAN_AMOUNT 9
+#define WEXT_CSCAN_BUF_LEN		360
+#define WEXT_CSCAN_HEADER		"CSCAN S\x01\x00\x00S\x00"
+#define WEXT_CSCAN_HEADER_SIZE		12
+#define WEXT_CSCAN_SSID_SECTION		'S'
+#define WEXT_CSCAN_CHANNEL_SECTION	'C'
+#define WEXT_CSCAN_NPROBE_SECTION	'N'
+#define WEXT_CSCAN_ACTV_DWELL_SECTION	'A'
+#define WEXT_CSCAN_PASV_DWELL_SECTION	'P'
+#define WEXT_CSCAN_HOME_DWELL_SECTION	'H'
+#define WEXT_CSCAN_TYPE_SECTION		'T'
+
+static struct mp_ioctl_handler mp_ioctl_hdl[] = {
+/*0*/	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_start_test_hdl, OID_RT_PRO_START_TEST)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_stop_test_hdl, OID_RT_PRO_STOP_TEST)
+
+	GEN_HANDLER(sizeof(struct rwreg_param), rtl8188eu_oid_rt_pro_read_register_hdl, OID_RT_PRO_READ_REGISTER)
+	GEN_HANDLER(sizeof(struct rwreg_param), rtl8188eu_oid_rt_pro_write_register_hdl, OID_RT_PRO_WRITE_REGISTER)
+	GEN_HANDLER(sizeof(struct bb_reg_param), rtl8188eu_oid_rt_pro_read_bb_reg_hdl, OID_RT_PRO_READ_BB_REG)
+/*5*/	GEN_HANDLER(sizeof(struct bb_reg_param), rtl8188eu_oid_rt_pro_write_bb_reg_hdl, OID_RT_PRO_WRITE_BB_REG)
+	GEN_HANDLER(sizeof(struct rf_reg_param), rtl8188eu_oid_rt_pro_read_rf_reg_hdl, OID_RT_PRO_RF_READ_REGISTRY)
+	GEN_HANDLER(sizeof(struct rf_reg_param), rtl8188eu_oid_rt_pro_write_rf_reg_hdl, OID_RT_PRO_RF_WRITE_REGISTRY)
+
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl, OID_RT_PRO_SET_CHANNEL_DIRECT_CALL)
+	GEN_HANDLER(sizeof(struct txpower_param), rtl8188eu_oid_rt_pro_set_tx_power_control_hdl, OID_RT_PRO_SET_TX_POWER_CONTROL)
+/*10*/	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_data_rate_hdl, OID_RT_PRO_SET_DATA_RATE)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_set_bandwidth_hdl, OID_RT_SET_BANDWIDTH)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_antenna_bb_hdl, OID_RT_PRO_SET_ANTENNA_BB)
+
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_continuous_tx_hdl, OID_RT_PRO_SET_CONTINUOUS_TX)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl, OID_RT_PRO_SET_SINGLE_CARRIER_TX)
+/*15*/	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl, OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl, OID_RT_PRO_SET_SINGLE_TONE_TX)
+
+	EXT_MP_IOCTL_HANDLER(0, xmit_packet, 0)
+
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_set_rx_packet_type_hdl, OID_RT_SET_RX_PACKET_TYPE)
+	GEN_HANDLER(0, rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl, OID_RT_RESET_PHY_RX_PACKET_COUNT)
+/*20*/	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl, OID_RT_GET_PHY_RX_PACKET_RECEIVED)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl, OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR)
+
+	GEN_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0)
+	GEN_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0)
+	GEN_HANDLER(sizeof(struct efuse_access_struct), rtl8188eu_oid_rt_pro_efuse_hdl, OID_RT_PRO_EFUSE)
+/*25*/	GEN_HANDLER(0, rtl8188eu_oid_rt_pro_efuse_map_hdl, OID_RT_PRO_EFUSE_MAP)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_efuse_max_size_hdl, OID_RT_GET_EFUSE_MAX_SIZE)
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_efuse_current_size_hdl, OID_RT_GET_EFUSE_CURRENT_SIZE)
+
+	GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_thermal_meter_hdl, OID_RT_PRO_GET_THERMAL_METER)
+	GEN_HANDLER(sizeof(u8), rtl8188eu_oid_rt_pro_set_power_tracking_hdl, OID_RT_PRO_SET_POWER_TRACKING)
+/*30*/	GEN_HANDLER(sizeof(u8), rtl8188eu_oid_rt_set_power_down_hdl, OID_RT_SET_POWER_DOWN)
+/*31*/	GEN_HANDLER(0, rtl8188eu_oid_rt_pro_trigger_gpio_hdl, 0)
+};
+
+static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000,
+	6000000, 9000000, 12000000, 18000000, 24000000, 36000000,
+	48000000, 54000000};
+
+static const char * const iw_operation_mode[] = {
+	"Auto", "Ad-Hoc", "Managed",  "Master", "Repeater",
+	"Secondary", "Monitor"
+};
+
+static int hex2num_i(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+/**
+ * hwaddr_aton - Convert ASCII string to MAC address
+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+static int hwaddr_aton_i(const char *txt, u8 *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		a = hex2num_i(*txt++);
+		if (a < 0)
+			return -1;
+		b = hex2num_i(*txt++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+		if (i < 5 && *txt++ != ':')
+			return -1;
+	}
+
+	return 0;
+}
+
+void indicate_wx_scan_complete_event(struct adapter *padapter)
+{
+	union iwreq_data wrqu;
+
+	_rtw_memset(&wrqu, 0, sizeof(union iwreq_data));
+	wireless_send_event(padapter->pnetdev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+void rtw_indicate_wx_assoc_event(struct adapter *padapter)
+{
+	union iwreq_data wrqu;
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	_rtw_memset(&wrqu, 0, sizeof(union iwreq_data));
+
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+	memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN);
+
+	DBG_88E_LEVEL(_drv_always_, "assoc success\n");
+	wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
+}
+
+void rtw_indicate_wx_disassoc_event(struct adapter *padapter)
+{
+	union iwreq_data wrqu;
+
+	_rtw_memset(&wrqu, 0, sizeof(union iwreq_data));
+
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	_rtw_memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+
+	DBG_88E_LEVEL(_drv_always_, "indicate disassoc\n");
+	wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
+}
+
+static char *translate_scan(struct adapter *padapter,
+			    struct iw_request_info *info,
+			    struct wlan_network *pnetwork,
+			    char *start, char *stop)
+{
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct iw_event iwe;
+	u16 cap;
+	__le16 le_tmp;
+	u32 ht_ielen = 0;
+	char custom[MAX_CUSTOM_LEN];
+	char *p;
+	u16 max_rate = 0, rate, ht_cap = false;
+	u32 i = 0;
+	u8 bw_40MHz = 0, short_GI = 0;
+	u16 mcs_rate = 0;
+	u8 ss, sq;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+	if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+		u32	blnGotP2PIE = false;
+
+		/*	User is doing the P2P device discovery */
+		/*	The prefix of SSID should be "DIRECT-" and the IE should contains the P2P IE. */
+		/*	If not, the driver should ignore this AP and go to the next AP. */
+
+		/*	Verifying the SSID */
+		if (!memcmp(pnetwork->network.Ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN)) {
+			u32	p2pielen = 0;
+
+			if (pnetwork->network.Reserved[0] == 2) {/*  Probe Request */
+				/*	Verifying the P2P IE */
+				if (rtw_get_p2p_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &p2pielen))
+					blnGotP2PIE = true;
+			} else {/*  Beacon or Probe Respones */
+				/*	Verifying the P2P IE */
+				if (rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen))
+					blnGotP2PIE = true;
+			}
+		}
+
+		if (!blnGotP2PIE)
+			return start;
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	/*  AP MAC address  */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+
+	memcpy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN);
+	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
+
+	/* Add the ESSID */
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.flags = 1;
+	iwe.u.data.length = min_t(u16, pnetwork->network.Ssid.SsidLength, 32);
+	start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid);
+
+	/* parsing HT_CAP_IE */
+	p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12);
+
+	if (p && ht_ielen > 0) {
+		struct rtw_ieee80211_ht_cap *pht_capie;
+		ht_cap = true;
+		pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
+		memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
+		bw_40MHz = (pht_capie->cap_info&IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
+		short_GI = (pht_capie->cap_info&(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
+	}
+
+	/* Add the protocol name */
+	iwe.cmd = SIOCGIWNAME;
+	if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates))) {
+		if (ht_cap)
+			snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn");
+		else
+		snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b");
+	} else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates))) {
+		if (ht_cap)
+			snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn");
+		else
+			snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg");
+	} else {
+		if (pnetwork->network.Configuration.DSConfig > 14) {
+			if (ht_cap)
+				snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11an");
+			else
+				snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a");
+		} else {
+			if (ht_cap)
+				snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn");
+			else
+				snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g");
+		}
+	}
+
+	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
+
+	  /* Add mode */
+	iwe.cmd = SIOCGIWMODE;
+	memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
+
+	cap = le16_to_cpu(le_tmp);
+
+	if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
+		if (cap & WLAN_CAPABILITY_BSS)
+			iwe.u.mode = IW_MODE_MASTER;
+		else
+			iwe.u.mode = IW_MODE_ADHOC;
+
+		start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
+	}
+
+	if (pnetwork->network.Configuration.DSConfig < 1)
+		pnetwork->network.Configuration.DSConfig = 1;
+
+	 /* Add frequency/channel */
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = rtw_ch2freq(pnetwork->network.Configuration.DSConfig) * 100000;
+	iwe.u.freq.e = 1;
+	iwe.u.freq.i = pnetwork->network.Configuration.DSConfig;
+	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
+
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if (cap & WLAN_CAPABILITY_PRIVACY)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid);
+
+	/*Add basic and extended rates */
+	max_rate = 0;
+	p = custom;
+	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+	while (pnetwork->network.SupportedRates[i] != 0) {
+		rate = pnetwork->network.SupportedRates[i]&0x7F;
+		if (rate > max_rate)
+			max_rate = rate;
+		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+			      "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+		i++;
+	}
+
+	if (ht_cap) {
+		if (mcs_rate&0x8000)/* MCS15 */
+			max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130);
+		else if (mcs_rate&0x0080)/* MCS7 */
+			;
+		else/* default MCS7 */
+			max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65);
+
+		max_rate = max_rate*2;/* Mbps/2; */
+	}
+
+	iwe.cmd = SIOCGIWRATE;
+	iwe.u.bitrate.fixed = 0;
+	iwe.u.bitrate.disabled = 0;
+	iwe.u.bitrate.value = max_rate * 500000;
+	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN);
+
+	/* parsing WPA/WPA2 IE */
+	{
+		u8 buf[MAX_WPA_IE_LEN];
+		u8 wpa_ie[255], rsn_ie[255];
+		u16 wpa_len = 0, rsn_len = 0;
+		u8 *p;
+
+		rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len);
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: ssid =%s\n", pnetwork->network.Ssid.Ssid));
+		RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len));
+
+		if (wpa_len > 0) {
+			p = buf;
+			_rtw_memset(buf, 0, MAX_WPA_IE_LEN);
+			p += sprintf(p, "wpa_ie =");
+			for (i = 0; i < wpa_len; i++)
+				p += sprintf(p, "%02x", wpa_ie[i]);
+
+			_rtw_memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			iwe.u.data.length = strlen(buf);
+			start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+
+			_rtw_memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = wpa_len;
+			start = iwe_stream_add_point(info, start, stop, &iwe, wpa_ie);
+		}
+		if (rsn_len > 0) {
+			p = buf;
+			_rtw_memset(buf, 0, MAX_WPA_IE_LEN);
+			p += sprintf(p, "rsn_ie =");
+			for (i = 0; i < rsn_len; i++)
+				p += sprintf(p, "%02x", rsn_ie[i]);
+			_rtw_memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			iwe.u.data.length = strlen(buf);
+			start = iwe_stream_add_point(info, start, stop, &iwe, buf);
+
+			_rtw_memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVGENIE;
+			iwe.u.data.length = rsn_len;
+			start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie);
+		}
+	}
+
+	{/* parsing WPS IE */
+		uint cnt = 0, total_ielen;
+		u8 *wpsie_ptr = NULL;
+		uint wps_ielen = 0;
+
+		u8 *ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
+		total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
+
+		while (cnt < total_ielen) {
+			if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen > 2)) {
+				wpsie_ptr = &ie_ptr[cnt];
+				iwe.cmd = IWEVGENIE;
+				iwe.u.data.length = (u16)wps_ielen;
+				start = iwe_stream_add_point(info, start, stop, &iwe, wpsie_ptr);
+			}
+			cnt += ie_ptr[cnt+1]+2; /* goto next */
+		}
+	}
+
+	/* Add quality statistics */
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) == true &&
+	    is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network)) {
+		ss = padapter->recvpriv.signal_strength;
+		sq = padapter->recvpriv.signal_qual;
+	} else {
+		ss = pnetwork->network.PhyInfo.SignalStrength;
+		sq = pnetwork->network.PhyInfo.SignalQuality;
+	}
+
+	iwe.u.qual.level = (u8)ss;
+	iwe.u.qual.qual = (u8)sq;   /*  signal quality */
+	iwe.u.qual.noise = 0; /*  noise level */
+	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
+	return start;
+}
+
+static int wpa_set_auth_algs(struct net_device *dev, u32 value)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	int ret = 0;
+
+	if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
+		DBG_88E("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and  AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value);
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+		padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+	} else if (value & AUTH_ALG_SHARED_KEY) {
+		DBG_88E("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY  [value:0x%x]\n", value);
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+		padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+	} else if (value & AUTH_ALG_OPEN_SYSTEM) {
+		DBG_88E("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n");
+		if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) {
+			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+			padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+		}
+	} else if (value & AUTH_ALG_LEAP) {
+		DBG_88E("wpa_set_auth_algs, AUTH_ALG_LEAP\n");
+	} else {
+		DBG_88E("wpa_set_auth_algs, error!\n");
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+	int ret = 0;
+	u32 wep_key_idx, wep_key_len, wep_total_len;
+	struct ndis_802_11_wep	 *pwep = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
+
+_func_enter_;
+
+	param->u.crypt.err = 0;
+	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+	if (param_len < (u32) ((u8 *)param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) {
+		ret =  -EINVAL;
+		goto exit;
+	}
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+		if (param->u.crypt.idx >= WEP_KEYS) {
+			ret = -EINVAL;
+			goto exit;
+		}
+	} else {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("wpa_set_encryption, crypt.alg = WEP\n"));
+		DBG_88E("wpa_set_encryption, crypt.alg = WEP\n");
+
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+		padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+		padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+
+		wep_key_idx = param->u.crypt.idx;
+		wep_key_len = param->u.crypt.key_len;
+
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(1)wep_key_idx =%d\n", wep_key_idx));
+		DBG_88E("(1)wep_key_idx =%d\n", wep_key_idx);
+
+		if (wep_key_idx > WEP_KEYS)
+			return -EINVAL;
+
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("(2)wep_key_idx =%d\n", wep_key_idx));
+
+		if (wep_key_len > 0) {
+			wep_key_len = wep_key_len <= 5 ? 5 : 13;
+			wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
+			pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
+			if (pwep == NULL) {
+				RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, (" wpa_set_encryption: pwep allocate fail !!!\n"));
+				goto exit;
+			}
+			_rtw_memset(pwep, 0, wep_total_len);
+			pwep->KeyLength = wep_key_len;
+			pwep->Length = wep_total_len;
+			if (wep_key_len == 13) {
+				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+				padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+			}
+		} else {
+			ret = -EINVAL;
+			goto exit;
+		}
+		pwep->KeyIndex = wep_key_idx;
+		pwep->KeyIndex |= 0x80000000;
+		memcpy(pwep->KeyMaterial,  param->u.crypt.key, pwep->KeyLength);
+		if (param->u.crypt.set_tx) {
+			DBG_88E("wep, set_tx = 1\n");
+			if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
+				ret = -EOPNOTSUPP;
+		} else {
+			DBG_88E("wep, set_tx = 0\n");
+			if (wep_key_idx >= WEP_KEYS) {
+				ret = -EOPNOTSUPP;
+				goto exit;
+			}
+		      memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+			psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+			rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0);
+		}
+		goto exit;
+	}
+
+	if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /*  802_1x */
+		struct sta_info *psta, *pbcmc_sta;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+
+		if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE)) { /* sta mode */
+			psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+			if (psta == NULL) {
+				;
+			} else {
+				if (strcmp(param->u.crypt.alg, "none") != 0)
+					psta->ieee8021x_blocked = false;
+
+				if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+				    (padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled))
+					psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+				if (param->u.crypt.set_tx == 1) { /* pairwise key */
+					memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+					if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
+						memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+						memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+						padapter->securitypriv.busetkipkey = false;
+					}
+
+					DBG_88E(" ~~~~set sta key:unicastkey\n");
+
+					rtw_setstakey_cmd(padapter, (unsigned char *)psta, true);
+				} else { /* group key */
+					memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+					memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+					memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+					padapter->securitypriv.binstallGrpkey = true;
+					DBG_88E(" ~~~~set sta key:groupkey\n");
+
+					padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
+
+					rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1);
+#ifdef CONFIG_88EU_P2P
+					if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+						rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE);
+#endif /* CONFIG_88EU_P2P */
+				}
+			}
+			pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+			if (pbcmc_sta == NULL) {
+				;
+			} else {
+				/* Jeff: don't disable ieee8021x_blocked while clearing key */
+				if (strcmp(param->u.crypt.alg, "none") != 0)
+					pbcmc_sta->ieee8021x_blocked = false;
+
+				if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+				    (padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled))
+					pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+			}
+		}
+	}
+
+exit:
+
+	kfree(pwep);
+
+_func_exit_;
+
+	return ret;
+}
+
+static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen)
+{
+	u8 *buf = NULL;
+	int group_cipher = 0, pairwise_cipher = 0;
+	int ret = 0;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
+
+	if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL)) {
+		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+		if (pie == NULL)
+			return ret;
+		else
+			return -EINVAL;
+	}
+
+	if (ielen) {
+		buf = rtw_zmalloc(ielen);
+		if (buf == NULL) {
+			ret =  -ENOMEM;
+			goto exit;
+		}
+
+		memcpy(buf, pie, ielen);
+
+		/* dump */
+		{
+			int i;
+			DBG_88E("\n wpa_ie(length:%d):\n", ielen);
+			for (i = 0; i < ielen; i += 8)
+				DBG_88E("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
+		}
+
+		if (ielen < RSN_HEADER_LEN) {
+			RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("Ie len too short %d\n", ielen));
+			ret  = -1;
+			goto exit;
+		}
+
+		if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
+			memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
+		}
+
+		if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+			padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
+			memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
+		}
+
+		switch (group_cipher) {
+		case WPA_CIPHER_NONE:
+			padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+			break;
+		case WPA_CIPHER_WEP40:
+			padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+			break;
+		case WPA_CIPHER_TKIP:
+			padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+			break;
+		case WPA_CIPHER_CCMP:
+			padapter->securitypriv.dot118021XGrpPrivacy = _AES_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+			break;
+		case WPA_CIPHER_WEP104:
+			padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+			break;
+		}
+
+		switch (pairwise_cipher) {
+		case WPA_CIPHER_NONE:
+			padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+			break;
+		case WPA_CIPHER_WEP40:
+			padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+			break;
+		case WPA_CIPHER_TKIP:
+			padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+			break;
+		case WPA_CIPHER_CCMP:
+			padapter->securitypriv.dot11PrivacyAlgrthm = _AES_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+			break;
+		case WPA_CIPHER_WEP104:
+			padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+			break;
+		}
+
+		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+		{/* set wps_ie */
+			u16 cnt = 0;
+			u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+			while (cnt < ielen) {
+				eid = buf[cnt];
+				if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt+2], wps_oui, 4))) {
+					DBG_88E("SET WPS_IE\n");
+
+					padapter->securitypriv.wps_ie_len = ((buf[cnt+1]+2) < (MAX_WPA_IE_LEN<<2)) ? (buf[cnt+1]+2) : (MAX_WPA_IE_LEN<<2);
+
+					memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len);
+
+					set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
+#ifdef CONFIG_88EU_P2P
+					if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK))
+						rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_ING);
+#endif /* CONFIG_88EU_P2P */
+					cnt += buf[cnt+1]+2;
+					break;
+				} else {
+					cnt += buf[cnt+1]+2; /* goto next */
+				}
+			}
+		}
+	}
+
+	RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+		 ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->securitypriv.ndisencryptstatus =%d padapter->securitypriv.ndisauthtype =%d\n",
+		 pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype));
+exit:
+	kfree(buf);
+	return ret;
+}
+
+typedef unsigned char   NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];
+
+static int rtw_wx_get_name(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u32 ht_ielen = 0;
+	char *p;
+	u8 ht_cap = false;
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
+	NDIS_802_11_RATES_EX *prates = NULL;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd));
+
+	_func_enter_;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) {
+		/* parsing HT_CAP_IE */
+		p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12);
+		if (p && ht_ielen > 0)
+			ht_cap = true;
+
+		prates = &pcur_bss->SupportedRates;
+
+		if (rtw_is_cckratesonly_included((u8 *)prates) == true) {
+			if (ht_cap)
+				snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn");
+			else
+				snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
+		} else if ((rtw_is_cckrates_included((u8 *)prates)) == true) {
+			if (ht_cap)
+				snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn");
+			else
+				snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg");
+		} else {
+			if (pcur_bss->Configuration.DSConfig > 14) {
+				if (ht_cap)
+					snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an");
+				else
+					snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a");
+			} else {
+				if (ht_cap)
+					snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn");
+				else
+					snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g");
+			}
+		}
+	} else {
+		snprintf(wrqu->name, IFNAMSIZ, "unassociated");
+	}
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_set_freq(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_wx_set_freq\n"));
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_get_freq(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+		/* wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000; */
+		wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000;
+		wrqu->freq.e = 1;
+		wrqu->freq.i = pcur_bss->Configuration.DSConfig;
+	} else {
+		wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000;
+		wrqu->freq.e = 1;
+		wrqu->freq.i = padapter->mlmeextpriv.cur_channel;
+	}
+
+	return 0;
+}
+
+static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
+			     union iwreq_data *wrqu, char *b)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	enum ndis_802_11_network_infra networkType;
+	int ret = 0;
+
+	_func_enter_;
+
+	if (_FAIL == rtw_pwr_wakeup(padapter)) {
+		ret = -EPERM;
+		goto exit;
+	}
+
+	if (!padapter->hw_init_completed) {
+		ret = -EPERM;
+		goto exit;
+	}
+
+	switch (wrqu->mode) {
+	case IW_MODE_AUTO:
+		networkType = Ndis802_11AutoUnknown;
+		DBG_88E("set_mode = IW_MODE_AUTO\n");
+		break;
+	case IW_MODE_ADHOC:
+		networkType = Ndis802_11IBSS;
+		DBG_88E("set_mode = IW_MODE_ADHOC\n");
+		break;
+	case IW_MODE_MASTER:
+		networkType = Ndis802_11APMode;
+		DBG_88E("set_mode = IW_MODE_MASTER\n");
+		break;
+	case IW_MODE_INFRA:
+		networkType = Ndis802_11Infrastructure;
+		DBG_88E("set_mode = IW_MODE_INFRA\n");
+		break;
+	default:
+		ret = -EINVAL;
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported\n", iw_operation_mode[wrqu->mode]));
+		goto exit;
+	}
+	if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) {
+		ret = -EPERM;
+		goto exit;
+	}
+	rtw_setopmode_cmd(padapter, networkType);
+exit:
+	_func_exit_;
+	return ret;
+}
+
+static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
+			     union iwreq_data *wrqu, char *b)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_get_mode\n"));
+
+	_func_enter_;
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+		wrqu->mode = IW_MODE_INFRA;
+	else if  ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ||
+		  (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
+		wrqu->mode = IW_MODE_ADHOC;
+	else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+		wrqu->mode = IW_MODE_MASTER;
+	else
+		wrqu->mode = IW_MODE_AUTO;
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_set_pmkid(struct net_device *dev,
+			    struct iw_request_info *a,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8   j, blInserted = false;
+	int  ret = false;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct iw_pmksa *pPMK = (struct iw_pmksa *)extra;
+	u8     strZeroMacAddress[ETH_ALEN] = {0x00};
+	u8     strIssueBssid[ETH_ALEN] = {0x00};
+
+	memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
+	if (pPMK->cmd == IW_PMKSA_ADD) {
+		DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n");
+		if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN) == true)
+			return ret;
+		else
+			ret = true;
+		blInserted = false;
+
+		/* overwrite PMKID */
+		for (j = 0; j < NUM_PMKID_CACHE; j++) {
+			if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
+				/*  BSSID is matched, the same AP => rewrite with new PMKID. */
+				DBG_88E("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n");
+				memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+				psecuritypriv->PMKIDList[j].bUsed = true;
+				psecuritypriv->PMKIDIndex = j+1;
+				blInserted = true;
+				break;
+			}
+		}
+
+		if (!blInserted) {
+			/*  Find a new entry */
+			DBG_88E("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n",
+				psecuritypriv->PMKIDIndex);
+
+			memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
+			memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+
+			psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true;
+			psecuritypriv->PMKIDIndex++;
+			if (psecuritypriv->PMKIDIndex == 16)
+				psecuritypriv->PMKIDIndex = 0;
+		}
+	} else if (pPMK->cmd == IW_PMKSA_REMOVE) {
+		DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n");
+		ret = true;
+		for (j = 0; j < NUM_PMKID_CACHE; j++) {
+			if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
+				/*  BSSID is matched, the same AP => Remove this PMKID information and reset it. */
+				_rtw_memset(psecuritypriv->PMKIDList[j].Bssid, 0x00, ETH_ALEN);
+				psecuritypriv->PMKIDList[j].bUsed = false;
+				break;
+			}
+	       }
+	} else if (pPMK->cmd == IW_PMKSA_FLUSH) {
+		DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n");
+		_rtw_memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+		psecuritypriv->PMKIDIndex = 0;
+		ret = true;
+	}
+	return ret;
+}
+
+static int rtw_wx_get_sens(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	wrqu->sens.value = 0;
+	wrqu->sens.fixed = 0;	/* no auto select */
+	wrqu->sens.disabled = 1;
+	return 0;
+}
+
+static int rtw_wx_get_range(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+	struct iw_range *range = (struct iw_range *)extra;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+
+	u16 val;
+	int i;
+
+	_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_range. cmd_code =%x\n", info->cmd));
+
+	wrqu->data.length = sizeof(*range);
+	_rtw_memset(range, 0, sizeof(*range));
+
+	/* Let's try to keep this struct in the same order as in
+	 * linux/include/wireless.h
+	 */
+
+	/* TODO: See what values we can set, and remove the ones we can't
+	 * set, or fill them with some default data.
+	 */
+
+	/* ~5 Mb/s real (802.11b) */
+	range->throughput = 5 * 1000 * 1000;
+
+	/* signal level threshold range */
+
+	/* percent values between 0 and 100. */
+	range->max_qual.qual = 100;
+	range->max_qual.level = 100;
+	range->max_qual.noise = 100;
+	range->max_qual.updated = 7; /* Updated all three */
+
+	range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
+	/* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+	range->avg_qual.level = 20 + -98;
+	range->avg_qual.noise = 0;
+	range->avg_qual.updated = 7; /* Updated all three */
+
+	range->num_bitrates = RATE_COUNT;
+
+	for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
+		range->bitrate[i] = rtw_rates[i];
+
+	range->min_frag = MIN_FRAG_THRESHOLD;
+	range->max_frag = MAX_FRAG_THRESHOLD;
+
+	range->pm_capa = 0;
+
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 16;
+
+	for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) {
+		/*  Include only legal frequencies for some countries */
+		if (pmlmeext->channel_set[i].ChannelNum != 0) {
+			range->freq[val].i = pmlmeext->channel_set[i].ChannelNum;
+			range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000;
+			range->freq[val].e = 1;
+			val++;
+		}
+
+		if (val == IW_MAX_FREQUENCIES)
+			break;
+	}
+
+	range->num_channels = val;
+	range->num_frequency = val;
+
+/*  The following code will proivde the security capability to network manager. */
+/*  If the driver doesn't provide this capability to network manager, */
+/*  the WPA/WPA2 routers can't be choosen in the network manager. */
+
+/*
+#define IW_SCAN_CAPA_NONE		0x00
+#define IW_SCAN_CAPA_ESSID		0x01
+#define IW_SCAN_CAPA_BSSID		0x02
+#define IW_SCAN_CAPA_CHANNEL		0x04
+#define IW_SCAN_CAPA_MODE		0x08
+#define IW_SCAN_CAPA_RATE		0x10
+#define IW_SCAN_CAPA_TYPE		0x20
+#define IW_SCAN_CAPA_TIME		0x40
+*/
+
+	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+	range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE |
+			   IW_SCAN_CAPA_BSSID | IW_SCAN_CAPA_CHANNEL |
+			   IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE;
+	_func_exit_;
+
+	return 0;
+}
+
+/* set bssid flow */
+/* s1. rtw_set_802_11_infrastructure_mode() */
+/* s2. rtw_set_802_11_authentication_mode() */
+/* s3. set_802_11_encryption_mode() */
+/* s4. rtw_set_802_11_bssid() */
+static int rtw_wx_set_wap(struct net_device *dev,
+			 struct iw_request_info *info,
+			 union iwreq_data *awrq,
+			 char *extra)
+{
+	unsigned long	irqL;
+	uint ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct sockaddr *temp = (struct sockaddr *)awrq;
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct list_head *phead;
+	u8 *dst_bssid, *src_bssid;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	enum ndis_802_11_auth_mode	authmode;
+
+	_func_enter_;
+
+	if (_FAIL == rtw_pwr_wakeup(padapter)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (!padapter->bup) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (temp->sa_family != ARPHRD_ETHER) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	authmode = padapter->securitypriv.ndisauthtype;
+	_enter_critical_bh(&queue->lock, &irqL);
+	phead = get_list_head(queue);
+	pmlmepriv->pscanned = get_next(phead);
+
+	while (1) {
+		if ((rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+
+		pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+		dst_bssid = pnetwork->network.MacAddress;
+
+		src_bssid = temp->sa_data;
+
+		if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) {
+			if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) {
+				ret = -1;
+				_exit_critical_bh(&queue->lock, &irqL);
+				goto exit;
+			}
+
+				break;
+		}
+	}
+	_exit_critical_bh(&queue->lock, &irqL);
+
+	rtw_set_802_11_authentication_mode(padapter, authmode);
+	/* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */
+	if (rtw_set_802_11_bssid(padapter, temp->sa_data) == false) {
+		ret = -1;
+		goto exit;
+	}
+
+exit:
+
+	_func_exit_;
+
+	return ret;
+}
+
+static int rtw_wx_get_wap(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
+
+	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+
+	_rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n"));
+
+	_func_enter_;
+
+	if (((check_fwstate(pmlmepriv, _FW_LINKED)) == true) ||
+	    ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true) ||
+	    ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true))
+		memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN);
+	else
+		_rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_set_mlme(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	u16 reason;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_mlme *mlme = (struct iw_mlme *)extra;
+
+	if (mlme == NULL)
+		return -1;
+
+	DBG_88E("%s\n", __func__);
+
+	reason = mlme->reason_code;
+
+	DBG_88E("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason);
+
+	switch (mlme->cmd) {
+	case IW_MLME_DEAUTH:
+		if (!rtw_set_802_11_disassociate(padapter))
+			ret = -1;
+		break;
+	case IW_MLME_DISASSOC:
+		if (!rtw_set_802_11_disassociate(padapter))
+			ret = -1;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
+			     union iwreq_data *wrqu, char *extra)
+{
+	u8 _status = false;
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+	unsigned long	irqL;
+#ifdef CONFIG_88EU_P2P
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_88EU_P2P */
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_set_scan\n"));
+
+_func_enter_;
+	if (padapter->registrypriv.mp_mode == 1) {
+		if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+			ret = -1;
+			goto exit;
+		}
+	}
+	if (_FAIL == rtw_pwr_wakeup(padapter)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (padapter->bDriverStopped) {
+		DBG_88E("bDriverStopped =%d\n", padapter->bDriverStopped);
+		ret = -1;
+		goto exit;
+	}
+
+	if (!padapter->bup) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (!padapter->hw_init_completed) {
+		ret = -1;
+		goto exit;
+	}
+
+	/*  When Busy Traffic, driver do not site survey. So driver return success. */
+	/*  wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */
+	/*  modify by thomas 2011-02-22. */
+	if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+		indicate_wx_scan_complete_event(padapter);
+		goto exit;
+	}
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) {
+		indicate_wx_scan_complete_event(padapter);
+		goto exit;
+	}
+
+/*	For the DMP WiFi Display project, the driver won't to scan because */
+/*	the pmlmepriv->scan_interval is always equal to 3. */
+/*	So, the wpa_supplicant won't find out the WPS SoftAP. */
+
+#ifdef CONFIG_88EU_P2P
+	if (pwdinfo->p2p_state != P2P_STATE_NONE) {
+		rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+		rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_FULL);
+		rtw_free_network_queue(padapter, true);
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	_rtw_memset(ssid, 0, sizeof(struct ndis_802_11_ssid)*RTW_SSID_SCAN_AMOUNT);
+
+	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+		struct iw_scan_req *req = (struct iw_scan_req *)extra;
+
+		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+			int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE);
+
+			memcpy(ssid[0].Ssid, req->essid, len);
+			ssid[0].SsidLength = len;
+
+			DBG_88E("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len);
+
+			_enter_critical_bh(&pmlmepriv->lock, &irqL);
+
+			_status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0);
+
+			_exit_critical_bh(&pmlmepriv->lock, &irqL);
+		} else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
+			DBG_88E("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n");
+		}
+	} else {
+		if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE &&
+		    !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) {
+			int len = wrqu->data.length - WEXT_CSCAN_HEADER_SIZE;
+			char *pos = extra+WEXT_CSCAN_HEADER_SIZE;
+			char section;
+			char sec_len;
+			int ssid_index = 0;
+
+			while (len >= 1) {
+				section = *(pos++);
+				len -= 1;
+
+				switch (section) {
+				case WEXT_CSCAN_SSID_SECTION:
+					if (len < 1) {
+						len = 0;
+						break;
+					}
+					sec_len = *(pos++); len -= 1;
+					if (sec_len > 0 && sec_len <= len) {
+						ssid[ssid_index].SsidLength = sec_len;
+						memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength);
+						ssid_index++;
+					}
+					pos += sec_len;
+					len -= sec_len;
+					break;
+				case WEXT_CSCAN_TYPE_SECTION:
+				case WEXT_CSCAN_CHANNEL_SECTION:
+					pos += 1;
+					len -= 1;
+					break;
+				case WEXT_CSCAN_PASV_DWELL_SECTION:
+				case WEXT_CSCAN_HOME_DWELL_SECTION:
+				case WEXT_CSCAN_ACTV_DWELL_SECTION:
+					pos += 2;
+					len -= 2;
+					break;
+				default:
+					len = 0; /*  stop parsing */
+				}
+			}
+
+			/* it has still some scan paramater to parse, we only do this now... */
+			_status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT);
+		} else {
+			_status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0);
+		}
+	}
+
+	if (!_status)
+		ret = -1;
+
+exit:
+
+_func_exit_;
+	return ret;
+}
+
+static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
+			     union iwreq_data *wrqu, char *extra)
+{
+	unsigned long	irqL;
+	struct list_head *plist, *phead;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	char *ev = extra;
+	char *stop = ev + wrqu->data.length;
+	u32 ret = 0;
+	u32 cnt = 0;
+	u32 wait_for_surveydone;
+	int wait_status;
+#ifdef CONFIG_88EU_P2P
+	struct	wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_88EU_P2P */
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan\n"));
+	RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n"));
+
+	_func_enter_;
+
+	if (padapter->pwrctrlpriv.brfoffbyhw && padapter->bDriverStopped) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+#ifdef CONFIG_88EU_P2P
+	if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+		/*	P2P is enabled */
+		wait_for_surveydone = 200;
+	} else {
+		/*	P2P is disabled */
+		wait_for_surveydone = 100;
+	}
+#else
+	{
+		wait_for_surveydone = 100;
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	wait_status = _FW_UNDER_SURVEY | _FW_UNDER_LINKING;
+
+	while (check_fwstate(pmlmepriv, wait_status)) {
+		rtw_msleep_os(30);
+		cnt++;
+		if (cnt > wait_for_surveydone)
+			break;
+	}
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist))
+			break;
+
+		if ((stop - ev) < SCAN_ITEM_SIZE) {
+			ret = -E2BIG;
+			break;
+		}
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		/* report network only if the current channel set contains the channel to which this network belongs */
+		if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0)
+			ev = translate_scan(padapter, a, pnetwork, ev, stop);
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	wrqu->data.length = ev-extra;
+	wrqu->data.flags = 0;
+
+exit:
+	_func_exit_;
+	return ret;
+}
+
+/* set ssid flow */
+/* s1. rtw_set_802_11_infrastructure_mode() */
+/* s2. set_802_11_authenticaion_mode() */
+/* s3. set_802_11_encryption_mode() */
+/* s4. rtw_set_802_11_ssid() */
+static int rtw_wx_set_essid(struct net_device *dev,
+			      struct iw_request_info *a,
+			      union iwreq_data *wrqu, char *extra)
+{
+	unsigned long irqL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct __queue *queue = &pmlmepriv->scanned_queue;
+	struct list_head *phead;
+	struct wlan_network *pnetwork = NULL;
+	enum ndis_802_11_auth_mode authmode;
+	struct ndis_802_11_ssid ndis_ssid;
+	u8 *dst_ssid, *src_ssid;
+
+	uint ret = 0, len;
+
+	_func_enter_;
+
+	RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+		 ("+rtw_wx_set_essid: fw_state = 0x%08x\n", get_fwstate(pmlmepriv)));
+	if (_FAIL == rtw_pwr_wakeup(padapter)) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (!padapter->bup) {
+		ret = -1;
+		goto exit;
+	}
+
+	if (wrqu->essid.length > IW_ESSID_MAX_SIZE) {
+		ret = -E2BIG;
+		goto exit;
+	}
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		ret = -1;
+		goto exit;
+	}
+
+	authmode = padapter->securitypriv.ndisauthtype;
+	DBG_88E("=>%s\n", __func__);
+	if (wrqu->essid.flags && wrqu->essid.length) {
+		len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE;
+
+		if (wrqu->essid.length != 33)
+			DBG_88E("ssid =%s, len =%d\n", extra, wrqu->essid.length);
+
+		_rtw_memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid));
+		ndis_ssid.SsidLength = len;
+		memcpy(ndis_ssid.Ssid, extra, len);
+		src_ssid = ndis_ssid.Ssid;
+
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("rtw_wx_set_essid: ssid =[%s]\n", src_ssid));
+		_enter_critical_bh(&queue->lock, &irqL);
+	       phead = get_list_head(queue);
+	      pmlmepriv->pscanned = get_next(phead);
+
+		while (1) {
+			if (rtw_end_of_queue_search(phead, pmlmepriv->pscanned) == true) {
+				RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_warning_,
+					 ("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n"));
+
+				break;
+			}
+
+			pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+
+			pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+			dst_ssid = pnetwork->network.Ssid.Ssid;
+
+			RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+				 ("rtw_wx_set_essid: dst_ssid =%s\n",
+				  pnetwork->network.Ssid.Ssid));
+
+			if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) &&
+			    (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) {
+				RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+					 ("rtw_wx_set_essid: find match, set infra mode\n"));
+
+				if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+					if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
+						continue;
+				}
+
+				if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) {
+					ret = -1;
+					_exit_critical_bh(&queue->lock, &irqL);
+					goto exit;
+				}
+
+				break;
+			}
+		}
+		_exit_critical_bh(&queue->lock, &irqL);
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+			 ("set ssid: set_802_11_auth. mode =%d\n", authmode));
+		rtw_set_802_11_authentication_mode(padapter, authmode);
+		if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) {
+			ret = -1;
+			goto exit;
+		}
+	}
+
+exit:
+
+	DBG_88E("<=%s, ret %d\n", __func__, ret);
+
+	_func_exit_;
+
+	return ret;
+}
+
+static int rtw_wx_get_essid(struct net_device *dev,
+			      struct iw_request_info *a,
+			      union iwreq_data *wrqu, char *extra)
+{
+	u32 len, ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_essid\n"));
+
+	_func_enter_;
+
+	if ((check_fwstate(pmlmepriv, _FW_LINKED)) ||
+	    (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) {
+		len = pcur_bss->Ssid.SsidLength;
+
+		wrqu->essid.length = len;
+
+		memcpy(extra, pcur_bss->Ssid.Ssid, len);
+
+		wrqu->essid.flags = 1;
+	} else {
+		ret = -1;
+		goto exit;
+	}
+
+exit:
+
+	_func_exit_;
+
+	return ret;
+}
+
+static int rtw_wx_set_rate(struct net_device *dev,
+			      struct iw_request_info *a,
+			      union iwreq_data *wrqu, char *extra)
+{
+	int i, ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8 datarates[NumRates];
+	u32	target_rate = wrqu->bitrate.value;
+	u32	fixed = wrqu->bitrate.fixed;
+	u32	ratevalue = 0;
+	 u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n"));
+	RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed));
+
+	if (target_rate == -1) {
+		ratevalue = 11;
+		goto set_rate;
+	}
+	target_rate = target_rate/100000;
+
+	switch (target_rate) {
+	case 10:
+		ratevalue = 0;
+		break;
+	case 20:
+		ratevalue = 1;
+		break;
+	case 55:
+		ratevalue = 2;
+		break;
+	case 60:
+		ratevalue = 3;
+		break;
+	case 90:
+		ratevalue = 4;
+		break;
+	case 110:
+		ratevalue = 5;
+		break;
+	case 120:
+		ratevalue = 6;
+		break;
+	case 180:
+		ratevalue = 7;
+		break;
+	case 240:
+		ratevalue = 8;
+		break;
+	case 360:
+		ratevalue = 9;
+		break;
+	case 480:
+		ratevalue = 10;
+		break;
+	case 540:
+		ratevalue = 11;
+		break;
+	default:
+		ratevalue = 11;
+		break;
+	}
+
+set_rate:
+
+	for (i = 0; i < NumRates; i++) {
+		if (ratevalue == mpdatarate[i]) {
+			datarates[i] = mpdatarate[i];
+			if (fixed == 0)
+				break;
+		} else {
+			datarates[i] = 0xff;
+		}
+
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("datarate_inx =%d\n", datarates[i]));
+	}
+
+	if (rtw_setdatarate_cmd(padapter, datarates) != _SUCCESS) {
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("rtw_wx_set_rate Fail!!!\n"));
+		ret = -1;
+	}
+
+_func_exit_;
+
+	return ret;
+}
+
+static int rtw_wx_get_rate(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	u16 max_rate = 0;
+
+	max_rate = rtw_get_cur_max_rate((struct adapter *)rtw_netdev_priv(dev));
+
+	if (max_rate == 0)
+		return -EPERM;
+
+	wrqu->bitrate.fixed = 0;	/* no auto select */
+	wrqu->bitrate.value = max_rate * 100000;
+
+	return 0;
+}
+
+static int rtw_wx_set_rts(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	_func_enter_;
+
+	if (wrqu->rts.disabled) {
+		padapter->registrypriv.rts_thresh = 2347;
+	} else {
+		if (wrqu->rts.value < 0 ||
+		    wrqu->rts.value > 2347)
+			return -EINVAL;
+
+		padapter->registrypriv.rts_thresh = wrqu->rts.value;
+	}
+
+	DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_get_rts(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	_func_enter_;
+
+	DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh);
+
+	wrqu->rts.value = padapter->registrypriv.rts_thresh;
+	wrqu->rts.fixed = 0;	/* no auto select */
+	/* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_set_frag(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	_func_enter_;
+
+	if (wrqu->frag.disabled) {
+		padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
+	} else {
+		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+		    wrqu->frag.value > MAX_FRAG_THRESHOLD)
+			return -EINVAL;
+
+		padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
+	}
+
+	DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_get_frag(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	_func_enter_;
+
+	DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len);
+
+	wrqu->frag.value = padapter->xmitpriv.frag_len;
+	wrqu->frag.fixed = 0;	/* no auto select */
+
+	_func_exit_;
+
+	return 0;
+}
+
+static int rtw_wx_get_retry(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	wrqu->retry.value = 7;
+	wrqu->retry.fixed = 0;	/* no auto select */
+	wrqu->retry.disabled = 1;
+
+	return 0;
+}
+
+static int rtw_wx_set_enc(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *keybuf)
+{
+	u32 key, ret = 0;
+	u32 keyindex_provided;
+	struct ndis_802_11_wep	 wep;
+	enum ndis_802_11_auth_mode authmode;
+
+	struct iw_point *erq = &(wrqu->encoding);
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	DBG_88E("+rtw_wx_set_enc, flags = 0x%x\n", erq->flags);
+
+	_rtw_memset(&wep, 0, sizeof(struct ndis_802_11_wep));
+
+	key = erq->flags & IW_ENCODE_INDEX;
+
+	_func_enter_;
+
+	if (erq->flags & IW_ENCODE_DISABLED) {
+		DBG_88E("EncryptionDisabled\n");
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+		padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+		padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+		authmode = Ndis802_11AuthModeOpen;
+		padapter->securitypriv.ndisauthtype = authmode;
+
+		goto exit;
+	}
+
+	if (key) {
+		if (key > WEP_KEYS)
+			return -EINVAL;
+		key--;
+		keyindex_provided = 1;
+	} else {
+		keyindex_provided = 0;
+		key = padapter->securitypriv.dot11PrivacyKeyIndex;
+		DBG_88E("rtw_wx_set_enc, key =%d\n", key);
+	}
+
+	/* set authentication mode */
+	if (erq->flags & IW_ENCODE_OPEN) {
+		DBG_88E("rtw_wx_set_enc():IW_ENCODE_OPEN\n");
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+		padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+		padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+		authmode = Ndis802_11AuthModeOpen;
+		padapter->securitypriv.ndisauthtype = authmode;
+	} else if (erq->flags & IW_ENCODE_RESTRICTED) {
+		DBG_88E("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n");
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+		padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+		padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+		authmode = Ndis802_11AuthModeShared;
+		padapter->securitypriv.ndisauthtype = authmode;
+	} else {
+		DBG_88E("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags);
+
+		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+		padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+		padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+		authmode = Ndis802_11AuthModeOpen;
+		padapter->securitypriv.ndisauthtype = authmode;
+	}
+
+	wep.KeyIndex = key;
+	if (erq->length > 0) {
+		wep.KeyLength = erq->length <= 5 ? 5 : 13;
+
+		wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
+	} else {
+		wep.KeyLength = 0;
+
+		if (keyindex_provided == 1) {
+			/*  set key_id only, no given KeyMaterial(erq->length == 0). */
+			padapter->securitypriv.dot11PrivacyKeyIndex = key;
+
+			DBG_88E("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]);
+
+			switch (padapter->securitypriv.dot11DefKeylen[key]) {
+			case 5:
+				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+				break;
+			case 13:
+				padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+				break;
+			default:
+				padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+				break;
+			}
+
+			goto exit;
+		}
+	}
+
+	wep.KeyIndex |= 0x80000000;
+
+	memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
+
+	if (rtw_set_802_11_add_wep(padapter, &wep) == false) {
+		if (rf_on == pwrpriv->rf_pwrstate)
+			ret = -EOPNOTSUPP;
+		goto exit;
+	}
+
+exit:
+
+	_func_exit_;
+
+	return ret;
+}
+
+static int rtw_wx_get_enc(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *keybuf)
+{
+	uint key, ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_point *erq = &(wrqu->encoding);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+
+	_func_enter_;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED) != true) {
+		if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) {
+			erq->length = 0;
+			erq->flags |= IW_ENCODE_DISABLED;
+			return 0;
+		}
+	}
+
+	key = erq->flags & IW_ENCODE_INDEX;
+
+	if (key) {
+		if (key > WEP_KEYS)
+			return -EINVAL;
+		key--;
+	} else {
+		key = padapter->securitypriv.dot11PrivacyKeyIndex;
+	}
+
+	erq->flags = key + 1;
+
+	switch (padapter->securitypriv.ndisencryptstatus) {
+	case Ndis802_11EncryptionNotSupported:
+	case Ndis802_11EncryptionDisabled:
+		erq->length = 0;
+		erq->flags |= IW_ENCODE_DISABLED;
+		break;
+	case Ndis802_11Encryption1Enabled:
+		erq->length = padapter->securitypriv.dot11DefKeylen[key];
+		if (erq->length) {
+			memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]);
+
+			erq->flags |= IW_ENCODE_ENABLED;
+
+			if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen)
+				erq->flags |= IW_ENCODE_OPEN;
+			else if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared)
+				erq->flags |= IW_ENCODE_RESTRICTED;
+		} else {
+			erq->length = 0;
+			erq->flags |= IW_ENCODE_DISABLED;
+		}
+		break;
+	case Ndis802_11Encryption2Enabled:
+	case Ndis802_11Encryption3Enabled:
+		erq->length = 16;
+		erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | IW_ENCODE_NOKEY);
+		break;
+	default:
+		erq->length = 0;
+		erq->flags |= IW_ENCODE_DISABLED;
+		break;
+	}
+	_func_exit_;
+
+	return ret;
+}
+
+static int rtw_wx_get_power(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	wrqu->power.value = 0;
+	wrqu->power.fixed = 0;	/* no auto select */
+	wrqu->power.disabled = 1;
+
+	return 0;
+}
+
+static int rtw_wx_set_gen_ie(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	int ret;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	ret = rtw_set_wpa_ie(padapter, extra, wrqu->data.length);
+	return ret;
+}
+
+static int rtw_wx_set_auth(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_param *param = (struct iw_param *)&(wrqu->param);
+	int ret = 0;
+
+	switch (param->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+		break;
+	case IW_AUTH_CIPHER_PAIRWISE:
+
+		break;
+	case IW_AUTH_CIPHER_GROUP:
+
+		break;
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 *  ??? does not use these parameters
+		 */
+		break;
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+		if (param->value) {
+			/*  wpa_supplicant is enabling the tkip countermeasure. */
+			padapter->securitypriv.btkip_countermeasure = true;
+		} else {
+			/*  wpa_supplicant is disabling the tkip countermeasure. */
+			padapter->securitypriv.btkip_countermeasure = false;
+		}
+		break;
+	case IW_AUTH_DROP_UNENCRYPTED:
+		/* HACK:
+		 *
+		 * wpa_supplicant calls set_wpa_enabled when the driver
+		 * is loaded and unloaded, regardless of if WPA is being
+		 * used.  No other calls are made which can be used to
+		 * determine if encryption will be used or not prior to
+		 * association being expected.  If encryption is not being
+		 * used, drop_unencrypted is set to false, else true -- we
+		 * can use this to determine if the CAP_PRIVACY_ON bit should
+		 * be set.
+		 */
+
+		if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled)
+			break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */
+					/*  then it needn't reset it; */
+
+		if (param->value) {
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+			padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+			padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+			padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+		}
+
+		break;
+	case IW_AUTH_80211_AUTH_ALG:
+		/*
+		 *  It's the starting point of a link layer connection using wpa_supplicant
+		*/
+		if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+			LeaveAllPowerSaveMode(padapter);
+			rtw_disassoc_cmd(padapter, 500, false);
+			DBG_88E("%s...call rtw_indicate_disconnect\n ", __func__);
+			rtw_indicate_disconnect(padapter);
+			rtw_free_assoc_resources(padapter, 1);
+		}
+		ret = wpa_set_auth_algs(dev, (u32)param->value);
+		break;
+	case IW_AUTH_WPA_ENABLED:
+		break;
+	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+		break;
+	case IW_AUTH_PRIVACY_INVOKED:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+static int rtw_wx_set_enc_ext(struct net_device *dev,
+			     struct iw_request_info *info,
+			     union iwreq_data *wrqu, char *extra)
+{
+	char *alg_name;
+	u32 param_len;
+	struct ieee_param *param = NULL;
+	struct iw_point *pencoding = &wrqu->encoding;
+	struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
+	int ret = 0;
+
+	param_len = sizeof(struct ieee_param) + pext->key_len;
+	param = (struct ieee_param *)rtw_malloc(param_len);
+	if (param == NULL)
+		return -1;
+
+	_rtw_memset(param, 0, param_len);
+
+	param->cmd = IEEE_CMD_SET_ENCRYPTION;
+	_rtw_memset(param->sta_addr, 0xff, ETH_ALEN);
+
+	switch (pext->alg) {
+	case IW_ENCODE_ALG_NONE:
+		/* todo: remove key */
+		/* remove = 1; */
+		alg_name = "none";
+		break;
+	case IW_ENCODE_ALG_WEP:
+		alg_name = "WEP";
+		break;
+	case IW_ENCODE_ALG_TKIP:
+		alg_name = "TKIP";
+		break;
+	case IW_ENCODE_ALG_CCMP:
+		alg_name = "CCMP";
+		break;
+	default:
+		return -1;
+	}
+
+	strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+
+	if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+		param->u.crypt.set_tx = 1;
+
+	/* cliW: WEP does not have group key
+	 * just not checking GROUP key setting
+	 */
+	if ((pext->alg != IW_ENCODE_ALG_WEP) &&
+	    (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY))
+		param->u.crypt.set_tx = 0;
+
+	param->u.crypt.idx = (pencoding->flags&0x00FF) - 1;
+
+	if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+		memcpy(param->u.crypt.seq, pext->rx_seq, 8);
+
+	if (pext->key_len) {
+		param->u.crypt.key_len = pext->key_len;
+		memcpy(param->u.crypt.key, pext + 1, pext->key_len);
+	}
+
+	ret =  wpa_set_encryption(dev, param, param_len);
+
+	kfree(param);
+	return ret;
+}
+
+static int rtw_wx_get_nick(struct net_device *dev,
+			   struct iw_request_info *info,
+			   union iwreq_data *wrqu, char *extra)
+{
+	if (extra) {
+		wrqu->data.length = 14;
+		wrqu->data.flags = 1;
+		memcpy(extra, "<WIFI@REALTEK>", 14);
+	}
+
+	/* dump debug info here */
+	return 0;
+}
+
+static int rtw_wx_read32(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter;
+	struct iw_point *p;
+	u16 len;
+	u32 addr;
+	u32 data32;
+	u32 bytes;
+	u8 *ptmp;
+
+	padapter = (struct adapter *)rtw_netdev_priv(dev);
+	p = &wrqu->data;
+	len = p->length;
+	ptmp = (u8 *)rtw_malloc(len);
+	if (NULL == ptmp)
+		return -ENOMEM;
+
+	if (copy_from_user(ptmp, p->pointer, len)) {
+		kfree(ptmp);
+		return -EFAULT;
+	}
+
+	bytes = 0;
+	addr = 0;
+	sscanf(ptmp, "%d,%x", &bytes, &addr);
+
+	switch (bytes) {
+	case 1:
+		data32 = rtw_read8(padapter, addr);
+		sprintf(extra, "0x%02X", data32);
+		break;
+	case 2:
+		data32 = rtw_read16(padapter, addr);
+		sprintf(extra, "0x%04X", data32);
+		break;
+	case 4:
+		data32 = rtw_read32(padapter, addr);
+		sprintf(extra, "0x%08X", data32);
+		break;
+	default:
+		DBG_88E(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__);
+		return -EINVAL;
+	}
+	DBG_88E(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra);
+
+	kfree(ptmp);
+	return 0;
+}
+
+static int rtw_wx_write32(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	u32 addr;
+	u32 data32;
+	u32 bytes;
+
+	bytes = 0;
+	addr = 0;
+	data32 = 0;
+	sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
+
+	switch (bytes) {
+	case 1:
+		rtw_write8(padapter, addr, (u8)data32);
+		DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32);
+		break;
+	case 2:
+		rtw_write16(padapter, addr, (u16)data32);
+		DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32);
+		break;
+	case 4:
+		rtw_write32(padapter, addr, data32);
+		DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32);
+		break;
+	default:
+		DBG_88E(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rtw_wx_read_rf(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u32 path, addr, data32;
+
+	path = *(u32 *)extra;
+	addr = *((u32 *)extra + 1);
+	data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF);
+	/*
+	 * IMPORTANT!!
+	 * Only when wireless private ioctl is at odd order,
+	 * "extra" would be copied to user space.
+	 */
+	sprintf(extra, "0x%05x", data32);
+
+	return 0;
+}
+
+static int rtw_wx_write_rf(struct net_device *dev,
+			    struct iw_request_info *info,
+			    union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u32 path, addr, data32;
+
+	path = *(u32 *)extra;
+	addr = *((u32 *)extra + 1);
+	data32 = *((u32 *)extra + 2);
+	rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32);
+
+	return 0;
+}
+
+static int rtw_wx_priv_null(struct net_device *dev, struct iw_request_info *a,
+		 union iwreq_data *wrqu, char *b)
+{
+	return -1;
+}
+
+static int dummy(struct net_device *dev, struct iw_request_info *a,
+		 union iwreq_data *wrqu, char *b)
+{
+	return -1;
+}
+
+static int rtw_wx_set_channel_plan(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	u8 channel_plan_req = (u8) (*((int *)wrqu));
+
+	if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1))
+		DBG_88E("%s set channel_plan = 0x%02X\n", __func__, pmlmepriv->ChannelPlan);
+	else
+		return -EPERM;
+
+	return 0;
+}
+
+static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev,
+		struct iw_request_info *a,
+		union iwreq_data *wrqu, char *b)
+{
+	return 0;
+}
+
+static int rtw_wx_get_sensitivity(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *buf)
+{
+	return 0;
+}
+
+static int rtw_wx_set_mtk_wps_ie(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+	return 0;
+}
+
+/*
+ *	For all data larger than 16 octets, we need to use a
+ *	pointer to memory allocated in user space.
+ */
+static  int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info,
+						union iwreq_data *wrqu, char *extra)
+{
+	return 0;
+}
+
+static void rtw_dbg_mode_hdl(struct adapter *padapter, u32 id, u8 *pdata, u32 len)
+{
+	struct mp_rw_reg *RegRWStruct;
+	struct rf_reg_param *prfreg;
+	u8 path;
+	u8 offset;
+	u32 value;
+
+	DBG_88E("%s\n", __func__);
+
+	switch (id) {
+	case GEN_MP_IOCTL_SUBCODE(MP_START):
+		DBG_88E("871x_driver is only for normal mode, can't enter mp mode\n");
+		break;
+	case GEN_MP_IOCTL_SUBCODE(READ_REG):
+		RegRWStruct = (struct mp_rw_reg *)pdata;
+		switch (RegRWStruct->width) {
+		case 1:
+			RegRWStruct->value = rtw_read8(padapter, RegRWStruct->offset);
+			break;
+		case 2:
+			RegRWStruct->value = rtw_read16(padapter, RegRWStruct->offset);
+			break;
+		case 4:
+			RegRWStruct->value = rtw_read32(padapter, RegRWStruct->offset);
+			break;
+		default:
+			break;
+		}
+
+		break;
+	case GEN_MP_IOCTL_SUBCODE(WRITE_REG):
+		RegRWStruct = (struct mp_rw_reg *)pdata;
+		switch (RegRWStruct->width) {
+		case 1:
+			rtw_write8(padapter, RegRWStruct->offset, (u8)RegRWStruct->value);
+			break;
+		case 2:
+			rtw_write16(padapter, RegRWStruct->offset, (u16)RegRWStruct->value);
+			break;
+		case 4:
+			rtw_write32(padapter, RegRWStruct->offset, (u32)RegRWStruct->value);
+			break;
+		default:
+			break;
+		}
+
+		break;
+	case GEN_MP_IOCTL_SUBCODE(READ_RF_REG):
+
+		prfreg = (struct rf_reg_param *)pdata;
+
+		path = (u8)prfreg->path;
+		offset = (u8)prfreg->offset;
+
+		value = rtw_hal_read_rfreg(padapter, path, offset, 0xffffffff);
+
+		prfreg->value = value;
+
+		break;
+	case GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG):
+
+		prfreg = (struct rf_reg_param *)pdata;
+
+		path = (u8)prfreg->path;
+		offset = (u8)prfreg->offset;
+		value = prfreg->value;
+
+		rtw_hal_write_rfreg(padapter, path, offset, 0xffffffff, value);
+
+		break;
+	case GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO):
+		DBG_88E("==> trigger gpio 0\n");
+		rtw_hal_set_hwreg(padapter, HW_VAR_TRIGGER_GPIO_0, NULL);
+		break;
+	case GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS):
+		*pdata = rtw_hal_sreset_get_wifi_status(padapter);
+		break;
+	default:
+		break;
+	}
+}
+
+static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info,
+						union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	u32 BytesRead, BytesWritten, BytesNeeded;
+	struct oid_par_priv	oid_par;
+	struct mp_ioctl_handler	*phandler;
+	struct mp_ioctl_param	*poidparam;
+	uint status = 0;
+	u16 len;
+	u8 *pparmbuf = NULL, bset;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_point *p = &wrqu->data;
+
+	if ((!p->length) || (!p->pointer)) {
+		ret = -EINVAL;
+		goto _rtw_mp_ioctl_hdl_exit;
+	}
+	pparmbuf = NULL;
+	bset = (u8)(p->flags & 0xFFFF);
+	len = p->length;
+	pparmbuf = (u8 *)rtw_malloc(len);
+	if (pparmbuf == NULL) {
+		ret = -ENOMEM;
+		goto _rtw_mp_ioctl_hdl_exit;
+	}
+
+	if (copy_from_user(pparmbuf, p->pointer, len)) {
+		ret = -EFAULT;
+		goto _rtw_mp_ioctl_hdl_exit;
+	}
+
+	poidparam = (struct mp_ioctl_param *)pparmbuf;
+	RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+		 ("rtw_mp_ioctl_hdl: subcode [%d], len[%d], buffer_len[%d]\r\n",
+		  poidparam->subcode, poidparam->len, len));
+
+	if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("no matching drvext subcodes\r\n"));
+		ret = -EINVAL;
+		goto _rtw_mp_ioctl_hdl_exit;
+	}
+
+	if (padapter->registrypriv.mp_mode == 1) {
+		phandler = mp_ioctl_hdl + poidparam->subcode;
+
+		if ((phandler->paramsize != 0) && (poidparam->len < phandler->paramsize)) {
+			RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_,
+				 ("no matching drvext param size %d vs %d\r\n",
+				  poidparam->len, phandler->paramsize));
+			ret = -EINVAL;
+			goto _rtw_mp_ioctl_hdl_exit;
+		}
+
+		if (phandler->handler) {
+			oid_par.adapter_context = padapter;
+			oid_par.oid = phandler->oid;
+			oid_par.information_buf = poidparam->data;
+			oid_par.information_buf_len = poidparam->len;
+			oid_par.dbg = 0;
+
+			BytesWritten = 0;
+			BytesNeeded = 0;
+
+			if (bset) {
+				oid_par.bytes_rw = &BytesRead;
+				oid_par.bytes_needed = &BytesNeeded;
+				oid_par.type_of_oid = SET_OID;
+			} else {
+				oid_par.bytes_rw = &BytesWritten;
+				oid_par.bytes_needed = &BytesNeeded;
+				oid_par.type_of_oid = QUERY_OID;
+			}
+
+			status = phandler->handler(&oid_par);
+		} else {
+			DBG_88E("rtw_mp_ioctl_hdl(): err!, subcode =%d, oid =%d, handler =%p\n",
+				poidparam->subcode, phandler->oid, phandler->handler);
+			ret = -EFAULT;
+			goto _rtw_mp_ioctl_hdl_exit;
+		}
+	} else {
+		rtw_dbg_mode_hdl(padapter, poidparam->subcode, poidparam->data, poidparam->len);
+	}
+
+	if (bset == 0x00) {/* query info */
+		if (copy_to_user(p->pointer, pparmbuf, len))
+			ret = -EFAULT;
+	}
+
+	if (status) {
+		ret = -EFAULT;
+		goto _rtw_mp_ioctl_hdl_exit;
+	}
+
+_rtw_mp_ioctl_hdl_exit:
+
+	kfree(pparmbuf);
+	return ret;
+}
+
+static int rtw_get_ap_info(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	u32 cnt = 0, wpa_ielen;
+	unsigned long	irqL;
+	struct list_head *plist, *phead;
+	unsigned char *pbuf;
+	u8 bssid[ETH_ALEN];
+	char data[32];
+	struct wlan_network *pnetwork = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct __queue *queue = &(pmlmepriv->scanned_queue);
+	struct iw_point *pdata = &wrqu->data;
+
+	DBG_88E("+rtw_get_aplist_info\n");
+
+	if ((padapter->bDriverStopped) || (pdata == NULL)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)))) {
+		rtw_msleep_os(30);
+		cnt++;
+		if (cnt > 100)
+			break;
+	}
+	pdata->flags = 0;
+	if (pdata->length >= 32) {
+		if (copy_from_user(data, pdata->pointer, 32)) {
+			ret = -EINVAL;
+			goto exit;
+		}
+	} else {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		if (hwaddr_aton_i(data, bssid)) {
+			DBG_88E("Invalid BSSID '%s'.\n", (u8 *)data);
+			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+			return -EINVAL;
+		}
+
+		if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN) == true) {
+			/* BSSID match, then check if supporting wpa/wpa2 */
+			DBG_88E("BSSID:%pM\n", (bssid));
+
+			pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+			if (pbuf && (wpa_ielen > 0)) {
+				pdata->flags = 1;
+				break;
+			}
+
+			pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
+			if (pbuf && (wpa_ielen > 0)) {
+				pdata->flags = 2;
+				break;
+			}
+		}
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (pdata->length >= 34) {
+		if (copy_to_user(pdata->pointer+32, (u8 *)&pdata->flags, 1)) {
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+
+exit:
+
+	return ret;
+}
+
+static int rtw_set_pid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	int *pdata = (int *)wrqu;
+	int selector;
+
+	if ((padapter->bDriverStopped) || (pdata == NULL)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	selector = *pdata;
+	if (selector < 3 && selector >= 0) {
+		padapter->pid[selector] = *(pdata+1);
+		ui_pid[selector] = *(pdata+1);
+		DBG_88E("%s set pid[%d] =%d\n", __func__, selector, padapter->pid[selector]);
+	} else {
+		DBG_88E("%s selector %d error\n", __func__, selector);
+	}
+exit:
+	return ret;
+}
+
+static int rtw_wps_start(struct net_device *dev,
+			 struct iw_request_info *info,
+			 union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_point *pdata = &wrqu->data;
+	u32   u32wps_start = 0;
+
+	ret = copy_from_user((void *)&u32wps_start, pdata->pointer, 4);
+	if (ret) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if ((padapter->bDriverStopped) || (pdata == NULL)) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	if (u32wps_start == 0)
+		u32wps_start = *extra;
+
+	DBG_88E("[%s] wps_start = %d\n", __func__, u32wps_start);
+
+	if (u32wps_start == 1) /*  WPS Start */
+		rtw_led_control(padapter, LED_CTL_START_WPS);
+	else if (u32wps_start == 2) /*  WPS Stop because of wps success */
+		rtw_led_control(padapter, LED_CTL_STOP_WPS);
+	else if (u32wps_start == 3) /*  WPS Stop because of wps fail */
+		rtw_led_control(padapter, LED_CTL_STOP_WPS_FAIL);
+
+exit:
+	return ret;
+}
+
+#ifdef CONFIG_88EU_P2P
+static int rtw_wext_p2p_enable(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	enum P2P_ROLE init_role = P2P_ROLE_DISABLE;
+
+	if (*extra == '0')
+		init_role = P2P_ROLE_DISABLE;
+	else if (*extra == '1')
+		init_role = P2P_ROLE_DEVICE;
+	else if (*extra == '2')
+		init_role = P2P_ROLE_CLIENT;
+	else if (*extra == '3')
+		init_role = P2P_ROLE_GO;
+
+	if (_FAIL == rtw_p2p_enable(padapter, init_role)) {
+		ret = -EFAULT;
+		goto exit;
+	}
+
+	/* set channel/bandwidth */
+	if (init_role != P2P_ROLE_DISABLE) {
+		u8 channel, ch_offset;
+		u16 bwmode;
+
+		if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) {
+			/*	Stay at the listen state and wait for discovery. */
+			channel = pwdinfo->listen_channel;
+			pwdinfo->operating_channel = pwdinfo->listen_channel;
+			ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+			bwmode = HT_CHANNEL_WIDTH_20;
+		} else {
+			pwdinfo->operating_channel = pmlmeext->cur_channel;
+
+			channel = pwdinfo->operating_channel;
+			ch_offset = pmlmeext->cur_ch_offset;
+			bwmode = pmlmeext->cur_bwmode;
+		}
+
+		set_channel_bwmode(padapter, channel, ch_offset, bwmode);
+	}
+
+exit:
+	return ret;
+}
+
+static int rtw_p2p_set_go_nego_ssid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] ssid = %s, len = %zu\n", __func__, extra, strlen(extra));
+	memcpy(pwdinfo->nego_ssid, extra, strlen(extra));
+	pwdinfo->nego_ssidlen = strlen(extra);
+
+	return ret;
+}
+
+static int rtw_p2p_set_intent(struct net_device *dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	u8 intent = pwdinfo->intent;
+
+	switch (wrqu->data.length) {
+	case 1:
+		intent = extra[0] - '0';
+		break;
+	case 2:
+		intent = str_2char2num(extra[0], extra[1]);
+		break;
+	}
+	if (intent <= 15)
+		pwdinfo->intent = intent;
+	else
+		ret = -1;
+	DBG_88E("[%s] intent = %d\n", __func__, intent);
+	return ret;
+}
+
+static int rtw_p2p_set_listen_ch(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	u8 listen_ch = pwdinfo->listen_channel;	/*	Listen channel number */
+
+	switch (wrqu->data.length) {
+	case 1:
+		listen_ch = extra[0] - '0';
+		break;
+	case 2:
+		listen_ch = str_2char2num(extra[0], extra[1]);
+		break;
+	}
+
+	if ((listen_ch == 1) || (listen_ch == 6) || (listen_ch == 11)) {
+		pwdinfo->listen_channel = listen_ch;
+		set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+	} else {
+		ret = -1;
+	}
+
+	DBG_88E("[%s] listen_ch = %d\n", __func__, pwdinfo->listen_channel);
+
+	return ret;
+}
+
+static int rtw_p2p_set_op_ch(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+/*	Commented by Albert 20110524 */
+/*	This function is used to set the operating channel if the driver will become the group owner */
+
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	u8 op_ch = pwdinfo->operating_channel;	/*	Operating channel number */
+
+	switch (wrqu->data.length) {
+	case 1:
+		op_ch = extra[0] - '0';
+		break;
+	case 2:
+		op_ch = str_2char2num(extra[0], extra[1]);
+		break;
+	}
+
+	if (op_ch > 0)
+		pwdinfo->operating_channel = op_ch;
+	else
+		ret = -1;
+
+	DBG_88E("[%s] op_ch = %d\n", __func__, pwdinfo->operating_channel);
+
+	return ret;
+}
+
+static int rtw_p2p_profilefound(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	/*	Comment by Albert 2010/10/13 */
+	/*	Input data format: */
+	/*	Ex:  0 */
+	/*	Ex:  1XX:XX:XX:XX:XX:XXYYSSID */
+	/*	0 => Reflush the profile record list. */
+	/*	1 => Add the profile list */
+	/*	XX:XX:XX:XX:XX:XX => peer's MAC Address (ex: 00:E0:4C:00:00:01) */
+	/*	YY => SSID Length */
+	/*	SSID => SSID for persistence group */
+
+	DBG_88E("[%s] In value = %s, len = %d\n", __func__, extra, wrqu->data.length - 1);
+
+	/*	The upper application should pass the SSID to driver by using this rtw_p2p_profilefound function. */
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+			if (extra[0] == '0') {
+			/*	Remove all the profile information of wifidirect_info structure. */
+			_rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
+			pwdinfo->profileindex = 0;
+		} else {
+			if (pwdinfo->profileindex >= P2P_MAX_PERSISTENT_GROUP_NUM) {
+				ret = -1;
+			} else {
+				int jj, kk;
+
+				/*	Add this profile information into pwdinfo->profileinfo */
+				/*	Ex:  1XX:XX:XX:XX:XX:XXYYSSID */
+				for (jj = 0, kk = 1; jj < ETH_ALEN; jj++, kk += 3)
+					pwdinfo->profileinfo[pwdinfo->profileindex].peermac[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+				pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen = (extra[18] - '0') * 10 + (extra[19] - '0');
+				memcpy(pwdinfo->profileinfo[pwdinfo->profileindex].ssid, &extra[20], pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen);
+				pwdinfo->profileindex++;
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int rtw_p2p_setDN(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+	_rtw_memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
+	memcpy(pwdinfo->device_name, extra, wrqu->data.length - 1);
+	pwdinfo->device_name_len = wrqu->data.length - 1;
+
+	return ret;
+}
+
+static int rtw_p2p_get_status(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	if (padapter->bShowGetP2PState)
+		DBG_88E("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+			pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+			pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+
+	/*	Commented by Albert 2010/10/12 */
+	/*	Because of the output size limitation, I had removed the "Role" information. */
+	/*	About the "Role" information, we will use the new private IOCTL to get the "Role" information. */
+	sprintf(extra, "\n\nStatus =%.2d\n", rtw_p2p_state(pwdinfo));
+	wrqu->data.length = strlen(extra);
+
+	return ret;
+}
+
+/*	Commented by Albert 20110520 */
+/*	This function will return the config method description */
+/*	This config method description will show us which config method the remote P2P device is intented to use */
+/*	by sending the provisioning discovery request frame. */
+
+static int rtw_p2p_get_req_cm(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	sprintf(extra, "\n\nCM =%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req);
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_role(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+			pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+			pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+
+	sprintf(extra, "\n\nRole =%.2d\n", rtw_p2p_role(pwdinfo));
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_peer_ifaddr(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", __func__,
+		rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+		pwdinfo->p2p_peer_interface_addr);
+	sprintf(extra, "\nMAC %pM",
+		pwdinfo->p2p_peer_interface_addr);
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_peer_devaddr(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", __func__,
+		rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+		pwdinfo->rx_prov_disc_info.peerDevAddr);
+	sprintf(extra, "\n%pM",
+		pwdinfo->rx_prov_disc_info.peerDevAddr);
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_peer_devaddr_by_invitation(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n",
+		__func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+		pwdinfo->p2p_peer_device_addr);
+	sprintf(extra, "\nMAC %pM",
+		pwdinfo->p2p_peer_device_addr);
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_groupid(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	sprintf(extra, "\n%.2X:%.2X:%.2X:%.2X:%.2X:%.2X %s",
+		pwdinfo->groupid_info.go_device_addr[0], pwdinfo->groupid_info.go_device_addr[1],
+		pwdinfo->groupid_info.go_device_addr[2], pwdinfo->groupid_info.go_device_addr[3],
+		pwdinfo->groupid_info.go_device_addr[4], pwdinfo->groupid_info.go_device_addr[5],
+		pwdinfo->groupid_info.ssid);
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_op_ch(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] Op_ch = %02x\n", __func__, pwdinfo->operating_channel);
+
+	sprintf(extra, "\n\nOp_ch =%.2d\n", pwdinfo->operating_channel);
+	wrqu->data.length = strlen(extra);
+	return ret;
+}
+
+static int rtw_p2p_get_wps_configmethod(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	u8 peerMACStr[17] = {0x00};
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	unsigned long				irqL;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	u8 blnMatch = 0;
+	u16	attr_content = 0;
+	uint attr_contentlen = 0;
+	/* 6 is the string "wpsCM =", 17 is the MAC addr, we have to clear it at wrqu->data.pointer */
+	u8 attr_content_str[6 + 17] = {0x00};
+
+	/*	Commented by Albert 20110727 */
+	/*	The input data is the MAC address which the application wants to know its WPS config method. */
+	/*	After knowing its WPS config method, the application can decide the config method for provisioning discovery. */
+	/*	Format: iwpriv wlanx p2p_get_wpsCM 00:E0:4C:00:00:05 */
+
+	DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+	if (copy_from_user(peerMACStr, wrqu->data.pointer + 6, 17))
+		return -EFAULT;
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+			u8 *wpsie;
+			uint wpsie_len = 0;
+			__be16 be_tmp;
+
+			/*  The mac address is matched. */
+			wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsie_len);
+			if (wpsie) {
+				rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_CONF_METHOD, (u8 *) &be_tmp, &attr_contentlen);
+				if (attr_contentlen) {
+					attr_content = be16_to_cpu(be_tmp);
+					sprintf(attr_content_str, "\n\nM =%.4d", attr_content);
+					blnMatch = 1;
+				}
+			}
+			break;
+		}
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (!blnMatch)
+		sprintf(attr_content_str, "\n\nM = 0000");
+
+	if (copy_to_user(wrqu->data.pointer, attr_content_str, 6 + 17))
+		return -EFAULT;
+	return ret;
+}
+
+static int rtw_p2p_get_go_device_address(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	u8 peerMACStr[17] = {0x00};
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	unsigned long				irqL;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	u8 blnMatch = 0;
+	u8 *p2pie;
+	uint p2pielen = 0, attr_contentlen = 0;
+	u8 attr_content[100] = {0x00};
+
+	u8 go_devadd_str[17 + 10] = {0x00};
+	/*  +10 is for the str "go_devadd =", we have to clear it at wrqu->data.pointer */
+
+	/*	Commented by Albert 20121209 */
+	/*	The input data is the GO's interface address which the application wants to know its device address. */
+	/*	Format: iwpriv wlanx p2p_get2 go_devadd = 00:E0:4C:00:00:05 */
+
+	DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+	if (copy_from_user(peerMACStr, wrqu->data.pointer + 10, 17))
+		return -EFAULT;
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+			/*	Commented by Albert 2011/05/18 */
+			/*	Match the device address located in the P2P IE */
+			/*	This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+			p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+			if (p2pie) {
+				while (p2pie) {
+					/*	The P2P Device ID attribute is included in the Beacon frame. */
+					/*	The P2P Device Info attribute is included in the probe response frame. */
+
+					_rtw_memset(attr_content, 0x00, 100);
+					if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+						/*	Handle the P2P Device ID attribute of Beacon first */
+						blnMatch = 1;
+						break;
+					} else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+						/*	Handle the P2P Device Info attribute of probe response */
+						blnMatch = 1;
+						break;
+					}
+
+					/* Get the next P2P IE */
+					p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen);
+				}
+			}
+	     }
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (!blnMatch)
+		sprintf(go_devadd_str, "\n\ndev_add = NULL");
+	else
+		sprintf(go_devadd_str, "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+			attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]);
+
+	if (copy_to_user(wrqu->data.pointer, go_devadd_str, 10 + 17))
+		return -EFAULT;
+	return ret;
+}
+
+static int rtw_p2p_get_device_type(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	u8 peerMACStr[17] = {0x00};
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	unsigned long				irqL;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	u8 blnMatch = 0;
+	u8 dev_type[8] = {0x00};
+	uint dev_type_len = 0;
+	u8 dev_type_str[17 + 9] = {0x00};	/*  +9 is for the str "dev_type =", we have to clear it at wrqu->data.pointer */
+
+	/*	Commented by Albert 20121209 */
+	/*	The input data is the MAC address which the application wants to know its device type. */
+	/*	Such user interface could know the device type. */
+	/*	Format: iwpriv wlanx p2p_get2 dev_type = 00:E0:4C:00:00:05 */
+
+	DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+	if (copy_from_user(peerMACStr, wrqu->data.pointer + 9, 17))
+		return -EFAULT;
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+			u8 *wpsie;
+			uint wpsie_len = 0;
+
+		/*	The mac address is matched. */
+
+			wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12],
+					       pnetwork->network.IELength - 12,
+					       NULL, &wpsie_len);
+			if (wpsie) {
+				rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_PRIMARY_DEV_TYPE, dev_type, &dev_type_len);
+				if (dev_type_len) {
+					u16	type = 0;
+					__be16 be_tmp;
+
+					memcpy(&be_tmp, dev_type, 2);
+					type = be16_to_cpu(be_tmp);
+					sprintf(dev_type_str, "\n\nN =%.2d", type);
+					blnMatch = 1;
+				}
+			}
+			break;
+	     }
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (!blnMatch)
+		sprintf(dev_type_str, "\n\nN = 00");
+
+	if (copy_to_user(wrqu->data.pointer, dev_type_str, 9 + 17)) {
+		return -EFAULT;
+	}
+
+	return ret;
+}
+
+static int rtw_p2p_get_device_name(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	u8 peerMACStr[17] = {0x00};
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	unsigned long				irqL;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	u8 blnMatch = 0;
+	u8 dev_name[WPS_MAX_DEVICE_NAME_LEN] = {0x00};
+	uint dev_len = 0;
+	u8 dev_name_str[WPS_MAX_DEVICE_NAME_LEN + 5] = {0x00};	/*  +5 is for the str "devN =", we have to clear it at wrqu->data.pointer */
+
+	/*	Commented by Albert 20121225 */
+	/*	The input data is the MAC address which the application wants to know its device name. */
+	/*	Such user interface could show peer device's device name instead of ssid. */
+	/*	Format: iwpriv wlanx p2p_get2 devN = 00:E0:4C:00:00:05 */
+
+	DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+	if (copy_from_user(peerMACStr, wrqu->data.pointer + 5, 17))
+		return -EFAULT;
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+			u8 *wpsie;
+			uint wpsie_len = 0;
+
+			/*	The mac address is matched. */
+			wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsie_len);
+			if (wpsie) {
+				rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_DEVICE_NAME, dev_name, &dev_len);
+				if (dev_len) {
+					sprintf(dev_name_str, "\n\nN =%s", dev_name);
+					blnMatch = 1;
+				}
+			}
+			break;
+		}
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (!blnMatch)
+		sprintf(dev_name_str, "\n\nN = 0000");
+
+	if (copy_to_user(wrqu->data.pointer, dev_name_str, 5 + ((dev_len > 17) ? dev_len : 17)))
+		return -EFAULT;
+	return ret;
+}
+
+static int rtw_p2p_get_invitation_procedure(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	u8 peerMACStr[17] = {0x00};
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	unsigned long				irqL;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	u8 blnMatch = 0;
+	u8 *p2pie;
+	uint p2pielen = 0, attr_contentlen = 0;
+	u8 attr_content[2] = {0x00};
+
+	u8 inv_proc_str[17 + 8] = {0x00};
+	/*  +8 is for the str "InvProc =", we have to clear it at wrqu->data.pointer */
+
+	/*	Commented by Ouden 20121226 */
+	/*	The application wants to know P2P initation procedure is support or not. */
+	/*	Format: iwpriv wlanx p2p_get2 InvProc = 00:E0:4C:00:00:05 */
+
+	DBG_88E("[%s] data = %s\n", __func__, (char *)extra);
+	if (copy_from_user(peerMACStr, wrqu->data.pointer + 8, 17))
+		return -EFAULT;
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+			/*	Commented by Albert 20121226 */
+			/*	Match the device address located in the P2P IE */
+			/*	This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+			p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+			if (p2pie) {
+				while (p2pie) {
+					if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_CAPABILITY, attr_content, &attr_contentlen)) {
+						/*	Handle the P2P capability attribute */
+						blnMatch = 1;
+						break;
+					}
+
+					/* Get the next P2P IE */
+					p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen);
+				}
+			}
+		}
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (!blnMatch) {
+		sprintf(inv_proc_str, "\nIP =-1");
+	} else {
+		if (attr_content[0] & 0x20)
+			sprintf(inv_proc_str, "\nIP = 1");
+		else
+			sprintf(inv_proc_str, "\nIP = 0");
+	}
+	if (copy_to_user(wrqu->data.pointer, inv_proc_str, 8 + 17))
+		return -EFAULT;
+	return ret;
+}
+
+static int rtw_p2p_connect(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	unsigned long				irqL;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	uint uintPeerChannel = 0;
+
+	/*	Commented by Albert 20110304 */
+	/*	The input data contains two informations. */
+	/*	1. First information is the MAC address which wants to formate with */
+	/*	2. Second information is the WPS PINCode or "pbc" string for push button method */
+	/*	Format: 00:E0:4C:00:00:05 */
+	/*	Format: 00:E0:4C:00:00:05 */
+
+	DBG_88E("[%s] data = %s\n", __func__, extra);
+
+	if (pwdinfo->p2p_state == P2P_STATE_NONE) {
+		DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+		return ret;
+	}
+
+	if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO)
+		return -1;
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+		if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+			uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+			break;
+		}
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (uintPeerChannel) {
+		_rtw_memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
+		_rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+
+		pwdinfo->nego_req_info.peer_channel_num[0] = uintPeerChannel;
+		memcpy(pwdinfo->nego_req_info.peerDevAddr, pnetwork->network.MacAddress, ETH_ALEN);
+		pwdinfo->nego_req_info.benable = true;
+
+		_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+		if (rtw_p2p_state(pwdinfo) != P2P_STATE_GONEGO_OK) {
+			/*	Restore to the listen state if the current p2p state is not nego OK */
+			rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+		}
+
+		rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
+
+		DBG_88E("[%s] Start PreTx Procedure!\n", __func__);
+		_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+		_set_timer(&pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT);
+	} else {
+		DBG_88E("[%s] Not Found in Scanning Queue~\n", __func__);
+		ret = -1;
+	}
+	return ret;
+}
+
+static int rtw_p2p_invite_req(struct net_device *dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	int jj, kk;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	uint uintPeerChannel = 0;
+	u8 attr_content[50] = {0x00};
+	u8 *p2pie;
+	uint p2pielen = 0, attr_contentlen = 0;
+	unsigned long	irqL;
+	struct tx_invite_req_info *pinvite_req_info = &pwdinfo->invitereq_info;
+
+	/*	The input data contains two informations. */
+	/*	1. First information is the P2P device address which you want to send to. */
+	/*	2. Second information is the group id which combines with GO's mac address, space and GO's ssid. */
+	/*	Command line sample: iwpriv wlan0 p2p_set invite ="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" */
+	/*	Format: 00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy */
+
+	DBG_88E("[%s] data = %s\n", __func__, extra);
+
+	if (wrqu->data.length <=  37) {
+		DBG_88E("[%s] Wrong format!\n", __func__);
+		return ret;
+	}
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+		DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+		return ret;
+	} else {
+		/*	Reset the content of struct tx_invite_req_info */
+		pinvite_req_info->benable = false;
+		_rtw_memset(pinvite_req_info->go_bssid, 0x00, ETH_ALEN);
+		_rtw_memset(pinvite_req_info->go_ssid, 0x00, WLAN_SSID_MAXLEN);
+		pinvite_req_info->ssidlen = 0x00;
+		pinvite_req_info->operating_ch = pwdinfo->operating_channel;
+		_rtw_memset(pinvite_req_info->peer_macaddr, 0x00, ETH_ALEN);
+		pinvite_req_info->token = 3;
+	}
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		pinvite_req_info->peer_macaddr[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		/*	Commented by Albert 2011/05/18 */
+		/*	Match the device address located in the P2P IE */
+		/*	This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+		p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+		if (p2pie) {
+			/*	The P2P Device ID attribute is included in the Beacon frame. */
+			/*	The P2P Device Info attribute is included in the probe response frame. */
+
+			if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+				/*	Handle the P2P Device ID attribute of Beacon first */
+				if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) {
+					uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+					break;
+				}
+			} else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+				/*	Handle the P2P Device Info attribute of probe response */
+				if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) {
+					uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+					break;
+				}
+			}
+		}
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (uintPeerChannel) {
+		/*	Store the GO's bssid */
+		for (jj = 0, kk = 18; jj < ETH_ALEN; jj++, kk += 3)
+			pinvite_req_info->go_bssid[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+		/*	Store the GO's ssid */
+		pinvite_req_info->ssidlen = wrqu->data.length - 36;
+		memcpy(pinvite_req_info->go_ssid, &extra[36], (u32) pinvite_req_info->ssidlen);
+		pinvite_req_info->benable = true;
+		pinvite_req_info->peer_ch = uintPeerChannel;
+
+		rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INVITE_REQ);
+
+		set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+		_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+		_set_timer(&pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT);
+	} else {
+		DBG_88E("[%s] NOT Found in the Scanning Queue!\n", __func__);
+	}
+	return ret;
+}
+
+static int rtw_p2p_set_persistent(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	/*	The input data is 0 or 1 */
+	/*	0: disable persistent group functionality */
+	/*	1: enable persistent group founctionality */
+
+	DBG_88E("[%s] data = %s\n", __func__, extra);
+
+	if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+		DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+		return ret;
+	} else {
+		if (extra[0] == '0')	/*	Disable the persistent group function. */
+			pwdinfo->persistent_supported = false;
+		else if (extra[0] == '1')	/*	Enable the persistent group function. */
+			pwdinfo->persistent_supported = true;
+		else
+			pwdinfo->persistent_supported = false;
+	}
+	pr_info("[%s] persistent_supported = %d\n", __func__, pwdinfo->persistent_supported);
+	return ret;
+}
+
+static int rtw_p2p_prov_disc(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+	u8 peerMAC[ETH_ALEN] = {0x00};
+	int jj, kk;
+	struct mlme_priv		*pmlmepriv = &padapter->mlmepriv;
+	struct list_head *plist, *phead;
+	struct __queue *queue	= &(pmlmepriv->scanned_queue);
+	struct	wlan_network	*pnetwork = NULL;
+	uint uintPeerChannel = 0;
+	u8 attr_content[100] = {0x00};
+	u8 *p2pie;
+	uint p2pielen = 0, attr_contentlen = 0;
+	unsigned long				irqL;
+
+	/*	The input data contains two informations. */
+	/*	1. First information is the MAC address which wants to issue the provisioning discovery request frame. */
+	/*	2. Second information is the WPS configuration method which wants to discovery */
+	/*	Format: 00:E0:4C:00:00:05_display */
+	/*	Format: 00:E0:4C:00:00:05_keypad */
+	/*	Format: 00:E0:4C:00:00:05_pbc */
+	/*	Format: 00:E0:4C:00:00:05_label */
+
+	DBG_88E("[%s] data = %s\n", __func__, extra);
+
+	if (pwdinfo->p2p_state == P2P_STATE_NONE) {
+		DBG_88E("[%s] WiFi Direct is disable!\n", __func__);
+		return ret;
+	} else {
+		/*	Reset the content of struct tx_provdisc_req_info excluded the wps_config_method_request. */
+		_rtw_memset(pwdinfo->tx_prov_disc_info.peerDevAddr, 0x00, ETH_ALEN);
+		_rtw_memset(pwdinfo->tx_prov_disc_info.peerIFAddr, 0x00, ETH_ALEN);
+		_rtw_memset(&pwdinfo->tx_prov_disc_info.ssid, 0x00, sizeof(struct ndis_802_11_ssid));
+		pwdinfo->tx_prov_disc_info.peer_channel_num[0] = 0;
+		pwdinfo->tx_prov_disc_info.peer_channel_num[1] = 0;
+		pwdinfo->tx_prov_disc_info.benable = false;
+	}
+
+	for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+		peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+	if (!memcmp(&extra[18], "display", 7)) {
+		pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA;
+	} else if (!memcmp(&extra[18], "keypad", 7)) {
+		pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD;
+	} else if (!memcmp(&extra[18], "pbc", 3)) {
+		pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON;
+	} else if (!memcmp(&extra[18], "label", 5)) {
+		pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL;
+	} else {
+		DBG_88E("[%s] Unknown WPS config methodn", __func__);
+		return ret;
+	}
+
+	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	phead = get_list_head(queue);
+	plist = get_next(phead);
+
+	while (1) {
+		if (rtw_end_of_queue_search(phead, plist) == true)
+			break;
+
+		if (uintPeerChannel != 0)
+			break;
+
+		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+		/*	Commented by Albert 2011/05/18 */
+		/*	Match the device address located in the P2P IE */
+		/*	This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+		p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen);
+		if (p2pie) {
+			while (p2pie) {
+				/*	The P2P Device ID attribute is included in the Beacon frame. */
+				/*	The P2P Device Info attribute is included in the probe response frame. */
+
+				if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+					/*	Handle the P2P Device ID attribute of Beacon first */
+					if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+						uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+						break;
+					}
+				} else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+					/*	Handle the P2P Device Info attribute of probe response */
+					if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+						uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+						break;
+					}
+				}
+
+				/* Get the next P2P IE */
+				p2pie = rtw_get_p2p_ie(p2pie+p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen);
+			}
+		}
+
+		plist = get_next(plist);
+	}
+
+	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+	if (uintPeerChannel) {
+		DBG_88E("[%s] peer channel: %d!\n", __func__, uintPeerChannel);
+		memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, pnetwork->network.MacAddress, ETH_ALEN);
+		memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, peerMAC, ETH_ALEN);
+		pwdinfo->tx_prov_disc_info.peer_channel_num[0] = (u16) uintPeerChannel;
+		pwdinfo->tx_prov_disc_info.benable = true;
+		rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+		rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ);
+
+		if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+			memcpy(&pwdinfo->tx_prov_disc_info.ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid));
+		} else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+			memcpy(pwdinfo->tx_prov_disc_info.ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+			pwdinfo->tx_prov_disc_info.ssid.SsidLength = P2P_WILDCARD_SSID_LEN;
+		}
+
+		set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+		_set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+		_set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+	} else {
+		DBG_88E("[%s] NOT Found in the Scanning Queue!\n", __func__);
+	}
+	return ret;
+}
+
+/*	This function is used to inform the driver the user had specified the pin code value or pbc */
+/*	to application. */
+
+static int rtw_p2p_got_wpsinfo(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+	DBG_88E("[%s] data = %s\n", __func__, extra);
+	/*	Added by Albert 20110328 */
+	/*	if the input data is P2P_NO_WPSINFO -> reset the wpsinfo */
+	/*	if the input data is P2P_GOT_WPSINFO_PEER_DISPLAY_PIN -> the utility just input the PIN code got from the peer P2P device. */
+	/*	if the input data is P2P_GOT_WPSINFO_SELF_DISPLAY_PIN -> the utility just got the PIN code from itself. */
+	/*	if the input data is P2P_GOT_WPSINFO_PBC -> the utility just determine to use the PBC */
+
+	if (*extra == '0')
+		pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+	else if (*extra == '1')
+		pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PEER_DISPLAY_PIN;
+	else if (*extra == '2')
+		pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_SELF_DISPLAY_PIN;
+	else if (*extra == '3')
+		pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PBC;
+	else
+		pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+	return ret;
+}
+
+#endif /* CONFIG_88EU_P2P */
+
+static int rtw_p2p_set(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+
+#ifdef CONFIG_88EU_P2P
+	DBG_88E("[%s] extra = %s\n", __func__, extra);
+	if (!memcmp(extra, "enable =", 7)) {
+		rtw_wext_p2p_enable(dev, info, wrqu, &extra[7]);
+	} else if (!memcmp(extra, "setDN =", 6)) {
+		wrqu->data.length -= 6;
+		rtw_p2p_setDN(dev, info, wrqu, &extra[6]);
+	} else if (!memcmp(extra, "profilefound =", 13)) {
+		wrqu->data.length -= 13;
+		rtw_p2p_profilefound(dev, info, wrqu, &extra[13]);
+	} else if (!memcmp(extra, "prov_disc =", 10)) {
+		wrqu->data.length -= 10;
+		rtw_p2p_prov_disc(dev, info, wrqu, &extra[10]);
+	} else if (!memcmp(extra, "nego =", 5)) {
+		wrqu->data.length -= 5;
+		rtw_p2p_connect(dev, info, wrqu, &extra[5]);
+	} else if (!memcmp(extra, "intent =", 7)) {
+		/*	Commented by Albert 2011/03/23 */
+		/*	The wrqu->data.length will include the null character */
+		/*	So, we will decrease 7 + 1 */
+		wrqu->data.length -= 8;
+		rtw_p2p_set_intent(dev, info, wrqu, &extra[7]);
+	} else if (!memcmp(extra, "ssid =", 5)) {
+		wrqu->data.length -= 5;
+		rtw_p2p_set_go_nego_ssid(dev, info, wrqu, &extra[5]);
+	} else if (!memcmp(extra, "got_wpsinfo =", 12)) {
+		wrqu->data.length -= 12;
+		rtw_p2p_got_wpsinfo(dev, info, wrqu, &extra[12]);
+	} else if (!memcmp(extra, "listen_ch =", 10)) {
+		/*	Commented by Albert 2011/05/24 */
+		/*	The wrqu->data.length will include the null character */
+		/*	So, we will decrease (10 + 1) */
+		wrqu->data.length -= 11;
+		rtw_p2p_set_listen_ch(dev, info, wrqu, &extra[10]);
+	} else if (!memcmp(extra, "op_ch =", 6)) {
+		/*	Commented by Albert 2011/05/24 */
+		/*	The wrqu->data.length will include the null character */
+		/*	So, we will decrease (6 + 1) */
+		wrqu->data.length -= 7;
+		rtw_p2p_set_op_ch(dev, info, wrqu, &extra[6]);
+	} else if (!memcmp(extra, "invite =", 7)) {
+		wrqu->data.length -= 8;
+		rtw_p2p_invite_req(dev, info, wrqu, &extra[7]);
+	} else if (!memcmp(extra, "persistent =", 11)) {
+		wrqu->data.length -= 11;
+		rtw_p2p_set_persistent(dev, info, wrqu, &extra[11]);
+	}
+#endif /* CONFIG_88EU_P2P */
+
+	return ret;
+}
+
+static int rtw_p2p_get(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+
+#ifdef CONFIG_88EU_P2P
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	if (padapter->bShowGetP2PState)
+		DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
+	if (!memcmp(wrqu->data.pointer, "status", 6)) {
+		rtw_p2p_get_status(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "role", 4)) {
+		rtw_p2p_get_role(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "peer_ifa", 8)) {
+		rtw_p2p_get_peer_ifaddr(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "req_cm", 6)) {
+		rtw_p2p_get_req_cm(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "peer_deva", 9)) {
+		/*	Get the P2P device address when receiving the provision discovery request frame. */
+		rtw_p2p_get_peer_devaddr(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "group_id", 8)) {
+		rtw_p2p_get_groupid(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "peer_deva_inv", 9)) {
+		/*	Get the P2P device address when receiving the P2P Invitation request frame. */
+		rtw_p2p_get_peer_devaddr_by_invitation(dev, info, wrqu, extra);
+	} else if (!memcmp(wrqu->data.pointer, "op_ch", 5)) {
+		rtw_p2p_get_op_ch(dev, info, wrqu, extra);
+	}
+#endif /* CONFIG_88EU_P2P */
+	return ret;
+}
+
+static int rtw_p2p_get2(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+
+#ifdef CONFIG_88EU_P2P
+	DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
+	if (!memcmp(extra, "wpsCM =", 6)) {
+		wrqu->data.length -= 6;
+		rtw_p2p_get_wps_configmethod(dev, info, wrqu,  &extra[6]);
+	} else if (!memcmp(extra, "devN =", 5)) {
+		wrqu->data.length -= 5;
+		rtw_p2p_get_device_name(dev, info, wrqu, &extra[5]);
+	} else if (!memcmp(extra, "dev_type =", 9)) {
+		wrqu->data.length -= 9;
+		rtw_p2p_get_device_type(dev, info, wrqu, &extra[9]);
+	} else if (!memcmp(extra, "go_devadd =", 10)) {
+		wrqu->data.length -= 10;
+		rtw_p2p_get_go_device_address(dev, info, wrqu, &extra[10]);
+	} else if (!memcmp(extra, "InvProc =", 8)) {
+		wrqu->data.length -= 8;
+		rtw_p2p_get_invitation_procedure(dev, info, wrqu, &extra[8]);
+	}
+
+#endif /* CONFIG_88EU_P2P */
+
+	return ret;
+}
+
+static int rtw_cta_test_start(struct net_device *dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	DBG_88E("%s %s\n", __func__, extra);
+	if (!strcmp(extra, "1"))
+		padapter->in_cta_test = 1;
+	else
+		padapter->in_cta_test = 0;
+
+	if (padapter->in_cta_test) {
+		u32 v = rtw_read32(padapter, REG_RCR);
+		v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/*  RCR_ADF */
+		rtw_write32(padapter, REG_RCR, v);
+		DBG_88E("enable RCR_ADF\n");
+	} else {
+		u32 v = rtw_read32(padapter, REG_RCR);
+		v |= RCR_CBSSID_DATA | RCR_CBSSID_BCN;/*  RCR_ADF */
+		rtw_write32(padapter, REG_RCR, v);
+		DBG_88E("disable RCR_ADF\n");
+	}
+	return ret;
+}
+
+static int rtw_rereg_nd_name(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	struct rereg_nd_name_data *rereg_priv = &padapter->rereg_nd_name_priv;
+	char new_ifname[IFNAMSIZ];
+
+	if (rereg_priv->old_ifname[0] == 0) {
+		char *reg_ifname;
+		reg_ifname = padapter->registrypriv.if2name;
+
+		strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ);
+		rereg_priv->old_ifname[IFNAMSIZ-1] = 0;
+	}
+
+	if (wrqu->data.length > IFNAMSIZ)
+		return -EFAULT;
+
+	if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ))
+		return -EFAULT;
+
+	if (0 == strcmp(rereg_priv->old_ifname, new_ifname))
+		return ret;
+
+	DBG_88E("%s new_ifname:%s\n", __func__, new_ifname);
+	ret = rtw_change_ifname(padapter, new_ifname);
+	if (0 != ret)
+		goto exit;
+
+	if (!memcmp(rereg_priv->old_ifname, "disable%d", 9) == true) {
+		padapter->ledpriv.bRegUseLed = rereg_priv->old_bRegUseLed;
+		rtw_hal_sw_led_init(padapter);
+		rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode);
+	}
+
+	strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ);
+	rereg_priv->old_ifname[IFNAMSIZ-1] = 0;
+
+	if (!memcmp(new_ifname, "disable%d", 9) == true) {
+		DBG_88E("%s disable\n", __func__);
+		/*  free network queue for Android's timming issue */
+		rtw_free_network_queue(padapter, true);
+
+		/*  close led */
+		rtw_led_control(padapter, LED_CTL_POWER_OFF);
+		rereg_priv->old_bRegUseLed = padapter->ledpriv.bRegUseLed;
+		padapter->ledpriv.bRegUseLed = false;
+		rtw_hal_sw_led_deinit(padapter);
+
+		/*  the interface is being "disabled", we can do deeper IPS */
+		rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv);
+		rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL);
+	}
+exit:
+	return ret;
+}
+
+static void mac_reg_dump(struct adapter *padapter)
+{
+	int i, j = 1;
+	pr_info("\n ======= MAC REG =======\n");
+	for (i = 0x0; i < 0x300; i += 4) {
+		if (j%4 == 1)
+			pr_info("0x%02x", i);
+		pr_info(" 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			pr_info("\n");
+	}
+	for (i = 0x400; i < 0x800; i += 4) {
+		if (j%4 == 1)
+			pr_info("0x%02x", i);
+		pr_info(" 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			pr_info("\n");
+	}
+}
+
+static void bb_reg_dump(struct adapter *padapter)
+{
+	int i, j = 1;
+	pr_info("\n ======= BB REG =======\n");
+	for (i = 0x800; i < 0x1000; i += 4) {
+		if (j%4 == 1)
+			pr_info("0x%02x", i);
+
+		pr_info(" 0x%08x ", rtw_read32(padapter, i));
+		if ((j++)%4 == 0)
+			pr_info("\n");
+	}
+}
+
+static void rf_reg_dump(struct adapter *padapter)
+{
+	int i, j = 1, path;
+	u32 value;
+	u8 rf_type, path_nums = 0;
+	rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+	pr_info("\n ======= RF REG =======\n");
+	if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type))
+		path_nums = 1;
+	else
+		path_nums = 2;
+
+	for (path = 0; path < path_nums; path++) {
+		pr_info("\nRF_Path(%x)\n", path);
+		for (i = 0; i < 0x100; i++) {
+			value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+			if (j%4 == 1)
+				pr_info("0x%02x ", i);
+			pr_info(" 0x%08x ", value);
+			if ((j++)%4 == 0)
+				pr_info("\n");
+		}
+	}
+}
+
+static int rtw_dbg_port(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	unsigned long irqL;
+	int ret = 0;
+	u8 major_cmd, minor_cmd;
+	u16 arg;
+	s32 extra_arg;
+	u32 *pdata, val32;
+	struct sta_info *psta;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+	struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	pdata = (u32 *)&wrqu->data;
+
+	val32 = *pdata;
+	arg = (u16)(val32 & 0x0000ffff);
+	major_cmd = (u8)(val32 >> 24);
+	minor_cmd = (u8)((val32 >> 16) & 0x00ff);
+
+	extra_arg = *(pdata+1);
+
+	switch (major_cmd) {
+	case 0x70:/* read_reg */
+		switch (minor_cmd) {
+		case 1:
+			DBG_88E("rtw_read8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg));
+			break;
+		case 2:
+			DBG_88E("rtw_read16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg));
+			break;
+		case 4:
+			DBG_88E("rtw_read32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg));
+			break;
+		}
+		break;
+	case 0x71:/* write_reg */
+		switch (minor_cmd) {
+		case 1:
+			rtw_write8(padapter, arg, extra_arg);
+			DBG_88E("rtw_write8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg));
+			break;
+		case 2:
+			rtw_write16(padapter, arg, extra_arg);
+			DBG_88E("rtw_write16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg));
+			break;
+		case 4:
+			rtw_write32(padapter, arg, extra_arg);
+			DBG_88E("rtw_write32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg));
+			break;
+		}
+		break;
+	case 0x72:/* read_bb */
+		DBG_88E("read_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff));
+		break;
+	case 0x73:/* write_bb */
+		rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg);
+		DBG_88E("write_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff));
+		break;
+	case 0x74:/* read_rf */
+		DBG_88E("read RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff));
+		break;
+	case 0x75:/* write_rf */
+		rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg);
+		DBG_88E("write RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff));
+		break;
+
+	case 0x76:
+		switch (minor_cmd) {
+		case 0x00: /* normal mode, */
+			padapter->recvpriv.is_signal_dbg = 0;
+			break;
+		case 0x01: /* dbg mode */
+			padapter->recvpriv.is_signal_dbg = 1;
+			extra_arg = extra_arg > 100 ? 100 : extra_arg;
+			extra_arg = extra_arg < 0 ? 0 : extra_arg;
+			padapter->recvpriv.signal_strength_dbg = extra_arg;
+			break;
+		}
+		break;
+	case 0x78: /* IOL test */
+		switch (minor_cmd) {
+		case 0x04: /* LLT table initialization test */
+		{
+			u8 page_boundary = 0xf9;
+			struct xmit_frame	*xmit_frame;
+
+			xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+			if (xmit_frame == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			rtw_IOL_append_LLT_cmd(xmit_frame, page_boundary);
+
+			if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 500, 0))
+				ret = -EPERM;
+		}
+			break;
+		case 0x05: /* blink LED test */
+		{
+			u16 reg = 0x4c;
+			u32 blink_num = 50;
+			u32 blink_delay_ms = 200;
+			int i;
+			struct xmit_frame	*xmit_frame;
+
+			xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+			if (xmit_frame == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			for (i = 0; i < blink_num; i++) {
+				rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x00, 0xff);
+				rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+				rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x08, 0xff);
+				rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+			}
+			if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, (blink_delay_ms*blink_num*2)+200, 0))
+				ret = -EPERM;
+		}
+			break;
+
+		case 0x06: /* continuous write byte test */
+		{
+			u16 reg = arg;
+			u16 start_value = 0;
+			u32 write_num = extra_arg;
+			int i;
+			u8 final;
+			struct xmit_frame	*xmit_frame;
+
+			xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+			if (xmit_frame == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			for (i = 0; i < write_num; i++)
+				rtw_IOL_append_WB_cmd(xmit_frame, reg, i+start_value, 0xFF);
+			if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+				ret = -EPERM;
+
+			final = rtw_read8(padapter, reg);
+			if (start_value+write_num-1 == final)
+				DBG_88E("continuous IOL_CMD_WB_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+			else
+				DBG_88E("continuous IOL_CMD_WB_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+		}
+			break;
+
+		case 0x07: /* continuous write word test */
+		{
+			u16 reg = arg;
+			u16 start_value = 200;
+			u32 write_num = extra_arg;
+
+			int i;
+			u16 final;
+			struct xmit_frame	*xmit_frame;
+
+			xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+			if (xmit_frame == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			for (i = 0; i < write_num; i++)
+				rtw_IOL_append_WW_cmd(xmit_frame, reg, i+start_value, 0xFFFF);
+			if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+				ret = -EPERM;
+
+			final = rtw_read16(padapter, reg);
+			if (start_value+write_num-1 == final)
+				DBG_88E("continuous IOL_CMD_WW_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+			else
+				DBG_88E("continuous IOL_CMD_WW_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+		}
+			break;
+		case 0x08: /* continuous write dword test */
+		{
+			u16 reg = arg;
+			u32 start_value = 0x110000c7;
+			u32 write_num = extra_arg;
+
+			int i;
+			u32 final;
+			struct xmit_frame	*xmit_frame;
+
+			xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+			if (xmit_frame == NULL) {
+				ret = -ENOMEM;
+				break;
+			}
+
+			for (i = 0; i < write_num; i++)
+				rtw_IOL_append_WD_cmd(xmit_frame, reg, i+start_value, 0xFFFFFFFF);
+			if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+				ret = -EPERM;
+
+			final = rtw_read32(padapter, reg);
+			if (start_value+write_num-1 == final)
+				DBG_88E("continuous IOL_CMD_WD_REG to 0x%x %u times Success, start:%u, final:%u\n",
+					reg, write_num, start_value, final);
+			else
+				DBG_88E("continuous IOL_CMD_WD_REG to 0x%x %u times Fail, start:%u, final:%u\n",
+					reg, write_num, start_value, final);
+		}
+			break;
+		}
+		break;
+	case 0x79:
+		{
+			/*
+			* dbg 0x79000000 [value], set RESP_TXAGC to + value, value:0~15
+			* dbg 0x79010000 [value], set RESP_TXAGC to - value, value:0~15
+			*/
+			u8 value =  extra_arg & 0x0f;
+			u8 sign = minor_cmd;
+			u16 write_value = 0;
+
+			DBG_88E("%s set RESP_TXAGC to %s %u\n", __func__, sign ? "minus" : "plus", value);
+
+			if (sign)
+				value = value | 0x10;
+
+			write_value = value | (value << 5);
+			rtw_write16(padapter, 0x6d9, write_value);
+		}
+		break;
+	case 0x7a:
+		receive_disconnect(padapter, pmlmeinfo->network.MacAddress
+			, WLAN_REASON_EXPIRATION_CHK);
+		break;
+	case 0x7F:
+		switch (minor_cmd) {
+		case 0x0:
+			DBG_88E("fwstate = 0x%x\n", get_fwstate(pmlmepriv));
+			break;
+		case 0x01:
+			DBG_88E("auth_alg = 0x%x, enc_alg = 0x%x, auth_type = 0x%x, enc_type = 0x%x\n",
+				psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+				psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
+			break;
+		case 0x02:
+			DBG_88E("pmlmeinfo->state = 0x%x\n", pmlmeinfo->state);
+			break;
+		case 0x03:
+			DBG_88E("qos_option =%d\n", pmlmepriv->qospriv.qos_option);
+			DBG_88E("ht_option =%d\n", pmlmepriv->htpriv.ht_option);
+			break;
+		case 0x04:
+			DBG_88E("cur_ch =%d\n", pmlmeext->cur_channel);
+			DBG_88E("cur_bw =%d\n", pmlmeext->cur_bwmode);
+			DBG_88E("cur_ch_off =%d\n", pmlmeext->cur_ch_offset);
+			break;
+		case 0x05:
+			psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+			if (psta) {
+				int i;
+				struct recv_reorder_ctrl *preorder_ctrl;
+
+				DBG_88E("SSID =%s\n", cur_network->network.Ssid.Ssid);
+				DBG_88E("sta's macaddr: %pM\n", psta->hwaddr);
+				DBG_88E("cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+				DBG_88E("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self);
+				DBG_88E("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+				DBG_88E("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+				DBG_88E("bwmode =%d, ch_offset =%d, sgi =%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+				DBG_88E("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+				DBG_88E("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+				for (i = 0; i < 16; i++) {
+					preorder_ctrl = &psta->recvreorder_ctrl[i];
+					if (preorder_ctrl->enable)
+						DBG_88E("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq);
+				}
+			} else {
+				DBG_88E("can't get sta's macaddr, cur_network's macaddr:%pM\n", (cur_network->network.MacAddress));
+			}
+			break;
+		case 0x06:
+			{
+				u32	ODMFlag;
+				rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag));
+				DBG_88E("(B)DMFlag = 0x%x, arg = 0x%x\n", ODMFlag, arg);
+				ODMFlag = (u32)(0x0f&arg);
+				DBG_88E("(A)DMFlag = 0x%x\n", ODMFlag);
+				rtw_hal_set_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag));
+			}
+			break;
+		case 0x07:
+			DBG_88E("bSurpriseRemoved =%d, bDriverStopped =%d\n",
+				padapter->bSurpriseRemoved, padapter->bDriverStopped);
+			break;
+		case 0x08:
+			{
+				struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+				struct recv_priv  *precvpriv = &padapter->recvpriv;
+
+				DBG_88E("free_xmitbuf_cnt =%d, free_xmitframe_cnt =%d, free_xmit_extbuf_cnt =%d\n",
+					pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt);
+				DBG_88E("rx_urb_pending_cn =%d\n", precvpriv->rx_pending_cnt);
+			}
+			break;
+		case 0x09:
+			{
+				int i, j;
+				struct list_head *plist, *phead;
+				struct recv_reorder_ctrl *preorder_ctrl;
+
+#ifdef CONFIG_88EU_AP_MODE
+				DBG_88E("sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+#endif
+				_enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+				for (i = 0; i < NUM_STA; i++) {
+					phead = &(pstapriv->sta_hash[i]);
+					plist = get_next(phead);
+
+					while ((rtw_end_of_queue_search(phead, plist)) == false) {
+						psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+						plist = get_next(plist);
+
+						if (extra_arg == psta->aid) {
+							DBG_88E("sta's macaddr:%pM\n", (psta->hwaddr));
+							DBG_88E("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self);
+							DBG_88E("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+							DBG_88E("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+							DBG_88E("bwmode =%d, ch_offset =%d, sgi =%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi);
+							DBG_88E("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+							DBG_88E("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+#ifdef CONFIG_88EU_AP_MODE
+							DBG_88E("capability = 0x%x\n", psta->capability);
+							DBG_88E("flags = 0x%x\n", psta->flags);
+							DBG_88E("wpa_psk = 0x%x\n", psta->wpa_psk);
+							DBG_88E("wpa2_group_cipher = 0x%x\n", psta->wpa2_group_cipher);
+							DBG_88E("wpa2_pairwise_cipher = 0x%x\n", psta->wpa2_pairwise_cipher);
+							DBG_88E("qos_info = 0x%x\n", psta->qos_info);
+#endif
+							DBG_88E("dot118021XPrivacy = 0x%x\n", psta->dot118021XPrivacy);
+
+							for (j = 0; j < 16; j++) {
+								preorder_ctrl = &psta->recvreorder_ctrl[j];
+								if (preorder_ctrl->enable)
+									DBG_88E("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq);
+							}
+						}
+					}
+				}
+				_exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+			}
+			break;
+		case 0x0c:/* dump rx/tx packet */
+			if (arg == 0) {
+				DBG_88E("dump rx packet (%d)\n", extra_arg);
+				rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg));
+			} else if (arg == 1) {
+				DBG_88E("dump tx packet (%d)\n", extra_arg);
+				rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg));
+			}
+			break;
+		case 0x0f:
+			if (extra_arg == 0) {
+				DBG_88E("###### silent reset test.......#####\n");
+				rtw_hal_sreset_reset(padapter);
+			}
+			break;
+		case 0x15:
+			{
+				struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+				DBG_88E("==>silent resete cnts:%d\n", pwrpriv->ips_enter_cnts);
+			}
+			break;
+		case 0x10:/*  driver version display */
+			DBG_88E("rtw driver version =%s\n", DRIVERVERSION);
+			break;
+		case 0x11:
+			DBG_88E("turn %s Rx RSSI display function\n", (extra_arg == 1) ? "on" : "off");
+			padapter->bRxRSSIDisplay = extra_arg;
+			rtw_hal_set_def_var(padapter, HW_DEF_FA_CNT_DUMP, &extra_arg);
+			break;
+		case 0x12: /* set rx_stbc */
+		{
+			struct registry_priv	*pregpriv = &padapter->registrypriv;
+			/*  0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */
+			/* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
+			if (pregpriv &&
+			    (extra_arg == 0 ||
+			     extra_arg == 1 ||
+			     extra_arg == 2 ||
+			     extra_arg == 3)) {
+				pregpriv->rx_stbc = extra_arg;
+				DBG_88E("set rx_stbc =%d\n", pregpriv->rx_stbc);
+			} else {
+				DBG_88E("get rx_stbc =%d\n", pregpriv->rx_stbc);
+			}
+		}
+			break;
+		case 0x13: /* set ampdu_enable */
+		{
+			struct registry_priv	*pregpriv = &padapter->registrypriv;
+			/*  0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */
+			if (pregpriv && extra_arg >= 0 && extra_arg < 3) {
+				pregpriv->ampdu_enable = extra_arg;
+				DBG_88E("set ampdu_enable =%d\n", pregpriv->ampdu_enable);
+			} else {
+				DBG_88E("get ampdu_enable =%d\n", pregpriv->ampdu_enable);
+			}
+		}
+			break;
+		case 0x14: /* get wifi_spec */
+		{
+			struct registry_priv	*pregpriv = &padapter->registrypriv;
+			DBG_88E("get wifi_spec =%d\n", pregpriv->wifi_spec);
+		}
+			break;
+		case 0x16:
+			if (arg == 0xff) {
+				pr_info("ODM_COMP_DIG\t\tBIT0\n");
+				pr_info("ODM_COMP_RA_MASK\t\tBIT1\n");
+				pr_info("ODM_COMP_DYNAMIC_TXPWR\tBIT2\n");
+				pr_info("ODM_COMP_FA_CNT\t\tBIT3\n");
+				pr_info("ODM_COMP_RSSI_MONITOR\tBIT4\n");
+				pr_info("ODM_COMP_CCK_PD\t\tBIT5\n");
+				pr_info("ODM_COMP_ANT_DIV\t\tBIT6\n");
+				pr_info("ODM_COMP_PWR_SAVE\t\tBIT7\n");
+				pr_info("ODM_COMP_PWR_TRAIN\tBIT8\n");
+				pr_info("ODM_COMP_RATE_ADAPTIVE\tBIT9\n");
+				pr_info("ODM_COMP_PATH_DIV\t\tBIT10\n");
+				pr_info("ODM_COMP_PSD	\tBIT11\n");
+				pr_info("ODM_COMP_DYNAMIC_PRICCA\tBIT12\n");
+				pr_info("ODM_COMP_RXHP\t\tBIT13\n");
+				pr_info("ODM_COMP_EDCA_TURBO\tBIT16\n");
+				pr_info("ODM_COMP_EARLY_MODE\tBIT17\n");
+				pr_info("ODM_COMP_TX_PWR_TRACK\tBIT24\n");
+				pr_info("ODM_COMP_RX_GAIN_TRACK\tBIT25\n");
+				pr_info("ODM_COMP_CALIBRATION\tBIT26\n");
+				rtw_hal_get_def_var(padapter, HW_DEF_ODM_DBG_FLAG, &extra_arg);
+			} else {
+				rtw_hal_set_def_var(padapter, HW_DEF_ODM_DBG_FLAG, &extra_arg);
+			}
+			break;
+		case 0x23:
+			DBG_88E("turn %s the bNotifyChannelChange Variable\n", (extra_arg == 1) ? "on" : "off");
+			padapter->bNotifyChannelChange = extra_arg;
+			break;
+		case 0x24:
+#ifdef CONFIG_88EU_P2P
+			DBG_88E("turn %s the bShowGetP2PState Variable\n", (extra_arg == 1) ? "on" : "off");
+			padapter->bShowGetP2PState = extra_arg;
+#endif /*  CONFIG_88EU_P2P */
+			break;
+		case 0xaa:
+			if (extra_arg > 0x13)
+				extra_arg = 0xFF;
+			DBG_88E("chang data rate to :0x%02x\n", extra_arg);
+			padapter->fix_rate = extra_arg;
+			break;
+		case 0xdd:/* registers dump, 0 for mac reg, 1 for bb reg, 2 for rf reg */
+			if (extra_arg == 0)
+				mac_reg_dump(padapter);
+			else if (extra_arg == 1)
+				bb_reg_dump(padapter);
+			else if (extra_arg == 2)
+				rf_reg_dump(padapter);
+			break;
+		case 0xee:/* turn on/off dynamic funcs */
+			{
+				u32 odm_flag;
+
+				if (0xf == extra_arg) {
+					rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag);
+					DBG_88E(" === DMFlag(0x%08x) ===\n", odm_flag);
+					DBG_88E("extra_arg = 0  - disable all dynamic func\n");
+					DBG_88E("extra_arg = 1  - disable DIG- BIT(0)\n");
+					DBG_88E("extra_arg = 2  - disable High power - BIT(1)\n");
+					DBG_88E("extra_arg = 3  - disable tx power tracking - BIT(2)\n");
+					DBG_88E("extra_arg = 4  - disable BT coexistence - BIT(3)\n");
+					DBG_88E("extra_arg = 5  - disable antenna diversity - BIT(4)\n");
+					DBG_88E("extra_arg = 6  - enable all dynamic func\n");
+				} else {
+					/*	extra_arg = 0  - disable all dynamic func
+						extra_arg = 1  - disable DIG
+						extra_arg = 2  - disable tx power tracking
+						extra_arg = 3  - turn on all dynamic func
+					*/
+					rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg));
+					rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag);
+					DBG_88E(" === DMFlag(0x%08x) ===\n", odm_flag);
+				}
+			}
+			break;
+
+		case 0xfd:
+			rtw_write8(padapter, 0xc50, arg);
+			DBG_88E("wr(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50));
+			rtw_write8(padapter, 0xc58, arg);
+			DBG_88E("wr(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58));
+			break;
+		case 0xfe:
+			DBG_88E("rd(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50));
+			DBG_88E("rd(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58));
+			break;
+		case 0xff:
+			DBG_88E("dbg(0x210) = 0x%x\n", rtw_read32(padapter, 0x210));
+			DBG_88E("dbg(0x608) = 0x%x\n", rtw_read32(padapter, 0x608));
+			DBG_88E("dbg(0x280) = 0x%x\n", rtw_read32(padapter, 0x280));
+			DBG_88E("dbg(0x284) = 0x%x\n", rtw_read32(padapter, 0x284));
+			DBG_88E("dbg(0x288) = 0x%x\n", rtw_read32(padapter, 0x288));
+
+			DBG_88E("dbg(0x664) = 0x%x\n", rtw_read32(padapter, 0x664));
+
+			DBG_88E("\n");
+
+			DBG_88E("dbg(0x430) = 0x%x\n", rtw_read32(padapter, 0x430));
+			DBG_88E("dbg(0x438) = 0x%x\n", rtw_read32(padapter, 0x438));
+
+			DBG_88E("dbg(0x440) = 0x%x\n", rtw_read32(padapter, 0x440));
+
+			DBG_88E("dbg(0x458) = 0x%x\n", rtw_read32(padapter, 0x458));
+
+			DBG_88E("dbg(0x484) = 0x%x\n", rtw_read32(padapter, 0x484));
+			DBG_88E("dbg(0x488) = 0x%x\n", rtw_read32(padapter, 0x488));
+
+			DBG_88E("dbg(0x444) = 0x%x\n", rtw_read32(padapter, 0x444));
+			DBG_88E("dbg(0x448) = 0x%x\n", rtw_read32(padapter, 0x448));
+			DBG_88E("dbg(0x44c) = 0x%x\n", rtw_read32(padapter, 0x44c));
+			DBG_88E("dbg(0x450) = 0x%x\n", rtw_read32(padapter, 0x450));
+			break;
+		}
+		break;
+	default:
+		DBG_88E("error dbg cmd!\n");
+		break;
+	}
+	return ret;
+}
+
+static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
+{
+	uint ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	switch (name) {
+	case IEEE_PARAM_WPA_ENABLED:
+		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; /* 802.1x */
+		switch ((value)&0xff) {
+		case 1: /* WPA */
+			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+			break;
+		case 2: /* WPA2 */
+			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
+			padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+			break;
+		}
+		RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+			 ("wpa_set_param:padapter->securitypriv.ndisauthtype =%d\n", padapter->securitypriv.ndisauthtype));
+		break;
+	case IEEE_PARAM_TKIP_COUNTERMEASURES:
+		break;
+	case IEEE_PARAM_DROP_UNENCRYPTED: {
+		/* HACK:
+		 *
+		 * wpa_supplicant calls set_wpa_enabled when the driver
+		 * is loaded and unloaded, regardless of if WPA is being
+		 * used.  No other calls are made which can be used to
+		 * determine if encryption will be used or not prior to
+		 * association being expected.  If encryption is not being
+		 * used, drop_unencrypted is set to false, else true -- we
+		 * can use this to determine if the CAP_PRIVACY_ON bit should
+		 * be set.
+		 */
+
+		break;
+	}
+	case IEEE_PARAM_PRIVACY_INVOKED:
+		break;
+
+	case IEEE_PARAM_AUTH_ALGS:
+		ret = wpa_set_auth_algs(dev, value);
+		break;
+	case IEEE_PARAM_IEEE_802_1X:
+		break;
+	case IEEE_PARAM_WPAX_SELECT:
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	switch (command) {
+	case IEEE_MLME_STA_DEAUTH:
+		if (!rtw_set_802_11_disassociate(padapter))
+			ret = -1;
+		break;
+	case IEEE_MLME_STA_DISASSOC:
+		if (!rtw_set_802_11_disassociate(padapter))
+			ret = -1;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
+{
+	struct ieee_param *param;
+	uint ret = 0;
+
+	if (p->length < sizeof(struct ieee_param) || !p->pointer) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	param = (struct ieee_param *)rtw_malloc(p->length);
+	if (param == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(param, p->pointer, p->length)) {
+		kfree(param);
+		ret = -EFAULT;
+		goto out;
+	}
+
+	switch (param->cmd) {
+	case IEEE_CMD_SET_WPA_PARAM:
+		ret = wpa_set_param(dev, param->u.wpa_param.name, param->u.wpa_param.value);
+		break;
+
+	case IEEE_CMD_SET_WPA_IE:
+		ret =  rtw_set_wpa_ie((struct adapter *)rtw_netdev_priv(dev),
+				      (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
+		break;
+
+	case IEEE_CMD_SET_ENCRYPTION:
+		ret = wpa_set_encryption(dev, param, p->length);
+		break;
+
+	case IEEE_CMD_MLME:
+		ret = wpa_mlme(dev, param->u.mlme.command, param->u.mlme.reason_code);
+		break;
+
+	default:
+		DBG_88E("Unknown WPA supplicant request: %d\n", param->cmd);
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+		ret = -EFAULT;
+
+	kfree(param);
+
+out:
+
+	return ret;
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+static u8 set_pairwise_key(struct adapter *padapter, struct sta_info *psta)
+{
+	struct cmd_obj *ph2c;
+	struct set_stakey_parm	*psetstakey_para;
+	struct cmd_priv	*pcmdpriv = &padapter->cmdpriv;
+	u8 res = _SUCCESS;
+
+	ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));
+	if (ph2c == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+
+	psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm));
+	if (psetstakey_para == NULL) {
+		kfree(ph2c);
+		res = _FAIL;
+		goto exit;
+	}
+
+	init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+
+	psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy;
+
+	memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN);
+
+	memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
+
+	res = rtw_enqueue_cmd(pcmdpriv, ph2c);
+
+exit:
+
+	return res;
+}
+
+static int set_group_key(struct adapter *padapter, u8 *key, u8 alg, int keyid)
+{
+	u8 keylen;
+	struct cmd_obj *pcmd;
+	struct setkey_parm *psetkeyparm;
+	struct cmd_priv	*pcmdpriv = &(padapter->cmdpriv);
+	int res = _SUCCESS;
+
+	DBG_88E("%s\n", __func__);
+
+	pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct	cmd_obj));
+	if (pcmd == NULL) {
+		res = _FAIL;
+		goto exit;
+	}
+	psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm));
+	if (psetkeyparm == NULL) {
+		kfree(pcmd);
+		res = _FAIL;
+		goto exit;
+	}
+
+	_rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm));
+
+	psetkeyparm->keyid = (u8)keyid;
+
+	psetkeyparm->algorithm = alg;
+
+	psetkeyparm->set_tx = 1;
+
+	switch (alg) {
+	case _WEP40_:
+		keylen = 5;
+		break;
+	case _WEP104_:
+		keylen = 13;
+		break;
+	case _TKIP_:
+	case _TKIP_WTMIC_:
+	case _AES_:
+		keylen = 16;
+	default:
+		keylen = 16;
+	}
+
+	memcpy(&(psetkeyparm->key[0]), key, keylen);
+
+	pcmd->cmdcode = _SetKey_CMD_;
+	pcmd->parmbuf = (u8 *)psetkeyparm;
+	pcmd->cmdsz =  (sizeof(struct setkey_parm));
+	pcmd->rsp = NULL;
+	pcmd->rspsz = 0;
+
+	_rtw_init_listhead(&pcmd->list);
+
+	res = rtw_enqueue_cmd(pcmdpriv, pcmd);
+
+exit:
+
+	return res;
+}
+
+static int set_wep_key(struct adapter *padapter, u8 *key, u8 keylen, int keyid)
+{
+	u8 alg;
+
+	switch (keylen) {
+	case 5:
+		alg = _WEP40_;
+		break;
+	case 13:
+		alg = _WEP104_;
+		break;
+	default:
+		alg = _NO_PRIVACY_;
+	}
+
+	return set_group_key(padapter, key, alg, keyid);
+}
+
+static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+	int ret = 0;
+	u32 wep_key_idx, wep_key_len, wep_total_len;
+	struct ndis_802_11_wep	 *pwep = NULL;
+	struct sta_info *psta = NULL, *pbcmc_sta = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	struct security_priv *psecuritypriv = &(padapter->securitypriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	DBG_88E("%s\n", __func__);
+	param->u.crypt.err = 0;
+	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+	if (param_len !=  sizeof(struct ieee_param) + param->u.crypt.key_len) {
+		ret =  -EINVAL;
+		goto exit;
+	}
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+		if (param->u.crypt.idx >= WEP_KEYS) {
+			ret = -EINVAL;
+			goto exit;
+		}
+	} else {
+		psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+		if (!psta) {
+			DBG_88E("rtw_set_encryption(), sta has already been removed or never been added\n");
+			goto exit;
+		}
+	}
+
+	if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) {
+		/* todo:clear default encryption keys */
+
+		DBG_88E("clear default encryption keys, keyid =%d\n", param->u.crypt.idx);
+		goto exit;
+	}
+	if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) {
+		DBG_88E("r871x_set_encryption, crypt.alg = WEP\n");
+		wep_key_idx = param->u.crypt.idx;
+		wep_key_len = param->u.crypt.key_len;
+		DBG_88E("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);
+		if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
+			ret = -EINVAL;
+			goto exit;
+		}
+
+		if (wep_key_len > 0) {
+			wep_key_len = wep_key_len <= 5 ? 5 : 13;
+			wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
+			pwep = (struct ndis_802_11_wep *)rtw_malloc(wep_total_len);
+			if (pwep == NULL) {
+				DBG_88E(" r871x_set_encryption: pwep allocate fail !!!\n");
+				goto exit;
+			}
+
+			_rtw_memset(pwep, 0, wep_total_len);
+
+			pwep->KeyLength = wep_key_len;
+			pwep->Length = wep_total_len;
+		}
+
+		pwep->KeyIndex = wep_key_idx;
+
+		memcpy(pwep->KeyMaterial,  param->u.crypt.key, pwep->KeyLength);
+
+		if (param->u.crypt.set_tx) {
+			DBG_88E("wep, set_tx = 1\n");
+
+			psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+			psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+			psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+			if (pwep->KeyLength == 13) {
+				psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+				psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+			}
+
+			psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+
+			memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+
+			psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+			set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
+		} else {
+			DBG_88E("wep, set_tx = 0\n");
+
+			/* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
+			/* psecuritypriv->dot11PrivacyKeyIndex = keyid", but can rtw_set_key to cam */
+
+		      memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+
+			psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+			set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);
+		}
+
+		goto exit;
+	}
+
+	if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /*  group key */
+		if (param->u.crypt.set_tx == 1) {
+			if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+				DBG_88E("%s, set group_key, WEP\n", __func__);
+
+				memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+					    param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+				psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+				if (param->u.crypt.key_len == 13)
+						psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+			} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+				DBG_88E("%s, set group_key, TKIP\n", __func__);
+				psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+				memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+					    param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+				/* set mic key */
+				memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+				memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+				psecuritypriv->busetkipkey = true;
+			} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+				DBG_88E("%s, set group_key, CCMP\n", __func__);
+				psecuritypriv->dot118021XGrpPrivacy = _AES_;
+				memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+					    param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+			} else {
+				DBG_88E("%s, set group_key, none\n", __func__);
+				psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+			}
+			psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+			psecuritypriv->binstallGrpkey = true;
+			psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/*  */
+			set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+			pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+			if (pbcmc_sta) {
+				pbcmc_sta->ieee8021x_blocked = false;
+				pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
+			}
+		}
+		goto exit;
+	}
+
+	if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /*  psk/802_1x */
+		if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+			if (param->u.crypt.set_tx == 1) {
+				memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+				if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+					DBG_88E("%s, set pairwise key, WEP\n", __func__);
+
+					psta->dot118021XPrivacy = _WEP40_;
+					if (param->u.crypt.key_len == 13)
+						psta->dot118021XPrivacy = _WEP104_;
+				} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+					DBG_88E("%s, set pairwise key, TKIP\n", __func__);
+
+					psta->dot118021XPrivacy = _TKIP_;
+
+					/* set mic key */
+					memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+					memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+					psecuritypriv->busetkipkey = true;
+				} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+					DBG_88E("%s, set pairwise key, CCMP\n", __func__);
+
+					psta->dot118021XPrivacy = _AES_;
+				} else {
+					DBG_88E("%s, set pairwise key, none\n", __func__);
+
+					psta->dot118021XPrivacy = _NO_PRIVACY_;
+				}
+
+				set_pairwise_key(padapter, psta);
+
+				psta->ieee8021x_blocked = false;
+			} else { /* group key??? */
+				if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+					memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+						    param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+					psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+					if (param->u.crypt.key_len == 13)
+						psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+				} else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+					psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+					memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+						    param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+					/* set mic key */
+					memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+					memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+					psecuritypriv->busetkipkey = true;
+				} else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+					psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+					memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,
+						    param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+				} else {
+					psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+				}
+
+				psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+				psecuritypriv->binstallGrpkey = true;
+
+				psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/*  */
+
+				set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+
+				pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+				if (pbcmc_sta) {
+					pbcmc_sta->ieee8021x_blocked = false;
+					pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
+				}
+			}
+		}
+	}
+
+exit:
+
+	kfree(pwep);
+
+	return ret;
+}
+
+static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	unsigned char *pbuf = param->u.bcn_ie.buf;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2);
+
+	if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0))
+		pstapriv->max_num_sta = NUM_STA;
+
+	if (rtw_check_beacon_data(padapter, pbuf,  (len-12-2)) == _SUCCESS)/*  12 = param header, 2:no packed */
+		ret = 0;
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static int rtw_hostapd_sta_flush(struct net_device *dev)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	DBG_88E("%s\n", __func__);
+
+	flush_all_cam_entry(padapter);	/* clear CAM */
+
+	ret = rtw_sta_flush(padapter);
+
+	return ret;
+}
+
+static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	DBG_88E("rtw_add_sta(aid =%d) =%pM\n", param->u.add_sta.aid, (param->sta_addr));
+
+	if (!check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)))
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+		return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+	if (psta) {
+		int flags = param->u.add_sta.flags;
+
+		psta->aid = param->u.add_sta.aid;/* aid = 1~2007 */
+
+		memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16);
+
+		/* check wmm cap. */
+		if (WLAN_STA_WME&flags)
+			psta->qos_option = 1;
+		else
+			psta->qos_option = 0;
+
+		if (pmlmepriv->qospriv.qos_option == 0)
+			psta->qos_option = 0;
+
+		/* chec 802.11n ht cap. */
+		if (WLAN_STA_HT&flags) {
+			psta->htpriv.ht_option = true;
+			psta->qos_option = 1;
+			memcpy((void *)&psta->htpriv.ht_cap, (void *)&param->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+		} else {
+			psta->htpriv.ht_option = false;
+		}
+
+		if (pmlmepriv->htpriv.ht_option == false)
+			psta->htpriv.ht_option = false;
+
+		update_sta_info_apmode(padapter, psta);
+	} else {
+		ret = -ENOMEM;
+	}
+
+	return ret;
+}
+
+static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
+{
+	unsigned long irqL;
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	int updated = 0;
+
+	DBG_88E("rtw_del_sta =%pM\n", (param->sta_addr));
+
+	if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+		return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+	if (psta) {
+		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		if (!rtw_is_list_empty(&psta->asoc_list)) {
+			rtw_list_delete(&psta->asoc_list);
+			pstapriv->asoc_list_cnt--;
+			updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+		}
+		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+		associated_clients_update(padapter, updated);
+		psta = NULL;
+	} else {
+		DBG_88E("rtw_del_sta(), sta has already been removed or never been added\n");
+	}
+
+	return ret;
+}
+
+static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+	struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param;
+	struct sta_data *psta_data = (struct sta_data *)param_ex->data;
+
+	DBG_88E("rtw_ioctl_get_sta_info, sta_addr: %pM\n", (param_ex->sta_addr));
+
+	if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+		return -EINVAL;
+
+	if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff &&
+	    param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff &&
+	    param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff)
+		return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr);
+	if (psta) {
+		psta_data->aid = (u16)psta->aid;
+		psta_data->capability = psta->capability;
+		psta_data->flags = psta->flags;
+
+/*
+		nonerp_set : BIT(0)
+		no_short_slot_time_set : BIT(1)
+		no_short_preamble_set : BIT(2)
+		no_ht_gf_set : BIT(3)
+		no_ht_set : BIT(4)
+		ht_20mhz_set : BIT(5)
+*/
+
+		psta_data->sta_set = ((psta->nonerp_set) |
+				      (psta->no_short_slot_time_set << 1) |
+				      (psta->no_short_preamble_set << 2) |
+				      (psta->no_ht_gf_set << 3) |
+				      (psta->no_ht_set << 4) |
+				      (psta->ht_20mhz_set << 5));
+		psta_data->tx_supp_rates_len =  psta->bssratelen;
+		memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen);
+		memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+		psta_data->rx_pkts = psta->sta_stats.rx_data_pkts;
+		psta_data->rx_bytes = psta->sta_stats.rx_bytes;
+		psta_data->rx_drops = psta->sta_stats.rx_drops;
+		psta_data->tx_pkts = psta->sta_stats.tx_pkts;
+		psta_data->tx_bytes = psta->sta_stats.tx_bytes;
+		psta_data->tx_drops = psta->sta_stats.tx_drops;
+	} else {
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
+{
+	int ret = 0;
+	struct sta_info *psta = NULL;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	DBG_88E("rtw_get_sta_wpaie, sta_addr: %pM\n", (param->sta_addr));
+
+	if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+		return -EINVAL;
+
+	psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+	if (psta) {
+		if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) {
+			int wpa_ie_len;
+			int copy_len;
+
+			wpa_ie_len = psta->wpa_ie[1];
+			copy_len = ((wpa_ie_len+2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)) : (wpa_ie_len+2);
+			param->u.wpa_ie.len = copy_len;
+			memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len);
+		} else {
+			DBG_88E("sta's wpa_ie is NONE\n");
+		}
+	} else {
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	int ie_len;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	ie_len = len-12-2;/*  12 = param header, 2:no packed */
+
+	if (pmlmepriv->wps_beacon_ie) {
+		kfree(pmlmepriv->wps_beacon_ie);
+		pmlmepriv->wps_beacon_ie = NULL;
+	}
+
+	if (ie_len > 0) {
+		pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
+		pmlmepriv->wps_beacon_ie_len = ie_len;
+		if (pmlmepriv->wps_beacon_ie == NULL) {
+			DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+
+		memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len);
+
+		update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true);
+
+		pmlmeext->bstart_bss = true;
+	}
+
+	return ret;
+}
+
+static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	int ie_len;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	ie_len = len-12-2;/*  12 = param header, 2:no packed */
+
+	if (pmlmepriv->wps_probe_resp_ie) {
+		kfree(pmlmepriv->wps_probe_resp_ie);
+		pmlmepriv->wps_probe_resp_ie = NULL;
+	}
+
+	if (ie_len > 0) {
+		pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
+		pmlmepriv->wps_probe_resp_ie_len = ie_len;
+		if (pmlmepriv->wps_probe_resp_ie == NULL) {
+			DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+		memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
+	}
+
+	return ret;
+}
+
+static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	int ie_len;
+
+	DBG_88E("%s, len =%d\n", __func__, len);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	ie_len = len-12-2;/*  12 = param header, 2:no packed */
+
+	if (pmlmepriv->wps_assoc_resp_ie) {
+		kfree(pmlmepriv->wps_assoc_resp_ie);
+		pmlmepriv->wps_assoc_resp_ie = NULL;
+	}
+
+	if (ie_len > 0) {
+		pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
+		pmlmepriv->wps_assoc_resp_ie_len = ie_len;
+		if (pmlmepriv->wps_assoc_resp_ie == NULL) {
+			DBG_88E("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+			return -EINVAL;
+		}
+
+		memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
+	}
+
+	return ret;
+}
+
+static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
+	struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+
+	u8 value;
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	if (param->u.wpa_param.name != 0) /* dummy test... */
+		DBG_88E("%s name(%u) != 0\n", __func__, param->u.wpa_param.name);
+	value = param->u.wpa_param.value;
+
+	/* use the same definition of hostapd's ignore_broadcast_ssid */
+	if (value != 1 && value != 2)
+		value = 0;
+	DBG_88E("%s value(%u)\n", __func__, value);
+	pmlmeinfo->hidden_ssid_mode = value;
+	return ret;
+}
+
+static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+		return -EINVAL;
+	ret = rtw_acl_remove_sta(padapter, param->sta_addr);
+	return ret;
+}
+
+static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+		return -EINVAL;
+	ret = rtw_acl_add_sta(padapter, param->sta_addr);
+	return ret;
+}
+
+static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len)
+{
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+		return -EINVAL;
+
+	rtw_set_macaddr_acl(padapter, param->u.mlme.command);
+
+	return ret;
+}
+
+static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
+{
+	struct ieee_param *param;
+	int ret = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	/*
+	* this function is expect to call in master mode, which allows no power saving
+	* so, we just check hw_init_completed
+	*/
+
+	if (!padapter->hw_init_completed) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	if (!p->pointer) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	param = (struct ieee_param *)rtw_malloc(p->length);
+	if (param == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(param, p->pointer, p->length)) {
+		kfree(param);
+		ret = -EFAULT;
+		goto out;
+	}
+
+	switch (param->cmd) {
+	case RTL871X_HOSTAPD_FLUSH:
+		ret = rtw_hostapd_sta_flush(dev);
+		break;
+	case RTL871X_HOSTAPD_ADD_STA:
+		ret = rtw_add_sta(dev, param);
+		break;
+	case RTL871X_HOSTAPD_REMOVE_STA:
+		ret = rtw_del_sta(dev, param);
+		break;
+	case RTL871X_HOSTAPD_SET_BEACON:
+		ret = rtw_set_beacon(dev, param, p->length);
+		break;
+	case RTL871X_SET_ENCRYPTION:
+		ret = rtw_set_encryption(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_GET_WPAIE_STA:
+		ret = rtw_get_sta_wpaie(dev, param);
+		break;
+	case RTL871X_HOSTAPD_SET_WPS_BEACON:
+		ret = rtw_set_wps_beacon(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
+		ret = rtw_set_wps_probe_resp(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
+		ret = rtw_set_wps_assoc_resp(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
+		ret = rtw_set_hidden_ssid(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_GET_INFO_STA:
+		ret = rtw_ioctl_get_sta_data(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_SET_MACADDR_ACL:
+		ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_ACL_ADD_STA:
+		ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
+		break;
+	case RTL871X_HOSTAPD_ACL_REMOVE_STA:
+		ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
+		break;
+	default:
+		DBG_88E("Unknown hostapd request: %d\n", param->cmd);
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+		ret = -EFAULT;
+	kfree(param);
+out:
+	return ret;
+}
+#endif
+
+#include <rtw_android.h>
+static int rtw_wx_set_priv(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *awrq,
+				char *extra)
+{
+	int ret = 0;
+	int len = 0;
+	char *ext;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_point *dwrq = (struct iw_point *)awrq;
+
+	if (dwrq->length == 0)
+		return -EFAULT;
+
+	len = dwrq->length;
+	ext = rtw_vmalloc(len);
+	if (!ext)
+		return -ENOMEM;
+
+	if (copy_from_user(ext, dwrq->pointer, len)) {
+		rtw_vmfree(ext, len);
+		return -EFAULT;
+	}
+
+	/* added for wps2.0 @20110524 */
+	if (dwrq->flags == 0x8766 && len > 8) {
+		u32 cp_sz;
+		struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+		u8 *probereq_wpsie = ext;
+		int probereq_wpsie_len = len;
+		u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+		if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) &&
+		    (!memcmp(&probereq_wpsie[2], wps_oui, 4))) {
+			cp_sz = probereq_wpsie_len > MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN : probereq_wpsie_len;
+
+			pmlmepriv->wps_probe_req_ie_len = 0;
+			kfree(pmlmepriv->wps_probe_req_ie);
+			pmlmepriv->wps_probe_req_ie = NULL;
+
+			pmlmepriv->wps_probe_req_ie = rtw_malloc(cp_sz);
+			if (pmlmepriv->wps_probe_req_ie == NULL) {
+				pr_info("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+				ret =  -EINVAL;
+				goto FREE_EXT;
+			}
+			memcpy(pmlmepriv->wps_probe_req_ie, probereq_wpsie, cp_sz);
+			pmlmepriv->wps_probe_req_ie_len = cp_sz;
+		}
+		goto FREE_EXT;
+	}
+
+	if (len >= WEXT_CSCAN_HEADER_SIZE &&
+	    !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) {
+		ret = rtw_wx_set_scan(dev, info, awrq, ext);
+		goto FREE_EXT;
+	}
+
+FREE_EXT:
+
+	rtw_vmfree(ext, len);
+
+	return ret;
+}
+
+static int rtw_pm_set(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu, char *extra)
+{
+	int ret = 0;
+	unsigned	mode = 0;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+
+	DBG_88E("[%s] extra = %s\n", __func__, extra);
+
+	if (!memcmp(extra, "lps =", 4)) {
+		sscanf(extra+4, "%u", &mode);
+		ret = rtw_pm_set_lps(padapter, mode);
+	} else if (!memcmp(extra, "ips =", 4)) {
+		sscanf(extra+4, "%u", &mode);
+		ret = rtw_pm_set_ips(padapter, mode);
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int rtw_mp_efuse_get(struct net_device *dev,
+			struct iw_request_info *info,
+			union iwreq_data *wdata, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+	struct hal_data_8188e *haldata = GET_HAL_DATA(padapter);
+	struct efuse_hal *pEfuseHal;
+	struct iw_point *wrqu;
+
+	u8 *PROMContent = pEEPROM->efuse_eeprom_data;
+	u8 ips_mode = 0, lps_mode = 0;
+	struct pwrctrl_priv *pwrctrlpriv;
+	u8 *data = NULL;
+	u8 *rawdata = NULL;
+	char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL};
+	u16 i = 0, j = 0, mapLen = 0, addr = 0, cnts = 0;
+	u16 max_available_size = 0, raw_cursize = 0, raw_maxsize = 0;
+	int err;
+	u8 org_fw_iol = padapter->registrypriv.fw_iol;/*  0:Disable, 1:enable, 2:by usb speed */
+
+	wrqu = (struct iw_point *)wdata;
+	pwrctrlpriv = &padapter->pwrctrlpriv;
+	pEfuseHal = &haldata->EfuseHal;
+
+	err = 0;
+	data = _rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
+	if (data == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	rawdata = _rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
+	if (rawdata == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	if (copy_from_user(extra, wrqu->pointer, wrqu->length)) {
+		err = -EFAULT;
+		goto exit;
+	}
+	lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
+	rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+	ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
+	rtw_pm_set_ips(padapter, IPS_NONE);
+
+	pch = extra;
+	DBG_88E("%s: in =%s\n", __func__, extra);
+
+	i = 0;
+	/* mac 16 "00e04c871200" rmap, 00, 2 */
+	while ((token = strsep(&pch, ",")) != NULL) {
+		if (i > 2)
+			break;
+		tmp[i] = token;
+		i++;
+	}
+	padapter->registrypriv.fw_iol = 0;/*  0:Disable, 1:enable, 2:by usb speed */
+
+	if (strcmp(tmp[0], "status") == 0) {
+		sprintf(extra, "Load File efuse =%s, Load File MAC =%s", (pEEPROM->bloadfile_fail_flag ? "FAIL" : "OK"), (pEEPROM->bloadmac_fail_flag ? "FAIL" : "OK"));
+
+		  goto exit;
+	} else if (strcmp(tmp[0], "filemap") == 0) {
+		mapLen = EFUSE_MAP_SIZE;
+
+		sprintf(extra, "\n");
+		for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+			sprintf(extra, "%s0x%02x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, PROMContent[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s%02X ", extra, PROMContent[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else if (strcmp(tmp[0], "realmap") == 0) {
+		mapLen = EFUSE_MAP_SIZE;
+		if (rtw_efuse_map_read(padapter, 0, mapLen, pEfuseHal->fakeEfuseInitMap) == _FAIL) {
+			DBG_88E("%s: read realmap Fail!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		sprintf(extra, "\n");
+		for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+			sprintf(extra, "%s0x%02x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseInitMap[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseInitMap[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else if (strcmp(tmp[0], "rmap") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			DBG_88E("%s: rmap Fail!! Parameters error!\n", __func__);
+			err = -EINVAL;
+			goto exit;
+		}
+
+		/*  rmap addr cnts */
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		DBG_88E("%s: addr =%x\n", __func__, addr);
+
+		cnts = simple_strtoul(tmp[2], &ptmp, 10);
+		if (cnts == 0) {
+			DBG_88E("%s: rmap Fail!! cnts error!\n", __func__);
+			err = -EINVAL;
+			goto exit;
+		}
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if ((addr + cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EINVAL;
+			goto exit;
+		}
+
+		if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_map_read error!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		*extra = 0;
+		for (i = 0; i < cnts; i++)
+			sprintf(extra, "%s0x%02X ", extra, data[i]);
+	} else if (strcmp(tmp[0], "realraw") == 0) {
+		addr = 0;
+		mapLen = EFUSE_MAX_SIZE;
+		if (rtw_efuse_access(padapter, false, addr, mapLen, rawdata) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_access Fail!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		sprintf(extra, "\n");
+		for (i = 0; i < mapLen; i++) {
+			sprintf(extra, "%s%02X", extra, rawdata[i]);
+
+			if ((i & 0xF) == 0xF)
+				sprintf(extra, "%s\n", extra);
+			else if ((i & 0x7) == 0x7)
+				sprintf(extra, "%s\t", extra);
+			else
+				sprintf(extra, "%s ", extra);
+		}
+	} else if (strcmp(tmp[0], "mac") == 0) {
+		cnts = 6;
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if ((addr + cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_map_read error!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		*extra = 0;
+		for (i = 0; i < cnts; i++) {
+			sprintf(extra, "%s%02X", extra, data[i]);
+			if (i != (cnts-1))
+				sprintf(extra, "%s:", extra);
+		}
+	} else if (strcmp(tmp[0], "vidpid") == 0) {
+		cnts = 4;
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if ((addr + cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+		if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_access error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		*extra = 0;
+		for (i = 0; i < cnts; i++) {
+			sprintf(extra, "%s0x%02X", extra, data[i]);
+			if (i != (cnts-1))
+				sprintf(extra, "%s,", extra);
+		}
+	} else if (strcmp(tmp[0], "ableraw") == 0) {
+		efuse_GetCurrentSize(padapter, &raw_cursize);
+		raw_maxsize = efuse_GetMaxSize(padapter);
+		sprintf(extra, "[available raw size] = %d bytes", raw_maxsize-raw_cursize);
+	} else if (strcmp(tmp[0], "btfmap") == 0) {
+		mapLen = EFUSE_BT_MAX_MAP_LEN;
+		if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) {
+			DBG_88E("%s: rtw_BT_efuse_map_read Fail!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		sprintf(extra, "\n");
+		for (i = 0; i < 512; i += 16) {
+			/*  set 512 because the iwpriv's extra size have limit 0x7FF */
+			sprintf(extra, "%s0x%03x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else if (strcmp(tmp[0], "btbmap") == 0) {
+		mapLen = EFUSE_BT_MAX_MAP_LEN;
+		if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) {
+			DBG_88E("%s: rtw_BT_efuse_map_read Fail!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		sprintf(extra, "\n");
+		for (i = 512; i < 1024; i += 16) {
+			sprintf(extra, "%s0x%03x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->BTEfuseInitMap[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else if (strcmp(tmp[0], "btrmap") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		/*  rmap addr cnts */
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+
+		cnts = simple_strtoul(tmp[2], &ptmp, 10);
+		if (cnts == 0) {
+			DBG_88E("%s: btrmap Fail!! cnts error!\n", __func__);
+			err = -EINVAL;
+			goto exit;
+		}
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if ((addr + cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_BT_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+			DBG_88E("%s: rtw_BT_efuse_map_read error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		*extra = 0;
+		for (i = 0; i < cnts; i++)
+			sprintf(extra, "%s 0x%02X ", extra, data[i]);
+	} else if (strcmp(tmp[0], "btffake") == 0) {
+		sprintf(extra, "\n");
+		for (i = 0; i < 512; i += 16) {
+			sprintf(extra, "%s0x%03x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else if (strcmp(tmp[0], "btbfake") == 0) {
+		sprintf(extra, "\n");
+		for (i = 512; i < 1024; i += 16) {
+			sprintf(extra, "%s0x%03x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeBTEfuseModifiedMap[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else if (strcmp(tmp[0], "wlrfkmap") == 0) {
+		sprintf(extra, "\n");
+		for (i = 0; i < EFUSE_MAP_SIZE; i += 16) {
+			sprintf(extra, "%s0x%02x\t", extra, i);
+			for (j = 0; j < 8; j++)
+				sprintf(extra, "%s%02X ", extra, pEfuseHal->fakeEfuseModifiedMap[i+j]);
+			sprintf(extra, "%s\t", extra);
+			for (; j < 16; j++)
+				sprintf(extra, "%s %02X", extra, pEfuseHal->fakeEfuseModifiedMap[i+j]);
+			sprintf(extra, "%s\n", extra);
+		}
+	} else {
+		 sprintf(extra, "Command not found!");
+	}
+
+exit:
+	kfree(data);
+	kfree(rawdata);
+	if (!err)
+		wrqu->length = strlen(extra);
+
+	rtw_pm_set_ips(padapter, ips_mode);
+	rtw_pm_set_lps(padapter, lps_mode);
+	padapter->registrypriv.fw_iol = org_fw_iol;/*  0:Disable, 1:enable, 2:by usb speed */
+	return err;
+}
+
+static int rtw_mp_efuse_set(struct net_device *dev,
+			struct iw_request_info *info,
+			union iwreq_data *wdata, char *extra)
+{
+	struct adapter *padapter;
+	struct pwrctrl_priv *pwrctrlpriv;
+	struct hal_data_8188e *haldata;
+	struct efuse_hal *pEfuseHal;
+
+	u8 ips_mode = 0, lps_mode = 0;
+	u32 i, jj, kk;
+	u8 *setdata = NULL;
+	u8 *ShadowMapBT = NULL;
+	u8 *ShadowMapWiFi = NULL;
+	u8 *setrawdata = NULL;
+	char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL};
+	u16 addr = 0, cnts = 0, max_available_size = 0;
+	int err;
+
+	padapter = rtw_netdev_priv(dev);
+	pwrctrlpriv = &padapter->pwrctrlpriv;
+	haldata = GET_HAL_DATA(padapter);
+	pEfuseHal = &haldata->EfuseHal;
+	err = 0;
+	setdata = _rtw_zmalloc(1024);
+	if (setdata == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	ShadowMapBT = _rtw_malloc(EFUSE_BT_MAX_MAP_LEN);
+	if (ShadowMapBT == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	ShadowMapWiFi = _rtw_malloc(EFUSE_MAP_SIZE);
+	if (ShadowMapWiFi == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	setrawdata = _rtw_malloc(EFUSE_MAX_SIZE);
+	if (setrawdata == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
+	rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+	ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
+	rtw_pm_set_ips(padapter, IPS_NONE);
+
+	pch = extra;
+	DBG_88E("%s: in =%s\n", __func__, extra);
+
+	i = 0;
+	while ((token = strsep(&pch, ",")) != NULL) {
+		if (i > 2)
+			break;
+		tmp[i] = token;
+		i++;
+	}
+
+	/*  tmp[0],[1],[2] */
+	/*  wmap, addr, 00e04c871200 */
+	if (strcmp(tmp[0], "wmap") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		addr &= 0xFFF;
+
+		cnts = strlen(tmp[2]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: map data =%s\n", __func__, tmp[2]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+		/* Change to check TYPE_EFUSE_MAP_LEN, beacuse 8188E raw 256, logic map over 256. */
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false);
+		if ((addr+cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "wraw") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		addr &= 0xFFF;
+
+		cnts = strlen(tmp[2]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: raw data =%s\n", __func__, tmp[2]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			setrawdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+
+		if (rtw_efuse_access(padapter, true, addr, cnts, setrawdata) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_access error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "mac") == 0) {
+		if (tmp[1] == NULL) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		/* mac, 00e04c871200 */
+		addr = EEPROM_MAC_ADDR_88EU;
+		cnts = strlen(tmp[1]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+		if (cnts > 6) {
+			DBG_88E("%s: error data for mac addr =\"%s\"\n", __func__, tmp[1]);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: MAC address =%s\n", __func__, tmp[1]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+		/* Change to check TYPE_EFUSE_MAP_LEN, beacuse 8188E raw 256, logic map over 256. */
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false);
+		if ((addr+cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "vidpid") == 0) {
+		if (tmp[1] == NULL) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		/*  pidvid, da0b7881 */
+		addr = EEPROM_VID_88EE;
+		cnts = strlen(tmp[1]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: VID/PID =%s\n", __func__, tmp[1]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if ((addr+cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "btwmap") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		addr &= 0xFFF;
+
+		cnts = strlen(tmp[2]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: BT data =%s\n", __func__, tmp[2]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if ((addr+cnts) > max_available_size) {
+			DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_BT_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+			DBG_88E("%s: rtw_BT_efuse_map_write error!!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "btwfake") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		addr &= 0xFFF;
+
+		cnts = strlen(tmp[2]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: BT tmp data =%s\n", __func__, tmp[2]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			pEfuseHal->fakeBTEfuseModifiedMap[addr+jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+	} else if (strcmp(tmp[0], "btdumpfake") == 0) {
+		if (rtw_BT_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _SUCCESS) {
+			DBG_88E("%s: BT read all map success\n", __func__);
+		} else {
+			DBG_88E("%s: BT read all map Fail!\n", __func__);
+			err = -EFAULT;
+		}
+	} else if (strcmp(tmp[0], "wldumpfake") == 0) {
+		if (rtw_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN,  pEfuseHal->fakeEfuseModifiedMap) == _SUCCESS) {
+			DBG_88E("%s: BT read all map success\n", __func__);
+		} else {
+			DBG_88E("%s: BT read all map  Fail\n", __func__);
+			err = -EFAULT;
+		}
+	} else if (strcmp(tmp[0], "btfk2map") == 0) {
+		memcpy(pEfuseHal->BTEfuseModifiedMap, pEfuseHal->fakeBTEfuseModifiedMap, EFUSE_BT_MAX_MAP_LEN);
+
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if (max_available_size < 1) {
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_BT_efuse_map_write(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _FAIL) {
+			DBG_88E("%s: rtw_BT_efuse_map_write error!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "wlfk2map") == 0) {
+		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+		if (max_available_size < 1) {
+			err = -EFAULT;
+			goto exit;
+		}
+
+		if (rtw_efuse_map_write(padapter, 0x00, EFUSE_MAX_MAP_LEN, pEfuseHal->fakeEfuseModifiedMap) == _FAIL) {
+			DBG_88E("%s: rtw_efuse_map_write error!\n", __func__);
+			err = -EFAULT;
+			goto exit;
+		}
+	} else if (strcmp(tmp[0], "wlwfake") == 0) {
+		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		addr = simple_strtoul(tmp[1], &ptmp, 16);
+		addr &= 0xFFF;
+
+		cnts = strlen(tmp[2]);
+		if (cnts%2) {
+			err = -EINVAL;
+			goto exit;
+		}
+		cnts /= 2;
+		if (cnts == 0) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		DBG_88E("%s: addr = 0x%X\n", __func__, addr);
+		DBG_88E("%s: cnts =%d\n", __func__, cnts);
+		DBG_88E("%s: map tmp data =%s\n", __func__, tmp[2]);
+
+		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+			pEfuseHal->fakeEfuseModifiedMap[addr+jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+	}
+
+exit:
+	kfree(setdata);
+	kfree(ShadowMapBT);
+	kfree(ShadowMapWiFi);
+	kfree(setrawdata);
+
+	rtw_pm_set_ips(padapter, ips_mode);
+	rtw_pm_set_lps(padapter, lps_mode);
+
+	return err;
+}
+
+/*
+ * Input Format: %s,%d,%d
+ *	%s is width, could be
+ *		"b" for 1 byte
+ *		"w" for WORD (2 bytes)
+ *		"dw" for DWORD (4 bytes)
+ *	1st %d is address(offset)
+ *	2st %d is data to write
+ */
+static int rtw_mp_write_reg(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	char *pch, *pnext, *ptmp;
+	char *width_str;
+	char width;
+	u32 addr, data;
+	int ret;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	pch = extra;
+	pnext = strpbrk(pch, ",.-");
+	if (pnext == NULL)
+		return -EINVAL;
+	*pnext = 0;
+	width_str = pch;
+
+	pch = pnext + 1;
+	pnext = strpbrk(pch, ",.-");
+	if (pnext == NULL)
+		return -EINVAL;
+	*pnext = 0;
+	addr = simple_strtoul(pch, &ptmp, 16);
+	if (addr > 0x3FFF)
+		return -EINVAL;
+
+	pch = pnext + 1;
+	if ((pch - extra) >= wrqu->length)
+		return -EINVAL;
+	data = simple_strtoul(pch, &ptmp, 16);
+
+	ret = 0;
+	width = width_str[0];
+	switch (width) {
+	case 'b':
+		/*  1 byte */
+		if (data > 0xFF) {
+			ret = -EINVAL;
+			break;
+		}
+		rtw_write8(padapter, addr, data);
+		break;
+	case 'w':
+		/*  2 bytes */
+		if (data > 0xFFFF) {
+			ret = -EINVAL;
+			break;
+		}
+		rtw_write16(padapter, addr, data);
+		break;
+	case 'd':
+		/*  4 bytes */
+		rtw_write32(padapter, addr, data);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Input Format: %s,%d
+ *	%s is width, could be
+ *		"b" for 1 byte
+ *		"w" for WORD (2 bytes)
+ *		"dw" for DWORD (4 bytes)
+ *	%d is address(offset)
+ *
+ * Return:
+ *	%d for data readed
+ */
+static int rtw_mp_read_reg(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	char *pch, *pnext, *ptmp;
+	char *width_str;
+	char width;
+	char data[20], tmp[20];
+	u32 addr;
+	u32 ret, i = 0, j = 0, strtout = 0;
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	_rtw_memset(data, 0, 20);
+	_rtw_memset(tmp, 0, 20);
+	_rtw_memset(extra, 0, wrqu->length);
+
+	pch = input;
+	pnext = strpbrk(pch, ",.-");
+	if (pnext == NULL) {
+		kfree(input);
+		return -EINVAL;
+	}
+	*pnext = 0;
+	width_str = pch;
+
+	pch = pnext + 1;
+	if ((pch - input) >= wrqu->length) {
+		kfree(input);
+		return -EINVAL;
+	}
+	kfree(input);
+	addr = simple_strtoul(pch, &ptmp, 16);
+	if (addr > 0x3FFF)
+		return -EINVAL;
+
+	ret = 0;
+	width = width_str[0];
+	switch (width) {
+	case 'b':
+		/*  1 byte */
+		sprintf(extra, "%d\n",  rtw_read8(padapter, addr));
+		wrqu->length = strlen(extra);
+		break;
+	case 'w':
+		/*  2 bytes */
+		sprintf(data, "%04x\n", rtw_read16(padapter, addr));
+		for (i = 0; i <= strlen(data); i++) {
+			if (i%2 == 0) {
+				tmp[j] = ' ';
+				j++;
+			}
+			if (data[i] != '\0')
+				tmp[j] = data[i];
+			j++;
+		}
+		pch = tmp;
+		DBG_88E("pch =%s", pch);
+
+		while (*pch != '\0') {
+			pnext = strpbrk(pch, " ");
+			if (!pnext)
+				break;
+
+			pnext++;
+			if (*pnext != '\0') {
+				  strtout = simple_strtoul(pnext, &ptmp, 16);
+				  sprintf(extra, "%s %d", extra, strtout);
+			} else {
+				  break;
+			}
+			pch = pnext;
+		}
+		wrqu->length = 6;
+		break;
+	case 'd':
+		/*  4 bytes */
+		sprintf(data, "%08x", rtw_read32(padapter, addr));
+		/* add read data format blank */
+		for (i = 0; i <= strlen(data); i++) {
+			if (i%2 == 0) {
+				tmp[j] = ' ';
+				j++;
+			}
+			if (data[i] != '\0')
+				tmp[j] = data[i];
+
+			j++;
+		}
+		pch = tmp;
+		DBG_88E("pch =%s", pch);
+
+		while (*pch != '\0') {
+			pnext = strpbrk(pch, " ");
+			if (!pnext)
+				break;
+			pnext++;
+			if (*pnext != '\0') {
+				strtout = simple_strtoul(pnext, &ptmp, 16);
+				sprintf(extra, "%s %d", extra, strtout);
+			} else {
+				break;
+			}
+			pch = pnext;
+		}
+		wrqu->length = strlen(extra);
+		break;
+	default:
+		wrqu->length = 0;
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Input Format: %d,%x,%x
+ *	%d is RF path, should be smaller than MAX_RF_PATH_NUMS
+ *	1st %x is address(offset)
+ *	2st %x is data to write
+ */
+ static int rtw_mp_write_rf(struct net_device *dev,
+			    struct iw_request_info *info,
+			    struct iw_point *wrqu, char *extra)
+{
+	u32 path, addr, data;
+	int ret;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	ret = sscanf(extra, "%d,%x,%x", &path, &addr, &data);
+	if (ret < 3)
+		return -EINVAL;
+
+	if (path >= MAX_RF_PATH_NUMS)
+		return -EINVAL;
+	if (addr > 0xFF)
+		return -EINVAL;
+	if (data > 0xFFFFF)
+		return -EINVAL;
+
+	_rtw_memset(extra, 0, wrqu->length);
+
+	write_rfreg(padapter, path, addr, data);
+
+	sprintf(extra, "write_rf completed\n");
+	wrqu->length = strlen(extra);
+
+	return 0;
+}
+
+/*
+ * Input Format: %d,%x
+ *	%d is RF path, should be smaller than MAX_RF_PATH_NUMS
+ *	%x is address(offset)
+ *
+ * Return:
+ *	%d for data readed
+ */
+static int rtw_mp_read_rf(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	char *pch, *pnext, *ptmp;
+	char data[20], tmp[20];
+	u32 path, addr;
+	u32 ret, i = 0, j = 0, strtou = 0;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	ret = sscanf(input, "%d,%x", &path, &addr);
+	kfree(input);
+	if (ret < 2)
+		return -EINVAL;
+
+	if (path >= MAX_RF_PATH_NUMS)
+		return -EINVAL;
+	if (addr > 0xFF)
+		return -EINVAL;
+
+	_rtw_memset(extra, 0, wrqu->length);
+
+	sprintf(data, "%08x", read_rfreg(padapter, path, addr));
+	/* add read data format blank */
+	for (i = 0; i <= strlen(data); i++) {
+		if (i%2 == 0) {
+			tmp[j] = ' ';
+			j++;
+		}
+		tmp[j] = data[i];
+		j++;
+	}
+	pch = tmp;
+	DBG_88E("pch =%s", pch);
+
+	while (*pch != '\0') {
+		pnext = strpbrk(pch, " ");
+		pnext++;
+		if (*pnext != '\0') {
+			  strtou = simple_strtoul(pnext, &ptmp, 16);
+			  sprintf(extra, "%s %d", extra, strtou);
+		} else {
+			  break;
+		}
+		pch = pnext;
+	}
+	wrqu->length = strlen(extra);
+	return 0;
+}
+
+static int rtw_mp_start(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (padapter->registrypriv.mp_mode == 0) {
+		padapter->registrypriv.mp_mode = 1;
+
+		rtw_pm_set_ips(padapter, IPS_NONE);
+		LeaveAllPowerSaveMode(padapter);
+
+		MPT_InitializeAdapter(padapter, 1);
+	}
+	if (padapter->registrypriv.mp_mode == 0)
+		return -EPERM;
+	if (padapter->mppriv.mode == MP_OFF) {
+		if (mp_start_test(padapter) == _FAIL)
+			return -EPERM;
+		padapter->mppriv.mode = MP_ON;
+	}
+	return 0;
+}
+
+static int rtw_mp_stop(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (padapter->registrypriv.mp_mode == 1) {
+		MPT_DeInitAdapter(padapter);
+		padapter->registrypriv.mp_mode = 0;
+	}
+
+	if (padapter->mppriv.mode != MP_OFF) {
+		mp_stop_test(padapter);
+		padapter->mppriv.mode = MP_OFF;
+	}
+
+	return 0;
+}
+
+extern int wifirate2_ratetbl_inx(unsigned char rate);
+
+static int rtw_mp_rate(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u32 rate = MPT_RATE_1M;
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	rate = rtw_atoi(input);
+	sprintf(extra, "Set data rate to %d", rate);
+	kfree(input);
+	if (rate <= 0x7f)
+		rate = wifirate2_ratetbl_inx((u8)rate);
+	else
+		rate = (rate-0x80+MPT_RATE_MCS0);
+
+	if (rate >= MPT_RATE_LAST)
+		return -EINVAL;
+
+	padapter->mppriv.rateidx = rate;
+	Hal_SetDataRate(padapter);
+
+	wrqu->length = strlen(extra) + 1;
+	return 0;
+}
+
+static int rtw_mp_channel(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	u32	channel = 1;
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	channel = rtw_atoi(input);
+	sprintf(extra, "Change channel %d to channel %d", padapter->mppriv.channel, channel);
+
+	padapter->mppriv.channel = channel;
+	Hal_SetChannel(padapter);
+
+	wrqu->length = strlen(extra) + 1;
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_bandwidth(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u32 bandwidth = 0, sg = 0;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	sscanf(extra, "40M =%d, shortGI =%d", &bandwidth, &sg);
+
+	if (bandwidth != HT_CHANNEL_WIDTH_40)
+		bandwidth = HT_CHANNEL_WIDTH_20;
+
+	padapter->mppriv.bandwidth = (u8)bandwidth;
+	padapter->mppriv.preamble = sg;
+
+	SetBandwidth(padapter);
+
+	return 0;
+}
+
+static int rtw_mp_txpower(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u32		idx_a = 0, idx_b = 0;
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	sscanf(input, "patha =%d, pathb =%d", &idx_a, &idx_b);
+
+	sprintf(extra, "Set power level path_A:%d path_B:%d", idx_a, idx_b);
+	padapter->mppriv.txpoweridx = (u8)idx_a;
+	padapter->mppriv.txpoweridx_b = (u8)idx_b;
+	padapter->mppriv.bSetTxPower = 1;
+	Hal_SetAntennaPathPower(padapter);
+
+	wrqu->length = strlen(extra) + 1;
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_ant_tx(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u8 i;
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	u16 antenna = 0;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+
+	sprintf(extra, "switch Tx antenna to %s", input);
+
+	for (i = 0; i < strlen(input); i++) {
+		switch (input[i]) {
+		case 'a':
+			antenna |= ANTENNA_A;
+			break;
+		case 'b':
+			antenna |= ANTENNA_B;
+			break;
+		}
+	}
+	padapter->mppriv.antenna_tx = antenna;
+
+	Hal_SetAntenna(padapter);
+
+	wrqu->length = strlen(extra) + 1;
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_ant_rx(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u8 i;
+	u16 antenna = 0;
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	_rtw_memset(extra, 0, wrqu->length);
+
+	sprintf(extra, "switch Rx antenna to %s", input);
+
+	for (i = 0; i < strlen(input); i++) {
+		switch (input[i]) {
+		case 'a':
+			antenna |= ANTENNA_A;
+			break;
+		case 'b':
+			antenna |= ANTENNA_B;
+			break;
+		}
+	}
+
+	padapter->mppriv.antenna_rx = antenna;
+	Hal_SetAntenna(padapter);
+	wrqu->length = strlen(extra);
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_ctx(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u32 pkTx = 1, countPkTx = 1, cotuTx = 1, CarrSprTx = 1, scTx = 1, sgleTx = 1, stop = 1;
+	u32 bStartTest = 1;
+	u32 count = 0;
+	struct mp_priv *pmp_priv;
+	struct pkt_attrib *pattrib;
+
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	pmp_priv = &padapter->mppriv;
+
+	if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+			return -EFAULT;
+
+	DBG_88E("%s: in =%s\n", __func__, extra);
+
+	countPkTx = strncmp(extra, "count =", 5); /*  strncmp true is 0 */
+	cotuTx = strncmp(extra, "background", 20);
+	CarrSprTx = strncmp(extra, "background, cs", 20);
+	scTx = strncmp(extra, "background, sc", 20);
+	sgleTx = strncmp(extra, "background, stone", 20);
+	pkTx = strncmp(extra, "background, pkt", 20);
+	stop = strncmp(extra, "stop", 4);
+	sscanf(extra, "count =%d, pkt", &count);
+
+	_rtw_memset(extra, '\0', sizeof(extra));
+
+	if (stop == 0) {
+		bStartTest = 0; /*  To set Stop */
+		pmp_priv->tx.stop = 1;
+		sprintf(extra, "Stop continuous Tx");
+	} else {
+		bStartTest = 1;
+		if (pmp_priv->mode != MP_ON) {
+			if (pmp_priv->tx.stop != 1) {
+				DBG_88E("%s: MP_MODE != ON %d\n", __func__, pmp_priv->mode);
+				return  -EFAULT;
+			}
+		}
+	}
+
+	if (pkTx == 0 || countPkTx == 0)
+		pmp_priv->mode = MP_PACKET_TX;
+	if (sgleTx == 0)
+		pmp_priv->mode = MP_SINGLE_TONE_TX;
+	if (cotuTx == 0)
+		pmp_priv->mode = MP_CONTINUOUS_TX;
+	if (CarrSprTx == 0)
+		pmp_priv->mode = MP_CARRIER_SUPPRISSION_TX;
+	if (scTx == 0)
+		pmp_priv->mode = MP_SINGLE_CARRIER_TX;
+
+	switch (pmp_priv->mode) {
+	case MP_PACKET_TX:
+		if (bStartTest == 0) {
+			pmp_priv->tx.stop = 1;
+			pmp_priv->mode = MP_ON;
+			sprintf(extra, "Stop continuous Tx");
+		} else if (pmp_priv->tx.stop == 1) {
+			sprintf(extra, "Start continuous DA = ffffffffffff len = 1500 count =%u,\n", count);
+			pmp_priv->tx.stop = 0;
+			pmp_priv->tx.count = count;
+			pmp_priv->tx.payload = 2;
+			pattrib = &pmp_priv->tx.attrib;
+			pattrib->pktlen = 1500;
+			_rtw_memset(pattrib->dst, 0xFF, ETH_ALEN);
+			SetPacketTx(padapter);
+		} else {
+			return -EFAULT;
+		}
+			wrqu->length = strlen(extra);
+			return 0;
+	case MP_SINGLE_TONE_TX:
+		if (bStartTest != 0)
+			sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+		Hal_SetSingleToneTx(padapter, (u8)bStartTest);
+		break;
+	case MP_CONTINUOUS_TX:
+		if (bStartTest != 0)
+			sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+		Hal_SetContinuousTx(padapter, (u8)bStartTest);
+		break;
+	case MP_CARRIER_SUPPRISSION_TX:
+		if (bStartTest != 0) {
+			if (pmp_priv->rateidx <= MPT_RATE_11M) {
+				sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+				Hal_SetCarrierSuppressionTx(padapter, (u8)bStartTest);
+			} else {
+				sprintf(extra, "Specify carrier suppression but not CCK rate");
+			}
+		}
+		break;
+	case MP_SINGLE_CARRIER_TX:
+		if (bStartTest != 0)
+			sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes.");
+		Hal_SetSingleCarrierTx(padapter, (u8)bStartTest);
+		break;
+	default:
+		sprintf(extra, "Error! Continuous-Tx is not on-going.");
+		return -EFAULT;
+	}
+
+	if (bStartTest == 1 && pmp_priv->mode != MP_ON) {
+		struct mp_priv *pmp_priv = &padapter->mppriv;
+		if (pmp_priv->tx.stop == 0) {
+			pmp_priv->tx.stop = 1;
+			rtw_msleep_os(5);
+		}
+		pmp_priv->tx.stop = 0;
+		pmp_priv->tx.count = 1;
+		SetPacketTx(padapter);
+	} else {
+		pmp_priv->mode = MP_ON;
+	}
+
+	wrqu->length = strlen(extra);
+	return 0;
+}
+
+static int rtw_mp_arx(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u8 bStartRx = 0, bStopRx = 0, bQueryPhy;
+	u32 cckok = 0, cckcrc = 0, ofdmok = 0, ofdmcrc = 0, htok = 0, htcrc = 0, OFDM_FA = 0, CCK_FA = 0;
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (!input)
+		return -ENOMEM;
+
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	DBG_88E("%s: %s\n", __func__, input);
+
+	bStartRx = (strncmp(input, "start", 5) == 0) ? 1 : 0; /*  strncmp true is 0 */
+	bStopRx = (strncmp(input, "stop", 5) == 0) ? 1 : 0; /*  strncmp true is 0 */
+	bQueryPhy = (strncmp(input, "phy", 3) == 0) ? 1 : 0; /*  strncmp true is 0 */
+
+	if (bStartRx) {
+		sprintf(extra, "start");
+		SetPacketRx(padapter, bStartRx);
+	} else if (bStopRx) {
+		SetPacketRx(padapter, 0);
+		sprintf(extra, "Received packet OK:%d CRC error:%d", padapter->mppriv.rx_pktcount, padapter->mppriv.rx_crcerrpktcount);
+	} else if (bQueryPhy) {
+		/*
+		OFDM FA
+		RegCF0[15:0]
+		RegCF2[31:16]
+		RegDA0[31:16]
+		RegDA4[15:0]
+		RegDA4[31:16]
+		RegDA8[15:0]
+		CCK FA
+		(RegA5B<<8) | RegA5C
+		*/
+		cckok = read_bbreg(padapter, 0xf88, 0xffffffff);
+		cckcrc = read_bbreg(padapter, 0xf84, 0xffffffff);
+		ofdmok = read_bbreg(padapter, 0xf94, 0x0000FFFF);
+		ofdmcrc = read_bbreg(padapter, 0xf94, 0xFFFF0000);
+		htok = read_bbreg(padapter, 0xf90, 0x0000FFFF);
+		htcrc = read_bbreg(padapter, 0xf90, 0xFFFF0000);
+
+		OFDM_FA = read_bbreg(padapter, 0xcf0, 0x0000FFFF);
+		OFDM_FA = read_bbreg(padapter, 0xcf2, 0xFFFF0000);
+		OFDM_FA = read_bbreg(padapter, 0xda0, 0xFFFF0000);
+		OFDM_FA = read_bbreg(padapter, 0xda4, 0x0000FFFF);
+		OFDM_FA = read_bbreg(padapter, 0xda4, 0xFFFF0000);
+		OFDM_FA = read_bbreg(padapter, 0xda8, 0x0000FFFF);
+		CCK_FA = (rtw_read8(padapter, 0xa5b)<<8) | (rtw_read8(padapter, 0xa5c));
+
+		sprintf(extra, "Phy Received packet OK:%d CRC error:%d FA Counter: %d", cckok+ofdmok+htok, cckcrc+ofdmcrc+htcrc, OFDM_FA+CCK_FA);
+	}
+	wrqu->length = strlen(extra) + 1;
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_trx_query(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u32 txok, txfail, rxok, rxfail;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	txok = padapter->mppriv.tx.sended;
+	txfail = 0;
+	rxok = padapter->mppriv.rx_pktcount;
+	rxfail = padapter->mppriv.rx_crcerrpktcount;
+
+	_rtw_memset(extra, '\0', 128);
+
+	sprintf(extra, "Tx OK:%d, Tx Fail:%d, Rx OK:%d, CRC error:%d ", txok, txfail, rxok, rxfail);
+
+	wrqu->length = strlen(extra)+1;
+
+	return 0;
+}
+
+static int rtw_mp_pwrtrk(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	u8 enable;
+	u32 thermal;
+	s32 ret;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+	_rtw_memset(extra, 0, wrqu->length);
+
+	enable = 1;
+	if (wrqu->length > 1) {/*  not empty string */
+		if (strncmp(input, "stop", 4) == 0) {
+			enable = 0;
+			sprintf(extra, "mp tx power tracking stop");
+		} else if (sscanf(input, "ther =%d", &thermal)) {
+				ret = Hal_SetThermalMeter(padapter, (u8)thermal);
+				if (ret == _FAIL)
+					return -EPERM;
+				sprintf(extra, "mp tx power tracking start, target value =%d ok ", thermal);
+		} else {
+			kfree(input);
+			return -EINVAL;
+		}
+	}
+
+	kfree(input);
+	ret = Hal_SetPowerTracking(padapter, enable);
+	if (ret == _FAIL)
+		return -EPERM;
+
+	wrqu->length = strlen(extra);
+	return 0;
+}
+
+static int rtw_mp_psd(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+
+	strcpy(extra, input);
+
+	wrqu->length = mp_query_psd(padapter, extra);
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_thermal(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_point *wrqu, char *extra)
+{
+	u8 val;
+	u16 bwrite = 1;
+	u16 addr = EEPROM_THERMAL_METER_88E;
+
+	u16 cnt = 1;
+	u16 max_available_size = 0;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+		return -EFAULT;
+
+	 bwrite = strncmp(extra, "write", 6); /*  strncmp true is 0 */
+
+	 Hal_GetThermalMeter(padapter, &val);
+
+	 if (bwrite == 0) {
+			EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+			if (2 > max_available_size) {
+				DBG_88E("no available efuse!\n");
+				return -EFAULT;
+			}
+			if (rtw_efuse_map_write(padapter, addr, cnt, &val) == _FAIL) {
+				DBG_88E("rtw_efuse_map_write error\n");
+				return -EFAULT;
+			} else {
+				 sprintf(extra, " efuse write ok :%d", val);
+			}
+	 } else {
+			 sprintf(extra, "%d", val);
+	 }
+	wrqu->length = strlen(extra);
+
+	return 0;
+}
+
+static int rtw_mp_reset_stats(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	struct mp_priv *pmp_priv;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	pmp_priv = &padapter->mppriv;
+
+	pmp_priv->tx.sended = 0;
+	pmp_priv->tx_pktcount = 0;
+	pmp_priv->rx_pktcount = 0;
+	pmp_priv->rx_crcerrpktcount = 0;
+
+	/* reset phy counter */
+	write_bbreg(padapter, 0xf14, BIT16, 0x1);
+	rtw_msleep_os(10);
+	write_bbreg(padapter, 0xf14, BIT16, 0x0);
+
+	return 0;
+}
+
+static int rtw_mp_dump(struct net_device *dev,
+		       struct iw_request_info *info,
+		       struct iw_point *wrqu, char *extra)
+{
+	u32 value;
+	u8 rf_type, path_nums = 0;
+	u32 i, j = 1, path;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (strncmp(extra, "all", 4) == 0) {
+		DBG_88E("\n ======= MAC REG =======\n");
+		for (i = 0x0; i < 0x300; i += 4) {
+			if (j%4 == 1)
+				DBG_88E("0x%02x", i);
+			DBG_88E(" 0x%08x ", rtw_read32(padapter, i));
+			if ((j++)%4 == 0)
+				DBG_88E("\n");
+		}
+		for (i = 0x400; i < 0x1000; i += 4) {
+			if (j%4 == 1)
+				DBG_88E("0x%02x", i);
+			DBG_88E(" 0x%08x ", rtw_read32(padapter, i));
+			if ((j++)%4 == 0)
+				DBG_88E("\n");
+		}
+
+		j = 1;
+		rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+		DBG_88E("\n ======= RF REG =======\n");
+		if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type))
+			path_nums = 1;
+		else
+			path_nums = 2;
+
+		for (path = 0; path < path_nums; path++) {
+			for (i = 0; i < 0x34; i++) {
+				value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff);
+				if (j%4 == 1)
+					DBG_88E("0x%02x ", i);
+				DBG_88E(" 0x%08x ", value);
+				if ((j++)%4 == 0)
+					DBG_88E("\n");
+			}
+		}
+	}
+	return 0;
+}
+
+static int rtw_mp_phypara(struct net_device *dev,
+			struct iw_request_info *info,
+			struct iw_point *wrqu, char *extra)
+{
+	char	*input = kmalloc(wrqu->length, GFP_KERNEL);
+	u32		valxcap;
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+		kfree(input);
+		return -EFAULT;
+	}
+
+	DBG_88E("%s:iwpriv in =%s\n", __func__, input);
+
+	sscanf(input, "xcap =%d", &valxcap);
+
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_SetRFPath(struct net_device *dev,
+			struct iw_request_info *info,
+			union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	char	*input = kmalloc(wrqu->data.length, GFP_KERNEL);
+	u8 bMain = 1, bTurnoff = 1;
+
+	if (!input)
+		return -ENOMEM;
+	if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length))
+			return -EFAULT;
+	DBG_88E("%s:iwpriv in =%s\n", __func__, input);
+
+	bMain = strncmp(input, "1", 2); /*  strncmp true is 0 */
+	bTurnoff = strncmp(input, "0", 3); /*  strncmp true is 0 */
+
+	if (bMain == 0) {
+		MP_PHY_SetRFPathSwitch(padapter, true);
+		DBG_88E("%s:PHY_SetRFPathSwitch = true\n", __func__);
+	} else if (bTurnoff == 0) {
+		MP_PHY_SetRFPathSwitch(padapter, false);
+		DBG_88E("%s:PHY_SetRFPathSwitch = false\n", __func__);
+	}
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_QueryDrv(struct net_device *dev,
+			struct iw_request_info *info,
+			union iwreq_data *wrqu, char *extra)
+{
+	struct adapter *padapter = rtw_netdev_priv(dev);
+	char	*input = kmalloc(wrqu->data.length, GFP_KERNEL);
+	u8 qAutoLoad = 1;
+	struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+
+	if (!input)
+		return -ENOMEM;
+
+	if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length))
+			return -EFAULT;
+	DBG_88E("%s:iwpriv in =%s\n", __func__, input);
+
+	qAutoLoad = strncmp(input, "autoload", 8); /*  strncmp true is 0 */
+
+	if (qAutoLoad == 0) {
+		DBG_88E("%s:qAutoLoad\n", __func__);
+
+		if (pEEPROM->bautoload_fail_flag)
+			sprintf(extra, "fail");
+		else
+		sprintf(extra, "ok");
+	}
+	wrqu->data.length = strlen(extra) + 1;
+	kfree(input);
+	return 0;
+}
+
+static int rtw_mp_set(struct net_device *dev,
+		      struct iw_request_info *info,
+		      union iwreq_data *wdata, char *extra)
+{
+	struct iw_point *wrqu = (struct iw_point *)wdata;
+	u32 subcmd = wrqu->flags;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (padapter == NULL)
+		return -ENETDOWN;
+
+	if (extra == NULL) {
+		wrqu->length = 0;
+		return -EIO;
+	}
+
+	switch (subcmd) {
+	case MP_START:
+		DBG_88E("set case mp_start\n");
+		rtw_mp_start(dev, info, wrqu, extra);
+		 break;
+	case MP_STOP:
+		DBG_88E("set case mp_stop\n");
+		rtw_mp_stop(dev, info, wrqu, extra);
+		 break;
+	case MP_BANDWIDTH:
+		DBG_88E("set case mp_bandwidth\n");
+		rtw_mp_bandwidth(dev, info, wrqu, extra);
+		break;
+	case MP_RESET_STATS:
+		DBG_88E("set case MP_RESET_STATS\n");
+		rtw_mp_reset_stats(dev, info, wrqu, extra);
+		break;
+	case MP_SetRFPathSwh:
+		DBG_88E("set MP_SetRFPathSwitch\n");
+		rtw_mp_SetRFPath(dev, info, wdata, extra);
+		break;
+	case CTA_TEST:
+		DBG_88E("set CTA_TEST\n");
+		rtw_cta_test_start(dev, info, wdata, extra);
+		break;
+	}
+
+	return 0;
+}
+
+static int rtw_mp_get(struct net_device *dev,
+			struct iw_request_info *info,
+			union iwreq_data *wdata, char *extra)
+{
+	struct iw_point *wrqu = (struct iw_point *)wdata;
+	u32 subcmd = wrqu->flags;
+	struct adapter *padapter = rtw_netdev_priv(dev);
+
+	if (padapter == NULL)
+		return -ENETDOWN;
+	if (extra == NULL) {
+		wrqu->length = 0;
+		return -EIO;
+	}
+
+	switch (subcmd) {
+	case WRITE_REG:
+		rtw_mp_write_reg(dev, info, wrqu, extra);
+		 break;
+	case WRITE_RF:
+		rtw_mp_write_rf(dev, info, wrqu, extra);
+		 break;
+	case MP_PHYPARA:
+		DBG_88E("mp_get  MP_PHYPARA\n");
+		rtw_mp_phypara(dev, info, wrqu, extra);
+		break;
+	case MP_CHANNEL:
+		DBG_88E("set case mp_channel\n");
+		rtw_mp_channel(dev, info, wrqu, extra);
+		break;
+	case READ_REG:
+		DBG_88E("mp_get  READ_REG\n");
+		rtw_mp_read_reg(dev, info, wrqu, extra);
+		 break;
+	case READ_RF:
+		DBG_88E("mp_get  READ_RF\n");
+		rtw_mp_read_rf(dev, info, wrqu, extra);
+		break;
+	case MP_RATE:
+		DBG_88E("set case mp_rate\n");
+		rtw_mp_rate(dev, info, wrqu, extra);
+		break;
+	case MP_TXPOWER:
+		DBG_88E("set case MP_TXPOWER\n");
+		rtw_mp_txpower(dev, info, wrqu, extra);
+		break;
+	case MP_ANT_TX:
+		DBG_88E("set case MP_ANT_TX\n");
+		rtw_mp_ant_tx(dev, info, wrqu, extra);
+		break;
+	case MP_ANT_RX:
+		DBG_88E("set case MP_ANT_RX\n");
+		rtw_mp_ant_rx(dev, info, wrqu, extra);
+		break;
+	case MP_QUERY:
+		rtw_mp_trx_query(dev, info, wrqu, extra);
+		break;
+	case MP_CTX:
+		DBG_88E("set case MP_CTX\n");
+		rtw_mp_ctx(dev, info, wrqu, extra);
+		break;
+	case MP_ARX:
+		DBG_88E("set case MP_ARX\n");
+		rtw_mp_arx(dev, info, wrqu, extra);
+		break;
+	case EFUSE_GET:
+		DBG_88E("efuse get EFUSE_GET\n");
+		rtw_mp_efuse_get(dev, info, wdata, extra);
+		 break;
+	case MP_DUMP:
+		DBG_88E("set case MP_DUMP\n");
+		rtw_mp_dump(dev, info, wrqu, extra);
+		 break;
+	case MP_PSD:
+		DBG_88E("set case MP_PSD\n");
+		rtw_mp_psd(dev, info, wrqu, extra);
+		break;
+	case MP_THER:
+		DBG_88E("set case MP_THER\n");
+		rtw_mp_thermal(dev, info, wrqu, extra);
+		break;
+	case MP_QueryDrvStats:
+		DBG_88E("mp_get MP_QueryDrvStats\n");
+		rtw_mp_QueryDrv (dev, info, wdata, extra);
+		break;
+	case MP_PWRTRK:
+		DBG_88E("set case MP_PWRTRK\n");
+		rtw_mp_pwrtrk(dev, info, wrqu, extra);
+		break;
+	case EFUSE_SET:
+		DBG_88E("set case efuse set\n");
+		rtw_mp_efuse_set(dev, info, wdata, extra);
+		break;
+	}
+
+	rtw_msleep_os(10); /* delay 5ms for sending pkt before exit adb shell operation */
+	return 0;
+}
+
+static int rtw_tdls(struct net_device *dev,
+		    struct iw_request_info *info,
+		    union iwreq_data *wrqu, char *extra)
+{
+	return 0;
+}
+
+static int rtw_tdls_get(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu, char *extra)
+{
+	return 0;
+}
+
+static int rtw_test(
+	struct net_device *dev,
+	struct iw_request_info *info,
+	union iwreq_data *wrqu, char *extra)
+{
+	u32 len;
+	u8 *pbuf, *pch;
+	char *ptmp;
+	u8 *delim = ",";
+
+	DBG_88E("+%s\n", __func__);
+	len = wrqu->data.length;
+
+	pbuf = (u8 *)rtw_zmalloc(len);
+	if (pbuf == NULL) {
+		DBG_88E("%s: no memory!\n", __func__);
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(pbuf, wrqu->data.pointer, len)) {
+		kfree(pbuf);
+		DBG_88E("%s: copy from user fail!\n", __func__);
+		return -EFAULT;
+	}
+	DBG_88E("%s: string =\"%s\"\n", __func__, pbuf);
+
+	ptmp = (char *)pbuf;
+	pch = strsep(&ptmp, delim);
+	if ((pch == NULL) || (strlen(pch) == 0)) {
+		kfree(pbuf);
+		DBG_88E("%s: parameter error(level 1)!\n", __func__);
+		return -EFAULT;
+	}
+	kfree(pbuf);
+	return 0;
+}
+
+static iw_handler rtw_handlers[] = {
+	NULL,					/* SIOCSIWCOMMIT */
+	rtw_wx_get_name,		/* SIOCGIWNAME */
+	dummy,					/* SIOCSIWNWID */
+	dummy,					/* SIOCGIWNWID */
+	rtw_wx_set_freq,		/* SIOCSIWFREQ */
+	rtw_wx_get_freq,		/* SIOCGIWFREQ */
+	rtw_wx_set_mode,		/* SIOCSIWMODE */
+	rtw_wx_get_mode,		/* SIOCGIWMODE */
+	dummy,					/* SIOCSIWSENS */
+	rtw_wx_get_sens,		/* SIOCGIWSENS */
+	NULL,					/* SIOCSIWRANGE */
+	rtw_wx_get_range,		/* SIOCGIWRANGE */
+	rtw_wx_set_priv,		/* SIOCSIWPRIV */
+	NULL,					/* SIOCGIWPRIV */
+	NULL,					/* SIOCSIWSTATS */
+	NULL,					/* SIOCGIWSTATS */
+	dummy,					/* SIOCSIWSPY */
+	dummy,					/* SIOCGIWSPY */
+	NULL,					/* SIOCGIWTHRSPY */
+	NULL,					/* SIOCWIWTHRSPY */
+	rtw_wx_set_wap,		/* SIOCSIWAP */
+	rtw_wx_get_wap,		/* SIOCGIWAP */
+	rtw_wx_set_mlme,		/* request MLME operation; uses struct iw_mlme */
+	dummy,					/* SIOCGIWAPLIST -- depricated */
+	rtw_wx_set_scan,		/* SIOCSIWSCAN */
+	rtw_wx_get_scan,		/* SIOCGIWSCAN */
+	rtw_wx_set_essid,		/* SIOCSIWESSID */
+	rtw_wx_get_essid,		/* SIOCGIWESSID */
+	dummy,					/* SIOCSIWNICKN */
+	rtw_wx_get_nick,		/* SIOCGIWNICKN */
+	NULL,					/* -- hole -- */
+	NULL,					/* -- hole -- */
+	rtw_wx_set_rate,		/* SIOCSIWRATE */
+	rtw_wx_get_rate,		/* SIOCGIWRATE */
+	rtw_wx_set_rts,			/* SIOCSIWRTS */
+	rtw_wx_get_rts,			/* SIOCGIWRTS */
+	rtw_wx_set_frag,		/* SIOCSIWFRAG */
+	rtw_wx_get_frag,		/* SIOCGIWFRAG */
+	dummy,					/* SIOCSIWTXPOW */
+	dummy,					/* SIOCGIWTXPOW */
+	dummy,					/* SIOCSIWRETRY */
+	rtw_wx_get_retry,		/* SIOCGIWRETRY */
+	rtw_wx_set_enc,			/* SIOCSIWENCODE */
+	rtw_wx_get_enc,			/* SIOCGIWENCODE */
+	dummy,					/* SIOCSIWPOWER */
+	rtw_wx_get_power,		/* SIOCGIWPOWER */
+	NULL,					/*---hole---*/
+	NULL,					/*---hole---*/
+	rtw_wx_set_gen_ie,		/* SIOCSIWGENIE */
+	NULL,					/* SIOCGWGENIE */
+	rtw_wx_set_auth,		/* SIOCSIWAUTH */
+	NULL,					/* SIOCGIWAUTH */
+	rtw_wx_set_enc_ext,		/* SIOCSIWENCODEEXT */
+	NULL,					/* SIOCGIWENCODEEXT */
+	rtw_wx_set_pmkid,		/* SIOCSIWPMKSA */
+	NULL,					/*---hole---*/
+};
+
+static const struct iw_priv_args rtw_private_args[] = {
+	{
+		SIOCIWFIRSTPRIV + 0x0,
+		IW_PRIV_TYPE_CHAR | 0x7FF, 0, "write"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x1,
+		IW_PRIV_TYPE_CHAR | 0x7FF,
+		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "read"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x4,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x5,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setpid"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x6,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x7,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "get_sensitivity"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x8,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_prob_req_ie"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x9,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_assoc_req_ie"
+	},
+
+	{
+		SIOCIWFIRSTPRIV + 0xA,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "channel_plan"
+	},
+
+	{
+		SIOCIWFIRSTPRIV + 0xB,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dbg"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0xC,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "rfw"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0xD,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "rfr"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x10,
+		IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, 0, "p2p_set"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x11,
+		IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN, "p2p_get"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x12,
+		IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IFNAMSIZ, "p2p_get2"
+	},
+	{SIOCIWFIRSTPRIV + 0x13, IW_PRIV_TYPE_CHAR | 128, 0, "NULL"},
+	{
+		SIOCIWFIRSTPRIV + 0x14,
+		IW_PRIV_TYPE_CHAR  | 64, 0, "tdls"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x15,
+		IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN, "tdls_get"
+	},
+	{
+		SIOCIWFIRSTPRIV + 0x16,
+		IW_PRIV_TYPE_CHAR | 64, 0, "pm_set"
+	},
+
+	{SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ, 0, "rereg_nd_name"},
+
+	{SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"},
+	{SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"},
+	{SIOCIWFIRSTPRIV + 0x1D, IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test"
+	},
+
+	{SIOCIWFIRSTPRIV + 0x0E, IW_PRIV_TYPE_CHAR | 1024, 0, ""},  /* set */
+	{SIOCIWFIRSTPRIV + 0x0F, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ""},/* get */
+/* --- sub-ioctls definitions --- */
+
+	{MP_START, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_start"}, /* set */
+	{MP_PHYPARA, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_phypara"},/* get */
+	{MP_STOP, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_stop"}, /* set */
+	{MP_CHANNEL, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_channel"},/* get */
+	{MP_BANDWIDTH, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_bandwidth"}, /* set */
+	{MP_RATE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate"},/* get */
+	{MP_RESET_STATS, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_reset_stats"},
+	{MP_QUERY, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_query"}, /* get */
+	{READ_REG, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_reg"},
+	{MP_RATE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate"},
+	{READ_RF, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_rf"},
+	{MP_PSD, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_psd"},
+	{MP_DUMP, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_dump"},
+	{MP_TXPOWER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_txpower"},
+	{MP_ANT_TX, IW_PRIV_TYPE_CHAR | 1024,  IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_tx"},
+	{MP_ANT_RX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_rx"},
+	{WRITE_REG, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_reg"},
+	{WRITE_RF, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_rf"},
+	{MP_CTX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ctx"},
+	{MP_ARX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_arx"},
+	{MP_THER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ther"},
+	{EFUSE_SET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_set"},
+	{EFUSE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"},
+	{MP_PWRTRK, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_pwrtrk"},
+	{MP_QueryDrvStats, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_drvquery"},
+	{MP_IOCTL, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_ioctl"}, /*  mp_ioctl */
+	{MP_SetRFPathSwh, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_setrfpath"},
+	{CTA_TEST, IW_PRIV_TYPE_CHAR | 1024, 0, "cta_test"},
+};
+
+static iw_handler rtw_private_handler[] = {
+rtw_wx_write32,				/* 0x00 */
+rtw_wx_read32,				/* 0x01 */
+rtw_drvext_hdl,				/* 0x02 */
+rtw_mp_ioctl_hdl,			/* 0x03 */
+
+/*  for MM DTV platform */
+	rtw_get_ap_info,		/* 0x04 */
+
+	rtw_set_pid,			/* 0x05 */
+	rtw_wps_start,			/* 0x06 */
+
+	rtw_wx_get_sensitivity,		/* 0x07 */
+	rtw_wx_set_mtk_wps_probe_ie,	/* 0x08 */
+	rtw_wx_set_mtk_wps_ie,		/* 0x09 */
+
+/*  Set Channel depend on the country code */
+	rtw_wx_set_channel_plan,	/* 0x0A */
+
+	rtw_dbg_port,			/* 0x0B */
+	rtw_wx_write_rf,		/* 0x0C */
+	rtw_wx_read_rf,			/* 0x0D */
+
+	rtw_mp_set,			/* 0x0E */
+	rtw_mp_get,			/* 0x0F */
+	rtw_p2p_set,			/* 0x10 */
+	rtw_p2p_get,			/* 0x11 */
+	rtw_p2p_get2,			/* 0x12 */
+
+	NULL,				/* 0x13 */
+	rtw_tdls,			/* 0x14 */
+	rtw_tdls_get,			/* 0x15 */
+
+	rtw_pm_set,			/* 0x16 */
+	rtw_wx_priv_null,		/* 0x17 */
+	rtw_rereg_nd_name,		/* 0x18 */
+	rtw_wx_priv_null,		/* 0x19 */
+
+	rtw_mp_efuse_set,		/* 0x1A */
+	rtw_mp_efuse_get,		/* 0x1B */
+	NULL,				/*  0x1C is reserved for hostapd */
+	rtw_test,			/*  0x1D */
+};
+
+static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
+	struct iw_statistics *piwstats = &padapter->iwstats;
+	int tmp_level = 0;
+	int tmp_qual = 0;
+	int tmp_noise = 0;
+
+	if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+		piwstats->qual.qual = 0;
+		piwstats->qual.level = 0;
+		piwstats->qual.noise = 0;
+	} else {
+		tmp_level = padapter->recvpriv.signal_strength;
+		tmp_qual = padapter->recvpriv.signal_qual;
+		tmp_noise = padapter->recvpriv.noise;
+
+		piwstats->qual.level = tmp_level;
+		piwstats->qual.qual = tmp_qual;
+		piwstats->qual.noise = tmp_noise;
+	}
+	piwstats->qual.updated = IW_QUAL_ALL_UPDATED;/* IW_QUAL_DBM; */
+	return &padapter->iwstats;
+}
+
+struct iw_handler_def rtw_handlers_def = {
+	.standard = rtw_handlers,
+	.num_standard = sizeof(rtw_handlers) / sizeof(iw_handler),
+	.private = rtw_private_handler,
+	.private_args = (struct iw_priv_args *)rtw_private_args,
+	.num_private = sizeof(rtw_private_handler) / sizeof(iw_handler),
+	.num_private_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args),
+	.get_wireless_stats = rtw_get_wireless_stats,
+};
+
+/*  copy from net/wireless/wext.c start */
+/* ---------------------------------------------------------------- */
+/*
+ * Calculate size of private arguments
+ */
+static const char iw_priv_type_size[] = {
+	0,			      /* IW_PRIV_TYPE_NONE */
+	1,			      /* IW_PRIV_TYPE_BYTE */
+	1,			      /* IW_PRIV_TYPE_CHAR */
+	0,			      /* Not defined */
+	sizeof(__u32),		  /* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),	 /* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,			      /* Not defined */
+};
+
+static int get_priv_size(__u16 args)
+{
+	int num = args & IW_PRIV_SIZE_MASK;
+	int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	return num * iw_priv_type_size[type];
+}
+/*  copy from net/wireless/wext.c end */
+
+static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_data)
+{
+	int err = 0;
+	u8 *input = NULL;
+	u32 input_len = 0;
+	const char delim[] = " ";
+	u8 *output = NULL;
+	u32 output_len = 0;
+	u32 count = 0;
+	u8 *buffer = NULL;
+	u32 buffer_len = 0;
+	char *ptr = NULL;
+	u8 cmdname[17] = {0}; /*  IFNAMSIZ+1 */
+	u32 cmdlen;
+	s32 len;
+	u8 *extra = NULL;
+	u32 extra_size = 0;
+
+	s32 k;
+	const iw_handler *priv;		/* Private ioctl */
+	const struct iw_priv_args *priv_args;	/* Private ioctl description */
+	u32 num_priv_args;			/* Number of descriptions */
+	iw_handler handler;
+	int temp;
+	int subcmd = 0;				/* sub-ioctl index */
+	int offset = 0;				/* Space for sub-ioctl index */
+
+	union iwreq_data wdata;
+
+	memcpy(&wdata, wrq_data, sizeof(wdata));
+
+	input_len = wdata.data.length;
+	input = rtw_zmalloc(input_len);
+	if (NULL == input)
+		return -ENOMEM;
+	if (copy_from_user(input, wdata.data.pointer, input_len)) {
+		err = -EFAULT;
+		goto exit;
+	}
+	ptr = input;
+	len = input_len;
+
+	sscanf(ptr, "%16s", cmdname);
+	cmdlen = strlen(cmdname);
+	DBG_88E("%s: cmd =%s\n", __func__, cmdname);
+
+	/*  skip command string */
+	if (cmdlen > 0)
+		cmdlen += 1; /*  skip one space */
+	ptr += cmdlen;
+	len -= cmdlen;
+	DBG_88E("%s: parameters =%s\n", __func__, ptr);
+
+	priv = rtw_private_handler;
+	priv_args = rtw_private_args;
+	num_priv_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args);
+
+	if (num_priv_args == 0) {
+		err = -EOPNOTSUPP;
+		goto exit;
+	}
+
+	/* Search the correct ioctl */
+	k = -1;
+	while ((++k < num_priv_args) && strcmp(priv_args[k].name, cmdname));
+
+	/* If not found... */
+	if (k == num_priv_args) {
+		err = -EOPNOTSUPP;
+		goto exit;
+	}
+
+	/* Watch out for sub-ioctls ! */
+	if (priv_args[k].cmd < SIOCDEVPRIVATE) {
+		int j = -1;
+
+		/* Find the matching *real* ioctl */
+		while ((++j < num_priv_args) && ((priv_args[j].name[0] != '\0') ||
+			(priv_args[j].set_args != priv_args[k].set_args) ||
+			(priv_args[j].get_args != priv_args[k].get_args)));
+
+		/* If not found... */
+		if (j == num_priv_args) {
+			err = -EINVAL;
+			goto exit;
+		}
+
+		/* Save sub-ioctl number */
+		subcmd = priv_args[k].cmd;
+		/* Reserve one int (simplify alignment issues) */
+		offset = sizeof(__u32);
+		/* Use real ioctl definition from now on */
+		k = j;
+	}
+
+	buffer = rtw_zmalloc(4096);
+	if (NULL == buffer) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* If we have to set some data */
+	if ((priv_args[k].set_args & IW_PRIV_TYPE_MASK) &&
+	    (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) {
+		u8 *str;
+
+		switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) {
+		case IW_PRIV_TYPE_BYTE:
+			/* Fetch args */
+			count = 0;
+			do {
+				str = strsep(&ptr, delim);
+				if (NULL == str)
+					break;
+				sscanf(str, "%i", &temp);
+				buffer[count++] = (u8)temp;
+			} while (1);
+			buffer_len = count;
+			/* Number of args to fetch */
+			wdata.data.length = count;
+			if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+				wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+			break;
+		case IW_PRIV_TYPE_INT:
+			/* Fetch args */
+			count = 0;
+			do {
+				str = strsep(&ptr, delim);
+				if (NULL == str)
+					break;
+				sscanf(str, "%i", &temp);
+				((s32 *)buffer)[count++] = (s32)temp;
+			} while (1);
+			buffer_len = count * sizeof(s32);
+			/* Number of args to fetch */
+			wdata.data.length = count;
+			if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+				wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+			break;
+		case IW_PRIV_TYPE_CHAR:
+			if (len > 0) {
+				/* Size of the string to fetch */
+				wdata.data.length = len;
+				if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+					wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+
+				/* Fetch string */
+				memcpy(buffer, ptr, wdata.data.length);
+			} else {
+				wdata.data.length = 1;
+				buffer[0] = '\0';
+			}
+			buffer_len = wdata.data.length;
+			break;
+		default:
+			DBG_88E("%s: Not yet implemented...\n", __func__);
+			err = -1;
+			goto exit;
+		}
+
+		if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+		    (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) {
+			DBG_88E("%s: The command %s needs exactly %d argument(s)...\n",
+				__func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK);
+			err = -EINVAL;
+			goto exit;
+		}
+	} else {
+		/* if args to set */
+		wdata.data.length = 0L;
+	}
+
+	/* Those two tests are important. They define how the driver
+	* will have to handle the data */
+	if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+	    ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) {
+		/* First case : all SET args fit within wrq */
+		if (offset)
+			wdata.mode = subcmd;
+		memcpy(wdata.name + offset, buffer, IFNAMSIZ - offset);
+	} else {
+		if ((priv_args[k].set_args == 0) &&
+		    (priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+		    (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) {
+			/* Second case : no SET args, GET args fit within wrq */
+			if (offset)
+				wdata.mode = subcmd;
+		} else {
+			/* Third case : args won't fit in wrq, or variable number of args */
+			if (copy_to_user(wdata.data.pointer, buffer, buffer_len)) {
+				err = -EFAULT;
+				goto exit;
+			}
+			wdata.data.flags = subcmd;
+		}
+	}
+
+	kfree(input);
+	input = NULL;
+
+	extra_size = 0;
+	if (IW_IS_SET(priv_args[k].cmd)) {
+		/* Size of set arguments */
+		extra_size = get_priv_size(priv_args[k].set_args);
+
+		/* Does it fits in iwr ? */
+		if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+		    ((extra_size + offset) <= IFNAMSIZ))
+			extra_size = 0;
+	} else {
+		/* Size of get arguments */
+		extra_size = get_priv_size(priv_args[k].get_args);
+
+		/* Does it fits in iwr ? */
+		if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+		    (extra_size <= IFNAMSIZ))
+			extra_size = 0;
+	}
+
+	if (extra_size == 0) {
+		extra = (u8 *)&wdata;
+		kfree(buffer);
+		buffer = NULL;
+	} else {
+		extra = buffer;
+	}
+
+	handler = priv[priv_args[k].cmd - SIOCIWFIRSTPRIV];
+	err = handler(dev, NULL, &wdata, extra);
+
+	/* If we have to get some data */
+	if ((priv_args[k].get_args & IW_PRIV_TYPE_MASK) &&
+	    (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) {
+		int j;
+		int n = 0;	/* number of args */
+		u8 str[20] = {0};
+
+		/* Check where is the returned data */
+		if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+		    (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ))
+			n = priv_args[k].get_args & IW_PRIV_SIZE_MASK;
+		else
+			n = wdata.data.length;
+
+		output = rtw_zmalloc(4096);
+		if (NULL == output) {
+			err =  -ENOMEM;
+			goto exit;
+		}
+		switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) {
+		case IW_PRIV_TYPE_BYTE:
+			/* Display args */
+			for (j = 0; j < n; j++) {
+				sprintf(str, "%d  ", extra[j]);
+				len = strlen(str);
+				output_len = strlen(output);
+				if ((output_len + len + 1) > 4096) {
+					err = -E2BIG;
+					goto exit;
+				}
+				memcpy(output+output_len, str, len);
+			}
+			break;
+		case IW_PRIV_TYPE_INT:
+			/* Display args */
+			for (j = 0; j < n; j++) {
+				sprintf(str, "%d  ", ((__s32 *)extra)[j]);
+				len = strlen(str);
+				output_len = strlen(output);
+				if ((output_len + len + 1) > 4096) {
+					err = -E2BIG;
+					goto exit;
+				}
+				memcpy(output+output_len, str, len);
+			}
+			break;
+		case IW_PRIV_TYPE_CHAR:
+			/* Display args */
+			memcpy(output, extra, n);
+			break;
+		default:
+			DBG_88E("%s: Not yet implemented...\n", __func__);
+			err = -1;
+			goto exit;
+		}
+
+		output_len = strlen(output) + 1;
+		wrq_data->data.length = output_len;
+		if (copy_to_user(wrq_data->data.pointer, output, output_len)) {
+			err = -EFAULT;
+			goto exit;
+		}
+	} else {
+		/* if args to set */
+		wrq_data->data.length = 0;
+	}
+
+exit:
+	kfree(input);
+	kfree(buffer);
+	kfree(output);
+	return err;
+}
+
+#include <rtw_android.h>
+int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct iwreq *wrq = (struct iwreq *)rq;
+	int ret = 0;
+
+	switch (cmd) {
+	case RTL_IOCTL_WPA_SUPPLICANT:
+		ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
+		break;
+#ifdef CONFIG_88EU_AP_MODE
+	case RTL_IOCTL_HOSTAPD:
+		ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
+		break;
+#endif /*  CONFIG_88EU_AP_MODE */
+	case SIOCDEVPRIVATE:
+		ret = rtw_ioctl_wext_private(dev, &wrq->u);
+		break;
+	case (SIOCDEVPRIVATE+1):
+		ret = rtw_android_priv_cmd(dev, rq, cmd);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
new file mode 100644
index 0000000..57d1ff7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -0,0 +1,246 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+
+#define _MLME_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <mlme_osdep.h>
+
+void rtw_join_timeout_handler (void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+
+	_rtw_join_timeout_handler(adapter);
+}
+
+
+void _rtw_scan_timeout_handler (void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+
+	rtw_scan_timeout_handler(adapter);
+}
+
+static void _dynamic_check_timer_handlder(void *FunctionContext)
+{
+	struct adapter *adapter = (struct adapter *)FunctionContext;
+
+	if (adapter->registrypriv.mp_mode == 1)
+		return;
+	rtw_dynamic_check_timer_handlder(adapter);
+	_set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000);
+}
+
+void rtw_init_mlme_timer(struct adapter *padapter)
+{
+	struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	_init_timer(&(pmlmepriv->assoc_timer), padapter->pnetdev, rtw_join_timeout_handler, padapter);
+	_init_timer(&(pmlmepriv->scan_to_timer), padapter->pnetdev, _rtw_scan_timeout_handler, padapter);
+	_init_timer(&(pmlmepriv->dynamic_chk_timer), padapter->pnetdev, _dynamic_check_timer_handlder, padapter);
+}
+
+void rtw_os_indicate_connect(struct adapter *adapter)
+{
+_func_enter_;
+	rtw_indicate_wx_assoc_event(adapter);
+	netif_carrier_on(adapter->pnetdev);
+	if (adapter->pid[2] != 0)
+		rtw_signal_process(adapter->pid[2], SIGALRM);
+_func_exit_;
+}
+
+void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted)
+{
+	indicate_wx_scan_complete_event(padapter);
+}
+
+static struct rt_pmkid_list backup_pmkid[NUM_PMKID_CACHE];
+
+void rtw_reset_securitypriv(struct adapter *adapter)
+{
+	u8	backup_index = 0;
+	u8	backup_counter = 0x00;
+	u32	backup_time = 0;
+
+	if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+		/* 802.1x */
+		/*  We have to backup the PMK information for WiFi PMK Caching test item. */
+		/*  Backup the btkip_countermeasure information. */
+		/*  When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */
+		_rtw_memset(&backup_pmkid[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+		memcpy(&backup_pmkid[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+		backup_index = adapter->securitypriv.PMKIDIndex;
+		backup_counter = adapter->securitypriv.btkip_countermeasure;
+		backup_time = adapter->securitypriv.btkip_countermeasure_time;
+		_rtw_memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv));
+
+		/*  Restore the PMK information to securitypriv structure for the following connection. */
+		memcpy(&adapter->securitypriv.PMKIDList[0],
+			    &backup_pmkid[0],
+			    sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+		adapter->securitypriv.PMKIDIndex = backup_index;
+		adapter->securitypriv.btkip_countermeasure = backup_counter;
+		adapter->securitypriv.btkip_countermeasure_time = backup_time;
+		adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+		adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+	} else {
+		/* reset values in securitypriv */
+		struct security_priv *psec_priv = &adapter->securitypriv;
+
+		psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;  /* open system */
+		psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+		psec_priv->dot11PrivacyKeyIndex = 0;
+		psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+		psec_priv->dot118021XGrpKeyid = 1;
+		psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
+		psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
+	}
+}
+
+void rtw_os_indicate_disconnect(struct adapter *adapter)
+{
+_func_enter_;
+	netif_carrier_off(adapter->pnetdev); /*  Do it first for tx broadcast pkt after disconnection issue! */
+	rtw_indicate_wx_disassoc_event(adapter);
+	 rtw_reset_securitypriv(adapter);
+_func_exit_;
+}
+
+void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie)
+{
+	uint	len;
+	u8	*buff, *p, i;
+	union iwreq_data wrqu;
+
+_func_enter_;
+	RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
+		 ("+rtw_report_sec_ie, authmode=%d\n", authmode));
+	buff = NULL;
+	if (authmode == _WPA_IE_ID_) {
+		RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
+			 ("rtw_report_sec_ie, authmode=%d\n", authmode));
+		buff = rtw_malloc(IW_CUSTOM_MAX);
+		if (!buff)
+			goto exit;
+		_rtw_memset(buff, 0, IW_CUSTOM_MAX);
+		p = buff;
+		p += sprintf(p, "ASSOCINFO(ReqIEs =");
+		len = sec_ie[1]+2;
+		len =  (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX;
+		for (i = 0; i < len; i++)
+			p += sprintf(p, "%02x", sec_ie[i]);
+		p += sprintf(p, ")");
+		_rtw_memset(&wrqu, 0, sizeof(wrqu));
+		wrqu.data.length = p-buff;
+		wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ?
+				   wrqu.data.length : IW_CUSTOM_MAX;
+		wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff);
+		kfree(buff);
+	}
+exit:
+_func_exit_;
+}
+
+static void _survey_timer_hdl(void *FunctionContext)
+{
+	struct adapter *padapter = (struct adapter *)FunctionContext;
+
+	survey_timer_hdl(padapter);
+}
+
+static void _link_timer_hdl(void *FunctionContext)
+{
+	struct adapter *padapter = (struct adapter *)FunctionContext;
+	link_timer_hdl(padapter);
+}
+
+static void _addba_timer_hdl(void *FunctionContext)
+{
+	struct sta_info *psta = (struct sta_info *)FunctionContext;
+	addba_timer_hdl(psta);
+}
+
+void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta)
+{
+	_init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta);
+}
+
+void init_mlme_ext_timer(struct adapter *padapter)
+{
+	struct	mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+	_init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter);
+	_init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter);
+}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *psta)
+{
+	union iwreq_data wrqu;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	if (psta == NULL)
+		return;
+
+	if (psta->aid > NUM_STA)
+		return;
+
+	if (pstapriv->sta_aid[psta->aid - 1] != psta)
+		return;
+
+
+	wrqu.addr.sa_family = ARPHRD_ETHER;
+
+	memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+	DBG_88E("+rtw_indicate_sta_assoc_event\n");
+
+	wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
+}
+
+void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *psta)
+{
+	union iwreq_data wrqu;
+	struct sta_priv *pstapriv = &padapter->stapriv;
+
+	if (psta == NULL)
+		return;
+
+	if (psta->aid > NUM_STA)
+		return;
+
+	if (pstapriv->sta_aid[psta->aid - 1] != psta)
+		return;
+
+
+	wrqu.addr.sa_family = ARPHRD_ETHER;
+
+	memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+	DBG_88E("+rtw_indicate_sta_disassoc_event\n");
+
+	wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
+}
+
+#endif
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
new file mode 100644
index 0000000..63bc913
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -0,0 +1,1251 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _OS_INTFS_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <xmit_osdep.h>
+#include <recv_osdep.h>
+#include <hal_intf.h>
+#include <rtw_ioctl.h>
+#include <rtw_version.h>
+
+#include <usb_osintf.h>
+#include <usb_hal.h>
+#include <rtw_br_ext.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
+MODULE_AUTHOR("Realtek Semiconductor Corp.");
+MODULE_VERSION(DRIVERVERSION);
+
+#define CONFIG_BR_EXT_BRNAME "br0"
+#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */
+
+/* module param defaults */
+static int rtw_chip_version = 0x00;
+static int rtw_rfintfs = HWPI;
+static int rtw_lbkmode;/* RTL8712_AIR_TRX; */
+static int rtw_network_mode = Ndis802_11IBSS;/* Ndis802_11Infrastructure; infra, ad-hoc, auto */
+static int rtw_channel = 1;/* ad-hoc support requirement */
+static int rtw_wireless_mode = WIRELESS_11BG_24N;
+static int rtw_vrtl_carrier_sense = AUTO_VCS;
+static int rtw_vcs_type = RTS_CTS;/*  */
+static int rtw_rts_thresh = 2347;/*  */
+static int rtw_frag_thresh = 2346;/*  */
+static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */
+static int rtw_scan_mode = 1;/* active, passive */
+static int rtw_adhoc_tx_pwr = 1;
+static int rtw_soft_ap;
+static int rtw_power_mgnt = 1;
+static int rtw_ips_mode = IPS_NORMAL;
+
+static int rtw_smart_ps = 2;
+
+module_param(rtw_ips_mode, int, 0644);
+MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode");
+
+static int rtw_debug = 1;
+static int rtw_radio_enable = 1;
+static int rtw_long_retry_lmt = 7;
+static int rtw_short_retry_lmt = 7;
+static int rtw_busy_thresh = 40;
+static int rtw_ack_policy = NORMAL_ACK;
+
+static int rtw_mp_mode;
+
+static int rtw_software_encrypt;
+static int rtw_software_decrypt;
+
+static int rtw_acm_method;/*  0:By SW 1:By HW. */
+
+static int rtw_wmm_enable = 1;/*  default is set to enable the wmm. */
+static int rtw_uapsd_enable;
+static int rtw_uapsd_max_sp = NO_LIMIT;
+static int rtw_uapsd_acbk_en;
+static int rtw_uapsd_acbe_en;
+static int rtw_uapsd_acvi_en;
+static int rtw_uapsd_acvo_en;
+
+int rtw_ht_enable = 1;
+int rtw_cbw40_enable = 3; /*  0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */
+int rtw_ampdu_enable = 1;/* for enable tx_ampdu */
+static int rtw_rx_stbc = 1;/*  0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
+static int rtw_ampdu_amsdu;/*  0: disabled, 1:enabled, 2:auto */
+
+static int rtw_lowrate_two_xmit = 1;/* Use 2 path Tx to transmit MCS0~7 and legacy mode */
+
+static int rtw_rf_config = RF_819X_MAX_TYPE;  /* auto */
+static int rtw_low_power;
+static int rtw_wifi_spec;
+static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX;
+static int rtw_AcceptAddbaReq = true;/*  0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */
+
+static int rtw_antdiv_cfg = 2; /*  0:OFF , 1:ON, 2:decide by Efuse config */
+static int rtw_antdiv_type; /* 0:decide by efuse  1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2:  for 88EE, 1Tx and 2Rx are diversity.(2 Ant, Tx and RxCG are both on aux port, RxCS is on main port), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */
+
+static int rtw_enusbss;/* 0:disable, 1:enable */
+
+static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */
+
+static int rtw_hwpwrp_detect; /* HW power  ping detect 0:disable , 1:enable */
+
+static int rtw_hw_wps_pbc = 1;
+
+int rtw_mc2u_disable;
+
+static int rtw_80211d;
+
+static char *ifname = "wlan%d";
+module_param(ifname, charp, 0644);
+MODULE_PARM_DESC(ifname, "The default name to allocate for first interface");
+
+static char *if2name = "wlan%d";
+module_param(if2name, charp, 0644);
+MODULE_PARM_DESC(if2name, "The default name to allocate for second interface");
+
+char *rtw_initmac;  /*  temp mac address if users want to use instead of the mac address in Efuse */
+
+module_param(rtw_initmac, charp, 0644);
+module_param(rtw_channel_plan, int, 0644);
+module_param(rtw_chip_version, int, 0644);
+module_param(rtw_rfintfs, int, 0644);
+module_param(rtw_lbkmode, int, 0644);
+module_param(rtw_network_mode, int, 0644);
+module_param(rtw_channel, int, 0644);
+module_param(rtw_mp_mode, int, 0644);
+module_param(rtw_wmm_enable, int, 0644);
+module_param(rtw_vrtl_carrier_sense, int, 0644);
+module_param(rtw_vcs_type, int, 0644);
+module_param(rtw_busy_thresh, int, 0644);
+module_param(rtw_ht_enable, int, 0644);
+module_param(rtw_cbw40_enable, int, 0644);
+module_param(rtw_ampdu_enable, int, 0644);
+module_param(rtw_rx_stbc, int, 0644);
+module_param(rtw_ampdu_amsdu, int, 0644);
+module_param(rtw_lowrate_two_xmit, int, 0644);
+module_param(rtw_rf_config, int, 0644);
+module_param(rtw_power_mgnt, int, 0644);
+module_param(rtw_smart_ps, int, 0644);
+module_param(rtw_low_power, int, 0644);
+module_param(rtw_wifi_spec, int, 0644);
+module_param(rtw_antdiv_cfg, int, 0644);
+module_param(rtw_antdiv_type, int, 0644);
+module_param(rtw_enusbss, int, 0644);
+module_param(rtw_hwpdn_mode, int, 0644);
+module_param(rtw_hwpwrp_detect, int, 0644);
+module_param(rtw_hw_wps_pbc, int, 0644);
+
+static uint rtw_max_roaming_times = 2;
+module_param(rtw_max_roaming_times, uint, 0644);
+MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try");
+
+static int rtw_fw_iol = 1;/*  0:Disable, 1:enable, 2:by usb speed */
+module_param(rtw_fw_iol, int, 0644);
+MODULE_PARM_DESC(rtw_fw_iol, "FW IOL");
+
+module_param(rtw_mc2u_disable, int, 0644);
+
+module_param(rtw_80211d, int, 0644);
+MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism");
+
+static uint rtw_notch_filter = RTW_NOTCH_FILTER;
+module_param(rtw_notch_filter, uint, 0644);
+MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P");
+module_param_named(debug, rtw_debug, int, 0444);
+MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)");
+
+/* dummy routines */
+void rtw_proc_remove_one(struct net_device *dev)
+{
+}
+
+void rtw_proc_init_one(struct net_device *dev)
+{
+}
+
+#if 0	/* TODO: Convert these to /sys */
+void rtw_proc_init_one(struct net_device *dev)
+{
+	struct proc_dir_entry *dir_dev = NULL;
+	struct proc_dir_entry *entry = NULL;
+	struct adapter	*padapter = rtw_netdev_priv(dev);
+	u8 rf_type;
+
+	if (rtw_proc == NULL) {
+		memcpy(rtw_proc_name, DRV_NAME, sizeof(DRV_NAME));
+
+		rtw_proc = create_proc_entry(rtw_proc_name, S_IFDIR, init_net.proc_net);
+		if (rtw_proc == NULL) {
+			DBG_88E(KERN_ERR "Unable to create rtw_proc directory\n");
+			return;
+		}
+
+		entry = create_proc_read_entry("ver_info", S_IFREG | S_IRUGO, rtw_proc, proc_get_drv_version, dev);
+		if (!entry) {
+			pr_info("Unable to create_proc_read_entry!\n");
+			return;
+		}
+	}
+
+	if (padapter->dir_dev == NULL) {
+		padapter->dir_dev = create_proc_entry(dev->name,
+					  S_IFDIR | S_IRUGO | S_IXUGO,
+					  rtw_proc);
+		dir_dev = padapter->dir_dev;
+		if (dir_dev == NULL) {
+			if (rtw_proc_cnt == 0) {
+				if (rtw_proc) {
+					remove_proc_entry(rtw_proc_name, init_net.proc_net);
+					rtw_proc = NULL;
+				}
+			}
+
+			pr_info("Unable to create dir_dev directory\n");
+			return;
+		}
+	} else {
+		return;
+	}
+
+	rtw_proc_cnt++;
+
+	entry = create_proc_read_entry("write_reg", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_write_reg, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_write_reg;
+
+	entry = create_proc_read_entry("read_reg", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_read_reg, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_read_reg;
+
+
+	entry = create_proc_read_entry("fwstate", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_fwstate, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("sec_info", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_sec_info, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("mlmext_state", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_mlmext_state, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("qos_option", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_qos_option, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("ht_option", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_ht_option, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("rf_info", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_rf_info, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("ap_info", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_ap_info, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("adapter_state", S_IFREG | S_IRUGO,
+				   dir_dev, proc_getstruct adapter_state, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("trx_info", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_trx_info, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("mac_reg_dump1", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_mac_reg_dump1, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("mac_reg_dump2", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_mac_reg_dump2, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("mac_reg_dump3", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_mac_reg_dump3, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("bb_reg_dump1", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_bb_reg_dump1, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("bb_reg_dump2", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_bb_reg_dump2, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("bb_reg_dump3", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_bb_reg_dump3, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("rf_reg_dump1", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_rf_reg_dump1, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("rf_reg_dump2", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_rf_reg_dump2, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+	if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) {
+		entry = create_proc_read_entry("rf_reg_dump3", S_IFREG | S_IRUGO,
+					   dir_dev, proc_get_rf_reg_dump3, dev);
+		if (!entry) {
+			pr_info("Unable to create_proc_read_entry!\n");
+			return;
+		}
+
+		entry = create_proc_read_entry("rf_reg_dump4", S_IFREG | S_IRUGO,
+					   dir_dev, proc_get_rf_reg_dump4, dev);
+		if (!entry) {
+			pr_info("Unable to create_proc_read_entry!\n");
+			return;
+		}
+	}
+
+#ifdef CONFIG_88EU_AP_MODE
+
+	entry = create_proc_read_entry("all_sta_info", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_all_sta_info, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+#endif
+
+	entry = create_proc_read_entry("best_channel", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_best_channel, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+
+	entry = create_proc_read_entry("rx_signal", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_rx_signal, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_rx_signal;
+	entry = create_proc_read_entry("ht_enable", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_ht_enable, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_ht_enable;
+
+	entry = create_proc_read_entry("cbw40_enable", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_cbw40_enable, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_cbw40_enable;
+
+	entry = create_proc_read_entry("ampdu_enable", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_ampdu_enable, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_ampdu_enable;
+
+	entry = create_proc_read_entry("rx_stbc", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_rx_stbc, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_rx_stbc;
+
+	entry = create_proc_read_entry("path_rssi", S_IFREG | S_IRUGO,
+					dir_dev, proc_get_two_path_rssi, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry = create_proc_read_entry("rssi_disp", S_IFREG | S_IRUGO,
+				   dir_dev, proc_get_rssi_disp, dev);
+	if (!entry) {
+		pr_info("Unable to create_proc_read_entry!\n");
+		return;
+	}
+	entry->write_proc = proc_set_rssi_disp;
+}
+
+void rtw_proc_remove_one(struct net_device *dev)
+{
+	struct proc_dir_entry *dir_dev = NULL;
+	struct adapter	*padapter = rtw_netdev_priv(dev);
+	u8 rf_type;
+
+	dir_dev = padapter->dir_dev;
+	padapter->dir_dev = NULL;
+
+	if (dir_dev) {
+		remove_proc_entry("write_reg", dir_dev);
+		remove_proc_entry("read_reg", dir_dev);
+		remove_proc_entry("fwstate", dir_dev);
+		remove_proc_entry("sec_info", dir_dev);
+		remove_proc_entry("mlmext_state", dir_dev);
+		remove_proc_entry("qos_option", dir_dev);
+		remove_proc_entry("ht_option", dir_dev);
+		remove_proc_entry("rf_info", dir_dev);
+		remove_proc_entry("ap_info", dir_dev);
+		remove_proc_entry("adapter_state", dir_dev);
+		remove_proc_entry("trx_info", dir_dev);
+		remove_proc_entry("mac_reg_dump1", dir_dev);
+		remove_proc_entry("mac_reg_dump2", dir_dev);
+		remove_proc_entry("mac_reg_dump3", dir_dev);
+		remove_proc_entry("bb_reg_dump1", dir_dev);
+		remove_proc_entry("bb_reg_dump2", dir_dev);
+		remove_proc_entry("bb_reg_dump3", dir_dev);
+		remove_proc_entry("rf_reg_dump1", dir_dev);
+		remove_proc_entry("rf_reg_dump2", dir_dev);
+		rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+		if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) {
+			remove_proc_entry("rf_reg_dump3", dir_dev);
+			remove_proc_entry("rf_reg_dump4", dir_dev);
+		}
+#ifdef CONFIG_88EU_AP_MODE
+		remove_proc_entry("all_sta_info", dir_dev);
+#endif
+
+		remove_proc_entry("best_channel", dir_dev);
+		remove_proc_entry("rx_signal", dir_dev);
+		remove_proc_entry("cbw40_enable", dir_dev);
+		remove_proc_entry("ht_enable", dir_dev);
+		remove_proc_entry("ampdu_enable", dir_dev);
+		remove_proc_entry("rx_stbc", dir_dev);
+		remove_proc_entry("path_rssi", dir_dev);
+		remove_proc_entry("rssi_disp", dir_dev);
+		remove_proc_entry(dev->name, rtw_proc);
+		dir_dev = NULL;
+	} else {
+		return;
+	}
+	rtw_proc_cnt--;
+
+	if (rtw_proc_cnt == 0) {
+		if (rtw_proc) {
+			remove_proc_entry("ver_info", rtw_proc);
+
+			remove_proc_entry(rtw_proc_name, init_net.proc_net);
+			rtw_proc = NULL;
+		}
+	}
+}
+#endif
+
+static uint loadparam(struct adapter *padapter,  struct  net_device *pnetdev)
+{
+	uint status = _SUCCESS;
+	struct registry_priv  *registry_par = &padapter->registrypriv;
+
+_func_enter_;
+
+	GlobalDebugLevel = rtw_debug;
+	registry_par->chip_version = (u8)rtw_chip_version;
+	registry_par->rfintfs = (u8)rtw_rfintfs;
+	registry_par->lbkmode = (u8)rtw_lbkmode;
+	registry_par->network_mode  = (u8)rtw_network_mode;
+
+	memcpy(registry_par->ssid.Ssid, "ANY", 3);
+	registry_par->ssid.SsidLength = 3;
+
+	registry_par->channel = (u8)rtw_channel;
+	registry_par->wireless_mode = (u8)rtw_wireless_mode;
+	registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ;
+	registry_par->vcs_type = (u8)rtw_vcs_type;
+	registry_par->rts_thresh = (u16)rtw_rts_thresh;
+	registry_par->frag_thresh = (u16)rtw_frag_thresh;
+	registry_par->preamble = (u8)rtw_preamble;
+	registry_par->scan_mode = (u8)rtw_scan_mode;
+	registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr;
+	registry_par->soft_ap =  (u8)rtw_soft_ap;
+	registry_par->smart_ps =  (u8)rtw_smart_ps;
+	registry_par->power_mgnt = (u8)rtw_power_mgnt;
+	registry_par->ips_mode = (u8)rtw_ips_mode;
+	registry_par->radio_enable = (u8)rtw_radio_enable;
+	registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt;
+	registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt;
+	registry_par->busy_thresh = (u16)rtw_busy_thresh;
+	registry_par->ack_policy = (u8)rtw_ack_policy;
+	registry_par->mp_mode = (u8)rtw_mp_mode;
+	registry_par->software_encrypt = (u8)rtw_software_encrypt;
+	registry_par->software_decrypt = (u8)rtw_software_decrypt;
+	registry_par->acm_method = (u8)rtw_acm_method;
+
+	 /* UAPSD */
+	registry_par->wmm_enable = (u8)rtw_wmm_enable;
+	registry_par->uapsd_enable = (u8)rtw_uapsd_enable;
+	registry_par->uapsd_max_sp = (u8)rtw_uapsd_max_sp;
+	registry_par->uapsd_acbk_en = (u8)rtw_uapsd_acbk_en;
+	registry_par->uapsd_acbe_en = (u8)rtw_uapsd_acbe_en;
+	registry_par->uapsd_acvi_en = (u8)rtw_uapsd_acvi_en;
+	registry_par->uapsd_acvo_en = (u8)rtw_uapsd_acvo_en;
+
+	registry_par->ht_enable = (u8)rtw_ht_enable;
+	registry_par->cbw40_enable = (u8)rtw_cbw40_enable;
+	registry_par->ampdu_enable = (u8)rtw_ampdu_enable;
+	registry_par->rx_stbc = (u8)rtw_rx_stbc;
+	registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu;
+	registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit;
+	registry_par->rf_config = (u8)rtw_rf_config;
+	registry_par->low_power = (u8)rtw_low_power;
+	registry_par->wifi_spec = (u8)rtw_wifi_spec;
+	registry_par->channel_plan = (u8)rtw_channel_plan;
+	registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq;
+	registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg;
+	registry_par->antdiv_type = (u8)rtw_antdiv_type;
+	registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode;/* 0:disable, 1:enable, 2:by EFUSE config */
+	registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect;/* 0:disable, 1:enable */
+	registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc;
+
+	registry_par->max_roaming_times = (u8)rtw_max_roaming_times;
+
+	registry_par->fw_iol = rtw_fw_iol;
+
+	registry_par->enable80211d = (u8)rtw_80211d;
+	snprintf(registry_par->ifname, 16, "%s", ifname);
+	snprintf(registry_par->if2name, 16, "%s", if2name);
+	registry_par->notch_filter = (u8)rtw_notch_filter;
+_func_exit_;
+	return status;
+}
+
+static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+	struct sockaddr *addr = p;
+
+	if (!padapter->bup)
+		memcpy(padapter->eeprompriv.mac_addr, addr->sa_data, ETH_ALEN);
+
+	return 0;
+}
+
+static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+	struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+	struct recv_priv *precvpriv = &(padapter->recvpriv);
+
+	padapter->stats.tx_packets = pxmitpriv->tx_pkts;/* pxmitpriv->tx_pkts++; */
+	padapter->stats.rx_packets = precvpriv->rx_pkts;/* precvpriv->rx_pkts++; */
+	padapter->stats.tx_dropped = pxmitpriv->tx_drop;
+	padapter->stats.rx_dropped = precvpriv->rx_drop;
+	padapter->stats.tx_bytes = pxmitpriv->tx_bytes;
+	padapter->stats.rx_bytes = precvpriv->rx_bytes;
+	return &padapter->stats;
+}
+
+/*
+ * AC to queue mapping
+ *
+ * AC_VO -> queue 0
+ * AC_VI -> queue 1
+ * AC_BE -> queue 2
+ * AC_BK -> queue 3
+ */
+static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
+
+/* Given a data frame determine the 802.1p/1d tag to use. */
+static unsigned int rtw_classify8021d(struct sk_buff *skb)
+{
+	unsigned int dscp;
+
+	/* skb->priority values from 256->263 are magic values to
+	 * directly indicate a specific 802.1d priority.  This is used
+	 * to allow 802.1d priority to be passed directly in from VLAN
+	 * tags, etc.
+	 */
+	if (skb->priority >= 256 && skb->priority <= 263)
+		return skb->priority - 256;
+
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		dscp = ip_hdr(skb)->tos & 0xfc;
+		break;
+	default:
+		return 0;
+	}
+
+	return dscp >> 5;
+}
+
+static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+	struct adapter	*padapter = rtw_netdev_priv(dev);
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+	skb->priority = rtw_classify8021d(skb);
+
+	if (pmlmepriv->acm_mask != 0)
+		skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority);
+
+	return rtw_1d_to_queue[skb->priority];
+}
+
+u16 rtw_recv_select_queue(struct sk_buff *skb)
+{
+	struct iphdr *piphdr;
+	unsigned int dscp;
+	__be16	eth_type;
+	u32 priority;
+	u8 *pdata = skb->data;
+
+	memcpy(&eth_type, pdata+(ETH_ALEN<<1), 2);
+
+	switch (eth_type) {
+	case htons(ETH_P_IP):
+		piphdr = (struct iphdr *)(pdata+ETH_HLEN);
+		dscp = piphdr->tos & 0xfc;
+		priority = dscp >> 5;
+		break;
+	default:
+		priority = 0;
+	}
+
+	return rtw_1d_to_queue[priority];
+}
+
+static const struct net_device_ops rtw_netdev_ops = {
+	.ndo_open = netdev_open,
+	.ndo_stop = netdev_close,
+	.ndo_start_xmit = rtw_xmit_entry,
+	.ndo_select_queue	= rtw_select_queue,
+	.ndo_set_mac_address = rtw_net_set_mac_address,
+	.ndo_get_stats = rtw_net_get_stats,
+	.ndo_do_ioctl = rtw_ioctl,
+};
+
+int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname)
+{
+	if (dev_alloc_name(pnetdev, ifname) < 0)
+		RT_TRACE(_module_os_intfs_c_, _drv_err_, ("dev_alloc_name, fail!\n"));
+
+	netif_carrier_off(pnetdev);
+	return 0;
+}
+
+struct net_device *rtw_init_netdev(struct adapter *old_padapter)
+{
+	struct adapter *padapter;
+	struct net_device *pnetdev;
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n"));
+
+	if (old_padapter != NULL)
+		pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(struct adapter), (void *)old_padapter);
+	else
+		pnetdev = rtw_alloc_etherdev(sizeof(struct adapter));
+
+	if (!pnetdev)
+		return NULL;
+
+	padapter = rtw_netdev_priv(pnetdev);
+	padapter->pnetdev = pnetdev;
+	DBG_88E("register rtw_netdev_ops to netdev_ops\n");
+	pnetdev->netdev_ops = &rtw_netdev_ops;
+	pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */
+	pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def;
+
+	/* step 2. */
+	loadparam(padapter, pnetdev);
+
+	return pnetdev;
+}
+
+u32 rtw_start_drv_threads(struct adapter *padapter)
+{
+	u32 _status = _SUCCESS;
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_start_drv_threads\n"));
+
+	padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD");
+	if (IS_ERR(padapter->cmdThread))
+		_status = _FAIL;
+	else
+		_rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); /* wait for cmd_thread to run */
+
+	rtw_hal_start_thread(padapter);
+	return _status;
+}
+
+void rtw_stop_drv_threads(struct adapter *padapter)
+{
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads\n"));
+
+	/* Below is to termindate rtw_cmd_thread & event_thread... */
+	_rtw_up_sema(&padapter->cmdpriv.cmd_queue_sema);
+	if (padapter->cmdThread)
+		_rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema);
+
+	rtw_hal_stop_thread(padapter);
+}
+
+static u8 rtw_init_default_value(struct adapter *padapter)
+{
+	u8 ret  = _SUCCESS;
+	struct registry_priv *pregistrypriv = &padapter->registrypriv;
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+	/* xmit_priv */
+	pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense;
+	pxmitpriv->vcs = pregistrypriv->vcs_type;
+	pxmitpriv->vcs_type = pregistrypriv->vcs_type;
+	pxmitpriv->frag_len = pregistrypriv->frag_thresh;
+
+	/* mlme_priv */
+	pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+	pmlmepriv->scan_mode = SCAN_ACTIVE;
+
+	/* ht_priv */
+	pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */
+
+	/* security_priv */
+	psecuritypriv->binstallGrpkey = _FAIL;
+	psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt;
+	psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt;
+	psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+	psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+	psecuritypriv->dot11PrivacyKeyIndex = 0;
+	psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+	psecuritypriv->dot118021XGrpKeyid = 1;
+	psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+	psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled;
+
+	/* registry_priv */
+	rtw_init_registrypriv_dev_network(padapter);
+	rtw_update_registrypriv_dev_network(padapter);
+
+	/* hal_priv */
+	rtw_hal_def_value_init(padapter);
+
+	/* misc. */
+	padapter->bReadPortCancel = false;
+	padapter->bWritePortCancel = false;
+	padapter->bRxRSSIDisplay = 0;
+	padapter->bNotifyChannelChange = 0;
+#ifdef CONFIG_88EU_P2P
+	padapter->bShowGetP2PState = 1;
+#endif
+	return ret;
+}
+
+u8 rtw_reset_drv_sw(struct adapter *padapter)
+{
+	u8	ret8 = _SUCCESS;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+	/* hal_priv */
+	rtw_hal_def_value_init(padapter);
+	padapter->bReadPortCancel = false;
+	padapter->bWritePortCancel = false;
+	padapter->bRxRSSIDisplay = 0;
+	pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+
+	padapter->xmitpriv.tx_pkts = 0;
+	padapter->recvpriv.rx_pkts = 0;
+
+	pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+
+	_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING);
+
+	rtw_hal_sreset_reset_value(padapter);
+	pwrctrlpriv->pwr_state_check_cnts = 0;
+
+	/* mlmeextpriv */
+	padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE;
+
+	rtw_set_signal_stat_timer(&padapter->recvpriv);
+
+	return ret8;
+}
+
+u8 rtw_init_drv_sw(struct adapter *padapter)
+{
+	u8	ret8 = _SUCCESS;
+
+_func_enter_;
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw\n"));
+
+	if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) {
+		RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init cmd_priv\n"));
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+	padapter->cmdpriv.padapter = padapter;
+
+	if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL) {
+		RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init evt_priv\n"));
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+	if (rtw_init_mlme_priv(padapter) == _FAIL) {
+		RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_priv\n"));
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+#ifdef CONFIG_88EU_P2P
+	rtw_init_wifidirect_timers(padapter);
+	init_wifidirect_info(padapter, P2P_ROLE_DISABLE);
+	reset_global_wifidirect_info(padapter);
+#endif /* CONFIG_88EU_P2P */
+
+	if (init_mlme_ext_priv(padapter) == _FAIL) {
+		RT_TRACE(_module_os_intfs_c_, _drv_err_, ("\n Can't init mlme_ext_priv\n"));
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+	if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) {
+		DBG_88E("Can't _rtw_init_xmit_priv\n");
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+	if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) {
+		DBG_88E("Can't _rtw_init_recv_priv\n");
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+	if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) {
+		DBG_88E("Can't _rtw_init_sta_priv\n");
+		ret8 = _FAIL;
+		goto exit;
+	}
+
+	padapter->stapriv.padapter = padapter;
+
+	rtw_init_bcmc_stainfo(padapter);
+
+	rtw_init_pwrctrl_priv(padapter);
+
+	if (init_mp_priv(padapter) == _FAIL)
+		DBG_88E("%s: initialize MP private data Fail!\n", __func__);
+
+	ret8 = rtw_init_default_value(padapter);
+
+	rtw_hal_dm_init(padapter);
+	rtw_hal_sw_led_init(padapter);
+
+	rtw_hal_sreset_init(padapter);
+
+	_rtw_spinlock_init(&padapter->br_ext_lock);
+
+exit:
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw\n"));
+
+	_func_exit_;
+
+	return ret8;
+}
+
+void rtw_cancel_all_timer(struct adapter *padapter)
+{
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer\n"));
+
+	_cancel_timer_ex(&padapter->mlmepriv.assoc_timer);
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel association timer complete!\n"));
+
+	_cancel_timer_ex(&padapter->mlmepriv.scan_to_timer);
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel scan_to_timer!\n"));
+
+	_cancel_timer_ex(&padapter->mlmepriv.dynamic_chk_timer);
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel dynamic_chk_timer!\n"));
+
+	/*  cancel sw led timer */
+	rtw_hal_sw_led_deinit(padapter);
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("rtw_cancel_all_timer:cancel DeInitSwLeds!\n"));
+
+	_cancel_timer_ex(&padapter->pwrctrlpriv.pwr_state_check_timer);
+
+	_cancel_timer_ex(&padapter->recvpriv.signal_stat_timer);
+	/* cancel dm timer */
+	rtw_hal_dm_deinit(padapter);
+}
+
+u8 rtw_free_drv_sw(struct adapter *padapter)
+{
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw"));
+
+	/* we can call rtw_p2p_enable here, but: */
+	/*  1. rtw_p2p_enable may have IO operation */
+	/*  2. rtw_p2p_enable is bundled with wext interface */
+	#ifdef CONFIG_88EU_P2P
+	{
+		struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+		if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+			_cancel_timer_ex(&pwdinfo->find_phase_timer);
+			_cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+			_cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
+			rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+		}
+	}
+	#endif
+
+
+	_rtw_spinlock_free(&padapter->br_ext_lock);
+
+	free_mlme_ext_priv(&padapter->mlmeextpriv);
+
+	rtw_free_cmd_priv(&padapter->cmdpriv);
+
+	rtw_free_evt_priv(&padapter->evtpriv);
+
+	rtw_free_mlme_priv(&padapter->mlmepriv);
+	_rtw_free_xmit_priv(&padapter->xmitpriv);
+
+	_rtw_free_sta_priv(&padapter->stapriv); /* will free bcmc_stainfo here */
+
+	_rtw_free_recv_priv(&padapter->recvpriv);
+
+	rtw_free_pwrctrl_priv(padapter);
+
+	rtw_hal_free_data(padapter);
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== rtw_free_drv_sw\n"));
+
+	/* free the old_pnetdev */
+	if (padapter->rereg_nd_name_priv.old_pnetdev) {
+		free_netdev(padapter->rereg_nd_name_priv.old_pnetdev);
+		padapter->rereg_nd_name_priv.old_pnetdev = NULL;
+	}
+
+	/*  clear pbuddystruct adapter to avoid access wrong pointer. */
+	if (padapter->pbuddy_adapter != NULL)
+		padapter->pbuddy_adapter->pbuddy_adapter = NULL;
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw\n"));
+
+	return _SUCCESS;
+}
+
+void netdev_br_init(struct net_device *netdev)
+{
+	struct adapter *adapter = (struct adapter *)rtw_netdev_priv(netdev);
+
+	rcu_read_lock();
+
+	if (rcu_dereference(adapter->pnetdev->rx_handler_data)) {
+		struct net_device *br_netdev;
+		struct net *devnet = NULL;
+
+		devnet = dev_net(netdev);
+		br_netdev = dev_get_by_name(devnet, CONFIG_BR_EXT_BRNAME);
+		if (br_netdev) {
+			memcpy(adapter->br_mac, br_netdev->dev_addr, ETH_ALEN);
+			dev_put(br_netdev);
+		} else {
+			pr_info("%s()-%d: dev_get_by_name(%s) failed!",
+				__func__, __LINE__, CONFIG_BR_EXT_BRNAME);
+		}
+	}
+	adapter->ethBrExtInfo.addPPPoETag = 1;
+
+	rcu_read_unlock();
+}
+
+int _netdev_open(struct net_device *pnetdev)
+{
+	uint status;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+	struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - dev_open\n"));
+	DBG_88E("+88eu_drv - drv_open, bup =%d\n", padapter->bup);
+
+	if (pwrctrlpriv->ps_flag) {
+		padapter->net_closed = false;
+		goto netdev_open_normal_process;
+	}
+
+	if (!padapter->bup) {
+		padapter->bDriverStopped = false;
+		padapter->bSurpriseRemoved = false;
+		padapter->bCardDisableWOHSM = false;
+
+		status = rtw_hal_init(padapter);
+		if (status == _FAIL) {
+			RT_TRACE(_module_os_intfs_c_, _drv_err_, ("rtl88eu_hal_init(): Can't init h/w!\n"));
+			goto netdev_open_error;
+		}
+
+		pr_info("MAC Address = %pM\n", pnetdev->dev_addr);
+
+		status = rtw_start_drv_threads(padapter);
+		if (status == _FAIL) {
+			pr_info("Initialize driver software resource Failed!\n");
+			goto netdev_open_error;
+		}
+
+		if (init_hw_mlme_ext(padapter) == _FAIL) {
+			pr_info("can't init mlme_ext_priv\n");
+			goto netdev_open_error;
+		}
+		if (padapter->intf_start)
+			padapter->intf_start(padapter);
+		rtw_proc_init_one(pnetdev);
+
+		rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+		padapter->bup = true;
+	}
+	padapter->net_closed = false;
+
+	_set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000);
+
+	padapter->pwrctrlpriv.bips_processing = false;
+	rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+
+	if (!rtw_netif_queue_stopped(pnetdev))
+		rtw_netif_start_queue(pnetdev);
+	else
+		rtw_netif_wake_queue(pnetdev);
+
+	netdev_br_init(pnetdev);
+
+netdev_open_normal_process:
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - dev_open\n"));
+	DBG_88E("-88eu_drv - drv_open, bup =%d\n", padapter->bup);
+	return 0;
+
+netdev_open_error:
+	padapter->bup = false;
+	netif_carrier_off(pnetdev);
+	rtw_netif_stop_queue(pnetdev);
+	RT_TRACE(_module_os_intfs_c_, _drv_err_, ("-88eu_drv - dev_open, fail!\n"));
+	DBG_88E("-88eu_drv - drv_open fail, bup =%d\n", padapter->bup);
+	return -1;
+}
+
+int netdev_open(struct net_device *pnetdev)
+{
+	int ret;
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+
+	_enter_critical_mutex(padapter->hw_init_mutex, NULL);
+	ret = _netdev_open(pnetdev);
+	_exit_critical_mutex(padapter->hw_init_mutex, NULL);
+	return ret;
+}
+
+static int  ips_netdrv_open(struct adapter *padapter)
+{
+	int status = _SUCCESS;
+	padapter->net_closed = false;
+	DBG_88E("===> %s.........\n", __func__);
+
+	padapter->bDriverStopped = false;
+	padapter->bSurpriseRemoved = false;
+	padapter->bCardDisableWOHSM = false;
+
+	status = rtw_hal_init(padapter);
+	if (status == _FAIL) {
+		RT_TRACE(_module_os_intfs_c_, _drv_err_, ("ips_netdrv_open(): Can't init h/w!\n"));
+		goto netdev_open_error;
+	}
+
+	if (padapter->intf_start)
+		padapter->intf_start(padapter);
+
+	rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+	_set_timer(&padapter->mlmepriv.dynamic_chk_timer, 5000);
+
+	 return _SUCCESS;
+
+netdev_open_error:
+	DBG_88E("-ips_netdrv_open - drv_open failure, bup =%d\n", padapter->bup);
+
+	return _FAIL;
+}
+
+
+int rtw_ips_pwr_up(struct adapter *padapter)
+{
+	int result;
+	u32 start_time = rtw_get_current_time();
+	DBG_88E("===>  rtw_ips_pwr_up..............\n");
+	rtw_reset_drv_sw(padapter);
+
+	result = ips_netdrv_open(padapter);
+
+	rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+	DBG_88E("<===  rtw_ips_pwr_up.............. in %dms\n", rtw_get_passing_time_ms(start_time));
+	return result;
+}
+
+void rtw_ips_pwr_down(struct adapter *padapter)
+{
+	u32 start_time = rtw_get_current_time();
+	DBG_88E("===> rtw_ips_pwr_down...................\n");
+
+	padapter->bCardDisableWOHSM = true;
+	padapter->net_closed = true;
+
+	rtw_led_control(padapter, LED_CTL_POWER_OFF);
+
+	rtw_ips_dev_unload(padapter);
+	padapter->bCardDisableWOHSM = false;
+	DBG_88E("<=== rtw_ips_pwr_down..................... in %dms\n", rtw_get_passing_time_ms(start_time));
+}
+
+void rtw_ips_dev_unload(struct adapter *padapter)
+{
+	DBG_88E("====> %s...\n", __func__);
+
+	rtw_hal_set_hwreg(padapter, HW_VAR_FIFO_CLEARN_UP, NULL);
+
+	if (padapter->intf_stop)
+		padapter->intf_stop(padapter);
+
+	/* s5. */
+	if (!padapter->bSurpriseRemoved)
+		rtw_hal_deinit(padapter);
+}
+
+int pm_netdev_open(struct net_device *pnetdev, u8 bnormal)
+{
+	int status;
+
+	if (bnormal)
+		status = netdev_open(pnetdev);
+	else
+		status =  (_SUCCESS == ips_netdrv_open((struct adapter *)rtw_netdev_priv(pnetdev))) ? (0) : (-1);
+	return status;
+}
+
+int netdev_close(struct net_device *pnetdev)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+88eu_drv - drv_close\n"));
+
+	if (padapter->pwrctrlpriv.bInternalAutoSuspend) {
+		if (padapter->pwrctrlpriv.rf_pwrstate == rf_off)
+			padapter->pwrctrlpriv.ps_flag = true;
+	}
+	padapter->net_closed = true;
+
+	if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) {
+		DBG_88E("(2)88eu_drv - drv_close, bup =%d, hw_init_completed =%d\n",
+			padapter->bup, padapter->hw_init_completed);
+
+		/* s1. */
+		if (pnetdev) {
+			if (!rtw_netif_queue_stopped(pnetdev))
+				rtw_netif_stop_queue(pnetdev);
+		}
+
+		/* s2. */
+		LeaveAllPowerSaveMode(padapter);
+		rtw_disassoc_cmd(padapter, 500, false);
+		/* s2-2.  indicate disconnect to os */
+		rtw_indicate_disconnect(padapter);
+		/* s2-3. */
+		rtw_free_assoc_resources(padapter, 1);
+		/* s2-4. */
+		rtw_free_network_queue(padapter, true);
+		/*  Close LED */
+		rtw_led_control(padapter, LED_CTL_POWER_OFF);
+	}
+
+	nat25_db_cleanup(padapter);
+
+#ifdef CONFIG_88EU_P2P
+	rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
+#endif /* CONFIG_88EU_P2P */
+
+	RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-88eu_drv - drv_close\n"));
+	DBG_88E("-88eu_drv - drv_close, bup =%d\n", padapter->bup);
+	return 0;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
new file mode 100644
index 0000000..4e0bfb7
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -0,0 +1,815 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+
+#define _OSDEP_SERVICE_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <linux/vmalloc.h>
+#include <rtw_ioctl_set.h>
+
+/*
+* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE
+* @return: one of RTW_STATUS_CODE
+*/
+inline int RTW_STATUS_CODE(int error_code)
+{
+	if (error_code >= 0)
+		return _SUCCESS;
+	return _FAIL;
+}
+
+u32 rtw_atoi(u8 *s)
+{
+	int num = 0, flag = 0;
+	int i;
+	for (i = 0; i <= strlen(s); i++) {
+		if (s[i] >= '0' && s[i] <= '9')
+			num = num * 10 + s[i] - '0';
+		else if (s[0] == '-' && i == 0)
+			flag = 1;
+		else
+			break;
+	}
+	if (flag == 1)
+		num = num * -1;
+	 return num;
+}
+
+inline u8 *_rtw_vmalloc(u32 sz)
+{
+	u8	*pbuf;
+	pbuf = vmalloc(sz);
+	return pbuf;
+}
+
+inline u8 *_rtw_zvmalloc(u32 sz)
+{
+	u8	*pbuf;
+	pbuf = _rtw_vmalloc(sz);
+	if (pbuf != NULL)
+		memset(pbuf, 0, sz);
+	return pbuf;
+}
+
+inline void _rtw_vmfree(u8 *pbuf, u32 sz)
+{
+	vfree(pbuf);
+}
+
+u8 *_rtw_malloc(u32 sz)
+{
+	u8	*pbuf = NULL;
+
+	pbuf = kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	return pbuf;
+}
+
+u8 *_rtw_zmalloc(u32 sz)
+{
+	u8	*pbuf = _rtw_malloc(sz);
+
+	if (pbuf != NULL)
+		memset(pbuf, 0, sz);
+	return pbuf;
+}
+
+void *rtw_malloc2d(int h, int w, int size)
+{
+	int j;
+
+	void **a = (void **)rtw_zmalloc(h*sizeof(void *) + h*w*size);
+	if (a == NULL) {
+		pr_info("%s: alloc memory fail!\n", __func__);
+		return NULL;
+	}
+
+	for (j = 0; j < h; j++)
+		a[j] = ((char *)(a+h)) + j*w*size;
+
+	return a;
+}
+
+void rtw_mfree2d(void *pbuf, int h, int w, int size)
+{
+	kfree(pbuf);
+}
+
+int _rtw_memcmp(void *dst, void *src, u32 sz)
+{
+/* under Linux/GNU/GLibc, the return value of memcmp for two same
+ * mem. chunk is 0 */
+	if (!(memcmp(dst, src, sz)))
+		return true;
+	else
+		return false;
+}
+
+void _rtw_memset(void *pbuf, int c, u32 sz)
+{
+	memset(pbuf, c, sz);
+}
+
+void _rtw_init_listhead(struct list_head *list)
+{
+	INIT_LIST_HEAD(list);
+}
+
+/*
+For the following list_xxx operations,
+caller must guarantee the atomic context.
+Otherwise, there will be racing condition.
+*/
+u32	rtw_is_list_empty(struct list_head *phead)
+{
+	if (list_empty(phead))
+		return true;
+	else
+		return false;
+}
+
+void rtw_list_insert_head(struct list_head *plist, struct list_head *phead)
+{
+	list_add(plist, phead);
+}
+
+void rtw_list_insert_tail(struct list_head *plist, struct list_head *phead)
+{
+	list_add_tail(plist, phead);
+}
+
+/*
+Caller must check if the list is empty before calling rtw_list_delete
+*/
+
+void _rtw_init_sema(struct semaphore *sema, int init_val)
+{
+	sema_init(sema, init_val);
+}
+
+void _rtw_free_sema(struct semaphore *sema)
+{
+}
+
+void _rtw_up_sema(struct semaphore *sema)
+{
+	up(sema);
+}
+
+u32 _rtw_down_sema(struct semaphore *sema)
+{
+	if (down_interruptible(sema))
+		return _FAIL;
+	else
+		return _SUCCESS;
+}
+
+void	_rtw_mutex_init(struct mutex *pmutex)
+{
+	mutex_init(pmutex);
+}
+
+void	_rtw_mutex_free(struct mutex *pmutex)
+{
+	mutex_destroy(pmutex);
+}
+
+void	_rtw_spinlock_init(spinlock_t *plock)
+{
+	spin_lock_init(plock);
+}
+
+void	_rtw_spinlock_free(spinlock_t *plock)
+{
+}
+
+void	_rtw_init_queue(struct __queue *pqueue)
+{
+	_rtw_init_listhead(&(pqueue->queue));
+	_rtw_spinlock_init(&(pqueue->lock));
+}
+
+u32	  _rtw_queue_empty(struct __queue *pqueue)
+{
+	return rtw_is_list_empty(&(pqueue->queue));
+}
+
+u32 rtw_end_of_queue_search(struct list_head *head, struct list_head *plist)
+{
+	if (head == plist)
+		return true;
+	else
+		return false;
+}
+
+u32	rtw_get_current_time(void)
+{
+	return jiffies;
+}
+
+inline u32 rtw_systime_to_ms(u32 systime)
+{
+	return systime * 1000 / HZ;
+}
+
+inline u32 rtw_ms_to_systime(u32 ms)
+{
+	return ms * HZ / 1000;
+}
+
+/*  the input parameter start use the same unit as returned by
+ *  rtw_get_current_time */
+inline s32 rtw_get_passing_time_ms(u32 start)
+{
+	return rtw_systime_to_ms(jiffies-start);
+}
+
+inline s32 rtw_get_time_interval_ms(u32 start, u32 end)
+{
+	return rtw_systime_to_ms(end-start);
+}
+
+void rtw_sleep_schedulable(int ms)
+{
+	u32 delta;
+
+	delta = (ms * HZ)/1000;/* ms) */
+	if (delta == 0)
+		delta = 1;/*  1 ms */
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (schedule_timeout(delta) != 0)
+		return;
+}
+
+void rtw_msleep_os(int ms)
+{
+	msleep((unsigned int)ms);
+}
+
+void rtw_usleep_os(int us)
+{
+	if (1 < (us/1000))
+		msleep(1);
+	else
+		msleep((us/1000) + 1);
+}
+
+void rtw_mdelay_os(int ms)
+{
+	mdelay((unsigned long)ms);
+}
+
+void rtw_udelay_os(int us)
+{
+	udelay((unsigned long)us);
+}
+
+void rtw_yield_os(void)
+{
+	yield();
+}
+
+#define RTW_SUSPEND_LOCK_NAME "rtw_wifi"
+
+inline void rtw_suspend_lock_init(void)
+{
+}
+
+inline void rtw_suspend_lock_uninit(void)
+{
+}
+
+inline void rtw_lock_suspend(void)
+{
+}
+
+inline void rtw_unlock_suspend(void)
+{
+}
+
+inline void ATOMIC_SET(ATOMIC_T *v, int i)
+{
+	atomic_set(v, i);
+}
+
+inline int ATOMIC_READ(ATOMIC_T *v)
+{
+	return atomic_read(v);
+}
+
+inline void ATOMIC_ADD(ATOMIC_T *v, int i)
+{
+	atomic_add(i, v);
+}
+
+inline void ATOMIC_SUB(ATOMIC_T *v, int i)
+{
+	atomic_sub(i, v);
+}
+
+inline void ATOMIC_INC(ATOMIC_T *v)
+{
+	atomic_inc(v);
+}
+
+inline void ATOMIC_DEC(ATOMIC_T *v)
+{
+	atomic_dec(v);
+}
+
+inline int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i)
+{
+	return atomic_add_return(i, v);
+}
+
+inline int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i)
+{
+	return atomic_sub_return(i, v);
+}
+
+inline int ATOMIC_INC_RETURN(ATOMIC_T *v)
+{
+	return atomic_inc_return(v);
+}
+
+inline int ATOMIC_DEC_RETURN(ATOMIC_T *v)
+{
+	return atomic_dec_return(v);
+}
+
+/* Open a file with the specific @param path, @param flag, @param mode
+ * @param fpp the pointer of struct file pointer to get struct file pointer while file opening is success
+ * @param path the path of the file to open
+ * @param flag file operation flags, please refer to linux document
+ * @param mode please refer to linux document
+ * @return Linux specific error code
+ */
+static int openfile(struct file **fpp, char *path, int flag, int mode)
+{
+	struct file *fp;
+
+	fp = filp_open(path, flag, mode);
+	if (IS_ERR(fp)) {
+		*fpp = NULL;
+		return PTR_ERR(fp);
+	} else {
+		*fpp = fp;
+		return 0;
+	}
+}
+
+/* Close the file with the specific @param fp
+ * @param fp the pointer of struct file to close
+ * @return always 0
+ */
+static int closefile(struct file *fp)
+{
+	filp_close(fp, NULL);
+	return 0;
+}
+
+static int readfile(struct file *fp, char __user *buf, int len)
+{
+	int rlen = 0, sum = 0;
+
+	if (!fp->f_op || !fp->f_op->read)
+		return -EPERM;
+
+	while (sum < len) {
+		rlen = fp->f_op->read(fp, buf+sum, len-sum, &fp->f_pos);
+		if (rlen > 0)
+			sum += rlen;
+		else if (0 != rlen)
+			return rlen;
+		else
+			break;
+	}
+	return  sum;
+}
+
+static int writefile(struct file *fp, char __user *buf, int len)
+{
+	int wlen = 0, sum = 0;
+
+	if (!fp->f_op || !fp->f_op->write)
+		return -EPERM;
+
+	while (sum < len) {
+		wlen = fp->f_op->write(fp, buf+sum, len-sum, &fp->f_pos);
+		if (wlen > 0)
+			sum += wlen;
+		else if (0 != wlen)
+			return wlen;
+		else
+			break;
+	}
+	return sum;
+}
+
+/* Test if the specifi @param path is a file and readable
+ * @param path the path of the file to test
+ * @return Linux specific error code
+ */
+static int isfilereadable(char *path)
+{
+	struct file *fp;
+	int ret = 0;
+	mm_segment_t oldfs;
+	char __user buf;
+
+	fp = filp_open(path, O_RDONLY, 0);
+	if (IS_ERR(fp)) {
+		ret = PTR_ERR(fp);
+	} else {
+		oldfs = get_fs(); set_fs(get_ds());
+
+		if (1 != readfile(fp, &buf, 1))
+			ret = PTR_ERR(fp);
+
+		set_fs(oldfs);
+		filp_close(fp, NULL);
+	}
+	return ret;
+}
+
+/* Open the file with @param path and retrive the file content into
+ * memory starting from @param buf for @param sz at most
+ * @param path the path of the file to open and read
+ * @param buf the starting address of the buffer to store file content
+ * @param sz how many bytes to read at most
+ * @return the byte we've read, or Linux specific error code
+ */
+static int retrievefromfile(char *path, u8 __user *buf, u32 sz)
+{
+	int ret = -1;
+	mm_segment_t oldfs;
+	struct file *fp;
+
+	if (path && buf) {
+		ret = openfile(&fp, path, O_RDONLY, 0);
+		if (0 == ret) {
+			DBG_88E("%s openfile path:%s fp =%p\n", __func__,
+				path, fp);
+
+			oldfs = get_fs(); set_fs(get_ds());
+			ret = readfile(fp, buf, sz);
+			set_fs(oldfs);
+			closefile(fp);
+
+			DBG_88E("%s readfile, ret:%d\n", __func__, ret);
+
+		} else {
+			DBG_88E("%s openfile path:%s Fail, ret:%d\n", __func__,
+				path, ret);
+		}
+	} else {
+		DBG_88E("%s NULL pointer\n", __func__);
+		ret =  -EINVAL;
+	}
+	return ret;
+}
+
+/*
+* Open the file with @param path and wirte @param sz byte of data starting from @param buf into the file
+* @param path the path of the file to open and write
+* @param buf the starting address of the data to write into file
+* @param sz how many bytes to write at most
+* @return the byte we've written, or Linux specific error code
+*/
+static int storetofile(char *path, u8 __user *buf, u32 sz)
+{
+	int ret = 0;
+	mm_segment_t oldfs;
+	struct file *fp;
+
+	if (path && buf) {
+		ret = openfile(&fp, path, O_CREAT|O_WRONLY, 0666);
+		if (0 == ret) {
+			DBG_88E("%s openfile path:%s fp =%p\n", __func__, path, fp);
+
+			oldfs = get_fs(); set_fs(get_ds());
+			ret = writefile(fp, buf, sz);
+			set_fs(oldfs);
+			closefile(fp);
+
+			DBG_88E("%s writefile, ret:%d\n", __func__, ret);
+
+		} else {
+			DBG_88E("%s openfile path:%s Fail, ret:%d\n", __func__, path, ret);
+		}
+	} else {
+		DBG_88E("%s NULL pointer\n", __func__);
+		ret =  -EINVAL;
+	}
+	return ret;
+}
+
+/*
+* Test if the specifi @param path is a file and readable
+* @param path the path of the file to test
+* @return true or false
+*/
+int rtw_is_file_readable(char *path)
+{
+	if (isfilereadable(path) == 0)
+		return true;
+	else
+		return false;
+}
+
+/*
+* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most
+* @param path the path of the file to open and read
+* @param buf the starting address of the buffer to store file content
+* @param sz how many bytes to read at most
+* @return the byte we've read
+*/
+int rtw_retrive_from_file(char *path, u8 __user *buf, u32 sz)
+{
+	int ret = retrievefromfile(path, buf, sz);
+
+	return ret >= 0 ? ret : 0;
+}
+
+/*
+ * Open the file with @param path and wirte @param sz byte of data
+ * starting from @param buf into the file
+ * @param path the path of the file to open and write
+ * @param buf the starting address of the data to write into file
+ * @param sz how many bytes to write at most
+ * @return the byte we've written
+ */
+int rtw_store_to_file(char *path, u8 __user *buf, u32 sz)
+{
+	int ret = storetofile(path, buf, sz);
+	return ret >= 0 ? ret : 0;
+}
+
+struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv,
+						    void *old_priv)
+{
+	struct net_device *pnetdev;
+	struct rtw_netdev_priv_indicator *pnpi;
+
+	pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+	if (!pnetdev)
+		goto RETURN;
+
+	pnpi = netdev_priv(pnetdev);
+	pnpi->priv = old_priv;
+	pnpi->sizeof_priv = sizeof_priv;
+
+RETURN:
+	return pnetdev;
+}
+
+struct net_device *rtw_alloc_etherdev(int sizeof_priv)
+{
+	struct net_device *pnetdev;
+	struct rtw_netdev_priv_indicator *pnpi;
+
+	pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+	if (!pnetdev)
+		goto RETURN;
+
+	pnpi = netdev_priv(pnetdev);
+
+	pnpi->priv = rtw_zvmalloc(sizeof_priv);
+	if (!pnpi->priv) {
+		free_netdev(pnetdev);
+		pnetdev = NULL;
+		goto RETURN;
+	}
+
+	pnpi->sizeof_priv = sizeof_priv;
+RETURN:
+	return pnetdev;
+}
+
+void rtw_free_netdev(struct net_device *netdev)
+{
+	struct rtw_netdev_priv_indicator *pnpi;
+
+	if (!netdev)
+		goto RETURN;
+
+	pnpi = netdev_priv(netdev);
+
+	if (!pnpi->priv)
+		goto RETURN;
+
+	rtw_vmfree(pnpi->priv, pnpi->sizeof_priv);
+	free_netdev(netdev);
+
+RETURN:
+	return;
+}
+
+int rtw_change_ifname(struct adapter *padapter, const char *ifname)
+{
+	struct net_device *pnetdev;
+	struct net_device *cur_pnetdev = padapter->pnetdev;
+	struct rereg_nd_name_data *rereg_priv;
+	int ret;
+
+	if (!padapter)
+		goto error;
+
+	rereg_priv = &padapter->rereg_nd_name_priv;
+
+	/* free the old_pnetdev */
+	if (rereg_priv->old_pnetdev) {
+		free_netdev(rereg_priv->old_pnetdev);
+		rereg_priv->old_pnetdev = NULL;
+	}
+
+	if (!rtnl_is_locked())
+		unregister_netdev(cur_pnetdev);
+	else
+		unregister_netdevice(cur_pnetdev);
+
+	rtw_proc_remove_one(cur_pnetdev);
+
+	rereg_priv->old_pnetdev = cur_pnetdev;
+
+	pnetdev = rtw_init_netdev(padapter);
+	if (!pnetdev)  {
+		ret = -1;
+		goto error;
+	}
+
+	SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter)));
+
+	rtw_init_netdev_name(pnetdev, ifname);
+
+	memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN);
+
+	if (!rtnl_is_locked())
+		ret = register_netdev(pnetdev);
+	else
+		ret = register_netdevice(pnetdev);
+	if (ret != 0) {
+		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+			 ("register_netdev() failed\n"));
+		goto error;
+	}
+	rtw_proc_init_one(pnetdev);
+	return 0;
+error:
+	return -1;
+}
+
+u64 rtw_modular64(u64 x, u64 y)
+{
+	return do_div(x, y);
+}
+
+u64 rtw_division64(u64 x, u64 y)
+{
+	do_div(x, y);
+	return x;
+}
+
+void rtw_buf_free(u8 **buf, u32 *buf_len)
+{
+	*buf_len = 0;
+	kfree(*buf);
+	*buf = NULL;
+}
+
+void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len)
+{
+	u32 ori_len = 0, dup_len = 0;
+	u8 *ori = NULL;
+	u8 *dup = NULL;
+
+	if (!buf || !buf_len)
+		return;
+
+	if (!src || !src_len)
+		goto keep_ori;
+
+	/* duplicate src */
+	dup = rtw_malloc(src_len);
+	if (dup) {
+		dup_len = src_len;
+		memcpy(dup, src, dup_len);
+	}
+
+keep_ori:
+	ori = *buf;
+	ori_len = *buf_len;
+
+	/* replace buf with dup */
+	*buf_len = 0;
+	*buf = dup;
+	*buf_len = dup_len;
+
+	/* free ori */
+	kfree(ori);
+}
+
+
+/**
+ * rtw_cbuf_full - test if cbuf is full
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is full
+ */
+inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
+{
+	return (cbuf->write == cbuf->read-1) ? true : false;
+}
+
+/**
+ * rtw_cbuf_empty - test if cbuf is empty
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is empty
+ */
+inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf)
+{
+	return (cbuf->write == cbuf->read) ? true : false;
+}
+
+/**
+ * rtw_cbuf_push - push a pointer into cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ * @buf: pointer to push in
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: true push success
+ */
+bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf)
+{
+	if (rtw_cbuf_full(cbuf))
+		return _FAIL;
+
+	if (0)
+		DBG_88E("%s on %u\n", __func__, cbuf->write);
+	cbuf->bufs[cbuf->write] = buf;
+	cbuf->write = (cbuf->write+1)%cbuf->size;
+
+	return _SUCCESS;
+}
+
+/**
+ * rtw_cbuf_pop - pop a pointer from cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: pointer popped out
+ */
+void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
+{
+	void *buf;
+	if (rtw_cbuf_empty(cbuf))
+		return NULL;
+
+	if (0)
+		DBG_88E("%s on %u\n", __func__, cbuf->read);
+	buf = cbuf->bufs[cbuf->read];
+	cbuf->read = (cbuf->read+1)%cbuf->size;
+
+	return buf;
+}
+
+/**
+ * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization
+ * @size: size of pointer
+ *
+ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure
+ */
+struct rtw_cbuf *rtw_cbuf_alloc(u32 size)
+{
+	struct rtw_cbuf *cbuf;
+
+	cbuf = (struct rtw_cbuf *)rtw_malloc(sizeof(*cbuf) +
+	       sizeof(void *)*size);
+
+	if (cbuf) {
+		cbuf->write = 0;
+		cbuf->read = 0;
+		cbuf->size = size;
+	}
+	return cbuf;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
new file mode 100644
index 0000000..e2f4e7d
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
@@ -0,0 +1,261 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _RECV_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <wifi.h>
+#include <recv_osdep.h>
+
+#include <osdep_intf.h>
+#include <ethernet.h>
+#include <usb_ops.h>
+
+/* init os related resource in struct recv_priv */
+int rtw_os_recv_resource_init(struct recv_priv *precvpriv,
+			      struct adapter *padapter)
+{
+	return _SUCCESS;
+}
+
+/* alloc os related resource in union recv_frame */
+int rtw_os_recv_resource_alloc(struct adapter *padapter,
+			       union recv_frame *precvframe)
+{
+	precvframe->u.hdr.pkt_newalloc = NULL;
+	precvframe->u.hdr.pkt = NULL;
+	return _SUCCESS;
+}
+
+/* free os related resource in union recv_frame */
+void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
+{
+}
+
+/* alloc os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_alloc(struct adapter *padapter,
+				  struct recv_buf *precvbuf)
+{
+	int res = _SUCCESS;
+
+	precvbuf->irp_pending = false;
+	precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
+	if (precvbuf->purb == NULL)
+		res = _FAIL;
+	precvbuf->pskb = NULL;
+	precvbuf->reuse = false;
+	precvbuf->pallocated_buf = NULL;
+	precvbuf->pbuf = NULL;
+	precvbuf->pdata = NULL;
+	precvbuf->phead = NULL;
+	precvbuf->ptail = NULL;
+	precvbuf->pend = NULL;
+	precvbuf->transfer_len = 0;
+	precvbuf->len = 0;
+	return res;
+}
+
+/* free os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_free(struct adapter *padapter,
+				 struct recv_buf *precvbuf)
+{
+	if (precvbuf->purb)
+		usb_free_urb(precvbuf->purb);
+	return _SUCCESS;
+}
+
+void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
+{
+	union iwreq_data wrqu;
+	struct iw_michaelmicfailure    ev;
+	struct mlme_priv *pmlmepriv  = &padapter->mlmepriv;
+	struct security_priv	*psecuritypriv = &padapter->securitypriv;
+	u32 cur_time = 0;
+
+	if (psecuritypriv->last_mic_err_time == 0) {
+		psecuritypriv->last_mic_err_time = rtw_get_current_time();
+	} else {
+		cur_time = rtw_get_current_time();
+
+		if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) {
+			psecuritypriv->btkip_countermeasure = true;
+			psecuritypriv->last_mic_err_time = 0;
+			psecuritypriv->btkip_countermeasure_time = cur_time;
+		} else {
+			psecuritypriv->last_mic_err_time = rtw_get_current_time();
+		}
+	}
+
+	_rtw_memset(&ev, 0x00, sizeof(ev));
+	if (bgroup)
+		ev.flags |= IW_MICFAILURE_GROUP;
+	else
+		ev.flags |= IW_MICFAILURE_PAIRWISE;
+
+	ev.src_addr.sa_family = ARPHRD_ETHER;
+	memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
+	_rtw_memset(&wrqu, 0x00, sizeof(wrqu));
+	wrqu.data.length = sizeof(ev);
+	wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE,
+			    &wrqu, (char *)&ev);
+}
+
+void rtw_hostapd_mlme_rx(struct adapter *padapter,
+			 union recv_frame *precv_frame)
+{
+}
+
+int rtw_recv_indicatepkt(struct adapter *padapter,
+			 union recv_frame *precv_frame)
+{
+	struct recv_priv *precvpriv;
+	struct __queue *pfree_recv_queue;
+	struct sk_buff *skb;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+_func_enter_;
+
+	precvpriv = &(padapter->recvpriv);
+	pfree_recv_queue = &(precvpriv->free_recv_queue);
+
+	skb = precv_frame->u.hdr.pkt;
+	if (skb == NULL) {
+		RT_TRACE(_module_recv_osdep_c_, _drv_err_,
+			 ("rtw_recv_indicatepkt():skb == NULL something wrong!!!!\n"));
+		goto _recv_indicatepkt_drop;
+	}
+
+	RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+		 ("rtw_recv_indicatepkt():skb != NULL !!!\n"));
+	RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+		 ("rtw_recv_indicatepkt():precv_frame->u.hdr.rx_head =%p  precv_frame->hdr.rx_data =%p\n",
+		 precv_frame->u.hdr.rx_head, precv_frame->u.hdr.rx_data));
+	RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+		 ("precv_frame->hdr.rx_tail =%p precv_frame->u.hdr.rx_end =%p precv_frame->hdr.len =%d\n",
+		 precv_frame->u.hdr.rx_tail, precv_frame->u.hdr.rx_end,
+		 precv_frame->u.hdr.len));
+
+	skb->data = precv_frame->u.hdr.rx_data;
+
+	skb_set_tail_pointer(skb, precv_frame->u.hdr.len);
+
+	skb->len = precv_frame->u.hdr.len;
+
+	RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+		 ("skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n",
+		 skb->head, skb->data, skb_tail_pointer(skb),
+		 skb_end_pointer(skb), skb->len));
+
+	if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+		struct sk_buff *pskb2 = NULL;
+		struct sta_info *psta = NULL;
+		struct sta_priv *pstapriv = &padapter->stapriv;
+		struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+		int bmcast = IS_MCAST(pattrib->dst);
+
+		if (!_rtw_memcmp(pattrib->dst, myid(&padapter->eeprompriv),
+				 ETH_ALEN)) {
+			if (bmcast) {
+				psta = rtw_get_bcmc_stainfo(padapter);
+				pskb2 = skb_clone(skb, GFP_ATOMIC);
+			} else {
+				psta = rtw_get_stainfo(pstapriv, pattrib->dst);
+			}
+
+			if (psta) {
+				struct net_device *pnetdev;
+
+				pnetdev = (struct net_device *)padapter->pnetdev;
+				skb->dev = pnetdev;
+				skb_set_queue_mapping(skb, rtw_recv_select_queue(skb));
+
+				rtw_xmit_entry(skb, pnetdev);
+
+				if (bmcast)
+					skb = pskb2;
+				else
+					goto _recv_indicatepkt_end;
+			}
+		}
+	}
+
+	rcu_read_lock();
+	rcu_dereference(padapter->pnetdev->rx_handler_data);
+	rcu_read_unlock();
+
+	skb->ip_summed = CHECKSUM_NONE;
+	skb->dev = padapter->pnetdev;
+	skb->protocol = eth_type_trans(skb, padapter->pnetdev);
+
+	netif_rx(skb);
+
+_recv_indicatepkt_end:
+
+	/*  pointers to NULL before rtw_free_recvframe() */
+	precv_frame->u.hdr.pkt = NULL;
+
+	rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+	RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+		 ("\n rtw_recv_indicatepkt :after netif_rx!!!!\n"));
+
+_func_exit_;
+
+	return _SUCCESS;
+
+_recv_indicatepkt_drop:
+
+	 /* enqueue back to free_recv_queue */
+	if (precv_frame)
+		rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+_func_exit_;
+	 return _FAIL;
+}
+
+void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf)
+{
+	struct recv_priv *precvpriv = &padapter->recvpriv;
+
+	precvbuf->ref_cnt--;
+	/* free skb in recv_buf */
+	dev_kfree_skb_any(precvbuf->pskb);
+	precvbuf->pskb = NULL;
+	precvbuf->reuse = false;
+	if (!precvbuf->irp_pending)
+		rtw_read_port(padapter, precvpriv->ff_hwaddr, 0,
+			      (unsigned char *)precvbuf);
+}
+
+static void _rtw_reordering_ctrl_timeout_handler(void *func_context)
+{
+	struct recv_reorder_ctrl *preorder_ctrl;
+
+	preorder_ctrl = (struct recv_reorder_ctrl *)func_context;
+	rtw_reordering_ctrl_timeout_handler(preorder_ctrl);
+}
+
+void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
+{
+	struct adapter *padapter = preorder_ctrl->padapter;
+
+	_init_timer(&(preorder_ctrl->reordering_ctrl_timer), padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
new file mode 100644
index 0000000..6cf71cc
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
@@ -0,0 +1,293 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include <rtw_android.h>
+#include <osdep_service.h>
+#include <rtw_debug.h>
+#include <ioctl_cfg80211.h>
+#include <rtw_ioctl_set.h>
+
+static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
+	"START",
+	"STOP",
+	"SCAN-ACTIVE",
+	"SCAN-PASSIVE",
+	"RSSI",
+	"LINKSPEED",
+	"RXFILTER-START",
+	"RXFILTER-STOP",
+	"RXFILTER-ADD",
+	"RXFILTER-REMOVE",
+	"BTCOEXSCAN-START",
+	"BTCOEXSCAN-STOP",
+	"BTCOEXMODE",
+	"SETSUSPENDOPT",
+	"P2P_DEV_ADDR",
+	"SETFWPATH",
+	"SETBAND",
+	"GETBAND",
+	"COUNTRY",
+	"P2P_SET_NOA",
+	"P2P_GET_NOA",
+	"P2P_SET_PS",
+	"SET_AP_WPS_P2P_IE",
+	"MACADDR",
+	"BLOCK",
+	"WFD-ENABLE",
+	"WFD-DISABLE",
+	"WFD-SET-TCPPORT",
+	"WFD-SET-MAXTPUT",
+	"WFD-SET-DEVTYPE",
+};
+
+struct android_wifi_priv_cmd {
+	const char __user *buf;
+	int used_len;
+	int total_len;
+};
+
+/**
+ * Local (static) functions and variables
+ */
+
+/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
+ * time (only) in dhd_open, subsequential wifi on will be handled by
+ * wl_android_wifi_on
+ */
+static int g_wifi_on = true;
+
+int rtw_android_cmdstr_to_num(char *cmdstr)
+{
+	int cmd_num;
+	for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
+		if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num],
+				  strlen(android_wifi_cmd_str[cmd_num])))
+			break;
+	return cmd_num;
+}
+
+static int rtw_android_get_rssi(struct net_device *net, char *command,
+				int total_len)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(net);
+	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
+	struct	wlan_network	*pcur_network = &pmlmepriv->cur_network;
+	int bytes_written = 0;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+		bytes_written += snprintf(&command[bytes_written], total_len,
+					  "%s rssi %d",
+					  pcur_network->network.Ssid.Ssid,
+					  padapter->recvpriv.rssi);
+	}
+	return bytes_written;
+}
+
+static int rtw_android_get_link_speed(struct net_device *net, char *command,
+				      int total_len)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(net);
+	int bytes_written;
+	u16 link_speed;
+
+	link_speed = rtw_get_cur_max_rate(padapter) / 10;
+	bytes_written = snprintf(command, total_len, "LinkSpeed %d",
+				 link_speed);
+	return bytes_written;
+}
+
+static int rtw_android_get_macaddr(struct net_device *net, char *command,
+				   int total_len)
+{
+	int bytes_written;
+
+	bytes_written = snprintf(command, total_len, "Macaddr = %pM",
+				 net->dev_addr);
+	return bytes_written;
+}
+
+static int android_set_cntry(struct net_device *net, char *command,
+			     int total_len)
+{
+	struct adapter *adapter = (struct adapter *)rtw_netdev_priv(net);
+	char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
+	int ret;
+
+	ret = rtw_set_country(adapter, country_code);
+	return (ret == _SUCCESS) ? 0 : -1;
+}
+
+static int android_get_p2p_addr(struct net_device *net, char *command,
+					int total_len)
+{
+	/* We use the same address as our HW MAC address */
+	memcpy(command, net->dev_addr, ETH_ALEN);
+	return ETH_ALEN;
+}
+
+static int rtw_android_set_block(struct net_device *net, char *command,
+				 int total_len)
+{
+	return 0;
+}
+
+int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+	int ret = 0;
+	char *command = NULL;
+	int cmd_num;
+	int bytes_written = 0;
+	struct android_wifi_priv_cmd priv_cmd;
+
+	rtw_lock_suspend();
+	if (!ifr->ifr_data) {
+		ret = -EINVAL;
+		goto exit;
+	}
+	if (copy_from_user(&priv_cmd, ifr->ifr_data,
+			   sizeof(struct android_wifi_priv_cmd))) {
+		ret = -EFAULT;
+		goto exit;
+	}
+	command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
+	if (!command) {
+		DBG_88E("%s: failed to allocate memory\n", __func__);
+		ret = -ENOMEM;
+		goto exit;
+	}
+	if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)) {
+		DBG_88E("%s: failed to access memory\n", __func__);
+		ret = -EFAULT;
+		goto exit;
+	}
+	if (copy_from_user(command, (char __user *)priv_cmd.buf,
+			   priv_cmd.total_len)) {
+		ret = -EFAULT;
+		goto exit;
+	}
+	DBG_88E("%s: Android private cmd \"%s\" on %s\n",
+		__func__, command, ifr->ifr_name);
+	cmd_num = rtw_android_cmdstr_to_num(command);
+	switch (cmd_num) {
+	case ANDROID_WIFI_CMD_START:
+		goto response;
+	case ANDROID_WIFI_CMD_SETFWPATH:
+		goto response;
+	}
+	if (!g_wifi_on) {
+		DBG_88E("%s: Ignore private cmd \"%s\" - iface %s is down\n",
+			__func__, command, ifr->ifr_name);
+		ret = 0;
+		goto exit;
+	}
+	switch (cmd_num) {
+	case ANDROID_WIFI_CMD_STOP:
+		break;
+	case ANDROID_WIFI_CMD_SCAN_ACTIVE:
+		break;
+	case ANDROID_WIFI_CMD_SCAN_PASSIVE:
+		break;
+	case ANDROID_WIFI_CMD_RSSI:
+		bytes_written = rtw_android_get_rssi(net, command,
+						     priv_cmd.total_len);
+		break;
+	case ANDROID_WIFI_CMD_LINKSPEED:
+		bytes_written = rtw_android_get_link_speed(net, command,
+							   priv_cmd.total_len);
+		break;
+	case ANDROID_WIFI_CMD_MACADDR:
+		bytes_written = rtw_android_get_macaddr(net, command,
+							priv_cmd.total_len);
+		break;
+	case ANDROID_WIFI_CMD_BLOCK:
+		bytes_written = rtw_android_set_block(net, command,
+						      priv_cmd.total_len);
+		break;
+	case ANDROID_WIFI_CMD_RXFILTER_START:
+		break;
+	case ANDROID_WIFI_CMD_RXFILTER_STOP:
+		break;
+	case ANDROID_WIFI_CMD_RXFILTER_ADD:
+		break;
+	case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
+		break;
+	case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
+		/* TBD: BTCOEXSCAN-START */
+		break;
+	case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
+		/* TBD: BTCOEXSCAN-STOP */
+		break;
+	case ANDROID_WIFI_CMD_BTCOEXMODE:
+		break;
+	case ANDROID_WIFI_CMD_SETSUSPENDOPT:
+		break;
+	case ANDROID_WIFI_CMD_SETBAND:
+		break;
+	case ANDROID_WIFI_CMD_GETBAND:
+		break;
+	case ANDROID_WIFI_CMD_COUNTRY:
+		bytes_written = android_set_cntry(net, command,
+						  priv_cmd.total_len);
+		break;
+	case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
+		bytes_written = android_get_p2p_addr(net, command,
+						     priv_cmd.total_len);
+		break;
+	case ANDROID_WIFI_CMD_P2P_SET_NOA:
+		break;
+	case ANDROID_WIFI_CMD_P2P_GET_NOA:
+		break;
+	case ANDROID_WIFI_CMD_P2P_SET_PS:
+		break;
+	default:
+		DBG_88E("Unknown PRIVATE command %s - ignored\n", command);
+		snprintf(command, 3, "OK");
+		bytes_written = strlen("OK");
+	}
+
+response:
+	if (bytes_written >= 0) {
+		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+			command[0] = '\0';
+		if (bytes_written >= priv_cmd.total_len) {
+			DBG_88E("%s: bytes_written = %d\n", __func__,
+				bytes_written);
+			bytes_written = priv_cmd.total_len;
+		} else {
+			bytes_written++;
+		}
+		priv_cmd.used_len = bytes_written;
+		if (copy_to_user((char __user *)priv_cmd.buf, command,
+				 bytes_written)) {
+			DBG_88E("%s: failed to copy data to user buffer\n",
+				__func__);
+			ret = -EFAULT;
+		}
+	} else {
+		ret = bytes_written;
+	}
+exit:
+	rtw_unlock_suspend();
+	kfree(command);
+	return ret;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
new file mode 100644
index 0000000..d3078d2
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -0,0 +1,892 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _HCI_INTF_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <hal_intf.h>
+#include <rtw_version.h>
+#include <linux/usb.h>
+#include <osdep_intf.h>
+
+#include <usb_vendor_req.h>
+#include <usb_ops.h>
+#include <usb_osintf.h>
+#include <usb_hal.h>
+#include <rtw_ioctl.h>
+
+int ui_pid[3] = {0, 0, 0};
+
+static int rtw_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtw_resume(struct usb_interface *intf);
+
+
+static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid);
+static void rtw_dev_remove(struct usb_interface *pusb_intf);
+
+
+#define USB_VENDER_ID_REALTEK		0x0bda
+
+/* DID_USB_v916_20130116 */
+static struct usb_device_id rtw_usb_id_tbl[] = {
+	/*=== Realtek demoboard ===*/
+	{USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)}, /* 8188EUS */
+	{USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */
+	/*=== Customer ID ===*/
+	/****** 8188EUS ********/
+	{USB_DEVICE(0x8179, 0x07B8)}, /* Abocom - Abocom */
+	{}	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl);
+
+static struct specific_device_id specific_device_id_tbl[] = {
+	{}		/* empty table for now */
+};
+
+struct rtw_usb_drv {
+	struct usb_driver usbdrv;
+	int drv_registered;
+	struct mutex hw_init_mutex;
+};
+
+static struct rtw_usb_drv rtl8188e_usb_drv = {
+	.usbdrv.name = (char *)"r8188eu",
+	.usbdrv.probe = rtw_drv_init,
+	.usbdrv.disconnect = rtw_dev_remove,
+	.usbdrv.id_table = rtw_usb_id_tbl,
+	.usbdrv.suspend =  rtw_suspend,
+	.usbdrv.resume = rtw_resume,
+	.usbdrv.reset_resume   = rtw_resume,
+};
+
+static struct rtw_usb_drv *usb_drv = &rtl8188e_usb_drv;
+
+static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+	return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+}
+
+static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+	return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
+}
+
+static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+	return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT;
+}
+
+static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+	return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK;
+}
+
+static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+	return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+	return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd);
+}
+
+static inline int usb_endpoint_is_int(const struct usb_endpoint_descriptor *epd)
+{
+	return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+	return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj)
+{
+	u8 rst = _SUCCESS;
+
+	_rtw_mutex_init(&dvobj->usb_vendor_req_mutex);
+
+	dvobj->usb_alloc_vendor_req_buf = rtw_zmalloc(MAX_USB_IO_CTL_SIZE);
+	if (dvobj->usb_alloc_vendor_req_buf == NULL) {
+		DBG_88E("alloc usb_vendor_req_buf failed... /n");
+		rst = _FAIL;
+		goto exit;
+	}
+	dvobj->usb_vendor_req_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(dvobj->usb_alloc_vendor_req_buf), ALIGNMENT_UNIT);
+exit:
+	return rst;
+}
+
+static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj)
+{
+	u8 rst = _SUCCESS;
+
+	kfree(dvobj->usb_alloc_vendor_req_buf);
+	_rtw_mutex_free(&dvobj->usb_vendor_req_mutex);
+	return rst;
+}
+
+static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
+{
+	int	i;
+	int	status = _FAIL;
+	struct dvobj_priv *pdvobjpriv;
+	struct usb_host_config		*phost_conf;
+	struct usb_config_descriptor	*pconf_desc;
+	struct usb_host_interface	*phost_iface;
+	struct usb_interface_descriptor	*piface_desc;
+	struct usb_host_endpoint	*phost_endp;
+	struct usb_endpoint_descriptor	*pendp_desc;
+	struct usb_device	*pusbd;
+
+_func_enter_;
+
+	pdvobjpriv = (struct dvobj_priv *)rtw_zmalloc(sizeof(*pdvobjpriv));
+	if (pdvobjpriv == NULL)
+		goto exit;
+
+	pdvobjpriv->pusbintf = usb_intf;
+	pusbd = interface_to_usbdev(usb_intf);
+	pdvobjpriv->pusbdev = pusbd;
+	usb_set_intfdata(usb_intf, pdvobjpriv);
+
+	pdvobjpriv->RtNumInPipes = 0;
+	pdvobjpriv->RtNumOutPipes = 0;
+
+	phost_conf = pusbd->actconfig;
+	pconf_desc = &phost_conf->desc;
+
+	phost_iface = &usb_intf->altsetting[0];
+	piface_desc = &phost_iface->desc;
+
+	pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces;
+	pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber;
+	pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
+
+	for (i = 0; i < pdvobjpriv->nr_endpoint; i++) {
+		phost_endp = phost_iface->endpoint + i;
+		if (phost_endp) {
+			pendp_desc = &phost_endp->desc;
+
+			DBG_88E("\nusb_endpoint_descriptor(%d):\n", i);
+			DBG_88E("bLength=%x\n", pendp_desc->bLength);
+			DBG_88E("bDescriptorType=%x\n",
+				pendp_desc->bDescriptorType);
+			DBG_88E("bEndpointAddress=%x\n",
+				pendp_desc->bEndpointAddress);
+			DBG_88E("wMaxPacketSize=%d\n",
+				le16_to_cpu(pendp_desc->wMaxPacketSize));
+			DBG_88E("bInterval=%x\n", pendp_desc->bInterval);
+
+			if (RT_usb_endpoint_is_bulk_in(pendp_desc)) {
+				DBG_88E("RT_usb_endpoint_is_bulk_in = %x\n",
+					RT_usb_endpoint_num(pendp_desc));
+				pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc);
+				pdvobjpriv->RtNumInPipes++;
+			} else if (usb_endpoint_is_int(pendp_desc)) {
+				DBG_88E("usb_endpoint_is_int = %x, Interval = %x\n",
+					RT_usb_endpoint_num(pendp_desc),
+					pendp_desc->bInterval);
+				pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc);
+				pdvobjpriv->RtNumInPipes++;
+			} else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) {
+				DBG_88E("RT_usb_endpoint_is_bulk_out = %x\n",
+					RT_usb_endpoint_num(pendp_desc));
+				pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = RT_usb_endpoint_num(pendp_desc);
+				pdvobjpriv->RtNumOutPipes++;
+			}
+			pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc);
+		}
+	}
+
+	DBG_88E("nr_endpoint=%d, in_num=%d, out_num=%d\n\n",
+		pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes,
+		pdvobjpriv->RtNumOutPipes);
+
+	if (pusbd->speed == USB_SPEED_HIGH) {
+		pdvobjpriv->ishighspeed = true;
+		DBG_88E("USB_SPEED_HIGH\n");
+	} else {
+		pdvobjpriv->ishighspeed = false;
+		DBG_88E("NON USB_SPEED_HIGH\n");
+	}
+
+	if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) {
+		RT_TRACE(_module_os_intfs_c_, _drv_err_,
+			 ("\n Can't INIT rtw_init_intf_priv\n"));
+		goto free_dvobj;
+	}
+
+	/* 3 misc */
+	_rtw_init_sema(&(pdvobjpriv->usb_suspend_sema), 0);
+	rtw_reset_continual_urb_error(pdvobjpriv);
+
+	usb_get_dev(pusbd);
+
+	status = _SUCCESS;
+
+free_dvobj:
+	if (status != _SUCCESS && pdvobjpriv) {
+		usb_set_intfdata(usb_intf, NULL);
+		kfree(pdvobjpriv);
+		pdvobjpriv = NULL;
+	}
+exit:
+_func_exit_;
+	return pdvobjpriv;
+}
+
+static void usb_dvobj_deinit(struct usb_interface *usb_intf)
+{
+	struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf);
+
+_func_enter_;
+
+	usb_set_intfdata(usb_intf, NULL);
+	if (dvobj) {
+		/* Modify condition for 92DU DMDP 2010.11.18, by Thomas */
+		if ((dvobj->NumInterfaces != 2 &&
+		    dvobj->NumInterfaces != 3) ||
+		    (dvobj->InterfaceNumber == 1)) {
+			if (interface_to_usbdev(usb_intf)->state !=
+			    USB_STATE_NOTATTACHED) {
+				/* If we didn't unplug usb dongle and
+				 * remove/insert module, driver fails
+				 * on sitesurvey for the first time when
+				 * device is up . Reset usb port for sitesurvey
+				 * fail issue. */
+				DBG_88E("usb attached..., try to reset usb device\n");
+				usb_reset_device(interface_to_usbdev(usb_intf));
+			}
+		}
+		rtw_deinit_intf_priv(dvobj);
+		kfree(dvobj);
+	}
+
+	usb_put_dev(interface_to_usbdev(usb_intf));
+
+_func_exit_;
+}
+
+static void chip_by_usb_id(struct adapter *padapter,
+			   const struct usb_device_id *pdid)
+{
+	padapter->chip_type = NULL_CHIP_TYPE;
+	hal_set_hw_type(padapter);
+}
+
+static void usb_intf_start(struct adapter *padapter)
+{
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_start\n"));
+
+	rtw_hal_inirp_init(padapter);
+
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_start\n"));
+}
+
+static void usb_intf_stop(struct adapter *padapter)
+{
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_stop\n"));
+
+	/* disabel_hw_interrupt */
+	if (!padapter->bSurpriseRemoved) {
+		/* device still exists, so driver can do i/o operation */
+		/* TODO: */
+		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+			 ("SurpriseRemoved == false\n"));
+	}
+
+	/* cancel in irp */
+	rtw_hal_inirp_deinit(padapter);
+
+	/* cancel out irp */
+	rtw_write_port_cancel(padapter);
+
+	/* todo:cancel other irps */
+
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_stop\n"));
+}
+
+static void rtw_dev_unload(struct adapter *padapter)
+{
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n"));
+
+	if (padapter->bup) {
+		DBG_88E("===> rtw_dev_unload\n");
+		padapter->bDriverStopped = true;
+		if (padapter->xmitpriv.ack_tx)
+			rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP);
+		/* s3. */
+		if (padapter->intf_stop)
+			padapter->intf_stop(padapter);
+		/* s4. */
+		if (!padapter->pwrctrlpriv.bInternalAutoSuspend)
+			rtw_stop_drv_threads(padapter);
+
+		/* s5. */
+		if (!padapter->bSurpriseRemoved) {
+			rtw_hal_deinit(padapter);
+			padapter->bSurpriseRemoved = true;
+		}
+
+		padapter->bup = false;
+	} else {
+		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+			 ("r871x_dev_unload():padapter->bup == false\n"));
+	}
+
+	DBG_88E("<=== rtw_dev_unload\n");
+
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n"));
+}
+
+static void process_spec_devid(const struct usb_device_id *pdid)
+{
+	u16 vid, pid;
+	u32 flags;
+	int i;
+	int num = sizeof(specific_device_id_tbl) /
+		  sizeof(struct specific_device_id);
+
+	for (i = 0; i < num; i++) {
+		vid = specific_device_id_tbl[i].idVendor;
+		pid = specific_device_id_tbl[i].idProduct;
+		flags = specific_device_id_tbl[i].flags;
+
+		if ((pdid->idVendor == vid) && (pdid->idProduct == pid) &&
+		    (flags&SPEC_DEV_ID_DISABLE_HT)) {
+			rtw_ht_enable = 0;
+			rtw_cbw40_enable = 0;
+			rtw_ampdu_enable = 0;
+		}
+	}
+}
+
+int rtw_hw_suspend(struct adapter *padapter)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct net_device *pnetdev = padapter->pnetdev;
+
+	_func_enter_;
+
+	if ((!padapter->bup) || (padapter->bDriverStopped) ||
+	    (padapter->bSurpriseRemoved)) {
+		DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n",
+			padapter->bup, padapter->bDriverStopped,
+			padapter->bSurpriseRemoved);
+		goto error_exit;
+	}
+
+	if (padapter) { /* system suspend */
+		LeaveAllPowerSaveMode(padapter);
+
+		DBG_88E("==> rtw_hw_suspend\n");
+		_enter_pwrlock(&pwrpriv->lock);
+		pwrpriv->bips_processing = true;
+		/* s1. */
+		if (pnetdev) {
+			netif_carrier_off(pnetdev);
+			rtw_netif_stop_queue(pnetdev);
+		}
+
+		/* s2. */
+		rtw_disassoc_cmd(padapter, 500, false);
+
+		/* s2-2.  indicate disconnect to os */
+		{
+			struct	mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+			if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+				_clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+				rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+				rtw_os_indicate_disconnect(padapter);
+
+				/* donnot enqueue cmd */
+				rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0);
+			}
+		}
+		/* s2-3. */
+		rtw_free_assoc_resources(padapter, 1);
+
+		/* s2-4. */
+		rtw_free_network_queue(padapter, true);
+		rtw_ips_dev_unload(padapter);
+		pwrpriv->rf_pwrstate = rf_off;
+		pwrpriv->bips_processing = false;
+
+		_exit_pwrlock(&pwrpriv->lock);
+	} else {
+		goto error_exit;
+	}
+	_func_exit_;
+	return 0;
+
+error_exit:
+	DBG_88E("%s, failed\n", __func__);
+	return -1;
+}
+
+int rtw_hw_resume(struct adapter *padapter)
+{
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	struct net_device *pnetdev = padapter->pnetdev;
+
+	_func_enter_;
+
+	if (padapter) { /* system resume */
+		DBG_88E("==> rtw_hw_resume\n");
+		_enter_pwrlock(&pwrpriv->lock);
+		pwrpriv->bips_processing = true;
+		rtw_reset_drv_sw(padapter);
+
+		if (pm_netdev_open(pnetdev, false) != 0) {
+			_exit_pwrlock(&pwrpriv->lock);
+			goto error_exit;
+		}
+
+		netif_device_attach(pnetdev);
+		netif_carrier_on(pnetdev);
+
+		if (!netif_queue_stopped(pnetdev))
+			netif_start_queue(pnetdev);
+		else
+			netif_wake_queue(pnetdev);
+
+		pwrpriv->bkeepfwalive = false;
+		pwrpriv->brfoffbyhw = false;
+
+		pwrpriv->rf_pwrstate = rf_on;
+		pwrpriv->bips_processing = false;
+
+		_exit_pwrlock(&pwrpriv->lock);
+	} else {
+		goto error_exit;
+	}
+
+	_func_exit_;
+
+	return 0;
+error_exit:
+	DBG_88E("%s, Open net dev failed\n", __func__);
+	return -1;
+}
+
+static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
+{
+	struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+	struct adapter *padapter = dvobj->if1;
+	struct net_device *pnetdev = padapter->pnetdev;
+	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+	int ret = 0;
+	u32 start_time = rtw_get_current_time();
+
+	_func_enter_;
+
+	DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+	if ((!padapter->bup) || (padapter->bDriverStopped) ||
+	    (padapter->bSurpriseRemoved)) {
+		DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n",
+			padapter->bup, padapter->bDriverStopped,
+			padapter->bSurpriseRemoved);
+		goto exit;
+	}
+
+	pwrpriv->bInSuspend = true;
+	rtw_cancel_all_timer(padapter);
+	LeaveAllPowerSaveMode(padapter);
+
+	_enter_pwrlock(&pwrpriv->lock);
+	/* s1. */
+	if (pnetdev) {
+		netif_carrier_off(pnetdev);
+		rtw_netif_stop_queue(pnetdev);
+	}
+
+	/* s2. */
+	rtw_disassoc_cmd(padapter, 0, false);
+
+	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
+	    check_fwstate(pmlmepriv, _FW_LINKED)) {
+		DBG_88E("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n",
+			__func__, __LINE__,
+			pmlmepriv->cur_network.network.Ssid.Ssid,
+			pmlmepriv->cur_network.network.MacAddress,
+			pmlmepriv->cur_network.network.Ssid.SsidLength,
+			pmlmepriv->assoc_ssid.SsidLength);
+
+		pmlmepriv->to_roaming = 1;
+	}
+	/* s2-2.  indicate disconnect to os */
+	rtw_indicate_disconnect(padapter);
+	/* s2-3. */
+	rtw_free_assoc_resources(padapter, 1);
+	/* s2-4. */
+	rtw_free_network_queue(padapter, true);
+
+	rtw_dev_unload(padapter);
+	_exit_pwrlock(&pwrpriv->lock);
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+		rtw_indicate_scan_done(padapter, 1);
+
+	if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+		rtw_indicate_disconnect(padapter);
+
+exit:
+	DBG_88E("<===  %s return %d.............. in %dms\n", __func__
+		, ret, rtw_get_passing_time_ms(start_time));
+
+	_func_exit_;
+	return ret;
+}
+
+static int rtw_resume(struct usb_interface *pusb_intf)
+{
+	struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+	struct adapter *padapter = dvobj->if1;
+	struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+	 int ret = 0;
+
+	if (pwrpriv->bInternalAutoSuspend)
+		ret = rtw_resume_process(padapter);
+	else
+		ret = rtw_resume_process(padapter);
+	return ret;
+}
+
+int rtw_resume_process(struct adapter *padapter)
+{
+	struct net_device *pnetdev;
+	struct pwrctrl_priv *pwrpriv = NULL;
+	int ret = -1;
+	u32 start_time = rtw_get_current_time();
+	_func_enter_;
+
+	DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+	if (padapter) {
+		pnetdev = padapter->pnetdev;
+		pwrpriv = &padapter->pwrctrlpriv;
+	} else {
+		goto exit;
+	}
+
+	_enter_pwrlock(&pwrpriv->lock);
+	rtw_reset_drv_sw(padapter);
+	if (pwrpriv)
+		pwrpriv->bkeepfwalive = false;
+
+	DBG_88E("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive);
+	if (pm_netdev_open(pnetdev, true) != 0)
+		goto exit;
+
+	netif_device_attach(pnetdev);
+	netif_carrier_on(pnetdev);
+
+	_exit_pwrlock(&pwrpriv->lock);
+
+	if (padapter->pid[1] != 0) {
+		DBG_88E("pid[1]:%d\n", padapter->pid[1]);
+		rtw_signal_process(padapter->pid[1], SIGUSR2);
+	}
+
+	rtw_roaming(padapter, NULL);
+
+	ret = 0;
+exit:
+	if (pwrpriv)
+		pwrpriv->bInSuspend = false;
+	DBG_88E("<===  %s return %d.............. in %dms\n", __func__,
+		ret, rtw_get_passing_time_ms(start_time));
+
+	_func_exit_;
+
+	return ret;
+}
+
+/*
+ * drv_init() - a device potentially for us
+ *
+ * notes: drv_init() is called when the bus driver has located
+ * a card for us to support.
+ *        We accept the new device by returning 0.
+ */
+
+static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj,
+	struct usb_interface *pusb_intf, const struct usb_device_id *pdid)
+{
+	struct adapter *padapter = NULL;
+	struct net_device *pnetdev = NULL;
+	int status = _FAIL;
+
+	padapter = (struct adapter *)rtw_zvmalloc(sizeof(*padapter));
+	if (padapter == NULL)
+		goto exit;
+	padapter->dvobj = dvobj;
+	dvobj->if1 = padapter;
+
+	padapter->bDriverStopped = true;
+
+	padapter->hw_init_mutex = &usb_drv->hw_init_mutex;
+
+	/* step 1-1., decide the chip_type via vid/pid */
+	padapter->interface_type = RTW_USB;
+	chip_by_usb_id(padapter, pdid);
+
+	if (rtw_handle_dualmac(padapter, 1) != _SUCCESS)
+		goto free_adapter;
+
+	pnetdev = rtw_init_netdev(padapter);
+	if (pnetdev == NULL)
+		goto handle_dualmac;
+	SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj));
+	padapter = rtw_netdev_priv(pnetdev);
+
+	/* step 2. hook HalFunc, allocate HalData */
+	hal_set_hal_ops(padapter);
+
+	padapter->intf_start = &usb_intf_start;
+	padapter->intf_stop = &usb_intf_stop;
+
+	/* step init_io_priv */
+	rtw_init_io_priv(padapter, usb_set_intf_ops);
+
+	/* step read_chip_version */
+	rtw_hal_read_chip_version(padapter);
+
+	/* step usb endpoint mapping */
+	rtw_hal_chip_configure(padapter);
+
+	/* step read efuse/eeprom data and get mac_addr */
+	rtw_hal_read_chip_info(padapter);
+
+	/* step 5. */
+	if (rtw_init_drv_sw(padapter) == _FAIL) {
+		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+			 ("Initialize driver software resource Failed!\n"));
+		goto free_hal_data;
+	}
+
+#ifdef CONFIG_PM
+	if (padapter->pwrctrlpriv.bSupportRemoteWakeup) {
+		dvobj->pusbdev->do_remote_wakeup = 1;
+		pusb_intf->needs_remote_wakeup = 1;
+		device_init_wakeup(&pusb_intf->dev, 1);
+		DBG_88E("\n  padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n");
+		DBG_88E("\n  padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n",
+			device_may_wakeup(&pusb_intf->dev));
+	}
+#endif
+
+	/* 2012-07-11 Move here to prevent the 8723AS-VAU BT auto
+	 * suspend influence */
+	if (usb_autopm_get_interface(pusb_intf) < 0)
+			DBG_88E("can't get autopm:\n");
+
+	/*  alloc dev name after read efuse. */
+	rtw_init_netdev_name(pnetdev, padapter->registrypriv.ifname);
+	rtw_macaddr_cfg(padapter->eeprompriv.mac_addr);
+#ifdef CONFIG_88EU_P2P
+	rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr,
+				  padapter->eeprompriv.mac_addr);
+#endif
+	memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN);
+	DBG_88E("MAC Address from pnetdev->dev_addr =  %pM\n",
+		pnetdev->dev_addr);
+
+	/* step 6. Tell the network stack we exist */
+	if (register_netdev(pnetdev) != 0) {
+		RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("register_netdev() failed\n"));
+		goto free_hal_data;
+	}
+
+	DBG_88E("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n"
+		, padapter->bDriverStopped
+		, padapter->bSurpriseRemoved
+		, padapter->bup
+		, padapter->hw_init_completed
+	);
+
+	status = _SUCCESS;
+
+free_hal_data:
+	if (status != _SUCCESS && padapter->HalData)
+		kfree(padapter->HalData);
+handle_dualmac:
+	if (status != _SUCCESS)
+		rtw_handle_dualmac(padapter, 0);
+free_adapter:
+	if (status != _SUCCESS) {
+		if (pnetdev)
+			rtw_free_netdev(pnetdev);
+		else if (padapter)
+			rtw_vmfree((u8 *)padapter, sizeof(*padapter));
+		padapter = NULL;
+	}
+exit:
+	return padapter;
+}
+
+static void rtw_usb_if1_deinit(struct adapter *if1)
+{
+	struct net_device *pnetdev = if1->pnetdev;
+	struct mlme_priv *pmlmepriv = &if1->mlmepriv;
+
+	if (check_fwstate(pmlmepriv, _FW_LINKED))
+		rtw_disassoc_cmd(if1, 0, false);
+
+#ifdef CONFIG_88EU_AP_MODE
+	free_mlme_ap_info(if1);
+#endif
+
+	if (if1->DriverState != DRIVER_DISAPPEAR) {
+		if (pnetdev) {
+			/* will call netdev_close() */
+			unregister_netdev(pnetdev);
+			rtw_proc_remove_one(pnetdev);
+		}
+	}
+	rtw_cancel_all_timer(if1);
+
+	rtw_dev_unload(if1);
+	DBG_88E("+r871xu_dev_remove, hw_init_completed=%d\n",
+		if1->hw_init_completed);
+	rtw_handle_dualmac(if1, 0);
+	rtw_free_drv_sw(if1);
+	if (pnetdev)
+		rtw_free_netdev(pnetdev);
+}
+
+static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid)
+{
+	struct adapter *if1 = NULL;
+	int status;
+	struct dvobj_priv *dvobj;
+
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n"));
+
+	/* step 0. */
+	process_spec_devid(pdid);
+
+	/* Initialize dvobj_priv */
+	dvobj = usb_dvobj_init(pusb_intf);
+	if (dvobj == NULL) {
+		RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+			 ("initialize device object priv Failed!\n"));
+		goto exit;
+	}
+
+	if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid);
+	if (if1 == NULL) {
+		DBG_88E("rtw_init_primarystruct adapter Failed!\n");
+		goto free_dvobj;
+	}
+
+	if (ui_pid[1] != 0) {
+		DBG_88E("ui_pid[1]:%d\n", ui_pid[1]);
+		rtw_signal_process(ui_pid[1], SIGUSR2);
+	}
+
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-871x_drv - drv_init, success!\n"));
+
+	status = _SUCCESS;
+
+	if (status != _SUCCESS && if1)
+		rtw_usb_if1_deinit(if1);
+free_dvobj:
+	if (status != _SUCCESS)
+		usb_dvobj_deinit(pusb_intf);
+exit:
+	return status == _SUCCESS ? 0 : -ENODEV;
+}
+
+/*
+ * dev_remove() - our device is being removed
+*/
+/* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() => how to recognize both */
+static void rtw_dev_remove(struct usb_interface *pusb_intf)
+{
+	struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+	struct adapter *padapter = dvobj->if1;
+
+_func_enter_;
+
+	DBG_88E("+rtw_dev_remove\n");
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n"));
+
+	if (usb_drv->drv_registered)
+		padapter->bSurpriseRemoved = true;
+
+	rtw_pm_set_ips(padapter, IPS_NONE);
+	rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+	LeaveAllPowerSaveMode(padapter);
+
+	rtw_usb_if1_deinit(padapter);
+
+	usb_dvobj_deinit(pusb_intf);
+
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n"));
+	DBG_88E("-r871xu_dev_remove, done\n");
+_func_exit_;
+
+	return;
+}
+
+static int __init rtw_drv_entry(void)
+{
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n"));
+
+	DBG_88E(DRV_NAME " driver version=%s\n", DRIVERVERSION);
+	DBG_88E("build time: %s %s\n", __DATE__, __TIME__);
+
+	rtw_suspend_lock_init();
+
+	_rtw_mutex_init(&usb_drv->hw_init_mutex);
+
+	usb_drv->drv_registered = true;
+	return usb_register(&usb_drv->usbdrv);
+}
+
+static void __exit rtw_drv_halt(void)
+{
+	RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n"));
+	DBG_88E("+rtw_drv_halt\n");
+
+	rtw_suspend_lock_uninit();
+
+	usb_drv->drv_registered = false;
+	usb_deregister(&usb_drv->usbdrv);
+
+	_rtw_mutex_free(&usb_drv->hw_init_mutex);
+	DBG_88E("-rtw_drv_halt\n");
+}
+
+module_init(rtw_drv_entry);
+module_exit(rtw_drv_halt);
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
new file mode 100644
index 0000000..4c71e3b
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -0,0 +1,288 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ ******************************************************************************/
+#define _USB_OPS_LINUX_C_
+
+#include <drv_types.h>
+#include <usb_ops_linux.h>
+#include <rtw_sreset.h>
+
+unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
+{
+	unsigned int pipe = 0, ep_num = 0;
+	struct usb_device *pusbd = pdvobj->pusbdev;
+
+	if (addr == RECV_BULK_IN_ADDR) {
+		pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
+	} else if (addr == RECV_INT_IN_ADDR) {
+		pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]);
+	} else if (addr < HW_QUEUE_ENTRY) {
+		ep_num = pdvobj->Queue2Pipe[addr];
+		pipe = usb_sndbulkpipe(pusbd, ep_num);
+	}
+
+	return pipe;
+}
+
+struct zero_bulkout_context {
+	void *pbuf;
+	void *purb;
+	void *pirp;
+	void *padapter;
+};
+
+void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+}
+
+void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+}
+
+void usb_read_port_cancel(struct intf_hdl *pintfhdl)
+{
+	int i;
+	struct recv_buf *precvbuf;
+	struct adapter	*padapter = pintfhdl->padapter;
+	precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
+
+	DBG_88E("%s\n", __func__);
+
+	padapter->bReadPortCancel = true;
+
+	for (i = 0; i < NR_RECVBUFF; i++) {
+		precvbuf->reuse = true;
+		if (precvbuf->purb)
+			usb_kill_urb(precvbuf->purb);
+		precvbuf++;
+	}
+}
+
+static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+	struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
+	struct adapter	*padapter = pxmitbuf->padapter;
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	struct hal_data_8188e	*haldata;
+
+_func_enter_;
+
+	switch (pxmitbuf->flags) {
+	case VO_QUEUE_INX:
+		pxmitpriv->voq_cnt--;
+		break;
+	case VI_QUEUE_INX:
+		pxmitpriv->viq_cnt--;
+		break;
+	case BE_QUEUE_INX:
+		pxmitpriv->beq_cnt--;
+		break;
+	case BK_QUEUE_INX:
+		pxmitpriv->bkq_cnt--;
+		break;
+	case HIGH_QUEUE_INX:
+#ifdef CONFIG_88EU_AP_MODE
+		rtw_chk_hi_queue_cmd(padapter);
+#endif
+		break;
+	default:
+		break;
+	}
+
+	if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
+	    padapter->bWritePortCancel) {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+			 ("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+			 padapter->bDriverStopped, padapter->bSurpriseRemoved));
+		DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n",
+			__func__, padapter->bDriverStopped,
+			padapter->bSurpriseRemoved, padapter->bReadPortCancel,
+			pxmitbuf->ext_tag);
+
+		goto check_completion;
+	}
+
+	if (purb->status) {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete : purb->status(%d) != 0\n", purb->status));
+		DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status);
+		if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
+			sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
+		} else if (purb->status == -EINPROGRESS) {
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: EINPROGESS\n"));
+			goto check_completion;
+		} else if (purb->status == -ENOENT) {
+			DBG_88E("%s: -ENOENT\n", __func__);
+			goto check_completion;
+		} else if (purb->status == -ECONNRESET) {
+			DBG_88E("%s: -ECONNRESET\n", __func__);
+			goto check_completion;
+		} else if (purb->status == -ESHUTDOWN) {
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: ESHUTDOWN\n"));
+			padapter->bDriverStopped = true;
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bDriverStopped = true\n"));
+			goto check_completion;
+		} else {
+			padapter->bSurpriseRemoved = true;
+			DBG_88E("bSurpriseRemoved = true\n");
+			RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bSurpriseRemoved = true\n"));
+
+			goto check_completion;
+		}
+	}
+
+	haldata = GET_HAL_DATA(padapter);
+	haldata->srestpriv.last_tx_complete_time = rtw_get_current_time();
+
+check_completion:
+	rtw_sctx_done_err(&pxmitbuf->sctx,
+			  purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
+			  RTW_SCTX_DONE_SUCCESS);
+
+	rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+
+	tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+
+_func_exit_;
+}
+
+u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+	unsigned long irqL;
+	unsigned int pipe;
+	int status;
+	u32 ret = _FAIL;
+	struct urb *purb = NULL;
+	struct adapter *padapter = (struct adapter *)pintfhdl->padapter;
+	struct dvobj_priv	*pdvobj = adapter_to_dvobj(padapter);
+	struct xmit_priv	*pxmitpriv = &padapter->xmitpriv;
+	struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
+	struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
+	struct usb_device *pusbd = pdvobj->pusbdev;
+
+_func_enter_;
+
+	RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port\n"));
+
+	if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||
+	    (padapter->pwrctrlpriv.pnp_bstop_trx)) {
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+			 ("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
+		goto exit;
+	}
+
+	_enter_critical(&pxmitpriv->lock, &irqL);
+
+	switch (addr) {
+	case VO_QUEUE_INX:
+		pxmitpriv->voq_cnt++;
+		pxmitbuf->flags = VO_QUEUE_INX;
+		break;
+	case VI_QUEUE_INX:
+		pxmitpriv->viq_cnt++;
+		pxmitbuf->flags = VI_QUEUE_INX;
+		break;
+	case BE_QUEUE_INX:
+		pxmitpriv->beq_cnt++;
+		pxmitbuf->flags = BE_QUEUE_INX;
+		break;
+	case BK_QUEUE_INX:
+		pxmitpriv->bkq_cnt++;
+		pxmitbuf->flags = BK_QUEUE_INX;
+		break;
+	case HIGH_QUEUE_INX:
+		pxmitbuf->flags = HIGH_QUEUE_INX;
+		break;
+	default:
+		pxmitbuf->flags = MGT_QUEUE_INX;
+		break;
+	}
+
+	_exit_critical(&pxmitpriv->lock, &irqL);
+
+	purb	= pxmitbuf->pxmit_urb[0];
+
+	/* translate DMA FIFO addr to pipehandle */
+	pipe = ffaddr2pipehdl(pdvobj, addr);
+
+	usb_fill_bulk_urb(purb, pusbd, pipe,
+			  pxmitframe->buf_addr, /*  pxmitbuf->pbuf */
+			  cnt,
+			  usb_write_port_complete,
+			  pxmitbuf);/* context is pxmitbuf */
+
+	status = usb_submit_urb(purb, GFP_ATOMIC);
+	if (!status) {
+		struct hal_data_8188e	*haldata = GET_HAL_DATA(padapter);
+
+		haldata->srestpriv.last_tx_time = rtw_get_current_time();
+	} else {
+		rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
+		DBG_88E("usb_write_port, status =%d\n", status);
+		RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port(): usb_submit_urb, status =%x\n", status));
+
+		switch (status) {
+		case -ENODEV:
+			padapter->bDriverStopped = true;
+			break;
+		default:
+			break;
+		}
+		goto exit;
+	}
+
+	ret = _SUCCESS;
+
+/*    We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
+
+	RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port\n"));
+
+exit:
+	if (ret != _SUCCESS)
+		rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+_func_exit_;
+	return ret;
+}
+
+void usb_write_port_cancel(struct intf_hdl *pintfhdl)
+{
+	int i, j;
+	struct adapter	*padapter = pintfhdl->padapter;
+	struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
+
+	DBG_88E("%s\n", __func__);
+
+	padapter->bWritePortCancel = true;
+
+	for (i = 0; i < NR_XMITBUFF; i++) {
+		for (j = 0; j < 8; j++) {
+			if (pxmitbuf->pxmit_urb[j])
+				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+		}
+		pxmitbuf++;
+	}
+
+	pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
+	for (i = 0; i < NR_XMIT_EXTBUFF; i++) {
+		for (j = 0; j < 8; j++) {
+			if (pxmitbuf->pxmit_urb[j])
+				usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+		}
+		pxmitbuf++;
+	}
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
new file mode 100644
index 0000000..2e586c0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek 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
+ *
+ *
+ ******************************************************************************/
+#define _XMIT_OSDEP_C_
+
+#include <linux/version.h>
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <if_ether.h>
+#include <ip.h>
+#include <wifi.h>
+#include <mlme_osdep.h>
+#include <xmit_osdep.h>
+#include <osdep_intf.h>
+#include <usb_osintf.h>
+
+uint rtw_remainder_len(struct pkt_file *pfile)
+{
+	return pfile->buf_len - ((size_t)(pfile->cur_addr) -
+	       (size_t)(pfile->buf_start));
+}
+
+void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile)
+{
+_func_enter_;
+
+	pfile->pkt = pktptr;
+	pfile->cur_addr = pktptr->data;
+	pfile->buf_start = pktptr->data;
+	pfile->pkt_len = pktptr->len;
+	pfile->buf_len = pktptr->len;
+
+	pfile->cur_buffer = pfile->buf_start;
+
+_func_exit_;
+}
+
+uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
+{
+	uint	len = 0;
+
+_func_enter_;
+
+	len =  rtw_remainder_len(pfile);
+	len = (rlen > len) ? len : rlen;
+
+	if (rmem)
+		skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len);
+
+	pfile->cur_addr += len;
+	pfile->pkt_len -= len;
+
+_func_exit_;
+
+	return len;
+}
+
+int rtw_endofpktfile(struct pkt_file *pfile)
+{
+_func_enter_;
+
+	if (pfile->pkt_len == 0) {
+	_func_exit_;
+		return true;
+	}
+
+_func_exit_;
+
+	return false;
+}
+
+void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib)
+{
+}
+
+int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz)
+{
+	int i;
+
+	pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
+	if (pxmitbuf->pallocated_buf == NULL)
+		return _FAIL;
+
+	pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
+	pxmitbuf->dma_transfer_addr = 0;
+
+	for (i = 0; i < 8; i++) {
+		pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+		if (pxmitbuf->pxmit_urb[i] == NULL) {
+			DBG_88E("pxmitbuf->pxmit_urb[i]==NULL");
+			return _FAIL;
+		}
+	}
+	return _SUCCESS;
+}
+
+void rtw_os_xmit_resource_free(struct adapter *padapter,
+			       struct xmit_buf *pxmitbuf, u32 free_sz)
+{
+	int i;
+
+	for (i = 0; i < 8; i++)
+		usb_free_urb(pxmitbuf->pxmit_urb[i]);
+
+	kfree(pxmitbuf->pallocated_buf);
+}
+
+#define WMM_XMIT_THRESHOLD	(NR_XMITFRAME*2/5)
+
+void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+	u16	queue;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+	queue = skb_get_queue_mapping(pkt);
+	if (padapter->registrypriv.wifi_spec) {
+		if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
+		    (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
+			netif_wake_subqueue(padapter->pnetdev, queue);
+	} else {
+		if (__netif_subqueue_stopped(padapter->pnetdev, queue))
+			netif_wake_subqueue(padapter->pnetdev, queue);
+	}
+#else
+	if (netif_queue_stopped(padapter->pnetdev))
+		netif_wake_queue(padapter->pnetdev);
+#endif
+
+	dev_kfree_skb_any(pkt);
+}
+
+void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe)
+{
+	if (pxframe->pkt)
+		rtw_os_pkt_complete(padapter, pxframe->pkt);
+	pxframe->pkt = NULL;
+}
+
+void rtw_os_xmit_schedule(struct adapter *padapter)
+{
+	unsigned long  irql;
+	struct xmit_priv *pxmitpriv;
+
+	if (!padapter)
+		return;
+
+	pxmitpriv = &padapter->xmitpriv;
+
+	_enter_critical_bh(&pxmitpriv->lock, &irql);
+
+	if (rtw_txframes_pending(padapter))
+		tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+
+	_exit_critical_bh(&pxmitpriv->lock, &irql);
+}
+
+static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt)
+{
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	u16	queue;
+
+	queue = skb_get_queue_mapping(pkt);
+	if (padapter->registrypriv.wifi_spec) {
+		/* No free space for Tx, tx_worker is too slow */
+		if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
+			netif_stop_subqueue(padapter->pnetdev, queue);
+	} else {
+		if (pxmitpriv->free_xmitframe_cnt <= 4) {
+			if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
+				netif_stop_subqueue(padapter->pnetdev, queue);
+		}
+	}
+}
+
+static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb)
+{
+	struct	sta_priv *pstapriv = &padapter->stapriv;
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	unsigned long	irql;
+	struct list_head *phead, *plist;
+	struct sk_buff *newskb;
+	struct sta_info *psta = NULL;
+	s32	res;
+
+	_enter_critical_bh(&pstapriv->asoc_list_lock, &irql);
+	phead = &pstapriv->asoc_list;
+	plist = get_next(phead);
+
+	/* free sta asoc_queue */
+	while (!rtw_end_of_queue_search(phead, plist)) {
+		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+		plist = get_next(plist);
+
+		/* avoid   come from STA1 and send back STA1 */
+		if (!memcmp(psta->hwaddr, &skb->data[6], 6))
+			continue;
+
+		newskb = skb_copy(skb, GFP_ATOMIC);
+
+		if (newskb) {
+			memcpy(newskb->data, psta->hwaddr, 6);
+			res = rtw_xmit(padapter, &newskb);
+			if (res < 0) {
+				DBG_88E("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__);
+				pxmitpriv->tx_drop++;
+				dev_kfree_skb_any(newskb);
+			} else {
+				pxmitpriv->tx_pkts++;
+			}
+		} else {
+			DBG_88E("%s-%d: skb_copy() failed!\n", __func__, __LINE__);
+			pxmitpriv->tx_drop++;
+
+			_exit_critical_bh(&pstapriv->asoc_list_lock, &irql);
+			return false;	/*  Caller shall tx this multicast frame via normal way. */
+		}
+	}
+
+	_exit_critical_bh(&pstapriv->asoc_list_lock, &irql);
+	dev_kfree_skb_any(skb);
+	return true;
+}
+
+
+int rtw_xmit_entry(struct sk_buff *pkt, struct  net_device *pnetdev)
+{
+	struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev);
+	struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
+	s32 res = 0;
+
+_func_enter_;
+
+	RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
+
+	if (rtw_if_up(padapter) == false) {
+		RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit_entry: rtw_if_up fail\n"));
+		goto drop_packet;
+	}
+
+	rtw_check_xmit_resource(padapter, pkt);
+
+	if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) &&
+	    (IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) &&
+	    (padapter->registrypriv.wifi_spec == 0)) {
+		if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) {
+			res = rtw_mlcst2unicst(padapter, pkt);
+			if (res)
+				goto exit;
+		}
+	}
+
+	res = rtw_xmit(padapter, &pkt);
+	if (res < 0)
+		goto drop_packet;
+
+	pxmitpriv->tx_pkts++;
+	RT_TRACE(_module_xmit_osdep_c_, _drv_info_, ("rtw_xmit_entry: tx_pkts=%d\n", (u32)pxmitpriv->tx_pkts));
+	goto exit;
+
+drop_packet:
+	pxmitpriv->tx_drop++;
+	dev_kfree_skb_any(pkt);
+	RT_TRACE(_module_xmit_osdep_c_, _drv_notice_, ("rtw_xmit_entry: drop, tx_drop=%d\n", (u32)pxmitpriv->tx_drop));
+
+exit:
+
+_func_exit_;
+
+	return 0;
+}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
index 50c7bb7..74fbd70 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
index b9b3b52..dbe0e1c 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
index baf3b63..fa5603a 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
index fa607f9..7d075d3 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 2b6c61c..e068443 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
@@ -94,6 +94,7 @@
 static int rtl8192_pci_probe(struct pci_dev *pdev,
 			const struct pci_device_id *id);
 static void rtl8192_pci_disconnect(struct pci_dev *pdev);
+static irqreturn_t rtl8192_interrupt(int irq, void *netdev);
 
 static struct pci_driver rtl8192_pci_driver = {
 	.name = DRV_NAME,	/* Driver name   */
@@ -1324,7 +1325,7 @@
 		    (unsigned long)dev);
 
 	rtl8192_irq_disable(dev);
-	if (request_irq(dev->irq, (void *)rtl8192_interrupt_rsl, IRQF_SHARED,
+	if (request_irq(dev->irq, rtl8192_interrupt, IRQF_SHARED,
 	    dev->name, dev)) {
 		printk(KERN_ERR "Error allocating IRQ %d", dev->irq);
 		return -1;
@@ -2704,7 +2705,7 @@
 }
 
 
-irqreturn_type rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs)
+irqreturn_t rtl8192_interrupt(int irq, void *netdev)
 {
 	struct net_device *dev = (struct net_device *) netdev;
 	struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index 87d4d34..b015bf6 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
@@ -88,10 +88,6 @@
 	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID , \
 	.driver_data = (kernel_ulong_t)&(cfg)
 
-#define irqreturn_type irqreturn_t
-
-#define rtl8192_interrupt(x, y, z) rtl8192_interrupt_rsl(x, y)
-
 #define RTL_MAX_SCAN_SIZE 128
 
 #define RTL_RATE_MAX		30
@@ -1044,8 +1040,6 @@
 void check_rfctrl_gpio_timer(unsigned long data);
 
 void rtl8192_hw_wakeup_wq(void *data);
-irqreturn_type rtl8192_interrupt(int irq, void *netdev, struct pt_regs *regs);
-
 short rtl8192_pci_initdescring(struct net_device *dev);
 
 void rtl8192_cancel_deferred_work(struct r8192_priv *priv);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
index c1ccff4..a6778e0 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
index 9452e16..adea2b4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
index 0cfb3ec..529ea54 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
index 5abbee3..2ad92ee 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
index 28c7da6..356aec4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
index c9a7c56..a8c2ade 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
index df79d6c..962f2e5 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index 3485ef1..05ef49f 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -14,7 +14,7 @@
  * Copyright (c) 2004, Intel Corporation
  *
  * Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
+ * <andrea.merello@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
diff --git a/drivers/staging/rtl8192e/rtllib_debug.h b/drivers/staging/rtl8192e/rtllib_debug.h
index 2bfc115..c59f67b 100644
--- a/drivers/staging/rtl8192e/rtllib_debug.h
+++ b/drivers/staging/rtl8192e/rtllib_debug.h
@@ -2,7 +2,7 @@
  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
  *
  * Based on the r8180 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
index 84ea721..51d46e0 100644
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ b/drivers/staging/rtl8192e/rtllib_module.c
@@ -233,7 +233,8 @@
 	.open = open_debug_level,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.write = write_debug_level
+	.write = write_debug_level,
+	.release = single_release,
 };
 
 int __init rtllib_init(void)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index e75364e..8aeaed5 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -14,7 +14,7 @@
  ******************************************************************************
 
   Few modifications for Realtek's Wi-Fi drivers by
-  Andrea Merello <andreamrl@tiscali.it>
+  Andrea Merello <andrea.merello@gmail.com>
 
   A special thanks goes to Realtek for their support !
 
@@ -777,6 +777,8 @@
 
 		/* Allocate new skb for releasing to upper layer */
 		sub_skb = dev_alloc_skb(RTLLIB_SKBBUFFER_SIZE);
+		if (!sub_skb)
+			return 0;
 		skb_reserve(sub_skb, 12);
 		data_ptr = (u8 *)skb_put(sub_skb, skb->len);
 		memcpy(data_ptr, skb->data, skb->len);
@@ -825,6 +827,8 @@
 
 			/* Allocate new skb for releasing to upper layer */
 			sub_skb = dev_alloc_skb(nSubframe_Length + 12);
+			if (!sub_skb)
+				return 0;
 			skb_reserve(sub_skb, 12);
 			data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
 			memcpy(data_ptr, skb->data, nSubframe_Length);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index aefffac..0cbf6f5 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -1,5 +1,5 @@
 /* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * Mostly extracted from the rtl8180-sa2400 driver for the
  * in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index 740cf85..e6af8cf 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -1,5 +1,5 @@
 /* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * Mostly extracted from the rtl8180-sa2400 driver for the
  * in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index 759d7c7..1cc6a9d 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -25,7 +25,7 @@
 ******************************************************************************
 
   Few modifications for Realtek's Wi-Fi drivers by
-  Andrea Merello <andreamrl@tiscali.it>
+  Andrea Merello <andrea.merello@gmail.com>
 
   A special thanks goes to Realtek for their support !
 
diff --git a/drivers/staging/rtl8192u/authors b/drivers/staging/rtl8192u/authors
index b08bbae..0fab112 100644
--- a/drivers/staging/rtl8192u/authors
+++ b/drivers/staging/rtl8192u/authors
@@ -1 +1 @@
-Andrea Merello <andreamrl@tiscali.it>
+Andrea Merello <andrea.merello@gmail.com>
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
index c9f3bb3..bc64f05 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h
@@ -14,7 +14,7 @@
  * Copyright (c) 2004, Intel Corporation
  *
  * Modified for Realtek's wi-fi cards by Andrea Merello
- * <andreamrl@tiscali.it>
+ * <andrea.merello@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
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index e0870c0..434c431 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -268,7 +268,8 @@
 	.open = open_debug_level,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.write = write_debug_level
+	.write = write_debug_level,
+	.release = single_release,
 };
 
 int __init ieee80211_debug_init(void)
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index a6b1840..59900bf 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -14,7 +14,7 @@
  ******************************************************************************
 
   Few modifications for Realtek's Wi-Fi drivers by
-  Andrea Merello <andreamrl@tiscali.it>
+  Andrea Merello <andrea.merello@gmail.com>
 
   A special thanks goes to Realtek for their support !
 
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index 8a0075d..5fd6969 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -1,5 +1,5 @@
 /* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * Mostly extracted from the rtl8180-sa2400 driver for the
  * in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
index 60746b8..7b7d929 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c
@@ -1,5 +1,5 @@
 /* IEEE 802.11 SoftMAC layer
- * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+ * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
  *
  * Mostly extracted from the rtl8180-sa2400 driver for the
  * in-kernel generic ieee802.11 stack.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 9955042..a7bcc64f 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -25,7 +25,7 @@
 ******************************************************************************
 
   Few modifications for Realtek's Wi-Fi drivers by
-  Andrea Merello <andreamrl@tiscali.it>
+  Andrea Merello <andrea.merello@gmail.com>
 
   A special thanks goes to Realtek for their support !
 
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index d219998..c61729b 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -3,7 +3,7 @@
    memory is addressed by 16 bits words.
 
    This is part of rtl8180 OpenSource driver.
-   Copyright (C) Andrea Merello 2004  <andreamrl@tiscali.it>
+   Copyright (C) Andrea Merello 2004  <andrea.merello@gmail.com>
    Released under the terms of GPL (General Public Licence)
 
    Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h
index 5cea51e..ee55dbf 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.h
+++ b/drivers/staging/rtl8192u/r8180_93cx6.h
@@ -1,6 +1,6 @@
 /*
 	This is part of rtl8187 OpenSource driver
-	Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8192u/r8180_pm.c b/drivers/staging/rtl8192u/r8180_pm.c
index 0c58d0e..999968d 100644
--- a/drivers/staging/rtl8192u/r8180_pm.c
+++ b/drivers/staging/rtl8192u/r8180_pm.c
@@ -5,7 +5,7 @@
    does not do anything useful.
 
    This is part of rtl8180 OpenSource driver.
-   Copyright (C) Andrea Merello 2004  <andreamrl@tiscali.it>
+   Copyright (C) Andrea Merello 2004  <andrea.merello@gmail.com>
    Released under the terms of GPL (General Public Licence)
 */
 
diff --git a/drivers/staging/rtl8192u/r8180_pm.h b/drivers/staging/rtl8192u/r8180_pm.h
index 52d6fba..4be63da 100644
--- a/drivers/staging/rtl8192u/r8180_pm.h
+++ b/drivers/staging/rtl8192u/r8180_pm.h
@@ -5,7 +5,7 @@
 	does not do anything useful.
 
 	This is part of rtl8180 OpenSource driver.
-	Copyright (C) Andrea Merello 2004  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 */
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.h b/drivers/staging/rtl8192u/r8190_rtl8256.h
index b64dd66..592e780 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.h
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.h
@@ -1,7 +1,7 @@
 /*
   This is part of the rtl8180-sa2400 driver
   released under the GPL (See file COPYING for details).
-  Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
+  Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
 
   This files contains programming code for the rtl8256
   radio frontend.
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 338e7bc..b484ee1 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -1,6 +1,6 @@
 /*
  * This is part of rtl8187 OpenSource driver.
- * Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+ * Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
  * Released under the terms of GPL (General Public Licence)
  *
  * Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 14c14c2..cd0946d 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -3,7 +3,7 @@
  * Linux device driver for RTL8192U
  *
  * Based on the r8187 driver, which is:
- * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ * Copyright 2004-2005 Andrea Merello <andrea.merello@gmail.com>, et al.
  * 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.
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index 7e612aa..dd07a73 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -1,6 +1,6 @@
 /*
 	This is part of rtl8187 OpenSource driver.
-	Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part of the
diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c
index 3e25763..61f6620 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.c
+++ b/drivers/staging/rtl8192u/r8192U_wx.c
@@ -2,7 +2,7 @@
    This file contains wireless extension handlers.
 
    This is part of rtl8180 OpenSource driver.
-   Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it>
+   Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
    Released under the terms of GPL (General Public Licence)
 
    Parts of this driver are based on the GPL part
diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h
index 9f6b105..ae7a617 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.h
+++ b/drivers/staging/rtl8192u/r8192U_wx.h
@@ -1,6 +1,6 @@
 /*
 	This is part of rtl8180 OpenSource driver - v 0.3
-	Copyright (C) Andrea Merello 2004  <andreamrl@tiscali.it>
+	Copyright (C) Andrea Merello 2004  <andrea.merello@gmail.com>
 	Released under the terms of GPL (General Public Licence)
 
 	Parts of this driver are based on the GPL part of the official realtek driver
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 6810766..5bc361b 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -1,81 +1,61 @@
 /******************************************************************************
-
-     (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
-
- Module:	r819xusb_cmdpkt.c	(RTL8190 TX/RX command packet handler Source C File)
-
- Note:      The module is responsible for handling TX and RX command packet.
-			1. TX : Send set and query configuration command packet.
-			2. RX : Receive tx feedback, beacon state, query configuration
-				command packet.
-
- Function:
-
- Export:
-
- Abbrev:
-
- History:
-	Data		Who		Remark
-
-	05/06/2008  amy		Create initial version porting from windows driver.
-
-******************************************************************************/
+ *
+ *  (c) Copyright 2008, RealTEK Technologies Inc. All Rights Reserved.
+ *
+ *  Module:	r819xusb_cmdpkt.c
+ *		(RTL8190 TX/RX command packet handler Source C File)
+ *
+ *  Note:	The module is responsible for handling TX and RX command packet.
+ *		1. TX : Send set and query configuration command packet.
+ *		2. RX : Receive tx feedback, beacon state, query configuration
+ *			command packet.
+ *
+ *  Function:
+ *
+ *  Export:
+ *
+ *  Abbrev:
+ *
+ *  History:
+ *
+ *	Date		Who		Remark
+ *	05/06/2008	amy		Create initial version porting from
+ *					windows driver.
+ *
+ ******************************************************************************/
 #include "r8192U.h"
 #include "r819xU_cmdpkt.h"
-/*---------------------------Define Local Constant---------------------------*/
-/* Debug constant*/
-#define		CMPK_DEBOUNCE_CNT			1
-/* 2007/10/24 MH Add for printing a range of data. */
-#define		CMPK_PRINT(Address)\
-{\
-	unsigned char	i;\
-	u32	temp[10];\
-	\
-	memcpy(temp, Address, 40);\
-	for (i = 0; i <40; i+=4)\
-		printk("\r\n %08x", temp[i]);\
-}\
-/*---------------------------Define functions---------------------------------*/
 
-rt_status
-SendTxCommandPacket(
-	struct net_device *dev,
-	void			*pData,
-	u32				DataLen
-	)
+rt_status SendTxCommandPacket(struct net_device *dev, void *pData, u32 DataLen)
 {
 	rt_status	rtStatus = RT_STATUS_SUCCESS;
 	struct r8192_priv   *priv = ieee80211_priv(dev);
 	struct sk_buff	    *skb;
 	cb_desc		    *tcb_desc;
 	unsigned char	    *ptr_buf;
-	//bool	bLastInitPacket = false;
 
-	//PlatformAcquireSpinLock(Adapter, RT_TX_SPINLOCK);
-
-	//Get TCB and local buffer from common pool. (It is shared by CmdQ, MgntQ, and USB coalesce DataQ)
+	/* Get TCB and local buffer from common pool.
+	   (It is shared by CmdQ, MgntQ, and USB coalesce DataQ) */
 	skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + DataLen + 4);
-	memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
+	memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
 	tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
 	tcb_desc->queue_index = TXCMD_QUEUE;
 	tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_NORMAL;
 	tcb_desc->bLastIniPkt = 0;
 	skb_reserve(skb, USB_HWDESC_HEADER_LEN);
 	ptr_buf = skb_put(skb, DataLen);
-	memcpy(ptr_buf,pData,DataLen);
-	tcb_desc->txbuf_size= (u16)DataLen;
+	memcpy(ptr_buf, pData, DataLen);
+	tcb_desc->txbuf_size = (u16)DataLen;
 
-	if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
-			(!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
-			(priv->ieee80211->queue_stop) ) {
-			RT_TRACE(COMP_FIRMWARE,"===================NULL packet==================================> tx full!\n");
-			skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
-		} else {
-			priv->ieee80211->softmac_hard_start_xmit(skb,dev);
-		}
+	if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
+	    (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
+	    (priv->ieee80211->queue_stop)) {
+		RT_TRACE(COMP_FIRMWARE, "=== NULL packet ======> tx full!\n");
+		skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
+	} else {
+		priv->ieee80211->softmac_hard_start_xmit(skb, dev);
+	}
 
-	//PlatformReleaseSpinLock(Adapter, RT_TX_SPINLOCK);
 	return rtStatus;
 }
 
@@ -83,27 +63,25 @@
  * Function:	cmpk_message_handle_tx()
  *
  * Overview:	Driver internal module can call the API to send message to
- *				firmware side. For example, you can send a debug command packet.
- *				Or you can send a request for FW to modify RLX4181 LBUS HW bank.
- *				Otherwise, you can change MAC/PHT/RF register by firmware at
- *				run time. We do not support message more than one segment now.
+ *		firmware side. For example, you can send a debug command packet.
+ *		Or you can send a request for FW to modify RLX4181 LBUS HW bank.
+ *		Otherwise, you can change MAC/PHT/RF register by firmware at
+ *		run time. We do not support message more than one segment now.
  *
- * Input:		NONE
+ * Input:	NONE
  *
- * Output:		NONE
+ * Output:	NONE
  *
- * Return:		NONE
+ * Return:	NONE
  *
  * Revised History:
  *	When		Who		Remark
  *	05/06/2008	amy		porting from windows code.
  *
  *---------------------------------------------------------------------------*/
- extern	rt_status	cmpk_message_handle_tx(
-	struct net_device *dev,
-	u8	*codevirtualaddress,
-	u32	packettype,
-	u32	buffer_len)
+extern rt_status cmpk_message_handle_tx(struct net_device *dev,
+					u8 *codevirtualaddress,
+					u32 packettype, u32 buffer_len)
 {
 
 	bool	    rt_status = true;
@@ -113,8 +91,6 @@
 	struct r8192_priv   *priv = ieee80211_priv(dev);
 	u16		    frag_threshold;
 	u16		    frag_length, frag_offset = 0;
-	//u16		    total_size;
-	//int		    i;
 
 	rt_firmware	    *pfirmware = priv->pFirmware;
 	struct sk_buff	    *skb;
@@ -123,11 +99,11 @@
 	u8                  bLastIniPkt;
 
 	firmware_init_param(dev);
-	//Fragmentation might be required
+	/* Fragmentation might be required */
 	frag_threshold = pfirmware->cmdpacket_frag_thresold;
 	do {
 		if ((buffer_len - frag_offset) > frag_threshold) {
-			frag_length = frag_threshold ;
+			frag_length = frag_threshold;
 			bLastIniPkt = 0;
 
 		} else {
@@ -136,146 +112,127 @@
 
 		}
 
-		/* Allocate skb buffer to contain firmware info and tx descriptor info
-		 * add 4 to avoid packet appending overflow.
-		 * */
-		#ifdef RTL8192U
+		/* Allocate skb buffer to contain firmware info and tx
+		   descriptor info add 4 to avoid packet appending overflow. */
+#ifdef RTL8192U
 		skb  = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4);
-		#else
+#else
 		skb  = dev_alloc_skb(frag_length + 4);
-		#endif
-		memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev));
+#endif
+		memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev));
 		tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
 		tcb_desc->queue_index = TXCMD_QUEUE;
 		tcb_desc->bCmdOrInit = packettype;
 		tcb_desc->bLastIniPkt = bLastIniPkt;
 
-		#ifdef RTL8192U
+#ifdef RTL8192U
 		skb_reserve(skb, USB_HWDESC_HEADER_LEN);
-		#endif
+#endif
 
 		seg_ptr = skb_put(skb, buffer_len);
 		/*
 		 * Transform from little endian to big endian
 		 * and pending zero
 		 */
-		memcpy(seg_ptr,codevirtualaddress,buffer_len);
-		tcb_desc->txbuf_size= (u16)buffer_len;
+		memcpy(seg_ptr, codevirtualaddress, buffer_len);
+		tcb_desc->txbuf_size = (u16)buffer_len;
 
 
-		if (!priv->ieee80211->check_nic_enough_desc(dev,tcb_desc->queue_index)||
-			(!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index]))||\
-			(priv->ieee80211->queue_stop) ) {
-			RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n");
+		if (!priv->ieee80211->check_nic_enough_desc(dev, tcb_desc->queue_index) ||
+		    (!skb_queue_empty(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index])) ||
+		    (priv->ieee80211->queue_stop)) {
+			RT_TRACE(COMP_FIRMWARE, "======> tx full!\n");
 			skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb);
 		} else {
-			priv->ieee80211->softmac_hard_start_xmit(skb,dev);
+			priv->ieee80211->softmac_hard_start_xmit(skb, dev);
 		}
 
 		codevirtualaddress += frag_length;
 		frag_offset += frag_length;
 
-	}while(frag_offset < buffer_len);
+	} while (frag_offset < buffer_len);
 
 	return rt_status;
 
 
 #endif
-}	/* CMPK_Message_Handle_Tx */
+}
 
 /*-----------------------------------------------------------------------------
  * Function:    cmpk_counttxstatistic()
  *
  * Overview:
  *
- * Input:       PADAPTER	pAdapter		-	.
- *				CMPK_TXFB_T *psTx_FB	-	.
+ * Input:       PADAPTER	pAdapter
+ *              CMPK_TXFB_T	*psTx_FB
  *
  * Output:      NONE
  *
  * Return:      NONE
  *
  * Revised History:
- *  When		Who		Remark
- *  05/12/2008	amy	Create Version 0 porting from windows code.
+ *  When		Who	Remark
+ *  05/12/2008		amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void
-cmpk_count_txstatistic(
-	struct net_device *dev,
-	cmpk_txfb_t	*pstx_fb)
+static void cmpk_count_txstatistic(struct net_device *dev, cmpk_txfb_t *pstx_fb)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 #ifdef ENABLE_PS
 	RT_RF_POWER_STATE	rtState;
 
-	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
+	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
+					  (pu1Byte)(&rtState));
 
-	// When RF is off, we should not count the packet for hw/sw synchronize
-	// reason, ie. there may be a duration while sw switch is changed and hw
-	// switch is being changed. 2006.12.04, by shien chang.
+	/* When RF is off, we should not count the packet for hw/sw synchronize
+	   reason, ie. there may be a duration while sw switch is changed and
+	   hw switch is being changed. */
 	if (rtState == eRfOff)
-	{
 		return;
-	}
 #endif
 
 #ifdef TODO
 	if (pAdapter->bInHctTest)
 		return;
 #endif
-	/* We can not know the packet length and transmit type: broadcast or uni
-	   or multicast. So the relative statistics must be collected in tx
-	   feedback info. */
-	if (pstx_fb->tok)
-	{
+	/* We can not know the packet length and transmit type:
+	   broadcast or uni or multicast. So the relative statistics
+	   must be collected in tx feedback info. */
+	if (pstx_fb->tok) {
 		priv->stats.txfeedbackok++;
 		priv->stats.txoktotal++;
 		priv->stats.txokbytestotal += pstx_fb->pkt_length;
 		priv->stats.txokinperiod++;
 
 		/* We can not make sure broadcast/multicast or unicast mode. */
-		if (pstx_fb->pkt_type == PACKET_MULTICAST)
-		{
+		if (pstx_fb->pkt_type == PACKET_MULTICAST) {
 			priv->stats.txmulticast++;
 			priv->stats.txbytesmulticast += pstx_fb->pkt_length;
-		}
-		else if (pstx_fb->pkt_type == PACKET_BROADCAST)
-		{
+		} else if (pstx_fb->pkt_type == PACKET_BROADCAST) {
 			priv->stats.txbroadcast++;
 			priv->stats.txbytesbroadcast += pstx_fb->pkt_length;
-		}
-		else
-		{
+		} else {
 			priv->stats.txunicast++;
 			priv->stats.txbytesunicast += pstx_fb->pkt_length;
 		}
-	}
-	else
-	{
+	} else {
 		priv->stats.txfeedbackfail++;
 		priv->stats.txerrtotal++;
 		priv->stats.txerrbytestotal += pstx_fb->pkt_length;
 
 		/* We can not make sure broadcast/multicast or unicast mode. */
 		if (pstx_fb->pkt_type == PACKET_MULTICAST)
-		{
 			priv->stats.txerrmulticast++;
-		}
 		else if (pstx_fb->pkt_type == PACKET_BROADCAST)
-		{
 			priv->stats.txerrbroadcast++;
-		}
 		else
-		{
 			priv->stats.txerrunicast++;
-		}
 	}
 
 	priv->stats.txretrycount += pstx_fb->retry_cnt;
 	priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
 
-}	/* cmpk_CountTxStatistic */
+}
 
 
 
@@ -283,80 +240,63 @@
  * Function:    cmpk_handle_tx_feedback()
  *
  * Overview:	The function is responsible for extract the message inside TX
- *				feedbck message from firmware. It will contain dedicated info in
- *				ws-06-0063-rtl8190-command-packet-specification. Please
- *				refer to chapter "TX Feedback Element". We have to read 20 bytes
- *				in the command packet.
+ *		feedbck message from firmware. It will contain dedicated info in
+ *		ws-06-0063-rtl8190-command-packet-specification.
+ *		Please refer to chapter "TX Feedback Element".
+ *              We have to read 20 bytes in the command packet.
  *
- * Input:       struct net_device *    dev
- *				u8	*	pmsg		-	Msg Ptr of the command packet.
+ * Input:       struct net_device	*dev
+ *              u8			*pmsg	- Msg Ptr of the command packet.
  *
  * Output:      NONE
  *
  * Return:      NONE
  *
  * Revised History:
- *  When		Who		Remark
- *  05/08/2008	amy		Create Version 0 porting from windows code.
+ *  When		Who	Remark
+ *  05/08/2008		amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void
-cmpk_handle_tx_feedback(
-	struct net_device *dev,
-	u8	*pmsg)
+static void cmpk_handle_tx_feedback(struct net_device *dev, u8 *pmsg)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
-	cmpk_txfb_t		rx_tx_fb;	/* */
+	cmpk_txfb_t		rx_tx_fb;
 
 	priv->stats.txfeedback++;
 
-	/* 0. Display received message. */
-	//cmpk_Display_Message(CMPK_RX_TX_FB_SIZE, pMsg);
-
 	/* 1. Extract TX feedback info from RFD to temp structure buffer. */
 	/* It seems that FW use big endian(MIPS) and DRV use little endian in
 	   windows OS. So we have to read the content byte by byte or transfer
 	   endian type before copy the message copy. */
-	/* 2007/07/05 MH Use pointer to transfer structure memory. */
-	//memcpy((UINT8 *)&rx_tx_fb, pMsg, sizeof(CMPK_TXFB_T));
+	/* Use pointer to transfer structure memory. */
 	memcpy((u8 *)&rx_tx_fb, pmsg, sizeof(cmpk_txfb_t));
 	/* 2. Use tx feedback info to count TX statistics. */
 	cmpk_count_txstatistic(dev, &rx_tx_fb);
-	/* 2007/01/17 MH Comment previous method for TX statistic function. */
+	/* Comment previous method for TX statistic function. */
 	/* Collect info TX feedback packet to fill TCB. */
 	/* We can not know the packet length and transmit type: broadcast or uni
 	   or multicast. */
-	//CountTxStatistics( pAdapter, &tcb );
 
-}	/* cmpk_Handle_Tx_Feedback */
+}
 
-void
-cmdpkt_beacontimerinterrupt_819xusb(
-	struct net_device *dev
-)
+void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 	u16 tx_rate;
-	{
-		//
-		// 070117, rcnjko: 87B have to S/W beacon for DTM encryption_cmn.
-		//
-		if (priv->ieee80211->current_network.mode == IEEE_A  ||
+		/* 87B have to S/W beacon for DTM encryption_cmn. */
+		if (priv->ieee80211->current_network.mode == IEEE_A ||
 			priv->ieee80211->current_network.mode == IEEE_N_5G ||
-			(priv->ieee80211->current_network.mode == IEEE_N_24G  && (!priv->ieee80211->pHTInfo->bCurSuppCCK)))
-		{
+			(priv->ieee80211->current_network.mode == IEEE_N_24G &&
+			 (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
 			tx_rate = 60;
 			DMESG("send beacon frame  tx rate is 6Mbpm\n");
-		}
-		else
-		{
-			tx_rate =10;
+		} else {
+			tx_rate = 10;
 			DMESG("send beacon frame  tx rate is 1Mbpm\n");
 		}
 
-		rtl819xusb_beacon_tx(dev,tx_rate); // HW Beacon
+		rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
 
-	}
 
 }
 
@@ -367,151 +307,129 @@
  * Function:    cmpk_handle_interrupt_status()
  *
  * Overview:    The function is responsible for extract the message from
- *				firmware. It will contain dedicated info in
- *				ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
- *				Please refer to chapter "Interrupt Status Element".
+ *		firmware. It will contain dedicated info in
+ *		ws-07-0063-v06-rtl819x-command-packet-specification-070315.doc.
+ *		Please refer to chapter "Interrupt Status Element".
  *
- * Input:       struct net_device *dev,
- *			u8*	pmsg		-	Message Pointer of the command packet.
+ * Input:       struct net_device *dev
+ *              u8 *pmsg		- Message Pointer of the command packet.
  *
  * Output:      NONE
  *
  * Return:      NONE
  *
  * Revised History:
- *  When			Who			Remark
- *  05/12/2008	amy		Add this for rtl8192 porting from windows code.
+ *  When		Who	Remark
+ *  05/12/2008		amy	Add this for rtl8192 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void
-cmpk_handle_interrupt_status(
-	struct net_device *dev,
-	u8	*pmsg)
+static void cmpk_handle_interrupt_status(struct net_device *dev, u8 *pmsg)
 {
 	cmpk_intr_sta_t		rx_intr_status;	/* */
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
 	DMESG("---> cmpk_Handle_Interrupt_Status()\n");
 
-	/* 0. Display received message. */
-	//cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
-
 	/* 1. Extract TX feedback info from RFD to temp structure buffer. */
 	/* It seems that FW use big endian(MIPS) and DRV use little endian in
 	   windows OS. So we have to read the content byte by byte or transfer
 	   endian type before copy the message copy. */
-	//rx_bcn_state.Element_ID	= pMsg[0];
-	//rx_bcn_state.Length		= pMsg[1];
 	rx_intr_status.length = pmsg[1];
-	if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2))
-	{
+	if (rx_intr_status.length != (sizeof(cmpk_intr_sta_t) - 2)) {
 		DMESG("cmpk_Handle_Interrupt_Status: wrong length!\n");
 		return;
 	}
 
 
-	// Statistics of beacon for ad-hoc mode.
-	if (	priv->ieee80211->iw_mode == IW_MODE_ADHOC)
-	{
-		//2 maybe need endian transform?
+	/* Statistics of beacon for ad-hoc mode. */
+	if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
+		/* 2 maybe need endian transform? */
 		rx_intr_status.interrupt_status = *((u32 *)(pmsg + 4));
-		//rx_intr_status.InterruptStatus = N2H4BYTE(*((UINT32 *)(pMsg + 4)));
 
-		DMESG("interrupt status = 0x%x\n", rx_intr_status.interrupt_status);
+		DMESG("interrupt status = 0x%x\n",
+		      rx_intr_status.interrupt_status);
 
-		if (rx_intr_status.interrupt_status & ISR_TxBcnOk)
-		{
+		if (rx_intr_status.interrupt_status & ISR_TxBcnOk) {
 			priv->ieee80211->bibsscoordinator = true;
 			priv->stats.txbeaconokint++;
-		}
-		else if (rx_intr_status.interrupt_status & ISR_TxBcnErr)
-		{
+		} else if (rx_intr_status.interrupt_status & ISR_TxBcnErr) {
 			priv->ieee80211->bibsscoordinator = false;
 			priv->stats.txbeaconerr++;
 		}
 
 		if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
-		{
 			cmdpkt_beacontimerinterrupt_819xusb(dev);
-		}
 
 	}
 
-	 // Other informations in interrupt status we need?
+	/* Other informations in interrupt status we need? */
 
 
 	DMESG("<---- cmpk_handle_interrupt_status()\n");
 
-}	/* cmpk_handle_interrupt_status */
+}
 
 
 /*-----------------------------------------------------------------------------
  * Function:    cmpk_handle_query_config_rx()
  *
  * Overview:    The function is responsible for extract the message from
- *				firmware. It will contain dedicated info in
- *				ws-06-0063-rtl8190-command-packet-specification. Please
- *				refer to chapter "Beacon State Element".
+ *		firmware. It will contain dedicated info in
+ *		ws-06-0063-rtl8190-command-packet-specification. Please
+ *		refer to chapter "Beacon State Element".
  *
- * Input:       u8 *  pmsg	-	Message Pointer of the command packet.
+ * Input:       u8    *pmsg	-	Message Pointer of the command packet.
  *
  * Output:      NONE
  *
  * Return:      NONE
  *
  * Revised History:
- *  When		Who		Remark
- *  05/12/2008	amy		Create Version 0 porting from windows code.
+ *  When		Who	Remark
+ *  05/12/2008		amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void
-cmpk_handle_query_config_rx(
-	struct net_device *dev,
-	u8	   *pmsg)
+static void cmpk_handle_query_config_rx(struct net_device *dev, u8 *pmsg)
 {
-	cmpk_query_cfg_t	rx_query_cfg;	/* */
+	cmpk_query_cfg_t	rx_query_cfg;
 
-	/* 0. Display received message. */
-	//cmpk_Display_Message(CMPK_RX_BEACON_STATE_SIZE, pMsg);
 
 	/* 1. Extract TX feedback info from RFD to temp structure buffer. */
 	/* It seems that FW use big endian(MIPS) and DRV use little endian in
 	   windows OS. So we have to read the content byte by byte or transfer
 	   endian type before copy the message copy. */
-	//rx_query_cfg.Element_ID	= pMsg[0];
-	//rx_query_cfg.Length		= pMsg[1];
-	rx_query_cfg.cfg_action		= (pmsg[4] & 0x80000000)>>31;
+	rx_query_cfg.cfg_action		= (pmsg[4] & 0x80000000) >> 31;
 	rx_query_cfg.cfg_type		= (pmsg[4] & 0x60) >> 5;
 	rx_query_cfg.cfg_size		= (pmsg[4] & 0x18) >> 3;
 	rx_query_cfg.cfg_page		= (pmsg[6] & 0x0F) >> 0;
-	rx_query_cfg.cfg_offset			= pmsg[7];
-	rx_query_cfg.value			= (pmsg[8] << 24) | (pmsg[9] << 16) |
-								  (pmsg[10] << 8) | (pmsg[11] << 0);
-	rx_query_cfg.mask			= (pmsg[12] << 24) | (pmsg[13] << 16) |
-								  (pmsg[14] << 8) | (pmsg[15] << 0);
+	rx_query_cfg.cfg_offset		= pmsg[7];
+	rx_query_cfg.value		= (pmsg[8]  << 24) | (pmsg[9]  << 16) |
+					  (pmsg[10] <<  8) | (pmsg[11] <<  0);
+	rx_query_cfg.mask		= (pmsg[12] << 24) | (pmsg[13] << 16) |
+					  (pmsg[14] <<  8) | (pmsg[15] <<  0);
 
-}	/* cmpk_Handle_Query_Config_Rx */
+}
 
 
 /*-----------------------------------------------------------------------------
  * Function:	cmpk_count_tx_status()
  *
  * Overview:	Count aggregated tx status from firmwar of one type rx command
- *				packet element id = RX_TX_STATUS.
+ *		packet element id = RX_TX_STATUS.
  *
- * Input:		NONE
+ * Input:	NONE
  *
- * Output:		NONE
+ * Output:	NONE
  *
- * Return:		NONE
+ * Return:	NONE
  *
  * Revised History:
- *	When		Who		Remark
- *	05/12/2008	amy		Create Version 0 porting from windows code.
+ *	When		Who	Remark
+ *	05/12/2008	amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void	cmpk_count_tx_status(	struct net_device *dev,
-									cmpk_tx_status_t	*pstx_status)
+static void cmpk_count_tx_status(struct net_device *dev,
+				 cmpk_tx_status_t *pstx_status)
 {
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
@@ -519,15 +437,14 @@
 
 	RT_RF_POWER_STATE	rtstate;
 
-	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
+	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
+					  (pu1Byte)(&rtState));
 
-	// When RF is off, we should not count the packet for hw/sw synchronize
-	// reason, ie. there may be a duration while sw switch is changed and hw
-	// switch is being changed. 2006.12.04, by shien chang.
+	/* When RF is off, we should not count the packet for hw/sw synchronize
+	   reason, ie. there may be a duration while sw switch is changed and
+	   hw switch is being changed. */
 	if (rtState == eRfOff)
-	{
 		return;
-	}
 #endif
 
 	priv->stats.txfeedbackok	+= pstx_status->txok;
@@ -536,15 +453,12 @@
 	priv->stats.txfeedbackfail	+= pstx_status->txfail;
 	priv->stats.txerrtotal		+= pstx_status->txfail;
 
-	priv->stats.txretrycount		+= pstx_status->txretry;
+	priv->stats.txretrycount	+= pstx_status->txretry;
 	priv->stats.txfeedbackretry	+= pstx_status->txretry;
 
-	//pAdapter->TxStats.NumTxOkBytesTotal += psTx_FB->pkt_length;
-	//pAdapter->TxStats.NumTxErrBytesTotal += psTx_FB->pkt_length;
-	//pAdapter->MgntInfo.LinkDetectInfo.NumTxOkInPeriod++;
 
-	priv->stats.txmulticast	+= pstx_status->txmcok;
-	priv->stats.txbroadcast	+= pstx_status->txbcok;
+	priv->stats.txmulticast		+= pstx_status->txmcok;
+	priv->stats.txbroadcast		+= pstx_status->txbcok;
 	priv->stats.txunicast		+= pstx_status->txucok;
 
 	priv->stats.txerrmulticast	+= pstx_status->txmcfail;
@@ -553,10 +467,10 @@
 
 	priv->stats.txbytesmulticast	+= pstx_status->txmclength;
 	priv->stats.txbytesbroadcast	+= pstx_status->txbclength;
-	priv->stats.txbytesunicast		+= pstx_status->txuclength;
+	priv->stats.txbytesunicast	+= pstx_status->txuclength;
 
-	priv->stats.last_packet_rate		= pstx_status->rate;
-}	/* cmpk_CountTxStatus */
+	priv->stats.last_packet_rate	= pstx_status->rate;
+}
 
 
 
@@ -564,7 +478,7 @@
  * Function:	cmpk_handle_tx_status()
  *
  * Overview:	Firmware add a new tx feedback status to reduce rx command
- *				packet buffer operation load.
+ *		packet buffer operation load.
  *
  * Input:		NONE
  *
@@ -573,22 +487,19 @@
  * Return:		NONE
  *
  * Revised History:
- *	When		Who		Remark
- *	05/12/2008	amy		Create Version 0 porting from windows code.
+ *	When		Who	Remark
+ *	05/12/2008	amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void
-cmpk_handle_tx_status(
-	struct net_device *dev,
-	u8	   *pmsg)
+static void cmpk_handle_tx_status(struct net_device *dev, u8 *pmsg)
 {
-	cmpk_tx_status_t	rx_tx_sts;	/* */
+	cmpk_tx_status_t	rx_tx_sts;
 
 	memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
 	/* 2. Use tx feedback info to count TX statistics. */
 	cmpk_count_tx_status(dev, &rx_tx_sts);
 
-}	/* cmpk_Handle_Tx_Status */
+}
 
 
 /*-----------------------------------------------------------------------------
@@ -603,82 +514,71 @@
  * Return:		NONE
  *
  * Revised History:
- *	When		Who		Remark
- *	05/12/2008	amy		Create Version 0 porting from windows code.
+ *	When		Who	Remark
+ *	05/12/2008	amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-static	void
-cmpk_handle_tx_rate_history(
-	struct net_device *dev,
-	u8	   *pmsg)
+static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
 {
 	cmpk_tx_rahis_t	*ptxrate;
-//	RT_RF_POWER_STATE	rtState;
-	u8				i, j;
-	u16				length = sizeof(cmpk_tx_rahis_t);
-	u32				*ptemp;
+	u8		i, j;
+	u16		length = sizeof(cmpk_tx_rahis_t);
+	u32		*ptemp;
 	struct r8192_priv *priv = ieee80211_priv(dev);
 
 
 #ifdef ENABLE_PS
-	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState));
+	pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
+					  (pu1Byte)(&rtState));
 
-	// When RF is off, we should not count the packet for hw/sw synchronize
-	// reason, ie. there may be a duration while sw switch is changed and hw
-	// switch is being changed. 2006.12.04, by shien chang.
+	/* When RF is off, we should not count the packet for hw/sw synchronize
+	   reason, ie. there may be a duration while sw switch is changed and
+	   hw switch is being changed. */
 	if (rtState == eRfOff)
-	{
 		return;
-	}
 #endif
 
 	ptemp = (u32 *)pmsg;
 
-	//
-	// Do endian transfer to word alignment(16 bits) for windows system.
-	// You must do different endian transfer for linux and MAC OS
-	//
-	for (i = 0; i < (length/4); i++)
-	{
+	/* Do endian transfer to word alignment(16 bits) for windows system.
+	   You must do different endian transfer for linux and MAC OS */
+	for (i = 0; i < (length/4); i++) {
 		u16	 temp1, temp2;
 
-		temp1 = ptemp[i]&0x0000FFFF;
-		temp2 = ptemp[i]>>16;
-		ptemp[i] = (temp1<<16)|temp2;
+		temp1 = ptemp[i] & 0x0000FFFF;
+		temp2 = ptemp[i] >> 16;
+		ptemp[i] = (temp1 << 16) | temp2;
 	}
 
 	ptxrate = (cmpk_tx_rahis_t *)pmsg;
 
-	if (ptxrate == NULL )
-	{
+	if (ptxrate == NULL)
 		return;
-	}
 
-	for (i = 0; i < 16; i++)
-	{
-		// Collect CCK rate packet num
+	for (i = 0; i < 16; i++) {
+		/* Collect CCK rate packet num */
 		if (i < 4)
 			priv->stats.txrate.cck[i] += ptxrate->cck[i];
 
-		// Collect OFDM rate packet num
-		if (i< 8)
+		/* Collect OFDM rate packet num */
+		if (i < 8)
 			priv->stats.txrate.ofdm[i] += ptxrate->ofdm[i];
 
 		for (j = 0; j < 4; j++)
 			priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
 	}
 
-}	/* cmpk_Handle_Tx_Rate_History */
+}
 
 
 /*-----------------------------------------------------------------------------
  * Function:    cmpk_message_handle_rx()
  *
  * Overview:    In the function, we will capture different RX command packet
- *				info. Every RX command packet element has different message
- *				length and meaning in content. We only support three type of RX
- *				command packet now. Please refer to document
- *				ws-06-0063-rtl8190-command-packet-specification.
+ *		info. Every RX command packet element has different message
+ *		length and meaning in content. We only support three type of RX
+ *		command packet now. Please refer to document
+ *		ws-06-0063-rtl8190-command-packet-specification.
  *
  * Input:       NONE
  *
@@ -687,30 +587,22 @@
  * Return:      NONE
  *
  * Revised History:
- *  When		Who		Remark
- *  05/06/2008	amy		Create Version 0 porting from windows code.
+ *  When		Who	Remark
+ *  05/06/2008		amy	Create Version 0 porting from windows code.
  *
  *---------------------------------------------------------------------------*/
-extern	u32
-cmpk_message_handle_rx(
-	struct net_device *dev,
-	struct ieee80211_rx_stats *pstats)
+extern u32 cmpk_message_handle_rx(struct net_device *dev,
+				  struct ieee80211_rx_stats *pstats)
 {
-//	u32			debug_level = DBG_LOUD;
 	int			total_length;
 	u8			cmd_length, exe_cnt = 0;
 	u8			element_id;
 	u8			*pcmd_buff;
 
-	/* 0. Check inpt arguments. If is is a command queue message or pointer is
-	      null. */
-	if (/*(prfd->queue_id != CMPK_RX_QUEUE_ID) || */(pstats== NULL))
-	{
-		/* Print error message. */
-		/*RT_TRACE(COMP_SEND, DebugLevel,
-				("\n\r[CMPK]-->Err queue id or pointer"));*/
+	/* 0. Check inpt arguments. If is is a command queue message or
+	   pointer is null. */
+	if (pstats == NULL)
 		return 0;	/* This is not a command packet. */
-	}
 
 	/* 1. Read received command packet message length from RFD. */
 	total_length = pstats->Length;
@@ -720,67 +612,58 @@
 
 	/* 3. Read command packet element id and length. */
 	element_id = pcmd_buff[0];
-	/*RT_TRACE(COMP_SEND, DebugLevel,
-			("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
 
 	/* 4. Check every received command packet content according to different
-	      element type. Because FW may aggregate RX command packet to minimize
-	      transmit time between DRV and FW.*/
-	// Add a counter to prevent the lock in the loop from being held too long
-	while (total_length > 0 && exe_cnt++ < 100)
-	{
-		/* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
+	      element type. Because FW may aggregate RX command packet to
+	      minimize transmit time between DRV and FW.*/
+	/* Add a counter to prevent the lock in the loop from being held too
+	   long */
+	while (total_length > 0 && exe_cnt++ < 100) {
+		/* We support aggregation of different cmd in the same packet */
 		element_id = pcmd_buff[0];
 
-		switch (element_id)
-		{
-			case RX_TX_FEEDBACK:
-				cmpk_handle_tx_feedback (dev, pcmd_buff);
-				cmd_length = CMPK_RX_TX_FB_SIZE;
-				break;
+		switch (element_id) {
+		case RX_TX_FEEDBACK:
+			cmpk_handle_tx_feedback(dev, pcmd_buff);
+			cmd_length = CMPK_RX_TX_FB_SIZE;
+			break;
 
-			case RX_INTERRUPT_STATUS:
-				cmpk_handle_interrupt_status(dev, pcmd_buff);
-				cmd_length = sizeof(cmpk_intr_sta_t);
-				break;
+		case RX_INTERRUPT_STATUS:
+			cmpk_handle_interrupt_status(dev, pcmd_buff);
+			cmd_length = sizeof(cmpk_intr_sta_t);
+			break;
 
-			case BOTH_QUERY_CONFIG:
-				cmpk_handle_query_config_rx(dev, pcmd_buff);
-				cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
-				break;
+		case BOTH_QUERY_CONFIG:
+			cmpk_handle_query_config_rx(dev, pcmd_buff);
+			cmd_length = CMPK_BOTH_QUERY_CONFIG_SIZE;
+			break;
 
-			case RX_TX_STATUS:
-				cmpk_handle_tx_status(dev, pcmd_buff);
-				cmd_length = CMPK_RX_TX_STS_SIZE;
-				break;
+		case RX_TX_STATUS:
+			cmpk_handle_tx_status(dev, pcmd_buff);
+			cmd_length = CMPK_RX_TX_STS_SIZE;
+			break;
 
-			case RX_TX_PER_PKT_FEEDBACK:
-				// You must at lease add a switch case element here,
-				// Otherwise, we will jump to default case.
-				//DbgPrint("CCX Test\r\n");
-				cmd_length = CMPK_RX_TX_FB_SIZE;
-				break;
+		case RX_TX_PER_PKT_FEEDBACK:
+			/* You must at lease add a switch case element here,
+			   Otherwise, we will jump to default case. */
+			cmd_length = CMPK_RX_TX_FB_SIZE;
+			break;
 
-			case RX_TX_RATE_HISTORY:
-				//DbgPrint(" rx tx rate history\r\n");
-				cmpk_handle_tx_rate_history(dev, pcmd_buff);
-				cmd_length = CMPK_TX_RAHIS_SIZE;
-				break;
+		case RX_TX_RATE_HISTORY:
+			cmpk_handle_tx_rate_history(dev, pcmd_buff);
+			cmd_length = CMPK_TX_RAHIS_SIZE;
+			break;
 
-			default:
+		default:
 
-				RT_TRACE(COMP_ERR, "---->cmpk_message_handle_rx():unknow CMD Element\n");
-				return 1;	/* This is a command packet. */
+			RT_TRACE(COMP_ERR, "---->%s():unknown CMD Element\n",
+				 __func__);
+			return 1;	/* This is a command packet. */
 		}
-		// 2007/01/22 MH Display received rx command packet info.
-		//cmpk_Display_Message(cmd_length, pcmd_buff);
-
-		// 2007/01/22 MH Add to display tx statistic.
-		//cmpk_DisplayTxStatistic(pAdapter);
 
 		total_length -= cmd_length;
 		pcmd_buff    += cmd_length;
-	}	/* while (total_length > 0) */
+	}
 	return	1;	/* This is a command packet. */
 
-}	/* CMPK_Message_Handle_Rx */
+}
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index f034567..d58aa7e 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -1000,12 +1000,8 @@
 		sprintf(ext, "LINKSPEED %d", mbps);
 	} else if (0 == strcasecmp(ext, "MACADDR")) {
 		/*Return mac address of the station */
-		/*Macaddr = xx.xx.xx.xx.xx.xx */
-		sprintf(ext,
-			"MACADDR = %02x.%02x.%02x.%02x.%02x.%02x",
-			*(dev->dev_addr), *(dev->dev_addr+1),
-			*(dev->dev_addr+2), *(dev->dev_addr+3),
-			*(dev->dev_addr+4), *(dev->dev_addr+5));
+		/* Macaddr = xx:xx:xx:xx:xx:xx */
+		sprintf(ext, "MACADDR = %pM", dev->dev_addr);
 	} else if (0 == strcasecmp(ext, "SCAN-ACTIVE")) {
 		/*Set scan type to active */
 		/*OK if successful */
diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c
index 48b9fb1..495272d 100644
--- a/drivers/staging/silicom/bpctl_mod.c
+++ b/drivers/staging/silicom/bpctl_mod.c
@@ -59,7 +59,7 @@
 	struct proc_dir_entry *bypass_entry;
 };
 
-typedef struct _bpctl_dev {
+struct bpctl_dev {
 	char *name;
 	char *desc;
 	struct pci_dev *pdev;	/* PCI device */
@@ -102,26 +102,26 @@
 	char *bp_tx_data;
 	struct bypass_pfs_sd bypass_pfs_set;
 
-} bpctl_dev_t;
+};
 
-static bpctl_dev_t *bpctl_dev_arr;
+static struct bpctl_dev *bpctl_dev_arr;
 
 static struct semaphore bpctl_sema;
 static int device_num;
 
 static int get_dev_idx(int ifindex);
-static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev);
-static int disc_status(bpctl_dev_t *pbpctl_dev);
-static int bypass_status(bpctl_dev_t *pbpctl_dev);
-static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left);
-static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev);
+static struct bpctl_dev *get_master_port_fn(struct bpctl_dev *pbpctl_dev);
+static int disc_status(struct bpctl_dev *pbpctl_dev);
+static int bypass_status(struct bpctl_dev *pbpctl_dev);
+static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left);
+static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev);
 static void if_scan_init(void);
 
-int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block);
-int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block);
+int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block);
+int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block);
 int bp_proc_create(void);
 
-int is_bypass_fn(bpctl_dev_t *pbpctl_dev);
+int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
 int get_dev_idx_bsf(int bus, int slot, int func);
 
 static unsigned long str_to_hex(char *p);
@@ -129,7 +129,7 @@
 			   unsigned long event, void *ptr)
 {
 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-	static bpctl_dev_t *pbpctl_dev, *pbpctl_dev_m;
+	static struct bpctl_dev *pbpctl_dev, *pbpctl_dev_m;
 	int dev_num = 0, ret = 0, ret_d = 0, time_left = 0;
 	/* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */
 	/* return NOTIFY_DONE; */
@@ -284,17 +284,17 @@
 	.notifier_call = bp_device_event,
 };
 
-int is_bypass_fn(bpctl_dev_t *pbpctl_dev);
-int wdt_time_left(bpctl_dev_t *pbpctl_dev);
+int is_bypass_fn(struct bpctl_dev *pbpctl_dev);
+int wdt_time_left(struct bpctl_dev *pbpctl_dev);
 
-static void write_pulse(bpctl_dev_t *pbpctl_dev,
+static void write_pulse(struct bpctl_dev *pbpctl_dev,
 			unsigned int ctrl_ext,
 			unsigned char value, unsigned char len)
 {
 	unsigned char ctrl_val = 0;
 	unsigned int i = len;
 	unsigned int ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_c = NULL;
+	struct bpctl_dev *pbpctl_dev_c = NULL;
 
 	if (pbpctl_dev->bp_i80)
 		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
@@ -590,13 +590,13 @@
 	}
 }
 
-static int read_pulse(bpctl_dev_t *pbpctl_dev, unsigned int ctrl_ext,
+static int read_pulse(struct bpctl_dev *pbpctl_dev, unsigned int ctrl_ext,
 		      unsigned char len)
 {
 	unsigned char ctrl_val = 0;
 	unsigned int i = len;
 	unsigned int ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_c = NULL;
+	struct bpctl_dev *pbpctl_dev_c = NULL;
 
 	if (pbpctl_dev->bp_i80)
 		ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT);
@@ -765,11 +765,11 @@
 	return ctrl_val;
 }
 
-static void write_reg(bpctl_dev_t *pbpctl_dev, unsigned char value,
+static void write_reg(struct bpctl_dev *pbpctl_dev, unsigned char value,
 		      unsigned char addr)
 {
 	uint32_t ctrl_ext = 0, ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_c = NULL;
+	struct bpctl_dev *pbpctl_dev_c = NULL;
 	unsigned long flags;
 	if (pbpctl_dev->bp_10g9) {
 		pbpctl_dev_c = get_status_port_fn(pbpctl_dev);
@@ -934,15 +934,15 @@
 
 }
 
-static void write_data(bpctl_dev_t *pbpctl_dev, unsigned char value)
+static void write_data(struct bpctl_dev *pbpctl_dev, unsigned char value)
 {
 	write_reg(pbpctl_dev, value, CMND_REG_ADDR);
 }
 
-static int read_reg(bpctl_dev_t *pbpctl_dev, unsigned char addr)
+static int read_reg(struct bpctl_dev *pbpctl_dev, unsigned char addr)
 {
 	uint32_t ctrl_ext = 0, ctrl = 0, ctrl_value = 0;
-	bpctl_dev_t *pbpctl_dev_c = NULL;
+	struct bpctl_dev *pbpctl_dev_c = NULL;
 
 #ifdef BP_SYNC_FLAG
 	unsigned long flags;
@@ -1208,10 +1208,10 @@
 	return ctrl_value;
 }
 
-static int wdt_pulse(bpctl_dev_t *pbpctl_dev)
+static int wdt_pulse(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0, ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_c = NULL;
+	struct bpctl_dev *pbpctl_dev_c = NULL;
 
 #ifdef BP_SYNC_FLAG
 	unsigned long flags;
@@ -1424,7 +1424,7 @@
 	return 0;
 }
 
-static void data_pulse(bpctl_dev_t *pbpctl_dev, unsigned char value)
+static void data_pulse(struct bpctl_dev *pbpctl_dev, unsigned char value)
 {
 
 	uint32_t ctrl_ext = 0;
@@ -1490,7 +1490,7 @@
 
 }
 
-static int send_wdt_pulse(bpctl_dev_t *pbpctl_dev)
+static int send_wdt_pulse(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1524,7 +1524,7 @@
 	return 0;
 }
 
-void send_bypass_clear_pulse(bpctl_dev_t *pbpctl_dev, unsigned int value)
+void send_bypass_clear_pulse(struct bpctl_dev *pbpctl_dev, unsigned int value)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1550,7 +1550,7 @@
 /*  #endif  OLD_FW */
 #ifdef BYPASS_DEBUG
 
-int pulse_set_fn(bpctl_dev_t *pbpctl_dev, unsigned int counter)
+int pulse_set_fn(struct bpctl_dev *pbpctl_dev, unsigned int counter)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1578,7 +1578,7 @@
 	return 0;
 }
 
-int zero_set_fn(bpctl_dev_t *pbpctl_dev)
+int zero_set_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0, ctrl_value = 0;
 	if (!pbpctl_dev)
@@ -1603,7 +1603,7 @@
 	return ctrl_value;
 }
 
-int pulse_get2_fn(bpctl_dev_t *pbpctl_dev)
+int pulse_get2_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0, ctrl_value = 0;
 	if (!pbpctl_dev)
@@ -1618,7 +1618,7 @@
 	return ctrl_value;
 }
 
-int pulse_get1_fn(bpctl_dev_t *pbpctl_dev)
+int pulse_get1_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0, ctrl_value = 0;
 	if (!pbpctl_dev)
@@ -1635,7 +1635,7 @@
 	return ctrl_value;
 }
 
-int gpio6_set_fn(bpctl_dev_t *pbpctl_dev)
+int gpio6_set_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1646,7 +1646,7 @@
 	return 0;
 }
 
-int gpio7_set_fn(bpctl_dev_t *pbpctl_dev)
+int gpio7_set_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1657,7 +1657,7 @@
 	return 0;
 }
 
-int gpio7_clear_fn(bpctl_dev_t *pbpctl_dev)
+int gpio7_clear_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1668,7 +1668,7 @@
 	return 0;
 }
 
-int gpio6_clear_fn(bpctl_dev_t *pbpctl_dev)
+int gpio6_clear_fn(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0;
 
@@ -1680,9 +1680,9 @@
 }
 #endif				/*BYPASS_DEBUG */
 
-static bpctl_dev_t *lookup_port(bpctl_dev_t *dev)
+static struct bpctl_dev *lookup_port(struct bpctl_dev *dev)
 {
-	bpctl_dev_t *p;
+	struct bpctl_dev *p;
 	int n;
 	for (n = 0, p = bpctl_dev_arr; n < device_num && p->pdev; n++) {
 		if (p->bus == dev->bus
@@ -1693,7 +1693,7 @@
 	return NULL;
 }
 
-static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev)
+static struct bpctl_dev *get_status_port_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev) {
 		if (pbpctl_dev->func == 0 || pbpctl_dev->func == 2)
@@ -1702,7 +1702,7 @@
 	return NULL;
 }
 
-static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev)
+static struct bpctl_dev *get_master_port_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev) {
 		if (pbpctl_dev->func == 1 || pbpctl_dev->func == 3)
@@ -1715,7 +1715,7 @@
 /**************INTEL API***************/
 /**************************************/
 
-static void write_data_port_int(bpctl_dev_t *pbpctl_dev,
+static void write_data_port_int(struct bpctl_dev *pbpctl_dev,
 				unsigned char ctrl_value)
 {
 	uint32_t value;
@@ -1740,9 +1740,9 @@
 
 }
 
-static int write_data_int(bpctl_dev_t *pbpctl_dev, unsigned char value)
+static int write_data_int(struct bpctl_dev *pbpctl_dev, unsigned char value)
 {
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 	if (!pbpctl_dev_b)
@@ -1755,7 +1755,7 @@
 	return 0;
 }
 
-static int wdt_pulse_int(bpctl_dev_t *pbpctl_dev)
+static int wdt_pulse_int(struct bpctl_dev *pbpctl_dev)
 {
 
 	if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)
@@ -1779,7 +1779,7 @@
 /*************************************/
 
 /* CMND_ON  0x4 (100)*/
-int cmnd_on(bpctl_dev_t *pbpctl_dev)
+int cmnd_on(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -1796,7 +1796,7 @@
 }
 
 /* CMND_OFF  0x2 (10)*/
-int cmnd_off(bpctl_dev_t *pbpctl_dev)
+int cmnd_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -1809,12 +1809,12 @@
 		else
 			data_pulse(pbpctl_dev, CMND_OFF);
 		ret = 0;
-	};
+	}
 	return ret;
 }
 
 /* BYPASS_ON (0xa)*/
-int bypass_on(bpctl_dev_t *pbpctl_dev)
+int bypass_on(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -1830,12 +1830,12 @@
 		} else
 			data_pulse(pbpctl_dev, BYPASS_ON);
 		ret = 0;
-	};
+	}
 	return ret;
 }
 
 /* BYPASS_OFF (0x8 111)*/
-int bypass_off(bpctl_dev_t *pbpctl_dev)
+int bypass_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -1858,7 +1858,7 @@
 }
 
 /* TAP_OFF (0x9)*/
-int tap_off(bpctl_dev_t *pbpctl_dev)
+int tap_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 	if ((pbpctl_dev->bp_caps & TAP_CAP)
@@ -1866,12 +1866,12 @@
 		write_data(pbpctl_dev, TAP_OFF);
 		msec_delay_bp(LATCH_DELAY);
 		ret = 0;
-	};
+	}
 	return ret;
 }
 
 /* TAP_ON (0xb)*/
-int tap_on(bpctl_dev_t *pbpctl_dev)
+int tap_on(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 	if ((pbpctl_dev->bp_caps & TAP_CAP)
@@ -1879,12 +1879,12 @@
 		write_data(pbpctl_dev, TAP_ON);
 		msec_delay_bp(LATCH_DELAY);
 		ret = 0;
-	};
+	}
 	return ret;
 }
 
 /* DISC_OFF (0x9)*/
-int disc_off(bpctl_dev_t *pbpctl_dev)
+int disc_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
@@ -1896,7 +1896,7 @@
 }
 
 /* DISC_ON (0xb)*/
-int disc_on(bpctl_dev_t *pbpctl_dev)
+int disc_on(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) {
@@ -1908,10 +1908,10 @@
 }
 
 /* DISC_PORT_ON */
-int disc_port_on(bpctl_dev_t *pbpctl_dev)
+int disc_port_on(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
 		pbpctl_dev_m = pbpctl_dev;
@@ -1933,10 +1933,10 @@
 }
 
 /* DISC_PORT_OFF */
-int disc_port_off(bpctl_dev_t *pbpctl_dev)
+int disc_port_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
 		pbpctl_dev_m = pbpctl_dev;
@@ -1958,10 +1958,10 @@
 }
 
 /*TWO_PORT_LINK_HW_EN (0xe)*/
-int tpl_hw_on(bpctl_dev_t *pbpctl_dev)
+int tpl_hw_on(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0, ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 	if (!pbpctl_dev_b)
@@ -1986,10 +1986,10 @@
 }
 
 /*TWO_PORT_LINK_HW_DIS (0xc)*/
-int tpl_hw_off(bpctl_dev_t *pbpctl_dev)
+int tpl_hw_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0, ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 	if (!pbpctl_dev_b)
@@ -2012,7 +2012,7 @@
 }
 
 /* WDT_OFF (0x6 110)*/
-int wdt_off(bpctl_dev_t *pbpctl_dev)
+int wdt_off(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -2025,7 +2025,7 @@
 			data_pulse(pbpctl_dev, WDT_OFF);
 		pbpctl_dev->wdt_status = WDT_STATUS_DIS;
 		ret = 0;
-	};
+	}
 	return ret;
 }
 
@@ -2035,7 +2035,7 @@
 static unsigned int
     wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 };
 
-int wdt_on(bpctl_dev_t *pbpctl_dev, unsigned int timeout)
+int wdt_on(struct bpctl_dev *pbpctl_dev, unsigned int timeout)
 {
 
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -2087,7 +2087,7 @@
 	return BP_NOT_CAP;
 }
 
-void bp75_put_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
+void bp75_put_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
 {
 	u32 swsm;
 
@@ -2098,7 +2098,7 @@
 	BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm);
 }
 
-s32 bp75_get_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev)
+s32 bp75_get_hw_semaphore_generic(struct bpctl_dev *pbpctl_dev)
 {
 	u32 swsm;
 	s32 ret_val = 0;
@@ -2146,7 +2146,7 @@
 	return ret_val;
 }
 
-static void bp75_release_phy(bpctl_dev_t *pbpctl_dev)
+static void bp75_release_phy(struct bpctl_dev *pbpctl_dev)
 {
 	u16 mask = BPCTLI_SWFW_PHY0_SM;
 	u32 swfw_sync;
@@ -2166,7 +2166,7 @@
 	bp75_put_hw_semaphore_generic(pbpctl_dev);
 }
 
-static s32 bp75_acquire_phy(bpctl_dev_t *pbpctl_dev)
+static s32 bp75_acquire_phy(struct bpctl_dev *pbpctl_dev)
 {
 	u16 mask = BPCTLI_SWFW_PHY0_SM;
 	u32 swfw_sync;
@@ -2212,7 +2212,7 @@
 	return ret_val;
 }
 
-s32 bp75_read_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
+s32 bp75_read_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
 {
 	u32 i, mdic = 0;
 	s32 ret_val = 0;
@@ -2245,7 +2245,7 @@
 	return ret_val;
 }
 
-s32 bp75_write_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
+s32 bp75_write_phy_reg_mdic(struct bpctl_dev *pbpctl_dev, u32 offset, u16 data)
 {
 	u32 i, mdic = 0;
 	s32 ret_val = 0;
@@ -2278,7 +2278,7 @@
 	return ret_val;
 }
 
-static s32 bp75_read_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data)
+static s32 bp75_read_phy_reg(struct bpctl_dev *pbpctl_dev, u32 offset, u16 *data)
 {
 	s32 ret_val = 0;
 
@@ -2304,7 +2304,7 @@
 	return ret_val;
 }
 
-static s32 bp75_write_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data)
+static s32 bp75_write_phy_reg(struct bpctl_dev *pbpctl_dev, u32 offset, u16 data)
 {
 	s32 ret_val = 0;
 
@@ -2332,10 +2332,10 @@
 }
 
 /* SET_TX  (non-Bypass command :)) */
-static int set_tx(bpctl_dev_t *pbpctl_dev, int tx_state)
+static int set_tx(struct bpctl_dev *pbpctl_dev, int tx_state)
 {
 	int ret = 0, ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
 		pbpctl_dev_m = pbpctl_dev;
 	else
@@ -2532,7 +2532,7 @@
 }
 
 /* SET_FORCE_LINK  (non-Bypass command :)) */
-static int set_bp_force_link(bpctl_dev_t *pbpctl_dev, int tx_state)
+static int set_bp_force_link(struct bpctl_dev *pbpctl_dev, int tx_state)
 {
 	int ret = 0, ctrl = 0;
 
@@ -2556,7 +2556,7 @@
 }
 
 /*RESET_CONT 0x20 */
-int reset_cont(bpctl_dev_t *pbpctl_dev)
+int reset_cont(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -2568,12 +2568,12 @@
 		else
 			data_pulse(pbpctl_dev, RESET_CONT);
 		ret = 0;
-	};
+	}
 	return ret;
 }
 
 /*DIS_BYPASS_CAP 0x22 */
-int dis_bypass_cap(bpctl_dev_t *pbpctl_dev)
+int dis_bypass_cap(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
@@ -2592,7 +2592,7 @@
 }
 
 /*EN_BYPASS_CAP 0x24 */
-int en_bypass_cap(bpctl_dev_t *pbpctl_dev)
+int en_bypass_cap(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
 		if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) {
@@ -2608,7 +2608,7 @@
 }
 
 /* BYPASS_STATE_PWRON 0x26*/
-int bypass_state_pwron(bpctl_dev_t *pbpctl_dev)
+int bypass_state_pwron(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) {
 		write_data(pbpctl_dev, BYPASS_STATE_PWRON);
@@ -2622,7 +2622,7 @@
 }
 
 /* NORMAL_STATE_PWRON 0x28*/
-int normal_state_pwron(bpctl_dev_t *pbpctl_dev)
+int normal_state_pwron(struct bpctl_dev *pbpctl_dev)
 {
 	if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)
 	    || (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) {
@@ -2637,7 +2637,7 @@
 }
 
 /* BYPASS_STATE_PWROFF 0x27*/
-int bypass_state_pwroff(bpctl_dev_t *pbpctl_dev)
+int bypass_state_pwroff(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) {
 		write_data(pbpctl_dev, BYPASS_STATE_PWROFF);
@@ -2648,7 +2648,7 @@
 }
 
 /* NORMAL_STATE_PWROFF 0x29*/
-int normal_state_pwroff(bpctl_dev_t *pbpctl_dev)
+int normal_state_pwroff(struct bpctl_dev *pbpctl_dev)
 {
 	if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) {
 		write_data(pbpctl_dev, NORMAL_STATE_PWROFF);
@@ -2659,7 +2659,7 @@
 }
 
 /*TAP_STATE_PWRON 0x2a*/
-int tap_state_pwron(bpctl_dev_t *pbpctl_dev)
+int tap_state_pwron(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
 		write_data(pbpctl_dev, TAP_STATE_PWRON);
@@ -2670,7 +2670,7 @@
 }
 
 /*DIS_TAP_CAP 0x2c*/
-int dis_tap_cap(bpctl_dev_t *pbpctl_dev)
+int dis_tap_cap(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
 		write_data(pbpctl_dev, DIS_TAP_CAP);
@@ -2681,7 +2681,7 @@
 }
 
 /*EN_TAP_CAP 0x2e*/
-int en_tap_cap(bpctl_dev_t *pbpctl_dev)
+int en_tap_cap(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & TAP_DIS_CAP) {
 		write_data(pbpctl_dev, EN_TAP_CAP);
@@ -2692,7 +2692,7 @@
 }
 
 /*DISC_STATE_PWRON 0x2a*/
-int disc_state_pwron(bpctl_dev_t *pbpctl_dev)
+int disc_state_pwron(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2705,7 +2705,7 @@
 }
 
 /*DIS_DISC_CAP 0x2c*/
-int dis_disc_cap(bpctl_dev_t *pbpctl_dev)
+int dis_disc_cap(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2718,10 +2718,10 @@
 }
 
 /*DISC_STATE_PWRON 0x2a*/
-int disc_port_state_pwron(bpctl_dev_t *pbpctl_dev)
+int disc_port_state_pwron(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 
 	return BP_NOT_CAP;
 
@@ -2744,10 +2744,10 @@
 	return ret;
 }
 
-int normal_port_state_pwron(bpctl_dev_t *pbpctl_dev)
+int normal_port_state_pwron(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 	return BP_NOT_CAP;
 
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
@@ -2770,7 +2770,7 @@
 }
 
 /*EN_TAP_CAP 0x2e*/
-int en_disc_cap(bpctl_dev_t *pbpctl_dev)
+int en_disc_cap(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & DISC_DIS_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= 0x8) {
@@ -2782,7 +2782,7 @@
 	return BP_NOT_CAP;
 }
 
-int std_nic_on(bpctl_dev_t *pbpctl_dev)
+int std_nic_on(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
@@ -2836,7 +2836,7 @@
 	return BP_NOT_CAP;
 }
 
-int std_nic_off(bpctl_dev_t *pbpctl_dev)
+int std_nic_off(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & STD_NIC_CAP) {
@@ -2888,7 +2888,7 @@
 	return BP_NOT_CAP;
 }
 
-int wdt_time_left(bpctl_dev_t *pbpctl_dev)
+int wdt_time_left(struct bpctl_dev *pbpctl_dev)
 {
 
 	/* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */
@@ -2920,7 +2920,7 @@
 	return time_left;
 }
 
-static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left)
+static int wdt_timer(struct bpctl_dev *pbpctl_dev, int *time_left)
 {
 	int ret = 0;
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -2936,7 +2936,7 @@
 	return ret;
 }
 
-static int wdt_timer_reload(bpctl_dev_t *pbpctl_dev)
+static int wdt_timer_reload(struct bpctl_dev *pbpctl_dev)
 {
 
 	int ret = 0;
@@ -2960,7 +2960,7 @@
 
 static void wd_reset_timer(unsigned long param)
 {
-	bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param;
+	struct bpctl_dev *pbpctl_dev = (struct bpctl_dev *) param;
 #ifdef BP_SELF_TEST
 	struct sk_buff *skb_tmp;
 #endif
@@ -2999,7 +2999,7 @@
 }
 
 /*WAIT_AT_PWRUP 0x80   */
-int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev)
+int bp_wait_at_pwup_en(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3014,7 +3014,7 @@
 }
 
 /*DIS_WAIT_AT_PWRUP       0x81 */
-int bp_wait_at_pwup_dis(bpctl_dev_t *pbpctl_dev)
+int bp_wait_at_pwup_dis(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3031,7 +3031,7 @@
 
 /*EN_HW_RESET  0x82   */
 
-int bp_hw_reset_en(bpctl_dev_t *pbpctl_dev)
+int bp_hw_reset_en(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3047,7 +3047,7 @@
 
 /*DIS_HW_RESET             0x83   */
 
-int bp_hw_reset_dis(bpctl_dev_t *pbpctl_dev)
+int bp_hw_reset_dis(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3062,7 +3062,7 @@
 }
 
 
-int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode)
+int wdt_exp_mode(struct bpctl_dev *pbpctl_dev, int mode)
 {
 	uint32_t status_reg = 0, status_reg1 = 0;
 
@@ -3113,7 +3113,7 @@
 	return BP_NOT_CAP;
 }
 
-int bypass_fw_ver(bpctl_dev_t *pbpctl_dev)
+int bypass_fw_ver(struct bpctl_dev *pbpctl_dev)
 {
 	if (is_bypass_fn(pbpctl_dev))
 		return read_reg(pbpctl_dev, VER_REG_ADDR);
@@ -3121,7 +3121,7 @@
 		return BP_NOT_CAP;
 }
 
-int bypass_sign_check(bpctl_dev_t *pbpctl_dev)
+int bypass_sign_check(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (is_bypass_fn(pbpctl_dev))
@@ -3131,10 +3131,10 @@
 		return BP_NOT_CAP;
 }
 
-static int tx_status(bpctl_dev_t *pbpctl_dev)
+static int tx_status(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl = 0;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
 		pbpctl_dev_m = pbpctl_dev;
 	else
@@ -3218,7 +3218,7 @@
 	return BP_NOT_CAP;
 }
 
-static int bp_force_link_status(bpctl_dev_t *pbpctl_dev)
+static int bp_force_link_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (DBI_IF_SERIES(pbpctl_dev->subdevice)) {
@@ -3232,10 +3232,10 @@
 	return BP_NOT_CAP;
 }
 
-int bypass_from_last_read(bpctl_dev_t *pbpctl_dev)
+int bypass_from_last_read(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t ctrl_ext = 0;
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
 		pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
@@ -3252,9 +3252,9 @@
 		return BP_NOT_CAP;
 }
 
-int bypass_status_clear(bpctl_dev_t *pbpctl_dev)
+int bypass_status_clear(struct bpctl_dev *pbpctl_dev)
 {
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
 		pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
@@ -3266,7 +3266,7 @@
 		return BP_NOT_CAP;
 }
 
-int bypass_flag_status(bpctl_dev_t *pbpctl_dev)
+int bypass_flag_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if ((pbpctl_dev->bp_caps & BP_CAP)) {
@@ -3279,7 +3279,7 @@
 	return BP_NOT_CAP;
 }
 
-int bypass_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+int bypass_flag_status_clear(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & BP_CAP) {
@@ -3294,7 +3294,7 @@
 	return BP_NOT_CAP;
 }
 
-int bypass_change_status(bpctl_dev_t *pbpctl_dev)
+int bypass_change_status(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -3313,7 +3313,7 @@
 	return ret;
 }
 
-int bypass_off_status(bpctl_dev_t *pbpctl_dev)
+int bypass_off_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & BP_CAP) {
@@ -3325,12 +3325,12 @@
 	return BP_NOT_CAP;
 }
 
-static int bypass_status(bpctl_dev_t *pbpctl_dev)
+static int bypass_status(struct bpctl_dev *pbpctl_dev)
 {
 	u32 ctrl_ext = 0;
 	if (pbpctl_dev->bp_caps & BP_CAP) {
 
-		bpctl_dev_t *pbpctl_dev_b = NULL;
+		struct bpctl_dev *pbpctl_dev_b = NULL;
 
 		pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 		if (!pbpctl_dev_b)
@@ -3408,7 +3408,7 @@
 	return BP_NOT_CAP;
 }
 
-int default_pwron_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3426,7 +3426,7 @@
 	return BP_NOT_CAP;
 }
 
-static int default_pwroff_status(bpctl_dev_t *pbpctl_dev)
+static int default_pwroff_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	/*if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&&
@@ -3440,7 +3440,7 @@
 	return BP_NOT_CAP;
 }
 
-int dis_bypass_cap_status(bpctl_dev_t *pbpctl_dev)
+int dis_bypass_cap_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & BP_DIS_CAP) {
@@ -3453,7 +3453,7 @@
 	return BP_NOT_CAP;
 }
 
-int cmd_en_status(bpctl_dev_t *pbpctl_dev)
+int cmd_en_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3465,7 +3465,7 @@
 	return BP_NOT_CAP;
 }
 
-int wdt_en_status(bpctl_dev_t *pbpctl_dev)
+int wdt_en_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -3477,7 +3477,7 @@
 	return BP_NOT_CAP;
 }
 
-int wdt_programmed(bpctl_dev_t *pbpctl_dev, int *timeout)
+int wdt_programmed(struct bpctl_dev *pbpctl_dev, int *timeout)
 {
 	int ret = 0;
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -3497,13 +3497,13 @@
 				*timeout =
 				    curr_wdt_status ==
 				    0 ? 0 : pbpctl_dev->bypass_timer_interval;
-		};
+		}
 	} else
 		ret = BP_NOT_CAP;
 	return ret;
 }
 
-int bypass_support(bpctl_dev_t *pbpctl_dev)
+int bypass_support(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 
@@ -3520,7 +3520,7 @@
 	return ret;
 }
 
-int tap_support(bpctl_dev_t *pbpctl_dev)
+int tap_support(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 
@@ -3536,7 +3536,7 @@
 	return ret;
 }
 
-int normal_support(bpctl_dev_t *pbpctl_dev)
+int normal_support(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 
@@ -3548,11 +3548,11 @@
 			      NORMAL_UNSUPPORT_MASK) ? 0 : 1);
 		} else
 			ret = 1;
-	};
+	}
 	return ret;
 }
 
-int get_bp_prod_caps(bpctl_dev_t *pbpctl_dev)
+int get_bp_prod_caps(struct bpctl_dev *pbpctl_dev)
 {
 	if ((pbpctl_dev->bp_caps & SW_CTL_CAP) &&
 	    (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER))
@@ -3561,7 +3561,7 @@
 
 }
 
-int tap_flag_status(bpctl_dev_t *pbpctl_dev)
+int tap_flag_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
@@ -3573,7 +3573,7 @@
 	return BP_NOT_CAP;
 }
 
-int tap_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+int tap_flag_status_clear(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t status_reg = 0;
 	if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) {
@@ -3587,7 +3587,7 @@
 	return BP_NOT_CAP;
 }
 
-int tap_change_status(bpctl_dev_t *pbpctl_dev)
+int tap_change_status(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 	if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) {
@@ -3604,7 +3604,7 @@
 	return ret;
 }
 
-int tap_off_status(bpctl_dev_t *pbpctl_dev)
+int tap_off_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & TAP_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3614,12 +3614,12 @@
 	return BP_NOT_CAP;
 }
 
-int tap_status(bpctl_dev_t *pbpctl_dev)
+int tap_status(struct bpctl_dev *pbpctl_dev)
 {
 	u32 ctrl_ext = 0;
 
 	if (pbpctl_dev->bp_caps & TAP_CAP) {
-		bpctl_dev_t *pbpctl_dev_b = NULL;
+		struct bpctl_dev *pbpctl_dev_b = NULL;
 
 		pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 		if (!pbpctl_dev_b)
@@ -3653,7 +3653,7 @@
 	return BP_NOT_CAP;
 }
 
-int default_pwron_tap_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_tap_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3664,7 +3664,7 @@
 	return BP_NOT_CAP;
 }
 
-int dis_tap_cap_status(bpctl_dev_t *pbpctl_dev)
+int dis_tap_cap_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)
@@ -3675,7 +3675,7 @@
 	return BP_NOT_CAP;
 }
 
-int disc_flag_status(bpctl_dev_t *pbpctl_dev)
+int disc_flag_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3687,7 +3687,7 @@
 	return BP_NOT_CAP;
 }
 
-int disc_flag_status_clear(bpctl_dev_t *pbpctl_dev)
+int disc_flag_status_clear(struct bpctl_dev *pbpctl_dev)
 {
 	uint32_t status_reg = 0;
 	if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3701,7 +3701,7 @@
 	return BP_NOT_CAP;
 }
 
-int disc_change_status(bpctl_dev_t *pbpctl_dev)
+int disc_change_status(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 	if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3712,9 +3712,9 @@
 	return BP_NOT_CAP;
 }
 
-int disc_off_status(bpctl_dev_t *pbpctl_dev)
+int disc_off_status(struct bpctl_dev *pbpctl_dev)
 {
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 	u32 ctrl_ext = 0;
 
 	if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3796,7 +3796,7 @@
 	return BP_NOT_CAP;
 }
 
-static int disc_status(bpctl_dev_t *pbpctl_dev)
+static int disc_status(struct bpctl_dev *pbpctl_dev)
 {
 	int ctrl = 0;
 	if (pbpctl_dev->bp_caps & DISC_CAP) {
@@ -3808,7 +3808,7 @@
 	return BP_NOT_CAP;
 }
 
-int default_pwron_disc_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_disc_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3819,7 +3819,7 @@
 	return BP_NOT_CAP;
 }
 
-int dis_disc_cap_status(bpctl_dev_t *pbpctl_dev)
+int dis_disc_cap_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & DIS_DISC_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3830,10 +3830,10 @@
 	return BP_NOT_CAP;
 }
 
-int disc_port_status(bpctl_dev_t *pbpctl_dev)
+int disc_port_status(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
 		pbpctl_dev_m = pbpctl_dev;
@@ -3854,10 +3854,10 @@
 	return ret;
 }
 
-int default_pwron_disc_port_status(bpctl_dev_t *pbpctl_dev)
+int default_pwron_disc_port_status(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
-	bpctl_dev_t *pbpctl_dev_m;
+	struct bpctl_dev *pbpctl_dev_m;
 
 	if ((is_bypass_fn(pbpctl_dev)) == 1)
 		pbpctl_dev_m = pbpctl_dev;
@@ -3878,7 +3878,7 @@
 	return ret;
 }
 
-int wdt_exp_mode_status(bpctl_dev_t *pbpctl_dev)
+int wdt_exp_mode_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
 		if (pbpctl_dev->bp_ext_ver <= PXG2BPI_VER)
@@ -3901,7 +3901,7 @@
 	return BP_NOT_CAP;
 }
 
-int tpl2_flag_status(bpctl_dev_t *pbpctl_dev)
+int tpl2_flag_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) {
@@ -3912,9 +3912,9 @@
 	return BP_NOT_CAP;
 }
 
-int tpl_hw_status(bpctl_dev_t *pbpctl_dev)
+int tpl_hw_status(struct bpctl_dev *pbpctl_dev)
 {
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 	if (!pbpctl_dev_b)
@@ -3927,7 +3927,7 @@
 }
 
 
-int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev)
+int bp_wait_at_pwup_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
 		if (pbpctl_dev->bp_ext_ver >= 0x8)
@@ -3938,7 +3938,7 @@
 	return BP_NOT_CAP;
 }
 
-int bp_hw_reset_status(bpctl_dev_t *pbpctl_dev)
+int bp_hw_reset_status(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & SW_CTL_CAP) {
@@ -3952,7 +3952,7 @@
 }
 
 
-int std_nic_status(bpctl_dev_t *pbpctl_dev)
+int std_nic_status(struct bpctl_dev *pbpctl_dev)
 {
 	int status_val = 0;
 
@@ -4000,10 +4000,10 @@
 /******************************************************/
 /**************SW_INIT*********************************/
 /******************************************************/
-void bypass_caps_init(bpctl_dev_t *pbpctl_dev)
+void bypass_caps_init(struct bpctl_dev *pbpctl_dev)
 {
 	u_int32_t ctrl_ext = 0;
-	bpctl_dev_t *pbpctl_dev_m = NULL;
+	struct bpctl_dev *pbpctl_dev_m = NULL;
 
 #ifdef BYPASS_DEBUG
 	int ret = 0;
@@ -4218,7 +4218,7 @@
 	}
 }
 
-int bypass_off_init(bpctl_dev_t *pbpctl_dev)
+int bypass_off_init(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = cmnd_on(pbpctl_dev);
 	if (ret < 0)
@@ -4234,10 +4234,10 @@
 	return 0;
 }
 
-void remove_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+void remove_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
 {
 #ifdef BP_SELF_TEST
-	bpctl_dev_t *pbpctl_dev_sl = NULL;
+	struct bpctl_dev *pbpctl_dev_sl = NULL;
 #endif
 
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -4263,7 +4263,7 @@
 
 }
 
-int init_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+int init_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
 		init_timer(&pbpctl_dev->bp_timer);
@@ -4277,7 +4277,7 @@
 #ifdef BP_SELF_TEST
 int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
+	struct bpctl_dev *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
 	int idx_dev = 0;
 	struct ethhdr *eth = (struct ethhdr *)skb->data;
 
@@ -4310,7 +4310,7 @@
 }
 #endif
 
-int set_bypass_wd_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
+int set_bypass_wd_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
 {
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
 		if (pbpctl_dev->reset_time != param) {
@@ -4329,7 +4329,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_bypass_wd_auto(bpctl_dev_t *pbpctl_dev)
+int get_bypass_wd_auto(struct bpctl_dev *pbpctl_dev)
 {
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP)
 		return pbpctl_dev->reset_time;
@@ -4339,9 +4339,9 @@
 
 #ifdef BP_SELF_TEST
 
-int set_bp_self_test(bpctl_dev_t *pbpctl_dev, unsigned int param)
+int set_bp_self_test(struct bpctl_dev *pbpctl_dev, unsigned int param)
 {
-	bpctl_dev_t *pbpctl_dev_sl = NULL;
+	struct bpctl_dev *pbpctl_dev_sl = NULL;
 
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
 		pbpctl_dev->bp_self_test_flag = param == 0 ? 0 : 1;
@@ -4374,7 +4374,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_bp_self_test(bpctl_dev_t *pbpctl_dev)
+int get_bp_self_test(struct bpctl_dev *pbpctl_dev)
 {
 
 	if (pbpctl_dev->bp_caps & WD_CTL_CAP) {
@@ -4392,7 +4392,7 @@
 /************************* API ********************************/
 /**************************************************************/
 
-int is_bypass_fn(bpctl_dev_t *pbpctl_dev)
+int is_bypass_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4400,7 +4400,7 @@
 	return (((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) ? 1 : 0);
 }
 
-int set_bypass_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+int set_bypass_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
 {
 	int ret = 0;
 
@@ -4418,12 +4418,12 @@
 	return ret;
 }
 
-int get_bypass_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_fn(struct bpctl_dev *pbpctl_dev)
 {
 	return bypass_status(pbpctl_dev);
 }
 
-int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_change_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4431,7 +4431,7 @@
 	return bypass_change_status(pbpctl_dev);
 }
 
-int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+int set_dis_bypass_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4450,7 +4450,7 @@
 	return ret;
 }
 
-int get_dis_bypass_fn(bpctl_dev_t *pbpctl_dev)
+int get_dis_bypass_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4458,7 +4458,7 @@
 	return dis_bypass_cap_status(pbpctl_dev);
 }
 
-int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+int set_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4477,7 +4477,7 @@
 	return ret;
 }
 
-int get_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_pwoff_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4485,7 +4485,7 @@
 	return default_pwroff_status(pbpctl_dev);
 }
 
-int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode)
+int set_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev, int bypass_mode)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4504,7 +4504,7 @@
 	return ret;
 }
 
-int get_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_pwup_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4512,7 +4512,7 @@
 	return default_pwron_status(pbpctl_dev);
 }
 
-int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout)
+int set_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int timeout)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4534,7 +4534,7 @@
 	return ret;
 }
 
-int get_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int *timeout)
+int get_bypass_wd_fn(struct bpctl_dev *pbpctl_dev, int *timeout)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4542,7 +4542,7 @@
 	return wdt_programmed(pbpctl_dev, timeout);
 }
 
-int get_wd_expire_time_fn(bpctl_dev_t *pbpctl_dev, int *time_left)
+int get_wd_expire_time_fn(struct bpctl_dev *pbpctl_dev, int *time_left)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4550,7 +4550,7 @@
 	return wdt_timer(pbpctl_dev, time_left);
 }
 
-int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev)
+int reset_bypass_wd_timer_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4558,7 +4558,7 @@
 	return wdt_timer_reload(pbpctl_dev);
 }
 
-int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev)
+int get_wd_set_caps_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int bp_status = 0;
 
@@ -4582,7 +4582,7 @@
 	return bp_status;
 }
 
-int set_std_nic_fn(bpctl_dev_t *pbpctl_dev, int nic_mode)
+int set_std_nic_fn(struct bpctl_dev *pbpctl_dev, int nic_mode)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4602,7 +4602,7 @@
 	return ret;
 }
 
-int get_std_nic_fn(bpctl_dev_t *pbpctl_dev)
+int get_std_nic_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4610,7 +4610,7 @@
 	return std_nic_status(pbpctl_dev);
 }
 
-int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_tap_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4626,7 +4626,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_tap_fn(bpctl_dev_t *pbpctl_dev)
+int get_tap_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4634,7 +4634,7 @@
 	return tap_status(pbpctl_dev);
 }
 
-int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_tap_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4652,7 +4652,7 @@
 	return ret;
 }
 
-int get_tap_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_tap_pwup_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4664,7 +4664,7 @@
 	return ((ret == 0) ? 1 : 0);
 }
 
-int get_tap_change_fn(bpctl_dev_t *pbpctl_dev)
+int get_tap_change_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4672,7 +4672,7 @@
 	return tap_change_status(pbpctl_dev);
 }
 
-int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+int set_dis_tap_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4689,7 +4689,7 @@
 		return BP_NOT_CAP;
 }
 
-int get_dis_tap_fn(bpctl_dev_t *pbpctl_dev)
+int get_dis_tap_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4697,7 +4697,7 @@
 	return dis_tap_cap_status(pbpctl_dev);
 }
 
-int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4714,7 +4714,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_disc_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4725,7 +4725,7 @@
 	return ret;
 }
 
-int set_disc_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4743,7 +4743,7 @@
 	return ret;
 }
 
-int get_disc_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_pwup_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4753,7 +4753,7 @@
 	return (ret == 0 ? 1 : (ret < 0 ? BP_NOT_CAP : 0));
 }
 
-int get_disc_change_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_change_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4763,7 +4763,7 @@
 	return ret;
 }
 
-int set_dis_disc_fn(bpctl_dev_t *pbpctl_dev, int dis_param)
+int set_dis_disc_fn(struct bpctl_dev *pbpctl_dev, int dis_param)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4781,7 +4781,7 @@
 		return BP_NOT_CAP;
 }
 
-int get_dis_disc_fn(bpctl_dev_t *pbpctl_dev)
+int get_dis_disc_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4792,7 +4792,7 @@
 	return ret;
 }
 
-int set_disc_port_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_port_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
 {
 	int ret = BP_NOT_CAP;
 	if (!pbpctl_dev)
@@ -4806,7 +4806,7 @@
 	return ret;
 }
 
-int get_disc_port_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_port_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4814,7 +4814,7 @@
 	return disc_port_status(pbpctl_dev);
 }
 
-int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode)
+int set_disc_port_pwup_fn(struct bpctl_dev *pbpctl_dev, int disc_mode)
 {
 	int ret = BP_NOT_CAP;
 	if (!pbpctl_dev)
@@ -4828,7 +4828,7 @@
 	return ret;
 }
 
-int get_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_disc_port_pwup_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4840,7 +4840,7 @@
 	return ((ret == 0) ? 1 : 0);
 }
 
-int get_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev)
+int get_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4848,7 +4848,7 @@
 	return wdt_exp_mode_status(pbpctl_dev);
 }
 
-int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param)
+int set_wd_exp_mode_fn(struct bpctl_dev *pbpctl_dev, int param)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4856,7 +4856,7 @@
 	return wdt_exp_mode(pbpctl_dev, param);
 }
 
-int reset_cont_fn(bpctl_dev_t *pbpctl_dev)
+int reset_cont_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -4868,10 +4868,10 @@
 	return reset_cont(pbpctl_dev);
 }
 
-int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state)
+int set_tx_fn(struct bpctl_dev *pbpctl_dev, int tx_state)
 {
 
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 	if (!pbpctl_dev)
 		return -1;
 
@@ -4891,7 +4891,7 @@
 
 int set_bp_force_link_fn(int dev_num, int tx_state)
 {
-	static bpctl_dev_t *bpctl_dev_curr;
+	static struct bpctl_dev *bpctl_dev_curr;
 
 	if ((dev_num < 0) || (dev_num > device_num)
 	    || (bpctl_dev_arr[dev_num].pdev == NULL))
@@ -4901,7 +4901,7 @@
 	return set_bp_force_link(bpctl_dev_curr, tx_state);
 }
 
-int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param)
+int set_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev, int param)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4909,7 +4909,7 @@
 	return set_bypass_wd_auto(pbpctl_dev, param);
 }
 
-int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev)
+int get_wd_autoreset_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4918,7 +4918,7 @@
 }
 
 #ifdef BP_SELF_TEST
-int set_bp_self_test_fn(bpctl_dev_t *pbpctl_dev, int param)
+int set_bp_self_test_fn(struct bpctl_dev *pbpctl_dev, int param)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4926,7 +4926,7 @@
 	return set_bp_self_test(pbpctl_dev, param);
 }
 
-int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev)
+int get_bp_self_test_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4936,7 +4936,7 @@
 
 #endif
 
-int get_bypass_caps_fn(bpctl_dev_t *pbpctl_dev)
+int get_bypass_caps_fn(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4945,7 +4945,7 @@
 
 }
 
-int get_bypass_slave_fn(bpctl_dev_t *pbpctl_dev, bpctl_dev_t **pbpctl_dev_out)
+int get_bypass_slave_fn(struct bpctl_dev *pbpctl_dev, struct bpctl_dev **pbpctl_dev_out)
 {
 	int idx_dev = 0;
 	if (!pbpctl_dev)
@@ -4977,7 +4977,7 @@
 		return 0;
 }
 
-int is_bypass(bpctl_dev_t *pbpctl_dev)
+int is_bypass(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -4988,9 +4988,9 @@
 		return 0;
 }
 
-int get_tx_fn(bpctl_dev_t *pbpctl_dev)
+int get_tx_fn(struct bpctl_dev *pbpctl_dev)
 {
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 	if (!pbpctl_dev)
 		return -1;
 
@@ -5010,7 +5010,7 @@
 
 int get_bp_force_link_fn(int dev_num)
 {
-	static bpctl_dev_t *bpctl_dev_curr;
+	static struct bpctl_dev *bpctl_dev_curr;
 
 	if ((dev_num < 0) || (dev_num > device_num)
 	    || (bpctl_dev_arr[dev_num].pdev == NULL))
@@ -5020,7 +5020,7 @@
 	return bp_force_link_status(bpctl_dev_curr);
 }
 
-static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev)
+static int get_bypass_link_status(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -5036,9 +5036,9 @@
 
 static void bp_tpl_timer_fn(unsigned long param)
 {
-	bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param;
+	struct bpctl_dev *pbpctl_dev = (struct bpctl_dev *) param;
 	uint32_t link1, link2;
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 
 	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
 	if (!pbpctl_dev_b)
@@ -5071,9 +5071,9 @@
 	mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + BP_LINK_MON_DELAY * HZ);
 }
 
-void remove_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+void remove_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
 {
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 	if (!pbpctl_dev)
 		return;
 	pbpctl_dev_b = get_status_port_fn(pbpctl_dev);
@@ -5089,7 +5089,7 @@
 	return;
 }
 
-int init_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+int init_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -5102,7 +5102,7 @@
 	return BP_NOT_CAP;
 }
 
-int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param)
+int set_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev, unsigned int param)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -5111,7 +5111,7 @@
 			pbpctl_dev->bp_tpl_flag = param;
 			mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + 1);
 			return BP_OK;
-		};
+		}
 		if ((!param) && (pbpctl_dev->bp_tpl_flag))
 			remove_bypass_tpl_auto(pbpctl_dev);
 
@@ -5120,7 +5120,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev)
+int get_bypass_tpl_auto(struct bpctl_dev *pbpctl_dev)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -5130,10 +5130,10 @@
 	return BP_NOT_CAP;
 }
 
-int set_tpl_fn(bpctl_dev_t *pbpctl_dev, int tpl_mode)
+int set_tpl_fn(struct bpctl_dev *pbpctl_dev, int tpl_mode)
 {
 
-	bpctl_dev_t *pbpctl_dev_b = NULL;
+	struct bpctl_dev *pbpctl_dev_b = NULL;
 	if (!pbpctl_dev)
 		return -1;
 
@@ -5160,7 +5160,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_tpl_fn(bpctl_dev_t *pbpctl_dev)
+int get_tpl_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = BP_NOT_CAP;
 	if (!pbpctl_dev)
@@ -5174,7 +5174,7 @@
 	return ret;
 }
 
-int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -5194,7 +5194,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev)
+int get_bp_wait_at_pwup_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -5207,7 +5207,7 @@
 	return ret;
 }
 
-int set_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev, int tap_mode)
+int set_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev, int tap_mode)
 {
 	if (!pbpctl_dev)
 		return -1;
@@ -5227,7 +5227,7 @@
 	return BP_NOT_CAP;
 }
 
-int get_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev)
+int get_bp_hw_reset_fn(struct bpctl_dev *pbpctl_dev)
 {
 	int ret = 0;
 	if (!pbpctl_dev)
@@ -5242,7 +5242,7 @@
 }
 
 
-int get_bypass_info_fn(bpctl_dev_t *pbpctl_dev, char *dev_name,
+int get_bypass_info_fn(struct bpctl_dev *pbpctl_dev, char *dev_name,
 		       char *add_param)
 {
 	if (!pbpctl_dev)
@@ -5313,7 +5313,7 @@
 	return -1;
 }
 
-static bpctl_dev_t *get_dev_idx_p(int ifindex)
+static struct bpctl_dev *get_dev_idx_p(int ifindex)
 {
 	int idx_dev = 0;
 
@@ -5401,12 +5401,12 @@
 {
 	struct bpctl_cmd bpctl_cmd;
 	int dev_idx = 0;
-	bpctl_dev_t *pbpctl_dev_out;
+	struct bpctl_dev *pbpctl_dev_out;
 	void __user *argp = (void __user *)ioctl_param;
 	int ret = 0;
 	unsigned long flags;
 
-	static bpctl_dev_t *pbpctl_dev;
+	static struct bpctl_dev *pbpctl_dev;
 
 	/* lock_kernel(); */
 	if (down_interruptible(&bpctl_sema))
@@ -5971,7 +5971,7 @@
 	PE210G2BPi40,
 };
 
-typedef struct _bpmod_info_t {
+struct bpmod_info {
 	unsigned int vendor;
 	unsigned int device;
 	unsigned int subvendor;
@@ -5979,13 +5979,11 @@
 	unsigned int index;
 	char *bp_name;
 
-} bpmod_info_t;
+};
 
-typedef struct _dev_desc {
+struct {
 	char *name;
-} dev_desc_t;
-
-dev_desc_t dev_desc[] = {
+} dev_desc[] = {
 	{"Silicom Bypass PXG2BPFI-SD series adapter"},
 	{"Silicom Bypass PXG2BPFIL-SD series adapter"},
 	{"Silicom Bypass PXG2BPFILX-SD series adapter"},
@@ -6155,7 +6153,7 @@
 	{0},
 };
 
-static bpmod_info_t tx_ctl_pci_tbl[] = {
+static struct bpmod_info tx_ctl_pci_tbl[] = {
 	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFI_SSID, PXG2BPFI,
 	 "PXG2BPFI-SD"},
 	{0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFIL_SSID, PXG2BPFIL,
@@ -6623,7 +6621,7 @@
 	{0,}
 };
 
-static void find_fw(bpctl_dev_t *dev)
+static void find_fw(struct bpctl_dev *dev)
 {
 	unsigned long mmio_start, mmio_len;
 	struct pci_dev *pdev1 = dev->pdev;
@@ -6653,7 +6651,7 @@
 	printk("firmware version: 0x%x\n", dev->bp_fw_ver);
 }
 
-static int init_one(bpctl_dev_t *dev, bpmod_info_t *info, struct pci_dev *pdev1)
+static int init_one(struct bpctl_dev *dev, struct bpmod_info *info, struct pci_dev *pdev1)
 {
 	unsigned long mmio_start, mmio_len;
 
@@ -6744,7 +6742,7 @@
 {
 	int ret_val, idx, idx_dev = 0;
 	struct pci_dev *pdev1 = NULL;
-	bpctl_dev_t *dev;
+	struct bpctl_dev *dev;
 
 	printk(BP_MOD_DESCR " v" BP_MOD_VER "\n");
 	ret_val = register_chrdev(major_num, DEVICE_NAME, &Fops);
@@ -6769,14 +6767,14 @@
 		return -1;
 	}
 
-	bpctl_dev_arr = kmalloc((device_num) * sizeof(bpctl_dev_t), GFP_KERNEL);
+	bpctl_dev_arr = kmalloc((device_num) * sizeof(struct bpctl_dev), GFP_KERNEL);
 
 	if (!bpctl_dev_arr) {
 		printk("Allocation error\n");
 		unregister_chrdev(major_num, DEVICE_NAME);
 		return -1;
 	}
-	memset(bpctl_dev_arr, 0, ((device_num) * sizeof(bpctl_dev_t)));
+	memset(bpctl_dev_arr, 0, ((device_num) * sizeof(struct bpctl_dev)));
 
 	pdev1 = NULL;
 	dev = bpctl_dev_arr;
@@ -6797,7 +6795,7 @@
 	spin_lock_init(&bpvm_lock);
 	{
 
-		bpctl_dev_t *pbpctl_dev_c = NULL;
+		struct bpctl_dev *pbpctl_dev_c = NULL;
 		for (idx_dev = 0, dev = bpctl_dev_arr;
 		     idx_dev < device_num && dev->pdev;
 		     idx_dev++, dev++) {
@@ -7169,7 +7167,7 @@
 
 int get_bypass_slave_sd(int ifindex)
 {
-	bpctl_dev_t *pbpctl_dev_out;
+	struct bpctl_dev *pbpctl_dev_out;
 	int ret = get_bypass_slave_fn(get_dev_idx_p(ifindex), &pbpctl_dev_out);
 	if (ret == 1)
 		return pbpctl_dev_out->ifindex;
@@ -7229,7 +7227,7 @@
 }
 
 static int procfs_add(char *proc_name, const struct file_operations *fops,
-		      bpctl_dev_t *dev)
+		      struct bpctl_dev *dev)
 {
 	struct bypass_pfs_sd *pfs = &dev->bypass_pfs_set;
 	if (!proc_create_data(proc_name, 0644, pfs->bypass_entry, fops, dev))
@@ -7264,7 +7262,7 @@
 
 static int show_bypass_info(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 
 	seq_printf(m, "Name\t\t\t%s\n", dev->name);
 	seq_printf(m, "Firmware version\t0x%x\n", dev->bp_fw_ver);
@@ -7274,8 +7272,8 @@
 
 static int show_bypass_slave(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
-	bpctl_dev_t *slave = get_status_port_fn(dev);
+	struct bpctl_dev *dev = m->private;
+	struct bpctl_dev *slave = get_status_port_fn(dev);
 	if (!slave)
 		slave = dev;
 	if (!slave)
@@ -7288,7 +7286,7 @@
 
 static int show_bypass_caps(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bypass_caps_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "-1\n");
@@ -7300,7 +7298,7 @@
 
 static int show_wd_set_caps(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_wd_set_caps_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "-1\n");
@@ -7346,7 +7344,7 @@
 }
 static int show_bypass(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bypass_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7370,7 +7368,7 @@
 }
 static int show_tap(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_tap_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7394,7 +7392,7 @@
 }
 static int show_disc(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_disc_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7408,7 +7406,7 @@
 
 static int show_bypass_change(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bypass_change_fn(dev);
 	if (ret == 1)
 		seq_puts(m, "on\n");
@@ -7422,7 +7420,7 @@
 
 static int show_tap_change(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_tap_change_fn(dev);
 	if (ret == 1)
 		seq_puts(m, "on\n");
@@ -7436,7 +7434,7 @@
 
 static int show_disc_change(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_disc_change_fn(dev);
 	if (ret == 1)
 		seq_puts(m, "on\n");
@@ -7451,7 +7449,7 @@
 static ssize_t bypass_wd_write(struct file *file, const char __user *buffer,
 				  size_t count, loff_t *pos)
 {
-	bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+	struct bpctl_dev *dev = PDE_DATA(file_inode(file));
 	int timeout;
 	int ret = kstrtoint_from_user(buffer, count, 10, &timeout);
 	if (ret)
@@ -7461,7 +7459,7 @@
 }
 static int show_bypass_wd(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = 0, timeout = 0;
 
 	ret = get_bypass_wd_fn(dev, &timeout);
@@ -7479,7 +7477,7 @@
 
 static int show_wd_expire_time(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = 0, timeout = 0;
 	ret = get_wd_expire_time_fn(dev, &timeout);
 	if (ret == BP_NOT_CAP)
@@ -7497,7 +7495,7 @@
 static ssize_t tpl_write(struct file *file, const char __user *buffer,
 				  size_t count, loff_t *pos)
 {
-	bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+	struct bpctl_dev *dev = PDE_DATA(file_inode(file));
 	int tpl_param = user_on_off(buffer, count);
 	if (tpl_param < 0)
 		return -1;
@@ -7507,7 +7505,7 @@
 }
 static int show_tpl(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_tpl_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7523,7 +7521,7 @@
 static ssize_t wait_at_pwup_write(struct file *file, const char __user *buffer,
 				  size_t count, loff_t *pos)
 {
-	bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+	struct bpctl_dev *dev = PDE_DATA(file_inode(file));
 	int tpl_param = user_on_off(buffer, count);
 	if (tpl_param < 0)
 		return -1;
@@ -7533,7 +7531,7 @@
 }
 static int show_wait_at_pwup(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bp_wait_at_pwup_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7548,7 +7546,7 @@
 static ssize_t hw_reset_write(struct file *file, const char __user *buffer,
 				  size_t count, loff_t *pos)
 {
-	bpctl_dev_t *dev = PDE_DATA(file_inode(file));
+	struct bpctl_dev *dev = PDE_DATA(file_inode(file));
 	int tpl_param = user_on_off(buffer, count);
 	if (tpl_param < 0)
 		return -1;
@@ -7558,7 +7556,7 @@
 }
 static int show_hw_reset(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bp_hw_reset_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7574,7 +7572,7 @@
 
 static int show_reset_bypass_wd(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = reset_bypass_wd_timer_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7598,7 +7596,7 @@
 }
 static int show_dis_bypass(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_dis_bypass_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7622,7 +7620,7 @@
 }
 static int show_dis_tap(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_dis_tap_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7646,7 +7644,7 @@
 }
 static int show_dis_disc(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_dis_disc_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7670,7 +7668,7 @@
 }
 static int show_bypass_pwup(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bypass_pwup_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7694,7 +7692,7 @@
 }
 static int show_bypass_pwoff(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_bypass_pwoff_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7718,7 +7716,7 @@
 }
 static int show_tap_pwup(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_tap_pwup_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7742,7 +7740,7 @@
 }
 static int show_disc_pwup(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_disc_pwup_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7766,7 +7764,7 @@
 }
 static int show_std_nic(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_std_nic_fn(dev);
 	if (ret == BP_NOT_CAP)
 		seq_puts(m, "fail\n");
@@ -7808,7 +7806,7 @@
 }
 static int show_wd_exp_mode(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_wd_exp_mode_fn(dev);
 	if (ret == 1)
 		seq_puts(m, "tap\n");
@@ -7834,7 +7832,7 @@
 }
 static int show_wd_autoreset(struct seq_file *m, void *v)
 {
-	bpctl_dev_t *dev = m->private;
+	struct bpctl_dev *dev = m->private;
 	int ret = get_wd_autoreset_fn(dev);
 	if (ret >= 0)
 		seq_printf(m, "%d\n", ret);
@@ -7844,7 +7842,7 @@
 }
 RW_FOPS(wd_autoreset)
 
-int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block)
+int bypass_proc_create_dev_sd(struct bpctl_dev *pbp_device_block)
 {
 	struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set);
 	static struct proc_dir_entry *procfs_dir;
@@ -7914,7 +7912,7 @@
 	return ret;
 }
 
-int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block)
+int bypass_proc_remove_dev_sd(struct bpctl_dev *pbp_device_block)
 {
 
 	struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set;
diff --git a/drivers/staging/tidspbridge/include/dspbridge/cmm.h b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
index c66bcf7..2adf9ec 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/cmm.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/cmm.h
@@ -293,7 +293,7 @@
  *  ======== cmm_xlator_info ========
  *  Purpose:
  *      Set/Get process specific "translator" address info.
- *      This is used to perform fast virtaul address translation
+ *      This is used to perform fast virtual address translation
  *      for shared memory buffers between the GPP and DSP.
  *  Parameters:
  *     xlator:     handle to translator.
diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h
index 774a3f6..64c2457 100644
--- a/drivers/staging/tidspbridge/include/dspbridge/proc.h
+++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h
@@ -284,7 +284,7 @@
  *      user_envp:       An Array of Environment settings(Unicode Strings)
  *  Returns:
  *      0:       Success.
- *      -ENOENT:       The DSP Execuetable was not found.
+ *      -ENOENT:       The DSP Executable was not found.
  *      -EFAULT:       Invalid processor handle.
  *      -EPERM   :       Unable to Load the Processor
  *  Requires:
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 83d629a..d8957a5 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -56,8 +56,8 @@
  * usbip_status shows the status of usbip-host as long as this driver is bound
  * to the target device.
  */
-static ssize_t show_status(struct device *dev, struct device_attribute *attr,
-			   char *buf)
+static ssize_t usbip_status_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct stub_device *sdev = dev_get_drvdata(dev);
 	int status;
@@ -73,7 +73,7 @@
 
 	return snprintf(buf, PAGE_SIZE, "%d\n", status);
 }
-static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR_RO(usbip_status);
 
 /*
  * usbip_sockfd gets a socket descriptor of an established TCP connection that
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 7b97df6..e3fc749 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -45,19 +45,20 @@
 struct device_attribute dev_attr_usbip_debug;
 EXPORT_SYMBOL_GPL(dev_attr_usbip_debug);
 
-static ssize_t show_flag(struct device *dev, struct device_attribute *attr,
-			 char *buf)
+static ssize_t usbip_debug_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%lx\n", usbip_debug_flag);
 }
 
-static ssize_t store_flag(struct device *dev, struct device_attribute *attr,
-			  const char *buf, size_t count)
+static ssize_t usbip_debug_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
 {
 	sscanf(buf, "%lx", &usbip_debug_flag);
 	return count;
 }
-DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag);
+DEVICE_ATTR_RW(usbip_debug);
 
 static void usbip_dump_buffer(char *buff, int bufflen)
 {
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 25e62e9..1091bb2 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -230,7 +230,7 @@
 
 	sysfs_close_list(cname_list);
 
-	/* seach under /sys/block */
+	/* search under /sys/block */
 	ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
 	if (ret < 0)
 		return -1;
diff --git a/drivers/staging/usbip/userspace/src/usbip.c b/drivers/staging/usbip/userspace/src/usbip.c
index fff4b76..04a5f20 100644
--- a/drivers/staging/usbip/userspace/src/usbip.c
+++ b/drivers/staging/usbip/userspace/src/usbip.c
@@ -26,6 +26,7 @@
 #include <syslog.h>
 
 #include "usbip_common.h"
+#include "usbip_network.h"
 #include "usbip.h"
 
 static int usbip_help(int argc, char *argv[]);
@@ -34,7 +35,7 @@
 static const char usbip_version_string[] = PACKAGE_STRING;
 
 static const char usbip_usage_string[] =
-	"usbip [--debug] [--log] [version]\n"
+	"usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
 	"             [help] <command> <args>\n";
 
 static void usbip_usage(void)
@@ -138,9 +139,10 @@
 int main(int argc, char *argv[])
 {
 	static const struct option opts[] = {
-		{ "debug", no_argument, NULL, 'd' },
-		{ "log",   no_argument, NULL, 'l' },
-		{ NULL,    0,           NULL,  0  }
+		{ "debug",    no_argument,       NULL, 'd' },
+		{ "log",      no_argument,       NULL, 'l' },
+		{ "tcp-port", required_argument, NULL, 't' },
+		{ NULL,       0,                 NULL,  0  }
 	};
 
 	char *cmd;
@@ -150,7 +152,7 @@
 	usbip_use_stderr = 1;
 	opterr = 0;
 	for (;;) {
-		opt = getopt_long(argc, argv, "+d", opts, NULL);
+		opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
 
 		if (opt == -1)
 			break;
@@ -163,6 +165,9 @@
 			usbip_use_syslog = 1;
 			openlog("", LOG_PID, LOG_USER);
 			break;
+		case 't':
+			usbip_setup_port_number(optarg);
+			break;
 		case '?':
 			printf("usbip: invalid option\n");
 		default:
diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c
index 0ec16e5..0858411 100644
--- a/drivers/staging/usbip/userspace/src/usbip_attach.c
+++ b/drivers/staging/usbip/userspace/src/usbip_attach.c
@@ -144,7 +144,7 @@
 		return -1;
 	}
 
-	/* recieve a reply */
+	/* receive a reply */
 	rc = usbip_net_recv_op_common(sockfd, &code);
 	if (rc < 0) {
 		err("recv op_common");
@@ -175,7 +175,7 @@
 	int rc;
 	int rhport;
 
-	sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
 	if (sockfd < 0) {
 		err("tcp connect");
 		return -1;
@@ -189,7 +189,7 @@
 
 	close(sockfd);
 
-	rc = record_connection(host, USBIP_PORT_STRING, busid, rhport);
+	rc = record_connection(host, usbip_port_string, busid, rhport);
 	if (rc < 0) {
 		err("record connection");
 		return -1;
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
index ff56255..237e099 100644
--- a/drivers/staging/usbip/userspace/src/usbip_list.c
+++ b/drivers/staging/usbip/userspace/src/usbip_list.c
@@ -131,13 +131,13 @@
 	int rc;
 	int sockfd;
 
-	sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING);
+	sockfd = usbip_net_tcp_connect(host, usbip_port_string);
 	if (sockfd < 0) {
 		err("could not connect to %s:%s: %s", host,
-		    USBIP_PORT_STRING, gai_strerror(sockfd));
+		    usbip_port_string, gai_strerror(sockfd));
 		return -1;
 	}
-	dbg("connected to %s:%s", host, USBIP_PORT_STRING);
+	dbg("connected to %s:%s", host, usbip_port_string);
 
 	rc = get_exported_devices(host, sockfd);
 	if (rc < 0) {
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c
index b12448e..c39a07f 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.c
+++ b/drivers/staging/usbip/userspace/src/usbip_network.c
@@ -28,6 +28,36 @@
 #include "usbip_common.h"
 #include "usbip_network.h"
 
+int usbip_port = 3240;
+char *usbip_port_string = "3240";
+
+void usbip_setup_port_number(char *arg)
+{
+	dbg("parsing port arg '%s'", arg);
+	char *end;
+	unsigned long int port = strtoul(arg, &end, 10);
+
+	if (end == arg) {
+		err("port: could not parse '%s' as a decimal integer", arg);
+		return;
+	}
+
+	if (*end != '\0') {
+		err("port: garbage at end of '%s'", arg);
+		return;
+	}
+
+	if (port > UINT16_MAX) {
+		err("port: %s too high (max=%d)",
+		    arg, UINT16_MAX);
+		return;
+	}
+
+	usbip_port = port;
+	usbip_port_string = arg;
+	info("using port %d (\"%s\")", usbip_port, usbip_port_string);
+}
+
 void usbip_net_pack_uint32_t(int pack, uint32_t *num)
 {
 	uint32_t i;
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h
index 1bbefc9..2d0e427 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.h
+++ b/drivers/staging/usbip/userspace/src/usbip_network.h
@@ -14,8 +14,9 @@
 
 #include <stdint.h>
 
-#define USBIP_PORT 3240
-#define USBIP_PORT_STRING "3240"
+extern int usbip_port;
+extern char *usbip_port_string;
+void usbip_setup_port_number(char *arg);
 
 /* ---------------------------------------------------------------------- */
 /* Common header for all the kinds of PDUs. */
diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c
index 3e913b8..1c76cfd 100644
--- a/drivers/staging/usbip/userspace/src/usbipd.c
+++ b/drivers/staging/usbip/userspace/src/usbipd.c
@@ -50,21 +50,30 @@
 
 #define MAIN_LOOP_TIMEOUT 10
 
+#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
+
 static const char usbip_version_string[] = PACKAGE_STRING;
 
 static const char usbipd_help_string[] =
-	"usage: usbipd [options]			\n"
-	"	-D, --daemon				\n"
-	"		Run as a daemon process.	\n"
-	"						\n"
-	"	-d, --debug				\n"
-	"		Print debugging information.	\n"
-	"						\n"
-	"	-h, --help				\n"
-	"		Print this help.		\n"
-	"						\n"
-	"	-v, --version				\n"
-	"		Show version.			\n";
+	"usage: usbipd [options]\n"
+	"	-D, --daemon\n"
+	"		Run as a daemon process.\n"
+	"\n"
+	"	-d, --debug\n"
+	"		Print debugging information.\n"
+	"\n"
+	"	-PFILE, --pid FILE\n"
+	"		Write process id to FILE.\n"
+	"		If no FILE specified, use " DEFAULT_PID_FILE "\n"
+	"\n"
+	"	-tPORT, --tcp-port PORT\n"
+	"		Listen on TCP/IP port PORT.\n"
+	"\n"
+	"	-h, --help\n"
+	"		Print this help.\n"
+	"\n"
+	"	-v, --version\n"
+	"		Show version.\n";
 
 static void usbipd_help(void)
 {
@@ -286,13 +295,13 @@
 
 	memset(&ss, 0, sizeof(ss));
 
-	connfd = accept(listenfd, (struct sockaddr *) &ss, &len);
+	connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
 	if (connfd < 0) {
 		err("failed to accept connection");
 		return -1;
 	}
 
-	rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host),
+	rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
 			 port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
 	if (rc)
 		err("getnameinfo: %s", gai_strerror(rc));
@@ -328,56 +337,69 @@
 	return 0;
 }
 
-static void log_addrinfo(struct addrinfo *ai)
+static void addrinfo_to_text(struct addrinfo *ai, char buf[],
+			     const size_t buf_size)
 {
 	char hbuf[NI_MAXHOST];
 	char sbuf[NI_MAXSERV];
 	int rc;
 
+	buf[0] = '\0';
+
 	rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
 			 sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
 	if (rc)
 		err("getnameinfo: %s", gai_strerror(rc));
 
-	info("listening on %s:%s", hbuf, sbuf);
+	snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
 }
 
 static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[])
 {
 	struct addrinfo *ai;
 	int ret, nsockfd = 0;
+	const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
+	char ai_buf[ai_buf_size];
 
 	for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) {
-		sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype,
-					     ai->ai_protocol);
-		if (sockfdlist[nsockfd] < 0)
-			continue;
-
-		usbip_net_set_reuseaddr(sockfdlist[nsockfd]);
-		usbip_net_set_nodelay(sockfdlist[nsockfd]);
-
-		if (sockfdlist[nsockfd] >= FD_SETSIZE) {
-			close(sockfdlist[nsockfd]);
-			sockfdlist[nsockfd] = -1;
+		int sock;
+		addrinfo_to_text(ai, ai_buf, ai_buf_size);
+		dbg("opening %s", ai_buf);
+		sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (sock < 0) {
+			err("socket: %s: %d (%s)",
+			    ai_buf, errno, strerror(errno));
 			continue;
 		}
 
-		ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen);
+		usbip_net_set_reuseaddr(sock);
+		usbip_net_set_nodelay(sock);
+
+		if (sock >= FD_SETSIZE) {
+			err("FD_SETSIZE: %s: sock=%d, max=%d",
+			    ai_buf, sock, FD_SETSIZE);
+			close(sock);
+			continue;
+		}
+
+		ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
 		if (ret < 0) {
-			close(sockfdlist[nsockfd]);
-			sockfdlist[nsockfd] = -1;
+			err("bind: %s: %d (%s)",
+			    ai_buf, errno, strerror(errno));
+			close(sock);
 			continue;
 		}
 
-		ret = listen(sockfdlist[nsockfd], SOMAXCONN);
+		ret = listen(sock, SOMAXCONN);
 		if (ret < 0) {
-			close(sockfdlist[nsockfd]);
-			sockfdlist[nsockfd] = -1;
+			err("listen: %s: %d (%s)",
+			    ai_buf, errno, strerror(errno));
+			close(sock);
 			continue;
 		}
 
-		log_addrinfo(ai);
-		nsockfd++;
+		info("listening on %s", ai_buf);
+		sockfdlist[nsockfd++] = sock;
 	}
 
 	if (nsockfd == 0)
@@ -398,9 +420,9 @@
 	hints.ai_socktype = SOCK_STREAM;
 	hints.ai_flags    = AI_PASSIVE;
 
-	rc = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head);
+	rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
 	if (rc) {
-		err("failed to get a network address %s: %s", USBIP_PORT_STRING,
+		err("failed to get a network address %s: %s", usbip_port_string,
 		    gai_strerror(rc));
 		return NULL;
 	}
@@ -426,6 +448,31 @@
 	sigaction(SIGCLD, &act, NULL);
 }
 
+static const char *pid_file;
+
+static void write_pid_file()
+{
+	if (pid_file) {
+		dbg("creating pid file %s", pid_file);
+		FILE *fp = fopen(pid_file, "w");
+		if (!fp) {
+			err("pid_file: %s: %d (%s)",
+			    pid_file, errno, strerror(errno));
+			return;
+		}
+		fprintf(fp, "%d\n", getpid());
+		fclose(fp);
+	}
+}
+
+static void remove_pid_file()
+{
+	if (pid_file) {
+		dbg("removing pid file %s", pid_file);
+		unlink(pid_file);
+	}
+}
+
 static int do_standalone_mode(int daemonize)
 {
 	struct addrinfo *ai_head;
@@ -452,6 +499,7 @@
 		usbip_use_syslog = 1;
 	}
 	set_signal();
+	write_pid_file();
 
 	ai_head = do_getaddrinfo(NULL, PF_UNSPEC);
 	if (!ai_head) {
@@ -496,8 +544,9 @@
 					process_request(sockfdlist[i]);
 				}
 			}
-		} else
+		} else {
 			dbg("heartbeat timeout on ppoll()");
+		}
 	}
 
 	info("shutting down " PROGNAME);
@@ -511,11 +560,13 @@
 int main(int argc, char *argv[])
 {
 	static const struct option longopts[] = {
-		{ "daemon",  no_argument, NULL, 'D' },
-		{ "debug",   no_argument, NULL, 'd' },
-		{ "help",    no_argument, NULL, 'h' },
-		{ "version", no_argument, NULL, 'v' },
-		{ NULL,	     0,           NULL,  0  }
+		{ "daemon",   no_argument,       NULL, 'D' },
+		{ "debug",    no_argument,       NULL, 'd' },
+		{ "pid",      optional_argument, NULL, 'P' },
+		{ "tcp-port", required_argument, NULL, 't' },
+		{ "help",     no_argument,       NULL, 'h' },
+		{ "version",  no_argument,       NULL, 'v' },
+		{ NULL,	      0,                 NULL,  0  }
 	};
 
 	enum {
@@ -526,6 +577,7 @@
 
 	int daemonize = 0;
 	int opt, rc = -1;
+	pid_file = NULL;
 
 	usbip_use_stderr = 1;
 	usbip_use_syslog = 0;
@@ -535,7 +587,7 @@
 
 	cmd = cmd_standalone_mode;
 	for (;;) {
-		opt = getopt_long(argc, argv, "Ddhv", longopts, NULL);
+		opt = getopt_long(argc, argv, "DdP::t:hv", longopts, NULL);
 
 		if (opt == -1)
 			break;
@@ -550,6 +602,12 @@
 		case 'h':
 			cmd = cmd_help;
 			break;
+		case 'P':
+			pid_file = optarg ? optarg : DEFAULT_PID_FILE;
+			break;
+		case 't':
+			usbip_setup_port_number(optarg);
+			break;
 		case 'v':
 			cmd = cmd_version;
 			break;
@@ -563,6 +621,7 @@
 	switch (cmd) {
 	case cmd_standalone_mode:
 		rc = do_standalone_mode(daemonize);
+		remove_pid_file();
 		break;
 	case cmd_version:
 		printf(PROGNAME " (%s)\n", usbip_version_string);
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index c66e9c0..9b51586 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -27,7 +27,7 @@
 /* TODO: refine locking ?*/
 
 /* Sysfs entry to show port status */
-static ssize_t show_status(struct device *dev, struct device_attribute *attr,
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
 			   char *out)
 {
 	char *s = out;
@@ -74,7 +74,7 @@
 
 	return out - s;
 }
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR_RO(status);
 
 /* Sysfs entry to shutdown a virtual connection */
 static int vhci_port_disconnect(__u32 rhport)
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 08b250f..7f36a71 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -3370,8 +3370,8 @@
 	PSMgmtObject  pMgmt = pDevice->pMgmt;
 	int power_status;   // to silence the compiler
 
-	power_status = pci_set_power_state(pcid, 0);
-	power_status = pci_enable_wake(pcid, 0, 0);
+	power_status = pci_set_power_state(pcid, PCI_D0);
+	power_status = pci_enable_wake(pcid, PCI_D0, 0);
 	pci_restore_state(pcid);
 	if (netif_running(pDevice->dev)) {
 		spin_lock_irq(&pDevice->lock);
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index 33fa767..1e8b841 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -680,7 +680,6 @@
     unsigned int uRate = 0;
 
     if (uRateIdx > RATE_54M) {
-        ASSERT(0);
         return 0;
     }
 
@@ -724,16 +723,16 @@
  *      cbFrameLength   - Tx Frame Length
  *      wRate           - Tx Rate
  *  Out:
- *      pwPhyLen        - pointer to Phy Length field
- *      pbyPhySrv       - pointer to Phy Service field
- *      pbyPhySgn       - pointer to Phy Signal field
+ *	struct vnt_phy_field *phy
+ * 			- pointer to Phy Length field
+ *			- pointer to Phy Service field
+ * 			- pointer to Phy Signal field
  *
  * Return Value: none
  *
  */
 void BBvCalculateParameter(struct vnt_private *pDevice, u32 cbFrameLength,
-	u16 wRate, u8 byPacketType, u16 *pwPhyLen, u8 *pbyPhySrv,
-		u8 *pbyPhySgn)
+	u16 wRate, u8 byPacketType, struct vnt_phy_field *phy)
 {
 	u32 cbBitCount;
 	u32 cbUsCount = 0;
@@ -748,15 +747,15 @@
     switch (wRate) {
     case RATE_1M :
         cbUsCount = cbBitCount;
-        *pbyPhySgn = 0x00;
+	phy->signal = 0x00;
         break;
 
     case RATE_2M :
         cbUsCount = cbBitCount / 2;
         if (byPreambleType == 1)
-            *pbyPhySgn = 0x09;
+		phy->signal = 0x09;
         else // long preamble
-            *pbyPhySgn = 0x01;
+		phy->signal = 0x01;
         break;
 
     case RATE_5M :
@@ -767,9 +766,9 @@
         if (cbTmp != cbBitCount)
             cbUsCount ++;
         if (byPreambleType == 1)
-            *pbyPhySgn = 0x0a;
+		phy->signal = 0x0a;
         else // long preamble
-            *pbyPhySgn = 0x02;
+		phy->signal = 0x02;
         break;
 
     case RATE_11M :
@@ -784,103 +783,102 @@
                 bExtBit = true;
         }
         if (byPreambleType == 1)
-            *pbyPhySgn = 0x0b;
+		phy->signal = 0x0b;
         else // long preamble
-            *pbyPhySgn = 0x03;
+		phy->signal = 0x03;
         break;
 
     case RATE_6M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9B; //1001 1011
+		phy->signal = 0x9b;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8B; //1000 1011
+		phy->signal = 0x8b;
         }
         break;
 
     case RATE_9M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9F; //1001 1111
+		phy->signal = 0x9f;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8F; //1000 1111
+		phy->signal = 0x8f;
         }
         break;
 
     case RATE_12M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9A; //1001 1010
+		phy->signal = 0x9a;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8A; //1000 1010
+		phy->signal = 0x8a;
         }
         break;
 
     case RATE_18M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9E; //1001 1110
+		phy->signal = 0x9e;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8E; //1000 1110
+		phy->signal = 0x8e;
         }
         break;
 
     case RATE_24M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x99; //1001 1001
+		phy->signal = 0x99;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x89; //1000 1001
+		phy->signal = 0x89;
         }
         break;
 
     case RATE_36M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9D; //1001 1101
+		phy->signal = 0x9d;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8D; //1000 1101
+		phy->signal = 0x8d;
         }
         break;
 
     case RATE_48M :
         if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x98; //1001 1000
+		phy->signal = 0x98;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x88; //1000 1000
+		phy->signal = 0x88;
         }
         break;
 
     case RATE_54M :
         if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9C; //1001 1100
+		phy->signal = 0x9c;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8C; //1000 1100
+		phy->signal = 0x8c;
         }
         break;
 
     default :
         if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
-            *pbyPhySgn = 0x9C; //1001 1100
+		phy->signal = 0x9c;
         }
         else {//11g, 2.4GHZ
-            *pbyPhySgn = 0x8C; //1000 1100
+		phy->signal = 0x8c;
         }
         break;
     }
 
-    if (byPacketType == PK_TYPE_11B) {
-        *pbyPhySrv = 0x00;
-        if (bExtBit)
-            *pbyPhySrv = *pbyPhySrv | 0x80;
-        *pwPhyLen = (u16) cbUsCount;
-    }
-    else {
-        *pbyPhySrv = 0x00;
-        *pwPhyLen = (u16)cbFrameLength;
-    }
+	if (byPacketType == PK_TYPE_11B) {
+		phy->service = 0x00;
+		if (bExtBit)
+			phy->service |= 0x80;
+		phy->len = cpu_to_le16((u16)cbUsCount);
+	} else {
+		phy->service = 0x00;
+		phy->len = cpu_to_le16((u16)cbFrameLength);
+	}
 }
 
 /*
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index 0a634ad..79faedf4 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -81,6 +81,13 @@
 #define TOP_RATE_2M         0x00200000
 #define TOP_RATE_1M         0x00100000
 
+/* Length, Service, and Signal fields of Phy for Tx */
+struct vnt_phy_field {
+	u8 signal;
+	u8 service;
+	__le16 len;
+} __packed;
+
 unsigned int
 BBuGetFrameTime(
      u8 byPreambleType,
@@ -90,8 +97,7 @@
     );
 
 void BBvCalculateParameter(struct vnt_private *, u32 cbFrameLength,
-	u16 wRate, u8 byPacketType, u16 *pwPhyLen, u8 *pbyPhySrv,
-	u8 *pbyPhySgn);
+	u16 wRate, u8 byPacketType, struct vnt_phy_field *);
 
 /* timer for antenna diversity */
 
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 24291ae..dbf11ec 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -319,53 +319,27 @@
  */
 void CARDvSetRSPINF(struct vnt_private *pDevice, u8 byBBType)
 {
-	u8 abyServ[4] = {0, 0, 0, 0}; /* For CCK */
-	u8 abySignal[4] = {0, 0, 0, 0};
-	u16 awLen[4] = {0, 0, 0, 0};
+	struct vnt_phy_field phy[4];
 	u8 abyTxRate[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; /* For OFDM */
 	u8 abyRsvTime[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 	u8 abyData[34];
 	int i;
 
     //RSPINF_b_1
-    BBvCalculateParameter(pDevice,
-                         14,
-                         swGetCCKControlRate(pDevice, RATE_1M),
-                         PK_TYPE_11B,
-                         &awLen[0],
-                         &abyServ[0],
-                         &abySignal[0]
-    );
+	BBvCalculateParameter(pDevice, 14,
+		swGetCCKControlRate(pDevice, RATE_1M), PK_TYPE_11B, &phy[0]);
 
     ///RSPINF_b_2
-    BBvCalculateParameter(pDevice,
-                         14,
-                         swGetCCKControlRate(pDevice, RATE_2M),
-                         PK_TYPE_11B,
-                         &awLen[1],
-                         &abyServ[1],
-                         &abySignal[1]
-    );
+	BBvCalculateParameter(pDevice, 14,
+		swGetCCKControlRate(pDevice, RATE_2M), PK_TYPE_11B, &phy[1]);
 
     //RSPINF_b_5
-    BBvCalculateParameter(pDevice,
-                         14,
-                         swGetCCKControlRate(pDevice, RATE_5M),
-                         PK_TYPE_11B,
-                         &awLen[2],
-                         &abyServ[2],
-                         &abySignal[2]
-    );
+	BBvCalculateParameter(pDevice, 14,
+		swGetCCKControlRate(pDevice, RATE_5M), PK_TYPE_11B, &phy[2]);
 
     //RSPINF_b_11
-    BBvCalculateParameter(pDevice,
-                         14,
-                         swGetCCKControlRate(pDevice, RATE_11M),
-                         PK_TYPE_11B,
-                         &awLen[3],
-                         &abyServ[3],
-                         &abySignal[3]
-    );
+	BBvCalculateParameter(pDevice, 14,
+		swGetCCKControlRate(pDevice, RATE_11M), PK_TYPE_11B, &phy[3]);
 
     //RSPINF_a_6
     CARDvCalculateOFDMRParameter (RATE_6M,
@@ -421,25 +395,21 @@
                                  &abyTxRate[8],
                                  &abyRsvTime[8]);
 
-    abyData[0] = (u8)(awLen[0]&0xFF);
-    abyData[1] = (u8)(awLen[0]>>8);
-    abyData[2] = abySignal[0];
-    abyData[3] = abyServ[0];
+	put_unaligned(phy[0].len, (u16 *)&abyData[0]);
+	abyData[2] = phy[0].signal;
+	abyData[3] = phy[0].service;
 
-    abyData[4] = (u8)(awLen[1]&0xFF);
-    abyData[5] = (u8)(awLen[1]>>8);
-    abyData[6] = abySignal[1];
-    abyData[7] = abyServ[1];
+	put_unaligned(phy[1].len, (u16 *)&abyData[4]);
+	abyData[6] = phy[1].signal;
+	abyData[7] = phy[1].service;
 
-    abyData[8] = (u8)(awLen[2]&0xFF);
-    abyData[9] = (u8)(awLen[2]>>8);
-    abyData[10] = abySignal[2];
-    abyData[11] = abyServ[2];
+	put_unaligned(phy[2].len, (u16 *)&abyData[8]);
+	abyData[10] = phy[2].signal;
+	abyData[11] = phy[2].service;
 
-    abyData[12] = (u8)(awLen[3]&0xFF);
-    abyData[13] = (u8)(awLen[3]>>8);
-    abyData[14] = abySignal[3];
-    abyData[15] = abyServ[3];
+	put_unaligned(phy[3].len, (u16 *)&abyData[12]);
+	abyData[14] = phy[3].signal;
+	abyData[15] = phy[3].service;
 
     for (i = 0; i < 9; i++) {
 	abyData[16+i*2] = abyTxRate[i];
diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h
index 64cb046..4675135 100644
--- a/drivers/staging/vt6656/desc.h
+++ b/drivers/staging/vt6656/desc.h
@@ -144,160 +144,6 @@
 #define TD_FLAGS_PS_RETRY  0x04 /* check if PS STA frame re-transmit */
 
 /*
- * RsvTime buffer header
- */
-typedef struct tagSRrvTime_gRTS {
-    u16        wRTSTxRrvTime_ba;
-    u16        wRTSTxRrvTime_aa;
-    u16        wRTSTxRrvTime_bb;
-    u16        wReserved;
-    u16        wTxRrvTime_b;
-    u16        wTxRrvTime_a;
-} __attribute__ ((__packed__))
-SRrvTime_gRTS, *PSRrvTime_gRTS;
-
-typedef const SRrvTime_gRTS *PCSRrvTime_gRTS;
-
-typedef struct tagSRrvTime_gCTS {
-    u16        wCTSTxRrvTime_ba;
-    u16        wReserved;
-    u16        wTxRrvTime_b;
-    u16        wTxRrvTime_a;
-} __attribute__ ((__packed__))
-SRrvTime_gCTS, *PSRrvTime_gCTS;
-
-typedef const SRrvTime_gCTS *PCSRrvTime_gCTS;
-
-typedef struct tagSRrvTime_ab {
-    u16        wRTSTxRrvTime;
-    u16        wTxRrvTime;
-} __attribute__ ((__packed__))
-SRrvTime_ab, *PSRrvTime_ab;
-
-typedef const SRrvTime_ab *PCSRrvTime_ab;
-
-typedef struct tagSRrvTime_atim {
-    u16        wCTSTxRrvTime_ba;
-    u16        wTxRrvTime_a;
-} __attribute__ ((__packed__))
-SRrvTime_atim, *PSRrvTime_atim;
-
-typedef const SRrvTime_atim *PCSRrvTime_atim;
-
-/*
- * RTS buffer header
- */
-typedef struct tagSRTSData {
-    u16    wFrameControl;
-    u16    wDurationID;
-    u8    abyRA[ETH_ALEN];
-    u8    abyTA[ETH_ALEN];
-} __attribute__ ((__packed__))
-SRTSData, *PSRTSData;
-
-typedef const SRTSData *PCSRTSData;
-
-typedef struct tagSRTS_g {
-    u8        bySignalField_b;
-    u8        byServiceField_b;
-    u16        wTransmitLength_b;
-    u8        bySignalField_a;
-    u8        byServiceField_a;
-    u16        wTransmitLength_a;
-    u16        wDuration_ba;
-    u16        wDuration_aa;
-    u16        wDuration_bb;
-    u16        wReserved;
-    SRTSData    Data;
-} __attribute__ ((__packed__))
-SRTS_g, *PSRTS_g;
-typedef const SRTS_g *PCSRTS_g;
-
-typedef struct tagSRTS_g_FB {
-    u8        bySignalField_b;
-    u8        byServiceField_b;
-    u16        wTransmitLength_b;
-    u8        bySignalField_a;
-    u8        byServiceField_a;
-    u16        wTransmitLength_a;
-    u16        wDuration_ba;
-    u16        wDuration_aa;
-    u16        wDuration_bb;
-    u16        wReserved;
-    u16        wRTSDuration_ba_f0;
-    u16        wRTSDuration_aa_f0;
-    u16        wRTSDuration_ba_f1;
-    u16        wRTSDuration_aa_f1;
-    SRTSData    Data;
-} __attribute__ ((__packed__))
-SRTS_g_FB, *PSRTS_g_FB;
-
-typedef const SRTS_g_FB *PCSRTS_g_FB;
-
-typedef struct tagSRTS_ab {
-    u8        bySignalField;
-    u8        byServiceField;
-    u16        wTransmitLength;
-    u16        wDuration;
-    u16        wReserved;
-    SRTSData    Data;
-} __attribute__ ((__packed__))
-SRTS_ab, *PSRTS_ab;
-
-typedef const SRTS_ab *PCSRTS_ab;
-
-typedef struct tagSRTS_a_FB {
-    u8        bySignalField;
-    u8        byServiceField;
-    u16        wTransmitLength;
-    u16        wDuration;
-    u16        wReserved;
-    u16        wRTSDuration_f0;
-    u16        wRTSDuration_f1;
-    SRTSData    Data;
-} __attribute__ ((__packed__))
-SRTS_a_FB, *PSRTS_a_FB;
-
-typedef const SRTS_a_FB *PCSRTS_a_FB;
-
-/*
- * CTS buffer header
- */
-typedef struct tagSCTSData {
-    u16    wFrameControl;
-    u16    wDurationID;
-    u8    abyRA[ETH_ALEN];
-    u16    wReserved;
-} __attribute__ ((__packed__))
-SCTSData, *PSCTSData;
-
-typedef struct tagSCTS {
-    u8        bySignalField_b;
-    u8        byServiceField_b;
-    u16        wTransmitLength_b;
-    u16        wDuration_ba;
-    u16        wReserved;
-    SCTSData    Data;
-} __attribute__ ((__packed__))
-SCTS, *PSCTS;
-
-typedef const SCTS *PCSCTS;
-
-typedef struct tagSCTS_FB {
-    u8        bySignalField_b;
-    u8        byServiceField_b;
-    u16        wTransmitLength_b;
-    u16        wDuration_ba;
-    u16        wReserved;
-    u16        wCTSDuration_ba_f0;
-    u16        wCTSDuration_ba_f1;
-    SCTSData    Data;
-} __attribute__ ((__packed__))
-SCTS_FB, *PSCTS_FB;
-
-typedef const SCTS_FB *PCSCTS_FB;
-
-/*
  * TX FIFO header
  */
 typedef struct tagSTxBufHead {
@@ -317,76 +163,6 @@
 STxShortBufHead, *PSTxShortBufHead;
 typedef const STxShortBufHead *PCSTxShortBufHead;
 
-/*
- * TX data header
- */
-typedef struct tagSTxDataHead_g {
-    u8    bySignalField_b;
-    u8    byServiceField_b;
-    u16    wTransmitLength_b;
-    u8    bySignalField_a;
-    u8    byServiceField_a;
-    u16    wTransmitLength_a;
-    u16    wDuration_b;
-    u16    wDuration_a;
-    u16    wTimeStampOff_b;
-    u16    wTimeStampOff_a;
-} __attribute__ ((__packed__))
-STxDataHead_g, *PSTxDataHead_g;
-
-typedef const STxDataHead_g *PCSTxDataHead_g;
-
-typedef struct tagSTxDataHead_g_FB {
-    u8    bySignalField_b;
-    u8    byServiceField_b;
-    u16    wTransmitLength_b;
-    u8    bySignalField_a;
-    u8    byServiceField_a;
-    u16    wTransmitLength_a;
-    u16    wDuration_b;
-    u16    wDuration_a;
-    u16    wDuration_a_f0;
-    u16    wDuration_a_f1;
-    u16    wTimeStampOff_b;
-    u16    wTimeStampOff_a;
-} __attribute__ ((__packed__))
-STxDataHead_g_FB, *PSTxDataHead_g_FB;
-typedef const STxDataHead_g_FB *PCSTxDataHead_g_FB;
-
-typedef struct tagSTxDataHead_ab {
-    u8    bySignalField;
-    u8    byServiceField;
-    u16    wTransmitLength;
-    u16    wDuration;
-    u16    wTimeStampOff;
-} __attribute__ ((__packed__))
-STxDataHead_ab, *PSTxDataHead_ab;
-typedef const STxDataHead_ab *PCSTxDataHead_ab;
-
-typedef struct tagSTxDataHead_a_FB {
-    u8    bySignalField;
-    u8    byServiceField;
-    u16    wTransmitLength;
-    u16    wDuration;
-    u16    wTimeStampOff;
-    u16    wDuration_f0;
-    u16    wDuration_f1;
-} __attribute__ ((__packed__))
-STxDataHead_a_FB, *PSTxDataHead_a_FB;
-typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
-
-/*
- * MICHDR data header
- */
-typedef struct tagSMICHDRHead {
-	u32 adwHDR0[4];
-	u32 adwHDR1[4];
-	u32 adwHDR2[4];
-} __attribute__ ((__packed__))
-SMICHDRHead, *PSMICHDRHead;
-
-typedef const SMICHDRHead *PCSMICHDRHead;
-
 typedef struct tagSBEACONCtl {
 	u32 BufReady:1;
 	u32 TSF:15;
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index f07ba24..8e39634 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -166,8 +166,7 @@
 } CONTEXT_TYPE;
 
 /* RCB (Receive Control Block) */
-typedef struct _RCB
-{
+struct vnt_rcb {
 	void *Next;
 	signed long Ref;
 	void *pDevice;
@@ -175,21 +174,20 @@
 	struct vnt_rx_mgmt sMngPacket;
 	struct sk_buff *skb;
 	int bBoolInUse;
-
-} RCB, *PRCB;
+};
 
 /* used to track bulk out irps */
-typedef struct _USB_SEND_CONTEXT {
-    void *pDevice;
-    struct sk_buff *pPacket;
-    struct urb      *pUrb;
-    unsigned int            uBufLen;
-    CONTEXT_TYPE    Type;
-    struct ethhdr sEthHeader;
-    void *Next;
-    bool            bBoolInUse;
-    unsigned char           Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
-} USB_SEND_CONTEXT, *PUSB_SEND_CONTEXT;
+struct vnt_usb_send_context {
+	void *pDevice;
+	struct sk_buff *pPacket;
+	struct urb *pUrb;
+	unsigned int uBufLen;
+	CONTEXT_TYPE Type;
+	struct ethhdr sEthHeader;
+	void *Next;
+	bool bBoolInUse;
+	unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
+};
 
 /* structure got from configuration file as user-desired default settings */
 typedef struct _DEFAULT_CONFIG {
@@ -416,21 +414,21 @@
 	u32 int_interval;
 
 	/* Variables to track resources for the BULK In Pipe */
-	PRCB pRCBMem;
-	PRCB apRCB[CB_MAX_RX_DESC];
+	struct vnt_rcb *pRCBMem;
+	struct vnt_rcb *apRCB[CB_MAX_RX_DESC];
 	u32 cbRD;
-	PRCB FirstRecvFreeList;
-	PRCB LastRecvFreeList;
+	struct vnt_rcb *FirstRecvFreeList;
+	struct vnt_rcb *LastRecvFreeList;
 	u32 NumRecvFreeList;
-	PRCB FirstRecvMngList;
-	PRCB LastRecvMngList;
+	struct vnt_rcb *FirstRecvMngList;
+	struct vnt_rcb *LastRecvMngList;
 	u32 NumRecvMngList;
 	int bIsRxWorkItemQueued;
 	int bIsRxMngWorkItemQueued;
 	unsigned long ulRcvRefCount; /* packets that have not returned back */
 
 	/* Variables to track resources for the BULK Out Pipe */
-	PUSB_SEND_CONTEXT apTD[CB_MAX_TX_DESC];
+	struct vnt_usb_send_context *apTD[CB_MAX_TX_DESC];
 	u32 cbTD;
 
 	/* Variables to track resources for the Interrupt In Pipe */
@@ -591,18 +589,11 @@
 	u8 abyBSSID[ETH_ALEN];
 	u8 abyDesireBSSID[ETH_ALEN];
 
-	u16 wCTSDuration;       /* update while speed change */
-	u16 wACKDuration;
-	u16 wRTSTransmitLen;
-	u8 byRTSServiceField;
-	u8 byRTSSignalField;
-
 	u32 dwMaxReceiveLifetime;  /* dot11MaxReceiveLifetime */
 
 	int bCCK;
 	int bEncryptionEnable;
 	int bLongHeader;
-	int bSoftwareGenCrcErr;
 	int bShortSlotTime;
 	int bProtectMode;
 	int bNonERPPresent;
@@ -781,7 +772,7 @@
 
 #define DequeueRCB(Head, Tail)                          \
 {                                                       \
-    PRCB   RCB = Head;                                  \
+    struct vnt_rcb *RCB = Head;                         \
     if (!RCB->Next) {                                   \
         Tail = NULL;                                    \
     }                                                   \
diff --git a/drivers/staging/vt6656/device_cfg.h b/drivers/staging/vt6656/device_cfg.h
index ea66b97..a97f7bb 100644
--- a/drivers/staging/vt6656/device_cfg.h
+++ b/drivers/staging/vt6656/device_cfg.h
@@ -82,18 +82,4 @@
     VT3184 = 1
 } CHIP_TYPE, *PCHIP_TYPE;
 
-#ifdef VIAWET_DEBUG
-#define ASSERT(x) { \
-    if (!(x)) { \
-	printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x, \
-        __FUNCTION__, __LINE__);\
-	*(int *) 0 = 0;		\
-    } \
-}
-#define DBG_PORT80(value)                   outb(value, 0x80)
-#else
-#define ASSERT(x)
-#define DBG_PORT80(value)
-#endif
-
 #endif
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index 7ec166a..ea7d443 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -246,7 +246,7 @@
     *pcbHeaderSize = cbHeaderSize;
 }
 
-int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
+int RXbBulkInProcessData(struct vnt_private *pDevice, struct vnt_rcb *pRCB,
 	unsigned long BytesToIndicate)
 {
 	struct net_device_stats *pStats = &pDevice->stats;
@@ -271,7 +271,7 @@
 	/* signed long ldBm = 0; */
 	int bIsWEP = false; int bExtIV = false;
 	u32 dwWbkStatus;
-	PRCB pRCBIndicate = pRCB;
+	struct vnt_rcb *pRCBIndicate = pRCB;
 	u8 *pbyDAddress;
 	u16 *pwPLCP_Length;
 	u8 abyVaildRate[MAX_RATE]
@@ -314,7 +314,6 @@
          (BytesToIndicate < (*pwPLCP_Length)) ) {
 
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Wrong PLCP Length %x\n", (int) *pwPLCP_Length);
-        ASSERT(0);
         return false;
     }
     for ( ii=RATE_1M;ii<MAX_RATE;ii++) {
@@ -1337,7 +1336,7 @@
 void RXvWorkItem(struct vnt_private *pDevice)
 {
 	int ntStatus;
-	PRCB pRCB = NULL;
+	struct vnt_rcb *pRCB = NULL;
 
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n");
     spin_lock_irq(&pDevice->lock);
@@ -1347,7 +1346,6 @@
             (pDevice->NumRecvFreeList != 0) ) {
         pRCB = pDevice->FirstRecvFreeList;
         pDevice->NumRecvFreeList--;
-        ASSERT(pRCB);// cannot be NULL
         DequeueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList);
         ntStatus = PIPEnsBulkInUsbRead(pDevice, pRCB);
     }
@@ -1356,15 +1354,12 @@
 
 }
 
-void RXvFreeRCB(PRCB pRCB, int bReAllocSkb)
+void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb)
 {
 	struct vnt_private *pDevice = pRCB->pDevice;
 
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n");
 
-    ASSERT(!pRCB->Ref);     // should be 0
-    ASSERT(pRCB->pDevice);  // shouldn't be NULL
-
 	if (bReAllocSkb == false) {
 		kfree_skb(pRCB->skb);
 		bReAllocSkb = true;
@@ -1396,7 +1391,7 @@
 
 void RXvMngWorkItem(struct vnt_private *pDevice)
 {
-	PRCB pRCB = NULL;
+	struct vnt_rcb *pRCB = NULL;
 	struct vnt_rx_mgmt *pRxPacket;
 	int bReAllocSkb = false;
 
@@ -1411,7 +1406,6 @@
         if(!pRCB){
             break;
         }
-        ASSERT(pRCB);// cannot be NULL
         pRxPacket = &(pRCB->sMngPacket);
 	vMgrRxManagePacket(pDevice, &pDevice->vnt_mgmt, pRxPacket);
         pRCB->Ref--;
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
index 876468f..95388dc 100644
--- a/drivers/staging/vt6656/dpc.h
+++ b/drivers/staging/vt6656/dpc.h
@@ -36,9 +36,9 @@
 
 void RXvMngWorkItem(void *Context);
 
-void RXvFreeRCB(PRCB pRCB, int bReAllocSkb);
+void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb);
 
-int RXbBulkInProcessData(struct vnt_private *, PRCB pRCB,
+int RXbBulkInProcessData(struct vnt_private *, struct vnt_rcb *pRCB,
 	unsigned long BytesToIndicate);
 
 #endif /* __RXTX_H__ */
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 3a3fdc5..5369717 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -267,7 +267,6 @@
     pDevice->bUpdateBBVGA = true;
     pDevice->byFOETuning = 0;
     pDevice->byAutoPwrTunning = 0;
-    pDevice->wCTSDuration = 0;
     pDevice->byPreambleType = 0;
     pDevice->bExistSWNetAddr = false;
     /* pDevice->bDiversityRegCtlON = true; */
@@ -734,7 +733,7 @@
 
 static void device_free_tx_bufs(struct vnt_private *pDevice)
 {
-    PUSB_SEND_CONTEXT pTxContext;
+	struct vnt_usb_send_context *pTxContext;
     int ii;
 
     for (ii = 0; ii < pDevice->cbTD; ii++) {
@@ -752,8 +751,8 @@
 
 static void device_free_rx_bufs(struct vnt_private *pDevice)
 {
-    PRCB pRCB;
-    int ii;
+	struct vnt_rcb *pRCB;
+	int ii;
 
     for (ii = 0; ii < pDevice->cbRD; ii++) {
 
@@ -789,14 +788,13 @@
 
 static bool device_alloc_bufs(struct vnt_private *pDevice)
 {
-
-    PUSB_SEND_CONTEXT pTxContext;
-    PRCB pRCB;
-    int ii;
+	struct vnt_usb_send_context *pTxContext;
+	struct vnt_rcb *pRCB;
+	int ii;
 
     for (ii = 0; ii < pDevice->cbTD; ii++) {
 
-        pTxContext = kmalloc(sizeof(USB_SEND_CONTEXT), GFP_KERNEL);
+	pTxContext = kmalloc(sizeof(struct vnt_usb_send_context), GFP_KERNEL);
         if (pTxContext == NULL) {
             DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate tx usb context failed\n", pDevice->dev->name);
             goto free_tx;
@@ -813,7 +811,8 @@
     }
 
     /* allocate RCB mem */
-	pDevice->pRCBMem = kzalloc((sizeof(RCB) * pDevice->cbRD), GFP_KERNEL);
+	pDevice->pRCBMem = kzalloc((sizeof(struct vnt_rcb) * pDevice->cbRD),
+								GFP_KERNEL);
     if (pDevice->pRCBMem == NULL) {
         DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : alloc rx usb context failed\n", pDevice->dev->name);
         goto free_tx;
@@ -824,7 +823,8 @@
     pDevice->FirstRecvMngList = NULL;
     pDevice->LastRecvMngList = NULL;
     pDevice->NumRecvFreeList = 0;
-    pRCB = (PRCB) pDevice->pRCBMem;
+
+	pRCB = (struct vnt_rcb *)pDevice->pRCBMem;
 
     for (ii = 0; ii < pDevice->cbRD; ii++) {
 
@@ -925,7 +925,6 @@
     pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
     if (pDeF->skb == NULL)
         return false;
-    ASSERT(pDeF->skb);
     pDeF->skb->dev = pDevice->dev;
 
     return true;
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index 9bf2f8d..fb743a8 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -52,7 +52,6 @@
 #include "card.h"
 #include "bssdb.h"
 #include "mac.h"
-#include "baseband.h"
 #include "michael.h"
 #include "tkip.h"
 #include "tcrc.h"
@@ -101,13 +100,12 @@
 
 static void s_vGenerateTxParameter(struct vnt_private *pDevice,
 	u8 byPktType, u16 wCurrentRate,	void *pTxBufHead, void *pvRrvTime,
-	void *pvRTS, void *pvCTS, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
-	struct ethhdr *psEthHeader);
+	void *rts_cts, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
+	struct ethhdr *psEthHeader, bool need_rts);
 
 static u32 s_uFillDataHead(struct vnt_private *pDevice,
 	u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength,
-	u32 uDMAIdx, int bNeedAck, u32 uFragIdx, u32 cbLastFragmentSize,
-	u32 uMACfragNum, u8 byFBOption);
+	u32 uDMAIdx, int bNeedAck, u8 byFBOption);
 
 static void s_vGenerateMACHeader(struct vnt_private *pDevice,
 	u8 *pbyBufferAddr, u16 wDuration, struct ethhdr *psEthHeader,
@@ -115,7 +113,7 @@
 
 static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
 	u8 *pbyIVHead, PSKeyItem pTransmitKey, u8 *pbyHdrBuf, u16 wPayloadLen,
-	u8 *pMICHDR);
+	struct vnt_mic_hdr *mic_hdr);
 
 static void s_vSWencryption(struct vnt_private *pDevice,
 	PSKeyItem pTransmitKey, u8 *pbyPayloadHead, u16 wPayloadSize);
@@ -123,30 +121,28 @@
 static unsigned int s_uGetTxRsvTime(struct vnt_private *pDevice, u8 byPktType,
 	u32 cbFrameLength, u16 wRate, int bNeedAck);
 
-static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice, u8 byRTSRsvType,
+static u16 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice, u8 byRTSRsvType,
 	u8 byPktType, u32 cbFrameLength, u16 wCurrentRate);
 
 static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
-	u8 byPktType, void *pvCTS, u32 cbFrameLength, int bNeedAck,
-	int bDisCRC, u16 wCurrentRate, u8 byFBOption);
+	u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength,
+	int bNeedAck, u16 wCurrentRate, u8 byFBOption);
 
 static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
-	void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
+	union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck,
 	struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption);
 
-static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
-	u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
-	u32 uFragIdx, u32 cbLastFragmentSize, u32 uMACfragNum,
-	u8 byFBOption);
+static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+	u8 byPktType, int bNeedAck);
 
-static unsigned int s_uGetRTSCTSDuration(struct vnt_private *pDevice,
+static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice,
 	u8 byDurType, u32 cbFrameLength, u8 byPktType, u16 wRate,
 	int bNeedAck, u8 byFBOption);
 
 static void *s_vGetFreeContext(struct vnt_private *pDevice)
 {
-	PUSB_SEND_CONTEXT pContext = NULL;
-	PUSB_SEND_CONTEXT pReturnContext = NULL;
+	struct vnt_usb_send_context *pContext = NULL;
+	struct vnt_usb_send_context *pReturnContext = NULL;
 	int ii;
 
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GetFreeContext()\n");
@@ -155,6 +151,7 @@
         pContext = pDevice->apTD[ii];
         if (pContext->bBoolInUse == false) {
             pContext->bBoolInUse = true;
+		memset(pContext->Data, 0, MAX_TOTAL_SIZE_WITH_ALL_HEADERS);
             pReturnContext = pContext;
             break;
         }
@@ -186,109 +183,117 @@
 
 static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
 	u8 *pbyIVHead, PSKeyItem pTransmitKey, u8 *pbyHdrBuf,
-	u16 wPayloadLen, u8 *pMICHDR)
+	u16 wPayloadLen, struct vnt_mic_hdr *mic_hdr)
 {
 	u32 *pdwIV = (u32 *)pbyIVHead;
 	u32 *pdwExtIV = (u32 *)((u8 *)pbyIVHead + 4);
-	u16 wValue;
 	struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyHdrBuf;
 	u32 dwRevIVCounter;
 
-    //Fill TXKEY
-    if (pTransmitKey == NULL)
-        return;
+	/* Fill TXKEY */
+	if (pTransmitKey == NULL)
+		return;
 
-    dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter);
-    *pdwIV = pDevice->dwIVCounter;
-    pDevice->byKeyIndex = pTransmitKey->dwKeyIndex & 0xf;
+	dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter);
+	*pdwIV = pDevice->dwIVCounter;
+	pDevice->byKeyIndex = pTransmitKey->dwKeyIndex & 0xf;
 
-    if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
-        if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN ){
-            memcpy(pDevice->abyPRNG, (u8 *)&(dwRevIVCounter), 3);
-            memcpy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
-        } else {
-            memcpy(pbyBuf, (u8 *)&(dwRevIVCounter), 3);
-            memcpy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
-            if(pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
-                memcpy(pbyBuf+8, (u8 *)&(dwRevIVCounter), 3);
-                memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
-            }
-            memcpy(pDevice->abyPRNG, pbyBuf, 16);
-        }
-        // Append IV after Mac Header
-        *pdwIV &= WEP_IV_MASK;//00000000 11111111 11111111 11111111
-	*pdwIV |= (u32)pDevice->byKeyIndex << 30;
-        *pdwIV = cpu_to_le32(*pdwIV);
-        pDevice->dwIVCounter++;
-        if (pDevice->dwIVCounter > WEP_IV_MASK) {
-            pDevice->dwIVCounter = 0;
-        }
-    } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
-        pTransmitKey->wTSC15_0++;
-        if (pTransmitKey->wTSC15_0 == 0) {
-            pTransmitKey->dwTSC47_16++;
-        }
-        TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
-                    pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
-        memcpy(pbyBuf, pDevice->abyPRNG, 16);
-        // Make IV
-        memcpy(pdwIV, pDevice->abyPRNG, 3);
+	switch (pTransmitKey->byCipherSuite) {
+	case KEY_CTL_WEP:
+		if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) {
+			memcpy(pDevice->abyPRNG, (u8 *)&dwRevIVCounter, 3);
+			memcpy(pDevice->abyPRNG + 3, pTransmitKey->abyKey,
+						pTransmitKey->uKeyLength);
+		} else {
+			memcpy(pbyBuf, (u8 *)&dwRevIVCounter, 3);
+			memcpy(pbyBuf + 3, pTransmitKey->abyKey,
+						pTransmitKey->uKeyLength);
+			if (pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
+				memcpy(pbyBuf+8, (u8 *)&dwRevIVCounter, 3);
+			memcpy(pbyBuf+11, pTransmitKey->abyKey,
+						pTransmitKey->uKeyLength);
+			}
 
-        *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
-        // Append IV&ExtIV after Mac Header
-        *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
-	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %x\n",
-		*pdwExtIV);
+			memcpy(pDevice->abyPRNG, pbyBuf, 16);
+		}
+		/* Append IV after Mac Header */
+		*pdwIV &= WEP_IV_MASK;
+		*pdwIV |= (u32)pDevice->byKeyIndex << 30;
+		*pdwIV = cpu_to_le32(*pdwIV);
 
-    } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
-        pTransmitKey->wTSC15_0++;
-        if (pTransmitKey->wTSC15_0 == 0) {
-            pTransmitKey->dwTSC47_16++;
-        }
-        memcpy(pbyBuf, pTransmitKey->abyKey, 16);
+		pDevice->dwIVCounter++;
+		if (pDevice->dwIVCounter > WEP_IV_MASK)
+			pDevice->dwIVCounter = 0;
 
-        // Make IV
-        *pdwIV = 0;
-        *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
-        *pdwIV |= cpu_to_le16((u16)(pTransmitKey->wTSC15_0));
-        //Append IV&ExtIV after Mac Header
-        *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+		break;
+	case KEY_CTL_TKIP:
+		pTransmitKey->wTSC15_0++;
+		if (pTransmitKey->wTSC15_0 == 0)
+			pTransmitKey->dwTSC47_16++;
 
-        //Fill MICHDR0
-        *pMICHDR = 0x59;
-        *((u8 *)(pMICHDR+1)) = 0; // TxPriority
-        memcpy(pMICHDR+2, &(pMACHeader->addr2[0]), 6);
-        *((u8 *)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
-        *((u8 *)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
-        *((u8 *)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
-        *((u8 *)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
-        *((u8 *)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
-        *((u8 *)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
-        *((u8 *)(pMICHDR+14)) = HIBYTE(wPayloadLen);
-        *((u8 *)(pMICHDR+15)) = LOBYTE(wPayloadLen);
+		TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
+			pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16,
+							pDevice->abyPRNG);
+		memcpy(pbyBuf, pDevice->abyPRNG, 16);
 
-        //Fill MICHDR1
-        *((u8 *)(pMICHDR+16)) = 0; // HLEN[15:8]
-        if (pDevice->bLongHeader) {
-            *((u8 *)(pMICHDR+17)) = 28; // HLEN[7:0]
-        } else {
-            *((u8 *)(pMICHDR+17)) = 22; // HLEN[7:0]
-        }
-        wValue = cpu_to_le16(pMACHeader->frame_control & 0xC78F);
-        memcpy(pMICHDR+18, (u8 *)&wValue, 2); // MSKFRACTL
-        memcpy(pMICHDR+20, &(pMACHeader->addr1[0]), 6);
-        memcpy(pMICHDR+26, &(pMACHeader->addr2[0]), 6);
+		/* Make IV */
+		memcpy(pdwIV, pDevice->abyPRNG, 3);
 
-        //Fill MICHDR2
-        memcpy(pMICHDR+32, &(pMACHeader->addr3[0]), 6);
-        wValue = pMACHeader->seq_ctrl;
-        wValue &= 0x000F;
-        wValue = cpu_to_le16(wValue);
-        memcpy(pMICHDR+38, (u8 *)&wValue, 2); // MSKSEQCTL
-        if (pDevice->bLongHeader) {
-            memcpy(pMICHDR+40, &(pMACHeader->addr4[0]), 6);
-        }
-    }
+		*(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) &
+							0xc0) | 0x20);
+		/*  Append IV&ExtIV after Mac Header */
+		*pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+
+		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+			"vFillTxKey()---- pdwExtIV: %x\n", *pdwExtIV);
+
+		break;
+	case KEY_CTL_CCMP:
+		pTransmitKey->wTSC15_0++;
+		if (pTransmitKey->wTSC15_0 == 0)
+			pTransmitKey->dwTSC47_16++;
+
+		memcpy(pbyBuf, pTransmitKey->abyKey, 16);
+
+		/* Make IV */
+		*pdwIV = 0;
+		*(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) &
+							0xc0) | 0x20);
+
+		*pdwIV |= cpu_to_le16((u16)(pTransmitKey->wTSC15_0));
+
+		/* Append IV&ExtIV after Mac Header */
+		*pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+
+		if (!mic_hdr)
+			return;
+
+		/* MICHDR0 */
+		mic_hdr->id = 0x59;
+		mic_hdr->payload_len = cpu_to_be16(wPayloadLen);
+		memcpy(mic_hdr->mic_addr2, pMACHeader->addr2, ETH_ALEN);
+
+		mic_hdr->tsc_47_16 = cpu_to_be32(pTransmitKey->dwTSC47_16);
+		mic_hdr->tsc_15_0 = cpu_to_be16(pTransmitKey->wTSC15_0);
+
+		/* MICHDR1 */
+		if (pDevice->bLongHeader)
+			mic_hdr->hlen = cpu_to_be16(28);
+		else
+			mic_hdr->hlen = cpu_to_be16(22);
+
+		memcpy(mic_hdr->addr1, pMACHeader->addr1, ETH_ALEN);
+		memcpy(mic_hdr->addr2, pMACHeader->addr2, ETH_ALEN);
+
+		/* MICHDR2 */
+		memcpy(mic_hdr->addr3, pMACHeader->addr3, ETH_ALEN);
+		mic_hdr->frame_control = cpu_to_le16(pMACHeader->frame_control
+								& 0xc78f);
+		mic_hdr->seq_ctrl = cpu_to_le16(pMACHeader->seq_ctrl & 0xf);
+
+		if (pDevice->bLongHeader)
+			memcpy(mic_hdr->addr4, pMACHeader->addr4, ETH_ALEN);
+	}
 }
 
 static void s_vSWencryption(struct vnt_private *pDevice,
@@ -326,6 +331,12 @@
     }
 }
 
+static u16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate)
+{
+	return cpu_to_le16(wTimeStampOff[priv->byPreambleType % 2]
+							[rate % MAX_RATE]);
+}
+
 /*byPktType : PK_TYPE_11A     0
              PK_TYPE_11B     1
              PK_TYPE_11GB    2
@@ -351,8 +362,15 @@
     }
 }
 
+static u16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type,
+	u32 frame_length, u16 rate, int need_ack)
+{
+	return cpu_to_le16((u16)s_uGetTxRsvTime(priv, pkt_type,
+		frame_length, rate, need_ack));
+}
+
 //byFreqType: 0=>5GHZ 1=>2.4GHZ
-static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
+static u16 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
 	u8 byRTSRsvType, u8 byPktType, u32 cbFrameLength, u16 wCurrentRate)
 {
 	u32 uRrvTime, uRTSTime, uCTSTime, uAckTime, uDataTime;
@@ -382,168 +400,30 @@
 
     //RTSRrvTime
     uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3*pDevice->uSIFS;
-    return uRrvTime;
+	return cpu_to_le16((u16)uRrvTime);
 }
 
 //byFreqType 0: 5GHz, 1:2.4Ghz
-static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
-	u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
-	u32 uFragIdx, u32 cbLastFragmentSize, u32 uMACfragNum,
-	u8 byFBOption)
+static u16 s_uGetDataDuration(struct vnt_private *pDevice,
+					u8 byPktType, int bNeedAck)
 {
-	int bLastFrag = 0;
-	u32 uAckTime = 0, uNextPktTime = 0;
+	u32 uAckTime = 0;
 
-    if (uFragIdx == (uMACfragNum-1)) {
-        bLastFrag = 1;
-    }
+	if (bNeedAck) {
+		if (byPktType == PK_TYPE_11B)
+			uAckTime = BBuGetFrameTime(pDevice->byPreambleType,
+				byPktType, 14, pDevice->byTopCCKBasicRate);
+		else
+			uAckTime = BBuGetFrameTime(pDevice->byPreambleType,
+				byPktType, 14, pDevice->byTopOFDMBasicRate);
+		return cpu_to_le16((u16)(pDevice->uSIFS + uAckTime));
+	}
 
-    switch (byDurType) {
-
-    case DATADUR_B:    //DATADUR_B
-        if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
-            if (bNeedAck) {
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
-                return (pDevice->uSIFS + uAckTime);
-            } else {
-                return 0;
-            }
-        }
-        else {//First Frag or Mid Frag
-            if (uFragIdx == (uMACfragNum-2)) {
-            	uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
-            } else {
-                uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
-            }
-            if (bNeedAck) {
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
-                return (pDevice->uSIFS + uAckTime + uNextPktTime);
-            } else {
-                return (pDevice->uSIFS + uNextPktTime);
-            }
-        }
-        break;
-
-    case DATADUR_A:    //DATADUR_A
-        if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
-            if(bNeedAck){
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
-                return (pDevice->uSIFS + uAckTime);
-            } else {
-                return 0;
-            }
-        }
-        else {//First Frag or Mid Frag
-            if(uFragIdx == (uMACfragNum-2)){
-            	uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
-            } else {
-                uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
-            }
-            if(bNeedAck){
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
-                return (pDevice->uSIFS + uAckTime + uNextPktTime);
-            } else {
-                return (pDevice->uSIFS + uNextPktTime);
-            }
-        }
-        break;
-
-    case DATADUR_A_F0:    //DATADUR_A_F0
-	    if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
-            if(bNeedAck){
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
-                return (pDevice->uSIFS + uAckTime);
-            } else {
-                return 0;
-            }
-        }
-	    else { //First Frag or Mid Frag
-	        if (byFBOption == AUTO_FB_0) {
-                if (wRate < RATE_18M)
-                    wRate = RATE_18M;
-                else if (wRate > RATE_54M)
-                    wRate = RATE_54M;
-
-	            if(uFragIdx == (uMACfragNum-2)){
-            	    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
-                } else {
-                    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
-                }
-	        } else { // (byFBOption == AUTO_FB_1)
-                if (wRate < RATE_18M)
-                    wRate = RATE_18M;
-                else if (wRate > RATE_54M)
-                    wRate = RATE_54M;
-
-	            if(uFragIdx == (uMACfragNum-2)){
-            	    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
-                } else {
-                    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
-                }
-	        }
-
-	        if(bNeedAck){
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
-                return (pDevice->uSIFS + uAckTime + uNextPktTime);
-            } else {
-                return (pDevice->uSIFS + uNextPktTime);
-            }
-	    }
-        break;
-
-    case DATADUR_A_F1:    //DATADUR_A_F1
-        if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
-            if(bNeedAck){
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
-                return (pDevice->uSIFS + uAckTime);
-            } else {
-                return 0;
-            }
-        }
-	    else { //First Frag or Mid Frag
-	        if (byFBOption == AUTO_FB_0) {
-                if (wRate < RATE_18M)
-                    wRate = RATE_18M;
-                else if (wRate > RATE_54M)
-                    wRate = RATE_54M;
-
-	            if(uFragIdx == (uMACfragNum-2)){
-            	    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
-                } else {
-                    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
-                }
-
-	        } else { // (byFBOption == AUTO_FB_1)
-                if (wRate < RATE_18M)
-                    wRate = RATE_18M;
-                else if (wRate > RATE_54M)
-                    wRate = RATE_54M;
-
-	            if(uFragIdx == (uMACfragNum-2)){
-            	    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
-                } else {
-                    uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
-                }
-	        }
-	        if(bNeedAck){
-            	uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
-                return (pDevice->uSIFS + uAckTime + uNextPktTime);
-            } else {
-                return (pDevice->uSIFS + uNextPktTime);
-            }
-	    }
-        break;
-
-    default:
-        break;
-    }
-
-	ASSERT(false);
 	return 0;
 }
 
 //byFreqType: 0=>5GHZ 1=>2.4GHZ
-static u32 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
+static u16 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
 	u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
 	u8 byFBOption)
 {
@@ -626,14 +506,12 @@
         break;
     }
 
-    return uDurTime;
-
+	return cpu_to_le16((u16)uDurTime);
 }
 
 static u32 s_uFillDataHead(struct vnt_private *pDevice,
 	u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength,
-	u32 uDMAIdx, int bNeedAck, u32 uFragIdx, u32 cbLastFragmentSize,
-	u32 uMACfragNum, u8 byFBOption)
+	u32 uDMAIdx, int bNeedAck, u8 byFBOption)
 {
 
     if (pTxDataHead == NULL) {
@@ -641,409 +519,301 @@
     }
 
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-	if ((uDMAIdx == TYPE_ATIMDMA) || (uDMAIdx == TYPE_BEACONDMA)) {
-		PSTxDataHead_ab pBuf = (PSTxDataHead_ab) pTxDataHead;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
-                (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-            );
-            //Get Duration and TimeStampOff
-            pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
-                                                       wCurrentRate, bNeedAck, uFragIdx,
-                                                       cbLastFragmentSize, uMACfragNum,
-                                                       byFBOption); //1: 2.4GHz
-            if(uDMAIdx!=TYPE_ATIMDMA) {
-                pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-            }
-            return (pBuf->wDuration);
-        }
-        else { // DATA & MANAGE Frame
             if (byFBOption == AUTO_FB_NONE) {
-                PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
+		struct vnt_tx_datahead_g *pBuf =
+				(struct vnt_tx_datahead_g *)pTxDataHead;
                 //Get SignalField,ServiceField,Length
-                BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
-                    (u16 *)&(pBuf->wTransmitLength_a), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
-                );
-                BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-                    (u16 *)&(pBuf->wTransmitLength_b), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
-                );
+		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+			byPktType, &pBuf->a);
+		BBvCalculateParameter(pDevice, cbFrameLength,
+			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
                 //Get Duration and TimeStamp
-                pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
-                                                             byPktType, wCurrentRate, bNeedAck, uFragIdx,
-                                                             cbLastFragmentSize, uMACfragNum,
-                                                             byFBOption); //1: 2.4GHz
-                pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
-                                                             PK_TYPE_11B, pDevice->byTopCCKBasicRate,
-                                                             bNeedAck, uFragIdx, cbLastFragmentSize,
-                                                             uMACfragNum, byFBOption); //1: 2.4GHz
+		pBuf->wDuration_a = s_uGetDataDuration(pDevice,
+							byPktType, bNeedAck);
+		pBuf->wDuration_b = s_uGetDataDuration(pDevice,
+							PK_TYPE_11B, bNeedAck);
 
-                pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-                pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
+		pBuf->wTimeStampOff_a =	vnt_time_stamp_off(pDevice,
+								wCurrentRate);
+		pBuf->wTimeStampOff_b = vnt_time_stamp_off(pDevice,
+						pDevice->byTopCCKBasicRate);
                 return (pBuf->wDuration_a);
              } else {
                 // Auto Fallback
-                PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
+		struct vnt_tx_datahead_g_fb *pBuf =
+			(struct vnt_tx_datahead_g_fb *)pTxDataHead;
                 //Get SignalField,ServiceField,Length
-                BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
-                    (u16 *)&(pBuf->wTransmitLength_a), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
-                );
-                BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-                    (u16 *)&(pBuf->wTransmitLength_b), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
-                );
+		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+			byPktType, &pBuf->a);
+		BBvCalculateParameter(pDevice, cbFrameLength,
+			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
                 //Get Duration and TimeStamp
-                pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
-                                             wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
-                pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
-                                             pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
-                pBuf->wDuration_a_f0 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
-                                             wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
-                pBuf->wDuration_a_f1 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
-                                             wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
-                pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-                pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
+		pBuf->wDuration_a = s_uGetDataDuration(pDevice,
+							byPktType, bNeedAck);
+		pBuf->wDuration_b = s_uGetDataDuration(pDevice,
+							PK_TYPE_11B, bNeedAck);
+		pBuf->wDuration_a_f0 = s_uGetDataDuration(pDevice,
+							byPktType, bNeedAck);
+		pBuf->wDuration_a_f1 = s_uGetDataDuration(pDevice,
+							byPktType, bNeedAck);
+		pBuf->wTimeStampOff_a = vnt_time_stamp_off(pDevice,
+								wCurrentRate);
+		pBuf->wTimeStampOff_b = vnt_time_stamp_off(pDevice,
+						pDevice->byTopCCKBasicRate);
                 return (pBuf->wDuration_a);
             } //if (byFBOption == AUTO_FB_NONE)
-        }
     }
     else if (byPktType == PK_TYPE_11A) {
-        if ((byFBOption != AUTO_FB_NONE) && (uDMAIdx != TYPE_ATIMDMA) && (uDMAIdx != TYPE_BEACONDMA)) {
-            // Auto Fallback
-            PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
+	if (byFBOption != AUTO_FB_NONE) {
+		struct vnt_tx_datahead_a_fb *pBuf =
+			(struct vnt_tx_datahead_a_fb *)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
-                (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-            );
+		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+			byPktType, &pBuf->a);
             //Get Duration and TimeStampOff
-            pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
-                                        wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
-            pBuf->wDuration_f0 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
-                                        wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
-            pBuf->wDuration_f1 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
-                                        wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
-            if(uDMAIdx!=TYPE_ATIMDMA) {
-                pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-            }
+		pBuf->wDuration = s_uGetDataDuration(pDevice,
+					byPktType, bNeedAck);
+		pBuf->wDuration_f0 = s_uGetDataDuration(pDevice,
+					byPktType, bNeedAck);
+		pBuf->wDuration_f1 = s_uGetDataDuration(pDevice,
+							byPktType, bNeedAck);
+		pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice,
+								wCurrentRate);
             return (pBuf->wDuration);
         } else {
-            PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
+		struct vnt_tx_datahead_ab *pBuf =
+			(struct vnt_tx_datahead_ab *)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
-                (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-            );
+		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+			byPktType, &pBuf->ab);
             //Get Duration and TimeStampOff
-            pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
-                                                       wCurrentRate, bNeedAck, uFragIdx,
-                                                       cbLastFragmentSize, uMACfragNum,
-                                                       byFBOption);
-
-            if(uDMAIdx!=TYPE_ATIMDMA) {
-                pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-            }
+		pBuf->wDuration = s_uGetDataDuration(pDevice,
+				byPktType, bNeedAck);
+		pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice,
+								wCurrentRate);
             return (pBuf->wDuration);
         }
     }
     else if (byPktType == PK_TYPE_11B) {
-            PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
+		struct vnt_tx_datahead_ab *pBuf =
+			(struct vnt_tx_datahead_ab *)pTxDataHead;
             //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
-                (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-            );
+		BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate,
+			byPktType, &pBuf->ab);
             //Get Duration and TimeStampOff
-            pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
-                                                       wCurrentRate, bNeedAck, uFragIdx,
-                                                       cbLastFragmentSize, uMACfragNum,
-                                                       byFBOption);
-            if (uDMAIdx != TYPE_ATIMDMA) {
-                pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-            }
+		pBuf->wDuration = s_uGetDataDuration(pDevice,
+				byPktType, bNeedAck);
+		pBuf->wTimeStampOff = vnt_time_stamp_off(pDevice,
+								wCurrentRate);
             return (pBuf->wDuration);
     }
     return 0;
 }
 
+static int vnt_fill_ieee80211_rts(struct vnt_private *priv,
+	struct ieee80211_rts *rts, struct ethhdr *eth_hdr,
+		u16 duration)
+{
+	rts->duration = duration;
+	rts->frame_control = TYPE_CTL_RTS;
+
+	if (priv->eOPMode == OP_MODE_ADHOC || priv->eOPMode == OP_MODE_AP)
+		memcpy(rts->ra, eth_hdr->h_dest, ETH_ALEN);
+	else
+		memcpy(rts->ra, priv->abyBSSID, ETH_ALEN);
+
+	if (priv->eOPMode == OP_MODE_AP)
+		memcpy(rts->ta, priv->abyBSSID, ETH_ALEN);
+	else
+		memcpy(rts->ta, eth_hdr->h_source, ETH_ALEN);
+
+	return 0;
+}
+
+static int vnt_rxtx_rts_g_head(struct vnt_private *priv,
+	struct vnt_rts_g *buf, struct ethhdr *eth_hdr,
+	u8 pkt_type, u32 frame_len, int need_ack,
+	u16 current_rate, u8 fb_option)
+{
+	u16 rts_frame_len = 20;
+
+	BBvCalculateParameter(priv, rts_frame_len, priv->byTopCCKBasicRate,
+		PK_TYPE_11B, &buf->b);
+	BBvCalculateParameter(priv, rts_frame_len,
+		priv->byTopOFDMBasicRate, pkt_type, &buf->a);
+
+	buf->wDuration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
+		PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack, fb_option);
+	buf->wDuration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+		pkt_type, current_rate, need_ack, fb_option);
+	buf->wDuration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
+		pkt_type, current_rate, need_ack, fb_option);
+
+	vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa);
+
+	return 0;
+}
+
+static int vnt_rxtx_rts_g_fb_head(struct vnt_private *priv,
+	struct vnt_rts_g_fb *buf, struct ethhdr *eth_hdr,
+	u8 pkt_type, u32 frame_len, int need_ack,
+	u16 current_rate, u8 fb_option)
+{
+	u16 rts_frame_len = 20;
+
+	BBvCalculateParameter(priv, rts_frame_len, priv->byTopCCKBasicRate,
+		PK_TYPE_11B, &buf->b);
+	BBvCalculateParameter(priv, rts_frame_len,
+		priv->byTopOFDMBasicRate, pkt_type, &buf->a);
+
+
+	buf->wDuration_bb = s_uGetRTSCTSDuration(priv, RTSDUR_BB, frame_len,
+		PK_TYPE_11B, priv->byTopCCKBasicRate, need_ack, fb_option);
+	buf->wDuration_aa = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+		pkt_type, current_rate, need_ack, fb_option);
+	buf->wDuration_ba = s_uGetRTSCTSDuration(priv, RTSDUR_BA, frame_len,
+		pkt_type, current_rate, need_ack, fb_option);
+
+
+	buf->wRTSDuration_ba_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F0,
+		frame_len, pkt_type, current_rate, need_ack, fb_option);
+	buf->wRTSDuration_aa_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
+		frame_len, pkt_type, current_rate, need_ack, fb_option);
+	buf->wRTSDuration_ba_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_BA_F1,
+		frame_len, pkt_type, current_rate, need_ack, fb_option);
+	buf->wRTSDuration_aa_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
+		frame_len, pkt_type, current_rate, need_ack, fb_option);
+
+	vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration_aa);
+
+	return 0;
+}
+
+static int vnt_rxtx_rts_ab_head(struct vnt_private *priv,
+	struct vnt_rts_ab *buf, struct ethhdr *eth_hdr,
+	u8 pkt_type, u32 frame_len, int need_ack,
+	u16 current_rate, u8 fb_option)
+{
+	u16 rts_frame_len = 20;
+
+	BBvCalculateParameter(priv, rts_frame_len,
+		priv->byTopOFDMBasicRate, pkt_type, &buf->ab);
+
+	buf->wDuration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+		pkt_type, current_rate, need_ack, fb_option);
+
+	vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration);
+
+	return 0;
+}
+
+static int vnt_rxtx_rts_a_fb_head(struct vnt_private *priv,
+	struct vnt_rts_a_fb *buf, struct ethhdr *eth_hdr,
+	u8 pkt_type, u32 frame_len, int need_ack,
+	u16 current_rate, u8 fb_option)
+{
+	u16 rts_frame_len = 20;
+
+	BBvCalculateParameter(priv, rts_frame_len,
+		priv->byTopOFDMBasicRate, pkt_type, &buf->a);
+
+	buf->wDuration = s_uGetRTSCTSDuration(priv, RTSDUR_AA, frame_len,
+		pkt_type, current_rate, need_ack, fb_option);
+
+	buf->wRTSDuration_f0 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F0,
+		frame_len, pkt_type, current_rate, need_ack, fb_option);
+
+	buf->wRTSDuration_f1 = s_uGetRTSCTSDuration(priv, RTSDUR_AA_F1,
+		frame_len, pkt_type, current_rate, need_ack, fb_option);
+
+	vnt_fill_ieee80211_rts(priv, &buf->data, eth_hdr, buf->wDuration);
+
+	return 0;
+}
+
 static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
-	void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
+	union vnt_tx_data_head *head, u32 cbFrameLength, int bNeedAck,
 	struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption)
 {
-	u32 uRTSFrameLen = 20;
-	u16 wLen = 0;
 
-    if (pvRTS == NULL)
-    	return;
+	if (!head)
+		return;
 
-    if (bDisCRC) {
-        // When CRCDIS bit is on, H/W forgot to generate FCS for RTS frame,
-        // in this case we need to decrease its length by 4.
-        uRTSFrameLen -= 4;
-    }
-
-    // Note: So far RTSHead doesn't appear in ATIM & Beacom DMA, so we don't need to take them into account.
-    //       Otherwise, we need to modified codes for them.
-    if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-        if (byFBOption == AUTO_FB_NONE) {
-            PSRTS_g pBuf = (PSRTS_g)pvRTS;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
-            );
-            pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
-            );
-            pBuf->wTransmitLength_a = cpu_to_le16(wLen);
-            //Get Duration
-            pBuf->wDuration_bb = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption));    //0:RTSDuration_bb, 1:2.4G, 1:CCKData
-            pBuf->wDuration_aa = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
-            pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
-
-            pBuf->Data.wDurationID = pBuf->wDuration_aa;
-            //Get RTS Frame body
-            pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
-	if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
-	    (pDevice->eOPMode == OP_MODE_AP)) {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(psEthHeader->h_dest[0]),
-		       ETH_ALEN);
+	/* Note: So far RTSHead doesn't appear in ATIM
+	*	& Beacom DMA, so we don't need to take them
+	*	into account.
+	*	Otherwise, we need to modified codes for them.
+	*/
+	switch (byPktType) {
+	case PK_TYPE_11GB:
+	case PK_TYPE_11GA:
+		if (byFBOption == AUTO_FB_NONE)
+			vnt_rxtx_rts_g_head(pDevice, &head->rts_g,
+				psEthHeader, byPktType, cbFrameLength,
+				bNeedAck, wCurrentRate, byFBOption);
+		else
+			vnt_rxtx_rts_g_fb_head(pDevice, &head->rts_g_fb,
+				psEthHeader, byPktType, cbFrameLength,
+				bNeedAck, wCurrentRate, byFBOption);
+		break;
+	case PK_TYPE_11A:
+		if (byFBOption) {
+			vnt_rxtx_rts_a_fb_head(pDevice, &head->rts_a_fb,
+				psEthHeader, byPktType, cbFrameLength,
+				bNeedAck, wCurrentRate, byFBOption);
+			break;
+		}
+	case PK_TYPE_11B:
+		vnt_rxtx_rts_ab_head(pDevice, &head->rts_ab,
+			psEthHeader, byPktType, cbFrameLength,
+			bNeedAck, wCurrentRate, byFBOption);
 	}
-            else {
-		    memcpy(&(pBuf->Data.abyRA[0]),
-			   &(pDevice->abyBSSID[0]),
-			   ETH_ALEN);
-	    }
-	if (pDevice->eOPMode == OP_MODE_AP) {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	}
-            else {
-		    memcpy(&(pBuf->Data.abyTA[0]),
-			   &(psEthHeader->h_source[0]),
-			   ETH_ALEN);
-            }
-        }
-        else {
-           PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
-            );
-            pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
-            );
-            pBuf->wTransmitLength_a = cpu_to_le16(wLen);
-            //Get Duration
-            pBuf->wDuration_bb = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption));    //0:RTSDuration_bb, 1:2.4G, 1:CCKData
-            pBuf->wDuration_aa = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
-            pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
-            pBuf->wRTSDuration_ba_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption));    //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
-            pBuf->wRTSDuration_aa_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption));    //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
-            pBuf->wRTSDuration_ba_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption));    //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
-            pBuf->wRTSDuration_aa_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption));    //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
-            pBuf->Data.wDurationID = pBuf->wDuration_aa;
-            //Get RTS Frame body
-            pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
-	if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
-	    (pDevice->eOPMode == OP_MODE_AP)) {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(psEthHeader->h_dest[0]),
-		       ETH_ALEN);
-	}
-            else {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-            }
-
-	if (pDevice->eOPMode == OP_MODE_AP) {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	}
-            else {
-		    memcpy(&(pBuf->Data.abyTA[0]),
-			   &(psEthHeader->h_source[0]),
-			   ETH_ALEN);
-            }
-
-        } // if (byFBOption == AUTO_FB_NONE)
-    }
-    else if (byPktType == PK_TYPE_11A) {
-        if (byFBOption == AUTO_FB_NONE) {
-            PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-            );
-            pBuf->wTransmitLength = cpu_to_le16(wLen);
-            //Get Duration
-            pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
-    	    pBuf->Data.wDurationID = pBuf->wDuration;
-            //Get RTS Frame body
-            pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
-	if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
-	    (pDevice->eOPMode == OP_MODE_AP)) {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(psEthHeader->h_dest[0]),
-		       ETH_ALEN);
-	} else {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	}
-
-	if (pDevice->eOPMode == OP_MODE_AP) {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	} else {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(psEthHeader->h_source[0]),
-		       ETH_ALEN);
-	}
-
-        }
-        else {
-            PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-            );
-            pBuf->wTransmitLength = cpu_to_le16(wLen);
-            //Get Duration
-            pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
-    	    pBuf->wRTSDuration_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
-    	    pBuf->wRTSDuration_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
-    	    pBuf->Data.wDurationID = pBuf->wDuration;
-    	    //Get RTS Frame body
-            pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
-	if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
-	    (pDevice->eOPMode == OP_MODE_AP)) {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(psEthHeader->h_dest[0]),
-		       ETH_ALEN);
-	} else {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	}
-	if (pDevice->eOPMode == OP_MODE_AP) {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	} else {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(psEthHeader->h_source[0]),
-		       ETH_ALEN);
-	}
-        }
-    }
-    else if (byPktType == PK_TYPE_11B) {
-        PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
-        //Get SignalField,ServiceField,Length
-        BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-            (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
-        );
-        pBuf->wTransmitLength = cpu_to_le16(wLen);
-        //Get Duration
-        pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
-        pBuf->Data.wDurationID = pBuf->wDuration;
-        //Get RTS Frame body
-        pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
-	if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
-            (pDevice->eOPMode == OP_MODE_AP)) {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(psEthHeader->h_dest[0]),
-		       ETH_ALEN);
-        }
-        else {
-		memcpy(&(pBuf->Data.abyRA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-        }
-
-        if (pDevice->eOPMode == OP_MODE_AP) {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(pDevice->abyBSSID[0]),
-		       ETH_ALEN);
-	} else {
-		memcpy(&(pBuf->Data.abyTA[0]),
-		       &(psEthHeader->h_source[0]),
-		       ETH_ALEN);
-        }
-    }
 }
 
 static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
-	u8 byPktType, void *pvCTS, u32 cbFrameLength, int bNeedAck,
-	int bDisCRC, u16 wCurrentRate, u8 byFBOption)
+	u8 byPktType, union vnt_tx_data_head *head, u32 cbFrameLength,
+	int bNeedAck, u16 wCurrentRate, u8 byFBOption)
 {
 	u32 uCTSFrameLen = 14;
-	u16 wLen = 0;
 
-    if (pvCTS == NULL) {
-        return;
-    }
+	if (!head)
+		return;
 
-    if (bDisCRC) {
-        // When CRCDIS bit is on, H/W forgot to generate FCS for CTS frame,
-        // in this case we need to decrease its length by 4.
-        uCTSFrameLen -= 4;
-    }
-
-    if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-        if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) {
-            // Auto Fall back
-            PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
-            );
-            pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            pBuf->wDuration_ba = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
-            pBuf->wDuration_ba += pDevice->wCTSDuration;
-            pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
-            //Get CTSDuration_ba_f0
-            pBuf->wCTSDuration_ba_f0 = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
-            pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration;
-            pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0);
-            //Get CTSDuration_ba_f1
-            pBuf->wCTSDuration_ba_f1 = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
-            pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration;
-            pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1);
-            //Get CTS Frame body
-            pBuf->Data.wDurationID = pBuf->wDuration_ba;
-            pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
-            pBuf->Data.wReserved = 0x0000;
-	memcpy(&(pBuf->Data.abyRA[0]),
-	       &(pDevice->abyCurrentNetAddr[0]),
-	       ETH_ALEN);
-        } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA)
-            PSCTS pBuf = (PSCTS)pvCTS;
-            //Get SignalField,ServiceField,Length
-            BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
-                (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
-            );
-            pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-            //Get CTSDuration_ba
-            pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
-            pBuf->wDuration_ba += pDevice->wCTSDuration;
-            pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
-
-            //Get CTS Frame body
-            pBuf->Data.wDurationID = pBuf->wDuration_ba;
-            pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
-            pBuf->Data.wReserved = 0x0000;
-	memcpy(&(pBuf->Data.abyRA[0]),
-	       &(pDevice->abyCurrentNetAddr[0]),
-	       ETH_ALEN);
+	if (byFBOption != AUTO_FB_NONE) {
+		/* Auto Fall back */
+		struct vnt_cts_fb *pBuf = &head->cts_g_fb;
+		/* Get SignalField,ServiceField,Length */
+		BBvCalculateParameter(pDevice, uCTSFrameLen,
+			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
+		pBuf->wDuration_ba = s_uGetRTSCTSDuration(pDevice, CTSDUR_BA,
+			cbFrameLength, byPktType,
+			wCurrentRate, bNeedAck, byFBOption);
+		/* Get CTSDuration_ba_f0 */
+		pBuf->wCTSDuration_ba_f0 = s_uGetRTSCTSDuration(pDevice,
+			CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate,
+			bNeedAck, byFBOption);
+		/* Get CTSDuration_ba_f1 */
+		pBuf->wCTSDuration_ba_f1 = s_uGetRTSCTSDuration(pDevice,
+			CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate,
+			bNeedAck, byFBOption);
+		/* Get CTS Frame body */
+		pBuf->data.duration = pBuf->wDuration_ba;
+		pBuf->data.frame_control = TYPE_CTL_CTS;
+		memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN);
+	} else {
+		struct vnt_cts *pBuf = &head->cts_g;
+		/* Get SignalField,ServiceField,Length */
+		BBvCalculateParameter(pDevice, uCTSFrameLen,
+			pDevice->byTopCCKBasicRate, PK_TYPE_11B, &pBuf->b);
+		/* Get CTSDuration_ba */
+		pBuf->wDuration_ba = s_uGetRTSCTSDuration(pDevice,
+			CTSDUR_BA, cbFrameLength, byPktType,
+			wCurrentRate, bNeedAck, byFBOption);
+		/*Get CTS Frame body*/
+		pBuf->data.duration = pBuf->wDuration_ba;
+		pBuf->data.frame_control = TYPE_CTL_CTS;
+		memcpy(pBuf->data.ra, pDevice->abyCurrentNetAddr, ETH_ALEN);
         }
-    }
 }
 
 /*+
@@ -1071,12 +841,12 @@
 
 static void s_vGenerateTxParameter(struct vnt_private *pDevice,
 	u8 byPktType, u16 wCurrentRate,	void *pTxBufHead, void *pvRrvTime,
-	void *pvRTS, void *pvCTS, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
-	struct ethhdr *psEthHeader)
+	void *rts_cts, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
+	struct ethhdr *psEthHeader, bool need_rts)
 {
+	union vnt_tx_data_head *head = rts_cts;
 	u32 cbMACHdLen = WLAN_HDR_ADDR3_LEN; /* 24 */
 	u16 wFifoCtl;
-	int bDisCRC = false;
 	u8 byFBOption = AUTO_FB_NONE;
 
     //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter...\n");
@@ -1084,10 +854,6 @@
     pFifoHead->wReserved = wCurrentRate;
     wFifoCtl = pFifoHead->wFIFOCtl;
 
-    if (wFifoCtl & FIFOCTL_CRCDIS) {
-        bDisCRC = true;
-    }
-
     if (wFifoCtl & FIFOCTL_AUTO_FB_0) {
         byFBOption = AUTO_FB_0;
     }
@@ -1095,75 +861,87 @@
         byFBOption = AUTO_FB_1;
     }
 
+	if (!pvRrvTime)
+		return;
+
     if (pDevice->bLongHeader)
         cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
 
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-
-        if (pvRTS != NULL) { //RTS_need
+	if (need_rts) {
             //Fill RsvTime
-            if (pvRrvTime) {
-                PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime;
-                pBuf->wRTSTxRrvTime_aa = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
-                pBuf->wRTSTxRrvTime_ba = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
-                pBuf->wRTSTxRrvTime_bb = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
-                pBuf->wTxRrvTime_a = cpu_to_le16((u16) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
-                pBuf->wTxRrvTime_b = cpu_to_le16((u16) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
-            }
-            //Fill RTS
-            s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+		struct vnt_rrv_time_rts *pBuf =
+			(struct vnt_rrv_time_rts *)pvRrvTime;
+		pBuf->wRTSTxRrvTime_aa = s_uGetRTSCTSRsvTime(pDevice, 2,
+				byPktType, cbFrameSize, wCurrentRate);
+		pBuf->wRTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 1,
+				byPktType, cbFrameSize, wCurrentRate);
+		pBuf->wRTSTxRrvTime_bb = s_uGetRTSCTSRsvTime(pDevice, 0,
+				byPktType, cbFrameSize, wCurrentRate);
+		pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice,
+			byPktType, cbFrameSize, wCurrentRate, bNeedACK);
+		pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice,
+			PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate,
+				bNeedACK);
+		/* Fill RTS */
+		s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize,
+			bNeedACK, psEthHeader, wCurrentRate, byFBOption);
         }
         else {//RTS_needless, PCF mode
-
             //Fill RsvTime
-            if (pvRrvTime) {
-                PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime;
-                pBuf->wTxRrvTime_a = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
-                pBuf->wTxRrvTime_b = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
-                pBuf->wCTSTxRrvTime_ba = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
-            }
-            //Fill CTS
-            s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption);
+		struct vnt_rrv_time_cts *pBuf =
+				(struct vnt_rrv_time_cts *)pvRrvTime;
+		pBuf->wTxRrvTime_a = vnt_rxtx_rsvtime_le16(pDevice, byPktType,
+			cbFrameSize, wCurrentRate, bNeedACK);
+		pBuf->wTxRrvTime_b = vnt_rxtx_rsvtime_le16(pDevice,
+			PK_TYPE_11B, cbFrameSize,
+			pDevice->byTopCCKBasicRate, bNeedACK);
+		pBuf->wCTSTxRrvTime_ba = s_uGetRTSCTSRsvTime(pDevice, 3,
+				byPktType, cbFrameSize, wCurrentRate);
+		/* Fill CTS */
+		s_vFillCTSHead(pDevice, uDMAIdx, byPktType, head,
+			cbFrameSize, bNeedACK, wCurrentRate, byFBOption);
         }
     }
     else if (byPktType == PK_TYPE_11A) {
-
-        if (pvRTS != NULL) {//RTS_need, non PCF mode
+	if (need_rts) {
             //Fill RsvTime
-            if (pvRrvTime) {
-                PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
-                pBuf->wRTSTxRrvTime = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
-                pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
-            }
-            //Fill RTS
-            s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
-        }
-        else if (pvRTS == NULL) {//RTS_needless, non PCF mode
+		struct vnt_rrv_time_ab *pBuf =
+				(struct vnt_rrv_time_ab *)pvRrvTime;
+		pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 2,
+				byPktType, cbFrameSize, wCurrentRate);
+		pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, byPktType,
+				cbFrameSize, wCurrentRate, bNeedACK);
+		/* Fill RTS */
+		s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize,
+			bNeedACK, psEthHeader, wCurrentRate, byFBOption);
+	} else {
             //Fill RsvTime
-            if (pvRrvTime) {
-                PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
-                pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
-            }
+		struct vnt_rrv_time_ab *pBuf =
+				(struct vnt_rrv_time_ab *)pvRrvTime;
+		pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11A,
+			cbFrameSize, wCurrentRate, bNeedACK);
         }
     }
     else if (byPktType == PK_TYPE_11B) {
-
-        if ((pvRTS != NULL)) {//RTS_need, non PCF mode
+	if (need_rts) {
             //Fill RsvTime
-            if (pvRrvTime) {
-                PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
-                pBuf->wRTSTxRrvTime = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
-                pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
-            }
-            //Fill RTS
-            s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+		struct vnt_rrv_time_ab *pBuf =
+				(struct vnt_rrv_time_ab *)pvRrvTime;
+		pBuf->wRTSTxRrvTime = s_uGetRTSCTSRsvTime(pDevice, 0,
+				byPktType, cbFrameSize, wCurrentRate);
+		pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B,
+				cbFrameSize, wCurrentRate, bNeedACK);
+		/* Fill RTS */
+		s_vFillRTSHead(pDevice, byPktType, head, cbFrameSize,
+			bNeedACK, psEthHeader, wCurrentRate, byFBOption);
         }
         else { //RTS_needless, non PCF mode
             //Fill RsvTime
-            if (pvRrvTime) {
-                PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
-                pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
-            }
+		struct vnt_rrv_time_ab *pBuf =
+				(struct vnt_rrv_time_ab *)pvRrvTime;
+		pBuf->wTxRrvTime = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B,
+			cbFrameSize, wCurrentRate, bNeedACK);
         }
     }
     //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n");
@@ -1175,17 +953,18 @@
 */
 
 static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
-	u8 *usbPacketBuf, int bNeedEncryption, u32 uSkbPacketLen, u32 uDMAIdx,
-	struct ethhdr *psEthHeader, u8 *pPacket, PSKeyItem pTransmitKey,
-	u32 uNodeIndex, u16 wCurrentRate, u32 *pcbHeaderLen, u32 *pcbTotalLen)
+	struct vnt_tx_buffer *pTxBufHead, int bNeedEncryption,
+	u32 uSkbPacketLen, u32 uDMAIdx,	struct ethhdr *psEthHeader,
+	u8 *pPacket, PSKeyItem pTransmitKey, u32 uNodeIndex, u16 wCurrentRate,
+	u32 *pcbHeaderLen, u32 *pcbTotalLen)
 {
 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
 	u32 cbFrameSize, cbFrameBodySize;
-	PTX_BUFFER pTxBufHead;
 	u32 cb802_1_H_len;
 	u32 cbIVlen = 0, cbICVlen = 0, cbMIClen = 0, cbMACHdLen = 0;
 	u32 cbFCSlen = 4, cbMICHDR = 0;
-	int bNeedACK, bRTS;
+	int bNeedACK;
+	bool bRTS = false;
 	u8 *pbyType, *pbyMacHdr, *pbyIVHead, *pbyPayloadHead, *pbyTxBufferAddr;
 	u8 abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
 	u8 abySNAP_Bridgetunnel[ETH_ALEN]
@@ -1193,26 +972,22 @@
 	u32 uDuration;
 	u32 cbHeaderLength = 0, uPadding = 0;
 	void *pvRrvTime;
-	PSMICHDRHead pMICHDR;
-	void *pvRTS;
-	void *pvCTS;
+	struct vnt_mic_hdr *pMICHDR;
+	void *rts_cts = NULL;
 	void *pvTxDataHd;
 	u8 byFBOption = AUTO_FB_NONE, byFragType;
 	u16 wTxBufSize;
-	u32 dwMICKey0, dwMICKey1, dwMIC_Priority, dwCRC;
+	u32 dwMICKey0, dwMICKey1, dwMIC_Priority;
 	u32 *pdwMIC_L, *pdwMIC_R;
 	int bSoftWEP = false;
 
-	pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
+	pvRrvTime = pMICHDR = pvTxDataHd = NULL;
 
 	if (bNeedEncryption && pTransmitKey->pvKeyTable) {
 		if (((PSKeyTable)pTransmitKey->pvKeyTable)->bSoftWEP == true)
 			bSoftWEP = true; /* WEP 256 */
 	}
 
-    pTxBufHead = (PTX_BUFFER) usbPacketBuf;
-    memset(pTxBufHead, 0, sizeof(TX_BUFFER));
-
     // Get pkt type
     if (ntohs(psEthHeader->h_proto) > ETH_DATA_LEN) {
         if (pDevice->dwDiagRefCount == 0) {
@@ -1257,10 +1032,6 @@
     if (pDevice->bLongHeader)
         pTxBufHead->wFIFOCtl |= FIFOCTL_LHEAD;
 
-    if (pDevice->bSoftwareGenCrcErr) {
-        pTxBufHead->wFIFOCtl |= FIFOCTL_CRCDIS; // set tx descriptors to NO hardware CRC
-    }
-
     //Set FRAGCTL_MACHDCNT
     if (pDevice->bLongHeader) {
         cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
@@ -1313,7 +1084,7 @@
         if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
             cbIVlen = 8;//RSN Header
             cbICVlen = 8;//MIC
-            cbMICHDR = sizeof(SMICHDRHead);
+	    cbMICHDR = sizeof(struct vnt_mic_hdr);
         }
         if (bSoftWEP == false) {
             //MAC Header should be padding 0 to DW alignment.
@@ -1336,76 +1107,116 @@
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
         if (byFBOption == AUTO_FB_NONE) {
             if (bRTS == true) {//RTS_need
-                pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
-                pvRTS = (PSRTS_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
-                pvCTS = NULL;
-                pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g));
-                cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g) + sizeof(STxDataHead_g);
+		pvRrvTime = (struct vnt_rrv_time_rts *)
+					(pbyTxBufferAddr + wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize +
+					sizeof(struct vnt_rrv_time_rts));
+		rts_cts = (struct vnt_rts_g *) (pbyTxBufferAddr + wTxBufSize +
+				sizeof(struct vnt_rrv_time_rts) + cbMICHDR);
+		pvTxDataHd = (struct vnt_tx_datahead_g *) (pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+				cbMICHDR + sizeof(struct vnt_rts_g));
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+			cbMICHDR + sizeof(struct vnt_rts_g) +
+				sizeof(struct vnt_tx_datahead_g);
             }
             else { //RTS_needless
-                pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
-                pvRTS = NULL;
-                pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
-                pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
-                cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
+		pvRrvTime = (struct vnt_rrv_time_cts *)
+				(pbyTxBufferAddr + wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+			sizeof(struct vnt_rrv_time_cts));
+		rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize +
+				sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
+		pvTxDataHd = (struct vnt_tx_datahead_g *)(pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+				cbMICHDR + sizeof(struct vnt_cts));
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+			cbMICHDR + sizeof(struct vnt_cts) +
+				sizeof(struct vnt_tx_datahead_g);
             }
         } else {
             // Auto Fall Back
             if (bRTS == true) {//RTS_need
-                pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
-                pvRTS = (PSRTS_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
-                pvCTS = NULL;
-                pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB));
-                cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB) + sizeof(STxDataHead_g_FB);
+		pvRrvTime = (struct vnt_rrv_time_rts *)(pbyTxBufferAddr +
+								wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+					sizeof(struct vnt_rrv_time_rts));
+		rts_cts = (struct vnt_rts_g_fb *)(pbyTxBufferAddr + wTxBufSize +
+				sizeof(struct vnt_rrv_time_rts) + cbMICHDR);
+		pvTxDataHd = (struct vnt_tx_datahead_g_fb *) (pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+				cbMICHDR + sizeof(struct vnt_rts_g_fb));
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) +
+			cbMICHDR + sizeof(struct vnt_rts_g_fb) +
+				sizeof(struct vnt_tx_datahead_g_fb);
             }
             else if (bRTS == false) { //RTS_needless
-                pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
-                pvRTS = NULL;
-                pvCTS = (PSCTS_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
-                pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB));
-                cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB) + sizeof(STxDataHead_g_FB);
+		pvRrvTime = (struct vnt_rrv_time_cts *)
+				(pbyTxBufferAddr + wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+				sizeof(struct vnt_rrv_time_cts));
+		rts_cts = (struct vnt_cts_fb *) (pbyTxBufferAddr + wTxBufSize +
+			sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
+		pvTxDataHd = (struct vnt_tx_datahead_g_fb *) (pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+				cbMICHDR + sizeof(struct vnt_cts_fb));
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+				cbMICHDR + sizeof(struct vnt_cts_fb) +
+					sizeof(struct vnt_tx_datahead_g_fb);
             }
         } // Auto Fall Back
     }
     else {//802.11a/b packet
         if (byFBOption == AUTO_FB_NONE) {
             if (bRTS == true) {//RTS_need
-                pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
-                pvRTS = (PSRTS_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
-                pvCTS = NULL;
-                pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab));
-                cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab) + sizeof(STxDataHead_ab);
+		pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr +
+								wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize +
+						sizeof(struct vnt_rrv_time_ab));
+		rts_cts = (struct vnt_rts_ab *) (pbyTxBufferAddr + wTxBufSize +
+				sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+		pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR +
+						sizeof(struct vnt_rts_ab));
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+			cbMICHDR + sizeof(struct vnt_rts_ab) +
+				sizeof(struct vnt_tx_datahead_ab);
             }
             else if (bRTS == false) { //RTS_needless, no MICHDR
-                pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
-                pvRTS = NULL;
-                pvCTS = NULL;
-                pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
-                cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
+		pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr +
+								wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+						sizeof(struct vnt_rrv_time_ab));
+		pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+				cbMICHDR + sizeof(struct vnt_tx_datahead_ab);
             }
         } else {
             // Auto Fall Back
             if (bRTS == true) {//RTS_need
-                pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
-                pvRTS = (PSRTS_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
-                pvCTS = NULL;
-                pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB));
-                cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB) + sizeof(STxDataHead_a_FB);
+		pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr +
+						wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+			sizeof(struct vnt_rrv_time_ab));
+		rts_cts = (struct vnt_rts_a_fb *)(pbyTxBufferAddr + wTxBufSize +
+				sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+		pvTxDataHd = (struct vnt_tx_datahead_a_fb *)(pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR +
+					sizeof(struct vnt_rts_a_fb));
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+			cbMICHDR + sizeof(struct vnt_rts_a_fb) +
+					sizeof(struct vnt_tx_datahead_a_fb);
             }
             else if (bRTS == false) { //RTS_needless
-                pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
-                pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
-                pvRTS = NULL;
-                pvCTS = NULL;
-                pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
-                cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_a_FB);
+		pvRrvTime = (struct vnt_rrv_time_ab *)(pbyTxBufferAddr +
+								wTxBufSize);
+		pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize +
+						sizeof(struct vnt_rrv_time_ab));
+		pvTxDataHd = (struct vnt_tx_datahead_a_fb *)(pbyTxBufferAddr +
+			wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+		cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+			cbMICHDR + sizeof(struct vnt_tx_datahead_a_fb);
             }
         } // Auto Fall Back
     }
@@ -1424,11 +1235,11 @@
 
     //Fill FIFO,RrvTime,RTS,and CTS
     s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
-			   (void *)pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
-                               cbFrameSize, bNeedACK, uDMAIdx, psEthHeader);
+		(void *)pbyTxBufferAddr, pvRrvTime, rts_cts,
+		cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, bRTS);
     //Fill DataHead
     uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK,
-                                    0, 0, 1/*uMACfragNum*/, byFBOption);
+				byFBOption);
     // Generate TX MAC Header
     s_vGenerateMACHeader(pDevice, pbyMacHdr, (u16)uDuration, psEthHeader, bNeedEncryption,
                            byFragType, uDMAIdx, 0);
@@ -1436,7 +1247,7 @@
     if (bNeedEncryption == true) {
         //Fill TXKEY
         s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
-                         pbyMacHdr, (u16)cbFrameBodySize, (u8 *)pMICHDR);
+		pbyMacHdr, (u16)cbFrameBodySize, pMICHDR);
 
         if (pDevice->bEnableHostWEP) {
             pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1475,8 +1286,6 @@
         memcpy((pbyPayloadHead + cb802_1_H_len), ((u8 *)psEthHeader) + ETH_HLEN, uSkbPacketLen - ETH_HLEN);
     }
 
-    ASSERT(uLength == cbNdisBodySize);
-
     if ((bNeedEncryption == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
 
         ///////////////////////////////////////////////////////////////////
@@ -1537,22 +1346,7 @@
         cbFrameSize -= cbICVlen;
     }
 
-    if (pDevice->bSoftwareGenCrcErr == true) {
-	unsigned int cbLen;
-        u32 * pdwCRC;
-
-        dwCRC = 0xFFFFFFFFL;
-        cbLen = cbFrameSize - cbFCSlen;
-        // calculate CRC, and wrtie CRC value to end of TD
-        dwCRC = CRCdwGetCrc32Ex(pbyMacHdr, cbLen, dwCRC);
-        pdwCRC = (u32 *)(pbyMacHdr + cbLen);
-        // finally, we must invert dwCRC to get the correct answer
-        *pdwCRC = ~dwCRC;
-        // Force Error
-        *pdwCRC -= 1;
-    } else {
         cbFrameSize -= cbFCSlen;
-    }
 
     *pcbHeaderLen = cbHeaderLength;
     *pcbTotalLen = cbHeaderLength + cbFrameSize ;
@@ -1589,13 +1383,7 @@
 {
 	struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyBufferAddr;
 
-    memset(pMACHeader, 0, (sizeof(struct ieee80211_hdr)));
-
-    if (uDMAIdx == TYPE_ATIMDMA) {
-    	pMACHeader->frame_control = TYPE_802_11_ATIM;
-    } else {
-        pMACHeader->frame_control = TYPE_802_11_DATA;
-    }
+	pMACHeader->frame_control = TYPE_802_11_DATA;
 
     if (pDevice->eOPMode == OP_MODE_AP) {
 	memcpy(&(pMACHeader->addr1[0]),
@@ -1678,14 +1466,14 @@
 	struct vnt_tx_mgmt *pPacket)
 {
 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
-	PTX_BUFFER pTX_Buffer;
+	struct vnt_tx_buffer *pTX_Buffer;
 	PSTxBufHead pTxBufHead;
-	PUSB_SEND_CONTEXT pContext;
+	struct vnt_usb_send_context *pContext;
 	struct ieee80211_hdr *pMACHeader;
-	PSCTS pCTS;
 	struct ethhdr sEthHeader;
 	u8 byPktType, *pbyTxBufferAddr;
-	void *pvRTS, *pvTxDataHd, *pvRrvTime, *pMICHDR;
+	void *rts_cts = NULL;
+	void *pvTxDataHd, *pvRrvTime, *pMICHDR;
 	u32 uDuration, cbReqCount, cbHeaderSize, cbFrameBodySize, cbFrameSize;
 	int bNeedACK, bIsPSPOLL = false;
 	u32 cbIVlen = 0, cbICVlen = 0, cbMIClen = 0, cbFCSlen = 4;
@@ -1694,19 +1482,18 @@
 	u32 cbMacHdLen;
 	u16 wCurrentRate = RATE_1M;
 
-    pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+	pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
 
     if (NULL == pContext) {
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ManagementSend TX...NO CONTEXT!\n");
         return CMD_STATUS_RESOURCES;
     }
 
-    pTX_Buffer = (PTX_BUFFER) (&pContext->Data[0]);
+	pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
     pbyTxBufferAddr = (u8 *)&(pTX_Buffer->adwTxKey[0]);
     cbFrameBodySize = pPacket->cbPayloadLen;
     pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
     wTxBufSize = sizeof(STxBufHead);
-    memset(pTxBufHead, 0, wTxBufSize);
 
     if (pDevice->byBBType == BB_TYPE_11A) {
         wCurrentRate = RATE_6M;
@@ -1819,25 +1606,24 @@
     //Set RrvTime/RTS/CTS Buffer
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
 
-        pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
+	pvRrvTime = (struct vnt_rrv_time_cts *) (pbyTxBufferAddr + wTxBufSize);
         pMICHDR = NULL;
-        pvRTS = NULL;
-        pCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
-        pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS));
-        cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS) + sizeof(STxDataHead_g);
+	rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize +
+					sizeof(struct vnt_rrv_time_cts));
+	pvTxDataHd = (struct vnt_tx_datahead_g *)(pbyTxBufferAddr + wTxBufSize +
+		sizeof(struct vnt_rrv_time_cts) + sizeof(struct vnt_cts));
+	cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_cts) +
+		sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g);
     }
     else { // 802.11a/b packet
-        pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+	pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + wTxBufSize);
         pMICHDR = NULL;
-        pvRTS = NULL;
-        pCTS = NULL;
-        pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
-        cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + sizeof(STxDataHead_ab);
+	pvTxDataHd = (struct vnt_tx_datahead_ab *) (pbyTxBufferAddr +
+		wTxBufSize + sizeof(struct vnt_rrv_time_ab));
+	cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_ab) +
+		sizeof(struct vnt_tx_datahead_ab);
     }
 
-    memset((void *)(pbyTxBufferAddr + wTxBufSize), 0,
-	   (cbHeaderSize - wTxBufSize));
-
     memcpy(&(sEthHeader.h_dest[0]),
 	   &(pPacket->p80211Header->sA3.abyAddr1[0]),
 	   ETH_ALEN);
@@ -1849,13 +1635,14 @@
     //=========================
     pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG;
 
-    //Fill FIFO,RrvTime,RTS,and CTS
-    s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,  pbyTxBufferAddr, pvRrvTime, pvRTS, pCTS,
-                           cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader);
+	/* Fill FIFO,RrvTime,RTS,and CTS */
+	s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
+		pbyTxBufferAddr, pvRrvTime, rts_cts,
+		cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, false);
 
     //Fill DataHead
     uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
-                                0, 0, 1, AUTO_FB_NONE);
+				AUTO_FB_NONE);
 
     pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize);
 
@@ -1918,12 +1705,15 @@
         // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
         // in the same place of other packet's Duration-field).
         // And it will cause Cisco-AP to issue Disassociation-packet
-        if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-            ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
-            ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
-        } else {
-            ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
-        }
+	if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+		((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_a =
+			cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+		((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_b =
+			cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+	} else {
+		((struct vnt_tx_datahead_ab *)pvTxDataHd)->wDuration =
+			cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+	}
     }
 
     pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount));
@@ -1948,60 +1738,60 @@
 CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
 	struct vnt_tx_mgmt *pPacket)
 {
+	struct vnt_beacon_buffer *pTX_Buffer;
 	u32 cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN;
 	u32 cbHeaderSize = 0;
 	u16 wTxBufSize = sizeof(STxShortBufHead);
 	PSTxShortBufHead pTxBufHead;
 	struct ieee80211_hdr *pMACHeader;
-	PSTxDataHead_ab pTxDataHead;
+	struct vnt_tx_datahead_ab *pTxDataHead;
 	u16 wCurrentRate;
 	u32 cbFrameBodySize;
 	u32 cbReqCount;
-	PBEACON_BUFFER pTX_Buffer;
 	u8 *pbyTxBufferAddr;
-	PUSB_SEND_CONTEXT pContext;
+	struct vnt_usb_send_context *pContext;
 	CMD_STATUS status;
 
-    pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+	pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
     if (NULL == pContext) {
         status = CMD_STATUS_RESOURCES;
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ManagementSend TX...NO CONTEXT!\n");
         return status ;
     }
-    pTX_Buffer = (PBEACON_BUFFER) (&pContext->Data[0]);
+
+	pTX_Buffer = (struct vnt_beacon_buffer *)&pContext->Data[0];
     pbyTxBufferAddr = (u8 *)&(pTX_Buffer->wFIFOCtl);
 
     cbFrameBodySize = pPacket->cbPayloadLen;
 
     pTxBufHead = (PSTxShortBufHead) pbyTxBufferAddr;
     wTxBufSize = sizeof(STxShortBufHead);
-    memset(pTxBufHead, 0, wTxBufSize);
 
     if (pDevice->byBBType == BB_TYPE_11A) {
         wCurrentRate = RATE_6M;
-        pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
+	pTxDataHead = (struct vnt_tx_datahead_ab *)
+			(pbyTxBufferAddr + wTxBufSize);
         //Get SignalField,ServiceField,Length
-        BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
-            (u16 *)&(pTxDataHead->wTransmitLength), (u8 *)&(pTxDataHead->byServiceField), (u8 *)&(pTxDataHead->bySignalField)
-        );
+	BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
+							&pTxDataHead->ab);
         //Get Duration and TimeStampOff
-        pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, PK_TYPE_11A,
-                                                          wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
-        pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-        cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
+	pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
+						PK_TYPE_11A, false);
+	pTxDataHead->wTimeStampOff = vnt_time_stamp_off(pDevice, wCurrentRate);
+	cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
     } else {
         wCurrentRate = RATE_1M;
         pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
-        pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
+	pTxDataHead = (struct vnt_tx_datahead_ab *)
+				(pbyTxBufferAddr + wTxBufSize);
         //Get SignalField,ServiceField,Length
-        BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
-            (u16 *)&(pTxDataHead->wTransmitLength), (u8 *)&(pTxDataHead->byServiceField), (u8 *)&(pTxDataHead->bySignalField)
-        );
+	BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
+							&pTxDataHead->ab);
         //Get Duration and TimeStampOff
-        pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, PK_TYPE_11B,
-                                                          wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
-        pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
-        cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
+	pTxDataHead->wDuration = s_uGetDataDuration(pDevice,
+						PK_TYPE_11B, false);
+	pTxDataHead->wTimeStampOff = vnt_time_stamp_off(pDevice, wCurrentRate);
+	cbHeaderSize = wTxBufSize + sizeof(struct vnt_tx_datahead_ab);
     }
 
     //Generate Beacon Header
@@ -2032,9 +1822,11 @@
 void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
 {
 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+	struct vnt_tx_buffer *pTX_Buffer;
 	u8 byPktType;
 	u8 *pbyTxBufferAddr;
-	void *pvRTS, *pvCTS, *pvTxDataHd;
+	void *rts_cts = NULL;
+	void *pvTxDataHd;
 	u32 uDuration, cbReqCount;
 	struct ieee80211_hdr *pMACHeader;
 	u32 cbHeaderSize, cbFrameBodySize;
@@ -2059,10 +1851,9 @@
 	PSKeyItem pTransmitKey = NULL;
 	u8 *pbyIVHead, *pbyPayloadHead, *pbyMacHdr;
 	u32 cbExtSuppRate = 0;
-	PTX_BUFFER pTX_Buffer;
-	PUSB_SEND_CONTEXT pContext;
+	struct vnt_usb_send_context *pContext;
 
-    pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
+	pvRrvTime = pMICHDR = pvTxDataHd = NULL;
 
     if(skb->len <= WLAN_HDR_ADDR3_LEN) {
        cbFrameBodySize = 0;
@@ -2072,7 +1863,7 @@
     }
     p80211Header = (PUWLAN_80211HDR)skb->data;
 
-    pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+	pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
 
     if (NULL == pContext) {
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0 TX...NO CONTEXT!\n");
@@ -2080,11 +1871,10 @@
         return ;
     }
 
-    pTX_Buffer = (PTX_BUFFER)(&pContext->Data[0]);
+	pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
     pbyTxBufferAddr = (u8 *)(&pTX_Buffer->adwTxKey[0]);
     pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
     wTxBufSize = sizeof(STxBufHead);
-    memset(pTxBufHead, 0, wTxBufSize);
 
     if (pDevice->byBBType == BB_TYPE_11A) {
         wCurrentRate = RATE_6M;
@@ -2204,7 +1994,7 @@
         else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
             cbIVlen = 8;//RSN Header
             cbICVlen = 8;//MIC
-            cbMICHDR = sizeof(SMICHDRHead);
+	    cbMICHDR = sizeof(struct vnt_mic_hdr);
             pTxBufHead->wFragCtl |= FRAGCTL_AES;
             pDevice->bAES = true;
         }
@@ -2222,26 +2012,28 @@
     //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
 
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
-
-        pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
-        pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
-        pvRTS = NULL;
-        pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
-        pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
-        cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
+	pvRrvTime = (struct vnt_rrv_time_cts *) (pbyTxBufferAddr + wTxBufSize);
+	pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+					sizeof(struct vnt_rrv_time_cts));
+	rts_cts = (struct vnt_cts *) (pbyTxBufferAddr + wTxBufSize +
+			sizeof(struct vnt_rrv_time_cts) + cbMICHDR);
+	pvTxDataHd = (struct vnt_tx_datahead_g *) (pbyTxBufferAddr +
+		wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR +
+					sizeof(struct vnt_cts));
+	cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR +
+		sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g);
 
     }
     else {//802.11a/b packet
 
-        pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
-        pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
-        pvRTS = NULL;
-        pvCTS = NULL;
-        pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
-        cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
+	pvRrvTime = (struct vnt_rrv_time_ab *) (pbyTxBufferAddr + wTxBufSize);
+	pMICHDR = (struct vnt_mic_hdr *) (pbyTxBufferAddr + wTxBufSize +
+		sizeof(struct vnt_rrv_time_ab));
+	pvTxDataHd = (struct vnt_tx_datahead_ab *)(pbyTxBufferAddr +
+		wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR);
+	cbHeaderSize = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR +
+					sizeof(struct vnt_tx_datahead_ab);
     }
-    memset((void *)(pbyTxBufferAddr + wTxBufSize), 0,
-	   (cbHeaderSize - wTxBufSize));
     memcpy(&(sEthHeader.h_dest[0]),
 	   &(p80211Header->sA3.abyAddr1[0]),
 	   ETH_ALEN);
@@ -2253,13 +2045,14 @@
     //=========================
     pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG;
 
-    //Fill FIFO,RrvTime,RTS,and CTS
-    s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
-                           cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader);
+	/* Fill FIFO,RrvTime,RTS,and CTS */
+	s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
+		pbyTxBufferAddr, pvRrvTime, rts_cts,
+		cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, false);
 
     //Fill DataHead
     uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
-                                0, 0, 1, AUTO_FB_NONE);
+				AUTO_FB_NONE);
 
     pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize);
 
@@ -2345,7 +2138,7 @@
         }
 
         s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
-                     pbyMacHdr, (u16)cbFrameBodySize, (u8 *)pMICHDR);
+		pbyMacHdr, (u16)cbFrameBodySize, pMICHDR);
 
         if (pDevice->bEnableHostWEP) {
             pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -2368,12 +2161,15 @@
         // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
         // in the same place of other packet's Duration-field).
         // And it will cause Cisco-AP to issue Disassociation-packet
-        if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-            ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(p80211Header->sA2.wDurationID);
-            ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(p80211Header->sA2.wDurationID);
-        } else {
-            ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(p80211Header->sA2.wDurationID);
-        }
+	if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+		((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_a =
+			cpu_to_le16(p80211Header->sA2.wDurationID);
+		((struct vnt_tx_datahead_g *)pvTxDataHd)->wDuration_b =
+			cpu_to_le16(p80211Header->sA2.wDurationID);
+	} else {
+		((struct vnt_tx_datahead_ab *)pvTxDataHd)->wDuration =
+			cpu_to_le16(p80211Header->sA2.wDurationID);
+	}
     }
 
     pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount));
@@ -2415,6 +2211,7 @@
 {
 	struct net_device_stats *pStats = &pDevice->stats;
 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+	struct vnt_tx_buffer *pTX_Buffer;
 	u32 BytesToWrite = 0, uHeaderLen = 0;
 	u32 uNodeIndex = 0;
 	u8 byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
@@ -2428,9 +2225,8 @@
 	int bNeedDeAuth = false;
 	u8 *pbyBSSID;
 	int bNodeExist = false;
-	PUSB_SEND_CONTEXT pContext;
+	struct vnt_usb_send_context *pContext;
 	bool fConvertedPacket;
-	PTX_BUFFER pTX_Buffer;
 	u32 status;
 	u16 wKeepRate = pDevice->wCurrentRate;
 	int bTxeapol_key = false;
@@ -2500,7 +2296,7 @@
         }
     }
 
-    pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+	pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
 
     if (pContext == NULL) {
         DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG" pContext == NULL\n");
@@ -2738,8 +2534,10 @@
         }
     }
 
+	pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
+
     fConvertedPacket = s_bPacketToWirelessUsb(pDevice, byPktType,
-                        (u8 *)(&pContext->Data[0]), bNeedEncryption,
+			pTX_Buffer, bNeedEncryption,
                         skb->len, uDMAIdx, &pDevice->sTxEthHeader,
                         (u8 *)skb->data, pTransmitKey, uNodeIndex,
                         pDevice->wCurrentRate,
@@ -2761,7 +2559,6 @@
         }
     }
 
-    pTX_Buffer = (PTX_BUFFER)&(pContext->Data[0]);
     pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
     pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
 
@@ -2808,20 +2605,20 @@
 	u32 uNodeIndex)
 {
 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
+	struct vnt_tx_buffer *pTX_Buffer;
 	u32 BytesToWrite = 0, uHeaderLen = 0;
 	u8 byPktType = PK_TYPE_11B;
 	int bNeedEncryption = false;
 	SKeyItem STempKey;
 	PSKeyItem pTransmitKey = NULL;
 	u8 *pbyBSSID;
-	PUSB_SEND_CONTEXT pContext;
+	struct vnt_usb_send_context *pContext;
 	u8 byPktTyp;
 	int fConvertedPacket;
-	PTX_BUFFER pTX_Buffer;
 	u32 status;
 	u16 wKeepRate = pDevice->wCurrentRate;
 
-    pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
+	pContext = (struct vnt_usb_send_context *)s_vGetFreeContext(pDevice);
 
     if (NULL == pContext) {
         return false;
@@ -2898,8 +2695,10 @@
     // Convert the packet to an usb frame and copy into our buffer
     // and send the irp.
 
+	pTX_Buffer = (struct vnt_tx_buffer *)&pContext->Data[0];
+
     fConvertedPacket = s_bPacketToWirelessUsb(pDevice, byPktType,
-                         (u8 *)(&pContext->Data[0]), bNeedEncryption,
+			pTX_Buffer, bNeedEncryption,
                          uDataLen, TYPE_AC0DMA, &pDevice->sTxEthHeader,
                          pbySkbData, pTransmitKey, uNodeIndex,
                          pDevice->wCurrentRate,
@@ -2911,7 +2710,6 @@
         return false;
     }
 
-    pTX_Buffer = (PTX_BUFFER)&(pContext->Data[0]);
     pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
     pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
 
diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h
index dd7e85d..4bbee1c 100644
--- a/drivers/staging/vt6656/rxtx.h
+++ b/drivers/staging/vt6656/rxtx.h
@@ -31,602 +31,173 @@
 
 #include "device.h"
 #include "wcmd.h"
+#include "baseband.h"
 
-//
-// RTS buffer header
-//
-typedef struct tagSRTSDataF {
-    u16    wFrameControl;
-    u16    wDurationID;
-    u8    abyRA[ETH_ALEN];
-    u8    abyTA[ETH_ALEN];
-} SRTSDataF, *PSRTSDataF;
+/* MIC HDR data header */
+struct vnt_mic_hdr {
+	u8 id;
+	u8 tx_priority;
+	u8 mic_addr2[6];
+	__be32 tsc_47_16;
+	__be16 tsc_15_0;
+	__be16 payload_len;
+	__be16 hlen;
+	__le16 frame_control;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	__le16 seq_ctrl;
+	u8 addr4[6];
+	u16 packing; /* packing to 48 bytes */
+} __packed;
 
-//
-// CTS buffer header
-//
-typedef struct tagSCTSDataF {
-    u16    wFrameControl;
-    u16    wDurationID;
-    u8    abyRA[ETH_ALEN];
-    u16    wReserved;
-} SCTSDataF, *PSCTSDataF;
+/* RsvTime buffer header */
+struct vnt_rrv_time_rts {
+	u16 wRTSTxRrvTime_ba;
+	u16 wRTSTxRrvTime_aa;
+	u16 wRTSTxRrvTime_bb;
+	u16 wReserved;
+	u16 wTxRrvTime_b;
+	u16 wTxRrvTime_a;
+} __packed;
 
-//
-// MICHDR data header
-//
-typedef struct tagSMICHDR {
-	u32 adwHDR0[4];
-	u32 adwHDR1[4];
-	u32 adwHDR2[4];
-} SMICHDR, *PSMICHDR;
+struct vnt_rrv_time_cts {
+	u16 wCTSTxRrvTime_ba;
+	u16 wReserved;
+	u16 wTxRrvTime_b;
+	u16 wTxRrvTime_a;
+} __packed;
 
-typedef struct tagSTX_NAF_G_RTS
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_ba;
-    u16            wRTSTxRrvTime_aa;
-    u16            wRTSTxRrvTime_bb;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
+struct vnt_rrv_time_ab {
+	u16 wRTSTxRrvTime;
+	u16 wTxRrvTime;
+} __packed;
 
-    //RTS
-    u8            byRTSSignalField_b;
-    u8            byRTSServiceField_b;
-    u16            wRTSTransmitLength_b;
-    u8            byRTSSignalField_a;
-    u8            byRTSServiceField_a;
-    u16            wRTSTransmitLength_a;
-    u16            wRTSDuration_ba;
-    u16            wRTSDuration_aa;
-    u16            wRTSDuration_bb;
-    u16            wReserved3;
-    SRTSDataF       sRTS;
+/* TX data header */
+struct vnt_tx_datahead_g {
+	struct vnt_phy_field b;
+	struct vnt_phy_field a;
+	u16 wDuration_b;
+	u16 wDuration_a;
+	u16 wTimeStampOff_b;
+	u16 wTimeStampOff_a;
+} __packed;
 
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
+struct vnt_tx_datahead_g_fb {
+	struct vnt_phy_field b;
+	struct vnt_phy_field a;
+	u16 wDuration_b;
+	u16 wDuration_a;
+	u16 wDuration_a_f0;
+	u16 wDuration_a_f1;
+	u16 wTimeStampOff_b;
+	u16 wTimeStampOff_a;
+} __packed;
 
-} TX_NAF_G_RTS, *PTX_NAF_G_RTS;
+struct vnt_tx_datahead_ab {
+	struct vnt_phy_field ab;
+	u16 wDuration;
+	u16 wTimeStampOff;
+} __packed;
 
-typedef struct tagSTX_NAF_G_RTS_MIC
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_ba;
-    u16            wRTSTxRrvTime_aa;
-    u16            wRTSTxRrvTime_bb;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
+struct vnt_tx_datahead_a_fb {
+	struct vnt_phy_field a;
+	u16 wDuration;
+	u16 wTimeStampOff;
+	u16 wDuration_f0;
+	u16 wDuration_f1;
+} __packed;
 
-    SMICHDR         sMICHDR;
+/* RTS buffer header */
+struct vnt_rts_g {
+	struct vnt_phy_field b;
+	struct vnt_phy_field a;
+	u16 wDuration_ba;
+	u16 wDuration_aa;
+	u16 wDuration_bb;
+	u16 wReserved;
+	struct ieee80211_rts data;
+} __packed;
 
-    //RTS
-    u8            byRTSSignalField_b;
-    u8            byRTSServiceField_b;
-    u16            wRTSTransmitLength_b;
-    u8            byRTSSignalField_a;
-    u8            byRTSServiceField_a;
-    u16            wRTSTransmitLength_a;
-    u16            wRTSDuration_ba;
-    u16            wRTSDuration_aa;
-    u16            wRTSDuration_bb;
-    u16            wReserved3;
-    SRTSDataF       sRTS;
+struct vnt_rts_g_fb {
+	struct vnt_phy_field b;
+	struct vnt_phy_field a;
+	u16 wDuration_ba;
+	u16 wDuration_aa;
+	u16 wDuration_bb;
+	u16 wReserved;
+	u16 wRTSDuration_ba_f0;
+	u16 wRTSDuration_aa_f0;
+	u16 wRTSDuration_ba_f1;
+	u16 wRTSDuration_aa_f1;
+	struct ieee80211_rts data;
+} __packed;
 
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
+struct vnt_rts_ab {
+	struct vnt_phy_field ab;
+	u16 wDuration;
+	u16 wReserved;
+	struct ieee80211_rts data;
+} __packed;
 
-} TX_NAF_G_RTS_MIC, *PTX_NAF_G_RTS_MIC;
+struct vnt_rts_a_fb {
+	struct vnt_phy_field a;
+	u16 wDuration;
+	u16 wReserved;
+	u16 wRTSDuration_f0;
+	u16 wRTSDuration_f1;
+	struct ieee80211_rts data;
+} __packed;
 
-typedef struct tagSTX_NAF_G_CTS
-{
-    //RsvTime
-    u16            wCTSTxRrvTime_ba;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
+/* CTS buffer header */
+struct vnt_cts {
+	struct vnt_phy_field b;
+	u16 wDuration_ba;
+	u16 wReserved;
+	struct ieee80211_cts data;
+	u16 reserved2;
+} __packed;
 
-    //CTS
-    u8            byCTSSignalField_b;
-    u8            byCTSServiceField_b;
-    u16            wCTSTransmitLength_b;
-    u16            wCTSDuration_ba;
-    u16            wReserved3;
-    SCTSDataF       sCTS;
+struct vnt_cts_fb {
+	struct vnt_phy_field b;
+	u16 wDuration_ba;
+	u16 wReserved;
+	u16 wCTSDuration_ba_f0;
+	u16 wCTSDuration_ba_f1;
+	struct ieee80211_cts data;
+	u16 reserved2;
+} __packed;
 
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
+union vnt_tx_data_head {
+	/* rts g */
+	struct vnt_rts_g rts_g;
+	struct vnt_rts_g_fb rts_g_fb;
+	/* rts a/b */
+	struct vnt_rts_ab rts_ab;
+	struct vnt_rts_a_fb rts_a_fb;
+	/* cts g */
+	struct vnt_cts cts_g;
+	struct vnt_cts_fb cts_g_fb;
+};
 
-} TX_NAF_G_CTS, *PTX_NAF_G_CTS;
-
-typedef struct tagSTX_NAF_G_CTS_MIC
-{
-    //RsvTime
-    u16            wCTSTxRrvTime_ba;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
-
-    SMICHDR         sMICHDR;
-
-    //CTS
-    u8            byCTSSignalField_b;
-    u8            byCTSServiceField_b;
-    u16            wCTSTransmitLength_b;
-    u16            wCTSDuration_ba;
-    u16            wReserved3;
-    SCTSDataF       sCTS;
-
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
-
-} TX_NAF_G_CTS_MIC, *PTX_NAF_G_CTS_MIC;
-
-typedef struct tagSTX_NAF_G_BEACON
-{
-    u16            wFIFOCtl;
-    u16            wTimeStamp;
-
-    //CTS
-    u8            byCTSSignalField_b;
-    u8            byCTSServiceField_b;
-    u16            wCTSTransmitLength_b;
-    u16            wCTSDuration_ba;
-    u16            wReserved1;
-    SCTSDataF       sCTS;
-
-    //Data
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_a;
-    u16            wTimeStampOff_a;
-
-} TX_NAF_G_BEACON, *PTX_NAF_G_BEACON;
-
-typedef struct tagSTX_NAF_AB_RTS
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_ab;
-    u16            wTxRrvTime_ab;
-
-    //RTS
-    u8            byRTSSignalField_ab;
-    u8            byRTSServiceField_ab;
-    u16            wRTSTransmitLength_ab;
-    u16            wRTSDuration_ab;
-    u16            wReserved2;
-    SRTSDataF       sRTS;
-
-    //Data
-    u8            bySignalField_ab;
-    u8            byServiceField_ab;
-    u16            wTransmitLength_ab;
-    u16            wDuration_ab;
-    u16            wTimeStampOff_ab;
-
-} TX_NAF_AB_RTS, *PTX_NAF_AB_RTS;
-
-typedef struct tagSTX_NAF_AB_RTS_MIC
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_ab;
-    u16            wTxRrvTime_ab;
-
-    SMICHDR         sMICHDR;
-
-    //RTS
-    u8            byRTSSignalField_ab;
-    u8            byRTSServiceField_ab;
-    u16            wRTSTransmitLength_ab;
-    u16            wRTSDuration_ab;
-    u16            wReserved2;
-    SRTSDataF       sRTS;
-
-    //Data
-    u8            bySignalField_ab;
-    u8            byServiceField_ab;
-    u16            wTransmitLength_ab;
-    u16            wDuration_ab;
-    u16            wTimeStampOff_ab;
-
-} TX_NAF_AB_RTS_MIC, *PTX_NAF_AB_RTS_MIC;
-
-typedef struct tagSTX_NAF_AB_CTS
-{
-    //RsvTime
-    u16            wReserved2;
-    u16            wTxRrvTime_ab;
-
-    //Data
-    u8            bySignalField_ab;
-    u8            byServiceField_ab;
-    u16            wTransmitLength_ab;
-    u16            wDuration_ab;
-    u16            wTimeStampOff_ab;
-
-} TX_NAF_AB_CTS, *PTX_NAF_AB_CTS;
-
-typedef struct tagSTX_NAF_AB_CTS_MIC
-{
-    //RsvTime
-    u16            wReserved2;
-    u16            wTxRrvTime_ab;
-
-    SMICHDR         sMICHDR;
-
-    //Data
-    u8            bySignalField_ab;
-    u8            byServiceField_ab;
-    u16            wTransmitLength_ab;
-    u16            wDuration_ab;
-    u16            wTimeStampOff_ab;
-
-} TX_NAF_AB_CTS_MIC, *PTX_NAF_AB_CTS_MIC;
-
-typedef struct tagSTX_NAF_AB_BEACON
-{
-    u16            wFIFOCtl;
-    u16            wTimeStamp;
-
-   //Data
-    u8            bySignalField_ab;
-    u8            byServiceField_ab;
-    u16            wTransmitLength_ab;
-    u16            wDuration_ab;
-    u16            wTimeStampOff_ab;
-
-} TX_NAF_AB_BEACON, *PTX_NAF_AB_BEACON;
-
-typedef struct tagSTX_AF_G_RTS
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_ba;
-    u16            wRTSTxRrvTime_aa;
-    u16            wRTSTxRrvTime_bb;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
-
-    //RTS
-    u8            byRTSSignalField_b;
-    u8            byRTSServiceField_b;
-    u16            wRTSTransmitLength_b;
-    u8            byRTSSignalField_a;
-    u8            byRTSServiceField_a;
-    u16            wRTSTransmitLength_a;
-    u16            wRTSDuration_ba;
-    u16            wRTSDuration_aa;
-    u16            wRTSDuration_bb;
-    u16            wReserved3;
-    u16            wRTSDuration_ba_f0;
-    u16            wRTSDuration_aa_f0;
-    u16            wRTSDuration_ba_f1;
-    u16            wRTSDuration_aa_f1;
-    SRTSDataF       sRTS;
-
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
-
-} TX_AF_G_RTS, *PTX_AF_G_RTS;
-
-typedef struct tagSTX_AF_G_RTS_MIC
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_ba;
-    u16            wRTSTxRrvTime_aa;
-    u16            wRTSTxRrvTime_bb;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
-
-    SMICHDR         sMICHDR;
-
-    //RTS
-    u8            byRTSSignalField_b;
-    u8            byRTSServiceField_b;
-    u16            wRTSTransmitLength_b;
-    u8            byRTSSignalField_a;
-    u8            byRTSServiceField_a;
-    u16            wRTSTransmitLength_a;
-    u16            wRTSDuration_ba;
-    u16            wRTSDuration_aa;
-    u16            wRTSDuration_bb;
-    u16            wReserved3;
-    u16            wRTSDuration_ba_f0;
-    u16            wRTSDuration_aa_f0;
-    u16            wRTSDuration_ba_f1;
-    u16            wRTSDuration_aa_f1;
-    SRTSDataF       sRTS;
-
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
-
-} TX_AF_G_RTS_MIC, *PTX_AF_G_RTS_MIC;
-
-typedef struct tagSTX_AF_G_CTS
-{
-    //RsvTime
-    u16            wCTSTxRrvTime_ba;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
-
-    //CTS
-    u8            byCTSSignalField_b;
-    u8            byCTSServiceField_b;
-    u16            wCTSTransmitLength_b;
-    u16            wCTSDuration_ba;
-    u16            wReserved3;
-    u16            wCTSDuration_ba_f0;
-    u16            wCTSDuration_ba_f1;
-    SCTSDataF       sCTS;
-
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
-
-} TX_AF_G_CTS, *PTX_AF_G_CTS;
-
-typedef struct tagSTX_AF_G_CTS_MIC
-{
-    //RsvTime
-    u16            wCTSTxRrvTime_ba;
-    u16            wReserved2;
-    u16            wTxRrvTime_b;
-    u16            wTxRrvTime_a;
-
-    SMICHDR         sMICHDR;
-
-    //CTS
-    u8            byCTSSignalField_b;
-    u8            byCTSServiceField_b;
-    u16            wCTSTransmitLength_b;
-    u16            wCTSDuration_ba;
-    u16            wReserved3;
-    u16            wCTSDuration_ba_f0;
-    u16            wCTSDuration_ba_f1;
-    SCTSDataF       sCTS;
-
-    //Data
-    u8            bySignalField_b;
-    u8            byServiceField_b;
-    u16            wTransmitLength_b;
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_b;
-    u16            wDuration_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-    u16            wTimeStampOff_b;
-    u16            wTimeStampOff_a;
-
-} TX_AF_G_CTS_MIC, *PTX_AF_G_CTS_MIC;
-
-typedef struct tagSTX_AF_A_RTS
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_a;
-    u16            wTxRrvTime_a;
-
-    //RTS
-    u8            byRTSSignalField_a;
-    u8            byRTSServiceField_a;
-    u16            wRTSTransmitLength_a;
-    u16            wRTSDuration_a;
-    u16            wReserved2;
-    u16            wRTSDuration_a_f0;
-    u16            wRTSDuration_a_f1;
-    SRTSDataF       sRTS;
-
-    //Data
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_a;
-    u16            wTimeStampOff_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-
-} TX_AF_A_RTS, *PTX_AF_A_RTS;
-
-typedef struct tagSTX_AF_A_RTS_MIC
-{
-    //RsvTime
-    u16            wRTSTxRrvTime_a;
-    u16            wTxRrvTime_a;
-
-    SMICHDR         sMICHDR;
-
-    //RTS
-    u8            byRTSSignalField_a;
-    u8            byRTSServiceField_a;
-    u16            wRTSTransmitLength_a;
-    u16            wRTSDuration_a;
-    u16            wReserved2;
-    u16            wRTSDuration_a_f0;
-    u16            wRTSDuration_a_f1;
-    SRTSDataF       sRTS;
-
-    //Data
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_a;
-    u16            wTimeStampOff_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-
-} TX_AF_A_RTS_MIC, *PTX_AF_A_RTS_MIC;
-
-typedef struct tagSTX_AF_A_CTS
-{
-    //RsvTime
-    u16            wReserved2;
-    u16            wTxRrvTime_a;
-
-    //Data
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_a;
-    u16            wTimeStampOff_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-
-} TX_AF_A_CTS, *PTX_AF_A_CTS;
-
-typedef struct tagSTX_AF_A_CTS_MIC
-{
-    //RsvTime
-    u16            wReserved2;
-    u16            wTxRrvTime_a;
-
-    SMICHDR         sMICHDR;
-
-    //Data
-    u8            bySignalField_a;
-    u8            byServiceField_a;
-    u16            wTransmitLength_a;
-    u16            wDuration_a;
-    u16            wTimeStampOff_a;
-    u16            wDuration_a_f0;
-    u16            wDuration_a_f1;
-
-} TX_AF_A_CTS_MIC, *PTX_AF_A_CTS_MIC;
-
-//
-// union with all of the TX Buffer Type
-//
-typedef union tagUTX_BUFFER_CONTAINER
-{
-    TX_NAF_G_RTS                    RTS_G;
-    TX_NAF_G_RTS_MIC                RTS_G_MIC;
-    TX_NAF_G_CTS                    CTS_G;
-    TX_NAF_G_CTS_MIC                CTS_G_MIC;
-    //TX_NAF_G_BEACON                 Beacon_G;
-    TX_NAF_AB_RTS                   RTS_AB;
-    TX_NAF_AB_RTS_MIC               RTS_AB_MIC;
-    TX_NAF_AB_CTS                   CTS_AB;
-    TX_NAF_AB_CTS_MIC               CTS_AB_MIC;
-    //TX_NAF_AB_BEACON                Beacon_AB;
-    TX_AF_G_RTS                     RTS_G_AutoFB;
-    TX_AF_G_RTS_MIC                 RTS_G_AutoFB_MIC;
-    TX_AF_G_CTS                     CTS_G_AutoFB;
-    TX_AF_G_CTS_MIC                 CTS_G_AutoFB_MIC;
-    TX_AF_A_RTS                     RTS_A_AutoFB;
-    TX_AF_A_RTS_MIC                 RTS_A_AutoFB_MIC;
-    TX_AF_A_CTS                     CTS_A_AutoFB;
-    TX_AF_A_CTS_MIC                 CTS_A_AutoFB_MIC;
-
-} TX_BUFFER_CONTAINER, *PTX_BUFFER_CONTAINER;
-
-//
-// Remote NDIS message format
-//
-typedef struct tagSTX_BUFFER
-{
-    u8                            byType;
-    u8                            byPKTNO;
-    u16                            wTxByteCount;
-
+struct vnt_tx_buffer {
+	u8 byType;
+	u8 byPKTNO;
+	u16 wTxByteCount;
 	u32 adwTxKey[4];
-    u16                            wFIFOCtl;
-    u16                            wTimeStamp;
-    u16                            wFragCtl;
-    u16                            wReserved;
+	u16 wFIFOCtl;
+	u16 wTimeStamp;
+	u16 wFragCtl;
+	u16 wReserved;
+} __packed;
 
-    // Actual message
-    TX_BUFFER_CONTAINER             BufferHeader;
-
-} TX_BUFFER, *PTX_BUFFER;
-
-//
-// Remote NDIS message format
-//
-typedef struct tagSBEACON_BUFFER
-{
-    u8                            byType;
-    u8                            byPKTNO;
-    u16                            wTxByteCount;
-
-    u16                            wFIFOCtl;
-    u16                            wTimeStamp;
-
-    // Actual message
-    TX_BUFFER_CONTAINER             BufferHeader;
-
-} BEACON_BUFFER, *PBEACON_BUFFER;
+struct vnt_beacon_buffer {
+	u8 byType;
+	u8 byPKTNO;
+	u16 wTxByteCount;
+	u16 wFIFOCtl;
+	u16 wTimeStamp;
+} __packed;
 
 void vDMA0_tx_80211(struct vnt_private *, struct sk_buff *skb);
 int nsDMA_tx_packet(struct vnt_private *, u32 uDMAIdx, struct sk_buff *skb);
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 098be60..3a03f1d 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -421,7 +421,7 @@
  *
  */
 
-int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, PRCB pRCB)
+int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB)
 {
 	int ntStatus = 0;
 	struct urb *pUrb;
@@ -479,7 +479,7 @@
 
 static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
 {
-	PRCB pRCB = (PRCB)urb->context;
+	struct vnt_rcb *pRCB = (struct vnt_rcb *)urb->context;
 	struct vnt_private *pDevice = pRCB->pDevice;
 	unsigned long   bytesRead;
 	int bIndicateReceive = false;
@@ -546,7 +546,8 @@
  *
  */
 
-int PIPEnsSendBulkOut(struct vnt_private *pDevice, PUSB_SEND_CONTEXT pContext)
+int PIPEnsSendBulkOut(struct vnt_private *pDevice,
+				struct vnt_usb_send_context *pContext)
 {
 	int status;
 	struct urb          *pUrb;
@@ -628,14 +629,13 @@
 	int status;
 	CONTEXT_TYPE ContextType;
 	unsigned long ulBufLen;
-	PUSB_SEND_CONTEXT pContext;
+	struct vnt_usb_send_context *pContext;
 
     DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n");
     //
     // The context given to IoSetCompletionRoutine is an USB_CONTEXT struct
     //
-    pContext = (PUSB_SEND_CONTEXT) urb->context;
-    ASSERT( NULL != pContext );
+	pContext = (struct vnt_usb_send_context *)urb->context;
 
     pDevice = pContext->pDevice;
     ContextType = pContext->Type;
diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h
index bb7a611..f537703 100644
--- a/drivers/staging/vt6656/usbpipe.h
+++ b/drivers/staging/vt6656/usbpipe.h
@@ -40,7 +40,8 @@
 	u16 wIndex, u16 wLength,  u8 *pbyBuffer);
 
 int PIPEnsInterruptRead(struct vnt_private *);
-int PIPEnsBulkInUsbRead(struct vnt_private *, PRCB pRCB);
-int PIPEnsSendBulkOut(struct vnt_private *, PUSB_SEND_CONTEXT pContext);
+int PIPEnsBulkInUsbRead(struct vnt_private *, struct vnt_rcb *pRCB);
+int PIPEnsSendBulkOut(struct vnt_private *,
+				struct vnt_usb_send_context *pContext);
 
 #endif /* __USBPIPE_H__ */
diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c
index 6d1ff5e..b6cbd13 100644
--- a/drivers/staging/vt6656/wmgr.c
+++ b/drivers/staging/vt6656/wmgr.c
@@ -751,7 +751,6 @@
 	    || (sFrame.pwStatus == NULL)
 	    || (sFrame.pwAid == NULL)
 	    || (sFrame.pSuppRates == NULL)) {
-		DBG_PORT80(0xCC);
 		return;
         }
 
@@ -3750,7 +3749,6 @@
 
 	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp:Fail addr:[%p]\n",
 		pRxPacket->p80211Header);
-	DBG_PORT80(0xCC);
 	return;
     }
 
diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c
index faa93f0..fcc3d21 100644
--- a/drivers/staging/winbond/mds.c
+++ b/drivers/staging/winbond/mds.c
@@ -15,7 +15,8 @@
 	return hal_get_tx_buffer(&adapter->sHwData, &pMds->pTxBuffer);
 }
 
-static void Mds_DurationSet(struct wbsoft_priv *adapter,  struct wb35_descriptor *pDes,  u8 *buffer)
+static void Mds_DurationSet(struct wbsoft_priv *adapter,
+			    struct wb35_descriptor *pDes, u8 *buffer)
 {
 	struct T00_descriptor *pT00;
 	struct T01_descriptor *pT01;
@@ -43,10 +44,11 @@
 	 * Set RTS/CTS mechanism
 	 ******************************************/
 	if (!boGroupAddr) {
-		/* NOTE : If the protection mode is enabled and the MSDU will be fragmented,
-		 *		 the tx rates of MPDUs will all be DSSS rates. So it will not use
-		 *		 CTS-to-self in this case. CTS-To-self will only be used when without
-		 *		 fragmentation. -- 20050112 */
+		/* NOTE : If the protection mode is enabled and the MSDU will
+		 *	  be fragmented, the tx rates of MPDUs will all be DSSS
+		 *	  rates. So it will not use CTS-to-self in this case.
+		 *	  CTS-To-self will only be used when without
+		 *	  fragmentation. -- 20050112 */
 		BodyLen = (u16)pT00->T00_frame_length;	/* include 802.11 header */
 		BodyLen += 4;	/* CRC */
 
@@ -90,8 +92,8 @@
 				 * CTS Rate : 24 Mega bps
 				 * CTS frame length = 14 bytes */
 				Duration += (DEFAULT_SIFSTIME +
-								PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION +
-								((112 + 22 + 95)/96)*Tsym);
+					    PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION +
+					    ((112 + 22 + 95)/96)*Tsym);
 			} else {
 				/* CTS + 1 SIFS + CTS duration
 				 * CTS Rate : ?? Mega bps
@@ -101,7 +103,8 @@
 				else
 					Duration += SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME;
 
-				Duration += (((112 + Rate-1) / Rate) + DEFAULT_SIFSTIME);
+				Duration += (((112 + Rate-1) / Rate) +
+					     DEFAULT_SIFSTIME);
 			}
 		}
 
@@ -127,9 +130,10 @@
 				 *  Rate : ??Mega bps
 				 *  ACK frame length = 14 bytes, tx rate = 24M */
 				Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION * 3;
-				Duration += (((NextBodyLen*8 + 22 + Rate*4 - 1)/(Rate*4)) * Tsym +
-							(((2*14)*8 + 22 + 95)/96)*Tsym +
-							DEFAULT_SIFSTIME*3);
+				Duration += (((NextBodyLen*8 + 22 + Rate*4 - 1)
+					     /(Rate*4)) * Tsym +
+					     (((2*14)*8 + 22 + 95)/96)*Tsym +
+					    DEFAULT_SIFSTIME*3);
 			} else {
 				/* DSSS
 				 *  data transmit time + 2 ACK + 3 SIFS
@@ -141,8 +145,9 @@
 				else
 					Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME*3;
 
-				Duration += (((NextBodyLen + (2*14))*8 + Rate-1) / Rate +
-							DEFAULT_SIFSTIME*3);
+				Duration += (((NextBodyLen + (2*14))*8
+					     + Rate-1) / Rate +
+					    DEFAULT_SIFSTIME*3);
 			}
 
 			((u16 *)buffer)[5] = cpu_to_le16(Duration); /* 4 USHOR for skip 8B USB, 2USHORT=FC + Duration */
@@ -168,7 +173,8 @@
 			 * ACK frame length = 14 bytes */
 			Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION;
 			/* The Tx rate of ACK use 24M */
-			Duration += (((112 + 22 + 95)/96)*Tsym + DEFAULT_SIFSTIME);
+			Duration += (((112 + 22 + 95)/96)*Tsym +
+				    DEFAULT_SIFSTIME);
 		} else {
 			/* DSSS
 			 * 1 ACK + 1 SIFS
@@ -191,7 +197,8 @@
 }
 
 /* The function return the 4n size of usb pk */
-static u16 Mds_BodyCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *TargetBuffer)
+static u16 Mds_BodyCopy(struct wbsoft_priv *adapter,
+			struct wb35_descriptor *pDes, u8 *TargetBuffer)
 {
 	struct T00_descriptor *pT00;
 	struct wb35_mds *pMds = &adapter->Mds;
@@ -246,7 +253,7 @@
 				buf_index++;
 				buf_index %= MAX_DESCRIPTOR_BUFFER_INDEX;
 			} else {
-				u8	*pctmp = pDes->buffer_address[buf_index];
+				u8 *pctmp = pDes->buffer_address[buf_index];
 				pctmp += CopySize;
 				pDes->buffer_address[buf_index] = pctmp;
 				pDes->buffer_size[buf_index] -= CopySize;
@@ -290,7 +297,8 @@
 	return Size;
 }
 
-static void Mds_HeaderCopy(struct wbsoft_priv *adapter, struct wb35_descriptor *pDes, u8 *TargetBuffer)
+static void Mds_HeaderCopy(struct wbsoft_priv *adapter,
+			   struct wb35_descriptor *pDes, u8 *TargetBuffer)
 {
 	struct wb35_mds *pMds = &adapter->Mds;
 	u8	*src_buffer = pDes->buffer_address[0]; /* 931130.5.g */
@@ -391,11 +399,12 @@
 		pDes->PreambleMode =  WLAN_PREAMBLE_TYPE_LONG;
 	else
 		pDes->PreambleMode =  CURRENT_PREAMBLE_MODE;
-	pT01->T01_plcp_header_length = pDes->PreambleMode;	/* Set preamble */
+	pT01->T01_plcp_header_length = pDes->PreambleMode; /* Set preamble */
 
 }
 
-static void MLME_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *desc)
+static void MLME_GetNextPacket(struct wbsoft_priv *adapter,
+			       struct wb35_descriptor *desc)
 {
 	desc->InternalUsed = desc->buffer_start_index + desc->buffer_number;
 	desc->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX;
@@ -423,7 +432,8 @@
 	}
 }
 
-static void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID, unsigned char SendOK)
+static void MLME_SendComplete(struct wbsoft_priv *adapter, u8 PacketID,
+			      unsigned char SendOK)
 {
     /* Reclaim the data buffer */
 	adapter->sMlmeFrame.len = 0;
@@ -440,9 +450,9 @@
 	struct wb35_mds *pMds = &adapter->Mds;
 	struct wb35_descriptor	TxDes;
 	struct wb35_descriptor *pTxDes = &TxDes;
-	u8		*XmitBufAddress;
-	u16		XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold;
-	u8		FillIndex, TxDesIndex, FragmentCount, FillCount;
+	u8	*XmitBufAddress;
+	u16	XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold;
+	u8	FillIndex, TxDesIndex, FragmentCount, FillCount;
 	unsigned char	BufferFilled = false;
 
 
diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h
index ce8be07..159b2eb 100644
--- a/drivers/staging/winbond/mds_f.h
+++ b/drivers/staging/winbond/mds_f.h
@@ -7,13 +7,16 @@
 unsigned char Mds_initial(struct wbsoft_priv *adapter);
 void Mds_Tx(struct wbsoft_priv *adapter);
 void Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pt02);
-void Mds_MpduProcess(struct wbsoft_priv *adapter, struct wb35_descriptor *prxdes);
-extern void DataDmp(u8 *pdata, u32 len, u32 offset);
+void Mds_MpduProcess(struct wbsoft_priv *adapter,
+		     struct wb35_descriptor *prxdes);
 
 /* For data frame sending */
 u16 MDS_GetPacketSize(struct wbsoft_priv *adapter);
-void MDS_GetNextPacket(struct wbsoft_priv *adapter, struct wb35_descriptor *pdes);
-void MDS_GetNextPacketComplete(struct wbsoft_priv *adapter, struct wb35_descriptor *pdes);
-void MDS_SendResult(struct wbsoft_priv *adapter, u8 packetid, unsigned char sendok);
+void MDS_GetNextPacket(struct wbsoft_priv *adapter,
+		       struct wb35_descriptor *pdes);
+void MDS_GetNextPacketComplete(struct wbsoft_priv *adapter,
+			       struct wb35_descriptor *pdes);
+void MDS_SendResult(struct wbsoft_priv *adapter, u8 packetid,
+		    unsigned char sendok);
 
 #endif
diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h
index 84f6e84..78fc680 100644
--- a/drivers/staging/winbond/phy_calibration.h
+++ b/drivers/staging/winbond/phy_calibration.h
@@ -79,6 +79,7 @@
 #define SHIFT_IQCAL_TONE_Q(x)	((x) >> 13)
 
 void phy_set_rf_data(struct hw_data *pHwData, u32 index, u32 value);
+void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency);
 #define phy_init_rf(_A)		/* RFSynthesizer_initial(_A) */
 
 #endif
diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c
index 9be1b3b..a5e255b 100644
--- a/drivers/staging/winbond/wb35reg.c
+++ b/drivers/staging/winbond/wb35reg.c
@@ -1,10 +1,9 @@
 #include "wb35reg_f.h"
+#include "phy_calibration.h"
 
 #include <linux/usb.h>
 #include <linux/slab.h>
 
-extern void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency);
-
 /*
  * true  : read command process successfully
  * false : register not support
@@ -14,7 +13,8 @@
  * Flag : AUTO_INCREMENT - RegisterNo will auto increment 4
  *	  NO_INCREMENT - Function will write data into the same register
  */
-unsigned char Wb35Reg_BurstWrite(struct hw_data *pHwData, u16 RegisterNo, u32 *pRegisterData, u8 NumberOfData, u8 Flag)
+unsigned char Wb35Reg_BurstWrite(struct hw_data *pHwData, u16 RegisterNo,
+				 u32 *pRegisterData, u8 NumberOfData, u8 Flag)
 {
 	struct wb35_reg		*reg = &pHwData->reg;
 	struct urb		*urb = NULL;
@@ -44,7 +44,7 @@
 	reg_queue->pBuffer = (u32 *)((u8 *)reg_queue + sizeof(struct wb35_reg_queue));
 	memcpy(reg_queue->pBuffer, pRegisterData, DataSize);
 	/* the function for reversing register data from little endian to big endian */
-	for (i = 0; i < NumberOfData ; i++)
+	for (i = 0; i < NumberOfData; i++)
 		reg_queue->pBuffer[i] = cpu_to_le32(reg_queue->pBuffer[i]);
 
 	dr = (struct usb_ctrlrequest *)((u8 *)reg_queue + sizeof(struct wb35_reg_queue) + DataSize);
@@ -72,7 +72,7 @@
 	return true;
 }
 
-void Wb35Reg_Update(struct hw_data *pHwData,  u16 RegisterNo,  u32 RegisterValue)
+void Wb35Reg_Update(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
 {
 	struct wb35_reg *reg = &pHwData->reg;
 	switch (RegisterNo) {
@@ -118,7 +118,8 @@
  * true  : read command process successfully
  * false : register not support
  */
-unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
+unsigned char Wb35Reg_WriteSync(struct hw_data *pHwData, u16 RegisterNo,
+				u32 RegisterValue)
 {
 	struct wb35_reg *reg = &pHwData->reg;
 	int ret = -1;
@@ -139,9 +140,10 @@
 	/* Sync IoCallDriver */
 	reg->EP0vm_state = VM_RUNNING;
 	ret = usb_control_msg(pHwData->udev,
-			       usb_sndctrlpipe(pHwData->udev, 0),
-			       0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-			       0x0, RegisterNo, &RegisterValue, 4, HZ * 100);
+			      usb_sndctrlpipe(pHwData->udev, 0),
+			      0x03,
+			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+			      0x0, RegisterNo, &RegisterValue, 4, HZ * 100);
 	reg->EP0vm_state = VM_STOP;
 	reg->SyncIoPause = 0;
 
@@ -159,7 +161,8 @@
  * true  : read command process successfully
  * false : register not support
  */
-unsigned char Wb35Reg_Write(struct hw_data *pHwData, u16 RegisterNo, u32 RegisterValue)
+unsigned char Wb35Reg_Write(struct hw_data *pHwData, u16 RegisterNo,
+			    u32 RegisterValue)
 {
 	struct wb35_reg		*reg = &pHwData->reg;
 	struct usb_ctrlrequest	*dr;
@@ -286,7 +289,8 @@
  * pRegisterValue : It must be a resident buffer due to
  *		    asynchronous read register.
  */
-unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo, u32 *pRegisterValue)
+unsigned char Wb35Reg_ReadSync(struct hw_data *pHwData, u16 RegisterNo,
+			       u32 *pRegisterValue)
 {
 	struct wb35_reg *reg = &pHwData->reg;
 	u32		*pltmp = pRegisterValue;
@@ -305,9 +309,10 @@
 
 	reg->EP0vm_state = VM_RUNNING;
 	ret = usb_control_msg(pHwData->udev,
-			       usb_rcvctrlpipe(pHwData->udev, 0),
-			       0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-			       0x0, RegisterNo, pltmp, 4, HZ * 100);
+			      usb_rcvctrlpipe(pHwData->udev, 0),
+			      0x01,
+			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			      0x0, RegisterNo, pltmp, 4, HZ * 100);
 
 	*pRegisterValue = cpu_to_le32(*pltmp);
 
@@ -332,7 +337,8 @@
  * pRegisterValue : It must be a resident buffer due to
  *		    asynchronous read register.
  */
-unsigned char Wb35Reg_Read(struct hw_data *pHwData, u16 RegisterNo, u32 *pRegisterValue)
+unsigned char Wb35Reg_Read(struct hw_data *pHwData, u16 RegisterNo,
+			   u32 *pRegisterValue)
 {
 	struct wb35_reg		*reg = &pHwData->reg;
 	struct usb_ctrlrequest	*dr;
diff --git a/drivers/staging/wlags49_h2/Makefile b/drivers/staging/wlags49_h2/Makefile
index 31e1d89..6eeb5d1 100644
--- a/drivers/staging/wlags49_h2/Makefile
+++ b/drivers/staging/wlags49_h2/Makefile
@@ -51,5 +51,3 @@
 		mmd.o \
 		hcf.o \
 		dhf.o
-
-$(WLNAME)-$(CONFIG_SYSFS)	+= wl_sysfs.o
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index b55dc43..a458705 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -99,7 +99,6 @@
 #include <wl_main.h>
 #include <wl_netdev.h>
 #include <wl_cs.h>
-#include <wl_sysfs.h>
 
 
 /*******************************************************************************
@@ -178,7 +177,6 @@
 	wl_adapter_release(link);
 
 	if (dev) {
-		unregister_wlags_sysfs(dev);
 		unregister_netdev(dev);
 		wl_device_dealloc(dev);
 	}
@@ -265,8 +263,6 @@
 		goto failed;
 	}
 
-	register_wlags_sysfs(dev);
-
 	printk(KERN_INFO "%s: Wireless, io_addr %#03lx, irq %d, mac_address"
 		" %pM\n", dev->name, dev->base_addr, dev->irq, dev->dev_addr);
 
diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h
index b230781..78129e9 100644
--- a/drivers/staging/wlags49_h2/wl_internal.h
+++ b/drivers/staging/wlags49_h2/wl_internal.h
@@ -883,7 +883,6 @@
 	int                         is_registered;
 	int                         is_handling_int;
 	int                         firmware_present;
-	bool                        sysfsCreated;
 	CFG_DRV_INFO_STRCT          driverInfo;
 	CFG_IDENTITY_STRCT          driverIdentity;
 	CFG_FW_IDENTITY_STRCT       StationIdentity;
diff --git a/drivers/staging/wlags49_h2/wl_sysfs.c b/drivers/staging/wlags49_h2/wl_sysfs.c
deleted file mode 100644
index 1508f04..0000000
--- a/drivers/staging/wlags49_h2/wl_sysfs.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * ex: sw=4
- */
-
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <net/sock.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <linux/sysfs.h>
-
-#include <debug.h>
-#include <hcf.h>
-#include <hcfdef.h>
-
-#include <wl_if.h>
-#include <wl_internal.h>
-#include <wl_util.h>
-#include <wl_main.h>
-#include <wl_wext.h>
-#include <wl_priv.h>
-
-static inline int dev_isalive(const struct net_device *dev)
-{
-            return dev->reg_state == NETREG_REGISTERED;
-}
-
-/*
- * empirically even if tallies are defined as 32 bits entities, only
- * high 16 bits are relevant; low half is always zero. It means tallies
- * are pretty much useless for traffic counting but at least give overview
- * about where error come from
- */
-static ssize_t show_tallies(struct device *d, struct device_attribute *attr,
-			    char *buf)
-{
-    struct net_device *dev = to_net_dev(d);
-    struct wl_private *lp = wl_priv(dev);
-    unsigned long flags;
-    CFG_HERMES_TALLIES_STRCT tallies;
-    ssize_t ret = -EINVAL;
-
-    rcu_read_lock();
-    if (dev_isalive(dev)) {
-	wl_lock(lp, &flags);
-
-	ret = wl_get_tallies(lp, &tallies);
-	if (ret == 0) {
-		wl_unlock(lp, &flags);
-		ret = snprintf(buf, PAGE_SIZE,
-		    "TxUnicastFrames:           %u\n"
-		    "TxMulticastFrames:         %u\n"
-		    "TxFragments:               %u\n"
-		    "TxUnicastOctets:           %u\n"
-		    "TxMulticastOctets:         %u\n"
-		    "TxDeferredTransmissions:   %u\n"
-		    "TxSingleRetryFrames:       %u\n"
-		    "TxMultipleRetryFrames:     %u\n"
-		    "TxRetryLimitExceeded:      %u\n"
-		    "TxDiscards:                %u\n"
-		    "RxUnicastFrames:           %u\n"
-		    "RxMulticastFrames:         %u\n"
-		    "RxFragments:               %u\n"
-		    "RxUnicastOctets:           %u\n"
-		    "RxMulticastOctets:         %u\n"
-		    "RxFCSErrors:               %u\n"
-		    "RxDiscardsNoBuffer:        %u\n"
-		    "TxDiscardsWrongSA:         %u\n"
-		    "RxWEPUndecryptable:        %u\n"
-		    "RxMsgInMsgFragments:       %u\n"
-		    "RxMsgInBadMsgFragments:    %u\n"
-		    "RxDiscardsWEPICVError:     %u\n"
-		    "RxDiscardsWEPExcluded:     %u\n"
-		    ,
-		    (unsigned int)tallies.TxUnicastFrames,
-		    (unsigned int)tallies.TxMulticastFrames,
-		    (unsigned int)tallies.TxFragments,
-		    (unsigned int)tallies.TxUnicastOctets,
-		    (unsigned int)tallies.TxMulticastOctets,
-		    (unsigned int)tallies.TxDeferredTransmissions,
-		    (unsigned int)tallies.TxSingleRetryFrames,
-		    (unsigned int)tallies.TxMultipleRetryFrames,
-		    (unsigned int)tallies.TxRetryLimitExceeded,
-		    (unsigned int)tallies.TxDiscards,
-		    (unsigned int)tallies.RxUnicastFrames,
-		    (unsigned int)tallies.RxMulticastFrames,
-		    (unsigned int)tallies.RxFragments,
-		    (unsigned int)tallies.RxUnicastOctets,
-		    (unsigned int)tallies.RxMulticastOctets,
-		    (unsigned int)tallies.RxFCSErrors,
-		    (unsigned int)tallies.RxDiscardsNoBuffer,
-		    (unsigned int)tallies.TxDiscardsWrongSA,
-		    (unsigned int)tallies.RxWEPUndecryptable,
-		    (unsigned int)tallies.RxMsgInMsgFragments,
-		    (unsigned int)tallies.RxMsgInBadMsgFragments,
-		    (unsigned int)tallies.RxDiscardsWEPICVError,
-		    (unsigned int)tallies.RxDiscardsWEPExcluded);
-	    } else {
-		wl_unlock( lp, &flags );
-	    }
-    }
-
-    rcu_read_unlock();
-    return ret;
-}
-
-static DEVICE_ATTR(tallies, S_IRUGO, show_tallies, NULL);
-
-static struct attribute *wlags_attrs[] = {
-    &dev_attr_tallies.attr,
-    NULL
-};
-
-static struct attribute_group wlags_group = {
-    .name = "wlags",
-    .attrs = wlags_attrs,
-};
-
-void register_wlags_sysfs(struct net_device *net)
-{
-	struct device *dev = &(net->dev);
-	struct wl_private *lp = wl_priv(net);
-	int err;
-	err = sysfs_create_group(&dev->kobj, &wlags_group);
-	if (!err)
-		lp->sysfsCreated = true;
-}
-
-void unregister_wlags_sysfs(struct net_device *net)
-{
-	struct device *dev = &(net->dev);
-	struct wl_private *lp = wl_priv(net);
-
-	if (lp->sysfsCreated)
-		sysfs_remove_group(&dev->kobj, &wlags_group);
-}
diff --git a/drivers/staging/wlags49_h2/wl_sysfs.h b/drivers/staging/wlags49_h2/wl_sysfs.h
deleted file mode 100644
index fa658c3..0000000
--- a/drivers/staging/wlags49_h2/wl_sysfs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifdef CONFIG_SYSFS
-extern void register_wlags_sysfs(struct net_device *);
-extern void unregister_wlags_sysfs(struct net_device *);
-#else
-static inline void register_wlags_sysfs(struct net_device *net) { }
-static inline void unregister_wlags_sysfs(struct net_device *net) { }
-#endif
diff --git a/drivers/staging/wlags49_h25/Makefile b/drivers/staging/wlags49_h25/Makefile
index 6e0159d..513ba01 100644
--- a/drivers/staging/wlags49_h25/Makefile
+++ b/drivers/staging/wlags49_h25/Makefile
@@ -50,6 +50,3 @@
 		mmd.o \
 		hcf.o \
 		dhf.o
-
-$(WLNAME)-$(CONFIG_SYSFS)	+= wl_sysfs.o
-
diff --git a/drivers/staging/wlags49_h25/wl_sysfs.c b/drivers/staging/wlags49_h25/wl_sysfs.c
deleted file mode 100644
index 6458ee6..0000000
--- a/drivers/staging/wlags49_h25/wl_sysfs.c
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Use common source from wlags49_h2 */
-#include "../wlags49_h2/wl_sysfs.c"
diff --git a/drivers/staging/wlags49_h25/wl_sysfs.h b/drivers/staging/wlags49_h25/wl_sysfs.h
deleted file mode 100644
index eb819a5..0000000
--- a/drivers/staging/wlags49_h25/wl_sysfs.h
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Use common source from wlags49_h2 */
-#include "../wlags49_h2/wl_sysfs.h"
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 801ac40..3b3e17d 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -60,7 +60,7 @@
 
 static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
 		struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned char modeno, unsigned char rateindex)
+		unsigned char modeno)
 {
 	unsigned short ModeNo = modeno;
 	unsigned short ModeIdIndex = 0, ClockIndex = 0;
@@ -68,7 +68,7 @@
 	int Clock;
 	InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
 
-	XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
+	XGI_SearchModeID(ModeNo, &ModeIdIndex);
 
 	RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
 			ModeIdIndex, XGI_Pr);
@@ -82,7 +82,7 @@
 
 static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
 		struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned char modeno, unsigned char rateindex,
+		unsigned char modeno,
 		u32 *left_margin, u32 *right_margin, u32 *upper_margin,
 		u32 *lower_margin, u32 *hsync_len, u32 *vsync_len, u32 *sync,
 		u32 *vmode)
@@ -96,7 +96,7 @@
 	unsigned char sr_data, cr_data, cr_data2;
 	int B, C, D, F, temp, j;
 	InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
-	if (!XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr))
+	if (!XGI_SearchModeID(ModeNo, &ModeIdIndex))
 		return 0;
 	RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
 			ModeIdIndex, XGI_Pr);
@@ -1980,12 +1980,10 @@
 	fb_info->var.pixclock = (u32) (1000000000 /
 			XGIfb_mode_rate_to_dclock(&xgifb_info->dev_info,
 				hw_info,
-				XGIbios_mode[xgifb_info->mode_idx].mode_no,
-				xgifb_info->rate_idx));
+				XGIbios_mode[xgifb_info->mode_idx].mode_no));
 
 	if (XGIfb_mode_rate_to_ddata(&xgifb_info->dev_info, hw_info,
 		XGIbios_mode[xgifb_info->mode_idx].mode_no,
-		xgifb_info->rate_idx,
 		&fb_info->var.left_margin,
 		&fb_info->var.right_margin,
 		&fb_info->var.upper_margin,
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 5f1c41e..2154172 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -102,10 +102,8 @@
 	xgifb_reg_set(P3c4, 0x1B, 0x00);
 }
 
-static void XGINew_SetMemoryClock(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGINew_SetMemoryClock(struct vb_device_info *pVBInfo)
 {
-
 	xgifb_reg_set(pVBInfo->P3c4,
 		      0x28,
 		      pVBInfo->MCLKData[pVBInfo->ram_type].SR28);
@@ -133,7 +131,7 @@
 {
 	unsigned long P3d4 = P3c4 + 0x10;
 	pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo);
-	XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+	XGINew_SetMemoryClock(pVBInfo);
 
 	/* Set Double Frequency */
 	xgifb_reg_set(P3d4, 0x97, pVBInfo->XGINew_CR97); /* CR97 */
@@ -206,7 +204,7 @@
 	unsigned long P3d4 = P3c4 + 0x10;
 
 	pVBInfo->ram_type = XGINew_GetXG20DRAMType(HwDeviceExtension, pVBInfo);
-	XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+	XGINew_SetMemoryClock(pVBInfo);
 
 	xgifb_reg_set(P3d4, 0x97, 0x11); /* CR97 */
 
@@ -280,7 +278,7 @@
 	unsigned long P3d4 = Port, P3c4 = Port - 0x10;
 
 	if (HwDeviceExtension->jChipType >= XG20) {
-		XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+		XGINew_SetMemoryClock(pVBInfo);
 		xgifb_reg_set(P3d4,
 			      0x82,
 			      pVBInfo->CR40[11][pVBInfo->ram_type]); /* CR82 */
@@ -296,7 +294,7 @@
 
 		XGINew_DDR1x_MRS_XG20(P3c4, pVBInfo);
 	} else {
-		XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
+		XGINew_SetMemoryClock(pVBInfo);
 
 		switch (HwDeviceExtension->jChipType) {
 		case XG42:
@@ -876,8 +874,7 @@
 	return rom_copy;
 }
 
-static bool xgifb_read_vbios(struct pci_dev *pdev,
-			      struct vb_device_info *pVBInfo)
+static bool xgifb_read_vbios(struct pci_dev *pdev)
 {
 	struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
 	u8 *vbios;
@@ -948,8 +945,7 @@
 	return false;
 }
 
-static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGINew_ChkSenseStatus(struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx = 0, temp, tempcx, CR3CData;
 
@@ -991,8 +987,7 @@
 	xgifb_reg_set(pVBInfo->P3d4, 0x3e, ((tempbx & 0xFF00) >> 8));
 }
 
-static void XGINew_SetModeScratch(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGINew_SetModeScratch(struct vb_device_info *pVBInfo)
 {
 	unsigned short temp, tempcl = 0, tempch = 0, CR31Data, CR38Data;
 
@@ -1102,7 +1097,7 @@
 	struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
 	unsigned char Temp;
 
-	if (xgifb_read_vbios(pdev, pVBInfo)) { /* For XG21 LVDS */
+	if (xgifb_read_vbios(pdev)) { /* For XG21 LVDS */
 		xgifb_reg_or(pVBInfo->P3d4, 0x32, LCDSense);
 		/* LVDS on chip */
 		xgifb_reg_and_or(pVBInfo->P3d4, 0x38, ~0xE0, 0xC0);
@@ -1126,8 +1121,7 @@
 	}
 }
 
-static void XGINew_GetXG27Sense(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGINew_GetXG27Sense(struct vb_device_info *pVBInfo)
 {
 	unsigned char Temp, bCR4A;
 
@@ -1222,7 +1216,7 @@
 		XGINew_GetXG21Sense(pdev, pVBInfo);
 
 	if (HwDeviceExtension->jChipType == XG27)
-		XGINew_GetXG27Sense(HwDeviceExtension, pVBInfo);
+		XGINew_GetXG27Sense(pVBInfo);
 
 	/* Reset Extended register */
 
@@ -1294,7 +1288,7 @@
 
 	if (HwDeviceExtension->jChipType < XG20) {
 		/* Set VB */
-		XGI_UnLockCRT2(HwDeviceExtension, pVBInfo);
+		XGI_UnLockCRT2(pVBInfo);
 		/* disable VideoCapture */
 		xgifb_reg_and_or(pVBInfo->Part0Port, 0x3F, 0xEF, 0x00);
 		xgifb_reg_set(pVBInfo->Part1Port, 0x00, 0x00);
@@ -1334,7 +1328,7 @@
 			xgifb_reg_set(pVBInfo->Part4Port,
 				      0x10, XGI330_CRT2Data_4_10);
 			xgifb_reg_set(pVBInfo->Part4Port, 0x0F, 0x3F);
-			XGI_LockCRT2(HwDeviceExtension, pVBInfo);
+			XGI_LockCRT2(pVBInfo);
 		}
 	} /* != XG20 */
 
@@ -1370,8 +1364,8 @@
 	xgifb_reg_set(pVBInfo->P3c4, 0x22, 0xfa);
 	xgifb_reg_set(pVBInfo->P3c4, 0x21, 0xa3);
 
-	XGINew_ChkSenseStatus(HwDeviceExtension, pVBInfo);
-	XGINew_SetModeScratch(HwDeviceExtension, pVBInfo);
+	XGINew_ChkSenseStatus(pVBInfo);
+	XGINew_SetModeScratch(pVBInfo);
 
 	xgifb_reg_set(pVBInfo->P3d4, 0x8c, 0x87);
 
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index fcefe5b..46dea3f 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -63,9 +63,7 @@
 
 }
 
-static void XGI_SetSeqRegs(unsigned short ModeNo,
-			   unsigned short ModeIdIndex,
-			   struct vb_device_info *pVBInfo)
+static void XGI_SetSeqRegs(struct vb_device_info *pVBInfo)
 {
 	unsigned char SRdata, i;
 
@@ -79,8 +77,7 @@
 	}
 }
 
-static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
-			    struct vb_device_info *pVBInfo)
+static void XGI_SetCRTCRegs(struct vb_device_info *pVBInfo)
 {
 	unsigned char CRTCdata;
 	unsigned short i;
@@ -96,8 +93,7 @@
 	}
 }
 
-static void XGI_SetATTRegs(unsigned short ModeNo,
-			   unsigned short ModeIdIndex,
+static void XGI_SetATTRegs(unsigned short ModeIdIndex,
 			   struct vb_device_info *pVBInfo)
 {
 	unsigned char ARdata;
@@ -171,8 +167,7 @@
 	return 0;
 }
 
-static unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo,
-		unsigned short ModeIdIndex,
+static unsigned char XGI_AjustCRT2Rate(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex, unsigned short *i,
 		struct vb_device_info *pVBInfo)
 {
@@ -322,7 +317,6 @@
 }
 
 static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex,
-				unsigned short ModeNo,
 				struct vb_device_info *pVBInfo)
 {
 	unsigned char data;
@@ -365,7 +359,7 @@
 	xgifb_reg_set(pVBInfo->P3d4, 0x09, data);
 }
 
-static void XGI_SetCRT1CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT1CRTC(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo,
 		struct xgi_hw_device_info *HwDeviceExtension)
@@ -391,7 +385,7 @@
 
 	XGI_SetCRT1Timing_H(pVBInfo, HwDeviceExtension);
 
-	XGI_SetCRT1Timing_V(ModeIdIndex, ModeNo, pVBInfo);
+	XGI_SetCRT1Timing_V(ModeIdIndex, pVBInfo);
 
 	if (pVBInfo->ModeType > 0x03)
 		xgifb_reg_set(pVBInfo->P3d4, 0x14, 0x4F);
@@ -403,8 +397,7 @@
 /* Output : Fill CRT Hsync/Vsync to SR2E/SR2F/SR30/SR33/SR34/SR3F */
 /* Description : Set LCD timing */
 /* --------------------------------------------------------------------- */
-static void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
+static void XGI_SetXG21CRTC(unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned char index, Tempax, Tempbx, Tempcx, Tempdx;
@@ -500,9 +493,7 @@
 	xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
 }
 
-static void XGI_SetXG27CRTC(unsigned short ModeNo,
-			    unsigned short ModeIdIndex,
-			    unsigned short RefreshRateTableIndex,
+static void XGI_SetXG27CRTC(unsigned short RefreshRateTableIndex,
 			    struct vb_device_info *pVBInfo)
 {
 	unsigned short index, Tempax, Tempbx, Tempcx;
@@ -605,8 +596,7 @@
 
 static void xgifb_set_lcd(int chip_id,
 			  struct vb_device_info *pVBInfo,
-			  unsigned short RefreshRateTableIndex,
-			  unsigned short ModeNo)
+			  unsigned short RefreshRateTableIndex)
 {
 	unsigned short temp;
 
@@ -687,8 +677,7 @@
 	}
 }
 
-static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT1DE(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
@@ -834,10 +823,8 @@
 	xgifb_reg_set(pVBInfo->P3c4, 0x10, ah);
 }
 
-static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
-		unsigned short ModeIdIndex,
+static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short VCLKIndex, modeflag;
@@ -886,8 +873,7 @@
 	return VCLKIndex;
 }
 
-static void XGI_SetCRT1VCLK(unsigned short ModeNo,
-			    unsigned short ModeIdIndex,
+static void XGI_SetCRT1VCLK(unsigned short ModeIdIndex,
 			    struct xgi_hw_device_info *HwDeviceExtension,
 			    unsigned short RefreshRateTableIndex,
 			    struct vb_device_info *pVBInfo)
@@ -899,9 +885,8 @@
 	    (pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV |
 				VB_SIS302LV | VB_XGI301C)) &&
 	    (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) {
-		vclkindex = XGI_GetVCLK2Ptr(ModeNo, ModeIdIndex,
-				RefreshRateTableIndex, HwDeviceExtension,
-				pVBInfo);
+		vclkindex = XGI_GetVCLK2Ptr(ModeIdIndex, RefreshRateTableIndex,
+					    pVBInfo);
 		data = xgifb_reg_get(pVBInfo->P3c4, 0x31) & 0xCF;
 		xgifb_reg_set(pVBInfo->P3c4, 0x31, data);
 		data = XGI_VBVCLKData[vclkindex].Part4_A;
@@ -948,9 +933,8 @@
 
 }
 
-static void XGI_SetCRT1FIFO(unsigned short ModeNo,
-		struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGI_SetCRT1FIFO(struct xgi_hw_device_info *HwDeviceExtension,
+			    struct vb_device_info *pVBInfo)
 {
 	unsigned short data;
 
@@ -971,7 +955,7 @@
 }
 
 static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned short ModeNo, unsigned short RefreshRateTableIndex,
+		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short data, data2 = 0;
@@ -1010,7 +994,7 @@
 }
 
 static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned short ModeNo, unsigned short ModeIdIndex,
+		unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
@@ -1063,8 +1047,7 @@
 	data = data ^ 0xA0;
 	xgifb_reg_and_or(pVBInfo->P3c4, 0x21, 0x1F, data);
 
-	XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex,
-			pVBInfo);
+	XGI_SetVCLKState(HwDeviceExtension, RefreshRateTableIndex, pVBInfo);
 
 	data = xgifb_reg_get(pVBInfo->P3d4, 0x31);
 
@@ -1122,8 +1105,7 @@
 	outb((unsigned short) bl, pVBInfo->P3c9);
 }
 
-static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct vb_device_info *pVBInfo)
+static void XGI_LoadDAC(struct vb_device_info *pVBInfo)
 {
 	unsigned short data, data2, i, k, m, n, o, si, di, bx, dl, al, ah, dh;
 	const unsigned short *table = XGINew_VGA_DAC;
@@ -1188,8 +1170,7 @@
 	}
 }
 
-static void XGI_GetLVDSResInfo(unsigned short ModeNo,
-			       unsigned short ModeIdIndex,
+static void XGI_GetLVDSResInfo(unsigned short ModeIdIndex,
 			       struct vb_device_info *pVBInfo)
 {
 	unsigned short resindex, xres, yres, modeflag;
@@ -1219,9 +1200,7 @@
 }
 
 static void const *XGI_GetLcdPtr(struct XGI330_LCDDataTablStruct const *table,
-		unsigned short ModeNo,
 		unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short i, tempdx, tempbx, modeflag;
@@ -1259,8 +1238,7 @@
 	return table[i].DATAPTR;
 }
 
-static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeNo,
-		unsigned short ModeIdIndex,
+static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
@@ -1289,17 +1267,15 @@
 	return &XGI_TVDataTable[i].DATAPTR[tempal];
 }
 
-static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
-		struct vb_device_info *pVBInfo)
+static void XGI_GetLVDSData(unsigned short ModeIdIndex,
+			    struct vb_device_info *pVBInfo)
 {
 	struct SiS_LVDSData const *LCDPtr;
 
 	if (!(pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)))
 		return;
 
-	LCDPtr = XGI_GetLcdPtr(XGI_EPLLCDDataPtr, ModeNo, ModeIdIndex,
-			       RefreshRateTableIndex, pVBInfo);
+	LCDPtr = XGI_GetLcdPtr(XGI_EPLLCDDataPtr, ModeIdIndex, pVBInfo);
 	pVBInfo->VGAHT	= LCDPtr->VGAHT;
 	pVBInfo->VGAVT	= LCDPtr->VGAVT;
 	pVBInfo->HT	= LCDPtr->LCDHT;
@@ -1325,18 +1301,17 @@
 	}
 }
 
-static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGI_ModCRT1Regs(unsigned short ModeIdIndex,
+			    struct xgi_hw_device_info *HwDeviceExtension,
+			    struct vb_device_info *pVBInfo)
 {
 	unsigned short i;
 	struct XGI_LVDSCRT1HDataStruct const *LCDPtr = NULL;
 	struct XGI_LVDSCRT1VDataStruct const *LCDPtr1 = NULL;
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr = XGI_GetLcdPtr(xgifb_epllcd_crt1_h, ModeNo, ModeIdIndex,
-				       RefreshRateTableIndex, pVBInfo);
+		LCDPtr = XGI_GetLcdPtr(xgifb_epllcd_crt1_h, ModeIdIndex,
+				       pVBInfo);
 
 		for (i = 0; i < 8; i++)
 			pVBInfo->TimingH.data[i] = LCDPtr[0].Reg[i];
@@ -1345,14 +1320,13 @@
 	XGI_SetCRT1Timing_H(pVBInfo, HwDeviceExtension);
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr1 = XGI_GetLcdPtr(xgifb_epllcd_crt1_v, ModeNo,
-					ModeIdIndex, RefreshRateTableIndex,
+		LCDPtr1 = XGI_GetLcdPtr(xgifb_epllcd_crt1_v, ModeIdIndex,
 					pVBInfo);
 		for (i = 0; i < 7; i++)
 			pVBInfo->TimingV.data[i] = LCDPtr1[0].Reg[i];
 	}
 
-	XGI_SetCRT1Timing_V(ModeIdIndex, ModeNo, pVBInfo);
+	XGI_SetCRT1Timing_V(ModeIdIndex, pVBInfo);
 }
 
 static unsigned short XGI_GetLCDCapPtr(struct vb_device_info *pVBInfo)
@@ -1425,17 +1399,15 @@
 	*VSyncWidth = pVBInfo->LCDCapList[Index].LCD_VSyncWidth;
 }
 
-static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
-		struct vb_device_info *pVBInfo)
+static void XGI_SetLVDSRegs(unsigned short ModeIdIndex,
+			    struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx, tempax, tempcx, tempdx, push1, push2, modeflag;
 	unsigned long temp, temp1, temp2, temp3, push3;
 	struct XGI330_LCDDataDesStruct2 const *LCDPtr1 = NULL;
 
 	modeflag = XGI330_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-	LCDPtr1 = XGI_GetLcdPtr(XGI_EPLLCDDesDataPtr, ModeNo, ModeIdIndex,
-					RefreshRateTableIndex, pVBInfo);
+	LCDPtr1 = XGI_GetLcdPtr(XGI_EPLLCDDesDataPtr, ModeIdIndex, pVBInfo);
 
 	XGI_GetLCDSync(&tempax, &tempbx, pVBInfo);
 	push1 = tempbx;
@@ -1686,8 +1658,7 @@
 }
 
 static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
-		unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct vb_device_info *pVBInfo)
+		unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
 {
 
 	unsigned short index, modeflag;
@@ -1769,15 +1740,14 @@
 	}
 }
 
-static void XGI_SetCRT2ECLK(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT2ECLK(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned char di_0, di_1, tempal;
 	int i;
 
-	tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeNo, ModeIdIndex,
-			pVBInfo);
+	tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeIdIndex, pVBInfo);
 	XGI_GetVCLKLen(tempal, &di_0, &di_1, pVBInfo);
 	XGI_GetLCDVCLKPtr(&di_0, &di_1, pVBInfo);
 
@@ -1795,8 +1765,7 @@
 	}
 }
 
-static void XGI_UpdateModeInfo(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGI_UpdateModeInfo(struct vb_device_info *pVBInfo)
 {
 	unsigned short tempcl, tempch, temp, tempbl, tempax;
 
@@ -1922,8 +1891,7 @@
 	pVBInfo->VBType = tempbx;
 }
 
-static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
+static void XGI_GetVBInfo(unsigned short ModeIdIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short tempax, push, tempbx, temp, modeflag;
@@ -2048,7 +2016,7 @@
 	pVBInfo->VBInfo = tempbx;
 }
 
-static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_GetTVInfo(unsigned short ModeIdIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx = 0, resinfo = 0, modeflag, index1;
@@ -2115,8 +2083,8 @@
 	pVBInfo->TVInfo = tempbx;
 }
 
-static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
-		unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
+static unsigned char XGI_GetLCDInfo(unsigned short ModeIdIndex,
+				    struct vb_device_info *pVBInfo)
 {
 	unsigned short temp, tempax, tempbx, resinfo = 0, LCDIdIndex;
 
@@ -2196,7 +2164,7 @@
 }
 
 unsigned char XGI_SearchModeID(unsigned short ModeNo,
-		unsigned short *ModeIdIndex, struct vb_device_info *pVBInfo)
+			       unsigned short *ModeIdIndex)
 {
 	for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
 		if (XGI330_EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo)
@@ -2435,8 +2403,7 @@
 	xgifb_reg_and_or(pVBInfo->P3d4, 0x31, temp2, temp1);
 }
 
-static void XGI_GetCRT2ResInfo(unsigned short ModeNo,
-			       unsigned short ModeIdIndex,
+static void XGI_GetCRT2ResInfo(unsigned short ModeIdIndex,
 			       struct vb_device_info *pVBInfo)
 {
 	unsigned short xres, yres, modeflag, resindex;
@@ -2508,8 +2475,7 @@
 	return 0;
 }
 
-static void XGI_GetRAMDAC2DATA(unsigned short ModeNo,
-			       unsigned short ModeIdIndex,
+static void XGI_GetRAMDAC2DATA(unsigned short ModeIdIndex,
 			       unsigned short RefreshRateTableIndex,
 			       struct vb_device_info *pVBInfo)
 {
@@ -2551,7 +2517,7 @@
 	pVBInfo->VT = tempbx;
 }
 
-static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_GetCRT2Data(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
@@ -2566,14 +2532,13 @@
 	pVBInfo->RVBHRS = 50;
 
 	if (pVBInfo->VBInfo & SetCRT2ToRAMDAC) {
-		XGI_GetRAMDAC2DATA(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-				pVBInfo);
+		XGI_GetRAMDAC2DATA(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
 		return;
 	}
 
 	if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) {
-		LCDPtr = XGI_GetLcdPtr(XGI_LCDDataTable, ModeNo, ModeIdIndex,
-				       RefreshRateTableIndex, pVBInfo);
+		LCDPtr = XGI_GetLcdPtr(XGI_LCDDataTable, ModeIdIndex,
+				       pVBInfo);
 
 		pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX;
 		pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT;
@@ -2654,7 +2619,7 @@
 	if (pVBInfo->VBInfo & (SetCRT2ToTV)) {
 		struct SiS_TVData const *TVPtr;
 
-		TVPtr = XGI_GetTVPtr(ModeNo, ModeIdIndex, RefreshRateTableIndex,
+		TVPtr = XGI_GetTVPtr(ModeIdIndex, RefreshRateTableIndex,
 				     pVBInfo);
 
 		pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX;
@@ -2722,14 +2687,13 @@
 	}
 }
 
-static void XGI_SetCRT2VCLK(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetCRT2VCLK(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned char di_0, di_1, tempal;
 
-	tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeNo, ModeIdIndex,
-			pVBInfo);
+	tempal = XGI_GetVCLKPtr(RefreshRateTableIndex, ModeIdIndex, pVBInfo);
 	XGI_GetVCLKLen(tempal, &di_0, &di_1, pVBInfo);
 	XGI_GetLCDVCLKPtr(&di_0, &di_1, pVBInfo);
 
@@ -2751,8 +2715,7 @@
 		xgifb_reg_or(pVBInfo->Part4Port, 0x12, 0x08);
 }
 
-static unsigned short XGI_GetColorDepth(unsigned short ModeNo,
-		unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
+static unsigned short XGI_GetColorDepth(unsigned short ModeIdIndex)
 {
 	unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
 	short index;
@@ -2769,9 +2732,7 @@
 
 static unsigned short XGI_GetOffset(unsigned short ModeNo,
 				    unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+		unsigned short RefreshRateTableIndex)
 {
 	unsigned short temp, colordepth, modeinfo, index, infoflag,
 			ColorDepth[] = { 0x01, 0x02, 0x04 };
@@ -2786,7 +2747,7 @@
 	if (infoflag & InterlaceMode)
 		temp = temp << 1;
 
-	colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+	colordepth = XGI_GetColorDepth(ModeIdIndex);
 
 	if ((ModeNo >= 0x7C) && (ModeNo <= 0x7E)) {
 		temp = ModeNo - 0x7C;
@@ -2801,7 +2762,6 @@
 static void XGI_SetCRT2Offset(unsigned short ModeNo,
 		unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short offset;
@@ -2810,8 +2770,7 @@
 	if (pVBInfo->VBInfo & SetInSlaveMode)
 		return;
 
-	offset = XGI_GetOffset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-			HwDeviceExtension, pVBInfo);
+	offset = XGI_GetOffset(ModeNo, ModeIdIndex, RefreshRateTableIndex);
 	temp = (unsigned char) (offset & 0xFF);
 	xgifb_reg_set(pVBInfo->Part1Port, 0x07, temp);
 	temp = (unsigned char) ((offset & 0xFF00) >> 8);
@@ -2829,14 +2788,12 @@
 }
 
 static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	u8 tempcx;
 
-	XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-			HwDeviceExtension, pVBInfo);
+	XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
 	XGI_SetCRT2FIFO(pVBInfo);
 
 	for (tempcx = 4; tempcx < 7; tempcx++)
@@ -2846,8 +2803,7 @@
 	xgifb_reg_set(pVBInfo->Part1Port, 0x02, 0x44); /* temp 0206 */
 }
 
-static void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
+static void XGI_SetGroup1(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
@@ -3002,8 +2958,6 @@
 }
 
 static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned short RefreshRateTableIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short push1, push2, tempax, tempbx = 0, tempcx, temp, resinfo,
@@ -3294,8 +3248,6 @@
 }
 
 static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex,
-		unsigned short RefreshRateTableIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short i, j, tempax, tempbx, tempcx, temp, push1, push2,
@@ -3724,9 +3676,7 @@
 	}
 }
 
-static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
-		unsigned short RefreshRateTableIndex,
+static void XGI_SetLCDRegs(unsigned short ModeIdIndex,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short pushbx, tempax, tempbx, tempcx, temp, tempah,
@@ -3772,11 +3722,10 @@
 
 	/* Customized LCDB Does not add */
 	if ((pVBInfo->VBType & VB_SIS301LV) || (pVBInfo->VBType & VB_SIS302LV))
-		LCDBDesPtr = XGI_GetLcdPtr(xgifb_lcddldes, ModeNo, ModeIdIndex,
-					   RefreshRateTableIndex, pVBInfo);
+		LCDBDesPtr = XGI_GetLcdPtr(xgifb_lcddldes, ModeIdIndex,
+					   pVBInfo);
 	else
-		LCDBDesPtr = XGI_GetLcdPtr(XGI_LCDDesDataTable, ModeNo,
-					   ModeIdIndex, RefreshRateTableIndex,
+		LCDBDesPtr = XGI_GetLcdPtr(XGI_LCDDesDataTable, ModeIdIndex,
 					   pVBInfo);
 
 	tempah = pVBInfo->LCDResInfo;
@@ -4003,8 +3952,8 @@
 		xgifb_reg_and_or(pVBInfo->Part2Port, 0x4E, ~0x14, 0x10);
 }
 
-static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct vb_device_info *pVBInfo)
+static void XGI_SetGroup3(unsigned short ModeIdIndex,
+			  struct vb_device_info *pVBInfo)
 {
 	unsigned short i;
 	unsigned char const *tempdi;
@@ -4059,9 +4008,8 @@
 	}
 }
 
-static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex,
+static void XGI_SetGroup4(unsigned short ModeIdIndex,
 		unsigned short RefreshRateTableIndex,
-		struct xgi_hw_device_info *HwDeviceExtension,
 		struct vb_device_info *pVBInfo)
 {
 	unsigned short tempax, tempcx, tempbx, modeflag, temp, temp2;
@@ -4224,7 +4172,7 @@
 	}
 	/* end 301b */
 
-	XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_SetCRT2VCLK(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
 }
 
 static void XGINew_EnableCRT2(struct vb_device_info *pVBInfo)
@@ -4232,8 +4180,7 @@
 	xgifb_reg_and_or(pVBInfo->P3c4, 0x1E, 0xFF, 0x20);
 }
 
-static void XGI_SetGroup5(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct vb_device_info *pVBInfo)
+static void XGI_SetGroup5(struct vb_device_info *pVBInfo)
 {
 	if (pVBInfo->ModeType == ModeVGA) {
 		if (!(pVBInfo->VBInfo & (SetInSlaveMode | LoadDACFlag
@@ -4243,16 +4190,13 @@
 	}
 }
 
-static void XGI_DisableGatingCRT(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGI_DisableGatingCRT(struct vb_device_info *pVBInfo)
 {
-
 	xgifb_reg_and_or(pVBInfo->P3d4, 0x63, 0xBF, 0x00);
 }
 
 static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
-		unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct vb_device_info *pVBInfo)
+		unsigned short ModeNo, unsigned short ModeIdIndex)
 {
 	unsigned short xres, yres, colordepth, modeflag, resindex;
 
@@ -4281,7 +4225,7 @@
 
 	if (xres != xgifb_info->lvds_data.LVDSHDE ||
 	    yres != xgifb_info->lvds_data.LVDSVDE) {
-		colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+		colordepth = XGI_GetColorDepth(ModeIdIndex);
 		if (colordepth > 2)
 			return 0;
 	}
@@ -4290,7 +4234,6 @@
 
 static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
 			   int chip_id,
-			   unsigned short ModeNo,
 			   unsigned short ModeIdIndex,
 			   struct vb_device_info *pVBInfo)
 {
@@ -4831,9 +4774,7 @@
 /* Output : */
 /* Description : Set TV Customized Param. */
 /* --------------------------------------------------------------------- */
-static void XGI_SetAntiFlicker(unsigned short ModeNo,
-			       unsigned short ModeIdIndex,
-			       struct vb_device_info *pVBInfo)
+static void XGI_SetAntiFlicker(struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx;
 
@@ -4850,9 +4791,7 @@
 	xgifb_reg_and_or(pVBInfo->Part2Port, 0x0A, 0x8F, tempah);
 }
 
-static void XGI_SetEdgeEnhance(unsigned short ModeNo,
-			       unsigned short ModeIdIndex,
-			       struct vb_device_info *pVBInfo)
+static void XGI_SetEdgeEnhance(struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx;
 
@@ -4887,8 +4826,8 @@
 			& 0xFF000000) >> 24));
 }
 
-static void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex,
-		struct vb_device_info *pVBInfo)
+static void XGI_SetYFilter(unsigned short ModeIdIndex,
+			   struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbx, index;
 	unsigned char const *filterPtr;
@@ -4957,8 +4896,7 @@
 /* Output : */
 /* Description : Customized Param. for 301 */
 /* --------------------------------------------------------------------- */
-static void XGI_OEM310Setting(unsigned short ModeNo,
-			      unsigned short ModeIdIndex,
+static void XGI_OEM310Setting(unsigned short ModeIdIndex,
 			      struct vb_device_info *pVBInfo)
 {
 	XGI_SetDelayComp(pVBInfo);
@@ -4968,11 +4906,11 @@
 
 	if (pVBInfo->VBInfo & SetCRT2ToTV) {
 		XGI_SetPhaseIncr(pVBInfo);
-		XGI_SetYFilter(ModeNo, ModeIdIndex, pVBInfo);
-		XGI_SetAntiFlicker(ModeNo, ModeIdIndex, pVBInfo);
+		XGI_SetYFilter(ModeIdIndex, pVBInfo);
+		XGI_SetAntiFlicker(pVBInfo);
 
 		if (pVBInfo->VBType & VB_SIS301)
-			XGI_SetEdgeEnhance(ModeNo, ModeIdIndex, pVBInfo);
+			XGI_SetEdgeEnhance(pVBInfo);
 	}
 }
 
@@ -4982,9 +4920,7 @@
 /* Output : */
 /* Description : Origin code for crt2group */
 /* --------------------------------------------------------------------- */
-static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
-		struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+static void XGI_SetCRT2ModeRegs(struct vb_device_info *pVBInfo)
 {
 	unsigned short tempbl;
 	short tempcl;
@@ -5146,20 +5082,14 @@
 }
 
 
-void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+void XGI_UnLockCRT2(struct vb_device_info *pVBInfo)
 {
-
 	xgifb_reg_and_or(pVBInfo->Part1Port, 0x2f, 0xFF, 0x01);
-
 }
 
-void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
-		struct vb_device_info *pVBInfo)
+void XGI_LockCRT2(struct vb_device_info *pVBInfo)
 {
-
 	xgifb_reg_and_or(pVBInfo->Part1Port, 0x2F, 0xFE, 0x00);
-
 }
 
 unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
@@ -5231,8 +5161,8 @@
 	}
 	i--;
 	if ((pVBInfo->SetFlag & ProgrammingCRT2)) {
-		temp = XGI_AjustCRT2Rate(ModeNo, ModeIdIndex,
-				RefreshRateTableIndex, &i, pVBInfo);
+		temp = XGI_AjustCRT2Rate(ModeIdIndex, RefreshRateTableIndex,
+					 &i, pVBInfo);
 	}
 	return RefreshRateTableIndex + i;
 }
@@ -5246,12 +5176,11 @@
 	pVBInfo->SetFlag |= ProgrammingCRT2;
 	RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
 			ModeIdIndex, pVBInfo);
-	XGI_GetLVDSResInfo(ModeNo, ModeIdIndex, pVBInfo);
-	XGI_GetLVDSData(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
-	XGI_ModCRT1Regs(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-			HwDeviceExtension, pVBInfo);
-	XGI_SetLVDSRegs(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
-	XGI_SetCRT2ECLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_GetLVDSResInfo(ModeIdIndex, pVBInfo);
+	XGI_GetLVDSData(ModeIdIndex, pVBInfo);
+	XGI_ModCRT1Regs(ModeIdIndex, HwDeviceExtension, pVBInfo);
+	XGI_SetLVDSRegs(ModeIdIndex, pVBInfo);
+	XGI_SetCRT2ECLK(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
 }
 
 static unsigned char XGI_SetCRT2Group301(unsigned short ModeNo,
@@ -5261,29 +5190,23 @@
 	unsigned short ModeIdIndex, RefreshRateTableIndex;
 
 	pVBInfo->SetFlag |= ProgrammingCRT2;
-	XGI_SearchModeID(ModeNo, &ModeIdIndex, pVBInfo);
+	XGI_SearchModeID(ModeNo, &ModeIdIndex);
 	pVBInfo->SelectCRT2Rate = 4;
 	RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
 			ModeIdIndex, pVBInfo);
 	XGI_SaveCRT2Info(ModeNo, pVBInfo);
-	XGI_GetCRT2ResInfo(ModeNo, ModeIdIndex, pVBInfo);
-	XGI_GetCRT2Data(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
-	XGI_PreSetGroup1(ModeNo, ModeIdIndex, HwDeviceExtension,
-			RefreshRateTableIndex, pVBInfo);
-	XGI_SetGroup1(ModeNo, ModeIdIndex, HwDeviceExtension,
-			RefreshRateTableIndex, pVBInfo);
-	XGI_SetLockRegs(ModeNo, ModeIdIndex, HwDeviceExtension,
-			RefreshRateTableIndex, pVBInfo);
-	XGI_SetGroup2(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-			HwDeviceExtension, pVBInfo);
-	XGI_SetLCDRegs(ModeNo, ModeIdIndex, HwDeviceExtension,
-			RefreshRateTableIndex, pVBInfo);
+	XGI_GetCRT2ResInfo(ModeIdIndex, pVBInfo);
+	XGI_GetCRT2Data(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_PreSetGroup1(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_SetGroup1(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_SetLockRegs(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetGroup2(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetLCDRegs(ModeIdIndex, pVBInfo);
 	XGI_SetTap4Regs(pVBInfo);
-	XGI_SetGroup3(ModeNo, ModeIdIndex, pVBInfo);
-	XGI_SetGroup4(ModeNo, ModeIdIndex, RefreshRateTableIndex,
-			HwDeviceExtension, pVBInfo);
-	XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo);
-	XGI_SetGroup5(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetGroup3(ModeIdIndex, pVBInfo);
+	XGI_SetGroup4(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_SetCRT2VCLK(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
+	XGI_SetGroup5(pVBInfo);
 	XGI_AutoThreshold(pVBInfo);
 	return 1;
 }
@@ -5442,7 +5365,7 @@
 		/* EnablePart4_1F */
 		xgifb_reg_or(pVBInfo->Part4Port, 0x1F, tempah);
 
-		XGI_DisableGatingCRT(HwDeviceExtension, pVBInfo);
+		XGI_DisableGatingCRT(pVBInfo);
 		XGI_DisplayOn(xgifb_info, HwDeviceExtension, pVBInfo);
 	} /* 301 */
 	else { /* LVDS */
@@ -5467,10 +5390,10 @@
 {
 	unsigned short RefreshRateTableIndex, temp;
 
-	XGI_SetSeqRegs(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetSeqRegs(pVBInfo);
 	outb(XGI330_StandTable.MISC, pVBInfo->P3c2);
-	XGI_SetCRTCRegs(HwDeviceExtension, pVBInfo);
-	XGI_SetATTRegs(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetCRTCRegs(pVBInfo);
+	XGI_SetATTRegs(ModeIdIndex, pVBInfo);
 	XGI_SetGRCRegs(pVBInfo);
 	XGI_ClearExt1Regs(pVBInfo);
 
@@ -5495,13 +5418,12 @@
 			ModeIdIndex, pVBInfo);
 	if (RefreshRateTableIndex != 0xFFFF) {
 		XGI_SetSync(RefreshRateTableIndex, pVBInfo);
-		XGI_SetCRT1CRTC(ModeNo, ModeIdIndex, RefreshRateTableIndex,
+		XGI_SetCRT1CRTC(ModeIdIndex, RefreshRateTableIndex,
 				pVBInfo, HwDeviceExtension);
-		XGI_SetCRT1DE(HwDeviceExtension, ModeNo, ModeIdIndex,
-				RefreshRateTableIndex, pVBInfo);
+		XGI_SetCRT1DE(ModeIdIndex, RefreshRateTableIndex, pVBInfo);
 		XGI_SetCRT1Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
 				HwDeviceExtension, pVBInfo);
-		XGI_SetCRT1VCLK(ModeNo, ModeIdIndex, HwDeviceExtension,
+		XGI_SetCRT1VCLK(ModeIdIndex, HwDeviceExtension,
 				RefreshRateTableIndex, pVBInfo);
 	}
 
@@ -5510,30 +5432,28 @@
 		if (temp & 0xA0) {
 
 			if (HwDeviceExtension->jChipType == XG27)
-				XGI_SetXG27CRTC(ModeNo, ModeIdIndex,
-						RefreshRateTableIndex, pVBInfo);
+				XGI_SetXG27CRTC(RefreshRateTableIndex, pVBInfo);
 			else
-				XGI_SetXG21CRTC(ModeNo, ModeIdIndex,
-						RefreshRateTableIndex, pVBInfo);
+				XGI_SetXG21CRTC(RefreshRateTableIndex, pVBInfo);
 
 			XGI_UpdateXG21CRTC(ModeNo, pVBInfo,
 					RefreshRateTableIndex);
 
 			xgifb_set_lcd(HwDeviceExtension->jChipType,
-					pVBInfo, RefreshRateTableIndex, ModeNo);
+				      pVBInfo, RefreshRateTableIndex);
 
 			if (pVBInfo->IF_DEF_LVDS == 1)
 				xgifb_set_lvds(xgifb_info,
 						HwDeviceExtension->jChipType,
-						ModeNo, ModeIdIndex, pVBInfo);
+						ModeIdIndex, pVBInfo);
 		}
 	}
 
 	pVBInfo->SetFlag &= (~ProgrammingCRT2);
-	XGI_SetCRT1FIFO(ModeNo, HwDeviceExtension, pVBInfo);
-	XGI_SetCRT1ModeRegs(HwDeviceExtension, ModeNo, ModeIdIndex,
-			RefreshRateTableIndex, pVBInfo);
-	XGI_LoadDAC(ModeNo, ModeIdIndex, pVBInfo);
+	XGI_SetCRT1FIFO(HwDeviceExtension, pVBInfo);
+	XGI_SetCRT1ModeRegs(HwDeviceExtension, ModeIdIndex,
+			    RefreshRateTableIndex, pVBInfo);
+	XGI_LoadDAC(pVBInfo);
 }
 
 unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
@@ -5568,14 +5488,14 @@
 	xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86);
 
 	if (HwDeviceExtension->jChipType < XG20)
-		XGI_UnLockCRT2(HwDeviceExtension, pVBInfo);
+		XGI_UnLockCRT2(pVBInfo);
 
-	XGI_SearchModeID(ModeNo, &ModeIdIndex, pVBInfo);
+	XGI_SearchModeID(ModeNo, &ModeIdIndex);
 
 	if (HwDeviceExtension->jChipType < XG20) {
-		XGI_GetVBInfo(ModeNo, ModeIdIndex, HwDeviceExtension, pVBInfo);
-		XGI_GetTVInfo(ModeNo, ModeIdIndex, pVBInfo);
-		XGI_GetLCDInfo(ModeNo, ModeIdIndex, pVBInfo);
+		XGI_GetVBInfo(ModeIdIndex, pVBInfo);
+		XGI_GetTVInfo(ModeIdIndex, pVBInfo);
+		XGI_GetLCDInfo(ModeIdIndex, pVBInfo);
 		XGI_DisableBridge(xgifb_info, HwDeviceExtension, pVBInfo);
 
 		if (pVBInfo->VBInfo & (SetSimuScanMode | XGI_SetCRT2ToLCDA) ||
@@ -5602,15 +5522,14 @@
 			}
 		}
 
-		XGI_SetCRT2ModeRegs(ModeNo, HwDeviceExtension, pVBInfo);
-		XGI_OEM310Setting(ModeNo, ModeIdIndex, pVBInfo); /*0212*/
+		XGI_SetCRT2ModeRegs(pVBInfo);
+		XGI_OEM310Setting(ModeIdIndex, pVBInfo); /*0212*/
 		XGI_EnableBridge(xgifb_info, HwDeviceExtension, pVBInfo);
 	} /* !XG20 */
 	else {
 		if (pVBInfo->IF_DEF_LVDS == 1)
 			if (!XGI_XG21CheckLVDSMode(xgifb_info, ModeNo,
-						   ModeIdIndex,
-						   pVBInfo))
+						   ModeIdIndex))
 				return 0;
 
 		pVBInfo->ModeType = XGI330_EModeIDTable[ModeIdIndex].
@@ -5627,10 +5546,10 @@
 		XGI_DisplayOn(xgifb_info, HwDeviceExtension, pVBInfo);
 	}
 
-	XGI_UpdateModeInfo(HwDeviceExtension, pVBInfo);
+	XGI_UpdateModeInfo(pVBInfo);
 
 	if (HwDeviceExtension->jChipType < XG20)
-		XGI_LockCRT2(HwDeviceExtension, pVBInfo);
+		XGI_LockCRT2(pVBInfo);
 
 	return 1;
 }
diff --git a/drivers/staging/xgifb/vb_setmode.h b/drivers/staging/xgifb/vb_setmode.h
index 2c0a31c..5301bec 100644
--- a/drivers/staging/xgifb/vb_setmode.h
+++ b/drivers/staging/xgifb/vb_setmode.h
@@ -2,10 +2,8 @@
 #define _VBSETMODE_
 
 extern void InitTo330Pointer(unsigned char, struct vb_device_info *);
-extern void XGI_UnLockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
-			   struct vb_device_info *);
-extern void XGI_LockCRT2(struct xgi_hw_device_info *HwDeviceExtension,
-			 struct vb_device_info *);
+extern void XGI_UnLockCRT2(struct vb_device_info *);
+extern void XGI_LockCRT2(struct vb_device_info *);
 extern void XGI_DisplayOff(struct xgifb_video_info *,
 			   struct xgi_hw_device_info *,
 			   struct vb_device_info *);
@@ -13,11 +11,10 @@
 extern void XGI_SenseCRT1(struct vb_device_info *);
 extern unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
 				   struct xgi_hw_device_info *HwDeviceExtension,
-				   unsigned short ModeNo) ;
+				   unsigned short ModeNo);
 
 extern unsigned char XGI_SearchModeID(unsigned short ModeNo,
-				      unsigned short *ModeIdIndex,
-				      struct vb_device_info *);
+				      unsigned short *ModeIdIndex);
 extern unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
 					 unsigned short ModeNo,
 					 unsigned short ModeIdIndex,
diff --git a/drivers/staging/xillybus/Kconfig b/drivers/staging/xillybus/Kconfig
new file mode 100644
index 0000000..8a4181f
--- /dev/null
+++ b/drivers/staging/xillybus/Kconfig
@@ -0,0 +1,32 @@
+#
+# Xillybus devices
+#
+
+config XILLYBUS
+	tristate "Xillybus generic FPGA interface"
+	depends on PCI || (OF_ADDRESS && OF_IRQ) && m
+	help
+	  Xillybus is a generic interface for peripherals designed on
+	  programmable logic (FPGA). The driver probes the hardware for
+	  its capabilities, and creates device files accordingly.
+
+	  If unsure, say N.
+
+if XILLYBUS
+
+config XILLYBUS_PCIE
+	tristate "Xillybus over PCIe"
+	depends on XILLYBUS && PCI
+	help
+	  Set to M if you want Xillybus to use PCI Express for communicating
+	  with the FPGA.
+
+config XILLYBUS_OF
+	tristate "Xillybus over Device Tree"
+	depends on XILLYBUS && OF_ADDRESS && OF_IRQ
+	help
+	  Set to M if you want Xillybus to find its resources from the
+	  Open Firmware Flattened Device Tree. If the target is an embedded
+	  system, say M.
+
+endif # if XILLYBUS
diff --git a/drivers/staging/xillybus/Makefile b/drivers/staging/xillybus/Makefile
new file mode 100644
index 0000000..b68b7eb
--- /dev/null
+++ b/drivers/staging/xillybus/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for Xillybus driver
+#
+
+obj-$(CONFIG_XILLYBUS)		+= xillybus_core.o
+obj-$(CONFIG_XILLYBUS_PCIE)	+= xillybus_pcie.o
+obj-$(CONFIG_XILLYBUS_OF)	+= xillybus_of.o
diff --git a/drivers/staging/xillybus/README b/drivers/staging/xillybus/README
new file mode 100644
index 0000000..d2d848a
--- /dev/null
+++ b/drivers/staging/xillybus/README
@@ -0,0 +1,403 @@
+
+               ==========================================
+               Xillybus driver for generic FPGA interface
+               ==========================================
+
+Author: Eli Billauer, Xillybus Ltd. (http://xillybus.com)
+Email:  eli.billauer@gmail.com or as advertised on Xillybus' site.
+
+Contents:
+
+ - Introduction
+  -- Background
+  -- Xillybus Overview
+
+ - Usage
+  -- User interface
+  -- Synchronization
+  -- Seekable pipes
+
+- Internals
+  -- Source code organization
+  -- Pipe attributes
+  -- Host never reads from the FPGA
+  -- Channels, pipes, and the message channel
+  -- Data streaming
+  -- Data granularity
+  -- Probing
+  -- Buffer allocation
+  -- Memory management
+  -- The "nonempty" message (supporting poll)
+
+
+INTRODUCTION
+============
+
+Background
+----------
+
+An FPGA (Field Programmable Gate Array) is a piece of logic hardware, which
+can be programmed to become virtually anything that is usually found as a
+dedicated chipset: For instance, a display adapter, network interface card,
+or even a processor with its peripherals. FPGAs are the LEGO of hardware:
+Based upon certain building blocks, you make your own toys the way you like
+them. It's usually pointless to reimplement something that is already
+available on the market as a chipset, so FPGAs are mostly used when some
+special functionality is needed, and the production volume is relatively low
+(hence not justifying the development of an ASIC).
+
+The challenge with FPGAs is that everything is implemented at a very low
+level, even lower than assembly language. In order to allow FPGA designers to
+focus on their specific project, and not reinvent the wheel over and over
+again, pre-designed building blocks, IP cores, are often used. These are the
+FPGA parallels of library functions. IP cores may implement certain
+mathematical functions, a functional unit (e.g. a USB interface), an entire
+processor (e.g. ARM) or anything that might come handy. Think of them as a
+building block, with electrical wires dangling on the sides for connection to
+other blocks.
+
+One of the daunting tasks in FPGA design is communicating with a fullblown
+operating system (actually, with the processor running it): Implementing the
+low-level bus protocol and the somewhat higher-level interface with the host
+(registers, interrupts, DMA etc.) is a project in itself. When the FPGA's
+function is a well-known one (e.g. a video adapter card, or a NIC), it can
+make sense to design the FPGA's interface logic specifically for the project.
+A special driver is then written to present the FPGA as a well-known interface
+to the kernel and/or user space. In that case, there is no reason to treat the
+FPGA differently than any device on the bus.
+
+It's however common that the desired data communication doesn't fit any well-
+known peripheral function. Also, the effort of designing an elegant
+abstraction for the data exchange is often considered too big. In those cases,
+a quicker and possibly less elegant solution is sought: The driver is
+effectively written as a user space program, leaving the kernel space part
+with just elementary data transport. This still requires designing some
+interface logic for the FPGA, and write a simple ad-hoc driver for the kernel.
+
+Xillybus Overview
+-----------------
+
+Xillybus is an IP core and a Linux driver. Together, they form a kit for
+elementary data transport between an FPGA and the host, providing pipe-like
+data streams with a straightforward user interface. It's intended as a low-
+effort solution for mixed FPGA-host projects, for which it makes sense to
+have the project-specific part of the driver running in a user-space program.
+
+Since the communication requirements may vary significantly from one FPGA
+project to another (the number of data pipes needed in each direction and
+their attributes), there isn't one specific chunk of logic being the Xillybus
+IP core. Rather, the IP core is configured and built based upon a
+specification given by its end user.
+
+Xillybus presents independent data streams, which resemble pipes or TCP/IP
+communication to the user. At the host side, a character device file is used
+just like any pipe file. On the FPGA side, hardware FIFOs are used to stream
+the data. This is contrary to a common method of communicating through fixed-
+sized buffers (even though such buffers are used by Xillybus under the hood).
+There may be more than a hundred of these streams on a single IP core, but
+also no more than one, depending on the configuration.
+
+In order to ease the deployment of the Xillybus IP core, it contains a simple
+data structure which completely defines the core's configuration. The Linux
+driver fetches this data structure during its initialization process, and sets
+up the DMA buffers and character devices accordingly. As a result, a single
+driver is used to work out of the box with any Xillybus IP core.
+
+The data structure just mentioned should not be confused with PCI's
+configuration space or the Flattened Device Tree.
+
+USAGE
+=====
+
+User interface
+--------------
+
+On the host, all interface with Xillybus is done through /dev/xillybus_*
+device files, which are generated automatically as the drivers loads. The
+names of these files depend on the IP core that is loaded in the FPGA (see
+Probing below). To communicate with the FPGA, open the device file that
+corresponds to the hardware FIFO you want to send data or receive data from,
+and use plain write() or read() calls, just like with a regular pipe. In
+particular, it makes perfect sense to go:
+
+$ cat mydata > /dev/xillybus_thisfifo
+
+$ cat /dev/xillybus_thatfifo > hisdata
+
+possibly pressing CTRL-C as some stage, even though the xillybus_* pipes have
+the capability to send an EOF (but may not use it).
+
+The driver and hardware are designed to behave sensibly as pipes, including:
+
+* Supporting non-blocking I/O (by setting O_NONBLOCK on open() ).
+
+* Supporting poll() and select().
+
+* Being bandwidth efficient under load (using DMA) but also handle small
+  pieces of data sent across (like TCP/IP) by autoflushing.
+
+A device file can be read only, write only or bidirectional. Bidirectional
+device files are treated like two independent pipes (except for sharing a
+"channel" structure in the implementation code).
+
+Synchronization
+---------------
+
+Xillybus pipes are configured (on the IP core) to be either synchronous or
+asynchronous. For a synchronous pipe, write() returns successfully only after
+some data has been submitted and acknowledged by the FPGA. This slows down
+bulk data transfers, and is nearly impossible for use with streams that
+require data at a constant rate: There is no data transmitted to the FPGA
+between write() calls, in particular when the process loses the CPU.
+
+When a pipe is configured asynchronous, write() returns if there was enough
+room in the buffers to store any of the data in the buffers.
+
+For FPGA to host pipes, asynchronous pipes allow data transfer from the FPGA
+as soon as the respective device file is opened, regardless of if the data
+has been requested by a read() call. On synchronous pipes, only the amount
+of data requested by a read() call is transmitted.
+
+In summary, for synchronous pipes, data between the host and FPGA is
+transmitted only to satisfy the read() or write() call currently handled
+by the driver, and those calls wait for the transmission to complete before
+returning.
+
+Note that the synchronization attribute has nothing to do with the possibility
+that read() or write() completes less bytes than requested. There is a
+separate configuration flag ("allowpartial") that determines whether such a
+partial completion is allowed.
+
+Seekable pipes
+--------------
+
+A synchronous pipe can be configured to have the stream's position exposed
+to the user logic at the FPGA. Such a pipe is also seekable on the host API.
+With this feature, a memory or register interface can be attached on the
+FPGA side to the seekable stream. Reading or writing to a certain address in
+the attached memory is done by seeking to the desired address, and calling
+read() or write() as required.
+
+
+INTERNALS
+=========
+
+Source code organization
+------------------------
+
+The Xillybus driver consists of a core module, xillybus_core.c, and modules
+that depend on the specific bus interface (xillybus_of.c and xillybus_pcie.c).
+
+The bus specific modules are those probed when a suitable device is found by
+the kernel. Since the DMA mapping and synchronization functions, which are bus
+dependent by their nature, are used by the core module, a
+xilly_endpoint_hardware structure is passed to the core module on
+initialization. This structure is populated with pointers to wrapper functions
+which execute the DMA-related operations on the bus.
+
+Pipe attributes
+---------------
+
+Each pipe has a number of attributes which are set when the FPGA component
+(IP core) is built. They are fetched from the IDT (the data structure which
+defines the core's configuration, see Probing below) by xilly_setupchannels()
+in xillybus_core.c as follows:
+
+* is_writebuf: The pipe's direction. A non-zero value means it's an FPGA to
+  host pipe (the FPGA "writes").
+
+* channelnum: The pipe's identification number in communication between the
+  host and FPGA.
+
+* format: The underlying data width. See Data Granularity below.
+
+* allowpartial: A non-zero value means that a read() or write() (whichever
+  applies) may return with less than the requested number of bytes. The common
+  choice is a non-zero value, to match standard UNIX behavior.
+
+* synchronous: A non-zero value means that the pipe is synchronous. See
+  Syncronization above.
+
+* bufsize: Each DMA buffer's size. Always a power of two.
+
+* bufnum: The number of buffers allocated for this pipe. Always a power of two.
+
+* exclusive_open: A non-zero value forces exclusive opening of the associated
+  device file. If the device file is bidirectional, and already opened only in
+  one direction, the opposite direction may be opened once.
+
+* seekable: A non-zero value indicates that the pipe is seekable. See
+  Seekable pipes above.
+
+* supports_nonempty: A non-zero value (which is typical) indicates that the
+  hardware will send the messages that are necessary to support select() and
+  poll() for this pipe.
+
+Host never reads from the FPGA
+------------------------------
+
+Even though PCI Express is hotpluggable in general, a typical motherboard
+doesn't expect a card to go away all of the sudden. But since the PCIe card
+is based upon reprogrammable logic, a sudden disappearance from the bus is
+quite likely as a result of an accidental reprogramming of the FPGA while the
+host is up. In practice, nothing happens immediately in such a situation. But
+if the host attempts to read from an address that is mapped to the PCI Express
+device, that leads to an immediate freeze of the system on some motherboards,
+even though the PCIe standard requires a graceful recovery.
+
+In order to avoid these freezes, the Xillybus driver refrains completely from
+reading from the device's register space. All communication from the FPGA to
+the host is done through DMA. In particular, the Interrupt Service Routine
+doesn't follow the common practice of checking a status register when it's
+invoked. Rather, the FPGA prepares a small buffer which contains short
+messages, which inform the host what the interrupt was about.
+
+This mechanism is used on non-PCIe buses as well for the sake of uniformity.
+
+
+Channels, pipes, and the message channel
+----------------------------------------
+
+Each of the (possibly bidirectional) pipes presented to the user is allocated
+a data channel between the FPGA and the host. The distinction between channels
+and pipes is necessary only because of channel 0, which is used for interrupt-
+related messages from the FPGA, and has no pipe attached to it.
+
+Data streaming
+--------------
+
+Even though a non-segmented data stream is presented to the user at both
+sides, the implementation relies on a set of DMA buffers which is allocated
+for each channel. For the sake of illustration, let's take the FPGA to host
+direction: As data streams into the respective channel's interface in the
+FPGA, the Xillybus IP core writes it to one of the DMA buffers. When the
+buffer is full, the FPGA informs the host about that (appending a
+XILLYMSG_OPCODE_RELEASEBUF message channel 0 and sending an interrupt if
+necessary). The host responds by making the data available for reading through
+the character device. When all data has been read, the host writes on the
+the FPGA's buffer control register, allowing the buffer's overwriting. Flow
+control mechanisms exist on both sides to prevent underflows and overflows.
+
+This is not good enough for creating a TCP/IP-like stream: If the data flow
+stops momentarily before a DMA buffer is filled, the intuitive expectation is
+that the partial data in buffer will arrive anyhow, despite the buffer not
+being completed. This is implemented by adding a field in the
+XILLYMSG_OPCODE_RELEASEBUF message, through which the FPGA informs not just
+which buffer is submitted, but how much data it contains.
+
+But the FPGA will submit a partially filled buffer only if directed to do so
+by the host. This situation occurs when the read() method has been blocking
+for XILLY_RX_TIMEOUT jiffies (currently 10 ms), after which the host commands
+the FPGA to submit a DMA buffer as soon as it can. This timeout mechanism
+balances between bus bandwidth efficiency (preventing a lot of partially
+filled buffers being sent) and a latency held fairly low for tails of data.
+
+A similar setting is used in the host to FPGA direction. The handling of
+partial DMA buffers is somewhat different, though. The user can tell the
+driver to submit all data it has in the buffers to the FPGA, by issuing a
+write() with the byte count set to zero. This is similar to a flush request,
+but it doesn't block. There is also an autoflushing mechanism, which triggers
+an equivalent flush roughly XILLY_RX_TIMEOUT jiffies after the last write().
+This allows the user to be oblivious about the underlying buffering mechanism
+and yet enjoy a stream-like interface.
+
+Note that the issue of partial buffer flushing is irrelevant for pipes having
+the "synchronous" attribute nonzero, since synchronous pipes don't allow data
+to lay around in the DMA buffers between read() and write() anyhow.
+
+Data granularity
+----------------
+
+The data arrives or is sent at the FPGA as 8, 16 or 32 bit wide words, as
+configured by the "format" attribute. Whenever possible, the driver attempts
+to hide this when the pipe is accessed differently from its natural alignment.
+For example, reading single bytes from a pipe with 32 bit granularity works
+with no issues. Writing single bytes to pipes with 16 or 32 bit granularity
+will also work, but the driver can't send partially completed words to the
+FPGA, so the transmission of up to one word may be held until it's fully
+occupied with user data.
+
+This somewhat complicates the handling of host to FPGA streams, because
+when a buffer is flushed, it may contain up to 3 bytes don't form a word in
+the FPGA, and hence can't be sent. To prevent loss of data, these leftover
+bytes need to be moved to the next buffer. The parts in xillybus_core.c
+that mention "leftovers" in some way are related to this complication.
+
+Probing
+-------
+
+As mentioned earlier, the number of pipes that are created when the driver
+loads and their attributes depend on the Xillybus IP core in the FPGA. During
+the driver's initialization, a blob containing configuration info, the
+Interface Description Table (IDT), is sent from the FPGA to the host. The
+bootstrap process is done in three phases:
+
+1. Acquire the length of the IDT, so a buffer can be allocated for it. This
+   is done by sending a quiesce command to the device, since the acknowledge
+   for this command contains the IDT's buffer length.
+
+2. Acquire the IDT itself.
+
+3. Create the interfaces according to the IDT.
+
+Buffer allocation
+-----------------
+
+In order to simplify the logic that prevents illegal boundary crossings of
+PCIe packets, the following rule applies: If a buffer is smaller than 4kB,
+it must not cross a 4kB boundary. Otherwise, it must be 4kB aligned. The
+xilly_setupchannels() functions allocates these buffers by requesting whole
+pages from the kernel, and diving them into DMA buffers as necessary. Since
+all buffers' sizes are powers of two, it's possible to pack any set of such
+buffers, with a maximal waste of one page of memory.
+
+All buffers are allocated when the driver is loaded. This is necessary,
+since large continuous physical memory segments are sometimes requested,
+which are more likely to be available when the system is freshly booted.
+
+The allocation of buffer memory takes place in the same order they appear in
+the IDT. The driver relies on a rule that the pipes are sorted with decreasing
+buffer size in the IDT. If a requested buffer is larger or equal to a page,
+the necessary number of pages is requested from the kernel, and these are
+used for this buffer. If the requested buffer is smaller than a page, one
+single page is requested from the kernel, and that page is partially used.
+Or, if there already is a partially used page at hand, the buffer is packed
+into that page. It can be shown that all pages requested from the kernel
+(except possibly for the last) are 100% utilized this way.
+
+Memory management
+-----------------
+
+The tricky part about the buffer allocation procedure described above is
+freeing and unmapping the buffers, in particular if something goes wrong in
+the middle, and the allocations need to be rolled back. The three-stage
+probing procedure makes this even more crucial, since temporary buffers are
+set up and mapped in the first of its two stages.
+
+To keep the code clean from complicated and bug-prone memory release routines,
+there are special routines for allocating memory. For example, instead of
+calling kzalloc, there's
+
+void *xilly_malloc(struct xilly_cleanup *mem, size_t size)
+
+which effectively allocates a zeroed buffer of size "size". Its first
+argument, "mem", is where this allocation is enlisted, so that it's released
+when xillybus_do_cleanup() is called with the same "mem" structure.
+
+Two other functions enlist allocations in this structure: xilly_pagealloc()
+for page allocations and xilly_map_single_*() for DMA mapping.
+
+The "nonempty" message (supporting poll)
+---------------------------------------
+
+In order to support the "poll" method (and hence select() ), there is a small
+catch regarding the FPGA to host direction: The FPGA may have filled a DMA
+buffer with some data, but not submitted that buffer. If the host waited for
+the buffer's submission by the FPGA, there would be a possibility that the
+FPGA side has sent data, but a select() call would still block, because the
+host has not received any notification about this. This is solved with
+XILLYMSG_OPCODE_NONEMPTY messages sent by the FPGA when a channel goes from
+completely empty to containing some data.
+
+These messages are used only to support poll() and select(). The IP core can
+be configured not to send them for a slight reduction of bandwidth.
diff --git a/drivers/staging/xillybus/TODO b/drivers/staging/xillybus/TODO
new file mode 100644
index 0000000..95cfe2f
--- /dev/null
+++ b/drivers/staging/xillybus/TODO
@@ -0,0 +1,5 @@
+TODO:
+- have the driver reviewed
+
+Please send any patches and/or comments to Eli Billauer,
+<eli.billauer@gmail.com>.
diff --git a/drivers/staging/xillybus/xillybus.h b/drivers/staging/xillybus/xillybus.h
new file mode 100644
index 0000000..e5e91d6
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus.h
@@ -0,0 +1,182 @@
+/*
+ * linux/drivers/misc/xillybus.h
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Header file for the Xillybus FPGA/host framework.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#ifndef __XILLYBUS_H
+#define __XILLYBUS_H
+
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/cdev.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+struct xilly_endpoint_hardware;
+
+struct xilly_page {
+	struct list_head node;
+	unsigned long addr;
+	unsigned int order;
+};
+
+struct xilly_dma {
+	struct list_head node;
+	struct pci_dev *pdev;
+	struct device *dev;
+	dma_addr_t dma_addr;
+	size_t size;
+	int direction;
+};
+
+struct xilly_buffer {
+	void *addr;
+	dma_addr_t dma_addr;
+	int end_offset; /* Counting elements, not bytes */
+};
+
+struct xilly_cleanup {
+	struct list_head to_kfree;
+	struct list_head to_pagefree;
+	struct list_head to_unmap;
+};
+
+struct xilly_idt_handle {
+	unsigned char *chandesc;
+	unsigned char *idt;
+	int entries;
+};
+
+/*
+ * Read-write confusion: wr_* and rd_* notation sticks to FPGA view, so
+ * wr_* buffers are those consumed by read(), since the FPGA writes to them
+ * and vice versa.
+ */
+
+struct xilly_channel {
+	struct xilly_endpoint *endpoint;
+	int chan_num;
+	int log2_element_size;
+	int seekable;
+
+	struct xilly_buffer **wr_buffers; /* FPGA writes, driver reads! */
+	int num_wr_buffers;
+	unsigned int wr_buf_size; /* In bytes */
+	int wr_fpga_buf_idx;
+	int wr_host_buf_idx;
+	int wr_host_buf_pos;
+	int wr_empty;
+	int wr_ready; /* Significant only when wr_empty == 1 */
+	int wr_sleepy;
+	int wr_eof;
+	int wr_hangup;
+	spinlock_t wr_spinlock;
+	struct mutex wr_mutex;
+	wait_queue_head_t wr_wait;
+	wait_queue_head_t wr_ready_wait;
+	int wr_ref_count;
+	int wr_synchronous;
+	int wr_allow_partial;
+	int wr_exclusive_open;
+	int wr_supports_nonempty;
+
+	struct xilly_buffer **rd_buffers; /* FPGA reads, driver writes! */
+	int num_rd_buffers;
+	unsigned int rd_buf_size; /* In bytes */
+	int rd_fpga_buf_idx;
+	int rd_host_buf_pos;
+	int rd_host_buf_idx;
+	int rd_full;
+	spinlock_t rd_spinlock;
+	struct mutex rd_mutex;
+	wait_queue_head_t rd_wait;
+	int rd_ref_count;
+	int rd_allow_partial;
+	int rd_synchronous;
+	int rd_exclusive_open;
+	struct delayed_work rd_workitem;
+	unsigned char rd_leftovers[4];
+};
+
+struct xilly_endpoint {
+	/*
+	 * One of pdev and dev is always NULL, and the other is a valid
+	 * pointer, depending on the type of device
+	 */
+	struct pci_dev *pdev;
+	struct device *dev;
+	struct resource res; /* OF devices only */
+	struct xilly_endpoint_hardware *ephw;
+
+	struct list_head ep_list;
+	int dma_using_dac; /* =1 if 64-bit DMA is used, =0 otherwise. */
+	__iomem u32 *registers;
+	int fatal_error;
+
+	struct mutex register_mutex;
+	wait_queue_head_t ep_wait;
+
+	/* List of memory allocations, to make release easy */
+	struct xilly_cleanup cleanup;
+
+	/* Channels and message handling */
+	struct cdev cdev;
+
+	int major;
+	int lowest_minor; /* Highest minor = lowest_minor + num_channels - 1 */
+
+	int num_channels; /* EXCLUDING message buffer */
+	struct xilly_channel **channels;
+	int msg_counter;
+	int failed_messages;
+	int idtlen;
+
+	u32 *msgbuf_addr;
+	dma_addr_t msgbuf_dma_addr;
+	unsigned int msg_buf_size;
+};
+
+struct xilly_endpoint_hardware {
+	struct module *owner;
+	void (*hw_sync_sgl_for_cpu)(struct xilly_endpoint *,
+				    dma_addr_t,
+				    size_t,
+				    int);
+	void (*hw_sync_sgl_for_device)(struct xilly_endpoint *,
+				       dma_addr_t,
+				       size_t,
+				       int);
+	dma_addr_t (*map_single)(struct xilly_cleanup *,
+				 struct xilly_endpoint *,
+				 void *,
+				 size_t,
+				 int);
+	void (*unmap_single)(struct xilly_dma *entry);
+};
+
+irqreturn_t xillybus_isr(int irq, void *data);
+
+void xillybus_do_cleanup(struct xilly_cleanup *mem,
+			 struct xilly_endpoint *endpoint);
+
+struct xilly_endpoint *xillybus_init_endpoint(struct pci_dev *pdev,
+					      struct device *dev,
+					      struct xilly_endpoint_hardware
+					      *ephw);
+
+int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint);
+
+void xillybus_endpoint_remove(struct xilly_endpoint *endpoint);
+
+#endif /* __XILLYBUS_H */
diff --git a/drivers/staging/xillybus/xillybus_core.c b/drivers/staging/xillybus/xillybus_core.c
new file mode 100644
index 0000000..efc5698
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus_core.c
@@ -0,0 +1,2345 @@
+/*
+ * linux/drivers/misc/xillybus_core.c
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus FPGA/host framework.
+ *
+ * This driver interfaces with a special IP core in an FPGA, setting up
+ * a pipe between a hardware FIFO in the programmable logic and a device
+ * file in the host. The number of such pipes and their attributes are
+ * set up on the logic. This driver detects these automatically and
+ * creates the device files accordingly.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/crc32.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "xillybus.h"
+
+MODULE_DESCRIPTION("Xillybus core functions");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_VERSION("1.07");
+MODULE_ALIAS("xillybus_core");
+MODULE_LICENSE("GPL v2");
+
+/* General timeout is 100 ms, rx timeout is 10 ms */
+#define XILLY_RX_TIMEOUT (10*HZ/1000)
+#define XILLY_TIMEOUT (100*HZ/1000)
+
+#define fpga_msg_ctrl_reg 0x0002
+#define fpga_dma_control_reg 0x0008
+#define fpga_dma_bufno_reg 0x0009
+#define fpga_dma_bufaddr_lowaddr_reg 0x000a
+#define fpga_dma_bufaddr_highaddr_reg 0x000b
+#define fpga_buf_ctrl_reg 0x000c
+#define fpga_buf_offset_reg 0x000d
+#define fpga_endian_reg 0x0010
+
+#define XILLYMSG_OPCODE_RELEASEBUF 1
+#define XILLYMSG_OPCODE_QUIESCEACK 2
+#define XILLYMSG_OPCODE_FIFOEOF 3
+#define XILLYMSG_OPCODE_FATAL_ERROR 4
+#define XILLYMSG_OPCODE_NONEMPTY 5
+
+static const char xillyname[] = "xillybus";
+
+static struct class *xillybus_class;
+
+/*
+ * ep_list_lock is the last lock to be taken; No other lock requests are
+ * allowed while holding it. It merely protects list_of_endpoints, and not
+ * the endpoints listed in it.
+ */
+
+static LIST_HEAD(list_of_endpoints);
+static struct mutex ep_list_lock;
+static struct workqueue_struct *xillybus_wq;
+
+/*
+ * Locking scheme: Mutexes protect invocations of character device methods.
+ * If both locks are taken, wr_mutex is taken first, rd_mutex second.
+ *
+ * wr_spinlock protects wr_*_buf_idx, wr_empty, wr_sleepy, wr_ready and the
+ * buffers' end_offset fields against changes made by IRQ handler (and in
+ * theory, other file request handlers, but the mutex handles that). Nothing
+ * else.
+ * They are held for short direct memory manipulations. Needless to say,
+ * no mutex locking is allowed when a spinlock is held.
+ *
+ * rd_spinlock does the same with rd_*_buf_idx, rd_empty and end_offset.
+ *
+ * register_mutex is endpoint-specific, and is held when non-atomic
+ * register operations are performed. wr_mutex and rd_mutex may be
+ * held when register_mutex is taken, but none of the spinlocks. Note that
+ * register_mutex doesn't protect against sporadic buf_ctrl_reg writes
+ * which are unrelated to buf_offset_reg, since they are harmless.
+ *
+ * Blocking on the wait queues is allowed with mutexes held, but not with
+ * spinlocks.
+ *
+ * Only interruptible blocking is allowed on mutexes and wait queues.
+ *
+ * All in all, the locking order goes (with skips allowed, of course):
+ * wr_mutex -> rd_mutex -> register_mutex -> wr_spinlock -> rd_spinlock
+ */
+
+static void malformed_message(u32 *buf)
+{
+	int opcode;
+	int msg_channel, msg_bufno, msg_data, msg_dir;
+
+	opcode = (buf[0] >> 24) & 0xff;
+	msg_dir = buf[0] & 1;
+	msg_channel = (buf[0] >> 1) & 0x7ff;
+	msg_bufno = (buf[0] >> 12) & 0x3ff;
+	msg_data = buf[1] & 0xfffffff;
+
+	pr_warn("xillybus: Malformed message (skipping): "
+		"opcode=%d, channel=%03x, dir=%d, bufno=%03x, data=%07x\n",
+		opcode, msg_channel, msg_dir, msg_bufno, msg_data);
+}
+
+/*
+ * xillybus_isr assumes the interrupt is allocated exclusively to it,
+ * which is the natural case MSI and several other hardware-oriented
+ * interrupts. Sharing is not allowed.
+ */
+
+irqreturn_t xillybus_isr(int irq, void *data)
+{
+	struct xilly_endpoint *ep = data;
+	u32 *buf;
+	unsigned int buf_size;
+	int i;
+	int opcode;
+	unsigned int msg_channel, msg_bufno, msg_data, msg_dir;
+	struct xilly_channel *channel;
+
+	/*
+	 * The endpoint structure is altered during periods when it's
+	 * guaranteed no interrupt will occur, but in theory, the cache
+	 * lines may not be updated. So a memory barrier is issued.
+	 */
+
+	smp_rmb();
+
+	buf = ep->msgbuf_addr;
+	buf_size = ep->msg_buf_size/sizeof(u32);
+
+
+	ep->ephw->hw_sync_sgl_for_cpu(ep,
+				      ep->msgbuf_dma_addr,
+				      ep->msg_buf_size,
+				      DMA_FROM_DEVICE);
+
+	for (i = 0; i < buf_size; i += 2)
+		if (((buf[i+1] >> 28) & 0xf) != ep->msg_counter) {
+			malformed_message(&buf[i]);
+			pr_warn("xillybus: Sending a NACK on "
+				"counter %x (instead of %x) on entry %d\n",
+				((buf[i+1] >> 28) & 0xf),
+				ep->msg_counter,
+				i/2);
+
+			if (++ep->failed_messages > 10)
+				pr_err("xillybus: Lost sync with "
+				       "interrupt messages. Stopping.\n");
+			else {
+				ep->ephw->hw_sync_sgl_for_device(
+					ep,
+					ep->msgbuf_dma_addr,
+					ep->msg_buf_size,
+					DMA_FROM_DEVICE);
+
+				iowrite32(0x01,  /* Message NACK */
+					  &ep->registers[fpga_msg_ctrl_reg]);
+			}
+			return IRQ_HANDLED;
+		} else if (buf[i] & (1 << 22)) /* Last message */
+			break;
+
+	if (i >= buf_size) {
+		pr_err("xillybus: Bad interrupt message. Stopping.\n");
+		return IRQ_HANDLED;
+	}
+
+	buf_size = i;
+
+	for (i = 0; i <= buf_size; i += 2) { /* Scan through messages */
+		opcode = (buf[i] >> 24) & 0xff;
+
+		msg_dir = buf[i] & 1;
+		msg_channel = (buf[i] >> 1) & 0x7ff;
+		msg_bufno = (buf[i] >> 12) & 0x3ff;
+		msg_data = buf[i+1] & 0xfffffff;
+
+		switch (opcode) {
+		case XILLYMSG_OPCODE_RELEASEBUF:
+
+			if ((msg_channel > ep->num_channels) ||
+			    (msg_channel == 0)) {
+				malformed_message(&buf[i]);
+				break;
+			}
+
+			channel = ep->channels[msg_channel];
+
+			if (msg_dir) { /* Write channel */
+				if (msg_bufno >= channel->num_wr_buffers) {
+					malformed_message(&buf[i]);
+					break;
+				}
+				spin_lock(&channel->wr_spinlock);
+				channel->wr_buffers[msg_bufno]->end_offset =
+					msg_data;
+				channel->wr_fpga_buf_idx = msg_bufno;
+				channel->wr_empty = 0;
+				channel->wr_sleepy = 0;
+				spin_unlock(&channel->wr_spinlock);
+
+				wake_up_interruptible(&channel->wr_wait);
+
+			} else {
+				/* Read channel */
+
+				if (msg_bufno >= channel->num_rd_buffers) {
+					malformed_message(&buf[i]);
+					break;
+				}
+
+				spin_lock(&channel->rd_spinlock);
+				channel->rd_fpga_buf_idx = msg_bufno;
+				channel->rd_full = 0;
+				spin_unlock(&channel->rd_spinlock);
+
+				wake_up_interruptible(&channel->rd_wait);
+				if (!channel->rd_synchronous)
+					queue_delayed_work(
+						xillybus_wq,
+						&channel->rd_workitem,
+						XILLY_RX_TIMEOUT);
+			}
+
+			break;
+		case XILLYMSG_OPCODE_NONEMPTY:
+			if ((msg_channel > ep->num_channels) ||
+			    (msg_channel == 0) || (!msg_dir) ||
+			    !ep->channels[msg_channel]->wr_supports_nonempty) {
+				malformed_message(&buf[i]);
+				break;
+			}
+
+			channel = ep->channels[msg_channel];
+
+			if (msg_bufno >= channel->num_wr_buffers) {
+				malformed_message(&buf[i]);
+				break;
+			}
+			spin_lock(&channel->wr_spinlock);
+			if (msg_bufno == channel->wr_host_buf_idx)
+				channel->wr_ready = 1;
+			spin_unlock(&channel->wr_spinlock);
+
+			wake_up_interruptible(&channel->wr_ready_wait);
+
+			break;
+		case XILLYMSG_OPCODE_QUIESCEACK:
+			ep->idtlen = msg_data;
+			wake_up_interruptible(&ep->ep_wait);
+
+			break;
+		case XILLYMSG_OPCODE_FIFOEOF:
+			channel = ep->channels[msg_channel];
+			spin_lock(&channel->wr_spinlock);
+			channel->wr_eof = msg_bufno;
+			channel->wr_sleepy = 0;
+
+			channel->wr_hangup = channel->wr_empty &&
+				(channel->wr_host_buf_idx == msg_bufno);
+
+			spin_unlock(&channel->wr_spinlock);
+
+			wake_up_interruptible(&channel->wr_wait);
+
+			break;
+		case XILLYMSG_OPCODE_FATAL_ERROR:
+			ep->fatal_error = 1;
+			wake_up_interruptible(&ep->ep_wait); /* For select() */
+			pr_err("xillybus: FPGA reported a fatal "
+			       "error. This means that the low-level "
+			       "communication with the device has failed. "
+			       "This hardware problem is most likely "
+			       "unrelated to xillybus (neither kernel "
+			       "module nor FPGA core), but reports are "
+			       "still welcome. All I/O is aborted.\n");
+			break;
+		default:
+			malformed_message(&buf[i]);
+			break;
+		}
+	}
+
+	ep->ephw->hw_sync_sgl_for_device(ep,
+					 ep->msgbuf_dma_addr,
+					 ep->msg_buf_size,
+					 DMA_FROM_DEVICE);
+
+	ep->msg_counter = (ep->msg_counter + 1) & 0xf;
+	ep->failed_messages = 0;
+	iowrite32(0x03, &ep->registers[fpga_msg_ctrl_reg]); /* Message ACK */
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(xillybus_isr);
+
+/*
+ * A few trivial memory management functions.
+ * NOTE: These functions are used only on probe and remove, and therefore
+ * no locks are applied!
+ */
+
+void xillybus_do_cleanup(struct xilly_cleanup *mem,
+			 struct xilly_endpoint *endpoint)
+{
+	struct list_head *this, *next;
+
+	list_for_each_safe(this, next, &mem->to_unmap) {
+		struct xilly_dma *entry =
+			list_entry(this, struct xilly_dma, node);
+
+		endpoint->ephw->unmap_single(entry);
+		kfree(entry);
+	}
+
+	INIT_LIST_HEAD(&mem->to_unmap);
+
+	list_for_each_safe(this, next, &mem->to_kfree)
+		kfree(this);
+
+	INIT_LIST_HEAD(&mem->to_kfree);
+
+	list_for_each_safe(this, next, &mem->to_pagefree) {
+		struct xilly_page *entry =
+			list_entry(this, struct xilly_page, node);
+
+		free_pages(entry->addr, entry->order);
+		kfree(entry);
+	}
+	INIT_LIST_HEAD(&mem->to_pagefree);
+}
+EXPORT_SYMBOL(xillybus_do_cleanup);
+
+static void *xilly_malloc(struct xilly_cleanup *mem, size_t size)
+{
+	void *ptr;
+
+	ptr = kzalloc(sizeof(struct list_head) + size, GFP_KERNEL);
+
+	if (!ptr)
+		return ptr;
+
+	list_add_tail((struct list_head *) ptr, &mem->to_kfree);
+
+	return ptr + sizeof(struct list_head);
+}
+
+static unsigned long xilly_pagealloc(struct xilly_cleanup *mem,
+				     unsigned long order)
+{
+	unsigned long addr;
+	struct xilly_page *this;
+
+	this = kmalloc(sizeof(struct xilly_page), GFP_KERNEL);
+	if (!this)
+		return 0;
+
+	addr =  __get_free_pages(GFP_KERNEL | __GFP_DMA32 | __GFP_ZERO, order);
+
+	if (!addr) {
+		kfree(this);
+		return 0;
+	}
+
+	this->addr = addr;
+	this->order = order;
+
+	list_add_tail(&this->node, &mem->to_pagefree);
+
+	return addr;
+}
+
+
+static void xillybus_autoflush(struct work_struct *work);
+
+static int xilly_setupchannels(struct xilly_endpoint *ep,
+			       struct xilly_cleanup *mem,
+			       unsigned char *chandesc,
+			       int entries
+	)
+{
+	int i, entry, wr_nbuffer, rd_nbuffer;
+	struct xilly_channel *channel;
+	int channelnum, bufnum, bufsize, format, is_writebuf;
+	int bytebufsize;
+	int synchronous, allowpartial, exclusive_open, seekable;
+	int supports_nonempty;
+	void *wr_salami = NULL;
+	void *rd_salami = NULL;
+	int left_of_wr_salami = 0;
+	int left_of_rd_salami = 0;
+	dma_addr_t dma_addr;
+	int msg_buf_done = 0;
+
+	struct xilly_buffer *this_buffer = NULL; /* Init to silence warning */
+
+	channel = xilly_malloc(mem, ep->num_channels *
+			       sizeof(struct xilly_channel));
+
+	if (!channel)
+		goto memfail;
+
+	ep->channels = xilly_malloc(mem, (ep->num_channels + 1) *
+				    sizeof(struct xilly_channel *));
+
+	if (!ep->channels)
+		goto memfail;
+
+	ep->channels[0] = NULL; /* Channel 0 is message buf. */
+
+	/* Initialize all channels with defaults */
+
+	for (i = 1; i <= ep->num_channels; i++) {
+		channel->wr_buffers = NULL;
+		channel->rd_buffers = NULL;
+		channel->num_wr_buffers = 0;
+		channel->num_rd_buffers = 0;
+		channel->wr_fpga_buf_idx = -1;
+		channel->wr_host_buf_idx = 0;
+		channel->wr_host_buf_pos = 0;
+		channel->wr_empty = 1;
+		channel->wr_ready = 0;
+		channel->wr_sleepy = 1;
+		channel->rd_fpga_buf_idx = 0;
+		channel->rd_host_buf_idx = 0;
+		channel->rd_host_buf_pos = 0;
+		channel->rd_full = 0;
+		channel->wr_ref_count = 0;
+		channel->rd_ref_count = 0;
+
+		spin_lock_init(&channel->wr_spinlock);
+		spin_lock_init(&channel->rd_spinlock);
+		mutex_init(&channel->wr_mutex);
+		mutex_init(&channel->rd_mutex);
+		init_waitqueue_head(&channel->rd_wait);
+		init_waitqueue_head(&channel->wr_wait);
+		init_waitqueue_head(&channel->wr_ready_wait);
+
+		INIT_DELAYED_WORK(&channel->rd_workitem, xillybus_autoflush);
+
+		channel->endpoint = ep;
+		channel->chan_num = i;
+
+		channel->log2_element_size = 0;
+
+		ep->channels[i] = channel++;
+	}
+
+	/*
+	 * The DMA buffer address update is atomic on the FPGA, so even if
+	 * it was in the middle of sending messages to some buffer, changing
+	 * the address is safe, since the data will go to either of the
+	 * buffers. Not that this situation should occur at all anyhow.
+	 */
+
+	wr_nbuffer = 1;
+	rd_nbuffer = 1; /* Buffer zero isn't used at all */
+
+	for (entry = 0; entry < entries; entry++, chandesc += 4) {
+		is_writebuf = chandesc[0] & 0x01;
+		channelnum = (chandesc[0] >> 1) | ((chandesc[1] & 0x0f) << 7);
+		format = (chandesc[1] >> 4) & 0x03;
+		allowpartial = (chandesc[1] >> 6) & 0x01;
+		synchronous = (chandesc[1] >> 7) & 0x01;
+		bufsize = 1 << (chandesc[2] & 0x1f);
+		bufnum = 1 << (chandesc[3] & 0x0f);
+		exclusive_open = (chandesc[2] >> 7) & 0x01;
+		seekable = (chandesc[2] >> 6) & 0x01;
+		supports_nonempty = (chandesc[2] >> 5) & 0x01;
+
+		if ((channelnum > ep->num_channels) ||
+		    ((channelnum == 0) && !is_writebuf)) {
+			pr_err("xillybus: IDT requests channel out "
+			       "of range. Aborting.\n");
+			return -ENODEV;
+		}
+
+		channel = ep->channels[channelnum]; /* NULL for msg channel */
+
+		bytebufsize = bufsize << 2; /* Overwritten just below */
+
+		if (!is_writebuf) {
+			channel->num_rd_buffers = bufnum;
+			channel->log2_element_size = ((format > 2) ?
+						      2 : format);
+			bytebufsize = channel->rd_buf_size = bufsize *
+				(1 << channel->log2_element_size);
+			channel->rd_allow_partial = allowpartial;
+			channel->rd_synchronous = synchronous;
+			channel->rd_exclusive_open = exclusive_open;
+			channel->seekable = seekable;
+
+			channel->rd_buffers = xilly_malloc(
+				mem,
+				bufnum * sizeof(struct xilly_buffer *));
+
+			if (!channel->rd_buffers)
+				goto memfail;
+
+			this_buffer = xilly_malloc(
+				mem,
+				bufnum * sizeof(struct xilly_buffer));
+
+			if (!this_buffer)
+				goto memfail;
+		}
+
+		else if (channelnum > 0) {
+			channel->num_wr_buffers = bufnum;
+			channel->log2_element_size = ((format > 2) ?
+						      2 : format);
+			bytebufsize = channel->wr_buf_size = bufsize *
+				(1 << channel->log2_element_size);
+
+			channel->seekable = seekable;
+			channel->wr_supports_nonempty = supports_nonempty;
+
+			channel->wr_allow_partial = allowpartial;
+			channel->wr_synchronous = synchronous;
+			channel->wr_exclusive_open = exclusive_open;
+
+			channel->wr_buffers = xilly_malloc(
+				mem,
+				bufnum * sizeof(struct xilly_buffer *));
+
+			if (!channel->wr_buffers)
+				goto memfail;
+
+			this_buffer = xilly_malloc(
+				mem,
+				bufnum * sizeof(struct xilly_buffer));
+
+			if (!this_buffer)
+				goto memfail;
+		}
+
+		/*
+		 * Although daunting, we cut the chunks for read buffers
+		 * from a different salami than the write buffers',
+		 * possibly improving performance.
+		 */
+
+		if (is_writebuf)
+			for (i = 0; i < bufnum; i++) {
+				/*
+				 * Buffers are expected in descending
+				 * byte-size order, so there is either
+				 * enough for this buffer or none at all.
+				 */
+				if ((left_of_wr_salami < bytebufsize) &&
+				    (left_of_wr_salami > 0)) {
+					pr_err("xillybus: "
+					       "Corrupt buffer allocation "
+					       "in IDT. Aborting.\n");
+					return -ENODEV;
+				}
+
+				if (left_of_wr_salami == 0) {
+					int allocorder, allocsize;
+
+					allocsize = PAGE_SIZE;
+					allocorder = 0;
+					while (bytebufsize > allocsize) {
+						allocsize *= 2;
+						allocorder++;
+					}
+
+					wr_salami = (void *)
+						xilly_pagealloc(mem,
+								allocorder);
+					if (!wr_salami)
+						goto memfail;
+					left_of_wr_salami = allocsize;
+				}
+
+				dma_addr = ep->ephw->map_single(
+					mem,
+					ep,
+					wr_salami,
+					bytebufsize,
+					DMA_FROM_DEVICE);
+
+				if (!dma_addr)
+					goto dmafail;
+
+				iowrite32(
+					(u32) (dma_addr & 0xffffffff),
+					&ep->registers[
+						fpga_dma_bufaddr_lowaddr_reg]
+					);
+				iowrite32(
+					((u32) ((((u64) dma_addr) >> 32)
+						& 0xffffffff)),
+					&ep->registers[
+						fpga_dma_bufaddr_highaddr_reg]
+					);
+				mmiowb();
+
+				if (channelnum > 0) {
+					this_buffer->addr = wr_salami;
+					this_buffer->dma_addr = dma_addr;
+					channel->wr_buffers[i] = this_buffer++;
+
+					iowrite32(
+						0x80000000 | wr_nbuffer++,
+						&ep->registers[
+							fpga_dma_bufno_reg]);
+				} else {
+					ep->msgbuf_addr = wr_salami;
+					ep->msgbuf_dma_addr = dma_addr;
+					ep->msg_buf_size = bytebufsize;
+					msg_buf_done++;
+
+					iowrite32(
+						0x80000000, &ep->registers[
+							fpga_dma_bufno_reg]);
+				}
+
+				left_of_wr_salami -= bytebufsize;
+				wr_salami += bytebufsize;
+			}
+		else /* Read buffers */
+			for (i = 0; i < bufnum; i++) {
+				/*
+				 * Buffers are expected in descending
+				 * byte-size order, so there is either
+				 * enough for this buffer or none at all.
+				 */
+				if ((left_of_rd_salami < bytebufsize) &&
+				    (left_of_rd_salami > 0)) {
+					pr_err("xillybus: "
+					       "Corrupt buffer allocation "
+					       "in IDT. Aborting.\n");
+					return -ENODEV;
+				}
+
+				if (left_of_rd_salami == 0) {
+					int allocorder, allocsize;
+
+					allocsize = PAGE_SIZE;
+					allocorder = 0;
+					while (bytebufsize > allocsize) {
+						allocsize *= 2;
+						allocorder++;
+					}
+
+					rd_salami = (void *)
+						xilly_pagealloc(
+							mem,
+							allocorder);
+
+					if (!rd_salami)
+						goto memfail;
+					left_of_rd_salami = allocsize;
+				}
+
+				dma_addr = ep->ephw->map_single(
+					mem,
+					ep,
+					rd_salami,
+					bytebufsize,
+					DMA_TO_DEVICE);
+
+				if (!dma_addr)
+					goto dmafail;
+
+				iowrite32(
+					(u32) (dma_addr & 0xffffffff),
+					&ep->registers[
+						fpga_dma_bufaddr_lowaddr_reg]
+					);
+				iowrite32(
+					((u32) ((((u64) dma_addr) >> 32)
+						& 0xffffffff)),
+					&ep->registers[
+						fpga_dma_bufaddr_highaddr_reg]
+					);
+				mmiowb();
+
+				this_buffer->addr = rd_salami;
+				this_buffer->dma_addr = dma_addr;
+				channel->rd_buffers[i] = this_buffer++;
+
+				iowrite32(rd_nbuffer++,
+					  &ep->registers[fpga_dma_bufno_reg]);
+
+				left_of_rd_salami -= bytebufsize;
+				rd_salami += bytebufsize;
+			}
+	}
+
+	if (!msg_buf_done) {
+		pr_err("xillybus: Corrupt IDT: No message buffer. "
+		       "Aborting.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+
+memfail:
+	pr_err("xillybus: Failed to allocate write buffer memory. "
+	       "Aborting.\n");
+	return -ENOMEM;
+dmafail:
+	pr_err("xillybus: Failed to map DMA memory!. Aborting.\n");
+	return -ENOMEM;
+}
+
+static void xilly_scan_idt(struct xilly_endpoint *endpoint,
+			   struct xilly_idt_handle *idt_handle)
+{
+	int count = 0;
+	unsigned char *idt = endpoint->channels[1]->wr_buffers[0]->addr;
+	unsigned char *end_of_idt = idt + endpoint->idtlen - 4;
+	unsigned char *scan;
+	int len;
+
+	scan = idt;
+	idt_handle->idt = idt;
+
+	scan++; /* Skip version number */
+
+	while ((scan <= end_of_idt) && *scan) {
+		while ((scan <= end_of_idt) && *scan++)
+			/* Do nothing, just scan thru string */;
+		count++;
+	}
+
+	scan++;
+
+	if (scan > end_of_idt) {
+		pr_err("xillybus: IDT device name list overflow. "
+		       "Aborting.\n");
+		idt_handle->chandesc = NULL;
+		return;
+	} else
+		idt_handle->chandesc = scan;
+
+	len = endpoint->idtlen - (3 + ((int) (scan - idt)));
+
+	if (len & 0x03) {
+		idt_handle->chandesc = NULL;
+
+		pr_err("xillybus: Corrupt IDT device name list. "
+		       "Aborting.\n");
+	}
+
+	idt_handle->entries = len >> 2;
+
+	endpoint->num_channels = count;
+}
+
+static int xilly_obtain_idt(struct xilly_endpoint *endpoint)
+{
+	int rc = 0;
+	struct xilly_channel *channel;
+	unsigned char *version;
+
+	channel = endpoint->channels[1]; /* This should be generated ad-hoc */
+
+	channel->wr_sleepy = 1;
+	wmb(); /* Setting wr_sleepy must come before the command */
+
+	iowrite32(1 |
+		   (3 << 24), /* Opcode 3 for channel 0 = Send IDT */
+		   &endpoint->registers[fpga_buf_ctrl_reg]);
+	mmiowb(); /* Just to appear safe */
+
+	wait_event_interruptible_timeout(channel->wr_wait,
+					 (!channel->wr_sleepy),
+					 XILLY_TIMEOUT);
+
+	if (channel->wr_sleepy) {
+		pr_err("xillybus: Failed to obtain IDT. Aborting.\n");
+
+		if (endpoint->fatal_error)
+			return -EIO;
+
+		rc = -ENODEV;
+		return rc;
+	}
+
+	endpoint->ephw->hw_sync_sgl_for_cpu(
+		channel->endpoint,
+		channel->wr_buffers[0]->dma_addr,
+		channel->wr_buf_size,
+		DMA_FROM_DEVICE);
+
+	if (channel->wr_buffers[0]->end_offset != endpoint->idtlen) {
+		pr_err("xillybus: IDT length mismatch (%d != %d). "
+		       "Aborting.\n",
+		       channel->wr_buffers[0]->end_offset, endpoint->idtlen);
+		rc = -ENODEV;
+		return rc;
+	}
+
+	if (crc32_le(~0, channel->wr_buffers[0]->addr,
+		     endpoint->idtlen+1) != 0) {
+		pr_err("xillybus: IDT failed CRC check. Aborting.\n");
+		rc = -ENODEV;
+		return rc;
+	}
+
+	version = channel->wr_buffers[0]->addr;
+
+	/* Check version number. Accept anything below 0x82 for now. */
+	if (*version > 0x82) {
+		pr_err("xillybus: No support for IDT version 0x%02x. "
+		       "Maybe the xillybus driver needs an upgarde. "
+		       "Aborting.\n",
+		       (int) *version);
+		rc = -ENODEV;
+		return rc;
+	}
+
+	return 0; /* Success */
+}
+
+static ssize_t xillybus_read(struct file *filp, char __user *userbuf,
+			     size_t count, loff_t *f_pos)
+{
+	ssize_t rc;
+	unsigned long flags;
+	int bytes_done = 0;
+	int no_time_left = 0;
+	long deadline, left_to_sleep;
+	struct xilly_channel *channel = filp->private_data;
+
+	int empty, reached_eof, exhausted, ready;
+	/* Initializations are there only to silence warnings */
+
+	int howmany = 0, bufpos = 0, bufidx = 0, bufferdone = 0;
+	int waiting_bufidx;
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	deadline = jiffies + 1 + XILLY_RX_TIMEOUT;
+
+	rc = mutex_lock_interruptible(&channel->wr_mutex);
+
+	if (rc)
+		return rc;
+
+	rc = 0; /* Just to be clear about it. Compiler optimizes this out */
+
+	while (1) { /* Note that we may drop mutex within this loop */
+		int bytes_to_do = count - bytes_done;
+		spin_lock_irqsave(&channel->wr_spinlock, flags);
+
+		empty = channel->wr_empty;
+		ready = !empty || channel->wr_ready;
+
+		if (!empty) {
+			bufidx = channel->wr_host_buf_idx;
+			bufpos = channel->wr_host_buf_pos;
+			howmany = ((channel->wr_buffers[bufidx]->end_offset
+				    + 1) << channel->log2_element_size)
+				- bufpos;
+
+			/* Update wr_host_* to its post-operation state */
+			if (howmany > bytes_to_do) {
+				bufferdone = 0;
+
+				howmany = bytes_to_do;
+				channel->wr_host_buf_pos += howmany;
+			} else {
+				bufferdone = 1;
+
+				channel->wr_host_buf_pos = 0;
+
+				if (bufidx == channel->wr_fpga_buf_idx) {
+					channel->wr_empty = 1;
+					channel->wr_sleepy = 1;
+					channel->wr_ready = 0;
+				}
+
+				if (bufidx >= (channel->num_wr_buffers - 1))
+					channel->wr_host_buf_idx = 0;
+				else
+					channel->wr_host_buf_idx++;
+			}
+		}
+
+		/*
+		 * Marking our situation after the possible changes above,
+		 * for use after releasing the spinlock.
+		 *
+		 * empty = empty before change
+		 * exhasted = empty after possible change
+		 */
+
+		reached_eof = channel->wr_empty &&
+			(channel->wr_host_buf_idx == channel->wr_eof);
+		channel->wr_hangup = reached_eof;
+		exhausted = channel->wr_empty;
+		waiting_bufidx = channel->wr_host_buf_idx;
+
+		spin_unlock_irqrestore(&channel->wr_spinlock, flags);
+
+		if (!empty) { /* Go on, now without the spinlock */
+
+			if (bufpos == 0) /* Position zero means it's virgin */
+				channel->endpoint->ephw->hw_sync_sgl_for_cpu(
+					channel->endpoint,
+					channel->wr_buffers[bufidx]->dma_addr,
+					channel->wr_buf_size,
+					DMA_FROM_DEVICE);
+
+			if (copy_to_user(
+				    userbuf,
+				    channel->wr_buffers[bufidx]->addr
+				    + bufpos, howmany))
+				rc = -EFAULT;
+
+			userbuf += howmany;
+			bytes_done += howmany;
+
+			if (bufferdone) {
+				channel->endpoint->ephw->
+					hw_sync_sgl_for_device
+					(
+						channel->endpoint,
+						channel->wr_buffers[bufidx]->
+						dma_addr,
+						channel->wr_buf_size,
+						DMA_FROM_DEVICE);
+
+				/*
+				 * Tell FPGA the buffer is done with. It's an
+				 * atomic operation to the FPGA, so what
+				 * happens with other channels doesn't matter,
+				 * and the certain channel is protected with
+				 * the channel-specific mutex.
+				 */
+
+				iowrite32(1 | (channel->chan_num << 1)
+					   | (bufidx << 12),
+					   &channel->endpoint->registers[
+						   fpga_buf_ctrl_reg]);
+				mmiowb(); /* Just to appear safe */
+			}
+
+			if (rc) {
+				mutex_unlock(&channel->wr_mutex);
+				return rc;
+			}
+		}
+
+		/* This includes a zero-count return = EOF */
+		if ((bytes_done >= count) || reached_eof)
+			break;
+
+		if (!exhausted)
+			continue; /* More in RAM buffer(s)? Just go on. */
+
+		if ((bytes_done > 0) &&
+		    (no_time_left ||
+		     (channel->wr_synchronous && channel->wr_allow_partial)))
+			break;
+
+		/*
+		 * Nonblocking read: The "ready" flag tells us that the FPGA
+		 * has data to send. In non-blocking mode, if it isn't on,
+		 * just return. But if there is, we jump directly to the point
+		 * where we ask for the FPGA to send all it has, and wait
+		 * until that data arrives. So in a sense, we *do* block in
+		 * nonblocking mode, but only for a very short time.
+		 */
+
+		if (!no_time_left && (filp->f_flags & O_NONBLOCK)) {
+			if (bytes_done > 0)
+				break;
+
+			if (ready)
+				goto desperate;
+
+			bytes_done = -EAGAIN;
+			break;
+		}
+
+		if (!no_time_left || (bytes_done > 0)) {
+			/*
+			 * Note that in case of an element-misaligned read
+			 * request, offsetlimit will include the last element,
+			 * which will be partially read from.
+			 */
+			int offsetlimit = ((count - bytes_done) - 1) >>
+				channel->log2_element_size;
+			int buf_elements = channel->wr_buf_size >>
+				channel->log2_element_size;
+
+			/*
+			 * In synchronous mode, always send an offset limit.
+			 * Just don't send a value too big.
+			 */
+
+			if (channel->wr_synchronous) {
+				/* Don't request more than one buffer */
+				if (channel->wr_allow_partial &&
+				    (offsetlimit >= buf_elements))
+					offsetlimit = buf_elements - 1;
+
+				/* Don't request more than all buffers */
+				if (!channel->wr_allow_partial &&
+				    (offsetlimit >=
+				     (buf_elements * channel->num_wr_buffers)))
+					offsetlimit = buf_elements *
+						channel->num_wr_buffers - 1;
+			}
+
+			/*
+			 * In asynchronous mode, force early flush of a buffer
+			 * only if that will allow returning a full count. The
+			 * "offsetlimit < ( ... )" rather than "<=" excludes
+			 * requesting a full buffer, which would obviously
+			 * cause a buffer transmission anyhow
+			 */
+
+			if (channel->wr_synchronous ||
+			    (offsetlimit < (buf_elements - 1))) {
+
+				mutex_lock(&channel->endpoint->register_mutex);
+
+				iowrite32(offsetlimit,
+					  &channel->endpoint->registers[
+						  fpga_buf_offset_reg]);
+				mmiowb();
+
+				iowrite32(1 | (channel->chan_num << 1) |
+					   (2 << 24) |  /* 2 = offset limit */
+					   (waiting_bufidx << 12),
+					   &channel->endpoint->registers[
+						   fpga_buf_ctrl_reg]);
+
+				mmiowb(); /* Just to appear safe */
+
+				mutex_unlock(&channel->endpoint->
+					     register_mutex);
+			}
+
+		}
+
+		/*
+		 * If partial completion is disallowed, there is no point in
+		 * timeout sleeping. Neither if no_time_left is set and
+		 * there's no data.
+		 */
+
+		if (!channel->wr_allow_partial ||
+		    (no_time_left && (bytes_done == 0))) {
+
+			/*
+			 * This do-loop will run more than once if another
+			 * thread reasserted wr_sleepy before we got the mutex
+			 * back, so we try again.
+			 */
+
+			do {
+				mutex_unlock(&channel->wr_mutex);
+
+				if (wait_event_interruptible(
+					    channel->wr_wait,
+					    (!channel->wr_sleepy)))
+					goto interrupted;
+
+				if (mutex_lock_interruptible(
+					    &channel->wr_mutex))
+					goto interrupted;
+			} while (channel->wr_sleepy);
+
+			continue;
+
+interrupted: /* Mutex is not held if got here */
+			if (channel->endpoint->fatal_error)
+				return -EIO;
+			if (bytes_done)
+				return bytes_done;
+			if (filp->f_flags & O_NONBLOCK)
+				return -EAGAIN; /* Don't admit snoozing */
+			return -EINTR;
+		}
+
+		left_to_sleep = deadline - ((long) jiffies);
+
+		/*
+		 * If our time is out, skip the waiting. We may miss wr_sleepy
+		 * being deasserted but hey, almost missing the train is like
+		 * missing it.
+		 */
+
+		if (left_to_sleep > 0) {
+			left_to_sleep =
+				wait_event_interruptible_timeout(
+					channel->wr_wait,
+					(!channel->wr_sleepy),
+					left_to_sleep);
+
+			if (!channel->wr_sleepy)
+				continue;
+
+			if (left_to_sleep < 0) { /* Interrupt */
+				mutex_unlock(&channel->wr_mutex);
+				if (channel->endpoint->fatal_error)
+					return -EIO;
+				if (bytes_done)
+					return bytes_done;
+				return -EINTR;
+			}
+		}
+
+desperate:
+		no_time_left = 1; /* We're out of sleeping time. Desperate! */
+
+		if (bytes_done == 0) {
+			/*
+			 * Reaching here means that we allow partial return,
+			 * that we've run out of time, and that we have
+			 * nothing to return.
+			 * So tell the FPGA to send anything it has or gets.
+			 */
+
+			iowrite32(1 | (channel->chan_num << 1) |
+				   (3 << 24) |  /* Opcode 3, flush it all! */
+				   (waiting_bufidx << 12),
+				   &channel->endpoint->registers[
+					   fpga_buf_ctrl_reg]);
+			mmiowb(); /* Just to appear safe */
+		}
+
+		/*
+		 * Formally speaking, we should block for data at this point.
+		 * But to keep the code cleaner, we'll just finish the loop,
+		 * make the unlikely check for data, and then block at the
+		 * usual place.
+		 */
+	}
+
+	mutex_unlock(&channel->wr_mutex);
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	return bytes_done;
+}
+
+/*
+ * The timeout argument takes values as follows:
+ *  >0 : Flush with timeout
+ * ==0 : Flush, and wait idefinitely for the flush to complete
+ *  <0 : Autoflush: Flush only if there's a single buffer occupied
+ */
+
+static int xillybus_myflush(struct xilly_channel *channel, long timeout)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	int end_offset_plus1;
+	int bufidx, bufidx_minus1;
+	int i;
+	int empty;
+	int new_rd_host_buf_pos;
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+	rc = mutex_lock_interruptible(&channel->rd_mutex);
+
+	if (rc)
+		return rc;
+
+	/*
+	 * Don't flush a closed channel. This can happen when the work queued
+	 * autoflush thread fires off after the file has closed. This is not
+	 * an error, just something to dismiss.
+	 */
+
+	if (!channel->rd_ref_count)
+		goto done;
+
+	bufidx = channel->rd_host_buf_idx;
+
+	bufidx_minus1 = (bufidx == 0) ? channel->num_rd_buffers - 1 : bufidx-1;
+
+	end_offset_plus1 = channel->rd_host_buf_pos >>
+		channel->log2_element_size;
+
+	new_rd_host_buf_pos = channel->rd_host_buf_pos -
+		(end_offset_plus1 << channel->log2_element_size);
+
+	/* Submit the current buffer if it's nonempty */
+	if (end_offset_plus1) {
+		unsigned char *tail = channel->rd_buffers[bufidx]->addr +
+			(end_offset_plus1 << channel->log2_element_size);
+
+		/* Copy  unflushed data, so we can put it in next buffer */
+		for (i = 0; i < new_rd_host_buf_pos; i++)
+			channel->rd_leftovers[i] = *tail++;
+
+		spin_lock_irqsave(&channel->rd_spinlock, flags);
+
+		/* Autoflush only if a single buffer is occupied */
+
+		if ((timeout < 0) &&
+		    (channel->rd_full ||
+		     (bufidx_minus1 != channel->rd_fpga_buf_idx))) {
+			spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+			/*
+			 * A new work item may be queued by the ISR exactly
+			 * now, since the execution of a work item allows the
+			 * queuing of a new one while it's running.
+			 */
+			goto done;
+		}
+
+		/* The 4th element is never needed for data, so it's a flag */
+		channel->rd_leftovers[3] = (new_rd_host_buf_pos != 0);
+
+		/* Set up rd_full to reflect a certain moment's state */
+
+		if (bufidx == channel->rd_fpga_buf_idx)
+			channel->rd_full = 1;
+		spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+		if (bufidx >= (channel->num_rd_buffers - 1))
+			channel->rd_host_buf_idx = 0;
+		else
+			channel->rd_host_buf_idx++;
+
+		channel->endpoint->ephw->hw_sync_sgl_for_device(
+			channel->endpoint,
+			channel->rd_buffers[bufidx]->dma_addr,
+			channel->rd_buf_size,
+			DMA_TO_DEVICE);
+
+		mutex_lock(&channel->endpoint->register_mutex);
+
+		iowrite32(end_offset_plus1 - 1,
+			  &channel->endpoint->registers[fpga_buf_offset_reg]);
+		mmiowb();
+
+		iowrite32((channel->chan_num << 1) | /* Channel ID */
+			   (2 << 24) |  /* Opcode 2, submit buffer */
+			   (bufidx << 12),
+			   &channel->endpoint->registers[fpga_buf_ctrl_reg]);
+		mmiowb(); /* Just to appear safe */
+
+		mutex_unlock(&channel->endpoint->register_mutex);
+	} else if (bufidx == 0)
+		bufidx = channel->num_rd_buffers - 1;
+	else
+		bufidx--;
+
+	channel->rd_host_buf_pos = new_rd_host_buf_pos;
+
+	if (timeout < 0)
+		goto done; /* Autoflush */
+
+
+	/*
+	 * bufidx is now the last buffer written to (or equal to
+	 * rd_fpga_buf_idx if buffer was never written to), and
+	 * channel->rd_host_buf_idx the one after it.
+	 *
+	 * If bufidx == channel->rd_fpga_buf_idx we're either empty or full.
+	 */
+
+	rc = 0;
+
+	while (1) { /* Loop waiting for draining of buffers */
+		spin_lock_irqsave(&channel->rd_spinlock, flags);
+
+		if (bufidx != channel->rd_fpga_buf_idx)
+			channel->rd_full = 1; /*
+					       * Not really full,
+					       * but needs waiting.
+					       */
+
+		empty = !channel->rd_full;
+
+		spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+		if (empty)
+			break;
+
+		/*
+		 * Indefinite sleep with mutex taken. With data waiting for
+		 * flushing user should not be surprised if open() for write
+		 * sleeps.
+		 */
+		if (timeout == 0)
+			wait_event_interruptible(channel->rd_wait,
+						 (!channel->rd_full));
+
+		else if (wait_event_interruptible_timeout(
+				 channel->rd_wait,
+				 (!channel->rd_full),
+				 timeout) == 0) {
+			pr_warn("xillybus: "
+				"Timed out while flushing. "
+				"Output data may be lost.\n");
+
+			rc = -ETIMEDOUT;
+			break;
+		}
+
+		if (channel->rd_full) {
+			rc = -EINTR;
+			break;
+		}
+	}
+
+done:
+	mutex_unlock(&channel->rd_mutex);
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	return rc;
+}
+
+static int xillybus_flush(struct file *filp, fl_owner_t id)
+{
+	if (!(filp->f_mode & FMODE_WRITE))
+		return 0;
+
+	return xillybus_myflush(filp->private_data, HZ); /* 1 second timeout */
+}
+
+static void xillybus_autoflush(struct work_struct *work)
+{
+	struct delayed_work *workitem = container_of(
+		work, struct delayed_work, work);
+	struct xilly_channel *channel = container_of(
+		workitem, struct xilly_channel, rd_workitem);
+	int rc;
+
+	rc = xillybus_myflush(channel, -1);
+
+	if (rc == -EINTR)
+		pr_warn("xillybus: Autoflush failed because "
+			"work queue thread got a signal.\n");
+	else if (rc)
+		pr_err("xillybus: Autoflush failed under "
+		       "weird circumstances.\n");
+
+}
+
+static ssize_t xillybus_write(struct file *filp, const char __user *userbuf,
+			      size_t count, loff_t *f_pos)
+{
+	ssize_t rc;
+	unsigned long flags;
+	int bytes_done = 0;
+	struct xilly_channel *channel = filp->private_data;
+
+	int full, exhausted;
+	/* Initializations are there only to silence warnings */
+
+	int howmany = 0, bufpos = 0, bufidx = 0, bufferdone = 0;
+	int end_offset_plus1 = 0;
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	rc = mutex_lock_interruptible(&channel->rd_mutex);
+
+	if (rc)
+		return rc;
+
+	rc = 0; /* Just to be clear about it. Compiler optimizes this out */
+
+	while (1) {
+		int bytes_to_do = count - bytes_done;
+
+		spin_lock_irqsave(&channel->rd_spinlock, flags);
+
+		full = channel->rd_full;
+
+		if (!full) {
+			bufidx = channel->rd_host_buf_idx;
+			bufpos = channel->rd_host_buf_pos;
+			howmany = channel->rd_buf_size - bufpos;
+
+			/*
+			 * Update rd_host_* to its state after this operation.
+			 * count=0 means committing the buffer immediately,
+			 * which is like flushing, but not necessarily block.
+			 */
+
+			if ((howmany > bytes_to_do) &&
+			    (count ||
+			     ((bufpos >> channel->log2_element_size) == 0))) {
+				bufferdone = 0;
+
+				howmany = bytes_to_do;
+				channel->rd_host_buf_pos += howmany;
+			} else {
+				bufferdone = 1;
+
+				if (count) {
+					end_offset_plus1 =
+						channel->rd_buf_size >>
+						channel->log2_element_size;
+					channel->rd_host_buf_pos = 0;
+				} else {
+					unsigned char *tail;
+					int i;
+
+					end_offset_plus1 = bufpos >>
+						channel->log2_element_size;
+
+					channel->rd_host_buf_pos -=
+						end_offset_plus1 <<
+						channel->log2_element_size;
+
+					tail = channel->
+						rd_buffers[bufidx]->addr +
+						(end_offset_plus1 <<
+						 channel->log2_element_size);
+
+					for (i = 0;
+					     i < channel->rd_host_buf_pos;
+					     i++)
+						channel->rd_leftovers[i] =
+							*tail++;
+				}
+
+				if (bufidx == channel->rd_fpga_buf_idx)
+					channel->rd_full = 1;
+
+				if (bufidx >= (channel->num_rd_buffers - 1))
+					channel->rd_host_buf_idx = 0;
+				else
+					channel->rd_host_buf_idx++;
+			}
+		}
+
+		/*
+		 * Marking our situation after the possible changes above,
+		 * for use  after releasing the spinlock.
+		 *
+		 * full = full before change
+		 * exhasted = full after possible change
+		 */
+
+		exhausted = channel->rd_full;
+
+		spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+		if (!full) { /* Go on, now without the spinlock */
+			unsigned char *head =
+				channel->rd_buffers[bufidx]->addr;
+			int i;
+
+			if ((bufpos == 0) || /* Zero means it's virgin */
+			    (channel->rd_leftovers[3] != 0)) {
+				channel->endpoint->ephw->hw_sync_sgl_for_cpu(
+					channel->endpoint,
+					channel->rd_buffers[bufidx]->dma_addr,
+					channel->rd_buf_size,
+					DMA_TO_DEVICE);
+
+				/* Virgin, but leftovers are due */
+				for (i = 0; i < bufpos; i++)
+					*head++ = channel->rd_leftovers[i];
+
+				channel->rd_leftovers[3] = 0; /* Clear flag */
+			}
+
+			if (copy_from_user(
+				    channel->rd_buffers[bufidx]->addr + bufpos,
+				    userbuf, howmany))
+				rc = -EFAULT;
+
+			userbuf += howmany;
+			bytes_done += howmany;
+
+			if (bufferdone) {
+				channel->endpoint->ephw->
+					hw_sync_sgl_for_device(
+						channel->endpoint,
+						channel->rd_buffers[bufidx]->
+						dma_addr,
+						channel->rd_buf_size,
+						DMA_TO_DEVICE);
+
+				mutex_lock(&channel->endpoint->register_mutex);
+
+				iowrite32(end_offset_plus1 - 1,
+					  &channel->endpoint->registers[
+						  fpga_buf_offset_reg]);
+				mmiowb();
+				iowrite32((channel->chan_num << 1) |
+					   (2 << 24) |  /* 2 = submit buffer */
+					   (bufidx << 12),
+					   &channel->endpoint->registers[
+						   fpga_buf_ctrl_reg]);
+				mmiowb(); /* Just to appear safe */
+
+				mutex_unlock(&channel->endpoint->
+					     register_mutex);
+
+				channel->rd_leftovers[3] =
+					(channel->rd_host_buf_pos != 0);
+			}
+
+			if (rc) {
+				mutex_unlock(&channel->rd_mutex);
+
+				if (channel->endpoint->fatal_error)
+					return -EIO;
+
+				if (!channel->rd_synchronous)
+					queue_delayed_work(
+						xillybus_wq,
+						&channel->rd_workitem,
+						XILLY_RX_TIMEOUT);
+
+				return rc;
+			}
+		}
+
+		if (bytes_done >= count)
+			break;
+
+		if (!exhausted)
+			continue; /* If there's more space, just go on */
+
+		if ((bytes_done > 0) && channel->rd_allow_partial)
+			break;
+
+		/*
+		 * Indefinite sleep with mutex taken. With data waiting for
+		 * flushing, user should not be surprised if open() for write
+		 * sleeps.
+		 */
+
+		if (filp->f_flags & O_NONBLOCK) {
+			bytes_done = -EAGAIN;
+			break;
+		}
+
+		wait_event_interruptible(channel->rd_wait,
+					 (!channel->rd_full));
+
+		if (channel->rd_full) {
+			mutex_unlock(&channel->rd_mutex);
+
+			if (channel->endpoint->fatal_error)
+				return -EIO;
+
+			if (bytes_done)
+				return bytes_done;
+			return -EINTR;
+		}
+	}
+
+	mutex_unlock(&channel->rd_mutex);
+
+	if (!channel->rd_synchronous)
+		queue_delayed_work(xillybus_wq,
+				   &channel->rd_workitem,
+				   XILLY_RX_TIMEOUT);
+
+	if ((channel->rd_synchronous) && (bytes_done > 0)) {
+		rc = xillybus_myflush(filp->private_data, 0); /* No timeout */
+
+		if (rc && (rc != -EINTR))
+			return rc;
+	}
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	return bytes_done;
+}
+
+static int xillybus_open(struct inode *inode, struct file *filp)
+{
+	int rc = 0;
+	unsigned long flags;
+	int minor = iminor(inode);
+	int major = imajor(inode);
+	struct xilly_endpoint *ep_iter, *endpoint = NULL;
+	struct xilly_channel *channel;
+
+	mutex_lock(&ep_list_lock);
+
+	list_for_each_entry(ep_iter, &list_of_endpoints, ep_list) {
+		if ((ep_iter->major == major) &&
+		    (minor >= ep_iter->lowest_minor) &&
+		    (minor < (ep_iter->lowest_minor +
+			      ep_iter->num_channels))) {
+			endpoint = ep_iter;
+			break;
+		}
+	}
+	mutex_unlock(&ep_list_lock);
+
+	if (!endpoint) {
+		pr_err("xillybus: open() failed to find a device "
+		       "for major=%d and minor=%d\n", major, minor);
+		return -ENODEV;
+	}
+
+	if (endpoint->fatal_error)
+		return -EIO;
+
+	channel = endpoint->channels[1 + minor - endpoint->lowest_minor];
+	filp->private_data = channel;
+
+
+	/*
+	 * It gets complicated because:
+	 * 1. We don't want to take a mutex we don't have to
+	 * 2. We don't want to open one direction if the other will fail.
+	 */
+
+	if ((filp->f_mode & FMODE_READ) && (!channel->num_wr_buffers))
+		return -ENODEV;
+
+	if ((filp->f_mode & FMODE_WRITE) && (!channel->num_rd_buffers))
+		return -ENODEV;
+
+	if ((filp->f_mode & FMODE_READ) && (filp->f_flags & O_NONBLOCK) &&
+	    (channel->wr_synchronous || !channel->wr_allow_partial ||
+	     !channel->wr_supports_nonempty)) {
+		pr_err("xillybus: open() failed: "
+		       "O_NONBLOCK not allowed for read on this device\n");
+		return -ENODEV;
+	}
+
+	if ((filp->f_mode & FMODE_WRITE) && (filp->f_flags & O_NONBLOCK) &&
+	    (channel->rd_synchronous || !channel->rd_allow_partial)) {
+		pr_err("xillybus: open() failed: "
+		       "O_NONBLOCK not allowed for write on this device\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Note: open() may block on getting mutexes despite O_NONBLOCK.
+	 * This shouldn't occur normally, since multiple open of the same
+	 * file descriptor is almost always prohibited anyhow
+	 * (*_exclusive_open is normally set in real-life systems).
+	 */
+
+	if (filp->f_mode & FMODE_READ) {
+		rc = mutex_lock_interruptible(&channel->wr_mutex);
+		if (rc)
+			return rc;
+	}
+
+	if (filp->f_mode & FMODE_WRITE) {
+		rc = mutex_lock_interruptible(&channel->rd_mutex);
+		if (rc)
+			goto unlock_wr;
+	}
+
+	if ((filp->f_mode & FMODE_READ) &&
+	    (channel->wr_ref_count != 0) &&
+	    (channel->wr_exclusive_open)) {
+		rc = -EBUSY;
+		goto unlock;
+	}
+
+	if ((filp->f_mode & FMODE_WRITE) &&
+	    (channel->rd_ref_count != 0) &&
+	    (channel->rd_exclusive_open)) {
+		rc = -EBUSY;
+		goto unlock;
+	}
+
+
+	if (filp->f_mode & FMODE_READ) {
+		if (channel->wr_ref_count == 0) { /* First open of file */
+			/* Move the host to first buffer */
+			spin_lock_irqsave(&channel->wr_spinlock, flags);
+			channel->wr_host_buf_idx = 0;
+			channel->wr_host_buf_pos = 0;
+			channel->wr_fpga_buf_idx = -1;
+			channel->wr_empty = 1;
+			channel->wr_ready = 0;
+			channel->wr_sleepy = 1;
+			channel->wr_eof = -1;
+			channel->wr_hangup = 0;
+
+			spin_unlock_irqrestore(&channel->wr_spinlock, flags);
+
+			iowrite32(1 | (channel->chan_num << 1) |
+				  (4 << 24) |  /* Opcode 4, open channel */
+				  ((channel->wr_synchronous & 1) << 23),
+				  &channel->endpoint->registers[
+					  fpga_buf_ctrl_reg]);
+			mmiowb(); /* Just to appear safe */
+		}
+
+		channel->wr_ref_count++;
+	}
+
+	if (filp->f_mode & FMODE_WRITE) {
+		if (channel->rd_ref_count == 0) { /* First open of file */
+			/* Move the host to first buffer */
+			spin_lock_irqsave(&channel->rd_spinlock, flags);
+			channel->rd_host_buf_idx = 0;
+			channel->rd_host_buf_pos = 0;
+			channel->rd_leftovers[3] = 0; /* No leftovers. */
+			channel->rd_fpga_buf_idx = channel->num_rd_buffers - 1;
+			channel->rd_full = 0;
+
+			spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+
+			iowrite32((channel->chan_num << 1) |
+				  (4 << 24),   /* Opcode 4, open channel */
+				  &channel->endpoint->registers[
+					  fpga_buf_ctrl_reg]);
+			mmiowb(); /* Just to appear safe */
+		}
+
+		channel->rd_ref_count++;
+	}
+
+unlock:
+	if (filp->f_mode & FMODE_WRITE)
+		mutex_unlock(&channel->rd_mutex);
+unlock_wr:
+	if (filp->f_mode & FMODE_READ)
+		mutex_unlock(&channel->wr_mutex);
+
+	if (!rc && (!channel->seekable))
+		return nonseekable_open(inode, filp);
+
+	return rc;
+}
+
+static int xillybus_release(struct inode *inode, struct file *filp)
+{
+	int rc;
+	unsigned long flags;
+	struct xilly_channel *channel = filp->private_data;
+
+	int buf_idx;
+	int eof;
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	if (filp->f_mode & FMODE_WRITE) {
+		rc = mutex_lock_interruptible(&channel->rd_mutex);
+
+		if (rc) {
+			pr_warn("xillybus: Failed to close file. "
+				"Hardware left in messy state.\n");
+			return rc;
+		}
+
+		channel->rd_ref_count--;
+
+		if (channel->rd_ref_count == 0) {
+
+			/*
+			 * We rely on the kernel calling flush()
+			 * before we get here.
+			 */
+
+			iowrite32((channel->chan_num << 1) | /* Channel ID */
+				  (5 << 24),  /* Opcode 5, close channel */
+				  &channel->endpoint->registers[
+					  fpga_buf_ctrl_reg]);
+			mmiowb(); /* Just to appear safe */
+		}
+		mutex_unlock(&channel->rd_mutex);
+	}
+
+	if (filp->f_mode & FMODE_READ) {
+		rc = mutex_lock_interruptible(&channel->wr_mutex);
+		if (rc) {
+			pr_warn("xillybus: Failed to close file. "
+				"Hardware left in messy state.\n");
+			return rc;
+		}
+
+		channel->wr_ref_count--;
+
+		if (channel->wr_ref_count == 0) {
+
+			iowrite32(1 | (channel->chan_num << 1) |
+				   (5 << 24),  /* Opcode 5, close channel */
+				   &channel->endpoint->registers[
+					   fpga_buf_ctrl_reg]);
+			mmiowb(); /* Just to appear safe */
+
+			/*
+			 * This is crazily cautious: We make sure that not
+			 * only that we got an EOF (be it because we closed
+			 * the channel or because of a user's EOF), but verify
+			 * that it's one beyond the last buffer arrived, so
+			 * we have no leftover buffers pending before wrapping
+			 * up (which can only happen in asynchronous channels,
+			 * BTW)
+			 */
+
+			while (1) {
+				spin_lock_irqsave(&channel->wr_spinlock,
+						  flags);
+				buf_idx = channel->wr_fpga_buf_idx;
+				eof = channel->wr_eof;
+				channel->wr_sleepy = 1;
+				spin_unlock_irqrestore(&channel->wr_spinlock,
+						       flags);
+
+				/*
+				 * Check if eof points at the buffer after
+				 * the last one the FPGA submitted. Note that
+				 * no EOF is marked by negative eof.
+				 */
+
+				buf_idx++;
+				if (buf_idx == channel->num_wr_buffers)
+					buf_idx = 0;
+
+				if (buf_idx == eof)
+					break;
+
+				/*
+				 * Steal extra 100 ms if awaken by interrupt.
+				 * This is a simple workaround for an
+				 * interrupt pending when entering, which would
+				 * otherwise result in declaring the hardware
+				 * non-responsive.
+				 */
+
+				if (wait_event_interruptible(
+					    channel->wr_wait,
+					    (!channel->wr_sleepy)))
+					msleep(100);
+
+				if (channel->wr_sleepy) {
+					mutex_unlock(&channel->wr_mutex);
+					pr_warn("xillybus: Hardware failed to "
+						"respond to close command, "
+						"therefore left in "
+						"messy state.\n");
+					return -EINTR;
+				}
+			}
+		}
+
+		mutex_unlock(&channel->wr_mutex);
+	}
+
+	return 0;
+}
+static loff_t xillybus_llseek(struct file *filp, loff_t offset, int whence)
+{
+	struct xilly_channel *channel = filp->private_data;
+	loff_t pos = filp->f_pos;
+	int rc = 0;
+
+	/*
+	 * Take both mutexes not allowing interrupts, since it seems like
+	 * common applications don't expect an -EINTR here. Besides, multiple
+	 * access to a single file descriptor on seekable devices is a mess
+	 * anyhow.
+	 */
+
+	if (channel->endpoint->fatal_error)
+		return -EIO;
+
+	mutex_lock(&channel->wr_mutex);
+	mutex_lock(&channel->rd_mutex);
+
+	switch (whence) {
+	case 0:
+		pos = offset;
+		break;
+	case 1:
+		pos += offset;
+		break;
+	case 2:
+		pos = offset; /* Going to the end => to the beginning */
+		break;
+	default:
+		rc = -EINVAL;
+		goto end;
+	}
+
+	/* In any case, we must finish on an element boundary */
+	if (pos & ((1 << channel->log2_element_size) - 1)) {
+		rc = -EINVAL;
+		goto end;
+	}
+
+	mutex_lock(&channel->endpoint->register_mutex);
+
+	iowrite32(pos >> channel->log2_element_size,
+		  &channel->endpoint->registers[fpga_buf_offset_reg]);
+	mmiowb();
+	iowrite32((channel->chan_num << 1) |
+		  (6 << 24),  /* Opcode 6, set address */
+		  &channel->endpoint->registers[fpga_buf_ctrl_reg]);
+	mmiowb(); /* Just to appear safe */
+
+	mutex_unlock(&channel->endpoint->register_mutex);
+
+end:
+	mutex_unlock(&channel->rd_mutex);
+	mutex_unlock(&channel->wr_mutex);
+
+	if (rc) /* Return error after releasing mutexes */
+		return rc;
+
+	filp->f_pos = pos;
+
+	/*
+	 * Since seekable devices are allowed only when the channel is
+	 * synchronous, we assume that there is no data pending in either
+	 * direction (which holds true as long as no concurrent access on the
+	 * file descriptor takes place).
+	 * The only thing we may need to throw away is leftovers from partial
+	 * write() flush.
+	 */
+
+	channel->rd_leftovers[3] = 0;
+
+	return pos;
+}
+
+static unsigned int xillybus_poll(struct file *filp, poll_table *wait)
+{
+	struct xilly_channel *channel = filp->private_data;
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	poll_wait(filp, &channel->endpoint->ep_wait, wait);
+
+	/*
+	 * poll() won't play ball regarding read() channels which
+	 * aren't asynchronous and support the nonempty message. Allowing
+	 * that will create situations where data has been delivered at
+	 * the FPGA, and users expecting select() to wake up, which it may
+	 * not.
+	 */
+
+	if (!channel->wr_synchronous && channel->wr_supports_nonempty) {
+		poll_wait(filp, &channel->wr_wait, wait);
+		poll_wait(filp, &channel->wr_ready_wait, wait);
+
+		spin_lock_irqsave(&channel->wr_spinlock, flags);
+		if (!channel->wr_empty || channel->wr_ready)
+			mask |= POLLIN | POLLRDNORM;
+
+		if (channel->wr_hangup)
+			/*
+			 * Not POLLHUP, because its behavior is in the
+			 * mist, and POLLIN does what we want: Wake up
+			 * the read file descriptor so it sees EOF.
+			 */
+			mask |=  POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore(&channel->wr_spinlock, flags);
+	}
+
+	/*
+	 * If partial data write is disallowed on a write() channel,
+	 * it's pointless to ever signal OK to write, because is could
+	 * block despite some space being available.
+	 */
+
+	if (channel->rd_allow_partial) {
+		poll_wait(filp, &channel->rd_wait, wait);
+
+		spin_lock_irqsave(&channel->rd_spinlock, flags);
+		if (!channel->rd_full)
+			mask |= POLLOUT | POLLWRNORM;
+		spin_unlock_irqrestore(&channel->rd_spinlock, flags);
+	}
+
+	if (channel->endpoint->fatal_error)
+		mask |= POLLERR;
+
+	return mask;
+}
+
+static const struct file_operations xillybus_fops = {
+	.owner      = THIS_MODULE,
+	.read       = xillybus_read,
+	.write      = xillybus_write,
+	.open       = xillybus_open,
+	.flush      = xillybus_flush,
+	.release    = xillybus_release,
+	.llseek     = xillybus_llseek,
+	.poll       = xillybus_poll,
+};
+
+static int xillybus_init_chrdev(struct xilly_endpoint *endpoint,
+				const unsigned char *idt)
+{
+	int rc;
+	dev_t dev;
+	int devnum, i, minor, major;
+	char devname[48];
+	struct device *device;
+
+	rc = alloc_chrdev_region(&dev, 0, /* minor start */
+				 endpoint->num_channels,
+				 xillyname);
+
+	if (rc) {
+		pr_warn("xillybus: Failed to obtain major/minors");
+		goto error1;
+	}
+
+	endpoint->major = major = MAJOR(dev);
+	endpoint->lowest_minor = minor = MINOR(dev);
+
+	cdev_init(&endpoint->cdev, &xillybus_fops);
+	endpoint->cdev.owner = endpoint->ephw->owner;
+	rc = cdev_add(&endpoint->cdev, MKDEV(major, minor),
+		      endpoint->num_channels);
+	if (rc) {
+		pr_warn("xillybus: Failed to add cdev. Aborting.\n");
+		goto error2;
+	}
+
+	idt++;
+
+	for (i = minor, devnum = 0;
+	     devnum < endpoint->num_channels;
+	     devnum++, i++) {
+		snprintf(devname, sizeof(devname)-1, "xillybus_%s", idt);
+
+		devname[sizeof(devname)-1] = 0; /* Should never matter */
+
+		while (*idt++)
+			/* Skip to next */;
+
+		device = device_create(xillybus_class,
+				       NULL,
+				       MKDEV(major, i),
+				       NULL,
+				       devname);
+
+		if (IS_ERR(device)) {
+			pr_warn("xillybus: Failed to create %s "
+				"device. Aborting.\n", devname);
+			goto error3;
+		}
+	}
+
+	pr_info("xillybus: Created %d device files.\n",
+		endpoint->num_channels);
+	return 0; /* succeed */
+
+error3:
+	devnum--; i--;
+	for (; devnum >= 0; devnum--, i--)
+		device_destroy(xillybus_class, MKDEV(major, i));
+
+	cdev_del(&endpoint->cdev);
+error2:
+	unregister_chrdev_region(MKDEV(major, minor), endpoint->num_channels);
+error1:
+
+	return rc;
+}
+
+static void xillybus_cleanup_chrdev(struct xilly_endpoint *endpoint)
+{
+	int minor;
+
+	for (minor = endpoint->lowest_minor;
+	     minor < (endpoint->lowest_minor + endpoint->num_channels);
+	     minor++)
+		device_destroy(xillybus_class, MKDEV(endpoint->major, minor));
+	cdev_del(&endpoint->cdev);
+	unregister_chrdev_region(MKDEV(endpoint->major,
+				       endpoint->lowest_minor),
+				 endpoint->num_channels);
+
+	pr_info("xillybus: Removed %d device files.\n",
+		endpoint->num_channels);
+}
+
+
+struct xilly_endpoint *xillybus_init_endpoint(struct pci_dev *pdev,
+					      struct device *dev,
+					      struct xilly_endpoint_hardware
+					      *ephw)
+{
+	struct xilly_endpoint *endpoint;
+
+	endpoint = kzalloc(sizeof(*endpoint), GFP_KERNEL);
+	if (!endpoint) {
+		pr_err("xillybus: Failed to allocate memory. Aborting.\n");
+		return NULL;
+	}
+
+	endpoint->pdev = pdev;
+	endpoint->dev = dev;
+	endpoint->ephw = ephw;
+	INIT_LIST_HEAD(&endpoint->cleanup.to_kfree);
+	INIT_LIST_HEAD(&endpoint->cleanup.to_pagefree);
+	INIT_LIST_HEAD(&endpoint->cleanup.to_unmap);
+	endpoint->msg_counter = 0x0b;
+	endpoint->failed_messages = 0;
+	endpoint->fatal_error = 0;
+
+	init_waitqueue_head(&endpoint->ep_wait);
+	mutex_init(&endpoint->register_mutex);
+
+	return endpoint;
+}
+EXPORT_SYMBOL(xillybus_init_endpoint);
+
+static int xilly_quiesce(struct xilly_endpoint *endpoint)
+{
+	endpoint->idtlen = -1;
+	wmb(); /* Make sure idtlen is set before sending command */
+	iowrite32((u32) (endpoint->dma_using_dac & 0x0001),
+		  &endpoint->registers[fpga_dma_control_reg]);
+	mmiowb();
+
+	wait_event_interruptible_timeout(endpoint->ep_wait,
+					 (endpoint->idtlen >= 0),
+					 XILLY_TIMEOUT);
+
+	if (endpoint->idtlen < 0) {
+		pr_err("xillybus: Failed to quiesce the device on "
+		       "exit. Quitting while leaving a mess.\n");
+		return -ENODEV;
+	}
+	return 0; /* Success */
+}
+
+int xillybus_endpoint_discovery(struct xilly_endpoint *endpoint)
+{
+	int rc = 0;
+
+	struct xilly_cleanup tmpmem;
+	int idtbuffersize = (1 << PAGE_SHIFT);
+
+	/*
+	 * The bogus IDT is used during bootstrap for allocating the initial
+	 * message buffer, and then the message buffer and space for the IDT
+	 * itself. The initial message buffer is of a single page's size, but
+	 * it's soon replaced with a more modest one (and memory is freed).
+	 */
+
+	unsigned char bogus_idt[8] = { 1, 224, (PAGE_SHIFT)-2, 0,
+				       3, 192, PAGE_SHIFT, 0 };
+	struct xilly_idt_handle idt_handle;
+
+	INIT_LIST_HEAD(&tmpmem.to_kfree);
+	INIT_LIST_HEAD(&tmpmem.to_pagefree);
+	INIT_LIST_HEAD(&tmpmem.to_unmap);
+
+	/*
+	 * Writing the value 0x00000001 to Endianness register signals which
+	 * endianness this processor is using, so the FPGA can swap words as
+	 * necessary.
+	 */
+
+	iowrite32(1, &endpoint->registers[fpga_endian_reg]);
+	mmiowb(); /* Writes below are affected by the one above. */
+
+	/* Bootstrap phase I: Allocate temporary message buffer */
+
+	endpoint->num_channels = 0;
+
+	rc = xilly_setupchannels(endpoint, &tmpmem, bogus_idt, 1);
+
+	if (rc)
+		goto failed_buffers;
+
+	/* Clear the message subsystem (and counter in particular) */
+	iowrite32(0x04, &endpoint->registers[fpga_msg_ctrl_reg]);
+	mmiowb();
+
+	endpoint->idtlen = -1;
+
+	smp_wmb();
+
+	/*
+	 * Set DMA 32/64 bit mode, quiesce the device (?!) and get IDT
+	 * buffer size.
+	 */
+	iowrite32((u32) (endpoint->dma_using_dac & 0x0001),
+		   &endpoint->registers[fpga_dma_control_reg]);
+	mmiowb();
+
+	wait_event_interruptible_timeout(endpoint->ep_wait,
+					 (endpoint->idtlen >= 0),
+					 XILLY_TIMEOUT);
+
+	if (endpoint->idtlen < 0) {
+		pr_err("xillybus: No response from FPGA. Aborting.\n");
+		rc = -ENODEV;
+		goto failed_quiesce;
+	}
+
+	/* Enable DMA */
+	iowrite32((u32) (0x0002 | (endpoint->dma_using_dac & 0x0001)),
+		   &endpoint->registers[fpga_dma_control_reg]);
+	mmiowb();
+
+	/* Bootstrap phase II: Allocate buffer for IDT and obtain it */
+	while (endpoint->idtlen >= idtbuffersize) {
+		idtbuffersize *= 2;
+		bogus_idt[6]++;
+	}
+
+	endpoint->num_channels = 1;
+
+	rc = xilly_setupchannels(endpoint, &tmpmem, bogus_idt, 2);
+
+	if (rc)
+		goto failed_idt;
+
+	smp_wmb();
+
+	rc = xilly_obtain_idt(endpoint);
+
+	if (rc)
+		goto failed_idt;
+
+	xilly_scan_idt(endpoint, &idt_handle);
+
+	if (!idt_handle.chandesc) {
+		rc = -ENODEV;
+		goto failed_idt;
+	}
+	/* Bootstrap phase III: Allocate buffers according to IDT */
+
+	rc = xilly_setupchannels(endpoint,
+				 &endpoint->cleanup,
+				 idt_handle.chandesc,
+				 idt_handle.entries);
+
+	if (rc)
+		goto failed_idt;
+
+	smp_wmb(); /* mutex_lock below should suffice, but won't hurt.*/
+
+	/*
+	 * endpoint is now completely configured. We put it on the list
+	 * available to open() before registering the char device(s)
+	 */
+
+	mutex_lock(&ep_list_lock);
+	list_add_tail(&endpoint->ep_list, &list_of_endpoints);
+	mutex_unlock(&ep_list_lock);
+
+	rc = xillybus_init_chrdev(endpoint, idt_handle.idt);
+
+	if (rc)
+		goto failed_chrdevs;
+
+	xillybus_do_cleanup(&tmpmem, endpoint);
+
+	return 0;
+
+failed_chrdevs:
+	mutex_lock(&ep_list_lock);
+	list_del(&endpoint->ep_list);
+	mutex_unlock(&ep_list_lock);
+
+failed_idt:
+	/* Quiesce the device. Now it's serious to do it */
+	rc = xilly_quiesce(endpoint);
+
+	if (rc)
+		return rc; /* FPGA may still DMA, so no release */
+
+	flush_workqueue(xillybus_wq);
+failed_quiesce:
+failed_buffers:
+	xillybus_do_cleanup(&tmpmem, endpoint);
+
+	return rc;
+}
+EXPORT_SYMBOL(xillybus_endpoint_discovery);
+
+void xillybus_endpoint_remove(struct xilly_endpoint *endpoint)
+{
+	xillybus_cleanup_chrdev(endpoint);
+
+	mutex_lock(&ep_list_lock);
+	list_del(&endpoint->ep_list);
+	mutex_unlock(&ep_list_lock);
+
+	xilly_quiesce(endpoint);
+
+	/*
+	 * Flushing is done upon endpoint release to prevent access to memory
+	 * just about to be released. This makes the quiesce complete.
+	 */
+	flush_workqueue(xillybus_wq);
+}
+EXPORT_SYMBOL(xillybus_endpoint_remove);
+
+static int __init xillybus_init(void)
+{
+	int rc = 0;
+
+	mutex_init(&ep_list_lock);
+
+	xillybus_class = class_create(THIS_MODULE, xillyname);
+	if (IS_ERR(xillybus_class)) {
+		rc = PTR_ERR(xillybus_class);
+		pr_warn("xillybus: Failed to register class xillybus\n");
+
+		return rc;
+	}
+
+	xillybus_wq = alloc_workqueue(xillyname, 0, 0);
+
+	return 0; /* Success */
+}
+
+static void __exit xillybus_exit(void)
+{
+	/* flush_workqueue() was called for each endpoint released */
+	destroy_workqueue(xillybus_wq);
+
+	class_destroy(xillybus_class);
+}
+
+module_init(xillybus_init);
+module_exit(xillybus_exit);
diff --git a/drivers/staging/xillybus/xillybus_of.c b/drivers/staging/xillybus/xillybus_of.c
new file mode 100644
index 0000000..92c2931
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus_of.c
@@ -0,0 +1,212 @@
+/*
+ * linux/drivers/misc/xillybus_of.c
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus FPGA/host framework using Open Firmware.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include "xillybus.h"
+
+MODULE_DESCRIPTION("Xillybus driver for Open Firmware");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_VERSION("1.06");
+MODULE_ALIAS("xillybus_of");
+MODULE_LICENSE("GPL v2");
+
+static const char xillyname[] = "xillybus_of";
+
+/* Match table for of_platform binding */
+static struct of_device_id xillybus_of_match[] = {
+	{ .compatible = "xlnx,xillybus-1.00.a", },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, xillybus_of_match);
+
+static void xilly_dma_sync_single_for_cpu_of(struct xilly_endpoint *ep,
+					     dma_addr_t dma_handle,
+					     size_t size,
+					     int direction)
+{
+	dma_sync_single_for_cpu(ep->dev, dma_handle, size, direction);
+}
+
+static void xilly_dma_sync_single_for_device_of(struct xilly_endpoint *ep,
+						dma_addr_t dma_handle,
+						size_t size,
+						int direction)
+{
+	dma_sync_single_for_device(ep->dev, dma_handle, size, direction);
+}
+
+static dma_addr_t xilly_map_single_of(struct xilly_cleanup *mem,
+				      struct xilly_endpoint *ep,
+				      void *ptr,
+				      size_t size,
+				      int direction
+	)
+{
+
+	dma_addr_t addr = 0;
+	struct xilly_dma *this;
+
+	this = kmalloc(sizeof(struct xilly_dma), GFP_KERNEL);
+	if (!this)
+		return 0;
+
+	addr = dma_map_single(ep->dev, ptr, size, direction);
+	this->direction = direction;
+
+	if (dma_mapping_error(ep->dev, addr)) {
+		kfree(this);
+		return 0;
+	}
+
+	this->dma_addr = addr;
+	this->dev = ep->dev;
+	this->size = size;
+
+	list_add_tail(&this->node, &mem->to_unmap);
+
+	return addr;
+}
+
+static void xilly_unmap_single_of(struct xilly_dma *entry)
+{
+	dma_unmap_single(entry->dev,
+			 entry->dma_addr,
+			 entry->size,
+			 entry->direction);
+}
+
+static struct xilly_endpoint_hardware of_hw = {
+	.owner = THIS_MODULE,
+	.hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_of,
+	.hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_of,
+	.map_single = xilly_map_single_of,
+	.unmap_single = xilly_unmap_single_of
+};
+
+static int xilly_drv_probe(struct platform_device *op)
+{
+	struct device *dev = &op->dev;
+	struct xilly_endpoint *endpoint;
+	int rc = 0;
+	int irq;
+
+	endpoint = xillybus_init_endpoint(NULL, dev, &of_hw);
+
+	if (!endpoint)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, endpoint);
+
+	rc = of_address_to_resource(dev->of_node, 0, &endpoint->res);
+	if (rc) {
+		pr_warn("xillybus: Failed to obtain device tree "
+			"resource\n");
+		goto failed_request_regions;
+	}
+
+	if  (!request_mem_region(endpoint->res.start,
+				 resource_size(&endpoint->res), xillyname)) {
+		pr_err("xillybus: request_mem_region failed. Aborting.\n");
+		rc = -EBUSY;
+		goto failed_request_regions;
+	}
+
+	endpoint->registers = of_iomap(dev->of_node, 0);
+
+	if (!endpoint->registers) {
+		pr_err("xillybus: Failed to map I/O memory. Aborting.\n");
+		goto failed_iomap0;
+	}
+
+	irq = irq_of_parse_and_map(dev->of_node, 0);
+
+	rc = request_irq(irq, xillybus_isr, 0, xillyname, endpoint);
+
+	if (rc) {
+		pr_err("xillybus: Failed to register IRQ handler. "
+		       "Aborting.\n");
+		rc = -ENODEV;
+		goto failed_register_irq;
+	}
+
+	rc = xillybus_endpoint_discovery(endpoint);
+
+	if (!rc)
+		return 0;
+
+	free_irq(irq, endpoint);
+
+failed_register_irq:
+	iounmap(endpoint->registers);
+failed_iomap0:
+	release_mem_region(endpoint->res.start,
+			   resource_size(&endpoint->res));
+
+failed_request_regions:
+	xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+	kfree(endpoint);
+	return rc;
+}
+
+static int xilly_drv_remove(struct platform_device *op)
+{
+	struct device *dev = &op->dev;
+	struct xilly_endpoint *endpoint = dev_get_drvdata(dev);
+	int irq = irq_of_parse_and_map(dev->of_node, 0);
+
+	xillybus_endpoint_remove(endpoint);
+
+	free_irq(irq, endpoint);
+
+	iounmap(endpoint->registers);
+	release_mem_region(endpoint->res.start,
+			   resource_size(&endpoint->res));
+
+	xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+	kfree(endpoint);
+
+	return 0;
+}
+
+static struct platform_driver xillybus_platform_driver = {
+	.probe = xilly_drv_probe,
+	.remove = xilly_drv_remove,
+	.driver = {
+		.name = xillyname,
+		.owner = THIS_MODULE,
+		.of_match_table = xillybus_of_match,
+	},
+};
+
+static int __init xillybus_of_init(void)
+{
+	return platform_driver_register(&xillybus_platform_driver);
+}
+
+static void __exit xillybus_of_exit(void)
+{
+	platform_driver_unregister(&xillybus_platform_driver);
+}
+
+module_init(xillybus_of_init);
+module_exit(xillybus_of_exit);
diff --git a/drivers/staging/xillybus/xillybus_pcie.c b/drivers/staging/xillybus/xillybus_pcie.c
new file mode 100644
index 0000000..6701365
--- /dev/null
+++ b/drivers/staging/xillybus/xillybus_pcie.c
@@ -0,0 +1,262 @@
+/*
+ * linux/drivers/misc/xillybus_pcie.c
+ *
+ * Copyright 2011 Xillybus Ltd, http://xillybus.com
+ *
+ * Driver for the Xillybus FPGA/host framework using PCI Express.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include <linux/slab.h>
+#include "xillybus.h"
+
+MODULE_DESCRIPTION("Xillybus driver for PCIe");
+MODULE_AUTHOR("Eli Billauer, Xillybus Ltd.");
+MODULE_VERSION("1.06");
+MODULE_ALIAS("xillybus_pcie");
+MODULE_LICENSE("GPL v2");
+
+#define PCI_DEVICE_ID_XILLYBUS		0xebeb
+
+#define PCI_VENDOR_ID_ALTERA		0x1172
+#define PCI_VENDOR_ID_ACTEL		0x11aa
+#define PCI_VENDOR_ID_LATTICE		0x1204
+
+static const char xillyname[] = "xillybus_pcie";
+
+static DEFINE_PCI_DEVICE_TABLE(xillyids) = {
+	{PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILLYBUS)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_XILLYBUS)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ACTEL, PCI_DEVICE_ID_XILLYBUS)},
+	{PCI_DEVICE(PCI_VENDOR_ID_LATTICE, PCI_DEVICE_ID_XILLYBUS)},
+	{ /* End: all zeroes */ }
+};
+
+static int xilly_pci_direction(int direction)
+{
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		return PCI_DMA_TODEVICE;
+	case DMA_FROM_DEVICE:
+		return PCI_DMA_FROMDEVICE;
+	default:
+		return PCI_DMA_BIDIRECTIONAL;
+	}
+}
+
+static void xilly_dma_sync_single_for_cpu_pci(struct xilly_endpoint *ep,
+					      dma_addr_t dma_handle,
+					      size_t size,
+					      int direction)
+{
+	pci_dma_sync_single_for_cpu(ep->pdev,
+				    dma_handle,
+				    size,
+				    xilly_pci_direction(direction));
+}
+
+static void xilly_dma_sync_single_for_device_pci(struct xilly_endpoint *ep,
+						 dma_addr_t dma_handle,
+						 size_t size,
+						 int direction)
+{
+	pci_dma_sync_single_for_device(ep->pdev,
+				       dma_handle,
+				       size,
+				       xilly_pci_direction(direction));
+}
+
+/*
+ * Map either through the PCI DMA mapper or the non_PCI one. Behind the
+ * scenes exactly the same functions are called with the same parameters,
+ * but that can change.
+ */
+
+static dma_addr_t xilly_map_single_pci(struct xilly_cleanup *mem,
+				       struct xilly_endpoint *ep,
+				       void *ptr,
+				       size_t size,
+				       int direction
+	)
+{
+
+	dma_addr_t addr = 0;
+	struct xilly_dma *this;
+	int pci_direction;
+
+	this = kmalloc(sizeof(struct xilly_dma), GFP_KERNEL);
+	if (!this)
+		return 0;
+
+	pci_direction = xilly_pci_direction(direction);
+	addr = pci_map_single(ep->pdev, ptr, size, pci_direction);
+	this->direction = pci_direction;
+
+	if (pci_dma_mapping_error(ep->pdev, addr)) {
+		kfree(this);
+		return 0;
+	}
+
+	this->dma_addr = addr;
+	this->pdev = ep->pdev;
+	this->size = size;
+
+	list_add_tail(&this->node, &mem->to_unmap);
+
+	return addr;
+}
+
+static void xilly_unmap_single_pci(struct xilly_dma *entry)
+{
+	pci_unmap_single(entry->pdev,
+			 entry->dma_addr,
+			 entry->size,
+			 entry->direction);
+}
+
+static struct xilly_endpoint_hardware pci_hw = {
+	.owner = THIS_MODULE,
+	.hw_sync_sgl_for_cpu = xilly_dma_sync_single_for_cpu_pci,
+	.hw_sync_sgl_for_device = xilly_dma_sync_single_for_device_pci,
+	.map_single = xilly_map_single_pci,
+	.unmap_single = xilly_unmap_single_pci
+};
+
+static int xilly_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
+{
+	struct xilly_endpoint *endpoint;
+	int rc = 0;
+
+	endpoint = xillybus_init_endpoint(pdev, NULL, &pci_hw);
+
+	if (!endpoint)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, endpoint);
+
+	rc = pci_enable_device(pdev);
+
+	/* L0s has caused packet drops. No power saving, thank you. */
+
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
+
+	if (rc) {
+		pr_err("xillybus: pci_enable_device() failed. "
+		       "Aborting.\n");
+		goto no_enable;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		pr_err("xillybus: Incorrect BAR configuration. "
+		       "Aborting.\n");
+		rc = -ENODEV;
+		goto bad_bar;
+	}
+
+	rc = pci_request_regions(pdev, xillyname);
+	if (rc) {
+		pr_err("xillybus: pci_request_regions() failed. "
+		       "Aborting.\n");
+		goto failed_request_regions;
+	}
+
+	endpoint->registers = pci_iomap(pdev, 0, 128);
+
+	if (!endpoint->registers) {
+		pr_err("xillybus: Failed to map BAR 0. Aborting.\n");
+		goto failed_iomap0;
+	}
+
+	pci_set_master(pdev);
+
+	/* Set up a single MSI interrupt */
+	if (pci_enable_msi(pdev)) {
+		pr_err("xillybus: Failed to enable MSI interrupts. "
+		       "Aborting.\n");
+		rc = -ENODEV;
+		goto failed_enable_msi;
+	}
+	rc = request_irq(pdev->irq, xillybus_isr, 0, xillyname, endpoint);
+
+	if (rc) {
+		pr_err("xillybus: Failed to register MSI handler. "
+		       "Aborting.\n");
+		rc = -ENODEV;
+		goto failed_register_msi;
+	}
+
+	/*
+	 * In theory, an attempt to set the DMA mask to 64 and dma_using_dac=1
+	 * is the right thing. But some unclever PCIe drivers report it's OK
+	 * when the hardware drops those 64-bit PCIe packets. So trust
+	 * nobody and use 32 bits DMA addressing in any case.
+	 */
+
+	if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
+		endpoint->dma_using_dac = 0;
+	else {
+		pr_err("xillybus: Failed to set DMA mask. "
+		       "Aborting.\n");
+		rc = -ENODEV;
+		goto failed_dmamask;
+	}
+
+	rc = xillybus_endpoint_discovery(endpoint);
+
+	if (!rc)
+		return 0;
+
+failed_dmamask:
+	free_irq(pdev->irq, endpoint);
+failed_register_msi:
+	pci_disable_msi(pdev);
+failed_enable_msi:
+	/* pci_clear_master(pdev); Nobody else seems to do this */
+	pci_iounmap(pdev, endpoint->registers);
+failed_iomap0:
+	pci_release_regions(pdev);
+failed_request_regions:
+bad_bar:
+	pci_disable_device(pdev);
+no_enable:
+	xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+	kfree(endpoint);
+	return rc;
+}
+
+static void xilly_remove(struct pci_dev *pdev)
+{
+	struct xilly_endpoint *endpoint = pci_get_drvdata(pdev);
+
+	xillybus_endpoint_remove(endpoint);
+
+	free_irq(pdev->irq, endpoint);
+
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, endpoint->registers);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+
+	xillybus_do_cleanup(&endpoint->cleanup, endpoint);
+
+	kfree(endpoint);
+}
+
+MODULE_DEVICE_TABLE(pci, xillyids);
+
+static struct pci_driver xillybus_driver = {
+	.name = xillyname,
+	.id_table = xillyids,
+	.probe = xilly_probe,
+	.remove = xilly_remove,
+};
+
+module_pci_driver(xillybus_driver);
diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig
deleted file mode 100644
index 2d7b2da..0000000
--- a/drivers/staging/zcache/Kconfig
+++ /dev/null
@@ -1,59 +0,0 @@
-config ZCACHE
-	tristate "Dynamic compression of swap pages and clean pagecache pages"
-	depends on CRYPTO=y && SWAP=y && CLEANCACHE && FRONTSWAP
-	select CRYPTO_LZO
-	default n
-	help
-	  Zcache doubles RAM efficiency while providing a significant
-	  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.
-
-config ZCACHE_DEBUG
-	bool "Enable debug statistics"
-	depends on DEBUG_FS && ZCACHE
-	default n
-	help
-	  This is used to provide an debugfs directory with counters of
-	  how zcache is doing. You probably want to set this to 'N'.
-
-config RAMSTER
-	tristate "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
-	depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE
-	depends on NET
-	# must ensure struct page is 8-byte aligned
-	select HAVE_ALIGNED_STRUCT_PAGE if !64BIT
-	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
-	  zcache2, compresses swap pages into local RAM, but then remotifies
-	  the compressed pages to another node in the RAMster cluster.
-
-config RAMSTER_DEBUG
-        bool "Enable ramster debug statistics"
-        depends on DEBUG_FS && RAMSTER
-        default n
-        help
-          This is used to provide an debugfs directory with counters of
-          how ramster is doing. You probably want to set this to 'N'.
-
-# Depends on not-yet-upstreamed mm patches to export end_swap_bio_write and
-# __add_to_swap_cache, and implement __swap_writepage (which is swap_writepage
-# without the frontswap call. When these are in-tree, the dependency on
-# BROKEN can be removed
-config ZCACHE_WRITEBACK
-	bool "Allow compressed swap pages to be writtenback to swap disk"
-	depends on ZCACHE=y && BROKEN
-	default n
-	help
-	  Zcache caches compressed swap pages (and other data) in RAM which
-	  often improves performance by avoiding I/O's due to swapping.
-	  In some workloads with very long-lived large processes, it can
-	  instead reduce performance.  Writeback decompresses zcache-compressed
-	  pages (in LRU order) when under memory pressure and writes them to
-	  the backing swap disk to ameliorate this problem.  Policy driving
-	  writeback is still under development.
diff --git a/drivers/staging/zcache/Makefile b/drivers/staging/zcache/Makefile
deleted file mode 100644
index 845a5c2..0000000
--- a/drivers/staging/zcache/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-zcache-y	:=		zcache-main.o tmem.o zbud.o
-zcache-$(CONFIG_ZCACHE_DEBUG) += debug.o
-zcache-$(CONFIG_RAMSTER_DEBUG) += ramster/debug.o
-zcache-$(CONFIG_RAMSTER)	+=	ramster/ramster.o ramster/r2net.o
-zcache-$(CONFIG_RAMSTER)	+=	ramster/nodemanager.o ramster/tcp.o
-zcache-$(CONFIG_RAMSTER)	+=	ramster/heartbeat.o ramster/masklog.o
-
-obj-$(CONFIG_ZCACHE)	+=	zcache.o
diff --git a/drivers/staging/zcache/TODO b/drivers/staging/zcache/TODO
deleted file mode 100644
index d0c18fa..0000000
--- a/drivers/staging/zcache/TODO
+++ /dev/null
@@ -1,64 +0,0 @@
-
-** ZCACHE PLAN FOR PROMOTION FROM STAGING **
-
-Last updated: Feb 13, 2013
-
-PLAN STEPS
-
-1. merge zcache and ramster to eliminate horrible code duplication
-2. converge on a predictable, writeback-capable allocator
-3. use debugfs instead of sysfs (per akpm feedback in 2011)
-4. zcache side of cleancache/mm WasActive patch
-5. zcache side of frontswap exclusive gets
-6. zcache must be able to writeback to physical swap disk
-    (per Andrea Arcangeli feedback in 2011)
-7. implement adequate policy for writeback
-8. frontswap/cleancache work to allow zcache to be loaded
-    as a module
-9. get core mm developer to review
-10. incorporate feedback from review
-11. get review/acks from 1-2 additional mm developers
-12. incorporate any feedback from additional mm reviews
-13. propose location/file-naming in mm tree
-14. repeat 9-13 as necessary until akpm is happy and merges
-
-STATUS/OWNERSHIP
-
-1. DONE as part of "new" zcache; in staging/zcache for 3.9
-2. DONE as part of "new" zcache (cf zbud.[ch]); in staging/zcache for 3.9
-    (this was the core of the zcache1 vs zcache2 flail)
-3. DONE as part of "new" zcache; in staging/zcache for 3.9
-4. DONE (w/caveats) as part of "new" zcache; per cleancache performance
-    feedback see https://lkml.org/lkml/2011/8/17/351, in
-    staging/zcache for 3.9; dependent on proposed mm patch, see
-    https://lkml.org/lkml/2012/1/25/300 
-5. DONE as part of "new" zcache; performance tuning only,
-    in staging/zcache for 3.9; dependent on frontswap patch
-    merged in 3.7 (33c2a174)
-6. DONE (w/caveats), prototyped as part of "new" zcache, had
-    bad memory leak; reimplemented to use sjennings clever tricks
-    and proposed mm patches with new version in staging/zcache
-    for 3.9, see https://lkml.org/lkml/2013/2/6/437;
-7. PROTOTYPED as part of "new" zcache; in staging/zcache for 3.9;
-    needs more review (plan to discuss at LSF/MM 2013)
-9. IN PROGRESS; owned by Konrad Wilk; Mel Gorman provided
-   great feedback in August 2012 (unfortunately of "old"
-   zcache)
-11. NOT DONE; owned by Konrad Wilk and Bob Liu
-12. TBD (depends on quantity of feedback)
-13. PROPOSED; one suggestion proposed by Dan; needs more ideas/feedback
-14. TBD (depends on feedback)
-
-WHO NEEDS TO AGREE
-
-Not sure.  Seth Jennings is now pursuing a separate but semi-parallel
-track.  Akpm clearly has to approve for any mm merge to happen.  Minchan
-Kim has interest but may be happy if/when zram is merged into mm.  Konrad
-Wilk may be maintainer if akpm decides compression is maintainable
-separately from the rest of mm.  (More LSF/MM 2013 discussion.)
-
-ZCACHE FUTURE NEW FUNCTIONALITY
-
-A. Support zsmalloc as an alternative high-density allocator
-    (See https://lkml.org/lkml/2013/1/23/511)
-B. Possibly support three zbuds per pageframe when space allows
diff --git a/drivers/staging/zcache/debug.c b/drivers/staging/zcache/debug.c
deleted file mode 100644
index daa2691..0000000
--- a/drivers/staging/zcache/debug.c
+++ /dev/null
@@ -1,107 +0,0 @@
-#include <linux/atomic.h>
-#include "debug.h"
-
-#ifdef CONFIG_ZCACHE_DEBUG
-#include <linux/debugfs.h>
-
-ssize_t zcache_obj_count;
-ssize_t zcache_obj_count_max;
-ssize_t zcache_objnode_count;
-ssize_t zcache_objnode_count_max;
-u64 zcache_eph_zbytes;
-u64 zcache_eph_zbytes_max;
-u64 zcache_pers_zbytes_max;
-ssize_t zcache_eph_pageframes_max;
-ssize_t zcache_pers_pageframes_max;
-ssize_t zcache_pageframes_alloced;
-ssize_t zcache_pageframes_freed;
-ssize_t zcache_eph_zpages;
-ssize_t zcache_eph_zpages_max;
-ssize_t zcache_pers_zpages_max;
-ssize_t zcache_flush_total;
-ssize_t zcache_flush_found;
-ssize_t zcache_flobj_total;
-ssize_t zcache_flobj_found;
-ssize_t zcache_failed_eph_puts;
-ssize_t zcache_failed_pers_puts;
-ssize_t zcache_failed_getfreepages;
-ssize_t zcache_failed_alloc;
-ssize_t zcache_put_to_flush;
-ssize_t zcache_compress_poor;
-ssize_t zcache_mean_compress_poor;
-ssize_t zcache_eph_ate_tail;
-ssize_t zcache_eph_ate_tail_failed;
-ssize_t zcache_pers_ate_eph;
-ssize_t zcache_pers_ate_eph_failed;
-ssize_t zcache_evicted_eph_zpages;
-ssize_t zcache_evicted_eph_pageframes;
-ssize_t zcache_zero_filled_pages;
-ssize_t zcache_zero_filled_pages_max;
-
-#define ATTR(x)  { .name = #x, .val = &zcache_##x, }
-static struct debug_entry {
-	const char *name;
-	ssize_t *val;
-} attrs[] = {
-	ATTR(obj_count), ATTR(obj_count_max),
-	ATTR(objnode_count), ATTR(objnode_count_max),
-	ATTR(flush_total), ATTR(flush_found),
-	ATTR(flobj_total), ATTR(flobj_found),
-	ATTR(failed_eph_puts), ATTR(failed_pers_puts),
-	ATTR(failed_getfreepages), ATTR(failed_alloc),
-	ATTR(put_to_flush),
-	ATTR(compress_poor), ATTR(mean_compress_poor),
-	ATTR(eph_ate_tail), ATTR(eph_ate_tail_failed),
-	ATTR(pers_ate_eph), ATTR(pers_ate_eph_failed),
-	ATTR(evicted_eph_zpages), ATTR(evicted_eph_pageframes),
-	ATTR(eph_pageframes), ATTR(eph_pageframes_max),
-	ATTR(pers_pageframes), ATTR(pers_pageframes_max),
-	ATTR(eph_zpages), ATTR(eph_zpages_max),
-	ATTR(pers_zpages), ATTR(pers_zpages_max),
-	ATTR(last_active_file_pageframes),
-	ATTR(last_inactive_file_pageframes),
-	ATTR(last_active_anon_pageframes),
-	ATTR(last_inactive_anon_pageframes),
-	ATTR(eph_nonactive_puts_ignored),
-	ATTR(pers_nonactive_puts_ignored),
-	ATTR(zero_filled_pages),
-#ifdef CONFIG_ZCACHE_WRITEBACK
-	ATTR(outstanding_writeback_pages),
-	ATTR(writtenback_pages),
-#endif
-};
-#undef ATTR
-int zcache_debugfs_init(void)
-{
-	unsigned int i;
-	struct dentry *root = debugfs_create_dir("zcache", NULL);
-	if (root == NULL)
-		return -ENXIO;
-
-	for (i = 0; i < ARRAY_SIZE(attrs); i++)
-		if (!debugfs_create_size_t(attrs[i].name, S_IRUGO, root, attrs[i].val))
-			goto out;
-
-	debugfs_create_u64("eph_zbytes", S_IRUGO, root, &zcache_eph_zbytes);
-	debugfs_create_u64("eph_zbytes_max", S_IRUGO, root, &zcache_eph_zbytes_max);
-	debugfs_create_u64("pers_zbytes", S_IRUGO, root, &zcache_pers_zbytes);
-	debugfs_create_u64("pers_zbytes_max", S_IRUGO, root, &zcache_pers_zbytes_max);
-
-	return 0;
-out:
-	return -ENODEV;
-}
-
-/* developers can call this in case of ooms, e.g. to find memory leaks */
-void zcache_dump(void)
-{
-	unsigned int i;
-	for (i = 0; i < ARRAY_SIZE(attrs); i++)
-		pr_debug("zcache: %s=%zu\n", attrs[i].name, *attrs[i].val);
-
-	pr_debug("zcache: eph_zbytes=%llu\n", (unsigned long long)zcache_eph_zbytes);
-	pr_debug("zcache: eph_zbytes_max=%llu\n", (unsigned long long)zcache_eph_zbytes_max);
-	pr_debug("zcache: pers_zbytes=%llu\n", (unsigned long long)zcache_pers_zbytes);
-	pr_debug("zcache: pers_zbytes_max=%llu\n", (unsigned long long)zcache_pers_zbytes_max);
-}
-#endif
diff --git a/drivers/staging/zcache/debug.h b/drivers/staging/zcache/debug.h
deleted file mode 100644
index 8088d28..0000000
--- a/drivers/staging/zcache/debug.h
+++ /dev/null
@@ -1,305 +0,0 @@
-#include <linux/bug.h>
-
-#ifdef CONFIG_ZCACHE_DEBUG
-
-/* we try to keep these statistics SMP-consistent */
-extern ssize_t zcache_obj_count;
-static atomic_t zcache_obj_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_obj_count_max;
-static inline void inc_zcache_obj_count(void)
-{
-	zcache_obj_count = atomic_inc_return(&zcache_obj_atomic);
-	if (zcache_obj_count > zcache_obj_count_max)
-		zcache_obj_count_max = zcache_obj_count;
-}
-static inline void dec_zcache_obj_count(void)
-{
-	zcache_obj_count = atomic_dec_return(&zcache_obj_atomic);
-	BUG_ON(zcache_obj_count < 0);
-};
-extern ssize_t zcache_objnode_count;
-static atomic_t zcache_objnode_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_objnode_count_max;
-static inline void inc_zcache_objnode_count(void)
-{
-	zcache_objnode_count = atomic_inc_return(&zcache_objnode_atomic);
-	if (zcache_objnode_count > zcache_objnode_count_max)
-		zcache_objnode_count_max = zcache_objnode_count;
-};
-static inline void dec_zcache_objnode_count(void)
-{
-	zcache_objnode_count = atomic_dec_return(&zcache_objnode_atomic);
-	BUG_ON(zcache_objnode_count < 0);
-};
-extern u64 zcache_eph_zbytes;
-static atomic_long_t zcache_eph_zbytes_atomic = ATOMIC_INIT(0);
-extern u64 zcache_eph_zbytes_max;
-static inline void inc_zcache_eph_zbytes(unsigned clen)
-{
-	zcache_eph_zbytes = atomic_long_add_return(clen, &zcache_eph_zbytes_atomic);
-	if (zcache_eph_zbytes > zcache_eph_zbytes_max)
-		zcache_eph_zbytes_max = zcache_eph_zbytes;
-};
-static inline void dec_zcache_eph_zbytes(unsigned zsize)
-{
-	zcache_eph_zbytes = atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
-};
-extern  u64 zcache_pers_zbytes;
-static atomic_long_t zcache_pers_zbytes_atomic = ATOMIC_INIT(0);
-extern u64 zcache_pers_zbytes_max;
-static inline void inc_zcache_pers_zbytes(unsigned clen)
-{
-	zcache_pers_zbytes = atomic_long_add_return(clen, &zcache_pers_zbytes_atomic);
-	if (zcache_pers_zbytes > zcache_pers_zbytes_max)
-		zcache_pers_zbytes_max = zcache_pers_zbytes;
-}
-static inline void dec_zcache_pers_zbytes(unsigned zsize)
-{
-	zcache_pers_zbytes = atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
-}
-extern ssize_t zcache_eph_pageframes;
-static atomic_t zcache_eph_pageframes_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_eph_pageframes_max;
-static inline void inc_zcache_eph_pageframes(void)
-{
-	zcache_eph_pageframes = atomic_inc_return(&zcache_eph_pageframes_atomic);
-	if (zcache_eph_pageframes > zcache_eph_pageframes_max)
-		zcache_eph_pageframes_max = zcache_eph_pageframes;
-};
-static inline void dec_zcache_eph_pageframes(void)
-{
-	zcache_eph_pageframes = atomic_dec_return(&zcache_eph_pageframes_atomic);
-};
-extern ssize_t zcache_pers_pageframes;
-static atomic_t zcache_pers_pageframes_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_pers_pageframes_max;
-static inline void inc_zcache_pers_pageframes(void)
-{
-	zcache_pers_pageframes = atomic_inc_return(&zcache_pers_pageframes_atomic);
-	if (zcache_pers_pageframes > zcache_pers_pageframes_max)
-		zcache_pers_pageframes_max = zcache_pers_pageframes;
-}
-static inline void dec_zcache_pers_pageframes(void)
-{
-	zcache_pers_pageframes = atomic_dec_return(&zcache_pers_pageframes_atomic);
-}
-extern ssize_t zcache_pageframes_alloced;
-static atomic_t zcache_pageframes_alloced_atomic = ATOMIC_INIT(0);
-static inline void inc_zcache_pageframes_alloced(void)
-{
-	zcache_pageframes_alloced = atomic_inc_return(&zcache_pageframes_alloced_atomic);
-};
-extern ssize_t zcache_pageframes_freed;
-static atomic_t zcache_pageframes_freed_atomic = ATOMIC_INIT(0);
-static inline void inc_zcache_pageframes_freed(void)
-{
-	zcache_pageframes_freed = atomic_inc_return(&zcache_pageframes_freed_atomic);
-}
-extern ssize_t zcache_eph_zpages;
-static atomic_t zcache_eph_zpages_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_eph_zpages_max;
-static inline void inc_zcache_eph_zpages(void)
-{
-	zcache_eph_zpages = atomic_inc_return(&zcache_eph_zpages_atomic);
-	if (zcache_eph_zpages > zcache_eph_zpages_max)
-		zcache_eph_zpages_max = zcache_eph_zpages;
-}
-static inline void dec_zcache_eph_zpages(unsigned zpages)
-{
-	zcache_eph_zpages = atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
-}
-extern ssize_t zcache_pers_zpages;
-static atomic_t zcache_pers_zpages_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_pers_zpages_max;
-static inline void inc_zcache_pers_zpages(void)
-{
-	zcache_pers_zpages = atomic_inc_return(&zcache_pers_zpages_atomic);
-	if (zcache_pers_zpages > zcache_pers_zpages_max)
-		zcache_pers_zpages_max = zcache_pers_zpages;
-}
-static inline void dec_zcache_pers_zpages(unsigned zpages)
-{
-	zcache_pers_zpages = atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
-}
-
-extern ssize_t zcache_zero_filled_pages;
-static atomic_t zcache_zero_filled_pages_atomic = ATOMIC_INIT(0);
-extern ssize_t zcache_zero_filled_pages_max;
-static inline void inc_zcache_zero_filled_pages(void)
-{
-	zcache_zero_filled_pages = atomic_inc_return(
-					&zcache_zero_filled_pages_atomic);
-	if (zcache_zero_filled_pages > zcache_zero_filled_pages_max)
-		zcache_zero_filled_pages_max = zcache_zero_filled_pages;
-}
-static inline void dec_zcache_zero_filled_pages(void)
-{
-	zcache_zero_filled_pages = atomic_dec_return(
-					&zcache_zero_filled_pages_atomic);
-}
-static inline unsigned long curr_pageframes_count(void)
-{
-	return zcache_pageframes_alloced -
-		atomic_read(&zcache_pageframes_freed_atomic) -
-		atomic_read(&zcache_eph_pageframes_atomic) -
-		atomic_read(&zcache_pers_pageframes_atomic);
-};
-/* but for the rest of these, counting races are ok */
-extern ssize_t zcache_flush_total;
-extern ssize_t zcache_flush_found;
-extern ssize_t zcache_flobj_total;
-extern ssize_t zcache_flobj_found;
-extern ssize_t zcache_failed_eph_puts;
-extern ssize_t zcache_failed_pers_puts;
-extern ssize_t zcache_failed_getfreepages;
-extern ssize_t zcache_failed_alloc;
-extern ssize_t zcache_put_to_flush;
-extern ssize_t zcache_compress_poor;
-extern ssize_t zcache_mean_compress_poor;
-extern ssize_t zcache_eph_ate_tail;
-extern ssize_t zcache_eph_ate_tail_failed;
-extern ssize_t zcache_pers_ate_eph;
-extern ssize_t zcache_pers_ate_eph_failed;
-extern ssize_t zcache_evicted_eph_zpages;
-extern ssize_t zcache_evicted_eph_pageframes;
-
-extern ssize_t zcache_last_active_file_pageframes;
-extern ssize_t zcache_last_inactive_file_pageframes;
-extern ssize_t zcache_last_active_anon_pageframes;
-extern ssize_t zcache_last_inactive_anon_pageframes;
-static ssize_t zcache_eph_nonactive_puts_ignored;
-static ssize_t zcache_pers_nonactive_puts_ignored;
-#ifdef CONFIG_ZCACHE_WRITEBACK
-extern ssize_t zcache_writtenback_pages;
-extern ssize_t zcache_outstanding_writeback_pages;
-#endif
-
-static inline void inc_zcache_flush_total(void)
-{
-	zcache_flush_total++;
-};
-static inline void inc_zcache_flush_found(void)
-{
-	zcache_flush_found++;
-};
-static inline void inc_zcache_flobj_total(void)
-{
-	zcache_flobj_total++;
-};
-static inline void inc_zcache_flobj_found(void)
-{
-	zcache_flobj_found++;
-};
-static inline void inc_zcache_failed_eph_puts(void)
-{
-	zcache_failed_eph_puts++;
-};
-static inline void inc_zcache_failed_pers_puts(void)
-{
-	zcache_failed_pers_puts++;
-};
-static inline void inc_zcache_failed_getfreepages(void)
-{
-	zcache_failed_getfreepages++;
-};
-static inline void inc_zcache_failed_alloc(void)
-{
-	zcache_failed_alloc++;
-};
-static inline void inc_zcache_put_to_flush(void)
-{
-	zcache_put_to_flush++;
-};
-static inline void inc_zcache_compress_poor(void)
-{
-	zcache_compress_poor++;
-};
-static inline void inc_zcache_mean_compress_poor(void)
-{
-	zcache_mean_compress_poor++;
-};
-static inline void inc_zcache_eph_ate_tail(void)
-{
-	zcache_eph_ate_tail++;
-};
-static inline void inc_zcache_eph_ate_tail_failed(void)
-{
-	zcache_eph_ate_tail_failed++;
-};
-static inline void inc_zcache_pers_ate_eph(void)
-{
-	zcache_pers_ate_eph++;
-};
-static inline void inc_zcache_pers_ate_eph_failed(void)
-{
-	zcache_pers_ate_eph_failed++;
-};
-static inline void inc_zcache_evicted_eph_zpages(unsigned zpages)
-{
-	zcache_evicted_eph_zpages += zpages;
-};
-static inline void inc_zcache_evicted_eph_pageframes(void)
-{
-	zcache_evicted_eph_pageframes++;
-};
-
-static inline void inc_zcache_eph_nonactive_puts_ignored(void)
-{
-	zcache_eph_nonactive_puts_ignored++;
-};
-static inline void inc_zcache_pers_nonactive_puts_ignored(void)
-{
-	zcache_pers_nonactive_puts_ignored++;
-};
-
-int zcache_debugfs_init(void);
-#else
-static inline void inc_zcache_obj_count(void) { };
-static inline void dec_zcache_obj_count(void) { };
-static inline void inc_zcache_objnode_count(void) { };
-static inline void dec_zcache_objnode_count(void) { };
-static inline void inc_zcache_eph_zbytes(unsigned clen) { };
-static inline void dec_zcache_eph_zbytes(unsigned zsize) { };
-static inline void inc_zcache_pers_zbytes(unsigned clen) { };
-static inline void dec_zcache_pers_zbytes(unsigned zsize) { };
-static inline void inc_zcache_eph_pageframes(void) { };
-static inline void dec_zcache_eph_pageframes(void) { };
-static inline void inc_zcache_pers_pageframes(void) { };
-static inline void dec_zcache_pers_pageframes(void) { };
-static inline void inc_zcache_pageframes_alloced(void) { };
-static inline void inc_zcache_pageframes_freed(void) { };
-static inline void inc_zcache_eph_zpages(void) { };
-static inline void dec_zcache_eph_zpages(unsigned zpages) { };
-static inline void inc_zcache_pers_zpages(void) { };
-static inline void dec_zcache_pers_zpages(unsigned zpages) { };
-static inline void inc_zcache_zero_filled_pages(void) { };
-static inline void dec_zcache_zero_filled_pages(void) { };
-static inline unsigned long curr_pageframes_count(void)
-{
-	return 0;
-};
-static inline int zcache_debugfs_init(void)
-{
-	return 0;
-};
-static inline void inc_zcache_flush_total(void) { };
-static inline void inc_zcache_flush_found(void) { };
-static inline void inc_zcache_flobj_total(void) { };
-static inline void inc_zcache_flobj_found(void) { };
-static inline void inc_zcache_failed_eph_puts(void) { };
-static inline void inc_zcache_failed_pers_puts(void) { };
-static inline void inc_zcache_failed_getfreepages(void) { };
-static inline void inc_zcache_failed_alloc(void) { };
-static inline void inc_zcache_put_to_flush(void) { };
-static inline void inc_zcache_compress_poor(void) { };
-static inline void inc_zcache_mean_compress_poor(void) { };
-static inline void inc_zcache_eph_ate_tail(void) { };
-static inline void inc_zcache_eph_ate_tail_failed(void) { };
-static inline void inc_zcache_pers_ate_eph(void) { };
-static inline void inc_zcache_pers_ate_eph_failed(void) { };
-static inline void inc_zcache_evicted_eph_zpages(unsigned zpages) { };
-static inline void inc_zcache_evicted_eph_pageframes(void) { };
-
-static inline void inc_zcache_eph_nonactive_puts_ignored(void) { };
-static inline void inc_zcache_pers_nonactive_puts_ignored(void) { };
-#endif
diff --git a/drivers/staging/zcache/ramster.h b/drivers/staging/zcache/ramster.h
deleted file mode 100644
index a858666..0000000
--- a/drivers/staging/zcache/ramster.h
+++ /dev/null
@@ -1,59 +0,0 @@
-
-/*
- * zcache/ramster.h
- *
- * Placeholder to resolve ramster references when !CONFIG_RAMSTER
- * Real ramster.h lives in ramster subdirectory.
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _ZCACHE_RAMSTER_H_
-#define _ZCACHE_RAMSTER_H_
-
-#ifdef CONFIG_RAMSTER
-#include "ramster/ramster.h"
-#else
-static inline void ramster_init(bool x, bool y, bool z, bool w)
-{
-}
-
-static inline void ramster_register_pamops(struct tmem_pamops *p)
-{
-}
-
-static inline int ramster_remotify_pageframe(bool b)
-{
-	return 0;
-}
-
-static inline void *ramster_pampd_free(void *v, struct tmem_pool *p,
-			struct tmem_oid *o, uint32_t u, bool b)
-{
-	return NULL;
-}
-
-static inline int ramster_do_preload_flnode(struct tmem_pool *p)
-{
-	return -1;
-}
-
-static inline bool pampd_is_remote(void *v)
-{
-	return false;
-}
-
-static inline void ramster_count_foreign_pages(bool b, int i)
-{
-}
-
-static inline void ramster_cpu_up(int cpu)
-{
-}
-
-static inline void ramster_cpu_down(int cpu)
-{
-}
-#endif
-
-#endif /* _ZCACHE_RAMSTER_H */
diff --git a/drivers/staging/zcache/ramster/debug.c b/drivers/staging/zcache/ramster/debug.c
deleted file mode 100644
index 5b26ee9..0000000
--- a/drivers/staging/zcache/ramster/debug.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <linux/atomic.h>
-#include "debug.h"
-
-ssize_t ramster_foreign_eph_pages;
-ssize_t ramster_foreign_pers_pages;
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-
-ssize_t ramster_eph_pages_remoted;
-ssize_t ramster_pers_pages_remoted;
-ssize_t ramster_eph_pages_remote_failed;
-ssize_t ramster_pers_pages_remote_failed;
-ssize_t ramster_remote_eph_pages_succ_get;
-ssize_t ramster_remote_pers_pages_succ_get;
-ssize_t ramster_remote_eph_pages_unsucc_get;
-ssize_t ramster_remote_pers_pages_unsucc_get;
-ssize_t ramster_pers_pages_remote_nomem;
-ssize_t ramster_remote_objects_flushed;
-ssize_t ramster_remote_object_flushes_failed;
-ssize_t ramster_remote_pages_flushed;
-ssize_t ramster_remote_page_flushes_failed;
-
-#define ATTR(x)  { .name = #x, .val = &ramster_##x, }
-static struct debug_entry {
-	const char *name;
-	ssize_t *val;
-} attrs[] = {
-	ATTR(eph_pages_remoted),
-	ATTR(pers_pages_remoted),
-	ATTR(eph_pages_remote_failed),
-	ATTR(pers_pages_remote_failed),
-	ATTR(remote_eph_pages_succ_get),
-	ATTR(remote_pers_pages_succ_get),
-	ATTR(remote_eph_pages_unsucc_get),
-	ATTR(remote_pers_pages_unsucc_get),
-	ATTR(pers_pages_remote_nomem),
-	ATTR(remote_objects_flushed),
-	ATTR(remote_pages_flushed),
-	ATTR(remote_object_flushes_failed),
-	ATTR(remote_page_flushes_failed),
-	ATTR(foreign_eph_pages),
-	ATTR(foreign_eph_pages_max),
-	ATTR(foreign_pers_pages),
-	ATTR(foreign_pers_pages_max),
-};
-#undef ATTR
-
-int ramster_debugfs_init(void)
-{
-	int i;
-	struct dentry *root = debugfs_create_dir("ramster", NULL);
-	if (root == NULL)
-		return -ENXIO;
-
-	for (i = 0; i < ARRAY_SIZE(attrs); i++)
-		if (!debugfs_create_size_t(attrs[i].name,
-				S_IRUGO, root, attrs[i].val))
-			goto out;
-	return 0;
-out:
-	return -ENODEV;
-}
-#else
-static inline int ramster_debugfs_init(void)
-{
-	return 0;
-}
-#endif
diff --git a/drivers/staging/zcache/ramster/debug.h b/drivers/staging/zcache/ramster/debug.h
deleted file mode 100644
index 5ffab50..0000000
--- a/drivers/staging/zcache/ramster/debug.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#include <linux/bug.h>
-
-#ifdef CONFIG_RAMSTER_DEBUG
-
-extern long ramster_flnodes;
-static atomic_t ramster_flnodes_atomic = ATOMIC_INIT(0);
-static unsigned long ramster_flnodes_max;
-static inline void inc_ramster_flnodes(void)
-{
-	ramster_flnodes = atomic_inc_return(&ramster_flnodes_atomic);
-	if (ramster_flnodes > ramster_flnodes_max)
-		ramster_flnodes_max = ramster_flnodes;
-}
-static inline void dec_ramster_flnodes(void)
-{
-	ramster_flnodes = atomic_dec_return(&ramster_flnodes_atomic);
-}
-extern ssize_t ramster_foreign_eph_pages;
-static atomic_t ramster_foreign_eph_pages_atomic = ATOMIC_INIT(0);
-static ssize_t ramster_foreign_eph_pages_max;
-static inline void inc_ramster_foreign_eph_pages(void)
-{
-	ramster_foreign_eph_pages = atomic_inc_return(
-		&ramster_foreign_eph_pages_atomic);
-	if (ramster_foreign_eph_pages > ramster_foreign_eph_pages_max)
-		ramster_foreign_eph_pages_max = ramster_foreign_eph_pages;
-}
-static inline void dec_ramster_foreign_eph_pages(void)
-{
-	ramster_foreign_eph_pages = atomic_dec_return(
-		&ramster_foreign_eph_pages_atomic);
-}
-extern ssize_t ramster_foreign_pers_pages;
-static atomic_t ramster_foreign_pers_pages_atomic = ATOMIC_INIT(0);
-static ssize_t ramster_foreign_pers_pages_max;
-static inline void inc_ramster_foreign_pers_pages(void)
-{
-	ramster_foreign_pers_pages = atomic_inc_return(
-		&ramster_foreign_pers_pages_atomic);
-	if (ramster_foreign_pers_pages > ramster_foreign_pers_pages_max)
-		ramster_foreign_pers_pages_max = ramster_foreign_pers_pages;
-}
-static inline void dec_ramster_foreign_pers_pages(void)
-{
-	ramster_foreign_pers_pages = atomic_dec_return(
-		&ramster_foreign_pers_pages_atomic);
-}
-
-extern ssize_t ramster_eph_pages_remoted;
-extern ssize_t ramster_pers_pages_remoted;
-extern ssize_t ramster_eph_pages_remote_failed;
-extern ssize_t ramster_pers_pages_remote_failed;
-extern ssize_t ramster_remote_eph_pages_succ_get;
-extern ssize_t ramster_remote_pers_pages_succ_get;
-extern ssize_t ramster_remote_eph_pages_unsucc_get;
-extern ssize_t ramster_remote_pers_pages_unsucc_get;
-extern ssize_t ramster_pers_pages_remote_nomem;
-extern ssize_t ramster_remote_objects_flushed;
-extern ssize_t ramster_remote_object_flushes_failed;
-extern ssize_t ramster_remote_pages_flushed;
-extern ssize_t ramster_remote_page_flushes_failed;
-
-int ramster_debugfs_init(void);
-
-static inline void inc_ramster_eph_pages_remoted(void)
-{
-	ramster_eph_pages_remoted++;
-};
-static inline void inc_ramster_pers_pages_remoted(void)
-{
-	ramster_pers_pages_remoted++;
-};
-static inline void inc_ramster_eph_pages_remote_failed(void)
-{
-	ramster_eph_pages_remote_failed++;
-};
-static inline void inc_ramster_pers_pages_remote_failed(void)
-{
-	ramster_pers_pages_remote_failed++;
-};
-static inline void inc_ramster_remote_eph_pages_succ_get(void)
-{
-	ramster_remote_eph_pages_succ_get++;
-};
-static inline void inc_ramster_remote_pers_pages_succ_get(void)
-{
-	ramster_remote_pers_pages_succ_get++;
-};
-static inline void inc_ramster_remote_eph_pages_unsucc_get(void)
-{
-	ramster_remote_eph_pages_unsucc_get++;
-};
-static inline void inc_ramster_remote_pers_pages_unsucc_get(void)
-{
-	ramster_remote_pers_pages_unsucc_get++;
-};
-static inline void inc_ramster_pers_pages_remote_nomem(void)
-{
-	ramster_pers_pages_remote_nomem++;
-};
-static inline void inc_ramster_remote_objects_flushed(void)
-{
-	ramster_remote_objects_flushed++;
-};
-static inline void inc_ramster_remote_object_flushes_failed(void)
-{
-	ramster_remote_object_flushes_failed++;
-};
-static inline void inc_ramster_remote_pages_flushed(void)
-{
-	ramster_remote_pages_flushed++;
-};
-static inline void inc_ramster_remote_page_flushes_failed(void)
-{
-	ramster_remote_page_flushes_failed++;
-};
-
-#else
-
-static inline void inc_ramster_flnodes(void) { };
-static inline void dec_ramster_flnodes(void) { };
-static inline void inc_ramster_foreign_eph_pages(void) { };
-static inline void dec_ramster_foreign_eph_pages(void) { };
-static inline void inc_ramster_foreign_pers_pages(void) { };
-static inline void dec_ramster_foreign_pers_pages(void) { };
-
-static inline void inc_ramster_eph_pages_remoted(void) { };
-static inline void inc_ramster_pers_pages_remoted(void) { };
-static inline void inc_ramster_eph_pages_remote_failed(void) { };
-static inline void inc_ramster_pers_pages_remote_failed(void) { };
-static inline void inc_ramster_remote_eph_pages_succ_get(void) { };
-static inline void inc_ramster_remote_pers_pages_succ_get(void) { };
-static inline void inc_ramster_remote_eph_pages_unsucc_get(void) { };
-static inline void inc_ramster_remote_pers_pages_unsucc_get(void) { };
-static inline void inc_ramster_pers_pages_remote_nomem(void) { };
-static inline void inc_ramster_remote_objects_flushed(void) { };
-static inline void inc_ramster_remote_object_flushes_failed(void) { };
-static inline void inc_ramster_remote_pages_flushed(void) { };
-static inline void inc_ramster_remote_page_flushes_failed(void) { };
-
-static inline int ramster_debugfs_init(void)
-{
-	return 0;
-}
-#endif
diff --git a/drivers/staging/zcache/ramster/heartbeat.c b/drivers/staging/zcache/ramster/heartbeat.c
deleted file mode 100644
index 75d3fe8..0000000
--- a/drivers/staging/zcache/ramster/heartbeat.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/* -*- 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()) {
-		pr_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)
-			pr_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/zcache/ramster/heartbeat.h b/drivers/staging/zcache/ramster/heartbeat.h
deleted file mode 100644
index 6cbc775..0000000
--- a/drivers/staging/zcache/ramster/heartbeat.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- 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/zcache/ramster/masklog.c b/drivers/staging/zcache/ramster/masklog.c
deleted file mode 100644
index 1261d85..0000000
--- a/drivers/staging/zcache/ramster/masklog.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/* -*- 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/zcache/ramster/masklog.h b/drivers/staging/zcache/ramster/masklog.h
deleted file mode 100644
index 918ae11..0000000
--- a/drivers/staging/zcache/ramster/masklog.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/* -*- 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/zcache/ramster/nodemanager.c b/drivers/staging/zcache/ramster/nodemanager.c
deleted file mode 100644
index 2cfe933..0000000
--- a/drivers/staging/zcache/ramster/nodemanager.c
+++ /dev/null
@@ -1,996 +0,0 @@
-/* -*- 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) {
-			pr_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();
-}
-
-int r2nm_init(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) {
-		pr_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;
-}
-EXPORT_SYMBOL_GPL(r2nm_init);
-
-MODULE_AUTHOR("Oracle");
-MODULE_LICENSE("GPL");
-
-#ifndef CONFIG_RAMSTER_MODULE
-late_initcall(r2nm_init);
-#endif
diff --git a/drivers/staging/zcache/ramster/nodemanager.h b/drivers/staging/zcache/ramster/nodemanager.h
deleted file mode 100644
index 41a04df..0000000
--- a/drivers/staging/zcache/ramster/nodemanager.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- 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/zcache/ramster/r2net.c b/drivers/staging/zcache/ramster/r2net.c
deleted file mode 100644
index 34818dc..0000000
--- a/drivers/staging/zcache/ramster/r2net.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * r2net.c
- *
- * Copyright (c) 2011-2012, Dan Magenheimer, Oracle Corp.
- *
- * Ramster_r2net provides an interface between zcache and r2net.
- *
- * FIXME: support more than two nodes
- */
-
-#include <linux/list.h>
-#include "tcp.h"
-#include "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 "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_page(xh.client_id, xh.pool_id, &xh.oid, xh.index,
-				pdata, &size, true, 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 = ramster_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_page(xh->client_id, xh->pool_id, &xh->oid, xh->index,
-				p, datalen, true, ephemeral);
-	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_page(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 r2net_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode,
-				size_t expect_size, uint8_t expect_cksum,
-				void *extra)
-{
-	int nodenum, ret = -1, status;
-	struct r2nm_node *node = NULL;
-	struct kvec vec[1];
-	size_t veclen = 1;
-	u32 msg_type;
-	struct r2net_node *nn;
-
-	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;
-
-	node = r2net_target_node;
-	if (!node)
-		goto out;
-
-	nodenum = r2net_target_nodenum;
-
-	r2nm_node_get(node);
-	nn = r2net_nn_from_num(nodenum);
-	if (nn->nn_persistent_error || !nn->nn_sc_valid) {
-		ret = -ENOTCONN;
-		r2nm_node_put(node);
-		goto out;
-	}
-
-	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) {
-		if (ret == -ENOTCONN || ret == -EHOSTDOWN)
-			goto out;
-		if (ret == -EAGAIN)
-			goto out;
-		/* FIXME handle bad message possibilities here? */
-		pr_err("UNTESTED ret<0 in ramster_remote_async_get: ret=%d\n",
-				ret);
-	}
-	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 r2net_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;
-	struct r2net_node *nn;
-
-	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);
-
-	nn = r2net_nn_from_num(nodenum);
-	if (nn->nn_persistent_error || !nn->nn_sc_valid) {
-		ret = -ENOTCONN;
-		r2nm_node_put(node);
-		goto out;
-	}
-
-	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);
-	if (ret < 0)
-		ret = -1;
-	else {
-		ret = status;
-		*remotenode = nodenum;
-	}
-
-	r2nm_node_put(node);
-out:
-	return ret;
-}
-
-int r2net_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 r2net_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/zcache/ramster/ramster-howto.txt b/drivers/staging/zcache/ramster/ramster-howto.txt
deleted file mode 100644
index 7b1ee3b..0000000
--- a/drivers/staging/zcache/ramster/ramster-howto.txt
+++ /dev/null
@@ -1,366 +0,0 @@
-			RAMSTER HOW-TO
-
-Author: Dan Magenheimer
-Ramster maintainer: Konrad Wilk <konrad.wilk@oracle.com>
-
-This is a HOWTO document for ramster which, as of this writing, is in
-the kernel as a subdirectory of zcache in drivers/staging, called ramster.
-(Zcache can be built with or without ramster functionality.)  If enabled
-and properly configured, ramster allows memory capacity load balancing
-across multiple machines in a cluster.  Further, the ramster code serves
-as an example of asynchronous access for zcache (as well as cleancache and
-frontswap) that may prove useful for future transcendent memory
-implementations, such as KVM and NVRAM.  While ramster works today on
-any network connection that supports kernel sockets, its features may
-become more interesting on future high-speed fabrics/interconnects.
-
-Ramster requires both kernel and userland support.  The userland support,
-called ramster-tools, is known to work with EL6-based distros, but is a
-set of poorly-hacked slightly-modified cluster tools based on ocfs2, which
-includes an init file, a config file, and a userland binary that interfaces
-to the kernel.  This state of userland support reflects the abysmal userland
-skills of this suitably-embarrassed author; any help/patches to turn
-ramster-tools into more distributable rpms/debs useful for a wider range
-of distros would be appreciated.  The source RPM that can be used as a
-starting point is available at:
-    http://oss.oracle.com/projects/tmem/files/RAMster/ 
-
-As a result of this author's ignorance, userland setup described in this
-HOWTO assumes an EL6 distro and is described in EL6 syntax.  Apologies
-if this offends anyone!
-
-Kernel support has only been tested on x86_64.  Systems with an active
-ocfs2 filesystem should work, but since ramster leverages a lot of
-code from ocfs2, there may be latent issues.  A kernel configuration that
-includes CONFIG_OCFS2_FS should build OK, and should certainly run OK
-if no ocfs2 filesystem is mounted.
-
-This HOWTO demonstrates memory capacity load balancing for a two-node
-cluster, where one node called the "local" node becomes overcommitted
-and the other node called the "remote" node provides additional RAM
-capacity for use by the local node.  Ramster is capable of more complex
-topologies; see the last section titled "ADVANCED RAMSTER TOPOLOGIES".
-
-If you find any terms in this HOWTO unfamiliar or don't understand the
-motivation for ramster, the following LWN reading is recommended:
--- Transcendent Memory in a Nutshell (lwn.net/Articles/454795)
--- The future calculus of memory management (lwn.net/Articles/475681)
-And since ramster is built on top of zcache, this article may be helpful:
--- In-kernel memory compression (lwn.net/Articles/545244)
-
-Now that you've memorized the contents of those articles, let's get started!
-
-A. PRELIMINARY
-
-1) Install two x86_64 Linux systems that are known to work when
-   upgraded to a recent upstream Linux kernel version.
-
-On each system:
-
-2) Configure, build and install, then boot Linux, just to ensure it
-   can be done with an unmodified upstream kernel.  Confirm you booted
-   the upstream kernel with "uname -a".
-
-3) If you plan to do any performance testing or unless you plan to
-   test only swapping, the "WasActive" patch is also highly recommended.
-   (Search lkml.org for WasActive, apply the patch, rebuild your kernel.)
-   For a demo or simple testing, the patch can be ignored.
-
-4) Install ramster-tools as root.  An x86_64 rpm for EL6-based systems
-   can be found at:
-    http://oss.oracle.com/projects/tmem/files/RAMster/ 
-   (Sorry but for now, non-EL6 users must recreate ramster-tools on
-   their own from source.  See above.)
-
-5) Ensure that debugfs is mounted at each boot.  Examples below assume it
-   is mounted at /sys/kernel/debug.
-
-B. BUILDING RAMSTER INTO THE KERNEL
-
-Do the following on each system:
-
-1) Using the kernel configuration mechanism of your choice, change
-   your config to include:
-
-	CONFIG_CLEANCACHE=y
-	CONFIG_FRONTSWAP=y
-	CONFIG_STAGING=y
-	CONFIG_CONFIGFS_FS=y # NOTE: MUST BE y, not m
-	CONFIG_ZCACHE=y
-	CONFIG_RAMSTER=y
-
-   For a linux-3.10 or later kernel, you should also set:
-
-	CONFIG_ZCACHE_DEBUG=y
-	CONFIG_RAMSTER_DEBUG=y
-
-   Before building the kernel please doublecheck your kernel config
-   file to ensure all of the settings are correct.
-
-2) Build this kernel and change your boot file (e.g. /etc/grub.conf)
-   so that the new kernel will boot.
-
-3) Add "zcache" and "ramster" as kernel boot parameters for the new kernel.
-
-4) Reboot each system approximately simultaneously.
-
-5) Check dmesg to ensure there are some messages from ramster, prefixed
-   by "ramster:"
-
-	# dmesg | grep ramster
-
-   You should also see a lot of files in:
-
-	# ls /sys/kernel/debug/zcache
-	# ls /sys/kernel/debug/ramster
-
-   These are mostly counters for various zcache and ramster activities.
-   You should also see files in:
-
-	# ls /sys/kernel/mm/ramster
-
-   These are sysfs files that control ramster as we shall see.
-
-   Ramster now will act as a single-system zcache on each system
-   but doesn't yet know anything about the cluster so can't yet do
-   anything remotely.
-
-C. CONFIGURING THE RAMSTER CLUSTER
-
-This part can be error prone unless you are familiar with clustering
-filesystems.  We need to describe the cluster in a /etc/ramster.conf
-file and the init scripts that parse it are extremely picky about
-the syntax.
-
-1) Create a /etc/ramster.conf file and ensure it is identical on both
-   systems.  This file mimics the ocfs2 format and there is a good amount
-   of documentation that can be searched for ocfs2.conf, but you can use:
-
-	cluster:
-		name = ramster
-		node_count = 2
-	node:
-		name = system1
-		cluster = ramster
-		number = 0
-		ip_address = my.ip.ad.r1
-		ip_port = 7777
-	node:
-		name = system2
-		cluster = ramster
-		number = 1
-		ip_address = my.ip.ad.r2
-		ip_port = 7777
-
-   You must ensure that the "name" field in the file exactly matches
-   the output of "hostname" on each system; if "hostname" shows a
-   fully-qualified hostname, ensure the name is fully qualified in
-   /etc/ramster.conf.  Obviously, substitute my.ip.ad.rx with proper
-   ip addresses.
-
-2) Enable the ramster service and configure it.  If you used the
-   EL6 ramster-tools, this would be:
-
-	# chkconfig --add ramster
-	# service ramster configure
-
-   Set "load on boot" to "y", cluster to start is "ramster" (or whatever
-   name you chose in ramster.conf), heartbeat dead threshold as "500",
-   network idle timeout as "1000000".  Leave the others as default.
-
-3) Reboot both systems.  After reboot, try (assuming EL6 ramster-tools):
-
-	# service ramster status
-
-   You should see "Checking RAMSTER cluster "ramster": Online".  If you do
-   not, something is wrong and ramster will not work.  Note that you
-   should also see that the driver for "configfs" is loaded and mounted,
-   the driver for ocfs2_dlmfs is not loaded, and some numbers for network
-   parameters.  You will also see "Checking RAMSTER heartbeat: Not active".
-   That's all OK.
-
-4) Now you need to start the cluster heartbeat; the cluster is not "up"
-   until all nodes detect a heartbeat.  In a real cluster, heartbeat detection
-   is done via a cluster filesystem, but ramster doesn't require one.  Some
-   hack-y kernel code in ramster can start the heartbeat for you though if
-   you tell it what nodes are "up".  To enable the heartbeat, do:
-
-	# echo 0 > /sys/kernel/mm/ramster/manual_node_up
-	# echo 1 > /sys/kernel/mm/ramster/manual_node_up
-
-   This must be done on BOTH nodes and, to avoid timeouts, must be done
-   approximately concurrently on both nodes.  On an EL6 system, it is
-   convenient to put these lines in /etc/rc.local.  To confirm that the
-   cluster is now up, on both systems do:
-
-	# dmesg | grep ramster
-
-   You should see ramster "Accepted connection" messages in dmesg on both
-   nodes after this.  Note that if you check userland status again with
-
-	# service ramster status
-
-   you will still see "Checking RAMSTER heartbeat: Not active".  That's
-   still OK... the ramster kernel heartbeat hack doesn't communicate to
-   userland.
-
-5) You now must tell each node the node to which it should "remotify" pages.
-   On this two node cluster, we will assume the "local" node, node 0, has
-   memory overcommitted and will use ramster to utilize RAM capacity on
-   the "remote node", node 1.  To configure this, on node 0, you do:
-
-	# echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-   You should see "ramster: node 1 set as remotification target" in dmesg
-   on node 0.  Again, on EL6, /etc/rc.local is a good place to put this
-   on node 0 so you don't forget to do it at each boot.
-
-6) One more step:  By default, the ramster code does not "remotify" any
-   pages; this is primarily for testing purposes, but sometimes it is
-   useful.  This may change in the future, but for now, on node 0, you do:
-
-	# echo 1 > /sys/kernel/mm/ramster/pers_remotify_enable
-	# echo 1 > /sys/kernel/mm/ramster/eph_remotify_enable
-
-   The first enables remotifying swap (persistent, aka frontswap) pages,
-   the second enables remotifying of page cache (ephemeral, cleancache)
-   pages.
-
-   On EL6, these lines can also be put in /etc/rc.local (AFTER the
-   node_up lines), or at the beginning of a script that runs a workload.
-
-7) Note that most testing has been done with both/all machines booted
-   roughly simultaneously to avoid cluster timeouts.  Ideally, you should
-   do this too unless you are trying to break ramster rather than just
-   use it. ;-)
-
-D. TESTING RAMSTER
-
-1) Note that ramster has no value unless pages get "remotified".  For
-   swap/frontswap/persistent pages, this doesn't happen unless/until
-   the workload would cause swapping to occur, at which point pages
-   are put into frontswap/zcache, and the remotification thread starts
-   working.  To get to the point where the system swaps, you either
-   need a workload for which the working set exceeds the RAM in the
-   system; or you need to somehow reduce the amount of RAM one of
-   the system sees.  This latter is easy when testing in a VM, but
-   harder on physical systems.  In some cases, "mem=xxxM" on the
-   kernel command line restricts memory, but for some values of xxx
-   the kernel may fail to boot.  One may also try creating a fixed
-   RAMdisk, doing nothing with it, but ensuring that it eats up a fixed
-   amount of RAM.
-
-2) To see if ramster is working, on the "remote node", node 1, try:
-
-	# grep . /sys/kernel/debug/ramster/foreign_*
-        # # note, that is space-dot-space between grep and the pathname
-
-   to monitor the number (and max) ephemeral and persistent pages
-   that ramster has sent.  If these stay at zero, ramster is not working
-   either because the workload on the local node (node 0) isn't creating
-   enough memory pressure or because "remotifying" isn't working.  On the
-   local system, node 0, you can watch lots of useful information also.
-   Try:
-
-	grep . /sys/kernel/debug/zcache/*pageframes* \
-		/sys/kernel/debug/zcache/*zbytes* \
-		/sys/kernel/debug/zcache/*zpages* \
-		/sys/kernel/debug/ramster/*remote*
-
-   Of particular note are the remote_*_pages_succ_get counters.  These
-   show how many disk reads and/or disk writes have been avoided on the
-   overcommitted local system by storing pages remotely using ramster.
-
-   At the risk of information overload, you can also grep:
-
-        /sys/kernel/debug/cleancache/* and /sys/kernel/debug/frontswap/*
-
-   These show, for example, how many disk reads and/or disk writes have
-   been avoided by using zcache to optimize RAM on the local system.
-
-
-AUTOMATIC SWAP REPATRIATION
-
-You may notice that while the systems are idle, the foreign persistent
-page count on the remote machine slowly decreases.  This is because
-ramster implements "frontswap selfshrinking":  When possible, swap
-pages that have been remotified are slowly repatriated to the local
-machine.  This is so that local RAM can be used when possible and
-so that, in case of remote machine crash, the probability of loss
-of data is reduced.
-
-REBOOTING / POWEROFF
-
-If a system is shut down while some of its swap pages still reside
-on a remote system, the system may lock up during the shutdown
-sequence.  This will occur if the network is shut down before the
-swap mechansim is shut down, which is the default ordering on many
-distros.  To avoid this annoying problem, simply shut off the swap
-subsystem before starting the shutdown sequence, e.g.:
-
-	# swapoff -a
-	# reboot
-
-Ideally, this swapoff-before-ifdown ordering should be enforced permanently
-using shutdown scripts.
-
-KNOWN PROBLEMS
-
-1) You may periodically see messages such as:
-
-    ramster_r2net, message length problem
-
-   This is harmless but indicates that a node is sending messages
-   containing compressed pages that exceed the maximum for zcache
-   (PAGE_SIZE*15/16).  The sender side needs to be fixed.
-
-2) If you see a "No longer connected to node..." message or a "No connection
-   established with node X after N seconds", it is possible you may
-   be in an unrecoverable state.  If you are certain all of the
-   appropriate cluster configuration steps described above have been
-   performed, try rebooting the two servers concurrently to see if
-   the cluster starts.
-
-   Note that "Connection to node... shutdown, state 7" is an intermediate
-   connection state.  As long as you later see "Accepted connection", the
-   intermediate states are harmless.
-
-3) There are known issues in counting certain values.  As a result
-   you may see periodic warnings from the kernel.  Almost always you
-   will see "ramster: bad accounting for XXX".  There are also "WARN_ONCE"
-   messages.  If you see kernel warnings with a tombstone, please report
-   them.  They are harmless but reflect bugs that need to be eventually fixed.
-
-ADVANCED RAMSTER TOPOLOGIES
-
-The kernel code for ramster can support up to eight nodes in a cluster,
-but no testing has been done with more than three nodes.
-
-In the example described above, the "remote" node serves as a RAM
-overflow for the "local" node.  This can be made symmetric by appropriate
-settings of the sysfs remote_target_nodenum file.  For example, by setting:
-
-	# echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 0, and
-
-	# echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 1, each node can serve as a RAM overflow for the other.
-
-For more than two nodes, a "RAM server" can be configured.  For a
-three node system, set:
-
-	# echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 1, and
-
-	# echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
-
-on node 2.  Then node 0 is a RAM server for node 1 and node 2.
-
-In this implementation of ramster, any remote node is potentially a single
-point of failure (SPOF).  Though the probability of failure is reduced
-by automatic swap repatriation (see above), a proposed future enhancement
-to ramster improves high-availability for the cluster by sending a copy
-of each page of date to two other nodes.  Patches welcome!
diff --git a/drivers/staging/zcache/ramster/ramster.c b/drivers/staging/zcache/ramster/ramster.c
deleted file mode 100644
index a937ce1..0000000
--- a/drivers/staging/zcache/ramster/ramster.c
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- * ramster.c
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- *
- * RAMster implements peer-to-peer transcendent memory, allowing a "cluster" of
- * kernels to dynamically pool their RAM so that a RAM-hungry workload on one
- * machine can temporarily and transparently utilize RAM on another machine
- * which is presumably idle or running a non-RAM-hungry workload.
- *
- * RAMster combines a clustering and messaging foundation based on the ocfs2
- * cluster layer with the in-kernel compression implementation of zcache, and
- * adds code to glue them together.  When a page is "put" to RAMster, it is
- * compressed and stored locally.  Periodically, a thread will "remotify" these
- * pages by sending them via messages to a remote machine.  When the page is
- * later needed as indicated by a page fault, a "get" is issued.  If the data
- * is local, it is uncompressed and the fault is resolved.  If the data is
- * remote, a message is sent to fetch the data and the faulting thread sleeps;
- * when the data arrives, the thread awakens, the data is decompressed and
- * the fault is resolved.
-
- * As of V5, clusters up to eight nodes are supported; each node can remotify
- * pages to one specified node, so clusters can be configured as clients to
- * a "memory server".  Some simple policy is in place that will need to be
- * refined over time.  Larger clusters and fault-resistant protocols can also
- * be added over time.
- */
-
-#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/frontswap.h>
-#include "../tmem.h"
-#include "../zcache.h"
-#include "../zbud.h"
-#include "ramster.h"
-#include "ramster_nodemanager.h"
-#include "tcp.h"
-#include "debug.h"
-
-#define RAMSTER_TESTING
-
-#ifndef CONFIG_SYSFS
-#error "ramster needs sysfs to define cluster nodes to use"
-#endif
-
-static bool use_cleancache __read_mostly;
-static bool use_frontswap __read_mostly;
-static bool use_frontswap_exclusive_gets __read_mostly;
-
-/* These must be sysfs not debugfs as they are checked/used by userland!! */
-static unsigned long ramster_interface_revision __read_mostly =
-	R2NM_API_VERSION; /* interface revision must match userspace! */
-static unsigned long ramster_pers_remotify_enable __read_mostly;
-static unsigned long ramster_eph_remotify_enable __read_mostly;
-static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0);
-#define MANUAL_NODES 8
-static bool ramster_nodes_manual_up[MANUAL_NODES] __read_mostly;
-static int ramster_remote_target_nodenum __read_mostly = -1;
-
-/* Used by this code. */
-long ramster_flnodes;
-/* FIXME frontswap selfshrinking knobs in debugfs? */
-
-static LIST_HEAD(ramster_rem_op_list);
-static DEFINE_SPINLOCK(ramster_rem_op_list_lock);
-static DEFINE_PER_CPU(struct ramster_preload, ramster_preloads);
-
-static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem1);
-static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem2);
-
-static struct kmem_cache *ramster_flnode_cache __read_mostly;
-
-static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
-{
-	struct flushlist_node *flnode = NULL;
-	struct ramster_preload *kp;
-
-	kp = &__get_cpu_var(ramster_preloads);
-	flnode = kp->flnode;
-	BUG_ON(flnode == NULL);
-	kp->flnode = NULL;
-	inc_ramster_flnodes();
-	return flnode;
-}
-
-/* the "flush list" asynchronously collects pages to remotely flush */
-#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1)
-static void ramster_flnode_free(struct flushlist_node *flnode,
-				struct tmem_pool *pool)
-{
-	dec_ramster_flnodes();
-	BUG_ON(ramster_flnodes < 0);
-	kmem_cache_free(ramster_flnode_cache, flnode);
-}
-
-int ramster_do_preload_flnode(struct tmem_pool *pool)
-{
-	struct ramster_preload *kp;
-	struct flushlist_node *flnode;
-	int ret = -ENOMEM;
-
-	BUG_ON(!irqs_disabled());
-	if (unlikely(ramster_flnode_cache == NULL))
-		BUG();
-	kp = &__get_cpu_var(ramster_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;
-}
-EXPORT_SYMBOL_GPL(ramster_do_preload_flnode);
-
-/*
- * 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 successfully 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 ramster_repatriate_preload), the page
- * is placed into both local zcache and at "extra".
- */
-int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
-			char *data, unsigned int size, void *extra)
-{
-	int ret = -ENOENT;
-	unsigned long flags;
-	struct tmem_pool *pool;
-	bool eph, delete = false;
-	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;
-	eph = 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 ramster_localify\n");
-#endif
-		if (eph)
-			inc_ramster_remote_eph_pages_unsucc_get();
-		else
-			inc_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 ramster_localify\n");
-#endif
-		if (eph)
-			inc_ramster_remote_eph_pages_unsucc_get();
-		else
-			inc_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 (eph)
-			inc_ramster_remote_eph_pages_unsucc_get();
-		else
-			BUG();
-		delete = true;
-		goto finish;
-	}
-	if (pampd_is_intransit(pampd)) {
-		/*
-		 *  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)
-		 */
-		BUG_ON(eph);
-		pampd = pampd_mask_intransit_and_remote(pampd);
-		zbud_copy_to_zbud(pampd, data, size);
-	} else {
-		/*
-		 * setting pampd to NULL tells tmem_localify_finish to leave
-		 * pampd alone... meaning it is left pointing to the
-		 * remote copy
-		 */
-		pampd = NULL;
-		obj = NULL;
-	}
-	/*
-	 * but in all cases, we decompress direct-to-memory to complete
-	 * the remotify and return success
-	 */
-	BUG_ON(extra == NULL);
-	zcache_decompress_to_page(data, size, (struct page *)extra);
-	if (eph)
-		inc_ramster_remote_eph_pages_succ_get();
-	else
-		inc_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;
-}
-
-void ramster_pampd_new_obj(struct tmem_obj *obj)
-{
-	obj->extra = NULL;
-}
-
-void ramster_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj,
-				bool pool_destroy)
-{
-	struct flushlist_node *flnode;
-
-	BUG_ON(preemptible());
-	if (obj->extra == NULL)
-		return;
-	if (pool_destroy && is_ephemeral(pool))
-		/* FIXME don't bother with remote eph data for now */
-		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(&ramster_rem_op_list_lock);
-	list_add(&flnode->rem_op.list, &ramster_rem_op_list);
-	spin_unlock(&ramster_rem_op_list_lock);
-}
-
-/*
- * Called on a remote persistent tmem_get to attempt to preallocate
- * local storage for the data contained in the remote persistent page.
- * If successfully preallocated, returns the pampd, marked as remote and
- * in_transit.  Else returns NULL.  Note that the appropriate tmem data
- * structure must be locked.
- */
-void *ramster_pampd_repatriate_preload(void *pampd, struct tmem_pool *pool,
-					struct tmem_oid *oidp, uint32_t index,
-					bool *intransit)
-{
-	int clen = pampd_remote_size(pampd), c;
-	void *ret_pampd = NULL;
-	unsigned long flags;
-	struct tmem_handle th;
-
-	BUG_ON(!pampd_is_remote(pampd));
-	BUG_ON(is_ephemeral(pool));
-	if (use_frontswap_exclusive_gets)
-		/* don't need local storage */
-		goto out;
-	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);
-	th.client_id = pampd_remote_node(pampd);
-	th.pool_id = pool->pool_id;
-	th.oid = *oidp;
-	th.index = index;
-	ret_pampd = zcache_pampd_create(NULL, clen, true, false, &th);
-	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);
-		c = atomic_dec_return(&ramster_remote_pers_pages);
-		WARN_ON_ONCE(c < 0);
-	} else {
-		inc_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 ramster_localify.
- */
-int ramster_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 = r2net_remote_async_get(&xh, free,
-					pampd_remote_node(fake_pampd),
-					pampd_remote_size(fake_pampd),
-					pampd_remote_cksum(fake_pampd),
-					extra);
-	return ret;
-}
-
-bool ramster_pampd_is_remote(void *pampd)
-{
-	return pampd_is_remote(pampd);
-}
-
-int ramster_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;
-}
-
-void *ramster_pampd_free(void *pampd, struct tmem_pool *pool,
-			      struct tmem_oid *oid, uint32_t index, bool acct)
-{
-	bool eph = is_ephemeral(pool);
-	void *local_pampd = NULL;
-	int c;
-
-	BUG_ON(preemptible());
-	BUG_ON(!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 */
-	} else if (pampd_is_intransit(pampd)) {
-		/* did a pers remote get_and_free, so just free local */
-		local_pampd = pampd_mask_intransit_and_remote(pampd);
-	} 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(&ramster_rem_op_list_lock);
-		list_add(&flnode->rem_op.list, &ramster_rem_op_list);
-		spin_unlock(&ramster_rem_op_list_lock);
-		c = atomic_dec_return(&ramster_remote_pers_pages);
-		WARN_ON_ONCE(c < 0);
-	}
-	return local_pampd;
-}
-EXPORT_SYMBOL_GPL(ramster_pampd_free);
-
-void ramster_count_foreign_pages(bool eph, int count)
-{
-	BUG_ON(count != 1 && count != -1);
-	if (eph) {
-		if (count > 0) {
-			inc_ramster_foreign_eph_pages();
-		} else {
-			dec_ramster_foreign_eph_pages();
-#ifdef CONFIG_RAMSTER_DEBUG
-			WARN_ON_ONCE(ramster_foreign_eph_pages < 0);
-#endif
-		}
-	} else {
-		if (count > 0) {
-			inc_ramster_foreign_pers_pages();
-		} else {
-			dec_ramster_foreign_pers_pages();
-#ifdef CONFIG_RAMSTER_DEBUG
-			WARN_ON_ONCE(ramster_foreign_pers_pages < 0);
-#endif
-		}
-	}
-}
-EXPORT_SYMBOL_GPL(ramster_count_foreign_pages);
-
-/*
- * 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 void ramster_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 = r2net_remote_flush(xh, remotenode);
-	if (ret >= 0)
-		inc_ramster_remote_pages_flushed();
-	else
-		inc_ramster_remote_page_flushes_failed();
-	preempt_enable_no_resched();
-	ramster_flnode_free(flnode, NULL);
-}
-
-static void ramster_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 = r2net_remote_flush_object(xh, remotenode);
-	if (ret >= 0)
-		inc_ramster_remote_objects_flushed();
-	else
-		inc_ramster_remote_object_flushes_failed();
-	preempt_enable_no_resched();
-	ramster_flnode_free(flnode, NULL);
-}
-
-int ramster_remotify_pageframe(bool eph)
-{
-	struct tmem_xhandle xh;
-	unsigned int size;
-	int remotenode, ret, zbuds;
-	struct tmem_pool *pool;
-	unsigned long flags;
-	unsigned char cksum;
-	char *p;
-	int i, j;
-	unsigned char *tmpmem[2];
-	struct tmem_handle th[2];
-	unsigned int zsize[2];
-
-	tmpmem[0] = __get_cpu_var(ramster_remoteputmem1);
-	tmpmem[1] = __get_cpu_var(ramster_remoteputmem2);
-	local_bh_disable();
-	zbuds = zbud_make_zombie_lru(&th[0], &tmpmem[0], &zsize[0], eph);
-	/* now OK to release lock set in caller */
-	local_bh_enable();
-	if (zbuds == 0)
-		goto out;
-	BUG_ON(zbuds > 2);
-	for (i = 0; i < zbuds; i++) {
-		xh.client_id = th[i].client_id;
-		xh.pool_id = th[i].pool_id;
-		xh.oid = th[i].oid;
-		xh.index = th[i].index;
-		size = zsize[i];
-		BUG_ON(size == 0 || size > zbud_max_buddy_size());
-		for (p = tmpmem[i], cksum = 0, j = 0; j < size; j++)
-			cksum += *p++;
-		ret = r2net_remote_put(&xh, tmpmem[i], size, eph, &remotenode);
-		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.
-		 */
-			if (eph)
-				inc_ramster_eph_pages_remote_failed();
-			else
-				inc_ramster_pers_pages_remote_failed();
-			break;
-		} else {
-			if (!eph)
-				atomic_inc(&ramster_remote_pers_pages);
-		}
-		if (eph)
-			inc_ramster_eph_pages_remoted();
-		else
-			inc_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 zbuds;
-}
-
-static void zcache_do_remotify_flushes(void)
-{
-	struct ramster_remotify_hdr *rem_op;
-	union remotify_list_node *u;
-
-	while (1) {
-		spin_lock(&ramster_rem_op_list_lock);
-		if (list_empty(&ramster_rem_op_list)) {
-			spin_unlock(&ramster_rem_op_list_lock);
-			goto out;
-		}
-		rem_op = list_first_entry(&ramster_rem_op_list,
-				struct ramster_remotify_hdr, list);
-		list_del_init(&rem_op->list);
-		spin_unlock(&ramster_rem_op_list_lock);
-		u = (union remotify_list_node *)rem_op;
-		switch (rem_op->op) {
-		case RAMSTER_REMOTIFY_FLUSH_PAGE:
-			ramster_remote_flush_page((struct flushlist_node *)u);
-			break;
-		case RAMSTER_REMOTIFY_FLUSH_OBJ:
-			ramster_remote_flush_object((struct flushlist_node *)u);
-			break;
-		default:
-			BUG();
-		}
-	}
-out:
-	return;
-}
-
-static void ramster_remotify_process(struct work_struct *work)
-{
-	static bool remotify_in_progress;
-	int i;
-
-	BUG_ON(irqs_disabled());
-	if (remotify_in_progress)
-		goto requeue;
-	if (ramster_remote_target_nodenum == -1)
-		goto requeue;
-	remotify_in_progress = true;
-	if (use_cleancache && ramster_eph_remotify_enable) {
-		for (i = 0; i < 100; i++) {
-			zcache_do_remotify_flushes();
-			(void)ramster_remotify_pageframe(true);
-		}
-	}
-	if (use_frontswap && ramster_pers_remotify_enable) {
-		for (i = 0; i < 100; i++) {
-			zcache_do_remotify_flushes();
-			(void)ramster_remotify_pageframe(false);
-		}
-	}
-	remotify_in_progress = false;
-requeue:
-	ramster_remotify_queue_delayed_work(HZ);
-}
-
-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 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,
-};
-
-#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);
-
-static struct attribute *ramster_attrs[] = {
-	&ramster_interface_revision_attr.attr,
-	&ramster_remote_pers_pages_attr.attr,
-	&ramster_manual_node_up_attr.attr,
-	&ramster_remote_target_nodenum_attr.attr,
-	&ramster_pers_remotify_enable_attr.attr,
-	&ramster_eph_remotify_enable_attr.attr,
-	NULL,
-};
-
-static struct attribute_group ramster_attr_group = {
-	.attrs = ramster_attrs,
-	.name = "ramster",
-};
-
-/*
- * frontswap selfshrinking
- */
-
-/* In HZ, controls frequency of worker invocation. */
-static unsigned int selfshrink_interval __read_mostly = 5;
-/* Enable/disable with sysfs. */
-static bool frontswap_selfshrinking __read_mostly;
-
-static void selfshrink_process(struct work_struct *work);
-static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process);
-
-#ifndef CONFIG_RAMSTER_MODULE
-/* Enable/disable with kernel boot option. */
-static bool use_frontswap_selfshrink = true;
-#endif
-
-/*
- * 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);
-}
-
-#ifndef CONFIG_RAMSTER_MODULE
-static int __init ramster_nofrontswap_selfshrink_setup(char *s)
-{
-	use_frontswap_selfshrink = false;
-	return 1;
-}
-
-__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup);
-#endif
-
-static void selfshrink_process(struct work_struct *work)
-{
-	if (frontswap_selfshrinking && frontswap_enabled) {
-		frontswap_selfshrink();
-		schedule_delayed_work(&selfshrink_worker,
-			selfshrink_interval * HZ);
-	}
-}
-
-void ramster_cpu_up(int cpu)
-{
-	unsigned char *p1 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
-	unsigned char *p2 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT);
-	BUG_ON(!p1 || !p2);
-	per_cpu(ramster_remoteputmem1, cpu) = p1;
-	per_cpu(ramster_remoteputmem2, cpu) = p2;
-}
-EXPORT_SYMBOL_GPL(ramster_cpu_up);
-
-void ramster_cpu_down(int cpu)
-{
-	struct ramster_preload *kp;
-
-	kfree(per_cpu(ramster_remoteputmem1, cpu));
-	per_cpu(ramster_remoteputmem1, cpu) = NULL;
-	kfree(per_cpu(ramster_remoteputmem2, cpu));
-	per_cpu(ramster_remoteputmem2, cpu) = NULL;
-	kp = &per_cpu(ramster_preloads, cpu);
-	if (kp->flnode) {
-		kmem_cache_free(ramster_flnode_cache, kp->flnode);
-		kp->flnode = NULL;
-	}
-}
-EXPORT_SYMBOL_GPL(ramster_cpu_down);
-
-void ramster_register_pamops(struct tmem_pamops *pamops)
-{
-	pamops->free_obj = ramster_pampd_free_obj;
-	pamops->new_obj = ramster_pampd_new_obj;
-	pamops->replace_in_obj = ramster_pampd_replace_in_obj;
-	pamops->is_remote = ramster_pampd_is_remote;
-	pamops->repatriate = ramster_pampd_repatriate;
-	pamops->repatriate_preload = ramster_pampd_repatriate_preload;
-}
-EXPORT_SYMBOL_GPL(ramster_register_pamops);
-
-void ramster_init(bool cleancache, bool frontswap,
-				bool frontswap_exclusive_gets,
-				bool frontswap_selfshrink)
-{
-	int ret = 0;
-
-	if (cleancache)
-		use_cleancache = true;
-	if (frontswap)
-		use_frontswap = true;
-	if (frontswap_exclusive_gets)
-		use_frontswap_exclusive_gets = true;
-	ramster_debugfs_init();
-	ret = sysfs_create_group(mm_kobj, &ramster_attr_group);
-	if (ret)
-		pr_err("ramster: can't create sysfs for ramster\n");
-	(void)r2net_register_handlers();
-#ifdef CONFIG_RAMSTER_MODULE
-	ret = r2nm_init();
-	if (ret)
-		pr_err("ramster: can't init r2net\n");
-	frontswap_selfshrinking = frontswap_selfshrink;
-#else
-	frontswap_selfshrinking = use_frontswap_selfshrink;
-#endif
-	INIT_LIST_HEAD(&ramster_rem_op_list);
-	ramster_flnode_cache = kmem_cache_create("ramster_flnode",
-				sizeof(struct flushlist_node), 0, 0, NULL);
-	if (frontswap_selfshrinking) {
-		pr_info("ramster: Initializing frontswap selfshrink driver.\n");
-		schedule_delayed_work(&selfshrink_worker,
-					selfshrink_interval * HZ);
-	}
-	ramster_remotify_init();
-}
-EXPORT_SYMBOL_GPL(ramster_init);
diff --git a/drivers/staging/zcache/ramster/ramster.h b/drivers/staging/zcache/ramster/ramster.h
deleted file mode 100644
index 6d41a7a..0000000
--- a/drivers/staging/zcache/ramster/ramster.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * ramster.h
- *
- * Peer-to-peer transcendent memory
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _RAMSTER_RAMSTER_H_
-#define _RAMSTER_RAMSTER_H_
-
-#include "../tmem.h"
-
-enum ramster_remotify_op {
-	RAMSTER_REMOTIFY_FLUSH_PAGE,
-	RAMSTER_REMOTIFY_FLUSH_OBJ,
-};
-
-struct ramster_remotify_hdr {
-	enum ramster_remotify_op op;
-	struct list_head list;
-};
-
-struct flushlist_node {
-	struct ramster_remotify_hdr rem_op;
-	struct tmem_xhandle xh;
-};
-
-struct ramster_preload {
-	struct flushlist_node *flnode;
-};
-
-union remotify_list_node {
-	struct ramster_remotify_hdr rem_op;
-	struct {
-		struct ramster_remotify_hdr rem_op;
-		struct tmem_handle th;
-	} zbud_hdr;
-	struct flushlist_node flist;
-};
-
-/*
- * format of remote pampd:
- *   bit 0 is reserved for zbud (in-page buddy selection)
- *   bit 1 == intransit
- *   bit 2 == is_remote... if this bit is set, then
- *   bit 3-10 == remotenode
- *   bit 11-23 == size
- *   bit 24-31 == 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	1
-#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 r2net_remote_async_get(struct tmem_xhandle *,
-				bool, int, size_t, uint8_t, void *extra);
-extern int r2net_remote_put(struct tmem_xhandle *, char *, size_t,
-				bool, int *);
-extern int r2net_remote_flush(struct tmem_xhandle *, int);
-extern int r2net_remote_flush_object(struct tmem_xhandle *, int);
-extern int r2net_register_handlers(void);
-extern int r2net_remote_target_node_set(int);
-
-extern int ramster_remotify_pageframe(bool);
-extern void ramster_init(bool, bool, bool, bool);
-extern void ramster_register_pamops(struct tmem_pamops *);
-extern int ramster_localify(int, struct tmem_oid *oidp, uint32_t, char *,
-				unsigned int, void *);
-extern void *ramster_pampd_free(void *, struct tmem_pool *, struct tmem_oid *,
-				uint32_t, bool);
-extern void ramster_count_foreign_pages(bool, int);
-extern int ramster_do_preload_flnode(struct tmem_pool *);
-extern void ramster_cpu_up(int);
-extern void ramster_cpu_down(int);
-
-#endif /* _RAMSTER_RAMSTER_H */
diff --git a/drivers/staging/zcache/ramster/ramster_nodemanager.h b/drivers/staging/zcache/ramster/ramster_nodemanager.h
deleted file mode 100644
index dbaae34..0000000
--- a/drivers/staging/zcache/ramster/ramster_nodemanager.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- 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 */
-
-extern int r2nm_init(void);
-
-#endif /* _RAMSTER_NODEMANAGER_H */
diff --git a/drivers/staging/zcache/ramster/tcp.c b/drivers/staging/zcache/ramster/tcp.c
deleted file mode 100644
index f6e1e52..0000000
--- a/drivers/staging/zcache/ramster/tcp.c
+++ /dev/null
@@ -1,2248 +0,0 @@
-/* -*- 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 quorum 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;
-
-	spin_lock(&nn->nn_lock);
-	ret = idr_alloc(&nn->nn_status_idr, nsw, 0, 0, GFP_ATOMIC);
-	if (ret >= 0) {
-		nsw->ns_id = ret;
-		list_add_tail(&nsw->ns_node_item, &nn->nn_status_list);
-	}
-	spin_unlock(&nn->nn_lock);
-
-	if (ret >= 0) {
-		init_waitqueue_head(&nsw->ns_wq);
-		nsw->ns_sys_status = R2NET_ERR_NONE;
-		nsw->ns_status = 0;
-		return 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) {
-		pr_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);
-		pr_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:
-		pr_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 are 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) ||
-			nn->nn_persistent_error || !nn->nn_sc_valid);
-
-	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) {
-		pr_err("ramster_r2net, message length problem\n");
-		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)) {
-		pr_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()) {
-		pr_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()) {
-		pr_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) {
-		pr_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;
-				WARN_ON_ONCE(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;
-	struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num);
-#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
-
-	pr_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.
-	 */
-	atomic_set(&nn->nn_timeout, 1);
-	r2net_sc_queue_work(sc, &sc->sc_shutdown_work);
-}
-
-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) {
-		pr_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) {
-		pr_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) {
-		pr_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());
-		pr_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) {
-		pr_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) {
-		pr_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 = /* SK_CAN_REUSE FIXME FOR 3.4 */ 1;
-	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
-	if (ret < 0) {
-		pr_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)
-		pr_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/zcache/ramster/tcp.h b/drivers/staging/zcache/ramster/tcp.h
deleted file mode 100644
index 9d05833..0000000
--- a/drivers/staging/zcache/ramster/tcp.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -*- 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/zcache/ramster/tcp_internal.h b/drivers/staging/zcache/ramster/tcp_internal.h
deleted file mode 100644
index 4d8cc9f..0000000
--- a/drivers/staging/zcache/ramster/tcp_internal.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/* -*- 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/zcache/tmem.c b/drivers/staging/zcache/tmem.c
deleted file mode 100644
index d7e51e4..0000000
--- a/drivers/staging/zcache/tmem.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * In-kernel transcendent memory (generic implementation)
- *
- * Copyright (c) 2009-2012, 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. For those familiar with key-value stores,
- * the tmem handle is a three-level hierarchical key, and the value is always
- * reconstituted (but not necessarily stored) as PAGE_SIZE bytes and is
- * referenced in the datastore by the pampd.  The hierarchy is required
- * to ensure that certain invalidation functions can be performed efficiently
- * (i.e. flush all indexes associated with this object_id, or
- * flush all objects associated with this pool).
- *
- * 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 the 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 only needs to memory allocation for objs
- * and objnodes and this is done via a set of callbacks that must be
- * 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/export.h>
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-#include <linux/delay.h>
-#endif
-
-#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 and no
- * searches, inserts, or deletions can be performed unless the lock is held.
- * As a result, care must be taken to ensure tmem routines are not called
- * recursively; the vast majority of the time, a recursive call may work
- * but a deadlock will occur a small fraction of the time due to the
- * hashbucket lock.
- *
- * The following routines manage tmem_objs.  In all of these routines,
- * the hashbucket lock is already held.
- */
-
-/* Search for object==oid in pool, returns object if found. */
-static struct tmem_obj *__tmem_obj_find(struct tmem_hashbucket *hb,
-					struct tmem_oid *oidp,
-					struct rb_node **parent,
-					struct rb_node ***link)
-{
-	struct rb_node *_parent = NULL, **rbnode;
-	struct tmem_obj *obj = NULL;
-
-	rbnode = &hb->obj_rb_root.rb_node;
-	while (*rbnode) {
-		BUG_ON(RB_EMPTY_NODE(*rbnode));
-		_parent = *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;
-		}
-	}
-
-	if (parent)
-		*parent = _parent;
-	if (link)
-		*link = rbnode;
-	obj = NULL;
-out:
-	return obj;
-}
-
-static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb,
-					struct tmem_oid *oidp)
-{
-	return __tmem_obj_find(hb, oidp, NULL, NULL);
-}
-
-static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *, bool);
-
-/* 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, false);
-	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 = NULL, *parent = NULL;
-
-	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;
-#ifdef CONFIG_RAMSTER
-	if (tmem_pamops.new_obj != NULL)
-		(*tmem_pamops.new_obj)(obj);
-#endif
-	SET_SENTINEL(obj, OBJ);
-
-	if (__tmem_obj_find(hb, oidp, &parent, &new))
-		BUG();
-
-	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, true);
-			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;
-}
-
-#ifdef CONFIG_RAMSTER
-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;
-}
-#endif
-
-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,
-						bool pool_destroy)
-{
-	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;
-#ifdef CONFIG_RAMSTER
-	if (tmem_pamops.free_obj != NULL)
-		(*tmem_pamops.free_obj)(obj->pool, obj, pool_destroy);
-#endif
-}
-
-/*
- * 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. associate the passed pampd with the passed handle.
- * 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,
-		bool raw, void *pampd_to_use)
-{
-	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 = pampd_to_use;
-	BUG_ON(pampd_to_use == NULL);
-	ret = tmem_pampd_add_to_obj(obj, index, pampd);
-	if (unlikely(ret == -ENOMEM))
-		/* may have partially built objnode tree ("stump") */
-		goto delete_and_free;
-	(*tmem_pamops.create_finish)(pampd, is_ephemeral(pool));
-	goto out;
-
-delete_and_free:
-	(void)tmem_pampd_delete_from_obj(obj, index);
-	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;
-}
-
-#ifdef CONFIG_RAMSTER
-/*
- * For ramster only:  The following routines provide a two-step sequence
- * to allow the caller to replace a pampd in the tmem data structures with
- * another pampd. Here, we lookup the passed handle and, if found, return the
- * associated pampd and object, leaving the hashbucket locked and returning
- * a reference to it.  The caller is expected to immediately call the
- * matching tmem_localify_finish routine which will handles the replacement
- * and unlocks the hashbucket.
- */
-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;
-}
-EXPORT_SYMBOL_GPL(tmem_localify_get_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);
-		(*tmem_pamops.create_finish)(pampd, is_ephemeral(obj->pool));
-	} else if (delete) {
-		BUG_ON(obj == NULL);
-		(void)tmem_pampd_delete_from_obj(obj, index);
-	}
-	spin_unlock(&hb->lock);
-}
-EXPORT_SYMBOL_GPL(tmem_localify_finish);
-
-/*
- * For ramster only.  Helper function to support asynchronous tmem_get.
- */
-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);
-	if (ret == -EAGAIN) {
-		/* rare I think, but should cond_resched()??? */
-		usleep_range(10, 1000);
-	} else if (ret == -ENOTCONN || ret == -EHOSTDOWN) {
-		ret = -1;
-	} else if (ret != 0 && ret != -ENOENT) {
-		ret = -1;
-	}
-	/* note hb->lock has now been unlocked */
-	return ret;
-}
-
-/*
- * For ramster only.  If a page in tmem matches the handle, replace the
- * page so that any subsequent "get" gets the new page.  Returns 0 if
- * there was a page to replace, else returns -1.
- */
-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);
-	/* if we bug here, pamops wasn't properly set up for ramster */
-	BUG_ON(tmem_pamops.replace_in_obj == NULL);
-	ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj);
-out:
-	spin_unlock(&hb->lock);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(tmem_replace);
-#endif
-
-/*
- * "Get" a page, e.g. if a pampd can be found matching the passed handle,
- * use a pamops callback to recreated the page from the pampd with the
- * matching handle.  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 *sizep, bool raw, int get_and_free)
-{
-	struct tmem_obj *obj;
-	void *pampd = NULL;
-	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 = false;
-	void **ppampd;
-
-	do {
-		hb = &pool->hashbucket[tmem_oid_hash(oidp)];
-		spin_lock(&hb->lock);
-		lock_held = true;
-		obj = tmem_obj_find(hb, oidp);
-		if (obj == NULL)
-			goto out;
-		ppampd = __tmem_pampd_lookup_in_obj(obj, index);
-		if (ppampd == NULL)
-			goto out;
-#ifdef CONFIG_RAMSTER
-		if ((tmem_pamops.is_remote != NULL) &&
-		     tmem_pamops.is_remote(*ppampd)) {
-			ret = tmem_repatriate(ppampd, hb, pool, oidp,
-						index, free, data);
-			/* tmem_repatriate releases hb->lock */
-			lock_held = false;
-			*sizep = PAGE_SIZE;
-			if (ret != -EAGAIN)
-				goto out;
-		}
-#endif
-	} while (ret == -EAGAIN);
-	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, sizep, raw, pampd, pool, oidp, index);
-	else
-		ret = (*tmem_pamops.get_data)(
-				data, sizep, 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;
-}
-
-/*
- * "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, false);
-	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/zcache/tmem.h b/drivers/staging/zcache/tmem.h
deleted file mode 100644
index d128ce2..0000000
--- a/drivers/staging/zcache/tmem.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * tmem.h
- *
- * Transcendent memory
- *
- * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _TMEM_H_
-#define _TMEM_H_
-
-#include <linux/types.h>
-#include <linux/highmem.h>
-#include <linux/hash.h>
-#include <linux/atomic.h>
-
-/*
- * These are defined by the Xen<->Linux ABI so should remain consistent
- */
-#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.
- */
-#undef 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)	lockdep_assert_held(_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];
-};
-
-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);
-}
-
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-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;
-}
-#endif
-
-
-/*
- * 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;
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-	/*
-	 * 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 private use by pampd implementation */
-#endif
-	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;
-};
-
-struct tmem_handle {
-	struct tmem_oid oid; /* 24 bytes */
-	uint32_t index;
-	uint16_t pool_id;
-	uint16_t client_id;
-};
-
-
-/* pampd abstract datatype methods provided by the PAM implementation */
-struct tmem_pamops {
-	void (*create_finish)(void *, bool);
-	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);
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-	void (*new_obj)(struct tmem_obj *);
-	void (*free_obj)(struct tmem_pool *, struct tmem_obj *, bool);
-	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 *);
-	bool (*is_remote)(void *);
-	int (*replace_in_obj)(void *, struct tmem_obj *);
-#endif
-};
-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,
-			bool, void *);
-extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index,
-			char *, size_t *, bool, int);
-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);
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-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);
-#endif
-#endif /* _TMEM_H */
diff --git a/drivers/staging/zcache/zbud.c b/drivers/staging/zcache/zbud.c
deleted file mode 100644
index 6cda4ed9..0000000
--- a/drivers/staging/zcache/zbud.c
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*
- * zbud.c - Compression buddies allocator
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- *
- * Compression buddies ("zbud") provides for efficiently packing two
- * (or, possibly in the future, more) compressed pages ("zpages") into
- * a single "raw" pageframe and for tracking both zpages and pageframes
- * so that whole pageframes can be easily reclaimed in LRU-like order.
- * It is designed to be used in conjunction with transcendent memory
- * ("tmem"); for example separate LRU lists are maintained for persistent
- * vs. ephemeral pages.
- *
- * A zbudpage is an overlay for a struct page and thus each zbudpage
- * refers to a physical pageframe of RAM.  When the caller passes a
- * struct page from the kernel's page allocator, zbud "transforms" it
- * to a zbudpage which sets/uses a different set of fields than the
- * struct-page and thus must "untransform" it back by reinitializing
- * certain fields before the struct-page can be freed.  The fields
- * of a zbudpage include a page lock for controlling access to the
- * corresponding pageframe, and there is a size field for each zpage.
- * Each zbudpage also lives on two linked lists: a "budlist" which is
- * used to support efficient buddying of zpages; and an "lru" which
- * is used for reclaiming pageframes in approximately least-recently-used
- * order.
- *
- * A zbudpageframe is a pageframe divided up into aligned 64-byte "chunks"
- * which contain the compressed data for zero, one, or two zbuds.  Contained
- * with the compressed data is a tmem_handle which is a key to allow
- * the same data to be found via the tmem interface so the zpage can
- * be invalidated (for ephemeral pages) or repatriated to the swap cache
- * (for persistent pages).  The contents of a zbudpageframe must never
- * be accessed without holding the page lock for the corresponding
- * zbudpage and, to accomodate highmem machines, the contents may
- * only be examined or changes when kmapped.  Thus, when in use, a
- * kmapped zbudpageframe is referred to in the zbud code as "void *zbpg".
- *
- * Note that the term "zbud" refers to the combination of a zpage and
- * a tmem_handle that is stored as one of possibly two "buddied" zpages;
- * it also generically refers to this allocator... sorry for any confusion.
- *
- * A zbudref is a pointer to a struct zbudpage (which can be cast to a
- * struct page), with the LSB either cleared or set to indicate, respectively,
- * the first or second zpage in the zbudpageframe. Since a zbudref can be
- * cast to a pointer, it is used as the tmem "pampd" pointer and uniquely
- * references a stored tmem page and so is the only zbud data structure
- * externally visible to zbud.c/zbud.h.
- *
- * Since we wish to reclaim entire pageframes but zpages may be randomly
- * added and deleted to any given pageframe, we approximate LRU by
- * promoting a pageframe to MRU when a zpage is added to it, but
- * leaving it at the current place in the list when a zpage is deleted
- * from it.  As a side effect, zpages that are difficult to buddy (e.g.
- * very large paages) will be reclaimed faster than average, which seems
- * reasonable.
- *
- * In the current implementation, no more than two zpages may be stored in
- * any pageframe and no zpage ever crosses a pageframe boundary.  While
- * other zpage allocation mechanisms may allow greater density, this two
- * zpage-per-pageframe limit both ensures simple reclaim of pageframes
- * (including garbage collection of references to the contents of those
- * pageframes from tmem data structures) AND avoids the need for compaction.
- * With additional complexity, zbud could be modified to support storing
- * up to three zpages per pageframe or, to handle larger average zpages,
- * up to three zpages per pair of pageframes, but it is not clear if the
- * additional complexity would be worth it.  So consider it an exercise
- * for future developers.
- *
- * Note also that zbud does no page allocation or freeing.  This is so
- * that the caller has complete control over and, for accounting, visibility
- * into if/when pages are allocated and freed.
- *
- * Finally, note that zbud limits the size of zpages it can store; the
- * caller must check the zpage size with zbud_max_buddy_size before
- * storing it, else BUGs will result.  User beware.
- */
-
-#include <linux/module.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/pagemap.h>
-#include <linux/atomic.h>
-#include <linux/bug.h>
-#include "tmem.h"
-#include "zcache.h"
-#include "zbud.h"
-
-/*
- * We need to ensure that a struct zbudpage is never larger than a
- * struct page.  This is checked with a BUG_ON in zbud_init.
- *
- * The unevictable field indicates that a zbud is being added to the
- * zbudpage.  Since this is a two-phase process (due to tmem locking),
- * this field locks the zbudpage against eviction when a zbud match
- * or creation is in process.  Since this addition process may occur
- * in parallel for two zbuds in one zbudpage, the field is a counter
- * that must not exceed two.
- */
-struct zbudpage {
-	union {
-		struct page page;
-		struct {
-			unsigned long space_for_flags;
-			struct {
-				unsigned zbud0_size:PAGE_SHIFT;
-				unsigned zbud1_size:PAGE_SHIFT;
-				unsigned unevictable:2;
-			};
-			struct list_head budlist;
-			struct list_head lru;
-		};
-	};
-};
-#if (PAGE_SHIFT * 2) + 2 > BITS_PER_LONG
-#error "zbud won't work for this arch, PAGE_SIZE is too large"
-#endif
-
-struct zbudref {
-	union {
-		struct zbudpage *zbudpage;
-		unsigned long zbudref;
-	};
-};
-
-#define CHUNK_SHIFT	6
-#define CHUNK_SIZE	(1 << CHUNK_SHIFT)
-#define CHUNK_MASK	(~(CHUNK_SIZE-1))
-#define NCHUNKS		(PAGE_SIZE >> CHUNK_SHIFT)
-#define MAX_CHUNK	(NCHUNKS-1)
-
-/*
- * The following functions deal with the difference between struct
- * page and struct zbudpage.  Note the hack of using the pageflags
- * from struct page; this is to avoid duplicating all the complex
- * pageflag macros.
- */
-static inline void zbudpage_spin_lock(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	while (unlikely(test_and_set_bit_lock(PG_locked, &page->flags))) {
-		do {
-			cpu_relax();
-		} while (test_bit(PG_locked, &page->flags));
-	}
-}
-
-static inline void zbudpage_spin_unlock(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	clear_bit(PG_locked, &page->flags);
-}
-
-static inline int zbudpage_spin_trylock(struct zbudpage *zbudpage)
-{
-	return trylock_page((struct page *)zbudpage);
-}
-
-static inline int zbudpage_is_locked(struct zbudpage *zbudpage)
-{
-	return PageLocked((struct page *)zbudpage);
-}
-
-static inline void *kmap_zbudpage_atomic(struct zbudpage *zbudpage)
-{
-	return kmap_atomic((struct page *)zbudpage);
-}
-
-/*
- * A dying zbudpage is an ephemeral page in the process of being evicted.
- * Any data contained in the zbudpage is invalid and we are just waiting for
- * the tmem pampds to be invalidated before freeing the page
- */
-static inline int zbudpage_is_dying(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	return test_bit(PG_reclaim, &page->flags);
-}
-
-static inline void zbudpage_set_dying(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	set_bit(PG_reclaim, &page->flags);
-}
-
-static inline void zbudpage_clear_dying(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	clear_bit(PG_reclaim, &page->flags);
-}
-
-/*
- * A zombie zbudpage is a persistent page in the process of being evicted.
- * The data contained in the zbudpage is valid and we are just waiting for
- * the tmem pampds to be invalidated before freeing the page
- */
-static inline int zbudpage_is_zombie(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	return test_bit(PG_dirty, &page->flags);
-}
-
-static inline void zbudpage_set_zombie(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	set_bit(PG_dirty, &page->flags);
-}
-
-static inline void zbudpage_clear_zombie(struct zbudpage *zbudpage)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	clear_bit(PG_dirty, &page->flags);
-}
-
-static inline void kunmap_zbudpage_atomic(void *zbpg)
-{
-	kunmap_atomic(zbpg);
-}
-
-/*
- * zbud "translation" and helper functions
- */
-
-static inline struct zbudpage *zbudref_to_zbudpage(struct zbudref *zref)
-{
-	unsigned long zbud = (unsigned long)zref;
-	zbud &= ~1UL;
-	return (struct zbudpage *)zbud;
-}
-
-static inline struct zbudref *zbudpage_to_zbudref(struct zbudpage *zbudpage,
-							unsigned budnum)
-{
-	unsigned long zbud = (unsigned long)zbudpage;
-	BUG_ON(budnum > 1);
-	zbud |= budnum;
-	return (struct zbudref *)zbud;
-}
-
-static inline int zbudref_budnum(struct zbudref *zbudref)
-{
-	unsigned long zbud = (unsigned long)zbudref;
-	return zbud & 1UL;
-}
-
-static inline unsigned zbud_max_size(void)
-{
-	return MAX_CHUNK << CHUNK_SHIFT;
-}
-
-static inline unsigned zbud_size_to_chunks(unsigned size)
-{
-	BUG_ON(size == 0 || size > zbud_max_size());
-	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
-}
-
-/* can only be used between kmap_zbudpage_atomic/kunmap_zbudpage_atomic! */
-static inline char *zbud_data(void *zbpg,
-			unsigned budnum, unsigned size)
-{
-	char *p;
-
-	BUG_ON(size == 0 || size > zbud_max_size());
-	p = (char *)zbpg;
-	if (budnum == 1)
-		p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK);
-	return p;
-}
-
-/*
- * These are all informative and exposed through debugfs... except for
- * the arrays... anyone know how to do that?  To avoid confusion for
- * debugfs viewers, some of these should also be atomic_long_t, but
- * I don't know how to expose atomics via debugfs either...
- */
-static ssize_t zbud_eph_pageframes;
-static ssize_t zbud_pers_pageframes;
-static ssize_t zbud_eph_zpages;
-static ssize_t zbud_pers_zpages;
-static u64 zbud_eph_zbytes;
-static u64 zbud_pers_zbytes;
-static ssize_t zbud_eph_evicted_pageframes;
-static ssize_t zbud_pers_evicted_pageframes;
-static ssize_t zbud_eph_cumul_zpages;
-static ssize_t zbud_pers_cumul_zpages;
-static u64 zbud_eph_cumul_zbytes;
-static u64 zbud_pers_cumul_zbytes;
-static ssize_t zbud_eph_cumul_chunk_counts[NCHUNKS];
-static ssize_t zbud_pers_cumul_chunk_counts[NCHUNKS];
-static ssize_t zbud_eph_buddied_count;
-static ssize_t zbud_pers_buddied_count;
-static ssize_t zbud_eph_unbuddied_count;
-static ssize_t zbud_pers_unbuddied_count;
-static ssize_t zbud_eph_zombie_count;
-static ssize_t zbud_pers_zombie_count;
-static atomic_t zbud_eph_zombie_atomic;
-static atomic_t zbud_pers_zombie_atomic;
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#define	zdfs	debugfs_create_size_t
-#define	zdfs64	debugfs_create_u64
-static int zbud_debugfs_init(void)
-{
-	struct dentry *root = debugfs_create_dir("zbud", NULL);
-	if (root == NULL)
-		return -ENXIO;
-
-	/*
-	 * would be nice to dump the sizes of the unbuddied
-	 * arrays, like was done with sysfs, but it doesn't
-	 * look like debugfs is flexible enough to do that
-	 */
-	zdfs64("eph_zbytes", S_IRUGO, root, &zbud_eph_zbytes);
-	zdfs64("eph_cumul_zbytes", S_IRUGO, root, &zbud_eph_cumul_zbytes);
-	zdfs64("pers_zbytes", S_IRUGO, root, &zbud_pers_zbytes);
-	zdfs64("pers_cumul_zbytes", S_IRUGO, root, &zbud_pers_cumul_zbytes);
-	zdfs("eph_cumul_zpages", S_IRUGO, root, &zbud_eph_cumul_zpages);
-	zdfs("eph_evicted_pageframes", S_IRUGO, root,
-				&zbud_eph_evicted_pageframes);
-	zdfs("eph_zpages", S_IRUGO, root, &zbud_eph_zpages);
-	zdfs("eph_pageframes", S_IRUGO, root, &zbud_eph_pageframes);
-	zdfs("eph_buddied_count", S_IRUGO, root, &zbud_eph_buddied_count);
-	zdfs("eph_unbuddied_count", S_IRUGO, root, &zbud_eph_unbuddied_count);
-	zdfs("pers_cumul_zpages", S_IRUGO, root, &zbud_pers_cumul_zpages);
-	zdfs("pers_evicted_pageframes", S_IRUGO, root,
-				&zbud_pers_evicted_pageframes);
-	zdfs("pers_zpages", S_IRUGO, root, &zbud_pers_zpages);
-	zdfs("pers_pageframes", S_IRUGO, root, &zbud_pers_pageframes);
-	zdfs("pers_buddied_count", S_IRUGO, root, &zbud_pers_buddied_count);
-	zdfs("pers_unbuddied_count", S_IRUGO, root, &zbud_pers_unbuddied_count);
-	zdfs("pers_zombie_count", S_IRUGO, root, &zbud_pers_zombie_count);
-	return 0;
-}
-#undef	zdfs
-#undef	zdfs64
-#else
-static inline int zbud_debugfs_init(void)
-{
-	return 0;
-}
-#endif
-
-/* protects the buddied list and all unbuddied lists */
-static DEFINE_SPINLOCK(zbud_eph_lists_lock);
-static DEFINE_SPINLOCK(zbud_pers_lists_lock);
-
-struct zbud_unbuddied {
-	struct list_head list;
-	unsigned count;
-};
-
-/* 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 struct zbud_unbuddied zbud_eph_unbuddied[NCHUNKS];
-static struct zbud_unbuddied zbud_pers_unbuddied[NCHUNKS];
-static LIST_HEAD(zbud_eph_lru_list);
-static LIST_HEAD(zbud_pers_lru_list);
-static LIST_HEAD(zbud_eph_buddied_list);
-static LIST_HEAD(zbud_pers_buddied_list);
-static LIST_HEAD(zbud_eph_zombie_list);
-static LIST_HEAD(zbud_pers_zombie_list);
-
-/*
- * Given a struct page, transform it to a zbudpage so that it can be
- * used by zbud and initialize fields as necessary.
- */
-static inline struct zbudpage *zbud_init_zbudpage(struct page *page, bool eph)
-{
-	struct zbudpage *zbudpage = (struct zbudpage *)page;
-
-	BUG_ON(page == NULL);
-	INIT_LIST_HEAD(&zbudpage->budlist);
-	INIT_LIST_HEAD(&zbudpage->lru);
-	zbudpage->zbud0_size = 0;
-	zbudpage->zbud1_size = 0;
-	zbudpage->unevictable = 0;
-	if (eph)
-		zbud_eph_pageframes++;
-	else
-		zbud_pers_pageframes++;
-	return zbudpage;
-}
-
-/* "Transform" a zbudpage back to a struct page suitable to free. */
-static inline struct page *zbud_unuse_zbudpage(struct zbudpage *zbudpage,
-								bool eph)
-{
-	struct page *page = (struct page *)zbudpage;
-
-	BUG_ON(!list_empty(&zbudpage->budlist));
-	BUG_ON(!list_empty(&zbudpage->lru));
-	BUG_ON(zbudpage->zbud0_size != 0);
-	BUG_ON(zbudpage->zbud1_size != 0);
-	BUG_ON(!PageLocked(page));
-	BUG_ON(zbudpage->unevictable != 0);
-	BUG_ON(zbudpage_is_dying(zbudpage));
-	BUG_ON(zbudpage_is_zombie(zbudpage));
-	if (eph)
-		zbud_eph_pageframes--;
-	else
-		zbud_pers_pageframes--;
-	zbudpage_spin_unlock(zbudpage);
-	page_mapcount_reset(page);
-	init_page_count(page);
-	page->index = 0;
-	return page;
-}
-
-/* Mark a zbud as unused and do accounting */
-static inline void zbud_unuse_zbud(struct zbudpage *zbudpage,
-					int budnum, bool eph)
-{
-	unsigned size;
-
-	BUG_ON(!zbudpage_is_locked(zbudpage));
-	if (budnum == 0) {
-		size = zbudpage->zbud0_size;
-		zbudpage->zbud0_size = 0;
-	} else {
-		size = zbudpage->zbud1_size;
-		zbudpage->zbud1_size = 0;
-	}
-	if (eph) {
-		zbud_eph_zbytes -= size;
-		zbud_eph_zpages--;
-	} else {
-		zbud_pers_zbytes -= size;
-		zbud_pers_zpages--;
-	}
-}
-
-/*
- * Given a zbudpage/budnum/size, a tmem handle, and a kmapped pointer
- * to some data, set up the zbud appropriately including data copying
- * and accounting.  Note that if cdata is NULL, the data copying is
- * skipped.  (This is useful for lazy writes such as for RAMster.)
- */
-static void zbud_init_zbud(struct zbudpage *zbudpage, struct tmem_handle *th,
-				bool eph, void *cdata,
-				unsigned budnum, unsigned size)
-{
-	char *to;
-	void *zbpg;
-	struct tmem_handle *to_th;
-	unsigned nchunks = zbud_size_to_chunks(size);
-
-	BUG_ON(!zbudpage_is_locked(zbudpage));
-	zbpg = kmap_zbudpage_atomic(zbudpage);
-	to = zbud_data(zbpg, budnum, size);
-	to_th = (struct tmem_handle *)to;
-	to_th->index = th->index;
-	to_th->oid = th->oid;
-	to_th->pool_id = th->pool_id;
-	to_th->client_id = th->client_id;
-	to += sizeof(struct tmem_handle);
-	if (cdata != NULL)
-		memcpy(to, cdata, size - sizeof(struct tmem_handle));
-	kunmap_zbudpage_atomic(zbpg);
-	if (budnum == 0)
-		zbudpage->zbud0_size = size;
-	else
-		zbudpage->zbud1_size = size;
-	if (eph) {
-		zbud_eph_cumul_chunk_counts[nchunks]++;
-		zbud_eph_zpages++;
-		zbud_eph_cumul_zpages++;
-		zbud_eph_zbytes += size;
-		zbud_eph_cumul_zbytes += size;
-	} else {
-		zbud_pers_cumul_chunk_counts[nchunks]++;
-		zbud_pers_zpages++;
-		zbud_pers_cumul_zpages++;
-		zbud_pers_zbytes += size;
-		zbud_pers_cumul_zbytes += size;
-	}
-}
-
-/*
- * Given a locked dying zbudpage, read out the tmem handles from the data,
- * unlock the page, then use the handles to tell tmem to flush out its
- * references
- */
-static void zbud_evict_tmem(struct zbudpage *zbudpage)
-{
-	int i, j;
-	uint32_t pool_id[2], client_id[2];
-	uint32_t index[2];
-	struct tmem_oid oid[2];
-	struct tmem_pool *pool;
-	void *zbpg;
-	struct tmem_handle *th;
-	unsigned size;
-
-	/* read out the tmem handles from the data and set aside */
-	zbpg = kmap_zbudpage_atomic(zbudpage);
-	for (i = 0, j = 0; i < 2; i++) {
-		size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size;
-		if (size) {
-			th = (struct tmem_handle *)zbud_data(zbpg, i, size);
-			client_id[j] = th->client_id;
-			pool_id[j] = th->pool_id;
-			oid[j] = th->oid;
-			index[j] = th->index;
-			j++;
-			zbud_unuse_zbud(zbudpage, i, true);
-		}
-	}
-	kunmap_zbudpage_atomic(zbpg);
-	zbudpage_spin_unlock(zbudpage);
-	/* zbudpage is now an unlocked dying... tell tmem to flush pointers */
-	for (i = 0; i < j; i++) {
-		pool = zcache_get_pool_by_id(client_id[i], pool_id[i]);
-		if (pool != NULL) {
-			tmem_flush_page(pool, &oid[i], index[i]);
-			zcache_put_pool(pool);
-		}
-	}
-}
-
-/*
- * Externally callable zbud handling routines.
- */
-
-/*
- * Return the maximum size compressed page that can be stored (secretly
- * setting aside space for the tmem handle.
- */
-unsigned int zbud_max_buddy_size(void)
-{
-	return zbud_max_size() - sizeof(struct tmem_handle);
-}
-
-/*
- * Given a zbud reference, free the corresponding zbud from all lists,
- * mark it as unused, do accounting, and if the freeing of the zbud
- * frees up an entire pageframe, return it to the caller (else NULL).
- */
-struct page *zbud_free_and_delist(struct zbudref *zref, bool eph,
-				  unsigned int *zsize, unsigned int *zpages)
-{
-	unsigned long budnum = zbudref_budnum(zref);
-	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
-	struct page *page = NULL;
-	unsigned chunks, bud_size, other_bud_size;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-	struct zbud_unbuddied *unbud =
-		eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
-
-
-	spin_lock(lists_lock);
-	zbudpage_spin_lock(zbudpage);
-	if (zbudpage_is_dying(zbudpage)) {
-		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
-		zbudpage_spin_unlock(zbudpage);
-		spin_unlock(lists_lock);
-		*zpages = 0;
-		*zsize = 0;
-		goto out;
-	}
-	if (budnum == 0) {
-		bud_size = zbudpage->zbud0_size;
-		other_bud_size = zbudpage->zbud1_size;
-	} else {
-		bud_size = zbudpage->zbud1_size;
-		other_bud_size = zbudpage->zbud0_size;
-	}
-	*zsize = bud_size - sizeof(struct tmem_handle);
-	*zpages = 1;
-	zbud_unuse_zbud(zbudpage, budnum, eph);
-	if (other_bud_size == 0) { /* was unbuddied: unlist and free */
-		chunks = zbud_size_to_chunks(bud_size) ;
-		if (zbudpage_is_zombie(zbudpage)) {
-			if (eph)
-				zbud_pers_zombie_count =
-				  atomic_dec_return(&zbud_eph_zombie_atomic);
-			else
-				zbud_pers_zombie_count =
-				  atomic_dec_return(&zbud_pers_zombie_atomic);
-			zbudpage_clear_zombie(zbudpage);
-		} else {
-			BUG_ON(list_empty(&unbud[chunks].list));
-			list_del_init(&zbudpage->budlist);
-			unbud[chunks].count--;
-		}
-		list_del_init(&zbudpage->lru);
-		spin_unlock(lists_lock);
-		if (eph)
-			zbud_eph_unbuddied_count--;
-		else
-			zbud_pers_unbuddied_count--;
-		page = zbud_unuse_zbudpage(zbudpage, eph);
-	} else { /* was buddied: move remaining buddy to unbuddied list */
-		chunks = zbud_size_to_chunks(other_bud_size) ;
-		if (!zbudpage_is_zombie(zbudpage)) {
-			list_del_init(&zbudpage->budlist);
-			list_add_tail(&zbudpage->budlist, &unbud[chunks].list);
-			unbud[chunks].count++;
-		}
-		if (eph) {
-			zbud_eph_buddied_count--;
-			zbud_eph_unbuddied_count++;
-		} else {
-			zbud_pers_unbuddied_count++;
-			zbud_pers_buddied_count--;
-		}
-		/* don't mess with lru, no need to move it */
-		zbudpage_spin_unlock(zbudpage);
-		spin_unlock(lists_lock);
-	}
-out:
-	return page;
-}
-
-/*
- * Given a tmem handle, and a kmapped pointer to compressed data of
- * the given size, try to find an unbuddied zbudpage in which to
- * create a zbud. If found, put it there, mark the zbudpage unevictable,
- * and return a zbudref to it.  Else return NULL.
- */
-struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph,
-				void *cdata, unsigned size)
-{
-	struct zbudpage *zbudpage = NULL, *zbudpage2;
-	unsigned long budnum = 0UL;
-	unsigned nchunks;
-	int i, found_good_buddy = 0;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-	struct zbud_unbuddied *unbud =
-		eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
-
-	size += sizeof(struct tmem_handle);
-	nchunks = zbud_size_to_chunks(size);
-	for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) {
-		spin_lock(lists_lock);
-		if (!list_empty(&unbud[i].list)) {
-			list_for_each_entry_safe(zbudpage, zbudpage2,
-				    &unbud[i].list, budlist) {
-				if (zbudpage_spin_trylock(zbudpage)) {
-					found_good_buddy = i;
-					goto found_unbuddied;
-				}
-			}
-		}
-		spin_unlock(lists_lock);
-	}
-	zbudpage = NULL;
-	goto out;
-
-found_unbuddied:
-	BUG_ON(!zbudpage_is_locked(zbudpage));
-	BUG_ON(!((zbudpage->zbud0_size == 0) ^ (zbudpage->zbud1_size == 0)));
-	if (zbudpage->zbud0_size == 0)
-		budnum = 0UL;
-	else if (zbudpage->zbud1_size == 0)
-		budnum = 1UL;
-	list_del_init(&zbudpage->budlist);
-	if (eph) {
-		list_add_tail(&zbudpage->budlist, &zbud_eph_buddied_list);
-		unbud[found_good_buddy].count--;
-		zbud_eph_unbuddied_count--;
-		zbud_eph_buddied_count++;
-		/* "promote" raw zbudpage to most-recently-used */
-		list_del_init(&zbudpage->lru);
-		list_add_tail(&zbudpage->lru, &zbud_eph_lru_list);
-	} else {
-		list_add_tail(&zbudpage->budlist, &zbud_pers_buddied_list);
-		unbud[found_good_buddy].count--;
-		zbud_pers_unbuddied_count--;
-		zbud_pers_buddied_count++;
-		/* "promote" raw zbudpage to most-recently-used */
-		list_del_init(&zbudpage->lru);
-		list_add_tail(&zbudpage->lru, &zbud_pers_lru_list);
-	}
-	zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size);
-	zbudpage->unevictable++;
-	BUG_ON(zbudpage->unevictable == 3);
-	zbudpage_spin_unlock(zbudpage);
-	spin_unlock(lists_lock);
-out:
-	return zbudpage_to_zbudref(zbudpage, budnum);
-
-}
-
-/*
- * Given a tmem handle, and a kmapped pointer to compressed data of
- * the given size, and a newly allocated struct page, create an unevictable
- * zbud in that new page and return a zbudref to it.
- */
-struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph,
-					void *cdata, unsigned size,
-					struct page *newpage)
-{
-	struct zbudpage *zbudpage;
-	unsigned long budnum = 0;
-	unsigned nchunks;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-	struct zbud_unbuddied *unbud =
-		eph ? zbud_eph_unbuddied : zbud_pers_unbuddied;
-
-#if 0
-	/* this may be worth it later to support decompress-in-place? */
-	static unsigned long counter;
-	budnum = counter++ & 1;	/* alternate using zbud0 and zbud1 */
-#endif
-
-	if (size  > zbud_max_buddy_size())
-		return NULL;
-	if (newpage == NULL)
-		return NULL;
-
-	size += sizeof(struct tmem_handle);
-	nchunks = zbud_size_to_chunks(size) ;
-	spin_lock(lists_lock);
-	zbudpage = zbud_init_zbudpage(newpage, eph);
-	zbudpage_spin_lock(zbudpage);
-	list_add_tail(&zbudpage->budlist, &unbud[nchunks].list);
-	if (eph) {
-		list_add_tail(&zbudpage->lru, &zbud_eph_lru_list);
-		zbud_eph_unbuddied_count++;
-	} else {
-		list_add_tail(&zbudpage->lru, &zbud_pers_lru_list);
-		zbud_pers_unbuddied_count++;
-	}
-	unbud[nchunks].count++;
-	zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size);
-	zbudpage->unevictable++;
-	BUG_ON(zbudpage->unevictable == 3);
-	zbudpage_spin_unlock(zbudpage);
-	spin_unlock(lists_lock);
-	return zbudpage_to_zbudref(zbudpage, budnum);
-}
-
-/*
- * Finish creation of a zbud by, assuming another zbud isn't being created
- * in parallel, marking it evictable.
- */
-void zbud_create_finish(struct zbudref *zref, bool eph)
-{
-	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
-	spin_lock(lists_lock);
-	zbudpage_spin_lock(zbudpage);
-	BUG_ON(zbudpage_is_dying(zbudpage));
-	zbudpage->unevictable--;
-	BUG_ON((int)zbudpage->unevictable < 0);
-	zbudpage_spin_unlock(zbudpage);
-	spin_unlock(lists_lock);
-}
-
-/*
- * Given a zbudref and a struct page, decompress the data from
- * the zbud into the physical page represented by the struct page
- * by upcalling to zcache_decompress
- */
-int zbud_decompress(struct page *data_page, struct zbudref *zref, bool eph,
-			void (*decompress)(char *, unsigned int, char *))
-{
-	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
-	unsigned long budnum = zbudref_budnum(zref);
-	void *zbpg;
-	char *to_va, *from_va;
-	unsigned size;
-	int ret = -1;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
-	spin_lock(lists_lock);
-	zbudpage_spin_lock(zbudpage);
-	if (zbudpage_is_dying(zbudpage)) {
-		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
-		goto out;
-	}
-	zbpg = kmap_zbudpage_atomic(zbudpage);
-	to_va = kmap_atomic(data_page);
-	if (budnum == 0)
-		size = zbudpage->zbud0_size;
-	else
-		size = zbudpage->zbud1_size;
-	BUG_ON(size == 0 || size > zbud_max_size());
-	from_va = zbud_data(zbpg, budnum, size);
-	from_va += sizeof(struct tmem_handle);
-	size -= sizeof(struct tmem_handle);
-	decompress(from_va, size, to_va);
-	kunmap_atomic(to_va);
-	kunmap_zbudpage_atomic(zbpg);
-	ret = 0;
-out:
-	zbudpage_spin_unlock(zbudpage);
-	spin_unlock(lists_lock);
-	return ret;
-}
-
-/*
- * Given a zbudref and a kernel pointer, copy the data from
- * the zbud to the kernel pointer.
- */
-int zbud_copy_from_zbud(char *to_va, struct zbudref *zref,
-				size_t *sizep, bool eph)
-{
-	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
-	unsigned long budnum = zbudref_budnum(zref);
-	void *zbpg;
-	char *from_va;
-	unsigned size;
-	int ret = -1;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
-	spin_lock(lists_lock);
-	zbudpage_spin_lock(zbudpage);
-	if (zbudpage_is_dying(zbudpage)) {
-		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
-		goto out;
-	}
-	zbpg = kmap_zbudpage_atomic(zbudpage);
-	if (budnum == 0)
-		size = zbudpage->zbud0_size;
-	else
-		size = zbudpage->zbud1_size;
-	BUG_ON(size == 0 || size > zbud_max_size());
-	from_va = zbud_data(zbpg, budnum, size);
-	from_va += sizeof(struct tmem_handle);
-	size -= sizeof(struct tmem_handle);
-	*sizep = size;
-	memcpy(to_va, from_va, size);
-
-	kunmap_zbudpage_atomic(zbpg);
-	ret = 0;
-out:
-	zbudpage_spin_unlock(zbudpage);
-	spin_unlock(lists_lock);
-	return ret;
-}
-
-/*
- * Given a zbudref and a kernel pointer, copy the data from
- * the kernel pointer to the zbud.
- */
-int zbud_copy_to_zbud(struct zbudref *zref, char *from_va, bool eph)
-{
-	struct zbudpage *zbudpage = zbudref_to_zbudpage(zref);
-	unsigned long budnum = zbudref_budnum(zref);
-	void *zbpg;
-	char *to_va;
-	unsigned size;
-	int ret = -1;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-
-	spin_lock(lists_lock);
-	zbudpage_spin_lock(zbudpage);
-	if (zbudpage_is_dying(zbudpage)) {
-		/* ignore dying zbudpage... see zbud_evict_pageframe_lru() */
-		goto out;
-	}
-	zbpg = kmap_zbudpage_atomic(zbudpage);
-	if (budnum == 0)
-		size = zbudpage->zbud0_size;
-	else
-		size = zbudpage->zbud1_size;
-	BUG_ON(size == 0 || size > zbud_max_size());
-	to_va = zbud_data(zbpg, budnum, size);
-	to_va += sizeof(struct tmem_handle);
-	size -= sizeof(struct tmem_handle);
-	memcpy(to_va, from_va, size);
-
-	kunmap_zbudpage_atomic(zbpg);
-	ret = 0;
-out:
-	zbudpage_spin_unlock(zbudpage);
-	spin_unlock(lists_lock);
-	return ret;
-}
-
-/*
- * Choose an ephemeral LRU zbudpage that is evictable (not locked), ensure
- * there are no references to it remaining, and return the now unused
- * (and re-init'ed) struct page and the total amount of compressed
- * data that was evicted.
- */
-struct page *zbud_evict_pageframe_lru(unsigned int *zsize, unsigned int *zpages)
-{
-	struct zbudpage *zbudpage = NULL, *zbudpage2;
-	struct zbud_unbuddied *unbud = zbud_eph_unbuddied;
-	struct page *page = NULL;
-	bool irqs_disabled = irqs_disabled();
-
-	/*
-	 * Since this can be called indirectly from cleancache_put, which
-	 * has interrupts disabled, as well as frontswap_put, which does not,
-	 * we need to be able to handle both cases, even though it is ugly.
-	 */
-	if (irqs_disabled)
-		spin_lock(&zbud_eph_lists_lock);
-	else
-		spin_lock_bh(&zbud_eph_lists_lock);
-	*zsize = 0;
-	if (list_empty(&zbud_eph_lru_list))
-		goto unlock_out;
-	list_for_each_entry_safe(zbudpage, zbudpage2, &zbud_eph_lru_list, lru) {
-		/* skip a locked zbudpage */
-		if (unlikely(!zbudpage_spin_trylock(zbudpage)))
-			continue;
-		/* skip an unevictable zbudpage */
-		if (unlikely(zbudpage->unevictable != 0)) {
-			zbudpage_spin_unlock(zbudpage);
-			continue;
-		}
-		/* got a locked evictable page */
-		goto evict_page;
-
-	}
-unlock_out:
-	/* no unlocked evictable pages, give up */
-	if (irqs_disabled)
-		spin_unlock(&zbud_eph_lists_lock);
-	else
-		spin_unlock_bh(&zbud_eph_lists_lock);
-	goto out;
-
-evict_page:
-	list_del_init(&zbudpage->budlist);
-	list_del_init(&zbudpage->lru);
-	zbudpage_set_dying(zbudpage);
-	/*
-	 * the zbudpage is now "dying" and attempts to read, write,
-	 * or delete data from it will be ignored
-	 */
-	if (zbudpage->zbud0_size != 0 && zbudpage->zbud1_size !=  0) {
-		*zsize = zbudpage->zbud0_size + zbudpage->zbud1_size -
-				(2 * sizeof(struct tmem_handle));
-		*zpages = 2;
-	} else if (zbudpage->zbud0_size != 0) {
-		unbud[zbud_size_to_chunks(zbudpage->zbud0_size)].count--;
-		*zsize = zbudpage->zbud0_size - sizeof(struct tmem_handle);
-		*zpages = 1;
-	} else if (zbudpage->zbud1_size != 0) {
-		unbud[zbud_size_to_chunks(zbudpage->zbud1_size)].count--;
-		*zsize = zbudpage->zbud1_size - sizeof(struct tmem_handle);
-		*zpages = 1;
-	} else {
-		BUG();
-	}
-	spin_unlock(&zbud_eph_lists_lock);
-	zbud_eph_evicted_pageframes++;
-	if (*zpages == 1)
-		zbud_eph_unbuddied_count--;
-	else
-		zbud_eph_buddied_count--;
-	zbud_evict_tmem(zbudpage);
-	zbudpage_spin_lock(zbudpage);
-	zbudpage_clear_dying(zbudpage);
-	page = zbud_unuse_zbudpage(zbudpage, true);
-	if (!irqs_disabled)
-		local_bh_enable();
-out:
-	return page;
-}
-
-/*
- * Choose a persistent LRU zbudpage that is evictable (not locked), zombify it,
- * read the tmem_handle(s) out of it into the passed array, and return the
- * number of zbuds.  Caller must perform necessary tmem functions and,
- * indirectly, zbud functions to fetch any valid data and cause the
- * now-zombified zbudpage to eventually be freed.  We track the zombified
- * zbudpage count so it is possible to observe if there is a leak.
- FIXME: describe (ramster) case where data pointers are passed in for memcpy
- */
-unsigned int zbud_make_zombie_lru(struct tmem_handle *th, unsigned char **data,
-					unsigned int *zsize, bool eph)
-{
-	struct zbudpage *zbudpage = NULL, *zbudpag2;
-	struct tmem_handle *thfrom;
-	char *from_va;
-	void *zbpg;
-	unsigned size;
-	int ret = 0, i;
-	spinlock_t *lists_lock =
-		eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock;
-	struct list_head *lru_list =
-		eph ? &zbud_eph_lru_list : &zbud_pers_lru_list;
-
-	spin_lock_bh(lists_lock);
-	if (list_empty(lru_list))
-		goto out;
-	list_for_each_entry_safe(zbudpage, zbudpag2, lru_list, lru) {
-		/* skip a locked zbudpage */
-		if (unlikely(!zbudpage_spin_trylock(zbudpage)))
-			continue;
-		/* skip an unevictable zbudpage */
-		if (unlikely(zbudpage->unevictable != 0)) {
-			zbudpage_spin_unlock(zbudpage);
-			continue;
-		}
-		/* got a locked evictable page */
-		goto zombify_page;
-	}
-	/* no unlocked evictable pages, give up */
-	goto out;
-
-zombify_page:
-	/* got an unlocked evictable page, zombify it */
-	list_del_init(&zbudpage->budlist);
-	zbudpage_set_zombie(zbudpage);
-	/* FIXME what accounting do I need to do here? */
-	list_del_init(&zbudpage->lru);
-	if (eph) {
-		list_add_tail(&zbudpage->lru, &zbud_eph_zombie_list);
-		zbud_eph_zombie_count =
-				atomic_inc_return(&zbud_eph_zombie_atomic);
-	} else {
-		list_add_tail(&zbudpage->lru, &zbud_pers_zombie_list);
-		zbud_pers_zombie_count =
-				atomic_inc_return(&zbud_pers_zombie_atomic);
-	}
-	/* FIXME what accounting do I need to do here? */
-	zbpg = kmap_zbudpage_atomic(zbudpage);
-	for (i = 0; i < 2; i++) {
-		size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size;
-		if (size) {
-			from_va = zbud_data(zbpg, i, size);
-			thfrom = (struct tmem_handle *)from_va;
-			from_va += sizeof(struct tmem_handle);
-			size -= sizeof(struct tmem_handle);
-			if (th != NULL)
-				th[ret] = *thfrom;
-			if (data != NULL)
-				memcpy(data[ret], from_va, size);
-			if (zsize != NULL)
-				*zsize++ = size;
-			ret++;
-		}
-	}
-	kunmap_zbudpage_atomic(zbpg);
-	zbudpage_spin_unlock(zbudpage);
-out:
-	spin_unlock_bh(lists_lock);
-	return ret;
-}
-
-void zbud_init(void)
-{
-	int i;
-
-	zbud_debugfs_init();
-	BUG_ON((sizeof(struct tmem_handle) * 2 > CHUNK_SIZE));
-	BUG_ON(sizeof(struct zbudpage) > sizeof(struct page));
-	for (i = 0; i < NCHUNKS; i++) {
-		INIT_LIST_HEAD(&zbud_eph_unbuddied[i].list);
-		INIT_LIST_HEAD(&zbud_pers_unbuddied[i].list);
-	}
-}
diff --git a/drivers/staging/zcache/zbud.h b/drivers/staging/zcache/zbud.h
deleted file mode 100644
index 891e8a7..0000000
--- a/drivers/staging/zcache/zbud.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * zbud.h
- *
- * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp.
- *
- */
-
-#ifndef _ZBUD_H_
-#define _ZBUD_H_
-
-#include "tmem.h"
-
-struct zbudref;
-
-extern unsigned int zbud_max_buddy_size(void);
-extern struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph,
-						void *cdata, unsigned size);
-extern struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph,
-						void *cdata, unsigned size,
-						struct page *newpage);
-extern void zbud_create_finish(struct zbudref *, bool);
-extern int zbud_decompress(struct page *, struct zbudref *, bool,
-				void (*func)(char *, unsigned int, char *));
-extern int zbud_copy_from_zbud(char *, struct zbudref *, size_t *, bool);
-extern int zbud_copy_to_zbud(struct zbudref *, char *, bool);
-extern struct page *zbud_free_and_delist(struct zbudref *, bool eph,
-						unsigned int *, unsigned int *);
-extern struct page *zbud_evict_pageframe_lru(unsigned int *, unsigned int *);
-extern unsigned int zbud_make_zombie_lru(struct tmem_handle *, unsigned char **,
-						unsigned int *, bool);
-extern void zbud_init(void);
-
-#endif /* _ZBUD_H_ */
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
deleted file mode 100644
index 81972fa..0000000
--- a/drivers/staging/zcache/zcache-main.c
+++ /dev/null
@@ -1,1943 +0,0 @@
-/*
- * 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
- * ("tmem") and, thus indirectly, for cleancache and frontswap.  Zcache uses
- * lzo1x compression to improve density and an embedded allocator called
- * "zbud" which "buddies" two compressed pages semi-optimally in each physical
- * pageframe.  Zbud is integrally tied into tmem to allow pageframes to
- * be "reclaimed" efficiently.
- */
-
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/highmem.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/atomic.h>
-#include <linux/math64.h>
-#include <linux/crypto.h>
-#include <linux/swap.h>
-#include <linux/swapops.h>
-#include <linux/pagemap.h>
-#include <linux/writeback.h>
-
-#include <linux/cleancache.h>
-#include <linux/frontswap.h>
-#include "tmem.h"
-#include "zcache.h"
-#include "zbud.h"
-#include "ramster.h"
-#include "debug.h"
-#ifdef CONFIG_RAMSTER
-static bool ramster_enabled __read_mostly;
-static int disable_frontswap_selfshrink;
-#else
-#define ramster_enabled false
-#define disable_frontswap_selfshrink 0
-#endif
-
-#ifndef __PG_WAS_ACTIVE
-static inline bool PageWasActive(struct page *page)
-{
-	return true;
-}
-
-static inline void SetPageWasActive(struct page *page)
-{
-}
-#endif
-
-#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
-static bool frontswap_has_exclusive_gets __read_mostly = true;
-#else
-static bool frontswap_has_exclusive_gets __read_mostly;
-static inline void frontswap_tmem_exclusive_gets(bool b)
-{
-}
-#endif
-
-/*
- * mark pampd to special value in order that later
- * retrieve will identify zero-filled pages
- */
-#define ZERO_FILLED 0x2
-
-/* enable (or fix code) when Seth's patches are accepted upstream */
-#define zcache_writeback_enabled 0
-
-static bool zcache_enabled __read_mostly;
-static bool disable_cleancache __read_mostly;
-static bool disable_frontswap __read_mostly;
-static bool disable_frontswap_ignore_nonactive __read_mostly;
-static bool disable_cleancache_ignore_nonactive __read_mostly;
-static char *namestr __read_mostly = "zcache";
-
-#define ZCACHE_GFP_MASK \
-	(__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
-
-/* crypto API for zcache  */
-#ifdef CONFIG_ZCACHE_MODULE
-static char *zcache_comp_name = "lzo";
-#else
-#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME
-static char zcache_comp_name[ZCACHE_COMP_NAME_SZ] __read_mostly;
-#endif
-static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms __read_mostly;
-
-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 = -1;
-
-	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;
-	default:
-		ret = -EINVAL;
-	}
-	put_cpu();
-	return ret;
-}
-
-/*
- * policy parameters
- */
-
-/*
- * byte count defining poor compression; pages with greater zsize will be
- * rejected
- */
-static unsigned int zbud_max_zsize __read_mostly = (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 zbud_max_mean_zsize __read_mostly = (PAGE_SIZE / 8) * 5;
-
-/*
- * 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 DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
-
-/* Used by debug.c */
-ssize_t zcache_pers_zpages;
-u64 zcache_pers_zbytes;
-ssize_t zcache_eph_pageframes;
-ssize_t zcache_pers_pageframes;
-
-/* Used by this code. */
-ssize_t zcache_last_active_file_pageframes;
-ssize_t zcache_last_inactive_file_pageframes;
-ssize_t zcache_last_active_anon_pageframes;
-ssize_t zcache_last_inactive_anon_pageframes;
-#ifdef CONFIG_ZCACHE_WRITEBACK
-ssize_t zcache_writtenback_pages;
-ssize_t zcache_outstanding_writeback_pages;
-#endif
-/*
- * zcache core code starts here
- */
-
-static struct zcache_client zcache_host;
-static struct zcache_client zcache_clients[MAX_CLIENTS];
-
-static inline bool is_local_client(struct zcache_client *cli)
-{
-	return cli == &zcache_host;
-}
-
-static struct zcache_client *zcache_get_client_by_id(uint16_t cli_id)
-{
-	struct zcache_client *cli = &zcache_host;
-
-	if (cli_id != LOCAL_CLIENT) {
-		if (cli_id >= MAX_CLIENTS)
-			goto out;
-		cli = &zcache_clients[cli_id];
-	}
-out:
-	return cli;
-}
-
-/*
- * 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.
- */
-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;
-
-	cli = zcache_get_client_by_id(cli_id);
-	if (cli == NULL)
-		goto out;
-	if (!is_local_client(cli))
-		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;
-}
-
-void zcache_put_pool(struct tmem_pool *pool)
-{
-	struct zcache_client *cli = NULL;
-
-	if (pool == NULL)
-		BUG();
-	cli = pool->client;
-	atomic_dec(&pool->refcount);
-	if (!is_local_client(cli))
-		atomic_dec(&cli->refcount);
-}
-
-int zcache_new_client(uint16_t cli_id)
-{
-	struct zcache_client *cli;
-	int ret = -1;
-
-	cli = zcache_get_client_by_id(cli_id);
-	if (cli == NULL)
-		goto out;
-	if (cli->allocated)
-		goto out;
-	cli->allocated = 1;
-	ret = 0;
-out:
-	return ret;
-}
-
-/*
- * zcache implementation for tmem host ops
- */
-
-static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
-{
-	struct tmem_objnode *objnode = NULL;
-	struct zcache_preload *kp;
-	int i;
-
-	kp = &__get_cpu_var(zcache_preloads);
-	for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
-		objnode = kp->objnodes[i];
-		if (objnode != NULL) {
-			kp->objnodes[i] = NULL;
-			break;
-		}
-	}
-	BUG_ON(objnode == NULL);
-	inc_zcache_objnode_count();
-	return objnode;
-}
-
-static void zcache_objnode_free(struct tmem_objnode *objnode,
-					struct tmem_pool *pool)
-{
-	dec_zcache_objnode_count();
-	kmem_cache_free(zcache_objnode_cache, objnode);
-}
-
-static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
-{
-	struct tmem_obj *obj = NULL;
-	struct zcache_preload *kp;
-
-	kp = &__get_cpu_var(zcache_preloads);
-	obj = kp->obj;
-	BUG_ON(obj == NULL);
-	kp->obj = NULL;
-	inc_zcache_obj_count();
-	return obj;
-}
-
-static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
-{
-	dec_zcache_obj_count();
-	kmem_cache_free(zcache_obj_cache, obj);
-}
-
-/*
- * Compressing zero-filled pages will waste memory and introduce
- * serious fragmentation, skip it to avoid overhead.
- */
-static bool page_is_zero_filled(struct page *p)
-{
-	unsigned int pos;
-	char *page;
-
-	page = kmap_atomic(p);
-	for (pos = 0; pos < PAGE_SIZE / sizeof(*page); pos++) {
-		if (page[pos]) {
-			kunmap_atomic(page);
-			return false;
-		}
-	}
-	kunmap_atomic(page);
-
-	return true;
-}
-
-static void handle_zero_filled_page(void *p)
-{
-	void *user_mem;
-	struct page *page = (struct page *)p;
-
-	user_mem = kmap_atomic(page);
-	memset(user_mem, 0, PAGE_SIZE);
-	kunmap_atomic(user_mem);
-
-	flush_dcache_page(page);
-}
-
-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,
-};
-
-static struct page *zcache_alloc_page(void)
-{
-	struct page *page = alloc_page(ZCACHE_GFP_MASK);
-
-	if (page != NULL)
-		inc_zcache_pageframes_alloced();
-	return page;
-}
-
-static void zcache_free_page(struct page *page)
-{
-	long curr_pageframes;
-	static long max_pageframes, min_pageframes;
-
-	if (page == NULL)
-		BUG();
-	__free_page(page);
-	inc_zcache_pageframes_freed();
-	curr_pageframes = curr_pageframes_count();
-	if (curr_pageframes > max_pageframes)
-		max_pageframes = curr_pageframes;
-	if (curr_pageframes < min_pageframes)
-		min_pageframes = curr_pageframes;
-#ifdef CONFIG_ZCACHE_DEBUG
-	if (curr_pageframes > 2L || curr_pageframes < -2L) {
-		/* pr_info here */
-	}
-#endif
-}
-
-/*
- * zcache implementations for PAM page descriptor ops
- */
-
-/* forward reference */
-static void zcache_compress(struct page *from,
-				void **out_va, unsigned *out_len);
-
-static struct page *zcache_evict_eph_pageframe(void);
-
-static void *zcache_pampd_eph_create(char *data, size_t size, bool raw,
-					struct tmem_handle *th)
-{
-	void *pampd = NULL, *cdata = data;
-	unsigned clen = size;
-	bool zero_filled = false;
-	struct page *page = (struct page *)(data), *newpage;
-
-	if (page_is_zero_filled(page)) {
-		clen = 0;
-		zero_filled = true;
-		inc_zcache_zero_filled_pages();
-		goto got_pampd;
-	}
-
-	if (!raw) {
-		zcache_compress(page, &cdata, &clen);
-		if (clen > zbud_max_buddy_size()) {
-			inc_zcache_compress_poor();
-			goto out;
-		}
-	} else {
-		BUG_ON(clen > zbud_max_buddy_size());
-	}
-
-	/* look for space via an existing match first */
-	pampd = (void *)zbud_match_prep(th, true, cdata, clen);
-	if (pampd != NULL)
-		goto got_pampd;
-
-	/* no match, now we need to find (or free up) a full page */
-	newpage = zcache_alloc_page();
-	if (newpage != NULL)
-		goto create_in_new_page;
-
-	inc_zcache_failed_getfreepages();
-	/* can't allocate a page, evict an ephemeral page via LRU */
-	newpage = zcache_evict_eph_pageframe();
-	if (newpage == NULL) {
-		inc_zcache_eph_ate_tail_failed();
-		goto out;
-	}
-	inc_zcache_eph_ate_tail();
-
-create_in_new_page:
-	pampd = (void *)zbud_create_prep(th, true, cdata, clen, newpage);
-	BUG_ON(pampd == NULL);
-	inc_zcache_eph_pageframes();
-
-got_pampd:
-	inc_zcache_eph_zbytes(clen);
-	inc_zcache_eph_zpages();
-	if (ramster_enabled && raw && !zero_filled)
-		ramster_count_foreign_pages(true, 1);
-	if (zero_filled)
-		pampd = (void *)ZERO_FILLED;
-out:
-	return pampd;
-}
-
-static void *zcache_pampd_pers_create(char *data, size_t size, bool raw,
-					struct tmem_handle *th)
-{
-	void *pampd = NULL, *cdata = data;
-	unsigned clen = size;
-	bool zero_filled = false;
-	struct page *page = (struct page *)(data), *newpage;
-	unsigned long zbud_mean_zsize;
-	unsigned long curr_pers_zpages, total_zsize;
-
-	if (data == NULL) {
-		BUG_ON(!ramster_enabled);
-		goto create_pampd;
-	}
-
-	if (page_is_zero_filled(page)) {
-		clen = 0;
-		zero_filled = true;
-		inc_zcache_zero_filled_pages();
-		goto got_pampd;
-	}
-
-	curr_pers_zpages = zcache_pers_zpages;
-/* FIXME CONFIG_RAMSTER... subtract atomic remote_pers_pages here? */
-	if (!raw)
-		zcache_compress(page, &cdata, &clen);
-	/* reject if compression is too poor */
-	if (clen > zbud_max_zsize) {
-		inc_zcache_compress_poor();
-		goto out;
-	}
-	/* reject if mean compression is too poor */
-	if ((clen > zbud_max_mean_zsize) && (curr_pers_zpages > 0)) {
-		total_zsize = zcache_pers_zbytes;
-		if ((long)total_zsize < 0)
-			total_zsize = 0;
-		zbud_mean_zsize = div_u64(total_zsize,
-					curr_pers_zpages);
-		if (zbud_mean_zsize > zbud_max_mean_zsize) {
-			inc_zcache_mean_compress_poor();
-			goto out;
-		}
-	}
-
-create_pampd:
-	/* look for space via an existing match first */
-	pampd = (void *)zbud_match_prep(th, false, cdata, clen);
-	if (pampd != NULL)
-		goto got_pampd;
-
-	/* no match, now we need to find (or free up) a full page */
-	newpage = zcache_alloc_page();
-	if (newpage != NULL)
-		goto create_in_new_page;
-	/*
-	 * FIXME do the following only if eph is oversized?
-	 * if (zcache_eph_pageframes >
-	 * (global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE) +
-	 * global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE)))
-	 */
-	inc_zcache_failed_getfreepages();
-	/* can't allocate a page, evict an ephemeral page via LRU */
-	newpage = zcache_evict_eph_pageframe();
-	if (newpage == NULL) {
-		inc_zcache_pers_ate_eph_failed();
-		goto out;
-	}
-	inc_zcache_pers_ate_eph();
-
-create_in_new_page:
-	pampd = (void *)zbud_create_prep(th, false, cdata, clen, newpage);
-	BUG_ON(pampd == NULL);
-	inc_zcache_pers_pageframes();
-
-got_pampd:
-	inc_zcache_pers_zpages();
-	inc_zcache_pers_zbytes(clen);
-	if (ramster_enabled && raw && !zero_filled)
-		ramster_count_foreign_pages(false, 1);
-	if (zero_filled)
-		pampd = (void *)ZERO_FILLED;
-out:
-	return pampd;
-}
-
-/*
- * This is called directly from zcache_put_page to pre-allocate space
- * to store a zpage.
- */
-void *zcache_pampd_create(char *data, unsigned int size, bool raw,
-					int eph, struct tmem_handle *th)
-{
-	void *pampd = NULL;
-	struct zcache_preload *kp;
-	struct tmem_objnode *objnode;
-	struct tmem_obj *obj;
-	int i;
-
-	BUG_ON(!irqs_disabled());
-	/* pre-allocate per-cpu metadata */
-	BUG_ON(zcache_objnode_cache == NULL);
-	BUG_ON(zcache_obj_cache == NULL);
-	kp = &__get_cpu_var(zcache_preloads);
-	for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
-		objnode = kp->objnodes[i];
-		if (objnode == NULL) {
-			objnode = kmem_cache_alloc(zcache_objnode_cache,
-							ZCACHE_GFP_MASK);
-			if (unlikely(objnode == NULL)) {
-				inc_zcache_failed_alloc();
-				goto out;
-			}
-			kp->objnodes[i] = objnode;
-		}
-	}
-	if (kp->obj == NULL) {
-		obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK);
-		kp->obj = obj;
-	}
-	if (unlikely(kp->obj == NULL)) {
-		inc_zcache_failed_alloc();
-		goto out;
-	}
-	/*
-	 * ok, have all the metadata pre-allocated, now do the data
-	 * but since how we allocate the data is dependent on ephemeral
-	 * or persistent, we split the call here to different sub-functions
-	 */
-	if (eph)
-		pampd = zcache_pampd_eph_create(data, size, raw, th);
-	else
-		pampd = zcache_pampd_pers_create(data, size, raw, th);
-out:
-	return pampd;
-}
-
-/*
- * This is a pamops called via tmem_put and is necessary to "finish"
- * a pampd creation.
- */
-void zcache_pampd_create_finish(void *pampd, bool eph)
-{
-	if (pampd != (void *)ZERO_FILLED)
-		zbud_create_finish((struct zbudref *)pampd, eph);
-}
-
-/*
- * This is passed as a function parameter to zbud_decompress so that
- * zbud need not be familiar with the details of crypto. It assumes that
- * the bytes from_va and to_va through from_va+size-1 and to_va+size-1 are
- * kmapped.  It must be successful, else there is a logic bug somewhere.
- */
-static void zcache_decompress(char *from_va, unsigned int size, char *to_va)
-{
-	int ret;
-	unsigned int outlen = PAGE_SIZE;
-
-	ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size,
-				to_va, &outlen);
-	BUG_ON(ret);
-	BUG_ON(outlen != PAGE_SIZE);
-}
-
-/*
- * Decompress from the kernel va to a pageframe
- */
-void zcache_decompress_to_page(char *from_va, unsigned int size,
-					struct page *to_page)
-{
-	char *to_va = kmap_atomic(to_page);
-	zcache_decompress(from_va, size, to_va);
-	kunmap_atomic(to_va);
-}
-
-/*
- * 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 *sizep, bool raw,
-					void *pampd, struct tmem_pool *pool,
-					struct tmem_oid *oid, uint32_t index)
-{
-	int ret;
-	bool eph = !is_persistent(pool);
-
-	BUG_ON(preemptible());
-	BUG_ON(eph);	/* fix later if shared pools get implemented */
-	BUG_ON(pampd_is_remote(pampd));
-
-	if (pampd == (void *)ZERO_FILLED) {
-		handle_zero_filled_page(data);
-		if (!raw)
-			*sizep = PAGE_SIZE;
-		return 0;
-	}
-
-	if (raw)
-		ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
-						sizep, eph);
-	else {
-		ret = zbud_decompress((struct page *)(data),
-					(struct zbudref *)pampd, false,
-					zcache_decompress);
-		*sizep = PAGE_SIZE;
-	}
-	return ret;
-}
-
-/*
- * fill the pageframe corresponding to the struct page with the data
- * from the passed pampd
- */
-static int zcache_pampd_get_data_and_free(char *data, size_t *sizep, bool raw,
-					void *pampd, struct tmem_pool *pool,
-					struct tmem_oid *oid, uint32_t index)
-{
-	int ret = 0;
-	bool eph = !is_persistent(pool), zero_filled = false;
-	struct page *page = NULL;
-	unsigned int zsize, zpages;
-
-	BUG_ON(preemptible());
-	BUG_ON(pampd_is_remote(pampd));
-
-	if (pampd == (void *)ZERO_FILLED) {
-		handle_zero_filled_page(data);
-		zero_filled = true;
-		zsize = 0;
-		zpages = 1;
-		if (!raw)
-			*sizep = PAGE_SIZE;
-		dec_zcache_zero_filled_pages();
-		goto zero_fill;
-	}
-
-	if (raw)
-		ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
-						sizep, eph);
-	else {
-		ret = zbud_decompress((struct page *)(data),
-					(struct zbudref *)pampd, eph,
-					zcache_decompress);
-		*sizep = PAGE_SIZE;
-	}
-	page = zbud_free_and_delist((struct zbudref *)pampd, eph,
-					&zsize, &zpages);
-zero_fill:
-	if (eph) {
-		if (page)
-			dec_zcache_eph_pageframes();
-		dec_zcache_eph_zpages(zpages);
-		dec_zcache_eph_zbytes(zsize);
-	} else {
-		if (page)
-			dec_zcache_pers_pageframes();
-		dec_zcache_pers_zpages(zpages);
-		dec_zcache_pers_zbytes(zsize);
-	}
-	if (!is_local_client(pool->client) && !zero_filled)
-		ramster_count_foreign_pages(eph, -1);
-	if (page && !zero_filled)
-		zcache_free_page(page);
-	return ret;
-}
-
-/*
- * 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 page *page = NULL;
-	unsigned int zsize, zpages;
-	bool zero_filled = false;
-
-	BUG_ON(preemptible());
-
-	if (pampd == (void *)ZERO_FILLED) {
-		zero_filled = true;
-		zsize = 0;
-		zpages = 1;
-		dec_zcache_zero_filled_pages();
-	}
-
-	if (pampd_is_remote(pampd) && !zero_filled) {
-		BUG_ON(!ramster_enabled);
-		pampd = ramster_pampd_free(pampd, pool, oid, index, acct);
-		if (pampd == NULL)
-			return;
-	}
-	if (is_ephemeral(pool)) {
-		if (!zero_filled)
-			page = zbud_free_and_delist((struct zbudref *)pampd,
-						true, &zsize, &zpages);
-		if (page)
-			dec_zcache_eph_pageframes();
-		dec_zcache_eph_zpages(zpages);
-		dec_zcache_eph_zbytes(zsize);
-		/* FIXME CONFIG_RAMSTER... check acct parameter? */
-	} else {
-		if (!zero_filled)
-			page = zbud_free_and_delist((struct zbudref *)pampd,
-						false, &zsize, &zpages);
-		if (page)
-			dec_zcache_pers_pageframes();
-		dec_zcache_pers_zpages(zpages);
-		dec_zcache_pers_zbytes(zsize);
-	}
-	if (!is_local_client(pool->client) && !zero_filled)
-		ramster_count_foreign_pages(is_ephemeral(pool), -1);
-	if (page && !zero_filled)
-		zcache_free_page(page);
-}
-
-static struct tmem_pamops zcache_pamops = {
-	.create_finish = zcache_pampd_create_finish,
-	.get_data = zcache_pampd_get_data,
-	.get_data_and_free = zcache_pampd_get_data_and_free,
-	.free = zcache_pampd_free,
-};
-
-/*
- * zcache compression/decompression and related per-cpu stuff
- */
-
-static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
-#define ZCACHE_DSTMEM_ORDER 1
-
-static void zcache_compress(struct page *from, void **out_va, unsigned *out_len)
-{
-	int ret;
-	unsigned char *dmem = __get_cpu_var(zcache_dstmem);
-	char *from_va;
-
-	BUG_ON(!irqs_disabled());
-	/* no buffer or no compressor so can't compress */
-	BUG_ON(dmem == NULL);
-	*out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER;
-	from_va = kmap_atomic(from);
-	mb();
-	ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem,
-				out_len);
-	BUG_ON(ret);
-	*out_va = dmem;
-	kunmap_atomic(from_va);
-}
-
-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 ret, i, 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("%s: can't allocate compressor xform\n",
-				namestr);
-			return ret;
-		}
-		per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
-			GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER);
-		if (ramster_enabled)
-			ramster_cpu_up(cpu);
-		break;
-	case CPU_DEAD:
-	case CPU_UP_CANCELED:
-		zcache_comp_cpu_down(cpu);
-		free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
-			ZCACHE_DSTMEM_ORDER);
-		per_cpu(zcache_dstmem, cpu) = NULL;
-		kp = &per_cpu(zcache_preloads, cpu);
-		for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) {
-			if (kp->objnodes[i])
-				kmem_cache_free(zcache_objnode_cache,
-						kp->objnodes[i]);
-		}
-		if (kp->obj) {
-			kmem_cache_free(zcache_obj_cache, kp->obj);
-			kp->obj = NULL;
-		}
-		if (ramster_enabled)
-			ramster_cpu_down(cpu);
-		break;
-	default:
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block zcache_cpu_notifier_block = {
-	.notifier_call = zcache_cpu_notifier
-};
-
-/*
- * The following code interacts with the zbud eviction and zbud
- * zombify code to access LRU pages
- */
-
-static struct page *zcache_evict_eph_pageframe(void)
-{
-	struct page *page;
-	unsigned int zsize = 0, zpages = 0;
-
-	page = zbud_evict_pageframe_lru(&zsize, &zpages);
-	if (page == NULL)
-		goto out;
-	dec_zcache_eph_zbytes(zsize);
-	dec_zcache_eph_zpages(zpages);
-	inc_zcache_evicted_eph_zpages(zpages);
-	dec_zcache_eph_pageframes();
-	inc_zcache_evicted_eph_pageframes();
-out:
-	return page;
-}
-
-#ifdef CONFIG_ZCACHE_WRITEBACK
-
-static atomic_t zcache_outstanding_writeback_pages_atomic = ATOMIC_INIT(0);
-
-static inline void inc_zcache_outstanding_writeback_pages(void)
-{
-	zcache_outstanding_writeback_pages =
-	    atomic_inc_return(&zcache_outstanding_writeback_pages_atomic);
-}
-static inline void dec_zcache_outstanding_writeback_pages(void)
-{
-	zcache_outstanding_writeback_pages =
-	  atomic_dec_return(&zcache_outstanding_writeback_pages_atomic);
-};
-static void unswiz(struct tmem_oid oid, u32 index,
-				unsigned *type, pgoff_t *offset);
-
-/*
- *  Choose an LRU persistent pageframe and attempt to write it back to
- *  the backing swap disk by calling frontswap_writeback on both zpages.
- *
- *  This is work-in-progress.
- */
-
-static void zcache_end_swap_write(struct bio *bio, int err)
-{
-	end_swap_bio_write(bio, err);
-	dec_zcache_outstanding_writeback_pages();
-	zcache_writtenback_pages++;
-}
-
-/*
- * zcache_get_swap_cache_page
- *
- * This is an adaption of read_swap_cache_async()
- *
- * If success, page is returned in retpage
- * Returns 0 if page was already in the swap cache, page is not locked
- * Returns 1 if the new page needs to be populated, page is locked
- */
-static int zcache_get_swap_cache_page(int type, pgoff_t offset,
-				struct page *new_page)
-{
-	struct page *found_page;
-	swp_entry_t entry = swp_entry(type, offset);
-	int err;
-
-	BUG_ON(new_page == NULL);
-	do {
-		/*
-		 * First check the swap cache.  Since this is normally
-		 * called after lookup_swap_cache() failed, re-calling
-		 * that would confuse statistics.
-		 */
-		found_page = find_get_page(&swapper_space, entry.val);
-		if (found_page)
-			return 0;
-
-		/*
-		 * call radix_tree_preload() while we can wait.
-		 */
-		err = radix_tree_preload(GFP_KERNEL);
-		if (err)
-			break;
-
-		/*
-		 * Swap entry may have been freed since our caller observed it.
-		 */
-		err = swapcache_prepare(entry);
-		if (err == -EEXIST) { /* seems racy */
-			radix_tree_preload_end();
-			continue;
-		}
-		if (err) { /* swp entry is obsolete ? */
-			radix_tree_preload_end();
-			break;
-		}
-
-		/* May fail (-ENOMEM) if radix-tree node allocation failed. */
-		__set_page_locked(new_page);
-		SetPageSwapBacked(new_page);
-		err = __add_to_swap_cache(new_page, entry);
-		if (likely(!err)) {
-			radix_tree_preload_end();
-			lru_cache_add_anon(new_page);
-			return 1;
-		}
-		radix_tree_preload_end();
-		ClearPageSwapBacked(new_page);
-		__clear_page_locked(new_page);
-		/*
-		 * add_to_swap_cache() doesn't return -EEXIST, so we can safely
-		 * clear SWAP_HAS_CACHE flag.
-		 */
-		swapcache_free(entry, NULL);
-		/* FIXME: is it possible to get here without err==-ENOMEM?
-		 * If not, we can dispense with the do loop, use goto retry */
-	} while (err != -ENOMEM);
-
-	return -ENOMEM;
-}
-
-/*
- * Given a frontswap zpage in zcache (identified by type/offset) and
- * an empty page, put the page into the swap cache, use frontswap
- * to get the page from zcache into the empty page, then give it
- * to the swap subsystem to send to disk (carefully avoiding the
- * possibility that frontswap might snatch it back).
- * Returns < 0 if error, 0 if successful, and 1 if successful but
- * the newpage passed in not needed and should be freed.
- */
-static int zcache_frontswap_writeback_zpage(int type, pgoff_t offset,
-					struct page *newpage)
-{
-	struct page *page = newpage;
-	int ret;
-	struct writeback_control wbc = {
-		.sync_mode = WB_SYNC_NONE,
-	};
-
-	ret = zcache_get_swap_cache_page(type, offset, page);
-	if (ret < 0)
-		return ret;
-	else if (ret == 0) {
-		/* more uptodate page is already in swapcache */
-		__frontswap_invalidate_page(type, offset);
-		return 1;
-	}
-
-	BUG_ON(!frontswap_has_exclusive_gets); /* load must also invalidate */
-	/* FIXME: how is it possible to get here when page is unlocked? */
-	__frontswap_load(page);
-	SetPageUptodate(page);  /* above does SetPageDirty, is that enough? */
-
-	/* start writeback */
-	SetPageReclaim(page);
-	/*
-	 * Return value is ignored here because it doesn't change anything
-	 * for us.  Page is returned unlocked.
-	 */
-	(void)__swap_writepage(page, &wbc, zcache_end_swap_write);
-	page_cache_release(page);
-	inc_zcache_outstanding_writeback_pages();
-
-	return 0;
-}
-
-/*
- * The following is still a magic number... we want to allow forward progress
- * for writeback because it clears out needed RAM when under pressure, but
- * we don't want to allow writeback to absorb and queue too many GFP_KERNEL
- * pages if the swap device is very slow.
- */
-#define ZCACHE_MAX_OUTSTANDING_WRITEBACK_PAGES 6400
-
-/*
- * Try to allocate two free pages, first using a non-aggressive alloc,
- * then by evicting zcache ephemeral (clean pagecache) pages, and last
- * by aggressive GFP_KERNEL alloc.  We allow zbud to choose a pageframe
- * consisting of 1-2 zbuds/zpages, then call the writeback_zpage helper
- * function above for each.
- */
-static int zcache_frontswap_writeback(void)
-{
-	struct tmem_handle th[2];
-	int ret = 0;
-	int nzbuds, writeback_ret;
-	unsigned type;
-	struct page *znewpage1 = NULL, *znewpage2 = NULL;
-	struct page *evictpage1 = NULL, *evictpage2 = NULL;
-	struct page *newpage1 = NULL, *newpage2 = NULL;
-	struct page *page1 = NULL, *page2 = NULL;
-	pgoff_t offset;
-
-	znewpage1 = alloc_page(ZCACHE_GFP_MASK);
-	znewpage2 = alloc_page(ZCACHE_GFP_MASK);
-	if (znewpage1 == NULL)
-		evictpage1 = zcache_evict_eph_pageframe();
-	if (znewpage2 == NULL)
-		evictpage2 = zcache_evict_eph_pageframe();
-
-	if ((evictpage1 == NULL || evictpage2 == NULL) &&
-	    atomic_read(&zcache_outstanding_writeback_pages_atomic) >
-				ZCACHE_MAX_OUTSTANDING_WRITEBACK_PAGES) {
-		goto free_and_out;
-	}
-	if (znewpage1 == NULL && evictpage1 == NULL)
-		newpage1 = alloc_page(GFP_KERNEL);
-	if (znewpage2 == NULL && evictpage2 == NULL)
-		newpage2 = alloc_page(GFP_KERNEL);
-	if (newpage1 == NULL || newpage2 == NULL)
-			goto free_and_out;
-
-	/* ok, we have two pageframes pre-allocated, get a pair of zbuds */
-	nzbuds = zbud_make_zombie_lru(&th[0], NULL, NULL, false);
-	if (nzbuds == 0) {
-		ret = -ENOENT;
-		goto free_and_out;
-	}
-
-	/* process the first zbud */
-	unswiz(th[0].oid, th[0].index, &type, &offset);
-	page1 = (znewpage1 != NULL) ? znewpage1 :
-			((newpage1 != NULL) ? newpage1 : evictpage1);
-	writeback_ret = zcache_frontswap_writeback_zpage(type, offset, page1);
-	if (writeback_ret < 0) {
-		ret = -ENOMEM;
-		goto free_and_out;
-	}
-	if (evictpage1 != NULL)
-		zcache_pageframes_freed =
-			atomic_inc_return(&zcache_pageframes_freed_atomic);
-	if (writeback_ret == 0) {
-		/* zcache_get_swap_cache_page will free, don't double free */
-		znewpage1 = NULL;
-		newpage1 = NULL;
-		evictpage1 = NULL;
-	}
-	if (nzbuds < 2)
-		goto free_and_out;
-
-	/* if there is a second zbud, process it */
-	unswiz(th[1].oid, th[1].index, &type, &offset);
-	page2 = (znewpage2 != NULL) ? znewpage2 :
-			((newpage2 != NULL) ? newpage2 : evictpage2);
-	writeback_ret = zcache_frontswap_writeback_zpage(type, offset, page2);
-	if (writeback_ret < 0) {
-		ret = -ENOMEM;
-		goto free_and_out;
-	}
-	if (evictpage2 != NULL)
-		zcache_pageframes_freed =
-			atomic_inc_return(&zcache_pageframes_freed_atomic);
-	if (writeback_ret == 0) {
-		znewpage2 = NULL;
-		newpage2 = NULL;
-		evictpage2 = NULL;
-	}
-
-free_and_out:
-	if (znewpage1 != NULL)
-		page_cache_release(znewpage1);
-	if (znewpage2 != NULL)
-		page_cache_release(znewpage2);
-	if (newpage1 != NULL)
-		page_cache_release(newpage1);
-	if (newpage2 != NULL)
-		page_cache_release(newpage2);
-	if (evictpage1 != NULL)
-		zcache_free_page(evictpage1);
-	if (evictpage2 != NULL)
-		zcache_free_page(evictpage2);
-	return ret;
-}
-#endif /* CONFIG_ZCACHE_WRITEBACK */
-
-/*
- * 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;
-
-/*
- * This zcache shrinker interface reduces the number of ephemeral pageframes
- * used by zcache to approximately the same as the total number of LRU_FILE
- * pageframes in use, and now also reduces the number of persistent pageframes
- * used by zcache to approximately the same as the total number of LRU_ANON
- * pageframes in use.  FIXME POLICY: Probably the writeback should only occur
- * if the eviction doesn't free enough pages.
- */
-static int shrink_zcache_memory(struct shrinker *shrink,
-				struct shrink_control *sc)
-{
-	static bool in_progress;
-	int ret = -1;
-	int nr = sc->nr_to_scan;
-	int nr_evict = 0;
-	int nr_writeback = 0;
-	struct page *page;
-	int  file_pageframes_inuse, anon_pageframes_inuse;
-
-	if (nr <= 0)
-		goto skip_evict;
-
-	/* don't allow more than one eviction thread at a time */
-	if (in_progress)
-		goto skip_evict;
-
-	in_progress = true;
-
-	/* we are going to ignore nr, and target a different value */
-	zcache_last_active_file_pageframes =
-		global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE);
-	zcache_last_inactive_file_pageframes =
-		global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
-	file_pageframes_inuse = zcache_last_active_file_pageframes +
-				zcache_last_inactive_file_pageframes;
-	if (zcache_eph_pageframes > file_pageframes_inuse)
-		nr_evict = zcache_eph_pageframes - file_pageframes_inuse;
-	else
-		nr_evict = 0;
-	while (nr_evict-- > 0) {
-		page = zcache_evict_eph_pageframe();
-		if (page == NULL)
-			break;
-		zcache_free_page(page);
-	}
-
-	zcache_last_active_anon_pageframes =
-		global_page_state(NR_LRU_BASE + LRU_ACTIVE_ANON);
-	zcache_last_inactive_anon_pageframes =
-		global_page_state(NR_LRU_BASE + LRU_INACTIVE_ANON);
-	anon_pageframes_inuse = zcache_last_active_anon_pageframes +
-				zcache_last_inactive_anon_pageframes;
-	if (zcache_pers_pageframes > anon_pageframes_inuse)
-		nr_writeback = zcache_pers_pageframes - anon_pageframes_inuse;
-	else
-		nr_writeback = 0;
-	while (nr_writeback-- > 0) {
-#ifdef CONFIG_ZCACHE_WRITEBACK
-		int writeback_ret;
-		writeback_ret = zcache_frontswap_writeback();
-		if (writeback_ret == -ENOMEM)
-#endif
-			break;
-	}
-	in_progress = false;
-
-skip_evict:
-	/* resample: has changed, but maybe not all the way yet */
-	zcache_last_active_file_pageframes =
-		global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE);
-	zcache_last_inactive_file_pageframes =
-		global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE);
-	ret = zcache_eph_pageframes - zcache_last_active_file_pageframes +
-		zcache_last_inactive_file_pageframes;
-	if (ret < 0)
-		ret = 0;
-	return ret;
-}
-
-static struct shrinker zcache_shrinker = {
-	.shrink = shrink_zcache_memory,
-	.seeks = DEFAULT_SEEKS,
-};
-
-/*
- * zcache shims between cleancache/frontswap ops and tmem
- */
-
-/* FIXME rename these core routines to zcache_tmemput etc? */
-int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
-				uint32_t index, void *page,
-				unsigned int size, bool raw, int ephemeral)
-{
-	struct tmem_pool *pool;
-	struct tmem_handle th;
-	int ret = -1;
-	void *pampd = NULL;
-
-	BUG_ON(!irqs_disabled());
-	pool = zcache_get_pool_by_id(cli_id, pool_id);
-	if (unlikely(pool == NULL))
-		goto out;
-	if (!zcache_freeze) {
-		ret = 0;
-		th.client_id = cli_id;
-		th.pool_id = pool_id;
-		th.oid = *oidp;
-		th.index = index;
-		pampd = zcache_pampd_create((char *)page, size, raw,
-				ephemeral, &th);
-		if (pampd == NULL) {
-			ret = -ENOMEM;
-			if (ephemeral)
-				inc_zcache_failed_eph_puts();
-			else
-				inc_zcache_failed_pers_puts();
-		} else {
-			if (ramster_enabled)
-				ramster_do_preload_flnode(pool);
-			ret = tmem_put(pool, oidp, index, 0, pampd);
-			if (ret < 0)
-				BUG();
-		}
-		zcache_put_pool(pool);
-	} else {
-		inc_zcache_put_to_flush();
-		if (ramster_enabled)
-			ramster_do_preload_flnode(pool);
-		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_page(int cli_id, int pool_id, struct tmem_oid *oidp,
-				uint32_t index, void *page,
-				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, (char *)(page),
-					sizep, raw, get_and_free);
-		zcache_put_pool(pool);
-	}
-	WARN_ONCE((!is_ephemeral(pool) && (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
-	return ret;
-}
-
-int zcache_flush_page(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);
-	inc_zcache_flush_total();
-	pool = zcache_get_pool_by_id(cli_id, pool_id);
-	if (ramster_enabled)
-		ramster_do_preload_flnode(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)
-		inc_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);
-	inc_zcache_flobj_total();
-	pool = zcache_get_pool_by_id(cli_id, pool_id);
-	if (ramster_enabled)
-		ramster_do_preload_flnode(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)
-		inc_zcache_flobj_found();
-	local_irq_restore(flags);
-	return ret;
-}
-
-static 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);
-	if (cli_id == LOCAL_CLIENT)
-		pr_info("%s: destroyed local pool id=%d\n", namestr, pool_id);
-	else
-		pr_info("%s: destroyed pool id=%d, client=%d\n",
-				namestr, pool_id, cli_id);
-out:
-	return ret;
-}
-
-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)
-		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("%s: pool creation failed: max exceeded\n", namestr);
-		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("%s: created %s local tmem pool, id=%d\n", namestr,
-			flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
-			poolid);
-	else
-		pr_info("%s: created %s tmem pool, id=%d, client=%d\n", namestr,
-			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(unsigned int cli_id, unsigned int pool_id, bool eph)
-{
-	struct tmem_pool *pool;
-	struct zcache_client *cli = NULL;
-	uint32_t flags = eph ? 0 : TMEM_POOL_PERSIST;
-	int ret = -1;
-
-	BUG_ON(!ramster_enabled);
-	if (cli_id == LOCAL_CLIENT)
-		goto out;
-	if (pool_id >= MAX_POOLS_PER_CLIENT)
-		goto out;
-	if (cli_id >= MAX_CLIENTS)
-		goto out;
-
-	cli = &zcache_clients[cli_id];
-	if ((eph && disable_cleancache) || (!eph && disable_frontswap)) {
-		pr_err("zcache_autocreate_pool: pool type disabled\n");
-		goto out;
-	}
-	if (!cli->allocated) {
-		if (zcache_new_client(cli_id)) {
-			pr_err("zcache_autocreate_pool: can't create client\n");
-			goto out;
-		}
-		cli = &zcache_clients[cli_id];
-	}
-	atomic_inc(&cli->refcount);
-	pool = cli->tmem_pools[pool_id];
-	if (pool != NULL) {
-		if (pool->persistent && eph) {
-			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)
-		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("%s: AUTOcreated %s tmem poolid=%d, for remote client=%d\n",
-		namestr, flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral",
-		pool_id, cli_id);
-	ret = 0;
-out:
-	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.
- */
-
-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;
-
-	if (!disable_cleancache_ignore_nonactive && !PageWasActive(page)) {
-		inc_zcache_eph_nonactive_puts_ignored();
-		return;
-	}
-	if (likely(ind == index))
-		(void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index,
-					page, PAGE_SIZE, false, 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;
-	size_t size;
-	int ret = -1;
-
-	if (likely(ind == index)) {
-		ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index,
-					page, &size, false, 0);
-		BUG_ON(ret >= 0 && size != PAGE_SIZE);
-		if (ret == 0)
-			SetPageWasActive(page);
-	}
-	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_page(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_client_destroy_pool(LOCAL_CLIENT, 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;
-}
-
-/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
-static int zcache_frontswap_poolid __read_mostly = -1;
-
-/*
- * Swizzling increases objects per swaptype, increasing tmem concurrency
- * for heavy swaploads.  Later, larger nr_cpus -> larger SWIZ_BITS
- * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from
- * frontswap_get_page(), but has side-effects. Hence using 8.
- */
-#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;
-}
-
-#ifdef CONFIG_ZCACHE_WRITEBACK
-static void unswiz(struct tmem_oid oid, u32 index,
-				unsigned *type, pgoff_t *offset)
-{
-	*type = (unsigned)(oid.oid[0] >> SWIZ_BITS);
-	*offset = (pgoff_t)((index << SWIZ_BITS) |
-			(oid.oid[0] & SWIZ_MASK));
-}
-#endif
-
-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;
-
-	BUG_ON(!PageLocked(page));
-	if (!disable_frontswap_ignore_nonactive && !PageWasActive(page)) {
-		inc_zcache_pers_nonactive_puts_ignored();
-		ret = -ERANGE;
-		goto out;
-	}
-	if (likely(ind64 == ind)) {
-		local_irq_save(flags);
-		ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid,
-					&oid, iswiz(ind),
-					page, PAGE_SIZE, false, 0);
-		local_irq_restore(flags);
-	}
-out:
-	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);
-	size_t size;
-	int ret = -1, get_and_free;
-
-	if (frontswap_has_exclusive_gets)
-		get_and_free = 1;
-	else
-		get_and_free = -1;
-	BUG_ON(!PageLocked(page));
-	if (likely(ind64 == ind)) {
-		ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid,
-					&oid, iswiz(ind),
-					page, &size, false, get_and_free);
-		BUG_ON(ret >= 0 && size != PAGE_SIZE);
-	}
-	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_page(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 = {
-	.store = zcache_frontswap_put_page,
-	.load = 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;
-}
-
-/*
- * zcache initialization
- * NOTE FOR NOW zcache or ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER
- * OR NOTHING HAPPENS!
- */
-
-#ifndef CONFIG_ZCACHE_MODULE
-static int __init enable_zcache(char *s)
-{
-	zcache_enabled = true;
-	return 1;
-}
-__setup("zcache", enable_zcache);
-
-static int __init enable_ramster(char *s)
-{
-	zcache_enabled = true;
-#ifdef CONFIG_RAMSTER
-	ramster_enabled = true;
-#endif
-	return 1;
-}
-__setup("ramster", enable_ramster);
-
-/* allow independent dynamic disabling of cleancache and frontswap */
-
-static int __init no_cleancache(char *s)
-{
-	disable_cleancache = true;
-	return 1;
-}
-
-__setup("nocleancache", no_cleancache);
-
-static int __init no_frontswap(char *s)
-{
-	disable_frontswap = true;
-	return 1;
-}
-
-__setup("nofrontswap", no_frontswap);
-
-static int __init no_frontswap_exclusive_gets(char *s)
-{
-	frontswap_has_exclusive_gets = false;
-	return 1;
-}
-
-__setup("nofrontswapexclusivegets", no_frontswap_exclusive_gets);
-
-static int __init no_frontswap_ignore_nonactive(char *s)
-{
-	disable_frontswap_ignore_nonactive = true;
-	return 1;
-}
-
-__setup("nofrontswapignorenonactive", no_frontswap_ignore_nonactive);
-
-static int __init no_cleancache_ignore_nonactive(char *s)
-{
-	disable_cleancache_ignore_nonactive = true;
-	return 1;
-}
-
-__setup("nocleancacheignorenonactive", no_cleancache_ignore_nonactive);
-
-static int __init enable_zcache_compressor(char *s)
-{
-	strlcpy(zcache_comp_name, s, sizeof(zcache_comp_name));
-	zcache_enabled = true;
-	return 1;
-}
-__setup("zcache=", enable_zcache_compressor);
-#endif
-
-
-static int zcache_comp_init(void)
-{
-	int ret = 0;
-
-	/* check crypto algorithm */
-#ifdef CONFIG_ZCACHE_MODULE
-	ret = crypto_has_comp(zcache_comp_name, 0, 0);
-	if (!ret) {
-		ret = -1;
-		goto out;
-	}
-#else
-	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);
-			ret = 1;
-			goto out;
-		}
-	}
-	if (!ret)
-		strcpy(zcache_comp_name, "lzo");
-	ret = crypto_has_comp(zcache_comp_name, 0, 0);
-	if (!ret) {
-		ret = 1;
-		goto out;
-	}
-#endif
-	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 zcache_init(void)
-{
-	int ret = 0;
-
-#ifdef CONFIG_ZCACHE_MODULE
-	zcache_enabled = 1;
-#endif
-	if (ramster_enabled) {
-		namestr = "ramster";
-		ramster_register_pamops(&zcache_pamops);
-	}
-	zcache_debugfs_init();
-	if (zcache_enabled) {
-		unsigned int cpu;
-
-		tmem_register_hostops(&zcache_hostops);
-		tmem_register_pamops(&zcache_pamops);
-		ret = register_cpu_notifier(&zcache_cpu_notifier_block);
-		if (ret) {
-			pr_err("%s: can't register cpu notifier\n", namestr);
-			goto out;
-		}
-		ret = zcache_comp_init();
-		if (ret) {
-			pr_err("%s: compressor initialization failed\n",
-				namestr);
-			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);
-	ret = zcache_new_client(LOCAL_CLIENT);
-	if (ret) {
-		pr_err("%s: can't create client\n", namestr);
-		goto out;
-	}
-	zbud_init();
-	if (zcache_enabled && !disable_cleancache) {
-		struct cleancache_ops *old_ops;
-
-		register_shrinker(&zcache_shrinker);
-		old_ops = zcache_cleancache_register_ops();
-		pr_info("%s: cleancache enabled using kernel transcendent "
-			"memory and compression buddies\n", namestr);
-#ifdef CONFIG_ZCACHE_DEBUG
-		pr_info("%s: cleancache: ignorenonactive = %d\n",
-			namestr, !disable_cleancache_ignore_nonactive);
-#endif
-		if (old_ops != NULL)
-			pr_warn("%s: cleancache_ops overridden\n", namestr);
-	}
-	if (zcache_enabled && !disable_frontswap) {
-		struct frontswap_ops *old_ops;
-
-		old_ops = zcache_frontswap_register_ops();
-		if (frontswap_has_exclusive_gets)
-			frontswap_tmem_exclusive_gets(true);
-		pr_info("%s: frontswap enabled using kernel transcendent "
-			"memory and compression buddies\n", namestr);
-#ifdef CONFIG_ZCACHE_DEBUG
-		pr_info("%s: frontswap: excl gets = %d active only = %d\n",
-			namestr, frontswap_has_exclusive_gets,
-			!disable_frontswap_ignore_nonactive);
-#endif
-		if (IS_ERR(old_ops) || old_ops) {
-			if (IS_ERR(old_ops))
-				return PTR_RET(old_ops);
-			pr_warn("%s: frontswap_ops overridden\n", namestr);
-		}
-	}
-	if (ramster_enabled)
-		ramster_init(!disable_cleancache, !disable_frontswap,
-				frontswap_has_exclusive_gets,
-				!disable_frontswap_selfshrink);
-out:
-	return ret;
-}
-
-#ifdef CONFIG_ZCACHE_MODULE
-#ifdef CONFIG_RAMSTER
-module_param(ramster_enabled, bool, S_IRUGO);
-module_param(disable_frontswap_selfshrink, int, S_IRUGO);
-#endif
-module_param(disable_cleancache, bool, S_IRUGO);
-module_param(disable_frontswap, bool, S_IRUGO);
-#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
-module_param(frontswap_has_exclusive_gets, bool, S_IRUGO);
-#endif
-module_param(disable_frontswap_ignore_nonactive, bool, S_IRUGO);
-module_param(zcache_comp_name, charp, S_IRUGO);
-module_init(zcache_init);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dan Magenheimer <dan.magenheimer@oracle.com>");
-MODULE_DESCRIPTION("In-kernel compression of cleancache/frontswap pages");
-#else
-late_initcall(zcache_init);
-#endif
diff --git a/drivers/staging/zcache/zcache.h b/drivers/staging/zcache/zcache.h
deleted file mode 100644
index 8491200..0000000
--- a/drivers/staging/zcache/zcache.h
+++ /dev/null
@@ -1,53 +0,0 @@
-
-/*
- * zcache.h
- *
- * Copyright (c) 2012, Dan Magenheimer, Oracle Corp.
- */
-
-#ifndef _ZCACHE_H_
-#define _ZCACHE_H_
-
-struct zcache_preload {
-	struct tmem_obj *obj;
-	struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH];
-};
-
-struct tmem_pool;
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
-
-struct zcache_client {
-	struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT];
-	bool allocated;
-	atomic_t refcount;
-};
-
-extern struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id,
-							uint16_t poolid);
-extern void zcache_put_pool(struct tmem_pool *pool);
-
-extern int zcache_put_page(int, int, struct tmem_oid *,
-				uint32_t, void *,
-				unsigned int, bool, int);
-extern int zcache_get_page(int, int, struct tmem_oid *, uint32_t,
-				void *, size_t *, bool, int);
-extern int zcache_flush_page(int, int, struct tmem_oid *, uint32_t);
-extern int zcache_flush_object(int, int, struct tmem_oid *);
-extern void zcache_decompress_to_page(char *, unsigned int, struct page *);
-
-#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
-extern void *zcache_pampd_create(char *, unsigned int, bool, int,
-				struct tmem_handle *);
-int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph);
-#endif
-
-#define MAX_POOLS_PER_CLIENT 16
-
-#define MAX_CLIENTS 16
-#define LOCAL_CLIENT ((uint16_t)-1)
-
-#endif /* _ZCACHE_H_ */
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index e77fb6e..91d94b5 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -169,7 +169,7 @@
 static inline int valid_io_request(struct zram *zram, struct bio *bio)
 {
 	u64 start, end, bound;
-	
+
 	/* unaligned request */
 	if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
 		return 0;
@@ -418,14 +418,6 @@
 			goto out;
 	}
 
-	/*
-	 * System overwrites unused sectors. Free memory associated
-	 * with this sector now.
-	 */
-	if (meta->table[index].handle ||
-	    zram_test_flag(meta, index, ZRAM_ZERO))
-		zram_free_page(zram, index);
-
 	user_mem = kmap_atomic(page);
 
 	if (is_partial_io(bvec)) {
@@ -439,12 +431,23 @@
 
 	if (page_zero_filled(uncmem)) {
 		kunmap_atomic(user_mem);
+		/* Free memory associated with this sector now. */
+		zram_free_page(zram, index);
+
 		zram->stats.pages_zero++;
 		zram_set_flag(meta, index, ZRAM_ZERO);
 		ret = 0;
 		goto out;
 	}
 
+	/*
+	 * zram_slot_free_notify could miss free so that let's
+	 * double check.
+	 */
+	if (unlikely(meta->table[index].handle ||
+			zram_test_flag(meta, index, ZRAM_ZERO)))
+		zram_free_page(zram, index);
+
 	ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
 			       meta->compress_workmem);
 
@@ -486,6 +489,12 @@
 
 	zs_unmap_object(meta->mem_pool, handle);
 
+	/*
+	 * Free memory associated with this sector
+	 * before overwriting unused sectors.
+	 */
+	zram_free_page(zram, index);
+
 	meta->table[index].handle = handle;
 	meta->table[index].size = clen;
 
@@ -504,6 +513,20 @@
 	return ret;
 }
 
+static void handle_pending_slot_free(struct zram *zram)
+{
+	struct zram_slot_free *free_rq;
+
+	spin_lock(&zram->slot_free_lock);
+	while (zram->slot_free_rq) {
+		free_rq = zram->slot_free_rq;
+		zram->slot_free_rq = free_rq->next;
+		zram_free_page(zram, free_rq->index);
+		kfree(free_rq);
+	}
+	spin_unlock(&zram->slot_free_lock);
+}
+
 static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
 			int offset, struct bio *bio, int rw)
 {
@@ -511,10 +534,12 @@
 
 	if (rw == READ) {
 		down_read(&zram->lock);
+		handle_pending_slot_free(zram);
 		ret = zram_bvec_read(zram, bvec, index, offset, bio);
 		up_read(&zram->lock);
 	} else {
 		down_write(&zram->lock);
+		handle_pending_slot_free(zram);
 		ret = zram_bvec_write(zram, bvec, index, offset);
 		up_write(&zram->lock);
 	}
@@ -522,11 +547,13 @@
 	return ret;
 }
 
-static void zram_reset_device(struct zram *zram)
+static void zram_reset_device(struct zram *zram, bool reset_capacity)
 {
 	size_t index;
 	struct zram_meta *meta;
 
+	flush_work(&zram->free_work);
+
 	down_write(&zram->init_lock);
 	if (!zram->init_done) {
 		up_write(&zram->init_lock);
@@ -551,7 +578,8 @@
 	memset(&zram->stats, 0, sizeof(zram->stats));
 
 	zram->disksize = 0;
-	set_capacity(zram->disk, 0);
+	if (reset_capacity)
+		set_capacity(zram->disk, 0);
 	up_write(&zram->init_lock);
 }
 
@@ -635,7 +663,7 @@
 	if (bdev)
 		fsync_bdev(bdev);
 
-	zram_reset_device(zram);
+	zram_reset_device(zram, true);
 	return len;
 }
 
@@ -720,16 +748,40 @@
 	bio_io_error(bio);
 }
 
+static void zram_slot_free(struct work_struct *work)
+{
+	struct zram *zram;
+
+	zram = container_of(work, struct zram, free_work);
+	down_write(&zram->lock);
+	handle_pending_slot_free(zram);
+	up_write(&zram->lock);
+}
+
+static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq)
+{
+	spin_lock(&zram->slot_free_lock);
+	free_rq->next = zram->slot_free_rq;
+	zram->slot_free_rq = free_rq;
+	spin_unlock(&zram->slot_free_lock);
+}
+
 static void zram_slot_free_notify(struct block_device *bdev,
 				unsigned long index)
 {
 	struct zram *zram;
+	struct zram_slot_free *free_rq;
 
 	zram = bdev->bd_disk->private_data;
-	down_write(&zram->lock);
-	zram_free_page(zram, index);
-	up_write(&zram->lock);
 	atomic64_inc(&zram->stats.notify_free);
+
+	free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC);
+	if (!free_rq)
+		return;
+
+	free_rq->index = index;
+	add_slot_free(zram, free_rq);
+	schedule_work(&zram->free_work);
 }
 
 static const struct block_device_operations zram_devops = {
@@ -776,6 +828,10 @@
 	init_rwsem(&zram->lock);
 	init_rwsem(&zram->init_lock);
 
+	INIT_WORK(&zram->free_work, zram_slot_free);
+	spin_lock_init(&zram->slot_free_lock);
+	zram->slot_free_rq = NULL;
+
 	zram->queue = blk_alloc_queue(GFP_KERNEL);
 	if (!zram->queue) {
 		pr_err("Error allocating disk queue for device %d\n",
@@ -902,10 +958,12 @@
 	for (i = 0; i < num_devices; i++) {
 		zram = &zram_devices[i];
 
-		get_disk(zram->disk);
 		destroy_device(zram);
-		zram_reset_device(zram);
-		put_disk(zram->disk);
+		/*
+		 * Shouldn't access zram->disk after destroy_device
+		 * because destroy_device already released zram->disk.
+		 */
+		zram_reset_device(zram, false);
 	}
 
 	unregister_blkdev(zram_major, "zram");
@@ -923,3 +981,4 @@
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");
 MODULE_DESCRIPTION("Compressed RAM Block Device");
+MODULE_ALIAS("devname:zram");
diff --git a/drivers/staging/zram/zram_drv.h b/drivers/staging/zram/zram_drv.h
index 9e57bfb..97a3acf 100644
--- a/drivers/staging/zram/zram_drv.h
+++ b/drivers/staging/zram/zram_drv.h
@@ -94,11 +94,20 @@
 	struct zs_pool *mem_pool;
 };
 
+struct zram_slot_free {
+	unsigned long index;
+	struct zram_slot_free *next;
+};
+
 struct zram {
 	struct zram_meta *meta;
 	struct rw_semaphore lock; /* protect compression buffers, table,
 				   * 32bit stat counters against concurrent
 				   * notifications, reads and writes */
+
+	struct work_struct free_work;  /* handle pending free request */
+	struct zram_slot_free *slot_free_rq; /* list head of free request */
+
 	struct request_queue *queue;
 	struct gendisk *disk;
 	int init_done;
@@ -109,6 +118,7 @@
 	 * we can store in a disk.
 	 */
 	u64 disksize;	/* bytes */
+	spinlock_t slot_free_lock;
 
 	struct zram_stats stats;
 };
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 4bb275b..1a67537 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -423,7 +423,7 @@
 	if (is_last_page(page))
 		next = NULL;
 	else if (is_first_page(page))
-		next = (struct page *)page->private;
+		next = (struct page *)page_private(page);
 	else
 		next = list_entry(page->lru.next, struct page, lru);
 
@@ -581,7 +581,7 @@
 			first_page->inuse = 0;
 		}
 		if (i == 1)
-			first_page->private = (unsigned long)page;
+			set_page_private(first_page, (unsigned long)page);
 		if (i >= 1)
 			page->first_page = first_page;
 		if (i >= 2)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index f73da43..3a17930 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1086,7 +1086,6 @@
 		if (cmd->reject_reason)
 			return 0;
 
-		target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
 		return 1;
 	}
 	/*
@@ -1124,14 +1123,10 @@
 		 */
 		cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
 					(unsigned char *)hdr, hdr->cmdsn);
-		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
+		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
 			return -1;
-		} else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
-			target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
-			return 0;
-		}
 
-		if (cmd->sense_reason) {
+		if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
 			int rc;
 
 			rc = iscsit_dump_data_payload(cmd->conn,
@@ -1527,6 +1522,10 @@
 	if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
 		pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
 			" not set, protocol error.\n");
+		if (!cmd)
+			return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+						 (unsigned char *)hdr);
+
 		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
 					 (unsigned char *)hdr);
 	}
@@ -1536,6 +1535,10 @@
 			" greater than MaxXmitDataSegmentLength: %u, protocol"
 			" error.\n", payload_length,
 			conn->conn_ops->MaxXmitDataSegmentLength);
+		if (!cmd)
+			return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
+						 (unsigned char *)hdr);
+
 		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
 					 (unsigned char *)hdr);
 	}
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 3402241..bc788c5 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1163,12 +1163,11 @@
 		if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
 			spin_unlock_bh(&np->np_thread_lock);
 			complete(&np->np_restart_comp);
-			if (ret == -ENODEV) {
-				iscsit_put_transport(conn->conn_transport);
-				kfree(conn);
-				conn = NULL;
+			iscsit_put_transport(conn->conn_transport);
+			kfree(conn);
+			conn = NULL;
+			if (ret == -ENODEV)
 				goto out;
-			}
 			/* Get another socket */
 			return 1;
 		}
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 4cb667d..9fabbf7 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -97,9 +97,12 @@
 
 	buf[7] = 0x2; /* CmdQue=1 */
 
-	snprintf(&buf[8], 8, "LIO-ORG");
-	snprintf(&buf[16], 16, "%s", dev->t10_wwn.model);
-	snprintf(&buf[32], 4, "%s", dev->t10_wwn.revision);
+	memcpy(&buf[8], "LIO-ORG ", 8);
+	memset(&buf[16], 0x20, 16);
+	memcpy(&buf[16], dev->t10_wwn.model,
+	       min_t(size_t, strlen(dev->t10_wwn.model), 16));
+	memcpy(&buf[32], dev->t10_wwn.revision,
+	       min_t(size_t, strlen(dev->t10_wwn.revision), 4));
 	buf[4] = 31; /* Set additional length to 31 */
 
 	return 0;
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 7172d00..d8e49d7 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2134,6 +2134,7 @@
 
 int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
 {
+	unsigned long flags;
 	int ret = 0;
 
 	if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
@@ -2144,6 +2145,16 @@
 	} else {
 		if (wait_for_tasks)
 			transport_wait_for_tasks(cmd);
+		/*
+		 * Handle WRITE failure case where transport_generic_new_cmd()
+		 * has already added se_cmd to state_list, but fabric has
+		 * failed command before I/O submission.
+		 */
+		if (cmd->state_active) {
+			spin_lock_irqsave(&cmd->t_state_lock, flags);
+			target_remove_from_state_list(cmd);
+			spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+		}
 
 		if (cmd->se_lun)
 			transport_lun_remove_cmd(cmd);
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 083710e..2b86f8e 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1785,8 +1785,6 @@
 	free_irq(IRQ_AMIGA_TBE, state);
 	free_irq(IRQ_AMIGA_RBF, state);
 
-	platform_set_drvdata(pdev, NULL);
-
 	return error;
 }
 
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index eb255e8..9eba119 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -361,7 +361,12 @@
 		tty->driver_data = NULL;
 		tty_port_put(&hp->port);
 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
-	}
+	} else
+		/* We are ready... raise DTR/RTS */
+		if (C_BAUD(tty))
+			if (hp->ops->dtr_rts)
+				hp->ops->dtr_rts(hp, 1);
+
 	/* Force wakeup of the polling thread */
 	hvc_kick();
 
@@ -393,6 +398,10 @@
 		/* We are done with the tty pointer now. */
 		tty_port_tty_set(&hp->port, NULL);
 
+		if (C_HUPCL(tty))
+			if (hp->ops->dtr_rts)
+				hp->ops->dtr_rts(hp, 0);
+
 		if (hp->ops->notifier_del)
 			hp->ops->notifier_del(hp, hp->data);
 
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index 674d23c..9131019 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -75,6 +75,9 @@
 	/* tiocmget/set implementation */
 	int (*tiocmget)(struct hvc_struct *hp);
 	int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear);
+
+	/* Callbacks to handle tty ports */
+	void (*dtr_rts)(struct hvc_struct *hp, int raise);
 };
 
 /* Register a vterm and a slot index for use as a console (console_init) */
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 9d47f50..fd17a9b 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -656,21 +656,64 @@
 }
 
 /**
+ * hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS
+ * @hp:		Pointer the HVC device (struct hvc_struct)
+ * @raise:	Non-zero to raise or zero to lower DTR/RTS lines
+ *
+ * This routine notifies the HVC back-end to raise or lower DTR/RTS
+ * lines.  Raising DTR/RTS is ignored.  Lowering DTR/RTS indicates to
+ * drop the IUCV connection (similar to hang up the modem).
+ */
+static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
+{
+	struct hvc_iucv_private *priv;
+	struct iucv_path        *path;
+
+	/* Raising the DTR/RTS is ignored as IUCV connections can be
+	 * established at any times.
+	 */
+	if (raise)
+		return;
+
+	priv = hvc_iucv_get_private(hp->vtermno);
+	if (!priv)
+		return;
+
+	/* Lowering the DTR/RTS lines disconnects an established IUCV
+	 * connection.
+	 */
+	flush_sndbuf_sync(priv);
+
+	spin_lock_bh(&priv->lock);
+	path = priv->path;		/* save reference to IUCV path */
+	priv->path = NULL;
+	priv->iucv_state = IUCV_DISCONN;
+	spin_unlock_bh(&priv->lock);
+
+	/* Sever IUCV path outside of priv->lock due to lock ordering of:
+	 * priv->lock <--> iucv_table_lock */
+	if (path) {
+		iucv_path_sever(path, NULL);
+		iucv_path_free(path);
+	}
+}
+
+/**
  * hvc_iucv_notifier_del() - HVC notifier for closing a TTY for the last time.
  * @hp:		Pointer to the HVC device (struct hvc_struct)
  * @id:		Additional data (originally passed to hvc_alloc):
  *		the index of an struct hvc_iucv_private instance.
  *
  * This routine notifies the HVC back-end that the last tty device fd has been
- * closed.  The function calls hvc_iucv_cleanup() to clean up the struct
- * hvc_iucv_private instance.
+ * closed.  The function cleans up tty resources.  The clean-up of the IUCV
+ * connection is done in hvc_iucv_dtr_rts() and depends on the HUPCL termios
+ * control setting.
  *
  * Locking:	struct hvc_iucv_private->lock
  */
 static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
 {
 	struct hvc_iucv_private *priv;
-	struct iucv_path	*path;
 
 	priv = hvc_iucv_get_private(id);
 	if (!priv)
@@ -679,17 +722,11 @@
 	flush_sndbuf_sync(priv);
 
 	spin_lock_bh(&priv->lock);
-	path = priv->path;		/* save reference to IUCV path */
-	priv->path = NULL;
-	hvc_iucv_cleanup(priv);
+	destroy_tty_buffer_list(&priv->tty_outqueue);
+	destroy_tty_buffer_list(&priv->tty_inqueue);
+	priv->tty_state = TTY_CLOSED;
+	priv->sndbuf_len = 0;
 	spin_unlock_bh(&priv->lock);
-
-	/* sever IUCV path outside of priv->lock due to lock ordering of:
-	 * priv->lock <--> iucv_table_lock */
-	if (path) {
-		iucv_path_sever(path, NULL);
-		iucv_path_free(path);
-	}
 }
 
 /**
@@ -931,6 +968,7 @@
 	.notifier_add = hvc_iucv_notifier_add,
 	.notifier_del = hvc_iucv_notifier_del,
 	.notifier_hangup = hvc_iucv_notifier_hangup,
+	.dtr_rts = hvc_iucv_dtr_rts,
 };
 
 /* Suspend / resume device operations */
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 682210d..e61c36c 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -208,7 +208,7 @@
 
 	info = vtermno_to_xencons(HVC_COOKIE);
 	if (!info) {
-		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 		if (!info)
 			return -ENOMEM;
 	} else if (info->intf != NULL) {
@@ -257,7 +257,7 @@
 
 	info = vtermno_to_xencons(HVC_COOKIE);
 	if (!info) {
-		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 		if (!info)
 			return -ENOMEM;
 	} else if (info->intf != NULL) {
@@ -284,7 +284,7 @@
 
 	info = vtermno_to_xencons(HVC_COOKIE);
 	if (!info) {
-		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
 		if (!info)
 			return -ENOMEM;
 	}
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 3396eb9..ac27671 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -341,8 +341,8 @@
 
 	pr_devel("HVSI@%x:   ... waiting handshake\n", pv->termno);
 
-	/* Try for up to 200s */
-	for (timeout = 0; timeout < 20; timeout++) {
+	/* Try for up to 400ms */
+	for (timeout = 0; timeout < 40; timeout++) {
 		if (pv->established)
 			goto established;
 		if (!hvsi_get_packet(pv))
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 6422390..c0f76da 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -807,7 +807,7 @@
 	int h = dlci->adaption - 1;
 
 	total_size = 0;
-	while(1) {
+	while (1) {
 		len = kfifo_len(dlci->fifo);
 		if (len == 0)
 			return total_size;
@@ -827,8 +827,8 @@
 		switch (dlci->adaption) {
 		case 1:	/* Unstructured */
 			break;
-		case 2:	/* Unstructed with modem bits. Always one byte as we never
-			   send inline break data */
+		case 2:	/* Unstructed with modem bits.
+		Always one byte as we never send inline break data */
 			*dp++ = gsm_encode_modem(dlci);
 			break;
 		}
@@ -968,7 +968,7 @@
 	unsigned long flags;
 	int sweep;
 
-	if (dlci->constipated) 
+	if (dlci->constipated)
 		return;
 
 	spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
@@ -981,7 +981,7 @@
 			gsm_dlci_data_output(dlci->gsm, dlci);
 	}
 	if (sweep)
- 		gsm_dlci_data_sweep(dlci->gsm);
+		gsm_dlci_data_sweep(dlci->gsm);
 	spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
 }
 
@@ -1138,7 +1138,7 @@
 static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
 {
 	struct tty_port *port;
-	unsigned int addr = 0 ;
+	unsigned int addr = 0;
 	u8 bits;
 	int len = clen;
 	u8 *dp = data;
@@ -1740,10 +1740,11 @@
 
 	if ((gsm->control & ~PF) == UI)
 		gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
-	if (gsm->encoding == 0){
-		/* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only.
-		            In this case it contain the last piece of data
-		            required to generate final CRC */
+	if (gsm->encoding == 0) {
+		/* WARNING: gsm->received_fcs is used for
+		gsm->encoding = 0 only.
+		In this case it contain the last piece of data
+		required to generate final CRC */
 		gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
 	}
 	if (gsm->fcs != GOOD_FCS) {
@@ -2904,9 +2905,11 @@
 	gsm = gsm_mux[mux];
 	if (gsm->dead)
 		return -EL2HLT;
-	/* If DLCI 0 is not yet fully open return an error. This is ok from a locking
-	   perspective as we don't have to worry about this if DLCI0 is lost */
-	if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) 
+	/* If DLCI 0 is not yet fully open return an error.
+	This is ok from a locking
+	perspective as we don't have to worry about this
+	if DLCI0 is lost */
+	if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
 		return -EL2NSYNC;
 	dlci = gsm->dlci[line];
 	if (dlci == NULL) {
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4bf0fc0..c9a9ddd 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -50,6 +50,7 @@
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
 
 
 /* number of characters left in xmit buffer before select has we have room */
@@ -74,37 +75,81 @@
 #define ECHO_OP_SET_CANON_COL 0x81
 #define ECHO_OP_ERASE_TAB 0x82
 
+#define ECHO_COMMIT_WATERMARK	256
+#define ECHO_BLOCK		256
+#define ECHO_DISCARD_WATERMARK	N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
+
+
+#undef N_TTY_TRACE
+#ifdef N_TTY_TRACE
+# define n_tty_trace(f, args...)	trace_printk(f, ##args)
+#else
+# define n_tty_trace(f, args...)
+#endif
+
 struct n_tty_data {
-	unsigned int column;
+	/* producer-published */
+	size_t read_head;
+	size_t canon_head;
+	size_t echo_head;
+	size_t echo_commit;
+	DECLARE_BITMAP(char_map, 256);
+
+	/* private to n_tty_receive_overrun (single-threaded) */
 	unsigned long overrun_time;
 	int num_overrun;
 
+	/* non-atomic */
+	bool no_room;
+
+	/* must hold exclusive termios_rwsem to reset these */
 	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
-	unsigned char echo_overrun:1;
 
-	DECLARE_BITMAP(process_char_map, 256);
+	/* shared by producer and consumer */
+	char read_buf[N_TTY_BUF_SIZE];
 	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE);
+	unsigned char echo_buf[N_TTY_BUF_SIZE];
 
-	char *read_buf;
-	int read_head;
-	int read_tail;
-	int read_cnt;
 	int minimum_to_wake;
 
-	unsigned char *echo_buf;
-	unsigned int echo_pos;
-	unsigned int echo_cnt;
+	/* consumer-published */
+	size_t read_tail;
+	size_t line_start;
 
-	int canon_data;
-	unsigned long canon_head;
+	/* protected by output lock */
+	unsigned int column;
 	unsigned int canon_column;
+	size_t echo_tail;
 
 	struct mutex atomic_read_lock;
 	struct mutex output_lock;
-	struct mutex echo_lock;
-	raw_spinlock_t read_lock;
 };
 
+static inline size_t read_cnt(struct n_tty_data *ldata)
+{
+	return ldata->read_head - ldata->read_tail;
+}
+
+static inline unsigned char read_buf(struct n_tty_data *ldata, size_t i)
+{
+	return ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
+static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+	return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
+static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i)
+{
+	return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
+static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
+{
+	return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
+}
+
 static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
 			       unsigned char __user *ptr)
 {
@@ -114,33 +159,18 @@
 	return put_user(x, ptr);
 }
 
-/**
- *	n_tty_set_room	-	receive space
- *	@tty: terminal
- *
- *	Updates tty->receive_room to reflect the currently available space
- *	in the input buffer, and re-schedules the flip buffer work if space
- *	just became available.
- *
- *	Locks: Concurrent update is protected with read_lock
- */
-
-static int set_room(struct tty_struct *tty)
+static int receive_room(struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 	int left;
-	int old_left;
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&ldata->read_lock, flags);
 
 	if (I_PARMRK(tty)) {
 		/* Multiply read_cnt by 3, since each byte might take up to
 		 * three times as many spaces when PARMRK is set (depending on
 		 * its flags, e.g. parity error). */
-		left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1;
+		left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1;
 	} else
-		left = N_TTY_BUF_SIZE - ldata->read_cnt - 1;
+		left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1;
 
 	/*
 	 * If we are doing input canonicalization, and there are no
@@ -149,19 +179,31 @@
 	 * characters will be beeped.
 	 */
 	if (left <= 0)
-		left = ldata->icanon && !ldata->canon_data;
-	old_left = tty->receive_room;
-	tty->receive_room = left;
+		left = ldata->icanon && ldata->canon_head == ldata->read_tail;
 
-	raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-
-	return left && !old_left;
+	return left;
 }
 
+/**
+ *	n_tty_set_room	-	receive space
+ *	@tty: terminal
+ *
+ *	Re-schedules the flip buffer work if space just became available.
+ *
+ *	Caller holds exclusive termios_rwsem
+ *	   or
+ *	n_tty_read()/consumer path:
+ *		holds non-exclusive termios_rwsem
+ */
+
 static void n_tty_set_room(struct tty_struct *tty)
 {
+	struct n_tty_data *ldata = tty->disc_data;
+
 	/* Did this open up the receive buffer? We may need to flip */
-	if (set_room(tty)) {
+	if (unlikely(ldata->no_room) && receive_room(tty)) {
+		ldata->no_room = 0;
+
 		WARN_RATELIMIT(tty->port->itty == NULL,
 				"scheduling with invalid itty\n");
 		/* see if ldisc has been killed - if so, this means that
@@ -170,17 +212,93 @@
 		 */
 		WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
 			       "scheduling buffer work for halted ldisc\n");
-		schedule_work(&tty->port->buf.work);
+		queue_work(system_unbound_wq, &tty->port->buf.work);
 	}
 }
 
-static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata)
+static ssize_t chars_in_buffer(struct tty_struct *tty)
 {
-	if (ldata->read_cnt < N_TTY_BUF_SIZE) {
-		ldata->read_buf[ldata->read_head] = c;
-		ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1);
-		ldata->read_cnt++;
+	struct n_tty_data *ldata = tty->disc_data;
+	ssize_t n = 0;
+
+	if (!ldata->icanon)
+		n = read_cnt(ldata);
+	else
+		n = ldata->canon_head - ldata->read_tail;
+	return n;
+}
+
+/**
+ *	n_tty_write_wakeup	-	asynchronous I/O notifier
+ *	@tty: tty device
+ *
+ *	Required for the ptys, serial driver etc. since processes
+ *	that attach themselves to the master and rely on ASYNC
+ *	IO must be woken up
+ */
+
+static void n_tty_write_wakeup(struct tty_struct *tty)
+{
+	if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
+		kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+}
+
+static void n_tty_check_throttle(struct tty_struct *tty)
+{
+	if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
+		return;
+	/*
+	 * Check the remaining room for the input canonicalization
+	 * mode.  We don't want to throttle the driver if we're in
+	 * canonical mode and don't have a newline yet!
+	 */
+	while (1) {
+		int throttled;
+		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
+		if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
+			break;
+		throttled = tty_throttle_safe(tty);
+		if (!throttled)
+			break;
 	}
+	__tty_set_flow_change(tty, 0);
+}
+
+static void n_tty_check_unthrottle(struct tty_struct *tty)
+{
+	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+	    tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
+		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+			return;
+		if (!tty->count)
+			return;
+		n_tty_set_room(tty);
+		n_tty_write_wakeup(tty->link);
+		wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
+		return;
+	}
+
+	/* If there is enough space in the read buffer now, let the
+	 * low-level driver know. We use chars_in_buffer() to
+	 * check the buffer, as it now knows about canonical mode.
+	 * Otherwise, if the driver is throttled and the line is
+	 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+	 * we won't get any more characters.
+	 */
+
+	while (1) {
+		int unthrottled;
+		tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+		if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+			break;
+		if (!tty->count)
+			break;
+		n_tty_set_room(tty);
+		unthrottled = tty_unthrottle_safe(tty);
+		if (!unthrottled)
+			break;
+	}
+	__tty_set_flow_change(tty, 0);
 }
 
 /**
@@ -188,21 +306,19 @@
  *	@c: character
  *	@ldata: n_tty data
  *
- *	Add a character to the tty read_buf queue. This is done under the
- *	read_lock to serialize character addition and also to protect us
- *	against parallel reads or flushes
+ *	Add a character to the tty read_buf queue.
+ *
+ *	n_tty_receive_buf()/producer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		modifies read_head
+ *
+ *	read_head is only considered 'published' if canonical mode is
+ *	not active.
  */
 
-static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
+static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
 {
-	unsigned long flags;
-	/*
-	 *	The problem of stomping on the buffers ends here.
-	 *	Why didn't anyone see this one coming? --AJK
-	*/
-	raw_spin_lock_irqsave(&ldata->read_lock, flags);
-	put_tty_queue_nolock(c, ldata);
-	raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
+	*read_buf_addr(ldata, ldata->read_head++) = c;
 }
 
 /**
@@ -212,22 +328,17 @@
  *	Reset the read buffer counters and clear the flags.
  *	Called from n_tty_open() and n_tty_flush_buffer().
  *
- *	Locking: tty_read_lock for read fields.
+ *	Locking: caller holds exclusive termios_rwsem
+ *		 (or locking is not required)
  */
 
 static void reset_buffer_flags(struct n_tty_data *ldata)
 {
-	unsigned long flags;
+	ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
+	ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
+	ldata->line_start = 0;
 
-	raw_spin_lock_irqsave(&ldata->read_lock, flags);
-	ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
-	raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-
-	mutex_lock(&ldata->echo_lock);
-	ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
-	mutex_unlock(&ldata->echo_lock);
-
-	ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
+	ldata->erasing = 0;
 	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
 }
 
@@ -251,16 +362,21 @@
  *	buffer flushed (eg at hangup) or when the N_TTY line discipline
  *	internally has to clean the pending queue (for example some signals).
  *
- *	Locking: ctrl_lock, read_lock.
+ *	Holds termios_rwsem to exclude producer/consumer while
+ *	buffer indices are reset.
+ *
+ *	Locking: ctrl_lock, exclusive termios_rwsem
  */
 
 static void n_tty_flush_buffer(struct tty_struct *tty)
 {
+	down_write(&tty->termios_rwsem);
 	reset_buffer_flags(tty->disc_data);
 	n_tty_set_room(tty);
 
 	if (tty->link)
 		n_tty_packet_mode_flush(tty);
+	up_write(&tty->termios_rwsem);
 }
 
 /**
@@ -270,24 +386,18 @@
  *	Report the number of characters buffered to be delivered to user
  *	at this instant in time.
  *
- *	Locking: read_lock
+ *	Locking: exclusive termios_rwsem
  */
 
 static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
 {
-	struct n_tty_data *ldata = tty->disc_data;
-	unsigned long flags;
-	ssize_t n = 0;
+	ssize_t n;
 
-	raw_spin_lock_irqsave(&ldata->read_lock, flags);
-	if (!ldata->icanon) {
-		n = ldata->read_cnt;
-	} else if (ldata->canon_data) {
-		n = (ldata->canon_head > ldata->read_tail) ?
-			ldata->canon_head - ldata->read_tail :
-			ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
-	}
-	raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
+	WARN_ONCE(1, "%s is deprecated and scheduled for removal.", __func__);
+
+	down_write(&tty->termios_rwsem);
+	n = chars_in_buffer(tty);
+	up_write(&tty->termios_rwsem);
 	return n;
 }
 
@@ -532,33 +642,23 @@
  *	are prioritized.  Also, when control characters are echoed with a
  *	prefixed "^", the pair is treated atomically and thus not separated.
  *
- *	Locking: output_lock to protect column state and space left,
- *		 echo_lock to protect the echo buffer
+ *	Locking: callers must hold output_lock
  */
 
-static void process_echoes(struct tty_struct *tty)
+static size_t __process_echoes(struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
-	int	space, nr;
+	int	space, old_space;
+	size_t tail;
 	unsigned char c;
-	unsigned char *cp, *buf_end;
 
-	if (!ldata->echo_cnt)
-		return;
+	old_space = space = tty_write_room(tty);
 
-	mutex_lock(&ldata->output_lock);
-	mutex_lock(&ldata->echo_lock);
-
-	space = tty_write_room(tty);
-
-	buf_end = ldata->echo_buf + N_TTY_BUF_SIZE;
-	cp = ldata->echo_buf + ldata->echo_pos;
-	nr = ldata->echo_cnt;
-	while (nr > 0) {
-		c = *cp;
+	tail = ldata->echo_tail;
+	while (ldata->echo_commit != tail) {
+		c = echo_buf(ldata, tail);
 		if (c == ECHO_OP_START) {
 			unsigned char op;
-			unsigned char *opp;
 			int no_space_left = 0;
 
 			/*
@@ -566,18 +666,13 @@
 			 * operation, get the next byte, which is either the
 			 * op code or a control character value.
 			 */
-			opp = cp + 1;
-			if (opp == buf_end)
-				opp -= N_TTY_BUF_SIZE;
-			op = *opp;
+			op = echo_buf(ldata, tail + 1);
 
 			switch (op) {
 				unsigned int num_chars, num_bs;
 
 			case ECHO_OP_ERASE_TAB:
-				if (++opp == buf_end)
-					opp -= N_TTY_BUF_SIZE;
-				num_chars = *opp;
+				num_chars = echo_buf(ldata, tail + 2);
 
 				/*
 				 * Determine how many columns to go back
@@ -603,21 +698,18 @@
 					if (ldata->column > 0)
 						ldata->column--;
 				}
-				cp += 3;
-				nr -= 3;
+				tail += 3;
 				break;
 
 			case ECHO_OP_SET_CANON_COL:
 				ldata->canon_column = ldata->column;
-				cp += 2;
-				nr -= 2;
+				tail += 2;
 				break;
 
 			case ECHO_OP_MOVE_BACK_COL:
 				if (ldata->column > 0)
 					ldata->column--;
-				cp += 2;
-				nr -= 2;
+				tail += 2;
 				break;
 
 			case ECHO_OP_START:
@@ -629,8 +721,7 @@
 				tty_put_char(tty, ECHO_OP_START);
 				ldata->column++;
 				space--;
-				cp += 2;
-				nr -= 2;
+				tail += 2;
 				break;
 
 			default:
@@ -651,8 +742,7 @@
 				tty_put_char(tty, op ^ 0100);
 				ldata->column += 2;
 				space -= 2;
-				cp += 2;
-				nr -= 2;
+				tail += 2;
 			}
 
 			if (no_space_left)
@@ -669,80 +759,92 @@
 				tty_put_char(tty, c);
 				space -= 1;
 			}
-			cp += 1;
-			nr -= 1;
+			tail += 1;
 		}
-
-		/* When end of circular buffer reached, wrap around */
-		if (cp >= buf_end)
-			cp -= N_TTY_BUF_SIZE;
 	}
 
-	if (nr == 0) {
-		ldata->echo_pos = 0;
-		ldata->echo_cnt = 0;
-		ldata->echo_overrun = 0;
-	} else {
-		int num_processed = ldata->echo_cnt - nr;
-		ldata->echo_pos += num_processed;
-		ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
-		ldata->echo_cnt = nr;
-		if (num_processed > 0)
-			ldata->echo_overrun = 0;
+	/* If the echo buffer is nearly full (so that the possibility exists
+	 * of echo overrun before the next commit), then discard enough
+	 * data at the tail to prevent a subsequent overrun */
+	while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
+		if (echo_buf(ldata, tail == ECHO_OP_START)) {
+			if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB)
+				tail += 3;
+			else
+				tail += 2;
+		} else
+			tail++;
 	}
 
-	mutex_unlock(&ldata->echo_lock);
+	ldata->echo_tail = tail;
+	return old_space - space;
+}
+
+static void commit_echoes(struct tty_struct *tty)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	size_t nr, old, echoed;
+	size_t head;
+
+	head = ldata->echo_head;
+	old = ldata->echo_commit - ldata->echo_tail;
+
+	/* Process committed echoes if the accumulated # of bytes
+	 * is over the threshold (and try again each time another
+	 * block is accumulated) */
+	nr = head - ldata->echo_tail;
+	if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
+		return;
+
+	mutex_lock(&ldata->output_lock);
+	ldata->echo_commit = head;
+	echoed = __process_echoes(tty);
 	mutex_unlock(&ldata->output_lock);
 
-	if (tty->ops->flush_chars)
+	if (echoed && tty->ops->flush_chars)
 		tty->ops->flush_chars(tty);
 }
 
+static void process_echoes(struct tty_struct *tty)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	size_t echoed;
+
+	if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_tail)
+		return;
+
+	mutex_lock(&ldata->output_lock);
+	echoed = __process_echoes(tty);
+	mutex_unlock(&ldata->output_lock);
+
+	if (echoed && tty->ops->flush_chars)
+		tty->ops->flush_chars(tty);
+}
+
+static void flush_echoes(struct tty_struct *tty)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+
+	if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_head)
+		return;
+
+	mutex_lock(&ldata->output_lock);
+	ldata->echo_commit = ldata->echo_head;
+	__process_echoes(tty);
+	mutex_unlock(&ldata->output_lock);
+}
+
 /**
  *	add_echo_byte	-	add a byte to the echo buffer
  *	@c: unicode byte to echo
  *	@ldata: n_tty data
  *
  *	Add a character or operation byte to the echo buffer.
- *
- *	Should be called under the echo lock to protect the echo buffer.
  */
 
-static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
+static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
 {
-	int	new_byte_pos;
-
-	if (ldata->echo_cnt == N_TTY_BUF_SIZE) {
-		/* Circular buffer is already at capacity */
-		new_byte_pos = ldata->echo_pos;
-
-		/*
-		 * Since the buffer start position needs to be advanced,
-		 * be sure to step by a whole operation byte group.
-		 */
-		if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) {
-			if (ldata->echo_buf[(ldata->echo_pos + 1) &
-					  (N_TTY_BUF_SIZE - 1)] ==
-						ECHO_OP_ERASE_TAB) {
-				ldata->echo_pos += 3;
-				ldata->echo_cnt -= 2;
-			} else {
-				ldata->echo_pos += 2;
-				ldata->echo_cnt -= 1;
-			}
-		} else {
-			ldata->echo_pos++;
-		}
-		ldata->echo_pos &= N_TTY_BUF_SIZE - 1;
-
-		ldata->echo_overrun = 1;
-	} else {
-		new_byte_pos = ldata->echo_pos + ldata->echo_cnt;
-		new_byte_pos &= N_TTY_BUF_SIZE - 1;
-		ldata->echo_cnt++;
-	}
-
-	ldata->echo_buf[new_byte_pos] = c;
+	*echo_buf_addr(ldata, ldata->echo_head++) = c;
 }
 
 /**
@@ -750,16 +852,12 @@
  *	@ldata: n_tty data
  *
  *	Add an operation to the echo buffer to move back one column.
- *
- *	Locking: echo_lock to protect the echo buffer
  */
 
 static void echo_move_back_col(struct n_tty_data *ldata)
 {
-	mutex_lock(&ldata->echo_lock);
 	add_echo_byte(ECHO_OP_START, ldata);
 	add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata);
-	mutex_unlock(&ldata->echo_lock);
 }
 
 /**
@@ -768,16 +866,12 @@
  *
  *	Add an operation to the echo buffer to set the canon column
  *	to the current column.
- *
- *	Locking: echo_lock to protect the echo buffer
  */
 
 static void echo_set_canon_col(struct n_tty_data *ldata)
 {
-	mutex_lock(&ldata->echo_lock);
 	add_echo_byte(ECHO_OP_START, ldata);
 	add_echo_byte(ECHO_OP_SET_CANON_COL, ldata);
-	mutex_unlock(&ldata->echo_lock);
 }
 
 /**
@@ -793,15 +887,11 @@
  *	of input.  This information will be used later, along with
  *	canon column (if applicable), to go back the correct number
  *	of columns.
- *
- *	Locking: echo_lock to protect the echo buffer
  */
 
 static void echo_erase_tab(unsigned int num_chars, int after_tab,
 			   struct n_tty_data *ldata)
 {
-	mutex_lock(&ldata->echo_lock);
-
 	add_echo_byte(ECHO_OP_START, ldata);
 	add_echo_byte(ECHO_OP_ERASE_TAB, ldata);
 
@@ -813,8 +903,6 @@
 		num_chars |= 0x80;
 
 	add_echo_byte(num_chars, ldata);
-
-	mutex_unlock(&ldata->echo_lock);
 }
 
 /**
@@ -826,20 +914,16 @@
  *	L_ECHO(tty) is true. Called from the driver receive_buf path.
  *
  *	This variant does not treat control characters specially.
- *
- *	Locking: echo_lock to protect the echo buffer
  */
 
 static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)
 {
-	mutex_lock(&ldata->echo_lock);
 	if (c == ECHO_OP_START) {
 		add_echo_byte(ECHO_OP_START, ldata);
 		add_echo_byte(ECHO_OP_START, ldata);
 	} else {
 		add_echo_byte(c, ldata);
 	}
-	mutex_unlock(&ldata->echo_lock);
 }
 
 /**
@@ -852,16 +936,12 @@
  *
  *	This variant tags control characters to be echoed as "^X"
  *	(where X is the letter representing the control char).
- *
- *	Locking: echo_lock to protect the echo buffer
  */
 
 static void echo_char(unsigned char c, struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 
-	mutex_lock(&ldata->echo_lock);
-
 	if (c == ECHO_OP_START) {
 		add_echo_byte(ECHO_OP_START, ldata);
 		add_echo_byte(ECHO_OP_START, ldata);
@@ -870,8 +950,6 @@
 			add_echo_byte(ECHO_OP_START, ldata);
 		add_echo_byte(c, ldata);
 	}
-
-	mutex_unlock(&ldata->echo_lock);
 }
 
 /**
@@ -896,17 +974,22 @@
  *	present in the stream from the driver layer. Handles the complexities
  *	of UTF-8 multibyte symbols.
  *
- *	Locking: read_lock for tty buffers
+ *	n_tty_receive_buf()/producer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		modifies read_head
+ *
+ *	Modifying the read_head is not considered a publish in this context
+ *	because canonical mode is active -- only canon_head publishes
  */
 
 static void eraser(unsigned char c, struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 	enum { ERASE, WERASE, KILL } kill_type;
-	int head, seen_alnums, cnt;
-	unsigned long flags;
+	size_t head;
+	size_t cnt;
+	int seen_alnums;
 
-	/* FIXME: locking needed ? */
 	if (ldata->read_head == ldata->canon_head) {
 		/* process_output('\a', tty); */ /* what do you think? */
 		return;
@@ -917,19 +1000,11 @@
 		kill_type = WERASE;
 	else {
 		if (!L_ECHO(tty)) {
-			raw_spin_lock_irqsave(&ldata->read_lock, flags);
-			ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
-					  (N_TTY_BUF_SIZE - 1));
 			ldata->read_head = ldata->canon_head;
-			raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
 			return;
 		}
 		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
-			raw_spin_lock_irqsave(&ldata->read_lock, flags);
-			ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
-					  (N_TTY_BUF_SIZE - 1));
 			ldata->read_head = ldata->canon_head;
-			raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
 			finish_erasing(ldata);
 			echo_char(KILL_CHAR(tty), tty);
 			/* Add a newline if ECHOK is on and ECHOKE is off. */
@@ -941,14 +1016,13 @@
 	}
 
 	seen_alnums = 0;
-	/* FIXME: Locking ?? */
 	while (ldata->read_head != ldata->canon_head) {
 		head = ldata->read_head;
 
 		/* erase a single possibly multibyte character */
 		do {
-			head = (head - 1) & (N_TTY_BUF_SIZE-1);
-			c = ldata->read_buf[head];
+			head--;
+			c = read_buf(ldata, head);
 		} while (is_continuation(c, tty) && head != ldata->canon_head);
 
 		/* do not partially erase */
@@ -962,11 +1036,8 @@
 			else if (seen_alnums)
 				break;
 		}
-		cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
-		raw_spin_lock_irqsave(&ldata->read_lock, flags);
+		cnt = ldata->read_head - head;
 		ldata->read_head = head;
-		ldata->read_cnt -= cnt;
-		raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
 		if (L_ECHO(tty)) {
 			if (L_ECHOPRT(tty)) {
 				if (!ldata->erasing) {
@@ -976,9 +1047,8 @@
 				/* if cnt > 1, output a multi-byte character */
 				echo_char(c, tty);
 				while (--cnt > 0) {
-					head = (head+1) & (N_TTY_BUF_SIZE-1);
-					echo_char_raw(ldata->read_buf[head],
-							ldata);
+					head++;
+					echo_char_raw(read_buf(ldata, head), ldata);
 					echo_move_back_col(ldata);
 				}
 			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
@@ -986,7 +1056,7 @@
 			} else if (c == '\t') {
 				unsigned int num_chars = 0;
 				int after_tab = 0;
-				unsigned long tail = ldata->read_head;
+				size_t tail = ldata->read_head;
 
 				/*
 				 * Count the columns used for characters
@@ -996,8 +1066,8 @@
 				 * number of columns.
 				 */
 				while (tail != ldata->canon_head) {
-					tail = (tail-1) & (N_TTY_BUF_SIZE-1);
-					c = ldata->read_buf[tail];
+					tail--;
+					c = read_buf(ldata, tail);
 					if (c == '\t') {
 						after_tab = 1;
 						break;
@@ -1040,7 +1110,7 @@
  *	Locking: ctrl_lock
  */
 
-static inline void isig(int sig, struct tty_struct *tty)
+static void isig(int sig, struct tty_struct *tty)
 {
 	struct pid *tty_pgrp = tty_get_pgrp(tty);
 	if (tty_pgrp) {
@@ -1056,10 +1126,14 @@
  *	An RS232 break event has been hit in the incoming bitstream. This
  *	can cause a variety of events depending upon the termios settings.
  *
- *	Called from the receive_buf path so single threaded.
+ *	n_tty_receive_buf()/producer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		publishes read_head via put_tty_queue()
+ *
+ *	Note: may get exclusive termios_rwsem if flushing input buffer
  */
 
-static inline void n_tty_receive_break(struct tty_struct *tty)
+static void n_tty_receive_break(struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 
@@ -1068,8 +1142,11 @@
 	if (I_BRKINT(tty)) {
 		isig(SIGINT, tty);
 		if (!L_NOFLSH(tty)) {
+			/* flushing needs exclusive termios_rwsem */
+			up_read(&tty->termios_rwsem);
 			n_tty_flush_buffer(tty);
 			tty_driver_flush_buffer(tty);
+			down_read(&tty->termios_rwsem);
 		}
 		return;
 	}
@@ -1094,7 +1171,7 @@
  *	private.
  */
 
-static inline void n_tty_receive_overrun(struct tty_struct *tty)
+static void n_tty_receive_overrun(struct tty_struct *tty)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 	char buf[64];
@@ -1116,10 +1193,13 @@
  *	@c: character
  *
  *	Process a parity error and queue the right data to indicate
- *	the error case if necessary. Locking as per n_tty_receive_buf.
+ *	the error case if necessary.
+ *
+ *	n_tty_receive_buf()/producer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		publishes read_head via put_tty_queue()
  */
-static inline void n_tty_receive_parity_error(struct tty_struct *tty,
-					      unsigned char c)
+static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
 {
 	struct n_tty_data *ldata = tty->disc_data;
 
@@ -1136,6 +1216,26 @@
 	wake_up_interruptible(&tty->read_wait);
 }
 
+static void
+n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
+{
+	if (!L_NOFLSH(tty)) {
+		/* flushing needs exclusive termios_rwsem */
+		up_read(&tty->termios_rwsem);
+		n_tty_flush_buffer(tty);
+		tty_driver_flush_buffer(tty);
+		down_read(&tty->termios_rwsem);
+	}
+	if (I_IXON(tty))
+		start_tty(tty);
+	if (L_ECHO(tty)) {
+		echo_char(c, tty);
+		commit_echoes(tty);
+	}
+	isig(signal, tty);
+	return;
+}
+
 /**
  *	n_tty_receive_char	-	perform processing
  *	@tty: terminal device
@@ -1144,117 +1244,54 @@
  *	Process an individual character of input received from the driver.
  *	This is serialized with respect to itself by the rules for the
  *	driver above.
+ *
+ *	n_tty_receive_buf()/producer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		publishes canon_head if canonical mode is active
+ *		otherwise, publishes read_head via put_tty_queue()
+ *
+ *	Returns 1 if LNEXT was received, else returns 0
  */
 
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+static int
+n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
 {
 	struct n_tty_data *ldata = tty->disc_data;
-	unsigned long flags;
 	int parmrk;
 
-	if (ldata->raw) {
-		put_tty_queue(c, ldata);
-		return;
-	}
-
-	if (I_ISTRIP(tty))
-		c &= 0x7f;
-	if (I_IUCLC(tty) && L_IEXTEN(tty))
-		c = tolower(c);
-
-	if (L_EXTPROC(tty)) {
-		put_tty_queue(c, ldata);
-		return;
-	}
-
-	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
-	    I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
-	    c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
-		start_tty(tty);
-		process_echoes(tty);
-	}
-
-	if (tty->closing) {
-		if (I_IXON(tty)) {
-			if (c == START_CHAR(tty)) {
-				start_tty(tty);
-				process_echoes(tty);
-			} else if (c == STOP_CHAR(tty))
-				stop_tty(tty);
-		}
-		return;
-	}
-
-	/*
-	 * If the previous character was LNEXT, or we know that this
-	 * character is not one of the characters that we'll have to
-	 * handle specially, do shortcut processing to speed things
-	 * up.
-	 */
-	if (!test_bit(c, ldata->process_char_map) || ldata->lnext) {
-		ldata->lnext = 0;
-		parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-		if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-			/* beep if no space */
-			if (L_ECHO(tty))
-				process_output('\a', tty);
-			return;
-		}
-		if (L_ECHO(tty)) {
-			finish_erasing(ldata);
-			/* Record the column of first canon char. */
-			if (ldata->canon_head == ldata->read_head)
-				echo_set_canon_col(ldata);
-			echo_char(c, tty);
-			process_echoes(tty);
-		}
-		if (parmrk)
-			put_tty_queue(c, ldata);
-		put_tty_queue(c, ldata);
-		return;
-	}
-
 	if (I_IXON(tty)) {
 		if (c == START_CHAR(tty)) {
 			start_tty(tty);
-			process_echoes(tty);
-			return;
+			commit_echoes(tty);
+			return 0;
 		}
 		if (c == STOP_CHAR(tty)) {
 			stop_tty(tty);
-			return;
+			return 0;
 		}
 	}
 
 	if (L_ISIG(tty)) {
-		int signal;
-		signal = SIGINT;
-		if (c == INTR_CHAR(tty))
-			goto send_signal;
-		signal = SIGQUIT;
-		if (c == QUIT_CHAR(tty))
-			goto send_signal;
-		signal = SIGTSTP;
-		if (c == SUSP_CHAR(tty)) {
-send_signal:
-			if (!L_NOFLSH(tty)) {
-				n_tty_flush_buffer(tty);
-				tty_driver_flush_buffer(tty);
-			}
-			if (I_IXON(tty))
-				start_tty(tty);
-			if (L_ECHO(tty)) {
-				echo_char(c, tty);
-				process_echoes(tty);
-			}
-			isig(signal, tty);
-			return;
+		if (c == INTR_CHAR(tty)) {
+			n_tty_receive_signal_char(tty, SIGINT, c);
+			return 0;
+		} else if (c == QUIT_CHAR(tty)) {
+			n_tty_receive_signal_char(tty, SIGQUIT, c);
+			return 0;
+		} else if (c == SUSP_CHAR(tty)) {
+			n_tty_receive_signal_char(tty, SIGTSTP, c);
+			return 0;
 		}
 	}
 
+	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+		start_tty(tty);
+		process_echoes(tty);
+	}
+
 	if (c == '\r') {
 		if (I_IGNCR(tty))
-			return;
+			return 0;
 		if (I_ICRNL(tty))
 			c = '\n';
 	} else if (c == '\n' && I_INLCR(tty))
@@ -1264,8 +1301,8 @@
 		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
 		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
 			eraser(c, tty);
-			process_echoes(tty);
-			return;
+			commit_echoes(tty);
+			return 0;
 		}
 		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
 			ldata->lnext = 1;
@@ -1274,42 +1311,32 @@
 				if (L_ECHOCTL(tty)) {
 					echo_char_raw('^', ldata);
 					echo_char_raw('\b', ldata);
-					process_echoes(tty);
+					commit_echoes(tty);
 				}
 			}
-			return;
+			return 1;
 		}
-		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
-		    L_IEXTEN(tty)) {
-			unsigned long tail = ldata->canon_head;
+		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
+			size_t tail = ldata->canon_head;
 
 			finish_erasing(ldata);
 			echo_char(c, tty);
 			echo_char_raw('\n', ldata);
 			while (tail != ldata->read_head) {
-				echo_char(ldata->read_buf[tail], tty);
-				tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+				echo_char(read_buf(ldata, tail), tty);
+				tail++;
 			}
-			process_echoes(tty);
-			return;
+			commit_echoes(tty);
+			return 0;
 		}
 		if (c == '\n') {
-			if (ldata->read_cnt >= N_TTY_BUF_SIZE) {
-				if (L_ECHO(tty))
-					process_output('\a', tty);
-				return;
-			}
 			if (L_ECHO(tty) || L_ECHONL(tty)) {
 				echo_char_raw('\n', ldata);
-				process_echoes(tty);
+				commit_echoes(tty);
 			}
 			goto handle_newline;
 		}
 		if (c == EOF_CHAR(tty)) {
-			if (ldata->read_cnt >= N_TTY_BUF_SIZE)
-				return;
-			if (ldata->canon_head != ldata->read_head)
-				set_bit(TTY_PUSH, &tty->flags);
 			c = __DISABLED_CHAR;
 			goto handle_newline;
 		}
@@ -1317,11 +1344,6 @@
 		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
 			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
 				 ? 1 : 0;
-			if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
-				if (L_ECHO(tty))
-					process_output('\a', tty);
-				return;
-			}
 			/*
 			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
 			 */
@@ -1330,7 +1352,7 @@
 				if (ldata->canon_head == ldata->read_head)
 					echo_set_canon_col(ldata);
 				echo_char(c, tty);
-				process_echoes(tty);
+				commit_echoes(tty);
 			}
 			/*
 			 * XXX does PARMRK doubling happen for
@@ -1340,26 +1362,17 @@
 				put_tty_queue(c, ldata);
 
 handle_newline:
-			raw_spin_lock_irqsave(&ldata->read_lock, flags);
-			set_bit(ldata->read_head, ldata->read_flags);
-			put_tty_queue_nolock(c, ldata);
+			set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
+			put_tty_queue(c, ldata);
 			ldata->canon_head = ldata->read_head;
-			ldata->canon_data++;
-			raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
 			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
 			if (waitqueue_active(&tty->read_wait))
 				wake_up_interruptible(&tty->read_wait);
-			return;
+			return 0;
 		}
 	}
 
 	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-	if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-		/* beep if no space */
-		if (L_ECHO(tty))
-			process_output('\a', tty);
-		return;
-	}
 	if (L_ECHO(tty)) {
 		finish_erasing(ldata);
 		if (c == '\n')
@@ -1370,29 +1383,123 @@
 				echo_set_canon_col(ldata);
 			echo_char(c, tty);
 		}
-		process_echoes(tty);
+		commit_echoes(tty);
 	}
 
 	if (parmrk)
 		put_tty_queue(c, ldata);
 
 	put_tty_queue(c, ldata);
+	return 0;
 }
 
-
-/**
- *	n_tty_write_wakeup	-	asynchronous I/O notifier
- *	@tty: tty device
- *
- *	Required for the ptys, serial driver etc. since processes
- *	that attach themselves to the master and rely on ASYNC
- *	IO must be woken up
- */
-
-static void n_tty_write_wakeup(struct tty_struct *tty)
+static inline void
+n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
 {
-	if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
-		kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+	struct n_tty_data *ldata = tty->disc_data;
+	int parmrk;
+
+	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+		start_tty(tty);
+		process_echoes(tty);
+	}
+	if (L_ECHO(tty)) {
+		finish_erasing(ldata);
+		/* Record the column of first canon char. */
+		if (ldata->canon_head == ldata->read_head)
+			echo_set_canon_col(ldata);
+		echo_char(c, tty);
+		commit_echoes(tty);
+	}
+	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+	if (parmrk)
+		put_tty_queue(c, ldata);
+	put_tty_queue(c, ldata);
+}
+
+static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+{
+	n_tty_receive_char_inline(tty, c);
+}
+
+static inline void
+n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+
+	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+		start_tty(tty);
+		process_echoes(tty);
+	}
+	if (L_ECHO(tty)) {
+		finish_erasing(ldata);
+		/* Record the column of first canon char. */
+		if (ldata->canon_head == ldata->read_head)
+			echo_set_canon_col(ldata);
+		echo_char(c, tty);
+		commit_echoes(tty);
+	}
+	put_tty_queue(c, ldata);
+}
+
+static inline void
+n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
+{
+	if (I_ISTRIP(tty))
+		c &= 0x7f;
+	if (I_IUCLC(tty) && L_IEXTEN(tty))
+		c = tolower(c);
+
+	if (I_IXON(tty)) {
+		if (c == STOP_CHAR(tty))
+			stop_tty(tty);
+		else if (c == START_CHAR(tty) ||
+			 (tty->stopped && !tty->flow_stopped && I_IXANY(tty) &&
+			  c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
+			  c != SUSP_CHAR(tty))) {
+			start_tty(tty);
+			process_echoes(tty);
+		}
+	}
+}
+
+static void
+n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
+{
+	char buf[64];
+
+	switch (flag) {
+	case TTY_BREAK:
+		n_tty_receive_break(tty);
+		break;
+	case TTY_PARITY:
+	case TTY_FRAME:
+		n_tty_receive_parity_error(tty, c);
+		break;
+	case TTY_OVERRUN:
+		n_tty_receive_overrun(tty);
+		break;
+	default:
+		printk(KERN_ERR "%s: unknown flag %d\n",
+		       tty_name(tty, buf), flag);
+		break;
+	}
+}
+
+static void
+n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+
+	ldata->lnext = 0;
+	if (likely(flag == TTY_NORMAL)) {
+		if (I_ISTRIP(tty))
+			c &= 0x7f;
+		if (I_IUCLC(tty) && L_IEXTEN(tty))
+			c = tolower(c);
+		n_tty_receive_char(tty, c);
+	} else
+		n_tty_receive_char_flagged(tty, c, flag);
 }
 
 /**
@@ -1406,86 +1513,220 @@
  *	been received. This function must be called from soft contexts
  *	not from interrupt context. The driver is responsible for making
  *	calls one at a time and in order (or using flush_to_ldisc)
+ *
+ *	n_tty_receive_buf()/producer path:
+ *		claims non-exclusive termios_rwsem
+ *		publishes read_head and canon_head
  */
 
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-			      char *fp, int count)
+static void
+n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
+			   char *fp, int count)
 {
 	struct n_tty_data *ldata = tty->disc_data;
-	const unsigned char *p;
-	char *f, flags = TTY_NORMAL;
-	int	i;
-	char	buf[64];
-	unsigned long cpuflags;
+	size_t n, head;
 
-	if (ldata->real_raw) {
-		raw_spin_lock_irqsave(&ldata->read_lock, cpuflags);
-		i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
-			N_TTY_BUF_SIZE - ldata->read_head);
-		i = min(count, i);
-		memcpy(ldata->read_buf + ldata->read_head, cp, i);
-		ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
-		ldata->read_cnt += i;
-		cp += i;
-		count -= i;
+	head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
+	n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
+	n = min_t(size_t, count, n);
+	memcpy(read_buf_addr(ldata, head), cp, n);
+	ldata->read_head += n;
+	cp += n;
+	count -= n;
 
-		i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
-			N_TTY_BUF_SIZE - ldata->read_head);
-		i = min(count, i);
-		memcpy(ldata->read_buf + ldata->read_head, cp, i);
-		ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
-		ldata->read_cnt += i;
-		raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
-	} else {
-		for (i = count, p = cp, f = fp; i; i--, p++) {
-			if (f)
-				flags = *f++;
-			switch (flags) {
-			case TTY_NORMAL:
-				n_tty_receive_char(tty, *p);
-				break;
-			case TTY_BREAK:
-				n_tty_receive_break(tty);
-				break;
-			case TTY_PARITY:
-			case TTY_FRAME:
-				n_tty_receive_parity_error(tty, *p);
-				break;
-			case TTY_OVERRUN:
-				n_tty_receive_overrun(tty);
-				break;
-			default:
-				printk(KERN_ERR "%s: unknown flag %d\n",
-				       tty_name(tty, buf), flags);
-				break;
+	head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
+	n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
+	n = min_t(size_t, count, n);
+	memcpy(read_buf_addr(ldata, head), cp, n);
+	ldata->read_head += n;
+}
+
+static void
+n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
+		      char *fp, int count)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	char flag = TTY_NORMAL;
+
+	while (count--) {
+		if (fp)
+			flag = *fp++;
+		if (likely(flag == TTY_NORMAL))
+			put_tty_queue(*cp++, ldata);
+		else
+			n_tty_receive_char_flagged(tty, *cp++, flag);
+	}
+}
+
+static void
+n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
+			  char *fp, int count)
+{
+	char flag = TTY_NORMAL;
+
+	while (count--) {
+		if (fp)
+			flag = *fp++;
+		if (likely(flag == TTY_NORMAL))
+			n_tty_receive_char_closing(tty, *cp++);
+		else
+			n_tty_receive_char_flagged(tty, *cp++, flag);
+	}
+}
+
+static void
+n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
+			  char *fp, int count)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	char flag = TTY_NORMAL;
+
+	while (count--) {
+		if (fp)
+			flag = *fp++;
+		if (likely(flag == TTY_NORMAL)) {
+			unsigned char c = *cp++;
+
+			if (I_ISTRIP(tty))
+				c &= 0x7f;
+			if (I_IUCLC(tty) && L_IEXTEN(tty))
+				c = tolower(c);
+			if (L_EXTPROC(tty)) {
+				put_tty_queue(c, ldata);
+				continue;
 			}
+			if (!test_bit(c, ldata->char_map))
+				n_tty_receive_char_inline(tty, c);
+			else if (n_tty_receive_char_special(tty, c) && count) {
+				if (fp)
+					flag = *fp++;
+				n_tty_receive_char_lnext(tty, *cp++, flag);
+				count--;
+			}
+		} else
+			n_tty_receive_char_flagged(tty, *cp++, flag);
+	}
+}
+
+static void
+n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp,
+		       char *fp, int count)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	char flag = TTY_NORMAL;
+
+	while (count--) {
+		if (fp)
+			flag = *fp++;
+		if (likely(flag == TTY_NORMAL)) {
+			unsigned char c = *cp++;
+
+			if (!test_bit(c, ldata->char_map))
+				n_tty_receive_char_fast(tty, c);
+			else if (n_tty_receive_char_special(tty, c) && count) {
+				if (fp)
+					flag = *fp++;
+				n_tty_receive_char_lnext(tty, *cp++, flag);
+				count--;
+			}
+		} else
+			n_tty_receive_char_flagged(tty, *cp++, flag);
+	}
+}
+
+static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
+			  char *fp, int count)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
+
+	if (ldata->real_raw)
+		n_tty_receive_buf_real_raw(tty, cp, fp, count);
+	else if (ldata->raw || (L_EXTPROC(tty) && !preops))
+		n_tty_receive_buf_raw(tty, cp, fp, count);
+	else if (tty->closing && !L_EXTPROC(tty))
+		n_tty_receive_buf_closing(tty, cp, fp, count);
+	else {
+		if (ldata->lnext) {
+			char flag = TTY_NORMAL;
+
+			if (fp)
+				flag = *fp++;
+			n_tty_receive_char_lnext(tty, *cp++, flag);
+			count--;
 		}
+
+		if (!preops && !I_PARMRK(tty))
+			n_tty_receive_buf_fast(tty, cp, fp, count);
+		else
+			n_tty_receive_buf_standard(tty, cp, fp, count);
+
+		flush_echoes(tty);
 		if (tty->ops->flush_chars)
 			tty->ops->flush_chars(tty);
 	}
 
-	set_room(tty);
-
-	if ((!ldata->icanon && (ldata->read_cnt >= ldata->minimum_to_wake)) ||
+	if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) ||
 		L_EXTPROC(tty)) {
 		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
 		if (waitqueue_active(&tty->read_wait))
 			wake_up_interruptible(&tty->read_wait);
 	}
+}
 
-	/*
-	 * Check the remaining room for the input canonicalization
-	 * mode.  We don't want to throttle the driver if we're in
-	 * canonical mode and don't have a newline yet!
-	 */
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+			      char *fp, int count)
+{
+	int room, n;
+
+	down_read(&tty->termios_rwsem);
+
 	while (1) {
-		tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
-		if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
+		room = receive_room(tty);
+		n = min(count, room);
+		if (!n)
 			break;
-		if (!tty_throttle_safe(tty))
-			break;
+		__receive_buf(tty, cp, fp, n);
+		cp += n;
+		if (fp)
+			fp += n;
+		count -= n;
 	}
-	__tty_set_flow_change(tty, 0);
+
+	tty->receive_room = room;
+	n_tty_check_throttle(tty);
+	up_read(&tty->termios_rwsem);
+}
+
+static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
+			      char *fp, int count)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	int room, n, rcvd = 0;
+
+	down_read(&tty->termios_rwsem);
+
+	while (1) {
+		room = receive_room(tty);
+		n = min(count, room);
+		if (!n) {
+			if (!room)
+				ldata->no_room = 1;
+			break;
+		}
+		__receive_buf(tty, cp, fp, n);
+		cp += n;
+		if (fp)
+			fp += n;
+		count -= n;
+		rcvd += n;
+	}
+
+	tty->receive_room = room;
+	n_tty_check_throttle(tty);
+	up_read(&tty->termios_rwsem);
+
+	return rcvd;
 }
 
 int is_ignored(int sig)
@@ -1505,7 +1746,7 @@
  *	guaranteed that this function will not be re-entered or in progress
  *	when the ldisc is closed.
  *
- *	Locking: Caller holds tty->termios_mutex
+ *	Locking: Caller holds tty->termios_rwsem
  */
 
 static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
@@ -1517,12 +1758,13 @@
 		canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
 	if (canon_change) {
 		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
+		ldata->line_start = 0;
 		ldata->canon_head = ldata->read_tail;
-		ldata->canon_data = 0;
 		ldata->erasing = 0;
+		ldata->lnext = 0;
 	}
 
-	if (canon_change && !L_ICANON(tty) && ldata->read_cnt)
+	if (canon_change && !L_ICANON(tty) && read_cnt(ldata))
 		wake_up_interruptible(&tty->read_wait);
 
 	ldata->icanon = (L_ICANON(tty) != 0);
@@ -1531,41 +1773,38 @@
 	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
 	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
 	    I_PARMRK(tty)) {
-		bitmap_zero(ldata->process_char_map, 256);
+		bitmap_zero(ldata->char_map, 256);
 
 		if (I_IGNCR(tty) || I_ICRNL(tty))
-			set_bit('\r', ldata->process_char_map);
+			set_bit('\r', ldata->char_map);
 		if (I_INLCR(tty))
-			set_bit('\n', ldata->process_char_map);
+			set_bit('\n', ldata->char_map);
 
 		if (L_ICANON(tty)) {
-			set_bit(ERASE_CHAR(tty), ldata->process_char_map);
-			set_bit(KILL_CHAR(tty), ldata->process_char_map);
-			set_bit(EOF_CHAR(tty), ldata->process_char_map);
-			set_bit('\n', ldata->process_char_map);
-			set_bit(EOL_CHAR(tty), ldata->process_char_map);
+			set_bit(ERASE_CHAR(tty), ldata->char_map);
+			set_bit(KILL_CHAR(tty), ldata->char_map);
+			set_bit(EOF_CHAR(tty), ldata->char_map);
+			set_bit('\n', ldata->char_map);
+			set_bit(EOL_CHAR(tty), ldata->char_map);
 			if (L_IEXTEN(tty)) {
-				set_bit(WERASE_CHAR(tty),
-					ldata->process_char_map);
-				set_bit(LNEXT_CHAR(tty),
-					ldata->process_char_map);
-				set_bit(EOL2_CHAR(tty),
-					ldata->process_char_map);
+				set_bit(WERASE_CHAR(tty), ldata->char_map);
+				set_bit(LNEXT_CHAR(tty), ldata->char_map);
+				set_bit(EOL2_CHAR(tty), ldata->char_map);
 				if (L_ECHO(tty))
 					set_bit(REPRINT_CHAR(tty),
-						ldata->process_char_map);
+						ldata->char_map);
 			}
 		}
 		if (I_IXON(tty)) {
-			set_bit(START_CHAR(tty), ldata->process_char_map);
-			set_bit(STOP_CHAR(tty), ldata->process_char_map);
+			set_bit(START_CHAR(tty), ldata->char_map);
+			set_bit(STOP_CHAR(tty), ldata->char_map);
 		}
 		if (L_ISIG(tty)) {
-			set_bit(INTR_CHAR(tty), ldata->process_char_map);
-			set_bit(QUIT_CHAR(tty), ldata->process_char_map);
-			set_bit(SUSP_CHAR(tty), ldata->process_char_map);
+			set_bit(INTR_CHAR(tty), ldata->char_map);
+			set_bit(QUIT_CHAR(tty), ldata->char_map);
+			set_bit(SUSP_CHAR(tty), ldata->char_map);
 		}
-		clear_bit(__DISABLED_CHAR, ldata->process_char_map);
+		clear_bit(__DISABLED_CHAR, ldata->char_map);
 		ldata->raw = 0;
 		ldata->real_raw = 0;
 	} else {
@@ -1608,9 +1847,7 @@
 	if (tty->link)
 		n_tty_packet_mode_flush(tty);
 
-	kfree(ldata->read_buf);
-	kfree(ldata->echo_buf);
-	kfree(ldata);
+	vfree(ldata);
 	tty->disc_data = NULL;
 }
 
@@ -1628,26 +1865,23 @@
 {
 	struct n_tty_data *ldata;
 
-	ldata = kzalloc(sizeof(*ldata), GFP_KERNEL);
+	/* Currently a malloc failure here can panic */
+	ldata = vmalloc(sizeof(*ldata));
 	if (!ldata)
 		goto err;
 
 	ldata->overrun_time = jiffies;
 	mutex_init(&ldata->atomic_read_lock);
 	mutex_init(&ldata->output_lock);
-	mutex_init(&ldata->echo_lock);
-	raw_spin_lock_init(&ldata->read_lock);
-
-	/* These are ugly. Currently a malloc failure here can panic */
-	ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-	ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-	if (!ldata->read_buf || !ldata->echo_buf)
-		goto err_free_bufs;
 
 	tty->disc_data = ldata;
 	reset_buffer_flags(tty->disc_data);
 	ldata->column = 0;
+	ldata->canon_column = 0;
 	ldata->minimum_to_wake = 1;
+	ldata->num_overrun = 0;
+	ldata->no_room = 0;
+	ldata->lnext = 0;
 	tty->closing = 0;
 	/* indicate buffer work may resume */
 	clear_bit(TTY_LDISC_HALTED, &tty->flags);
@@ -1655,10 +1889,6 @@
 	tty_unthrottle(tty);
 
 	return 0;
-err_free_bufs:
-	kfree(ldata->read_buf);
-	kfree(ldata->echo_buf);
-	kfree(ldata);
 err:
 	return -ENOMEM;
 }
@@ -1667,11 +1897,10 @@
 {
 	struct n_tty_data *ldata = tty->disc_data;
 
-	tty_flush_to_ldisc(tty);
 	if (ldata->icanon && !L_EXTPROC(tty)) {
-		if (ldata->canon_data)
+		if (ldata->canon_head != ldata->read_tail)
 			return 1;
-	} else if (ldata->read_cnt >= (amt ? amt : 1))
+	} else if (read_cnt(ldata) >= (amt ? amt : 1))
 		return 1;
 
 	return 0;
@@ -1692,6 +1921,9 @@
  *
  *	Called under the ldata->atomic_read_lock sem
  *
+ *	n_tty_read()/consumer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		read_tail published
  */
 
 static int copy_from_read_buf(struct tty_struct *tty,
@@ -1702,34 +1934,114 @@
 	struct n_tty_data *ldata = tty->disc_data;
 	int retval;
 	size_t n;
-	unsigned long flags;
 	bool is_eof;
+	size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
 
 	retval = 0;
-	raw_spin_lock_irqsave(&ldata->read_lock, flags);
-	n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
+	n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail);
 	n = min(*nr, n);
-	raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
 	if (n) {
-		retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
+		retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
 		n -= retval;
-		is_eof = n == 1 &&
-			ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
-		tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
+		is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
+		tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
 				ldata->icanon);
-		raw_spin_lock_irqsave(&ldata->read_lock, flags);
-		ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
-		ldata->read_cnt -= n;
+		ldata->read_tail += n;
 		/* Turn single EOF into zero-length read */
-		if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
+		if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata))
 			n = 0;
-		raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
 		*b += n;
 		*nr -= n;
 	}
 	return retval;
 }
 
+/**
+ *	canon_copy_from_read_buf	-	copy read data in canonical mode
+ *	@tty: terminal device
+ *	@b: user data
+ *	@nr: size of data
+ *
+ *	Helper function for n_tty_read.  It is only called when ICANON is on;
+ *	it copies one line of input up to and including the line-delimiting
+ *	character into the user-space buffer.
+ *
+ *	Called under the atomic_read_lock mutex
+ *
+ *	n_tty_read()/consumer path:
+ *		caller holds non-exclusive termios_rwsem
+ *		read_tail published
+ */
+
+static int canon_copy_from_read_buf(struct tty_struct *tty,
+				    unsigned char __user **b,
+				    size_t *nr)
+{
+	struct n_tty_data *ldata = tty->disc_data;
+	size_t n, size, more, c;
+	size_t eol;
+	size_t tail;
+	int ret, found = 0;
+	bool eof_push = 0;
+
+	/* N.B. avoid overrun if nr == 0 */
+	n = min(*nr, read_cnt(ldata));
+	if (!n)
+		return 0;
+
+	tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
+	size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
+
+	n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
+		    __func__, *nr, tail, n, size);
+
+	eol = find_next_bit(ldata->read_flags, size, tail);
+	more = n - (size - tail);
+	if (eol == N_TTY_BUF_SIZE && more) {
+		/* scan wrapped without finding set bit */
+		eol = find_next_bit(ldata->read_flags, more, 0);
+		if (eol != more)
+			found = 1;
+	} else if (eol != size)
+		found = 1;
+
+	size = N_TTY_BUF_SIZE - tail;
+	n = (found + eol + size) & (N_TTY_BUF_SIZE - 1);
+	c = n;
+
+	if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
+		n--;
+		eof_push = !n && ldata->read_tail != ldata->line_start;
+	}
+
+	n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
+		    __func__, eol, found, n, c, size, more);
+
+	if (n > size) {
+		ret = copy_to_user(*b, read_buf_addr(ldata, tail), size);
+		if (ret)
+			return -EFAULT;
+		ret = copy_to_user(*b + size, ldata->read_buf, n - size);
+	} else
+		ret = copy_to_user(*b, read_buf_addr(ldata, tail), n);
+
+	if (ret)
+		return -EFAULT;
+	*b += n;
+	*nr -= n;
+
+	if (found)
+		clear_bit(eol, ldata->read_flags);
+	smp_mb__after_clear_bit();
+	ldata->read_tail += c;
+
+	if (found) {
+		ldata->line_start = ldata->read_tail;
+		tty_audit_push(tty);
+	}
+	return eof_push ? -EAGAIN : 0;
+}
+
 extern ssize_t redirected_tty_write(struct file *, const char __user *,
 							size_t, loff_t *);
 
@@ -1787,6 +2099,10 @@
  *	a hangup. Always called in user context, may sleep.
  *
  *	This code must be sure never to sleep through a hangup.
+ *
+ *	n_tty_read()/consumer path:
+ *		claims non-exclusive termios_rwsem
+ *		publishes read_tail
  */
 
 static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
@@ -1798,16 +2114,27 @@
 	int c;
 	int minimum, time;
 	ssize_t retval = 0;
-	ssize_t size;
 	long timeout;
 	unsigned long flags;
 	int packet;
 
-do_it_again:
 	c = job_control(tty, file);
 	if (c < 0)
 		return c;
 
+	/*
+	 *	Internal serialization of reads.
+	 */
+	if (file->f_flags & O_NONBLOCK) {
+		if (!mutex_trylock(&ldata->atomic_read_lock))
+			return -EAGAIN;
+	} else {
+		if (mutex_lock_interruptible(&ldata->atomic_read_lock))
+			return -ERESTARTSYS;
+	}
+
+	down_read(&tty->termios_rwsem);
+
 	minimum = time = 0;
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (!ldata->icanon) {
@@ -1825,16 +2152,6 @@
 		}
 	}
 
-	/*
-	 *	Internal serialization of reads.
-	 */
-	if (file->f_flags & O_NONBLOCK) {
-		if (!mutex_trylock(&ldata->atomic_read_lock))
-			return -EAGAIN;
-	} else {
-		if (mutex_lock_interruptible(&ldata->atomic_read_lock))
-			return -ERESTARTSYS;
-	}
 	packet = tty->packet;
 
 	add_wait_queue(&tty->read_wait, &wait);
@@ -1883,7 +2200,11 @@
 				break;
 			}
 			n_tty_set_room(tty);
+			up_read(&tty->termios_rwsem);
+
 			timeout = schedule_timeout(timeout);
+
+			down_read(&tty->termios_rwsem);
 			continue;
 		}
 		__set_current_state(TASK_RUNNING);
@@ -1899,45 +2220,11 @@
 		}
 
 		if (ldata->icanon && !L_EXTPROC(tty)) {
-			/* N.B. avoid overrun if nr == 0 */
-			raw_spin_lock_irqsave(&ldata->read_lock, flags);
-			while (nr && ldata->read_cnt) {
-				int eol;
-
-				eol = test_and_clear_bit(ldata->read_tail,
-						ldata->read_flags);
-				c = ldata->read_buf[ldata->read_tail];
-				ldata->read_tail = ((ldata->read_tail+1) &
-						  (N_TTY_BUF_SIZE-1));
-				ldata->read_cnt--;
-				if (eol) {
-					/* this test should be redundant:
-					 * we shouldn't be reading data if
-					 * canon_data is 0
-					 */
-					if (--ldata->canon_data < 0)
-						ldata->canon_data = 0;
-				}
-				raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-
-				if (!eol || (c != __DISABLED_CHAR)) {
-					if (tty_put_user(tty, c, b++)) {
-						retval = -EFAULT;
-						b--;
-						raw_spin_lock_irqsave(&ldata->read_lock, flags);
-						break;
-					}
-					nr--;
-				}
-				if (eol) {
-					tty_audit_push(tty);
-					raw_spin_lock_irqsave(&ldata->read_lock, flags);
-					break;
-				}
-				raw_spin_lock_irqsave(&ldata->read_lock, flags);
-			}
-			raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
-			if (retval)
+			retval = canon_copy_from_read_buf(tty, &b, &nr);
+			if (retval == -EAGAIN) {
+				retval = 0;
+				continue;
+			} else if (retval)
 				break;
 		} else {
 			int uncopied;
@@ -1951,24 +2238,7 @@
 			}
 		}
 
-		/* If there is enough space in the read buffer now, let the
-		 * low-level driver know. We use n_tty_chars_in_buffer() to
-		 * check the buffer, as it now knows about canonical mode.
-		 * Otherwise, if the driver is throttled and the line is
-		 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
-		 * we won't get any more characters.
-		 */
-		while (1) {
-			tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
-			if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
-				break;
-			if (!tty->count)
-				break;
-			n_tty_set_room(tty);
-			if (!tty_unthrottle_safe(tty))
-				break;
-		}
-		__tty_set_flow_change(tty, 0);
+		n_tty_check_unthrottle(tty);
 
 		if (b - buf >= minimum)
 			break;
@@ -1982,15 +2252,11 @@
 		ldata->minimum_to_wake = minimum;
 
 	__set_current_state(TASK_RUNNING);
-	size = b - buf;
-	if (size) {
-		retval = size;
-		if (nr)
-			clear_bit(TTY_PUSH, &tty->flags);
-	} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-		goto do_it_again;
+	if (b - buf)
+		retval = b - buf;
 
 	n_tty_set_room(tty);
+	up_read(&tty->termios_rwsem);
 	return retval;
 }
 
@@ -2031,6 +2297,8 @@
 			return retval;
 	}
 
+	down_read(&tty->termios_rwsem);
+
 	/* Write out any echoed characters that are still pending */
 	process_echoes(tty);
 
@@ -2084,13 +2352,18 @@
 			retval = -EAGAIN;
 			break;
 		}
+		up_read(&tty->termios_rwsem);
+
 		schedule();
+
+		down_read(&tty->termios_rwsem);
 	}
 break_out:
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&tty->write_wait, &wait);
 	if (b - buf != nr && tty->fasync)
 		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+	up_read(&tty->termios_rwsem);
 	return (b - buf) ? b - buf : retval;
 }
 
@@ -2139,19 +2412,19 @@
 
 static unsigned long inq_canon(struct n_tty_data *ldata)
 {
-	int nr, head, tail;
+	size_t nr, head, tail;
 
-	if (!ldata->canon_data)
+	if (ldata->canon_head == ldata->read_tail)
 		return 0;
 	head = ldata->canon_head;
 	tail = ldata->read_tail;
-	nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+	nr = head - tail;
 	/* Skip EOF-chars.. */
 	while (head != tail) {
-		if (test_bit(tail, ldata->read_flags) &&
-		    ldata->read_buf[tail] == __DISABLED_CHAR)
+		if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) &&
+		    read_buf(ldata, tail) == __DISABLED_CHAR)
 			nr--;
-		tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+		tail++;
 	}
 	return nr;
 }
@@ -2166,10 +2439,12 @@
 	case TIOCOUTQ:
 		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
 	case TIOCINQ:
-		/* FIXME: Locking */
-		retval = ldata->read_cnt;
+		down_write(&tty->termios_rwsem);
 		if (L_ICANON(tty))
 			retval = inq_canon(ldata);
+		else
+			retval = read_cnt(ldata);
+		up_write(&tty->termios_rwsem);
 		return put_user(retval, (unsigned int __user *) arg);
 	default:
 		return n_tty_ioctl_helper(tty, file, cmd, arg);
@@ -2203,6 +2478,7 @@
 	.receive_buf     = n_tty_receive_buf,
 	.write_wakeup    = n_tty_write_wakeup,
 	.fasync		 = n_tty_fasync,
+	.receive_buf2	 = n_tty_receive_buf2,
 };
 
 /**
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index abfd990..25c9bc7 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -89,17 +89,13 @@
  *	pty_space	-	report space left for writing
  *	@to: tty we are writing into
  *
- *	The tty buffers allow 64K but we sneak a peak and clip at 8K this
- *	allows a lot of overspill room for echo and other fun messes to
- *	be handled properly
+ *	Limit the buffer space used by ptys to 8k.
  */
 
 static int pty_space(struct tty_struct *to)
 {
-	int n = 8192 - to->port->buf.memory_used;
-	if (n < 0)
-		return 0;
-	return n;
+	int n = tty_buffer_space_avail(to->port);
+	return min(n, 8192);
 }
 
 /**
@@ -125,10 +121,8 @@
 		/* Stuff the data into the input queue of the other end */
 		c = tty_insert_flip_string(to->port, buf, c);
 		/* And shovel */
-		if (c) {
+		if (c)
 			tty_flip_buffer_push(to->port);
-			tty_wakeup(tty);
-		}
 	}
 	return c;
 }
@@ -287,7 +281,7 @@
 	struct tty_struct *pty = tty->link;
 
 	/* For a PTY we need to lock the tty side */
-	mutex_lock(&tty->termios_mutex);
+	mutex_lock(&tty->winsize_mutex);
 	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
 		goto done;
 
@@ -314,7 +308,7 @@
 	tty->winsize = *ws;
 	pty->winsize = *ws;	/* Never used so will go away soon */
 done:
-	mutex_unlock(&tty->termios_mutex);
+	mutex_unlock(&tty->winsize_mutex);
 	return 0;
 }
 
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 86c00b1..570df9d 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -3062,7 +3062,7 @@
  */
 static int serial8250_probe(struct platform_device *dev)
 {
-	struct plat_serial8250_port *p = dev->dev.platform_data;
+	struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
 	struct uart_8250_port uart;
 	int ret, i, irqflag = 0;
 
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 76a8daa..daf710f 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -57,11 +57,25 @@
 
 struct dw8250_data {
 	int		last_lcr;
+	int		last_mcr;
 	int		line;
 	struct clk	*clk;
 	u8		usr_reg;
 };
 
+static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
+{
+	struct dw8250_data *d = p->private_data;
+
+	/* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */
+	if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) {
+		value |= UART_MSR_CTS;
+		value &= ~UART_MSR_DCTS;
+	}
+
+	return value;
+}
+
 static void dw8250_serial_out(struct uart_port *p, int offset, int value)
 {
 	struct dw8250_data *d = p->private_data;
@@ -69,15 +83,17 @@
 	if (offset == UART_LCR)
 		d->last_lcr = value;
 
-	offset <<= p->regshift;
-	writeb(value, p->membase + offset);
+	if (offset == UART_MCR)
+		d->last_mcr = value;
+
+	writeb(value, p->membase + (offset << p->regshift));
 }
 
 static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
 {
-	offset <<= p->regshift;
+	unsigned int value = readb(p->membase + (offset << p->regshift));
 
-	return readb(p->membase + offset);
+	return dw8250_modify_msr(p, offset, value);
 }
 
 /* Read Back (rb) version to ensure register access ording. */
@@ -94,15 +110,17 @@
 	if (offset == UART_LCR)
 		d->last_lcr = value;
 
-	offset <<= p->regshift;
-	writel(value, p->membase + offset);
+	if (offset == UART_MCR)
+		d->last_mcr = value;
+
+	writel(value, p->membase + (offset << p->regshift));
 }
 
 static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
 {
-	offset <<= p->regshift;
+	unsigned int value = readl(p->membase + (offset << p->regshift));
 
-	return readl(p->membase + offset);
+	return dw8250_modify_msr(p, offset, value);
 }
 
 static int dw8250_handle_irq(struct uart_port *p)
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 946ddd2..c100d63 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -194,7 +194,7 @@
 		options++;
 		device->baud = simple_strtoul(options, NULL, 0);
 		length = min(strcspn(options, " ") + 1,
-			     sizeof(device->options));
+			     (size_t)(sizeof(device->options)));
 		strlcpy(device->options, options, length);
 	} else {
 		device->baud = probe_baud(port);
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index 916cc19..5f3bba1 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -95,25 +95,23 @@
 	struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	struct serial8250_em_priv *priv;
 	struct uart_8250_port up;
-	int ret = -EINVAL;
+	int ret;
 
 	if (!regs || !irq) {
 		dev_err(&pdev->dev, "missing registers or irq\n");
-		goto err0;
+		return -EINVAL;
 	}
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
 		dev_err(&pdev->dev, "unable to allocate private data\n");
-		ret = -ENOMEM;
-		goto err0;
+		return -ENOMEM;
 	}
 
-	priv->sclk = clk_get(&pdev->dev, "sclk");
+	priv->sclk = devm_clk_get(&pdev->dev, "sclk");
 	if (IS_ERR(priv->sclk)) {
 		dev_err(&pdev->dev, "unable to get clock\n");
-		ret = PTR_ERR(priv->sclk);
-		goto err1;
+		return PTR_ERR(priv->sclk);
 	}
 
 	memset(&up, 0, sizeof(up));
@@ -136,20 +134,13 @@
 	ret = serial8250_register_8250_port(&up);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "unable to register 8250 port\n");
-		goto err2;
+		clk_disable(priv->sclk);
+		return ret;
 	}
 
 	priv->line = ret;
 	platform_set_drvdata(pdev, priv);
 	return 0;
-
- err2:
-	clk_disable(priv->sclk);
-	clk_put(priv->sclk);
- err1:
-	kfree(priv);
- err0:
-	return ret;
 }
 
 static int serial8250_em_remove(struct platform_device *pdev)
@@ -158,8 +149,6 @@
 
 	serial8250_unregister_port(priv->line);
 	clk_disable(priv->sclk);
-	clk_put(priv->sclk);
-	kfree(priv);
 	return 0;
 }
 
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index c52948b..c810da7 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1565,6 +1565,7 @@
 #define PCI_DEVICE_ID_COMMTECH_4228PCIE	0x0021
 #define PCI_DEVICE_ID_COMMTECH_4222PCIE	0x0022
 #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
+#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
 
 #define PCI_VENDOR_ID_SUNIX		0x1fd4
 #define PCI_DEVICE_ID_SUNIX_1999	0x1999
@@ -1587,8 +1588,8 @@
 	* ADDI-DATA GmbH communication cards <info@addi-data.com>
 	*/
 	{
-		.vendor         = PCI_VENDOR_ID_ADDIDATA_OLD,
-		.device         = PCI_DEVICE_ID_ADDIDATA_APCI7800,
+		.vendor         = PCI_VENDOR_ID_AMCC,
+		.device         = PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 		.setup          = addidata_apci7800_setup,
@@ -4697,8 +4698,8 @@
 		0,
 		pbn_b0_1_115200 },
 
-	{	PCI_VENDOR_ID_ADDIDATA_OLD,
-		PCI_DEVICE_ID_ADDIDATA_APCI7800,
+	{	PCI_VENDOR_ID_AMCC,
+		PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800,
 		PCI_ANY_ID,
 		PCI_ANY_ID,
 		0,
@@ -4797,6 +4798,12 @@
 		PCI_VENDOR_ID_IBM, 0x0299,
 		0, 0, pbn_b0_bt_2_115200 },
 
+	/*
+	 * other NetMos 9835 devices are most likely handled by the
+	 * parport_serial driver, check drivers/parport/parport_serial.c
+	 * before adding them here.
+	 */
+
 	{	PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
 		0xA000, 0x1000,
 		0, 0, pbn_b0_1_115200 },
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index a1ba94d..f3b306e 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -116,6 +116,8 @@
 	  This builds standard PCI serial support. You may be able to
 	  disable this feature if you only need legacy serial support.
 	  Saves about 9K.
+	  Note that serial ports on NetMos 9835 Multi-I/O cards are handled
+	  by the parport_serial driver, enabled with CONFIG_PARPORT_SERIAL.
 
 config SERIAL_8250_HP300
 	tristate
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 1456673..cc4c868 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -291,13 +291,13 @@
 
 config SERIAL_MAX310X
 	bool "MAX310X support"
-	depends on SPI
+	depends on SPI_MASTER
 	select SERIAL_CORE
-	select REGMAP_SPI if SPI
+	select REGMAP_SPI if SPI_MASTER
 	default n
 	help
 	  This selects support for an advanced UART from Maxim (Dallas).
-	  Supported ICs are MAX3107, MAX3108.
+	  Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830.
 	  Each IC contains 128 words each of receive and transmit FIFO
 	  that can be controlled through I2C or high-speed SPI.
 
@@ -1401,13 +1401,16 @@
 	  Enable a Xilinx PS UART port to be the system console.
 
 config SERIAL_AR933X
-	bool "AR933X serial port support"
-	depends on SOC_AR933X
+	tristate "AR933X serial port support"
+	depends on HAVE_CLK && SOC_AR933X
 	select SERIAL_CORE
 	help
 	  If you have an Atheros AR933X SOC based board and want to use the
 	  built-in UART of the SoC, say Y to this option.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called ar933x_uart.
+
 config SERIAL_AR933X_CONSOLE
 	bool "Console on AR933X serial port"
 	depends on SERIAL_AR933X=y
@@ -1424,8 +1427,8 @@
 	  to support.
 
 config SERIAL_EFM32_UART
-	tristate "EFM32 UART/USART port."
-	depends on ARCH_EFM32
+	tristate "EFM32 UART/USART port"
+	depends on ARM && (ARCH_EFM32 || COMPILE_TEST)
 	select SERIAL_CORE
 	help
 	  This driver support the USART and UART ports on
@@ -1497,6 +1500,22 @@
 	  If you have enabled the lpuart serial port on the Freescale SoCs,
 	  you can make it the console by answering Y to this option.
 
+config SERIAL_ST_ASC
+	tristate "ST ASC serial port support"
+	select SERIAL_CORE
+	help
+	  This driver is for the on-chip Asychronous Serial Controller on
+	  STMicroelectronics STi SoCs.
+	  ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality.
+	  It support all industry standard baud rates.
+
+	  If unsure, say N.
+
+config SERIAL_ST_ASC_CONSOLE
+	bool "Support for console on ST ASC"
+	depends on SERIAL_ST_ASC=y
+	select SERIAL_CORE_CONSOLE
+
 endmenu
 
 endif # TTY
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index cf650f0..47b679c 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -65,6 +65,7 @@
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
 obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
+obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o
 obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
 obj-$(CONFIG_SERIAL_TIMBERDALE)	+= timbuart.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index c6bdb94..18e038f 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -139,7 +139,9 @@
 		uart_insert_char(port, 0, 0, ch, flag);
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
 }
 
 static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
@@ -408,7 +410,8 @@
 
 static int altera_jtaguart_probe(struct platform_device *pdev)
 {
-	struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
+	struct altera_jtaguart_platform_uart *platp =
+			dev_get_platdata(&pdev->dev);
 	struct uart_port *port;
 	struct resource *res_irq, *res_mem;
 	int i = pdev->id;
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 1d46966..6431472 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -231,7 +231,9 @@
 				 flag);
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
 }
 
 static void altera_uart_tx_chars(struct altera_uart *pp)
@@ -534,7 +536,7 @@
 
 static int altera_uart_probe(struct platform_device *pdev)
 {
-	struct altera_uart_platform_uart *platp = pdev->dev.platform_data;
+	struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev);
 	struct uart_port *port;
 	struct resource *res_mem;
 	struct resource *res_irq;
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index c368405..8b90f0b 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -721,7 +721,7 @@
 	uap->port.flags = UPF_BOOT_AUTOCONF;
 	uap->port.line = i;
 	uap->dev = dev;
-	uap->data = dev->dev.platform_data;
+	uap->data = dev_get_platdata(&dev->dev);
 
 	amba_ports[i] = uap;
 
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 28b35ad..aaa2286 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -265,7 +265,7 @@
 static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap)
 {
 	/* DMA is the sole user of the platform data right now */
-	struct amba_pl011_data *plat = uap->port.dev->platform_data;
+	struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev);
 	struct dma_slave_config tx_conf = {
 		.dst_addr = uap->port.mapbase + UART01x_DR,
 		.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
@@ -677,6 +677,8 @@
  * Locking: called with port lock held and IRQs disabled.
  */
 static void pl011_dma_flush_buffer(struct uart_port *port)
+__releases(&uap->port.lock)
+__acquires(&uap->port.lock)
 {
 	struct uart_amba_port *uap = (struct uart_amba_port *)port;
 
@@ -1198,6 +1200,8 @@
 }
 
 static void pl011_rx_chars(struct uart_amba_port *uap)
+__releases(&uap->port.lock)
+__acquires(&uap->port.lock)
 {
 	pl011_fifo_to_tty(uap);
 
@@ -1497,10 +1501,10 @@
 	uap->im = readw(uap->port.membase + UART011_IMSC);
 	writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC);
 
-	if (uap->port.dev->platform_data) {
+	if (dev_get_platdata(uap->port.dev)) {
 		struct amba_pl011_data *plat;
 
-		plat = uap->port.dev->platform_data;
+		plat = dev_get_platdata(uap->port.dev);
 		if (plat->init)
 			plat->init();
 	}
@@ -1645,10 +1649,10 @@
 	/* Optionally let pins go into sleep states */
 	pinctrl_pm_select_sleep_state(port->dev);
 
-	if (uap->port.dev->platform_data) {
+	if (dev_get_platdata(uap->port.dev)) {
 		struct amba_pl011_data *plat;
 
-		plat = uap->port.dev->platform_data;
+		plat = dev_get_platdata(uap->port.dev);
 		if (plat->exit)
 			plat->exit();
 	}
@@ -2002,10 +2006,10 @@
 	if (ret)
 		return ret;
 
-	if (uap->port.dev->platform_data) {
+	if (dev_get_platdata(uap->port.dev)) {
 		struct amba_pl011_data *plat;
 
-		plat = uap->port.dev->platform_data;
+		plat = dev_get_platdata(uap->port.dev);
 		if (plat->init)
 			plat->init();
 	}
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 6331464..de11ab8 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -125,7 +125,9 @@
 		status = UART_GET_STATUS(port);
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
 }
 
 static void apbuart_tx_chars(struct uart_port *port)
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 27f20c5..acd03af 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -17,6 +17,8 @@
 #include <linux/sysrq.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
@@ -24,11 +26,11 @@
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/clk.h>
 
 #include <asm/div64.h>
 
 #include <asm/mach-ath79/ar933x_uart.h>
-#include <asm/mach-ath79/ar933x_uart_platform.h>
 
 #define DRIVER_NAME "ar933x-uart"
 
@@ -47,8 +49,14 @@
 	unsigned int		ier;	/* shadow Interrupt Enable Register */
 	unsigned int		min_baud;
 	unsigned int		max_baud;
+	struct clk		*clk;
 };
 
+static inline bool ar933x_uart_console_enabled(void)
+{
+	return config_enabled(CONFIG_SERIAL_AR933X_CONSOLE);
+}
+
 static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
 					    int offset)
 {
@@ -322,7 +330,9 @@
 			tty_insert_flip_char(port, ch, TTY_NORMAL);
 	} while (max_count-- > 0);
 
+	spin_unlock(&up->port.lock);
 	tty_flip_buffer_push(port);
+	spin_lock(&up->port.lock);
 }
 
 static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
@@ -497,8 +507,6 @@
 	.verify_port	= ar933x_uart_verify_port,
 };
 
-#ifdef CONFIG_SERIAL_AR933X_CONSOLE
-
 static struct ar933x_uart_port *
 ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
 
@@ -597,80 +605,88 @@
 
 static void ar933x_uart_add_console_port(struct ar933x_uart_port *up)
 {
+	if (!ar933x_uart_console_enabled())
+		return;
+
 	ar933x_console_ports[up->port.line] = up;
 }
 
-#define AR933X_SERIAL_CONSOLE	(&ar933x_uart_console)
-
-#else
-
-static inline void ar933x_uart_add_console_port(struct ar933x_uart_port *up) {}
-
-#define AR933X_SERIAL_CONSOLE	NULL
-
-#endif /* CONFIG_SERIAL_AR933X_CONSOLE */
-
 static struct uart_driver ar933x_uart_driver = {
 	.owner		= THIS_MODULE,
 	.driver_name	= DRIVER_NAME,
 	.dev_name	= "ttyATH",
 	.nr		= CONFIG_SERIAL_AR933X_NR_UARTS,
-	.cons		= AR933X_SERIAL_CONSOLE,
+	.cons		= NULL, /* filled in runtime */
 };
 
 static int ar933x_uart_probe(struct platform_device *pdev)
 {
-	struct ar933x_uart_platform_data *pdata;
 	struct ar933x_uart_port *up;
 	struct uart_port *port;
 	struct resource *mem_res;
 	struct resource *irq_res;
+	struct device_node *np;
 	unsigned int baud;
 	int id;
 	int ret;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata)
-		return -EINVAL;
-
-	id = pdev->id;
-	if (id == -1)
-		id = 0;
+	np = pdev->dev.of_node;
+	if (config_enabled(CONFIG_OF) && np) {
+		id = of_alias_get_id(np, "serial");
+		if (id < 0) {
+			dev_err(&pdev->dev, "unable to get alias id, err=%d\n",
+				id);
+			return id;
+		}
+	} else {
+		id = pdev->id;
+		if (id == -1)
+			id = 0;
+	}
 
 	if (id > CONFIG_SERIAL_AR933X_NR_UARTS)
 		return -EINVAL;
 
-	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res) {
-		dev_err(&pdev->dev, "no MEM resource\n");
-		return -EINVAL;
-	}
-
 	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!irq_res) {
 		dev_err(&pdev->dev, "no IRQ resource\n");
 		return -EINVAL;
 	}
 
-	up = kzalloc(sizeof(struct ar933x_uart_port), GFP_KERNEL);
+	up = devm_kzalloc(&pdev->dev, sizeof(struct ar933x_uart_port),
+			  GFP_KERNEL);
 	if (!up)
 		return -ENOMEM;
 
-	port = &up->port;
-	port->mapbase = mem_res->start;
-
-	port->membase = ioremap(mem_res->start, AR933X_UART_REGS_SIZE);
-	if (!port->membase) {
-		ret = -ENOMEM;
-		goto err_free_up;
+	up->clk = devm_clk_get(&pdev->dev, "uart");
+	if (IS_ERR(up->clk)) {
+		dev_err(&pdev->dev, "unable to get UART clock\n");
+		return PTR_ERR(up->clk);
 	}
 
+	port = &up->port;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	port->membase = devm_ioremap_resource(&pdev->dev, mem_res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
+
+	ret = clk_prepare_enable(up->clk);
+	if (ret)
+		return ret;
+
+	port->uartclk = clk_get_rate(up->clk);
+	if (!port->uartclk) {
+		ret = -EINVAL;
+		goto err_disable_clk;
+	}
+
+	port->mapbase = mem_res->start;
 	port->line = id;
 	port->irq = irq_res->start;
 	port->dev = &pdev->dev;
 	port->type = PORT_AR933X;
 	port->iotype = UPIO_MEM32;
-	port->uartclk = pdata->uartclk;
 
 	port->regshift = 2;
 	port->fifosize = AR933X_UART_FIFO_SIZE;
@@ -686,15 +702,13 @@
 
 	ret = uart_add_one_port(&ar933x_uart_driver, &up->port);
 	if (ret)
-		goto err_unmap;
+		goto err_disable_clk;
 
 	platform_set_drvdata(pdev, up);
 	return 0;
 
-err_unmap:
-	iounmap(up->port.membase);
-err_free_up:
-	kfree(up);
+err_disable_clk:
+	clk_disable_unprepare(up->clk);
 	return ret;
 }
 
@@ -703,23 +717,30 @@
 	struct ar933x_uart_port *up;
 
 	up = platform_get_drvdata(pdev);
-	platform_set_drvdata(pdev, NULL);
 
 	if (up) {
 		uart_remove_one_port(&ar933x_uart_driver, &up->port);
-		iounmap(up->port.membase);
-		kfree(up);
+		clk_disable_unprepare(up->clk);
 	}
 
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id ar933x_uart_of_ids[] = {
+	{ .compatible = "qca,ar9330-uart" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids);
+#endif
+
 static struct platform_driver ar933x_uart_platform_driver = {
 	.probe		= ar933x_uart_probe,
 	.remove		= ar933x_uart_remove,
 	.driver		= {
 		.name		= DRIVER_NAME,
 		.owner		= THIS_MODULE,
+		.of_match_table = of_match_ptr(ar933x_uart_of_ids),
 	},
 };
 
@@ -727,7 +748,9 @@
 {
 	int ret;
 
-	ar933x_uart_driver.nr = CONFIG_SERIAL_AR933X_NR_UARTS;
+	if (ar933x_uart_console_enabled())
+		ar933x_uart_driver.cons = &ar933x_uart_console;
+
 	ret = uart_register_driver(&ar933x_uart_driver);
 	if (ret)
 		goto err_out;
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 22f280a..569872f 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -209,9 +209,9 @@
 	arc_serial_tx_chars(uart);
 }
 
-static void arc_serial_rx_chars(struct arc_uart_port *uart)
+static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)
 {
-	unsigned int status, ch, flg = 0;
+	unsigned int ch, flg = 0;
 
 	/*
 	 * UART has 4 deep RX-FIFO. Driver's recongnition of this fact
@@ -222,11 +222,11 @@
 	 * before RX-EMPTY=0, implies some sort of buffering going on in the
 	 * controller, which is indeed the Rx-FIFO.
 	 */
-	while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)) {
-
-		ch = UART_GET_DATA(uart);
-		uart->port.icount.rx++;
-
+	do {
+		/*
+		 * This could be an Rx Intr for err (no data),
+		 * so check err and clear that Intr first
+		 */
 		if (unlikely(status & (RXOERR | RXFERR))) {
 			if (status & RXOERR) {
 				uart->port.icount.overrun++;
@@ -242,14 +242,19 @@
 		} else
 			flg = TTY_NORMAL;
 
-		if (unlikely(uart_handle_sysrq_char(&uart->port, ch)))
-			goto done;
+		if (status & RXEMPTY)
+			continue;
 
-		uart_insert_char(&uart->port, status, RXOERR, ch, flg);
+		ch = UART_GET_DATA(uart);
+		uart->port.icount.rx++;
 
-done:
+		if (!(uart_handle_sysrq_char(&uart->port, ch)))
+			uart_insert_char(&uart->port, status, RXOERR, ch, flg);
+
+		spin_unlock(&uart->port.lock);
 		tty_flip_buffer_push(&uart->port.state->port);
-	}
+		spin_lock(&uart->port.lock);
+	} while (!((status = UART_GET_STATUS(uart)) & RXEMPTY));
 }
 
 /*
@@ -292,11 +297,11 @@
 	 * notifications from the UART Controller.
 	 * To demultiplex between the two, we check the relevant bits
 	 */
-	if ((status & RXIENB) && !(status & RXEMPTY)) {
+	if (status & RXIENB) {
 
 		/* already in ISR, no need of xx_irqsave */
 		spin_lock(&uart->port.lock);
-		arc_serial_rx_chars(uart);
+		arc_serial_rx_chars(uart, status);
 		spin_unlock(&uart->port.lock);
 	}
 
@@ -528,7 +533,7 @@
 	unsigned long *plat_data;
 	struct arc_uart_port *uart = &arc_uart_ports[dev_id];
 
-	plat_data = ((unsigned long *)(pdev->dev.platform_data));
+	plat_data = (unsigned long *)dev_get_platdata(&pdev->dev);
 	if (!plat_data)
 		return -ENODEV;
 
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 691265f..d067285 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -39,8 +39,8 @@
 #include <linux/atmel_pdc.h>
 #include <linux/atmel_serial.h>
 #include <linux/uaccess.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/atmel.h>
+#include <linux/timer.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -98,6 +98,7 @@
 #define UART_PUT_BRGR(port,v)	__raw_writel(v, (port)->membase + ATMEL_US_BRGR)
 #define UART_PUT_RTOR(port,v)	__raw_writel(v, (port)->membase + ATMEL_US_RTOR)
 #define UART_PUT_TTGR(port, v)	__raw_writel(v, (port)->membase + ATMEL_US_TTGR)
+#define UART_GET_IP_NAME(port)	__raw_readl((port)->membase + ATMEL_US_NAME)
 
  /* PDC registers */
 #define UART_PUT_PTCR(port,v)	__raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
@@ -140,13 +141,25 @@
 	u32			backup_imr;	/* IMR saved during suspend */
 	int			break_active;	/* break being received */
 
-	short			use_dma_rx;	/* enable PDC receiver */
+	bool			use_dma_rx;	/* enable DMA receiver */
+	bool			use_pdc_rx;	/* enable PDC receiver */
 	short			pdc_rx_idx;	/* current PDC RX buffer */
 	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */
 
-	short			use_dma_tx;	/* enable PDC transmitter */
+	bool			use_dma_tx;     /* enable DMA transmitter */
+	bool			use_pdc_tx;	/* enable PDC transmitter */
 	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */
 
+	spinlock_t			lock_tx;	/* port lock */
+	spinlock_t			lock_rx;	/* port lock */
+	struct dma_chan			*chan_tx;
+	struct dma_chan			*chan_rx;
+	struct dma_async_tx_descriptor	*desc_tx;
+	struct dma_async_tx_descriptor	*desc_rx;
+	dma_cookie_t			cookie_tx;
+	dma_cookie_t			cookie_rx;
+	struct scatterlist		sg_tx;
+	struct scatterlist		sg_rx;
 	struct tasklet_struct	tasklet;
 	unsigned int		irq_status;
 	unsigned int		irq_status_prev;
@@ -155,6 +168,14 @@
 
 	struct serial_rs485	rs485;		/* rs485 settings */
 	unsigned int		tx_done_mask;
+	bool			is_usart;	/* usart or uart */
+	struct timer_list	uart_timer;	/* uart timer */
+	int (*prepare_rx)(struct uart_port *port);
+	int (*prepare_tx)(struct uart_port *port);
+	void (*schedule_rx)(struct uart_port *port);
+	void (*schedule_tx)(struct uart_port *port);
+	void (*release_rx)(struct uart_port *port);
+	void (*release_tx)(struct uart_port *port);
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -181,30 +202,44 @@
 }
 
 #ifdef CONFIG_SERIAL_ATMEL_PDC
-static bool atmel_use_dma_rx(struct uart_port *port)
+static bool atmel_use_pdc_rx(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	return atmel_port->use_dma_rx;
+	return atmel_port->use_pdc_rx;
 }
 
+static bool atmel_use_pdc_tx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	return atmel_port->use_pdc_tx;
+}
+#else
+static bool atmel_use_pdc_rx(struct uart_port *port)
+{
+	return false;
+}
+
+static bool atmel_use_pdc_tx(struct uart_port *port)
+{
+	return false;
+}
+#endif
+
 static bool atmel_use_dma_tx(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
 	return atmel_port->use_dma_tx;
 }
-#else
+
 static bool atmel_use_dma_rx(struct uart_port *port)
 {
-	return false;
-}
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-static bool atmel_use_dma_tx(struct uart_port *port)
-{
-	return false;
+	return atmel_port->use_dma_rx;
 }
-#endif
 
 /* Enable or disable the rs485 support */
 void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
@@ -233,7 +268,7 @@
 		mode |= ATMEL_US_USMODE_RS485;
 	} else {
 		dev_dbg(port->dev, "Setting UART to RS232\n");
-		if (atmel_use_dma_tx(port))
+		if (atmel_use_pdc_tx(port))
 			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
 				ATMEL_US_TXBUFE;
 		else
@@ -345,7 +380,7 @@
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		/* disable PDC transmit */
 		UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
 	}
@@ -364,7 +399,7 @@
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
 			/* The transmitter is already running.  Yes, we
 			   really need this.*/
@@ -390,7 +425,7 @@
 
 	UART_PUT_CR(port, ATMEL_US_RXEN);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/* enable PDC controller */
 		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
 			port->read_status_mask);
@@ -407,7 +442,7 @@
 {
 	UART_PUT_CR(port, ATMEL_US_RXDIS);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/* disable PDC receive */
 		UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
 		UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
@@ -564,6 +599,372 @@
 		UART_PUT_IER(port, atmel_port->tx_done_mask);
 }
 
+static void atmel_complete_tx_dma(void *arg)
+{
+	struct atmel_uart_port *atmel_port = arg;
+	struct uart_port *port = &atmel_port->uart;
+	struct circ_buf *xmit = &port->state->xmit;
+	struct dma_chan *chan = atmel_port->chan_tx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (chan)
+		dmaengine_terminate_all(chan);
+	xmit->tail += sg_dma_len(&atmel_port->sg_tx);
+	xmit->tail &= UART_XMIT_SIZE - 1;
+
+	port->icount.tx += sg_dma_len(&atmel_port->sg_tx);
+
+	spin_lock_irq(&atmel_port->lock_tx);
+	async_tx_ack(atmel_port->desc_tx);
+	atmel_port->cookie_tx = -EINVAL;
+	atmel_port->desc_tx = NULL;
+	spin_unlock_irq(&atmel_port->lock_tx);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	/* Do we really need this? */
+	if (!uart_circ_empty(xmit))
+		tasklet_schedule(&atmel_port->tasklet);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void atmel_release_tx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct dma_chan *chan = atmel_port->chan_tx;
+
+	if (chan) {
+		dmaengine_terminate_all(chan);
+		dma_release_channel(chan);
+		dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
+				DMA_MEM_TO_DEV);
+	}
+
+	atmel_port->desc_tx = NULL;
+	atmel_port->chan_tx = NULL;
+	atmel_port->cookie_tx = -EINVAL;
+}
+
+/*
+ * Called from tasklet with TXRDY interrupt is disabled.
+ */
+static void atmel_tx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct circ_buf *xmit = &port->state->xmit;
+	struct dma_chan *chan = atmel_port->chan_tx;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist *sg = &atmel_port->sg_tx;
+
+	/* Make sure we have an idle channel */
+	if (atmel_port->desc_tx != NULL)
+		return;
+
+	if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+		/*
+		 * DMA is idle now.
+		 * Port xmit buffer is already mapped,
+		 * and it is one page... Just adjust
+		 * offsets and lengths. Since it is a circular buffer,
+		 * we have to transmit till the end, and then the rest.
+		 * Take the port lock to get a
+		 * consistent xmit buffer state.
+		 */
+		sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+		sg_dma_address(sg) = (sg_dma_address(sg) &
+					~(UART_XMIT_SIZE - 1))
+					+ sg->offset;
+		sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head,
+						xmit->tail,
+						UART_XMIT_SIZE);
+		BUG_ON(!sg_dma_len(sg));
+
+		desc = dmaengine_prep_slave_sg(chan,
+						sg,
+						1,
+						DMA_MEM_TO_DEV,
+						DMA_PREP_INTERRUPT |
+						DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(port->dev, "Failed to send via dma!\n");
+			return;
+		}
+
+		dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
+
+		atmel_port->desc_tx = desc;
+		desc->callback = atmel_complete_tx_dma;
+		desc->callback_param = atmel_port;
+		atmel_port->cookie_tx = dmaengine_submit(desc);
+
+	} else {
+		if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+			/* DMA done, stop TX, start RX for RS485 */
+			atmel_start_rx(port);
+		}
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+}
+
+static int atmel_prepare_tx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	dma_cap_mask_t		mask;
+	struct dma_slave_config config;
+	int ret, nent;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx");
+	if (atmel_port->chan_tx == NULL)
+		goto chan_err;
+	dev_info(port->dev, "using %s for tx DMA transfers\n",
+		dma_chan_name(atmel_port->chan_tx));
+
+	spin_lock_init(&atmel_port->lock_tx);
+	sg_init_table(&atmel_port->sg_tx, 1);
+	/* UART circular tx buffer is an aligned page. */
+	BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+	sg_set_page(&atmel_port->sg_tx,
+			virt_to_page(port->state->xmit.buf),
+			UART_XMIT_SIZE,
+			(int)port->state->xmit.buf & ~PAGE_MASK);
+	nent = dma_map_sg(port->dev,
+				&atmel_port->sg_tx,
+				1,
+				DMA_MEM_TO_DEV);
+
+	if (!nent) {
+		dev_dbg(port->dev, "need to release resource of dma\n");
+		goto chan_err;
+	} else {
+		dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+			sg_dma_len(&atmel_port->sg_tx),
+			port->state->xmit.buf,
+			sg_dma_address(&atmel_port->sg_tx));
+	}
+
+	/* Configure the slave DMA */
+	memset(&config, 0, sizeof(config));
+	config.direction = DMA_MEM_TO_DEV;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	config.dst_addr = port->mapbase + ATMEL_US_THR;
+
+	ret = dmaengine_device_control(atmel_port->chan_tx,
+					DMA_SLAVE_CONFIG,
+					(unsigned long)&config);
+	if (ret) {
+		dev_err(port->dev, "DMA tx slave configuration failed\n");
+		goto chan_err;
+	}
+
+	return 0;
+
+chan_err:
+	dev_err(port->dev, "TX channel not available, switch to pio\n");
+	atmel_port->use_dma_tx = 0;
+	if (atmel_port->chan_tx)
+		atmel_release_tx_dma(port);
+	return -EINVAL;
+}
+
+static void atmel_flip_buffer_rx_dma(struct uart_port *port,
+					char *buf, size_t count)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct tty_port *tport = &port->state->port;
+
+	dma_sync_sg_for_cpu(port->dev,
+				&atmel_port->sg_rx,
+				1,
+				DMA_DEV_TO_MEM);
+
+	tty_insert_flip_string(tport, buf, count);
+
+	dma_sync_sg_for_device(port->dev,
+				&atmel_port->sg_rx,
+				1,
+				DMA_DEV_TO_MEM);
+	/*
+	 * Drop the lock here since it might end up calling
+	 * uart_start(), which takes the lock.
+	 */
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+}
+
+static void atmel_complete_rx_dma(void *arg)
+{
+	struct uart_port *port = arg;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	tasklet_schedule(&atmel_port->tasklet);
+}
+
+static void atmel_release_rx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct dma_chan *chan = atmel_port->chan_rx;
+
+	if (chan) {
+		dmaengine_terminate_all(chan);
+		dma_release_channel(chan);
+		dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
+				DMA_DEV_TO_MEM);
+	}
+
+	atmel_port->desc_rx = NULL;
+	atmel_port->chan_rx = NULL;
+	atmel_port->cookie_rx = -EINVAL;
+
+	if (!atmel_port->is_usart)
+		del_timer_sync(&atmel_port->uart_timer);
+}
+
+static void atmel_rx_from_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct circ_buf *ring = &atmel_port->rx_ring;
+	struct dma_chan *chan = atmel_port->chan_rx;
+	struct dma_tx_state state;
+	enum dma_status dmastat;
+	size_t pending, count;
+
+
+	/* Reset the UART timeout early so that we don't miss one */
+	UART_PUT_CR(port, ATMEL_US_STTTO);
+	dmastat = dmaengine_tx_status(chan,
+				atmel_port->cookie_rx,
+				&state);
+	/* Restart a new tasklet if DMA status is error */
+	if (dmastat == DMA_ERROR) {
+		dev_dbg(port->dev, "Get residue error, restart tasklet\n");
+		UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+		tasklet_schedule(&atmel_port->tasklet);
+		return;
+	}
+	/* current transfer size should no larger than dma buffer */
+	pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
+	BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
+
+	/*
+	 * This will take the chars we have so far,
+	 * ring->head will record the transfer size, only new bytes come
+	 * will insert into the framework.
+	 */
+	if (pending > ring->head) {
+		count = pending - ring->head;
+
+		atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count);
+
+		ring->head += count;
+		if (ring->head == sg_dma_len(&atmel_port->sg_rx))
+			ring->head = 0;
+
+		port->icount.rx += count;
+	}
+
+	UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+}
+
+static int atmel_prepare_rx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct dma_async_tx_descriptor *desc;
+	dma_cap_mask_t		mask;
+	struct dma_slave_config config;
+	struct circ_buf		*ring;
+	int ret, nent;
+
+	ring = &atmel_port->rx_ring;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_CYCLIC, mask);
+
+	atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx");
+	if (atmel_port->chan_rx == NULL)
+		goto chan_err;
+	dev_info(port->dev, "using %s for rx DMA transfers\n",
+		dma_chan_name(atmel_port->chan_rx));
+
+	spin_lock_init(&atmel_port->lock_rx);
+	sg_init_table(&atmel_port->sg_rx, 1);
+	/* UART circular rx buffer is an aligned page. */
+	BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+	sg_set_page(&atmel_port->sg_rx,
+			virt_to_page(ring->buf),
+			ATMEL_SERIAL_RINGSIZE,
+			(int)ring->buf & ~PAGE_MASK);
+			nent = dma_map_sg(port->dev,
+					&atmel_port->sg_rx,
+					1,
+					DMA_DEV_TO_MEM);
+
+	if (!nent) {
+		dev_dbg(port->dev, "need to release resource of dma\n");
+		goto chan_err;
+	} else {
+		dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+			sg_dma_len(&atmel_port->sg_rx),
+			ring->buf,
+			sg_dma_address(&atmel_port->sg_rx));
+	}
+
+	/* Configure the slave DMA */
+	memset(&config, 0, sizeof(config));
+	config.direction = DMA_DEV_TO_MEM;
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	config.src_addr = port->mapbase + ATMEL_US_RHR;
+
+	ret = dmaengine_device_control(atmel_port->chan_rx,
+					DMA_SLAVE_CONFIG,
+					(unsigned long)&config);
+	if (ret) {
+		dev_err(port->dev, "DMA rx slave configuration failed\n");
+		goto chan_err;
+	}
+	/*
+	 * Prepare a cyclic dma transfer, assign 2 descriptors,
+	 * each one is half ring buffer size
+	 */
+	desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
+				sg_dma_address(&atmel_port->sg_rx),
+				sg_dma_len(&atmel_port->sg_rx),
+				sg_dma_len(&atmel_port->sg_rx)/2,
+				DMA_DEV_TO_MEM,
+				DMA_PREP_INTERRUPT);
+	desc->callback = atmel_complete_rx_dma;
+	desc->callback_param = port;
+	atmel_port->desc_rx = desc;
+	atmel_port->cookie_rx = dmaengine_submit(desc);
+
+	return 0;
+
+chan_err:
+	dev_err(port->dev, "RX channel not available, switch to pio\n");
+	atmel_port->use_dma_rx = 0;
+	if (atmel_port->chan_rx)
+		atmel_release_rx_dma(port);
+	return -EINVAL;
+}
+
+static void atmel_uart_timer_callback(unsigned long data)
+{
+	struct uart_port *port = (void *)data;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	tasklet_schedule(&atmel_port->tasklet);
+	mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port));
+}
+
 /*
  * receive interrupt handler.
  */
@@ -572,7 +973,7 @@
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/*
 		 * PDC receive. Just schedule the tasklet and let it
 		 * figure out the details.
@@ -591,6 +992,13 @@
 			atmel_pdc_rxerr(port, pending);
 	}
 
+	if (atmel_use_dma_rx(port)) {
+		if (pending & ATMEL_US_TIMEOUT) {
+			UART_PUT_IDR(port, ATMEL_US_TIMEOUT);
+			tasklet_schedule(&atmel_port->tasklet);
+		}
+	}
+
 	/* Interrupt receive */
 	if (pending & ATMEL_US_RXRDY)
 		atmel_rx_chars(port);
@@ -658,10 +1066,21 @@
 	return pass_counter ? IRQ_HANDLED : IRQ_NONE;
 }
 
+static void atmel_release_tx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+	dma_unmap_single(port->dev,
+			 pdc->dma_addr,
+			 pdc->dma_size,
+			 DMA_TO_DEVICE);
+}
+
 /*
  * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
  */
-static void atmel_tx_dma(struct uart_port *port)
+static void atmel_tx_pdc(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	struct circ_buf *xmit = &port->state->xmit;
@@ -710,6 +1129,23 @@
 		uart_write_wakeup(port);
 }
 
+static int atmel_prepare_tx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	pdc->buf = xmit->buf;
+	pdc->dma_addr = dma_map_single(port->dev,
+					pdc->buf,
+					UART_XMIT_SIZE,
+					DMA_TO_DEVICE);
+	pdc->dma_size = UART_XMIT_SIZE;
+	pdc->ofs = 0;
+
+	return 0;
+}
+
 static void atmel_rx_from_ring(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -778,7 +1214,26 @@
 	spin_lock(&port->lock);
 }
 
-static void atmel_rx_from_dma(struct uart_port *port)
+static void atmel_release_rx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+		dma_unmap_single(port->dev,
+				 pdc->dma_addr,
+				 pdc->dma_size,
+				 DMA_FROM_DEVICE);
+		kfree(pdc->buf);
+	}
+
+	if (!atmel_port->is_usart)
+		del_timer_sync(&atmel_port->uart_timer);
+}
+
+static void atmel_rx_from_pdc(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	struct tty_port *tport = &port->state->port;
@@ -855,6 +1310,45 @@
 	UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
 }
 
+static int atmel_prepare_rx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+		pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+		if (pdc->buf == NULL) {
+			if (i != 0) {
+				dma_unmap_single(port->dev,
+					atmel_port->pdc_rx[0].dma_addr,
+					PDC_BUFFER_SIZE,
+					DMA_FROM_DEVICE);
+				kfree(atmel_port->pdc_rx[0].buf);
+			}
+			atmel_port->use_pdc_rx = 0;
+			return -ENOMEM;
+		}
+		pdc->dma_addr = dma_map_single(port->dev,
+						pdc->buf,
+						PDC_BUFFER_SIZE,
+						DMA_FROM_DEVICE);
+		pdc->dma_size = PDC_BUFFER_SIZE;
+		pdc->ofs = 0;
+	}
+
+	atmel_port->pdc_rx_idx = 0;
+
+	UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+	UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+	UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+	UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+
+	return 0;
+}
+
 /*
  * tasklet handling tty stuff outside the interrupt handler.
  */
@@ -868,10 +1362,7 @@
 	/* The interrupt handler does not take the lock */
 	spin_lock(&port->lock);
 
-	if (atmel_use_dma_tx(port))
-		atmel_tx_dma(port);
-	else
-		atmel_tx_chars(port);
+	atmel_port->schedule_tx(port);
 
 	status = atmel_port->irq_status;
 	status_change = status ^ atmel_port->irq_status_prev;
@@ -893,19 +1384,152 @@
 		atmel_port->irq_status_prev = status;
 	}
 
-	if (atmel_use_dma_rx(port))
-		atmel_rx_from_dma(port);
-	else
-		atmel_rx_from_ring(port);
+	atmel_port->schedule_rx(port);
 
 	spin_unlock(&port->lock);
 }
 
+static int atmel_init_property(struct atmel_uart_port *atmel_port,
+				struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
+
+	if (np) {
+		/* DMA/PDC usage specification */
+		if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
+			if (of_get_property(np, "dmas", NULL)) {
+				atmel_port->use_dma_rx  = true;
+				atmel_port->use_pdc_rx  = false;
+			} else {
+				atmel_port->use_dma_rx  = false;
+				atmel_port->use_pdc_rx  = true;
+			}
+		} else {
+			atmel_port->use_dma_rx  = false;
+			atmel_port->use_pdc_rx  = false;
+		}
+
+		if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
+			if (of_get_property(np, "dmas", NULL)) {
+				atmel_port->use_dma_tx  = true;
+				atmel_port->use_pdc_tx  = false;
+			} else {
+				atmel_port->use_dma_tx  = false;
+				atmel_port->use_pdc_tx  = true;
+			}
+		} else {
+			atmel_port->use_dma_tx  = false;
+			atmel_port->use_pdc_tx  = false;
+		}
+
+	} else {
+		atmel_port->use_pdc_rx  = pdata->use_dma_rx;
+		atmel_port->use_pdc_tx  = pdata->use_dma_tx;
+		atmel_port->use_dma_rx  = false;
+		atmel_port->use_dma_tx  = false;
+	}
+
+	return 0;
+}
+
+static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
+				struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
+
+	if (np) {
+		u32 rs485_delay[2];
+		/* rs485 properties */
+		if (of_property_read_u32_array(np, "rs485-rts-delay",
+					rs485_delay, 2) == 0) {
+			struct serial_rs485 *rs485conf = &atmel_port->rs485;
+
+			rs485conf->delay_rts_before_send = rs485_delay[0];
+			rs485conf->delay_rts_after_send = rs485_delay[1];
+			rs485conf->flags = 0;
+
+		if (of_get_property(np, "rs485-rx-during-tx", NULL))
+			rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+		if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
+								NULL))
+			rs485conf->flags |= SER_RS485_ENABLED;
+		}
+	} else {
+		atmel_port->rs485       = pdata->rs485;
+	}
+
+}
+
+static void atmel_set_ops(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	if (atmel_use_dma_rx(port)) {
+		atmel_port->prepare_rx = &atmel_prepare_rx_dma;
+		atmel_port->schedule_rx = &atmel_rx_from_dma;
+		atmel_port->release_rx = &atmel_release_rx_dma;
+	} else if (atmel_use_pdc_rx(port)) {
+		atmel_port->prepare_rx = &atmel_prepare_rx_pdc;
+		atmel_port->schedule_rx = &atmel_rx_from_pdc;
+		atmel_port->release_rx = &atmel_release_rx_pdc;
+	} else {
+		atmel_port->prepare_rx = NULL;
+		atmel_port->schedule_rx = &atmel_rx_from_ring;
+		atmel_port->release_rx = NULL;
+	}
+
+	if (atmel_use_dma_tx(port)) {
+		atmel_port->prepare_tx = &atmel_prepare_tx_dma;
+		atmel_port->schedule_tx = &atmel_tx_dma;
+		atmel_port->release_tx = &atmel_release_tx_dma;
+	} else if (atmel_use_pdc_tx(port)) {
+		atmel_port->prepare_tx = &atmel_prepare_tx_pdc;
+		atmel_port->schedule_tx = &atmel_tx_pdc;
+		atmel_port->release_tx = &atmel_release_tx_pdc;
+	} else {
+		atmel_port->prepare_tx = NULL;
+		atmel_port->schedule_tx = &atmel_tx_chars;
+		atmel_port->release_tx = NULL;
+	}
+}
+
+/*
+ * Get ip name usart or uart
+ */
+static int atmel_get_ip_name(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int name = UART_GET_IP_NAME(port);
+	int usart, uart;
+	/* usart and uart ascii */
+	usart = 0x55534152;
+	uart = 0x44424755;
+
+	atmel_port->is_usart = false;
+
+	if (name == usart) {
+		dev_dbg(port->dev, "This is usart\n");
+		atmel_port->is_usart = true;
+	} else if (name == uart) {
+		dev_dbg(port->dev, "This is uart\n");
+		atmel_port->is_usart = false;
+	} else {
+		dev_err(port->dev, "Not supported ip name, set to uart\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /*
  * Perform initialization and enable port for reception
  */
 static int atmel_startup(struct uart_port *port)
 {
+	struct platform_device *pdev = to_platform_device(port->dev);
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	struct tty_struct *tty = port->state->port.tty;
 	int retval;
@@ -930,53 +1554,19 @@
 	/*
 	 * Initialize DMA (if necessary)
 	 */
-	if (atmel_use_dma_rx(port)) {
-		int i;
+	atmel_init_property(atmel_port, pdev);
 
-		for (i = 0; i < 2; i++) {
-			struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-			pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
-			if (pdc->buf == NULL) {
-				if (i != 0) {
-					dma_unmap_single(port->dev,
-						atmel_port->pdc_rx[0].dma_addr,
-						PDC_BUFFER_SIZE,
-						DMA_FROM_DEVICE);
-					kfree(atmel_port->pdc_rx[0].buf);
-				}
-				free_irq(port->irq, port);
-				return -ENOMEM;
-			}
-			pdc->dma_addr = dma_map_single(port->dev,
-						       pdc->buf,
-						       PDC_BUFFER_SIZE,
-						       DMA_FROM_DEVICE);
-			pdc->dma_size = PDC_BUFFER_SIZE;
-			pdc->ofs = 0;
-		}
-
-		atmel_port->pdc_rx_idx = 0;
-
-		UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
-		UART_PUT_RCR(port, PDC_BUFFER_SIZE);
-
-		UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
-		UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
-	}
-	if (atmel_use_dma_tx(port)) {
-		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-		struct circ_buf *xmit = &port->state->xmit;
-
-		pdc->buf = xmit->buf;
-		pdc->dma_addr = dma_map_single(port->dev,
-					       pdc->buf,
-					       UART_XMIT_SIZE,
-					       DMA_TO_DEVICE);
-		pdc->dma_size = UART_XMIT_SIZE;
-		pdc->ofs = 0;
+	if (atmel_port->prepare_rx) {
+		retval = atmel_port->prepare_rx(port);
+		if (retval < 0)
+			atmel_set_ops(port);
 	}
 
+	if (atmel_port->prepare_tx) {
+		retval = atmel_port->prepare_tx(port);
+		if (retval < 0)
+			atmel_set_ops(port);
+	}
 	/*
 	 * If there is a specific "open" function (to register
 	 * control line interrupts)
@@ -1000,14 +1590,38 @@
 	/* enable xmit & rcvr */
 	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/* set UART timeout */
-		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
-		UART_PUT_CR(port, ATMEL_US_STTTO);
+		if (!atmel_port->is_usart) {
+			setup_timer(&atmel_port->uart_timer,
+					atmel_uart_timer_callback,
+					(unsigned long)port);
+			mod_timer(&atmel_port->uart_timer,
+					jiffies + uart_poll_timeout(port));
+		/* set USART timeout */
+		} else {
+			UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+			UART_PUT_CR(port, ATMEL_US_STTTO);
 
-		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+			UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+		}
 		/* enable PDC controller */
 		UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+	} else if (atmel_use_dma_rx(port)) {
+		/* set UART timeout */
+		if (!atmel_port->is_usart) {
+			setup_timer(&atmel_port->uart_timer,
+					atmel_uart_timer_callback,
+					(unsigned long)port);
+			mod_timer(&atmel_port->uart_timer,
+					jiffies + uart_poll_timeout(port));
+		/* set USART timeout */
+		} else {
+			UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+			UART_PUT_CR(port, ATMEL_US_STTTO);
+
+			UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+		}
 	} else {
 		/* enable receive only */
 		UART_PUT_IER(port, ATMEL_US_RXRDY);
@@ -1031,27 +1645,10 @@
 	/*
 	 * Shut-down the DMA.
 	 */
-	if (atmel_use_dma_rx(port)) {
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-			dma_unmap_single(port->dev,
-					 pdc->dma_addr,
-					 pdc->dma_size,
-					 DMA_FROM_DEVICE);
-			kfree(pdc->buf);
-		}
-	}
-	if (atmel_use_dma_tx(port)) {
-		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-
-		dma_unmap_single(port->dev,
-				 pdc->dma_addr,
-				 pdc->dma_size,
-				 DMA_TO_DEVICE);
-	}
+	if (atmel_port->release_rx)
+		atmel_port->release_rx(port);
+	if (atmel_port->release_tx)
+		atmel_port->release_tx(port);
 
 	/*
 	 * Disable all interrupts, port and break condition.
@@ -1080,7 +1677,7 @@
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		UART_PUT_TCR(port, 0);
 		atmel_port->pdc_tx.ofs = 0;
 	}
@@ -1193,7 +1790,7 @@
 	if (termios->c_iflag & (BRKINT | PARMRK))
 		port->read_status_mask |= ATMEL_US_RXBRK;
 
-	if (atmel_use_dma_rx(port))
+	if (atmel_use_pdc_rx(port))
 		/* need to enable error interrupts */
 		UART_PUT_IER(port, port->read_status_mask);
 
@@ -1423,38 +2020,6 @@
 #endif
 };
 
-static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
-					 struct device_node *np)
-{
-	u32 rs485_delay[2];
-
-	/* DMA/PDC usage specification */
-	if (of_get_property(np, "atmel,use-dma-rx", NULL))
-		atmel_port->use_dma_rx	= 1;
-	else
-		atmel_port->use_dma_rx	= 0;
-	if (of_get_property(np, "atmel,use-dma-tx", NULL))
-		atmel_port->use_dma_tx	= 1;
-	else
-		atmel_port->use_dma_tx	= 0;
-
-	/* rs485 properties */
-	if (of_property_read_u32_array(np, "rs485-rts-delay",
-					    rs485_delay, 2) == 0) {
-		struct serial_rs485 *rs485conf = &atmel_port->rs485;
-
-		rs485conf->delay_rts_before_send = rs485_delay[0];
-		rs485conf->delay_rts_after_send = rs485_delay[1];
-		rs485conf->flags = 0;
-
-		if (of_get_property(np, "rs485-rx-during-tx", NULL))
-			rs485conf->flags |= SER_RS485_RX_DURING_TX;
-
-		if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
-			rs485conf->flags |= SER_RS485_ENABLED;
-	}
-}
-
 /*
  * Configure the port from the platform device resource info.
  */
@@ -1463,15 +2028,12 @@
 {
 	int ret;
 	struct uart_port *port = &atmel_port->uart;
-	struct atmel_uart_data *pdata = pdev->dev.platform_data;
+	struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
 
-	if (pdev->dev.of_node) {
-		atmel_of_init_port(atmel_port, pdev->dev.of_node);
-	} else {
-		atmel_port->use_dma_rx	= pdata->use_dma_rx;
-		atmel_port->use_dma_tx	= pdata->use_dma_tx;
-		atmel_port->rs485	= pdata->rs485;
-	}
+	if (!atmel_init_property(atmel_port, pdev))
+		atmel_set_ops(port);
+
+	atmel_init_rs485(atmel_port, pdev);
 
 	port->iotype		= UPIO_MEM;
 	port->flags		= UPF_BOOT_AUTOCONF;
@@ -1516,7 +2078,7 @@
 	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
 	if (atmel_port->rs485.flags & SER_RS485_ENABLED)
 		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-	else if (atmel_use_dma_tx(port)) {
+	else if (atmel_use_pdc_tx(port)) {
 		port->fifosize = PDC_BUFFER_SIZE;
 		atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
 	} else {
@@ -1664,7 +2226,7 @@
 	int ret;
 	if (atmel_default_console_device) {
 		struct atmel_uart_data *pdata =
-			atmel_default_console_device->dev.platform_data;
+			dev_get_platdata(&atmel_default_console_device->dev);
 		int id = pdata->num;
 		struct atmel_uart_port *port = &atmel_ports[id];
 
@@ -1772,10 +2334,9 @@
 {
 	struct atmel_uart_port *port;
 	struct device_node *np = pdev->dev.of_node;
-	struct atmel_uart_data *pdata = pdev->dev.platform_data;
+	struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
 	void *data;
 	int ret = -ENODEV;
-	struct pinctrl *pinctrl;
 
 	BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
 
@@ -1809,13 +2370,7 @@
 	if (ret)
 		goto err;
 
-	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		ret = PTR_ERR(pinctrl);
-		goto err;
-	}
-
-	if (!atmel_use_dma_rx(&port->uart)) {
+	if (!atmel_use_pdc_rx(&port->uart)) {
 		ret = -ENOMEM;
 		data = kmalloc(sizeof(struct atmel_uart_char)
 				* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
@@ -1847,6 +2402,13 @@
 		UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
 	}
 
+	/*
+	 * Get port name of usart or uart
+	 */
+	ret = atmel_get_ip_name(&port->uart);
+	if (ret < 0)
+		goto err_add_port;
+
 	return 0;
 
 err_add_port:
@@ -1868,7 +2430,6 @@
 	int ret = 0;
 
 	device_init_wakeup(&pdev->dev, 0);
-	platform_set_drvdata(pdev, NULL);
 
 	ret = uart_remove_one_port(&atmel_uart, port);
 
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 6fa2ae77..649d512 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -302,7 +302,9 @@
 
 	} while (--max_count);
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tty_port);
+	spin_lock(&port->lock);
 }
 
 /*
@@ -852,7 +854,6 @@
 
 	port = platform_get_drvdata(pdev);
 	uart_remove_one_port(&bcm_uart_driver, port);
-	platform_set_drvdata(pdev, NULL);
 	/* mark port as free */
 	ports[pdev->id].membase = 0;
 	return 0;
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
index 487c173..87636cc 100644
--- a/drivers/tty/serial/bfin_sport_uart.c
+++ b/drivers/tty/serial/bfin_sport_uart.c
@@ -161,11 +161,12 @@
 		if (!uart_handle_sysrq_char(&up->port, ch))
 			tty_insert_flip_char(port, ch, TTY_NORMAL);
 	}
-	/* XXX this won't deadlock with lowlat? */
-	tty_flip_buffer_push(port);
 
 	spin_unlock(&up->port.lock);
 
+	/* XXX this won't deadlock with lowlat? */
+	tty_flip_buffer_push(port);
+
 	return IRQ_HANDLED;
 }
 
@@ -766,7 +767,8 @@
 		}
 
 		ret = peripheral_request_list(
-			(unsigned short *)pdev->dev.platform_data, DRV_NAME);
+			(unsigned short *)dev_get_platdata(&pdev->dev),
+			DRV_NAME);
 		if (ret) {
 			dev_err(&pdev->dev,
 				"Fail to request SPORT peripherals\n");
@@ -843,7 +845,7 @@
 		iounmap(sport->port.membase);
 out_error_free_peripherals:
 		peripheral_free_list(
-			(unsigned short *)pdev->dev.platform_data);
+			(unsigned short *)dev_get_platdata(&pdev->dev));
 out_error_free_mem:
 		kfree(sport);
 		bfin_sport_uart_ports[pdev->id] = NULL;
@@ -863,7 +865,7 @@
 		uart_remove_one_port(&sport_uart_reg, &sport->port);
 		iounmap(sport->port.membase);
 		peripheral_free_list(
-			(unsigned short *)pdev->dev.platform_data);
+			(unsigned short *)dev_get_platdata(&pdev->dev));
 		kfree(sport);
 		bfin_sport_uart_ports[pdev->id] = NULL;
 	}
@@ -883,7 +885,7 @@
 };
 
 #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
-static __initdata struct early_platform_driver early_sport_uart_driver = {
+static struct early_platform_driver early_sport_uart_driver __initdata = {
 	.class_str = CLASS_BFIN_SPORT_CONSOLE,
 	.pdrv = &sport_uart_driver,
 	.requested_id = EARLY_PLATFORM_ID_UNSET,
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 26a3be7..3c75e8e 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -41,10 +41,6 @@
 # undef CONFIG_EARLY_PRINTK
 #endif
 
-#ifdef CONFIG_SERIAL_BFIN_MODULE
-# undef CONFIG_EARLY_PRINTK
-#endif
-
 /* UART name and device definitions */
 #define BFIN_SERIAL_DEV_NAME	"ttyBF"
 #define BFIN_SERIAL_MAJOR	204
@@ -1180,7 +1176,7 @@
  * don't let the common infrastructure play with things. (see calls to setup
  * & earlysetup in ./kernel/printk.c:register_console()
  */
-static struct __initdata console bfin_early_serial_console = {
+static struct console bfin_early_serial_console __initdata = {
 	.name = "early_BFuart",
 	.write = bfin_earlyprintk_console_write,
 	.device = uart_console_device,
@@ -1244,7 +1240,8 @@
 			 */
 #endif
 		ret = peripheral_request_list(
-			(unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+			(unsigned short *)dev_get_platdata(&pdev->dev),
+			DRIVER_NAME);
 		if (ret) {
 			dev_err(&pdev->dev,
 				"fail to request bfin serial peripherals\n");
@@ -1362,7 +1359,7 @@
 		iounmap(uart->port.membase);
 out_error_free_peripherals:
 		peripheral_free_list(
-			(unsigned short *)pdev->dev.platform_data);
+			(unsigned short *)dev_get_platdata(&pdev->dev));
 out_error_free_mem:
 		kfree(uart);
 		bfin_serial_ports[pdev->id] = NULL;
@@ -1381,7 +1378,7 @@
 		uart_remove_one_port(&bfin_serial_reg, &uart->port);
 		iounmap(uart->port.membase);
 		peripheral_free_list(
-			(unsigned short *)pdev->dev.platform_data);
+			(unsigned short *)dev_get_platdata(&pdev->dev));
 		kfree(uart);
 		bfin_serial_ports[pdev->id] = NULL;
 	}
@@ -1401,7 +1398,7 @@
 };
 
 #if defined(CONFIG_SERIAL_BFIN_CONSOLE)
-static __initdata struct early_platform_driver early_bfin_serial_driver = {
+static struct early_platform_driver early_bfin_serial_driver __initdata = {
 	.class_str = CLASS_BFIN_CONSOLE,
 	.pdrv = &bfin_serial_driver,
 	.requested_id = EARLY_PLATFORM_ID_UNSET,
@@ -1436,7 +1433,7 @@
 	}
 
 	ret = peripheral_request_list(
-		(unsigned short *)pdev->dev.platform_data, DRIVER_NAME);
+		(unsigned short *)dev_get_platdata(&pdev->dev), DRIVER_NAME);
 	if (ret) {
 		dev_err(&pdev->dev,
 				"fail to request bfin serial peripherals\n");
@@ -1467,7 +1464,7 @@
 
 out_error_free_peripherals:
 	peripheral_free_list(
-		(unsigned short *)pdev->dev.platform_data);
+		(unsigned short *)dev_get_platdata(&pdev->dev));
 
 	return ret;
 }
@@ -1480,7 +1477,7 @@
 	},
 };
 
-static __initdata struct early_platform_driver early_bfin_earlyprintk_driver = {
+static struct early_platform_driver early_bfin_earlyprintk_driver __initdata = {
 	.class_str = CLASS_BFIN_EARLYPRINTK,
 	.pdrv = &bfin_earlyprintk_driver,
 	.requested_id = EARLY_PLATFORM_ID_UNSET,
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index bfb1796..7e4e408 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -438,8 +438,7 @@
 	s->uart_clk = devm_clk_get(&pdev->dev, "uart");
 	if (IS_ERR(s->uart_clk)) {
 		dev_err(&pdev->dev, "Can't get UART clocks\n");
-		ret = PTR_ERR(s->uart_clk);
-		goto err_out;
+		return PTR_ERR(s->uart_clk);
 	}
 
 	s->uart.owner		= THIS_MODULE;
@@ -461,7 +460,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "Registering UART driver failed\n");
 		devm_clk_put(&pdev->dev, s->uart_clk);
-		goto err_out;
+		return ret;
 	}
 
 	for (i = 0; i < UART_CLPS711X_NR; i++) {
@@ -478,11 +477,6 @@
 	}
 
 	return 0;
-
-err_out:
-	platform_set_drvdata(pdev, NULL);
-
-	return ret;
 }
 
 static int uart_clps711x_remove(struct platform_device *pdev)
@@ -495,7 +489,6 @@
 
 	devm_clk_put(&pdev->dev, s->uart_clk);
 	uart_unregister_driver(&s->uart);
-	platform_set_drvdata(pdev, NULL);
 
 	return 0;
 }
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index f7672ca..1a535f7 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -1213,8 +1213,32 @@
 		goto out_pram;
 	}
 
-	for (i = 0; i < NUM_GPIOS; i++)
-		pinfo->gpios[i] = of_get_gpio(np, i);
+	for (i = 0; i < NUM_GPIOS; i++) {
+		int gpio;
+
+		pinfo->gpios[i] = -1;
+
+		gpio = of_get_gpio(np, i);
+
+		if (gpio_is_valid(gpio)) {
+			ret = gpio_request(gpio, "cpm_uart");
+			if (ret) {
+				pr_err("can't request gpio #%d: %d\n", i, ret);
+				continue;
+			}
+			if (i == GPIO_RTS || i == GPIO_DTR)
+				ret = gpio_direction_output(gpio, 0);
+			else
+				ret = gpio_direction_input(gpio);
+			if (ret) {
+				pr_err("can't set direction for gpio #%d: %d\n",
+					i, ret);
+				gpio_free(gpio);
+				continue;
+			}
+			pinfo->gpios[i] = gpio;
+		}
+	}
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_CPM
 	udbg_putc = NULL;
diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c
index 7d199c8..0eb5b56 100644
--- a/drivers/tty/serial/efm32-uart.c
+++ b/drivers/tty/serial/efm32-uart.c
@@ -268,10 +268,10 @@
 		handled = IRQ_HANDLED;
 	}
 
-	tty_flip_buffer_push(tport);
-
 	spin_unlock(&port->lock);
 
+	tty_flip_buffer_push(tport);
+
 	return handled;
 }
 
@@ -698,6 +698,7 @@
 {
 	struct efm32_uart_port *efm_port;
 	struct resource *res;
+	unsigned int line;
 	int ret;
 
 	efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
@@ -750,18 +751,21 @@
 
 		if (pdata)
 			efm_port->pdata = *pdata;
-	}
+	} else if (ret < 0)
+		goto err_probe_dt;
 
-	if (efm_port->port.line >= 0 &&
-			efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
-		efm32_uart_ports[efm_port->port.line] = efm_port;
+	line = efm_port->port.line;
+
+	if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
+		efm32_uart_ports[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;
+		if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
+			efm32_uart_ports[line] = NULL;
+err_probe_dt:
 err_get_rxirq:
 err_too_small:
 err_get_base:
@@ -777,20 +781,19 @@
 static int efm32_uart_remove(struct platform_device *pdev)
 {
 	struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
-
-	platform_set_drvdata(pdev, NULL);
+	unsigned int line = efm_port->port.line;
 
 	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;
+	if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
+		efm32_uart_ports[line] = NULL;
 
 	kfree(efm_port);
 
 	return 0;
 }
 
-static struct of_device_id efm32_uart_dt_ids[] = {
+static const struct of_device_id efm32_uart_dt_ids[] = {
 	{
 		.compatible = "efm32,uart",
 	}, {
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 263cfaa..8978dc9a 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -342,8 +342,10 @@
 static void lpuart_setup_watermark(struct lpuart_port *sport)
 {
 	unsigned char val, cr2;
+	unsigned char cr2_saved;
 
 	cr2 = readb(sport->port.membase + UARTCR2);
+	cr2_saved = cr2;
 	cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_TE |
 			UARTCR2_RIE | UARTCR2_RE);
 	writeb(cr2, sport->port.membase + UARTCR2);
@@ -366,6 +368,9 @@
 
 	writeb(2, sport->port.membase + UARTTWFIFO);
 	writeb(1, sport->port.membase + UARTRWFIFO);
+
+	/* Restore cr2 */
+	writeb(cr2_saved, sport->port.membase + UARTCR2);
 }
 
 static int lpuart_startup(struct uart_port *port)
@@ -858,7 +863,7 @@
 	if (ret)
 		uart_unregister_driver(&lpuart_reg);
 
-	return 0;
+	return ret;
 }
 
 static void __exit lpuart_serial_exit(void)
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 18ed5ae..d98e433 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -105,7 +105,7 @@
 	{}
 };
 
-struct lookup_proc_table start_proc[4] = {
+static struct lookup_proc_table start_proc[4] = {
 	{NULL, ICOM_CONTROL_START_A},
 	{NULL, ICOM_CONTROL_START_B},
 	{NULL, ICOM_CONTROL_START_C},
@@ -113,14 +113,14 @@
 };
 
 
-struct lookup_proc_table stop_proc[4] = {
+static struct lookup_proc_table stop_proc[4] = {
 	{NULL, ICOM_CONTROL_STOP_A},
 	{NULL, ICOM_CONTROL_STOP_B},
 	{NULL, ICOM_CONTROL_STOP_C},
 	{NULL, ICOM_CONTROL_STOP_D}
 };
 
-struct lookup_int_table int_mask_tbl[4] = {
+static struct lookup_int_table int_mask_tbl[4] = {
 	{NULL, ICOM_INT_MASK_PRC_A},
 	{NULL, ICOM_INT_MASK_PRC_B},
 	{NULL, ICOM_INT_MASK_PRC_C},
@@ -297,25 +297,25 @@
 	spin_lock_irqsave(&icom_lock, flags);
 
 	port = icom_port->port;
+	if (port >= ARRAY_SIZE(stop_proc)) {
+		dev_err(&icom_port->adapter->pci_dev->dev,
+			"Invalid port assignment\n");
+		goto unlock;
+	}
+
 	if (port == 0 || port == 1)
 		stop_proc[port].global_control_reg = &icom_port->global_reg->control;
 	else
 		stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
 
+	temp = readl(stop_proc[port].global_control_reg);
+	temp = (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
+	writel(temp, stop_proc[port].global_control_reg);
 
-	if (port < 4) {
-		temp = readl(stop_proc[port].global_control_reg);
-		temp =
-			(temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
-		writel(temp, stop_proc[port].global_control_reg);
+	/* write flush */
+	readl(stop_proc[port].global_control_reg);
 
-		/* write flush */
-		readl(stop_proc[port].global_control_reg);
-	} else {
-		dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-	}
-
+unlock:
 	spin_unlock_irqrestore(&icom_lock, flags);
 }
 
@@ -328,23 +328,25 @@
 	spin_lock_irqsave(&icom_lock, flags);
 
 	port = icom_port->port;
+	if (port >= ARRAY_SIZE(start_proc)) {
+		dev_err(&icom_port->adapter->pci_dev->dev,
+			"Invalid port assignment\n");
+		goto unlock;
+	}
+
 	if (port == 0 || port == 1)
 		start_proc[port].global_control_reg = &icom_port->global_reg->control;
 	else
 		start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
-	if (port < 4) {
-		temp = readl(start_proc[port].global_control_reg);
-		temp =
-			(temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
-		writel(temp, start_proc[port].global_control_reg);
 
-		/* write flush */
-		readl(start_proc[port].global_control_reg);
-	} else {
-		dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-	}
+	temp = readl(start_proc[port].global_control_reg);
+	temp = (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
+	writel(temp, start_proc[port].global_control_reg);
 
+	/* write flush */
+	readl(start_proc[port].global_control_reg);
+
+unlock:
 	spin_unlock_irqrestore(&icom_lock, flags);
 }
 
@@ -557,6 +559,12 @@
 	 */
 	spin_lock_irqsave(&icom_lock, flags);
 	port = icom_port->port;
+	if (port >= ARRAY_SIZE(int_mask_tbl)) {
+		dev_err(&icom_port->adapter->pci_dev->dev,
+			"Invalid port assignment\n");
+		goto unlock;
+	}
+
 	if (port == 0 || port == 1)
 		int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
 	else
@@ -566,17 +574,14 @@
 		writew(0x00FF, icom_port->int_reg);
 	else
 		writew(0x3F00, icom_port->int_reg);
-	if (port < 4) {
-		temp = readl(int_mask_tbl[port].global_int_mask);
-		writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
 
-		/* write flush */
-		readl(int_mask_tbl[port].global_int_mask);
-	} else {
-		dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-	}
+	temp = readl(int_mask_tbl[port].global_int_mask);
+	writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
 
+	/* write flush */
+	readl(int_mask_tbl[port].global_int_mask);
+
+unlock:
 	spin_unlock_irqrestore(&icom_lock, flags);
 	return 0;
 }
@@ -595,21 +600,23 @@
 	 * disable all interrupts
 	 */
 	port = icom_port->port;
+	if (port >= ARRAY_SIZE(int_mask_tbl)) {
+		dev_err(&icom_port->adapter->pci_dev->dev,
+			"Invalid port assignment\n");
+		goto unlock;
+	}
 	if (port == 0 || port == 1)
 		int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
 	else
 		int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
 
-	if (port < 4) {
-		temp = readl(int_mask_tbl[port].global_int_mask);
-		writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
+	temp = readl(int_mask_tbl[port].global_int_mask);
+	writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
 
-		/* write flush */
-		readl(int_mask_tbl[port].global_int_mask);
-	} else {
-		dev_err(&icom_port->adapter->pci_dev->dev,
-                        "Invalid port assignment\n");
-	}
+	/* write flush */
+	readl(int_mask_tbl[port].global_int_mask);
+
+unlock:
 	spin_unlock_irqrestore(&icom_lock, flags);
 
 	/*
@@ -834,7 +841,10 @@
 		status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
 	}
 	icom_port->next_rcv = rcv_buff;
+
+	spin_unlock(&icom_port->uart_port.lock);
 	tty_flip_buffer_push(port);
+	spin_lock(&icom_port->uart_port.lock);
 }
 
 static void process_interrupt(u16 port_int_reg,
@@ -1087,8 +1097,7 @@
 
 	/* stop receiver */
 	cmdReg = readb(&ICOM_PORT->dram->CmdReg);
-	writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
-	       &ICOM_PORT->dram->CmdReg);
+	writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
 
 	shutdown(ICOM_PORT);
 
@@ -1567,7 +1576,7 @@
 			icom_port->uart_port.type = PORT_ICOM;
 			icom_port->uart_port.iotype = UPIO_MEM;
 			icom_port->uart_port.membase =
-					       (char *) icom_adapter->base_addr_pci;
+				(unsigned char __iomem *)icom_adapter->base_addr_pci;
 			icom_port->uart_port.fifosize = 16;
 			icom_port->uart_port.ops = &icom_ops;
 			icom_port->uart_port.line =
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 8b1534c..af286e6 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -1008,7 +1008,7 @@
 		return -ENODEV;
 	}
 
-	pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data;
+	pl_data = (struct ifx_modem_platform_data *)dev_get_platdata(&spi->dev);
 	if (!pl_data) {
 		dev_err(&spi->dev, "missing platform data!");
 		return -ENODEV;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 415cec6..a0ebbc9 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -47,11 +47,12 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
+#include <linux/platform_data/dma-imx.h>
 
 /* Register definitions */
 #define URXD0 0x0  /* Receiver Register */
@@ -83,6 +84,7 @@
 #define UCR1_ADBR	(1<<14) /* Auto detect baud rate */
 #define UCR1_TRDYEN	(1<<13) /* Transmitter ready interrupt enable */
 #define UCR1_IDEN	(1<<12) /* Idle condition interrupt */
+#define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */
 #define UCR1_RRDYEN	(1<<9)	/* Recv ready interrupt enable */
 #define UCR1_RDMAEN	(1<<8)	/* Recv ready DMA enable */
 #define UCR1_IREN	(1<<7)	/* Infrared interface enable */
@@ -91,6 +93,7 @@
 #define UCR1_SNDBRK	(1<<4)	/* Send break */
 #define UCR1_TDMAEN	(1<<3)	/* Transmitter ready DMA enable */
 #define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */
+#define UCR1_ATDMAEN    (1<<2)  /* Aging DMA Timer Enable */
 #define UCR1_DOZE	(1<<1)	/* Doze */
 #define UCR1_UARTEN	(1<<0)	/* UART enabled */
 #define UCR2_ESCI	(1<<15)	/* Escape seq interrupt enable */
@@ -126,6 +129,7 @@
 #define UCR4_ENIRI	(1<<8)	/* Serial infrared interrupt enable */
 #define UCR4_WKEN	(1<<7)	/* Wake interrupt enable */
 #define UCR4_REF16	(1<<6)	/* Ref freq 16 MHz */
+#define UCR4_IDDMAEN    (1<<6)  /* DMA IDLE Condition Detected */
 #define UCR4_IRSC	(1<<5)	/* IR special case */
 #define UCR4_TCEN	(1<<3)	/* Transmit complete interrupt enable */
 #define UCR4_BKEN	(1<<2)	/* Break condition interrupt enable */
@@ -187,6 +191,7 @@
 enum imx_uart_type {
 	IMX1_UART,
 	IMX21_UART,
+	IMX6Q_UART,
 };
 
 /* device type dependent stuff */
@@ -209,6 +214,19 @@
 	struct clk		*clk_ipg;
 	struct clk		*clk_per;
 	const struct imx_uart_data *devdata;
+
+	/* DMA fields */
+	unsigned int		dma_is_inited:1;
+	unsigned int		dma_is_enabled:1;
+	unsigned int		dma_is_rxing:1;
+	unsigned int		dma_is_txing:1;
+	struct dma_chan		*dma_chan_rx, *dma_chan_tx;
+	struct scatterlist	rx_sgl, tx_sgl[2];
+	void			*rx_buf;
+	unsigned int		rx_bytes, tx_bytes;
+	struct work_struct	tsk_dma_rx, tsk_dma_tx;
+	unsigned int		dma_tx_nents;
+	wait_queue_head_t	dma_wait;
 };
 
 struct imx_port_ucrs {
@@ -232,6 +250,10 @@
 		.uts_reg = IMX21_UTS,
 		.devtype = IMX21_UART,
 	},
+	[IMX6Q_UART] = {
+		.uts_reg = IMX21_UTS,
+		.devtype = IMX6Q_UART,
+	},
 };
 
 static struct platform_device_id imx_uart_devtype[] = {
@@ -242,12 +264,16 @@
 		.name = "imx21-uart",
 		.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
 	}, {
+		.name = "imx6q-uart",
+		.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART],
+	}, {
 		/* sentinel */
 	}
 };
 MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
 
 static struct of_device_id imx_uart_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },
 	{ .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
 	{ .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
 	{ /* sentinel */ }
@@ -269,6 +295,10 @@
 	return sport->devdata->devtype == IMX21_UART;
 }
 
+static inline int is_imx6q_uart(struct imx_port *sport)
+{
+	return sport->devdata->devtype == IMX6Q_UART;
+}
 /*
  * Save and restore functions for UCR1, UCR2 and UCR3 registers
  */
@@ -387,6 +417,13 @@
 		return;
 	}
 
+	/*
+	 * We are maybe in the SMP context, so if the DMA TX thread is running
+	 * on other cpu, we have to wait for it to finish.
+	 */
+	if (sport->dma_is_enabled && sport->dma_is_txing)
+		return;
+
 	temp = readl(sport->port.membase + UCR1);
 	writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
 }
@@ -399,6 +436,13 @@
 	struct imx_port *sport = (struct imx_port *)port;
 	unsigned long temp;
 
+	/*
+	 * We are maybe in the SMP context, so if the DMA TX thread is running
+	 * on other cpu, we have to wait for it to finish.
+	 */
+	if (sport->dma_is_enabled && sport->dma_is_rxing)
+		return;
+
 	temp = readl(sport->port.membase + UCR2);
 	writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
 }
@@ -434,6 +478,95 @@
 		imx_stop_tx(&sport->port);
 }
 
+static void dma_tx_callback(void *data)
+{
+	struct imx_port *sport = data;
+	struct scatterlist *sgl = &sport->tx_sgl[0];
+	struct circ_buf *xmit = &sport->port.state->xmit;
+	unsigned long flags;
+
+	dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+
+	sport->dma_is_txing = 0;
+
+	/* update the stat */
+	spin_lock_irqsave(&sport->port.lock, flags);
+	xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
+	sport->port.icount.tx += sport->tx_bytes;
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&sport->port);
+
+	if (waitqueue_active(&sport->dma_wait)) {
+		wake_up(&sport->dma_wait);
+		dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
+		return;
+	}
+
+	schedule_work(&sport->tsk_dma_tx);
+}
+
+static void dma_tx_work(struct work_struct *w)
+{
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
+	struct circ_buf *xmit = &sport->port.state->xmit;
+	struct scatterlist *sgl = sport->tx_sgl;
+	struct dma_async_tx_descriptor *desc;
+	struct dma_chan	*chan = sport->dma_chan_tx;
+	struct device *dev = sport->port.dev;
+	enum dma_status status;
+	unsigned long flags;
+	int ret;
+
+	status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL);
+	if (DMA_IN_PROGRESS == status)
+		return;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+	sport->tx_bytes = uart_circ_chars_pending(xmit);
+	if (sport->tx_bytes == 0) {
+		spin_unlock_irqrestore(&sport->port.lock, flags);
+		return;
+	}
+
+	if (xmit->tail > xmit->head) {
+		sport->dma_tx_nents = 2;
+		sg_init_table(sgl, 2);
+		sg_set_buf(sgl, xmit->buf + xmit->tail,
+				UART_XMIT_SIZE - xmit->tail);
+		sg_set_buf(sgl + 1, xmit->buf, xmit->head);
+	} else {
+		sport->dma_tx_nents = 1;
+		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+	}
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+	if (ret == 0) {
+		dev_err(dev, "DMA mapping error for TX.\n");
+		return;
+	}
+	desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+					DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+	if (!desc) {
+		dev_err(dev, "We cannot prepare for the TX slave dma!\n");
+		return;
+	}
+	desc->callback = dma_tx_callback;
+	desc->callback_param = sport;
+
+	dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
+			uart_circ_chars_pending(xmit));
+	/* fire it */
+	sport->dma_is_txing = 1;
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+	return;
+}
+
 /*
  * interrupts disabled on entry
  */
@@ -460,8 +593,10 @@
 	temp |= UCR4_OREN;
 	writel(temp, sport->port.membase + UCR4);
 
-	temp = readl(sport->port.membase + UCR1);
-	writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+	if (!sport->dma_is_enabled) {
+		temp = readl(sport->port.membase + UCR1);
+		writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+	}
 
 	if (USE_IRDA(sport)) {
 		temp = readl(sport->port.membase + UCR1);
@@ -473,6 +608,15 @@
 		writel(temp, sport->port.membase + UCR4);
 	}
 
+	if (sport->dma_is_enabled) {
+		/*
+		 * We may in the interrupt context, so arise a work_struct to
+		 * do the real job.
+		 */
+		schedule_work(&sport->tsk_dma_tx);
+		return;
+	}
+
 	if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
 		imx_transmit_buffer(sport);
 }
@@ -588,6 +732,28 @@
 	return IRQ_HANDLED;
 }
 
+/*
+ * If the RXFIFO is filled with some data, and then we
+ * arise a DMA operation to receive them.
+ */
+static void imx_dma_rxint(struct imx_port *sport)
+{
+	unsigned long temp;
+
+	temp = readl(sport->port.membase + USR2);
+	if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
+		sport->dma_is_rxing = 1;
+
+		/* disable the `Recerver Ready Interrrupt` */
+		temp = readl(sport->port.membase + UCR1);
+		temp &= ~(UCR1_RRDYEN);
+		writel(temp, sport->port.membase + UCR1);
+
+		/* tell the DMA to receive the data. */
+		schedule_work(&sport->tsk_dma_rx);
+	}
+}
+
 static irqreturn_t imx_int(int irq, void *dev_id)
 {
 	struct imx_port *sport = dev_id;
@@ -596,8 +762,12 @@
 
 	sts = readl(sport->port.membase + USR1);
 
-	if (sts & USR1_RRDY)
-		imx_rxint(irq, dev_id);
+	if (sts & USR1_RRDY) {
+		if (sport->dma_is_enabled)
+			imx_dma_rxint(sport);
+		else
+			imx_rxint(irq, dev_id);
+	}
 
 	if (sts & USR1_TRDY &&
 			readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
@@ -654,7 +824,8 @@
 	temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
 
 	if (mctrl & TIOCM_RTS)
-		temp |= UCR2_CTS;
+		if (!sport->dma_is_enabled)
+			temp |= UCR2_CTS;
 
 	writel(temp, sport->port.membase + UCR2);
 }
@@ -693,6 +864,226 @@
 	return 0;
 }
 
+#define RX_BUF_SIZE	(PAGE_SIZE)
+static int start_rx_dma(struct imx_port *sport);
+static void dma_rx_work(struct work_struct *w)
+{
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx);
+	struct tty_port *port = &sport->port.state->port;
+
+	if (sport->rx_bytes) {
+		tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes);
+		tty_flip_buffer_push(port);
+		sport->rx_bytes = 0;
+	}
+
+	if (sport->dma_is_rxing)
+		start_rx_dma(sport);
+}
+
+static void imx_rx_dma_done(struct imx_port *sport)
+{
+	unsigned long temp;
+
+	/* Enable this interrupt when the RXFIFO is empty. */
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_RRDYEN;
+	writel(temp, sport->port.membase + UCR1);
+
+	sport->dma_is_rxing = 0;
+
+	/* Is the shutdown waiting for us? */
+	if (waitqueue_active(&sport->dma_wait))
+		wake_up(&sport->dma_wait);
+}
+
+/*
+ * There are three kinds of RX DMA interrupts(such as in the MX6Q):
+ *   [1] the RX DMA buffer is full.
+ *   [2] the Aging timer expires(wait for 8 bytes long)
+ *   [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *
+ * The [2] is trigger when a character was been sitting in the FIFO
+ * meanwhile [3] can wait for 32 bytes long when the RX line is
+ * on IDLE state and RxFIFO is empty.
+ */
+static void dma_rx_callback(void *data)
+{
+	struct imx_port *sport = data;
+	struct dma_chan	*chan = sport->dma_chan_rx;
+	struct scatterlist *sgl = &sport->rx_sgl;
+	struct dma_tx_state state;
+	enum dma_status status;
+	unsigned int count;
+
+	/* unmap it first */
+	dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
+
+	status = chan->device->device_tx_status(chan, (dma_cookie_t)0, &state);
+	count = RX_BUF_SIZE - state.residue;
+	dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
+
+	if (count) {
+		sport->rx_bytes = count;
+		schedule_work(&sport->tsk_dma_rx);
+	} else
+		imx_rx_dma_done(sport);
+}
+
+static int start_rx_dma(struct imx_port *sport)
+{
+	struct scatterlist *sgl = &sport->rx_sgl;
+	struct dma_chan	*chan = sport->dma_chan_rx;
+	struct device *dev = sport->port.dev;
+	struct dma_async_tx_descriptor *desc;
+	int ret;
+
+	sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
+	ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
+	if (ret == 0) {
+		dev_err(dev, "DMA mapping error for RX.\n");
+		return -EINVAL;
+	}
+	desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
+					DMA_PREP_INTERRUPT);
+	if (!desc) {
+		dev_err(dev, "We cannot prepare for the RX slave dma!\n");
+		return -EINVAL;
+	}
+	desc->callback = dma_rx_callback;
+	desc->callback_param = sport;
+
+	dev_dbg(dev, "RX: prepare for the DMA.\n");
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+	return 0;
+}
+
+static void imx_uart_dma_exit(struct imx_port *sport)
+{
+	if (sport->dma_chan_rx) {
+		dma_release_channel(sport->dma_chan_rx);
+		sport->dma_chan_rx = NULL;
+
+		kfree(sport->rx_buf);
+		sport->rx_buf = NULL;
+	}
+
+	if (sport->dma_chan_tx) {
+		dma_release_channel(sport->dma_chan_tx);
+		sport->dma_chan_tx = NULL;
+	}
+
+	sport->dma_is_inited = 0;
+}
+
+static int imx_uart_dma_init(struct imx_port *sport)
+{
+	struct dma_slave_config slave_config = {};
+	struct device *dev = sport->port.dev;
+	int ret;
+
+	/* Prepare for RX : */
+	sport->dma_chan_rx = dma_request_slave_channel(dev, "rx");
+	if (!sport->dma_chan_rx) {
+		dev_dbg(dev, "cannot get the DMA channel.\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	slave_config.direction = DMA_DEV_TO_MEM;
+	slave_config.src_addr = sport->port.mapbase + URXD0;
+	slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	slave_config.src_maxburst = RXTL;
+	ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
+	if (ret) {
+		dev_err(dev, "error in RX dma configuration.\n");
+		goto err;
+	}
+
+	sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!sport->rx_buf) {
+		dev_err(dev, "cannot alloc DMA buffer.\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	sport->rx_bytes = 0;
+
+	/* Prepare for TX : */
+	sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
+	if (!sport->dma_chan_tx) {
+		dev_err(dev, "cannot get the TX DMA channel!\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	slave_config.direction = DMA_MEM_TO_DEV;
+	slave_config.dst_addr = sport->port.mapbase + URTX0;
+	slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	slave_config.dst_maxburst = TXTL;
+	ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
+	if (ret) {
+		dev_err(dev, "error in TX dma configuration.");
+		goto err;
+	}
+
+	sport->dma_is_inited = 1;
+
+	return 0;
+err:
+	imx_uart_dma_exit(sport);
+	return ret;
+}
+
+static void imx_enable_dma(struct imx_port *sport)
+{
+	unsigned long temp;
+	struct tty_port *port = &sport->port.state->port;
+
+	port->low_latency = 1;
+	INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
+	INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);
+	init_waitqueue_head(&sport->dma_wait);
+
+	/* set UCR1 */
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
+		/* wait for 32 idle frames for IDDMA interrupt */
+		UCR1_ICD_REG(3);
+	writel(temp, sport->port.membase + UCR1);
+
+	/* set UCR4 */
+	temp = readl(sport->port.membase + UCR4);
+	temp |= UCR4_IDDMAEN;
+	writel(temp, sport->port.membase + UCR4);
+
+	sport->dma_is_enabled = 1;
+}
+
+static void imx_disable_dma(struct imx_port *sport)
+{
+	unsigned long temp;
+	struct tty_port *port = &sport->port.state->port;
+
+	/* clear UCR1 */
+	temp = readl(sport->port.membase + UCR1);
+	temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN);
+	writel(temp, sport->port.membase + UCR1);
+
+	/* clear UCR2 */
+	temp = readl(sport->port.membase + UCR2);
+	temp &= ~(UCR2_CTSC | UCR2_CTS);
+	writel(temp, sport->port.membase + UCR2);
+
+	/* clear UCR4 */
+	temp = readl(sport->port.membase + UCR4);
+	temp &= ~UCR4_IDDMAEN;
+	writel(temp, sport->port.membase + UCR4);
+
+	sport->dma_is_enabled = 0;
+	port->low_latency = 0;
+}
+
 /* half the RX buffer size */
 #define CTSTL 16
 
@@ -702,15 +1093,13 @@
 	int retval;
 	unsigned long flags, temp;
 
-	if (!uart_console(port)) {
-		retval = clk_prepare_enable(sport->clk_per);
-		if (retval)
-			goto error_out1;
-		retval = clk_prepare_enable(sport->clk_ipg);
-		if (retval) {
-			clk_disable_unprepare(sport->clk_per);
-			goto error_out1;
-		}
+	retval = clk_prepare_enable(sport->clk_per);
+	if (retval)
+		goto error_out1;
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval) {
+		clk_disable_unprepare(sport->clk_per);
+		goto error_out1;
 	}
 
 	imx_setup_ufcr(sport, 0);
@@ -803,7 +1192,7 @@
 		}
 	}
 
-	if (is_imx21_uart(sport)) {
+	if (!is_imx1_uart(sport)) {
 		temp = readl(sport->port.membase + UCR3);
 		temp |= IMX21_UCR3_RXDMUXSEL;
 		writel(temp, sport->port.membase + UCR3);
@@ -833,7 +1222,7 @@
 
 	if (USE_IRDA(sport)) {
 		struct imxuart_platform_data *pdata;
-		pdata = sport->port.dev->platform_data;
+		pdata = dev_get_platdata(sport->port.dev);
 		sport->irda_inv_rx = pdata->irda_inv_rx;
 		sport->irda_inv_tx = pdata->irda_inv_tx;
 		sport->trcv_delay = pdata->transceiver_delay;
@@ -859,6 +1248,15 @@
 	unsigned long temp;
 	unsigned long flags;
 
+	if (sport->dma_is_enabled) {
+		/* We have to wait for the DMA to finish. */
+		wait_event(sport->dma_wait,
+			!sport->dma_is_rxing && !sport->dma_is_txing);
+		imx_stop_rx(port);
+		imx_disable_dma(sport);
+		imx_uart_dma_exit(sport);
+	}
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 	temp = readl(sport->port.membase + UCR2);
 	temp &= ~(UCR2_TXEN);
@@ -867,7 +1265,7 @@
 
 	if (USE_IRDA(sport)) {
 		struct imxuart_platform_data *pdata;
-		pdata = sport->port.dev->platform_data;
+		pdata = dev_get_platdata(sport->port.dev);
 		if (pdata->irda_enable)
 			pdata->irda_enable(0);
 	}
@@ -901,10 +1299,8 @@
 	writel(temp, sport->port.membase + UCR1);
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 
-	if (!uart_console(&sport->port)) {
-		clk_disable_unprepare(sport->clk_per);
-		clk_disable_unprepare(sport->clk_ipg);
-	}
+	clk_disable_unprepare(sport->clk_per);
+	clk_disable_unprepare(sport->clk_ipg);
 }
 
 static void
@@ -947,6 +1343,11 @@
 		if (sport->have_rtscts) {
 			ucr2 &= ~UCR2_IRTS;
 			ucr2 |= UCR2_CTSC;
+
+			/* Can we enable the DMA support? */
+			if (is_imx6q_uart(sport) && !uart_console(port)
+				&& !sport->dma_is_inited)
+				imx_uart_dma_init(sport);
 		} else {
 			termios->c_cflag &= ~CRTSCTS;
 		}
@@ -1020,6 +1421,11 @@
 		 */
 		div = 1;
 	} else {
+		/* custom-baudrate handling */
+		div = sport->port.uartclk / (baud * 16);
+		if (baud == 38400 && quot != div)
+			baud = sport->port.uartclk / (quot * 16);
+
 		div = sport->port.uartclk / (baud * 16);
 		if (div > 7)
 			div = 7;
@@ -1048,7 +1454,7 @@
 	writel(num, sport->port.membase + UBIR);
 	writel(denom, sport->port.membase + UBMR);
 
-	if (is_imx21_uart(sport))
+	if (!is_imx1_uart(sport))
 		writel(sport->port.uartclk / div / 1000,
 				sport->port.membase + IMX21_ONEMS);
 
@@ -1060,6 +1466,8 @@
 	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
 		imx_enable_ms(&sport->port);
 
+	if (sport->dma_is_inited && !sport->dma_is_enabled)
+		imx_enable_dma(sport);
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
@@ -1251,6 +1659,16 @@
 	unsigned int ucr1;
 	unsigned long flags = 0;
 	int locked = 1;
+	int retval;
+
+	retval = clk_enable(sport->clk_per);
+	if (retval)
+		return;
+	retval = clk_enable(sport->clk_ipg);
+	if (retval) {
+		clk_disable(sport->clk_per);
+		return;
+	}
 
 	if (sport->port.sysrq)
 		locked = 0;
@@ -1286,6 +1704,9 @@
 
 	if (locked)
 		spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	clk_disable(sport->clk_ipg);
+	clk_disable(sport->clk_per);
 }
 
 /*
@@ -1359,6 +1780,7 @@
 	int bits = 8;
 	int parity = 'n';
 	int flow = 'n';
+	int retval;
 
 	/*
 	 * Check whether an invalid uart number has been specified, and
@@ -1371,6 +1793,11 @@
 	if (sport == NULL)
 		return -ENODEV;
 
+	/* For setting the registers, we only need to enable the ipg clock. */
+	retval = clk_prepare_enable(sport->clk_ipg);
+	if (retval)
+		goto error_console;
+
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	else
@@ -1378,7 +1805,20 @@
 
 	imx_setup_ufcr(sport, 0);
 
-	return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+	retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
+
+	clk_disable(sport->clk_ipg);
+	if (retval) {
+		clk_unprepare(sport->clk_ipg);
+		goto error_console;
+	}
+
+	retval = clk_prepare(sport->clk_per);
+	if (retval)
+		clk_disable_unprepare(sport->clk_ipg);
+
+error_console:
+	return retval;
 }
 
 static struct uart_driver imx_reg;
@@ -1472,6 +1912,9 @@
 
 	sport->devdata = of_id->data;
 
+	if (of_device_is_stdout_path(np))
+		add_preferred_console(imx_reg.cons->name, sport->port.line, 0);
+
 	return 0;
 }
 #else
@@ -1485,7 +1928,7 @@
 static void serial_imx_probe_pdata(struct imx_port *sport,
 		struct platform_device *pdev)
 {
-	struct imxuart_platform_data *pdata = pdev->dev.platform_data;
+	struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	sport->port.line = pdev->id;
 	sport->devdata = (struct imx_uart_data	*) pdev->id_entry->driver_data;
@@ -1507,7 +1950,6 @@
 	void __iomem *base;
 	int ret = 0;
 	struct resource *res;
-	struct pinctrl *pinctrl;
 
 	sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
 	if (!sport)
@@ -1543,13 +1985,6 @@
 	sport->timer.function = imx_timeout;
 	sport->timer.data     = (unsigned long)sport;
 
-	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		ret = PTR_ERR(pinctrl);
-		dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
-		return ret;
-	}
-
 	sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(sport->clk_ipg)) {
 		ret = PTR_ERR(sport->clk_ipg);
@@ -1564,18 +1999,15 @@
 		return ret;
 	}
 
-	clk_prepare_enable(sport->clk_per);
-	clk_prepare_enable(sport->clk_ipg);
-
 	sport->port.uartclk = clk_get_rate(sport->clk_per);
 
 	imx_ports[sport->port.line] = sport;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (pdata && pdata->init) {
 		ret = pdata->init(pdev);
 		if (ret)
-			goto clkput;
+			return ret;
 	}
 
 	ret = uart_add_one_port(&imx_reg, &sport->port);
@@ -1583,18 +2015,10 @@
 		goto deinit;
 	platform_set_drvdata(pdev, sport);
 
-	if (!uart_console(&sport->port)) {
-		clk_disable_unprepare(sport->clk_per);
-		clk_disable_unprepare(sport->clk_ipg);
-	}
-
 	return 0;
 deinit:
 	if (pdata && pdata->exit)
 		pdata->exit(pdev);
-clkput:
-	clk_disable_unprepare(sport->clk_per);
-	clk_disable_unprepare(sport->clk_ipg);
 	return ret;
 }
 
@@ -1603,9 +2027,7 @@
 	struct imxuart_platform_data *pdata;
 	struct imx_port *sport = platform_get_drvdata(pdev);
 
-	pdata = pdev->dev.platform_data;
-
-	platform_set_drvdata(pdev, NULL);
+	pdata = dev_get_platdata(&pdev->dev);
 
 	uart_remove_one_port(&imx_reg, &sport->port);
 
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index e2520ab..1274499 100644
--- a/drivers/tty/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
@@ -297,7 +297,7 @@
 	struct ioc4_uartregs uart_1;
 	struct ioc4_uartregs uart_2;
 	struct ioc4_uartregs uart_3;
-} ioc4_serial;
+};
 
 /* UART clock speed */
 #define IOC4_SER_XIN_CLK_66     66666667
@@ -2767,7 +2767,7 @@
  *		called per card found from IOC4 master module.
  * @idd: Master module data for this IOC4
  */
-int
+static int
 ioc4_serial_attach_one(struct ioc4_driver_data *idd)
 {
 	unsigned long tmp_addr1;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 15733da..88d01e0 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -318,7 +318,7 @@
 	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
 	int retval;
 
-	if (ltq_port->clk)
+	if (!IS_ERR(ltq_port->clk))
 		clk_enable(ltq_port->clk);
 	port->uartclk = clk_get_rate(ltq_port->fpiclk);
 
@@ -386,7 +386,7 @@
 		port->membase + LTQ_ASC_RXFCON);
 	ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
 		port->membase + LTQ_ASC_TXFCON);
-	if (ltq_port->clk)
+	if (!IS_ERR(ltq_port->clk))
 		clk_disable(ltq_port->clk);
 }
 
@@ -636,6 +636,9 @@
 
 	port = &ltq_port->port;
 
+	if (!IS_ERR(ltq_port->clk))
+		clk_enable(ltq_port->clk);
+
 	port->uartclk = clk_get_rate(ltq_port->fpiclk);
 
 	if (options)
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index dffea6b..701644f 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -279,7 +279,10 @@
 
 		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
 	}
+
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
 }
 
 static void __serial_lpc32xx_tx(struct uart_port *port)
@@ -351,10 +354,8 @@
 	}
 
 	/* Data received? */
-	if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+	if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT))
 		__serial_lpc32xx_rx(port);
-		tty_flip_buffer_push(tport);
-	}
 
 	/* Transmit data request? */
 	if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index bb1afa0..9cd9b4e 100644
--- a/drivers/tty/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
@@ -368,7 +368,10 @@
 	ignore_char:
 		*status = serial_in(up, UART_LSR);
 	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+
+	spin_unlock(&up->port.lock);
 	tty_flip_buffer_push(port);
+	spin_lock(&up->port.lock);
 }
 
 static void transmit_chars(struct uart_sio_port *up)
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 35866d5..79f9a9e 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -779,7 +779,7 @@
 	max3100s[i]->irq = spi->irq;
 	spin_lock_init(&max3100s[i]->conf_lock);
 	spi_set_drvdata(spi, max3100s[i]);
-	pdata = spi->dev.platform_data;
+	pdata = dev_get_platdata(&spi->dev);
 	max3100s[i]->crystal = pdata->crystal;
 	max3100s[i]->loopback = pdata->loopback;
 	max3100s[i]->poll_time = pdata->poll_time * HZ / 1000;
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 8941e64..b2e707aa 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1,7 +1,7 @@
 /*
- *  Maxim (Dallas) MAX3107/8 serial driver
+ *  Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
  *
- *  Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *  Copyright (C) 2012-2013 Alexander Shiyan <shc_work@mail.ru>
  *
  *  Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
  *  Based on max3110.c, by Feng Tang <feng.tang@intel.com>
@@ -13,11 +13,10 @@
  *  (at your option) any later version.
  */
 
-/* TODO: MAX3109 support (Dual) */
-/* TODO: MAX14830 support (Quad) */
-
 #include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/bitops.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
 #include <linux/tty.h>
@@ -25,8 +24,10 @@
 #include <linux/regmap.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
+
 #include <linux/platform_data/max310x.h>
 
+#define MAX310X_NAME			"max310x"
 #define MAX310X_MAJOR			204
 #define MAX310X_MINOR			209
 
@@ -37,7 +38,8 @@
 #define MAX310X_IRQSTS_REG		(0x02) /* IRQ status */
 #define MAX310X_LSR_IRQEN_REG		(0x03) /* LSR IRQ enable */
 #define MAX310X_LSR_IRQSTS_REG		(0x04) /* LSR IRQ status */
-#define MAX310X_SPCHR_IRQEN_REG		(0x05) /* Special char IRQ enable */
+#define MAX310X_REG_05			(0x05)
+#define MAX310X_SPCHR_IRQEN_REG		MAX310X_REG_05 /* Special char IRQ en */
 #define MAX310X_SPCHR_IRQSTS_REG	(0x06) /* Special char IRQ status */
 #define MAX310X_STS_IRQEN_REG		(0x07) /* Status IRQ enable */
 #define MAX310X_STS_IRQSTS_REG		(0x08) /* Status IRQ status */
@@ -63,8 +65,15 @@
 #define MAX310X_BRGDIVLSB_REG		(0x1c) /* Baud rate divisor LSB */
 #define MAX310X_BRGDIVMSB_REG		(0x1d) /* Baud rate divisor MSB */
 #define MAX310X_CLKSRC_REG		(0x1e) /* Clock source */
-/* Only present in MAX3107 */
-#define MAX3107_REVID_REG		(0x1f) /* Revision identification */
+#define MAX310X_REG_1F			(0x1f)
+
+#define MAX310X_REVID_REG		MAX310X_REG_1F /* Revision ID */
+
+#define MAX310X_GLOBALIRQ_REG		MAX310X_REG_1F /* Global IRQ (RO) */
+#define MAX310X_GLOBALCMD_REG		MAX310X_REG_1F /* Global Command (WO) */
+
+/* Extended registers */
+#define MAX310X_REVID_EXTREG		MAX310X_REG_05 /* Revision ID */
 
 /* IRQ register bits */
 #define MAX310X_IRQ_LSR_BIT		(1 << 0) /* LSR interrupt */
@@ -246,58 +255,210 @@
 #define MAX310X_CLKSRC_EXTCLK_BIT	(1 << 4) /* External clock enable */
 #define MAX310X_CLKSRC_CLK2RTS_BIT	(1 << 7) /* Baud clk to RTS pin */
 
+/* Global commands */
+#define MAX310X_EXTREG_ENBL		(0xce)
+#define MAX310X_EXTREG_DSBL		(0xcd)
+
 /* Misc definitions */
 #define MAX310X_FIFO_SIZE		(128)
+#define MAX310x_REV_MASK		(0xfc)
 
 /* MAX3107 specific */
 #define MAX3107_REV_ID			(0xa0)
-#define MAX3107_REV_MASK		(0xfe)
 
-/* IRQ status bits definitions */
-#define MAX310X_IRQ_TX			(MAX310X_IRQ_TXFIFO_BIT | \
-					 MAX310X_IRQ_TXEMPTY_BIT)
-#define MAX310X_IRQ_RX			(MAX310X_IRQ_RXFIFO_BIT | \
-					 MAX310X_IRQ_RXEMPTY_BIT)
+/* MAX3109 specific */
+#define MAX3109_REV_ID			(0xc0)
 
-/* Supported chip types */
-enum {
-	MAX310X_TYPE_MAX3107	= 3107,
-	MAX310X_TYPE_MAX3108	= 3108,
+/* MAX14830 specific */
+#define MAX14830_BRGCFG_CLKDIS_BIT	(1 << 6) /* Clock Disable */
+#define MAX14830_REV_ID			(0xb0)
+
+struct max310x_devtype {
+	char	name[9];
+	int	nr;
+	int	(*detect)(struct device *);
+	void	(*power)(struct uart_port *, int);
+};
+
+struct max310x_one {
+	struct uart_port	port;
+	struct work_struct	tx_work;
 };
 
 struct max310x_port {
 	struct uart_driver	uart;
-	struct uart_port	port;
-
-	const char		*name;
-	int			uartclk;
-
-	unsigned int		nr_gpio;
+	struct max310x_devtype	*devtype;
+	struct regmap		*regmap;
+	struct regmap_config	regcfg;
+	struct mutex		mutex;
+	struct max310x_pdata	*pdata;
+	int			gpio_used;
 #ifdef CONFIG_GPIOLIB
 	struct gpio_chip	gpio;
 #endif
-
-	struct regmap		*regmap;
-	struct regmap_config	regcfg;
-
-	struct workqueue_struct	*wq;
-	struct work_struct	tx_work;
-
-	struct mutex		max310x_mutex;
-
-	struct max310x_pdata	*pdata;
+	struct max310x_one	p[0];
 };
 
-static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg)
+static u8 max310x_port_read(struct uart_port *port, u8 reg)
 {
-	switch (reg) {
+	struct max310x_port *s = dev_get_drvdata(port->dev);
+	unsigned int val = 0;
+
+	regmap_read(s->regmap, port->iobase + reg, &val);
+
+	return val;
+}
+
+static void max310x_port_write(struct uart_port *port, u8 reg, u8 val)
+{
+	struct max310x_port *s = dev_get_drvdata(port->dev);
+
+	regmap_write(s->regmap, port->iobase + reg, val);
+}
+
+static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)
+{
+	struct max310x_port *s = dev_get_drvdata(port->dev);
+
+	regmap_update_bits(s->regmap, port->iobase + reg, mask, val);
+}
+
+static int max3107_detect(struct device *dev)
+{
+	struct max310x_port *s = dev_get_drvdata(dev);
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
+	if (ret)
+		return ret;
+
+	if (((val & MAX310x_REV_MASK) != MAX3107_REV_ID)) {
+		dev_err(dev,
+			"%s ID 0x%02x does not match\n", s->devtype->name, val);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int max3108_detect(struct device *dev)
+{
+	struct max310x_port *s = dev_get_drvdata(dev);
+	unsigned int val = 0;
+	int ret;
+
+	/* MAX3108 have not REV ID register, we just check default value
+	 * from clocksource register to make sure everything works.
+	 */
+	ret = regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
+	if (ret)
+		return ret;
+
+	if (val != (MAX310X_CLKSRC_EXTCLK_BIT | MAX310X_CLKSRC_PLLBYP_BIT)) {
+		dev_err(dev, "%s not present\n", s->devtype->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int max3109_detect(struct device *dev)
+{
+	struct max310x_port *s = dev_get_drvdata(dev);
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
+	if (ret)
+		return ret;
+
+	if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
+		dev_err(dev,
+			"%s ID 0x%02x does not match\n", s->devtype->name, val);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void max310x_power(struct uart_port *port, int on)
+{
+	max310x_port_update(port, MAX310X_MODE1_REG,
+			    MAX310X_MODE1_FORCESLEEP_BIT,
+			    on ? 0 : MAX310X_MODE1_FORCESLEEP_BIT);
+	if (on)
+		msleep(50);
+}
+
+static int max14830_detect(struct device *dev)
+{
+	struct max310x_port *s = dev_get_drvdata(dev);
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
+			   MAX310X_EXTREG_ENBL);
+	if (ret)
+		return ret;
+	
+	regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
+	regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
+	if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) {
+		dev_err(dev,
+			"%s ID 0x%02x does not match\n", s->devtype->name, val);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void max14830_power(struct uart_port *port, int on)
+{
+	max310x_port_update(port, MAX310X_BRGCFG_REG,
+			    MAX14830_BRGCFG_CLKDIS_BIT,
+			    on ? 0 : MAX14830_BRGCFG_CLKDIS_BIT);
+	if (on)
+		msleep(50);
+}
+
+static const struct max310x_devtype max3107_devtype = {
+	.name	= "MAX3107",
+	.nr	= 1,
+	.detect	= max3107_detect,
+	.power	= max310x_power,
+};
+
+static const struct max310x_devtype max3108_devtype = {
+	.name	= "MAX3108",
+	.nr	= 1,
+	.detect	= max3108_detect,
+	.power	= max310x_power,
+};
+
+static const struct max310x_devtype max3109_devtype = {
+	.name	= "MAX3109",
+	.nr	= 2,
+	.detect	= max3109_detect,
+	.power	= max310x_power,
+};
+
+static const struct max310x_devtype max14830_devtype = {
+	.name	= "MAX14830",
+	.nr	= 4,
+	.detect	= max14830_detect,
+	.power	= max14830_power,
+};
+
+static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg & 0x1f) {
 	case MAX310X_IRQSTS_REG:
 	case MAX310X_LSR_IRQSTS_REG:
 	case MAX310X_SPCHR_IRQSTS_REG:
 	case MAX310X_STS_IRQSTS_REG:
 	case MAX310X_TXFIFOLVL_REG:
 	case MAX310X_RXFIFOLVL_REG:
-	case MAX3107_REVID_REG: /* Only available on MAX3107 */
 		return false;
 	default:
 		break;
@@ -308,7 +469,7 @@
 
 static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
 {
-	switch (reg) {
+	switch (reg & 0x1f) {
 	case MAX310X_RHR_REG:
 	case MAX310X_IRQSTS_REG:
 	case MAX310X_LSR_IRQSTS_REG:
@@ -317,6 +478,9 @@
 	case MAX310X_TXFIFOLVL_REG:
 	case MAX310X_RXFIFOLVL_REG:
 	case MAX310X_GPIODATA_REG:
+	case MAX310X_BRGDIVLSB_REG:
+	case MAX310X_REG_05:
+	case MAX310X_REG_1F:
 		return true;
 	default:
 		break;
@@ -327,7 +491,7 @@
 
 static bool max310x_reg_precious(struct device *dev, unsigned int reg)
 {
-	switch (reg) {
+	switch (reg & 0x1f) {
 	case MAX310X_RHR_REG:
 	case MAX310X_IRQSTS_REG:
 	case MAX310X_SPCHR_IRQSTS_REG:
@@ -340,42 +504,25 @@
 	return false;
 }
 
-static void max310x_set_baud(struct max310x_port *s, int baud)
+static void max310x_set_baud(struct uart_port *port, int baud)
 {
-	unsigned int mode = 0, div = s->uartclk / baud;
+	unsigned int mode = 0, div = port->uartclk / baud;
 
 	if (!(div / 16)) {
 		/* Mode x2 */
 		mode = MAX310X_BRGCFG_2XMODE_BIT;
-		div = (s->uartclk * 2) / baud;
+		div = (port->uartclk * 2) / baud;
 	}
 
 	if (!(div / 16)) {
 		/* Mode x4 */
 		mode = MAX310X_BRGCFG_4XMODE_BIT;
-		div = (s->uartclk * 4) / baud;
+		div = (port->uartclk * 4) / baud;
 	}
 
-	regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG,
-		     ((div / 16) >> 8) & 0xff);
-	regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff);
-	regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode);
-}
-
-static void max310x_wait_pll(struct max310x_port *s)
-{
-	int tryes = 1000;
-
-	/* Wait for PLL only if crystal is used */
-	if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) {
-		unsigned int sts = 0;
-
-		while (tryes--) {
-			regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts);
-			if (sts & MAX310X_STS_CLKREADY_BIT)
-				break;
-		}
-	}
+	max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
+	max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
+	max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
 }
 
 static int max310x_update_best_err(unsigned long f, long *besterr)
@@ -449,49 +596,49 @@
 
 	regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
 
-	if (pllcfg)
-		max310x_wait_pll(s);
-
-	dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq);
+	/* Wait for crystal */
+	if (pllcfg && !(s->pdata->driver_flags & MAX310X_EXT_CLK))
+		msleep(10);
 
 	return (int)bestfreq;
 }
 
-static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
+static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
 {
-	unsigned int sts = 0, ch = 0, flag;
+	unsigned int sts, ch, flag;
 
-	if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) {
-		dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen);
+	if (unlikely(rxlen >= port->fifosize)) {
+		dev_warn_ratelimited(port->dev,
+				     "Port %i: Possible RX FIFO overrun\n",
+				     port->line);
+		port->icount.buf_overrun++;
 		/* Ensure sanity of RX level */
-		rxlen = MAX310X_FIFO_SIZE;
+		rxlen = port->fifosize;
 	}
 
-	dev_dbg(s->port.dev, "RX Len = %u\n", rxlen);
-
 	while (rxlen--) {
-		regmap_read(s->regmap, MAX310X_RHR_REG, &ch);
-		regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts);
+		ch = max310x_port_read(port, MAX310X_RHR_REG);
+		sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
 
 		sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT |
 		       MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT;
 
-		s->port.icount.rx++;
+		port->icount.rx++;
 		flag = TTY_NORMAL;
 
 		if (unlikely(sts)) {
 			if (sts & MAX310X_LSR_RXBRK_BIT) {
-				s->port.icount.brk++;
-				if (uart_handle_break(&s->port))
+				port->icount.brk++;
+				if (uart_handle_break(port))
 					continue;
 			} else if (sts & MAX310X_LSR_RXPAR_BIT)
-				s->port.icount.parity++;
+				port->icount.parity++;
 			else if (sts & MAX310X_LSR_FRERR_BIT)
-				s->port.icount.frame++;
+				port->icount.frame++;
 			else if (sts & MAX310X_LSR_RXOVR_BIT)
-				s->port.icount.overrun++;
+				port->icount.overrun++;
 
-			sts &= s->port.read_status_mask;
+			sts &= port->read_status_mask;
 			if (sts & MAX310X_LSR_RXBRK_BIT)
 				flag = TTY_BREAK;
 			else if (sts & MAX310X_LSR_RXPAR_BIT)
@@ -502,129 +649,129 @@
 				flag = TTY_OVERRUN;
 		}
 
-		if (uart_handle_sysrq_char(s->port, ch))
+		if (uart_handle_sysrq_char(port, ch))
 			continue;
 
-		if (sts & s->port.ignore_status_mask)
+		if (sts & port->ignore_status_mask)
 			continue;
 
-		uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT,
-				 ch, flag);
+		uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, ch, flag);
 	}
 
-	tty_flip_buffer_push(&s->port.state->port);
+	tty_flip_buffer_push(&port->state->port);
 }
 
-static void max310x_handle_tx(struct max310x_port *s)
+static void max310x_handle_tx(struct uart_port *port)
 {
-	struct circ_buf *xmit = &s->port.state->xmit;
-	unsigned int txlen = 0, to_send;
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned int txlen, to_send;
 
-	if (unlikely(s->port.x_char)) {
-		regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char);
-		s->port.icount.tx++;
-		s->port.x_char = 0;
+	if (unlikely(port->x_char)) {
+		max310x_port_write(port, MAX310X_THR_REG, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
 		return;
 	}
 
-	if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
 		return;
 
 	/* Get length of data pending in circular buffer */
 	to_send = uart_circ_chars_pending(xmit);
 	if (likely(to_send)) {
 		/* Limit to size of TX FIFO */
-		regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen);
-		txlen = MAX310X_FIFO_SIZE - txlen;
+		txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
+		txlen = port->fifosize - txlen;
 		to_send = (to_send > txlen) ? txlen : to_send;
 
-		dev_dbg(s->port.dev, "TX Len = %u\n", to_send);
-
 		/* Add data to send */
-		s->port.icount.tx += to_send;
+		port->icount.tx += to_send;
 		while (to_send--) {
-			regmap_write(s->regmap, MAX310X_THR_REG,
-				     xmit->buf[xmit->tail]);
+			max310x_port_write(port, MAX310X_THR_REG,
+					   xmit->buf[xmit->tail]);
 			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		};
 	}
 
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(&s->port);
+		uart_write_wakeup(port);
+}
+
+static void max310x_port_irq(struct max310x_port *s, int portno)
+{
+	struct uart_port *port = &s->p[portno].port;
+
+	do {
+		unsigned int ists, lsr, rxlen;
+
+		/* Read IRQ status & RX FIFO level */
+		ists = max310x_port_read(port, MAX310X_IRQSTS_REG);
+		rxlen = max310x_port_read(port, MAX310X_RXFIFOLVL_REG);
+		if (!ists && !rxlen)
+			break;
+
+		if (ists & MAX310X_IRQ_CTS_BIT) {
+			lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
+			uart_handle_cts_change(port,
+					       !!(lsr & MAX310X_LSR_CTS_BIT));
+		}
+		if (rxlen)
+			max310x_handle_rx(port, rxlen);
+		if (ists & MAX310X_IRQ_TXEMPTY_BIT) {
+			mutex_lock(&s->mutex);
+			max310x_handle_tx(port);
+			mutex_unlock(&s->mutex);
+		}
+	} while (1);
 }
 
 static irqreturn_t max310x_ist(int irq, void *dev_id)
 {
 	struct max310x_port *s = (struct max310x_port *)dev_id;
-	unsigned int ists = 0, lsr = 0, rxlen = 0;
 
-	mutex_lock(&s->max310x_mutex);
+	if (s->uart.nr > 1) {
+		do {
+			unsigned int val = ~0;
 
-	for (;;) {
-		/* Read IRQ status & RX FIFO level */
-		regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists);
-		regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr);
-		regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen);
-		if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen)
-			break;
-
-		dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists);
-
-		if (rxlen)
-			max310x_handle_rx(s, rxlen);
-		if (ists & MAX310X_IRQ_TX)
-			max310x_handle_tx(s);
-		if (ists & MAX310X_IRQ_CTS_BIT)
-			uart_handle_cts_change(&s->port,
-					       !!(lsr & MAX310X_LSR_CTS_BIT));
-	}
-
-	mutex_unlock(&s->max310x_mutex);
+			WARN_ON_ONCE(regmap_read(s->regmap,
+						 MAX310X_GLOBALIRQ_REG, &val));
+			val = ((1 << s->uart.nr) - 1) & ~val;
+			if (!val)
+				break;
+			max310x_port_irq(s, fls(val) - 1);
+		} while (1);
+	} else
+		max310x_port_irq(s, 0);
 
 	return IRQ_HANDLED;
 }
 
 static void max310x_wq_proc(struct work_struct *ws)
 {
-	struct max310x_port *s = container_of(ws, struct max310x_port, tx_work);
+	struct max310x_one *one = container_of(ws, struct max310x_one, tx_work);
+	struct max310x_port *s = dev_get_drvdata(one->port.dev);
 
-	mutex_lock(&s->max310x_mutex);
-	max310x_handle_tx(s);
-	mutex_unlock(&s->max310x_mutex);
+	mutex_lock(&s->mutex);
+	max310x_handle_tx(&one->port);
+	mutex_unlock(&s->mutex);
 }
 
 static void max310x_start_tx(struct uart_port *port)
 {
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
+	struct max310x_one *one = container_of(port, struct max310x_one, port);
 
-	queue_work(s->wq, &s->tx_work);
-}
-
-static void max310x_stop_tx(struct uart_port *port)
-{
-	/* Do nothing */
-}
-
-static void max310x_stop_rx(struct uart_port *port)
-{
-	/* Do nothing */
+	if (!work_pending(&one->tx_work))
+		schedule_work(&one->tx_work);
 }
 
 static unsigned int max310x_tx_empty(struct uart_port *port)
 {
-	unsigned int val = 0;
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
+	unsigned int lvl, sts;
 
-	mutex_lock(&s->max310x_mutex);
-	regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val);
-	mutex_unlock(&s->max310x_mutex);
+	lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
+	sts = max310x_port_read(port, MAX310X_IRQSTS_REG);
 
-	return val ? 0 : TIOCSER_TEMT;
-}
-
-static void max310x_enable_ms(struct uart_port *port)
-{
-	/* Modem status not supported */
+	return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0;
 }
 
 static unsigned int max310x_get_mctrl(struct uart_port *port)
@@ -644,28 +791,20 @@
 
 static void max310x_break_ctl(struct uart_port *port, int break_state)
 {
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
-
-	mutex_lock(&s->max310x_mutex);
-	regmap_update_bits(s->regmap, MAX310X_LCR_REG,
-			   MAX310X_LCR_TXBREAK_BIT,
-			   break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
-	mutex_unlock(&s->max310x_mutex);
+	max310x_port_update(port, MAX310X_LCR_REG,
+			    MAX310X_LCR_TXBREAK_BIT,
+			    break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
 }
 
 static void max310x_set_termios(struct uart_port *port,
 				struct ktermios *termios,
 				struct ktermios *old)
 {
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
 	unsigned int lcr, flow = 0;
 	int baud;
 
-	mutex_lock(&s->max310x_mutex);
-
 	/* Mask termios capabilities we don't support */
 	termios->c_cflag &= ~CMSPAR;
-	termios->c_iflag &= ~IXANY;
 
 	/* Word size */
 	switch (termios->c_cflag & CSIZE) {
@@ -696,7 +835,7 @@
 		lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
 
 	/* Update LCR register */
-	regmap_write(s->regmap, MAX310X_LCR_REG, lcr);
+	max310x_port_write(port, MAX310X_LCR_REG, lcr);
 
 	/* Set read status mask */
 	port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
@@ -717,8 +856,8 @@
 					    MAX310X_LSR_RXBRK_BIT;
 
 	/* Configure flow control */
-	regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]);
-	regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
+	max310x_port_write(port, MAX310X_XON1_REG, termios->c_cc[VSTART]);
+	max310x_port_write(port, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
 	if (termios->c_cflag & CRTSCTS)
 		flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT |
 			MAX310X_FLOWCTRL_AUTORTS_BIT;
@@ -728,7 +867,7 @@
 	if (termios->c_iflag & IXOFF)
 		flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT |
 			MAX310X_FLOWCTRL_SWFLOWEN_BIT;
-	regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow);
+	max310x_port_write(port, MAX310X_FLOWCTRL_REG, flow);
 
 	/* Get baud rate generator configuration */
 	baud = uart_get_baud_rate(port, termios, old,
@@ -736,36 +875,30 @@
 				  port->uartclk / 4);
 
 	/* Setup baudrate generator */
-	max310x_set_baud(s, baud);
+	max310x_set_baud(port, baud);
 
 	/* Update timeout according to new baud rate */
 	uart_update_timeout(port, termios->c_cflag, baud);
-
-	mutex_unlock(&s->max310x_mutex);
 }
 
 static int max310x_startup(struct uart_port *port)
 {
 	unsigned int val, line = port->line;
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
+	struct max310x_port *s = dev_get_drvdata(port->dev);
 
-	if (s->pdata->suspend)
-		s->pdata->suspend(0);
-
-	mutex_lock(&s->max310x_mutex);
+	s->devtype->power(port, 1);
 
 	/* Configure baud rate, 9600 as default */
-	max310x_set_baud(s, 9600);
+	max310x_set_baud(port, 9600);
 
 	/* Configure LCR register, 8N1 mode by default */
-	val = MAX310X_LCR_WORD_LEN_8;
-	regmap_write(s->regmap, MAX310X_LCR_REG, val);
+	max310x_port_write(port, MAX310X_LCR_REG, MAX310X_LCR_WORD_LEN_8);
 
 	/* Configure MODE1 register */
-	regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
-			   MAX310X_MODE1_TRNSCVCTRL_BIT,
-			   (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
-			   ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
+	max310x_port_update(port, MAX310X_MODE1_REG,
+			    MAX310X_MODE1_TRNSCVCTRL_BIT,
+			    (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
+			    ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
 
 	/* Configure MODE2 register */
 	val = MAX310X_MODE2_RXEMPTINV_BIT;
@@ -776,63 +909,40 @@
 
 	/* Reset FIFOs */
 	val |= MAX310X_MODE2_FIFORST_BIT;
-	regmap_write(s->regmap, MAX310X_MODE2_REG, val);
-
-	/* Configure FIFO trigger level register */
-	/* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */
-	val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64);
-	regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val);
+	max310x_port_write(port, MAX310X_MODE2_REG, val);
+	max310x_port_update(port, MAX310X_MODE2_REG,
+			    MAX310X_MODE2_FIFORST_BIT, 0);
 
 	/* Configure flow control levels */
 	/* Flow control halt level 96, resume level 48 */
-	val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96);
-	regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val);
+	max310x_port_write(port, MAX310X_FLOWLVL_REG,
+			   MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96));
 
-	/* Clear timeout register */
-	regmap_write(s->regmap, MAX310X_RXTO_REG, 0);
+	/* Clear IRQ status register */
+	max310x_port_read(port, MAX310X_IRQSTS_REG);
 
-	/* Configure LSR interrupt enable register */
-	/* Enable RX timeout interrupt */
-	val = MAX310X_LSR_RXTO_BIT;
-	regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val);
-
-	/* Clear FIFO reset */
-	regmap_update_bits(s->regmap, MAX310X_MODE2_REG,
-			   MAX310X_MODE2_FIFORST_BIT, 0);
-
-	/* Clear IRQ status register by reading it */
-	regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val);
-
-	/* Configure interrupt enable register */
-	/* Enable CTS change interrupt */
-	val = MAX310X_IRQ_CTS_BIT;
-	/* Enable RX, TX interrupts */
-	val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX;
-	regmap_write(s->regmap, MAX310X_IRQEN_REG, val);
-
-	mutex_unlock(&s->max310x_mutex);
+	/* Enable RX, TX, CTS change interrupts */
+	val = MAX310X_IRQ_RXEMPTY_BIT | MAX310X_IRQ_TXEMPTY_BIT;
+	max310x_port_write(port, MAX310X_IRQEN_REG, val | MAX310X_IRQ_CTS_BIT);
 
 	return 0;
 }
 
 static void max310x_shutdown(struct uart_port *port)
 {
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
+	struct max310x_port *s = dev_get_drvdata(port->dev);
 
 	/* Disable all interrupts */
-	mutex_lock(&s->max310x_mutex);
-	regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
-	mutex_unlock(&s->max310x_mutex);
+	max310x_port_write(port, MAX310X_IRQEN_REG, 0);
 
-	if (s->pdata->suspend)
-		s->pdata->suspend(1);
+	s->devtype->power(port, 0);
 }
 
 static const char *max310x_type(struct uart_port *port)
 {
-	struct max310x_port *s = container_of(port, struct max310x_port, port);
+	struct max310x_port *s = dev_get_drvdata(port->dev);
 
-	return (port->type == PORT_MAX310X) ? s->name : NULL;
+	return (port->type == PORT_MAX310X) ? s->devtype->name : NULL;
 }
 
 static int max310x_request_port(struct uart_port *port)
@@ -841,134 +951,99 @@
 	return 0;
 }
 
-static void max310x_release_port(struct uart_port *port)
-{
-	/* Do nothing */
-}
-
 static void max310x_config_port(struct uart_port *port, int flags)
 {
 	if (flags & UART_CONFIG_TYPE)
 		port->type = PORT_MAX310X;
 }
 
-static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int max310x_verify_port(struct uart_port *port, struct serial_struct *s)
 {
-	if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X))
-		return 0;
-	if (ser->irq == port->irq)
-		return 0;
+	if ((s->type != PORT_UNKNOWN) && (s->type != PORT_MAX310X))
+		return -EINVAL;
+	if (s->irq != port->irq)
+		return -EINVAL;
 
-	return -EINVAL;
+	return 0;
 }
 
-static struct uart_ops max310x_ops = {
+static void max310x_null_void(struct uart_port *port)
+{
+	/* Do nothing */
+}
+
+static const struct uart_ops max310x_ops = {
 	.tx_empty	= max310x_tx_empty,
 	.set_mctrl	= max310x_set_mctrl,
 	.get_mctrl	= max310x_get_mctrl,
-	.stop_tx	= max310x_stop_tx,
+	.stop_tx	= max310x_null_void,
 	.start_tx	= max310x_start_tx,
-	.stop_rx	= max310x_stop_rx,
-	.enable_ms	= max310x_enable_ms,
+	.stop_rx	= max310x_null_void,
+	.enable_ms	= max310x_null_void,
 	.break_ctl	= max310x_break_ctl,
 	.startup	= max310x_startup,
 	.shutdown	= max310x_shutdown,
 	.set_termios	= max310x_set_termios,
 	.type		= max310x_type,
 	.request_port	= max310x_request_port,
-	.release_port	= max310x_release_port,
+	.release_port	= max310x_null_void,
 	.config_port	= max310x_config_port,
 	.verify_port	= max310x_verify_port,
 };
 
-#ifdef CONFIG_PM_SLEEP
-
-static int max310x_suspend(struct device *dev)
-{
-	int ret;
-	struct max310x_port *s = dev_get_drvdata(dev);
-
-	dev_dbg(dev, "Suspend\n");
-
-	ret = uart_suspend_port(&s->uart, &s->port);
-
-	mutex_lock(&s->max310x_mutex);
-
-	/* Enable sleep mode */
-	regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
-			   MAX310X_MODE1_FORCESLEEP_BIT,
-			   MAX310X_MODE1_FORCESLEEP_BIT);
-
-	mutex_unlock(&s->max310x_mutex);
-
-	if (s->pdata->suspend)
-		s->pdata->suspend(1);
-
-	return ret;
-}
-
-static int max310x_resume(struct device *dev)
+static int __maybe_unused max310x_suspend(struct device *dev)
 {
 	struct max310x_port *s = dev_get_drvdata(dev);
+	int i;
 
-	dev_dbg(dev, "Resume\n");
+	for (i = 0; i < s->uart.nr; i++) {
+		uart_suspend_port(&s->uart, &s->p[i].port);
+		s->devtype->power(&s->p[i].port, 0);
+	}
 
-	if (s->pdata->suspend)
-		s->pdata->suspend(0);
-
-	mutex_lock(&s->max310x_mutex);
-
-	/* Disable sleep mode */
-	regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
-			   MAX310X_MODE1_FORCESLEEP_BIT,
-			   0);
-
-	max310x_wait_pll(s);
-
-	mutex_unlock(&s->max310x_mutex);
-
-	return uart_resume_port(&s->uart, &s->port);
+	return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
-#define MAX310X_PM_OPS (&max310x_pm_ops)
+static int __maybe_unused max310x_resume(struct device *dev)
+{
+	struct max310x_port *s = dev_get_drvdata(dev);
+	int i;
 
-#else
-#define MAX310X_PM_OPS NULL
-#endif
+	for (i = 0; i < s->uart.nr; i++) {
+		s->devtype->power(&s->p[i].port, 1);
+		uart_resume_port(&s->uart, &s->p[i].port);
+	}
+
+	return 0;
+}
 
 #ifdef CONFIG_GPIOLIB
 static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	unsigned int val = 0;
+	unsigned int val;
 	struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+	struct uart_port *port = &s->p[offset / 4].port;
 
-	mutex_lock(&s->max310x_mutex);
-	regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val);
-	mutex_unlock(&s->max310x_mutex);
+	val = max310x_port_read(port, MAX310X_GPIODATA_REG);
 
-	return !!((val >> 4) & (1 << offset));
+	return !!((val >> 4) & (1 << (offset % 4)));
 }
 
 static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+	struct uart_port *port = &s->p[offset / 4].port;
 
-	mutex_lock(&s->max310x_mutex);
-	regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
-							    1 << offset : 0);
-	mutex_unlock(&s->max310x_mutex);
+	max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
+			    value ? 1 << (offset % 4) : 0);
 }
 
 static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
 	struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+	struct uart_port *port = &s->p[offset / 4].port;
 
-	mutex_lock(&s->max310x_mutex);
-
-	regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0);
-
-	mutex_unlock(&s->max310x_mutex);
+	max310x_port_update(port, MAX310X_GPIOCFG_REG, 1 << (offset % 4), 0);
 
 	return 0;
 }
@@ -977,74 +1052,42 @@
 					 unsigned offset, int value)
 {
 	struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+	struct uart_port *port = &s->p[offset / 4].port;
 
-	mutex_lock(&s->max310x_mutex);
-
-	regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset,
-							   1 << offset);
-	regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
-							    1 << offset : 0);
-
-	mutex_unlock(&s->max310x_mutex);
+	max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
+			    value ? 1 << (offset % 4) : 0);
+	max310x_port_update(port, MAX310X_GPIOCFG_REG, 1 << (offset % 4),
+			    1 << (offset % 4));
 
 	return 0;
 }
 #endif
 
-/* Generic platform data */
-static struct max310x_pdata generic_plat_data = {
-	.driver_flags	= MAX310X_EXT_CLK,
-	.uart_flags[0]	= MAX310X_ECHO_SUPRESS,
-	.frequency	= 26000000,
-};
-
-static int max310x_probe(struct spi_device *spi)
+static int max310x_probe(struct device *dev, int is_spi,
+			 struct max310x_devtype *devtype, int irq)
 {
 	struct max310x_port *s;
-	struct device *dev = &spi->dev;
-	int chiptype = spi_get_device_id(spi)->driver_data;
-	struct max310x_pdata *pdata = dev->platform_data;
-	unsigned int val = 0;
-	int ret;
+	struct max310x_pdata *pdata = dev_get_platdata(dev);
+	int i, ret, uartclk;
 
 	/* Check for IRQ */
-	if (spi->irq <= 0) {
+	if (irq <= 0) {
 		dev_err(dev, "No IRQ specified\n");
 		return -ENOTSUPP;
 	}
 
+	if (!pdata) {
+		dev_err(dev, "No platform data supplied\n");
+		return -EINVAL;
+	}
+
 	/* Alloc port structure */
-	s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL);
+	s = devm_kzalloc(dev, sizeof(*s) +
+			 sizeof(struct max310x_one) * devtype->nr, GFP_KERNEL);
 	if (!s) {
 		dev_err(dev, "Error allocating port structure\n");
 		return -ENOMEM;
 	}
-	dev_set_drvdata(dev, s);
-
-	if (!pdata) {
-		dev_warn(dev, "No platform data supplied, using defaults\n");
-		pdata = &generic_plat_data;
-	}
-	s->pdata = pdata;
-
-	/* Individual chip settings */
-	switch (chiptype) {
-	case MAX310X_TYPE_MAX3107:
-		s->name = "MAX3107";
-		s->nr_gpio = 4;
-		s->uart.nr = 1;
-		s->regcfg.max_register = 0x1f;
-		break;
-	case MAX310X_TYPE_MAX3108:
-		s->name = "MAX3108";
-		s->nr_gpio = 4;
-		s->uart.nr = 1;
-		s->regcfg.max_register = 0x1e;
-		break;
-	default:
-		dev_err(dev, "Unsupported chip type %i\n", chiptype);
-		return -ENOTSUPP;
-	}
 
 	/* Check input frequency */
 	if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
@@ -1055,13 +1098,11 @@
 	   ((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
 		goto err_freq;
 
-	mutex_init(&s->max310x_mutex);
+	s->pdata = pdata;
+	s->devtype = devtype;
+	dev_set_drvdata(dev, s);
 
-	/* Setup SPI bus */
-	spi->mode		= SPI_MODE_0;
-	spi->bits_per_word	= 8;
-	spi->max_speed_hz	= 26000000;
-	spi_setup(spi);
+	mutex_init(&s->mutex);
 
 	/* Setup regmap */
 	s->regcfg.reg_bits		= 8;
@@ -1069,109 +1110,100 @@
 	s->regcfg.read_flag_mask	= 0x00;
 	s->regcfg.write_flag_mask	= 0x80;
 	s->regcfg.cache_type		= REGCACHE_RBTREE;
-	s->regcfg.writeable_reg		= max3107_8_reg_writeable;
+	s->regcfg.writeable_reg		= max310x_reg_writeable;
 	s->regcfg.volatile_reg		= max310x_reg_volatile;
 	s->regcfg.precious_reg		= max310x_reg_precious;
-	s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+	s->regcfg.max_register		= devtype->nr * 0x20 - 1;
+
+	if (IS_ENABLED(CONFIG_SPI_MASTER) && is_spi) {
+		struct spi_device *spi = to_spi_device(dev);
+
+		s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+	} else
+		return -ENOTSUPP;
+
 	if (IS_ERR(s->regmap)) {
-		ret = PTR_ERR(s->regmap);
 		dev_err(dev, "Failed to initialize register map\n");
-		goto err_out;
-	}
-
-	/* Reset chip & check SPI function */
-	ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT);
-	if (ret) {
-		dev_err(dev, "SPI transfer failed\n");
-		goto err_out;
-	}
-	/* Clear chip reset */
-	regmap_write(s->regmap, MAX310X_MODE2_REG, 0);
-
-	switch (chiptype) {
-	case MAX310X_TYPE_MAX3107:
-		/* Check REV ID to ensure we are talking to what we expect */
-		regmap_read(s->regmap, MAX3107_REVID_REG, &val);
-		if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) {
-			dev_err(dev, "%s ID 0x%02x does not match\n",
-				s->name, val);
-			ret = -ENODEV;
-			goto err_out;
-		}
-		break;
-	case MAX310X_TYPE_MAX3108:
-		/* MAX3108 have not REV ID register, we just check default value
-		 * from clocksource register to make sure everything works.
-		 */
-		regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
-		if (val != (MAX310X_CLKSRC_EXTCLK_BIT |
-			    MAX310X_CLKSRC_PLLBYP_BIT)) {
-			dev_err(dev, "%s not present\n", s->name);
-			ret = -ENODEV;
-			goto err_out;
-		}
-		break;
+		return PTR_ERR(s->regmap);
 	}
 
 	/* Board specific configure */
-	if (pdata->init)
-		pdata->init();
-	if (pdata->suspend)
-		pdata->suspend(0);
+	if (s->pdata->init)
+		s->pdata->init();
 
-	/* Calculate referecne clock */
-	s->uartclk = max310x_set_ref_clk(s);
+	/* Check device to ensure we are talking to what we expect */
+	ret = devtype->detect(dev);
+	if (ret)
+		return ret;
 
-	/* Disable all interrupts */
-	regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+	for (i = 0; i < devtype->nr; i++) {
+		unsigned int offs = i << 5;
 
-	/* Setup MODE1 register */
-	val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */
-	if (pdata->driver_flags & MAX310X_AUTOSLEEP)
-		val = MAX310X_MODE1_AUTOSLEEP_BIT;
-	regmap_write(s->regmap, MAX310X_MODE1_REG, val);
+		/* Reset port */
+		regmap_write(s->regmap, MAX310X_MODE2_REG + offs,
+			     MAX310X_MODE2_RST_BIT);
+		/* Clear port reset */
+		regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0);
 
-	/* Setup interrupt */
-	ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist,
-					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-					dev_name(dev), s);
-	if (ret) {
-		dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq);
-		goto err_out;
+		/* Wait for port startup */
+		do {
+			regmap_read(s->regmap,
+				    MAX310X_BRGDIVLSB_REG + offs, &ret);
+		} while (ret != 0x01);
+
+		regmap_update_bits(s->regmap, MAX310X_MODE1_REG + offs,
+				   MAX310X_MODE1_AUTOSLEEP_BIT,
+				   MAX310X_MODE1_AUTOSLEEP_BIT);
 	}
 
+	uartclk = max310x_set_ref_clk(s);
+	dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
+
 	/* Register UART driver */
 	s->uart.owner		= THIS_MODULE;
-	s->uart.driver_name	= dev_name(dev);
 	s->uart.dev_name	= "ttyMAX";
 	s->uart.major		= MAX310X_MAJOR;
 	s->uart.minor		= MAX310X_MINOR;
+	s->uart.nr		= devtype->nr;
 	ret = uart_register_driver(&s->uart);
 	if (ret) {
 		dev_err(dev, "Registering UART driver failed\n");
-		goto err_out;
+		return ret;
 	}
 
-	/* Initialize workqueue for start TX */
-	s->wq = create_freezable_workqueue(dev_name(dev));
-	INIT_WORK(&s->tx_work, max310x_wq_proc);
-
-	/* Initialize UART port data */
-	s->port.line		= 0;
-	s->port.dev		= dev;
-	s->port.irq		= spi->irq;
-	s->port.type		= PORT_MAX310X;
-	s->port.fifosize	= MAX310X_FIFO_SIZE;
-	s->port.flags		= UPF_SKIP_TEST | UPF_FIXED_TYPE;
-	s->port.iotype		= UPIO_PORT;
-	s->port.membase		= (void __iomem *)0xffffffff; /* Bogus value */
-	s->port.uartclk		= s->uartclk;
-	s->port.ops		= &max310x_ops;
-	uart_add_one_port(&s->uart, &s->port);
+	for (i = 0; i < devtype->nr; i++) {
+		/* Initialize port data */
+		s->p[i].port.line	= i;
+		s->p[i].port.dev	= dev;
+		s->p[i].port.irq	= irq;
+		s->p[i].port.type	= PORT_MAX310X;
+		s->p[i].port.fifosize	= MAX310X_FIFO_SIZE;
+		s->p[i].port.flags	= UPF_SKIP_TEST | UPF_FIXED_TYPE |
+					  UPF_LOW_LATENCY;
+		s->p[i].port.iotype	= UPIO_PORT;
+		s->p[i].port.iobase	= i * 0x20;
+		s->p[i].port.membase	= (void __iomem *)~0;
+		s->p[i].port.uartclk	= uartclk;
+		s->p[i].port.ops	= &max310x_ops;
+		/* Disable all interrupts */
+		max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0);
+		/* Clear IRQ status register */
+		max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG);
+		/* Enable IRQ pin */
+		max310x_port_update(&s->p[i].port, MAX310X_MODE1_REG,
+				    MAX310X_MODE1_IRQSEL_BIT,
+				    MAX310X_MODE1_IRQSEL_BIT);
+		/* Initialize queue for start TX */
+		INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
+		/* Register port */
+		uart_add_one_port(&s->uart, &s->p[i].port);
+		/* Go to suspend mode */
+		devtype->power(&s->p[i].port, 0);
+	}
 
 #ifdef CONFIG_GPIOLIB
 	/* Setup GPIO cotroller */
-	if (pdata->gpio_base) {
+	if (s->pdata->gpio_base) {
 		s->gpio.owner		= THIS_MODULE;
 		s->gpio.dev		= dev;
 		s->gpio.label		= dev_name(dev);
@@ -1179,86 +1211,107 @@
 		s->gpio.get		= max310x_gpio_get;
 		s->gpio.direction_output= max310x_gpio_direction_output;
 		s->gpio.set		= max310x_gpio_set;
-		s->gpio.base		= pdata->gpio_base;
-		s->gpio.ngpio		= s->nr_gpio;
+		s->gpio.base		= s->pdata->gpio_base;
+		s->gpio.ngpio		= devtype->nr * 4;
 		s->gpio.can_sleep	= 1;
-		if (gpiochip_add(&s->gpio)) {
-			/* Indicate that we should not call gpiochip_remove */
-			s->gpio.base = 0;
-		}
+		if (!gpiochip_add(&s->gpio))
+			s->gpio_used = 1;
 	} else
 		dev_info(dev, "GPIO support not enabled\n");
 #endif
 
-	/* Go to suspend mode */
-	if (pdata->suspend)
-		pdata->suspend(1);
+	/* Setup interrupt */
+	ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
+					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					dev_name(dev), s);
+	if (ret) {
+		dev_err(dev, "Unable to reguest IRQ %i\n", irq);
+#ifdef CONFIG_GPIOLIB
+		if (s->gpio_used)
+			WARN_ON(gpiochip_remove(&s->gpio));
+#endif
+	}
 
-	return 0;
+	return ret;
 
 err_freq:
 	dev_err(dev, "Frequency parameter incorrect\n");
-	ret = -EINVAL;
-
-err_out:
-	dev_set_drvdata(dev, NULL);
-
-	return ret;
+	return -EINVAL;
 }
 
-static int max310x_remove(struct spi_device *spi)
+static int max310x_remove(struct device *dev)
 {
-	struct device *dev = &spi->dev;
 	struct max310x_port *s = dev_get_drvdata(dev);
-	int ret = 0;
+	int i, ret = 0;
 
-	dev_dbg(dev, "Removing port\n");
-
-	devm_free_irq(dev, s->port.irq, s);
-
-	destroy_workqueue(s->wq);
-
-	uart_remove_one_port(&s->uart, &s->port);
+	for (i = 0; i < s->uart.nr; i++) {
+		cancel_work_sync(&s->p[i].tx_work);
+		uart_remove_one_port(&s->uart, &s->p[i].port);
+		s->devtype->power(&s->p[i].port, 0);
+	}
 
 	uart_unregister_driver(&s->uart);
 
 #ifdef CONFIG_GPIOLIB
-	if (s->pdata->gpio_base) {
+	if (s->gpio_used)
 		ret = gpiochip_remove(&s->gpio);
-		if (ret)
-			dev_err(dev, "Failed to remove gpio chip: %d\n", ret);
-	}
 #endif
 
-	dev_set_drvdata(dev, NULL);
-
-	if (s->pdata->suspend)
-		s->pdata->suspend(1);
 	if (s->pdata->exit)
 		s->pdata->exit();
 
 	return ret;
 }
 
+#ifdef CONFIG_SPI_MASTER
+static int max310x_spi_probe(struct spi_device *spi)
+{
+	struct max310x_devtype *devtype =
+		(struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
+	int ret;
+
+	/* Setup SPI bus */
+	spi->bits_per_word	= 8;
+	spi->mode		= spi->mode ? : SPI_MODE_0;
+	spi->max_speed_hz	= spi->max_speed_hz ? : 26000000;
+	ret = spi_setup(spi);
+	if (ret) {
+		dev_err(&spi->dev, "SPI setup failed\n");
+		return ret;
+	}
+
+	return max310x_probe(&spi->dev, 1, devtype, spi->irq);
+}
+
+static int max310x_spi_remove(struct spi_device *spi)
+{
+	return max310x_remove(&spi->dev);
+}
+
+static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
+
 static const struct spi_device_id max310x_id_table[] = {
-	{ "max3107",	MAX310X_TYPE_MAX3107 },
-	{ "max3108",	MAX310X_TYPE_MAX3108 },
+	{ "max3107",	(kernel_ulong_t)&max3107_devtype, },
+	{ "max3108",	(kernel_ulong_t)&max3108_devtype, },
+	{ "max3109",	(kernel_ulong_t)&max3109_devtype, },
+	{ "max14830",	(kernel_ulong_t)&max14830_devtype, },
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, max310x_id_table);
 
-static struct spi_driver max310x_driver = {
+static struct spi_driver max310x_uart_driver = {
 	.driver = {
-		.name	= "max310x",
+		.name	= MAX310X_NAME,
 		.owner	= THIS_MODULE,
-		.pm	= MAX310X_PM_OPS,
+		.pm	= &max310x_pm_ops,
 	},
-	.probe		= max310x_probe,
-	.remove		= max310x_remove,
+	.probe		= max310x_spi_probe,
+	.remove		= max310x_spi_remove,
 	.id_table	= max310x_id_table,
 };
-module_spi_driver(max310x_driver);
+module_spi_driver(max310x_uart_driver);
+#endif
 
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
 MODULE_DESCRIPTION("MAX310X serial driver");
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 65be0c0..0edfaf8 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -24,6 +24,7 @@
 #include <linux/serial_core.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
+#include <linux/platform_device.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
@@ -324,7 +325,9 @@
 		uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
 }
 
 /****************************************************************************/
@@ -644,7 +647,7 @@
 
 static int mcf_probe(struct platform_device *pdev)
 {
-	struct mcf_platform_uart *platp = pdev->dev.platform_data;
+	struct mcf_platform_uart *platp = dev_get_platdata(&pdev->dev);
 	struct uart_port *port;
 	int i;
 
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c
index 4a82267..d3db042 100644
--- a/drivers/tty/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
@@ -386,7 +386,7 @@
 
 /* This is always called in spinlock protected mode, so
  * modify timeout timer is safe here */
-void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
+void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, unsigned long *flags)
 {
 	struct hsu_dma_buffer *dbuf = &up->rxbuf;
 	struct hsu_dma_chan *chan = up->rxc;
@@ -438,7 +438,9 @@
 					 | (0x1 << 16)
 					 | (0x1 << 24)	/* timeout bit, see HSU Errata 1 */
 					 );
+	spin_unlock_irqrestore(&up->port.lock, *flags);
 	tty_flip_buffer_push(tport);
+	spin_lock_irqsave(&up->port.lock, *flags);
 
 	chan_writel(chan, HSU_CH_CR, 0x3);
 
@@ -459,7 +461,8 @@
 	}
 }
 
-static inline void receive_chars(struct uart_hsu_port *up, int *status)
+static inline void receive_chars(struct uart_hsu_port *up, int *status,
+		unsigned long *flags)
 {
 	unsigned int ch, flag;
 	unsigned int max_count = 256;
@@ -519,7 +522,10 @@
 	ignore_char:
 		*status = serial_in(up, UART_LSR);
 	} while ((*status & UART_LSR_DR) && max_count--);
+
+	spin_unlock_irqrestore(&up->port.lock, *flags);
 	tty_flip_buffer_push(&up->port.state->port);
+	spin_lock_irqsave(&up->port.lock, *flags);
 }
 
 static void transmit_chars(struct uart_hsu_port *up)
@@ -613,7 +619,7 @@
 
 	lsr = serial_in(up, UART_LSR);
 	if (lsr & UART_LSR_DR)
-		receive_chars(up, &lsr);
+		receive_chars(up, &lsr, &flags);
 	check_modem_status(up);
 
 	/* lsr will be renewed during the receive_chars */
@@ -643,7 +649,7 @@
 
 	/* Rx channel */
 	if (chan->dirt == DMA_FROM_DEVICE)
-		hsu_dma_rx(up, int_sts);
+		hsu_dma_rx(up, int_sts, &flags);
 
 	/* Tx channel */
 	if (chan->dirt == DMA_TO_DEVICE) {
diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index bc24f49..8d70267 100644
--- a/drivers/tty/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
@@ -934,7 +934,7 @@
  ******************************************************************************
  */
 
-static int mpsc_rx_intr(struct mpsc_port_info *pi)
+static int mpsc_rx_intr(struct mpsc_port_info *pi, unsigned long *flags)
 {
 	struct mpsc_rx_desc *rxre;
 	struct tty_port *port = &pi->port.state->port;
@@ -969,8 +969,11 @@
 #endif
 		/* Following use of tty struct directly is deprecated */
 		if (tty_buffer_request_room(port, bytes_in) < bytes_in) {
-			if (port->low_latency)
+			if (port->low_latency) {
+				spin_unlock_irqrestore(&pi->port.lock, *flags);
 				tty_flip_buffer_push(port);
+				spin_lock_irqsave(&pi->port.lock, *flags);
+			}
 			/*
 			 * If this failed then we will throw away the bytes
 			 * but must do so to clear interrupts.
@@ -1080,7 +1083,9 @@
 	if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
 		mpsc_start_rx(pi);
 
+	spin_unlock_irqrestore(&pi->port.lock, *flags);
 	tty_flip_buffer_push(port);
+	spin_lock_irqsave(&pi->port.lock, *flags);
 	return rc;
 }
 
@@ -1222,7 +1227,7 @@
 
 	spin_lock_irqsave(&pi->port.lock, iflags);
 	mpsc_sdma_intr_ack(pi);
-	if (mpsc_rx_intr(pi))
+	if (mpsc_rx_intr(pi, &iflags))
 		rc = IRQ_HANDLED;
 	if (mpsc_tx_intr(pi))
 		rc = IRQ_HANDLED;
@@ -1884,7 +1889,7 @@
 	if (dev->id == 0) {
 		if (!(rc = mpsc_shared_map_regs(dev))) {
 			pdata = (struct mpsc_shared_pdata *)
-				dev->dev.platform_data;
+				dev_get_platdata(&dev->dev);
 
 			mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
 			mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
@@ -2025,7 +2030,7 @@
 {
 	struct mpsc_pdata	*pdata;
 
-	pdata = (struct mpsc_pdata *)pd->dev.platform_data;
+	pdata = (struct mpsc_pdata *)dev_get_platdata(&pd->dev);
 
 	pi->port.uartclk = pdata->brg_clk_freq;
 	pi->port.iotype = UPIO_MEM;
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index 9b6ef20..a67e708 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -713,7 +713,7 @@
 {
 }
 
-struct uart_ops serial_m3110_ops = {
+static struct uart_ops serial_m3110_ops = {
 	.tx_empty	= serial_m3110_tx_empty,
 	.set_mctrl	= serial_m3110_set_mctrl,
 	.get_mctrl	= serial_m3110_get_mctrl,
@@ -844,7 +844,7 @@
 	pmax = max;
 
 	/* Give membase a psudo value to pass serial_core's check */
-	max->port.membase = (void *)0xff110000;
+	max->port.membase = (unsigned char __iomem *)0xff110000;
 	uart_add_one_port(&serial_m3110_reg, &max->port);
 
 	return 0;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 2c6cfb3..b5d779c 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -45,16 +45,19 @@
 	struct clk		*clk;
 	struct clk		*pclk;
 	unsigned int		imr;
-	unsigned int            *gsbi_base;
+	void __iomem		*gsbi_base;
 	int			is_uartdm;
 	unsigned int		old_snap_state;
 };
 
-static inline void wait_for_xmitr(struct uart_port *port, int bits)
+static inline void wait_for_xmitr(struct uart_port *port)
 {
-	if (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY))
-		while ((msm_read(port, UART_ISR) & bits) != bits)
-			cpu_relax();
+	while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
+		if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
+			break;
+		udelay(1);
+	}
+	msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
 }
 
 static void msm_stop_tx(struct uart_port *port)
@@ -137,7 +140,10 @@
 		count -= 4;
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+
 	if (misr & (UART_IMR_RXSTALE))
 		msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
 	msm_write(port, 0xFFFFFF, UARTDM_DMRX);
@@ -189,52 +195,69 @@
 			tty_insert_flip_char(tport, c, flag);
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
 }
 
-static void reset_dm_count(struct uart_port *port)
+static void reset_dm_count(struct uart_port *port, int count)
 {
-	wait_for_xmitr(port, UART_ISR_TX_READY);
-	msm_write(port, 1, UARTDM_NCF_TX);
+	wait_for_xmitr(port);
+	msm_write(port, count, UARTDM_NCF_TX);
+	msm_read(port, UARTDM_NCF_TX);
 }
 
 static void handle_tx(struct uart_port *port)
 {
 	struct circ_buf *xmit = &port->state->xmit;
 	struct msm_port *msm_port = UART_TO_MSM(port);
-	int sent_tx;
+	unsigned int tx_count, num_chars;
+	unsigned int tf_pointer = 0;
+
+	tx_count = uart_circ_chars_pending(xmit);
+	tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
+			port->fifosize);
 
 	if (port->x_char) {
 		if (msm_port->is_uartdm)
-			reset_dm_count(port);
+			reset_dm_count(port, tx_count + 1);
 
 		msm_write(port, port->x_char,
 			  msm_port->is_uartdm ? UARTDM_TF : UART_TF);
 		port->icount.tx++;
 		port->x_char = 0;
+	} else if (tx_count && msm_port->is_uartdm) {
+		reset_dm_count(port, tx_count);
 	}
 
-	if (msm_port->is_uartdm)
-		reset_dm_count(port);
+	while (tf_pointer < tx_count) {
+		int i;
+		char buf[4] = { 0 };
+		unsigned int *bf = (unsigned int *)&buf;
 
-	while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
-		if (uart_circ_empty(xmit)) {
-			/* disable tx interrupts */
-			msm_port->imr &= ~UART_IMR_TXLEV;
-			msm_write(port, msm_port->imr, UART_IMR);
+		if (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
 			break;
-		}
-		msm_write(port, xmit->buf[xmit->tail],
-			  msm_port->is_uartdm ? UARTDM_TF : UART_TF);
 
 		if (msm_port->is_uartdm)
-			reset_dm_count(port);
+			num_chars = min(tx_count - tf_pointer,
+					(unsigned int)sizeof(buf));
+		else
+			num_chars = 1;
 
-		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-		port->icount.tx++;
-		sent_tx = 1;
+		for (i = 0; i < num_chars; i++) {
+			buf[i] = xmit->buf[xmit->tail + i];
+			port->icount.tx++;
+		}
+
+		msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+		xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1);
+		tf_pointer += num_chars;
 	}
 
+	/* disable tx interrupts if nothing more to send */
+	if (uart_circ_empty(xmit))
+		msm_stop_tx(port);
+
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(port);
 }
@@ -295,7 +318,7 @@
 	msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
 }
 
-void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	unsigned int mr;
 	mr = msm_read(port, UART_MR1);
@@ -318,70 +341,60 @@
 		msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
 }
 
+struct msm_baud_map {
+	u16	divisor;
+	u8	code;
+	u8	rxstale;
+};
+
+static const struct msm_baud_map *
+msm_find_best_baud(struct uart_port *port, unsigned int baud)
+{
+	unsigned int i, divisor;
+	const struct msm_baud_map *entry;
+	static const struct msm_baud_map table[] = {
+		{ 1536, 0x00,  1 },
+		{  768, 0x11,  1 },
+		{  384, 0x22,  1 },
+		{  192, 0x33,  1 },
+		{   96, 0x44,  1 },
+		{   48, 0x55,  1 },
+		{   32, 0x66,  1 },
+		{   24, 0x77,  1 },
+		{   16, 0x88,  1 },
+		{   12, 0x99,  6 },
+		{    8, 0xaa,  6 },
+		{    6, 0xbb,  6 },
+		{    4, 0xcc,  6 },
+		{    3, 0xdd,  8 },
+		{    2, 0xee, 16 },
+		{    1, 0xff, 31 },
+	};
+
+	divisor = uart_get_divisor(port, baud);
+
+	for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
+		if (entry->divisor <= divisor)
+			break;
+
+	return entry; /* Default to smallest divider */
+}
+
 static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
 {
-	unsigned int baud_code, rxstale, watermark;
+	unsigned int rxstale, watermark;
 	struct msm_port *msm_port = UART_TO_MSM(port);
+	const struct msm_baud_map *entry;
 
-	switch (baud) {
-	case 300:
-		baud_code = UART_CSR_300;
-		rxstale = 1;
-		break;
-	case 600:
-		baud_code = UART_CSR_600;
-		rxstale = 1;
-		break;
-	case 1200:
-		baud_code = UART_CSR_1200;
-		rxstale = 1;
-		break;
-	case 2400:
-		baud_code = UART_CSR_2400;
-		rxstale = 1;
-		break;
-	case 4800:
-		baud_code = UART_CSR_4800;
-		rxstale = 1;
-		break;
-	case 9600:
-		baud_code = UART_CSR_9600;
-		rxstale = 2;
-		break;
-	case 14400:
-		baud_code = UART_CSR_14400;
-		rxstale = 3;
-		break;
-	case 19200:
-		baud_code = UART_CSR_19200;
-		rxstale = 4;
-		break;
-	case 28800:
-		baud_code = UART_CSR_28800;
-		rxstale = 6;
-		break;
-	case 38400:
-		baud_code = UART_CSR_38400;
-		rxstale = 8;
-		break;
-	case 57600:
-		baud_code = UART_CSR_57600;
-		rxstale = 16;
-		break;
-	case 115200:
-	default:
-		baud_code = UART_CSR_115200;
-		baud = 115200;
-		rxstale = 31;
-		break;
-	}
+	entry = msm_find_best_baud(port, baud);
 
 	if (msm_port->is_uartdm)
 		msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
 
-	msm_write(port, baud_code, UART_CSR);
+	msm_write(port, entry->code, UART_CSR);
 
 	/* RX stale watermark */
+	rxstale = entry->rxstale;
 	watermark = UART_IPR_STALE_LSB & rxstale;
 	watermark |= UART_IPR_RXSTALE_LAST;
 	watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
@@ -409,8 +422,7 @@
 	struct msm_port *msm_port = UART_TO_MSM(port);
 
 	clk_prepare_enable(msm_port->clk);
-	if (!IS_ERR(msm_port->pclk))
-		clk_prepare_enable(msm_port->pclk);
+	clk_prepare_enable(msm_port->pclk);
 	msm_serial_set_mnd_regs(port);
 }
 
@@ -589,12 +601,10 @@
 	port->membase = NULL;
 
 	if (msm_port->gsbi_base) {
-		iowrite32(GSBI_PROTOCOL_IDLE, msm_port->gsbi_base +
-			  GSBI_CONTROL);
+		writel_relaxed(GSBI_PROTOCOL_IDLE,
+				msm_port->gsbi_base + GSBI_CONTROL);
 
-		gsbi_resource = platform_get_resource(pdev,
-							IORESOURCE_MEM, 1);
-
+		gsbi_resource = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 		if (unlikely(!gsbi_resource))
 			return;
 
@@ -637,7 +647,7 @@
 		if (!request_mem_region(gsbi_resource->start, size,
 						 "msm_serial")) {
 			ret = -EBUSY;
-			goto fail_release_port;
+			goto fail_release_port_membase;
 		}
 
 		msm_port->gsbi_base = ioremap(gsbi_resource->start, size);
@@ -651,6 +661,8 @@
 
 fail_release_gsbi:
 	release_mem_region(gsbi_resource->start, size);
+fail_release_port_membase:
+	iounmap(port->membase);
 fail_release_port:
 	release_mem_region(port->mapbase, size);
 	return ret;
@@ -666,10 +678,9 @@
 		if (ret)
 			return;
 	}
-
-	if (msm_port->is_uartdm)
-		iowrite32(GSBI_PROTOCOL_UART, msm_port->gsbi_base +
-			  GSBI_CONTROL);
+	if (msm_port->gsbi_base)
+		writel_relaxed(GSBI_PROTOCOL_UART,
+				msm_port->gsbi_base + GSBI_CONTROL);
 }
 
 static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
@@ -689,13 +700,11 @@
 	switch (state) {
 	case 0:
 		clk_prepare_enable(msm_port->clk);
-		if (!IS_ERR(msm_port->pclk))
-			clk_prepare_enable(msm_port->pclk);
+		clk_prepare_enable(msm_port->pclk);
 		break;
 	case 3:
 		clk_disable_unprepare(msm_port->clk);
-		if (!IS_ERR(msm_port->pclk))
-			clk_disable_unprepare(msm_port->pclk);
+		clk_disable_unprepare(msm_port->pclk);
 		break;
 	default:
 		printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
@@ -760,32 +769,63 @@
 }
 
 #ifdef CONFIG_SERIAL_MSM_CONSOLE
-
-static void msm_console_putchar(struct uart_port *port, int c)
-{
-	struct msm_port *msm_port = UART_TO_MSM(port);
-
-	if (msm_port->is_uartdm)
-		reset_dm_count(port);
-
-	while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
-		;
-	msm_write(port, c, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
-}
-
 static void msm_console_write(struct console *co, const char *s,
 			      unsigned int count)
 {
+	int i;
 	struct uart_port *port;
 	struct msm_port *msm_port;
+	int num_newlines = 0;
+	bool replaced = false;
 
 	BUG_ON(co->index < 0 || co->index >= UART_NR);
 
 	port = get_port_from_line(co->index);
 	msm_port = UART_TO_MSM(port);
 
+	/* Account for newlines that will get a carriage return added */
+	for (i = 0; i < count; i++)
+		if (s[i] == '\n')
+			num_newlines++;
+	count += num_newlines;
+
 	spin_lock(&port->lock);
-	uart_console_write(port, s, count, msm_console_putchar);
+	if (msm_port->is_uartdm)
+		reset_dm_count(port, count);
+
+	i = 0;
+	while (i < count) {
+		int j;
+		unsigned int num_chars;
+		char buf[4] = { 0 };
+		unsigned int *bf = (unsigned int *)&buf;
+
+		if (msm_port->is_uartdm)
+			num_chars = min(count - i, (unsigned int)sizeof(buf));
+		else
+			num_chars = 1;
+
+		for (j = 0; j < num_chars; j++) {
+			char c = *s;
+
+			if (c == '\n' && !replaced) {
+				buf[j] = '\r';
+				j++;
+				replaced = true;
+			}
+			if (j < num_chars) {
+				buf[j] = c;
+				s++;
+				replaced = false;
+			}
+		}
+
+		while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+			cpu_relax();
+
+		msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF);
+		i += num_chars;
+	}
 	spin_unlock(&port->lock);
 }
 
@@ -859,6 +899,11 @@
 
 static atomic_t msm_uart_next_id = ATOMIC_INIT(0);
 
+static const struct of_device_id msm_uartdm_table[] = {
+	{ .compatible = "qcom,msm-uartdm" },
+	{ }
+};
+
 static int __init msm_serial_probe(struct platform_device *pdev)
 {
 	struct msm_port *msm_port;
@@ -878,23 +923,17 @@
 	port->dev = &pdev->dev;
 	msm_port = UART_TO_MSM(port);
 
-	if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
+	if (of_match_device(msm_uartdm_table, &pdev->dev))
 		msm_port->is_uartdm = 1;
 	else
 		msm_port->is_uartdm = 0;
 
-	if (msm_port->is_uartdm) {
-		msm_port->clk = devm_clk_get(&pdev->dev, "gsbi_uart_clk");
-		msm_port->pclk = devm_clk_get(&pdev->dev, "gsbi_pclk");
-	} else {
-		msm_port->clk = devm_clk_get(&pdev->dev, "uart_clk");
-		msm_port->pclk = ERR_PTR(-ENOENT);
-	}
-
+	msm_port->clk = devm_clk_get(&pdev->dev, "core");
 	if (IS_ERR(msm_port->clk))
 		return PTR_ERR(msm_port->clk);
 
 	if (msm_port->is_uartdm) {
+		msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
 		if (IS_ERR(msm_port->pclk))
 			return PTR_ERR(msm_port->pclk);
 
@@ -931,6 +970,7 @@
 
 static struct of_device_id msm_match_table[] = {
 	{ .compatible = "qcom,msm-uart" },
+	{ .compatible = "qcom,msm-uartdm" },
 	{}
 };
 
diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index e4acef5..469fda5 100644
--- a/drivers/tty/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
@@ -38,19 +38,7 @@
 #define UART_MR2_PARITY_MODE_SPACE	0x3
 #define UART_MR2_PARITY_MODE		0x3
 
-#define UART_CSR	0x0008
-#define UART_CSR_115200	0xFF
-#define UART_CSR_57600	0xEE
-#define UART_CSR_38400	0xDD
-#define UART_CSR_28800	0xCC
-#define UART_CSR_19200	0xBB
-#define UART_CSR_14400	0xAA
-#define UART_CSR_9600	0x99
-#define UART_CSR_4800	0x77
-#define UART_CSR_2400	0x55
-#define UART_CSR_1200	0x44
-#define UART_CSR_600	0x33
-#define UART_CSR_300	0x22
+#define UART_CSR			0x0008
 
 #define UART_TF		0x000C
 #define UARTDM_TF	0x0070
@@ -71,6 +59,7 @@
 #define UART_CR_CMD_RESET_RFR		(14 << 4)
 #define UART_CR_CMD_PROTECTION_EN	(16 << 4)
 #define UART_CR_CMD_STALE_EVENT_ENABLE	(80 << 4)
+#define UART_CR_CMD_RESET_TX_READY	(3 << 8)
 #define UART_CR_TX_DISABLE		(1 << 3)
 #define UART_CR_TX_ENABLE		(1 << 2)
 #define UART_CR_RX_DISABLE		(1 << 1)
@@ -151,6 +140,7 @@
 	msm_write(port, 0xF1, UART_NREG);
 	msm_write(port, 0x0F, UART_DREG);
 	msm_write(port, 0x1A, UART_MNDREG);
+	port->uartclk = 1843200;
 }
 
 /*
@@ -162,6 +152,7 @@
 	msm_write(port, 0xF6, UART_NREG);
 	msm_write(port, 0x0F, UART_DREG);
 	msm_write(port, 0x0A, UART_MNDREG);
+	port->uartclk = 1843200;
 }
 
 static inline
@@ -169,7 +160,7 @@
 {
 	if (port->uartclk == 19200000)
 		msm_serial_set_mnd_regs_tcxo(port);
-	else
+	else if (port->uartclk == 4800000)
 		msm_serial_set_mnd_regs_tcxoby4(port);
 }
 
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4ca2f64..48e9496 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1618,7 +1618,7 @@
 	struct msm_hs_port *msm_uport;
 	struct resource *resource;
 	const struct msm_serial_hs_platform_data *pdata =
-						pdev->dev.platform_data;
+						dev_get_platdata(&pdev->dev);
 
 	if (pdev->id < 0 || pdev->id >= UARTDM_NR) {
 		printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index f85b8e6..10e9d70 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -32,7 +32,6 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/of_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -134,10 +133,10 @@
 struct mxs_auart_port {
 	struct uart_port port;
 
-#define MXS_AUART_DMA_CONFIG	0x1
 #define MXS_AUART_DMA_ENABLED	0x2
 #define MXS_AUART_DMA_TX_SYNC	2  /* bit 2 */
 #define MXS_AUART_DMA_RX_READY	3  /* bit 3 */
+#define MXS_AUART_RTSCTS	4  /* bit 4 */
 	unsigned long flags;
 	unsigned int ctrl;
 	enum mxs_auart_type devtype;
@@ -640,7 +639,8 @@
 		 * we can only implement the DMA support for auart
 		 * in mx28.
 		 */
-		if (is_imx28_auart(s) && (s->flags & MXS_AUART_DMA_CONFIG)) {
+		if (is_imx28_auart(s)
+				&& test_bit(MXS_AUART_RTSCTS, &s->flags)) {
 			if (!mxs_auart_dma_init(s))
 				/* enable DMA tranfer */
 				ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE
@@ -1008,7 +1008,8 @@
 	}
 	s->port.line = ret;
 
-	s->flags |= MXS_AUART_DMA_CONFIG;
+	if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+		set_bit(MXS_AUART_RTSCTS, &s->flags);
 
 	return 0;
 }
@@ -1021,7 +1022,6 @@
 	u32 version;
 	int ret = 0;
 	struct resource *r;
-	struct pinctrl *pinctrl;
 
 	s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
 	if (!s) {
@@ -1035,12 +1035,6 @@
 	else if (ret < 0)
 		goto out_free;
 
-	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		ret = PTR_ERR(pinctrl);
-		goto out_free;
-	}
-
 	if (of_id) {
 		pdev->id_entry = of_id->data;
 		s->devtype = pdev->id_entry->driver_data;
diff --git a/drivers/tty/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
index b9a40ed..0a4dd70 100644
--- a/drivers/tty/serial/netx-serial.c
+++ b/drivers/tty/serial/netx-serial.c
@@ -196,7 +196,7 @@
 		uart_write_wakeup(port);
 }
 
-static void netx_rxint(struct uart_port *port)
+static void netx_rxint(struct uart_port *port, unsigned long *flags)
 {
 	unsigned char rx, flg, status;
 
@@ -236,7 +236,9 @@
 		uart_insert_char(port, status, SR_OE, rx, flg);
 	}
 
+	spin_unlock_irqrestore(&port->lock, *flags);
 	tty_flip_buffer_push(&port->state->port);
+	spin_lock_irqsave(&port->lock, *flags);
 }
 
 static irqreturn_t netx_int(int irq, void *dev_id)
@@ -250,7 +252,7 @@
 	status = readl(port->membase + UART_IIR) & IIR_MASK;
 	while (status) {
 		if (status & IIR_RIS)
-			netx_rxint(port);
+			netx_rxint(port, &flags);
 		if (status & IIR_TIS)
 			netx_txint(port);
 		if (status & IIR_MIS) {
@@ -693,8 +695,6 @@
 {
 	struct netx_port *sport = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (sport)
 		uart_remove_one_port(&netx_reg, &sport->port);
 
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
index 549c70a2..693bc6c 100644
--- a/drivers/tty/serial/nwpserial.c
+++ b/drivers/tty/serial/nwpserial.c
@@ -149,7 +149,10 @@
 			tty_insert_flip_char(port, ch, TTY_NORMAL);
 	} while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
 
+	spin_unlock(&up->port.lock);
 	tty_flip_buffer_push(port);
+	spin_lock(&up->port.lock);
+
 	ret = IRQ_HANDLED;
 
 	/* clear interrupt */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index b6d1728..816d1a2 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -40,9 +40,11 @@
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/gpio.h>
-#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_data/serial-omap.h>
 
+#include <dt-bindings/gpio/gpio.h>
+
 #define OMAP_MAX_HSUART_PORTS	6
 
 #define UART_BUILD_REVISION(x, y)	(((x) << 8) | (y))
@@ -52,6 +54,11 @@
 #define OMAP_UART_REV_52 0x0502
 #define OMAP_UART_REV_63 0x0603
 
+#define OMAP_UART_TX_WAKEUP_EN		BIT(7)
+
+/* Feature flags */
+#define OMAP_UART_WER_HAS_TX_WAKEUP	BIT(0)
+
 #define UART_ERRATA_i202_MDR1_ACCESS	BIT(0)
 #define UART_ERRATA_i291_DMA_FORCEIDLE	BIT(1)
 
@@ -137,6 +144,7 @@
 	unsigned char		dlh;
 	unsigned char		mdr1;
 	unsigned char		scr;
+	unsigned char		wer;
 
 	int			use_dma;
 	/*
@@ -151,16 +159,19 @@
 	int			context_loss_cnt;
 	u32			errata;
 	u8			wakeups_enabled;
+	u32			features;
 
 	int			DTR_gpio;
 	int			DTR_inverted;
 	int			DTR_active;
 
+	struct serial_rs485	rs485;
+	int			rts_gpio;
+
 	struct pm_qos_request	pm_qos_request;
 	u32			latency;
 	u32			calc_latency;
 	struct work_struct	qos_work;
-	struct pinctrl		*pins;
 	bool			is_suspending;
 };
 
@@ -195,7 +206,7 @@
 
 static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
 {
-	struct omap_uart_port_info *pdata = up->dev->platform_data;
+	struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
 
 	if (!pdata || !pdata->get_context_loss_count)
 		return -EINVAL;
@@ -205,7 +216,7 @@
 
 static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
 {
-	struct omap_uart_port_info *pdata = up->dev->platform_data;
+	struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
 
 	if (!pdata || !pdata->enable_wakeup)
 		return;
@@ -272,13 +283,42 @@
 static void serial_omap_stop_tx(struct uart_port *port)
 {
 	struct uart_omap_port *up = to_uart_omap_port(port);
+	struct circ_buf *xmit = &up->port.state->xmit;
+	int res;
 
 	pm_runtime_get_sync(up->dev);
+
+	/* handle rs485 */
+	if (up->rs485.flags & SER_RS485_ENABLED) {
+		/* do nothing if current tx not yet completed */
+		res = serial_in(up, UART_LSR) & UART_LSR_TEMT;
+		if (!res)
+			return;
+
+		/* if there's no more data to send, turn off rts */
+		if (uart_circ_empty(xmit)) {
+			/* if rts not already disabled */
+			res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
+			if (gpio_get_value(up->rts_gpio) != res) {
+				if (up->rs485.delay_rts_after_send > 0) {
+					mdelay(up->rs485.delay_rts_after_send);
+				}
+				gpio_set_value(up->rts_gpio, res);
+			}
+		}
+	}
+
 	if (up->ier & UART_IER_THRI) {
 		up->ier &= ~UART_IER_THRI;
 		serial_out(up, UART_IER, up->ier);
 	}
 
+	if ((up->rs485.flags & SER_RS485_ENABLED) &&
+	    !(up->rs485.flags & SER_RS485_RX_DURING_TX)) {
+		up->ier = UART_IER_RLSI | UART_IER_RDI;
+		serial_out(up, UART_IER, up->ier);
+	}
+
 	pm_runtime_mark_last_busy(up->dev);
 	pm_runtime_put_autosuspend(up->dev);
 }
@@ -340,8 +380,26 @@
 static void serial_omap_start_tx(struct uart_port *port)
 {
 	struct uart_omap_port *up = to_uart_omap_port(port);
+	int res;
 
 	pm_runtime_get_sync(up->dev);
+
+	/* handle rs485 */
+	if (up->rs485.flags & SER_RS485_ENABLED) {
+		/* if rts not already enabled */
+		res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;
+		if (gpio_get_value(up->rts_gpio) != res) {
+			gpio_set_value(up->rts_gpio, res);
+			if (up->rs485.delay_rts_before_send > 0) {
+				mdelay(up->rs485.delay_rts_before_send);
+			}
+		}
+	}
+
+	if ((up->rs485.flags & SER_RS485_ENABLED) &&
+	    !(up->rs485.flags & SER_RS485_RX_DURING_TX))
+		serial_omap_stop_rx(port);
+
 	serial_omap_enable_ier_thri(up);
 	pm_runtime_mark_last_busy(up->dev);
 	pm_runtime_put_autosuspend(up->dev);
@@ -683,7 +741,11 @@
 	serial_out(up, UART_IER, up->ier);
 
 	/* Enable module level wake up */
-	serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP);
+	up->wer = OMAP_UART_WER_MOD_WKUP;
+	if (up->features & OMAP_UART_WER_HAS_TX_WAKEUP)
+		up->wer |= OMAP_UART_TX_WAKEUP_EN;
+
+	serial_out(up, UART_OMAP_WER, up->wer);
 
 	pm_runtime_mark_last_busy(up->dev);
 	pm_runtime_put_autosuspend(up->dev);
@@ -1254,6 +1316,76 @@
 
 #endif
 
+/* Enable or disable the rs485 support */
+static void
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+{
+	struct uart_omap_port *up = to_uart_omap_port(port);
+	unsigned long flags;
+	unsigned int mode;
+	int val;
+
+	pm_runtime_get_sync(up->dev);
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	/* Disable interrupts from this port */
+	mode = up->ier;
+	up->ier = 0;
+	serial_out(up, UART_IER, 0);
+
+	/* store new config */
+	up->rs485 = *rs485conf;
+
+	/*
+	 * Just as a precaution, only allow rs485
+	 * to be enabled if the gpio pin is valid
+	 */
+	if (gpio_is_valid(up->rts_gpio)) {
+		/* enable / disable rts */
+		val = (up->rs485.flags & SER_RS485_ENABLED) ?
+			SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND;
+		val = (up->rs485.flags & val) ? 1 : 0;
+		gpio_set_value(up->rts_gpio, val);
+	} else
+		up->rs485.flags &= ~SER_RS485_ENABLED;
+
+	/* Enable interrupts */
+	up->ier = mode;
+	serial_out(up, UART_IER, up->ier);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+	pm_runtime_mark_last_busy(up->dev);
+	pm_runtime_put_autosuspend(up->dev);
+}
+
+static int
+serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+	struct serial_rs485 rs485conf;
+
+	switch (cmd) {
+	case TIOCSRS485:
+		if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+					sizeof(rs485conf)))
+			return -EFAULT;
+
+		serial_omap_config_rs485(port, &rs485conf);
+		break;
+
+	case TIOCGRS485:
+		if (copy_to_user((struct serial_rs485 *) arg,
+					&(to_uart_omap_port(port)->rs485),
+					sizeof(rs485conf)))
+			return -EFAULT;
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+
 static struct uart_ops serial_omap_pops = {
 	.tx_empty	= serial_omap_tx_empty,
 	.set_mctrl	= serial_omap_set_mctrl,
@@ -1275,6 +1407,7 @@
 	.request_port	= serial_omap_request_port,
 	.config_port	= serial_omap_config_port,
 	.verify_port	= serial_omap_verify_port,
+	.ioctl		= serial_omap_ioctl,
 #ifdef CONFIG_CONSOLE_POLL
 	.poll_put_char  = serial_omap_poll_put_char,
 	.poll_get_char  = serial_omap_poll_get_char,
@@ -1334,7 +1467,7 @@
 	u32 mvr, scheme;
 	u16 revision, major, minor;
 
-	mvr = serial_in(up, UART_OMAP_MVER);
+	mvr = readl(up->port.membase + (UART_OMAP_MVER << up->port.regshift));
 
 	/* Check revision register scheme */
 	scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
@@ -1373,9 +1506,11 @@
 	case OMAP_UART_REV_52:
 		up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
 				UART_ERRATA_i291_DMA_FORCEIDLE);
+		up->features |= OMAP_UART_WER_HAS_TX_WAKEUP;
 		break;
 	case OMAP_UART_REV_63:
 		up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
+		up->features |= OMAP_UART_WER_HAS_TX_WAKEUP;
 		break;
 	default:
 		break;
@@ -1395,15 +1530,64 @@
 	return omap_up_info;
 }
 
+static int serial_omap_probe_rs485(struct uart_omap_port *up,
+				   struct device_node *np)
+{
+	struct serial_rs485 *rs485conf = &up->rs485;
+	u32 rs485_delay[2];
+	enum of_gpio_flags flags;
+	int ret;
+
+	rs485conf->flags = 0;
+	up->rts_gpio = -EINVAL;
+
+	if (!np)
+		return 0;
+
+	if (of_property_read_bool(np, "rs485-rts-active-high"))
+		rs485conf->flags |= SER_RS485_RTS_ON_SEND;
+	else
+		rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
+
+	/* check for tx enable gpio */
+	up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
+	if (gpio_is_valid(up->rts_gpio)) {
+		ret = gpio_request(up->rts_gpio, "omap-serial");
+		if (ret < 0)
+			return ret;
+		ret = gpio_direction_output(up->rts_gpio,
+					    flags & SER_RS485_RTS_AFTER_SEND);
+		if (ret < 0)
+			return ret;
+	} else
+		up->rts_gpio = -EINVAL;
+
+	if (of_property_read_u32_array(np, "rs485-rts-delay",
+				    rs485_delay, 2) == 0) {
+		rs485conf->delay_rts_before_send = rs485_delay[0];
+		rs485conf->delay_rts_after_send = rs485_delay[1];
+	}
+
+	if (of_property_read_bool(np, "rs485-rx-during-tx"))
+		rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+	if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time"))
+		rs485conf->flags |= SER_RS485_ENABLED;
+
+	return 0;
+}
+
 static int serial_omap_probe(struct platform_device *pdev)
 {
 	struct uart_omap_port	*up;
 	struct resource		*mem, *irq;
-	struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+	struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
 	int ret;
 
-	if (pdev->dev.of_node)
+	if (pdev->dev.of_node) {
 		omap_up_info = of_get_uart_port_info(&pdev->dev);
+		pdev->dev.platform_data = omap_up_info;
+	}
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!mem) {
@@ -1468,12 +1652,9 @@
 		goto err_port_line;
 	}
 
-	up->pins = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(up->pins)) {
-		dev_warn(&pdev->dev, "did not get pins for uart%i error: %li\n",
-			 up->port.line, PTR_ERR(up->pins));
-		up->pins = NULL;
-	}
+	ret = serial_omap_probe_rs485(up, pdev->dev.of_node);
+	if (ret < 0)
+		goto err_rs485;
 
 	sprintf(up->name, "OMAP UART%d", up->port.line);
 	up->port.mapbase = mem->start;
@@ -1501,7 +1682,6 @@
 	INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
 
 	platform_set_drvdata(pdev, up);
-	pm_runtime_enable(&pdev->dev);
 	if (omap_up_info->autosuspend_timeout == 0)
 		omap_up_info->autosuspend_timeout = -1;
 	device_init_wakeup(up->dev, true);
@@ -1510,6 +1690,8 @@
 			omap_up_info->autosuspend_timeout);
 
 	pm_runtime_irq_safe(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	pm_runtime_get_sync(&pdev->dev);
 
 	omap_serial_fill_features_erratas(up);
@@ -1529,6 +1711,7 @@
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 err_ioremap:
+err_rs485:
 err_port_line:
 	dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
 				pdev->id, __func__, ret);
@@ -1609,6 +1792,7 @@
 		serial_omap_mdr1_errataset(up, up->mdr1);
 	else
 		serial_out(up, UART_OMAP_MDR1, up->mdr1);
+	serial_out(up, UART_OMAP_WER, up->wer);
 }
 
 static int serial_omap_runtime_suspend(struct device *dev)
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 572d481..52379e5 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -232,7 +232,7 @@
 	unsigned int iobase;
 	struct pci_dev *pdev;
 	int fifo_size;
-	int uartclk;
+	unsigned int uartclk;
 	int start_tx;
 	int start_rx;
 	int tx_empty;
@@ -373,35 +373,62 @@
 };
 #endif	/* CONFIG_DEBUG_FS */
 
+static struct dmi_system_id pch_uart_dmi_table[] = {
+	{
+		.ident = "CM-iTC",
+		{
+			DMI_MATCH(DMI_BOARD_NAME, "CM-iTC"),
+		},
+		(void *)CMITC_UARTCLK,
+	},
+	{
+		.ident = "FRI2",
+		{
+			DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
+		},
+		(void *)FRI2_64_UARTCLK,
+	},
+	{
+		.ident = "Fish River Island II",
+		{
+			DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
+		},
+		(void *)FRI2_48_UARTCLK,
+	},
+	{
+		.ident = "COMe-mTT",
+		{
+			DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
+		},
+		(void *)NTC1_UARTCLK,
+	},
+	{
+		.ident = "nanoETXexpress-TT",
+		{
+			DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
+		},
+		(void *)NTC1_UARTCLK,
+	},
+	{
+		.ident = "MinnowBoard",
+		{
+			DMI_MATCH(DMI_BOARD_NAME, "MinnowBoard"),
+		},
+		(void *)MINNOW_UARTCLK,
+	},
+};
+
 /* Return UART clock, checking for board specific clocks. */
-static int pch_uart_get_uartclk(void)
+static unsigned int pch_uart_get_uartclk(void)
 {
-	const char *cmp;
+	const struct dmi_system_id *d;
 
 	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;
-
-	/* Kontron COMe-mTT10 (nanoETXexpress-TT) */
-	cmp = dmi_get_system_info(DMI_BOARD_NAME);
-	if (cmp && (strstr(cmp, "COMe-mTT") ||
-		    strstr(cmp, "nanoETXexpress-TT")))
-		return NTC1_UARTCLK;
-
-	cmp = dmi_get_system_info(DMI_BOARD_NAME);
-	if (cmp && strstr(cmp, "MinnowBoard"))
-		return MINNOW_UARTCLK;
+	d = dmi_first_match(pch_uart_dmi_table);
+	if (d)
+		return (unsigned long)d->driver_data;
 
 	return DEFAULT_UARTCLK;
 }
@@ -422,7 +449,7 @@
 	iowrite8(ier, priv->membase + UART_IER);
 }
 
-static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud,
+static int pch_uart_hal_set_line(struct eg20t_port *priv, unsigned int baud,
 				 unsigned int parity, unsigned int bits,
 				 unsigned int stb)
 {
@@ -457,7 +484,7 @@
 	lcr |= bits;
 	lcr |= stb;
 
-	dev_dbg(priv->port.dev, "%s:baud = %d, div = %04x, lcr = %02x (%lu)\n",
+	dev_dbg(priv->port.dev, "%s:baud = %u, div = %04x, lcr = %02x (%lu)\n",
 		 __func__, baud, div, lcr, jiffies);
 	iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
 	iowrite8(dll, priv->membase + PCH_UART_DLL);
@@ -1363,9 +1390,8 @@
 static void pch_uart_set_termios(struct uart_port *port,
 				 struct ktermios *termios, struct ktermios *old)
 {
-	int baud;
 	int rtn;
-	unsigned int parity, bits, stb;
+	unsigned int baud, parity, bits, stb;
 	struct eg20t_port *priv;
 	unsigned long flags;
 
@@ -1498,6 +1524,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_PCH_UART_CONSOLE)
 /*
  *	Wait for transmitter & holding register to empty
  */
@@ -1528,6 +1555,7 @@
 		}
 	}
 }
+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_PCH_UART_CONSOLE */
 
 #ifdef CONFIG_CONSOLE_POLL
 /*
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index b1785f5..f87f1a0 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -1798,7 +1798,6 @@
 
 	uart_remove_one_port(&pmz_uart_reg, &uap->port);
 
-	platform_set_drvdata(pdev, NULL);
 	uap->port.dev = NULL;
 
 	return 0;
diff --git a/drivers/tty/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
index 7e277a5..de6c05c 100644
--- a/drivers/tty/serial/pnx8xxx_uart.c
+++ b/drivers/tty/serial/pnx8xxx_uart.c
@@ -237,7 +237,10 @@
 		status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
 			 ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
 	}
+
+	spin_unlock(&sport->port.lock);
 	tty_flip_buffer_push(&sport->port.state->port);
+	spin_lock(&sport->port.lock);
 }
 
 static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
@@ -801,8 +804,6 @@
 {
 	struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (sport)
 		uart_remove_one_port(&pnx8xxx_reg, &sport->port);
 
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 05f504e..f9f20f3 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -332,31 +332,6 @@
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
-#if 0
-static void serial_pxa_dma_init(struct pxa_uart *up)
-{
-	up->rxdma =
-		pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
-	if (up->rxdma < 0)
-		goto out;
-	up->txdma =
-		pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
-	if (up->txdma < 0)
-		goto err_txdma;
-	up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
-	if (!up->dmadesc)
-		goto err_alloc;
-
-	/* ... */
-err_alloc:
-	pxa_free_dma(up->txdma);
-err_rxdma:
-	pxa_free_dma(up->rxdma);
-out:
-	return;
-}
-#endif
-
 static int serial_pxa_startup(struct uart_port *port)
 {
 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
@@ -790,7 +765,7 @@
 #define PXA_CONSOLE	NULL
 #endif
 
-struct uart_ops serial_pxa_pops = {
+static struct uart_ops serial_pxa_pops = {
 	.tx_empty	= serial_pxa_tx_empty,
 	.set_mctrl	= serial_pxa_set_mctrl,
 	.get_mctrl	= serial_pxa_get_mctrl,
@@ -945,8 +920,6 @@
 {
 	struct uart_pxa_port *sport = platform_get_drvdata(dev);
 
-	platform_set_drvdata(dev, NULL);
-
 	uart_remove_one_port(&serial_pxa_reg, &sport->port);
 
 	clk_unprepare(sport->clk);
@@ -970,7 +943,7 @@
 	},
 };
 
-int __init serial_pxa_init(void)
+static int __init serial_pxa_init(void)
 {
 	int ret;
 
@@ -985,7 +958,7 @@
 	return ret;
 }
 
-void __exit serial_pxa_exit(void)
+static void __exit serial_pxa_exit(void)
 {
 	platform_driver_unregister(&serial_pxa_driver);
 	uart_unregister_driver(&serial_pxa_reg);
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
index a314a94..328d6de 100644
--- a/drivers/tty/serial/rp2.c
+++ b/drivers/tty/serial/rp2.c
@@ -427,7 +427,9 @@
 		up->port.icount.rx++;
 	}
 
+	spin_unlock(&up->port.lock);
 	tty_flip_buffer_push(port);
+	spin_lock(&up->port.lock);
 }
 
 static void rp2_tx_chars(struct rp2_uart_port *up)
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index af6b3e3..ba25722 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -232,7 +232,10 @@
 		status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
 			 UTSR0_TO_SM(UART_GET_UTSR0(sport));
 	}
+
+	spin_unlock(&sport->port.lock);
 	tty_flip_buffer_push(&sport->port.state->port);
+	spin_lock(&sport->port.lock);
 }
 
 static void sa1100_tx_chars(struct sa1100_port *sport)
@@ -864,8 +867,6 @@
 {
 	struct sa1100_port *sport = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
-
 	if (sport)
 		uart_remove_one_port(&sa1100_reg, &sport->port);
 
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 376079b..f3dfa19 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -249,6 +249,8 @@
 					ufcon |= S3C2410_UFCON_RESETRX;
 					wr_regl(port, S3C2410_UFCON, ufcon);
 					rx_enabled(port) = 1;
+					spin_unlock_irqrestore(&port->lock,
+							flags);
 					goto out;
 				}
 				continue;
@@ -297,10 +299,11 @@
  ignore_char:
 		continue;
 	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
 	tty_flip_buffer_push(&port->state->port);
 
  out:
-	spin_unlock_irqrestore(&port->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -1250,8 +1253,8 @@
 
 	ourport->baudclk = ERR_PTR(-EINVAL);
 	ourport->info = ourport->drv_data->info;
-	ourport->cfg = (pdev->dev.platform_data) ?
-			(struct s3c2410_uartcfg *)pdev->dev.platform_data :
+	ourport->cfg = (dev_get_platdata(&pdev->dev)) ?
+			(struct s3c2410_uartcfg *)dev_get_platdata(&pdev->dev) :
 			ourport->drv_data->def_cfg;
 
 	ourport->port.fifosize = (ourport->info->fifosize) ?
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index 00a499e..aaa617a 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -68,7 +68,8 @@
 /* register access controls */
 
 #define portaddr(port, reg) ((port)->membase + (reg))
-#define portaddrl(port, reg) ((unsigned long *)((port)->membase + (reg)))
+#define portaddrl(port, reg) \
+	((unsigned long *)(unsigned long)((port)->membase + (reg)))
 
 #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
 #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index 4b1434d..887b4f7 100644
--- a/drivers/tty/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
@@ -637,7 +637,7 @@
 {
 	struct resource *res;
 	struct uart_sc26xx_port *up;
-	unsigned int *sc26xx_data = dev->dev.platform_data;
+	unsigned int *sc26xx_data = dev_get_platdata(&dev->dev);
 	int err;
 
 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index c773041..49e9bbf 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -15,6 +15,7 @@
 #define SUPPORT_SYSRQ
 #endif
 
+#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/device.h>
@@ -94,16 +95,17 @@
 #define MCTRL_IBIT(cfg, sig)		((((cfg) >> (sig)) & 0xf) - LINE_IP0)
 #define MCTRL_OBIT(cfg, sig)		((((cfg) >> (sig)) & 0xf) - LINE_OP0)
 
-/* Supported chip types */
-enum {
-	SCCNXP_TYPE_SC2681	= 2681,
-	SCCNXP_TYPE_SC2691	= 2691,
-	SCCNXP_TYPE_SC2692	= 2692,
-	SCCNXP_TYPE_SC2891	= 2891,
-	SCCNXP_TYPE_SC2892	= 2892,
-	SCCNXP_TYPE_SC28202	= 28202,
-	SCCNXP_TYPE_SC68681	= 68681,
-	SCCNXP_TYPE_SC68692	= 68692,
+#define SCCNXP_HAVE_IO		0x00000001
+#define SCCNXP_HAVE_MR0		0x00000002
+
+struct sccnxp_chip {
+	const char		*name;
+	unsigned int		nr;
+	unsigned long		freq_min;
+	unsigned long		freq_std;
+	unsigned long		freq_max;
+	unsigned int		flags;
+	unsigned int		fifosize;
 };
 
 struct sccnxp_port {
@@ -111,16 +113,10 @@
 	struct uart_port	port[SCCNXP_MAX_UARTS];
 	bool			opened[SCCNXP_MAX_UARTS];
 
-	const char		*name;
 	int			irq;
-
 	u8			imr;
-	u8			addr_mask;
-	int			freq_std;
 
-	int			flags;
-#define SCCNXP_HAVE_IO		0x00000001
-#define SCCNXP_HAVE_MR0		0x00000002
+	struct sccnxp_chip	*chip;
 
 #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
 	struct console		console;
@@ -136,29 +132,94 @@
 	struct regulator	*regulator;
 };
 
-static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
-{
-	return readb(base + (reg << shift));
-}
+static const struct sccnxp_chip sc2681 = {
+	.name		= "SC2681",
+	.nr		= 2,
+	.freq_min	= 1000000,
+	.freq_std	= 3686400,
+	.freq_max	= 4000000,
+	.flags		= SCCNXP_HAVE_IO,
+	.fifosize	= 3,
+};
 
-static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v)
-{
-	writeb(v, base + (reg << shift));
-}
+static const struct sccnxp_chip sc2691 = {
+	.name		= "SC2691",
+	.nr		= 1,
+	.freq_min	= 1000000,
+	.freq_std	= 3686400,
+	.freq_max	= 4000000,
+	.flags		= 0,
+	.fifosize	= 3,
+};
+
+static const struct sccnxp_chip sc2692 = {
+	.name		= "SC2692",
+	.nr		= 2,
+	.freq_min	= 1000000,
+	.freq_std	= 3686400,
+	.freq_max	= 4000000,
+	.flags		= SCCNXP_HAVE_IO,
+	.fifosize	= 3,
+};
+
+static const struct sccnxp_chip sc2891 = {
+	.name		= "SC2891",
+	.nr		= 1,
+	.freq_min	= 100000,
+	.freq_std	= 3686400,
+	.freq_max	= 8000000,
+	.flags		= SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
+	.fifosize	= 16,
+};
+
+static const struct sccnxp_chip sc2892 = {
+	.name		= "SC2892",
+	.nr		= 2,
+	.freq_min	= 100000,
+	.freq_std	= 3686400,
+	.freq_max	= 8000000,
+	.flags		= SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
+	.fifosize	= 16,
+};
+
+static const struct sccnxp_chip sc28202 = {
+	.name		= "SC28202",
+	.nr		= 2,
+	.freq_min	= 1000000,
+	.freq_std	= 14745600,
+	.freq_max	= 50000000,
+	.flags		= SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0,
+	.fifosize	= 256,
+};
+
+static const struct sccnxp_chip sc68681 = {
+	.name		= "SC68681",
+	.nr		= 2,
+	.freq_min	= 1000000,
+	.freq_std	= 3686400,
+	.freq_max	= 4000000,
+	.flags		= SCCNXP_HAVE_IO,
+	.fifosize	= 3,
+};
+
+static const struct sccnxp_chip sc68692 = {
+	.name		= "SC68692",
+	.nr		= 2,
+	.freq_min	= 1000000,
+	.freq_std	= 3686400,
+	.freq_max	= 4000000,
+	.flags		= SCCNXP_HAVE_IO,
+	.fifosize	= 3,
+};
 
 static inline u8 sccnxp_read(struct uart_port *port, u8 reg)
 {
-	struct sccnxp_port *s = dev_get_drvdata(port->dev);
-
-	return sccnxp_raw_read(port->membase, reg & s->addr_mask,
-			       port->regshift);
+	return readb(port->membase + (reg << port->regshift));
 }
 
 static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v)
 {
-	struct sccnxp_port *s = dev_get_drvdata(port->dev);
-
-	sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v);
+	writeb(v, port->membase + (reg << port->regshift));
 }
 
 static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg)
@@ -224,13 +285,14 @@
 {
 	struct sccnxp_port *s = dev_get_drvdata(port->dev);
 	int div_std, tmp_baud, bestbaud = baud, besterr = -1;
+	struct sccnxp_chip *chip = s->chip;
 	u8 i, acr = 0, csr = 0, mr0 = 0;
 
 	/* Find best baud from table */
 	for (i = 0; baud_std[i].baud && besterr; i++) {
-		if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0))
+		if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0))
 			continue;
-		div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud);
+		div_std = DIV_ROUND_CLOSEST(chip->freq_std, baud_std[i].baud);
 		tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std);
 		if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) {
 			acr = baud_std[i].acr;
@@ -240,7 +302,7 @@
 		}
 	}
 
-	if (s->flags & SCCNXP_HAVE_MR0) {
+	if (chip->flags & SCCNXP_HAVE_MR0) {
 		/* Enable FIFO, set half level for TX */
 		mr0 |= MR0_FIFO | MR0_TXLVL;
 		/* Update MR0 */
@@ -363,7 +425,7 @@
 			sccnxp_disable_irq(port, IMR_TXRDY);
 
 			/* Set direction to input */
-			if (s->flags & SCCNXP_HAVE_IO)
+			if (s->chip->flags & SCCNXP_HAVE_IO)
 				sccnxp_set_bit(port, DIR_OP, 0);
 		}
 		return;
@@ -437,7 +499,7 @@
 	spin_lock_irqsave(&s->lock, flags);
 
 	/* Set direction to output */
-	if (s->flags & SCCNXP_HAVE_IO)
+	if (s->chip->flags & SCCNXP_HAVE_IO)
 		sccnxp_set_bit(port, DIR_OP, 1);
 
 	sccnxp_enable_irq(port, IMR_TXRDY);
@@ -483,7 +545,7 @@
 	struct sccnxp_port *s = dev_get_drvdata(port->dev);
 	unsigned long flags;
 
-	if (!(s->flags & SCCNXP_HAVE_IO))
+	if (!(s->chip->flags & SCCNXP_HAVE_IO))
 		return;
 
 	spin_lock_irqsave(&s->lock, flags);
@@ -501,7 +563,7 @@
 	struct sccnxp_port *s = dev_get_drvdata(port->dev);
 	unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
 
-	if (!(s->flags & SCCNXP_HAVE_IO))
+	if (!(s->chip->flags & SCCNXP_HAVE_IO))
 		return mctrl;
 
 	spin_lock_irqsave(&s->lock, flags);
@@ -617,7 +679,7 @@
 
 	/* Setup baudrate */
 	baud = uart_get_baud_rate(port, termios, old, 50,
-				  (s->flags & SCCNXP_HAVE_MR0) ?
+				  (s->chip->flags & SCCNXP_HAVE_MR0) ?
 				  230400 : 38400);
 	baud = sccnxp_set_baud(port, baud);
 
@@ -641,7 +703,7 @@
 
 	spin_lock_irqsave(&s->lock, flags);
 
-	if (s->flags & SCCNXP_HAVE_IO) {
+	if (s->chip->flags & SCCNXP_HAVE_IO) {
 		/* Outputs are controlled manually */
 		sccnxp_write(port, SCCNXP_OPCR_REG, 0);
 	}
@@ -681,7 +743,7 @@
 	sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE);
 
 	/* Leave direction to input */
-	if (s->flags & SCCNXP_HAVE_IO)
+	if (s->chip->flags & SCCNXP_HAVE_IO)
 		sccnxp_set_bit(port, DIR_OP, 0);
 
 	spin_unlock_irqrestore(&s->lock, flags);
@@ -691,7 +753,7 @@
 {
 	struct sccnxp_port *s = dev_get_drvdata(port->dev);
 
-	return (port->type == PORT_SC26XX) ? s->name : NULL;
+	return (port->type == PORT_SC26XX) ? s->chip->name : NULL;
 }
 
 static void sccnxp_release_port(struct uart_port *port)
@@ -778,19 +840,31 @@
 }
 #endif
 
+static const struct platform_device_id sccnxp_id_table[] = {
+	{ .name = "sc2681",	.driver_data = (kernel_ulong_t)&sc2681, },
+	{ .name = "sc2691",	.driver_data = (kernel_ulong_t)&sc2691, },
+	{ .name = "sc2692",	.driver_data = (kernel_ulong_t)&sc2692, },
+	{ .name = "sc2891",	.driver_data = (kernel_ulong_t)&sc2891, },
+	{ .name = "sc2892",	.driver_data = (kernel_ulong_t)&sc2892, },
+	{ .name = "sc28202",	.driver_data = (kernel_ulong_t)&sc28202, },
+	{ .name = "sc68681",	.driver_data = (kernel_ulong_t)&sc68681, },
+	{ .name = "sc68692",	.driver_data = (kernel_ulong_t)&sc68692, },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, sccnxp_id_table);
+
 static int sccnxp_probe(struct platform_device *pdev)
 {
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	int chiptype = pdev->id_entry->driver_data;
 	struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev);
-	int i, ret, fifosize, freq_min, freq_max;
+	int i, ret, uartclk;
 	struct sccnxp_port *s;
 	void __iomem *membase;
+	struct clk *clk;
 
-	if (!res) {
-		dev_err(&pdev->dev, "Missing memory resource data\n");
-		return -EADDRNOTAVAIL;
-	}
+	membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(membase))
+		return PTR_ERR(membase);
 
 	s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
 	if (!s) {
@@ -801,99 +875,38 @@
 
 	spin_lock_init(&s->lock);
 
-	/* Individual chip settings */
-	switch (chiptype) {
-	case SCCNXP_TYPE_SC2681:
-		s->name		= "SC2681";
-		s->uart.nr	= 2;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x0f;
-		s->flags	= SCCNXP_HAVE_IO;
-		fifosize	= 3;
-		freq_min	= 1000000;
-		freq_max	= 4000000;
-		break;
-	case SCCNXP_TYPE_SC2691:
-		s->name		= "SC2691";
-		s->uart.nr	= 1;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x07;
-		s->flags	= 0;
-		fifosize	= 3;
-		freq_min	= 1000000;
-		freq_max	= 4000000;
-		break;
-	case SCCNXP_TYPE_SC2692:
-		s->name		= "SC2692";
-		s->uart.nr	= 2;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x0f;
-		s->flags	= SCCNXP_HAVE_IO;
-		fifosize	= 3;
-		freq_min	= 1000000;
-		freq_max	= 4000000;
-		break;
-	case SCCNXP_TYPE_SC2891:
-		s->name		= "SC2891";
-		s->uart.nr	= 1;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x0f;
-		s->flags	= SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
-		fifosize	= 16;
-		freq_min	= 100000;
-		freq_max	= 8000000;
-		break;
-	case SCCNXP_TYPE_SC2892:
-		s->name		= "SC2892";
-		s->uart.nr	= 2;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x0f;
-		s->flags	= SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
-		fifosize	= 16;
-		freq_min	= 100000;
-		freq_max	= 8000000;
-		break;
-	case SCCNXP_TYPE_SC28202:
-		s->name		= "SC28202";
-		s->uart.nr	= 2;
-		s->freq_std	= 14745600;
-		s->addr_mask	= 0x7f;
-		s->flags	= SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0;
-		fifosize	= 256;
-		freq_min	= 1000000;
-		freq_max	= 50000000;
-		break;
-	case SCCNXP_TYPE_SC68681:
-		s->name		= "SC68681";
-		s->uart.nr	= 2;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x0f;
-		s->flags	= SCCNXP_HAVE_IO;
-		fifosize	= 3;
-		freq_min	= 1000000;
-		freq_max	= 4000000;
-		break;
-	case SCCNXP_TYPE_SC68692:
-		s->name		= "SC68692";
-		s->uart.nr	= 2;
-		s->freq_std	= 3686400;
-		s->addr_mask	= 0x0f;
-		s->flags	= SCCNXP_HAVE_IO;
-		fifosize	= 3;
-		freq_min	= 1000000;
-		freq_max	= 4000000;
-		break;
-	default:
-		dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype);
-		ret = -ENOTSUPP;
+	s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data;
+
+	s->regulator = devm_regulator_get(&pdev->dev, "vcc");
+	if (!IS_ERR(s->regulator)) {
+		ret = regulator_enable(s->regulator);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to enable regulator: %i\n", ret);
+			return ret;
+		}
+	} else if (PTR_ERR(s->regulator) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+
+	clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		if (PTR_ERR(clk) == -EPROBE_DEFER) {
+			ret = -EPROBE_DEFER;
+			goto err_out;
+		}
+		dev_notice(&pdev->dev, "Using default clock frequency\n");
+		uartclk = s->chip->freq_std;
+	} else
+		uartclk = clk_get_rate(clk);
+
+	/* Check input frequency */
+	if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
+		dev_err(&pdev->dev, "Frequency out of bounds\n");
+		ret = -EINVAL;
 		goto err_out;
 	}
 
-	if (!pdata) {
-		dev_warn(&pdev->dev,
-			 "No platform data supplied, using defaults\n");
-		s->pdata.frequency = s->freq_std;
-	} else
+	if (pdata)
 		memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata));
 
 	if (s->pdata.poll_time_us) {
@@ -911,34 +924,11 @@
 		}
 	}
 
-	/* Check input frequency */
-	if ((s->pdata.frequency < freq_min) ||
-	    (s->pdata.frequency > freq_max)) {
-		dev_err(&pdev->dev, "Frequency out of bounds\n");
-		ret = -EINVAL;
-		goto err_out;
-	}
-
-	s->regulator = devm_regulator_get(&pdev->dev, "VCC");
-	if (!IS_ERR(s->regulator)) {
-		ret = regulator_enable(s->regulator);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Failed to enable regulator: %i\n", ret);
-			return ret;
-		}
-	}
-
-	membase = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(membase)) {
-		ret = PTR_ERR(membase);
-		goto err_out;
-	}
-
 	s->uart.owner		= THIS_MODULE;
 	s->uart.dev_name	= "ttySC";
 	s->uart.major		= SCCNXP_MAJOR;
 	s->uart.minor		= SCCNXP_MINOR;
+	s->uart.nr		= s->chip->nr;
 #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
 	s->uart.cons		= &s->console;
 	s->uart.cons->device	= uart_console_device;
@@ -960,17 +950,17 @@
 		s->port[i].dev		= &pdev->dev;
 		s->port[i].irq		= s->irq;
 		s->port[i].type		= PORT_SC26XX;
-		s->port[i].fifosize	= fifosize;
+		s->port[i].fifosize	= s->chip->fifosize;
 		s->port[i].flags	= UPF_SKIP_TEST | UPF_FIXED_TYPE;
 		s->port[i].iotype	= UPIO_MEM;
 		s->port[i].mapbase	= res->start;
 		s->port[i].membase	= membase;
 		s->port[i].regshift	= s->pdata.reg_shift;
-		s->port[i].uartclk	= s->pdata.frequency;
+		s->port[i].uartclk	= uartclk;
 		s->port[i].ops		= &sccnxp_ops;
 		uart_add_one_port(&s->uart, &s->port[i]);
 		/* Set direction to input */
-		if (s->flags & SCCNXP_HAVE_IO)
+		if (s->chip->flags & SCCNXP_HAVE_IO)
 			sccnxp_set_bit(&s->port[i], DIR_OP, 0);
 	}
 
@@ -997,7 +987,8 @@
 	}
 
 err_out:
-	platform_set_drvdata(pdev, NULL);
+	if (!IS_ERR(s->regulator))
+		return regulator_disable(s->regulator);
 
 	return ret;
 }
@@ -1016,7 +1007,6 @@
 		uart_remove_one_port(&s->uart, &s->port[i]);
 
 	uart_unregister_driver(&s->uart);
-	platform_set_drvdata(pdev, NULL);
 
 	if (!IS_ERR(s->regulator))
 		return regulator_disable(s->regulator);
@@ -1024,19 +1014,6 @@
 	return 0;
 }
 
-static const struct platform_device_id sccnxp_id_table[] = {
-	{ "sc2681",	SCCNXP_TYPE_SC2681 },
-	{ "sc2691",	SCCNXP_TYPE_SC2691 },
-	{ "sc2692",	SCCNXP_TYPE_SC2692 },
-	{ "sc2891",	SCCNXP_TYPE_SC2891 },
-	{ "sc2892",	SCCNXP_TYPE_SC2892 },
-	{ "sc28202",	SCCNXP_TYPE_SC28202 },
-	{ "sc68681",	SCCNXP_TYPE_SC68681 },
-	{ "sc68692",	SCCNXP_TYPE_SC68692 },
-	{ },
-};
-MODULE_DEVICE_TABLE(platform, sccnxp_id_table);
-
 static struct platform_driver sccnxp_uart_driver = {
 	.driver = {
 		.name	= SCCNXP_NAME,
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index ee7c812..d0d972f 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -571,7 +571,9 @@
 
 	tegra_uart_handle_rx_pio(tup, port);
 	if (tty) {
+		spin_unlock_irqrestore(&u->lock, flags);
 		tty_flip_buffer_push(port);
+		spin_lock_irqsave(&u->lock, flags);
 		tty_kref_put(tty);
 	}
 	tegra_uart_start_rx_dma(tup);
@@ -583,11 +585,13 @@
 	spin_unlock_irqrestore(&u->lock, flags);
 }
 
-static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
+static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
+		unsigned long *flags)
 {
 	struct dma_tx_state state;
 	struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
 	struct tty_port *port = &tup->uport.state->port;
+	struct uart_port *u = &tup->uport;
 	int count;
 
 	/* Deactivate flow control to stop sender */
@@ -604,7 +608,9 @@
 
 	tegra_uart_handle_rx_pio(tup, port);
 	if (tty) {
+		spin_unlock_irqrestore(&u->lock, *flags);
 		tty_flip_buffer_push(port);
+		spin_lock_irqsave(&u->lock, *flags);
 		tty_kref_put(tty);
 	}
 	tegra_uart_start_rx_dma(tup);
@@ -671,7 +677,7 @@
 		iir = tegra_uart_read(tup, UART_IIR);
 		if (iir & UART_IIR_NO_INT) {
 			if (is_rx_int) {
-				tegra_uart_handle_rx_dma(tup);
+				tegra_uart_handle_rx_dma(tup, &flags);
 				if (tup->rx_in_progress) {
 					ier = tup->ier_shadow;
 					ier |= (UART_IER_RLSI | UART_IER_RTOIE |
@@ -1206,7 +1212,7 @@
 	.owner		= THIS_MODULE,
 	.driver_name	= "tegra_hsuart",
 	.dev_name	= "ttyTHS",
-	.cons		= 0,
+	.cons		= NULL,
 	.nr		= TEGRA_UART_MAXIMUM,
 };
 
@@ -1237,13 +1243,13 @@
 	return 0;
 }
 
-struct tegra_uart_chip_data tegra20_uart_chip_data = {
+static struct tegra_uart_chip_data tegra20_uart_chip_data = {
 	.tx_fifo_full_status		= false,
 	.allow_txfifo_reset_fifo_mode	= true,
 	.support_clk_src_div		= false,
 };
 
-struct tegra_uart_chip_data tegra30_uart_chip_data = {
+static struct tegra_uart_chip_data tegra30_uart_chip_data = {
 	.tx_fifo_full_status		= true,
 	.allow_txfifo_reset_fifo_mode	= false,
 	.support_clk_src_div		= true,
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 28cdd28..0f02351 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2095,12 +2095,12 @@
 		break;
 	}
 
-	printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
+	printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
 	       port->dev ? dev_name(port->dev) : "",
 	       port->dev ? ": " : "",
 	       drv->dev_name,
 	       drv->tty_driver->name_base + port->line,
-	       address, port->irq, uart_type(port));
+	       address, port->irq, port->uartclk / 16, uart_type(port));
 }
 
 static void
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index fe48a0c..440a962 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -1097,7 +1097,7 @@
  */
 static int serial_txx9_probe(struct platform_device *dev)
 {
-	struct uart_port *p = dev->dev.platform_data;
+	struct uart_port *p = dev_get_platdata(&dev->dev);
 	struct uart_port port;
 	int ret, i;
 
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 7477e0e..5377502 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2380,7 +2380,7 @@
 
 static int sci_probe_earlyprintk(struct platform_device *pdev)
 {
-	struct plat_sci_port *cfg = pdev->dev.platform_data;
+	struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
 
 	if (early_serial_console.data)
 		return -EEXIST;
@@ -2469,7 +2469,7 @@
 
 static int sci_probe(struct platform_device *dev)
 {
-	struct plat_sci_port *p = dev->dev.platform_data;
+	struct plat_sci_port *p = dev_get_platdata(&dev->dev);
 	struct sci_port *sp = &sci_ports[dev->id];
 	int ret;
 
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 1fd564b..61c1ad0 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -20,9 +20,13 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/sirfsoc_dma.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
-#include <linux/pinctrl/consumer.h>
 
 #include "sirfsoc_uart.h"
 
@@ -32,6 +36,9 @@
 sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
 static struct uart_driver sirfsoc_uart_drv;
 
+static void sirfsoc_uart_tx_dma_complete_callback(void *param);
+static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port);
+static void sirfsoc_uart_rx_dma_complete_callback(void *param);
 static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
 	{4000000, 2359296},
 	{3500000, 1310721},
@@ -89,6 +96,13 @@
 			.line		= 4,
 		},
 	},
+	[5] = {
+		.port = {
+			.iotype		= UPIO_MEM,
+			.flags		= UPF_BOOT_AUTOCONF,
+			.line		= 5,
+		},
+	},
 };
 
 static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
@@ -99,21 +113,28 @@
 static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
 {
 	unsigned long reg;
-	reg = rd_regl(port, SIRFUART_TX_FIFO_STATUS);
-	if (reg & SIRFUART_FIFOEMPTY_MASK(port))
-		return TIOCSER_TEMT;
-	else
-		return 0;
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
+	reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
+
+	return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0;
 }
 
 static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-	if (!(sirfport->ms_enabled)) {
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
 		goto cts_asserted;
-	} else if (sirfport->hw_flow_ctrl) {
-		if (!(rd_regl(port, SIRFUART_AFC_CTRL) &
-						SIRFUART_CTS_IN_STATUS))
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		if (!(rd_regl(port, ureg->sirfsoc_afc_ctrl) &
+						SIRFUART_AFC_CTS_STATUS))
+			goto cts_asserted;
+		else
+			goto cts_deasserted;
+	} else {
+		if (!gpio_get_value(sirfport->cts_gpio))
 			goto cts_asserted;
 		else
 			goto cts_deasserted;
@@ -127,89 +148,276 @@
 static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
 	unsigned int assert = mctrl & TIOCM_RTS;
 	unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
 	unsigned int current_val;
-	if (sirfport->hw_flow_ctrl) {
-		current_val = rd_regl(port, SIRFUART_AFC_CTRL) & ~0xFF;
+
+	if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
+		return;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		current_val = rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0xFF;
 		val |= current_val;
-		wr_regl(port, SIRFUART_AFC_CTRL, val);
+		wr_regl(port, ureg->sirfsoc_afc_ctrl, val);
+	} else {
+		if (!val)
+			gpio_set_value(sirfport->rts_gpio, 1);
+		else
+			gpio_set_value(sirfport->rts_gpio, 0);
 	}
 }
 
 static void sirfsoc_uart_stop_tx(struct uart_port *port)
 {
-	unsigned int regv;
-	regv = rd_regl(port, SIRFUART_INT_EN);
-	wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_TX_INT_EN);
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
+	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+		if (sirfport->tx_dma_state == TX_DMA_RUNNING) {
+			dmaengine_pause(sirfport->tx_dma_chan);
+			sirfport->tx_dma_state = TX_DMA_PAUSE;
+		} else {
+			if (!sirfport->is_marco)
+				wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) &
+				~uint_en->sirfsoc_txfifo_empty_en);
+			else
+				wr_regl(port, SIRFUART_INT_EN_CLR,
+				uint_en->sirfsoc_txfifo_empty_en);
+		}
+	} else {
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) &
+				~uint_en->sirfsoc_txfifo_empty_en);
+		else
+			wr_regl(port, SIRFUART_INT_EN_CLR,
+				uint_en->sirfsoc_txfifo_empty_en);
+	}
 }
 
-void sirfsoc_uart_start_tx(struct uart_port *port)
+static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
+{
+	struct uart_port *port = &sirfport->port;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long tran_size;
+	unsigned long tran_start;
+	unsigned long pio_tx_size;
+
+	tran_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+	tran_start = (unsigned long)(xmit->buf + xmit->tail);
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port) ||
+			!tran_size)
+		return;
+	if (sirfport->tx_dma_state == TX_DMA_PAUSE) {
+		dmaengine_resume(sirfport->tx_dma_chan);
+		return;
+	}
+	if (sirfport->tx_dma_state == TX_DMA_RUNNING)
+		return;
+	if (!sirfport->is_marco)
+		wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg)&
+				~(uint_en->sirfsoc_txfifo_empty_en));
+	else
+		wr_regl(port, SIRFUART_INT_EN_CLR,
+				uint_en->sirfsoc_txfifo_empty_en);
+	/*
+	 * DMA requires buffer address and buffer length are both aligned with
+	 * 4 bytes, so we use PIO for
+	 * 1. if address is not aligned with 4bytes, use PIO for the first 1~3
+	 * bytes, and move to DMA for the left part aligned with 4bytes
+	 * 2. if buffer length is not aligned with 4bytes, use DMA for aligned
+	 * part first, move to PIO for the left 1~3 bytes
+	 */
+	if (tran_size < 4 || BYTES_TO_ALIGN(tran_start)) {
+		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
+		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
+			rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)|
+			SIRFUART_IO_MODE);
+		if (BYTES_TO_ALIGN(tran_start)) {
+			pio_tx_size = sirfsoc_uart_pio_tx_chars(sirfport,
+				BYTES_TO_ALIGN(tran_start));
+			tran_size -= pio_tx_size;
+		}
+		if (tran_size < 4)
+			sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg)|
+				uint_en->sirfsoc_txfifo_empty_en);
+		else
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				uint_en->sirfsoc_txfifo_empty_en);
+		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
+	} else {
+		/* tx transfer mode switch into dma mode */
+		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
+		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
+			rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)&
+			~SIRFUART_IO_MODE);
+		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
+		tran_size &= ~(0x3);
+
+		sirfport->tx_dma_addr = dma_map_single(port->dev,
+			xmit->buf + xmit->tail,
+			tran_size, DMA_TO_DEVICE);
+		sirfport->tx_dma_desc = dmaengine_prep_slave_single(
+			sirfport->tx_dma_chan, sirfport->tx_dma_addr,
+			tran_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+		if (!sirfport->tx_dma_desc) {
+			dev_err(port->dev, "DMA prep slave single fail\n");
+			return;
+		}
+		sirfport->tx_dma_desc->callback =
+			sirfsoc_uart_tx_dma_complete_callback;
+		sirfport->tx_dma_desc->callback_param = (void *)sirfport;
+		sirfport->transfer_size = tran_size;
+
+		dmaengine_submit(sirfport->tx_dma_desc);
+		dma_async_issue_pending(sirfport->tx_dma_chan);
+		sirfport->tx_dma_state = TX_DMA_RUNNING;
+	}
+}
+
+static void sirfsoc_uart_start_tx(struct uart_port *port)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-	unsigned long regv;
-	sirfsoc_uart_pio_tx_chars(sirfport, 1);
-	wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_START);
-	regv = rd_regl(port, SIRFUART_INT_EN);
-	wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_TX_INT_EN);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+		sirfsoc_uart_tx_with_dma(sirfport);
+	else {
+		sirfsoc_uart_pio_tx_chars(sirfport, 1);
+		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+					rd_regl(port, ureg->sirfsoc_int_en_reg)|
+					uint_en->sirfsoc_txfifo_empty_en);
+		else
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+					uint_en->sirfsoc_txfifo_empty_en);
+	}
 }
 
 static void sirfsoc_uart_stop_rx(struct uart_port *port)
 {
-	unsigned long regv;
-	wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
-	regv = rd_regl(port, SIRFUART_INT_EN);
-	wr_regl(port, SIRFUART_INT_EN, regv & ~SIRFUART_RX_IO_INT_EN);
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) &
+				~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
+				uint_en->sirfsoc_rx_done_en));
+		else
+			wr_regl(port, SIRFUART_INT_EN_CLR,
+					SIRFUART_RX_DMA_INT_EN(port, uint_en)|
+					uint_en->sirfsoc_rx_done_en);
+		dmaengine_terminate_all(sirfport->rx_dma_chan);
+	} else {
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg)&
+				~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
+		else
+			wr_regl(port, SIRFUART_INT_EN_CLR,
+					SIRFUART_RX_IO_INT_EN(port, uint_en));
+	}
 }
 
 static void sirfsoc_uart_disable_ms(struct uart_port *port)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-	unsigned long reg;
-	sirfport->ms_enabled = 0;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
 	if (!sirfport->hw_flow_ctrl)
 		return;
-	reg = rd_regl(port, SIRFUART_AFC_CTRL);
-	wr_regl(port, SIRFUART_AFC_CTRL, reg & ~0x3FF);
-	reg = rd_regl(port, SIRFUART_INT_EN);
-	wr_regl(port, SIRFUART_INT_EN, reg & ~SIRFUART_CTS_INT_EN);
+	sirfport->ms_enabled = false;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		wr_regl(port, ureg->sirfsoc_afc_ctrl,
+				rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+					rd_regl(port, ureg->sirfsoc_int_en_reg)&
+					~uint_en->sirfsoc_cts_en);
+		else
+			wr_regl(port, SIRFUART_INT_EN_CLR,
+					uint_en->sirfsoc_cts_en);
+	} else
+		disable_irq(gpio_to_irq(sirfport->cts_gpio));
+}
+
+static irqreturn_t sirfsoc_uart_usp_cts_handler(int irq, void *dev_id)
+{
+	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
+	struct uart_port *port = &sirfport->port;
+	if (gpio_is_valid(sirfport->cts_gpio) && sirfport->ms_enabled)
+		uart_handle_cts_change(port,
+				!gpio_get_value(sirfport->cts_gpio));
+	return IRQ_HANDLED;
 }
 
 static void sirfsoc_uart_enable_ms(struct uart_port *port)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-	unsigned long reg;
-	unsigned long flg;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
 	if (!sirfport->hw_flow_ctrl)
 		return;
-	flg = SIRFUART_AFC_RX_EN | SIRFUART_AFC_TX_EN;
-	reg = rd_regl(port, SIRFUART_AFC_CTRL);
-	wr_regl(port, SIRFUART_AFC_CTRL, reg | flg);
-	reg = rd_regl(port, SIRFUART_INT_EN);
-	wr_regl(port, SIRFUART_INT_EN, reg | SIRFUART_CTS_INT_EN);
-	uart_handle_cts_change(port,
-		!(rd_regl(port, SIRFUART_AFC_CTRL) & SIRFUART_CTS_IN_STATUS));
-	sirfport->ms_enabled = 1;
+	sirfport->ms_enabled = true;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		wr_regl(port, ureg->sirfsoc_afc_ctrl,
+				rd_regl(port, ureg->sirfsoc_afc_ctrl) |
+				SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+					rd_regl(port, ureg->sirfsoc_int_en_reg)
+					| uint_en->sirfsoc_cts_en);
+		else
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+					uint_en->sirfsoc_cts_en);
+	} else
+		enable_irq(gpio_to_irq(sirfport->cts_gpio));
 }
 
 static void sirfsoc_uart_break_ctl(struct uart_port *port, int break_state)
 {
-	unsigned long ulcon = rd_regl(port, SIRFUART_LINE_CTRL);
-	if (break_state)
-		ulcon |= SIRFUART_SET_BREAK;
-	else
-		ulcon &= ~SIRFUART_SET_BREAK;
-	wr_regl(port, SIRFUART_LINE_CTRL, ulcon);
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		unsigned long ulcon = rd_regl(port, ureg->sirfsoc_line_ctrl);
+		if (break_state)
+			ulcon |= SIRFUART_SET_BREAK;
+		else
+			ulcon &= ~SIRFUART_SET_BREAK;
+		wr_regl(port, ureg->sirfsoc_line_ctrl, ulcon);
+	}
 }
 
 static unsigned int
 sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
 {
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
 	unsigned int ch, rx_count = 0;
-
-	while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) &
-					SIRFUART_FIFOEMPTY_MASK(port))) {
-		ch = rd_regl(port, SIRFUART_RX_FIFO_DATA) | SIRFUART_DUMMY_READ;
+	struct tty_struct *tty;
+	tty = tty_port_tty_get(&port->state->port);
+	if (!tty)
+		return -ENODEV;
+	while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
+					ufifo_st->ff_empty(port->line))) {
+		ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
+			SIRFUART_DUMMY_READ;
 		if (unlikely(uart_handle_sysrq_char(port, ch)))
 			continue;
 		uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
@@ -218,8 +426,12 @@
 			break;
 	}
 
+	sirfport->rx_io_count += rx_count;
 	port->icount.rx += rx_count;
+
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
 
 	return rx_count;
 }
@@ -228,13 +440,16 @@
 sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
 {
 	struct uart_port *port = &sirfport->port;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
 	struct circ_buf *xmit = &port->state->xmit;
 	unsigned int num_tx = 0;
 	while (!uart_circ_empty(xmit) &&
-		!(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
-					SIRFUART_FIFOFULL_MASK(port)) &&
+		!(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
+					ufifo_st->ff_full(port->line)) &&
 		count--) {
-		wr_regl(port, SIRFUART_TX_FIFO_DATA, xmit->buf[xmit->tail]);
+		wr_regl(port, ureg->sirfsoc_tx_fifo_data,
+				xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		port->icount.tx++;
 		num_tx++;
@@ -244,6 +459,166 @@
 	return num_tx;
 }
 
+static void sirfsoc_uart_tx_dma_complete_callback(void *param)
+{
+	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+	struct uart_port *port = &sirfport->port;
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned long flags;
+
+	xmit->tail = (xmit->tail + sirfport->transfer_size) &
+				(UART_XMIT_SIZE - 1);
+	port->icount.tx += sirfport->transfer_size;
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+	if (sirfport->tx_dma_addr)
+		dma_unmap_single(port->dev, sirfport->tx_dma_addr,
+				sirfport->transfer_size, DMA_TO_DEVICE);
+	spin_lock_irqsave(&sirfport->tx_lock, flags);
+	sirfport->tx_dma_state = TX_DMA_IDLE;
+	sirfsoc_uart_tx_with_dma(sirfport);
+	spin_unlock_irqrestore(&sirfport->tx_lock, flags);
+}
+
+static void sirfsoc_uart_insert_rx_buf_to_tty(
+		struct sirfsoc_uart_port *sirfport, int count)
+{
+	struct uart_port *port = &sirfport->port;
+	struct tty_port *tport = &port->state->port;
+	int inserted;
+
+	inserted = tty_insert_flip_string(tport,
+		sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
+	port->icount.rx += inserted;
+	tty_flip_buffer_push(tport);
+}
+
+static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
+{
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+
+	sirfport->rx_dma_items[index].xmit.tail =
+		sirfport->rx_dma_items[index].xmit.head = 0;
+	sirfport->rx_dma_items[index].desc =
+		dmaengine_prep_slave_single(sirfport->rx_dma_chan,
+		sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
+		DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+	if (!sirfport->rx_dma_items[index].desc) {
+		dev_err(port->dev, "DMA slave single fail\n");
+		return;
+	}
+	sirfport->rx_dma_items[index].desc->callback =
+		sirfsoc_uart_rx_dma_complete_callback;
+	sirfport->rx_dma_items[index].desc->callback_param = sirfport;
+	sirfport->rx_dma_items[index].cookie =
+		dmaengine_submit(sirfport->rx_dma_items[index].desc);
+	dma_async_issue_pending(sirfport->rx_dma_chan);
+}
+
+static void sirfsoc_rx_tmo_process_tl(unsigned long param)
+{
+	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+	struct uart_port *port = &sirfport->port;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+	struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
+	unsigned int count;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sirfport->rx_lock, flags);
+	while (sirfport->rx_completed != sirfport->rx_issued) {
+		sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
+					SIRFSOC_RX_DMA_BUF_SIZE);
+		sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++);
+		sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
+	}
+	count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
+		sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
+		SIRFSOC_RX_DMA_BUF_SIZE);
+	if (count > 0)
+		sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
+	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+			rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
+			SIRFUART_IO_MODE);
+	sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
+	spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+	if (sirfport->rx_io_count == 4) {
+		spin_lock_irqsave(&sirfport->rx_lock, flags);
+		sirfport->rx_io_count = 0;
+		wr_regl(port, ureg->sirfsoc_int_st_reg,
+				uint_st->sirfsoc_rx_done);
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) &
+				~(uint_en->sirfsoc_rx_done_en));
+		else
+			wr_regl(port, SIRFUART_INT_EN_CLR,
+					uint_en->sirfsoc_rx_done_en);
+		spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+
+		sirfsoc_uart_start_next_rx_dma(port);
+	} else {
+		spin_lock_irqsave(&sirfport->rx_lock, flags);
+		wr_regl(port, ureg->sirfsoc_int_st_reg,
+				uint_st->sirfsoc_rx_done);
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) |
+				(uint_en->sirfsoc_rx_done_en));
+		else
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+					uint_en->sirfsoc_rx_done_en);
+		spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+	}
+}
+
+static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
+{
+	struct uart_port *port = &sirfport->port;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+	struct dma_tx_state tx_state;
+	spin_lock(&sirfport->rx_lock);
+
+	dmaengine_tx_status(sirfport->rx_dma_chan,
+		sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
+	dmaengine_terminate_all(sirfport->rx_dma_chan);
+	sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
+		SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
+	if (!sirfport->is_marco)
+		wr_regl(port, ureg->sirfsoc_int_en_reg,
+			rd_regl(port, ureg->sirfsoc_int_en_reg) &
+			~(uint_en->sirfsoc_rx_timeout_en));
+	else
+		wr_regl(port, SIRFUART_INT_EN_CLR,
+				uint_en->sirfsoc_rx_timeout_en);
+	spin_unlock(&sirfport->rx_lock);
+	tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
+}
+
+static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
+{
+	struct uart_port *port = &sirfport->port;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+	struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
+
+	sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
+	if (sirfport->rx_io_count == 4) {
+		sirfport->rx_io_count = 0;
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) &
+				~(uint_en->sirfsoc_rx_done_en));
+		else
+			wr_regl(port, SIRFUART_INT_EN_CLR,
+					uint_en->sirfsoc_rx_done_en);
+		wr_regl(port, ureg->sirfsoc_int_st_reg,
+				uint_st->sirfsoc_rx_timeout);
+		sirfsoc_uart_start_next_rx_dma(port);
+	}
+}
+
 static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
 {
 	unsigned long intr_status;
@@ -251,79 +626,191 @@
 	unsigned long flag = TTY_NORMAL;
 	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)dev_id;
 	struct uart_port *port = &sirfport->port;
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
+	struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
 	struct uart_state *state = port->state;
 	struct circ_buf *xmit = &port->state->xmit;
 	spin_lock(&port->lock);
-	intr_status = rd_regl(port, SIRFUART_INT_STATUS);
-	wr_regl(port, SIRFUART_INT_STATUS, intr_status);
-	intr_status &= rd_regl(port, SIRFUART_INT_EN);
-	if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT))) {
-		if (intr_status & SIRFUART_RXD_BREAK) {
+	intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
+	wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
+	intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
+	if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
+		if (intr_status & uint_st->sirfsoc_rxd_brk) {
+			port->icount.brk++;
 			if (uart_handle_break(port))
 				goto recv_char;
-			uart_insert_char(port, intr_status,
-					SIRFUART_RX_OFLOW, 0, TTY_BREAK);
-			spin_unlock(&port->lock);
-			return IRQ_HANDLED;
 		}
-		if (intr_status & SIRFUART_RX_OFLOW)
+		if (intr_status & uint_st->sirfsoc_rx_oflow)
 			port->icount.overrun++;
-		if (intr_status & SIRFUART_FRM_ERR) {
+		if (intr_status & uint_st->sirfsoc_frm_err) {
 			port->icount.frame++;
 			flag = TTY_FRAME;
 		}
-		if (intr_status & SIRFUART_PARITY_ERR)
+		if (intr_status & uint_st->sirfsoc_parity_err)
 			flag = TTY_PARITY;
-		wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
-		wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
-		wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+		wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+		wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+		wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
 		intr_status &= port->read_status_mask;
 		uart_insert_char(port, intr_status,
-					SIRFUART_RX_OFLOW_INT, 0, flag);
+					uint_en->sirfsoc_rx_oflow_en, 0, flag);
+		tty_flip_buffer_push(&state->port);
 	}
 recv_char:
-	if (intr_status & SIRFUART_CTS_INT_EN) {
-		cts_status = !(rd_regl(port, SIRFUART_AFC_CTRL) &
-							SIRFUART_CTS_IN_STATUS);
-		if (cts_status != 0) {
-			uart_handle_cts_change(port, 1);
-		} else {
-			uart_handle_cts_change(port, 0);
-			wake_up_interruptible(&state->port.delta_msr_wait);
-		}
+	if ((sirfport->uart_reg->uart_type == SIRF_REAL_UART) &&
+			(intr_status & SIRFUART_CTS_INT_ST(uint_st)) &&
+			!sirfport->tx_dma_state) {
+		cts_status = rd_regl(port, ureg->sirfsoc_afc_ctrl) &
+					SIRFUART_AFC_CTS_STATUS;
+		if (cts_status != 0)
+			cts_status = 0;
+		else
+			cts_status = 1;
+		uart_handle_cts_change(port, cts_status);
+		wake_up_interruptible(&state->port.delta_msr_wait);
 	}
-	if (intr_status & SIRFUART_RX_IO_INT_EN)
-		sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
-	if (intr_status & SIRFUART_TX_INT_EN) {
-		if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-			spin_unlock(&port->lock);
-			return IRQ_HANDLED;
-		} else {
-			sirfsoc_uart_pio_tx_chars(sirfport,
+	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+		if (intr_status & uint_st->sirfsoc_rx_timeout)
+			sirfsoc_uart_handle_rx_tmo(sirfport);
+		if (intr_status & uint_st->sirfsoc_rx_done)
+			sirfsoc_uart_handle_rx_done(sirfport);
+	} else {
+		if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
+			sirfsoc_uart_pio_rx_chars(port,
+					SIRFSOC_UART_IO_RX_MAX_CNT);
+	}
+	if (intr_status & uint_st->sirfsoc_txfifo_empty) {
+		if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+			sirfsoc_uart_tx_with_dma(sirfport);
+		else {
+			if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+				spin_unlock(&port->lock);
+				return IRQ_HANDLED;
+			} else {
+				sirfsoc_uart_pio_tx_chars(sirfport,
 					SIRFSOC_UART_IO_TX_REASONABLE_CNT);
-			if ((uart_circ_empty(xmit)) &&
-				(rd_regl(port, SIRFUART_TX_FIFO_STATUS) &
-						SIRFUART_FIFOEMPTY_MASK(port)))
-				sirfsoc_uart_stop_tx(port);
+				if ((uart_circ_empty(xmit)) &&
+				(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
+				ufifo_st->ff_empty(port->line)))
+					sirfsoc_uart_stop_tx(port);
+			}
 		}
 	}
 	spin_unlock(&port->lock);
 	return IRQ_HANDLED;
 }
 
+static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
+{
+	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+	struct uart_port *port = &sirfport->port;
+	unsigned long flags;
+	spin_lock_irqsave(&sirfport->rx_lock, flags);
+	while (sirfport->rx_completed != sirfport->rx_issued) {
+		sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
+					SIRFSOC_RX_DMA_BUF_SIZE);
+		sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++);
+		sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
+	}
+	spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+}
+
+static void sirfsoc_uart_rx_dma_complete_callback(void *param)
+{
+	struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
+	spin_lock(&sirfport->rx_lock);
+	sirfport->rx_issued++;
+	sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
+	spin_unlock(&sirfport->rx_lock);
+	tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
+}
+
+/* submit rx dma task into dmaengine */
+static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
+{
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+	unsigned long flags;
+	int i;
+	spin_lock_irqsave(&sirfport->rx_lock, flags);
+	sirfport->rx_io_count = 0;
+	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+		rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
+		~SIRFUART_IO_MODE);
+	spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
+		sirfsoc_rx_submit_one_dma_desc(port, i);
+	sirfport->rx_completed = sirfport->rx_issued = 0;
+	spin_lock_irqsave(&sirfport->rx_lock, flags);
+	if (!sirfport->is_marco)
+		wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) |
+				SIRFUART_RX_DMA_INT_EN(port, uint_en));
+	else
+		wr_regl(port, ureg->sirfsoc_int_en_reg,
+			SIRFUART_RX_DMA_INT_EN(port, uint_en));
+	spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+}
+
 static void sirfsoc_uart_start_rx(struct uart_port *port)
 {
-	unsigned long regv;
-	regv = rd_regl(port, SIRFUART_INT_EN);
-	wr_regl(port, SIRFUART_INT_EN, regv | SIRFUART_RX_IO_INT_EN);
-	wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
-	wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
-	wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_START);
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
+
+	sirfport->rx_io_count = 0;
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
+	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+		sirfsoc_uart_start_next_rx_dma(port);
+	else {
+		if (!sirfport->is_marco)
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				rd_regl(port, ureg->sirfsoc_int_en_reg) |
+				SIRFUART_RX_IO_INT_EN(port, uint_en));
+		else
+			wr_regl(port, ureg->sirfsoc_int_en_reg,
+				SIRFUART_RX_IO_INT_EN(port, uint_en));
+	}
 }
 
 static unsigned int
-sirfsoc_calc_sample_div(unsigned long baud_rate,
-			unsigned long ioclk_rate, unsigned long *setted_baud)
+sirfsoc_usp_calc_sample_div(unsigned long set_rate,
+		unsigned long ioclk_rate, unsigned long *sample_reg)
+{
+	unsigned long min_delta = ~0UL;
+	unsigned short sample_div;
+	unsigned long ioclk_div = 0;
+	unsigned long temp_delta;
+
+	for (sample_div = SIRF_MIN_SAMPLE_DIV;
+			sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
+		temp_delta = ioclk_rate -
+		(ioclk_rate + (set_rate * sample_div) / 2)
+		/ (set_rate * sample_div) * set_rate * sample_div;
+
+		temp_delta = (temp_delta > 0) ? temp_delta : -temp_delta;
+		if (temp_delta < min_delta) {
+			ioclk_div = (2 * ioclk_rate /
+				(set_rate * sample_div) + 1) / 2 - 1;
+			if (ioclk_div > SIRF_IOCLK_DIV_MAX)
+				continue;
+			min_delta = temp_delta;
+			*sample_reg = sample_div;
+			if (!temp_delta)
+				break;
+		}
+	}
+	return ioclk_div;
+}
+
+static unsigned int
+sirfsoc_uart_calc_sample_div(unsigned long baud_rate,
+			unsigned long ioclk_rate, unsigned long *set_baud)
 {
 	unsigned long min_delta = ~0UL;
 	unsigned short sample_div;
@@ -346,7 +833,7 @@
 			regv = regv & (~SIRF_SAMPLE_DIV_MASK);
 			regv = regv | (sample_div << SIRF_SAMPLE_DIV_SHIFT);
 			min_delta = temp_delta;
-			*setted_baud = baud_tmp;
+			*set_baud = baud_tmp;
 		}
 	}
 	return regv;
@@ -357,63 +844,93 @@
 				       struct ktermios *old)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
 	unsigned long	config_reg = 0;
 	unsigned long	baud_rate;
-	unsigned long	setted_baud;
+	unsigned long	set_baud;
 	unsigned long	flags;
 	unsigned long	ic;
 	unsigned int	clk_div_reg = 0;
-	unsigned long	temp_reg_val;
+	unsigned long	txfifo_op_reg, ioclk_rate;
 	unsigned long	rx_time_out;
 	int		threshold_div;
-	int		temp;
+	u32		data_bit_len, stop_bit_len, len_val;
+	unsigned long	sample_div_reg = 0xf;
+	ioclk_rate	= port->uartclk;
 
 	switch (termios->c_cflag & CSIZE) {
 	default:
 	case CS8:
+		data_bit_len = 8;
 		config_reg |= SIRFUART_DATA_BIT_LEN_8;
 		break;
 	case CS7:
+		data_bit_len = 7;
 		config_reg |= SIRFUART_DATA_BIT_LEN_7;
 		break;
 	case CS6:
+		data_bit_len = 6;
 		config_reg |= SIRFUART_DATA_BIT_LEN_6;
 		break;
 	case CS5:
+		data_bit_len = 5;
 		config_reg |= SIRFUART_DATA_BIT_LEN_5;
 		break;
 	}
-	if (termios->c_cflag & CSTOPB)
+	if (termios->c_cflag & CSTOPB) {
 		config_reg |= SIRFUART_STOP_BIT_LEN_2;
-	baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
+		stop_bit_len = 2;
+	} else
+		stop_bit_len = 1;
+
 	spin_lock_irqsave(&port->lock, flags);
-	port->read_status_mask = SIRFUART_RX_OFLOW_INT;
+	port->read_status_mask = uint_en->sirfsoc_rx_oflow_en;
 	port->ignore_status_mask = 0;
-	/* read flags */
-	if (termios->c_iflag & INPCK)
-		port->read_status_mask |=
-			SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		if (termios->c_iflag & INPCK)
+			port->read_status_mask |= uint_en->sirfsoc_frm_err_en |
+				uint_en->sirfsoc_parity_err_en;
+	} else {
+		if (termios->c_iflag & INPCK)
+			port->read_status_mask |= uint_en->sirfsoc_frm_err_en;
+	}
 	if (termios->c_iflag & (BRKINT | PARMRK))
-		port->read_status_mask |= SIRFUART_RXD_BREAK_INT;
-	/* ignore flags */
-	if (termios->c_iflag & IGNPAR)
+			port->read_status_mask |= uint_en->sirfsoc_rxd_brk_en;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |=
+				uint_en->sirfsoc_frm_err_en |
+				uint_en->sirfsoc_parity_err_en;
+		if (termios->c_cflag & PARENB) {
+			if (termios->c_cflag & CMSPAR) {
+				if (termios->c_cflag & PARODD)
+					config_reg |= SIRFUART_STICK_BIT_MARK;
+				else
+					config_reg |= SIRFUART_STICK_BIT_SPACE;
+			} else if (termios->c_cflag & PARODD) {
+				config_reg |= SIRFUART_STICK_BIT_ODD;
+			} else {
+				config_reg |= SIRFUART_STICK_BIT_EVEN;
+			}
+		}
+	} else {
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |=
+				uint_en->sirfsoc_frm_err_en;
+		if (termios->c_cflag & PARENB)
+			dev_warn(port->dev,
+					"USP-UART not support parity err\n");
+	}
+	if (termios->c_iflag & IGNBRK) {
 		port->ignore_status_mask |=
-			SIRFUART_FRM_ERR_INT | SIRFUART_PARITY_ERR_INT;
+			uint_en->sirfsoc_rxd_brk_en;
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |=
+				uint_en->sirfsoc_rx_oflow_en;
+	}
 	if ((termios->c_cflag & CREAD) == 0)
 		port->ignore_status_mask |= SIRFUART_DUMMY_READ;
-	/* enable parity if PARENB is set*/
-	if (termios->c_cflag & PARENB) {
-		if (termios->c_cflag & CMSPAR) {
-			if (termios->c_cflag & PARODD)
-				config_reg |= SIRFUART_STICK_BIT_MARK;
-			else
-				config_reg |= SIRFUART_STICK_BIT_SPACE;
-		} else if (termios->c_cflag & PARODD) {
-			config_reg |= SIRFUART_STICK_BIT_ODD;
-		} else {
-			config_reg |= SIRFUART_STICK_BIT_EVEN;
-		}
-	}
 	/* Hardware Flow Control Settings */
 	if (UART_ENABLE_MS(port, termios->c_cflag)) {
 		if (!sirfport->ms_enabled)
@@ -422,75 +939,184 @@
 		if (sirfport->ms_enabled)
 			sirfsoc_uart_disable_ms(port);
 	}
-
-	if (port->uartclk == 150000000) {
-		/* common rate: fast calculation */
+	baud_rate = uart_get_baud_rate(port, termios, old, 0, 4000000);
+	if (ioclk_rate == 150000000) {
 		for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
 			if (baud_rate == baudrate_to_regv[ic].baud_rate)
 				clk_div_reg = baudrate_to_regv[ic].reg_val;
 	}
-
-	setted_baud = baud_rate;
-	/* arbitary rate setting */
-	if (unlikely(clk_div_reg == 0))
-		clk_div_reg = sirfsoc_calc_sample_div(baud_rate, port->uartclk,
-								&setted_baud);
-	wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);
-
+	set_baud = baud_rate;
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		if (unlikely(clk_div_reg == 0))
+			clk_div_reg = sirfsoc_uart_calc_sample_div(baud_rate,
+					ioclk_rate, &set_baud);
+		wr_regl(port, ureg->sirfsoc_divisor, clk_div_reg);
+	} else {
+		clk_div_reg = sirfsoc_usp_calc_sample_div(baud_rate,
+				ioclk_rate, &sample_div_reg);
+		sample_div_reg--;
+		set_baud = ((ioclk_rate / (clk_div_reg+1) - 1) /
+				(sample_div_reg + 1));
+		/* setting usp mode 2 */
+		len_val = ((1 << SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET) |
+				(1 << SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET));
+		len_val |= ((clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK)
+				<< SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET);
+		wr_regl(port, ureg->sirfsoc_mode2, len_val);
+	}
 	if (tty_termios_baud_rate(termios))
-		tty_termios_encode_baud_rate(termios, setted_baud, setted_baud);
-
-	/* set receive timeout */
-	rx_time_out = SIRFSOC_UART_RX_TIMEOUT(baud_rate, 20000);
-	rx_time_out = (rx_time_out > 0xFFFF) ? 0xFFFF : rx_time_out;
-	config_reg |= SIRFUART_RECV_TIMEOUT(rx_time_out);
-	temp_reg_val = rd_regl(port, SIRFUART_TX_FIFO_OP);
-	wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
-	wr_regl(port, SIRFUART_TX_FIFO_OP,
-				temp_reg_val & ~SIRFUART_TX_FIFO_START);
-	wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, SIRFUART_TX_MODE_IO);
-	wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, SIRFUART_RX_MODE_IO);
-	wr_regl(port, SIRFUART_LINE_CTRL, config_reg);
-
+		tty_termios_encode_baud_rate(termios, set_baud, set_baud);
+	/* set receive timeout && data bits len */
+	rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000);
+	rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out);
+	txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op);
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP);
+	wr_regl(port, ureg->sirfsoc_tx_fifo_op,
+			(txfifo_op_reg & ~SIRFUART_FIFO_START));
+	if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
+		config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
+		wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
+	} else {
+		/*tx frame ctrl*/
+		len_val = (data_bit_len - 1) << SIRFSOC_USP_TX_DATA_LEN_OFFSET;
+		len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
+				SIRFSOC_USP_TX_FRAME_LEN_OFFSET;
+		len_val |= ((data_bit_len - 1) <<
+				SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET);
+		len_val |= (((clk_div_reg & 0xc00) >> 10) <<
+				SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET);
+		wr_regl(port, ureg->sirfsoc_tx_frame_ctrl, len_val);
+		/*rx frame ctrl*/
+		len_val = (data_bit_len - 1) << SIRFSOC_USP_RX_DATA_LEN_OFFSET;
+		len_val |= (data_bit_len + 1 + stop_bit_len - 1) <<
+				SIRFSOC_USP_RX_FRAME_LEN_OFFSET;
+		len_val |= (data_bit_len - 1) <<
+				SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET;
+		len_val |= (((clk_div_reg & 0xf000) >> 12) <<
+				SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET);
+		wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
+		/*async param*/
+		wr_regl(port, ureg->sirfsoc_async_param_reg,
+			(SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
+			(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
+			SIRFSOC_USP_ASYNC_DIV2_OFFSET);
+	}
+	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no))
+		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_DMA_MODE);
+	else
+		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE);
+	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
+	else
+		wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
 	/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
-	if (baud_rate < 1000000)
+	if (set_baud < 1000000)
 		threshold_div = 1;
 	else
 		threshold_div = 2;
-	temp = port->line == 1 ? 16 : 64;
-	wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp / threshold_div);
-	wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp / threshold_div);
-	temp_reg_val |= SIRFUART_TX_FIFO_START;
-	wr_regl(port, SIRFUART_TX_FIFO_OP, temp_reg_val);
-	uart_update_timeout(port, termios->c_cflag, baud_rate);
+	wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl,
+				SIRFUART_FIFO_THD(port) / threshold_div);
+	wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl,
+				SIRFUART_FIFO_THD(port) / threshold_div);
+	txfifo_op_reg |= SIRFUART_FIFO_START;
+	wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg);
+	uart_update_timeout(port, termios->c_cflag, set_baud);
 	sirfsoc_uart_start_rx(port);
-	wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_TX_EN | SIRFUART_RX_EN);
+	wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN);
 	spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void startup_uart_controller(struct uart_port *port)
+static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port)
 {
-	unsigned long temp_regv;
-	int temp;
-	temp_regv = rd_regl(port, SIRFUART_TX_DMA_IO_CTRL);
-	wr_regl(port, SIRFUART_TX_DMA_IO_CTRL, temp_regv | SIRFUART_TX_MODE_IO);
-	temp_regv = rd_regl(port, SIRFUART_RX_DMA_IO_CTRL);
-	wr_regl(port, SIRFUART_RX_DMA_IO_CTRL, temp_regv | SIRFUART_RX_MODE_IO);
-	wr_regl(port, SIRFUART_TX_DMA_IO_LEN, 0);
-	wr_regl(port, SIRFUART_RX_DMA_IO_LEN, 0);
-	wr_regl(port, SIRFUART_TX_RX_EN, SIRFUART_RX_EN | SIRFUART_TX_EN);
-	wr_regl(port, SIRFUART_TX_FIFO_OP, SIRFUART_TX_FIFO_RESET);
-	wr_regl(port, SIRFUART_TX_FIFO_OP, 0);
-	wr_regl(port, SIRFUART_RX_FIFO_OP, SIRFUART_RX_FIFO_RESET);
-	wr_regl(port, SIRFUART_RX_FIFO_OP, 0);
-	temp = port->line == 1 ? 16 : 64;
-	wr_regl(port, SIRFUART_TX_FIFO_CTRL, temp);
-	wr_regl(port, SIRFUART_RX_FIFO_CTRL, temp);
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	dma_cap_mask_t dma_mask;
+	struct dma_slave_config tx_slv_cfg = {
+		.dst_maxburst = 2,
+	};
+
+	dma_cap_zero(dma_mask);
+	dma_cap_set(DMA_SLAVE, dma_mask);
+	sirfport->tx_dma_chan = dma_request_channel(dma_mask,
+		(dma_filter_fn)sirfsoc_dma_filter_id,
+		(void *)sirfport->tx_dma_no);
+	if (!sirfport->tx_dma_chan) {
+		dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
+					sirfport->tx_dma_no);
+		return  -EPROBE_DEFER;
+	}
+	dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
+
+	return 0;
+}
+
+static unsigned int sirfsoc_uart_init_rx_dma(struct uart_port *port)
+{
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	dma_cap_mask_t dma_mask;
+	int ret;
+	int i, j;
+	struct dma_slave_config slv_cfg = {
+		.src_maxburst = 2,
+	};
+
+	dma_cap_zero(dma_mask);
+	dma_cap_set(DMA_SLAVE, dma_mask);
+	sirfport->rx_dma_chan = dma_request_channel(dma_mask,
+					(dma_filter_fn)sirfsoc_dma_filter_id,
+					(void *)sirfport->rx_dma_no);
+	if (!sirfport->rx_dma_chan) {
+		dev_err(port->dev, "Uart Request Dma Channel Fail %d\n",
+				sirfport->rx_dma_no);
+		ret = -EPROBE_DEFER;
+		goto request_err;
+	}
+	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
+		sirfport->rx_dma_items[i].xmit.buf =
+			dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+			&sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
+		if (!sirfport->rx_dma_items[i].xmit.buf) {
+			dev_err(port->dev, "Uart alloc bufa failed\n");
+			ret = -ENOMEM;
+			goto alloc_coherent_err;
+		}
+		sirfport->rx_dma_items[i].xmit.head =
+			sirfport->rx_dma_items[i].xmit.tail = 0;
+	}
+	dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
+
+	return 0;
+alloc_coherent_err:
+	for (j = 0; j < i; j++)
+		dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+				sirfport->rx_dma_items[j].xmit.buf,
+				sirfport->rx_dma_items[j].dma_addr);
+	dma_release_channel(sirfport->rx_dma_chan);
+request_err:
+	return ret;
+}
+
+static void sirfsoc_uart_uninit_tx_dma(struct sirfsoc_uart_port *sirfport)
+{
+	dmaengine_terminate_all(sirfport->tx_dma_chan);
+	dma_release_channel(sirfport->tx_dma_chan);
+}
+
+static void sirfsoc_uart_uninit_rx_dma(struct sirfsoc_uart_port *sirfport)
+{
+	int i;
+	struct uart_port *port = &sirfport->port;
+	dmaengine_terminate_all(sirfport->rx_dma_chan);
+	dma_release_channel(sirfport->rx_dma_chan);
+	for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
+		dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
+				sirfport->rx_dma_items[i].xmit.buf,
+				sirfport->rx_dma_items[i].dma_addr);
 }
 
 static int sirfsoc_uart_startup(struct uart_port *port)
 {
 	struct sirfsoc_uart_port *sirfport	= to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
 	unsigned int index			= port->line;
 	int ret;
 	set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN);
@@ -504,8 +1130,64 @@
 							index, port->irq);
 		goto irq_err;
 	}
-	startup_uart_controller(port);
+
+	/* initial hardware settings */
+	wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
+		rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
+		SIRFUART_IO_MODE);
+	wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
+		rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
+		SIRFUART_IO_MODE);
+	wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
+	wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
+	wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
+	if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+		wr_regl(port, ureg->sirfsoc_mode1,
+			SIRFSOC_USP_ENDIAN_CTRL_LSBF |
+			SIRFSOC_USP_EN);
+	wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
+	wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
+	wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
+	wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
+	wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port));
+
+	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no)) {
+		ret = sirfsoc_uart_init_rx_dma(port);
+		if (ret)
+			goto init_rx_err;
+		wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk,
+				SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) |
+				SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) |
+				SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b));
+	}
+	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+		sirfsoc_uart_init_tx_dma(port);
+		sirfport->tx_dma_state = TX_DMA_IDLE;
+		wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk,
+				SIRFUART_TX_FIFO_CHK_SC(port->line, 0x1b) |
+				SIRFUART_TX_FIFO_CHK_LC(port->line, 0xe) |
+				SIRFUART_TX_FIFO_CHK_HC(port->line, 0x4));
+	}
+	sirfport->ms_enabled = false;
+	if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
+		sirfport->hw_flow_ctrl) {
+		set_irq_flags(gpio_to_irq(sirfport->cts_gpio),
+			IRQF_VALID | IRQF_NOAUTOEN);
+		ret = request_irq(gpio_to_irq(sirfport->cts_gpio),
+			sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING |
+			IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport);
+		if (ret != 0) {
+			dev_err(port->dev, "UART-USP:request gpio irq fail\n");
+			goto init_rx_err;
+		}
+	}
+
 	enable_irq(port->irq);
+
+	return 0;
+init_rx_err:
+	free_irq(port->irq, sirfport);
 irq_err:
 	return ret;
 }
@@ -513,11 +1195,25 @@
 static void sirfsoc_uart_shutdown(struct uart_port *port)
 {
 	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
-	wr_regl(port, SIRFUART_INT_EN, 0);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	if (!sirfport->is_marco)
+		wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
+	else
+		wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
+
 	free_irq(port->irq, sirfport);
-	if (sirfport->ms_enabled) {
+	if (sirfport->ms_enabled)
 		sirfsoc_uart_disable_ms(port);
-		sirfport->ms_enabled = 0;
+	if (sirfport->uart_reg->uart_type == SIRF_USP_UART &&
+			sirfport->hw_flow_ctrl) {
+		gpio_set_value(sirfport->rts_gpio, 1);
+		free_irq(gpio_to_irq(sirfport->cts_gpio), sirfport);
+	}
+	if (IS_DMA_CHAN_VALID(sirfport->rx_dma_no))
+		sirfsoc_uart_uninit_rx_dma(sirfport);
+	if (IS_DMA_CHAN_VALID(sirfport->tx_dma_no)) {
+		sirfsoc_uart_uninit_tx_dma(sirfport);
+		sirfport->tx_dma_state = TX_DMA_IDLE;
 	}
 }
 
@@ -528,9 +1224,11 @@
 
 static int sirfsoc_uart_request_port(struct uart_port *port)
 {
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_uart_param *uart_param = &sirfport->uart_reg->uart_param;
 	void *ret;
 	ret = request_mem_region(port->mapbase,
-				SIRFUART_MAP_SIZE, SIRFUART_PORT_NAME);
+		SIRFUART_MAP_SIZE, uart_param->port_name);
 	return ret ? 0 : -EBUSY;
 }
 
@@ -566,32 +1264,45 @@
 };
 
 #ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
-static int __init sirfsoc_uart_console_setup(struct console *co, char *options)
+static int __init
+sirfsoc_uart_console_setup(struct console *co, char *options)
 {
 	unsigned int baud = 115200;
 	unsigned int bits = 8;
 	unsigned int parity = 'n';
 	unsigned int flow = 'n';
 	struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
-
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
 	if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
 		return -EINVAL;
 
 	if (!port->mapbase)
 		return -ENODEV;
 
+	/* enable usp in mode1 register */
+	if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
+		wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
+				SIRFSOC_USP_ENDIAN_CTRL_LSBF);
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	port->cons = co;
+
+	/* default console tx/rx transfer using io mode */
+	sirfport->rx_dma_no = UNVALID_DMA_CHAN;
+	sirfport->tx_dma_no = UNVALID_DMA_CHAN;
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
 static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
 {
+	struct sirfsoc_uart_port *sirfport = to_sirfport(port);
+	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
+	struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
 	while (rd_regl(port,
-		SIRFUART_TX_FIFO_STATUS) & SIRFUART_FIFOFULL_MASK(port))
+		ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
 		cpu_relax();
-	wr_regb(port, SIRFUART_TX_FIFO_DATA, ch);
+	wr_regb(port, ureg->sirfsoc_tx_fifo_data, ch);
 }
 
 static void sirfsoc_uart_console_write(struct console *co, const char *s,
@@ -633,27 +1344,99 @@
 #endif
 };
 
-int sirfsoc_uart_probe(struct platform_device *pdev)
+static struct of_device_id sirfsoc_uart_ids[] = {
+	{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
+	{ .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
+	{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
+
+static int sirfsoc_uart_probe(struct platform_device *pdev)
 {
 	struct sirfsoc_uart_port *sirfport;
 	struct uart_port *port;
 	struct resource *res;
 	int ret;
+	const struct of_device_id *match;
 
+	match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
 	if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
 		dev_err(&pdev->dev,
 			"Unable to find cell-index in uart node.\n");
 		ret = -EFAULT;
 		goto err;
 	}
-
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
+		pdev->id += ((struct sirfsoc_uart_register *)
+				match->data)->uart_param.register_uart_nr;
 	sirfport = &sirfsoc_uart_ports[pdev->id];
 	port = &sirfport->port;
 	port->dev = &pdev->dev;
 	port->private_data = sirfport;
+	sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
 
-	if (of_find_property(pdev->dev.of_node, "hw_flow_ctrl", NULL))
-		sirfport->hw_flow_ctrl = 1;
+	sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
+		"sirf,uart-has-rtscts");
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) {
+		sirfport->uart_reg->uart_type = SIRF_REAL_UART;
+		if (of_property_read_u32(pdev->dev.of_node,
+				"sirf,uart-dma-rx-channel",
+				&sirfport->rx_dma_no))
+			sirfport->rx_dma_no = UNVALID_DMA_CHAN;
+		if (of_property_read_u32(pdev->dev.of_node,
+				"sirf,uart-dma-tx-channel",
+				&sirfport->tx_dma_no))
+			sirfport->tx_dma_no = UNVALID_DMA_CHAN;
+	}
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
+		sirfport->uart_reg->uart_type =	SIRF_USP_UART;
+		if (of_property_read_u32(pdev->dev.of_node,
+				"sirf,usp-dma-rx-channel",
+				&sirfport->rx_dma_no))
+			sirfport->rx_dma_no = UNVALID_DMA_CHAN;
+		if (of_property_read_u32(pdev->dev.of_node,
+				"sirf,usp-dma-tx-channel",
+				&sirfport->tx_dma_no))
+			sirfport->tx_dma_no = UNVALID_DMA_CHAN;
+		if (!sirfport->hw_flow_ctrl)
+			goto usp_no_flow_control;
+		if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
+			sirfport->cts_gpio = of_get_named_gpio(
+					pdev->dev.of_node, "cts-gpios", 0);
+		else
+			sirfport->cts_gpio = -1;
+		if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL))
+			sirfport->rts_gpio = of_get_named_gpio(
+					pdev->dev.of_node, "rts-gpios", 0);
+		else
+			sirfport->rts_gpio = -1;
+
+		if ((!gpio_is_valid(sirfport->cts_gpio) ||
+			 !gpio_is_valid(sirfport->rts_gpio))) {
+			ret = -EINVAL;
+			dev_err(&pdev->dev,
+				"Usp flow control must have cts and rts gpio");
+			goto err;
+		}
+		ret = devm_gpio_request(&pdev->dev, sirfport->cts_gpio,
+				"usp-cts-gpio");
+		if (ret) {
+			dev_err(&pdev->dev, "Unable request cts gpio");
+			goto err;
+		}
+		gpio_direction_input(sirfport->cts_gpio);
+		ret = devm_gpio_request(&pdev->dev, sirfport->rts_gpio,
+				"usp-rts-gpio");
+		if (ret) {
+			dev_err(&pdev->dev, "Unable request rts gpio");
+			goto err;
+		}
+		gpio_direction_output(sirfport->rts_gpio, 1);
+	}
+usp_no_flow_control:
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
+		sirfport->is_marco = true;
 
 	if (of_property_read_u32(pdev->dev.of_node,
 			"fifosize",
@@ -670,6 +1453,12 @@
 		ret = -EFAULT;
 		goto err;
 	}
+	spin_lock_init(&sirfport->rx_lock);
+	spin_lock_init(&sirfport->tx_lock);
+	tasklet_init(&sirfport->rx_dma_complete_tasklet,
+			sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
+	tasklet_init(&sirfport->rx_tmo_process_tasklet,
+			sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport);
 	port->mapbase = res->start;
 	port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
 	if (!port->membase) {
@@ -685,18 +1474,10 @@
 	}
 	port->irq = res->start;
 
-	if (sirfport->hw_flow_ctrl) {
-		sirfport->p = pinctrl_get_select_default(&pdev->dev);
-		if (IS_ERR(sirfport->p)) {
-			ret = PTR_ERR(sirfport->p);
-			goto err;
-		}
-	}
-
 	sirfport->clk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(sirfport->clk)) {
 		ret = PTR_ERR(sirfport->clk);
-		goto clk_err;
+		goto err;
 	}
 	clk_prepare_enable(sirfport->clk);
 	port->uartclk = clk_get_rate(sirfport->clk);
@@ -716,10 +1497,6 @@
 port_err:
 	clk_disable_unprepare(sirfport->clk);
 	clk_put(sirfport->clk);
-clk_err:
-	platform_set_drvdata(pdev, NULL);
-	if (sirfport->hw_flow_ctrl)
-		pinctrl_put(sirfport->p);
 err:
 	return ret;
 }
@@ -728,9 +1505,6 @@
 {
 	struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
 	struct uart_port *port = &sirfport->port;
-	platform_set_drvdata(pdev, NULL);
-	if (sirfport->hw_flow_ctrl)
-		pinctrl_put(sirfport->p);
 	clk_disable_unprepare(sirfport->clk);
 	clk_put(sirfport->clk);
 	uart_remove_one_port(&sirfsoc_uart_drv, port);
@@ -754,13 +1528,6 @@
 	return 0;
 }
 
-static struct of_device_id sirfsoc_uart_ids[] = {
-	{ .compatible = "sirf,prima2-uart", },
-	{ .compatible = "sirf,marco-uart", },
-	{}
-};
-MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
-
 static struct platform_driver sirfsoc_uart_driver = {
 	.probe		= sirfsoc_uart_probe,
 	.remove		= sirfsoc_uart_remove,
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 85328ba..fb8d0a0 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -6,31 +6,260 @@
  * Licensed under GPLv2 or later.
  */
 #include <linux/bitops.h>
+struct sirfsoc_uart_param {
+	const char *uart_name;
+	const char *port_name;
+	u32 uart_nr;
+	u32 register_uart_nr;
+};
 
-/* UART Register Offset Define */
-#define SIRFUART_LINE_CTRL			0x0040
-#define SIRFUART_TX_RX_EN			0x004c
-#define SIRFUART_DIVISOR			0x0050
-#define SIRFUART_INT_EN				0x0054
-#define SIRFUART_INT_STATUS			0x0058
-#define SIRFUART_TX_DMA_IO_CTRL			0x0100
-#define SIRFUART_TX_DMA_IO_LEN			0x0104
-#define SIRFUART_TX_FIFO_CTRL			0x0108
-#define SIRFUART_TX_FIFO_LEVEL_CHK		0x010C
-#define SIRFUART_TX_FIFO_OP			0x0110
-#define SIRFUART_TX_FIFO_STATUS			0x0114
-#define SIRFUART_TX_FIFO_DATA			0x0118
-#define SIRFUART_RX_DMA_IO_CTRL			0x0120
-#define SIRFUART_RX_DMA_IO_LEN			0x0124
-#define SIRFUART_RX_FIFO_CTRL			0x0128
-#define SIRFUART_RX_FIFO_LEVEL_CHK		0x012C
-#define SIRFUART_RX_FIFO_OP			0x0130
-#define SIRFUART_RX_FIFO_STATUS			0x0134
-#define SIRFUART_RX_FIFO_DATA			0x0138
-#define SIRFUART_AFC_CTRL			0x0140
-#define SIRFUART_SWH_DMA_IO			0x0148
+struct sirfsoc_register {
+	/* hardware uart specific */
+	u32 sirfsoc_line_ctrl;
+	u32 sirfsoc_divisor;
+	/* uart - usp common */
+	u32 sirfsoc_tx_rx_en;
+	u32 sirfsoc_int_en_reg;
+	u32 sirfsoc_int_st_reg;
+	u32 sirfsoc_tx_dma_io_ctrl;
+	u32 sirfsoc_tx_dma_io_len;
+	u32 sirfsoc_tx_fifo_ctrl;
+	u32 sirfsoc_tx_fifo_level_chk;
+	u32 sirfsoc_tx_fifo_op;
+	u32 sirfsoc_tx_fifo_status;
+	u32 sirfsoc_tx_fifo_data;
+	u32 sirfsoc_rx_dma_io_ctrl;
+	u32 sirfsoc_rx_dma_io_len;
+	u32 sirfsoc_rx_fifo_ctrl;
+	u32 sirfsoc_rx_fifo_level_chk;
+	u32 sirfsoc_rx_fifo_op;
+	u32 sirfsoc_rx_fifo_status;
+	u32 sirfsoc_rx_fifo_data;
+	u32 sirfsoc_afc_ctrl;
+	u32 sirfsoc_swh_dma_io;
+	/* hardware usp specific */
+	u32 sirfsoc_mode1;
+	u32 sirfsoc_mode2;
+	u32 sirfsoc_tx_frame_ctrl;
+	u32 sirfsoc_rx_frame_ctrl;
+	u32 sirfsoc_async_param_reg;
+};
 
-/* UART Line Control Register */
+typedef u32 (*fifo_full_mask)(int line);
+typedef u32 (*fifo_empty_mask)(int line);
+
+struct sirfsoc_fifo_status {
+	fifo_full_mask ff_full;
+	fifo_empty_mask ff_empty;
+};
+
+struct sirfsoc_int_en {
+	u32 sirfsoc_rx_done_en;
+	u32 sirfsoc_tx_done_en;
+	u32 sirfsoc_rx_oflow_en;
+	u32 sirfsoc_tx_allout_en;
+	u32 sirfsoc_rx_io_dma_en;
+	u32 sirfsoc_tx_io_dma_en;
+	u32 sirfsoc_rxfifo_full_en;
+	u32 sirfsoc_txfifo_empty_en;
+	u32 sirfsoc_rxfifo_thd_en;
+	u32 sirfsoc_txfifo_thd_en;
+	u32 sirfsoc_frm_err_en;
+	u32 sirfsoc_rxd_brk_en;
+	u32 sirfsoc_rx_timeout_en;
+	u32 sirfsoc_parity_err_en;
+	u32 sirfsoc_cts_en;
+	u32 sirfsoc_rts_en;
+};
+
+struct sirfsoc_int_status {
+	u32 sirfsoc_rx_done;
+	u32 sirfsoc_tx_done;
+	u32 sirfsoc_rx_oflow;
+	u32 sirfsoc_tx_allout;
+	u32 sirfsoc_rx_io_dma;
+	u32 sirfsoc_tx_io_dma;
+	u32 sirfsoc_rxfifo_full;
+	u32 sirfsoc_txfifo_empty;
+	u32 sirfsoc_rxfifo_thd;
+	u32 sirfsoc_txfifo_thd;
+	u32 sirfsoc_frm_err;
+	u32 sirfsoc_rxd_brk;
+	u32 sirfsoc_rx_timeout;
+	u32 sirfsoc_parity_err;
+	u32 sirfsoc_cts;
+	u32 sirfsoc_rts;
+};
+
+enum sirfsoc_uart_type {
+	SIRF_REAL_UART,
+	SIRF_USP_UART,
+};
+
+struct sirfsoc_uart_register {
+	struct sirfsoc_register uart_reg;
+	struct sirfsoc_int_en uart_int_en;
+	struct sirfsoc_int_status uart_int_st;
+	struct sirfsoc_fifo_status fifo_status;
+	struct sirfsoc_uart_param uart_param;
+	enum sirfsoc_uart_type uart_type;
+};
+
+u32 usp_ff_full(int line)
+{
+	return 0x80;
+}
+u32 usp_ff_empty(int line)
+{
+	return 0x100;
+}
+u32 uart_ff_full(int line)
+{
+	return (line == 1) ? (0x20) : (0x80);
+}
+u32 uart_ff_empty(int line)
+{
+	return (line == 1) ? (0x40) : (0x100);
+}
+struct sirfsoc_uart_register sirfsoc_usp = {
+	.uart_reg = {
+		.sirfsoc_mode1		= 0x0000,
+		.sirfsoc_mode2		= 0x0004,
+		.sirfsoc_tx_frame_ctrl	= 0x0008,
+		.sirfsoc_rx_frame_ctrl	= 0x000c,
+		.sirfsoc_tx_rx_en	= 0x0010,
+		.sirfsoc_int_en_reg	= 0x0014,
+		.sirfsoc_int_st_reg	= 0x0018,
+		.sirfsoc_async_param_reg = 0x0024,
+		.sirfsoc_tx_dma_io_ctrl	= 0x0100,
+		.sirfsoc_tx_dma_io_len	= 0x0104,
+		.sirfsoc_tx_fifo_ctrl	= 0x0108,
+		.sirfsoc_tx_fifo_level_chk = 0x010c,
+		.sirfsoc_tx_fifo_op	= 0x0110,
+		.sirfsoc_tx_fifo_status	= 0x0114,
+		.sirfsoc_tx_fifo_data	= 0x0118,
+		.sirfsoc_rx_dma_io_ctrl	= 0x0120,
+		.sirfsoc_rx_dma_io_len	= 0x0124,
+		.sirfsoc_rx_fifo_ctrl	= 0x0128,
+		.sirfsoc_rx_fifo_level_chk = 0x012c,
+		.sirfsoc_rx_fifo_op	= 0x0130,
+		.sirfsoc_rx_fifo_status	= 0x0134,
+		.sirfsoc_rx_fifo_data	= 0x0138,
+	},
+	.uart_int_en = {
+		.sirfsoc_rx_done_en	= BIT(0),
+		.sirfsoc_tx_done_en	= BIT(1),
+		.sirfsoc_rx_oflow_en	= BIT(2),
+		.sirfsoc_tx_allout_en	= BIT(3),
+		.sirfsoc_rx_io_dma_en	= BIT(4),
+		.sirfsoc_tx_io_dma_en	= BIT(5),
+		.sirfsoc_rxfifo_full_en	= BIT(6),
+		.sirfsoc_txfifo_empty_en = BIT(7),
+		.sirfsoc_rxfifo_thd_en	= BIT(8),
+		.sirfsoc_txfifo_thd_en	= BIT(9),
+		.sirfsoc_frm_err_en	= BIT(10),
+		.sirfsoc_rx_timeout_en	= BIT(11),
+		.sirfsoc_rxd_brk_en	= BIT(15),
+	},
+	.uart_int_st = {
+		.sirfsoc_rx_done	= BIT(0),
+		.sirfsoc_tx_done	= BIT(1),
+		.sirfsoc_rx_oflow	= BIT(2),
+		.sirfsoc_tx_allout	= BIT(3),
+		.sirfsoc_rx_io_dma	= BIT(4),
+		.sirfsoc_tx_io_dma	= BIT(5),
+		.sirfsoc_rxfifo_full	= BIT(6),
+		.sirfsoc_txfifo_empty	= BIT(7),
+		.sirfsoc_rxfifo_thd	= BIT(8),
+		.sirfsoc_txfifo_thd	= BIT(9),
+		.sirfsoc_frm_err	= BIT(10),
+		.sirfsoc_rx_timeout	= BIT(11),
+		.sirfsoc_rxd_brk	= BIT(15),
+	},
+	.fifo_status = {
+		.ff_full		= usp_ff_full,
+		.ff_empty		= usp_ff_empty,
+	},
+	.uart_param = {
+		.uart_name = "ttySiRF",
+		.port_name = "sirfsoc-uart",
+		.uart_nr = 2,
+		.register_uart_nr = 3,
+	},
+};
+
+struct sirfsoc_uart_register sirfsoc_uart = {
+	.uart_reg = {
+		.sirfsoc_line_ctrl	= 0x0040,
+		.sirfsoc_tx_rx_en	= 0x004c,
+		.sirfsoc_divisor	= 0x0050,
+		.sirfsoc_int_en_reg	= 0x0054,
+		.sirfsoc_int_st_reg	= 0x0058,
+		.sirfsoc_tx_dma_io_ctrl	= 0x0100,
+		.sirfsoc_tx_dma_io_len	= 0x0104,
+		.sirfsoc_tx_fifo_ctrl	= 0x0108,
+		.sirfsoc_tx_fifo_level_chk = 0x010c,
+		.sirfsoc_tx_fifo_op	= 0x0110,
+		.sirfsoc_tx_fifo_status	= 0x0114,
+		.sirfsoc_tx_fifo_data	= 0x0118,
+		.sirfsoc_rx_dma_io_ctrl	= 0x0120,
+		.sirfsoc_rx_dma_io_len	= 0x0124,
+		.sirfsoc_rx_fifo_ctrl	= 0x0128,
+		.sirfsoc_rx_fifo_level_chk = 0x012c,
+		.sirfsoc_rx_fifo_op	= 0x0130,
+		.sirfsoc_rx_fifo_status	= 0x0134,
+		.sirfsoc_rx_fifo_data	= 0x0138,
+		.sirfsoc_afc_ctrl	= 0x0140,
+		.sirfsoc_swh_dma_io	= 0x0148,
+	},
+	.uart_int_en = {
+		.sirfsoc_rx_done_en	= BIT(0),
+		.sirfsoc_tx_done_en	= BIT(1),
+		.sirfsoc_rx_oflow_en	= BIT(2),
+		.sirfsoc_tx_allout_en	= BIT(3),
+		.sirfsoc_rx_io_dma_en	= BIT(4),
+		.sirfsoc_tx_io_dma_en	= BIT(5),
+		.sirfsoc_rxfifo_full_en	= BIT(6),
+		.sirfsoc_txfifo_empty_en = BIT(7),
+		.sirfsoc_rxfifo_thd_en	= BIT(8),
+		.sirfsoc_txfifo_thd_en	= BIT(9),
+		.sirfsoc_frm_err_en	= BIT(10),
+		.sirfsoc_rxd_brk_en	= BIT(11),
+		.sirfsoc_rx_timeout_en	= BIT(12),
+		.sirfsoc_parity_err_en	= BIT(13),
+		.sirfsoc_cts_en		= BIT(14),
+		.sirfsoc_rts_en		= BIT(15),
+	},
+	.uart_int_st = {
+		.sirfsoc_rx_done	= BIT(0),
+		.sirfsoc_tx_done	= BIT(1),
+		.sirfsoc_rx_oflow	= BIT(2),
+		.sirfsoc_tx_allout	= BIT(3),
+		.sirfsoc_rx_io_dma	= BIT(4),
+		.sirfsoc_tx_io_dma	= BIT(5),
+		.sirfsoc_rxfifo_full	= BIT(6),
+		.sirfsoc_txfifo_empty	= BIT(7),
+		.sirfsoc_rxfifo_thd	= BIT(8),
+		.sirfsoc_txfifo_thd	= BIT(9),
+		.sirfsoc_frm_err	= BIT(10),
+		.sirfsoc_rxd_brk	= BIT(11),
+		.sirfsoc_rx_timeout	= BIT(12),
+		.sirfsoc_parity_err	= BIT(13),
+		.sirfsoc_cts		= BIT(14),
+		.sirfsoc_rts		= BIT(15),
+	},
+	.fifo_status = {
+		.ff_full		= uart_ff_full,
+		.ff_empty		= uart_ff_empty,
+	},
+	.uart_param = {
+		.uart_name = "ttySiRF",
+		.port_name = "sirfsoc_uart",
+		.uart_nr = 3,
+		.register_uart_nr = 0,
+	},
+};
+/* uart io ctrl */
 #define SIRFUART_DATA_BIT_LEN_MASK		0x3
 #define SIRFUART_DATA_BIT_LEN_5			BIT(0)
 #define SIRFUART_DATA_BIT_LEN_6			1
@@ -50,96 +279,93 @@
 #define SIRFUART_LOOP_BACK			BIT(7)
 #define SIRFUART_PARITY_MASK			(7 << 3)
 #define SIRFUART_DUMMY_READ			BIT(16)
-
-#define SIRFSOC_UART_RX_TIMEOUT(br, to)	(((br) * (((to) + 999) / 1000)) / 1000)
-#define SIRFUART_RECV_TIMEOUT_MASK	(0xFFFF << 16)
-#define SIRFUART_RECV_TIMEOUT(x)	(((x) & 0xFFFF) << 16)
-
-/* UART Auto Flow Control */
-#define SIRFUART_AFC_RX_THD_MASK		0x000000FF
+#define SIRFUART_AFC_CTRL_RX_THD		0x70
 #define SIRFUART_AFC_RX_EN			BIT(8)
 #define SIRFUART_AFC_TX_EN			BIT(9)
-#define SIRFUART_CTS_CTRL			BIT(10)
-#define SIRFUART_RTS_CTRL			BIT(11)
-#define SIRFUART_CTS_IN_STATUS			BIT(12)
-#define SIRFUART_RTS_OUT_STATUS			BIT(13)
-
-/* UART Interrupt Enable Register */
-#define SIRFUART_RX_DONE_INT			BIT(0)
-#define SIRFUART_TX_DONE_INT			BIT(1)
-#define SIRFUART_RX_OFLOW_INT			BIT(2)
-#define SIRFUART_TX_ALLOUT_INT			BIT(3)
-#define SIRFUART_RX_IO_DMA_INT			BIT(4)
-#define SIRFUART_TX_IO_DMA_INT			BIT(5)
-#define SIRFUART_RXFIFO_FULL_INT		BIT(6)
-#define SIRFUART_TXFIFO_EMPTY_INT		BIT(7)
-#define SIRFUART_RXFIFO_THD_INT			BIT(8)
-#define SIRFUART_TXFIFO_THD_INT			BIT(9)
-#define SIRFUART_FRM_ERR_INT			BIT(10)
-#define SIRFUART_RXD_BREAK_INT			BIT(11)
-#define SIRFUART_RX_TIMEOUT_INT			BIT(12)
-#define SIRFUART_PARITY_ERR_INT			BIT(13)
-#define SIRFUART_CTS_INT_EN			BIT(14)
-#define SIRFUART_RTS_INT_EN			BIT(15)
-
-/* UART Interrupt Status Register */
-#define SIRFUART_RX_DONE			BIT(0)
-#define SIRFUART_TX_DONE			BIT(1)
-#define SIRFUART_RX_OFLOW			BIT(2)
-#define SIRFUART_TX_ALL_EMPTY			BIT(3)
-#define SIRFUART_DMA_IO_RX_DONE			BIT(4)
-#define SIRFUART_DMA_IO_TX_DONE			BIT(5)
-#define SIRFUART_RXFIFO_FULL			BIT(6)
-#define SIRFUART_TXFIFO_EMPTY			BIT(7)
-#define SIRFUART_RXFIFO_THD_REACH		BIT(8)
-#define SIRFUART_TXFIFO_THD_REACH		BIT(9)
-#define SIRFUART_FRM_ERR			BIT(10)
-#define SIRFUART_RXD_BREAK			BIT(11)
-#define SIRFUART_RX_TIMEOUT			BIT(12)
-#define SIRFUART_PARITY_ERR			BIT(13)
-#define SIRFUART_CTS_CHANGE			BIT(14)
-#define SIRFUART_RTS_CHANGE			BIT(15)
-#define SIRFUART_PLUG_IN			BIT(16)
-
-#define SIRFUART_ERR_INT_STAT					\
-				(SIRFUART_RX_OFLOW |		\
-				SIRFUART_FRM_ERR |		\
-				SIRFUART_RXD_BREAK |		\
-				SIRFUART_PARITY_ERR)
-#define SIRFUART_ERR_INT_EN					\
-				(SIRFUART_RX_OFLOW_INT |	\
-				SIRFUART_FRM_ERR_INT |		\
-				SIRFUART_RXD_BREAK_INT |	\
-				SIRFUART_PARITY_ERR_INT)
-#define SIRFUART_TX_INT_EN	SIRFUART_TXFIFO_EMPTY_INT
-#define SIRFUART_RX_IO_INT_EN					\
-				(SIRFUART_RX_TIMEOUT_INT |	\
-				SIRFUART_RXFIFO_THD_INT |	\
-				SIRFUART_RXFIFO_FULL_INT |	\
-				SIRFUART_ERR_INT_EN)
-
+#define SIRFUART_AFC_CTS_CTRL			BIT(10)
+#define SIRFUART_AFC_RTS_CTRL			BIT(11)
+#define	SIRFUART_AFC_CTS_STATUS			BIT(12)
+#define	SIRFUART_AFC_RTS_STATUS			BIT(13)
 /* UART FIFO Register */
-#define SIRFUART_TX_FIFO_STOP			0x0
-#define SIRFUART_TX_FIFO_RESET			0x1
-#define SIRFUART_TX_FIFO_START			0x2
-#define SIRFUART_RX_FIFO_STOP			0x0
-#define SIRFUART_RX_FIFO_RESET			0x1
-#define SIRFUART_RX_FIFO_START			0x2
-#define SIRFUART_TX_MODE_DMA			0
-#define SIRFUART_TX_MODE_IO			1
-#define SIRFUART_RX_MODE_DMA			0
-#define SIRFUART_RX_MODE_IO			1
+#define SIRFUART_FIFO_STOP			0x0
+#define SIRFUART_FIFO_RESET			BIT(0)
+#define SIRFUART_FIFO_START			BIT(1)
 
-#define SIRFUART_RX_EN				0x1
-#define SIRFUART_TX_EN				0x2
+#define SIRFUART_RX_EN				BIT(0)
+#define SIRFUART_TX_EN				BIT(1)
 
+#define SIRFUART_IO_MODE			BIT(0)
+#define SIRFUART_DMA_MODE			0x0
+
+/* Macro Specific*/
+#define SIRFUART_INT_EN_CLR                    0x0060
+/* Baud Rate Calculation */
+#define SIRF_MIN_SAMPLE_DIV			0xf
+#define SIRF_MAX_SAMPLE_DIV			0x3f
+#define SIRF_IOCLK_DIV_MAX			0xffff
+#define SIRF_SAMPLE_DIV_SHIFT			16
+#define SIRF_IOCLK_DIV_MASK			0xffff
+#define SIRF_SAMPLE_DIV_MASK			0x3f0000
+#define SIRF_BAUD_RATE_SUPPORT_NR		18
+
+/* USP SPEC */
+#define SIRFSOC_USP_ENDIAN_CTRL_LSBF		BIT(4)
+#define SIRFSOC_USP_EN				BIT(5)
+#define SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET	0
+#define SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET	8
+#define SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK	0x3ff
+#define SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET	21
+#define SIRFSOC_USP_TX_DATA_LEN_OFFSET		0
+#define SIRFSOC_USP_TX_SYNC_LEN_OFFSET		8
+#define SIRFSOC_USP_TX_FRAME_LEN_OFFSET		16
+#define SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET	24
+#define SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET	30
+#define SIRFSOC_USP_RX_DATA_LEN_OFFSET		0
+#define SIRFSOC_USP_RX_FRAME_LEN_OFFSET		8
+#define SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET	16
+#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET	24
+#define SIRFSOC_USP_ASYNC_DIV2_MASK		0x3f
+#define SIRFSOC_USP_ASYNC_DIV2_OFFSET		16
+
+/* USP-UART Common */
+#define SIRFSOC_UART_RX_TIMEOUT(br, to)	(((br) * (((to) + 999) / 1000)) / 1000)
+#define SIRFUART_RECV_TIMEOUT_VALUE(x)	\
+				(((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF))
+#define SIRFUART_RECV_TIMEOUT(port, x)	\
+		(((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16)
+
+#define SIRFUART_FIFO_THD(port)		((port->line) == 1 ? 16 : 64)
+#define SIRFUART_ERR_INT_STAT(port, unit_st)			\
+				(uint_st->sirfsoc_rx_oflow |		\
+				uint_st->sirfsoc_frm_err |		\
+				uint_st->sirfsoc_rxd_brk |		\
+		((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err))
+#define SIRFUART_RX_IO_INT_EN(port, uint_en)				\
+				(uint_en->sirfsoc_rx_timeout_en |\
+				 uint_en->sirfsoc_rxfifo_thd_en |\
+				 uint_en->sirfsoc_rxfifo_full_en |\
+				 uint_en->sirfsoc_frm_err_en |\
+				 uint_en->sirfsoc_rx_oflow_en |\
+				 uint_en->sirfsoc_rxd_brk_en |\
+		((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
+#define SIRFUART_RX_IO_INT_ST(uint_st)				\
+				(uint_st->sirfsoc_rx_timeout |\
+				 uint_st->sirfsoc_rxfifo_thd |\
+				 uint_st->sirfsoc_rxfifo_full)
+#define SIRFUART_CTS_INT_ST(uint_st)	(uint_st->sirfsoc_cts)
+#define SIRFUART_RX_DMA_INT_EN(port, uint_en)				\
+				(uint_en->sirfsoc_rx_timeout_en |\
+				 uint_en->sirfsoc_frm_err_en |\
+				 uint_en->sirfsoc_rx_oflow_en |\
+				 uint_en->sirfsoc_rxd_brk_en |\
+		((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
 /* Generic Definitions */
 #define SIRFSOC_UART_NAME			"ttySiRF"
 #define SIRFSOC_UART_MAJOR			0
 #define SIRFSOC_UART_MINOR			0
 #define SIRFUART_PORT_NAME			"sirfsoc-uart"
 #define SIRFUART_MAP_SIZE			0x200
-#define SIRFSOC_UART_NR				5
+#define SIRFSOC_UART_NR				6
 #define SIRFSOC_PORT_TYPE			0xa5
 
 /* Baud Rate Calculation */
@@ -151,19 +377,80 @@
 #define SIRF_SAMPLE_DIV_MASK			0x3f0000
 #define SIRF_BAUD_RATE_SUPPORT_NR		18
 
+/* Uart Common Use Macro*/
+#define SIRFSOC_RX_DMA_BUF_SIZE	256
+#define BYTES_TO_ALIGN(dma_addr)	((unsigned long)(dma_addr) & 0x3)
+#define LOOP_DMA_BUFA_FILL	1
+#define LOOP_DMA_BUFB_FILL	2
+#define TX_TRAN_PIO		1
+#define TX_TRAN_DMA		2
+/* Uart Fifo Level Chk */
+#define SIRFUART_TX_FIFO_SC_OFFSET	0
+#define SIRFUART_TX_FIFO_LC_OFFSET	10
+#define SIRFUART_TX_FIFO_HC_OFFSET	20
+#define SIRFUART_TX_FIFO_CHK_SC(line, value) ((((line) == 1) ? (value & 0x3) :\
+				(value & 0x1f)) << SIRFUART_TX_FIFO_SC_OFFSET)
+#define SIRFUART_TX_FIFO_CHK_LC(line, value) ((((line) == 1) ? (value & 0x3) :\
+				(value & 0x1f)) << SIRFUART_TX_FIFO_LC_OFFSET)
+#define SIRFUART_TX_FIFO_CHK_HC(line, value) ((((line) == 1) ? (value & 0x3) :\
+				(value & 0x1f)) << SIRFUART_TX_FIFO_HC_OFFSET)
+
+#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC
+#define	SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC
+#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC
+/* Indicate how many buffers used */
+#define SIRFSOC_RX_LOOP_BUF_CNT		2
+
+/* Indicate if DMA channel valid */
+#define IS_DMA_CHAN_VALID(x)	((x) != -1)
+#define UNVALID_DMA_CHAN	-1
 /* For Fast Baud Rate Calculation */
 struct sirfsoc_baudrate_to_regv {
 	unsigned int baud_rate;
 	unsigned int reg_val;
 };
 
+enum sirfsoc_tx_state {
+	TX_DMA_IDLE,
+	TX_DMA_RUNNING,
+	TX_DMA_PAUSE,
+};
+
+struct sirfsoc_loop_buffer {
+	struct circ_buf			xmit;
+	dma_cookie_t			cookie;
+	struct dma_async_tx_descriptor	*desc;
+	dma_addr_t			dma_addr;
+};
+
 struct sirfsoc_uart_port {
-	unsigned char			hw_flow_ctrl;
-	unsigned char			ms_enabled;
+	bool				hw_flow_ctrl;
+	bool				ms_enabled;
 
 	struct uart_port		port;
-	struct pinctrl			*p;
 	struct clk			*clk;
+	/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
+	bool				is_marco;
+	struct sirfsoc_uart_register	*uart_reg;
+	int				rx_dma_no;
+	int				tx_dma_no;
+	struct dma_chan			*rx_dma_chan;
+	struct dma_chan			*tx_dma_chan;
+	dma_addr_t			tx_dma_addr;
+	struct dma_async_tx_descriptor	*tx_dma_desc;
+	spinlock_t			rx_lock;
+	spinlock_t			tx_lock;
+	struct tasklet_struct		rx_dma_complete_tasklet;
+	struct tasklet_struct		rx_tmo_process_tasklet;
+	unsigned int			rx_io_count;
+	unsigned long			transfer_size;
+	enum sirfsoc_tx_state		tx_dma_state;
+	unsigned int			cts_gpio;
+	unsigned int			rts_gpio;
+
+	struct sirfsoc_loop_buffer	rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT];
+	int				rx_completed;
+	int				rx_issued;
 };
 
 /* Hardware Flow Control */
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
new file mode 100644
index 0000000..21e6e84
--- /dev/null
+++ b/drivers/tty/serial/st-asc.c
@@ -0,0 +1,932 @@
+/*
+ * st-asc.c: ST Asynchronous serial controller (ASC) driver
+ *
+ * Copyright (C) 2003-2013 STMicroelectronics (R&D) Limited
+ *
+ * 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.
+ *
+ */
+
+#if defined(CONFIG_SERIAL_ST_ASC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/serial_core.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "st-asc"
+#define ASC_SERIAL_NAME "ttyAS"
+#define ASC_FIFO_SIZE 16
+#define ASC_MAX_PORTS 8
+
+struct asc_port {
+	struct uart_port port;
+	struct clk *clk;
+	unsigned int hw_flow_control:1;
+	unsigned int force_m1:1;
+};
+
+static struct asc_port asc_ports[ASC_MAX_PORTS];
+static struct uart_driver asc_uart_driver;
+
+/*---- UART Register definitions ------------------------------*/
+
+/* Register offsets */
+
+#define ASC_BAUDRATE			0x00
+#define ASC_TXBUF			0x04
+#define ASC_RXBUF			0x08
+#define ASC_CTL				0x0C
+#define ASC_INTEN			0x10
+#define ASC_STA				0x14
+#define ASC_GUARDTIME			0x18
+#define ASC_TIMEOUT			0x1C
+#define ASC_TXRESET			0x20
+#define ASC_RXRESET			0x24
+#define ASC_RETRIES			0x28
+
+/* ASC_RXBUF */
+#define ASC_RXBUF_PE			0x100
+#define ASC_RXBUF_FE			0x200
+/**
+ * Some of status comes from higher bits of the character and some come from
+ * the status register. Combining both of them in to single status using dummy
+ * bits.
+ */
+#define ASC_RXBUF_DUMMY_RX		0x10000
+#define ASC_RXBUF_DUMMY_BE		0x20000
+#define ASC_RXBUF_DUMMY_OE		0x40000
+
+/* ASC_CTL */
+
+#define ASC_CTL_MODE_MSK		0x0007
+#define  ASC_CTL_MODE_8BIT		0x0001
+#define  ASC_CTL_MODE_7BIT_PAR		0x0003
+#define  ASC_CTL_MODE_9BIT		0x0004
+#define  ASC_CTL_MODE_8BIT_WKUP		0x0005
+#define  ASC_CTL_MODE_8BIT_PAR		0x0007
+#define ASC_CTL_STOP_MSK		0x0018
+#define  ASC_CTL_STOP_HALFBIT		0x0000
+#define  ASC_CTL_STOP_1BIT		0x0008
+#define  ASC_CTL_STOP_1_HALFBIT		0x0010
+#define  ASC_CTL_STOP_2BIT		0x0018
+#define ASC_CTL_PARITYODD		0x0020
+#define ASC_CTL_LOOPBACK		0x0040
+#define ASC_CTL_RUN			0x0080
+#define ASC_CTL_RXENABLE		0x0100
+#define ASC_CTL_SCENABLE		0x0200
+#define ASC_CTL_FIFOENABLE		0x0400
+#define ASC_CTL_CTSENABLE		0x0800
+#define ASC_CTL_BAUDMODE		0x1000
+
+/* ASC_GUARDTIME */
+
+#define ASC_GUARDTIME_MSK		0x00FF
+
+/* ASC_INTEN */
+
+#define ASC_INTEN_RBE			0x0001
+#define ASC_INTEN_TE			0x0002
+#define ASC_INTEN_THE			0x0004
+#define ASC_INTEN_PE			0x0008
+#define ASC_INTEN_FE			0x0010
+#define ASC_INTEN_OE			0x0020
+#define ASC_INTEN_TNE			0x0040
+#define ASC_INTEN_TOI			0x0080
+#define ASC_INTEN_RHF			0x0100
+
+/* ASC_RETRIES */
+
+#define ASC_RETRIES_MSK			0x00FF
+
+/* ASC_RXBUF */
+
+#define ASC_RXBUF_MSK			0x03FF
+
+/* ASC_STA */
+
+#define ASC_STA_RBF			0x0001
+#define ASC_STA_TE			0x0002
+#define ASC_STA_THE			0x0004
+#define ASC_STA_PE			0x0008
+#define ASC_STA_FE			0x0010
+#define ASC_STA_OE			0x0020
+#define ASC_STA_TNE			0x0040
+#define ASC_STA_TOI			0x0080
+#define ASC_STA_RHF			0x0100
+#define ASC_STA_TF			0x0200
+#define ASC_STA_NKD			0x0400
+
+/* ASC_TIMEOUT */
+
+#define ASC_TIMEOUT_MSK			0x00FF
+
+/* ASC_TXBUF */
+
+#define ASC_TXBUF_MSK			0x01FF
+
+/*---- Inline function definitions ---------------------------*/
+
+static inline struct asc_port *to_asc_port(struct uart_port *port)
+{
+	return container_of(port, struct asc_port, port);
+}
+
+static inline u32 asc_in(struct uart_port *port, u32 offset)
+{
+	return readl(port->membase + offset);
+}
+
+static inline void asc_out(struct uart_port *port, u32 offset, u32 value)
+{
+	writel(value, port->membase + offset);
+}
+
+/*
+ * Some simple utility functions to enable and disable interrupts.
+ * Note that these need to be called with interrupts disabled.
+ */
+static inline void asc_disable_tx_interrupts(struct uart_port *port)
+{
+	u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_THE;
+	asc_out(port, ASC_INTEN, intenable);
+	(void)asc_in(port, ASC_INTEN);	/* Defeat bus write posting */
+}
+
+static inline void asc_enable_tx_interrupts(struct uart_port *port)
+{
+	u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_THE;
+	asc_out(port, ASC_INTEN, intenable);
+}
+
+static inline void asc_disable_rx_interrupts(struct uart_port *port)
+{
+	u32 intenable = asc_in(port, ASC_INTEN) & ~ASC_INTEN_RBE;
+	asc_out(port, ASC_INTEN, intenable);
+	(void)asc_in(port, ASC_INTEN);	/* Defeat bus write posting */
+}
+
+static inline void asc_enable_rx_interrupts(struct uart_port *port)
+{
+	u32 intenable = asc_in(port, ASC_INTEN) | ASC_INTEN_RBE;
+	asc_out(port, ASC_INTEN, intenable);
+}
+
+static inline u32 asc_txfifo_is_empty(struct uart_port *port)
+{
+	return asc_in(port, ASC_STA) & ASC_STA_TE;
+}
+
+static inline int asc_txfifo_is_full(struct uart_port *port)
+{
+	return asc_in(port, ASC_STA) & ASC_STA_TF;
+}
+
+static inline const char *asc_port_name(struct uart_port *port)
+{
+	return to_platform_device(port->dev)->name;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * This section contains code to support the use of the ASC as a
+ * generic serial port.
+ */
+
+static inline unsigned asc_hw_txroom(struct uart_port *port)
+{
+	u32 status = asc_in(port, ASC_STA);
+
+	if (status & ASC_STA_THE)
+		return port->fifosize / 2;
+	else if (!(status & ASC_STA_TF))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Start transmitting chars.
+ * This is called from both interrupt and task level.
+ * Either way interrupts are disabled.
+ */
+static void asc_transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	int txroom;
+	unsigned char c;
+
+	txroom = asc_hw_txroom(port);
+
+	if ((txroom != 0) && port->x_char) {
+		c = port->x_char;
+		port->x_char = 0;
+		asc_out(port, ASC_TXBUF, c);
+		port->icount.tx++;
+		txroom = asc_hw_txroom(port);
+	}
+
+	if (uart_tx_stopped(port)) {
+		/*
+		 * We should try and stop the hardware here, but I
+		 * don't think the ASC has any way to do that.
+		 */
+		asc_disable_tx_interrupts(port);
+		return;
+	}
+
+	if (uart_circ_empty(xmit)) {
+		asc_disable_tx_interrupts(port);
+		return;
+	}
+
+	if (txroom == 0)
+		return;
+
+	do {
+		c = xmit->buf[xmit->tail];
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		asc_out(port, ASC_TXBUF, c);
+		port->icount.tx++;
+		txroom--;
+	} while ((txroom > 0) && (!uart_circ_empty(xmit)));
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		asc_disable_tx_interrupts(port);
+}
+
+static void asc_receive_chars(struct uart_port *port)
+{
+	struct tty_port *tport = &port->state->port;
+	unsigned long status;
+	unsigned long c = 0;
+	char flag;
+
+	if (port->irq_wake)
+		pm_wakeup_event(tport->tty->dev, 0);
+
+	while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) {
+		c = asc_in(port, ASC_RXBUF) | ASC_RXBUF_DUMMY_RX;
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if ((c & (ASC_RXBUF_FE | ASC_RXBUF_PE)) ||
+			status & ASC_STA_OE) {
+
+			if (c & ASC_RXBUF_FE) {
+				if (c == ASC_RXBUF_FE) {
+					port->icount.brk++;
+					if (uart_handle_break(port))
+						continue;
+					c |= ASC_RXBUF_DUMMY_BE;
+				} else {
+					port->icount.frame++;
+				}
+			} else if (c & ASC_RXBUF_PE) {
+				port->icount.parity++;
+			}
+			/*
+			 * Reading any data from the RX FIFO clears the
+			 * overflow error condition.
+			 */
+			if (status & ASC_STA_OE) {
+				port->icount.overrun++;
+				c |= ASC_RXBUF_DUMMY_OE;
+			}
+
+			c &= port->read_status_mask;
+
+			if (c & ASC_RXBUF_DUMMY_BE)
+				flag = TTY_BREAK;
+			else if (c & ASC_RXBUF_PE)
+				flag = TTY_PARITY;
+			else if (c & ASC_RXBUF_FE)
+				flag = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(port, c))
+			continue;
+
+		uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag);
+	}
+
+	/* Tell the rest of the system the news. New characters! */
+	tty_flip_buffer_push(tport);
+}
+
+static irqreturn_t asc_interrupt(int irq, void *ptr)
+{
+	struct uart_port *port = ptr;
+	u32 status;
+
+	spin_lock(&port->lock);
+
+	status = asc_in(port, ASC_STA);
+
+	if (status & ASC_STA_RBF) {
+		/* Receive FIFO not empty */
+		asc_receive_chars(port);
+	}
+
+	if ((status & ASC_STA_THE) &&
+	    (asc_in(port, ASC_INTEN) & ASC_INTEN_THE)) {
+		/* Transmitter FIFO at least half empty */
+		asc_transmit_chars(port);
+	}
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * UART Functions
+ */
+
+static unsigned int asc_tx_empty(struct uart_port *port)
+{
+	return asc_txfifo_is_empty(port) ? TIOCSER_TEMT : 0;
+}
+
+static void asc_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/*
+	 * This routine is used for seting signals of: DTR, DCD, CTS/RTS
+	 * We use ASC's hardware for CTS/RTS, so don't need any for that.
+	 * Some boards have DTR and DCD implemented using PIO pins,
+	 * code to do this should be hooked in here.
+	 */
+}
+
+static unsigned int asc_get_mctrl(struct uart_port *port)
+{
+	/*
+	 * This routine is used for geting signals of: DTR, DCD, DSR, RI,
+	 * and CTS/RTS
+	 */
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* There are probably characters waiting to be transmitted. */
+static void asc_start_tx(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (!uart_circ_empty(xmit))
+		asc_enable_tx_interrupts(port);
+}
+
+/* Transmit stop */
+static void asc_stop_tx(struct uart_port *port)
+{
+	asc_disable_tx_interrupts(port);
+}
+
+/* Receive stop */
+static void asc_stop_rx(struct uart_port *port)
+{
+	asc_disable_rx_interrupts(port);
+}
+
+/* Force modem status interrupts on */
+static void asc_enable_ms(struct uart_port *port)
+{
+	/* Nothing here yet .. */
+}
+
+/* Handle breaks - ignored by us */
+static void asc_break_ctl(struct uart_port *port, int break_state)
+{
+	/* Nothing here yet .. */
+}
+
+/*
+ * Enable port for reception.
+ */
+static int asc_startup(struct uart_port *port)
+{
+	if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND,
+			asc_port_name(port), port)) {
+		dev_err(port->dev, "cannot allocate irq.\n");
+		return -ENODEV;
+	}
+
+	asc_transmit_chars(port);
+	asc_enable_rx_interrupts(port);
+
+	return 0;
+}
+
+static void asc_shutdown(struct uart_port *port)
+{
+	asc_disable_tx_interrupts(port);
+	asc_disable_rx_interrupts(port);
+	free_irq(port->irq, port);
+}
+
+static void asc_pm(struct uart_port *port, unsigned int state,
+		unsigned int oldstate)
+{
+	struct asc_port *ascport = to_asc_port(port);
+	unsigned long flags = 0;
+	u32 ctl;
+
+	switch (state) {
+	case UART_PM_STATE_ON:
+		clk_prepare_enable(ascport->clk);
+		break;
+	case UART_PM_STATE_OFF:
+		/*
+		 * Disable the ASC baud rate generator, which is as close as
+		 * we can come to turning it off. Note this is not called with
+		 * the port spinlock held.
+		 */
+		spin_lock_irqsave(&port->lock, flags);
+		ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN;
+		asc_out(port, ASC_CTL, ctl);
+		spin_unlock_irqrestore(&port->lock, flags);
+		clk_disable_unprepare(ascport->clk);
+		break;
+	}
+}
+
+static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
+			    struct ktermios *old)
+{
+	struct asc_port *ascport = to_asc_port(port);
+	unsigned int baud;
+	u32 ctrl_val;
+	tcflag_t cflag;
+	unsigned long flags;
+
+	/* Update termios to reflect hardware capabilities */
+	termios->c_cflag &= ~(CMSPAR |
+			 (ascport->hw_flow_control ? 0 : CRTSCTS));
+
+	port->uartclk = clk_get_rate(ascport->clk);
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+	cflag = termios->c_cflag;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* read control register */
+	ctrl_val = asc_in(port, ASC_CTL);
+
+	/* stop serial port and reset value */
+	asc_out(port, ASC_CTL, (ctrl_val & ~ASC_CTL_RUN));
+	ctrl_val = ASC_CTL_RXENABLE | ASC_CTL_FIFOENABLE;
+
+	/* reset fifo rx & tx */
+	asc_out(port, ASC_TXRESET, 1);
+	asc_out(port, ASC_RXRESET, 1);
+
+	/* set character length */
+	if ((cflag & CSIZE) == CS7) {
+		ctrl_val |= ASC_CTL_MODE_7BIT_PAR;
+	} else {
+		ctrl_val |= (cflag & PARENB) ?  ASC_CTL_MODE_8BIT_PAR :
+						ASC_CTL_MODE_8BIT;
+	}
+
+	/* set stop bit */
+	ctrl_val |= (cflag & CSTOPB) ? ASC_CTL_STOP_2BIT : ASC_CTL_STOP_1BIT;
+
+	/* odd parity */
+	if (cflag & PARODD)
+		ctrl_val |= ASC_CTL_PARITYODD;
+
+	/* hardware flow control */
+	if ((cflag & CRTSCTS))
+		ctrl_val |= ASC_CTL_CTSENABLE;
+
+	if ((baud < 19200) && !ascport->force_m1) {
+		asc_out(port, ASC_BAUDRATE, (port->uartclk / (16 * baud)));
+	} else {
+		/*
+		 * MODE 1: recommended for high bit rates (above 19.2K)
+		 *
+		 *                   baudrate * 16 * 2^16
+		 * ASCBaudRate =   ------------------------
+		 *                          inputclock
+		 *
+		 * However to keep the maths inside 32bits we divide top and
+		 * bottom by 64. The +1 is to avoid a divide by zero if the
+		 * input clock rate is something unexpected.
+		 */
+		u32 counter = (baud * 16384) / ((port->uartclk / 64) + 1);
+		asc_out(port, ASC_BAUDRATE, counter);
+		ctrl_val |= ASC_CTL_BAUDMODE;
+	}
+
+	uart_update_timeout(port, cflag, baud);
+
+	ascport->port.read_status_mask = ASC_RXBUF_DUMMY_OE;
+	if (termios->c_iflag & INPCK)
+		ascport->port.read_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		ascport->port.read_status_mask |= ASC_RXBUF_DUMMY_BE;
+
+	/*
+	 * Characters to ignore
+	 */
+	ascport->port.ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		ascport->port.ignore_status_mask |= ASC_RXBUF_FE | ASC_RXBUF_PE;
+	if (termios->c_iflag & IGNBRK) {
+		ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_BE;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_OE;
+	}
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+	if (!(termios->c_cflag & CREAD))
+		ascport->port.ignore_status_mask |= ASC_RXBUF_DUMMY_RX;
+
+	/* Set the timeout */
+	asc_out(port, ASC_TIMEOUT, 20);
+
+	/* write final value and enable port */
+	asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN));
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *asc_type(struct uart_port *port)
+{
+	return (port->type == PORT_ASC) ? DRIVER_NAME : NULL;
+}
+
+static void asc_release_port(struct uart_port *port)
+{
+}
+
+static int asc_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/*
+ * Called when the port is opened, and UPF_BOOT_AUTOCONF flag is set
+ * Set type field if successful
+ */
+static void asc_config_port(struct uart_port *port, int flags)
+{
+	if ((flags & UART_CONFIG_TYPE))
+		port->type = PORT_ASC;
+}
+
+static int
+asc_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* No user changeable parameters */
+	return -EINVAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for writing and reading from the uart while
+ * in an interrupt or debug context (i.e. kgdb).
+ */
+
+static int asc_get_poll_char(struct uart_port *port)
+{
+	if (!(asc_in(port, ASC_STA) & ASC_STA_RBF))
+		return NO_POLL_CHAR;
+
+	return asc_in(port, ASC_RXBUF);
+}
+
+static void asc_put_poll_char(struct uart_port *port, unsigned char c)
+{
+	while (asc_txfifo_is_full(port))
+		cpu_relax();
+	asc_out(port, ASC_TXBUF, c);
+}
+
+#endif /* CONFIG_CONSOLE_POLL */
+
+/*---------------------------------------------------------------------*/
+
+static struct uart_ops asc_uart_ops = {
+	.tx_empty	= asc_tx_empty,
+	.set_mctrl	= asc_set_mctrl,
+	.get_mctrl	= asc_get_mctrl,
+	.start_tx	= asc_start_tx,
+	.stop_tx	= asc_stop_tx,
+	.stop_rx	= asc_stop_rx,
+	.enable_ms	= asc_enable_ms,
+	.break_ctl	= asc_break_ctl,
+	.startup	= asc_startup,
+	.shutdown	= asc_shutdown,
+	.set_termios	= asc_set_termios,
+	.type		= asc_type,
+	.release_port	= asc_release_port,
+	.request_port	= asc_request_port,
+	.config_port	= asc_config_port,
+	.verify_port	= asc_verify_port,
+	.pm		= asc_pm,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_get_char = asc_get_poll_char,
+	.poll_put_char = asc_put_poll_char,
+#endif /* CONFIG_CONSOLE_POLL */
+};
+
+static int asc_init_port(struct asc_port *ascport,
+			  struct platform_device *pdev)
+{
+	struct uart_port *port = &ascport->port;
+	struct resource *res;
+
+	port->iotype	= UPIO_MEM;
+	port->flags	= UPF_BOOT_AUTOCONF;
+	port->ops	= &asc_uart_ops;
+	port->fifosize	= ASC_FIFO_SIZE;
+	port->dev	= &pdev->dev;
+	port->irq	= platform_get_irq(pdev, 0);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	port->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
+	port->mapbase = res->start;
+
+	spin_lock_init(&port->lock);
+
+	ascport->clk = devm_clk_get(&pdev->dev, NULL);
+
+	if (WARN_ON(IS_ERR(ascport->clk)))
+		return -EINVAL;
+	/* ensure that clk rate is correct by enabling the clk */
+	clk_prepare_enable(ascport->clk);
+	ascport->port.uartclk = clk_get_rate(ascport->clk);
+	WARN_ON(ascport->port.uartclk == 0);
+	clk_disable_unprepare(ascport->clk);
+
+	return 0;
+}
+
+static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int id;
+
+	if (!np)
+		return NULL;
+
+	id = of_alias_get_id(np, ASC_SERIAL_NAME);
+
+	if (id < 0)
+		id = 0;
+
+	if (WARN_ON(id >= ASC_MAX_PORTS))
+		return NULL;
+
+	asc_ports[id].hw_flow_control = of_property_read_bool(np,
+							"st,hw-flow-control");
+	asc_ports[id].force_m1 =  of_property_read_bool(np, "st,force_m1");
+	asc_ports[id].port.line = id;
+	return &asc_ports[id];
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id asc_match[] = {
+	{ .compatible = "st,asc", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, asc_match);
+#endif
+
+static int asc_serial_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct asc_port *ascport;
+
+	ascport = asc_of_get_asc_port(pdev);
+	if (!ascport)
+		return -ENODEV;
+
+	ret = asc_init_port(ascport, pdev);
+	if (ret)
+		return ret;
+
+	ret = uart_add_one_port(&asc_uart_driver, &ascport->port);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, &ascport->port);
+
+	return 0;
+}
+
+static int asc_serial_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_remove_one_port(&asc_uart_driver, port);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int asc_serial_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_suspend_port(&asc_uart_driver, port);
+}
+
+static int asc_serial_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct uart_port *port = platform_get_drvdata(pdev);
+
+	return uart_resume_port(&asc_uart_driver, port);
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_SERIAL_ST_ASC_CONSOLE
+static void asc_console_putchar(struct uart_port *port, int ch)
+{
+	unsigned int timeout = 1000000;
+
+	/* Wait for upto 1 second in case flow control is stopping us. */
+	while (--timeout && asc_txfifo_is_full(port))
+		udelay(1);
+
+	asc_out(port, ASC_TXBUF, ch);
+}
+
+/*
+ *  Print a string to the serial port trying not to disturb
+ *  any possible real use of the port...
+ */
+
+static void asc_console_write(struct console *co, const char *s, unsigned count)
+{
+	struct uart_port *port = &asc_ports[co->index].port;
+	unsigned long flags;
+	unsigned long timeout = 1000000;
+	int locked = 1;
+	u32 intenable;
+
+	local_irq_save(flags);
+	if (port->sysrq)
+		locked = 0; /* asc_interrupt has already claimed the lock */
+	else if (oops_in_progress)
+		locked = spin_trylock(&port->lock);
+	else
+		spin_lock(&port->lock);
+
+	/*
+	 * Disable interrupts so we don't get the IRQ line bouncing
+	 * up and down while interrupts are disabled.
+	 */
+	intenable = asc_in(port, ASC_INTEN);
+	asc_out(port, ASC_INTEN, 0);
+	(void)asc_in(port, ASC_INTEN);	/* Defeat bus write posting */
+
+	uart_console_write(port, s, count, asc_console_putchar);
+
+	while (--timeout && !asc_txfifo_is_empty(port))
+		udelay(1);
+
+	asc_out(port, ASC_INTEN, intenable);
+
+	if (locked)
+		spin_unlock(&port->lock);
+	local_irq_restore(flags);
+}
+
+static int asc_console_setup(struct console *co, char *options)
+{
+	struct asc_port *ascport;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= ASC_MAX_PORTS)
+		return -ENODEV;
+
+	ascport = &asc_ports[co->index];
+
+	/*
+	 * This driver does not support early console initialization
+	 * (use ARM early printk support instead), so we only expect
+	 * this to be called during the uart port registration when the
+	 * driver gets probed and the port should be mapped at that point.
+	 */
+	BUG_ON(ascport->port.mapbase == 0 || ascport->port.membase == NULL);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&ascport->port, co, baud, parity, bits, flow);
+}
+
+static struct console asc_console = {
+	.name		= ASC_SERIAL_NAME,
+	.device		= uart_console_device,
+	.write		= asc_console_write,
+	.setup		= asc_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &asc_uart_driver,
+};
+
+#define ASC_SERIAL_CONSOLE (&asc_console)
+
+#else
+#define ASC_SERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_ST_ASC_CONSOLE */
+
+static struct uart_driver asc_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= ASC_SERIAL_NAME,
+	.major		= 0,
+	.minor		= 0,
+	.nr		= ASC_MAX_PORTS,
+	.cons		= ASC_SERIAL_CONSOLE,
+};
+
+static const struct dev_pm_ops asc_serial_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume)
+};
+
+static struct platform_driver asc_serial_driver = {
+	.probe		= asc_serial_probe,
+	.remove		= asc_serial_remove,
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.pm	= &asc_serial_pm_ops,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(asc_match),
+	},
+};
+
+static int __init asc_init(void)
+{
+	int ret;
+	static char banner[] __initdata =
+		KERN_INFO "STMicroelectronics ASC driver initialized\n";
+
+	printk(banner);
+
+	ret = uart_register_driver(&asc_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&asc_serial_driver);
+	if (ret)
+		uart_unregister_driver(&asc_uart_driver);
+
+	return ret;
+}
+
+static void __exit asc_exit(void)
+{
+	platform_driver_unregister(&asc_serial_driver);
+	uart_unregister_driver(&asc_uart_driver);
+}
+
+module_init(asc_init);
+module_exit(asc_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("STMicroelectronics (R&D) Limited");
+MODULE_DESCRIPTION("STMicroelectronics ASC serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index 6818410..f87097a 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -162,7 +162,7 @@
 	dev_dbg(port->dev, "%s - leaving\n", __func__);
 }
 
-void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
+static void timbuart_handle_rx_port(struct uart_port *port, u32 isr, u32 *ier)
 {
 	if (isr & RXFLAGS) {
 		/* Some RX status is set */
@@ -184,7 +184,7 @@
 	dev_dbg(port->dev, "%s - leaving\n", __func__);
 }
 
-void timbuart_tasklet(unsigned long arg)
+static void timbuart_tasklet(unsigned long arg)
 {
 	struct timbuart_port *uart = (struct timbuart_port *)arg;
 	u32 isr, ier = 0;
diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index f655997f..a63c14b 100644
--- a/drivers/tty/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
@@ -705,7 +705,7 @@
 {
 	struct uart_port *port;
 	struct resource *res;
-	int *type = pdev->dev.platform_data;
+	int *type = dev_get_platdata(&pdev->dev);
 	int i;
 
 	if (!type)
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 48af43d..93b697a 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -170,7 +170,9 @@
 			tty_insert_flip_char(tport, c, flag);
 	}
 
+	spin_unlock(&port->lock);
 	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
 }
 
 static void handle_tx(struct uart_port *port)
@@ -630,7 +632,6 @@
 {
 	struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
 	clk_disable_unprepare(vt8500_port->clk);
 	uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
 
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 8eaf1ab..e1ce141 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -577,22 +577,22 @@
 
 #define SICR_RXC_ACTIVE			BIT15
 #define SICR_RXC_INACTIVE		BIT14
-#define SICR_RXC			(BIT15+BIT14)
+#define SICR_RXC			(BIT15|BIT14)
 #define SICR_TXC_ACTIVE			BIT13
 #define SICR_TXC_INACTIVE		BIT12
-#define SICR_TXC			(BIT13+BIT12)
+#define SICR_TXC			(BIT13|BIT12)
 #define SICR_RI_ACTIVE			BIT11
 #define SICR_RI_INACTIVE		BIT10
-#define SICR_RI				(BIT11+BIT10)
+#define SICR_RI				(BIT11|BIT10)
 #define SICR_DSR_ACTIVE			BIT9
 #define SICR_DSR_INACTIVE		BIT8
-#define SICR_DSR			(BIT9+BIT8)
+#define SICR_DSR			(BIT9|BIT8)
 #define SICR_DCD_ACTIVE			BIT7
 #define SICR_DCD_INACTIVE		BIT6
-#define SICR_DCD			(BIT7+BIT6)
+#define SICR_DCD			(BIT7|BIT6)
 #define SICR_CTS_ACTIVE			BIT5
 #define SICR_CTS_INACTIVE		BIT4
-#define SICR_CTS			(BIT5+BIT4)
+#define SICR_CTS			(BIT5|BIT4)
 #define SICR_RCC_UNDERFLOW		BIT3
 #define SICR_DPLL_NO_SYNC		BIT2
 #define SICR_BRG1_ZERO			BIT1
@@ -1161,7 +1161,7 @@
 {
 	u16 status = usc_InReg( info, RCSR );
 
-	if ( debug_level >= DEBUG_LEVEL_ISR )	
+	if ( debug_level >= DEBUG_LEVEL_ISR )
 		printk("%s(%d):mgsl_isr_receive_status status=%04X\n",
 			__FILE__,__LINE__,status);
 			
@@ -1181,7 +1181,7 @@
  			(usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED));
  	}
 
-	if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {
+	if (status & (RXSTATUS_EXITED_HUNT | RXSTATUS_IDLE_RECEIVED)) {
 		if (status & RXSTATUS_EXITED_HUNT)
 			info->icount.exithunt++;
 		if (status & RXSTATUS_IDLE_RECEIVED)
@@ -1463,21 +1463,21 @@
 
 		/* get the status of the received byte */
 		status = usc_InReg(info, RCSR);
-		if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
-				RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) )
+		if ( status & (RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR |
+				RXSTATUS_OVERRUN | RXSTATUS_BREAK_RECEIVED) )
 			usc_UnlatchRxstatusBits(info,RXSTATUS_ALL);
 		
 		icount->rx++;
 		
 		flag = 0;
-		if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR +
-				RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) {
-			printk("rxerr=%04X\n",status);					
+		if ( status & (RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR |
+				RXSTATUS_OVERRUN | RXSTATUS_BREAK_RECEIVED) ) {
+			printk("rxerr=%04X\n",status);
 			/* update error statistics */
 			if ( status & RXSTATUS_BREAK_RECEIVED ) {
-				status &= ~(RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR);
+				status &= ~(RXSTATUS_FRAMING_ERROR | RXSTATUS_PARITY_ERROR);
 				icount->brk++;
-			} else if (status & RXSTATUS_PARITY_ERROR) 
+			} else if (status & RXSTATUS_PARITY_ERROR)
 				icount->parity++;
 			else if (status & RXSTATUS_FRAMING_ERROR)
 				icount->frame++;
@@ -1488,7 +1488,7 @@
 				icount->overrun++;
 			}
 
-			/* discard char if tty control flags say so */					
+			/* discard char if tty control flags say so */
 			if (status & info->ignore_status_mask)
 				continue;
 				
@@ -1545,8 +1545,8 @@
 		usc_EnableReceiver(info,DISABLE_UNCONDITIONAL);
 		usc_DmaCmd(info, DmaCmd_ResetRxChannel);
 		usc_UnlatchRxstatusBits(info, RXSTATUS_ALL);
-		usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS);
-		usc_DisableInterrupts(info, RECEIVE_DATA + RECEIVE_STATUS);
+		usc_ClearIrqPendingBits(info, RECEIVE_DATA | RECEIVE_STATUS);
+		usc_DisableInterrupts(info, RECEIVE_DATA | RECEIVE_STATUS);
 
 		/* schedule BH handler to restart receiver */
 		info->pending_bh |= BH_RECEIVE;
@@ -1595,7 +1595,7 @@
 	u16 status;
 	
 	/* clear interrupt pending and IUS bit for Rx DMA IRQ */
-	usc_OutDmaReg( info, CDIR, BIT9+BIT1 );
+	usc_OutDmaReg( info, CDIR, BIT9 | BIT1 );
 
 	/* Read the receive DMA status to identify interrupt type. */
 	/* This also clears the status bits. */
@@ -1639,7 +1639,7 @@
 	u16 status;
 
 	/* clear interrupt pending and IUS bit for Tx DMA IRQ */
-	usc_OutDmaReg(info, CDIR, BIT8+BIT0 );
+	usc_OutDmaReg(info, CDIR, BIT8 | BIT0 );
 
 	/* Read the transmit DMA status to identify interrupt type. */
 	/* This also clears the status bits. */
@@ -1832,8 +1832,8 @@
 	usc_DisableMasterIrqBit(info);
 	usc_stop_receiver(info);
 	usc_stop_transmitter(info);
-	usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS +
-		TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC );
+	usc_DisableInterrupts(info,RECEIVE_DATA | RECEIVE_STATUS |
+		TRANSMIT_DATA | TRANSMIT_STATUS | IO_PIN | MISC );
 	usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE);
 
 	/* Disable DMAEN (Port 7, Bit 14) */
@@ -1886,7 +1886,7 @@
 	info->ri_chkcount = 0;
 	info->dsr_chkcount = 0;
 
-	usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);		
+	usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);
 	usc_EnableInterrupts(info, IO_PIN);
 	usc_get_serial_signals(info);
 		
@@ -2773,7 +2773,7 @@
 		if (!waitqueue_active(&info->event_wait_q)) {
 			/* disable enable exit hunt mode/idle rcvd IRQs */
 			usc_OutReg(info, RICR, usc_InReg(info,RICR) &
-				~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED));
+				~(RXSTATUS_EXITED_HUNT | RXSTATUS_IDLE_RECEIVED));
 		}
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 	}
@@ -3092,7 +3092,7 @@
 		printk("%s(%d):mgsl_close(%s) entry, count=%d\n",
 			 __FILE__,__LINE__, info->device_name, info->port.count);
 
-	if (tty_port_close_start(&info->port, tty, filp) == 0)			 
+	if (tty_port_close_start(&info->port, tty, filp) == 0)
 		goto cleanup;
 
 	mutex_lock(&info->port.mutex);
@@ -4297,7 +4297,7 @@
 		spin_lock_init(&info->irq_spinlock);
 		spin_lock_init(&info->netlock);
 		memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
-		info->idle_mode = HDLC_TXIDLE_FLAGS;		
+		info->idle_mode = HDLC_TXIDLE_FLAGS;
 		info->num_tx_dma_buffers = 1;
 		info->num_tx_holding_buffers = 0;
 	}
@@ -4722,7 +4722,7 @@
 		else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
 			RegValue |= BIT15;
 		else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
-			RegValue |= BIT15 + BIT14;
+			RegValue |= BIT15 | BIT14;
 		}
 
 		if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
@@ -4763,11 +4763,11 @@
 	switch ( info->params.encoding ) {
 	case HDLC_ENCODING_NRZB:               RegValue |= BIT13; break;
 	case HDLC_ENCODING_NRZI_MARK:          RegValue |= BIT14; break;
-	case HDLC_ENCODING_NRZI_SPACE:	       RegValue |= BIT14 + BIT13; break;
+	case HDLC_ENCODING_NRZI_SPACE:	       RegValue |= BIT14 | BIT13; break;
 	case HDLC_ENCODING_BIPHASE_MARK:       RegValue |= BIT15; break;
-	case HDLC_ENCODING_BIPHASE_SPACE:      RegValue |= BIT15 + BIT13; break;
-	case HDLC_ENCODING_BIPHASE_LEVEL:      RegValue |= BIT15 + BIT14; break;
-	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break;
+	case HDLC_ENCODING_BIPHASE_SPACE:      RegValue |= BIT15 | BIT13; break;
+	case HDLC_ENCODING_BIPHASE_LEVEL:      RegValue |= BIT15 | BIT14; break;
+	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14 | BIT13; break;
 	}
 
 	if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT )
@@ -4838,15 +4838,15 @@
 	switch ( info->params.encoding ) {
 	case HDLC_ENCODING_NRZB:               RegValue |= BIT13; break;
 	case HDLC_ENCODING_NRZI_MARK:          RegValue |= BIT14; break;
-	case HDLC_ENCODING_NRZI_SPACE:         RegValue |= BIT14 + BIT13; break;
+	case HDLC_ENCODING_NRZI_SPACE:         RegValue |= BIT14 | BIT13; break;
 	case HDLC_ENCODING_BIPHASE_MARK:       RegValue |= BIT15; break;
-	case HDLC_ENCODING_BIPHASE_SPACE:      RegValue |= BIT15 + BIT13; break;
-	case HDLC_ENCODING_BIPHASE_LEVEL:      RegValue |= BIT15 + BIT14; break;
-	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break;
+	case HDLC_ENCODING_BIPHASE_SPACE:      RegValue |= BIT15 | BIT13; break;
+	case HDLC_ENCODING_BIPHASE_LEVEL:      RegValue |= BIT15 | BIT14; break;
+	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 | BIT14 | BIT13; break;
 	}
 
 	if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT )
-		RegValue |= BIT9 + BIT8;
+		RegValue |= BIT9 | BIT8;
 	else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT )
 		RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8);
 
@@ -4957,7 +4957,7 @@
 
 	RegValue = 0x0000;
 
-	if ( info->params.flags & (HDLC_FLAG_RXC_DPLL + HDLC_FLAG_TXC_DPLL) ) {
+	if ( info->params.flags & (HDLC_FLAG_RXC_DPLL | HDLC_FLAG_TXC_DPLL) ) {
 		u32 XtalSpeed;
 		u32 DpllDivisor;
 		u16 Tc;
@@ -5019,7 +5019,7 @@
 		case HDLC_ENCODING_BIPHASE_MARK:
 		case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT9; break;
 		case HDLC_ENCODING_BIPHASE_LEVEL:
-		case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 + BIT8; break;
+		case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 | BIT8; break;
 		}
 	}
 
@@ -5056,8 +5056,8 @@
 	/* enable Master Interrupt Enable bit (MIE) */
 	usc_EnableMasterIrqBit( info );
 
-	usc_ClearIrqPendingBits( info, RECEIVE_STATUS + RECEIVE_DATA +
-				TRANSMIT_STATUS + TRANSMIT_DATA + MISC);
+	usc_ClearIrqPendingBits( info, RECEIVE_STATUS | RECEIVE_DATA |
+				TRANSMIT_STATUS | TRANSMIT_DATA | MISC);
 
 	/* arm RCC underflow interrupt */
 	usc_OutReg(info, SICR, (u16)(usc_InReg(info,SICR) | BIT3));
@@ -5175,14 +5175,14 @@
 	switch ( info->params.preamble_length ) {
 	case HDLC_PREAMBLE_LENGTH_16BITS: RegValue |= BIT10; break;
 	case HDLC_PREAMBLE_LENGTH_32BITS: RegValue |= BIT11; break;
-	case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 + BIT10; break;
+	case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 | BIT10; break;
 	}
 
 	switch ( info->params.preamble ) {
-	case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 + BIT12; break;
+	case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 | BIT12; break;
 	case HDLC_PREAMBLE_PATTERN_ONES:  RegValue |= BIT8; break;
 	case HDLC_PREAMBLE_PATTERN_10:    RegValue |= BIT9; break;
-	case HDLC_PREAMBLE_PATTERN_01:    RegValue |= BIT9 + BIT8; break;
+	case HDLC_PREAMBLE_PATTERN_01:    RegValue |= BIT9 | BIT8; break;
 	}
 
 	usc_OutReg( info, CCR, RegValue );
@@ -5221,7 +5221,7 @@
 {
 	if (enable) {
 		/* blank external TXD output */
-		usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7+BIT6));
+		usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7 | BIT6));
 	
 		/* Clock mode Control Register (CMCR)
 		 *
@@ -5260,7 +5260,7 @@
 		outw( 0x0300, info->io_base + CCAR );
 	} else {
 		/* enable external TXD output */
-		usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7+BIT6));
+		usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7 | BIT6));
 	
 		/* clear Internal Data loopback mode */
 		info->loopback_bits = 0;
@@ -5447,13 +5447,13 @@
 		usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) );
 
 		usc_UnlatchRxstatusBits( info, RXSTATUS_ALL );
-		usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS );
+		usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS );
 		usc_EnableInterrupts( info, RECEIVE_STATUS );
 
 		/* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */
 		/* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */
 
-		usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 );
+		usc_OutDmaReg( info, RDIAR, BIT3 | BIT2 );
 		usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) );
 		usc_DmaCmd( info, DmaCmd_InitRxChannel );
 		if ( info->params.flags & HDLC_FLAG_AUTO_DCD )
@@ -5488,8 +5488,8 @@
 	usc_DmaCmd( info, DmaCmd_ResetRxChannel );
 
 	usc_UnlatchRxstatusBits( info, RXSTATUS_ALL );
-	usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS );
-	usc_DisableInterrupts( info, RECEIVE_DATA + RECEIVE_STATUS );
+	usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS );
+	usc_DisableInterrupts( info, RECEIVE_DATA | RECEIVE_STATUS );
 
 	usc_EnableReceiver(info,DISABLE_UNCONDITIONAL);
 
@@ -5536,13 +5536,13 @@
 		usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) );
 
 		usc_UnlatchRxstatusBits( info, RXSTATUS_ALL );
-		usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS );
+		usc_ClearIrqPendingBits( info, RECEIVE_DATA | RECEIVE_STATUS );
 		usc_EnableInterrupts( info, RECEIVE_STATUS );
 
 		/* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */
 		/* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */
 
-		usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 );
+		usc_OutDmaReg( info, RDIAR, BIT3 | BIT2 );
 		usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) );
 		usc_DmaCmd( info, DmaCmd_InitRxChannel );
 		if ( info->params.flags & HDLC_FLAG_AUTO_DCD )
@@ -5551,7 +5551,7 @@
 			usc_EnableReceiver(info,ENABLE_UNCONDITIONAL);
 	} else {
 		usc_UnlatchRxstatusBits(info, RXSTATUS_ALL);
-		usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS);
+		usc_ClearIrqPendingBits(info, RECEIVE_DATA | RECEIVE_STATUS);
 		usc_EnableInterrupts(info, RECEIVE_DATA);
 
 		usc_RTCmd( info, RTCmd_PurgeRxFifo );
@@ -5925,7 +5925,7 @@
 	RegValue = 0;
 
 	if ( info->params.data_bits != 8 )
-		RegValue |= BIT4+BIT3+BIT2;
+		RegValue |= BIT4 | BIT3 | BIT2;
 
 	if ( info->params.parity != ASYNC_PARITY_NONE ) {
 		RegValue |= BIT5;
@@ -5982,7 +5982,7 @@
 	RegValue = 0;
 
 	if ( info->params.data_bits != 8 )
-		RegValue |= BIT4+BIT3+BIT2;
+		RegValue |= BIT4 | BIT3 | BIT2;
 
 	if ( info->params.parity != ASYNC_PARITY_NONE ) {
 		RegValue |= BIT5;
@@ -6129,7 +6129,7 @@
 							
 	/* WAIT FOR RECEIVE COMPLETE */
 	for (i=0 ; i<1000 ; i++)
-		if (usc_InReg( info, RCSR ) & (BIT8 + BIT4 + BIT3 + BIT1))
+		if (usc_InReg( info, RCSR ) & (BIT8 | BIT4 | BIT3 | BIT1))
 			break;
 
 	/* clear Internal Data loopback mode */
@@ -6579,8 +6579,8 @@
 	
 	status = info->rx_buffer_list[EndIndex].status;
 
-	if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN +
-			RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) {
+	if ( status & (RXSTATUS_SHORT_FRAME | RXSTATUS_OVERRUN |
+			RXSTATUS_CRC_ERROR | RXSTATUS_ABORT) ) {
 		if ( status & RXSTATUS_SHORT_FRAME )
 			info->icount.rxshort++;
 		else if ( status & RXSTATUS_ABORT )
@@ -6762,8 +6762,8 @@
 
 		status = info->rx_buffer_list[CurrentIndex].status;
 
-		if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN +
-				RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) {
+		if ( status & (RXSTATUS_SHORT_FRAME | RXSTATUS_OVERRUN |
+				RXSTATUS_CRC_ERROR | RXSTATUS_ABORT) ) {
 			if ( status & RXSTATUS_SHORT_FRAME )
 				info->icount.rxshort++;
 			else if ( status & RXSTATUS_ABORT )
@@ -6899,7 +6899,7 @@
 		/* set CMR:13 to start transmit when
 		 * next GoAhead (abort) is received
 		 */
-	 	info->cmr_value |= BIT13;			  
+	 	info->cmr_value |= BIT13;
 	}
 		
 	/* begin loading the frame in the next available tx dma
@@ -7278,7 +7278,7 @@
 		
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
-						
+
 		/******************************/
 		/* WAIT FOR TRANSMIT COMPLETE */
 		/******************************/
@@ -7292,7 +7292,7 @@
 		status = usc_InReg( info, TCSR );
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
-		while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) {
+		while ( !(status & (BIT6 | BIT5 | BIT4 | BIT2 | BIT1)) ) {
 			if (time_after(jiffies, EndTime)) {
 				rc = false;
 				break;
@@ -7307,7 +7307,7 @@
 
 	if ( rc ){
 		/* CHECK FOR TRANSMIT ERRORS */
-		if ( status & (BIT5 + BIT1) ) 
+		if ( status & (BIT5 | BIT1) )
 			rc = false;
 	}
 
@@ -7333,7 +7333,7 @@
 		/* CHECK FOR RECEIVE ERRORS */
 		status = info->rx_buffer_list[0].status;
 
-		if ( status & (BIT8 + BIT3 + BIT1) ) {
+		if ( status & (BIT8 | BIT3 | BIT1) ) {
 			/* receive error has occurred */
 			rc = false;
 		} else {
@@ -7605,7 +7605,7 @@
 {
  	info->loopmode_send_done_requested = false;
  	/* clear CMR:13 to 0 to start echoing RxData to TxData */
- 	info->cmr_value &= ~BIT13;			  
+ 	info->cmr_value &= ~BIT13;
  	usc_OutReg(info, CMR, info->cmr_value);
 }
 
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 9121c1f..c043136f 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -18,31 +18,118 @@
 #include <linux/module.h>
 #include <linux/ratelimit.h>
 
+
+#define MIN_TTYB_SIZE	256
+#define TTYB_ALIGN_MASK	255
+
+/*
+ * Byte threshold to limit memory consumption for flip buffers.
+ * The actual memory limit is > 2x this amount.
+ */
+#define TTYB_MEM_LIMIT	65536
+
+/*
+ * We default to dicing tty buffer allocations to this many characters
+ * in order to avoid multiple page allocations. We know the size of
+ * tty_buffer itself but it must also be taken into account that the
+ * the buffer is 256 byte aligned. See tty_buffer_find for the allocation
+ * logic this must match
+ */
+
+#define TTY_BUFFER_PAGE	(((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
+
+
+/**
+ *	tty_buffer_lock_exclusive	-	gain exclusive access to buffer
+ *	tty_buffer_unlock_exclusive	-	release exclusive access
+ *
+ *	@port - tty_port owning the flip buffer
+ *
+ *	Guarantees safe use of the line discipline's receive_buf() method by
+ *	excluding the buffer work and any pending flush from using the flip
+ *	buffer. Data can continue to be added concurrently to the flip buffer
+ *	from the driver side.
+ *
+ *	On release, the buffer work is restarted if there is data in the
+ *	flip buffer
+ */
+
+void tty_buffer_lock_exclusive(struct tty_port *port)
+{
+	struct tty_bufhead *buf = &port->buf;
+
+	atomic_inc(&buf->priority);
+	mutex_lock(&buf->lock);
+}
+
+void tty_buffer_unlock_exclusive(struct tty_port *port)
+{
+	struct tty_bufhead *buf = &port->buf;
+	int restart;
+
+	restart = buf->head->commit != buf->head->read;
+
+	atomic_dec(&buf->priority);
+	mutex_unlock(&buf->lock);
+	if (restart)
+		queue_work(system_unbound_wq, &buf->work);
+}
+
+/**
+ *	tty_buffer_space_avail	-	return unused buffer space
+ *	@port - tty_port owning the flip buffer
+ *
+ *	Returns the # of bytes which can be written by the driver without
+ *	reaching the buffer limit.
+ *
+ *	Note: this does not guarantee that memory is available to write
+ *	the returned # of bytes (use tty_prepare_flip_string_xxx() to
+ *	pre-allocate if memory guarantee is required).
+ */
+
+int tty_buffer_space_avail(struct tty_port *port)
+{
+	int space = TTYB_MEM_LIMIT - atomic_read(&port->buf.memory_used);
+	return max(space, 0);
+}
+
+static void tty_buffer_reset(struct tty_buffer *p, size_t size)
+{
+	p->used = 0;
+	p->size = size;
+	p->next = NULL;
+	p->commit = 0;
+	p->read = 0;
+}
+
 /**
  *	tty_buffer_free_all		-	free buffers used by a tty
  *	@tty: tty to free from
  *
  *	Remove all the buffers pending on a tty whether queued with data
  *	or in the free ring. Must be called when the tty is no longer in use
- *
- *	Locking: none
  */
 
 void tty_buffer_free_all(struct tty_port *port)
 {
 	struct tty_bufhead *buf = &port->buf;
-	struct tty_buffer *thead;
+	struct tty_buffer *p, *next;
+	struct llist_node *llist;
 
-	while ((thead = buf->head) != NULL) {
-		buf->head = thead->next;
-		kfree(thead);
+	while ((p = buf->head) != NULL) {
+		buf->head = p->next;
+		if (p->size > 0)
+			kfree(p);
 	}
-	while ((thead = buf->free) != NULL) {
-		buf->free = thead->next;
-		kfree(thead);
-	}
-	buf->tail = NULL;
-	buf->memory_used = 0;
+	llist = llist_del_all(&buf->free);
+	llist_for_each_entry_safe(p, next, llist, free)
+		kfree(p);
+
+	tty_buffer_reset(&buf->sentinel, 0);
+	buf->head = &buf->sentinel;
+	buf->tail = &buf->sentinel;
+
+	atomic_set(&buf->memory_used, 0);
 }
 
 /**
@@ -51,29 +138,39 @@
  *	@size: desired size (characters)
  *
  *	Allocate a new tty buffer to hold the desired number of characters.
+ *	We round our buffers off in 256 character chunks to get better
+ *	allocation behaviour.
  *	Return NULL if out of memory or the allocation would exceed the
  *	per device queue
- *
- *	Locking: Caller must hold tty->buf.lock
  */
 
 static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
 {
+	struct llist_node *free;
 	struct tty_buffer *p;
 
-	if (port->buf.memory_used + size > 65536)
+	/* Round the buffer size out */
+	size = __ALIGN_MASK(size, TTYB_ALIGN_MASK);
+
+	if (size <= MIN_TTYB_SIZE) {
+		free = llist_del_first(&port->buf.free);
+		if (free) {
+			p = llist_entry(free, struct tty_buffer, free);
+			goto found;
+		}
+	}
+
+	/* Should possibly check if this fails for the largest buffer we
+	   have queued and recycle that ? */
+	if (atomic_read(&port->buf.memory_used) > TTYB_MEM_LIMIT)
 		return NULL;
 	p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
 	if (p == NULL)
 		return NULL;
-	p->used = 0;
-	p->size = size;
-	p->next = NULL;
-	p->commit = 0;
-	p->read = 0;
-	p->char_buf_ptr = (char *)(p->data);
-	p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-	port->buf.memory_used += size;
+
+found:
+	tty_buffer_reset(p, size);
+	atomic_add(size, &port->buf.memory_used);
 	return p;
 }
 
@@ -84,8 +181,6 @@
  *
  *	Free a tty buffer, or add it to the free list according to our
  *	internal strategy
- *
- *	Locking: Caller must hold tty->buf.lock
  */
 
 static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
@@ -93,41 +188,12 @@
 	struct tty_bufhead *buf = &port->buf;
 
 	/* Dumb strategy for now - should keep some stats */
-	buf->memory_used -= b->size;
-	WARN_ON(buf->memory_used < 0);
+	WARN_ON(atomic_sub_return(b->size, &buf->memory_used) < 0);
 
-	if (b->size >= 512)
+	if (b->size > MIN_TTYB_SIZE)
 		kfree(b);
-	else {
-		b->next = buf->free;
-		buf->free = b;
-	}
-}
-
-/**
- *	__tty_buffer_flush		-	flush full tty buffers
- *	@tty: tty to flush
- *
- *	flush all the buffers containing receive data. Caller must
- *	hold the buffer lock and must have ensured no parallel flush to
- *	ldisc is running.
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_port *port)
-{
-	struct tty_bufhead *buf = &port->buf;
-	struct tty_buffer *thead;
-
-	if (unlikely(buf->head == NULL))
-		return;
-	while ((thead = buf->head->next) != NULL) {
-		tty_buffer_free(port, buf->head);
-		buf->head = thead;
-	}
-	WARN_ON(buf->head != buf->tail);
-	buf->head->read = buf->head->commit;
+	else if (b->size > 0)
+		llist_add(&b->free, &buf->free);
 }
 
 /**
@@ -138,65 +204,28 @@
  *	being processed by flush_to_ldisc then we defer the processing
  *	to that function
  *
- *	Locking: none
+ *	Locking: takes buffer lock to ensure single-threaded flip buffer
+ *		 'consumer'
  */
 
 void tty_buffer_flush(struct tty_struct *tty)
 {
 	struct tty_port *port = tty->port;
 	struct tty_bufhead *buf = &port->buf;
-	unsigned long flags;
+	struct tty_buffer *next;
 
-	spin_lock_irqsave(&buf->lock, flags);
+	atomic_inc(&buf->priority);
 
-	/* If the data is being pushed to the tty layer then we can't
-	   process it here. Instead set a flag and the flush_to_ldisc
-	   path will process the flush request before it exits */
-	if (test_bit(TTYP_FLUSHING, &port->iflags)) {
-		set_bit(TTYP_FLUSHPENDING, &port->iflags);
-		spin_unlock_irqrestore(&buf->lock, flags);
-		wait_event(tty->read_wait,
-				test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0);
-		return;
-	} else
-		__tty_buffer_flush(port);
-	spin_unlock_irqrestore(&buf->lock, flags);
-}
-
-/**
- *	tty_buffer_find		-	find a free tty buffer
- *	@tty: tty owning the buffer
- *	@size: characters wanted
- *
- *	Locate an existing suitable tty buffer or if we are lacking one then
- *	allocate a new one. We round our buffers off in 256 character chunks
- *	to get better allocation behaviour.
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size)
-{
-	struct tty_buffer **tbh = &port->buf.free;
-	while ((*tbh) != NULL) {
-		struct tty_buffer *t = *tbh;
-		if (t->size >= size) {
-			*tbh = t->next;
-			t->next = NULL;
-			t->used = 0;
-			t->commit = 0;
-			t->read = 0;
-			port->buf.memory_used += t->size;
-			return t;
-		}
-		tbh = &((*tbh)->next);
+	mutex_lock(&buf->lock);
+	while ((next = buf->head->next) != NULL) {
+		tty_buffer_free(port, buf->head);
+		buf->head = next;
 	}
-	/* Round the buffer size out */
-	size = (size + 0xFF) & ~0xFF;
-	return tty_buffer_alloc(port, size);
-	/* Should possibly check if this fails for the largest buffer we
-	   have queued and recycle that ? */
+	buf->head->read = buf->head->commit;
+	atomic_dec(&buf->priority);
+	mutex_unlock(&buf->lock);
 }
+
 /**
  *	tty_buffer_request_room		-	grow tty buffer if needed
  *	@tty: tty structure
@@ -204,38 +233,26 @@
  *
  *	Make at least size bytes of linear space available for the tty
  *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes port->buf.lock
  */
 int tty_buffer_request_room(struct tty_port *port, size_t size)
 {
 	struct tty_bufhead *buf = &port->buf;
 	struct tty_buffer *b, *n;
 	int left;
-	unsigned long flags;
-	spin_lock_irqsave(&buf->lock, flags);
-	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-	   remove this conditional if its worth it. This would be invisible
-	   to the callers */
+
 	b = buf->tail;
-	if (b != NULL)
-		left = b->size - b->used;
-	else
-		left = 0;
+	left = b->size - b->used;
 
 	if (left < size) {
 		/* This is the slow path - looking for new buffers to use */
-		if ((n = tty_buffer_find(port, size)) != NULL) {
-			if (b != NULL) {
-				b->next = n;
-				b->commit = b->used;
-			} else
-				buf->head = n;
+		if ((n = tty_buffer_alloc(port, size)) != NULL) {
 			buf->tail = n;
+			b->commit = b->used;
+			smp_mb();
+			b->next = n;
 		} else
 			size = left;
 	}
-	spin_unlock_irqrestore(&buf->lock, flags);
 	return size;
 }
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
@@ -249,8 +266,6 @@
  *
  *	Queue a series of bytes to the tty buffering. All the characters
  *	passed are marked with the supplied flag. Returns the number added.
- *
- *	Locking: Called functions may take port->buf.lock
  */
 
 int tty_insert_flip_string_fixed_flag(struct tty_port *port,
@@ -261,12 +276,10 @@
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
 		int space = tty_buffer_request_room(port, goal);
 		struct tty_buffer *tb = port->buf.tail;
-		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0)) {
+		if (unlikely(space == 0))
 			break;
-		}
-		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memset(tb->flag_buf_ptr + tb->used, flag, space);
+		memcpy(char_buf_ptr(tb, tb->used), chars, space);
+		memset(flag_buf_ptr(tb, tb->used), flag, space);
 		tb->used += space;
 		copied += space;
 		chars += space;
@@ -287,8 +300,6 @@
  *	Queue a series of bytes to the tty buffering. For each character
  *	the flags array indicates the status of the character. Returns the
  *	number added.
- *
- *	Locking: Called functions may take port->buf.lock
  */
 
 int tty_insert_flip_string_flags(struct tty_port *port,
@@ -299,12 +310,10 @@
 		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
 		int space = tty_buffer_request_room(port, goal);
 		struct tty_buffer *tb = port->buf.tail;
-		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0)) {
+		if (unlikely(space == 0))
 			break;
-		}
-		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+		memcpy(char_buf_ptr(tb, tb->used), chars, space);
+		memcpy(flag_buf_ptr(tb, tb->used), flags, space);
 		tb->used += space;
 		copied += space;
 		chars += space;
@@ -325,20 +334,14 @@
  *	processing by the line discipline.
  *	Note that this function can only be used when the low_latency flag
  *	is unset. Otherwise the workqueue won't be flushed.
- *
- *	Locking: Takes port->buf.lock
  */
 
 void tty_schedule_flip(struct tty_port *port)
 {
 	struct tty_bufhead *buf = &port->buf;
-	unsigned long flags;
 	WARN_ON(port->low_latency);
 
-	spin_lock_irqsave(&buf->lock, flags);
-	if (buf->tail != NULL)
-		buf->tail->commit = buf->tail->used;
-	spin_unlock_irqrestore(&buf->lock, flags);
+	buf->tail->commit = buf->tail->used;
 	schedule_work(&buf->work);
 }
 EXPORT_SYMBOL(tty_schedule_flip);
@@ -354,8 +357,6 @@
  *	accounted for as ready for normal characters. This is used for drivers
  *	that need their own block copy routines into the buffer. There is no
  *	guarantee the buffer is a DMA target!
- *
- *	Locking: May call functions taking port->buf.lock
  */
 
 int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
@@ -364,8 +365,8 @@
 	int space = tty_buffer_request_room(port, size);
 	if (likely(space)) {
 		struct tty_buffer *tb = port->buf.tail;
-		*chars = tb->char_buf_ptr + tb->used;
-		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+		*chars = char_buf_ptr(tb, tb->used);
+		memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
 		tb->used += space;
 	}
 	return space;
@@ -384,8 +385,6 @@
  *	accounted for as ready for characters. This is used for drivers
  *	that need their own block copy routines into the buffer. There is no
  *	guarantee the buffer is a DMA target!
- *
- *	Locking: May call functions taking port->buf.lock
  */
 
 int tty_prepare_flip_string_flags(struct tty_port *port,
@@ -394,8 +393,8 @@
 	int space = tty_buffer_request_room(port, size);
 	if (likely(space)) {
 		struct tty_buffer *tb = port->buf.tail;
-		*chars = tb->char_buf_ptr + tb->used;
-		*flags = tb->flag_buf_ptr + tb->used;
+		*chars = char_buf_ptr(tb, tb->used);
+		*flags = flag_buf_ptr(tb, tb->used);
 		tb->used += space;
 	}
 	return space;
@@ -403,6 +402,23 @@
 EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
 
 
+static int
+receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
+{
+	struct tty_ldisc *disc = tty->ldisc;
+	unsigned char *p = char_buf_ptr(head, head->read);
+	char	      *f = flag_buf_ptr(head, head->read);
+
+	if (disc->ops->receive_buf2)
+		count = disc->ops->receive_buf2(tty, p, f, count);
+	else {
+		count = min_t(int, count, tty->receive_room);
+		if (count)
+			disc->ops->receive_buf(tty, p, f, count);
+	}
+	head->read += count;
+	return count;
+}
 
 /**
  *	flush_to_ldisc
@@ -411,9 +427,10 @@
  *	This routine is called out of the software interrupt to flush data
  *	from the buffer chain to the line discipline.
  *
- *	Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *	while invoking the line discipline receive_buf method. The
- *	receive_buf method is single threaded for each tty instance.
+ *	The receive_buf method is single threaded for each tty instance.
+ *
+ *	Locking: takes buffer lock to ensure single-threaded flip buffer
+ *		 'consumer'
  */
 
 static void flush_to_ldisc(struct work_struct *work)
@@ -421,7 +438,6 @@
 	struct tty_port *port = container_of(work, struct tty_port, buf.work);
 	struct tty_bufhead *buf = &port->buf;
 	struct tty_struct *tty;
-	unsigned long 	flags;
 	struct tty_ldisc *disc;
 
 	tty = port->itty;
@@ -429,52 +445,34 @@
 		return;
 
 	disc = tty_ldisc_ref(tty);
-	if (disc == NULL)	/*  !TTY_LDISC */
+	if (disc == NULL)
 		return;
 
-	spin_lock_irqsave(&buf->lock, flags);
+	mutex_lock(&buf->lock);
 
-	if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
-		struct tty_buffer *head;
-		while ((head = buf->head) != NULL) {
-			int count;
-			char *char_buf;
-			unsigned char *flag_buf;
+	while (1) {
+		struct tty_buffer *head = buf->head;
+		int count;
 
-			count = head->commit - head->read;
-			if (!count) {
-				if (head->next == NULL)
-					break;
-				buf->head = head->next;
-				tty_buffer_free(port, head);
-				continue;
-			}
-			if (!tty->receive_room)
+		/* Ldisc or user is trying to gain exclusive access */
+		if (atomic_read(&buf->priority))
+			break;
+
+		count = head->commit - head->read;
+		if (!count) {
+			if (head->next == NULL)
 				break;
-			if (count > tty->receive_room)
-				count = tty->receive_room;
-			char_buf = head->char_buf_ptr + head->read;
-			flag_buf = head->flag_buf_ptr + head->read;
-			head->read += count;
-			spin_unlock_irqrestore(&buf->lock, flags);
-			disc->ops->receive_buf(tty, char_buf,
-							flag_buf, count);
-			spin_lock_irqsave(&buf->lock, flags);
-			/* Ldisc or user is trying to flush the buffers.
-			   We may have a deferred request to flush the
-			   input buffer, if so pull the chain under the lock
-			   and empty the queue */
-			if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
-				__tty_buffer_flush(port);
-				clear_bit(TTYP_FLUSHPENDING, &port->iflags);
-				wake_up(&tty->read_wait);
-				break;
-			}
+			buf->head = head->next;
+			tty_buffer_free(port, head);
+			continue;
 		}
-		clear_bit(TTYP_FLUSHING, &port->iflags);
+
+		count = receive_buf(tty, head, count);
+		if (!count)
+			break;
 	}
 
-	spin_unlock_irqrestore(&buf->lock, flags);
+	mutex_unlock(&buf->lock);
 
 	tty_ldisc_deref(disc);
 }
@@ -503,19 +501,13 @@
  *
  *	In the event of the queue being busy for flipping the work will be
  *	held off and retried later.
- *
- *	Locking: tty buffer lock. Driver locks in low latency mode.
  */
 
 void tty_flip_buffer_push(struct tty_port *port)
 {
 	struct tty_bufhead *buf = &port->buf;
-	unsigned long flags;
 
-	spin_lock_irqsave(&buf->lock, flags);
-	if (buf->tail != NULL)
-		buf->tail->commit = buf->tail->used;
-	spin_unlock_irqrestore(&buf->lock, flags);
+	buf->tail->commit = buf->tail->used;
 
 	if (port->low_latency)
 		flush_to_ldisc(&buf->work);
@@ -530,19 +522,18 @@
  *
  *	Set up the initial state of the buffer management for a tty device.
  *	Must be called before the other tty buffer functions are used.
- *
- *	Locking: none
  */
 
 void tty_buffer_init(struct tty_port *port)
 {
 	struct tty_bufhead *buf = &port->buf;
 
-	spin_lock_init(&buf->lock);
-	buf->head = NULL;
-	buf->tail = NULL;
-	buf->free = NULL;
-	buf->memory_used = 0;
+	mutex_init(&buf->lock);
+	tty_buffer_reset(&buf->sentinel, 0);
+	buf->head = &buf->sentinel;
+	buf->tail = &buf->sentinel;
+	init_llist_head(&buf->free);
+	atomic_set(&buf->memory_used, 0);
+	atomic_set(&buf->priority, 0);
 	INIT_WORK(&buf->work, flush_to_ldisc);
 }
-
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 366af83..a9355ce 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -603,8 +603,8 @@
  *		BTM
  *		  redirect lock for undoing redirection
  *		  file list lock for manipulating list of ttys
- *		  tty_ldisc_lock from called functions
- *		  termios_mutex resetting termios data
+ *		  tty_ldiscs_lock from called functions
+ *		  termios_rwsem resetting termios data
  *		  tasklist_lock to walk task list for hangup event
  *		    ->siglock to protect ->signal/->sighand
  */
@@ -629,6 +629,11 @@
 
 	tty_lock(tty);
 
+	if (test_bit(TTY_HUPPED, &tty->flags)) {
+		tty_unlock(tty);
+		return;
+	}
+
 	/* some functions below drop BTM, so we need this bit */
 	set_bit(TTY_HUPPING, &tty->flags);
 
@@ -664,7 +669,6 @@
 
 	spin_lock_irq(&tty->ctrl_lock);
 	clear_bit(TTY_THROTTLED, &tty->flags);
-	clear_bit(TTY_PUSH, &tty->flags);
 	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	put_pid(tty->session);
 	put_pid(tty->pgrp);
@@ -1388,8 +1392,7 @@
 	struct tty_driver *driver = tty->driver;
 
 	if (test_bit(TTY_CLOSING, &tty->flags) ||
-			test_bit(TTY_HUPPING, &tty->flags) ||
-			test_bit(TTY_LDISC_CHANGING, &tty->flags))
+			test_bit(TTY_HUPPING, &tty->flags))
 		return -EIO;
 
 	if (driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -1405,7 +1408,7 @@
 	}
 	tty->count++;
 
-	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+	WARN_ON(!tty->ldisc);
 
 	return 0;
 }
@@ -2202,7 +2205,7 @@
  *	FIXME: does not honour flow control ??
  *
  *	Locking:
- *		Called functions take tty_ldisc_lock
+ *		Called functions take tty_ldiscs_lock
  *		current->signal->tty check is safe without locks
  *
  *	FIXME: may race normal receive processing
@@ -2231,7 +2234,7 @@
  *
  *	Copies the kernel idea of the window size into the user buffer.
  *
- *	Locking: tty->termios_mutex is taken to ensure the winsize data
+ *	Locking: tty->winsize_mutex is taken to ensure the winsize data
  *		is consistent.
  */
 
@@ -2239,9 +2242,9 @@
 {
 	int err;
 
-	mutex_lock(&tty->termios_mutex);
+	mutex_lock(&tty->winsize_mutex);
 	err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-	mutex_unlock(&tty->termios_mutex);
+	mutex_unlock(&tty->winsize_mutex);
 
 	return err ? -EFAULT: 0;
 }
@@ -2262,7 +2265,7 @@
 	unsigned long flags;
 
 	/* Lock the tty */
-	mutex_lock(&tty->termios_mutex);
+	mutex_lock(&tty->winsize_mutex);
 	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
 		goto done;
 	/* Get the PID values and reference them so we can
@@ -2277,7 +2280,7 @@
 
 	tty->winsize = *ws;
 done:
-	mutex_unlock(&tty->termios_mutex);
+	mutex_unlock(&tty->winsize_mutex);
 	return 0;
 }
 EXPORT_SYMBOL(tty_do_resize);
@@ -3016,8 +3019,10 @@
 	tty->session = NULL;
 	tty->pgrp = NULL;
 	mutex_init(&tty->legacy_mutex);
-	mutex_init(&tty->termios_mutex);
-	mutex_init(&tty->ldisc_mutex);
+	mutex_init(&tty->throttle_mutex);
+	init_rwsem(&tty->termios_rwsem);
+	mutex_init(&tty->winsize_mutex);
+	init_ldsem(&tty->ldisc_sem);
 	init_waitqueue_head(&tty->write_wait);
 	init_waitqueue_head(&tty->read_wait);
 	INIT_WORK(&tty->hangup_work, do_tty_hangup);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 3500d41..03ba081 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -94,20 +94,20 @@
  *	@tty: terminal
  *
  *	Indicate that a tty should stop transmitting data down the stack.
- *	Takes the termios mutex to protect against parallel throttle/unthrottle
+ *	Takes the termios rwsem to protect against parallel throttle/unthrottle
  *	and also to ensure the driver can consistently reference its own
  *	termios data at this point when implementing software flow control.
  */
 
 void tty_throttle(struct tty_struct *tty)
 {
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	/* check TTY_THROTTLED first so it indicates our state */
 	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
 	    tty->ops->throttle)
 		tty->ops->throttle(tty);
 	tty->flow_change = 0;
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 }
 EXPORT_SYMBOL(tty_throttle);
 
@@ -116,7 +116,7 @@
  *	@tty: terminal
  *
  *	Indicate that a tty may continue transmitting data down the stack.
- *	Takes the termios mutex to protect against parallel throttle/unthrottle
+ *	Takes the termios rwsem to protect against parallel throttle/unthrottle
  *	and also to ensure the driver can consistently reference its own
  *	termios data at this point when implementing software flow control.
  *
@@ -126,12 +126,12 @@
 
 void tty_unthrottle(struct tty_struct *tty)
 {
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
 	    tty->ops->unthrottle)
 		tty->ops->unthrottle(tty);
 	tty->flow_change = 0;
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 }
 EXPORT_SYMBOL(tty_unthrottle);
 
@@ -151,7 +151,7 @@
 {
 	int ret = 0;
 
-	mutex_lock(&tty->termios_mutex);
+	mutex_lock(&tty->throttle_mutex);
 	if (!test_bit(TTY_THROTTLED, &tty->flags)) {
 		if (tty->flow_change != TTY_THROTTLE_SAFE)
 			ret = 1;
@@ -161,7 +161,7 @@
 				tty->ops->throttle(tty);
 		}
 	}
-	mutex_unlock(&tty->termios_mutex);
+	mutex_unlock(&tty->throttle_mutex);
 
 	return ret;
 }
@@ -182,7 +182,7 @@
 {
 	int ret = 0;
 
-	mutex_lock(&tty->termios_mutex);
+	mutex_lock(&tty->throttle_mutex);
 	if (test_bit(TTY_THROTTLED, &tty->flags)) {
 		if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
 			ret = 1;
@@ -192,7 +192,7 @@
 				tty->ops->unthrottle(tty);
 		}
 	}
-	mutex_unlock(&tty->termios_mutex);
+	mutex_unlock(&tty->throttle_mutex);
 
 	return ret;
 }
@@ -468,7 +468,7 @@
  *	@obad: output baud rate
  *
  *	Update the current termios data for the tty with the new speed
- *	settings. The caller must hold the termios_mutex for the tty in
+ *	settings. The caller must hold the termios_rwsem for the tty in
  *	question.
  */
 
@@ -528,7 +528,7 @@
  *	is a bit of layering violation here with n_tty in terms of the
  *	internal knowledge of this function.
  *
- *	Locking: termios_mutex
+ *	Locking: termios_rwsem
  */
 
 int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
@@ -544,7 +544,7 @@
 
 	/* FIXME: we need to decide on some locking/ordering semantics
 	   for the set_termios notification eventually */
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	old_termios = tty->termios;
 	tty->termios = *new_termios;
 	unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
@@ -586,7 +586,7 @@
 			(ld->ops->set_termios)(tty, &old_termios);
 		tty_ldisc_deref(ld);
 	}
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(tty_set_termios);
@@ -601,7 +601,7 @@
  *	functions before using tty_set_termios to do the actual changes.
  *
  *	Locking:
- *		Called functions take ldisc and termios_mutex locks
+ *		Called functions take ldisc and termios_rwsem locks
  */
 
 static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
@@ -613,9 +613,9 @@
 	if (retval)
 		return retval;
 
-	mutex_lock(&tty->termios_mutex);
+	down_read(&tty->termios_rwsem);
 	tmp_termios = tty->termios;
-	mutex_unlock(&tty->termios_mutex);
+	up_read(&tty->termios_rwsem);
 
 	if (opt & TERMIOS_TERMIO) {
 		if (user_termio_to_kernel_termios(&tmp_termios,
@@ -667,16 +667,16 @@
 
 static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
 {
-	mutex_lock(&tty->termios_mutex);
+	down_read(&tty->termios_rwsem);
 	*kterm = tty->termios;
-	mutex_unlock(&tty->termios_mutex);
+	up_read(&tty->termios_rwsem);
 }
 
 static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
 {
-	mutex_lock(&tty->termios_mutex);
+	down_read(&tty->termios_rwsem);
 	*kterm = tty->termios_locked;
-	mutex_unlock(&tty->termios_mutex);
+	up_read(&tty->termios_rwsem);
 }
 
 static int get_termio(struct tty_struct *tty, struct termio __user *termio)
@@ -723,10 +723,10 @@
 			return -ERESTARTSYS;
 	}
 
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	if (tty->ops->set_termiox)
 		tty->ops->set_termiox(tty, &tnew);
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 	return 0;
 }
 
@@ -761,13 +761,13 @@
 {
 	struct sgttyb tmp;
 
-	mutex_lock(&tty->termios_mutex);
+	down_read(&tty->termios_rwsem);
 	tmp.sg_ispeed = tty->termios.c_ispeed;
 	tmp.sg_ospeed = tty->termios.c_ospeed;
 	tmp.sg_erase = tty->termios.c_cc[VERASE];
 	tmp.sg_kill = tty->termios.c_cc[VKILL];
 	tmp.sg_flags = get_sgflags(tty);
-	mutex_unlock(&tty->termios_mutex);
+	up_read(&tty->termios_rwsem);
 
 	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
@@ -806,7 +806,7 @@
  *	Updates a terminal from the legacy BSD style terminal information
  *	structure.
  *
- *	Locking: termios_mutex
+ *	Locking: termios_rwsem
  */
 
 static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
@@ -822,7 +822,7 @@
 	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
 		return -EFAULT;
 
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	termios = tty->termios;
 	termios.c_cc[VERASE] = tmp.sg_erase;
 	termios.c_cc[VKILL] = tmp.sg_kill;
@@ -832,7 +832,7 @@
 	tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
 						termios.c_ospeed);
 #endif
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 	tty_set_termios(tty, &termios);
 	return 0;
 }
@@ -843,14 +843,14 @@
 {
 	struct tchars tmp;
 
-	mutex_lock(&tty->termios_mutex);
+	down_read(&tty->termios_rwsem);
 	tmp.t_intrc = tty->termios.c_cc[VINTR];
 	tmp.t_quitc = tty->termios.c_cc[VQUIT];
 	tmp.t_startc = tty->termios.c_cc[VSTART];
 	tmp.t_stopc = tty->termios.c_cc[VSTOP];
 	tmp.t_eofc = tty->termios.c_cc[VEOF];
 	tmp.t_brkc = tty->termios.c_cc[VEOL2];	/* what is brkc anyway? */
-	mutex_unlock(&tty->termios_mutex);
+	up_read(&tty->termios_rwsem);
 	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
@@ -860,14 +860,14 @@
 
 	if (copy_from_user(&tmp, tchars, sizeof(tmp)))
 		return -EFAULT;
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	tty->termios.c_cc[VINTR] = tmp.t_intrc;
 	tty->termios.c_cc[VQUIT] = tmp.t_quitc;
 	tty->termios.c_cc[VSTART] = tmp.t_startc;
 	tty->termios.c_cc[VSTOP] = tmp.t_stopc;
 	tty->termios.c_cc[VEOF] = tmp.t_eofc;
 	tty->termios.c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 	return 0;
 }
 #endif
@@ -877,7 +877,7 @@
 {
 	struct ltchars tmp;
 
-	mutex_lock(&tty->termios_mutex);
+	down_read(&tty->termios_rwsem);
 	tmp.t_suspc = tty->termios.c_cc[VSUSP];
 	/* what is dsuspc anyway? */
 	tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
@@ -886,7 +886,7 @@
 	tmp.t_flushc = tty->termios.c_cc[VEOL2];
 	tmp.t_werasc = tty->termios.c_cc[VWERASE];
 	tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
-	mutex_unlock(&tty->termios_mutex);
+	up_read(&tty->termios_rwsem);
 	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
@@ -897,7 +897,7 @@
 	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
 		return -EFAULT;
 
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	tty->termios.c_cc[VSUSP] = tmp.t_suspc;
 	/* what is dsuspc anyway? */
 	tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
@@ -906,7 +906,7 @@
 	tty->termios.c_cc[VEOL2] = tmp.t_flushc;
 	tty->termios.c_cc[VWERASE] = tmp.t_werasc;
 	tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 	return 0;
 }
 #endif
@@ -946,7 +946,7 @@
  *	@arg: enable/disable CLOCAL
  *
  *	Perform a change to the CLOCAL state and call into the driver
- *	layer to make it visible. All done with the termios mutex
+ *	layer to make it visible. All done with the termios rwsem
  */
 
 static int tty_change_softcar(struct tty_struct *tty, int arg)
@@ -955,7 +955,7 @@
 	int bit = arg ? CLOCAL : 0;
 	struct ktermios old;
 
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	old = tty->termios;
 	tty->termios.c_cflag &= ~CLOCAL;
 	tty->termios.c_cflag |= bit;
@@ -963,7 +963,7 @@
 		tty->ops->set_termios(tty, &old);
 	if ((tty->termios.c_cflag & CLOCAL) != bit)
 		ret = -EINVAL;
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 	return ret;
 }
 
@@ -1066,9 +1066,9 @@
 		if (user_termios_to_kernel_termios(&kterm,
 					       (struct termios __user *) arg))
 			return -EFAULT;
-		mutex_lock(&real_tty->termios_mutex);
+		down_write(&real_tty->termios_rwsem);
 		real_tty->termios_locked = kterm;
-		mutex_unlock(&real_tty->termios_mutex);
+		up_write(&real_tty->termios_rwsem);
 		return 0;
 #else
 	case TIOCGLCKTRMIOS:
@@ -1083,9 +1083,9 @@
 		if (user_termios_to_kernel_termios_1(&kterm,
 					       (struct termios __user *) arg))
 			return -EFAULT;
-		mutex_lock(&real_tty->termios_mutex);
+		down_write(&real_tty->termios_rwsem);
 		real_tty->termios_locked = kterm;
-		mutex_unlock(&real_tty->termios_mutex);
+		up_write(&real_tty->termios_rwsem);
 		return ret;
 #endif
 #ifdef TCGETX
@@ -1093,9 +1093,9 @@
 		struct termiox ktermx;
 		if (real_tty->termiox == NULL)
 			return -EINVAL;
-		mutex_lock(&real_tty->termios_mutex);
+		down_read(&real_tty->termios_rwsem);
 		memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
-		mutex_unlock(&real_tty->termios_mutex);
+		up_read(&real_tty->termios_rwsem);
 		if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
 			ret = -EFAULT;
 		return ret;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 1afe192..6458e11 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -31,14 +31,20 @@
 #define tty_ldisc_debug(tty, f, args...)
 #endif
 
+/* lockdep nested classes for tty->ldisc_sem */
+enum {
+	LDISC_SEM_NORMAL,
+	LDISC_SEM_OTHER,
+};
+
+
 /*
  *	This guards the refcounted line discipline lists. The lock
  *	must be taken with irqs off because there are hangup path
  *	callers who will do ldisc lookups and cannot sleep.
  */
 
-static DEFINE_RAW_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+static DEFINE_RAW_SPINLOCK(tty_ldiscs_lock);
 /* Line disc dispatch table */
 static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
 
@@ -52,7 +58,7 @@
  *	from this point onwards.
  *
  *	Locking:
- *		takes tty_ldisc_lock to guard against ldisc races
+ *		takes tty_ldiscs_lock to guard against ldisc races
  */
 
 int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
@@ -63,11 +69,11 @@
 	if (disc < N_TTY || disc >= NR_LDISCS)
 		return -EINVAL;
 
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
 	tty_ldiscs[disc] = new_ldisc;
 	new_ldisc->num = disc;
 	new_ldisc->refcount = 0;
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
 
 	return ret;
 }
@@ -82,7 +88,7 @@
  *	currently in use.
  *
  *	Locking:
- *		takes tty_ldisc_lock to guard against ldisc races
+ *		takes tty_ldiscs_lock to guard against ldisc races
  */
 
 int tty_unregister_ldisc(int disc)
@@ -93,12 +99,12 @@
 	if (disc < N_TTY || disc >= NR_LDISCS)
 		return -EINVAL;
 
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
 	if (tty_ldiscs[disc]->refcount)
 		ret = -EBUSY;
 	else
 		tty_ldiscs[disc] = NULL;
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
 
 	return ret;
 }
@@ -109,7 +115,7 @@
 	unsigned long flags;
 	struct tty_ldisc_ops *ldops, *ret;
 
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
 	ret = ERR_PTR(-EINVAL);
 	ldops = tty_ldiscs[disc];
 	if (ldops) {
@@ -119,7 +125,7 @@
 			ret = ldops;
 		}
 	}
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
 	return ret;
 }
 
@@ -127,10 +133,10 @@
 {
 	unsigned long flags;
 
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
 	ldops->refcount--;
 	module_put(ldops->owner);
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
 }
 
 /**
@@ -143,10 +149,10 @@
  *	available
  *
  *	Locking:
- *		takes tty_ldisc_lock to guard against ldisc races
+ *		takes tty_ldiscs_lock to guard against ldisc races
  */
 
-static struct tty_ldisc *tty_ldisc_get(int disc)
+static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
 {
 	struct tty_ldisc *ld;
 	struct tty_ldisc_ops *ldops;
@@ -173,8 +179,7 @@
 	}
 
 	ld->ops = ldops;
-	atomic_set(&ld->users, 1);
-	init_waitqueue_head(&ld->wq_idle);
+	ld->tty = tty;
 
 	return ld;
 }
@@ -186,20 +191,11 @@
  */
 static inline void tty_ldisc_put(struct tty_ldisc *ld)
 {
-	unsigned long flags;
-
 	if (WARN_ON_ONCE(!ld))
 		return;
 
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
-
-	/* unreleased reader reference(s) will cause this WARN */
-	WARN_ON(!atomic_dec_and_test(&ld->users));
-
-	ld->ops->refcount--;
-	module_put(ld->ops->owner);
+	put_ldops(ld->ops);
 	kfree(ld);
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
 }
 
 static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
@@ -251,34 +247,6 @@
 };
 
 /**
- *	tty_ldisc_try		-	internal helper
- *	@tty: the tty
- *
- *	Make a single attempt to grab and bump the refcount on
- *	the tty ldisc. Return 0 on failure or 1 on success. This is
- *	used to implement both the waiting and non waiting versions
- *	of tty_ldisc_ref
- *
- *	Locking: takes tty_ldisc_lock
- */
-
-static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
-{
-	unsigned long flags;
-	struct tty_ldisc *ld;
-
-	/* FIXME: this allows reference acquire after TTY_LDISC is cleared */
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
-	ld = NULL;
-	if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) {
-		ld = tty->ldisc;
-		atomic_inc(&ld->users);
-	}
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-	return ld;
-}
-
-/**
  *	tty_ldisc_ref_wait	-	wait for the tty ldisc
  *	@tty: tty device
  *
@@ -291,16 +259,15 @@
  *	against a discipline change, such as an existing ldisc reference
  *	(which we check for)
  *
- *	Locking: call functions take tty_ldisc_lock
+ *	Note: only callable from a file_operations routine (which
+ *	guarantees tty->ldisc != NULL when the lock is acquired).
  */
 
 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
 {
-	struct tty_ldisc *ld;
-
-	/* wait_event is a macro */
-	wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
-	return ld;
+	ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
+	WARN_ON(!tty->ldisc);
+	return tty->ldisc;
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
 
@@ -311,13 +278,18 @@
  *	Dereference the line discipline for the terminal and take a
  *	reference to it. If the line discipline is in flux then
  *	return NULL. Can be called from IRQ and timer functions.
- *
- *	Locking: called functions take tty_ldisc_lock
  */
 
 struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
 {
-	return tty_ldisc_try(tty);
+	struct tty_ldisc *ld = NULL;
+
+	if (ldsem_down_read_trylock(&tty->ldisc_sem)) {
+		ld = tty->ldisc;
+		if (!ld)
+			ldsem_up_read(&tty->ldisc_sem);
+	}
+	return ld;
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_ref);
 
@@ -327,48 +299,91 @@
  *
  *	Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
  *	be called in IRQ context.
- *
- *	Locking: takes tty_ldisc_lock
  */
 
 void tty_ldisc_deref(struct tty_ldisc *ld)
 {
-	unsigned long flags;
-
-	if (WARN_ON_ONCE(!ld))
-		return;
-
-	raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
-	/*
-	 * WARNs if one-too-many reader references were released
-	 * - the last reference must be released with tty_ldisc_put
-	 */
-	WARN_ON(atomic_dec_and_test(&ld->users));
-	raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-	if (waitqueue_active(&ld->wq_idle))
-		wake_up(&ld->wq_idle);
+	ldsem_up_read(&ld->tty->ldisc_sem);
 }
 EXPORT_SYMBOL_GPL(tty_ldisc_deref);
 
-/**
- *	tty_ldisc_enable	-	allow ldisc use
- *	@tty: terminal to activate ldisc on
- *
- *	Set the TTY_LDISC flag when the line discipline can be called
- *	again. Do necessary wakeups for existing sleepers. Clear the LDISC
- *	changing flag to indicate any ldisc change is now over.
- *
- *	Note: nobody should set the TTY_LDISC bit except via this function.
- *	Clearing directly is allowed.
- */
 
-static void tty_ldisc_enable(struct tty_struct *tty)
+static inline int __lockfunc
+tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
+{
+	return ldsem_down_write(&tty->ldisc_sem, timeout);
+}
+
+static inline int __lockfunc
+tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
+{
+	return ldsem_down_write_nested(&tty->ldisc_sem,
+				       LDISC_SEM_OTHER, timeout);
+}
+
+static inline void tty_ldisc_unlock(struct tty_struct *tty)
+{
+	return ldsem_up_write(&tty->ldisc_sem);
+}
+
+static int __lockfunc
+tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
+			    unsigned long timeout)
+{
+	int ret;
+
+	if (tty < tty2) {
+		ret = tty_ldisc_lock(tty, timeout);
+		if (ret) {
+			ret = tty_ldisc_lock_nested(tty2, timeout);
+			if (!ret)
+				tty_ldisc_unlock(tty);
+		}
+	} else {
+		/* if this is possible, it has lots of implications */
+		WARN_ON_ONCE(tty == tty2);
+		if (tty2 && tty != tty2) {
+			ret = tty_ldisc_lock(tty2, timeout);
+			if (ret) {
+				ret = tty_ldisc_lock_nested(tty, timeout);
+				if (!ret)
+					tty_ldisc_unlock(tty2);
+			}
+		} else
+			ret = tty_ldisc_lock(tty, timeout);
+	}
+
+	if (!ret)
+		return -EBUSY;
+
+	set_bit(TTY_LDISC_HALTED, &tty->flags);
+	if (tty2)
+		set_bit(TTY_LDISC_HALTED, &tty2->flags);
+	return 0;
+}
+
+static void __lockfunc
+tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
+{
+	tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
+}
+
+static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
+					     struct tty_struct *tty2)
+{
+	tty_ldisc_unlock(tty);
+	if (tty2)
+		tty_ldisc_unlock(tty2);
+}
+
+static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
+					     struct tty_struct *tty2)
 {
 	clear_bit(TTY_LDISC_HALTED, &tty->flags);
-	set_bit(TTY_LDISC, &tty->flags);
-	clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-	wake_up(&tty_ldisc_wait);
+	if (tty2)
+		clear_bit(TTY_LDISC_HALTED, &tty2->flags);
+
+	tty_ldisc_unlock_pair(tty, tty2);
 }
 
 /**
@@ -400,14 +415,14 @@
  *	they are not on hot paths so a little discipline won't do
  *	any harm.
  *
- *	Locking: takes termios_mutex
+ *	Locking: takes termios_rwsem
  */
 
 static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 {
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	tty->termios.c_line = num;
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 }
 
 /**
@@ -468,14 +483,14 @@
 	int r;
 
 	/* There is an outstanding reference here so this is safe */
-	old = tty_ldisc_get(old->ops->num);
+	old = tty_ldisc_get(tty, old->ops->num);
 	WARN_ON(IS_ERR(old));
 	tty->ldisc = old;
 	tty_set_termios_ldisc(tty, old->ops->num);
 	if (tty_ldisc_open(tty, old) < 0) {
 		tty_ldisc_put(old);
 		/* This driver is always present */
-		new_ldisc = tty_ldisc_get(N_TTY);
+		new_ldisc = tty_ldisc_get(tty, N_TTY);
 		if (IS_ERR(new_ldisc))
 			panic("n_tty: get");
 		tty->ldisc = new_ldisc;
@@ -489,101 +504,6 @@
 }
 
 /**
- *	tty_ldisc_wait_idle	-	wait for the ldisc to become idle
- *	@tty: tty to wait for
- *	@timeout: for how long to wait at most
- *
- *	Wait for the line discipline to become idle. The discipline must
- *	have been halted for this to guarantee it remains idle.
- */
-static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
-{
-	long ret;
-	ret = wait_event_timeout(tty->ldisc->wq_idle,
-			atomic_read(&tty->ldisc->users) == 1, timeout);
-	return ret > 0 ? 0 : -EBUSY;
-}
-
-/**
- *	tty_ldisc_halt		-	shut down the line discipline
- *	@tty: tty device
- *	@o_tty: paired pty device (can be NULL)
- *	@timeout: # of jiffies to wait for ldisc refs to be released
- *
- *	Shut down the line discipline and work queue for this tty device and
- *	its paired pty (if exists). Clearing the TTY_LDISC flag ensures
- *	no further references can be obtained, while waiting for existing
- *	references to be released ensures no more data is fed to the ldisc.
- *
- *	You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
- *	in order to make sure any currently executing ldisc work is also
- *	flushed.
- */
-
-static int tty_ldisc_halt(struct tty_struct *tty, struct tty_struct *o_tty,
-			  long timeout)
-{
-	int retval;
-
-	clear_bit(TTY_LDISC, &tty->flags);
-	if (o_tty)
-		clear_bit(TTY_LDISC, &o_tty->flags);
-
-	retval = tty_ldisc_wait_idle(tty, timeout);
-	if (!retval && o_tty)
-		retval = tty_ldisc_wait_idle(o_tty, timeout);
-	if (retval)
-		return retval;
-
-	set_bit(TTY_LDISC_HALTED, &tty->flags);
-	if (o_tty)
-		set_bit(TTY_LDISC_HALTED, &o_tty->flags);
-
-	return 0;
-}
-
-/**
- *	tty_ldisc_hangup_halt - halt the line discipline for hangup
- *	@tty: tty being hung up
- *
- *	Shut down the line discipline and work queue for the tty device
- *	being hungup. Clear the TTY_LDISC flag to ensure no further
- *	references can be obtained and wait for remaining references to be
- *	released to ensure no more data is fed to this ldisc.
- *	Caller must hold legacy and ->ldisc_mutex.
- *
- *	NB: tty_set_ldisc() is prevented from changing the ldisc concurrently
- *	with this function by checking the TTY_HUPPING flag.
- */
-static bool tty_ldisc_hangup_halt(struct tty_struct *tty)
-{
-	char cur_n[TASK_COMM_LEN], tty_n[64];
-	long timeout = 3 * HZ;
-
-	clear_bit(TTY_LDISC, &tty->flags);
-
-	if (tty->ldisc) {	/* Not yet closed */
-		tty_unlock(tty);
-
-		while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
-			timeout = MAX_SCHEDULE_TIMEOUT;
-			printk_ratelimited(KERN_WARNING
-				"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
-				__func__, get_task_comm(cur_n, current),
-				tty_name(tty, tty_n));
-		}
-
-		set_bit(TTY_LDISC_HALTED, &tty->flags);
-
-		/* must reacquire both locks and preserve lock order */
-		mutex_unlock(&tty->ldisc_mutex);
-		tty_lock(tty);
-		mutex_lock(&tty->ldisc_mutex);
-	}
-	return !!tty->ldisc;
-}
-
-/**
  *	tty_set_ldisc		-	set line discipline
  *	@tty: the terminal to set
  *	@ldisc: the line discipline
@@ -592,110 +512,49 @@
  *	context. The ldisc change logic has to protect itself against any
  *	overlapping ldisc change (including on the other end of pty pairs),
  *	the close of one side of a tty/pty pair, and eventually hangup.
- *
- *	Locking: takes tty_ldisc_lock, termios_mutex
  */
 
 int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
 	int retval;
-	struct tty_ldisc *o_ldisc, *new_ldisc;
-	struct tty_struct *o_tty;
+	struct tty_ldisc *old_ldisc, *new_ldisc;
+	struct tty_struct *o_tty = tty->link;
 
-	new_ldisc = tty_ldisc_get(ldisc);
+	new_ldisc = tty_ldisc_get(tty, ldisc);
 	if (IS_ERR(new_ldisc))
 		return PTR_ERR(new_ldisc);
 
-	tty_lock(tty);
-	/*
-	 *	We need to look at the tty locking here for pty/tty pairs
-	 *	when both sides try to change in parallel.
-	 */
-
-	o_tty = tty->link;	/* o_tty is the pty side or NULL */
-
+	retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
+	if (retval) {
+		tty_ldisc_put(new_ldisc);
+		return retval;
+	}
 
 	/*
 	 *	Check the no-op case
 	 */
 
 	if (tty->ldisc->ops->num == ldisc) {
-		tty_unlock(tty);
+		tty_ldisc_enable_pair(tty, o_tty);
 		tty_ldisc_put(new_ldisc);
 		return 0;
 	}
 
-	mutex_lock(&tty->ldisc_mutex);
-
-	/*
-	 *	We could be midstream of another ldisc change which has
-	 *	dropped the lock during processing. If so we need to wait.
-	 */
-
-	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
-		mutex_unlock(&tty->ldisc_mutex);
-		tty_unlock(tty);
-		wait_event(tty_ldisc_wait,
-			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-		tty_lock(tty);
-		mutex_lock(&tty->ldisc_mutex);
-	}
-
-	set_bit(TTY_LDISC_CHANGING, &tty->flags);
-
-	/*
-	 *	No more input please, we are switching. The new ldisc
-	 *	will update this value in the ldisc open function
-	 */
-
-	tty->receive_room = 0;
-
-	o_ldisc = tty->ldisc;
-
-	tty_unlock(tty);
-	/*
-	 *	Make sure we don't change while someone holds a
-	 *	reference to the line discipline. The TTY_LDISC bit
-	 *	prevents anyone taking a reference once it is clear.
-	 *	We need the lock to avoid racing reference takers.
-	 *
-	 *	We must clear the TTY_LDISC bit here to avoid a livelock
-	 *	with a userspace app continually trying to use the tty in
-	 *	parallel to the change and re-referencing the tty.
-	 */
-
-	retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);
-
-	/*
-	 * Wait for hangup to complete, if pending.
-	 * We must drop the mutex here in case a hangup is also in process.
-	 */
-
-	mutex_unlock(&tty->ldisc_mutex);
-
-	flush_work(&tty->hangup_work);
-
+	old_ldisc = tty->ldisc;
 	tty_lock(tty);
-	mutex_lock(&tty->ldisc_mutex);
 
-	/* handle wait idle failure locked */
-	if (retval) {
-		tty_ldisc_put(new_ldisc);
-		goto enable;
-	}
-
-	if (test_bit(TTY_HUPPING, &tty->flags)) {
+	if (test_bit(TTY_HUPPING, &tty->flags) ||
+	    test_bit(TTY_HUPPED, &tty->flags)) {
 		/* We were raced by the hangup method. It will have stomped
 		   the ldisc data and closed the ldisc down */
-		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-		mutex_unlock(&tty->ldisc_mutex);
+		tty_ldisc_enable_pair(tty, o_tty);
 		tty_ldisc_put(new_ldisc);
 		tty_unlock(tty);
 		return -EIO;
 	}
 
-	/* Shutdown the current discipline. */
-	tty_ldisc_close(tty, o_ldisc);
+	/* Shutdown the old discipline. */
+	tty_ldisc_close(tty, old_ldisc);
 
 	/* Now set up the new line discipline. */
 	tty->ldisc = new_ldisc;
@@ -705,26 +564,24 @@
 	if (retval < 0) {
 		/* Back to the old one or N_TTY if we can't */
 		tty_ldisc_put(new_ldisc);
-		tty_ldisc_restore(tty, o_ldisc);
+		tty_ldisc_restore(tty, old_ldisc);
 	}
 
-	/* At this point we hold a reference to the new ldisc and a
-	   a reference to the old ldisc. If we ended up flipping back
-	   to the existing ldisc we have two references to it */
-
-	if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
+	if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
 		tty->ops->set_ldisc(tty);
 
-	tty_ldisc_put(o_ldisc);
+	/* At this point we hold a reference to the new ldisc and a
+	   reference to the old ldisc, or we hold two references to
+	   the old ldisc (if it was restored as part of error cleanup
+	   above). In either case, releasing a single reference from
+	   the old ldisc is correct. */
 
-enable:
+	tty_ldisc_put(old_ldisc);
+
 	/*
 	 *	Allow ldisc referencing to occur again
 	 */
-
-	tty_ldisc_enable(tty);
-	if (o_tty)
-		tty_ldisc_enable(o_tty);
+	tty_ldisc_enable_pair(tty, o_tty);
 
 	/* Restart the work queue in case no characters kick it off. Safe if
 	   already running */
@@ -732,7 +589,6 @@
 	if (o_tty)
 		schedule_work(&o_tty->port->buf.work);
 
-	mutex_unlock(&tty->ldisc_mutex);
 	tty_unlock(tty);
 	return retval;
 }
@@ -746,11 +602,11 @@
 
 static void tty_reset_termios(struct tty_struct *tty)
 {
-	mutex_lock(&tty->termios_mutex);
+	down_write(&tty->termios_rwsem);
 	tty->termios = tty->driver->init_termios;
 	tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
 	tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
-	mutex_unlock(&tty->termios_mutex);
+	up_write(&tty->termios_rwsem);
 }
 
 
@@ -765,7 +621,7 @@
 
 static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
 {
-	struct tty_ldisc *ld = tty_ldisc_get(ldisc);
+	struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
 
 	if (IS_ERR(ld))
 		return -1;
@@ -804,14 +660,8 @@
 
 	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
 
-	/*
-	 * FIXME! What are the locking issues here? This may me overdoing
-	 * things... This question is especially important now that we've
-	 * removed the irqlock.
-	 */
 	ld = tty_ldisc_ref(tty);
 	if (ld != NULL) {
-		/* We may have no line discipline at this point */
 		if (ld->ops->flush_buffer)
 			ld->ops->flush_buffer(tty);
 		tty_driver_flush_buffer(tty);
@@ -822,21 +672,22 @@
 			ld->ops->hangup(tty);
 		tty_ldisc_deref(ld);
 	}
-	/*
-	 * FIXME: Once we trust the LDISC code better we can wait here for
-	 * ldisc completion and fix the driver call race
-	 */
+
 	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
 	wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+
+	tty_unlock(tty);
+
 	/*
 	 * Shutdown the current line discipline, and reset it to
 	 * N_TTY if need be.
 	 *
 	 * Avoid racing set_ldisc or tty_ldisc_release
 	 */
-	mutex_lock(&tty->ldisc_mutex);
+	tty_ldisc_lock_pair(tty, tty->link);
+	tty_lock(tty);
 
-	if (tty_ldisc_hangup_halt(tty)) {
+	if (tty->ldisc) {
 
 		/* At this point we have a halted ldisc; we want to close it and
 		   reopen a new ldisc. We could defer the reopen to the next
@@ -855,9 +706,8 @@
 			BUG_ON(tty_ldisc_reinit(tty, N_TTY));
 			WARN_ON(tty_ldisc_open(tty, tty->ldisc));
 		}
-		tty_ldisc_enable(tty);
 	}
-	mutex_unlock(&tty->ldisc_mutex);
+	tty_ldisc_enable_pair(tty, tty->link);
 	if (reset)
 		tty_reset_termios(tty);
 
@@ -889,15 +739,12 @@
 			tty_ldisc_close(tty, ld);
 			return retval;
 		}
-		tty_ldisc_enable(o_tty);
 	}
-	tty_ldisc_enable(tty);
 	return 0;
 }
 
 static void tty_ldisc_kill(struct tty_struct *tty)
 {
-	mutex_lock(&tty->ldisc_mutex);
 	/*
 	 * Now kill off the ldisc
 	 */
@@ -908,7 +755,6 @@
 
 	/* Ensure the next open requests the N_TTY ldisc */
 	tty_set_termios_ldisc(tty, N_TTY);
-	mutex_unlock(&tty->ldisc_mutex);
 }
 
 /**
@@ -930,15 +776,16 @@
 
 	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
 
-	tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);
-
+	tty_ldisc_lock_pair(tty, o_tty);
 	tty_lock_pair(tty, o_tty);
-	/* This will need doing differently if we need to lock */
+
 	tty_ldisc_kill(tty);
 	if (o_tty)
 		tty_ldisc_kill(o_tty);
 
 	tty_unlock_pair(tty, o_tty);
+	tty_ldisc_unlock_pair(tty, o_tty);
+
 	/* And the memory resources remaining (buffers, termios) will be
 	   disposed of when the kref hits zero */
 
@@ -955,7 +802,7 @@
 
 void tty_ldisc_init(struct tty_struct *tty)
 {
-	struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
+	struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
 	if (IS_ERR(ld))
 		panic("n_tty: init_tty");
 	tty->ldisc = ld;
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index a9af1b9a..d0e3a44 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -132,12 +132,6 @@
 static unsigned char ledstate = 0xff;			/* undefined */
 static unsigned char ledioctl;
 
-static struct ledptr {
-	unsigned int *addr;
-	unsigned int mask;
-	unsigned char valid:1;
-} ledptrs[3];
-
 /*
  * Notifier list for console keyboard events
  */
@@ -994,24 +988,11 @@
 static inline unsigned char getleds(void)
 {
 	struct kbd_struct *kbd = kbd_table + fg_console;
-	unsigned char leds;
-	int i;
 
 	if (kbd->ledmode == LED_SHOW_IOCTL)
 		return ledioctl;
 
-	leds = kbd->ledflagstate;
-
-	if (kbd->ledmode == LED_SHOW_MEM) {
-		for (i = 0; i < 3; i++)
-			if (ledptrs[i].valid) {
-				if (*ledptrs[i].addr & ledptrs[i].mask)
-					leds |= (1 << i);
-				else
-					leds &= ~(1 << i);
-			}
-	}
-	return leds;
+	return kbd->ledflagstate;
 }
 
 static int kbd_update_leds_helper(struct input_handle *handle, void *data)
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 60b7b69..ea27804 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -24,6 +24,7 @@
 #include <linux/selection.h>
 #include <linux/tiocl.h>
 #include <linux/console.h>
+#include <linux/tty_flip.h>
 
 /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
 #define isspace(c)	((c) == ' ')
@@ -346,8 +347,8 @@
 	console_unlock();
 
 	ld = tty_ldisc_ref_wait(tty);
+	tty_buffer_lock_exclusive(&vc->port);
 
-	/* FIXME: this is completely unsafe */
 	add_wait_queue(&vc->paste_wait, &wait);
 	while (sel_buffer && sel_buffer_lth > pasted) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -356,13 +357,14 @@
 			continue;
 		}
 		count = sel_buffer_lth - pasted;
-		count = min(count, tty->receive_room);
-		ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count);
+		count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL,
+					      count);
 		pasted += count;
 	}
 	remove_wait_queue(&vc->paste_wait, &wait);
 	__set_current_state(TASK_RUNNING);
 
+	tty_buffer_unlock_exclusive(&vc->port);
 	tty_ldisc_deref(ld);
 	return 0;
 }
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index c677829..9a8e8c5 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -828,7 +828,7 @@
  *	If the caller passes a tty structure then update the termios winsize
  *	information and perform any necessary signal handling.
  *
- *	Caller must hold the console semaphore. Takes the termios mutex and
+ *	Caller must hold the console semaphore. Takes the termios rwsem and
  *	ctrl_lock of the tty IFF a tty is passed.
  */
 
@@ -972,7 +972,7 @@
  *	the actual work.
  *
  *	Takes the console sem and the called methods then take the tty
- *	termios_mutex and the tty ctrl_lock in that order.
+ *	termios_rwsem and the tty ctrl_lock in that order.
  */
 static int vt_resize(struct tty_struct *tty, struct winsize *ws)
 {
@@ -2809,8 +2809,10 @@
 	console_unlock();
 }
 
+static int default_color           = 7; /* white */
 static int default_italic_color    = 2; // green (ASCII)
 static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
 module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
 module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
 
@@ -2832,7 +2834,7 @@
 		vc->vc_palette[k++] = default_grn[j] ;
 		vc->vc_palette[k++] = default_blu[j] ;
 	}
-	vc->vc_def_color       = 0x07;   /* white */
+	vc->vc_def_color       = default_color;
 	vc->vc_ulcolor         = default_underline_color;
 	vc->vc_itcolor         = default_italic_color;
 	vc->vc_halfcolor       = 0x08;   /* grey */
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5295be0..5a90914 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -1,5 +1,6 @@
 menuconfig UIO
 	tristate "Userspace I/O drivers"
+	depends on MMU
 	help
 	  Enable this to allow the userspace driver core code to be
 	  built.  This code allows userspace programs easy access to
@@ -23,13 +24,6 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called uio_cif.
 
-config UIO_PDRV
-	tristate "Userspace I/O platform driver"
-	help
-	  Generic platform driver for Userspace I/O devices.
-
-	  If you don't know what to do here, say N.
-
 config UIO_PDRV_GENIRQ
 	tristate "Userspace I/O platform driver with generic IRQ handling"
 	help
@@ -128,4 +122,17 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called uio_pruss.
 
+config UIO_MF624
+	tristate "Humusoft MF624 DAQ PCI card driver"
+	depends on PCI
+	help
+	  Userspace I/O interface for the Humusoft MF624 PCI card.
+	  A sample userspace application using this driver is available
+	  (among other MF624 related information and software components)
+	  for download in a git repository:
+
+	    git clone git://rtime.felk.cvut.cz/mf6xx.git
+
+	  If you compile this as a module, it will be called uio_mf624.
+
 endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index b354c53..d3218bd 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -1,6 +1,5 @@
 obj-$(CONFIG_UIO)	+= uio.o
 obj-$(CONFIG_UIO_CIF)	+= uio_cif.o
-obj-$(CONFIG_UIO_PDRV)	+= uio_pdrv.o
 obj-$(CONFIG_UIO_PDRV_GENIRQ)	+= uio_pdrv_genirq.o
 obj-$(CONFIG_UIO_DMEM_GENIRQ)	+= uio_dmem_genirq.o
 obj-$(CONFIG_UIO_AEC)	+= uio_aec.o
@@ -8,3 +7,4 @@
 obj-$(CONFIG_UIO_PCI_GENERIC)	+= uio_pci_generic.o
 obj-$(CONFIG_UIO_NETX)	+= uio_netx.o
 obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o
+obj-$(CONFIG_UIO_MF624)         += uio_mf624.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 3b96f18..ba47563 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -35,7 +35,6 @@
 	atomic_t		event;
 	struct fasync_struct	*async_queue;
 	wait_queue_head_t	wait;
-	int			vma_count;
 	struct uio_info		*info;
 	struct kobject		*map_dir;
 	struct kobject		*portio_dir;
@@ -224,38 +223,42 @@
 	.default_attrs	= portio_attrs,
 };
 
-static ssize_t show_name(struct device *dev,
+static ssize_t name_show(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
 	struct uio_device *idev = dev_get_drvdata(dev);
 	return sprintf(buf, "%s\n", idev->info->name);
 }
+static DEVICE_ATTR_RO(name);
 
-static ssize_t show_version(struct device *dev,
+static ssize_t version_show(struct device *dev,
 			    struct device_attribute *attr, char *buf)
 {
 	struct uio_device *idev = dev_get_drvdata(dev);
 	return sprintf(buf, "%s\n", idev->info->version);
 }
+static DEVICE_ATTR_RO(version);
 
-static ssize_t show_event(struct device *dev,
+static ssize_t event_show(struct device *dev,
 			  struct device_attribute *attr, char *buf)
 {
 	struct uio_device *idev = dev_get_drvdata(dev);
 	return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event));
 }
+static DEVICE_ATTR_RO(event);
 
-static struct device_attribute uio_class_attributes[] = {
-	__ATTR(name, S_IRUGO, show_name, NULL),
-	__ATTR(version, S_IRUGO, show_version, NULL),
-	__ATTR(event, S_IRUGO, show_event, NULL),
-	{}
+static struct attribute *uio_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_version.attr,
+	&dev_attr_event.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(uio);
 
 /* UIO class infrastructure */
 static struct class uio_class = {
 	.name = "uio",
-	.dev_attrs = uio_class_attributes,
+	.dev_groups = uio_groups,
 };
 
 /*
@@ -593,18 +596,6 @@
 	return -1;
 }
 
-static void uio_vma_open(struct vm_area_struct *vma)
-{
-	struct uio_device *idev = vma->vm_private_data;
-	idev->vma_count++;
-}
-
-static void uio_vma_close(struct vm_area_struct *vma)
-{
-	struct uio_device *idev = vma->vm_private_data;
-	idev->vma_count--;
-}
-
 static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct uio_device *idev = vma->vm_private_data;
@@ -630,12 +621,23 @@
 	return 0;
 }
 
-static const struct vm_operations_struct uio_vm_ops = {
-	.open = uio_vma_open,
-	.close = uio_vma_close,
+static const struct vm_operations_struct uio_logical_vm_ops = {
 	.fault = uio_vma_fault,
 };
 
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_ops = &uio_logical_vm_ops;
+	return 0;
+}
+
+static const struct vm_operations_struct uio_physical_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+	.access = generic_access_phys,
+#endif
+};
+
 static int uio_mmap_physical(struct vm_area_struct *vma)
 {
 	struct uio_device *idev = vma->vm_private_data;
@@ -643,6 +645,8 @@
 	if (mi < 0)
 		return -EINVAL;
 
+	vma->vm_ops = &uio_physical_vm_ops;
+
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	return remap_pfn_range(vma,
@@ -652,14 +656,6 @@
 			       vma->vm_page_prot);
 }
 
-static int uio_mmap_logical(struct vm_area_struct *vma)
-{
-	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
-	vma->vm_ops = &uio_vm_ops;
-	uio_vma_open(vma);
-	return 0;
-}
-
 static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
 {
 	struct uio_listener *listener = filep->private_data;
diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c
index 125d0e5..1270f3b 100644
--- a/drivers/uio/uio_dmem_genirq.c
+++ b/drivers/uio/uio_dmem_genirq.c
@@ -146,7 +146,7 @@
 
 static int uio_dmem_genirq_probe(struct platform_device *pdev)
 {
-	struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data;
+	struct uio_dmem_genirq_pdata *pdata = dev_get_platdata(&pdev->dev);
 	struct uio_info *uioinfo = &pdata->uioinfo;
 	struct uio_dmem_genirq_platdata *priv;
 	struct uio_mem *uiomem;
diff --git a/drivers/uio/uio_mf624.c b/drivers/uio/uio_mf624.c
new file mode 100644
index 0000000..a1768b2
--- /dev/null
+++ b/drivers/uio/uio_mf624.c
@@ -0,0 +1,247 @@
+/*
+ * UIO driver fo Humusoft MF624 DAQ card.
+ * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
+ *                    Czech Technical University in Prague
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/uio_driver.h>
+
+#define PCI_VENDOR_ID_HUMUSOFT		0x186c
+#define PCI_DEVICE_ID_MF624		0x0624
+#define PCI_SUBVENDOR_ID_HUMUSOFT	0x186c
+#define PCI_SUBDEVICE_DEVICE		0x0624
+
+/* BAR0 Interrupt control/status register */
+#define INTCSR				0x4C
+#define INTCSR_ADINT_ENABLE		(1 << 0)
+#define INTCSR_CTR4INT_ENABLE		(1 << 3)
+#define INTCSR_PCIINT_ENABLE		(1 << 6)
+#define INTCSR_ADINT_STATUS		(1 << 2)
+#define INTCSR_CTR4INT_STATUS		(1 << 5)
+
+enum mf624_interrupt_source {ADC, CTR4, ALL};
+
+void mf624_disable_interrupt(enum mf624_interrupt_source source,
+			     struct uio_info *info)
+{
+	void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+	switch (source) {
+	case ADC:
+		iowrite32(ioread32(INTCSR_reg)
+			& ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
+			INTCSR_reg);
+		break;
+
+	case CTR4:
+		iowrite32(ioread32(INTCSR_reg)
+			& ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
+			INTCSR_reg);
+		break;
+
+	case ALL:
+	default:
+		iowrite32(ioread32(INTCSR_reg)
+			& ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
+			    | INTCSR_PCIINT_ENABLE),
+			INTCSR_reg);
+		break;
+	}
+}
+
+void mf624_enable_interrupt(enum mf624_interrupt_source source,
+			    struct uio_info *info)
+{
+	void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+	switch (source) {
+	case ADC:
+		iowrite32(ioread32(INTCSR_reg)
+			| INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE,
+			INTCSR_reg);
+		break;
+
+	case CTR4:
+		iowrite32(ioread32(INTCSR_reg)
+			| INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE,
+			INTCSR_reg);
+		break;
+
+	case ALL:
+	default:
+		iowrite32(ioread32(INTCSR_reg)
+			| INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
+			| INTCSR_PCIINT_ENABLE,
+			INTCSR_reg);
+		break;
+	}
+}
+
+static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
+{
+	void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
+
+	if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
+	    && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
+		mf624_disable_interrupt(ADC, info);
+		return IRQ_HANDLED;
+	}
+
+	if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
+	    && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
+		mf624_disable_interrupt(CTR4, info);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
+{
+	if (irq_on == 0)
+		mf624_disable_interrupt(ALL, info);
+	else if (irq_on == 1)
+		mf624_enable_interrupt(ALL, info);
+
+	return 0;
+}
+
+static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct uio_info *info;
+
+	info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if (pci_enable_device(dev))
+		goto out_free;
+
+	if (pci_request_regions(dev, "mf624"))
+		goto out_disable;
+
+	info->name = "mf624";
+	info->version = "0.0.1";
+
+	/* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */
+
+	/* BAR0 */
+	info->mem[0].name = "PCI chipset, interrupts, status "
+			"bits, special functions";
+	info->mem[0].addr = pci_resource_start(dev, 0);
+	if (!info->mem[0].addr)
+		goto out_release;
+	info->mem[0].size = pci_resource_len(dev, 0);
+	info->mem[0].memtype = UIO_MEM_PHYS;
+	info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
+	if (!info->mem[0].internal_addr)
+		goto out_release;
+
+	/* BAR2 */
+	info->mem[1].name = "ADC, DAC, DIO";
+	info->mem[1].addr = pci_resource_start(dev, 2);
+	if (!info->mem[1].addr)
+		goto out_unmap0;
+	info->mem[1].size = pci_resource_len(dev, 2);
+	info->mem[1].memtype = UIO_MEM_PHYS;
+	info->mem[1].internal_addr = pci_ioremap_bar(dev, 2);
+	if (!info->mem[1].internal_addr)
+		goto out_unmap0;
+
+	/* BAR4 */
+	info->mem[2].name = "Counter/timer chip";
+	info->mem[2].addr = pci_resource_start(dev, 4);
+	if (!info->mem[2].addr)
+		goto out_unmap1;
+	info->mem[2].size = pci_resource_len(dev, 4);
+	info->mem[2].memtype = UIO_MEM_PHYS;
+	info->mem[2].internal_addr = pci_ioremap_bar(dev, 4);
+	if (!info->mem[2].internal_addr)
+		goto out_unmap1;
+
+	info->irq = dev->irq;
+	info->irq_flags = IRQF_SHARED;
+	info->handler = mf624_irq_handler;
+
+	info->irqcontrol = mf624_irqcontrol;
+
+	if (uio_register_device(&dev->dev, info))
+		goto out_unmap2;
+
+	pci_set_drvdata(dev, info);
+
+	return 0;
+
+out_unmap2:
+	iounmap(info->mem[2].internal_addr);
+out_unmap1:
+	iounmap(info->mem[1].internal_addr);
+out_unmap0:
+	iounmap(info->mem[0].internal_addr);
+
+out_release:
+	pci_release_regions(dev);
+
+out_disable:
+	pci_disable_device(dev);
+
+out_free:
+	kfree(info);
+	return -ENODEV;
+}
+
+static void mf624_pci_remove(struct pci_dev *dev)
+{
+	struct uio_info *info = pci_get_drvdata(dev);
+
+	mf624_disable_interrupt(ALL, info);
+
+	uio_unregister_device(info);
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(info->mem[0].internal_addr);
+	iounmap(info->mem[1].internal_addr);
+	iounmap(info->mem[2].internal_addr);
+
+	kfree(info);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(mf624_pci_id) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
+	{ 0, }
+};
+
+static struct pci_driver mf624_pci_driver = {
+	.name = "mf624",
+	.id_table = mf624_pci_id,
+	.probe = mf624_pci_probe,
+	.remove = mf624_pci_remove,
+};
+MODULE_DEVICE_TABLE(pci, mf624_pci_id);
+
+module_pci_driver(mf624_pci_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c
deleted file mode 100644
index 39be9e0..0000000
--- a/drivers/uio/uio_pdrv.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * drivers/uio/uio_pdrv.c
- *
- * Copyright (C) 2008 by Digi International Inc.
- * 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 version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/platform_device.h>
-#include <linux/uio_driver.h>
-#include <linux/stringify.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#define DRIVER_NAME "uio_pdrv"
-
-struct uio_platdata {
-	struct uio_info *uioinfo;
-};
-
-static int uio_pdrv_probe(struct platform_device *pdev)
-{
-	struct uio_info *uioinfo = pdev->dev.platform_data;
-	struct uio_platdata *pdata;
-	struct uio_mem *uiomem;
-	int ret = -ENODEV;
-	int i;
-
-	if (!uioinfo || !uioinfo->name || !uioinfo->version) {
-		dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__);
-		goto err_uioinfo;
-	}
-
-	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
-	if (!pdata) {
-		ret = -ENOMEM;
-		dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__);
-		goto err_alloc_pdata;
-	}
-
-	pdata->uioinfo = uioinfo;
-
-	uiomem = &uioinfo->mem[0];
-
-	for (i = 0; i < pdev->num_resources; ++i) {
-		struct resource *r = &pdev->resource[i];
-
-		if (r->flags != IORESOURCE_MEM)
-			continue;
-
-		if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
-			dev_warn(&pdev->dev, "device has more than "
-					__stringify(MAX_UIO_MAPS)
-					" I/O memory resources.\n");
-			break;
-		}
-
-		uiomem->memtype = UIO_MEM_PHYS;
-		uiomem->addr = r->start;
-		uiomem->size = resource_size(r);
-		uiomem->name = r->name;
-		++uiomem;
-	}
-
-	while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
-		uiomem->size = 0;
-		++uiomem;
-	}
-
-	pdata->uioinfo->priv = pdata;
-
-	ret = uio_register_device(&pdev->dev, pdata->uioinfo);
-
-	if (ret) {
-		kfree(pdata);
-err_alloc_pdata:
-err_uioinfo:
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, pdata);
-
-	return 0;
-}
-
-static int uio_pdrv_remove(struct platform_device *pdev)
-{
-	struct uio_platdata *pdata = platform_get_drvdata(pdev);
-
-	uio_unregister_device(pdata->uioinfo);
-
-	kfree(pdata);
-
-	return 0;
-}
-
-static struct platform_driver uio_pdrv = {
-	.probe = uio_pdrv_probe,
-	.remove = uio_pdrv_remove,
-	.driver = {
-		.name = DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
-module_platform_driver(uio_pdrv);
-
-MODULE_AUTHOR("Uwe Kleine-Koenig");
-MODULE_DESCRIPTION("Userspace I/O platform driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 4eb8eaf..90ff17a 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -104,7 +104,7 @@
 
 static int uio_pdrv_genirq_probe(struct platform_device *pdev)
 {
-	struct uio_info *uioinfo = pdev->dev.platform_data;
+	struct uio_info *uioinfo = dev_get_platdata(&pdev->dev);
 	struct uio_pdrv_genirq_platdata *priv;
 	struct uio_mem *uiomem;
 	int ret = -EINVAL;
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
index 21f7a72..f519da9 100644
--- a/drivers/uio/uio_pruss.c
+++ b/drivers/uio/uio_pruss.c
@@ -121,7 +121,7 @@
 	struct uio_pruss_dev *gdev;
 	struct resource *regs_prussio;
 	int ret = -ENODEV, cnt = 0, len;
-	struct uio_pruss_pdata *pdata = dev->dev.platform_data;
+	struct uio_pruss_pdata *pdata = dev_get_platdata(&dev->dev);
 
 	gdev = kzalloc(sizeof(struct uio_pruss_dev), GFP_KERNEL);
 	if (!gdev)
@@ -224,7 +224,6 @@
 	struct uio_pruss_dev *gdev = platform_get_drvdata(dev);
 
 	pruss_cleanup(dev, gdev);
-	platform_set_drvdata(dev, NULL);
 	return 0;
 }
 
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 73f62ca..2642b8a 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -6,9 +6,26 @@
 config USB_ARCH_HAS_OHCI
 	bool
 
+config USB_OHCI_BIG_ENDIAN_DESC
+	bool
+
+config USB_OHCI_BIG_ENDIAN_MMIO
+	bool
+
+config USB_OHCI_LITTLE_ENDIAN
+	bool
+	default n if STB03xxx || PPC_MPC52xx
+	default y
+
 config USB_ARCH_HAS_EHCI
 	bool
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+	bool
+
+config USB_EHCI_BIG_ENDIAN_DESC
+	bool
+
 config USB_ARCH_HAS_XHCI
 	bool
 
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 238c5d4..70d7c5b 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -26,6 +26,7 @@
 obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/
 obj-$(CONFIG_USB_FUSBH200_HCD)	+= host/
+obj-$(CONFIG_USB_FOTG210_HCD)	+= host/
 
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 
@@ -45,7 +46,7 @@
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
 obj-$(CONFIG_USB)		+= misc/
-obj-$(CONFIG_USB_PHY)		+= phy/
+obj-$(CONFIG_USB_SUPPORT)	+= phy/
 obj-$(CONFIG_EARLY_PRINTK_DBGP)	+= early/
 
 obj-$(CONFIG_USB_ATM)		+= atm/
diff --git a/drivers/usb/atm/Makefile b/drivers/usb/atm/Makefile
index a5d792e..ac27894 100644
--- a/drivers/usb/atm/Makefile
+++ b/drivers/usb/atm/Makefile
@@ -1,9 +1,6 @@
 #
 # Makefile for USB ATM/xDSL drivers
 #
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
 obj-$(CONFIG_USB_CXACRU)	+= cxacru.o
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= speedtch.o
 obj-$(CONFIG_USB_UEAGLEATM)	+= ueagle-atm.o
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 807627b..69461d6 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -888,7 +888,7 @@
 		usb_fill_int_urb(instance->int_urb, usb_dev,
 				 usb_rcvintpipe(usb_dev, ENDPOINT_INT),
 				 instance->int_data, sizeof(instance->int_data),
-				 speedtch_handle_int, instance, 50);
+				 speedtch_handle_int, instance, 16);
 	else
 		usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
 
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 5e0d33a..25a7bfc 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -311,8 +311,6 @@
 	int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
 	u8 pti = ((source[3] & 0xe) >> 1);
 
-	vdbg(&instance->usb_intf->dev, "%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
-
 	if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) {
 		instance->cached_vpi = vpi;
 		instance->cached_vci = vci;
@@ -344,7 +342,6 @@
 				__func__, sarb->len, vcc);
 		/* discard cells already received */
 		skb_trim(sarb, 0);
-		UDSL_ASSERT(instance, sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
 	}
 
 	memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
@@ -437,8 +434,6 @@
 		unsigned char *cell_buf = instance->cell_buf;
 		unsigned int space_left = stride - buf_usage;
 
-		UDSL_ASSERT(instance, buf_usage <= stride);
-
 		if (avail_data >= space_left) {
 			/* add new data and process cell */
 			memcpy(cell_buf + buf_usage, source, space_left);
@@ -479,10 +474,6 @@
 	unsigned int bytes_written;
 	unsigned int stride = instance->tx_channel.stride;
 
-	vdbg(&instance->usb_intf->dev, "%s: skb->len=%d, avail_space=%u",
-	     __func__, skb->len, avail_space);
-	UDSL_ASSERT(instance, !(avail_space % stride));
-
 	for (bytes_written = 0; bytes_written < avail_space && ctrl->len;
 	     bytes_written += stride, target += stride) {
 		unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
@@ -553,8 +544,6 @@
 				if (!urb->iso_frame_desc[i].status) {
 					unsigned int actual_length = urb->iso_frame_desc[i].actual_length;
 
-					UDSL_ASSERT(instance, actual_length <= packet_size);
-
 					if (!merge_length)
 						merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
 					merge_length += actual_length;
@@ -645,7 +634,6 @@
 {
 	struct sk_buff *skb, *n;
 
-	atm_dbg(instance, "%s entered\n", __func__);
 	spin_lock_irq(&instance->sndqueue.lock);
 	skb_queue_walk_safe(&instance->sndqueue, skb, n) {
 		if (UDSL_SKB(skb)->atm.vcc == vcc) {
@@ -663,7 +651,6 @@
 		usbatm_pop(vcc, skb);
 	}
 	tasklet_enable(&instance->tx_channel.tasklet);
-	atm_dbg(instance, "%s done\n", __func__);
 }
 
 static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
@@ -674,16 +661,13 @@
 
 	/* racy disconnection check - fine */
 	if (!instance || instance->disconnected) {
-#ifdef DEBUG
+#ifdef VERBOSE_DEBUG
 		printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
 #endif
 		err = -ENODEV;
 		goto fail;
 	}
 
-	vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
-	     skb, skb->len);
-
 	if (vcc->qos.aal != ATM_AAL5) {
 		atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
 		err = -EINVAL;
@@ -723,8 +707,6 @@
 {
 	struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
 
-	usb_dbg(instance, "%s\n", __func__);
-
 	tasklet_kill(&instance->rx_channel.tasklet);
 	tasklet_kill(&instance->tx_channel.tasklet);
 	usb_put_dev(instance->usb_dev);
@@ -733,15 +715,11 @@
 
 static void usbatm_get_instance(struct usbatm_data *instance)
 {
-	usb_dbg(instance, "%s\n", __func__);
-
 	kref_get(&instance->refcount);
 }
 
 static void usbatm_put_instance(struct usbatm_data *instance)
 {
-	usb_dbg(instance, "%s\n", __func__);
-
 	kref_put(&instance->refcount, usbatm_destroy_instance);
 }
 
@@ -757,7 +735,6 @@
 	if (!instance)
 		return;
 
-	usb_dbg(instance, "%s\n", __func__);
 	atm_dev->dev_data = NULL; /* catch bugs */
 	usbatm_put_instance(instance);	/* taken in usbatm_atm_init */
 }
@@ -813,8 +790,6 @@
 	if (!instance)
 		return -ENODEV;
 
-	atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
-
 	/* only support AAL5 */
 	if ((vcc->qos.aal != ATM_AAL5)) {
 		atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
@@ -891,11 +866,6 @@
 	if (!instance || !vcc_data)
 		return;
 
-	atm_dbg(instance, "%s entered\n", __func__);
-
-	atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",
-		__func__, vcc_data, vcc_data->vpi, vcc_data->vci);
-
 	usbatm_cancel_send(instance, vcc);
 
 	mutex_lock(&instance->serialize);	/* vs self, usbatm_atm_open, usbatm_usb_disconnect */
@@ -922,8 +892,6 @@
 	clear_bit(ATM_VF_ADDR, &vcc->flags);
 
 	mutex_unlock(&instance->serialize);
-
-	atm_dbg(instance, "%s successful\n", __func__);
 }
 
 static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
@@ -1060,12 +1028,6 @@
 	int i, length;
 	unsigned int maxpacket, num_packets;
 
-	dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n",
-			__func__, driver->driver_name,
-			le16_to_cpu(usb_dev->descriptor.idVendor),
-			le16_to_cpu(usb_dev->descriptor.idProduct),
-			intf->altsetting->desc.bInterfaceNumber);
-
 	/* instance init */
 	instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
 	if (!instance) {
@@ -1158,14 +1120,13 @@
 	instance->rx_channel.buf_size = num_packets * maxpacket;
 	instance->rx_channel.packet_size = maxpacket;
 
-#ifdef DEBUG
 	for (i = 0; i < 2; i++) {
 		struct usbatm_channel *channel = i ?
 			&instance->tx_channel : &instance->rx_channel;
 
-		dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel);
+		dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n",
+			__func__, channel->buf_size, i ? "tx" : "rx", channel);
 	}
-#endif
 
 	/* initialize urbs */
 
@@ -1176,8 +1137,6 @@
 		struct urb *urb;
 		unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0;
 
-		UDSL_ASSERT(instance, !usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint));
-
 		urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
 		if (!urb) {
 			dev_err(dev, "%s: no memory for urb %d!\n", __func__, i);
@@ -1266,8 +1225,6 @@
 	struct usbatm_vcc_data *vcc_data;
 	int i;
 
-	dev_dbg(dev, "%s entered\n", __func__);
-
 	if (!instance) {
 		dev_dbg(dev, "%s: NULL instance!\n", __func__);
 		return;
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index 5fc4894..5651231 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -39,31 +39,14 @@
 #define VERBOSE_DEBUG
 */
 
-#ifdef DEBUG
-#define UDSL_ASSERT(instance, x)	BUG_ON(!(x))
-#else
-#define UDSL_ASSERT(instance, x)					\
-	do {	\
-		if (!(x))						\
-			dev_warn(&(instance)->usb_intf->dev,		\
-				 "failed assertion '%s' at line %d",	\
-				 __stringify(x), __LINE__);		\
-	} while (0)
-#endif
-
 #define usb_err(instance, format, arg...)	\
 	dev_err(&(instance)->usb_intf->dev , format , ## arg)
 #define usb_info(instance, format, arg...)	\
 	dev_info(&(instance)->usb_intf->dev , format , ## arg)
 #define usb_warn(instance, format, arg...)	\
 	dev_warn(&(instance)->usb_intf->dev , format , ## arg)
-#ifdef DEBUG
 #define usb_dbg(instance, format, arg...)	\
-	dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg)
-#else
-#define usb_dbg(instance, format, arg...)	\
-	do {} while (0)
-#endif
+	dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
 
 /* FIXME: move to dev_* once ATM is driver model aware */
 #define atm_printk(level, instance, format, arg...)	\
@@ -76,18 +59,12 @@
 	atm_printk(KERN_INFO, instance , format , ## arg)
 #define atm_warn(instance, format, arg...)	\
 	atm_printk(KERN_WARNING, instance , format , ## arg)
-#ifdef DEBUG
-#define atm_dbg(instance, format, arg...)	\
-	atm_printk(KERN_DEBUG, instance , format , ## arg)
-#define atm_rldbg(instance, format, arg...)	\
+#define atm_dbg(instance, format, arg...)		\
+	dynamic_pr_debug("ATM dev %d: " format ,	\
+	(instance)->atm_dev->number , ## arg)
+#define atm_rldbg(instance, format, arg...)		\
 	if (printk_ratelimit())				\
-		atm_printk(KERN_DEBUG, instance , format , ## arg)
-#else
-#define atm_dbg(instance, format, arg...)	\
-	do {} while (0)
-#define atm_rldbg(instance, format, arg...)	\
-	do {} while (0)
-#endif
+		atm_dbg(instance , format , ## arg)
 
 
 /* flags, set by mini-driver in bind() */
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
index fe815ec..8db3380 100644
--- a/drivers/usb/c67x00/c67x00-drv.c
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -131,7 +131,7 @@
 	if (!res2)
 		return -ENODEV;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata)
 		return -ENODEV;
 
@@ -154,7 +154,7 @@
 
 	spin_lock_init(&c67x00->hpi.lock);
 	c67x00->hpi.regstep = pdata->hpi_regstep;
-	c67x00->pdata = pdev->dev.platform_data;
+	c67x00->pdata = dev_get_platdata(&pdev->dev);
 	c67x00->pdev = pdev;
 
 	c67x00_ll_init(c67x00);
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index d1bd8ef..4a851e1 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -1,6 +1,6 @@
 config USB_CHIPIDEA
 	tristate "ChipIdea Highspeed Dual Role Controller"
-	depends on USB || USB_GADGET
+	depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)
 	help
 	  Say Y here if your system has a dual role high speed USB
 	  controller based on ChipIdea silicon IP. Currently, only the
@@ -12,15 +12,14 @@
 
 config USB_CHIPIDEA_UDC
 	bool "ChipIdea device controller"
-	depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m)
+	depends on USB_GADGET
 	help
 	  Say Y here to enable device controller functionality of the
 	  ChipIdea driver.
 
 config USB_CHIPIDEA_HOST
 	bool "ChipIdea host controller"
-	depends on USB=y
-	depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m)
+	depends on USB_EHCI_HCD
 	select USB_EHCI_ROOT_HUB_TT
 	help
 	  Say Y here to enable host controller functionality of the
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index 6cf5f68..a99d980 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -2,7 +2,7 @@
 
 obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
 
-ci_hdrc-y				:= core.o
+ci_hdrc-y				:= core.o otg.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 1b23e35..464584c 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -79,11 +79,21 @@
 #define OTGSC_ASVIS	      BIT(18)
 #define OTGSC_BSVIS	      BIT(19)
 #define OTGSC_BSEIS	      BIT(20)
+#define OTGSC_1MSIS	      BIT(21)
+#define OTGSC_DPIS	      BIT(22)
 #define OTGSC_IDIE	      BIT(24)
 #define OTGSC_AVVIE	      BIT(25)
 #define OTGSC_ASVIE	      BIT(26)
 #define OTGSC_BSVIE	      BIT(27)
 #define OTGSC_BSEIE	      BIT(28)
+#define OTGSC_1MSIE	      BIT(29)
+#define OTGSC_DPIE	      BIT(30)
+#define OTGSC_INT_EN_BITS	(OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \
+				| OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \
+				| OTGSC_DPIE)
+#define OTGSC_INT_STATUS_BITS	(OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS	\
+				| OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \
+				| OTGSC_DPIS)
 
 /* USBMODE */
 #define USBMODE_CM            (0x03UL <<  0)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 33cb29f..1c94fc5 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -132,6 +132,9 @@
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
  * @debugfs: root dentry for this controller in debugfs
+ * @id_event: indicates there is an id event, and handled at ci_otg_work
+ * @b_sess_valid_event: indicates there is a vbus event, and handled
+ * at ci_otg_work
  */
 struct ci_hdrc {
 	struct device			*dev;
@@ -168,6 +171,8 @@
 	struct usb_phy			*transceiver;
 	struct usb_hcd			*hcd;
 	struct dentry			*debugfs;
+	bool				id_event;
+	bool				b_sess_valid_event;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
@@ -303,4 +308,7 @@
 
 u8 hw_port_test_get(struct ci_hdrc *ci);
 
+int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
+				u32 value, unsigned int timeout_ms);
+
 #endif	/* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 14362c0..74d998d 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -19,70 +19,56 @@
 #include <linux/dma-mapping.h>
 #include <linux/usb/chipidea.h>
 #include <linux/clk.h>
-#include <linux/regulator/consumer.h>
 
 #include "ci.h"
 #include "ci_hdrc_imx.h"
 
-#define pdev_to_phy(pdev) \
-	((struct usb_phy *)platform_get_drvdata(pdev))
-
 struct ci_hdrc_imx_data {
 	struct usb_phy *phy;
 	struct platform_device *ci_pdev;
 	struct clk *clk;
-	struct regulator *reg_vbus;
+	struct imx_usbmisc_data *usbmisc_data;
 };
 
-static const struct usbmisc_ops *usbmisc_ops;
-
 /* Common functions shared by usbmisc drivers */
 
-int usbmisc_set_ops(const struct usbmisc_ops *ops)
-{
-	if (usbmisc_ops)
-		return -EBUSY;
-
-	usbmisc_ops = ops;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(usbmisc_set_ops);
-
-void usbmisc_unset_ops(const struct usbmisc_ops *ops)
-{
-	usbmisc_ops = NULL;
-}
-EXPORT_SYMBOL_GPL(usbmisc_unset_ops);
-
-int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
+static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
+	struct imx_usbmisc_data *data;
 	int ret;
 
-	usbdev->dev = dev;
+	/*
+	 * In case the fsl,usbmisc property is not present this device doesn't
+	 * need usbmisc. Return NULL (which is no error here)
+	 */
+	if (!of_get_property(np, "fsl,usbmisc", NULL))
+		return NULL;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
 
 	ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
 					0, &args);
 	if (ret) {
 		dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
 			ret);
-		memset(usbdev, 0, sizeof(*usbdev));
-		return ret;
+		return ERR_PTR(ret);
 	}
-	usbdev->index = args.args[0];
+
+	data->index = args.args[0];
 	of_node_put(args.np);
 
 	if (of_find_property(np, "disable-over-current", NULL))
-		usbdev->disable_oc = 1;
+		data->disable_oc = 1;
 
 	if (of_find_property(np, "external-vbus-divider", NULL))
-		usbdev->evdo = 1;
+		data->evdo = 1;
 
-	return 0;
+	return data;
 }
-EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
 
 /* End of common functions shared by usbmisc drivers*/
 
@@ -93,27 +79,19 @@
 		.name		= "ci_hdrc_imx",
 		.capoffset	= DEF_CAPOFFSET,
 		.flags		= CI_HDRC_REQUIRE_TRANSCEIVER |
-				  CI_HDRC_PULLUP_ON_VBUS |
 				  CI_HDRC_DISABLE_STREAMING,
 	};
-	struct resource *res;
 	int ret;
 
-	if (of_find_property(pdev->dev.of_node, "fsl,usbmisc", NULL)
-		&& !usbmisc_ops)
-		return -EPROBE_DEFER;
-
 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
 		return -ENOMEM;
 	}
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Can't get device resources!\n");
-		return -ENOENT;
-	}
+	data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
+	if (IS_ERR(data->usbmisc_data))
+		return PTR_ERR(data->usbmisc_data);
 
 	data->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(data->clk)) {
@@ -141,20 +119,6 @@
 		goto err_clk;
 	}
 
-	/* we only support host now, so enable vbus here */
-	data->reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
-	if (!IS_ERR(data->reg_vbus)) {
-		ret = regulator_enable(data->reg_vbus);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Failed to enable vbus regulator, err=%d\n",
-				ret);
-			goto err_clk;
-		}
-	} else {
-		data->reg_vbus = NULL;
-	}
-
 	pdata.phy = data->phy;
 
 	if (!pdev->dev.dma_mask)
@@ -162,12 +126,12 @@
 	if (!pdev->dev.coherent_dma_mask)
 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
-	if (usbmisc_ops && usbmisc_ops->init) {
-		ret = usbmisc_ops->init(&pdev->dev);
+	if (data->usbmisc_data) {
+		ret = imx_usbmisc_init(data->usbmisc_data);
 		if (ret) {
-			dev_err(&pdev->dev,
-				"usbmisc init failed, ret=%d\n", ret);
-			goto err;
+			dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n",
+					ret);
+			goto err_clk;
 		}
 	}
 
@@ -179,14 +143,14 @@
 		dev_err(&pdev->dev,
 			"Can't register ci_hdrc platform device, err=%d\n",
 			ret);
-		goto err;
+		goto err_clk;
 	}
 
-	if (usbmisc_ops && usbmisc_ops->post) {
-		ret = usbmisc_ops->post(&pdev->dev);
+	if (data->usbmisc_data) {
+		ret = imx_usbmisc_init_post(data->usbmisc_data);
 		if (ret) {
-			dev_err(&pdev->dev,
-				"usbmisc post failed, ret=%d\n", ret);
+			dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n",
+					ret);
 			goto disable_device;
 		}
 	}
@@ -200,9 +164,6 @@
 
 disable_device:
 	ci_hdrc_remove_device(data->ci_pdev);
-err:
-	if (data->reg_vbus)
-		regulator_disable(data->reg_vbus);
 err_clk:
 	clk_disable_unprepare(data->clk);
 	return ret;
@@ -215,13 +176,8 @@
 	pm_runtime_disable(&pdev->dev);
 	ci_hdrc_remove_device(data->ci_pdev);
 
-	if (data->reg_vbus)
-		regulator_disable(data->reg_vbus);
-
-	if (data->phy) {
+	if (data->phy)
 		usb_phy_shutdown(data->phy);
-		module_put(data->phy->dev->driver->owner);
-	}
 
 	clk_disable_unprepare(data->clk);
 
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h
index 550bfa4..c727159 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.h
+++ b/drivers/usb/chipidea/ci_hdrc_imx.h
@@ -9,23 +9,12 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-/* Used to set SoC specific callbacks */
-struct usbmisc_ops {
-	/* It's called once when probe a usb device */
-	int (*init)(struct device *dev);
-	/* It's called once after adding a usb device */
-	int (*post)(struct device *dev);
-};
-
-struct usbmisc_usb_device {
-	struct device *dev; /* usb controller device */
+struct imx_usbmisc_data {
 	int index;
 
 	unsigned int disable_oc:1; /* over current detect disabled */
 	unsigned int evdo:1; /* set external vbus divider option */
 };
 
-int usbmisc_set_ops(const struct usbmisc_ops *ops);
-void usbmisc_unset_ops(const struct usbmisc_ops *ops);
-int
-usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev);
+int imx_usbmisc_init(struct imx_usbmisc_data *);
+int imx_usbmisc_init_post(struct imx_usbmisc_data *);
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index fb657ef..2d51d85 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -49,7 +49,6 @@
 	.name			= "ci_hdrc_msm",
 	.flags			= CI_HDRC_REGS_SHARED |
 				  CI_HDRC_REQUIRE_TRANSCEIVER |
-				  CI_HDRC_PULLUP_ON_VBUS |
 				  CI_HDRC_DISABLE_STREAMING,
 
 	.notify_event		= ci_hdrc_msm_notify_event,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index a5df24c..9462640 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -65,12 +65,14 @@
 #include <linux/usb/chipidea.h>
 #include <linux/usb/of.h>
 #include <linux/phy.h>
+#include <linux/regulator/consumer.h>
 
 #include "ci.h"
 #include "udc.h"
 #include "bits.h"
 #include "host.h"
 #include "debug.h"
+#include "otg.h"
 
 /* Controller register map */
 static uintptr_t ci_regs_nolpm[] = {
@@ -197,6 +199,12 @@
 	if (ci->hw_ep_max > ENDPT_MAX)
 		return -ENODEV;
 
+	/* Disable all interrupts bits */
+	hw_write(ci, OP_USBINTR, 0xffffffff, 0);
+
+	/* Clear all interrupts status bits*/
+	hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff);
+
 	dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
 		ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
 
@@ -264,8 +272,6 @@
 	while (hw_read(ci, OP_USBCMD, USBCMD_RST))
 		udelay(10);		/* not RTOS friendly */
 
-	hw_phymode_configure(ci);
-
 	if (ci->platdata->notify_event)
 		ci->platdata->notify_event(ci,
 			CI_HDRC_CONTROLLER_RESET_EVENT);
@@ -289,37 +295,35 @@
 }
 
 /**
- * ci_otg_role - pick role based on ID pin state
+ * hw_wait_reg: wait the register value
+ *
+ * Sometimes, it needs to wait register value before going on.
+ * Eg, when switch to device mode, the vbus value should be lower
+ * than OTGSC_BSV before connects to host.
+ *
  * @ci: the controller
+ * @reg: register index
+ * @mask: mast bit
+ * @value: the bit value to wait
+ * @timeout_ms: timeout in millisecond
+ *
+ * This function returns an error code if timeout
  */
-static enum ci_role ci_otg_role(struct ci_hdrc *ci)
+int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
+				u32 value, unsigned int timeout_ms)
 {
-	u32 sts = hw_read(ci, OP_OTGSC, ~0);
-	enum ci_role role = sts & OTGSC_ID
-		? CI_ROLE_GADGET
-		: CI_ROLE_HOST;
+	unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms);
 
-	return role;
-}
-
-/**
- * ci_role_work - perform role changing based on ID pin
- * @work: work struct
- */
-static void ci_role_work(struct work_struct *work)
-{
-	struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
-	enum ci_role role = ci_otg_role(ci);
-
-	if (role != ci->role) {
-		dev_dbg(ci->dev, "switching from %s to %s\n",
-			ci_role(ci)->name, ci->roles[role]->name);
-
-		ci_role_stop(ci);
-		ci_role_start(ci, role);
+	while (hw_read(ci, reg, mask) != value) {
+		if (time_after(jiffies, elapse)) {
+			dev_err(ci->dev, "timeout waiting for %08x in %d\n",
+					mask, reg);
+			return -ETIMEDOUT;
+		}
+		msleep(20);
 	}
 
-	enable_irq(ci->irq);
+	return 0;
 }
 
 static irqreturn_t ci_irq(int irq, void *data)
@@ -331,17 +335,53 @@
 	if (ci->is_otg)
 		otgsc = hw_read(ci, OP_OTGSC, ~0);
 
+	/*
+	 * Handle id change interrupt, it indicates device/host function
+	 * switch.
+	 */
+	if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
+		ci->id_event = true;
+		ci_clear_otg_interrupt(ci, OTGSC_IDIS);
+		disable_irq_nosync(ci->irq);
+		queue_work(ci->wq, &ci->work);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * Handle vbus change interrupt, it indicates device connection
+	 * and disconnection events.
+	 */
+	if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+		ci->b_sess_valid_event = true;
+		ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+		disable_irq_nosync(ci->irq);
+		queue_work(ci->wq, &ci->work);
+		return IRQ_HANDLED;
+	}
+
+	/* Handle device/host interrupt */
 	if (ci->role != CI_ROLE_END)
 		ret = ci_role(ci)->irq(ci);
 
-	if (ci->is_otg && (otgsc & OTGSC_IDIS)) {
-		hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
-		disable_irq_nosync(ci->irq);
-		queue_work(ci->wq, &ci->work);
-		ret = IRQ_HANDLED;
+	return ret;
+}
+
+static int ci_get_platdata(struct device *dev,
+		struct ci_hdrc_platform_data *platdata)
+{
+	/* Get the vbus regulator */
+	platdata->reg_vbus = devm_regulator_get(dev, "vbus");
+	if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
+		return -EPROBE_DEFER;
+	} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
+		platdata->reg_vbus = NULL; /* no vbus regualator is needed */
+	} else if (IS_ERR(platdata->reg_vbus)) {
+		dev_err(dev, "Getting regulator error: %ld\n",
+			PTR_ERR(platdata->reg_vbus));
+		return PTR_ERR(platdata->reg_vbus);
 	}
 
-	return ret;
+	return 0;
 }
 
 static DEFINE_IDA(ci_ida);
@@ -353,6 +393,10 @@
 	struct platform_device *pdev;
 	int id, ret;
 
+	ret = ci_get_platdata(dev, platdata);
+	if (ret)
+		return ERR_PTR(ret);
+
 	id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL);
 	if (id < 0)
 		return ERR_PTR(id);
@@ -398,6 +442,29 @@
 }
 EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
 
+static inline void ci_role_destroy(struct ci_hdrc *ci)
+{
+	ci_hdrc_gadget_destroy(ci);
+	ci_hdrc_host_destroy(ci);
+	if (ci->is_otg)
+		ci_hdrc_otg_destroy(ci);
+}
+
+static void ci_get_otg_capable(struct ci_hdrc *ci)
+{
+	if (ci->platdata->flags & CI_HDRC_DUAL_ROLE_NOT_OTG)
+		ci->is_otg = false;
+	else
+		ci->is_otg = (hw_read(ci, CAP_DCCPARAMS,
+				DCCPARAMS_DC | DCCPARAMS_HC)
+					== (DCCPARAMS_DC | DCCPARAMS_HC));
+	if (ci->is_otg) {
+		dev_dbg(ci->dev, "It is OTG capable controller\n");
+		ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+		ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+	}
+}
+
 static int ci_hdrc_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
@@ -406,15 +473,13 @@
 	void __iomem	*base;
 	int		ret;
 	enum usb_dr_mode dr_mode;
+	struct device_node *of_node = dev->of_node ?: dev->parent->of_node;
 
 	if (!dev->platform_data) {
 		dev_err(dev, "platform data missing\n");
 		return -ENODEV;
 	}
 
-	if (!dev->of_node && dev->parent)
-		dev->of_node = dev->parent->of_node;
-
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(base))
@@ -447,18 +512,15 @@
 		return -ENODEV;
 	}
 
-	INIT_WORK(&ci->work, ci_role_work);
-	ci->wq = create_singlethread_workqueue("ci_otg");
-	if (!ci->wq) {
-		dev_err(dev, "can't create workqueue\n");
-		return -ENODEV;
-	}
+	ci_get_otg_capable(ci);
 
 	if (!ci->platdata->phy_mode)
-		ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
+		ci->platdata->phy_mode = of_usb_get_phy_mode(of_node);
+
+	hw_phymode_configure(ci);
 
 	if (!ci->platdata->dr_mode)
-		ci->platdata->dr_mode = of_usb_get_dr_mode(dev->of_node);
+		ci->platdata->dr_mode = of_usb_get_dr_mode(of_node);
 
 	if (ci->platdata->dr_mode == USB_DR_MODE_UNKNOWN)
 		ci->platdata->dr_mode = USB_DR_MODE_OTG;
@@ -479,15 +541,34 @@
 
 	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
 		dev_err(dev, "no supported roles\n");
-		ret = -ENODEV;
-		goto rm_wq;
+		return -ENODEV;
+	}
+
+	if (ci->is_otg) {
+		ret = ci_hdrc_otg_init(ci);
+		if (ret) {
+			dev_err(dev, "init otg fails, ret = %d\n", ret);
+			goto stop;
+		}
 	}
 
 	if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
-		ci->is_otg = true;
-		/* ID pin needs 1ms debouce time, we delay 2ms for safe */
-		mdelay(2);
-		ci->role = ci_otg_role(ci);
+		if (ci->is_otg) {
+			/*
+			 * ID pin needs 1ms debouce time,
+			 * we delay 2ms for safe.
+			 */
+			mdelay(2);
+			ci->role = ci_otg_role(ci);
+			ci_enable_otg_interrupt(ci, OTGSC_IDIE);
+		} else {
+			/*
+			 * If the controller is not OTG capable, but support
+			 * role switch, the defalt role is gadget, and the
+			 * user can switch it through debugfs.
+			 */
+			ci->role = CI_ROLE_GADGET;
+		}
 	} else {
 		ci->role = ci->roles[CI_ROLE_HOST]
 			? CI_ROLE_HOST
@@ -497,8 +578,7 @@
 	ret = ci_role_start(ci, ci->role);
 	if (ret) {
 		dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
-		ret = -ENODEV;
-		goto rm_wq;
+		goto stop;
 	}
 
 	platform_set_drvdata(pdev, ci);
@@ -507,19 +587,13 @@
 	if (ret)
 		goto stop;
 
-	if (ci->is_otg)
-		hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
-
 	ret = dbg_create_files(ci);
 	if (!ret)
 		return 0;
 
 	free_irq(ci->irq, ci);
 stop:
-	ci_role_stop(ci);
-rm_wq:
-	flush_workqueue(ci->wq);
-	destroy_workqueue(ci->wq);
+	ci_role_destroy(ci);
 
 	return ret;
 }
@@ -529,10 +603,8 @@
 	struct ci_hdrc *ci = platform_get_drvdata(pdev);
 
 	dbg_remove_files(ci);
-	flush_workqueue(ci->wq);
-	destroy_workqueue(ci->wq);
 	free_irq(ci->irq, ci);
-	ci_role_stop(ci);
+	ci_role_destroy(ci);
 
 	return 0;
 }
@@ -548,7 +620,6 @@
 module_platform_driver(ci_hdrc_driver);
 
 MODULE_ALIAS("platform:ci_hdrc");
-MODULE_ALIAS("platform:ci13xxx");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
 MODULE_DESCRIPTION("ChipIdea HDRC Driver");
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 40d0fda..6f96795 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -24,6 +24,7 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/chipidea.h>
+#include <linux/regulator/consumer.h>
 
 #include "../host/ehci.h"
 
@@ -63,10 +64,21 @@
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = ci->hw_bank.cap;
 	ehci->has_hostpc = ci->hw_bank.lpm;
+	ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
+
+	if (ci->platdata->reg_vbus) {
+		ret = regulator_enable(ci->platdata->reg_vbus);
+		if (ret) {
+			dev_err(ci->dev,
+				"Failed to enable vbus regulator, ret=%d\n",
+				ret);
+			goto put_hcd;
+		}
+	}
 
 	ret = usb_add_hcd(hcd, 0, 0);
 	if (ret)
-		usb_put_hcd(hcd);
+		goto disable_reg;
 	else
 		ci->hcd = hcd;
 
@@ -74,6 +86,14 @@
 		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
 
 	return ret;
+
+disable_reg:
+	regulator_disable(ci->platdata->reg_vbus);
+
+put_hcd:
+	usb_put_hcd(hcd);
+
+	return ret;
 }
 
 static void host_stop(struct ci_hdrc *ci)
@@ -82,6 +102,15 @@
 
 	usb_remove_hcd(hcd);
 	usb_put_hcd(hcd);
+	if (ci->platdata->reg_vbus)
+		regulator_disable(ci->platdata->reg_vbus);
+}
+
+
+void ci_hdrc_host_destroy(struct ci_hdrc *ci)
+{
+	if (ci->role == CI_ROLE_HOST)
+		host_stop(ci);
 }
 
 int ci_hdrc_host_init(struct ci_hdrc *ci)
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 058875c..5707bf3 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -4,6 +4,7 @@
 #ifdef CONFIG_USB_CHIPIDEA_HOST
 
 int ci_hdrc_host_init(struct ci_hdrc *ci);
+void ci_hdrc_host_destroy(struct ci_hdrc *ci);
 
 #else
 
@@ -12,6 +13,11 @@
 	return -ENXIO;
 }
 
+static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
new file mode 100644
index 0000000..39bd7ec
--- /dev/null
+++ b/drivers/usb/chipidea/otg.c
@@ -0,0 +1,120 @@
+/*
+ * otg.c - ChipIdea USB IP core OTG driver
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * 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 file mainly handles otgsc register, it may include OTG operation
+ * in the future.
+ */
+
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "bits.h"
+#include "otg.h"
+
+/**
+ * ci_otg_role - pick role based on ID pin state
+ * @ci: the controller
+ */
+enum ci_role ci_otg_role(struct ci_hdrc *ci)
+{
+	u32 sts = hw_read(ci, OP_OTGSC, ~0);
+	enum ci_role role = sts & OTGSC_ID
+		? CI_ROLE_GADGET
+		: CI_ROLE_HOST;
+
+	return role;
+}
+
+void ci_handle_vbus_change(struct ci_hdrc *ci)
+{
+	u32 otgsc;
+
+	if (!ci->is_otg)
+		return;
+
+	otgsc = hw_read(ci, OP_OTGSC, ~0);
+
+	if (otgsc & OTGSC_BSV)
+		usb_gadget_vbus_connect(&ci->gadget);
+	else
+		usb_gadget_vbus_disconnect(&ci->gadget);
+}
+
+#define CI_VBUS_STABLE_TIMEOUT_MS 5000
+static void ci_handle_id_switch(struct ci_hdrc *ci)
+{
+	enum ci_role role = ci_otg_role(ci);
+
+	if (role != ci->role) {
+		dev_dbg(ci->dev, "switching from %s to %s\n",
+			ci_role(ci)->name, ci->roles[role]->name);
+
+		ci_role_stop(ci);
+		/* wait vbus lower than OTGSC_BSV */
+		hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+				CI_VBUS_STABLE_TIMEOUT_MS);
+		ci_role_start(ci, role);
+	}
+}
+/**
+ * ci_otg_work - perform otg (vbus/id) event handle
+ * @work: work struct
+ */
+static void ci_otg_work(struct work_struct *work)
+{
+	struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
+
+	if (ci->id_event) {
+		ci->id_event = false;
+		ci_handle_id_switch(ci);
+	} else if (ci->b_sess_valid_event) {
+		ci->b_sess_valid_event = false;
+		ci_handle_vbus_change(ci);
+	} else
+		dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
+
+	enable_irq(ci->irq);
+}
+
+
+/**
+ * ci_hdrc_otg_init - initialize otg struct
+ * ci: the controller
+ */
+int ci_hdrc_otg_init(struct ci_hdrc *ci)
+{
+	INIT_WORK(&ci->work, ci_otg_work);
+	ci->wq = create_singlethread_workqueue("ci_otg");
+	if (!ci->wq) {
+		dev_err(ci->dev, "can't create workqueue\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ * ci_hdrc_otg_destroy - destroy otg struct
+ * ci: the controller
+ */
+void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
+{
+	if (ci->wq) {
+		flush_workqueue(ci->wq);
+		destroy_workqueue(ci->wq);
+	}
+	ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+	ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+}
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
new file mode 100644
index 0000000..2d9f090
--- /dev/null
+++ b/drivers/usb/chipidea/otg.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_OTG_H
+#define __DRIVERS_USB_CHIPIDEA_OTG_H
+
+static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+	/* Only clear request bits */
+	hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits);
+}
+
+static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+	hw_write(ci, OP_OTGSC, bits, bits);
+}
+
+static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits)
+{
+	hw_write(ci, OP_OTGSC, bits, 0);
+}
+
+int ci_hdrc_otg_init(struct ci_hdrc *ci);
+void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
+enum ci_role ci_otg_role(struct ci_hdrc *ci);
+void ci_handle_vbus_change(struct ci_hdrc *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index e475fcd..6b4c2f2 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -27,6 +27,7 @@
 #include "udc.h"
 #include "bits.h"
 #include "debug.h"
+#include "otg.h"
 
 /* control endpoint description */
 static const struct usb_endpoint_descriptor
@@ -84,8 +85,10 @@
 		/* interrupt, error, port change, reset, sleep/suspend */
 		hw_write(ci, OP_USBINTR, ~0,
 			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
 	} else {
 		hw_write(ci, OP_USBINTR, ~0, 0);
+		hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
 	}
 	return 0;
 }
@@ -1445,9 +1448,6 @@
 	unsigned long flags;
 	int gadget_ready = 0;
 
-	if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS))
-		return -EOPNOTSUPP;
-
 	spin_lock_irqsave(&ci->lock, flags);
 	ci->vbus_active = is_active;
 	if (ci->driver)
@@ -1459,6 +1459,7 @@
 			pm_runtime_get_sync(&_gadget->dev);
 			hw_device_reset(ci, USBMODE_CM_DC);
 			hw_device_state(ci, ci->ep0out->qh.dma);
+			dev_dbg(ci->dev, "Connected to host\n");
 		} else {
 			hw_device_state(ci, 0);
 			if (ci->platdata->notify_event)
@@ -1466,6 +1467,7 @@
 				CI_HDRC_CONTROLLER_STOPPED_EVENT);
 			_gadget_stop_activity(&ci->gadget);
 			pm_runtime_put_sync(&_gadget->dev);
+			dev_dbg(ci->dev, "Disconnected from host\n");
 		}
 	}
 
@@ -1509,6 +1511,9 @@
 {
 	struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
 
+	if (!ci->vbus_active)
+		return -EOPNOTSUPP;
+
 	if (is_on)
 		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
 	else
@@ -1630,14 +1635,11 @@
 
 	ci->driver = driver;
 	pm_runtime_get_sync(&ci->gadget.dev);
-	if (ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) {
-		if (ci->vbus_active) {
-			if (ci->platdata->flags & CI_HDRC_REGS_SHARED)
-				hw_device_reset(ci, USBMODE_CM_DC);
-		} else {
-			pm_runtime_put_sync(&ci->gadget.dev);
-			goto done;
-		}
+	if (ci->vbus_active) {
+		hw_device_reset(ci, USBMODE_CM_DC);
+	} else {
+		pm_runtime_put_sync(&ci->gadget.dev);
+		goto done;
 	}
 
 	retval = hw_device_state(ci, ci->ep0out->qh.dma);
@@ -1660,8 +1662,7 @@
 
 	spin_lock_irqsave(&ci->lock, flags);
 
-	if (!(ci->platdata->flags & CI_HDRC_PULLUP_ON_VBUS) ||
-			ci->vbus_active) {
+	if (ci->vbus_active) {
 		hw_device_state(ci, 0);
 		if (ci->platdata->notify_event)
 			ci->platdata->notify_event(ci,
@@ -1796,16 +1797,15 @@
 		}
 	}
 
-	if (!(ci->platdata->flags & CI_HDRC_REGS_SHARED)) {
-		retval = hw_device_reset(ci, USBMODE_CM_DC);
-		if (retval)
-			goto put_transceiver;
-	}
-
 	if (ci->transceiver) {
 		retval = otg_set_peripheral(ci->transceiver->otg,
 						&ci->gadget);
-		if (retval)
+		/*
+		 * If we implement all USB functions using chipidea drivers,
+		 * it doesn't need to call above API, meanwhile, if we only
+		 * use gadget function, calling above API is useless.
+		 */
+		if (retval && retval != -ENOTSUPP)
 			goto put_transceiver;
 	}
 
@@ -1816,6 +1816,9 @@
 	pm_runtime_no_callbacks(&ci->gadget.dev);
 	pm_runtime_enable(&ci->gadget.dev);
 
+	/* Update ci->vbus_active */
+	ci_handle_vbus_change(ci);
+
 	return retval;
 
 remove_trans:
@@ -1839,13 +1842,13 @@
 }
 
 /**
- * udc_remove: parent remove must call this to remove UDC
+ * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
  *
  * No interrupts active, the IRQ has been released
  */
-static void udc_stop(struct ci_hdrc *ci)
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
 {
-	if (ci == NULL)
+	if (!ci->roles[CI_ROLE_GADGET])
 		return;
 
 	usb_del_gadget_udc(&ci->gadget);
@@ -1860,15 +1863,32 @@
 		if (ci->global_phy)
 			usb_put_phy(ci->transceiver);
 	}
-	/* my kobject is dynamic, I swear! */
-	memset(&ci->gadget, 0, sizeof(ci->gadget));
+}
+
+static int udc_id_switch_for_device(struct ci_hdrc *ci)
+{
+	if (ci->is_otg) {
+		ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+		ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+	}
+
+	return 0;
+}
+
+static void udc_id_switch_for_host(struct ci_hdrc *ci)
+{
+	if (ci->is_otg) {
+		/* host doesn't care B_SESSION_VALID event */
+		ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+		ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
+	}
 }
 
 /**
  * ci_hdrc_gadget_init - initialize device related bits
  * ci: the controller
  *
- * This function enables the gadget role, if the device is "device capable".
+ * This function initializes the gadget, if the device is "device capable".
  */
 int ci_hdrc_gadget_init(struct ci_hdrc *ci)
 {
@@ -1881,11 +1901,11 @@
 	if (!rdrv)
 		return -ENOMEM;
 
-	rdrv->start	= udc_start;
-	rdrv->stop	= udc_stop;
+	rdrv->start	= udc_id_switch_for_device;
+	rdrv->stop	= udc_id_switch_for_host;
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
 	ci->roles[CI_ROLE_GADGET] = rdrv;
 
-	return 0;
+	return udc_start(ci);
 }
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index 455ac21..e66df00 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -84,6 +84,7 @@
 #ifdef CONFIG_USB_CHIPIDEA_UDC
 
 int ci_hdrc_gadget_init(struct ci_hdrc *ci);
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci);
 
 #else
 
@@ -92,6 +93,11 @@
 	return -ENXIO;
 }
 
+static inline void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
+{
+
+}
+
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index ac5a461..8a1094b 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -18,8 +18,6 @@
 
 #include "ci_hdrc_imx.h"
 
-#define USB_DEV_MAX 4
-
 #define MX25_USB_PHY_CTRL_OFFSET	0x08
 #define MX25_BM_EXTERNAL_VBUS_DIVIDER	BIT(23)
 
@@ -32,51 +30,34 @@
 
 #define MX6_BM_OVER_CUR_DIS		BIT(7)
 
+struct usbmisc_ops {
+	/* It's called once when probe a usb device */
+	int (*init)(struct imx_usbmisc_data *data);
+	/* It's called once after adding a usb device */
+	int (*post)(struct imx_usbmisc_data *data);
+};
+
 struct imx_usbmisc {
 	void __iomem *base;
 	spinlock_t lock;
 	struct clk *clk;
-	struct usbmisc_usb_device usbdev[USB_DEV_MAX];
 	const struct usbmisc_ops *ops;
 };
 
 static struct imx_usbmisc *usbmisc;
 
-static struct usbmisc_usb_device *get_usbdev(struct device *dev)
+static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
 {
-	int i, ret;
-
-	for (i = 0; i < USB_DEV_MAX; i++) {
-		if (usbmisc->usbdev[i].dev == dev)
-			return &usbmisc->usbdev[i];
-		else if (!usbmisc->usbdev[i].dev)
-			break;
-	}
-
-	if (i >= USB_DEV_MAX)
-		return ERR_PTR(-EBUSY);
-
-	ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
-	if (ret)
-		return ERR_PTR(ret);
-
-	return &usbmisc->usbdev[i];
-}
-
-static int usbmisc_imx25_post(struct device *dev)
-{
-	struct usbmisc_usb_device *usbdev;
 	void __iomem *reg;
 	unsigned long flags;
 	u32 val;
 
-	usbdev = get_usbdev(dev);
-	if (IS_ERR(usbdev))
-		return PTR_ERR(usbdev);
+	if (data->index > 2)
+		return -EINVAL;
 
 	reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
 
-	if (usbdev->evdo) {
+	if (data->evdo) {
 		spin_lock_irqsave(&usbmisc->lock, flags);
 		val = readl(reg);
 		writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
@@ -87,20 +68,18 @@
 	return 0;
 }
 
-static int usbmisc_imx53_init(struct device *dev)
+static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
 {
-	struct usbmisc_usb_device *usbdev;
 	void __iomem *reg = NULL;
 	unsigned long flags;
 	u32 val = 0;
 
-	usbdev = get_usbdev(dev);
-	if (IS_ERR(usbdev))
-		return PTR_ERR(usbdev);
+	if (data->index > 3)
+		return -EINVAL;
 
-	if (usbdev->disable_oc) {
+	if (data->disable_oc) {
 		spin_lock_irqsave(&usbmisc->lock, flags);
-		switch (usbdev->index) {
+		switch (data->index) {
 		case 0:
 			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
 			val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
@@ -126,22 +105,19 @@
 	return 0;
 }
 
-static int usbmisc_imx6q_init(struct device *dev)
+static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
 {
-
-	struct usbmisc_usb_device *usbdev;
 	unsigned long flags;
 	u32 reg;
 
-	usbdev = get_usbdev(dev);
-	if (IS_ERR(usbdev))
-		return PTR_ERR(usbdev);
+	if (data->index > 3)
+		return -EINVAL;
 
-	if (usbdev->disable_oc) {
+	if (data->disable_oc) {
 		spin_lock_irqsave(&usbmisc->lock, flags);
-		reg = readl(usbmisc->base + usbdev->index * 4);
+		reg = readl(usbmisc->base + data->index * 4);
 		writel(reg | MX6_BM_OVER_CUR_DIS,
-			usbmisc->base + usbdev->index * 4);
+			usbmisc->base + data->index * 4);
 		spin_unlock_irqrestore(&usbmisc->lock, flags);
 	}
 
@@ -160,6 +136,26 @@
 	.init = usbmisc_imx6q_init,
 };
 
+int imx_usbmisc_init(struct imx_usbmisc_data *data)
+{
+	if (!usbmisc)
+		return -EPROBE_DEFER;
+	if (!usbmisc->ops->init)
+		return 0;
+	return usbmisc->ops->init(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_init);
+
+int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
+{
+	if (!usbmisc)
+		return -EPROBE_DEFER;
+	if (!usbmisc->ops->post)
+		return 0;
+	return usbmisc->ops->post(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
+
 static const struct of_device_id usbmisc_imx_dt_ids[] = {
 	{
 		.compatible = "fsl,imx25-usbmisc",
@@ -216,19 +212,12 @@
 		of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
 	data->ops = (const struct usbmisc_ops *)tmp_dev->data;
 	usbmisc = data;
-	ret = usbmisc_set_ops(data->ops);
-	if (ret) {
-		usbmisc = NULL;
-		clk_disable_unprepare(data->clk);
-		return ret;
-	}
 
 	return 0;
 }
 
 static int usbmisc_imx_remove(struct platform_device *pdev)
 {
-	usbmisc_unset_ops(usbmisc->ops);
 	clk_disable_unprepare(usbmisc->clk);
 	usbmisc = NULL;
 	return 0;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 9f49bfe..3e7560f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1295,7 +1295,7 @@
 			 usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
 			 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
 			 /* works around buggy devices */
-			 epctrl->bInterval ? epctrl->bInterval : 0xff);
+			 epctrl->bInterval ? epctrl->bInterval : 16);
 	acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	acm->ctrlurb->transfer_dma = acm->ctrl_dma;
 
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 8a230f0e..d3318a0 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -209,6 +209,7 @@
 static void wdm_int_callback(struct urb *urb)
 {
 	int rv = 0;
+	int responding;
 	int status = urb->status;
 	struct wdm_device *desc;
 	struct usb_cdc_notification *dr;
@@ -262,8 +263,8 @@
 
 	spin_lock(&desc->iuspin);
 	clear_bit(WDM_READ, &desc->flags);
-	set_bit(WDM_RESPONDING, &desc->flags);
-	if (!test_bit(WDM_DISCONNECTING, &desc->flags)
+	responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
+	if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags)
 		&& !test_bit(WDM_SUSPENDING, &desc->flags)) {
 		rv = usb_submit_urb(desc->response, GFP_ATOMIC);
 		dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
@@ -685,16 +686,20 @@
 {
 	struct wdm_device *desc = container_of(work, struct wdm_device, rxwork);
 	unsigned long flags;
-	int rv;
+	int rv = 0;
+	int responding;
 
 	spin_lock_irqsave(&desc->iuspin, flags);
 	if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
 		spin_unlock_irqrestore(&desc->iuspin, flags);
 	} else {
+		responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
 		spin_unlock_irqrestore(&desc->iuspin, flags);
-		rv = usb_submit_urb(desc->response, GFP_KERNEL);
+		if (!responding)
+			rv = usb_submit_urb(desc->response, GFP_KERNEL);
 		if (rv < 0 && rv != -EPERM) {
 			spin_lock_irqsave(&desc->iuspin, flags);
+			clear_bit(WDM_RESPONDING, &desc->flags);
 			if (!test_bit(WDM_DISCONNECTING, &desc->flags))
 				schedule_work(&desc->rxwork);
 			spin_unlock_irqrestore(&desc->iuspin, flags);
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 83b4ef4..09de131 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -19,6 +19,8 @@
  * http://www.gnu.org/copyleft/gpl.html.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -119,7 +121,6 @@
 	struct usbtmc_device_data *data = to_usbtmc_data(kref);
 
 	usb_put_dev(data->usb_dev);
-	kfree(data);
 }
 
 static int usbtmc_open(struct inode *inode, struct file *filp)
@@ -130,10 +131,8 @@
 
 	intf = usb_find_interface(&usbtmc_driver, iminor(inode));
 	if (!intf) {
-		printk(KERN_ERR KBUILD_MODNAME
-		       ": can not find device for minor %d", iminor(inode));
-		retval = -ENODEV;
-		goto exit;
+		pr_err("can not find device for minor %d", iminor(inode));
+		return -ENODEV;
 	}
 
 	data = usb_get_intfdata(intf);
@@ -142,7 +141,6 @@
 	/* Store pointer in file structure's private data field */
 	filp->private_data = data;
 
-exit:
 	return retval;
 }
 
@@ -394,12 +392,12 @@
 	 */
 	buffer[0] = 2;
 	buffer[1] = data->bTag;
-	buffer[2] = ~(data->bTag);
+	buffer[2] = ~data->bTag;
 	buffer[3] = 0; /* Reserved */
-	buffer[4] = (transfer_size) & 255;
-	buffer[5] = ((transfer_size) >> 8) & 255;
-	buffer[6] = ((transfer_size) >> 16) & 255;
-	buffer[7] = ((transfer_size) >> 24) & 255;
+	buffer[4] = transfer_size >> 0;
+	buffer[5] = transfer_size >> 8;
+	buffer[6] = transfer_size >> 16;
+	buffer[7] = transfer_size >> 24;
 	buffer[8] = data->TermCharEnabled * 2;
 	/* Use term character? */
 	buffer[9] = data->TermChar;
@@ -418,7 +416,7 @@
 	/* Increment bTag -- and increment again if zero */
 	data->bTag++;
 	if (!data->bTag)
-		(data->bTag)++;
+		data->bTag++;
 
 	if (retval < 0) {
 		dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);
@@ -473,7 +471,7 @@
 	done = 0;
 
 	while (remaining > 0) {
-		if (!(data->rigol_quirk)) {
+		if (!data->rigol_quirk) {
 			dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
 
 			if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
@@ -510,7 +508,7 @@
 		}
 
 		/* Parse header in first packet */
-		if ((done == 0) || (!(data->rigol_quirk))) {
+		if ((done == 0) || !data->rigol_quirk) {
 			/* Sanity checks for the header */
 			if (actual < USBTMC_HEADER_SIZE) {
 				dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
@@ -554,14 +552,14 @@
 				if (remaining > n_characters)
 					remaining = n_characters;
 				/* Remove padding if it exists */
-				if (actual > remaining) 
+				if (actual > remaining)
 					actual = remaining;
 			}
 			else {
 				if (this_part > n_characters)
 					this_part = n_characters;
 				/* Remove padding if it exists */
-				if (actual > this_part) 
+				if (actual > this_part)
 					actual = this_part;
 			}
 
@@ -570,7 +568,7 @@
 			remaining -= actual;
 
 			/* Terminate if end-of-message bit received from device */
-			if ((buffer[8] &  0x01) && (actual >= n_characters))
+			if ((buffer[8] & 0x01) && (actual >= n_characters))
 				remaining = 0;
 
 			dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
@@ -585,7 +583,7 @@
 			done += actual;
 		}
 		else  {
-			if (actual > remaining) 
+			if (actual > remaining)
 				actual = remaining;
 
 			remaining -= actual;
@@ -651,12 +649,12 @@
 		/* Setup IO buffer for DEV_DEP_MSG_OUT message */
 		buffer[0] = 1;
 		buffer[1] = data->bTag;
-		buffer[2] = ~(data->bTag);
+		buffer[2] = ~data->bTag;
 		buffer[3] = 0; /* Reserved */
-		buffer[4] = this_part & 255;
-		buffer[5] = (this_part >> 8) & 255;
-		buffer[6] = (this_part >> 16) & 255;
-		buffer[7] = (this_part >> 24) & 255;
+		buffer[4] = this_part >> 0;
+		buffer[5] = this_part >> 8;
+		buffer[6] = this_part >> 16;
+		buffer[7] = this_part >> 24;
 		/* buffer[8] is set above... */
 		buffer[9] = 0; /* Reserved */
 		buffer[10] = 0; /* Reserved */
@@ -901,7 +899,7 @@
 }
 
 #define capability_attribute(name)					\
-static ssize_t show_##name(struct device *dev,				\
+static ssize_t name##_show(struct device *dev,				\
 			   struct device_attribute *attr, char *buf)	\
 {									\
 	struct usb_interface *intf = to_usb_interface(dev);		\
@@ -909,7 +907,7 @@
 									\
 	return sprintf(buf, "%d\n", data->capabilities.name);		\
 }									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR_RO(name)
 
 capability_attribute(interface_capabilities);
 capability_attribute(device_capabilities);
@@ -928,7 +926,7 @@
 	.attrs = capability_attrs,
 };
 
-static ssize_t show_TermChar(struct device *dev,
+static ssize_t TermChar_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf = to_usb_interface(dev);
@@ -937,7 +935,7 @@
 	return sprintf(buf, "%c\n", data->TermChar);
 }
 
-static ssize_t store_TermChar(struct device *dev,
+static ssize_t TermChar_store(struct device *dev,
 			      struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
@@ -949,10 +947,10 @@
 	data->TermChar = buf[0];
 	return count;
 }
-static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar);
+static DEVICE_ATTR_RW(TermChar);
 
 #define data_attribute(name)						\
-static ssize_t show_##name(struct device *dev,				\
+static ssize_t name##_show(struct device *dev,				\
 			   struct device_attribute *attr, char *buf)	\
 {									\
 	struct usb_interface *intf = to_usb_interface(dev);		\
@@ -960,7 +958,7 @@
 									\
 	return sprintf(buf, "%d\n", data->name);			\
 }									\
-static ssize_t store_##name(struct device *dev,				\
+static ssize_t name##_store(struct device *dev,				\
 			    struct device_attribute *attr,		\
 			    const char *buf, size_t count)		\
 {									\
@@ -978,7 +976,7 @@
 	else								\
 		return count;						\
 }									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name)
+static DEVICE_ATTR_RW(name)
 
 data_attribute(TermCharEnabled);
 data_attribute(auto_abort);
@@ -1102,7 +1100,7 @@
 
 	dev_dbg(&intf->dev, "%s called\n", __func__);
 
-	data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
+	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		dev_err(&intf->dev, "Unable to allocate kernel memory\n");
 		return -ENOMEM;
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index b0585e6..2355974 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -43,10 +43,11 @@
  *
  * Call this as part of initializing a host controller that uses the dma
  * memory allocators.  It initializes some pools of dma-coherent memory that
- * will be shared by all drivers using that controller, or returns a negative
- * errno value on error.
+ * will be shared by all drivers using that controller.
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
+ *
+ * Return: 0 if successful. A negative errno value otherwise.
  */
 int hcd_buffer_create(struct usb_hcd *hcd)
 {
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 7199adc..a6b2cab 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -424,7 +424,8 @@
 
 	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
 	if (config->desc.bDescriptorType != USB_DT_CONFIG ||
-	    config->desc.bLength < USB_DT_CONFIG_SIZE) {
+	    config->desc.bLength < USB_DT_CONFIG_SIZE ||
+	    config->desc.bLength > size) {
 		dev_err(ddev, "invalid descriptor for config index %d: "
 		    "type = 0x%X, length = %d\n", cfgidx,
 		    config->desc.bDescriptorType, config->desc.bLength);
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 05986507..737e3c1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -725,15 +725,15 @@
 
 	/*
 	 * check for the special corner case 'get_device_id' in the printer
-	 * class specification, where wIndex is (interface << 8 | altsetting)
-	 * instead of just interface
+	 * class specification, which we always want to allow as it is used
+	 * to query things like ink level, etc.
 	 */
 	if (requesttype == 0xa1 && request == 0) {
 		alt_setting = usb_find_alt_setting(ps->dev->actconfig,
 						   index >> 8, index & 0xff);
 		if (alt_setting
 		 && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
-			index >>= 8;
+			return 0;
 	}
 
 	index &= 0xff;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 7609ac4..f7841d4 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -94,32 +94,27 @@
 }
 EXPORT_SYMBOL_GPL(usb_show_dynids);
 
-static ssize_t show_dynids(struct device_driver *driver, char *buf)
+static ssize_t new_id_show(struct device_driver *driver, char *buf)
 {
 	struct usb_driver *usb_drv = to_usb_driver(driver);
 
 	return usb_show_dynids(&usb_drv->dynids, buf);
 }
 
-static ssize_t store_new_id(struct device_driver *driver,
+static ssize_t new_id_store(struct device_driver *driver,
 			    const char *buf, size_t count)
 {
 	struct usb_driver *usb_drv = to_usb_driver(driver);
 
 	return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
 }
-static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id);
+static DRIVER_ATTR_RW(new_id);
 
-/**
- * store_remove_id - remove a USB device ID from this driver
- * @driver: target device driver
- * @buf: buffer for scanning device ID data
- * @count: input size
- *
- * Removes a dynamic usb device ID from this driver.
+/*
+ * Remove a USB device ID from this driver
  */
-static ssize_t
-store_remove_id(struct device_driver *driver, const char *buf, size_t count)
+static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
+			       size_t count)
 {
 	struct usb_dynid *dynid, *n;
 	struct usb_driver *usb_driver = to_usb_driver(driver);
@@ -144,7 +139,12 @@
 	spin_unlock(&usb_driver->dynids.lock);
 	return count;
 }
-static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id);
+
+static ssize_t remove_id_show(struct device_driver *driver, char *buf)
+{
+	return new_id_show(driver, buf);
+}
+static DRIVER_ATTR_RW(remove_id);
 
 static int usb_create_newid_files(struct usb_driver *usb_drv)
 {
@@ -457,6 +457,8 @@
  * Callers must own the device lock, so driver probe() entries don't need
  * extra locking, but other call contexts may need to explicitly claim that
  * lock.
+ *
+ * Return: 0 on success.
  */
 int usb_driver_claim_interface(struct usb_driver *driver,
 				struct usb_interface *iface, void *priv)
@@ -658,6 +660,8 @@
  * These device tables are exported with MODULE_DEVICE_TABLE, through
  * modutils, to support the driver loading functionality of USB hotplugging.
  *
+ * Return: The first matching usb_device_id, or %NULL.
+ *
  * What Matches:
  *
  * The "match_flags" element in a usb_device_id controls which
@@ -823,7 +827,8 @@
  * Registers a USB device driver with the USB core.  The list of
  * unattached devices will be rescanned whenever a new driver is
  * added, allowing the new driver to attach to any recognized devices.
- * Returns a negative error code on failure and 0 on success.
+ *
+ * Return: A negative error code on failure and 0 on success.
  */
 int usb_register_device_driver(struct usb_device_driver *new_udriver,
 		struct module *owner)
@@ -879,7 +884,8 @@
  * Registers a USB interface driver with the USB core.  The list of
  * unattached interfaces will be rescanned whenever a new driver is
  * added, allowing the new driver to attach to any recognized interfaces.
- * Returns a negative error code on failure and 0 on success.
+ *
+ * Return: A negative error code on failure and 0 on success.
  *
  * NOTE: if you want your driver to use the USB major number, you must call
  * usb_register_dev() to enable that functionality.  This function no longer
@@ -1213,6 +1219,8 @@
  * unpredictable times.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 if the suspend succeeded.
  */
 static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 {
@@ -1294,6 +1302,8 @@
  * unpredictable times.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 on success.
  */
 static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
 {
@@ -1491,6 +1501,8 @@
  * The caller must hold @udev's device lock.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
  */
 int usb_autoresume_device(struct usb_device *udev)
 {
@@ -1600,6 +1612,8 @@
  * However if the autoresume fails then the counter is re-decremented.
  *
  * This routine can run only in process context.
+ *
+ * Return: 0 on success.
  */
 int usb_autopm_get_interface(struct usb_interface *intf)
 {
@@ -1633,6 +1647,8 @@
  * resumed.
  *
  * This routine can run in atomic context.
+ *
+ * Return: 0 on success. A negative error code otherwise.
  */
 int usb_autopm_get_interface_async(struct usb_interface *intf)
 {
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 68cc653..39a2402 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -12,7 +12,6 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
-#include <linux/idr.h>
 #include <linux/usb.h>
 #include "usb.h"
 
@@ -33,31 +32,31 @@
 	container_of(_attr, struct ep_attribute, attr)
 
 #define usb_ep_attr(field, format_string)			\
-static ssize_t show_ep_##field(struct device *dev,		\
+static ssize_t field##_show(struct device *dev,			\
 			       struct device_attribute *attr,	\
 			       char *buf)			\
 {								\
 	struct ep_device *ep = to_ep_device(dev);		\
 	return sprintf(buf, format_string, ep->desc->field);	\
 }								\
-static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL);
+static DEVICE_ATTR_RO(field)
 
-usb_ep_attr(bLength, "%02x\n")
-usb_ep_attr(bEndpointAddress, "%02x\n")
-usb_ep_attr(bmAttributes, "%02x\n")
-usb_ep_attr(bInterval, "%02x\n")
+usb_ep_attr(bLength, "%02x\n");
+usb_ep_attr(bEndpointAddress, "%02x\n");
+usb_ep_attr(bmAttributes, "%02x\n");
+usb_ep_attr(bInterval, "%02x\n");
 
-static ssize_t show_ep_wMaxPacketSize(struct device *dev,
-				      struct device_attribute *attr, char *buf)
+static ssize_t wMaxPacketSize_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
 {
 	struct ep_device *ep = to_ep_device(dev);
 	return sprintf(buf, "%04x\n",
 		        usb_endpoint_maxp(ep->desc) & 0x07ff);
 }
-static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
+static DEVICE_ATTR_RO(wMaxPacketSize);
 
-static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr,
-			    char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct ep_device *ep = to_ep_device(dev);
 	char *type = "unknown";
@@ -78,10 +77,10 @@
 	}
 	return sprintf(buf, "%s\n", type);
 }
-static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL);
+static DEVICE_ATTR_RO(type);
 
-static ssize_t show_ep_interval(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t interval_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
 {
 	struct ep_device *ep = to_ep_device(dev);
 	char unit;
@@ -124,10 +123,10 @@
 
 	return sprintf(buf, "%d%cs\n", interval, unit);
 }
-static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL);
+static DEVICE_ATTR_RO(interval);
 
-static ssize_t show_ep_direction(struct device *dev,
-				 struct device_attribute *attr, char *buf)
+static ssize_t direction_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
 {
 	struct ep_device *ep = to_ep_device(dev);
 	char *direction;
@@ -140,7 +139,7 @@
 		direction = "out";
 	return sprintf(buf, "%s\n", direction);
 }
-static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL);
+static DEVICE_ATTR_RO(direction);
 
 static struct attribute *ep_dev_attrs[] = {
 	&dev_attr_bLength.attr,
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 6a4c407..7421888 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -153,7 +153,7 @@
  * usb_deregister_dev() must be called when the driver is done with
  * the minor numbers given out by this function.
  *
- * Returns -EINVAL if something bad happens with trying to register a
+ * Return: -EINVAL if something bad happens with trying to register a
  * device, and 0 on success.
  */
 int usb_register_dev(struct usb_interface *intf,
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index caeb8d6..b9d3c43 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -171,6 +171,8 @@
  * through the hotplug entry's driver_data.
  *
  * Store this function in the HCD's struct pci_driver as probe().
+ *
+ * Return: 0 if successful.
  */
 int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 014dc99..d6a8d23 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -378,9 +378,10 @@
  * @buf: Buffer for USB string descriptor (header + UTF-16LE)
  * @len: Length (in bytes; may be odd) of descriptor buffer.
  *
- * The return value is the number of bytes filled in: 2 + 2*strlen(s) or
- * buflen, whichever is less.
+ * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len,
+ * whichever is less.
  *
+ * Note:
  * USB String descriptors can contain at most 126 characters; input
  * strings longer than that are truncated.
  */
@@ -416,7 +417,8 @@
  *
  * Produces either a manufacturer, product or serial number string for the
  * virtual root hub device.
- * Returns the number of bytes filled in: the length of the descriptor or
+ *
+ * Return: The number of bytes filled in: the length of the descriptor or
  * of the provided buffer, whichever is less.
  */
 static unsigned
@@ -464,17 +466,13 @@
 	struct usb_ctrlrequest *cmd;
  	u16		typeReq, wValue, wIndex, wLength;
 	u8		*ubuf = urb->transfer_buffer;
-	/*
-	 * tbuf should be as big as the BOS descriptor and
-	 * the USB hub descriptor.
-	 */
-	u8		tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
-		__attribute__((aligned(4)));
-	const u8	*bufp = tbuf;
 	unsigned	len = 0;
 	int		status;
 	u8		patch_wakeup = 0;
 	u8		patch_protocol = 0;
+	u16		tbuf_size;
+	u8		*tbuf = NULL;
+	const u8	*bufp;
 
 	might_sleep();
 
@@ -494,6 +492,18 @@
 	if (wLength > urb->transfer_buffer_length)
 		goto error;
 
+	/*
+	 * tbuf should be at least as big as the
+	 * USB hub descriptor.
+	 */
+	tbuf_size =  max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
+	tbuf = kzalloc(tbuf_size, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+
+	bufp = tbuf;
+
+
 	urb->actual_length = 0;
 	switch (typeReq) {
 
@@ -691,18 +701,12 @@
 				bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
 	}
 
+	kfree(tbuf);
+
 	/* any errors get returned through the urb completion */
 	spin_lock_irq(&hcd_root_hub_lock);
 	usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-	/* This peculiar use of spinlocks echoes what real HC drivers do.
-	 * Avoiding calls to local_irq_disable/enable makes the code
-	 * RT-friendly.
-	 */
-	spin_unlock(&hcd_root_hub_lock);
 	usb_hcd_giveback_urb(hcd, urb, status);
-	spin_lock(&hcd_root_hub_lock);
-
 	spin_unlock_irq(&hcd_root_hub_lock);
 	return 0;
 }
@@ -742,9 +746,7 @@
 			memcpy(urb->transfer_buffer, buffer, length);
 
 			usb_hcd_unlink_urb_from_ep(hcd, urb);
-			spin_unlock(&hcd_root_hub_lock);
 			usb_hcd_giveback_urb(hcd, urb, 0);
-			spin_lock(&hcd_root_hub_lock);
 		} else {
 			length = 0;
 			set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
@@ -834,10 +836,7 @@
 		if (urb == hcd->status_urb) {
 			hcd->status_urb = NULL;
 			usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-			spin_unlock(&hcd_root_hub_lock);
 			usb_hcd_giveback_urb(hcd, urb, status);
-			spin_lock(&hcd_root_hub_lock);
 		}
 	}
  done:
@@ -850,9 +849,8 @@
 /*
  * Show & store the current value of authorized_default
  */
-static ssize_t usb_host_authorized_default_show(struct device *dev,
-						struct device_attribute *attr,
-						char *buf)
+static ssize_t authorized_default_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
 	struct usb_device *rh_usb_dev = to_usb_device(dev);
 	struct usb_bus *usb_bus = rh_usb_dev->bus;
@@ -864,9 +862,9 @@
 	return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
 }
 
-static ssize_t usb_host_authorized_default_store(struct device *dev,
-						 struct device_attribute *attr,
-						 const char *buf, size_t size)
+static ssize_t authorized_default_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
 {
 	ssize_t result;
 	unsigned val;
@@ -886,11 +884,7 @@
 		result = -EINVAL;
 	return result;
 }
-
-static DEVICE_ATTR(authorized_default, 0644,
-	    usb_host_authorized_default_show,
-	    usb_host_authorized_default_store);
-
+static DEVICE_ATTR_RW(authorized_default);
 
 /* Group all the USB bus attributes */
 static struct attribute *usb_bus_attrs[] = {
@@ -938,6 +932,8 @@
  *
  * Assigns a bus number, and links the controller into usbcore data
  * structures so that it can be seen by scanning the bus list.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
@@ -1002,6 +998,8 @@
  * the device properly in the device tree and then calls usb_new_device()
  * to register the usb device.  It also assigns the root hub's USB address
  * (always 1).
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int register_root_hub(struct usb_hcd *hcd)
 {
@@ -1108,7 +1106,9 @@
  * @isoc: true for isochronous transactions, false for interrupt ones
  * @bytecount: how many bytes in the transaction.
  *
- * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * Return: Approximate bus time in nanoseconds for a periodic transaction.
+ *
+ * Note:
  * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
  * scheduled in software, this function is only used for such scheduling.
  */
@@ -1166,7 +1166,7 @@
  * be disabled.  The actions carried out here are required for URB
  * submission, as well as for endpoint shutdown and for usb_kill_urb.
  *
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
  * the enqueue() method must fail).  If no error occurs but enqueue() fails
  * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
  * the private spinlock and returning.
@@ -1221,7 +1221,7 @@
  * be disabled.  The actions carried out here are required for making
  * sure than an unlink is valid.
  *
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
  * the dequeue() method must fail).  The possible error codes are:
  *
  *	-EIDRM: @urb was not submitted or has already completed.
@@ -1648,6 +1648,72 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void __usb_hcd_giveback_urb(struct urb *urb)
+{
+	struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+	int status = urb->unlinked;
+	unsigned long flags;
+
+	urb->hcpriv = NULL;
+	if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+	    urb->actual_length < urb->transfer_buffer_length &&
+	    !status))
+		status = -EREMOTEIO;
+
+	unmap_urb_for_dma(hcd, urb);
+	usbmon_urb_complete(&hcd->self, urb, status);
+	usb_unanchor_urb(urb);
+
+	/* pass ownership to the completion handler */
+	urb->status = status;
+
+	/*
+	 * We disable local IRQs here avoid possible deadlock because
+	 * drivers may call spin_lock() to hold lock which might be
+	 * acquired in one hard interrupt handler.
+	 *
+	 * The local_irq_save()/local_irq_restore() around complete()
+	 * will be removed if current USB drivers have been cleaned up
+	 * and no one may trigger the above deadlock situation when
+	 * running complete() in tasklet.
+	 */
+	local_irq_save(flags);
+	urb->complete(urb);
+	local_irq_restore(flags);
+
+	atomic_dec(&urb->use_count);
+	if (unlikely(atomic_read(&urb->reject)))
+		wake_up(&usb_kill_urb_queue);
+	usb_put_urb(urb);
+}
+
+static void usb_giveback_urb_bh(unsigned long param)
+{
+	struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param;
+	struct list_head local_list;
+
+	spin_lock_irq(&bh->lock);
+	bh->running = true;
+ restart:
+	list_replace_init(&bh->head, &local_list);
+	spin_unlock_irq(&bh->lock);
+
+	while (!list_empty(&local_list)) {
+		struct urb *urb;
+
+		urb = list_entry(local_list.next, struct urb, urb_list);
+		list_del_init(&urb->urb_list);
+		__usb_hcd_giveback_urb(urb);
+	}
+
+	/* check if there are new URBs to giveback */
+	spin_lock_irq(&bh->lock);
+	if (!list_empty(&bh->head))
+		goto restart;
+	bh->running = false;
+	spin_unlock_irq(&bh->lock);
+}
+
 /**
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
@@ -1667,25 +1733,37 @@
  */
 void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-	urb->hcpriv = NULL;
-	if (unlikely(urb->unlinked))
-		status = urb->unlinked;
-	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-			urb->actual_length < urb->transfer_buffer_length &&
-			!status))
-		status = -EREMOTEIO;
+	struct giveback_urb_bh *bh;
+	bool running, high_prio_bh;
 
-	unmap_urb_for_dma(hcd, urb);
-	usbmon_urb_complete(&hcd->self, urb, status);
-	usb_unanchor_urb(urb);
+	/* pass status to tasklet via unlinked */
+	if (likely(!urb->unlinked))
+		urb->unlinked = status;
 
-	/* pass ownership to the completion handler */
-	urb->status = status;
-	urb->complete (urb);
-	atomic_dec (&urb->use_count);
-	if (unlikely(atomic_read(&urb->reject)))
-		wake_up (&usb_kill_urb_queue);
-	usb_put_urb (urb);
+	if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
+		__usb_hcd_giveback_urb(urb);
+		return;
+	}
+
+	if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+		bh = &hcd->high_prio_bh;
+		high_prio_bh = true;
+	} else {
+		bh = &hcd->low_prio_bh;
+		high_prio_bh = false;
+	}
+
+	spin_lock(&bh->lock);
+	list_add_tail(&urb->urb_list, &bh->head);
+	running = bh->running;
+	spin_unlock(&bh->lock);
+
+	if (running)
+		;
+	else if (high_prio_bh)
+		tasklet_hi_schedule(&bh->bh);
+	else
+		tasklet_schedule(&bh->bh);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
 
@@ -1784,7 +1862,7 @@
  * pass in the current alternate interface setting in cur_alt,
  * and pass in the new alternate interface setting in new_alt.
  *
- * Returns an error if the requested bandwidth change exceeds the
+ * Return: An error if the requested bandwidth change exceeds the
  * bus bandwidth or host controller internal resources.
  */
 int usb_hcd_alloc_bandwidth(struct usb_device *udev,
@@ -1954,9 +2032,12 @@
  * @num_streams:	number of streams to allocate.
  * @mem_flags:		flags hcd should use to allocate memory.
  *
- * Sets up a group of bulk endpoints to have num_streams stream IDs available.
+ * Sets up a group of bulk endpoints to have @num_streams stream IDs available.
  * Drivers may queue multiple transfers to different stream IDs, which may
  * complete in a different order than they were queued.
+ *
+ * Return: On success, the number of allocated streams. On failure, a negative
+ * error code.
  */
 int usb_alloc_streams(struct usb_interface *interface,
 		struct usb_host_endpoint **eps, unsigned int num_eps,
@@ -2201,6 +2282,8 @@
  * khubd identifying and possibly configuring the device.
  * This is needed by OTG controller drivers, where it helps meet
  * HNP protocol timing requirements for starting a port reset.
+ *
+ * Return: 0 if successful.
  */
 int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
 {
@@ -2235,6 +2318,8 @@
  *
  * If the controller isn't HALTed, calls the driver's irq handler.
  * Checks whether the controller is now dead.
+ *
+ * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise.
  */
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
@@ -2307,6 +2392,14 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
+{
+
+	spin_lock_init(&bh->lock);
+	INIT_LIST_HEAD(&bh->head);
+	tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
+}
+
 /**
  * usb_create_shared_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
@@ -2320,7 +2413,8 @@
  * HC driver's private data.  Initialize the generic members of the
  * hcd structure.
  *
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
  */
 struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
 		struct device *dev, const char *bus_name,
@@ -2384,7 +2478,8 @@
  * HC driver's private data.  Initialize the generic members of the
  * hcd structure.
  *
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD
+ * structure. On failure (e.g. if memory is unavailable), %NULL.
  */
 struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
 		struct device *dev, const char *bus_name)
@@ -2563,7 +2658,7 @@
 	 * should already have been reset (and boot firmware kicked off etc).
 	 */
 	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
-		dev_err(hcd->self.controller, "can't setup\n");
+		dev_err(hcd->self.controller, "can't setup: %d\n", retval);
 		goto err_hcd_driver_setup;
 	}
 	hcd->rh_pollable = 1;
@@ -2573,6 +2668,10 @@
 			&& device_can_wakeup(&hcd->self.root_hub->dev))
 		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
 
+	/* initialize tasklets */
+	init_giveback_urb_bh(&hcd->high_prio_bh);
+	init_giveback_urb_bh(&hcd->low_prio_bh);
+
 	/* enable irqs just before we start the controller,
 	 * if the BIOS provides legacy PCI irqs.
 	 */
@@ -2681,6 +2780,16 @@
 	usb_disconnect(&rhdev);		/* Sets rhdev to NULL */
 	mutex_unlock(&usb_bus_list_lock);
 
+	/*
+	 * tasklet_kill() isn't needed here because:
+	 * - driver's disconnect() called from usb_disconnect() should
+	 *   make sure its URBs are completed during the disconnect()
+	 *   callback
+	 *
+	 * - it is too late to run complete() here since driver may have
+	 *   been removed already now
+	 */
+
 	/* Prevent any more root-hub status calls from the timer.
 	 * The HCD might still restart the timer (if a port status change
 	 * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 558313d..dde4c83 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -451,7 +451,7 @@
 	if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing)
 		return;
 
-	for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
+	for (i = 0; i < hdev->maxchild; i++) {
 		unsigned	selector, mode;
 
 		/* 30%-50% duty cycle */
@@ -500,7 +500,7 @@
 	}
 	if (!changed && blinkenlights) {
 		cursor++;
-		cursor %= hub->descriptor->bNbrPorts;
+		cursor %= hdev->maxchild;
 		set_port_led(hub, cursor + 1, HUB_LED_GREEN);
 		hub->indicator[cursor] = INDICATOR_CYCLE;
 		changed++;
@@ -734,6 +734,8 @@
  *
  * call this function to control port's power via setting or
  * clearing the port's PORT_POWER feature.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
 			   int port1, bool set)
@@ -762,6 +764,8 @@
  *
  * It may not be possible for that hub to handle additional full (or low)
  * speed transactions until that state is fully cleared out.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 int usb_hub_clear_tt_buffer(struct urb *urb)
 {
@@ -826,7 +830,7 @@
 	else
 		dev_dbg(hub->intfdev, "trying to enable port power on "
 				"non-switchable hub\n");
-	for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
+	for (port1 = 1; port1 <= hub->hdev->maxchild; port1++)
 		if (hub->ports[port1 - 1]->power_is_on)
 			set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
 		else
@@ -964,6 +968,8 @@
  * see that the device has been disconnected.  When the device is
  * physically unplugged and something is plugged in, the events will
  * be received and processed normally.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 int usb_remove_device(struct usb_device *udev)
 {
@@ -1464,11 +1470,10 @@
 	 * and battery-powered root hubs (may provide just 8 mA).
 	 */
 	ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
-	if (ret < 2) {
+	if (ret) {
 		message = "can't get hub status";
 		goto fail;
 	}
-	le16_to_cpus(&hubstatus);
 	hcd = bus_to_hcd(hdev->bus);
 	if (hdev == hdev->bus->root_hub) {
 		if (hcd->power_budget > 0)
@@ -1557,10 +1562,15 @@
 	if (hub->has_indicators && blinkenlights)
 		hub->indicator [0] = INDICATOR_CYCLE;
 
-	for (i = 0; i < hdev->maxchild; i++)
-		if (usb_hub_create_port_device(hub, i + 1) < 0)
+	for (i = 0; i < hdev->maxchild; i++) {
+		ret = usb_hub_create_port_device(hub, i + 1);
+		if (ret < 0) {
 			dev_err(hub->intfdev,
 				"couldn't create port%d device.\n", i + 1);
+			hdev->maxchild = i;
+			goto fail_keep_maxchild;
+		}
+	}
 
 	usb_hub_adjust_deviceremovable(hdev, hub->descriptor);
 
@@ -1568,6 +1578,8 @@
 	return 0;
 
 fail:
+	hdev->maxchild = 0;
+fail_keep_maxchild:
 	dev_err (hub_dev, "config failed, %s (err %d)\n",
 			message, ret);
 	/* hub_disconnect() frees urb and descriptor */
@@ -2116,6 +2128,8 @@
  * @udev: newly addressed device (in ADDRESS state)
  *
  * Finish enumeration for On-The-Go devices
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int usb_enumerate_device_otg(struct usb_device *udev)
 {
@@ -2198,6 +2212,8 @@
  * If the device is WUSB and not authorized, we don't attempt to read
  * the string descriptors, as they will be errored out by the device
  * until it has been authorized.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
  */
 static int usb_enumerate_device(struct usb_device *udev)
 {
@@ -2278,13 +2294,14 @@
  * udev has already been installed, but udev is not yet visible through
  * sysfs or other filesystem code.
  *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
  * This call is synchronous, and may not be used in an interrupt context.
  *
  * Only the hub driver or root-hub registrar should ever call this.
+ *
+ * Return: Whether the device is configured properly or not. Zero if the
+ * interface was registered with the driver core; else a negative errno
+ * value.
+ *
  */
 int usb_new_device(struct usb_device *udev)
 {
@@ -2392,6 +2409,8 @@
  *
  * We share a lock (that we have) with device_del(), so we need to
  * defer its call.
+ *
+ * Return: 0.
  */
 int usb_deauthorize_device(struct usb_device *usb_dev)
 {
@@ -2838,20 +2857,51 @@
 }
 EXPORT_SYMBOL_GPL(usb_enable_ltm);
 
-#ifdef	CONFIG_PM
 /*
- * usb_disable_function_remotewakeup - disable usb3.0
- * device's function remote wakeup
+ * usb_enable_remote_wakeup - enable remote wakeup for a device
  * @udev: target device
  *
- * Assume there's only one function on the USB 3.0
- * device and disable remote wake for the first
- * interface. FIXME if the interface association
- * descriptor shows there's more than one function.
+ * For USB-2 devices: Set the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * enable remote wake for the first interface.  FIXME if the interface
+ * association descriptor shows there's more than one function.
  */
-static int usb_disable_function_remotewakeup(struct usb_device *udev)
+static int usb_enable_remote_wakeup(struct usb_device *udev)
 {
-	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+	if (udev->speed < USB_SPEED_SUPER)
+		return 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
+		return 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);
+}
+
+/*
+ * usb_disable_remote_wakeup - disable remote wakeup for a device
+ * @udev: target device
+ *
+ * For USB-2 devices: Clear the device's remote wakeup feature.
+ *
+ * For USB-3 devices: Assume there's only one function on the device and
+ * disable remote wake for the first interface.  FIXME if the interface
+ * association descriptor shows there's more than one function.
+ */
+static int usb_disable_remote_wakeup(struct usb_device *udev)
+{
+	if (udev->speed < USB_SPEED_SUPER)
+		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
+				USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0,
+				USB_CTRL_SET_TIMEOUT);
+	else
+		return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
 				USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE,
 				USB_INTRF_FUNC_SUSPEND,	0, NULL, 0,
 				USB_CTRL_SET_TIMEOUT);
@@ -2918,7 +2968,6 @@
 {
 	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent);
 	struct usb_port *port_dev = hub->ports[udev->portnum - 1];
-	enum pm_qos_flags_status pm_qos_stat;
 	int		port1 = udev->portnum;
 	int		status;
 	bool		really_suspend = true;
@@ -2930,33 +2979,13 @@
 	 * we don't explicitly enable it here.
 	 */
 	if (udev->do_remote_wakeup) {
-		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);
-		}
+		status = usb_enable_remote_wakeup(udev);
 		if (status) {
 			dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
 					status);
 			/* bail if autosuspend is requested */
 			if (PMSG_IS_AUTO(msg))
-				return status;
+				goto err_wakeup;
 		}
 	}
 
@@ -2965,14 +2994,16 @@
 		usb_set_usb2_hardware_lpm(udev, 0);
 
 	if (usb_disable_ltm(udev)) {
-		dev_err(&udev->dev, "%s Failed to disable LTM before suspend\n.",
-				__func__);
-		return -ENOMEM;
+		dev_err(&udev->dev, "Failed to disable LTM before suspend\n.");
+		status = -ENOMEM;
+		if (PMSG_IS_AUTO(msg))
+			goto err_ltm;
 	}
 	if (usb_unlocked_disable_lpm(udev)) {
-		dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
-				__func__);
-		return -ENOMEM;
+		dev_err(&udev->dev, "Failed to disable LPM before suspend\n.");
+		status = -ENOMEM;
+		if (PMSG_IS_AUTO(msg))
+			goto err_lpm3;
 	}
 
 	/* see 7.1.7.6 */
@@ -3000,28 +3031,19 @@
 	if (status) {
 		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
 				port1, status);
-		/* paranoia:  "should not happen" */
-		if (udev->do_remote_wakeup) {
-			if (!hub_is_superspeed(hub->hdev)) {
-				(void) usb_control_msg(udev,
-						usb_sndctrlpipe(udev, 0),
-						USB_REQ_CLEAR_FEATURE,
-						USB_RECIP_DEVICE,
-						USB_DEVICE_REMOTE_WAKEUP, 0,
-						NULL, 0,
-						USB_CTRL_SET_TIMEOUT);
-			} else
-				(void) usb_disable_function_remotewakeup(udev);
 
-		}
-
+		/* Try to enable USB3 LPM and LTM again */
+		usb_unlocked_enable_lpm(udev);
+ err_lpm3:
+		usb_enable_ltm(udev);
+ err_ltm:
 		/* Try to enable USB2 hardware LPM again */
 		if (udev->usb2_hw_lpm_capable == 1)
 			usb_set_usb2_hardware_lpm(udev, 1);
 
-		/* Try to enable USB3 LTM and LPM again */
-		usb_enable_ltm(udev);
-		usb_unlocked_enable_lpm(udev);
+		if (udev->do_remote_wakeup)
+			(void) usb_disable_remote_wakeup(udev);
+ err_wakeup:
 
 		/* System sleep transitions should never fail */
 		if (!PMSG_IS_AUTO(msg))
@@ -3039,16 +3061,7 @@
 		usb_set_device_state(udev, USB_STATE_SUSPENDED);
 	}
 
-	/*
-	 * Check whether current status meets the requirement of
-	 * usb port power off mechanism
-	 */
-	pm_qos_stat = dev_pm_qos_flags(&port_dev->dev,
-			PM_QOS_FLAG_NO_POWER_OFF);
-	if (!udev->do_remote_wakeup
-			&& pm_qos_stat != PM_QOS_FLAGS_ALL
-			&& udev->persist_enabled
-			&& !status) {
+	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) {
 		pm_runtime_put_sync(&port_dev->dev);
 		port_dev->did_runtime_put = true;
 	}
@@ -3102,8 +3115,6 @@
 	if (status == 0) {
 		devstatus = 0;
 		status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
-		if (status >= 0)
-			status = (status > 0 ? 0 : -ENODEV);
 
 		/* If a normal resume failed, try doing a reset-resume */
 		if (status && !udev->reset_resume && udev->persist_enabled) {
@@ -3123,24 +3134,15 @@
 	 * udev->reset_resume
 	 */
 	} else if (udev->actconfig && !udev->reset_resume) {
-		if (!hub_is_superspeed(udev->parent)) {
-			le16_to_cpus(&devstatus);
+		if (udev->speed < USB_SPEED_SUPER) {
 			if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
-				status = usb_control_msg(udev,
-						usb_sndctrlpipe(udev, 0),
-						USB_REQ_CLEAR_FEATURE,
-						USB_RECIP_DEVICE,
-						USB_DEVICE_REMOTE_WAKEUP, 0,
-						NULL, 0,
-						USB_CTRL_SET_TIMEOUT);
+				status = usb_disable_remote_wakeup(udev);
 		} else {
 			status = usb_get_status(udev, USB_RECIP_INTERFACE, 0,
 					&devstatus);
-			le16_to_cpus(&devstatus);
 			if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
 					| USB_INTRF_STAT_FUNC_RW))
-				status =
-					usb_disable_function_remotewakeup(udev);
+				status = usb_disable_remote_wakeup(udev);
 		}
 
 		if (status)
@@ -3274,8 +3276,6 @@
 	return status;
 }
 
-#endif	/* CONFIG_PM */
-
 #ifdef	CONFIG_PM_RUNTIME
 
 /* caller has locked udev */
@@ -3843,7 +3843,8 @@
 
 void usb_enable_ltm(struct usb_device *udev) { }
 EXPORT_SYMBOL_GPL(usb_enable_ltm);
-#endif
+
+#endif	/* CONFIG_PM */
 
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
@@ -4483,11 +4484,10 @@
 
 			status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
 					&devstat);
-			if (status < 2) {
+			if (status) {
 				dev_dbg(&udev->dev, "get status %d ?\n", status);
 				goto loop_disable;
 			}
-			le16_to_cpus(&devstat);
 			if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
 				dev_err(&udev->dev,
 					"can't connect bus-powered hub "
@@ -4648,9 +4648,7 @@
 		hub_dev = hub->intfdev;
 		intf = to_usb_interface(hub_dev);
 		dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
-				hdev->state, hub->descriptor
-					? hub->descriptor->bNbrPorts
-					: 0,
+				hdev->state, hdev->maxchild,
 				/* NOTE: expects max 15 ports... */
 				(u16) hub->change_bits[0],
 				(u16) hub->event_bits[0]);
@@ -4695,7 +4693,7 @@
 		}
 
 		/* deal with port status changes */
-		for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
+		for (i = 1; i <= hdev->maxchild; i++) {
 			if (test_bit(i, hub->busy_bits))
 				continue;
 			connect_change = test_bit(i, hub->change_bits);
@@ -4946,7 +4944,8 @@
 } /* usb_hub_cleanup() */
 
 static int descriptors_changed(struct usb_device *udev,
-		struct usb_device_descriptor *old_device_descriptor)
+		struct usb_device_descriptor *old_device_descriptor,
+		struct usb_host_bos *old_bos)
 {
 	int		changed = 0;
 	unsigned	index;
@@ -4960,6 +4959,16 @@
 			sizeof(*old_device_descriptor)) != 0)
 		return 1;
 
+	if ((old_bos && !udev->bos) || (!old_bos && udev->bos))
+		return 1;
+	if (udev->bos) {
+		len = le16_to_cpu(udev->bos->desc->wTotalLength);
+		if (len != le16_to_cpu(old_bos->desc->wTotalLength))
+			return 1;
+		if (memcmp(udev->bos->desc, old_bos->desc, len))
+			return 1;
+	}
+
 	/* Since the idVendor, idProduct, and bcdDevice values in the
 	 * device descriptor haven't changed, we will assume the
 	 * Manufacturer and Product strings haven't changed either.
@@ -5035,10 +5044,11 @@
  * re-connected.  All drivers will be unbound, and the device will be
  * re-enumerated and probed all over again.
  *
- * Returns 0 if the reset succeeded, -ENODEV if the device has been
+ * Return: 0 if the reset succeeded, -ENODEV if the device has been
  * flagged for logical disconnection, or some other negative error code
  * if the reset wasn't even attempted.
  *
+ * Note:
  * The caller must own the device lock.  For example, it's safe to use
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
@@ -5055,6 +5065,7 @@
 	struct usb_hub			*parent_hub;
 	struct usb_hcd			*hcd = bus_to_hcd(udev->bus);
 	struct usb_device_descriptor	descriptor = udev->descriptor;
+	struct usb_host_bos		*bos;
 	int 				i, ret = 0;
 	int				port1 = udev->portnum;
 
@@ -5072,6 +5083,9 @@
 	}
 	parent_hub = usb_hub_to_struct_hub(parent_hdev);
 
+	bos = udev->bos;
+	udev->bos = NULL;
+
 	/* Disable LPM and LTM while we reset the device and reinstall the alt
 	 * settings.  Device-initiated LPM settings, and system exit latency
 	 * settings are cleared when the device is reset, so we have to set
@@ -5105,7 +5119,7 @@
 		goto re_enumerate;
  
 	/* Device might have changed firmware (DFU or similar) */
-	if (descriptors_changed(udev, &descriptor)) {
+	if (descriptors_changed(udev, &descriptor, bos)) {
 		dev_info(&udev->dev, "device firmware changed\n");
 		udev->descriptor = descriptor;	/* for disconnect() calls */
 		goto re_enumerate;
@@ -5178,11 +5192,15 @@
 	/* Now that the alt settings are re-installed, enable LTM and LPM. */
 	usb_unlocked_enable_lpm(udev);
 	usb_enable_ltm(udev);
+	usb_release_bos_descriptor(udev);
+	udev->bos = bos;
 	return 0;
  
 re_enumerate:
 	/* LPM state doesn't matter when we're about to destroy the device. */
 	hub_port_logical_disconnect(parent_hub, port1);
+	usb_release_bos_descriptor(udev);
+	udev->bos = bos;
 	return -ENODEV;
 }
 
@@ -5194,8 +5212,9 @@
  * method), performs the port reset, and then lets the drivers know that
  * the reset is over (using their post_reset method).
  *
- * Return value is the same as for usb_reset_and_verify_device().
+ * Return: The same as for usb_reset_and_verify_device().
  *
+ * Note:
  * The caller must own the device lock.  For example, it's safe to use
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
@@ -5333,7 +5352,7 @@
  * USB drivers call this function to get hub's child device
  * pointer.
  *
- * Return NULL if input param is invalid and
+ * Return: %NULL if input param is invalid and
  * child's usb_device pointer if non-NULL.
  */
 struct usb_device *usb_hub_find_child(struct usb_device *hdev,
@@ -5367,8 +5386,8 @@
  * @hdev: USB device belonging to the usb hub
  * @port1: port num of the port
  *
- * Return connect type of the port and if input params are
- * invalid, return USB_PORT_CONNECT_TYPE_UNKNOWN.
+ * Return: The connect type of the port if successful. Or
+ * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid.
  */
 enum usb_port_connect_type
 usb_get_hub_port_connect_type(struct usb_device *hdev, int port1)
@@ -5428,8 +5447,8 @@
  * @hdev: USB device belonging to the usb hub
  * @port1: port num of the port
  *
- * Return port's acpi handle if successful, NULL if params are
- * invaild.
+ * Return: Port's acpi handle if successful, %NULL if params are
+ * invalid.
  */
 acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,
 	int port1)
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e7ee1e4..82927e1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -119,15 +119,15 @@
  * This function sends a simple control message to a specified endpoint and
  * waits for the message to complete, or timeout.
  *
- * If successful, it returns the number of bytes transferred, otherwise a
- * negative error number.
- *
  * Don't use this function from within an interrupt context, like a bottom half
  * handler.  If you need an asynchronous message, or need to send a message
  * from within interrupt context, use usb_submit_urb().
  * If a thread in your driver uses this call, make sure your disconnect()
  * method can wait for it to complete.  Since you don't have a handle on the
  * URB used, you can't cancel the request.
+ *
+ * Return: If successful, the number of bytes transferred. Otherwise, a negative
+ * error number.
  */
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 		    __u8 requesttype, __u16 value, __u16 index, void *data,
@@ -170,15 +170,16 @@
  * This function sends a simple interrupt message to a specified endpoint and
  * waits for the message to complete, or timeout.
  *
- * If successful, it returns 0, otherwise a negative error number.  The number
- * of actual bytes transferred will be stored in the actual_length paramater.
- *
  * Don't use this function from within an interrupt context, like a bottom half
  * handler.  If you need an asynchronous message, or need to send a message
  * from within interrupt context, use usb_submit_urb() If a thread in your
  * driver uses this call, make sure your disconnect() method can wait for it to
  * complete.  Since you don't have a handle on the URB used, you can't cancel
  * the request.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length paramater.
  */
 int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
 		      void *data, int len, int *actual_length, int timeout)
@@ -203,9 +204,6 @@
  * This function sends a simple bulk message to a specified endpoint
  * and waits for the message to complete, or timeout.
  *
- * If successful, it returns 0, otherwise a negative error number.  The number
- * of actual bytes transferred will be stored in the actual_length paramater.
- *
  * Don't use this function from within an interrupt context, like a bottom half
  * handler.  If you need an asynchronous message, or need to send a message
  * from within interrupt context, use usb_submit_urb() If a thread in your
@@ -217,6 +215,11 @@
  * users are forced to abuse this routine by using it to submit URBs for
  * interrupt endpoints.  We will take the liberty of creating an interrupt URB
  * (with the default interval) if the target is an interrupt endpoint.
+ *
+ * Return:
+ * If successful, 0. Otherwise a negative error number. The number of actual
+ * bytes transferred will be stored in the @actual_length paramater.
+ *
  */
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
 		 void *data, int len, int *actual_length, int timeout)
@@ -341,9 +344,9 @@
  * 	send every byte identified in the list.
  * @mem_flags: SLAB_* flags affecting memory allocations in this call
  *
- * Returns zero for success, else a negative errno value.  This initializes a
- * scatter/gather request, allocating resources such as I/O mappings and urb
- * memory (except maybe memory used by USB controller drivers).
+ * This initializes a scatter/gather request, allocating resources such as
+ * I/O mappings and urb memory (except maybe memory used by USB controller
+ * drivers).
  *
  * The request must be issued using usb_sg_wait(), which waits for the I/O to
  * complete (or to be canceled) and then cleans up all resources allocated by
@@ -351,6 +354,8 @@
  *
  * The request may be canceled with usb_sg_cancel(), either before or after
  * usb_sg_wait() is called.
+ *
+ * Return: Zero for success, else a negative errno value.
  */
 int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
 		unsigned pipe, unsigned	period, struct scatterlist *sg,
@@ -623,7 +628,7 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
 int usb_get_descriptor(struct usb_device *dev, unsigned char type,
@@ -671,7 +676,7 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
 static int usb_get_string(struct usb_device *dev, unsigned short langid,
@@ -805,7 +810,7 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns length of the string (>= 0) or usb_control_msg status (< 0).
+ * Return: length of the string (>= 0) or usb_control_msg status (< 0).
  */
 int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 {
@@ -853,8 +858,8 @@
  * @udev: the device whose string descriptor is being read
  * @index: the descriptor index
  *
- * Returns a pointer to a kmalloc'ed buffer containing the descriptor string,
- * or NULL if the index is 0 or the string could not be read.
+ * Return: A pointer to a kmalloc'ed buffer containing the descriptor string,
+ * or %NULL if the index is 0 or the string could not be read.
  */
 char *usb_cache_string(struct usb_device *udev, int index)
 {
@@ -894,7 +899,7 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
+ * Return: The number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  */
 int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
@@ -934,13 +939,13 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns the number of bytes received on success, or else the status code
- * returned by the underlying usb_control_msg() call.
+ * Returns 0 and the status value in *@data (in host byte order) on success,
+ * or else the status code from the underlying usb_control_msg() call.
  */
 int usb_get_status(struct usb_device *dev, int type, int target, void *data)
 {
 	int ret;
-	u16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+	__le16 *status = kmalloc(sizeof(*status), GFP_KERNEL);
 
 	if (!status)
 		return -ENOMEM;
@@ -949,7 +954,12 @@
 		USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status,
 		sizeof(*status), USB_CTRL_GET_TIMEOUT);
 
-	*(u16 *)data = *status;
+	if (ret == 2) {
+		*(u16 *) data = le16_to_cpu(*status);
+		ret = 0;
+	} else if (ret >= 0) {
+		ret = -EIO;
+	}
 	kfree(status);
 	return ret;
 }
@@ -975,7 +985,7 @@
  *
  * This call is synchronous, and may not be used in an interrupt context.
  *
- * Returns zero on success, or else the status code returned by the
+ * Return: Zero on success, or else the status code returned by the
  * underlying usb_control_msg() call.
  */
 int usb_clear_halt(struct usb_device *dev, int pipe)
@@ -1272,7 +1282,7 @@
  * endpoints in that interface; all such urbs must first be completed
  * (perhaps forced by unlinking).
  *
- * Returns zero on success, or else the status code returned by the
+ * Return: Zero on success, or else the status code returned by the
  * underlying usb_control_msg() call.
  */
 int usb_set_interface(struct usb_device *dev, int interface, int alternate)
@@ -1426,7 +1436,7 @@
  *
  * The caller must own the device lock.
  *
- * Returns zero on success, else a negative error code.
+ * Return: Zero on success, else a negative error code.
  */
 int usb_reset_configuration(struct usb_device *dev)
 {
@@ -1968,7 +1978,7 @@
  * routine gets around the normal restrictions by using a work thread to
  * submit the change-config request.
  *
- * Returns 0 if the request was successfully queued, error code otherwise.
+ * Return: 0 if the request was successfully queued, error code otherwise.
  * The caller has no way to know whether the queued request will eventually
  * succeed.
  */
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index d6b0fad..51542f8 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -23,8 +23,8 @@
 
 static const struct attribute_group *port_dev_group[];
 
-static ssize_t show_port_connect_type(struct device *dev,
-	struct device_attribute *attr, char *buf)
+static ssize_t connect_type_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct usb_port *port_dev = to_usb_port(dev);
 	char *result;
@@ -46,8 +46,7 @@
 
 	return sprintf(buf, "%s\n", result);
 }
-static DEVICE_ATTR(connect_type, S_IRUGO, show_port_connect_type,
-		NULL);
+static DEVICE_ATTR_RO(connect_type);
 
 static struct attribute *port_dev_attrs[] = {
 	&dev_attr_connect_type.attr,
@@ -89,22 +88,19 @@
 	retval = usb_hub_set_port_power(hdev, hub, port1, true);
 	if (port_dev->child && !retval) {
 		/*
-		 * Wait for usb hub port to be reconnected in order to make
-		 * the resume procedure successful.
+		 * Attempt to wait for usb hub port to be reconnected in order
+		 * to make the resume procedure successful.  The device may have
+		 * disconnected while the port was powered off, so ignore the
+		 * return status.
 		 */
 		retval = hub_port_debounce_be_connected(hub, port1);
-		if (retval < 0) {
+		if (retval < 0)
 			dev_dbg(&port_dev->dev, "can't get reconnection after setting port  power on, status %d\n",
 					retval);
-			goto out;
-		}
 		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);
-
-		/* Set return value to 0 if debounce successful */
 		retval = 0;
 	}
 
-out:
 	clear_bit(port1, hub->busy_bits);
 	usb_autopm_put_interface(intf);
 	return retval;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d9284b9..6d2c8ed 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -18,8 +18,8 @@
 
 /* Active configuration fields */
 #define usb_actconfig_show(field, format_string)			\
-static ssize_t  show_##field(struct device *dev,			\
-		struct device_attribute *attr, char *buf)		\
+static ssize_t field##_show(struct device *dev,				\
+			    struct device_attribute *attr, char *buf)	\
 {									\
 	struct usb_device *udev;					\
 	struct usb_host_config *actconfig;				\
@@ -35,12 +35,12 @@
 
 #define usb_actconfig_attr(field, format_string)		\
 	usb_actconfig_show(field, format_string)		\
-	static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+	static DEVICE_ATTR_RO(field)
 
-usb_actconfig_attr(bNumInterfaces, "%2d\n")
-usb_actconfig_attr(bmAttributes, "%2x\n")
+usb_actconfig_attr(bNumInterfaces, "%2d\n");
+usb_actconfig_attr(bmAttributes, "%2x\n");
 
-static ssize_t show_bMaxPower(struct device *dev,
+static ssize_t bMaxPower_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
@@ -52,9 +52,9 @@
 		return 0;
 	return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig));
 }
-static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL);
+static DEVICE_ATTR_RO(bMaxPower);
 
-static ssize_t show_configuration_string(struct device *dev,
+static ssize_t configuration_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
@@ -66,14 +66,14 @@
 		return 0;
 	return sprintf(buf, "%s\n", actconfig->string);
 }
-static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
+static DEVICE_ATTR_RO(configuration);
 
 /* configuration value is always present, and r/w */
 usb_actconfig_show(bConfigurationValue, "%u\n");
 
-static ssize_t
-set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t bConfigurationValue_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
 {
 	struct usb_device	*udev = to_usb_device(dev);
 	int			config, value;
@@ -85,13 +85,12 @@
 	usb_unlock_device(udev);
 	return (value < 0) ? value : count;
 }
-
 static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
-		show_bConfigurationValue, set_bConfigurationValue);
+		bConfigurationValue_show, bConfigurationValue_store);
 
 /* String fields */
 #define usb_string_attr(name)						\
-static ssize_t  show_##name(struct device *dev,				\
+static ssize_t  name##_show(struct device *dev,				\
 		struct device_attribute *attr, char *buf)		\
 {									\
 	struct usb_device *udev;					\
@@ -103,14 +102,14 @@
 	usb_unlock_device(udev);					\
 	return retval;							\
 }									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static DEVICE_ATTR_RO(name)
 
 usb_string_attr(product);
 usb_string_attr(manufacturer);
 usb_string_attr(serial);
 
-static ssize_t
-show_speed(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t speed_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct usb_device *udev;
 	char *speed;
@@ -139,40 +138,40 @@
 	}
 	return sprintf(buf, "%s\n", speed);
 }
-static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
+static DEVICE_ATTR_RO(speed);
 
-static ssize_t
-show_busnum(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t busnum_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
 	return sprintf(buf, "%d\n", udev->bus->busnum);
 }
-static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL);
+static DEVICE_ATTR_RO(busnum);
 
-static ssize_t
-show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t devnum_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
 	return sprintf(buf, "%d\n", udev->devnum);
 }
-static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
+static DEVICE_ATTR_RO(devnum);
 
-static ssize_t
-show_devpath(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t devpath_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
 	return sprintf(buf, "%s\n", udev->devpath);
 }
-static DEVICE_ATTR(devpath, S_IRUGO, show_devpath, NULL);
+static DEVICE_ATTR_RO(devpath);
 
-static ssize_t
-show_version(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct usb_device *udev;
 	u16 bcdUSB;
@@ -181,30 +180,30 @@
 	bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB);
 	return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff);
 }
-static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR_RO(version);
 
-static ssize_t
-show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxchild_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
 {
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
 	return sprintf(buf, "%d\n", udev->maxchild);
 }
-static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
+static DEVICE_ATTR_RO(maxchild);
 
-static ssize_t
-show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
 	return sprintf(buf, "0x%x\n", udev->quirks);
 }
-static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+static DEVICE_ATTR_RO(quirks);
 
-static ssize_t
-show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t avoid_reset_quirk_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 
@@ -212,9 +211,9 @@
 	return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET));
 }
 
-static ssize_t
-set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t avoid_reset_quirk_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
 {
 	struct usb_device	*udev = to_usb_device(dev);
 	int			val;
@@ -229,22 +228,20 @@
 	usb_unlock_device(udev);
 	return count;
 }
+static DEVICE_ATTR_RW(avoid_reset_quirk);
 
-static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR,
-		show_avoid_reset_quirk, set_avoid_reset_quirk);
-
-static ssize_t
-show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct usb_device *udev;
 
 	udev = to_usb_device(dev);
 	return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
 }
-static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+static DEVICE_ATTR_RO(urbnum);
 
-static ssize_t
-show_removable(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
 {
 	struct usb_device *udev;
 	char *state;
@@ -264,30 +261,29 @@
 
 	return sprintf(buf, "%s\n", state);
 }
-static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
+static DEVICE_ATTR_RO(removable);
 
-static ssize_t
-show_ltm_capable(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ltm_capable_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	if (usb_device_supports_ltm(to_usb_device(dev)))
 		return sprintf(buf, "%s\n", "yes");
 	return sprintf(buf, "%s\n", "no");
 }
-static DEVICE_ATTR(ltm_capable, S_IRUGO, show_ltm_capable, NULL);
+static DEVICE_ATTR_RO(ltm_capable);
 
 #ifdef	CONFIG_PM
 
-static ssize_t
-show_persist(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t persist_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 
 	return sprintf(buf, "%d\n", udev->persist_enabled);
 }
 
-static ssize_t
-set_persist(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t persist_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	int value;
@@ -304,8 +300,7 @@
 	usb_unlock_device(udev);
 	return count;
 }
-
-static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist);
+static DEVICE_ATTR_RW(persist);
 
 static int add_persist_attributes(struct device *dev)
 {
@@ -340,17 +335,15 @@
 
 #ifdef	CONFIG_PM_RUNTIME
 
-static ssize_t
-show_connected_duration(struct device *dev, struct device_attribute *attr,
-		char *buf)
+static ssize_t connected_duration_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 
 	return sprintf(buf, "%u\n",
 			jiffies_to_msecs(jiffies - udev->connect_time));
 }
-
-static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL);
+static DEVICE_ATTR_RO(connected_duration);
 
 /*
  * If the device is resumed, the last time the device was suspended has
@@ -359,9 +352,8 @@
  *
  * If the device is suspended, the active_duration is up-to-date.
  */
-static ssize_t
-show_active_duration(struct device *dev, struct device_attribute *attr,
-		char *buf)
+static ssize_t active_duration_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	int duration;
@@ -372,18 +364,17 @@
 		duration = jiffies_to_msecs(udev->active_duration);
 	return sprintf(buf, "%u\n", duration);
 }
+static DEVICE_ATTR_RO(active_duration);
 
-static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL);
-
-static ssize_t
-show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t autosuspend_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000);
 }
 
-static ssize_t
-set_autosuspend(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t autosuspend_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
 {
 	int value;
 
@@ -394,9 +385,7 @@
 	pm_runtime_set_autosuspend_delay(dev, value * 1000);
 	return count;
 }
-
-static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
-		show_autosuspend, set_autosuspend);
+static DEVICE_ATTR_RW(autosuspend);
 
 static const char on_string[] = "on";
 static const char auto_string[] = "auto";
@@ -411,8 +400,8 @@
 	}
 }
 
-static ssize_t
-show_level(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t level_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	const char *p = auto_string;
@@ -423,9 +412,8 @@
 	return sprintf(buf, "%s\n", p);
 }
 
-static ssize_t
-set_level(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t level_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	int len = count;
@@ -453,12 +441,10 @@
 	usb_unlock_device(udev);
 	return rc;
 }
+static DEVICE_ATTR_RW(level);
 
-static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
-
-static ssize_t
-show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
-				char *buf)
+static ssize_t usb2_hardware_lpm_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	const char *p;
@@ -471,9 +457,9 @@
 	return sprintf(buf, "%s\n", p);
 }
 
-static ssize_t
-set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t usb2_hardware_lpm_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	bool value;
@@ -493,21 +479,19 @@
 
 	return ret;
 }
+static DEVICE_ATTR_RW(usb2_hardware_lpm);
 
-static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
-			set_usb2_hardware_lpm);
-
-static ssize_t
-show_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
-			 char *buf)
+static ssize_t usb2_lpm_l1_timeout_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	return sprintf(buf, "%d\n", udev->l1_params.timeout);
 }
 
-static ssize_t
-set_usb2_lpm_l1_timeout(struct device *dev, struct device_attribute *attr,
-			const char *buf, size_t count)
+static ssize_t usb2_lpm_l1_timeout_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	u16 timeout;
@@ -519,21 +503,18 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(usb2_lpm_l1_timeout);
 
-static DEVICE_ATTR(usb2_lpm_l1_timeout, S_IRUGO | S_IWUSR,
-		   show_usb2_lpm_l1_timeout, set_usb2_lpm_l1_timeout);
-
-static ssize_t
-show_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
-		   char *buf)
+static ssize_t usb2_lpm_besl_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	return sprintf(buf, "%d\n", udev->l1_params.besl);
 }
 
-static ssize_t
-set_usb2_lpm_besl(struct device *dev, struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t usb2_lpm_besl_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	u8 besl;
@@ -545,9 +526,7 @@
 
 	return count;
 }
-
-static DEVICE_ATTR(usb2_lpm_besl, S_IRUGO | S_IWUSR,
-		   show_usb2_lpm_besl, set_usb2_lpm_besl);
+static DEVICE_ATTR_RW(usb2_lpm_besl);
 
 static struct attribute *usb2_hardware_lpm_attr[] = {
 	&dev_attr_usb2_hardware_lpm.attr,
@@ -604,7 +583,7 @@
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)			\
 static ssize_t								\
-show_##field(struct device *dev, struct device_attribute *attr,	\
+field##_show(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_device *udev;					\
@@ -613,15 +592,15 @@
 	return sprintf(buf, format_string, 				\
 			le16_to_cpu(udev->descriptor.field));		\
 }									\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+static DEVICE_ATTR_RO(field)
 
-usb_descriptor_attr_le16(idVendor, "%04x\n")
-usb_descriptor_attr_le16(idProduct, "%04x\n")
-usb_descriptor_attr_le16(bcdDevice, "%04x\n")
+usb_descriptor_attr_le16(idVendor, "%04x\n");
+usb_descriptor_attr_le16(idProduct, "%04x\n");
+usb_descriptor_attr_le16(bcdDevice, "%04x\n");
 
 #define usb_descriptor_attr(field, format_string)			\
 static ssize_t								\
-show_##field(struct device *dev, struct device_attribute *attr,	\
+field##_show(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_device *udev;					\
@@ -629,34 +608,31 @@
 	udev = to_usb_device(dev);					\
 	return sprintf(buf, format_string, udev->descriptor.field);	\
 }									\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+static DEVICE_ATTR_RO(field)
 
-usb_descriptor_attr(bDeviceClass, "%02x\n")
-usb_descriptor_attr(bDeviceSubClass, "%02x\n")
-usb_descriptor_attr(bDeviceProtocol, "%02x\n")
-usb_descriptor_attr(bNumConfigurations, "%d\n")
-usb_descriptor_attr(bMaxPacketSize0, "%d\n")
-
+usb_descriptor_attr(bDeviceClass, "%02x\n");
+usb_descriptor_attr(bDeviceSubClass, "%02x\n");
+usb_descriptor_attr(bDeviceProtocol, "%02x\n");
+usb_descriptor_attr(bNumConfigurations, "%d\n");
+usb_descriptor_attr(bMaxPacketSize0, "%d\n");
 
 
 /* show if the device is authorized (1) or not (0) */
-static ssize_t usb_dev_authorized_show(struct device *dev,
-				       struct device_attribute *attr,
-				       char *buf)
+static ssize_t authorized_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct usb_device *usb_dev = to_usb_device(dev);
 	return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
 }
 
-
 /*
  * Authorize a device to be used in the system
  *
  * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
  */
-static ssize_t usb_dev_authorized_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t size)
+static ssize_t authorized_store(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t size)
 {
 	ssize_t result;
 	struct usb_device *usb_dev = to_usb_device(dev);
@@ -670,14 +646,12 @@
 		result = usb_authorize_device(usb_dev);
 	return result < 0? result : size;
 }
-
-static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644,
-	    usb_dev_authorized_show, usb_dev_authorized_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,
+				  authorized_show, authorized_store);
 
 /* "Safely remove a device" */
-static ssize_t usb_remove_store(struct device *dev,
-		struct device_attribute *attr,
-		const char *buf, size_t count)
+static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
 {
 	struct usb_device *udev = to_usb_device(dev);
 	int rc = 0;
@@ -694,7 +668,7 @@
 	usb_unlock_device(udev);
 	return rc;
 }
-static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, S_IWUSR, NULL, remove_store);
 
 
 static struct attribute *dev_attrs[] = {
@@ -853,7 +827,7 @@
 /* Interface Accociation Descriptor fields */
 #define usb_intf_assoc_attr(field, format_string)			\
 static ssize_t								\
-show_iad_##field(struct device *dev, struct device_attribute *attr,	\
+iad_##field##_show(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_interface *intf = to_usb_interface(dev);		\
@@ -861,18 +835,18 @@
 	return sprintf(buf, format_string,				\
 			intf->intf_assoc->field); 			\
 }									\
-static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
+static DEVICE_ATTR_RO(iad_##field)
 
-usb_intf_assoc_attr(bFirstInterface, "%02x\n")
-usb_intf_assoc_attr(bInterfaceCount, "%02d\n")
-usb_intf_assoc_attr(bFunctionClass, "%02x\n")
-usb_intf_assoc_attr(bFunctionSubClass, "%02x\n")
-usb_intf_assoc_attr(bFunctionProtocol, "%02x\n")
+usb_intf_assoc_attr(bFirstInterface, "%02x\n");
+usb_intf_assoc_attr(bInterfaceCount, "%02d\n");
+usb_intf_assoc_attr(bFunctionClass, "%02x\n");
+usb_intf_assoc_attr(bFunctionSubClass, "%02x\n");
+usb_intf_assoc_attr(bFunctionProtocol, "%02x\n");
 
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
-show_##field(struct device *dev, struct device_attribute *attr,	\
+field##_show(struct device *dev, struct device_attribute *attr,		\
 		char *buf)						\
 {									\
 	struct usb_interface *intf = to_usb_interface(dev);		\
@@ -880,17 +854,17 @@
 	return sprintf(buf, format_string,				\
 			intf->cur_altsetting->desc.field); 		\
 }									\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+static DEVICE_ATTR_RO(field)
 
-usb_intf_attr(bInterfaceNumber, "%02x\n")
-usb_intf_attr(bAlternateSetting, "%2d\n")
-usb_intf_attr(bNumEndpoints, "%02x\n")
-usb_intf_attr(bInterfaceClass, "%02x\n")
-usb_intf_attr(bInterfaceSubClass, "%02x\n")
-usb_intf_attr(bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n");
+usb_intf_attr(bAlternateSetting, "%2d\n");
+usb_intf_attr(bNumEndpoints, "%02x\n");
+usb_intf_attr(bInterfaceClass, "%02x\n");
+usb_intf_attr(bInterfaceSubClass, "%02x\n");
+usb_intf_attr(bInterfaceProtocol, "%02x\n");
 
-static ssize_t show_interface_string(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t interface_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
 {
 	struct usb_interface *intf;
 	char *string;
@@ -903,10 +877,10 @@
 		return 0;
 	return sprintf(buf, "%s\n", string);
 }
-static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
+static DEVICE_ATTR_RO(interface);
 
-static ssize_t show_modalias(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
 {
 	struct usb_interface *intf;
 	struct usb_device *udev;
@@ -929,10 +903,11 @@
 			alt->desc.bInterfaceProtocol,
 			alt->desc.bInterfaceNumber);
 }
-static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+static DEVICE_ATTR_RO(modalias);
 
-static ssize_t show_supports_autosuspend(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t supports_autosuspend_show(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
 {
 	struct usb_interface *intf;
 	struct usb_device *udev;
@@ -952,7 +927,7 @@
 
 	return ret;
 }
-static DEVICE_ATTR(supports_autosuspend, S_IRUGO, show_supports_autosuspend, NULL);
+static DEVICE_ATTR_RO(supports_autosuspend);
 
 static struct attribute *intf_attrs[] = {
 	&dev_attr_bInterfaceNumber.attr,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 16927fa..c12bc79 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -7,6 +7,7 @@
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
 
 #define to_urb(d) container_of(d, struct urb, kref)
 
@@ -54,12 +55,12 @@
  * Creates an urb for the USB driver to use, initializes a few internal
  * structures, incrementes the usage counter, and returns a pointer to it.
  *
- * If no memory is available, NULL is returned.
- *
  * If the driver want to use this urb for interrupt, control, or bulk
  * endpoints, pass '0' as the number of iso packets.
  *
  * The driver must call usb_free_urb() when it is finished with the urb.
+ *
+ * Return: A pointer to the new urb, or %NULL if no memory is available.
  */
 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
 {
@@ -102,7 +103,7 @@
  * host controller driver.  This allows proper reference counting to happen
  * for urbs.
  *
- * A pointer to the urb with the incremented reference counter is returned.
+ * Return: A pointer to the urb with the incremented reference counter.
  */
 struct urb *usb_get_urb(struct urb *urb)
 {
@@ -199,13 +200,12 @@
  * the particular kind of transfer, although they will not initialize
  * any transfer flags.
  *
- * Successful submissions return 0; otherwise this routine returns a
- * negative error number.  If the submission is successful, the complete()
- * callback from the URB will be called exactly once, when the USB core and
- * Host Controller Driver (HCD) are finished with the URB.  When the completion
- * function is called, control of the URB is returned to the device
- * driver which issued the request.  The completion handler may then
- * immediately free or reuse that URB.
+ * If the submission is successful, the complete() callback from the URB
+ * will be called exactly once, when the USB core and Host Controller Driver
+ * (HCD) are finished with the URB.  When the completion function is called,
+ * control of the URB is returned to the device driver which issued the
+ * request.  The completion handler may then immediately free or reuse that
+ * URB.
  *
  * With few exceptions, USB device drivers should never access URB fields
  * provided by usbcore or the HCD until its complete() is called.
@@ -240,6 +240,9 @@
  * that are standardized in the USB 2.0 specification.  For bulk
  * endpoints, a synchronous usb_bulk_msg() call is available.
  *
+ * Return:
+ * 0 on successful submissions. A negative error number otherwise.
+ *
  * Request Queuing:
  *
  * URBs may be submitted to endpoints before previous ones complete, to
@@ -413,6 +416,14 @@
 			urb->iso_frame_desc[n].status = -EXDEV;
 			urb->iso_frame_desc[n].actual_length = 0;
 		}
+	} else if (urb->num_sgs && !urb->dev->bus->no_sg_constraint &&
+			dev->speed != USB_SPEED_WIRELESS) {
+		struct scatterlist *sg;
+		int i;
+
+		for_each_sg(urb->sg, sg, urb->num_sgs - 1, i)
+			if (sg->length % max)
+				return -EINVAL;
 	}
 
 	/* the I/O buffer must be mapped/unmapped, except when length=0 */
@@ -564,6 +575,9 @@
  * particular, when a driver calls this routine, it must insure that the
  * completion handler cannot deallocate the URB.
  *
+ * Return: -EINPROGRESS on success. See description for other values on
+ * failure.
+ *
  * Unlinking and Endpoint Queues:
  *
  * [The behaviors and guarantees described below do not apply to virtual
@@ -838,6 +852,8 @@
  *
  * Call this is you want to be sure all an anchor's
  * URBs have finished
+ *
+ * Return: Non-zero if the anchor became unused. Zero on timeout.
  */
 int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
 				  unsigned int timeout)
@@ -851,8 +867,11 @@
  * usb_get_from_anchor - get an anchor's oldest urb
  * @anchor: the anchor whose urb you want
  *
- * this will take the oldest urb from an anchor,
+ * This will take the oldest urb from an anchor,
  * unanchor and return it
+ *
+ * Return: The oldest urb from @anchor, or %NULL if @anchor has no
+ * urbs associated with it.
  */
 struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
 {
@@ -901,7 +920,7 @@
  * usb_anchor_empty - is an anchor empty
  * @anchor: the anchor you want to query
  *
- * returns 1 if the anchor has no urbs associated with it
+ * Return: 1 if the anchor has no urbs associated with it.
  */
 int usb_anchor_empty(struct usb_anchor *anchor)
 {
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 7dad603..0a6ee2e 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -68,6 +68,8 @@
  * @alt_num: alternate interface setting number to search for.
  *
  * Search the configuration's interface cache for the given alt setting.
+ *
+ * Return: The alternate setting, if found. %NULL otherwise.
  */
 struct usb_host_interface *usb_find_alt_setting(
 		struct usb_host_config *config,
@@ -103,8 +105,7 @@
  * @ifnum: the desired interface
  *
  * This walks the device descriptor for the currently active configuration
- * and returns a pointer to the interface with that particular interface
- * number, or null.
+ * to find the interface object with the particular interface number.
  *
  * Note that configuration descriptors are not required to assign interface
  * numbers sequentially, so that it would be incorrect to assume that
@@ -115,6 +116,9 @@
  *
  * Don't call this function unless you are bound to one of the interfaces
  * on this device or you have locked the device!
+ *
+ * Return: A pointer to the interface that has @ifnum as interface number,
+ * if found. %NULL otherwise.
  */
 struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
 				      unsigned ifnum)
@@ -139,8 +143,7 @@
  * @altnum: the desired alternate setting number
  *
  * This searches the altsetting array of the specified interface for
- * an entry with the correct bAlternateSetting value and returns a pointer
- * to that entry, or null.
+ * an entry with the correct bAlternateSetting value.
  *
  * Note that altsettings need not be stored sequentially by number, so
  * it would be incorrect to assume that the first altsetting entry in
@@ -149,6 +152,9 @@
  *
  * Don't call this function unless you are bound to the intf interface
  * or you have locked the device!
+ *
+ * Return: A pointer to the entry of the altsetting array of @intf that
+ * has @altnum as the alternate setting number. %NULL if not found.
  */
 struct usb_host_interface *usb_altnum_to_altsetting(
 					const struct usb_interface *intf,
@@ -191,6 +197,8 @@
  * This walks the bus device list and returns a pointer to the interface
  * with the matching minor and driver.  Note, this only works for devices
  * that share the USB major number.
+ *
+ * Return: A pointer to the interface with the matching major and @minor.
  */
 struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
 {
@@ -390,6 +398,9 @@
  * controllers) should ever call this.
  *
  * This call may not be used in a non-sleeping context.
+ *
+ * Return: On success, a pointer to the allocated usb device. %NULL on
+ * failure.
  */
 struct usb_device *usb_alloc_dev(struct usb_device *parent,
 				 struct usb_bus *bus, unsigned port1)
@@ -501,7 +512,7 @@
  * their probe() methods, when they bind to an interface, and release
  * them by calling usb_put_dev(), in their disconnect() methods.
  *
- * A pointer to the device with the incremented reference counter is returned.
+ * Return: A pointer to the device with the incremented reference counter.
  */
 struct usb_device *usb_get_dev(struct usb_device *dev)
 {
@@ -535,8 +546,7 @@
  * their probe() methods, when they bind to an interface, and release
  * them by calling usb_put_intf(), in their disconnect() methods.
  *
- * A pointer to the interface with the incremented reference counter is
- * returned.
+ * Return: A pointer to the interface with the incremented reference counter.
  */
 struct usb_interface *usb_get_intf(struct usb_interface *intf)
 {
@@ -589,7 +599,7 @@
  * disconnect; in some drivers (such as usb-storage) the disconnect()
  * or suspend() method will block waiting for a device reset to complete.
  *
- * Returns a negative error code for failure, otherwise 0.
+ * Return: A negative error code for failure, otherwise 0.
  */
 int usb_lock_device_for_reset(struct usb_device *udev,
 			      const struct usb_interface *iface)
@@ -628,14 +638,15 @@
  * usb_get_current_frame_number - return current bus frame number
  * @dev: the device whose bus is being queried
  *
- * Returns the current frame number for the USB host controller
- * used with the given USB device.  This can be used when scheduling
+ * Return: The current frame number for the USB host controller used
+ * with the given USB device. This can be used when scheduling
  * isochronous requests.
  *
- * Note that different kinds of host controller have different
- * "scheduling horizons".  While one type might support scheduling only
- * 32 frames into the future, others could support scheduling up to
- * 1024 frames into the future.
+ * Note: Different kinds of host controller have different "scheduling
+ * horizons". While one type might support scheduling only 32 frames
+ * into the future, others could support scheduling up to 1024 frames
+ * into the future.
+ *
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
@@ -685,11 +696,12 @@
  * @mem_flags: affect whether allocation may block
  * @dma: used to return DMA address of buffer
  *
- * Return value is either null (indicating no buffer could be allocated), or
- * the cpu-space pointer to a buffer that may be used to perform DMA to the
+ * Return: Either null (indicating no buffer could be allocated), or the
+ * cpu-space pointer to a buffer that may be used to perform DMA to the
  * specified device.  Such cpu-space buffers are returned along with the DMA
  * address (through the pointer provided).
  *
+ * Note:
  * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
  * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
  * hardware during URB completion/resubmit.  The implementation varies between
@@ -735,17 +747,18 @@
  * usb_buffer_map - create DMA mapping(s) for an urb
  * @urb: urb whose transfer_buffer/setup_packet will be mapped
  *
- * Return value is either null (indicating no buffer could be mapped), or
- * the parameter.  URB_NO_TRANSFER_DMA_MAP is
- * added to urb->transfer_flags if the operation succeeds.  If the device
- * is connected to this system through a non-DMA controller, this operation
- * always succeeds.
+ * URB_NO_TRANSFER_DMA_MAP is added to urb->transfer_flags if the operation
+ * succeeds. If the device is connected to this system through a non-DMA
+ * controller, this operation always succeeds.
  *
  * This call would normally be used for an urb which is reused, perhaps
  * as the target of a large periodic transfer, with usb_buffer_dmasync()
  * calls to synchronize memory and dma state.
  *
  * Reverse the effect of this call with usb_buffer_unmap().
+ *
+ * Return: Either %NULL (indicating no buffer could be mapped), or @urb.
+ *
  */
 #if 0
 struct urb *usb_buffer_map(struct urb *urb)
@@ -850,9 +863,10 @@
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
- * Return value is either < 0 (indicating no buffers could be mapped), or
- * the number of DMA mapping array entries in the scatterlist.
+ * Return: Either < 0 (indicating no buffers could be mapped), or the
+ * number of DMA mapping array entries in the scatterlist.
  *
+ * Note:
  * The caller is responsible for placing the resulting DMA addresses from
  * the scatterlist into URB transfer buffer pointers, and for setting the
  * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 2378958..f969ea2 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,6 +1,7 @@
 config USB_DWC3
 	tristate "DesignWare USB3 DRD Core Support"
 	depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA
+	depends on EXTCON
 	select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
 	help
 	  Say Y or M here if your system has a Dual Role SuperSpeed
@@ -40,6 +41,38 @@
 
 endchoice
 
+comment "Platform Glue Driver Support"
+
+config USB_DWC3_OMAP
+	tristate "Texas Instruments OMAP5 and similar Platforms"
+	depends on EXTCON
+	default USB_DWC3
+	help
+	  Some platforms from Texas Instruments like OMAP5, DRA7xxx and
+	  AM437x use this IP for USB2/3 functionality.
+
+	  Say 'Y' or 'M' here if you have one such device
+
+config USB_DWC3_EXYNOS
+	tristate "Samsung Exynos Platform"
+	default USB_DWC3
+	help
+	  Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
+	  say 'Y' or 'M' if you have one such device.
+
+config USB_DWC3_PCI
+	tristate "PCIe-based Platforms"
+	depends on PCI
+	default USB_DWC3
+	help
+	  If you're using the DesignWare Core IP with a PCIe, please say
+	  'Y' or 'M' here.
+
+	  One such PCIe-based platform is Synopsys' PCIe HAPS model of
+	  this IP.
+
+comment "Debugging features"
+
 config USB_DWC3_DEBUG
 	bool "Enable Debugging Messages"
 	help
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 0c7ac92..dd17601 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -27,15 +27,8 @@
 # the entire driver (with all its glue layers) on several architectures
 # and make sure it compiles fine. This will also help with allmodconfig
 # and allyesconfig builds.
-#
-# The only exception is the PCI glue layer, but that's only because
-# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
 ##
 
-obj-$(CONFIG_USB_DWC3)		+= dwc3-omap.o
-obj-$(CONFIG_USB_DWC3)		+= dwc3-exynos.o
-
-ifneq ($(CONFIG_PCI),)
-	obj-$(CONFIG_USB_DWC3)		+= dwc3-pci.o
-endif
-
+obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_EXYNOS)		+= dwc3-exynos.o
+obj-$(CONFIG_USB_DWC3_PCI)		+= dwc3-pci.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 358375e..474162e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -6,34 +6,17 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") 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.
  *
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/module.h>
@@ -50,20 +33,18 @@
 #include <linux/dma-mapping.h>
 #include <linux/of.h>
 
-#include <linux/usb/otg.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/of.h>
+#include <linux/usb/otg.h>
 
+#include "platform_data.h"
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
 #include "debug.h"
 
-static char *maximum_speed = "super";
-module_param(maximum_speed, charp, 0);
-MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
-
 /* -------------------------------------------------------------------------- */
 
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@@ -236,7 +217,7 @@
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
 				upper_32_bits(evt->dma));
 		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
-				evt->length & 0xffff);
+				DWC3_GEVNTSIZ_SIZE(evt->length));
 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
 	}
 
@@ -255,7 +236,8 @@
 
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
-		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
+				| DWC3_GEVNTSIZ_SIZE(0));
 		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
 	}
 }
@@ -367,18 +349,17 @@
 
 static int dwc3_probe(struct platform_device *pdev)
 {
-	struct device_node	*node = pdev->dev.of_node;
+	struct device		*dev = &pdev->dev;
+	struct dwc3_platform_data *pdata = dev_get_platdata(dev);
+	struct device_node	*node = dev->of_node;
 	struct resource		*res;
 	struct dwc3		*dwc;
-	struct device		*dev = &pdev->dev;
 
 	int			ret = -ENOMEM;
 
 	void __iomem		*regs;
 	void			*mem;
 
-	u8			mode;
-
 	mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
 	if (!mem) {
 		dev_err(dev, "not enough memory\n");
@@ -402,38 +383,32 @@
 		dev_err(dev, "missing memory resource\n");
 		return -ENODEV;
 	}
-	dwc->xhci_resources[0].start = res->start;
-	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
-					DWC3_XHCI_REGS_END;
-	dwc->xhci_resources[0].flags = res->flags;
-	dwc->xhci_resources[0].name = res->name;
-
-	 /*
-	  * Request memory region but exclude xHCI regs,
-	  * since it will be requested by the xhci-plat driver.
-	  */
-	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
-			resource_size(res) - DWC3_GLOBALS_REGS_START,
-			dev_name(dev));
-	if (!res) {
-		dev_err(dev, "can't request mem region\n");
-		return -ENOMEM;
-	}
-
-	regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-	if (!regs) {
-		dev_err(dev, "ioremap failed\n");
-		return -ENOMEM;
-	}
 
 	if (node) {
+		dwc->maximum_speed = of_usb_get_maximum_speed(node);
+
 		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0);
 		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1);
+
+		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+		dwc->dr_mode = of_usb_get_dr_mode(node);
+	} else if (pdata) {
+		dwc->maximum_speed = pdata->maximum_speed;
+
+		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
+
+		dwc->needs_fifo_resize = pdata->tx_fifo_resize;
+		dwc->dr_mode = pdata->dr_mode;
 	} else {
 		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
 		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
 	}
 
+	/* default to superspeed if no maximum_speed passed */
+	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
+		dwc->maximum_speed = USB_SPEED_SUPER;
+
 	if (IS_ERR(dwc->usb2_phy)) {
 		ret = PTR_ERR(dwc->usb2_phy);
 
@@ -464,6 +439,22 @@
 		return -EPROBE_DEFER;
 	}
 
+	dwc->xhci_resources[0].start = res->start;
+	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+					DWC3_XHCI_REGS_END;
+	dwc->xhci_resources[0].flags = res->flags;
+	dwc->xhci_resources[0].name = res->name;
+
+	res->start += DWC3_GLOBALS_REGS_START;
+
+	/*
+	 * Request memory region but exclude xHCI regs,
+	 * since it will be requested by the xhci-plat driver.
+	 */
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
 	usb_phy_set_suspend(dwc->usb2_phy, 0);
 	usb_phy_set_suspend(dwc->usb3_phy, 0);
 
@@ -478,19 +469,6 @@
 	dev->dma_parms	= dev->parent->dma_parms;
 	dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
 
-	if (!strncmp("super", maximum_speed, 5))
-		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-	else if (!strncmp("high", maximum_speed, 4))
-		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
-	else if (!strncmp("full", maximum_speed, 4))
-		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
-	else if (!strncmp("low", maximum_speed, 3))
-		dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
-	else
-		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
-
-	dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
-
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 	pm_runtime_forbid(dev);
@@ -517,14 +495,15 @@
 	}
 
 	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
-		mode = DWC3_MODE_HOST;
+		dwc->dr_mode = USB_DR_MODE_HOST;
 	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
-		mode = DWC3_MODE_DEVICE;
-	else
-		mode = DWC3_MODE_DRD;
+		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
 
-	switch (mode) {
-	case DWC3_MODE_DEVICE:
+	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+		dwc->dr_mode = USB_DR_MODE_OTG;
+
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
@@ -532,7 +511,7 @@
 			goto err2;
 		}
 		break;
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
 		ret = dwc3_host_init(dwc);
 		if (ret) {
@@ -540,7 +519,7 @@
 			goto err2;
 		}
 		break;
-	case DWC3_MODE_DRD:
+	case USB_DR_MODE_OTG:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
 		ret = dwc3_host_init(dwc);
 		if (ret) {
@@ -555,10 +534,9 @@
 		}
 		break;
 	default:
-		dev_err(dev, "Unsupported mode of operation %d\n", mode);
+		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
 		goto err2;
 	}
-	dwc->mode = mode;
 
 	ret = dwc3_debugfs_init(dwc);
 	if (ret) {
@@ -571,14 +549,14 @@
 	return 0;
 
 err3:
-	switch (mode) {
-	case DWC3_MODE_DEVICE:
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
 		dwc3_gadget_exit(dwc);
 		break;
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 		dwc3_host_exit(dwc);
 		break;
-	case DWC3_MODE_DRD:
+	case USB_DR_MODE_OTG:
 		dwc3_host_exit(dwc);
 		dwc3_gadget_exit(dwc);
 		break;
@@ -611,14 +589,14 @@
 
 	dwc3_debugfs_exit(dwc);
 
-	switch (dwc->mode) {
-	case DWC3_MODE_DEVICE:
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
 		dwc3_gadget_exit(dwc);
 		break;
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 		dwc3_host_exit(dwc);
 		break;
-	case DWC3_MODE_DRD:
+	case USB_DR_MODE_OTG:
 		dwc3_host_exit(dwc);
 		dwc3_gadget_exit(dwc);
 		break;
@@ -642,12 +620,12 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	switch (dwc->mode) {
-	case DWC3_MODE_DEVICE:
-	case DWC3_MODE_DRD:
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
 		dwc3_gadget_prepare(dwc);
 		/* FALLTHROUGH */
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 	default:
 		dwc3_event_buffers_cleanup(dwc);
 		break;
@@ -665,12 +643,12 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	switch (dwc->mode) {
-	case DWC3_MODE_DEVICE:
-	case DWC3_MODE_DRD:
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
 		dwc3_gadget_complete(dwc);
 		/* FALLTHROUGH */
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 	default:
 		dwc3_event_buffers_setup(dwc);
 		break;
@@ -686,12 +664,12 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	switch (dwc->mode) {
-	case DWC3_MODE_DEVICE:
-	case DWC3_MODE_DRD:
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
 		dwc3_gadget_suspend(dwc);
 		/* FALLTHROUGH */
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 	default:
 		/* do nothing */
 		break;
@@ -719,12 +697,12 @@
 
 	dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
 
-	switch (dwc->mode) {
-	case DWC3_MODE_DEVICE:
-	case DWC3_MODE_DRD:
+	switch (dwc->dr_mode) {
+	case USB_DR_MODE_PERIPHERAL:
+	case USB_DR_MODE_OTG:
 		dwc3_gadget_resume(dwc);
 		/* FALLTHROUGH */
-	case DWC3_MODE_HOST:
+	case USB_DR_MODE_HOST:
 	default:
 		/* do nothing */
 		break;
@@ -754,6 +732,9 @@
 #ifdef CONFIG_OF
 static const struct of_device_id of_dwc3_match[] = {
 	{
+		.compatible = "snps,dwc3"
+	},
+	{
 		.compatible = "synopsys,dwc3"
 	},
 	{ },
@@ -775,5 +756,5 @@
 
 MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 27dad99..f8af8d4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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 __DRIVERS_USB_DWC3_CORE_H
@@ -49,6 +29,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 
 /* Global constants */
 #define DWC3_EP0_BOUNCE_SIZE	512
@@ -194,6 +175,10 @@
 #define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
 #define DWC3_GTXFIFOSIZ_TXFSTADDR(n)	((n) & 0xffff0000)
 
+/* Global Event Size Registers */
+#define DWC3_GEVNTSIZ_INTMASK		(1 << 31)
+#define DWC3_GEVNTSIZ_SIZE(n)		((n) & 0xffff)
+
 /* Global HWPARAMS1 Register */
 #define DWC3_GHWPARAMS1_EN_PWROPT(n)	(((n) & (3 << 24)) >> 24)
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
@@ -207,7 +192,6 @@
 #define DWC3_MAX_HIBER_SCRATCHBUFS		15
 
 /* Device Configuration Register */
-#define DWC3_DCFG_LPM_CAP	(1 << 22)
 #define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
 #define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
 
@@ -367,7 +351,6 @@
 
 /**
  * struct dwc3_event_buffer - Software event buffer representation
- * @list: a list of event buffers
  * @buf: _THE_ buffer
  * @length: size of this buffer
  * @lpos: event offset
@@ -415,7 +398,7 @@
  * @number: endpoint number (1 - 15)
  * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
  * @resource_index: Resource transfer index
- * @interval: the intervall on which the ISOC transfer is started
+ * @interval: the interval on which the ISOC transfer is started
  * @name: a human readable name e.g. ep1out-bulk
  * @direction: true for TX, false for RX
  * @stream_capable: true when streams are enabled
@@ -566,11 +549,6 @@
 /* HWPARAMS0 */
 #define DWC3_MODE(n)		((n) & 0x7)
 
-#define DWC3_MODE_DEVICE	0
-#define DWC3_MODE_HOST		1
-#define DWC3_MODE_DRD		2
-#define DWC3_MODE_HUB		3
-
 #define DWC3_MDWIDTH(n)		(((n) & 0xff00) >> 8)
 
 /* HWPARAMS1 */
@@ -632,7 +610,7 @@
  * @u1u2: only used on revisions <1.83a for workaround
  * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
- * @mode: mode of operation
+ * @dr_mode: requested mode of operation
  * @usb2_phy: pointer to USB2 PHY
  * @usb3_phy: pointer to USB3 PHY
  * @dcfg: saved contents of DCFG register
@@ -690,6 +668,8 @@
 	void __iomem		*regs;
 	size_t			regs_size;
 
+	enum usb_dr_mode	dr_mode;
+
 	/* used for suspend/resume */
 	u32			dcfg;
 	u32			gctl;
@@ -698,7 +678,6 @@
 	u32			u1u2;
 	u32			maximum_speed;
 	u32			revision;
-	u32			mode;
 
 #define DWC3_REVISION_173A	0x5533173a
 #define DWC3_REVISION_175A	0x5533175a
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index 5894ee8..fceb39d 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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 "core.h"
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 9e9f122..9ac37fe 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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/kernel.h>
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index 8ce9d7f..2f2e88a 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -6,10 +6,14 @@
  *
  * 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.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the 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.
  */
 
 #include <linux/module.h>
@@ -20,7 +24,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
 #include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 
@@ -34,13 +38,13 @@
 
 static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)
 {
-	struct nop_usb_xceiv_platform_data pdata;
+	struct usb_phy_gen_xceiv_platform_data pdata;
 	struct platform_device	*pdev;
 	int			ret;
 
 	memset(&pdata, 0x00, sizeof(pdata));
 
-	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+	pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
 	if (!pdev)
 		return -ENOMEM;
 
@@ -51,7 +55,7 @@
 	if (ret)
 		goto err1;
 
-	pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
+	pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO);
 	if (!pdev) {
 		ret = -ENOMEM;
 		goto err1;
@@ -228,5 +232,5 @@
 
 MODULE_ALIAS("platform:exynos-dwc3");
 MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 077f110b..7f7ea62 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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/module.h>
@@ -43,13 +23,15 @@
 #include <linux/spinlock.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/dwc3-omap.h>
-#include <linux/usb/dwc3-omap.h>
 #include <linux/pm_runtime.h>
 #include <linux/dma-mapping.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/extcon.h>
+#include <linux/extcon/of_extcon.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/usb/otg.h>
 
@@ -155,9 +137,21 @@
 	u32			revision;
 
 	u32			dma_status:1;
+
+	struct extcon_specific_cable_nb extcon_vbus_dev;
+	struct extcon_specific_cable_nb extcon_id_dev;
+	struct notifier_block	vbus_nb;
+	struct notifier_block	id_nb;
+
+	struct regulator	*vbus_reg;
 };
 
-static struct dwc3_omap		*_omap;
+enum omap_dwc3_vbus_id_status {
+	OMAP_DWC3_ID_FLOAT,
+	OMAP_DWC3_ID_GROUND,
+	OMAP_DWC3_VBUS_OFF,
+	OMAP_DWC3_VBUS_VALID,
+};
 
 static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
 {
@@ -221,18 +215,24 @@
 						omap->irq0_offset, value);
 }
 
-int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
+	enum omap_dwc3_vbus_id_status status)
 {
-	u32			val;
-	struct dwc3_omap	*omap = _omap;
-
-	if (!omap)
-		return -EPROBE_DEFER;
+	int	ret;
+	u32	val;
 
 	switch (status) {
 	case OMAP_DWC3_ID_GROUND:
 		dev_dbg(omap->dev, "ID GND\n");
 
+		if (omap->vbus_reg) {
+			ret = regulator_enable(omap->vbus_reg);
+			if (ret) {
+				dev_dbg(omap->dev, "regulator enable failed\n");
+				return;
+			}
+		}
+
 		val = dwc3_omap_read_utmi_status(omap);
 		val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
 				| USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
@@ -255,6 +255,9 @@
 		break;
 
 	case OMAP_DWC3_ID_FLOAT:
+		if (omap->vbus_reg)
+			regulator_disable(omap->vbus_reg);
+
 	case OMAP_DWC3_VBUS_OFF:
 		dev_dbg(omap->dev, "VBUS Disconnect\n");
 
@@ -268,12 +271,9 @@
 		break;
 
 	default:
-		dev_dbg(omap->dev, "ID float\n");
+		dev_dbg(omap->dev, "invalid state\n");
 	}
-
-	return 0;
 }
-EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
 
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 {
@@ -366,6 +366,32 @@
 
 static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
 
+static int dwc3_omap_id_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb);
+
+	if (event)
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+
+	return NOTIFY_DONE;
+}
+
+static int dwc3_omap_vbus_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb);
+
+	if (event)
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+	else
+		dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+	return NOTIFY_DONE;
+}
+
 static int dwc3_omap_probe(struct platform_device *pdev)
 {
 	struct device_node	*node = pdev->dev.of_node;
@@ -373,6 +399,8 @@
 	struct dwc3_omap	*omap;
 	struct resource		*res;
 	struct device		*dev = &pdev->dev;
+	struct extcon_dev	*edev;
+	struct regulator	*vbus_reg = NULL;
 
 	int			ret = -ENOMEM;
 	int			irq;
@@ -409,10 +437,16 @@
 		return -EINVAL;
 	}
 
-	base = devm_ioremap_nocache(dev, res->start, resource_size(res));
-	if (!base) {
-		dev_err(dev, "ioremap failed\n");
-		return -ENOMEM;
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	if (of_property_read_bool(node, "vbus-supply")) {
+		vbus_reg = devm_regulator_get(dev, "vbus");
+		if (IS_ERR(vbus_reg)) {
+			dev_err(dev, "vbus init failed\n");
+			return PTR_ERR(vbus_reg);
+		}
 	}
 
 	spin_lock_init(&omap->lock);
@@ -420,14 +454,9 @@
 	omap->dev	= dev;
 	omap->irq	= irq;
 	omap->base	= base;
+	omap->vbus_reg	= vbus_reg;
 	dev->dma_mask	= &dwc3_omap_dma_mask;
 
-	/*
-	 * REVISIT if we ever have two instances of the wrapper, we will be
-	 * in big trouble
-	 */
-	_omap	= omap;
-
 	pm_runtime_enable(dev);
 	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
@@ -502,14 +531,46 @@
 
 	dwc3_omap_enable_irqs(omap);
 
+	if (of_property_read_bool(node, "extcon")) {
+		edev = of_extcon_get_extcon_dev(dev, 0);
+		if (IS_ERR(edev)) {
+			dev_vdbg(dev, "couldn't get extcon device\n");
+			ret = PTR_ERR(edev);
+			goto err2;
+		}
+
+		omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
+		ret = extcon_register_interest(&omap->extcon_vbus_dev,
+			edev->name, "USB", &omap->vbus_nb);
+		if (ret < 0)
+			dev_vdbg(dev, "failed to register notifier for USB\n");
+		omap->id_nb.notifier_call = dwc3_omap_id_notifier;
+		ret = extcon_register_interest(&omap->extcon_id_dev, edev->name,
+					 "USB-HOST", &omap->id_nb);
+		if (ret < 0)
+			dev_vdbg(dev,
+				"failed to register notifier for USB-HOST\n");
+
+		if (extcon_get_cable_state(edev, "USB") == true)
+			dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+		if (extcon_get_cable_state(edev, "USB-HOST") == true)
+			dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+	}
+
 	ret = of_platform_populate(node, NULL, NULL, dev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to create dwc3 core\n");
-		goto err2;
+		goto err3;
 	}
 
 	return 0;
 
+err3:
+	if (omap->extcon_vbus_dev.edev)
+		extcon_unregister_interest(&omap->extcon_vbus_dev);
+	if (omap->extcon_id_dev.edev)
+		extcon_unregister_interest(&omap->extcon_id_dev);
+
 err2:
 	dwc3_omap_disable_irqs(omap);
 
@@ -526,6 +587,10 @@
 {
 	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
 
+	if (omap->extcon_vbus_dev.edev)
+		extcon_unregister_interest(&omap->extcon_vbus_dev);
+	if (omap->extcon_id_dev.edev)
+		extcon_unregister_interest(&omap->extcon_id_dev);
 	dwc3_omap_disable_irqs(omap);
 	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -610,5 +675,5 @@
 
 MODULE_ALIAS("platform:omap-dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index ed07ec0..9b13812 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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/kernel.h>
@@ -43,7 +23,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 /* FIXME define these in <linux/pci_ids.h> */
 #define PCI_VENDOR_ID_SYNOPSYS		0x16c3
@@ -58,13 +38,13 @@
 
 static int dwc3_pci_register_phys(struct dwc3_pci *glue)
 {
-	struct nop_usb_xceiv_platform_data pdata;
+	struct usb_phy_gen_xceiv_platform_data pdata;
 	struct platform_device	*pdev;
 	int			ret;
 
 	memset(&pdata, 0x00, sizeof(pdata));
 
-	pdev = platform_device_alloc("nop_usb_xceiv", 0);
+	pdev = platform_device_alloc("usb_phy_gen_xceiv", 0);
 	if (!pdev)
 		return -ENOMEM;
 
@@ -75,7 +55,7 @@
 	if (ret)
 		goto err1;
 
-	pdev = platform_device_alloc("nop_usb_xceiv", 1);
+	pdev = platform_device_alloc("usb_phy_gen_xceiv", 1);
 	if (!pdev) {
 		ret = -ENOMEM;
 		goto err1;
@@ -211,7 +191,7 @@
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int dwc3_pci_suspend(struct device *dev)
 {
 	struct pci_dev	*pci = to_pci_dev(dev);
@@ -236,28 +216,24 @@
 
 	return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
 };
 
-#define DEV_PM_OPS	(&dwc3_pci_dev_pm_ops)
-#else
-#define DEV_PM_OPS	NULL
-#endif /* CONFIG_PM */
-
 static struct pci_driver dwc3_pci_driver = {
 	.name		= "dwc3-pci",
 	.id_table	= dwc3_pci_id_table,
 	.probe		= dwc3_pci_probe,
 	.remove		= dwc3_pci_remove,
 	.driver		= {
-		.pm	= DEV_PM_OPS,
+		.pm	= &dwc3_pci_dev_pm_ops,
 	},
 };
 
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
-MODULE_LICENSE("Dual BSD/GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
 
 module_pci_driver(dwc3_pci_driver);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 5acbb94..7fa93f4 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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/kernel.h>
@@ -168,6 +148,7 @@
 
 		direction = !dwc->ep0_expect_in;
 		dwc->delayed_status = false;
+		usb_gadget_set_state(&dwc->gadget, USB_STATE_CONFIGURED);
 
 		if (dwc->ep0state == EP0_STATUS_PHASE)
 			__dwc3_ep0_do_control_status(dwc, dwc->eps[direction]);
@@ -553,8 +534,16 @@
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
 		/* if the cfg matches and the cfg is non zero */
 		if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
-			usb_gadget_set_state(&dwc->gadget,
-					USB_STATE_CONFIGURED);
+
+			/*
+			 * only change state if set_config has already
+			 * been processed. If gadget driver returns
+			 * USB_GADGET_DELAYED_STATUS, we will wait
+			 * to change the state on the next usb_ep_queue()
+			 */
+			if (ret == 0)
+				usb_gadget_set_state(&dwc->gadget,
+						USB_STATE_CONFIGURED);
 
 			/*
 			 * Enable transition to U1/U2 state when
@@ -571,7 +560,7 @@
 
 	case USB_STATE_CONFIGURED:
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
-		if (!cfg)
+		if (!cfg && !ret)
 			usb_gadget_set_state(&dwc->gadget,
 					USB_STATE_ADDRESS);
 		break;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index f77083f..f168eae 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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/kernel.h>
@@ -520,6 +500,8 @@
 	u32			reg;
 	int			ret = -ENOMEM;
 
+	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
 	if (!(dep->flags & DWC3_EP_ENABLED)) {
 		ret = dwc3_gadget_start_config(dwc, dep);
 		if (ret)
@@ -676,8 +658,6 @@
 		dev_err(dwc->dev, "invalid endpoint transfer type\n");
 	}
 
-	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
-
 	spin_lock_irqsave(&dwc->lock, flags);
 	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
 	spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1508,6 +1488,15 @@
 	int			irq;
 	u32			reg;
 
+	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+			IRQF_SHARED, "dwc3", dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				irq, ret);
+		goto err0;
+	}
+
 	spin_lock_irqsave(&dwc->lock, flags);
 
 	if (dwc->gadget_driver) {
@@ -1515,7 +1504,7 @@
 				dwc->gadget.name,
 				dwc->gadget_driver->driver.name);
 		ret = -EBUSY;
-		goto err0;
+		goto err1;
 	}
 
 	dwc->gadget_driver	= driver;
@@ -1536,10 +1525,25 @@
 	 * STAR#9000525659: Clock Domain Crossing on DCTL in
 	 * USB 2.0 Mode
 	 */
-	if (dwc->revision < DWC3_REVISION_220A)
+	if (dwc->revision < DWC3_REVISION_220A) {
 		reg |= DWC3_DCFG_SUPERSPEED;
-	else
-		reg |= dwc->maximum_speed;
+	} else {
+		switch (dwc->maximum_speed) {
+		case USB_SPEED_LOW:
+			reg |= DWC3_DSTS_LOWSPEED;
+			break;
+		case USB_SPEED_FULL:
+			reg |= DWC3_DSTS_FULLSPEED1;
+			break;
+		case USB_SPEED_HIGH:
+			reg |= DWC3_DSTS_HIGHSPEED;
+			break;
+		case USB_SPEED_SUPER:	/* FALLTHROUGH */
+		case USB_SPEED_UNKNOWN:	/* FALTHROUGH */
+		default:
+			reg |= DWC3_DSTS_SUPERSPEED;
+		}
+	}
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
 	dwc->start_config_issued = false;
@@ -1551,42 +1555,38 @@
 	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-		goto err0;
+		goto err2;
 	}
 
 	dep = dwc->eps[1];
 	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
-		goto err1;
+		goto err3;
 	}
 
 	/* begin to receive SETUP packets */
 	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 
-	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-	ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
-			IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
-	if (ret) {
-		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
-				irq, ret);
-		goto err1;
-	}
-
 	dwc3_gadget_enable_irq(dwc);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 
-err1:
+err3:
 	__dwc3_gadget_ep_disable(dwc->eps[0]);
 
-err0:
+err2:
 	dwc->gadget_driver = NULL;
+
+err1:
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
+	free_irq(irq, dwc);
+
+err0:
 	return ret;
 }
 
@@ -1600,9 +1600,6 @@
 	spin_lock_irqsave(&dwc->lock, flags);
 
 	dwc3_gadget_disable_irq(dwc);
-	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-	free_irq(irq, dwc);
-
 	__dwc3_gadget_ep_disable(dwc->eps[0]);
 	__dwc3_gadget_ep_disable(dwc->eps[1]);
 
@@ -1610,6 +1607,9 @@
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
+	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+	free_irq(irq, dwc);
+
 	return 0;
 }
 
@@ -1642,13 +1642,15 @@
 
 		dep->dwc = dwc;
 		dep->number = epnum;
+		dep->direction = !!direction;
 		dwc->eps[epnum] = dep;
 
 		snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
 				(epnum & 1) ? "in" : "out");
 
 		dep->endpoint.name = dep->name;
-		dep->direction = (epnum & 1);
+
+		dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
 
 		if (epnum == 0 || epnum == 1) {
 			dep->endpoint.maxpacket = 512;
@@ -2105,34 +2107,6 @@
 	dwc->setup_packet_pending = false;
 }
 
-static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
-{
-	u32			reg;
-
-	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
-
-	if (suspend)
-		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
-	else
-		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
-
-	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
-}
-
-static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend)
-{
-	u32			reg;
-
-	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
-
-	if (suspend)
-		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
-	else
-		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
-
-	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
-}
-
 static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 {
 	u32			reg;
@@ -2173,13 +2147,6 @@
 	/* after reset -> Default State */
 	usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
 
-	/* Recent versions support automatic phy suspend and don't need this */
-	if (dwc->revision < DWC3_REVISION_194A) {
-		/* Resume PHYs */
-		dwc3_gadget_usb2_phy_suspend(dwc, false);
-		dwc3_gadget_usb3_phy_suspend(dwc, false);
-	}
-
 	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
 		dwc3_disconnect_gadget(dwc);
 
@@ -2223,20 +2190,6 @@
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 }
 
-static void dwc3_gadget_phy_suspend(struct dwc3 *dwc, u8 speed)
-{
-	switch (speed) {
-	case USB_SPEED_SUPER:
-		dwc3_gadget_usb2_phy_suspend(dwc, true);
-		break;
-	case USB_SPEED_HIGH:
-	case USB_SPEED_FULL:
-	case USB_SPEED_LOW:
-		dwc3_gadget_usb3_phy_suspend(dwc, true);
-		break;
-	}
-}
-
 static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 {
 	struct dwc3_ep		*dep;
@@ -2312,12 +2265,6 @@
 		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 	}
 
-	/* Recent versions support automatic phy suspend and don't need this */
-	if (dwc->revision < DWC3_REVISION_194A) {
-		/* Suspend unneeded PHY */
-		dwc3_gadget_phy_suspend(dwc, dwc->gadget.speed);
-	}
-
 	dep = dwc->eps[0];
 	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
 	if (ret) {
@@ -2495,6 +2442,53 @@
 	}
 }
 
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+	struct dwc3_event_buffer *evt;
+	irqreturn_t ret = IRQ_NONE;
+	int left;
+	u32 reg;
+
+	evt = dwc->ev_buffs[buf];
+	left = evt->count;
+
+	if (!(evt->flags & DWC3_EVENT_PENDING))
+		return IRQ_NONE;
+
+	while (left > 0) {
+		union dwc3_event event;
+
+		event.raw = *(u32 *) (evt->buf + evt->lpos);
+
+		dwc3_process_event_entry(dwc, &event);
+
+		/*
+		 * FIXME we wrap around correctly to the next entry as
+		 * almost all entries are 4 bytes in size. There is one
+		 * entry which has 12 bytes which is a regular entry
+		 * followed by 8 bytes data. ATM I don't know how
+		 * things are organized if we get next to the a
+		 * boundary so I worry about that once we try to handle
+		 * that.
+		 */
+		evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+		left -= 4;
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+	}
+
+	evt->count = 0;
+	evt->flags &= ~DWC3_EVENT_PENDING;
+	ret = IRQ_HANDLED;
+
+	/* Unmask interrupt */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+	reg &= ~DWC3_GEVNTSIZ_INTMASK;
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
+	return ret;
+}
+
 static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
 {
 	struct dwc3 *dwc = _dwc;
@@ -2504,52 +2498,19 @@
 
 	spin_lock_irqsave(&dwc->lock, flags);
 
-	for (i = 0; i < dwc->num_event_buffers; i++) {
-		struct dwc3_event_buffer *evt;
-		int			left;
-
-		evt = dwc->ev_buffs[i];
-		left = evt->count;
-
-		if (!(evt->flags & DWC3_EVENT_PENDING))
-			continue;
-
-		while (left > 0) {
-			union dwc3_event event;
-
-			event.raw = *(u32 *) (evt->buf + evt->lpos);
-
-			dwc3_process_event_entry(dwc, &event);
-
-			/*
-			 * FIXME we wrap around correctly to the next entry as
-			 * almost all entries are 4 bytes in size. There is one
-			 * entry which has 12 bytes which is a regular entry
-			 * followed by 8 bytes data. ATM I don't know how
-			 * things are organized if we get next to the a
-			 * boundary so I worry about that once we try to handle
-			 * that.
-			 */
-			evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
-			left -= 4;
-
-			dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
-		}
-
-		evt->count = 0;
-		evt->flags &= ~DWC3_EVENT_PENDING;
-		ret = IRQ_HANDLED;
-	}
+	for (i = 0; i < dwc->num_event_buffers; i++)
+		ret |= dwc3_process_event_buf(dwc, i);
 
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
 }
 
-static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
 {
 	struct dwc3_event_buffer *evt;
 	u32 count;
+	u32 reg;
 
 	evt = dwc->ev_buffs[buf];
 
@@ -2561,6 +2522,11 @@
 	evt->count = count;
 	evt->flags |= DWC3_EVENT_PENDING;
 
+	/* Mask interrupt */
+	reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
+	reg |= DWC3_GEVNTSIZ_INTMASK;
+	dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+
 	return IRQ_WAKE_THREAD;
 }
 
@@ -2575,7 +2541,7 @@
 	for (i = 0; i < dwc->num_event_buffers; i++) {
 		irqreturn_t status;
 
-		status = dwc3_process_event_buf(dwc, i);
+		status = dwc3_check_event_buf(dwc, i);
 		if (status == IRQ_WAKE_THREAD)
 			ret = status;
 	}
@@ -2593,7 +2559,6 @@
  */
 int dwc3_gadget_init(struct dwc3 *dwc)
 {
-	u32					reg;
 	int					ret;
 
 	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
@@ -2643,16 +2608,6 @@
 	if (ret)
 		goto err4;
 
-	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
-	reg |= DWC3_DCFG_LPM_CAP;
-	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
-	/* Enable USB2 LPM and automatic phy suspend only on recent versions */
-	if (dwc->revision >= DWC3_REVISION_194A) {
-		dwc3_gadget_usb2_phy_suspend(dwc, false);
-		dwc3_gadget_usb3_phy_suspend(dwc, false);
-	}
-
 	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
 	if (ret) {
 		dev_err(dwc->dev, "failed to register udc\n");
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 99e6d72..febe1aa 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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 __DRIVERS_USB_DWC3_GADGET_H
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 0fa1846..32db328 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -5,34 +5,14 @@
  *
  * Authors: Felipe Balbi <balbi@ti.com>,
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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/platform_device.h>
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index a50f76b..d94441c 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -6,34 +6,14 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. 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.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * 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.
+ * 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 __DRIVERS_USB_DWC3_IO_H
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
new file mode 100644
index 0000000..7db34f0
--- /dev/null
+++ b/drivers/usb/dwc3/platform_data.h
@@ -0,0 +1,27 @@
+/**
+ * platform_data.h - USB DWC3 Platform Data Support
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Felipe Balbi <balbi@ti.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  of
+ * the 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+struct dwc3_platform_data {
+	enum usb_device_speed maximum_speed;
+	enum usb_dr_mode dr_mode;
+	bool tx_fifo_resize;
+};
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 8e93683..30e2dd8 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -144,7 +144,6 @@
 config USB_LPC32XX
 	tristate "LPC32XX USB Peripheral Controller"
 	depends on ARCH_LPC32XX
-	depends on USB_PHY
 	select USB_ISP1301
 	help
 	   This option selects the USB device controller in the LPC32xx SoC.
@@ -188,7 +187,7 @@
 
 config USB_FUSB300
 	tristate "Faraday FUSB300 USB Peripheral Controller"
-	depends on !PHYS_ADDR_T_64BIT
+	depends on !PHYS_ADDR_T_64BIT && HAS_DMA
 	help
 	   Faraday usb device controller FUSB300 driver
 
@@ -206,7 +205,6 @@
 config USB_OMAP
 	tristate "OMAP USB Device Controller"
 	depends on ARCH_OMAP1
-	depends on USB_PHY
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
 	help
 	   Many Texas Instruments OMAP processors have flexible full
@@ -246,6 +244,7 @@
 
 config USB_R8A66597
 	tristate "Renesas R8A66597 USB Peripheral Controller"
+	depends on HAS_DMA
 	help
 	   R8A66597 is a discrete USB host and peripheral controller chip that
 	   supports both full and high speed USB 2.0 data transfers.
@@ -287,21 +286,6 @@
 	  The Samsung S3C64XX USB2.0 high-speed gadget controller
 	  integrated into the S3C64XX series SoC.
 
-config USB_IMX
-	tristate "Freescale i.MX1 USB Peripheral Controller"
-	depends on ARCH_MXC
-	depends on BROKEN
-	help
-	   Freescale's i.MX1 includes an integrated full speed
-	   USB 1.1 device controller.
-
-	   It has Six fixed-function endpoints, as well as endpoint
-	   zero (for control transfers).
-
-	   Say "y" to link the driver statically, or "m" to build a
-	   dynamically linked module called "imx_udc" and force all
-	   gadget drivers to also be dynamically linked.
-
 config USB_S3C2410
 	tristate "S3C2410 USB Device Controller"
 	depends on ARCH_S3C24XX
@@ -402,7 +386,7 @@
 
 config USB_NET2272_DMA
 	boolean "Support external DMA controller"
-	depends on USB_NET2272
+	depends on USB_NET2272 && HAS_DMA
 	help
 	  The NET2272 part can optionally support an external DMA
 	  controller, but your board has to have support in the
@@ -572,7 +556,7 @@
 	  specified simply by creating appropriate directories in configfs.
 	  Associating functions with configurations is done by creating
 	  appropriate symbolic links.
-	  For more information see Documentation/usb/gadget-configfs.txt.
+	  For more information see Documentation/usb/gadget_configfs.txt.
 
 config USB_CONFIGFS_SERIAL
 	boolean "Generic serial bulk in/out"
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index bad08e6..386db9d 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -13,7 +13,6 @@
 obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
 obj-$(CONFIG_USB_PXA25X)	+= pxa25x_udc.o
 obj-$(CONFIG_USB_PXA27X)	+= pxa27x_udc.o
-obj-$(CONFIG_USB_IMX)		+= imx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index f52dcfe..a9a4346 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1122,7 +1122,7 @@
 			goto finished;
 		}
 		if (ep->dma) {
-			retval = prep_dma(ep, req, gfp);
+			retval = prep_dma(ep, req, GFP_ATOMIC);
 			if (retval != 0)
 				goto finished;
 			/* write desc pointer to enable DMA */
@@ -1190,7 +1190,7 @@
 		 * for PPB modes, because of chain creation reasons
 		 */
 		if (ep->in) {
-			retval = prep_dma(ep, req, gfp);
+			retval = prep_dma(ep, req, GFP_ATOMIC);
 			if (retval != 0)
 				goto finished;
 		}
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index d9a6add0..4cc4fd6 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -870,6 +870,11 @@
 	if (udc->clocked)
 		return;
 	udc->clocked = 1;
+
+	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+		clk_set_rate(udc->uclk, 48000000);
+		clk_prepare_enable(udc->uclk);
+	}
 	clk_prepare_enable(udc->iclk);
 	clk_prepare_enable(udc->fclk);
 }
@@ -882,6 +887,8 @@
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	clk_disable_unprepare(udc->fclk);
 	clk_disable_unprepare(udc->iclk);
+	if (IS_ENABLED(CONFIG_COMMON_CLK))
+		clk_disable_unprepare(udc->uclk);
 }
 
 /*
@@ -1697,7 +1704,7 @@
 	int		retval;
 	struct resource	*res;
 
-	if (!dev->platform_data && !pdev->dev.of_node) {
+	if (!dev_get_platdata(dev) && !pdev->dev.of_node) {
 		/* small (so we copy it) but critical! */
 		DBG("missing platform_data\n");
 		return -ENODEV;
@@ -1728,7 +1735,7 @@
 	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
 		at91udc_of_init(udc, pdev->dev.of_node);
 	else
-		memcpy(&udc->board, dev->platform_data,
+		memcpy(&udc->board, dev_get_platdata(dev),
 		       sizeof(struct at91_udc_data));
 	udc->pdev = pdev;
 	udc->enabled = 0;
@@ -1774,10 +1781,12 @@
 	/* get interface and function clocks */
 	udc->iclk = clk_get(dev, "udc_clk");
 	udc->fclk = clk_get(dev, "udpck");
-	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+	if (IS_ENABLED(CONFIG_COMMON_CLK))
+		udc->uclk = clk_get(dev, "usb_clk");
+	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) ||
+	    (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) {
 		DBG("clocks missing\n");
 		retval = -ENODEV;
-		/* NOTE: we "know" here that refcounts on these are NOPs */
 		goto fail1;
 	}
 
@@ -1851,6 +1860,12 @@
 fail2:
 	free_irq(udc->udp_irq, udc);
 fail1:
+	if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
+		clk_put(udc->uclk);
+	if (!IS_ERR(udc->fclk))
+		clk_put(udc->fclk);
+	if (!IS_ERR(udc->iclk))
+		clk_put(udc->iclk);
 	iounmap(udc->udp_baseaddr);
 fail0a:
 	if (cpu_is_at91rm9200())
@@ -1894,6 +1909,8 @@
 
 	clk_put(udc->iclk);
 	clk_put(udc->fclk);
+	if (IS_ENABLED(CONFIG_COMMON_CLK))
+		clk_put(udc->uclk);
 
 	return 0;
 }
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index e647d1c..0175246 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -126,7 +126,7 @@
 	unsigned			active_suspend:1;
 	u8				addr;
 	struct at91_udc_data		board;
-	struct clk			*iclk, *fclk;
+	struct clk			*iclk, *fclk, *uclk;
 	struct platform_device		*pdev;
 	struct proc_dir_entry		*pde;
 	void __iomem			*udp_baseaddr;
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 1d97222..2cb52e0 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1772,6 +1772,7 @@
 static int atmel_usba_start(struct usb_gadget *gadget,
 		struct usb_gadget_driver *driver)
 {
+	int ret;
 	struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
 	unsigned long flags;
 
@@ -1781,8 +1782,14 @@
 	udc->driver = driver;
 	spin_unlock_irqrestore(&udc->lock, flags);
 
-	clk_enable(udc->pclk);
-	clk_enable(udc->hclk);
+	ret = clk_prepare_enable(udc->pclk);
+	if (ret)
+		return ret;
+	ret = clk_prepare_enable(udc->hclk);
+	if (ret) {
+		clk_disable_unprepare(udc->pclk);
+		return ret;
+	}
 
 	DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
 
@@ -1822,8 +1829,8 @@
 
 	udc->driver = NULL;
 
-	clk_disable(udc->hclk);
-	clk_disable(udc->pclk);
+	clk_disable_unprepare(udc->hclk);
+	clk_disable_unprepare(udc->pclk);
 
 	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
 
@@ -1922,7 +1929,7 @@
 static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,
 						 struct usba_udc *udc)
 {
-	struct usba_platform_data *pdata = pdev->dev.platform_data;
+	struct usba_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct usba_ep *eps;
 	int i;
 
@@ -2022,10 +2029,14 @@
 	platform_set_drvdata(pdev, udc);
 
 	/* Make sure we start from a clean slate */
-	clk_enable(pclk);
+	ret = clk_prepare_enable(pclk);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
+		goto err_clk_enable;
+	}
 	toggle_bias(0);
 	usba_writel(udc, CTRL, USBA_DISABLE_MASK);
-	clk_disable(pclk);
+	clk_disable_unprepare(pclk);
 
 	if (pdev->dev.of_node)
 		udc->usba_ep = atmel_udc_of_init(pdev, udc);
@@ -2081,6 +2092,7 @@
 	free_irq(irq, udc);
 err_request_irq:
 err_alloc_ep:
+err_clk_enable:
 	iounmap(udc->fifo);
 err_map_fifo:
 	iounmap(udc->regs);
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
index fd24cb4..c58fcf1 100644
--- a/drivers/usb/gadget/bcm63xx_udc.c
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -2313,7 +2313,7 @@
 static int bcm63xx_udc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct bcm63xx_usbd_platform_data *pd = dev->platform_data;
+	struct bcm63xx_usbd_platform_data *pd = dev_get_platdata(dev);
 	struct bcm63xx_udc *udc;
 	struct resource *res;
 	int rc = -ENOMEM, i, irq;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 55f4df6..d4f0f33 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1497,17 +1497,15 @@
 
 /*-------------------------------------------------------------------------*/
 
-static ssize_t composite_show_suspended(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
+static ssize_t suspended_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
 {
 	struct usb_gadget *gadget = dev_to_usb_gadget(dev);
 	struct usb_composite_dev *cdev = get_gadget_data(gadget);
 
 	return sprintf(buf, "%d\n", cdev->suspended);
 }
-
-static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
+static DEVICE_ATTR_RO(suspended);
 
 static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
 {
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 80e7f75..8f0d614 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -859,8 +859,10 @@
 		list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
 			list_del(&f->list);
 			ret = usb_add_function(c, f);
-			if (ret)
+			if (ret) {
+				list_add(&f->list, &cfg->func_list);
 				goto err_purge_funcs;
+			}
 		}
 		usb_ep_autoconfig_reset(cdev->gadget);
 	}
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c588e8e..06ecd08 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -868,7 +868,7 @@
 /*-------------------------------------------------------------------------*/
 
 /* "function" sysfs attribute */
-static ssize_t show_function(struct device *dev, struct device_attribute *attr,
+static ssize_t function_show(struct device *dev, struct device_attribute *attr,
 		char *buf)
 {
 	struct dummy	*dum = gadget_dev_to_dummy(dev);
@@ -877,7 +877,7 @@
 		return 0;
 	return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function);
 }
-static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR_RO(function);
 
 /*-------------------------------------------------------------------------*/
 
@@ -2290,7 +2290,7 @@
 		urb->actual_length, urb->transfer_buffer_length);
 }
 
-static ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
+static ssize_t urbs_show(struct device *dev, struct device_attribute *attr,
 		char *buf)
 {
 	struct usb_hcd		*hcd = dev_get_drvdata(dev);
@@ -2311,7 +2311,7 @@
 
 	return size;
 }
-static DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL);
+static DEVICE_ATTR_RO(urbs);
 
 static int dummy_start_ss(struct dummy_hcd *dum_hcd)
 {
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 4b7e33e..ab1065a 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -285,6 +285,7 @@
 	[ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
 	[ACM_DATA_IDX].s = "CDC ACM Data",
 	[ACM_IAD_IDX ].s = "CDC Serial",
+	{  } /* end of list */
 };
 
 static struct usb_gadget_strings acm_string_table = {
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f394f29..1a66c5b 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1417,8 +1417,8 @@
 		usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
 		ffs->ep0req = NULL;
 		ffs->gadget = NULL;
-		ffs_data_put(ffs);
 		clear_bit(FFS_FL_BOUND, &ffs->flags);
+		ffs_data_put(ffs);
 	}
 }
 
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 56f1fd1..313b835 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2578,14 +2578,12 @@
 
 /*************************** DEVICE ATTRIBUTES ***************************/
 
-static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
-static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
-static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
+static DEVICE_ATTR_RW(ro);
+static DEVICE_ATTR_RW(nofua);
+static DEVICE_ATTR_RW(file);
 
-static struct device_attribute dev_attr_ro_cdrom =
-	__ATTR(ro, 0444, fsg_show_ro, NULL);
-static struct device_attribute dev_attr_file_nonremovable =
-	__ATTR(file, 0444, fsg_show_file, NULL);
+static struct device_attribute dev_attr_ro_cdrom = __ATTR_RO(ro);
+static struct device_attribute dev_attr_file_nonremovable = __ATTR_RO(file);
 
 
 /****************************** FSG COMMON ******************************/
@@ -3043,12 +3041,12 @@
 		lun->filename =
 			params->file_count > i && params->file[i][0]
 			? params->file[i]
-			: 0;
+			: NULL;
 	}
 
 	/* Let MSF use defaults */
-	cfg->vendor_name = 0;
-	cfg->product_name = 0;
+	cfg->vendor_name = NULL;
+	cfg->product_name = NULL;
 
 	cfg->ops = NULL;
 	cfg->private_data = NULL;
diff --git a/drivers/usb/gadget/f_uac1.c b/drivers/usb/gadget/f_uac1.c
index fa8ea4e..2b4c82d 100644
--- a/drivers/usb/gadget/f_uac1.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -695,7 +695,7 @@
 }
 
 /* Todo: add more control selecotor dynamically */
-int __init control_selector_init(struct f_audio *audio)
+static int __init control_selector_init(struct f_audio *audio)
 {
 	INIT_LIST_HEAD(&audio->cs);
 	list_add(&feature_unit.list, &audio->cs);
@@ -719,7 +719,7 @@
  *
  * Returns zero on success, else negative errno.
  */
-int __init audio_bind_config(struct usb_configuration *c)
+static int __init audio_bind_config(struct usb_configuration *c)
 {
 	struct f_audio *audio;
 	int status;
diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c
index 10cd18d..32db2ee 100644
--- a/drivers/usb/gadget/fotg210-udc.c
+++ b/drivers/usb/gadget/fotg210-udc.c
@@ -1076,7 +1076,7 @@
 
 static int fotg210_udc_remove(struct platform_device *pdev)
 {
-	struct fotg210_udc *fotg210 = dev_get_drvdata(&pdev->dev);
+	struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
 
 	usb_del_gadget_udc(&fotg210->gadget);
 	iounmap(fotg210->reg);
@@ -1134,7 +1134,7 @@
 
 	spin_lock_init(&fotg210->lock);
 
-	dev_set_drvdata(&pdev->dev, fotg210);
+	platform_set_drvdata(pdev, fotg210);
 
 	fotg210->gadget.ops = &fotg210_gadget_ops;
 
diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c
index d3bd7b0..9b140fc 100644
--- a/drivers/usb/gadget/fsl_mxc_udc.c
+++ b/drivers/usb/gadget/fsl_mxc_udc.c
@@ -33,7 +33,7 @@
 	unsigned long freq;
 	int ret;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 
 	mxc_ipg_clk = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(mxc_ipg_clk)) {
@@ -80,7 +80,7 @@
 
 int fsl_udc_clk_finalize(struct platform_device *pdev)
 {
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	int ret = 0;
 
 	/* workaround ENGcm09152 for i.MX35 */
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index a766a4c..36ac7cf 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -2248,7 +2248,7 @@
 	struct fsl_usb2_platform_data *pdata;
 	size_t size;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	udc->phy_mode = pdata->phy_mode;
 
 	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
@@ -2343,7 +2343,7 @@
 		return -ENOMEM;
 	}
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	udc_controller->pdata = pdata;
 	spin_lock_init(&udc_controller->lock);
 	udc_controller->stopped = 1;
@@ -2524,7 +2524,7 @@
 static int __exit fsl_udc_remove(struct platform_device *pdev)
 {
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	DECLARE_COMPLETION(done);
 
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index c83f3e1..f1dd6da 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -557,7 +557,7 @@
 }
 
 /* read data from cx fifo */
-void fusb300_rdcxf(struct fusb300 *fusb300,
+static void fusb300_rdcxf(struct fusb300 *fusb300,
 		   u8 *buffer, u32 length)
 {
 	int i = 0;
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 52dd6cc..c64deb9 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -772,7 +772,7 @@
 
 	} /* else pio or dma irq handler advances the queue. */
 
-	if (likely(req != 0))
+	if (likely(req != NULL))
 		list_add_tail(&req->queue, &ep->queue);
 
 	if (likely(!list_empty(&ep->queue))
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index c36260ea..778613eb 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -185,7 +185,7 @@
 
 static int __init hidg_plat_driver_probe(struct platform_device *pdev)
 {
-	struct hidg_func_descriptor *func = pdev->dev.platform_data;
+	struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
 	struct hidg_func_node *entry;
 
 	if (!func) {
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
deleted file mode 100644
index 9b2d24e..0000000
--- a/drivers/usb/gadget/imx_udc.c
+++ /dev/null
@@ -1,1544 +0,0 @@
-/*
- *	driver/usb/gadget/imx_udc.c
- *
- *	Copyright (C) 2005 Mike Lee <eemike@gmail.com>
- *	Copyright (C) 2008 Darius Augulis <augulis.darius@gmail.com>
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/prefetch.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include <linux/platform_data/usb-imx_udc.h>
-#include <mach/hardware.h>
-
-#include "imx_udc.h"
-
-static const char driver_name[] = "imx_udc";
-static const char ep0name[] = "ep0";
-
-void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb,
-							enum ep0_state stat);
-
-/*******************************************************************************
- * IMX UDC hardware related functions
- *******************************************************************************
- */
-
-void imx_udc_enable(struct imx_udc_struct *imx_usb)
-{
-	int temp = __raw_readl(imx_usb->base + USB_CTRL);
-	__raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA,
-						imx_usb->base + USB_CTRL);
-	imx_usb->gadget.speed = USB_SPEED_FULL;
-}
-
-void imx_udc_disable(struct imx_udc_struct *imx_usb)
-{
-	int temp = __raw_readl(imx_usb->base + USB_CTRL);
-
-	__raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA),
-		 imx_usb->base + USB_CTRL);
-
-	ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
-	imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-}
-
-void imx_udc_reset(struct imx_udc_struct *imx_usb)
-{
-	int temp = __raw_readl(imx_usb->base + USB_ENAB);
-
-	/* set RST bit */
-	__raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB);
-
-	/* wait RST bit to clear */
-	do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST);
-
-	/* wait CFG bit to assert */
-	do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
-
-	/* udc module is now ready */
-}
-
-void imx_udc_config(struct imx_udc_struct *imx_usb)
-{
-	u8 ep_conf[5];
-	u8 i, j, cfg;
-	struct imx_ep_struct *imx_ep;
-
-	/* wait CFG bit to assert */
-	do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
-
-	/* Download the endpoint buffer for endpoint 0. */
-	for (j = 0; j < 5; j++) {
-		i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00);
-		__raw_writeb(i, imx_usb->base + USB_DDAT);
-		do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY);
-	}
-
-	/* Download the endpoint buffers for endpoints 1-5.
-	 * We specify two configurations, one interface
-	 */
-	for (cfg = 1; cfg < 3; cfg++) {
-		for (i = 1; i < IMX_USB_NB_EP; i++) {
-			imx_ep = &imx_usb->imx_ep[i];
-			/* EP no | Config no */
-			ep_conf[0] = (i << 4) | (cfg << 2);
-			/* Type | Direction */
-			ep_conf[1] = (imx_ep->bmAttributes << 3) |
-					(EP_DIR(imx_ep) << 2);
-			/* Max packet size */
-			ep_conf[2] = imx_ep->fifosize;
-			/* TRXTYP */
-			ep_conf[3] = 0xC0;
-			/* FIFO no */
-			ep_conf[4] = i;
-
-			D_INI(imx_usb->dev,
-				"<%s> ep%d_conf[%d]:"
-				"[%02x-%02x-%02x-%02x-%02x]\n",
-				__func__, i, cfg,
-				ep_conf[0], ep_conf[1], ep_conf[2],
-				ep_conf[3], ep_conf[4]);
-
-			for (j = 0; j < 5; j++) {
-				__raw_writeb(ep_conf[j],
-					imx_usb->base + USB_DDAT);
-				do {} while (__raw_readl(imx_usb->base
-								+ USB_DADR)
-					& DADR_BSY);
-			}
-		}
-	}
-
-	/* wait CFG bit to clear */
-	do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG);
-}
-
-void imx_udc_init_irq(struct imx_udc_struct *imx_usb)
-{
-	int i;
-
-	/* Mask and clear all irqs */
-	__raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK);
-	__raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR);
-	for (i = 0; i < IMX_USB_NB_EP; i++) {
-		__raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i));
-		__raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i));
-	}
-
-	/* Enable USB irqs */
-	__raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK);
-
-	/* Enable EP0 irqs */
-	__raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT
-		| EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL),
-		imx_usb->base + USB_EP_MASK(0));
-}
-
-void imx_udc_init_ep(struct imx_udc_struct *imx_usb)
-{
-	int i, max, temp;
-	struct imx_ep_struct *imx_ep;
-	for (i = 0; i < IMX_USB_NB_EP; i++) {
-		imx_ep = &imx_usb->imx_ep[i];
-		switch (imx_ep->fifosize) {
-		case 8:
-			max = 0;
-			break;
-		case 16:
-			max = 1;
-			break;
-		case 32:
-			max = 2;
-			break;
-		case 64:
-			max = 3;
-			break;
-		default:
-			max = 1;
-			break;
-		}
-		temp = (EP_DIR(imx_ep) << 7) | (max << 5)
-			| (imx_ep->bmAttributes << 3);
-		__raw_writel(temp, imx_usb->base + USB_EP_STAT(i));
-		__raw_writel(temp | EPSTAT_FLUSH,
-						imx_usb->base + USB_EP_STAT(i));
-		D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i,
-			__raw_readl(imx_usb->base + USB_EP_STAT(i)));
-	}
-}
-
-void imx_udc_init_fifo(struct imx_udc_struct *imx_usb)
-{
-	int i, temp;
-	struct imx_ep_struct *imx_ep;
-	for (i = 0; i < IMX_USB_NB_EP; i++) {
-		imx_ep = &imx_usb->imx_ep[i];
-
-		/* Fifo control */
-		temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000;
-		__raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i));
-		D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i,
-			__raw_readl(imx_usb->base + USB_EP_FCTRL(i)));
-
-		/* Fifo alarm */
-		temp = (i ? imx_ep->fifosize / 2 : 0);
-		__raw_writel(temp, imx_usb->base + USB_EP_FALRM(i));
-		D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i,
-			__raw_readl(imx_usb->base + USB_EP_FALRM(i)));
-	}
-}
-
-static void imx_udc_init(struct imx_udc_struct *imx_usb)
-{
-	/* Reset UDC */
-	imx_udc_reset(imx_usb);
-
-	/* Download config to enpoint buffer */
-	imx_udc_config(imx_usb);
-
-	/* Setup interrups */
-	imx_udc_init_irq(imx_usb);
-
-	/* Setup endpoints */
-	imx_udc_init_ep(imx_usb);
-
-	/* Setup fifos */
-	imx_udc_init_fifo(imx_usb);
-}
-
-void imx_ep_irq_enable(struct imx_ep_struct *imx_ep)
-{
-
-	int i = EP_NO(imx_ep);
-
-	__raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
-	__raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
-	__raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF),
-		imx_ep->imx_usb->base + USB_EP_MASK(i));
-}
-
-void imx_ep_irq_disable(struct imx_ep_struct *imx_ep)
-{
-
-	int i = EP_NO(imx_ep);
-
-	__raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
-	__raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
-}
-
-int imx_ep_empty(struct imx_ep_struct *imx_ep)
-{
-	struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
-	return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
-			& FSTAT_EMPTY;
-}
-
-unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep)
-{
-	struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
-	return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)))
-			& EPSTAT_BCOUNT) >> 16;
-}
-
-void imx_flush(struct imx_ep_struct *imx_ep)
-{
-	struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-
-	int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-	__raw_writel(temp | EPSTAT_FLUSH,
-		imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-}
-
-void imx_ep_stall(struct imx_ep_struct *imx_ep)
-{
-	struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-	int temp, i;
-
-	D_ERR(imx_usb->dev,
-		"<%s> Forced stall on %s\n", __func__, imx_ep->ep.name);
-
-	imx_flush(imx_ep);
-
-	/* Special care for ep0 */
-	if (!EP_NO(imx_ep)) {
-		temp = __raw_readl(imx_usb->base + USB_CTRL);
-		__raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR,
-						imx_usb->base + USB_CTRL);
-		do { } while (__raw_readl(imx_usb->base + USB_CTRL)
-						& CTRL_CMDOVER);
-		temp = __raw_readl(imx_usb->base + USB_CTRL);
-		__raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL);
-	}
-	else {
-		temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-		__raw_writel(temp | EPSTAT_STALL,
-			imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
-
-		for (i = 0; i < 100; i ++) {
-			temp = __raw_readl(imx_usb->base
-						+ USB_EP_STAT(EP_NO(imx_ep)));
-			if (!(temp & EPSTAT_STALL))
-	 			break;
-	 		udelay(20);
-	 	}
-		if (i == 100)
-			D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n",
-				__func__, imx_ep->ep.name);
-	}
-}
-
-static int imx_udc_get_frame(struct usb_gadget *_gadget)
-{
-	struct imx_udc_struct *imx_usb = container_of(_gadget,
-			struct imx_udc_struct, gadget);
-
-	return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF;
-}
-
-static int imx_udc_wakeup(struct usb_gadget *_gadget)
-{
-	return 0;
-}
-
-/*******************************************************************************
- * USB request control functions
- *******************************************************************************
- */
-
-static void ep_add_request(struct imx_ep_struct *imx_ep,
-							struct imx_request *req)
-{
-	if (unlikely(!req))
-		return;
-
-	req->in_use = 1;
-	list_add_tail(&req->queue, &imx_ep->queue);
-}
-
-static void ep_del_request(struct imx_ep_struct *imx_ep,
-							struct imx_request *req)
-{
-	if (unlikely(!req))
-		return;
-
-	list_del_init(&req->queue);
-	req->in_use = 0;
-}
-
-static void done(struct imx_ep_struct *imx_ep,
-					struct imx_request *req, int status)
-{
-	ep_del_request(imx_ep, req);
-
-	if (likely(req->req.status == -EINPROGRESS))
-		req->req.status = status;
-	else
-		status = req->req.status;
-
-	if (status && status != -ESHUTDOWN)
-		D_ERR(imx_ep->imx_usb->dev,
-			"<%s> complete %s req %p stat %d len %u/%u\n", __func__,
-			imx_ep->ep.name, &req->req, status,
-			req->req.actual, req->req.length);
-
-	req->req.complete(&imx_ep->ep, &req->req);
-}
-
-static void nuke(struct imx_ep_struct *imx_ep, int status)
-{
-	struct imx_request *req;
-
-	while (!list_empty(&imx_ep->queue)) {
-		req = list_entry(imx_ep->queue.next, struct imx_request, queue);
-		done(imx_ep, req, status);
-	}
-}
-
-/*******************************************************************************
- * Data tansfer over USB functions
- *******************************************************************************
- */
-static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-	u8	*buf;
-	int	bytes_ep, bufferspace, count, i;
-
-	bytes_ep = imx_fifo_bcount(imx_ep);
-	bufferspace = req->req.length - req->req.actual;
-
-	buf = req->req.buf + req->req.actual;
-	prefetchw(buf);
-
-	if (unlikely(imx_ep_empty(imx_ep)))
-		count = 0;	/* zlp */
-	else
-		count = min(bytes_ep, bufferspace);
-
-	for (i = count; i > 0; i--)
-		*buf++ = __raw_readb(imx_ep->imx_usb->base
-						+ USB_EP_FDAT0(EP_NO(imx_ep)));
-	req->req.actual += count;
-
-	return count;
-}
-
-static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-	u8	*buf;
-	int	length, count, temp;
-
-	if (unlikely(__raw_readl(imx_ep->imx_usb->base +
-				 USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) {
-		D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n",
-			__func__, imx_ep->ep.name);
-		return -1;
-	}
-
-	buf = req->req.buf + req->req.actual;
-	prefetch(buf);
-
-	length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize);
-
-	if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) {
-		D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n",
-			__func__, imx_ep->ep.name);
-		return -1;
-	}
-
-	req->req.actual += length;
-	count = length;
-
-	if (!count && req->req.zero) {	/* zlp */
-		temp = __raw_readl(imx_ep->imx_usb->base
-			+ USB_EP_STAT(EP_NO(imx_ep)));
-		__raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base
-			+ USB_EP_STAT(EP_NO(imx_ep)));
-		D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__);
-		return 0;
-	}
-
-	while (count--) {
-		if (count == 0) {	/* last byte */
-			temp = __raw_readl(imx_ep->imx_usb->base
-				+ USB_EP_FCTRL(EP_NO(imx_ep)));
-			__raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base
-				+ USB_EP_FCTRL(EP_NO(imx_ep)));
-		}
-		__raw_writeb(*buf++,
-			imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep)));
-	}
-
-	return length;
-}
-
-static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-	int 	bytes = 0,
-		count,
-		completed = 0;
-
-	while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
-		& FSTAT_FR) {
-			count = read_packet(imx_ep, req);
-			bytes += count;
-
-			completed = (count != imx_ep->fifosize);
-			if (completed || req->req.actual == req->req.length) {
-				completed = 1;
-				break;
-			}
-	}
-
-	if (completed || !req->req.length) {
-		done(imx_ep, req, 0);
-		D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
-			__func__, imx_ep->ep.name, req,
-			completed ? "completed" : "not completed");
-		if (!EP_NO(imx_ep))
-			ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE);
-	}
-
-	D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes);
-
-	return completed;
-}
-
-static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
-{
-	int	bytes = 0,
-		count,
-		completed = 0;
-
-	while (!completed) {
-		count = write_packet(imx_ep, req);
-		if (count < 0)
-			break; /* busy */
-		bytes += count;
-
-		/* last packet "must be" short (or a zlp) */
-		completed = (count != imx_ep->fifosize);
-
-		if (unlikely(completed)) {
-			done(imx_ep, req, 0);
-			D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
-				__func__, imx_ep->ep.name, req,
-				completed ? "completed" : "not completed");
-			if (!EP_NO(imx_ep))
-				ep0_chg_stat(__func__,
-						imx_ep->imx_usb, EP0_IDLE);
-		}
-	}
-
-	D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes);
-
-	return completed;
-}
-
-/*******************************************************************************
- * Endpoint handlers
- *******************************************************************************
- */
-static int handle_ep(struct imx_ep_struct *imx_ep)
-{
-	struct imx_request *req;
-	int completed = 0;
-
-	do {
-		if (!list_empty(&imx_ep->queue))
-			req = list_entry(imx_ep->queue.next,
-				struct imx_request, queue);
-		else {
-			D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
-				__func__, imx_ep->ep.name);
-			return 0;
-		}
-
-		if (EP_DIR(imx_ep))	/* to host */
-			completed = write_fifo(imx_ep, req);
-		else			/* to device */
-			completed = read_fifo(imx_ep, req);
-
-		dump_ep_stat(__func__, imx_ep);
-
-	} while (completed);
-
-	return 0;
-}
-
-static int handle_ep0(struct imx_ep_struct *imx_ep)
-{
-	struct imx_request *req = NULL;
-	int ret = 0;
-
-	if (!list_empty(&imx_ep->queue)) {
-		req = list_entry(imx_ep->queue.next, struct imx_request, queue);
-
-		switch (imx_ep->imx_usb->ep0state) {
-
-		case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR */
-			write_fifo(imx_ep, req);
-			break;
-		case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR */
-			read_fifo(imx_ep, req);
-			break;
-		default:
-			D_EP0(imx_ep->imx_usb->dev,
-				"<%s> ep0 i/o, odd state %d\n",
-				__func__, imx_ep->imx_usb->ep0state);
-			ep_del_request(imx_ep, req);
-			ret = -EL2HLT;
-			break;
-		}
-	}
-
-	else
-		D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
-						__func__, imx_ep->ep.name);
-
-	return ret;
-}
-
-static void handle_ep0_devreq(struct imx_udc_struct *imx_usb)
-{
-	struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
-	union {
-		struct usb_ctrlrequest	r;
-		u8			raw[8];
-		u32			word[2];
-	} u;
-	int temp, i;
-
-	nuke(imx_ep, -EPROTO);
-
-	/* read SETUP packet */
-	for (i = 0; i < 2; i++) {
-		if (imx_ep_empty(imx_ep)) {
-			D_ERR(imx_usb->dev,
-				"<%s> no setup packet received\n", __func__);
-			goto stall;
-		}
-		u.word[i] = __raw_readl(imx_usb->base
-						+ USB_EP_FDAT(EP_NO(imx_ep)));
-	}
-
-	temp = imx_ep_empty(imx_ep);
-	while (!imx_ep_empty(imx_ep)) {
-		i = __raw_readl(imx_usb->base +	USB_EP_FDAT(EP_NO(imx_ep)));
-		D_ERR(imx_usb->dev,
-			"<%s> wrong to have extra bytes for setup : 0x%08x\n",
-			__func__, i);
-	}
-	if (!temp)
-		goto stall;
-
-	le16_to_cpus(&u.r.wValue);
-	le16_to_cpus(&u.r.wIndex);
-	le16_to_cpus(&u.r.wLength);
-
-	D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n",
-		__func__, u.r.bRequestType, u.r.bRequest,
-		u.r.wValue, u.r.wIndex, u.r.wLength);
-
-	if (imx_usb->set_config) {
-		/* NACK the host by using CMDOVER */
-		temp = __raw_readl(imx_usb->base + USB_CTRL);
-		__raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL);
-
-		D_ERR(imx_usb->dev,
-			"<%s> set config req is pending, NACK the host\n",
-			__func__);
-		return;
-	}
-
-	if (u.r.bRequestType & USB_DIR_IN)
-		ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE);
-	else
-		ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE);
-
-	i = imx_usb->driver->setup(&imx_usb->gadget, &u.r);
-	if (i < 0) {
-		D_ERR(imx_usb->dev, "<%s> device setup error %d\n",
-			__func__, i);
-		goto stall;
-	}
-
-	return;
-stall:
-	D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__);
-	imx_ep_stall(imx_ep);
-	ep0_chg_stat(__func__, imx_usb, EP0_STALL);
-	return;
-}
-
-/*******************************************************************************
- * USB gadget callback functions
- *******************************************************************************
- */
-
-static int imx_ep_enable(struct usb_ep *usb_ep,
-				const struct usb_endpoint_descriptor *desc)
-{
-	struct imx_ep_struct *imx_ep = container_of(usb_ep,
-						struct imx_ep_struct, ep);
-	struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
-	unsigned long flags;
-
-	if (!usb_ep
-		|| !desc
-		|| !EP_NO(imx_ep)
-		|| desc->bDescriptorType != USB_DT_ENDPOINT
-		|| imx_ep->bEndpointAddress != desc->bEndpointAddress) {
-			D_ERR(imx_usb->dev,
-				"<%s> bad ep or descriptor\n", __func__);
-			return -EINVAL;
-	}
-
-	if (imx_ep->bmAttributes != desc->bmAttributes) {
-		D_ERR(imx_usb->dev,
-			"<%s> %s type mismatch\n", __func__, usb_ep->name);
-		return -EINVAL;
-	}
-
-	if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
-		D_ERR(imx_usb->dev,
-			"<%s> bad %s maxpacket\n", __func__, usb_ep->name);
-		return -ERANGE;
-	}
-
-	if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
-		D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
-		return -ESHUTDOWN;
-	}
-
-	local_irq_save(flags);
-
-	imx_ep->stopped = 0;
-	imx_flush(imx_ep);
-	imx_ep_irq_enable(imx_ep);
-
-	local_irq_restore(flags);
-
-	D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name);
-	return 0;
-}
-
-static int imx_ep_disable(struct usb_ep *usb_ep)
-{
-	struct imx_ep_struct *imx_ep = container_of(usb_ep,
-						struct imx_ep_struct, ep);
-	unsigned long flags;
-
-	if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
-		D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n",
-			__func__, usb_ep ? imx_ep->ep.name : NULL);
-		return -EINVAL;
-	}
-
-	local_irq_save(flags);
-
-	imx_ep->stopped = 1;
-	nuke(imx_ep, -ESHUTDOWN);
-	imx_flush(imx_ep);
-	imx_ep_irq_disable(imx_ep);
-
-	local_irq_restore(flags);
-
-	D_EPX(imx_ep->imx_usb->dev,
-		"<%s> DISABLED %s\n", __func__, usb_ep->name);
-	return 0;
-}
-
-static struct usb_request *imx_ep_alloc_request
-					(struct usb_ep *usb_ep, gfp_t gfp_flags)
-{
-	struct imx_request *req;
-
-	if (!usb_ep)
-		return NULL;
-
-	req = kzalloc(sizeof *req, gfp_flags);
-	if (!req)
-		return NULL;
-
-	INIT_LIST_HEAD(&req->queue);
-	req->in_use = 0;
-
-	return &req->req;
-}
-
-static void imx_ep_free_request
-			(struct usb_ep *usb_ep, struct usb_request *usb_req)
-{
-	struct imx_request *req;
-
-	req = container_of(usb_req, struct imx_request, req);
-	WARN_ON(!list_empty(&req->queue));
-	kfree(req);
-}
-
-static int imx_ep_queue
-	(struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags)
-{
-	struct imx_ep_struct	*imx_ep;
-	struct imx_udc_struct	*imx_usb;
-	struct imx_request	*req;
-	unsigned long		flags;
-	int			ret = 0;
-
-	imx_ep = container_of(usb_ep, struct imx_ep_struct, ep);
-	imx_usb = imx_ep->imx_usb;
-	req = container_of(usb_req, struct imx_request, req);
-
-	/*
-	  Special care on IMX udc.
-	  Ignore enqueue when after set configuration from the
-	  host. This assume all gadget drivers reply set
-	  configuration with the next ep0 req enqueue.
-	*/
-	if (imx_usb->set_config && !EP_NO(imx_ep)) {
-		imx_usb->set_config = 0;
-		D_ERR(imx_usb->dev,
-			"<%s> gadget reply set config\n", __func__);
-		return 0;
-	}
-
-	if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) {
-		D_ERR(imx_usb->dev, "<%s> bad params\n", __func__);
-		return -EINVAL;
-	}
-
-	if (unlikely(!usb_ep || !imx_ep)) {
-		D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__);
-		return -EINVAL;
-	}
-
-	if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
-		D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
-		return -ESHUTDOWN;
-	}
-
-	/* Debug */
-	D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n",
-		__func__, EP_NO(imx_ep),
-		((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
-							== EP0_IN_DATA_PHASE)
-		|| (EP_NO(imx_ep) && EP_DIR(imx_ep)))
-					? "IN" : "OUT", usb_req->length);
-	dump_req(__func__, imx_ep, usb_req);
-
-	if (imx_ep->stopped) {
-		usb_req->status = -ESHUTDOWN;
-		return -ESHUTDOWN;
-	}
-
-	if (req->in_use) {
-		D_ERR(imx_usb->dev,
-			"<%s> refusing to queue req %p (already queued)\n",
-			__func__, req);
-		return 0;
-	}
-
-	local_irq_save(flags);
-
-	usb_req->status = -EINPROGRESS;
-	usb_req->actual = 0;
-
-	ep_add_request(imx_ep, req);
-
-	if (!EP_NO(imx_ep))
-		ret = handle_ep0(imx_ep);
-	else
-		ret = handle_ep(imx_ep);
-
-	local_irq_restore(flags);
-	return ret;
-}
-
-static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
-{
-
-	struct imx_ep_struct *imx_ep = container_of
-					(usb_ep, struct imx_ep_struct, ep);
-	struct imx_request *req;
-	unsigned long flags;
-
-	if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
-		D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-		return -EINVAL;
-	}
-
-	local_irq_save(flags);
-
-	/* make sure it's actually queued on this endpoint */
-	list_for_each_entry(req, &imx_ep->queue, queue) {
-		if (&req->req == usb_req)
-			break;
-	}
-	if (&req->req != usb_req) {
-		local_irq_restore(flags);
-		return -EINVAL;
-	}
-
-	done(imx_ep, req, -ECONNRESET);
-
-	local_irq_restore(flags);
-	return 0;
-}
-
-static int imx_ep_set_halt(struct usb_ep *usb_ep, int value)
-{
-	struct imx_ep_struct *imx_ep = container_of
-					(usb_ep, struct imx_ep_struct, ep);
-	unsigned long flags;
-
-	if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
-		D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-		return -EINVAL;
-	}
-
-	local_irq_save(flags);
-
-	if ((imx_ep->bEndpointAddress & USB_DIR_IN)
-		&& !list_empty(&imx_ep->queue)) {
-			local_irq_restore(flags);
-			return -EAGAIN;
-	}
-
-	imx_ep_stall(imx_ep);
-
-	local_irq_restore(flags);
-
-	D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name);
-	return 0;
-}
-
-static int imx_ep_fifo_status(struct usb_ep *usb_ep)
-{
-	struct imx_ep_struct *imx_ep = container_of
-					(usb_ep, struct imx_ep_struct, ep);
-
-	if (!usb_ep) {
-		D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-		return -ENODEV;
-	}
-
-	if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
-		return 0;
-	else
-		return imx_fifo_bcount(imx_ep);
-}
-
-static void imx_ep_fifo_flush(struct usb_ep *usb_ep)
-{
-	struct imx_ep_struct *imx_ep = container_of
-					(usb_ep, struct imx_ep_struct, ep);
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
-		D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
-		local_irq_restore(flags);
-		return;
-	}
-
-	/* toggle and halt bits stay unchanged */
-	imx_flush(imx_ep);
-
-	local_irq_restore(flags);
-}
-
-static struct usb_ep_ops imx_ep_ops = {
-	.enable		= imx_ep_enable,
-	.disable	= imx_ep_disable,
-
-	.alloc_request	= imx_ep_alloc_request,
-	.free_request	= imx_ep_free_request,
-
-	.queue		= imx_ep_queue,
-	.dequeue	= imx_ep_dequeue,
-
-	.set_halt	= imx_ep_set_halt,
-	.fifo_status	= imx_ep_fifo_status,
-	.fifo_flush	= imx_ep_fifo_flush,
-};
-
-/*******************************************************************************
- * USB endpoint control functions
- *******************************************************************************
- */
-
-void ep0_chg_stat(const char *label,
-			struct imx_udc_struct *imx_usb, enum ep0_state stat)
-{
-	D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n",
-		label, state_name[imx_usb->ep0state], state_name[stat]);
-
-	if (imx_usb->ep0state == stat)
-		return;
-
-	imx_usb->ep0state = stat;
-}
-
-static void usb_init_data(struct imx_udc_struct *imx_usb)
-{
-	struct imx_ep_struct *imx_ep;
-	u8 i;
-
-	/* device/ep0 records init */
-	INIT_LIST_HEAD(&imx_usb->gadget.ep_list);
-	INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list);
-	ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
-
-	/* basic endpoint records init */
-	for (i = 0; i < IMX_USB_NB_EP; i++) {
-		imx_ep = &imx_usb->imx_ep[i];
-
-		if (i) {
-			list_add_tail(&imx_ep->ep.ep_list,
-				&imx_usb->gadget.ep_list);
-			imx_ep->stopped = 1;
-		} else
-			imx_ep->stopped = 0;
-
-		INIT_LIST_HEAD(&imx_ep->queue);
-	}
-}
-
-static void udc_stop_activity(struct imx_udc_struct *imx_usb,
-					struct usb_gadget_driver *driver)
-{
-	struct imx_ep_struct *imx_ep;
-	int i;
-
-	if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
-		driver = NULL;
-
-	/* prevent new request submissions, kill any outstanding requests  */
-	for (i = 1; i < IMX_USB_NB_EP; i++) {
-		imx_ep = &imx_usb->imx_ep[i];
-		imx_flush(imx_ep);
-		imx_ep->stopped = 1;
-		imx_ep_irq_disable(imx_ep);
-		nuke(imx_ep, -ESHUTDOWN);
-	}
-
-	imx_usb->cfg = 0;
-	imx_usb->intf = 0;
-	imx_usb->alt = 0;
-
-	if (driver)
-		driver->disconnect(&imx_usb->gadget);
-}
-
-/*******************************************************************************
- * Interrupt handlers
- *******************************************************************************
- */
-
-/*
- * Called when timer expires.
- * Timer is started when CFG_CHG is received.
- */
-static void handle_config(unsigned long data)
-{
-	struct imx_udc_struct *imx_usb = (void *)data;
-	struct usb_ctrlrequest u;
-	int temp, cfg, intf, alt;
-
-	local_irq_disable();
-
-	temp = __raw_readl(imx_usb->base + USB_STAT);
-	cfg  = (temp & STAT_CFG) >> 5;
-	intf = (temp & STAT_INTF) >> 3;
-	alt  =  temp & STAT_ALTSET;
-
-	D_REQ(imx_usb->dev,
-		"<%s> orig config C=%d, I=%d, A=%d / "
-		"req config C=%d, I=%d, A=%d\n",
-		__func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt,
-		cfg, intf, alt);
-
-	if (cfg == 1 || cfg == 2) {
-
-		if (imx_usb->cfg != cfg) {
-			u.bRequest = USB_REQ_SET_CONFIGURATION;
-			u.bRequestType = USB_DIR_OUT |
-					USB_TYPE_STANDARD |
-					USB_RECIP_DEVICE;
-			u.wValue = cfg;
-			u.wIndex = 0;
-			u.wLength = 0;
-			imx_usb->cfg = cfg;
-			imx_usb->driver->setup(&imx_usb->gadget, &u);
-
-		}
-		if (imx_usb->intf != intf || imx_usb->alt != alt) {
-			u.bRequest = USB_REQ_SET_INTERFACE;
-			u.bRequestType = USB_DIR_OUT |
-					  USB_TYPE_STANDARD |
-					  USB_RECIP_INTERFACE;
-			u.wValue = alt;
-			u.wIndex = intf;
-			u.wLength = 0;
-			imx_usb->intf = intf;
-			imx_usb->alt = alt;
-			imx_usb->driver->setup(&imx_usb->gadget, &u);
-		}
-	}
-
-	imx_usb->set_config = 0;
-
-	local_irq_enable();
-}
-
-static irqreturn_t imx_udc_irq(int irq, void *dev)
-{
-	struct imx_udc_struct *imx_usb = dev;
-	int intr = __raw_readl(imx_usb->base + USB_INTR);
-	int temp;
-
-	if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START
-			| INTR_RESET_STOP | INTR_CFG_CHG)) {
-				dump_intr(__func__, intr, imx_usb->dev);
-				dump_usb_stat(__func__, imx_usb);
-	}
-
-	if (!imx_usb->driver)
-		goto end_irq;
-
-	if (intr & INTR_SOF) {
-		/* Copy from Freescale BSP.
-		   We must enable SOF intr and set CMDOVER.
-		   Datasheet don't specifiy this action, but it
-		   is done in Freescale BSP, so just copy it.
-		*/
-		if (imx_usb->ep0state == EP0_IDLE) {
-			temp = __raw_readl(imx_usb->base + USB_CTRL);
-			__raw_writel(temp | CTRL_CMDOVER,
-						imx_usb->base + USB_CTRL);
-		}
-	}
-
-	if (intr & INTR_CFG_CHG) {
-		/* A workaround of serious IMX UDC bug.
-		   Handling of CFG_CHG should be delayed for some time, because
-		   IMX does not NACK the host when CFG_CHG interrupt is pending.
-		   There is no time to handle current CFG_CHG
-		   if next CFG_CHG or SETUP packed is send immediately.
-		   We have to clear CFG_CHG, start the timer and
-		   NACK the host by setting CTRL_CMDOVER
-		   if it sends any SETUP packet.
-		   When timer expires, handler is called to handle configuration
-		   changes. While CFG_CHG is not handled (set_config=1),
-		   we must NACK the host to every SETUP packed.
-		   This delay prevents from going out of sync with host.
-		 */
-		__raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR);
-		imx_usb->set_config = 1;
-		mod_timer(&imx_usb->timer, jiffies + 5);
-		goto end_irq;
-	}
-
-	if (intr & INTR_WAKEUP) {
-		if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN
-			&& imx_usb->driver && imx_usb->driver->resume)
-				imx_usb->driver->resume(&imx_usb->gadget);
-		imx_usb->set_config = 0;
-		del_timer(&imx_usb->timer);
-		imx_usb->gadget.speed = USB_SPEED_FULL;
-	}
-
-	if (intr & INTR_SUSPEND) {
-		if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN
-			&& imx_usb->driver && imx_usb->driver->suspend)
-				imx_usb->driver->suspend(&imx_usb->gadget);
-		imx_usb->set_config = 0;
-		del_timer(&imx_usb->timer);
-		imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-	}
-
-	if (intr & INTR_RESET_START) {
-		__raw_writel(intr, imx_usb->base + USB_INTR);
-		udc_stop_activity(imx_usb, imx_usb->driver);
-		imx_usb->set_config = 0;
-		del_timer(&imx_usb->timer);
-		imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
-	}
-
-	if (intr & INTR_RESET_STOP)
-		imx_usb->gadget.speed = USB_SPEED_FULL;
-
-end_irq:
-	__raw_writel(intr, imx_usb->base + USB_INTR);
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
-{
-	struct imx_udc_struct *imx_usb = dev;
-	struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
-	int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0));
-
-	dump_ep_intr(__func__, 0, intr, imx_usb->dev);
-
-	if (!imx_usb->driver) {
-		__raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
-		return IRQ_HANDLED;
-	}
-
-	/* DEVREQ has highest priority */
-	if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ))
-		handle_ep0_devreq(imx_usb);
-	/* Seem i.MX is missing EOF interrupt sometimes.
-	 * Therefore we don't monitor EOF.
-	 * We call handle_ep0() only if a request is queued for ep0.
-	 */
-	else if (!list_empty(&imx_ep->queue))
-		handle_ep0(imx_ep);
-
-	__raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
-
-	return IRQ_HANDLED;
-}
-
-#ifndef MX1_INT_USBD0
-#define MX1_INT_USBD0 MX1_USBD_INT0
-#endif
-
-static irqreturn_t imx_udc_bulk_irq(int irq, void *dev)
-{
-	struct imx_udc_struct *imx_usb = dev;
-	struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0];
-	int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-
-	dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev);
-
-	if (!imx_usb->driver) {
-		__raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-		return IRQ_HANDLED;
-	}
-
-	handle_ep(imx_ep);
-
-	__raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
-
-	return IRQ_HANDLED;
-}
-
-irq_handler_t intr_handler(int i)
-{
-	switch (i) {
-	case 0:
-		return imx_udc_ctrl_irq;
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-		return imx_udc_bulk_irq;
-	default:
-		return imx_udc_irq;
-	}
-}
-
-/*******************************************************************************
- * Static defined IMX UDC structure
- *******************************************************************************
- */
-
-static int imx_udc_start(struct usb_gadget *gadget,
-		struct usb_gadget_driver *driver);
-static int imx_udc_stop(struct usb_gadget *gadget,
-		struct usb_gadget_driver *driver);
-static const struct usb_gadget_ops imx_udc_ops = {
-	.get_frame	= imx_udc_get_frame,
-	.wakeup		= imx_udc_wakeup,
-	.udc_start	= imx_udc_start,
-	.udc_stop	= imx_udc_stop,
-};
-
-static struct imx_udc_struct controller = {
-	.gadget = {
-		.ops		= &imx_udc_ops,
-		.ep0		= &controller.imx_ep[0].ep,
-		.name		= driver_name,
-		.dev = {
-			.init_name	= "gadget",
-		},
-	},
-
-	.imx_ep[0] = {
-		.ep = {
-			.name		= ep0name,
-			.ops		= &imx_ep_ops,
-			.maxpacket	= 32,
-		},
-		.imx_usb		= &controller,
-		.fifosize		= 32,
-		.bEndpointAddress	= 0,
-		.bmAttributes		= USB_ENDPOINT_XFER_CONTROL,
-	 },
-	.imx_ep[1] = {
-		.ep = {
-			.name		= "ep1in-bulk",
-			.ops		= &imx_ep_ops,
-			.maxpacket	= 64,
-		},
-		.imx_usb		= &controller,
-		.fifosize		= 64,
-		.bEndpointAddress	= USB_DIR_IN | 1,
-		.bmAttributes		= USB_ENDPOINT_XFER_BULK,
-	 },
-	.imx_ep[2] = {
-		.ep = {
-			.name		= "ep2out-bulk",
-			.ops		= &imx_ep_ops,
-			.maxpacket	= 64,
-		},
-		.imx_usb		= &controller,
-		.fifosize		= 64,
-		.bEndpointAddress	= USB_DIR_OUT | 2,
-		.bmAttributes		= USB_ENDPOINT_XFER_BULK,
-	 },
-	.imx_ep[3] = {
-		.ep = {
-			.name		= "ep3out-bulk",
-			.ops		= &imx_ep_ops,
-			.maxpacket	= 32,
-		},
-		.imx_usb		= &controller,
-		.fifosize		= 32,
-		.bEndpointAddress 	= USB_DIR_OUT | 3,
-		.bmAttributes		= USB_ENDPOINT_XFER_BULK,
-	 },
-	.imx_ep[4] = {
-		.ep = {
-			.name		= "ep4in-int",
-			.ops		= &imx_ep_ops,
-			.maxpacket	= 32,
-		 },
-		.imx_usb		= &controller,
-		.fifosize		= 32,
-		.bEndpointAddress 	= USB_DIR_IN | 4,
-		.bmAttributes		= USB_ENDPOINT_XFER_INT,
-	 },
-	.imx_ep[5] = {
-		.ep = {
-			.name		= "ep5out-int",
-			.ops		= &imx_ep_ops,
-			.maxpacket	= 32,
-		},
-		.imx_usb		= &controller,
-		.fifosize		= 32,
-		.bEndpointAddress 	= USB_DIR_OUT | 5,
-		.bmAttributes		= USB_ENDPOINT_XFER_INT,
-	 },
-};
-
-/*******************************************************************************
- * USB gadget driver functions
- *******************************************************************************
- */
-static int imx_udc_start(struct usb_gadget *gadget,
-		struct usb_gadget_driver *driver)
-{
-	struct imx_udc_struct *imx_usb;
-
-	imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
-	/* first hook up the driver ... */
-	imx_usb->driver = driver;
-
-	D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
-		__func__, driver->driver.name);
-
-	imx_udc_enable(imx_usb);
-
-	return 0;
-}
-
-static int imx_udc_stop(struct usb_gadget *gadget,
-		struct usb_gadget_driver *driver)
-{
-	struct imx_udc_struct *imx_usb = container_of(gadget,
-			struct imx_udc_struct, gadget);
-
-	udc_stop_activity(imx_usb, driver);
-	imx_udc_disable(imx_usb);
-	del_timer(&imx_usb->timer);
-
-	imx_usb->driver = NULL;
-
-	D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
-		__func__, driver->driver.name);
-
-	return 0;
-}
-
-/*******************************************************************************
- * Module functions
- *******************************************************************************
- */
-
-static int __init imx_udc_probe(struct platform_device *pdev)
-{
-	struct imx_udc_struct *imx_usb = &controller;
-	struct resource *res;
-	struct imxusb_platform_data *pdata;
-	struct clk *clk;
-	void __iomem *base;
-	int ret = 0;
-	int i;
-	resource_size_t res_size;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "can't get device resources\n");
-		return -ENODEV;
-	}
-
-	pdata = pdev->dev.platform_data;
-	if (!pdata) {
-		dev_err(&pdev->dev, "driver needs platform data\n");
-		return -ENODEV;
-	}
-
-	res_size = resource_size(res);
-	if (!request_mem_region(res->start, res_size, res->name)) {
-		dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
-			res_size, res->start);
-		return -ENOMEM;
-	}
-
-	if (pdata->init) {
-		ret = pdata->init(&pdev->dev);
-		if (ret)
-			goto fail0;
-	}
-
-	base = ioremap(res->start, res_size);
-	if (!base) {
-		dev_err(&pdev->dev, "ioremap failed\n");
-		ret = -EIO;
-		goto fail1;
-	}
-
-	clk = clk_get(NULL, "usbd_clk");
-	if (IS_ERR(clk)) {
-		ret = PTR_ERR(clk);
-		dev_err(&pdev->dev, "can't get USB clock\n");
-		goto fail2;
-	}
-	clk_prepare_enable(clk);
-
-	if (clk_get_rate(clk) != 48000000) {
-		D_INI(&pdev->dev,
-			"Bad USB clock (%d Hz), changing to 48000000 Hz\n",
-			(int)clk_get_rate(clk));
-		if (clk_set_rate(clk, 48000000)) {
-			dev_err(&pdev->dev,
-				"Unable to set correct USB clock (48MHz)\n");
-			ret = -EIO;
-			goto fail3;
-		}
-	}
-
-	for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
-		imx_usb->usbd_int[i] = platform_get_irq(pdev, i);
-		if (imx_usb->usbd_int[i] < 0) {
-			dev_err(&pdev->dev, "can't get irq number\n");
-			ret = -ENODEV;
-			goto fail3;
-		}
-	}
-
-	for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
-		ret = request_irq(imx_usb->usbd_int[i], intr_handler(i),
-				     0, driver_name, imx_usb);
-		if (ret) {
-			dev_err(&pdev->dev, "can't get irq %i, err %d\n",
-				imx_usb->usbd_int[i], ret);
-			for (--i; i >= 0; i--)
-				free_irq(imx_usb->usbd_int[i], imx_usb);
-			goto fail3;
-		}
-	}
-
-	imx_usb->res = res;
-	imx_usb->base = base;
-	imx_usb->clk = clk;
-	imx_usb->dev = &pdev->dev;
-
-	platform_set_drvdata(pdev, imx_usb);
-
-	usb_init_data(imx_usb);
-	imx_udc_init(imx_usb);
-
-	init_timer(&imx_usb->timer);
-	imx_usb->timer.function = handle_config;
-	imx_usb->timer.data = (unsigned long)imx_usb;
-
-	ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
-	if (ret)
-		goto fail4;
-
-	return 0;
-fail4:
-	for (i = 0; i < IMX_USB_NB_EP + 1; i++)
-		free_irq(imx_usb->usbd_int[i], imx_usb);
-fail3:
-	clk_put(clk);
-	clk_disable_unprepare(clk);
-fail2:
-	iounmap(base);
-fail1:
-	if (pdata->exit)
-		pdata->exit(&pdev->dev);
-fail0:
-	release_mem_region(res->start, res_size);
-	return ret;
-}
-
-static int __exit imx_udc_remove(struct platform_device *pdev)
-{
-	struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev);
-	struct imxusb_platform_data *pdata = pdev->dev.platform_data;
-	int i;
-
-	usb_del_gadget_udc(&imx_usb->gadget);
-	imx_udc_disable(imx_usb);
-	del_timer(&imx_usb->timer);
-
-	for (i = 0; i < IMX_USB_NB_EP + 1; i++)
-		free_irq(imx_usb->usbd_int[i], imx_usb);
-
-	clk_put(imx_usb->clk);
-	clk_disable_unprepare(imx_usb->clk);
-	iounmap(imx_usb->base);
-
-	release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
-
-	if (pdata->exit)
-		pdata->exit(&pdev->dev);
-
-	return 0;
-}
-
-/*----------------------------------------------------------------------------*/
-
-#ifdef	CONFIG_PM
-#define	imx_udc_suspend	NULL
-#define	imx_udc_resume	NULL
-#else
-#define	imx_udc_suspend	NULL
-#define	imx_udc_resume	NULL
-#endif
-
-/*----------------------------------------------------------------------------*/
-
-static struct platform_driver udc_driver = {
-	.driver		= {
-		.name	= driver_name,
-		.owner	= THIS_MODULE,
-	},
-	.remove		= __exit_p(imx_udc_remove),
-	.suspend	= imx_udc_suspend,
-	.resume		= imx_udc_resume,
-};
-
-module_platform_driver_probe(udc_driver, imx_udc_probe);
-
-MODULE_DESCRIPTION("IMX USB Device Controller driver");
-MODULE_AUTHOR("Darius Augulis <augulis.darius@gmail.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx_udc");
diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h
deleted file mode 100644
index d118fb7..0000000
--- a/drivers/usb/gadget/imx_udc.h
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- *	Copyright (C) 2005 Mike Lee(eemike@gmail.com)
- *
- *	This udc driver is now under testing and code is based on pxa2xx_udc.h
- *	Please use it with your own risk!
- *
- *	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 __LINUX_USB_GADGET_IMX_H
-#define __LINUX_USB_GADGET_IMX_H
-
-#include <linux/types.h>
-
-/* Helper macros */
-#define EP_NO(ep)	((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
-#define EP_DIR(ep)	((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
-#define IMX_USB_NB_EP	6
-
-/* Driver structures */
-struct imx_request {
-	struct usb_request			req;
-	struct list_head			queue;
-	unsigned int				in_use;
-};
-
-enum ep0_state {
-	EP0_IDLE,
-	EP0_IN_DATA_PHASE,
-	EP0_OUT_DATA_PHASE,
-	EP0_CONFIG,
-	EP0_STALL,
-};
-
-struct imx_ep_struct {
-	struct usb_ep				ep;
-	struct imx_udc_struct			*imx_usb;
-	struct list_head			queue;
-	unsigned char				stopped;
-	unsigned char				fifosize;
-	unsigned char				bEndpointAddress;
-	unsigned char				bmAttributes;
-};
-
-struct imx_udc_struct {
-	struct usb_gadget			gadget;
-	struct usb_gadget_driver		*driver;
-	struct device				*dev;
-	struct imx_ep_struct			imx_ep[IMX_USB_NB_EP];
-	struct clk				*clk;
-	struct timer_list			timer;
-	enum ep0_state				ep0state;
-	struct resource				*res;
-	void __iomem				*base;
-	unsigned char				set_config;
-	int					cfg,
-						intf,
-						alt,
-						usbd_int[7];
-};
-
-/* USB registers */
-#define  USB_FRAME		(0x00)	/* USB frame */
-#define  USB_SPEC		(0x04)	/* USB Spec */
-#define  USB_STAT		(0x08)	/* USB Status */
-#define  USB_CTRL		(0x0C)	/* USB Control */
-#define  USB_DADR		(0x10)	/* USB Desc RAM addr */
-#define  USB_DDAT		(0x14)	/* USB Desc RAM/EP buffer data */
-#define  USB_INTR		(0x18)	/* USB interrupt */
-#define  USB_MASK		(0x1C)	/* USB Mask */
-#define  USB_ENAB		(0x24)	/* USB Enable */
-#define  USB_EP_STAT(x)		(0x30 + (x*0x30)) /* USB status/control */
-#define  USB_EP_INTR(x)		(0x34 + (x*0x30)) /* USB interrupt */
-#define  USB_EP_MASK(x)		(0x38 + (x*0x30)) /* USB mask */
-#define  USB_EP_FDAT(x)		(0x3C + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT0(x)	(0x3C + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT1(x)	(0x3D + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT2(x)	(0x3E + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FDAT3(x)	(0x3F + (x*0x30)) /* USB FIFO data */
-#define  USB_EP_FSTAT(x)	(0x40 + (x*0x30)) /* USB FIFO status */
-#define  USB_EP_FCTRL(x)	(0x44 + (x*0x30)) /* USB FIFO control */
-#define  USB_EP_LRFP(x)		(0x48 + (x*0x30)) /* USB last rd f. pointer */
-#define  USB_EP_LWFP(x)		(0x4C + (x*0x30)) /* USB last wr f. pointer */
-#define  USB_EP_FALRM(x)	(0x50 + (x*0x30)) /* USB FIFO alarm */
-#define  USB_EP_FRDP(x)		(0x54 + (x*0x30)) /* USB FIFO read pointer */
-#define  USB_EP_FWRP(x)		(0x58 + (x*0x30)) /* USB FIFO write pointer */
-/* USB Control Register Bit Fields.*/
-#define CTRL_CMDOVER		(1<<6)	/* UDC status */
-#define CTRL_CMDERROR		(1<<5)	/* UDC status */
-#define CTRL_FE_ENA		(1<<3)	/* Enable Font End logic */
-#define CTRL_UDC_RST		(1<<2)	/* UDC reset */
-#define CTRL_AFE_ENA		(1<<1)	/* Analog Font end enable */
-#define CTRL_RESUME		(1<<0)	/* UDC resume */
-/* USB Status Register Bit Fields.*/
-#define STAT_RST		(1<<8)
-#define STAT_SUSP		(1<<7)
-#define STAT_CFG		(3<<5)
-#define STAT_INTF		(3<<3)
-#define STAT_ALTSET		(7<<0)
-/* USB Interrupt Status/Mask Registers Bit fields */
-#define INTR_WAKEUP		(1<<31)	/* Wake up Interrupt */
-#define INTR_MSOF		(1<<7)	/* Missed Start of Frame */
-#define INTR_SOF		(1<<6)	/* Start of Frame */
-#define INTR_RESET_STOP		(1<<5)	/* Reset Signaling stop */
-#define INTR_RESET_START	(1<<4)	/* Reset Signaling start */
-#define INTR_RESUME		(1<<3)	/* Suspend to resume */
-#define INTR_SUSPEND		(1<<2)	/* Active to suspend */
-#define INTR_FRAME_MATCH	(1<<1)	/* Frame matched */
-#define INTR_CFG_CHG		(1<<0)	/* Configuration change occurred */
-/* USB Enable Register Bit Fields.*/
-#define ENAB_RST		(1<<31)	/* Reset USB modules */
-#define ENAB_ENAB		(1<<30)	/* Enable USB modules*/
-#define ENAB_SUSPEND		(1<<29)	/* Suspend USB modules */
-#define ENAB_ENDIAN		(1<<28)	/* Endian of USB modules */
-#define ENAB_PWRMD		(1<<0)	/* Power mode of USB modules */
-/* USB Descriptor Ram Address Register bit fields */
-#define DADR_CFG		(1<<31)	/* Configuration */
-#define DADR_BSY		(1<<30)	/* Busy status */
-#define DADR_DADR		(0x1FF)	/* Descriptor Ram Address */
-/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */
-#define DDAT_DDAT		(0xFF)	/* Descriptor Endpoint Buffer */
-/* USB Endpoint Status Register bit fields */
-#define EPSTAT_BCOUNT		(0x7F<<16)	/* Endpoint FIFO byte count */
-#define EPSTAT_SIP		(1<<8)	/* Endpoint setup in progress */
-#define EPSTAT_DIR		(1<<7)	/* Endpoint transfer direction */
-#define EPSTAT_MAX		(3<<5)	/* Endpoint Max packet size */
-#define EPSTAT_TYP		(3<<3)	/* Endpoint type */
-#define EPSTAT_ZLPS		(1<<2)	/* Send zero length packet */
-#define EPSTAT_FLUSH		(1<<1)	/* Endpoint FIFO Flush */
-#define EPSTAT_STALL		(1<<0)	/* Force stall */
-/* USB Endpoint FIFO Status Register bit fields */
-#define FSTAT_FRAME_STAT	(0xF<<24)	/* Frame status bit [0-3] */
-#define FSTAT_ERR		(1<<22)	/* FIFO error */
-#define FSTAT_UF		(1<<21)	/* FIFO underflow */
-#define FSTAT_OF		(1<<20)	/* FIFO overflow */
-#define FSTAT_FR		(1<<19)	/* FIFO frame ready */
-#define FSTAT_FULL		(1<<18)	/* FIFO full */
-#define FSTAT_ALRM		(1<<17)	/* FIFO alarm */
-#define FSTAT_EMPTY		(1<<16)	/* FIFO empty */
-/* USB Endpoint FIFO Control Register bit fields */
-#define FCTRL_WFR		(1<<29)	/* Write frame end */
-/* USB Endpoint Interrupt Status Regsiter bit fields */
-#define EPINTR_FIFO_FULL	(1<<8)	/* fifo full */
-#define EPINTR_FIFO_EMPTY	(1<<7)	/* fifo empty */
-#define EPINTR_FIFO_ERROR	(1<<6)	/* fifo error */
-#define EPINTR_FIFO_HIGH	(1<<5)	/* fifo high */
-#define EPINTR_FIFO_LOW		(1<<4)	/* fifo low */
-#define EPINTR_MDEVREQ		(1<<3)	/* multi Device request */
-#define EPINTR_EOT		(1<<2)	/* fifo end of transfer */
-#define EPINTR_DEVREQ		(1<<1)	/* Device request */
-#define EPINTR_EOF		(1<<0)	/* fifo end of frame */
-
-/* Debug macros */
-#ifdef DEBUG
-
-/* #define DEBUG_REQ */
-/* #define DEBUG_TRX */
-/* #define DEBUG_INIT */
-/* #define DEBUG_EP0 */
-/* #define DEBUG_EPX */
-/* #define DEBUG_IRQ */
-/* #define DEBUG_EPIRQ */
-/* #define DEBUG_DUMP */
-/* #define DEBUG_ERR */
-
-#ifdef DEBUG_REQ
-	#define D_REQ(dev, args...)	dev_dbg(dev, ## args)
-#else
-	#define D_REQ(dev, args...)	do {} while (0)
-#endif /* DEBUG_REQ */
-
-#ifdef DEBUG_TRX
-	#define D_TRX(dev, args...)	dev_dbg(dev, ## args)
-#else
-	#define D_TRX(dev, args...)	do {} while (0)
-#endif /* DEBUG_TRX */
-
-#ifdef DEBUG_INIT
-	#define D_INI(dev, args...)	dev_dbg(dev, ## args)
-#else
-	#define D_INI(dev, args...)	do {} while (0)
-#endif /* DEBUG_INIT */
-
-#ifdef DEBUG_EP0
-	static const char *state_name[] = {
-		"EP0_IDLE",
-		"EP0_IN_DATA_PHASE",
-		"EP0_OUT_DATA_PHASE",
-		"EP0_CONFIG",
-		"EP0_STALL"
-	};
-	#define D_EP0(dev, args...)	dev_dbg(dev, ## args)
-#else
-	#define D_EP0(dev, args...)	do {} while (0)
-#endif /* DEBUG_EP0 */
-
-#ifdef DEBUG_EPX
-	#define D_EPX(dev, args...)	dev_dbg(dev, ## args)
-#else
-	#define D_EPX(dev, args...)	do {} while (0)
-#endif /* DEBUG_EP0 */
-
-#ifdef DEBUG_IRQ
-	static void dump_intr(const char *label, int irqreg, struct device *dev)
-	{
-		dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label,
-			(irqreg & INTR_WAKEUP) ? " wake" : "",
-			(irqreg & INTR_MSOF) ? " msof" : "",
-			(irqreg & INTR_SOF) ? " sof" : "",
-			(irqreg & INTR_RESUME) ? " resume" : "",
-			(irqreg & INTR_SUSPEND) ? " suspend" : "",
-			(irqreg & INTR_RESET_STOP) ? " noreset" : "",
-			(irqreg & INTR_RESET_START) ? " reset" : "",
-			(irqreg & INTR_FRAME_MATCH) ? " fmatch" : "",
-			(irqreg & INTR_CFG_CHG) ? " config" : "");
-	}
-#else
-	#define dump_intr(x, y, z)		do {} while (0)
-#endif /* DEBUG_IRQ */
-
-#ifdef DEBUG_EPIRQ
-	static void dump_ep_intr(const char *label, int nr, int irqreg,
-							struct device *dev)
-	{
-		dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr,
-			(irqreg & EPINTR_FIFO_FULL) ? " full" : "",
-			(irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "",
-			(irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "",
-			(irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "",
-			(irqreg & EPINTR_FIFO_LOW) ? " flow" : "",
-			(irqreg & EPINTR_MDEVREQ) ? " mreq" : "",
-			(irqreg & EPINTR_EOF) ? " eof" : "",
-			(irqreg & EPINTR_DEVREQ) ? " devreq" : "",
-			(irqreg & EPINTR_EOT) ? " eot" : "");
-	}
-#else
-	#define dump_ep_intr(x, y, z, i)	do {} while (0)
-#endif /* DEBUG_IRQ */
-
-#ifdef DEBUG_DUMP
-	static void dump_usb_stat(const char *label,
-						struct imx_udc_struct *imx_usb)
-	{
-		int temp = __raw_readl(imx_usb->base + USB_STAT);
-
-		dev_dbg(imx_usb->dev,
-			"<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label,
-			(temp & STAT_RST) ? " reset" : "",
-			(temp & STAT_SUSP) ? " suspend" : "",
-			(temp & STAT_CFG) >> 5,
-			(temp & STAT_INTF) >> 3,
-			(temp & STAT_ALTSET));
-	}
-
-	static void dump_ep_stat(const char *label,
-						struct imx_ep_struct *imx_ep)
-	{
-		int temp = __raw_readl(imx_ep->imx_usb->base
-						+ USB_EP_INTR(EP_NO(imx_ep)));
-
-		dev_dbg(imx_ep->imx_usb->dev,
-			"<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n",
-			label, EP_NO(imx_ep),
-			(temp & EPINTR_FIFO_FULL) ? " full" : "",
-			(temp & EPINTR_FIFO_EMPTY) ? " fempty" : "",
-			(temp & EPINTR_FIFO_ERROR) ? " ferr" : "",
-			(temp & EPINTR_FIFO_HIGH) ? " fhigh" : "",
-			(temp & EPINTR_FIFO_LOW) ? " flow" : "",
-			(temp & EPINTR_MDEVREQ) ? " mreq" : "",
-			(temp & EPINTR_EOF) ? " eof" : "",
-			(temp & EPINTR_DEVREQ) ? " devreq" : "",
-			(temp & EPINTR_EOT) ? " eot" : "");
-
-		temp = __raw_readl(imx_ep->imx_usb->base
-						+ USB_EP_STAT(EP_NO(imx_ep)));
-
-		dev_dbg(imx_ep->imx_usb->dev,
-			"<%s> EP%d_STAT=[%s%s bcount=%d]\n",
-			label, EP_NO(imx_ep),
-			(temp & EPSTAT_SIP) ? " sip" : "",
-			(temp & EPSTAT_STALL) ? " stall" : "",
-			(temp & EPSTAT_BCOUNT) >> 16);
-
-		temp = __raw_readl(imx_ep->imx_usb->base
-						+ USB_EP_FSTAT(EP_NO(imx_ep)));
-
-		dev_dbg(imx_ep->imx_usb->dev,
-			"<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n",
-			label, EP_NO(imx_ep),
-			(temp & FSTAT_ERR) ? " ferr" : "",
-			(temp & FSTAT_UF) ? " funder" : "",
-			(temp & FSTAT_OF) ? " fover" : "",
-			(temp & FSTAT_FR) ? " fready" : "",
-			(temp & FSTAT_FULL) ? " ffull" : "",
-			(temp & FSTAT_ALRM) ? " falarm" : "",
-			(temp & FSTAT_EMPTY) ? " fempty" : "");
-	}
-
-	static void dump_req(const char *label, struct imx_ep_struct *imx_ep,
-							struct usb_request *req)
-	{
-		int i;
-
-		if (!req || !req->buf) {
-			dev_dbg(imx_ep->imx_usb->dev,
-					"<%s> req or req buf is free\n", label);
-			return;
-		}
-
-		if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state
-			== EP0_IN_DATA_PHASE)
-			|| (EP_NO(imx_ep) && EP_DIR(imx_ep))) {
-
-			dev_dbg(imx_ep->imx_usb->dev,
-						"<%s> request dump <", label);
-			for (i = 0; i < req->length; i++)
-				printk("%02x-", *((u8 *)req->buf + i));
-			printk(">\n");
-		}
-	}
-
-#else
-	#define dump_ep_stat(x, y)		do {} while (0)
-	#define dump_usb_stat(x, y)		do {} while (0)
-	#define dump_req(x, y, z)		do {} while (0)
-#endif /* DEBUG_DUMP */
-
-#ifdef DEBUG_ERR
-	#define D_ERR(dev, args...)	dev_dbg(dev, ## args)
-#else
-	#define D_ERR(dev, args...)	do {} while (0)
-#endif
-
-#else
-	#define D_REQ(dev, args...)		do {} while (0)
-	#define D_TRX(dev, args...)		do {} while (0)
-	#define D_INI(dev, args...)		do {} while (0)
-	#define D_EP0(dev, args...)		do {} while (0)
-	#define D_EPX(dev, args...)		do {} while (0)
-	#define dump_ep_intr(x, y, z, i)	do {} while (0)
-	#define dump_intr(x, y, z)		do {} while (0)
-	#define dump_ep_stat(x, y)		do {} while (0)
-	#define dump_usb_stat(x, y)		do {} while (0)
-	#define dump_req(x, y, z)		do {} while (0)
-	#define D_ERR(dev, args...)		do {} while (0)
-#endif /* DEBUG */
-
-#endif /* __LINUX_USB_GADGET_IMX_H */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 570c005..465ef8e 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1270,10 +1270,6 @@
 	dev->buf = NULL;
 	put_dev (dev);
 
-	/* other endpoints were all decoupled from this device */
-	spin_lock_irq(&dev->lock);
-	dev->state = STATE_DEV_DISABLED;
-	spin_unlock_irq(&dev->lock);
 	return 0;
 }
 
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 46ba983..d5f050d 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1584,7 +1584,7 @@
 		goto clean_up;
 	}
 
-	if (pdev->dev.platform_data == NULL) {
+	if (dev_get_platdata(&pdev->dev) == NULL) {
 		dev_err(&pdev->dev, "no platform data\n");
 		ret = -ENODEV;
 		goto clean_up;
@@ -1598,7 +1598,7 @@
 		goto clean_up;
 	}
 
-	m66592->pdata = pdev->dev.platform_data;
+	m66592->pdata = dev_get_platdata(&pdev->dev);
 	m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
 
 	spin_lock_init(&m66592->lock);
diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c
index ec6a2d2..bbb6e98 100644
--- a/drivers/usb/gadget/mv_u3d_core.c
+++ b/drivers/usb/gadget/mv_u3d_core.c
@@ -1109,7 +1109,7 @@
 
 static int mv_u3d_enable(struct mv_u3d *u3d)
 {
-	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
 	int retval;
 
 	if (u3d->active)
@@ -1138,7 +1138,7 @@
 
 static void mv_u3d_disable(struct mv_u3d *u3d)
 {
-	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
 	if (u3d->clock_gating && u3d->active) {
 		dev_dbg(u3d->dev, "disable u3d\n");
 		if (pdata->phy_deinit)
@@ -1246,7 +1246,7 @@
 		struct usb_gadget_driver *driver)
 {
 	struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
-	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
 	unsigned long flags;
 
 	if (u3d->driver)
@@ -1277,7 +1277,7 @@
 		struct usb_gadget_driver *driver)
 {
 	struct mv_u3d *u3d = container_of(g, struct mv_u3d, gadget);
-	struct mv_usb_platform_data *pdata = u3d->dev->platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(u3d->dev);
 	unsigned long flags;
 
 	u3d->vbus_valid_detect = 0;
@@ -1794,12 +1794,12 @@
 static int mv_u3d_probe(struct platform_device *dev)
 {
 	struct mv_u3d *u3d = NULL;
-	struct mv_usb_platform_data *pdata = dev->dev.platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(&dev->dev);
 	int retval = 0;
 	struct resource *r;
 	size_t size;
 
-	if (!dev->dev.platform_data) {
+	if (!dev_get_platdata(&dev->dev)) {
 		dev_err(&dev->dev, "missing platform_data\n");
 		retval = -ENODEV;
 		goto err_pdata;
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index c2a5702..104cdbe 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -2100,7 +2100,7 @@
 
 static int mv_udc_probe(struct platform_device *pdev)
 {
-	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct mv_udc *udc;
 	int retval = 0;
 	struct resource *r;
@@ -2118,7 +2118,7 @@
 	}
 
 	udc->done = &release_done;
-	udc->pdata = pdev->dev.platform_data;
+	udc->pdata = dev_get_platdata(&pdev->dev);
 	spin_lock_init(&udc->lock);
 
 	udc->dev = pdev;
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index f1e50a3..bf2bb39 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -1184,7 +1184,7 @@
 /*---------------------------------------------------------------------------*/
 
 static ssize_t
-net2272_show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
+registers_show(struct device *_dev, struct device_attribute *attr, char *buf)
 {
 	struct net2272 *dev;
 	char *next;
@@ -1308,7 +1308,7 @@
 
 	return PAGE_SIZE - size;
 }
-static DEVICE_ATTR(registers, S_IRUGO, net2272_show_registers, NULL);
+static DEVICE_ATTR_RO(registers);
 
 /*---------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index fbd006a..0781bff 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1424,8 +1424,8 @@
  */
 
 /* "function" sysfs attribute */
-static ssize_t
-show_function (struct device *_dev, struct device_attribute *attr, char *buf)
+static ssize_t function_show(struct device *_dev, struct device_attribute *attr,
+			     char *buf)
 {
 	struct net2280	*dev = dev_get_drvdata (_dev);
 
@@ -1435,10 +1435,10 @@
 		return 0;
 	return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
 }
-static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR_RO(function);
 
-static ssize_t net2280_show_registers(struct device *_dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t registers_show(struct device *_dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct net2280		*dev;
 	char			*next;
@@ -1590,10 +1590,10 @@
 
 	return PAGE_SIZE - size;
 }
-static DEVICE_ATTR(registers, S_IRUGO, net2280_show_registers, NULL);
+static DEVICE_ATTR_RO(registers);
 
-static ssize_t
-show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
+static ssize_t queues_show(struct device *_dev, struct device_attribute *attr,
+			   char *buf)
 {
 	struct net2280		*dev;
 	char			*next;
@@ -1690,7 +1690,7 @@
 	spin_unlock_irqrestore (&dev->lock, flags);
 	return PAGE_SIZE - size;
 }
-static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
+static DEVICE_ATTR_RO(queues);
 
 
 #else
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index b8ed74a..83957cc 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2734,7 +2734,7 @@
 	int			hmc;
 	struct usb_phy		*xceiv = NULL;
 	const char		*type = NULL;
-	struct omap_usb_config	*config = pdev->dev.platform_data;
+	struct omap_usb_config	*config = dev_get_platdata(&pdev->dev);
 	struct clk		*dc_clk = NULL;
 	struct clk		*hhc_clk = NULL;
 
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 95c531d..cc92074 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -2117,7 +2117,7 @@
 
 	/* other non-static parts of init */
 	dev->dev = &pdev->dev;
-	dev->mach = pdev->dev.platform_data;
+	dev->mach = dev_get_platdata(&pdev->dev);
 
 	dev->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 41cea95..3c97da7 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -2422,7 +2422,7 @@
 		return udc->irq;
 
 	udc->dev = &pdev->dev;
-	udc->mach = pdev->dev.platform_data;
+	udc->mach = dev_get_platdata(&pdev->dev);
 	udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
 	gpio = udc->mach->gpio_pullup;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index c6af649..68be48d 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1910,7 +1910,7 @@
 
 	spin_lock_init(&r8a66597->lock);
 	platform_set_drvdata(pdev, r8a66597);
-	r8a66597->pdata = pdev->dev.platform_data;
+	r8a66597->pdata = dev_get_platdata(&pdev->dev);
 	r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
 	r8a66597->gadget.ops = &r8a66597_gadget_ops;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 3e3ea72..9575085 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1142,7 +1142,7 @@
 #endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 
-int rndis_init(void)
+static int rndis_init(void)
 {
 	u8 i;
 
@@ -1176,7 +1176,7 @@
 }
 module_init(rndis_init);
 
-void rndis_exit(void)
+static void rndis_exit(void)
 {
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 	u8 i;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index af22f24..d69b36a 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -3450,7 +3451,7 @@
 
 static int s3c_hsotg_probe(struct platform_device *pdev)
 {
-	struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
+	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
 	struct usb_phy *phy;
 	struct device *dev = &pdev->dev;
 	struct s3c_hsotg_ep *eps;
@@ -3469,7 +3470,7 @@
 	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
 	if (IS_ERR(phy)) {
 		/* Fallback for pdata */
-		plat = pdev->dev.platform_data;
+		plat = dev_get_platdata(&pdev->dev);
 		if (!plat) {
 			dev_err(&pdev->dev, "no platform data or transceiver defined\n");
 			return -EPROBE_DEFER;
@@ -3648,10 +3649,19 @@
 #define s3c_hsotg_resume NULL
 #endif
 
+#ifdef CONFIG_OF
+static const struct of_device_id s3c_hsotg_of_ids[] = {
+	{ .compatible = "samsung,s3c6400-hsotg", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids);
+#endif
+
 static struct platform_driver s3c_hsotg_driver = {
 	.driver		= {
 		.name	= "s3c-hsotg",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(s3c_hsotg_of_ids),
 	},
 	.probe		= s3c_hsotg_probe,
 	.remove		= s3c_hsotg_remove,
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index b1f0771..1a1a414 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -1262,7 +1262,7 @@
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct s3c_hsudc *hsudc;
-	struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
+	struct s3c24xx_hsudc_platdata *pd = dev_get_platdata(&pdev->dev);
 	int ret, i;
 
 	hsudc = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsudc) +
@@ -1275,7 +1275,7 @@
 
 	platform_set_drvdata(pdev, dev);
 	hsudc->dev = dev;
-	hsudc->pd = pdev->dev.platform_data;
+	hsudc->pd = dev_get_platdata(&pdev->dev);
 
 	hsudc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
 
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 09c4f70..c72d810 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1809,7 +1809,7 @@
 	}
 
 	spin_lock_init(&udc->lock);
-	udc_info = pdev->dev.platform_data;
+	udc_info = dev_get_platdata(&pdev->dev);
 
 	rsrc_start = S3C2410_PA_USBDEV;
 	rsrc_len   = S3C24XX_SZ_USBDEV;
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index dbce3a9..08a1a32 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -172,7 +172,7 @@
  */
 #define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
 
-#endif /* CONFIG_USB_DEBUG */
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
 
 /* check if fsg_num_buffers is within a valid range */
 static inline int fsg_num_buffers_validate(void)
@@ -547,8 +547,8 @@
 /*-------------------------------------------------------------------------*/
 
 
-static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
-			   char *buf)
+static ssize_t ro_show(struct device *dev, struct device_attribute *attr,
+		       char *buf)
 {
 	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 
@@ -557,16 +557,16 @@
 				  : curlun->initially_ro);
 }
 
-static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
-			      char *buf)
+static ssize_t nofua_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 
 	return sprintf(buf, "%u\n", curlun->nofua);
 }
 
-static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
-			     char *buf)
+static ssize_t file_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
@@ -593,8 +593,8 @@
 }
 
 
-static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
-			    const char *buf, size_t count)
+static ssize_t ro_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
 {
 	ssize_t		rc;
 	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
@@ -623,9 +623,8 @@
 	return rc;
 }
 
-static ssize_t fsg_store_nofua(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
+static ssize_t nofua_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
 {
 	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 	unsigned	nofua;
@@ -644,8 +643,8 @@
 	return count;
 }
 
-static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
-			      const char *buf, size_t count)
+static ssize_t file_store(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
 {
 	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
diff --git a/drivers/usb/gadget/u_uac1.c b/drivers/usb/gadget/u_uac1.c
index c7d460f..7a55fea 100644
--- a/drivers/usb/gadget/u_uac1.c
+++ b/drivers/usb/gadget/u_uac1.c
@@ -191,7 +191,7 @@
 	frames = bytes_to_frames(runtime, count);
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	result = snd_pcm_lib_write(snd->substream, buf, frames);
+	result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames);
 	if (result != frames) {
 		ERROR(card, "Playback error: %d\n", (int)result);
 		set_fs(old_fs);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 13e25f8..59891b1 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -23,6 +23,7 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -105,11 +106,18 @@
 
 /* ------------------------------------------------------------------------- */
 
+static void usb_gadget_state_work(struct work_struct *work)
+{
+	struct usb_gadget	*gadget = work_to_gadget(work);
+
+	sysfs_notify(&gadget->dev.kobj, NULL, "state");
+}
+
 void usb_gadget_set_state(struct usb_gadget *gadget,
 		enum usb_device_state state)
 {
 	gadget->state = state;
-	sysfs_notify(&gadget->dev.kobj, NULL, "state");
+	schedule_work(&gadget->work);
 }
 EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
@@ -196,6 +204,7 @@
 		goto err1;
 
 	dev_set_name(&gadget->dev, "gadget");
+	INIT_WORK(&gadget->work, usb_gadget_state_work);
 	gadget->dev.parent = parent;
 
 #ifdef	CONFIG_HAS_DMA
@@ -315,6 +324,7 @@
 		usb_gadget_remove_driver(udc);
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+	flush_work(&gadget->work);
 	device_unregister(&udc->dev);
 	device_unregister(&gadget->dev);
 }
@@ -460,31 +470,31 @@
 }
 static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
 
-static ssize_t usb_gadget_state_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev);
 	struct usb_gadget	*gadget = udc->gadget;
 
 	return sprintf(buf, "%s\n", usb_state_string(gadget->state));
 }
-static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
+static DEVICE_ATTR_RO(state);
 
 #define USB_UDC_SPEED_ATTR(name, param)					\
-ssize_t usb_udc_##param##_show(struct device *dev,			\
+ssize_t name##_show(struct device *dev,					\
 		struct device_attribute *attr, char *buf)		\
 {									\
 	struct usb_udc *udc = container_of(dev, struct usb_udc, dev);	\
 	return snprintf(buf, PAGE_SIZE, "%s\n",				\
 			usb_speed_string(udc->gadget->param));		\
 }									\
-static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
+static DEVICE_ATTR_RO(name)
 
 static USB_UDC_SPEED_ATTR(current_speed, speed);
 static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
 
 #define USB_UDC_ATTR(name)					\
-ssize_t usb_udc_##name##_show(struct device *dev,		\
+ssize_t name##_show(struct device *dev,				\
 		struct device_attribute *attr, char *buf)	\
 {								\
 	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev); \
@@ -492,7 +502,7 @@
 								\
 	return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name);	\
 }								\
-static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL)
+static DEVICE_ATTR_RO(name)
 
 static USB_UDC_ATTR(is_otg);
 static USB_UDC_ATTR(is_a_peripheral);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index e617047..0bb5d50 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -193,12 +193,16 @@
 
 	mutex_lock(&queue->mutex);
 	ret = vb2_qbuf(&queue->queue, buf);
+	if (ret < 0)
+		goto done;
+
 	spin_lock_irqsave(&queue->irqlock, flags);
 	ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
 	queue->flags &= ~UVC_QUEUE_PAUSED;
 	spin_unlock_irqrestore(&queue->irqlock, flags);
-	mutex_unlock(&queue->mutex);
 
+done:
+	mutex_unlock(&queue->mutex);
 	return ret;
 }
 
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 4263d01..5be0326 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -29,15 +29,6 @@
 config USB_XHCI_PLATFORM
 	tristate
 
-config USB_XHCI_HCD_DEBUGGING
-	bool "Debugging for the xHCI host controller"
-	---help---
-	  Say 'Y' to turn on debugging for the xHCI host controller driver.
-	  This will spew debugging output, even in interrupt context.
-	  This should only be used for debugging xHCI driver bugs.
-
-	  If unsure, say N.
-
 endif # USB_XHCI_HCD
 
 config USB_EHCI_HCD
@@ -113,12 +104,6 @@
 		Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's.
 		If unsure, say N.
 
-config USB_EHCI_BIG_ENDIAN_MMIO
-	bool
-
-config USB_EHCI_BIG_ENDIAN_DESC
-	bool
-
 config XPS_USB_HCD_XILINX
 	bool "Use Xilinx usb host EHCI controller core"
 	depends on (PPC32 || MICROBLAZE)
@@ -148,13 +133,11 @@
 config USB_EHCI_HCD_OMAP
 	tristate "EHCI support for OMAP3 and later chips"
 	depends on ARCH_OMAP
+	select NOP_USB_XCEIV
 	default y
 	---help---
 	  Enables support for the on-chip EHCI controller on
 	  OMAP3 and later chips.
-	  If your system uses a PHY on the USB port, you will need to
-	  enable USB_PHY and the appropriate PHY driver as well. Most
-	  boards need the NOP_USB_XCEIV PHY driver.
 
 config USB_EHCI_HCD_ORION
 	tristate  "Support for Marvell EBU on-chip EHCI USB controller"
@@ -186,7 +169,6 @@
 config USB_EHCI_MSM
 	tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller"
 	depends on ARCH_MSM
-	depends on USB_PHY
 	select USB_EHCI_ROOT_HUB_TT
 	select USB_MSM_OTG
 	---help---
@@ -354,6 +336,18 @@
 	To compile this driver as a module, choose M here: the
 	module will be called fusbh200-hcd.
 
+config USB_FOTG210_HCD
+	tristate "FOTG210 HCD support"
+	depends on USB
+	default N
+	---help---
+	  Faraday FOTG210 is an OTG controller which can be configured as
+	  an USB2.0 host. It is designed to meet USB2.0 EHCI specification
+	  with minor modification.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fotg210-hcd.
+
 config USB_OHCI_HCD
 	tristate "OHCI HCD (USB 1.1) support"
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
@@ -497,20 +491,6 @@
 	  controller.  It is needed for low-speed USB 1.0 device
 	  support.  All CN6XXX based chips with USB are supported.
 
-
-config USB_OHCI_BIG_ENDIAN_DESC
-	bool
-	default n
-
-config USB_OHCI_BIG_ENDIAN_MMIO
-	bool
-	default n
-
-config USB_OHCI_LITTLE_ENDIAN
-	bool
-	default n if STB03xxx || PPC_MPC52xx
-	default y
-
 endif # USB_OHCI_HCD
 
 config USB_UHCI_HCD
@@ -710,3 +690,20 @@
 	  for ehci and ohci.
 
 	  If unsure, say N.
+
+config USB_HCD_TEST_MODE
+	bool "HCD test mode support"
+	---help---
+	  Say 'Y' to enable additional software test modes that may be
+	  supported by the host controller drivers.
+
+	  One such test mode is the Embedded High-speed Host Electrical Test
+	  (EHSET) for EHCI host controller hardware, specifically the "Single
+	  Step Set Feature" test.  Typically this will be enabled for On-the-Go
+	  or embedded hosts that need to undergo USB-IF compliance testing with
+	  the aid of special testing hardware.  In the future, this may expand
+	  to include other tests that require support from a HCD driver.
+
+	  This option is of interest only to developers who need to validate
+	  their USB hardware designs.  It is not needed for normal use.  If
+	  unsure, say N.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index bea7112..50b0041 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -4,6 +4,9 @@
 
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
+# tell define_trace.h where to find the xhci trace header
+CFLAGS_xhci-trace.o := -I$(src)
+
 isp1760-y := isp1760-hcd.o isp1760-if.o
 
 fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
@@ -13,6 +16,7 @@
 
 xhci-hcd-y := xhci.o xhci-mem.o
 xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
+xhci-hcd-y += xhci-trace.o
 xhci-hcd-$(CONFIG_PCI)	+= xhci-pci.o
 
 ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
@@ -58,3 +62,4 @@
 obj-$(CONFIG_USB_HCD_BCMA)	+= bcma-hcd.o
 obj-$(CONFIG_USB_HCD_SSB)	+= ssb-hcd.o
 obj-$(CONFIG_USB_FUSBH200_HCD)	+= fusbh200-hcd.o
+obj-$(CONFIG_USB_FOTG210_HCD)	+= fotg210-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 5429d26..aa5b603 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -18,7 +18,7 @@
 
 /* this file is part of ehci-hcd.c */
 
-#ifdef	DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 
 /* check the values in the HCSPARAMS register
  * (host controller _Structural_ parameters)
@@ -62,7 +62,7 @@
 
 #endif
 
-#ifdef	DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 
 /* check the values in the HCCPARAMS register
  * (host controller _Capability_ parameters)
@@ -101,7 +101,7 @@
 
 #endif
 
-#ifdef	DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 
 static void __maybe_unused
 dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
@@ -301,7 +301,7 @@
 dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
 { return 0; }
 
-#endif	/* DEBUG */
+#endif	/* DEBUG || CONFIG_DYNAMIC_DEBUG */
 
 /* functions have the "wrong" filename when they're output... */
 #define dbg_status(ehci, label, status) { \
@@ -336,7 +336,6 @@
 static int debug_async_open(struct inode *, struct file *);
 static int debug_periodic_open(struct inode *, struct file *);
 static int debug_registers_open(struct inode *, struct file *);
-static int debug_async_open(struct inode *, struct file *);
 
 static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
 static int debug_close(struct inode *, struct file *);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index bd831ec..947b009 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -57,7 +57,7 @@
 	pr_debug("initializing FSL-SOC USB Controller\n");
 
 	/* Need platform data for setup */
-	pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+	pdata = (struct fsl_usb2_platform_data *)dev_get_platdata(&pdev->dev);
 	if (!pdata) {
 		dev_err(&pdev->dev,
 			"No platform data for %s.\n", dev_name(&pdev->dev));
@@ -190,7 +190,7 @@
 static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 			       struct platform_device *pdev)
 {
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	if (!IS_ERR_OR_NULL(hcd->phy)) {
 		otg_set_host(hcd->phy->otg, NULL);
@@ -218,7 +218,7 @@
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	void __iomem *non_ehci = hcd->regs;
 	struct device *dev = hcd->self.controller;
-	struct fsl_usb2_platform_data *pdata = dev->platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
 
 	if (pdata->controller_ver < 0) {
 		dev_warn(hcd->self.controller, "Could not get controller version\n");
@@ -291,7 +291,7 @@
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
 
-	pdata = hcd->self.controller->platform_data;
+	pdata = dev_get_platdata(hcd->self.controller);
 
 	if (pdata->have_sysif_regs) {
 		/*
@@ -363,7 +363,7 @@
 	struct device *dev;
 
 	dev = hcd->self.controller;
-	pdata = hcd->self.controller->platform_data;
+	pdata = dev_get_platdata(hcd->self.controller);
 	ehci->big_endian_desc = pdata->big_endian_desc;
 	ehci->big_endian_mmio = pdata->big_endian_mmio;
 
@@ -415,10 +415,10 @@
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	struct fsl_usb2_platform_data *pdata = dev->platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
 	u32 tmp;
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 	u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);
 	mode &= USBMODE_CM_MASK;
 	tmp = ehci_readl(ehci, hcd->regs + 0x140);	/* usbcmd */
@@ -484,7 +484,7 @@
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-	struct fsl_usb2_platform_data *pdata = dev->platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);
 	u32 tmp;
 
 	dev_dbg(dev, "suspend=%d already_suspended=%d\n",
@@ -669,7 +669,7 @@
 	 * generic hardware linkage
 	 */
 	.irq = ehci_irq,
-	.flags = HCD_USB2 | HCD_MEMORY,
+	.flags = HCD_USB2 | HCD_MEMORY | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index a77bd8d..b52a66c 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -43,7 +43,7 @@
 	 * generic hardware linkage
 	 */
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
@@ -167,15 +167,6 @@
 }
 
 
-static void ehci_hcd_grlib_shutdown(struct platform_device *op)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(op);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ehci_hcd_grlib_of_match[] = {
 	{
 		.name = "GAISLER_EHCI",
@@ -191,7 +182,7 @@
 static struct platform_driver ehci_grlib_driver = {
 	.probe		= ehci_hcd_grlib_probe,
 	.remove		= ehci_hcd_grlib_remove,
-	.shutdown	= ehci_hcd_grlib_shutdown,
+	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "grlib-ehci",
 		.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 7abf1ce..5d6022f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -440,14 +440,6 @@
 	if (ehci->amd_pll_fix == 1)
 		usb_amd_dev_put();
 
-#ifdef	EHCI_STATS
-	ehci_dbg(ehci, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
-		ehci->stats.normal, ehci->stats.error, ehci->stats.iaa,
-		ehci->stats.lost_iaa);
-	ehci_dbg (ehci, "complete %ld unlink %ld\n",
-		ehci->stats.complete, ehci->stats.unlink);
-#endif
-
 	dbg_status (ehci, "ehci_stop completed",
 		    ehci_readl(ehci, &ehci->regs->status));
 }
@@ -487,6 +479,7 @@
 	ehci->periodic_size = DEFAULT_I_TDPS;
 	INIT_LIST_HEAD(&ehci->async_unlink);
 	INIT_LIST_HEAD(&ehci->async_idle);
+	INIT_LIST_HEAD(&ehci->intr_unlink_wait);
 	INIT_LIST_HEAD(&ehci->intr_unlink);
 	INIT_LIST_HEAD(&ehci->intr_qh_list);
 	INIT_LIST_HEAD(&ehci->cached_itd_list);
@@ -942,7 +935,7 @@
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	unsigned long		flags;
-	struct ehci_qh		*qh, *tmp;
+	struct ehci_qh		*qh;
 
 	/* ASSERT:  any requests/urbs are being unlinked */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
@@ -972,17 +965,13 @@
 		qh->qh_state = QH_STATE_IDLE;
 	switch (qh->qh_state) {
 	case QH_STATE_LINKED:
-	case QH_STATE_COMPLETING:
-		for (tmp = ehci->async->qh_next.qh;
-				tmp && tmp != qh;
-				tmp = tmp->qh_next.qh)
-			continue;
-		/* periodic qh self-unlinks on empty, and a COMPLETING qh
-		 * may already be unlinked.
-		 */
-		if (tmp)
+		WARN_ON(!list_empty(&qh->qtd_list));
+		if (usb_endpoint_type(&ep->desc) != USB_ENDPOINT_XFER_INT)
 			start_unlink_async(ehci, qh);
+		else
+			start_unlink_intr(ehci, qh);
 		/* FALL THROUGH */
+	case QH_STATE_COMPLETING:	/* already in unlinking */
 	case QH_STATE_UNLINK:		/* wait for hw to finish? */
 	case QH_STATE_UNLINK_WAIT:
 idle_timeout:
@@ -1169,7 +1158,7 @@
 	 * generic hardware linkage
 	 */
 	.irq =			ehci_irq,
-	.flags =		HCD_MEMORY | HCD_USB2,
+	.flags =		HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
@@ -1303,7 +1292,7 @@
 		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
 		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
 
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 	ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
 	if (!ehci_debug_root) {
 		retval = -ENOENT;
@@ -1352,7 +1341,7 @@
 	platform_driver_unregister(&PLATFORM_DRIVER);
 clean0:
 #endif
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 	debugfs_remove(ehci_debug_root);
 	ehci_debug_root = NULL;
 err_debug:
@@ -1376,7 +1365,7 @@
 #ifdef PS3_SYSTEM_BUS_DRIVER
 	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
 #endif
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 	debugfs_remove(ehci_debug_root);
 #endif
 	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 6dce375..835fc08 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -183,7 +183,7 @@
 	spin_lock_irq(&ehci->lock);
 
 	/* clear phy low-power mode before changing wakeup flags */
-	if (ehci->has_hostpc) {
+	if (ehci->has_tdi_phy_lpm) {
 		port = HCS_N_PORTS(ehci->hcs_params);
 		while (port--) {
 			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
@@ -211,13 +211,11 @@
 			else
 				t2 |= PORT_WKOC_E | PORT_WKCONN_E;
 		}
-		ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
-				port + 1, t1, t2);
 		ehci_writel(ehci, t2, reg);
 	}
 
 	/* enter phy low-power mode again */
-	if (ehci->has_hostpc) {
+	if (ehci->has_tdi_phy_lpm) {
 		port = HCS_N_PORTS(ehci->hcs_params);
 		while (port--) {
 			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port];
@@ -302,14 +300,12 @@
 		}
 
 		if (t1 != t2) {
-			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
-				port + 1, t1, t2);
 			ehci_writel(ehci, t2, reg);
 			changed = 1;
 		}
 	}
 
-	if (changed && ehci->has_hostpc) {
+	if (changed && ehci->has_tdi_phy_lpm) {
 		spin_unlock_irq(&ehci->lock);
 		msleep(5);	/* 5 ms for HCD to enter low-power mode */
 		spin_lock_irq(&ehci->lock);
@@ -345,6 +341,7 @@
 
 	end_unlink_async(ehci);
 	unlink_empty_async_suspended(ehci);
+	ehci_handle_start_intr_unlinks(ehci);
 	ehci_handle_intr_unlinks(ehci);
 	end_free_itds(ehci);
 
@@ -435,7 +432,7 @@
 		goto shutdown;
 
 	/* clear phy low-power mode before resume */
-	if (ehci->bus_suspended && ehci->has_hostpc) {
+	if (ehci->bus_suspended && ehci->has_tdi_phy_lpm) {
 		i = HCS_N_PORTS(ehci->hcs_params);
 		while (i--) {
 			if (test_bit(i, &ehci->bus_suspended)) {
@@ -482,7 +479,6 @@
 		if (test_bit(i, &resume_needed)) {
 			temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
 			ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
-			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 		}
 	}
 
@@ -711,6 +707,145 @@
 }
 
 /*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
+
+static void usb_ehset_completion(struct urb *urb)
+{
+	struct completion  *done = urb->context;
+
+	complete(done);
+}
+static int submit_single_step_set_feature(
+	struct usb_hcd	*hcd,
+	struct urb	*urb,
+	int		is_setup
+);
+
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+	struct usb_device	*udev,
+	void			*dr,
+	void			*buf,
+	struct completion	*done
+) {
+	struct urb *urb;
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+	struct usb_host_endpoint *ep;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return NULL;
+
+	urb->pipe = usb_rcvctrlpipe(udev, 0);
+	ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+				[usb_pipeendpoint(urb->pipe)];
+	if (!ep) {
+		usb_free_urb(urb);
+		return NULL;
+	}
+
+	urb->ep = ep;
+	urb->dev = udev;
+	urb->setup_packet = (void *)dr;
+	urb->transfer_buffer = buf;
+	urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+	urb->complete = usb_ehset_completion;
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->transfer_flags = URB_DIR_IN;
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	urb->setup_dma = dma_map_single(
+			hcd->self.controller,
+			urb->setup_packet,
+			sizeof(struct usb_ctrlrequest),
+			DMA_TO_DEVICE);
+	urb->transfer_dma = dma_map_single(
+			hcd->self.controller,
+			urb->transfer_buffer,
+			urb->transfer_buffer_length,
+			DMA_FROM_DEVICE);
+	urb->context = done;
+	return urb;
+}
+
+static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+	int retval = -ENOMEM;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
+	struct usb_device *udev;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct usb_device_descriptor *buf;
+	DECLARE_COMPLETION_ONSTACK(done);
+
+	/* Obtain udev of the rhub's child port */
+	udev = usb_hub_find_child(hcd->self.root_hub, port);
+	if (!udev) {
+		ehci_err(ehci, "No device attached to the RootHub\n");
+		return -ENODEV;
+	}
+	buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!dr) {
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	/* Fill Setup packet for GetDescriptor */
+	dr->bRequestType = USB_DIR_IN;
+	dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+	dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+	dr->wIndex = 0;
+	dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+	urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+	if (!urb)
+		goto cleanup;
+
+	/* Submit just the SETUP stage */
+	retval = submit_single_step_set_feature(hcd, urb, 1);
+	if (retval)
+		goto out1;
+	if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+		usb_kill_urb(urb);
+		retval = -ETIMEDOUT;
+		ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
+		goto out1;
+	}
+	msleep(15 * 1000);
+
+	/* Complete remaining DATA and STATUS stages using the same URB */
+	urb->status = -EINPROGRESS;
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	retval = submit_single_step_set_feature(hcd, urb, 0);
+	if (!retval && !wait_for_completion_timeout(&done,
+						msecs_to_jiffies(2000))) {
+		usb_kill_urb(urb);
+		retval = -ETIMEDOUT;
+		ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
+	}
+out1:
+	usb_free_urb(urb);
+cleanup:
+	kfree(dr);
+	kfree(buf);
+	return retval;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+/*-------------------------------------------------------------------------*/
 
 static int ehci_hub_control (
 	struct usb_hcd	*hcd,
@@ -788,7 +923,7 @@
 				goto error;
 
 			/* clear phy low-power mode before resume */
-			if (ehci->has_hostpc) {
+			if (ehci->has_tdi_phy_lpm) {
 				temp1 = ehci_readl(ehci, hostpc_reg);
 				ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
 						hostpc_reg);
@@ -801,6 +936,8 @@
 			ehci_writel(ehci, temp | PORT_RESUME, status_reg);
 			ehci->reset_done[wIndex] = jiffies
 					+ msecs_to_jiffies(20);
+			set_bit(wIndex, &ehci->resuming_ports);
+			usb_hcd_start_port_resume(&hcd->self, wIndex);
 			break;
 		case USB_PORT_FEAT_C_SUSPEND:
 			clear_bit(wIndex, &ehci->port_c_suspend);
@@ -865,11 +1002,11 @@
 			}
 		}
 
-		/* whoever resumes must GetPortStatus to complete it!! */
-		if (temp & PORT_RESUME) {
+		/* no reset or resume pending */
+		if (!ehci->reset_done[wIndex]) {
 
 			/* Remote Wakeup received? */
-			if (!ehci->reset_done[wIndex]) {
+			if (temp & PORT_RESUME) {
 				/* resume signaling for 20 msec */
 				ehci->reset_done[wIndex] = jiffies
 						+ msecs_to_jiffies(20);
@@ -880,38 +1017,34 @@
 						ehci->reset_done[wIndex]);
 			}
 
-			/* resume completed? */
-			else if (time_after_eq(jiffies,
-					ehci->reset_done[wIndex])) {
-				clear_bit(wIndex, &ehci->suspended_ports);
-				set_bit(wIndex, &ehci->port_c_suspend);
-				ehci->reset_done[wIndex] = 0;
-				usb_hcd_end_port_resume(&hcd->self, wIndex);
+		/* reset or resume not yet complete */
+		} else if (!time_after_eq(jiffies, ehci->reset_done[wIndex])) {
+			;	/* wait until it is complete */
 
-				/* stop resume signaling */
-				temp &= ~(PORT_RWC_BITS |
-						PORT_SUSPEND | PORT_RESUME);
-				ehci_writel(ehci, temp, status_reg);
-				clear_bit(wIndex, &ehci->resuming_ports);
-				retval = ehci_handshake(ehci, status_reg,
-					   PORT_RESUME, 0, 2000 /* 2msec */);
-				if (retval != 0) {
-					ehci_err(ehci,
-						"port %d resume error %d\n",
+		/* resume completed */
+		} else if (test_bit(wIndex, &ehci->resuming_ports)) {
+			clear_bit(wIndex, &ehci->suspended_ports);
+			set_bit(wIndex, &ehci->port_c_suspend);
+			ehci->reset_done[wIndex] = 0;
+			usb_hcd_end_port_resume(&hcd->self, wIndex);
+
+			/* stop resume signaling */
+			temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
+			ehci_writel(ehci, temp, status_reg);
+			clear_bit(wIndex, &ehci->resuming_ports);
+			retval = ehci_handshake(ehci, status_reg,
+					PORT_RESUME, 0, 2000 /* 2msec */);
+			if (retval != 0) {
+				ehci_err(ehci, "port %d resume error %d\n",
 						wIndex + 1, retval);
-					goto error;
-				}
-				temp = ehci_readl(ehci, status_reg);
+				goto error;
 			}
-		}
+			temp = ehci_readl(ehci, status_reg);
 
 		/* whoever resets must GetPortStatus to complete it!! */
-		if ((temp & PORT_RESET)
-				&& time_after_eq(jiffies,
-					ehci->reset_done[wIndex])) {
+		} else {
 			status |= USB_PORT_STAT_C_RESET << 16;
 			ehci->reset_done [wIndex] = 0;
-			clear_bit(wIndex, &ehci->resuming_ports);
 
 			/* force reset to complete */
 			ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
@@ -932,11 +1065,6 @@
 					ehci_readl(ehci, status_reg));
 		}
 
-		if (!(temp & (PORT_RESUME|PORT_RESET))) {
-			ehci->reset_done[wIndex] = 0;
-			clear_bit(wIndex, &ehci->resuming_ports);
-		}
-
 		/* transfer dedicated ports to the companion hc */
 		if ((temp & PORT_CONNECT) &&
 				test_bit(wIndex, &ehci->companion_ports)) {
@@ -1032,12 +1160,12 @@
 
 			/* After above check the port must be connected.
 			 * Set appropriate bit thus could put phy into low power
-			 * mode if we have hostpc feature
+			 * mode if we have tdi_phy_lpm feature
 			 */
 			temp &= ~PORT_WKCONN_E;
 			temp |= PORT_WKDISC_E | PORT_WKOC_E;
 			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
-			if (ehci->has_hostpc) {
+			if (ehci->has_tdi_phy_lpm) {
 				spin_unlock_irqrestore(&ehci->lock, flags);
 				msleep(5);/* 5ms for HCD enter low pwr mode */
 				spin_lock_irqsave(&ehci->lock, flags);
@@ -1057,7 +1185,7 @@
 						status_reg);
 			break;
 		case USB_PORT_FEAT_RESET:
-			if (temp & PORT_RESUME)
+			if (temp & (PORT_SUSPEND|PORT_RESUME))
 				goto error;
 			/* line status bits may report this as low speed,
 			 * which can be fine if this root hub has a
@@ -1071,7 +1199,6 @@
 					wIndex + 1);
 				temp |= PORT_OWNER;
 			} else {
-				ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
 				temp |= PORT_RESET;
 				temp &= ~PORT_PE;
 
@@ -1092,6 +1219,15 @@
 		 * about the EHCI-specific stuff.
 		 */
 		case USB_PORT_FEAT_TEST:
+#ifdef CONFIG_USB_HCD_TEST_MODE
+			if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+				spin_unlock_irqrestore(&ehci->lock, flags);
+				retval = ehset_single_step_set_feature(hcd,
+									wIndex);
+				spin_lock_irqsave(&ehci->lock, flags);
+				break;
+			}
+#endif
 			if (!selector || selector > 5)
 				goto error;
 			spin_unlock_irqrestore(&ehci->lock, flags);
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index ef2c3a1..52a7773 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -93,6 +93,7 @@
 	qh->qh_dma = dma;
 	// INIT_LIST_HEAD (&qh->qh_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
+	INIT_LIST_HEAD(&qh->unlink_node);
 
 	/* dummy td enables safe urb queuing */
 	qh->dummy = ehci_qtd_alloc (ehci, flags);
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 915c2db..417c10d 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -96,7 +96,7 @@
 	 * generic hardware linkage
 	 */
 	.irq = ehci_irq,
-	.flags = HCD_MEMORY | HCD_USB2,
+	.flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
@@ -131,7 +131,7 @@
 
 static int mv_ehci_probe(struct platform_device *pdev)
 {
-	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
 	struct ehci_hcd_mv *ehci_mv;
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index e4c34ac..0528dc4 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -49,7 +49,7 @@
 
 static int ehci_mxc_drv_probe(struct platform_device *pdev)
 {
-	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
+	struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct usb_hcd *hcd;
 	struct resource *res;
 	int irq, ret;
@@ -174,7 +174,7 @@
 
 static int ehci_mxc_drv_remove(struct platform_device *pdev)
 {
-	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
+	struct mxc_usbh_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
@@ -184,7 +184,7 @@
 	if (pdata && pdata->exit)
 		pdata->exit(pdev);
 
-	if (pdata->otg)
+	if (pdata && pdata->otg)
 		usb_phy_shutdown(pdata->otg);
 
 	clk_disable_unprepare(priv->usbclk);
@@ -197,20 +197,12 @@
 	return 0;
 }
 
-static void ehci_mxc_drv_shutdown(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
 MODULE_ALIAS("platform:mxc-ehci");
 
 static struct platform_driver ehci_mxc_driver = {
 	.probe = ehci_mxc_drv_probe,
 	.remove = ehci_mxc_drv_remove,
-	.shutdown = ehci_mxc_drv_shutdown,
+	.shutdown = usb_hcd_platform_shutdown,
 	.driver = {
 		   .name = "mxc-ehci",
 	},
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
index 45cc001..ab0397e 100644
--- a/drivers/usb/host/ehci-octeon.c
+++ b/drivers/usb/host/ehci-octeon.c
@@ -51,7 +51,7 @@
 	 * generic hardware linkage
 	 */
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 9bd7dfe..78b01fa 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -100,7 +100,7 @@
 static int ehci_hcd_omap_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct usbhs_omap_platform_data *pdata = dev->platform_data;
+	struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev);
 	struct resource	*res;
 	struct usb_hcd	*hcd;
 	void __iomem *regs;
@@ -119,7 +119,7 @@
 
 	/* For DT boot, get platform data from parent. i.e. usbhshost */
 	if (dev->of_node) {
-		pdata = dev->parent->platform_data;
+		pdata = dev_get_platdata(dev->parent);
 		dev->platform_data = pdata;
 	}
 
@@ -278,14 +278,6 @@
 	return 0;
 }
 
-static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
 static const struct of_device_id omap_ehci_dt_ids[] = {
 	{ .compatible = "ti,ehci-omap" },
 	{ }
@@ -296,7 +288,7 @@
 static struct platform_driver ehci_hcd_omap_driver = {
 	.probe			= ehci_hcd_omap_probe,
 	.remove			= ehci_hcd_omap_remove,
-	.shutdown		= ehci_hcd_omap_shutdown,
+	.shutdown		= usb_hcd_platform_shutdown,
 	/*.suspend		= ehci_hcd_omap_suspend, */
 	/*.resume		= ehci_hcd_omap_resume, */
 	.driver = {
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 1a450aa..d1dfb9d 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -139,7 +139,7 @@
 
 static int ehci_orion_drv_probe(struct platform_device *pdev)
 {
-	struct orion_ehci_data *pd = pdev->dev.platform_data;
+	struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev);
 	const struct mbus_dram_target_info *dram;
 	struct resource *res;
 	struct usb_hcd *hcd;
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 595d210..6bd299e 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -315,53 +315,11 @@
  * Also they depend on separate root hub suspend/resume.
  */
 
-static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
-{
-	return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
-		pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		(pdev->device == 0x1E26 ||
-		 pdev->device == 0x8C2D ||
-		 pdev->device == 0x8C26 ||
-		 pdev->device == 0x9C26);
-}
-
-static void ehci_enable_xhci_companion(void)
-{
-	struct pci_dev		*companion = NULL;
-
-	/* The xHCI and EHCI controllers are not on the same PCI slot */
-	for_each_pci_dev(companion) {
-		if (!usb_is_intel_switchable_xhci(companion))
-			continue;
-		usb_enable_xhci_ports(companion);
-		return;
-	}
-}
-
 static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller);
 
-	/* The BIOS on systems with the Intel Panther Point chipset may or may
-	 * not support xHCI natively.  That means that during system resume, it
-	 * may switch the ports back to EHCI so that users can use their
-	 * keyboard to select a kernel from GRUB after resume from hibernate.
-	 *
-	 * The BIOS is supposed to remember whether the OS had xHCI ports
-	 * enabled before resume, and switch the ports back to xHCI when the
-	 * BIOS/OS semaphore is written, but we all know we can't trust BIOS
-	 * writers.
-	 *
-	 * Unconditionally switch the ports back to xHCI after a system resume.
-	 * We can't tell whether the EHCI or xHCI controller will be resumed
-	 * first, so we have to do the port switchover in both drivers.  Writing
-	 * a '1' to the port switchover registers should have no effect if the
-	 * port was already switched over.
-	 */
-	if (usb_is_intel_switchable_ehci(pdev))
-		ehci_enable_xhci_companion();
-
 	if (ehci_resume(hcd, hibernated) != 0)
 		(void) ehci_pci_reinit(ehci, pdev);
 	return 0;
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 5196d72..f6b790c 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -39,7 +39,7 @@
 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 usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
 
@@ -87,14 +87,14 @@
 	 * use reasonable defaults so platforms don't have to provide these.
 	 * with DT probing on ARM, none of these are set.
 	 */
-	if (!dev->dev.platform_data)
+	if (!dev_get_platdata(&dev->dev))
 		dev->dev.platform_data = &ehci_platform_defaults;
 	if (!dev->dev.dma_mask)
 		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
 	if (!dev->dev.coherent_dma_mask)
 		dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
-	pdata = dev->dev.platform_data;
+	pdata = dev_get_platdata(&dev->dev);
 
 	irq = platform_get_irq(dev, 0);
 	if (irq < 0) {
@@ -148,7 +148,7 @@
 static int ehci_platform_remove(struct platform_device *dev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
-	struct usb_ehci_pdata *pdata = dev->dev.platform_data;
+	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 
 	usb_remove_hcd(hcd);
 	usb_put_hcd(hcd);
@@ -167,7 +167,7 @@
 static int ehci_platform_suspend(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct usb_ehci_pdata *pdata = dev->platform_data;
+	struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
 	struct platform_device *pdev =
 		container_of(dev, struct platform_device, dev);
 	bool do_wakeup = device_may_wakeup(dev);
@@ -184,7 +184,7 @@
 static int ehci_platform_resume(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct usb_ehci_pdata *pdata = dev->platform_data;
+	struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
 	struct platform_device *pdev =
 		container_of(dev, struct platform_device, dev);
 
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index 601e208..893b707 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -286,7 +286,7 @@
 #else
 	.irq =			ehci_irq,
 #endif
-	.flags =		HCD_MEMORY | HCD_USB2,
+	.flags =		HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 86da09c..6cc5567 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -28,7 +28,7 @@
 	 * generic hardware linkage
 	 */
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
@@ -215,15 +215,6 @@
 }
 
 
-static void ehci_hcd_ppc_of_shutdown(struct platform_device *op)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(op);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ehci_hcd_ppc_of_match[] = {
 	{
 		.compatible = "usb-ehci",
@@ -236,7 +227,7 @@
 static struct platform_driver ehci_hcd_ppc_of_driver = {
 	.probe		= ehci_hcd_ppc_of_probe,
 	.remove		= ehci_hcd_ppc_of_remove,
-	.shutdown	= ehci_hcd_ppc_of_shutdown,
+	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "ppc-of-ehci",
 		.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index fd98377..8188542 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -71,7 +71,7 @@
 	.product_desc		= "PS3 EHCI Host Controller",
 	.hcd_priv_size		= sizeof(struct ehci_hcd),
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 	.reset			= ps3_ehci_hc_reset,
 	.start			= ehci_run,
 	.stop			= ehci_stop,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index d34b399..e321804 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -168,13 +168,13 @@
 	 * Note: this routine is never called for Isochronous transfers.
 	 */
 	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 		struct usb_device *tt = urb->dev->tt->hub;
 		dev_dbg(&tt->dev,
 			"clear tt buffer port %d, a%d ep%d t%08x\n",
 			urb->dev->ttport, urb->dev->devnum,
 			usb_pipeendpoint(urb->pipe), token);
-#endif /* DEBUG */
+#endif /* DEBUG || CONFIG_DYNAMIC_DEBUG */
 		if (!ehci_is_TDI(ehci)
 				|| urb->dev->tt->hub !=
 				   ehci_to_hcd(ehci)->self.root_hub) {
@@ -240,13 +240,6 @@
 		} else {	/* unknown */
 			status = -EPROTO;
 		}
-
-		ehci_vdbg (ehci,
-			"dev%d ep%d%s qtd token %08x --> status %d\n",
-			usb_pipedevice (urb->pipe),
-			usb_pipeendpoint (urb->pipe),
-			usb_pipein (urb->pipe) ? "in" : "out",
-			token, status);
 	}
 
 	return status;
@@ -254,8 +247,6 @@
 
 static void
 ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
-__releases(ehci->lock)
-__acquires(ehci->lock)
 {
 	if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
 		/* ... update hc-wide periodic stats */
@@ -281,11 +272,8 @@
 		urb->actual_length, urb->transfer_buffer_length);
 #endif
 
-	/* complete() can reenter this HCD */
 	usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
-	spin_unlock (&ehci->lock);
 	usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
-	spin_lock (&ehci->lock);
 }
 
 static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -1144,6 +1132,109 @@
 }
 
 /*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+/*
+ * This function creates the qtds and submits them for the
+ * SINGLE_STEP_SET_FEATURE Test.
+ * This is done in two parts: first SETUP req for GetDesc is sent then
+ * 15 seconds later, the IN stage for GetDesc starts to req data from dev
+ *
+ * is_setup : i/p arguement decides which of the two stage needs to be
+ * performed; TRUE - SETUP and FALSE - IN+STATUS
+ * Returns 0 if success
+ */
+static int submit_single_step_set_feature(
+	struct usb_hcd  *hcd,
+	struct urb      *urb,
+	int             is_setup
+) {
+	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
+	struct list_head	qtd_list;
+	struct list_head	*head;
+
+	struct ehci_qtd		*qtd, *qtd_prev;
+	dma_addr_t		buf;
+	int			len, maxpacket;
+	u32			token;
+
+	INIT_LIST_HEAD(&qtd_list);
+	head = &qtd_list;
+
+	/* URBs map to sequences of QTDs:  one logical transaction */
+	qtd = ehci_qtd_alloc(ehci, GFP_KERNEL);
+	if (unlikely(!qtd))
+		return -1;
+	list_add_tail(&qtd->qtd_list, head);
+	qtd->urb = urb;
+
+	token = QTD_STS_ACTIVE;
+	token |= (EHCI_TUNE_CERR << 10);
+
+	len = urb->transfer_buffer_length;
+	/*
+	 * Check if the request is to perform just the SETUP stage (getDesc)
+	 * as in SINGLE_STEP_SET_FEATURE test, DATA stage (IN) happens
+	 * 15 secs after the setup
+	 */
+	if (is_setup) {
+		/* SETUP pid */
+		qtd_fill(ehci, qtd, urb->setup_dma,
+				sizeof(struct usb_ctrlrequest),
+				token | (2 /* "setup" */ << 8), 8);
+
+		submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
+		return 0; /*Return now; we shall come back after 15 seconds*/
+	}
+
+	/*
+	 * IN: data transfer stage:  buffer setup : start the IN txn phase for
+	 * the get_Desc SETUP which was sent 15seconds back
+	 */
+	token ^= QTD_TOGGLE;   /*We need to start IN with DATA-1 Pid-sequence*/
+	buf = urb->transfer_dma;
+
+	token |= (1 /* "in" */ << 8);  /*This is IN stage*/
+
+	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, 0));
+
+	qtd_fill(ehci, qtd, buf, len, token, maxpacket);
+
+	/*
+	 * Our IN phase shall always be a short read; so keep the queue running
+	 * and let it advance to the next qtd which zero length OUT status
+	 */
+	qtd->hw_alt_next = EHCI_LIST_END(ehci);
+
+	/* STATUS stage for GetDesc control request */
+	token ^= 0x0100;        /* "in" <--> "out"  */
+	token |= QTD_TOGGLE;    /* force DATA1 */
+
+	qtd_prev = qtd;
+	qtd = ehci_qtd_alloc(ehci, GFP_ATOMIC);
+	if (unlikely(!qtd))
+		goto cleanup;
+	qtd->urb = urb;
+	qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
+	list_add_tail(&qtd->qtd_list, head);
+
+	/* dont fill any data in such packets */
+	qtd_fill(ehci, qtd, 0, 0, token, 0);
+
+	/* by default, enable interrupt on urb completion */
+	if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
+		qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
+
+	submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
+
+	return 0;
+
+cleanup:
+	qtd_list_free(ehci, urb, head);
+	return -1;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
+/*-------------------------------------------------------------------------*/
 
 static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 7cc26e6..7c3de95 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -75,7 +75,7 @@
 
 static int s5p_ehci_probe(struct platform_device *pdev)
 {
-	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+	struct s5p_ehci_platdata *pdata = dev_get_platdata(&pdev->dev);
 	struct s5p_ehci_hcd *s5p_ehci;
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
@@ -220,14 +220,6 @@
 	return 0;
 }
 
-static void s5p_ehci_shutdown(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
 #ifdef CONFIG_PM
 static int s5p_ehci_suspend(struct device *dev)
 {
@@ -297,7 +289,7 @@
 static struct platform_driver s5p_ehci_driver = {
 	.probe		= s5p_ehci_probe,
 	.remove		= s5p_ehci_remove,
-	.shutdown	= s5p_ehci_shutdown,
+	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name	= "s5p-ehci",
 		.owner	= THIS_MODULE,
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 8e3c878..85dd24e 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -169,7 +169,7 @@
 			break;
 		}
 	}
-#ifdef	DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 	if (usecs > ehci->uframe_periodic_max)
 		ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
 			frame * 8 + uframe, usecs);
@@ -327,17 +327,8 @@
 
 		periodic_tt_usecs (ehci, dev, frame, tt_usecs);
 
-		ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in"
-			" schedule %d/%d/%d/%d/%d/%d/%d/%d\n",
-			frame, usecs, uframe,
-			tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3],
-			tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]);
-
-		if (max_tt_usecs[uframe] <= tt_usecs[uframe]) {
-			ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n",
-				frame, uframe);
+		if (max_tt_usecs[uframe] <= tt_usecs[uframe])
 			return 0;
-		}
 
 		/* special case for isoc transfers larger than 125us:
 		 * the first and each subsequent fully used uframe
@@ -348,13 +339,8 @@
 			int ufs = (usecs / 125);
 			int i;
 			for (i = uframe; i < (uframe + ufs) && i < 8; i++)
-				if (0 < tt_usecs[i]) {
-					ehci_vdbg(ehci,
-						"multi-uframe xfer can't fit "
-						"in frame %d uframe %d\n",
-						frame, i);
+				if (0 < tt_usecs[i])
 					return 0;
-				}
 		}
 
 		tt_usecs[uframe] += usecs;
@@ -362,12 +348,8 @@
 		carryover_tt_bandwidth(tt_usecs);
 
 		/* fail if the carryover pushed bw past the last uframe's limit */
-		if (max_tt_usecs[7] < tt_usecs[7]) {
-			ehci_vdbg(ehci,
-				"tt unavailable usecs %d frame %d uframe %d\n",
-				usecs, frame, uframe);
+		if (max_tt_usecs[7] < tt_usecs[7])
 			return 0;
-		}
 	}
 
 	return 1;
@@ -601,12 +583,29 @@
 	list_del(&qh->intr_node);
 }
 
+static void cancel_unlink_wait_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	if (qh->qh_state != QH_STATE_LINKED ||
+			list_empty(&qh->unlink_node))
+		return;
+
+	list_del_init(&qh->unlink_node);
+
+	/*
+	 * TODO: disable the event of EHCI_HRTIMER_START_UNLINK_INTR for
+	 * avoiding unnecessary CPU wakeup
+	 */
+}
+
 static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	/* If the QH isn't linked then there's nothing we can do. */
 	if (qh->qh_state != QH_STATE_LINKED)
 		return;
 
+	/* if the qh is waiting for unlink, cancel it now */
+	cancel_unlink_wait_intr(ehci, qh);
+
 	qh_unlink_periodic (ehci, qh);
 
 	/* Make sure the unlinks are visible before starting the timer */
@@ -632,6 +631,27 @@
 	}
 }
 
+/*
+ * It is common only one intr URB is scheduled on one qh, and
+ * given complete() is run in tasklet context, introduce a bit
+ * delay to avoid unlink qh too early.
+ */
+static void start_unlink_intr_wait(struct ehci_hcd *ehci,
+				   struct ehci_qh *qh)
+{
+	qh->unlink_cycle = ehci->intr_unlink_wait_cycle;
+
+	/* New entries go at the end of the intr_unlink_wait list */
+	list_add_tail(&qh->unlink_node, &ehci->intr_unlink_wait);
+
+	if (ehci->rh_state < EHCI_RH_RUNNING)
+		ehci_handle_start_intr_unlinks(ehci);
+	else if (ehci->intr_unlink_wait.next == &qh->unlink_node) {
+		ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
+		++ehci->intr_unlink_wait_cycle;
+	}
+}
+
 static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	struct ehci_qh_hw	*hw = qh->hw;
@@ -889,6 +909,9 @@
 	if (qh->qh_state == QH_STATE_IDLE) {
 		qh_refresh(ehci, qh);
 		qh_link_periodic(ehci, qh);
+	} else {
+		/* cancel unlink wait for the qh */
+		cancel_unlink_wait_intr(ehci, qh);
 	}
 
 	/* ... update usbfs periodic stats */
@@ -924,9 +947,11 @@
 			 * in qh_unlink_periodic().
 			 */
 			temp = qh_completions(ehci, qh);
-			if (unlikely(temp || (list_empty(&qh->qtd_list) &&
-					qh->qh_state == QH_STATE_LINKED)))
+			if (unlikely(temp))
 				start_unlink_intr(ehci, qh);
+			else if (unlikely(list_empty(&qh->qtd_list) &&
+					qh->qh_state == QH_STATE_LINKED))
+				start_unlink_intr_wait(ehci, qh);
 		}
 	}
 }
@@ -1573,16 +1598,9 @@
 
 	next_uframe = stream->next_uframe & (mod - 1);
 
-	if (unlikely (list_empty(&stream->td_list))) {
+	if (unlikely (list_empty(&stream->td_list)))
 		ehci_to_hcd(ehci)->self.bandwidth_allocated
 				+= stream->bandwidth;
-		ehci_vdbg (ehci,
-			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",
-			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
-			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
-			urb->interval,
-			next_uframe >> 3, next_uframe & 0x7);
-	}
 
 	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
 		if (ehci->amd_pll_fix == 1)
@@ -1717,14 +1735,9 @@
 			usb_amd_quirk_pll_enable();
 	}
 
-	if (unlikely(list_is_singular(&stream->td_list))) {
+	if (unlikely(list_is_singular(&stream->td_list)))
 		ehci_to_hcd(ehci)->self.bandwidth_allocated
 				-= stream->bandwidth;
-		ehci_vdbg (ehci,
-			"deschedule devp %s ep%d%s-iso\n",
-			dev->devpath, stream->bEndpointAddress & 0x0f,
-			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
-	}
 
 done:
 	itd->urb = NULL;
@@ -1982,17 +1995,10 @@
 
 	next_uframe = stream->next_uframe;
 
-	if (list_empty(&stream->td_list)) {
+	if (list_empty(&stream->td_list))
 		/* usbfs ignores TT bandwidth */
 		ehci_to_hcd(ehci)->self.bandwidth_allocated
 				+= stream->bandwidth;
-		ehci_vdbg (ehci,
-			"sched devp %s ep%d%s-iso [%d] %dms/%04x\n",
-			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
-			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
-			(next_uframe >> 3) & (ehci->periodic_size - 1),
-			stream->interval, hc32_to_cpu(ehci, stream->splits));
-	}
 
 	if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
 		if (ehci->amd_pll_fix == 1)
@@ -2106,14 +2112,9 @@
 			usb_amd_quirk_pll_enable();
 	}
 
-	if (list_is_singular(&stream->td_list)) {
+	if (list_is_singular(&stream->td_list))
 		ehci_to_hcd(ehci)->self.bandwidth_allocated
 				-= stream->bandwidth;
-		ehci_vdbg (ehci,
-			"deschedule devp %s ep%d%s-iso\n",
-			dev->devpath, stream->bEndpointAddress & 0x0f,
-			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
-	}
 
 done:
 	sitd->urb = NULL;
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index b2de52d..8a73449 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -55,7 +55,7 @@
 	 * generic hardware linkage
 	 */
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index c4c0ee9..dc899eb 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -36,7 +36,7 @@
 	 * generic hardware linkage
 	 */
 	.irq				= ehci_irq,
-	.flags				= HCD_USB2 | HCD_MEMORY,
+	.flags				= HCD_USB2 | HCD_MEMORY | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
@@ -104,7 +104,7 @@
 		goto fail_create_hcd;
 	}
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 
 	/* initialize hcd */
 	hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 6ee7ef7..78fa76d 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -25,9 +25,9 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/tegra_usb.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/usb/ehci_def.h>
@@ -51,6 +51,10 @@
 
 static struct hc_driver __read_mostly tegra_ehci_hc_driver;
 
+struct tegra_ehci_soc_config {
+	bool has_hostpc;
+};
+
 static int (*orig_hub_control)(struct usb_hcd *hcd,
 				u16 typeReq, u16 wValue, u16 wIndex,
 				char *buf, u16 wLength);
@@ -58,7 +62,6 @@
 struct tegra_ehci_hcd {
 	struct tegra_usb_phy *phy;
 	struct clk *clk;
-	struct usb_phy *transceiver;
 	int port_resuming;
 	bool needs_double_reset;
 	enum tegra_usb_phy_port_speed port_speed;
@@ -322,50 +325,38 @@
 	free_dma_aligned_buffer(urb);
 }
 
-static int setup_vbus_gpio(struct platform_device *pdev,
-			   struct tegra_ehci_platform_data *pdata)
-{
-	int err = 0;
-	int gpio;
+static const struct tegra_ehci_soc_config tegra30_soc_config = {
+	.has_hostpc = true,
+};
 
-	gpio = pdata->vbus_gpio;
-	if (!gpio_is_valid(gpio))
-		gpio = of_get_named_gpio(pdev->dev.of_node,
-					 "nvidia,vbus-gpio", 0);
-	if (!gpio_is_valid(gpio))
-		return 0;
+static const struct tegra_ehci_soc_config tegra20_soc_config = {
+	.has_hostpc = false,
+};
 
-	err = gpio_request(gpio, "vbus_gpio");
-	if (err) {
-		dev_err(&pdev->dev, "can't request vbus gpio %d", gpio);
-		return err;
-	}
-	err = gpio_direction_output(gpio, 1);
-	if (err) {
-		dev_err(&pdev->dev, "can't enable vbus\n");
-		return err;
-	}
-
-	return err;
-}
+static struct of_device_id tegra_ehci_of_match[] = {
+	{ .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config },
+	{ .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config },
+	{ },
+};
 
 static int tegra_ehci_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
+	const struct tegra_ehci_soc_config *soc_config;
 	struct resource *res;
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
 	struct tegra_ehci_hcd *tegra;
-	struct tegra_ehci_platform_data *pdata;
 	int err = 0;
 	int irq;
-	struct device_node *np_phy;
 	struct usb_phy *u_phy;
 
-	pdata = pdev->dev.platform_data;
-	if (!pdata) {
-		dev_err(&pdev->dev, "Platform data missing\n");
-		return -EINVAL;
+	match = of_match_device(tegra_ehci_of_match, &pdev->dev);
+	if (!match) {
+		dev_err(&pdev->dev, "Error: No device match found\n");
+		return -ENODEV;
 	}
+	soc_config = match->data;
 
 	/* Right now device-tree probed devices don't get dma_mask set.
 	 * Since shared usb code relies on it, set it here for now.
@@ -376,14 +367,11 @@
 	if (!pdev->dev.coherent_dma_mask)
 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
-	setup_vbus_gpio(pdev, pdata);
-
 	hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
 					dev_name(&pdev->dev));
 	if (!hcd) {
 		dev_err(&pdev->dev, "Unable to create HCD\n");
-		err = -ENOMEM;
-		goto cleanup_vbus_gpio;
+		return -ENOMEM;
 	}
 	platform_set_drvdata(pdev, hcd);
 	ehci = hcd_to_ehci(hcd);
@@ -406,13 +394,7 @@
 	udelay(1);
 	tegra_periph_reset_deassert(tegra->clk);
 
-	np_phy = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
-	if (!np_phy) {
-		err = -ENODEV;
-		goto cleanup_clk_en;
-	}
-
-	u_phy = tegra_usb_get_phy(np_phy);
+	u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
 	if (IS_ERR(u_phy)) {
 		err = PTR_ERR(u_phy);
 		goto cleanup_clk_en;
@@ -437,6 +419,7 @@
 		goto cleanup_clk_en;
 	}
 	ehci->caps = hcd->regs + 0x100;
+	ehci->has_hostpc = soc_config->has_hostpc;
 
 	err = usb_phy_init(hcd->phy);
 	if (err) {
@@ -466,26 +449,18 @@
 		goto cleanup_phy;
 	}
 
-	if (pdata->operating_mode == TEGRA_USB_OTG) {
-		tegra->transceiver =
-			devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-		if (!IS_ERR(tegra->transceiver))
-			otg_set_host(tegra->transceiver->otg, &hcd->self);
-	} else {
-		tegra->transceiver = ERR_PTR(-ENODEV);
-	}
+	otg_set_host(u_phy->otg, &hcd->self);
 
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to add USB HCD\n");
-		goto cleanup_transceiver;
+		goto cleanup_otg_set_host;
 	}
 
 	return err;
 
-cleanup_transceiver:
-	if (!IS_ERR(tegra->transceiver))
-		otg_set_host(tegra->transceiver->otg, NULL);
+cleanup_otg_set_host:
+	otg_set_host(u_phy->otg, NULL);
 cleanup_phy:
 	usb_phy_shutdown(hcd->phy);
 cleanup_clk_en:
@@ -494,8 +469,6 @@
 	clk_put(tegra->clk);
 cleanup_hcd_create:
 	usb_put_hcd(hcd);
-cleanup_vbus_gpio:
-	/* FIXME: Undo setup_vbus_gpio() here */
 	return err;
 }
 
@@ -505,8 +478,7 @@
 	struct tegra_ehci_hcd *tegra =
 		(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
 
-	if (!IS_ERR(tegra->transceiver))
-		otg_set_host(tegra->transceiver->otg, NULL);
+	otg_set_host(hcd->phy->otg, NULL);
 
 	usb_phy_shutdown(hcd->phy);
 	usb_remove_hcd(hcd);
@@ -525,11 +497,6 @@
 		hcd->driver->shutdown(hcd);
 }
 
-static struct of_device_id tegra_ehci_of_match[] = {
-	{ .compatible = "nvidia,tegra20-ehci", },
-	{ },
-};
-
 static struct platform_driver tegra_ehci_driver = {
 	.probe		= tegra_ehci_probe,
 	.remove		= tegra_ehci_remove,
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c
index d72b292..67026ff 100644
--- a/drivers/usb/host/ehci-tilegx.c
+++ b/drivers/usb/host/ehci-tilegx.c
@@ -61,7 +61,7 @@
 	 * Generic hardware linkage.
 	 */
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * Basic lifecycle operations.
@@ -101,7 +101,7 @@
 {
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
-	struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	pte_t pte = { 0 };
 	int my_cpu = smp_processor_id();
 	int ret;
@@ -186,7 +186,7 @@
 static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-	struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	usb_remove_hcd(hcd);
 	usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 11e5b32..424ac5d 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -72,6 +72,7 @@
 	1 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_POLL_DEAD */
 	1125 * NSEC_PER_USEC,	/* EHCI_HRTIMER_UNLINK_INTR */
 	2 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_FREE_ITDS */
+	5 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_START_UNLINK_INTR */
 	6 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_ASYNC_UNLINKS */
 	10 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_IAA_WATCHDOG */
 	10 * NSEC_PER_MSEC,	/* EHCI_HRTIMER_DISABLE_PERIODIC */
@@ -215,6 +216,36 @@
 	/* Not in process context, so don't try to reset the controller */
 }
 
+/* start to unlink interrupt QHs  */
+static void ehci_handle_start_intr_unlinks(struct ehci_hcd *ehci)
+{
+	bool		stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+
+	/*
+	 * Process all the QHs on the intr_unlink list that were added
+	 * before the current unlink cycle began.  The list is in
+	 * temporal order, so stop when we reach the first entry in the
+	 * current cycle.  But if the root hub isn't running then
+	 * process all the QHs on the list.
+	 */
+	while (!list_empty(&ehci->intr_unlink_wait)) {
+		struct ehci_qh	*qh;
+
+		qh = list_first_entry(&ehci->intr_unlink_wait,
+				struct ehci_qh, unlink_node);
+		if (!stopped && (qh->unlink_cycle ==
+				ehci->intr_unlink_wait_cycle))
+			break;
+		list_del_init(&qh->unlink_node);
+		start_unlink_intr(ehci, qh);
+	}
+
+	/* Handle remaining entries later */
+	if (!list_empty(&ehci->intr_unlink_wait)) {
+		ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
+		++ehci->intr_unlink_wait_cycle;
+	}
+}
 
 /* Handle unlinked interrupt QHs once they are gone from the hardware */
 static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
@@ -236,7 +267,7 @@
 				unlink_node);
 		if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
 			break;
-		list_del(&qh->unlink_node);
+		list_del_init(&qh->unlink_node);
 		end_unlink_intr(ehci, qh);
 	}
 
@@ -363,6 +394,7 @@
 	ehci_handle_controller_death,	/* EHCI_HRTIMER_POLL_DEAD */
 	ehci_handle_intr_unlinks,	/* EHCI_HRTIMER_UNLINK_INTR */
 	end_free_itds,			/* EHCI_HRTIMER_FREE_ITDS */
+	ehci_handle_start_intr_unlinks,	/* EHCI_HRTIMER_START_UNLINK_INTR */
 	unlink_empty_async,		/* EHCI_HRTIMER_ASYNC_UNLINKS */
 	ehci_iaa_watchdog,		/* EHCI_HRTIMER_IAA_WATCHDOG */
 	ehci_disable_PSE,		/* EHCI_HRTIMER_DISABLE_PERIODIC */
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index 59e0e24..1c370df 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -108,7 +108,7 @@
 	 * generic hardware linkage
 	 */
 	.irq = ehci_irq,
-	.flags = HCD_USB2|HCD_MEMORY,
+	.flags = HCD_USB2|HCD_MEMORY|HCD_BH,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 35c7f90..95979f9 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -79,7 +79,7 @@
 	 * generic hardware linkage
 	 */
 	.irq			= ehci_irq,
-	.flags			= HCD_MEMORY | HCD_USB2,
+	.flags			= HCD_MEMORY | HCD_USB2 | HCD_BH,
 
 	/*
 	 * basic lifecycle operations
@@ -220,21 +220,6 @@
 	return 0;
 }
 
-/**
- * ehci_hcd_xilinx_of_shutdown - shutdown the hcd
- * @op:		pointer to platform_device structure that is to be removed
- *
- * Properly shutdown the hcd, call driver's shutdown routine.
- */
-static void ehci_hcd_xilinx_of_shutdown(struct platform_device *op)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(op);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
 		{.compatible = "xlnx,xps-usb-host-1.00.a",},
 	{},
@@ -244,7 +229,7 @@
 static struct platform_driver ehci_hcd_xilinx_of_driver = {
 	.probe		= ehci_hcd_xilinx_of_probe,
 	.remove		= ehci_hcd_xilinx_of_remove,
-	.shutdown	= ehci_hcd_xilinx_of_shutdown,
+	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "xilinx-of-ehci",
 		.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 64f9a08..291db7d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -38,7 +38,7 @@
 #endif
 
 /* statistics can be kept for tuning/monitoring */
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 #define EHCI_STATS
 #endif
 
@@ -88,6 +88,7 @@
 	EHCI_HRTIMER_POLL_DEAD,		/* Wait for dead controller to stop */
 	EHCI_HRTIMER_UNLINK_INTR,	/* Wait for interrupt QH unlink */
 	EHCI_HRTIMER_FREE_ITDS,		/* Wait for unused iTDs and siTDs */
+	EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
 	EHCI_HRTIMER_ASYNC_UNLINKS,	/* Unlink empty async QHs */
 	EHCI_HRTIMER_IAA_WATCHDOG,	/* Handle lost IAA interrupts */
 	EHCI_HRTIMER_DISABLE_PERIODIC,	/* Wait to disable periodic sched */
@@ -143,7 +144,9 @@
 	unsigned		i_thresh;	/* uframes HC might cache */
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
+	struct list_head	intr_unlink_wait;
 	struct list_head	intr_unlink;
+	unsigned		intr_unlink_wait_cycle;
 	unsigned		intr_unlink_cycle;
 	unsigned		now_frame;	/* frame from HC hardware */
 	unsigned		last_iso_frame;	/* last frame scanned for iso */
@@ -210,6 +213,7 @@
 	#define OHCI_HCCTRL_LEN         0x4
 	__hc32			*ohci_hcctrl_reg;
 	unsigned		has_hostpc:1;
+	unsigned		has_tdi_phy_lpm:1;
 	unsigned		has_ppcd:1; /* support per-port change bits */
 	u8			sbrn;		/* packed release number */
 
@@ -222,7 +226,7 @@
 #endif
 
 	/* debug files */
-#ifdef DEBUG
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 	struct dentry		*debug_dir;
 #endif
 
@@ -778,15 +782,10 @@
 #define ehci_warn(ehci, fmt, args...) \
 	dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args)
 
-#ifdef VERBOSE_DEBUG
-#	define ehci_vdbg ehci_dbg
-#else
-	static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
-#endif
 
-#ifndef DEBUG
+#if !defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG)
 #define STUB_DEBUG_FILES
-#endif	/* DEBUG */
+#endif	/* !DEBUG && !CONFIG_DYNAMIC_DEBUG */
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
new file mode 100644
index 0000000..fce13bc
--- /dev/null
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -0,0 +1,6049 @@
+/*
+ * Faraday FOTG210 EHCI-like driver
+ *
+ * Copyright (c) 2013 Faraday Technology Corporation
+ *
+ * Author: Yuan-Hsin Chen <yhchen@faraday-tech.com>
+ *	   Feng-Hsin Chiang <john453@faraday-tech.com>
+ *	   Po-Yu Chuang <ratbert.chuang@gmail.com>
+ *
+ * Most of code borrowed from the Linux-3.7 EHCI driver
+ *
+ * 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/device.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/unaligned.h>
+
+/*-------------------------------------------------------------------------*/
+#define DRIVER_AUTHOR "Yuan-Hsin Chen"
+#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
+
+static const char	hcd_name[] = "fotg210_hcd";
+
+#undef VERBOSE_DEBUG
+#undef FOTG210_URB_TRACE
+
+#ifdef DEBUG
+#define FOTG210_STATS
+#endif
+
+/* magic numbers that can affect system performance */
+#define	FOTG210_TUNE_CERR		3 /* 0-3 qtd retries; 0 == don't stop */
+#define	FOTG210_TUNE_RL_HS		4 /* nak throttle; see 4.9 */
+#define	FOTG210_TUNE_RL_TT		0
+#define	FOTG210_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
+#define	FOTG210_TUNE_MULT_TT	1
+/*
+ * Some drivers think it's safe to schedule isochronous transfers more than
+ * 256 ms into the future (partly as a result of an old bug in the scheduling
+ * code).  In an attempt to avoid trouble, we will use a minimum scheduling
+ * length of 512 frames instead of 256.
+ */
+#define	FOTG210_TUNE_FLS		1 /* (medium) 512-frame schedule */
+
+/* Initial IRQ latency:  faster than hw default */
+static int log2_irq_thresh;		/* 0 to 6 */
+module_param(log2_irq_thresh, int, S_IRUGO);
+MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* initial park setting:  slower than hw default */
+static unsigned park;
+module_param(park, uint, S_IRUGO);
+MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
+
+/* for link power management(LPM) feature */
+static unsigned int hird;
+module_param(hird, int, S_IRUGO);
+MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
+
+#define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+#include "fotg210.h"
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_dbg(fotg210, fmt, args...) \
+	dev_dbg(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_err(fotg210, fmt, args...) \
+	dev_err(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_info(fotg210, fmt, args...) \
+	dev_info(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+#define fotg210_warn(fotg210, fmt, args...) \
+	dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args)
+
+#ifdef VERBOSE_DEBUG
+#	define fotg210_vdbg fotg210_dbg
+#else
+	static inline void fotg210_vdbg(struct fotg210_hcd *fotg210, ...) {}
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
+static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
+{
+	u32	params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
+
+	fotg210_dbg(fotg210,
+		"%s hcs_params 0x%x ports=%d\n",
+		label, params,
+		HCS_N_PORTS(params)
+		);
+}
+#else
+
+static inline void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
+static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
+{
+	u32	params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+	fotg210_dbg(fotg210,
+		"%s hcc_params %04x uframes %s%s\n",
+		label,
+		params,
+		HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+		HCC_CANPARK(params) ? " park" : "");
+}
+#else
+
+static inline void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+static void __maybe_unused
+dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
+{
+	fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
+		hc32_to_cpup(fotg210, &qtd->hw_next),
+		hc32_to_cpup(fotg210, &qtd->hw_alt_next),
+		hc32_to_cpup(fotg210, &qtd->hw_token),
+		hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
+	if (qtd->hw_buf[1])
+		fotg210_dbg(fotg210, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
+			hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
+			hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
+			hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
+			hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
+}
+
+static void __maybe_unused
+dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	struct fotg210_qh_hw *hw = qh->hw;
+
+	fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label,
+		qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
+	dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
+}
+
+static void __maybe_unused
+dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
+{
+	fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n",
+		label, itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
+		itd->urb);
+	fotg210_dbg(fotg210,
+		"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		hc32_to_cpu(fotg210, itd->hw_transaction[0]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[1]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[2]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[3]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[4]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[5]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[6]),
+		hc32_to_cpu(fotg210, itd->hw_transaction[7]));
+	fotg210_dbg(fotg210,
+		"  buf:   %08x %08x %08x %08x %08x %08x %08x\n",
+		hc32_to_cpu(fotg210, itd->hw_bufp[0]),
+		hc32_to_cpu(fotg210, itd->hw_bufp[1]),
+		hc32_to_cpu(fotg210, itd->hw_bufp[2]),
+		hc32_to_cpu(fotg210, itd->hw_bufp[3]),
+		hc32_to_cpu(fotg210, itd->hw_bufp[4]),
+		hc32_to_cpu(fotg210, itd->hw_bufp[5]),
+		hc32_to_cpu(fotg210, itd->hw_bufp[6]));
+	fotg210_dbg(fotg210, "  index: %d %d %d %d %d %d %d %d\n",
+		itd->index[0], itd->index[1], itd->index[2],
+		itd->index[3], itd->index[4], itd->index[5],
+		itd->index[6], itd->index[7]);
+}
+
+static int __maybe_unused
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{
+	return scnprintf(buf, len,
+		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+		label, label[0] ? " " : "", status,
+		(status & STS_ASS) ? " Async" : "",
+		(status & STS_PSS) ? " Periodic" : "",
+		(status & STS_RECL) ? " Recl" : "",
+		(status & STS_HALT) ? " Halt" : "",
+		(status & STS_IAA) ? " IAA" : "",
+		(status & STS_FATAL) ? " FATAL" : "",
+		(status & STS_FLR) ? " FLR" : "",
+		(status & STS_PCD) ? " PCD" : "",
+		(status & STS_ERR) ? " ERR" : "",
+		(status & STS_INT) ? " INT" : ""
+		);
+}
+
+static int __maybe_unused
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{
+	return scnprintf(buf, len,
+		"%s%sintrenable %02x%s%s%s%s%s%s",
+		label, label[0] ? " " : "", enable,
+		(enable & STS_IAA) ? " IAA" : "",
+		(enable & STS_FATAL) ? " FATAL" : "",
+		(enable & STS_FLR) ? " FLR" : "",
+		(enable & STS_PCD) ? " PCD" : "",
+		(enable & STS_ERR) ? " ERR" : "",
+		(enable & STS_INT) ? " INT" : ""
+		);
+}
+
+static const char *const fls_strings[] = { "1024", "512", "256", "??" };
+
+static int
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{
+	return scnprintf(buf, len,
+		"%s%scommand %07x %s=%d ithresh=%d%s%s%s "
+		"period=%s%s %s",
+		label, label[0] ? " " : "", command,
+		(command & CMD_PARK) ? " park" : "(park)",
+		CMD_PARK_CNT(command),
+		(command >> 16) & 0x3f,
+		(command & CMD_IAAD) ? " IAAD" : "",
+		(command & CMD_ASE) ? " Async" : "",
+		(command & CMD_PSE) ? " Periodic" : "",
+		fls_strings[(command >> 2) & 0x3],
+		(command & CMD_RESET) ? " Reset" : "",
+		(command & CMD_RUN) ? "RUN" : "HALT"
+		);
+}
+
+static int
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{
+	char	*sig;
+
+	/* signaling state */
+	switch (status & (3 << 10)) {
+	case 0 << 10:
+		sig = "se0";
+		break;
+	case 1 << 10:
+		sig = "k";
+		break; /* low speed */
+	case 2 << 10:
+		sig = "j";
+		break;
+	default:
+		sig = "?";
+		break;
+	}
+
+	return scnprintf(buf, len,
+		"%s%sport:%d status %06x %d "
+		"sig=%s%s%s%s%s%s%s%s",
+		label, label[0] ? " " : "", port, status,
+		status>>25,/*device address */
+		sig,
+		(status & PORT_RESET) ? " RESET" : "",
+		(status & PORT_SUSPEND) ? " SUSPEND" : "",
+		(status & PORT_RESUME) ? " RESUME" : "",
+		(status & PORT_PEC) ? " PEC" : "",
+		(status & PORT_PE) ? " PE" : "",
+		(status & PORT_CSC) ? " CSC" : "",
+		(status & PORT_CONNECT) ? " CONNECT" : "");
+}
+
+#else
+static inline void __maybe_unused
+dbg_qh(char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{}
+
+static inline int __maybe_unused
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{ return 0; }
+
+static inline int __maybe_unused
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{ return 0; }
+
+#endif	/* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+#define dbg_status(fotg210, label, status) { \
+	char _buf[80]; \
+	dbg_status_buf(_buf, sizeof(_buf), label, status); \
+	fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+#define dbg_cmd(fotg210, label, command) { \
+	char _buf[80]; \
+	dbg_command_buf(_buf, sizeof(_buf), label, command); \
+	fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+#define dbg_port(fotg210, label, port, status) { \
+	char _buf[80]; \
+	dbg_port_buf(_buf, sizeof(_buf), label, port, status); \
+	fotg210_dbg(fotg210, "%s\n", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files(struct fotg210_hcd *bus) { }
+static inline void remove_debug_files(struct fotg210_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in debugfs */
+
+static int debug_async_open(struct inode *, struct file *);
+static int debug_periodic_open(struct inode *, struct file *);
+static int debug_registers_open(struct inode *, struct file *);
+static int debug_async_open(struct inode *, struct file *);
+
+static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
+static int debug_close(struct inode *, struct file *);
+
+static const struct file_operations debug_async_fops = {
+	.owner		= THIS_MODULE,
+	.open		= debug_async_open,
+	.read		= debug_output,
+	.release	= debug_close,
+	.llseek		= default_llseek,
+};
+static const struct file_operations debug_periodic_fops = {
+	.owner		= THIS_MODULE,
+	.open		= debug_periodic_open,
+	.read		= debug_output,
+	.release	= debug_close,
+	.llseek		= default_llseek,
+};
+static const struct file_operations debug_registers_fops = {
+	.owner		= THIS_MODULE,
+	.open		= debug_registers_open,
+	.read		= debug_output,
+	.release	= debug_close,
+	.llseek		= default_llseek,
+};
+
+static struct dentry *fotg210_debug_root;
+
+struct debug_buffer {
+	ssize_t (*fill_func)(struct debug_buffer *);	/* fill method */
+	struct usb_bus *bus;
+	struct mutex mutex;	/* protect filling of buffer */
+	size_t count;		/* number of characters filled into buffer */
+	char *output_buf;
+	size_t alloc_size;
+};
+
+#define speed_char(info1)({ char tmp; \
+		switch (info1 & (3 << 12)) { \
+		case QH_FULL_SPEED:	\
+			tmp = 'f'; break; \
+		case QH_LOW_SPEED:	\
+			tmp = 'l'; break; \
+		case QH_HIGH_SPEED:	\
+			tmp = 'h'; break; \
+		default:		\
+			tmp = '?'; break; \
+		}; tmp; })
+
+static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
+{
+	__u32 v = hc32_to_cpu(fotg210, token);
+
+	if (v & QTD_STS_ACTIVE)
+		return '*';
+	if (v & QTD_STS_HALT)
+		return '-';
+	if (!IS_SHORT_READ(v))
+		return ' ';
+	/* tries to advance through hw_alt_next */
+	return '/';
+}
+
+static void qh_lines(
+	struct fotg210_hcd *fotg210,
+	struct fotg210_qh *qh,
+	char **nextp,
+	unsigned *sizep
+)
+{
+	u32			scratch;
+	u32			hw_curr;
+	struct fotg210_qtd	*td;
+	unsigned		temp;
+	unsigned		size = *sizep;
+	char			*next = *nextp;
+	char			mark;
+	__le32			list_end = FOTG210_LIST_END(fotg210);
+	struct fotg210_qh_hw	*hw = qh->hw;
+
+	if (hw->hw_qtd_next == list_end)	/* NEC does this */
+		mark = '@';
+	else
+		mark = token_mark(fotg210, hw->hw_token);
+	if (mark == '/') {	/* qh_alt_next controls qh advance? */
+		if ((hw->hw_alt_next & QTD_MASK(fotg210))
+				== fotg210->async->hw->hw_alt_next)
+			mark = '#';	/* blocked */
+		else if (hw->hw_alt_next == list_end)
+			mark = '.';	/* use hw_qtd_next */
+		/* else alt_next points to some other qtd */
+	}
+	scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
+	hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
+	temp = scnprintf(next, size,
+			"qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
+			qh, scratch & 0x007f,
+			speed_char(scratch),
+			(scratch >> 8) & 0x000f,
+			scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
+			hc32_to_cpup(fotg210, &hw->hw_token), mark,
+			(cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
+				? "data1" : "data0",
+			(hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
+	size -= temp;
+	next += temp;
+
+	/* hc may be modifying the list as we read it ... */
+	list_for_each_entry(td, &qh->qtd_list, qtd_list) {
+		scratch = hc32_to_cpup(fotg210, &td->hw_token);
+		mark = ' ';
+		if (hw_curr == td->qtd_dma)
+			mark = '*';
+		else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
+			mark = '+';
+		else if (QTD_LENGTH(scratch)) {
+			if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
+				mark = '#';
+			else if (td->hw_alt_next != list_end)
+				mark = '/';
+		}
+		temp = snprintf(next, size,
+				"\n\t%p%c%s len=%d %08x urb %p",
+				td, mark, ({ char *tmp;
+				 switch ((scratch>>8)&0x03) {
+				 case 0:
+					tmp = "out";
+					break;
+				 case 1:
+					tmp = "in";
+					break;
+				 case 2:
+					tmp = "setup";
+					break;
+				 default:
+					tmp = "?";
+					break;
+				 } tmp; }),
+				(scratch >> 16) & 0x7fff,
+				scratch,
+				td->urb);
+		if (size < temp)
+			temp = size;
+		size -= temp;
+		next += temp;
+		if (temp == size)
+			goto done;
+	}
+
+	temp = snprintf(next, size, "\n");
+	if (size < temp)
+		temp = size;
+	size -= temp;
+	next += temp;
+
+done:
+	*sizep = size;
+	*nextp = next;
+}
+
+static ssize_t fill_async_buffer(struct debug_buffer *buf)
+{
+	struct usb_hcd		*hcd;
+	struct fotg210_hcd	*fotg210;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	struct fotg210_qh		*qh;
+
+	hcd = bus_to_hcd(buf->bus);
+	fotg210 = hcd_to_fotg210(hcd);
+	next = buf->output_buf;
+	size = buf->alloc_size;
+
+	*next = 0;
+
+	/* dumps a snapshot of the async schedule.
+	 * usually empty except for long-term bulk reads, or head.
+	 * one QH per line, and TDs we know about
+	 */
+	spin_lock_irqsave(&fotg210->lock, flags);
+	for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
+	     qh = qh->qh_next.qh)
+		qh_lines(fotg210, qh, &next, &size);
+	if (fotg210->async_unlink && size > 0) {
+		temp = scnprintf(next, size, "\nunlink =\n");
+		size -= temp;
+		next += temp;
+
+		for (qh = fotg210->async_unlink; size > 0 && qh;
+				qh = qh->unlink_next)
+			qh_lines(fotg210, qh, &next, &size);
+	}
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+
+	return strlen(buf->output_buf);
+}
+
+#define DBG_SCHED_LIMIT 64
+static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
+{
+	struct usb_hcd		*hcd;
+	struct fotg210_hcd		*fotg210;
+	unsigned long		flags;
+	union fotg210_shadow	p, *seen;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i;
+	__hc32			tag;
+
+	seen = kmalloc(DBG_SCHED_LIMIT * sizeof(*seen), GFP_ATOMIC);
+	if (!seen)
+		return 0;
+	seen_count = 0;
+
+	hcd = bus_to_hcd(buf->bus);
+	fotg210 = hcd_to_fotg210(hcd);
+	next = buf->output_buf;
+	size = buf->alloc_size;
+
+	temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule.
+	 * iso changes, interrupt usually doesn't.
+	 */
+	spin_lock_irqsave(&fotg210->lock, flags);
+	for (i = 0; i < fotg210->periodic_size; i++) {
+		p = fotg210->pshadow[i];
+		if (likely(!p.ptr))
+			continue;
+		tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
+
+		temp = scnprintf(next, size, "%4d: ", i);
+		size -= temp;
+		next += temp;
+
+		do {
+			struct fotg210_qh_hw *hw;
+
+			switch (hc32_to_cpu(fotg210, tag)) {
+			case Q_TYPE_QH:
+				hw = p.qh->hw;
+				temp = scnprintf(next, size, " qh%d-%04x/%p",
+						p.qh->period,
+						hc32_to_cpup(fotg210,
+							&hw->hw_info2)
+							/* uframe masks */
+							& (QH_CMASK | QH_SMASK),
+						p.qh);
+				size -= temp;
+				next += temp;
+				/* don't repeat what follows this qh */
+				for (temp = 0; temp < seen_count; temp++) {
+					if (seen[temp].ptr != p.ptr)
+						continue;
+					if (p.qh->qh_next.ptr) {
+						temp = scnprintf(next, size,
+							" ...");
+						size -= temp;
+						next += temp;
+					}
+					break;
+				}
+				/* show more info the first time around */
+				if (temp == seen_count) {
+					u32	scratch = hc32_to_cpup(fotg210,
+							&hw->hw_info1);
+					struct fotg210_qtd	*qtd;
+					char		*type = "";
+
+					/* count tds, get ep direction */
+					temp = 0;
+					list_for_each_entry(qtd,
+							&p.qh->qtd_list,
+							qtd_list) {
+						temp++;
+						switch (0x03 & (hc32_to_cpu(
+							fotg210,
+							qtd->hw_token) >> 8)) {
+						case 0:
+							type = "out";
+							continue;
+						case 1:
+							type = "in";
+							continue;
+						}
+					}
+
+					temp = scnprintf(next, size,
+						"(%c%d ep%d%s "
+						"[%d/%d] q%d p%d)",
+						speed_char(scratch),
+						scratch & 0x007f,
+						(scratch >> 8) & 0x000f, type,
+						p.qh->usecs, p.qh->c_usecs,
+						temp,
+						0x7ff & (scratch >> 16));
+
+					if (seen_count < DBG_SCHED_LIMIT)
+						seen[seen_count++].qh = p.qh;
+				} else
+					temp = 0;
+				tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
+				p = p.qh->qh_next;
+				break;
+			case Q_TYPE_FSTN:
+				temp = scnprintf(next, size,
+					" fstn-%8x/%p", p.fstn->hw_prev,
+					p.fstn);
+				tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
+				p = p.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				temp = scnprintf(next, size,
+					" itd/%p", p.itd);
+				tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
+				p = p.itd->itd_next;
+				break;
+			}
+			size -= temp;
+			next += temp;
+		} while (p.ptr);
+
+		temp = scnprintf(next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	kfree(seen);
+
+	return buf->alloc_size - size;
+}
+#undef DBG_SCHED_LIMIT
+
+static const char *rh_state_string(struct fotg210_hcd *fotg210)
+{
+	switch (fotg210->rh_state) {
+	case FOTG210_RH_HALTED:
+		return "halted";
+	case FOTG210_RH_SUSPENDED:
+		return "suspended";
+	case FOTG210_RH_RUNNING:
+		return "running";
+	case FOTG210_RH_STOPPING:
+		return "stopping";
+	}
+	return "?";
+}
+
+static ssize_t fill_registers_buffer(struct debug_buffer *buf)
+{
+	struct usb_hcd		*hcd;
+	struct fotg210_hcd	*fotg210;
+	unsigned long		flags;
+	unsigned		temp, size, i;
+	char			*next, scratch[80];
+	static const char	fmt[] = "%*s\n";
+	static const char	label[] = "";
+
+	hcd = bus_to_hcd(buf->bus);
+	fotg210 = hcd_to_fotg210(hcd);
+	next = buf->output_buf;
+	size = buf->alloc_size;
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+
+	if (!HCD_HW_ACCESSIBLE(hcd)) {
+		size = scnprintf(next, size,
+			"bus %s, device %s\n"
+			"%s\n"
+			"SUSPENDED(no register access)\n",
+			hcd->self.controller->bus->name,
+			dev_name(hcd->self.controller),
+			hcd->product_desc);
+		goto done;
+	}
+
+	/* Capability Registers */
+	i = HC_VERSION(fotg210, fotg210_readl(fotg210,
+					      &fotg210->caps->hc_capbase));
+	temp = scnprintf(next, size,
+		"bus %s, device %s\n"
+		"%s\n"
+		"EHCI %x.%02x, rh state %s\n",
+		hcd->self.controller->bus->name,
+		dev_name(hcd->self.controller),
+		hcd->product_desc,
+		i >> 8, i & 0x0ff, rh_state_string(fotg210));
+	size -= temp;
+	next += temp;
+
+	/* FIXME interpret both types of params */
+	i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
+	temp = scnprintf(next, size, "structural params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+	temp = scnprintf(next, size, "capability params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	/* Operational Registers */
+	temp = dbg_status_buf(scratch, sizeof(scratch), label,
+			fotg210_readl(fotg210, &fotg210->regs->status));
+	temp = scnprintf(next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_command_buf(scratch, sizeof(scratch), label,
+			fotg210_readl(fotg210, &fotg210->regs->command));
+	temp = scnprintf(next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_intr_buf(scratch, sizeof(scratch), label,
+			fotg210_readl(fotg210, &fotg210->regs->intr_enable));
+	temp = scnprintf(next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = scnprintf(next, size, "uframe %04x\n",
+			fotg210_read_frame_index(fotg210));
+	size -= temp;
+	next += temp;
+
+	if (fotg210->async_unlink) {
+		temp = scnprintf(next, size, "async unlink qh %p\n",
+				fotg210->async_unlink);
+		size -= temp;
+		next += temp;
+	}
+
+#ifdef FOTG210_STATS
+	temp = scnprintf(next, size,
+		"irq normal %ld err %ld iaa %ld(lost %ld)\n",
+		fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
+		fotg210->stats.lost_iaa);
+	size -= temp;
+	next += temp;
+
+	temp = scnprintf(next, size, "complete %ld unlink %ld\n",
+		fotg210->stats.complete, fotg210->stats.unlink);
+	size -= temp;
+	next += temp;
+#endif
+
+done:
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+
+	return buf->alloc_size - size;
+}
+
+static struct debug_buffer *alloc_buffer(struct usb_bus *bus,
+				ssize_t (*fill_func)(struct debug_buffer *))
+{
+	struct debug_buffer *buf;
+
+	buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
+
+	if (buf) {
+		buf->bus = bus;
+		buf->fill_func = fill_func;
+		mutex_init(&buf->mutex);
+		buf->alloc_size = PAGE_SIZE;
+	}
+
+	return buf;
+}
+
+static int fill_buffer(struct debug_buffer *buf)
+{
+	int ret = 0;
+
+	if (!buf->output_buf)
+		buf->output_buf = vmalloc(buf->alloc_size);
+
+	if (!buf->output_buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = buf->fill_func(buf);
+
+	if (ret >= 0) {
+		buf->count = ret;
+		ret = 0;
+	}
+
+out:
+	return ret;
+}
+
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+			    size_t len, loff_t *offset)
+{
+	struct debug_buffer *buf = file->private_data;
+	int ret = 0;
+
+	mutex_lock(&buf->mutex);
+	if (buf->count == 0) {
+		ret = fill_buffer(buf);
+		if (ret != 0) {
+			mutex_unlock(&buf->mutex);
+			goto out;
+		}
+	}
+	mutex_unlock(&buf->mutex);
+
+	ret = simple_read_from_buffer(user_buf, len, offset,
+				      buf->output_buf, buf->count);
+
+out:
+	return ret;
+
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+	struct debug_buffer *buf = file->private_data;
+
+	if (buf) {
+		vfree(buf->output_buf);
+		kfree(buf);
+	}
+
+	return 0;
+}
+static int debug_async_open(struct inode *inode, struct file *file)
+{
+	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
+
+	return file->private_data ? 0 : -ENOMEM;
+}
+
+static int debug_periodic_open(struct inode *inode, struct file *file)
+{
+	struct debug_buffer *buf;
+	buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
+	if (!buf)
+		return -ENOMEM;
+
+	buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
+	file->private_data = buf;
+	return 0;
+}
+
+static int debug_registers_open(struct inode *inode, struct file *file)
+{
+	file->private_data = alloc_buffer(inode->i_private,
+					  fill_registers_buffer);
+
+	return file->private_data ? 0 : -ENOMEM;
+}
+
+static inline void create_debug_files(struct fotg210_hcd *fotg210)
+{
+	struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
+
+	fotg210->debug_dir = debugfs_create_dir(bus->bus_name,
+						fotg210_debug_root);
+	if (!fotg210->debug_dir)
+		return;
+
+	if (!debugfs_create_file("async", S_IRUGO, fotg210->debug_dir, bus,
+						&debug_async_fops))
+		goto file_error;
+
+	if (!debugfs_create_file("periodic", S_IRUGO, fotg210->debug_dir, bus,
+						&debug_periodic_fops))
+		goto file_error;
+
+	if (!debugfs_create_file("registers", S_IRUGO, fotg210->debug_dir, bus,
+						    &debug_registers_fops))
+		goto file_error;
+
+	return;
+
+file_error:
+	debugfs_remove_recursive(fotg210->debug_dir);
+}
+
+static inline void remove_debug_files(struct fotg210_hcd *fotg210)
+{
+	debugfs_remove_recursive(fotg210->debug_dir);
+}
+
+#endif /* STUB_DEBUG_FILES */
+/*-------------------------------------------------------------------------*/
+
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown:  shutting down the bridge before the devices using it.
+ */
+static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
+		      u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = fotg210_readl(fotg210, ptr);
+		if (result == ~(u32)0)		/* card removed */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay(1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
+/*
+ * Force HC to halt state from unknown (EHCI spec section 2.3).
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static int fotg210_halt(struct fotg210_hcd *fotg210)
+{
+	u32	temp;
+
+	spin_lock_irq(&fotg210->lock);
+
+	/* disable any irqs left enabled by previous code */
+	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+
+	/*
+	 * This routine gets called during probe before fotg210->command
+	 * has been initialized, so we can't rely on its value.
+	 */
+	fotg210->command &= ~CMD_RUN;
+	temp = fotg210_readl(fotg210, &fotg210->regs->command);
+	temp &= ~(CMD_RUN | CMD_IAAD);
+	fotg210_writel(fotg210, temp, &fotg210->regs->command);
+
+	spin_unlock_irq(&fotg210->lock);
+	synchronize_irq(fotg210_to_hcd(fotg210)->irq);
+
+	return handshake(fotg210, &fotg210->regs->status,
+			  STS_HALT, STS_HALT, 16 * 125);
+}
+
+/*
+ * Reset a non-running (STS_HALT == 1) controller.
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static int fotg210_reset(struct fotg210_hcd *fotg210)
+{
+	int	retval;
+	u32	command = fotg210_readl(fotg210, &fotg210->regs->command);
+
+	/* If the EHCI debug controller is active, special care must be
+	 * taken before and after a host controller reset */
+	if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
+		fotg210->debug = NULL;
+
+	command |= CMD_RESET;
+	dbg_cmd(fotg210, "reset", command);
+	fotg210_writel(fotg210, command, &fotg210->regs->command);
+	fotg210->rh_state = FOTG210_RH_HALTED;
+	fotg210->next_statechange = jiffies;
+	retval = handshake(fotg210, &fotg210->regs->command,
+			    CMD_RESET, 0, 250 * 1000);
+
+	if (retval)
+		return retval;
+
+	if (fotg210->debug)
+		dbgp_external_startup(fotg210_to_hcd(fotg210));
+
+	fotg210->port_c_suspend = fotg210->suspended_ports =
+			fotg210->resuming_ports = 0;
+	return retval;
+}
+
+/*
+ * Idle the controller (turn off the schedules).
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static void fotg210_quiesce(struct fotg210_hcd *fotg210)
+{
+	u32	temp;
+
+	if (fotg210->rh_state != FOTG210_RH_RUNNING)
+		return;
+
+	/* wait for any schedule enables/disables to take effect */
+	temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
+	handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
+		  16 * 125);
+
+	/* then disable anything that's still active */
+	spin_lock_irq(&fotg210->lock);
+	fotg210->command &= ~(CMD_ASE | CMD_PSE);
+	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+	spin_unlock_irq(&fotg210->lock);
+
+	/* hardware can take 16 microframes to turn off ... */
+	handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
+		  16 * 125);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void end_unlink_async(struct fotg210_hcd *fotg210);
+static void unlink_empty_async(struct fotg210_hcd *fotg210);
+static void fotg210_work(struct fotg210_hcd *fotg210);
+static void start_unlink_intr(struct fotg210_hcd *fotg210,
+			      struct fotg210_qh *qh);
+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+/*-------------------------------------------------------------------------*/
+
+/* Set a bit in the USBCMD register */
+static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
+{
+	fotg210->command |= bit;
+	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+
+	/* unblock posted write */
+	fotg210_readl(fotg210, &fotg210->regs->command);
+}
+
+/* Clear a bit in the USBCMD register */
+static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
+{
+	fotg210->command &= ~bit;
+	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+
+	/* unblock posted write */
+	fotg210_readl(fotg210, &fotg210->regs->command);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI timer support...  Now using hrtimers.
+ *
+ * Lots of different events are triggered from fotg210->hrtimer.  Whenever
+ * the timer routine runs, it checks each possible event; events that are
+ * currently enabled and whose expiration time has passed get handled.
+ * The set of enabled events is stored as a collection of bitflags in
+ * fotg210->enabled_hrtimer_events, and they are numbered in order of
+ * increasing delay values (ranging between 1 ms and 100 ms).
+ *
+ * Rather than implementing a sorted list or tree of all pending events,
+ * we keep track only of the lowest-numbered pending event, in
+ * fotg210->next_hrtimer_event.  Whenever fotg210->hrtimer gets restarted, its
+ * expiration time is set to the timeout value for this event.
+ *
+ * As a result, events might not get handled right away; the actual delay
+ * could be anywhere up to twice the requested delay.  This doesn't
+ * matter, because none of the events are especially time-critical.  The
+ * ones that matter most all have a delay of 1 ms, so they will be
+ * handled after 2 ms at most, which is okay.  In addition to this, we
+ * allow for an expiration range of 1 ms.
+ */
+
+/*
+ * Delay lengths for the hrtimer event types.
+ * Keep this list sorted by delay length, in the same order as
+ * the event types indexed by enum fotg210_hrtimer_event in fotg210.h.
+ */
+static unsigned event_delays_ns[] = {
+	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_ASS */
+	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_PSS */
+	1 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_POLL_DEAD */
+	1125 * NSEC_PER_USEC,	/* FOTG210_HRTIMER_UNLINK_INTR */
+	2 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_FREE_ITDS */
+	6 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_ASYNC_UNLINKS */
+	10 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_IAA_WATCHDOG */
+	10 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_DISABLE_PERIODIC */
+	15 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_DISABLE_ASYNC */
+	100 * NSEC_PER_MSEC,	/* FOTG210_HRTIMER_IO_WATCHDOG */
+};
+
+/* Enable a pending hrtimer event */
+static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
+		bool resched)
+{
+	ktime_t		*timeout = &fotg210->hr_timeouts[event];
+
+	if (resched)
+		*timeout = ktime_add(ktime_get(),
+				ktime_set(0, event_delays_ns[event]));
+	fotg210->enabled_hrtimer_events |= (1 << event);
+
+	/* Track only the lowest-numbered pending event */
+	if (event < fotg210->next_hrtimer_event) {
+		fotg210->next_hrtimer_event = event;
+		hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
+				NSEC_PER_MSEC, HRTIMER_MODE_ABS);
+	}
+}
+
+
+/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
+static void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
+{
+	unsigned	actual, want;
+
+	/* Don't enable anything if the controller isn't running (e.g., died) */
+	if (fotg210->rh_state != FOTG210_RH_RUNNING)
+		return;
+
+	want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
+	actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
+
+	if (want != actual) {
+
+		/* Poll again later, but give up after about 20 ms */
+		if (fotg210->ASS_poll_count++ < 20) {
+			fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
+					     true);
+			return;
+		}
+		fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
+				want, actual);
+	}
+	fotg210->ASS_poll_count = 0;
+
+	/* The status is up-to-date; restart or stop the schedule as needed */
+	if (want == 0) {	/* Stopped */
+		if (fotg210->async_count > 0)
+			fotg210_set_command_bit(fotg210, CMD_ASE);
+
+	} else {		/* Running */
+		if (fotg210->async_count == 0) {
+
+			/* Turn off the schedule after a while */
+			fotg210_enable_event(fotg210,
+					     FOTG210_HRTIMER_DISABLE_ASYNC,
+					     true);
+		}
+	}
+}
+
+/* Turn off the async schedule after a brief delay */
+static void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
+{
+	fotg210_clear_command_bit(fotg210, CMD_ASE);
+}
+
+
+/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
+static void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
+{
+	unsigned	actual, want;
+
+	/* Don't do anything if the controller isn't running (e.g., died) */
+	if (fotg210->rh_state != FOTG210_RH_RUNNING)
+		return;
+
+	want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
+	actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
+
+	if (want != actual) {
+
+		/* Poll again later, but give up after about 20 ms */
+		if (fotg210->PSS_poll_count++ < 20) {
+			fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
+					     true);
+			return;
+		}
+		fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
+				want, actual);
+	}
+	fotg210->PSS_poll_count = 0;
+
+	/* The status is up-to-date; restart or stop the schedule as needed */
+	if (want == 0) {	/* Stopped */
+		if (fotg210->periodic_count > 0)
+			fotg210_set_command_bit(fotg210, CMD_PSE);
+
+	} else {		/* Running */
+		if (fotg210->periodic_count == 0) {
+
+			/* Turn off the schedule after a while */
+			fotg210_enable_event(fotg210,
+					     FOTG210_HRTIMER_DISABLE_PERIODIC,
+					     true);
+		}
+	}
+}
+
+/* Turn off the periodic schedule after a brief delay */
+static void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
+{
+	fotg210_clear_command_bit(fotg210, CMD_PSE);
+}
+
+
+/* Poll the STS_HALT status bit; see when a dead controller stops */
+static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
+{
+	if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
+
+		/* Give up after a few milliseconds */
+		if (fotg210->died_poll_count++ < 5) {
+			/* Try again later */
+			fotg210_enable_event(fotg210,
+					     FOTG210_HRTIMER_POLL_DEAD, true);
+			return;
+		}
+		fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
+	}
+
+	/* Clean up the mess */
+	fotg210->rh_state = FOTG210_RH_HALTED;
+	fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+	fotg210_work(fotg210);
+	end_unlink_async(fotg210);
+
+	/* Not in process context, so don't try to reset the controller */
+}
+
+
+/* Handle unlinked interrupt QHs once they are gone from the hardware */
+static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
+{
+	bool		stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
+
+	/*
+	 * Process all the QHs on the intr_unlink list that were added
+	 * before the current unlink cycle began.  The list is in
+	 * temporal order, so stop when we reach the first entry in the
+	 * current cycle.  But if the root hub isn't running then
+	 * process all the QHs on the list.
+	 */
+	fotg210->intr_unlinking = true;
+	while (fotg210->intr_unlink) {
+		struct fotg210_qh	*qh = fotg210->intr_unlink;
+
+		if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
+			break;
+		fotg210->intr_unlink = qh->unlink_next;
+		qh->unlink_next = NULL;
+		end_unlink_intr(fotg210, qh);
+	}
+
+	/* Handle remaining entries later */
+	if (fotg210->intr_unlink) {
+		fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
+				     true);
+		++fotg210->intr_unlink_cycle;
+	}
+	fotg210->intr_unlinking = false;
+}
+
+
+/* Start another free-iTDs/siTDs cycle */
+static void start_free_itds(struct fotg210_hcd *fotg210)
+{
+	if (!(fotg210->enabled_hrtimer_events &
+			BIT(FOTG210_HRTIMER_FREE_ITDS))) {
+		fotg210->last_itd_to_free = list_entry(
+				fotg210->cached_itd_list.prev,
+				struct fotg210_itd, itd_list);
+		fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
+	}
+}
+
+/* Wait for controller to stop using old iTDs and siTDs */
+static void end_free_itds(struct fotg210_hcd *fotg210)
+{
+	struct fotg210_itd		*itd, *n;
+
+	if (fotg210->rh_state < FOTG210_RH_RUNNING)
+		fotg210->last_itd_to_free = NULL;
+
+	list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
+		list_del(&itd->itd_list);
+		dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
+		if (itd == fotg210->last_itd_to_free)
+			break;
+	}
+
+	if (!list_empty(&fotg210->cached_itd_list))
+		start_free_itds(fotg210);
+}
+
+
+/* Handle lost (or very late) IAA interrupts */
+static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
+{
+	if (fotg210->rh_state != FOTG210_RH_RUNNING)
+		return;
+
+	/*
+	 * Lost IAA irqs wedge things badly; seen first with a vt8235.
+	 * So we need this watchdog, but must protect it against both
+	 * (a) SMP races against real IAA firing and retriggering, and
+	 * (b) clean HC shutdown, when IAA watchdog was pending.
+	 */
+	if (fotg210->async_iaa) {
+		u32 cmd, status;
+
+		/* If we get here, IAA is *REALLY* late.  It's barely
+		 * conceivable that the system is so busy that CMD_IAAD
+		 * is still legitimately set, so let's be sure it's
+		 * clear before we read STS_IAA.  (The HC should clear
+		 * CMD_IAAD when it sets STS_IAA.)
+		 */
+		cmd = fotg210_readl(fotg210, &fotg210->regs->command);
+
+		/*
+		 * If IAA is set here it either legitimately triggered
+		 * after the watchdog timer expired (_way_ late, so we'll
+		 * still count it as lost) ... or a silicon erratum:
+		 * - VIA seems to set IAA without triggering the IRQ;
+		 * - IAAD potentially cleared without setting IAA.
+		 */
+		status = fotg210_readl(fotg210, &fotg210->regs->status);
+		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+			COUNT(fotg210->stats.lost_iaa);
+			fotg210_writel(fotg210, STS_IAA,
+				       &fotg210->regs->status);
+		}
+
+		fotg210_vdbg(fotg210, "IAA watchdog: status %x cmd %x\n",
+				status, cmd);
+		end_unlink_async(fotg210);
+	}
+}
+
+
+/* Enable the I/O watchdog, if appropriate */
+static void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
+{
+	/* Not needed if the controller isn't running or it's already enabled */
+	if (fotg210->rh_state != FOTG210_RH_RUNNING ||
+			(fotg210->enabled_hrtimer_events &
+				BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
+		return;
+
+	/*
+	 * Isochronous transfers always need the watchdog.
+	 * For other sorts we use it only if the flag is set.
+	 */
+	if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
+			fotg210->async_count + fotg210->intr_count > 0))
+		fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG,
+				     true);
+}
+
+
+/*
+ * Handler functions for the hrtimer event types.
+ * Keep this array in the same order as the event types indexed by
+ * enum fotg210_hrtimer_event in fotg210.h.
+ */
+static void (*event_handlers[])(struct fotg210_hcd *) = {
+	fotg210_poll_ASS,			/* FOTG210_HRTIMER_POLL_ASS */
+	fotg210_poll_PSS,			/* FOTG210_HRTIMER_POLL_PSS */
+	fotg210_handle_controller_death,	/* FOTG210_HRTIMER_POLL_DEAD */
+	fotg210_handle_intr_unlinks,	/* FOTG210_HRTIMER_UNLINK_INTR */
+	end_free_itds,			/* FOTG210_HRTIMER_FREE_ITDS */
+	unlink_empty_async,		/* FOTG210_HRTIMER_ASYNC_UNLINKS */
+	fotg210_iaa_watchdog,		/* FOTG210_HRTIMER_IAA_WATCHDOG */
+	fotg210_disable_PSE,		/* FOTG210_HRTIMER_DISABLE_PERIODIC */
+	fotg210_disable_ASE,		/* FOTG210_HRTIMER_DISABLE_ASYNC */
+	fotg210_work,			/* FOTG210_HRTIMER_IO_WATCHDOG */
+};
+
+static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
+{
+	struct fotg210_hcd *fotg210 =
+			container_of(t, struct fotg210_hcd, hrtimer);
+	ktime_t		now;
+	unsigned long	events;
+	unsigned long	flags;
+	unsigned	e;
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+
+	events = fotg210->enabled_hrtimer_events;
+	fotg210->enabled_hrtimer_events = 0;
+	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
+
+	/*
+	 * Check each pending event.  If its time has expired, handle
+	 * the event; otherwise re-enable it.
+	 */
+	now = ktime_get();
+	for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
+		if (now.tv64 >= fotg210->hr_timeouts[e].tv64)
+			event_handlers[e](fotg210);
+		else
+			fotg210_enable_event(fotg210, e, false);
+	}
+
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	return HRTIMER_NORESTART;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define fotg210_bus_suspend	NULL
+#define fotg210_bus_resume	NULL
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete(
+	struct fotg210_hcd	*fotg210,
+	int		index,
+	u32 __iomem	*status_reg,
+	int		port_status
+) {
+	if (!(port_status & PORT_CONNECT))
+		return port_status;
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+		/* with integrated TT, there's nobody to hand it to! */
+		fotg210_dbg(fotg210,
+			"Failed to enable port %d on root hub TT\n",
+			index+1);
+		return port_status;
+	} else {
+		fotg210_dbg(fotg210, "port %d reset complete, port enabled\n",
+			index + 1);
+	}
+
+	return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct fotg210_hcd	*fotg210 = hcd_to_fotg210(hcd);
+	u32		temp, status;
+	u32		mask;
+	int		retval = 1;
+	unsigned long	flags;
+
+	/* init status to no-changes */
+	buf[0] = 0;
+
+	/* Inform the core about resumes-in-progress by returning
+	 * a non-zero value even if there are no status changes.
+	 */
+	status = fotg210->resuming_ports;
+
+	mask = PORT_CSC | PORT_PEC;
+	/* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
+
+	/* no hub change reports (bit 0) for now (power, ...) */
+
+	/* port N changes (bit N)? */
+	spin_lock_irqsave(&fotg210->lock, flags);
+
+	temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
+
+	/*
+	 * Return status information even for ports with OWNER set.
+	 * Otherwise khubd wouldn't see the disconnect event when a
+	 * high-speed device is switched over to the companion
+	 * controller by the user.
+	 */
+
+	if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend)
+			|| (fotg210->reset_done[0] && time_after_eq(
+				jiffies, fotg210->reset_done[0]))) {
+		buf[0] |= 1 << 1;
+		status = STS_PCD;
+	}
+	/* FIXME autosuspend idle root hubs */
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+fotg210_hub_descriptor(
+	struct fotg210_hcd		*fotg210,
+	struct usb_hub_descriptor	*desc
+) {
+	int		ports = HCS_N_PORTS(fotg210->hcs_params);
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = 10;	/* fotg210 1.0, 2.3.9 says 20ms max */
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
+	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
+
+	temp = 0x0008;		/* per-port overcurrent reporting */
+	temp |= 0x0002;		/* no power switching */
+	desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int fotg210_hub_control(
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct fotg210_hcd	*fotg210 = hcd_to_fotg210(hcd);
+	int		ports = HCS_N_PORTS(fotg210->hcs_params);
+	u32 __iomem	*status_reg = &fotg210->regs->port_status;
+	u32		temp, temp1, status;
+	unsigned long	flags;
+	int		retval = 0;
+	unsigned	selector;
+
+	/*
+	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+	 * (track current state ourselves) ... blink for diagnostics,
+	 * power, "this is the one", etc.  EHCI spec supports this.
+	 */
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = fotg210_readl(fotg210, status_reg);
+		temp &= ~PORT_RWC_BITS;
+
+		/*
+		 * Even if OWNER is set, so the port is owned by the
+		 * companion controller, khubd needs to be able to clear
+		 * the port-change status bits (especially
+		 * USB_PORT_STAT_C_CONNECTION).
+		 */
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			if (temp & PORT_RESET)
+				goto error;
+			if (!(temp & PORT_SUSPEND))
+				break;
+			if ((temp & PORT_PE) == 0)
+				goto error;
+
+			/* resume signaling for 20 msec */
+			fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
+			fotg210->reset_done[wIndex] = jiffies
+					+ msecs_to_jiffies(20);
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			clear_bit(wIndex, &fotg210->port_c_suspend);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			fotg210_writel(fotg210, temp | OTGISR_OVC,
+				       &fotg210->regs->otgisr);
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		fotg210_readl(fotg210, &fotg210->regs->command);
+		break;
+	case GetHubDescriptor:
+		fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
+			buf);
+		break;
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset(buf, 0, 4);
+		/*cpu_to_le32s ((u32 *) buf); */
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		status = 0;
+		temp = fotg210_readl(fotg210, status_reg);
+
+		/* wPortChange bits */
+		if (temp & PORT_CSC)
+			status |= USB_PORT_STAT_C_CONNECTION << 16;
+		if (temp & PORT_PEC)
+			status |= USB_PORT_STAT_C_ENABLE << 16;
+
+		temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
+		if (temp1 & OTGISR_OVC)
+			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+
+		/* whoever resumes must GetPortStatus to complete it!! */
+		if (temp & PORT_RESUME) {
+
+			/* Remote Wakeup received? */
+			if (!fotg210->reset_done[wIndex]) {
+				/* resume signaling for 20 msec */
+				fotg210->reset_done[wIndex] = jiffies
+						+ msecs_to_jiffies(20);
+				/* check the port again */
+				mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
+						fotg210->reset_done[wIndex]);
+			}
+
+			/* resume completed? */
+			else if (time_after_eq(jiffies,
+					fotg210->reset_done[wIndex])) {
+				clear_bit(wIndex, &fotg210->suspended_ports);
+				set_bit(wIndex, &fotg210->port_c_suspend);
+				fotg210->reset_done[wIndex] = 0;
+
+				/* stop resume signaling */
+				temp = fotg210_readl(fotg210, status_reg);
+				fotg210_writel(fotg210,
+					temp & ~(PORT_RWC_BITS | PORT_RESUME),
+					status_reg);
+				clear_bit(wIndex, &fotg210->resuming_ports);
+				retval = handshake(fotg210, status_reg,
+					   PORT_RESUME, 0, 2000 /* 2msec */);
+				if (retval != 0) {
+					fotg210_err(fotg210,
+						"port %d resume error %d\n",
+						wIndex + 1, retval);
+					goto error;
+				}
+				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+			}
+		}
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+				&& time_after_eq(jiffies,
+					fotg210->reset_done[wIndex])) {
+			status |= USB_PORT_STAT_C_RESET << 16;
+			fotg210->reset_done[wIndex] = 0;
+			clear_bit(wIndex, &fotg210->resuming_ports);
+
+			/* force reset to complete */
+			fotg210_writel(fotg210,
+				       temp & ~(PORT_RWC_BITS | PORT_RESET),
+				       status_reg);
+			/* REVISIT:  some hardware needs 550+ usec to clear
+			 * this bit; seems too long to spin routinely...
+			 */
+			retval = handshake(fotg210, status_reg,
+					PORT_RESET, 0, 1000);
+			if (retval != 0) {
+				fotg210_err(fotg210, "port %d reset error %d\n",
+					wIndex + 1, retval);
+				goto error;
+			}
+
+			/* see what we found out */
+			temp = check_reset_complete(fotg210, wIndex, status_reg,
+					fotg210_readl(fotg210, status_reg));
+		}
+
+		if (!(temp & (PORT_RESUME|PORT_RESET))) {
+			fotg210->reset_done[wIndex] = 0;
+			clear_bit(wIndex, &fotg210->resuming_ports);
+		}
+
+		/* transfer dedicated ports to the companion hc */
+		if ((temp & PORT_CONNECT) &&
+				test_bit(wIndex, &fotg210->companion_ports)) {
+			temp &= ~PORT_RWC_BITS;
+			fotg210_writel(fotg210, temp, status_reg);
+			fotg210_dbg(fotg210, "port %d --> companion\n",
+				    wIndex + 1);
+			temp = fotg210_readl(fotg210, status_reg);
+		}
+
+		/*
+		 * Even if OWNER is set, there's no harm letting khubd
+		 * see the wPortStatus values (they should all be 0 except
+		 * for PORT_POWER anyway).
+		 */
+
+		if (temp & PORT_CONNECT) {
+			status |= USB_PORT_STAT_CONNECTION;
+			status |= fotg210_port_speed(fotg210, temp);
+		}
+		if (temp & PORT_PE)
+			status |= USB_PORT_STAT_ENABLE;
+
+		/* maybe the port was unsuspended without our knowledge */
+		if (temp & (PORT_SUSPEND|PORT_RESUME)) {
+			status |= USB_PORT_STAT_SUSPEND;
+		} else if (test_bit(wIndex, &fotg210->suspended_ports)) {
+			clear_bit(wIndex, &fotg210->suspended_ports);
+			clear_bit(wIndex, &fotg210->resuming_ports);
+			fotg210->reset_done[wIndex] = 0;
+			if (temp & PORT_PE)
+				set_bit(wIndex, &fotg210->port_c_suspend);
+		}
+
+		temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
+		if (temp1 & OTGISR_OVC)
+			status |= USB_PORT_STAT_OVERCURRENT;
+		if (temp & PORT_RESET)
+			status |= USB_PORT_STAT_RESET;
+		if (test_bit(wIndex, &fotg210->port_c_suspend))
+			status |= USB_PORT_STAT_C_SUSPEND << 16;
+
+#ifndef	VERBOSE_DEBUG
+	if (status & ~0xffff)	/* only if wPortChange is interesting */
+#endif
+		dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
+		put_unaligned_le32(status, buf);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		selector = wIndex >> 8;
+		wIndex &= 0xff;
+
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = fotg210_readl(fotg210, status_reg);
+		temp &= ~PORT_RWC_BITS;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			if ((temp & PORT_PE) == 0
+					|| (temp & PORT_RESET) != 0)
+				goto error;
+
+			/* After above check the port must be connected.
+			 * Set appropriate bit thus could put phy into low power
+			 * mode if we have hostpc feature
+			 */
+			fotg210_writel(fotg210, temp | PORT_SUSPEND,
+				       status_reg);
+			set_bit(wIndex, &fotg210->suspended_ports);
+			break;
+		case USB_PORT_FEAT_RESET:
+			if (temp & PORT_RESUME)
+				goto error;
+			/* line status bits may report this as low speed,
+			 * which can be fine if this root hub has a
+			 * transaction translator built in.
+			 */
+			fotg210_vdbg(fotg210, "port %d reset\n", wIndex + 1);
+			temp |= PORT_RESET;
+			temp &= ~PORT_PE;
+
+			/*
+			 * caller must wait, then call GetPortStatus
+			 * usb 2.0 spec says 50 ms resets on root
+			 */
+			fotg210->reset_done[wIndex] = jiffies
+					+ msecs_to_jiffies(50);
+			fotg210_writel(fotg210, temp, status_reg);
+			break;
+
+		/* For downstream facing ports (these):  one hub port is put
+		 * into test mode according to USB2 11.24.2.13, then the hub
+		 * must be reset (which for root hub now means rmmod+modprobe,
+		 * or else system reboot).  See EHCI 2.3.9 and 4.14 for info
+		 * about the EHCI-specific stuff.
+		 */
+		case USB_PORT_FEAT_TEST:
+			if (!selector || selector > 5)
+				goto error;
+			spin_unlock_irqrestore(&fotg210->lock, flags);
+			fotg210_quiesce(fotg210);
+			spin_lock_irqsave(&fotg210->lock, flags);
+
+			/* Put all enabled ports into suspend */
+			temp = fotg210_readl(fotg210, status_reg) &
+				~PORT_RWC_BITS;
+			if (temp & PORT_PE)
+				fotg210_writel(fotg210, temp | PORT_SUSPEND,
+						status_reg);
+
+			spin_unlock_irqrestore(&fotg210->lock, flags);
+			fotg210_halt(fotg210);
+			spin_lock_irqsave(&fotg210->lock, flags);
+
+			temp = fotg210_readl(fotg210, status_reg);
+			temp |= selector << 16;
+			fotg210_writel(fotg210, temp, status_reg);
+			break;
+
+		default:
+			goto error;
+		}
+		fotg210_readl(fotg210, &fotg210->regs->command);
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	return retval;
+}
+
+static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
+		int portnum)
+{
+	return;
+}
+
+static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
+		int portnum)
+{
+	return 0;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use dma_pool or dma_alloc_coherent
+ *	- driver buffers, read/written by HC ... single shot DMA mapped
+ *
+ * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
+ * No memory seen by this driver is pageable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
+				    struct fotg210_qtd *qtd, dma_addr_t dma)
+{
+	memset(qtd, 0, sizeof(*qtd));
+	qtd->qtd_dma = dma;
+	qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
+	qtd->hw_next = FOTG210_LIST_END(fotg210);
+	qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
+	INIT_LIST_HEAD(&qtd->qtd_list);
+}
+
+static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
+					     gfp_t flags)
+{
+	struct fotg210_qtd		*qtd;
+	dma_addr_t		dma;
+
+	qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
+	if (qtd != NULL)
+		fotg210_qtd_init(fotg210, qtd, dma);
+
+	return qtd;
+}
+
+static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
+				    struct fotg210_qtd *qtd)
+{
+	dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	/* clean qtds first, and know this is not linked */
+	if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
+		fotg210_dbg(fotg210, "unused qh not empty!\n");
+		BUG();
+	}
+	if (qh->dummy)
+		fotg210_qtd_free(fotg210, qh->dummy);
+	dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
+	kfree(qh);
+}
+
+static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
+					   gfp_t flags)
+{
+	struct fotg210_qh		*qh;
+	dma_addr_t		dma;
+
+	qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
+	if (!qh)
+		goto done;
+	qh->hw = (struct fotg210_qh_hw *)
+		dma_pool_alloc(fotg210->qh_pool, flags, &dma);
+	if (!qh->hw)
+		goto fail;
+	memset(qh->hw, 0, sizeof(*qh->hw));
+	qh->qh_dma = dma;
+	INIT_LIST_HEAD(&qh->qtd_list);
+
+	/* dummy td enables safe urb queuing */
+	qh->dummy = fotg210_qtd_alloc(fotg210, flags);
+	if (qh->dummy == NULL) {
+		fotg210_dbg(fotg210, "no dummy td\n");
+		goto fail1;
+	}
+done:
+	return qh;
+fail1:
+	dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
+fail:
+	kfree(qh);
+	return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
+{
+	if (fotg210->async)
+		qh_destroy(fotg210, fotg210->async);
+	fotg210->async = NULL;
+
+	if (fotg210->dummy)
+		qh_destroy(fotg210, fotg210->dummy);
+	fotg210->dummy = NULL;
+
+	/* DMA consistent memory and pools */
+	if (fotg210->qtd_pool)
+		dma_pool_destroy(fotg210->qtd_pool);
+	fotg210->qtd_pool = NULL;
+
+	if (fotg210->qh_pool) {
+		dma_pool_destroy(fotg210->qh_pool);
+		fotg210->qh_pool = NULL;
+	}
+
+	if (fotg210->itd_pool)
+		dma_pool_destroy(fotg210->itd_pool);
+	fotg210->itd_pool = NULL;
+
+	if (fotg210->periodic)
+		dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
+			fotg210->periodic_size * sizeof(u32),
+			fotg210->periodic, fotg210->periodic_dma);
+	fotg210->periodic = NULL;
+
+	/* shadow periodic table */
+	kfree(fotg210->pshadow);
+	fotg210->pshadow = NULL;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
+{
+	int i;
+
+	/* QTDs for control/bulk/intr transfers */
+	fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
+			fotg210_to_hcd(fotg210)->self.controller,
+			sizeof(struct fotg210_qtd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!fotg210->qtd_pool)
+		goto fail;
+
+	/* QHs for control/bulk/intr transfers */
+	fotg210->qh_pool = dma_pool_create("fotg210_qh",
+			fotg210_to_hcd(fotg210)->self.controller,
+			sizeof(struct fotg210_qh_hw),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!fotg210->qh_pool)
+		goto fail;
+
+	fotg210->async = fotg210_qh_alloc(fotg210, flags);
+	if (!fotg210->async)
+		goto fail;
+
+	/* ITD for high speed ISO transfers */
+	fotg210->itd_pool = dma_pool_create("fotg210_itd",
+			fotg210_to_hcd(fotg210)->self.controller,
+			sizeof(struct fotg210_itd),
+			64 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */);
+	if (!fotg210->itd_pool)
+		goto fail;
+
+	/* Hardware periodic table */
+	fotg210->periodic = (__le32 *)
+		dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
+			fotg210->periodic_size * sizeof(__le32),
+			&fotg210->periodic_dma, 0);
+	if (fotg210->periodic == NULL)
+		goto fail;
+
+	for (i = 0; i < fotg210->periodic_size; i++)
+		fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
+
+	/* software shadow of hardware table */
+	fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
+				   flags);
+	if (fotg210->pshadow != NULL)
+		return 0;
+
+fail:
+	fotg210_dbg(fotg210, "couldn't init memory\n");
+	fotg210_mem_cleanup(fotg210);
+	return -ENOMEM;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
+ *
+ * ISO traffic uses "ISO TD" (itd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.  That's in "ehci-sched.c".
+ *
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd, dma_addr_t buf,
+		  size_t len, int token, int maxpacket)
+{
+	int	i, count;
+	u64	addr = buf;
+
+	/* one buffer entry per 4K ... first might be short or unaligned */
+	qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
+	qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
+	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
+	if (likely(len < count))		/* ... iff needed */
+		count = len;
+	else {
+		buf +=  0x1000;
+		buf &= ~0x0fff;
+
+		/* per-qtd limit: from 16K to 20K (best alignment) */
+		for (i = 1; count < len && i < 5; i++) {
+			addr = buf;
+			qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
+			qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
+					(u32)(addr >> 32));
+			buf += 0x1000;
+			if ((count + 0x1000) < len)
+				count += 0x1000;
+			else
+				count = len;
+		}
+
+		/* short packets may only terminate transfers */
+		if (count != len)
+			count -= (count % maxpacket);
+	}
+	qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
+	qtd->length = count;
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+qh_update(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
+	  struct fotg210_qtd *qtd)
+{
+	struct fotg210_qh_hw *hw = qh->hw;
+
+	/* writes to an active overlay are unsafe */
+	BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+	hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+	hw->hw_alt_next = FOTG210_LIST_END(fotg210);
+
+	/* Except for control endpoints, we make hardware maintain data
+	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+	 * ever clear it.
+	 */
+	if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
+		unsigned	is_out, epnum;
+
+		is_out = qh->is_out;
+		epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
+		if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
+			hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
+			usb_settoggle(qh->dev, epnum, is_out, 1);
+		}
+	}
+
+	hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
+}
+
+/* if it weren't for a common silicon quirk (writing the dummy into the qh
+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
+ * recovery (including urb dequeue) would need software changes to a QH...
+ */
+static void
+qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	struct fotg210_qtd *qtd;
+
+	if (list_empty(&qh->qtd_list))
+		qtd = qh->dummy;
+	else {
+		qtd = list_entry(qh->qtd_list.next,
+				struct fotg210_qtd, qtd_list);
+		/*
+		 * first qtd may already be partially processed.
+		 * If we come here during unlink, the QH overlay region
+		 * might have reference to the just unlinked qtd. The
+		 * qtd is updated in qh_completions(). Update the QH
+		 * overlay here.
+		 */
+		if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
+			qh->hw->hw_qtd_next = qtd->hw_next;
+			qtd = NULL;
+		}
+	}
+
+	if (qtd)
+		qh_update(fotg210, qh, qtd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
+		struct usb_host_endpoint *ep)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	struct fotg210_qh		*qh = ep->hcpriv;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+	qh->clearing_tt = 0;
+	if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
+			&& fotg210->rh_state == FOTG210_RH_RUNNING)
+		qh_link_async(fotg210, qh);
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
+				    struct fotg210_qh *qh,
+				    struct urb *urb, u32 token)
+{
+
+	/* If an async split transaction gets an error or is unlinked,
+	 * the TT buffer may be left in an indeterminate state.  We
+	 * have to clear the TT buffer.
+	 *
+	 * Note: this routine is never called for Isochronous transfers.
+	 */
+	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
+#ifdef DEBUG
+		struct usb_device *tt = urb->dev->tt->hub;
+		dev_dbg(&tt->dev,
+			"clear tt buffer port %d, a%d ep%d t%08x\n",
+			urb->dev->ttport, urb->dev->devnum,
+			usb_pipeendpoint(urb->pipe), token);
+#endif /* DEBUG */
+		if (urb->dev->tt->hub !=
+		    fotg210_to_hcd(fotg210)->self.root_hub) {
+			if (usb_hub_clear_tt_buffer(urb) == 0)
+				qh->clearing_tt = 1;
+		}
+	}
+}
+
+static int qtd_copy_status(
+	struct fotg210_hcd *fotg210,
+	struct urb *urb,
+	size_t length,
+	u32 token
+)
+{
+	int	status = -EINPROGRESS;
+
+	/* count IN/OUT bytes, not SETUP (even short packets) */
+	if (likely(QTD_PID(token) != 2))
+		urb->actual_length += length - QTD_LENGTH(token);
+
+	/* don't modify error codes */
+	if (unlikely(urb->unlinked))
+		return status;
+
+	/* force cleanup after short read; not always an error */
+	if (unlikely(IS_SHORT_READ(token)))
+		status = -EREMOTEIO;
+
+	/* serious "can't proceed" faults reported by the hardware */
+	if (token & QTD_STS_HALT) {
+		if (token & QTD_STS_BABBLE) {
+			/* FIXME "must" disable babbling device's port too */
+			status = -EOVERFLOW;
+		/* CERR nonzero + halt --> stall */
+		} else if (QTD_CERR(token)) {
+			status = -EPIPE;
+
+		/* In theory, more than one of the following bits can be set
+		 * since they are sticky and the transaction is retried.
+		 * Which to test first is rather arbitrary.
+		 */
+		} else if (token & QTD_STS_MMF) {
+			/* fs/ls interrupt xfer missed the complete-split */
+			status = -EPROTO;
+		} else if (token & QTD_STS_DBE) {
+			status = (QTD_PID(token) == 1) /* IN ? */
+				? -ENOSR  /* hc couldn't read data */
+				: -ECOMM; /* hc couldn't write data */
+		} else if (token & QTD_STS_XACT) {
+			/* timeout, bad CRC, wrong PID, etc */
+			fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
+				urb->dev->devpath,
+				usb_pipeendpoint(urb->pipe),
+				usb_pipein(urb->pipe) ? "in" : "out");
+			status = -EPROTO;
+		} else {	/* unknown */
+			status = -EPROTO;
+		}
+
+		fotg210_vdbg(fotg210,
+			"dev%d ep%d%s qtd token %08x --> status %d\n",
+			usb_pipedevice(urb->pipe),
+			usb_pipeendpoint(urb->pipe),
+			usb_pipein(urb->pipe) ? "in" : "out",
+			token, status);
+	}
+
+	return status;
+}
+
+static void
+fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb, int status)
+__releases(fotg210->lock)
+__acquires(fotg210->lock)
+{
+	if (likely(urb->hcpriv != NULL)) {
+		struct fotg210_qh	*qh = (struct fotg210_qh *) urb->hcpriv;
+
+		/* S-mask in a QH means it's an interrupt urb */
+		if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
+
+			/* ... update hc-wide periodic stats (for usbfs) */
+			fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
+		}
+	}
+
+	if (unlikely(urb->unlinked)) {
+		COUNT(fotg210->stats.unlink);
+	} else {
+		/* report non-error and short read status as zero */
+		if (status == -EINPROGRESS || status == -EREMOTEIO)
+			status = 0;
+		COUNT(fotg210->stats.complete);
+	}
+
+#ifdef FOTG210_URB_TRACE
+	fotg210_dbg(fotg210,
+		"%s %s urb %p ep%d%s status %d len %d/%d\n",
+		__func__, urb->dev->devpath, urb,
+		usb_pipeendpoint(urb->pipe),
+		usb_pipein(urb->pipe) ? "in" : "out",
+		status,
+		urb->actual_length, urb->transfer_buffer_length);
+#endif
+
+	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+	spin_unlock(&fotg210->lock);
+	usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
+	spin_lock(&fotg210->lock);
+}
+
+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
+
+/*
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current.  Returns number of completions called,
+ * indicating how much "real" work we did.
+ */
+static unsigned
+qh_completions(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	struct fotg210_qtd		*last, *end = qh->dummy;
+	struct list_head	*entry, *tmp;
+	int			last_status;
+	int			stopped;
+	unsigned		count = 0;
+	u8			state;
+	struct fotg210_qh_hw	*hw = qh->hw;
+
+	if (unlikely(list_empty(&qh->qtd_list)))
+		return count;
+
+	/* completions (or tasks on other cpus) must never clobber HALT
+	 * till we've gone through and cleaned everything up, even when
+	 * they add urbs to this qh's queue or mark them for unlinking.
+	 *
+	 * NOTE:  unlinking expects to be done in queue order.
+	 *
+	 * It's a bug for qh->qh_state to be anything other than
+	 * QH_STATE_IDLE, unless our caller is scan_async() or
+	 * scan_intr().
+	 */
+	state = qh->qh_state;
+	qh->qh_state = QH_STATE_COMPLETING;
+	stopped = (state == QH_STATE_IDLE);
+
+ rescan:
+	last = NULL;
+	last_status = -EINPROGRESS;
+	qh->needs_rescan = 0;
+
+	/* remove de-activated QTDs from front of queue.
+	 * after faults (including short reads), cleanup this urb
+	 * then let the queue advance.
+	 * if queue is stopped, handles unlinks.
+	 */
+	list_for_each_safe(entry, tmp, &qh->qtd_list) {
+		struct fotg210_qtd	*qtd;
+		struct urb	*urb;
+		u32		token = 0;
+
+		qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+		urb = qtd->urb;
+
+		/* clean up any state from previous QTD ...*/
+		if (last) {
+			if (likely(last->urb != urb)) {
+				fotg210_urb_done(fotg210, last->urb,
+						 last_status);
+				count++;
+				last_status = -EINPROGRESS;
+			}
+			fotg210_qtd_free(fotg210, last);
+			last = NULL;
+		}
+
+		/* ignore urbs submitted during completions we reported */
+		if (qtd == end)
+			break;
+
+		/* hardware copies qtd out of qh overlay */
+		rmb();
+		token = hc32_to_cpu(fotg210, qtd->hw_token);
+
+		/* always clean up qtds the hc de-activated */
+ retry_xacterr:
+		if ((token & QTD_STS_ACTIVE) == 0) {
+
+			/* Report Data Buffer Error: non-fatal but useful */
+			if (token & QTD_STS_DBE)
+				fotg210_dbg(fotg210,
+					"detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+					urb,
+					usb_endpoint_num(&urb->ep->desc),
+					usb_endpoint_dir_in(&urb->ep->desc)
+						? "in" : "out",
+					urb->transfer_buffer_length,
+					qtd,
+					qh);
+
+			/* on STALL, error, and short reads this urb must
+			 * complete and all its qtds must be recycled.
+			 */
+			if ((token & QTD_STS_HALT) != 0) {
+
+				/* retry transaction errors until we
+				 * reach the software xacterr limit
+				 */
+				if ((token & QTD_STS_XACT) &&
+					QTD_CERR(token) == 0 &&
+					++qh->xacterrs < QH_XACTERR_MAX &&
+					!urb->unlinked) {
+					fotg210_dbg(fotg210,
+	"detected XactErr len %zu/%zu retry %d\n",
+	qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs);
+
+					/* reset the token in the qtd and the
+					 * qh overlay (which still contains
+					 * the qtd) so that we pick up from
+					 * where we left off
+					 */
+					token &= ~QTD_STS_HALT;
+					token |= QTD_STS_ACTIVE |
+						 (FOTG210_TUNE_CERR << 10);
+					qtd->hw_token = cpu_to_hc32(fotg210,
+							token);
+					wmb();
+					hw->hw_token = cpu_to_hc32(fotg210,
+							token);
+					goto retry_xacterr;
+				}
+				stopped = 1;
+
+			/* magic dummy for some short reads; qh won't advance.
+			 * that silicon quirk can kick in with this dummy too.
+			 *
+			 * other short reads won't stop the queue, including
+			 * control transfers (status stage handles that) or
+			 * most other single-qtd reads ... the queue stops if
+			 * URB_SHORT_NOT_OK was set so the driver submitting
+			 * the urbs could clean it up.
+			 */
+			} else if (IS_SHORT_READ(token)
+					&& !(qtd->hw_alt_next
+						& FOTG210_LIST_END(fotg210))) {
+				stopped = 1;
+			}
+
+		/* stop scanning when we reach qtds the hc is using */
+		} else if (likely(!stopped
+				&& fotg210->rh_state >= FOTG210_RH_RUNNING)) {
+			break;
+
+		/* scan the whole queue for unlinks whenever it stops */
+		} else {
+			stopped = 1;
+
+			/* cancel everything if we halt, suspend, etc */
+			if (fotg210->rh_state < FOTG210_RH_RUNNING)
+				last_status = -ESHUTDOWN;
+
+			/* this qtd is active; skip it unless a previous qtd
+			 * for its urb faulted, or its urb was canceled.
+			 */
+			else if (last_status == -EINPROGRESS && !urb->unlinked)
+				continue;
+
+			/* qh unlinked; token in overlay may be most current */
+			if (state == QH_STATE_IDLE
+					&& cpu_to_hc32(fotg210, qtd->qtd_dma)
+						== hw->hw_current) {
+				token = hc32_to_cpu(fotg210, hw->hw_token);
+
+				/* An unlink may leave an incomplete
+				 * async transaction in the TT buffer.
+				 * We have to clear it.
+				 */
+				fotg210_clear_tt_buffer(fotg210, qh, urb,
+							token);
+			}
+		}
+
+		/* unless we already know the urb's status, collect qtd status
+		 * and update count of bytes transferred.  in common short read
+		 * cases with only one data qtd (including control transfers),
+		 * queue processing won't halt.  but with two or more qtds (for
+		 * example, with a 32 KB transfer), when the first qtd gets a
+		 * short read the second must be removed by hand.
+		 */
+		if (last_status == -EINPROGRESS) {
+			last_status = qtd_copy_status(fotg210, urb,
+					qtd->length, token);
+			if (last_status == -EREMOTEIO
+					&& (qtd->hw_alt_next
+						& FOTG210_LIST_END(fotg210)))
+				last_status = -EINPROGRESS;
+
+			/* As part of low/full-speed endpoint-halt processing
+			 * we must clear the TT buffer (11.17.5).
+			 */
+			if (unlikely(last_status != -EINPROGRESS &&
+					last_status != -EREMOTEIO)) {
+				/* The TT's in some hubs malfunction when they
+				 * receive this request following a STALL (they
+				 * stop sending isochronous packets).  Since a
+				 * STALL can't leave the TT buffer in a busy
+				 * state (if you believe Figures 11-48 - 11-51
+				 * in the USB 2.0 spec), we won't clear the TT
+				 * buffer in this case.  Strictly speaking this
+				 * is a violation of the spec.
+				 */
+				if (last_status != -EPIPE)
+					fotg210_clear_tt_buffer(fotg210, qh,
+								urb, token);
+			}
+		}
+
+		/* if we're removing something not at the queue head,
+		 * patch the hardware queue pointer.
+		 */
+		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
+			last = list_entry(qtd->qtd_list.prev,
+					struct fotg210_qtd, qtd_list);
+			last->hw_next = qtd->hw_next;
+		}
+
+		/* remove qtd; it's recycled after possible urb completion */
+		list_del(&qtd->qtd_list);
+		last = qtd;
+
+		/* reinit the xacterr counter for the next qtd */
+		qh->xacterrs = 0;
+	}
+
+	/* last urb's completion might still need calling */
+	if (likely(last != NULL)) {
+		fotg210_urb_done(fotg210, last->urb, last_status);
+		count++;
+		fotg210_qtd_free(fotg210, last);
+	}
+
+	/* Do we need to rescan for URBs dequeued during a giveback? */
+	if (unlikely(qh->needs_rescan)) {
+		/* If the QH is already unlinked, do the rescan now. */
+		if (state == QH_STATE_IDLE)
+			goto rescan;
+
+		/* Otherwise we have to wait until the QH is fully unlinked.
+		 * Our caller will start an unlink if qh->needs_rescan is
+		 * set.  But if an unlink has already started, nothing needs
+		 * to be done.
+		 */
+		if (state != QH_STATE_LINKED)
+			qh->needs_rescan = 0;
+	}
+
+	/* restore original state; caller must unlink or relink */
+	qh->qh_state = state;
+
+	/* be sure the hardware's done with the qh before refreshing
+	 * it after fault cleanup, or recovering from silicon wrongly
+	 * overlaying the dummy qtd (which reduces DMA chatter).
+	 */
+	if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
+		switch (state) {
+		case QH_STATE_IDLE:
+			qh_refresh(fotg210, qh);
+			break;
+		case QH_STATE_LINKED:
+			/* We won't refresh a QH that's linked (after the HC
+			 * stopped the queue).  That avoids a race:
+			 *  - HC reads first part of QH;
+			 *  - CPU updates that first part and the token;
+			 *  - HC reads rest of that QH, including token
+			 * Result:  HC gets an inconsistent image, and then
+			 * DMAs to/from the wrong memory (corrupting it).
+			 *
+			 * That should be rare for interrupt transfers,
+			 * except maybe high bandwidth ...
+			 */
+
+			/* Tell the caller to start an unlink */
+			qh->needs_rescan = 1;
+			break;
+		/* otherwise, unlink already started */
+		}
+	}
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+/* ... and packet size, for any kind of endpoint descriptor */
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/*
+ * reverse of qh_urb_transaction:  free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	struct list_head	*qtd_list
+) {
+	struct list_head	*entry, *temp;
+
+	list_for_each_safe(entry, temp, qtd_list) {
+		struct fotg210_qtd	*qtd;
+
+		qtd = list_entry(entry, struct fotg210_qtd, qtd_list);
+		list_del(&qtd->qtd_list);
+		fotg210_qtd_free(fotg210, qtd);
+	}
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	struct list_head	*head,
+	gfp_t			flags
+) {
+	struct fotg210_qtd		*qtd, *qtd_prev;
+	dma_addr_t		buf;
+	int			len, this_sg_len, maxpacket;
+	int			is_input;
+	u32			token;
+	int			i;
+	struct scatterlist	*sg;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+	qtd = fotg210_qtd_alloc(fotg210, flags);
+	if (unlikely(!qtd))
+		return NULL;
+	list_add_tail(&qtd->qtd_list, head);
+	qtd->urb = urb;
+
+	token = QTD_STS_ACTIVE;
+	token |= (FOTG210_TUNE_CERR << 10);
+	/* for split transactions, SplitXState initialized to zero */
+
+	len = urb->transfer_buffer_length;
+	is_input = usb_pipein(urb->pipe);
+	if (usb_pipecontrol(urb->pipe)) {
+		/* SETUP pid */
+		qtd_fill(fotg210, qtd, urb->setup_dma,
+				sizeof(struct usb_ctrlrequest),
+				token | (2 /* "setup" */ << 8), 8);
+
+		/* ... and always at least one more pid */
+		token ^= QTD_TOGGLE;
+		qtd_prev = qtd;
+		qtd = fotg210_qtd_alloc(fotg210, flags);
+		if (unlikely(!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+		list_add_tail(&qtd->qtd_list, head);
+
+		/* for zero length DATA stages, STATUS is always IN */
+		if (len == 0)
+			token |= (1 /* "in" */ << 8);
+	}
+
+	/*
+	 * data transfer stage:  buffer setup
+	 */
+	i = urb->num_mapped_sgs;
+	if (len > 0 && i > 0) {
+		sg = urb->sg;
+		buf = sg_dma_address(sg);
+
+		/* urb->transfer_buffer_length may be smaller than the
+		 * size of the scatterlist (or vice versa)
+		 */
+		this_sg_len = min_t(int, sg_dma_len(sg), len);
+	} else {
+		sg = NULL;
+		buf = urb->transfer_dma;
+		this_sg_len = len;
+	}
+
+	if (is_input)
+		token |= (1 /* "in" */ << 8);
+	/* else it's already initted to "out" pid (0 << 8) */
+
+	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	for (;;) {
+		int this_qtd_len;
+
+		this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
+				maxpacket);
+		this_sg_len -= this_qtd_len;
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+
+		/*
+		 * short reads advance to a "magic" dummy instead of the next
+		 * qtd ... that forces the queue to stop, for manual cleanup.
+		 * (this will usually be overridden later.)
+		 */
+		if (is_input)
+			qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
+
+		/* qh makes control packets use qtd toggle; maybe switch it */
+		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+			token ^= QTD_TOGGLE;
+
+		if (likely(this_sg_len <= 0)) {
+			if (--i <= 0 || len <= 0)
+				break;
+			sg = sg_next(sg);
+			buf = sg_dma_address(sg);
+			this_sg_len = min_t(int, sg_dma_len(sg), len);
+		}
+
+		qtd_prev = qtd;
+		qtd = fotg210_qtd_alloc(fotg210, flags);
+		if (unlikely(!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+		list_add_tail(&qtd->qtd_list, head);
+	}
+
+	/*
+	 * unless the caller requires manual cleanup after short reads,
+	 * have the alt_next mechanism keep the queue running after the
+	 * last data qtd (the only one, for control and most other cases).
+	 */
+	if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
+				|| usb_pipecontrol(urb->pipe)))
+		qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * other OUT ones may need a terminating short packet
+	 * (zero length).
+	 */
+	if (likely(urb->transfer_buffer_length != 0)) {
+		int	one_more = 0;
+
+		if (usb_pipecontrol(urb->pipe)) {
+			one_more = 1;
+			token ^= 0x0100;	/* "in" <--> "out"  */
+			token |= QTD_TOGGLE;	/* force DATA1 */
+		} else if (usb_pipeout(urb->pipe)
+				&& (urb->transfer_flags & URB_ZERO_PACKET)
+				&& !(urb->transfer_buffer_length % maxpacket)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd_prev = qtd;
+			qtd = fotg210_qtd_alloc(fotg210, flags);
+			if (unlikely(!qtd))
+				goto cleanup;
+			qtd->urb = urb;
+			qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
+			list_add_tail(&qtd->qtd_list, head);
+
+			/* never any data in such packets */
+			qtd_fill(fotg210, qtd, 0, 0, token, 0);
+		}
+	}
+
+	/* by default, enable interrupt on urb completion */
+	if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
+		qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
+	return head;
+
+cleanup:
+	qtd_list_free(fotg210, urb, head);
+	return NULL;
+}
+
+/*-------------------------------------------------------------------------*/
+/*
+ * Would be best to create all qh's from config descriptors,
+ * when each interface/altsetting is established.  Unlink
+ * any previous qh and cancel its urbs first; endpoints are
+ * implicitly reset then (data toggle too).
+ * That'd mean updating how usbcore talks to HCDs. (2.7?)
+*/
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct fotg210_qh *
+qh_make(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	gfp_t			flags
+) {
+	struct fotg210_qh		*qh = fotg210_qh_alloc(fotg210, flags);
+	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
+	struct usb_tt		*tt = urb->dev->tt;
+	struct fotg210_qh_hw	*hw;
+
+	if (!qh)
+		return qh;
+
+	/*
+	 * init endpoint/device data for this QH
+	 */
+	info1 |= usb_pipeendpoint(urb->pipe) << 8;
+	info1 |= usb_pipedevice(urb->pipe) << 0;
+
+	is_input = usb_pipein(urb->pipe);
+	type = usb_pipetype(urb->pipe);
+	maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input);
+
+	/* 1024 byte maxpacket is a hardware ceiling.  High bandwidth
+	 * acts like up to 3KB, but is built from smaller packets.
+	 */
+	if (max_packet(maxp) > 1024) {
+		fotg210_dbg(fotg210, "bogus qh maxpacket %d\n",
+			    max_packet(maxp));
+		goto done;
+	}
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+				is_input, 0,
+				hb_mult(maxp) * max_packet(maxp)));
+		qh->start = NO_FRAME;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			qh->period = urb->interval >> 3;
+			if (qh->period == 0 && urb->interval != 1) {
+				/* NOTE interval 2 or 4 uframes could work.
+				 * But interval 1 scheduling is simpler, and
+				 * includes high bandwidth.
+				 */
+				urb->interval = 1;
+			} else if (qh->period > fotg210->periodic_size) {
+				qh->period = fotg210->periodic_size;
+				urb->interval = qh->period << 3;
+			}
+		} else {
+			int		think_time;
+
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		/* SPLIT, gap, CSPLIT+DATA */
+				qh->c_usecs = qh->usecs + HS_USECS(0);
+				qh->usecs = HS_USECS(1);
+			} else {		/* SPLIT+DATA, gap, CSPLIT */
+				qh->usecs += HS_USECS(1);
+				qh->c_usecs = HS_USECS(0);
+			}
+
+			think_time = tt ? tt->think_time : 0;
+			qh->tt_usecs = NS_TO_US(think_time +
+					usb_calc_bus_time(urb->dev->speed,
+					is_input, 0, max_packet(maxp)));
+			qh->period = urb->interval;
+			if (qh->period > fotg210->periodic_size) {
+				qh->period = fotg210->periodic_size;
+				urb->interval = qh->period;
+			}
+		}
+	}
+
+	/* support for tt scheduling, and access to toggles */
+	qh->dev = urb->dev;
+
+	/* using TT? */
+	switch (urb->dev->speed) {
+	case USB_SPEED_LOW:
+		info1 |= QH_LOW_SPEED;
+		/* FALL THROUGH */
+
+	case USB_SPEED_FULL:
+		/* EPS 0 means "full" */
+		if (type != PIPE_INTERRUPT)
+			info1 |= (FOTG210_TUNE_RL_TT << 28);
+		if (type == PIPE_CONTROL) {
+			info1 |= QH_CONTROL_EP;		/* for TT */
+			info1 |= QH_TOGGLE_CTL;		/* toggle from qtd */
+		}
+		info1 |= maxp << 16;
+
+		info2 |= (FOTG210_TUNE_MULT_TT << 30);
+
+		/* Some Freescale processors have an erratum in which the
+		 * port number in the queue head was 0..N-1 instead of 1..N.
+		 */
+		if (fotg210_has_fsl_portno_bug(fotg210))
+			info2 |= (urb->dev->ttport-1) << 23;
+		else
+			info2 |= urb->dev->ttport << 23;
+
+		/* set the address of the TT; for TDI's integrated
+		 * root hub tt, leave it zeroed.
+		 */
+		if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
+			info2 |= tt->hub->devnum << 16;
+
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
+		break;
+
+	case USB_SPEED_HIGH:		/* no TT involved */
+		info1 |= QH_HIGH_SPEED;
+		if (type == PIPE_CONTROL) {
+			info1 |= (FOTG210_TUNE_RL_HS << 28);
+			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
+			info1 |= QH_TOGGLE_CTL;	/* toggle from qtd */
+			info2 |= (FOTG210_TUNE_MULT_HS << 30);
+		} else if (type == PIPE_BULK) {
+			info1 |= (FOTG210_TUNE_RL_HS << 28);
+			/* The USB spec says that high speed bulk endpoints
+			 * always use 512 byte maxpacket.  But some device
+			 * vendors decided to ignore that, and MSFT is happy
+			 * to help them do so.  So now people expect to use
+			 * such nonconformant devices with Linux too; sigh.
+			 */
+			info1 |= max_packet(maxp) << 16;
+			info2 |= (FOTG210_TUNE_MULT_HS << 30);
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet(maxp) << 16;
+			info2 |= hb_mult(maxp) << 30;
+		}
+		break;
+	default:
+		fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
+			urb->dev->speed);
+done:
+		qh_destroy(fotg210, qh);
+		return NULL;
+	}
+
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+	/* init as live, toggle clear, advance to dummy */
+	qh->qh_state = QH_STATE_IDLE;
+	hw = qh->hw;
+	hw->hw_info1 = cpu_to_hc32(fotg210, info1);
+	hw->hw_info2 = cpu_to_hc32(fotg210, info2);
+	qh->is_out = !is_input;
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
+	qh_refresh(fotg210, qh);
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void enable_async(struct fotg210_hcd *fotg210)
+{
+	if (fotg210->async_count++)
+		return;
+
+	/* Stop waiting to turn off the async schedule */
+	fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
+
+	/* Don't start the schedule until ASS is 0 */
+	fotg210_poll_ASS(fotg210);
+	turn_on_io_watchdog(fotg210);
+}
+
+static void disable_async(struct fotg210_hcd *fotg210)
+{
+	if (--fotg210->async_count)
+		return;
+
+	/* The async schedule and async_unlink list are supposed to be empty */
+	WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
+
+	/* Don't turn off the schedule until ASS is 1 */
+	fotg210_poll_ASS(fotg210);
+}
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	__hc32		dma = QH_NEXT(fotg210, qh->qh_dma);
+	struct fotg210_qh	*head;
+
+	/* Don't link a QH if there's a Clear-TT-Buffer pending */
+	if (unlikely(qh->clearing_tt))
+		return;
+
+	WARN_ON(qh->qh_state != QH_STATE_IDLE);
+
+	/* clear halt and/or toggle; and maybe recover from silicon quirk */
+	qh_refresh(fotg210, qh);
+
+	/* splice right after start */
+	head = fotg210->async;
+	qh->qh_next = head->qh_next;
+	qh->hw->hw_next = head->hw->hw_next;
+	wmb();
+
+	head->qh_next.qh = qh;
+	head->hw->hw_next = dma;
+
+	qh->xacterrs = 0;
+	qh->qh_state = QH_STATE_LINKED;
+	/* qtd completions reported later by interrupt */
+
+	enable_async(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct fotg210_qh *qh_append_tds(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			epnum,
+	void			**ptr
+)
+{
+	struct fotg210_qh		*qh = NULL;
+	__hc32			qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
+
+	qh = (struct fotg210_qh *) *ptr;
+	if (unlikely(qh == NULL)) {
+		/* can't sleep here, we have fotg210->lock... */
+		qh = qh_make(fotg210, urb, GFP_ATOMIC);
+		*ptr = qh;
+	}
+	if (likely(qh != NULL)) {
+		struct fotg210_qtd	*qtd;
+
+		if (unlikely(list_empty(qtd_list)))
+			qtd = NULL;
+		else
+			qtd = list_entry(qtd_list->next, struct fotg210_qtd,
+					qtd_list);
+
+		/* control qh may need patching ... */
+		if (unlikely(epnum == 0)) {
+			/* usb_reset_device() briefly reverts to address 0 */
+			if (usb_pipedevice(urb->pipe) == 0)
+				qh->hw->hw_info1 &= ~qh_addr_mask;
+		}
+
+		/* just one way to queue requests: swap with the dummy qtd.
+		 * only hc or qh_refresh() ever modify the overlay.
+		 */
+		if (likely(qtd != NULL)) {
+			struct fotg210_qtd		*dummy;
+			dma_addr_t		dma;
+			__hc32			token;
+
+			/* to avoid racing the HC, use the dummy td instead of
+			 * the first td of our list (becomes new dummy).  both
+			 * tds stay deactivated until we're done, when the
+			 * HC is allowed to fetch the old dummy (4.10.2).
+			 */
+			token = qtd->hw_token;
+			qtd->hw_token = HALT_BIT(fotg210);
+
+			dummy = qh->dummy;
+
+			dma = dummy->qtd_dma;
+			*dummy = *qtd;
+			dummy->qtd_dma = dma;
+
+			list_del(&qtd->qtd_list);
+			list_add(&dummy->qtd_list, qtd_list);
+			list_splice_tail(qtd_list, &qh->qtd_list);
+
+			fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
+			qh->dummy = qtd;
+
+			/* hc must see the new dummy at list end */
+			dma = qtd->qtd_dma;
+			qtd = list_entry(qh->qtd_list.prev,
+					struct fotg210_qtd, qtd_list);
+			qtd->hw_next = QTD_NEXT(fotg210, dma);
+
+			/* let the hc process these next qtds */
+			wmb();
+			dummy->hw_token = token;
+
+			urb->hcpriv = qh;
+		}
+	}
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	gfp_t			mem_flags
+) {
+	int			epnum;
+	unsigned long		flags;
+	struct fotg210_qh		*qh = NULL;
+	int			rc;
+
+	epnum = urb->ep->desc.bEndpointAddress;
+
+#ifdef FOTG210_URB_TRACE
+	{
+		struct fotg210_qtd *qtd;
+		qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
+		fotg210_dbg(fotg210,
+			 "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+			 __func__, urb->dev->devpath, urb,
+			 epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
+			 urb->transfer_buffer_length,
+			 qtd, urb->ep->hcpriv);
+	}
+#endif
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+		rc = -ESHUTDOWN;
+		goto done;
+	}
+	rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+	if (unlikely(rc))
+		goto done;
+
+	qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
+	if (unlikely(qh == NULL)) {
+		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	/* Control/bulk operations through TTs don't need scheduling,
+	 * the HC and TT handle it when the TT has a buffer ready.
+	 */
+	if (likely(qh->qh_state == QH_STATE_IDLE))
+		qh_link_async(fotg210, qh);
+ done:
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	if (unlikely(qh == NULL))
+		qtd_list_free(fotg210, urb, qtd_list);
+	return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void single_unlink_async(struct fotg210_hcd *fotg210,
+				struct fotg210_qh *qh)
+{
+	struct fotg210_qh		*prev;
+
+	/* Add to the end of the list of QHs waiting for the next IAAD */
+	qh->qh_state = QH_STATE_UNLINK;
+	if (fotg210->async_unlink)
+		fotg210->async_unlink_last->unlink_next = qh;
+	else
+		fotg210->async_unlink = qh;
+	fotg210->async_unlink_last = qh;
+
+	/* Unlink it from the schedule */
+	prev = fotg210->async;
+	while (prev->qh_next.qh != qh)
+		prev = prev->qh_next.qh;
+
+	prev->hw->hw_next = qh->hw->hw_next;
+	prev->qh_next = qh->qh_next;
+	if (fotg210->qh_scan_next == qh)
+		fotg210->qh_scan_next = qh->qh_next.qh;
+}
+
+static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
+{
+	/*
+	 * Do nothing if an IAA cycle is already running or
+	 * if one will be started shortly.
+	 */
+	if (fotg210->async_iaa || fotg210->async_unlinking)
+		return;
+
+	/* Do all the waiting QHs at once */
+	fotg210->async_iaa = fotg210->async_unlink;
+	fotg210->async_unlink = NULL;
+
+	/* If the controller isn't running, we don't have to wait for it */
+	if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
+		if (!nested)		/* Avoid recursion */
+			end_unlink_async(fotg210);
+
+	/* Otherwise start a new IAA cycle */
+	} else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
+		/* Make sure the unlinks are all visible to the hardware */
+		wmb();
+
+		fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
+				&fotg210->regs->command);
+		fotg210_readl(fotg210, &fotg210->regs->command);
+		fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
+				     true);
+	}
+}
+
+/* the async qh for the qtds being unlinked are now gone from the HC */
+
+static void end_unlink_async(struct fotg210_hcd *fotg210)
+{
+	struct fotg210_qh		*qh;
+
+	/* Process the idle QHs */
+ restart:
+	fotg210->async_unlinking = true;
+	while (fotg210->async_iaa) {
+		qh = fotg210->async_iaa;
+		fotg210->async_iaa = qh->unlink_next;
+		qh->unlink_next = NULL;
+
+		qh->qh_state = QH_STATE_IDLE;
+		qh->qh_next.qh = NULL;
+
+		qh_completions(fotg210, qh);
+		if (!list_empty(&qh->qtd_list) &&
+				fotg210->rh_state == FOTG210_RH_RUNNING)
+			qh_link_async(fotg210, qh);
+		disable_async(fotg210);
+	}
+	fotg210->async_unlinking = false;
+
+	/* Start a new IAA cycle if any QHs are waiting for it */
+	if (fotg210->async_unlink) {
+		start_iaa_cycle(fotg210, true);
+		if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
+			goto restart;
+	}
+}
+
+static void unlink_empty_async(struct fotg210_hcd *fotg210)
+{
+	struct fotg210_qh *qh, *next;
+	bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
+	bool check_unlinks_later = false;
+
+	/* Unlink all the async QHs that have been empty for a timer cycle */
+	next = fotg210->async->qh_next.qh;
+	while (next) {
+		qh = next;
+		next = qh->qh_next.qh;
+
+		if (list_empty(&qh->qtd_list) &&
+				qh->qh_state == QH_STATE_LINKED) {
+			if (!stopped && qh->unlink_cycle ==
+					fotg210->async_unlink_cycle)
+				check_unlinks_later = true;
+			else
+				single_unlink_async(fotg210, qh);
+		}
+	}
+
+	/* Start a new IAA cycle if any QHs are waiting for it */
+	if (fotg210->async_unlink)
+		start_iaa_cycle(fotg210, false);
+
+	/* QHs that haven't been empty for long enough will be handled later */
+	if (check_unlinks_later) {
+		fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
+				     true);
+		++fotg210->async_unlink_cycle;
+	}
+}
+
+/* makes sure the async qh will become idle */
+/* caller must own fotg210->lock */
+
+static void start_unlink_async(struct fotg210_hcd *fotg210,
+			       struct fotg210_qh *qh)
+{
+	/*
+	 * If the QH isn't linked then there's nothing we can do
+	 * unless we were called during a giveback, in which case
+	 * qh_completions() has to deal with it.
+	 */
+	if (qh->qh_state != QH_STATE_LINKED) {
+		if (qh->qh_state == QH_STATE_COMPLETING)
+			qh->needs_rescan = 1;
+		return;
+	}
+
+	single_unlink_async(fotg210, qh);
+	start_iaa_cycle(fotg210, false);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_async(struct fotg210_hcd *fotg210)
+{
+	struct fotg210_qh		*qh;
+	bool			check_unlinks_later = false;
+
+	fotg210->qh_scan_next = fotg210->async->qh_next.qh;
+	while (fotg210->qh_scan_next) {
+		qh = fotg210->qh_scan_next;
+		fotg210->qh_scan_next = qh->qh_next.qh;
+ rescan:
+		/* clean any finished work for this qh */
+		if (!list_empty(&qh->qtd_list)) {
+			int temp;
+
+			/*
+			 * Unlinks could happen here; completion reporting
+			 * drops the lock.  That's why fotg210->qh_scan_next
+			 * always holds the next qh to scan; if the next qh
+			 * gets unlinked then fotg210->qh_scan_next is adjusted
+			 * in single_unlink_async().
+			 */
+			temp = qh_completions(fotg210, qh);
+			if (qh->needs_rescan) {
+				start_unlink_async(fotg210, qh);
+			} else if (list_empty(&qh->qtd_list)
+					&& qh->qh_state == QH_STATE_LINKED) {
+				qh->unlink_cycle = fotg210->async_unlink_cycle;
+				check_unlinks_later = true;
+			} else if (temp != 0)
+				goto rescan;
+		}
+	}
+
+	/*
+	 * Unlink empty entries, reducing DMA usage as well
+	 * as HCD schedule-scanning costs.  Delay for any qh
+	 * we just scanned, there's a not-unusual case that it
+	 * doesn't stay idle for long.
+	 */
+	if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING &&
+			!(fotg210->enabled_hrtimer_events &
+				BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
+		fotg210_enable_event(fotg210,
+				     FOTG210_HRTIMER_ASYNC_UNLINKS, true);
+		++fotg210->async_unlink_cycle;
+	}
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ *
+ * Note that for interrupt transfers, the QH/QTD manipulation is shared
+ * with the "asynchronous" transaction support (control/bulk transfers).
+ * The only real difference is in how interrupt transfers are scheduled.
+ *
+ * For ISO, we make an "iso_stream" head to serve the same role as a QH.
+ * It keeps track of every ITD (or SITD) that's linked, and holds enough
+ * pre-calculated schedule data to make appending to the queue be quick.
+ */
+
+static int fotg210_get_frame(struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd
+ * @tag: hardware tag for type of this record
+ */
+static union fotg210_shadow *
+periodic_next_shadow(struct fotg210_hcd *fotg210,
+		     union fotg210_shadow *periodic, __hc32 tag)
+{
+	switch (hc32_to_cpu(fotg210, tag)) {
+	case Q_TYPE_QH:
+		return &periodic->qh->qh_next;
+	case Q_TYPE_FSTN:
+		return &periodic->fstn->fstn_next;
+	default:
+		return &periodic->itd->itd_next;
+	}
+}
+
+static __hc32 *
+shadow_next_periodic(struct fotg210_hcd *fotg210,
+		     union fotg210_shadow *periodic, __hc32 tag)
+{
+	switch (hc32_to_cpu(fotg210, tag)) {
+	/* our fotg210_shadow.qh is actually software part */
+	case Q_TYPE_QH:
+		return &periodic->qh->hw->hw_next;
+	/* others are hw parts */
+	default:
+		return periodic->hw_next;
+	}
+}
+
+/* caller must hold fotg210->lock */
+static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
+			    void *ptr)
+{
+	union fotg210_shadow	*prev_p = &fotg210->pshadow[frame];
+	__hc32			*hw_p = &fotg210->periodic[frame];
+	union fotg210_shadow	here = *prev_p;
+
+	/* find predecessor of "ptr"; hw and shadow lists are in sync */
+	while (here.ptr && here.ptr != ptr) {
+		prev_p = periodic_next_shadow(fotg210, prev_p,
+				Q_NEXT_TYPE(fotg210, *hw_p));
+		hw_p = shadow_next_periodic(fotg210, &here,
+				Q_NEXT_TYPE(fotg210, *hw_p));
+		here = *prev_p;
+	}
+	/* an interrupt entry (at list end) could have been shared */
+	if (!here.ptr)
+		return;
+
+	/* update shadow and hardware lists ... the old "next" pointers
+	 * from ptr may still be in use, the caller updates them.
+	 */
+	*prev_p = *periodic_next_shadow(fotg210, &here,
+			Q_NEXT_TYPE(fotg210, *hw_p));
+
+	*hw_p = *shadow_next_periodic(fotg210, &here,
+				Q_NEXT_TYPE(fotg210, *hw_p));
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe)
+{
+	__hc32			*hw_p = &fotg210->periodic[frame];
+	union fotg210_shadow	*q = &fotg210->pshadow[frame];
+	unsigned		usecs = 0;
+	struct fotg210_qh_hw	*hw;
+
+	while (q->ptr) {
+		switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
+		case Q_TYPE_QH:
+			hw = q->qh->hw;
+			/* is it in the S-mask? */
+			if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
+				usecs += q->qh->usecs;
+			/* ... or C-mask? */
+			if (hw->hw_info2 & cpu_to_hc32(fotg210,
+					1 << (8 + uframe)))
+				usecs += q->qh->c_usecs;
+			hw_p = &hw->hw_next;
+			q = &q->qh->qh_next;
+			break;
+		/* case Q_TYPE_FSTN: */
+		default:
+			/* for "save place" FSTNs, count the relevant INTR
+			 * bandwidth from the previous frame
+			 */
+			if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
+				fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
+
+			hw_p = &q->fstn->hw_next;
+			q = &q->fstn->fstn_next;
+			break;
+		case Q_TYPE_ITD:
+			if (q->itd->hw_transaction[uframe])
+				usecs += q->itd->stream->usecs;
+			hw_p = &q->itd->hw_next;
+			q = &q->itd->itd_next;
+			break;
+		}
+	}
+#ifdef	DEBUG
+	if (usecs > fotg210->uframe_periodic_max)
+		fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
+			frame * 8 + uframe, usecs);
+#endif
+	return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int same_tt(struct usb_device *dev1, struct usb_device *dev2)
+{
+	if (!dev1->tt || !dev2->tt)
+		return 0;
+	if (dev1->tt != dev2->tt)
+		return 0;
+	if (dev1->tt->multi)
+		return dev1->ttport == dev2->ttport;
+	else
+		return 1;
+}
+
+/* return true iff the device's transaction translator is available
+ * for a periodic transfer starting at the specified frame, using
+ * all the uframes in the mask.
+ */
+static int tt_no_collision(
+	struct fotg210_hcd		*fotg210,
+	unsigned		period,
+	struct usb_device	*dev,
+	unsigned		frame,
+	u32			uf_mask
+)
+{
+	if (period == 0)	/* error */
+		return 0;
+
+	/* note bandwidth wastage:  split never follows csplit
+	 * (different dev or endpoint) until the next uframe.
+	 * calling convention doesn't make that distinction.
+	 */
+	for (; frame < fotg210->periodic_size; frame += period) {
+		union fotg210_shadow	here;
+		__hc32			type;
+		struct fotg210_qh_hw	*hw;
+
+		here = fotg210->pshadow[frame];
+		type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
+		while (here.ptr) {
+			switch (hc32_to_cpu(fotg210, type)) {
+			case Q_TYPE_ITD:
+				type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
+				here = here.itd->itd_next;
+				continue;
+			case Q_TYPE_QH:
+				hw = here.qh->hw;
+				if (same_tt(dev, here.qh->dev)) {
+					u32		mask;
+
+					mask = hc32_to_cpu(fotg210,
+							hw->hw_info2);
+					/* "knows" no gap is needed */
+					mask |= mask >> 8;
+					if (mask & uf_mask)
+						break;
+				}
+				type = Q_NEXT_TYPE(fotg210, hw->hw_next);
+				here = here.qh->qh_next;
+				continue;
+			/* case Q_TYPE_FSTN: */
+			default:
+				fotg210_dbg(fotg210,
+					"periodic frame %d bogus type %d\n",
+					frame, type);
+			}
+
+			/* collision or error */
+			return 0;
+		}
+	}
+
+	/* no collision */
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void enable_periodic(struct fotg210_hcd *fotg210)
+{
+	if (fotg210->periodic_count++)
+		return;
+
+	/* Stop waiting to turn off the periodic schedule */
+	fotg210->enabled_hrtimer_events &=
+		~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
+
+	/* Don't start the schedule until PSS is 0 */
+	fotg210_poll_PSS(fotg210);
+	turn_on_io_watchdog(fotg210);
+}
+
+static void disable_periodic(struct fotg210_hcd *fotg210)
+{
+	if (--fotg210->periodic_count)
+		return;
+
+	/* Don't turn off the schedule until PSS is 1 */
+	fotg210_poll_PSS(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* periodic schedule slots have iso tds (normal or split) first, then a
+ * sparse tree for active interrupt transfers.
+ *
+ * this just links in a qh; caller guarantees uframe masks are set right.
+ * no FSTN support (yet; fotg210 0.96+)
+ */
+static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	unsigned	i;
+	unsigned	period = qh->period;
+
+	dev_dbg(&qh->dev->dev,
+		"link qh%d-%04x/%p start %d [%d/%d us]\n",
+		period, hc32_to_cpup(fotg210, &qh->hw->hw_info2)
+			& (QH_CMASK | QH_SMASK),
+		qh, qh->start, qh->usecs, qh->c_usecs);
+
+	/* high bandwidth, or otherwise every microframe */
+	if (period == 0)
+		period = 1;
+
+	for (i = qh->start; i < fotg210->periodic_size; i += period) {
+		union fotg210_shadow	*prev = &fotg210->pshadow[i];
+		__hc32			*hw_p = &fotg210->periodic[i];
+		union fotg210_shadow	here = *prev;
+		__hc32			type = 0;
+
+		/* skip the iso nodes at list head */
+		while (here.ptr) {
+			type = Q_NEXT_TYPE(fotg210, *hw_p);
+			if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
+				break;
+			prev = periodic_next_shadow(fotg210, prev, type);
+			hw_p = shadow_next_periodic(fotg210, &here, type);
+			here = *prev;
+		}
+
+		/* sorting each branch by period (slow-->fast)
+		 * enables sharing interior tree nodes
+		 */
+		while (here.ptr && qh != here.qh) {
+			if (qh->period > here.qh->period)
+				break;
+			prev = &here.qh->qh_next;
+			hw_p = &here.qh->hw->hw_next;
+			here = *prev;
+		}
+		/* link in this qh, unless some earlier pass did that */
+		if (qh != here.qh) {
+			qh->qh_next = here;
+			if (here.qh)
+				qh->hw->hw_next = *hw_p;
+			wmb();
+			prev->qh = qh;
+			*hw_p = QH_NEXT(fotg210, qh->qh_dma);
+		}
+	}
+	qh->qh_state = QH_STATE_LINKED;
+	qh->xacterrs = 0;
+
+	/* update per-qh bandwidth for usbfs */
+	fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
+		? ((qh->usecs + qh->c_usecs) / qh->period)
+		: (qh->usecs * 8);
+
+	list_add(&qh->intr_node, &fotg210->intr_qh_list);
+
+	/* maybe enable periodic schedule processing */
+	++fotg210->intr_count;
+	enable_periodic(fotg210);
+}
+
+static void qh_unlink_periodic(struct fotg210_hcd *fotg210,
+			       struct fotg210_qh *qh)
+{
+	unsigned	i;
+	unsigned	period;
+
+	/*
+	 * If qh is for a low/full-speed device, simply unlinking it
+	 * could interfere with an ongoing split transaction.  To unlink
+	 * it safely would require setting the QH_INACTIVATE bit and
+	 * waiting at least one frame, as described in EHCI 4.12.2.5.
+	 *
+	 * We won't bother with any of this.  Instead, we assume that the
+	 * only reason for unlinking an interrupt QH while the current URB
+	 * is still active is to dequeue all the URBs (flush the whole
+	 * endpoint queue).
+	 *
+	 * If rebalancing the periodic schedule is ever implemented, this
+	 * approach will no longer be valid.
+	 */
+
+	/* high bandwidth, or otherwise part of every microframe */
+	period = qh->period;
+	if (!period)
+		period = 1;
+
+	for (i = qh->start; i < fotg210->periodic_size; i += period)
+		periodic_unlink(fotg210, i, qh);
+
+	/* update per-qh bandwidth for usbfs */
+	fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
+		? ((qh->usecs + qh->c_usecs) / qh->period)
+		: (qh->usecs * 8);
+
+	dev_dbg(&qh->dev->dev,
+		"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+		qh->period,
+		hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
+		(QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs, qh->c_usecs);
+
+	/* qh->qh_next still "live" to HC */
+	qh->qh_state = QH_STATE_UNLINK;
+	qh->qh_next.ptr = NULL;
+
+	if (fotg210->qh_scan_next == qh)
+		fotg210->qh_scan_next = list_entry(qh->intr_node.next,
+				struct fotg210_qh, intr_node);
+	list_del(&qh->intr_node);
+}
+
+static void start_unlink_intr(struct fotg210_hcd *fotg210,
+			      struct fotg210_qh *qh)
+{
+	/* If the QH isn't linked then there's nothing we can do
+	 * unless we were called during a giveback, in which case
+	 * qh_completions() has to deal with it.
+	 */
+	if (qh->qh_state != QH_STATE_LINKED) {
+		if (qh->qh_state == QH_STATE_COMPLETING)
+			qh->needs_rescan = 1;
+		return;
+	}
+
+	qh_unlink_periodic(fotg210, qh);
+
+	/* Make sure the unlinks are visible before starting the timer */
+	wmb();
+
+	/*
+	 * The EHCI spec doesn't say how long it takes the controller to
+	 * stop accessing an unlinked interrupt QH.  The timer delay is
+	 * 9 uframes; presumably that will be long enough.
+	 */
+	qh->unlink_cycle = fotg210->intr_unlink_cycle;
+
+	/* New entries go at the end of the intr_unlink list */
+	if (fotg210->intr_unlink)
+		fotg210->intr_unlink_last->unlink_next = qh;
+	else
+		fotg210->intr_unlink = qh;
+	fotg210->intr_unlink_last = qh;
+
+	if (fotg210->intr_unlinking)
+		;	/* Avoid recursive calls */
+	else if (fotg210->rh_state < FOTG210_RH_RUNNING)
+		fotg210_handle_intr_unlinks(fotg210);
+	else if (fotg210->intr_unlink == qh) {
+		fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
+				     true);
+		++fotg210->intr_unlink_cycle;
+	}
+}
+
+static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	struct fotg210_qh_hw	*hw = qh->hw;
+	int			rc;
+
+	qh->qh_state = QH_STATE_IDLE;
+	hw->hw_next = FOTG210_LIST_END(fotg210);
+
+	qh_completions(fotg210, qh);
+
+	/* reschedule QH iff another request is queued */
+	if (!list_empty(&qh->qtd_list) &&
+	    fotg210->rh_state == FOTG210_RH_RUNNING) {
+		rc = qh_schedule(fotg210, qh);
+
+		/* An error here likely indicates handshake failure
+		 * or no space left in the schedule.  Neither fault
+		 * should happen often ...
+		 *
+		 * FIXME kill the now-dysfunctional queued urbs
+		 */
+		if (rc != 0)
+			fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
+					qh, rc);
+	}
+
+	/* maybe turn off periodic schedule */
+	--fotg210->intr_count;
+	disable_periodic(fotg210);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int check_period(
+	struct fotg210_hcd *fotg210,
+	unsigned	frame,
+	unsigned	uframe,
+	unsigned	period,
+	unsigned	usecs
+) {
+	int		claimed;
+
+	/* complete split running into next frame?
+	 * given FSTN support, we could sometimes check...
+	 */
+	if (uframe >= 8)
+		return 0;
+
+	/* convert "usecs we need" to "max already claimed" */
+	usecs = fotg210->uframe_periodic_max - usecs;
+
+	/* we "know" 2 and 4 uframe intervals were rejected; so
+	 * for period 0, check _every_ microframe in the schedule.
+	 */
+	if (unlikely(period == 0)) {
+		do {
+			for (uframe = 0; uframe < 7; uframe++) {
+				claimed = periodic_usecs(fotg210, frame,
+							 uframe);
+				if (claimed > usecs)
+					return 0;
+			}
+		} while ((frame += 1) < fotg210->periodic_size);
+
+	/* just check the specified uframe, at that period */
+	} else {
+		do {
+			claimed = periodic_usecs(fotg210, frame, uframe);
+			if (claimed > usecs)
+				return 0;
+		} while ((frame += period) < fotg210->periodic_size);
+	}
+
+	/* success! */
+	return 1;
+}
+
+static int check_intr_schedule(
+	struct fotg210_hcd		*fotg210,
+	unsigned		frame,
+	unsigned		uframe,
+	const struct fotg210_qh	*qh,
+	__hc32			*c_maskp
+)
+{
+	int		retval = -ENOSPC;
+	u8		mask = 0;
+
+	if (qh->c_usecs && uframe >= 6)		/* FSTN territory? */
+		goto done;
+
+	if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
+		goto done;
+	if (!qh->c_usecs) {
+		retval = 0;
+		*c_maskp = 0;
+		goto done;
+	}
+
+	/* Make sure this tt's buffer is also available for CSPLITs.
+	 * We pessimize a bit; probably the typical full speed case
+	 * doesn't need the second CSPLIT.
+	 *
+	 * NOTE:  both SPLIT and CSPLIT could be checked in just
+	 * one smart pass...
+	 */
+	mask = 0x03 << (uframe + qh->gap_uf);
+	*c_maskp = cpu_to_hc32(fotg210, mask << 8);
+
+	mask |= 1 << uframe;
+	if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
+		if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
+					qh->period, qh->c_usecs))
+			goto done;
+		if (!check_period(fotg210, frame, uframe + qh->gap_uf,
+					qh->period, qh->c_usecs))
+			goto done;
+		retval = 0;
+	}
+done:
+	return retval;
+}
+
+/* "first fit" scheduling policy used the first time through,
+ * or when the previous schedule slot can't be re-used.
+ */
+static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
+{
+	int		status;
+	unsigned	uframe;
+	__hc32		c_mask;
+	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
+	struct fotg210_qh_hw	*hw = qh->hw;
+
+	qh_refresh(fotg210, qh);
+	hw->hw_next = FOTG210_LIST_END(fotg210);
+	frame = qh->start;
+
+	/* reuse the previous schedule slots, if we can */
+	if (frame < qh->period) {
+		uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
+		status = check_intr_schedule(fotg210, frame, --uframe,
+				qh, &c_mask);
+	} else {
+		uframe = 0;
+		c_mask = 0;
+		status = -ENOSPC;
+	}
+
+	/* else scan the schedule to find a group of slots such that all
+	 * uframes have enough periodic bandwidth available.
+	 */
+	if (status) {
+		/* "normal" case, uframing flexible except with splits */
+		if (qh->period) {
+			int		i;
+
+			for (i = qh->period; status && i > 0; --i) {
+				frame = ++fotg210->random_frame % qh->period;
+				for (uframe = 0; uframe < 8; uframe++) {
+					status = check_intr_schedule(fotg210,
+							frame, uframe, qh,
+							&c_mask);
+					if (status == 0)
+						break;
+				}
+			}
+
+		/* qh->period == 0 means every uframe */
+		} else {
+			frame = 0;
+			status = check_intr_schedule(fotg210, 0, 0, qh,
+						     &c_mask);
+		}
+		if (status)
+			goto done;
+		qh->start = frame;
+
+		/* reset S-frame and (maybe) C-frame masks */
+		hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
+		hw->hw_info2 |= qh->period
+			? cpu_to_hc32(fotg210, 1 << uframe)
+			: cpu_to_hc32(fotg210, QH_SMASK);
+		hw->hw_info2 |= c_mask;
+	} else
+		fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
+
+	/* stuff into the periodic schedule */
+	qh_link_periodic(fotg210, qh);
+done:
+	return status;
+}
+
+static int intr_submit(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	gfp_t			mem_flags
+) {
+	unsigned		epnum;
+	unsigned long		flags;
+	struct fotg210_qh		*qh;
+	int			status;
+	struct list_head	empty;
+
+	/* get endpoint and transfer/schedule data */
+	epnum = urb->ep->desc.bEndpointAddress;
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+
+	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+		status = -ESHUTDOWN;
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+
+	/* get qh and force any scheduling errors */
+	INIT_LIST_HEAD(&empty);
+	qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
+	if (qh == NULL) {
+		status = -ENOMEM;
+		goto done;
+	}
+	if (qh->qh_state == QH_STATE_IDLE) {
+		status = qh_schedule(fotg210, qh);
+		if (status)
+			goto done;
+	}
+
+	/* then queue the urb's tds to the qh */
+	qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
+	BUG_ON(qh == NULL);
+
+	/* ... update usbfs periodic stats */
+	fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
+
+done:
+	if (unlikely(status))
+		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+done_not_linked:
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	if (status)
+		qtd_list_free(fotg210, urb, qtd_list);
+
+	return status;
+}
+
+static void scan_intr(struct fotg210_hcd *fotg210)
+{
+	struct fotg210_qh		*qh;
+
+	list_for_each_entry_safe(qh, fotg210->qh_scan_next,
+				 &fotg210->intr_qh_list, intr_node) {
+ rescan:
+		/* clean any finished work for this qh */
+		if (!list_empty(&qh->qtd_list)) {
+			int temp;
+
+			/*
+			 * Unlinks could happen here; completion reporting
+			 * drops the lock.  That's why fotg210->qh_scan_next
+			 * always holds the next qh to scan; if the next qh
+			 * gets unlinked then fotg210->qh_scan_next is adjusted
+			 * in qh_unlink_periodic().
+			 */
+			temp = qh_completions(fotg210, qh);
+			if (unlikely(qh->needs_rescan ||
+					(list_empty(&qh->qtd_list) &&
+					 qh->qh_state == QH_STATE_LINKED)))
+				start_unlink_intr(fotg210, qh);
+			else if (temp != 0)
+				goto rescan;
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fotg210_iso_stream ops work with both ITD and SITD */
+
+static struct fotg210_iso_stream *
+iso_stream_alloc(gfp_t mem_flags)
+{
+	struct fotg210_iso_stream *stream;
+
+	stream = kzalloc(sizeof(*stream), mem_flags);
+	if (likely(stream != NULL)) {
+		INIT_LIST_HEAD(&stream->td_list);
+		INIT_LIST_HEAD(&stream->free_list);
+		stream->next_uframe = -1;
+	}
+	return stream;
+}
+
+static void
+iso_stream_init(
+	struct fotg210_hcd		*fotg210,
+	struct fotg210_iso_stream	*stream,
+	struct usb_device	*dev,
+	int			pipe,
+	unsigned		interval
+)
+{
+	u32			buf1;
+	unsigned		epnum, maxp;
+	int			is_input;
+	long			bandwidth;
+	unsigned		multi;
+
+	/*
+	 * this might be a "high bandwidth" highspeed endpoint,
+	 * as encoded in the ep descriptor's wMaxPacket field
+	 */
+	epnum = usb_pipeendpoint(pipe);
+	is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
+	maxp = usb_maxpacket(dev, pipe, !is_input);
+	if (is_input)
+		buf1 = (1 << 11);
+	else
+		buf1 = 0;
+
+	maxp = max_packet(maxp);
+	multi = hb_mult(maxp);
+	buf1 |= maxp;
+	maxp *= multi;
+
+	stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
+	stream->buf1 = cpu_to_hc32(fotg210, buf1);
+	stream->buf2 = cpu_to_hc32(fotg210, multi);
+
+	/* usbfs wants to report the average usecs per frame tied up
+	 * when transfers on this endpoint are scheduled ...
+	 */
+	if (dev->speed == USB_SPEED_FULL) {
+		interval <<= 3;
+		stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
+				is_input, 1, maxp));
+		stream->usecs /= 8;
+	} else {
+		stream->highspeed = 1;
+		stream->usecs = HS_USECS_ISO(maxp);
+	}
+	bandwidth = stream->usecs * 8;
+	bandwidth /= interval;
+
+	stream->bandwidth = bandwidth;
+	stream->udev = dev;
+	stream->bEndpointAddress = is_input | epnum;
+	stream->interval = interval;
+	stream->maxp = maxp;
+}
+
+static struct fotg210_iso_stream *
+iso_stream_find(struct fotg210_hcd *fotg210, struct urb *urb)
+{
+	unsigned		epnum;
+	struct fotg210_iso_stream	*stream;
+	struct usb_host_endpoint *ep;
+	unsigned long		flags;
+
+	epnum = usb_pipeendpoint(urb->pipe);
+	if (usb_pipein(urb->pipe))
+		ep = urb->dev->ep_in[epnum];
+	else
+		ep = urb->dev->ep_out[epnum];
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+	stream = ep->hcpriv;
+
+	if (unlikely(stream == NULL)) {
+		stream = iso_stream_alloc(GFP_ATOMIC);
+		if (likely(stream != NULL)) {
+			ep->hcpriv = stream;
+			stream->ep = ep;
+			iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
+					urb->interval);
+		}
+
+	/* if dev->ep[epnum] is a QH, hw is set */
+	} else if (unlikely(stream->hw != NULL)) {
+		fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
+			urb->dev->devpath, epnum,
+			usb_pipein(urb->pipe) ? "in" : "out");
+		stream = NULL;
+	}
+
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	return stream;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* fotg210_iso_sched ops can be ITD-only or SITD-only */
+
+static struct fotg210_iso_sched *
+iso_sched_alloc(unsigned packets, gfp_t mem_flags)
+{
+	struct fotg210_iso_sched	*iso_sched;
+	int			size = sizeof(*iso_sched);
+
+	size += packets * sizeof(struct fotg210_iso_packet);
+	iso_sched = kzalloc(size, mem_flags);
+	if (likely(iso_sched != NULL))
+		INIT_LIST_HEAD(&iso_sched->td_list);
+
+	return iso_sched;
+}
+
+static inline void
+itd_sched_init(
+	struct fotg210_hcd		*fotg210,
+	struct fotg210_iso_sched	*iso_sched,
+	struct fotg210_iso_stream	*stream,
+	struct urb		*urb
+)
+{
+	unsigned	i;
+	dma_addr_t	dma = urb->transfer_dma;
+
+	/* how many uframes are needed for these transfers */
+	iso_sched->span = urb->number_of_packets * stream->interval;
+
+	/* figure out per-uframe itd fields that we'll need later
+	 * when we fit new itds into the schedule.
+	 */
+	for (i = 0; i < urb->number_of_packets; i++) {
+		struct fotg210_iso_packet	*uframe = &iso_sched->packet[i];
+		unsigned		length;
+		dma_addr_t		buf;
+		u32			trans;
+
+		length = urb->iso_frame_desc[i].length;
+		buf = dma + urb->iso_frame_desc[i].offset;
+
+		trans = FOTG210_ISOC_ACTIVE;
+		trans |= buf & 0x0fff;
+		if (unlikely(((i + 1) == urb->number_of_packets))
+				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
+			trans |= FOTG210_ITD_IOC;
+		trans |= length << 16;
+		uframe->transaction = cpu_to_hc32(fotg210, trans);
+
+		/* might need to cross a buffer page within a uframe */
+		uframe->bufp = (buf & ~(u64)0x0fff);
+		buf += length;
+		if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
+			uframe->cross = 1;
+	}
+}
+
+static void
+iso_sched_free(
+	struct fotg210_iso_stream	*stream,
+	struct fotg210_iso_sched	*iso_sched
+)
+{
+	if (!iso_sched)
+		return;
+	/* caller must hold fotg210->lock!*/
+	list_splice(&iso_sched->td_list, &stream->free_list);
+	kfree(iso_sched);
+}
+
+static int
+itd_urb_transaction(
+	struct fotg210_iso_stream	*stream,
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	gfp_t			mem_flags
+)
+{
+	struct fotg210_itd		*itd;
+	dma_addr_t		itd_dma;
+	int			i;
+	unsigned		num_itds;
+	struct fotg210_iso_sched	*sched;
+	unsigned long		flags;
+
+	sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
+	if (unlikely(sched == NULL))
+		return -ENOMEM;
+
+	itd_sched_init(fotg210, sched, stream, urb);
+
+	if (urb->interval < 8)
+		num_itds = 1 + (sched->span + 7) / 8;
+	else
+		num_itds = urb->number_of_packets;
+
+	/* allocate/init ITDs */
+	spin_lock_irqsave(&fotg210->lock, flags);
+	for (i = 0; i < num_itds; i++) {
+
+		/*
+		 * Use iTDs from the free list, but not iTDs that may
+		 * still be in use by the hardware.
+		 */
+		if (likely(!list_empty(&stream->free_list))) {
+			itd = list_first_entry(&stream->free_list,
+					struct fotg210_itd, itd_list);
+			if (itd->frame == fotg210->now_frame)
+				goto alloc_itd;
+			list_del(&itd->itd_list);
+			itd_dma = itd->itd_dma;
+		} else {
+ alloc_itd:
+			spin_unlock_irqrestore(&fotg210->lock, flags);
+			itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
+					&itd_dma);
+			spin_lock_irqsave(&fotg210->lock, flags);
+			if (!itd) {
+				iso_sched_free(stream, sched);
+				spin_unlock_irqrestore(&fotg210->lock, flags);
+				return -ENOMEM;
+			}
+		}
+
+		memset(itd, 0, sizeof(*itd));
+		itd->itd_dma = itd_dma;
+		list_add(&itd->itd_list, &sched->td_list);
+	}
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+
+	/* temporarily store schedule info in hcpriv */
+	urb->hcpriv = sched;
+	urb->error_count = 0;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+itd_slot_ok(
+	struct fotg210_hcd		*fotg210,
+	u32			mod,
+	u32			uframe,
+	u8			usecs,
+	u32			period
+)
+{
+	uframe %= period;
+	do {
+		/* can't commit more than uframe_periodic_max usec */
+		if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
+				> (fotg210->uframe_periodic_max - usecs))
+			return 0;
+
+		/* we know urb->interval is 2^N uframes */
+		uframe += period;
+	} while (uframe < mod);
+	return 1;
+}
+
+/*
+ * This scheduler plans almost as far into the future as it has actual
+ * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
+ * "as small as possible" to be cache-friendlier.)  That limits the size
+ * transfers you can stream reliably; avoid more than 64 msec per urb.
+ * Also avoid queue depths of less than fotg210's worst irq latency (affected
+ * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
+ * and other factors); or more than about 230 msec total (for portability,
+ * given FOTG210_TUNE_FLS and the slop).  Or, write a smarter scheduler!
+ */
+
+#define SCHEDULE_SLOP	80	/* microframes */
+
+static int
+iso_stream_schedule(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	struct fotg210_iso_stream	*stream
+)
+{
+	u32			now, next, start, period, span;
+	int			status;
+	unsigned		mod = fotg210->periodic_size << 3;
+	struct fotg210_iso_sched	*sched = urb->hcpriv;
+
+	period = urb->interval;
+	span = sched->span;
+
+	if (span > mod - SCHEDULE_SLOP) {
+		fotg210_dbg(fotg210, "iso request %p too long\n", urb);
+		status = -EFBIG;
+		goto fail;
+	}
+
+	now = fotg210_read_frame_index(fotg210) & (mod - 1);
+
+	/* Typical case: reuse current schedule, stream is still active.
+	 * Hopefully there are no gaps from the host falling behind
+	 * (irq delays etc), but if there are we'll take the next
+	 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
+	 */
+	if (likely(!list_empty(&stream->td_list))) {
+		u32	excess;
+
+		/* For high speed devices, allow scheduling within the
+		 * isochronous scheduling threshold.  For full speed devices
+		 * and Intel PCI-based controllers, don't (work around for
+		 * Intel ICH9 bug).
+		 */
+		if (!stream->highspeed && fotg210->fs_i_thresh)
+			next = now + fotg210->i_thresh;
+		else
+			next = now;
+
+		/* Fell behind (by up to twice the slop amount)?
+		 * We decide based on the time of the last currently-scheduled
+		 * slot, not the time of the next available slot.
+		 */
+		excess = (stream->next_uframe - period - next) & (mod - 1);
+		if (excess >= mod - 2 * SCHEDULE_SLOP)
+			start = next + excess - mod + period *
+					DIV_ROUND_UP(mod - excess, period);
+		else
+			start = next + excess + period;
+		if (start - now >= mod) {
+			fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
+					urb, start - now - period, period,
+					mod);
+			status = -EFBIG;
+			goto fail;
+		}
+	}
+
+	/* need to schedule; when's the next (u)frame we could start?
+	 * this is bigger than fotg210->i_thresh allows; scheduling itself
+	 * isn't free, the slop should handle reasonably slow cpus.  it
+	 * can also help high bandwidth if the dma and irq loads don't
+	 * jump until after the queue is primed.
+	 */
+	else {
+		int done = 0;
+		start = SCHEDULE_SLOP + (now & ~0x07);
+
+		/* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
+
+		/* find a uframe slot with enough bandwidth.
+		 * Early uframes are more precious because full-speed
+		 * iso IN transfers can't use late uframes,
+		 * and therefore they should be allocated last.
+		 */
+		next = start;
+		start += period;
+		do {
+			start--;
+			/* check schedule: enough space? */
+			if (itd_slot_ok(fotg210, mod, start,
+					stream->usecs, period))
+				done = 1;
+		} while (start > next && !done);
+
+		/* no room in the schedule */
+		if (!done) {
+			fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
+				urb, now, now + mod);
+			status = -ENOSPC;
+			goto fail;
+		}
+	}
+
+	/* Tried to schedule too far into the future? */
+	if (unlikely(start - now + span - period
+				>= mod - 2 * SCHEDULE_SLOP)) {
+		fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
+				urb, start - now, span - period,
+				mod - 2 * SCHEDULE_SLOP);
+		status = -EFBIG;
+		goto fail;
+	}
+
+	stream->next_uframe = start & (mod - 1);
+
+	/* report high speed start in uframes; full speed, in frames */
+	urb->start_frame = stream->next_uframe;
+	if (!stream->highspeed)
+		urb->start_frame >>= 3;
+
+	/* Make sure scan_isoc() sees these */
+	if (fotg210->isoc_count == 0)
+		fotg210->next_frame = now >> 3;
+	return 0;
+
+ fail:
+	iso_sched_free(stream, sched);
+	urb->hcpriv = NULL;
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+itd_init(struct fotg210_hcd *fotg210, struct fotg210_iso_stream *stream,
+		struct fotg210_itd *itd)
+{
+	int i;
+
+	/* it's been recently zeroed */
+	itd->hw_next = FOTG210_LIST_END(fotg210);
+	itd->hw_bufp[0] = stream->buf0;
+	itd->hw_bufp[1] = stream->buf1;
+	itd->hw_bufp[2] = stream->buf2;
+
+	for (i = 0; i < 8; i++)
+		itd->index[i] = -1;
+
+	/* All other fields are filled when scheduling */
+}
+
+static inline void
+itd_patch(
+	struct fotg210_hcd		*fotg210,
+	struct fotg210_itd		*itd,
+	struct fotg210_iso_sched	*iso_sched,
+	unsigned		index,
+	u16			uframe
+)
+{
+	struct fotg210_iso_packet	*uf = &iso_sched->packet[index];
+	unsigned		pg = itd->pg;
+
+	uframe &= 0x07;
+	itd->index[uframe] = index;
+
+	itd->hw_transaction[uframe] = uf->transaction;
+	itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
+	itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
+	itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
+
+	/* iso_frame_desc[].offset must be strictly increasing */
+	if (unlikely(uf->cross)) {
+		u64	bufp = uf->bufp + 4096;
+
+		itd->pg = ++pg;
+		itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
+		itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
+	}
+}
+
+static inline void
+itd_link(struct fotg210_hcd *fotg210, unsigned frame, struct fotg210_itd *itd)
+{
+	union fotg210_shadow	*prev = &fotg210->pshadow[frame];
+	__hc32			*hw_p = &fotg210->periodic[frame];
+	union fotg210_shadow	here = *prev;
+	__hc32			type = 0;
+
+	/* skip any iso nodes which might belong to previous microframes */
+	while (here.ptr) {
+		type = Q_NEXT_TYPE(fotg210, *hw_p);
+		if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
+			break;
+		prev = periodic_next_shadow(fotg210, prev, type);
+		hw_p = shadow_next_periodic(fotg210, &here, type);
+		here = *prev;
+	}
+
+	itd->itd_next = here;
+	itd->hw_next = *hw_p;
+	prev->itd = itd;
+	itd->frame = frame;
+	wmb();
+	*hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
+}
+
+/* fit urb's itds into the selected schedule slot; activate as needed */
+static void itd_link_urb(
+	struct fotg210_hcd		*fotg210,
+	struct urb		*urb,
+	unsigned		mod,
+	struct fotg210_iso_stream	*stream
+)
+{
+	int			packet;
+	unsigned		next_uframe, uframe, frame;
+	struct fotg210_iso_sched	*iso_sched = urb->hcpriv;
+	struct fotg210_itd		*itd;
+
+	next_uframe = stream->next_uframe & (mod - 1);
+
+	if (unlikely(list_empty(&stream->td_list))) {
+		fotg210_to_hcd(fotg210)->self.bandwidth_allocated
+				+= stream->bandwidth;
+		fotg210_vdbg(fotg210,
+			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",
+			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
+			urb->interval,
+			next_uframe >> 3, next_uframe & 0x7);
+	}
+
+	/* fill iTDs uframe by uframe */
+	for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
+		if (itd == NULL) {
+			/* ASSERT:  we have all necessary itds */
+
+			/* ASSERT:  no itds for this endpoint in this uframe */
+
+			itd = list_entry(iso_sched->td_list.next,
+					struct fotg210_itd, itd_list);
+			list_move_tail(&itd->itd_list, &stream->td_list);
+			itd->stream = stream;
+			itd->urb = urb;
+			itd_init(fotg210, stream, itd);
+		}
+
+		uframe = next_uframe & 0x07;
+		frame = next_uframe >> 3;
+
+		itd_patch(fotg210, itd, iso_sched, packet, uframe);
+
+		next_uframe += stream->interval;
+		next_uframe &= mod - 1;
+		packet++;
+
+		/* link completed itds into the schedule */
+		if (((next_uframe >> 3) != frame)
+				|| packet == urb->number_of_packets) {
+			itd_link(fotg210, frame & (fotg210->periodic_size - 1),
+				 itd);
+			itd = NULL;
+		}
+	}
+	stream->next_uframe = next_uframe;
+
+	/* don't need that schedule data any more */
+	iso_sched_free(stream, iso_sched);
+	urb->hcpriv = NULL;
+
+	++fotg210->isoc_count;
+	enable_periodic(fotg210);
+}
+
+#define	ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
+		  FOTG210_ISOC_XACTERR)
+
+/* Process and recycle a completed ITD.  Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly.  That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs.  It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
+static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
+{
+	struct urb				*urb = itd->urb;
+	struct usb_iso_packet_descriptor	*desc;
+	u32					t;
+	unsigned				uframe;
+	int					urb_index = -1;
+	struct fotg210_iso_stream			*stream = itd->stream;
+	struct usb_device			*dev;
+	bool					retval = false;
+
+	/* for each uframe with a packet */
+	for (uframe = 0; uframe < 8; uframe++) {
+		if (likely(itd->index[uframe] == -1))
+			continue;
+		urb_index = itd->index[uframe];
+		desc = &urb->iso_frame_desc[urb_index];
+
+		t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
+		itd->hw_transaction[uframe] = 0;
+
+		/* report transfer status */
+		if (unlikely(t & ISO_ERRS)) {
+			urb->error_count++;
+			if (t & FOTG210_ISOC_BUF_ERR)
+				desc->status = usb_pipein(urb->pipe)
+					? -ENOSR  /* hc couldn't read */
+					: -ECOMM; /* hc couldn't write */
+			else if (t & FOTG210_ISOC_BABBLE)
+				desc->status = -EOVERFLOW;
+			else /* (t & FOTG210_ISOC_XACTERR) */
+				desc->status = -EPROTO;
+
+			/* HC need not update length with this error */
+			if (!(t & FOTG210_ISOC_BABBLE)) {
+				desc->actual_length =
+					fotg210_itdlen(urb, desc, t);
+				urb->actual_length += desc->actual_length;
+			}
+		} else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
+			desc->status = 0;
+			desc->actual_length = fotg210_itdlen(urb, desc, t);
+			urb->actual_length += desc->actual_length;
+		} else {
+			/* URB was too late */
+			desc->status = -EXDEV;
+		}
+	}
+
+	/* handle completion now? */
+	if (likely((urb_index + 1) != urb->number_of_packets))
+		goto done;
+
+	/* ASSERT: it's really the last itd for this urb
+	list_for_each_entry (itd, &stream->td_list, itd_list)
+		BUG_ON (itd->urb == urb);
+	 */
+
+	/* give urb back to the driver; completion often (re)submits */
+	dev = urb->dev;
+	fotg210_urb_done(fotg210, urb, 0);
+	retval = true;
+	urb = NULL;
+
+	--fotg210->isoc_count;
+	disable_periodic(fotg210);
+
+	if (unlikely(list_is_singular(&stream->td_list))) {
+		fotg210_to_hcd(fotg210)->self.bandwidth_allocated
+				-= stream->bandwidth;
+		fotg210_vdbg(fotg210,
+			"deschedule devp %s ep%d%s-iso\n",
+			dev->devpath, stream->bEndpointAddress & 0x0f,
+			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
+	}
+
+done:
+	itd->urb = NULL;
+
+	/* Add to the end of the free list for later reuse */
+	list_move_tail(&itd->itd_list, &stream->free_list);
+
+	/* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
+	if (list_empty(&stream->td_list)) {
+		list_splice_tail_init(&stream->free_list,
+				&fotg210->cached_itd_list);
+		start_free_itds(fotg210);
+	}
+
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
+	gfp_t mem_flags)
+{
+	int			status = -EINVAL;
+	unsigned long		flags;
+	struct fotg210_iso_stream	*stream;
+
+	/* Get iso_stream head */
+	stream = iso_stream_find(fotg210, urb);
+	if (unlikely(stream == NULL)) {
+		fotg210_dbg(fotg210, "can't get iso stream\n");
+		return -ENOMEM;
+	}
+	if (unlikely(urb->interval != stream->interval &&
+		      fotg210_port_speed(fotg210, 0) ==
+				USB_PORT_STAT_HIGH_SPEED)) {
+			fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
+				stream->interval, urb->interval);
+			goto done;
+	}
+
+#ifdef FOTG210_URB_TRACE
+	fotg210_dbg(fotg210,
+		"%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
+		__func__, urb->dev->devpath, urb,
+		usb_pipeendpoint(urb->pipe),
+		usb_pipein(urb->pipe) ? "in" : "out",
+		urb->transfer_buffer_length,
+		urb->number_of_packets, urb->interval,
+		stream);
+#endif
+
+	/* allocate ITDs w/o locking anything */
+	status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
+	if (unlikely(status < 0)) {
+		fotg210_dbg(fotg210, "can't init itds\n");
+		goto done;
+	}
+
+	/* schedule ... need to lock */
+	spin_lock_irqsave(&fotg210->lock, flags);
+	if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
+		status = -ESHUTDOWN;
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(fotg210, urb, stream);
+	if (likely(status == 0))
+		itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
+ done_not_linked:
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+ done:
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_isoc(struct fotg210_hcd *fotg210)
+{
+	unsigned	uf, now_frame, frame;
+	unsigned	fmask = fotg210->periodic_size - 1;
+	bool		modified, live;
+
+	/*
+	 * When running, scan from last scan point up to "now"
+	 * else clean up by scanning everything that's left.
+	 * Touches as few pages as possible:  cache-friendly.
+	 */
+	if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
+		uf = fotg210_read_frame_index(fotg210);
+		now_frame = (uf >> 3) & fmask;
+		live = true;
+	} else  {
+		now_frame = (fotg210->next_frame - 1) & fmask;
+		live = false;
+	}
+	fotg210->now_frame = now_frame;
+
+	frame = fotg210->next_frame;
+	for (;;) {
+		union fotg210_shadow	q, *q_p;
+		__hc32			type, *hw_p;
+
+restart:
+		/* scan each element in frame's queue for completions */
+		q_p = &fotg210->pshadow[frame];
+		hw_p = &fotg210->periodic[frame];
+		q.ptr = q_p->ptr;
+		type = Q_NEXT_TYPE(fotg210, *hw_p);
+		modified = false;
+
+		while (q.ptr != NULL) {
+			switch (hc32_to_cpu(fotg210, type)) {
+			case Q_TYPE_ITD:
+				/* If this ITD is still active, leave it for
+				 * later processing ... check the next entry.
+				 * No need to check for activity unless the
+				 * frame is current.
+				 */
+				if (frame == now_frame && live) {
+					rmb();
+					for (uf = 0; uf < 8; uf++) {
+						if (q.itd->hw_transaction[uf] &
+							    ITD_ACTIVE(fotg210))
+							break;
+					}
+					if (uf < 8) {
+						q_p = &q.itd->itd_next;
+						hw_p = &q.itd->hw_next;
+						type = Q_NEXT_TYPE(fotg210,
+							q.itd->hw_next);
+						q = *q_p;
+						break;
+					}
+				}
+
+				/* Take finished ITDs out of the schedule
+				 * and process them:  recycle, maybe report
+				 * URB completion.  HC won't cache the
+				 * pointer for much longer, if at all.
+				 */
+				*q_p = q.itd->itd_next;
+				*hw_p = q.itd->hw_next;
+				type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
+				wmb();
+				modified = itd_complete(fotg210, q.itd);
+				q = *q_p;
+				break;
+			default:
+				fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
+					type, frame, q.ptr);
+				/* FALL THROUGH */
+			case Q_TYPE_QH:
+			case Q_TYPE_FSTN:
+				/* End of the iTDs and siTDs */
+				q.ptr = NULL;
+				break;
+			}
+
+			/* assume completion callbacks modify the queue */
+			if (unlikely(modified && fotg210->isoc_count > 0))
+				goto restart;
+		}
+
+		/* Stop when we have reached the current frame */
+		if (frame == now_frame)
+			break;
+		frame = (frame + 1) & fmask;
+	}
+	fotg210->next_frame = now_frame;
+}
+/*-------------------------------------------------------------------------*/
+/*
+ * Display / Set uframe_periodic_max
+ */
+static ssize_t show_uframe_periodic_max(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct fotg210_hcd		*fotg210;
+	int			n;
+
+	fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
+	n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
+	return n;
+}
+
+
+static ssize_t store_uframe_periodic_max(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct fotg210_hcd	*fotg210;
+	unsigned		uframe_periodic_max;
+	unsigned		frame, uframe;
+	unsigned short		allocated_max;
+	unsigned long		flags;
+	ssize_t			ret;
+
+	fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
+	if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
+		return -EINVAL;
+
+	if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
+		fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
+			     uframe_periodic_max);
+		return -EINVAL;
+	}
+
+	ret = -EINVAL;
+
+	/*
+	 * lock, so that our checking does not race with possible periodic
+	 * bandwidth allocation through submitting new urbs.
+	 */
+	spin_lock_irqsave(&fotg210->lock, flags);
+
+	/*
+	 * for request to decrease max periodic bandwidth, we have to check
+	 * every microframe in the schedule to see whether the decrease is
+	 * possible.
+	 */
+	if (uframe_periodic_max < fotg210->uframe_periodic_max) {
+		allocated_max = 0;
+
+		for (frame = 0; frame < fotg210->periodic_size; ++frame)
+			for (uframe = 0; uframe < 7; ++uframe)
+				allocated_max = max(allocated_max,
+						    periodic_usecs(fotg210, frame, uframe));
+
+		if (allocated_max > uframe_periodic_max) {
+			fotg210_info(fotg210,
+				"cannot decrease uframe_periodic_max becase "
+				"periodic bandwidth is already allocated "
+				"(%u > %u)\n",
+				allocated_max, uframe_periodic_max);
+			goto out_unlock;
+		}
+	}
+
+	/* increasing is always ok */
+
+	fotg210_info(fotg210, "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
+		     100 * uframe_periodic_max/125, uframe_periodic_max);
+
+	if (uframe_periodic_max != 100)
+		fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
+
+	fotg210->uframe_periodic_max = uframe_periodic_max;
+	ret = count;
+
+out_unlock:
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	return ret;
+}
+
+static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max,
+		   store_uframe_periodic_max);
+
+static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
+{
+	struct device	*controller = fotg210_to_hcd(fotg210)->self.controller;
+	int	i = 0;
+
+	if (i)
+		goto out;
+
+	i = device_create_file(controller, &dev_attr_uframe_periodic_max);
+out:
+	return i;
+}
+
+static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
+{
+	struct device	*controller = fotg210_to_hcd(fotg210)->self.controller;
+
+	device_remove_file(controller, &dev_attr_uframe_periodic_max);
+}
+/*-------------------------------------------------------------------------*/
+
+/* On some systems, leaving remote wakeup enabled prevents system shutdown.
+ * The firmware seems to think that powering off is a wakeup event!
+ * This routine turns off remote wakeup and everything else, on all ports.
+ */
+static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
+{
+	u32 __iomem *status_reg = &fotg210->regs->port_status;
+
+	fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
+}
+
+/*
+ * Halt HC, turn off all ports, and let the BIOS use the companion controllers.
+ * Must be called with interrupts enabled and the lock not held.
+ */
+static void fotg210_silence_controller(struct fotg210_hcd *fotg210)
+{
+	fotg210_halt(fotg210);
+
+	spin_lock_irq(&fotg210->lock);
+	fotg210->rh_state = FOTG210_RH_HALTED;
+	fotg210_turn_off_all_ports(fotg210);
+	spin_unlock_irq(&fotg210->lock);
+}
+
+/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
+ */
+static void fotg210_shutdown(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd	*fotg210 = hcd_to_fotg210(hcd);
+
+	spin_lock_irq(&fotg210->lock);
+	fotg210->shutdown = true;
+	fotg210->rh_state = FOTG210_RH_STOPPING;
+	fotg210->enabled_hrtimer_events = 0;
+	spin_unlock_irq(&fotg210->lock);
+
+	fotg210_silence_controller(fotg210);
+
+	hrtimer_cancel(&fotg210->hrtimer);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * fotg210_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping fotg210->lock.
+ */
+static void fotg210_work(struct fotg210_hcd *fotg210)
+{
+	/* another CPU may drop fotg210->lock during a schedule scan while
+	 * it reports urb completions.  this flag guards against bogus
+	 * attempts at re-entrant schedule scanning.
+	 */
+	if (fotg210->scanning) {
+		fotg210->need_rescan = true;
+		return;
+	}
+	fotg210->scanning = true;
+
+ rescan:
+	fotg210->need_rescan = false;
+	if (fotg210->async_count)
+		scan_async(fotg210);
+	if (fotg210->intr_count > 0)
+		scan_intr(fotg210);
+	if (fotg210->isoc_count > 0)
+		scan_isoc(fotg210);
+	if (fotg210->need_rescan)
+		goto rescan;
+	fotg210->scanning = false;
+
+	/* the IO watchdog guards against hardware or driver bugs that
+	 * misplace IRQs, and should let us run completely without IRQs.
+	 * such lossage has been observed on both VT6202 and VT8235.
+	 */
+	turn_on_io_watchdog(fotg210);
+}
+
+/*
+ * Called when the fotg210_hcd module is removed.
+ */
+static void fotg210_stop(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+
+	fotg210_dbg(fotg210, "stop\n");
+
+	/* no more interrupts ... */
+
+	spin_lock_irq(&fotg210->lock);
+	fotg210->enabled_hrtimer_events = 0;
+	spin_unlock_irq(&fotg210->lock);
+
+	fotg210_quiesce(fotg210);
+	fotg210_silence_controller(fotg210);
+	fotg210_reset(fotg210);
+
+	hrtimer_cancel(&fotg210->hrtimer);
+	remove_sysfs_files(fotg210);
+	remove_debug_files(fotg210);
+
+	/* root hub is shut down separately (first, when possible) */
+	spin_lock_irq(&fotg210->lock);
+	end_free_itds(fotg210);
+	spin_unlock_irq(&fotg210->lock);
+	fotg210_mem_cleanup(fotg210);
+
+#ifdef	FOTG210_STATS
+	fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
+		fotg210->stats.normal, fotg210->stats.error, fotg210->stats.iaa,
+		fotg210->stats.lost_iaa);
+	fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
+		fotg210->stats.complete, fotg210->stats.unlink);
+#endif
+
+	dbg_status(fotg210, "fotg210_stop completed",
+		    fotg210_readl(fotg210, &fotg210->regs->status));
+}
+
+/* one-time init, only for memory state */
+static int hcd_fotg210_init(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	u32			temp;
+	int			retval;
+	u32			hcc_params;
+	struct fotg210_qh_hw	*hw;
+
+	spin_lock_init(&fotg210->lock);
+
+	/*
+	 * keep io watchdog by default, those good HCDs could turn off it later
+	 */
+	fotg210->need_io_watchdog = 1;
+
+	hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	fotg210->hrtimer.function = fotg210_hrtimer_func;
+	fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
+
+	hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+	/*
+	 * by default set standard 80% (== 100 usec/uframe) max periodic
+	 * bandwidth as required by USB 2.0
+	 */
+	fotg210->uframe_periodic_max = 100;
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	fotg210->periodic_size = DEFAULT_I_TDPS;
+	INIT_LIST_HEAD(&fotg210->intr_qh_list);
+	INIT_LIST_HEAD(&fotg210->cached_itd_list);
+
+	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+		/* periodic schedule size can be smaller than default */
+		switch (FOTG210_TUNE_FLS) {
+		case 0:
+			fotg210->periodic_size = 1024;
+			break;
+		case 1:
+			fotg210->periodic_size = 512;
+			break;
+		case 2:
+			fotg210->periodic_size = 256;
+			break;
+		default:
+			BUG();
+		}
+	}
+	retval = fotg210_mem_init(fotg210, GFP_KERNEL);
+	if (retval < 0)
+		return retval;
+
+	/* controllers may cache some of the periodic schedule ... */
+	fotg210->i_thresh = 2;
+
+	/*
+	 * dedicate a qh for the async ring head, since we couldn't unlink
+	 * a 'real' qh without stopping the async schedule [4.8].  use it
+	 * as the 'reclamation list head' too.
+	 * its dummy is used in hw_alt_next of many tds, to prevent the qh
+	 * from automatically advancing to the next td after short reads.
+	 */
+	fotg210->async->qh_next.qh = NULL;
+	hw = fotg210->async->hw;
+	hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
+	hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
+	hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
+	hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
+	fotg210->async->qh_state = QH_STATE_LINKED;
+	hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
+
+	/* clear interrupt enables, set irq latency */
+	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+		log2_irq_thresh = 0;
+	temp = 1 << (16 + log2_irq_thresh);
+	if (HCC_CANPARK(hcc_params)) {
+		/* HW default park == 3, on hardware that supports it (like
+		 * NVidia and ALI silicon), maximizes throughput on the async
+		 * schedule by avoiding QH fetches between transfers.
+		 *
+		 * With fast usb storage devices and NForce2, "park" seems to
+		 * make problems:  throughput reduction (!), data errors...
+		 */
+		if (park) {
+			park = min_t(unsigned, park, 3);
+			temp |= CMD_PARK;
+			temp |= park << 8;
+		}
+		fotg210_dbg(fotg210, "park %d\n", park);
+	}
+	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+		/* periodic schedule size can be smaller than default */
+		temp &= ~(3 << 2);
+		temp |= (FOTG210_TUNE_FLS << 2);
+	}
+	fotg210->command = temp;
+
+	/* Accept arbitrarily long scatter-gather lists */
+	if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+		hcd->self.sg_tablesize = ~0;
+	return 0;
+}
+
+/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */
+static int fotg210_run(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	u32			temp;
+	u32			hcc_params;
+
+	hcd->uses_new_polling = 1;
+
+	/* EHCI spec section 4.1 */
+
+	fotg210_writel(fotg210, fotg210->periodic_dma,
+		       &fotg210->regs->frame_list);
+	fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
+		       &fotg210->regs->async_next);
+
+	/*
+	 * hcc_params controls whether fotg210->regs->segment must (!!!)
+	 * be used; it constrains QH/ITD/SITD and QTD locations.
+	 * pci_pool consistent memory always uses segment zero.
+	 * streaming mappings for I/O buffers, like pci_map_single(),
+	 * can return segments above 4GB, if the device allows.
+	 *
+	 * NOTE:  the dma mask is visible through dma_supported(), so
+	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
+	 * host side drivers though.
+	 */
+	hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
+
+	/*
+	 * Philips, Intel, and maybe others need CMD_RUN before the
+	 * root hub will detect new devices (why?); NEC doesn't
+	 */
+	fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+	fotg210->command |= CMD_RUN;
+	fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
+	dbg_cmd(fotg210, "init", fotg210->command);
+
+	/*
+	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+	 * are explicitly handed to companion controller(s), so no TT is
+	 * involved with the root hub.  (Except where one is integrated,
+	 * and there's no companion controller unless maybe for USB OTG.)
+	 *
+	 * Turning on the CF flag will transfer ownership of all ports
+	 * from the companions to the EHCI controller.  If any of the
+	 * companions are in the middle of a port reset at the time, it
+	 * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+	 * guarantees that no resets are in progress.  After we set CF,
+	 * a short delay lets the hardware catch up; new resets shouldn't
+	 * be started before the port switching actions could complete.
+	 */
+	down_write(&ehci_cf_port_reset_rwsem);
+	fotg210->rh_state = FOTG210_RH_RUNNING;
+	/* unblock posted writes */
+	fotg210_readl(fotg210, &fotg210->regs->command);
+	msleep(5);
+	up_write(&ehci_cf_port_reset_rwsem);
+	fotg210->last_periodic_enable = ktime_get_real();
+
+	temp = HC_VERSION(fotg210,
+			  fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
+	fotg210_info(fotg210,
+		"USB %x.%x started, EHCI %x.%02x\n",
+		((fotg210->sbrn & 0xf0)>>4), (fotg210->sbrn & 0x0f),
+		temp >> 8, temp & 0xff);
+
+	fotg210_writel(fotg210, INTR_MASK,
+		    &fotg210->regs->intr_enable); /* Turn On Interrupts */
+
+	/* GRR this is run-once init(), being done every time the HC starts.
+	 * So long as they're part of class devices, we can't do it init()
+	 * since the class device isn't created that early.
+	 */
+	create_debug_files(fotg210);
+	create_sysfs_files(fotg210);
+
+	return 0;
+}
+
+static int fotg210_setup(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
+	int retval;
+
+	fotg210->regs = (void __iomem *)fotg210->caps +
+	    HC_LENGTH(fotg210,
+		      fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
+	dbg_hcs_params(fotg210, "reset");
+	dbg_hcc_params(fotg210, "reset");
+
+	/* cache this readonly data; minimize chip reads */
+	fotg210->hcs_params = fotg210_readl(fotg210,
+					    &fotg210->caps->hcs_params);
+
+	fotg210->sbrn = HCD_USB2;
+
+	/* data structure init */
+	retval = hcd_fotg210_init(hcd);
+	if (retval)
+		return retval;
+
+	retval = fotg210_halt(fotg210);
+	if (retval)
+		return retval;
+
+	fotg210_reset(fotg210);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	u32			status, masked_status, pcd_status = 0, cmd;
+	int			bh;
+
+	spin_lock(&fotg210->lock);
+
+	status = fotg210_readl(fotg210, &fotg210->regs->status);
+
+	/* e.g. cardbus physical eject */
+	if (status == ~(u32) 0) {
+		fotg210_dbg(fotg210, "device removed\n");
+		goto dead;
+	}
+
+	/*
+	 * We don't use STS_FLR, but some controllers don't like it to
+	 * remain on, so mask it out along with the other status bits.
+	 */
+	masked_status = status & (INTR_MASK | STS_FLR);
+
+	/* Shared IRQ? */
+	if (!masked_status ||
+	    unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
+		spin_unlock(&fotg210->lock);
+		return IRQ_NONE;
+	}
+
+	/* clear (just) interrupts */
+	fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
+	cmd = fotg210_readl(fotg210, &fotg210->regs->command);
+	bh = 0;
+
+#ifdef	VERBOSE_DEBUG
+	/* unrequested/ignored: Frame List Rollover */
+	dbg_status(fotg210, "irq", status);
+#endif
+
+	/* INT, ERR, and IAA interrupt rates can be throttled */
+
+	/* normal [4.15.1.2] or error [4.15.1.1] completion */
+	if (likely((status & (STS_INT|STS_ERR)) != 0)) {
+		if (likely((status & STS_ERR) == 0))
+			COUNT(fotg210->stats.normal);
+		else
+			COUNT(fotg210->stats.error);
+		bh = 1;
+	}
+
+	/* complete the unlinking of some qh [4.15.2.3] */
+	if (status & STS_IAA) {
+
+		/* Turn off the IAA watchdog */
+		fotg210->enabled_hrtimer_events &=
+			~BIT(FOTG210_HRTIMER_IAA_WATCHDOG);
+
+		/*
+		 * Mild optimization: Allow another IAAD to reset the
+		 * hrtimer, if one occurs before the next expiration.
+		 * In theory we could always cancel the hrtimer, but
+		 * tests show that about half the time it will be reset
+		 * for some other event anyway.
+		 */
+		if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
+			++fotg210->next_hrtimer_event;
+
+		/* guard against (alleged) silicon errata */
+		if (cmd & CMD_IAAD)
+			fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
+		if (fotg210->async_iaa) {
+			COUNT(fotg210->stats.iaa);
+			end_unlink_async(fotg210);
+		} else
+			fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
+	}
+
+	/* remote wakeup [4.3.1] */
+	if (status & STS_PCD) {
+		int pstatus;
+		u32 __iomem *status_reg = &fotg210->regs->port_status;
+
+		/* kick root hub later */
+		pcd_status = status;
+
+		/* resume root hub? */
+		if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
+			usb_hcd_resume_root_hub(hcd);
+
+		pstatus = fotg210_readl(fotg210, status_reg);
+
+		if (test_bit(0, &fotg210->suspended_ports) &&
+				((pstatus & PORT_RESUME) ||
+					!(pstatus & PORT_SUSPEND)) &&
+				(pstatus & PORT_PE) &&
+				fotg210->reset_done[0] == 0) {
+
+			/* start 20 msec resume signaling from this port,
+			 * and make khubd collect PORT_STAT_C_SUSPEND to
+			 * stop that signaling.  Use 5 ms extra for safety,
+			 * like usb_port_resume() does.
+			 */
+			fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
+			set_bit(0, &fotg210->resuming_ports);
+			fotg210_dbg(fotg210, "port 1 remote wakeup\n");
+			mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
+		}
+	}
+
+	/* PCI errors [4.15.2.4] */
+	if (unlikely((status & STS_FATAL) != 0)) {
+		fotg210_err(fotg210, "fatal error\n");
+		dbg_cmd(fotg210, "fatal", cmd);
+		dbg_status(fotg210, "fatal", status);
+dead:
+		usb_hc_died(hcd);
+
+		/* Don't let the controller do anything more */
+		fotg210->shutdown = true;
+		fotg210->rh_state = FOTG210_RH_STOPPING;
+		fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
+		fotg210_writel(fotg210, fotg210->command,
+			       &fotg210->regs->command);
+		fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
+		fotg210_handle_controller_death(fotg210);
+
+		/* Handle completions when the controller stops */
+		bh = 0;
+	}
+
+	if (bh)
+		fotg210_work(fotg210);
+	spin_unlock(&fotg210->lock);
+	if (pcd_status)
+		usb_hcd_poll_rh_status(hcd);
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd.self.controller.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
+ */
+static int fotg210_urb_enqueue(
+	struct usb_hcd	*hcd,
+	struct urb	*urb,
+	gfp_t		mem_flags
+) {
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	struct list_head	qtd_list;
+
+	INIT_LIST_HEAD(&qtd_list);
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		/* qh_completions() code doesn't handle all the fault cases
+		 * in multi-TD control transfers.  Even 1KB is rare anyway.
+		 */
+		if (urb->transfer_buffer_length > (16 * 1024))
+			return -EMSGSIZE;
+		/* FALLTHROUGH */
+	/* case PIPE_BULK: */
+	default:
+		if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return submit_async(fotg210, urb, &qtd_list, mem_flags);
+
+	case PIPE_INTERRUPT:
+		if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return intr_submit(fotg210, urb, &qtd_list, mem_flags);
+
+	case PIPE_ISOCHRONOUS:
+		return itd_submit(fotg210, urb, mem_flags);
+	}
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	struct fotg210_qh		*qh;
+	unsigned long		flags;
+	int			rc;
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
+	switch (usb_pipetype(urb->pipe)) {
+	/* case PIPE_CONTROL: */
+	/* case PIPE_BULK:*/
+	default:
+		qh = (struct fotg210_qh *) urb->hcpriv;
+		if (!qh)
+			break;
+		switch (qh->qh_state) {
+		case QH_STATE_LINKED:
+		case QH_STATE_COMPLETING:
+			start_unlink_async(fotg210, qh);
+			break;
+		case QH_STATE_UNLINK:
+		case QH_STATE_UNLINK_WAIT:
+			/* already started */
+			break;
+		case QH_STATE_IDLE:
+			/* QH might be waiting for a Clear-TT-Buffer */
+			qh_completions(fotg210, qh);
+			break;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		qh = (struct fotg210_qh *) urb->hcpriv;
+		if (!qh)
+			break;
+		switch (qh->qh_state) {
+		case QH_STATE_LINKED:
+		case QH_STATE_COMPLETING:
+			start_unlink_intr(fotg210, qh);
+			break;
+		case QH_STATE_IDLE:
+			qh_completions(fotg210, qh);
+			break;
+		default:
+			fotg210_dbg(fotg210, "bogus qh %p state %d\n",
+					qh, qh->qh_state);
+			goto done;
+		}
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		/* itd... */
+
+		/* wait till next completion, do it then. */
+		/* completion irqs can wait up to 1024 msec, */
+		break;
+	}
+done:
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+	return rc;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bulk qh holds the data toggle */
+
+static void
+fotg210_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	unsigned long		flags;
+	struct fotg210_qh		*qh, *tmp;
+
+	/* ASSERT:  any requests/urbs are being unlinked */
+	/* ASSERT:  nobody can be submitting urbs for this any more */
+
+rescan:
+	spin_lock_irqsave(&fotg210->lock, flags);
+	qh = ep->hcpriv;
+	if (!qh)
+		goto done;
+
+	/* endpoints can be iso streams.  for now, we don't
+	 * accelerate iso completions ... so spin a while.
+	 */
+	if (qh->hw == NULL) {
+		struct fotg210_iso_stream	*stream = ep->hcpriv;
+
+		if (!list_empty(&stream->td_list))
+			goto idle_timeout;
+
+		/* BUG_ON(!list_empty(&stream->free_list)); */
+		kfree(stream);
+		goto done;
+	}
+
+	if (fotg210->rh_state < FOTG210_RH_RUNNING)
+		qh->qh_state = QH_STATE_IDLE;
+	switch (qh->qh_state) {
+	case QH_STATE_LINKED:
+	case QH_STATE_COMPLETING:
+		for (tmp = fotg210->async->qh_next.qh;
+				tmp && tmp != qh;
+				tmp = tmp->qh_next.qh)
+			continue;
+		/* periodic qh self-unlinks on empty, and a COMPLETING qh
+		 * may already be unlinked.
+		 */
+		if (tmp)
+			start_unlink_async(fotg210, qh);
+		/* FALL THROUGH */
+	case QH_STATE_UNLINK:		/* wait for hw to finish? */
+	case QH_STATE_UNLINK_WAIT:
+idle_timeout:
+		spin_unlock_irqrestore(&fotg210->lock, flags);
+		schedule_timeout_uninterruptible(1);
+		goto rescan;
+	case QH_STATE_IDLE:		/* fully unlinked */
+		if (qh->clearing_tt)
+			goto idle_timeout;
+		if (list_empty(&qh->qtd_list)) {
+			qh_destroy(fotg210, qh);
+			break;
+		}
+		/* else FALL THROUGH */
+	default:
+		/* caller was supposed to have unlinked any requests;
+		 * that's not our job.  just leak this memory.
+		 */
+		fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
+			qh, ep->desc.bEndpointAddress, qh->qh_state,
+			list_empty(&qh->qtd_list) ? "" : "(has tds)");
+		break;
+	}
+ done:
+	ep->hcpriv = NULL;
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static void
+fotg210_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	struct fotg210_qh		*qh;
+	int			eptype = usb_endpoint_type(&ep->desc);
+	int			epnum = usb_endpoint_num(&ep->desc);
+	int			is_out = usb_endpoint_dir_out(&ep->desc);
+	unsigned long		flags;
+
+	if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
+		return;
+
+	spin_lock_irqsave(&fotg210->lock, flags);
+	qh = ep->hcpriv;
+
+	/* For Bulk and Interrupt endpoints we maintain the toggle state
+	 * in the hardware; the toggle bits in udev aren't used at all.
+	 * When an endpoint is reset by usb_clear_halt() we must reset
+	 * the toggle bit in the QH.
+	 */
+	if (qh) {
+		usb_settoggle(qh->dev, epnum, is_out, 0);
+		if (!list_empty(&qh->qtd_list)) {
+			WARN_ONCE(1, "clear_halt for a busy endpoint\n");
+		} else if (qh->qh_state == QH_STATE_LINKED ||
+				qh->qh_state == QH_STATE_COMPLETING) {
+
+			/* The toggle value in the QH can't be updated
+			 * while the QH is active.  Unlink it now;
+			 * re-linking will call qh_refresh().
+			 */
+			if (eptype == USB_ENDPOINT_XFER_BULK)
+				start_unlink_async(fotg210, qh);
+			else
+				start_unlink_intr(fotg210, qh);
+		}
+	}
+	spin_unlock_irqrestore(&fotg210->lock, flags);
+}
+
+static int fotg210_get_frame(struct usb_hcd *hcd)
+{
+	struct fotg210_hcd		*fotg210 = hcd_to_fotg210(hcd);
+	return (fotg210_read_frame_index(fotg210) >> 3) %
+		fotg210->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
+ * because its registers (and irq) are shared between host/gadget/otg
+ * functions  and in order to facilitate role switching we cannot
+ * give the fotg210 driver exclusive access to those.
+ */
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static const struct hc_driver fotg210_fotg210_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "Faraday USB2.0 Host Controller",
+	.hcd_priv_size		= sizeof(struct fotg210_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq			= fotg210_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset			= hcd_fotg210_init,
+	.start			= fotg210_run,
+	.stop			= fotg210_stop,
+	.shutdown		= fotg210_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= fotg210_urb_enqueue,
+	.urb_dequeue		= fotg210_urb_dequeue,
+	.endpoint_disable	= fotg210_endpoint_disable,
+	.endpoint_reset		= fotg210_endpoint_reset,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number	= fotg210_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= fotg210_hub_status_data,
+	.hub_control		= fotg210_hub_control,
+	.bus_suspend		= fotg210_bus_suspend,
+	.bus_resume		= fotg210_bus_resume,
+
+	.relinquish_port	= fotg210_relinquish_port,
+	.port_handed_over	= fotg210_port_handed_over,
+
+	.clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
+};
+
+static void fotg210_init(struct fotg210_hcd *fotg210)
+{
+	u32 value;
+
+	iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
+		  &fotg210->regs->gmir);
+
+	value = ioread32(&fotg210->regs->otgcsr);
+	value &= ~OTGCSR_A_BUS_DROP;
+	value |= OTGCSR_A_BUS_REQ;
+	iowrite32(value, &fotg210->regs->otgcsr);
+}
+
+/**
+ * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int fotg210_hcd_probe(struct platform_device *pdev)
+{
+	struct device			*dev = &pdev->dev;
+	struct usb_hcd			*hcd;
+	struct resource			*res;
+	int				irq;
+	int				retval = -ENODEV;
+	struct fotg210_hcd		*fotg210;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	pdev->dev.power.power_state = PMSG_ON;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev,
+			"Found HC with no IRQ. Check %s setup!\n",
+			dev_name(dev));
+		return -ENODEV;
+	}
+
+	irq = res->start;
+
+	hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
+			dev_name(dev));
+	if (!hcd) {
+		dev_err(dev, "failed to create hcd with err %d\n", retval);
+		retval = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev,
+			"Found HC with no register addr. Check %s setup!\n",
+			dev_name(dev));
+		retval = -ENODEV;
+		goto fail_request_resource;
+	}
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+	hcd->has_tt = 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+				fotg210_fotg210_hc_driver.description)) {
+		dev_dbg(dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto fail_request_resource;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!res) {
+		dev_err(dev,
+			"Found HC with no register addr. Check %s setup!\n",
+			dev_name(dev));
+		retval = -ENODEV;
+		goto fail_request_resource;
+	}
+
+	hcd->regs = ioremap_nocache(res->start, resource_size(res));
+	if (hcd->regs == NULL) {
+		dev_dbg(dev, "error mapping memory\n");
+		retval = -EFAULT;
+		goto fail_ioremap;
+	}
+
+	fotg210 = hcd_to_fotg210(hcd);
+
+	fotg210->caps = hcd->regs;
+
+	retval = fotg210_setup(hcd);
+	if (retval)
+		goto fail_add_hcd;
+
+	fotg210_init(fotg210);
+
+	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+	if (retval) {
+		dev_err(dev, "failed to add hcd with err %d\n", retval);
+		goto fail_add_hcd;
+	}
+
+	return retval;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+fail_request_resource:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
+	return retval;
+}
+
+/**
+ * fotg210_hcd_remove - shutdown processing for EHCI HCDs
+ * @dev: USB Host Controller being removed
+ *
+ */
+static int fotg210_hcd_remove(struct platform_device *pdev)
+{
+	struct device *dev	= &pdev->dev;
+	struct usb_hcd *hcd	= dev_get_drvdata(dev);
+
+	if (!hcd)
+		return 0;
+
+	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 fotg210_hcd_driver = {
+	.driver = {
+		.name   = "fotg210-hcd",
+	},
+	.probe  = fotg210_hcd_probe,
+	.remove = fotg210_hcd_remove,
+};
+
+static int __init fotg210_hcd_init(void)
+{
+	int retval = 0;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+	set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+	if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
+			test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
+		pr_warn(KERN_WARNING "Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
+
+	pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd\n",
+		 hcd_name,
+		 sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd),
+		 sizeof(struct fotg210_itd));
+
+#ifdef DEBUG
+	fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
+	if (!fotg210_debug_root) {
+		retval = -ENOENT;
+		goto err_debug;
+	}
+#endif
+
+	retval = platform_driver_register(&fotg210_hcd_driver);
+	if (retval < 0)
+		goto clean;
+	return retval;
+
+	platform_driver_unregister(&fotg210_hcd_driver);
+clean:
+#ifdef DEBUG
+	debugfs_remove(fotg210_debug_root);
+	fotg210_debug_root = NULL;
+err_debug:
+#endif
+	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+	return retval;
+}
+module_init(fotg210_hcd_init);
+
+static void __exit fotg210_hcd_cleanup(void)
+{
+	platform_driver_unregister(&fotg210_hcd_driver);
+#ifdef DEBUG
+	debugfs_remove(fotg210_debug_root);
+#endif
+	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
+}
+module_exit(fotg210_hcd_cleanup);
diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
new file mode 100644
index 0000000..8920f9d
--- /dev/null
+++ b/drivers/usb/host/fotg210.h
@@ -0,0 +1,750 @@
+#ifndef __LINUX_FOTG210_H
+#define __LINUX_FOTG210_H
+
+/* definitions used for the EHCI driver */
+
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on
+ * the host controller implementation.
+ *
+ * To facilitate the strongest possible byte-order checking from "sparse"
+ * and so on, we use __leXX unless that's not practical.
+ */
+#define __hc32	__le32
+#define __hc16	__le16
+
+/* statistics can be kept for tuning/monitoring */
+struct fotg210_stats {
+	/* irq usage */
+	unsigned long		normal;
+	unsigned long		error;
+	unsigned long		iaa;
+	unsigned long		lost_iaa;
+
+	/* termination of urbs from core */
+	unsigned long		complete;
+	unsigned long		unlink;
+};
+
+/* fotg210_hcd->lock guards shared data against other CPUs:
+ *   fotg210_hcd:	async, unlink, periodic (and shadow), ...
+ *   usb_host_endpoint: hcpriv
+ *   fotg210_qh:	qh_next, qtd_list
+ *   fotg210_qtd:	qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define	FOTG210_MAX_ROOT_PORTS	1		/* see HCS_N_PORTS */
+
+/*
+ * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the
+ * controller may be doing DMA.  Lower values mean there's no DMA.
+ */
+enum fotg210_rh_state {
+	FOTG210_RH_HALTED,
+	FOTG210_RH_SUSPENDED,
+	FOTG210_RH_RUNNING,
+	FOTG210_RH_STOPPING
+};
+
+/*
+ * Timer events, ordered by increasing delay length.
+ * Always update event_delays_ns[] and event_handlers[] (defined in
+ * ehci-timer.c) in parallel with this list.
+ */
+enum fotg210_hrtimer_event {
+	FOTG210_HRTIMER_POLL_ASS,	/* Poll for async schedule off */
+	FOTG210_HRTIMER_POLL_PSS,	/* Poll for periodic schedule off */
+	FOTG210_HRTIMER_POLL_DEAD,	/* Wait for dead controller to stop */
+	FOTG210_HRTIMER_UNLINK_INTR,	/* Wait for interrupt QH unlink */
+	FOTG210_HRTIMER_FREE_ITDS,	/* Wait for unused iTDs and siTDs */
+	FOTG210_HRTIMER_ASYNC_UNLINKS,	/* Unlink empty async QHs */
+	FOTG210_HRTIMER_IAA_WATCHDOG,	/* Handle lost IAA interrupts */
+	FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
+	FOTG210_HRTIMER_DISABLE_ASYNC,	/* Wait to disable async sched */
+	FOTG210_HRTIMER_IO_WATCHDOG,	/* Check for missing IRQs */
+	FOTG210_HRTIMER_NUM_EVENTS	/* Must come last */
+};
+#define FOTG210_HRTIMER_NO_EVENT	99
+
+struct fotg210_hcd {			/* one per controller */
+	/* timing support */
+	enum fotg210_hrtimer_event	next_hrtimer_event;
+	unsigned		enabled_hrtimer_events;
+	ktime_t			hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS];
+	struct hrtimer		hrtimer;
+
+	int			PSS_poll_count;
+	int			ASS_poll_count;
+	int			died_poll_count;
+
+	/* glue to PCI and HCD framework */
+	struct fotg210_caps __iomem *caps;
+	struct fotg210_regs __iomem *regs;
+	struct fotg210_dbg_port __iomem *debug;
+
+	__u32			hcs_params;	/* cached register copy */
+	spinlock_t		lock;
+	enum fotg210_rh_state	rh_state;
+
+	/* general schedule support */
+	bool			scanning:1;
+	bool			need_rescan:1;
+	bool			intr_unlinking:1;
+	bool			async_unlinking:1;
+	bool			shutdown:1;
+	struct fotg210_qh		*qh_scan_next;
+
+	/* async schedule support */
+	struct fotg210_qh		*async;
+	struct fotg210_qh		*dummy;		/* For AMD quirk use */
+	struct fotg210_qh		*async_unlink;
+	struct fotg210_qh		*async_unlink_last;
+	struct fotg210_qh		*async_iaa;
+	unsigned		async_unlink_cycle;
+	unsigned		async_count;	/* async activity count */
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
+	unsigned		periodic_size;
+	__hc32			*periodic;	/* hw periodic table */
+	dma_addr_t		periodic_dma;
+	struct list_head	intr_qh_list;
+	unsigned		i_thresh;	/* uframes HC might cache */
+
+	union fotg210_shadow	*pshadow;	/* mirror hw periodic table */
+	struct fotg210_qh		*intr_unlink;
+	struct fotg210_qh		*intr_unlink_last;
+	unsigned		intr_unlink_cycle;
+	unsigned		now_frame;	/* frame from HC hardware */
+	unsigned		next_frame;	/* scan periodic, start here */
+	unsigned		intr_count;	/* intr activity count */
+	unsigned		isoc_count;	/* isoc activity count */
+	unsigned		periodic_count;	/* periodic activity count */
+	/* max periodic time per uframe */
+	unsigned		uframe_periodic_max;
+
+
+	/* list of itds completed while now_frame was still active */
+	struct list_head	cached_itd_list;
+	struct fotg210_itd	*last_itd_to_free;
+
+	/* per root hub port */
+	unsigned long		reset_done[FOTG210_MAX_ROOT_PORTS];
+
+	/* bit vectors (one bit per port) */
+	unsigned long		bus_suspended;		/* which ports were
+			already suspended at the start of a bus suspend */
+	unsigned long		companion_ports;	/* which ports are
+			dedicated to the companion controller */
+	unsigned long		owned_ports;		/* which ports are
+			owned by the companion during a bus suspend */
+	unsigned long		port_c_suspend;		/* which ports have
+			the change-suspend feature turned on */
+	unsigned long		suspended_ports;	/* which ports are
+			suspended */
+	unsigned long		resuming_ports;		/* which ports have
+			started to resume */
+
+	/* per-HC memory pools (could be per-bus, but ...) */
+	struct dma_pool		*qh_pool;	/* qh per active urb */
+	struct dma_pool		*qtd_pool;	/* one or more per qh */
+	struct dma_pool		*itd_pool;	/* itd per iso urb */
+
+	unsigned		random_frame;
+	unsigned long		next_statechange;
+	ktime_t			last_periodic_enable;
+	u32			command;
+
+	/* SILICON QUIRKS */
+	unsigned		need_io_watchdog:1;
+	unsigned		fs_i_thresh:1;	/* Intel iso scheduling */
+
+	u8			sbrn;		/* packed release number */
+
+	/* irq statistics */
+#ifdef FOTG210_STATS
+	struct fotg210_stats	stats;
+#	define COUNT(x) ((x)++)
+#else
+#	define COUNT(x)
+#endif
+
+	/* debug files */
+#ifdef DEBUG
+	struct dentry		*debug_dir;
+#endif
+};
+
+/* convert between an HCD pointer and the corresponding FOTG210_HCD */
+static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd)
+{
+	return (struct fotg210_hcd *)(hcd->hcd_priv);
+}
+static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210)
+{
+	return container_of((void *) fotg210, struct usb_hcd, hcd_priv);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct fotg210_caps {
+	/* these fields are specified as 8 and 16 bit registers,
+	 * but some hosts can't perform 8 or 16 bit PCI accesses.
+	 * some hosts treat caplength and hciversion as parts of a 32-bit
+	 * register, others treat them as two separate registers, this
+	 * affects the memory map for big endian controllers.
+	 */
+	u32		hc_capbase;
+#define HC_LENGTH(fotg210, p)	(0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
+				(fotg210_big_endian_capbase(fotg210) ? 24 : 0)))
+#define HC_VERSION(fotg210, p)	(0xffff&((p) >> /* bits 31:16 / offset 02h */ \
+				(fotg210_big_endian_capbase(fotg210) ? 0 : 16)))
+	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+
+	u32		hcc_params;	/* HCCPARAMS - offset 0x8 */
+#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+	u8		portroute[8];	 /* nibbles for routing - offset 0xC */
+};
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct fotg210_regs {
+
+	/* USBCMD: offset 0x00 */
+	u32		command;
+
+/* EHCI 1.1 addendum */
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
+#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
+#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
+#define CMD_ASE		(1<<5)		/* async schedule enable */
+#define CMD_PSE		(1<<4)		/* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET	(1<<1)		/* reset HC not bus */
+#define CMD_RUN		(1<<0)		/* start/stop HC */
+
+	/* USBSTS: offset 0x04 */
+	u32		status;
+#define STS_ASS		(1<<15)		/* Async Schedule Status */
+#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
+#define STS_RECL	(1<<13)		/* Reclamation */
+#define STS_HALT	(1<<12)		/* Not running (any reason) */
+/* some bits reserved */
+	/* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA		(1<<5)		/* Interrupted on async advance */
+#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
+#define STS_FLR		(1<<3)		/* frame list rolled over */
+#define STS_PCD		(1<<2)		/* port change detect */
+#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
+#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
+
+	/* USBINTR: offset 0x08 */
+	u32		intr_enable;
+
+	/* FRINDEX: offset 0x0C */
+	u32		frame_index;	/* current microframe number */
+	/* CTRLDSSEGMENT: offset 0x10 */
+	u32		segment;	/* address bits 63:32 if needed */
+	/* PERIODICLISTBASE: offset 0x14 */
+	u32		frame_list;	/* points to periodic list */
+	/* ASYNCLISTADDR: offset 0x18 */
+	u32		async_next;	/* address of next async queue head */
+
+	u32	reserved1;
+	/* PORTSC: offset 0x20 */
+	u32	port_status;
+/* 31:23 reserved */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))	/* USB 1.1 device */
+#define PORT_RESET	(1<<8)		/* reset port */
+#define PORT_SUSPEND	(1<<7)		/* suspend port */
+#define PORT_RESUME	(1<<6)		/* resume it */
+#define PORT_PEC	(1<<3)		/* port enable change */
+#define PORT_PE		(1<<2)		/* port enable */
+#define PORT_CSC	(1<<1)		/* connect status change */
+#define PORT_CONNECT	(1<<0)		/* device connected */
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC)
+	u32     reserved2[19];
+
+	/* OTGCSR: offet 0x70 */
+	u32     otgcsr;
+#define OTGCSR_HOST_SPD_TYP     (3 << 22)
+#define OTGCSR_A_BUS_DROP	(1 << 5)
+#define OTGCSR_A_BUS_REQ	(1 << 4)
+
+	/* OTGISR: offset 0x74 */
+	u32     otgisr;
+#define OTGISR_OVC	(1 << 10)
+
+	u32     reserved3[15];
+
+	/* GMIR: offset 0xB4 */
+	u32     gmir;
+#define GMIR_INT_POLARITY	(1 << 3) /*Active High*/
+#define GMIR_MHC_INT		(1 << 2)
+#define GMIR_MOTG_INT		(1 << 1)
+#define GMIR_MDEV_INT	(1 << 0)
+};
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct fotg210_dbg_port {
+	u32	control;
+#define DBGP_OWNER	(1<<30)
+#define DBGP_ENABLED	(1<<28)
+#define DBGP_DONE	(1<<16)
+#define DBGP_INUSE	(1<<10)
+#define DBGP_ERRCODE(x)	(((x)>>7)&0x07)
+#	define DBGP_ERR_BAD	1
+#	define DBGP_ERR_SIGNAL	2
+#define DBGP_ERROR	(1<<6)
+#define DBGP_GO		(1<<5)
+#define DBGP_OUT	(1<<4)
+#define DBGP_LEN(x)	(((x)>>0)&0x0f)
+	u32	pids;
+#define DBGP_PID_GET(x)		(((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok)	(((data)<<8)|(tok))
+	u32	data03;
+	u32	data47;
+	u32	address;
+#define DBGP_EPADDR(dev, ep)	(((dev)<<8)|(ep))
+};
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+#include <linux/init.h>
+extern int __init early_dbgp_init(char *s);
+extern struct console early_dbgp_console;
+#endif /* CONFIG_EARLY_PRINTK_DBGP */
+
+struct usb_hcd;
+
+static inline int xen_dbgp_reset_prep(struct usb_hcd *hcd)
+{
+	return 1; /* Shouldn't this be 0? */
+}
+
+static inline int xen_dbgp_external_startup(struct usb_hcd *hcd)
+{
+	return -1;
+}
+
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+/* Call backs from fotg210 host driver to fotg210 debug driver */
+extern int dbgp_external_startup(struct usb_hcd *);
+extern int dbgp_reset_prep(struct usb_hcd *hcd);
+#else
+static inline int dbgp_reset_prep(struct usb_hcd *hcd)
+{
+	return xen_dbgp_reset_prep(hcd);
+}
+static inline int dbgp_external_startup(struct usb_hcd *hcd)
+{
+	return xen_dbgp_external_startup(hcd);
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define	QTD_NEXT(fotg210, dma)	cpu_to_hc32(fotg210, (u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct fotg210_qtd {
+	/* first part defined by EHCI spec */
+	__hc32			hw_next;	/* see EHCI 3.5.1 */
+	__hc32			hw_alt_next;    /* see EHCI 3.5.2 */
+	__hc32			hw_token;	/* see EHCI 3.5.3 */
+#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
+#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
+#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
+#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
+#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
+#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
+#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
+#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
+#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
+#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
+#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
+#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
+
+#define ACTIVE_BIT(fotg210)	cpu_to_hc32(fotg210, QTD_STS_ACTIVE)
+#define HALT_BIT(fotg210)		cpu_to_hc32(fotg210, QTD_STS_HALT)
+#define STATUS_BIT(fotg210)	cpu_to_hc32(fotg210, QTD_STS_STS)
+
+	__hc32			hw_buf[5];	/* see EHCI 3.5.4 */
+	__hc32			hw_buf_hi[5];	/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		qtd_dma;		/* qtd address */
+	struct list_head	qtd_list;		/* sw qtd list */
+	struct urb		*urb;			/* qtd's urb */
+	size_t			length;			/* length of buffer */
+} __aligned(32);
+
+/* mask NakCnt+T in qh->hw_alt_next */
+#define QTD_MASK(fotg210)	cpu_to_hc32(fotg210, ~0x1f)
+
+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,fstn}->hw_next */
+#define Q_NEXT_TYPE(fotg210, dma)	((dma) & cpu_to_hc32(fotg210, 3 << 1))
+
+/*
+ * Now the following defines are not converted using the
+ * cpu_to_le32() macro anymore, since we have to support
+ * "dynamic" switching between be and le support, so that the driver
+ * can be used on one system with SoC EHCI controller using big-endian
+ * descriptors as well as a normal little-endian PCI EHCI controller.
+ */
+/* values for that type tag */
+#define Q_TYPE_ITD	(0 << 1)
+#define Q_TYPE_QH	(1 << 1)
+#define Q_TYPE_SITD	(2 << 1)
+#define Q_TYPE_FSTN	(3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define QH_NEXT(fotg210, dma) \
+	(cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH))
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define FOTG210_LIST_END(fotg210) \
+	cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union fotg210_shadow {
+	struct fotg210_qh	*qh;		/* Q_TYPE_QH */
+	struct fotg210_itd	*itd;		/* Q_TYPE_ITD */
+	struct fotg210_fstn	*fstn;		/* Q_TYPE_FSTN */
+	__hc32			*hw_next;	/* (all types) */
+	void			*ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+/* first part defined by EHCI spec */
+struct fotg210_qh_hw {
+	__hc32			hw_next;	/* see EHCI 3.6.1 */
+	__hc32			hw_info1;	/* see EHCI 3.6.2 */
+#define	QH_CONTROL_EP	(1 << 27)	/* FS/LS control endpoint */
+#define	QH_HEAD		(1 << 15)	/* Head of async reclamation list */
+#define	QH_TOGGLE_CTL	(1 << 14)	/* Data toggle control */
+#define	QH_HIGH_SPEED	(2 << 12)	/* Endpoint speed */
+#define	QH_LOW_SPEED	(1 << 12)
+#define	QH_FULL_SPEED	(0 << 12)
+#define	QH_INACTIVATE	(1 << 7)	/* Inactivate on next transaction */
+	__hc32			hw_info2;	/* see EHCI 3.6.2 */
+#define	QH_SMASK	0x000000ff
+#define	QH_CMASK	0x0000ff00
+#define	QH_HUBADDR	0x007f0000
+#define	QH_HUBPORT	0x3f800000
+#define	QH_MULT		0xc0000000
+	__hc32			hw_current;	/* qtd list - see EHCI 3.6.4 */
+
+	/* qtd overlay (hardware parts of a struct fotg210_qtd) */
+	__hc32			hw_qtd_next;
+	__hc32			hw_alt_next;
+	__hc32			hw_token;
+	__hc32			hw_buf[5];
+	__hc32			hw_buf_hi[5];
+} __aligned(32);
+
+struct fotg210_qh {
+	struct fotg210_qh_hw	*hw;		/* Must come first */
+	/* the rest is HCD-private */
+	dma_addr_t		qh_dma;		/* address of qh */
+	union fotg210_shadow	qh_next;	/* ptr to qh; or periodic */
+	struct list_head	qtd_list;	/* sw qtd list */
+	struct list_head	intr_node;	/* list of intr QHs */
+	struct fotg210_qtd	*dummy;
+	struct fotg210_qh	*unlink_next;	/* next on unlink list */
+
+	unsigned		unlink_cycle;
+
+	u8			needs_rescan;	/* Dequeue during giveback */
+	u8			qh_state;
+#define	QH_STATE_LINKED		1		/* HC sees this */
+#define	QH_STATE_UNLINK		2		/* HC may still see this */
+#define	QH_STATE_IDLE		3		/* HC doesn't see this */
+#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on unlink q */
+#define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
+
+	u8			xacterrs;	/* XactErr retry counter */
+#define	QH_XACTERR_MAX		32		/* XactErr retry limit */
+
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	u16			tt_usecs;	/* tt downstream bandwidth */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+#define NO_FRAME ((unsigned short)~0)			/* pick new start */
+
+	struct usb_device	*dev;		/* access to TT */
+	unsigned		is_out:1;	/* bulk or intr OUT */
+	unsigned		clearing_tt:1;	/* Clear-TT-Buf in progress */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* description of one iso transaction (up to 3 KB data if highspeed) */
+struct fotg210_iso_packet {
+	/* These will be copied to iTD when scheduling */
+	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
+	__hc32			transaction;	/* itd->hw_transaction[i] |= */
+	u8			cross;		/* buf crosses pages */
+	/* for full speed OUT splits */
+	u32			buf1;
+};
+
+/* temporary schedule data for packets from iso urbs (both speeds)
+ * each packet is one logical usb transaction to the device (not TT),
+ * beginning at stream->next_uframe
+ */
+struct fotg210_iso_sched {
+	struct list_head	td_list;
+	unsigned		span;
+	struct fotg210_iso_packet	packet[0];
+};
+
+/*
+ * fotg210_iso_stream - groups all (s)itds for this endpoint.
+ * acts like a qh would, if EHCI had them for ISO.
+ */
+struct fotg210_iso_stream {
+	/* first field matches fotg210_hq, but is NULL */
+	struct fotg210_qh_hw	*hw;
+
+	u8			bEndpointAddress;
+	u8			highspeed;
+	struct list_head	td_list;	/* queued itds */
+	struct list_head	free_list;	/* list of unused itds */
+	struct usb_device	*udev;
+	struct usb_host_endpoint *ep;
+
+	/* output of (re)scheduling */
+	int			next_uframe;
+	__hc32			splits;
+
+	/* the rest is derived from the endpoint descriptor,
+	 * trusting urb->interval == f(epdesc->bInterval) and
+	 * including the extra info for hw_bufp[0..2]
+	 */
+	u8			usecs, c_usecs;
+	u16			interval;
+	u16			tt_usecs;
+	u16			maxp;
+	u16			raw_mask;
+	unsigned		bandwidth;
+
+	/* This is used to initialize iTD's hw_bufp fields */
+	__hc32			buf0;
+	__hc32			buf1;
+	__hc32			buf2;
+
+	/* this is used to initialize sITD's tt info */
+	__hc32			address;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct fotg210_itd {
+	/* first part defined by EHCI spec */
+	__hc32			hw_next;	/* see EHCI 3.3.1 */
+	__hc32			hw_transaction[8]; /* see EHCI 3.3.2 */
+#define FOTG210_ISOC_ACTIVE	(1<<31)	/* activate transfer this slot */
+#define FOTG210_ISOC_BUF_ERR	(1<<30)	/* Data buffer error */
+#define FOTG210_ISOC_BABBLE	(1<<29)	/* babble detected */
+#define FOTG210_ISOC_XACTERR	(1<<28)	/* XactErr - transaction error */
+#define	FOTG210_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
+#define	FOTG210_ITD_IOC		(1 << 15)	/* interrupt on complete */
+
+#define ITD_ACTIVE(fotg210)	cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE)
+
+	__hc32			hw_bufp[7];	/* see EHCI 3.3.3 */
+	__hc32			hw_bufp_hi[7];	/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		itd_dma;	/* for this itd */
+	union fotg210_shadow	itd_next;	/* ptr to periodic q entry */
+
+	struct urb		*urb;
+	struct fotg210_iso_stream	*stream;	/* endpoint's queue */
+	struct list_head	itd_list;	/* list of stream's itds */
+
+	/* any/all hw_transactions here may be used by that urb */
+	unsigned		frame;		/* where scheduled */
+	unsigned		pg;
+	unsigned		index[8];	/* in urb->iso_frame_desc */
+} __aligned(32);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct fotg210_fstn {
+	__hc32			hw_next;	/* any periodic q entry */
+	__hc32			hw_prev;	/* qh or FOTG210_LIST_END */
+
+	/* the rest is HCD-private */
+	dma_addr_t		fstn_dma;
+	union fotg210_shadow	fstn_next;	/* ptr to periodic q entry */
+} __aligned(32);
+
+/*-------------------------------------------------------------------------*/
+
+/* Prepare the PORTSC wakeup flags during controller suspend/resume */
+
+#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \
+		fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup);
+
+#define fotg210_prepare_ports_for_controller_resume(fotg210)		\
+		fotg210_adjust_port_wakeup_flags(fotg210, false, false);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Some EHCI controllers have a Transaction Translator built into the
+ * root hub. This is a non-standard feature.  Each controller will need
+ * to add code to the following inline functions, and call them as
+ * needed (mostly in root hub code).
+ */
+
+static inline unsigned int
+fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
+{
+	return (readl(&fotg210->regs->otgcsr)
+		& OTGCSR_HOST_SPD_TYP) >> 22;
+}
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int
+fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
+{
+	switch (fotg210_get_speed(fotg210, portsc)) {
+	case 0:
+		return 0;
+	case 1:
+		return USB_PORT_STAT_LOW_SPEED;
+	case 2:
+	default:
+		return USB_PORT_STAT_HIGH_SPEED;
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	fotg210_has_fsl_portno_bug(e)		(0)
+
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ *
+ */
+
+#define fotg210_big_endian_mmio(e)	0
+#define fotg210_big_endian_capbase(e)	0
+
+static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210,
+		__u32 __iomem *regs)
+{
+	return readl(regs);
+}
+
+static inline void fotg210_writel(const struct fotg210_hcd *fotg210,
+		const unsigned int val, __u32 __iomem *regs)
+{
+	writel(val, regs);
+}
+
+/* cpu to fotg210 */
+static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x)
+{
+	return cpu_to_le32(x);
+}
+
+/* fotg210 to cpu */
+static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x)
+{
+	return le32_to_cpu(x);
+}
+
+static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210,
+			       const __hc32 *x)
+{
+	return le32_to_cpup(x);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210)
+{
+	return fotg210_readl(fotg210, &fotg210->regs->frame_index);
+}
+
+#define fotg210_itdlen(urb, desc, t) ({			\
+	usb_pipein((urb)->pipe) ?				\
+	(desc)->length - FOTG210_ITD_LENGTH(t) :			\
+	FOTG210_ITD_LENGTH(t);					\
+})
+/*-------------------------------------------------------------------------*/
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif	/* DEBUG */
+
+/*-------------------------------------------------------------------------*/
+
+#endif /* __LINUX_FOTG210_H */
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 11e0b79..cfbff71 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -258,7 +258,7 @@
 
 int fsl_usb2_mpc5121_init(struct platform_device *pdev)
 {
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct clk *clk;
 	char clk_name[10];
 	int base, clk_num;
@@ -298,7 +298,7 @@
 
 static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
 {
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	pdata->regs = NULL;
 
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 483990c..5b86ffb 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -161,6 +161,13 @@
 	usb_hcd->uses_new_polling = 1;
 	set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
 	usb_hcd->state = HC_STATE_RUNNING;
+
+	/*
+	 * prevent USB core from suspending the root hub since
+	 * bus_suspend and bus_resume are not yet supported.
+	 */
+	pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
+
 	result = 0;
 out:
 	mutex_unlock(&wusbhc->mutex);
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index 03dc4d9..60a5de5 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1860,7 +1860,7 @@
 	imx21 = hcd_to_imx21(hcd);
 	imx21->hcd = hcd;
 	imx21->dev = &pdev->dev;
-	imx21->pdata = pdev->dev.platform_data;
+	imx21->pdata = dev_get_platdata(&pdev->dev);
 	if (!imx21->pdata)
 		imx21->pdata = &default_pdata;
 
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index b64e661..c7d0f8f 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1626,7 +1626,7 @@
 	isp116x->addr_reg = addr_reg;
 	spin_lock_init(&isp116x->lock);
 	INIT_LIST_HEAD(&isp116x->async);
-	isp116x->board = pdev->dev.platform_data;
+	isp116x->board = dev_get_platdata(&pdev->dev);
 
 	if (!isp116x->board) {
 		ERR("Platform data structure not initialized\n");
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
index 9a2c400..dd34b7a 100644
--- a/drivers/usb/host/isp116x.h
+++ b/drivers/usb/host/isp116x.h
@@ -325,11 +325,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(stuff...)		printk(KERN_DEBUG "116x: " stuff)
-#else
-#define DBG(stuff...)		do{}while(0)
-#endif
+#define DBG(stuff...)		pr_debug("116x: " stuff)
 
 #ifdef VERBOSE
 #    define VDBG		DBG
@@ -358,15 +354,8 @@
 #define isp116x_check_platform_delay(h)	0
 #endif
 
-#if defined(DEBUG)
-#define	IRQ_TEST()	BUG_ON(!irqs_disabled())
-#else
-#define	IRQ_TEST()	do{}while(0)
-#endif
-
 static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
 {
-	IRQ_TEST();
 	writew(reg & 0xff, isp116x->addr_reg);
 	isp116x_delay(isp116x, 300);
 }
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index b04e8ec..6f29aba 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -37,11 +37,7 @@
  * recovery time (MSCx = 0x7f8c) with a memory clock of 99.53 MHz.
  */
 
-#ifdef CONFIG_USB_DEBUG
-# define ISP1362_DEBUG
-#else
-# undef ISP1362_DEBUG
-#endif
+#undef ISP1362_DEBUG
 
 /*
  * The PXA255 UDC apparently doesn't handle GET_STATUS, GET_CONFIG and
@@ -82,6 +78,8 @@
 #include <linux/io.h>
 #include <linux/bitmap.h>
 #include <linux/prefetch.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/irq.h>
 #include <asm/byteorder.h>
@@ -92,7 +90,6 @@
 module_param(dbg_level, int, 0644);
 #else
 module_param(dbg_level, int, 0);
-#define	STUB_DEBUG_FILE
 #endif
 
 #include "../core/usb.h"
@@ -350,8 +347,6 @@
 	struct ptd *ptd = &ep->ptd;
 	int len = PTD_GET_DIR(ptd) == PTD_DIR_IN ? 0 : ep->length;
 
-	_BUG_ON(ep->ptd_offset < 0);
-
 	prefetch(ptd);
 	isp1362_write_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE);
 	if (len)
@@ -1575,12 +1570,12 @@
 		DBG(0, "ClearHubFeature: ");
 		switch (wValue) {
 		case C_HUB_OVER_CURRENT:
-			_DBG(0, "C_HUB_OVER_CURRENT\n");
+			DBG(0, "C_HUB_OVER_CURRENT\n");
 			spin_lock_irqsave(&isp1362_hcd->lock, flags);
 			isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_OCIC);
 			spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
 		case C_HUB_LOCAL_POWER:
-			_DBG(0, "C_HUB_LOCAL_POWER\n");
+			DBG(0, "C_HUB_LOCAL_POWER\n");
 			break;
 		default:
 			goto error;
@@ -1591,7 +1586,7 @@
 		switch (wValue) {
 		case C_HUB_OVER_CURRENT:
 		case C_HUB_LOCAL_POWER:
-			_DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
+			DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
 			break;
 		default:
 			goto error;
@@ -1622,36 +1617,36 @@
 
 		switch (wValue) {
 		case USB_PORT_FEAT_ENABLE:
-			_DBG(0, "USB_PORT_FEAT_ENABLE\n");
+			DBG(0, "USB_PORT_FEAT_ENABLE\n");
 			tmp = RH_PS_CCS;
 			break;
 		case USB_PORT_FEAT_C_ENABLE:
-			_DBG(0, "USB_PORT_FEAT_C_ENABLE\n");
+			DBG(0, "USB_PORT_FEAT_C_ENABLE\n");
 			tmp = RH_PS_PESC;
 			break;
 		case USB_PORT_FEAT_SUSPEND:
-			_DBG(0, "USB_PORT_FEAT_SUSPEND\n");
+			DBG(0, "USB_PORT_FEAT_SUSPEND\n");
 			tmp = RH_PS_POCI;
 			break;
 		case USB_PORT_FEAT_C_SUSPEND:
-			_DBG(0, "USB_PORT_FEAT_C_SUSPEND\n");
+			DBG(0, "USB_PORT_FEAT_C_SUSPEND\n");
 			tmp = RH_PS_PSSC;
 			break;
 		case USB_PORT_FEAT_POWER:
-			_DBG(0, "USB_PORT_FEAT_POWER\n");
+			DBG(0, "USB_PORT_FEAT_POWER\n");
 			tmp = RH_PS_LSDA;
 
 			break;
 		case USB_PORT_FEAT_C_CONNECTION:
-			_DBG(0, "USB_PORT_FEAT_C_CONNECTION\n");
+			DBG(0, "USB_PORT_FEAT_C_CONNECTION\n");
 			tmp = RH_PS_CSC;
 			break;
 		case USB_PORT_FEAT_C_OVER_CURRENT:
-			_DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n");
+			DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n");
 			tmp = RH_PS_OCIC;
 			break;
 		case USB_PORT_FEAT_C_RESET:
-			_DBG(0, "USB_PORT_FEAT_C_RESET\n");
+			DBG(0, "USB_PORT_FEAT_C_RESET\n");
 			tmp = RH_PS_PRSC;
 			break;
 		default:
@@ -1671,7 +1666,7 @@
 		wIndex--;
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
-			_DBG(0, "USB_PORT_FEAT_SUSPEND\n");
+			DBG(0, "USB_PORT_FEAT_SUSPEND\n");
 			spin_lock_irqsave(&isp1362_hcd->lock, flags);
 			isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS);
 			isp1362_hcd->rhport[wIndex] =
@@ -1679,7 +1674,7 @@
 			spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
 			break;
 		case USB_PORT_FEAT_POWER:
-			_DBG(0, "USB_PORT_FEAT_POWER\n");
+			DBG(0, "USB_PORT_FEAT_POWER\n");
 			spin_lock_irqsave(&isp1362_hcd->lock, flags);
 			isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PPS);
 			isp1362_hcd->rhport[wIndex] =
@@ -1687,7 +1682,7 @@
 			spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
 			break;
 		case USB_PORT_FEAT_RESET:
-			_DBG(0, "USB_PORT_FEAT_RESET\n");
+			DBG(0, "USB_PORT_FEAT_RESET\n");
 			spin_lock_irqsave(&isp1362_hcd->lock, flags);
 
 			t1 = jiffies + msecs_to_jiffies(USB_RESET_WIDTH);
@@ -1721,7 +1716,7 @@
 	default:
  error:
 		/* "protocol stall" on error */
-		_DBG(0, "PROTOCOL STALL\n");
+		DBG(0, "PROTOCOL STALL\n");
 		retval = -EPIPE;
 	}
 
@@ -1913,20 +1908,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef STUB_DEBUG_FILE
-
-static inline void create_debug_file(struct isp1362_hcd *isp1362_hcd)
-{
-}
-static inline void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
-{
-}
-
-#else
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
 static void dump_irq(struct seq_file *s, char *label, u16 mask)
 {
 	seq_printf(s, "%-15s %04x%s%s%s%s%s%s\n", label, mask,
@@ -2069,7 +2050,7 @@
 		   isp1362_read_reg16(isp1362_hcd, HCATLDTCTO));
 }
 
-static int proc_isp1362_show(struct seq_file *s, void *unused)
+static int isp1362_show(struct seq_file *s, void *unused)
 {
 	struct isp1362_hcd *isp1362_hcd = s->private;
 	struct isp1362_ep *ep;
@@ -2173,41 +2154,31 @@
 	return 0;
 }
 
-static int proc_isp1362_open(struct inode *inode, struct file *file)
+static int isp1362_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, proc_isp1362_show, PDE_DATA(inode));
+	return single_open(file, isp1362_show, inode);
 }
 
-static const struct file_operations proc_ops = {
-	.open = proc_isp1362_open,
+static const struct file_operations debug_ops = {
+	.open = isp1362_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = single_release,
 };
 
 /* expect just one isp1362_hcd per system */
-static const char proc_filename[] = "driver/isp1362";
-
 static void create_debug_file(struct isp1362_hcd *isp1362_hcd)
 {
-	struct proc_dir_entry *pde;
-
-	pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, isp1362_hcd);
-	if (pde == NULL) {
-		pr_warning("%s: Failed to create debug file '%s'\n", __func__, proc_filename);
-		return;
-	}
-	isp1362_hcd->pde = pde;
+	isp1362_hcd->debug_file = debugfs_create_file("isp1362", S_IRUGO,
+						      usb_debug_root,
+						      isp1362_hcd, &debug_ops);
 }
 
 static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
 {
-	if (isp1362_hcd->pde)
-		remove_proc_entry(proc_filename, NULL);
+	debugfs_remove(isp1362_hcd->debug_file);
 }
 
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
@@ -2754,7 +2725,7 @@
 	INIT_LIST_HEAD(&isp1362_hcd->periodic);
 	INIT_LIST_HEAD(&isp1362_hcd->isoc);
 	INIT_LIST_HEAD(&isp1362_hcd->remove_list);
-	isp1362_hcd->board = pdev->dev.platform_data;
+	isp1362_hcd->board = dev_get_platdata(&pdev->dev);
 #if USE_PLATFORM_DELAY
 	if (!isp1362_hcd->board->delay) {
 		dev_err(hcd->self.controller, "No platform delay function given\n");
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 0f97820..3b0b484 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -76,14 +76,14 @@
 
 #define ISP1362_REG_WRITE_OFFSET	0x80
 
-#ifdef ISP1362_DEBUG
-typedef const unsigned int isp1362_reg_t;
-
 #define REG_WIDTH_16			0x000
 #define REG_WIDTH_32			0x100
 #define REG_WIDTH_MASK			0x100
 #define REG_NO_MASK			0x0ff
 
+#ifdef ISP1362_DEBUG
+typedef const unsigned int isp1362_reg_t;
+
 #define REG_ACCESS_R			0x200
 #define REG_ACCESS_W			0x400
 #define REG_ACCESS_RW			0x600
@@ -91,9 +91,6 @@
 
 #define ISP1362_REG_NO(r)		((r) & REG_NO_MASK)
 
-#define _BUG_ON(x)	BUG_ON(x)
-#define _WARN_ON(x)	WARN_ON(x)
-
 #define ISP1362_REG(name, addr, width, rw) \
 static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw))
 
@@ -102,8 +99,6 @@
 #else
 typedef const unsigned char isp1362_reg_t;
 #define ISP1362_REG_NO(r)		(r)
-#define _BUG_ON(x)			do {} while (0)
-#define _WARN_ON(x)			do {} while (0)
 
 #define ISP1362_REG(name, addr, width, rw) \
 static isp1362_reg_t ISP1362_REG_##name = addr
@@ -485,7 +480,7 @@
 
 	struct isp1362_platform_data *board;
 
-	struct proc_dir_entry	*pde;
+	struct dentry		*debug_file;
 	unsigned long		stat1, stat2, stat4, stat8, stat16;
 
 	/* HC registers */
@@ -587,21 +582,11 @@
  * ISP1362 HW Interface
  */
 
-#ifdef ISP1362_DEBUG
 #define DBG(level, fmt...) \
 	do { \
 		if (dbg_level > level) \
 			pr_debug(fmt); \
 	} while (0)
-#define _DBG(level, fmt...)	\
-	do { \
-		if (dbg_level > level) \
-			printk(fmt); \
-	} while (0)
-#else
-#define DBG(fmt...)		do {} while (0)
-#define _DBG DBG
-#endif
 
 #ifdef VERBOSE
 #    define VDBG(fmt...)	DBG(3, fmt)
@@ -645,9 +630,7 @@
  */
 static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg)
 {
-	/*_BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W));*/
 	REG_ACCESS_TEST(reg);
-	_BUG_ON(!irqs_disabled());
 	DUMMY_DELAY_ACCESS;
 	writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg);
 	DUMMY_DELAY_ACCESS;
@@ -656,7 +639,6 @@
 
 static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val)
 {
-	_BUG_ON(!irqs_disabled());
 	DUMMY_DELAY_ACCESS;
 	writew(val, isp1362_hcd->data_reg);
 }
@@ -665,7 +647,6 @@
 {
 	u16 val;
 
-	_BUG_ON(!irqs_disabled());
 	DUMMY_DELAY_ACCESS;
 	val = readw(isp1362_hcd->data_reg);
 
@@ -674,7 +655,6 @@
 
 static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val)
 {
-	_BUG_ON(!irqs_disabled());
 #if USE_32BIT
 	DUMMY_DELAY_ACCESS;
 	writel(val, isp1362_hcd->data_reg);
@@ -690,7 +670,6 @@
 {
 	u32 val;
 
-	_BUG_ON(!irqs_disabled());
 #if USE_32BIT
 	DUMMY_DELAY_ACCESS;
 	val = readl(isp1362_hcd->data_reg);
@@ -713,8 +692,6 @@
 	if (!len)
 		return;
 
-	_BUG_ON(!irqs_disabled());
-
 	RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf);
 #if USE_32BIT
 	if (len >= 4) {
@@ -760,8 +737,6 @@
 		return;
 	}
 
-	_BUG_ON(!irqs_disabled());
-
 	RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf);
 #if USE_32BIT
 	if (len >= 4) {
@@ -854,7 +829,6 @@
 		isp1362_write_reg32(d, r, __v & ~m);	\
 }
 
-#ifdef ISP1362_DEBUG
 #define isp1362_show_reg(d, r) {								\
 	if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32)			\
 		DBG(0, "%-12s[%02x]: %08x\n", #r,					\
@@ -863,9 +837,6 @@
 		DBG(0, "%-12s[%02x]:     %04x\n", #r,					\
 			ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r));	\
 }
-#else
-#define isp1362_show_reg(d, r)	do {} while (0)
-#endif
 
 static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd)
 {
@@ -923,10 +894,6 @@
 
 static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len)
 {
-	_BUG_ON(offset & 1);
-	_BUG_ON(offset >= ISP1362_BUF_SIZE);
-	_BUG_ON(len > ISP1362_BUF_SIZE);
-	_BUG_ON(offset + len > ISP1362_BUF_SIZE);
 	len = (len + 1) & ~1;
 
 	isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE);
@@ -936,42 +903,32 @@
 
 static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
 {
-	_BUG_ON(offset & 1);
-
 	isp1362_write_diraddr(isp1362_hcd, offset, len);
 
 	DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
 	    __func__, len, offset, buf);
 
 	isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-	_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 
 	isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA);
 
 	isp1362_read_fifo(isp1362_hcd, buf, len);
-	_WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 	isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-	_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 }
 
 static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
 {
-	_BUG_ON(offset & 1);
-
 	isp1362_write_diraddr(isp1362_hcd, offset, len);
 
 	DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
 	    __func__, len, offset, buf);
 
 	isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-	_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 
 	isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET);
 	isp1362_write_fifo(isp1362_hcd, buf, len);
 
-	_WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 	isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
-	_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
 }
 
 static void __attribute__((unused)) dump_data(char *buf, int len)
@@ -1002,7 +959,7 @@
 	}
 }
 
-#if defined(ISP1362_DEBUG) && defined(PTD_TRACE)
+#if defined(PTD_TRACE)
 
 static void dump_ptd(struct ptd *ptd)
 {
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 3df49b1..df931e9 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -351,7 +351,7 @@
 	struct resource *mem_res;
 	struct resource *irq_res;
 	resource_size_t mem_size;
-	struct isp1760_platform_data *priv = pdev->dev.platform_data;
+	struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
 	unsigned int devflags = 0;
 	unsigned long irqflags = IRQF_SHARED;
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 9677f68..caa3764 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -31,8 +31,8 @@
 #define at91_for_each_port(index)	\
 		for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
 
-/* interface and function clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *hclk;
+/* interface, function and usb clocks; sometimes also an AHB clock */
+static struct clk *iclk, *fclk, *uclk, *hclk;
 static int clocked;
 
 extern int usb_disabled(void);
@@ -41,6 +41,10 @@
 
 static void at91_start_clock(void)
 {
+	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+		clk_set_rate(uclk, 48000000);
+		clk_prepare_enable(uclk);
+	}
 	clk_prepare_enable(hclk);
 	clk_prepare_enable(iclk);
 	clk_prepare_enable(fclk);
@@ -52,6 +56,8 @@
 	clk_disable_unprepare(fclk);
 	clk_disable_unprepare(iclk);
 	clk_disable_unprepare(hclk);
+	if (IS_ENABLED(CONFIG_COMMON_CLK))
+		clk_disable_unprepare(uclk);
 	clocked = 0;
 }
 
@@ -162,6 +168,14 @@
 		retval = PTR_ERR(hclk);
 		goto err5;
 	}
+	if (IS_ENABLED(CONFIG_COMMON_CLK)) {
+		uclk = clk_get(&pdev->dev, "usb_clk");
+		if (IS_ERR(uclk)) {
+			dev_err(&pdev->dev, "failed to get uclk\n");
+			retval = PTR_ERR(uclk);
+			goto err6;
+		}
+	}
 
 	at91_start_hc(pdev);
 	ohci_hcd_init(hcd_to_ohci(hcd));
@@ -173,6 +187,9 @@
 	/* Error handling */
 	at91_stop_hc(pdev);
 
+	if (IS_ENABLED(CONFIG_COMMON_CLK))
+		clk_put(uclk);
+ err6:
 	clk_put(hclk);
  err5:
 	clk_put(fclk);
@@ -212,12 +229,12 @@
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 
+	if (IS_ENABLED(CONFIG_COMMON_CLK))
+		clk_put(uclk);
 	clk_put(hclk);
 	clk_put(fclk);
 	clk_put(iclk);
 	fclk = iclk = hclk = NULL;
-
-	dev_set_drvdata(&pdev->dev, NULL);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -225,7 +242,7 @@
 static int
 ohci_at91_reset (struct usb_hcd *hcd)
 {
-	struct at91_usbh_data	*board = hcd->self.controller->platform_data;
+	struct at91_usbh_data	*board = dev_get_platdata(hcd->self.controller);
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	int			ret;
 
@@ -280,7 +297,7 @@
  */
 static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
-	struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
+	struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller);
 	int length = ohci_hub_status_data(hcd, buf);
 	int port;
 
@@ -301,7 +318,7 @@
 static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 				 u16 wIndex, char *buf, u16 wLength)
 {
-	struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
+	struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller);
 	struct usb_hub_descriptor *desc;
 	int ret = -EINVAL;
 	u32 *data = (u32 *)buf;
@@ -461,7 +478,7 @@
 static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
 {
 	struct platform_device *pdev = data;
-	struct at91_usbh_data *pdata = pdev->dev.platform_data;
+	struct at91_usbh_data *pdata = dev_get_platdata(&pdev->dev);
 	int val, gpio, port;
 
 	/* From the GPIO notifying the over-current situation, find
@@ -567,7 +584,7 @@
 	if (ret)
 		return ret;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 
 	if (pdata) {
 		at91_for_each_port(i) {
@@ -643,7 +660,7 @@
 
 static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
 {
-	struct at91_usbh_data	*pdata = pdev->dev.platform_data;
+	struct at91_usbh_data	*pdata = dev_get_platdata(&pdev->dev);
 	int			i;
 
 	if (pdata) {
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 6aaa9c9..9be59f1 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -85,7 +85,7 @@
 static int ohci_da8xx_init(struct usb_hcd *hcd)
 {
 	struct device *dev		= hcd->self.controller;
-	struct da8xx_ohci_root_hub *hub	= dev->platform_data;
+	struct da8xx_ohci_root_hub *hub	= dev_get_platdata(dev);
 	struct ohci_hcd	*ohci		= hcd_to_ohci(hcd);
 	int result;
 	u32 rh_a;
@@ -171,7 +171,7 @@
 				  u16 wIndex, char *buf, u16 wLength)
 {
 	struct device *dev		= hcd->self.controller;
-	struct da8xx_ohci_root_hub *hub	= dev->platform_data;
+	struct da8xx_ohci_root_hub *hub	= dev_get_platdata(dev);
 	int temp;
 
 	switch (typeReq) {
@@ -292,7 +292,7 @@
 static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
 			       struct platform_device *pdev)
 {
-	struct da8xx_ohci_root_hub *hub	= pdev->dev.platform_data;
+	struct da8xx_ohci_root_hub *hub	= dev_get_platdata(&pdev->dev);
 	struct usb_hcd	*hcd;
 	struct resource *mem;
 	int error, irq;
@@ -380,7 +380,7 @@
 static inline void
 usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
 {
-	struct da8xx_ohci_root_hub *hub	= pdev->dev.platform_data;
+	struct da8xx_ohci_root_hub *hub	= dev_get_platdata(&pdev->dev);
 
 	hub->ocic_notify(NULL);
 	usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 8704e9f..84a20d5 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -30,83 +30,6 @@
 
 static struct clk *usb_host_clock;
 
-static void ep93xx_start_hc(struct device *dev)
-{
-	clk_enable(usb_host_clock);
-}
-
-static void ep93xx_stop_hc(struct device *dev)
-{
-	clk_disable(usb_host_clock);
-}
-
-static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
-			 struct platform_device *pdev)
-{
-	int retval;
-	struct usb_hcd *hcd;
-
-	if (pdev->resource[1].flags != IORESOURCE_IRQ) {
-		dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n");
-		return -ENOMEM;
-	}
-
-	hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx");
-	if (hcd == NULL)
-		return -ENOMEM;
-
-	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)) {
-		usb_put_hcd(hcd);
-		retval = -EBUSY;
-		goto err1;
-	}
-
-	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
-	if (hcd->regs == NULL) {
-		dev_dbg(&pdev->dev, "ioremap failed\n");
-		retval = -ENOMEM;
-		goto err2;
-	}
-
-	usb_host_clock = clk_get(&pdev->dev, NULL);
-	if (IS_ERR(usb_host_clock)) {
-		dev_dbg(&pdev->dev, "clk_get failed\n");
-		retval = PTR_ERR(usb_host_clock);
-		goto err3;
-	}
-
-	ep93xx_start_hc(&pdev->dev);
-
-	ohci_hcd_init(hcd_to_ohci(hcd));
-
-	retval = usb_add_hcd(hcd, pdev->resource[1].start, 0);
-	if (retval == 0)
-		return retval;
-
-	ep93xx_stop_hc(&pdev->dev);
-err3:
-	iounmap(hcd->regs);
-err2:
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err1:
-	usb_put_hcd(hcd);
-
-	return retval;
-}
-
-static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd,
-			struct platform_device *pdev)
-{
-	usb_remove_hcd(hcd);
-	ep93xx_stop_hc(&pdev->dev);
-	clk_put(usb_host_clock);
-	iounmap(hcd->regs);
-	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	usb_put_hcd(hcd);
-}
-
 static int ohci_ep93xx_start(struct usb_hcd *hcd)
 {
 	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
@@ -147,15 +70,57 @@
 	.start_port_reset	= ohci_start_port_reset,
 };
 
-extern int usb_disabled(void);
-
 static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev)
 {
+	struct usb_hcd *hcd;
+	struct resource *res;
+	int irq;
 	int ret;
 
-	ret = -ENODEV;
-	if (!usb_disabled())
-		ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev);
+	if (usb_disabled())
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	hcd = usb_create_hcd(&ohci_ep93xx_hc_driver, &pdev->dev, "ep93xx");
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hcd->regs)) {
+		ret = PTR_ERR(hcd->regs);
+		goto err_put_hcd;
+	}
+
+	usb_host_clock = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(usb_host_clock)) {
+		ret = PTR_ERR(usb_host_clock);
+		goto err_put_hcd;
+	}
+
+	clk_enable(usb_host_clock);
+
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	ret = usb_add_hcd(hcd, irq, 0);
+	if (ret)
+		goto err_clk_disable;
+
+	return 0;
+
+err_clk_disable:
+	clk_disable(usb_host_clock);
+err_put_hcd:
+	usb_put_hcd(hcd);
 
 	return ret;
 }
@@ -164,7 +129,9 @@
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
-	usb_hcd_ep93xx_remove(hcd, pdev);
+	usb_remove_hcd(hcd);
+	clk_disable(usb_host_clock);
+	usb_put_hcd(hcd);
 
 	return 0;
 }
@@ -179,7 +146,7 @@
 		msleep(5);
 	ohci->next_statechange = jiffies;
 
-	ep93xx_stop_hc(&pdev->dev);
+	clk_disable(usb_host_clock);
 	return 0;
 }
 
@@ -192,7 +159,7 @@
 		msleep(5);
 	ohci->next_statechange = jiffies;
 
-	ep93xx_start_hc(&pdev->dev);
+	clk_enable(usb_host_clock);
 
 	ohci_resume(hcd, false);
 	return 0;
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index b0b542c..dc6ee9a 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -100,7 +100,7 @@
 
 static int exynos_ohci_probe(struct platform_device *pdev)
 {
-	struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
+	struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev);
 	struct exynos_ohci_hcd *exynos_ohci;
 	struct usb_hcd *hcd;
 	struct ohci_hcd *ohci;
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a9d3437..8f6b695 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -938,8 +938,8 @@
 	if (quirk_nec(ohci))
 		flush_work(&ohci->nec_work);
 
-	ohci_usb_reset (ohci);
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	ohci_usb_reset(ohci);
 	free_irq(hcd->irq, hcd);
 	hcd->irq = 0;
 
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 8747fa6..31d3a12 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -191,7 +191,7 @@
 static int ohci_omap_init(struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci(hcd);
-	struct omap_usb_config	*config = hcd->self.controller->platform_data;
+	struct omap_usb_config	*config = dev_get_platdata(hcd->self.controller);
 	int			need_transceiver = (config->otg != 0);
 	int			ret;
 
@@ -427,7 +427,7 @@
 
 	if (!host_enabled)
 		return 0;
-	config = hcd->self.controller->platform_data;
+	config = dev_get_platdata(hcd->self.controller);
 	if (config->otg || config->rwc) {
 		ohci->hc_control = OHCI_CTRL_RWC;
 		writel(OHCI_CTRL_RWC, &ohci->regs->control);
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index 8f71357..a09af26 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -231,14 +231,6 @@
 	return 0;
 }
 
-static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
-
-	if (hcd->driver->shutdown)
-		hcd->driver->shutdown(hcd);
-}
-
 static const struct of_device_id omap_ohci_dt_ids[] = {
 	{ .compatible = "ti,ohci-omap3" },
 	{ }
@@ -249,7 +241,7 @@
 static struct platform_driver ohci_hcd_omap3_driver = {
 	.probe		= ohci_hcd_omap3_probe,
 	.remove		= ohci_hcd_omap3_remove,
-	.shutdown	= ohci_hcd_omap3_shutdown,
+	.shutdown	= usb_hcd_platform_shutdown,
 	.driver		= {
 		.name	= "ohci-omap3",
 		.of_match_table = omap_ohci_dt_ids,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 08613e2..ec337c2 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -289,7 +289,7 @@
 	.remove =	usb_hcd_pci_remove,
 	.shutdown =	usb_hcd_pci_shutdown,
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 	.driver =	{
 		.pm =	&usb_hcd_pci_pm_ops
 	},
@@ -304,6 +304,13 @@
 	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
 
 	ohci_init_driver(&ohci_pci_hc_driver, &pci_overrides);
+
+#ifdef	CONFIG_PM
+	/* Entries for the PCI suspend/resume callbacks are special */
+	ohci_pci_hc_driver.pci_suspend = ohci_suspend;
+	ohci_pci_hc_driver.pci_resume = ohci_resume;
+#endif
+
 	return pci_register_driver(&ohci_pci_driver);
 }
 module_init(ohci_pci_init);
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index bc30475..a4c6410 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -33,7 +33,7 @@
 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 usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev);
 	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
 
 	if (pdata->big_endian_desc)
@@ -59,7 +59,7 @@
 {
 	struct usb_hcd *hcd;
 	struct resource *res_mem;
-	struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 	int irq;
 	int err = -ENOMEM;
 
@@ -124,7 +124,7 @@
 static int ohci_platform_remove(struct platform_device *dev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
-	struct usb_ohci_pdata *pdata = dev->dev.platform_data;
+	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 
 	usb_remove_hcd(hcd);
 	usb_put_hcd(hcd);
@@ -139,7 +139,7 @@
 
 static int ohci_platform_suspend(struct device *dev)
 {
-	struct usb_ohci_pdata *pdata = dev->platform_data;
+	struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
 	struct platform_device *pdev =
 		container_of(dev, struct platform_device, dev);
 
@@ -152,7 +152,7 @@
 static int ohci_platform_resume(struct device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
-	struct usb_ohci_pdata *pdata = dev->platform_data;
+	struct usb_ohci_pdata *pdata = dev_get_platdata(dev);
 	struct platform_device *pdev =
 		container_of(dev, struct platform_device, dev);
 
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 8294e2f..75f5a1e 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -200,15 +200,6 @@
 	return 0;
 }
 
-static void ohci_hcd_ppc_of_shutdown(struct platform_device *op)
-{
-	struct usb_hcd *hcd = platform_get_drvdata(op);
-
-        if (hcd->driver->shutdown)
-                hcd->driver->shutdown(hcd);
-}
-
-
 static const struct of_device_id ohci_hcd_ppc_of_match[] = {
 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
 	{
@@ -243,7 +234,7 @@
 static struct platform_driver ohci_hcd_ppc_of_driver = {
 	.probe		= ohci_hcd_ppc_of_probe,
 	.remove		= ohci_hcd_ppc_of_remove,
-	.shutdown 	= ohci_hcd_ppc_of_shutdown,
+	.shutdown	= usb_hcd_platform_shutdown,
 	.driver = {
 		.name = "ppc-of-ohci",
 		.owner = THIS_MODULE,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3a9c01d..93371a2 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -219,7 +219,7 @@
 	struct pxaohci_platform_data *inf;
 	uint32_t uhchr;
 
-	inf = dev->platform_data;
+	inf = dev_get_platdata(dev);
 
 	clk_prepare_enable(ohci->clk);
 
@@ -256,7 +256,7 @@
 	struct pxaohci_platform_data *inf;
 	uint32_t uhccoms;
 
-	inf = dev->platform_data;
+	inf = dev_get_platdata(dev);
 
 	if (cpu_is_pxa3xx())
 		pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self);
@@ -364,7 +364,7 @@
 	if (retval)
 		return retval;
 
-	inf = pdev->dev.platform_data;
+	inf = dev_get_platdata(&pdev->dev);
 
 	if (!inf)
 		return -ENODEV;
@@ -577,7 +577,7 @@
 {
 	struct usb_hcd *hcd = dev_get_drvdata(dev);
 	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
-	struct pxaohci_platform_data *inf = dev->platform_data;
+	struct pxaohci_platform_data *inf = dev_get_platdata(dev);
 	int status;
 
 	if (time_before(jiffies, ohci->ohci.next_statechange))
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index e125770..4919afa 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -38,12 +38,12 @@
 
 static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd)
 {
-	return hcd->self.controller->platform_data;
+	return dev_get_platdata(hcd->self.controller);
 }
 
 static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
 {
-	struct s3c2410_hcd_info *info = dev->dev.platform_data;
+	struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
 
 	dev_dbg(&dev->dev, "s3c2410_start_hc:\n");
 
@@ -63,7 +63,7 @@
 
 static void s3c2410_stop_hc(struct platform_device *dev)
 {
-	struct s3c2410_hcd_info *info = dev->dev.platform_data;
+	struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
 
 	dev_dbg(&dev->dev, "s3c2410_stop_hc:\n");
 
@@ -339,10 +339,11 @@
 				  struct platform_device *dev)
 {
 	struct usb_hcd *hcd = NULL;
+	struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
 	int retval;
 
-	s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
-	s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
+	s3c2410_usb_set_power(info, 1, 1);
+	s3c2410_usb_set_power(info, 2, 1);
 
 	hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
 	if (hcd == NULL)
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c
index 197d514..22540ab 100644
--- a/drivers/usb/host/ohci-tilegx.c
+++ b/drivers/usb/host/ohci-tilegx.c
@@ -95,7 +95,7 @@
 static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
-	struct tilegx_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	pte_t pte = { 0 };
 	int my_cpu = smp_processor_id();
 	int ret;
@@ -175,7 +175,7 @@
 static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
-	struct tilegx_usb_platform_data* pdata = pdev->dev.platform_data;
+	struct tilegx_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	usb_remove_hcd(hcd);
 	usb_put_hcd(hcd);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index b9848e4..2c76ef1 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -735,32 +735,6 @@
 	return -ETIMEDOUT;
 }
 
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI	0x8C31
-#define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI	0x9C31
-
-bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
-{
-	return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
-		pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
-}
-
-/* The Intel Lynx Point chipset also has switchable ports. */
-bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
-{
-	return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
-		pdev->vendor == PCI_VENDOR_ID_INTEL &&
-		(pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI ||
-		 pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI);
-}
-
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
-{
-	return usb_is_intel_ppt_switchable_xhci(pdev) ||
-		usb_is_intel_lpt_switchable_xhci(pdev);
-}
-EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
-
 /*
  * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that
  * share some number of ports.  These ports can be switched between either
@@ -779,9 +753,23 @@
  * terminations before switching the USB 2.0 wires over, so that USB 3.0
  * devices connect at SuperSpeed, rather than at USB 2.0 speeds.
  */
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
+void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
 {
 	u32		ports_available;
+	bool		ehci_found = false;
+	struct pci_dev	*companion = NULL;
+
+	/* make sure an intel EHCI controller exists */
+	for_each_pci_dev(companion) {
+		if (companion->class == PCI_CLASS_SERIAL_USB_EHCI &&
+		    companion->vendor == PCI_VENDOR_ID_INTEL) {
+			ehci_found = true;
+			break;
+		}
+	}
+
+	if (!ehci_found)
+		return;
 
 	/* Don't switchover the ports if the user hasn't compiled the xHCI
 	 * driver.  Otherwise they will see "dead" USB ports that don't power
@@ -840,7 +828,7 @@
 	dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
 			"to xHCI: 0x%x\n", ports_available);
 }
-EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
+EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
 
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
 {
@@ -921,8 +909,8 @@
 	writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
 
 hc_init:
-	if (usb_is_intel_switchable_xhci(pdev))
-		usb_enable_xhci_ports(pdev);
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+		usb_enable_intel_xhci_ports(pdev);
 
 	op_reg_base = base + XHCI_HC_LENGTH(readl(base));
 
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index 978c849..ed6700d 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -8,8 +8,7 @@
 void usb_amd_dev_put(void);
 void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
-void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
+void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
 #else
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index a6fd8f53..2ad004a 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2393,7 +2393,7 @@
 
 static int r8a66597_remove(struct platform_device *pdev)
 {
-	struct r8a66597		*r8a66597 = dev_get_drvdata(&pdev->dev);
+	struct r8a66597		*r8a66597 = platform_get_drvdata(pdev);
 	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
 
 	del_timer_sync(&r8a66597->rh_timer);
@@ -2466,8 +2466,8 @@
 	}
 	r8a66597 = hcd_to_r8a66597(hcd);
 	memset(r8a66597, 0, sizeof(struct r8a66597));
-	dev_set_drvdata(&pdev->dev, r8a66597);
-	r8a66597->pdata = pdev->dev.platform_data;
+	platform_set_drvdata(pdev, r8a66597);
+	r8a66597->pdata = dev_get_platdata(&pdev->dev);
 	r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
 	if (r8a66597->pdata->on_chip) {
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index b2ec7fe..5477bf5 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -48,6 +48,8 @@
 #include <linux/usb/hcd.h>
 #include <linux/platform_device.h>
 #include <linux/prefetch.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -63,11 +65,6 @@
 
 #define DRIVER_VERSION	"19 May 2005"
 
-
-#ifndef DEBUG
-#	define	STUB_DEBUG_FILE
-#endif
-
 /* for now, use only one transfer register bank */
 #undef	USE_B
 
@@ -100,7 +97,8 @@
 
 	if (sl811->board && sl811->board->port_power) {
 		/* switch VBUS, at 500mA unless hub power budget gets set */
-		DBG("power %s\n", is_on ? "on" : "off");
+		dev_dbg(hcd->self.controller, "power %s\n",
+			is_on ? "on" : "off");
 		sl811->board->port_power(hcd->self.controller, is_on);
 	}
 
@@ -282,7 +280,7 @@
 {
 	if (sl811->irq_enable & SL11H_INTMASK_SOFINTR)
 		return;
-	VDBG("sof irq on\n");
+	dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq on\n");
 	sl811->irq_enable |= SL11H_INTMASK_SOFINTR;
 }
 
@@ -290,7 +288,7 @@
 {
 	if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR))
 		return;
-	VDBG("sof irq off\n");
+	dev_dbg(sl811_to_hcd(sl811)->self.controller, "sof irq off\n");
 	sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR;
 }
 
@@ -338,7 +336,8 @@
 	}
 
 	if (unlikely(list_empty(&ep->hep->urb_list))) {
-		DBG("empty %p queue?\n", ep);
+		dev_dbg(sl811_to_hcd(sl811)->self.controller,
+			"empty %p queue?\n", ep);
 		return NULL;
 	}
 
@@ -391,7 +390,8 @@
 		status_packet(sl811, ep, urb, bank, control);
 		break;
 	default:
-		DBG("bad ep%p pid %02x\n", ep, ep->nextpid);
+		dev_dbg(sl811_to_hcd(sl811)->self.controller,
+			"bad ep%p pid %02x\n", ep, ep->nextpid);
 		ep = NULL;
 	}
 	return ep;
@@ -447,7 +447,8 @@
 	}
 
 	/* periodic deschedule */
-	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+	dev_dbg(sl811_to_hcd(sl811)->self.controller,
+		"deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
 	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
 		struct sl811h_ep	*temp;
 		struct sl811h_ep	**prev = &sl811->periodic[i];
@@ -593,7 +594,8 @@
 		ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG));
 		if (ctl & SL11H_HCTLMASK_ARM)
 			sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
-		DBG("%s DONE_A: ctrl %02x sts %02x\n",
+		dev_dbg(sl811_to_hcd(sl811)->self.controller,
+			"%s DONE_A: ctrl %02x sts %02x\n",
 			(ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
 			ctl,
 			sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG)));
@@ -604,7 +606,8 @@
 		ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG));
 		if (ctl & SL11H_HCTLMASK_ARM)
 			sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
-		DBG("%s DONE_B: ctrl %02x sts %02x\n",
+		dev_dbg(sl811_to_hcd(sl811)->self.controller,
+			"%s DONE_B: ctrl %02x sts %02x\n",
 			(ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost",
 			ctl,
 			sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG)));
@@ -665,7 +668,7 @@
 		 * this one has nothing scheduled.
 		 */
 		if (sl811->next_periodic) {
-			// ERR("overrun to slot %d\n", index);
+			// dev_err(hcd->self.controller, "overrun to slot %d\n", index);
 			sl811->stat_overrun++;
 		}
 		if (sl811->periodic[index])
@@ -723,7 +726,7 @@
 
 	} else if (irqstat & SL11H_INTMASK_RD) {
 		if (sl811->port1 & USB_PORT_STAT_SUSPEND) {
-			DBG("wakeup\n");
+			dev_dbg(hcd->self.controller, "wakeup\n");
 			sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16;
 			sl811->stat_wake++;
 		} else
@@ -852,8 +855,9 @@
 
 		if (ep->maxpacket > H_MAXPACKET) {
 			/* iso packets up to 240 bytes could work... */
-			DBG("dev %d ep%d maxpacket %d\n",
-				udev->devnum, epnum, ep->maxpacket);
+			dev_dbg(hcd->self.controller,
+				"dev %d ep%d maxpacket %d\n", udev->devnum,
+				epnum, ep->maxpacket);
 			retval = -EINVAL;
 			kfree(ep);
 			goto fail;
@@ -917,7 +921,8 @@
 		 * to share the faster parts of the tree without needing
 		 * dummy/placeholder nodes
 		 */
-		DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+		dev_dbg(hcd->self.controller, "schedule qh%d/%p branch %d\n",
+			ep->period, ep, ep->branch);
 		for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
 			struct sl811h_ep	**prev = &sl811->periodic[i];
 			struct sl811h_ep	*here = *prev;
@@ -976,7 +981,8 @@
 		} else if (sl811->active_a == ep) {
 			if (time_before_eq(sl811->jiffies_a, jiffies)) {
 				/* happens a lot with lowspeed?? */
-				DBG("giveup on DONE_A: ctrl %02x sts %02x\n",
+				dev_dbg(hcd->self.controller,
+					"giveup on DONE_A: ctrl %02x sts %02x\n",
 					sl811_read(sl811,
 						SL811_EP_A(SL11H_HOSTCTLREG)),
 					sl811_read(sl811,
@@ -990,7 +996,8 @@
 		} else if (sl811->active_b == ep) {
 			if (time_before_eq(sl811->jiffies_a, jiffies)) {
 				/* happens a lot with lowspeed?? */
-				DBG("giveup on DONE_B: ctrl %02x sts %02x\n",
+				dev_dbg(hcd->self.controller,
+					"giveup on DONE_B: ctrl %02x sts %02x\n",
 					sl811_read(sl811,
 						SL811_EP_B(SL11H_HOSTCTLREG)),
 					sl811_read(sl811,
@@ -1008,7 +1015,8 @@
 		if (urb)
 			finish_request(sl811, ep, urb, 0);
 		else
-			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
+			dev_dbg(sl811_to_hcd(sl811)->self.controller,
+				"dequeue, urb %p active %s; wait4irq\n", urb,
 				(sl811->active_a == ep) ? "A" : "B");
 	} else
 		retval = -EINVAL;
@@ -1029,7 +1037,7 @@
 	if (!list_empty(&hep->urb_list))
 		msleep(3);
 	if (!list_empty(&hep->urb_list))
-		WARNING("ep %p not empty?\n", ep);
+		dev_warn(hcd->self.controller, "ep %p not empty?\n", ep);
 
 	kfree(ep);
 	hep->hcpriv = NULL;
@@ -1132,7 +1140,7 @@
 
 	switch (signaling) {
 	case SL11H_CTL1MASK_SE0:
-		DBG("end reset\n");
+		dev_dbg(sl811_to_hcd(sl811)->self.controller, "end reset\n");
 		sl811->port1 = (USB_PORT_STAT_C_RESET << 16)
 				 | USB_PORT_STAT_POWER;
 		sl811->ctrl1 = 0;
@@ -1141,11 +1149,12 @@
 			irqstat &= ~SL11H_INTMASK_RD;
 		break;
 	case SL11H_CTL1MASK_K:
-		DBG("end resume\n");
+		dev_dbg(sl811_to_hcd(sl811)->self.controller, "end resume\n");
 		sl811->port1 &= ~USB_PORT_STAT_SUSPEND;
 		break;
 	default:
-		DBG("odd timer signaling: %02x\n", signaling);
+		dev_dbg(sl811_to_hcd(sl811)->self.controller,
+			"odd timer signaling: %02x\n", signaling);
 		break;
 	}
 	sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
@@ -1243,7 +1252,7 @@
 				break;
 
 			/* 20 msec of resume/K signaling, other irqs blocked */
-			DBG("start resume...\n");
+			dev_dbg(hcd->self.controller, "start resume...\n");
 			sl811->irq_enable = 0;
 			sl811_write(sl811, SL11H_IRQ_ENABLE,
 						sl811->irq_enable);
@@ -1281,7 +1290,8 @@
 #ifndef	VERBOSE
 	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
 #endif
-		DBG("GetPortStatus %08x\n", sl811->port1);
+		dev_dbg(hcd->self.controller, "GetPortStatus %08x\n",
+			sl811->port1);
 		break;
 	case SetPortFeature:
 		if (wIndex != 1 || wLength != 0)
@@ -1293,7 +1303,7 @@
 			if (!(sl811->port1 & USB_PORT_STAT_ENABLE))
 				goto error;
 
-			DBG("suspend...\n");
+			dev_dbg(hcd->self.controller,"suspend...\n");
 			sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
 			sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
 			break;
@@ -1338,7 +1348,7 @@
 sl811h_bus_suspend(struct usb_hcd *hcd)
 {
 	// SOFs off
-	DBG("%s\n", __func__);
+	dev_dbg(hcd->self.controller, "%s\n", __func__);
 	return 0;
 }
 
@@ -1346,7 +1356,7 @@
 sl811h_bus_resume(struct usb_hcd *hcd)
 {
 	// SOFs on
-	DBG("%s\n", __func__);
+	dev_dbg(hcd->self.controller, "%s\n", __func__);
 	return 0;
 }
 
@@ -1360,16 +1370,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef STUB_DEBUG_FILE
-
-static inline void create_debug_file(struct sl811 *sl811) { }
-static inline void remove_debug_file(struct sl811 *sl811) { }
-
-#else
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-
 static void dump_irq(struct seq_file *s, char *label, u8 mask)
 {
 	seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask,
@@ -1381,7 +1381,7 @@
 		(mask & SL11H_INTMASK_DP) ? " dp" : "");
 }
 
-static int proc_sl811h_show(struct seq_file *s, void *unused)
+static int sl811h_show(struct seq_file *s, void *unused)
 {
 	struct sl811		*sl811 = s->private;
 	struct sl811h_ep	*ep;
@@ -1492,34 +1492,31 @@
 	return 0;
 }
 
-static int proc_sl811h_open(struct inode *inode, struct file *file)
+static int sl811h_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, proc_sl811h_show, PDE_DATA(inode));
+	return single_open(file, sl811h_show, inode->i_private);
 }
 
-static const struct file_operations proc_ops = {
-	.open		= proc_sl811h_open,
+static const struct file_operations debug_ops = {
+	.open		= sl811h_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
 	.release	= single_release,
 };
 
 /* expect just one sl811 per system */
-static const char proc_filename[] = "driver/sl811h";
-
 static void create_debug_file(struct sl811 *sl811)
 {
-	sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811);
+	sl811->debug_file = debugfs_create_file("sl811h", S_IRUGO,
+						usb_debug_root, sl811,
+						&debug_ops);
 }
 
 static void remove_debug_file(struct sl811 *sl811)
 {
-	if (sl811->pde)
-		remove_proc_entry(proc_filename, NULL);
+	debugfs_remove(sl811->debug_file);
 }
 
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 static void
@@ -1648,7 +1645,7 @@
 
 	/* refuse to confuse usbcore */
 	if (dev->dev.dma_mask) {
-		DBG("no we won't dma\n");
+		dev_dbg(&dev->dev, "no we won't dma\n");
 		return -EINVAL;
 	}
 
@@ -1694,7 +1691,7 @@
 
 	spin_lock_init(&sl811->lock);
 	INIT_LIST_HEAD(&sl811->async);
-	sl811->board = dev->dev.platform_data;
+	sl811->board = dev_get_platdata(&dev->dev);
 	init_timer(&sl811->timer);
 	sl811->timer.function = sl811h_timer;
 	sl811->timer.data = (unsigned long) sl811;
@@ -1716,7 +1713,7 @@
 		break;
 	default:
 		/* reject case 0, SL11S is less functional */
-		DBG("chiprev %02x\n", tmp);
+		dev_dbg(&dev->dev, "chiprev %02x\n", tmp);
 		retval = -ENXIO;
 		goto err6;
 	}
@@ -1747,7 +1744,7 @@
 	if (!ioaddr)
 		iounmap(addr_reg);
  err2:
-	DBG("init error, %d\n", retval);
+	dev_dbg(&dev->dev, "init error, %d\n", retval);
 	return retval;
 }
 
diff --git a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h
index b6b8c1f..1e23ef4 100644
--- a/drivers/usb/host/sl811.h
+++ b/drivers/usb/host/sl811.h
@@ -122,7 +122,7 @@
 	void __iomem		*addr_reg;
 	void __iomem		*data_reg;
 	struct sl811_platform_data	*board;
-	struct proc_dir_entry	*pde;
+	struct dentry 		*debug_file;
 
 	unsigned long		stat_insrmv;
 	unsigned long		stat_wake;
@@ -242,25 +242,8 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef DEBUG
-#define DBG(stuff...)		printk(KERN_DEBUG "sl811: " stuff)
-#else
-#define DBG(stuff...)		do{}while(0)
-#endif
-
-#ifdef VERBOSE
-#    define VDBG		DBG
-#else
-#    define VDBG(stuff...)	do{}while(0)
-#endif
-
 #ifdef PACKET_TRACE
-#    define PACKET		VDBG
+#    define PACKET		pr_debug("sl811: "stuff)
 #else
 #    define PACKET(stuff...)	do{}while(0)
 #endif
-
-#define ERR(stuff...)		printk(KERN_ERR "sl811: " stuff)
-#define WARNING(stuff...)	printk(KERN_WARNING "sl811: " stuff)
-#define INFO(stuff...)		printk(KERN_INFO "sl811: " stuff)
-
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5c124bf..e402beb 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -1809,9 +1809,9 @@
 		struct platform_device *pdev =
 			to_platform_device(hcd->self.controller);
 		u16 vendor = ((struct u132_platform_data *)
-			(pdev->dev.platform_data))->vendor;
+			dev_get_platdata(&pdev->dev))->vendor;
 		u16 device = ((struct u132_platform_data *)
-			(pdev->dev.platform_data))->device;
+			dev_get_platdata(&pdev->dev))->device;
 		mutex_lock(&u132->sw_lock);
 		msleep(10);
 		if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
@@ -3034,7 +3034,7 @@
 	int addrs = MAX_U132_ADDRS;
 	int udevs = MAX_U132_UDEVS;
 	int endps = MAX_U132_ENDPS;
-	u132->board = pdev->dev.platform_data;
+	u132->board = dev_get_platdata(&pdev->dev);
 	u132->platform_dev = pdev;
 	u132->power = 0;
 	u132->reset = 0;
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 5d5e58f..73503a8 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -580,3 +580,17 @@
 	xhci_dbg_slot_ctx(xhci, ctx);
 	xhci_dbg_ep_ctx(xhci, ctx, last_ep);
 }
+
+void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
+			const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+	vaf.fmt = fmt;
+	vaf.va = &args;
+	xhci_dbg(xhci, "%pV\n", &vaf);
+	trace(&vaf);
+	va_end(args);
+}
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index 8d7a132..9fe3225 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -71,7 +71,7 @@
 
 /* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */
 #define XHCI_HLC               (1 << 19)
-#define XHCI_BLC               (1 << 19)
+#define XHCI_BLC               (1 << 20)
 
 /* command register values to disable interrupts and halt the HC */
 /* start/stop HC execution - do not write unless HC is halted*/
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 1d35459..fae697e 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -24,6 +24,7 @@
 #include <asm/unaligned.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 #define	PORT_WAKE_BITS	(PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
 #define	PORT_RWC_BITS	(PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
@@ -461,8 +462,15 @@
 	}
 }
 
+/* Updates Link Status for USB 2.1 port */
+static void xhci_hub_report_usb2_link_state(u32 *status, u32 status_reg)
+{
+	if ((status_reg & PORT_PLS_MASK) == XDEV_U2)
+		*status |= USB_PORT_STAT_L1;
+}
+
 /* Updates Link Status for super Speed port */
-static void xhci_hub_report_link_state(u32 *status, u32 status_reg)
+static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg)
 {
 	u32 pls = status_reg & PORT_PLS_MASK;
 
@@ -528,12 +536,128 @@
 		xhci->port_status_u0 |= 1 << wIndex;
 		if (xhci->port_status_u0 == all_ports_seen_u0) {
 			del_timer_sync(&xhci->comp_mode_recovery_timer);
-			xhci_dbg(xhci, "All USB3 ports have entered U0 already!\n");
-			xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted.\n");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"All USB3 ports have entered U0 already!");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Compliance Mode Recovery Timer Deleted.");
 		}
 	}
 }
 
+/*
+ * Converts a raw xHCI port status into the format that external USB 2.0 or USB
+ * 3.0 hubs use.
+ *
+ * Possible side effects:
+ *  - Mark a port as being done with device resume,
+ *    and ring the endpoint doorbells.
+ *  - Stop the Synopsys redriver Compliance Mode polling.
+ */
+static u32 xhci_get_port_status(struct usb_hcd *hcd,
+		struct xhci_bus_state *bus_state,
+		__le32 __iomem **port_array,
+		u16 wIndex, u32 raw_port_status)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	u32 status = 0;
+	int slot_id;
+
+	/* wPortChange bits */
+	if (raw_port_status & PORT_CSC)
+		status |= USB_PORT_STAT_C_CONNECTION << 16;
+	if (raw_port_status & PORT_PEC)
+		status |= USB_PORT_STAT_C_ENABLE << 16;
+	if ((raw_port_status & PORT_OCC))
+		status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+	if ((raw_port_status & PORT_RC))
+		status |= USB_PORT_STAT_C_RESET << 16;
+	/* USB3.0 only */
+	if (hcd->speed == HCD_USB3) {
+		if ((raw_port_status & PORT_PLC))
+			status |= USB_PORT_STAT_C_LINK_STATE << 16;
+		if ((raw_port_status & PORT_WRC))
+			status |= USB_PORT_STAT_C_BH_RESET << 16;
+	}
+
+	if (hcd->speed != HCD_USB3) {
+		if ((raw_port_status & PORT_PLS_MASK) == XDEV_U3
+				&& (raw_port_status & PORT_POWER))
+			status |= USB_PORT_STAT_SUSPEND;
+	}
+	if ((raw_port_status & PORT_PLS_MASK) == XDEV_RESUME &&
+			!DEV_SUPERSPEED(raw_port_status)) {
+		if ((raw_port_status & PORT_RESET) ||
+				!(raw_port_status & PORT_PE))
+			return 0xffffffff;
+		if (time_after_eq(jiffies,
+					bus_state->resume_done[wIndex])) {
+			xhci_dbg(xhci, "Resume USB2 port %d\n",
+					wIndex + 1);
+			bus_state->resume_done[wIndex] = 0;
+			clear_bit(wIndex, &bus_state->resuming_ports);
+			xhci_set_link_state(xhci, port_array, wIndex,
+					XDEV_U0);
+			xhci_dbg(xhci, "set port %d resume\n",
+					wIndex + 1);
+			slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+					wIndex + 1);
+			if (!slot_id) {
+				xhci_dbg(xhci, "slot_id is zero\n");
+				return 0xffffffff;
+			}
+			xhci_ring_device(xhci, slot_id);
+			bus_state->port_c_suspend |= 1 << wIndex;
+			bus_state->suspended_ports &= ~(1 << wIndex);
+		} else {
+			/*
+			 * The resume has been signaling for less than
+			 * 20ms. Report the port status as SUSPEND,
+			 * let the usbcore check port status again
+			 * and clear resume signaling later.
+			 */
+			status |= USB_PORT_STAT_SUSPEND;
+		}
+	}
+	if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
+			&& (raw_port_status & PORT_POWER)
+			&& (bus_state->suspended_ports & (1 << wIndex))) {
+		bus_state->suspended_ports &= ~(1 << wIndex);
+		if (hcd->speed != HCD_USB3)
+			bus_state->port_c_suspend |= 1 << wIndex;
+	}
+	if (raw_port_status & PORT_CONNECT) {
+		status |= USB_PORT_STAT_CONNECTION;
+		status |= xhci_port_speed(raw_port_status);
+	}
+	if (raw_port_status & PORT_PE)
+		status |= USB_PORT_STAT_ENABLE;
+	if (raw_port_status & PORT_OC)
+		status |= USB_PORT_STAT_OVERCURRENT;
+	if (raw_port_status & PORT_RESET)
+		status |= USB_PORT_STAT_RESET;
+	if (raw_port_status & PORT_POWER) {
+		if (hcd->speed == HCD_USB3)
+			status |= USB_SS_PORT_STAT_POWER;
+		else
+			status |= USB_PORT_STAT_POWER;
+	}
+	/* Update Port Link State */
+	if (hcd->speed == HCD_USB3) {
+		xhci_hub_report_usb3_link_state(&status, raw_port_status);
+		/*
+		 * Verify if all USB3 Ports Have entered U0 already.
+		 * Delete Compliance Mode Timer if so.
+		 */
+		xhci_del_comp_mod_timer(xhci, raw_port_status, wIndex);
+	} else {
+		xhci_hub_report_usb2_link_state(&status, raw_port_status);
+	}
+	if (bus_state->port_c_suspend & (1 << wIndex))
+		status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+
+	return status;
+}
+
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		u16 wIndex, char *buf, u16 wLength)
 {
@@ -598,104 +722,20 @@
 		if (!wIndex || wIndex > max_ports)
 			goto error;
 		wIndex--;
-		status = 0;
 		temp = xhci_readl(xhci, port_array[wIndex]);
 		if (temp == 0xffffffff) {
 			retval = -ENODEV;
 			break;
 		}
-		xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n", wIndex, temp);
+		status = xhci_get_port_status(hcd, bus_state, port_array,
+				wIndex, temp);
+		if (status == 0xffffffff)
+			goto error;
 
-		/* wPortChange bits */
-		if (temp & PORT_CSC)
-			status |= USB_PORT_STAT_C_CONNECTION << 16;
-		if (temp & PORT_PEC)
-			status |= USB_PORT_STAT_C_ENABLE << 16;
-		if ((temp & PORT_OCC))
-			status |= USB_PORT_STAT_C_OVERCURRENT << 16;
-		if ((temp & PORT_RC))
-			status |= USB_PORT_STAT_C_RESET << 16;
-		/* USB3.0 only */
-		if (hcd->speed == HCD_USB3) {
-			if ((temp & PORT_PLC))
-				status |= USB_PORT_STAT_C_LINK_STATE << 16;
-			if ((temp & PORT_WRC))
-				status |= USB_PORT_STAT_C_BH_RESET << 16;
-		}
-
-		if (hcd->speed != HCD_USB3) {
-			if ((temp & PORT_PLS_MASK) == XDEV_U3
-					&& (temp & PORT_POWER))
-				status |= USB_PORT_STAT_SUSPEND;
-		}
-		if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
-				!DEV_SUPERSPEED(temp)) {
-			if ((temp & PORT_RESET) || !(temp & PORT_PE))
-				goto error;
-			if (time_after_eq(jiffies,
-					bus_state->resume_done[wIndex])) {
-				xhci_dbg(xhci, "Resume USB2 port %d\n",
-					wIndex + 1);
-				bus_state->resume_done[wIndex] = 0;
-				clear_bit(wIndex, &bus_state->resuming_ports);
-				xhci_set_link_state(xhci, port_array, wIndex,
-							XDEV_U0);
-				xhci_dbg(xhci, "set port %d resume\n",
-					wIndex + 1);
-				slot_id = xhci_find_slot_id_by_port(hcd, xhci,
-								 wIndex + 1);
-				if (!slot_id) {
-					xhci_dbg(xhci, "slot_id is zero\n");
-					goto error;
-				}
-				xhci_ring_device(xhci, slot_id);
-				bus_state->port_c_suspend |= 1 << wIndex;
-				bus_state->suspended_ports &= ~(1 << wIndex);
-			} else {
-				/*
-				 * The resume has been signaling for less than
-				 * 20ms. Report the port status as SUSPEND,
-				 * let the usbcore check port status again
-				 * and clear resume signaling later.
-				 */
-				status |= USB_PORT_STAT_SUSPEND;
-			}
-		}
-		if ((temp & PORT_PLS_MASK) == XDEV_U0
-			&& (temp & PORT_POWER)
-			&& (bus_state->suspended_ports & (1 << wIndex))) {
-			bus_state->suspended_ports &= ~(1 << wIndex);
-			if (hcd->speed != HCD_USB3)
-				bus_state->port_c_suspend |= 1 << wIndex;
-		}
-		if (temp & PORT_CONNECT) {
-			status |= USB_PORT_STAT_CONNECTION;
-			status |= xhci_port_speed(temp);
-		}
-		if (temp & PORT_PE)
-			status |= USB_PORT_STAT_ENABLE;
-		if (temp & PORT_OC)
-			status |= USB_PORT_STAT_OVERCURRENT;
-		if (temp & PORT_RESET)
-			status |= USB_PORT_STAT_RESET;
-		if (temp & PORT_POWER) {
-			if (hcd->speed == HCD_USB3)
-				status |= USB_SS_PORT_STAT_POWER;
-			else
-				status |= USB_PORT_STAT_POWER;
-		}
-		/* Update Port Link State for super speed ports*/
-		if (hcd->speed == HCD_USB3) {
-			xhci_hub_report_link_state(&status, temp);
-			/*
-			 * Verify if all USB3 Ports Have entered U0 already.
-			 * Delete Compliance Mode Timer if so.
-			 */
-			xhci_del_comp_mod_timer(xhci, temp, wIndex);
-		}
-		if (bus_state->port_c_suspend & (1 << wIndex))
-			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+		xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n",
+				wIndex, temp);
 		xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+
 		put_unaligned(cpu_to_le32(status), (__le32 *) buf);
 		break;
 	case SetPortFeature:
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 6f8c2fd..53b972c 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -27,6 +27,7 @@
 #include <linux/dma-mapping.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 /*
  * Allocates a generic ring segment from the ring pool, sets the dma address,
@@ -348,7 +349,8 @@
 		return -ENOMEM;
 
 	xhci_link_rings(xhci, ring, first, last, num_segs);
-	xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+			"ring expansion succeed, now has %d segments",
 			ring->num_segs);
 
 	return 0;
@@ -482,17 +484,6 @@
 	return ep->ring;
 }
 
-/* Only use this when you know stream_info is valid */
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static struct xhci_ring *dma_to_stream_ring(
-		struct xhci_stream_info *stream_info,
-		u64 address)
-{
-	return radix_tree_lookup(&stream_info->trb_address_map,
-			address >> TRB_SEGMENT_SHIFT);
-}
-#endif	/* CONFIG_USB_XHCI_HCD_DEBUGGING */
-
 struct xhci_ring *xhci_stream_id_to_ring(
 		struct xhci_virt_device *dev,
 		unsigned int ep_index,
@@ -510,58 +501,6 @@
 	return ep->stream_info->stream_rings[stream_id];
 }
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static int xhci_test_radix_tree(struct xhci_hcd *xhci,
-		unsigned int num_streams,
-		struct xhci_stream_info *stream_info)
-{
-	u32 cur_stream;
-	struct xhci_ring *cur_ring;
-	u64 addr;
-
-	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
-		struct xhci_ring *mapped_ring;
-		int trb_size = sizeof(union xhci_trb);
-
-		cur_ring = stream_info->stream_rings[cur_stream];
-		for (addr = cur_ring->first_seg->dma;
-				addr < cur_ring->first_seg->dma + TRB_SEGMENT_SIZE;
-				addr += trb_size) {
-			mapped_ring = dma_to_stream_ring(stream_info, addr);
-			if (cur_ring != mapped_ring) {
-				xhci_warn(xhci, "WARN: DMA address 0x%08llx "
-						"didn't map to stream ID %u; "
-						"mapped to ring %p\n",
-						(unsigned long long) addr,
-						cur_stream,
-						mapped_ring);
-				return -EINVAL;
-			}
-		}
-		/* One TRB after the end of the ring segment shouldn't return a
-		 * pointer to the current ring (although it may be a part of a
-		 * different ring).
-		 */
-		mapped_ring = dma_to_stream_ring(stream_info, addr);
-		if (mapped_ring != cur_ring) {
-			/* One TRB before should also fail */
-			addr = cur_ring->first_seg->dma - trb_size;
-			mapped_ring = dma_to_stream_ring(stream_info, addr);
-		}
-		if (mapped_ring == cur_ring) {
-			xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx "
-					"mapped to valid stream ID %u; "
-					"mapped ring = %p\n",
-					(unsigned long long) addr,
-					cur_stream,
-					mapped_ring);
-			return -EINVAL;
-		}
-	}
-	return 0;
-}
-#endif	/* CONFIG_USB_XHCI_HCD_DEBUGGING */
-
 /*
  * Change an endpoint's internal structure so it supports stream IDs.  The
  * number of requested streams includes stream 0, which cannot be used by device
@@ -688,13 +627,6 @@
 	 * was any other way, the host controller would assume the ring is
 	 * "empty" and wait forever for data to be queued to that stream ID).
 	 */
-#if XHCI_DEBUG
-	/* Do a little test on the radix tree to make sure it returns the
-	 * correct values.
-	 */
-	if (xhci_test_radix_tree(xhci, num_streams, stream_info))
-		goto cleanup_rings;
-#endif
 
 	return stream_info;
 
@@ -732,7 +664,8 @@
 	 * fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc.
 	 */
 	max_primary_streams = fls(stream_info->num_stream_ctxs) - 2;
-	xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n",
+	xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+			"Setting number of stream ctx array entries to %u",
 			1 << (max_primary_streams + 1));
 	ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK);
 	ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams)
@@ -1614,7 +1547,8 @@
 	struct device *dev = xhci_to_hcd(xhci)->self.controller;
 	int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
 
-	xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Allocating %d scratchpad buffers", num_sp);
 
 	if (!num_sp)
 		return 0;
@@ -1771,11 +1705,11 @@
 		dma_free_coherent(&pdev->dev, size,
 				xhci->erst.entries, xhci->erst.erst_dma_addr);
 	xhci->erst.entries = NULL;
-	xhci_dbg(xhci, "Freed ERST\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST");
 	if (xhci->event_ring)
 		xhci_ring_free(xhci, xhci->event_ring);
 	xhci->event_ring = NULL;
-	xhci_dbg(xhci, "Freed event ring\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring");
 
 	if (xhci->lpm_command)
 		xhci_free_command(xhci, xhci->lpm_command);
@@ -1783,7 +1717,7 @@
 	if (xhci->cmd_ring)
 		xhci_ring_free(xhci, xhci->cmd_ring);
 	xhci->cmd_ring = NULL;
-	xhci_dbg(xhci, "Freed command ring\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring");
 	list_for_each_entry_safe(cur_cd, next_cd,
 			&xhci->cancel_cmd_list, cancel_cmd_list) {
 		list_del(&cur_cd->cancel_cmd_list);
@@ -1796,22 +1730,24 @@
 	if (xhci->segment_pool)
 		dma_pool_destroy(xhci->segment_pool);
 	xhci->segment_pool = NULL;
-	xhci_dbg(xhci, "Freed segment pool\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed segment pool");
 
 	if (xhci->device_pool)
 		dma_pool_destroy(xhci->device_pool);
 	xhci->device_pool = NULL;
-	xhci_dbg(xhci, "Freed device context pool\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed device context pool");
 
 	if (xhci->small_streams_pool)
 		dma_pool_destroy(xhci->small_streams_pool);
 	xhci->small_streams_pool = NULL;
-	xhci_dbg(xhci, "Freed small stream array pool\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Freed small stream array pool");
 
 	if (xhci->medium_streams_pool)
 		dma_pool_destroy(xhci->medium_streams_pool);
 	xhci->medium_streams_pool = NULL;
-	xhci_dbg(xhci, "Freed medium stream array pool\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Freed medium stream array pool");
 
 	if (xhci->dcbaa)
 		dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
@@ -2037,8 +1973,9 @@
 	 * there might be more events to service.
 	 */
 	temp &= ~ERST_EHB;
-	xhci_dbg(xhci, "// Write event ring dequeue pointer, "
-			"preserving EHB bit\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Write event ring dequeue pointer, "
+			"preserving EHB bit");
 	xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
 			&xhci->ir_set->erst_dequeue);
 }
@@ -2061,8 +1998,9 @@
 	temp = xhci_readl(xhci, addr + 2);
 	port_offset = XHCI_EXT_PORT_OFF(temp);
 	port_count = XHCI_EXT_PORT_COUNT(temp);
-	xhci_dbg(xhci, "Ext Cap %p, port offset = %u, "
-			"count = %u, revision = 0x%x\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Ext Cap %p, port offset = %u, "
+			"count = %u, revision = 0x%x",
 			addr, port_offset, port_count, major_revision);
 	/* Port count includes the current port offset */
 	if (port_offset == 0 || (port_offset + port_count - 1) > num_ports)
@@ -2076,15 +2014,18 @@
 	/* Check the host's USB2 LPM capability */
 	if ((xhci->hci_version == 0x96) && (major_revision != 0x03) &&
 			(temp & XHCI_L1C)) {
-		xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"xHCI 0.96: support USB2 software lpm");
 		xhci->sw_lpm_support = 1;
 	}
 
 	if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) {
-		xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"xHCI 1.0: support USB2 software lpm");
 		xhci->sw_lpm_support = 1;
 		if (temp & XHCI_HLC) {
-			xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+					"xHCI 1.0: support USB2 hardware lpm");
 			xhci->hw_lpm_support = 1;
 		}
 	}
@@ -2208,18 +2149,21 @@
 		xhci_warn(xhci, "No ports on the roothubs?\n");
 		return -ENODEV;
 	}
-	xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Found %u USB 2.0 ports and %u USB 3.0 ports.",
 			xhci->num_usb2_ports, xhci->num_usb3_ports);
 
 	/* Place limits on the number of roothub ports so that the hub
 	 * descriptors aren't longer than the USB core will allocate.
 	 */
 	if (xhci->num_usb3_ports > 15) {
-		xhci_dbg(xhci, "Limiting USB 3.0 roothub ports to 15.\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"Limiting USB 3.0 roothub ports to 15.");
 		xhci->num_usb3_ports = 15;
 	}
 	if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
-		xhci_dbg(xhci, "Limiting USB 2.0 roothub ports to %u.\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"Limiting USB 2.0 roothub ports to %u.",
 				USB_MAXCHILDREN);
 		xhci->num_usb2_ports = USB_MAXCHILDREN;
 	}
@@ -2244,8 +2188,9 @@
 			xhci->usb2_ports[port_index] =
 				&xhci->op_regs->port_status_base +
 				NUM_PORT_REGS*i;
-			xhci_dbg(xhci, "USB 2.0 port at index %u, "
-					"addr = %p\n", i,
+			xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+					"USB 2.0 port at index %u, "
+					"addr = %p", i,
 					xhci->usb2_ports[port_index]);
 			port_index++;
 			if (port_index == xhci->num_usb2_ports)
@@ -2264,8 +2209,9 @@
 				xhci->usb3_ports[port_index] =
 					&xhci->op_regs->port_status_base +
 					NUM_PORT_REGS*i;
-				xhci_dbg(xhci, "USB 3.0 port at index %u, "
-						"addr = %p\n", i,
+				xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+						"USB 3.0 port at index %u, "
+						"addr = %p", i,
 						xhci->usb3_ports[port_index]);
 				port_index++;
 				if (port_index == xhci->num_usb3_ports)
@@ -2289,32 +2235,35 @@
 	INIT_LIST_HEAD(&xhci->cancel_cmd_list);
 
 	page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
-	xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Supported page size register = 0x%x", page_size);
 	for (i = 0; i < 16; i++) {
 		if ((0x1 & page_size) != 0)
 			break;
 		page_size = page_size >> 1;
 	}
 	if (i < 16)
-		xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024);
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Supported page size of %iK", (1 << (i+12)) / 1024);
 	else
 		xhci_warn(xhci, "WARN: no supported page size\n");
 	/* Use 4K pages, since that's common and the minimum the HC supports */
 	xhci->page_shift = 12;
 	xhci->page_size = 1 << xhci->page_shift;
-	xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"HCD page size set to %iK", xhci->page_size / 1024);
 
 	/*
 	 * Program the Number of Device Slots Enabled field in the CONFIG
 	 * register with the max value of slots the HC can handle.
 	 */
 	val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1));
-	xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n",
-			(unsigned int) val);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// xHC can handle at most %d device slots.", val);
 	val2 = xhci_readl(xhci, &xhci->op_regs->config_reg);
 	val |= (val2 & ~HCS_SLOTS_MASK);
-	xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n",
-			(unsigned int) val);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Setting Max device slots reg = 0x%x.", val);
 	xhci_writel(xhci, val, &xhci->op_regs->config_reg);
 
 	/*
@@ -2327,7 +2276,8 @@
 		goto fail;
 	memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
 	xhci->dcbaa->dma = dma;
-	xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Device context base array address = 0x%llx (DMA), %p (virt)",
 			(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
 	xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
 
@@ -2366,8 +2316,9 @@
 	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);
-	xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Allocated command ring at %p", xhci->cmd_ring);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx",
 			(unsigned long long)xhci->cmd_ring->first_seg->dma);
 
 	/* Set the address in the Command Ring Control register */
@@ -2375,7 +2326,8 @@
 	val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
 		(xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
 		xhci->cmd_ring->cycle_state;
-	xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Setting command ring address to 0x%x", val);
 	xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
 	xhci_dbg_cmd_ptrs(xhci);
 
@@ -2391,8 +2343,9 @@
 
 	val = xhci_readl(xhci, &xhci->cap_regs->db_off);
 	val &= DBOFF_MASK;
-	xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
-			" from cap regs base addr\n", val);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Doorbell array is located at offset 0x%x"
+			" from cap regs base addr", val);
 	xhci->dba = (void __iomem *) xhci->cap_regs + val;
 	xhci_dbg_regs(xhci);
 	xhci_print_run_regs(xhci);
@@ -2403,7 +2356,7 @@
 	 * Event ring setup: Allocate a normal ring, but also setup
 	 * the event ring segment table (ERST).  Section 4.9.3.
 	 */
-	xhci_dbg(xhci, "// Allocating event ring\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring");
 	xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
 						flags);
 	if (!xhci->event_ring)
@@ -2416,13 +2369,15 @@
 			GFP_KERNEL);
 	if (!xhci->erst.entries)
 		goto fail;
-	xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Allocated event ring segment table at 0x%llx",
 			(unsigned long long)dma);
 
 	memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
 	xhci->erst.num_entries = ERST_NUM_SEGS;
 	xhci->erst.erst_dma_addr = dma;
-	xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx",
 			xhci->erst.num_entries,
 			xhci->erst.entries,
 			(unsigned long long)xhci->erst.erst_dma_addr);
@@ -2440,13 +2395,16 @@
 	val = xhci_readl(xhci, &xhci->ir_set->erst_size);
 	val &= ERST_SIZE_MASK;
 	val |= ERST_NUM_SEGS;
-	xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Write ERST size = %i to ir_set 0 (some bits preserved)",
 			val);
 	xhci_writel(xhci, val, &xhci->ir_set->erst_size);
 
-	xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Set ERST entries to point to event ring.");
 	/* set the segment table base address */
-	xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Set ERST base address for ir_set 0 = 0x%llx",
 			(unsigned long long)xhci->erst.erst_dma_addr);
 	val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
 	val_64 &= ERST_PTR_MASK;
@@ -2455,7 +2413,8 @@
 
 	/* Set the event ring dequeue address */
 	xhci_set_hc_event_deq(xhci);
-	xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Wrote ERST address to ir_set 0.");
 	xhci_print_ir_set(xhci, 0);
 
 	/*
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index f00cb20..c2d4950 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 /* Device for a quirk */
 #define PCI_VENDOR_ID_FRESCO_LOGIC	0x1b73
@@ -64,16 +65,18 @@
 		if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
 				pdev->revision == 0x0) {
 			xhci->quirks |= XHCI_RESET_EP_QUIRK;
-			xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
-					" endpoint cmd after reset endpoint\n");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"QUIRK: Fresco Logic xHC needs configure"
+				" endpoint cmd after reset endpoint");
 		}
 		/* Fresco Logic confirms: all revisions of this chip do not
 		 * support MSI, even though some of them claim to in their PCI
 		 * capabilities.
 		 */
 		xhci->quirks |= XHCI_BROKEN_MSI;
-		xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
-				"has broken MSI implementation\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"QUIRK: Fresco Logic revision %u "
+				"has broken MSI implementation",
 				pdev->revision);
 		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 	}
@@ -110,7 +113,8 @@
 	if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
 			pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
 		xhci->quirks |= XHCI_RESET_ON_RESUME;
-		xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"QUIRK: Resetting on resume");
 		xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 	}
 	if (pdev->vendor == PCI_VENDOR_ID_VIA)
@@ -249,13 +253,15 @@
 	 * writers.
 	 *
 	 * Unconditionally switch the ports back to xHCI after a system resume.
-	 * We can't tell whether the EHCI or xHCI controller will be resumed
-	 * first, so we have to do the port switchover in both drivers.  Writing
-	 * a '1' to the port switchover registers should have no effect if the
-	 * port was already switched over.
+	 * It should not matter whether the EHCI or xHCI controller is
+	 * resumed first. It's enough to do the switchover in xHCI because
+	 * USB core won't notice anything as the hub driver doesn't start
+	 * running again until after all the devices (including both EHCI and
+	 * xHCI host controllers) have been resumed.
 	 */
-	if (usb_is_intel_switchable_xhci(pdev))
-		usb_enable_xhci_ports(pdev);
+
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+		usb_enable_intel_xhci_ports(pdev);
 
 	retval = xhci_resume(xhci, hibernated);
 	return retval;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 51e22bf..d9c169f 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -14,6 +14,8 @@
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
 
 #include "xhci.h"
 
@@ -24,7 +26,7 @@
 	 * 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;
+	xhci->quirks |= XHCI_PLAT;
 }
 
 /* called during probe() after chip reset completes */
@@ -104,6 +106,15 @@
 	if (!res)
 		return -ENODEV;
 
+	/* Initialize dma_mask and coherent_dma_mask to 32-bits */
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+	if (!pdev->dev.dma_mask)
+		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+	else
+		dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+
 	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
 	if (!hcd)
 		return -ENOMEM;
@@ -186,11 +197,46 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int xhci_plat_suspend(struct device *dev)
+{
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	return xhci_suspend(xhci);
+}
+
+static int xhci_plat_resume(struct device *dev)
+{
+	struct usb_hcd	*hcd = dev_get_drvdata(dev);
+	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
+
+	return xhci_resume(xhci, 0);
+}
+
+static const struct dev_pm_ops xhci_plat_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+};
+#define DEV_PM_OPS	(&xhci_plat_pm_ops)
+#else
+#define DEV_PM_OPS	NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id usb_xhci_of_match[] = {
+	{ .compatible = "xhci-platform" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
+#endif
+
 static struct platform_driver usb_xhci_driver = {
 	.probe	= xhci_plat_probe,
 	.remove	= xhci_plat_remove,
 	.driver	= {
 		.name = "xhci-hcd",
+		.pm = DEV_PM_OPS,
+		.of_match_table = of_match_ptr(usb_xhci_of_match),
 	},
 };
 MODULE_ALIAS("platform:xhci-hcd");
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 5b08cd8..411da1f 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -67,6 +67,7 @@
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include "xhci.h"
+#include "xhci-trace.h"
 
 static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
 		struct xhci_virt_device *virt_dev,
@@ -555,7 +556,8 @@
 		return;
 	}
 	state->new_cycle_state = 0;
-	xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Finding segment containing stopped TRB.");
 	state->new_deq_seg = find_trb_seg(cur_td->start_seg,
 			dev->eps[ep_index].stopped_trb,
 			&state->new_cycle_state);
@@ -565,12 +567,14 @@
 	}
 
 	/* Dig out the cycle state saved by the xHC during the stop ep cmd */
-	xhci_dbg(xhci, "Finding endpoint context\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Finding endpoint context");
 	ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
 	state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq);
 
 	state->new_deq_ptr = cur_td->last_trb;
-	xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Finding segment containing last TRB in TD.");
 	state->new_deq_seg = find_trb_seg(state->new_deq_seg,
 			state->new_deq_ptr,
 			&state->new_cycle_state);
@@ -597,13 +601,16 @@
 	if (ep_ring->first_seg == ep_ring->first_seg->next &&
 			state->new_deq_ptr < dev->eps[ep_index].stopped_trb)
 		state->new_cycle_state ^= 0x1;
-	xhci_dbg(xhci, "Cycle state = 0x%x\n", state->new_cycle_state);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Cycle state = 0x%x", state->new_cycle_state);
 
 	/* Don't update the ring cycle state for the producer (us). */
-	xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"New dequeue segment = %p (virtual)",
 			state->new_deq_seg);
 	addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr);
-	xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"New dequeue pointer = 0x%llx (DMA)",
 			(unsigned long long) addr);
 }
 
@@ -631,9 +638,11 @@
 			if (flip_cycle)
 				cur_trb->generic.field[3] ^=
 					cpu_to_le32(TRB_CYCLE);
-			xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
-			xhci_dbg(xhci, "Address = %p (0x%llx dma); "
-					"in seg %p (0x%llx dma)\n",
+			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+					"Cancel (unchain) link TRB");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+					"Address = %p (0x%llx dma); "
+					"in seg %p (0x%llx dma)",
 					cur_trb,
 					(unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
 					cur_seg,
@@ -651,7 +660,8 @@
 					cpu_to_le32(TRB_CYCLE);
 			cur_trb->generic.field[3] |= cpu_to_le32(
 				TRB_TYPE(TRB_TR_NOOP));
-			xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n",
+			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+					"TRB to noop at offset 0x%llx",
 					(unsigned long long)
 					xhci_trb_virt_to_dma(cur_seg, cur_trb));
 		}
@@ -672,8 +682,9 @@
 {
 	struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
 
-	xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
-			"new deq ptr = %p (0x%llx dma), new cycle = %u\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
+			"new deq ptr = %p (0x%llx dma), new cycle = %u",
 			deq_state->new_deq_seg,
 			(unsigned long long)deq_state->new_deq_seg->dma,
 			deq_state->new_deq_ptr,
@@ -793,7 +804,8 @@
 	 */
 	list_for_each(entry, &ep->cancelled_td_list) {
 		cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
-		xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+				"Removing canceled TD starting at 0x%llx (dma).",
 				(unsigned long long)xhci_trb_virt_to_dma(
 					cur_td->start_seg, cur_td->first_trb));
 		ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
@@ -913,14 +925,16 @@
 
 	ep->stop_cmds_pending--;
 	if (xhci->xhc_state & XHCI_STATE_DYING) {
-		xhci_dbg(xhci, "Stop EP timer ran, but another timer marked "
-				"xHCI as DYING, exiting.\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+				"Stop EP timer ran, but another timer marked "
+				"xHCI as DYING, exiting.");
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		return;
 	}
 	if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
-		xhci_dbg(xhci, "Stop EP timer ran, but no command pending, "
-				"exiting.\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+				"Stop EP timer ran, but no command pending, "
+				"exiting.");
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		return;
 	}
@@ -962,8 +976,9 @@
 			ring = temp_ep->ring;
 			if (!ring)
 				continue;
-			xhci_dbg(xhci, "Killing URBs for slot ID %u, "
-					"ep index %u\n", i, j);
+			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+					"Killing URBs for slot ID %u, "
+					"ep index %u", i, j);
 			while (!list_empty(&ring->td_list)) {
 				cur_td = list_first_entry(&ring->td_list,
 						struct xhci_td,
@@ -986,9 +1001,11 @@
 		}
 	}
 	spin_unlock_irqrestore(&xhci->lock, flags);
-	xhci_dbg(xhci, "Calling usb_hc_died()\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Calling usb_hc_died()");
 	usb_hc_died(xhci_to_hcd(xhci)->primary_hcd);
-	xhci_dbg(xhci, "xHCI host controller is dead.\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"xHCI host controller is dead.");
 }
 
 
@@ -1092,7 +1109,8 @@
 			ep_state &= EP_STATE_MASK;
 			slot_state = le32_to_cpu(slot_ctx->dev_state);
 			slot_state = GET_SLOT_STATE(slot_state);
-			xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
+			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+					"Slot state = %u, EP state = %u",
 					slot_state, ep_state);
 			break;
 		case COMP_EBADSLT:
@@ -1112,7 +1130,8 @@
 		 * cancelling URBs, which might not be an error...
 		 */
 	} else {
-		xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+			"Successful Set TR Deq Ptr cmd, deq = @%08llx",
 			 le64_to_cpu(ep_ctx->deq));
 		if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg,
 					 dev->eps[ep_index].queued_deq_ptr) ==
@@ -1150,7 +1169,8 @@
 	/* This command will only fail if the endpoint wasn't halted,
 	 * but we don't care.
 	 */
-	xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+		"Ignoring reset ep completion code of %u",
 		 GET_COMP_CODE(le32_to_cpu(event->status)));
 
 	/* HW with the reset endpoint quirk needs to have a configure endpoint
@@ -1158,7 +1178,8 @@
 	 * because the HW can't handle two commands being queued in a row.
 	 */
 	if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
-		xhci_dbg(xhci, "Queueing configure endpoint command\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Queueing configure endpoint command");
 		xhci_queue_configure_endpoint(xhci,
 				xhci->devs[slot_id]->in_ctx->dma, slot_id,
 				false);
@@ -1377,6 +1398,9 @@
 		return;
 	}
 
+	trace_xhci_cmd_completion(&xhci->cmd_ring->dequeue->generic,
+					(struct xhci_generic_trb *) event);
+
 	if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) ||
 		(GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) {
 		/* If the return value is 0, we think the trb pointed by
@@ -1444,8 +1468,9 @@
 			ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
 			if (!(ep_state & EP_HALTED))
 				goto bandwidth_change;
-			xhci_dbg(xhci, "Completed config ep cmd - "
-					"last ep index = %d, state = %d\n",
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+					"Completed config ep cmd - "
+					"last ep index = %d, state = %d",
 					ep_index, ep_state);
 			/* Clear internal halted state and restart ring(s) */
 			xhci->devs[slot_id]->eps[ep_index].ep_state &=
@@ -1454,7 +1479,8 @@
 			break;
 		}
 bandwidth_change:
-		xhci_dbg(xhci, "Completed config ep cmd\n");
+		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+				"Completed config ep cmd");
 		xhci->devs[slot_id]->cmd_status =
 			GET_COMP_CODE(le32_to_cpu(event->status));
 		complete(&xhci->devs[slot_id]->cmd_completion);
@@ -1497,7 +1523,8 @@
 			xhci->error_bitmask |= 1 << 6;
 			break;
 		}
-		xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+			"NEC firmware version %2x.%02x",
 			 NEC_FW_MAJOR(le32_to_cpu(event->status)),
 			 NEC_FW_MINOR(le32_to_cpu(event->status)));
 		break;
@@ -2877,8 +2904,8 @@
 			return -ENOMEM;
 		}
 
-		xhci_dbg(xhci, "ERROR no room on ep ring, "
-					"try ring expansion\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
+				"ERROR no room on ep ring, try ring expansion");
 		num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
 		if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
 					mem_flags)) {
@@ -3060,14 +3087,10 @@
 	 * to set the polling interval (once the API is added).
 	 */
 	if (xhci_interval != ep_interval) {
-		if (printk_ratelimit())
-			dev_dbg(&urb->dev->dev, "Driver uses different interval"
-					" (%d microframe%s) than xHCI "
-					"(%d microframe%s)\n",
-					ep_interval,
-					ep_interval == 1 ? "" : "s",
-					xhci_interval,
-					xhci_interval == 1 ? "" : "s");
+		dev_dbg_ratelimited(&urb->dev->dev,
+				"Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n",
+				ep_interval, ep_interval == 1 ? "" : "s",
+				xhci_interval, xhci_interval == 1 ? "" : "s");
 		urb->interval = xhci_interval;
 		/* Convert back to frames for LS/FS devices */
 		if (urb->dev->speed == USB_SPEED_LOW ||
@@ -3849,14 +3872,10 @@
 	 * to set the polling interval (once the API is added).
 	 */
 	if (xhci_interval != ep_interval) {
-		if (printk_ratelimit())
-			dev_dbg(&urb->dev->dev, "Driver uses different interval"
-					" (%d microframe%s) than xHCI "
-					"(%d microframe%s)\n",
-					ep_interval,
-					ep_interval == 1 ? "" : "s",
-					xhci_interval,
-					xhci_interval == 1 ? "" : "s");
+		dev_dbg_ratelimited(&urb->dev->dev,
+				"Driver uses different interval (%d microframe%s) than xHCI (%d microframe%s)\n",
+				ep_interval, ep_interval == 1 ? "" : "s",
+				xhci_interval, xhci_interval == 1 ? "" : "s");
 		urb->interval = xhci_interval;
 		/* Convert back to frames for LS/FS devices */
 		if (urb->dev->speed == USB_SPEED_LOW ||
diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c
new file mode 100644
index 0000000..7cf30c8
--- /dev/null
+++ b/drivers/usb/host/xhci-trace.c
@@ -0,0 +1,15 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2013 Xenia Ragiadakou
+ *
+ * Author: Xenia Ragiadakou
+ * Email : burzalodowa@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.
+ */
+
+#define CREATE_TRACE_POINTS
+#include "xhci-trace.h"
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
new file mode 100644
index 0000000..20364cc
--- /dev/null
+++ b/drivers/usb/host/xhci-trace.h
@@ -0,0 +1,151 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2013 Xenia Ragiadakou
+ *
+ * Author: Xenia Ragiadakou
+ * Email : burzalodowa@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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM xhci-hcd
+
+#if !defined(__XHCI_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __XHCI_TRACE_H
+
+#include <linux/tracepoint.h>
+#include "xhci.h"
+
+#define XHCI_MSG_MAX	500
+
+DECLARE_EVENT_CLASS(xhci_log_msg,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf),
+	TP_STRUCT__entry(__dynamic_array(char, msg, XHCI_MSG_MAX)),
+	TP_fast_assign(
+		vsnprintf(__get_str(msg), XHCI_MSG_MAX, vaf->fmt, *vaf->va);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_address,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_context_change,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_quirks,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_reset_ep,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_cancel_urb,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_init,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(xhci_log_msg, xhci_dbg_ring_expansion,
+	TP_PROTO(struct va_format *vaf),
+	TP_ARGS(vaf)
+);
+
+DECLARE_EVENT_CLASS(xhci_log_ctx,
+	TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+		 unsigned int ep_num),
+	TP_ARGS(xhci, ctx, ep_num),
+	TP_STRUCT__entry(
+		__field(int, ctx_64)
+		__field(unsigned, ctx_type)
+		__field(dma_addr_t, ctx_dma)
+		__field(u8 *, ctx_va)
+		__field(unsigned, ctx_ep_num)
+		__field(int, slot_id)
+		__dynamic_array(u32, ctx_data,
+			((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 8) *
+			((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1))
+	),
+	TP_fast_assign(
+		struct usb_device *udev;
+
+		udev = to_usb_device(xhci_to_hcd(xhci)->self.controller);
+		__entry->ctx_64 = HCC_64BYTE_CONTEXT(xhci->hcc_params);
+		__entry->ctx_type = ctx->type;
+		__entry->ctx_dma = ctx->dma;
+		__entry->ctx_va = ctx->bytes;
+		__entry->slot_id = udev->slot_id;
+		__entry->ctx_ep_num = ep_num;
+		memcpy(__get_dynamic_array(ctx_data), ctx->bytes,
+			((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) *
+			((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1));
+	),
+	TP_printk("\nctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p",
+			__entry->ctx_64, __entry->ctx_type,
+			(unsigned long long) __entry->ctx_dma, __entry->ctx_va
+	)
+);
+
+DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx,
+	TP_PROTO(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
+		 unsigned int ep_num),
+	TP_ARGS(xhci, ctx, ep_num)
+);
+
+DECLARE_EVENT_CLASS(xhci_log_event,
+	TP_PROTO(void *trb_va, struct xhci_generic_trb *ev),
+	TP_ARGS(trb_va, ev),
+	TP_STRUCT__entry(
+		__field(void *, va)
+		__field(u64, dma)
+		__field(u32, status)
+		__field(u32, flags)
+		__dynamic_array(__le32, trb, 4)
+	),
+	TP_fast_assign(
+		__entry->va = trb_va;
+		__entry->dma = le64_to_cpu(((u64)ev->field[1]) << 32 |
+						ev->field[0]);
+		__entry->status = le32_to_cpu(ev->field[2]);
+		__entry->flags = le32_to_cpu(ev->field[3]);
+		memcpy(__get_dynamic_array(trb), trb_va,
+			sizeof(struct xhci_generic_trb));
+	),
+	TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x",
+			(unsigned long long) __entry->dma, __entry->va,
+			__entry->status, __entry->flags
+	)
+);
+
+DEFINE_EVENT(xhci_log_event, xhci_cmd_completion,
+	TP_PROTO(void *trb_va, struct xhci_generic_trb *ev),
+	TP_ARGS(trb_va, ev)
+);
+
+#endif /* __XHCI_TRACE_H */
+
+/* this part must be outside header guard */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE xhci-trace
+
+#include <trace/define_trace.h>
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 9478caa..49b6edb 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -30,6 +30,7 @@
 #include <linux/dma-mapping.h>
 
 #include "xhci.h"
+#include "xhci-trace.h"
 
 #define DRIVER_AUTHOR "Sarah Sharp"
 #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -101,7 +102,7 @@
 int xhci_halt(struct xhci_hcd *xhci)
 {
 	int ret;
-	xhci_dbg(xhci, "// Halt the HC\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC");
 	xhci_quiesce(xhci);
 
 	ret = xhci_handshake(xhci, &xhci->op_regs->status,
@@ -125,7 +126,7 @@
 
 	temp = xhci_readl(xhci, &xhci->op_regs->command);
 	temp |= (CMD_RUN);
-	xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
 			temp);
 	xhci_writel(xhci, temp, &xhci->op_regs->command);
 
@@ -163,7 +164,7 @@
 		return 0;
 	}
 
-	xhci_dbg(xhci, "// Reset the HC\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC");
 	command = xhci_readl(xhci, &xhci->op_regs->command);
 	command |= CMD_RESET;
 	xhci_writel(xhci, command, &xhci->op_regs->command);
@@ -173,7 +174,8 @@
 	if (ret)
 		return ret;
 
-	xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			 "Wait for controller to be ready for doorbell rings");
 	/*
 	 * xHCI cannot write to any doorbells or operational registers other
 	 * than status until the "Controller Not Ready" flag is cleared.
@@ -215,14 +217,16 @@
 
 	ret = pci_enable_msi(pdev);
 	if (ret) {
-		xhci_dbg(xhci, "failed to allocate MSI entry\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"failed to allocate MSI entry");
 		return ret;
 	}
 
 	ret = request_irq(pdev->irq, xhci_msi_irq,
 				0, "xhci_hcd", xhci_to_hcd(xhci));
 	if (ret) {
-		xhci_dbg(xhci, "disable MSI interrupt\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"disable MSI interrupt");
 		pci_disable_msi(pdev);
 	}
 
@@ -285,7 +289,8 @@
 
 	ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
 	if (ret) {
-		xhci_dbg(xhci, "Failed to enable MSI-X\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"Failed to enable MSI-X");
 		goto free_entries;
 	}
 
@@ -301,7 +306,7 @@
 	return ret;
 
 disable_msix:
-	xhci_dbg(xhci, "disable MSI-X interrupt\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
 	xhci_free_irq(xhci);
 	pci_disable_msix(pdev);
 free_entries:
@@ -343,9 +348,14 @@
 static int xhci_try_enable_msi(struct usb_hcd *hcd)
 {
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-	struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+	struct pci_dev  *pdev;
 	int ret;
 
+	/* The xhci platform device has set up IRQs through usb_add_hcd. */
+	if (xhci->quirks & XHCI_PLAT)
+		return 0;
+
+	pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
 	/*
 	 * Some Fresco Logic host controllers advertise MSI, but fail to
 	 * generate interrupts.  Don't even try to enable MSI.
@@ -418,9 +428,11 @@
 			 * Compliance Mode Detected. Letting USB Core
 			 * handle the Warm Reset
 			 */
-			xhci_dbg(xhci, "Compliance mode detected->port %d\n",
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+					"Compliance mode detected->port %d",
 					i + 1);
-			xhci_dbg(xhci, "Attempting compliance mode recovery\n");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+					"Attempting compliance mode recovery");
 			hcd = xhci->shared_hcd;
 
 			if (hcd->state == HC_STATE_SUSPENDED)
@@ -458,7 +470,8 @@
 	set_timer_slack(&xhci->comp_mode_recovery_timer,
 			msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
 	add_timer(&xhci->comp_mode_recovery_timer);
-	xhci_dbg(xhci, "Compliance mode recovery timer initialized\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+			"Compliance mode recovery timer initialized");
 }
 
 /*
@@ -506,16 +519,18 @@
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 	int retval = 0;
 
-	xhci_dbg(xhci, "xhci_init\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init");
 	spin_lock_init(&xhci->lock);
 	if (xhci->hci_version == 0x95 && link_quirk) {
-		xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"QUIRK: Not clearing Link TRB chain bits.");
 		xhci->quirks |= XHCI_LINK_TRB_QUIRK;
 	} else {
-		xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+				"xHCI doesn't need link TRB QUIRK");
 	}
 	retval = xhci_mem_init(xhci, GFP_KERNEL);
-	xhci_dbg(xhci, "Finished xhci_init\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init");
 
 	/* Initializing Compliance Mode Recovery Data If Needed */
 	if (xhci_compliance_mode_recovery_timer_quirk_check()) {
@@ -529,57 +544,6 @@
 /*-------------------------------------------------------------------------*/
 
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-static void xhci_event_ring_work(unsigned long arg)
-{
-	unsigned long flags;
-	int temp;
-	u64 temp_64;
-	struct xhci_hcd *xhci = (struct xhci_hcd *) arg;
-	int i, j;
-
-	xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies);
-
-	spin_lock_irqsave(&xhci->lock, flags);
-	temp = xhci_readl(xhci, &xhci->op_regs->status);
-	xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
-	if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
-			(xhci->xhc_state & XHCI_STATE_HALTED)) {
-		xhci_dbg(xhci, "HW died, polling stopped.\n");
-		spin_unlock_irqrestore(&xhci->lock, flags);
-		return;
-	}
-
-	temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
-	xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
-	xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask);
-	xhci->error_bitmask = 0;
-	xhci_dbg(xhci, "Event ring:\n");
-	xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
-	xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
-	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
-	temp_64 &= ~ERST_PTR_MASK;
-	xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
-	xhci_dbg(xhci, "Command ring:\n");
-	xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
-	xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
-	xhci_dbg_cmd_ptrs(xhci);
-	for (i = 0; i < MAX_HC_SLOTS; ++i) {
-		if (!xhci->devs[i])
-			continue;
-		for (j = 0; j < 31; ++j) {
-			xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]);
-		}
-	}
-	spin_unlock_irqrestore(&xhci->lock, flags);
-
-	if (!xhci->zombie)
-		mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ);
-	else
-		xhci_dbg(xhci, "Quit polling the event ring.\n");
-}
-#endif
-
 static int xhci_run_finished(struct xhci_hcd *xhci)
 {
 	if (xhci_start(xhci)) {
@@ -592,7 +556,8 @@
 	if (xhci->quirks & XHCI_NEC_HOST)
 		xhci_ring_cmd_db(xhci);
 
-	xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Finished xhci_run for USB3 roothub");
 	return 0;
 }
 
@@ -623,23 +588,12 @@
 	if (!usb_hcd_is_primary_hcd(hcd))
 		return xhci_run_finished(xhci);
 
-	xhci_dbg(xhci, "xhci_run\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run");
 
 	ret = xhci_try_enable_msi(hcd);
 	if (ret)
 		return ret;
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-	init_timer(&xhci->event_ring_timer);
-	xhci->event_ring_timer.data = (unsigned long) xhci;
-	xhci->event_ring_timer.function = xhci_event_ring_work;
-	/* Poll the event ring */
-	xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ;
-	xhci->zombie = 0;
-	xhci_dbg(xhci, "Setting event ring polling timer\n");
-	add_timer(&xhci->event_ring_timer);
-#endif
-
 	xhci_dbg(xhci, "Command ring memory map follows:\n");
 	xhci_debug_ring(xhci, xhci->cmd_ring);
 	xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
@@ -652,9 +606,11 @@
 	xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
 	temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
 	temp_64 &= ~ERST_PTR_MASK;
-	xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"ERST deq = 64'h%0lx", (long unsigned int) temp_64);
 
-	xhci_dbg(xhci, "// Set the interrupt modulation register\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Set the interrupt modulation register");
 	temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
 	temp &= ~ER_IRQ_INTERVAL_MASK;
 	temp |= (u32) 160;
@@ -663,12 +619,13 @@
 	/* Set the HCD state before we enable the irqs */
 	temp = xhci_readl(xhci, &xhci->op_regs->command);
 	temp |= (CMD_EIE);
-	xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n",
-			temp);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Enable interrupts, cmd = 0x%x.", temp);
 	xhci_writel(xhci, temp, &xhci->op_regs->command);
 
 	temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
-	xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Enabling event ring interrupter %p by writing 0x%x to irq_pending",
 			xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
 	xhci_writel(xhci, ER_IRQ_ENABLE(temp),
 			&xhci->ir_set->irq_pending);
@@ -678,7 +635,8 @@
 		xhci_queue_vendor_command(xhci, 0, 0, 0,
 				TRB_TYPE(TRB_NEC_GET_FW));
 
-	xhci_dbg(xhci, "Finished xhci_run for USB2 roothub\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"Finished xhci_run for USB2 roothub");
 	return 0;
 }
 
@@ -726,24 +684,20 @@
 
 	xhci_cleanup_msix(xhci);
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-	/* Tell the event ring poll function not to reschedule */
-	xhci->zombie = 1;
-	del_timer_sync(&xhci->event_ring_timer);
-#endif
-
 	/* Deleting Compliance Mode Recovery Timer */
 	if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
 			(!(xhci_all_ports_seen_u0(xhci)))) {
 		del_timer_sync(&xhci->comp_mode_recovery_timer);
-		xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"%s: compliance mode recovery timer deleted",
 				__func__);
 	}
 
 	if (xhci->quirks & XHCI_AMD_PLL_FIX)
 		usb_amd_dev_put();
 
-	xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Disabling event ring interrupts");
 	temp = xhci_readl(xhci, &xhci->op_regs->status);
 	xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
 	temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
@@ -751,10 +705,11 @@
 			&xhci->ir_set->irq_pending);
 	xhci_print_ir_set(xhci, 0);
 
-	xhci_dbg(xhci, "cleaning up memory\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
 	xhci_mem_cleanup(xhci);
-	xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
-		    xhci_readl(xhci, &xhci->op_regs->status));
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"xhci_stop completed - status = %x",
+			xhci_readl(xhci, &xhci->op_regs->status));
 }
 
 /*
@@ -779,8 +734,9 @@
 
 	xhci_cleanup_msix(xhci);
 
-	xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
-		    xhci_readl(xhci, &xhci->op_regs->status));
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"xhci_shutdown completed - status = %x",
+			xhci_readl(xhci, &xhci->op_regs->status));
 }
 
 #ifdef CONFIG_PM
@@ -821,7 +777,8 @@
 				      xhci->cmd_ring->dequeue) &
 		 (u64) ~CMD_RING_RSVD_BITS) |
 		xhci->cmd_ring->cycle_state;
-	xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+			"// Setting command ring address to 0x%llx",
 			(long unsigned long) val_64);
 	xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
 }
@@ -934,7 +891,8 @@
 	if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
 			(!(xhci_all_ports_seen_u0(xhci)))) {
 		del_timer_sync(&xhci->comp_mode_recovery_timer);
-		xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"%s: compliance mode recovery timer deleted",
 				__func__);
 	}
 
@@ -999,7 +957,8 @@
 		if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
 				!(xhci_all_ports_seen_u0(xhci))) {
 			del_timer_sync(&xhci->comp_mode_recovery_timer);
-			xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n");
+			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Compliance Mode Recovery Timer deleted!");
 		}
 
 		/* Let the USB core know _both_ roothubs lost power. */
@@ -1012,12 +971,6 @@
 		spin_unlock_irq(&xhci->lock);
 		xhci_cleanup_msix(xhci);
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-		/* Tell the event ring poll function not to reschedule */
-		xhci->zombie = 1;
-		del_timer_sync(&xhci->event_ring_timer);
-#endif
-
 		xhci_dbg(xhci, "// Disabling event ring interrupts\n");
 		temp = xhci_readl(xhci, &xhci->op_regs->status);
 		xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
@@ -1171,27 +1124,25 @@
 	struct xhci_virt_device	*virt_dev;
 
 	if (!hcd || (check_ep && !ep) || !udev) {
-		printk(KERN_DEBUG "xHCI %s called with invalid args\n",
-				func);
+		pr_debug("xHCI %s called with invalid args\n", func);
 		return -EINVAL;
 	}
 	if (!udev->parent) {
-		printk(KERN_DEBUG "xHCI %s called for root hub\n",
-				func);
+		pr_debug("xHCI %s called for root hub\n", func);
 		return 0;
 	}
 
 	xhci = hcd_to_xhci(hcd);
 	if (check_virt_dev) {
 		if (!udev->slot_id || !xhci->devs[udev->slot_id]) {
-			printk(KERN_DEBUG "xHCI %s called with unaddressed "
-						"device\n", func);
+			xhci_dbg(xhci, "xHCI %s called with unaddressed device\n",
+					func);
 			return -EINVAL;
 		}
 
 		virt_dev = xhci->devs[udev->slot_id];
 		if (virt_dev->udev != udev) {
-			printk(KERN_DEBUG "xHCI %s called with udev and "
+			xhci_dbg(xhci, "xHCI %s called with udev and "
 					  "virt_dev does not match\n", func);
 			return -EINVAL;
 		}
@@ -1229,12 +1180,16 @@
 	hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
 	max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
 	if (hw_max_packet_size != max_packet_size) {
-		xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
-		xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
+		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+				"Max Packet Size for ep 0 changed.");
+		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+				"Max packet size in usb_device = %d",
 				max_packet_size);
-		xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
+		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+				"Max packet size in xHCI HW = %d",
 				hw_max_packet_size);
-		xhci_dbg(xhci, "Issuing evaluate context command.\n");
+		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+				"Issuing evaluate context command.");
 
 		/* Set up the input context flags for the command */
 		/* FIXME: This won't work if a non-default control endpoint
@@ -1499,7 +1454,8 @@
 		goto done;
 	temp = xhci_readl(xhci, &xhci->op_regs->status);
 	if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
-		xhci_dbg(xhci, "HW died, freeing TD.\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+				"HW died, freeing TD.");
 		urb_priv = urb->hcpriv;
 		for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
 			td = urb_priv->td[i];
@@ -1517,8 +1473,9 @@
 	}
 	if ((xhci->xhc_state & XHCI_STATE_DYING) ||
 			(xhci->xhc_state & XHCI_STATE_HALTED)) {
-		xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on "
-				"non-responsive xHCI host.\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+				"Ep 0x%x: URB %p to be canceled on "
+				"non-responsive xHCI host.",
 				urb->ep->desc.bEndpointAddress, urb);
 		/* Let the stop endpoint command watchdog timer (which set this
 		 * state) finish cleaning up the endpoint TD lists.  We must
@@ -1539,8 +1496,9 @@
 	urb_priv = urb->hcpriv;
 	i = urb_priv->td_cnt;
 	if (i < urb_priv->length)
-		xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, "
-				"starting at offset 0x%llx\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
+				"Cancel URB %p, dev %s, ep 0x%x, "
+				"starting at offset 0x%llx",
 				urb, urb->dev->devpath,
 				urb->ep->desc.bEndpointAddress,
 				(unsigned long long) xhci_trb_virt_to_dma(
@@ -1852,7 +1810,8 @@
 		ret = -ENODEV;
 		break;
 	case COMP_SUCCESS:
-		dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+				"Successful Endpoint Configure command");
 		ret = 0;
 		break;
 	default:
@@ -1898,7 +1857,8 @@
 		ret = -EINVAL;
 		break;
 	case COMP_SUCCESS:
-		dev_dbg(&udev->dev, "Successful evaluate context command\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+				"Successful evaluate context command");
 		ret = 0;
 		break;
 	default:
@@ -1964,14 +1924,16 @@
 
 	added_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx);
 	if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) {
-		xhci_dbg(xhci, "Not enough ep ctxs: "
-				"%u active, need to add %u, limit is %u.\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Not enough ep ctxs: "
+				"%u active, need to add %u, limit is %u.",
 				xhci->num_active_eps, added_eps,
 				xhci->limit_active_eps);
 		return -ENOMEM;
 	}
 	xhci->num_active_eps += added_eps;
-	xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps,
+	xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+			"Adding %u ep ctxs, %u now active.", added_eps,
 			xhci->num_active_eps);
 	return 0;
 }
@@ -1989,7 +1951,8 @@
 
 	num_failed_eps = xhci_count_num_new_endpoints(xhci, ctrl_ctx);
 	xhci->num_active_eps -= num_failed_eps;
-	xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+			"Removing %u failed ep ctxs, %u now active.",
 			num_failed_eps,
 			xhci->num_active_eps);
 }
@@ -2008,7 +1971,8 @@
 	num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, ctrl_ctx);
 	xhci->num_active_eps -= num_dropped_eps;
 	if (num_dropped_eps)
-		xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Removing %u dropped ep ctxs, %u now active.",
 				num_dropped_eps,
 				xhci->num_active_eps);
 }
@@ -2169,18 +2133,21 @@
 	 * that the HS bus has enough bandwidth if we are activing a new TT.
 	 */
 	if (virt_dev->tt_info) {
-		xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Recalculating BW for rootport %u",
 				virt_dev->real_port);
 		if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) {
 			xhci_warn(xhci, "Not enough bandwidth on HS bus for "
 					"newly activated TT.\n");
 			return -ENOMEM;
 		}
-		xhci_dbg(xhci, "Recalculating BW for TT slot %u port %u\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Recalculating BW for TT slot %u port %u",
 				virt_dev->tt_info->slot_id,
 				virt_dev->tt_info->ttport);
 	} else {
-		xhci_dbg(xhci, "Recalculating BW for rootport %u\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Recalculating BW for rootport %u",
 				virt_dev->real_port);
 	}
 
@@ -2288,8 +2255,9 @@
 			xhci->rh_bw[port_index].num_active_tts;
 	}
 
-	xhci_dbg(xhci, "Final bandwidth: %u, Limit: %u, Reserved: %u, "
-		"Available: %u " "percent\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+		"Final bandwidth: %u, Limit: %u, Reserved: %u, "
+		"Available: %u " "percent",
 		bw_used, max_bandwidth, bw_reserved,
 		(max_bandwidth - bw_used - bw_reserved) * 100 /
 		max_bandwidth);
@@ -2659,7 +2627,8 @@
 		if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))
 			xhci_free_host_resources(xhci, ctrl_ctx);
 		spin_unlock_irqrestore(&xhci->lock, flags);
-		xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
+		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change,
+				"FIXME allocate a new ring segment");
 		return -ENOMEM;
 	}
 	xhci_ring_cmd_db(xhci);
@@ -2872,7 +2841,8 @@
 	struct xhci_dequeue_state deq_state;
 	struct xhci_virt_ep *ep;
 
-	xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+			"Cleaning up stalled endpoint ring");
 	ep = &xhci->devs[udev->slot_id]->eps[ep_index];
 	/* We need to move the HW's dequeue pointer past this TD,
 	 * or it will attempt to resend it on the next doorbell ring.
@@ -2885,7 +2855,8 @@
 	 * issue a configure endpoint command later.
 	 */
 	if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
-		xhci_dbg(xhci, "Queueing new dequeue state\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+				"Queueing new dequeue state");
 		xhci_queue_new_dequeue_state(xhci, udev->slot_id,
 				ep_index, ep->stopped_stream, &deq_state);
 	} else {
@@ -2894,8 +2865,9 @@
 		 * XXX: No idea how this hardware will react when stream rings
 		 * are enabled.
 		 */
-		xhci_dbg(xhci, "Setting up input context for "
-				"configure endpoint command\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Setting up input context for "
+				"configure endpoint command");
 		xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id,
 				ep_index, &deq_state);
 	}
@@ -2927,16 +2899,19 @@
 	ep_index = xhci_get_endpoint_index(&ep->desc);
 	virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
 	if (!virt_ep->stopped_td) {
-		xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
-				ep->desc.bEndpointAddress);
+		xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+			"Endpoint 0x%x not halted, refusing to reset.",
+			ep->desc.bEndpointAddress);
 		return;
 	}
 	if (usb_endpoint_xfer_control(&ep->desc)) {
-		xhci_dbg(xhci, "Control endpoint stall already handled.\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+				"Control endpoint stall already handled.");
 		return;
 	}
 
-	xhci_dbg(xhci, "Queueing reset endpoint command\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,
+			"Queueing reset endpoint command");
 	spin_lock_irqsave(&xhci->lock, flags);
 	ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index);
 	/*
@@ -3076,8 +3051,8 @@
 		/* Are streams already being freed for the endpoint? */
 		if (ep_state & EP_GETTING_NO_STREAMS) {
 			xhci_warn(xhci, "WARN Can't disable streams for "
-					"endpoint 0x%x\n, "
-					"streams are being disabled already.",
+					"endpoint 0x%x, "
+					"streams are being disabled already\n",
 					eps[i]->desc.bEndpointAddress);
 			return 0;
 		}
@@ -3085,8 +3060,8 @@
 		if (!(ep_state & EP_HAS_STREAMS) &&
 				!(ep_state & EP_GETTING_STREAMS)) {
 			xhci_warn(xhci, "WARN Can't disable streams for "
-					"endpoint 0x%x\n, "
-					"streams are already disabled!",
+					"endpoint 0x%x, "
+					"streams are already disabled!\n",
 					eps[i]->desc.bEndpointAddress);
 			xhci_warn(xhci, "WARN xhci_free_streams() called "
 					"with non-streams endpoint\n");
@@ -3374,8 +3349,9 @@
 	}
 	xhci->num_active_eps -= num_dropped_eps;
 	if (num_dropped_eps)
-		xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, "
-				"%u now active.\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Dropped %u ep ctxs, flags = 0x%x, "
+				"%u now active.",
 				num_dropped_eps, drop_flags,
 				xhci->num_active_eps);
 }
@@ -3509,10 +3485,10 @@
 	switch (ret) {
 	case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
 	case COMP_CTX_STATE: /* 0.96 completion code for same thing */
-		xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n",
+		xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n",
 				slot_id,
 				xhci_get_slot_state(xhci, virt_dev->out_ctx));
-		xhci_info(xhci, "Not freeing device rings.\n");
+		xhci_dbg(xhci, "Not freeing device rings.\n");
 		/* Don't treat this as an error.  May change my mind later. */
 		ret = 0;
 		goto command_cleanup;
@@ -3585,6 +3561,16 @@
 	u32 state;
 	int i, ret;
 
+#ifndef CONFIG_USB_DEFAULT_PERSIST
+	/*
+	 * We called pm_runtime_get_noresume when the device was attached.
+	 * Decrement the counter here to allow controller to runtime suspend
+	 * if no devices remain.
+	 */
+	if (xhci->quirks & XHCI_RESET_ON_RESUME)
+		pm_runtime_put_noidle(hcd->self.controller);
+#endif
+
 	ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
 	/* If the host is halted due to driver unload, we still need to free the
 	 * device.
@@ -3637,13 +3623,15 @@
 static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci)
 {
 	if (xhci->num_active_eps + 1 > xhci->limit_active_eps) {
-		xhci_dbg(xhci, "Not enough ep ctxs: "
-				"%u active, need to add 1, limit is %u.\n",
+		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+				"Not enough ep ctxs: "
+				"%u active, need to add 1, limit is %u.",
 				xhci->num_active_eps, xhci->limit_active_eps);
 		return -ENOMEM;
 	}
 	xhci->num_active_eps += 1;
-	xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
+			"Adding 1 ep ctx, %u now active.",
 			xhci->num_active_eps);
 	return 0;
 }
@@ -3708,6 +3696,16 @@
 		goto disable_slot;
 	}
 	udev->slot_id = xhci->slot_id;
+
+#ifndef CONFIG_USB_DEFAULT_PERSIST
+	/*
+	 * If resetting upon resume, we can't put the controller into runtime
+	 * suspend if there is a device attached.
+	 */
+	if (xhci->quirks & XHCI_RESET_ON_RESUME)
+		pm_runtime_get_noresume(hcd->self.controller);
+#endif
+
 	/* Is this a LS or FS device under a HS hub? */
 	/* Hub or peripherial? */
 	return 1;
@@ -3743,7 +3741,8 @@
 	union xhci_trb *cmd_trb;
 
 	if (!udev->slot_id) {
-		xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
+		xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+				"Bad Slot ID %d", udev->slot_id);
 		return -EINVAL;
 	}
 
@@ -3782,6 +3781,8 @@
 
 	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
 	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+	trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
+				slot_ctx->dev_info >> 27);
 
 	spin_lock_irqsave(&xhci->lock, flags);
 	cmd_trb = xhci->cmd_ring->dequeue;
@@ -3789,7 +3790,8 @@
 					udev->slot_id);
 	if (ret) {
 		spin_unlock_irqrestore(&xhci->lock, flags);
-		xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+				"FIXME: allocate a command ring segment");
 		return ret;
 	}
 	xhci_ring_cmd_db(xhci);
@@ -3829,13 +3831,15 @@
 		ret = -ENODEV;
 		break;
 	case COMP_SUCCESS:
-		xhci_dbg(xhci, "Successful Address Device command\n");
+		xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+				"Successful Address Device command");
 		break;
 	default:
 		xhci_err(xhci, "ERROR: unexpected command completion "
 				"code 0x%x.\n", virt_dev->cmd_status);
 		xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
 		xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
+		trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1);
 		ret = -EINVAL;
 		break;
 	}
@@ -3843,16 +3847,21 @@
 		return ret;
 	}
 	temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
-	xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64);
-	xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n",
-		 udev->slot_id,
-		 &xhci->dcbaa->dev_context_ptrs[udev->slot_id],
-		 (unsigned long long)
-		 le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
-	xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
+	xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+			"Op regs DCBAA ptr = %#016llx", temp_64);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+		"Slot ID %d dcbaa entry @%p = %#016llx",
+		udev->slot_id,
+		&xhci->dcbaa->dev_context_ptrs[udev->slot_id],
+		(unsigned long long)
+		le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id]));
+	xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+			"Output Context DMA address = %#08llx",
 			(unsigned long long)virt_dev->out_ctx->dma);
 	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
 	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
+	trace_xhci_address_ctx(xhci, virt_dev->in_ctx,
+				slot_ctx->dev_info >> 27);
 	xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
 	xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);
 	/*
@@ -3860,6 +3869,8 @@
 	 * address given back to us by the HC.
 	 */
 	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+	trace_xhci_address_ctx(xhci, virt_dev->out_ctx,
+				slot_ctx->dev_info >> 27);
 	/* Use kernel assigned address for devices; store xHC assigned
 	 * address locally. */
 	virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK)
@@ -3868,7 +3879,8 @@
 	ctrl_ctx->add_flags = 0;
 	ctrl_ctx->drop_flags = 0;
 
-	xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address);
+	xhci_dbg_trace(xhci, trace_xhci_dbg_address,
+			"Internal device address = %d", virt_dev->address);
 
 	return 0;
 }
@@ -3934,7 +3946,8 @@
 	slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
 	slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
 
-	xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
+	xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
+			"Set up evaluate context for LPM MEL change.");
 	xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
 	xhci_dbg_ctx(xhci, command->in_ctx, 0);
 
@@ -4354,7 +4367,7 @@
 				state_name, sel);
 	else
 		dev_dbg(&udev->dev, "Device-initiated %s disabled "
-				"due to long PEL %llu\n ms",
+				"due to long PEL %llu ms\n",
 				state_name, pel);
 	return USB3_LPM_DISABLED;
 }
@@ -4838,10 +4851,13 @@
 	struct xhci_hcd		*xhci;
 	struct device		*dev = hcd->self.controller;
 	int			retval;
-	u32			temp;
 
 	/* Accept arbitrarily long scatter-gather lists */
 	hcd->self.sg_tablesize = ~0;
+
+	/* support to build packet from discontinuous buffers */
+	hcd->self.no_sg_constraint = 1;
+
 	/* XHCI controllers don't stop the ep queue on short packets :| */
 	hcd->self.no_stop_on_short = 1;
 
@@ -4866,14 +4882,6 @@
 		/* xHCI private pointer was set in xhci_pci_probe for the second
 		 * registered roothub.
 		 */
-		xhci = hcd_to_xhci(hcd);
-		temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
-		if (HCC_64BIT_ADDR(temp)) {
-			xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-			dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
-		} else {
-			dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
-		}
 		return 0;
 	}
 
@@ -4912,12 +4920,12 @@
 		goto error;
 	xhci_dbg(xhci, "Reset complete\n");
 
-	temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
-	if (HCC_64BIT_ADDR(temp)) {
+	/* Set dma_mask and coherent_dma_mask to 64-bits,
+	 * if xHC supports 64-bit addressing */
+	if (HCC_64BIT_ADDR(xhci->hcc_params) &&
+			!dma_set_mask(dev, DMA_BIT_MASK(64))) {
 		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
-		dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
-	} else {
-		dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
+		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
 	}
 
 	xhci_dbg(xhci, "Calling HCD init\n");
@@ -4942,12 +4950,12 @@
 
 	retval = xhci_register_pci();
 	if (retval < 0) {
-		printk(KERN_DEBUG "Problem registering PCI driver.");
+		pr_debug("Problem registering PCI driver.\n");
 		return retval;
 	}
 	retval = xhci_register_plat();
 	if (retval < 0) {
-		printk(KERN_DEBUG "Problem registering platform driver.");
+		pr_debug("Problem registering platform driver.\n");
 		goto unreg_pci;
 	}
 	/*
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c338741..46aa148 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1490,11 +1490,6 @@
 	struct dma_pool	*small_streams_pool;
 	struct dma_pool	*medium_streams_pool;
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-	/* Poll the rings - for debugging */
-	struct timer_list	event_ring_timer;
-	int			zombie;
-#endif
 	/* Host controller watchdog timer structures */
 	unsigned int		xhc_state;
 
@@ -1542,6 +1537,7 @@
 #define XHCI_SPURIOUS_REBOOT	(1 << 13)
 #define XHCI_COMP_MODE_QUIRK	(1 << 14)
 #define XHCI_AVOID_BEI		(1 << 15)
+#define XHCI_PLAT		(1 << 16)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
@@ -1579,16 +1575,8 @@
 	return xhci->main_hcd;
 }
 
-#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
-#define XHCI_DEBUG	1
-#else
-#define XHCI_DEBUG	0
-#endif
-
 #define xhci_dbg(xhci, fmt, args...) \
-	do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
-#define xhci_info(xhci, fmt, args...) \
-	do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
+	dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_err(xhci, fmt, args...) \
 	dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_warn(xhci, fmt, args...) \
@@ -1660,6 +1648,8 @@
 void xhci_dbg_ep_rings(struct xhci_hcd *xhci,
 		unsigned int slot_id, unsigned int ep_index,
 		struct xhci_virt_ep *ep);
+void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
+			const char *fmt, ...);
 
 /* xHCI memory management */
 void xhci_mem_cleanup(struct xhci_hcd *xhci);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a51e7d6..e2b21c1 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -200,6 +200,19 @@
 	  See <http://www.linux-usb.org/usbtest/> for more information,
 	  including sample test device firmware and "how to use it".
 
+config USB_EHSET_TEST_FIXTURE
+        tristate "USB EHSET Test Fixture driver"
+        help
+	  Say Y here if you want to support the special test fixture device
+	  used for the USB-IF Embedded Host High-Speed Electrical Test procedure.
+
+	  When the test fixture is connected, it can enumerate as one of several
+	  VID/PID pairs. This driver then initiates a corresponding test mode on
+	  the downstream port to which the test fixture is attached.
+
+	  See <http://www.usb.org/developers/onthego/EHSET_v1.01.pdf> for more
+	  information.
+
 config USB_ISIGHTFW
 	tristate "iSight firmware loading support"
 	select FW_LOADER
@@ -233,5 +246,6 @@
 config USB_HSIC_USB3503
        tristate "USB3503 HSIC to USB20 Driver"
        depends on I2C
+       select REGMAP
        help
          This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver.
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 3e1bd70..e748fd5 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -2,9 +2,6 @@
 # Makefile for the rest of the USB drivers
 # (the ones that don't fit into any other categories)
 #
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
 obj-$(CONFIG_USB_ADUTUX)		+= adutux.o
 obj-$(CONFIG_USB_APPLEDISPLAY)		+= appledisplay.o
 obj-$(CONFIG_USB_CYPRESS_CY7C63)	+= cypress_cy7c63.o
@@ -22,6 +19,7 @@
 obj-$(CONFIG_USB_LEGOTOWER)		+= legousbtower.o
 obj-$(CONFIG_USB_RIO500)		+= rio500.o
 obj-$(CONFIG_USB_TEST)			+= usbtest.o
+obj-$(CONFIG_USB_EHSET_TEST_FIXTURE)    += ehset.o
 obj-$(CONFIG_USB_TRANCEVIBRATOR)	+= trancevibrator.o
 obj-$(CONFIG_USB_USS720)		+= uss720.o
 obj-$(CONFIG_USB_SEVSEG)		+= usbsevseg.o
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index eeb2720..3eaa83f 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -18,6 +18,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -27,30 +29,11 @@
 #include <linux/mutex.h>
 #include <linux/uaccess.h>
 
-#ifdef CONFIG_USB_DEBUG
-static int debug = 5;
-#else
-static int debug = 1;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(lvl, format, arg...)	\
-do {								\
-	if (debug >= lvl)						\
-		printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg);	\
-} while (0)
-
-
 /* Version Information */
 #define DRIVER_VERSION "v0.0.13"
 #define DRIVER_AUTHOR "John Homppi"
 #define DRIVER_DESC "adutux (see www.ontrak.net)"
 
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 /* Define these values to match your device */
 #define ADU_VENDOR_ID 0x0a07
 #define ADU_PRODUCT_ID 0x0064
@@ -124,19 +107,11 @@
 
 static struct usb_driver adu_driver;
 
-static void adu_debug_data(int level, const char *function, int size,
-			   const unsigned char *data)
+static inline void adu_debug_data(struct device *dev, const char *function,
+				  int size, const unsigned char *data)
 {
-	int i;
-
-	if (debug < level)
-		return;
-
-	printk(KERN_DEBUG "%s: %s - length = %d, data = ",
-	       __FILE__, function, size);
-	for (i = 0; i < size; ++i)
-		printk("%.2x ", data[i]);
-	printk("\n");
+	dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+		function, size, size, data);
 }
 
 /**
@@ -147,12 +122,8 @@
 {
 	unsigned long flags;
 
-	dbg(2, " %s : enter", __func__);
-
-	if (dev->udev == NULL) {
-		dbg(1, " %s : udev is null", __func__);
-		goto exit;
-	}
+	if (dev->udev == NULL)
+		return;
 
 	/* shutdown transfer */
 
@@ -170,15 +141,10 @@
 		usb_kill_urb(dev->interrupt_out_urb);
 	} else
 		spin_unlock_irqrestore(&dev->buflock, flags);
-
-exit:
-	dbg(2, " %s : leave", __func__);
 }
 
 static void adu_delete(struct adu_device *dev)
 {
-	dbg(2, "%s enter", __func__);
-
 	/* free data structures */
 	usb_free_urb(dev->interrupt_in_urb);
 	usb_free_urb(dev->interrupt_out_urb);
@@ -187,8 +153,6 @@
 	kfree(dev->interrupt_in_buffer);
 	kfree(dev->interrupt_out_buffer);
 	kfree(dev);
-
-	dbg(2, "%s : leave", __func__);
 }
 
 static void adu_interrupt_in_callback(struct urb *urb)
@@ -196,17 +160,17 @@
 	struct adu_device *dev = urb->context;
 	int status = urb->status;
 
-	dbg(4, " %s : enter, status %d", __func__, status);
-	adu_debug_data(5, __func__, urb->actual_length,
-		       urb->transfer_buffer);
+	adu_debug_data(&dev->udev->dev, __func__,
+		       urb->actual_length, urb->transfer_buffer);
 
 	spin_lock(&dev->buflock);
 
 	if (status != 0) {
 		if ((status != -ENOENT) && (status != -ECONNRESET) &&
 			(status != -ESHUTDOWN)) {
-			dbg(1, " %s : nonzero status received: %d",
-			    __func__, status);
+			dev_dbg(&dev->udev->dev,
+				"%s : nonzero status received: %d\n",
+				__func__, status);
 		}
 		goto exit;
 	}
@@ -220,10 +184,11 @@
 				dev->interrupt_in_buffer, urb->actual_length);
 
 			dev->read_buffer_length += urb->actual_length;
-			dbg(2, " %s reading  %d ", __func__,
-			    urb->actual_length);
+			dev_dbg(&dev->udev->dev,"%s reading  %d\n", __func__,
+				urb->actual_length);
 		} else {
-			dbg(1, " %s : read_buffer overflow", __func__);
+			dev_dbg(&dev->udev->dev,"%s : read_buffer overflow\n",
+				__func__);
 		}
 	}
 
@@ -232,9 +197,6 @@
 	spin_unlock(&dev->buflock);
 	/* always wake up so we recover from errors */
 	wake_up_interruptible(&dev->read_wait);
-	adu_debug_data(5, __func__, urb->actual_length,
-		       urb->transfer_buffer);
-	dbg(4, " %s : leave, status %d", __func__, status);
 }
 
 static void adu_interrupt_out_callback(struct urb *urb)
@@ -242,27 +204,23 @@
 	struct adu_device *dev = urb->context;
 	int status = urb->status;
 
-	dbg(4, " %s : enter, status %d", __func__, status);
-	adu_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+	adu_debug_data(&dev->udev->dev, __func__,
+		       urb->actual_length, urb->transfer_buffer);
 
 	if (status != 0) {
 		if ((status != -ENOENT) &&
 		    (status != -ECONNRESET)) {
-			dbg(1, " %s :nonzero status received: %d",
-			    __func__, status);
+			dev_dbg(&dev->udev->dev,
+				"%s :nonzero status received: %d\n", __func__,
+				status);
 		}
-		goto exit;
+		return;
 	}
 
 	spin_lock(&dev->buflock);
 	dev->out_urb_finished = 1;
 	wake_up(&dev->write_wait);
 	spin_unlock(&dev->buflock);
-exit:
-
-	adu_debug_data(5, __func__, urb->actual_length,
-		       urb->transfer_buffer);
-	dbg(4, " %s : leave, status %d", __func__, status);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
@@ -272,20 +230,16 @@
 	int subminor;
 	int retval;
 
-	dbg(2, "%s : enter", __func__);
-
 	subminor = iminor(inode);
 
 	retval = mutex_lock_interruptible(&adutux_mutex);
-	if (retval) {
-		dbg(2, "%s : mutex lock failed", __func__);
+	if (retval)
 		goto exit_no_lock;
-	}
 
 	interface = usb_find_interface(&adu_driver, subminor);
 	if (!interface) {
-		printk(KERN_ERR "adutux: %s - error, can't find device for "
-		       "minor %d\n", __func__, subminor);
+		pr_err("%s - error, can't find device for minor %d\n",
+		       __func__, subminor);
 		retval = -ENODEV;
 		goto exit_no_device;
 	}
@@ -303,7 +257,8 @@
 	}
 
 	++dev->open_count;
-	dbg(2, "%s : open count %d", __func__, dev->open_count);
+	dev_dbg(&dev->udev->dev, "%s: open count %d\n", __func__,
+		dev->open_count);
 
 	/* save device in the file's private structure */
 	file->private_data = dev;
@@ -333,23 +288,19 @@
 exit_no_device:
 	mutex_unlock(&adutux_mutex);
 exit_no_lock:
-	dbg(2, "%s : leave, return value %d ", __func__, retval);
 	return retval;
 }
 
 static void adu_release_internal(struct adu_device *dev)
 {
-	dbg(2, " %s : enter", __func__);
-
 	/* decrement our usage count for the device */
 	--dev->open_count;
-	dbg(2, " %s : open count %d", __func__, dev->open_count);
+	dev_dbg(&dev->udev->dev, "%s : open count %d\n", __func__,
+		dev->open_count);
 	if (dev->open_count <= 0) {
 		adu_abort_transfers(dev);
 		dev->open_count = 0;
 	}
-
-	dbg(2, " %s : leave", __func__);
 }
 
 static int adu_release(struct inode *inode, struct file *file)
@@ -357,17 +308,13 @@
 	struct adu_device *dev;
 	int retval = 0;
 
-	dbg(2, " %s : enter", __func__);
-
 	if (file == NULL) {
-		dbg(1, " %s : file is NULL", __func__);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	dev = file->private_data;
 	if (dev == NULL) {
-		dbg(1, " %s : object is NULL", __func__);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -375,7 +322,7 @@
 	mutex_lock(&adutux_mutex); /* not interruptible */
 
 	if (dev->open_count <= 0) {
-		dbg(1, " %s : device not opened", __func__);
+		dev_dbg(&dev->udev->dev, "%s : device not opened\n", __func__);
 		retval = -ENODEV;
 		goto unlock;
 	}
@@ -389,7 +336,6 @@
 unlock:
 	mutex_unlock(&adutux_mutex);
 exit:
-	dbg(2, " %s : leave, return value %d", __func__, retval);
 	return retval;
 }
 
@@ -406,35 +352,32 @@
 	unsigned long flags;
 	DECLARE_WAITQUEUE(wait, current);
 
-	dbg(2, " %s : enter, count = %Zd, file=%p", __func__, count, file);
-
 	dev = file->private_data;
-	dbg(2, " %s : dev=%p", __func__, dev);
-
 	if (mutex_lock_interruptible(&dev->mtx))
 		return -ERESTARTSYS;
 
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL) {
 		retval = -ENODEV;
-		printk(KERN_ERR "adutux: No device or device unplugged %d\n",
-		       retval);
+		pr_err("No device or device unplugged %d\n", retval);
 		goto exit;
 	}
 
 	/* verify that some data was requested */
 	if (count == 0) {
-		dbg(1, " %s : read request of 0 bytes", __func__);
+		dev_dbg(&dev->udev->dev, "%s : read request of 0 bytes\n",
+			__func__);
 		goto exit;
 	}
 
 	timeout = COMMAND_TIMEOUT;
-	dbg(2, " %s : about to start looping", __func__);
+	dev_dbg(&dev->udev->dev, "%s : about to start looping\n", __func__);
 	while (bytes_to_read) {
 		int data_in_secondary = dev->secondary_tail - dev->secondary_head;
-		dbg(2, " %s : while, data_in_secondary=%d, status=%d",
-		    __func__, data_in_secondary,
-		    dev->interrupt_in_urb->status);
+		dev_dbg(&dev->udev->dev,
+			"%s : while, data_in_secondary=%d, status=%d\n",
+			__func__, data_in_secondary,
+			dev->interrupt_in_urb->status);
 
 		if (data_in_secondary) {
 			/* drain secondary buffer */
@@ -457,8 +400,9 @@
 			if (dev->read_buffer_length) {
 				/* we secure access to the primary */
 				char *tmp;
-				dbg(2, " %s : swap, read_buffer_length = %d",
-				    __func__, dev->read_buffer_length);
+				dev_dbg(&dev->udev->dev,
+					"%s : swap, read_buffer_length = %d\n",
+					__func__, dev->read_buffer_length);
 				tmp = dev->read_buffer_secondary;
 				dev->read_buffer_secondary = dev->read_buffer_primary;
 				dev->read_buffer_primary = tmp;
@@ -473,10 +417,14 @@
 				if (!dev->read_urb_finished) {
 					/* somebody is doing IO */
 					spin_unlock_irqrestore(&dev->buflock, flags);
-					dbg(2, " %s : submitted already", __func__);
+					dev_dbg(&dev->udev->dev,
+						"%s : submitted already\n",
+						__func__);
 				} else {
 					/* we must initiate input */
-					dbg(2, " %s : initiate input", __func__);
+					dev_dbg(&dev->udev->dev,
+						"%s : initiate input\n",
+						__func__);
 					dev->read_urb_finished = 0;
 					spin_unlock_irqrestore(&dev->buflock, flags);
 
@@ -494,7 +442,9 @@
 						if (retval == -ENOMEM) {
 							retval = bytes_read ? bytes_read : -ENOMEM;
 						}
-						dbg(2, " %s : submit failed", __func__);
+						dev_dbg(&dev->udev->dev,
+							"%s : submit failed\n",
+							__func__);
 						goto exit;
 					}
 				}
@@ -513,13 +463,16 @@
 				remove_wait_queue(&dev->read_wait, &wait);
 
 				if (timeout <= 0) {
-					dbg(2, " %s : timeout", __func__);
+					dev_dbg(&dev->udev->dev,
+						"%s : timeout\n", __func__);
 					retval = bytes_read ? bytes_read : -ETIMEDOUT;
 					goto exit;
 				}
 
 				if (signal_pending(current)) {
-					dbg(2, " %s : signal pending", __func__);
+					dev_dbg(&dev->udev->dev,
+						"%s : signal pending\n",
+						__func__);
 					retval = bytes_read ? bytes_read : -EINTR;
 					goto exit;
 				}
@@ -552,7 +505,6 @@
 	/* unlock the device */
 	mutex_unlock(&dev->mtx);
 
-	dbg(2, " %s : leave, return value %d", __func__, retval);
 	return retval;
 }
 
@@ -567,8 +519,6 @@
 	unsigned long flags;
 	int retval;
 
-	dbg(2, " %s : enter, count = %Zd", __func__, count);
-
 	dev = file->private_data;
 
 	retval = mutex_lock_interruptible(&dev->mtx);
@@ -578,14 +528,14 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL) {
 		retval = -ENODEV;
-		printk(KERN_ERR "adutux: No device or device unplugged %d\n",
-		       retval);
+		pr_err("No device or device unplugged %d\n", retval);
 		goto exit;
 	}
 
 	/* verify that we actually have some data to write */
 	if (count == 0) {
-		dbg(1, " %s : write request of 0 bytes", __func__);
+		dev_dbg(&dev->udev->dev, "%s : write request of 0 bytes\n",
+			__func__);
 		goto exit;
 	}
 
@@ -598,13 +548,15 @@
 
 			mutex_unlock(&dev->mtx);
 			if (signal_pending(current)) {
-				dbg(1, " %s : interrupted", __func__);
+				dev_dbg(&dev->udev->dev, "%s : interrupted\n",
+					__func__);
 				set_current_state(TASK_RUNNING);
 				retval = -EINTR;
 				goto exit_onqueue;
 			}
 			if (schedule_timeout(COMMAND_TIMEOUT) == 0) {
-				dbg(1, "%s - command timed out.", __func__);
+				dev_dbg(&dev->udev->dev,
+					"%s - command timed out.\n", __func__);
 				retval = -ETIMEDOUT;
 				goto exit_onqueue;
 			}
@@ -615,18 +567,22 @@
 				goto exit_nolock;
 			}
 
-			dbg(4, " %s : in progress, count = %Zd", __func__, count);
+			dev_dbg(&dev->udev->dev,
+				"%s : in progress, count = %Zd\n",
+				__func__, count);
 		} else {
 			spin_unlock_irqrestore(&dev->buflock, flags);
 			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&dev->write_wait, &waita);
-			dbg(4, " %s : sending, count = %Zd", __func__, count);
+			dev_dbg(&dev->udev->dev, "%s : sending, count = %Zd\n",
+				__func__, count);
 
 			/* write the data into interrupt_out_buffer from userspace */
 			buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint);
 			bytes_to_write = count > buffer_size ? buffer_size : count;
-			dbg(4, " %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
-			    __func__, buffer_size, count, bytes_to_write);
+			dev_dbg(&dev->udev->dev,
+				"%s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd\n",
+				__func__, buffer_size, count, bytes_to_write);
 
 			if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
 				retval = -EFAULT;
@@ -665,7 +621,6 @@
 exit:
 	mutex_unlock(&dev->mtx);
 exit_nolock:
-	dbg(2, " %s : leave, return value %d", __func__, retval);
 	return retval;
 
 exit_onqueue:
@@ -711,8 +666,6 @@
 	int out_end_size;
 	int i;
 
-	dbg(2, " %s : enter", __func__);
-
 	if (udev == NULL) {
 		dev_err(&interface->dev, "udev is NULL.\n");
 		goto exit;
@@ -812,7 +765,7 @@
 		dev_err(&interface->dev, "Could not retrieve serial number\n");
 		goto error;
 	}
-	dbg(2, " %s : serial_number=%s", __func__, dev->serial_number);
+	dev_dbg(&interface->dev,"serial_number=%s", dev->serial_number);
 
 	/* we can register the device now, as it is ready */
 	usb_set_intfdata(interface, dev);
@@ -833,8 +786,6 @@
 		 le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
 		 (dev->minor - ADU_MINOR_BASE));
 exit:
-	dbg(2, " %s : leave, return value %p (dev)", __func__, dev);
-
 	return retval;
 
 error:
@@ -852,8 +803,6 @@
 	struct adu_device *dev;
 	int minor;
 
-	dbg(2, " %s : enter", __func__);
-
 	dev = usb_get_intfdata(interface);
 
 	mutex_lock(&dev->mtx);	/* not interruptible */
@@ -866,7 +815,8 @@
 	usb_set_intfdata(interface, NULL);
 
 	/* if the device is not opened, then we clean up right now */
-	dbg(2, " %s : open count %d", __func__, dev->open_count);
+	dev_dbg(&dev->udev->dev, "%s : open count %d\n",
+		__func__, dev->open_count);
 	if (!dev->open_count)
 		adu_delete(dev);
 
@@ -874,8 +824,6 @@
 
 	dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",
 		 (minor - ADU_MINOR_BASE));
-
-	dbg(2, " %s : leave", __func__);
 }
 
 /* usb specific object needed to register this driver with the usb subsystem */
diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
new file mode 100644
index 0000000..c31b4a3
--- /dev/null
+++ b/drivers/usb/misc/ehset.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/ch11.h>
+
+#define TEST_SE0_NAK_PID			0x0101
+#define TEST_J_PID				0x0102
+#define TEST_K_PID				0x0103
+#define TEST_PACKET_PID				0x0104
+#define TEST_HS_HOST_PORT_SUSPEND_RESUME	0x0106
+#define TEST_SINGLE_STEP_GET_DEV_DESC		0x0107
+#define TEST_SINGLE_STEP_SET_FEATURE		0x0108
+
+static int ehset_probe(struct usb_interface *intf,
+		       const struct usb_device_id *id)
+{
+	int ret = -EINVAL;
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_device *hub_udev = dev->parent;
+	struct usb_device_descriptor *buf;
+	u8 portnum = dev->portnum;
+	u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
+
+	switch (test_pid) {
+	case TEST_SE0_NAK_PID:
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_SET_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_TEST,
+					(TEST_SE0_NAK << 8) | portnum,
+					NULL, 0, 1000);
+		break;
+	case TEST_J_PID:
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_SET_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_TEST,
+					(TEST_J << 8) | portnum,
+					NULL, 0, 1000);
+		break;
+	case TEST_K_PID:
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_SET_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_TEST,
+					(TEST_K << 8) | portnum,
+					NULL, 0, 1000);
+		break;
+	case TEST_PACKET_PID:
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_SET_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_TEST,
+					(TEST_PACKET << 8) | portnum,
+					NULL, 0, 1000);
+		break;
+	case TEST_HS_HOST_PORT_SUSPEND_RESUME:
+		/* Test: wait for 15secs -> suspend -> 15secs delay -> resume */
+		msleep(15 * 1000);
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_SET_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_SUSPEND, portnum,
+					NULL, 0, 1000);
+		if (ret < 0)
+			break;
+
+		msleep(15 * 1000);
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_CLEAR_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_SUSPEND, portnum,
+					NULL, 0, 1000);
+		break;
+	case TEST_SINGLE_STEP_GET_DEV_DESC:
+		/* Test: wait for 15secs -> GetDescriptor request */
+		msleep(15 * 1000);
+		buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+		if (!buf)
+			return -ENOMEM;
+
+		ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+					USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+					USB_DT_DEVICE << 8, 0,
+					buf, USB_DT_DEVICE_SIZE,
+					USB_CTRL_GET_TIMEOUT);
+		kfree(buf);
+		break;
+	case TEST_SINGLE_STEP_SET_FEATURE:
+		/*
+		 * GetDescriptor SETUP request -> 15secs delay -> IN & STATUS
+		 *
+		 * Note, this test is only supported on root hubs since the
+		 * SetPortFeature handling can only be done inside the HCD's
+		 * hub_control callback function.
+		 */
+		if (hub_udev != dev->bus->root_hub) {
+			dev_err(&intf->dev, "SINGLE_STEP_SET_FEATURE test only supported on root hub\n");
+			break;
+		}
+
+		ret = usb_control_msg(hub_udev, usb_sndctrlpipe(hub_udev, 0),
+					USB_REQ_SET_FEATURE, USB_RT_PORT,
+					USB_PORT_FEAT_TEST,
+					(6 << 8) | portnum,
+					NULL, 0, 60 * 1000);
+
+		break;
+	default:
+		dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
+			__func__, test_pid);
+	}
+
+	return (ret < 0) ? ret : 0;
+}
+
+static void ehset_disconnect(struct usb_interface *intf)
+{
+}
+
+static const struct usb_device_id ehset_id_table[] = {
+	{ USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
+	{ USB_DEVICE(0x1a0a, TEST_J_PID) },
+	{ USB_DEVICE(0x1a0a, TEST_K_PID) },
+	{ USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
+	{ USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
+	{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
+	{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ehset_id_table);
+
+static struct usb_driver ehset_driver = {
+	.name =		"usb_ehset_test",
+	.probe =	ehset_probe,
+	.disconnect =	ehset_disconnect,
+	.id_table =	ehset_id_table,
+};
+
+module_usb_driver(ehset_driver);
+
+MODULE_DESCRIPTION("USB Driver for EHSET Test Fixture");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index ac76229..b1d5953 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -129,19 +129,6 @@
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("LD USB Devices");
 
-#ifdef CONFIG_USB_DEBUG
-	static int debug = 1;
-#else
-	static int debug = 0;
-#endif
-
-/* Use our own dbg macro */
-#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
-
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-
 /* All interrupt in transfers are collected in a ring buffer to
  * avoid racing conditions and get better performance of the driver.
  */
@@ -256,8 +243,9 @@
 		    status == -ESHUTDOWN) {
 			goto exit;
 		} else {
-			dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-				 __func__, status);
+			dev_dbg(&dev->intf->dev,
+				"%s: nonzero status received: %d\n", __func__,
+				status);
 			spin_lock(&dev->rbsl);
 			goto resubmit; /* maybe we can recover */
 		}
@@ -272,8 +260,8 @@
 			*actual_buffer = urb->actual_length;
 			memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length);
 			dev->ring_head = next_ring_head;
-			dbg_info(&dev->intf->dev, "%s: received %d bytes\n",
-				 __func__, urb->actual_length);
+			dev_dbg(&dev->intf->dev, "%s: received %d bytes\n",
+				__func__, urb->actual_length);
 		} else {
 			dev_warn(&dev->intf->dev,
 				 "Ring buffer overflow, %d bytes dropped\n",
@@ -310,9 +298,9 @@
 	if (status && !(status == -ENOENT ||
 			status == -ECONNRESET ||
 			status == -ESHUTDOWN))
-		dbg_info(&dev->intf->dev,
-			 "%s - nonzero write interrupt status received: %d\n",
-			 __func__, status);
+		dev_dbg(&dev->intf->dev,
+			"%s - nonzero write interrupt status received: %d\n",
+			__func__, status);
 
 	dev->interrupt_out_busy = 0;
 	wake_up_interruptible(&dev->write_wait);
@@ -585,7 +573,8 @@
 	bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
 	if (bytes_to_write < count)
 		dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
-	dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write);
+	dev_dbg(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n",
+		__func__, count, bytes_to_write);
 
 	if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
 		retval = -EFAULT;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 8089479..eb37c95 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -75,6 +75,8 @@
  *   - move reset into open to clean out spurious data
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -87,28 +89,11 @@
 #include <linux/poll.h>
 
 
-#ifdef CONFIG_USB_DEBUG
-	static int debug = 4;
-#else
-	static int debug = 0;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(lvl, format, arg...)					\
-do {									\
-	if (debug >= lvl)						\
-		printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg);	\
-} while (0)
-
 /* Version Information */
 #define DRIVER_VERSION "v0.96"
 #define DRIVER_AUTHOR "Juergen Stuber <starblue@sourceforge.net>"
 #define DRIVER_DESC "LEGO USB Tower Driver"
 
-/* Module parameters */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
 
 /* The defaults are chosen to work with the latest versions of leJOS and NQC.
  */
@@ -298,18 +283,12 @@
 /**
  *	lego_usb_tower_debug_data
  */
-static inline void lego_usb_tower_debug_data (int level, const char *function, int size, const unsigned char *data)
+static inline void lego_usb_tower_debug_data(struct device *dev,
+					     const char *function, int size,
+					     const unsigned char *data)
 {
-	int i;
-
-	if (debug < level)
-		return;
-
-	printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size);
-	for (i = 0; i < size; ++i) {
-		printk ("%.2x ", data[i]);
-	}
-	printk ("\n");
+	dev_dbg(dev, "%s - length = %d, data = %*ph\n",
+		function, size, size, data);
 }
 
 
@@ -318,8 +297,6 @@
  */
 static inline void tower_delete (struct lego_usb_tower *dev)
 {
-	dbg(2, "%s: enter", __func__);
-
 	tower_abort_transfers (dev);
 
 	/* free data structures */
@@ -329,8 +306,6 @@
 	kfree (dev->interrupt_in_buffer);
 	kfree (dev->interrupt_out_buffer);
 	kfree (dev);
-
-	dbg(2, "%s: leave", __func__);
 }
 
 
@@ -346,16 +321,13 @@
 	struct tower_reset_reply reset_reply;
 	int result;
 
-	dbg(2, "%s: enter", __func__);
-
 	nonseekable_open(inode, file);
 	subminor = iminor(inode);
 
 	interface = usb_find_interface (&tower_driver, subminor);
 
 	if (!interface) {
-		printk(KERN_ERR "%s - error, can't find device for minor %d\n",
-		       __func__, subminor);
+		pr_err("error, can't find device for minor %d\n", subminor);
 		retval = -ENODEV;
 		goto exit;
 	}
@@ -435,8 +407,6 @@
 	mutex_unlock(&dev->lock);
 
 exit:
-	dbg(2, "%s: leave, return value %d ", __func__, retval);
-
 	return retval;
 }
 
@@ -448,12 +418,9 @@
 	struct lego_usb_tower *dev;
 	int retval = 0;
 
-	dbg(2, "%s: enter", __func__);
-
 	dev = file->private_data;
 
 	if (dev == NULL) {
-		dbg(1, "%s: object is NULL", __func__);
 		retval = -ENODEV;
 		goto exit_nolock;
 	}
@@ -465,7 +432,8 @@
 	}
 
 	if (dev->open_count != 1) {
-		dbg(1, "%s: device not opened exactly once", __func__);
+		dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n",
+			__func__);
 		retval = -ENODEV;
 		goto unlock_exit;
 	}
@@ -491,7 +459,6 @@
 exit:
 	mutex_unlock(&open_disc_mutex);
 exit_nolock:
-	dbg(2, "%s: leave, return value %d", __func__, retval);
 	return retval;
 }
 
@@ -502,12 +469,8 @@
  */
 static void tower_abort_transfers (struct lego_usb_tower *dev)
 {
-	dbg(2, "%s: enter", __func__);
-
-	if (dev == NULL) {
-		dbg(1, "%s: dev is null", __func__);
-		goto exit;
-	}
+	if (dev == NULL)
+		return;
 
 	/* shutdown transfer */
 	if (dev->interrupt_in_running) {
@@ -518,9 +481,6 @@
 	}
 	if (dev->interrupt_out_busy && dev->udev)
 		usb_kill_urb(dev->interrupt_out_urb);
-
-exit:
-	dbg(2, "%s: leave", __func__);
 }
 
 
@@ -553,8 +513,6 @@
 	struct lego_usb_tower *dev;
 	unsigned int mask = 0;
 
-	dbg(2, "%s: enter", __func__);
-
 	dev = file->private_data;
 
 	if (!dev->udev)
@@ -571,8 +529,6 @@
 		mask |= POLLOUT | POLLWRNORM;
 	}
 
-	dbg(2, "%s: leave, mask = %d", __func__, mask);
-
 	return mask;
 }
 
@@ -597,8 +553,6 @@
 	int retval = 0;
 	unsigned long timeout = 0;
 
-	dbg(2, "%s: enter, count = %Zd", __func__, count);
-
 	dev = file->private_data;
 
 	/* lock this object */
@@ -610,13 +564,13 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL) {
 		retval = -ENODEV;
-		printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
+		pr_err("No device or device unplugged %d\n", retval);
 		goto unlock_exit;
 	}
 
 	/* verify that we actually have some data to read */
 	if (count == 0) {
-		dbg(1, "%s: read request of 0 bytes", __func__);
+		dev_dbg(&dev->udev->dev, "read request of 0 bytes\n");
 		goto unlock_exit;
 	}
 
@@ -672,7 +626,6 @@
 	mutex_unlock(&dev->lock);
 
 exit:
-	dbg(2, "%s: leave, return value %d", __func__, retval);
 	return retval;
 }
 
@@ -686,8 +639,6 @@
 	size_t bytes_to_write;
 	int retval = 0;
 
-	dbg(2, "%s: enter, count = %Zd", __func__, count);
-
 	dev = file->private_data;
 
 	/* lock this object */
@@ -699,13 +650,13 @@
 	/* verify that the device wasn't unplugged */
 	if (dev->udev == NULL) {
 		retval = -ENODEV;
-		printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
+		pr_err("No device or device unplugged %d\n", retval);
 		goto unlock_exit;
 	}
 
 	/* verify that we actually have some data to write */
 	if (count == 0) {
-		dbg(1, "%s: write request of 0 bytes", __func__);
+		dev_dbg(&dev->udev->dev, "write request of 0 bytes\n");
 		goto unlock_exit;
 	}
 
@@ -723,7 +674,8 @@
 
 	/* write the data into interrupt_out_buffer from userspace */
 	bytes_to_write = min_t(int, count, write_buffer_size);
-	dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __func__, count, bytes_to_write);
+	dev_dbg(&dev->udev->dev, "%s: count = %Zd, bytes_to_write = %Zd\n",
+		__func__, count, bytes_to_write);
 
 	if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
 		retval = -EFAULT;
@@ -757,8 +709,6 @@
 	mutex_unlock(&dev->lock);
 
 exit:
-	dbg(2, "%s: leave, return value %d", __func__, retval);
-
 	return retval;
 }
 
@@ -772,9 +722,8 @@
 	int status = urb->status;
 	int retval;
 
-	dbg(4, "%s: enter, status %d", __func__, status);
-
-	lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+	lego_usb_tower_debug_data(&dev->udev->dev, __func__,
+				  urb->actual_length, urb->transfer_buffer);
 
 	if (status) {
 		if (status == -ENOENT ||
@@ -782,7 +731,9 @@
 		    status == -ESHUTDOWN) {
 			goto exit;
 		} else {
-			dbg(1, "%s: nonzero status received: %d", __func__, status);
+			dev_dbg(&dev->udev->dev,
+				"%s: nonzero status received: %d\n", __func__,
+				status);
 			goto resubmit; /* maybe we can recover */
 		}
 	}
@@ -795,9 +746,11 @@
 				urb->actual_length);
 			dev->read_buffer_length += urb->actual_length;
 			dev->read_last_arrival = jiffies;
-			dbg(3, "%s: received %d bytes", __func__, urb->actual_length);
+			dev_dbg(&dev->udev->dev, "%s: received %d bytes\n",
+				__func__, urb->actual_length);
 		} else {
-			printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length);
+			pr_warn("read_buffer overflow, %d bytes dropped\n",
+				urb->actual_length);
 		}
 		spin_unlock (&dev->read_buffer_lock);
 	}
@@ -815,9 +768,6 @@
 exit:
 	dev->interrupt_in_done = 1;
 	wake_up_interruptible (&dev->read_wait);
-
-	lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
-	dbg(4, "%s: leave, status %d", __func__, status);
 }
 
 
@@ -829,22 +779,20 @@
 	struct lego_usb_tower *dev = urb->context;
 	int status = urb->status;
 
-	dbg(4, "%s: enter, status %d", __func__, status);
-	lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
+	lego_usb_tower_debug_data(&dev->udev->dev, __func__,
+				  urb->actual_length, urb->transfer_buffer);
 
 	/* sync/async unlink faults aren't errors */
 	if (status && !(status == -ENOENT ||
 			status == -ECONNRESET ||
 			status == -ESHUTDOWN)) {
-		dbg(1, "%s - nonzero write bulk status received: %d",
-		    __func__, status);
+		dev_dbg(&dev->udev->dev,
+			"%s: nonzero write bulk status received: %d\n", __func__,
+			status);
 	}
 
 	dev->interrupt_out_busy = 0;
 	wake_up_interruptible(&dev->write_wait);
-
-	lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
-	dbg(4, "%s: leave, status %d", __func__, status);
 }
 
 
@@ -866,8 +814,6 @@
 	int retval = -ENOMEM;
 	int result;
 
-	dbg(2, "%s: enter", __func__);
-
 	/* allocate memory for our device state and initialize it */
 
 	dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
@@ -993,8 +939,6 @@
 
 
 exit:
-	dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev);
-
 	return retval;
 
 error:
@@ -1013,8 +957,6 @@
 	struct lego_usb_tower *dev;
 	int minor;
 
-	dbg(2, "%s: enter", __func__);
-
 	dev = usb_get_intfdata (interface);
 	mutex_lock(&open_disc_mutex);
 	usb_set_intfdata (interface, NULL);
@@ -1041,8 +983,6 @@
 
 	dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
 		 (minor - LEGO_USB_TOWER_MINOR_BASE));
-
-	dbg(2, "%s: leave", __func__);
 }
 
 module_usb_driver(tower_driver);
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index c357839..a31641e 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -26,6 +26,7 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/usb3503.h>
+#include <linux/regmap.h>
 
 #define USB3503_VIDL		0x00
 #define USB3503_VIDM		0x01
@@ -50,60 +51,25 @@
 #define USB3503_CFGP		0xee
 #define USB3503_CLKSUSP		(1 << 7)
 
+#define USB3503_RESET		0xff
+
 struct usb3503 {
 	enum usb3503_mode	mode;
-	struct i2c_client	*client;
+	struct regmap		*regmap;
+	struct device		*dev;
 	u8	port_off_mask;
 	int	gpio_intn;
 	int	gpio_reset;
 	int	gpio_connect;
 };
 
-static int usb3503_write_register(struct i2c_client *client,
-		char reg, char data)
+static int usb3503_reset(struct usb3503 *hub, int state)
 {
-	return i2c_smbus_write_byte_data(client, reg, data);
-}
+	if (!state && gpio_is_valid(hub->gpio_connect))
+		gpio_set_value_cansleep(hub->gpio_connect, 0);
 
-static int usb3503_read_register(struct i2c_client *client, char reg)
-{
-	return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int usb3503_set_bits(struct i2c_client *client, char reg, char req)
-{
-	int err;
-
-	err = usb3503_read_register(client, reg);
-	if (err < 0)
-		return err;
-
-	err = usb3503_write_register(client, reg, err | req);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-static int usb3503_clear_bits(struct i2c_client *client, char reg, char req)
-{
-	int err;
-
-	err = usb3503_read_register(client, reg);
-	if (err < 0)
-		return err;
-
-	err = usb3503_write_register(client, reg, err & ~req);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-static int usb3503_reset(int gpio_reset, int state)
-{
-	if (gpio_is_valid(gpio_reset))
-		gpio_set_value(gpio_reset, state);
+	if (gpio_is_valid(hub->gpio_reset))
+		gpio_set_value_cansleep(hub->gpio_reset, state);
 
 	/* Wait T_HUBINIT == 4ms for hub logic to stabilize */
 	if (state)
@@ -112,90 +78,105 @@
 	return 0;
 }
 
-static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
+static int usb3503_connect(struct usb3503 *hub)
 {
-	struct i2c_client *i2c = hub->client;
-	int err = 0;
+	struct device *dev = hub->dev;
+	int err;
 
-	switch (mode) {
-	case USB3503_MODE_HUB:
-		usb3503_reset(hub->gpio_reset, 1);
+	usb3503_reset(hub, 1);
 
+	if (hub->regmap) {
 		/* SP_ILOCK: set connect_n, config_n for config */
-		err = usb3503_write_register(i2c, USB3503_SP_ILOCK,
-				(USB3503_SPILOCK_CONNECT
+		err = regmap_write(hub->regmap, USB3503_SP_ILOCK,
+			   (USB3503_SPILOCK_CONNECT
 				 | USB3503_SPILOCK_CONFIG));
 		if (err < 0) {
-			dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err);
-			goto err_hubmode;
+			dev_err(dev, "SP_ILOCK failed (%d)\n", err);
+			return err;
 		}
 
 		/* PDS : Disable For Self Powered Operation */
 		if (hub->port_off_mask) {
-			err = usb3503_set_bits(i2c, USB3503_PDS,
+			err = regmap_update_bits(hub->regmap, USB3503_PDS,
+					hub->port_off_mask,
 					hub->port_off_mask);
 			if (err < 0) {
-				dev_err(&i2c->dev, "PDS failed (%d)\n", err);
-				goto err_hubmode;
+				dev_err(dev, "PDS failed (%d)\n", err);
+				return err;
 			}
 		}
 
 		/* CFG1 : SELF_BUS_PWR -> Self-Powerd operation */
-		err = usb3503_set_bits(i2c, USB3503_CFG1, USB3503_SELF_BUS_PWR);
+		err = regmap_update_bits(hub->regmap, USB3503_CFG1,
+					 USB3503_SELF_BUS_PWR,
+					 USB3503_SELF_BUS_PWR);
 		if (err < 0) {
-			dev_err(&i2c->dev, "CFG1 failed (%d)\n", err);
-			goto err_hubmode;
+			dev_err(dev, "CFG1 failed (%d)\n", err);
+			return err;
 		}
 
 		/* SP_LOCK: clear connect_n, config_n for hub connect */
-		err = usb3503_clear_bits(i2c, USB3503_SP_ILOCK,
-				(USB3503_SPILOCK_CONNECT
-				 | USB3503_SPILOCK_CONFIG));
+		err = regmap_update_bits(hub->regmap, USB3503_SP_ILOCK,
+					 (USB3503_SPILOCK_CONNECT
+					  | USB3503_SPILOCK_CONFIG), 0);
 		if (err < 0) {
-			dev_err(&i2c->dev, "SP_ILOCK failed (%d)\n", err);
-			goto err_hubmode;
+			dev_err(dev, "SP_ILOCK failed (%d)\n", err);
+			return err;
 		}
+	}
 
-		hub->mode = mode;
-		dev_info(&i2c->dev, "switched to HUB mode\n");
+	if (gpio_is_valid(hub->gpio_connect))
+		gpio_set_value_cansleep(hub->gpio_connect, 1);
+
+	hub->mode = USB3503_MODE_HUB;
+	dev_info(dev, "switched to HUB mode\n");
+
+	return 0;
+}
+
+static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode)
+{
+	struct device *dev = hub->dev;
+	int err = 0;
+
+	switch (mode) {
+	case USB3503_MODE_HUB:
+		err = usb3503_connect(hub);
 		break;
 
 	case USB3503_MODE_STANDBY:
-		usb3503_reset(hub->gpio_reset, 0);
+		usb3503_reset(hub, 0);
 
 		hub->mode = mode;
-		dev_info(&i2c->dev, "switched to STANDBY mode\n");
+		dev_info(dev, "switched to STANDBY mode\n");
 		break;
 
 	default:
-		dev_err(&i2c->dev, "unknown mode is request\n");
+		dev_err(dev, "unknown mode is requested\n");
 		err = -EINVAL;
 		break;
 	}
 
-err_hubmode:
 	return err;
 }
 
-static int usb3503_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+static const struct regmap_config usb3503_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = USB3503_RESET,
+};
+
+static int usb3503_probe(struct usb3503 *hub)
 {
-	struct usb3503_platform_data *pdata = i2c->dev.platform_data;
-	struct device_node *np = i2c->dev.of_node;
-	struct usb3503 *hub;
-	int err = -ENOMEM;
-	u32 mode = USB3503_MODE_UNKNOWN;
+	struct device *dev = hub->dev;
+	struct usb3503_platform_data *pdata = dev_get_platdata(dev);
+	struct device_node *np = dev->of_node;
+	int err;
+	u32 mode = USB3503_MODE_HUB;
 	const u32 *property;
 	int len;
 
-	hub = kzalloc(sizeof(struct usb3503), GFP_KERNEL);
-	if (!hub) {
-		dev_err(&i2c->dev, "private data alloc fail\n");
-		return err;
-	}
-
-	i2c_set_clientdata(i2c, hub);
-	hub->client = i2c;
-
 	if (pdata) {
 		hub->port_off_mask	= pdata->port_off_mask;
 		hub->gpio_intn		= pdata->gpio_intn;
@@ -215,10 +196,10 @@
 			}
 		}
 
-		hub->gpio_intn	= of_get_named_gpio(np, "connect-gpios", 0);
+		hub->gpio_intn	= of_get_named_gpio(np, "intn-gpios", 0);
 		if (hub->gpio_intn == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
-		hub->gpio_connect = of_get_named_gpio(np, "intn-gpios", 0);
+		hub->gpio_connect = of_get_named_gpio(np, "connect-gpios", 0);
 		if (hub->gpio_connect == -EPROBE_DEFER)
 			return -EPROBE_DEFER;
 		hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0);
@@ -228,72 +209,86 @@
 		hub->mode = mode;
 	}
 
+	if (hub->port_off_mask && !hub->regmap)
+		dev_err(dev, "Ports disabled with no control interface\n");
+
 	if (gpio_is_valid(hub->gpio_intn)) {
-		err = gpio_request_one(hub->gpio_intn,
+		err = devm_gpio_request_one(dev, hub->gpio_intn,
 				GPIOF_OUT_INIT_HIGH, "usb3503 intn");
 		if (err) {
-			dev_err(&i2c->dev,
-					"unable to request GPIO %d as connect pin (%d)\n",
-					hub->gpio_intn, err);
-			goto err_out;
+			dev_err(dev,
+				"unable to request GPIO %d as connect pin (%d)\n",
+				hub->gpio_intn, err);
+			return err;
 		}
 	}
 
 	if (gpio_is_valid(hub->gpio_connect)) {
-		err = gpio_request_one(hub->gpio_connect,
-				GPIOF_OUT_INIT_HIGH, "usb3503 connect");
+		err = devm_gpio_request_one(dev, hub->gpio_connect,
+				GPIOF_OUT_INIT_LOW, "usb3503 connect");
 		if (err) {
-			dev_err(&i2c->dev,
-					"unable to request GPIO %d as connect pin (%d)\n",
-					hub->gpio_connect, err);
-			goto err_gpio_connect;
+			dev_err(dev,
+				"unable to request GPIO %d as connect pin (%d)\n",
+				hub->gpio_connect, err);
+			return err;
 		}
 	}
 
 	if (gpio_is_valid(hub->gpio_reset)) {
-		err = gpio_request_one(hub->gpio_reset,
+		err = devm_gpio_request_one(dev, hub->gpio_reset,
 				GPIOF_OUT_INIT_LOW, "usb3503 reset");
 		if (err) {
-			dev_err(&i2c->dev,
-					"unable to request GPIO %d as reset pin (%d)\n",
-					hub->gpio_reset, err);
-			goto err_gpio_reset;
+			dev_err(dev,
+				"unable to request GPIO %d as reset pin (%d)\n",
+				hub->gpio_reset, err);
+			return err;
 		}
 	}
 
 	usb3503_switch_mode(hub, hub->mode);
 
-	dev_info(&i2c->dev, "%s: probed on  %s mode\n", __func__,
+	dev_info(dev, "%s: probed in %s mode\n", __func__,
 			(hub->mode == USB3503_MODE_HUB) ? "hub" : "standby");
 
 	return 0;
-
-err_gpio_reset:
-	if (gpio_is_valid(hub->gpio_connect))
-		gpio_free(hub->gpio_connect);
-err_gpio_connect:
-	if (gpio_is_valid(hub->gpio_intn))
-		gpio_free(hub->gpio_intn);
-err_out:
-	kfree(hub);
-
-	return err;
 }
 
-static int usb3503_remove(struct i2c_client *i2c)
+static int usb3503_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
 {
-	struct usb3503 *hub = i2c_get_clientdata(i2c);
+	struct usb3503 *hub;
+	int err;
 
-	if (gpio_is_valid(hub->gpio_intn))
-		gpio_free(hub->gpio_intn);
-	if (gpio_is_valid(hub->gpio_connect))
-		gpio_free(hub->gpio_connect);
-	if (gpio_is_valid(hub->gpio_reset))
-		gpio_free(hub->gpio_reset);
+	hub = devm_kzalloc(&i2c->dev, sizeof(struct usb3503), GFP_KERNEL);
+	if (!hub) {
+		dev_err(&i2c->dev, "private data alloc fail\n");
+		return -ENOMEM;
+	}
 
-	kfree(hub);
+	i2c_set_clientdata(i2c, hub);
+	hub->regmap = devm_regmap_init_i2c(i2c, &usb3503_regmap_config);
+	if (IS_ERR(hub->regmap)) {
+		err = PTR_ERR(hub->regmap);
+		dev_err(&i2c->dev, "Failed to initialise regmap: %d\n", err);
+		return err;
+	}
+	hub->dev = &i2c->dev;
 
-	return 0;
+	return usb3503_probe(hub);
+}
+
+static int usb3503_platform_probe(struct platform_device *pdev)
+{
+	struct usb3503 *hub;
+
+	hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL);
+	if (!hub) {
+		dev_err(&pdev->dev, "private data alloc fail\n");
+		return -ENOMEM;
+	}
+	hub->dev = &pdev->dev;
+
+	return usb3503_probe(hub);
 }
 
 static const struct i2c_device_id usb3503_id[] = {
@@ -305,22 +300,53 @@
 #ifdef CONFIG_OF
 static const struct of_device_id usb3503_of_match[] = {
 	{ .compatible = "smsc,usb3503", },
+	{ .compatible = "smsc,usb3503a", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, usb3503_of_match);
 #endif
 
-static struct i2c_driver usb3503_driver = {
+static struct i2c_driver usb3503_i2c_driver = {
 	.driver = {
 		.name = USB3503_I2C_NAME,
 		.of_match_table = of_match_ptr(usb3503_of_match),
 	},
-	.probe		= usb3503_probe,
-	.remove		= usb3503_remove,
+	.probe		= usb3503_i2c_probe,
 	.id_table	= usb3503_id,
 };
 
-module_i2c_driver(usb3503_driver);
+static struct platform_driver usb3503_platform_driver = {
+	.driver = {
+		.name = USB3503_I2C_NAME,
+		.of_match_table = of_match_ptr(usb3503_of_match),
+		.owner = THIS_MODULE,
+	},
+	.probe		= usb3503_platform_probe,
+};
+
+static int __init usb3503_init(void)
+{
+	int err;
+
+	err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver);
+	if (err != 0)
+		pr_err("usb3503: Failed to register I2C driver: %d\n", err);
+
+	err = platform_driver_register(&usb3503_platform_driver);
+	if (err != 0)
+		pr_err("usb3503: Failed to register platform driver: %d\n",
+		       err);
+
+	return 0;
+}
+module_init(usb3503_init);
+
+static void __exit usb3503_exit(void)
+{
+	platform_driver_unregister(&usb3503_platform_driver);
+	i2c_del_driver(&usb3503_i2c_driver);
+}
+module_exit(usb3503_exit);
 
 MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");
 MODULE_DESCRIPTION("USB3503 USB HUB driver");
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 8b4ca1c..aa28ac8 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -747,9 +747,9 @@
 
 	/* [9.4.5] get_status always works */
 	retval = usb_get_status(udev, USB_RECIP_DEVICE, 0, dev->buf);
-	if (retval != 2) {
+	if (retval) {
 		dev_err(&iface->dev, "get dev status --> %d\n", retval);
-		return (retval < 0) ? retval : -EDOM;
+		return retval;
 	}
 
 	/* FIXME configuration.bmAttributes says if we could try to set/clear
@@ -758,9 +758,9 @@
 
 	retval = usb_get_status(udev, USB_RECIP_INTERFACE,
 			iface->altsetting[0].desc.bInterfaceNumber, dev->buf);
-	if (retval != 2) {
+	if (retval) {
 		dev_err(&iface->dev, "get interface status --> %d\n", retval);
-		return (retval < 0) ? retval : -EDOM;
+		return retval;
 	}
 	/* FIXME get status for each endpoint in the interface */
 
@@ -1351,7 +1351,6 @@
 				ep, retval);
 		return retval;
 	}
-	le16_to_cpus(&status);
 	if (status != 1) {
 		ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
 		return -EINVAL;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index e129cf6..40ef40a 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -75,7 +75,7 @@
 	struct list_head asynclist;
 	struct completion compl;
 	struct urb *urb;
-	struct usb_ctrlrequest dr;
+	struct usb_ctrlrequest *dr;
 	__u8 reg[7];
 };
 
@@ -98,6 +98,7 @@
 
 	if (likely(rq->urb))
 		usb_free_urb(rq->urb);
+	kfree(rq->dr);
 	spin_lock_irqsave(&priv->asynclock, flags);
 	list_del_init(&rq->asynclist);
 	spin_unlock_irqrestore(&priv->asynclock, flags);
@@ -120,7 +121,7 @@
 	if (status) {
 		dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
 			status);
-	} else if (rq->dr.bRequest == 3) {
+	} else if (rq->dr->bRequest == 3) {
 		memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
 		dev_dbg(&priv->usbdev->dev,
@@ -152,7 +153,7 @@
 	usbdev = priv->usbdev;
 	if (!usbdev)
 		return NULL;
-	rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
+	rq = kzalloc(sizeof(struct uss720_async_request), mem_flags);
 	if (!rq) {
 		dev_err(&usbdev->dev, "submit_async_request out of memory\n");
 		return NULL;
@@ -168,13 +169,18 @@
 		dev_err(&usbdev->dev, "submit_async_request out of memory\n");
 		return NULL;
 	}
-	rq->dr.bRequestType = requesttype;
-	rq->dr.bRequest = request;
-	rq->dr.wValue = cpu_to_le16(value);
-	rq->dr.wIndex = cpu_to_le16(index);
-	rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
+	rq->dr = kmalloc(sizeof(*rq->dr), mem_flags);
+	if (!rq->dr) {
+		kref_put(&rq->ref_count, destroy_async);
+		return NULL;
+	}
+	rq->dr->bRequestType = requesttype;
+	rq->dr->bRequest = request;
+	rq->dr->wValue = cpu_to_le16(value);
+	rq->dr->wIndex = cpu_to_le16(index);
+	rq->dr->wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
 	usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
-			     (unsigned char *)&rq->dr,
+			     (unsigned char *)rq->dr,
 			     (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
 	/* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
 	spin_lock_irqsave(&priv->asynclock, flags);
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 797e3fd..c64ee09a7 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -83,6 +83,8 @@
 
 config USB_MUSB_DSPS
 	tristate "TI DSPS platforms"
+	select USB_MUSB_AM335X_CHILD
+	depends on OF_IRQ
 
 config USB_MUSB_BLACKFIN
 	tristate "Blackfin"
@@ -93,6 +95,9 @@
 
 endchoice
 
+config USB_MUSB_AM335X_CHILD
+	tristate
+
 choice
 	prompt 'MUSB DMA mode'
 	default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
@@ -125,6 +130,10 @@
 	help
 	  Enable DMA transfers when TI CPPI DMA is available.
 
+config USB_TI_CPPI41_DMA
+	bool 'TI CPPI 4.1 (AM335x)'
+	depends on ARCH_OMAP
+
 config USB_TUSB_OMAP_DMA
 	bool 'TUSB 6010'
 	depends on USB_MUSB_TUSB6010
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 2b82ed7..c5ea5c6 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -20,6 +20,9 @@
 obj-$(CONFIG_USB_MUSB_BLACKFIN)			+= blackfin.o
 obj-$(CONFIG_USB_MUSB_UX500)			+= ux500.o
 
+
+obj-$(CONFIG_USB_MUSB_AM335X_CHILD)		+= musb_am335x.o
+
 # the kconfig must guarantee that only one of the
 # possible I/O schemes will be enabled at a time ...
 # PIO only, or DMA (several potential schemes).
@@ -29,3 +32,4 @@
 musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA)		+= cppi_dma.o
 musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA)		+= tusb6010_omap.o
 musb_hdrc-$(CONFIG_USB_UX500_DMA)		+= ux500_dma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA)		+= musb_cppi41.o
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 2231850..5c310c6 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -33,7 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/platform_data/usb-omap.h>
 
 #include "musb_core.h"
@@ -218,7 +218,7 @@
 	struct musb  *musb = hci;
 	void __iomem *reg_base = musb->ctrl_base;
 	struct device *dev = musb->controller;
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 	struct usb_otg *otg = musb->xceiv->otg;
 	unsigned long flags;
@@ -335,7 +335,7 @@
 static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
 {
 	struct device *dev = musb->controller;
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 	int     retval = 0;
 
@@ -350,7 +350,7 @@
 static int am35x_musb_init(struct musb *musb)
 {
 	struct device *dev = musb->controller;
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 	void __iomem *reg_base = musb->ctrl_base;
 	u32 rev;
@@ -394,7 +394,7 @@
 static int am35x_musb_exit(struct musb *musb)
 {
 	struct device *dev = musb->controller;
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 
 	del_timer_sync(&otg_workaround);
@@ -456,7 +456,7 @@
 
 static int am35x_probe(struct platform_device *pdev)
 {
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct platform_device		*musb;
 	struct am35x_glue		*glue;
 
@@ -577,7 +577,7 @@
 static int am35x_suspend(struct device *dev)
 {
 	struct am35x_glue	*glue = dev_get_drvdata(dev);
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 
 	/* Shutdown the on-chip PHY and its PLL. */
@@ -593,7 +593,7 @@
 static int am35x_resume(struct device *dev)
 {
 	struct am35x_glue	*glue = dev_get_drvdata(dev);
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 	int			ret;
 
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 6ba8439..72e2056 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -19,7 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/prefetch.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <asm/cacheflush.h>
 
@@ -451,7 +451,7 @@
 static int bfin_probe(struct platform_device *pdev)
 {
 	struct resource musb_resources[2];
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct platform_device		*musb;
 	struct bfin_glue		*glue;
 
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 9db211e..904fb85 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -150,14 +150,11 @@
 	c->last_processed = NULL;
 }
 
-static int cppi_controller_start(struct dma_controller *c)
+static void cppi_controller_start(struct cppi *controller)
 {
-	struct cppi	*controller;
 	void __iomem	*tibase;
 	int		i;
 
-	controller = container_of(c, struct cppi, controller);
-
 	/* do whatever is necessary to start controller */
 	for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
 		controller->tx[i].transmit = true;
@@ -212,8 +209,6 @@
 	/* disable RNDIS mode, also host rx RNDIS autorequest */
 	musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
 	musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
-
-	return 0;
 }
 
 /*
@@ -222,14 +217,12 @@
  *  De-Init the DMA controller as necessary.
  */
 
-static int cppi_controller_stop(struct dma_controller *c)
+static void cppi_controller_stop(struct cppi *controller)
 {
-	struct cppi		*controller;
 	void __iomem		*tibase;
 	int			i;
 	struct musb		*musb;
 
-	controller = container_of(c, struct cppi, controller);
 	musb = controller->musb;
 
 	tibase = controller->tibase;
@@ -255,8 +248,6 @@
 	/*disable tx/rx cppi */
 	musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
 	musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
-
-	return 0;
 }
 
 /* While dma channel is allocated, we only want the core irqs active
@@ -1321,8 +1312,6 @@
 	controller->tibase = mregs - DAVINCI_BASE_OFFSET;
 
 	controller->musb = musb;
-	controller->controller.start = cppi_controller_start;
-	controller->controller.stop = cppi_controller_stop;
 	controller->controller.channel_alloc = cppi_channel_allocate;
 	controller->controller.channel_release = cppi_channel_release;
 	controller->controller.channel_program = cppi_channel_program;
@@ -1351,6 +1340,7 @@
 		controller->irq = irq;
 	}
 
+	cppi_controller_start(controller);
 	return &controller->controller;
 }
 
@@ -1363,6 +1353,8 @@
 
 	cppi = container_of(c, struct cppi, controller);
 
+	cppi_controller_stop(cppi);
+
 	if (cppi->irq)
 		free_irq(cppi->irq, cppi->musb);
 
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 0da6f64..d9ddf41 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -33,7 +33,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <mach/da8xx.h>
 #include <linux/platform_data/usb-davinci.h>
@@ -477,7 +477,7 @@
 static int da8xx_probe(struct platform_device *pdev)
 {
 	struct resource musb_resources[2];
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct platform_device		*musb;
 	struct da8xx_glue		*glue;
 
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index f8aeaf2..ed0834e 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -33,7 +33,7 @@
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include <mach/cputype.h>
 #include <mach/hardware.h>
@@ -510,7 +510,7 @@
 static int davinci_probe(struct platform_device *pdev)
 {
 	struct resource musb_resources[2];
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct platform_device		*musb;
 	struct davinci_glue		*glue;
 	struct clk			*clk;
diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c
new file mode 100644
index 0000000..41ac5b5
--- /dev/null
+++ b/drivers/usb/musb/musb_am335x.c
@@ -0,0 +1,55 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+static int am335x_child_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pm_runtime_enable(&pdev->dev);
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	pm_runtime_disable(&pdev->dev);
+	return ret;
+}
+
+static int of_remove_populated_child(struct device *dev, void *d)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	of_device_unregister(pdev);
+	return 0;
+}
+
+static int am335x_child_remove(struct platform_device *pdev)
+{
+	device_for_each_child(&pdev->dev, NULL, of_remove_populated_child);
+	pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id am335x_child_of_match[] = {
+	{ .compatible = "ti,am33xx-usb" },
+	{  },
+};
+MODULE_DEVICE_TABLE(of, am335x_child_of_match);
+
+static struct platform_driver am335x_child_driver = {
+	.probe		= am335x_child_probe,
+	.remove         = am335x_child_remove,
+	.driver         = {
+		.name   = "am335x-usb-childs",
+		.of_match_table	= of_match_ptr(am335x_child_of_match),
+	},
+};
+
+module_platform_driver(am335x_child_driver);
+MODULE_DESCRIPTION("AM33xx child devices");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 29a24ce..18e877f 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -99,7 +99,6 @@
 #include <linux/prefetch.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/idr.h>
 #include <linux/dma-mapping.h>
 
 #include "musb_core.h"
@@ -1764,12 +1763,8 @@
 			disable_irq_wake(musb->nIrq);
 		free_irq(musb->nIrq, musb);
 	}
-	if (is_dma_capable() && musb->dma_controller) {
-		struct dma_controller	*c = musb->dma_controller;
-
-		(void) c->stop(c);
-		dma_controller_destroy(c);
-	}
+	if (musb->dma_controller)
+		dma_controller_destroy(musb->dma_controller);
 
 	musb_host_free(musb);
 }
@@ -1787,7 +1782,7 @@
 {
 	int			status;
 	struct musb		*musb;
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 
 	/* The driver might handle more features than the board; OK.
 	 * Fail when the board needs a feature that's not enabled.
@@ -1844,19 +1839,8 @@
 
 	pm_runtime_get_sync(musb->controller);
 
-#ifndef CONFIG_MUSB_PIO_ONLY
-	if (use_dma && dev->dma_mask) {
-		struct dma_controller	*c;
-
-		c = dma_controller_create(musb, musb->mregs);
-		musb->dma_controller = c;
-		if (c)
-			(void) c->start(c);
-	}
-#endif
-	/* ideally this would be abstracted in platform setup */
-	if (!is_dma_capable() || !musb->dma_controller)
-		dev->dma_mask = NULL;
+	if (use_dma && dev->dma_mask)
+		musb->dma_controller = dma_controller_create(musb, musb->mregs);
 
 	/* be sure interrupts are disabled before connecting ISR */
 	musb_platform_disable(musb);
@@ -1944,6 +1928,8 @@
 	musb_gadget_cleanup(musb);
 
 fail3:
+	if (musb->dma_controller)
+		dma_controller_destroy(musb->dma_controller);
 	pm_runtime_put_sync(musb->controller);
 
 fail2:
@@ -2002,9 +1988,6 @@
 
 	musb_free(musb);
 	device_init_wakeup(dev, 0);
-#ifndef CONFIG_MUSB_PIO_ONLY
-	dma_set_mask(dev, *dev->parent->dma_mask);
-#endif
 	return 0;
 }
 
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 7d341c3..65f3917 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -83,11 +83,6 @@
 	MUSB_PORT_MODE_DUAL_ROLE,
 };
 
-#ifdef CONFIG_PROC_FS
-#include <linux/fs.h>
-#define MUSB_CONFIG_PROC_FS
-#endif
-
 /****************************** CONSTANTS ********************************/
 
 #ifndef MUSB_C_NUM_EPS
@@ -425,9 +420,6 @@
 
 	struct musb_hdrc_config	*config;
 
-#ifdef MUSB_CONFIG_PROC_FS
-	struct proc_dir_entry *proc_entry;
-#endif
 	int			xceiv_old_state;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry		*debugfs_root;
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
new file mode 100644
index 0000000..ae95974
--- /dev/null
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -0,0 +1,557 @@
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sizes.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include "musb_core.h"
+
+#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
+
+#define EP_MODE_AUTOREG_NONE		0
+#define EP_MODE_AUTOREG_ALL_NEOP	1
+#define EP_MODE_AUTOREG_ALWAYS		3
+
+#define EP_MODE_DMA_TRANSPARENT		0
+#define EP_MODE_DMA_RNDIS		1
+#define EP_MODE_DMA_GEN_RNDIS		3
+
+#define USB_CTRL_TX_MODE	0x70
+#define USB_CTRL_RX_MODE	0x74
+#define USB_CTRL_AUTOREQ	0xd0
+#define USB_TDOWN		0xd8
+
+struct cppi41_dma_channel {
+	struct dma_channel channel;
+	struct cppi41_dma_controller *controller;
+	struct musb_hw_ep *hw_ep;
+	struct dma_chan *dc;
+	dma_cookie_t cookie;
+	u8 port_num;
+	u8 is_tx;
+	u8 is_allocated;
+	u8 usb_toggle;
+
+	dma_addr_t buf_addr;
+	u32 total_len;
+	u32 prog_len;
+	u32 transferred;
+	u32 packet_sz;
+};
+
+#define MUSB_DMA_NUM_CHANNELS 15
+
+struct cppi41_dma_controller {
+	struct dma_controller controller;
+	struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];
+	struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];
+	struct musb *musb;
+	u32 rx_mode;
+	u32 tx_mode;
+	u32 auto_req;
+};
+
+static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+	u16 csr;
+	u8 toggle;
+
+	if (cppi41_channel->is_tx)
+		return;
+	if (!is_host_active(cppi41_channel->controller->musb))
+		return;
+
+	csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+	toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+	cppi41_channel->usb_toggle = toggle;
+}
+
+static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+	u16 csr;
+	u8 toggle;
+
+	if (cppi41_channel->is_tx)
+		return;
+	if (!is_host_active(cppi41_channel->controller->musb))
+		return;
+
+	csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+	toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+	/*
+	 * AM335x Advisory 1.0.13: Due to internal synchronisation error the
+	 * data toggle may reset from DATA1 to DATA0 during receiving data from
+	 * more than one endpoint.
+	 */
+	if (!toggle && toggle == cppi41_channel->usb_toggle) {
+		csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE;
+		musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr);
+		dev_dbg(cppi41_channel->controller->musb->controller,
+				"Restoring DATA1 toggle.\n");
+	}
+
+	cppi41_channel->usb_toggle = toggle;
+}
+
+static void cppi41_dma_callback(void *private_data)
+{
+	struct dma_channel *channel = private_data;
+	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+	struct musb *musb = hw_ep->musb;
+	unsigned long flags;
+	struct dma_tx_state txstate;
+	u32 transferred;
+
+	spin_lock_irqsave(&musb->lock, flags);
+
+	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie,
+			&txstate);
+	transferred = cppi41_channel->prog_len - txstate.residue;
+	cppi41_channel->transferred += transferred;
+
+	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n",
+		hw_ep->epnum, cppi41_channel->transferred,
+		cppi41_channel->total_len);
+
+	update_rx_toggle(cppi41_channel);
+
+	if (cppi41_channel->transferred == cppi41_channel->total_len ||
+			transferred < cppi41_channel->packet_sz) {
+
+		/* done, complete */
+		cppi41_channel->channel.actual_len =
+			cppi41_channel->transferred;
+		cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+		musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
+	} else {
+		/* next iteration, reload */
+		struct dma_chan *dc = cppi41_channel->dc;
+		struct dma_async_tx_descriptor *dma_desc;
+		enum dma_transfer_direction direction;
+		u16 csr;
+		u32 remain_bytes;
+		void __iomem *epio = cppi41_channel->hw_ep->regs;
+
+		cppi41_channel->buf_addr += cppi41_channel->packet_sz;
+
+		remain_bytes = cppi41_channel->total_len;
+		remain_bytes -= cppi41_channel->transferred;
+		remain_bytes = min(remain_bytes, cppi41_channel->packet_sz);
+		cppi41_channel->prog_len = remain_bytes;
+
+		direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV
+			: DMA_DEV_TO_MEM;
+		dma_desc = dmaengine_prep_slave_single(dc,
+				cppi41_channel->buf_addr,
+				remain_bytes,
+				direction,
+				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (WARN_ON(!dma_desc)) {
+			spin_unlock_irqrestore(&musb->lock, flags);
+			return;
+		}
+
+		dma_desc->callback = cppi41_dma_callback;
+		dma_desc->callback_param = channel;
+		cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+		dma_async_issue_pending(dc);
+
+		if (!cppi41_channel->is_tx) {
+			csr = musb_readw(epio, MUSB_RXCSR);
+			csr |= MUSB_RXCSR_H_REQPKT;
+			musb_writew(epio, MUSB_RXCSR, csr);
+		}
+	}
+	spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old)
+{
+	unsigned shift;
+
+	shift = (ep - 1) * 2;
+	old &= ~(3 << shift);
+	old |= mode << shift;
+	return old;
+}
+
+static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel,
+		unsigned mode)
+{
+	struct cppi41_dma_controller *controller = cppi41_channel->controller;
+	u32 port;
+	u32 new_mode;
+	u32 old_mode;
+
+	if (cppi41_channel->is_tx)
+		old_mode = controller->tx_mode;
+	else
+		old_mode = controller->rx_mode;
+	port = cppi41_channel->port_num;
+	new_mode = update_ep_mode(port, mode, old_mode);
+
+	if (new_mode == old_mode)
+		return;
+	if (cppi41_channel->is_tx) {
+		controller->tx_mode = new_mode;
+		musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE,
+				new_mode);
+	} else {
+		controller->rx_mode = new_mode;
+		musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE,
+				new_mode);
+	}
+}
+
+static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel,
+		unsigned mode)
+{
+	struct cppi41_dma_controller *controller = cppi41_channel->controller;
+	u32 port;
+	u32 new_mode;
+	u32 old_mode;
+
+	old_mode = controller->auto_req;
+	port = cppi41_channel->port_num;
+	new_mode = update_ep_mode(port, mode, old_mode);
+
+	if (new_mode == old_mode)
+		return;
+	controller->auto_req = new_mode;
+	musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode);
+}
+
+static bool cppi41_configure_channel(struct dma_channel *channel,
+				u16 packet_sz, u8 mode,
+				dma_addr_t dma_addr, u32 len)
+{
+	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+	struct dma_chan *dc = cppi41_channel->dc;
+	struct dma_async_tx_descriptor *dma_desc;
+	enum dma_transfer_direction direction;
+	struct musb *musb = cppi41_channel->controller->musb;
+	unsigned use_gen_rndis = 0;
+
+	dev_dbg(musb->controller,
+		"configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
+		cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num),
+		packet_sz, mode, (unsigned long long) dma_addr,
+		len, cppi41_channel->is_tx);
+
+	cppi41_channel->buf_addr = dma_addr;
+	cppi41_channel->total_len = len;
+	cppi41_channel->transferred = 0;
+	cppi41_channel->packet_sz = packet_sz;
+
+	/*
+	 * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
+	 * than max packet size at a time.
+	 */
+	if (cppi41_channel->is_tx)
+		use_gen_rndis = 1;
+
+	if (use_gen_rndis) {
+		/* RNDIS mode */
+		if (len > packet_sz) {
+			musb_writel(musb->ctrl_base,
+				RNDIS_REG(cppi41_channel->port_num), len);
+			/* gen rndis */
+			cppi41_set_dma_mode(cppi41_channel,
+					EP_MODE_DMA_GEN_RNDIS);
+
+			/* auto req */
+			cppi41_set_autoreq_mode(cppi41_channel,
+					EP_MODE_AUTOREG_ALL_NEOP);
+		} else {
+			musb_writel(musb->ctrl_base,
+					RNDIS_REG(cppi41_channel->port_num), 0);
+			cppi41_set_dma_mode(cppi41_channel,
+					EP_MODE_DMA_TRANSPARENT);
+			cppi41_set_autoreq_mode(cppi41_channel,
+					EP_MODE_AUTOREG_NONE);
+		}
+	} else {
+		/* fallback mode */
+		cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+		cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+		len = min_t(u32, packet_sz, len);
+	}
+	cppi41_channel->prog_len = len;
+	direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+	dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!dma_desc)
+		return false;
+
+	dma_desc->callback = cppi41_dma_callback;
+	dma_desc->callback_param = channel;
+	cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+
+	save_rx_toggle(cppi41_channel);
+	dma_async_issue_pending(dc);
+	return true;
+}
+
+static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c,
+				struct musb_hw_ep *hw_ep, u8 is_tx)
+{
+	struct cppi41_dma_controller *controller = container_of(c,
+			struct cppi41_dma_controller, controller);
+	struct cppi41_dma_channel *cppi41_channel = NULL;
+	u8 ch_num = hw_ep->epnum - 1;
+
+	if (ch_num >= MUSB_DMA_NUM_CHANNELS)
+		return NULL;
+
+	if (is_tx)
+		cppi41_channel = &controller->tx_channel[ch_num];
+	else
+		cppi41_channel = &controller->rx_channel[ch_num];
+
+	if (!cppi41_channel->dc)
+		return NULL;
+
+	if (cppi41_channel->is_allocated)
+		return NULL;
+
+	cppi41_channel->hw_ep = hw_ep;
+	cppi41_channel->is_allocated = 1;
+
+	return &cppi41_channel->channel;
+}
+
+static void cppi41_dma_channel_release(struct dma_channel *channel)
+{
+	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+
+	if (cppi41_channel->is_allocated) {
+		cppi41_channel->is_allocated = 0;
+		channel->status = MUSB_DMA_STATUS_FREE;
+		channel->actual_len = 0;
+	}
+}
+
+static int cppi41_dma_channel_program(struct dma_channel *channel,
+				u16 packet_sz, u8 mode,
+				dma_addr_t dma_addr, u32 len)
+{
+	int ret;
+
+	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
+		channel->status == MUSB_DMA_STATUS_BUSY);
+
+	channel->status = MUSB_DMA_STATUS_BUSY;
+	channel->actual_len = 0;
+	ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);
+	if (!ret)
+		channel->status = MUSB_DMA_STATUS_FREE;
+
+	return ret;
+}
+
+static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,
+		void *buf, u32 length)
+{
+	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+	struct cppi41_dma_controller *controller = cppi41_channel->controller;
+	struct musb *musb = controller->musb;
+
+	if (is_host_active(musb)) {
+		WARN_ON(1);
+		return 1;
+	}
+	if (cppi41_channel->is_tx)
+		return 1;
+	/* AM335x Advisory 1.0.13. No workaround for device RX mode */
+	return 0;
+}
+
+static int cppi41_dma_channel_abort(struct dma_channel *channel)
+{
+	struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+	struct cppi41_dma_controller *controller = cppi41_channel->controller;
+	struct musb *musb = controller->musb;
+	void __iomem *epio = cppi41_channel->hw_ep->regs;
+	int tdbit;
+	int ret;
+	unsigned is_tx;
+	u16 csr;
+
+	is_tx = cppi41_channel->is_tx;
+	dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n",
+			cppi41_channel->port_num, is_tx);
+
+	if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)
+		return 0;
+
+	if (is_tx) {
+		csr = musb_readw(epio, MUSB_TXCSR);
+		csr &= ~MUSB_TXCSR_DMAENAB;
+		musb_writew(epio, MUSB_TXCSR, csr);
+	} else {
+		csr = musb_readw(epio, MUSB_RXCSR);
+		csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
+		musb_writew(epio, MUSB_RXCSR, csr);
+
+		csr = musb_readw(epio, MUSB_RXCSR);
+		if (csr & MUSB_RXCSR_RXPKTRDY) {
+			csr |= MUSB_RXCSR_FLUSHFIFO;
+			musb_writew(epio, MUSB_RXCSR, csr);
+			musb_writew(epio, MUSB_RXCSR, csr);
+		}
+	}
+
+	tdbit = 1 << cppi41_channel->port_num;
+	if (is_tx)
+		tdbit <<= 16;
+
+	do {
+		musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+		ret = dmaengine_terminate_all(cppi41_channel->dc);
+	} while (ret == -EAGAIN);
+
+	musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+
+	if (is_tx) {
+		csr = musb_readw(epio, MUSB_TXCSR);
+		if (csr & MUSB_TXCSR_TXPKTRDY) {
+			csr |= MUSB_TXCSR_FLUSHFIFO;
+			musb_writew(epio, MUSB_TXCSR, csr);
+		}
+	}
+
+	cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+	return 0;
+}
+
+static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl)
+{
+	struct dma_chan *dc;
+	int i;
+
+	for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) {
+		dc = ctrl->tx_channel[i].dc;
+		if (dc)
+			dma_release_channel(dc);
+		dc = ctrl->rx_channel[i].dc;
+		if (dc)
+			dma_release_channel(dc);
+	}
+}
+
+static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller)
+{
+	cppi41_release_all_dma_chans(controller);
+}
+
+static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
+{
+	struct musb *musb = controller->musb;
+	struct device *dev = musb->controller;
+	struct device_node *np = dev->of_node;
+	struct cppi41_dma_channel *cppi41_channel;
+	int count;
+	int i;
+	int ret;
+
+	count = of_property_count_strings(np, "dma-names");
+	if (count < 0)
+		return count;
+
+	for (i = 0; i < count; i++) {
+		struct dma_chan *dc;
+		struct dma_channel *musb_dma;
+		const char *str;
+		unsigned is_tx;
+		unsigned int port;
+
+		ret = of_property_read_string_index(np, "dma-names", i, &str);
+		if (ret)
+			goto err;
+		if (!strncmp(str, "tx", 2))
+			is_tx = 1;
+		else if (!strncmp(str, "rx", 2))
+			is_tx = 0;
+		else {
+			dev_err(dev, "Wrong dmatype %s\n", str);
+			goto err;
+		}
+		ret = kstrtouint(str + 2, 0, &port);
+		if (ret)
+			goto err;
+
+		if (port > MUSB_DMA_NUM_CHANNELS || !port)
+			goto err;
+		if (is_tx)
+			cppi41_channel = &controller->tx_channel[port - 1];
+		else
+			cppi41_channel = &controller->rx_channel[port - 1];
+
+		cppi41_channel->controller = controller;
+		cppi41_channel->port_num = port;
+		cppi41_channel->is_tx = is_tx;
+
+		musb_dma = &cppi41_channel->channel;
+		musb_dma->private_data = cppi41_channel;
+		musb_dma->status = MUSB_DMA_STATUS_FREE;
+		musb_dma->max_len = SZ_4M;
+
+		dc = dma_request_slave_channel(dev, str);
+		if (!dc) {
+			dev_err(dev, "Falied to request %s.\n", str);
+			goto err;
+		}
+		cppi41_channel->dc = dc;
+	}
+	return 0;
+err:
+	cppi41_release_all_dma_chans(controller);
+	return -EINVAL;
+}
+
+void dma_controller_destroy(struct dma_controller *c)
+{
+	struct cppi41_dma_controller *controller = container_of(c,
+			struct cppi41_dma_controller, controller);
+
+	cppi41_dma_controller_stop(controller);
+	kfree(controller);
+}
+
+struct dma_controller *dma_controller_create(struct musb *musb,
+					void __iomem *base)
+{
+	struct cppi41_dma_controller *controller;
+	int ret;
+
+	if (!musb->controller->of_node) {
+		dev_err(musb->controller, "Need DT for the DMA engine.\n");
+		return NULL;
+	}
+
+	controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+	if (!controller)
+		goto kzalloc_fail;
+
+	controller->musb = musb;
+
+	controller->controller.channel_alloc = cppi41_dma_channel_allocate;
+	controller->controller.channel_release = cppi41_dma_channel_release;
+	controller->controller.channel_program = cppi41_dma_channel_program;
+	controller->controller.channel_abort = cppi41_dma_channel_abort;
+	controller->controller.is_compatible = cppi41_is_compatible;
+
+	ret = cppi41_dma_controller_start(controller);
+	if (ret)
+		goto plat_get_fail;
+	return &controller->controller;
+
+plat_get_fail:
+	kfree(controller);
+kzalloc_fail:
+	return NULL;
+}
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 1b6b827..1345a4f 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -62,13 +62,13 @@
 
 #define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
 
-#ifndef CONFIG_MUSB_PIO_ONLY
-#define	is_dma_capable()	(1)
-#else
+#ifdef CONFIG_MUSB_PIO_ONLY
 #define	is_dma_capable()	(0)
+#else
+#define	is_dma_capable()	(1)
 #endif
 
-#ifdef CONFIG_USB_TI_CPPI_DMA
+#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
 #define	is_cppi_enabled()	1
 #else
 #define	is_cppi_enabled()	0
@@ -159,8 +159,6 @@
  * Controllers manage dma channels.
  */
 struct dma_controller {
-	int			(*start)(struct dma_controller *);
-	int			(*stop)(struct dma_controller *);
 	struct dma_channel	*(*channel_alloc)(struct dma_controller *,
 					struct musb_hw_ep *, u8 is_tx);
 	void			(*channel_release)(struct dma_channel *);
@@ -177,9 +175,20 @@
 /* called after channel_program(), may indicate a fault */
 extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
 
+#ifdef CONFIG_MUSB_PIO_ONLY
+static inline struct dma_controller *dma_controller_create(struct musb *m,
+		void __iomem *io)
+{
+	return NULL;
+}
+
+static inline void dma_controller_destroy(struct dma_controller *d) { }
+
+#else
 
 extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);
 
 extern void dma_controller_destroy(struct dma_controller *);
+#endif
 
 #endif	/* __MUSB_DMA_H__ */
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 5233804..4047cbb 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -36,19 +36,19 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/platform_data/usb-omap.h>
 #include <linux/sizes.h>
 
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/usb/of.h>
 
 #include "musb_core.h"
 
-#ifdef CONFIG_OF
 static const struct of_device_id musb_dsps_of_match[];
-#endif
 
 /**
  * avoid using musb_readx()/musb_writex() as glue layer should not be
@@ -75,7 +75,6 @@
 	u16	revision;
 	u16	control;
 	u16	status;
-	u16	eoi;
 	u16	epintr_set;
 	u16	epintr_clear;
 	u16	epintr_status;
@@ -108,10 +107,7 @@
 	/* bit positions for mode */
 	unsigned	iddig:5;
 	/* miscellaneous stuff */
-	u32		musb_core_offset;
 	u8		poll_seconds;
-	/* number of musb instances */
-	u8		instances;
 };
 
 /**
@@ -119,53 +115,12 @@
  */
 struct dsps_glue {
 	struct device *dev;
-	struct platform_device *musb[2];	/* child musb pdev */
+	struct platform_device *musb;	/* child musb pdev */
 	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
-	struct timer_list timer[2];	/* otg_workaround timer */
-	unsigned long last_timer[2];    /* last timer data for each instance */
-	u32 __iomem *usb_ctrl[2];
+	struct timer_list timer;	/* otg_workaround timer */
+	unsigned long last_timer;    /* last timer data for each instance */
 };
 
-#define	DSPS_AM33XX_CONTROL_MODULE_PHYS_0	0x44e10620
-#define	DSPS_AM33XX_CONTROL_MODULE_PHYS_1	0x44e10628
-
-static const resource_size_t dsps_control_module_phys[] = {
-	DSPS_AM33XX_CONTROL_MODULE_PHYS_0,
-	DSPS_AM33XX_CONTROL_MODULE_PHYS_1,
-};
-
-#define USBPHY_CM_PWRDN		(1 << 0)
-#define USBPHY_OTG_PWRDN	(1 << 1)
-#define USBPHY_OTGVDET_EN	(1 << 19)
-#define USBPHY_OTGSESSEND_EN	(1 << 20)
-
-/**
- * musb_dsps_phy_control - phy on/off
- * @glue: struct dsps_glue *
- * @id: musb instance
- * @on: flag for phy to be switched on or off
- *
- * This is to enable the PHY using usb_ctrl register in system control
- * module space.
- *
- * XXX: This function will be removed once we have a seperate driver for
- * control module
- */
-static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on)
-{
-	u32 usbphycfg;
-
-	usbphycfg = readl(glue->usb_ctrl[id]);
-
-	if (on) {
-		usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
-		usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
-	} else {
-		usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
-	}
-
-	writel(usbphycfg, glue->usb_ctrl[id]);
-}
 /**
  * dsps_musb_enable - enable interrupts
  */
@@ -205,7 +160,6 @@
 	dsps_writel(reg_base, wrp->epintr_clear,
 			 wrp->txep_bitmap | wrp->rxep_bitmap);
 	dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
-	dsps_writel(reg_base, wrp->eoi, 0);
 }
 
 static void otg_timer(unsigned long _musb)
@@ -213,7 +167,6 @@
 	struct musb *musb = (void *)_musb;
 	void __iomem *mregs = musb->mregs;
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 	const struct dsps_musb_wrapper *wrp = glue->wrp;
 	u8 devctl;
@@ -250,7 +203,7 @@
 	case OTG_STATE_B_IDLE:
 		devctl = dsps_readb(mregs, MUSB_DEVCTL);
 		if (devctl & MUSB_DEVCTL_BDEVICE)
-			mod_timer(&glue->timer[pdev->id],
+			mod_timer(&glue->timer,
 					jiffies + wrp->poll_seconds * HZ);
 		else
 			musb->xceiv->state = OTG_STATE_A_IDLE;
@@ -264,7 +217,6 @@
 static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
 {
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 
 	if (timeout == 0)
@@ -275,23 +227,25 @@
 				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
 		dev_dbg(musb->controller, "%s active, deleting timer\n",
 				usb_otg_state_string(musb->xceiv->state));
-		del_timer(&glue->timer[pdev->id]);
-		glue->last_timer[pdev->id] = jiffies;
+		del_timer(&glue->timer);
+		glue->last_timer = jiffies;
 		return;
 	}
+	if (musb->port_mode == MUSB_PORT_MODE_HOST)
+		return;
 
-	if (time_after(glue->last_timer[pdev->id], timeout) &&
-				timer_pending(&glue->timer[pdev->id])) {
+	if (time_after(glue->last_timer, timeout) &&
+				timer_pending(&glue->timer)) {
 		dev_dbg(musb->controller,
 			"Longer idle timer already pending, ignoring...\n");
 		return;
 	}
-	glue->last_timer[pdev->id] = timeout;
+	glue->last_timer = timeout;
 
 	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
 		usb_otg_state_string(musb->xceiv->state),
 			jiffies_to_msecs(timeout - jiffies));
-	mod_timer(&glue->timer[pdev->id], timeout);
+	mod_timer(&glue->timer, timeout);
 }
 
 static irqreturn_t dsps_interrupt(int irq, void *hci)
@@ -299,7 +253,6 @@
 	struct musb  *musb = hci;
 	void __iomem *reg_base = musb->ctrl_base;
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 	const struct dsps_musb_wrapper *wrp = glue->wrp;
 	unsigned long flags;
@@ -319,7 +272,7 @@
 	/* Get usb core interrupts */
 	usbintr = dsps_readl(reg_base, wrp->coreintr_status);
 	if (!usbintr && !epintr)
-		goto eoi;
+		goto out;
 
 	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
 	if (usbintr)
@@ -359,15 +312,14 @@
 			 */
 			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
-			mod_timer(&glue->timer[pdev->id],
+			mod_timer(&glue->timer,
 					jiffies + wrp->poll_seconds * HZ);
 			WARNING("VBUS error workaround (delay coming)\n");
 		} else if (drvvbus) {
-			musb->is_active = 1;
 			MUSB_HST_MODE(musb);
 			musb->xceiv->otg->default_a = 1;
 			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
-			del_timer(&glue->timer[pdev->id]);
+			del_timer(&glue->timer);
 		} else {
 			musb->is_active = 0;
 			MUSB_DEV_MODE(musb);
@@ -387,16 +339,10 @@
 	if (musb->int_tx || musb->int_rx || musb->int_usb)
 		ret |= musb_interrupt(musb);
 
- eoi:
-	/* EOI needs to be written for the IRQ to be re-asserted. */
-	if (ret == IRQ_HANDLED || epintr || usbintr)
-		dsps_writel(reg_base, wrp->eoi, 1);
-
 	/* Poll for ID change */
 	if (musb->xceiv->state == OTG_STATE_B_IDLE)
-		mod_timer(&glue->timer[pdev->id],
-			 jiffies + wrp->poll_seconds * HZ);
-
+		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+out:
 	spin_unlock_irqrestore(&musb->lock, flags);
 
 	return ret;
@@ -405,37 +351,38 @@
 static int dsps_musb_init(struct musb *musb)
 {
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+	struct platform_device *parent = to_platform_device(dev->parent);
 	const struct dsps_musb_wrapper *wrp = glue->wrp;
-	void __iomem *reg_base = musb->ctrl_base;
+	void __iomem *reg_base;
+	struct resource *r;
 	u32 rev, val;
-	int status;
 
-	/* mentor core register starts at offset of 0x400 from musb base */
-	musb->mregs += wrp->musb_core_offset;
+	r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
+	if (!r)
+		return -EINVAL;
+
+	reg_base = devm_ioremap_resource(dev, r);
+	if (IS_ERR(reg_base))
+		return PTR_ERR(reg_base);
+	musb->ctrl_base = reg_base;
 
 	/* NOP driver needs change if supporting dual instance */
-	usb_nop_xceiv_register();
-	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
-	if (IS_ERR_OR_NULL(musb->xceiv))
-		return -EPROBE_DEFER;
+	musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+	if (IS_ERR(musb->xceiv))
+		return PTR_ERR(musb->xceiv);
 
 	/* Returns zero if e.g. not clocked */
 	rev = dsps_readl(reg_base, wrp->revision);
-	if (!rev) {
-		status = -ENODEV;
-		goto err0;
-	}
+	if (!rev)
+		return -ENODEV;
 
-	setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
+	usb_phy_init(musb->xceiv);
+	setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
 
 	/* Reset the musb */
 	dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
 
-	/* Start the on-chip PHY and its PLL. */
-	musb_dsps_phy_control(glue, pdev->id, 1);
-
 	musb->isr = dsps_interrupt;
 
 	/* reset the otgdisable bit, needed for host mode to work */
@@ -443,31 +390,17 @@
 	val &= ~(1 << wrp->otg_disable);
 	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
 
-	/* clear level interrupt */
-	dsps_writel(reg_base, wrp->eoi, 0);
-
 	return 0;
-err0:
-	usb_put_phy(musb->xceiv);
-	usb_nop_xceiv_unregister();
-	return status;
 }
 
 static int dsps_musb_exit(struct musb *musb)
 {
 	struct device *dev = musb->controller;
-	struct platform_device *pdev = to_platform_device(dev);
 	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
 
-	del_timer_sync(&glue->timer[pdev->id]);
+	del_timer_sync(&glue->timer);
 
-	/* Shutdown the on-chip PHY and its PLL. */
-	musb_dsps_phy_control(glue, pdev->id, 0);
-
-	/* NOP driver needs change if supporting dual instance */
-	usb_put_phy(musb->xceiv);
-	usb_nop_xceiv_unregister();
-
+	usb_phy_shutdown(musb->xceiv);
 	return 0;
 }
 
@@ -483,116 +416,115 @@
 
 static u64 musb_dmamask = DMA_BIT_MASK(32);
 
-static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+static int get_int_prop(struct device_node *dn, const char *s)
 {
-	struct device *dev = glue->dev;
-	struct platform_device *pdev = to_platform_device(dev);
-	struct musb_hdrc_platform_data  *pdata = dev->platform_data;
-	struct device_node *np = pdev->dev.of_node;
-	struct musb_hdrc_config	*config;
-	struct platform_device	*musb;
-	struct resource *res;
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(dn, s, &val);
+	if (ret)
+		return 0;
+	return val;
+}
+
+static int get_musb_port_mode(struct device *dev)
+{
+	enum usb_dr_mode mode;
+
+	mode = of_usb_get_dr_mode(dev->of_node);
+	switch (mode) {
+	case USB_DR_MODE_HOST:
+		return MUSB_PORT_MODE_HOST;
+
+	case USB_DR_MODE_PERIPHERAL:
+		return MUSB_PORT_MODE_GADGET;
+
+	case USB_DR_MODE_UNKNOWN:
+	case USB_DR_MODE_OTG:
+	default:
+		return MUSB_PORT_MODE_DUAL_ROLE;
+	};
+}
+
+static int dsps_create_musb_pdev(struct dsps_glue *glue,
+		struct platform_device *parent)
+{
+	struct musb_hdrc_platform_data pdata;
 	struct resource	resources[2];
-	char res_name[11];
+	struct resource	*res;
+	struct device *dev = &parent->dev;
+	struct musb_hdrc_config	*config;
+	struct platform_device *musb;
+	struct device_node *dn = parent->dev.of_node;
 	int ret;
 
-	resources[0].start = dsps_control_module_phys[id];
-	resources[0].end = resources[0].start + SZ_4 - 1;
-	resources[0].flags = IORESOURCE_MEM;
-
-	glue->usb_ctrl[id] = devm_ioremap_resource(&pdev->dev, resources);
-	if (IS_ERR(glue->usb_ctrl[id])) {
-		ret = PTR_ERR(glue->usb_ctrl[id]);
-		goto err0;
-	}
-
-	/* first resource is for usbss, so start index from 1 */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1);
+	memset(resources, 0, sizeof(resources));
+	res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc");
 	if (!res) {
-		dev_err(dev, "failed to get memory for instance %d\n", id);
-		ret = -ENODEV;
-		goto err0;
+		dev_err(dev, "failed to get memory.\n");
+		return -EINVAL;
 	}
-	res->parent = NULL;
 	resources[0] = *res;
 
-	/* first resource is for usbss, so start index from 1 */
-	res = platform_get_resource(pdev, IORESOURCE_IRQ, id + 1);
+	res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc");
 	if (!res) {
-		dev_err(dev, "failed to get irq for instance %d\n", id);
-		ret = -ENODEV;
-		goto err0;
+		dev_err(dev, "failed to get irq.\n");
+		return -EINVAL;
 	}
-	res->parent = NULL;
 	resources[1] = *res;
-	resources[1].name = "mc";
 
 	/* allocate the child platform device */
 	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
 	if (!musb) {
 		dev_err(dev, "failed to allocate musb device\n");
-		ret = -ENOMEM;
-		goto err0;
+		return -ENOMEM;
 	}
 
 	musb->dev.parent		= dev;
 	musb->dev.dma_mask		= &musb_dmamask;
 	musb->dev.coherent_dma_mask	= musb_dmamask;
+	musb->dev.of_node		= of_node_get(dn);
 
-	glue->musb[id]			= musb;
+	glue->musb = musb;
 
-	ret = platform_device_add_resources(musb, resources, 2);
+	ret = platform_device_add_resources(musb, resources,
+			ARRAY_SIZE(resources));
 	if (ret) {
 		dev_err(dev, "failed to add resources\n");
-		goto err2;
+		goto err;
 	}
 
-	if (np) {
-		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-		if (!pdata) {
-			dev_err(&pdev->dev,
-				"failed to allocate musb platform data\n");
-			ret = -ENOMEM;
-			goto err2;
-		}
-
-		config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
-		if (!config) {
-			dev_err(&pdev->dev,
-				"failed to allocate musb hdrc config\n");
-			ret = -ENOMEM;
-			goto err2;
-		}
-
-		of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
-		of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
-		snprintf(res_name, sizeof(res_name), "port%d-mode", id);
-		of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
-		of_property_read_u32(np, "power", (u32 *)&pdata->power);
-		config->multipoint = of_property_read_bool(np, "multipoint");
-
-		pdata->config		= config;
+	config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
+	if (!config) {
+		dev_err(dev, "failed to allocate musb hdrc config\n");
+		ret = -ENOMEM;
+		goto err;
 	}
+	pdata.config = config;
+	pdata.platform_ops = &dsps_ops;
 
-	pdata->platform_ops		= &dsps_ops;
+	config->num_eps = get_int_prop(dn, "mentor,num-eps");
+	config->ram_bits = get_int_prop(dn, "mentor,ram-bits");
+	pdata.mode = get_musb_port_mode(dev);
+	/* DT keeps this entry in mA, musb expects it as per USB spec */
+	pdata.power = get_int_prop(dn, "mentor,power") / 2;
+	config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
 
-	ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+	ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
 	if (ret) {
 		dev_err(dev, "failed to add platform_data\n");
-		goto err2;
+		goto err;
 	}
 
 	ret = platform_device_add(musb);
 	if (ret) {
 		dev_err(dev, "failed to register musb device\n");
-		goto err2;
+		goto err;
 	}
-
 	return 0;
 
-err2:
+err:
 	platform_device_put(musb);
-err0:
 	return ret;
 }
 
@@ -601,14 +533,12 @@
 	const struct of_device_id *match;
 	const struct dsps_musb_wrapper *wrp;
 	struct dsps_glue *glue;
-	struct resource *iomem;
-	int ret, i;
+	int ret;
 
 	match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
 	if (!match) {
 		dev_err(&pdev->dev, "fail to get matching of_match struct\n");
-		ret = -EINVAL;
-		goto err0;
+		return -EINVAL;
 	}
 	wrp = match->data;
 
@@ -616,29 +546,13 @@
 	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
 	if (!glue) {
 		dev_err(&pdev->dev, "unable to allocate glue memory\n");
-		ret = -ENOMEM;
-		goto err0;
-	}
-
-	/* get memory resource */
-	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!iomem) {
-		dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
-		ret = -ENODEV;
-		goto err1;
+		return -ENOMEM;
 	}
 
 	glue->dev = &pdev->dev;
+	glue->wrp = wrp;
 
-	glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
-	if (!glue->wrp) {
-		dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
-		ret = -ENOMEM;
-		goto err1;
-	}
 	platform_set_drvdata(pdev, glue);
-
-	/* enable the usbss clocks */
 	pm_runtime_enable(&pdev->dev);
 
 	ret = pm_runtime_get_sync(&pdev->dev);
@@ -647,17 +561,9 @@
 		goto err2;
 	}
 
-	/* create the child platform device for all instances of musb */
-	for (i = 0; i < wrp->instances ; i++) {
-		ret = dsps_create_musb_pdev(glue, i);
-		if (ret != 0) {
-			dev_err(&pdev->dev, "failed to create child pdev\n");
-			/* release resources of previously created instances */
-			for (i--; i >= 0 ; i--)
-				platform_device_unregister(glue->musb[i]);
-			goto err3;
-		}
-	}
+	ret = dsps_create_musb_pdev(glue, pdev);
+	if (ret)
+		goto err3;
 
 	return 0;
 
@@ -665,65 +571,27 @@
 	pm_runtime_put(&pdev->dev);
 err2:
 	pm_runtime_disable(&pdev->dev);
-	kfree(glue->wrp);
-err1:
 	kfree(glue);
-err0:
 	return ret;
 }
+
 static int dsps_remove(struct platform_device *pdev)
 {
 	struct dsps_glue *glue = platform_get_drvdata(pdev);
-	const struct dsps_musb_wrapper *wrp = glue->wrp;
-	int i;
 
-	/* delete the child platform device */
-	for (i = 0; i < wrp->instances ; i++)
-		platform_device_unregister(glue->musb[i]);
+	platform_device_unregister(glue->musb);
 
 	/* disable usbss clocks */
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
-	kfree(glue->wrp);
 	kfree(glue);
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int dsps_suspend(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
-	const struct dsps_musb_wrapper *wrp = glue->wrp;
-	int i;
-
-	for (i = 0; i < wrp->instances; i++)
-		musb_dsps_phy_control(glue, i, 0);
-
-	return 0;
-}
-
-static int dsps_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev->parent);
-	struct dsps_glue *glue = platform_get_drvdata(pdev);
-	const struct dsps_musb_wrapper *wrp = glue->wrp;
-	int i;
-
-	for (i = 0; i < wrp->instances; i++)
-		musb_dsps_phy_control(glue, i, 1);
-
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
-
-static const struct dsps_musb_wrapper ti81xx_driver_data = {
+static const struct dsps_musb_wrapper am33xx_driver_data = {
 	.revision		= 0x00,
 	.control		= 0x14,
 	.status			= 0x18,
-	.eoi			= 0x24,
 	.epintr_set		= 0x38,
 	.epintr_clear		= 0x40,
 	.epintr_status		= 0x30,
@@ -745,38 +613,23 @@
 	.rxep_shift		= 16,
 	.rxep_mask		= 0xfffe,
 	.rxep_bitmap		= (0xfffe << 16),
-	.musb_core_offset	= 0x400,
 	.poll_seconds		= 2,
-	.instances		= 1,
 };
 
-static const struct platform_device_id musb_dsps_id_table[] = {
-	{
-		.name	= "musb-ti81xx",
-		.driver_data	= (kernel_ulong_t) &ti81xx_driver_data,
-	},
-	{  },	/* Terminating Entry */
-};
-MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
-
-#ifdef CONFIG_OF
 static const struct of_device_id musb_dsps_of_match[] = {
 	{ .compatible = "ti,musb-am33xx",
-		.data = (void *) &ti81xx_driver_data, },
+		.data = (void *) &am33xx_driver_data, },
 	{  },
 };
 MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
-#endif
 
 static struct platform_driver dsps_usbss_driver = {
 	.probe		= dsps_probe,
 	.remove         = dsps_remove,
 	.driver         = {
 		.name   = "musb-dsps",
-		.pm	= &dsps_pm_ops,
 		.of_match_table	= of_match_ptr(musb_dsps_of_match),
 	},
-	.id_table	= musb_dsps_id_table,
 };
 
 MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
@@ -784,14 +637,4 @@
 MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
 MODULE_LICENSE("GPL v2");
 
-static int __init dsps_init(void)
-{
-	return platform_driver_register(&dsps_usbss_driver);
-}
-subsys_initcall(dsps_init);
-
-static void __exit dsps_exit(void)
-{
-	platform_driver_unregister(&dsps_usbss_driver);
-}
-module_exit(dsps_exit);
+module_platform_driver(dsps_usbss_driver);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 0414bc1..9a08679 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -76,13 +76,21 @@
 		return;
 
 	if (request->request.dma == DMA_ADDR_INVALID) {
-		request->request.dma = dma_map_single(
+		dma_addr_t dma_addr;
+		int ret;
+
+		dma_addr = dma_map_single(
 				musb->controller,
 				request->request.buf,
 				request->request.length,
 				request->tx
 					? DMA_TO_DEVICE
 					: DMA_FROM_DEVICE);
+		ret = dma_mapping_error(musb->controller, dma_addr);
+		if (ret)
+			return;
+
+		request->request.dma = dma_addr;
 		request->map_state = MUSB_MAPPED;
 	} else {
 		dma_sync_single_for_device(musb->controller,
@@ -357,47 +365,49 @@
 			}
 		}
 
-#elif defined(CONFIG_USB_TI_CPPI_DMA)
-		/* program endpoint CSR first, then setup DMA */
-		csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
-		csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
-		       MUSB_TXCSR_MODE;
-		musb_writew(epio, MUSB_TXCSR,
-			(MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
-				| csr);
-
-		/* ensure writebuffer is empty */
-		csr = musb_readw(epio, MUSB_TXCSR);
-
-		/* NOTE host side sets DMAENAB later than this; both are
-		 * OK since the transfer dma glue (between CPPI and Mentor
-		 * fifos) just tells CPPI it could start.  Data only moves
-		 * to the USB TX fifo when both fifos are ready.
-		 */
-
-		/* "mode" is irrelevant here; handle terminating ZLPs like
-		 * PIO does, since the hardware RNDIS mode seems unreliable
-		 * except for the last-packet-is-already-short case.
-		 */
-		use_dma = use_dma && c->channel_program(
-				musb_ep->dma, musb_ep->packet_sz,
-				0,
-				request->dma + request->actual,
-				request_size);
-		if (!use_dma) {
-			c->channel_release(musb_ep->dma);
-			musb_ep->dma = NULL;
-			csr &= ~MUSB_TXCSR_DMAENAB;
-			musb_writew(epio, MUSB_TXCSR, csr);
-			/* invariant: prequest->buf is non-null */
-		}
-#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
-		use_dma = use_dma && c->channel_program(
-				musb_ep->dma, musb_ep->packet_sz,
-				request->zero,
-				request->dma + request->actual,
-				request_size);
 #endif
+		if (is_cppi_enabled()) {
+			/* program endpoint CSR first, then setup DMA */
+			csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+			csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+				MUSB_TXCSR_MODE;
+			musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS &
+						~MUSB_TXCSR_P_UNDERRUN) | csr);
+
+			/* ensure writebuffer is empty */
+			csr = musb_readw(epio, MUSB_TXCSR);
+
+			/*
+			 * NOTE host side sets DMAENAB later than this; both are
+			 * OK since the transfer dma glue (between CPPI and
+			 * Mentor fifos) just tells CPPI it could start. Data
+			 * only moves to the USB TX fifo when both fifos are
+			 * ready.
+			 */
+			/*
+			 * "mode" is irrelevant here; handle terminating ZLPs
+			 * like PIO does, since the hardware RNDIS mode seems
+			 * unreliable except for the
+			 * last-packet-is-already-short case.
+			 */
+			use_dma = use_dma && c->channel_program(
+					musb_ep->dma, musb_ep->packet_sz,
+					0,
+					request->dma + request->actual,
+					request_size);
+			if (!use_dma) {
+				c->channel_release(musb_ep->dma);
+				musb_ep->dma = NULL;
+				csr &= ~MUSB_TXCSR_DMAENAB;
+				musb_writew(epio, MUSB_TXCSR, csr);
+				/* invariant: prequest->buf is non-null */
+			}
+		} else if (tusb_dma_omap())
+			use_dma = use_dma && c->channel_program(
+					musb_ep->dma, musb_ep->packet_sz,
+					request->zero,
+					request->dma + request->actual,
+					request_size);
 	}
 #endif
 
@@ -1266,7 +1276,8 @@
 		dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
 				req, ep->name, "disabled");
 		status = -ESHUTDOWN;
-		goto cleanup;
+		unmap_dma_buffer(request, musb);
+		goto unlock;
 	}
 
 	/* add request to the list */
@@ -1276,7 +1287,7 @@
 	if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
 		musb_ep_restart(musb, request);
 
-cleanup:
+unlock:
 	spin_unlock_irqrestore(&musb->lock, lockflags);
 	return status;
 }
@@ -1801,6 +1812,8 @@
 
 void musb_gadget_cleanup(struct musb *musb)
 {
+	if (musb->port_mode == MUSB_PORT_MODE_HOST)
+		return;
 	usb_del_gadget_udc(&musb->g);
 }
 
@@ -1926,7 +1939,8 @@
 	stop_activity(musb, driver);
 	otg_set_peripheral(musb->xceiv->otg, NULL);
 
-	dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
+	dev_dbg(musb->controller, "unregistering driver %s\n",
+				  driver ? driver->function : "(removed)");
 
 	musb->is_active = 0;
 	musb->gadget_driver = NULL;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index a9695f5..9a2b8c8 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2628,6 +2628,8 @@
 
 void musb_host_cleanup(struct musb *musb)
 {
+	if (musb->port_mode == MUSB_PORT_MODE_GADGET)
+		return;
 	usb_remove_hcd(musb->hcd);
 	musb->hcd = NULL;
 }
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 3d1fd52..e8e9f9a 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -37,18 +37,10 @@
 #include "musb_core.h"
 #include "musbhsdma.h"
 
-static int dma_controller_start(struct dma_controller *c)
-{
-	/* nothing to do */
-	return 0;
-}
-
 static void dma_channel_release(struct dma_channel *channel);
 
-static int dma_controller_stop(struct dma_controller *c)
+static void dma_controller_stop(struct musb_dma_controller *controller)
 {
-	struct musb_dma_controller *controller = container_of(c,
-			struct musb_dma_controller, controller);
 	struct musb *musb = controller->private_data;
 	struct dma_channel *channel;
 	u8 bit;
@@ -67,8 +59,6 @@
 			}
 		}
 	}
-
-	return 0;
 }
 
 static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
@@ -371,8 +361,7 @@
 	struct musb_dma_controller *controller = container_of(c,
 			struct musb_dma_controller, controller);
 
-	if (!controller)
-		return;
+	dma_controller_stop(controller);
 
 	if (controller->irq)
 		free_irq(controller->irq, c);
@@ -400,8 +389,6 @@
 	controller->private_data = musb;
 	controller->base = base;
 
-	controller->controller.start = dma_controller_start;
-	controller->controller.stop = dma_controller_stop;
 	controller->controller.channel_alloc = dma_channel_allocate;
 	controller->controller.channel_release = dma_channel_release;
 	controller->controller.channel_program = dma_channel_program;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index f44e8b5..59d2245 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -255,7 +255,7 @@
 {
 	struct musb *musb = glue_to_musb(glue);
 	struct device *dev = musb->controller;
-	struct musb_hdrc_platform_data *pdata = dev->platform_data;
+	struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = pdata->board_data;
 	struct usb_otg *otg = musb->xceiv->otg;
 
@@ -341,7 +341,7 @@
 	int status = 0;
 	struct device *dev = musb->controller;
 	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = plat->board_data;
 
 	/* We require some kind of external transceiver, hooked
@@ -412,7 +412,7 @@
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	struct device *dev = musb->controller;
 	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
-	struct musb_hdrc_platform_data *pdata = dev->platform_data;
+	struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
 	struct omap_musb_board_data *data = pdata->board_data;
 
 	switch (glue->status) {
@@ -482,7 +482,7 @@
 static int omap2430_probe(struct platform_device *pdev)
 {
 	struct resource			musb_resources[3];
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct omap_musb_board_data	*data;
 	struct platform_device		*musb;
 	struct omap2430_glue		*glue;
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 6f8a9ca..b3b3ed7 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -25,7 +25,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 
 #include "musb_core.h"
 
@@ -1157,7 +1157,7 @@
 static int tusb_probe(struct platform_device *pdev)
 {
 	struct resource musb_resources[3];
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct platform_device		*musb;
 	struct tusb6010_glue		*glue;
 
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 98df17c..b8794eb 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -66,28 +66,6 @@
 	unsigned			multichannel:1;
 };
 
-static int tusb_omap_dma_start(struct dma_controller *c)
-{
-	struct tusb_omap_dma	*tusb_dma;
-
-	tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
-	/* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
-	return 0;
-}
-
-static int tusb_omap_dma_stop(struct dma_controller *c)
-{
-	struct tusb_omap_dma	*tusb_dma;
-
-	tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
-	/* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
-	return 0;
-}
-
 /*
  * Allocate dmareq0 to the current channel unless it's already taken
  */
@@ -695,8 +673,6 @@
 	tusb_dma->dmareq = -1;
 	tusb_dma->sync_dev = -1;
 
-	tusb_dma->controller.start = tusb_omap_dma_start;
-	tusb_dma->controller.stop = tusb_omap_dma_stop;
 	tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
 	tusb_dma->controller.channel_release = tusb_omap_dma_release;
 	tusb_dma->controller.channel_program = tusb_omap_dma_program;
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index fce71b6..59256b1 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -227,7 +227,7 @@
 static int ux500_probe(struct platform_device *pdev)
 {
 	struct resource musb_resources[2];
-	struct musb_hdrc_platform_data	*pdata = pdev->dev.platform_data;
+	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
 	struct device_node		*np = pdev->dev.of_node;
 	struct platform_device		*musb;
 	struct ux500_glue		*glue;
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index bfb7a65..3700e97 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -254,10 +254,8 @@
 	return 0;
 }
 
-static int ux500_dma_controller_stop(struct dma_controller *c)
+static void ux500_dma_controller_stop(struct ux500_dma_controller *controller)
 {
-	struct ux500_dma_controller *controller = container_of(c,
-			struct ux500_dma_controller, controller);
 	struct ux500_dma_channel *ux500_channel;
 	struct dma_channel *channel;
 	u8 ch_num;
@@ -281,18 +279,14 @@
 		if (ux500_channel->dma_chan)
 			dma_release_channel(ux500_channel->dma_chan);
 	}
-
-	return 0;
 }
 
-static int ux500_dma_controller_start(struct dma_controller *c)
+static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
 {
-	struct ux500_dma_controller *controller = container_of(c,
-			struct ux500_dma_controller, controller);
 	struct ux500_dma_channel *ux500_channel = NULL;
 	struct musb *musb = controller->private_data;
 	struct device *dev = musb->controller;
-	struct musb_hdrc_platform_data *plat = dev->platform_data;
+	struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 	struct ux500_musb_board_data *data;
 	struct dma_channel *dma_channel = NULL;
 	char **chan_names;
@@ -339,7 +333,9 @@
 			if (!ux500_channel->dma_chan)
 				ux500_channel->dma_chan =
 					dma_request_channel(mask,
-							    data->dma_filter,
+							    data ?
+							    data->dma_filter :
+							    NULL,
 							    param_array[ch_num]);
 
 			if (!ux500_channel->dma_chan) {
@@ -347,7 +343,7 @@
 					dir, ch_num);
 
 				/* Release already allocated channels */
-				ux500_dma_controller_stop(c);
+				ux500_dma_controller_stop(controller);
 
 				return -EBUSY;
 			}
@@ -369,6 +365,7 @@
 	struct ux500_dma_controller *controller = container_of(c,
 			struct ux500_dma_controller, controller);
 
+	ux500_dma_controller_stop(controller);
 	kfree(controller);
 }
 
@@ -378,6 +375,7 @@
 	struct ux500_dma_controller *controller;
 	struct platform_device *pdev = to_platform_device(musb->controller);
 	struct resource	*iomem;
+	int ret;
 
 	controller = kzalloc(sizeof(*controller), GFP_KERNEL);
 	if (!controller)
@@ -394,14 +392,15 @@
 
 	controller->phy_base = (dma_addr_t) iomem->start;
 
-	controller->controller.start = ux500_dma_controller_start;
-	controller->controller.stop = ux500_dma_controller_stop;
 	controller->controller.channel_alloc = ux500_dma_channel_allocate;
 	controller->controller.channel_release = ux500_dma_channel_release;
 	controller->controller.channel_program = ux500_dma_channel_program;
 	controller->controller.channel_abort = ux500_dma_channel_abort;
 	controller->controller.is_compatible = ux500_dma_is_compatible;
 
+	ret = ux500_dma_controller_start(controller);
+	if (ret)
+		goto plat_get_fail;
 	return &controller->controller;
 
 plat_get_fail:
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 3622fff..d5589f9 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -1,22 +1,10 @@
 #
 # Physical Layer USB driver configuration
 #
-menuconfig USB_PHY
-	bool "USB Physical Layer drivers"
-	help
-	  Most USB controllers have the physical layer signalling part
-	  (commonly called a PHY) built in.  However, dual-role devices
-	  (a.k.a. USB on-the-go) which support being USB master or slave
-	  with the same connector often use an external PHY.
+menu "USB Physical Layer drivers"
 
-	  The drivers in this submenu add support for such PHY devices.
-	  They are not needed for standard master-only (or the vast
-	  majority of slave-only) USB interfaces.
-
-	  If you're not sure if this applies to you, it probably doesn't;
-	  say N here.
-
-if USB_PHY
+config USB_PHY
+	def_bool n
 
 #
 # USB Transceiver Drivers
@@ -24,6 +12,7 @@
 config AB8500_USB
 	tristate "AB8500 USB Transceiver Driver"
 	depends on AB8500_CORE
+	select USB_PHY
 	help
 	  Enable this to support the USB OTG transceiver in AB8500 chip.
 	  This transceiver supports high and full speed devices plus,
@@ -33,12 +22,14 @@
 	bool "Freescale USB OTG Transceiver Driver"
 	depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME
 	select USB_OTG
+	select USB_PHY
 	help
 	  Enable this to support Freescale USB OTG transceiver.
 
 config ISP1301_OMAP
 	tristate "Philips ISP1301 with OMAP OTG"
 	depends on I2C && ARCH_OMAP_OTG
+	select USB_PHY
 	help
 	  If you say yes here you get support for the Philips ISP1301
 	  USB-On-The-Go transceiver working with the OMAP OTG controller.
@@ -52,12 +43,14 @@
 config MV_U3D_PHY
 	bool "Marvell USB 3.0 PHY controller Driver"
 	depends on CPU_MMP3
+	select USB_PHY
 	help
 	  Enable this to support Marvell USB 3.0 phy controller for Marvell
 	  SoC.
 
 config NOP_USB_XCEIV
 	tristate "NOP USB Transceiver Driver"
+	select USB_PHY
 	help
 	  This driver is to be used by all the usb transceiver which are either
 	  built-in with usb ip or which are autonomous and doesn't require any
@@ -65,6 +58,7 @@
 
 config OMAP_CONTROL_USB
 	tristate "OMAP CONTROL USB Driver"
+	depends on ARCH_OMAP2PLUS || COMPILE_TEST
 	help
 	  Enable this to add support for the USB part present in the control
 	  module. This driver has API to power on the USB2 PHY and to write to
@@ -76,6 +70,7 @@
 	tristate "OMAP USB2 PHY Driver"
 	depends on ARCH_OMAP2PLUS
 	select OMAP_CONTROL_USB
+	select USB_PHY
 	help
 	  Enable this to support the transceiver that is part of SOC. This
 	  driver takes care of all the PHY functionality apart from comparator.
@@ -84,13 +79,27 @@
 
 config OMAP_USB3
 	tristate "OMAP USB3 PHY Driver"
+	depends on ARCH_OMAP2PLUS || COMPILE_TEST
 	select OMAP_CONTROL_USB
+	select USB_PHY
 	help
 	  Enable this to support the USB3 PHY that is part of SOC. This
 	  driver takes care of all the PHY functionality apart from comparator.
 	  This driver interacts with the "OMAP Control USB Driver" to power
 	  on/off the PHY.
 
+config AM335X_CONTROL_USB
+	tristate
+
+config AM335X_PHY_USB
+	tristate "AM335x USB PHY Driver"
+	select USB_PHY
+	select AM335X_CONTROL_USB
+	select NOP_USB_XCEIV
+	help
+	  This driver provides PHY support for that phy which part for the
+	  AM335x SoC.
+
 config SAMSUNG_USBPHY
 	tristate
 	help
@@ -101,6 +110,7 @@
 config SAMSUNG_USB2PHY
 	tristate "Samsung USB 2.0 PHY controller Driver"
 	select SAMSUNG_USBPHY
+	select USB_PHY
 	help
 	  Enable this to support Samsung USB 2.0 (High Speed) PHY controller
 	  driver for Samsung SoCs.
@@ -108,6 +118,7 @@
 config SAMSUNG_USB3PHY
 	tristate "Samsung USB 3.0 PHY controller Driver"
 	select SAMSUNG_USBPHY
+	select USB_PHY
 	help
 	  Enable this to support Samsung USB 3.0 (Super Speed) phy controller
 	  for samsung SoCs.
@@ -115,6 +126,7 @@
 config TWL4030_USB
 	tristate "TWL4030 USB Transceiver Driver"
 	depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+	select USB_PHY
 	help
 	  Enable this to support the USB OTG transceiver on TWL4030
 	  family chips (including the TWL5030 and TPS659x0 devices).
@@ -135,6 +147,7 @@
 config USB_GPIO_VBUS
 	tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
 	depends on GPIOLIB
+	select USB_PHY
 	help
 	  Provides simple GPIO VBUS sensing for controllers with an
 	  internal transceiver via the usb_phy interface, and
@@ -145,6 +158,7 @@
 	tristate "NXP ISP1301 USB transceiver support"
 	depends on USB || USB_GADGET
 	depends on I2C
+	select USB_PHY
 	help
 	  Say Y here to add support for the NXP ISP1301 USB transceiver driver.
 	  This chip is typically used as USB transceiver for USB host, gadget
@@ -156,6 +170,7 @@
 config USB_MSM_OTG
 	tristate "OTG support for Qualcomm on-chip USB controller"
 	depends on (USB || USB_GADGET) && ARCH_MSM
+	select USB_PHY
 	help
 	  Enable this to support the USB OTG transceiver on MSM chips. It
 	  handles PHY initialization, clock management, and workarounds
@@ -169,6 +184,7 @@
 	tristate "Marvell USB OTG support"
 	depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME
 	select USB_OTG
+	select USB_PHY
 	help
 	  Say Y here if you want to build Marvell USB OTG transciever
 	  driver in kernel (including PXA and MMP series). This driver
@@ -180,6 +196,7 @@
 	tristate "Freescale MXS USB PHY support"
 	depends on ARCH_MXC || ARCH_MXS
 	select STMP_DEVICE
+	select USB_PHY
 	help
 	  Enable this to support the Freescale MXS USB PHY.
 
@@ -188,6 +205,7 @@
 config USB_RCAR_PHY
 	tristate "Renesas R-Car USB PHY support"
 	depends on USB || USB_GADGET
+	select USB_PHY
 	help
 	  Say Y here to add support for the Renesas R-Car USB common PHY driver.
 	  This chip is typically used as USB PHY for USB host, gadget.
@@ -210,4 +228,4 @@
 	  Provides read/write operations to the ULPI phy register set for
 	  controllers with a viewport register (e.g. Chipidea/ARC controllers).
 
-endif # USB_PHY
+endmenu
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 070eca3..2135e85 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -1,9 +1,6 @@
 #
 # Makefile for physical layer USB drivers
 #
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-
 obj-$(CONFIG_USB_PHY)			+= phy.o
 obj-$(CONFIG_OF)			+= of.o
 
@@ -14,8 +11,10 @@
 obj-$(CONFIG_FSL_USB2_OTG)		+= phy-fsl-usb2.o
 obj-$(CONFIG_ISP1301_OMAP)		+= phy-isp1301-omap.o
 obj-$(CONFIG_MV_U3D_PHY)		+= phy-mv-u3d-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV)		+= phy-nop.o
+obj-$(CONFIG_NOP_USB_XCEIV)		+= phy-generic.o
 obj-$(CONFIG_OMAP_CONTROL_USB)		+= phy-omap-control.o
+obj-$(CONFIG_AM335X_CONTROL_USB)	+= phy-am335x-control.o
+obj-$(CONFIG_AM335X_PHY_USB)		+= phy-am335x.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_OMAP_USB3)			+= phy-omap-usb3.o
 obj-$(CONFIG_SAMSUNG_USBPHY)		+= phy-samsung-usb.o
diff --git a/drivers/usb/phy/am35x-phy-control.h b/drivers/usb/phy/am35x-phy-control.h
new file mode 100644
index 0000000..b96594d
--- /dev/null
+++ b/drivers/usb/phy/am35x-phy-control.h
@@ -0,0 +1,21 @@
+#ifndef _AM335x_PHY_CONTROL_H_
+#define _AM335x_PHY_CONTROL_H_
+
+struct phy_control {
+	void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+	void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+	phy_ctrl->phy_power(phy_ctrl, id, on);
+}
+
+static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+	phy_ctrl->phy_wkup(phy_ctrl, id, on);
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev);
+
+#endif
diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c
new file mode 100644
index 0000000..22cf07d
--- /dev/null
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -0,0 +1,137 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/io.h>
+
+struct phy_control {
+	void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+	void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
+};
+
+struct am335x_control_usb {
+	struct device *dev;
+	void __iomem *phy_reg;
+	void __iomem *wkup;
+	spinlock_t lock;
+	struct phy_control phy_ctrl;
+};
+
+#define AM335X_USB0_CTRL		0x0
+#define AM335X_USB1_CTRL		0x8
+#define AM335x_USB_WKUP			0x0
+
+#define USBPHY_CM_PWRDN		(1 << 0)
+#define USBPHY_OTG_PWRDN	(1 << 1)
+#define USBPHY_OTGVDET_EN	(1 << 19)
+#define USBPHY_OTGSESSEND_EN	(1 << 20)
+
+static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
+{
+	struct am335x_control_usb *usb_ctrl;
+	u32 val;
+	u32 reg;
+
+	usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl);
+
+	switch (id) {
+	case 0:
+		reg = AM335X_USB0_CTRL;
+		break;
+	case 1:
+		reg = AM335X_USB1_CTRL;
+		break;
+	default:
+		WARN_ON(1);
+		return;
+	}
+
+	val = readl(usb_ctrl->phy_reg + reg);
+	if (on) {
+		val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+		val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+	} else {
+		val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
+	}
+
+	writel(val, usb_ctrl->phy_reg + reg);
+}
+
+static const struct phy_control ctrl_am335x = {
+	.phy_power = am335x_phy_power,
+};
+
+static const struct of_device_id omap_control_usb_id_table[] = {
+	{ .compatible = "ti,am335x-usb-ctrl-module", .data = &ctrl_am335x },
+	{}
+};
+MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+
+static struct platform_driver am335x_control_driver;
+static int match(struct device *dev, void *data)
+{
+	struct device_node *node = (struct device_node *)data;
+	return dev->of_node == node &&
+		dev->driver == &am335x_control_driver.driver;
+}
+
+struct phy_control *am335x_get_phy_control(struct device *dev)
+{
+	struct device_node *node;
+	struct am335x_control_usb *ctrl_usb;
+
+	node = of_parse_phandle(dev->of_node, "ti,ctrl_mod", 0);
+	if (!node)
+		return NULL;
+
+	dev = bus_find_device(&platform_bus_type, NULL, node, match);
+	ctrl_usb = dev_get_drvdata(dev);
+	if (!ctrl_usb)
+		return NULL;
+	return &ctrl_usb->phy_ctrl;
+}
+EXPORT_SYMBOL_GPL(am335x_get_phy_control);
+
+static int am335x_control_usb_probe(struct platform_device *pdev)
+{
+	struct resource	*res;
+	struct am335x_control_usb *ctrl_usb;
+	const struct of_device_id *of_id;
+	const struct phy_control *phy_ctrl;
+
+	of_id = of_match_node(omap_control_usb_id_table, pdev->dev.of_node);
+	if (!of_id)
+		return -EINVAL;
+
+	phy_ctrl = of_id->data;
+
+	ctrl_usb = devm_kzalloc(&pdev->dev, sizeof(*ctrl_usb), GFP_KERNEL);
+	if (!ctrl_usb) {
+		dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+		return -ENOMEM;
+	}
+
+	ctrl_usb->dev = &pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+	ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctrl_usb->phy_reg))
+		return PTR_ERR(ctrl_usb->phy_reg);
+	spin_lock_init(&ctrl_usb->lock);
+	ctrl_usb->phy_ctrl = *phy_ctrl;
+
+	dev_set_drvdata(ctrl_usb->dev, ctrl_usb);
+	return 0;
+}
+
+static struct platform_driver am335x_control_driver = {
+	.probe		= am335x_control_usb_probe,
+	.driver		= {
+		.name	= "am335x-control-usb",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(omap_control_usb_id_table),
+	},
+};
+
+module_platform_driver(am335x_control_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
new file mode 100644
index 0000000..c4d614d
--- /dev/null
+++ b/drivers/usb/phy/phy-am335x.c
@@ -0,0 +1,99 @@
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "am35x-phy-control.h"
+#include "phy-generic.h"
+
+struct am335x_phy {
+	struct usb_phy_gen_xceiv usb_phy_gen;
+	struct phy_control *phy_ctrl;
+	int id;
+};
+
+static int am335x_init(struct usb_phy *phy)
+{
+	struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+	return 0;
+}
+
+static void am335x_shutdown(struct usb_phy *phy)
+{
+	struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
+
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+}
+
+static int am335x_phy_probe(struct platform_device *pdev)
+{
+	struct am335x_phy *am_phy;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	am_phy = devm_kzalloc(dev, sizeof(*am_phy), GFP_KERNEL);
+	if (!am_phy)
+		return -ENOMEM;
+
+	am_phy->phy_ctrl = am335x_get_phy_control(dev);
+	if (!am_phy->phy_ctrl)
+		return -EPROBE_DEFER;
+	am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
+	if (am_phy->id < 0) {
+		dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
+		return am_phy->id;
+	}
+
+	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen,
+			USB_PHY_TYPE_USB2, 0, false, false);
+	if (ret)
+		return ret;
+
+	ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
+	if (ret)
+		goto err_add;
+	am_phy->usb_phy_gen.phy.init = am335x_init;
+	am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
+
+	platform_set_drvdata(pdev, am_phy);
+	return 0;
+
+err_add:
+	usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen);
+	return ret;
+}
+
+static int am335x_phy_remove(struct platform_device *pdev)
+{
+	struct am335x_phy *am_phy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&am_phy->usb_phy_gen.phy);
+	return 0;
+}
+
+static const struct of_device_id am335x_phy_ids[] = {
+	{ .compatible = "ti,am335x-usb-phy" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, am335x_phy_ids);
+
+static struct platform_driver am335x_phy_driver = {
+	.probe          = am335x_phy_probe,
+	.remove         = am335x_phy_remove,
+	.driver         = {
+		.name   = "am335x-phy-driver",
+		.owner  = THIS_MODULE,
+		.of_match_table = of_match_ptr(am335x_phy_ids),
+	},
+};
+
+module_platform_driver(am335x_phy_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index e771baf..fa7c9f9 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -611,7 +611,7 @@
 	otg_dev->fsm.b_bus_req = 1;
 
 	/* start the gadget right away if the ID pin says Mini-B */
-	DBG("ID pin=%d\n", otg_dev->fsm.id);
+	pr_debug("ID pin=%d\n", otg_dev->fsm.id);
 	if (otg_dev->fsm.id == 1) {
 		fsl_otg_start_host(&otg_dev->fsm, 0);
 		otg_drv_vbus(&otg_dev->fsm, 0);
@@ -684,7 +684,7 @@
 	if (otg_dev != fsl_otg_dev)
 		return -ENODEV;
 
-	DBG("start_hnp...n");
+	pr_debug("start_hnp...\n");
 
 	/* clear a_bus_req to enter a_suspend state */
 	otg_dev->fsm.a_bus_req = 0;
@@ -834,7 +834,7 @@
 	int status;
 	struct resource *res;
 	u32 temp;
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	p_otg = container_of(otg_trans, struct fsl_otg, phy);
 	fsm = &p_otg->fsm;
@@ -941,7 +941,7 @@
 		p_otg->fsm.id = 0;
 	}
 
-	DBG("initial ID pin=%d\n", p_otg->fsm.id);
+	pr_debug("initial ID pin=%d\n", p_otg->fsm.id);
 
 	/* enable OTG ID pin interrupt */
 	temp = fsl_readl(&p_otg->dr_mem_map->otgsc);
@@ -1105,7 +1105,7 @@
 {
 	int ret;
 
-	if (!pdev->dev.platform_data)
+	if (!dev_get_platdata(&pdev->dev))
 		return -ENODEV;
 
 	/* configure the OTG */
@@ -1137,7 +1137,7 @@
 
 static int fsl_otg_remove(struct platform_device *pdev)
 {
-	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
 
 	usb_remove_phy(&fsl_otg_dev->phy);
 	free_irq(fsl_otg_dev->irq, fsl_otg_dev);
diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h
index ca26628..e1859b8 100644
--- a/drivers/usb/phy/phy-fsl-usb.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
@@ -15,7 +15,7 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include "otg_fsm.h"
+#include "phy-fsm-usb.h"
 #include <linux/usb/otg.h>
 #include <linux/ioctl.h>
 
diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c
index c520b35..7f45966 100644
--- a/drivers/usb/phy/phy-fsm-usb.c
+++ b/drivers/usb/phy/phy-fsm-usb.c
@@ -29,7 +29,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 
-#include "phy-otg-fsm.h"
+#include "phy-fsm-usb.h"
 
 /* Change USB protocol when there is a protocol change */
 static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h
index c30a2e1..fbe5862 100644
--- a/drivers/usb/phy/phy-fsm-usb.h
+++ b/drivers/usb/phy/phy-fsm-usb.h
@@ -15,18 +15,11 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#undef DEBUG
 #undef VERBOSE
 
-#ifdef DEBUG
-#define DBG(fmt, args...) printk(KERN_DEBUG "[%s]  " fmt , \
-				 __func__, ## args)
-#else
-#define DBG(fmt, args...)	do {} while (0)
-#endif
-
 #ifdef VERBOSE
-#define VDBG		DBG
+#define VDBG(fmt, args...) pr_debug("[%s]  " fmt , \
+				 __func__, ## args)
 #else
 #define VDBG(stuff...)	do {} while (0)
 #endif
diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-generic.c
similarity index 66%
rename from drivers/usb/phy/phy-nop.c
rename to drivers/usb/phy/phy-generic.c
index 55445e5d..efe59f3 100644
--- a/drivers/usb/phy/phy-nop.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -30,19 +30,13 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
+#include <linux/usb/usb_phy_gen_xceiv.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
 
-struct nop_usb_xceiv {
-	struct usb_phy phy;
-	struct device *dev;
-	struct clk *clk;
-	struct regulator *vcc;
-	struct regulator *reset;
-};
+#include "phy-generic.h"
 
 static struct platform_device *pd;
 
@@ -50,9 +44,9 @@
 {
 	if (pd)
 		return;
-	pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
+	pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0);
 	if (!pd) {
-		printk(KERN_ERR "Unable to register usb nop transceiver\n");
+		pr_err("Unable to register generic usb transceiver\n");
 		return;
 	}
 }
@@ -70,9 +64,9 @@
 	return 0;
 }
 
-static int nop_init(struct usb_phy *phy)
+int usb_gen_phy_init(struct usb_phy *phy)
 {
-	struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
 
 	if (!IS_ERR(nop->vcc)) {
 		if (regulator_enable(nop->vcc))
@@ -90,10 +84,11 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(usb_gen_phy_init);
 
-static void nop_shutdown(struct usb_phy *phy)
+void usb_gen_phy_shutdown(struct usb_phy *phy)
 {
-	struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
 
 	if (!IS_ERR(nop->reset)) {
 		/* Assert RESET */
@@ -109,6 +104,7 @@
 			dev_err(phy->dev, "Failed to disable power\n");
 	}
 }
+EXPORT_SYMBOL_GPL(usb_gen_phy_shutdown);
 
 static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 {
@@ -139,26 +135,90 @@
 	return 0;
 }
 
-static int nop_usb_xceiv_probe(struct platform_device *pdev)
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+		enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+		bool needs_reset)
+{
+	int err;
+
+	nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
+			GFP_KERNEL);
+	if (!nop->phy.otg)
+		return -ENOMEM;
+
+	nop->clk = devm_clk_get(dev, "main_clk");
+	if (IS_ERR(nop->clk)) {
+		dev_dbg(dev, "Can't get phy clock: %ld\n",
+					PTR_ERR(nop->clk));
+	}
+
+	if (!IS_ERR(nop->clk) && clk_rate) {
+		err = clk_set_rate(nop->clk, clk_rate);
+		if (err) {
+			dev_err(dev, "Error setting clock rate\n");
+			return err;
+		}
+	}
+
+	if (!IS_ERR(nop->clk)) {
+		err = clk_prepare(nop->clk);
+		if (err) {
+			dev_err(dev, "Error preparing clock\n");
+			return err;
+		}
+	}
+
+	nop->vcc = devm_regulator_get(dev, "vcc");
+	if (IS_ERR(nop->vcc)) {
+		dev_dbg(dev, "Error getting vcc regulator: %ld\n",
+					PTR_ERR(nop->vcc));
+		if (needs_vcc)
+			return -EPROBE_DEFER;
+	}
+
+	nop->reset = devm_regulator_get(dev, "reset");
+	if (IS_ERR(nop->reset)) {
+		dev_dbg(dev, "Error getting reset regulator: %ld\n",
+					PTR_ERR(nop->reset));
+		if (needs_reset)
+			return -EPROBE_DEFER;
+	}
+
+	nop->dev		= 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.type		= type;
+
+	nop->phy.otg->phy		= &nop->phy;
+	nop->phy.otg->set_host		= nop_set_host;
+	nop->phy.otg->set_peripheral	= nop_set_peripheral;
+
+	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
+
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop)
+{
+	if (!IS_ERR(nop->clk))
+		clk_unprepare(nop->clk);
+}
+EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy);
+
+static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
-	struct nop_usb_xceiv	*nop;
+	struct usb_phy_gen_xceiv_platform_data *pdata =
+			dev_get_platdata(&pdev->dev);
+	struct usb_phy_gen_xceiv	*nop;
 	enum usb_phy_type	type = USB_PHY_TYPE_USB2;
 	int err;
 	u32 clk_rate = 0;
 	bool needs_vcc = false;
 	bool needs_reset = false;
 
-	nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
-	if (!nop)
-		return -ENOMEM;
-
-	nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
-							GFP_KERNEL);
-	if (!nop->phy.otg)
-		return -ENOMEM;
-
 	if (dev->of_node) {
 		struct device_node *node = dev->of_node;
 
@@ -175,56 +235,18 @@
 		needs_reset = pdata->needs_reset;
 	}
 
-	nop->clk = devm_clk_get(&pdev->dev, "main_clk");
-	if (IS_ERR(nop->clk)) {
-		dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
-					PTR_ERR(nop->clk));
-	}
+	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
+	if (!nop)
+		return -ENOMEM;
 
-	if (!IS_ERR(nop->clk) && clk_rate) {
-		err = clk_set_rate(nop->clk, clk_rate);
-		if (err) {
-			dev_err(&pdev->dev, "Error setting clock rate\n");
-			return err;
-		}
-	}
 
-	if (!IS_ERR(nop->clk)) {
-		err = clk_prepare(nop->clk);
-		if (err) {
-			dev_err(&pdev->dev, "Error preparing clock\n");
-			return err;
-		}
-	}
+	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc,
+			needs_reset);
+	if (err)
+		return err;
 
-	nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
-	if (IS_ERR(nop->vcc)) {
-		dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
-					PTR_ERR(nop->vcc));
-		if (needs_vcc)
-			return -EPROBE_DEFER;
-	}
-
-	nop->reset = devm_regulator_get(&pdev->dev, "reset");
-	if (IS_ERR(nop->reset)) {
-		dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
-					PTR_ERR(nop->reset));
-		if (needs_reset)
-			return -EPROBE_DEFER;
-	}
-
-	nop->dev		= &pdev->dev;
-	nop->phy.dev		= nop->dev;
-	nop->phy.label		= "nop-xceiv";
-	nop->phy.set_suspend	= nop_set_suspend;
-	nop->phy.init		= nop_init;
-	nop->phy.shutdown	= nop_shutdown;
-	nop->phy.state		= OTG_STATE_UNDEFINED;
-	nop->phy.type		= type;
-
-	nop->phy.otg->phy		= &nop->phy;
-	nop->phy.otg->set_host		= nop_set_host;
-	nop->phy.otg->set_peripheral	= nop_set_peripheral;
+	nop->phy.init		= usb_gen_phy_init;
+	nop->phy.shutdown	= usb_gen_phy_shutdown;
 
 	err = usb_add_phy_dev(&nop->phy);
 	if (err) {
@@ -235,23 +257,18 @@
 
 	platform_set_drvdata(pdev, nop);
 
-	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
-
 	return 0;
 
 err_add:
-	if (!IS_ERR(nop->clk))
-		clk_unprepare(nop->clk);
+	usb_phy_gen_cleanup_phy(nop);
 	return err;
 }
 
-static int nop_usb_xceiv_remove(struct platform_device *pdev)
+static int usb_phy_gen_xceiv_remove(struct platform_device *pdev)
 {
-	struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
+	struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev);
 
-	if (!IS_ERR(nop->clk))
-		clk_unprepare(nop->clk);
-
+	usb_phy_gen_cleanup_phy(nop);
 	usb_remove_phy(&nop->phy);
 
 	return 0;
@@ -264,29 +281,29 @@
 
 MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
 
-static struct platform_driver nop_usb_xceiv_driver = {
-	.probe		= nop_usb_xceiv_probe,
-	.remove		= nop_usb_xceiv_remove,
+static struct platform_driver usb_phy_gen_xceiv_driver = {
+	.probe		= usb_phy_gen_xceiv_probe,
+	.remove		= usb_phy_gen_xceiv_remove,
 	.driver		= {
-		.name	= "nop_usb_xceiv",
+		.name	= "usb_phy_gen_xceiv",
 		.owner	= THIS_MODULE,
 		.of_match_table = nop_xceiv_dt_ids,
 	},
 };
 
-static int __init nop_usb_xceiv_init(void)
+static int __init usb_phy_gen_xceiv_init(void)
 {
-	return platform_driver_register(&nop_usb_xceiv_driver);
+	return platform_driver_register(&usb_phy_gen_xceiv_driver);
 }
-subsys_initcall(nop_usb_xceiv_init);
+subsys_initcall(usb_phy_gen_xceiv_init);
 
-static void __exit nop_usb_xceiv_exit(void)
+static void __exit usb_phy_gen_xceiv_exit(void)
 {
-	platform_driver_unregister(&nop_usb_xceiv_driver);
+	platform_driver_unregister(&usb_phy_gen_xceiv_driver);
 }
-module_exit(nop_usb_xceiv_exit);
+module_exit(usb_phy_gen_xceiv_exit);
 
-MODULE_ALIAS("platform:nop_usb_xceiv");
+MODULE_ALIAS("platform:usb_phy_gen_xceiv");
 MODULE_AUTHOR("Texas Instruments Inc");
 MODULE_DESCRIPTION("NOP USB Transceiver driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
new file mode 100644
index 0000000..61687d5
--- /dev/null
+++ b/drivers/usb/phy/phy-generic.h
@@ -0,0 +1,20 @@
+#ifndef _PHY_GENERIC_H_
+#define _PHY_GENERIC_H_
+
+struct usb_phy_gen_xceiv {
+	struct usb_phy phy;
+	struct device *dev;
+	struct clk *clk;
+	struct regulator *vcc;
+	struct regulator *reset;
+};
+
+int usb_gen_phy_init(struct usb_phy *phy);
+void usb_gen_phy_shutdown(struct usb_phy *phy);
+
+int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
+		enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
+		bool needs_reset);
+void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop);
+
+#endif
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 8443335..b2f29c9 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -101,7 +101,7 @@
 {
 	struct gpio_vbus_data *gpio_vbus =
 		container_of(work, struct gpio_vbus_data, work.work);
-	struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
+	struct gpio_vbus_mach_info *pdata = dev_get_platdata(gpio_vbus->dev);
 	int gpio, status, vbus;
 
 	if (!gpio_vbus->phy.otg->gadget)
@@ -155,7 +155,7 @@
 static irqreturn_t gpio_vbus_irq(int irq, void *data)
 {
 	struct platform_device *pdev = data;
-	struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+	struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
 	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
 	struct usb_otg *otg = gpio_vbus->phy.otg;
 
@@ -182,7 +182,7 @@
 
 	gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
 	pdev = to_platform_device(gpio_vbus->dev);
-	pdata = gpio_vbus->dev->platform_data;
+	pdata = dev_get_platdata(gpio_vbus->dev);
 	gpio = pdata->gpio_pullup;
 
 	if (!gadget) {
@@ -243,7 +243,7 @@
 
 static int __init gpio_vbus_probe(struct platform_device *pdev)
 {
-	struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+	struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
 	struct gpio_vbus_data *gpio_vbus;
 	struct resource *res;
 	int err, gpio, irq;
@@ -352,7 +352,7 @@
 static int __exit gpio_vbus_remove(struct platform_device *pdev)
 {
 	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
-	struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+	struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);
 	int gpio = pdata->gpio_vbus;
 
 	device_init_wakeup(&pdev->dev, 0);
diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index ae481af..d3a5160 100644
--- a/drivers/usb/phy/phy-isp1301-omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -40,9 +40,7 @@
 
 #include <mach/usb.h>
 
-#ifndef	DEBUG
-#undef	VERBOSE
-#endif
+#undef VERBOSE
 
 
 #define	DRIVER_VERSION	"24 August 2004"
@@ -387,7 +385,6 @@
 static void
 dump_regs(struct isp1301 *isp, const char *label)
 {
-#ifdef	DEBUG
 	u8	ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1);
 	u8	status = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
 	u8	src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
@@ -396,7 +393,6 @@
 		omap_readl(OTG_CTRL), label, state_name(isp),
 		ctrl, status, src);
 	/* mode control and irq enables don't change much */
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index d08f334..e9d4cd9 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -1419,7 +1419,7 @@
 	struct usb_phy *phy;
 
 	dev_info(&pdev->dev, "msm_otg probe\n");
-	if (!pdev->dev.platform_data) {
+	if (!dev_get_platdata(&pdev->dev)) {
 		dev_err(&pdev->dev, "No platform data given. Bailing out\n");
 		return -ENODEV;
 	}
@@ -1436,7 +1436,7 @@
 		return -ENOMEM;
 	}
 
-	motg->pdata = pdev->dev.platform_data;
+	motg->pdata = dev_get_platdata(&pdev->dev);
 	phy = &motg->phy;
 	phy->dev = &pdev->dev;
 
diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c
index 1568ea6..d317903 100644
--- a/drivers/usb/phy/phy-mv-u3d-usb.c
+++ b/drivers/usb/phy/phy-mv-u3d-usb.c
@@ -82,7 +82,7 @@
 	writel_relaxed(value, data);
 }
 
-void mv_u3d_phy_shutdown(struct usb_phy *phy)
+static void mv_u3d_phy_shutdown(struct usb_phy *phy)
 {
 	struct mv_u3d_phy *mv_u3d_phy;
 	void __iomem *base;
@@ -271,7 +271,7 @@
 	void __iomem	*phy_base;
 	int	ret;
 
-	pdata = pdev->dev.platform_data;
+	pdata = dev_get_platdata(&pdev->dev);
 	if (!pdata) {
 		dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
 		return -EINVAL;
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index 4a6b03c..98f6ac6 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -653,7 +653,7 @@
 	.attrs = inputs_attrs,
 };
 
-int mv_otg_remove(struct platform_device *pdev)
+static int mv_otg_remove(struct platform_device *pdev)
 {
 	struct mv_otg *mvotg = platform_get_drvdata(pdev);
 
@@ -673,7 +673,7 @@
 
 static int mv_otg_probe(struct platform_device *pdev)
 {
-	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct mv_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
 	struct mv_otg *mvotg;
 	struct usb_otg *otg;
 	struct resource *r;
@@ -893,7 +893,7 @@
 
 static struct platform_driver mv_otg_driver = {
 	.probe = mv_otg_probe,
-	.remove = __exit_p(mv_otg_remove),
+	.remove = mv_otg_remove,
 	.driver = {
 		   .owner = THIS_MODULE,
 		   .name = driver_name,
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index bd601c5..fdd33b4 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -41,11 +41,14 @@
 
 #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
 
-static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
+static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
 {
+	int ret;
 	void __iomem *base = mxs_phy->phy.io_priv;
 
-	stmp_reset_block(base + HW_USBPHY_CTRL);
+	ret = stmp_reset_block(base + HW_USBPHY_CTRL);
+	if (ret)
+		return ret;
 
 	/* Power up the PHY */
 	writel(0, base + HW_USBPHY_PWD);
@@ -54,6 +57,8 @@
 	writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
 	       BM_USBPHY_CTRL_ENUTMILEVEL3,
 	       base + HW_USBPHY_CTRL_SET);
+
+	return 0;
 }
 
 static int mxs_phy_init(struct usb_phy *phy)
@@ -61,9 +66,7 @@
 	struct mxs_phy *mxs_phy = to_mxs_phy(phy);
 
 	clk_prepare_enable(mxs_phy->clk);
-	mxs_phy_hw_init(mxs_phy);
-
-	return 0;
+	return mxs_phy_hw_init(mxs_phy);
 }
 
 static void mxs_phy_shutdown(struct usb_phy *phy)
diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c
index 1419ced..a4dda8e 100644
--- a/drivers/usb/phy/phy-omap-control.c
+++ b/drivers/usb/phy/phy-omap-control.c
@@ -197,7 +197,8 @@
 {
 	struct resource	*res;
 	struct device_node *np = pdev->dev.of_node;
-	struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct omap_control_usb_platform_data *pdata =
+			dev_get_platdata(&pdev->dev);
 
 	control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
 		GFP_KERNEL);
diff --git a/drivers/usb/phy/phy-omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c
index 844ab68..d266861 100644
--- a/drivers/usb/phy/phy-omap-usb2.c
+++ b/drivers/usb/phy/phy-omap-usb2.c
@@ -98,8 +98,8 @@
 
 static int omap_usb2_suspend(struct usb_phy *x, int suspend)
 {
-	u32 ret;
 	struct omap_usb *phy = phy_to_omapusb(x);
+	int ret;
 
 	if (suspend && !phy->is_suspended) {
 		omap_control_usb_phy_power(phy->control_dev, 0);
@@ -108,8 +108,7 @@
 	} else if (!suspend && phy->is_suspended) {
 		ret = pm_runtime_get_sync(phy->dev);
 		if (ret < 0) {
-			dev_err(phy->dev, "get_sync failed with err %d\n",
-									ret);
+			dev_err(phy->dev, "get_sync failed with err %d\n", ret);
 			return ret;
 		}
 		omap_control_usb_phy_power(phy->control_dev, 1);
@@ -209,9 +208,9 @@
 
 static int omap_usb2_runtime_resume(struct device *dev)
 {
-	u32 ret = 0;
 	struct platform_device	*pdev = to_platform_device(dev);
 	struct omap_usb	*phy = platform_get_drvdata(pdev);
+	int ret;
 
 	ret = clk_enable(phy->wkupclk);
 	if (ret < 0) {
diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c
index a2fb30b..fc15694 100644
--- a/drivers/usb/phy/phy-omap-usb3.c
+++ b/drivers/usb/phy/phy-omap-usb3.c
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 #include <linux/usb/omap_control_usb.h>
 
-#define	NUM_SYS_CLKS		6
 #define	PLL_STATUS		0x00000004
 #define	PLL_GO			0x00000008
 #define	PLL_CONFIGURATION1	0x0000000C
@@ -57,26 +56,32 @@
  */
 # define PLL_IDLE_TIME  100;
 
-enum sys_clk_rate {
-	CLK_RATE_UNDEFINED = -1,
-	CLK_RATE_12MHZ,
-	CLK_RATE_16MHZ,
-	CLK_RATE_19MHZ,
-	CLK_RATE_20MHZ,
-	CLK_RATE_26MHZ,
-	CLK_RATE_38MHZ
+struct usb_dpll_map {
+	unsigned long rate;
+	struct usb_dpll_params params;
 };
 
-static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = {
-	{1250, 5, 4, 20, 0},		/* 12 MHz */
-	{3125, 20, 4, 20, 0},		/* 16.8 MHz */
-	{1172, 8, 4, 20, 65537},	/* 19.2 MHz */
-	{1000, 7, 4, 10, 0},            /* 20 MHz */
-	{1250, 12, 4, 20, 0},		/* 26 MHz */
-	{3125, 47, 4, 20, 92843},	/* 38.4 MHz */
-
+static struct usb_dpll_map dpll_map[] = {
+	{12000000, {1250, 5, 4, 20, 0} },	/* 12 MHz */
+	{16800000, {3125, 20, 4, 20, 0} },	/* 16.8 MHz */
+	{19200000, {1172, 8, 4, 20, 65537} },	/* 19.2 MHz */
+	{20000000, {1000, 7, 4, 10, 0} },	/* 20 MHz */
+	{26000000, {1250, 12, 4, 20, 0} },	/* 26 MHz */
+	{38400000, {3125, 47, 4, 20, 92843} },	/* 38.4 MHz */
 };
 
+static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dpll_map); i++) {
+		if (rate == dpll_map[i].rate)
+			return &dpll_map[i].params;
+	}
+
+	return 0;
+}
+
 static int omap_usb3_suspend(struct usb_phy *x, int suspend)
 {
 	struct omap_usb *phy = phy_to_omapusb(x);
@@ -116,26 +121,6 @@
 	return 0;
 }
 
-static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate)
-{
-	switch (rate) {
-	case 12000000:
-		return CLK_RATE_12MHZ;
-	case 16800000:
-		return CLK_RATE_16MHZ;
-	case 19200000:
-		return CLK_RATE_19MHZ;
-	case 20000000:
-		return CLK_RATE_20MHZ;
-	case 26000000:
-		return CLK_RATE_26MHZ;
-	case 38400000:
-		return CLK_RATE_38MHZ;
-	default:
-		return CLK_RATE_UNDEFINED;
-	}
-}
-
 static void omap_usb_dpll_relock(struct omap_usb *phy)
 {
 	u32		val;
@@ -155,39 +140,39 @@
 {
 	u32			val;
 	unsigned long		rate;
-	enum sys_clk_rate	clk_index;
+	struct usb_dpll_params *dpll_params;
 
-	rate		= clk_get_rate(phy->sys_clk);
-	clk_index	= __get_sys_clk_index(rate);
-
-	if (clk_index == CLK_RATE_UNDEFINED) {
-		pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate);
+	rate = clk_get_rate(phy->sys_clk);
+	dpll_params = omap_usb3_get_dpll_params(rate);
+	if (!dpll_params) {
+		dev_err(phy->dev,
+			  "No DPLL configuration for %lu Hz SYS CLK\n", rate);
 		return -EINVAL;
 	}
 
 	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 	val &= ~PLL_REGN_MASK;
-	val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT;
+	val |= dpll_params->n << PLL_REGN_SHIFT;
 	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 
 	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
 	val &= ~PLL_SELFREQDCO_MASK;
-	val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT;
+	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
 	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 
 	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 	val &= ~PLL_REGM_MASK;
-	val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT;
+	val |= dpll_params->m << PLL_REGM_SHIFT;
 	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 
 	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
 	val &= ~PLL_REGM_F_MASK;
-	val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT;
+	val |= dpll_params->mf << PLL_REGM_F_SHIFT;
 	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
 
 	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
 	val &= ~PLL_SD_MASK;
-	val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT;
+	val |= dpll_params->sd << PLL_SD_SHIFT;
 	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
 
 	omap_usb_dpll_relock(phy);
@@ -198,8 +183,12 @@
 static int omap_usb3_init(struct usb_phy *x)
 {
 	struct omap_usb	*phy = phy_to_omapusb(x);
+	int ret;
 
-	omap_usb_dpll_lock(phy);
+	ret = omap_usb_dpll_lock(phy);
+	if (ret)
+		return ret;
+
 	omap_control_usb3_phy_power(phy->control_dev, 1);
 
 	return 0;
diff --git a/drivers/usb/phy/phy-rcar-usb.c b/drivers/usb/phy/phy-rcar-usb.c
index ae90940..33265a5 100644
--- a/drivers/usb/phy/phy-rcar-usb.c
+++ b/drivers/usb/phy/phy-rcar-usb.c
@@ -83,7 +83,7 @@
 {
 	struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
 	struct device *dev = phy->dev;
-	struct rcar_phy_platform_data *pdata = dev->platform_data;
+	struct rcar_phy_platform_data *pdata = dev_get_platdata(dev);
 	void __iomem *reg0 = priv->reg0;
 	void __iomem *reg1 = priv->reg1;
 	static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
@@ -184,17 +184,12 @@
 	void __iomem *reg0, *reg1 = NULL;
 	int ret;
 
-	if (!pdev->dev.platform_data) {
+	if (!dev_get_platdata(&pdev->dev)) {
 		dev_err(dev, "No platform data\n");
 		return -EINVAL;
 	}
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res0) {
-		dev_err(dev, "Not enough platform resources\n");
-		return -EINVAL;
-	}
-
 	reg0 = devm_ioremap_resource(dev, res0);
 	if (IS_ERR(reg0))
 		return PTR_ERR(reg0);
diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c
index 758b86d..ff70e4b 100644
--- a/drivers/usb/phy/phy-samsung-usb2.c
+++ b/drivers/usb/phy/phy-samsung-usb2.c
@@ -359,7 +359,7 @@
 {
 	struct samsung_usbphy *sphy;
 	struct usb_otg *otg;
-	struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+	struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev);
 	const struct samsung_usbphy_drvdata *drv_data;
 	struct device *dev = &pdev->dev;
 	struct resource *phy_mem;
diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c
index 300e0cf..c6eb222 100644
--- a/drivers/usb/phy/phy-samsung-usb3.c
+++ b/drivers/usb/phy/phy-samsung-usb3.c
@@ -231,7 +231,7 @@
 static int samsung_usb3phy_probe(struct platform_device *pdev)
 {
 	struct samsung_usbphy *sphy;
-	struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+	struct samsung_usbphy_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device *dev = &pdev->dev;
 	struct resource *phy_mem;
 	void __iomem	*phy_base;
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index cec0855..e9cb1cb 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -28,20 +28,28 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
+#include <linux/usb/of.h>
 #include <asm/mach-types.h>
 #include <linux/usb/ehci_def.h>
 #include <linux/usb/tegra_usb_phy.h>
+#include <linux/regulator/consumer.h>
 
 #define ULPI_VIEWPORT		0x170
 
-/* PORTSC registers */
+/* PORTSC PTS/PHCD bits, Tegra20 only */
 #define TEGRA_USB_PORTSC1				0x184
 #define TEGRA_USB_PORTSC1_PTS(x)			(((x) & 0x3) << 30)
 #define TEGRA_USB_PORTSC1_PHCD				(1 << 23)
 
+/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */
+#define TEGRA_USB_HOSTPC1_DEVLC		0x1b4
+#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x)	(((x) & 0x7) << 29)
+#define TEGRA_USB_HOSTPC1_DEVLC_PHCD	(1 << 22)
+
 /* Bits of PORTSC1, which will get cleared by writing 1 into them */
 #define TEGRA_PORTSC1_RWC_BITS	(PORT_CSC | PORT_PEC | PORT_OCC)
 
@@ -84,16 +92,22 @@
 
 #define UTMIP_XCVR_CFG0		0x808
 #define   UTMIP_XCVR_SETUP(x)			(((x) & 0xf) << 0)
+#define   UTMIP_XCVR_SETUP_MSB(x)		((((x) & 0x70) >> 4) << 22)
 #define   UTMIP_XCVR_LSRSLEW(x)			(((x) & 0x3) << 8)
 #define   UTMIP_XCVR_LSFSLEW(x)			(((x) & 0x3) << 10)
 #define   UTMIP_FORCE_PD_POWERDOWN		(1 << 14)
 #define   UTMIP_FORCE_PD2_POWERDOWN		(1 << 16)
 #define   UTMIP_FORCE_PDZI_POWERDOWN		(1 << 18)
-#define   UTMIP_XCVR_HSSLEW_MSB(x)		(((x) & 0x7f) << 25)
+#define   UTMIP_XCVR_LSBIAS_SEL			(1 << 21)
+#define   UTMIP_XCVR_HSSLEW(x)			(((x) & 0x3) << 4)
+#define   UTMIP_XCVR_HSSLEW_MSB(x)		((((x) & 0x1fc) >> 2) << 25)
 
 #define UTMIP_BIAS_CFG0		0x80c
 #define   UTMIP_OTGPD			(1 << 11)
 #define   UTMIP_BIASPD			(1 << 10)
+#define   UTMIP_HSSQUELCH_LEVEL(x)	(((x) & 0x3) << 0)
+#define   UTMIP_HSDISCON_LEVEL(x)	(((x) & 0x3) << 2)
+#define   UTMIP_HSDISCON_LEVEL_MSB(x)	((((x) & 0x4) >> 2) << 24)
 
 #define UTMIP_HSRX_CFG0		0x810
 #define   UTMIP_ELASTIC_LIMIT(x)	(((x) & 0x1f) << 10)
@@ -137,6 +151,12 @@
 #define UTMIP_BIAS_CFG1		0x83c
 #define   UTMIP_BIAS_PDTRK_COUNT(x)	(((x) & 0x1f) << 3)
 
+/* For Tegra30 and above only, the address is different in Tegra20 */
+#define USB_USBMODE		0x1f8
+#define   USB_USBMODE_MASK		(3 << 0)
+#define   USB_USBMODE_HOST		(3 << 0)
+#define   USB_USBMODE_DEVICE		(2 << 0)
+
 static DEFINE_SPINLOCK(utmip_pad_lock);
 static int utmip_pad_count;
 
@@ -184,36 +204,22 @@
 	},
 };
 
-static struct tegra_utmip_config utmip_default[] = {
-	[0] = {
-		.hssync_start_delay = 9,
-		.idle_wait_delay = 17,
-		.elastic_limit = 16,
-		.term_range_adj = 6,
-		.xcvr_setup = 9,
-		.xcvr_lsfslew = 1,
-		.xcvr_lsrslew = 1,
-	},
-	[2] = {
-		.hssync_start_delay = 9,
-		.idle_wait_delay = 17,
-		.elastic_limit = 16,
-		.term_range_adj = 6,
-		.xcvr_setup = 9,
-		.xcvr_lsfslew = 2,
-		.xcvr_lsrslew = 2,
-	},
-};
-
 static void set_pts(struct tegra_usb_phy *phy, u8 pts_val)
 {
 	void __iomem *base = phy->regs;
 	unsigned long val;
 
-	val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
-	val &= ~TEGRA_USB_PORTSC1_PTS(3);
-	val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3);
-	writel(val, base + TEGRA_USB_PORTSC1);
+	if (phy->soc_config->has_hostpc) {
+		val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
+		val &= ~TEGRA_USB_HOSTPC1_DEVLC_PTS(~0);
+		val |= TEGRA_USB_HOSTPC1_DEVLC_PTS(pts_val);
+		writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
+	} else {
+		val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
+		val &= ~TEGRA_USB_PORTSC1_PTS(~0);
+		val |= TEGRA_USB_PORTSC1_PTS(pts_val);
+		writel(val, base + TEGRA_USB_PORTSC1);
+	}
 }
 
 static void set_phcd(struct tegra_usb_phy *phy, bool enable)
@@ -221,17 +227,26 @@
 	void __iomem *base = phy->regs;
 	unsigned long val;
 
-	val = readl(base + TEGRA_USB_PORTSC1) & ~TEGRA_PORTSC1_RWC_BITS;
-	if (enable)
-		val |= TEGRA_USB_PORTSC1_PHCD;
-	else
-		val &= ~TEGRA_USB_PORTSC1_PHCD;
-	writel(val, base + TEGRA_USB_PORTSC1);
+	if (phy->soc_config->has_hostpc) {
+		val = readl(base + TEGRA_USB_HOSTPC1_DEVLC);
+		if (enable)
+			val |= TEGRA_USB_HOSTPC1_DEVLC_PHCD;
+		else
+			val &= ~TEGRA_USB_HOSTPC1_DEVLC_PHCD;
+		writel(val, base + TEGRA_USB_HOSTPC1_DEVLC);
+	} else {
+		val = readl(base + TEGRA_USB_PORTSC1) & ~PORT_RWC_BITS;
+		if (enable)
+			val |= TEGRA_USB_PORTSC1_PHCD;
+		else
+			val &= ~TEGRA_USB_PORTSC1_PHCD;
+		writel(val, base + TEGRA_USB_PORTSC1);
+	}
 }
 
 static int utmip_pad_open(struct tegra_usb_phy *phy)
 {
-	phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads");
+	phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads");
 	if (IS_ERR(phy->pad_clk)) {
 		pr_err("%s: can't get utmip pad clock\n", __func__);
 		return PTR_ERR(phy->pad_clk);
@@ -244,6 +259,7 @@
 {
 	unsigned long val, flags;
 	void __iomem *base = phy->pad_regs;
+	struct tegra_utmip_config *config = phy->config;
 
 	clk_prepare_enable(phy->pad_clk);
 
@@ -252,6 +268,16 @@
 	if (utmip_pad_count++ == 0) {
 		val = readl(base + UTMIP_BIAS_CFG0);
 		val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+
+		if (phy->soc_config->requires_extra_tuning_parameters) {
+			val &= ~(UTMIP_HSSQUELCH_LEVEL(~0) |
+				UTMIP_HSDISCON_LEVEL(~0) |
+				UTMIP_HSDISCON_LEVEL_MSB(~0));
+
+			val |= UTMIP_HSSQUELCH_LEVEL(config->hssquelch_level);
+			val |= UTMIP_HSDISCON_LEVEL(config->hsdiscon_level);
+			val |= UTMIP_HSDISCON_LEVEL_MSB(config->hsdiscon_level);
+		}
 		writel(val, base + UTMIP_BIAS_CFG0);
 	}
 
@@ -361,7 +387,7 @@
 	}
 
 	val = readl(base + UTMIP_TX_CFG0);
-	val &= ~UTMIP_FS_PREABMLE_J;
+	val |= UTMIP_FS_PREABMLE_J;
 	writel(val, base + UTMIP_TX_CFG0);
 
 	val = readl(base + UTMIP_HSRX_CFG0);
@@ -384,34 +410,56 @@
 	val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
 	writel(val, base + UTMIP_MISC_CFG0);
 
-	val = readl(base + UTMIP_MISC_CFG1);
-	val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
-	val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
-		UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
-	writel(val, base + UTMIP_MISC_CFG1);
+	if (!phy->soc_config->utmi_pll_config_in_car_module) {
+		val = readl(base + UTMIP_MISC_CFG1);
+		val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) |
+			UTMIP_PLLU_STABLE_COUNT(~0));
+		val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+			UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+		writel(val, base + UTMIP_MISC_CFG1);
 
-	val = readl(base + UTMIP_PLL_CFG1);
-	val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
-	val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
-		UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
-	writel(val, base + UTMIP_PLL_CFG1);
+		val = readl(base + UTMIP_PLL_CFG1);
+		val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) |
+			UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+		val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+			UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+		writel(val, base + UTMIP_PLL_CFG1);
+	}
 
-	if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+	if (phy->mode == USB_DR_MODE_PERIPHERAL) {
 		val = readl(base + USB_SUSP_CTRL);
 		val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
 		writel(val, base + USB_SUSP_CTRL);
+
+		val = readl(base + UTMIP_BAT_CHRG_CFG0);
+		val &= ~UTMIP_PD_CHRG;
+		writel(val, base + UTMIP_BAT_CHRG_CFG0);
+	} else {
+		val = readl(base + UTMIP_BAT_CHRG_CFG0);
+		val |= UTMIP_PD_CHRG;
+		writel(val, base + UTMIP_BAT_CHRG_CFG0);
 	}
 
 	utmip_pad_power_on(phy);
 
 	val = readl(base + UTMIP_XCVR_CFG0);
 	val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
-		 UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
-		 UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
-		 UTMIP_XCVR_HSSLEW_MSB(~0));
-	val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+		 UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_LSBIAS_SEL |
+		 UTMIP_XCVR_SETUP(~0) | UTMIP_XCVR_SETUP_MSB(~0) |
+		 UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0));
+
+	if (!config->xcvr_setup_use_fuses) {
+		val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+		val |= UTMIP_XCVR_SETUP_MSB(config->xcvr_setup);
+	}
 	val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
 	val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+
+	if (phy->soc_config->requires_extra_tuning_parameters) {
+		val &= ~(UTMIP_XCVR_HSSLEW(~0) | UTMIP_XCVR_HSSLEW_MSB(~0));
+		val |= UTMIP_XCVR_HSSLEW(config->xcvr_hsslew);
+		val |= UTMIP_XCVR_HSSLEW_MSB(config->xcvr_hsslew);
+	}
 	writel(val, base + UTMIP_XCVR_CFG0);
 
 	val = readl(base + UTMIP_XCVR_CFG1);
@@ -420,23 +468,19 @@
 	val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
 	writel(val, base + UTMIP_XCVR_CFG1);
 
-	val = readl(base + UTMIP_BAT_CHRG_CFG0);
-	val &= ~UTMIP_PD_CHRG;
-	writel(val, base + UTMIP_BAT_CHRG_CFG0);
-
 	val = readl(base + UTMIP_BIAS_CFG1);
 	val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
 	val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
 	writel(val, base + UTMIP_BIAS_CFG1);
 
-	if (phy->is_legacy_phy) {
-		val = readl(base + UTMIP_SPARE_CFG0);
-		if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
-			val &= ~FUSE_SETUP_SEL;
-		else
-			val |= FUSE_SETUP_SEL;
-		writel(val, base + UTMIP_SPARE_CFG0);
-	} else {
+	val = readl(base + UTMIP_SPARE_CFG0);
+	if (config->xcvr_setup_use_fuses)
+		val |= FUSE_SETUP_SEL;
+	else
+		val &= ~FUSE_SETUP_SEL;
+	writel(val, base + UTMIP_SPARE_CFG0);
+
+	if (!phy->is_legacy_phy) {
 		val = readl(base + USB_SUSP_CTRL);
 		val |= UTMIP_PHY_ENABLE;
 		writel(val, base + USB_SUSP_CTRL);
@@ -459,6 +503,16 @@
 
 	utmi_phy_clk_enable(phy);
 
+	if (phy->soc_config->requires_usbmode_setup) {
+		val = readl(base + USB_USBMODE);
+		val &= ~USB_USBMODE_MASK;
+		if (phy->mode == USB_DR_MODE_HOST)
+			val |= USB_USBMODE_HOST;
+		else
+			val |= USB_USBMODE_DEVICE;
+		writel(val, base + USB_USBMODE);
+	}
+
 	if (!phy->is_legacy_phy)
 		set_pts(phy, 0);
 
@@ -472,7 +526,7 @@
 
 	utmi_phy_clk_disable(phy);
 
-	if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+	if (phy->mode == USB_DR_MODE_PERIPHERAL) {
 		val = readl(base + USB_SUSP_CTRL);
 		val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
 		val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
@@ -560,13 +614,15 @@
 
 	ret = gpio_direction_output(phy->reset_gpio, 0);
 	if (ret < 0) {
-		dev_err(phy->dev, "gpio %d not set to 0\n", phy->reset_gpio);
+		dev_err(phy->u_phy.dev, "gpio %d not set to 0\n",
+			phy->reset_gpio);
 		return ret;
 	}
 	msleep(5);
 	ret = gpio_direction_output(phy->reset_gpio, 1);
 	if (ret < 0) {
-		dev_err(phy->dev, "gpio %d not set to 1\n", phy->reset_gpio);
+		dev_err(phy->u_phy.dev, "gpio %d not set to 1\n",
+			phy->reset_gpio);
 		return ret;
 	}
 
@@ -634,6 +690,9 @@
 {
 	struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
 
+	if (!IS_ERR(phy->vbus))
+		regulator_disable(phy->vbus);
+
 	clk_disable_unprepare(phy->pll_u);
 }
 
@@ -666,29 +725,30 @@
 {
 	int err;
 
-	phy->clk = devm_clk_get(phy->dev, "ulpi-link");
+	phy->clk = devm_clk_get(phy->u_phy.dev, "ulpi-link");
 	if (IS_ERR(phy->clk)) {
 		pr_err("%s: can't get ulpi clock\n", __func__);
 		return PTR_ERR(phy->clk);
 	}
 
-	err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b");
+	err = devm_gpio_request(phy->u_phy.dev, phy->reset_gpio,
+		"ulpi_phy_reset_b");
 	if (err < 0) {
-		dev_err(phy->dev, "request failed for gpio: %d\n",
+		dev_err(phy->u_phy.dev, "request failed for gpio: %d\n",
 		       phy->reset_gpio);
 		return err;
 	}
 
 	err = gpio_direction_output(phy->reset_gpio, 0);
 	if (err < 0) {
-		dev_err(phy->dev, "gpio %d direction not set to output\n",
+		dev_err(phy->u_phy.dev, "gpio %d direction not set to output\n",
 		       phy->reset_gpio);
 		return err;
 	}
 
 	phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
 	if (!phy->ulpi) {
-		dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
+		dev_err(phy->u_phy.dev, "otg_ulpi_create returned NULL\n");
 		err = -ENOMEM;
 		return err;
 	}
@@ -703,14 +763,7 @@
 	int i;
 	int err;
 
-	if (!phy->is_ulpi_phy) {
-		if (phy->is_legacy_phy)
-			phy->config = &utmip_default[0];
-		else
-			phy->config = &utmip_default[2];
-	}
-
-	phy->pll_u = devm_clk_get(phy->dev, "pll_u");
+	phy->pll_u = devm_clk_get(phy->u_phy.dev, "pll_u");
 	if (IS_ERR(phy->pll_u)) {
 		pr_err("Can't get pll_u clock\n");
 		return PTR_ERR(phy->pll_u);
@@ -733,6 +786,16 @@
 		goto fail;
 	}
 
+	if (!IS_ERR(phy->vbus)) {
+		err = regulator_enable(phy->vbus);
+		if (err) {
+			dev_err(phy->u_phy.dev,
+				"failed to enable usb vbus regulator: %d\n",
+				err);
+			goto fail;
+		}
+	}
+
 	if (phy->is_ulpi_phy)
 		err = ulpi_open(phy);
 	else
@@ -784,11 +847,138 @@
 }
 EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
 
+static int read_utmi_param(struct platform_device *pdev, const char *param,
+			   u8 *dest)
+{
+	u32 value;
+	int err = of_property_read_u32(pdev->dev.of_node, param, &value);
+	*dest = (u8)value;
+	if (err < 0)
+		dev_err(&pdev->dev, "Failed to read USB UTMI parameter %s: %d\n",
+			param, err);
+	return err;
+}
+
+static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
+			  struct platform_device *pdev)
+{
+	struct resource *res;
+	int err;
+	struct tegra_utmip_config *config;
+
+	tegra_phy->is_ulpi_phy = false;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
+		return  -ENXIO;
+	}
+
+	tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
+		resource_size(res));
+	if (!tegra_phy->regs) {
+		dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
+		return -ENOMEM;
+	}
+
+	tegra_phy->config = devm_kzalloc(&pdev->dev,
+		sizeof(*tegra_phy->config), GFP_KERNEL);
+	if (!tegra_phy->config) {
+		dev_err(&pdev->dev,
+			"unable to allocate memory for USB UTMIP config\n");
+		return -ENOMEM;
+	}
+
+	config = tegra_phy->config;
+
+	err = read_utmi_param(pdev, "nvidia,hssync-start-delay",
+		&config->hssync_start_delay);
+	if (err < 0)
+		return err;
+
+	err = read_utmi_param(pdev, "nvidia,elastic-limit",
+		&config->elastic_limit);
+	if (err < 0)
+		return err;
+
+	err = read_utmi_param(pdev, "nvidia,idle-wait-delay",
+		&config->idle_wait_delay);
+	if (err < 0)
+		return err;
+
+	err = read_utmi_param(pdev, "nvidia,term-range-adj",
+		&config->term_range_adj);
+	if (err < 0)
+		return err;
+
+	err = read_utmi_param(pdev, "nvidia,xcvr-lsfslew",
+		&config->xcvr_lsfslew);
+	if (err < 0)
+		return err;
+
+	err = read_utmi_param(pdev, "nvidia,xcvr-lsrslew",
+		&config->xcvr_lsrslew);
+	if (err < 0)
+		return err;
+
+	if (tegra_phy->soc_config->requires_extra_tuning_parameters) {
+		err = read_utmi_param(pdev, "nvidia,xcvr-hsslew",
+			&config->xcvr_hsslew);
+		if (err < 0)
+			return err;
+
+		err = read_utmi_param(pdev, "nvidia,hssquelch-level",
+			&config->hssquelch_level);
+		if (err < 0)
+			return err;
+
+		err = read_utmi_param(pdev, "nvidia,hsdiscon-level",
+			&config->hsdiscon_level);
+		if (err < 0)
+			return err;
+	}
+
+	config->xcvr_setup_use_fuses = of_property_read_bool(
+		pdev->dev.of_node, "nvidia,xcvr-setup-use-fuses");
+
+	if (!config->xcvr_setup_use_fuses) {
+		err = read_utmi_param(pdev, "nvidia,xcvr-setup",
+			&config->xcvr_setup);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct tegra_phy_soc_config tegra20_soc_config = {
+	.utmi_pll_config_in_car_module = false,
+	.has_hostpc = false,
+	.requires_usbmode_setup = false,
+	.requires_extra_tuning_parameters = false,
+};
+
+static const struct tegra_phy_soc_config tegra30_soc_config = {
+	.utmi_pll_config_in_car_module = true,
+	.has_hostpc = true,
+	.requires_usbmode_setup = true,
+	.requires_extra_tuning_parameters = true,
+};
+
+static struct of_device_id tegra_usb_phy_id_table[] = {
+	{ .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },
+	{ .compatible = "nvidia,tegra20-usb-phy", .data = &tegra20_soc_config },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+
 static int tegra_usb_phy_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
 	struct resource *res;
 	struct tegra_usb_phy *tegra_phy = NULL;
 	struct device_node *np = pdev->dev.of_node;
+	enum usb_phy_interface phy_type;
 	int err;
 
 	tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
@@ -797,6 +987,13 @@
 		return -ENOMEM;
 	}
 
+	match = of_match_device(tegra_usb_phy_id_table, &pdev->dev);
+	if (!match) {
+		dev_err(&pdev->dev, "Error: No device match found\n");
+		return -ENODEV;
+	}
+	tegra_phy->soc_config = match->data;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "Failed to get I/O memory\n");
@@ -813,23 +1010,15 @@
 	tegra_phy->is_legacy_phy =
 		of_property_read_bool(np, "nvidia,has-legacy-mode");
 
-	err = of_property_match_string(np, "phy_type", "ulpi");
-	if (err < 0) {
-		tegra_phy->is_ulpi_phy = false;
+	phy_type = of_usb_get_phy_mode(np);
+	switch (phy_type) {
+	case USBPHY_INTERFACE_MODE_UTMI:
+		err = utmi_phy_probe(tegra_phy, pdev);
+		if (err < 0)
+			return err;
+		break;
 
-		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-		if (!res) {
-			dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
-			return  -ENXIO;
-		}
-
-		tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
-			resource_size(res));
-		if (!tegra_phy->regs) {
-			dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
-			return -ENOMEM;
-		}
-	} else {
+	case USBPHY_INTERFACE_MODE_ULPI:
 		tegra_phy->is_ulpi_phy = true;
 
 		tegra_phy->reset_gpio =
@@ -839,19 +1028,35 @@
 				tegra_phy->reset_gpio);
 			return tegra_phy->reset_gpio;
 		}
+		tegra_phy->config = NULL;
+		break;
+
+	default:
+		dev_err(&pdev->dev, "phy_type is invalid or unsupported\n");
+		return -EINVAL;
 	}
 
-	err = of_property_match_string(np, "dr_mode", "otg");
-	if (err < 0) {
-		err = of_property_match_string(np, "dr_mode", "peripheral");
-		if (err < 0)
-			tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST;
-		else
-			tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
-	} else
-		tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG;
+	if (of_find_property(np, "dr_mode", NULL))
+		tegra_phy->mode = of_usb_get_dr_mode(np);
+	else
+		tegra_phy->mode = USB_DR_MODE_HOST;
 
-	tegra_phy->dev = &pdev->dev;
+	if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) {
+		dev_err(&pdev->dev, "dr_mode is invalid\n");
+		return -EINVAL;
+	}
+
+	/* On some boards, the VBUS regulator doesn't need to be controlled */
+	if (of_find_property(np, "vbus-supply", NULL)) {
+		tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus");
+		if (IS_ERR(tegra_phy->vbus))
+			return PTR_ERR(tegra_phy->vbus);
+	} else {
+		dev_notice(&pdev->dev, "no vbus regulator");
+		tegra_phy->vbus = ERR_PTR(-ENODEV);
+	}
+
+	tegra_phy->u_phy.dev = &pdev->dev;
 	err = tegra_usb_phy_init(tegra_phy);
 	if (err < 0)
 		return err;
@@ -859,18 +1064,29 @@
 	tegra_phy->u_phy.shutdown = tegra_usb_phy_close;
 	tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
 
-	dev_set_drvdata(&pdev->dev, tegra_phy);
+	platform_set_drvdata(pdev, tegra_phy);
+
+	err = usb_add_phy_dev(&tegra_phy->u_phy);
+	if (err < 0) {
+		tegra_usb_phy_close(&tegra_phy->u_phy);
+		return err;
+	}
+
 	return 0;
 }
 
-static struct of_device_id tegra_usb_phy_id_table[] = {
-	{ .compatible = "nvidia,tegra20-usb-phy", },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
+static int tegra_usb_phy_remove(struct platform_device *pdev)
+{
+	struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev);
+
+	usb_remove_phy(&tegra_phy->u_phy);
+
+	return 0;
+}
 
 static struct platform_driver tegra_usb_phy_driver = {
 	.probe		= tegra_usb_phy_probe,
+	.remove		= tegra_usb_phy_remove,
 	.driver		= {
 		.name	= "tegra-phy",
 		.owner	= THIS_MODULE,
@@ -879,29 +1095,5 @@
 };
 module_platform_driver(tegra_usb_phy_driver);
 
-static int tegra_usb_phy_match(struct device *dev, void *data)
-{
-	struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev);
-	struct device_node *dn = data;
-
-	return (tegra_phy->dev->of_node == dn) ? 1 : 0;
-}
-
-struct usb_phy *tegra_usb_get_phy(struct device_node *dn)
-{
-	struct device *dev;
-	struct tegra_usb_phy *tegra_phy;
-
-	dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn,
-				 tegra_usb_phy_match);
-	if (!dev)
-		return ERR_PTR(-EPROBE_DEFER);
-
-	tegra_phy = dev_get_drvdata(dev);
-
-	return &tegra_phy->u_phy;
-}
-EXPORT_SYMBOL_GPL(tegra_usb_get_phy);
-
 MODULE_DESCRIPTION("Tegra USB PHY driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c
index 8f78d2d..90730c8 100644
--- a/drivers/usb/phy/phy-twl4030-usb.c
+++ b/drivers/usb/phy/phy-twl4030-usb.c
@@ -648,7 +648,7 @@
 
 static int twl4030_usb_probe(struct platform_device *pdev)
 {
-	struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+	struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
 	struct twl4030_usb	*twl;
 	int			status, err;
 	struct usb_otg		*otg;
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 1753bd3..16dbc93 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -324,7 +324,7 @@
 	int			status, err;
 	struct device_node	*np = pdev->dev.of_node;
 	struct device		*dev = &pdev->dev;
-	struct twl4030_usb_data	*pdata = dev->platform_data;
+	struct twl4030_usb_data	*pdata = dev_get_platdata(dev);
 
 	twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL);
 	if (!twl)
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index cfd2050..17267b0 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -416,7 +416,7 @@
  */
 static int usbhs_probe(struct platform_device *pdev)
 {
-	struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+	struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
 	struct renesas_usbhs_driver_callback *dfunc;
 	struct usbhs_priv *priv;
 	struct resource *res, *irq_res;
@@ -499,7 +499,7 @@
 		goto probe_end_fifo_exit;
 
 	/* dev_set_drvdata should be called after usbhs_mod_init */
-	dev_set_drvdata(&pdev->dev, priv);
+	platform_set_drvdata(pdev, priv);
 
 	/*
 	 * deviece reset here because
@@ -558,7 +558,7 @@
 static int usbhs_remove(struct platform_device *pdev)
 {
 	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
-	struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
+	struct renesas_usbhs_platform_info *info = dev_get_platdata(&pdev->dev);
 	struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
 
 	dev_dbg(&pdev->dev, "usb remove\n");
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 805940c..3385aeb 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -77,9 +77,9 @@
 		struct usbhsg_gpriv, mod)
 
 #define __usbhsg_for_each_uep(start, pos, g, i)	\
-	for (i = start, pos = (g)->uep + i;	\
-	     i < (g)->uep_size;			\
-	     i++, pos = (g)->uep + i)
+	for ((i) = start;					\
+	     ((i) < (g)->uep_size) && ((pos) = (g)->uep + (i));	\
+	     (i)++)
 
 #define usbhsg_for_each_uep(pos, gpriv, i)	\
 	__usbhsg_for_each_uep(1, pos, gpriv, i)
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index b868154..e40f565 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -111,9 +111,9 @@
 	container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
 
 #define __usbhsh_for_each_udev(start, pos, h, i)	\
-	for (i = start, pos = (h)->udev + i;		\
-	     i < USBHSH_DEVICE_MAX;			\
-	     i++, pos = (h)->udev + i)
+	for ((i) = start;						\
+	     ((i) < USBHSH_DEVICE_MAX) && ((pos) = (h)->udev + (i));	\
+	     (i)++)
 
 #define usbhsh_for_each_udev(pos, hpriv, i)	\
 	__usbhsh_for_each_udev(1, pos, hpriv, i)
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index b476fde..3e53498 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -54,9 +54,9 @@
  * pipe list
  */
 #define __usbhs_for_each_pipe(start, pos, info, i)	\
-	for (i = start, pos = (info)->pipe + i;		\
-	     i < (info)->size;				\
-	     i++, pos = (info)->pipe + i)
+	for ((i) = start;						\
+	     ((i) < (info)->size) && ((pos) = (info)->pipe + (i));	\
+	     (i)++)
 
 #define usbhs_for_each_pipe(pos, priv, i)			\
 	__usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i)
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 7eef9b3..c454bfa 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -51,6 +51,24 @@
 	  support" be compiled as a module for this driver to be used
 	  properly.
 
+config USB_SERIAL_SIMPLE
+	tristate "USB Serial Simple Driver"
+	help
+	  Say Y here to use the USB serial "simple" driver.  This driver
+	  handles a wide range of very simple devices, all in one
+	  driver.  Specifically, it supports:
+		- Suunto ANT+ USB device.
+		- Fundamental Software dongle.
+		- HP4x calculators
+		- a number of Motoroloa phones
+		- Siemens USB/MPI adapter.
+		- ViVOtech ViVOpay USB device.
+		- Infineon Modem Flashloader USB interface
+		- ZIO Motherboard USB serial interface
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called usb-serial-simple.
+
 config USB_SERIAL_AIRCABLE
 	tristate "USB AIRcable Bluetooth Dongle Driver"
 	help
@@ -158,14 +176,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ftdi_sio.
 
-config USB_SERIAL_FUNSOFT
-	tristate "USB Fundamental Software Dongle Driver"
-	---help---
-	  Say Y here if you want to use the Fundamental Software dongle.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called funsoft.
-
 config USB_SERIAL_VISOR
 	tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
 	help
@@ -462,15 +472,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mos7840.  If unsure, choose N.
 
-config USB_SERIAL_MOTOROLA
-	tristate "USB Motorola Phone modem driver"
-	---help---
-	  Say Y here if you want to use a Motorola phone with a USB
-	  connector as a modem link.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called moto_modem.  If unsure, choose N.
-
 config USB_SERIAL_NAVMAN
 	tristate "USB Navman GPS device"
 	help
@@ -525,14 +526,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called spcp8x5.
 
-config USB_SERIAL_HP4X
-        tristate "USB HP4x Calculators support"
-        help
-          Say Y here if you want to use an Hewlett-Packard 4x Calculator.
-
-          To compile this driver as a module, choose M here: the
-          module will be called hp4x.
-
 config USB_SERIAL_SAFE
 	tristate "USB Safe Serial (Encapsulated) Driver"
 
@@ -540,14 +533,6 @@
 	bool "USB Secure Encapsulated Driver - Padded"
 	depends on USB_SERIAL_SAFE
 
-config USB_SERIAL_SIEMENS_MPI
-	tristate "USB Siemens MPI driver"
-	help
-	  Say M here if you want to use a Siemens USB/MPI adapter.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called siemens_mpi.
-
 config USB_SERIAL_SIERRAWIRELESS
 	tristate "USB Sierra Wireless Driver"
 	help
@@ -639,14 +624,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called opticon.
 
-config USB_SERIAL_VIVOPAY_SERIAL
-        tristate "USB ViVOpay serial interface driver"
-        help
-          Say Y here if you want to use a ViVOtech ViVOpay USB device.
-
-          To compile this driver as a module, choose M here: the
-          module will be called vivopay-serial.
-
 config USB_SERIAL_XSENS_MT
 	tristate "Xsens motion tracker serial interface driver"
 	help
@@ -659,14 +636,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called xsens_mt.
 
-config USB_SERIAL_ZIO
-	tristate "ZIO Motherboard USB serial interface driver"
-	help
-	  Say Y here if you want to use ZIO Motherboard.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called zio.
-
 config USB_SERIAL_WISHBONE
 	tristate "USB-Wishbone adapter interface driver"
 	help
@@ -710,23 +679,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called quatech-serial.
 
-config USB_SERIAL_FLASHLOADER
-	tristate "Infineon Modem Flashloader USB interface driver"
-	help
-	  Say Y here if you want to download Infineon Modem
-	  via USB Flashloader serial driver.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called flashloader.
-
-config USB_SERIAL_SUUNTO
-	tristate "USB Suunto ANT+ driver"
-	help
-	  Say Y here if you want to use the Suunto ANT+ USB device.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called suunto.
-
 config USB_SERIAL_DEBUG
 	tristate "USB Debugging Device"
 	help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index a14a870..42670f0 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -24,9 +24,7 @@
 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
-obj-$(CONFIG_USB_SERIAL_HP4X)			+= hp4x.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)			+= ipaq.o
 obj-$(CONFIG_USB_SERIAL_IPW)			+= ipw.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
@@ -39,7 +37,6 @@
 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
 obj-$(CONFIG_USB_SERIAL_NAVMAN)			+= navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTICON)		+= opticon.o
@@ -50,11 +47,10 @@
 obj-$(CONFIG_USB_SERIAL_QUALCOMM)		+= qcserial.o
 obj-$(CONFIG_USB_SERIAL_QT2)			+= quatech2.o
 obj-$(CONFIG_USB_SERIAL_SAFE)			+= safe_serial.o
-obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)		+= siemens_mpi.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)		+= sierra.o
+obj-$(CONFIG_USB_SERIAL_SIMPLE)			+= usb-serial-simple.o
 obj-$(CONFIG_USB_SERIAL_SPCP8X5)		+= spcp8x5.o
 obj-$(CONFIG_USB_SERIAL_SSU100)			+= ssu100.o
-obj-$(CONFIG_USB_SERIAL_SUUNTO)			+= suunto.o
 obj-$(CONFIG_USB_SERIAL_SYMBOL)			+= symbolserial.o
 obj-$(CONFIG_USB_SERIAL_WWAN)			+= usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)			+= ti_usb_3410_5052.o
@@ -62,8 +58,5 @@
 obj-$(CONFIG_USB_SERIAL_WISHBONE)		+= wishbone-serial.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)		+= whiteheat.o
 obj-$(CONFIG_USB_SERIAL_XIRCOM)			+= keyspan_pda.o
-obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)		+= vivopay-serial.o
 obj-$(CONFIG_USB_SERIAL_XSENS_MT)		+= xsens_mt.o
-obj-$(CONFIG_USB_SERIAL_ZIO)			+= zio.o
 obj-$(CONFIG_USB_SERIAL_ZTE)			+= zte_ev.o
-obj-$(CONFIG_USB_SERIAL_FLASHLOADER)		+= flashloader.o
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index f053b30..6335490 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -38,15 +38,14 @@
 	return 0;
 }
 
-static ssize_t show_port_number(struct device *dev,
+static ssize_t port_number_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 
 	return sprintf(buf, "%d\n", port->port_number);
 }
-
-static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+static DEVICE_ATTR_RO(port_number);
 
 static int usb_serial_device_probe(struct device *dev)
 {
@@ -122,7 +121,7 @@
 	return retval;
 }
 
-static ssize_t store_new_id(struct device_driver *driver,
+static ssize_t new_id_store(struct device_driver *driver,
 			    const char *buf, size_t count)
 {
 	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
@@ -135,17 +134,19 @@
 	return retval;
 }
 
-static ssize_t show_dynids(struct device_driver *driver, char *buf)
+static ssize_t new_id_show(struct device_driver *driver, char *buf)
 {
 	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
 
 	return usb_show_dynids(&usb_drv->dynids, buf);
 }
+static DRIVER_ATTR_RW(new_id);
 
-static struct driver_attribute drv_attrs[] = {
-	__ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id),
-	__ATTR_NULL,
+static struct attribute *usb_serial_drv_attrs[] = {
+	&driver_attr_new_id.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(usb_serial_drv);
 
 static void free_dynids(struct usb_serial_driver *drv)
 {
@@ -164,7 +165,7 @@
 	.match =	usb_serial_device_match,
 	.probe =	usb_serial_device_probe,
 	.remove =	usb_serial_device_remove,
-	.drv_attrs = 	drv_attrs,
+	.drv_groups = 	usb_serial_drv_groups,
 };
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index afb50ea..c69bb50 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -151,11 +151,7 @@
 
 		/* only call the device specific open if this
 		 * is the first time the port is opened */
-		if (serial->type->open)
-			retval = serial->type->open(NULL, port);
-		else
-			retval = usb_serial_generic_open(NULL, port);
-
+		retval = serial->type->open(NULL, port);
 		if (retval) {
 			dev_err(&port->dev, "could not open USB console port\n");
 			goto fail;
@@ -210,10 +206,10 @@
 	if (count == 0)
 		return;
 
-	pr_debug("%s - minor %d, %d byte(s)\n", __func__, port->minor, count);
+	dev_dbg(&port->dev, "%s - %d byte(s)\n", __func__, count);
 
 	if (!port->port.console) {
-		pr_debug("%s - port not opened\n", __func__);
+		dev_dbg(&port->dev, "%s - port not opened\n", __func__);
 		return;
 	}
 
@@ -230,21 +226,14 @@
 		}
 		/* pass on to the driver specific version of this function if
 		   it is available */
-		if (serial->type->write)
-			retval = serial->type->write(NULL, port, buf, i);
-		else
-			retval = usb_serial_generic_write(NULL, port, buf, i);
-		pr_debug("%s - return value : %d\n", __func__, retval);
+		retval = serial->type->write(NULL, port, buf, i);
+		dev_dbg(&port->dev, "%s - write: %d\n", __func__, retval);
 		if (lf) {
 			/* append CR after LF */
 			unsigned char cr = 13;
-			if (serial->type->write)
-				retval = serial->type->write(NULL,
-								port, &cr, 1);
-			else
-				retval = usb_serial_generic_write(NULL,
-								port, &cr, 1);
-			pr_debug("%s - return value : %d\n", __func__, retval);
+			retval = serial->type->write(NULL, port, &cr, 1);
+			dev_dbg(&port->dev, "%s - write cr: %d\n",
+							__func__, retval);
 		}
 		buf += i;
 		count -= i;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 0eae4ba..6987b53 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -670,9 +670,6 @@
 	unsigned int bits;
 	unsigned int modem_ctl[4];
 
-	if (!tty)
-		return;
-
 	cflag = tty->termios.c_cflag;
 	old_cflag = old_termios->c_cflag;
 
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index e948dc0..558605d 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -495,6 +495,8 @@
 	}
 	usb_set_serial_port_data(port, priv);
 
+	port->port.drain_delay = 256;
+
 	return 0;
 }
 
@@ -625,7 +627,7 @@
 							__func__, result);
 		cypress_set_dead(port);
 	}
-	port->port.drain_delay = 256;
+
 	return result;
 } /* cypress_open */
 
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 75e85cb..639a18f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -207,7 +207,6 @@
 		return result;
 	}
 
-	port->port.drain_delay = 256;
 	return 0;
 }
 
@@ -322,6 +321,8 @@
 
 	usb_set_serial_port_data(port, priv);
 
+	port->port.drain_delay = 256;
+
 	return 0;
 }
 
diff --git a/drivers/usb/serial/flashloader.c b/drivers/usb/serial/flashloader.c
deleted file mode 100644
index e6f5c10..0000000
--- a/drivers/usb/serial/flashloader.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Infineon Flashloader driver
- *
- * Copyright (C) 2013 Wei Shuai <cpuwolf@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/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x8087, 0x0716) },
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver flashloader_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"flashloader",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&flashloader_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index b65e657..c45f9c0 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -51,8 +51,6 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
-static __u16 vendor = FTDI_VID;
-static __u16 product;
 
 struct ftdi_private {
 	enum ftdi_chip_type chip_type;
@@ -144,8 +142,8 @@
 
 
 /*
- * Device ID not listed? Test via module params product/vendor or
- * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
+ * Device ID not listed? Test it using
+ * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
  */
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
@@ -906,7 +904,6 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
 	/* Crucible Devices */
 	{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
-	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
 
@@ -930,9 +927,6 @@
 #define FTDI_STATUS_B1_MASK	(FTDI_RS_BI)
 /* End TIOCMIWAIT */
 
-#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \
- | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP)
-
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_probe(struct usb_serial *serial,
 					const struct usb_device_id *id);
@@ -999,10 +993,6 @@
 #define WDR_TIMEOUT 5000 /* default urb timeout */
 #define WDR_SHORT_TIMEOUT 1000	/* shorter urb timeout */
 
-/* High and low are for DTR, RTS etc etc */
-#define HIGH 1
-#define LOW 0
-
 /*
  * ***************************************************************************
  * Utility functions
@@ -1571,8 +1561,8 @@
  * ***************************************************************************
  */
 
-static ssize_t show_latency_timer(struct device *dev,
-				struct device_attribute *attr, char *buf)
+static ssize_t latency_timer_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1582,11 +1572,10 @@
 		return sprintf(buf, "%i\n", priv->latency);
 }
 
-
 /* Write a new value of the latency timer, in units of milliseconds. */
-static ssize_t store_latency_timer(struct device *dev,
-			struct device_attribute *attr, const char *valbuf,
-			size_t count)
+static ssize_t latency_timer_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *valbuf, size_t count)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
@@ -1599,6 +1588,7 @@
 		return -EIO;
 	return count;
 }
+static DEVICE_ATTR_RW(latency_timer);
 
 /* Write an event character directly to the FTDI register.  The ASCII
    value is in the low 8 bits, with the enable bit in the 9th bit. */
@@ -1626,9 +1616,6 @@
 
 	return count;
 }
-
-static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer,
-							store_latency_timer);
 static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
 
 static int create_sysfs_attrs(struct usb_serial_port *port)
@@ -1867,7 +1854,6 @@
 
 static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
-	struct ktermios dummy;
 	struct usb_device *dev = port->serial->dev;
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 
@@ -1883,10 +1869,8 @@
 	   This is same behaviour as serial.c/rs_open() - Kuba */
 
 	/* ftdi_set_termios  will send usb control messages */
-	if (tty) {
-		memset(&dummy, 0, sizeof(dummy));
-		ftdi_set_termios(tty, port, &dummy);
-	}
+	if (tty)
+		ftdi_set_termios(tty, port, NULL);
 
 	return usb_serial_generic_open(tty, port);
 }
@@ -2215,7 +2199,7 @@
 			dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
 		mutex_unlock(&priv->cfg_lock);
 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
-		if (!old_termios || (old_termios->c_cflag & CBAUD) == B0)
+		if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
 			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 	}
 
@@ -2405,38 +2389,11 @@
 	return -ENOIOCTLCMD;
 }
 
-static int __init ftdi_init(void)
-{
-	if (vendor > 0 && product > 0) {
-		/* Add user specified VID/PID to reserved element of table. */
-		int i;
-		for (i = 0; id_table_combined[i].idVendor; i++)
-			;
-		id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-		id_table_combined[i].idVendor = vendor;
-		id_table_combined[i].idProduct = product;
-	}
-	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
-}
-
-static void __exit ftdi_exit(void)
-{
-	usb_serial_deregister_drivers(serial_drivers);
-}
-
-
-module_init(ftdi_init);
-module_exit(ftdi_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
-		__MODULE_STRING(FTDI_VID)")");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
 module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
deleted file mode 100644
index 9362f8f..0000000
--- a/drivers/usb/serial/funsoft.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Funsoft Serial USB driver
- *
- * Copyright (C) 2006 Greg Kroah-Hartman <gregkh@suse.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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x1404, 0xcddc) },
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver funsoft_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"funsoft",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&funsoft_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index ba45170..1f31e6b 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -460,12 +460,7 @@
 	/*
 	 * Use tty-port initialised flag to detect all hangups including the
 	 * one generated at USB-device disconnect.
-	 *
-	 * FIXME: Remove hupping check once tty_port_hangup calls shutdown
-	 *        (which clears the initialised flag) before wake up.
 	 */
-	if (test_bit(TTY_HUPPING, &tty->flags))
-		return true;
 	if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
 		return true;
 
@@ -496,12 +491,8 @@
 
 	ret = wait_event_interruptible(port->port.delta_msr_wait,
 			usb_serial_generic_msr_changed(tty, arg, &cnow));
-	if (!ret) {
-		if (test_bit(TTY_HUPPING, &tty->flags))
-			ret = -EIO;
-		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
-			ret = -EIO;
-	}
+	if (!ret && !test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+		ret = -EIO;
 
 	return ret;
 }
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
deleted file mode 100644
index 2cba60d..0000000
--- a/drivers/usb/serial/hp4x.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * HP4x Calculators Serial USB driver
- *
- * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- * See Documentation/usb/usb-serial.txt for more information on using this
- * driver
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "HP4x (48/49) Generic Serial driver"
-
-#define HP_VENDOR_ID 0x03f0
-#define HP49GP_PRODUCT_ID 0x0121
-
-static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
-	{ }					/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver hp49gp_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"hp4X",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&hp49gp_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index dc2803b..c91481d 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -56,9 +56,7 @@
 
 #define MAX_NAME_LEN		64
 
-#define CHASE_TIMEOUT		(5*HZ)		/* 5 seconds */
 #define OPEN_TIMEOUT		(5*HZ)		/* 5 seconds */
-#define COMMAND_TIMEOUT		(5*HZ)		/* 5 seconds */
 
 /* receive port state */
 enum RXSTATE {
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 60054e7..b7187bf 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -64,8 +64,6 @@
 
 #define EDGE_CLOSING_WAIT	4000	/* in .01 sec */
 
-#define EDGE_OUT_BUF_SIZE	1024
-
 
 /* Product information read from the Edgeport */
 struct product_info {
@@ -93,7 +91,6 @@
 	spinlock_t ep_lock;
 	int ep_read_urb_state;
 	int ep_write_urb_in_use;
-	struct kfifo write_fifo;
 };
 
 struct edgeport_serial {
@@ -1732,22 +1729,6 @@
 		return -ENODEV;
 
 	port_number = port->port_number;
-	switch (port_number) {
-	case 0:
-		edge_port->uart_base = UMPMEM_BASE_UART1;
-		edge_port->dma_address = UMPD_OEDB1_ADDRESS;
-		break;
-	case 1:
-		edge_port->uart_base = UMPMEM_BASE_UART2;
-		edge_port->dma_address = UMPD_OEDB2_ADDRESS;
-		break;
-	default:
-		dev_err(&port->dev, "Unknown port number!!!\n");
-		return -ENODEV;
-	}
-
-	dev_dbg(&port->dev, "%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
-		__func__, port_number, edge_port->uart_base, edge_port->dma_address);
 
 	dev = port->serial->dev;
 
@@ -1872,8 +1853,6 @@
 
 	++edge_serial->num_ports_open;
 
-	port->port.drain_delay = 1;
-
 	goto release_es_lock;
 
 unlink_int_urb:
@@ -1905,7 +1884,7 @@
 	usb_kill_urb(port->write_urb);
 	edge_port->ep_write_urb_in_use = 0;
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
-	kfifo_reset_out(&edge_port->write_fifo);
+	kfifo_reset_out(&port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
 	dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
@@ -1939,7 +1918,7 @@
 	if (edge_port->close_pending == 1)
 		return -ENODEV;
 
-	count = kfifo_in_locked(&edge_port->write_fifo, data, count,
+	count = kfifo_in_locked(&port->write_fifo, data, count,
 							&edge_port->ep_lock);
 	edge_send(port, tty);
 
@@ -1959,7 +1938,7 @@
 		return;
 	}
 
-	count = kfifo_out(&edge_port->write_fifo,
+	count = kfifo_out(&port->write_fifo,
 				port->write_urb->transfer_buffer,
 				port->bulk_out_size);
 
@@ -2007,7 +1986,7 @@
 		return 0;
 
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
-	room = kfifo_avail(&edge_port->write_fifo);
+	room = kfifo_avail(&port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
 	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -2024,7 +2003,7 @@
 		return 0;
 
 	spin_lock_irqsave(&edge_port->ep_lock, flags);
-	chars = kfifo_len(&edge_port->write_fifo);
+	chars = kfifo_len(&port->write_fifo);
 	spin_unlock_irqrestore(&edge_port->ep_lock, flags);
 
 	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
@@ -2451,30 +2430,45 @@
 	if (!edge_port)
 		return -ENOMEM;
 
-	ret = kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE,
-								GFP_KERNEL);
-	if (ret) {
-		kfree(edge_port);
-		return -ENOMEM;
-	}
-
 	spin_lock_init(&edge_port->ep_lock);
 	edge_port->port = port;
 	edge_port->edge_serial = usb_get_serial_data(port->serial);
 	edge_port->bUartMode = default_uart_mode;
 
+	switch (port->port_number) {
+	case 0:
+		edge_port->uart_base = UMPMEM_BASE_UART1;
+		edge_port->dma_address = UMPD_OEDB1_ADDRESS;
+		break;
+	case 1:
+		edge_port->uart_base = UMPMEM_BASE_UART2;
+		edge_port->dma_address = UMPD_OEDB2_ADDRESS;
+		break;
+	default:
+		dev_err(&port->dev, "unknown port number\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	dev_dbg(&port->dev,
+		"%s - port_number = %d, uart_base = %04x, dma_address = %04x\n",
+		__func__, port->port_number, edge_port->uart_base,
+		edge_port->dma_address);
+
 	usb_set_serial_port_data(port, edge_port);
 
 	ret = edge_create_sysfs_attrs(port);
-	if (ret) {
-		kfifo_free(&edge_port->write_fifo);
-		kfree(edge_port);
-		return ret;
-	}
+	if (ret)
+		goto err;
 
 	port->port.closing_wait = msecs_to_jiffies(closing_wait * 10);
+	port->port.drain_delay = 1;
 
 	return 0;
+err:
+	kfree(edge_port);
+
+	return ret;
 }
 
 static int edge_port_remove(struct usb_serial_port *port)
@@ -2483,7 +2477,6 @@
 
 	edge_port = usb_get_serial_port_data(port);
 	edge_remove_sysfs_attrs(port);
-	kfifo_free(&edge_port->write_fifo);
 	kfree(edge_port);
 
 	return 0;
@@ -2491,7 +2484,7 @@
 
 /* Sysfs Attributes */
 
-static ssize_t show_uart_mode(struct device *dev,
+static ssize_t uart_mode_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -2500,7 +2493,7 @@
 	return sprintf(buf, "%d\n", edge_port->bUartMode);
 }
 
-static ssize_t store_uart_mode(struct device *dev,
+static ssize_t uart_mode_store(struct device *dev,
 	struct device_attribute *attr, const char *valbuf, size_t count)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -2516,9 +2509,7 @@
 
 	return count;
 }
-
-static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode,
-							store_uart_mode);
+static DEVICE_ATTR_RW(uart_mode);
 
 static int edge_create_sysfs_attrs(struct usb_serial_port *port)
 {
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 790673e..57c439a 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -1130,7 +1130,7 @@
  * Sysfs Attributes
  */
 
-static ssize_t show_vcc_mode(struct device *dev,
+static ssize_t vcc_mode_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1139,7 +1139,7 @@
 	return sprintf(buf, "%d\n", priv->vcc);
 }
 
-static ssize_t store_vcc_mode(struct device *dev,
+static ssize_t vcc_mode_store(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -1163,9 +1163,7 @@
 fail_store_vcc_mode:
 	return count;
 }
-
-static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode,
-	store_vcc_mode);
+static DEVICE_ATTR_RW(vcc_mode);
 
 static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
 {
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 58c17fd..d6960ae 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -50,23 +50,27 @@
 #define INSTAT_BUFLEN	32
 #define GLOCONT_BUFLEN	64
 #define INDAT49W_BUFLEN	512
+#define IN_BUFLEN	64
+#define OUT_BUFLEN	64
+#define INACK_BUFLEN	1
+#define OUTCONT_BUFLEN	64
 
 	/* Per device and per port private data */
 struct keyspan_serial_private {
 	const struct keyspan_device_details	*device_details;
 
 	struct urb	*instat_urb;
-	char		instat_buf[INSTAT_BUFLEN];
+	char		*instat_buf;
 
 	/* added to support 49wg, where data from all 4 ports comes in
 	   on 1 EP and high-speed supported */
 	struct urb	*indat_urb;
-	char		indat_buf[INDAT49W_BUFLEN];
+	char		*indat_buf;
 
 	/* XXX this one probably will need a lock */
 	struct urb	*glocont_urb;
-	char		glocont_buf[GLOCONT_BUFLEN];
-	char		ctrl_buf[8];	/* for EP0 control message */
+	char		*glocont_buf;
+	char		*ctrl_buf;	/* for EP0 control message */
 };
 
 struct keyspan_port_private {
@@ -81,18 +85,18 @@
 
 	/* Input endpoints and buffer for this port */
 	struct urb	*in_urbs[2];
-	char		in_buffer[2][64];
+	char		*in_buffer[2];
 	/* Output endpoints and buffer for this port */
 	struct urb	*out_urbs[2];
-	char		out_buffer[2][64];
+	char		*out_buffer[2];
 
 	/* Input ack endpoint */
 	struct urb	*inack_urb;
-	char		inack_buffer[1];
+	char		*inack_buffer;
 
 	/* Output control endpoint */
 	struct urb	*outcont_urb;
-	char		outcont_buffer[64];
+	char		*outcont_buffer;
 
 	/* Settings for the port */
 	int		baud;
@@ -2313,6 +2317,22 @@
 		return -ENOMEM;
 	}
 
+	s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
+	if (!s_priv->instat_buf)
+		goto err_instat_buf;
+
+	s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
+	if (!s_priv->indat_buf)
+		goto err_indat_buf;
+
+	s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
+	if (!s_priv->glocont_buf)
+		goto err_glocont_buf;
+
+	s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!s_priv->ctrl_buf)
+		goto err_ctrl_buf;
+
 	s_priv->device_details = d_details;
 	usb_set_serial_data(serial, s_priv);
 
@@ -2330,6 +2350,17 @@
 	}
 
 	return 0;
+
+err_ctrl_buf:
+	kfree(s_priv->glocont_buf);
+err_glocont_buf:
+	kfree(s_priv->indat_buf);
+err_indat_buf:
+	kfree(s_priv->instat_buf);
+err_instat_buf:
+	kfree(s_priv);
+
+	return -ENOMEM;
 }
 
 static void keyspan_disconnect(struct usb_serial *serial)
@@ -2353,6 +2384,11 @@
 	usb_free_urb(s_priv->indat_urb);
 	usb_free_urb(s_priv->glocont_urb);
 
+	kfree(s_priv->ctrl_buf);
+	kfree(s_priv->glocont_buf);
+	kfree(s_priv->indat_buf);
+	kfree(s_priv->instat_buf);
+
 	kfree(s_priv);
 }
 
@@ -2374,6 +2410,26 @@
 	if (!p_priv)
 		return -ENOMEM;
 
+	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
+		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
+		if (!p_priv->in_buffer[i])
+			goto err_in_buffer;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
+		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
+		if (!p_priv->out_buffer[i])
+			goto err_out_buffer;
+	}
+
+	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
+	if (!p_priv->inack_buffer)
+		goto err_inack_buffer;
+
+	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
+	if (!p_priv->outcont_buffer)
+		goto err_outcont_buffer;
+
 	p_priv->device_details = d_details;
 
 	/* Setup values for the various callback routines */
@@ -2386,7 +2442,8 @@
 	for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
 		p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
 						USB_DIR_IN, port,
-						p_priv->in_buffer[i], 64,
+						p_priv->in_buffer[i],
+						IN_BUFLEN,
 						cback->indat_callback);
 	}
 	/* outdat endpoints also have flip */
@@ -2394,25 +2451,41 @@
 	for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
 		p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
 						USB_DIR_OUT, port,
-						p_priv->out_buffer[i], 64,
+						p_priv->out_buffer[i],
+						OUT_BUFLEN,
 						cback->outdat_callback);
 	}
 	/* inack endpoint */
 	p_priv->inack_urb = keyspan_setup_urb(serial,
 					d_details->inack_endpoints[port_num],
 					USB_DIR_IN, port,
-					p_priv->inack_buffer, 1,
+					p_priv->inack_buffer,
+					INACK_BUFLEN,
 					cback->inack_callback);
 	/* outcont endpoint */
 	p_priv->outcont_urb = keyspan_setup_urb(serial,
 					d_details->outcont_endpoints[port_num],
 					USB_DIR_OUT, port,
-					p_priv->outcont_buffer, 64,
+					p_priv->outcont_buffer,
+					OUTCONT_BUFLEN,
 					 cback->outcont_callback);
 
 	usb_set_serial_port_data(port, p_priv);
 
 	return 0;
+
+err_outcont_buffer:
+	kfree(p_priv->inack_buffer);
+err_inack_buffer:
+	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+		kfree(p_priv->out_buffer[i]);
+err_out_buffer:
+	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+		kfree(p_priv->in_buffer[i]);
+err_in_buffer:
+	kfree(p_priv);
+
+	return -ENOMEM;
 }
 
 static int keyspan_port_remove(struct usb_serial_port *port)
@@ -2436,6 +2509,13 @@
 		usb_free_urb(p_priv->out_urbs[i]);
 	}
 
+	kfree(p_priv->outcont_buffer);
+	kfree(p_priv->inack_buffer);
+	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
+		kfree(p_priv->out_buffer[i]);
+	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
+		kfree(p_priv->in_buffer[i]);
+
 	kfree(p_priv);
 
 	return 0;
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index b013001..84657e0 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -374,7 +374,7 @@
 		kfree(urbtrack);
 		return -ENOMEM;
 	}
-	urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_KERNEL);
+	urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_ATOMIC);
 	if (!urbtrack->setup) {
 		usb_free_urb(urbtrack->urb);
 		kfree(urbtrack);
@@ -382,8 +382,8 @@
 	}
 	urbtrack->setup->bRequestType = (__u8)0x40;
 	urbtrack->setup->bRequest = (__u8)0x0e;
-	urbtrack->setup->wValue = get_reg_value(reg, dummy);
-	urbtrack->setup->wIndex = get_reg_index(reg);
+	urbtrack->setup->wValue = cpu_to_le16(get_reg_value(reg, dummy));
+	urbtrack->setup->wIndex = cpu_to_le16(get_reg_index(reg));
 	urbtrack->setup->wLength = 0;
 	usb_fill_control_urb(urbtrack->urb, usbdev,
 			     usb_sndctrlpipe(usbdev, 0),
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 3bac469..fdf9535 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -221,7 +221,6 @@
 	__u8 shadowMCR;		/* last MCR value received */
 	char open;
 	char open_ports;
-	wait_queue_head_t wait_chase;	/* for handling sleeping while waiting for chase to finish */
 	struct usb_serial_port *port;	/* loop back to the owner of this object */
 
 	/* Offsets */
@@ -1100,9 +1099,6 @@
 		mos7840_port->read_urb_busy = false;
 	}
 
-	/* initialize our wait queues */
-	init_waitqueue_head(&mos7840_port->wait_chase);
-
 	/* initialize our port settings */
 	/* Must set to enable ints! */
 	mos7840_port->shadowMCR = MCR_MASTER_IE;
@@ -1228,47 +1224,6 @@
 	mos7840_port->open = 0;
 }
 
-/************************************************************************
- *
- * mos7840_block_until_chase_response
- *
- *	This function will block the close until one of the following:
- *		1. Response to our Chase comes from mos7840
- *		2. A timeout of 10 seconds without activity has expired
- *		   (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
- *
- ************************************************************************/
-
-static void mos7840_block_until_chase_response(struct tty_struct *tty,
-					struct moschip_port *mos7840_port)
-{
-	int timeout = msecs_to_jiffies(1000);
-	int wait = 10;
-	int count;
-
-	while (1) {
-		count = mos7840_chars_in_buffer(tty);
-
-		/* Check for Buffer status */
-		if (count <= 0)
-			return;
-
-		/* Block the thread for a while */
-		interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
-					       timeout);
-		/* No activity.. count down section */
-		wait--;
-		if (wait == 0) {
-			dev_dbg(&mos7840_port->port->dev, "%s - TIMEOUT\n", __func__);
-			return;
-		} else {
-			/* Reset timeout value back to seconds */
-			wait = 10;
-		}
-	}
-
-}
-
 /*****************************************************************************
  * mos7840_break
  *	this function sends a break to the port
@@ -1292,9 +1247,6 @@
 	if (mos7840_port == NULL)
 		return;
 
-	/* flush and block until tx is empty */
-	mos7840_block_until_chase_response(tty, mos7840_port);
-
 	if (break_state == -1)
 		data = mos7840_port->shadowLCR | LCR_SET_BREAK;
 	else
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
deleted file mode 100644
index c5ff6c7..0000000
--- a/drivers/usb/serial/moto_modem.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Motorola USB Phone driver
- *
- * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- * {sigh}
- * Motorola should be using the CDC ACM USB spec, but instead
- * they try to just "do their own thing"...  This driver should handle a
- * few phones in which a basic "dumb serial connection" is needed to be
- * able to get a connection through to them.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x05c6, 0x3197) },	/* unknown Motorola phone */
-	{ USB_DEVICE(0x0c44, 0x0022) },	/* unknown Mororola phone */
-	{ USB_DEVICE(0x22b8, 0x2a64) },	/* Motorola KRZR K1m */
-	{ USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */
-	{ USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver moto_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"moto-modem",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&moto_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 7e3e078..a2080ac 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -343,6 +343,8 @@
 
 	usb_set_serial_port_data(port, priv);
 
+	port->port.drain_delay = 256;	/* FIXME: check the FIFO length */
+
 	return 0;
 }
 
@@ -411,9 +413,6 @@
 	__le16 divisor;
 	int br;
 
-	if (!tty)
-		return;
-
 	cflag = tty->termios.c_cflag;
 
 	spin_lock_irqsave(&priv->lock, flags);
@@ -509,7 +508,6 @@
 static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct oti6858_private *priv = usb_get_serial_port_data(port);
-	struct ktermios tmp_termios;
 	struct usb_serial *serial = port->serial;
 	struct oti6858_control_pkt *buf;
 	unsigned long flags;
@@ -560,8 +558,8 @@
 
 	/* setup termios */
 	if (tty)
-		oti6858_set_termios(tty, port, &tmp_termios);
-	port->port.drain_delay = 256;	/* FIXME: check the FIFO length */
+		oti6858_set_termios(tty, port, NULL);
+
 	return 0;
 }
 
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index cb6bbed..e7a84f0 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -4,6 +4,11 @@
  * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2003 IBM Corp.
  *
+ * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+ *  - fixes, improvements and documentation for the baud rate encoding methods
+ * Copyright (C) 2013 Reinhard Max <max@suse.de>
+ *  - fixes and improvements for the divisor based baud rate encoding method
+ *
  * Original driver for 2.2.x by anonymous
  *
  *	This program is free software; you can redistribute it and/or
@@ -29,6 +34,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <asm/unaligned.h>
 #include "pl2303.h"
 
 /*
@@ -128,10 +134,17 @@
 
 
 enum pl2303_type {
-	type_0,		/* don't know the difference between type 0 and */
-	type_1,		/* type 1, until someone from prolific tells us... */
-	HX,		/* HX version of the pl2303 chip */
+	type_0,		/* H version ? */
+	type_1,		/* H version ? */
+	HX_TA,		/* HX(A) / X(A) / TA version  */ /* TODO: improve */
+	HXD_EA_RA_SA,	/* HXD / EA / RA / SA version */ /* TODO: improve */
+	TB,		/* TB version */
 };
+/*
+ * NOTE: don't know the difference between type 0 and type 1,
+ * until someone from Prolific tells us...
+ * TODO: distinguish between X/HX, TA and HXD, EA, RA, SA variants
+ */
 
 struct pl2303_serial_private {
 	enum pl2303_type type;
@@ -171,6 +184,7 @@
 {
 	struct pl2303_serial_private *spriv;
 	enum pl2303_type type = type_0;
+	char *type_str = "unknown (treating as type_0)";
 	unsigned char *buf;
 
 	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
@@ -183,15 +197,38 @@
 		return -ENOMEM;
 	}
 
-	if (serial->dev->descriptor.bDeviceClass == 0x02)
+	if (serial->dev->descriptor.bDeviceClass == 0x02) {
 		type = type_0;
-	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
-		type = HX;
-	else if (serial->dev->descriptor.bDeviceClass == 0x00)
+		type_str = "type_0";
+	} else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) {
+		/*
+		 * NOTE: The bcdDevice version is the only difference between
+		 * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB
+		 */
+		if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) {
+			type = HX_TA;
+			type_str = "X/HX/TA";
+		} else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
+								     == 0x400) {
+			type = HXD_EA_RA_SA;
+			type_str = "HXD/EA/RA/SA";
+		} else if (le16_to_cpu(serial->dev->descriptor.bcdDevice)
+								     == 0x500) {
+			type = TB;
+			type_str = "TB";
+		} else {
+			dev_info(&serial->interface->dev,
+					   "unknown/unsupported device type\n");
+			kfree(spriv);
+			kfree(buf);
+			return -ENODEV;
+		}
+	} else if (serial->dev->descriptor.bDeviceClass == 0x00
+		   || serial->dev->descriptor.bDeviceClass == 0xFF) {
 		type = type_1;
-	else if (serial->dev->descriptor.bDeviceClass == 0xFF)
-		type = type_1;
-	dev_dbg(&serial->interface->dev, "device type: %d\n", type);
+		type_str = "type_1";
+	}
+	dev_dbg(&serial->interface->dev, "device type: %s\n", type_str);
 
 	spriv->type = type;
 	usb_set_serial_data(serial, spriv);
@@ -206,10 +243,10 @@
 	pl2303_vendor_read(0x8383, 0, serial, buf);
 	pl2303_vendor_write(0, 1, serial);
 	pl2303_vendor_write(1, 0, serial);
-	if (type == HX)
-		pl2303_vendor_write(2, 0x44, serial);
-	else
+	if (type == type_0 || type == type_1)
 		pl2303_vendor_write(2, 0x24, serial);
+	else
+		pl2303_vendor_write(2, 0x44, serial);
 
 	kfree(buf);
 	return 0;
@@ -235,6 +272,8 @@
 
 	usb_set_serial_port_data(port, priv);
 
+	port->port.drain_delay = 256;
+
 	return 0;
 }
 
@@ -261,6 +300,175 @@
 	return retval;
 }
 
+static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type,
+								      u8 buf[4])
+{
+	/*
+	 * NOTE: Only the values defined in baud_sup are supported !
+	 *       => if unsupported values are set, the PL2303 seems to
+	 *	    use 9600 baud (at least my PL2303X always does)
+	 */
+	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
+				 4800, 7200, 9600, 14400, 19200, 28800, 38400,
+				 57600, 115200, 230400, 460800, 614400, 921600,
+				 1228800, 2457600, 3000000, 6000000, 12000000 };
+	/*
+	 * NOTE: With the exception of type_0/1 devices, the following
+	 * additional baud rates are supported (tested with HX rev. 3A only):
+	 * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800,
+	 * 403200, 806400.	(*: not HX)
+	 *
+	 * Maximum values: HXD, TB: 12000000; HX, TA: 6000000;
+	 *                 type_0+1: 1228800; RA: 921600; SA: 115200
+	 *
+	 * As long as we are not using this encoding method for anything else
+	 * than the type_0+1 and HX chips, there is no point in complicating
+	 * the code to support them.
+	 */
+	int i;
+
+	/* Set baudrate to nearest supported value */
+	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {
+		if (baud_sup[i] > baud)
+			break;
+	}
+	if (i == ARRAY_SIZE(baud_sup))
+		baud = baud_sup[i - 1];
+	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))
+		baud = baud_sup[i - 1];
+	else
+		baud = baud_sup[i];
+	/* Respect the chip type specific baud rate limits */
+	/*
+	 * FIXME: as long as we don't know how to distinguish between the
+	 * HXD, EA, RA, and SA chip variants, allow the max. value of 12M.
+	 */
+	if (type == HX_TA)
+		baud = min_t(int, baud, 6000000);
+	else if (type == type_0 || type == type_1)
+		baud = min_t(int, baud, 1228800);
+	/* Direct (standard) baud rate encoding method */
+	put_unaligned_le32(baud, buf);
+
+	return baud;
+}
+
+static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type,
+								      u8 buf[4])
+{
+	/*
+	 * Divisor based baud rate encoding method
+	 *
+	 * NOTE: it's not clear if the type_0/1 chips support this method
+	 *
+	 * divisor = 12MHz * 32 / baudrate = 2^A * B
+	 *
+	 * with
+	 *
+	 * A = buf[1] & 0x0e
+	 * B = buf[0]  +  (buf[1] & 0x01) << 8
+	 *
+	 * Special cases:
+	 * => 8 < B < 16: device seems to work not properly
+	 * => B <= 8: device uses the max. value B = 512 instead
+	 */
+	unsigned int A, B;
+
+	/*
+	 * NOTE: The Windows driver allows maximum baud rates of 110% of the
+	 * specified maximium value.
+	 * Quick tests with early (2004) HX (rev. A) chips suggest, that even
+	 * higher baud rates (up to the maximum of 24M baud !) are working fine,
+	 * but that should really be tested carefully in "real life" scenarios
+	 * before removing the upper limit completely.
+	 * Baud rates smaller than the specified 75 baud are definitely working
+	 * fine.
+	 */
+	if (type == type_0 || type == type_1)
+		baud = min_t(int, baud, 1228800 * 1.1);
+	else if (type == HX_TA)
+		baud = min_t(int, baud, 6000000 * 1.1);
+	else if (type == HXD_EA_RA_SA)
+		/* HXD, EA: 12Mbps; RA: 1Mbps; SA: 115200 bps */
+		/*
+		 * FIXME: as long as we don't know how to distinguish between
+		 * these chip variants, allow the max. of these values
+		 */
+		baud = min_t(int, baud, 12000000 * 1.1);
+	else if (type == TB)
+		baud = min_t(int, baud, 12000000 * 1.1);
+	/* Determine factors A and B */
+	A = 0;
+	B = 12000000 * 32 / baud;  /* 12MHz */
+	B <<= 1; /* Add one bit for rounding */
+	while (B > (512 << 1) && A <= 14) {
+		A += 2;
+		B >>= 2;
+	}
+	if (A > 14) { /* max. divisor = min. baudrate reached */
+		A = 14;
+		B = 512;
+		/* => ~45.78 baud */
+	} else {
+		B = (B + 1) >> 1; /* Round the last bit */
+	}
+	/* Handle special cases */
+	if (B == 512)
+		B = 0; /* also: 1 to 8 */
+	else if (B < 16)
+		/*
+		 * NOTE: With the current algorithm this happens
+		 * only for A=0 and means that the min. divisor
+		 * (respectively: the max. baudrate) is reached.
+		 */
+		B = 16;		/* => 24 MBaud */
+	/* Encode the baud rate */
+	buf[3] = 0x80;     /* Select divisor encoding method */
+	buf[2] = 0;
+	buf[1] = (A & 0x0e);		/* A */
+	buf[1] |= ((B & 0x100) >> 8);	/* MSB of B */
+	buf[0] = B & 0xff;		/* 8 LSBs of B */
+	/* Calculate the actual/resulting baud rate */
+	if (B <= 8)
+		B = 512;
+	baud = 12000000 * 32 / ((1 << A) * B);
+
+	return baud;
+}
+
+static void pl2303_encode_baudrate(struct tty_struct *tty,
+					struct usb_serial_port *port,
+					enum pl2303_type type,
+					u8 buf[4])
+{
+	int baud;
+
+	baud = tty_get_baud_rate(tty);
+	dev_dbg(&port->dev, "baud requested = %d\n", baud);
+	if (!baud)
+		return;
+	/*
+	 * There are two methods for setting/encoding the baud rate
+	 * 1) Direct method: encodes the baud rate value directly
+	 *    => supported by all chip types
+	 * 2) Divisor based method: encodes a divisor to a base value (12MHz*32)
+	 *    => supported by HX chips (and likely not by type_0/1 chips)
+	 *
+	 * NOTE: Although the divisor based baud rate encoding method is much
+	 * more flexible, some of the standard baud rate values can not be
+	 * realized exactly. But the difference is very small (max. 0.2%) and
+	 * the device likely uses the same baud rate generator for both methods
+	 * so that there is likley no difference.
+	 */
+	if (type == type_0 || type == type_1)
+		baud = pl2303_baudrate_encode_direct(baud, type, buf);
+	else
+		baud = pl2303_baudrate_encode_divisor(baud, type, buf);
+	/* Save resulting baud rate */
+	tty_encode_baud_rate(tty, baud, baud);
+	dev_dbg(&port->dev, "baud set = %d\n", baud);
+}
+
 static void pl2303_set_termios(struct tty_struct *tty,
 		struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -268,27 +476,18 @@
 	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
 	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
-	unsigned int cflag;
 	unsigned char *buf;
-	int baud;
 	int i;
 	u8 control;
-	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
-	                         4800, 7200, 9600, 14400, 19200, 28800, 38400,
-	                         57600, 115200, 230400, 460800, 500000, 614400,
-	                         921600, 1228800, 2457600, 3000000, 6000000 };
-	int baud_floor, baud_ceil;
-	int k;
 
-	/* The PL2303 is reported to lose bytes if you change
-	   serial settings even to the same values as before. Thus
-	   we actually need to filter in this specific case */
-
+	/*
+	 * The PL2303 is reported to lose bytes if you change serial settings
+	 * even to the same values as before. Thus we actually need to filter
+	 * in this specific case.
+	 */
 	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
 		return;
 
-	cflag = tty->termios.c_cflag;
-
 	buf = kzalloc(7, GFP_KERNEL);
 	if (!buf) {
 		dev_err(&port->dev, "%s - out of memory.\n", __func__);
@@ -303,8 +502,8 @@
 			    0, 0, buf, 7, 100);
 	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
 
-	if (cflag & CSIZE) {
-		switch (cflag & CSIZE) {
+	if (C_CSIZE(tty)) {
+		switch (C_CSIZE(tty)) {
 		case CS5:
 			buf[6] = 5;
 			break;
@@ -317,73 +516,22 @@
 		default:
 		case CS8:
 			buf[6] = 8;
-			break;
 		}
 		dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
 	}
 
-	/* For reference buf[0]:buf[3] baud rate value */
-	/* NOTE: Only the values defined in baud_sup are supported !
-	 *       => if unsupported values are set, the PL2303 seems to use
-	 *          9600 baud (at least my PL2303X always does)
-	 */
-	baud = tty_get_baud_rate(tty);
-	dev_dbg(&port->dev, "baud requested = %d\n", baud);
-	if (baud) {
-		/* Set baudrate to nearest supported value */
-		for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
-			if (baud_sup[k] / baud) {
-				baud_ceil = baud_sup[k];
-				if (k==0) {
-					baud = baud_ceil;
-				} else {
-					baud_floor = baud_sup[k-1];
-					if ((baud_ceil % baud)
-					    > (baud % baud_floor))
-						baud = baud_floor;
-					else
-						baud = baud_ceil;
-				}
-				break;
-			}
-		}
-		if (baud > 1228800) {
-			/* type_0, type_1 only support up to 1228800 baud */
-			if (spriv->type != HX)
-				baud = 1228800;
-			else if (baud > 6000000)
-				baud = 6000000;
-		}
-		dev_dbg(&port->dev, "baud set = %d\n", baud);
-		if (baud <= 115200) {
-			buf[0] = baud & 0xff;
-			buf[1] = (baud >> 8) & 0xff;
-			buf[2] = (baud >> 16) & 0xff;
-			buf[3] = (baud >> 24) & 0xff;
-		} else {
-			/* apparently the formula for higher speeds is:
-			 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]
-			 */
-			unsigned tmp = 12*1000*1000*32 / baud;
-			buf[3] = 0x80;
-			buf[2] = 0;
-			buf[1] = (tmp >= 256);
-			while (tmp >= 256) {
-				tmp >>= 2;
-				buf[1] <<= 1;
-			}
-			buf[0] = tmp;
-		}
-	}
+	/* For reference:   buf[0]:buf[3] baud rate value */
+	pl2303_encode_baudrate(tty, port, spriv->type, buf);
 
 	/* For reference buf[4]=0 is 1 stop bits */
 	/* For reference buf[4]=1 is 1.5 stop bits */
 	/* For reference buf[4]=2 is 2 stop bits */
-	if (cflag & CSTOPB) {
-		/* NOTE: Comply with "real" UARTs / RS232:
+	if (C_CSTOPB(tty)) {
+		/*
+		 * NOTE: Comply with "real" UARTs / RS232:
 		 *       use 1.5 instead of 2 stop bits with 5 data bits
 		 */
-		if ((cflag & CSIZE) == CS5) {
+		if (C_CSIZE(tty) == CS5) {
 			buf[4] = 1;
 			dev_dbg(&port->dev, "stop bits = 1.5\n");
 		} else {
@@ -395,14 +543,14 @@
 		dev_dbg(&port->dev, "stop bits = 1\n");
 	}
 
-	if (cflag & PARENB) {
+	if (C_PARENB(tty)) {
 		/* For reference buf[5]=0 is none parity */
 		/* For reference buf[5]=1 is odd parity */
 		/* For reference buf[5]=2 is even parity */
 		/* For reference buf[5]=3 is mark parity */
 		/* For reference buf[5]=4 is space parity */
-		if (cflag & PARODD) {
-			if (cflag & CMSPAR) {
+		if (C_PARODD(tty)) {
+			if (tty->termios.c_cflag & CMSPAR) {
 				buf[5] = 3;
 				dev_dbg(&port->dev, "parity = mark\n");
 			} else {
@@ -410,7 +558,7 @@
 				dev_dbg(&port->dev, "parity = odd\n");
 			}
 		} else {
-			if (cflag & CMSPAR) {
+			if (tty->termios.c_cflag & CMSPAR) {
 				buf[5] = 4;
 				dev_dbg(&port->dev, "parity = space\n");
 			} else {
@@ -431,7 +579,7 @@
 	/* change control lines if we are switching to or from B0 */
 	spin_lock_irqsave(&priv->lock, flags);
 	control = priv->line_control;
-	if ((cflag & CBAUD) == B0)
+	if (C_BAUD(tty) == B0)
 		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
 	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
 		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
@@ -443,26 +591,21 @@
 		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
-
+	memset(buf, 0, 7);
 	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
 			    0, 0, buf, 7, 100);
 	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf);
 
-	if (cflag & CRTSCTS) {
-		if (spriv->type == HX)
-			pl2303_vendor_write(0x0, 0x61, serial);
-		else
+	if (C_CRTSCTS(tty)) {
+		if (spriv->type == type_0 || spriv->type == type_1)
 			pl2303_vendor_write(0x0, 0x41, serial);
+		else
+			pl2303_vendor_write(0x0, 0x61, serial);
 	} else {
 		pl2303_vendor_write(0x0, 0x0, serial);
 	}
 
-	/* Save resulting baud rate */
-	if (baud)
-		tty_encode_baud_rate(tty, baud, baud);
-
 	kfree(buf);
 }
 
@@ -495,7 +638,7 @@
 	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
 	int result;
 
-	if (spriv->type != HX) {
+	if (spriv->type == type_0 || spriv->type == type_1) {
 		usb_clear_halt(serial->dev, port->write_urb->pipe);
 		usb_clear_halt(serial->dev, port->read_urb->pipe);
 	} else {
@@ -521,7 +664,6 @@
 		return result;
 	}
 
-	port->port.drain_delay = 256;
 	return 0;
 }
 
@@ -789,8 +931,10 @@
 		tty_flag = TTY_PARITY;
 	else if (line_status & UART_FRAME_ERROR)
 		tty_flag = TTY_FRAME;
-	dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
 
+	if (tty_flag != TTY_NORMAL)
+		dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__,
+								tty_flag);
 	/* overrun is special, not associated with a char */
 	if (line_status & UART_OVERRUN_ERROR)
 		tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index d997432..a24d59a 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -62,6 +62,7 @@
 #define  MAX_BAUD_RATE              921600
 #define  DEFAULT_BAUD_RATE          9600
 
+#define QT2_READ_BUFFER_SIZE    512  /* size of read buffer */
 #define QT2_WRITE_BUFFER_SIZE   512  /* size of write buffer */
 #define QT2_WRITE_CONTROL_SIZE  5    /* control bytes used for a write */
 
@@ -112,7 +113,7 @@
 	unsigned char current_port;  /* current port for incoming data */
 
 	struct urb	*read_urb;   /* shared among all ports */
-	char		read_buffer[512];
+	char		*read_buffer;
 };
 
 struct qt2_port_private {
@@ -121,7 +122,7 @@
 	spinlock_t urb_lock;
 	bool       urb_in_use;
 	struct urb *write_urb;
-	char       write_buffer[QT2_WRITE_BUFFER_SIZE];
+	char       *write_buffer;
 
 	spinlock_t  lock;
 	u8          shadowLSR;
@@ -142,6 +143,7 @@
 	serial_priv = usb_get_serial_data(serial);
 
 	usb_free_urb(serial_priv->read_urb);
+	kfree(serial_priv->read_buffer);
 	kfree(serial_priv);
 }
 
@@ -683,7 +685,7 @@
 			  usb_rcvbulkpipe(serial->dev,
 					  port0->bulk_in_endpointAddress),
 			  serial_priv->read_buffer,
-			  sizeof(serial_priv->read_buffer),
+			  QT2_READ_BUFFER_SIZE,
 			  qt2_read_bulk_callback, serial);
 
 	status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
@@ -718,6 +720,12 @@
 		return -ENOMEM;
 	}
 
+	serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL);
+	if (!serial_priv->read_buffer) {
+		status = -ENOMEM;
+		goto err_buf;
+	}
+
 	usb_set_serial_data(serial, serial_priv);
 
 	status = qt2_setup_urbs(serial);
@@ -727,6 +735,8 @@
 	return 0;
 
 attach_failed:
+	kfree(serial_priv->read_buffer);
+err_buf:
 	kfree(serial_priv);
 	return status;
 }
@@ -745,21 +755,29 @@
 	spin_lock_init(&port_priv->urb_lock);
 	port_priv->port = port;
 
+	port_priv->write_buffer = kmalloc(QT2_WRITE_BUFFER_SIZE, GFP_KERNEL);
+	if (!port_priv->write_buffer)
+		goto err_buf;
+
 	port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!port_priv->write_urb) {
-		kfree(port_priv);
-		return -ENOMEM;
-	}
+	if (!port_priv->write_urb)
+		goto err_urb;
+
 	bEndpointAddress = serial->port[0]->bulk_out_endpointAddress;
 	usb_fill_bulk_urb(port_priv->write_urb, serial->dev,
 				usb_sndbulkpipe(serial->dev, bEndpointAddress),
 				port_priv->write_buffer,
-				sizeof(port_priv->write_buffer),
+				QT2_WRITE_BUFFER_SIZE,
 				qt2_write_bulk_callback, port);
 
 	usb_set_serial_port_data(port, port_priv);
 
 	return 0;
+err_urb:
+	kfree(port_priv->write_buffer);
+err_buf:
+	kfree(port_priv);
+	return -ENOMEM;
 }
 
 static int qt2_port_remove(struct usb_serial_port *port)
@@ -768,6 +786,7 @@
 
 	port_priv = usb_get_serial_port_data(port);
 	usb_free_urb(port_priv->write_urb);
+	kfree(port_priv->write_buffer);
 	kfree(port_priv);
 
 	return 0;
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 21cd7bf..ba89598 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -92,13 +92,6 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static __u16 vendor;		/* no default */
-static __u16 product;		/* no default */
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-
 module_param(safe, bool, 0);
 MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off");
 
@@ -140,8 +133,6 @@
 	{MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Collie */
 	{MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Collie */
 	{MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Sharp tmp */
-	/* extra null entry for module vendor/produc parameters */
-	{MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
 	{}			/* terminating entry  */
 };
 
@@ -272,7 +263,19 @@
 
 static int safe_startup(struct usb_serial *serial)
 {
-	switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) {
+	struct usb_interface_descriptor	*desc;
+
+	if (serial->dev->descriptor.bDeviceClass != CDC_DEVICE_CLASS)
+		return -ENODEV;
+
+	desc = &serial->interface->cur_altsetting->desc;
+
+	if (desc->bInterfaceClass != LINEO_INTERFACE_CLASS)
+		return -ENODEV;
+	if (desc->bInterfaceSubClass != LINEO_INTERFACE_SUBCLASS_SAFESERIAL)
+		return -ENODEV;
+
+	switch (desc->bInterfaceProtocol) {
 	case LINEO_SAFESERIAL_CRC:
 		break;
 	case LINEO_SAFESERIAL_CRC_PADDED:
@@ -300,30 +303,4 @@
 	&safe_device, NULL
 };
 
-static int __init safe_init(void)
-{
-	int i;
-
-	/* if we have vendor / product parameters patch them into id list */
-	if (vendor || product) {
-		pr_info("vendor: %x product: %x\n", vendor, product);
-
-		for (i = 0; i < ARRAY_SIZE(id_table); i++) {
-			if (!id_table[i].idVendor && !id_table[i].idProduct) {
-				id_table[i].idVendor = vendor;
-				id_table[i].idProduct = product;
-				break;
-			}
-		}
-	}
-
-	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
-}
-
-static void __exit safe_exit(void)
-{
-	usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(safe_init);
-module_exit(safe_exit);
+module_usb_serial_driver(serial_drivers, id_table);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
deleted file mode 100644
index a76b1ae5..0000000
--- a/drivers/usb/serial/siemens_mpi.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Siemens USB-MPI Serial USB driver
- *
- * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
- * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net"
-#define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
-
-
-static const struct usb_device_id id_table[] = {
-	/* Vendor and product id for 6ES7-972-0CB20-0XA0 */
-	{ USB_DEVICE(0x908, 0x0004) },
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver siemens_usb_mpi_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"siemens_mpi",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&siemens_usb_mpi_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index ddf6c47..4abac28 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -169,6 +169,8 @@
 
 	usb_set_serial_port_data(port, priv);
 
+	port->port.drain_delay = 256;
+
 	return 0;
 }
 
@@ -411,8 +413,6 @@
 	if (tty)
 		spcp8x5_set_termios(tty, port, NULL);
 
-	port->port.drain_delay = 256;
-
 	return usb_serial_generic_open(tty, port);
 }
 
diff --git a/drivers/usb/serial/suunto.c b/drivers/usb/serial/suunto.c
deleted file mode 100644
index 2248e7a..0000000
--- a/drivers/usb/serial/suunto.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Suunto ANT+ USB Driver
- *
- * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- * Copyright (C) 2013 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 only.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x0fcf, 0x1008) },
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver suunto_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		KBUILD_MODNAME,
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&suunto_device,
-	NULL,
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 5c9f9b1..760b785 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -45,8 +45,6 @@
 
 #define TI_FIRMWARE_BUF_SIZE	16284
 
-#define TI_WRITE_BUF_SIZE	1024
-
 #define TI_TRANSFER_TIMEOUT	2
 
 #define TI_DEFAULT_CLOSING_WAIT	4000		/* in .01 secs */
@@ -71,13 +69,11 @@
 	__u8			tp_uart_mode;	/* 232 or 485 modes */
 	unsigned int		tp_uart_base_addr;
 	int			tp_flags;
-	wait_queue_head_t	tp_write_wait;
 	struct ti_device	*tp_tdev;
 	struct usb_serial_port	*tp_port;
 	spinlock_t		tp_lock;
 	int			tp_read_urb_state;
 	int			tp_write_urb_in_use;
-	struct kfifo		write_fifo;
 };
 
 struct ti_device {
@@ -145,20 +141,9 @@
 
 /* module parameters */
 static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
-static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_3410_count;
-static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_3410_count;
-static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int vendor_5052_count;
-static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static unsigned int product_5052_count;
 
 /* supported devices */
-/* the array dimension is the number of default entries plus */
-/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
-/* null entry */
-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[] = {
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
 	{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -175,16 +160,18 @@
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+	{ }	/* terminator */
 };
 
-static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_5052[] = {
 	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
+	{ }	/* terminator */
 };
 
-static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[] = {
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
 	{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -204,7 +191,7 @@
 	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
 	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
 	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
-	{ }
+	{ }	/* terminator */
 };
 
 static struct usb_serial_driver ti_1port_device = {
@@ -293,61 +280,12 @@
 MODULE_PARM_DESC(closing_wait,
     "Maximum wait for data to drain in close, in .01 secs, default is 4000");
 
-module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_3410,
-		"Vendor ids for 3410 based devices, 1-5 short integers");
-module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO);
-MODULE_PARM_DESC(product_3410,
-		"Product ids for 3410 based devices, 1-5 short integers");
-module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO);
-MODULE_PARM_DESC(vendor_5052,
-		"Vendor ids for 5052 based devices, 1-5 short integers");
-module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO);
-MODULE_PARM_DESC(product_5052,
-		"Product ids for 5052 based devices, 1-5 short integers");
-
 MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
 
+module_usb_serial_driver(serial_drivers, ti_id_table_combined);
 
 /* Functions */
 
-static int __init ti_init(void)
-{
-	int i, j, c;
-
-	/* insert extra vendor and product ids */
-	c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1;
-	j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1;
-	for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) {
-		ti_id_table_3410[j].idVendor = vendor_3410[i];
-		ti_id_table_3410[j].idProduct = product_3410[i];
-		ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-		ti_id_table_combined[c].idVendor = vendor_3410[i];
-		ti_id_table_combined[c].idProduct = product_3410[i];
-		ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-	}
-	j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1;
-	for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) {
-		ti_id_table_5052[j].idVendor = vendor_5052[i];
-		ti_id_table_5052[j].idProduct = product_5052[i];
-		ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-		ti_id_table_combined[c].idVendor = vendor_5052[i];
-		ti_id_table_combined[c].idProduct = product_5052[i];
-		ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-	}
-
-	return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
-}
-
-static void __exit ti_exit(void)
-{
-	usb_serial_deregister_drivers(serial_drivers);
-}
-
-module_init(ti_init);
-module_exit(ti_exit);
-
-
 static int ti_startup(struct usb_serial *serial)
 {
 	struct ti_device *tdev;
@@ -430,17 +368,14 @@
 	else
 		tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;
 	port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
-	init_waitqueue_head(&tport->tp_write_wait);
-	if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
-		kfree(tport);
-		return -ENOMEM;
-	}
 	tport->tp_port = port;
 	tport->tp_tdev = usb_get_serial_data(port->serial);
 	tport->tp_uart_mode = 0;	/* default is RS232 */
 
 	usb_set_serial_port_data(port, tport);
 
+	port->port.drain_delay = 3;
+
 	return 0;
 }
 
@@ -449,7 +384,6 @@
 	struct ti_port *tport;
 
 	tport = usb_get_serial_port_data(port);
-	kfifo_free(&tport->write_fifo);
 	kfree(tport);
 
 	return 0;
@@ -582,8 +516,6 @@
 	tport->tp_is_open = 1;
 	++tdev->td_open_port_count;
 
-	port->port.drain_delay = 3;
-
 	goto release_lock;
 
 unlink_int_urb:
@@ -616,7 +548,7 @@
 	usb_kill_urb(port->write_urb);
 	tport->tp_write_urb_in_use = 0;
 	spin_lock_irqsave(&tport->tp_lock, flags);
-	kfifo_reset_out(&tport->write_fifo);
+	kfifo_reset_out(&port->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
 	port_number = port->port_number;
@@ -655,7 +587,7 @@
 	if (tport == NULL || !tport->tp_is_open)
 		return -ENODEV;
 
-	count = kfifo_in_locked(&tport->write_fifo, data, count,
+	count = kfifo_in_locked(&port->write_fifo, data, count,
 							&tport->tp_lock);
 	ti_send(tport);
 
@@ -674,7 +606,7 @@
 		return 0;
 
 	spin_lock_irqsave(&tport->tp_lock, flags);
-	room = kfifo_avail(&tport->write_fifo);
+	room = kfifo_avail(&port->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
 	dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
@@ -693,7 +625,7 @@
 		return 0;
 
 	spin_lock_irqsave(&tport->tp_lock, flags);
-	chars = kfifo_len(&tport->write_fifo);
+	chars = kfifo_len(&port->write_fifo);
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
 
 	dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
@@ -1090,13 +1022,11 @@
 	case -ESHUTDOWN:
 		dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status);
 		tport->tp_tdev->td_urb_error = 1;
-		wake_up_interruptible(&tport->tp_write_wait);
 		return;
 	default:
 		dev_err(dev, "%s - nonzero urb status, %d\n",
 			__func__, status);
 		tport->tp_tdev->td_urb_error = 1;
-		wake_up_interruptible(&tport->tp_write_wait);
 	}
 
 	if (status == -EPIPE)
@@ -1152,13 +1082,11 @@
 	case -ESHUTDOWN:
 		dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status);
 		tport->tp_tdev->td_urb_error = 1;
-		wake_up_interruptible(&tport->tp_write_wait);
 		return;
 	default:
 		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);
 	}
 
 	/* send any buffered data */
@@ -1197,7 +1125,7 @@
 	if (tport->tp_write_urb_in_use)
 		goto unlock;
 
-	count = kfifo_out(&tport->write_fifo,
+	count = kfifo_out(&port->write_fifo,
 				port->write_urb->transfer_buffer,
 				port->bulk_out_size);
 
@@ -1232,7 +1160,6 @@
 	/* more room in the buffer for new writes, wakeup */
 	tty_port_tty_wakeup(&port->port);
 
-	wake_up_interruptible(&tport->tp_write_wait);
 	return;
 unlock:
 	spin_unlock_irqrestore(&tport->tp_lock, flags);
@@ -1312,7 +1239,7 @@
 	ret_serial.line = port->minor;
 	ret_serial.port = port->port_number;
 	ret_serial.flags = tport->tp_flags;
-	ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE;
+	ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo);
 	ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
 	ret_serial.closing_wait = cwait;
 
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
new file mode 100644
index 0000000..52eb91f
--- /dev/null
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -0,0 +1,110 @@
+/*
+ * USB Serial "Simple" driver
+ *
+ * Copyright (C) 2001-2006,2008,2013 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net)
+ * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
+ * Copyright (C) 2009 Outpost Embedded, LLC
+ * Copyright (C) 2010 Zilogic Systems <code@zilogic.com>
+ * Copyright (C) 2013 Wei Shuai <cpuwolf@gmail.com>
+ * Copyright (C) 2013 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/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#define DEVICE(vendor, IDS)					\
+static const struct usb_device_id vendor##_id_table[] = {	\
+	IDS(),							\
+	{ },							\
+};								\
+static struct usb_serial_driver vendor##_device = {		\
+	.driver = {						\
+		.owner =	THIS_MODULE,			\
+		.name =		#vendor,			\
+	},							\
+	.id_table =		vendor##_id_table,		\
+	.num_ports =		1,				\
+};
+
+
+/* ZIO Motherboard USB driver */
+#define ZIO_IDS()			\
+	{ USB_DEVICE(0x1CBE, 0x0103) }
+DEVICE(zio, ZIO_IDS);
+
+/* Funsoft Serial USB driver */
+#define FUNSOFT_IDS()			\
+	{ USB_DEVICE(0x1404, 0xcddc) }
+DEVICE(funsoft, FUNSOFT_IDS);
+
+/* Infineon Flashloader driver */
+#define FLASHLOADER_IDS()		\
+	{ USB_DEVICE(0x8087, 0x0716) }
+DEVICE(flashloader, FLASHLOADER_IDS);
+
+/* ViVOpay USB Serial Driver */
+#define VIVOPAY_IDS()			\
+	{ USB_DEVICE(0x1d5f, 0x1004) }	/* ViVOpay 8800 */
+DEVICE(vivopay, VIVOPAY_IDS);
+
+/* Motorola USB Phone driver */
+#define MOTO_IDS()			\
+	{ USB_DEVICE(0x05c6, 0x3197) },	/* unknown Motorola phone */	\
+	{ USB_DEVICE(0x0c44, 0x0022) },	/* unknown Mororola phone */	\
+	{ USB_DEVICE(0x22b8, 0x2a64) },	/* Motorola KRZR K1m */		\
+	{ USB_DEVICE(0x22b8, 0x2c84) },	/* Motorola VE240 phone */	\
+	{ USB_DEVICE(0x22b8, 0x2c64) }	/* Motorola V950 phone */
+DEVICE(moto_modem, MOTO_IDS);
+
+/* HP4x (48/49) Generic Serial driver */
+#define HP4X_IDS()			\
+	{ USB_DEVICE(0x03f0, 0x0121) }
+DEVICE(hp4x, HP4X_IDS);
+
+/* Suunto ANT+ USB Driver */
+#define SUUNTO_IDS()			\
+	{ USB_DEVICE(0x0fcf, 0x1008) }
+DEVICE(suunto, SUUNTO_IDS);
+
+/* Siemens USB/MPI adapter */
+#define SIEMENS_IDS()			\
+	{ USB_DEVICE(0x908, 0x0004) }
+DEVICE(siemens_mpi, SIEMENS_IDS);
+
+/* All of the above structures mushed into two lists */
+static struct usb_serial_driver * const serial_drivers[] = {
+	&zio_device,
+	&funsoft_device,
+	&flashloader_device,
+	&vivopay_device,
+	&moto_modem_device,
+	&hp4x_device,
+	&suunto_device,
+	&siemens_mpi_device,
+	NULL
+};
+
+static const struct usb_device_id id_table[] = {
+	ZIO_IDS(),
+	FUNSOFT_IDS(),
+	FLASHLOADER_IDS(),
+	VIVOPAY_IDS(),
+	MOTO_IDS(),
+	HP4X_IDS(),
+	SUUNTO_IDS(),
+	SIEMENS_IDS(),
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index cb27fcb..6091bd5 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -681,20 +681,10 @@
 static void serial_port_dtr_rts(struct tty_port *port, int on)
 {
 	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
-	struct usb_serial *serial = p->serial;
-	struct usb_serial_driver *drv = serial->type;
+	struct usb_serial_driver *drv = p->serial->type;
 
-	if (!drv->dtr_rts)
-		return;
-	/*
-	 * Work-around bug in the tty-layer which can result in dtr_rts
-	 * being called after a disconnect (and tty_unregister_device
-	 * has returned). Remove once bug has been squashed.
-	 */
-	mutex_lock(&serial->disc_mutex);
-	if (!serial->disconnected)
+	if (drv->dtr_rts)
 		drv->dtr_rts(p, on);
-	mutex_unlock(&serial->disc_mutex);
 }
 
 static const struct tty_port_operations serial_port_ops = {
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
deleted file mode 100644
index 6299526..0000000
--- a/drivers/usb/serial/vivopay-serial.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2009 Outpost Embedded, LLC
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-#define DRIVER_DESC "ViVOpay USB Serial Driver"
-
-#define VIVOPAY_VENDOR_ID 0x1d5f
-
-
-static struct usb_device_id id_table [] = {
-	/* ViVOpay 8800 */
-	{ USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) },
-	{ },
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver vivopay_serial_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"vivopay-serial",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&vivopay_serial_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-
-MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
deleted file mode 100644
index c043aa8..0000000
--- a/drivers/usb/serial/zio.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * ZIO Motherboard USB driver
- *
- * Copyright (C) 2010 Zilogic Systems <code@zilogic.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/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x1CBE, 0x0103) },
-	{ },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_serial_driver zio_device = {
-	.driver = {
-		.owner =	THIS_MODULE,
-		.name =		"zio",
-	},
-	.id_table =		id_table,
-	.num_ports =		1,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
-	&zio_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, id_table);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 92b05d9..94d75ed 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -496,7 +496,7 @@
  ***********************************************************************/
 
 /* Output routine for the sysfs max_sectors file */
-static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t max_sectors_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev = to_scsi_device(dev);
 
@@ -504,7 +504,7 @@
 }
 
 /* Input routine for the sysfs max_sectors file */
-static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf,
+static ssize_t max_sectors_store(struct device *dev, struct device_attribute *attr, const char *buf,
 		size_t count)
 {
 	struct scsi_device *sdev = to_scsi_device(dev);
@@ -514,16 +514,14 @@
 		blk_queue_max_hw_sectors(sdev->request_queue, ms);
 		return count;
 	}
-	return -EINVAL;	
+	return -EINVAL;
 }
-
-static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
-		store_max_sectors);
+static DEVICE_ATTR_RW(max_sectors);
 
 static struct device_attribute *sysfs_device_attr_list[] = {
-		&dev_attr_max_sectors,
-		NULL,
-		};
+	&dev_attr_max_sectors,
+	NULL,
+};
 
 /*
  * this defines our host template, with which we'll allocate hosts
diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c
index 675384d..d771870a 100644
--- a/drivers/usb/usb-common.c
+++ b/drivers/usb/usb-common.c
@@ -43,20 +43,20 @@
 }
 EXPORT_SYMBOL_GPL(usb_otg_state_string);
 
+static const char *const speed_names[] = {
+	[USB_SPEED_UNKNOWN] = "UNKNOWN",
+	[USB_SPEED_LOW] = "low-speed",
+	[USB_SPEED_FULL] = "full-speed",
+	[USB_SPEED_HIGH] = "high-speed",
+	[USB_SPEED_WIRELESS] = "wireless",
+	[USB_SPEED_SUPER] = "super-speed",
+};
+
 const char *usb_speed_string(enum usb_device_speed speed)
 {
-	static const char *const names[] = {
-		[USB_SPEED_UNKNOWN] = "UNKNOWN",
-		[USB_SPEED_LOW] = "low-speed",
-		[USB_SPEED_FULL] = "full-speed",
-		[USB_SPEED_HIGH] = "high-speed",
-		[USB_SPEED_WIRELESS] = "wireless",
-		[USB_SPEED_SUPER] = "super-speed",
-	};
-
-	if (speed < 0 || speed >= ARRAY_SIZE(names))
+	if (speed < 0 || speed >= ARRAY_SIZE(speed_names))
 		speed = USB_SPEED_UNKNOWN;
-	return names[speed];
+	return speed_names[speed];
 }
 EXPORT_SYMBOL_GPL(usb_speed_string);
 
@@ -112,6 +112,33 @@
 	return USB_DR_MODE_UNKNOWN;
 }
 EXPORT_SYMBOL_GPL(of_usb_get_dr_mode);
+
+/**
+ * of_usb_get_maximum_speed - Get maximum requested speed for a given USB
+ * controller.
+ * @np: Pointer to the given device_node
+ *
+ * The function gets the maximum speed string from property "maximum-speed",
+ * and returns the corresponding enum usb_device_speed.
+ */
+enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np)
+{
+	const char *maximum_speed;
+	int err;
+	int i;
+
+	err = of_property_read_string(np, "maximum-speed", &maximum_speed);
+	if (err < 0)
+		return USB_SPEED_UNKNOWN;
+
+	for (i = 0; i < ARRAY_SIZE(speed_names); i++)
+		if (strcmp(maximum_speed, speed_names[i]) == 0)
+			return i;
+
+	return USB_SPEED_UNKNOWN;
+}
+EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed);
+
 #endif
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 7ed3b03..ff97652 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -325,9 +325,8 @@
 		rv = skel_do_read_io(dev, count);
 		if (rv < 0)
 			goto exit;
-		else if (!(file->f_flags & O_NONBLOCK))
+		else
 			goto retry;
-		rv = -EAGAIN;
 	}
 exit:
 	mutex_unlock(&dev->io_mutex);
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index bdb0cc3..fe8bc77 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -141,18 +141,26 @@
 int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
 {
 	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-	size_t cnt, size;
-	unsigned long *buf = (unsigned long *) _buf;
+	size_t cnt, size, bits_set = 0;
 
 	/* WE DON'T LOCK, see comment */
-	size = wusbhc->ports_max + 1 /* hub bit */;
-	size = (size + 8 - 1) / 8;	/* round to bytes */
-	for (cnt = 0; cnt < wusbhc->ports_max; cnt++)
-		if (wusb_port_by_idx(wusbhc, cnt)->change)
-			set_bit(cnt + 1, buf);
-		else
-			clear_bit(cnt + 1, buf);
-	return size;
+	/* round up to bytes.  Hub bit is bit 0 so add 1. */
+	size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
+
+	/* clear the output buffer. */
+	memset(_buf, 0, size);
+	/* set the bit for each changed port. */
+	for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
+
+		if (wusb_port_by_idx(wusbhc, cnt)->change) {
+			const int bitpos = cnt+1;
+
+			_buf[bitpos/8] |= (1 << (bitpos % 8));
+			bits_set++;
+		}
+	}
+
+	return bits_set ? size : 0;
 }
 EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
 
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
index d6bea3e..cf250c2 100644
--- a/drivers/usb/wusbcore/wa-hc.h
+++ b/drivers/usb/wusbcore/wa-hc.h
@@ -91,6 +91,7 @@
 struct wusbhc;
 struct wahc;
 extern void wa_urb_enqueue_run(struct work_struct *ws);
+extern void wa_process_errored_transfers_run(struct work_struct *ws);
 
 /**
  * RPipe instance
@@ -190,8 +191,14 @@
 
 	struct list_head xfer_list;
 	struct list_head xfer_delayed_list;
+	struct list_head xfer_errored_list;
+	/*
+	 * lock for the above xfer lists.  Can be taken while a xfer->lock is
+	 * held but not in the reverse order.
+	 */
 	spinlock_t xfer_list_lock;
-	struct work_struct xfer_work;
+	struct work_struct xfer_enqueue_work;
+	struct work_struct xfer_error_work;
 	atomic_t xfer_id_count;
 };
 
@@ -244,8 +251,10 @@
 	edc_init(&wa->dti_edc);
 	INIT_LIST_HEAD(&wa->xfer_list);
 	INIT_LIST_HEAD(&wa->xfer_delayed_list);
+	INIT_LIST_HEAD(&wa->xfer_errored_list);
 	spin_lock_init(&wa->xfer_list_lock);
-	INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run);
+	INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
+	INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
 	atomic_set(&wa->xfer_id_count, 1);
 }
 
@@ -269,6 +278,8 @@
 
 }
 extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
+extern void rpipe_clear_feature_stalled(struct wahc *,
+			struct usb_host_endpoint *);
 extern int wa_rpipes_create(struct wahc *);
 extern void wa_rpipes_destroy(struct wahc *);
 static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index 9a595c1..fd4f1ce 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -527,3 +527,24 @@
 	mutex_unlock(&wa->rpipe_mutex);
 }
 EXPORT_SYMBOL_GPL(rpipe_ep_disable);
+
+/* Clear the stalled status of an RPIPE. */
+void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+	struct wa_rpipe *rpipe;
+
+	mutex_lock(&wa->rpipe_mutex);
+	rpipe = ep->hcpriv;
+	if (rpipe != NULL) {
+		u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+		usb_control_msg(
+			wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+			USB_REQ_CLEAR_FEATURE,
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+			RPIPE_STALL, index, NULL, 0, 1000);
+	}
+	mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
+
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index d3493ca..6ad02f5 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -125,10 +125,13 @@
 	u8 xfer_extra[];		/* xtra space for xfer_hdr_ctl */
 };
 
-static void wa_seg_init(struct wa_seg *seg)
+static inline void wa_seg_init(struct wa_seg *seg)
 {
-	/* usb_init_urb() repeats a lot of work, so we do it here */
-	kref_init(&seg->urb.kref);
+	usb_init_urb(&seg->urb);
+
+	/* set the remaining memory to 0. */
+	memset(((void *)seg) + sizeof(seg->urb), 0,
+		sizeof(*seg) - sizeof(seg->urb));
 }
 
 /*
@@ -166,8 +169,8 @@
 /*
  * Destroy a transfer structure
  *
- * Note that the xfer->seg[index] thingies follow the URB life cycle,
- * so we need to put them, not free them.
+ * Note that freeing xfer->seg[cnt]->urb will free the containing
+ * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
  */
 static void wa_xfer_destroy(struct kref *_xfer)
 {
@@ -175,9 +178,8 @@
 	if (xfer->seg) {
 		unsigned cnt;
 		for (cnt = 0; cnt < xfer->segs; cnt++) {
-			if (xfer->is_inbound)
-				usb_put_urb(xfer->seg[cnt]->dto_urb);
-			usb_put_urb(&xfer->seg[cnt]->urb);
+			usb_free_urb(xfer->seg[cnt]->dto_urb);
+			usb_free_urb(&xfer->seg[cnt]->urb);
 		}
 	}
 	kfree(xfer);
@@ -732,9 +734,9 @@
 	buf_itr = 0;
 	buf_size = xfer->urb->transfer_buffer_length;
 	for (cnt = 0; cnt < xfer->segs; cnt++) {
-		seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC);
+		seg = xfer->seg[cnt] = kmalloc(alloc_size, GFP_ATOMIC);
 		if (seg == NULL)
-			goto error_seg_kzalloc;
+			goto error_seg_kmalloc;
 		wa_seg_init(seg);
 		seg->xfer = xfer;
 		seg->index = cnt;
@@ -804,15 +806,17 @@
 	return 0;
 
 error_sg_alloc:
-	kfree(seg->dto_urb);
+	usb_free_urb(xfer->seg[cnt]->dto_urb);
 error_dto_alloc:
 	kfree(xfer->seg[cnt]);
 	cnt--;
-error_seg_kzalloc:
+error_seg_kmalloc:
 	/* use the fact that cnt is left at were it failed */
 	for (; cnt >= 0; cnt--) {
-		if (xfer->seg[cnt] && xfer->is_inbound == 0)
+		if (xfer->seg[cnt] && xfer->is_inbound == 0) {
 			usb_free_urb(xfer->seg[cnt]->dto_urb);
+			kfree(xfer->seg[cnt]->dto_urb->sg);
+		}
 		kfree(xfer->seg[cnt]);
 	}
 error_segs_kzalloc:
@@ -928,7 +932,7 @@
 	spin_lock_irqsave(&rpipe->seg_lock, flags);
 	while (atomic_read(&rpipe->segs_available) > 0
 	      && !list_empty(&rpipe->seg_list)) {
-		seg = list_entry(rpipe->seg_list.next, struct wa_seg,
+		seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
 				 list_node);
 		list_del(&seg->list_node);
 		xfer = seg->xfer;
@@ -1093,34 +1097,82 @@
  *
  * We need to be careful here, as dequeue() could be called in the
  * middle.  That's why we do the whole thing under the
- * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock
+ * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
  * and then checks the list -- so as we would be acquiring in inverse
- * order, we just drop the lock once we have the xfer and reacquire it
- * later.
+ * order, we move the delayed list to a separate list while locked and then
+ * submit them without the list lock held.
  */
 void wa_urb_enqueue_run(struct work_struct *ws)
 {
-	struct wahc *wa = container_of(ws, struct wahc, xfer_work);
+	struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
 	struct wa_xfer *xfer, *next;
 	struct urb *urb;
+	LIST_HEAD(tmp_list);
 
+	/* Create a copy of the wa->xfer_delayed_list while holding the lock */
 	spin_lock_irq(&wa->xfer_list_lock);
-	list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list,
-				 list_node) {
+	list_cut_position(&tmp_list, &wa->xfer_delayed_list,
+			wa->xfer_delayed_list.prev);
+	spin_unlock_irq(&wa->xfer_list_lock);
+
+	/*
+	 * enqueue from temp list without list lock held since wa_urb_enqueue_b
+	 * can take xfer->lock as well as lock mutexes.
+	 */
+	list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
 		list_del_init(&xfer->list_node);
-		spin_unlock_irq(&wa->xfer_list_lock);
 
 		urb = xfer->urb;
 		wa_urb_enqueue_b(xfer);
 		usb_put_urb(urb);	/* taken when queuing */
-
-		spin_lock_irq(&wa->xfer_list_lock);
 	}
-	spin_unlock_irq(&wa->xfer_list_lock);
 }
 EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
 
 /*
+ * Process the errored transfers on the Wire Adapter outside of interrupt.
+ */
+void wa_process_errored_transfers_run(struct work_struct *ws)
+{
+	struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
+	struct wa_xfer *xfer, *next;
+	LIST_HEAD(tmp_list);
+
+	pr_info("%s: Run delayed STALL processing.\n", __func__);
+
+	/* Create a copy of the wa->xfer_errored_list while holding the lock */
+	spin_lock_irq(&wa->xfer_list_lock);
+	list_cut_position(&tmp_list, &wa->xfer_errored_list,
+			wa->xfer_errored_list.prev);
+	spin_unlock_irq(&wa->xfer_list_lock);
+
+	/*
+	 * run rpipe_clear_feature_stalled from temp list without list lock
+	 * held.
+	 */
+	list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+		struct usb_host_endpoint *ep;
+		unsigned long flags;
+		struct wa_rpipe *rpipe;
+
+		spin_lock_irqsave(&xfer->lock, flags);
+		ep = xfer->ep;
+		rpipe = ep->hcpriv;
+		spin_unlock_irqrestore(&xfer->lock, flags);
+
+		/* clear RPIPE feature stalled without holding a lock. */
+		rpipe_clear_feature_stalled(wa, ep);
+
+		/* complete the xfer. This removes it from the tmp list. */
+		wa_xfer_completion(xfer);
+
+		/* check for work. */
+		wa_xfer_delayed_run(rpipe);
+	}
+}
+EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
+
+/*
  * Submit a transfer to the Wire Adapter in a delayed way
  *
  * The process of enqueuing involves possible sleeps() [see
@@ -1175,7 +1227,7 @@
 		spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
 		list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
 		spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-		queue_work(wusbd, &wa->xfer_work);
+		queue_work(wusbd, &wa->xfer_enqueue_work);
 	} else {
 		wa_urb_enqueue_b(xfer);
 	}
@@ -1217,7 +1269,8 @@
 
 	xfer = urb->hcpriv;
 	if (xfer == NULL) {
-		/* NOthing setup yet enqueue will see urb->status !=
+		/*
+		 * Nothing setup yet enqueue will see urb->status !=
 		 * -EINPROGRESS (by hcd layer) and bail out with
 		 * error, no need to do completion
 		 */
@@ -1361,7 +1414,7 @@
  *
  * inbound transfers: need to schedule a DTI read
  *
- * FIXME: this functio needs to be broken up in parts
+ * FIXME: this function needs to be broken up in parts
  */
 static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
 {
@@ -1483,17 +1536,37 @@
 	seg->result = result;
 	kfree(wa->buf_in_urb->sg);
 error_sg_alloc:
+	__wa_xfer_abort(xfer);
 error_complete:
 	seg->status = WA_SEG_ERROR;
 	xfer->segs_done++;
 	rpipe_ready = rpipe_avail_inc(rpipe);
-	__wa_xfer_abort(xfer);
 	done = __wa_xfer_is_done(xfer);
-	spin_unlock_irqrestore(&xfer->lock, flags);
-	if (done)
-		wa_xfer_completion(xfer);
-	if (rpipe_ready)
-		wa_xfer_delayed_run(rpipe);
+	/*
+	 * queue work item to clear STALL for control endpoints.
+	 * Otherwise, let endpoint_reset take care of it.
+	 */
+	if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
+		usb_endpoint_xfer_control(&xfer->ep->desc) &&
+		done) {
+
+		dev_info(dev, "Control EP stall.  Queue delayed work.\n");
+		spin_lock_irq(&wa->xfer_list_lock);
+		/* remove xfer from xfer_list. */
+		list_del(&xfer->list_node);
+		/* add xfer to xfer_errored_list. */
+		list_add_tail(&xfer->list_node, &wa->xfer_errored_list);
+		spin_unlock_irq(&wa->xfer_list_lock);
+		spin_unlock_irqrestore(&xfer->lock, flags);
+		queue_work(wusbd, &wa->xfer_error_work);
+	} else {
+		spin_unlock_irqrestore(&xfer->lock, flags);
+		if (done)
+			wa_xfer_completion(xfer);
+		if (rpipe_ready)
+			wa_xfer_delayed_run(rpipe);
+	}
+
 	return;
 
 error_bad_seg:
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c
index 5206731..b7d4f6b7 100644
--- a/drivers/uwb/drp-ie.c
+++ b/drivers/uwb/drp-ie.c
@@ -27,7 +27,7 @@
 /*
  * Return the reason code for a reservations's DRP IE.
  */
-int uwb_rsv_reason_code(struct uwb_rsv *rsv)
+static int uwb_rsv_reason_code(struct uwb_rsv *rsv)
 {
 	static const int reason_codes[] = {
 		[UWB_RSV_STATE_O_INITIATED]          = UWB_DRP_REASON_ACCEPTED,
@@ -55,7 +55,7 @@
 /*
  * Return the reason code for a reservations's companion DRP IE .
  */
-int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
+static int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
 {
 	static const int companion_reason_codes[] = {
 		[UWB_RSV_STATE_O_MOVE_EXPANDING]     = UWB_DRP_REASON_ACCEPTED,
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
index 0621abe..0257f35 100644
--- a/drivers/uwb/hwa-rc.c
+++ b/drivers/uwb/hwa-rc.c
@@ -611,7 +611,16 @@
 int hwarc_reset(struct uwb_rc *uwb_rc)
 {
 	struct hwarc *hwarc = uwb_rc->priv;
-	return usb_reset_device(hwarc->usb_dev);
+	int result;
+
+	/* device lock must be held when calling usb_reset_device. */
+	result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
+	if (result >= 0) {
+		result = usb_reset_device(hwarc->usb_dev);
+		usb_unlock_device(hwarc->usb_dev);
+	}
+
+	return result;
 }
 
 /**
@@ -709,8 +718,10 @@
 
 error_neep_submit:
 	usb_free_urb(hwarc->neep_urb);
+	hwarc->neep_urb = NULL;
 error_urb_alloc:
 	free_page((unsigned long)hwarc->rd_buffer);
+	hwarc->rd_buffer = NULL;
 error_rd_buffer:
 	return -ENOMEM;
 }
@@ -723,7 +734,10 @@
 
 	usb_kill_urb(hwarc->neep_urb);
 	usb_free_urb(hwarc->neep_urb);
+	hwarc->neep_urb = NULL;
+
 	free_page((unsigned long)hwarc->rd_buffer);
+	hwarc->rd_buffer = NULL;
 }
 
 /**
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
index 690577d..c1304b8 100644
--- a/drivers/uwb/pal.c
+++ b/drivers/uwb/pal.c
@@ -68,8 +68,40 @@
 }
 EXPORT_SYMBOL_GPL(uwb_pal_register);
 
+static int find_rc(struct device *dev, const void *data)
+{
+	const struct uwb_rc *target_rc = data;
+	struct uwb_rc *rc = dev_get_drvdata(dev);
+
+	if (rc == NULL) {
+		WARN_ON(1);
+		return 0;
+	}
+	if (rc == target_rc) {
+		if (rc->ready == 0)
+			return 0;
+		else
+			return 1;
+	}
+	return 0;
+}
+
 /**
- * uwb_pal_register - unregister a UWB PAL
+ * Given a radio controller descriptor see if it is registered.
+ *
+ * @returns false if the rc does not exist or is quiescing; true otherwise.
+ */
+static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
+{
+	struct device *dev;
+
+	dev = class_find_device(&uwb_rc_class, NULL, target_rc,	find_rc);
+
+	return (dev != NULL);
+}
+
+/**
+ * uwb_pal_unregister - unregister a UWB PAL
  * @pal: the PAL
  */
 void uwb_pal_unregister(struct uwb_pal *pal)
@@ -85,7 +117,11 @@
 	debugfs_remove(pal->debugfs_dir);
 
 	if (pal->device) {
-		sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+		/* remove link to the PAL in the UWB device's directory. */
+		if (uwb_rc_class_device_exists(rc))
+			sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+
+		/* remove link to uwb_rc in the PAL device's directory. */
 		sysfs_remove_link(&pal->device->kobj, "uwb_rc");
 	}
 }
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4cf1e1d..34c3d96 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2457,7 +2457,7 @@
 
 config FB_SIMPLE
 	bool "Simple framebuffer support"
-	depends on (FB = y) && OF
+	depends on (FB = y)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
@@ -2469,8 +2469,7 @@
 	  pre-allocated frame buffer surface.
 
 	  Configuration re: surface address, size, and format must be provided
-	  through device tree, or potentially plain old platform data in the
-	  future.
+	  through device tree, or plain old platform data.
 
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 3fccb6d..94a403a 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -103,16 +103,16 @@
 	sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
 }
 
-static ssize_t backlight_show_power(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.power);
 }
 
-static ssize_t backlight_store_power(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	int rc;
 	struct backlight_device *bd = to_backlight_device(dev);
@@ -136,8 +136,9 @@
 
 	return rc;
 }
+static DEVICE_ATTR_RW(bl_power);
 
-static ssize_t backlight_show_brightness(struct device *dev,
+static ssize_t brightness_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct backlight_device *bd = to_backlight_device(dev);
@@ -145,7 +146,7 @@
 	return sprintf(buf, "%d\n", bd->props.brightness);
 }
 
-static ssize_t backlight_store_brightness(struct device *dev,
+static ssize_t brightness_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc;
@@ -175,24 +176,27 @@
 
 	return rc;
 }
+static DEVICE_ATTR_RW(brightness);
 
-static ssize_t backlight_show_type(struct device *dev,
-		struct device_attribute *attr, char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
 }
+static DEVICE_ATTR_RO(type);
 
-static ssize_t backlight_show_max_brightness(struct device *dev,
+static ssize_t max_brightness_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.max_brightness);
 }
+static DEVICE_ATTR_RO(max_brightness);
 
-static ssize_t backlight_show_actual_brightness(struct device *dev,
+static ssize_t actual_brightness_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	int rc = -ENXIO;
@@ -205,6 +209,7 @@
 
 	return rc;
 }
+static DEVICE_ATTR_RO(actual_brightness);
 
 static struct class *backlight_class;
 
@@ -247,16 +252,15 @@
 	kfree(bd);
 }
 
-static struct device_attribute bl_device_attributes[] = {
-	__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
-	__ATTR(brightness, 0644, backlight_show_brightness,
-		     backlight_store_brightness),
-	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
-		     NULL),
-	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
-	__ATTR(type, 0444, backlight_show_type, NULL),
-	__ATTR_NULL,
+static struct attribute *bl_device_attrs[] = {
+	&dev_attr_bl_power.attr,
+	&dev_attr_brightness.attr,
+	&dev_attr_actual_brightness.attr,
+	&dev_attr_max_brightness.attr,
+	&dev_attr_type.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(bl_device);
 
 /**
  * backlight_force_update - tell the backlight subsystem that hardware state
@@ -493,7 +497,7 @@
 		return PTR_ERR(backlight_class);
 	}
 
-	backlight_class->dev_attrs = bl_device_attributes;
+	backlight_class->dev_groups = bl_device_groups;
 	backlight_class->pm = &backlight_class_dev_pm_ops;
 	return 0;
 }
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 41964a7..93cf15e 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -89,7 +89,7 @@
 }
 #endif /* CONFIG_FB */
 
-static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+static ssize_t lcd_power_show(struct device *dev, struct device_attribute *attr,
 		char *buf)
 {
 	int rc;
@@ -105,7 +105,7 @@
 	return rc;
 }
 
-static ssize_t lcd_store_power(struct device *dev,
+static ssize_t lcd_power_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc;
@@ -128,8 +128,9 @@
 
 	return rc;
 }
+static DEVICE_ATTR_RW(lcd_power);
 
-static ssize_t lcd_show_contrast(struct device *dev,
+static ssize_t contrast_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	int rc = -ENXIO;
@@ -143,7 +144,7 @@
 	return rc;
 }
 
-static ssize_t lcd_store_contrast(struct device *dev,
+static ssize_t contrast_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc;
@@ -166,14 +167,16 @@
 
 	return rc;
 }
+static DEVICE_ATTR_RW(contrast);
 
-static ssize_t lcd_show_max_contrast(struct device *dev,
+static ssize_t max_contrast_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct lcd_device *ld = to_lcd_device(dev);
 
 	return sprintf(buf, "%d\n", ld->props.max_contrast);
 }
+static DEVICE_ATTR_RO(max_contrast);
 
 static struct class *lcd_class;
 
@@ -183,12 +186,13 @@
 	kfree(ld);
 }
 
-static struct device_attribute lcd_device_attributes[] = {
-	__ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
-	__ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
-	__ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
-	__ATTR_NULL,
+static struct attribute *lcd_device_attrs[] = {
+	&dev_attr_lcd_power.attr,
+	&dev_attr_contrast.attr,
+	&dev_attr_max_contrast.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(lcd_device);
 
 /**
  * lcd_device_register - register a new object of lcd_device class.
@@ -344,7 +348,7 @@
 		return PTR_ERR(lcd_class);
 	}
 
-	lcd_class->dev_attrs = lcd_device_attributes;
+	lcd_class->dev_groups = lcd_device_groups;
 	return 0;
 }
 
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 8c30603..846caab 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -92,7 +92,8 @@
 
 config FRAMEBUFFER_CONSOLE
 	tristate "Framebuffer Console support"
-	depends on FB
+	depends on FB && !UML
+	select VT_HW_CONSOLE_BINDING
 	select CRC32
 	select FONT_SUPPORT
 	help
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 50fe668..2a8286e 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -15,6 +15,7 @@
 #include <linux/dmi.h>
 #include <linux/pci.h>
 #include <video/vga.h>
+#include <asm/sysfb.h>
 
 static bool request_mem_succeeded = false;
 
@@ -38,223 +39,6 @@
 	.visual			= FB_VISUAL_TRUECOLOR,
 };
 
-enum {
-	M_I17,		/* 17-Inch iMac */
-	M_I20,		/* 20-Inch iMac */
-	M_I20_SR,	/* 20-Inch iMac (Santa Rosa) */
-	M_I24,		/* 24-Inch iMac */
-	M_I24_8_1,	/* 24-Inch iMac, 8,1th gen */
-	M_I24_10_1,	/* 24-Inch iMac, 10,1th gen */
-	M_I27_11_1,	/* 27-Inch iMac, 11,1th gen */
-	M_MINI,		/* Mac Mini */
-	M_MINI_3_1,	/* Mac Mini, 3,1th gen */
-	M_MINI_4_1,	/* Mac Mini, 4,1th gen */
-	M_MB,		/* MacBook */
-	M_MB_2,		/* MacBook, 2nd rev. */
-	M_MB_3,		/* MacBook, 3rd rev. */
-	M_MB_5_1,	/* MacBook, 5th rev. */
-	M_MB_6_1,	/* MacBook, 6th rev. */
-	M_MB_7_1,	/* MacBook, 7th rev. */
-	M_MB_SR,	/* MacBook, 2nd gen, (Santa Rosa) */
-	M_MBA,		/* MacBook Air */
-	M_MBA_3,	/* Macbook Air, 3rd rev */
-	M_MBP,		/* MacBook Pro */
-	M_MBP_2,	/* MacBook Pro 2nd gen */
-	M_MBP_2_2,	/* MacBook Pro 2,2nd gen */
-	M_MBP_SR,	/* MacBook Pro (Santa Rosa) */
-	M_MBP_4,	/* MacBook Pro, 4th gen */
-	M_MBP_5_1,    /* MacBook Pro, 5,1th gen */
-	M_MBP_5_2,	/* MacBook Pro, 5,2th gen */
-	M_MBP_5_3,	/* MacBook Pro, 5,3rd gen */
-	M_MBP_6_1,	/* MacBook Pro, 6,1th gen */
-	M_MBP_6_2,	/* MacBook Pro, 6,2th gen */
-	M_MBP_7_1,	/* MacBook Pro, 7,1th gen */
-	M_MBP_8_2,	/* MacBook Pro, 8,2nd gen */
-	M_UNKNOWN	/* placeholder */
-};
-
-#define OVERRIDE_NONE	0x0
-#define OVERRIDE_BASE	0x1
-#define OVERRIDE_STRIDE	0x2
-#define OVERRIDE_HEIGHT	0x4
-#define OVERRIDE_WIDTH	0x8
-
-static struct efifb_dmi_info {
-	char *optname;
-	unsigned long base;
-	int stride;
-	int width;
-	int height;
-	int flags;
-} dmi_list[] __initdata = {
-	[M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */
-	[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE },
-	[M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */
-	[M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE },
-	[M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE },
-	[M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE },
-	[M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE },
-	[M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	/* 11" Macbook Air 3,1 passes the wrong stride */
-	[M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE },
-	[M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */
-	[M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE },
-	[M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE },
-	[M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE },
-	[M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE },
-	[M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE }
-};
-
-static int set_system(const struct dmi_system_id *id);
-
-#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid)		\
-	{ set_system, name, {					\
-		DMI_MATCH(DMI_BIOS_VENDOR, vendor),		\
-		DMI_MATCH(DMI_PRODUCT_NAME, name) },		\
-	  &dmi_list[enumid] }
-
-static const struct dmi_system_id dmi_system_table[] __initconst = {
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac8,1", M_I24_8_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac10,1", M_I24_10_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac11,1", M_I27_11_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini3,1", M_MINI_3_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "Macmini4,1", M_MINI_4_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
-	/* At least one of these two will be right; maybe both? */
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook5,1", M_MB_5_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,2", M_MBP_5_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,3", M_MBP_5_3),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1),
-	EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2),
-	{},
-};
-
-#define choose_value(dmivalue, fwvalue, field, flags) ({	\
-		typeof(fwvalue) _ret_ = fwvalue;		\
-		if ((flags) & (field))				\
-			_ret_ = dmivalue;			\
-		else if ((fwvalue) == 0)			\
-			_ret_ = dmivalue;			\
-		_ret_;						\
-	})
-
-static int set_system(const struct dmi_system_id *id)
-{
-	struct efifb_dmi_info *info = id->driver_data;
-
-	if (info->base == 0 && info->height == 0 && info->width == 0
-			&& info->stride == 0)
-		return 0;
-
-	/* Trust the bootloader over the DMI tables */
-	if (screen_info.lfb_base == 0) {
-#if defined(CONFIG_PCI)
-		struct pci_dev *dev = NULL;
-		int found_bar = 0;
-#endif
-		if (info->base) {
-			screen_info.lfb_base = choose_value(info->base,
-				screen_info.lfb_base, OVERRIDE_BASE,
-				info->flags);
-
-#if defined(CONFIG_PCI)
-			/* make sure that the address in the table is actually
-			 * on a VGA device's PCI BAR */
-
-			for_each_pci_dev(dev) {
-				int i;
-				if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-					continue;
-				for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-					resource_size_t start, end;
-
-					start = pci_resource_start(dev, i);
-					if (start == 0)
-						break;
-					end = pci_resource_end(dev, i);
-					if (screen_info.lfb_base >= start &&
-					    screen_info.lfb_base < end) {
-						found_bar = 1;
-					}
-				}
-			}
-			if (!found_bar)
-				screen_info.lfb_base = 0;
-#endif
-		}
-	}
-	if (screen_info.lfb_base) {
-		screen_info.lfb_linelength = choose_value(info->stride,
-			screen_info.lfb_linelength, OVERRIDE_STRIDE,
-			info->flags);
-		screen_info.lfb_width = choose_value(info->width,
-			screen_info.lfb_width, OVERRIDE_WIDTH,
-			info->flags);
-		screen_info.lfb_height = choose_value(info->height,
-			screen_info.lfb_height, OVERRIDE_HEIGHT,
-			info->flags);
-		if (screen_info.orig_video_isVGA == 0)
-			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
-	} else {
-		screen_info.lfb_linelength = 0;
-		screen_info.lfb_width = 0;
-		screen_info.lfb_height = 0;
-		screen_info.orig_video_isVGA = 0;
-		return 0;
-	}
-
-	printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
-			 "(%dx%d, stride %d)\n", id->ident,
-			 screen_info.lfb_base, screen_info.lfb_width,
-			 screen_info.lfb_height, screen_info.lfb_linelength);
-
-
-	return 1;
-}
-
 static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			   unsigned blue, unsigned transp,
 			   struct fb_info *info)
@@ -312,7 +96,7 @@
 	default_vga = pdev;
 }
 
-static int __init efifb_setup(char *options)
+static int efifb_setup(char *options)
 {
 	char *this_opt;
 	int i;
@@ -323,12 +107,12 @@
 			if (!*this_opt) continue;
 
 			for (i = 0; i < M_UNKNOWN; i++) {
-				if (!strcmp(this_opt, dmi_list[i].optname) &&
-				    dmi_list[i].base != 0) {
-					screen_info.lfb_base = dmi_list[i].base;
-					screen_info.lfb_linelength = dmi_list[i].stride;
-					screen_info.lfb_width = dmi_list[i].width;
-					screen_info.lfb_height = dmi_list[i].height;
+				if (!strcmp(this_opt, efifb_dmi_list[i].optname) &&
+				    efifb_dmi_list[i].base != 0) {
+					screen_info.lfb_base = efifb_dmi_list[i].base;
+					screen_info.lfb_linelength = efifb_dmi_list[i].stride;
+					screen_info.lfb_width = efifb_dmi_list[i].width;
+					screen_info.lfb_height = efifb_dmi_list[i].height;
 				}
 			}
 			if (!strncmp(this_opt, "base:", 5))
@@ -369,13 +153,28 @@
 	return 0;
 }
 
-static int __init efifb_probe(struct platform_device *dev)
+static int efifb_probe(struct platform_device *dev)
 {
 	struct fb_info *info;
 	int err;
 	unsigned int size_vmode;
 	unsigned int size_remap;
 	unsigned int size_total;
+	char *option = NULL;
+
+	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+		return -ENODEV;
+
+	if (fb_get_options("efifb", &option))
+		return -ENODEV;
+	efifb_setup(option);
+
+	/* We don't get linelength from UGA Draw Protocol, only from
+	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
+	 * passed in from the user, we really can't use the framebuffer.
+	 */
+	if (!screen_info.lfb_linelength)
+		return -ENODEV;
 
 	if (!screen_info.lfb_depth)
 		screen_info.lfb_depth = 32;
@@ -539,55 +338,12 @@
 }
 
 static struct platform_driver efifb_driver = {
-	.driver	= {
-		.name	= "efifb",
+	.driver = {
+		.name = "efi-framebuffer",
+		.owner = THIS_MODULE,
 	},
+	.probe = efifb_probe,
 };
 
-static struct platform_device efifb_device = {
-	.name	= "efifb",
-};
-
-static int __init efifb_init(void)
-{
-	int ret;
-	char *option = NULL;
-
-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
-	    !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
-		dmi_check_system(dmi_system_table);
-
-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
-		return -ENODEV;
-
-	if (fb_get_options("efifb", &option))
-		return -ENODEV;
-	efifb_setup(option);
-
-	/* We don't get linelength from UGA Draw Protocol, only from
-	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
-	 * passed in from the user, we really can't use the framebuffer.
-	 */
-	if (!screen_info.lfb_linelength)
-		return -ENODEV;
-
-	ret = platform_device_register(&efifb_device);
-	if (ret)
-		return ret;
-
-	/*
-	 * This is not just an optimization.  We will interfere
-	 * with a real driver if we get reprobed, so don't allow
-	 * it.
-	 */
-	ret = platform_driver_probe(&efifb_driver, efifb_probe);
-	if (ret) {
-		platform_device_unregister(&efifb_device);
-		return ret;
-	}
-
-	return ret;
-}
-module_init(efifb_init);
-
+module_platform_driver(efifb_driver);
 MODULE_LICENSE("GPL");
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
index d4d2c5f..8ac99b8 100644
--- a/drivers/video/hyperv_fb.c
+++ b/drivers/video/hyperv_fb.c
@@ -825,5 +825,4 @@
 module_exit(hvfb_drv_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
 MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 1aeb274..a7ce26c 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -189,7 +189,7 @@
 	d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
 			write, &dss_debug_fops);
 
-	return PTR_RET(d);
+	return PTR_ERR_OR_ZERO(d);
 }
 #else /* CONFIG_OMAP2_DSS_DEBUGFS */
 static inline int dss_initialize_debugfs(void)
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
index e2e9e3e..8d78106 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb.c
@@ -24,6 +24,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/platform_data/simplefb.h>
 #include <linux/platform_device.h>
 
 static struct fb_fix_screeninfo simplefb_fix = {
@@ -73,18 +74,7 @@
 	.fb_imageblit	= cfb_imageblit,
 };
 
-struct simplefb_format {
-	const char *name;
-	u32 bits_per_pixel;
-	struct fb_bitfield red;
-	struct fb_bitfield green;
-	struct fb_bitfield blue;
-	struct fb_bitfield transp;
-};
-
-static struct simplefb_format simplefb_formats[] = {
-	{ "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} },
-};
+static struct simplefb_format simplefb_formats[] = SIMPLEFB_FORMATS;
 
 struct simplefb_params {
 	u32 width;
@@ -139,6 +129,33 @@
 	return 0;
 }
 
+static int simplefb_parse_pd(struct platform_device *pdev,
+			     struct simplefb_params *params)
+{
+	struct simplefb_platform_data *pd = pdev->dev.platform_data;
+	int i;
+
+	params->width = pd->width;
+	params->height = pd->height;
+	params->stride = pd->stride;
+
+	params->format = NULL;
+	for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
+		if (strcmp(pd->format, simplefb_formats[i].name))
+			continue;
+
+		params->format = &simplefb_formats[i];
+		break;
+	}
+
+	if (!params->format) {
+		dev_err(&pdev->dev, "Invalid format value\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int simplefb_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -149,7 +166,12 @@
 	if (fb_get_options("simplefb", NULL))
 		return -ENODEV;
 
-	ret = simplefb_parse_dt(pdev, &params);
+	ret = -ENODEV;
+	if (pdev->dev.platform_data)
+		ret = simplefb_parse_pd(pdev, &params);
+	else if (pdev->dev.of_node)
+		ret = simplefb_parse_dt(pdev, &params);
+
 	if (ret)
 		return ret;
 
@@ -180,8 +202,16 @@
 	info->var.blue = params.format->blue;
 	info->var.transp = params.format->transp;
 
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures) {
+		framebuffer_release(info);
+		return -ENOMEM;
+	}
+	info->apertures->ranges[0].base = info->fix.smem_start;
+	info->apertures->ranges[0].size = info->fix.smem_len;
+
 	info->fbops = &simplefb_ops;
-	info->flags = FBINFO_DEFAULT;
+	info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
 	info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start,
 					 info->fix.smem_len);
 	if (!info->screen_base) {
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 501b340..bd83233 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -29,7 +29,7 @@
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vesafb_defined __initdata = {
+static struct fb_var_screeninfo vesafb_defined = {
 	.activate	= FB_ACTIVATE_NOW,
 	.height		= -1,
 	.width		= -1,
@@ -40,7 +40,7 @@
 	.vmode		= FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo vesafb_fix __initdata = {
+static struct fb_fix_screeninfo vesafb_fix = {
 	.id	= "VESA VGA",
 	.type	= FB_TYPE_PACKED_PIXELS,
 	.accel	= FB_ACCEL_NONE,
@@ -48,8 +48,8 @@
 
 static int   inverse    __read_mostly;
 static int   mtrr       __read_mostly;		/* disable mtrr */
-static int   vram_remap __initdata;		/* Set amount of memory to be used */
-static int   vram_total __initdata;		/* Set total amount of memory */
+static int   vram_remap;			/* Set amount of memory to be used */
+static int   vram_total;			/* Set total amount of memory */
 static int   pmi_setpal __read_mostly = 1;	/* pmi for palette changes ??? */
 static int   ypan       __read_mostly;		/* 0..nothing, 1..ypan, 2..ywrap */
 static void  (*pmi_start)(void) __read_mostly;
@@ -192,7 +192,7 @@
 	.fb_imageblit	= cfb_imageblit,
 };
 
-static int __init vesafb_setup(char *options)
+static int vesafb_setup(char *options)
 {
 	char *this_opt;
 	
@@ -226,13 +226,18 @@
 	return 0;
 }
 
-static int __init vesafb_probe(struct platform_device *dev)
+static int vesafb_probe(struct platform_device *dev)
 {
 	struct fb_info *info;
 	int i, err;
 	unsigned int size_vmode;
 	unsigned int size_remap;
 	unsigned int size_total;
+	char *option = NULL;
+
+	/* ignore error return of fb_get_options */
+	fb_get_options("vesafb", &option);
+	vesafb_setup(option);
 
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
 		return -ENODEV;
@@ -496,40 +501,12 @@
 }
 
 static struct platform_driver vesafb_driver = {
-	.driver	= {
-		.name	= "vesafb",
+	.driver = {
+		.name = "vesa-framebuffer",
+		.owner = THIS_MODULE,
 	},
+	.probe = vesafb_probe,
 };
 
-static struct platform_device *vesafb_device;
-
-static int __init vesafb_init(void)
-{
-	int ret;
-	char *option = NULL;
-
-	/* ignore error return of fb_get_options */
-	fb_get_options("vesafb", &option);
-	vesafb_setup(option);
-
-	vesafb_device = platform_device_alloc("vesafb", 0);
-	if (!vesafb_device)
-		return -ENOMEM;
-
-	ret = platform_device_add(vesafb_device);
-	if (!ret) {
-		ret = platform_driver_probe(&vesafb_driver, vesafb_probe);
-		if (ret)
-			platform_device_del(vesafb_device);
-	}
-
-	if (ret) {
-		platform_device_put(vesafb_device);
-		vesafb_device = NULL;
-	}
-
-	return ret;
-}
-module_init(vesafb_init);
-
+module_platform_driver(vesafb_driver);
 MODULE_LICENSE("GPL");
diff --git a/drivers/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c
index dd22b50..cf74aee 100644
--- a/drivers/vme/boards/vme_vmivme7805.c
+++ b/drivers/vme/boards/vme_vmivme7805.c
@@ -23,7 +23,7 @@
 static void vmic_remove(struct pci_dev *);
 
 /** Base address to access FPGA register */
-static void *vmic_base;
+static void __iomem *vmic_base;
 
 static const char driver_name[] = "vmivme_7805";
 
diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index 64bfea3..f844857 100644
--- a/drivers/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -243,6 +243,8 @@
 static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge,
 	struct pci_dev *pdev)
 {
+	struct vme_bridge *ca91cx42_bridge;
+
 	/* Disable interrupts from PCI to VME */
 	iowrite32(0, bridge->base + VINT_EN);
 
@@ -251,7 +253,9 @@
 	/* Clear Any Pending PCI Interrupts */
 	iowrite32(0x00FFFFFF, bridge->base + LINT_STAT);
 
-	free_irq(pdev->irq, pdev);
+	ca91cx42_bridge = container_of((void *)bridge, struct vme_bridge,
+				       driver_priv);
+	free_irq(pdev->irq, ca91cx42_bridge);
 }
 
 static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level)
@@ -856,7 +860,7 @@
 	void *buf, size_t count, loff_t offset)
 {
 	ssize_t retval;
-	void *addr = image->kern_base + offset;
+	void __iomem *addr = image->kern_base + offset;
 	unsigned int done = 0;
 	unsigned int count32;
 
@@ -916,7 +920,7 @@
 	void *buf, size_t count, loff_t offset)
 {
 	ssize_t retval;
-	void *addr = image->kern_base + offset;
+	void __iomem *addr = image->kern_base + offset;
 	unsigned int done = 0;
 	unsigned int count32;
 
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index 94c892f..9cf8833 100644
--- a/drivers/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -1267,7 +1267,7 @@
 	u32 aspace, cycle, dwidth;
 	struct vme_bus_error *vme_err = NULL;
 	struct vme_bridge *tsi148_bridge;
-	void *addr = image->kern_base + offset;
+	void __iomem *addr = image->kern_base + offset;
 	unsigned int done = 0;
 	unsigned int count32;
 
@@ -1348,7 +1348,7 @@
 	int retval = 0, enabled;
 	unsigned long long vme_base, size;
 	u32 aspace, cycle, dwidth;
-	void *addr = image->kern_base + offset;
+	void __iomem *addr = image->kern_base + offset;
 	unsigned int done = 0;
 	unsigned int count32;
 
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index cb8a8e5..7dfa0e1 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -72,10 +72,9 @@
 	return 1;
 }
 
-static ssize_t w1_f29_read_state(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t state_read(struct file *filp, struct kobject *kobj,
+			  struct bin_attribute *bin_attr, char *buf, loff_t off,
+			  size_t count)
 {
 	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
 		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -85,10 +84,9 @@
 	return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
 }
 
-static ssize_t w1_f29_read_output(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t output_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
 {
 	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
 		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -99,10 +97,9 @@
 					 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
 }
 
-static ssize_t w1_f29_read_activity(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t activity_read(struct file *filp, struct kobject *kobj,
+			     struct bin_attribute *bin_attr, char *buf,
+			     loff_t off, size_t count)
 {
 	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
 		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -113,10 +110,9 @@
 					 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
 }
 
-static ssize_t w1_f29_read_cond_search_mask(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
+				     struct bin_attribute *bin_attr, char *buf,
+				     loff_t off, size_t count)
 {
 	dev_dbg(&kobj_to_w1_slave(kobj)->dev,
 		"Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
@@ -127,10 +123,10 @@
 		W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
 }
 
-static ssize_t w1_f29_read_cond_search_polarity(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t cond_search_polarity_read(struct file *filp,
+					 struct kobject *kobj,
+					 struct bin_attribute *bin_attr,
+					 char *buf, loff_t off, size_t count)
 {
 	if (count != 1 || off != 0)
 		return -EFAULT;
@@ -138,10 +134,9 @@
 		W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
 }
 
-static ssize_t w1_f29_read_status_control(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
+				   struct bin_attribute *bin_attr, char *buf,
+				   loff_t off, size_t count)
 {
 	if (count != 1 || off != 0)
 		return -EFAULT;
@@ -149,13 +144,9 @@
 		W1_F29_REG_CONTROL_AND_STATUS, buf);
 }
 
-
-
-
-static ssize_t w1_f29_write_output(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t output_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	u8 w1_buf[3];
@@ -224,10 +215,9 @@
 /**
  * Writing to the activity file resets the activity latches.
  */
-static ssize_t w1_f29_write_activity(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t activity_write(struct file *filp, struct kobject *kobj,
+			      struct bin_attribute *bin_attr, char *buf,
+			      loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	unsigned int retries = W1_F29_RETRIES;
@@ -255,13 +245,9 @@
 	return -EIO;
 }
 
-static ssize_t w1_f29_write_status_control(
-	struct file *filp,
-	struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf,
-	loff_t off,
-	size_t count)
+static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
+				    struct bin_attribute *bin_attr, char *buf,
+				    loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	u8 w1_buf[4];
@@ -330,91 +316,35 @@
 	return res;
 }
 
-static struct bin_attribute w1_f29_sysfs_bin_files[] = {
-	{
-		.attr =	{
-			.name = "state",
-			.mode = S_IRUGO,
-		},
-		.size = 1,
-		.read = w1_f29_read_state,
-	},
-	{
-		.attr =	{
-			.name = "output",
-			.mode = S_IRUGO | S_IWUSR | S_IWGRP,
-		},
-		.size = 1,
-		.read = w1_f29_read_output,
-		.write = w1_f29_write_output,
-	},
-	{
-		.attr =	{
-			.name = "activity",
-			.mode = S_IRUGO,
-		},
-		.size = 1,
-		.read = w1_f29_read_activity,
-		.write = w1_f29_write_activity,
-	},
-	{
-		.attr =	{
-			.name = "cond_search_mask",
-			.mode = S_IRUGO,
-		},
-		.size = 1,
-		.read = w1_f29_read_cond_search_mask,
-	},
-	{
-		.attr =	{
-			.name = "cond_search_polarity",
-			.mode = S_IRUGO,
-		},
-		.size = 1,
-		.read = w1_f29_read_cond_search_polarity,
-	},
-	{
-		.attr =	{
-			.name = "status_control",
-			.mode = S_IRUGO | S_IWUSR | S_IWGRP,
-		},
-		.size = 1,
-		.read = w1_f29_read_status_control,
-		.write = w1_f29_write_status_control,
-	}
+static BIN_ATTR_RO(state, 1);
+static BIN_ATTR_RW(output, 1);
+static BIN_ATTR_RW(activity, 1);
+static BIN_ATTR_RO(cond_search_mask, 1);
+static BIN_ATTR_RO(cond_search_polarity, 1);
+static BIN_ATTR_RW(status_control, 1);
+
+static struct bin_attribute *w1_f29_bin_attrs[] = {
+	&bin_attr_state,
+	&bin_attr_output,
+	&bin_attr_activity,
+	&bin_attr_cond_search_mask,
+	&bin_attr_cond_search_polarity,
+	&bin_attr_status_control,
+	NULL,
 };
 
-static int w1_f29_add_slave(struct w1_slave *sl)
-{
-	int err = 0;
-	int i;
+static const struct attribute_group w1_f29_group = {
+	.bin_attrs = w1_f29_bin_attrs,
+};
 
-	err = w1_f29_disable_test_mode(sl);
-	if (err)
-		return err;
-
-	for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i)
-		err = sysfs_create_bin_file(
-			&sl->dev.kobj,
-			&(w1_f29_sysfs_bin_files[i]));
-	if (err)
-		while (--i >= 0)
-			sysfs_remove_bin_file(&sl->dev.kobj,
-				&(w1_f29_sysfs_bin_files[i]));
-	return err;
-}
-
-static void w1_f29_remove_slave(struct w1_slave *sl)
-{
-	int i;
-	for (i = ARRAY_SIZE(w1_f29_sysfs_bin_files) - 1; i >= 0; --i)
-		sysfs_remove_bin_file(&sl->dev.kobj,
-			&(w1_f29_sysfs_bin_files[i]));
-}
+static const struct attribute_group *w1_f29_groups[] = {
+	&w1_f29_group,
+	NULL,
+};
 
 static struct w1_family_ops w1_f29_fops = {
-	.add_slave      = w1_f29_add_slave,
-	.remove_slave   = w1_f29_remove_slave,
+	.add_slave      = w1_f29_disable_test_mode,
+	.groups		= w1_f29_groups,
 };
 
 static struct w1_family w1_family_29 = {
diff --git a/drivers/w1/slaves/w1_ds2413.c b/drivers/w1/slaves/w1_ds2413.c
index 8593777..ee28fc1 100644
--- a/drivers/w1/slaves/w1_ds2413.c
+++ b/drivers/w1/slaves/w1_ds2413.c
@@ -30,10 +30,9 @@
 #define W1_F3A_FUNC_PIO_ACCESS_WRITE       0x5A
 #define W1_F3A_SUCCESS_CONFIRM_BYTE        0xAA
 
-static ssize_t w1_f3a_read_state(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static ssize_t state_read(struct file *filp, struct kobject *kobj,
+			  struct bin_attribute *bin_attr, char *buf, loff_t off,
+			  size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	dev_dbg(&sl->dev,
@@ -66,10 +65,11 @@
 		return 1;
 }
 
-static ssize_t w1_f3a_write_output(
-	struct file *filp, struct kobject *kobj,
-	struct bin_attribute *bin_attr,
-	char *buf, loff_t off, size_t count)
+static BIN_ATTR_RO(state, 1);
+
+static ssize_t output_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	u8 w1_buf[3];
@@ -110,53 +110,25 @@
 	return -EIO;
 }
 
-#define NB_SYSFS_BIN_FILES 2
-static struct bin_attribute w1_f3a_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
-	{
-		.attr = {
-			.name = "state",
-			.mode = S_IRUGO,
-		},
-		.size = 1,
-		.read = w1_f3a_read_state,
-	},
-	{
-		.attr = {
-			.name = "output",
-			.mode = S_IRUGO | S_IWUSR | S_IWGRP,
-		},
-		.size = 1,
-		.write = w1_f3a_write_output,
-	}
+static BIN_ATTR(output, S_IRUGO | S_IWUSR | S_IWGRP, NULL, output_write, 1);
+
+static struct bin_attribute *w1_f3a_bin_attrs[] = {
+	&bin_attr_state,
+	&bin_attr_output,
+	NULL,
 };
 
-static int w1_f3a_add_slave(struct w1_slave *sl)
-{
-	int err = 0;
-	int i;
+static const struct attribute_group w1_f3a_group = {
+	.bin_attrs = w1_f3a_bin_attrs,
+};
 
-	for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
-		err = sysfs_create_bin_file(
-			&sl->dev.kobj,
-			&(w1_f3a_sysfs_bin_files[i]));
-	if (err)
-		while (--i >= 0)
-			sysfs_remove_bin_file(&sl->dev.kobj,
-				&(w1_f3a_sysfs_bin_files[i]));
-	return err;
-}
-
-static void w1_f3a_remove_slave(struct w1_slave *sl)
-{
-	int i;
-	for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
-		sysfs_remove_bin_file(&sl->dev.kobj,
-			&(w1_f3a_sysfs_bin_files[i]));
-}
+static const struct attribute_group *w1_f3a_groups[] = {
+	&w1_f3a_group,
+	NULL,
+};
 
 static struct w1_family_ops w1_f3a_fops = {
-	.add_slave      = w1_f3a_add_slave,
-	.remove_slave   = w1_f3a_remove_slave,
+	.groups		= w1_f3a_groups,
 };
 
 static struct w1_family w1_family_3a = {
diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c
index 7f86aec..7e41b7d 100644
--- a/drivers/w1/slaves/w1_ds2423.c
+++ b/drivers/w1/slaves/w1_ds2423.c
@@ -40,14 +40,8 @@
 #define COUNTER_COUNT 4
 #define READ_BYTE_COUNT 42
 
-static ssize_t w1_counter_read(struct device *device,
-	struct device_attribute *attr, char *buf);
-
-static struct device_attribute w1_counter_attr =
-	__ATTR(w1_slave, S_IRUGO, w1_counter_read, NULL);
-
-static ssize_t w1_counter_read(struct device *device,
-	struct device_attribute *attr, char *out_buf)
+static ssize_t w1_slave_show(struct device *device,
+			     struct device_attribute *attr, char *out_buf)
 {
 	struct w1_slave *sl = dev_to_w1_slave(device);
 	struct w1_master *dev = sl->master;
@@ -128,19 +122,16 @@
 	return PAGE_SIZE - c;
 }
 
-static int w1_f1d_add_slave(struct w1_slave *sl)
-{
-	return device_create_file(&sl->dev, &w1_counter_attr);
-}
+static DEVICE_ATTR_RO(w1_slave);
 
-static void w1_f1d_remove_slave(struct w1_slave *sl)
-{
-	device_remove_file(&sl->dev, &w1_counter_attr);
-}
+static struct attribute *w1_f1d_attrs[] = {
+	&dev_attr_w1_slave.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(w1_f1d);
 
 static struct w1_family_ops w1_f1d_fops = {
-	.add_slave      = w1_f1d_add_slave,
-	.remove_slave   = w1_f1d_remove_slave,
+	.groups		= w1_f1d_groups,
 };
 
 static struct w1_family w1_family_1d = {
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
index cef8605..9c4ff9d 100644
--- a/drivers/w1/slaves/w1_ds2431.c
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -96,9 +96,9 @@
 	return -1;
 }
 
-static ssize_t w1_f2d_read_bin(struct file *filp, struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	int todo = count;
@@ -202,9 +202,9 @@
 	return 0;
 }
 
-static ssize_t w1_f2d_write_bin(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t off, size_t count)
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	int addr, len;
@@ -264,29 +264,24 @@
 	return count;
 }
 
-static struct bin_attribute w1_f2d_bin_attr = {
-	.attr = {
-		.name = "eeprom",
-		.mode = S_IRUGO | S_IWUSR,
-	},
-	.size = W1_F2D_EEPROM_SIZE,
-	.read = w1_f2d_read_bin,
-	.write = w1_f2d_write_bin,
+static BIN_ATTR_RW(eeprom, W1_F2D_EEPROM_SIZE);
+
+static struct bin_attribute *w1_f2d_bin_attrs[] = {
+	&bin_attr_eeprom,
+	NULL,
 };
 
-static int w1_f2d_add_slave(struct w1_slave *sl)
-{
-	return sysfs_create_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
-}
+static const struct attribute_group w1_f2d_group = {
+	.bin_attrs = w1_f2d_bin_attrs,
+};
 
-static void w1_f2d_remove_slave(struct w1_slave *sl)
-{
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
-}
+static const struct attribute_group *w1_f2d_groups[] = {
+	&w1_f2d_group,
+	NULL,
+};
 
 static struct w1_family_ops w1_f2d_fops = {
-	.add_slave      = w1_f2d_add_slave,
-	.remove_slave   = w1_f2d_remove_slave,
+	.groups		= w1_f2d_groups,
 };
 
 static struct w1_family w1_family_2d = {
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index 10cc1b6..72319a9 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -93,9 +93,9 @@
 }
 #endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
 
-static ssize_t w1_f23_read_bin(struct file *filp, struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 #ifdef CONFIG_W1_SLAVE_DS2433_CRC
@@ -207,9 +207,9 @@
 	return 0;
 }
 
-static ssize_t w1_f23_write_bin(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t off, size_t count)
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	int addr, len, idx;
@@ -257,19 +257,24 @@
 	return count;
 }
 
-static struct bin_attribute w1_f23_bin_attr = {
-	.attr = {
-		.name = "eeprom",
-		.mode = S_IRUGO | S_IWUSR,
-	},
-	.size = W1_EEPROM_SIZE,
-	.read = w1_f23_read_bin,
-	.write = w1_f23_write_bin,
+static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+
+static struct bin_attribute *w1_f23_bin_attributes[] = {
+	&bin_attr_eeprom,
+	NULL,
+};
+
+static const struct attribute_group w1_f23_group = {
+	.bin_attrs = w1_f23_bin_attributes,
+};
+
+static const struct attribute_group *w1_f23_groups[] = {
+	&w1_f23_group,
+	NULL,
 };
 
 static int w1_f23_add_slave(struct w1_slave *sl)
 {
-	int err;
 #ifdef CONFIG_W1_SLAVE_DS2433_CRC
 	struct w1_f23_data *data;
 
@@ -279,15 +284,7 @@
 	sl->family_data = data;
 
 #endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
-
-	err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
-
-#ifdef CONFIG_W1_SLAVE_DS2433_CRC
-	if (err)
-		kfree(data);
-#endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
-
-	return err;
+	return 0;
 }
 
 static void w1_f23_remove_slave(struct w1_slave *sl)
@@ -296,12 +293,12 @@
 	kfree(sl->family_data);
 	sl->family_data = NULL;
 #endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr);
 }
 
 static struct w1_family_ops w1_f23_fops = {
 	.add_slave      = w1_f23_add_slave,
 	.remove_slave   = w1_f23_remove_slave,
+	.groups		= w1_f23_groups,
 };
 
 static struct w1_family w1_family_23 = {
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
index 93719d25..65f90dc 100644
--- a/drivers/w1/slaves/w1_ds2760.c
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -97,21 +97,28 @@
 	return w1_ds2760_eeprom_cmd(dev, addr, W1_DS2760_RECALL_DATA);
 }
 
-static ssize_t w1_ds2760_read_bin(struct file *filp, struct kobject *kobj,
-				  struct bin_attribute *bin_attr,
-				  char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read(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_ds2760_read(dev, buf, off, count);
 }
 
-static struct bin_attribute w1_ds2760_bin_attr = {
-	.attr = {
-		.name = "w1_slave",
-		.mode = S_IRUGO,
-	},
-	.size = DS2760_DATA_SIZE,
-	.read = w1_ds2760_read_bin,
+static BIN_ATTR_RO(w1_slave, DS2760_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2760_bin_attrs[] = {
+	&bin_attr_w1_slave,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2760_group = {
+	.bin_attrs = w1_ds2760_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2760_groups[] = {
+	&w1_ds2760_group,
+	NULL,
 };
 
 static DEFINE_IDA(bat_ida);
@@ -139,16 +146,10 @@
 	if (ret)
 		goto pdev_add_failed;
 
-	ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
-	if (ret)
-		goto bin_attr_failed;
-
 	dev_set_drvdata(&sl->dev, pdev);
 
 	goto success;
 
-bin_attr_failed:
-	platform_device_del(pdev);
 pdev_add_failed:
 	platform_device_put(pdev);
 pdev_alloc_failed:
@@ -165,12 +166,12 @@
 
 	platform_device_unregister(pdev);
 	ida_simple_remove(&bat_ida, id);
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
 }
 
 static struct w1_family_ops w1_ds2760_fops = {
 	.add_slave    = w1_ds2760_add_slave,
 	.remove_slave = w1_ds2760_remove_slave,
+	.groups       = w1_ds2760_groups,
 };
 
 static struct w1_family w1_ds2760_family = {
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
index 0cd7a27..50e85f7 100644
--- a/drivers/w1/slaves/w1_ds2780.c
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -89,22 +89,28 @@
 }
 EXPORT_SYMBOL(w1_ds2780_eeprom_cmd);
 
-static ssize_t w1_ds2780_read_bin(struct file *filp,
-				  struct kobject *kobj,
-				  struct bin_attribute *bin_attr,
-				  char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read(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_ds2780_io(dev, buf, off, count, 0);
 }
 
-static struct bin_attribute w1_ds2780_bin_attr = {
-	.attr = {
-		.name = "w1_slave",
-		.mode = S_IRUGO,
-	},
-	.size = DS2780_DATA_SIZE,
-	.read = w1_ds2780_read_bin,
+static BIN_ATTR_RO(w1_slave, DS2780_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2780_bin_attrs[] = {
+	&bin_attr_w1_slave,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2780_group = {
+	.bin_attrs = w1_ds2780_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2780_groups[] = {
+	&w1_ds2780_group,
+	NULL,
 };
 
 static DEFINE_IDA(bat_ida);
@@ -132,16 +138,10 @@
 	if (ret)
 		goto pdev_add_failed;
 
-	ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
-	if (ret)
-		goto bin_attr_failed;
-
 	dev_set_drvdata(&sl->dev, pdev);
 
 	return 0;
 
-bin_attr_failed:
-	platform_device_del(pdev);
 pdev_add_failed:
 	platform_device_put(pdev);
 pdev_alloc_failed:
@@ -157,12 +157,12 @@
 
 	platform_device_unregister(pdev);
 	ida_simple_remove(&bat_ida, id);
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
 }
 
 static struct w1_family_ops w1_ds2780_fops = {
 	.add_slave    = w1_ds2780_add_slave,
 	.remove_slave = w1_ds2780_remove_slave,
+	.groups       = w1_ds2780_groups,
 };
 
 static struct w1_family w1_ds2780_family = {
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
index 1aba8e4..1eb98fb 100644
--- a/drivers/w1/slaves/w1_ds2781.c
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -87,22 +87,28 @@
 }
 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)
+static ssize_t w1_slave_read(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 BIN_ATTR_RO(w1_slave, DS2781_DATA_SIZE);
+
+static struct bin_attribute *w1_ds2781_bin_attrs[] = {
+	&bin_attr_w1_slave,
+	NULL,
+};
+
+static const struct attribute_group w1_ds2781_group = {
+	.bin_attrs = w1_ds2781_bin_attrs,
+};
+
+static const struct attribute_group *w1_ds2781_groups[] = {
+	&w1_ds2781_group,
+	NULL,
 };
 
 static DEFINE_IDA(bat_ida);
@@ -130,16 +136,10 @@
 	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:
-	platform_device_del(pdev);
 pdev_add_failed:
 	platform_device_put(pdev);
 pdev_alloc_failed:
@@ -155,12 +155,12 @@
 
 	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,
+	.groups       = w1_ds2781_groups,
 };
 
 static struct w1_family w1_ds2781_family = {
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c
index cd30a6d..365d6df 100644
--- a/drivers/w1/slaves/w1_ds28e04.c
+++ b/drivers/w1/slaves/w1_ds28e04.c
@@ -118,9 +118,9 @@
 	return w1_read_block(sl->master, data, len);
 }
 
-static ssize_t w1_f1C_read_bin(struct file *filp, struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
+			   struct bin_attribute *bin_attr, char *buf,
+			   loff_t off, size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 	struct w1_f1C_data *data = sl->family_data;
@@ -226,9 +226,9 @@
 	return 0;
 }
 
-static ssize_t w1_f1C_write_bin(struct file *filp, struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t off, size_t count)
+static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
+			    struct bin_attribute *bin_attr, char *buf,
+			    loff_t off, size_t count)
 
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -280,9 +280,11 @@
 	return count;
 }
 
-static ssize_t w1_f1C_read_pio(struct file *filp, struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t off, size_t count)
+static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+
+static ssize_t pio_read(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr, char *buf, loff_t off,
+			size_t count)
 
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -299,9 +301,9 @@
 	return ret;
 }
 
-static ssize_t w1_f1C_write_pio(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t off, size_t count)
+static ssize_t pio_write(struct file *filp, struct kobject *kobj,
+			 struct bin_attribute *bin_attr, char *buf, loff_t off,
+			 size_t count)
 
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -339,8 +341,10 @@
 	return count;
 }
 
-static ssize_t w1_f1C_show_crccheck(struct device *dev,
-				    struct device_attribute *attr, char *buf)
+static BIN_ATTR_RW(pio, 1);
+
+static ssize_t crccheck_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
 {
 	if (put_user(w1_enable_crccheck + 0x30, buf))
 		return -EFAULT;
@@ -348,9 +352,8 @@
 	return sizeof(w1_enable_crccheck);
 }
 
-static ssize_t w1_f1C_store_crccheck(struct device *dev,
-				     struct device_attribute *attr,
-				     const char *buf, size_t count)
+static ssize_t crccheck_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
 {
 	char val;
 
@@ -371,35 +374,31 @@
 	return sizeof(w1_enable_crccheck);
 }
 
-#define NB_SYSFS_BIN_FILES 2
-static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = {
-	{
-		.attr = {
-			.name = "eeprom",
-			.mode = S_IRUGO | S_IWUSR,
-		},
-		.size = W1_EEPROM_SIZE,
-		.read = w1_f1C_read_bin,
-		.write = w1_f1C_write_bin,
-	},
-	{
-		.attr = {
-			.name = "pio",
-			.mode = S_IRUGO | S_IWUSR,
-		},
-		.size = 1,
-		.read = w1_f1C_read_pio,
-		.write = w1_f1C_write_pio,
-	}
+static DEVICE_ATTR_RW(crccheck);
+
+static struct attribute *w1_f1C_attrs[] = {
+	&dev_attr_crccheck.attr,
+	NULL,
 };
 
-static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO,
-		   w1_f1C_show_crccheck, w1_f1C_store_crccheck);
+static struct bin_attribute *w1_f1C_bin_attrs[] = {
+	&bin_attr_eeprom,
+	&bin_attr_pio,
+	NULL,
+};
+
+static const struct attribute_group w1_f1C_group = {
+	.attrs		= w1_f1C_attrs,
+	.bin_attrs	= w1_f1C_bin_attrs,
+};
+
+static const struct attribute_group *w1_f1C_groups[] = {
+	&w1_f1C_group,
+	NULL,
+};
 
 static int w1_f1C_add_slave(struct w1_slave *sl)
 {
-	int err = 0;
-	int i;
 	struct w1_f1C_data *data = NULL;
 
 	if (w1_enable_crccheck) {
@@ -409,46 +408,19 @@
 		sl->family_data = data;
 	}
 
-	/* create binary sysfs attributes */
-	for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
-		err = sysfs_create_bin_file(
-			&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
-
-	if (!err) {
-		/* create device attributes */
-		err = device_create_file(&sl->dev, &dev_attr_crccheck);
-	}
-
-	if (err) {
-		/* remove binary sysfs attributes */
-		for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
-			sysfs_remove_bin_file(
-				&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
-
-		kfree(data);
-	}
-
-	return err;
+	return 0;
 }
 
 static void w1_f1C_remove_slave(struct w1_slave *sl)
 {
-	int i;
-
 	kfree(sl->family_data);
 	sl->family_data = NULL;
-
-	/* remove device attributes */
-	device_remove_file(&sl->dev, &dev_attr_crccheck);
-
-	/* remove binary sysfs attributes */
-	for (i = 0; i < NB_SYSFS_BIN_FILES; ++i)
-		sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i]));
 }
 
 static struct w1_family_ops w1_f1C_fops = {
 	.add_slave      = w1_f1C_add_slave,
 	.remove_slave   = w1_f1C_remove_slave,
+	.groups		= w1_f1C_groups,
 };
 
 static struct w1_family w1_family_1C = {
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 8978360..8b5ff33 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -59,25 +59,19 @@
 module_param_named(strong_pullup, w1_strong_pullup, int, 0);
 
 
-static ssize_t w1_therm_read(struct device *device,
+static ssize_t w1_slave_show(struct device *device,
 	struct device_attribute *attr, char *buf);
 
-static struct device_attribute w1_therm_attr =
-	__ATTR(w1_slave, S_IRUGO, w1_therm_read, NULL);
+static DEVICE_ATTR_RO(w1_slave);
 
-static int w1_therm_add_slave(struct w1_slave *sl)
-{
-	return device_create_file(&sl->dev, &w1_therm_attr);
-}
-
-static void w1_therm_remove_slave(struct w1_slave *sl)
-{
-	device_remove_file(&sl->dev, &w1_therm_attr);
-}
+static struct attribute *w1_therm_attrs[] = {
+	&dev_attr_w1_slave.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(w1_therm);
 
 static struct w1_family_ops w1_therm_fops = {
-	.add_slave	= w1_therm_add_slave,
-	.remove_slave	= w1_therm_remove_slave,
+	.groups		= w1_therm_groups,
 };
 
 static struct w1_family w1_therm_family_DS18S20 = {
@@ -178,7 +172,7 @@
 }
 
 
-static ssize_t w1_therm_read(struct device *device,
+static ssize_t w1_slave_show(struct device *device,
 	struct device_attribute *attr, char *buf)
 {
 	struct w1_slave *sl = dev_to_w1_slave(device);
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 0459df8..22013ca 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -96,14 +96,15 @@
 	complete(&sl->released);
 }
 
-static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct w1_slave *sl = dev_to_w1_slave(dev);
 
 	return sprintf(buf, "%s\n", sl->name);
 }
+static DEVICE_ATTR_RO(name);
 
-static ssize_t w1_slave_read_id(struct device *dev,
+static ssize_t id_show(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
 	struct w1_slave *sl = dev_to_w1_slave(dev);
@@ -112,17 +113,20 @@
 	memcpy(buf, (u8 *)&sl->reg_num, count);
 	return count;
 }
+static DEVICE_ATTR_RO(id);
 
-static struct device_attribute w1_slave_attr_name =
-	__ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
-static struct device_attribute w1_slave_attr_id =
-	__ATTR(id, S_IRUGO, w1_slave_read_id, NULL);
+static struct attribute *w1_slave_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_id.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(w1_slave);
 
 /* Default family */
 
-static ssize_t w1_default_write(struct file *filp, struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t off, size_t count)
+static ssize_t rw_write(struct file *filp, struct kobject *kobj,
+			struct bin_attribute *bin_attr, char *buf, loff_t off,
+			size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 
@@ -139,9 +143,9 @@
 	return count;
 }
 
-static ssize_t w1_default_read(struct file *filp, struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t off, size_t count)
+static ssize_t rw_read(struct file *filp, struct kobject *kobj,
+		       struct bin_attribute *bin_attr, char *buf, loff_t off,
+		       size_t count)
 {
 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
 
@@ -151,29 +155,24 @@
 	return count;
 }
 
-static struct bin_attribute w1_default_attr = {
-      .attr = {
-              .name = "rw",
-              .mode = S_IRUGO | S_IWUSR,
-      },
-      .size = PAGE_SIZE,
-      .read = w1_default_read,
-      .write = w1_default_write,
+static BIN_ATTR_RW(rw, PAGE_SIZE);
+
+static struct bin_attribute *w1_slave_bin_attrs[] = {
+	&bin_attr_rw,
+	NULL,
 };
 
-static int w1_default_add_slave(struct w1_slave *sl)
-{
-	return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr);
-}
+static const struct attribute_group w1_slave_default_group = {
+	.bin_attrs = w1_slave_bin_attrs,
+};
 
-static void w1_default_remove_slave(struct w1_slave *sl)
-{
-	sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr);
-}
+static const struct attribute_group *w1_slave_default_groups[] = {
+	&w1_slave_default_group,
+	NULL,
+};
 
 static struct w1_family_ops w1_default_fops = {
-	.add_slave	= w1_default_add_slave,
-	.remove_slave	= w1_default_remove_slave,
+	.groups		= w1_slave_default_groups,
 };
 
 static struct w1_family w1_default_family = {
@@ -587,6 +586,66 @@
 	return err;
 }
 
+/*
+ * Handle sysfs file creation and removal here, before userspace is told that
+ * the device is added / removed from the system
+ */
+static int w1_bus_notify(struct notifier_block *nb, unsigned long action,
+			 void *data)
+{
+	struct device *dev = data;
+	struct w1_slave *sl;
+	struct w1_family_ops *fops;
+	int err;
+
+	/*
+	 * Only care about slave devices at the moment.  Yes, we should use a
+	 * separate "type" for this, but for now, look at the release function
+	 * to know which type it is...
+	 */
+	if (dev->release != w1_slave_release)
+		return 0;
+
+	sl = dev_to_w1_slave(dev);
+	fops = sl->family->fops;
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		/* if the family driver needs to initialize something... */
+		if (fops->add_slave) {
+			err = fops->add_slave(sl);
+			if (err < 0) {
+				dev_err(&sl->dev,
+					"add_slave() call failed. err=%d\n",
+					err);
+				return err;
+			}
+		}
+		if (fops->groups) {
+			err = sysfs_create_groups(&sl->dev.kobj, fops->groups);
+			if (err) {
+				dev_err(&sl->dev,
+					"sysfs group creation failed. err=%d\n",
+					err);
+				return err;
+			}
+		}
+
+		break;
+	case BUS_NOTIFY_DEL_DEVICE:
+		if (fops->remove_slave)
+			sl->family->fops->remove_slave(sl);
+		if (fops->groups)
+			sysfs_remove_groups(&sl->dev.kobj, fops->groups);
+		break;
+	}
+	return 0;
+}
+
+static struct notifier_block w1_bus_nb = {
+	.notifier_call = w1_bus_notify,
+};
+
 static int __w1_attach_slave_device(struct w1_slave *sl)
 {
 	int err;
@@ -595,6 +654,7 @@
 	sl->dev.driver = &w1_slave_driver;
 	sl->dev.bus = &w1_bus_type;
 	sl->dev.release = &w1_slave_release;
+	sl->dev.groups = w1_slave_groups;
 
 	dev_set_name(&sl->dev, "%02x-%012llx",
 		 (unsigned int) sl->reg_num.family,
@@ -615,44 +675,13 @@
 		return err;
 	}
 
-	/* Create "name" entry */
-	err = device_create_file(&sl->dev, &w1_slave_attr_name);
-	if (err < 0) {
-		dev_err(&sl->dev,
-			"sysfs file creation for [%s] failed. err=%d\n",
-			dev_name(&sl->dev), err);
-		goto out_unreg;
-	}
 
-	/* Create "id" entry */
-	err = device_create_file(&sl->dev, &w1_slave_attr_id);
-	if (err < 0) {
-		dev_err(&sl->dev,
-			"sysfs file creation for [%s] failed. err=%d\n",
-			dev_name(&sl->dev), err);
-		goto out_rem1;
-	}
-
-	/* if the family driver needs to initialize something... */
-	if (sl->family->fops && sl->family->fops->add_slave &&
-	    ((err = sl->family->fops->add_slave(sl)) < 0)) {
-		dev_err(&sl->dev,
-			"sysfs file creation for [%s] failed. err=%d\n",
-			dev_name(&sl->dev), err);
-		goto out_rem2;
-	}
+	dev_set_uevent_suppress(&sl->dev, false);
+	kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
 
 	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
 
 	return 0;
-
-out_rem2:
-	device_remove_file(&sl->dev, &w1_slave_attr_id);
-out_rem1:
-	device_remove_file(&sl->dev, &w1_slave_attr_name);
-out_unreg:
-	device_unregister(&sl->dev);
-	return err;
 }
 
 static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
@@ -723,16 +752,11 @@
 
 	list_del(&sl->w1_slave_entry);
 
-	if (sl->family->fops && sl->family->fops->remove_slave)
-		sl->family->fops->remove_slave(sl);
-
 	memset(&msg, 0, sizeof(msg));
 	memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
 	msg.type = W1_SLAVE_REMOVE;
 	w1_netlink_send(sl->master, &msg);
 
-	device_remove_file(&sl->dev, &w1_slave_attr_id);
-	device_remove_file(&sl->dev, &w1_slave_attr_name);
 	device_unregister(&sl->dev);
 
 	wait_for_completion(&sl->released);
@@ -1017,6 +1041,10 @@
 		goto err_out_exit_init;
 	}
 
+	retval = bus_register_notifier(&w1_bus_type, &w1_bus_nb);
+	if (retval)
+		goto err_out_bus_unregister;
+
 	retval = driver_register(&w1_master_driver);
 	if (retval) {
 		printk(KERN_ERR
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 625dd08..4ad0e81 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -52,6 +52,7 @@
 {
 	int  (* add_slave)(struct w1_slave *);
 	void (* remove_slave)(struct w1_slave *);
+	const struct attribute_group **groups;
 };
 
 struct w1_family
diff --git a/drivers/xen/acpi.c b/drivers/xen/acpi.c
index 119d42a..90307c0 100644
--- a/drivers/xen/acpi.c
+++ b/drivers/xen/acpi.c
@@ -35,28 +35,43 @@
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 
-int xen_acpi_notify_hypervisor_state(u8 sleep_state,
-				     u32 pm1a_cnt, u32 pm1b_cnt)
+static int xen_acpi_notify_hypervisor_state(u8 sleep_state,
+					    u32 val_a, u32 val_b,
+					    bool extended)
 {
+	unsigned int bits = extended ? 8 : 16;
+
 	struct xen_platform_op op = {
 		.cmd = XENPF_enter_acpi_sleep,
 		.interface_version = XENPF_INTERFACE_VERSION,
-		.u = {
-			.enter_acpi_sleep = {
-				.pm1a_cnt_val = (u16)pm1a_cnt,
-				.pm1b_cnt_val = (u16)pm1b_cnt,
-				.sleep_state = sleep_state,
-			},
+		.u.enter_acpi_sleep = {
+			.val_a = (u16)val_a,
+			.val_b = (u16)val_b,
+			.sleep_state = sleep_state,
+			.flags = extended ? XENPF_ACPI_SLEEP_EXTENDED : 0,
 		},
 	};
 
-	if ((pm1a_cnt & 0xffff0000) || (pm1b_cnt & 0xffff0000)) {
-		WARN(1, "Using more than 16bits of PM1A/B 0x%x/0x%x!"
-		     "Email xen-devel@lists.xensource.com  Thank you.\n", \
-		     pm1a_cnt, pm1b_cnt);
+	if (WARN((val_a & (~0 << bits)) || (val_b & (~0 << bits)),
+		 "Using more than %u bits of sleep control values %#x/%#x!"
+		 "Email xen-devel@lists.xen.org - Thank you.\n", \
+		 bits, val_a, val_b))
 		return -1;
-	}
 
 	HYPERVISOR_dom0_op(&op);
 	return 1;
 }
+
+int xen_acpi_notify_hypervisor_sleep(u8 sleep_state,
+				     u32 pm1a_cnt, u32 pm1b_cnt)
+{
+	return xen_acpi_notify_hypervisor_state(sleep_state, pm1a_cnt,
+						pm1b_cnt, false);
+}
+
+int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state,
+				     u32 val_a, u32 val_b)
+{
+	return xen_acpi_notify_hypervisor_state(sleep_state, val_a,
+						val_b, true);
+}
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 2a2ef97..3101cf6 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -38,6 +38,7 @@
 
 #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
 
+#include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -52,6 +53,7 @@
 #include <linux/notifier.h>
 #include <linux/memory.h>
 #include <linux/memory_hotplug.h>
+#include <linux/percpu-defs.h>
 
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -90,6 +92,8 @@
 
 /* We increase/decrease in batches which fit in a page */
 static xen_pfn_t frame_list[PAGE_SIZE / sizeof(unsigned long)];
+static DEFINE_PER_CPU(struct page *, balloon_scratch_page);
+
 
 /* List of ballooned pages, threaded through the mem_map array. */
 static LIST_HEAD(ballooned_pages);
@@ -412,7 +416,8 @@
 		if (xen_pv_domain() && !PageHighMem(page)) {
 			ret = HYPERVISOR_update_va_mapping(
 				(unsigned long)__va(pfn << PAGE_SHIFT),
-				__pte_ma(0), 0);
+				pfn_pte(page_to_pfn(__get_cpu_var(balloon_scratch_page)),
+					PAGE_KERNEL_RO), 0);
 			BUG_ON(ret);
 		}
 #endif
@@ -425,7 +430,13 @@
 	/* No more mappings: invalidate P2M and add to balloon. */
 	for (i = 0; i < nr_pages; i++) {
 		pfn = mfn_to_pfn(frame_list[i]);
-		__set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
+		if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+			unsigned long p;
+			struct page *pg;
+			pg = __get_cpu_var(balloon_scratch_page);
+			p = page_to_pfn(pg);
+			__set_phys_to_machine(pfn, pfn_to_mfn(p));
+		}
 		balloon_append(pfn_to_page(pfn));
 	}
 
@@ -480,6 +491,18 @@
 	mutex_unlock(&balloon_mutex);
 }
 
+struct page *get_balloon_scratch_page(void)
+{
+	struct page *ret = get_cpu_var(balloon_scratch_page);
+	BUG_ON(ret == NULL);
+	return ret;
+}
+
+void put_balloon_scratch_page(void)
+{
+	put_cpu_var(balloon_scratch_page);
+}
+
 /* Resets the Xen limit, sets new target, and kicks off processing. */
 void balloon_set_new_target(unsigned long target)
 {
@@ -573,13 +596,47 @@
 	}
 }
 
+static int __cpuinit balloon_cpu_notify(struct notifier_block *self,
+				    unsigned long action, void *hcpu)
+{
+	int cpu = (long)hcpu;
+	switch (action) {
+	case CPU_UP_PREPARE:
+		if (per_cpu(balloon_scratch_page, cpu) != NULL)
+			break;
+		per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
+		if (per_cpu(balloon_scratch_page, cpu) == NULL) {
+			pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
+			return NOTIFY_BAD;
+		}
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block balloon_cpu_notifier __cpuinitdata = {
+	.notifier_call	= balloon_cpu_notify,
+};
+
 static int __init balloon_init(void)
 {
-	int i;
+	int i, cpu;
 
 	if (!xen_domain())
 		return -ENODEV;
 
+	for_each_online_cpu(cpu)
+	{
+		per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
+		if (per_cpu(balloon_scratch_page, cpu) == NULL) {
+			pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
+			return -ENOMEM;
+		}
+	}
+	register_cpu_notifier(&balloon_cpu_notifier);
+
 	pr_info("Initialising balloon driver\n");
 
 	balloon_stats.current_pages = xen_pv_domain()
@@ -616,4 +673,15 @@
 
 subsys_initcall(balloon_init);
 
+static int __init balloon_clear(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		per_cpu(balloon_scratch_page, cpu) = NULL;
+
+	return 0;
+}
+early_initcall(balloon_clear);
+
 MODULE_LICENSE("GPL");
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index a58ac43..4035e83 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -56,6 +56,7 @@
 #include <xen/interface/hvm/params.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/sched.h>
+#include <xen/interface/vcpu.h>
 #include <asm/hw_irq.h>
 
 /*
@@ -348,7 +349,7 @@
 
 	for_each_possible_cpu(i)
 		memset(per_cpu(cpu_evtchn_mask, i),
-		       (i == 0) ? ~0 : 0, sizeof(*per_cpu(cpu_evtchn_mask, i)));
+		       (i == 0) ? ~0 : 0, NR_EVENT_CHANNELS/8);
 }
 
 static inline void clear_evtchn(int port)
@@ -1212,7 +1213,17 @@
 
 void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
 {
-	int irq = per_cpu(ipi_to_irq, cpu)[vector];
+	int irq;
+
+#ifdef CONFIG_X86
+	if (unlikely(vector == XEN_NMI_VECTOR)) {
+		int rc =  HYPERVISOR_vcpu_op(VCPUOP_send_nmi, cpu, NULL);
+		if (rc < 0)
+			printk(KERN_WARNING "Sending nmi to CPU%d failed (rc:%d)\n", cpu, rc);
+		return;
+	}
+#endif
+	irq = per_cpu(ipi_to_irq, cpu)[vector];
 	BUG_ON(irq < 0);
 	notify_remote_via_irq(irq);
 }
@@ -1379,14 +1390,21 @@
 
 			pending_bits = active_evtchns(cpu, s, word_idx);
 			bit_idx = 0; /* usually scan entire word from start */
+			/*
+			 * We scan the starting word in two parts.
+			 *
+			 * 1st time: start in the middle, scanning the
+			 * upper bits.
+			 *
+			 * 2nd time: scan the whole word (not just the
+			 * parts skipped in the first pass) -- if an
+			 * event in the previously scanned bits is
+			 * pending again it would just be scanned on
+			 * the next loop anyway.
+			 */
 			if (word_idx == start_word_idx) {
-				/* We scan the starting word in two parts */
 				if (i == 0)
-					/* 1st time: start in the middle */
 					bit_idx = start_bit_idx;
-				else
-					/* 2nd time: mask bits done already */
-					bit_idx &= (1UL << start_bit_idx) - 1;
 			}
 
 			do {
@@ -1493,8 +1511,10 @@
 /* Rebind an evtchn so that it gets delivered to a specific cpu */
 static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
 {
+	struct shared_info *s = HYPERVISOR_shared_info;
 	struct evtchn_bind_vcpu bind_vcpu;
 	int evtchn = evtchn_from_irq(irq);
+	int masked;
 
 	if (!VALID_EVTCHN(evtchn))
 		return -1;
@@ -1511,6 +1531,12 @@
 	bind_vcpu.vcpu = tcpu;
 
 	/*
+	 * Mask the event while changing the VCPU binding to prevent
+	 * it being delivered on an unexpected VCPU.
+	 */
+	masked = sync_test_and_set_bit(evtchn, BM(s->evtchn_mask));
+
+	/*
 	 * If this fails, it usually just indicates that we're dealing with a
 	 * virq or IPI channel, which don't actually need to be rebound. Ignore
 	 * it, but don't do the xenlinux-level rebind in that case.
@@ -1518,6 +1544,9 @@
 	if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
 		bind_evtchn_to_cpu(evtchn, tcpu);
 
+	if (!masked)
+		unmask_evtchn(evtchn);
+
 	return 0;
 }
 
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index b6165e0..8b3a69a 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -57,6 +57,7 @@
 
 struct per_user_data {
 	struct mutex bind_mutex; /* serialize bind/unbind operations */
+	struct rb_root evtchns;
 
 	/* Notification ring, accessed via /dev/xen/evtchn. */
 #define EVTCHN_RING_SIZE     (PAGE_SIZE / sizeof(evtchn_port_t))
@@ -64,6 +65,7 @@
 	evtchn_port_t *ring;
 	unsigned int ring_cons, ring_prod, ring_overflow;
 	struct mutex ring_cons_mutex; /* protect against concurrent readers */
+	spinlock_t ring_prod_lock; /* product against concurrent interrupts */
 
 	/* Processes wait on this queue when ring is empty. */
 	wait_queue_head_t evtchn_wait;
@@ -71,54 +73,79 @@
 	const char *name;
 };
 
-/*
- * Who's bound to each port?  This is logically an array of struct
- * per_user_data *, but we encode the current enabled-state in bit 0.
- */
-static unsigned long *port_user;
-static DEFINE_SPINLOCK(port_user_lock); /* protects port_user[] and ring_prod */
+struct user_evtchn {
+	struct rb_node node;
+	struct per_user_data *user;
+	unsigned port;
+	bool enabled;
+};
 
-static inline struct per_user_data *get_port_user(unsigned port)
+static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
 {
-	return (struct per_user_data *)(port_user[port] & ~1);
+	struct rb_node **new = &(u->evtchns.rb_node), *parent = NULL;
+
+	while (*new) {
+		struct user_evtchn *this;
+
+		this = container_of(*new, struct user_evtchn, node);
+
+		parent = *new;
+		if (this->port < evtchn->port)
+			new = &((*new)->rb_left);
+		else if (this->port > evtchn->port)
+			new = &((*new)->rb_right);
+		else
+			return -EEXIST;
+	}
+
+	/* Add new node and rebalance tree. */
+	rb_link_node(&evtchn->node, parent, new);
+	rb_insert_color(&evtchn->node, &u->evtchns);
+
+	return 0;
 }
 
-static inline void set_port_user(unsigned port, struct per_user_data *u)
+static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
 {
-	port_user[port] = (unsigned long)u;
+	rb_erase(&evtchn->node, &u->evtchns);
+	kfree(evtchn);
 }
 
-static inline bool get_port_enabled(unsigned port)
+static struct user_evtchn *find_evtchn(struct per_user_data *u, unsigned port)
 {
-	return port_user[port] & 1;
-}
+	struct rb_node *node = u->evtchns.rb_node;
 
-static inline void set_port_enabled(unsigned port, bool enabled)
-{
-	if (enabled)
-		port_user[port] |= 1;
-	else
-		port_user[port] &= ~1;
+	while (node) {
+		struct user_evtchn *evtchn;
+
+		evtchn = container_of(node, struct user_evtchn, node);
+
+		if (evtchn->port < port)
+			node = node->rb_left;
+		else if (evtchn->port > port)
+			node = node->rb_right;
+		else
+			return evtchn;
+	}
+	return NULL;
 }
 
 static irqreturn_t evtchn_interrupt(int irq, void *data)
 {
-	unsigned int port = (unsigned long)data;
-	struct per_user_data *u;
+	struct user_evtchn *evtchn = data;
+	struct per_user_data *u = evtchn->user;
 
-	spin_lock(&port_user_lock);
-
-	u = get_port_user(port);
-
-	WARN(!get_port_enabled(port),
+	WARN(!evtchn->enabled,
 	     "Interrupt for port %d, but apparently not enabled; per-user %p\n",
-	     port, u);
+	     evtchn->port, u);
 
 	disable_irq_nosync(irq);
-	set_port_enabled(port, false);
+	evtchn->enabled = false;
+
+	spin_lock(&u->ring_prod_lock);
 
 	if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
-		u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
+		u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port;
 		wmb(); /* Ensure ring contents visible */
 		if (u->ring_cons == u->ring_prod++) {
 			wake_up_interruptible(&u->evtchn_wait);
@@ -128,7 +155,7 @@
 	} else
 		u->ring_overflow = 1;
 
-	spin_unlock(&port_user_lock);
+	spin_unlock(&u->ring_prod_lock);
 
 	return IRQ_HANDLED;
 }
@@ -229,20 +256,20 @@
 	if (copy_from_user(kbuf, buf, count) != 0)
 		goto out;
 
-	spin_lock_irq(&port_user_lock);
+	mutex_lock(&u->bind_mutex);
 
 	for (i = 0; i < (count/sizeof(evtchn_port_t)); i++) {
 		unsigned port = kbuf[i];
+		struct user_evtchn *evtchn;
 
-		if (port < NR_EVENT_CHANNELS &&
-		    get_port_user(port) == u &&
-		    !get_port_enabled(port)) {
-			set_port_enabled(port, true);
+		evtchn = find_evtchn(u, port);
+		if (evtchn && !evtchn->enabled) {
+			evtchn->enabled = true;
 			enable_irq(irq_from_evtchn(port));
 		}
 	}
 
-	spin_unlock_irq(&port_user_lock);
+	mutex_unlock(&u->bind_mutex);
 
 	rc = count;
 
@@ -253,6 +280,8 @@
 
 static int evtchn_bind_to_user(struct per_user_data *u, int port)
 {
+	struct user_evtchn *evtchn;
+	struct evtchn_close close;
 	int rc = 0;
 
 	/*
@@ -263,35 +292,46 @@
 	 * interrupt handler yet, and our caller has already
 	 * serialized bind operations.)
 	 */
-	BUG_ON(get_port_user(port) != NULL);
-	set_port_user(port, u);
-	set_port_enabled(port, true); /* start enabled */
+
+	evtchn = kzalloc(sizeof(*evtchn), GFP_KERNEL);
+	if (!evtchn)
+		return -ENOMEM;
+
+	evtchn->user = u;
+	evtchn->port = port;
+	evtchn->enabled = true; /* start enabled */
+
+	rc = add_evtchn(u, evtchn);
+	if (rc < 0)
+		goto err;
 
 	rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
-				       u->name, (void *)(unsigned long)port);
-	if (rc >= 0)
-		rc = evtchn_make_refcounted(port);
-	else {
-		/* bind failed, should close the port now */
-		struct evtchn_close close;
-		close.port = port;
-		if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
-			BUG();
-		set_port_user(port, NULL);
-	}
+				       u->name, evtchn);
+	if (rc < 0)
+		goto err;
 
+	rc = evtchn_make_refcounted(port);
+	return rc;
+
+err:
+	/* bind failed, should close the port now */
+	close.port = port;
+	if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
+		BUG();
+	del_evtchn(u, evtchn);
 	return rc;
 }
 
-static void evtchn_unbind_from_user(struct per_user_data *u, int port)
+static void evtchn_unbind_from_user(struct per_user_data *u,
+				    struct user_evtchn *evtchn)
 {
-	int irq = irq_from_evtchn(port);
+	int irq = irq_from_evtchn(evtchn->port);
 
 	BUG_ON(irq < 0);
 
-	unbind_from_irqhandler(irq, (void *)(unsigned long)port);
+	unbind_from_irqhandler(irq, evtchn);
 
-	set_port_user(port, NULL);
+	del_evtchn(u, evtchn);
 }
 
 static long evtchn_ioctl(struct file *file,
@@ -370,6 +410,7 @@
 
 	case IOCTL_EVTCHN_UNBIND: {
 		struct ioctl_evtchn_unbind unbind;
+		struct user_evtchn *evtchn;
 
 		rc = -EFAULT;
 		if (copy_from_user(&unbind, uarg, sizeof(unbind)))
@@ -380,29 +421,27 @@
 			break;
 
 		rc = -ENOTCONN;
-		if (get_port_user(unbind.port) != u)
+		evtchn = find_evtchn(u, unbind.port);
+		if (!evtchn)
 			break;
 
 		disable_irq(irq_from_evtchn(unbind.port));
-
-		evtchn_unbind_from_user(u, unbind.port);
-
+		evtchn_unbind_from_user(u, evtchn);
 		rc = 0;
 		break;
 	}
 
 	case IOCTL_EVTCHN_NOTIFY: {
 		struct ioctl_evtchn_notify notify;
+		struct user_evtchn *evtchn;
 
 		rc = -EFAULT;
 		if (copy_from_user(&notify, uarg, sizeof(notify)))
 			break;
 
-		if (notify.port >= NR_EVENT_CHANNELS) {
-			rc = -EINVAL;
-		} else if (get_port_user(notify.port) != u) {
-			rc = -ENOTCONN;
-		} else {
+		rc = -ENOTCONN;
+		evtchn = find_evtchn(u, notify.port);
+		if (evtchn) {
 			notify_remote_via_evtchn(notify.port);
 			rc = 0;
 		}
@@ -412,9 +451,9 @@
 	case IOCTL_EVTCHN_RESET: {
 		/* Initialise the ring to empty. Clear errors. */
 		mutex_lock(&u->ring_cons_mutex);
-		spin_lock_irq(&port_user_lock);
+		spin_lock_irq(&u->ring_prod_lock);
 		u->ring_cons = u->ring_prod = u->ring_overflow = 0;
-		spin_unlock_irq(&port_user_lock);
+		spin_unlock_irq(&u->ring_prod_lock);
 		mutex_unlock(&u->ring_cons_mutex);
 		rc = 0;
 		break;
@@ -473,6 +512,7 @@
 
 	mutex_init(&u->bind_mutex);
 	mutex_init(&u->ring_cons_mutex);
+	spin_lock_init(&u->ring_prod_lock);
 
 	filp->private_data = u;
 
@@ -481,15 +521,15 @@
 
 static int evtchn_release(struct inode *inode, struct file *filp)
 {
-	int i;
 	struct per_user_data *u = filp->private_data;
+	struct rb_node *node;
 
-	for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-		if (get_port_user(i) != u)
-			continue;
+	while ((node = u->evtchns.rb_node)) {
+		struct user_evtchn *evtchn;
 
-		disable_irq(irq_from_evtchn(i));
-		evtchn_unbind_from_user(get_port_user(i), i);
+		evtchn = rb_entry(node, struct user_evtchn, node);
+		disable_irq(irq_from_evtchn(evtchn->port));
+		evtchn_unbind_from_user(u, evtchn);
 	}
 
 	free_page((unsigned long)u->ring);
@@ -523,12 +563,6 @@
 	if (!xen_domain())
 		return -ENODEV;
 
-	port_user = kcalloc(NR_EVENT_CHANNELS, sizeof(*port_user), GFP_KERNEL);
-	if (port_user == NULL)
-		return -ENOMEM;
-
-	spin_lock_init(&port_user_lock);
-
 	/* Create '/dev/xen/evtchn'. */
 	err = misc_register(&evtchn_miscdev);
 	if (err != 0) {
@@ -543,9 +577,6 @@
 
 static void __exit evtchn_cleanup(void)
 {
-	kfree(port_user);
-	port_user = NULL;
-
 	misc_deregister(&evtchn_miscdev);
 }
 
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index eab5427..e41c79c 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -272,19 +272,12 @@
 		 * with find_grant_ptes.
 		 */
 		for (i = 0; i < map->count; i++) {
-			unsigned level;
 			unsigned long address = (unsigned long)
 				pfn_to_kaddr(page_to_pfn(map->pages[i]));
-			pte_t *ptep;
-			u64 pte_maddr = 0;
 			BUG_ON(PageHighMem(map->pages[i]));
 
-			ptep = lookup_address(address, &level);
-			pte_maddr = arbitrary_virt_to_machine(ptep).maddr;
-			gnttab_set_map_op(&map->kmap_ops[i], pte_maddr,
-				map->flags |
-				GNTMAP_host_map |
-				GNTMAP_contains_pte,
+			gnttab_set_map_op(&map->kmap_ops[i], address,
+				map->flags | GNTMAP_host_map,
 				map->grants[i].ref,
 				map->grants[i].domid);
 		}
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 04cdeb8..c4d2298 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -730,9 +730,18 @@
 				  void (*fn)(void *), void *arg, u16 count)
 {
 	unsigned long flags;
+	struct gnttab_free_callback *cb;
+
 	spin_lock_irqsave(&gnttab_list_lock, flags);
-	if (callback->next)
-		goto out;
+
+	/* Check if the callback is already on the list */
+	cb = gnttab_free_callback_list;
+	while (cb) {
+		if (cb == callback)
+			goto out;
+		cb = cb->next;
+	}
+
 	callback->fn = fn;
 	callback->arg = arg;
 	callback->count = count;
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index f8e5dd70..8e74590 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -43,9 +43,10 @@
 
 #define PRIV_VMA_LOCKED ((void *)1)
 
-#ifndef HAVE_ARCH_PRIVCMD_MMAP
-static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
-#endif
+static int privcmd_vma_range_is_mapped(
+               struct vm_area_struct *vma,
+               unsigned long addr,
+               unsigned long nr_pages);
 
 static long privcmd_ioctl_hypercall(void __user *udata)
 {
@@ -225,9 +226,9 @@
 		vma = find_vma(mm, msg->va);
 		rc = -EINVAL;
 
-		if (!vma || (msg->va != vma->vm_start) ||
-		    !privcmd_enforce_singleshot_mapping(vma))
+		if (!vma || (msg->va != vma->vm_start) || vma->vm_private_data)
 			goto out_up;
+		vma->vm_private_data = PRIV_VMA_LOCKED;
 	}
 
 	state.va = vma->vm_start;
@@ -358,7 +359,7 @@
 		kfree(pages);
 		return -ENOMEM;
 	}
-	BUG_ON(vma->vm_private_data != PRIV_VMA_LOCKED);
+	BUG_ON(vma->vm_private_data != NULL);
 	vma->vm_private_data = pages;
 
 	return 0;
@@ -421,19 +422,43 @@
 
 	vma = find_vma(mm, m.addr);
 	if (!vma ||
-	    vma->vm_ops != &privcmd_vm_ops ||
-	    (m.addr != vma->vm_start) ||
-	    ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
-	    !privcmd_enforce_singleshot_mapping(vma)) {
-		up_write(&mm->mmap_sem);
+	    vma->vm_ops != &privcmd_vm_ops) {
 		ret = -EINVAL;
-		goto out;
+		goto out_unlock;
 	}
-	if (xen_feature(XENFEAT_auto_translated_physmap)) {
-		ret = alloc_empty_pages(vma, m.num);
-		if (ret < 0) {
-			up_write(&mm->mmap_sem);
-			goto out;
+
+	/*
+	 * Caller must either:
+	 *
+	 * Map the whole VMA range, which will also allocate all the
+	 * pages required for the auto_translated_physmap case.
+	 *
+	 * Or
+	 *
+	 * Map unmapped holes left from a previous map attempt (e.g.,
+	 * because those foreign frames were previously paged out).
+	 */
+	if (vma->vm_private_data == NULL) {
+		if (m.addr != vma->vm_start ||
+		    m.addr + (nr_pages << PAGE_SHIFT) != vma->vm_end) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		if (xen_feature(XENFEAT_auto_translated_physmap)) {
+			ret = alloc_empty_pages(vma, m.num);
+			if (ret < 0)
+				goto out_unlock;
+		} else
+			vma->vm_private_data = PRIV_VMA_LOCKED;
+	} else {
+		if (m.addr < vma->vm_start ||
+		    m.addr + (nr_pages << PAGE_SHIFT) > vma->vm_end) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+		if (privcmd_vma_range_is_mapped(vma, m.addr, nr_pages)) {
+			ret = -EINVAL;
+			goto out_unlock;
 		}
 	}
 
@@ -466,8 +491,11 @@
 
 out:
 	free_page_list(&pagelist);
-
 	return ret;
+
+out_unlock:
+	up_write(&mm->mmap_sem);
+	goto out;
 }
 
 static long privcmd_ioctl(struct file *file,
@@ -540,9 +568,24 @@
 	return 0;
 }
 
-static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
+/*
+ * For MMAPBATCH*. This allows asserting the singleshot mapping
+ * on a per pfn/pte basis. Mapping calls that fail with ENOENT
+ * can be then retried until success.
+ */
+static int is_mapped_fn(pte_t *pte, struct page *pmd_page,
+	                unsigned long addr, void *data)
 {
-	return !cmpxchg(&vma->vm_private_data, NULL, PRIV_VMA_LOCKED);
+	return pte_none(*pte) ? 0 : -EBUSY;
+}
+
+static int privcmd_vma_range_is_mapped(
+	           struct vm_area_struct *vma,
+	           unsigned long addr,
+	           unsigned long nr_pages)
+{
+	return apply_to_page_range(vma->vm_mm, addr, nr_pages << PAGE_SHIFT,
+				   is_mapped_fn, NULL) != 0;
 }
 
 const struct file_operations xen_privcmd_fops = {
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index aadffcf..1b2277c 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -506,13 +506,13 @@
 				   to do proper error handling. */
 				xen_swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,
 							   attrs);
-				sgl[0].dma_length = 0;
+				sg_dma_len(sgl) = 0;
 				return DMA_ERROR_CODE;
 			}
 			sg->dma_address = xen_phys_to_bus(map);
 		} else
 			sg->dma_address = dev_addr;
-		sg->dma_length = sg->length;
+		sg_dma_len(sg) = sg->length;
 	}
 	return nelems;
 }
@@ -533,7 +533,7 @@
 	BUG_ON(dir == DMA_NONE);
 
 	for_each_sg(sgl, sg, nelems, i)
-		xen_unmap_single(hwdev, sg->dma_address, sg->dma_length, dir);
+		xen_unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir);
 
 }
 EXPORT_SYMBOL_GPL(xen_swiotlb_unmap_sg_attrs);
@@ -555,7 +555,7 @@
 
 	for_each_sg(sgl, sg, nelems, i)
 		xen_swiotlb_sync_single(hwdev, sg->dma_address,
-					sg->dma_length, dir, target);
+					sg_dma_len(sg), dir, target);
 }
 
 void
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
index 02817a8..21e18c1 100644
--- a/drivers/xen/xen-selfballoon.c
+++ b/drivers/xen/xen-selfballoon.c
@@ -265,8 +265,10 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	err = strict_strtoul(buf, 10, &tmp);
-	if (err || ((tmp != 0) && (tmp != 1)))
+	err = kstrtoul(buf, 10, &tmp);
+	if (err)
+		return err;
+	if ((tmp != 0) && (tmp != 1))
 		return -EINVAL;
 
 	xen_selfballooning_enabled = !!tmp;
@@ -292,8 +294,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	selfballoon_interval = val;
 	return count;
@@ -314,8 +318,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	selfballoon_downhysteresis = val;
 	return count;
@@ -337,8 +343,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	selfballoon_uphysteresis = val;
 	return count;
@@ -360,8 +368,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	selfballoon_min_usable_mb = val;
 	return count;
@@ -384,8 +394,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	selfballoon_reserved_mb = val;
 	return count;
@@ -410,8 +422,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &tmp);
-	if (err || ((tmp != 0) && (tmp != 1)))
+	err = kstrtoul(buf, 10, &tmp);
+	if (err)
+		return err;
+	if ((tmp != 0) && (tmp != 1))
 		return -EINVAL;
 	frontswap_selfshrinking = !!tmp;
 	if (!was_enabled && !xen_selfballooning_enabled &&
@@ -437,8 +451,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	frontswap_inertia = val;
 	frontswap_inertia_counter = val;
@@ -460,8 +476,10 @@
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	err = strict_strtoul(buf, 10, &val);
-	if (err || val == 0)
+	err = kstrtoul(buf, 10, &val);
+	if (err)
+		return err;
+	if (val == 0)
 		return -EINVAL;
 	frontswap_hysteresis = val;
 	return count;
diff --git a/fs/bio.c b/fs/bio.c
index 94bbc04..b3b20ed 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1045,12 +1045,22 @@
 int bio_uncopy_user(struct bio *bio)
 {
 	struct bio_map_data *bmd = bio->bi_private;
-	int ret = 0;
+	struct bio_vec *bvec;
+	int ret = 0, i;
 
-	if (!bio_flagged(bio, BIO_NULL_MAPPED))
-		ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
-				     bmd->nr_sgvecs, bio_data_dir(bio) == READ,
-				     0, bmd->is_our_pages);
+	if (!bio_flagged(bio, BIO_NULL_MAPPED)) {
+		/*
+		 * if we're in a workqueue, the request is orphaned, so
+		 * don't copy into a random user address space, just free.
+		 */
+		if (current->mm)
+			ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
+					     bmd->nr_sgvecs, bio_data_dir(bio) == READ,
+					     0, bmd->is_our_pages);
+		else if (bmd->is_our_pages)
+			bio_for_each_segment_all(bvec, bio, i)
+				__free_page(bvec->bv_page);
+	}
 	bio_free_map_data(bmd);
 	bio_put(bio);
 	return ret;
@@ -1946,7 +1956,7 @@
 
 	/* associate blkcg if exists */
 	rcu_read_lock();
-	css = task_subsys_state(current, blkio_subsys_id);
+	css = task_css(current, blkio_subsys_id);
 	if (css && css_tryget(css))
 		bio->bi_css = css;
 	rcu_read_unlock();
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 4253ad5..5f8f334 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -747,7 +747,7 @@
 	WARN_ON(atomic_xchg(
 		&fs_info->mutually_exclusive_operation_running, 1));
 	task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl");
-	return PTR_RET(task);
+	return PTR_ERR_OR_ZERO(task);
 }
 
 static int btrfs_dev_replace_kthread(void *data)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 021694c..7bdc83d 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3174,7 +3174,7 @@
 		found_key.type = BTRFS_INODE_ITEM_KEY;
 		found_key.offset = 0;
 		inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
-		ret = PTR_RET(inode);
+		ret = PTR_ERR_OR_ZERO(inode);
 		if (ret && ret != -ESTALE)
 			goto out;
 
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 78b8717..67a0853 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3302,7 +3302,7 @@
 	}
 
 	tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance");
-	return PTR_RET(tsk);
+	return PTR_ERR_OR_ZERO(tsk);
 }
 
 int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
diff --git a/fs/dcache.c b/fs/dcache.c
index 2e5f9ca..5aa53bc 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -229,7 +229,7 @@
  */
 static void d_free(struct dentry *dentry)
 {
-	BUG_ON(dentry->d_count);
+	BUG_ON(dentry->d_lockref.count);
 	this_cpu_dec(nr_dentry);
 	if (dentry->d_op && dentry->d_op->d_release)
 		dentry->d_op->d_release(dentry);
@@ -467,7 +467,7 @@
 	}
 
 	if (ref)
-		dentry->d_count--;
+		dentry->d_lockref.count--;
 	/*
 	 * inform the fs via d_prune that this dentry is about to be
 	 * unhashed and destroyed.
@@ -513,15 +513,10 @@
 		return;
 
 repeat:
-	if (dentry->d_count == 1)
+	if (dentry->d_lockref.count == 1)
 		might_sleep();
-	spin_lock(&dentry->d_lock);
-	BUG_ON(!dentry->d_count);
-	if (dentry->d_count > 1) {
-		dentry->d_count--;
-		spin_unlock(&dentry->d_lock);
+	if (lockref_put_or_lock(&dentry->d_lockref))
 		return;
-	}
 
 	if (dentry->d_flags & DCACHE_OP_DELETE) {
 		if (dentry->d_op->d_delete(dentry))
@@ -535,7 +530,7 @@
 	dentry->d_flags |= DCACHE_REFERENCED;
 	dentry_lru_add(dentry);
 
-	dentry->d_count--;
+	dentry->d_lockref.count--;
 	spin_unlock(&dentry->d_lock);
 	return;
 
@@ -590,7 +585,7 @@
 	 * We also need to leave mountpoints alone,
 	 * directory or not.
 	 */
-	if (dentry->d_count > 1 && dentry->d_inode) {
+	if (dentry->d_lockref.count > 1 && dentry->d_inode) {
 		if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
 			spin_unlock(&dentry->d_lock);
 			return -EBUSY;
@@ -606,20 +601,33 @@
 /* This must be called with d_lock held */
 static inline void __dget_dlock(struct dentry *dentry)
 {
-	dentry->d_count++;
+	dentry->d_lockref.count++;
 }
 
 static inline void __dget(struct dentry *dentry)
 {
-	spin_lock(&dentry->d_lock);
-	__dget_dlock(dentry);
-	spin_unlock(&dentry->d_lock);
+	lockref_get(&dentry->d_lockref);
 }
 
 struct dentry *dget_parent(struct dentry *dentry)
 {
+	int gotref;
 	struct dentry *ret;
 
+	/*
+	 * Do optimistic parent lookup without any
+	 * locking.
+	 */
+	rcu_read_lock();
+	ret = ACCESS_ONCE(dentry->d_parent);
+	gotref = lockref_get_not_zero(&ret->d_lockref);
+	rcu_read_unlock();
+	if (likely(gotref)) {
+		if (likely(ret == ACCESS_ONCE(dentry->d_parent)))
+			return ret;
+		dput(ret);
+	}
+
 repeat:
 	/*
 	 * Don't need rcu_dereference because we re-check it was correct under
@@ -634,8 +642,8 @@
 		goto repeat;
 	}
 	rcu_read_unlock();
-	BUG_ON(!ret->d_count);
-	ret->d_count++;
+	BUG_ON(!ret->d_lockref.count);
+	ret->d_lockref.count++;
 	spin_unlock(&ret->d_lock);
 	return ret;
 }
@@ -718,7 +726,7 @@
 	spin_lock(&inode->i_lock);
 	hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
 		spin_lock(&dentry->d_lock);
-		if (!dentry->d_count) {
+		if (!dentry->d_lockref.count) {
 			/*
 			 * inform the fs via d_prune that this dentry
 			 * is about to be unhashed and destroyed.
@@ -771,12 +779,8 @@
 	/* Prune ancestors. */
 	dentry = parent;
 	while (dentry) {
-		spin_lock(&dentry->d_lock);
-		if (dentry->d_count > 1) {
-			dentry->d_count--;
-			spin_unlock(&dentry->d_lock);
+		if (lockref_put_or_lock(&dentry->d_lockref))
 			return;
-		}
 		dentry = dentry_kill(dentry, 1);
 	}
 }
@@ -801,7 +805,7 @@
 		 * the LRU because of laziness during lookup.  Do not free
 		 * it - just keep it off the LRU list.
 		 */
-		if (dentry->d_count) {
+		if (dentry->d_lockref.count) {
 			dentry_lru_del(dentry);
 			spin_unlock(&dentry->d_lock);
 			continue;
@@ -922,7 +926,7 @@
 			dentry_lru_del(dentry);
 			__d_shrink(dentry);
 
-			if (dentry->d_count != 0) {
+			if (dentry->d_lockref.count != 0) {
 				printk(KERN_ERR
 				       "BUG: Dentry %p{i=%lx,n=%s}"
 				       " still in use (%d)"
@@ -931,7 +935,7 @@
 				       dentry->d_inode ?
 				       dentry->d_inode->i_ino : 0UL,
 				       dentry->d_name.name,
-				       dentry->d_count,
+				       dentry->d_lockref.count,
 				       dentry->d_sb->s_type->name,
 				       dentry->d_sb->s_id);
 				BUG();
@@ -942,7 +946,7 @@
 				list_del(&dentry->d_u.d_child);
 			} else {
 				parent = dentry->d_parent;
-				parent->d_count--;
+				parent->d_lockref.count--;
 				list_del(&dentry->d_u.d_child);
 			}
 
@@ -990,7 +994,7 @@
 
 	dentry = sb->s_root;
 	sb->s_root = NULL;
-	dentry->d_count--;
+	dentry->d_lockref.count--;
 	shrink_dcache_for_umount_subtree(dentry);
 
 	while (!hlist_bl_empty(&sb->s_anon)) {
@@ -1156,7 +1160,7 @@
 		 * loop in shrink_dcache_parent() might not make any progress
 		 * and loop forever.
 		 */
-		if (dentry->d_count) {
+		if (dentry->d_lockref.count) {
 			dentry_lru_del(dentry);
 		} else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
 			dentry_lru_move_list(dentry, dispose);
@@ -1278,7 +1282,7 @@
 	smp_wmb();
 	dentry->d_name.name = dname;
 
-	dentry->d_count = 1;
+	dentry->d_lockref.count = 1;
 	dentry->d_flags = 0;
 	spin_lock_init(&dentry->d_lock);
 	seqcount_init(&dentry->d_seq);
@@ -1791,7 +1795,7 @@
  * without taking d_lock and checking d_seq sequence count against @seq
  * returned here.
  *
- * A refcount may be taken on the found dentry with the __d_rcu_to_refcount
+ * A refcount may be taken on the found dentry with the d_rcu_to_refcount
  * function.
  *
  * Alternatively, __d_lookup_rcu may be called again to look up the child of
@@ -1979,7 +1983,7 @@
 				goto next;
 		}
 
-		dentry->d_count++;
+		dentry->d_lockref.count++;
 		found = dentry;
 		spin_unlock(&dentry->d_lock);
 		break;
@@ -2078,7 +2082,7 @@
 	spin_lock(&dentry->d_lock);
 	inode = dentry->d_inode;
 	isdir = S_ISDIR(inode->i_mode);
-	if (dentry->d_count == 1) {
+	if (dentry->d_lockref.count == 1) {
 		if (!spin_trylock(&inode->i_lock)) {
 			spin_unlock(&dentry->d_lock);
 			cpu_relax();
@@ -2957,7 +2961,7 @@
 		}
 		if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
 			dentry->d_flags |= DCACHE_GENOCIDE;
-			dentry->d_count--;
+			dentry->d_lockref.count--;
 		}
 		spin_unlock(&dentry->d_lock);
 	}
@@ -2965,7 +2969,7 @@
 		struct dentry *child = this_parent;
 		if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
 			this_parent->d_flags |= DCACHE_GENOCIDE;
-			this_parent->d_count--;
+			this_parent->d_lockref.count--;
 		}
 		this_parent = try_to_ascend(this_parent, locked, seq);
 		if (!this_parent)
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index 27a6ba9..0e90f0c 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -267,10 +267,7 @@
 int dlm_callback_start(struct dlm_ls *ls)
 {
 	ls->ls_callback_wq = alloc_workqueue("dlm_callback",
-					     WQ_UNBOUND |
-					     WQ_MEM_RECLAIM |
-					     WQ_NON_REENTRANT,
-					     0);
+					     WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
 	if (!ls->ls_callback_wq) {
 		log_print("can't start dlm_callback workqueue");
 		return -ENOMEM;
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 81214911..142e2165 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -493,7 +493,6 @@
 {
 	struct dlm_user_proc *proc = file->private_data;
 	struct dlm_write_request *kbuf;
-	sigset_t tmpsig, allsigs;
 	int error;
 
 #ifdef CONFIG_COMPAT
@@ -557,9 +556,6 @@
 		goto out_free;
 	}
 
-	sigfillset(&allsigs);
-	sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
-
 	error = -EINVAL;
 
 	switch (kbuf->cmd)
@@ -567,7 +563,7 @@
 	case DLM_USER_LOCK:
 		if (!proc) {
 			log_print("no locking on control device");
-			goto out_sig;
+			goto out_free;
 		}
 		error = device_user_lock(proc, &kbuf->i.lock);
 		break;
@@ -575,7 +571,7 @@
 	case DLM_USER_UNLOCK:
 		if (!proc) {
 			log_print("no locking on control device");
-			goto out_sig;
+			goto out_free;
 		}
 		error = device_user_unlock(proc, &kbuf->i.lock);
 		break;
@@ -583,7 +579,7 @@
 	case DLM_USER_DEADLOCK:
 		if (!proc) {
 			log_print("no locking on control device");
-			goto out_sig;
+			goto out_free;
 		}
 		error = device_user_deadlock(proc, &kbuf->i.lock);
 		break;
@@ -591,7 +587,7 @@
 	case DLM_USER_CREATE_LOCKSPACE:
 		if (proc) {
 			log_print("create/remove only on control device");
-			goto out_sig;
+			goto out_free;
 		}
 		error = device_create_lockspace(&kbuf->i.lspace);
 		break;
@@ -599,7 +595,7 @@
 	case DLM_USER_REMOVE_LOCKSPACE:
 		if (proc) {
 			log_print("create/remove only on control device");
-			goto out_sig;
+			goto out_free;
 		}
 		error = device_remove_lockspace(&kbuf->i.lspace);
 		break;
@@ -607,7 +603,7 @@
 	case DLM_USER_PURGE:
 		if (!proc) {
 			log_print("no locking on control device");
-			goto out_sig;
+			goto out_free;
 		}
 		error = device_user_purge(proc, &kbuf->i.purge);
 		break;
@@ -617,8 +613,6 @@
 			  kbuf->cmd);
 	}
 
- out_sig:
-	sigprocmask(SIG_SETMASK, &tmpsig, NULL);
  out_free:
 	kfree(kbuf);
 	return error;
@@ -659,15 +653,11 @@
 {
 	struct dlm_user_proc *proc = file->private_data;
 	struct dlm_ls *ls;
-	sigset_t tmpsig, allsigs;
 
 	ls = dlm_find_lockspace_local(proc->lockspace);
 	if (!ls)
 		return -ENOENT;
 
-	sigfillset(&allsigs);
-	sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
-
 	set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
 
 	dlm_clear_proc_locks(ls, proc);
@@ -685,8 +675,6 @@
 	/* FIXME: AUTOFREE: if this ls is no longer used do
 	   device_remove_lockspace() */
 
-	sigprocmask(SIG_SETMASK, &tmpsig, NULL);
-
 	return 0;
 }
 
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index f522425..bafdd48 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -41,7 +41,7 @@
 
 /**
  * Check if the given dir-inode refers to an htree-indexed directory
- * (or a directory which chould potentially get coverted to use htree
+ * (or a directory which could potentially get converted to use htree
  * indexing).
  *
  * Return 1 if it is a dx dir, 0 if not
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index ddd715e..dc5d572 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -184,6 +184,7 @@
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	ext4_fsblk_t start, tmp;
 	int flex_bg = 0;
+	struct ext4_group_info *grp;
 
 	J_ASSERT_BH(bh, buffer_locked(bh));
 
@@ -191,11 +192,9 @@
 	 * essentially implementing a per-group read-only flag. */
 	if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
 		ext4_error(sb, "Checksum bad for group %u", block_group);
-		ext4_free_group_clusters_set(sb, gdp, 0);
-		ext4_free_inodes_set(sb, gdp, 0);
-		ext4_itable_unused_set(sb, gdp, 0);
-		memset(bh->b_data, 0xff, sb->s_blocksize);
-		ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
+		grp = ext4_get_group_info(sb, block_group);
+		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
+		set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
 		return;
 	}
 	memset(bh->b_data, 0, sb->s_blocksize);
@@ -305,7 +304,7 @@
  */
 static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
 					    struct ext4_group_desc *desc,
-					    unsigned int block_group,
+					    ext4_group_t block_group,
 					    struct buffer_head *bh)
 {
 	ext4_grpblk_t offset;
@@ -352,10 +351,11 @@
 
 void ext4_validate_block_bitmap(struct super_block *sb,
 			       struct ext4_group_desc *desc,
-			       unsigned int block_group,
+			       ext4_group_t block_group,
 			       struct buffer_head *bh)
 {
 	ext4_fsblk_t	blk;
+	struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
 
 	if (buffer_verified(bh))
 		return;
@@ -366,12 +366,14 @@
 		ext4_unlock_group(sb, block_group);
 		ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
 			   block_group, blk);
+		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
 		return;
 	}
 	if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
 			desc, bh))) {
 		ext4_unlock_group(sb, block_group);
 		ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
+		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
 		return;
 	}
 	set_buffer_verified(bh);
@@ -445,7 +447,10 @@
 	return bh;
 verify:
 	ext4_validate_block_bitmap(sb, desc, block_group, bh);
-	return bh;
+	if (buffer_verified(bh))
+		return bh;
+	put_bh(bh);
+	return NULL;
 }
 
 /* Returns 0 on success, 1 on error */
@@ -469,7 +474,8 @@
 	clear_buffer_new(bh);
 	/* Panic or remount fs read-only if block bitmap is invalid */
 	ext4_validate_block_bitmap(sb, desc, block_group, bh);
-	return 0;
+	/* ...but check for error just in case errors=continue. */
+	return !buffer_verified(bh);
 }
 
 struct buffer_head *
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 3c7d288..680bb33 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -33,7 +33,7 @@
 
 /**
  * Check if the given dir-inode refers to an htree-indexed directory
- * (or a directory which chould potentially get coverted to use htree
+ * (or a directory which could potentially get converted to use htree
  * indexing).
  *
  * Return 1 if it is a dx dir, 0 if not
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index b247fbb..af815ea 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -558,6 +558,18 @@
 #define EXT4_GET_BLOCKS_NO_PUT_HOLE		0x0200
 
 /*
+ * The bit position of these flags must not overlap with any of the
+ * EXT4_GET_BLOCKS_*.  They are used by ext4_ext_find_extent(),
+ * read_extent_tree_block(), ext4_split_extent_at(),
+ * ext4_ext_insert_extent(), and ext4_ext_create_new_leaf().
+ * EXT4_EX_NOCACHE is used to indicate that the we shouldn't be
+ * caching the extents when reading from the extent tree while a
+ * truncate or punch hole operation is in progress.
+ */
+#define EXT4_EX_NOCACHE				0x0400
+#define EXT4_EX_FORCE_CACHE			0x0800
+
+/*
  * Flags used by ext4_free_blocks
  */
 #define EXT4_FREE_BLOCKS_METADATA	0x0001
@@ -566,6 +578,7 @@
 #define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE	0x0008
 #define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER	0x0010
 #define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER	0x0020
+#define EXT4_FREE_BLOCKS_RESERVE		0x0040
 
 /*
  * ioctl commands
@@ -587,6 +600,7 @@
 #define EXT4_IOC_MOVE_EXT		_IOWR('f', 15, struct move_extent)
 #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
 #define EXT4_IOC_SWAP_BOOT		_IO('f', 17)
+#define EXT4_IOC_PRECACHE_EXTENTS	_IO('f', 18)
 
 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /*
@@ -1365,6 +1379,7 @@
 					   nolocking */
 	EXT4_STATE_MAY_INLINE_DATA,	/* may have in-inode data */
 	EXT4_STATE_ORDERED_MODE,	/* data=ordered mode */
+	EXT4_STATE_EXT_PRECACHED,	/* extents have been precached */
 };
 
 #define EXT4_INODE_BIT_FNS(name, field, offset)				\
@@ -1905,7 +1920,7 @@
 
 extern void ext4_validate_block_bitmap(struct super_block *sb,
 				       struct ext4_group_desc *desc,
-				       unsigned int block_group,
+				       ext4_group_t block_group,
 				       struct buffer_head *bh);
 extern unsigned int ext4_block_group(struct super_block *sb,
 			ext4_fsblk_t blocknr);
@@ -2407,16 +2422,32 @@
 #define EXT4_FREECLUSTERS_WATERMARK 0
 #endif
 
+/* Update i_disksize. Requires i_mutex to avoid races with truncate */
 static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
 {
-	/*
-	 * XXX: replace with spinlock if seen contended -bzzz
-	 */
+	WARN_ON_ONCE(S_ISREG(inode->i_mode) &&
+		     !mutex_is_locked(&inode->i_mutex));
 	down_write(&EXT4_I(inode)->i_data_sem);
 	if (newsize > EXT4_I(inode)->i_disksize)
 		EXT4_I(inode)->i_disksize = newsize;
 	up_write(&EXT4_I(inode)->i_data_sem);
-	return ;
+}
+
+/*
+ * Update i_disksize after writeback has been started. Races with truncate
+ * are avoided by checking i_size under i_data_sem.
+ */
+static inline void ext4_wb_update_i_disksize(struct inode *inode, loff_t newsize)
+{
+	loff_t i_size;
+
+	down_write(&EXT4_I(inode)->i_data_sem);
+	i_size = i_size_read(inode);
+	if (newsize > i_size)
+		newsize = i_size;
+	if (newsize > EXT4_I(inode)->i_disksize)
+		EXT4_I(inode)->i_disksize = newsize;
+	up_write(&EXT4_I(inode)->i_data_sem);
 }
 
 struct ext4_group_info {
@@ -2439,9 +2470,15 @@
 
 #define EXT4_GROUP_INFO_NEED_INIT_BIT		0
 #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT		1
+#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT	2
+#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT	3
 
 #define EXT4_MB_GRP_NEED_INIT(grp)	\
 	(test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp)	\
+	(test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp)	\
+	(test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
 
 #define EXT4_MB_GRP_WAS_TRIMMED(grp)	\
 	(test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
@@ -2645,6 +2682,12 @@
 struct ext4_ext_path;
 struct ext4_extent;
 
+/*
+ * Maximum number of logical blocks in a file; ext4_extent's ee_block is
+ * __le32.
+ */
+#define EXT_MAX_BLOCKS	0xffffffff
+
 extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
 extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
 extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents);
@@ -2674,7 +2717,8 @@
 				  struct ext4_ext_path *,
 				  struct ext4_extent *, int);
 extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
-						  struct ext4_ext_path *);
+						  struct ext4_ext_path *,
+						  int flags);
 extern void ext4_ext_drop_refs(struct ext4_ext_path *);
 extern int ext4_ext_check_inode(struct inode *inode);
 extern int ext4_find_delalloc_range(struct inode *inode,
@@ -2683,7 +2727,7 @@
 extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk);
 extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 			__u64 start, __u64 len);
-
+extern int ext4_ext_precache(struct inode *inode);
 
 /* move_extent.c */
 extern void ext4_double_down_write_data_sem(struct inode *first,
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index 51bc821..5074fe2 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -134,12 +134,6 @@
  */
 
 /*
- * Maximum number of logical blocks in a file; ext4_extent's ee_block is
- * __le32.
- */
-#define EXT_MAX_BLOCKS	0xffffffff
-
-/*
  * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
  * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
  * MSB of ee_len field in the extent datastructure to signify if this
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 2877258..81cfefa 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -197,7 +197,7 @@
  * ext4_journal_callback_del: delete a registered callback
  * @handle: active journal transaction handle on which callback was registered
  * @jce: registered journal callback entry to unregister
- * Return true if object was sucessfully removed
+ * Return true if object was successfully removed
  */
 static inline bool ext4_journal_callback_try_del(handle_t *handle,
 					     struct ext4_journal_cb_entry *jce)
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 72ba470..54d52af 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -407,7 +407,7 @@
 
 static int __ext4_ext_check(const char *function, unsigned int line,
 			    struct inode *inode, struct ext4_extent_header *eh,
-			    int depth)
+			    int depth, ext4_fsblk_t pblk)
 {
 	const char *error_msg;
 	int max = 0;
@@ -447,43 +447,150 @@
 
 corrupted:
 	ext4_error_inode(inode, function, line, 0,
-			"bad header/extent: %s - magic %x, "
-			"entries %u, max %u(%u), depth %u(%u)",
-			error_msg, le16_to_cpu(eh->eh_magic),
-			le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
-			max, le16_to_cpu(eh->eh_depth), depth);
-
+			 "pblk %llu bad header/extent: %s - magic %x, "
+			 "entries %u, max %u(%u), depth %u(%u)",
+			 (unsigned long long) pblk, error_msg,
+			 le16_to_cpu(eh->eh_magic),
+			 le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
+			 max, le16_to_cpu(eh->eh_depth), depth);
 	return -EIO;
 }
 
-#define ext4_ext_check(inode, eh, depth)	\
-	__ext4_ext_check(__func__, __LINE__, inode, eh, depth)
+#define ext4_ext_check(inode, eh, depth, pblk)			\
+	__ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk))
 
 int ext4_ext_check_inode(struct inode *inode)
 {
-	return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode));
+	return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode), 0);
 }
 
-static int __ext4_ext_check_block(const char *function, unsigned int line,
-				  struct inode *inode,
-				  struct ext4_extent_header *eh,
-				  int depth,
-				  struct buffer_head *bh)
+static struct buffer_head *
+__read_extent_tree_block(const char *function, unsigned int line,
+			 struct inode *inode, ext4_fsblk_t pblk, int depth,
+			 int flags)
 {
-	int ret;
+	struct buffer_head		*bh;
+	int				err;
 
-	if (buffer_verified(bh))
-		return 0;
-	ret = ext4_ext_check(inode, eh, depth);
-	if (ret)
-		return ret;
+	bh = sb_getblk(inode->i_sb, pblk);
+	if (unlikely(!bh))
+		return ERR_PTR(-ENOMEM);
+
+	if (!bh_uptodate_or_lock(bh)) {
+		trace_ext4_ext_load_extent(inode, pblk, _RET_IP_);
+		err = bh_submit_read(bh);
+		if (err < 0)
+			goto errout;
+	}
+	if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
+		return bh;
+	err = __ext4_ext_check(function, line, inode,
+			       ext_block_hdr(bh), depth, pblk);
+	if (err)
+		goto errout;
 	set_buffer_verified(bh);
+	/*
+	 * If this is a leaf block, cache all of its entries
+	 */
+	if (!(flags & EXT4_EX_NOCACHE) && depth == 0) {
+		struct ext4_extent_header *eh = ext_block_hdr(bh);
+		struct ext4_extent *ex = EXT_FIRST_EXTENT(eh);
+		ext4_lblk_t prev = 0;
+		int i;
+
+		for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
+			unsigned int status = EXTENT_STATUS_WRITTEN;
+			ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
+			int len = ext4_ext_get_actual_len(ex);
+
+			if (prev && (prev != lblk))
+				ext4_es_cache_extent(inode, prev,
+						     lblk - prev, ~0,
+						     EXTENT_STATUS_HOLE);
+
+			if (ext4_ext_is_uninitialized(ex))
+				status = EXTENT_STATUS_UNWRITTEN;
+			ext4_es_cache_extent(inode, lblk, len,
+					     ext4_ext_pblock(ex), status);
+			prev = lblk + len;
+		}
+	}
+	return bh;
+errout:
+	put_bh(bh);
+	return ERR_PTR(err);
+
+}
+
+#define read_extent_tree_block(inode, pblk, depth, flags)		\
+	__read_extent_tree_block(__func__, __LINE__, (inode), (pblk),   \
+				 (depth), (flags))
+
+/*
+ * This function is called to cache a file's extent information in the
+ * extent status tree
+ */
+int ext4_ext_precache(struct inode *inode)
+{
+	struct ext4_inode_info *ei = EXT4_I(inode);
+	struct ext4_ext_path *path = NULL;
+	struct buffer_head *bh;
+	int i = 0, depth, ret = 0;
+
+	if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+		return 0;	/* not an extent-mapped inode */
+
+	down_read(&ei->i_data_sem);
+	depth = ext_depth(inode);
+
+	path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
+		       GFP_NOFS);
+	if (path == NULL) {
+		up_read(&ei->i_data_sem);
+		return -ENOMEM;
+	}
+
+	/* Don't cache anything if there are no external extent blocks */
+	if (depth == 0)
+		goto out;
+	path[0].p_hdr = ext_inode_hdr(inode);
+	ret = ext4_ext_check(inode, path[0].p_hdr, depth, 0);
+	if (ret)
+		goto out;
+	path[0].p_idx = EXT_FIRST_INDEX(path[0].p_hdr);
+	while (i >= 0) {
+		/*
+		 * If this is a leaf block or we've reached the end of
+		 * the index block, go up
+		 */
+		if ((i == depth) ||
+		    path[i].p_idx > EXT_LAST_INDEX(path[i].p_hdr)) {
+			brelse(path[i].p_bh);
+			path[i].p_bh = NULL;
+			i--;
+			continue;
+		}
+		bh = read_extent_tree_block(inode,
+					    ext4_idx_pblock(path[i].p_idx++),
+					    depth - i - 1,
+					    EXT4_EX_FORCE_CACHE);
+		if (IS_ERR(bh)) {
+			ret = PTR_ERR(bh);
+			break;
+		}
+		i++;
+		path[i].p_bh = bh;
+		path[i].p_hdr = ext_block_hdr(bh);
+		path[i].p_idx = EXT_FIRST_INDEX(path[i].p_hdr);
+	}
+	ext4_set_inode_state(inode, EXT4_STATE_EXT_PRECACHED);
+out:
+	up_read(&ei->i_data_sem);
+	ext4_ext_drop_refs(path);
+	kfree(path);
 	return ret;
 }
 
-#define ext4_ext_check_block(inode, eh, depth, bh)	\
-	__ext4_ext_check_block(__func__, __LINE__, inode, eh, depth, bh)
-
 #ifdef EXT_DEBUG
 static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
 {
@@ -716,7 +823,7 @@
 
 struct ext4_ext_path *
 ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block,
-					struct ext4_ext_path *path)
+		     struct ext4_ext_path *path, int flags)
 {
 	struct ext4_extent_header *eh;
 	struct buffer_head *bh;
@@ -748,20 +855,13 @@
 		path[ppos].p_depth = i;
 		path[ppos].p_ext = NULL;
 
-		bh = sb_getblk(inode->i_sb, path[ppos].p_block);
-		if (unlikely(!bh)) {
-			ret = -ENOMEM;
+		bh = read_extent_tree_block(inode, path[ppos].p_block, --i,
+					    flags);
+		if (IS_ERR(bh)) {
+			ret = PTR_ERR(bh);
 			goto err;
 		}
-		if (!bh_uptodate_or_lock(bh)) {
-			trace_ext4_ext_load_extent(inode, block,
-						path[ppos].p_block);
-			ret = bh_submit_read(bh);
-			if (ret < 0) {
-				put_bh(bh);
-				goto err;
-			}
-		}
+
 		eh = ext_block_hdr(bh);
 		ppos++;
 		if (unlikely(ppos > depth)) {
@@ -773,11 +873,6 @@
 		}
 		path[ppos].p_bh = bh;
 		path[ppos].p_hdr = eh;
-		i--;
-
-		ret = ext4_ext_check_block(inode, eh, i, bh);
-		if (ret < 0)
-			goto err;
 	}
 
 	path[ppos].p_depth = i;
@@ -1198,7 +1293,8 @@
  * if no free index is found, then it requests in-depth growing.
  */
 static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
-				    unsigned int flags,
+				    unsigned int mb_flags,
+				    unsigned int gb_flags,
 				    struct ext4_ext_path *path,
 				    struct ext4_extent *newext)
 {
@@ -1220,7 +1316,7 @@
 	if (EXT_HAS_FREE_INDEX(curp)) {
 		/* if we found index with free entry, then use that
 		 * entry: create all needed subtree and add new leaf */
-		err = ext4_ext_split(handle, inode, flags, path, newext, i);
+		err = ext4_ext_split(handle, inode, mb_flags, path, newext, i);
 		if (err)
 			goto out;
 
@@ -1228,12 +1324,12 @@
 		ext4_ext_drop_refs(path);
 		path = ext4_ext_find_extent(inode,
 				    (ext4_lblk_t)le32_to_cpu(newext->ee_block),
-				    path);
+				    path, gb_flags);
 		if (IS_ERR(path))
 			err = PTR_ERR(path);
 	} else {
 		/* tree is full, time to grow in depth */
-		err = ext4_ext_grow_indepth(handle, inode, flags, newext);
+		err = ext4_ext_grow_indepth(handle, inode, mb_flags, newext);
 		if (err)
 			goto out;
 
@@ -1241,7 +1337,7 @@
 		ext4_ext_drop_refs(path);
 		path = ext4_ext_find_extent(inode,
 				   (ext4_lblk_t)le32_to_cpu(newext->ee_block),
-				    path);
+				    path, gb_flags);
 		if (IS_ERR(path)) {
 			err = PTR_ERR(path);
 			goto out;
@@ -1412,29 +1508,21 @@
 	ix++;
 	block = ext4_idx_pblock(ix);
 	while (++depth < path->p_depth) {
-		bh = sb_bread(inode->i_sb, block);
-		if (bh == NULL)
-			return -EIO;
-		eh = ext_block_hdr(bh);
 		/* subtract from p_depth to get proper eh_depth */
-		if (ext4_ext_check_block(inode, eh,
-					 path->p_depth - depth, bh)) {
-			put_bh(bh);
-			return -EIO;
-		}
+		bh = read_extent_tree_block(inode, block,
+					    path->p_depth - depth, 0);
+		if (IS_ERR(bh))
+			return PTR_ERR(bh);
+		eh = ext_block_hdr(bh);
 		ix = EXT_FIRST_INDEX(eh);
 		block = ext4_idx_pblock(ix);
 		put_bh(bh);
 	}
 
-	bh = sb_bread(inode->i_sb, block);
-	if (bh == NULL)
-		return -EIO;
+	bh = read_extent_tree_block(inode, block, path->p_depth - depth, 0);
+	if (IS_ERR(bh))
+		return PTR_ERR(bh);
 	eh = ext_block_hdr(bh);
-	if (ext4_ext_check_block(inode, eh, path->p_depth - depth, bh)) {
-		put_bh(bh);
-		return -EIO;
-	}
 	ex = EXT_FIRST_EXTENT(eh);
 found_extent:
 	*logical = le32_to_cpu(ex->ee_block);
@@ -1705,7 +1793,8 @@
 
 	brelse(path[1].p_bh);
 	ext4_free_blocks(handle, inode, NULL, blk, 1,
-			 EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
+			 EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET |
+			 EXT4_FREE_BLOCKS_RESERVE);
 }
 
 /*
@@ -1793,7 +1882,7 @@
  */
 int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
 				struct ext4_ext_path *path,
-				struct ext4_extent *newext, int flag)
+				struct ext4_extent *newext, int gb_flags)
 {
 	struct ext4_extent_header *eh;
 	struct ext4_extent *ex, *fex;
@@ -1802,7 +1891,7 @@
 	int depth, len, err;
 	ext4_lblk_t next;
 	unsigned uninitialized = 0;
-	int flags = 0;
+	int mb_flags = 0;
 
 	if (unlikely(ext4_ext_get_actual_len(newext) == 0)) {
 		EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0");
@@ -1817,7 +1906,7 @@
 	}
 
 	/* try to insert block into found extent and return */
-	if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)) {
+	if (ex && !(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) {
 
 		/*
 		 * Try to see whether we should rather test the extent on
@@ -1920,7 +2009,7 @@
 	if (next != EXT_MAX_BLOCKS) {
 		ext_debug("next leaf block - %u\n", next);
 		BUG_ON(npath != NULL);
-		npath = ext4_ext_find_extent(inode, next, NULL);
+		npath = ext4_ext_find_extent(inode, next, NULL, 0);
 		if (IS_ERR(npath))
 			return PTR_ERR(npath);
 		BUG_ON(npath->p_depth != path->p_depth);
@@ -1939,9 +2028,10 @@
 	 * There is no free space in the found leaf.
 	 * We're gonna add a new leaf in the tree.
 	 */
-	if (flag & EXT4_GET_BLOCKS_METADATA_NOFAIL)
-		flags = EXT4_MB_USE_RESERVED;
-	err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext);
+	if (gb_flags & EXT4_GET_BLOCKS_METADATA_NOFAIL)
+		mb_flags = EXT4_MB_USE_RESERVED;
+	err = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags,
+				       path, newext);
 	if (err)
 		goto cleanup;
 	depth = ext_depth(inode);
@@ -2007,7 +2097,7 @@
 
 merge:
 	/* try to merge extents */
-	if (!(flag & EXT4_GET_BLOCKS_PRE_IO))
+	if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
 		ext4_ext_try_to_merge(handle, inode, path, nearex);
 
 
@@ -2050,7 +2140,7 @@
 			path = NULL;
 		}
 
-		path = ext4_ext_find_extent(inode, block, path);
+		path = ext4_ext_find_extent(inode, block, path, 0);
 		if (IS_ERR(path)) {
 			up_read(&EXT4_I(inode)->i_data_sem);
 			err = PTR_ERR(path);
@@ -2195,8 +2285,8 @@
 				ext4_lblk_t block)
 {
 	int depth = ext_depth(inode);
-	unsigned long len;
-	ext4_lblk_t lblock;
+	unsigned long len = 0;
+	ext4_lblk_t lblock = 0;
 	struct ext4_extent *ex;
 
 	ex = path[depth].p_ext;
@@ -2233,7 +2323,6 @@
 			ext4_es_insert_extent(inode, lblock, len, ~0,
 					      EXTENT_STATUS_HOLE);
 	} else {
-		lblock = len = 0;
 		BUG();
 	}
 
@@ -2712,7 +2801,7 @@
 		ext4_lblk_t ee_block;
 
 		/* find extent for this block */
-		path = ext4_ext_find_extent(inode, end, NULL);
+		path = ext4_ext_find_extent(inode, end, NULL, EXT4_EX_NOCACHE);
 		if (IS_ERR(path)) {
 			ext4_journal_stop(handle);
 			return PTR_ERR(path);
@@ -2754,6 +2843,7 @@
 			 */
 			err = ext4_split_extent_at(handle, inode, path,
 					end + 1, split_flag,
+					EXT4_EX_NOCACHE |
 					EXT4_GET_BLOCKS_PRE_IO |
 					EXT4_GET_BLOCKS_METADATA_NOFAIL);
 
@@ -2782,7 +2872,7 @@
 		path[0].p_hdr = ext_inode_hdr(inode);
 		i = 0;
 
-		if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
+		if (ext4_ext_check(inode, path[0].p_hdr, depth, 0)) {
 			err = -EIO;
 			goto out;
 		}
@@ -2829,10 +2919,12 @@
 			ext_debug("move to level %d (block %llu)\n",
 				  i + 1, ext4_idx_pblock(path[i].p_idx));
 			memset(path + i + 1, 0, sizeof(*path));
-			bh = sb_bread(sb, ext4_idx_pblock(path[i].p_idx));
-			if (!bh) {
+			bh = read_extent_tree_block(inode,
+				ext4_idx_pblock(path[i].p_idx), depth - i - 1,
+				EXT4_EX_NOCACHE);
+			if (IS_ERR(bh)) {
 				/* should we reset i_size? */
-				err = -EIO;
+				err = PTR_ERR(bh);
 				break;
 			}
 			/* Yield here to deal with large extent trees.
@@ -2842,11 +2934,6 @@
 				err = -EIO;
 				break;
 			}
-			if (ext4_ext_check_block(inode, ext_block_hdr(bh),
-							depth - i - 1, bh)) {
-				err = -EIO;
-				break;
-			}
 			path[i + 1].p_bh = bh;
 
 			/* save actual number of indexes since this
@@ -2961,6 +3048,23 @@
 #endif
 }
 
+static int ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex)
+{
+	ext4_lblk_t  ee_block;
+	ext4_fsblk_t ee_pblock;
+	unsigned int ee_len;
+
+	ee_block  = le32_to_cpu(ex->ee_block);
+	ee_len    = ext4_ext_get_actual_len(ex);
+	ee_pblock = ext4_ext_pblock(ex);
+
+	if (ee_len == 0)
+		return 0;
+
+	return ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock,
+				     EXTENT_STATUS_WRITTEN);
+}
+
 /* FIXME!! we need to try to merge to left or right after zero-out  */
 static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
 {
@@ -3113,7 +3217,7 @@
 			goto fix_extent_len;
 
 		/* update extent status tree */
-		err = ext4_es_zeroout(inode, &zero_ex);
+		err = ext4_zeroout_es(inode, &zero_ex);
 
 		goto out;
 	} else if (err)
@@ -3133,7 +3237,7 @@
  * ext4_split_extents() splits an extent and mark extent which is covered
  * by @map as split_flags indicates
  *
- * It may result in splitting the extent into multiple extents (upto three)
+ * It may result in splitting the extent into multiple extents (up to three)
  * There are three possibilities:
  *   a> There is no split required
  *   b> Splits in two extents: Split is happening at either end of the extent
@@ -3181,7 +3285,7 @@
 	 * result in split of original leaf or extent zeroout.
 	 */
 	ext4_ext_drop_refs(path);
-	path = ext4_ext_find_extent(inode, map->m_lblk, path);
+	path = ext4_ext_find_extent(inode, map->m_lblk, path, 0);
 	if (IS_ERR(path))
 		return PTR_ERR(path);
 	depth = ext_depth(inode);
@@ -3464,7 +3568,7 @@
 out:
 	/* If we have gotten a failure, don't zero out status tree */
 	if (!err)
-		err = ext4_es_zeroout(inode, &zero_ex);
+		err = ext4_zeroout_es(inode, &zero_ex);
 	return err ? err : allocated;
 }
 
@@ -3565,7 +3669,7 @@
 		if (err < 0)
 			goto out;
 		ext4_ext_drop_refs(path);
-		path = ext4_ext_find_extent(inode, map->m_lblk, path);
+		path = ext4_ext_find_extent(inode, map->m_lblk, path, 0);
 		if (IS_ERR(path)) {
 			err = PTR_ERR(path);
 			goto out;
@@ -4052,7 +4156,7 @@
 	trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags);
 
 	/* find extent for this block */
-	path = ext4_ext_find_extent(inode, map->m_lblk, NULL);
+	path = ext4_ext_find_extent(inode, map->m_lblk, NULL, 0);
 	if (IS_ERR(path)) {
 		err = PTR_ERR(path);
 		path = NULL;
@@ -4744,6 +4848,12 @@
 			return error;
 	}
 
+	if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
+		error = ext4_ext_precache(inode);
+		if (error)
+			return error;
+	}
+
 	/* fallback to generic here if not in extents fmt */
 	if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
 		return generic_block_fiemap(inode, fieinfo, start, len,
@@ -4771,6 +4881,6 @@
 		error = ext4_fill_fiemap_extents(inode, start_blk,
 						 len_blks, fieinfo);
 	}
-
+	ext4_es_lru_add(inode);
 	return error;
 }
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index 91cb110..2d1bdbe 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -13,7 +13,6 @@
 #include <linux/list_sort.h>
 #include "ext4.h"
 #include "extents_status.h"
-#include "ext4_extents.h"
 
 #include <trace/events/ext4.h>
 
@@ -263,7 +262,7 @@
 	if (tree->cache_es) {
 		es1 = tree->cache_es;
 		if (in_range(lblk, es1->es_lblk, es1->es_len)) {
-			es_debug("%u cached by [%u/%u) %llu %llx\n",
+			es_debug("%u cached by [%u/%u) %llu %x\n",
 				 lblk, es1->es_lblk, es1->es_len,
 				 ext4_es_pblock(es1), ext4_es_status(es1));
 			goto out;
@@ -409,6 +408,8 @@
 }
 
 #ifdef ES_AGGRESSIVE_TEST
+#include "ext4_extents.h"	/* Needed when ES_AGGRESSIVE_TEST is defined */
+
 static void ext4_es_insert_extent_ext_check(struct inode *inode,
 					    struct extent_status *es)
 {
@@ -419,7 +420,7 @@
 	unsigned short ee_len;
 	int depth, ee_status, es_status;
 
-	path = ext4_ext_find_extent(inode, es->es_lblk, NULL);
+	path = ext4_ext_find_extent(inode, es->es_lblk, NULL, EXT4_EX_NOCACHE);
 	if (IS_ERR(path))
 		return;
 
@@ -641,13 +642,13 @@
  */
 int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
 			  ext4_lblk_t len, ext4_fsblk_t pblk,
-			  unsigned long long status)
+			  unsigned int status)
 {
 	struct extent_status newes;
 	ext4_lblk_t end = lblk + len - 1;
 	int err = 0;
 
-	es_debug("add [%u/%u) %llu %llx to extent status tree of inode %lu\n",
+	es_debug("add [%u/%u) %llu %x to extent status tree of inode %lu\n",
 		 lblk, len, pblk, status, inode->i_ino);
 
 	if (!len)
@@ -684,6 +685,38 @@
 }
 
 /*
+ * ext4_es_cache_extent() inserts information into the extent status
+ * tree if and only if there isn't information about the range in
+ * question already.
+ */
+void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,
+			  ext4_lblk_t len, ext4_fsblk_t pblk,
+			  unsigned int status)
+{
+	struct extent_status *es;
+	struct extent_status newes;
+	ext4_lblk_t end = lblk + len - 1;
+
+	newes.es_lblk = lblk;
+	newes.es_len = len;
+	ext4_es_store_pblock(&newes, pblk);
+	ext4_es_store_status(&newes, status);
+	trace_ext4_es_cache_extent(inode, &newes);
+
+	if (!len)
+		return;
+
+	BUG_ON(end < lblk);
+
+	write_lock(&EXT4_I(inode)->i_es_lock);
+
+	es = __es_tree_search(&EXT4_I(inode)->i_es_tree.root, lblk);
+	if (!es || es->es_lblk > end)
+		__es_insert_extent(inode, &newes);
+	write_unlock(&EXT4_I(inode)->i_es_lock);
+}
+
+/*
  * ext4_es_lookup_extent() looks up an extent in extent status tree.
  *
  * ext4_es_lookup_extent is called by ext4_map_blocks/ext4_da_map_blocks.
@@ -871,23 +904,6 @@
 	return err;
 }
 
-int ext4_es_zeroout(struct inode *inode, struct ext4_extent *ex)
-{
-	ext4_lblk_t  ee_block;
-	ext4_fsblk_t ee_pblock;
-	unsigned int ee_len;
-
-	ee_block  = le32_to_cpu(ex->ee_block);
-	ee_len    = ext4_ext_get_actual_len(ex);
-	ee_pblock = ext4_ext_pblock(ex);
-
-	if (ee_len == 0)
-		return 0;
-
-	return ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock,
-				     EXTENT_STATUS_WRITTEN);
-}
-
 static int ext4_inode_touch_time_cmp(void *priv, struct list_head *a,
 				     struct list_head *b)
 {
@@ -895,6 +911,12 @@
 	eia = list_entry(a, struct ext4_inode_info, i_es_lru);
 	eib = list_entry(b, struct ext4_inode_info, i_es_lru);
 
+	if (ext4_test_inode_state(&eia->vfs_inode, EXT4_STATE_EXT_PRECACHED) &&
+	    !ext4_test_inode_state(&eib->vfs_inode, EXT4_STATE_EXT_PRECACHED))
+		return 1;
+	if (!ext4_test_inode_state(&eia->vfs_inode, EXT4_STATE_EXT_PRECACHED) &&
+	    ext4_test_inode_state(&eib->vfs_inode, EXT4_STATE_EXT_PRECACHED))
+		return -1;
 	if (eia->i_touch_when == eib->i_touch_when)
 		return 0;
 	if (time_after(eia->i_touch_when, eib->i_touch_when))
@@ -908,21 +930,13 @@
 {
 	struct ext4_inode_info *ei;
 	struct list_head *cur, *tmp;
-	LIST_HEAD(skiped);
+	LIST_HEAD(skipped);
 	int ret, nr_shrunk = 0;
+	int retried = 0, skip_precached = 1, nr_skipped = 0;
 
 	spin_lock(&sbi->s_es_lru_lock);
 
-	/*
-	 * If the inode that is at the head of LRU list is newer than
-	 * last_sorted time, that means that we need to sort this list.
-	 */
-	ei = list_first_entry(&sbi->s_es_lru, struct ext4_inode_info, i_es_lru);
-	if (sbi->s_es_last_sorted < ei->i_touch_when) {
-		list_sort(NULL, &sbi->s_es_lru, ext4_inode_touch_time_cmp);
-		sbi->s_es_last_sorted = jiffies;
-	}
-
+retry:
 	list_for_each_safe(cur, tmp, &sbi->s_es_lru) {
 		/*
 		 * If we have already reclaimed all extents from extent
@@ -933,9 +947,16 @@
 
 		ei = list_entry(cur, struct ext4_inode_info, i_es_lru);
 
-		/* Skip the inode that is newer than the last_sorted time */
-		if (sbi->s_es_last_sorted < ei->i_touch_when) {
-			list_move_tail(cur, &skiped);
+		/*
+		 * Skip the inode that is newer than the last_sorted
+		 * time.  Normally we try hard to avoid shrinking
+		 * precached inodes, but we will as a last resort.
+		 */
+		if ((sbi->s_es_last_sorted < ei->i_touch_when) ||
+		    (skip_precached && ext4_test_inode_state(&ei->vfs_inode,
+						EXT4_STATE_EXT_PRECACHED))) {
+			nr_skipped++;
+			list_move_tail(cur, &skipped);
 			continue;
 		}
 
@@ -955,11 +976,33 @@
 	}
 
 	/* Move the newer inodes into the tail of the LRU list. */
-	list_splice_tail(&skiped, &sbi->s_es_lru);
+	list_splice_tail(&skipped, &sbi->s_es_lru);
+	INIT_LIST_HEAD(&skipped);
+
+	/*
+	 * If we skipped any inodes, and we weren't able to make any
+	 * forward progress, sort the list and try again.
+	 */
+	if ((nr_shrunk == 0) && nr_skipped && !retried) {
+		retried++;
+		list_sort(NULL, &sbi->s_es_lru, ext4_inode_touch_time_cmp);
+		sbi->s_es_last_sorted = jiffies;
+		ei = list_first_entry(&sbi->s_es_lru, struct ext4_inode_info,
+				      i_es_lru);
+		/*
+		 * If there are no non-precached inodes left on the
+		 * list, start releasing precached extents.
+		 */
+		if (ext4_test_inode_state(&ei->vfs_inode,
+					  EXT4_STATE_EXT_PRECACHED))
+			skip_precached = 0;
+		goto retry;
+	}
+
 	spin_unlock(&sbi->s_es_lru_lock);
 
 	if (locked_ei && nr_shrunk == 0)
-		nr_shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan);
+		nr_shrunk = __es_try_to_reclaim_extents(locked_ei, nr_to_scan);
 
 	return nr_shrunk;
 }
@@ -1034,10 +1077,16 @@
 	struct rb_node *node;
 	struct extent_status *es;
 	int nr_shrunk = 0;
+	static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
+				      DEFAULT_RATELIMIT_BURST);
 
 	if (ei->i_es_lru_nr == 0)
 		return 0;
 
+	if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED) &&
+	    __ratelimit(&_rs))
+		ext4_warning(inode->i_sb, "forced shrink of precached extents");
+
 	node = rb_first(&tree->root);
 	while (node != NULL) {
 		es = rb_entry(node, struct extent_status, rb_node);
diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
index e936730..167f4ab8 100644
--- a/fs/ext4/extents_status.h
+++ b/fs/ext4/extents_status.h
@@ -29,16 +29,26 @@
 /*
  * These flags live in the high bits of extent_status.es_pblk
  */
-#define EXTENT_STATUS_WRITTEN	(1ULL << 63)
-#define EXTENT_STATUS_UNWRITTEN (1ULL << 62)
-#define EXTENT_STATUS_DELAYED	(1ULL << 61)
-#define EXTENT_STATUS_HOLE	(1ULL << 60)
+#define ES_SHIFT	60
+
+#define EXTENT_STATUS_WRITTEN	(1 << 3)
+#define EXTENT_STATUS_UNWRITTEN (1 << 2)
+#define EXTENT_STATUS_DELAYED	(1 << 1)
+#define EXTENT_STATUS_HOLE	(1 << 0)
 
 #define EXTENT_STATUS_FLAGS	(EXTENT_STATUS_WRITTEN | \
 				 EXTENT_STATUS_UNWRITTEN | \
 				 EXTENT_STATUS_DELAYED | \
 				 EXTENT_STATUS_HOLE)
 
+#define ES_WRITTEN		(1ULL << 63)
+#define ES_UNWRITTEN		(1ULL << 62)
+#define ES_DELAYED		(1ULL << 61)
+#define ES_HOLE			(1ULL << 60)
+
+#define ES_MASK			(ES_WRITTEN | ES_UNWRITTEN | \
+				 ES_DELAYED | ES_HOLE)
+
 struct ext4_sb_info;
 struct ext4_extent;
 
@@ -60,7 +70,10 @@
 
 extern int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
 				 ext4_lblk_t len, ext4_fsblk_t pblk,
-				 unsigned long long status);
+				 unsigned int status);
+extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,
+				 ext4_lblk_t len, ext4_fsblk_t pblk,
+				 unsigned int status);
 extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
 				 ext4_lblk_t len);
 extern void ext4_es_find_delayed_extent_range(struct inode *inode,
@@ -68,36 +81,35 @@
 					struct extent_status *es);
 extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
 				 struct extent_status *es);
-extern int ext4_es_zeroout(struct inode *inode, struct ext4_extent *ex);
 
 static inline int ext4_es_is_written(struct extent_status *es)
 {
-	return (es->es_pblk & EXTENT_STATUS_WRITTEN) != 0;
+	return (es->es_pblk & ES_WRITTEN) != 0;
 }
 
 static inline int ext4_es_is_unwritten(struct extent_status *es)
 {
-	return (es->es_pblk & EXTENT_STATUS_UNWRITTEN) != 0;
+	return (es->es_pblk & ES_UNWRITTEN) != 0;
 }
 
 static inline int ext4_es_is_delayed(struct extent_status *es)
 {
-	return (es->es_pblk & EXTENT_STATUS_DELAYED) != 0;
+	return (es->es_pblk & ES_DELAYED) != 0;
 }
 
 static inline int ext4_es_is_hole(struct extent_status *es)
 {
-	return (es->es_pblk & EXTENT_STATUS_HOLE) != 0;
+	return (es->es_pblk & ES_HOLE) != 0;
 }
 
-static inline ext4_fsblk_t ext4_es_status(struct extent_status *es)
+static inline unsigned int ext4_es_status(struct extent_status *es)
 {
-	return (es->es_pblk & EXTENT_STATUS_FLAGS);
+	return es->es_pblk >> ES_SHIFT;
 }
 
 static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es)
 {
-	return (es->es_pblk & ~EXTENT_STATUS_FLAGS);
+	return es->es_pblk & ~ES_MASK;
 }
 
 static inline void ext4_es_store_pblock(struct extent_status *es,
@@ -105,19 +117,16 @@
 {
 	ext4_fsblk_t block;
 
-	block = (pb & ~EXTENT_STATUS_FLAGS) |
-		(es->es_pblk & EXTENT_STATUS_FLAGS);
+	block = (pb & ~ES_MASK) | (es->es_pblk & ES_MASK);
 	es->es_pblk = block;
 }
 
 static inline void ext4_es_store_status(struct extent_status *es,
-					unsigned long long status)
+					unsigned int status)
 {
-	ext4_fsblk_t block;
-
-	block = (status & EXTENT_STATUS_FLAGS) |
-		(es->es_pblk & ~EXTENT_STATUS_FLAGS);
-	es->es_pblk = block;
+	es->es_pblk = (((ext4_fsblk_t)
+			(status & EXTENT_STATUS_FLAGS) << ES_SHIFT) |
+		       (es->es_pblk & ~ES_MASK));
 }
 
 extern void ext4_es_register_shrinker(struct ext4_sb_info *sbi);
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 8bf5999..137193f 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -70,18 +70,16 @@
 				       ext4_group_t block_group,
 				       struct ext4_group_desc *gdp)
 {
+	struct ext4_group_info *grp;
 	J_ASSERT_BH(bh, buffer_locked(bh));
 
 	/* If checksum is bad mark all blocks and inodes use to prevent
 	 * allocation, essentially implementing a per-group read-only flag. */
 	if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
 		ext4_error(sb, "Checksum bad for group %u", block_group);
-		ext4_free_group_clusters_set(sb, gdp, 0);
-		ext4_free_inodes_set(sb, gdp, 0);
-		ext4_itable_unused_set(sb, gdp, 0);
-		memset(bh->b_data, 0xff, sb->s_blocksize);
-		ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
-					   EXT4_INODES_PER_GROUP(sb) / 8);
+		grp = ext4_get_group_info(sb, block_group);
+		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
+		set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
 		return 0;
 	}
 
@@ -117,6 +115,7 @@
 	struct ext4_group_desc *desc;
 	struct buffer_head *bh = NULL;
 	ext4_fsblk_t bitmap_blk;
+	struct ext4_group_info *grp;
 
 	desc = ext4_get_group_desc(sb, block_group, NULL);
 	if (!desc)
@@ -185,6 +184,8 @@
 		put_bh(bh);
 		ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
 			   "inode_bitmap = %llu", block_group, bitmap_blk);
+		grp = ext4_get_group_info(sb, block_group);
+		set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
 		return NULL;
 	}
 	ext4_unlock_group(sb, block_group);
@@ -221,6 +222,7 @@
 	struct ext4_super_block *es;
 	struct ext4_sb_info *sbi;
 	int fatal = 0, err, count, cleared;
+	struct ext4_group_info *grp;
 
 	if (!sb) {
 		printk(KERN_ERR "EXT4-fs: %s:%d: inode on "
@@ -266,7 +268,9 @@
 	block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
 	bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
 	bitmap_bh = ext4_read_inode_bitmap(sb, block_group);
-	if (!bitmap_bh)
+	/* Don't bother if the inode bitmap is corrupt. */
+	grp = ext4_get_group_info(sb, block_group);
+	if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) || !bitmap_bh)
 		goto error_return;
 
 	BUFFER_TRACE(bitmap_bh, "get_write_access");
@@ -315,8 +319,10 @@
 		err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
 		if (!fatal)
 			fatal = err;
-	} else
+	} else {
 		ext4_error(sb, "bit already cleared for inode %lu", ino);
+		set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
+	}
 
 error_return:
 	brelse(bitmap_bh);
@@ -625,6 +631,51 @@
 }
 
 /*
+ * In no journal mode, if an inode has recently been deleted, we want
+ * to avoid reusing it until we're reasonably sure the inode table
+ * block has been written back to disk.  (Yes, these values are
+ * somewhat arbitrary...)
+ */
+#define RECENTCY_MIN	5
+#define RECENTCY_DIRTY	30
+
+static int recently_deleted(struct super_block *sb, ext4_group_t group, int ino)
+{
+	struct ext4_group_desc	*gdp;
+	struct ext4_inode	*raw_inode;
+	struct buffer_head	*bh;
+	unsigned long		dtime, now;
+	int	inodes_per_block = EXT4_SB(sb)->s_inodes_per_block;
+	int	offset, ret = 0, recentcy = RECENTCY_MIN;
+
+	gdp = ext4_get_group_desc(sb, group, NULL);
+	if (unlikely(!gdp))
+		return 0;
+
+	bh = sb_getblk(sb, ext4_inode_table(sb, gdp) +
+		       (ino / inodes_per_block));
+	if (unlikely(!bh) || !buffer_uptodate(bh))
+		/*
+		 * If the block is not in the buffer cache, then it
+		 * must have been written out.
+		 */
+		goto out;
+
+	offset = (ino % inodes_per_block) * EXT4_INODE_SIZE(sb);
+	raw_inode = (struct ext4_inode *) (bh->b_data + offset);
+	dtime = le32_to_cpu(raw_inode->i_dtime);
+	now = get_seconds();
+	if (buffer_dirty(bh))
+		recentcy += RECENTCY_DIRTY;
+
+	if (dtime && (dtime < now) && (now < dtime + recentcy))
+		ret = 1;
+out:
+	brelse(bh);
+	return ret;
+}
+
+/*
  * There are two policies for allocating an inode.  If the new inode is
  * a directory, then a forward search is made for a block group with both
  * free space and a low directory-to-inode ratio; if that fails, then of
@@ -652,6 +703,7 @@
 	struct inode *ret;
 	ext4_group_t i;
 	ext4_group_t flex_group;
+	struct ext4_group_info *grp;
 
 	/* Cannot create files in a deleted directory */
 	if (!dir || !dir->i_nlink)
@@ -725,10 +777,22 @@
 			continue;
 		}
 
+		grp = ext4_get_group_info(sb, group);
+		/* Skip groups with already-known suspicious inode tables */
+		if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
+			if (++group == ngroups)
+				group = 0;
+			continue;
+		}
+
 		brelse(inode_bitmap_bh);
 		inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
-		if (!inode_bitmap_bh)
-			goto out;
+		/* Skip groups with suspicious inode tables */
+		if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || !inode_bitmap_bh) {
+			if (++group == ngroups)
+				group = 0;
+			continue;
+		}
 
 repeat_in_this_group:
 		ino = ext4_find_next_zero_bit((unsigned long *)
@@ -741,6 +805,11 @@
 				   "inode=%lu", ino + 1);
 			continue;
 		}
+		if ((EXT4_SB(sb)->s_journal == NULL) &&
+		    recently_deleted(sb, group, ino)) {
+			ino++;
+			goto next_inode;
+		}
 		if (!handle) {
 			BUG_ON(nblocks <= 0);
 			handle = __ext4_journal_start_sb(dir->i_sb, line_no,
@@ -764,6 +833,7 @@
 		ino++;		/* the inode bitmap is zero-based */
 		if (!ret2)
 			goto got; /* we grabbed the inode! */
+next_inode:
 		if (ino < EXT4_INODES_PER_GROUP(sb))
 			goto repeat_in_this_group;
 next_group:
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index 87b30cd..594009f 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -23,7 +23,6 @@
 #include <linux/aio.h>
 #include "ext4_jbd2.h"
 #include "truncate.h"
-#include "ext4_extents.h"	/* Needed for EXT_MAX_BLOCKS */
 
 #include <trace/events/ext4.h>
 
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 123bd81..c79fd7d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -553,7 +553,7 @@
 	}
 	if (retval > 0) {
 		int ret;
-		unsigned long long status;
+		unsigned int status;
 
 		if (unlikely(retval != map->m_len)) {
 			ext4_warning(inode->i_sb,
@@ -653,7 +653,7 @@
 
 	if (retval > 0) {
 		int ret;
-		unsigned long long status;
+		unsigned int status;
 
 		if (unlikely(retval != map->m_len)) {
 			ext4_warning(inode->i_sb,
@@ -973,7 +973,8 @@
 		ext4_journal_stop(handle);
 		goto retry_grab;
 	}
-	wait_on_page_writeback(page);
+	/* In case writeback began while the page was unlocked */
+	wait_for_stable_page(page);
 
 	if (ext4_should_dioread_nolock(inode))
 		ret = __block_write_begin(page, pos, len, ext4_get_block_write);
@@ -1637,7 +1638,7 @@
 		set_buffer_delay(bh);
 	} else if (retval > 0) {
 		int ret;
-		unsigned long long status;
+		unsigned int status;
 
 		if (unlikely(retval != map->m_len)) {
 			ext4_warning(inode->i_sb,
@@ -1894,78 +1895,6 @@
 	return ret;
 }
 
-#define BH_FLAGS ((1 << BH_Unwritten) | (1 << BH_Delay))
-
-/*
- * mballoc gives us at most this number of blocks...
- * XXX: That seems to be only a limitation of ext4_mb_normalize_request().
- * The rest of mballoc seems to handle chunks upto full group size.
- */
-#define MAX_WRITEPAGES_EXTENT_LEN 2048
-
-/*
- * mpage_add_bh_to_extent - try to add bh to extent of blocks to map
- *
- * @mpd - extent of blocks
- * @lblk - logical number of the block in the file
- * @b_state - b_state of the buffer head added
- *
- * the function is used to collect contig. blocks in same state
- */
-static int mpage_add_bh_to_extent(struct mpage_da_data *mpd, ext4_lblk_t lblk,
-				  unsigned long b_state)
-{
-	struct ext4_map_blocks *map = &mpd->map;
-
-	/* Don't go larger than mballoc is willing to allocate */
-	if (map->m_len >= MAX_WRITEPAGES_EXTENT_LEN)
-		return 0;
-
-	/* First block in the extent? */
-	if (map->m_len == 0) {
-		map->m_lblk = lblk;
-		map->m_len = 1;
-		map->m_flags = b_state & BH_FLAGS;
-		return 1;
-	}
-
-	/* Can we merge the block to our big extent? */
-	if (lblk == map->m_lblk + map->m_len &&
-	    (b_state & BH_FLAGS) == map->m_flags) {
-		map->m_len++;
-		return 1;
-	}
-	return 0;
-}
-
-static bool add_page_bufs_to_extent(struct mpage_da_data *mpd,
-				    struct buffer_head *head,
-				    struct buffer_head *bh,
-				    ext4_lblk_t lblk)
-{
-	struct inode *inode = mpd->inode;
-	ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1)
-							>> inode->i_blkbits;
-
-	do {
-		BUG_ON(buffer_locked(bh));
-
-		if (!buffer_dirty(bh) || !buffer_mapped(bh) ||
-		    (!buffer_delay(bh) && !buffer_unwritten(bh)) ||
-		    lblk >= blocks) {
-			/* Found extent to map? */
-			if (mpd->map.m_len)
-				return false;
-			if (lblk >= blocks)
-				return true;
-			continue;
-		}
-		if (!mpage_add_bh_to_extent(mpd, lblk, bh->b_state))
-			return false;
-	} while (lblk++, (bh = bh->b_this_page) != head);
-	return true;
-}
-
 static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
 {
 	int len;
@@ -1986,6 +1915,110 @@
 	return err;
 }
 
+#define BH_FLAGS ((1 << BH_Unwritten) | (1 << BH_Delay))
+
+/*
+ * mballoc gives us at most this number of blocks...
+ * XXX: That seems to be only a limitation of ext4_mb_normalize_request().
+ * The rest of mballoc seems to handle chunks up to full group size.
+ */
+#define MAX_WRITEPAGES_EXTENT_LEN 2048
+
+/*
+ * mpage_add_bh_to_extent - try to add bh to extent of blocks to map
+ *
+ * @mpd - extent of blocks
+ * @lblk - logical number of the block in the file
+ * @bh - buffer head we want to add to the extent
+ *
+ * The function is used to collect contig. blocks in the same state. If the
+ * buffer doesn't require mapping for writeback and we haven't started the
+ * extent of buffers to map yet, the function returns 'true' immediately - the
+ * caller can write the buffer right away. Otherwise the function returns true
+ * if the block has been added to the extent, false if the block couldn't be
+ * added.
+ */
+static bool mpage_add_bh_to_extent(struct mpage_da_data *mpd, ext4_lblk_t lblk,
+				   struct buffer_head *bh)
+{
+	struct ext4_map_blocks *map = &mpd->map;
+
+	/* Buffer that doesn't need mapping for writeback? */
+	if (!buffer_dirty(bh) || !buffer_mapped(bh) ||
+	    (!buffer_delay(bh) && !buffer_unwritten(bh))) {
+		/* So far no extent to map => we write the buffer right away */
+		if (map->m_len == 0)
+			return true;
+		return false;
+	}
+
+	/* First block in the extent? */
+	if (map->m_len == 0) {
+		map->m_lblk = lblk;
+		map->m_len = 1;
+		map->m_flags = bh->b_state & BH_FLAGS;
+		return true;
+	}
+
+	/* Don't go larger than mballoc is willing to allocate */
+	if (map->m_len >= MAX_WRITEPAGES_EXTENT_LEN)
+		return false;
+
+	/* Can we merge the block to our big extent? */
+	if (lblk == map->m_lblk + map->m_len &&
+	    (bh->b_state & BH_FLAGS) == map->m_flags) {
+		map->m_len++;
+		return true;
+	}
+	return false;
+}
+
+/*
+ * mpage_process_page_bufs - submit page buffers for IO or add them to extent
+ *
+ * @mpd - extent of blocks for mapping
+ * @head - the first buffer in the page
+ * @bh - buffer we should start processing from
+ * @lblk - logical number of the block in the file corresponding to @bh
+ *
+ * Walk through page buffers from @bh upto @head (exclusive) and either submit
+ * the page for IO if all buffers in this page were mapped and there's no
+ * accumulated extent of buffers to map or add buffers in the page to the
+ * extent of buffers to map. The function returns 1 if the caller can continue
+ * by processing the next page, 0 if it should stop adding buffers to the
+ * extent to map because we cannot extend it anymore. It can also return value
+ * < 0 in case of error during IO submission.
+ */
+static int mpage_process_page_bufs(struct mpage_da_data *mpd,
+				   struct buffer_head *head,
+				   struct buffer_head *bh,
+				   ext4_lblk_t lblk)
+{
+	struct inode *inode = mpd->inode;
+	int err;
+	ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1)
+							>> inode->i_blkbits;
+
+	do {
+		BUG_ON(buffer_locked(bh));
+
+		if (lblk >= blocks || !mpage_add_bh_to_extent(mpd, lblk, bh)) {
+			/* Found extent to map? */
+			if (mpd->map.m_len)
+				return 0;
+			/* Everything mapped so far and we hit EOF */
+			break;
+		}
+	} while (lblk++, (bh = bh->b_this_page) != head);
+	/* So far everything mapped? Submit the page for IO. */
+	if (mpd->map.m_len == 0) {
+		err = mpage_submit_page(mpd, head->b_page);
+		if (err < 0)
+			return err;
+	}
+	return lblk < blocks;
+}
+
 /*
  * mpage_map_buffers - update buffers corresponding to changed extent and
  *		       submit fully mapped pages for IO
@@ -2007,8 +2040,6 @@
 	struct inode *inode = mpd->inode;
 	struct buffer_head *head, *bh;
 	int bpp_bits = PAGE_CACHE_SHIFT - inode->i_blkbits;
-	ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1)
-							>> inode->i_blkbits;
 	pgoff_t start, end;
 	ext4_lblk_t lblk;
 	sector_t pblock;
@@ -2030,7 +2061,7 @@
 
 			if (page->index > end)
 				break;
-			/* Upto 'end' pages must be contiguous */
+			/* Up to 'end' pages must be contiguous */
 			BUG_ON(page->index != start);
 			bh = head = page_buffers(page);
 			do {
@@ -2043,18 +2074,26 @@
 					 */
 					mpd->map.m_len = 0;
 					mpd->map.m_flags = 0;
-					add_page_bufs_to_extent(mpd, head, bh,
-								lblk);
+					/*
+					 * FIXME: If dioread_nolock supports
+					 * blocksize < pagesize, we need to make
+					 * sure we add size mapped so far to
+					 * io_end->size as the following call
+					 * can submit the page for IO.
+					 */
+					err = mpage_process_page_bufs(mpd, head,
+								      bh, lblk);
 					pagevec_release(&pvec);
-					return 0;
+					if (err > 0)
+						err = 0;
+					return err;
 				}
 				if (buffer_delay(bh)) {
 					clear_buffer_delay(bh);
 					bh->b_blocknr = pblock++;
 				}
 				clear_buffer_unwritten(bh);
-			} while (++lblk < blocks &&
-				 (bh = bh->b_this_page) != head);
+			} while (lblk++, (bh = bh->b_this_page) != head);
 
 			/*
 			 * FIXME: This is going to break if dioread_nolock
@@ -2203,12 +2242,10 @@
 
 	/* Update on-disk size after IO is submitted */
 	disksize = ((loff_t)mpd->first_page) << PAGE_CACHE_SHIFT;
-	if (disksize > i_size_read(inode))
-		disksize = i_size_read(inode);
 	if (disksize > EXT4_I(inode)->i_disksize) {
 		int err2;
 
-		ext4_update_i_disksize(inode, disksize);
+		ext4_wb_update_i_disksize(inode, disksize);
 		err2 = ext4_mark_inode_dirty(handle, inode);
 		if (err2)
 			ext4_error(inode->i_sb,
@@ -2223,7 +2260,7 @@
 /*
  * Calculate the total number of credits to reserve for one writepages
  * iteration. This is called from ext4_writepages(). We map an extent of
- * upto MAX_WRITEPAGES_EXTENT_LEN blocks and then we go on and finish mapping
+ * up to MAX_WRITEPAGES_EXTENT_LEN blocks and then we go on and finish mapping
  * the last partial page. So in total we can map MAX_WRITEPAGES_EXTENT_LEN +
  * bpp - 1 blocks in bpp different extents.
  */
@@ -2323,14 +2360,10 @@
 			lblk = ((ext4_lblk_t)page->index) <<
 				(PAGE_CACHE_SHIFT - blkbits);
 			head = page_buffers(page);
-			if (!add_page_bufs_to_extent(mpd, head, head, lblk))
+			err = mpage_process_page_bufs(mpd, head, head, lblk);
+			if (err <= 0)
 				goto out;
-			/* So far everything mapped? Submit the page for IO. */
-			if (mpd->map.m_len == 0) {
-				err = mpage_submit_page(mpd, page);
-				if (err < 0)
-					goto out;
-			}
+			err = 0;
 
 			/*
 			 * Accumulated enough dirty pages? This doesn't apply
@@ -2414,7 +2447,7 @@
 
 	if (ext4_should_dioread_nolock(inode)) {
 		/*
-		 * We may need to convert upto one extent per block in
+		 * We may need to convert up to one extent per block in
 		 * the page and we may dirty the inode.
 		 */
 		rsv_blocks = 1 + (PAGE_CACHE_SIZE >> inode->i_blkbits);
@@ -2650,7 +2683,7 @@
 		goto retry_grab;
 	}
 	/* In case writeback began while the page was unlocked */
-	wait_on_page_writeback(page);
+	wait_for_stable_page(page);
 
 	ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
 	if (ret < 0) {
@@ -4552,7 +4585,9 @@
 		ext4_journal_stop(handle);
 	}
 
-	if (attr->ia_valid & ATTR_SIZE) {
+	if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
+		handle_t *handle;
+		loff_t oldsize = inode->i_size;
 
 		if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
 			struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
@@ -4560,73 +4595,69 @@
 			if (attr->ia_size > sbi->s_bitmap_maxbytes)
 				return -EFBIG;
 		}
-	}
-
-	if (S_ISREG(inode->i_mode) &&
-	    attr->ia_valid & ATTR_SIZE &&
-	    (attr->ia_size < inode->i_size)) {
-		handle_t *handle;
-
-		handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
-		if (IS_ERR(handle)) {
-			error = PTR_ERR(handle);
-			goto err_out;
-		}
-		if (ext4_handle_valid(handle)) {
-			error = ext4_orphan_add(handle, inode);
-			orphan = 1;
-		}
-		EXT4_I(inode)->i_disksize = attr->ia_size;
-		rc = ext4_mark_inode_dirty(handle, inode);
-		if (!error)
-			error = rc;
-		ext4_journal_stop(handle);
-
-		if (ext4_should_order_data(inode)) {
-			error = ext4_begin_ordered_truncate(inode,
+		if (S_ISREG(inode->i_mode) &&
+		    (attr->ia_size < inode->i_size)) {
+			if (ext4_should_order_data(inode)) {
+				error = ext4_begin_ordered_truncate(inode,
 							    attr->ia_size);
-			if (error) {
-				/* Do as much error cleanup as possible */
-				handle = ext4_journal_start(inode,
-							    EXT4_HT_INODE, 3);
-				if (IS_ERR(handle)) {
-					ext4_orphan_del(NULL, inode);
+				if (error)
 					goto err_out;
-				}
-				ext4_orphan_del(handle, inode);
-				orphan = 0;
-				ext4_journal_stop(handle);
+			}
+			handle = ext4_journal_start(inode, EXT4_HT_INODE, 3);
+			if (IS_ERR(handle)) {
+				error = PTR_ERR(handle);
 				goto err_out;
 			}
-		}
-	}
-
-	if (attr->ia_valid & ATTR_SIZE) {
-		if (attr->ia_size != inode->i_size) {
-			loff_t oldsize = inode->i_size;
-
-			i_size_write(inode, attr->ia_size);
-			/*
-			 * Blocks are going to be removed from the inode. Wait
-			 * for dio in flight.  Temporarily disable
-			 * dioread_nolock to prevent livelock.
-			 */
-			if (orphan) {
-				if (!ext4_should_journal_data(inode)) {
-					ext4_inode_block_unlocked_dio(inode);
-					inode_dio_wait(inode);
-					ext4_inode_resume_unlocked_dio(inode);
-				} else
-					ext4_wait_for_tail_page_commit(inode);
+			if (ext4_handle_valid(handle)) {
+				error = ext4_orphan_add(handle, inode);
+				orphan = 1;
 			}
+			down_write(&EXT4_I(inode)->i_data_sem);
+			EXT4_I(inode)->i_disksize = attr->ia_size;
+			rc = ext4_mark_inode_dirty(handle, inode);
+			if (!error)
+				error = rc;
 			/*
-			 * Truncate pagecache after we've waited for commit
-			 * in data=journal mode to make pages freeable.
+			 * We have to update i_size under i_data_sem together
+			 * with i_disksize to avoid races with writeback code
+			 * running ext4_wb_update_i_disksize().
 			 */
-			truncate_pagecache(inode, oldsize, inode->i_size);
+			if (!error)
+				i_size_write(inode, attr->ia_size);
+			up_write(&EXT4_I(inode)->i_data_sem);
+			ext4_journal_stop(handle);
+			if (error) {
+				ext4_orphan_del(NULL, inode);
+				goto err_out;
+			}
+		} else
+			i_size_write(inode, attr->ia_size);
+
+		/*
+		 * Blocks are going to be removed from the inode. Wait
+		 * for dio in flight.  Temporarily disable
+		 * dioread_nolock to prevent livelock.
+		 */
+		if (orphan) {
+			if (!ext4_should_journal_data(inode)) {
+				ext4_inode_block_unlocked_dio(inode);
+				inode_dio_wait(inode);
+				ext4_inode_resume_unlocked_dio(inode);
+			} else
+				ext4_wait_for_tail_page_commit(inode);
 		}
-		ext4_truncate(inode);
+		/*
+		 * Truncate pagecache after we've waited for commit
+		 * in data=journal mode to make pages freeable.
+		 */
+		truncate_pagecache(inode, oldsize, inode->i_size);
 	}
+	/*
+	 * We want to call ext4_truncate() even if attr->ia_size ==
+	 * inode->i_size for cases like truncation of fallocated space
+	 */
+	if (attr->ia_valid & ATTR_SIZE)
+		ext4_truncate(inode);
 
 	if (!rc) {
 		setattr_copy(inode, attr);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index c0427e2..a569d33 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -17,7 +17,6 @@
 #include <asm/uaccess.h>
 #include "ext4_jbd2.h"
 #include "ext4.h"
-#include "ext4_extents.h"
 
 #define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
 
@@ -624,6 +623,8 @@
 
 		return 0;
 	}
+	case EXT4_IOC_PRECACHE_EXTENTS:
+		return ext4_ext_precache(inode);
 
 	default:
 		return -ENOTTY;
@@ -688,6 +689,7 @@
 	case EXT4_IOC_MOVE_EXT:
 	case FITRIM:
 	case EXT4_IOC_RESIZE_FS:
+	case EXT4_IOC_PRECACHE_EXTENTS:
 		break;
 	default:
 		return -ENOIOCTLCMD;
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 4bbbf13b..a41e3ba 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -751,13 +751,15 @@
 
 	if (free != grp->bb_free) {
 		ext4_grp_locked_error(sb, group, 0, 0,
-				      "%u clusters in bitmap, %u in gd",
+				      "%u clusters in bitmap, %u in gd; "
+				      "block bitmap corrupt.",
 				      free, grp->bb_free);
 		/*
-		 * If we intent to continue, we consider group descritor
+		 * If we intend to continue, we consider group descriptor
 		 * corrupt and update bb_free using bitmap value
 		 */
 		grp->bb_free = free;
+		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
 	}
 	mb_set_largest_free_order(sb, grp);
 
@@ -1398,6 +1400,10 @@
 
 	BUG_ON(last >= (sb->s_blocksize << 3));
 	assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
+	/* Don't bother if the block group is corrupt. */
+	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)))
+		return;
+
 	mb_check_buddy(e4b);
 	mb_free_blocks_double(inode, e4b, first, count);
 
@@ -1423,7 +1429,11 @@
 				      inode ? inode->i_ino : 0,
 				      blocknr,
 				      "freeing already freed block "
-				      "(bit %u)", block);
+				      "(bit %u); block bitmap corrupt.",
+				      block);
+		/* Mark the block group as corrupt. */
+		set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
+			&e4b->bd_info->bb_state);
 		mb_regenerate_buddy(e4b);
 		goto done;
 	}
@@ -1790,6 +1800,11 @@
 	if (err)
 		return err;
 
+	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) {
+		ext4_mb_unload_buddy(e4b);
+		return 0;
+	}
+
 	ext4_lock_group(ac->ac_sb, group);
 	max = mb_find_extent(e4b, ac->ac_g_ex.fe_start,
 			     ac->ac_g_ex.fe_len, &ex);
@@ -1987,6 +2002,9 @@
 	if (cr <= 2 && free < ac->ac_g_ex.fe_len)
 		return 0;
 
+	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp)))
+		return 0;
+
 	/* We only do this if the grp has never been initialized */
 	if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) {
 		int ret = ext4_mb_init_group(ac->ac_sb, group);
@@ -4585,6 +4603,7 @@
 	struct buffer_head *gd_bh;
 	ext4_group_t block_group;
 	struct ext4_sb_info *sbi;
+	struct ext4_inode_info *ei = EXT4_I(inode);
 	struct ext4_buddy e4b;
 	unsigned int count_clusters;
 	int err = 0;
@@ -4673,6 +4692,10 @@
 	overflow = 0;
 	ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
 
+	if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(
+			ext4_get_group_info(sb, block_group))))
+		return;
+
 	/*
 	 * Check to see if we are freeing blocks across a group
 	 * boundary.
@@ -4784,7 +4807,6 @@
 	ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh);
 	ext4_group_desc_csum_set(sb, block_group, gdp);
 	ext4_unlock_group(sb, block_group);
-	percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters);
 
 	if (sbi->s_log_groups_per_flex) {
 		ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
@@ -4792,10 +4814,23 @@
 			     &sbi->s_flex_groups[flex_group].free_clusters);
 	}
 
-	ext4_mb_unload_buddy(&e4b);
-
-	if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
+	if (flags & EXT4_FREE_BLOCKS_RESERVE && ei->i_reserved_data_blocks) {
+		percpu_counter_add(&sbi->s_dirtyclusters_counter,
+				   count_clusters);
+		spin_lock(&ei->i_block_reservation_lock);
+		if (flags & EXT4_FREE_BLOCKS_METADATA)
+			ei->i_reserved_meta_blocks += count_clusters;
+		else
+			ei->i_reserved_data_blocks += count_clusters;
+		spin_unlock(&ei->i_block_reservation_lock);
+		if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
+			dquot_reclaim_block(inode,
+					EXT4_C2B(sbi, count_clusters));
+	} else if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE))
 		dquot_free_block(inode, EXT4_C2B(sbi, count_clusters));
+	percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters);
+
+	ext4_mb_unload_buddy(&e4b);
 
 	/* We dirtied the bitmap block */
 	BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index 49e8bdf..2ae73a8 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -39,7 +39,7 @@
 	newext.ee_block = cpu_to_le32(lb->first_block);
 	newext.ee_len   = cpu_to_le16(lb->last_block - lb->first_block + 1);
 	ext4_ext_store_pblock(&newext, lb->first_pblock);
-	path = ext4_ext_find_extent(inode, lb->first_block, NULL);
+	path = ext4_ext_find_extent(inode, lb->first_block, NULL, 0);
 
 	if (IS_ERR(path)) {
 		retval = PTR_ERR(path);
@@ -494,7 +494,7 @@
 	 * superblock modification.
 	 *
 	 * For the tmp_inode we already have committed the
-	 * trascation that created the inode. Later as and
+	 * transaction that created the inode. Later as and
 	 * when we add extents we extent the journal
 	 */
 	/*
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index e86dddb..7fa4d85 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -37,7 +37,7 @@
 	int ret = 0;
 	struct ext4_ext_path *path;
 
-	path = ext4_ext_find_extent(inode, lblock, *orig_path);
+	path = ext4_ext_find_extent(inode, lblock, *orig_path, EXT4_EX_NOCACHE);
 	if (IS_ERR(path))
 		ret = PTR_ERR(path);
 	else if (path[ext_depth(inode)].p_ext == NULL)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 35f55a0..1bec5a5 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3005,15 +3005,19 @@
 /*
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
+ *
+ * n.b.  old_{dentry,inode) refers to the source dentry/inode
+ * while new_{dentry,inode) refers to the destination dentry/inode
+ * This comes from rename(const char *oldpath, const char *newpath)
  */
 static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 		       struct inode *new_dir, struct dentry *new_dentry)
 {
-	handle_t *handle;
+	handle_t *handle = NULL;
 	struct inode *old_inode, *new_inode;
 	struct buffer_head *old_bh, *new_bh, *dir_bh;
 	struct ext4_dir_entry_2 *old_de, *new_de;
-	int retval, force_da_alloc = 0;
+	int retval;
 	int inlined = 0, new_inlined = 0;
 	struct ext4_dir_entry_2 *parent_de;
 
@@ -3026,14 +3030,6 @@
 	 * in separate transaction */
 	if (new_dentry->d_inode)
 		dquot_initialize(new_dentry->d_inode);
-	handle = ext4_journal_start(old_dir, EXT4_HT_DIR,
-		(2 * EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) +
-		 EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2));
-	if (IS_ERR(handle))
-		return PTR_ERR(handle);
-
-	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
-		ext4_handle_sync(handle);
 
 	old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de, NULL);
 	/*
@@ -3056,6 +3052,18 @@
 			new_bh = NULL;
 		}
 	}
+	if (new_inode && !test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC))
+		ext4_alloc_da_blocks(old_inode);
+
+	handle = ext4_journal_start(old_dir, EXT4_HT_DIR,
+		(2 * EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) +
+		 EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2));
+	if (IS_ERR(handle))
+		return PTR_ERR(handle);
+
+	if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
+		ext4_handle_sync(handle);
+
 	if (S_ISDIR(old_inode->i_mode)) {
 		if (new_inode) {
 			retval = -ENOTEMPTY;
@@ -3186,8 +3194,6 @@
 		ext4_mark_inode_dirty(handle, new_inode);
 		if (!new_inode->i_nlink)
 			ext4_orphan_add(handle, new_inode);
-		if (!test_opt(new_dir->i_sb, NO_AUTO_DA_ALLOC))
-			force_da_alloc = 1;
 	}
 	retval = 0;
 
@@ -3195,9 +3201,8 @@
 	brelse(dir_bh);
 	brelse(old_bh);
 	brelse(new_bh);
-	ext4_journal_stop(handle);
-	if (retval == 0 && force_da_alloc)
-		ext4_alloc_da_blocks(old_inode);
+	if (handle)
+		ext4_journal_stop(handle);
 	return retval;
 }
 
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 5db4f0d..049c8a8 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1130,8 +1130,8 @@
 	Opt_nouid32, Opt_debug, Opt_removed,
 	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
 	Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,
-	Opt_commit, Opt_min_batch_time, Opt_max_batch_time,
-	Opt_journal_dev, Opt_journal_checksum, Opt_journal_async_commit,
+	Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev,
+	Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
 	Opt_data_err_abort, Opt_data_err_ignore,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -1175,6 +1175,7 @@
 	{Opt_min_batch_time, "min_batch_time=%u"},
 	{Opt_max_batch_time, "max_batch_time=%u"},
 	{Opt_journal_dev, "journal_dev=%u"},
+	{Opt_journal_path, "journal_path=%s"},
 	{Opt_journal_checksum, "journal_checksum"},
 	{Opt_journal_async_commit, "journal_async_commit"},
 	{Opt_abort, "abort"},
@@ -1334,6 +1335,7 @@
 #define MOPT_NO_EXT2	0x0100
 #define MOPT_NO_EXT3	0x0200
 #define MOPT_EXT4_ONLY	(MOPT_NO_EXT2 | MOPT_NO_EXT3)
+#define MOPT_STRING	0x0400
 
 static const struct mount_opts {
 	int	token;
@@ -1383,6 +1385,7 @@
 	{Opt_resuid, 0, MOPT_GTE0},
 	{Opt_resgid, 0, MOPT_GTE0},
 	{Opt_journal_dev, 0, MOPT_GTE0},
+	{Opt_journal_path, 0, MOPT_STRING},
 	{Opt_journal_ioprio, 0, MOPT_GTE0},
 	{Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
 	{Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
@@ -1476,7 +1479,7 @@
 		return -1;
 	}
 
-	if (args->from && match_int(args, &arg))
+	if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg))
 		return -1;
 	if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
 		return -1;
@@ -1540,6 +1543,44 @@
 			return -1;
 		}
 		*journal_devnum = arg;
+	} else if (token == Opt_journal_path) {
+		char *journal_path;
+		struct inode *journal_inode;
+		struct path path;
+		int error;
+
+		if (is_remount) {
+			ext4_msg(sb, KERN_ERR,
+				 "Cannot specify journal on remount");
+			return -1;
+		}
+		journal_path = match_strdup(&args[0]);
+		if (!journal_path) {
+			ext4_msg(sb, KERN_ERR, "error: could not dup "
+				"journal device string");
+			return -1;
+		}
+
+		error = kern_path(journal_path, LOOKUP_FOLLOW, &path);
+		if (error) {
+			ext4_msg(sb, KERN_ERR, "error: could not find "
+				"journal device path: error %d", error);
+			kfree(journal_path);
+			return -1;
+		}
+
+		journal_inode = path.dentry->d_inode;
+		if (!S_ISBLK(journal_inode->i_mode)) {
+			ext4_msg(sb, KERN_ERR, "error: journal path %s "
+				"is not a block device", journal_path);
+			path_put(&path);
+			kfree(journal_path);
+			return -1;
+		}
+
+		*journal_devnum = new_encode_dev(journal_inode->i_rdev);
+		path_put(&path);
+		kfree(journal_path);
 	} else if (token == Opt_journal_ioprio) {
 		if (arg > 7) {
 			ext4_msg(sb, KERN_ERR, "Invalid journal IO priority"
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index aef34b1..adbfd66 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -568,6 +568,7 @@
 
 	return sprintf(buf, "%d\n", atomic_read(&cc->fc.num_waiting));
 }
+static DEVICE_ATTR(waiting, S_IFREG | 0400, cuse_class_waiting_show, NULL);
 
 static ssize_t cuse_class_abort_store(struct device *dev,
 				      struct device_attribute *attr,
@@ -578,12 +579,14 @@
 	fuse_abort_conn(&cc->fc);
 	return count;
 }
+static DEVICE_ATTR(abort, S_IFREG | 0200, NULL, cuse_class_abort_store);
 
-static struct device_attribute cuse_class_dev_attrs[] = {
-	__ATTR(waiting, S_IFREG | 0400, cuse_class_waiting_show, NULL),
-	__ATTR(abort, S_IFREG | 0200, NULL, cuse_class_abort_store),
-	{ }
+static struct attribute *cuse_class_dev_attrs[] = {
+	&dev_attr_waiting.attr,
+	&dev_attr_abort.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(cuse_class_dev);
 
 static struct miscdevice cuse_miscdev = {
 	.minor		= MISC_DYNAMIC_MINOR,
@@ -609,7 +612,7 @@
 	if (IS_ERR(cuse_class))
 		return PTR_ERR(cuse_class);
 
-	cuse_class->dev_attrs = cuse_class_dev_attrs;
+	cuse_class->dev_groups = cuse_class_dev_groups;
 
 	rc = misc_register(&cuse_miscdev);
 	if (rc) {
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 9435384..544a809 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -1838,14 +1838,14 @@
 
 	glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM |
 					  WQ_HIGHPRI | WQ_FREEZABLE, 0);
-	if (IS_ERR(glock_workqueue))
-		return PTR_ERR(glock_workqueue);
+	if (!glock_workqueue)
+		return -ENOMEM;
 	gfs2_delete_workqueue = alloc_workqueue("delete_workqueue",
 						WQ_MEM_RECLAIM | WQ_FREEZABLE,
 						0);
-	if (IS_ERR(gfs2_delete_workqueue)) {
+	if (!gfs2_delete_workqueue) {
 		destroy_workqueue(glock_workqueue);
-		return PTR_ERR(gfs2_delete_workqueue);
+		return -ENOMEM;
 	}
 
 	register_shrinker(&glock_shrinker);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 5f2e522..e2e0a90 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -47,7 +47,8 @@
  * None of the buffers should be dirty, locked, or pinned.
  */
 
-static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync)
+static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync,
+			     unsigned int nr_revokes)
 {
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 	struct list_head *head = &gl->gl_ail_list;
@@ -57,7 +58,9 @@
 
 	gfs2_log_lock(sdp);
 	spin_lock(&sdp->sd_ail_lock);
-	list_for_each_entry_safe(bd, tmp, head, bd_ail_gl_list) {
+	list_for_each_entry_safe_reverse(bd, tmp, head, bd_ail_gl_list) {
+		if (nr_revokes == 0)
+			break;
 		bh = bd->bd_bh;
 		if (bh->b_state & b_state) {
 			if (fsync)
@@ -65,6 +68,7 @@
 			gfs2_ail_error(gl, bh);
 		}
 		gfs2_trans_add_revoke(sdp, bd);
+		nr_revokes--;
 	}
 	GLOCK_BUG_ON(gl, !fsync && atomic_read(&gl->gl_ail_count));
 	spin_unlock(&sdp->sd_ail_lock);
@@ -91,7 +95,7 @@
 	WARN_ON_ONCE(current->journal_info);
 	current->journal_info = &tr;
 
-	__gfs2_ail_flush(gl, 0);
+	__gfs2_ail_flush(gl, 0, tr.tr_revokes);
 
 	gfs2_trans_end(sdp);
 	gfs2_log_flush(sdp, NULL);
@@ -101,15 +105,19 @@
 {
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 	unsigned int revokes = atomic_read(&gl->gl_ail_count);
+	unsigned int max_revokes = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / sizeof(u64);
 	int ret;
 
 	if (!revokes)
 		return;
 
-	ret = gfs2_trans_begin(sdp, 0, revokes);
+	while (revokes > max_revokes)
+		max_revokes += (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) / sizeof(u64);
+
+	ret = gfs2_trans_begin(sdp, 0, max_revokes);
 	if (ret)
 		return;
-	__gfs2_ail_flush(gl, fsync);
+	__gfs2_ail_flush(gl, fsync, max_revokes);
 	gfs2_trans_end(sdp);
 	gfs2_log_flush(sdp, NULL);
 }
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index bbb2715..64915ee 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -594,7 +594,7 @@
 		}
 		gfs2_glock_dq_uninit(ghs);
 		if (IS_ERR(d))
-			return PTR_RET(d);
+			return PTR_ERR(d);
 		return error;
 	} else if (error != -ENOENT) {
 		goto fail_gunlock;
@@ -1750,6 +1750,10 @@
 	struct gfs2_holder gh;
 	int ret;
 
+	/* For selinux during lookup */
+	if (gfs2_glock_is_locked_by_me(ip->i_gl))
+		return generic_getxattr(dentry, name, data, size);
+
 	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
 	ret = gfs2_glock_nq(&gh);
 	if (ret == 0) {
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index e04d0e0..7b0f504 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -155,7 +155,7 @@
 		goto fail_wq;
 
 	gfs2_control_wq = alloc_workqueue("gfs2_control",
-			       WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
+					  WQ_UNBOUND | WQ_FREEZABLE, 0);
 	if (!gfs2_control_wq)
 		goto fail_recovery;
 
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 559bec1..cf2fc05 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -343,14 +343,14 @@
 	struct page *page = bh->b_page;
 	__u8 *addr;
 	__u32 csum32;
+	__be32 seq;
 
 	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
 		return;
 
-	sequence = cpu_to_be32(sequence);
+	seq = cpu_to_be32(sequence);
 	addr = kmap_atomic(page);
-	csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
-			     sizeof(sequence));
+	csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
 	csum32 = jbd2_chksum(j, csum32, addr + offset_in_page(bh->b_data),
 			     bh->b_size);
 	kunmap_atomic(addr);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 02c7ad9..5203264 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -130,9 +130,10 @@
 	return sb->s_checksum_type == JBD2_CRC32C_CHKSUM;
 }
 
-static __u32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb)
+static __be32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb)
 {
-	__u32 csum, old_csum;
+	__u32 csum;
+	__be32 old_csum;
 
 	old_csum = sb->s_checksum;
 	sb->s_checksum = 0;
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index d4851464..3929c50 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -178,7 +178,8 @@
 					void *buf)
 {
 	struct jbd2_journal_block_tail *tail;
-	__u32 provided, calculated;
+	__be32 provided;
+	__u32 calculated;
 
 	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
 		return 1;
@@ -190,8 +191,7 @@
 	calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
 	tail->t_checksum = provided;
 
-	provided = be32_to_cpu(provided);
-	return provided == calculated;
+	return provided == cpu_to_be32(calculated);
 }
 
 /*
@@ -381,7 +381,8 @@
 static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
 {
 	struct commit_header *h;
-	__u32 provided, calculated;
+	__be32 provided;
+	__u32 calculated;
 
 	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
 		return 1;
@@ -392,21 +393,20 @@
 	calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
 	h->h_chksum[0] = provided;
 
-	provided = be32_to_cpu(provided);
-	return provided == calculated;
+	return provided == cpu_to_be32(calculated);
 }
 
 static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
 				      void *buf, __u32 sequence)
 {
 	__u32 csum32;
+	__be32 seq;
 
 	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
 		return 1;
 
-	sequence = cpu_to_be32(sequence);
-	csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence,
-			     sizeof(sequence));
+	seq = cpu_to_be32(sequence);
+	csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
 	csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize);
 
 	return tag->t_checksum == cpu_to_be16(csum32);
@@ -808,7 +808,8 @@
 					 void *buf)
 {
 	struct jbd2_journal_revoke_tail *tail;
-	__u32 provided, calculated;
+	__be32 provided;
+	__u32 calculated;
 
 	if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
 		return 1;
@@ -820,8 +821,7 @@
 	calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize);
 	tail->r_checksum = provided;
 
-	provided = be32_to_cpu(provided);
-	return provided == calculated;
+	return provided == cpu_to_be32(calculated);
 }
 
 /* Scan a revoke record, marking all blocks mentioned as revoked. */
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 8743ba9..984c2bb 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -3047,6 +3047,14 @@
 
 		dir_index = (u32) ctx->pos;
 
+		/*
+		 * NFSv4 reserves cookies 1 and 2 for . and .. so the value
+		 * we return to the vfs is one greater than the one we use
+		 * internally.
+		 */
+		if (dir_index)
+			dir_index--;
+
 		if (dir_index > 1) {
 			struct dir_table_slot dirtab_slot;
 
@@ -3086,7 +3094,7 @@
 			if (p->header.flag & BT_INTERNAL) {
 				jfs_err("jfs_readdir: bad index table");
 				DT_PUTPAGE(mp);
-				ctx->pos = -1;
+				ctx->pos = DIREND;
 				return 0;
 			}
 		} else {
@@ -3094,14 +3102,14 @@
 				/*
 				 * self "."
 				 */
-				ctx->pos = 0;
+				ctx->pos = 1;
 				if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
 					return 0;
 			}
 			/*
 			 * parent ".."
 			 */
-			ctx->pos = 1;
+			ctx->pos = 2;
 			if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
 				return 0;
 
@@ -3122,22 +3130,23 @@
 		/*
 		 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
 		 *
-		 * pn = index = 0:	First entry "."
-		 * pn = 0; index = 1:	Second entry ".."
+		 * pn = 0; index = 1:	First entry "."
+		 * pn = 0; index = 2:	Second entry ".."
 		 * pn > 0:		Real entries, pn=1 -> leftmost page
 		 * pn = index = -1:	No more entries
 		 */
 		dtpos = ctx->pos;
-		if (dtpos == 0) {
+		if (dtpos < 2) {
 			/* build "." entry */
+			ctx->pos = 1;
 			if (!dir_emit(ctx, ".", 1, ip->i_ino, DT_DIR))
 				return 0;
-			dtoffset->index = 1;
+			dtoffset->index = 2;
 			ctx->pos = dtpos;
 		}
 
 		if (dtoffset->pn == 0) {
-			if (dtoffset->index == 1) {
+			if (dtoffset->index == 2) {
 				/* build ".." entry */
 				if (!dir_emit(ctx, "..", 2, PARENT(ip), DT_DIR))
 					return 0;
@@ -3228,6 +3237,12 @@
 					}
 					jfs_dirent->position = unique_pos++;
 				}
+				/*
+				 * We add 1 to the index because we may
+				 * use a value of 2 internally, and NFSv4
+				 * doesn't like that.
+				 */
+				jfs_dirent->position++;
 			} else {
 				jfs_dirent->position = dtpos;
 				len = min(d_namleft, DTLHDRDATALEN_LEGACY);
diff --git a/fs/namei.c b/fs/namei.c
index b234e4e..f415c66 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -494,6 +494,50 @@
 	br_read_unlock(&vfsmount_lock);
 }
 
+/*
+ * When we move over from the RCU domain to properly refcounted
+ * long-lived dentries, we need to check the sequence numbers
+ * we got before lookup very carefully.
+ *
+ * We cannot blindly increment a dentry refcount - even if it
+ * is not locked - if it is zero, because it may have gone
+ * through the final d_kill() logic already.
+ *
+ * So for a zero refcount, we need to get the spinlock (which is
+ * safe even for a dead dentry because the de-allocation is
+ * RCU-delayed), and check the sequence count under the lock.
+ *
+ * Once we have checked the sequence count, we know it is live,
+ * and since we hold the spinlock it cannot die from under us.
+ *
+ * In contrast, if the reference count wasn't zero, we can just
+ * increment the lockref without having to take the spinlock.
+ * Even if the sequence number ends up being stale, we haven't
+ * gone through the final dput() and killed the dentry yet.
+ */
+static inline int d_rcu_to_refcount(struct dentry *dentry, seqcount_t *validate, unsigned seq)
+{
+	int gotref;
+
+	gotref = lockref_get_or_lock(&dentry->d_lockref);
+
+	/* Does the sequence number still match? */
+	if (read_seqcount_retry(validate, seq)) {
+		if (gotref)
+			dput(dentry);
+		else
+			spin_unlock(&dentry->d_lock);
+		return -ECHILD;
+	}
+
+	/* Get the ref now, if we couldn't get it originally */
+	if (!gotref) {
+		dentry->d_lockref.count++;
+		spin_unlock(&dentry->d_lock);
+	}
+	return 0;
+}
+
 /**
  * unlazy_walk - try to switch to ref-walk mode.
  * @nd: nameidata pathwalk data
@@ -518,29 +562,28 @@
 				nd->root.dentry != fs->root.dentry)
 			goto err_root;
 	}
-	spin_lock(&parent->d_lock);
+
+	/*
+	 * For a negative lookup, the lookup sequence point is the parents
+	 * sequence point, and it only needs to revalidate the parent dentry.
+	 *
+	 * For a positive lookup, we need to move both the parent and the
+	 * dentry from the RCU domain to be properly refcounted. And the
+	 * sequence number in the dentry validates *both* dentry counters,
+	 * since we checked the sequence number of the parent after we got
+	 * the child sequence number. So we know the parent must still
+	 * be valid if the child sequence number is still valid.
+	 */
 	if (!dentry) {
-		if (!__d_rcu_to_refcount(parent, nd->seq))
-			goto err_parent;
+		if (d_rcu_to_refcount(parent, &parent->d_seq, nd->seq) < 0)
+			goto err_root;
 		BUG_ON(nd->inode != parent->d_inode);
 	} else {
-		if (dentry->d_parent != parent)
+		if (d_rcu_to_refcount(dentry, &dentry->d_seq, nd->seq) < 0)
+			goto err_root;
+		if (d_rcu_to_refcount(parent, &dentry->d_seq, nd->seq) < 0)
 			goto err_parent;
-		spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-		if (!__d_rcu_to_refcount(dentry, nd->seq))
-			goto err_child;
-		/*
-		 * If the sequence check on the child dentry passed, then
-		 * the child has not been removed from its parent. This
-		 * means the parent dentry must be valid and able to take
-		 * a reference at this point.
-		 */
-		BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
-		BUG_ON(!parent->d_count);
-		parent->d_count++;
-		spin_unlock(&dentry->d_lock);
 	}
-	spin_unlock(&parent->d_lock);
 	if (want_root) {
 		path_get(&nd->root);
 		spin_unlock(&fs->lock);
@@ -551,10 +594,8 @@
 	nd->flags &= ~LOOKUP_RCU;
 	return 0;
 
-err_child:
-	spin_unlock(&dentry->d_lock);
 err_parent:
-	spin_unlock(&parent->d_lock);
+	dput(dentry);
 err_root:
 	if (want_root)
 		spin_unlock(&fs->lock);
@@ -585,14 +626,11 @@
 		nd->flags &= ~LOOKUP_RCU;
 		if (!(nd->flags & LOOKUP_ROOT))
 			nd->root.mnt = NULL;
-		spin_lock(&dentry->d_lock);
-		if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
-			spin_unlock(&dentry->d_lock);
+
+		if (d_rcu_to_refcount(dentry, &dentry->d_seq, nd->seq) < 0) {
 			unlock_rcu_walk();
 			return -ECHILD;
 		}
-		BUG_ON(nd->inode != dentry->d_inode);
-		spin_unlock(&dentry->d_lock);
 		mntget(nd->path.mnt);
 		unlock_rcu_walk();
 	}
@@ -3509,7 +3547,7 @@
 {
 	shrink_dcache_parent(dentry);
 	spin_lock(&dentry->d_lock);
-	if (dentry->d_count == 1)
+	if (dentry->d_lockref.count == 1)
 		__d_drop(dentry);
 	spin_unlock(&dentry->d_lock);
 }
@@ -3853,11 +3891,15 @@
 	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
 		return -EINVAL;
 	/*
-	 * Using empty names is equivalent to using AT_SYMLINK_FOLLOW
-	 * on /proc/self/fd/<fd>.
+	 * To use null names we require CAP_DAC_READ_SEARCH
+	 * This ensures that not everyone will be able to create
+	 * handlink using the passed filedescriptor.
 	 */
-	if (flags & AT_EMPTY_PATH)
+	if (flags & AT_EMPTY_PATH) {
+		if (!capable(CAP_DAC_READ_SEARCH))
+			return -ENOENT;
 		how = LOOKUP_EMPTY;
+	}
 
 	if (flags & AT_SYMLINK_FOLLOW)
 		how |= LOOKUP_FOLLOW;
diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c
index dc9a913..2d8be51 100644
--- a/fs/nilfs2/segbuf.c
+++ b/fs/nilfs2/segbuf.c
@@ -345,8 +345,7 @@
 
 	if (err == -EOPNOTSUPP) {
 		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
-		bio_put(bio);
-		/* to be detected by submit_seg_bio() */
+		/* to be detected by nilfs_segbuf_submit_bio() */
 	}
 
 	if (!uptodate)
@@ -377,12 +376,12 @@
 	bio->bi_private = segbuf;
 	bio_get(bio);
 	submit_bio(mode, bio);
+	segbuf->sb_nbio++;
 	if (bio_flagged(bio, BIO_EOPNOTSUPP)) {
 		bio_put(bio);
 		err = -EOPNOTSUPP;
 		goto failed;
 	}
-	segbuf->sb_nbio++;
 	bio_put(bio);
 
 	wi->bio = NULL;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 854d809..121da2d 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -1022,7 +1022,7 @@
 	struct inode *inode = NULL;
 	struct ocfs2_super *osb = NULL;
 	struct buffer_head *bh = NULL;
-	char nodestr[8];
+	char nodestr[12];
 	struct ocfs2_blockcheck_stats stats;
 
 	trace_ocfs2_fill_super(sb, data, silent);
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 94441a4..737e156 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -271,7 +271,7 @@
 		de = next;
 	} while (de);
 	spin_unlock(&proc_subdir_lock);
-	return 0;
+	return 1;
 }
 
 int proc_readdir(struct file *file, struct dir_context *ctx)
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 229e366..e0a790d 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -205,7 +205,9 @@
 static int proc_root_readdir(struct file *file, struct dir_context *ctx)
 {
 	if (ctx->pos < FIRST_PROCESS_ENTRY) {
-		proc_readdir(file, ctx);
+		int error = proc_readdir(file, ctx);
+		if (unlikely(error <= 0))
+			return error;
 		ctx->pos = FIRST_PROCESS_ENTRY;
 	}
 
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index ca71db6..983d951 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,6 +1,8 @@
 config PSTORE
 	bool "Persistent store support"
 	default n
+	select ZLIB_DEFLATE
+	select ZLIB_INFLATE
 	help
 	   This option enables generic access to platform level
 	   persistent storage via "pstore" filesystem that can
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 71bf5f4..1282384 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -275,8 +275,8 @@
  * Set the mtime & ctime to the date that this record was originally stored.
  */
 int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
-		  char *data, size_t size, struct timespec time,
-		  struct pstore_info *psi)
+		  char *data, bool compressed, size_t size,
+		  struct timespec time, struct pstore_info *psi)
 {
 	struct dentry		*root = pstore_sb->s_root;
 	struct dentry		*dentry;
@@ -315,7 +315,8 @@
 
 	switch (type) {
 	case PSTORE_TYPE_DMESG:
-		sprintf(name, "dmesg-%s-%lld", psname, id);
+		sprintf(name, "dmesg-%s-%lld%s", psname, id,
+						compressed ? ".enc.z" : "");
 		break;
 	case PSTORE_TYPE_CONSOLE:
 		sprintf(name, "console-%s", psname);
@@ -345,9 +346,8 @@
 
 	mutex_lock(&root->d_inode->i_mutex);
 
-	rc = -ENOSPC;
 	dentry = d_alloc_name(root, name);
-	if (IS_ERR(dentry))
+	if (!dentry)
 		goto fail_lockedalloc;
 
 	memcpy(private->data, data, size);
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 937d820..3b3d305 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -50,8 +50,9 @@
 extern void	pstore_set_kmsg_bytes(int);
 extern void	pstore_get_records(int);
 extern int	pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
-			      int count, char *data, size_t size,
-			      struct timespec time, struct pstore_info *psi);
+			      int count, char *data, bool compressed,
+			      size_t size, struct timespec time,
+			      struct pstore_info *psi);
 extern int	pstore_is_mounted(void);
 
 #endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 422962a..4ffb7ab 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -26,6 +26,7 @@
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/pstore.h>
+#include <linux/zlib.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
@@ -65,6 +66,15 @@
 
 static char *backend;
 
+/* Compression parameters */
+#define COMPR_LEVEL 6
+#define WINDOW_BITS 12
+#define MEM_LEVEL 4
+static struct z_stream_s stream;
+
+static char *big_oops_buf;
+static size_t big_oops_buf_sz;
+
 /* How much of the console log to snapshot */
 static unsigned long kmsg_bytes = 10240;
 
@@ -117,6 +127,121 @@
 }
 EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
 
+/* Derived from logfs_compress() */
+static int pstore_compress(const void *in, void *out, size_t inlen,
+							size_t outlen)
+{
+	int err, ret;
+
+	ret = -EIO;
+	err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
+						MEM_LEVEL, Z_DEFAULT_STRATEGY);
+	if (err != Z_OK)
+		goto error;
+
+	stream.next_in = in;
+	stream.avail_in = inlen;
+	stream.total_in = 0;
+	stream.next_out = out;
+	stream.avail_out = outlen;
+	stream.total_out = 0;
+
+	err = zlib_deflate(&stream, Z_FINISH);
+	if (err != Z_STREAM_END)
+		goto error;
+
+	err = zlib_deflateEnd(&stream);
+	if (err != Z_OK)
+		goto error;
+
+	if (stream.total_out >= stream.total_in)
+		goto error;
+
+	ret = stream.total_out;
+error:
+	return ret;
+}
+
+/* Derived from logfs_uncompress */
+static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
+{
+	int err, ret;
+
+	ret = -EIO;
+	err = zlib_inflateInit(&stream);
+	if (err != Z_OK)
+		goto error;
+
+	stream.next_in = in;
+	stream.avail_in = inlen;
+	stream.total_in = 0;
+	stream.next_out = out;
+	stream.avail_out = outlen;
+	stream.total_out = 0;
+
+	err = zlib_inflate(&stream, Z_FINISH);
+	if (err != Z_STREAM_END)
+		goto error;
+
+	err = zlib_inflateEnd(&stream);
+	if (err != Z_OK)
+		goto error;
+
+	ret = stream.total_out;
+error:
+	return ret;
+}
+
+static void allocate_buf_for_compression(void)
+{
+	size_t size;
+
+	big_oops_buf_sz = (psinfo->bufsize * 100) / 45;
+	big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
+	if (big_oops_buf) {
+		size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
+			zlib_inflate_workspacesize());
+		stream.workspace = kmalloc(size, GFP_KERNEL);
+		if (!stream.workspace) {
+			pr_err("pstore: No memory for compression workspace; "
+				"skipping compression\n");
+			kfree(big_oops_buf);
+			big_oops_buf = NULL;
+		}
+	} else {
+		pr_err("No memory for uncompressed data; "
+			"skipping compression\n");
+		stream.workspace = NULL;
+	}
+
+}
+
+/*
+ * Called when compression fails, since the printk buffer
+ * would be fetched for compression calling it again when
+ * compression fails would have moved the iterator of
+ * printk buffer which results in fetching old contents.
+ * Copy the recent messages from big_oops_buf to psinfo->buf
+ */
+static size_t copy_kmsg_to_buffer(int hsize, size_t len)
+{
+	size_t total_len;
+	size_t diff;
+
+	total_len = hsize + len;
+
+	if (total_len > psinfo->bufsize) {
+		diff = total_len - psinfo->bufsize + hsize;
+		memcpy(psinfo->buf, big_oops_buf, hsize);
+		memcpy(psinfo->buf + hsize, big_oops_buf + diff,
+					psinfo->bufsize - hsize);
+		total_len = psinfo->bufsize;
+	} else
+		memcpy(psinfo->buf, big_oops_buf, total_len);
+
+	return total_len;
+}
+
 /*
  * callback from kmsg_dump. (s2,l2) has the most recently
  * written bytes, older bytes are in (s1,l1). Save as much
@@ -148,22 +273,56 @@
 		char *dst;
 		unsigned long size;
 		int hsize;
+		int zipped_len = -1;
 		size_t len;
+		bool compressed;
+		size_t total_len;
 
-		dst = psinfo->buf;
-		hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part);
-		size = psinfo->bufsize - hsize;
-		dst += hsize;
+		if (big_oops_buf) {
+			dst = big_oops_buf;
+			hsize = sprintf(dst, "%s#%d Part%d\n", why,
+							oopscount, part);
+			size = big_oops_buf_sz - hsize;
 
-		if (!kmsg_dump_get_buffer(dumper, true, dst, size, &len))
-			break;
+			if (!kmsg_dump_get_buffer(dumper, true, dst + hsize,
+								size, &len))
+				break;
+
+			zipped_len = pstore_compress(dst, psinfo->buf,
+						hsize + len, psinfo->bufsize);
+
+			if (zipped_len > 0) {
+				compressed = true;
+				total_len = zipped_len;
+			} else {
+				pr_err("pstore: compression failed for Part %d"
+					" returned %d\n", part, zipped_len);
+				pr_err("pstore: Capture uncompressed"
+					" oops/panic report of Part %d\n", part);
+				compressed = false;
+				total_len = copy_kmsg_to_buffer(hsize, len);
+			}
+		} else {
+			dst = psinfo->buf;
+			hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount,
+									part);
+			size = psinfo->bufsize - hsize;
+			dst += hsize;
+
+			if (!kmsg_dump_get_buffer(dumper, true, dst,
+								size, &len))
+				break;
+
+			compressed = false;
+			total_len = hsize + len;
+		}
 
 		ret = psinfo->write(PSTORE_TYPE_DMESG, reason, &id, part,
-				    oopscount, hsize, hsize + len, psinfo);
+				    oopscount, compressed, total_len, psinfo);
 		if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted())
 			pstore_new_entry = 1;
 
-		total += hsize + len;
+		total += total_len;
 		part++;
 	}
 	if (pstore_cannot_block_path(reason)) {
@@ -221,10 +380,10 @@
 static int pstore_write_compat(enum pstore_type_id type,
 			       enum kmsg_dump_reason reason,
 			       u64 *id, unsigned int part, int count,
-			       size_t hsize, size_t size,
+			       bool compressed, size_t size,
 			       struct pstore_info *psi)
 {
-	return psi->write_buf(type, reason, id, part, psinfo->buf, hsize,
+	return psi->write_buf(type, reason, id, part, psinfo->buf, compressed,
 			     size, psi);
 }
 
@@ -261,6 +420,8 @@
 		return -EINVAL;
 	}
 
+	allocate_buf_for_compression();
+
 	if (pstore_is_mounted())
 		pstore_get_records(0);
 
@@ -297,6 +458,8 @@
 	enum pstore_type_id	type;
 	struct timespec		time;
 	int			failed = 0, rc;
+	bool			compressed;
+	int			unzipped_len = -1;
 
 	if (!psi)
 		return;
@@ -305,11 +468,32 @@
 	if (psi->open && psi->open(psi))
 		goto out;
 
-	while ((size = psi->read(&id, &type, &count, &time, &buf, psi)) > 0) {
+	while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
+				psi)) > 0) {
+		if (compressed && (type == PSTORE_TYPE_DMESG)) {
+			if (big_oops_buf)
+				unzipped_len = pstore_decompress(buf,
+							big_oops_buf, size,
+							big_oops_buf_sz);
+
+			if (unzipped_len > 0) {
+				buf = big_oops_buf;
+				size = unzipped_len;
+				compressed = false;
+			} else {
+				pr_err("pstore: decompression failed;"
+					"returned %d\n", unzipped_len);
+				compressed = true;
+			}
+		}
 		rc = pstore_mkfile(type, psi->name, id, count, buf,
-				  (size_t)size, time, psi);
-		kfree(buf);
-		buf = NULL;
+				  compressed, (size_t)size, time, psi);
+		if (unzipped_len < 0) {
+			/* Free buffer other than big oops */
+			kfree(buf);
+			buf = NULL;
+		} else
+			unzipped_len = -1;
 		if (rc && (rc != -EEXIST || !quiet))
 			failed++;
 	}
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index a6119f9..fa8cef2 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -131,9 +131,31 @@
 	return prz;
 }
 
+static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
+				  bool *compressed)
+{
+	char data_type;
+
+	if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
+			&time->tv_sec, &time->tv_nsec, &data_type) == 3) {
+		if (data_type == 'C')
+			*compressed = true;
+		else
+			*compressed = false;
+	} else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
+			&time->tv_sec, &time->tv_nsec) == 2) {
+			*compressed = false;
+	} else {
+		time->tv_sec = 0;
+		time->tv_nsec = 0;
+		*compressed = false;
+	}
+}
+
 static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 				   int *count, struct timespec *time,
-				   char **buf, struct pstore_info *psi)
+				   char **buf, bool *compressed,
+				   struct pstore_info *psi)
 {
 	ssize_t size;
 	ssize_t ecc_notice_size;
@@ -152,10 +174,6 @@
 	if (!prz)
 		return 0;
 
-	/* TODO(kees): Bogus time for the moment. */
-	time->tv_sec = 0;
-	time->tv_nsec = 0;
-
 	size = persistent_ram_old_size(prz);
 
 	/* ECC correction notice */
@@ -166,12 +184,14 @@
 		return -ENOMEM;
 
 	memcpy(*buf, persistent_ram_old(prz), size);
+	ramoops_read_kmsg_hdr(*buf, time, compressed);
 	persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
 
 	return size + ecc_notice_size;
 }
 
-static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
+static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
+				     bool compressed)
 {
 	char *hdr;
 	struct timespec timestamp;
@@ -182,8 +202,9 @@
 		timestamp.tv_sec = 0;
 		timestamp.tv_nsec = 0;
 	}
-	hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
-		(long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000));
+	hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
+		(long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000),
+		compressed ? 'C' : 'D');
 	WARN_ON_ONCE(!hdr);
 	len = hdr ? strlen(hdr) : 0;
 	persistent_ram_write(prz, hdr, len);
@@ -196,7 +217,7 @@
 					    enum kmsg_dump_reason reason,
 					    u64 *id, unsigned int part,
 					    const char *buf,
-					    size_t hsize, size_t size,
+					    bool compressed, size_t size,
 					    struct pstore_info *psi)
 {
 	struct ramoops_context *cxt = psi->data;
@@ -242,7 +263,7 @@
 
 	prz = cxt->przs[cxt->dump_write_cnt];
 
-	hlen = ramoops_write_kmsg_hdr(prz);
+	hlen = ramoops_write_kmsg_hdr(prz, compressed);
 	if (size + hlen > prz->buffer_size)
 		size = prz->buffer_size - hlen;
 	persistent_ram_write(prz, buf, size);
@@ -400,11 +421,11 @@
 		goto fail_out;
 	}
 
-	if (!is_power_of_2(pdata->record_size))
+	if (pdata->record_size && !is_power_of_2(pdata->record_size))
 		pdata->record_size = rounddown_pow_of_two(pdata->record_size);
-	if (!is_power_of_2(pdata->console_size))
+	if (pdata->console_size && !is_power_of_2(pdata->console_size))
 		pdata->console_size = rounddown_pow_of_two(pdata->console_size);
-	if (!is_power_of_2(pdata->ftrace_size))
+	if (pdata->ftrace_size && !is_power_of_2(pdata->ftrace_size))
 		pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
 
 	cxt->dump_read_cnt = 0;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index fbad622..9a702e19 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1094,6 +1094,14 @@
 	dquot->dq_dqb.dqb_rsvspace -= number;
 }
 
+static void dquot_reclaim_reserved_space(struct dquot *dquot, qsize_t number)
+{
+	if (WARN_ON_ONCE(dquot->dq_dqb.dqb_curspace < number))
+		number = dquot->dq_dqb.dqb_curspace;
+	dquot->dq_dqb.dqb_rsvspace += number;
+	dquot->dq_dqb.dqb_curspace -= number;
+}
+
 static inline
 void dquot_free_reserved_space(struct dquot *dquot, qsize_t number)
 {
@@ -1528,6 +1536,15 @@
 }
 EXPORT_SYMBOL(inode_claim_rsv_space);
 
+void inode_reclaim_rsv_space(struct inode *inode, qsize_t number)
+{
+	spin_lock(&inode->i_lock);
+	*inode_reserved_space(inode) += number;
+	__inode_sub_bytes(inode, number);
+	spin_unlock(&inode->i_lock);
+}
+EXPORT_SYMBOL(inode_reclaim_rsv_space);
+
 void inode_sub_rsv_space(struct inode *inode, qsize_t number)
 {
 	spin_lock(&inode->i_lock);
@@ -1702,6 +1719,35 @@
 EXPORT_SYMBOL(dquot_claim_space_nodirty);
 
 /*
+ * Convert allocated space back to in-memory reserved quotas
+ */
+void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
+{
+	int cnt;
+
+	if (!dquot_active(inode)) {
+		inode_reclaim_rsv_space(inode, number);
+		return;
+	}
+
+	down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	spin_lock(&dq_data_lock);
+	/* Claim reserved quotas to allocated quotas */
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (inode->i_dquot[cnt])
+			dquot_reclaim_reserved_space(inode->i_dquot[cnt],
+						     number);
+	}
+	/* Update inode bytes */
+	inode_reclaim_rsv_space(inode, number);
+	spin_unlock(&dq_data_lock);
+	mark_all_dquot_dirty(inode->i_dquot);
+	up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+	return;
+}
+EXPORT_SYMBOL(dquot_reclaim_space_nodirty);
+
+/*
  * This operation can block, but only after everything is updated
  */
 void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
diff --git a/fs/stat.c b/fs/stat.c
index 04ce1ac..d0ea7ef 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -447,9 +447,8 @@
 
 EXPORT_SYMBOL(inode_add_bytes);
 
-void inode_sub_bytes(struct inode *inode, loff_t bytes)
+void __inode_sub_bytes(struct inode *inode, loff_t bytes)
 {
-	spin_lock(&inode->i_lock);
 	inode->i_blocks -= bytes >> 9;
 	bytes &= 511;
 	if (inode->i_bytes < bytes) {
@@ -457,6 +456,14 @@
 		inode->i_bytes += 512;
 	}
 	inode->i_bytes -= bytes;
+}
+
+EXPORT_SYMBOL(__inode_sub_bytes);
+
+void inode_sub_bytes(struct inode *inode, loff_t bytes)
+{
+	spin_lock(&inode->i_lock);
+	__inode_sub_bytes(inode, bytes);
 	spin_unlock(&inode->i_lock);
 }
 
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 15c68f9..c590cab 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -22,8 +22,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/mm.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "sysfs.h"
 
@@ -391,7 +390,7 @@
 	return rc;
 }
 
-static int open(struct inode * inode, struct file * file)
+static int open(struct inode *inode, struct file *file)
 {
 	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
 	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
@@ -435,7 +434,7 @@
 	return error;
 }
 
-static int release(struct inode * inode, struct file * file)
+static int release(struct inode *inode, struct file *file)
 {
 	struct bin_buffer *bb = file->private_data;
 
@@ -481,7 +480,6 @@
  *	@kobj:	object.
  *	@attr:	attribute descriptor.
  */
-
 int sysfs_create_bin_file(struct kobject *kobj,
 			  const struct bin_attribute *attr)
 {
@@ -489,19 +487,16 @@
 
 	return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
 }
-
+EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
 
 /**
  *	sysfs_remove_bin_file - remove binary file for object.
  *	@kobj:	object.
  *	@attr:	attribute descriptor.
  */
-
 void sysfs_remove_bin_file(struct kobject *kobj,
 			   const struct bin_attribute *attr)
 {
 	sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
 }
-
-EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_bin_file);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index e068e74..99ec5b4 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -46,7 +46,7 @@
 	unsigned int len = strlen(name);
 	while (len--)
 		hash = partial_name_hash(*name++, hash);
-	hash = ( end_name_hash(hash) ^ hash_ptr( (void *)ns, 31 ) );
+	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)
@@ -258,7 +258,7 @@
 	spin_unlock(&sysfs_ino_lock);
 }
 
-void release_sysfs_dirent(struct sysfs_dirent * sd)
+void release_sysfs_dirent(struct sysfs_dirent *sd)
 {
 	struct sysfs_dirent *parent_sd;
 
@@ -451,7 +451,7 @@
 
 	if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) {
 		WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
-			sysfs_ns_type(acxt->parent_sd)? "required": "invalid",
+			sysfs_ns_type(acxt->parent_sd) ? "required" : "invalid",
 			acxt->parent_sd->s_name, sd->s_name);
 		return -EINVAL;
 	}
@@ -619,7 +619,7 @@
 
 	if (!!sysfs_ns_type(parent_sd) != !!ns) {
 		WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
-			sysfs_ns_type(parent_sd)? "required": "invalid",
+			sysfs_ns_type(parent_sd) ? "required" : "invalid",
 			parent_sd->s_name, name);
 		return NULL;
 	}
@@ -674,7 +674,7 @@
 	enum kobj_ns_type type, const void *ns, const char *name,
 	struct sysfs_dirent **p_sd)
 {
-	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
+	umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
 	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
 	int rc;
@@ -735,9 +735,9 @@
 
 /**
  *	sysfs_create_dir - create a directory for an object.
- *	@kobj:		object we're creating directory for. 
+ *	@kobj:		object we're creating directory for.
  */
-int sysfs_create_dir(struct kobject * kobj)
+int sysfs_create_dir(struct kobject *kobj)
 {
 	enum kobj_ns_type type;
 	struct sysfs_dirent *parent_sd, *sd;
@@ -764,8 +764,8 @@
 	return error;
 }
 
-static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
-				unsigned int flags)
+static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry,
+				   unsigned int flags)
 {
 	struct dentry *ret = NULL;
 	struct dentry *parent = dentry->d_parent;
@@ -857,7 +857,7 @@
  *	what used to be sysfs_rmdir() below, instead of calling separately.
  */
 
-void sysfs_remove_dir(struct kobject * kobj)
+void sysfs_remove_dir(struct kobject *kobj)
 {
 	struct sysfs_dirent *sd = kobj->sd;
 
@@ -896,7 +896,9 @@
 		sd->s_name = new_name;
 	}
 
-	/* Move to the appropriate place in the appropriate directories rbtree. */
+	/*
+	 * Move to the appropriate place in the appropriate directories rbtree.
+	 */
 	sysfs_unlink_sibling(sd);
 	sysfs_get(new_parent_sd);
 	sysfs_put(sd->s_parent);
@@ -988,20 +990,21 @@
 	struct sysfs_dirent *parent_sd,	ino_t ino, struct sysfs_dirent *pos)
 {
 	pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
-	if (pos) do {
-		struct rb_node *node = rb_next(&pos->s_rb);
-		if (!node)
-			pos = NULL;
-		else
-			pos = to_sysfs_dirent(node);
-	} while (pos && pos->s_ns != ns);
+	if (pos)
+		do {
+			struct rb_node *node = rb_next(&pos->s_rb);
+			if (!node)
+				pos = NULL;
+			else
+				pos = to_sysfs_dirent(node);
+		} while (pos && pos->s_ns != ns);
 	return pos;
 }
 
 static int sysfs_readdir(struct file *file, struct dir_context *ctx)
 {
 	struct dentry *dentry = file->f_path.dentry;
-	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+	struct sysfs_dirent *parent_sd = dentry->d_fsdata;
 	struct sysfs_dirent *pos = file->private_data;
 	enum kobj_ns_type type;
 	const void *ns;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index d2bb7ed..15ef5eb 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -20,7 +20,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/limits.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "sysfs.h"
 
@@ -45,8 +45,8 @@
 struct sysfs_buffer {
 	size_t			count;
 	loff_t			pos;
-	char			* page;
-	const struct sysfs_ops	* ops;
+	char			*page;
+	const struct sysfs_ops	*ops;
 	struct mutex		mutex;
 	int			needs_read_fill;
 	int			event;
@@ -59,16 +59,16 @@
  *	@buffer:	data buffer for file.
  *
  *	Allocate @buffer->page, if it hasn't been already, then call the
- *	kobject's show() method to fill the buffer with this attribute's 
- *	data. 
+ *	kobject's show() method to fill the buffer with this attribute's
+ *	data.
  *	This is called only once, on the file's first read unless an error
  *	is returned.
  */
-static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
+static int fill_read_buffer(struct dentry *dentry, struct sysfs_buffer *buffer)
 {
 	struct sysfs_dirent *attr_sd = dentry->d_fsdata;
 	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
-	const struct sysfs_ops * ops = buffer->ops;
+	const struct sysfs_ops *ops = buffer->ops;
 	int ret = 0;
 	ssize_t count;
 
@@ -106,7 +106,7 @@
 }
 
 /**
- *	sysfs_read_file - read an attribute. 
+ *	sysfs_read_file - read an attribute.
  *	@file:	file pointer.
  *	@buf:	buffer to fill.
  *	@count:	number of bytes to read.
@@ -127,12 +127,12 @@
 static ssize_t
 sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 {
-	struct sysfs_buffer * buffer = file->private_data;
+	struct sysfs_buffer *buffer = file->private_data;
 	ssize_t retval = 0;
 
 	mutex_lock(&buffer->mutex);
 	if (buffer->needs_read_fill || *ppos == 0) {
-		retval = fill_read_buffer(file->f_path.dentry,buffer);
+		retval = fill_read_buffer(file->f_path.dentry, buffer);
 		if (retval)
 			goto out;
 	}
@@ -154,9 +154,8 @@
  *	Allocate @buffer->page if it hasn't been already, then
  *	copy the user-supplied buffer into it.
  */
-
-static int 
-fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t count)
+static int fill_write_buffer(struct sysfs_buffer *buffer,
+			     const char __user *buf, size_t count)
 {
 	int error;
 
@@ -167,7 +166,7 @@
 
 	if (count >= PAGE_SIZE)
 		count = PAGE_SIZE - 1;
-	error = copy_from_user(buffer->page,buf,count);
+	error = copy_from_user(buffer->page, buf, count);
 	buffer->needs_read_fill = 1;
 	/* if buf is assumed to contain a string, terminate it by \0,
 	   so e.g. sscanf() can scan the string easily */
@@ -183,16 +182,15 @@
  *	@count:		number of bytes
  *
  *	Get the correct pointers for the kobject and the attribute we're
- *	dealing with, then call the store() method for the attribute, 
+ *	dealing with, then call the store() method for the attribute,
  *	passing the buffer that we acquired in fill_write_buffer().
  */
-
-static int
-flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
+static int flush_write_buffer(struct dentry *dentry,
+			      struct sysfs_buffer *buffer, size_t count)
 {
 	struct sysfs_dirent *attr_sd = dentry->d_fsdata;
 	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
-	const struct sysfs_ops * ops = buffer->ops;
+	const struct sysfs_ops *ops = buffer->ops;
 	int rc;
 
 	/* need attr_sd for attr and ops, its parent for kobj */
@@ -219,15 +217,14 @@
  *	then push it to the kobject in flush_write_buffer().
  *	There is no easy way for us to know if userspace is only doing a partial
  *	write, so we don't support them. We expect the entire buffer to come
- *	on the first write. 
+ *	on the first write.
  *	Hint: if you're writing a value, first read the file, modify only the
- *	the value you're changing, then write entire buffer back. 
+ *	the value you're changing, then write entire buffer back.
  */
-
-static ssize_t
-sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+static ssize_t sysfs_write_file(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
 {
-	struct sysfs_buffer * buffer = file->private_data;
+	struct sysfs_buffer *buffer = file->private_data;
 	ssize_t len;
 
 	mutex_lock(&buffer->mutex);
@@ -339,13 +336,14 @@
 	if (kobj->ktype && kobj->ktype->sysfs_ops)
 		ops = kobj->ktype->sysfs_ops;
 	else {
-		WARN(1, KERN_ERR "missing sysfs attribute operations for "
-		       "kobject: %s\n", kobject_name(kobj));
+		WARN(1, KERN_ERR
+		     "missing sysfs attribute operations for kobject: %s\n",
+		     kobject_name(kobj));
 		goto err_out;
 	}
 
 	/* File needs write support.
-	 * The inode's perms must say it's ok, 
+	 * The inode's perms must say it's ok,
 	 * and we must have a store method.
 	 */
 	if (file->f_mode & FMODE_WRITE) {
@@ -420,7 +418,7 @@
  */
 static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
 {
-	struct sysfs_buffer * buffer = filp->private_data;
+	struct sysfs_buffer *buffer = filp->private_data;
 	struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
 	struct sysfs_open_dirent *od = attr_sd->s_attr.open;
 
@@ -518,8 +516,9 @@
 	ns = ops->namespace(kobj, attr);
 out:
 	if (err) {
-		WARN(1, KERN_ERR "missing sysfs namespace attribute operation for "
-		     "kobject: %s\n", kobject_name(kobj));
+		WARN(1, KERN_ERR
+		     "missing sysfs namespace attribute operation for kobject: %s\n",
+		     kobject_name(kobj));
 	}
 	*pns = ns;
 	return err;
@@ -566,17 +565,17 @@
 
 /**
  *	sysfs_create_file - create an attribute file for an object.
- *	@kobj:	object we're creating for. 
+ *	@kobj:	object we're creating for.
  *	@attr:	attribute descriptor.
  */
-
-int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
+int sysfs_create_file(struct kobject *kobj, const struct attribute *attr)
 {
 	BUG_ON(!kobj || !kobj->sd || !attr);
 
 	return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
 
 }
+EXPORT_SYMBOL_GPL(sysfs_create_file);
 
 int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr)
 {
@@ -590,6 +589,7 @@
 			sysfs_remove_file(kobj, ptr[i]);
 	return err;
 }
+EXPORT_SYMBOL_GPL(sysfs_create_files);
 
 /**
  * sysfs_add_file_to_group - add an attribute file to a pre-existing group.
@@ -654,7 +654,6 @@
 }
 EXPORT_SYMBOL_GPL(sysfs_chmod_file);
 
-
 /**
  *	sysfs_remove_file - remove an object attribute.
  *	@kobj:	object we're acting for.
@@ -662,8 +661,7 @@
  *
  *	Hash the attribute name and kill the victim.
  */
-
-void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
+void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
 {
 	const void *ns;
 
@@ -672,13 +670,15 @@
 
 	sysfs_hash_and_remove(kobj->sd, ns, attr->name);
 }
+EXPORT_SYMBOL_GPL(sysfs_remove_file);
 
-void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr)
+void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr)
 {
 	int i;
 	for (i = 0; ptr[i]; i++)
 		sysfs_remove_file(kobj, ptr[i]);
 }
+EXPORT_SYMBOL_GPL(sysfs_remove_files);
 
 /**
  * sysfs_remove_file_from_group - remove an attribute file from a group.
@@ -793,9 +793,3 @@
 	return 0;
 }
 EXPORT_SYMBOL_GPL(sysfs_schedule_callback);
-
-
-EXPORT_SYMBOL_GPL(sysfs_create_file);
-EXPORT_SYMBOL_GPL(sysfs_remove_file);
-EXPORT_SYMBOL_GPL(sysfs_remove_files);
-EXPORT_SYMBOL_GPL(sysfs_create_files);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 09a1a25..5f92cd2 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -3,8 +3,10 @@
  *
  * Copyright (c) 2003 Patrick Mochel
  * Copyright (c) 2003 Open Source Development Lab
+ * Copyright (c) 2013 Greg Kroah-Hartman
+ * Copyright (c) 2013 The Linux Foundation
  *
- * This file is released undert the GPL v2. 
+ * This file is released undert the GPL v2.
  *
  */
 
@@ -19,8 +21,8 @@
 static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
 			 const struct attribute_group *grp)
 {
-	struct attribute *const* attr;
-	struct bin_attribute *const* bin_attr;
+	struct attribute *const *attr;
+	struct bin_attribute *const *bin_attr;
 
 	if (grp->attrs)
 		for (attr = grp->attrs; *attr; attr++)
@@ -33,8 +35,8 @@
 static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
 			const struct attribute_group *grp, int update)
 {
-	struct attribute *const* attr;
-	struct bin_attribute *const* bin_attr;
+	struct attribute *const *attr;
+	struct bin_attribute *const *bin_attr;
 	int error = 0, i;
 
 	if (grp->attrs) {
@@ -129,6 +131,41 @@
 {
 	return internal_create_group(kobj, 0, grp);
 }
+EXPORT_SYMBOL_GPL(sysfs_create_group);
+
+/**
+ * sysfs_create_groups - given a directory kobject, create a bunch of attribute groups
+ * @kobj:	The kobject to create the group on
+ * @groups:	The attribute groups to create, NULL terminated
+ *
+ * This function creates a bunch of attribute groups.  If an error occurs when
+ * creating a group, all previously created groups will be removed, unwinding
+ * everything back to the original state when this function was called.
+ * It will explicitly warn and error if any of the attribute files being
+ * created already exist.
+ *
+ * Returns 0 on success or error code from sysfs_create_group on error.
+ */
+int sysfs_create_groups(struct kobject *kobj,
+			const struct attribute_group **groups)
+{
+	int error = 0;
+	int i;
+
+	if (!groups)
+		return 0;
+
+	for (i = 0; groups[i]; i++) {
+		error = sysfs_create_group(kobj, groups[i]);
+		if (error) {
+			while (--i >= 0)
+				sysfs_remove_group(kobj, groups[i]);
+			break;
+		}
+	}
+	return error;
+}
+EXPORT_SYMBOL_GPL(sysfs_create_groups);
 
 /**
  * sysfs_update_group - given a directory kobject, update an attribute group
@@ -152,11 +189,18 @@
 {
 	return internal_create_group(kobj, 1, grp);
 }
+EXPORT_SYMBOL_GPL(sysfs_update_group);
 
-
-
-void sysfs_remove_group(struct kobject * kobj, 
-			const struct attribute_group * grp)
+/**
+ * sysfs_remove_group: remove a group from a kobject
+ * @kobj:	kobject to remove the group from
+ * @grp:	group to remove
+ *
+ * This function removes a group of attributes from a kobject.  The attributes
+ * previously have to have been created for this group, otherwise it will fail.
+ */
+void sysfs_remove_group(struct kobject *kobj,
+			const struct attribute_group *grp)
 {
 	struct sysfs_dirent *dir_sd = kobj->sd;
 	struct sysfs_dirent *sd;
@@ -164,8 +208,9 @@
 	if (grp->name) {
 		sd = sysfs_get_dirent(dir_sd, NULL, grp->name);
 		if (!sd) {
-			WARN(!sd, KERN_WARNING "sysfs group %p not found for "
-				"kobject '%s'\n", grp, kobject_name(kobj));
+			WARN(!sd, KERN_WARNING
+			     "sysfs group %p not found for kobject '%s'\n",
+			     grp, kobject_name(kobj));
 			return;
 		}
 	} else
@@ -177,6 +222,27 @@
 
 	sysfs_put(sd);
 }
+EXPORT_SYMBOL_GPL(sysfs_remove_group);
+
+/**
+ * sysfs_remove_groups - remove a list of groups
+ *
+ * @kobj:	The kobject for the groups to be removed from
+ * @groups:	NULL terminated list of groups to be removed
+ *
+ * If groups is not NULL, remove the specified groups from the kobject.
+ */
+void sysfs_remove_groups(struct kobject *kobj,
+			 const struct attribute_group **groups)
+{
+	int i;
+
+	if (!groups)
+		return;
+	for (i = 0; groups[i]; i++)
+		sysfs_remove_group(kobj, groups[i]);
+}
+EXPORT_SYMBOL_GPL(sysfs_remove_groups);
 
 /**
  * sysfs_merge_group - merge files into a pre-existing attribute group.
@@ -273,7 +339,3 @@
 	}
 }
 EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group);
-
-EXPORT_SYMBOL_GPL(sysfs_create_group);
-EXPORT_SYMBOL_GPL(sysfs_update_group);
-EXPORT_SYMBOL_GPL(sysfs_remove_group);
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 3e2837a..963f910 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -10,7 +10,7 @@
  * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
-#undef DEBUG 
+#undef DEBUG
 
 #include <linux/pagemap.h>
 #include <linux/namei.h>
@@ -36,7 +36,7 @@
 	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
 };
 
-static const struct inode_operations sysfs_inode_operations ={
+static const struct inode_operations sysfs_inode_operations = {
 	.permission	= sysfs_permission,
 	.setattr	= sysfs_setattr,
 	.getattr	= sysfs_getattr,
@@ -67,7 +67,7 @@
 	return attrs;
 }
 
-int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr)
+int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr)
 {
 	struct sysfs_inode_attrs *sd_attrs;
 	struct iattr *iattrs;
@@ -128,7 +128,8 @@
 	return error;
 }
 
-static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len)
+static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata,
+			       u32 *secdata_len)
 {
 	struct sysfs_inode_attrs *iattrs;
 	void *old_secdata;
@@ -186,13 +187,13 @@
 	return error;
 }
 
-static inline void set_default_inode_attr(struct inode * inode, umode_t mode)
+static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
 {
 	inode->i_mode = mode;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 }
 
-static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
+static inline void set_inode_attr(struct inode *inode, struct iattr *iattr)
 {
 	inode->i_uid = iattr->ia_uid;
 	inode->i_gid = iattr->ia_gid;
@@ -220,7 +221,8 @@
 		set_nlink(inode, sd->s_dir.subdirs + 2);
 }
 
-int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		  struct kstat *stat)
 {
 	struct sysfs_dirent *sd = dentry->d_fsdata;
 	struct inode *inode = dentry->d_inode;
@@ -285,7 +287,7 @@
  *	RETURNS:
  *	Pointer to allocated inode on success, NULL on failure.
  */
-struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)
+struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd)
 {
 	struct inode *inode;
 
@@ -312,7 +314,8 @@
 	sysfs_put(sd);
 }
 
-int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name)
+int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns,
+			  const char *name)
 {
 	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index afd8327..fd7ce7a 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -64,7 +64,7 @@
 	/* instantiate and link root dentry */
 	root = d_make_root(inode);
 	if (!root) {
-		pr_debug("%s: could not get root dentry!\n",__func__);
+		pr_debug("%s: could not get root dentry!\n", __func__);
 		return -ENOMEM;
 	}
 	root->d_fsdata = &sysfs_root;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 8c940df..2dd4507 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -125,6 +125,7 @@
 {
 	return sysfs_do_create_link(kobj, target, name, 1);
 }
+EXPORT_SYMBOL_GPL(sysfs_create_link);
 
 /**
  *	sysfs_create_link_nowarn - create symlink between two objects.
@@ -166,8 +167,7 @@
  *	@kobj:	object we're acting for.
  *	@name:	name of the symlink to remove.
  */
-
-void sysfs_remove_link(struct kobject * kobj, const char * name)
+void sysfs_remove_link(struct kobject *kobj, const char *name)
 {
 	struct sysfs_dirent *parent_sd = NULL;
 
@@ -178,6 +178,7 @@
 
 	sysfs_hash_and_remove(parent_sd, NULL, name);
 }
+EXPORT_SYMBOL_GPL(sysfs_remove_link);
 
 /**
  *	sysfs_rename_link - rename symlink in object's directory.
@@ -223,6 +224,7 @@
 	sysfs_put(sd);
 	return result;
 }
+EXPORT_SYMBOL_GPL(sysfs_rename_link);
 
 static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
 				 struct sysfs_dirent *target_sd, char *path)
@@ -276,7 +278,7 @@
 	return 0;
 }
 
-static int sysfs_getlink(struct dentry *dentry, char * path)
+static int sysfs_getlink(struct dentry *dentry, char *path)
 {
 	struct sysfs_dirent *sd = dentry->d_fsdata;
 	struct sysfs_dirent *parent_sd = sd->s_parent;
@@ -295,7 +297,7 @@
 	int error = -ENOMEM;
 	unsigned long page = get_zeroed_page(GFP_KERNEL);
 	if (page) {
-		error = sysfs_getlink(dentry, (char *) page); 
+		error = sysfs_getlink(dentry, (char *) page);
 		if (error < 0)
 			free_page((unsigned long)page);
 	}
@@ -303,7 +305,8 @@
 	return NULL;
 }
 
-static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
+static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd,
+			   void *cookie)
 {
 	char *page = nd_get_link(nd);
 	if (!IS_ERR(page))
@@ -319,8 +322,3 @@
 	.getattr	= sysfs_getattr,
 	.permission	= sysfs_permission,
 };
-
-
-EXPORT_SYMBOL_GPL(sysfs_create_link);
-EXPORT_SYMBOL_GPL(sysfs_remove_link);
-EXPORT_SYMBOL_GPL(sysfs_rename_link);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index d1e4043..b6deca3 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -78,7 +78,7 @@
 	};
 
 	unsigned short		s_flags;
-	umode_t 		s_mode;
+	umode_t			s_mode;
 	unsigned int		s_ino;
 	struct sysfs_inode_attrs *s_iattr;
 };
@@ -123,9 +123,9 @@
 		key = &attr->skey;				\
 								\
 	lockdep_init_map(&sd->dep_map, "s_active", key, 0);	\
-} while(0)
+} while (0)
 #else
-#define sysfs_dirent_init_lockdep(sd) do {} while(0)
+#define sysfs_dirent_init_lockdep(sd) do {} while (0)
 #endif
 
 /*
@@ -186,8 +186,8 @@
 			struct sysfs_dirent **p_sd);
 void sysfs_remove_subdir(struct sysfs_dirent *sd);
 
-int sysfs_rename(struct sysfs_dirent *sd,
-	struct sysfs_dirent *new_parent_sd, const void *ns, const char *new_name);
+int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd,
+		 const void *ns, const char *new_name);
 
 static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd)
 {
@@ -214,10 +214,12 @@
 int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr);
 int sysfs_permission(struct inode *inode, int mask);
 int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
-int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		  struct kstat *stat);
 int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
-		size_t size, int flags);
-int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name);
+		   size_t size, int flags);
+int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns,
+			  const char *name);
 int sysfs_inode_init(void);
 
 /*
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 94383a7..02e113b 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -56,6 +56,16 @@
 
 acpi_status
 acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld);
+
+bool acpi_has_method(acpi_handle handle, char *name);
+acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
+				       u64 arg);
+acpi_status acpi_evaluate_ej0(acpi_handle handle);
+acpi_status acpi_evaluate_lck(acpi_handle handle, int lock);
+bool acpi_ata_match(acpi_handle handle);
+bool acpi_bay_match(acpi_handle handle);
+bool acpi_dock_match(acpi_handle handle);
+
 #ifdef CONFIG_ACPI
 
 #include <linux/proc_fs.h>
@@ -157,9 +167,8 @@
 	u32 removable:1;
 	u32 ejectable:1;
 	u32 power_manageable:1;
-	u32 eject_pending:1;
 	u32 match_driver:1;
-	u32 reserved:26;
+	u32 reserved:27;
 };
 
 /* File System */
@@ -352,14 +361,11 @@
 extern int register_acpi_notifier(struct notifier_block *);
 extern int unregister_acpi_notifier(struct notifier_block *);
 
-extern int register_acpi_bus_notifier(struct notifier_block *nb);
-extern void unregister_acpi_bus_notifier(struct notifier_block *nb);
 /*
  * External Functions
  */
 
 int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device);
-void acpi_bus_data_handler(acpi_handle handle, void *context);
 acpi_status acpi_bus_get_status_handle(acpi_handle handle,
 				       unsigned long long *sta);
 int acpi_bus_get_status(struct acpi_device *device);
@@ -379,15 +385,6 @@
 static inline bool acpi_bus_can_wakeup(acpi_handle handle) { return false; }
 #endif
 
-#ifdef CONFIG_ACPI_PROC_EVENT
-int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data);
-int acpi_bus_generate_proc_event4(const char *class, const char *bid, u8 type, int data);
-int acpi_bus_receive_event(struct acpi_bus_event *event);
-#else
-static inline int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
-	{ return 0; }
-#endif
-
 void acpi_scan_lock_acquire(void);
 void acpi_scan_lock_release(void);
 int acpi_scan_add_handler(struct acpi_scan_handler *handler);
@@ -478,7 +475,8 @@
 	if (p)
 		*p = ACPI_STATE_D0;
 
-	return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0;
+	return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
+		m : ACPI_STATE_D0;
 }
 static inline void acpi_dev_pm_add_dependent(acpi_handle handle,
 					     struct device *depdev) {}
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index b420939..1cedfcb 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -113,14 +113,13 @@
                                   Dock Station
   -------------------------------------------------------------------------- */
 struct acpi_dock_ops {
+	acpi_notify_handler fixup;
 	acpi_notify_handler handler;
 	acpi_notify_handler uevent;
 };
 
-#if defined(CONFIG_ACPI_DOCK) || defined(CONFIG_ACPI_DOCK_MODULE)
+#ifdef CONFIG_ACPI_DOCK
 extern int is_dock_device(acpi_handle handle);
-extern int register_dock_notifier(struct notifier_block *nb);
-extern void unregister_dock_notifier(struct notifier_block *nb);
 extern int register_hotplug_dock_device(acpi_handle handle,
 					const struct acpi_dock_ops *ops,
 					void *context,
@@ -132,13 +131,6 @@
 {
 	return 0;
 }
-static inline int register_dock_notifier(struct notifier_block *nb)
-{
-	return -ENODEV;
-}
-static inline void unregister_dock_notifier(struct notifier_block *nb)
-{
-}
 static inline int register_hotplug_dock_device(acpi_handle handle,
 					       const struct acpi_dock_ops *ops,
 					       void *context,
@@ -150,6 +142,6 @@
 static inline void unregister_hotplug_dock_device(acpi_handle handle)
 {
 }
-#endif
+#endif /* CONFIG_ACPI_DOCK */
 
 #endif /*__ACPI_DRIVERS_H__*/
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 22d497e..85bfdbe 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20130517
+#define ACPI_CA_VERSION                 0x20130725
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -147,6 +147,8 @@
 
 acpi_status acpi_remove_interface(acpi_string interface_name);
 
+acpi_status acpi_update_interfaces(u8 action);
+
 u32
 acpi_check_address_range(acpi_adr_space_type space_id,
 			 acpi_physical_address address,
@@ -210,8 +212,8 @@
 acpi_walk_namespace(acpi_object_type type,
 		    acpi_handle start_object,
 		    u32 max_depth,
-		    acpi_walk_callback pre_order_visit,
-		    acpi_walk_callback post_order_visit,
+		    acpi_walk_callback descending_callback,
+		    acpi_walk_callback ascending_callback,
 		    void *context, void **return_value);
 
 acpi_status
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 22b03c9..b748aef 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -668,13 +668,6 @@
 #define ACPI_EVENT_FLAG_SET             (acpi_event_status) 0x04
 #define ACPI_EVENT_FLAG_HANDLE		(acpi_event_status) 0x08
 
-/*
- * General Purpose Events (GPE)
- */
-#define ACPI_GPE_INVALID                0xFF
-#define ACPI_GPE_MAX                    0xFF
-#define ACPI_NUM_GPE                    256
-
 /* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */
 
 #define ACPI_GPE_ENABLE                 0
@@ -1144,7 +1137,19 @@
 #endif
 };
 
-/* Definitions for _OSI support */
+/* Definitions of _OSI support */
+
+#define ACPI_VENDOR_STRINGS                 0x01
+#define ACPI_FEATURE_STRINGS                0x02
+#define ACPI_ENABLE_INTERFACES              0x00
+#define ACPI_DISABLE_INTERFACES             0x04
+
+#define ACPI_DISABLE_ALL_VENDOR_STRINGS     (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS)
+#define ACPI_DISABLE_ALL_FEATURE_STRINGS    (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS)
+#define ACPI_DISABLE_ALL_STRINGS            (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS)
+#define ACPI_ENABLE_ALL_VENDOR_STRINGS      (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS)
+#define ACPI_ENABLE_ALL_FEATURE_STRINGS     (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS)
+#define ACPI_ENABLE_ALL_STRINGS             (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS)
 
 #define ACPI_OSI_WIN_2000               0x01
 #define ACPI_OSI_WIN_XP                 0x02
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 0807ddf..f330d28 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -208,10 +208,6 @@
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 #endif
 
-#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-#define page_test_and_clear_young(pfn) (0)
-#endif
-
 #ifndef __HAVE_ARCH_PGD_OFFSET_GATE
 #define pgd_offset_gate(mm, addr)	pgd_offset(mm, addr)
 #endif
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 69732d2..83e2c31 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -122,8 +122,12 @@
 #define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .;      \
 			 *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
 			 VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
+#define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .;	\
+			 *(__tracepoint_str) /* Trace_printk fmt' pointer */ \
+			 VMLINUX_SYMBOL(__stop___tracepoint_str) = .;
 #else
 #define TRACE_PRINTKS()
+#define TRACEPOINT_STR()
 #endif
 
 #ifdef CONFIG_FTRACE_SYSCALLS
@@ -190,7 +194,8 @@
 	VMLINUX_SYMBOL(__stop___verbose) = .;				\
 	LIKELY_PROFILE()		       				\
 	BRANCH_PROFILE()						\
-	TRACE_PRINTKS()
+	TRACE_PRINTKS()							\
+	TRACEPOINT_STR()
 
 /*
  * Data section helpers
diff --git a/include/asm-generic/vtime.h b/include/asm-generic/vtime.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/asm-generic/vtime.h
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index c463ce9..93b7f96 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -23,16 +23,20 @@
 #define ARCH_TIMER_CTRL_IT_MASK		(1 << 1)
 #define ARCH_TIMER_CTRL_IT_STAT		(1 << 2)
 
-#define ARCH_TIMER_REG_CTRL		0
-#define ARCH_TIMER_REG_TVAL		1
+enum arch_timer_reg {
+	ARCH_TIMER_REG_CTRL,
+	ARCH_TIMER_REG_TVAL,
+};
 
 #define ARCH_TIMER_PHYS_ACCESS		0
 #define ARCH_TIMER_VIRT_ACCESS		1
+#define ARCH_TIMER_MEM_PHYS_ACCESS	2
+#define ARCH_TIMER_MEM_VIRT_ACCESS	3
 
 #ifdef CONFIG_ARM_ARCH_TIMER
 
 extern u32 arch_timer_get_rate(void);
-extern u64 arch_timer_read_counter(void);
+extern u64 (*arch_timer_read_counter)(void);
 extern struct timecounter *arch_timer_get_timecounter(void);
 
 #else
diff --git a/include/dt-bindings/pwm/pwm.h b/include/dt-bindings/pwm/pwm.h
new file mode 100644
index 0000000..96f49e8
--- /dev/null
+++ b/include/dt-bindings/pwm/pwm.h
@@ -0,0 +1,14 @@
+/*
+ * This header provides constants for most PWM bindings.
+ *
+ * Most PWM bindings can include a flags cell as part of the PWM specifier.
+ * In most cases, the format of the flags cell uses the standard values
+ * defined in this header.
+ */
+
+#ifndef _DT_BINDINGS_PWM_PWM_H
+#define _DT_BINDINGS_PWM_PWM_H
+
+#define PWM_POLARITY_INVERTED			(1 << 0)
+
+#endif
diff --git a/include/dt-bindings/sound/fsl-imx-audmux.h b/include/dt-bindings/sound/fsl-imx-audmux.h
new file mode 100644
index 0000000..50b09e9
--- /dev/null
+++ b/include/dt-bindings/sound/fsl-imx-audmux.h
@@ -0,0 +1,56 @@
+#ifndef __DT_FSL_IMX_AUDMUX_H
+#define __DT_FSL_IMX_AUDMUX_H
+
+#define MX27_AUDMUX_HPCR1_SSI0		0
+#define MX27_AUDMUX_HPCR2_SSI1		1
+#define MX27_AUDMUX_HPCR3_SSI_PINS_4	2
+#define MX27_AUDMUX_PPCR1_SSI_PINS_1	3
+#define MX27_AUDMUX_PPCR2_SSI_PINS_2	4
+#define MX27_AUDMUX_PPCR3_SSI_PINS_3	5
+
+#define MX31_AUDMUX_PORT1_SSI0		0
+#define MX31_AUDMUX_PORT2_SSI1		1
+#define MX31_AUDMUX_PORT3_SSI_PINS_3	2
+#define MX31_AUDMUX_PORT4_SSI_PINS_4	3
+#define MX31_AUDMUX_PORT5_SSI_PINS_5	4
+#define MX31_AUDMUX_PORT6_SSI_PINS_6	5
+#define MX31_AUDMUX_PORT7_SSI_PINS_7	6
+
+#define MX51_AUDMUX_PORT1_SSI0		0
+#define MX51_AUDMUX_PORT2_SSI1		1
+#define MX51_AUDMUX_PORT3		2
+#define MX51_AUDMUX_PORT4		3
+#define MX51_AUDMUX_PORT5		4
+#define MX51_AUDMUX_PORT6		5
+#define MX51_AUDMUX_PORT7		6
+
+/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
+#define IMX_AUDMUX_V1_PCR_INMMASK(x)	((x) & 0xff)
+#define IMX_AUDMUX_V1_PCR_INMEN		(1 << 8)
+#define IMX_AUDMUX_V1_PCR_TXRXEN	(1 << 10)
+#define IMX_AUDMUX_V1_PCR_SYN		(1 << 12)
+#define IMX_AUDMUX_V1_PCR_RXDSEL(x)	(((x) & 0x7) << 13)
+#define IMX_AUDMUX_V1_PCR_RFCSEL(x)	(((x) & 0xf) << 20)
+#define IMX_AUDMUX_V1_PCR_RCLKDIR	(1 << 24)
+#define IMX_AUDMUX_V1_PCR_RFSDIR	(1 << 25)
+#define IMX_AUDMUX_V1_PCR_TFCSEL(x)	(((x) & 0xf) << 26)
+#define IMX_AUDMUX_V1_PCR_TCLKDIR	(1 << 30)
+#define IMX_AUDMUX_V1_PCR_TFSDIR	(1 << 31)
+
+/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */
+#define IMX_AUDMUX_V2_PTCR_TFSDIR	(1 << 31)
+#define IMX_AUDMUX_V2_PTCR_TFSEL(x)	(((x) & 0xf) << 27)
+#define IMX_AUDMUX_V2_PTCR_TCLKDIR	(1 << 26)
+#define IMX_AUDMUX_V2_PTCR_TCSEL(x)	(((x) & 0xf) << 22)
+#define IMX_AUDMUX_V2_PTCR_RFSDIR	(1 << 21)
+#define IMX_AUDMUX_V2_PTCR_RFSEL(x)	(((x) & 0xf) << 17)
+#define IMX_AUDMUX_V2_PTCR_RCLKDIR	(1 << 16)
+#define IMX_AUDMUX_V2_PTCR_RCSEL(x)	(((x) & 0xf) << 12)
+#define IMX_AUDMUX_V2_PTCR_SYN		(1 << 11)
+
+#define IMX_AUDMUX_V2_PDCR_RXDSEL(x)	(((x) & 0x7) << 13)
+#define IMX_AUDMUX_V2_PDCR_TXRXEN	(1 << 12)
+#define IMX_AUDMUX_V2_PDCR_MODE(x)	(((x) & 0x3) << 8)
+#define IMX_AUDMUX_V2_PDCR_INMMASK(x)	((x) & 0xff)
+
+#endif /* __DT_FSL_IMX_AUDMUX_H */
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 343744e..7e2d158 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -26,7 +26,7 @@
 #include <linux/types.h>
 #include <linux/irqchip/arm-gic.h>
 
-#define VGIC_NR_IRQS		128
+#define VGIC_NR_IRQS		256
 #define VGIC_NR_SGIS		16
 #define VGIC_NR_PPIS		16
 #define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 353ba25..a5db4ae 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -481,6 +481,13 @@
 
 acpi_status acpi_os_prepare_sleep(u8 sleep_state,
 				  u32 pm1a_control, u32 pm1b_control);
+
+void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
+				        u32 val_a,  u32 val_b));
+
+acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state,
+					   u32 val_a, u32 val_b);
+
 #ifdef CONFIG_X86
 void arch_reserve_mem_area(acpi_physical_address addr, size_t size);
 #else
diff --git a/include/linux/ata.h b/include/linux/ata.h
index ee0bd95..bf4c69c 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -239,6 +239,8 @@
 	ATA_CMD_WRITE_QUEUED_FUA_EXT = 0x3E,
 	ATA_CMD_FPDMA_READ	= 0x60,
 	ATA_CMD_FPDMA_WRITE	= 0x61,
+	ATA_CMD_FPDMA_SEND	= 0x64,
+	ATA_CMD_FPDMA_RECV	= 0x65,
 	ATA_CMD_PIO_READ	= 0x20,
 	ATA_CMD_PIO_READ_EXT	= 0x24,
 	ATA_CMD_PIO_WRITE	= 0x30,
@@ -293,8 +295,13 @@
 	/* marked obsolete in the ATA/ATAPI-7 spec */
 	ATA_CMD_RESTORE		= 0x10,
 
+	/* Subcmds for ATA_CMD_FPDMA_SEND */
+	ATA_SUBCMD_FPDMA_SEND_DSM            = 0x00,
+	ATA_SUBCMD_FPDMA_SEND_WR_LOG_DMA_EXT = 0x02,
+
 	/* READ_LOG_EXT pages */
 	ATA_LOG_SATA_NCQ	= 0x10,
+	ATA_LOG_NCQ_SEND_RECV	  = 0x13,
 	ATA_LOG_SATA_ID_DEV_DATA  = 0x30,
 	ATA_LOG_SATA_SETTINGS	  = 0x08,
 	ATA_LOG_DEVSLP_OFFSET	  = 0x30,
@@ -305,6 +312,15 @@
 	ATA_LOG_DEVSLP_VALID	  = 0x07,
 	ATA_LOG_DEVSLP_VALID_MASK = 0x80,
 
+	/* NCQ send and receive log */
+	ATA_LOG_NCQ_SEND_RECV_SUBCMDS_OFFSET	= 0x00,
+	ATA_LOG_NCQ_SEND_RECV_SUBCMDS_DSM	= (1 << 0),
+	ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET	= 0x04,
+	ATA_LOG_NCQ_SEND_RECV_DSM_TRIM		= (1 << 0),
+	ATA_LOG_NCQ_SEND_RECV_RD_LOG_OFFSET	= 0x08,
+	ATA_LOG_NCQ_SEND_RECV_WR_LOG_OFFSET	= 0x0C,
+	ATA_LOG_NCQ_SEND_RECV_SIZE		= 0x10,
+
 	/* READ/WRITE LONG (obsolete) */
 	ATA_CMD_READ_LONG	= 0x22,
 	ATA_CMD_READ_LONG_ONCE	= 0x23,
@@ -446,22 +462,6 @@
 	SERR_TRANS_ST_ERROR	= (1 << 24), /* Transport state trans. error */
 	SERR_UNRECOG_FIS	= (1 << 25), /* Unrecognized FIS */
 	SERR_DEV_XCHG		= (1 << 26), /* device exchanged */
-
-	/* struct ata_taskfile flags */
-	ATA_TFLAG_LBA48		= (1 << 0), /* enable 48-bit LBA and "HOB" */
-	ATA_TFLAG_ISADDR	= (1 << 1), /* enable r/w to nsect/lba regs */
-	ATA_TFLAG_DEVICE	= (1 << 2), /* enable r/w to device reg */
-	ATA_TFLAG_WRITE		= (1 << 3), /* data dir: host->dev==1 (write) */
-	ATA_TFLAG_LBA		= (1 << 4), /* enable LBA */
-	ATA_TFLAG_FUA		= (1 << 5), /* enable FUA */
-	ATA_TFLAG_POLLING	= (1 << 6), /* set nIEN to 1 and use polling */
-
-	/* protocol flags */
-	ATA_PROT_FLAG_PIO	= (1 << 0), /* is PIO */
-	ATA_PROT_FLAG_DMA	= (1 << 1), /* is DMA */
-	ATA_PROT_FLAG_DATA	= ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
-	ATA_PROT_FLAG_NCQ	= (1 << 2), /* is NCQ */
-	ATA_PROT_FLAG_ATAPI	= (1 << 3), /* is ATAPI */
 };
 
 enum ata_tf_protocols {
@@ -488,83 +488,6 @@
 	__le32			flags_len;
 };
 
-struct ata_taskfile {
-	unsigned long		flags;		/* ATA_TFLAG_xxx */
-	u8			protocol;	/* ATA_PROT_xxx */
-
-	u8			ctl;		/* control reg */
-
-	u8			hob_feature;	/* additional data */
-	u8			hob_nsect;	/* to support LBA48 */
-	u8			hob_lbal;
-	u8			hob_lbam;
-	u8			hob_lbah;
-
-	u8			feature;
-	u8			nsect;
-	u8			lbal;
-	u8			lbam;
-	u8			lbah;
-
-	u8			device;
-
-	u8			command;	/* IO operation */
-};
-
-/*
- * protocol tests
- */
-static inline unsigned int ata_prot_flags(u8 prot)
-{
-	switch (prot) {
-	case ATA_PROT_NODATA:
-		return 0;
-	case ATA_PROT_PIO:
-		return ATA_PROT_FLAG_PIO;
-	case ATA_PROT_DMA:
-		return ATA_PROT_FLAG_DMA;
-	case ATA_PROT_NCQ:
-		return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
-	case ATAPI_PROT_NODATA:
-		return ATA_PROT_FLAG_ATAPI;
-	case ATAPI_PROT_PIO:
-		return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
-	case ATAPI_PROT_DMA:
-		return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
-	}
-	return 0;
-}
-
-static inline int ata_is_atapi(u8 prot)
-{
-	return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
-}
-
-static inline int ata_is_nodata(u8 prot)
-{
-	return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
-}
-
-static inline int ata_is_pio(u8 prot)
-{
-	return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
-}
-
-static inline int ata_is_dma(u8 prot)
-{
-	return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
-}
-
-static inline int ata_is_ncq(u8 prot)
-{
-	return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
-}
-
-static inline int ata_is_data(u8 prot)
-{
-	return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
-}
-
 /*
  * id tests
  */
@@ -865,6 +788,11 @@
 	return val;
 }
 
+static inline bool ata_id_has_ncq_send_and_recv(const u16 *id)
+{
+	return id[ATA_ID_SATA_CAPABILITY_2] & BIT(6);
+}
+
 static inline bool ata_id_has_trim(const u16 *id)
 {
 	if (ata_id_major_version(id) >= 7 &&
@@ -1060,15 +988,6 @@
 	return used_bytes;
 }
 
-static inline int is_multi_taskfile(struct ata_taskfile *tf)
-{
-	return (tf->command == ATA_CMD_READ_MULTI) ||
-	       (tf->command == ATA_CMD_WRITE_MULTI) ||
-	       (tf->command == ATA_CMD_READ_MULTI_EXT) ||
-	       (tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
-	       (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
-}
-
 static inline bool ata_ok(u8 status)
 {
 	return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
index deb0ae5..66a0e53 100644
--- a/include/linux/atmel-ssc.h
+++ b/include/linux/atmel-ssc.h
@@ -11,7 +11,7 @@
 
 struct ssc_device {
 	struct list_head	list;
-	resource_size_t		phybase;
+	dma_addr_t		phybase;
 	void __iomem		*regs;
 	struct platform_device	*pdev;
 	struct atmel_ssc_platform_data *pdata;
diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h
index fd68337..be201ca 100644
--- a/include/linux/atmel_serial.h
+++ b/include/linux/atmel_serial.h
@@ -124,4 +124,6 @@
 #define ATMEL_US_NER		0x44			/* Number of Errors Register */
 #define ATMEL_US_IF		0x4c			/* IrDA Filter Register */
 
+#define ATMEL_US_NAME		0xf0			/* Ip Name */
+
 #endif
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index e9ac882..3561d30 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -66,22 +66,25 @@
 
 /* Per-subsystem/per-cgroup state maintained by the system. */
 struct cgroup_subsys_state {
-	/*
-	 * The cgroup that this subsystem is attached to. Useful
-	 * for subsystems that want to know about the cgroup
-	 * hierarchy structure
-	 */
+	/* the cgroup that this css is attached to */
 	struct cgroup *cgroup;
 
+	/* the cgroup subsystem that this css is attached to */
+	struct cgroup_subsys *ss;
+
 	/* reference count - access via css_[try]get() and css_put() */
 	struct percpu_ref refcnt;
 
+	/* the parent css */
+	struct cgroup_subsys_state *parent;
+
 	unsigned long flags;
 	/* ID for this css, if possible */
 	struct css_id __rcu *id;
 
-	/* Used to put @cgroup->dentry on the last css_put() */
-	struct work_struct dput_work;
+	/* percpu_ref killing and RCU release */
+	struct rcu_head rcu_head;
+	struct work_struct destroy_work;
 };
 
 /* bits in struct cgroup_subsys_state flags field */
@@ -161,7 +164,16 @@
 struct cgroup {
 	unsigned long flags;		/* "unsigned long" so bitops work */
 
-	int id;				/* ida allocated in-hierarchy ID */
+	/*
+	 * idr allocated in-hierarchy ID.
+	 *
+	 * The ID of the root cgroup is always 0, and a new cgroup
+	 * will be assigned with a smallest available ID.
+	 */
+	int id;
+
+	/* the number of attached css's */
+	int nr_css;
 
 	/*
 	 * We link our 'sibling' struct into our parent's 'children'.
@@ -196,7 +208,7 @@
 	struct cgroup_name __rcu *name;
 
 	/* Private pointers for each registered subsystem */
-	struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
+	struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT];
 
 	struct cgroupfs_root *root;
 
@@ -220,10 +232,12 @@
 	struct list_head pidlists;
 	struct mutex pidlist_mutex;
 
+	/* dummy css with NULL ->ss, points back to this cgroup */
+	struct cgroup_subsys_state dummy_css;
+
 	/* For css percpu_ref killing and RCU-protected deletion */
 	struct rcu_head rcu_head;
 	struct work_struct destroy_work;
-	atomic_t css_kill_cnt;
 
 	/* List of events which userspace want to receive */
 	struct list_head event_list;
@@ -322,7 +336,7 @@
 	unsigned long flags;
 
 	/* IDs for cgroups in this hierarchy */
-	struct ida cgroup_ida;
+	struct idr cgroup_idr;
 
 	/* The path to use for release notifications. */
 	char release_agent_path[PATH_MAX];
@@ -394,9 +408,10 @@
 
 /* cftype->flags */
 enum {
-	CFTYPE_ONLY_ON_ROOT	= (1 << 0),	/* only create on root cg */
-	CFTYPE_NOT_ON_ROOT	= (1 << 1),	/* don't create on root cg */
+	CFTYPE_ONLY_ON_ROOT	= (1 << 0),	/* only create on root cgrp */
+	CFTYPE_NOT_ON_ROOT	= (1 << 1),	/* don't create on root cgrp */
 	CFTYPE_INSANE		= (1 << 2),	/* don't create if sane_behavior */
+	CFTYPE_NO_PREFIX	= (1 << 3),	/* (DON'T USE FOR NEW FILES) no subsys prefix */
 };
 
 #define MAX_CFTYPE_NAME		64
@@ -424,35 +439,41 @@
 	/* CFTYPE_* flags */
 	unsigned int flags;
 
+	/*
+	 * The subsys this file belongs to.  Initialized automatically
+	 * during registration.  NULL for cgroup core files.
+	 */
+	struct cgroup_subsys *ss;
+
 	int (*open)(struct inode *inode, struct file *file);
-	ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
+	ssize_t (*read)(struct cgroup_subsys_state *css, struct cftype *cft,
 			struct file *file,
 			char __user *buf, size_t nbytes, loff_t *ppos);
 	/*
 	 * read_u64() is a shortcut for the common case of returning a
 	 * single integer. Use it in place of read()
 	 */
-	u64 (*read_u64)(struct cgroup *cgrp, struct cftype *cft);
+	u64 (*read_u64)(struct cgroup_subsys_state *css, struct cftype *cft);
 	/*
 	 * read_s64() is a signed version of read_u64()
 	 */
-	s64 (*read_s64)(struct cgroup *cgrp, struct cftype *cft);
+	s64 (*read_s64)(struct cgroup_subsys_state *css, struct cftype *cft);
 	/*
 	 * read_map() is used for defining a map of key/value
 	 * pairs. It should call cb->fill(cb, key, value) for each
 	 * entry. The key/value pairs (and their ordering) should not
 	 * change between reboots.
 	 */
-	int (*read_map)(struct cgroup *cgrp, struct cftype *cft,
+	int (*read_map)(struct cgroup_subsys_state *css, struct cftype *cft,
 			struct cgroup_map_cb *cb);
 	/*
 	 * read_seq_string() is used for outputting a simple sequence
 	 * using seqfile.
 	 */
-	int (*read_seq_string)(struct cgroup *cgrp, struct cftype *cft,
-			       struct seq_file *m);
+	int (*read_seq_string)(struct cgroup_subsys_state *css,
+			       struct cftype *cft, struct seq_file *m);
 
-	ssize_t (*write)(struct cgroup *cgrp, struct cftype *cft,
+	ssize_t (*write)(struct cgroup_subsys_state *css, struct cftype *cft,
 			 struct file *file,
 			 const char __user *buf, size_t nbytes, loff_t *ppos);
 
@@ -461,18 +482,20 @@
 	 * a single integer (as parsed by simple_strtoull) from
 	 * userspace. Use in place of write(); return 0 or error.
 	 */
-	int (*write_u64)(struct cgroup *cgrp, struct cftype *cft, u64 val);
+	int (*write_u64)(struct cgroup_subsys_state *css, struct cftype *cft,
+			 u64 val);
 	/*
 	 * write_s64() is a signed version of write_u64()
 	 */
-	int (*write_s64)(struct cgroup *cgrp, struct cftype *cft, s64 val);
+	int (*write_s64)(struct cgroup_subsys_state *css, struct cftype *cft,
+			 s64 val);
 
 	/*
 	 * write_string() is passed a nul-terminated kernelspace
 	 * buffer of maximum length determined by max_write_len.
 	 * Returns 0 or -ve error code.
 	 */
-	int (*write_string)(struct cgroup *cgrp, struct cftype *cft,
+	int (*write_string)(struct cgroup_subsys_state *css, struct cftype *cft,
 			    const char *buffer);
 	/*
 	 * trigger() callback can be used to get some kick from the
@@ -480,7 +503,7 @@
 	 * at all. The private field can be used to determine the
 	 * kick type for multiplexing.
 	 */
-	int (*trigger)(struct cgroup *cgrp, unsigned int event);
+	int (*trigger)(struct cgroup_subsys_state *css, unsigned int event);
 
 	int (*release)(struct inode *inode, struct file *file);
 
@@ -490,16 +513,18 @@
 	 * you want to provide this functionality. Use eventfd_signal()
 	 * on eventfd to send notification to userspace.
 	 */
-	int (*register_event)(struct cgroup *cgrp, struct cftype *cft,
-			struct eventfd_ctx *eventfd, const char *args);
+	int (*register_event)(struct cgroup_subsys_state *css,
+			      struct cftype *cft, struct eventfd_ctx *eventfd,
+			      const char *args);
 	/*
 	 * unregister_event() callback will be called when userspace
 	 * closes the eventfd or on cgroup removing.
 	 * This callback must be implemented, if you want provide
 	 * notification functionality.
 	 */
-	void (*unregister_event)(struct cgroup *cgrp, struct cftype *cft,
-			struct eventfd_ctx *eventfd);
+	void (*unregister_event)(struct cgroup_subsys_state *css,
+				 struct cftype *cft,
+				 struct eventfd_ctx *eventfd);
 };
 
 /*
@@ -512,15 +537,6 @@
 	struct cftype			*cfts;
 };
 
-struct cgroup_scanner {
-	struct cgroup *cg;
-	int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan);
-	void (*process_task)(struct task_struct *p,
-			struct cgroup_scanner *scan);
-	struct ptr_heap *heap;
-	void *data;
-};
-
 /*
  * See the comment above CGRP_ROOT_SANE_BEHAVIOR for details.  This
  * function can be called as long as @cgrp is accessible.
@@ -537,7 +553,7 @@
 }
 
 int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
-int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
+int cgroup_rm_cftypes(struct cftype *cfts);
 
 bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
 
@@ -553,20 +569,22 @@
 struct cgroup_taskset;
 struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset);
 struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset);
-struct cgroup *cgroup_taskset_cur_cgroup(struct cgroup_taskset *tset);
+struct cgroup_subsys_state *cgroup_taskset_cur_css(struct cgroup_taskset *tset,
+						   int subsys_id);
 int cgroup_taskset_size(struct cgroup_taskset *tset);
 
 /**
  * cgroup_taskset_for_each - iterate cgroup_taskset
  * @task: the loop cursor
- * @skip_cgrp: skip if task's cgroup matches this, %NULL to iterate through all
+ * @skip_css: skip if task's css matches this, %NULL to iterate through all
  * @tset: taskset to iterate
  */
-#define cgroup_taskset_for_each(task, skip_cgrp, tset)			\
+#define cgroup_taskset_for_each(task, skip_css, tset)			\
 	for ((task) = cgroup_taskset_first((tset)); (task);		\
 	     (task) = cgroup_taskset_next((tset)))			\
-		if (!(skip_cgrp) ||					\
-		    cgroup_taskset_cur_cgroup((tset)) != (skip_cgrp))
+		if (!(skip_css) ||					\
+		    cgroup_taskset_cur_css((tset),			\
+			(skip_css)->ss->subsys_id) != (skip_css))
 
 /*
  * Control Group subsystem type.
@@ -574,18 +592,22 @@
  */
 
 struct cgroup_subsys {
-	struct cgroup_subsys_state *(*css_alloc)(struct cgroup *cgrp);
-	int (*css_online)(struct cgroup *cgrp);
-	void (*css_offline)(struct cgroup *cgrp);
-	void (*css_free)(struct cgroup *cgrp);
+	struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css);
+	int (*css_online)(struct cgroup_subsys_state *css);
+	void (*css_offline)(struct cgroup_subsys_state *css);
+	void (*css_free)(struct cgroup_subsys_state *css);
 
-	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);
+	int (*can_attach)(struct cgroup_subsys_state *css,
+			  struct cgroup_taskset *tset);
+	void (*cancel_attach)(struct cgroup_subsys_state *css,
+			      struct cgroup_taskset *tset);
+	void (*attach)(struct cgroup_subsys_state *css,
+		       struct cgroup_taskset *tset);
 	void (*fork)(struct task_struct *task);
-	void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp,
+	void (*exit)(struct cgroup_subsys_state *css,
+		     struct cgroup_subsys_state *old_css,
 		     struct task_struct *task);
-	void (*bind)(struct cgroup *root);
+	void (*bind)(struct cgroup_subsys_state *root_css);
 
 	int subsys_id;
 	int disabled;
@@ -641,10 +663,17 @@
 #undef IS_SUBSYS_ENABLED
 #undef SUBSYS
 
-static inline struct cgroup_subsys_state *cgroup_subsys_state(
-	struct cgroup *cgrp, int subsys_id)
+/**
+ * css_parent - find the parent css
+ * @css: the target cgroup_subsys_state
+ *
+ * Return the parent css of @css.  This function is guaranteed to return
+ * non-NULL parent as long as @css isn't the root.
+ */
+static inline
+struct cgroup_subsys_state *css_parent(struct cgroup_subsys_state *css)
 {
-	return cgrp->subsys[subsys_id];
+	return css->parent;
 }
 
 /**
@@ -672,7 +701,7 @@
 #endif
 
 /**
- * task_subsys_state_check - obtain css for (task, subsys) w/ extra access conds
+ * task_css_check - obtain css for (task, subsys) w/ extra access conds
  * @task: the target task
  * @subsys_id: the target subsystem ID
  * @__c: extra condition expression to be passed to rcu_dereference_check()
@@ -680,7 +709,7 @@
  * Return the cgroup_subsys_state for the (@task, @subsys_id) pair.  The
  * synchronization rules are the same as task_css_set_check().
  */
-#define task_subsys_state_check(task, subsys_id, __c)			\
+#define task_css_check(task, subsys_id, __c)				\
 	task_css_set_check((task), (__c))->subsys[(subsys_id)]
 
 /**
@@ -695,87 +724,92 @@
 }
 
 /**
- * task_subsys_state - obtain css for (task, subsys)
+ * task_css - obtain css for (task, subsys)
  * @task: the target task
  * @subsys_id: the target subsystem ID
  *
- * See task_subsys_state_check().
+ * See task_css_check().
  */
-static inline struct cgroup_subsys_state *
-task_subsys_state(struct task_struct *task, int subsys_id)
+static inline struct cgroup_subsys_state *task_css(struct task_struct *task,
+						   int subsys_id)
 {
-	return task_subsys_state_check(task, subsys_id, false);
+	return task_css_check(task, subsys_id, false);
 }
 
-static inline struct cgroup* task_cgroup(struct task_struct *task,
-					       int subsys_id)
+static inline struct cgroup *task_cgroup(struct task_struct *task,
+					 int subsys_id)
 {
-	return task_subsys_state(task, subsys_id)->cgroup;
+	return task_css(task, subsys_id)->cgroup;
 }
 
-struct cgroup *cgroup_next_sibling(struct cgroup *pos);
+struct cgroup_subsys_state *css_next_child(struct cgroup_subsys_state *pos,
+					   struct cgroup_subsys_state *parent);
+
+struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss);
 
 /**
- * cgroup_for_each_child - iterate through children of a cgroup
- * @pos: the cgroup * to use as the loop cursor
- * @cgrp: cgroup whose children to walk
+ * css_for_each_child - iterate through children of a css
+ * @pos: the css * to use as the loop cursor
+ * @parent: css whose children to walk
  *
- * Walk @cgrp's children.  Must be called under rcu_read_lock().  A child
- * cgroup which hasn't finished ->css_online() or already has finished
+ * Walk @parent's children.  Must be called under rcu_read_lock().  A child
+ * css which hasn't finished ->css_online() or already has finished
  * ->css_offline() may show up during traversal and it's each subsystem's
  * responsibility to verify that each @pos is alive.
  *
  * If a subsystem synchronizes against the parent in its ->css_online() and
- * before starting iterating, a cgroup which finished ->css_online() is
+ * before starting iterating, a css which finished ->css_online() is
  * guaranteed to be visible in the future iterations.
  *
  * It is allowed to temporarily drop RCU read lock during iteration.  The
  * caller is responsible for ensuring that @pos remains accessible until
  * the start of the next iteration by, for example, bumping the css refcnt.
  */
-#define cgroup_for_each_child(pos, cgrp)				\
-	for ((pos) = list_first_or_null_rcu(&(cgrp)->children,		\
-					    struct cgroup, sibling);	\
-	     (pos); (pos) = cgroup_next_sibling((pos)))
+#define css_for_each_child(pos, parent)					\
+	for ((pos) = css_next_child(NULL, (parent)); (pos);		\
+	     (pos) = css_next_child((pos), (parent)))
 
-struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
-					  struct cgroup *cgroup);
-struct cgroup *cgroup_rightmost_descendant(struct cgroup *pos);
+struct cgroup_subsys_state *
+css_next_descendant_pre(struct cgroup_subsys_state *pos,
+			struct cgroup_subsys_state *css);
+
+struct cgroup_subsys_state *
+css_rightmost_descendant(struct cgroup_subsys_state *pos);
 
 /**
- * cgroup_for_each_descendant_pre - pre-order walk of a cgroup's descendants
- * @pos: the cgroup * to use as the loop cursor
- * @cgroup: cgroup whose descendants to walk
+ * css_for_each_descendant_pre - pre-order walk of a css's descendants
+ * @pos: the css * to use as the loop cursor
+ * @root: css whose descendants to walk
  *
- * Walk @cgroup's descendants.  Must be called under rcu_read_lock().  A
- * descendant cgroup which hasn't finished ->css_online() or already has
+ * Walk @root's descendants.  @root is included in the iteration and the
+ * first node to be visited.  Must be called under rcu_read_lock().  A
+ * descendant css which hasn't finished ->css_online() or already has
  * finished ->css_offline() may show up during traversal and it's each
  * subsystem's responsibility to verify that each @pos is alive.
  *
  * If a subsystem synchronizes against the parent in its ->css_online() and
  * before starting iterating, and synchronizes against @pos on each
- * iteration, any descendant cgroup which finished ->css_online() is
+ * iteration, any descendant css which finished ->css_online() is
  * guaranteed to be visible in the future iterations.
  *
  * In other words, the following guarantees that a descendant can't escape
  * state updates of its ancestors.
  *
- * my_online(@cgrp)
+ * my_online(@css)
  * {
- *	Lock @cgrp->parent and @cgrp;
- *	Inherit state from @cgrp->parent;
+ *	Lock @css's parent and @css;
+ *	Inherit state from the parent;
  *	Unlock both.
  * }
  *
- * my_update_state(@cgrp)
+ * my_update_state(@css)
  * {
- *	Lock @cgrp;
- *	Update @cgrp's state;
- *	Unlock @cgrp;
- *
- *	cgroup_for_each_descendant_pre(@pos, @cgrp) {
+ *	css_for_each_descendant_pre(@pos, @css) {
  *		Lock @pos;
- *		Verify @pos is alive and inherit state from @pos->parent;
+ *		if (@pos == @css)
+ *			Update @css's state;
+ *		else
+ *			Verify @pos is alive and inherit state from its parent;
  *		Unlock @pos;
  *	}
  * }
@@ -786,8 +820,7 @@
  * visible by walking order and, as long as inheriting operations to the
  * same @pos are atomic to each other, multiple updates racing each other
  * still result in the correct state.  It's guaranateed that at least one
- * inheritance happens for any cgroup after the latest update to its
- * parent.
+ * inheritance happens for any css after the latest update to its parent.
  *
  * If checking parent's state requires locking the parent, each inheriting
  * iteration should lock and unlock both @pos->parent and @pos.
@@ -800,52 +833,45 @@
  * caller is responsible for ensuring that @pos remains accessible until
  * the start of the next iteration by, for example, bumping the css refcnt.
  */
-#define cgroup_for_each_descendant_pre(pos, cgroup)			\
-	for (pos = cgroup_next_descendant_pre(NULL, (cgroup)); (pos);	\
-	     pos = cgroup_next_descendant_pre((pos), (cgroup)))
+#define css_for_each_descendant_pre(pos, css)				\
+	for ((pos) = css_next_descendant_pre(NULL, (css)); (pos);	\
+	     (pos) = css_next_descendant_pre((pos), (css)))
 
-struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
-					   struct cgroup *cgroup);
+struct cgroup_subsys_state *
+css_next_descendant_post(struct cgroup_subsys_state *pos,
+			 struct cgroup_subsys_state *css);
 
 /**
- * cgroup_for_each_descendant_post - post-order walk of a cgroup's descendants
- * @pos: the cgroup * to use as the loop cursor
- * @cgroup: cgroup whose descendants to walk
+ * css_for_each_descendant_post - post-order walk of a css's descendants
+ * @pos: the css * to use as the loop cursor
+ * @css: css whose descendants to walk
  *
- * Similar to cgroup_for_each_descendant_pre() but performs post-order
- * traversal instead.  Note that the walk visibility guarantee described in
- * pre-order walk doesn't apply the same to post-order walks.
+ * Similar to css_for_each_descendant_pre() but performs post-order
+ * traversal instead.  @root is included in the iteration and the last
+ * node to be visited.  Note that the walk visibility guarantee described
+ * in pre-order walk doesn't apply the same to post-order walks.
  */
-#define cgroup_for_each_descendant_post(pos, cgroup)			\
-	for (pos = cgroup_next_descendant_post(NULL, (cgroup)); (pos);	\
-	     pos = cgroup_next_descendant_post((pos), (cgroup)))
+#define css_for_each_descendant_post(pos, css)				\
+	for ((pos) = css_next_descendant_post(NULL, (css)); (pos);	\
+	     (pos) = css_next_descendant_post((pos), (css)))
 
-/* A cgroup_iter should be treated as an opaque object */
-struct cgroup_iter {
-	struct list_head *cset_link;
-	struct list_head *task;
+/* A css_task_iter should be treated as an opaque object */
+struct css_task_iter {
+	struct cgroup_subsys_state	*origin_css;
+	struct list_head		*cset_link;
+	struct list_head		*task;
 };
 
-/*
- * To iterate across the tasks in a cgroup:
- *
- * 1) call cgroup_iter_start to initialize an iterator
- *
- * 2) call cgroup_iter_next() to retrieve member tasks until it
- *    returns NULL or until you want to end the iteration
- *
- * 3) call cgroup_iter_end() to destroy the iterator.
- *
- * Or, call cgroup_scan_tasks() to iterate through every task in a
- * cgroup - cgroup_scan_tasks() holds the css_set_lock when calling
- * the test_task() callback, but not while calling the process_task()
- * callback.
- */
-void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it);
-struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
-					struct cgroup_iter *it);
-void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
-int cgroup_scan_tasks(struct cgroup_scanner *scan);
+void css_task_iter_start(struct cgroup_subsys_state *css,
+			 struct css_task_iter *it);
+struct task_struct *css_task_iter_next(struct css_task_iter *it);
+void css_task_iter_end(struct css_task_iter *it);
+
+int css_scan_tasks(struct cgroup_subsys_state *css,
+		   bool (*test)(struct task_struct *, void *),
+		   void (*process)(struct task_struct *, void *),
+		   void *data, struct ptr_heap *heap);
+
 int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
 int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
 
@@ -878,7 +904,8 @@
 
 /* Get id and depth of css */
 unsigned short css_id(struct cgroup_subsys_state *css);
-struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id);
+struct cgroup_subsys_state *css_from_dir(struct dentry *dentry,
+					 struct cgroup_subsys *ss);
 
 #else /* !CONFIG_CGROUPS */
 
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 7f0c1dd..ec1aee4 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -669,6 +669,13 @@
 
 int compat_restore_altstack(const compat_stack_t __user *uss);
 int __compat_save_altstack(compat_stack_t __user *, unsigned long);
+#define compat_save_altstack_ex(uss, sp) do { \
+	compat_stack_t __user *__uss = uss; \
+	struct task_struct *t = current; \
+	put_user_ex(ptr_to_compat((void __user *)t->sas_ss_sp), &__uss->ss_sp); \
+	put_user_ex(sas_ss_flags(sp), &__uss->ss_flags); \
+	put_user_ex(t->sas_ss_size, &__uss->ss_size); \
+} while (0);
 
 asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid,
 						 struct compat_timespec __user *interval);
diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h
index fc09d7b..1581587 100644
--- a/include/linux/context_tracking.h
+++ b/include/linux/context_tracking.h
@@ -2,100 +2,110 @@
 #define _LINUX_CONTEXT_TRACKING_H
 
 #include <linux/sched.h>
-#include <linux/percpu.h>
 #include <linux/vtime.h>
+#include <linux/context_tracking_state.h>
 #include <asm/ptrace.h>
 
-struct context_tracking {
-	/*
-	 * When active is false, probes are unset in order
-	 * to minimize overhead: TIF flags are cleared
-	 * and calls to user_enter/exit are ignored. This
-	 * may be further optimized using static keys.
-	 */
-	bool active;
-	enum ctx_state {
-		IN_KERNEL = 0,
-		IN_USER,
-	} state;
-};
-
-static inline void __guest_enter(void)
-{
-	/*
-	 * This is running in ioctl context so we can avoid
-	 * the call to vtime_account() with its unnecessary idle check.
-	 */
-	vtime_account_system(current);
-	current->flags |= PF_VCPU;
-}
-
-static inline void __guest_exit(void)
-{
-	/*
-	 * This is running in ioctl context so we can avoid
-	 * the call to vtime_account() with its unnecessary idle check.
-	 */
-	vtime_account_system(current);
-	current->flags &= ~PF_VCPU;
-}
 
 #ifdef CONFIG_CONTEXT_TRACKING
-DECLARE_PER_CPU(struct context_tracking, context_tracking);
+extern void context_tracking_cpu_set(int cpu);
 
-static inline bool context_tracking_in_user(void)
+extern void context_tracking_user_enter(void);
+extern void context_tracking_user_exit(void);
+extern void __context_tracking_task_switch(struct task_struct *prev,
+					   struct task_struct *next);
+
+static inline void user_enter(void)
 {
-	return __this_cpu_read(context_tracking.state) == IN_USER;
-}
+	if (static_key_false(&context_tracking_enabled))
+		context_tracking_user_enter();
 
-static inline bool context_tracking_active(void)
+}
+static inline void user_exit(void)
 {
-	return __this_cpu_read(context_tracking.active);
+	if (static_key_false(&context_tracking_enabled))
+		context_tracking_user_exit();
 }
 
-extern void user_enter(void);
-extern void user_exit(void);
-
-extern void guest_enter(void);
-extern void guest_exit(void);
-
 static inline enum ctx_state exception_enter(void)
 {
 	enum ctx_state prev_ctx;
 
+	if (!static_key_false(&context_tracking_enabled))
+		return 0;
+
 	prev_ctx = this_cpu_read(context_tracking.state);
-	user_exit();
+	context_tracking_user_exit();
 
 	return prev_ctx;
 }
 
 static inline void exception_exit(enum ctx_state prev_ctx)
 {
-	if (prev_ctx == IN_USER)
-		user_enter();
+	if (static_key_false(&context_tracking_enabled)) {
+		if (prev_ctx == IN_USER)
+			context_tracking_user_enter();
+	}
 }
 
-extern void context_tracking_task_switch(struct task_struct *prev,
-					 struct task_struct *next);
+static inline void context_tracking_task_switch(struct task_struct *prev,
+						struct task_struct *next)
+{
+	if (static_key_false(&context_tracking_enabled))
+		__context_tracking_task_switch(prev, next);
+}
 #else
-static inline bool context_tracking_in_user(void) { return false; }
 static inline void user_enter(void) { }
 static inline void user_exit(void) { }
-
-static inline void guest_enter(void)
-{
-	__guest_enter();
-}
-
-static inline void guest_exit(void)
-{
-	__guest_exit();
-}
-
 static inline enum ctx_state exception_enter(void) { return 0; }
 static inline void exception_exit(enum ctx_state prev_ctx) { }
 static inline void context_tracking_task_switch(struct task_struct *prev,
 						struct task_struct *next) { }
 #endif /* !CONFIG_CONTEXT_TRACKING */
 
+
+#ifdef CONFIG_CONTEXT_TRACKING_FORCE
+extern void context_tracking_init(void);
+#else
+static inline void context_tracking_init(void) { }
+#endif /* CONFIG_CONTEXT_TRACKING_FORCE */
+
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+static inline void guest_enter(void)
+{
+	if (vtime_accounting_enabled())
+		vtime_guest_enter(current);
+	else
+		current->flags |= PF_VCPU;
+}
+
+static inline void guest_exit(void)
+{
+	if (vtime_accounting_enabled())
+		vtime_guest_exit(current);
+	else
+		current->flags &= ~PF_VCPU;
+}
+
+#else
+static inline void guest_enter(void)
+{
+	/*
+	 * This is running in ioctl context so its safe
+	 * to assume that it's the stime pending cputime
+	 * to flush.
+	 */
+	vtime_account_system(current);
+	current->flags |= PF_VCPU;
+}
+
+static inline void guest_exit(void)
+{
+	/* Flush the guest cputime we spent on the guest */
+	vtime_account_system(current);
+	current->flags &= ~PF_VCPU;
+}
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
+
 #endif
diff --git a/include/linux/context_tracking_state.h b/include/linux/context_tracking_state.h
new file mode 100644
index 0000000..0f1979d
--- /dev/null
+++ b/include/linux/context_tracking_state.h
@@ -0,0 +1,39 @@
+#ifndef _LINUX_CONTEXT_TRACKING_STATE_H
+#define _LINUX_CONTEXT_TRACKING_STATE_H
+
+#include <linux/percpu.h>
+#include <linux/static_key.h>
+
+struct context_tracking {
+	/*
+	 * When active is false, probes are unset in order
+	 * to minimize overhead: TIF flags are cleared
+	 * and calls to user_enter/exit are ignored. This
+	 * may be further optimized using static keys.
+	 */
+	bool active;
+	enum ctx_state {
+		IN_KERNEL = 0,
+		IN_USER,
+	} state;
+};
+
+#ifdef CONFIG_CONTEXT_TRACKING
+extern struct static_key context_tracking_enabled;
+DECLARE_PER_CPU(struct context_tracking, context_tracking);
+
+static inline bool context_tracking_in_user(void)
+{
+	return __this_cpu_read(context_tracking.state) == IN_USER;
+}
+
+static inline bool context_tracking_active(void)
+{
+	return __this_cpu_read(context_tracking.active);
+}
+#else
+static inline bool context_tracking_in_user(void) { return false; }
+static inline bool context_tracking_active(void) { return false; }
+#endif /* CONFIG_CONTEXT_TRACKING */
+
+#endif
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ab0eade..801ff9e 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -28,6 +28,7 @@
 extern int register_cpu(struct cpu *cpu, int num);
 extern struct device *get_cpu_device(unsigned cpu);
 extern bool cpu_is_hotpluggable(unsigned cpu);
+extern bool arch_match_cpu_phys_id(int cpu, u64 phys_id);
 
 extern int cpu_add_dev_attr(struct device_attribute *attr);
 extern void cpu_remove_dev_attr(struct device_attribute *attr);
@@ -172,6 +173,8 @@
 #ifdef CONFIG_HOTPLUG_CPU
 /* Stop CPUs going up and down. */
 
+extern void cpu_hotplug_begin(void);
+extern void cpu_hotplug_done(void);
 extern void get_online_cpus(void);
 extern void put_online_cpus(void);
 extern void cpu_hotplug_disable(void);
@@ -197,6 +200,8 @@
 
 #else		/* CONFIG_HOTPLUG_CPU */
 
+static inline void cpu_hotplug_begin(void) {}
+static inline void cpu_hotplug_done(void) {}
 #define get_online_cpus()	do { } while (0)
 #define put_online_cpus()	do { } while (0)
 #define cpu_hotplug_disable()	do { } while (0)
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 90d5a15..d568f39 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -11,71 +11,36 @@
 #ifndef _LINUX_CPUFREQ_H
 #define _LINUX_CPUFREQ_H
 
-#include <asm/cputime.h>
-#include <linux/mutex.h>
-#include <linux/notifier.h>
-#include <linux/threads.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include <linux/completion.h>
-#include <linux/workqueue.h>
 #include <linux/cpumask.h>
-#include <asm/div64.h>
-
-#define CPUFREQ_NAME_LEN 16
-/* Print length for names. Extra 1 space for accomodating '\n' in prints */
-#define CPUFREQ_NAME_PLEN (CPUFREQ_NAME_LEN + 1)
+#include <linux/completion.h>
+#include <linux/kobject.h>
+#include <linux/notifier.h>
+#include <linux/sysfs.h>
 
 /*********************************************************************
- *                     CPUFREQ NOTIFIER INTERFACE                    *
+ *                        CPUFREQ INTERFACE                          *
  *********************************************************************/
-
-#define CPUFREQ_TRANSITION_NOTIFIER	(0)
-#define CPUFREQ_POLICY_NOTIFIER		(1)
-
-#ifdef CONFIG_CPU_FREQ
-int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
-int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
-extern void disable_cpufreq(void);
-#else		/* CONFIG_CPU_FREQ */
-static inline int cpufreq_register_notifier(struct notifier_block *nb,
-						unsigned int list)
-{
-	return 0;
-}
-static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
-						unsigned int list)
-{
-	return 0;
-}
-static inline void disable_cpufreq(void) { }
-#endif		/* CONFIG_CPU_FREQ */
-
-/* if (cpufreq_driver->target) exists, the ->governor decides what frequency
- * within the limits is used. If (cpufreq_driver->setpolicy> exists, these
- * two generic policies are available:
- */
-
-#define CPUFREQ_POLICY_POWERSAVE	(1)
-#define CPUFREQ_POLICY_PERFORMANCE	(2)
-
-/* Frequency values here are CPU kHz so that hardware which doesn't run
- * with some frequencies can complain without having to guess what per
- * cent / per mille means.
+/*
+ * Frequency values here are CPU kHz
+ *
  * Maximum transition latency is in nanoseconds - if it's unknown,
  * CPUFREQ_ETERNAL shall be used.
  */
 
+#define CPUFREQ_ETERNAL			(-1)
+#define CPUFREQ_NAME_LEN		16
+/* Print length for names. Extra 1 space for accomodating '\n' in prints */
+#define CPUFREQ_NAME_PLEN		(CPUFREQ_NAME_LEN + 1)
+
 struct cpufreq_governor;
 
-/* /sys/devices/system/cpu/cpufreq: entry point for global variables */
-extern struct kobject *cpufreq_global_kobject;
-int cpufreq_get_global_kobject(void);
-void cpufreq_put_global_kobject(void);
-int cpufreq_sysfs_create_file(const struct attribute *attr);
-void cpufreq_sysfs_remove_file(const struct attribute *attr);
+struct cpufreq_freqs {
+	unsigned int cpu;	/* cpu nr */
+	unsigned int old;
+	unsigned int new;
+	u8 flags;		/* flags of cpufreq_driver, see below. */
+};
 
-#define CPUFREQ_ETERNAL			(-1)
 struct cpufreq_cpuinfo {
 	unsigned int		max_freq;
 	unsigned int		min_freq;
@@ -117,111 +82,59 @@
 
 	struct cpufreq_real_policy	user_policy;
 
+	struct list_head        policy_list;
 	struct kobject		kobj;
 	struct completion	kobj_unregister;
 	int			transition_ongoing; /* Tracks transition status */
 };
 
-#define CPUFREQ_ADJUST			(0)
-#define CPUFREQ_INCOMPATIBLE		(1)
-#define CPUFREQ_NOTIFY			(2)
-#define CPUFREQ_START			(3)
-#define CPUFREQ_UPDATE_POLICY_CPU	(4)
-
 /* Only for ACPI */
 #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */
 #define CPUFREQ_SHARED_TYPE_HW	 (1) /* HW does needed coordination */
 #define CPUFREQ_SHARED_TYPE_ALL	 (2) /* All dependent CPUs should set freq */
 #define CPUFREQ_SHARED_TYPE_ANY	 (3) /* Freq can be set from any dependent CPU*/
 
+struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
+void cpufreq_cpu_put(struct cpufreq_policy *policy);
+
 static inline bool policy_is_shared(struct cpufreq_policy *policy)
 {
 	return cpumask_weight(policy->cpus) > 1;
 }
 
-/******************** cpufreq transition notifiers *******************/
+/* /sys/devices/system/cpu/cpufreq: entry point for global variables */
+extern struct kobject *cpufreq_global_kobject;
+int cpufreq_get_global_kobject(void);
+void cpufreq_put_global_kobject(void);
+int cpufreq_sysfs_create_file(const struct attribute *attr);
+void cpufreq_sysfs_remove_file(const struct attribute *attr);
 
-#define CPUFREQ_PRECHANGE	(0)
-#define CPUFREQ_POSTCHANGE	(1)
-#define CPUFREQ_RESUMECHANGE	(8)
-#define CPUFREQ_SUSPENDCHANGE	(9)
+#ifdef CONFIG_CPU_FREQ
+unsigned int cpufreq_get(unsigned int cpu);
+unsigned int cpufreq_quick_get(unsigned int cpu);
+unsigned int cpufreq_quick_get_max(unsigned int cpu);
+void disable_cpufreq(void);
 
-struct cpufreq_freqs {
-	unsigned int cpu;	/* cpu nr */
-	unsigned int old;
-	unsigned int new;
-	u8 flags;		/* flags of cpufreq_driver, see below. */
-};
-
-/**
- * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch
- * safe)
- * @old:   old value
- * @div:   divisor
- * @mult:  multiplier
- *
- *
- * new = old * mult / div
- */
-static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
-		u_int mult)
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
+int cpufreq_update_policy(unsigned int cpu);
+bool have_governor_per_policy(void);
+struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy);
+#else
+static inline unsigned int cpufreq_get(unsigned int cpu)
 {
-#if BITS_PER_LONG == 32
-
-	u64 result = ((u64) old) * ((u64) mult);
-	do_div(result, div);
-	return (unsigned long) result;
-
-#elif BITS_PER_LONG == 64
-
-	unsigned long result = old * ((u64) mult);
-	result /= div;
-	return result;
-
+	return 0;
+}
+static inline unsigned int cpufreq_quick_get(unsigned int cpu)
+{
+	return 0;
+}
+static inline unsigned int cpufreq_quick_get_max(unsigned int cpu)
+{
+	return 0;
+}
+static inline void disable_cpufreq(void) { }
 #endif
-};
-
-/*********************************************************************
- *                          CPUFREQ GOVERNORS                        *
- *********************************************************************/
-
-#define CPUFREQ_GOV_START	1
-#define CPUFREQ_GOV_STOP	2
-#define CPUFREQ_GOV_LIMITS	3
-#define CPUFREQ_GOV_POLICY_INIT	4
-#define CPUFREQ_GOV_POLICY_EXIT	5
-
-struct cpufreq_governor {
-	char	name[CPUFREQ_NAME_LEN];
-	int	initialized;
-	int	(*governor)	(struct cpufreq_policy *policy,
-				 unsigned int event);
-	ssize_t	(*show_setspeed)	(struct cpufreq_policy *policy,
-					 char *buf);
-	int	(*store_setspeed)	(struct cpufreq_policy *policy,
-					 unsigned int freq);
-	unsigned int max_transition_latency; /* HW must be able to switch to
-			next freq faster than this value in nano secs or we
-			will fallback to performance governor */
-	struct list_head	governor_list;
-	struct module		*owner;
-};
-
-/*
- * Pass a target to the cpufreq driver.
- */
-extern int cpufreq_driver_target(struct cpufreq_policy *policy,
-				 unsigned int target_freq,
-				 unsigned int relation);
-extern int __cpufreq_driver_target(struct cpufreq_policy *policy,
-				   unsigned int target_freq,
-				   unsigned int relation);
-
-extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
-				   unsigned int cpu);
-
-int cpufreq_register_governor(struct cpufreq_governor *governor);
-void cpufreq_unregister_governor(struct cpufreq_governor *governor);
 
 /*********************************************************************
  *                      CPUFREQ DRIVER INTERFACE                     *
@@ -230,76 +143,6 @@
 #define CPUFREQ_RELATION_L 0  /* lowest frequency at or above target */
 #define CPUFREQ_RELATION_H 1  /* highest frequency below or at target */
 
-struct freq_attr;
-
-struct cpufreq_driver {
-	struct module		*owner;
-	char			name[CPUFREQ_NAME_LEN];
-	u8			flags;
-	/*
-	 * This should be set by platforms having multiple clock-domains, i.e.
-	 * supporting multiple policies. With this sysfs directories of governor
-	 * would be created in cpu/cpu<num>/cpufreq/ directory and so they can
-	 * use the same governor with different tunables for different clusters.
-	 */
-	bool			have_governor_per_policy;
-
-	/* needed by all drivers */
-	int	(*init)		(struct cpufreq_policy *policy);
-	int	(*verify)	(struct cpufreq_policy *policy);
-
-	/* define one out of two */
-	int	(*setpolicy)	(struct cpufreq_policy *policy);
-	int	(*target)	(struct cpufreq_policy *policy,
-				 unsigned int target_freq,
-				 unsigned int relation);
-
-	/* should be defined, if possible */
-	unsigned int	(*get)	(unsigned int cpu);
-
-	/* optional */
-	unsigned int (*getavg)	(struct cpufreq_policy *policy,
-				 unsigned int cpu);
-	int	(*bios_limit)	(int cpu, unsigned int *limit);
-
-	int	(*exit)		(struct cpufreq_policy *policy);
-	int	(*suspend)	(struct cpufreq_policy *policy);
-	int	(*resume)	(struct cpufreq_policy *policy);
-	struct freq_attr	**attr;
-};
-
-/* flags */
-
-#define CPUFREQ_STICKY		0x01	/* the driver isn't removed even if
-					 * all ->init() calls failed */
-#define CPUFREQ_CONST_LOOPS	0x02	/* loops_per_jiffy or other kernel
-					 * "constants" aren't affected by
-					 * frequency transitions */
-#define CPUFREQ_PM_NO_WARN	0x04	/* don't warn on suspend/resume speed
-					 * mismatches */
-
-int cpufreq_register_driver(struct cpufreq_driver *driver_data);
-int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
-
-void cpufreq_notify_transition(struct cpufreq_policy *policy,
-		struct cpufreq_freqs *freqs, unsigned int state);
-
-static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
-		unsigned int min, unsigned int max)
-{
-	if (policy->min < min)
-		policy->min = min;
-	if (policy->max < min)
-		policy->max = min;
-	if (policy->min > max)
-		policy->min = max;
-	if (policy->max > max)
-		policy->max = max;
-	if (policy->min > policy->max)
-		policy->min = policy->max;
-	return;
-}
-
 struct freq_attr {
 	struct attribute attr;
 	ssize_t (*show)(struct cpufreq_policy *, char *);
@@ -334,52 +177,181 @@
 static struct global_attr _name =		\
 __ATTR(_name, 0644, show_##_name, store_##_name)
 
-struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
-void cpufreq_cpu_put(struct cpufreq_policy *data);
+
+struct cpufreq_driver {
+	char			name[CPUFREQ_NAME_LEN];
+	u8			flags;
+	/*
+	 * This should be set by platforms having multiple clock-domains, i.e.
+	 * supporting multiple policies. With this sysfs directories of governor
+	 * would be created in cpu/cpu<num>/cpufreq/ directory and so they can
+	 * use the same governor with different tunables for different clusters.
+	 */
+	bool			have_governor_per_policy;
+
+	/* needed by all drivers */
+	int	(*init)		(struct cpufreq_policy *policy);
+	int	(*verify)	(struct cpufreq_policy *policy);
+
+	/* define one out of two */
+	int	(*setpolicy)	(struct cpufreq_policy *policy);
+	int	(*target)	(struct cpufreq_policy *policy,
+				 unsigned int target_freq,
+				 unsigned int relation);
+
+	/* should be defined, if possible */
+	unsigned int	(*get)	(unsigned int cpu);
+
+	/* optional */
+	int	(*bios_limit)	(int cpu, unsigned int *limit);
+
+	int	(*exit)		(struct cpufreq_policy *policy);
+	int	(*suspend)	(struct cpufreq_policy *policy);
+	int	(*resume)	(struct cpufreq_policy *policy);
+	struct freq_attr	**attr;
+};
+
+/* flags */
+#define CPUFREQ_STICKY		0x01	/* the driver isn't removed even if
+					 * all ->init() calls failed */
+#define CPUFREQ_CONST_LOOPS	0x02	/* loops_per_jiffy or other kernel
+					 * "constants" aren't affected by
+					 * frequency transitions */
+#define CPUFREQ_PM_NO_WARN	0x04	/* don't warn on suspend/resume speed
+					 * mismatches */
+
+int cpufreq_register_driver(struct cpufreq_driver *driver_data);
+int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
+
 const char *cpufreq_get_current_driver(void);
 
-/*********************************************************************
- *                        CPUFREQ 2.6. INTERFACE                     *
- *********************************************************************/
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
-int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
-int cpufreq_update_policy(unsigned int cpu);
-bool have_governor_per_policy(void);
-struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy);
-
-#ifdef CONFIG_CPU_FREQ
-/*
- * query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it
- */
-unsigned int cpufreq_get(unsigned int cpu);
-#else
-static inline unsigned int cpufreq_get(unsigned int cpu)
+static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
+		unsigned int min, unsigned int max)
 {
-	return 0;
+	if (policy->min < min)
+		policy->min = min;
+	if (policy->max < min)
+		policy->max = min;
+	if (policy->min > max)
+		policy->min = max;
+	if (policy->max > max)
+		policy->max = max;
+	if (policy->min > policy->max)
+		policy->min = policy->max;
+	return;
 }
-#endif
-
-/*
- * query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it
- */
-#ifdef CONFIG_CPU_FREQ
-unsigned int cpufreq_quick_get(unsigned int cpu);
-unsigned int cpufreq_quick_get_max(unsigned int cpu);
-#else
-static inline unsigned int cpufreq_quick_get(unsigned int cpu)
-{
-	return 0;
-}
-static inline unsigned int cpufreq_quick_get_max(unsigned int cpu)
-{
-	return 0;
-}
-#endif
 
 /*********************************************************************
- *                       CPUFREQ DEFAULT GOVERNOR                    *
+ *                     CPUFREQ NOTIFIER INTERFACE                    *
  *********************************************************************/
 
+#define CPUFREQ_TRANSITION_NOTIFIER	(0)
+#define CPUFREQ_POLICY_NOTIFIER		(1)
+
+/* Transition notifiers */
+#define CPUFREQ_PRECHANGE		(0)
+#define CPUFREQ_POSTCHANGE		(1)
+#define CPUFREQ_RESUMECHANGE		(8)
+#define CPUFREQ_SUSPENDCHANGE		(9)
+
+/* Policy Notifiers  */
+#define CPUFREQ_ADJUST			(0)
+#define CPUFREQ_INCOMPATIBLE		(1)
+#define CPUFREQ_NOTIFY			(2)
+#define CPUFREQ_START			(3)
+#define CPUFREQ_UPDATE_POLICY_CPU	(4)
+
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+void cpufreq_notify_transition(struct cpufreq_policy *policy,
+		struct cpufreq_freqs *freqs, unsigned int state);
+
+#else /* CONFIG_CPU_FREQ */
+static inline int cpufreq_register_notifier(struct notifier_block *nb,
+						unsigned int list)
+{
+	return 0;
+}
+static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
+						unsigned int list)
+{
+	return 0;
+}
+#endif /* !CONFIG_CPU_FREQ */
+
+/**
+ * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch
+ * safe)
+ * @old:   old value
+ * @div:   divisor
+ * @mult:  multiplier
+ *
+ *
+ * new = old * mult / div
+ */
+static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
+		u_int mult)
+{
+#if BITS_PER_LONG == 32
+	u64 result = ((u64) old) * ((u64) mult);
+	do_div(result, div);
+	return (unsigned long) result;
+
+#elif BITS_PER_LONG == 64
+	unsigned long result = old * ((u64) mult);
+	result /= div;
+	return result;
+#endif
+}
+
+/*********************************************************************
+ *                          CPUFREQ GOVERNORS                        *
+ *********************************************************************/
+
+/*
+ * If (cpufreq_driver->target) exists, the ->governor decides what frequency
+ * within the limits is used. If (cpufreq_driver->setpolicy> exists, these
+ * two generic policies are available:
+ */
+#define CPUFREQ_POLICY_POWERSAVE	(1)
+#define CPUFREQ_POLICY_PERFORMANCE	(2)
+
+/* Governor Events */
+#define CPUFREQ_GOV_START	1
+#define CPUFREQ_GOV_STOP	2
+#define CPUFREQ_GOV_LIMITS	3
+#define CPUFREQ_GOV_POLICY_INIT	4
+#define CPUFREQ_GOV_POLICY_EXIT	5
+
+struct cpufreq_governor {
+	char	name[CPUFREQ_NAME_LEN];
+	int	initialized;
+	int	(*governor)	(struct cpufreq_policy *policy,
+				 unsigned int event);
+	ssize_t	(*show_setspeed)	(struct cpufreq_policy *policy,
+					 char *buf);
+	int	(*store_setspeed)	(struct cpufreq_policy *policy,
+					 unsigned int freq);
+	unsigned int max_transition_latency; /* HW must be able to switch to
+			next freq faster than this value in nano secs or we
+			will fallback to performance governor */
+	struct list_head	governor_list;
+	struct module		*owner;
+};
+
+/* Pass a target to the cpufreq driver */
+int cpufreq_driver_target(struct cpufreq_policy *policy,
+				 unsigned int target_freq,
+				 unsigned int relation);
+int __cpufreq_driver_target(struct cpufreq_policy *policy,
+				   unsigned int target_freq,
+				   unsigned int relation);
+int cpufreq_register_governor(struct cpufreq_governor *governor);
+void cpufreq_unregister_governor(struct cpufreq_governor *governor);
+
+/* CPUFREQ DEFAULT GOVERNOR */
 /*
  * Performance governor is fallback governor if any other gov failed to auto
  * load due latency restrictions
@@ -428,18 +400,16 @@
 				   unsigned int relation,
 				   unsigned int *index);
 
-/* the following 3 funtions are for cpufreq core use only */
+void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
+ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
+
+/* the following funtion is for cpufreq core use only */
 struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
 
 /* the following are really really optional */
 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
-
 void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
 				      unsigned int cpu);
-void cpufreq_frequency_table_update_policy_cpu(struct cpufreq_policy *policy);
-
 void cpufreq_frequency_table_put_attr(unsigned int cpu);
 
-ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf);
-
 #endif /* _LINUX_CPUFREQ_H */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 0bc4b74..781addc 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -13,8 +13,6 @@
 
 #include <linux/percpu.h>
 #include <linux/list.h>
-#include <linux/kobject.h>
-#include <linux/completion.h>
 #include <linux/hrtimer.h>
 
 #define CPUIDLE_STATE_MAX	10
@@ -61,6 +59,10 @@
 
 #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
 
+struct cpuidle_device_kobj;
+struct cpuidle_state_kobj;
+struct cpuidle_driver_kobj;
+
 struct cpuidle_device {
 	unsigned int		registered:1;
 	unsigned int		enabled:1;
@@ -71,9 +73,8 @@
 	struct cpuidle_state_usage	states_usage[CPUIDLE_STATE_MAX];
 	struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
 	struct cpuidle_driver_kobj *kobj_driver;
+	struct cpuidle_device_kobj *kobj_dev;
 	struct list_head 	device_list;
-	struct kobject		kobj;
-	struct completion	kobj_unregister;
 
 #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
 	int			safe_state_index;
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 4a12532..9169b91 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -9,6 +9,7 @@
 #include <linux/seqlock.h>
 #include <linux/cache.h>
 #include <linux/rcupdate.h>
+#include <linux/lockref.h>
 
 struct nameidata;
 struct path;
@@ -100,6 +101,8 @@
 # endif
 #endif
 
+#define d_lock	d_lockref.lock
+
 struct dentry {
 	/* RCU lookup touched fields */
 	unsigned int d_flags;		/* protected by d_lock */
@@ -112,8 +115,7 @@
 	unsigned char d_iname[DNAME_INLINE_LEN];	/* small names */
 
 	/* Ref lookup also touches following */
-	unsigned int d_count;		/* protected by d_lock */
-	spinlock_t d_lock;		/* per dentry lock */
+	struct lockref d_lockref;	/* per-dentry lock and refcount */
 	const struct dentry_operations *d_op;
 	struct super_block *d_sb;	/* The root of the dentry tree */
 	unsigned long d_time;		/* used by d_revalidate */
@@ -302,31 +304,9 @@
 extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
 				const struct qstr *name, unsigned *seq);
 
-/**
- * __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok
- * @dentry: dentry to take a ref on
- * @seq: seqcount to verify against
- * Returns: 0 on failure, else 1.
- *
- * __d_rcu_to_refcount operates on a dentry,seq pair that was returned
- * by __d_lookup_rcu, to get a reference on an rcu-walk dentry.
- */
-static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq)
-{
-	int ret = 0;
-
-	assert_spin_locked(&dentry->d_lock);
-	if (!read_seqcount_retry(&dentry->d_seq, seq)) {
-		ret = 1;
-		dentry->d_count++;
-	}
-
-	return ret;
-}
-
 static inline unsigned d_count(const struct dentry *dentry)
 {
-	return dentry->d_count;
+	return dentry->d_lockref.count;
 }
 
 /* validate "insecure" dentry pointer */
@@ -357,17 +337,14 @@
 static inline struct dentry *dget_dlock(struct dentry *dentry)
 {
 	if (dentry)
-		dentry->d_count++;
+		dentry->d_lockref.count++;
 	return dentry;
 }
 
 static inline struct dentry *dget(struct dentry *dentry)
 {
-	if (dentry) {
-		spin_lock(&dentry->d_lock);
-		dget_dlock(dentry);
-		spin_unlock(&dentry->d_lock);
-	}
+	if (dentry)
+		lockref_get(&dentry->d_lockref);
 	return dentry;
 }
 
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index d68b4ea..263489d 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -192,6 +192,13 @@
 	return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_x64(const char *name, umode_t mode,
+						struct dentry *parent,
+						u64 *value)
+{
+	return ERR_PTR(-ENODEV);
+}
+
 static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
 				     struct dentry *parent,
 				     size_t *value)
diff --git a/include/linux/debugobjects.h b/include/linux/debugobjects.h
index 0e5f578..98ffcbd 100644
--- a/include/linux/debugobjects.h
+++ b/include/linux/debugobjects.h
@@ -63,7 +63,7 @@
 extern void debug_object_init      (void *addr, struct debug_obj_descr *descr);
 extern void
 debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr);
-extern void debug_object_activate  (void *addr, struct debug_obj_descr *descr);
+extern int debug_object_activate  (void *addr, struct debug_obj_descr *descr);
 extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
 extern void debug_object_destroy   (void *addr, struct debug_obj_descr *descr);
 extern void debug_object_free      (void *addr, struct debug_obj_descr *descr);
@@ -85,8 +85,8 @@
 debug_object_init      (void *addr, struct debug_obj_descr *descr) { }
 static inline void
 debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { }
-static inline void
-debug_object_activate  (void *addr, struct debug_obj_descr *descr) { }
+static inline int
+debug_object_activate  (void *addr, struct debug_obj_descr *descr) { return 0; }
 static inline void
 debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { }
 static inline void
diff --git a/include/linux/device.h b/include/linux/device.h
index 22b546a..f46646e 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -66,6 +66,9 @@
  * @bus_attrs:	Default attributes of the bus.
  * @dev_attrs:	Default attributes of the devices on the bus.
  * @drv_attrs:	Default attributes of the device drivers on the bus.
+ * @bus_groups:	Default attributes of the bus.
+ * @dev_groups:	Default attributes of the devices on the bus.
+ * @drv_groups: Default attributes of the device drivers on the bus.
  * @match:	Called, perhaps multiple times, whenever a new device or driver
  *		is added for this bus. It should return a nonzero value if the
  *		given device can be handled by the given driver.
@@ -103,9 +106,12 @@
 	const char		*name;
 	const char		*dev_name;
 	struct device		*dev_root;
-	struct bus_attribute	*bus_attrs;
-	struct device_attribute	*dev_attrs;
-	struct driver_attribute	*drv_attrs;
+	struct bus_attribute	*bus_attrs;	/* use bus_groups instead */
+	struct device_attribute	*dev_attrs;	/* use dev_groups instead */
+	struct driver_attribute	*drv_attrs;	/* use drv_groups instead */
+	const struct attribute_group **bus_groups;
+	const struct attribute_group **dev_groups;
+	const struct attribute_group **drv_groups;
 
 	int (*match)(struct device *dev, struct device_driver *drv);
 	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
@@ -271,6 +277,8 @@
 	struct driver_attribute driver_attr_##_name = __ATTR_RW(_name)
 #define DRIVER_ATTR_RO(_name) \
 	struct driver_attribute driver_attr_##_name = __ATTR_RO(_name)
+#define DRIVER_ATTR_WO(_name) \
+	struct driver_attribute driver_attr_##_name = __ATTR_WO(_name)
 
 extern int __must_check driver_create_file(struct device_driver *driver,
 					const struct driver_attribute *attr);
@@ -528,6 +536,8 @@
 	struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
 #define DEVICE_ATTR_RO(_name) \
 	struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
+#define DEVICE_ATTR_WO(_name) \
+	struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
 #define DEVICE_ULONG_ATTR(_name, _mode, _var) \
 	struct dev_ext_attribute dev_attr_##_name = \
 		{ __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
@@ -895,6 +905,7 @@
 
 extern void lock_device_hotplug(void);
 extern void unlock_device_hotplug(void);
+extern int lock_device_hotplug_sysfs(void);
 extern int device_offline(struct device *dev);
 extern int device_online(struct device *dev);
 /*
@@ -1099,7 +1110,8 @@
 	dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__)
 #define dev_info_ratelimited(dev, fmt, ...)				\
 	dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__)
-#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
+/* descriptor check is first to prevent flooding with "callbacks suppressed" */
 #define dev_dbg_ratelimited(dev, fmt, ...)				\
 do {									\
 	static DEFINE_RATELIMIT_STATE(_rs,				\
@@ -1108,8 +1120,17 @@
 	DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);			\
 	if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) &&	\
 	    __ratelimit(&_rs))						\
-		__dynamic_pr_debug(&descriptor, pr_fmt(fmt),		\
-				   ##__VA_ARGS__);			\
+		__dynamic_dev_dbg(&descriptor, dev, fmt,		\
+				  ##__VA_ARGS__);			\
+} while (0)
+#elif defined(DEBUG)
+#define dev_dbg_ratelimited(dev, fmt, ...)				\
+do {									\
+	static DEFINE_RATELIMIT_STATE(_rs,				\
+				      DEFAULT_RATELIMIT_INTERVAL,	\
+				      DEFAULT_RATELIMIT_BURST);		\
+	if (__ratelimit(&_rs))						\
+		dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);	\
 } while (0)
 #else
 #define dev_dbg_ratelimited(dev, fmt, ...)			\
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 01b5c84..00141d3 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -57,7 +57,7 @@
 struct page;
 struct device;
 
-#ifdef CONFIG_CMA
+#ifdef CONFIG_DMA_CMA
 
 /*
  * There is always at least global CMA area and a few optional device
diff --git a/include/linux/err.h b/include/linux/err.h
index 221fcfb..15f92e0 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -52,7 +52,7 @@
 	return (void *) ptr;
 }
 
-static inline int __must_check PTR_RET(__force const void *ptr)
+static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
 {
 	if (IS_ERR(ptr))
 		return PTR_ERR(ptr);
@@ -60,6 +60,9 @@
 		return 0;
 }
 
+/* Deprecated */
+#define PTR_RET(p) PTR_ERR_OR_ZERO(p)
+
 #endif
 
 #endif /* _LINUX_ERR_H */
diff --git a/include/linux/extcon/of_extcon.h b/include/linux/extcon/of_extcon.h
new file mode 100644
index 0000000..0ebfeff
--- /dev/null
+++ b/include/linux/extcon/of_extcon.h
@@ -0,0 +1,31 @@
+/*
+ * OF helpers for External connector (extcon) framework
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ * Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * Chanwoo Choi <cw00.choi@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 __LINUX_OF_EXTCON_H
+#define __LINUX_OF_EXTCON_H
+
+#include <linux/err.h>
+
+#if IS_ENABLED(CONFIG_OF_EXTCON)
+extern struct extcon_dev
+	*of_extcon_get_extcon_dev(struct device *dev, int index);
+#else
+static inline struct extcon_dev
+	*of_extcon_get_extcon_dev(struct device *dev, int index)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_OF_EXTCON */
+#endif /* __LINUX_OF_EXTCON_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c901387..3b4cd82 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2506,6 +2506,7 @@
 extern int vfs_getattr(struct path *, struct kstat *);
 void __inode_add_bytes(struct inode *inode, loff_t bytes);
 void inode_add_bytes(struct inode *inode, loff_t bytes);
+void __inode_sub_bytes(struct inode *inode, loff_t bytes);
 void inode_sub_bytes(struct inode *inode, loff_t bytes);
 loff_t inode_get_bytes(struct inode *inode);
 void inode_set_bytes(struct inode *inode, loff_t bytes);
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 120d57a..5eaa746 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -359,6 +359,40 @@
 		__trace_printk(ip, fmt, ##args);			\
 } while (0)
 
+/**
+ * tracepoint_string - register constant persistent string to trace system
+ * @str - a constant persistent string that will be referenced in tracepoints
+ *
+ * If constant strings are being used in tracepoints, it is faster and
+ * more efficient to just save the pointer to the string and reference
+ * that with a printf "%s" instead of saving the string in the ring buffer
+ * and wasting space and time.
+ *
+ * The problem with the above approach is that userspace tools that read
+ * the binary output of the trace buffers do not have access to the string.
+ * Instead they just show the address of the string which is not very
+ * useful to users.
+ *
+ * With tracepoint_string(), the string will be registered to the tracing
+ * system and exported to userspace via the debugfs/tracing/printk_formats
+ * file that maps the string address to the string text. This way userspace
+ * tools that read the binary buffers have a way to map the pointers to
+ * the ASCII strings they represent.
+ *
+ * The @str used must be a constant string and persistent as it would not
+ * make sense to show a string that no longer exists. But it is still fine
+ * to be used with modules, because when modules are unloaded, if they
+ * had tracepoints, the ring buffers are cleared too. As long as the string
+ * does not change during the life of the module, it is fine to use
+ * tracepoint_string() within a module.
+ */
+#define tracepoint_string(str)						\
+	({								\
+		static const char *___tp_str __tracepoint_string = str; \
+		___tp_str;						\
+	})
+#define __tracepoint_string	__attribute__((section("__tracepoint_str")))
+
 #ifdef CONFIG_PERF_EVENTS
 struct perf_event;
 
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 05bcc09..ccfe17c 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -1,126 +1,11 @@
 #ifndef LINUX_HARDIRQ_H
 #define LINUX_HARDIRQ_H
 
-#include <linux/preempt.h>
+#include <linux/preempt_mask.h>
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
 #include <linux/vtime.h>
-#include <asm/hardirq.h>
 
-/*
- * We put the hardirq and softirq counter into the preemption
- * counter. The bitmask has the following meaning:
- *
- * - bits 0-7 are the preemption count (max preemption depth: 256)
- * - bits 8-15 are the softirq count (max # of softirqs: 256)
- *
- * The hardirq count can in theory reach the same as NR_IRQS.
- * In reality, the number of nested IRQS is limited to the stack
- * size as well. For archs with over 1000 IRQS it is not practical
- * to expect that they will all nest. We give a max of 10 bits for
- * hardirq nesting. An arch may choose to give less than 10 bits.
- * m68k expects it to be 8.
- *
- * - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
- * - bit 26 is the NMI_MASK
- * - bit 27 is the PREEMPT_ACTIVE flag
- *
- * PREEMPT_MASK: 0x000000ff
- * SOFTIRQ_MASK: 0x0000ff00
- * HARDIRQ_MASK: 0x03ff0000
- *     NMI_MASK: 0x04000000
- */
-#define PREEMPT_BITS	8
-#define SOFTIRQ_BITS	8
-#define NMI_BITS	1
-
-#define MAX_HARDIRQ_BITS 10
-
-#ifndef HARDIRQ_BITS
-# define HARDIRQ_BITS	MAX_HARDIRQ_BITS
-#endif
-
-#if HARDIRQ_BITS > MAX_HARDIRQ_BITS
-#error HARDIRQ_BITS too high!
-#endif
-
-#define PREEMPT_SHIFT	0
-#define SOFTIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)
-#define HARDIRQ_SHIFT	(SOFTIRQ_SHIFT + SOFTIRQ_BITS)
-#define NMI_SHIFT	(HARDIRQ_SHIFT + HARDIRQ_BITS)
-
-#define __IRQ_MASK(x)	((1UL << (x))-1)
-
-#define PREEMPT_MASK	(__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
-#define SOFTIRQ_MASK	(__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
-#define HARDIRQ_MASK	(__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
-#define NMI_MASK	(__IRQ_MASK(NMI_BITS)     << NMI_SHIFT)
-
-#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
-#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
-#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
-#define NMI_OFFSET	(1UL << NMI_SHIFT)
-
-#define SOFTIRQ_DISABLE_OFFSET	(2 * SOFTIRQ_OFFSET)
-
-#ifndef PREEMPT_ACTIVE
-#define PREEMPT_ACTIVE_BITS	1
-#define PREEMPT_ACTIVE_SHIFT	(NMI_SHIFT + NMI_BITS)
-#define PREEMPT_ACTIVE	(__IRQ_MASK(PREEMPT_ACTIVE_BITS) << PREEMPT_ACTIVE_SHIFT)
-#endif
-
-#if PREEMPT_ACTIVE < (1 << (NMI_SHIFT + NMI_BITS))
-#error PREEMPT_ACTIVE is too low!
-#endif
-
-#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
-#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
-#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
-				 | NMI_MASK))
-
-/*
- * Are we doing bottom half or hardware interrupt processing?
- * Are we in a softirq context? Interrupt context?
- * in_softirq - Are we currently processing softirq or have bh disabled?
- * in_serving_softirq - Are we currently processing softirq?
- */
-#define in_irq()		(hardirq_count())
-#define in_softirq()		(softirq_count())
-#define in_interrupt()		(irq_count())
-#define in_serving_softirq()	(softirq_count() & SOFTIRQ_OFFSET)
-
-/*
- * Are we in NMI context?
- */
-#define in_nmi()	(preempt_count() & NMI_MASK)
-
-#if defined(CONFIG_PREEMPT_COUNT)
-# define PREEMPT_CHECK_OFFSET 1
-#else
-# define PREEMPT_CHECK_OFFSET 0
-#endif
-
-/*
- * Are we running in atomic context?  WARNING: this macro cannot
- * always detect atomic context; in particular, it cannot know about
- * held spinlocks in non-preemptible kernels.  Thus it should not be
- * used in the general case to determine whether sleeping is possible.
- * Do not use in_atomic() in driver code.
- */
-#define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != 0)
-
-/*
- * Check whether we were atomic before we did preempt_disable():
- * (used by the scheduler, *after* releasing the kernel lock)
- */
-#define in_atomic_preempt_off() \
-		((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET)
-
-#ifdef CONFIG_PREEMPT_COUNT
-# define preemptible()	(preempt_count() == 0 && !irqs_disabled())
-#else
-# define preemptible()	0
-#endif
 
 #if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS)
 extern void synchronize_irq(unsigned int irq);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index fae8bac..a3b8b2e 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -27,6 +27,14 @@
 
 #include <linux/types.h>
 
+/*
+ * Framework version for util services.
+ */
+
+#define UTIL_FW_MAJOR  3
+#define UTIL_FW_MINOR  0
+#define UTIL_FW_MAJOR_MINOR     (UTIL_FW_MAJOR << 16 | UTIL_FW_MINOR)
+
 
 /*
  * Implementation of host controlled snapshot of the guest.
@@ -455,27 +463,6 @@
 	*read = dsize - *write;
 }
 
-
-/*
- * We use the same version numbering for all Hyper-V modules.
- *
- * Definition of versioning is as follows;
- *
- *	Major Number	Changes for these scenarios;
- *			1.	When a new version of Windows Hyper-V
- *				is released.
- *			2.	A Major change has occurred in the
- *				Linux IC's.
- *			(For example the merge for the first time
- *			into the kernel) Every time the Major Number
- *			changes, the Revision number is reset to 0.
- *	Minor Number	Changes when new functionality is added
- *			to the Linux IC's that is not a bug fix.
- *
- * 3.1 - Added completed hv_utils driver. Shutdown/Heartbeat/Timesync
- */
-#define HV_DRV_VERSION           "3.1"
-
 /*
  * VMBUS version is 32 bit entity broken up into
  * two 16 bit quantities: major_number. minor_number.
@@ -1494,7 +1481,7 @@
 };
 
 #define MAX_SRV_VER	0x7ffffff
-extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
+extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
 					struct icmsg_negotiate *, u8 *, int,
 					int);
 
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index 72b2694..e51f654 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -17,6 +17,8 @@
 #include <linux/iio/trigger.h>
 #include <linux/bitops.h>
 
+#include <linux/platform_data/st_sensors_pdata.h>
+
 #define ST_SENSORS_TX_MAX_LENGTH		2
 #define ST_SENSORS_RX_MAX_LENGTH		6
 
@@ -118,14 +120,16 @@
 /**
  * struct st_sensor_data_ready_irq - ST sensor device data-ready interrupt
  * @addr: address of the register.
- * @mask: mask to write the on/off value.
+ * @mask_int1: mask to enable/disable IRQ on INT1 pin.
+ * @mask_int2: mask to enable/disable IRQ on INT2 pin.
  * struct ig1 - represents the Interrupt Generator 1 of sensors.
  * @en_addr: address of the enable ig1 register.
  * @en_mask: mask to write the on/off value for enable.
  */
 struct st_sensor_data_ready_irq {
 	u8 addr;
-	u8 mask;
+	u8 mask_int1;
+	u8 mask_int2;
 	struct {
 		u8 en_addr;
 		u8 en_mask;
@@ -201,6 +205,7 @@
  * @buffer_data: Data used by buffer part.
  * @odr: Output data rate of the sensor [Hz].
  * num_data_channels: Number of data channels used in buffer.
+ * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
  * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
  * @tf: Transfer function structure used by I/O operations.
  * @tb: Transfer buffers and mutex used by I/O operations.
@@ -219,6 +224,8 @@
 	unsigned int odr;
 	unsigned int num_data_channels;
 
+	u8 drdy_int_pin;
+
 	unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
 
 	const struct st_sensor_transfer_function *tf;
@@ -249,7 +256,8 @@
 }
 #endif
 
-int st_sensors_init_sensor(struct iio_dev *indio_dev);
+int st_sensors_init_sensor(struct iio_dev *indio_dev,
+					struct st_sensors_platform_data *pdata);
 
 int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable);
 
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 3d35b70..2103cc3 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -532,6 +532,60 @@
 void iio_device_free(struct iio_dev *indio_dev);
 
 /**
+ * devm_iio_device_alloc - Resource-managed iio_device_alloc()
+ * @dev: 		Device to allocate iio_dev for
+ * @sizeof_priv: 	Space to allocate for private structure.
+ *
+ * Managed iio_device_alloc.  iio_dev allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * If an iio_dev allocated with this function needs to be freed separately,
+ * devm_iio_device_free() must be used.
+ *
+ * RETURNS:
+ * Pointer to allocated iio_dev on success, NULL on failure.
+ */
+struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv);
+
+/**
+ * devm_iio_device_free - Resource-managed iio_device_free()
+ * @dev:		Device this iio_dev belongs to
+ * @indio_dev: 		the iio_dev associated with the device
+ *
+ * Free iio_dev allocated with devm_iio_device_alloc().
+ */
+void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev);
+
+/**
+ * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc()
+ * @dev:		Device to allocate iio_trigger for
+ * @fmt:		trigger name format. If it includes format
+ *			specifiers, the additional arguments following
+ *			format are formatted and inserted in the resulting
+ *			string replacing their respective specifiers.
+ *
+ * Managed iio_trigger_alloc.  iio_trigger allocated with this function is
+ * automatically freed on driver detach.
+ *
+ * If an iio_trigger allocated with this function needs to be freed separately,
+ * devm_iio_trigger_free() must be used.
+ *
+ * RETURNS:
+ * Pointer to allocated iio_trigger on success, NULL on failure.
+ */
+struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
+						const char *fmt, ...);
+
+/**
+ * devm_iio_trigger_free - Resource-managed iio_trigger_free()
+ * @dev:		Device this iio_dev belongs to
+ * @iio_trig:		the iio_trigger associated with the device
+ *
+ * Free iio_trigger allocated with devm_iio_trigger_alloc().
+ */
+void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig);
+
+/**
  * iio_buffer_enabled() - helper function to test if the buffer is enabled
  * @indio_dev:		IIO device structure for device
  **/
diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
index b7a934b..2958c96 100644
--- a/include/linux/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
@@ -73,11 +73,6 @@
 	    .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)}
 
 /* Generic attributes of onetype or another */
-/**
- * IIO_DEV_ATTR_RESET: resets the device
- **/
-#define IIO_DEV_ATTR_RESET(_store)			\
-	IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, _store, 0)
 
 /**
  * IIO_DEV_ATTR_SAMP_FREQ - sets any internal clock frequency
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index b99cd23..79640e01 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -5,45 +5,13 @@
 
 #include <linux/bitmap.h>
 #include <linux/if.h>
+#include <linux/ip.h>
 #include <linux/netdevice.h>
 #include <linux/rcupdate.h>
 #include <linux/timer.h>
 #include <linux/sysctl.h>
 #include <linux/rtnetlink.h>
 
-enum
-{
-	IPV4_DEVCONF_FORWARDING=1,
-	IPV4_DEVCONF_MC_FORWARDING,
-	IPV4_DEVCONF_PROXY_ARP,
-	IPV4_DEVCONF_ACCEPT_REDIRECTS,
-	IPV4_DEVCONF_SECURE_REDIRECTS,
-	IPV4_DEVCONF_SEND_REDIRECTS,
-	IPV4_DEVCONF_SHARED_MEDIA,
-	IPV4_DEVCONF_RP_FILTER,
-	IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
-	IPV4_DEVCONF_BOOTP_RELAY,
-	IPV4_DEVCONF_LOG_MARTIANS,
-	IPV4_DEVCONF_TAG,
-	IPV4_DEVCONF_ARPFILTER,
-	IPV4_DEVCONF_MEDIUM_ID,
-	IPV4_DEVCONF_NOXFRM,
-	IPV4_DEVCONF_NOPOLICY,
-	IPV4_DEVCONF_FORCE_IGMP_VERSION,
-	IPV4_DEVCONF_ARP_ANNOUNCE,
-	IPV4_DEVCONF_ARP_IGNORE,
-	IPV4_DEVCONF_PROMOTE_SECONDARIES,
-	IPV4_DEVCONF_ARP_ACCEPT,
-	IPV4_DEVCONF_ARP_NOTIFY,
-	IPV4_DEVCONF_ACCEPT_LOCAL,
-	IPV4_DEVCONF_SRC_VMARK,
-	IPV4_DEVCONF_PROXY_ARP_PVLAN,
-	IPV4_DEVCONF_ROUTE_LOCALNET,
-	__IPV4_DEVCONF_MAX
-};
-
-#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1)
-
 struct ipv4_devconf {
 	void	*sysctl;
 	int	data[IPV4_DEVCONF_MAX];
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 850e95b..b8b7dc7 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -101,6 +101,7 @@
 #define IP6SKB_FORWARDED	2
 #define IP6SKB_REROUTED		4
 #define IP6SKB_ROUTERALERT	8
+#define IP6SKB_FRAGMENTED      16
 };
 
 #define IP6CB(skb)	((struct inet6_skb_parm*)((skb)->cb))
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 97ba4e7..d235e88 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -101,13 +101,13 @@
 #define time_after(a,b)		\
 	(typecheck(unsigned long, a) && \
 	 typecheck(unsigned long, b) && \
-	 ((long)(b) - (long)(a) < 0))
+	 ((long)((b) - (a)) < 0))
 #define time_before(a,b)	time_after(b,a)
 
 #define time_after_eq(a,b)	\
 	(typecheck(unsigned long, a) && \
 	 typecheck(unsigned long, b) && \
-	 ((long)(a) - (long)(b) >= 0))
+	 ((long)((a) - (b)) >= 0))
 #define time_before_eq(a,b)	time_after_eq(b,a)
 
 /*
@@ -130,13 +130,13 @@
 #define time_after64(a,b)	\
 	(typecheck(__u64, a) &&	\
 	 typecheck(__u64, b) && \
-	 ((__s64)(b) - (__s64)(a) < 0))
+	 ((__s64)((b) - (a)) < 0))
 #define time_before64(a,b)	time_after64(b,a)
 
 #define time_after_eq64(a,b)	\
 	(typecheck(__u64, a) && \
 	 typecheck(__u64, b) && \
-	 ((__s64)(a) - (__s64)(b) >= 0))
+	 ((__s64)((a) - (b)) >= 0))
 #define time_before_eq64(a,b)	time_after_eq64(b,a)
 
 #define time_in_range64(a, b, c) \
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index 0976fc4..a507907 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -48,7 +48,6 @@
 
 #include <linux/types.h>
 #include <linux/compiler.h>
-#include <linux/workqueue.h>
 
 #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL)
 
@@ -61,12 +60,6 @@
 #endif
 };
 
-struct static_key_deferred {
-	struct static_key key;
-	unsigned long timeout;
-	struct delayed_work work;
-};
-
 # include <asm/jump_label.h>
 # define HAVE_JUMP_LABEL
 #endif	/* CC_HAVE_ASM_GOTO && CONFIG_JUMP_LABEL */
@@ -78,6 +71,7 @@
 
 struct module;
 
+#include <linux/atomic.h>
 #ifdef HAVE_JUMP_LABEL
 
 #define JUMP_LABEL_TRUE_BRANCH 1UL
@@ -119,10 +113,7 @@
 extern int jump_label_text_reserved(void *start, void *end);
 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 static_key_deferred *key, unsigned long rl);
 
 #define STATIC_KEY_INIT_TRUE ((struct static_key) \
 	{ .enabled = ATOMIC_INIT(1), .entries = (void *)1 })
@@ -131,8 +122,6 @@
 
 #else  /* !HAVE_JUMP_LABEL */
 
-#include <linux/atomic.h>
-
 struct static_key {
 	atomic_t enabled;
 };
@@ -141,10 +130,6 @@
 {
 }
 
-struct static_key_deferred {
-	struct static_key  key;
-};
-
 static __always_inline bool static_key_false(struct static_key *key)
 {
 	if (unlikely(atomic_read(&key->enabled)) > 0)
@@ -169,11 +154,6 @@
 	atomic_dec(&key->enabled);
 }
 
-static inline void static_key_slow_dec_deferred(struct static_key_deferred *key)
-{
-	static_key_slow_dec(&key->key);
-}
-
 static inline int jump_label_text_reserved(void *start, void *end)
 {
 	return 0;
@@ -187,12 +167,6 @@
 	return 0;
 }
 
-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) \
diff --git a/include/linux/jump_label_ratelimit.h b/include/linux/jump_label_ratelimit.h
new file mode 100644
index 0000000..1137883
--- /dev/null
+++ b/include/linux/jump_label_ratelimit.h
@@ -0,0 +1,34 @@
+#ifndef _LINUX_JUMP_LABEL_RATELIMIT_H
+#define _LINUX_JUMP_LABEL_RATELIMIT_H
+
+#include <linux/jump_label.h>
+#include <linux/workqueue.h>
+
+#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL)
+struct static_key_deferred {
+	struct static_key key;
+	unsigned long timeout;
+	struct delayed_work work;
+};
+#endif
+
+#ifdef HAVE_JUMP_LABEL
+extern void static_key_slow_dec_deferred(struct static_key_deferred *key);
+extern void
+jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl);
+
+#else	/* !HAVE_JUMP_LABEL */
+struct static_key_deferred {
+	struct static_key  key;
+};
+static inline void static_key_slow_dec_deferred(struct static_key_deferred *key)
+{
+	static_key_slow_dec(&key->key);
+}
+static inline void
+jump_label_rate_limit(struct static_key_deferred *key,
+		unsigned long rl)
+{
+}
+#endif	/* HAVE_JUMP_LABEL */
+#endif	/* _LINUX_JUMP_LABEL_RATELIMIT_H */
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index b7c8cdc..cbfb171 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -36,10 +36,9 @@
 #define VC_CTRLRLOCK	KG_CTRLR 	/* ctrlr lock mode */
 	unsigned char slockstate; 	/* for `sticky' Shift, Ctrl, etc. */
 
-	unsigned char ledmode:2; 	/* one 2-bit value */
+	unsigned char ledmode:1;
 #define LED_SHOW_FLAGS 0        /* traditional state */
 #define LED_SHOW_IOCTL 1        /* only change leds upon ioctl */
-#define LED_SHOW_MEM 2          /* `heartbeat': peek into memory */
 
 	unsigned char ledflagstate:4;	/* flags, not lights */
 	unsigned char default_ledflagstate:4;
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 939b112..de6dcbcc 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/wait.h>
 #include <linux/atomic.h>
+#include <linux/workqueue.h>
 
 #define UEVENT_HELPER_PATH_LEN		256
 #define UEVENT_NUM_ENVP			32	/* number of env pointers */
@@ -65,6 +66,9 @@
 	struct kobj_type	*ktype;
 	struct sysfs_dirent	*sd;
 	struct kref		kref;
+#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
+	struct delayed_work	release;
+#endif
 	unsigned int state_initialized:1;
 	unsigned int state_in_sysfs:1;
 	unsigned int state_add_uevent_sent:1;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index a63d83e..ca645a0 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -85,6 +85,12 @@
 	return pfn == KVM_PFN_NOSLOT;
 }
 
+/*
+ * architectures with KVM_HVA_ERR_BAD other than PAGE_OFFSET (e.g. s390)
+ * provide own defines and kvm_is_error_hva
+ */
+#ifndef KVM_HVA_ERR_BAD
+
 #define KVM_HVA_ERR_BAD		(PAGE_OFFSET)
 #define KVM_HVA_ERR_RO_BAD	(PAGE_OFFSET + PAGE_SIZE)
 
@@ -93,6 +99,8 @@
 	return addr >= PAGE_OFFSET;
 }
 
+#endif
+
 #define KVM_ERR_PTR_BAD_PAGE	(ERR_PTR(-ENOENT))
 
 static inline bool is_error_page(struct page *page)
@@ -160,8 +168,12 @@
 
 int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 		     int len, const void *val);
+int kvm_io_bus_write_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+			    int len, const void *val, long cookie);
 int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len,
 		    void *val);
+int kvm_io_bus_read_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+			   int len, void *val, long cookie);
 int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 			    int len, struct kvm_io_device *dev);
 int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
@@ -499,6 +511,7 @@
 void kvm_arch_free_memslot(struct kvm_memory_slot *free,
 			   struct kvm_memory_slot *dont);
 int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages);
+void kvm_arch_memslots_updated(struct kvm *kvm);
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
 				struct kvm_memory_slot *memslot,
 				struct kvm_userspace_memory_region *mem,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 4ea55bb..0e23c26 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -138,6 +138,22 @@
 	ATA_SHT_THIS_ID		= -1,
 	ATA_SHT_USE_CLUSTERING	= 1,
 
+	/* struct ata_taskfile flags */
+	ATA_TFLAG_LBA48		= (1 << 0), /* enable 48-bit LBA and "HOB" */
+	ATA_TFLAG_ISADDR	= (1 << 1), /* enable r/w to nsect/lba regs */
+	ATA_TFLAG_DEVICE	= (1 << 2), /* enable r/w to device reg */
+	ATA_TFLAG_WRITE		= (1 << 3), /* data dir: host->dev==1 (write) */
+	ATA_TFLAG_LBA		= (1 << 4), /* enable LBA */
+	ATA_TFLAG_FUA		= (1 << 5), /* enable FUA */
+	ATA_TFLAG_POLLING	= (1 << 6), /* set nIEN to 1 and use polling */
+
+	/* protocol flags */
+	ATA_PROT_FLAG_PIO	= (1 << 0), /* is PIO */
+	ATA_PROT_FLAG_DMA	= (1 << 1), /* is DMA */
+	ATA_PROT_FLAG_DATA	= ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
+	ATA_PROT_FLAG_NCQ	= (1 << 2), /* is NCQ */
+	ATA_PROT_FLAG_ATAPI	= (1 << 3), /* is ATAPI */
+
 	/* struct ata_device stuff */
 	ATA_DFLAG_LBA		= (1 << 0), /* device supports LBA */
 	ATA_DFLAG_LBA48		= (1 << 1), /* device supports LBA48 */
@@ -156,6 +172,7 @@
 	ATA_DFLAG_DUBIOUS_XFER	= (1 << 16), /* data transfer not verified */
 	ATA_DFLAG_NO_UNLOAD	= (1 << 17), /* device doesn't support unload */
 	ATA_DFLAG_UNLOCK_HPA	= (1 << 18), /* unlock HPA */
+	ATA_DFLAG_NCQ_SEND_RECV = (1 << 19), /* device supports NCQ SEND and RECV */
 	ATA_DFLAG_INIT_MASK	= (1 << 24) - 1,
 
 	ATA_DFLAG_DETACH	= (1 << 24),
@@ -207,6 +224,7 @@
 	ATA_FLAG_ACPI_SATA	= (1 << 17), /* need native SATA ACPI layout */
 	ATA_FLAG_AN		= (1 << 18), /* controller supports AN */
 	ATA_FLAG_PMP		= (1 << 19), /* controller supports PMP */
+	ATA_FLAG_FPDMA_AUX	= (1 << 20), /* controller supports H2DFIS aux field */
 	ATA_FLAG_EM		= (1 << 21), /* driver supports enclosure
 					      * management */
 	ATA_FLAG_SW_ACTIVITY	= (1 << 22), /* driver supports sw activity
@@ -518,6 +536,33 @@
 	BLINK_OFF,
 };
 
+struct ata_taskfile {
+	unsigned long		flags;		/* ATA_TFLAG_xxx */
+	u8			protocol;	/* ATA_PROT_xxx */
+
+	u8			ctl;		/* control reg */
+
+	u8			hob_feature;	/* additional data */
+	u8			hob_nsect;	/* to support LBA48 */
+	u8			hob_lbal;
+	u8			hob_lbam;
+	u8			hob_lbah;
+
+	u8			feature;
+	u8			nsect;
+	u8			lbal;
+	u8			lbam;
+	u8			lbah;
+
+	u8			device;
+
+	u8			command;	/* IO operation */
+
+	u32			auxiliary;	/* auxiliary field */
+						/* from SATA 3.1 and */
+						/* ATA-8 ACS-3 */
+};
+
 #ifdef CONFIG_ATA_SFF
 struct ata_ioports {
 	void __iomem		*cmd_addr;
@@ -660,6 +705,9 @@
 	/* DEVSLP Timing Variables from Identify Device Data Log */
 	u8			devslp_timing[ATA_LOG_DEVSLP_SIZE];
 
+	/* NCQ send and receive log subcommand support */
+	u8			ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_SIZE];
+
 	/* error history */
 	int			spdn_cnt;
 	/* ering is CLEAR_END, read comment above CLEAR_END */
@@ -959,6 +1007,69 @@
 extern struct ata_port_operations ata_dummy_port_ops;
 extern const struct ata_port_info ata_dummy_port_info;
 
+/*
+ * protocol tests
+ */
+static inline unsigned int ata_prot_flags(u8 prot)
+{
+	switch (prot) {
+	case ATA_PROT_NODATA:
+		return 0;
+	case ATA_PROT_PIO:
+		return ATA_PROT_FLAG_PIO;
+	case ATA_PROT_DMA:
+		return ATA_PROT_FLAG_DMA;
+	case ATA_PROT_NCQ:
+		return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
+	case ATAPI_PROT_NODATA:
+		return ATA_PROT_FLAG_ATAPI;
+	case ATAPI_PROT_PIO:
+		return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
+	case ATAPI_PROT_DMA:
+		return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
+	}
+	return 0;
+}
+
+static inline int ata_is_atapi(u8 prot)
+{
+	return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
+}
+
+static inline int ata_is_nodata(u8 prot)
+{
+	return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
+}
+
+static inline int ata_is_pio(u8 prot)
+{
+	return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
+}
+
+static inline int ata_is_dma(u8 prot)
+{
+	return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
+}
+
+static inline int ata_is_ncq(u8 prot)
+{
+	return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
+}
+
+static inline int ata_is_data(u8 prot)
+{
+	return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
+}
+
+static inline int is_multi_taskfile(struct ata_taskfile *tf)
+{
+	return (tf->command == ATA_CMD_READ_MULTI) ||
+	       (tf->command == ATA_CMD_WRITE_MULTI) ||
+	       (tf->command == ATA_CMD_READ_MULTI_EXT) ||
+	       (tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
+	       (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
+}
+
 static inline const unsigned long *
 sata_ehc_deb_timing(struct ata_eh_context *ehc)
 {
@@ -1142,8 +1253,6 @@
 int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm);
 unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev,
 				    const struct ata_acpi_gtm *gtm);
-acpi_handle ata_ap_acpi_handle(struct ata_port *ap);
-acpi_handle ata_dev_acpi_handle(struct ata_device *dev);
 int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm);
 #else
 static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap)
@@ -1497,6 +1606,13 @@
 			      ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ;
 }
 
+static inline bool ata_fpdma_dsm_supported(struct ata_device *dev)
+{
+	return (dev->flags & ATA_DFLAG_NCQ_SEND_RECV) &&
+		(dev->ncq_send_recv_cmds[ATA_LOG_NCQ_SEND_RECV_DSM_OFFSET] &
+		 ATA_LOG_NCQ_SEND_RECV_DSM_TRIM);
+}
+
 static inline void ata_qc_set_polling(struct ata_queued_cmd *qc)
 {
 	qc->tf.ctl |= ATA_NIEN;
diff --git a/include/linux/llist.h b/include/linux/llist.h
index cdaa7f0..8828a78 100644
--- a/include/linux/llist.h
+++ b/include/linux/llist.h
@@ -125,6 +125,29 @@
 	     (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
 /**
+ * llist_for_each_entry_safe - iterate over some deleted entries of lock-less list of given type
+ *			       safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @node:	the first entry of deleted list entries.
+ * @member:	the name of the llist_node with the struct.
+ *
+ * In general, some entries of the lock-less list can be traversed
+ * safely only after being removed from list, so start with an entry
+ * instead of list head.
+ *
+ * If being used on entries deleted from lock-less list directly, the
+ * traverse order is from the newest to the oldest added entry.  If
+ * you want to traverse from the oldest to the newest, you must
+ * reverse the order by yourself before traversing.
+ */
+#define llist_for_each_entry_safe(pos, n, node, member)			       \
+	for (pos = llist_entry((node), typeof(*pos), member);		       \
+	     &pos->member != NULL &&					       \
+	        (n = llist_entry(pos->member.next, typeof(*n), member), true); \
+	     pos = n)
+
+/**
  * llist_empty - tests whether a lock-less list is empty
  * @head:	the list to test
  *
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index f1e877b..cfc2f11 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -365,7 +365,7 @@
 
 #define lockdep_recursing(tsk)	((tsk)->lockdep_recursion)
 
-#else /* !LOCKDEP */
+#else /* !CONFIG_LOCKDEP */
 
 static inline void lockdep_off(void)
 {
@@ -479,82 +479,36 @@
  * on the per lock-class debug mode:
  */
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define spin_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define spin_acquire_nest(l, s, t, n, i)	lock_acquire(l, s, t, 0, 2, n, i)
-# else
-#  define spin_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define spin_acquire_nest(l, s, t, n, i)	lock_acquire(l, s, t, 0, 1, NULL, i)
-# endif
-# define spin_release(l, n, i)			lock_release(l, n, i)
+#ifdef CONFIG_PROVE_LOCKING
+ #define lock_acquire_exclusive(l, s, t, n, i)		lock_acquire(l, s, t, 0, 2, n, i)
+ #define lock_acquire_shared(l, s, t, n, i)		lock_acquire(l, s, t, 1, 2, n, i)
+ #define lock_acquire_shared_recursive(l, s, t, n, i)	lock_acquire(l, s, t, 2, 2, n, i)
 #else
-# define spin_acquire(l, s, t, i)		do { } while (0)
-# define spin_release(l, n, i)			do { } while (0)
+ #define lock_acquire_exclusive(l, s, t, n, i)		lock_acquire(l, s, t, 0, 1, n, i)
+ #define lock_acquire_shared(l, s, t, n, i)		lock_acquire(l, s, t, 1, 1, n, i)
+ #define lock_acquire_shared_recursive(l, s, t, n, i)	lock_acquire(l, s, t, 2, 1, n, i)
 #endif
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define rwlock_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define rwlock_acquire_read(l, s, t, i)	lock_acquire(l, s, t, 2, 2, NULL, i)
-# else
-#  define rwlock_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define rwlock_acquire_read(l, s, t, i)	lock_acquire(l, s, t, 2, 1, NULL, i)
-# endif
-# define rwlock_release(l, n, i)		lock_release(l, n, i)
-#else
-# define rwlock_acquire(l, s, t, i)		do { } while (0)
-# define rwlock_acquire_read(l, s, t, i)	do { } while (0)
-# define rwlock_release(l, n, i)		do { } while (0)
-#endif
+#define spin_acquire(l, s, t, i)		lock_acquire_exclusive(l, s, t, NULL, i)
+#define spin_acquire_nest(l, s, t, n, i)	lock_acquire_exclusive(l, s, t, n, i)
+#define spin_release(l, n, i)			lock_release(l, n, i)
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define mutex_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define mutex_acquire_nest(l, s, t, n, i)	lock_acquire(l, s, t, 0, 2, n, i)
-# else
-#  define mutex_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define mutex_acquire_nest(l, s, t, n, i)	lock_acquire(l, s, t, 0, 1, n, i)
-# endif
-# define mutex_release(l, n, i)			lock_release(l, n, i)
-#else
-# define mutex_acquire(l, s, t, i)		do { } while (0)
-# define mutex_acquire_nest(l, s, t, n, i)	do { } while (0)
-# define mutex_release(l, n, i)			do { } while (0)
-#endif
+#define rwlock_acquire(l, s, t, i)		lock_acquire_exclusive(l, s, t, NULL, i)
+#define rwlock_acquire_read(l, s, t, i)		lock_acquire_shared_recursive(l, s, t, NULL, i)
+#define rwlock_release(l, n, i)			lock_release(l, n, i)
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define rwsem_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 2, NULL, i)
-#  define rwsem_acquire_nest(l, s, t, n, i)	lock_acquire(l, s, t, 0, 2, n, i)
-#  define rwsem_acquire_read(l, s, t, i)	lock_acquire(l, s, t, 1, 2, NULL, i)
-# else
-#  define rwsem_acquire(l, s, t, i)		lock_acquire(l, s, t, 0, 1, NULL, i)
-#  define rwsem_acquire_nest(l, s, t, n, i)	lock_acquire(l, s, t, 0, 1, n, i)
-#  define rwsem_acquire_read(l, s, t, i)	lock_acquire(l, s, t, 1, 1, NULL, i)
-# endif
+#define mutex_acquire(l, s, t, i)		lock_acquire_exclusive(l, s, t, NULL, i)
+#define mutex_acquire_nest(l, s, t, n, i)	lock_acquire_exclusive(l, s, t, n, i)
+#define mutex_release(l, n, i)			lock_release(l, n, i)
+
+#define rwsem_acquire(l, s, t, i)		lock_acquire_exclusive(l, s, t, NULL, i)
+#define rwsem_acquire_nest(l, s, t, n, i)	lock_acquire_exclusive(l, s, t, n, i)
+#define rwsem_acquire_read(l, s, t, i)		lock_acquire_shared(l, s, t, NULL, i)
 # define rwsem_release(l, n, i)			lock_release(l, n, i)
-#else
-# define rwsem_acquire(l, s, t, i)		do { } while (0)
-# define rwsem_acquire_nest(l, s, t, n, i)	do { } while (0)
-# define rwsem_acquire_read(l, s, t, i)		do { } while (0)
-# define rwsem_release(l, n, i)			do { } while (0)
-#endif
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-# ifdef CONFIG_PROVE_LOCKING
-#  define lock_map_acquire(l)		lock_acquire(l, 0, 0, 0, 2, NULL, _THIS_IP_)
-#  define lock_map_acquire_read(l)	lock_acquire(l, 0, 0, 2, 2, NULL, _THIS_IP_)
-# else
-#  define lock_map_acquire(l)		lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_)
-#  define lock_map_acquire_read(l)	lock_acquire(l, 0, 0, 2, 1, NULL, _THIS_IP_)
-# endif
+#define lock_map_acquire(l)			lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
+#define lock_map_acquire_read(l)		lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_)
 # define lock_map_release(l)			lock_release(l, 1, _THIS_IP_)
-#else
-# define lock_map_acquire(l)			do { } while (0)
-# define lock_map_acquire_read(l)		do { } while (0)
-# define lock_map_release(l)			do { } while (0)
-#endif
 
 #ifdef CONFIG_PROVE_LOCKING
 # define might_lock(lock) 						\
diff --git a/include/linux/lockref.h b/include/linux/lockref.h
new file mode 100644
index 0000000..ca07b50
--- /dev/null
+++ b/include/linux/lockref.h
@@ -0,0 +1,36 @@
+#ifndef __LINUX_LOCKREF_H
+#define __LINUX_LOCKREF_H
+
+/*
+ * Locked reference counts.
+ *
+ * These are different from just plain atomic refcounts in that they
+ * are atomic with respect to the spinlock that goes with them.  In
+ * particular, there can be implementations that don't actually get
+ * the spinlock for the common decrement/increment operations, but they
+ * still have to check that the operation is done semantically as if
+ * the spinlock had been taken (using a cmpxchg operation that covers
+ * both the lock and the count word, or using memory transactions, for
+ * example).
+ */
+
+#include <linux/spinlock.h>
+
+struct lockref {
+	union {
+#ifdef CONFIG_CMPXCHG_LOCKREF
+		aligned_u64 lock_count;
+#endif
+		struct {
+			spinlock_t lock;
+			unsigned int count;
+		};
+	};
+};
+
+extern void lockref_get(struct lockref *);
+extern int lockref_get_not_zero(struct lockref *);
+extern int lockref_get_or_lock(struct lockref *);
+extern int lockref_put_or_lock(struct lockref *);
+
+#endif /* __LINUX_LOCKREF_H */
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 7b4d9d7..6c41609 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -85,7 +85,7 @@
 extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
 
 extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg);
-extern struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont);
+extern struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css);
 
 static inline
 bool mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *memcg)
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 85c31a8..9a6bbf7 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -25,16 +25,9 @@
 struct memory_block {
 	unsigned long start_section_nr;
 	unsigned long end_section_nr;
-	unsigned long state;
-	int section_count;
-
-	/*
-	 * This serializes all state change requests.  It isn't
-	 * held during creation because the control files are
-	 * created long after the critical areas during
-	 * initialization.
-	 */
-	struct mutex state_mutex;
+	unsigned long state;		/* serialized by the dev->lock */
+	int section_count;		/* serialized by mem_sysfs_mutex */
+	int online_type;		/* for passing data to online routine */
 	int phys_device;		/* to which fru does this belong? */
 	void *hw;			/* optional pointer to fw/hw data */
 	int (*phys_callback)(struct memory_block *);
@@ -125,7 +118,6 @@
 							struct memory_block *);
 extern struct memory_block *find_memory_block(struct mem_section *);
 #define CONFIG_MEM_BLOCK_SIZE	(PAGES_PER_SECTION<<PAGE_SHIFT)
-enum mem_add_context { BOOT, HOTPLUG };
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
 
 #ifdef CONFIG_MEMORY_HOTPLUG
diff --git a/include/linux/mfd/arizona/gpio.h b/include/linux/mfd/arizona/gpio.h
new file mode 100644
index 0000000..d2146bb
--- /dev/null
+++ b/include/linux/mfd/arizona/gpio.h
@@ -0,0 +1,96 @@
+/*
+ * GPIO configuration for Arizona devices
+ *
+ * Copyright 2013 Wolfson Microelectronics. PLC.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ARIZONA_GPIO_H
+#define _ARIZONA_GPIO_H
+
+#define ARIZONA_GP_FN_TXLRCLK                    0x00
+#define ARIZONA_GP_FN_GPIO                       0x01
+#define ARIZONA_GP_FN_IRQ1                       0x02
+#define ARIZONA_GP_FN_IRQ2                       0x03
+#define ARIZONA_GP_FN_OPCLK                      0x04
+#define ARIZONA_GP_FN_FLL1_OUT                   0x05
+#define ARIZONA_GP_FN_FLL2_OUT                   0x06
+#define ARIZONA_GP_FN_PWM1                       0x08
+#define ARIZONA_GP_FN_PWM2                       0x09
+#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED        0x0A
+#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED      0x0B
+#define ARIZONA_GP_FN_FLL1_LOCK                  0x0C
+#define ARIZONA_GP_FN_FLL2_LOCK                  0x0D
+#define ARIZONA_GP_FN_FLL1_CLOCK_OK              0x0F
+#define ARIZONA_GP_FN_FLL2_CLOCK_OK              0x10
+#define ARIZONA_GP_FN_HEADPHONE_DET              0x12
+#define ARIZONA_GP_FN_MIC_DET                    0x13
+#define ARIZONA_GP_FN_WSEQ_STATUS                0x15
+#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR          0x16
+#define ARIZONA_GP_FN_ASRC1_LOCK                 0x1A
+#define ARIZONA_GP_FN_ASRC2_LOCK                 0x1B
+#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR          0x1C
+#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT         0x1D
+#define ARIZONA_GP_FN_DRC1_ANTICLIP              0x1E
+#define ARIZONA_GP_FN_DRC1_DECAY                 0x1F
+#define ARIZONA_GP_FN_DRC1_NOISE                 0x20
+#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE         0x21
+#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT         0x22
+#define ARIZONA_GP_FN_DRC2_ANTICLIP              0x23
+#define ARIZONA_GP_FN_DRC2_DECAY                 0x24
+#define ARIZONA_GP_FN_DRC2_NOISE                 0x25
+#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE         0x26
+#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE       0x27
+#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR          0x28
+#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR          0x29
+#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR          0x2A
+#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN          0x2B
+#define ARIZONA_GP_FN_SPK_TEMP_WARNING           0x2C
+#define ARIZONA_GP_FN_UNDERCLOCKED               0x2D
+#define ARIZONA_GP_FN_OVERCLOCKED                0x2E
+#define ARIZONA_GP_FN_DSP_IRQ1                   0x35
+#define ARIZONA_GP_FN_DSP_IRQ2                   0x36
+#define ARIZONA_GP_FN_ASYNC_OPCLK                0x3D
+#define ARIZONA_GP_FN_BOOT_DONE                  0x44
+#define ARIZONA_GP_FN_DSP1_RAM_READY             0x45
+#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS          0x4B
+#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS        0x4C
+
+#define ARIZONA_GPN_DIR                          0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_MASK                     0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_SHIFT                        15  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_WIDTH                         1  /* GPN_DIR */
+#define ARIZONA_GPN_PU                           0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_MASK                      0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_SHIFT                         14  /* GPN_PU */
+#define ARIZONA_GPN_PU_WIDTH                          1  /* GPN_PU */
+#define ARIZONA_GPN_PD                           0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_MASK                      0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_SHIFT                         13  /* GPN_PD */
+#define ARIZONA_GPN_PD_WIDTH                          1  /* GPN_PD */
+#define ARIZONA_GPN_LVL                          0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_MASK                     0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_SHIFT                        11  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_WIDTH                         1  /* GPN_LVL */
+#define ARIZONA_GPN_POL                          0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_MASK                     0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_SHIFT                        10  /* GPN_POL */
+#define ARIZONA_GPN_POL_WIDTH                         1  /* GPN_POL */
+#define ARIZONA_GPN_OP_CFG                       0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_MASK                  0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_SHIFT                      9  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_WIDTH                      1  /* GPN_OP_CFG */
+#define ARIZONA_GPN_DB                           0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_MASK                      0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_SHIFT                          8  /* GPN_DB */
+#define ARIZONA_GPN_DB_WIDTH                          1  /* GPN_DB */
+#define ARIZONA_GPN_FN_MASK                      0x007F  /* GPN_DB */
+#define ARIZONA_GPN_FN_SHIFT                          0  /* GPN_DB */
+#define ARIZONA_GPN_FN_WIDTH                          7  /* GPN_DB */
+
+#endif
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index 1a8dd7a..37e48c9 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -160,7 +160,8 @@
 	PALMAS_REG_SMPS7,
 	PALMAS_REG_SMPS8,
 	PALMAS_REG_SMPS9,
-	PALMAS_REG_SMPS10,
+	PALMAS_REG_SMPS10_OUT2,
+	PALMAS_REG_SMPS10_OUT1,
 	/* LDO regulators */
 	PALMAS_REG_LDO1,
 	PALMAS_REG_LDO2,
@@ -355,9 +356,9 @@
 	int smps123;
 	int smps457;
 
-	int range[PALMAS_REG_SMPS10];
-	unsigned int ramp_delay[PALMAS_REG_SMPS10];
-	unsigned int current_reg_mode[PALMAS_REG_SMPS10];
+	int range[PALMAS_REG_SMPS10_OUT1];
+	unsigned int ramp_delay[PALMAS_REG_SMPS10_OUT1];
+	unsigned int current_reg_mode[PALMAS_REG_SMPS10_OUT1];
 };
 
 struct palmas_resource {
@@ -371,17 +372,15 @@
 
 	struct extcon_dev edev;
 
-	/* used to set vbus, in atomic path */
-	struct work_struct set_vbus_work;
-
 	int id_otg_irq;
 	int id_irq;
 	int vbus_otg_irq;
 	int vbus_irq;
 
-	int vbus_enable;
-
 	enum palmas_usb_state linkstat;
+	int wakeup;
+	bool enable_vbus_detection;
+	bool enable_id_detection;
 };
 
 #define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)
@@ -449,7 +448,7 @@
 #define PALMAS_DVFS_BASE					0x180
 #define PALMAS_PMU_CONTROL_BASE					0x1A0
 #define PALMAS_RESOURCE_BASE					0x1D4
-#define PALMAS_PU_PD_OD_BASE					0x1F4
+#define PALMAS_PU_PD_OD_BASE					0x1F0
 #define PALMAS_LED_BASE						0x200
 #define PALMAS_INTERRUPT_BASE					0x210
 #define PALMAS_USB_OTG_BASE					0x250
@@ -1734,16 +1733,20 @@
 #define PALMAS_REGEN3_CTRL_MODE_ACTIVE_SHIFT			0
 
 /* Registers for function PAD_CONTROL */
-#define PALMAS_PU_PD_INPUT_CTRL1				0x0
-#define PALMAS_PU_PD_INPUT_CTRL2				0x1
-#define PALMAS_PU_PD_INPUT_CTRL3				0x2
-#define PALMAS_OD_OUTPUT_CTRL					0x4
-#define PALMAS_POLARITY_CTRL					0x5
-#define PALMAS_PRIMARY_SECONDARY_PAD1				0x6
-#define PALMAS_PRIMARY_SECONDARY_PAD2				0x7
-#define PALMAS_I2C_SPI						0x8
-#define PALMAS_PU_PD_INPUT_CTRL4				0x9
-#define PALMAS_PRIMARY_SECONDARY_PAD3				0xA
+#define PALMAS_OD_OUTPUT_CTRL2					0x2
+#define PALMAS_POLARITY_CTRL2					0x3
+#define PALMAS_PU_PD_INPUT_CTRL1				0x4
+#define PALMAS_PU_PD_INPUT_CTRL2				0x5
+#define PALMAS_PU_PD_INPUT_CTRL3				0x6
+#define PALMAS_PU_PD_INPUT_CTRL5				0x7
+#define PALMAS_OD_OUTPUT_CTRL					0x8
+#define PALMAS_POLARITY_CTRL					0x9
+#define PALMAS_PRIMARY_SECONDARY_PAD1				0xA
+#define PALMAS_PRIMARY_SECONDARY_PAD2				0xB
+#define PALMAS_I2C_SPI						0xC
+#define PALMAS_PU_PD_INPUT_CTRL4				0xD
+#define PALMAS_PRIMARY_SECONDARY_PAD3				0xE
+#define PALMAS_PRIMARY_SECONDARY_PAD4				0xF
 
 /* Bit definitions for PU_PD_INPUT_CTRL1 */
 #define PALMAS_PU_PD_INPUT_CTRL1_RESET_IN_PD			0x40
@@ -2501,6 +2504,15 @@
 #define PALMAS_PU_PD_GPIO_CTRL1					0x6
 #define PALMAS_PU_PD_GPIO_CTRL2					0x7
 #define PALMAS_OD_OUTPUT_GPIO_CTRL				0x8
+#define PALMAS_GPIO_DATA_IN2					0x9
+#define PALMAS_GPIO_DATA_DIR2					0x0A
+#define PALMAS_GPIO_DATA_OUT2					0x0B
+#define PALMAS_GPIO_DEBOUNCE_EN2				0x0C
+#define PALMAS_GPIO_CLEAR_DATA_OUT2				0x0D
+#define PALMAS_GPIO_SET_DATA_OUT2				0x0E
+#define PALMAS_PU_PD_GPIO_CTRL3					0x0F
+#define PALMAS_PU_PD_GPIO_CTRL4					0x10
+#define PALMAS_OD_OUTPUT_GPIO_CTRL2				0x11
 
 /* Bit definitions for GPIO_DATA_IN */
 #define PALMAS_GPIO_DATA_IN_GPIO_7_IN				0x80
diff --git a/include/linux/mfd/samsung/s2mps11.h b/include/linux/mfd/samsung/s2mps11.h
index 4e94dc6..d0d52ea 100644
--- a/include/linux/mfd/samsung/s2mps11.h
+++ b/include/linux/mfd/samsung/s2mps11.h
@@ -191,6 +191,17 @@
 #define S2MPS11_BUCK_N_VOLTAGES (S2MPS11_BUCK_VSEL_MASK + 1)
 #define S2MPS11_RAMP_DELAY	25000		/* uV/us */
 
+
+#define S2MPS11_BUCK2_RAMP_SHIFT	6
+#define S2MPS11_BUCK34_RAMP_SHIFT	4
+#define S2MPS11_BUCK5_RAMP_SHIFT	6
+#define S2MPS11_BUCK16_RAMP_SHIFT	4
+#define S2MPS11_BUCK7810_RAMP_SHIFT	2
+#define S2MPS11_BUCK9_RAMP_SHIFT	0
+#define S2MPS11_BUCK2_RAMP_EN_SHIFT	3
+#define S2MPS11_BUCK3_RAMP_EN_SHIFT	2
+#define S2MPS11_BUCK4_RAMP_EN_SHIFT	1
+#define S2MPS11_BUCK6_RAMP_EN_SHIFT	0
 #define S2MPS11_PMIC_EN_SHIFT	6
 #define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3)
 
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index 29eab2b..a5a7f01 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -244,24 +244,6 @@
 };
 
 /**
- * struct tps_info - packages regulator constraints
- * @name:		Voltage regulator name
- * @min_uV:		minimum micro volts
- * @max_uV:		minimum micro volts
- * @vsel_to_uv:		Function pointer to get voltage from selector
- * @uv_to_vsel:		Function pointer to get selector from voltage
- *
- * This data is used to check the regualtor voltage limits while setting.
- */
-struct tps_info {
-	const char *name;
-	int min_uV;
-	int max_uV;
-	int (*vsel_to_uv)(unsigned int vsel);
-	int (*uv_to_vsel)(int uV, unsigned int *vsel);
-};
-
-/**
  * struct tps65217 - tps65217 sub-driver chip access routines
  *
  * Device data may be used to access the TPS65217 chip
@@ -273,7 +255,6 @@
 	unsigned int id;
 	struct regulator_desc desc[TPS65217_NUM_REGULATOR];
 	struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
-	struct tps_info *info[TPS65217_NUM_REGULATOR];
 	struct regmap *regmap;
 };
 
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f022460..d2d59b4 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1798,6 +1798,7 @@
 	MF_COUNT_INCREASED = 1 << 0,
 	MF_ACTION_REQUIRED = 1 << 1,
 	MF_MUST_KILL = 1 << 2,
+	MF_SOFT_OFFLINE = 1 << 3,
 };
 extern int memory_failure(unsigned long pfn, int trapno, int flags);
 extern void memory_failure_queue(unsigned long pfn, int trapno, int flags);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index fb425aa..faf4b7c 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -332,6 +332,7 @@
 				unsigned long pgoff, unsigned long flags);
 #endif
 	unsigned long mmap_base;		/* base of mmap area */
+	unsigned long mmap_legacy_base;         /* base of mmap area in bottom-up allocations */
 	unsigned long task_size;		/* size of task vm space */
 	unsigned long highest_vm_end;		/* highest vma end address */
 	pgd_t * pgd;
diff --git a/include/linux/module.h b/include/linux/module.h
index 46f1ea0..05f2447 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -42,6 +42,7 @@
 	struct module *mod;
 	struct kobject *drivers_dir;
 	struct module_param_attrs *mp;
+	struct completion *kobj_completion;
 };
 
 struct module_attribute {
@@ -97,6 +98,11 @@
 /* For userspace: you can also call me... */
 #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
 
+/* Soft module dependencies. See man modprobe.d for details.
+ * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
+ */
+#define MODULE_SOFTDEP(_softdep) MODULE_INFO(softdep, _softdep)
+
 /*
  * The following license idents are currently accepted as indicating free
  * software modules
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 27d9da3..c3eb102 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -36,7 +36,18 @@
 
 struct kernel_param;
 
+/*
+ * Flags available for kernel_param_ops
+ *
+ * NOARG - the parameter allows for no argument (foo instead of foo=1)
+ */
+enum {
+	KERNEL_PARAM_FL_NOARG = (1 << 0)
+};
+
 struct kernel_param_ops {
+	/* How the ops should behave */
+	unsigned int flags;
 	/* Returns 0, or -errno.  arg is in kp->arg. */
 	int (*set)(const char *val, const struct kernel_param *kp);
 	/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
@@ -187,7 +198,7 @@
 /* Obsolete - use module_param_cb() */
 #define module_param_call(name, set, get, arg, perm)			\
 	static struct kernel_param_ops __param_ops_##name =		\
-		 { (void *)set, (void *)get };				\
+		{ 0, (void *)set, (void *)get };			\
 	__module_param_call(MODULE_PARAM_PREFIX,			\
 			    name, &__param_ops_##name, arg,		\
 			    (perm) + sizeof(__check_old_set_param(set))*0, -1)
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 4e2cbfa..58b9a02 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -98,8 +98,17 @@
 typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
 extern nodemask_t _unused_nodemask_arg_;
 
+/*
+ * The inline keyword gives the compiler room to decide to inline, or
+ * not inline a function as it sees best.  However, as these functions
+ * are called in both __init and non-__init functions, if they are not
+ * inlined we will end up with a section mis-match error (of the type of
+ * freeable items not being freed).  So we must use __always_inline here
+ * to fix the problem.  If other functions in the future also end up in
+ * this situation they will also need to be annotated as __always_inline
+ */
 #define node_set(node, dst) __node_set((node), &(dst))
-static inline void __node_set(int node, volatile nodemask_t *dstp)
+static __always_inline void __node_set(int node, volatile nodemask_t *dstp)
 {
 	set_bit(node, dstp->bits);
 }
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 10e5947..b4ec59d 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -14,6 +14,10 @@
  * A structure to contain pointers to all per-process
  * namespaces - fs (mount), uts, network, sysvipc, etc.
  *
+ * The pid namespace is an exception -- it's accessed using
+ * task_active_pid_ns.  The pid namespace here is the
+ * namespace that children will use.
+ *
  * 'count' is the number of tasks holding a reference.
  * The count for each namespace, then, will be the number
  * of nsproxies pointing to it, not the number of tasks.
@@ -27,7 +31,7 @@
 	struct uts_namespace *uts_ns;
 	struct ipc_namespace *ipc_ns;
 	struct mnt_namespace *mnt_ns;
-	struct pid_namespace *pid_ns;
+	struct pid_namespace *pid_ns_for_children;
 	struct net 	     *net_ns;
 };
 extern struct nsproxy init_nsproxy;
diff --git a/include/linux/of.h b/include/linux/of.h
index 1fd08ca..3a45c4f 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -266,6 +266,7 @@
 extern const void *of_get_property(const struct device_node *node,
 				const char *name,
 				int *lenp);
+extern struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
 #define for_each_property_of_node(dn, pp) \
 	for (pp = dn->properties; pp != NULL; pp = pp->next)
 
@@ -343,6 +344,8 @@
 		s;						\
 		s = of_prop_next_string(prop, s))
 
+int of_device_is_stdout_path(struct device_node *dn);
+
 #else /* CONFIG_OF */
 
 static inline const char* of_node_full_name(struct device_node *np)
@@ -459,6 +462,12 @@
 	return NULL;
 }
 
+static inline struct device_node *of_get_cpu_node(int cpu,
+					unsigned int *thread)
+{
+	return NULL;
+}
+
 static inline int of_property_read_u64(const struct device_node *np,
 				       const char *propname, u64 *out_value)
 {
@@ -505,6 +514,11 @@
 	return 0;
 }
 
+static inline int of_device_is_stdout_path(struct device_node *dn)
+{
+	return 0;
+}
+
 #define of_match_ptr(_ptr)	NULL
 #define of_match_node(_matches, _node)	NULL
 #define of_property_for_each_u32(np, propname, prop, p, u) \
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 9d27475f..82ce324 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_OF_DEVICE_H
 #define _LINUX_OF_DEVICE_H
 
+#include <linux/cpu.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h> /* temporary until merge */
 
@@ -43,6 +44,15 @@
 	of_node_put(dev->of_node);
 }
 
+static inline struct device_node *of_cpu_device_node_get(int cpu)
+{
+	struct device *cpu_dev;
+	cpu_dev = get_cpu_device(cpu);
+	if (!cpu_dev)
+		return NULL;
+	return of_node_get(cpu_dev->of_node);
+}
+
 #else /* CONFIG_OF */
 
 static inline int of_driver_match_device(struct device *dev,
@@ -67,6 +77,11 @@
 {
 	return NULL;
 }
+
+static inline struct device_node *of_cpu_device_node_get(int cpu)
+{
+	return NULL;
+}
 #endif /* CONFIG_OF */
 
 #endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/olpc-ec.h b/include/linux/olpc-ec.h
index 5bb6e76..2925df3 100644
--- a/include/linux/olpc-ec.h
+++ b/include/linux/olpc-ec.h
@@ -6,6 +6,7 @@
 #define EC_WRITE_SCI_MASK		0x1b
 #define EC_WAKE_UP_WLAN			0x24
 #define EC_WLAN_LEAVE_RESET		0x25
+#define EC_DCON_POWER_MODE		0x26
 #define EC_READ_EB_MODE			0x2a
 #define EC_SET_SCI_INHIBIT		0x32
 #define EC_SET_SCI_INHIBIT_RELEASE	0x34
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 1704479..d006f0c 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -47,24 +47,22 @@
 
 #ifdef	CONFIG_ACPI_PCI_SLOT
 void acpi_pci_slot_init(void);
-void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle);
+void acpi_pci_slot_enumerate(struct pci_bus *bus);
 void acpi_pci_slot_remove(struct pci_bus *bus);
 #else
 static inline void acpi_pci_slot_init(void) { }
-static inline void acpi_pci_slot_enumerate(struct pci_bus *bus,
-					   acpi_handle handle) { }
+static inline void acpi_pci_slot_enumerate(struct pci_bus *bus) { }
 static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
 #endif
 
 #ifdef	CONFIG_HOTPLUG_PCI_ACPI
 void acpiphp_init(void);
-void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle);
+void acpiphp_enumerate_slots(struct pci_bus *bus);
 void acpiphp_remove_slots(struct pci_bus *bus);
 void acpiphp_check_host_bridge(acpi_handle handle);
 #else
 static inline void acpiphp_init(void) { }
-static inline void acpiphp_enumerate_slots(struct pci_bus *bus,
-					   acpi_handle handle) { }
+static inline void acpiphp_enumerate_slots(struct pci_bus *bus) { }
 static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
 static inline void acpiphp_check_host_bridge(acpi_handle handle) { }
 #endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 0fd1f15..186540d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -675,7 +675,7 @@
 /* these external functions are only available when PCI support is enabled */
 #ifdef CONFIG_PCI
 
-void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
+void pcie_bus_configure_settings(struct pci_bus *bus);
 
 enum pcie_bus_config_types {
 	PCIE_BUS_TUNE_OFF,
@@ -914,6 +914,7 @@
 void pci_msi_off(struct pci_dev *dev);
 int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size);
 int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask);
+int pci_wait_for_pending_transaction(struct pci_dev *dev);
 int pcix_get_max_mmrbc(struct pci_dev *dev);
 int pcix_get_mmrbc(struct pci_dev *dev);
 int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
@@ -924,6 +925,11 @@
 int __pci_reset_function(struct pci_dev *dev);
 int __pci_reset_function_locked(struct pci_dev *dev);
 int pci_reset_function(struct pci_dev *dev);
+int pci_probe_reset_slot(struct pci_slot *slot);
+int pci_reset_slot(struct pci_slot *slot);
+int pci_probe_reset_bus(struct pci_bus *bus);
+int pci_reset_bus(struct pci_bus *bus);
+void pci_reset_bridge_secondary_bus(struct pci_dev *dev);
 void pci_update_resource(struct pci_dev *dev, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
 int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align);
@@ -1003,6 +1009,7 @@
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
+void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
 void pdev_enable_device(struct pci_dev *);
 int pci_enable_resources(struct pci_dev *, int mask);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
@@ -1043,7 +1050,6 @@
 						  resource_size_t,
 						  resource_size_t),
 			void *alignf_data);
-void pci_enable_bridges(struct pci_bus *bus);
 
 /* Proper probing supporting hot-pluggable devices */
 int __must_check __pci_register_driver(struct pci_driver *, struct module *,
@@ -1648,6 +1654,10 @@
 int pcibios_add_device(struct pci_dev *dev);
 void pcibios_release_device(struct pci_dev *dev);
 
+#ifdef CONFIG_HIBERNATE_CALLBACKS
+extern struct dev_pm_ops pcibios_pm_ops;
+#endif
+
 #ifdef CONFIG_PCI_MMCONFIG
 void __init pci_mmcfg_early_init(void);
 void __init pci_mmcfg_late_init(void);
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
index 8db71dcd..bd32109 100644
--- a/include/linux/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -63,6 +63,9 @@
  * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
+ * @reset_slot: Optional interface to allow override of a bus reset for the
+ *	slot for cases where a secondary bus reset can result in spurious
+ *	hotplug events or where a slot can be reset independent of the bus.
  *
  * The table of function pointers that is passed to the hotplug pci core by a
  * hotplug pci driver.  These functions are called by the hotplug pci core when
@@ -80,6 +83,7 @@
 	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
 	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
 	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*reset_slot)		(struct hotplug_slot *slot, int probe);
 };
 
 /**
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3bed2e8..bc95b2b 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -518,6 +518,8 @@
 #define PCI_DEVICE_ID_AMD_11H_NB_MISC	0x1303
 #define PCI_DEVICE_ID_AMD_11H_NB_LINK	0x1304
 #define PCI_DEVICE_ID_AMD_15H_M10H_F3	0x1403
+#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d
+#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e
 #define PCI_DEVICE_ID_AMD_15H_NB_F0	0x1600
 #define PCI_DEVICE_ID_AMD_15H_NB_F1	0x1601
 #define PCI_DEVICE_ID_AMD_15H_NB_F2	0x1602
@@ -1311,6 +1313,8 @@
 #define PCI_DEVICE_ID_IMS_TT128		0x9128
 #define PCI_DEVICE_ID_IMS_TT3D		0x9135
 
+#define PCI_VENDOR_ID_AMCC		0x10e8
+
 #define PCI_VENDOR_ID_INTERG		0x10ea
 #define PCI_DEVICE_ID_INTERG_1682	0x1682
 #define PCI_DEVICE_ID_INTERG_2000	0x2000
@@ -2256,12 +2260,10 @@
 /*
  * ADDI-DATA GmbH communication cards <info@addi-data.com>
  */
-#define PCI_VENDOR_ID_ADDIDATA_OLD             0x10E8
 #define PCI_VENDOR_ID_ADDIDATA                 0x15B8
 #define PCI_DEVICE_ID_ADDIDATA_APCI7500        0x7000
 #define PCI_DEVICE_ID_ADDIDATA_APCI7420        0x7001
 #define PCI_DEVICE_ID_ADDIDATA_APCI7300        0x7002
-#define PCI_DEVICE_ID_ADDIDATA_APCI7800        0x818E
 #define PCI_DEVICE_ID_ADDIDATA_APCI7500_2      0x7009
 #define PCI_DEVICE_ID_ADDIDATA_APCI7420_2      0x700A
 #define PCI_DEVICE_ID_ADDIDATA_APCI7300_2      0x700B
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index 27ef6b1..57e890a 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -22,9 +22,12 @@
  * Macro which verifies @ptr is a percpu pointer without evaluating
  * @ptr.  This is to be used in percpu accessors to verify that the
  * input parameter is a percpu pointer.
+ *
+ * + 0 is required in order to convert the pointer type from a
+ * potential array type to a pointer to a single item of the array.
  */
 #define __verify_pcpu_ptr(ptr)	do {					\
-	const void __percpu *__vpp_verify = (typeof(ptr))NULL;		\
+	const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL;	\
 	(void)__vpp_verify;						\
 } while (0)
 
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index c43f6ea..866e85c 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -48,6 +48,7 @@
 #include <linux/cpu.h>
 #include <linux/irq_work.h>
 #include <linux/static_key.h>
+#include <linux/jump_label_ratelimit.h>
 #include <linux/atomic.h>
 #include <linux/sysfs.h>
 #include <linux/perf_regs.h>
@@ -64,30 +65,6 @@
 };
 
 /*
- * 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.
- *
- *     in_tx: running in a hardware transaction
- *     abort: aborting a hardware transaction
- */
-struct perf_branch_entry {
-	__u64	from;
-	__u64	to;
-	__u64	mispred:1,  /* target mispredicted */
-		predicted:1,/* target predicted */
-		in_tx:1,    /* in transaction */
-		abort:1,    /* transaction abort */
-		reserved:60;
-};
-
-/*
  * branch stack layout:
  *  nr: number of taken branches stored in entries[]
  *
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index bf7e989..fb90ef5 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -137,6 +137,39 @@
 	return PIN_CONF_PACKED(param, argument);
 }
 
+#ifdef CONFIG_OF
+
+#include <linux/device.h>
+#include <linux/pinctrl/machine.h>
+struct pinctrl_dev;
+struct pinctrl_map;
+
+int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+		struct device_node *np, struct pinctrl_map **map,
+		unsigned *reserved_maps, unsigned *num_maps,
+		enum pinctrl_map_type type);
+int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
+		struct device_node *np_config, struct pinctrl_map **map,
+		unsigned *num_maps, enum pinctrl_map_type type);
+
+static inline int pinconf_generic_dt_node_to_map_group(
+		struct pinctrl_dev *pctldev, struct device_node *np_config,
+		struct pinctrl_map **map, unsigned *num_maps)
+{
+	return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps,
+			PIN_MAP_TYPE_CONFIGS_GROUP);
+}
+
+static inline int pinconf_generic_dt_node_to_map_pin(
+		struct pinctrl_dev *pctldev, struct device_node *np_config,
+		struct pinctrl_map **map, unsigned *num_maps)
+{
+	return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps,
+			PIN_MAP_TYPE_CONFIGS_PIN);
+}
+
+#endif
+
 #endif /* CONFIG_GENERIC_PINCONF */
 
 #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */
diff --git a/include/linux/pinctrl/pinconf.h b/include/linux/pinctrl/pinconf.h
index f699869..09eb80f 100644
--- a/include/linux/pinctrl/pinconf.h
+++ b/include/linux/pinctrl/pinconf.h
@@ -47,13 +47,15 @@
 			       unsigned long *config);
 	int (*pin_config_set) (struct pinctrl_dev *pctldev,
 			       unsigned pin,
-			       unsigned long config);
+			       unsigned long *configs,
+			       unsigned num_configs);
 	int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
 				     unsigned selector,
 				     unsigned long *config);
 	int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
 				     unsigned selector,
-				     unsigned long config);
+				     unsigned long *configs,
+				     unsigned num_configs);
 	int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
 					   const char *arg,
 					   unsigned long *config);
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h
index 8827259..9efc04d 100644
--- a/include/linux/platform_data/asoc-s3c.h
+++ b/include/linux/platform_data/asoc-s3c.h
@@ -36,6 +36,7 @@
  */
 #define QUIRK_NO_MUXPSR		(1 << 2)
 #define QUIRK_NEED_RSTCLR	(1 << 3)
+#define QUIRK_SUPPORTS_TDM	(1 << 4)
 	/* Quirks of the I2S controller */
 	u32 quirks;
 	dma_addr_t idma_addr;
diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
index e15745b..b3ca1e9 100644
--- a/include/linux/platform_data/at91_adc.h
+++ b/include/linux/platform_data/at91_adc.h
@@ -14,12 +14,16 @@
 			(Interruptions registers mostly)
  * @status_register:	Offset of the Interrupt Status Register
  * @trigger_register:	Offset of the Trigger setup register
+ * @mr_prescal_mask:	Mask of the PRESCAL field in the adc MR register
+ * @mr_startup_mask:	Mask of the STARTUP field in the adc MR register
  */
 struct at91_adc_reg_desc {
 	u8	channel_base;
 	u32	drdy_mask;
 	u8	status_register;
 	u8	trigger_register;
+	u32	mr_prescal_mask;
+	u32	mr_startup_mask;
 };
 
 /**
diff --git a/include/linux/platform_data/efm32-spi.h b/include/linux/platform_data/efm32-spi.h
new file mode 100644
index 0000000..31b19ca
--- /dev/null
+++ b/include/linux/platform_data/efm32-spi.h
@@ -0,0 +1,14 @@
+#ifndef __LINUX_PLATFORM_DATA_EFM32_SPI_H__
+#define __LINUX_PLATFORM_DATA_EFM32_SPI_H__
+
+#include <linux/types.h>
+
+/**
+ * struct efm32_spi_pdata
+ * @location: pinmux location for the I/O pins (to be written to the ROUTE
+ * 	register)
+ */
+struct efm32_spi_pdata {
+	u8 location;
+};
+#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_SPI_H__ */
diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h
index 91648bf..dd11dcd 100644
--- a/include/linux/platform_data/max310x.h
+++ b/include/linux/platform_data/max310x.h
@@ -1,5 +1,5 @@
 /*
- *  Maxim (Dallas) MAX3107/8 serial driver
+ *  Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
  *
  *  Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
  *
@@ -37,14 +37,13 @@
  * };
  */
 
-#define MAX310X_MAX_UARTS	1
+#define MAX310X_MAX_UARTS	4
 
 /* MAX310X platform data structure */
 struct max310x_pdata {
 	/* Flags global to driver */
-	const u8		driver_flags:2;
+	const u8		driver_flags;
 #define MAX310X_EXT_CLK		(0x00000001)	/* External clock enable */
-#define MAX310X_AUTOSLEEP	(0x00000002)	/* Enable AutoSleep mode */
 	/* Flags global to UART port */
 	const u8		uart_flags[MAX310X_MAX_UARTS];
 #define MAX310X_LOOPBACK	(0x00000001)	/* Loopback mode enable */
@@ -60,8 +59,6 @@
 	void (*init)(void);
 	/* Called before finish */
 	void (*exit)(void);
-	/* Suspend callback */
-	void (*suspend)(int do_suspend);
 };
 
 #endif
diff --git a/include/linux/platform_data/omap-abe-twl6040.h b/include/linux/platform_data/omap-abe-twl6040.h
deleted file mode 100644
index 5d298ac..0000000
--- a/include/linux/platform_data/omap-abe-twl6040.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * omap-abe-twl6040.h - ASoC machine driver OMAP4+ devices, header.
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
- * All rights reserved.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.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.  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 _OMAP_ABE_TWL6040_H_
-#define _OMAP_ABE_TWL6040_H_
-
-/* To select if only one channel is connected in a stereo port */
-#define ABE_TWL6040_LEFT	(1 << 0)
-#define ABE_TWL6040_RIGHT	(1 << 1)
-
-struct omap_abe_twl6040_data {
-	char *card_name;
-	/* Feature flags for connected audio pins */
-	u8	has_hs;
-	u8	has_hf;
-	bool	has_ep;
-	u8	has_aux;
-	u8	has_vibra;
-	bool	has_dmic;
-	bool	has_hsmic;
-	bool	has_mainmic;
-	bool	has_submic;
-	u8	has_afm;
-	/* Other features */
-	bool	jack_detection;	/* board can detect jack events */
-	int	mclk_freq;	/* MCLK frequency speed for twl6040 */
-};
-
-#endif /* _OMAP_ABE_TWL6040_H_ */
diff --git a/include/linux/platform_data/pinctrl-nomadik.h b/include/linux/platform_data/pinctrl-nomadik.h
index f73b2f0..abf5bed 100644
--- a/include/linux/platform_data/pinctrl-nomadik.h
+++ b/include/linux/platform_data/pinctrl-nomadik.h
@@ -226,30 +226,6 @@
 	NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
 };
 
-/* Older deprecated pin config API that should go away soon */
-extern int nmk_config_pin(pin_cfg_t cfg, bool sleep);
-extern int nmk_config_pins(pin_cfg_t *cfgs, int num);
-extern int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num);
-extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
-extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
-#ifdef CONFIG_PINCTRL_NOMADIK
-extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
-#else
-static inline int nmk_gpio_set_mode(int gpio, int gpio_mode)
-{
-	return -ENODEV;
-}
-#endif
-extern int nmk_gpio_get_mode(int gpio);
-
-extern void nmk_gpio_wakeups_suspend(void);
-extern void nmk_gpio_wakeups_resume(void);
-
-extern void nmk_gpio_clocks_enable(void);
-extern void nmk_gpio_clocks_disable(void);
-
-extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
-
 /*
  * Platform data to register a block: only the initial gpio/irq number.
  */
diff --git a/include/linux/platform_data/serial-sccnxp.h b/include/linux/platform_data/serial-sccnxp.h
index bdc510d..af0c8c3 100644
--- a/include/linux/platform_data/serial-sccnxp.h
+++ b/include/linux/platform_data/serial-sccnxp.h
@@ -60,7 +60,6 @@
  * };
  *
  * static struct sccnxp_pdata sc2892_info = {
- *	.frequency	= 3686400,
  *	.mctrl_cfg[0]	= MCTRL_SIG(DIR_OP, LINE_OP0),
  *	.mctrl_cfg[1]	= MCTRL_SIG(DIR_OP, LINE_OP1),
  * };
@@ -78,8 +77,6 @@
 
 /* SCCNXP platform data structure */
 struct sccnxp_pdata {
-	/* Frequency (extrenal clock or crystal) */
-	int			frequency;
 	/* Shift for A0 line */
 	const u8		reg_shift;
 	/* Modem control lines configuration */
diff --git a/include/linux/platform_data/simplefb.h b/include/linux/platform_data/simplefb.h
new file mode 100644
index 0000000..53774b0
--- /dev/null
+++ b/include/linux/platform_data/simplefb.h
@@ -0,0 +1,63 @@
+/*
+ * simplefb.h - Simple Framebuffer Device
+ *
+ * Copyright (C) 2013 David Herrmann <dh.herrmann@gmail.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 __PLATFORM_DATA_SIMPLEFB_H__
+#define __PLATFORM_DATA_SIMPLEFB_H__
+
+#include <drm/drm_fourcc.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+
+/* format array, use it to initialize a "struct simplefb_format" array */
+#define SIMPLEFB_FORMATS \
+{ \
+	{ "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0}, DRM_FORMAT_RGB565 }, \
+	{ "x1r5g5b5", 16, {10, 5}, {5, 5}, {0, 5}, {0, 0}, DRM_FORMAT_XRGB1555 }, \
+	{ "a1r5g5b5", 16, {10, 5}, {5, 5}, {0, 5}, {15, 1}, DRM_FORMAT_ARGB1555 }, \
+	{ "r8g8b8", 24, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_RGB888 }, \
+	{ "x8r8g8b8", 32, {16, 8}, {8, 8}, {0, 8}, {0, 0}, DRM_FORMAT_XRGB8888 }, \
+	{ "a8r8g8b8", 32, {16, 8}, {8, 8}, {0, 8}, {24, 8}, DRM_FORMAT_ARGB8888 }, \
+	{ "x2r10g10b10", 32, {20, 10}, {10, 10}, {0, 10}, {0, 0}, DRM_FORMAT_XRGB2101010 }, \
+	{ "a2r10g10b10", 32, {20, 10}, {10, 10}, {0, 10}, {30, 2}, DRM_FORMAT_ARGB2101010 }, \
+}
+
+/*
+ * Data-Format for Simple-Framebuffers
+ * @name: unique 0-terminated name that can be used to identify the mode
+ * @red,green,blue: Offsets and sizes of the single RGB parts
+ * @transp: Offset and size of the alpha bits. length=0 means no alpha
+ * @fourcc: 32bit DRM four-CC code (see drm_fourcc.h)
+ */
+struct simplefb_format {
+	const char *name;
+	u32 bits_per_pixel;
+	struct fb_bitfield red;
+	struct fb_bitfield green;
+	struct fb_bitfield blue;
+	struct fb_bitfield transp;
+	u32 fourcc;
+};
+
+/*
+ * Simple-Framebuffer description
+ * If the arch-boot code creates simple-framebuffers without DT support, it
+ * can pass the width, height, stride and format via this platform-data object.
+ * The framebuffer location must be given as IORESOURCE_MEM resource.
+ * @format must be a format as described in "struct simplefb_format" above.
+ */
+struct simplefb_platform_data {
+	u32 width;
+	u32 height;
+	u32 stride;
+	const char *format;
+};
+
+#endif /* __PLATFORM_DATA_SIMPLEFB_H__ */
diff --git a/include/linux/platform_data/st_sensors_pdata.h b/include/linux/platform_data/st_sensors_pdata.h
new file mode 100644
index 0000000..7538391
--- /dev/null
+++ b/include/linux/platform_data/st_sensors_pdata.h
@@ -0,0 +1,24 @@
+/*
+ * STMicroelectronics sensors platform-data driver
+ *
+ * Copyright 2013 STMicroelectronics Inc.
+ *
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_SENSORS_PDATA_H
+#define ST_SENSORS_PDATA_H
+
+/**
+ * struct st_sensors_platform_data - Platform data for the ST sensors
+ * @drdy_int_pin: Redirect DRDY on pin 1 (1) or pin 2 (2).
+ *	Available only for accelerometer and pressure sensors.
+ *	Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet).
+ */
+struct st_sensors_platform_data {
+	u8 drdy_int_pin;
+};
+
+#endif /* ST_SENSORS_PDATA_H */
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
deleted file mode 100644
index 66c673f..0000000
--- a/include/linux/platform_data/tegra_usb.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 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 _TEGRA_USB_H_
-#define _TEGRA_USB_H_
-
-enum tegra_usb_operating_modes {
-	TEGRA_USB_DEVICE,
-	TEGRA_USB_HOST,
-	TEGRA_USB_OTG,
-};
-
-struct tegra_ehci_platform_data {
-	enum tegra_usb_operating_modes operating_mode;
-	/* power down the phy on bus suspend */
-	int power_down_on_bus_suspend;
-	void *phy_config;
-	int vbus_gpio;
-};
-
-#endif /* _TEGRA_USB_H_ */
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
index 7db3eb9..1d2cd21 100644
--- a/include/linux/pps_kernel.h
+++ b/include/linux/pps_kernel.h
@@ -80,7 +80,7 @@
  * Global variables
  */
 
-extern struct device_attribute pps_attrs[];
+extern const struct attribute_group *pps_groups[];
 
 /*
  * Internal functions.
diff --git a/include/linux/preempt_mask.h b/include/linux/preempt_mask.h
new file mode 100644
index 0000000..931bc61
--- /dev/null
+++ b/include/linux/preempt_mask.h
@@ -0,0 +1,122 @@
+#ifndef LINUX_PREEMPT_MASK_H
+#define LINUX_PREEMPT_MASK_H
+
+#include <linux/preempt.h>
+#include <asm/hardirq.h>
+
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ *
+ * The hardirq count can in theory reach the same as NR_IRQS.
+ * In reality, the number of nested IRQS is limited to the stack
+ * size as well. For archs with over 1000 IRQS it is not practical
+ * to expect that they will all nest. We give a max of 10 bits for
+ * hardirq nesting. An arch may choose to give less than 10 bits.
+ * m68k expects it to be 8.
+ *
+ * - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
+ * - bit 26 is the NMI_MASK
+ * - bit 27 is the PREEMPT_ACTIVE flag
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * SOFTIRQ_MASK: 0x0000ff00
+ * HARDIRQ_MASK: 0x03ff0000
+ *     NMI_MASK: 0x04000000
+ */
+#define PREEMPT_BITS	8
+#define SOFTIRQ_BITS	8
+#define NMI_BITS	1
+
+#define MAX_HARDIRQ_BITS 10
+
+#ifndef HARDIRQ_BITS
+# define HARDIRQ_BITS	MAX_HARDIRQ_BITS
+#endif
+
+#if HARDIRQ_BITS > MAX_HARDIRQ_BITS
+#error HARDIRQ_BITS too high!
+#endif
+
+#define PREEMPT_SHIFT	0
+#define SOFTIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT	(SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+#define NMI_SHIFT	(HARDIRQ_SHIFT + HARDIRQ_BITS)
+
+#define __IRQ_MASK(x)	((1UL << (x))-1)
+
+#define PREEMPT_MASK	(__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define SOFTIRQ_MASK	(__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+#define HARDIRQ_MASK	(__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define NMI_MASK	(__IRQ_MASK(NMI_BITS)     << NMI_SHIFT)
+
+#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
+#define NMI_OFFSET	(1UL << NMI_SHIFT)
+
+#define SOFTIRQ_DISABLE_OFFSET	(2 * SOFTIRQ_OFFSET)
+
+#ifndef PREEMPT_ACTIVE
+#define PREEMPT_ACTIVE_BITS	1
+#define PREEMPT_ACTIVE_SHIFT	(NMI_SHIFT + NMI_BITS)
+#define PREEMPT_ACTIVE	(__IRQ_MASK(PREEMPT_ACTIVE_BITS) << PREEMPT_ACTIVE_SHIFT)
+#endif
+
+#if PREEMPT_ACTIVE < (1 << (NMI_SHIFT + NMI_BITS))
+#error PREEMPT_ACTIVE is too low!
+#endif
+
+#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
+#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \
+				 | NMI_MASK))
+
+/*
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context? Interrupt context?
+ * in_softirq - Are we currently processing softirq or have bh disabled?
+ * in_serving_softirq - Are we currently processing softirq?
+ */
+#define in_irq()		(hardirq_count())
+#define in_softirq()		(softirq_count())
+#define in_interrupt()		(irq_count())
+#define in_serving_softirq()	(softirq_count() & SOFTIRQ_OFFSET)
+
+/*
+ * Are we in NMI context?
+ */
+#define in_nmi()	(preempt_count() & NMI_MASK)
+
+#if defined(CONFIG_PREEMPT_COUNT)
+# define PREEMPT_CHECK_OFFSET 1
+#else
+# define PREEMPT_CHECK_OFFSET 0
+#endif
+
+/*
+ * Are we running in atomic context?  WARNING: this macro cannot
+ * always detect atomic context; in particular, it cannot know about
+ * held spinlocks in non-preemptible kernels.  Thus it should not be
+ * used in the general case to determine whether sleeping is possible.
+ * Do not use in_atomic() in driver code.
+ */
+#define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != 0)
+
+/*
+ * Check whether we were atomic before we did preempt_disable():
+ * (used by the scheduler, *after* releasing the kernel lock)
+ */
+#define in_atomic_preempt_off() \
+		((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET)
+
+#ifdef CONFIG_PREEMPT_COUNT
+# define preemptible()	(preempt_count() == 0 && !irqs_disabled())
+#else
+# define preemptible()	0
+#endif
+
+#endif /* LINUX_PREEMPT_MASK_H */
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 22c7052..e6131a78 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -200,7 +200,7 @@
 }
 #endif
 
-extern void dump_stack(void) __cold;
+extern asmlinkage void dump_stack(void) __cold;
 
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 4aa80ba..abd437d 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -55,14 +55,14 @@
 	int		(*close)(struct pstore_info *psi);
 	ssize_t		(*read)(u64 *id, enum pstore_type_id *type,
 			int *count, struct timespec *time, char **buf,
-			struct pstore_info *psi);
+			bool *compressed, struct pstore_info *psi);
 	int		(*write)(enum pstore_type_id type,
 			enum kmsg_dump_reason reason, u64 *id,
-			unsigned int part, int count, size_t hsize,
+			unsigned int part, int count, bool compressed,
 			size_t size, struct pstore_info *psi);
 	int		(*write_buf)(enum pstore_type_id type,
 			enum kmsg_dump_reason reason, u64 *id,
-			unsigned int part, const char *buf, size_t hsize,
+			unsigned int part, const char *buf, bool compressed,
 			size_t size, struct pstore_info *psi);
 	int		(*erase)(enum pstore_type_id type, u64 id,
 			int count, struct timespec time,
diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h
index 467cc63..4944420 100644
--- a/include/linux/pxa2xx_ssp.h
+++ b/include/linux/pxa2xx_ssp.h
@@ -21,6 +21,8 @@
 
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/of.h>
+
 
 /*
  * SSP Serial Port Registers
@@ -190,6 +192,8 @@
 	int		irq;
 	int		drcmr_rx;
 	int		drcmr_tx;
+
+	struct device_node	*of_node;
 };
 
 /**
@@ -218,11 +222,18 @@
 #ifdef CONFIG_ARCH_PXA
 struct ssp_device *pxa_ssp_request(int port, const char *label);
 void pxa_ssp_free(struct ssp_device *);
+struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
+				      const char *label);
 #else
 static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
 {
 	return NULL;
 }
+static inline struct ssp_device *pxa_ssp_request_of(const struct device_node *n,
+						    const char *name)
+{
+	return NULL;
+}
 static inline void pxa_ssp_free(struct ssp_device *ssp) {}
 #endif
 
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 1c50093..6965fe3 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -41,6 +41,7 @@
 void inode_add_rsv_space(struct inode *inode, qsize_t number);
 void inode_claim_rsv_space(struct inode *inode, qsize_t number);
 void inode_sub_rsv_space(struct inode *inode, qsize_t number);
+void inode_reclaim_rsv_space(struct inode *inode, qsize_t number);
 
 void dquot_initialize(struct inode *inode);
 void dquot_drop(struct inode *inode);
@@ -59,6 +60,7 @@
 
 int dquot_claim_space_nodirty(struct inode *inode, qsize_t number);
 void dquot_free_inode(const struct inode *inode);
+void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number);
 
 int dquot_disable(struct super_block *sb, int type, unsigned int flags);
 /* Suspend quotas on remount RO */
@@ -238,6 +240,13 @@
 	return 0;
 }
 
+static inline int dquot_reclaim_space_nodirty(struct inode *inode,
+					      qsize_t number)
+{
+	inode_sub_bytes(inode, number);
+	return 0;
+}
+
 static inline int dquot_disable(struct super_block *sb, int type,
 		unsigned int flags)
 {
@@ -336,6 +345,12 @@
 	return ret;
 }
 
+static inline void dquot_reclaim_block(struct inode *inode, qsize_t nr)
+{
+	dquot_reclaim_space_nodirty(inode, nr << inode->i_blkbits);
+	mark_inode_dirty_sync(inode);
+}
+
 static inline void dquot_free_space_nodirty(struct inode *inode, qsize_t nr)
 {
 	__dquot_free_space(inode, nr, 0);
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index f4b1001..4106721 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -267,8 +267,9 @@
  */
 #define list_first_or_null_rcu(ptr, type, member) \
 	({struct list_head *__ptr = (ptr); \
-	  struct list_head __rcu *__next = list_next_rcu(__ptr); \
-	  likely(__ptr != __next) ? container_of(__next, type, member) : NULL; \
+	  struct list_head *__next = ACCESS_ONCE(__ptr->next); \
+	  likely(__ptr != __next) ? \
+		list_entry_rcu(__next, type, member) : NULL; \
 	})
 
 /**
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 4b14bdc..f1f1bc3 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -52,7 +52,7 @@
 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
 extern void rcutorture_record_test_transition(void);
 extern void rcutorture_record_progress(unsigned long vernum);
-extern void do_trace_rcu_torture_read(char *rcutorturename,
+extern void do_trace_rcu_torture_read(const char *rcutorturename,
 				      struct rcu_head *rhp,
 				      unsigned long secs,
 				      unsigned long c_old,
@@ -65,7 +65,7 @@
 {
 }
 #ifdef CONFIG_RCU_TRACE
-extern void do_trace_rcu_torture_read(char *rcutorturename,
+extern void do_trace_rcu_torture_read(const char *rcutorturename,
 				      struct rcu_head *rhp,
 				      unsigned long secs,
 				      unsigned long c_old,
@@ -229,13 +229,9 @@
 #ifdef CONFIG_RCU_USER_QS
 extern void rcu_user_enter(void);
 extern void rcu_user_exit(void);
-extern void rcu_user_enter_after_irq(void);
-extern void rcu_user_exit_after_irq(void);
 #else
 static inline void rcu_user_enter(void) { }
 static inline void rcu_user_exit(void) { }
-static inline void rcu_user_enter_after_irq(void) { }
-static inline void rcu_user_exit_after_irq(void) { }
 static inline void rcu_user_hooks_switch(struct task_struct *prev,
 					 struct task_struct *next) { }
 #endif /* CONFIG_RCU_USER_QS */
@@ -1015,4 +1011,22 @@
 #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
 
 
+/* Only for use by adaptive-ticks code. */
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+extern bool rcu_sys_is_idle(void);
+extern void rcu_sysidle_force_exit(void);
+#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
+
+static inline bool rcu_sys_is_idle(void)
+{
+	return false;
+}
+
+static inline void rcu_sysidle_force_exit(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
+
+
 #endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 580a532..a10380b 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <linux/err.h>
+#include <linux/bug.h>
 
 struct module;
 struct device;
@@ -471,6 +472,9 @@
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
+ * @init_ack_masked: Ack all masked interrupts once during initalization.
+ * @mask_invert: Inverted mask register: cleared bits are masked out.
+ * @wake_invert: Inverted wake register: cleared bits are wake enabled.
  * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
@@ -486,9 +490,10 @@
 	unsigned int ack_base;
 	unsigned int wake_base;
 	unsigned int irq_reg_stride;
-	unsigned int mask_invert;
-	unsigned int wake_invert;
-	bool runtime_pm;
+	bool init_ack_masked:1;
+	bool mask_invert:1;
+	bool wake_invert:1;
+	bool runtime_pm:1;
 
 	int num_regs;
 
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 3a76389..27be915 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -137,6 +137,12 @@
 					     const char *id);
 struct regulator *__must_check regulator_get_exclusive(struct device *dev,
 						       const char *id);
+struct regulator *__must_check devm_regulator_get_exclusive(struct device *dev,
+							const char *id);
+struct regulator *__must_check regulator_get_optional(struct device *dev,
+						      const char *id);
+struct regulator *__must_check devm_regulator_get_optional(struct device *dev,
+							   const char *id);
 void regulator_put(struct regulator *regulator);
 void devm_regulator_put(struct regulator *regulator);
 
@@ -217,6 +223,25 @@
 	return NULL;
 }
 
+static inline struct regulator *__must_check
+regulator_get_exclusive(struct device *dev, const char *id)
+{
+	return NULL;
+}
+
+static inline struct regulator *__must_check
+regulator_get_optional(struct device *dev, const char *id)
+{
+	return NULL;
+}
+
+
+static inline struct regulator *__must_check
+devm_regulator_get_optional(struct device *dev, const char *id)
+{
+	return NULL;
+}
+
 static inline void regulator_put(struct regulator *regulator)
 {
 }
@@ -369,8 +394,11 @@
 static inline int regulator_set_voltage_tol(struct regulator *regulator,
 					    int new_uV, int tol_uV)
 {
-	return regulator_set_voltage(regulator,
-				     new_uV - tol_uV, new_uV + tol_uV);
+	if (regulator_set_voltage(regulator, new_uV, new_uV + tol_uV) == 0)
+		return 0;
+	else
+		return regulator_set_voltage(regulator,
+					     new_uV - tol_uV, new_uV + tol_uV);
 }
 
 static inline int regulator_is_supported_voltage_tol(struct regulator *regulator,
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 6700cc9..67e13aa 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -40,6 +40,24 @@
 };
 
 /**
+ * Specify a range of voltages for regulator_map_linar_range() and
+ * regulator_list_linear_range().
+ *
+ * @min_uV:  Lowest voltage in range
+ * @max_uV:  Highest voltage in range
+ * @min_sel: Lowest selector for range
+ * @max_sel: Highest selector for range
+ * @uV_step: Step size
+ */
+struct regulator_linear_range {
+	unsigned int min_uV;
+	unsigned int max_uV;
+	unsigned int min_sel;
+	unsigned int max_sel;
+	unsigned int uV_step;
+};
+
+/**
  * struct regulator_ops - regulator operations.
  *
  * @enable: Configure the regulator as enabled.
@@ -223,6 +241,9 @@
 	unsigned int linear_min_sel;
 	unsigned int ramp_delay;
 
+	const struct regulator_linear_range *linear_ranges;
+	int n_linear_ranges;
+
 	const unsigned int *volt_table;
 
 	unsigned int vsel_reg;
@@ -326,10 +347,14 @@
 
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
 				  unsigned int selector);
+int regulator_list_voltage_linear_range(struct regulator_dev *rdev,
+					unsigned int selector);
 int regulator_list_voltage_table(struct regulator_dev *rdev,
 				  unsigned int selector);
 int regulator_map_voltage_linear(struct regulator_dev *rdev,
 				  int min_uV, int max_uV);
+int regulator_map_voltage_linear_range(struct regulator_dev *rdev,
+				       int min_uV, int max_uV);
 int regulator_map_voltage_iterate(struct regulator_dev *rdev,
 				  int min_uV, int max_uV);
 int regulator_map_voltage_ascend(struct regulator_dev *rdev,
diff --git a/include/linux/regulator/fan53555.h b/include/linux/regulator/fan53555.h
index 5c45c85..f13880e 100644
--- a/include/linux/regulator/fan53555.h
+++ b/include/linux/regulator/fan53555.h
@@ -11,6 +11,7 @@
  */
 
 #ifndef __FAN53555_H__
+#define __FAN53555_H__
 
 /* VSEL ID */
 enum {
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 36adbc8..999b20c 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -134,6 +134,7 @@
 	unsigned always_on:1;	/* regulator never off when system is on */
 	unsigned boot_on:1;	/* bootloader/firmware enabled regulator */
 	unsigned apply_uV:1;	/* apply uV constraint if min == max */
+	unsigned ramp_disable:1; /* disable ramp delay */
 };
 
 /**
diff --git a/include/linux/regulator/max8660.h b/include/linux/regulator/max8660.h
index 9936763..f8a6a48 100644
--- a/include/linux/regulator/max8660.h
+++ b/include/linux/regulator/max8660.h
@@ -39,7 +39,7 @@
  */
 struct max8660_subdev_data {
 	int				id;
-	char				*name;
+	const char			*name;
 	struct regulator_init_data	*platform_data;
 };
 
diff --git a/include/linux/regulator/pfuze100.h b/include/linux/regulator/pfuze100.h
new file mode 100644
index 0000000..65d550b
--- /dev/null
+++ b/include/linux/regulator/pfuze100.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef __LINUX_REG_PFUZE100_H
+#define __LINUX_REG_PFUZE100_H
+
+#define PFUZE100_SW1AB		0
+#define PFUZE100_SW1C		1
+#define PFUZE100_SW2		2
+#define PFUZE100_SW3A		3
+#define PFUZE100_SW3B		4
+#define PFUZE100_SW4		5
+#define PFUZE100_SWBST		6
+#define PFUZE100_VSNVS		7
+#define PFUZE100_VREFDDR	8
+#define PFUZE100_VGEN1		9
+#define PFUZE100_VGEN2		10
+#define PFUZE100_VGEN3		11
+#define PFUZE100_VGEN4		12
+#define PFUZE100_VGEN5		13
+#define PFUZE100_VGEN6		14
+#define PFUZE100_MAX_REGULATOR	15
+
+struct regulator_init_data;
+
+struct pfuze_regulator_platform_data {
+	struct regulator_init_data *init_data[PFUZE100_MAX_REGULATOR];
+};
+
+#endif /* __LINUX_REG_PFUZE100_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e9995eb..ce1e1c0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -107,14 +107,6 @@
 extern void calc_global_load(unsigned long ticks);
 extern void update_cpu_load_nohz(void);
 
-/* Notifier for when a task gets migrated to a new CPU */
-struct task_migration_notifier {
-	struct task_struct *task;
-	int from_cpu;
-	int to_cpu;
-};
-extern void register_task_migration_notifier(struct notifier_block *n);
-
 extern unsigned long get_parent_ip(unsigned long addr);
 
 extern void dump_cpu_task(int cpu);
@@ -314,7 +306,6 @@
 struct user_namespace;
 
 #ifdef CONFIG_MMU
-extern unsigned long mmap_legacy_base(void);
 extern void arch_pick_mmap_layout(struct mm_struct *mm);
 extern unsigned long
 arch_get_unmapped_area(struct file *, unsigned long, unsigned long,
@@ -1035,6 +1026,9 @@
 #ifdef CONFIG_SMP
 	struct llist_node wake_entry;
 	int on_cpu;
+	struct task_struct *last_wakee;
+	unsigned long wakee_flips;
+	unsigned long wakee_flip_decay_ts;
 #endif
 	int on_rq;
 
diff --git a/include/linux/signal.h b/include/linux/signal.h
index d897484..2ac423b 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -434,6 +434,14 @@
 int restore_altstack(const stack_t __user *);
 int __save_altstack(stack_t __user *, unsigned long);
 
+#define save_altstack_ex(uss, sp) do { \
+	stack_t __user *__uss = uss; \
+	struct task_struct *t = current; \
+	put_user_ex((void __user *)t->sas_ss_sp, &__uss->ss_sp); \
+	put_user_ex(sas_ss_flags(sp), &__uss->ss_flags); \
+	put_user_ex(t->sas_ss_size, &__uss->ss_size); \
+} while (0);
+
 #ifdef CONFIG_PROC_FS
 struct seq_file;
 extern void render_sigset_t(struct seq_file *, const char *, sigset_t *);
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 28e440b..887116d 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -74,7 +74,7 @@
 	struct spi_master	*master;
 	u32			max_speed_hz;
 	u8			chip_select;
-	u8			mode;
+	u16			mode;
 #define	SPI_CPHA	0x01			/* clock phase */
 #define	SPI_CPOL	0x02			/* clock polarity */
 #define	SPI_MODE_0	(0|0)			/* (original MicroWire) */
@@ -87,6 +87,10 @@
 #define	SPI_LOOP	0x20			/* loopback mode */
 #define	SPI_NO_CS	0x40			/* 1 dev/bus, no chipselect */
 #define	SPI_READY	0x80			/* slave pulls low to pause */
+#define	SPI_TX_DUAL	0x100			/* transmit with 2 wires */
+#define	SPI_TX_QUAD	0x200			/* transmit with 4 wires */
+#define	SPI_RX_DUAL	0x400			/* receive with 2 wires */
+#define	SPI_RX_QUAD	0x800			/* receive with 4 wires */
 	u8			bits_per_word;
 	int			irq;
 	void			*controller_state;
@@ -233,6 +237,8 @@
  *	suported. If set, the SPI core will reject any transfer with an
  *	unsupported bits_per_word. If not set, this value is simply ignored,
  *	and it's up to the individual driver to perform any validation.
+ * @min_speed_hz: Lowest supported transfer speed
+ * @max_speed_hz: Highest supported transfer speed
  * @flags: other constraints relevant to this driver
  * @bus_lock_spinlock: spinlock for SPI bus locking
  * @bus_lock_mutex: mutex for SPI bus locking
@@ -254,6 +260,9 @@
  * @busy: message pump is busy
  * @running: message pump is running
  * @rt: whether this queue is set to run as a realtime task
+ * @auto_runtime_pm: the core should ensure a runtime PM reference is held
+ *                   while the hardware is prepared, using the parent
+ *                   device for the spidev
  * @prepare_transfer_hardware: a message will soon arrive from the queue
  *	so the subsystem requests the driver to prepare the transfer hardware
  *	by issuing this call
@@ -309,9 +318,13 @@
 	/* bitmask of supported bits_per_word for transfers */
 	u32			bits_per_word_mask;
 #define SPI_BPW_MASK(bits) BIT((bits) - 1)
-#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1))
+#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))
 #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))
 
+	/* limits on transfer speed */
+	u32			min_speed_hz;
+	u32			max_speed_hz;
+
 	/* other constraints relevant to this driver */
 	u16			flags;
 #define SPI_MASTER_HALF_DUPLEX	BIT(0)		/* can't do full duplex */
@@ -374,11 +387,13 @@
 	bool				busy;
 	bool				running;
 	bool				rt;
+	bool				auto_runtime_pm;
 
 	int (*prepare_transfer_hardware)(struct spi_master *master);
 	int (*transfer_one_message)(struct spi_master *master,
 				    struct spi_message *mesg);
 	int (*unprepare_transfer_hardware)(struct spi_master *master);
+
 	/* gpio chip select */
 	int			*cs_gpios;
 };
@@ -448,6 +463,10 @@
  * @rx_buf: data to be read (dma-safe memory), or NULL
  * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
  * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
+ * @tx_nbits: number of bits used for writting. If 0 the default
+ *      (SPI_NBITS_SINGLE) is used.
+ * @rx_nbits: number of bits used for reading. If 0 the default
+ *      (SPI_NBITS_SINGLE) is used.
  * @len: size of rx and tx buffers (in bytes)
  * @speed_hz: Select a speed other than the device default for this
  *      transfer. If 0 the default (from @spi_device) is used.
@@ -502,6 +521,11 @@
  * by the results of previous messages and where the whole transaction
  * ends when the chipselect goes intactive.
  *
+ * When SPI can transfer in 1x,2x or 4x. It can get this tranfer information
+ * from device through @tx_nbits and @rx_nbits. In Bi-direction, these
+ * two should both be set. User can set transfer mode with SPI_NBITS_SINGLE(1x)
+ * SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer.
+ *
  * The code that submits an spi_message (and its spi_transfers)
  * to the lower layers is responsible for managing its memory.
  * Zero-initialize every field you don't set up explicitly, to
@@ -522,6 +546,11 @@
 	dma_addr_t	rx_dma;
 
 	unsigned	cs_change:1;
+	u8		tx_nbits;
+	u8		rx_nbits;
+#define	SPI_NBITS_SINGLE	0x01 /* 1bit transfer */
+#define	SPI_NBITS_DUAL		0x02 /* 2bits transfer */
+#define	SPI_NBITS_QUAD		0x04 /* 4bits transfer */
 	u8		bits_per_word;
 	u16		delay_usecs;
 	u32		speed_hz;
@@ -578,6 +607,7 @@
 	/* completion is reported through a callback */
 	void			(*complete)(void *context);
 	void			*context;
+	unsigned		frame_length;
 	unsigned		actual_length;
 	int			status;
 
@@ -869,7 +899,7 @@
 	/* mode becomes spi_device.mode, and is essential for chips
 	 * where the default of SPI_CS_HIGH = 0 is wrong.
 	 */
-	u8		mode;
+	u16		mode;
 
 	/* ... may need additional spi_device chip config data here.
 	 * avoid stuff protocol drivers can set; but include stuff
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index f987a2b..daebaba 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -4,11 +4,7 @@
 #include <linux/workqueue.h>
 
 struct spi_bitbang {
-	struct workqueue_struct	*workqueue;
-	struct work_struct	work;
-
 	spinlock_t		lock;
-	struct list_head	queue;
 	u8			busy;
 	u8			use_dma;
 	u8			flags;		/* extra spi->mode support */
@@ -41,7 +37,6 @@
  */
 extern int spi_bitbang_setup(struct spi_device *spi);
 extern void spi_bitbang_cleanup(struct spi_device *spi);
-extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
 extern int spi_bitbang_setup_transfer(struct spi_device *spi,
 				      struct spi_transfer *t);
 
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 9e8a9b5..11baec7 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -51,9 +51,9 @@
 	static struct lock_class_key __key;		\
 							\
 	(attr)->key = &__key;				\
-} while(0)
+} while (0)
 #else
-#define sysfs_attr_init(attr) do {} while(0)
+#define sysfs_attr_init(attr) do {} while (0)
 #endif
 
 struct attribute_group {
@@ -69,7 +69,7 @@
  * for examples..
  */
 
-#define __ATTR(_name,_mode,_show,_store) { 				\
+#define __ATTR(_name, _mode, _show, _store) {				\
 	.attr = {.name = __stringify(_name), .mode = _mode },		\
 	.show	= _show,						\
 	.store	= _store,						\
@@ -80,6 +80,11 @@
 	.show	= _name##_show,						\
 }
 
+#define __ATTR_WO(_name) {						\
+	.attr	= { .name = __stringify(_name), .mode = S_IWUSR },	\
+	.store	= _name##_store,					\
+}
+
 #define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO),		\
 			 _name##_show, _name##_store)
 
@@ -108,8 +113,6 @@
 };								\
 __ATTRIBUTE_GROUPS(_name)
 
-#define attr_name(_attr) (_attr).attr.name
-
 struct file;
 struct vm_area_struct;
 
@@ -119,7 +122,7 @@
 	void			*private;
 	ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
 			char *, loff_t, size_t);
-	ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,
+	ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,
 			 char *, loff_t, size_t);
 	int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,
 		    struct vm_area_struct *vma);
@@ -153,7 +156,7 @@
 
 #define __BIN_ATTR_RW(_name, _size) __BIN_ATTR(_name,			\
 				   (S_IWUSR | S_IRUGO), _name##_read,	\
-				   _name##_write)
+				   _name##_write, _size)
 
 #define __BIN_ATTR_NULL __ATTR_NULL
 
@@ -168,8 +171,8 @@
 struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size)
 
 struct sysfs_ops {
-	ssize_t	(*show)(struct kobject *, struct attribute *,char *);
-	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
+	ssize_t	(*show)(struct kobject *, struct attribute *, char *);
+	ssize_t	(*store)(struct kobject *, struct attribute *, const char *, size_t);
 	const void *(*namespace)(struct kobject *, const struct attribute *);
 };
 
@@ -215,10 +218,14 @@
 
 int __must_check sysfs_create_group(struct kobject *kobj,
 				    const struct attribute_group *grp);
+int __must_check sysfs_create_groups(struct kobject *kobj,
+				     const struct attribute_group **groups);
 int sysfs_update_group(struct kobject *kobj,
 		       const struct attribute_group *grp);
 void sysfs_remove_group(struct kobject *kobj,
 			const struct attribute_group *grp);
+void sysfs_remove_groups(struct kobject *kobj,
+			 const struct attribute_group **groups);
 int sysfs_add_file_to_group(struct kobject *kobj,
 			const struct attribute *attr, const char *group);
 void sysfs_remove_file_from_group(struct kobject *kobj,
@@ -343,6 +350,12 @@
 	return 0;
 }
 
+static inline int sysfs_create_groups(struct kobject *kobj,
+				      const struct attribute_group **groups)
+{
+	return 0;
+}
+
 static inline int sysfs_update_group(struct kobject *kobj,
 				const struct attribute_group *grp)
 {
@@ -354,6 +367,11 @@
 {
 }
 
+static inline void sysfs_remove_groups(struct kobject *kobj,
+				       const struct attribute_group **groups)
+{
+}
+
 static inline int sysfs_add_file_to_group(struct kobject *kobj,
 		const struct attribute *attr, const char *group)
 {
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 62bd8b7..5128d33 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -10,6 +10,8 @@
 #include <linux/irqflags.h>
 #include <linux/percpu.h>
 #include <linux/hrtimer.h>
+#include <linux/context_tracking_state.h>
+#include <linux/cpumask.h>
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 
@@ -158,20 +160,51 @@
 # endif /* !CONFIG_NO_HZ_COMMON */
 
 #ifdef CONFIG_NO_HZ_FULL
+extern bool tick_nohz_full_running;
+extern cpumask_var_t tick_nohz_full_mask;
+
+static inline bool tick_nohz_full_enabled(void)
+{
+	if (!static_key_false(&context_tracking_enabled))
+		return false;
+
+	return tick_nohz_full_running;
+}
+
+static inline bool tick_nohz_full_cpu(int cpu)
+{
+	if (!tick_nohz_full_enabled())
+		return false;
+
+	return cpumask_test_cpu(cpu, tick_nohz_full_mask);
+}
+
 extern void tick_nohz_init(void);
-extern int tick_nohz_full_cpu(int cpu);
-extern void tick_nohz_full_check(void);
+extern void __tick_nohz_full_check(void);
 extern void tick_nohz_full_kick(void);
 extern void tick_nohz_full_kick_all(void);
-extern void tick_nohz_task_switch(struct task_struct *tsk);
+extern void __tick_nohz_task_switch(struct task_struct *tsk);
 #else
 static inline void tick_nohz_init(void) { }
-static inline int tick_nohz_full_cpu(int cpu) { return 0; }
-static inline void tick_nohz_full_check(void) { }
+static inline bool tick_nohz_full_enabled(void) { return false; }
+static inline bool tick_nohz_full_cpu(int cpu) { return false; }
+static inline void __tick_nohz_full_check(void) { }
 static inline void tick_nohz_full_kick(void) { }
 static inline void tick_nohz_full_kick_all(void) { }
-static inline void tick_nohz_task_switch(struct task_struct *tsk) { }
+static inline void __tick_nohz_task_switch(struct task_struct *tsk) { }
 #endif
 
+static inline void tick_nohz_full_check(void)
+{
+	if (tick_nohz_full_enabled())
+		__tick_nohz_full_check();
+}
+
+static inline void tick_nohz_task_switch(struct task_struct *tsk)
+{
+	if (tick_nohz_full_enabled())
+		__tick_nohz_task_switch(tsk);
+}
+
 
 #endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 01ac30e..64f8646 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -10,6 +10,8 @@
 #include <linux/mutex.h>
 #include <linux/tty_flags.h>
 #include <uapi/linux/tty.h>
+#include <linux/rwsem.h>
+#include <linux/llist.h>
 
 
 
@@ -29,9 +31,10 @@
 #define __DISABLED_CHAR '\0'
 
 struct tty_buffer {
-	struct tty_buffer *next;
-	char *char_buf_ptr;
-	unsigned char *flag_buf_ptr;
+	union {
+		struct tty_buffer *next;
+		struct llist_node free;
+	};
 	int used;
 	int size;
 	int commit;
@@ -40,25 +43,25 @@
 	unsigned long data[0];
 };
 
-/*
- * We default to dicing tty buffer allocations to this many characters
- * in order to avoid multiple page allocations. We know the size of
- * tty_buffer itself but it must also be taken into account that the
- * the buffer is 256 byte aligned. See tty_buffer_find for the allocation
- * logic this must match
- */
+static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs)
+{
+	return ((unsigned char *)b->data) + ofs;
+}
 
-#define TTY_BUFFER_PAGE	(((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
-
+static inline char *flag_buf_ptr(struct tty_buffer *b, int ofs)
+{
+	return (char *)char_buf_ptr(b, ofs) + b->size;
+}
 
 struct tty_bufhead {
-	struct work_struct work;
-	spinlock_t lock;
 	struct tty_buffer *head;	/* Queue head */
+	struct work_struct work;
+	struct mutex	   lock;
+	atomic_t	   priority;
+	struct tty_buffer sentinel;
+	struct llist_head free;		/* Free queue head */
+	atomic_t	   memory_used; /* In-use buffers excluding free list */
 	struct tty_buffer *tail;	/* Active buffer */
-	struct tty_buffer *free;	/* Free queue head */
-	int memory_used;		/* Buffer space used excluding
-								free queue */
 };
 /*
  * When a break, frame error, or parity error happens, these codes are
@@ -199,9 +202,6 @@
 	wait_queue_head_t	close_wait;	/* Close waiters */
 	wait_queue_head_t	delta_msr_wait;	/* Modem status change */
 	unsigned long		flags;		/* TTY flags ASY_*/
-	unsigned long		iflags;		/* TTYP_ internal flags */
-#define TTYP_FLUSHING			1  /* Flushing to ldisc in progress */
-#define TTYP_FLUSHPENDING		2  /* Queued buffer flush pending */
 	unsigned char		console:1,	/* port is a console */
 				low_latency:1;	/* direct buffer flush */
 	struct mutex		mutex;		/* Locking */
@@ -238,14 +238,16 @@
 	int index;
 
 	/* Protects ldisc changes: Lock tty not pty */
-	struct mutex ldisc_mutex;
+	struct ld_semaphore ldisc_sem;
 	struct tty_ldisc *ldisc;
 
 	struct mutex atomic_write_lock;
 	struct mutex legacy_mutex;
-	struct mutex termios_mutex;
+	struct mutex throttle_mutex;
+	struct rw_semaphore termios_rwsem;
+	struct mutex winsize_mutex;
 	spinlock_t ctrl_lock;
-	/* Termios values are protected by the termios mutex */
+	/* Termios values are protected by the termios rwsem */
 	struct ktermios termios, termios_locked;
 	struct termiox *termiox;	/* May be NULL for unsupported */
 	char name[64];
@@ -253,7 +255,7 @@
 	struct pid *session;
 	unsigned long flags;
 	int count;
-	struct winsize winsize;		/* termios mutex */
+	struct winsize winsize;		/* winsize_mutex */
 	unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
 	unsigned char ctrl_status;	/* ctrl_lock */
 	unsigned int receive_room;	/* Bytes free for queue */
@@ -303,10 +305,7 @@
 #define TTY_EXCLUSIVE 		3	/* Exclusive open mode */
 #define TTY_DEBUG 		4	/* Debugging */
 #define TTY_DO_WRITE_WAKEUP 	5	/* Call write_wakeup after queuing new */
-#define TTY_PUSH 		6	/* n_tty private */
 #define TTY_CLOSING 		7	/* ->close() in progress */
-#define TTY_LDISC 		9	/* Line discipline attached */
-#define TTY_LDISC_CHANGING 	10	/* Line discipline changing */
 #define TTY_LDISC_OPEN	 	11	/* Line discipline is open */
 #define TTY_PTY_LOCK 		16	/* pty private */
 #define TTY_NO_WRITE_SPLIT 	17	/* Preserve write boundaries to driver */
@@ -559,6 +558,19 @@
 extern void tty_ldisc_deinit(struct tty_struct *tty);
 extern void tty_ldisc_begin(void);
 
+static inline int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p,
+					char *f, int count)
+{
+	if (ld->ops->receive_buf2)
+		count = ld->ops->receive_buf2(ld->tty, p, f, count);
+	else {
+		count = min_t(int, count, ld->tty->receive_room);
+		if (count)
+			ld->ops->receive_buf(ld->tty, p, f, count);
+	}
+	return count;
+}
+
 
 /* n_tty.c */
 extern struct tty_ldisc_ops tty_ldisc_N_TTY;
diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h
index e0f2526..21ddd7d 100644
--- a/include/linux/tty_flip.h
+++ b/include/linux/tty_flip.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_TTY_FLIP_H
 #define _LINUX_TTY_FLIP_H
 
+extern int tty_buffer_space_avail(struct tty_port *port);
 extern int tty_buffer_request_room(struct tty_port *port, size_t size);
 extern int tty_insert_flip_string_flags(struct tty_port *port,
 		const unsigned char *chars, const char *flags, size_t size);
@@ -18,8 +19,8 @@
 {
 	struct tty_buffer *tb = port->buf.tail;
 	if (tb && tb->used < tb->size) {
-		tb->flag_buf_ptr[tb->used] = flag;
-		tb->char_buf_ptr[tb->used++] = ch;
+		*flag_buf_ptr(tb, tb->used) = flag;
+		*char_buf_ptr(tb, tb->used++) = ch;
 		return 1;
 	}
 	return tty_insert_flip_string_flags(port, &ch, &flag, 1);
@@ -31,4 +32,7 @@
 	return tty_insert_flip_string_fixed_flag(port, chars, TTY_NORMAL, size);
 }
 
+extern void tty_buffer_lock_exclusive(struct tty_port *port);
+extern void tty_buffer_unlock_exclusive(struct tty_port *port);
+
 #endif /* _LINUX_TTY_FLIP_H */
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index a1b0489..f15c898 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -109,6 +109,17 @@
  *
  *	Tells the discipline that the DCD pin has changed its status.
  *	Used exclusively by the N_PPS (Pulse-Per-Second) line discipline.
+ *
+ * int	(*receive_buf2)(struct tty_struct *, const unsigned char *cp,
+ *			char *fp, int count);
+ *
+ *	This function is called by the low-level tty driver to send
+ *	characters received by the hardware to the line discpline for
+ *	processing.  <cp> is a pointer to the buffer of input
+ *	character received by the device.  <fp> is a pointer to a
+ *	pointer of flag bytes which indicate whether a character was
+ *	received with a parity error, etc.
+ *	If assigned, prefer this function for automatic flow control.
  */
 
 #include <linux/fs.h>
@@ -195,6 +206,8 @@
 	void	(*write_wakeup)(struct tty_struct *);
 	void	(*dcd_change)(struct tty_struct *, unsigned int);
 	void	(*fasync)(struct tty_struct *tty, int on);
+	int	(*receive_buf2)(struct tty_struct *, const unsigned char *cp,
+				char *fp, int count);
 
 	struct  module *owner;
 
@@ -203,8 +216,7 @@
 
 struct tty_ldisc {
 	struct tty_ldisc_ops *ops;
-	atomic_t users;
-	wait_queue_head_t wq_idle;
+	struct tty_struct *tty;
 };
 
 #define TTY_LDISC_MAGIC	0x5403
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 0eec268..001629c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -337,6 +337,7 @@
 					 * the ep queue on a short transfer
 					 * with the URB_SHORT_NOT_OK flag set.
 					 */
+	unsigned no_sg_constraint:1;	/* no sg constraint */
 	unsigned sg_tablesize;		/* 0 or largest number of sg list entries */
 
 	int devnum_next;		/* Next open device number in
@@ -684,6 +685,11 @@
 	return udev->bos->ss_cap->bmAttributes & USB_LTM_SUPPORT;
 }
 
+static inline bool usb_device_no_sg_constraint(struct usb_device *udev)
+{
+	return udev && udev->bus && udev->bus->no_sg_constraint;
+}
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -708,7 +714,10 @@
  * usb_interface_claimed - returns true iff an interface is claimed
  * @iface: the interface being checked
  *
- * Returns true (nonzero) iff the interface is claimed, else false (zero).
+ * Return: %true (nonzero) iff the interface is claimed, else %false
+ * (zero).
+ *
+ * Note:
  * Callers must own the driver model's usb bus readlock.  So driver
  * probe() entries don't need extra locking, but other call contexts
  * may need to explicitly claim that lock.
@@ -745,8 +754,9 @@
  * @buf: where to put the string
  * @size: how big is "buf"?
  *
- * Returns length of the string (> 0) or negative if size was too small.
+ * Return: Length of the string (> 0) or negative if size was too small.
  *
+ * Note:
  * This identifier is intended to be "stable", reflecting physical paths in
  * hardware such as physical bus addresses for host controllers or ports on
  * USB hubs.  That makes it stay the same until systems are physically
@@ -1247,7 +1257,9 @@
  *	the device driver is saying that it provided this DMA address,
  *	which the host controller driver should use in preference to the
  *	transfer_buffer.
- * @sg: scatter gather buffer list
+ * @sg: scatter gather buffer list, the buffer size of each element in
+ * 	the list (except the last) must be divisible by the endpoint's
+ * 	max packet size if no_sg_constraint isn't set in 'struct usb_bus'
  * @num_mapped_sgs: (internal) number of mapped sg entries
  * @num_sgs: number of entries in the sg list
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
@@ -1534,10 +1546,16 @@
 	urb->transfer_buffer_length = buffer_length;
 	urb->complete = complete_fn;
 	urb->context = context;
-	if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER)
+
+	if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
+		/* make sure interval is within allowed range */
+		interval = clamp(interval, 1, 16);
+
 		urb->interval = 1 << (interval - 1);
-	else
+	} else {
 		urb->interval = interval;
+	}
+
 	urb->start_frame = -1;
 }
 
@@ -1570,7 +1588,7 @@
  * usb_urb_dir_in - check if an URB describes an IN transfer
  * @urb: URB to be checked
  *
- * Returns 1 if @urb describes an IN transfer (device-to-host),
+ * Return: 1 if @urb describes an IN transfer (device-to-host),
  * otherwise 0.
  */
 static inline int usb_urb_dir_in(struct urb *urb)
@@ -1582,7 +1600,7 @@
  * usb_urb_dir_out - check if an URB describes an OUT transfer
  * @urb: URB to be checked
  *
- * Returns 1 if @urb describes an OUT transfer (host-to-device),
+ * Return: 1 if @urb describes an OUT transfer (host-to-device),
  * otherwise 0.
  */
 static inline int usb_urb_dir_out(struct urb *urb)
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 2562994..7d39967 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -18,12 +18,17 @@
 	unsigned long	 flags;
 #define CI_HDRC_REGS_SHARED		BIT(0)
 #define CI_HDRC_REQUIRE_TRANSCEIVER	BIT(1)
-#define CI_HDRC_PULLUP_ON_VBUS		BIT(2)
 #define CI_HDRC_DISABLE_STREAMING	BIT(3)
+	/*
+	 * Only set it when DCCPARAMS.DC==1 and DCCPARAMS.HC==1,
+	 * but otg is not supported (no register otgsc).
+	 */
+#define CI_HDRC_DUAL_ROLE_NOT_OTG	BIT(4)
 	enum usb_dr_mode	dr_mode;
 #define CI_HDRC_CONTROLLER_RESET_EVENT		0
 #define CI_HDRC_CONTROLLER_STOPPED_EVENT	1
 	void	(*notify_event) (struct ci_hdrc *ci, unsigned event);
+	struct regulator	*reg_vbus;
 };
 
 /* Default offset of capability registers */
diff --git a/include/linux/usb/dwc3-omap.h b/include/linux/usb/dwc3-omap.h
deleted file mode 100644
index 5615f4d..0000000
--- a/include/linux/usb/dwc3-omap.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2013 by Texas Instruments
- *
- * The Inventra Controller Driver for Linux 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 __DWC3_OMAP_H__
-#define __DWC3_OMAP_H__
-
-enum omap_dwc3_vbus_id_status {
-	OMAP_DWC3_UNKNOWN = 0,
-	OMAP_DWC3_ID_GROUND,
-	OMAP_DWC3_ID_FLOAT,
-	OMAP_DWC3_VBUS_VALID,
-	OMAP_DWC3_VBUS_OFF,
-};
-
-#if (defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_DWC3_MODULE))
-extern int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
-#else
-static inline int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
-{
-	return -ENODEV;
-}
-#endif
-
-#endif	/* __DWC3_OMAP_H__ */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index f1b0dca..942ef5e 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 #include <linux/usb/ch9.h>
 
 struct usb_ep;
@@ -475,6 +476,7 @@
 
 /**
  * struct usb_gadget - represents a usb slave device
+ * @work: (internal use) Workqueue to be used for sysfs_notify()
  * @ops: Function pointers used to access hardware-specific operations.
  * @ep0: Endpoint zero, used when reading or writing responses to
  *	driver setup() requests
@@ -520,6 +522,7 @@
  * device is acting as a B-Peripheral (so is_a_peripheral is false).
  */
 struct usb_gadget {
+	struct work_struct		work;
 	/* readonly to gadget driver */
 	const struct usb_gadget_ops	*ops;
 	struct usb_ep			*ep0;
@@ -538,6 +541,7 @@
 	unsigned			out_epnum;
 	unsigned			in_epnum;
 };
+#define work_to_gadget(w)	(container_of((w), struct usb_gadget, work))
 
 static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
 	{ dev_set_drvdata(&gadget->dev, data); }
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 1e88377..75efc45 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -22,6 +22,7 @@
 #ifdef __KERNEL__
 
 #include <linux/rwsem.h>
+#include <linux/interrupt.h>
 
 #define MAX_TOPO_LEVEL		6
 
@@ -67,6 +68,13 @@
 
 /*-------------------------------------------------------------------------*/
 
+struct giveback_urb_bh {
+	bool running;
+	spinlock_t lock;
+	struct list_head  head;
+	struct tasklet_struct bh;
+};
+
 struct usb_hcd {
 
 	/*
@@ -139,6 +147,9 @@
 	resource_size_t		rsrc_len;	/* memory/io resource length */
 	unsigned		power_budget;	/* in mA, 0 = no limit */
 
+	struct giveback_urb_bh  high_prio_bh;
+	struct giveback_urb_bh  low_prio_bh;
+
 	/* bandwidth_mutex should be taken before adding or removing
 	 * any new bus bandwidth constraints:
 	 *   1. Before adding a configuration for a new device.
@@ -221,6 +232,7 @@
 #define	HCD_USB25	0x0030		/* Wireless USB 1.0 (USB 2.5)*/
 #define	HCD_USB3	0x0040		/* USB 3.0 */
 #define	HCD_MASK	0x0070
+#define	HCD_BH		0x0100		/* URB complete in BH context */
 
 	/* called to init HCD and root hub */
 	int	(*reset) (struct usb_hcd *hcd);
@@ -361,6 +373,11 @@
 	int	(*find_raw_port_number)(struct usb_hcd *, int);
 };
 
+static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
+{
+	return hcd->driver->flags & HCD_BH;
+}
+
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
 		int status);
@@ -411,7 +428,7 @@
 extern void usb_hcd_pci_remove(struct pci_dev *dev);
 extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
 #endif
 #endif /* CONFIG_PCI */
diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h
index a0ef405..8c38aa2 100644
--- a/include/linux/usb/of.h
+++ b/include/linux/usb/of.h
@@ -7,19 +7,27 @@
 #ifndef __LINUX_USB_OF_H
 #define __LINUX_USB_OF_H
 
+#include <linux/usb/ch9.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/phy.h>
 
 #if IS_ENABLED(CONFIG_OF)
 enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np);
+enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np);
 #else
 static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
 {
 	return USB_DR_MODE_UNKNOWN;
 }
+
+static inline enum usb_device_speed
+of_usb_get_maximum_speed(struct device_node *np)
+{
+	return USB_SPEED_UNKNOWN;
+}
 #endif
 
-#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_PHY)
+#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
 enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np);
 #else
 static inline enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np)
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 4403680..6c0b1c5 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -142,7 +142,7 @@
 /* helpers for direct access thru low-level io interface */
 static inline int usb_phy_io_read(struct usb_phy *x, u32 reg)
 {
-	if (x->io_ops && x->io_ops->read)
+	if (x && x->io_ops && x->io_ops->read)
 		return x->io_ops->read(x, reg);
 
 	return -EINVAL;
@@ -150,7 +150,7 @@
 
 static inline int usb_phy_io_write(struct usb_phy *x, u32 val, u32 reg)
 {
-	if (x->io_ops && x->io_ops->write)
+	if (x && x->io_ops && x->io_ops->write)
 		return x->io_ops->write(x, val, reg);
 
 	return -EINVAL;
@@ -159,7 +159,7 @@
 static inline int
 usb_phy_init(struct usb_phy *x)
 {
-	if (x->init)
+	if (x && x->init)
 		return x->init(x);
 
 	return 0;
@@ -168,14 +168,14 @@
 static inline void
 usb_phy_shutdown(struct usb_phy *x)
 {
-	if (x->shutdown)
+	if (x && x->shutdown)
 		x->shutdown(x);
 }
 
 static inline int
 usb_phy_vbus_on(struct usb_phy *x)
 {
-	if (!x->set_vbus)
+	if (!x || !x->set_vbus)
 		return 0;
 
 	return x->set_vbus(x, true);
@@ -184,7 +184,7 @@
 static inline int
 usb_phy_vbus_off(struct usb_phy *x)
 {
-	if (!x->set_vbus)
+	if (!x || !x->set_vbus)
 		return 0;
 
 	return x->set_vbus(x, false);
@@ -258,7 +258,7 @@
 static inline int
 usb_phy_set_suspend(struct usb_phy *x, int suspend)
 {
-	if (x->set_suspend != NULL)
+	if (x && x->set_suspend != NULL)
 		return x->set_suspend(x, suspend);
 	else
 		return 0;
@@ -267,7 +267,7 @@
 static inline int
 usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed)
 {
-	if (x->notify_connect)
+	if (x && x->notify_connect)
 		return x->notify_connect(x, speed);
 	else
 		return 0;
@@ -276,7 +276,7 @@
 static inline int
 usb_phy_notify_disconnect(struct usb_phy *x, enum usb_device_speed speed)
 {
-	if (x->notify_disconnect)
+	if (x && x->notify_disconnect)
 		return x->notify_disconnect(x, speed);
 	else
 		return 0;
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index d2ca919..1de16c3 100644
--- a/include/linux/usb/tegra_usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -18,19 +18,36 @@
 #include <linux/clk.h>
 #include <linux/usb/otg.h>
 
+/*
+ * utmi_pll_config_in_car_module: true if the UTMI PLL configuration registers
+ *     should be set up by clk-tegra, false if by the PHY code
+ * has_hostpc: true if the USB controller has the HOSTPC extension, which
+ *     changes the location of the PHCD and PTS fields
+ * requires_usbmode_setup: true if the USBMODE register needs to be set to
+ *      enter host mode
+ * requires_extra_tuning_parameters: true if xcvr_hsslew, hssquelch_level
+ *      and hsdiscon_level should be set for adequate signal quality
+ */
+
+struct tegra_phy_soc_config {
+	bool utmi_pll_config_in_car_module;
+	bool has_hostpc;
+	bool requires_usbmode_setup;
+	bool requires_extra_tuning_parameters;
+};
+
 struct tegra_utmip_config {
 	u8 hssync_start_delay;
 	u8 elastic_limit;
 	u8 idle_wait_delay;
 	u8 term_range_adj;
+	bool xcvr_setup_use_fuses;
 	u8 xcvr_setup;
 	u8 xcvr_lsfslew;
 	u8 xcvr_lsrslew;
-};
-
-struct tegra_ulpi_config {
-	int reset_gpio;
-	const char *clk;
+	u8 xcvr_hsslew;
+	u8 hssquelch_level;
+	u8 hsdiscon_level;
 };
 
 enum tegra_usb_phy_port_speed {
@@ -39,12 +56,6 @@
 	TEGRA_USB_PHY_PORT_SPEED_HIGH,
 };
 
-enum tegra_usb_phy_mode {
-	TEGRA_USB_PHY_MODE_DEVICE,
-	TEGRA_USB_PHY_MODE_HOST,
-	TEGRA_USB_PHY_MODE_OTG,
-};
-
 struct tegra_xtal_freq;
 
 struct tegra_usb_phy {
@@ -55,18 +66,17 @@
 	struct clk *clk;
 	struct clk *pll_u;
 	struct clk *pad_clk;
-	enum tegra_usb_phy_mode mode;
+	struct regulator *vbus;
+	enum usb_dr_mode mode;
 	void *config;
+	const struct tegra_phy_soc_config *soc_config;
 	struct usb_phy *ulpi;
 	struct usb_phy u_phy;
-	struct device *dev;
 	bool is_legacy_phy;
 	bool is_ulpi_phy;
 	int reset_gpio;
 };
 
-struct usb_phy *tegra_usb_get_phy(struct device_node *dn);
-
 void tegra_usb_phy_preresume(struct usb_phy *phy);
 
 void tegra_usb_phy_postresume(struct usb_phy *phy);
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/usb_phy_gen_xceiv.h
similarity index 81%
rename from include/linux/usb/nop-usb-xceiv.h
rename to include/linux/usb/usb_phy_gen_xceiv.h
index 148d351..f9a7e7b 100644
--- a/include/linux/usb/nop-usb-xceiv.h
+++ b/include/linux/usb/usb_phy_gen_xceiv.h
@@ -3,7 +3,7 @@
 
 #include <linux/usb/otg.h>
 
-struct nop_usb_xceiv_platform_data {
+struct usb_phy_gen_xceiv_platform_data {
 	enum usb_phy_type type;
 	unsigned long clk_rate;
 
@@ -12,7 +12,7 @@
 	unsigned int needs_reset:1;
 };
 
-#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_NOP_USB_XCEIV)
 /* sometimes transceivers are accessed only through e.g. ULPI */
 extern void usb_nop_xceiv_register(void);
 extern void usb_nop_xceiv_unregister(void);
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index f18d641..2b47e63 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -34,6 +34,7 @@
 	struct mutex		phy_mutex;
 	unsigned char		suspend_count;
 	unsigned char		pkt_cnt, pkt_err;
+	unsigned		can_dma_sg:1;
 
 	/* i/o info: pipes etc */
 	unsigned		in, out;
diff --git a/include/linux/usb/wusb-wa.h b/include/linux/usb/wusb-wa.h
index 6be985b..4ff744e 100644
--- a/include/linux/usb/wusb-wa.h
+++ b/include/linux/usb/wusb-wa.h
@@ -66,6 +66,7 @@
 	WA_ENABLE = 0x01,
 	WA_RESET = 0x02,
 	RPIPE_PAUSE = 0x1,
+	RPIPE_STALL = 0x2,
 };
 
 /* Responses from Get Status request ([WUSB] section 8.3.1.6) */
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
index 7dc17e2..3f3788d 100644
--- a/include/linux/vmpressure.h
+++ b/include/linux/vmpressure.h
@@ -34,10 +34,12 @@
 extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
 extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr);
 extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css);
-extern int vmpressure_register_event(struct cgroup *cg, struct cftype *cft,
+extern int vmpressure_register_event(struct cgroup_subsys_state *css,
+				     struct cftype *cft,
 				     struct eventfd_ctx *eventfd,
 				     const char *args);
-extern void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
+extern void vmpressure_unregister_event(struct cgroup_subsys_state *css,
+					struct cftype *cft,
 					struct eventfd_ctx *eventfd);
 #else
 static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
diff --git a/include/linux/vtime.h b/include/linux/vtime.h
index b1dd2db..f5b72b3 100644
--- a/include/linux/vtime.h
+++ b/include/linux/vtime.h
@@ -1,18 +1,68 @@
 #ifndef _LINUX_KERNEL_VTIME_H
 #define _LINUX_KERNEL_VTIME_H
 
+#include <linux/context_tracking_state.h>
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+#include <asm/vtime.h>
+#endif
+
+
 struct task_struct;
 
+/*
+ * vtime_accounting_enabled() definitions/declarations
+ */
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+static inline bool vtime_accounting_enabled(void) { return true; }
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+static inline bool vtime_accounting_enabled(void)
+{
+	if (static_key_false(&context_tracking_enabled)) {
+		if (context_tracking_active())
+			return true;
+	}
+
+	return false;
+}
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
+
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+static inline bool vtime_accounting_enabled(void) { return false; }
+#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
+
+
+/*
+ * Common vtime APIs
+ */
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+
+#ifdef __ARCH_HAS_VTIME_TASK_SWITCH
 extern void vtime_task_switch(struct task_struct *prev);
+#else
+extern void vtime_common_task_switch(struct task_struct *prev);
+static inline void vtime_task_switch(struct task_struct *prev)
+{
+	if (vtime_accounting_enabled())
+		vtime_common_task_switch(prev);
+}
+#endif /* __ARCH_HAS_VTIME_TASK_SWITCH */
+
 extern void vtime_account_system(struct task_struct *tsk);
 extern void vtime_account_idle(struct task_struct *tsk);
 extern void vtime_account_user(struct task_struct *tsk);
-extern void vtime_account_irq_enter(struct task_struct *tsk);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-static inline bool vtime_accounting_enabled(void) { return true; }
-#endif
+#ifdef __ARCH_HAS_VTIME_ACCOUNT
+extern void vtime_account_irq_enter(struct task_struct *tsk);
+#else
+extern void vtime_common_account_irq_enter(struct task_struct *tsk);
+static inline void vtime_account_irq_enter(struct task_struct *tsk)
+{
+	if (vtime_accounting_enabled())
+		vtime_common_account_irq_enter(tsk);
+}
+#endif /* __ARCH_HAS_VTIME_ACCOUNT */
 
 #else /* !CONFIG_VIRT_CPU_ACCOUNTING */
 
@@ -20,14 +70,20 @@
 static inline void vtime_account_system(struct task_struct *tsk) { }
 static inline void vtime_account_user(struct task_struct *tsk) { }
 static inline void vtime_account_irq_enter(struct task_struct *tsk) { }
-static inline bool vtime_accounting_enabled(void) { return false; }
-#endif
+#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 extern void arch_vtime_task_switch(struct task_struct *tsk);
-extern void vtime_account_irq_exit(struct task_struct *tsk);
-extern bool vtime_accounting_enabled(void);
+extern void vtime_gen_account_irq_exit(struct task_struct *tsk);
+
+static inline void vtime_account_irq_exit(struct task_struct *tsk)
+{
+	if (vtime_accounting_enabled())
+		vtime_gen_account_irq_exit(tsk);
+}
+
 extern void vtime_user_enter(struct task_struct *tsk);
+
 static inline void vtime_user_exit(struct task_struct *tsk)
 {
 	vtime_account_user(tsk);
@@ -35,7 +91,7 @@
 extern void vtime_guest_enter(struct task_struct *tsk);
 extern void vtime_guest_exit(struct task_struct *tsk);
 extern void vtime_init_idle(struct task_struct *tsk, int cpu);
-#else
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING_GEN  */
 static inline void vtime_account_irq_exit(struct task_struct *tsk)
 {
 	/* On hard|softirq exit we always account to hard|softirq cputime */
diff --git a/include/linux/wait.h b/include/linux/wait.h
index f487a47..a67fc16 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -811,6 +811,63 @@
 	__ret;								\
 })
 
+#define __wait_event_interruptible_lock_irq_timeout(wq, condition,	\
+						    lock, ret)		\
+do {									\
+	DEFINE_WAIT(__wait);						\
+									\
+	for (;;) {							\
+		prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);	\
+		if (condition)						\
+			break;						\
+		if (signal_pending(current)) {				\
+			ret = -ERESTARTSYS;				\
+			break;						\
+		}							\
+		spin_unlock_irq(&lock);					\
+		ret = schedule_timeout(ret);				\
+		spin_lock_irq(&lock);					\
+		if (!ret)						\
+			break;						\
+	}								\
+	finish_wait(&wq, &__wait);					\
+} while (0)
+
+/**
+ * wait_event_interruptible_lock_irq_timeout - sleep until a condition gets true or a timeout elapses.
+ *		The condition is checked under the lock. This is expected
+ *		to be called with the lock taken.
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ * @lock: a locked spinlock_t, which will be released before schedule()
+ *	  and reacquired afterwards.
+ * @timeout: timeout, in jiffies
+ *
+ * The process is put to sleep (TASK_INTERRUPTIBLE) until the
+ * @condition evaluates to true or signal is received. The @condition is
+ * checked each time the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ *
+ * This is supposed to be called while holding the lock. The lock is
+ * dropped before going to sleep and is reacquired afterwards.
+ *
+ * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it
+ * was interrupted by a signal, and the remaining jiffies otherwise
+ * if the condition evaluated to true before the timeout elapsed.
+ */
+#define wait_event_interruptible_lock_irq_timeout(wq, condition, lock,	\
+						  timeout)		\
+({									\
+	int __ret = timeout;						\
+									\
+	if (!(condition))						\
+		__wait_event_interruptible_lock_irq_timeout(		\
+					wq, condition, lock, __ret);	\
+	__ret;								\
+})
+
 
 /*
  * These are the old interfaces to sleep waiting for an event.
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index a0ed78a..594521b 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -295,7 +295,12 @@
  * Documentation/workqueue.txt.
  */
 enum {
-	WQ_NON_REENTRANT	= 1 << 0, /* guarantee non-reentrance */
+	/*
+	 * All wqs are now non-reentrant making the following flag
+	 * meaningless.  Will be removed.
+	 */
+	WQ_NON_REENTRANT	= 1 << 0, /* DEPRECATED */
+
 	WQ_UNBOUND		= 1 << 1, /* not bound to any cpu */
 	WQ_FREEZABLE		= 1 << 2, /* freeze during suspend */
 	WQ_MEM_RECLAIM		= 1 << 3, /* may be used for memory reclaim */
diff --git a/include/net/busy_poll.h b/include/net/busy_poll.h
index 8a358a2..829627d 100644
--- a/include/net/busy_poll.h
+++ b/include/net/busy_poll.h
@@ -123,6 +123,7 @@
 			/* local bh are disabled so it is ok to use _BH */
 			NET_ADD_STATS_BH(sock_net(sk),
 					 LINUX_MIB_BUSYPOLLRXPACKETS, rc);
+		cpu_relax();
 
 	} while (!nonblock && skb_queue_empty(&sk->sk_receive_queue) &&
 		 !need_resched() && !busy_loop_timeout(end_time));
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
index 0fee061..52adaa7 100644
--- a/include/net/cls_cgroup.h
+++ b/include/net/cls_cgroup.h
@@ -35,7 +35,7 @@
 		return 0;
 
 	rcu_read_lock();
-	classid = container_of(task_subsys_state(p, net_cls_subsys_id),
+	classid = container_of(task_css(p, net_cls_subsys_id),
 			       struct cgroup_cls_state, css)->classid;
 	rcu_read_unlock();
 
@@ -51,7 +51,7 @@
 		return 0;
 
 	rcu_read_lock();
-	css = task_subsys_state(p, net_cls_subsys_id);
+	css = task_css(p, net_cls_subsys_id);
 	if (css)
 		classid = container_of(css,
 				       struct cgroup_cls_state, css)->classid;
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 93024a4..8e0b6c8 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -61,6 +61,7 @@
 	struct list_head	ops_list;	/* private */
 	struct list_head	family_list;	/* private */
 	struct list_head	mcast_groups;	/* private */
+	struct module		*module;
 };
 
 /**
@@ -121,9 +122,24 @@
 	struct list_head	ops_list;
 };
 
-extern int genl_register_family(struct genl_family *family);
-extern int genl_register_family_with_ops(struct genl_family *family,
+extern int __genl_register_family(struct genl_family *family);
+
+static inline int genl_register_family(struct genl_family *family)
+{
+	family->module = THIS_MODULE;
+	return __genl_register_family(family);
+}
+
+extern int __genl_register_family_with_ops(struct genl_family *family,
 	struct genl_ops *ops, size_t n_ops);
+
+static inline int genl_register_family_with_ops(struct genl_family *family,
+	struct genl_ops *ops, size_t n_ops)
+{
+	family->module = THIS_MODULE;
+	return __genl_register_family_with_ops(family, ops, n_ops);
+}
+
 extern int genl_unregister_family(struct genl_family *family);
 extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
 extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 260f83f..f667248 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -135,6 +135,8 @@
 extern void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk,
 			       __be32 mtu);
 extern void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark);
+extern void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
+				   u32 mark);
 extern void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk);
 
 struct netlink_callback;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5b7a3da..551ba6a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1499,6 +1499,7 @@
 	IEEE80211_HW_SUPPORTS_RC_TABLE			= 1<<24,
 	IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF		= 1<<25,
 	IEEE80211_HW_TIMING_BEACON_ONLY			= 1<<26,
+	IEEE80211_HW_SUPPORTS_HT_CCK_RATES		= 1<<27,
 };
 
 /**
diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h
index 50ab8c2..a24f8bb 100644
--- a/include/net/netprio_cgroup.h
+++ b/include/net/netprio_cgroup.h
@@ -25,10 +25,6 @@
 	u32 priomap[];
 };
 
-struct cgroup_netprio_state {
-	struct cgroup_subsys_state css;
-};
-
 extern void sock_update_netprioidx(struct sock *sk);
 
 #if IS_BUILTIN(CONFIG_NETPRIO_CGROUP)
@@ -39,7 +35,7 @@
 	u32 idx;
 
 	rcu_read_lock();
-	css = task_subsys_state(p, net_prio_subsys_id);
+	css = task_css(p, net_prio_subsys_id);
 	idx = css->cgroup->id;
 	rcu_read_unlock();
 	return idx;
@@ -53,7 +49,7 @@
 	u32 idx = 0;
 
 	rcu_read_lock();
-	css = task_subsys_state(p, net_prio_subsys_id);
+	css = task_css(p, net_prio_subsys_id);
 	if (css)
 		idx = css->cgroup->id;
 	rcu_read_unlock();
diff --git a/include/net/route.h b/include/net/route.h
index 2ea40c1..afdeeb5 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -317,4 +317,12 @@
 	return hoplimit;
 }
 
+static inline int ip_skb_dst_mtu(struct sk_buff *skb)
+{
+	struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
+
+	return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
+	       skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+}
+
 #endif	/* _ROUTE_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 94ce082..e823786 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -341,10 +341,13 @@
 						  struct sk_buff *skb);
 	int			(*transport_finish)(struct sk_buff *skb,
 						    int async);
+	void			(*local_error)(struct sk_buff *skb, u32 mtu);
 };
 
 extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo);
 extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
+extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
+extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
 extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
 
@@ -1477,6 +1480,7 @@
 extern int xfrm_output_resume(struct sk_buff *skb, int err);
 extern int xfrm_output(struct sk_buff *skb);
 extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
+extern void xfrm_local_error(struct sk_buff *skb, int mtu);
 extern int xfrm4_extract_header(struct sk_buff *skb);
 extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
@@ -1497,6 +1501,7 @@
 extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
 extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler);
 extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler);
+extern void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
 extern int xfrm6_extract_header(struct sk_buff *skb);
 extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
 extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
@@ -1514,6 +1519,7 @@
 extern int xfrm6_output_finish(struct sk_buff *skb);
 extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
 				 u8 **prevhdr);
+extern void xfrm6_local_error(struct sk_buff *skb, u32 mtu);
 
 #ifdef CONFIG_XFRM
 extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 9d28ded..13d81c5 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -494,6 +494,38 @@
 	ISCSI_PARAM_BOOT_NIC,
 	ISCSI_PARAM_BOOT_TARGET,
 
+	ISCSI_PARAM_AUTO_SND_TGT_DISABLE,
+	ISCSI_PARAM_DISCOVERY_SESS,
+	ISCSI_PARAM_PORTAL_TYPE,
+	ISCSI_PARAM_CHAP_AUTH_EN,
+	ISCSI_PARAM_DISCOVERY_LOGOUT_EN,
+	ISCSI_PARAM_BIDI_CHAP_EN,
+	ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL,
+
+	ISCSI_PARAM_DEF_TIME2WAIT,
+	ISCSI_PARAM_DEF_TIME2RETAIN,
+	ISCSI_PARAM_MAX_SEGMENT_SIZE,
+	ISCSI_PARAM_STATSN,
+	ISCSI_PARAM_KEEPALIVE_TMO,
+	ISCSI_PARAM_LOCAL_PORT,
+	ISCSI_PARAM_TSID,
+	ISCSI_PARAM_DEF_TASKMGMT_TMO,
+
+	ISCSI_PARAM_TCP_TIMESTAMP_STAT,
+	ISCSI_PARAM_TCP_WSF_DISABLE,
+	ISCSI_PARAM_TCP_NAGLE_DISABLE,
+	ISCSI_PARAM_TCP_TIMER_SCALE,
+	ISCSI_PARAM_TCP_TIMESTAMP_EN,
+	ISCSI_PARAM_TCP_XMIT_WSF,
+	ISCSI_PARAM_TCP_RECV_WSF,
+	ISCSI_PARAM_IP_FRAGMENT_DISABLE,
+	ISCSI_PARAM_IPV4_TOS,
+	ISCSI_PARAM_IPV6_TC,
+	ISCSI_PARAM_IPV6_FLOW_LABEL,
+	ISCSI_PARAM_IS_FW_ASSIGNED_IPV6,
+
+	ISCSI_PARAM_DISCOVERY_PARENT_IDX,
+	ISCSI_PARAM_DISCOVERY_PARENT_TYPE,
 	/* must always be last */
 	ISCSI_PARAM_MAX,
 };
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 4265a4b..6ac9e17a 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -62,6 +62,8 @@
 	TMF_NOT_FOUND,
 };
 
+#define ISID_SIZE			6
+
 /* Connection suspend "bit" */
 #define ISCSI_SUSPEND_BIT		1
 
@@ -173,6 +175,7 @@
 
 	/* iSCSI connection-wide sequencing */
 	uint32_t		exp_statsn;
+	uint32_t		statsn;
 
 	/* control data */
 	int			id;		/* CID */
@@ -213,6 +216,22 @@
 	int			persistent_port;
 	char			*persistent_address;
 
+	unsigned		max_segment_size;
+	unsigned		tcp_xmit_wsf;
+	unsigned		tcp_recv_wsf;
+	uint16_t		keepalive_tmo;
+	uint16_t		local_port;
+	uint8_t			tcp_timestamp_stat;
+	uint8_t			tcp_nagle_disable;
+	uint8_t			tcp_wsf_disable;
+	uint8_t			tcp_timer_scale;
+	uint8_t			tcp_timestamp_en;
+	uint8_t			fragment_disable;
+	uint8_t			ipv4_tos;
+	uint8_t			ipv6_traffic_class;
+	uint8_t			ipv6_flow_label;
+	uint8_t			is_fw_assigned_ipv6;
+
 	/* MIB-statistics */
 	uint64_t		txdata_octets;
 	uint64_t		rxdata_octets;
@@ -290,6 +309,18 @@
 	char			*boot_root;
 	char			*boot_nic;
 	char			*boot_target;
+	char			*portal_type;
+	char			*discovery_parent_type;
+	uint16_t		discovery_parent_idx;
+	uint16_t		def_taskmgmt_tmo;
+	uint16_t		tsid;
+	uint8_t			auto_snd_tgt_disable;
+	uint8_t			discovery_sess;
+	uint8_t			chap_auth_en;
+	uint8_t			discovery_logout_en;
+	uint8_t			bidi_chap_en;
+	uint8_t			discovery_auth_optional;
+	uint8_t			isid[ISID_SIZE];
 
 	/* control data */
 	struct iscsi_transport	*tt;
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 4b87d99..d477bfb 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -457,6 +457,8 @@
 				 * other paths */
 #define DID_NEXUS_FAILURE 0x11  /* Permanent nexus failure, retry on other
 				 * paths might yield different results */
+#define DID_ALLOC_FAILURE 0x12  /* Space allocation on the device failed */
+#define DID_MEDIUM_ERROR  0x13  /* Medium error */
 #define DRIVER_OK       0x00	/* Driver status                           */
 
 /*
@@ -486,7 +488,6 @@
 #define TIMEOUT_ERROR   0x2007
 #define SCSI_RETURN_NOT_HANDLED   0x2008
 #define FAST_IO_FAIL	0x2009
-#define TARGET_ERROR    0x200A
 
 /*
  * Midlevel queue return values.
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index a44954c..d65fbec 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -52,8 +52,15 @@
 
 enum scsi_device_event {
 	SDEV_EVT_MEDIA_CHANGE	= 1,	/* media has changed */
+	SDEV_EVT_INQUIRY_CHANGE_REPORTED,		/* 3F 03  UA reported */
+	SDEV_EVT_CAPACITY_CHANGE_REPORTED,		/* 2A 09  UA reported */
+	SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED,	/* 38 07  UA reported */
+	SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED,	/* 2A 01  UA reported */
+	SDEV_EVT_LUN_CHANGE_REPORTED,			/* 3F 0E  UA reported */
 
-	SDEV_EVT_LAST		= SDEV_EVT_MEDIA_CHANGE,
+	SDEV_EVT_FIRST		= SDEV_EVT_MEDIA_CHANGE,
+	SDEV_EVT_LAST		= SDEV_EVT_LUN_CHANGE_REPORTED,
+
 	SDEV_EVT_MAXBITS	= SDEV_EVT_LAST + 1
 };
 
@@ -164,6 +171,7 @@
 	atomic_t disk_events_disable_depth; /* disable depth for disk events */
 
 	DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
+	DECLARE_BITMAP(pending_events, SDEV_EVT_MAXBITS); /* pending events */
 	struct list_head event_list;	/* asserted events */
 	struct work_struct event_work;
 
@@ -261,6 +269,9 @@
 						 * means no lun present. */
 	unsigned int		no_report_luns:1;	/* Don't use
 						 * REPORT LUNS for scanning. */
+	unsigned int		expecting_lun_change:1;	/* A device has reported
+						 * a 3F/0E UA, other devices on
+						 * the same target will also. */
 	/* commands actually active on LLD. protected by host lock. */
 	unsigned int		target_busy;
 	/*
diff --git a/include/sound/core.h b/include/sound/core.h
index c586617..2a14f1f 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -27,6 +27,7 @@
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/pm.h>			/* pm_message_t */
 #include <linux/stringify.h>
+#include <linux/printk.h>
 
 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -376,6 +377,11 @@
 #define snd_BUG()		WARN(1, "BUG?\n")
 
 /**
+ * Suppress high rates of output when CONFIG_SND_DEBUG is enabled.
+ */
+#define snd_printd_ratelimit() printk_ratelimit()
+
+/**
  * snd_BUG_ON - debugging check macro
  * @cond: condition to evaluate
  *
@@ -398,6 +404,8 @@
 	unlikely(__ret_warn_on); \
 })
 
+static inline bool snd_printd_ratelimit(void) { return false; }
+
 #endif /* CONFIG_SND_DEBUG */
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h
index 2fd3d25..56e818e 100644
--- a/include/sound/pxa2xx-lib.h
+++ b/include/sound/pxa2xx-lib.h
@@ -6,13 +6,6 @@
 
 /* PCM */
 
-struct pxa2xx_pcm_dma_params {
-	char *name;			/* stream identifier */
-	u32 dcmd;			/* DMA descriptor dcmd field */
-	volatile u32 *drcmr;		/* the DMA request channel to use */
-	u32 dev_addr;			/* device physical address for DMA */
-};
-
 extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params);
 extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
new file mode 100644
index 0000000..d35412a
--- /dev/null
+++ b/include/sound/rcar_snd.h
@@ -0,0 +1,84 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RCAR_SND_H
+#define RCAR_SND_H
+
+#include <linux/sh_clk.h>
+
+#define RSND_GEN1_SRU	0
+#define RSND_GEN1_ADG	1
+#define RSND_GEN1_SSI	2
+
+#define RSND_GEN2_SRU	0
+#define RSND_GEN2_ADG	1
+#define RSND_GEN2_SSIU	2
+#define RSND_GEN2_SSI	3
+
+#define RSND_BASE_MAX	4
+
+/*
+ * flags
+ *
+ * 0xAB000000
+ *
+ * A : clock sharing settings
+ * B : SSI direction
+ */
+#define RSND_SSI_CLK_PIN_SHARE		(1 << 31)
+#define RSND_SSI_CLK_FROM_ADG		(1 << 30) /* clock parent is master */
+#define RSND_SSI_SYNC			(1 << 29) /* SSI34_sync etc */
+#define RSND_SSI_DEPENDENT		(1 << 28) /* SSI needs SRU/SCU */
+
+#define RSND_SSI_PLAY			(1 << 24)
+
+#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags)	\
+{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
+#define RSND_SSI_UNUSED \
+{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
+
+struct rsnd_ssi_platform_info {
+	int dai_id;
+	int dma_id;
+	int pio_irq;
+	u32 flags;
+};
+
+/*
+ * flags
+ */
+#define RSND_SCU_USB_HPBIF		(1 << 31) /* it needs RSND_SSI_DEPENDENT */
+
+struct rsnd_scu_platform_info {
+	u32 flags;
+};
+
+/*
+ * flags
+ *
+ * 0x0000000A
+ *
+ * A : generation
+ */
+#define RSND_GEN1	(1 << 0) /* fixme */
+#define RSND_GEN2	(2 << 0) /* fixme */
+
+struct rcar_snd_info {
+	u32 flags;
+	struct rsnd_ssi_platform_info *ssi_info;
+	int ssi_info_nr;
+	struct rsnd_scu_platform_info *scu_info;
+	int scu_info_nr;
+	int (*start)(int id);
+	int (*stop)(int id);
+};
+
+#endif
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 3e479f4..27a72d5 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -70,121 +70,144 @@
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
+#define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
+	.reg = wreg, .mask = 1, .shift = wshift, \
+	.on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
+
 /* path domain */
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
-{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{	.id = snd_soc_dapm_pga, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
-{	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{	.id = snd_soc_dapm_out_drv, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
-{	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{	.id = snd_soc_dapm_mixer, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-	.num_kcontrols = wncontrols}
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
+{	.id = snd_soc_dapm_micbias, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{	.id = snd_soc_dapm_switch, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{	.id = snd_soc_dapm_virt_mux, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{	.id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-	.num_kcontrols = 1}
+{	.id = snd_soc_dapm_value_mux, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 	 wcontrols) \
-{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{	.id = snd_soc_dapm_pga, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
-{	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{	.id = snd_soc_dapm_mixer, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-	.num_kcontrols = ARRAY_SIZE(wcontrols)}
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
-{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{	.id = snd_soc_dapm_pga, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
-{	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{	.id = snd_soc_dapm_out_drv, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
-{	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{	.id = snd_soc_dapm_mixer, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
 	wcontrols, wncontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, \
+{       .id = snd_soc_dapm_mixer, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{	.id = snd_soc_dapm_switch, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{	.id = snd_soc_dapm_mux, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{	.id = snd_soc_dapm_virt_mux, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .event = wevent, .event_flags = wflags, \
+{	.id = snd_soc_dapm_pga, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.event = wevent, .event_flags = wflags, \
 	.subseq = wsubseq}
 #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
 	wflags)	\
-{	.id = snd_soc_dapm_supply, .name = wname, .reg = wreg,	\
-	.shift = wshift, .invert = winvert, .event = wevent, \
-	.event_flags = wflags, .subseq = wsubseq}
+{	.id = snd_soc_dapm_supply, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.event = wevent, .event_flags = wflags, .subseq = wsubseq}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+{	.id = snd_soc_dapm_pga, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
-{	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+{	.id = snd_soc_dapm_mixer, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
 	wcontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrol_news = wcontrols, \
-	.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
+{       .id = snd_soc_dapm_mixer, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+	.event = wevent, .event_flags = wflags}
 
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
@@ -199,35 +222,36 @@
 /* stream domain */
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
-	.reg = wreg, .shift = wshift, .invert = winvert }
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
 			      wevent, wflags)				\
 {	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
-	.reg = wreg, .shift = wshift, .invert = winvert, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
-	.reg = wreg, .shift = wshift, .invert = winvert }
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
 			     wevent, wflags)				\
 {	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
-	.reg = wreg, .shift = wshift, .invert = winvert, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
-	.shift = wshift, .invert = winvert}
+{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
 #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
 			   wevent, wflags)				\
-{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, \
+{	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags}
+
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
-{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
-	.shift = wshift, .invert = winvert}
+{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
 			   wevent, wflags)				\
-{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, \
+{	.id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
 {	.id = snd_soc_dapm_clock_supply, .name = wname, \
@@ -241,14 +265,14 @@
 	.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
-{	.id = snd_soc_dapm_supply, .name = wname, .reg = wreg,	\
-	.shift = wshift, .invert = winvert, .event = wevent, \
-	.event_flags = wflags}
+{	.id = snd_soc_dapm_supply, .name = wname, \
+	SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)	    \
 {	.id = snd_soc_dapm_regulator_supply, .name = wname, \
 	.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
-	.invert = wflags}
+	.on_val = wflags}
 
 
 /* dapm kcontrol types */
@@ -256,14 +280,26 @@
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, \
 	.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+#define SOC_DAPM_SINGLE_AUTODISABLE(xname, reg, shift, max, invert) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
 #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 	.tlv.p = (tlv_array), \
 	.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+#define SOC_DAPM_SINGLE_TLV_AUTODISABLE(xname, reg, shift, max, invert, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+	.info = snd_soc_info_volsw, \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.tlv.p = (tlv_array), \
+	.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 #define SOC_DAPM_ENUM(xname, xenum) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_enum_double, \
@@ -333,6 +369,7 @@
 struct snd_soc_dapm_context;
 struct regulator;
 struct snd_soc_dapm_widget_list;
+struct snd_soc_dapm_update;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event);
@@ -376,7 +413,7 @@
 			 struct snd_soc_dapm_widget *sink);
 
 /* dapm path setup */
-int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
+int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 			    const struct snd_soc_dapm_route *route, int num);
@@ -391,10 +428,12 @@
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-		struct snd_kcontrol *kcontrol, int connect);
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e);
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
+		struct snd_kcontrol *kcontrol, int connect,
+		struct snd_soc_dapm_update *update);
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
+		struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
+		struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
@@ -424,6 +463,8 @@
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 	struct snd_soc_dapm_widget_list **list);
 
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
 	snd_soc_dapm_input = 0,		/* input pin */
@@ -455,6 +496,7 @@
 	snd_soc_dapm_dai_in,		/* link to DAI structure */
 	snd_soc_dapm_dai_out,
 	snd_soc_dapm_dai_link,		/* link between two DAI structures */
+	snd_soc_dapm_kcontrol,		/* Auto-disabled kcontrol */
 };
 
 enum snd_soc_dapm_subclass {
@@ -485,7 +527,6 @@
 	/* source (input) and sink (output) widgets */
 	struct snd_soc_dapm_widget *source;
 	struct snd_soc_dapm_widget *sink;
-	struct snd_kcontrol *kcontrol;
 
 	/* status */
 	u32 connect:1;	/* source and sink widgets are connected */
@@ -498,6 +539,7 @@
 
 	struct list_head list_source;
 	struct list_head list_sink;
+	struct list_head list_kcontrol;
 	struct list_head list;
 };
 
@@ -518,12 +560,10 @@
 	/* dapm control */
 	int reg;				/* negative reg = no direct dapm */
 	unsigned char shift;			/* bits to shift */
-	unsigned int value;				/* widget current value */
 	unsigned int mask;			/* non-shifted mask */
 	unsigned int on_val;			/* on state value */
 	unsigned int off_val;			/* off state value */
 	unsigned char power:1;			/* block power status */
-	unsigned char invert:1;			/* invert the power bit */
 	unsigned char active:1;			/* active stream on DAC, ADC's */
 	unsigned char connected:1;		/* connected codec pin */
 	unsigned char new:1;			/* cnew complete */
@@ -559,7 +599,6 @@
 };
 
 struct snd_soc_dapm_update {
-	struct snd_soc_dapm_widget *widget;
 	struct snd_kcontrol *kcontrol;
 	int reg;
 	int mask;
@@ -573,8 +612,6 @@
 	struct delayed_work delayed_work;
 	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
 
-	struct snd_soc_dapm_update *update;
-
 	void (*seq_notifier)(struct snd_soc_dapm_context *,
 			     enum snd_soc_dapm_type, int);
 
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
index 04598f1..047d657 100644
--- a/include/sound/soc-dpcm.h
+++ b/include/sound/soc-dpcm.h
@@ -133,6 +133,6 @@
 /* internal use only */
 int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
 int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
-int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
+int soc_dpcm_runtime_update(struct snd_soc_card *);
 
 #endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 6eabee7..d22cb0a 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -30,13 +30,13 @@
 /*
  * Convenience kcontrol builders
  */
-#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \
+#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \
 	((unsigned long)&(struct soc_mixer_control) \
 	{.reg = xreg, .rreg = xreg, .shift = shift_left, \
 	.rshift = shift_right, .max = xmax, .platform_max = xmax, \
-	.invert = xinvert})
-#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
-	SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert)
+	.invert = xinvert, .autodisable = xautodisable})
+#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
+	SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
 #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
 	((unsigned long)&(struct soc_mixer_control) \
 	{.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
@@ -52,7 +52,7 @@
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.put = snd_soc_put_volsw, \
-	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
@@ -68,7 +68,7 @@
 	.tlv.p = (tlv_array), \
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
 	.put = snd_soc_put_volsw, \
-	.private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+	.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
 {       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -97,7 +97,7 @@
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
 	.put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
-					  max, invert) }
+					  max, invert, 0) }
 #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 	.info = snd_soc_info_volsw, \
@@ -119,7 +119,7 @@
 	.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
 	.put = snd_soc_put_volsw, \
 	.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
-					  max, invert) }
+					  max, invert, 0) }
 #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -190,14 +190,14 @@
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
-	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
 #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\
 	 xhandler_get, xhandler_put) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = \
-		SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) }
+		SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@@ -206,7 +206,7 @@
 	.tlv.p = (tlv_array), \
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
-	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+	.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
 #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -216,7 +216,7 @@
 	.info = snd_soc_info_volsw, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \
-					  xmax, xinvert) }
+					  xmax, xinvert, 0) }
 #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
 	 xhandler_get, xhandler_put, tlv_array) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
@@ -234,7 +234,7 @@
 	.private_value = xdata }
 #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-	.info = snd_soc_info_enum_ext, \
+	.info = snd_soc_info_enum_double, \
 	.get = xhandler_get, .put = xhandler_put, \
 	.private_value = (unsigned long)&xenum }
 
@@ -468,6 +468,8 @@
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
 int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
+int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+		struct platform_device *pdev);
 
 /*
  *Controls
@@ -475,6 +477,8 @@
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
 				  void *data, const char *long_name,
 				  const char *prefix);
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+					       const char *name);
 int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
 	const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
@@ -485,8 +489,6 @@
 	const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
-int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
@@ -497,8 +499,6 @@
 	struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_info *uinfo);
-int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo);
 #define snd_soc_info_bool_ext		snd_ctl_boolean_mono_info
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol);
@@ -697,7 +697,6 @@
 	unsigned int probed:1; /* Codec has been probed */
 	unsigned int ac97_registered:1; /* Codec has been AC97 registered */
 	unsigned int ac97_created:1; /* Codec has been created by SoC */
-	unsigned int sysfs_registered:1; /* codec has been sysfs registered */
 	unsigned int cache_init:1; /* codec cache has been initialized */
 	unsigned int using_regmap:1; /* using regmap access */
 	u32 cache_only;  /* Suppress writes to hardware */
@@ -705,7 +704,6 @@
 
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
-	enum snd_soc_control_type control_type;
 	hw_write_t hw_write;
 	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
@@ -724,7 +722,6 @@
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_codec_root;
 	struct dentry *debugfs_reg;
-	struct dentry *debugfs_dapm;
 #endif
 };
 
@@ -849,7 +846,6 @@
 
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_platform_root;
-	struct dentry *debugfs_dapm;
 #endif
 };
 
@@ -934,6 +930,10 @@
 	/* machine stream operations */
 	const struct snd_soc_ops *ops;
 	const struct snd_soc_compr_ops *compr_ops;
+
+	/* For unidirectional dai links */
+	bool playback_only;
+	bool capture_only;
 };
 
 struct snd_soc_codec_conf {
@@ -1042,6 +1042,7 @@
 	/* Generic DAPM context for the card */
 	struct snd_soc_dapm_context dapm;
 	struct snd_soc_dapm_stats dapm_stats;
+	struct snd_soc_dapm_update *update;
 
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_card_root;
@@ -1087,7 +1088,9 @@
 /* mixer control */
 struct soc_mixer_control {
 	int min, max, platform_max;
-	unsigned int reg, rreg, shift, rshift, invert;
+	unsigned int reg, rreg, shift, rshift;
+	unsigned int invert:1;
+	unsigned int autodisable:1;
 };
 
 struct soc_bytes {
diff --git a/include/trace/events/context_tracking.h b/include/trace/events/context_tracking.h
new file mode 100644
index 0000000..ce8007c
--- /dev/null
+++ b/include/trace/events/context_tracking.h
@@ -0,0 +1,58 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM context_tracking
+
+#if !defined(_TRACE_CONTEXT_TRACKING_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_CONTEXT_TRACKING_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(context_tracking_user,
+
+	TP_PROTO(int dummy),
+
+	TP_ARGS(dummy),
+
+	TP_STRUCT__entry(
+		__field( int,	dummy	)
+	),
+
+	TP_fast_assign(
+		__entry->dummy		= dummy;
+	),
+
+	TP_printk("%s", "")
+);
+
+/**
+ * user_enter - called when the kernel resumes to userspace
+ * @dummy:	dummy arg to make trace event macro happy
+ *
+ * This event occurs when the kernel resumes to userspace  after
+ * an exception or a syscall.
+ */
+DEFINE_EVENT(context_tracking_user, user_enter,
+
+	TP_PROTO(int dummy),
+
+	TP_ARGS(dummy)
+);
+
+/**
+ * user_exit - called when userspace enters the kernel
+ * @dummy:	dummy arg to make trace event macro happy
+ *
+ * This event occurs when userspace enters the kernel through
+ * an exception or a syscall.
+ */
+DEFINE_EVENT(context_tracking_user, user_exit,
+
+	TP_PROTO(int dummy),
+
+	TP_ARGS(dummy)
+);
+
+
+#endif /*  _TRACE_CONTEXT_TRACKING_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 2068db2..197d312 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -14,7 +14,6 @@
 struct ext4_inode_info;
 struct mpage_da_data;
 struct ext4_map_blocks;
-struct ext4_extent;
 struct extent_status;
 
 #define EXT4_I(inode) (container_of(inode, struct ext4_inode_info, vfs_inode))
@@ -64,10 +63,10 @@
 	{ EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER,	"LAST_CLUSTER" })
 
 #define show_extent_status(status) __print_flags(status, "",	\
-	{ (1 << 3),	"W" }, 					\
-	{ (1 << 2),	"U" },					\
-	{ (1 << 1),	"D" },					\
-	{ (1 << 0),	"H" })
+	{ EXTENT_STATUS_WRITTEN,	"W" },			\
+	{ EXTENT_STATUS_UNWRITTEN,	"U" },			\
+	{ EXTENT_STATUS_DELAYED,	"D" },			\
+	{ EXTENT_STATUS_HOLE,		"H" })
 
 
 TRACE_EVENT(ext4_free_inode,
@@ -2192,7 +2191,7 @@
 		  (unsigned short) __entry->eh_entries)
 );
 
-TRACE_EVENT(ext4_es_insert_extent,
+DECLARE_EVENT_CLASS(ext4__es_extent,
 	TP_PROTO(struct inode *inode, struct extent_status *es),
 
 	TP_ARGS(inode, es),
@@ -2212,7 +2211,7 @@
 		__entry->lblk	= es->es_lblk;
 		__entry->len	= es->es_len;
 		__entry->pblk	= ext4_es_pblock(es);
-		__entry->status	= ext4_es_status(es) >> 60;
+		__entry->status	= ext4_es_status(es);
 	),
 
 	TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s",
@@ -2222,6 +2221,18 @@
 		  __entry->pblk, show_extent_status(__entry->status))
 );
 
+DEFINE_EVENT(ext4__es_extent, ext4_es_insert_extent,
+	TP_PROTO(struct inode *inode, struct extent_status *es),
+
+	TP_ARGS(inode, es)
+);
+
+DEFINE_EVENT(ext4__es_extent, ext4_es_cache_extent,
+	TP_PROTO(struct inode *inode, struct extent_status *es),
+
+	TP_ARGS(inode, es)
+);
+
 TRACE_EVENT(ext4_es_remove_extent,
 	TP_PROTO(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len),
 
@@ -2289,7 +2300,7 @@
 		__entry->lblk	= es->es_lblk;
 		__entry->len	= es->es_len;
 		__entry->pblk	= ext4_es_pblock(es);
-		__entry->status	= ext4_es_status(es) >> 60;
+		__entry->status	= ext4_es_status(es);
 	),
 
 	TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s",
@@ -2343,7 +2354,7 @@
 		__entry->lblk	= es->es_lblk;
 		__entry->len	= es->es_len;
 		__entry->pblk	= ext4_es_pblock(es);
-		__entry->status	= ext4_es_status(es) >> 60;
+		__entry->status	= ext4_es_status(es);
 		__entry->found	= found;
 	),
 
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index 8e42410..cda100d 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -66,6 +66,43 @@
 	TP_printk("state=%lu", (unsigned long)__entry->state)
 );
 
+TRACE_EVENT(device_pm_report_time,
+
+	TP_PROTO(struct device *dev, const char *pm_ops, s64 ops_time,
+		 char *pm_event_str, int error),
+
+	TP_ARGS(dev, pm_ops, ops_time, pm_event_str, error),
+
+	TP_STRUCT__entry(
+		__string(device, dev_name(dev))
+		__string(driver, dev_driver_string(dev))
+		__string(parent, dev->parent ? dev_name(dev->parent) : "none")
+		__string(pm_ops, pm_ops ? pm_ops : "none ")
+		__string(pm_event_str, pm_event_str)
+		__field(s64, ops_time)
+		__field(int, error)
+	),
+
+	TP_fast_assign(
+		const char *tmp = dev->parent ? dev_name(dev->parent) : "none";
+		const char *tmp_i = pm_ops ? pm_ops : "none ";
+
+		__assign_str(device, dev_name(dev));
+		__assign_str(driver, dev_driver_string(dev));
+		__assign_str(parent, tmp);
+		__assign_str(pm_ops, tmp_i);
+		__assign_str(pm_event_str, pm_event_str);
+		__entry->ops_time = ops_time;
+		__entry->error = error;
+	),
+
+	/* ops_str has an extra space at the end */
+	TP_printk("%s %s parent=%s state=%s ops=%snsecs=%lld err=%d",
+		__get_str(driver), __get_str(device), __get_str(parent),
+		__get_str(pm_event_str), __get_str(pm_ops),
+		__entry->ops_time, __entry->error)
+);
+
 DECLARE_EVENT_CLASS(wakeup_source,
 
 	TP_PROTO(const char *name, unsigned int state),
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index 59ebcc8..ee2376c 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -19,12 +19,12 @@
  */
 TRACE_EVENT(rcu_utilization,
 
-	TP_PROTO(char *s),
+	TP_PROTO(const char *s),
 
 	TP_ARGS(s),
 
 	TP_STRUCT__entry(
-		__field(char *, s)
+		__field(const char *, s)
 	),
 
 	TP_fast_assign(
@@ -51,14 +51,14 @@
  */
 TRACE_EVENT(rcu_grace_period,
 
-	TP_PROTO(char *rcuname, unsigned long gpnum, char *gpevent),
+	TP_PROTO(const char *rcuname, unsigned long gpnum, const char *gpevent),
 
 	TP_ARGS(rcuname, gpnum, gpevent),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
-		__field(char *, gpevent)
+		__field(const char *, gpevent)
 	),
 
 	TP_fast_assign(
@@ -89,21 +89,21 @@
  */
 TRACE_EVENT(rcu_future_grace_period,
 
-	TP_PROTO(char *rcuname, unsigned long gpnum, unsigned long completed,
+	TP_PROTO(const char *rcuname, unsigned long gpnum, unsigned long completed,
 		 unsigned long c, u8 level, int grplo, int grphi,
-		 char *gpevent),
+		 const char *gpevent),
 
 	TP_ARGS(rcuname, gpnum, completed, c, level, grplo, grphi, gpevent),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
 		__field(unsigned long, completed)
 		__field(unsigned long, c)
 		__field(u8, level)
 		__field(int, grplo)
 		__field(int, grphi)
-		__field(char *, gpevent)
+		__field(const char *, gpevent)
 	),
 
 	TP_fast_assign(
@@ -132,13 +132,13 @@
  */
 TRACE_EVENT(rcu_grace_period_init,
 
-	TP_PROTO(char *rcuname, unsigned long gpnum, u8 level,
+	TP_PROTO(const char *rcuname, unsigned long gpnum, u8 level,
 		 int grplo, int grphi, unsigned long qsmask),
 
 	TP_ARGS(rcuname, gpnum, level, grplo, grphi, qsmask),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
 		__field(u8, level)
 		__field(int, grplo)
@@ -168,12 +168,12 @@
  */
 TRACE_EVENT(rcu_preempt_task,
 
-	TP_PROTO(char *rcuname, int pid, unsigned long gpnum),
+	TP_PROTO(const char *rcuname, int pid, unsigned long gpnum),
 
 	TP_ARGS(rcuname, pid, gpnum),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
 		__field(int, pid)
 	),
@@ -195,12 +195,12 @@
  */
 TRACE_EVENT(rcu_unlock_preempted_task,
 
-	TP_PROTO(char *rcuname, unsigned long gpnum, int pid),
+	TP_PROTO(const char *rcuname, unsigned long gpnum, int pid),
 
 	TP_ARGS(rcuname, gpnum, pid),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
 		__field(int, pid)
 	),
@@ -224,14 +224,14 @@
  */
 TRACE_EVENT(rcu_quiescent_state_report,
 
-	TP_PROTO(char *rcuname, unsigned long gpnum,
+	TP_PROTO(const char *rcuname, unsigned long gpnum,
 		 unsigned long mask, unsigned long qsmask,
 		 u8 level, int grplo, int grphi, int gp_tasks),
 
 	TP_ARGS(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
 		__field(unsigned long, mask)
 		__field(unsigned long, qsmask)
@@ -268,15 +268,15 @@
  */
 TRACE_EVENT(rcu_fqs,
 
-	TP_PROTO(char *rcuname, unsigned long gpnum, int cpu, char *qsevent),
+	TP_PROTO(const char *rcuname, unsigned long gpnum, int cpu, const char *qsevent),
 
 	TP_ARGS(rcuname, gpnum, cpu, qsevent),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(unsigned long, gpnum)
 		__field(int, cpu)
-		__field(char *, qsevent)
+		__field(const char *, qsevent)
 	),
 
 	TP_fast_assign(
@@ -308,12 +308,12 @@
  */
 TRACE_EVENT(rcu_dyntick,
 
-	TP_PROTO(char *polarity, long long oldnesting, long long newnesting),
+	TP_PROTO(const char *polarity, long long oldnesting, long long newnesting),
 
 	TP_ARGS(polarity, oldnesting, newnesting),
 
 	TP_STRUCT__entry(
-		__field(char *, polarity)
+		__field(const char *, polarity)
 		__field(long long, oldnesting)
 		__field(long long, newnesting)
 	),
@@ -352,12 +352,12 @@
  */
 TRACE_EVENT(rcu_prep_idle,
 
-	TP_PROTO(char *reason),
+	TP_PROTO(const char *reason),
 
 	TP_ARGS(reason),
 
 	TP_STRUCT__entry(
-		__field(char *, reason)
+		__field(const char *, reason)
 	),
 
 	TP_fast_assign(
@@ -376,13 +376,13 @@
  */
 TRACE_EVENT(rcu_callback,
 
-	TP_PROTO(char *rcuname, struct rcu_head *rhp, long qlen_lazy,
+	TP_PROTO(const char *rcuname, struct rcu_head *rhp, long qlen_lazy,
 		 long qlen),
 
 	TP_ARGS(rcuname, rhp, qlen_lazy, qlen),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(void *, rhp)
 		__field(void *, func)
 		__field(long, qlen_lazy)
@@ -412,13 +412,13 @@
  */
 TRACE_EVENT(rcu_kfree_callback,
 
-	TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset,
+	TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset,
 		 long qlen_lazy, long qlen),
 
 	TP_ARGS(rcuname, rhp, offset, qlen_lazy, qlen),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(void *, rhp)
 		__field(unsigned long, offset)
 		__field(long, qlen_lazy)
@@ -447,12 +447,12 @@
  */
 TRACE_EVENT(rcu_batch_start,
 
-	TP_PROTO(char *rcuname, long qlen_lazy, long qlen, long blimit),
+	TP_PROTO(const char *rcuname, long qlen_lazy, long qlen, long blimit),
 
 	TP_ARGS(rcuname, qlen_lazy, qlen, blimit),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(long, qlen_lazy)
 		__field(long, qlen)
 		__field(long, blimit)
@@ -477,12 +477,12 @@
  */
 TRACE_EVENT(rcu_invoke_callback,
 
-	TP_PROTO(char *rcuname, struct rcu_head *rhp),
+	TP_PROTO(const char *rcuname, struct rcu_head *rhp),
 
 	TP_ARGS(rcuname, rhp),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(void *, rhp)
 		__field(void *, func)
 	),
@@ -506,12 +506,12 @@
  */
 TRACE_EVENT(rcu_invoke_kfree_callback,
 
-	TP_PROTO(char *rcuname, struct rcu_head *rhp, unsigned long offset),
+	TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset),
 
 	TP_ARGS(rcuname, rhp, offset),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(void *, rhp)
 		__field(unsigned long, offset)
 	),
@@ -539,13 +539,13 @@
  */
 TRACE_EVENT(rcu_batch_end,
 
-	TP_PROTO(char *rcuname, int callbacks_invoked,
+	TP_PROTO(const char *rcuname, int callbacks_invoked,
 		 bool cb, bool nr, bool iit, bool risk),
 
 	TP_ARGS(rcuname, callbacks_invoked, cb, nr, iit, risk),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
+		__field(const char *, rcuname)
 		__field(int, callbacks_invoked)
 		__field(bool, cb)
 		__field(bool, nr)
@@ -577,13 +577,13 @@
  */
 TRACE_EVENT(rcu_torture_read,
 
-	TP_PROTO(char *rcutorturename, struct rcu_head *rhp,
+	TP_PROTO(const char *rcutorturename, struct rcu_head *rhp,
 		 unsigned long secs, unsigned long c_old, unsigned long c),
 
 	TP_ARGS(rcutorturename, rhp, secs, c_old, c),
 
 	TP_STRUCT__entry(
-		__field(char *, rcutorturename)
+		__field(const char *, rcutorturename)
 		__field(struct rcu_head *, rhp)
 		__field(unsigned long, secs)
 		__field(unsigned long, c_old)
@@ -623,13 +623,13 @@
  */
 TRACE_EVENT(rcu_barrier,
 
-	TP_PROTO(char *rcuname, char *s, int cpu, int cnt, unsigned long done),
+	TP_PROTO(const char *rcuname, const char *s, int cpu, int cnt, unsigned long done),
 
 	TP_ARGS(rcuname, s, cpu, cnt, done),
 
 	TP_STRUCT__entry(
-		__field(char *, rcuname)
-		__field(char *, s)
+		__field(const char *, rcuname)
+		__field(const char *, s)
 		__field(int, cpu)
 		__field(int, cnt)
 		__field(unsigned long, done)
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index e5586ca..2e7d994 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -57,7 +57,7 @@
 
 	TP_PROTO(struct task_struct *p, int success),
 
-	TP_ARGS(p, success),
+	TP_ARGS(__perf_task(p), success),
 
 	TP_STRUCT__entry(
 		__array(	char,	comm,	TASK_COMM_LEN	)
@@ -73,9 +73,6 @@
 		__entry->prio		= p->prio;
 		__entry->success	= success;
 		__entry->target_cpu	= task_cpu(p);
-	)
-	TP_perf_assign(
-		__perf_task(p);
 	),
 
 	TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
@@ -313,7 +310,7 @@
 
 	TP_PROTO(struct task_struct *tsk, u64 delay),
 
-	TP_ARGS(tsk, delay),
+	TP_ARGS(__perf_task(tsk), __perf_count(delay)),
 
 	TP_STRUCT__entry(
 		__array( char,	comm,	TASK_COMM_LEN	)
@@ -325,10 +322,6 @@
 		memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
 		__entry->pid	= tsk->pid;
 		__entry->delay	= delay;
-	)
-	TP_perf_assign(
-		__perf_count(delay);
-		__perf_task(tsk);
 	),
 
 	TP_printk("comm=%s pid=%d delay=%Lu [ns]",
@@ -372,11 +365,11 @@
  * Tracepoint for accounting runtime (time the task is executing
  * on a CPU).
  */
-TRACE_EVENT(sched_stat_runtime,
+DECLARE_EVENT_CLASS(sched_stat_runtime,
 
 	TP_PROTO(struct task_struct *tsk, u64 runtime, u64 vruntime),
 
-	TP_ARGS(tsk, runtime, vruntime),
+	TP_ARGS(tsk, __perf_count(runtime), vruntime),
 
 	TP_STRUCT__entry(
 		__array( char,	comm,	TASK_COMM_LEN	)
@@ -390,9 +383,6 @@
 		__entry->pid		= tsk->pid;
 		__entry->runtime	= runtime;
 		__entry->vruntime	= vruntime;
-	)
-	TP_perf_assign(
-		__perf_count(runtime);
 	),
 
 	TP_printk("comm=%s pid=%d runtime=%Lu [ns] vruntime=%Lu [ns]",
@@ -401,6 +391,10 @@
 			(unsigned long long)__entry->vruntime)
 );
 
+DEFINE_EVENT(sched_stat_runtime, sched_stat_runtime,
+	     TP_PROTO(struct task_struct *tsk, u64 runtime, u64 vruntime),
+	     TP_ARGS(tsk, runtime, vruntime));
+
 /*
  * Tracepoint for showing priority inheritance modifying a tasks
  * priority.
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 41a6643..5c7ab17 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -507,8 +507,14 @@
 #undef TP_fast_assign
 #define TP_fast_assign(args...) args
 
-#undef TP_perf_assign
-#define TP_perf_assign(args...)
+#undef __perf_addr
+#define __perf_addr(a)	(a)
+
+#undef __perf_count
+#define __perf_count(c)	(c)
+
+#undef __perf_task
+#define __perf_task(t)	(t)
 
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)	\
@@ -636,16 +642,13 @@
 #define __get_str(field) (char *)__get_dynamic_array(field)
 
 #undef __perf_addr
-#define __perf_addr(a) __addr = (a)
+#define __perf_addr(a)	(__addr = (a))
 
 #undef __perf_count
-#define __perf_count(c) __count = (c)
+#define __perf_count(c)	(__count = (c))
 
 #undef __perf_task
-#define __perf_task(t) __task = (t)
-
-#undef TP_perf_assign
-#define TP_perf_assign(args...) args
+#define __perf_task(t)	(__task = (t))
 
 #undef DECLARE_EVENT_CLASS
 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print)	\
@@ -663,15 +666,20 @@
 	int __data_size;						\
 	int rctx;							\
 									\
-	perf_fetch_caller_regs(&__regs);				\
-									\
 	__data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
+									\
+	head = this_cpu_ptr(event_call->perf_events);			\
+	if (__builtin_constant_p(!__task) && !__task &&			\
+				hlist_empty(head))			\
+		return;							\
+									\
 	__entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
 			     sizeof(u64));				\
 	__entry_size -= sizeof(u32);					\
 									\
-	entry = (struct ftrace_raw_##call *)perf_trace_buf_prepare(	\
-		__entry_size, event_call->event.type, &__regs, &rctx);	\
+	perf_fetch_caller_regs(&__regs);				\
+	entry = perf_trace_buf_prepare(__entry_size,			\
+			event_call->event.type, &__regs, &rctx);	\
 	if (!entry)							\
 		return;							\
 									\
@@ -679,7 +687,6 @@
 									\
 	{ assign; }							\
 									\
-	head = this_cpu_ptr(event_call->perf_events);			\
 	perf_trace_buf_submit(entry, __entry_size, rctx, __addr,	\
 		__count, &__regs, head, __task);			\
 }
diff --git a/include/uapi/linux/cm4000_cs.h b/include/uapi/linux/cm4000_cs.h
index bc51f77..1217f75 100644
--- a/include/uapi/linux/cm4000_cs.h
+++ b/include/uapi/linux/cm4000_cs.h
@@ -2,6 +2,7 @@
 #define _UAPI_CM4000_H_
 
 #include <linux/types.h>
+#include <linux/ioctl.h>
 
 #define	MAX_ATR			33
 
diff --git a/include/uapi/linux/fiemap.h b/include/uapi/linux/fiemap.h
index d830747..0c51d61 100644
--- a/include/uapi/linux/fiemap.h
+++ b/include/uapi/linux/fiemap.h
@@ -40,6 +40,7 @@
 
 #define FIEMAP_FLAG_SYNC	0x00000001 /* sync file data before map */
 #define FIEMAP_FLAG_XATTR	0x00000002 /* map extended attribute tree */
+#define FIEMAP_FLAG_CACHE	0x00000004 /* request caching of the extents */
 
 #define FIEMAP_FLAGS_COMPAT	(FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR)
 
diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h
index 6cf06bf..2fee45b 100644
--- a/include/uapi/linux/ip.h
+++ b/include/uapi/linux/ip.h
@@ -133,4 +133,38 @@
 	__u8 reserved;
 };
 
+/* index values for the variables in ipv4_devconf */
+enum
+{
+	IPV4_DEVCONF_FORWARDING=1,
+	IPV4_DEVCONF_MC_FORWARDING,
+	IPV4_DEVCONF_PROXY_ARP,
+	IPV4_DEVCONF_ACCEPT_REDIRECTS,
+	IPV4_DEVCONF_SECURE_REDIRECTS,
+	IPV4_DEVCONF_SEND_REDIRECTS,
+	IPV4_DEVCONF_SHARED_MEDIA,
+	IPV4_DEVCONF_RP_FILTER,
+	IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE,
+	IPV4_DEVCONF_BOOTP_RELAY,
+	IPV4_DEVCONF_LOG_MARTIANS,
+	IPV4_DEVCONF_TAG,
+	IPV4_DEVCONF_ARPFILTER,
+	IPV4_DEVCONF_MEDIUM_ID,
+	IPV4_DEVCONF_NOXFRM,
+	IPV4_DEVCONF_NOPOLICY,
+	IPV4_DEVCONF_FORCE_IGMP_VERSION,
+	IPV4_DEVCONF_ARP_ANNOUNCE,
+	IPV4_DEVCONF_ARP_IGNORE,
+	IPV4_DEVCONF_PROMOTE_SECONDARIES,
+	IPV4_DEVCONF_ARP_ACCEPT,
+	IPV4_DEVCONF_ARP_NOTIFY,
+	IPV4_DEVCONF_ACCEPT_LOCAL,
+	IPV4_DEVCONF_SRC_VMARK,
+	IPV4_DEVCONF_PROXY_ARP_PVLAN,
+	IPV4_DEVCONF_ROUTE_LOCALNET,
+	__IPV4_DEVCONF_MAX
+};
+
+#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1)
+
 #endif /* _UAPI_LINUX_IP_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index acccd08..99c2533 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -667,6 +667,7 @@
 #define KVM_CAP_PPC_RTAS 91
 #define KVM_CAP_IRQ_XICS 92
 #define KVM_CAP_ARM_EL1_32BIT 93
+#define KVM_CAP_SPAPR_MULTITCE 94
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
index cea2c5c..2841f86 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -19,6 +19,7 @@
 #define KVM_HC_MMU_OP			2
 #define KVM_HC_FEATURES			3
 #define KVM_HC_PPC_MAP_MAGIC_PAGE	4
+#define KVM_HC_KICK_CPU			5
 
 /*
  * hypercalls use architecture specific
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index c3cc01d..baa7852 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -421,24 +421,24 @@
 #define  PCI_EXP_TYPE_ROOT_PORT 0x4	/* Root Port */
 #define  PCI_EXP_TYPE_UPSTREAM	0x5	/* Upstream Port */
 #define  PCI_EXP_TYPE_DOWNSTREAM 0x6	/* Downstream Port */
-#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7	/* PCI/PCI-X Bridge */
-#define  PCI_EXP_TYPE_PCIE_BRIDGE 0x8	/* PCI/PCI-X to PCIE Bridge */
+#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7	/* PCIe to PCI/PCI-X Bridge */
+#define  PCI_EXP_TYPE_PCIE_BRIDGE 0x8	/* PCI/PCI-X to PCIe Bridge */
 #define  PCI_EXP_TYPE_RC_END	0x9	/* Root Complex Integrated Endpoint */
 #define  PCI_EXP_TYPE_RC_EC	0xa	/* Root Complex Event Collector */
 #define PCI_EXP_FLAGS_SLOT	0x0100	/* Slot implemented */
 #define PCI_EXP_FLAGS_IRQ	0x3e00	/* Interrupt message number */
 #define PCI_EXP_DEVCAP		4	/* Device capabilities */
-#define  PCI_EXP_DEVCAP_PAYLOAD	0x07	/* Max_Payload_Size */
-#define  PCI_EXP_DEVCAP_PHANTOM	0x18	/* Phantom functions */
-#define  PCI_EXP_DEVCAP_EXT_TAG	0x20	/* Extended tags */
-#define  PCI_EXP_DEVCAP_L0S	0x1c0	/* L0s Acceptable Latency */
-#define  PCI_EXP_DEVCAP_L1	0xe00	/* L1 Acceptable Latency */
-#define  PCI_EXP_DEVCAP_ATN_BUT	0x1000	/* Attention Button Present */
-#define  PCI_EXP_DEVCAP_ATN_IND	0x2000	/* Attention Indicator Present */
-#define  PCI_EXP_DEVCAP_PWR_IND	0x4000	/* Power Indicator Present */
-#define  PCI_EXP_DEVCAP_RBER	0x8000	/* Role-Based Error Reporting */
-#define  PCI_EXP_DEVCAP_PWR_VAL	0x3fc0000 /* Slot Power Limit Value */
-#define  PCI_EXP_DEVCAP_PWR_SCL	0xc000000 /* Slot Power Limit Scale */
+#define  PCI_EXP_DEVCAP_PAYLOAD	0x00000007 /* Max_Payload_Size */
+#define  PCI_EXP_DEVCAP_PHANTOM	0x00000018 /* Phantom functions */
+#define  PCI_EXP_DEVCAP_EXT_TAG	0x00000020 /* Extended tags */
+#define  PCI_EXP_DEVCAP_L0S	0x000001c0 /* L0s Acceptable Latency */
+#define  PCI_EXP_DEVCAP_L1	0x00000e00 /* L1 Acceptable Latency */
+#define  PCI_EXP_DEVCAP_ATN_BUT	0x00001000 /* Attention Button Present */
+#define  PCI_EXP_DEVCAP_ATN_IND	0x00002000 /* Attention Indicator Present */
+#define  PCI_EXP_DEVCAP_PWR_IND	0x00004000 /* Power Indicator Present */
+#define  PCI_EXP_DEVCAP_RBER	0x00008000 /* Role-Based Error Reporting */
+#define  PCI_EXP_DEVCAP_PWR_VAL	0x03fc0000 /* Slot Power Limit Value */
+#define  PCI_EXP_DEVCAP_PWR_SCL	0x0c000000 /* Slot Power Limit Scale */
 #define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
 #define PCI_EXP_DEVCTL		8	/* Device Control */
 #define  PCI_EXP_DEVCTL_CERE	0x0001	/* Correctable Error Reporting En. */
@@ -454,16 +454,16 @@
 #define  PCI_EXP_DEVCTL_READRQ	0x7000	/* Max_Read_Request_Size */
 #define  PCI_EXP_DEVCTL_BCR_FLR 0x8000  /* Bridge Configuration Retry / FLR */
 #define PCI_EXP_DEVSTA		10	/* Device Status */
-#define  PCI_EXP_DEVSTA_CED	0x01	/* Correctable Error Detected */
-#define  PCI_EXP_DEVSTA_NFED	0x02	/* Non-Fatal Error Detected */
-#define  PCI_EXP_DEVSTA_FED	0x04	/* Fatal Error Detected */
-#define  PCI_EXP_DEVSTA_URD	0x08	/* Unsupported Request Detected */
-#define  PCI_EXP_DEVSTA_AUXPD	0x10	/* AUX Power Detected */
-#define  PCI_EXP_DEVSTA_TRPND	0x20	/* Transactions Pending */
+#define  PCI_EXP_DEVSTA_CED	0x0001	/* Correctable Error Detected */
+#define  PCI_EXP_DEVSTA_NFED	0x0002	/* Non-Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_FED	0x0004	/* Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_URD	0x0008	/* Unsupported Request Detected */
+#define  PCI_EXP_DEVSTA_AUXPD	0x0010	/* AUX Power Detected */
+#define  PCI_EXP_DEVSTA_TRPND	0x0020	/* Transactions Pending */
 #define PCI_EXP_LNKCAP		12	/* Link Capabilities */
 #define  PCI_EXP_LNKCAP_SLS	0x0000000f /* Supported Link Speeds */
-#define  PCI_EXP_LNKCAP_SLS_2_5GB 0x1	/* LNKCAP2 SLS Vector bit 0 (2.5GT/s) */
-#define  PCI_EXP_LNKCAP_SLS_5_0GB 0x2	/* LNKCAP2 SLS Vector bit 1 (5.0GT/s) */
+#define  PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
+#define  PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
 #define  PCI_EXP_LNKCAP_MLW	0x000003f0 /* Maximum Link Width */
 #define  PCI_EXP_LNKCAP_ASPMS	0x00000c00 /* ASPM Support */
 #define  PCI_EXP_LNKCAP_L0SEL	0x00007000 /* L0s Exit Latency */
@@ -475,21 +475,21 @@
 #define  PCI_EXP_LNKCAP_PN	0xff000000 /* Port Number */
 #define PCI_EXP_LNKCTL		16	/* Link Control */
 #define  PCI_EXP_LNKCTL_ASPMC	0x0003	/* ASPM Control */
-#define  PCI_EXP_LNKCTL_ASPM_L0S  0x01	/* L0s Enable */
-#define  PCI_EXP_LNKCTL_ASPM_L1   0x02	/* L1 Enable */
+#define  PCI_EXP_LNKCTL_ASPM_L0S 0x0001	/* L0s Enable */
+#define  PCI_EXP_LNKCTL_ASPM_L1  0x0002	/* L1 Enable */
 #define  PCI_EXP_LNKCTL_RCB	0x0008	/* Read Completion Boundary */
 #define  PCI_EXP_LNKCTL_LD	0x0010	/* Link Disable */
 #define  PCI_EXP_LNKCTL_RL	0x0020	/* Retrain Link */
 #define  PCI_EXP_LNKCTL_CCC	0x0040	/* Common Clock Configuration */
 #define  PCI_EXP_LNKCTL_ES	0x0080	/* Extended Synch */
-#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100	/* Enable clkreq */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x0100 /* Enable clkreq */
 #define  PCI_EXP_LNKCTL_HAWD	0x0200	/* Hardware Autonomous Width Disable */
 #define  PCI_EXP_LNKCTL_LBMIE	0x0400	/* Link Bandwidth Management Interrupt Enable */
 #define  PCI_EXP_LNKCTL_LABIE	0x0800	/* Lnk Autonomous Bandwidth Interrupt Enable */
 #define PCI_EXP_LNKSTA		18	/* Link Status */
 #define  PCI_EXP_LNKSTA_CLS	0x000f	/* Current Link Speed */
-#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01	/* Current Link Speed 2.5GT/s */
-#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02	/* Current Link Speed 5.0GT/s */
+#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x0002 /* Current Link Speed 5.0GT/s */
 #define  PCI_EXP_LNKSTA_NLW	0x03f0	/* Nogotiated Link Width */
 #define  PCI_EXP_LNKSTA_NLW_SHIFT 4	/* start of NLW mask in link status */
 #define  PCI_EXP_LNKSTA_LT	0x0800	/* Link Training */
@@ -534,44 +534,49 @@
 #define  PCI_EXP_SLTSTA_EIS	0x0080	/* Electromechanical Interlock Status */
 #define  PCI_EXP_SLTSTA_DLLSC	0x0100	/* Data Link Layer State Changed */
 #define PCI_EXP_RTCTL		28	/* Root Control */
-#define  PCI_EXP_RTCTL_SECEE	0x01	/* System Error on Correctable Error */
-#define  PCI_EXP_RTCTL_SENFEE	0x02	/* System Error on Non-Fatal Error */
-#define  PCI_EXP_RTCTL_SEFEE	0x04	/* System Error on Fatal Error */
-#define  PCI_EXP_RTCTL_PMEIE	0x08	/* PME Interrupt Enable */
-#define  PCI_EXP_RTCTL_CRSSVE	0x10	/* CRS Software Visibility Enable */
+#define  PCI_EXP_RTCTL_SECEE	0x0001	/* System Error on Correctable Error */
+#define  PCI_EXP_RTCTL_SENFEE	0x0002	/* System Error on Non-Fatal Error */
+#define  PCI_EXP_RTCTL_SEFEE	0x0004	/* System Error on Fatal Error */
+#define  PCI_EXP_RTCTL_PMEIE	0x0008	/* PME Interrupt Enable */
+#define  PCI_EXP_RTCTL_CRSSVE	0x0010	/* CRS Software Visibility Enable */
 #define PCI_EXP_RTCAP		30	/* Root Capabilities */
 #define PCI_EXP_RTSTA		32	/* Root Status */
-#define PCI_EXP_RTSTA_PME	0x10000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING	0x20000 /* PME pending */
+#define PCI_EXP_RTSTA_PME	0x00010000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING	0x00020000 /* PME pending */
 /*
- * Note that the following PCI Express 'Capability Structure' registers
- * were introduced with 'Capability Version' 0x2 (v2).  These registers
- * do not exist on devices with Capability Version 1.  Use pci_pcie_cap2()
- * to use these fields safely.
+ * The Device Capabilities 2, Device Status 2, Device Control 2,
+ * Link Capabilities 2, Link Status 2, Link Control 2,
+ * Slot Capabilities 2, Slot Status 2, and Slot Control 2 registers
+ * are only present on devices with PCIe Capability version 2.
+ * Use pcie_capability_read_word() and similar interfaces to use them
+ * safely.
  */
 #define PCI_EXP_DEVCAP2		36	/* Device Capabilities 2 */
-#define  PCI_EXP_DEVCAP2_ARI	0x20	/* Alternative Routing-ID */
-#define  PCI_EXP_DEVCAP2_LTR	0x800	/* Latency tolerance reporting */
-#define  PCI_EXP_OBFF_MASK	0xc0000 /* OBFF support mechanism */
-#define  PCI_EXP_OBFF_MSG	0x40000 /* New message signaling */
-#define  PCI_EXP_OBFF_WAKE	0x80000 /* Re-use WAKE# for OBFF */
+#define  PCI_EXP_DEVCAP2_ARI		0x00000020 /* Alternative Routing-ID */
+#define  PCI_EXP_DEVCAP2_LTR		0x00000800 /* Latency tolerance reporting */
+#define  PCI_EXP_DEVCAP2_OBFF_MASK	0x000c0000 /* OBFF support mechanism */
+#define  PCI_EXP_DEVCAP2_OBFF_MSG	0x00040000 /* New message signaling */
+#define  PCI_EXP_DEVCAP2_OBFF_WAKE	0x00080000 /* Re-use WAKE# for OBFF */
 #define PCI_EXP_DEVCTL2		40	/* Device Control 2 */
-#define  PCI_EXP_DEVCTL2_ARI	0x20	/* Alternative Routing-ID */
-#define  PCI_EXP_IDO_REQ_EN	0x100	/* ID-based ordering request enable */
-#define  PCI_EXP_IDO_CMP_EN	0x200	/* ID-based ordering completion enable */
-#define  PCI_EXP_LTR_EN		0x400	/* Latency tolerance reporting */
-#define  PCI_EXP_OBFF_MSGA_EN	0x2000	/* OBFF enable with Message type A */
-#define  PCI_EXP_OBFF_MSGB_EN	0x4000	/* OBFF enable with Message type B */
-#define  PCI_EXP_OBFF_WAKE_EN	0x6000	/* OBFF using WAKE# signaling */
+#define  PCI_EXP_DEVCTL2_ARI		0x20	/* Alternative Routing-ID */
+#define  PCI_EXP_DEVCTL2_IDO_REQ_EN	0x0100	/* Allow IDO for requests */
+#define  PCI_EXP_DEVCTL2_IDO_CMP_EN	0x0200	/* Allow IDO for completions */
+#define  PCI_EXP_DEVCTL2_LTR_EN		0x0400	/* Enable LTR mechanism */
+#define  PCI_EXP_DEVCTL2_OBFF_MSGA_EN	0x2000	/* Enable OBFF Message type A */
+#define  PCI_EXP_DEVCTL2_OBFF_MSGB_EN	0x4000	/* Enable OBFF Message type B */
+#define  PCI_EXP_DEVCTL2_OBFF_WAKE_EN	0x6000	/* OBFF using WAKE# signaling */
+#define PCI_EXP_DEVSTA2		42	/* Device Status 2 */
 #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2	44	/* v2 endpoints end here */
-#define PCI_EXP_LNKCAP2		44	/* Link Capability 2 */
-#define  PCI_EXP_LNKCAP2_SLS_2_5GB 0x02	/* Supported Link Speed 2.5GT/s */
-#define  PCI_EXP_LNKCAP2_SLS_5_0GB 0x04	/* Supported Link Speed 5.0GT/s */
-#define  PCI_EXP_LNKCAP2_SLS_8_0GB 0x08	/* Supported Link Speed 8.0GT/s */
-#define  PCI_EXP_LNKCAP2_CROSSLINK 0x100 /* Crosslink supported */
+#define PCI_EXP_LNKCAP2		44	/* Link Capabilities 2 */
+#define  PCI_EXP_LNKCAP2_SLS_2_5GB	0x00000002 /* Supported Speed 2.5GT/s */
+#define  PCI_EXP_LNKCAP2_SLS_5_0GB	0x00000004 /* Supported Speed 5.0GT/s */
+#define  PCI_EXP_LNKCAP2_SLS_8_0GB	0x00000008 /* Supported Speed 8.0GT/s */
+#define  PCI_EXP_LNKCAP2_CROSSLINK	0x00000100 /* Crosslink supported */
 #define PCI_EXP_LNKCTL2		48	/* Link Control 2 */
 #define PCI_EXP_LNKSTA2		50	/* Link Status 2 */
+#define PCI_EXP_SLTCAP2		52	/* Slot Capabilities 2 */
 #define PCI_EXP_SLTCTL2		56	/* Slot Control 2 */
+#define PCI_EXP_SLTSTA2		58	/* Slot Status 2 */
 
 /* Extended Capabilities (PCI-X 2.0 and Express) */
 #define PCI_EXT_CAP_ID(header)		(header & 0x0000ffff)
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 0b1df41..ca1d90b 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -109,6 +109,7 @@
 	PERF_COUNT_SW_PAGE_FAULTS_MAJ		= 6,
 	PERF_COUNT_SW_ALIGNMENT_FAULTS		= 7,
 	PERF_COUNT_SW_EMULATION_FAULTS		= 8,
+	PERF_COUNT_SW_DUMMY			= 9,
 
 	PERF_COUNT_SW_MAX,			/* non-ABI */
 };
@@ -134,8 +135,9 @@
 	PERF_SAMPLE_STACK_USER			= 1U << 13,
 	PERF_SAMPLE_WEIGHT			= 1U << 14,
 	PERF_SAMPLE_DATA_SRC			= 1U << 15,
+	PERF_SAMPLE_IDENTIFIER			= 1U << 16,
 
-	PERF_SAMPLE_MAX = 1U << 16,		/* non-ABI */
+	PERF_SAMPLE_MAX = 1U << 17,		/* non-ABI */
 };
 
 /*
@@ -275,8 +277,9 @@
 
 				exclude_callchain_kernel : 1, /* exclude kernel callchains */
 				exclude_callchain_user   : 1, /* exclude user callchains */
+				mmap2          :  1, /* include mmap with inode data     */
 
-				__reserved_1   : 41;
+				__reserved_1   : 40;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
@@ -321,6 +324,7 @@
 #define PERF_EVENT_IOC_PERIOD		_IOW('$', 4, __u64)
 #define PERF_EVENT_IOC_SET_OUTPUT	_IO ('$', 5)
 #define PERF_EVENT_IOC_SET_FILTER	_IOW('$', 6, char *)
+#define PERF_EVENT_IOC_ID		_IOR('$', 7, u64 *)
 
 enum perf_event_ioc_flags {
 	PERF_IOC_FLAG_GROUP		= 1U << 0,
@@ -375,9 +379,12 @@
 	__u64	time_running;		/* time event on cpu */
 	union {
 		__u64	capabilities;
-		__u64	cap_usr_time  : 1,
-			cap_usr_rdpmc : 1,
-			cap_____res   : 62;
+		struct {
+			__u64	cap_usr_time		: 1,
+				cap_usr_rdpmc		: 1,
+				cap_usr_time_zero	: 1,
+				cap_____res		: 61;
+		};
 	};
 
 	/*
@@ -418,12 +425,29 @@
 	__u16	time_shift;
 	__u32	time_mult;
 	__u64	time_offset;
+	/*
+	 * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
+	 * from sample timestamps.
+	 *
+	 *   time = timestamp - time_zero;
+	 *   quot = time / time_mult;
+	 *   rem  = time % time_mult;
+	 *   cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
+	 *
+	 * And vice versa:
+	 *
+	 *   quot = cyc >> time_shift;
+	 *   rem  = cyc & ((1 << time_shift) - 1);
+	 *   timestamp = time_zero + quot * time_mult +
+	 *               ((rem * time_mult) >> time_shift);
+	 */
+	__u64	time_zero;
 
 		/*
 		 * Hole for extension of the self monitor capabilities
 		 */
 
-	__u64	__reserved[120];	/* align to 1k */
+	__u64	__reserved[119];	/* align to 1k */
 
 	/*
 	 * Control data for the mmap() data buffer.
@@ -471,13 +495,28 @@
 	/*
 	 * If perf_event_attr.sample_id_all is set then all event types will
 	 * have the sample_type selected fields related to where/when
-	 * (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID)
-	 * described in PERF_RECORD_SAMPLE below, it will be stashed just after
-	 * the perf_event_header and the fields already present for the existing
-	 * fields, i.e. at the end of the payload. That way a newer perf.data
-	 * file will be supported by older perf tools, with these new optional
-	 * fields being ignored.
+	 * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
+	 * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
+	 * just after the perf_event_header and the fields already present for
+	 * the existing fields, i.e. at the end of the payload. That way a newer
+	 * perf.data file will be supported by older perf tools, with these new
+	 * optional fields being ignored.
 	 *
+	 * struct sample_id {
+	 * 	{ u32			pid, tid; } && PERF_SAMPLE_TID
+	 * 	{ u64			time;     } && PERF_SAMPLE_TIME
+	 * 	{ u64			id;       } && PERF_SAMPLE_ID
+	 * 	{ u64			stream_id;} && PERF_SAMPLE_STREAM_ID
+	 * 	{ u32			cpu, res; } && PERF_SAMPLE_CPU
+	 *	{ u64			id;	  } && PERF_SAMPLE_IDENTIFIER
+	 * } && perf_event_attr::sample_id_all
+	 *
+	 * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.  The
+	 * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
+	 * relative to header.size.
+	 */
+
+	/*
 	 * The MMAP events record the PROT_EXEC mappings so that we can
 	 * correlate userspace IPs to code. They have the following structure:
 	 *
@@ -498,6 +537,7 @@
 	 *	struct perf_event_header	header;
 	 *	u64				id;
 	 *	u64				lost;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_LOST			= 2,
@@ -508,6 +548,7 @@
 	 *
 	 *	u32				pid, tid;
 	 *	char				comm[];
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_COMM			= 3,
@@ -518,6 +559,7 @@
 	 *	u32				pid, ppid;
 	 *	u32				tid, ptid;
 	 *	u64				time;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_EXIT			= 4,
@@ -528,6 +570,7 @@
 	 *	u64				time;
 	 *	u64				id;
 	 *	u64				stream_id;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_THROTTLE			= 5,
@@ -539,6 +582,7 @@
 	 *	u32				pid, ppid;
 	 *	u32				tid, ptid;
 	 *	u64				time;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_FORK			= 7,
@@ -549,6 +593,7 @@
 	 *	u32				pid, tid;
 	 *
 	 *	struct read_format		values;
+	 * 	struct sample_id		sample_id;
 	 * };
 	 */
 	PERF_RECORD_READ			= 8,
@@ -557,6 +602,13 @@
 	 * struct {
 	 *	struct perf_event_header	header;
 	 *
+	 *	#
+	 *	# Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
+	 *	# The advantage of PERF_SAMPLE_IDENTIFIER is that its position
+	 *	# is fixed relative to header.
+	 *	#
+	 *
+	 *	{ u64			id;	  } && PERF_SAMPLE_IDENTIFIER
 	 *	{ u64			ip;	  } && PERF_SAMPLE_IP
 	 *	{ u32			pid, tid; } && PERF_SAMPLE_TID
 	 *	{ u64			time;     } && PERF_SAMPLE_TIME
@@ -596,11 +648,32 @@
 	 * 	  u64			dyn_size; } && PERF_SAMPLE_STACK_USER
 	 *
 	 *	{ u64			weight;   } && PERF_SAMPLE_WEIGHT
-	 *	{ u64			data_src;     } && PERF_SAMPLE_DATA_SRC
+	 *	{ u64			data_src; } && PERF_SAMPLE_DATA_SRC
 	 * };
 	 */
 	PERF_RECORD_SAMPLE			= 9,
 
+	/*
+	 * The MMAP2 records are an augmented version of MMAP, they add
+	 * maj, min, ino numbers to be used to uniquely identify each mapping
+	 *
+	 * struct {
+	 *	struct perf_event_header	header;
+	 *
+	 *	u32				pid, tid;
+	 *	u64				addr;
+	 *	u64				len;
+	 *	u64				pgoff;
+	 *	u32				maj;
+	 *	u32				min;
+	 *	u64				ino;
+	 *	u64				ino_generation;
+	 *	char				filename[];
+	 * 	struct sample_id		sample_id;
+	 * };
+	 */
+	PERF_RECORD_MMAP2			= 10,
+
 	PERF_RECORD_MAX,			/* non-ABI */
 };
 
@@ -685,4 +758,28 @@
 #define PERF_MEM_S(a, s) \
 	(((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
 
+/*
+ * 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.
+ *
+ *     in_tx: running in a hardware transaction
+ *     abort: aborting a hardware transaction
+ */
+struct perf_branch_entry {
+	__u64	from;
+	__u64	to;
+	__u64	mispred:1,  /* target mispredicted */
+		predicted:1,/* target predicted */
+		in_tx:1,    /* in transaction */
+		abort:1,    /* transaction abort */
+		reserved:60;
+};
+
 #endif /* _UAPI_LINUX_PERF_EVENT_H */
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 9119cc0..e40ebe1 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -232,4 +232,7 @@
 /* SH-SCI */
 #define PORT_HSCIF	104
 
+/* ST ASC type numbers */
+#define PORT_ASC       105
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h
index 1f59ea2..d956c35 100644
--- a/include/uapi/sound/hdspm.h
+++ b/include/uapi/sound/hdspm.h
@@ -111,7 +111,7 @@
 	enum hdspm_ltc_input_format input_format;
 };
 
-#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_mixer_ioctl)
+#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_ltc)
 
 /**
  * The status data reflects the device's current state
diff --git a/include/xen/acpi.h b/include/xen/acpi.h
index 46aa3d1..4ddd7dc 100644
--- a/include/xen/acpi.h
+++ b/include/xen/acpi.h
@@ -75,8 +75,10 @@
 	return -ENXIO;
 }
 
-int xen_acpi_notify_hypervisor_state(u8 sleep_state,
+int xen_acpi_notify_hypervisor_sleep(u8 sleep_state,
 				     u32 pm1a_cnt, u32 pm1b_cnd);
+int xen_acpi_notify_hypervisor_extended_sleep(u8 sleep_state,
+				     u32 val_a, u32 val_b);
 
 static inline int xen_acpi_suspend_lowlevel(void)
 {
@@ -93,7 +95,9 @@
 {
 	if (xen_initial_domain()) {
 		acpi_os_set_prepare_sleep(
-			&xen_acpi_notify_hypervisor_state);
+			&xen_acpi_notify_hypervisor_sleep);
+		acpi_os_set_prepare_extended_sleep(
+			&xen_acpi_notify_hypervisor_extended_sleep);
 
 		acpi_suspend_lowlevel = xen_acpi_suspend_lowlevel;
 	}
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
index cc2e1a7..a4c1c6a 100644
--- a/include/xen/balloon.h
+++ b/include/xen/balloon.h
@@ -29,6 +29,9 @@
 		bool highmem);
 void free_xenballooned_pages(int nr_pages, struct page **pages);
 
+struct page *get_balloon_scratch_page(void);
+void put_balloon_scratch_page(void);
+
 struct device;
 #ifdef CONFIG_XEN_SELFBALLOONING
 extern int register_xen_selfballooning(struct device *dev);
diff --git a/include/xen/interface/io/tpmif.h b/include/xen/interface/io/tpmif.h
new file mode 100644
index 0000000..28e7dcd
--- /dev/null
+++ b/include/xen/interface/io/tpmif.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * tpmif.h
+ *
+ * TPM I/O interface for Xen guest OSes, v2
+ *
+ * This file is in the public domain.
+ *
+ */
+
+#ifndef __XEN_PUBLIC_IO_TPMIF_H__
+#define __XEN_PUBLIC_IO_TPMIF_H__
+
+/*
+ * Xenbus state machine
+ *
+ * Device open:
+ *   1. Both ends start in XenbusStateInitialising
+ *   2. Backend transitions to InitWait (frontend does not wait on this step)
+ *   3. Frontend populates ring-ref, event-channel, feature-protocol-v2
+ *   4. Frontend transitions to Initialised
+ *   5. Backend maps grant and event channel, verifies feature-protocol-v2
+ *   6. Backend transitions to Connected
+ *   7. Frontend verifies feature-protocol-v2, transitions to Connected
+ *
+ * Device close:
+ *   1. State is changed to XenbusStateClosing
+ *   2. Frontend transitions to Closed
+ *   3. Backend unmaps grant and event, changes state to InitWait
+ */
+
+enum vtpm_shared_page_state {
+	VTPM_STATE_IDLE,         /* no contents / vTPM idle / cancel complete */
+	VTPM_STATE_SUBMIT,       /* request ready / vTPM working */
+	VTPM_STATE_FINISH,       /* response ready / vTPM idle */
+	VTPM_STATE_CANCEL,       /* cancel requested / vTPM working */
+};
+/* The backend should only change state to IDLE or FINISH, while the
+ * frontend should only change to SUBMIT or CANCEL. */
+
+
+struct vtpm_shared_page {
+	uint32_t length;         /* request/response length in bytes */
+
+	uint8_t state;           /* enum vtpm_shared_page_state */
+	uint8_t locality;        /* for the current request */
+	uint8_t pad;
+
+	uint8_t nr_extra_pages;  /* extra pages for long packets; may be zero */
+	uint32_t extra_pages[0]; /* grant IDs; length in nr_extra_pages */
+};
+
+#endif
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index c57d5f6..f1331e3 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -152,10 +152,11 @@
 #define XENPF_enter_acpi_sleep    51
 struct xenpf_enter_acpi_sleep {
 	/* IN variables */
-	uint16_t pm1a_cnt_val;      /* PM1a control value. */
-	uint16_t pm1b_cnt_val;      /* PM1b control value. */
+	uint16_t val_a;             /* PM1a control / sleep type A. */
+	uint16_t val_b;             /* PM1b control / sleep type B. */
 	uint32_t sleep_state;       /* Which state to enter (Sn). */
-	uint32_t flags;             /* Must be zero. */
+#define XENPF_ACPI_SLEEP_EXTENDED 0x00000001
+	uint32_t flags;             /* XENPF_ACPI_SLEEP_*. */
 };
 DEFINE_GUEST_HANDLE_STRUCT(xenpf_enter_acpi_sleep_t);
 
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
index 87e6f8a..b05288c 100644
--- a/include/xen/interface/vcpu.h
+++ b/include/xen/interface/vcpu.h
@@ -170,4 +170,6 @@
 };
 DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_vcpu_info);
 
+/* Send an NMI to the specified VCPU. @extra_arg == NULL. */
+#define VCPUOP_send_nmi             11
 #endif /* __XEN_PUBLIC_VCPU_H__ */
diff --git a/init/Kconfig b/init/Kconfig
index 247084b..0a2c4bc 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -470,6 +470,7 @@
 config TREE_PREEMPT_RCU
 	bool "Preemptible tree-based hierarchical RCU"
 	depends on PREEMPT
+	select IRQ_WORK
 	help
 	  This option selects the RCU implementation that is
 	  designed for very large SMP systems with hundreds or
@@ -527,13 +528,29 @@
 config CONTEXT_TRACKING_FORCE
 	bool "Force context tracking"
 	depends on CONTEXT_TRACKING
-	default CONTEXT_TRACKING
+	default y if !NO_HZ_FULL
 	help
-	  Probe on user/kernel boundaries by default in order to
-	  test the features that rely on it such as userspace RCU extended
-	  quiescent states.
-	  This test is there for debugging until we have a real user like the
-	  full dynticks mode.
+	  The major pre-requirement for full dynticks to work is to
+	  support the context tracking subsystem. But there are also
+	  other dependencies to provide in order to make the full
+	  dynticks working.
+
+	  This option stands for testing when an arch implements the
+	  context tracking backend but doesn't yet fullfill all the
+	  requirements to make the full dynticks feature working.
+	  Without the full dynticks, there is no way to test the support
+	  for context tracking and the subsystems that rely on it: RCU
+	  userspace extended quiescent state and tickless cputime
+	  accounting. This option copes with the absence of the full
+	  dynticks subsystem by forcing the context tracking on all
+	  CPUs in the system.
+
+	  Say Y only if you're working on the developpement of an
+	  architecture backend for the context tracking.
+
+	  Say N otherwise, this option brings an overhead that you
+	  don't want in production.
+
 
 config RCU_FANOUT
 	int "Tree-based hierarchical RCU fanout value"
@@ -955,7 +972,7 @@
 	  Memory Resource Controller Swap Extension comes with its price in
 	  a bigger memory consumption. General purpose distribution kernels
 	  which want to enable the feature but keep it disabled by default
-	  and let the user enable it by swapaccount boot command line
+	  and let the user enable it by swapaccount=1 boot command line
 	  parameter should have this option unselected.
 	  For those who want to have the feature enabled by default should
 	  select this option (if, for some reason, they need to disable it
diff --git a/init/main.c b/init/main.c
index d03d2ec..af310af 100644
--- a/init/main.c
+++ b/init/main.c
@@ -75,6 +75,7 @@
 #include <linux/blkdev.h>
 #include <linux/elevator.h>
 #include <linux/sched_clock.h>
+#include <linux/context_tracking.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -545,6 +546,7 @@
 	idr_init_cache();
 	rcu_init();
 	tick_nohz_init();
+	context_tracking_init();
 	radix_tree_init();
 	/* init some links before init_ISA_irqs() */
 	early_irq_init();
diff --git a/ipc/msg.c b/ipc/msg.c
index bd60d7e..b65fdf1 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -680,16 +680,18 @@
 		goto out_unlock1;
 	}
 
+	ipc_lock_object(&msq->q_perm);
+
 	for (;;) {
 		struct msg_sender s;
 
 		err = -EACCES;
 		if (ipcperms(ns, &msq->q_perm, S_IWUGO))
-			goto out_unlock1;
+			goto out_unlock0;
 
 		err = security_msg_queue_msgsnd(msq, msg, msgflg);
 		if (err)
-			goto out_unlock1;
+			goto out_unlock0;
 
 		if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
 				1 + msq->q_qnum <= msq->q_qbytes) {
@@ -699,10 +701,9 @@
 		/* queue full, wait: */
 		if (msgflg & IPC_NOWAIT) {
 			err = -EAGAIN;
-			goto out_unlock1;
+			goto out_unlock0;
 		}
 
-		ipc_lock_object(&msq->q_perm);
 		ss_add(msq, &s);
 
 		if (!ipc_rcu_getref(msq)) {
@@ -730,10 +731,7 @@
 			goto out_unlock0;
 		}
 
-		ipc_unlock_object(&msq->q_perm);
 	}
-
-	ipc_lock_object(&msq->q_perm);
 	msq->q_lspid = task_tgid_vnr(current);
 	msq->q_stime = get_seconds();
 
@@ -839,7 +837,7 @@
 
 static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
 {
-	struct msg_msg *msg;
+	struct msg_msg *msg, *found = NULL;
 	long count = 0;
 
 	list_for_each_entry(msg, &msq->q_messages, m_list) {
@@ -848,6 +846,7 @@
 					       *msgtyp, mode)) {
 			if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
 				*msgtyp = msg->m_type - 1;
+				found = msg;
 			} else if (mode == SEARCH_NUMBER) {
 				if (*msgtyp == count)
 					return msg;
@@ -857,7 +856,7 @@
 		}
 	}
 
-	return ERR_PTR(-EAGAIN);
+	return found ?: ERR_PTR(-EAGAIN);
 }
 
 long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgflg,
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 781845a..e0aeb32 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -81,7 +81,7 @@
  */
 #ifdef CONFIG_PROVE_RCU
 DEFINE_MUTEX(cgroup_mutex);
-EXPORT_SYMBOL_GPL(cgroup_mutex);	/* only for task_subsys_state_check() */
+EXPORT_SYMBOL_GPL(cgroup_mutex);	/* only for lockdep */
 #else
 static DEFINE_MUTEX(cgroup_mutex);
 #endif
@@ -117,6 +117,7 @@
 	struct list_head		node;
 	struct dentry			*dentry;
 	struct cftype			*type;
+	struct cgroup_subsys_state	*css;
 
 	/* file xattrs */
 	struct simple_xattrs		xattrs;
@@ -159,9 +160,9 @@
  */
 struct cgroup_event {
 	/*
-	 * Cgroup which the event belongs to.
+	 * css which the event belongs to.
 	 */
-	struct cgroup *cgrp;
+	struct cgroup_subsys_state *css;
 	/*
 	 * Control file which the event associated.
 	 */
@@ -215,10 +216,33 @@
  */
 static int need_forkexit_callback __read_mostly;
 
-static void cgroup_offline_fn(struct work_struct *work);
+static struct cftype cgroup_base_files[];
+
+static void cgroup_destroy_css_killed(struct cgroup *cgrp);
 static int cgroup_destroy_locked(struct cgroup *cgrp);
-static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
-			      struct cftype cfts[], bool is_add);
+static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[],
+			      bool is_add);
+
+/**
+ * cgroup_css - obtain a cgroup's css for the specified subsystem
+ * @cgrp: the cgroup of interest
+ * @ss: the subsystem of interest (%NULL returns the dummy_css)
+ *
+ * Return @cgrp's css (cgroup_subsys_state) associated with @ss.  This
+ * function must be called either under cgroup_mutex or rcu_read_lock() and
+ * the caller is responsible for pinning the returned css if it wants to
+ * keep accessing it outside the said locks.  This function may return
+ * %NULL if @cgrp doesn't have @subsys_id enabled.
+ */
+static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp,
+					      struct cgroup_subsys *ss)
+{
+	if (ss)
+		return rcu_dereference_check(cgrp->subsys[ss->subsys_id],
+					     lockdep_is_held(&cgroup_mutex));
+	else
+		return &cgrp->dummy_css;
+}
 
 /* convenient tests for these bits */
 static inline bool cgroup_is_dead(const struct cgroup *cgrp)
@@ -365,9 +389,11 @@
 static int cgroup_init_idr(struct cgroup_subsys *ss,
 			   struct cgroup_subsys_state *css);
 
-/* css_set_lock protects the list of css_set objects, and the
- * chain of tasks off each css_set.  Nests outside task->alloc_lock
- * due to cgroup_iter_start() */
+/*
+ * css_set_lock protects the list of css_set objects, and the chain of
+ * tasks off each css_set.  Nests outside task->alloc_lock due to
+ * css_task_iter_start().
+ */
 static DEFINE_RWLOCK(css_set_lock);
 static int css_set_count;
 
@@ -392,10 +418,12 @@
 	return key;
 }
 
-/* We don't maintain the lists running through each css_set to its
- * task until after the first call to cgroup_iter_start(). This
- * reduces the fork()/exit() overhead for people who have cgroups
- * compiled into their kernel but not actually in use */
+/*
+ * We don't maintain the lists running through each css_set to its task
+ * until after the first call to css_task_iter_start().  This reduces the
+ * fork()/exit() overhead for people who have cgroups compiled into their
+ * kernel but not actually in use.
+ */
 static int use_task_css_set_links __read_mostly;
 
 static void __put_css_set(struct css_set *cset, int taskexit)
@@ -464,7 +492,7 @@
  * @new_cgrp: cgroup that's being entered by the task
  * @template: desired set of css pointers in css_set (pre-calculated)
  *
- * Returns true if "cg" matches "old_cg" except for the hierarchy
+ * Returns true if "cset" matches "old_cset" except for the hierarchy
  * which "new_cgrp" belongs to, for which it should match "new_cgrp".
  */
 static bool compare_css_sets(struct css_set *cset,
@@ -555,7 +583,7 @@
 			/* Subsystem is in this hierarchy. So we want
 			 * the subsystem state from the new
 			 * cgroup */
-			template[i] = cgrp->subsys[i];
+			template[i] = cgroup_css(cgrp, ss);
 		} else {
 			/* Subsystem is not in this hierarchy, so we
 			 * don't want to change the subsystem state */
@@ -803,8 +831,7 @@
 
 static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
-static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
-			       unsigned long subsys_mask);
+static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask);
 static const struct inode_operations cgroup_dir_inode_operations;
 static const struct file_operations proc_cgroupstats_operations;
 
@@ -813,8 +840,7 @@
 	.capabilities	= BDI_CAP_NO_ACCT_AND_WRITEBACK,
 };
 
-static int alloc_css_id(struct cgroup_subsys *ss,
-			struct cgroup *parent, struct cgroup *child);
+static int alloc_css_id(struct cgroup_subsys_state *child_css);
 
 static struct inode *cgroup_new_inode(umode_t mode, struct super_block *sb)
 {
@@ -845,15 +871,8 @@
 static void cgroup_free_fn(struct work_struct *work)
 {
 	struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work);
-	struct cgroup_subsys *ss;
 
 	mutex_lock(&cgroup_mutex);
-	/*
-	 * Release the subsystem state objects.
-	 */
-	for_each_root_subsys(cgrp->root, ss)
-		ss->css_free(cgrp);
-
 	cgrp->root->number_of_cgroups--;
 	mutex_unlock(&cgroup_mutex);
 
@@ -864,8 +883,6 @@
 	 */
 	dput(cgrp->parent->dentry);
 
-	ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
-
 	/*
 	 * Drop the active superblock reference that we took when we
 	 * created the cgroup. This will free cgrp->root, if we are
@@ -956,27 +973,22 @@
 }
 
 /**
- * cgroup_clear_directory - selective removal of base and subsystem files
- * @dir: directory containing the files
- * @base_files: true if the base files should be removed
+ * cgroup_clear_dir - remove subsys files in a cgroup directory
+ * @cgrp: target cgroup
  * @subsys_mask: mask of the subsystem ids whose files should be removed
  */
-static void cgroup_clear_directory(struct dentry *dir, bool base_files,
-				   unsigned long subsys_mask)
+static void cgroup_clear_dir(struct cgroup *cgrp, unsigned long subsys_mask)
 {
-	struct cgroup *cgrp = __d_cgrp(dir);
 	struct cgroup_subsys *ss;
+	int i;
 
-	for_each_root_subsys(cgrp->root, ss) {
+	for_each_subsys(ss, i) {
 		struct cftype_set *set;
-		if (!test_bit(ss->subsys_id, &subsys_mask))
+
+		if (!test_bit(i, &subsys_mask))
 			continue;
 		list_for_each_entry(set, &ss->cftsets, node)
-			cgroup_addrm_files(cgrp, NULL, set->cfts, false);
-	}
-	if (base_files) {
-		while (!list_empty(&cgrp->files))
-			cgroup_rm_file(cgrp, NULL);
+			cgroup_addrm_files(cgrp, set->cfts, false);
 	}
 }
 
@@ -986,9 +998,6 @@
 static void cgroup_d_remove_dir(struct dentry *dentry)
 {
 	struct dentry *parent;
-	struct cgroupfs_root *root = dentry->d_sb->s_fs_info;
-
-	cgroup_clear_directory(dentry, true, root->subsys_mask);
 
 	parent = dentry->d_parent;
 	spin_lock(&parent->d_lock);
@@ -1009,79 +1018,84 @@
 {
 	struct cgroup *cgrp = &root->top_cgroup;
 	struct cgroup_subsys *ss;
-	int i;
+	unsigned long pinned = 0;
+	int i, ret;
 
 	BUG_ON(!mutex_is_locked(&cgroup_mutex));
 	BUG_ON(!mutex_is_locked(&cgroup_root_mutex));
 
 	/* Check that any added subsystems are currently free */
 	for_each_subsys(ss, i) {
-		unsigned long bit = 1UL << i;
-
-		if (!(bit & added_mask))
+		if (!(added_mask & (1 << i)))
 			continue;
 
+		/* is the subsystem mounted elsewhere? */
 		if (ss->root != &cgroup_dummy_root) {
-			/* Subsystem isn't free */
-			return -EBUSY;
+			ret = -EBUSY;
+			goto out_put;
 		}
+
+		/* pin the module */
+		if (!try_module_get(ss->module)) {
+			ret = -ENOENT;
+			goto out_put;
+		}
+		pinned |= 1 << i;
 	}
 
-	/* Currently we don't handle adding/removing subsystems when
-	 * any child cgroups exist. This is theoretically supportable
-	 * but involves complex error handling, so it's being left until
-	 * later */
-	if (root->number_of_cgroups > 1)
-		return -EBUSY;
+	/* subsys could be missing if unloaded between parsing and here */
+	if (added_mask != pinned) {
+		ret = -ENOENT;
+		goto out_put;
+	}
 
-	/* Process each subsystem */
+	ret = cgroup_populate_dir(cgrp, added_mask);
+	if (ret)
+		goto out_put;
+
+	/*
+	 * Nothing can fail from this point on.  Remove files for the
+	 * removed subsystems and rebind each subsystem.
+	 */
+	cgroup_clear_dir(cgrp, removed_mask);
+
 	for_each_subsys(ss, i) {
 		unsigned long bit = 1UL << i;
 
 		if (bit & added_mask) {
 			/* We're binding this subsystem to this hierarchy */
-			BUG_ON(cgrp->subsys[i]);
-			BUG_ON(!cgroup_dummy_top->subsys[i]);
-			BUG_ON(cgroup_dummy_top->subsys[i]->cgroup != cgroup_dummy_top);
+			BUG_ON(cgroup_css(cgrp, ss));
+			BUG_ON(!cgroup_css(cgroup_dummy_top, ss));
+			BUG_ON(cgroup_css(cgroup_dummy_top, ss)->cgroup != cgroup_dummy_top);
 
-			cgrp->subsys[i] = cgroup_dummy_top->subsys[i];
-			cgrp->subsys[i]->cgroup = cgrp;
+			rcu_assign_pointer(cgrp->subsys[i],
+					   cgroup_css(cgroup_dummy_top, ss));
+			cgroup_css(cgrp, ss)->cgroup = cgrp;
+
 			list_move(&ss->sibling, &root->subsys_list);
 			ss->root = root;
 			if (ss->bind)
-				ss->bind(cgrp);
+				ss->bind(cgroup_css(cgrp, ss));
 
 			/* refcount was already taken, and we're keeping it */
 			root->subsys_mask |= bit;
 		} else if (bit & removed_mask) {
 			/* We're removing this subsystem */
-			BUG_ON(cgrp->subsys[i] != cgroup_dummy_top->subsys[i]);
-			BUG_ON(cgrp->subsys[i]->cgroup != cgrp);
+			BUG_ON(cgroup_css(cgrp, ss) != cgroup_css(cgroup_dummy_top, ss));
+			BUG_ON(cgroup_css(cgrp, ss)->cgroup != cgrp);
 
 			if (ss->bind)
-				ss->bind(cgroup_dummy_top);
-			cgroup_dummy_top->subsys[i]->cgroup = cgroup_dummy_top;
-			cgrp->subsys[i] = NULL;
+				ss->bind(cgroup_css(cgroup_dummy_top, ss));
+
+			cgroup_css(cgroup_dummy_top, ss)->cgroup = cgroup_dummy_top;
+			RCU_INIT_POINTER(cgrp->subsys[i], NULL);
+
 			cgroup_subsys[i]->root = &cgroup_dummy_root;
 			list_move(&ss->sibling, &cgroup_dummy_root.subsys_list);
 
 			/* subsystem is now free - drop reference on module */
 			module_put(ss->module);
 			root->subsys_mask &= ~bit;
-		} else if (bit & root->subsys_mask) {
-			/* Subsystem state should already exist */
-			BUG_ON(!cgrp->subsys[i]);
-			/*
-			 * a refcount was taken, but we already had one, so
-			 * drop the extra reference.
-			 */
-			module_put(ss->module);
-#ifdef CONFIG_MODULE_UNLOAD
-			BUG_ON(ss->module && !module_refcount(ss->module));
-#endif
-		} else {
-			/* Subsystem state shouldn't exist */
-			BUG_ON(cgrp->subsys[i]);
 		}
 	}
 
@@ -1092,6 +1106,12 @@
 	root->flags |= CGRP_ROOT_SUBSYS_BOUND;
 
 	return 0;
+
+out_put:
+	for_each_subsys(ss, i)
+		if (pinned & (1 << i))
+			module_put(ss->module);
+	return ret;
 }
 
 static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
@@ -1142,7 +1162,6 @@
 	char *token, *o = data;
 	bool all_ss = false, one_ss = false;
 	unsigned long mask = (unsigned long)-1;
-	bool module_pin_failed = false;
 	struct cgroup_subsys *ss;
 	int i;
 
@@ -1285,52 +1304,9 @@
 	if (!opts->subsys_mask && !opts->name)
 		return -EINVAL;
 
-	/*
-	 * Grab references on all the modules we'll need, so the subsystems
-	 * don't dance around before rebind_subsystems attaches them. This may
-	 * take duplicate reference counts on a subsystem that's already used,
-	 * but rebind_subsystems handles this case.
-	 */
-	for_each_subsys(ss, i) {
-		if (!(opts->subsys_mask & (1UL << i)))
-			continue;
-		if (!try_module_get(cgroup_subsys[i]->module)) {
-			module_pin_failed = true;
-			break;
-		}
-	}
-	if (module_pin_failed) {
-		/*
-		 * oops, one of the modules was going away. this means that we
-		 * raced with a module_delete call, and to the user this is
-		 * essentially a "subsystem doesn't exist" case.
-		 */
-		for (i--; i >= 0; i--) {
-			/* drop refcounts only on the ones we took */
-			unsigned long bit = 1UL << i;
-
-			if (!(bit & opts->subsys_mask))
-				continue;
-			module_put(cgroup_subsys[i]->module);
-		}
-		return -ENOENT;
-	}
-
 	return 0;
 }
 
-static void drop_parsed_module_refcounts(unsigned long subsys_mask)
-{
-	struct cgroup_subsys *ss;
-	int i;
-
-	mutex_lock(&cgroup_mutex);
-	for_each_subsys(ss, i)
-		if (subsys_mask & (1UL << i))
-			module_put(cgroup_subsys[i]->module);
-	mutex_unlock(&cgroup_mutex);
-}
-
 static int cgroup_remount(struct super_block *sb, int *flags, char *data)
 {
 	int ret = 0;
@@ -1370,22 +1346,15 @@
 		goto out_unlock;
 	}
 
-	/*
-	 * Clear out the files of subsystems that should be removed, do
-	 * this before rebind_subsystems, since rebind_subsystems may
-	 * change this hierarchy's subsys_list.
-	 */
-	cgroup_clear_directory(cgrp->dentry, false, removed_mask);
-
-	ret = rebind_subsystems(root, added_mask, removed_mask);
-	if (ret) {
-		/* rebind_subsystems failed, re-populate the removed files */
-		cgroup_populate_dir(cgrp, false, removed_mask);
+	/* remounting is not allowed for populated hierarchies */
+	if (root->number_of_cgroups > 1) {
+		ret = -EBUSY;
 		goto out_unlock;
 	}
 
-	/* re-populate subsystem files */
-	cgroup_populate_dir(cgrp, false, added_mask);
+	ret = rebind_subsystems(root, added_mask, removed_mask);
+	if (ret)
+		goto out_unlock;
 
 	if (opts.release_agent)
 		strcpy(root->release_agent_path, opts.release_agent);
@@ -1395,8 +1364,6 @@
 	mutex_unlock(&cgroup_root_mutex);
 	mutex_unlock(&cgroup_mutex);
 	mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
-	if (ret)
-		drop_parsed_module_refcounts(opts.subsys_mask);
 	return ret;
 }
 
@@ -1416,6 +1383,7 @@
 	INIT_LIST_HEAD(&cgrp->release_list);
 	INIT_LIST_HEAD(&cgrp->pidlists);
 	mutex_init(&cgrp->pidlist_mutex);
+	cgrp->dummy_css.cgroup = cgrp;
 	INIT_LIST_HEAD(&cgrp->event_list);
 	spin_lock_init(&cgrp->event_list_lock);
 	simple_xattrs_init(&cgrp->xattrs);
@@ -1431,6 +1399,7 @@
 	cgrp->root = root;
 	RCU_INIT_POINTER(cgrp->name, &root_cgroup_name);
 	init_cgroup_housekeeping(cgrp);
+	idr_init(&root->cgroup_idr);
 }
 
 static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end)
@@ -1503,7 +1472,6 @@
 	 */
 	root->subsys_mask = opts->subsys_mask;
 	root->flags = opts->flags;
-	ida_init(&root->cgroup_ida);
 	if (opts->release_agent)
 		strcpy(root->release_agent_path, opts->release_agent);
 	if (opts->name)
@@ -1519,7 +1487,7 @@
 		/* hierarhcy ID shoulid already have been released */
 		WARN_ON_ONCE(root->hierarchy_id);
 
-		ida_destroy(&root->cgroup_ida);
+		idr_destroy(&root->cgroup_idr);
 		kfree(root);
 	}
 }
@@ -1584,7 +1552,9 @@
 	int ret = 0;
 	struct super_block *sb;
 	struct cgroupfs_root *new_root;
+	struct list_head tmp_links;
 	struct inode *inode;
+	const struct cred *cred;
 
 	/* First find the desired set of subsystems */
 	mutex_lock(&cgroup_mutex);
@@ -1600,7 +1570,7 @@
 	new_root = cgroup_root_from_opts(&opts);
 	if (IS_ERR(new_root)) {
 		ret = PTR_ERR(new_root);
-		goto drop_modules;
+		goto out_err;
 	}
 	opts.new_root = new_root;
 
@@ -1609,17 +1579,15 @@
 	if (IS_ERR(sb)) {
 		ret = PTR_ERR(sb);
 		cgroup_free_root(opts.new_root);
-		goto drop_modules;
+		goto out_err;
 	}
 
 	root = sb->s_fs_info;
 	BUG_ON(!root);
 	if (root == opts.new_root) {
 		/* We used the new root structure, so this is a new hierarchy */
-		struct list_head tmp_links;
 		struct cgroup *root_cgrp = &root->top_cgroup;
 		struct cgroupfs_root *existing_root;
-		const struct cred *cred;
 		int i;
 		struct css_set *cset;
 
@@ -1634,6 +1602,11 @@
 		mutex_lock(&cgroup_mutex);
 		mutex_lock(&cgroup_root_mutex);
 
+		root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp,
+					   0, 1, GFP_KERNEL);
+		if (root_cgrp->id < 0)
+			goto unlock_drop;
+
 		/* Check for name clashes with existing mounts */
 		ret = -EBUSY;
 		if (strlen(root->name))
@@ -1657,26 +1630,37 @@
 		if (ret)
 			goto unlock_drop;
 
+		sb->s_root->d_fsdata = root_cgrp;
+		root_cgrp->dentry = sb->s_root;
+
+		/*
+		 * We're inside get_sb() and will call lookup_one_len() to
+		 * create the root files, which doesn't work if SELinux is
+		 * in use.  The following cred dancing somehow works around
+		 * it.  See 2ce9738ba ("cgroupfs: use init_cred when
+		 * populating new cgroupfs mount") for more details.
+		 */
+		cred = override_creds(&init_cred);
+
+		ret = cgroup_addrm_files(root_cgrp, cgroup_base_files, true);
+		if (ret)
+			goto rm_base_files;
+
 		ret = rebind_subsystems(root, root->subsys_mask, 0);
-		if (ret == -EBUSY) {
-			free_cgrp_cset_links(&tmp_links);
-			goto unlock_drop;
-		}
+		if (ret)
+			goto rm_base_files;
+
+		revert_creds(cred);
+
 		/*
 		 * There must be no failure case after here, since rebinding
 		 * takes care of subsystems' refcounts, which are explicitly
 		 * dropped in the failure exit path.
 		 */
 
-		/* EBUSY should be the only error here */
-		BUG_ON(ret);
-
 		list_add(&root->root_list, &cgroup_roots);
 		cgroup_root_count++;
 
-		sb->s_root->d_fsdata = root_cgrp;
-		root->top_cgroup.dentry = sb->s_root;
-
 		/* Link the top cgroup in this hierarchy into all
 		 * the css_set objects */
 		write_lock(&css_set_lock);
@@ -1689,9 +1673,6 @@
 		BUG_ON(!list_empty(&root_cgrp->children));
 		BUG_ON(root->number_of_cgroups != 1);
 
-		cred = override_creds(&init_cred);
-		cgroup_populate_dir(root_cgrp, true, root->subsys_mask);
-		revert_creds(cred);
 		mutex_unlock(&cgroup_root_mutex);
 		mutex_unlock(&cgroup_mutex);
 		mutex_unlock(&inode->i_mutex);
@@ -1711,15 +1692,16 @@
 				pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n");
 			}
 		}
-
-		/* no subsys rebinding, so refcounts don't change */
-		drop_parsed_module_refcounts(opts.subsys_mask);
 	}
 
 	kfree(opts.release_agent);
 	kfree(opts.name);
 	return dget(sb->s_root);
 
+ rm_base_files:
+	free_cgrp_cset_links(&tmp_links);
+	cgroup_addrm_files(&root->top_cgroup, cgroup_base_files, false);
+	revert_creds(cred);
  unlock_drop:
 	cgroup_exit_root_id(root);
 	mutex_unlock(&cgroup_root_mutex);
@@ -1727,8 +1709,6 @@
 	mutex_unlock(&inode->i_mutex);
  drop_new_super:
 	deactivate_locked_super(sb);
- drop_modules:
-	drop_parsed_module_refcounts(opts.subsys_mask);
  out_err:
 	kfree(opts.release_agent);
 	kfree(opts.name);
@@ -1746,6 +1726,7 @@
 	BUG_ON(root->number_of_cgroups != 1);
 	BUG_ON(!list_empty(&cgrp->children));
 
+	mutex_lock(&cgrp->dentry->d_inode->i_mutex);
 	mutex_lock(&cgroup_mutex);
 	mutex_lock(&cgroup_root_mutex);
 
@@ -1778,6 +1759,7 @@
 
 	mutex_unlock(&cgroup_root_mutex);
 	mutex_unlock(&cgroup_mutex);
+	mutex_unlock(&cgrp->dentry->d_inode->i_mutex);
 
 	simple_xattrs_free(&cgrp->xattrs);
 
@@ -1889,7 +1871,7 @@
 struct task_and_cgroup {
 	struct task_struct	*task;
 	struct cgroup		*cgrp;
-	struct css_set		*cg;
+	struct css_set		*cset;
 };
 
 struct cgroup_taskset {
@@ -1939,18 +1921,20 @@
 EXPORT_SYMBOL_GPL(cgroup_taskset_next);
 
 /**
- * cgroup_taskset_cur_cgroup - return the matching cgroup for the current task
+ * cgroup_taskset_cur_css - return the matching css for the current task
  * @tset: taskset of interest
+ * @subsys_id: the ID of the target subsystem
  *
- * Return the cgroup for the current (last returned) task of @tset.  This
- * function must be preceded by either cgroup_taskset_first() or
- * cgroup_taskset_next().
+ * Return the css for the current (last returned) task of @tset for
+ * subsystem specified by @subsys_id.  This function must be preceded by
+ * either cgroup_taskset_first() or cgroup_taskset_next().
  */
-struct cgroup *cgroup_taskset_cur_cgroup(struct cgroup_taskset *tset)
+struct cgroup_subsys_state *cgroup_taskset_cur_css(struct cgroup_taskset *tset,
+						   int subsys_id)
 {
-	return tset->cur_cgrp;
+	return cgroup_css(tset->cur_cgrp, cgroup_subsys[subsys_id]);
 }
-EXPORT_SYMBOL_GPL(cgroup_taskset_cur_cgroup);
+EXPORT_SYMBOL_GPL(cgroup_taskset_cur_css);
 
 /**
  * cgroup_taskset_size - return the number of tasks in taskset
@@ -2089,8 +2073,10 @@
 	 * step 1: check that we can legitimately attach to the cgroup.
 	 */
 	for_each_root_subsys(root, ss) {
+		struct cgroup_subsys_state *css = cgroup_css(cgrp, ss);
+
 		if (ss->can_attach) {
-			retval = ss->can_attach(cgrp, &tset);
+			retval = ss->can_attach(css, &tset);
 			if (retval) {
 				failed_ss = ss;
 				goto out_cancel_attach;
@@ -2107,8 +2093,8 @@
 
 		tc = flex_array_get(group, i);
 		old_cset = task_css_set(tc->task);
-		tc->cg = find_css_set(old_cset, cgrp);
-		if (!tc->cg) {
+		tc->cset = find_css_set(old_cset, cgrp);
+		if (!tc->cset) {
 			retval = -ENOMEM;
 			goto out_put_css_set_refs;
 		}
@@ -2121,7 +2107,7 @@
 	 */
 	for (i = 0; i < group_size; i++) {
 		tc = flex_array_get(group, i);
-		cgroup_task_migrate(tc->cgrp, tc->task, tc->cg);
+		cgroup_task_migrate(tc->cgrp, tc->task, tc->cset);
 	}
 	/* nothing is sensitive to fork() after this point. */
 
@@ -2129,8 +2115,10 @@
 	 * step 4: do subsystem attach callbacks.
 	 */
 	for_each_root_subsys(root, ss) {
+		struct cgroup_subsys_state *css = cgroup_css(cgrp, ss);
+
 		if (ss->attach)
-			ss->attach(cgrp, &tset);
+			ss->attach(css, &tset);
 	}
 
 	/*
@@ -2141,18 +2129,20 @@
 	if (retval) {
 		for (i = 0; i < group_size; i++) {
 			tc = flex_array_get(group, i);
-			if (!tc->cg)
+			if (!tc->cset)
 				break;
-			put_css_set(tc->cg);
+			put_css_set(tc->cset);
 		}
 	}
 out_cancel_attach:
 	if (retval) {
 		for_each_root_subsys(root, ss) {
+			struct cgroup_subsys_state *css = cgroup_css(cgrp, ss);
+
 			if (ss == failed_ss)
 				break;
 			if (ss->cancel_attach)
-				ss->cancel_attach(cgrp, &tset);
+				ss->cancel_attach(css, &tset);
 		}
 	}
 out_free_group_list:
@@ -2253,9 +2243,9 @@
 
 	mutex_lock(&cgroup_mutex);
 	for_each_active_root(root) {
-		struct cgroup *from_cg = task_cgroup_from_root(from, root);
+		struct cgroup *from_cgrp = task_cgroup_from_root(from, root);
 
-		retval = cgroup_attach_task(from_cg, tsk, false);
+		retval = cgroup_attach_task(from_cgrp, tsk, false);
 		if (retval)
 			break;
 	}
@@ -2265,34 +2255,38 @@
 }
 EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
 
-static int cgroup_tasks_write(struct cgroup *cgrp, struct cftype *cft, u64 pid)
+static int cgroup_tasks_write(struct cgroup_subsys_state *css,
+			      struct cftype *cft, u64 pid)
 {
-	return attach_task_by_pid(cgrp, pid, false);
+	return attach_task_by_pid(css->cgroup, pid, false);
 }
 
-static int cgroup_procs_write(struct cgroup *cgrp, struct cftype *cft, u64 tgid)
+static int cgroup_procs_write(struct cgroup_subsys_state *css,
+			      struct cftype *cft, u64 tgid)
 {
-	return attach_task_by_pid(cgrp, tgid, true);
+	return attach_task_by_pid(css->cgroup, tgid, true);
 }
 
-static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
-				      const char *buffer)
+static int cgroup_release_agent_write(struct cgroup_subsys_state *css,
+				      struct cftype *cft, const char *buffer)
 {
-	BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);
+	BUILD_BUG_ON(sizeof(css->cgroup->root->release_agent_path) < PATH_MAX);
 	if (strlen(buffer) >= PATH_MAX)
 		return -EINVAL;
-	if (!cgroup_lock_live_group(cgrp))
+	if (!cgroup_lock_live_group(css->cgroup))
 		return -ENODEV;
 	mutex_lock(&cgroup_root_mutex);
-	strcpy(cgrp->root->release_agent_path, buffer);
+	strcpy(css->cgroup->root->release_agent_path, buffer);
 	mutex_unlock(&cgroup_root_mutex);
 	mutex_unlock(&cgroup_mutex);
 	return 0;
 }
 
-static int cgroup_release_agent_show(struct cgroup *cgrp, struct cftype *cft,
-				     struct seq_file *seq)
+static int cgroup_release_agent_show(struct cgroup_subsys_state *css,
+				     struct cftype *cft, struct seq_file *seq)
 {
+	struct cgroup *cgrp = css->cgroup;
+
 	if (!cgroup_lock_live_group(cgrp))
 		return -ENODEV;
 	seq_puts(seq, cgrp->root->release_agent_path);
@@ -2301,20 +2295,20 @@
 	return 0;
 }
 
-static int cgroup_sane_behavior_show(struct cgroup *cgrp, struct cftype *cft,
-				     struct seq_file *seq)
+static int cgroup_sane_behavior_show(struct cgroup_subsys_state *css,
+				     struct cftype *cft, struct seq_file *seq)
 {
-	seq_printf(seq, "%d\n", cgroup_sane_behavior(cgrp));
+	seq_printf(seq, "%d\n", cgroup_sane_behavior(css->cgroup));
 	return 0;
 }
 
 /* A buffer size big enough for numbers or short strings */
 #define CGROUP_LOCAL_BUFFER_SIZE 64
 
-static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft,
-				struct file *file,
-				const char __user *userbuf,
-				size_t nbytes, loff_t *unused_ppos)
+static ssize_t cgroup_write_X64(struct cgroup_subsys_state *css,
+				struct cftype *cft, struct file *file,
+				const char __user *userbuf, size_t nbytes,
+				loff_t *unused_ppos)
 {
 	char buffer[CGROUP_LOCAL_BUFFER_SIZE];
 	int retval = 0;
@@ -2332,22 +2326,22 @@
 		u64 val = simple_strtoull(strstrip(buffer), &end, 0);
 		if (*end)
 			return -EINVAL;
-		retval = cft->write_u64(cgrp, cft, val);
+		retval = cft->write_u64(css, cft, val);
 	} else {
 		s64 val = simple_strtoll(strstrip(buffer), &end, 0);
 		if (*end)
 			return -EINVAL;
-		retval = cft->write_s64(cgrp, cft, val);
+		retval = cft->write_s64(css, cft, val);
 	}
 	if (!retval)
 		retval = nbytes;
 	return retval;
 }
 
-static ssize_t cgroup_write_string(struct cgroup *cgrp, struct cftype *cft,
-				   struct file *file,
-				   const char __user *userbuf,
-				   size_t nbytes, loff_t *unused_ppos)
+static ssize_t cgroup_write_string(struct cgroup_subsys_state *css,
+				   struct cftype *cft, struct file *file,
+				   const char __user *userbuf, size_t nbytes,
+				   loff_t *unused_ppos)
 {
 	char local_buffer[CGROUP_LOCAL_BUFFER_SIZE];
 	int retval = 0;
@@ -2370,7 +2364,7 @@
 	}
 
 	buffer[nbytes] = 0;     /* nul-terminate */
-	retval = cft->write_string(cgrp, cft, strstrip(buffer));
+	retval = cft->write_string(css, cft, strstrip(buffer));
 	if (!retval)
 		retval = nbytes;
 out:
@@ -2380,65 +2374,60 @@
 }
 
 static ssize_t cgroup_file_write(struct file *file, const char __user *buf,
-						size_t nbytes, loff_t *ppos)
+				 size_t nbytes, loff_t *ppos)
 {
+	struct cfent *cfe = __d_cfe(file->f_dentry);
 	struct cftype *cft = __d_cft(file->f_dentry);
-	struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
+	struct cgroup_subsys_state *css = cfe->css;
 
-	if (cgroup_is_dead(cgrp))
-		return -ENODEV;
 	if (cft->write)
-		return cft->write(cgrp, cft, file, buf, nbytes, ppos);
+		return cft->write(css, cft, file, buf, nbytes, ppos);
 	if (cft->write_u64 || cft->write_s64)
-		return cgroup_write_X64(cgrp, cft, file, buf, nbytes, ppos);
+		return cgroup_write_X64(css, cft, file, buf, nbytes, ppos);
 	if (cft->write_string)
-		return cgroup_write_string(cgrp, cft, file, buf, nbytes, ppos);
+		return cgroup_write_string(css, cft, file, buf, nbytes, ppos);
 	if (cft->trigger) {
-		int ret = cft->trigger(cgrp, (unsigned int)cft->private);
+		int ret = cft->trigger(css, (unsigned int)cft->private);
 		return ret ? ret : nbytes;
 	}
 	return -EINVAL;
 }
 
-static ssize_t cgroup_read_u64(struct cgroup *cgrp, struct cftype *cft,
-			       struct file *file,
-			       char __user *buf, size_t nbytes,
-			       loff_t *ppos)
+static ssize_t cgroup_read_u64(struct cgroup_subsys_state *css,
+			       struct cftype *cft, struct file *file,
+			       char __user *buf, size_t nbytes, loff_t *ppos)
 {
 	char tmp[CGROUP_LOCAL_BUFFER_SIZE];
-	u64 val = cft->read_u64(cgrp, cft);
+	u64 val = cft->read_u64(css, cft);
 	int len = sprintf(tmp, "%llu\n", (unsigned long long) val);
 
 	return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
 }
 
-static ssize_t cgroup_read_s64(struct cgroup *cgrp, struct cftype *cft,
-			       struct file *file,
-			       char __user *buf, size_t nbytes,
-			       loff_t *ppos)
+static ssize_t cgroup_read_s64(struct cgroup_subsys_state *css,
+			       struct cftype *cft, struct file *file,
+			       char __user *buf, size_t nbytes, loff_t *ppos)
 {
 	char tmp[CGROUP_LOCAL_BUFFER_SIZE];
-	s64 val = cft->read_s64(cgrp, cft);
+	s64 val = cft->read_s64(css, cft);
 	int len = sprintf(tmp, "%lld\n", (long long) val);
 
 	return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
 }
 
 static ssize_t cgroup_file_read(struct file *file, char __user *buf,
-				   size_t nbytes, loff_t *ppos)
+				size_t nbytes, loff_t *ppos)
 {
+	struct cfent *cfe = __d_cfe(file->f_dentry);
 	struct cftype *cft = __d_cft(file->f_dentry);
-	struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
-
-	if (cgroup_is_dead(cgrp))
-		return -ENODEV;
+	struct cgroup_subsys_state *css = cfe->css;
 
 	if (cft->read)
-		return cft->read(cgrp, cft, file, buf, nbytes, ppos);
+		return cft->read(css, cft, file, buf, nbytes, ppos);
 	if (cft->read_u64)
-		return cgroup_read_u64(cgrp, cft, file, buf, nbytes, ppos);
+		return cgroup_read_u64(css, cft, file, buf, nbytes, ppos);
 	if (cft->read_s64)
-		return cgroup_read_s64(cgrp, cft, file, buf, nbytes, ppos);
+		return cgroup_read_s64(css, cft, file, buf, nbytes, ppos);
 	return -EINVAL;
 }
 
@@ -2447,11 +2436,6 @@
  * supports string->u64 maps, but can be extended in future.
  */
 
-struct cgroup_seqfile_state {
-	struct cftype *cft;
-	struct cgroup *cgroup;
-};
-
 static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
 {
 	struct seq_file *sf = cb->state;
@@ -2460,69 +2444,86 @@
 
 static int cgroup_seqfile_show(struct seq_file *m, void *arg)
 {
-	struct cgroup_seqfile_state *state = m->private;
-	struct cftype *cft = state->cft;
+	struct cfent *cfe = m->private;
+	struct cftype *cft = cfe->type;
+	struct cgroup_subsys_state *css = cfe->css;
+
 	if (cft->read_map) {
 		struct cgroup_map_cb cb = {
 			.fill = cgroup_map_add,
 			.state = m,
 		};
-		return cft->read_map(state->cgroup, cft, &cb);
+		return cft->read_map(css, cft, &cb);
 	}
-	return cft->read_seq_string(state->cgroup, cft, m);
-}
-
-static int cgroup_seqfile_release(struct inode *inode, struct file *file)
-{
-	struct seq_file *seq = file->private_data;
-	kfree(seq->private);
-	return single_release(inode, file);
+	return cft->read_seq_string(css, cft, m);
 }
 
 static const struct file_operations cgroup_seqfile_operations = {
 	.read = seq_read,
 	.write = cgroup_file_write,
 	.llseek = seq_lseek,
-	.release = cgroup_seqfile_release,
+	.release = single_release,
 };
 
 static int cgroup_file_open(struct inode *inode, struct file *file)
 {
+	struct cfent *cfe = __d_cfe(file->f_dentry);
+	struct cftype *cft = __d_cft(file->f_dentry);
+	struct cgroup *cgrp = __d_cgrp(cfe->dentry->d_parent);
+	struct cgroup_subsys_state *css;
 	int err;
-	struct cftype *cft;
 
 	err = generic_file_open(inode, file);
 	if (err)
 		return err;
-	cft = __d_cft(file->f_dentry);
+
+	/*
+	 * If the file belongs to a subsystem, pin the css.  Will be
+	 * unpinned either on open failure or release.  This ensures that
+	 * @css stays alive for all file operations.
+	 */
+	rcu_read_lock();
+	css = cgroup_css(cgrp, cft->ss);
+	if (cft->ss && !css_tryget(css))
+		css = NULL;
+	rcu_read_unlock();
+
+	if (!css)
+		return -ENODEV;
+
+	/*
+	 * @cfe->css is used by read/write/close to determine the
+	 * associated css.  @file->private_data would be a better place but
+	 * that's already used by seqfile.  Multiple accessors may use it
+	 * simultaneously which is okay as the association never changes.
+	 */
+	WARN_ON_ONCE(cfe->css && cfe->css != css);
+	cfe->css = css;
 
 	if (cft->read_map || cft->read_seq_string) {
-		struct cgroup_seqfile_state *state;
-
-		state = kzalloc(sizeof(*state), GFP_USER);
-		if (!state)
-			return -ENOMEM;
-
-		state->cft = cft;
-		state->cgroup = __d_cgrp(file->f_dentry->d_parent);
 		file->f_op = &cgroup_seqfile_operations;
-		err = single_open(file, cgroup_seqfile_show, state);
-		if (err < 0)
-			kfree(state);
-	} else if (cft->open)
+		err = single_open(file, cgroup_seqfile_show, cfe);
+	} else if (cft->open) {
 		err = cft->open(inode, file);
-	else
-		err = 0;
+	}
 
+	if (css->ss && err)
+		css_put(css);
 	return err;
 }
 
 static int cgroup_file_release(struct inode *inode, struct file *file)
 {
+	struct cfent *cfe = __d_cfe(file->f_dentry);
 	struct cftype *cft = __d_cft(file->f_dentry);
+	struct cgroup_subsys_state *css = cfe->css;
+	int ret = 0;
+
 	if (cft->release)
-		return cft->release(inode, file);
-	return 0;
+		ret = cft->release(inode, file);
+	if (css->ss)
+		css_put(css);
+	return ret;
 }
 
 /*
@@ -2736,8 +2737,7 @@
 	return mode;
 }
 
-static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
-			   struct cftype *cft)
+static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft)
 {
 	struct dentry *dir = cgrp->dentry;
 	struct cgroup *parent = __d_cgrp(dir);
@@ -2747,8 +2747,9 @@
 	umode_t mode;
 	char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
 
-	if (subsys && !(cgrp->root->flags & CGRP_ROOT_NOPREFIX)) {
-		strcpy(name, subsys->name);
+	if (cft->ss && !(cft->flags & CFTYPE_NO_PREFIX) &&
+	    !(cgrp->root->flags & CGRP_ROOT_NOPREFIX)) {
+		strcpy(name, cft->ss->name);
 		strcat(name, ".");
 	}
 	strcat(name, cft->name);
@@ -2782,11 +2783,25 @@
 	return error;
 }
 
-static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
-			      struct cftype cfts[], bool is_add)
+/**
+ * cgroup_addrm_files - add or remove files to a cgroup directory
+ * @cgrp: the target cgroup
+ * @cfts: array of cftypes to be added
+ * @is_add: whether to add or remove
+ *
+ * Depending on @is_add, add or remove files defined by @cfts on @cgrp.
+ * For removals, this function never fails.  If addition fails, this
+ * function doesn't remove files already added.  The caller is responsible
+ * for cleaning up.
+ */
+static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[],
+			      bool is_add)
 {
 	struct cftype *cft;
-	int err, ret = 0;
+	int ret;
+
+	lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex);
+	lockdep_assert_held(&cgroup_mutex);
 
 	for (cft = cfts; cft->name[0] != '\0'; cft++) {
 		/* does cft->flags tell us to skip this file on @cgrp? */
@@ -2798,16 +2813,17 @@
 			continue;
 
 		if (is_add) {
-			err = cgroup_add_file(cgrp, subsys, cft);
-			if (err)
+			ret = cgroup_add_file(cgrp, cft);
+			if (ret) {
 				pr_warn("cgroup_addrm_files: failed to add %s, err=%d\n",
-					cft->name, err);
-			ret = err;
+					cft->name, ret);
+				return ret;
+			}
 		} else {
 			cgroup_rm_file(cgrp, cft);
 		}
 	}
-	return ret;
+	return 0;
 }
 
 static void cgroup_cfts_prepare(void)
@@ -2816,28 +2832,30 @@
 	/*
 	 * Thanks to the entanglement with vfs inode locking, we can't walk
 	 * the existing cgroups under cgroup_mutex and create files.
-	 * Instead, we use cgroup_for_each_descendant_pre() and drop RCU
-	 * read lock before calling cgroup_addrm_files().
+	 * Instead, we use css_for_each_descendant_pre() and drop RCU read
+	 * lock before calling cgroup_addrm_files().
 	 */
 	mutex_lock(&cgroup_mutex);
 }
 
-static void cgroup_cfts_commit(struct cgroup_subsys *ss,
-			       struct cftype *cfts, bool is_add)
+static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
 	__releases(&cgroup_mutex)
 {
 	LIST_HEAD(pending);
-	struct cgroup *cgrp, *root = &ss->root->top_cgroup;
+	struct cgroup_subsys *ss = cfts[0].ss;
+	struct cgroup *root = &ss->root->top_cgroup;
 	struct super_block *sb = ss->root->sb;
 	struct dentry *prev = NULL;
 	struct inode *inode;
+	struct cgroup_subsys_state *css;
 	u64 update_before;
+	int ret = 0;
 
 	/* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
 	if (!cfts || ss->root == &cgroup_dummy_root ||
 	    !atomic_inc_not_zero(&sb->s_active)) {
 		mutex_unlock(&cgroup_mutex);
-		return;
+		return 0;
 	}
 
 	/*
@@ -2849,17 +2867,11 @@
 
 	mutex_unlock(&cgroup_mutex);
 
-	/* @root always needs to be updated */
-	inode = root->dentry->d_inode;
-	mutex_lock(&inode->i_mutex);
-	mutex_lock(&cgroup_mutex);
-	cgroup_addrm_files(root, ss, cfts, is_add);
-	mutex_unlock(&cgroup_mutex);
-	mutex_unlock(&inode->i_mutex);
-
 	/* add/rm files for all cgroups created before */
 	rcu_read_lock();
-	cgroup_for_each_descendant_pre(cgrp, root) {
+	css_for_each_descendant_pre(css, cgroup_css(root, ss)) {
+		struct cgroup *cgrp = css->cgroup;
+
 		if (cgroup_is_dead(cgrp))
 			continue;
 
@@ -2873,15 +2885,18 @@
 		mutex_lock(&inode->i_mutex);
 		mutex_lock(&cgroup_mutex);
 		if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
-			cgroup_addrm_files(cgrp, ss, cfts, is_add);
+			ret = cgroup_addrm_files(cgrp, cfts, is_add);
 		mutex_unlock(&cgroup_mutex);
 		mutex_unlock(&inode->i_mutex);
 
 		rcu_read_lock();
+		if (ret)
+			break;
 	}
 	rcu_read_unlock();
 	dput(prev);
 	deactivate_super(sb);
+	return ret;
 }
 
 /**
@@ -2901,49 +2916,56 @@
 int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 {
 	struct cftype_set *set;
+	struct cftype *cft;
+	int ret;
 
 	set = kzalloc(sizeof(*set), GFP_KERNEL);
 	if (!set)
 		return -ENOMEM;
 
+	for (cft = cfts; cft->name[0] != '\0'; cft++)
+		cft->ss = ss;
+
 	cgroup_cfts_prepare();
 	set->cfts = cfts;
 	list_add_tail(&set->node, &ss->cftsets);
-	cgroup_cfts_commit(ss, cfts, true);
-
-	return 0;
+	ret = cgroup_cfts_commit(cfts, true);
+	if (ret)
+		cgroup_rm_cftypes(cfts);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
 
 /**
  * cgroup_rm_cftypes - remove an array of cftypes from a subsystem
- * @ss: target cgroup subsystem
  * @cfts: zero-length name terminated array of cftypes
  *
- * Unregister @cfts from @ss.  Files described by @cfts are removed from
- * all existing cgroups to which @ss is attached and all future cgroups
- * won't have them either.  This function can be called anytime whether @ss
- * is attached or not.
+ * Unregister @cfts.  Files described by @cfts are removed from all
+ * existing cgroups and all future cgroups won't have them either.  This
+ * function can be called anytime whether @cfts' subsys is attached or not.
  *
  * Returns 0 on successful unregistration, -ENOENT if @cfts is not
- * registered with @ss.
+ * registered.
  */
-int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
+int cgroup_rm_cftypes(struct cftype *cfts)
 {
 	struct cftype_set *set;
 
+	if (!cfts || !cfts[0].ss)
+		return -ENOENT;
+
 	cgroup_cfts_prepare();
 
-	list_for_each_entry(set, &ss->cftsets, node) {
+	list_for_each_entry(set, &cfts[0].ss->cftsets, node) {
 		if (set->cfts == cfts) {
 			list_del(&set->node);
 			kfree(set);
-			cgroup_cfts_commit(ss, cfts, false);
+			cgroup_cfts_commit(cfts, false);
 			return 0;
 		}
 	}
 
-	cgroup_cfts_commit(ss, NULL, false);
+	cgroup_cfts_commit(NULL, false);
 	return -ENOENT;
 }
 
@@ -2966,34 +2988,10 @@
 }
 
 /*
- * Advance a list_head iterator.  The iterator should be positioned at
- * the start of a css_set
- */
-static void cgroup_advance_iter(struct cgroup *cgrp, struct cgroup_iter *it)
-{
-	struct list_head *l = it->cset_link;
-	struct cgrp_cset_link *link;
-	struct css_set *cset;
-
-	/* Advance to the next non-empty css_set */
-	do {
-		l = l->next;
-		if (l == &cgrp->cset_links) {
-			it->cset_link = NULL;
-			return;
-		}
-		link = list_entry(l, struct cgrp_cset_link, cset_link);
-		cset = link->cset;
-	} while (list_empty(&cset->tasks));
-	it->cset_link = l;
-	it->task = cset->tasks.next;
-}
-
-/*
- * To reduce the fork() overhead for systems that are not actually
- * 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().
+ * To reduce the fork() overhead for systems that are not actually 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 css_task_iter_start().
  */
 static void cgroup_enable_task_cg_lists(void)
 {
@@ -3024,16 +3022,21 @@
 }
 
 /**
- * cgroup_next_sibling - find the next sibling of a given cgroup
- * @pos: the current cgroup
+ * css_next_child - find the next child of a given css
+ * @pos_css: the current position (%NULL to initiate traversal)
+ * @parent_css: css whose children to walk
  *
- * This function returns the next sibling of @pos and should be called
- * under RCU read lock.  The only requirement is that @pos is accessible.
- * The next sibling is guaranteed to be returned regardless of @pos's
- * state.
+ * This function returns the next child of @parent_css and should be called
+ * under RCU read lock.  The only requirement is that @parent_css and
+ * @pos_css are accessible.  The next sibling is guaranteed to be returned
+ * regardless of their states.
  */
-struct cgroup *cgroup_next_sibling(struct cgroup *pos)
+struct cgroup_subsys_state *
+css_next_child(struct cgroup_subsys_state *pos_css,
+	       struct cgroup_subsys_state *parent_css)
 {
+	struct cgroup *pos = pos_css ? pos_css->cgroup : NULL;
+	struct cgroup *cgrp = parent_css->cgroup;
 	struct cgroup *next;
 
 	WARN_ON_ONCE(!rcu_read_lock_held());
@@ -3048,78 +3051,81 @@
 	 * safe to dereference from this RCU critical section.  If
 	 * ->sibling.next is inaccessible, cgroup_is_dead() is guaranteed
 	 * to be visible as %true here.
+	 *
+	 * If @pos is dead, its next pointer can't be dereferenced;
+	 * however, as each cgroup is given a monotonically increasing
+	 * unique serial number and always appended to the sibling list,
+	 * the next one can be found by walking the parent's children until
+	 * we see a cgroup with higher serial number than @pos's.  While
+	 * this path can be slower, it's taken only when either the current
+	 * cgroup is removed or iteration and removal race.
 	 */
-	if (likely(!cgroup_is_dead(pos))) {
+	if (!pos) {
+		next = list_entry_rcu(cgrp->children.next, struct cgroup, sibling);
+	} else if (likely(!cgroup_is_dead(pos))) {
 		next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
-		if (&next->sibling != &pos->parent->children)
-			return next;
-		return NULL;
+	} else {
+		list_for_each_entry_rcu(next, &cgrp->children, sibling)
+			if (next->serial_nr > pos->serial_nr)
+				break;
 	}
 
-	/*
-	 * Can't dereference the next pointer.  Each cgroup is given a
-	 * monotonically increasing unique serial number and always
-	 * appended to the sibling list, so the next one can be found by
-	 * walking the parent's children until we see a cgroup with higher
-	 * serial number than @pos's.
-	 *
-	 * While this path can be slow, it's taken only when either the
-	 * current cgroup is removed or iteration and removal race.
-	 */
-	list_for_each_entry_rcu(next, &pos->parent->children, sibling)
-		if (next->serial_nr > pos->serial_nr)
-			return next;
-	return NULL;
+	if (&next->sibling == &cgrp->children)
+		return NULL;
+
+	return cgroup_css(next, parent_css->ss);
 }
-EXPORT_SYMBOL_GPL(cgroup_next_sibling);
+EXPORT_SYMBOL_GPL(css_next_child);
 
 /**
- * cgroup_next_descendant_pre - find the next descendant for pre-order walk
+ * css_next_descendant_pre - find the next descendant for pre-order walk
  * @pos: the current position (%NULL to initiate traversal)
- * @cgroup: cgroup whose descendants to walk
+ * @root: css whose descendants to walk
  *
- * To be used by cgroup_for_each_descendant_pre().  Find the next
- * descendant to visit for pre-order traversal of @cgroup's descendants.
+ * To be used by css_for_each_descendant_pre().  Find the next descendant
+ * to visit for pre-order traversal of @root's descendants.  @root is
+ * included in the iteration and the first node to be visited.
  *
  * While this function requires RCU read locking, it doesn't require the
  * whole traversal to be contained in a single RCU critical section.  This
  * function will return the correct next descendant as long as both @pos
- * and @cgroup are accessible and @pos is a descendant of @cgroup.
+ * and @root are accessible and @pos is a descendant of @root.
  */
-struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
-					  struct cgroup *cgroup)
+struct cgroup_subsys_state *
+css_next_descendant_pre(struct cgroup_subsys_state *pos,
+			struct cgroup_subsys_state *root)
 {
-	struct cgroup *next;
+	struct cgroup_subsys_state *next;
 
 	WARN_ON_ONCE(!rcu_read_lock_held());
 
-	/* if first iteration, pretend we just visited @cgroup */
+	/* if first iteration, visit @root */
 	if (!pos)
-		pos = cgroup;
+		return root;
 
 	/* visit the first child if exists */
-	next = list_first_or_null_rcu(&pos->children, struct cgroup, sibling);
+	next = css_next_child(NULL, pos);
 	if (next)
 		return next;
 
 	/* no child, visit my or the closest ancestor's next sibling */
-	while (pos != cgroup) {
-		next = cgroup_next_sibling(pos);
+	while (pos != root) {
+		next = css_next_child(pos, css_parent(pos));
 		if (next)
 			return next;
-		pos = pos->parent;
+		pos = css_parent(pos);
 	}
 
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(cgroup_next_descendant_pre);
+EXPORT_SYMBOL_GPL(css_next_descendant_pre);
 
 /**
- * cgroup_rightmost_descendant - return the rightmost descendant of a cgroup
- * @pos: cgroup of interest
+ * css_rightmost_descendant - return the rightmost descendant of a css
+ * @pos: css of interest
  *
- * Return the rightmost descendant of @pos.  If there's no descendant,
- * @pos is returned.  This can be used during pre-order traversal to skip
+ * Return the rightmost descendant of @pos.  If there's no descendant, @pos
+ * is returned.  This can be used during pre-order traversal to skip
  * subtree of @pos.
  *
  * While this function requires RCU read locking, it doesn't require the
@@ -3127,9 +3133,10 @@
  * function will return the correct rightmost descendant as long as @pos is
  * accessible.
  */
-struct cgroup *cgroup_rightmost_descendant(struct cgroup *pos)
+struct cgroup_subsys_state *
+css_rightmost_descendant(struct cgroup_subsys_state *pos)
 {
-	struct cgroup *last, *tmp;
+	struct cgroup_subsys_state *last, *tmp;
 
 	WARN_ON_ONCE(!rcu_read_lock_held());
 
@@ -3137,82 +3144,138 @@
 		last = pos;
 		/* ->prev isn't RCU safe, walk ->next till the end */
 		pos = NULL;
-		list_for_each_entry_rcu(tmp, &last->children, sibling)
+		css_for_each_child(tmp, last)
 			pos = tmp;
 	} while (pos);
 
 	return last;
 }
-EXPORT_SYMBOL_GPL(cgroup_rightmost_descendant);
+EXPORT_SYMBOL_GPL(css_rightmost_descendant);
 
-static struct cgroup *cgroup_leftmost_descendant(struct cgroup *pos)
+static struct cgroup_subsys_state *
+css_leftmost_descendant(struct cgroup_subsys_state *pos)
 {
-	struct cgroup *last;
+	struct cgroup_subsys_state *last;
 
 	do {
 		last = pos;
-		pos = list_first_or_null_rcu(&pos->children, struct cgroup,
-					     sibling);
+		pos = css_next_child(NULL, pos);
 	} while (pos);
 
 	return last;
 }
 
 /**
- * cgroup_next_descendant_post - find the next descendant for post-order walk
+ * css_next_descendant_post - find the next descendant for post-order walk
  * @pos: the current position (%NULL to initiate traversal)
- * @cgroup: cgroup whose descendants to walk
+ * @root: css whose descendants to walk
  *
- * To be used by cgroup_for_each_descendant_post().  Find the next
- * descendant to visit for post-order traversal of @cgroup's descendants.
+ * To be used by css_for_each_descendant_post().  Find the next descendant
+ * to visit for post-order traversal of @root's descendants.  @root is
+ * included in the iteration and the last node to be visited.
  *
  * While this function requires RCU read locking, it doesn't require the
  * whole traversal to be contained in a single RCU critical section.  This
  * function will return the correct next descendant as long as both @pos
  * and @cgroup are accessible and @pos is a descendant of @cgroup.
  */
-struct cgroup *cgroup_next_descendant_post(struct cgroup *pos,
-					   struct cgroup *cgroup)
+struct cgroup_subsys_state *
+css_next_descendant_post(struct cgroup_subsys_state *pos,
+			 struct cgroup_subsys_state *root)
 {
-	struct cgroup *next;
+	struct cgroup_subsys_state *next;
 
 	WARN_ON_ONCE(!rcu_read_lock_held());
 
 	/* if first iteration, visit the leftmost descendant */
 	if (!pos) {
-		next = cgroup_leftmost_descendant(cgroup);
-		return next != cgroup ? next : NULL;
+		next = css_leftmost_descendant(root);
+		return next != root ? next : NULL;
 	}
 
+	/* if we visited @root, we're done */
+	if (pos == root)
+		return NULL;
+
 	/* if there's an unvisited sibling, visit its leftmost descendant */
-	next = cgroup_next_sibling(pos);
+	next = css_next_child(pos, css_parent(pos));
 	if (next)
-		return cgroup_leftmost_descendant(next);
+		return css_leftmost_descendant(next);
 
 	/* no sibling left, visit parent */
-	next = pos->parent;
-	return next != cgroup ? next : NULL;
+	return css_parent(pos);
 }
-EXPORT_SYMBOL_GPL(cgroup_next_descendant_post);
+EXPORT_SYMBOL_GPL(css_next_descendant_post);
 
-void cgroup_iter_start(struct cgroup *cgrp, struct cgroup_iter *it)
+/**
+ * css_advance_task_iter - advance a task itererator to the next css_set
+ * @it: the iterator to advance
+ *
+ * Advance @it to the next css_set to walk.
+ */
+static void css_advance_task_iter(struct css_task_iter *it)
+{
+	struct list_head *l = it->cset_link;
+	struct cgrp_cset_link *link;
+	struct css_set *cset;
+
+	/* Advance to the next non-empty css_set */
+	do {
+		l = l->next;
+		if (l == &it->origin_css->cgroup->cset_links) {
+			it->cset_link = NULL;
+			return;
+		}
+		link = list_entry(l, struct cgrp_cset_link, cset_link);
+		cset = link->cset;
+	} while (list_empty(&cset->tasks));
+	it->cset_link = l;
+	it->task = cset->tasks.next;
+}
+
+/**
+ * css_task_iter_start - initiate task iteration
+ * @css: the css to walk tasks of
+ * @it: the task iterator to use
+ *
+ * Initiate iteration through the tasks of @css.  The caller can call
+ * css_task_iter_next() to walk through the tasks until the function
+ * returns NULL.  On completion of iteration, css_task_iter_end() must be
+ * called.
+ *
+ * Note that this function acquires a lock which is released when the
+ * iteration finishes.  The caller can't sleep while iteration is in
+ * progress.
+ */
+void css_task_iter_start(struct cgroup_subsys_state *css,
+			 struct css_task_iter *it)
 	__acquires(css_set_lock)
 {
 	/*
-	 * The first time anyone tries to iterate across a cgroup,
-	 * we need to enable the list linking each css_set to its
-	 * tasks, and fix up all existing tasks.
+	 * The first time anyone tries to iterate across a css, we need to
+	 * enable the list linking each css_set to its tasks, and fix up
+	 * all existing tasks.
 	 */
 	if (!use_task_css_set_links)
 		cgroup_enable_task_cg_lists();
 
 	read_lock(&css_set_lock);
-	it->cset_link = &cgrp->cset_links;
-	cgroup_advance_iter(cgrp, it);
+
+	it->origin_css = css;
+	it->cset_link = &css->cgroup->cset_links;
+
+	css_advance_task_iter(it);
 }
 
-struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
-					struct cgroup_iter *it)
+/**
+ * css_task_iter_next - return the next task for the iterator
+ * @it: the task iterator being iterated
+ *
+ * The "next" function for task iteration.  @it should have been
+ * initialized via css_task_iter_start().  Returns NULL when the iteration
+ * reaches the end.
+ */
+struct task_struct *css_task_iter_next(struct css_task_iter *it)
 {
 	struct task_struct *res;
 	struct list_head *l = it->task;
@@ -3226,16 +3289,24 @@
 	l = l->next;
 	link = list_entry(it->cset_link, struct cgrp_cset_link, cset_link);
 	if (l == &link->cset->tasks) {
-		/* We reached the end of this task list - move on to
-		 * the next cg_cgroup_link */
-		cgroup_advance_iter(cgrp, it);
+		/*
+		 * We reached the end of this task list - move on to the
+		 * next cgrp_cset_link.
+		 */
+		css_advance_task_iter(it);
 	} else {
 		it->task = l;
 	}
 	return res;
 }
 
-void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it)
+/**
+ * css_task_iter_end - finish task iteration
+ * @it: the task iterator to finish
+ *
+ * Finish task iteration started by css_task_iter_start().
+ */
+void css_task_iter_end(struct css_task_iter *it)
 	__releases(css_set_lock)
 {
 	read_unlock(&css_set_lock);
@@ -3276,46 +3347,49 @@
 }
 
 /**
- * cgroup_scan_tasks - iterate though all the tasks in a cgroup
- * @scan: struct cgroup_scanner containing arguments for the scan
+ * css_scan_tasks - iterate though all the tasks in a css
+ * @css: the css to iterate tasks of
+ * @test: optional test callback
+ * @process: process callback
+ * @data: data passed to @test and @process
+ * @heap: optional pre-allocated heap used for task iteration
  *
- * Arguments include pointers to callback functions test_task() and
- * process_task().
- * Iterate through all the tasks in a cgroup, calling test_task() for each,
- * and if it returns true, call process_task() for it also.
- * The test_task pointer may be NULL, meaning always true (select all tasks).
- * Effectively duplicates cgroup_iter_{start,next,end}()
- * but does not lock css_set_lock for the call to process_task().
- * The struct cgroup_scanner may be embedded in any structure of the caller's
- * creation.
- * It is guaranteed that process_task() will act on every task that
- * is a member of the cgroup for the duration of this call. This
- * function may or may not call process_task() for tasks that exit
- * or move to a different cgroup during the call, or are forked or
- * move into the cgroup during the call.
+ * Iterate through all the tasks in @css, calling @test for each, and if it
+ * returns %true, call @process for it also.
  *
- * Note that test_task() may be called with locks held, and may in some
- * situations be called multiple times for the same task, so it should
- * be cheap.
- * If the heap pointer in the struct cgroup_scanner is non-NULL, a heap has been
- * pre-allocated and will be used for heap operations (and its "gt" member will
- * be overwritten), else a temporary heap will be used (allocation of which
- * may cause this function to fail).
+ * @test may be NULL, meaning always true (select all tasks), which
+ * effectively duplicates css_task_iter_{start,next,end}() but does not
+ * lock css_set_lock for the call to @process.
+ *
+ * It is guaranteed that @process will act on every task that is a member
+ * of @css for the duration of this call.  This function may or may not
+ * call @process for tasks that exit or move to a different css during the
+ * call, or are forked or move into the css during the call.
+ *
+ * Note that @test may be called with locks held, and may in some
+ * situations be called multiple times for the same task, so it should be
+ * cheap.
+ *
+ * If @heap is non-NULL, a heap has been pre-allocated and will be used for
+ * heap operations (and its "gt" member will be overwritten), else a
+ * temporary heap will be used (allocation of which may cause this function
+ * to fail).
  */
-int cgroup_scan_tasks(struct cgroup_scanner *scan)
+int css_scan_tasks(struct cgroup_subsys_state *css,
+		   bool (*test)(struct task_struct *, void *),
+		   void (*process)(struct task_struct *, void *),
+		   void *data, struct ptr_heap *heap)
 {
 	int retval, i;
-	struct cgroup_iter it;
+	struct css_task_iter it;
 	struct task_struct *p, *dropped;
 	/* Never dereference latest_task, since it's not refcounted */
 	struct task_struct *latest_task = NULL;
 	struct ptr_heap tmp_heap;
-	struct ptr_heap *heap;
 	struct timespec latest_time = { 0, 0 };
 
-	if (scan->heap) {
+	if (heap) {
 		/* The caller supplied our heap and pre-allocated its memory */
-		heap = scan->heap;
 		heap->gt = &started_after;
 	} else {
 		/* We need to allocate our own heap memory */
@@ -3328,25 +3402,24 @@
 
  again:
 	/*
-	 * Scan tasks in the cgroup, using the scanner's "test_task" callback
-	 * to determine which are of interest, and using the scanner's
-	 * "process_task" callback to process any of them that need an update.
-	 * Since we don't want to hold any locks during the task updates,
-	 * gather tasks to be processed in a heap structure.
-	 * The heap is sorted by descending task start time.
-	 * If the statically-sized heap fills up, we overflow tasks that
-	 * started later, and in future iterations only consider tasks that
-	 * started after the latest task in the previous pass. This
+	 * Scan tasks in the css, using the @test callback to determine
+	 * which are of interest, and invoking @process callback on the
+	 * ones which need an update.  Since we don't want to hold any
+	 * locks during the task updates, gather tasks to be processed in a
+	 * heap structure.  The heap is sorted by descending task start
+	 * time.  If the statically-sized heap fills up, we overflow tasks
+	 * that started later, and in future iterations only consider tasks
+	 * that started after the latest task in the previous pass. This
 	 * guarantees forward progress and that we don't miss any tasks.
 	 */
 	heap->size = 0;
-	cgroup_iter_start(scan->cg, &it);
-	while ((p = cgroup_iter_next(scan->cg, &it))) {
+	css_task_iter_start(css, &it);
+	while ((p = css_task_iter_next(&it))) {
 		/*
 		 * Only affect tasks that qualify per the caller's callback,
 		 * if he provided one
 		 */
-		if (scan->test_task && !scan->test_task(p, scan))
+		if (test && !test(p, data))
 			continue;
 		/*
 		 * Only process tasks that started after the last task
@@ -3374,7 +3447,7 @@
 		 * the heap and wasn't inserted
 		 */
 	}
-	cgroup_iter_end(scan->cg, &it);
+	css_task_iter_end(&it);
 
 	if (heap->size) {
 		for (i = 0; i < heap->size; i++) {
@@ -3384,7 +3457,7 @@
 				latest_task = q;
 			}
 			/* Process the task per the caller's callback */
-			scan->process_task(q, scan);
+			process(q, data);
 			put_task_struct(q);
 		}
 		/*
@@ -3401,10 +3474,9 @@
 	return 0;
 }
 
-static void cgroup_transfer_one_task(struct task_struct *task,
-				     struct cgroup_scanner *scan)
+static void cgroup_transfer_one_task(struct task_struct *task, void *data)
 {
-	struct cgroup *new_cgroup = scan->data;
+	struct cgroup *new_cgroup = data;
 
 	mutex_lock(&cgroup_mutex);
 	cgroup_attach_task(new_cgroup, task, false);
@@ -3418,15 +3490,8 @@
  */
 int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
 {
-	struct cgroup_scanner scan;
-
-	scan.cg = from;
-	scan.test_task = NULL; /* select all tasks in cgroup */
-	scan.process_task = cgroup_transfer_one_task;
-	scan.heap = NULL;
-	scan.data = to;
-
-	return cgroup_scan_tasks(&scan);
+	return css_scan_tasks(&from->dummy_css, NULL, cgroup_transfer_one_task,
+			      to, NULL);
 }
 
 /*
@@ -3468,7 +3533,7 @@
 	/* pointer to the cgroup we belong to, for list removal purposes */
 	struct cgroup *owner;
 	/* protects the other fields */
-	struct rw_semaphore mutex;
+	struct rw_semaphore rwsem;
 };
 
 /*
@@ -3541,7 +3606,7 @@
 	struct pid_namespace *ns = task_active_pid_ns(current);
 
 	/*
-	 * We can't drop the pidlist_mutex before taking the l->mutex in case
+	 * We can't drop the pidlist_mutex before taking the l->rwsem in case
 	 * the last ref-holder is trying to remove l from the list at the same
 	 * time. Holding the pidlist_mutex precludes somebody taking whichever
 	 * list we find out from under us - compare release_pid_array().
@@ -3550,7 +3615,7 @@
 	list_for_each_entry(l, &cgrp->pidlists, links) {
 		if (l->key.type == type && l->key.ns == ns) {
 			/* make sure l doesn't vanish out from under us */
-			down_write(&l->mutex);
+			down_write(&l->rwsem);
 			mutex_unlock(&cgrp->pidlist_mutex);
 			return l;
 		}
@@ -3561,8 +3626,8 @@
 		mutex_unlock(&cgrp->pidlist_mutex);
 		return l;
 	}
-	init_rwsem(&l->mutex);
-	down_write(&l->mutex);
+	init_rwsem(&l->rwsem);
+	down_write(&l->rwsem);
 	l->key.type = type;
 	l->key.ns = get_pid_ns(ns);
 	l->owner = cgrp;
@@ -3580,7 +3645,7 @@
 	pid_t *array;
 	int length;
 	int pid, n = 0; /* used for populating the array */
-	struct cgroup_iter it;
+	struct css_task_iter it;
 	struct task_struct *tsk;
 	struct cgroup_pidlist *l;
 
@@ -3595,8 +3660,8 @@
 	if (!array)
 		return -ENOMEM;
 	/* now, populate the array */
-	cgroup_iter_start(cgrp, &it);
-	while ((tsk = cgroup_iter_next(cgrp, &it))) {
+	css_task_iter_start(&cgrp->dummy_css, &it);
+	while ((tsk = css_task_iter_next(&it))) {
 		if (unlikely(n == length))
 			break;
 		/* get tgid or pid for procs or tasks file respectively */
@@ -3607,7 +3672,7 @@
 		if (pid > 0) /* make sure to only use valid results */
 			array[n++] = pid;
 	}
-	cgroup_iter_end(cgrp, &it);
+	css_task_iter_end(&it);
 	length = n;
 	/* now sort & (if procs) strip out duplicates */
 	sort(array, length, sizeof(pid_t), cmppid, NULL);
@@ -3623,7 +3688,7 @@
 	l->list = array;
 	l->length = length;
 	l->use_count++;
-	up_write(&l->mutex);
+	up_write(&l->rwsem);
 	*lp = l;
 	return 0;
 }
@@ -3641,7 +3706,7 @@
 {
 	int ret = -EINVAL;
 	struct cgroup *cgrp;
-	struct cgroup_iter it;
+	struct css_task_iter it;
 	struct task_struct *tsk;
 
 	/*
@@ -3655,8 +3720,8 @@
 	ret = 0;
 	cgrp = dentry->d_fsdata;
 
-	cgroup_iter_start(cgrp, &it);
-	while ((tsk = cgroup_iter_next(cgrp, &it))) {
+	css_task_iter_start(&cgrp->dummy_css, &it);
+	while ((tsk = css_task_iter_next(&it))) {
 		switch (tsk->state) {
 		case TASK_RUNNING:
 			stats->nr_running++;
@@ -3676,7 +3741,7 @@
 			break;
 		}
 	}
-	cgroup_iter_end(cgrp, &it);
+	css_task_iter_end(&it);
 
 err:
 	return ret;
@@ -3701,7 +3766,7 @@
 	int index = 0, pid = *pos;
 	int *iter;
 
-	down_read(&l->mutex);
+	down_read(&l->rwsem);
 	if (pid) {
 		int end = l->length;
 
@@ -3728,7 +3793,7 @@
 static void cgroup_pidlist_stop(struct seq_file *s, void *v)
 {
 	struct cgroup_pidlist *l = s->private;
-	up_read(&l->mutex);
+	up_read(&l->rwsem);
 }
 
 static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos)
@@ -3774,7 +3839,7 @@
 	 * pidlist_mutex, we have to take pidlist_mutex first.
 	 */
 	mutex_lock(&l->owner->pidlist_mutex);
-	down_write(&l->mutex);
+	down_write(&l->rwsem);
 	BUG_ON(!l->use_count);
 	if (!--l->use_count) {
 		/* we're the last user if refcount is 0; remove and free */
@@ -3782,12 +3847,12 @@
 		mutex_unlock(&l->owner->pidlist_mutex);
 		pidlist_free(l->list);
 		put_pid_ns(l->key.ns);
-		up_write(&l->mutex);
+		up_write(&l->rwsem);
 		kfree(l);
 		return;
 	}
 	mutex_unlock(&l->owner->pidlist_mutex);
-	up_write(&l->mutex);
+	up_write(&l->rwsem);
 }
 
 static int cgroup_pidlist_release(struct inode *inode, struct file *file)
@@ -3851,21 +3916,20 @@
 	return cgroup_pidlist_open(file, CGROUP_FILE_PROCS);
 }
 
-static u64 cgroup_read_notify_on_release(struct cgroup *cgrp,
-					    struct cftype *cft)
+static u64 cgroup_read_notify_on_release(struct cgroup_subsys_state *css,
+					 struct cftype *cft)
 {
-	return notify_on_release(cgrp);
+	return notify_on_release(css->cgroup);
 }
 
-static int cgroup_write_notify_on_release(struct cgroup *cgrp,
-					  struct cftype *cft,
-					  u64 val)
+static int cgroup_write_notify_on_release(struct cgroup_subsys_state *css,
+					  struct cftype *cft, u64 val)
 {
-	clear_bit(CGRP_RELEASABLE, &cgrp->flags);
+	clear_bit(CGRP_RELEASABLE, &css->cgroup->flags);
 	if (val)
-		set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
+		set_bit(CGRP_NOTIFY_ON_RELEASE, &css->cgroup->flags);
 	else
-		clear_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
+		clear_bit(CGRP_NOTIFY_ON_RELEASE, &css->cgroup->flags);
 	return 0;
 }
 
@@ -3895,18 +3959,18 @@
 {
 	struct cgroup_event *event = container_of(work, struct cgroup_event,
 			remove);
-	struct cgroup *cgrp = event->cgrp;
+	struct cgroup_subsys_state *css = event->css;
 
 	remove_wait_queue(event->wqh, &event->wait);
 
-	event->cft->unregister_event(cgrp, event->cft, event->eventfd);
+	event->cft->unregister_event(css, event->cft, event->eventfd);
 
 	/* Notify userspace the event is going away. */
 	eventfd_signal(event->eventfd, 1);
 
 	eventfd_ctx_put(event->eventfd);
 	kfree(event);
-	cgroup_dput(cgrp);
+	css_put(css);
 }
 
 /*
@@ -3919,7 +3983,7 @@
 {
 	struct cgroup_event *event = container_of(wait,
 			struct cgroup_event, wait);
-	struct cgroup *cgrp = event->cgrp;
+	struct cgroup *cgrp = event->css->cgroup;
 	unsigned long flags = (unsigned long)key;
 
 	if (flags & POLLHUP) {
@@ -3963,14 +4027,15 @@
  * Input must be in format '<event_fd> <control_fd> <args>'.
  * Interpretation of args is defined by control file implementation.
  */
-static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
-				      const char *buffer)
+static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css,
+				      struct cftype *cft, const char *buffer)
 {
-	struct cgroup_event *event = NULL;
-	struct cgroup *cgrp_cfile;
+	struct cgroup *cgrp = dummy_css->cgroup;
+	struct cgroup_event *event;
+	struct cgroup_subsys_state *cfile_css;
 	unsigned int efd, cfd;
-	struct file *efile = NULL;
-	struct file *cfile = NULL;
+	struct file *efile;
+	struct file *cfile;
 	char *endp;
 	int ret;
 
@@ -3987,7 +4052,7 @@
 	event = kzalloc(sizeof(*event), GFP_KERNEL);
 	if (!event)
 		return -ENOMEM;
-	event->cgrp = cgrp;
+
 	INIT_LIST_HEAD(&event->list);
 	init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc);
 	init_waitqueue_func_entry(&event->wait, cgroup_event_wake);
@@ -3996,62 +4061,68 @@
 	efile = eventfd_fget(efd);
 	if (IS_ERR(efile)) {
 		ret = PTR_ERR(efile);
-		goto fail;
+		goto out_kfree;
 	}
 
 	event->eventfd = eventfd_ctx_fileget(efile);
 	if (IS_ERR(event->eventfd)) {
 		ret = PTR_ERR(event->eventfd);
-		goto fail;
+		goto out_put_efile;
 	}
 
 	cfile = fget(cfd);
 	if (!cfile) {
 		ret = -EBADF;
-		goto fail;
+		goto out_put_eventfd;
 	}
 
 	/* the process need read permission on control file */
 	/* AV: shouldn't we check that it's been opened for read instead? */
 	ret = inode_permission(file_inode(cfile), MAY_READ);
 	if (ret < 0)
-		goto fail;
+		goto out_put_cfile;
 
 	event->cft = __file_cft(cfile);
 	if (IS_ERR(event->cft)) {
 		ret = PTR_ERR(event->cft);
-		goto fail;
+		goto out_put_cfile;
+	}
+
+	if (!event->cft->ss) {
+		ret = -EBADF;
+		goto out_put_cfile;
 	}
 
 	/*
-	 * The file to be monitored must be in the same cgroup as
-	 * cgroup.event_control is.
+	 * Determine the css of @cfile, verify it belongs to the same
+	 * cgroup as cgroup.event_control, and associate @event with it.
+	 * Remaining events are automatically removed on cgroup destruction
+	 * but the removal is asynchronous, so take an extra ref.
 	 */
-	cgrp_cfile = __d_cgrp(cfile->f_dentry->d_parent);
-	if (cgrp_cfile != cgrp) {
-		ret = -EINVAL;
-		goto fail;
-	}
+	rcu_read_lock();
+
+	ret = -EINVAL;
+	event->css = cgroup_css(cgrp, event->cft->ss);
+	cfile_css = css_from_dir(cfile->f_dentry->d_parent, event->cft->ss);
+	if (event->css && event->css == cfile_css && css_tryget(event->css))
+		ret = 0;
+
+	rcu_read_unlock();
+	if (ret)
+		goto out_put_cfile;
 
 	if (!event->cft->register_event || !event->cft->unregister_event) {
 		ret = -EINVAL;
-		goto fail;
+		goto out_put_css;
 	}
 
-	ret = event->cft->register_event(cgrp, event->cft,
+	ret = event->cft->register_event(event->css, event->cft,
 			event->eventfd, buffer);
 	if (ret)
-		goto fail;
+		goto out_put_css;
 
 	efile->f_op->poll(efile, &event->pt);
 
-	/*
-	 * Events should be removed after rmdir of cgroup directory, but before
-	 * destroying subsystem state objects. Let's take reference to cgroup
-	 * directory dentry to do that.
-	 */
-	dget(cgrp->dentry);
-
 	spin_lock(&cgrp->event_list_lock);
 	list_add(&event->list, &cgrp->event_list);
 	spin_unlock(&cgrp->event_list_lock);
@@ -4061,35 +4132,33 @@
 
 	return 0;
 
-fail:
-	if (cfile)
-		fput(cfile);
-
-	if (event && event->eventfd && !IS_ERR(event->eventfd))
-		eventfd_ctx_put(event->eventfd);
-
-	if (!IS_ERR_OR_NULL(efile))
-		fput(efile);
-
+out_put_css:
+	css_put(event->css);
+out_put_cfile:
+	fput(cfile);
+out_put_eventfd:
+	eventfd_ctx_put(event->eventfd);
+out_put_efile:
+	fput(efile);
+out_kfree:
 	kfree(event);
 
 	return ret;
 }
 
-static u64 cgroup_clone_children_read(struct cgroup *cgrp,
-				    struct cftype *cft)
+static u64 cgroup_clone_children_read(struct cgroup_subsys_state *css,
+				      struct cftype *cft)
 {
-	return test_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
+	return test_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags);
 }
 
-static int cgroup_clone_children_write(struct cgroup *cgrp,
-				     struct cftype *cft,
-				     u64 val)
+static int cgroup_clone_children_write(struct cgroup_subsys_state *css,
+				       struct cftype *cft, u64 val)
 {
 	if (val)
-		set_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
+		set_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags);
 	else
-		clear_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);
+		clear_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags);
 	return 0;
 }
 
@@ -4148,36 +4217,34 @@
 };
 
 /**
- * cgroup_populate_dir - selectively creation of files in a directory
+ * cgroup_populate_dir - create subsys files in a cgroup directory
  * @cgrp: target cgroup
- * @base_files: true if the base files should be added
  * @subsys_mask: mask of the subsystem ids whose files should be added
+ *
+ * On failure, no file is added.
  */
-static int cgroup_populate_dir(struct cgroup *cgrp, bool base_files,
-			       unsigned long subsys_mask)
+static int cgroup_populate_dir(struct cgroup *cgrp, unsigned long subsys_mask)
 {
-	int err;
 	struct cgroup_subsys *ss;
-
-	if (base_files) {
-		err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true);
-		if (err < 0)
-			return err;
-	}
+	int i, ret = 0;
 
 	/* process cftsets of each subsystem */
-	for_each_root_subsys(cgrp->root, ss) {
+	for_each_subsys(ss, i) {
 		struct cftype_set *set;
-		if (!test_bit(ss->subsys_id, &subsys_mask))
+
+		if (!test_bit(i, &subsys_mask))
 			continue;
 
-		list_for_each_entry(set, &ss->cftsets, node)
-			cgroup_addrm_files(cgrp, ss, set->cfts, true);
+		list_for_each_entry(set, &ss->cftsets, node) {
+			ret = cgroup_addrm_files(cgrp, set->cfts, true);
+			if (ret < 0)
+				goto err;
+		}
 	}
 
 	/* This cgroup is ready now */
 	for_each_root_subsys(cgrp->root, ss) {
-		struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+		struct cgroup_subsys_state *css = cgroup_css(cgrp, ss);
 		struct css_id *id = rcu_dereference_protected(css->id, true);
 
 		/*
@@ -4190,14 +4257,57 @@
 	}
 
 	return 0;
+err:
+	cgroup_clear_dir(cgrp, subsys_mask);
+	return ret;
 }
 
-static void css_dput_fn(struct work_struct *work)
+/*
+ * css destruction is four-stage process.
+ *
+ * 1. Destruction starts.  Killing of the percpu_ref is initiated.
+ *    Implemented in kill_css().
+ *
+ * 2. When the percpu_ref is confirmed to be visible as killed on all CPUs
+ *    and thus css_tryget() is guaranteed to fail, the css can be offlined
+ *    by invoking offline_css().  After offlining, the base ref is put.
+ *    Implemented in css_killed_work_fn().
+ *
+ * 3. When the percpu_ref reaches zero, the only possible remaining
+ *    accessors are inside RCU read sections.  css_release() schedules the
+ *    RCU callback.
+ *
+ * 4. After the grace period, the css can be freed.  Implemented in
+ *    css_free_work_fn().
+ *
+ * It is actually hairier because both step 2 and 4 require process context
+ * and thus involve punting to css->destroy_work adding two additional
+ * steps to the already complex sequence.
+ */
+static void css_free_work_fn(struct work_struct *work)
 {
 	struct cgroup_subsys_state *css =
-		container_of(work, struct cgroup_subsys_state, dput_work);
+		container_of(work, struct cgroup_subsys_state, destroy_work);
+	struct cgroup *cgrp = css->cgroup;
 
-	cgroup_dput(css->cgroup);
+	if (css->parent)
+		css_put(css->parent);
+
+	css->ss->css_free(css);
+	cgroup_dput(cgrp);
+}
+
+static void css_free_rcu_fn(struct rcu_head *rcu_head)
+{
+	struct cgroup_subsys_state *css =
+		container_of(rcu_head, struct cgroup_subsys_state, rcu_head);
+
+	/*
+	 * css holds an extra ref to @cgrp->dentry which is put on the last
+	 * css_put().  dput() requires process context which we don't have.
+	 */
+	INIT_WORK(&css->destroy_work, css_free_work_fn);
+	schedule_work(&css->destroy_work);
 }
 
 static void css_release(struct percpu_ref *ref)
@@ -4205,49 +4315,47 @@
 	struct cgroup_subsys_state *css =
 		container_of(ref, struct cgroup_subsys_state, refcnt);
 
-	schedule_work(&css->dput_work);
+	call_rcu(&css->rcu_head, css_free_rcu_fn);
 }
 
-static void init_cgroup_css(struct cgroup_subsys_state *css,
-			       struct cgroup_subsys *ss,
-			       struct cgroup *cgrp)
+static void init_css(struct cgroup_subsys_state *css, struct cgroup_subsys *ss,
+		     struct cgroup *cgrp)
 {
 	css->cgroup = cgrp;
+	css->ss = ss;
 	css->flags = 0;
 	css->id = NULL;
-	if (cgrp == cgroup_dummy_top)
-		css->flags |= CSS_ROOT;
-	BUG_ON(cgrp->subsys[ss->subsys_id]);
-	cgrp->subsys[ss->subsys_id] = css;
 
-	/*
-	 * css holds an extra ref to @cgrp->dentry which is put on the last
-	 * css_put().  dput() requires process context, which css_put() may
-	 * be called without.  @css->dput_work will be used to invoke
-	 * dput() asynchronously from css_put().
-	 */
-	INIT_WORK(&css->dput_work, css_dput_fn);
+	if (cgrp->parent)
+		css->parent = cgroup_css(cgrp->parent, ss);
+	else
+		css->flags |= CSS_ROOT;
+
+	BUG_ON(cgroup_css(cgrp, ss));
 }
 
-/* invoke ->post_create() on a new CSS and mark it online if successful */
-static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
+/* invoke ->css_online() on a new CSS and mark it online if successful */
+static int online_css(struct cgroup_subsys_state *css)
 {
+	struct cgroup_subsys *ss = css->ss;
 	int ret = 0;
 
 	lockdep_assert_held(&cgroup_mutex);
 
 	if (ss->css_online)
-		ret = ss->css_online(cgrp);
-	if (!ret)
-		cgrp->subsys[ss->subsys_id]->flags |= CSS_ONLINE;
+		ret = ss->css_online(css);
+	if (!ret) {
+		css->flags |= CSS_ONLINE;
+		css->cgroup->nr_css++;
+		rcu_assign_pointer(css->cgroup->subsys[ss->subsys_id], css);
+	}
 	return ret;
 }
 
-/* if the CSS is online, invoke ->pre_destory() on it and mark it offline */
-static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
-	__releases(&cgroup_mutex) __acquires(&cgroup_mutex)
+/* if the CSS is online, invoke ->css_offline() on it and mark it offline */
+static void offline_css(struct cgroup_subsys_state *css)
 {
-	struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+	struct cgroup_subsys *ss = css->ss;
 
 	lockdep_assert_held(&cgroup_mutex);
 
@@ -4255,9 +4363,11 @@
 		return;
 
 	if (ss->css_offline)
-		ss->css_offline(cgrp);
+		ss->css_offline(css);
 
-	cgrp->subsys[ss->subsys_id]->flags &= ~CSS_ONLINE;
+	css->flags &= ~CSS_ONLINE;
+	css->cgroup->nr_css--;
+	RCU_INIT_POINTER(css->cgroup->subsys[ss->subsys_id], css);
 }
 
 /*
@@ -4271,6 +4381,7 @@
 static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 			     umode_t mode)
 {
+	struct cgroup_subsys_state *css_ar[CGROUP_SUBSYS_COUNT] = { };
 	struct cgroup *cgrp;
 	struct cgroup_name *name;
 	struct cgroupfs_root *root = parent->root;
@@ -4288,7 +4399,11 @@
 		goto err_free_cgrp;
 	rcu_assign_pointer(cgrp->name, name);
 
-	cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL);
+	/*
+	 * Temporarily set the pointer to NULL, so idr_find() won't return
+	 * a half-baked cgroup.
+	 */
+	cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
 	if (cgrp->id < 0)
 		goto err_free_name;
 
@@ -4317,6 +4432,7 @@
 	cgrp->dentry = dentry;
 
 	cgrp->parent = parent;
+	cgrp->dummy_css.parent = &parent->dummy_css;
 	cgrp->root = parent->root;
 
 	if (notify_on_release(parent))
@@ -4328,22 +4444,21 @@
 	for_each_root_subsys(root, ss) {
 		struct cgroup_subsys_state *css;
 
-		css = ss->css_alloc(cgrp);
+		css = ss->css_alloc(cgroup_css(parent, ss));
 		if (IS_ERR(css)) {
 			err = PTR_ERR(css);
 			goto err_free_all;
 		}
+		css_ar[ss->subsys_id] = css;
 
 		err = percpu_ref_init(&css->refcnt, css_release);
-		if (err) {
-			ss->css_free(cgrp);
+		if (err)
 			goto err_free_all;
-		}
 
-		init_cgroup_css(css, ss, cgrp);
+		init_css(css, ss, cgrp);
 
 		if (ss->use_id) {
-			err = alloc_css_id(ss, parent, cgrp);
+			err = alloc_css_id(css);
 			if (err)
 				goto err_free_all;
 		}
@@ -4365,16 +4480,22 @@
 	list_add_tail_rcu(&cgrp->sibling, &cgrp->parent->children);
 	root->number_of_cgroups++;
 
-	/* each css holds a ref to the cgroup's dentry */
-	for_each_root_subsys(root, ss)
+	/* each css holds a ref to the cgroup's dentry and the parent css */
+	for_each_root_subsys(root, ss) {
+		struct cgroup_subsys_state *css = css_ar[ss->subsys_id];
+
 		dget(dentry);
+		css_get(css->parent);
+	}
 
 	/* hold a ref to the parent's dentry */
 	dget(parent->dentry);
 
 	/* creation succeeded, notify subsystems */
 	for_each_root_subsys(root, ss) {
-		err = online_css(ss, cgrp);
+		struct cgroup_subsys_state *css = css_ar[ss->subsys_id];
+
+		err = online_css(css);
 		if (err)
 			goto err_destroy;
 
@@ -4388,7 +4509,13 @@
 		}
 	}
 
-	err = cgroup_populate_dir(cgrp, true, root->subsys_mask);
+	idr_replace(&root->cgroup_idr, cgrp, cgrp->id);
+
+	err = cgroup_addrm_files(cgrp, cgroup_base_files, true);
+	if (err)
+		goto err_destroy;
+
+	err = cgroup_populate_dir(cgrp, root->subsys_mask);
 	if (err)
 		goto err_destroy;
 
@@ -4399,18 +4526,18 @@
 
 err_free_all:
 	for_each_root_subsys(root, ss) {
-		struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
+		struct cgroup_subsys_state *css = css_ar[ss->subsys_id];
 
 		if (css) {
 			percpu_ref_cancel_init(&css->refcnt);
-			ss->css_free(cgrp);
+			ss->css_free(css);
 		}
 	}
 	mutex_unlock(&cgroup_mutex);
 	/* Release the reference count that we took on the superblock */
 	deactivate_super(sb);
 err_free_id:
-	ida_simple_remove(&root->cgroup_ida, cgrp->id);
+	idr_remove(&root->cgroup_idr, cgrp->id);
 err_free_name:
 	kfree(rcu_dereference_raw(cgrp->name));
 err_free_cgrp:
@@ -4432,22 +4559,84 @@
 	return cgroup_create(c_parent, dentry, mode | S_IFDIR);
 }
 
-static void cgroup_css_killed(struct cgroup *cgrp)
+/*
+ * This is called when the refcnt of a css is confirmed to be killed.
+ * css_tryget() is now guaranteed to fail.
+ */
+static void css_killed_work_fn(struct work_struct *work)
 {
-	if (!atomic_dec_and_test(&cgrp->css_kill_cnt))
-		return;
+	struct cgroup_subsys_state *css =
+		container_of(work, struct cgroup_subsys_state, destroy_work);
+	struct cgroup *cgrp = css->cgroup;
 
-	/* percpu ref's of all css's are killed, kick off the next step */
-	INIT_WORK(&cgrp->destroy_work, cgroup_offline_fn);
-	schedule_work(&cgrp->destroy_work);
+	mutex_lock(&cgroup_mutex);
+
+	/*
+	 * css_tryget() is guaranteed to fail now.  Tell subsystems to
+	 * initate destruction.
+	 */
+	offline_css(css);
+
+	/*
+	 * If @cgrp is marked dead, it's waiting for refs of all css's to
+	 * be disabled before proceeding to the second phase of cgroup
+	 * destruction.  If we are the last one, kick it off.
+	 */
+	if (!cgrp->nr_css && cgroup_is_dead(cgrp))
+		cgroup_destroy_css_killed(cgrp);
+
+	mutex_unlock(&cgroup_mutex);
+
+	/*
+	 * Put the css refs from kill_css().  Each css holds an extra
+	 * reference to the cgroup's dentry and cgroup removal proceeds
+	 * regardless of css refs.  On the last put of each css, whenever
+	 * that may be, the extra dentry ref is put so that dentry
+	 * destruction happens only after all css's are released.
+	 */
+	css_put(css);
 }
 
-static void css_ref_killed_fn(struct percpu_ref *ref)
+/* css kill confirmation processing requires process context, bounce */
+static void css_killed_ref_fn(struct percpu_ref *ref)
 {
 	struct cgroup_subsys_state *css =
 		container_of(ref, struct cgroup_subsys_state, refcnt);
 
-	cgroup_css_killed(css->cgroup);
+	INIT_WORK(&css->destroy_work, css_killed_work_fn);
+	schedule_work(&css->destroy_work);
+}
+
+/**
+ * kill_css - destroy a css
+ * @css: css to destroy
+ *
+ * This function initiates destruction of @css by removing cgroup interface
+ * files and putting its base reference.  ->css_offline() will be invoked
+ * asynchronously once css_tryget() is guaranteed to fail and when the
+ * reference count reaches zero, @css will be released.
+ */
+static void kill_css(struct cgroup_subsys_state *css)
+{
+	cgroup_clear_dir(css->cgroup, 1 << css->ss->subsys_id);
+
+	/*
+	 * Killing would put the base ref, but we need to keep it alive
+	 * until after ->css_offline().
+	 */
+	css_get(css);
+
+	/*
+	 * cgroup core guarantees that, by the time ->css_offline() is
+	 * invoked, no new css reference will be given out via
+	 * css_tryget().  We can't simply call percpu_ref_kill() and
+	 * proceed to offlining css's because percpu_ref_kill() doesn't
+	 * guarantee that the ref is seen as killed on all CPUs on return.
+	 *
+	 * Use percpu_ref_kill_and_confirm() to get notifications as each
+	 * css is confirmed to be seen as killed on all CPUs.
+	 */
+	percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn);
 }
 
 /**
@@ -4480,6 +4669,7 @@
 	struct dentry *d = cgrp->dentry;
 	struct cgroup_event *event, *tmp;
 	struct cgroup_subsys *ss;
+	struct cgroup *child;
 	bool empty;
 
 	lockdep_assert_held(&d->d_inode->i_mutex);
@@ -4490,47 +4680,41 @@
 	 * @cgrp from being removed while __put_css_set() is in progress.
 	 */
 	read_lock(&css_set_lock);
-	empty = list_empty(&cgrp->cset_links) && list_empty(&cgrp->children);
+	empty = list_empty(&cgrp->cset_links);
 	read_unlock(&css_set_lock);
 	if (!empty)
 		return -EBUSY;
 
 	/*
-	 * Block new css_tryget() by killing css refcnts.  cgroup core
-	 * guarantees that, by the time ->css_offline() is invoked, no new
-	 * css reference will be given out via css_tryget().  We can't
-	 * simply call percpu_ref_kill() and proceed to offlining css's
-	 * because percpu_ref_kill() doesn't guarantee that the ref is seen
-	 * as killed on all CPUs on return.
-	 *
-	 * Use percpu_ref_kill_and_confirm() to get notifications as each
-	 * css is confirmed to be seen as killed on all CPUs.  The
-	 * notification callback keeps track of the number of css's to be
-	 * killed and schedules cgroup_offline_fn() to perform the rest of
-	 * destruction once the percpu refs of all css's are confirmed to
-	 * be killed.
+	 * Make sure there's no live children.  We can't test ->children
+	 * emptiness as dead children linger on it while being destroyed;
+	 * otherwise, "rmdir parent/child parent" may fail with -EBUSY.
 	 */
-	atomic_set(&cgrp->css_kill_cnt, 1);
-	for_each_root_subsys(cgrp->root, ss) {
-		struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
-
-		/*
-		 * Killing would put the base ref, but we need to keep it
-		 * alive until after ->css_offline.
-		 */
-		percpu_ref_get(&css->refcnt);
-
-		atomic_inc(&cgrp->css_kill_cnt);
-		percpu_ref_kill_and_confirm(&css->refcnt, css_ref_killed_fn);
+	empty = true;
+	rcu_read_lock();
+	list_for_each_entry_rcu(child, &cgrp->children, sibling) {
+		empty = cgroup_is_dead(child);
+		if (!empty)
+			break;
 	}
-	cgroup_css_killed(cgrp);
+	rcu_read_unlock();
+	if (!empty)
+		return -EBUSY;
+
+	/*
+	 * Initiate massacre of all css's.  cgroup_destroy_css_killed()
+	 * will be invoked to perform the rest of destruction once the
+	 * percpu refs of all css's are confirmed to be killed.
+	 */
+	for_each_root_subsys(cgrp->root, ss)
+		kill_css(cgroup_css(cgrp, ss));
 
 	/*
 	 * Mark @cgrp dead.  This prevents further task migration and child
 	 * creation by disabling cgroup_lock_live_group().  Note that
-	 * CGRP_DEAD assertion is depended upon by cgroup_next_sibling() to
+	 * CGRP_DEAD assertion is depended upon by css_next_child() to
 	 * resume iteration after dropping RCU read lock.  See
-	 * cgroup_next_sibling() for details.
+	 * css_next_child() for details.
 	 */
 	set_bit(CGRP_DEAD, &cgrp->flags);
 
@@ -4541,9 +4725,20 @@
 	raw_spin_unlock(&release_list_lock);
 
 	/*
-	 * Remove @cgrp directory.  The removal puts the base ref but we
-	 * aren't quite done with @cgrp yet, so hold onto it.
+	 * If @cgrp has css's attached, the second stage of cgroup
+	 * destruction is kicked off from css_killed_work_fn() after the
+	 * refs of all attached css's are killed.  If @cgrp doesn't have
+	 * any css, we kick it off here.
 	 */
+	if (!cgrp->nr_css)
+		cgroup_destroy_css_killed(cgrp);
+
+	/*
+	 * Clear the base files and remove @cgrp directory.  The removal
+	 * puts the base ref but we aren't quite done with @cgrp yet, so
+	 * hold onto it.
+	 */
+	cgroup_addrm_files(cgrp, cgroup_base_files, false);
 	dget(d);
 	cgroup_d_remove_dir(d);
 
@@ -4563,50 +4758,36 @@
 };
 
 /**
- * cgroup_offline_fn - the second step of cgroup destruction
+ * cgroup_destroy_css_killed - the second step of cgroup destruction
  * @work: cgroup->destroy_free_work
  *
  * This function is invoked from a work item for a cgroup which is being
- * destroyed after the percpu refcnts of all css's are guaranteed to be
- * seen as killed on all CPUs, and performs the rest of destruction.  This
- * is the second step of destruction described in the comment above
- * cgroup_destroy_locked().
+ * destroyed after all css's are offlined and performs the rest of
+ * destruction.  This is the second step of destruction described in the
+ * comment above cgroup_destroy_locked().
  */
-static void cgroup_offline_fn(struct work_struct *work)
+static void cgroup_destroy_css_killed(struct cgroup *cgrp)
 {
-	struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work);
 	struct cgroup *parent = cgrp->parent;
 	struct dentry *d = cgrp->dentry;
-	struct cgroup_subsys *ss;
 
-	mutex_lock(&cgroup_mutex);
-
-	/*
-	 * css_tryget() is guaranteed to fail now.  Tell subsystems to
-	 * initate destruction.
-	 */
-	for_each_root_subsys(cgrp->root, ss)
-		offline_css(ss, cgrp);
-
-	/*
-	 * Put the css refs from cgroup_destroy_locked().  Each css holds
-	 * an extra reference to the cgroup's dentry and cgroup removal
-	 * proceeds regardless of css refs.  On the last put of each css,
-	 * whenever that may be, the extra dentry ref is put so that dentry
-	 * destruction happens only after all css's are released.
-	 */
-	for_each_root_subsys(cgrp->root, ss)
-		css_put(cgrp->subsys[ss->subsys_id]);
+	lockdep_assert_held(&cgroup_mutex);
 
 	/* delete this cgroup from parent->children */
 	list_del_rcu(&cgrp->sibling);
 
+	/*
+	 * We should remove the cgroup object from idr before its grace
+	 * period starts, so we won't be looking up a cgroup while the
+	 * cgroup is being freed.
+	 */
+	idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+	cgrp->id = -1;
+
 	dput(d);
 
 	set_bit(CGRP_RELEASABLE, &parent->flags);
 	check_for_release(parent);
-
-	mutex_unlock(&cgroup_mutex);
 }
 
 static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
@@ -4629,6 +4810,11 @@
 	 * deregistration.
 	 */
 	if (ss->base_cftypes) {
+		struct cftype *cft;
+
+		for (cft = ss->base_cftypes; cft->name[0] != '\0'; cft++)
+			cft->ss = ss;
+
 		ss->base_cftset.cfts = ss->base_cftypes;
 		list_add_tail(&ss->base_cftset.node, &ss->cftsets);
 	}
@@ -4648,10 +4834,10 @@
 	/* Create the top cgroup state for this subsystem */
 	list_add(&ss->sibling, &cgroup_dummy_root.subsys_list);
 	ss->root = &cgroup_dummy_root;
-	css = ss->css_alloc(cgroup_dummy_top);
+	css = ss->css_alloc(cgroup_css(cgroup_dummy_top, ss));
 	/* We don't handle early failures gracefully */
 	BUG_ON(IS_ERR(css));
-	init_cgroup_css(css, ss, cgroup_dummy_top);
+	init_css(css, ss, cgroup_dummy_top);
 
 	/* Update the init_css_set to contain a subsys
 	 * pointer to this state - since the subsystem is
@@ -4666,7 +4852,7 @@
 	 * need to invoke fork callbacks here. */
 	BUG_ON(!list_empty(&init_task.tasks));
 
-	BUG_ON(online_css(ss, cgroup_dummy_top));
+	BUG_ON(online_css(css));
 
 	mutex_unlock(&cgroup_mutex);
 
@@ -4727,7 +4913,7 @@
 	 * struct, so this can happen first (i.e. before the dummy root
 	 * attachment).
 	 */
-	css = ss->css_alloc(cgroup_dummy_top);
+	css = ss->css_alloc(cgroup_css(cgroup_dummy_top, ss));
 	if (IS_ERR(css)) {
 		/* failure case - need to deassign the cgroup_subsys[] slot. */
 		cgroup_subsys[ss->subsys_id] = NULL;
@@ -4739,8 +4925,8 @@
 	ss->root = &cgroup_dummy_root;
 
 	/* our new subsystem will be attached to the dummy hierarchy. */
-	init_cgroup_css(css, ss, cgroup_dummy_top);
-	/* init_idr must be after init_cgroup_css because it sets css->id. */
+	init_css(css, ss, cgroup_dummy_top);
+	/* init_idr must be after init_css() because it sets css->id. */
 	if (ss->use_id) {
 		ret = cgroup_init_idr(ss, css);
 		if (ret)
@@ -4770,7 +4956,7 @@
 	}
 	write_unlock(&css_set_lock);
 
-	ret = online_css(ss, cgroup_dummy_top);
+	ret = online_css(css);
 	if (ret)
 		goto err_unload;
 
@@ -4802,14 +4988,14 @@
 
 	/*
 	 * we shouldn't be called if the subsystem is in use, and the use of
-	 * try_module_get in parse_cgroupfs_options should ensure that it
+	 * try_module_get() in rebind_subsystems() should ensure that it
 	 * doesn't start being used while we're killing it off.
 	 */
 	BUG_ON(ss->root != &cgroup_dummy_root);
 
 	mutex_lock(&cgroup_mutex);
 
-	offline_css(ss, cgroup_dummy_top);
+	offline_css(cgroup_css(cgroup_dummy_top, ss));
 
 	if (ss->use_id)
 		idr_destroy(&ss->idr);
@@ -4843,8 +5029,8 @@
 	 * the cgrp->subsys pointer to find their state. note that this
 	 * also takes care of freeing the css_id.
 	 */
-	ss->css_free(cgroup_dummy_top);
-	cgroup_dummy_top->subsys[ss->subsys_id] = NULL;
+	ss->css_free(cgroup_css(cgroup_dummy_top, ss));
+	RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL);
 
 	mutex_unlock(&cgroup_mutex);
 }
@@ -4926,6 +5112,10 @@
 
 	BUG_ON(cgroup_init_root_id(&cgroup_dummy_root, 0, 1));
 
+	err = idr_alloc(&cgroup_dummy_root.cgroup_idr, cgroup_dummy_top,
+			0, 1, GFP_KERNEL);
+	BUG_ON(err < 0);
+
 	mutex_unlock(&cgroup_root_mutex);
 	mutex_unlock(&cgroup_mutex);
 
@@ -5082,7 +5272,7 @@
  * Adds the task to the list running through its css_set if necessary and
  * call the subsystem fork() callbacks.  Has to be after the task is
  * visible on the task list in case we race with the first call to
- * cgroup_iter_start() - to guarantee that the new task ends up on its
+ * cgroup_task_iter_start() - to guarantee that the new task ends up on its
  * list.
  */
 void cgroup_post_fork(struct task_struct *child)
@@ -5195,10 +5385,10 @@
 		 */
 		for_each_builtin_subsys(ss, i) {
 			if (ss->exit) {
-				struct cgroup *old_cgrp = cset->subsys[i]->cgroup;
-				struct cgroup *cgrp = task_cgroup(tsk, i);
+				struct cgroup_subsys_state *old_css = cset->subsys[i];
+				struct cgroup_subsys_state *css = task_css(tsk, i);
 
-				ss->exit(cgrp, old_cgrp, tsk);
+				ss->exit(css, old_css, tsk);
 			}
 		}
 	}
@@ -5457,20 +5647,16 @@
 	return 0;
 }
 
-static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
-			struct cgroup *child)
+static int alloc_css_id(struct cgroup_subsys_state *child_css)
 {
-	int subsys_id, i, depth = 0;
-	struct cgroup_subsys_state *parent_css, *child_css;
+	struct cgroup_subsys_state *parent_css = css_parent(child_css);
 	struct css_id *child_id, *parent_id;
+	int i, depth;
 
-	subsys_id = ss->subsys_id;
-	parent_css = parent->subsys[subsys_id];
-	child_css = child->subsys[subsys_id];
 	parent_id = rcu_dereference_protected(parent_css->id, true);
 	depth = parent_id->depth + 1;
 
-	child_id = get_new_cssid(ss, depth);
+	child_id = get_new_cssid(child_css->ss, depth);
 	if (IS_ERR(child_id))
 		return PTR_ERR(child_id);
 
@@ -5508,31 +5694,56 @@
 }
 EXPORT_SYMBOL_GPL(css_lookup);
 
-/*
- * get corresponding css from file open on cgroupfs directory
+/**
+ * css_from_dir - get corresponding css from the dentry of a cgroup dir
+ * @dentry: directory dentry of interest
+ * @ss: subsystem of interest
+ *
+ * Must be called under RCU read lock.  The caller is responsible for
+ * pinning the returned css if it needs to be accessed outside the RCU
+ * critical section.
  */
-struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id)
+struct cgroup_subsys_state *css_from_dir(struct dentry *dentry,
+					 struct cgroup_subsys *ss)
 {
 	struct cgroup *cgrp;
-	struct inode *inode;
-	struct cgroup_subsys_state *css;
 
-	inode = file_inode(f);
-	/* check in cgroup filesystem dir */
-	if (inode->i_op != &cgroup_dir_inode_operations)
+	WARN_ON_ONCE(!rcu_read_lock_held());
+
+	/* is @dentry a cgroup dir? */
+	if (!dentry->d_inode ||
+	    dentry->d_inode->i_op != &cgroup_dir_inode_operations)
 		return ERR_PTR(-EBADF);
 
-	if (id < 0 || id >= CGROUP_SUBSYS_COUNT)
-		return ERR_PTR(-EINVAL);
+	cgrp = __d_cgrp(dentry);
+	return cgroup_css(cgrp, ss) ?: ERR_PTR(-ENOENT);
+}
 
-	/* get cgroup */
-	cgrp = __d_cgrp(f->f_dentry);
-	css = cgrp->subsys[id];
-	return css ? css : ERR_PTR(-ENOENT);
+/**
+ * css_from_id - lookup css by id
+ * @id: the cgroup id
+ * @ss: cgroup subsys to be looked into
+ *
+ * Returns the css if there's valid one with @id, otherwise returns NULL.
+ * Should be called under rcu_read_lock().
+ */
+struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
+{
+	struct cgroup *cgrp;
+
+	rcu_lockdep_assert(rcu_read_lock_held() ||
+			   lockdep_is_held(&cgroup_mutex),
+			   "css_from_id() needs proper protection");
+
+	cgrp = idr_find(&ss->root->cgroup_idr, id);
+	if (cgrp)
+		return cgroup_css(cgrp, ss);
+	return NULL;
 }
 
 #ifdef CONFIG_CGROUP_DEBUG
-static struct cgroup_subsys_state *debug_css_alloc(struct cgroup *cgrp)
+static struct cgroup_subsys_state *
+debug_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct cgroup_subsys_state *css = kzalloc(sizeof(*css), GFP_KERNEL);
 
@@ -5542,22 +5753,24 @@
 	return css;
 }
 
-static void debug_css_free(struct cgroup *cgrp)
+static void debug_css_free(struct cgroup_subsys_state *css)
 {
-	kfree(cgrp->subsys[debug_subsys_id]);
+	kfree(css);
 }
 
-static u64 debug_taskcount_read(struct cgroup *cgrp, struct cftype *cft)
+static u64 debug_taskcount_read(struct cgroup_subsys_state *css,
+				struct cftype *cft)
 {
-	return cgroup_task_count(cgrp);
+	return cgroup_task_count(css->cgroup);
 }
 
-static u64 current_css_set_read(struct cgroup *cgrp, struct cftype *cft)
+static u64 current_css_set_read(struct cgroup_subsys_state *css,
+				struct cftype *cft)
 {
 	return (u64)(unsigned long)current->cgroups;
 }
 
-static u64 current_css_set_refcount_read(struct cgroup *cgrp,
+static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css,
 					 struct cftype *cft)
 {
 	u64 count;
@@ -5568,7 +5781,7 @@
 	return count;
 }
 
-static int current_css_set_cg_links_read(struct cgroup *cgrp,
+static int current_css_set_cg_links_read(struct cgroup_subsys_state *css,
 					 struct cftype *cft,
 					 struct seq_file *seq)
 {
@@ -5595,14 +5808,13 @@
 }
 
 #define MAX_TASKS_SHOWN_PER_CSS 25
-static int cgroup_css_links_read(struct cgroup *cgrp,
-				 struct cftype *cft,
-				 struct seq_file *seq)
+static int cgroup_css_links_read(struct cgroup_subsys_state *css,
+				 struct cftype *cft, struct seq_file *seq)
 {
 	struct cgrp_cset_link *link;
 
 	read_lock(&css_set_lock);
-	list_for_each_entry(link, &cgrp->cset_links, cset_link) {
+	list_for_each_entry(link, &css->cgroup->cset_links, cset_link) {
 		struct css_set *cset = link->cset;
 		struct task_struct *task;
 		int count = 0;
@@ -5621,9 +5833,9 @@
 	return 0;
 }
 
-static u64 releasable_read(struct cgroup *cgrp, struct cftype *cft)
+static u64 releasable_read(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	return test_bit(CGRP_RELEASABLE, &cgrp->flags);
+	return test_bit(CGRP_RELEASABLE, &css->cgroup->flags);
 }
 
 static struct cftype debug_files[] =  {
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index 75dda1e..f0ff64d 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -45,25 +45,19 @@
 	spinlock_t			lock;
 };
 
-static inline struct freezer *cgroup_freezer(struct cgroup *cgroup)
+static inline struct freezer *css_freezer(struct cgroup_subsys_state *css)
 {
-	return container_of(cgroup_subsys_state(cgroup, freezer_subsys_id),
-			    struct freezer, css);
+	return css ? container_of(css, struct freezer, css) : NULL;
 }
 
 static inline struct freezer *task_freezer(struct task_struct *task)
 {
-	return container_of(task_subsys_state(task, freezer_subsys_id),
-			    struct freezer, css);
+	return css_freezer(task_css(task, freezer_subsys_id));
 }
 
 static struct freezer *parent_freezer(struct freezer *freezer)
 {
-	struct cgroup *pcg = freezer->css.cgroup->parent;
-
-	if (pcg)
-		return cgroup_freezer(pcg);
-	return NULL;
+	return css_freezer(css_parent(&freezer->css));
 }
 
 bool cgroup_freezing(struct task_struct *task)
@@ -92,7 +86,8 @@
 
 struct cgroup_subsys freezer_subsys;
 
-static struct cgroup_subsys_state *freezer_css_alloc(struct cgroup *cgroup)
+static struct cgroup_subsys_state *
+freezer_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct freezer *freezer;
 
@@ -105,22 +100,22 @@
 }
 
 /**
- * freezer_css_online - commit creation of a freezer cgroup
- * @cgroup: cgroup being created
+ * freezer_css_online - commit creation of a freezer css
+ * @css: css being created
  *
- * We're committing to creation of @cgroup.  Mark it online and inherit
+ * We're committing to creation of @css.  Mark it online and inherit
  * parent's freezing state while holding both parent's and our
  * freezer->lock.
  */
-static int freezer_css_online(struct cgroup *cgroup)
+static int freezer_css_online(struct cgroup_subsys_state *css)
 {
-	struct freezer *freezer = cgroup_freezer(cgroup);
+	struct freezer *freezer = css_freezer(css);
 	struct freezer *parent = parent_freezer(freezer);
 
 	/*
 	 * The following double locking and freezing state inheritance
 	 * guarantee that @cgroup can never escape ancestors' freezing
-	 * states.  See cgroup_for_each_descendant_pre() for details.
+	 * states.  See css_for_each_descendant_pre() for details.
 	 */
 	if (parent)
 		spin_lock_irq(&parent->lock);
@@ -141,15 +136,15 @@
 }
 
 /**
- * freezer_css_offline - initiate destruction of @cgroup
- * @cgroup: cgroup being destroyed
+ * freezer_css_offline - initiate destruction of a freezer css
+ * @css: css being destroyed
  *
- * @cgroup is going away.  Mark it dead and decrement system_freezing_count
- * if it was holding one.
+ * @css is going away.  Mark it dead and decrement system_freezing_count if
+ * it was holding one.
  */
-static void freezer_css_offline(struct cgroup *cgroup)
+static void freezer_css_offline(struct cgroup_subsys_state *css)
 {
-	struct freezer *freezer = cgroup_freezer(cgroup);
+	struct freezer *freezer = css_freezer(css);
 
 	spin_lock_irq(&freezer->lock);
 
@@ -161,9 +156,9 @@
 	spin_unlock_irq(&freezer->lock);
 }
 
-static void freezer_css_free(struct cgroup *cgroup)
+static void freezer_css_free(struct cgroup_subsys_state *css)
 {
-	kfree(cgroup_freezer(cgroup));
+	kfree(css_freezer(css));
 }
 
 /*
@@ -175,25 +170,26 @@
  * @freezer->lock.  freezer_attach() makes the new tasks conform to the
  * current state and all following state changes can see the new tasks.
  */
-static void freezer_attach(struct cgroup *new_cgrp, struct cgroup_taskset *tset)
+static void freezer_attach(struct cgroup_subsys_state *new_css,
+			   struct cgroup_taskset *tset)
 {
-	struct freezer *freezer = cgroup_freezer(new_cgrp);
+	struct freezer *freezer = css_freezer(new_css);
 	struct task_struct *task;
 	bool clear_frozen = false;
 
 	spin_lock_irq(&freezer->lock);
 
 	/*
-	 * Make the new tasks conform to the current state of @new_cgrp.
+	 * Make the new tasks conform to the current state of @new_css.
 	 * For simplicity, when migrating any task to a FROZEN cgroup, we
 	 * revert it to FREEZING and let update_if_frozen() determine the
 	 * correct state later.
 	 *
-	 * Tasks in @tset are on @new_cgrp but may not conform to its
+	 * Tasks in @tset are on @new_css but may not conform to its
 	 * current state before executing the following - !frozen tasks may
 	 * be visible in a FROZEN cgroup and frozen tasks in a THAWED one.
 	 */
-	cgroup_taskset_for_each(task, new_cgrp, tset) {
+	cgroup_taskset_for_each(task, new_css, tset) {
 		if (!(freezer->state & CGROUP_FREEZING)) {
 			__thaw_task(task);
 		} else {
@@ -231,7 +227,7 @@
 	 * The root cgroup is non-freezable, so we can skip the
 	 * following check.
 	 */
-	if (!freezer->css.cgroup->parent)
+	if (!parent_freezer(freezer))
 		goto out;
 
 	spin_lock_irq(&freezer->lock);
@@ -244,7 +240,7 @@
 
 /**
  * update_if_frozen - update whether a cgroup finished freezing
- * @cgroup: cgroup of interest
+ * @css: css of interest
  *
  * Once FREEZING is initiated, transition to FROZEN is lazily updated by
  * calling this function.  If the current state is FREEZING but not FROZEN,
@@ -255,14 +251,14 @@
  * update_if_frozen() on all descendants prior to invoking this function.
  *
  * Task states and freezer state might disagree while tasks are being
- * migrated into or out of @cgroup, so we can't verify task states against
+ * migrated into or out of @css, so we can't verify task states against
  * @freezer state here.  See freezer_attach() for details.
  */
-static void update_if_frozen(struct cgroup *cgroup)
+static void update_if_frozen(struct cgroup_subsys_state *css)
 {
-	struct freezer *freezer = cgroup_freezer(cgroup);
-	struct cgroup *pos;
-	struct cgroup_iter it;
+	struct freezer *freezer = css_freezer(css);
+	struct cgroup_subsys_state *pos;
+	struct css_task_iter it;
 	struct task_struct *task;
 
 	WARN_ON_ONCE(!rcu_read_lock_held());
@@ -274,8 +270,8 @@
 		goto out_unlock;
 
 	/* are all (live) children frozen? */
-	cgroup_for_each_child(pos, cgroup) {
-		struct freezer *child = cgroup_freezer(pos);
+	css_for_each_child(pos, css) {
+		struct freezer *child = css_freezer(pos);
 
 		if ((child->state & CGROUP_FREEZER_ONLINE) &&
 		    !(child->state & CGROUP_FROZEN))
@@ -283,9 +279,9 @@
 	}
 
 	/* are all tasks frozen? */
-	cgroup_iter_start(cgroup, &it);
+	css_task_iter_start(css, &it);
 
-	while ((task = cgroup_iter_next(cgroup, &it))) {
+	while ((task = css_task_iter_next(&it))) {
 		if (freezing(task)) {
 			/*
 			 * freezer_should_skip() indicates that the task
@@ -300,52 +296,49 @@
 
 	freezer->state |= CGROUP_FROZEN;
 out_iter_end:
-	cgroup_iter_end(cgroup, &it);
+	css_task_iter_end(&it);
 out_unlock:
 	spin_unlock_irq(&freezer->lock);
 }
 
-static int freezer_read(struct cgroup *cgroup, struct cftype *cft,
+static int freezer_read(struct cgroup_subsys_state *css, struct cftype *cft,
 			struct seq_file *m)
 {
-	struct cgroup *pos;
+	struct cgroup_subsys_state *pos;
 
 	rcu_read_lock();
 
 	/* update states bottom-up */
-	cgroup_for_each_descendant_post(pos, cgroup)
+	css_for_each_descendant_post(pos, css)
 		update_if_frozen(pos);
-	update_if_frozen(cgroup);
 
 	rcu_read_unlock();
 
-	seq_puts(m, freezer_state_strs(cgroup_freezer(cgroup)->state));
+	seq_puts(m, freezer_state_strs(css_freezer(css)->state));
 	seq_putc(m, '\n');
 	return 0;
 }
 
 static void freeze_cgroup(struct freezer *freezer)
 {
-	struct cgroup *cgroup = freezer->css.cgroup;
-	struct cgroup_iter it;
+	struct css_task_iter it;
 	struct task_struct *task;
 
-	cgroup_iter_start(cgroup, &it);
-	while ((task = cgroup_iter_next(cgroup, &it)))
+	css_task_iter_start(&freezer->css, &it);
+	while ((task = css_task_iter_next(&it)))
 		freeze_task(task);
-	cgroup_iter_end(cgroup, &it);
+	css_task_iter_end(&it);
 }
 
 static void unfreeze_cgroup(struct freezer *freezer)
 {
-	struct cgroup *cgroup = freezer->css.cgroup;
-	struct cgroup_iter it;
+	struct css_task_iter it;
 	struct task_struct *task;
 
-	cgroup_iter_start(cgroup, &it);
-	while ((task = cgroup_iter_next(cgroup, &it)))
+	css_task_iter_start(&freezer->css, &it);
+	while ((task = css_task_iter_next(&it)))
 		__thaw_task(task);
-	cgroup_iter_end(cgroup, &it);
+	css_task_iter_end(&it);
 }
 
 /**
@@ -395,12 +388,7 @@
  */
 static void freezer_change_state(struct freezer *freezer, bool freeze)
 {
-	struct cgroup *pos;
-
-	/* update @freezer */
-	spin_lock_irq(&freezer->lock);
-	freezer_apply_state(freezer, freeze, CGROUP_FREEZING_SELF);
-	spin_unlock_irq(&freezer->lock);
+	struct cgroup_subsys_state *pos;
 
 	/*
 	 * Update all its descendants in pre-order traversal.  Each
@@ -408,24 +396,33 @@
 	 * CGROUP_FREEZING_PARENT.
 	 */
 	rcu_read_lock();
-	cgroup_for_each_descendant_pre(pos, freezer->css.cgroup) {
-		struct freezer *pos_f = cgroup_freezer(pos);
+	css_for_each_descendant_pre(pos, &freezer->css) {
+		struct freezer *pos_f = css_freezer(pos);
 		struct freezer *parent = parent_freezer(pos_f);
 
-		/*
-		 * Our update to @parent->state is already visible which is
-		 * all we need.  No need to lock @parent.  For more info on
-		 * synchronization, see freezer_post_create().
-		 */
 		spin_lock_irq(&pos_f->lock);
-		freezer_apply_state(pos_f, parent->state & CGROUP_FREEZING,
-				    CGROUP_FREEZING_PARENT);
+
+		if (pos_f == freezer) {
+			freezer_apply_state(pos_f, freeze,
+					    CGROUP_FREEZING_SELF);
+		} else {
+			/*
+			 * Our update to @parent->state is already visible
+			 * which is all we need.  No need to lock @parent.
+			 * For more info on synchronization, see
+			 * freezer_post_create().
+			 */
+			freezer_apply_state(pos_f,
+					    parent->state & CGROUP_FREEZING,
+					    CGROUP_FREEZING_PARENT);
+		}
+
 		spin_unlock_irq(&pos_f->lock);
 	}
 	rcu_read_unlock();
 }
 
-static int freezer_write(struct cgroup *cgroup, struct cftype *cft,
+static int freezer_write(struct cgroup_subsys_state *css, struct cftype *cft,
 			 const char *buffer)
 {
 	bool freeze;
@@ -437,20 +434,22 @@
 	else
 		return -EINVAL;
 
-	freezer_change_state(cgroup_freezer(cgroup), freeze);
+	freezer_change_state(css_freezer(css), freeze);
 	return 0;
 }
 
-static u64 freezer_self_freezing_read(struct cgroup *cgroup, struct cftype *cft)
+static u64 freezer_self_freezing_read(struct cgroup_subsys_state *css,
+				      struct cftype *cft)
 {
-	struct freezer *freezer = cgroup_freezer(cgroup);
+	struct freezer *freezer = css_freezer(css);
 
 	return (bool)(freezer->state & CGROUP_FREEZING_SELF);
 }
 
-static u64 freezer_parent_freezing_read(struct cgroup *cgroup, struct cftype *cft)
+static u64 freezer_parent_freezing_read(struct cgroup_subsys_state *css,
+					struct cftype *cft)
 {
-	struct freezer *freezer = cgroup_freezer(cgroup);
+	struct freezer *freezer = css_freezer(css);
 
 	return (bool)(freezer->state & CGROUP_FREEZING_PARENT);
 }
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 383f823..247091b 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -20,22 +20,33 @@
 #include <linux/hardirq.h>
 #include <linux/export.h>
 
-DEFINE_PER_CPU(struct context_tracking, context_tracking) = {
-#ifdef CONFIG_CONTEXT_TRACKING_FORCE
-	.active = true,
-#endif
-};
+#define CREATE_TRACE_POINTS
+#include <trace/events/context_tracking.h>
+
+struct static_key context_tracking_enabled = STATIC_KEY_INIT_FALSE;
+EXPORT_SYMBOL_GPL(context_tracking_enabled);
+
+DEFINE_PER_CPU(struct context_tracking, context_tracking);
+EXPORT_SYMBOL_GPL(context_tracking);
+
+void context_tracking_cpu_set(int cpu)
+{
+	if (!per_cpu(context_tracking.active, cpu)) {
+		per_cpu(context_tracking.active, cpu) = true;
+		static_key_slow_inc(&context_tracking_enabled);
+	}
+}
 
 /**
- * user_enter - Inform the context tracking that the CPU is going to
- *              enter userspace mode.
+ * context_tracking_user_enter - Inform the context tracking that the CPU is going to
+ *                               enter userspace mode.
  *
  * This function must be called right before we switch from the kernel
  * to userspace, when it's guaranteed the remaining kernel instructions
  * to execute won't use any RCU read side critical section because this
  * function sets RCU in extended quiescent state.
  */
-void user_enter(void)
+void context_tracking_user_enter(void)
 {
 	unsigned long flags;
 
@@ -54,17 +65,32 @@
 	WARN_ON_ONCE(!current->mm);
 
 	local_irq_save(flags);
-	if (__this_cpu_read(context_tracking.active) &&
-	    __this_cpu_read(context_tracking.state) != IN_USER) {
+	if ( __this_cpu_read(context_tracking.state) != IN_USER) {
+		if (__this_cpu_read(context_tracking.active)) {
+			trace_user_enter(0);
+			/*
+			 * At this stage, only low level arch entry code remains and
+			 * then we'll run in userspace. We can assume there won't be
+			 * any RCU read-side critical section until the next call to
+			 * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency
+			 * on the tick.
+			 */
+			vtime_user_enter(current);
+			rcu_user_enter();
+		}
 		/*
-		 * At this stage, only low level arch entry code remains and
-		 * then we'll run in userspace. We can assume there won't be
-		 * any RCU read-side critical section until the next call to
-		 * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency
-		 * on the tick.
+		 * Even if context tracking is disabled on this CPU, because it's outside
+		 * the full dynticks mask for example, we still have to keep track of the
+		 * context transitions and states to prevent inconsistency on those of
+		 * other CPUs.
+		 * If a task triggers an exception in userspace, sleep on the exception
+		 * handler and then migrate to another CPU, that new CPU must know where
+		 * the exception returns by the time we call exception_exit().
+		 * This information can only be provided by the previous CPU when it called
+		 * exception_enter().
+		 * OTOH we can spare the calls to vtime and RCU when context_tracking.active
+		 * is false because we know that CPU is not tickless.
 		 */
-		vtime_user_enter(current);
-		rcu_user_enter();
 		__this_cpu_write(context_tracking.state, IN_USER);
 	}
 	local_irq_restore(flags);
@@ -87,10 +113,9 @@
  */
 void __sched notrace preempt_schedule_context(void)
 {
-	struct thread_info *ti = current_thread_info();
 	enum ctx_state prev_ctx;
 
-	if (likely(ti->preempt_count || irqs_disabled()))
+	if (likely(!preemptible()))
 		return;
 
 	/*
@@ -112,8 +137,8 @@
 #endif /* CONFIG_PREEMPT */
 
 /**
- * user_exit - Inform the context tracking that the CPU is
- *             exiting userspace mode and entering the kernel.
+ * context_tracking_user_exit - Inform the context tracking that the CPU is
+ *                              exiting userspace mode and entering the kernel.
  *
  * This function must be called after we entered the kernel from userspace
  * before any use of RCU read side critical section. This potentially include
@@ -122,7 +147,7 @@
  * This call supports re-entrancy. This way it can be called from any exception
  * handler without needing to know if we came from userspace or not.
  */
-void user_exit(void)
+void context_tracking_user_exit(void)
 {
 	unsigned long flags;
 
@@ -131,38 +156,22 @@
 
 	local_irq_save(flags);
 	if (__this_cpu_read(context_tracking.state) == IN_USER) {
-		/*
-		 * We are going to run code that may use RCU. Inform
-		 * RCU core about that (ie: we may need the tick again).
-		 */
-		rcu_user_exit();
-		vtime_user_exit(current);
+		if (__this_cpu_read(context_tracking.active)) {
+			/*
+			 * We are going to run code that may use RCU. Inform
+			 * RCU core about that (ie: we may need the tick again).
+			 */
+			rcu_user_exit();
+			vtime_user_exit(current);
+			trace_user_exit(0);
+		}
 		__this_cpu_write(context_tracking.state, IN_KERNEL);
 	}
 	local_irq_restore(flags);
 }
 
-void guest_enter(void)
-{
-	if (vtime_accounting_enabled())
-		vtime_guest_enter(current);
-	else
-		__guest_enter();
-}
-EXPORT_SYMBOL_GPL(guest_enter);
-
-void guest_exit(void)
-{
-	if (vtime_accounting_enabled())
-		vtime_guest_exit(current);
-	else
-		__guest_exit();
-}
-EXPORT_SYMBOL_GPL(guest_exit);
-
-
 /**
- * context_tracking_task_switch - context switch the syscall callbacks
+ * __context_tracking_task_switch - context switch the syscall callbacks
  * @prev: the task that is being switched out
  * @next: the task that is being switched in
  *
@@ -174,11 +183,19 @@
  * migrate to some CPU that doesn't do the context tracking. As such the TIF
  * flag may not be desired there.
  */
-void context_tracking_task_switch(struct task_struct *prev,
-			     struct task_struct *next)
+void __context_tracking_task_switch(struct task_struct *prev,
+				    struct task_struct *next)
 {
-	if (__this_cpu_read(context_tracking.active)) {
-		clear_tsk_thread_flag(prev, TIF_NOHZ);
-		set_tsk_thread_flag(next, TIF_NOHZ);
-	}
+	clear_tsk_thread_flag(prev, TIF_NOHZ);
+	set_tsk_thread_flag(next, TIF_NOHZ);
 }
+
+#ifdef CONFIG_CONTEXT_TRACKING_FORCE
+void __init context_tracking_init(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		context_tracking_cpu_set(cpu);
+}
+#endif
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b2b227b..d7f07a2 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -113,7 +113,7 @@
  * get_online_cpus() not an api which is called all that often.
  *
  */
-static void cpu_hotplug_begin(void)
+void cpu_hotplug_begin(void)
 {
 	cpu_hotplug.active_writer = current;
 
@@ -127,7 +127,7 @@
 	}
 }
 
-static void cpu_hotplug_done(void)
+void cpu_hotplug_done(void)
 {
 	cpu_hotplug.active_writer = NULL;
 	mutex_unlock(&cpu_hotplug.lock);
@@ -154,10 +154,7 @@
 	cpu_maps_update_done();
 }
 
-#else /* #if CONFIG_HOTPLUG_CPU */
-static void cpu_hotplug_begin(void) {}
-static void cpu_hotplug_done(void) {}
-#endif	/* #else #if CONFIG_HOTPLUG_CPU */
+#endif	/* CONFIG_HOTPLUG_CPU */
 
 /* Need to know about CPUs going up/down? */
 int __ref register_cpu_notifier(struct notifier_block *nb)
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 010a008..6bf981e 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -68,10 +68,6 @@
  */
 int number_of_cpusets __read_mostly;
 
-/* Forward declare cgroup structures */
-struct cgroup_subsys cpuset_subsys;
-struct cpuset;
-
 /* See "Frequency meter" comments, below. */
 
 struct fmeter {
@@ -115,27 +111,20 @@
 	int relax_domain_level;
 };
 
-/* Retrieve the cpuset for a cgroup */
-static inline struct cpuset *cgroup_cs(struct cgroup *cgrp)
+static inline struct cpuset *css_cs(struct cgroup_subsys_state *css)
 {
-	return container_of(cgroup_subsys_state(cgrp, cpuset_subsys_id),
-			    struct cpuset, css);
+	return css ? container_of(css, struct cpuset, css) : NULL;
 }
 
 /* Retrieve the cpuset for a task */
 static inline struct cpuset *task_cs(struct task_struct *task)
 {
-	return container_of(task_subsys_state(task, cpuset_subsys_id),
-			    struct cpuset, css);
+	return css_cs(task_css(task, cpuset_subsys_id));
 }
 
-static inline struct cpuset *parent_cs(const struct cpuset *cs)
+static inline struct cpuset *parent_cs(struct cpuset *cs)
 {
-	struct cgroup *pcgrp = cs->css.cgroup->parent;
-
-	if (pcgrp)
-		return cgroup_cs(pcgrp);
-	return NULL;
+	return css_cs(css_parent(&cs->css));
 }
 
 #ifdef CONFIG_NUMA
@@ -212,29 +201,30 @@
 /**
  * cpuset_for_each_child - traverse online children of a cpuset
  * @child_cs: loop cursor pointing to the current child
- * @pos_cgrp: used for iteration
+ * @pos_css: used for iteration
  * @parent_cs: target cpuset to walk children of
  *
  * Walk @child_cs through the online children of @parent_cs.  Must be used
  * with RCU read locked.
  */
-#define cpuset_for_each_child(child_cs, pos_cgrp, parent_cs)		\
-	cgroup_for_each_child((pos_cgrp), (parent_cs)->css.cgroup)	\
-		if (is_cpuset_online(((child_cs) = cgroup_cs((pos_cgrp)))))
+#define cpuset_for_each_child(child_cs, pos_css, parent_cs)		\
+	css_for_each_child((pos_css), &(parent_cs)->css)		\
+		if (is_cpuset_online(((child_cs) = css_cs((pos_css)))))
 
 /**
  * cpuset_for_each_descendant_pre - pre-order walk of a cpuset's descendants
  * @des_cs: loop cursor pointing to the current descendant
- * @pos_cgrp: used for iteration
+ * @pos_css: used for iteration
  * @root_cs: target cpuset to walk ancestor of
  *
  * Walk @des_cs through the online descendants of @root_cs.  Must be used
- * with RCU read locked.  The caller may modify @pos_cgrp by calling
- * cgroup_rightmost_descendant() to skip subtree.
+ * with RCU read locked.  The caller may modify @pos_css by calling
+ * css_rightmost_descendant() to skip subtree.  @root_cs is included in the
+ * iteration and the first node to be visited.
  */
-#define cpuset_for_each_descendant_pre(des_cs, pos_cgrp, root_cs)	\
-	cgroup_for_each_descendant_pre((pos_cgrp), (root_cs)->css.cgroup) \
-		if (is_cpuset_online(((des_cs) = cgroup_cs((pos_cgrp)))))
+#define cpuset_for_each_descendant_pre(des_cs, pos_css, root_cs)	\
+	css_for_each_descendant_pre((pos_css), &(root_cs)->css)		\
+		if (is_cpuset_online(((des_cs) = css_cs((pos_css)))))
 
 /*
  * There are two global mutexes guarding cpuset structures - cpuset_mutex
@@ -320,8 +310,7 @@
  *
  * Call with callback_mutex held.
  */
-static void guarantee_online_cpus(const struct cpuset *cs,
-				  struct cpumask *pmask)
+static void guarantee_online_cpus(struct cpuset *cs, struct cpumask *pmask)
 {
 	while (!cpumask_intersects(cs->cpus_allowed, cpu_online_mask))
 		cs = parent_cs(cs);
@@ -339,7 +328,7 @@
  *
  * Call with callback_mutex held.
  */
-static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
+static void guarantee_online_mems(struct cpuset *cs, nodemask_t *pmask)
 {
 	while (!nodes_intersects(cs->mems_allowed, node_states[N_MEMORY]))
 		cs = parent_cs(cs);
@@ -384,7 +373,7 @@
  * alloc_trial_cpuset - allocate a trial cpuset
  * @cs: the cpuset that the trial cpuset duplicates
  */
-static struct cpuset *alloc_trial_cpuset(const struct cpuset *cs)
+static struct cpuset *alloc_trial_cpuset(struct cpuset *cs)
 {
 	struct cpuset *trial;
 
@@ -431,9 +420,9 @@
  * Return 0 if valid, -errno if not.
  */
 
-static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
+static int validate_change(struct cpuset *cur, struct cpuset *trial)
 {
-	struct cgroup *cgrp;
+	struct cgroup_subsys_state *css;
 	struct cpuset *c, *par;
 	int ret;
 
@@ -441,7 +430,7 @@
 
 	/* Each of our child cpusets must be a subset of us */
 	ret = -EBUSY;
-	cpuset_for_each_child(c, cgrp, cur)
+	cpuset_for_each_child(c, css, cur)
 		if (!is_cpuset_subset(c, trial))
 			goto out;
 
@@ -462,7 +451,7 @@
 	 * overlap
 	 */
 	ret = -EINVAL;
-	cpuset_for_each_child(c, cgrp, par) {
+	cpuset_for_each_child(c, css, par) {
 		if ((is_cpu_exclusive(trial) || is_cpu_exclusive(c)) &&
 		    c != cur &&
 		    cpumask_intersects(trial->cpus_allowed, c->cpus_allowed))
@@ -475,13 +464,17 @@
 
 	/*
 	 * Cpusets with tasks - existing or newly being attached - can't
-	 * have empty cpus_allowed or mems_allowed.
+	 * be changed to have empty cpus_allowed or mems_allowed.
 	 */
 	ret = -ENOSPC;
-	if ((cgroup_task_count(cur->css.cgroup) || cur->attach_in_progress) &&
-	    (cpumask_empty(trial->cpus_allowed) &&
-	     nodes_empty(trial->mems_allowed)))
-		goto out;
+	if ((cgroup_task_count(cur->css.cgroup) || cur->attach_in_progress)) {
+		if (!cpumask_empty(cur->cpus_allowed) &&
+		    cpumask_empty(trial->cpus_allowed))
+			goto out;
+		if (!nodes_empty(cur->mems_allowed) &&
+		    nodes_empty(trial->mems_allowed))
+			goto out;
+	}
 
 	ret = 0;
 out:
@@ -511,13 +504,16 @@
 				    struct cpuset *root_cs)
 {
 	struct cpuset *cp;
-	struct cgroup *pos_cgrp;
+	struct cgroup_subsys_state *pos_css;
 
 	rcu_read_lock();
-	cpuset_for_each_descendant_pre(cp, pos_cgrp, root_cs) {
+	cpuset_for_each_descendant_pre(cp, pos_css, root_cs) {
+		if (cp == root_cs)
+			continue;
+
 		/* skip the whole subtree if @cp doesn't have any CPU */
 		if (cpumask_empty(cp->cpus_allowed)) {
-			pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
+			pos_css = css_rightmost_descendant(pos_css);
 			continue;
 		}
 
@@ -592,7 +588,7 @@
 	struct sched_domain_attr *dattr;  /* attributes for custom domains */
 	int ndoms = 0;		/* number of sched domains in result */
 	int nslot;		/* next empty doms[] struct cpumask slot */
-	struct cgroup *pos_cgrp;
+	struct cgroup_subsys_state *pos_css;
 
 	doms = NULL;
 	dattr = NULL;
@@ -621,7 +617,9 @@
 	csn = 0;
 
 	rcu_read_lock();
-	cpuset_for_each_descendant_pre(cp, pos_cgrp, &top_cpuset) {
+	cpuset_for_each_descendant_pre(cp, pos_css, &top_cpuset) {
+		if (cp == &top_cpuset)
+			continue;
 		/*
 		 * Continue traversing beyond @cp iff @cp has some CPUs and
 		 * isn't load balancing.  The former is obvious.  The
@@ -638,7 +636,7 @@
 			csa[csn++] = cp;
 
 		/* skip @cp's subtree */
-		pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
+		pos_css = css_rightmost_descendant(pos_css);
 	}
 	rcu_read_unlock();
 
@@ -833,52 +831,45 @@
 /**
  * cpuset_change_cpumask - make a task's cpus_allowed the same as its cpuset's
  * @tsk: task to test
- * @scan: struct cgroup_scanner containing the cgroup of the task
+ * @data: cpuset to @tsk belongs to
  *
- * Called by cgroup_scan_tasks() for each task in a cgroup whose
- * cpus_allowed mask needs to be changed.
+ * Called by css_scan_tasks() for each task in a cgroup whose cpus_allowed
+ * mask needs to be changed.
  *
  * We don't need to re-check for the cgroup/cpuset membership, since we're
  * holding cpuset_mutex at this point.
  */
-static void cpuset_change_cpumask(struct task_struct *tsk,
-				  struct cgroup_scanner *scan)
+static void cpuset_change_cpumask(struct task_struct *tsk, void *data)
 {
-	struct cpuset *cpus_cs;
+	struct cpuset *cs = data;
+	struct cpuset *cpus_cs = effective_cpumask_cpuset(cs);
 
-	cpus_cs = effective_cpumask_cpuset(cgroup_cs(scan->cg));
 	set_cpus_allowed_ptr(tsk, cpus_cs->cpus_allowed);
 }
 
 /**
  * update_tasks_cpumask - Update the cpumasks of tasks in the cpuset.
  * @cs: the cpuset in which each task's cpus_allowed mask needs to be changed
- * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ * @heap: if NULL, defer allocating heap memory to css_scan_tasks()
  *
  * Called with cpuset_mutex held
  *
- * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
+ * The css_scan_tasks() function will scan all the tasks in a cgroup,
  * calling callback functions for each.
  *
- * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * No return value. It's guaranteed that css_scan_tasks() always returns 0
  * if @heap != NULL.
  */
 static void update_tasks_cpumask(struct cpuset *cs, struct ptr_heap *heap)
 {
-	struct cgroup_scanner scan;
-
-	scan.cg = cs->css.cgroup;
-	scan.test_task = NULL;
-	scan.process_task = cpuset_change_cpumask;
-	scan.heap = heap;
-	cgroup_scan_tasks(&scan);
+	css_scan_tasks(&cs->css, NULL, cpuset_change_cpumask, cs, heap);
 }
 
 /*
  * update_tasks_cpumask_hier - Update the cpumasks of tasks in the hierarchy.
  * @root_cs: the root cpuset of the hierarchy
  * @update_root: update root cpuset or not?
- * @heap: the heap used by cgroup_scan_tasks()
+ * @heap: the heap used by css_scan_tasks()
  *
  * This will update cpumasks of tasks in @root_cs and all other empty cpusets
  * which take on cpumask of @root_cs.
@@ -889,17 +880,19 @@
 				      bool update_root, struct ptr_heap *heap)
 {
 	struct cpuset *cp;
-	struct cgroup *pos_cgrp;
-
-	if (update_root)
-		update_tasks_cpumask(root_cs, heap);
+	struct cgroup_subsys_state *pos_css;
 
 	rcu_read_lock();
-	cpuset_for_each_descendant_pre(cp, pos_cgrp, root_cs) {
-		/* skip the whole subtree if @cp have some CPU */
-		if (!cpumask_empty(cp->cpus_allowed)) {
-			pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
-			continue;
+	cpuset_for_each_descendant_pre(cp, pos_css, root_cs) {
+		if (cp == root_cs) {
+			if (!update_root)
+				continue;
+		} else {
+			/* skip the whole subtree if @cp have some CPU */
+			if (!cpumask_empty(cp->cpus_allowed)) {
+				pos_css = css_rightmost_descendant(pos_css);
+				continue;
+			}
 		}
 		if (!css_tryget(&cp->css))
 			continue;
@@ -1055,20 +1048,24 @@
 	task_unlock(tsk);
 }
 
+struct cpuset_change_nodemask_arg {
+	struct cpuset		*cs;
+	nodemask_t		*newmems;
+};
+
 /*
  * Update task's mems_allowed and rebind its mempolicy and vmas' mempolicy
  * of it to cpuset's new mems_allowed, and migrate pages to new nodes if
  * memory_migrate flag is set. Called with cpuset_mutex held.
  */
-static void cpuset_change_nodemask(struct task_struct *p,
-				   struct cgroup_scanner *scan)
+static void cpuset_change_nodemask(struct task_struct *p, void *data)
 {
-	struct cpuset *cs = cgroup_cs(scan->cg);
+	struct cpuset_change_nodemask_arg *arg = data;
+	struct cpuset *cs = arg->cs;
 	struct mm_struct *mm;
 	int migrate;
-	nodemask_t *newmems = scan->data;
 
-	cpuset_change_task_nodemask(p, newmems);
+	cpuset_change_task_nodemask(p, arg->newmems);
 
 	mm = get_task_mm(p);
 	if (!mm)
@@ -1078,7 +1075,7 @@
 
 	mpol_rebind_mm(mm, &cs->mems_allowed);
 	if (migrate)
-		cpuset_migrate_mm(mm, &cs->old_mems_allowed, newmems);
+		cpuset_migrate_mm(mm, &cs->old_mems_allowed, arg->newmems);
 	mmput(mm);
 }
 
@@ -1087,28 +1084,22 @@
 /**
  * update_tasks_nodemask - Update the nodemasks of tasks in the cpuset.
  * @cs: the cpuset in which each task's mems_allowed mask needs to be changed
- * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ * @heap: if NULL, defer allocating heap memory to css_scan_tasks()
  *
- * Called with cpuset_mutex held
- * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
- * if @heap != NULL.
+ * Called with cpuset_mutex held.  No return value. It's guaranteed that
+ * css_scan_tasks() always returns 0 if @heap != NULL.
  */
 static void update_tasks_nodemask(struct cpuset *cs, struct ptr_heap *heap)
 {
 	static nodemask_t newmems;	/* protected by cpuset_mutex */
-	struct cgroup_scanner scan;
 	struct cpuset *mems_cs = effective_nodemask_cpuset(cs);
+	struct cpuset_change_nodemask_arg arg = { .cs = cs,
+						  .newmems = &newmems };
 
 	cpuset_being_rebound = cs;		/* causes mpol_dup() rebind */
 
 	guarantee_online_mems(mems_cs, &newmems);
 
-	scan.cg = cs->css.cgroup;
-	scan.test_task = NULL;
-	scan.process_task = cpuset_change_nodemask;
-	scan.heap = heap;
-	scan.data = &newmems;
-
 	/*
 	 * The mpol_rebind_mm() call takes mmap_sem, which we couldn't
 	 * take while holding tasklist_lock.  Forks can happen - the
@@ -1119,7 +1110,7 @@
 	 * It's ok if we rebind the same mm twice; mpol_rebind_mm()
 	 * is idempotent.  Also migrate pages in each mm to new nodes.
 	 */
-	cgroup_scan_tasks(&scan);
+	css_scan_tasks(&cs->css, NULL, cpuset_change_nodemask, &arg, heap);
 
 	/*
 	 * All the tasks' nodemasks have been updated, update
@@ -1135,7 +1126,7 @@
  * update_tasks_nodemask_hier - Update the nodemasks of tasks in the hierarchy.
  * @cs: the root cpuset of the hierarchy
  * @update_root: update the root cpuset or not?
- * @heap: the heap used by cgroup_scan_tasks()
+ * @heap: the heap used by css_scan_tasks()
  *
  * This will update nodemasks of tasks in @root_cs and all other empty cpusets
  * which take on nodemask of @root_cs.
@@ -1146,17 +1137,19 @@
 				       bool update_root, struct ptr_heap *heap)
 {
 	struct cpuset *cp;
-	struct cgroup *pos_cgrp;
-
-	if (update_root)
-		update_tasks_nodemask(root_cs, heap);
+	struct cgroup_subsys_state *pos_css;
 
 	rcu_read_lock();
-	cpuset_for_each_descendant_pre(cp, pos_cgrp, root_cs) {
-		/* skip the whole subtree if @cp have some CPU */
-		if (!nodes_empty(cp->mems_allowed)) {
-			pos_cgrp = cgroup_rightmost_descendant(pos_cgrp);
-			continue;
+	cpuset_for_each_descendant_pre(cp, pos_css, root_cs) {
+		if (cp == root_cs) {
+			if (!update_root)
+				continue;
+		} else {
+			/* skip the whole subtree if @cp have some CPU */
+			if (!nodes_empty(cp->mems_allowed)) {
+				pos_css = css_rightmost_descendant(pos_css);
+				continue;
+			}
 		}
 		if (!css_tryget(&cp->css))
 			continue;
@@ -1263,44 +1256,39 @@
 	return 0;
 }
 
-/*
+/**
  * cpuset_change_flag - make a task's spread flags the same as its cpuset's
  * @tsk: task to be updated
- * @scan: struct cgroup_scanner containing the cgroup of the task
+ * @data: cpuset to @tsk belongs to
  *
- * Called by cgroup_scan_tasks() for each task in a cgroup.
+ * Called by css_scan_tasks() for each task in a cgroup.
  *
  * We don't need to re-check for the cgroup/cpuset membership, since we're
  * holding cpuset_mutex at this point.
  */
-static void cpuset_change_flag(struct task_struct *tsk,
-				struct cgroup_scanner *scan)
+static void cpuset_change_flag(struct task_struct *tsk, void *data)
 {
-	cpuset_update_task_spread_flag(cgroup_cs(scan->cg), tsk);
+	struct cpuset *cs = data;
+
+	cpuset_update_task_spread_flag(cs, tsk);
 }
 
-/*
+/**
  * update_tasks_flags - update the spread flags of tasks in the cpuset.
  * @cs: the cpuset in which each task's spread flags needs to be changed
- * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ * @heap: if NULL, defer allocating heap memory to css_scan_tasks()
  *
  * Called with cpuset_mutex held
  *
- * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
+ * The css_scan_tasks() function will scan all the tasks in a cgroup,
  * calling callback functions for each.
  *
- * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * No return value. It's guaranteed that css_scan_tasks() always returns 0
  * if @heap != NULL.
  */
 static void update_tasks_flags(struct cpuset *cs, struct ptr_heap *heap)
 {
-	struct cgroup_scanner scan;
-
-	scan.cg = cs->css.cgroup;
-	scan.test_task = NULL;
-	scan.process_task = cpuset_change_flag;
-	scan.heap = heap;
-	cgroup_scan_tasks(&scan);
+	css_scan_tasks(&cs->css, NULL, cpuset_change_flag, cs, heap);
 }
 
 /*
@@ -1458,9 +1446,10 @@
 }
 
 /* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
-static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static int cpuset_can_attach(struct cgroup_subsys_state *css,
+			     struct cgroup_taskset *tset)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	struct task_struct *task;
 	int ret;
 
@@ -1471,11 +1460,11 @@
 	 * flag is set.
 	 */
 	ret = -ENOSPC;
-	if (!cgroup_sane_behavior(cgrp) &&
+	if (!cgroup_sane_behavior(css->cgroup) &&
 	    (cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)))
 		goto out_unlock;
 
-	cgroup_taskset_for_each(task, cgrp, tset) {
+	cgroup_taskset_for_each(task, css, tset) {
 		/*
 		 * Kthreads which disallow setaffinity shouldn't be moved
 		 * to a new cpuset; we don't want to change their cpu
@@ -1504,11 +1493,11 @@
 	return ret;
 }
 
-static void cpuset_cancel_attach(struct cgroup *cgrp,
+static void cpuset_cancel_attach(struct cgroup_subsys_state *css,
 				 struct cgroup_taskset *tset)
 {
 	mutex_lock(&cpuset_mutex);
-	cgroup_cs(cgrp)->attach_in_progress--;
+	css_cs(css)->attach_in_progress--;
 	mutex_unlock(&cpuset_mutex);
 }
 
@@ -1519,16 +1508,18 @@
  */
 static cpumask_var_t cpus_attach;
 
-static void cpuset_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static void cpuset_attach(struct cgroup_subsys_state *css,
+			  struct cgroup_taskset *tset)
 {
 	/* static buf protected by cpuset_mutex */
 	static nodemask_t cpuset_attach_nodemask_to;
 	struct mm_struct *mm;
 	struct task_struct *task;
 	struct task_struct *leader = cgroup_taskset_first(tset);
-	struct cgroup *oldcgrp = cgroup_taskset_cur_cgroup(tset);
-	struct cpuset *cs = cgroup_cs(cgrp);
-	struct cpuset *oldcs = cgroup_cs(oldcgrp);
+	struct cgroup_subsys_state *oldcss = cgroup_taskset_cur_css(tset,
+							cpuset_subsys_id);
+	struct cpuset *cs = css_cs(css);
+	struct cpuset *oldcs = css_cs(oldcss);
 	struct cpuset *cpus_cs = effective_cpumask_cpuset(cs);
 	struct cpuset *mems_cs = effective_nodemask_cpuset(cs);
 
@@ -1542,7 +1533,7 @@
 
 	guarantee_online_mems(mems_cs, &cpuset_attach_nodemask_to);
 
-	cgroup_taskset_for_each(task, cgrp, tset) {
+	cgroup_taskset_for_each(task, css, tset) {
 		/*
 		 * can_attach beforehand should guarantee that this doesn't
 		 * fail.  TODO: have a better way to handle failure here
@@ -1604,9 +1595,10 @@
 	FILE_SPREAD_SLAB,
 } cpuset_filetype_t;
 
-static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
+static int cpuset_write_u64(struct cgroup_subsys_state *css, struct cftype *cft,
+			    u64 val)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	cpuset_filetype_t type = cft->private;
 	int retval = 0;
 
@@ -1653,9 +1645,10 @@
 	return retval;
 }
 
-static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val)
+static int cpuset_write_s64(struct cgroup_subsys_state *css, struct cftype *cft,
+			    s64 val)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	cpuset_filetype_t type = cft->private;
 	int retval = -ENODEV;
 
@@ -1679,10 +1672,10 @@
 /*
  * Common handling for a write to a "cpus" or "mems" file.
  */
-static int cpuset_write_resmask(struct cgroup *cgrp, struct cftype *cft,
-				const char *buf)
+static int cpuset_write_resmask(struct cgroup_subsys_state *css,
+				struct cftype *cft, const char *buf)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	struct cpuset *trialcs;
 	int retval = -ENODEV;
 
@@ -1761,13 +1754,12 @@
 	return count;
 }
 
-static ssize_t cpuset_common_file_read(struct cgroup *cgrp,
-				       struct cftype *cft,
-				       struct file *file,
-				       char __user *buf,
-				       size_t nbytes, loff_t *ppos)
+static ssize_t cpuset_common_file_read(struct cgroup_subsys_state *css,
+				       struct cftype *cft, struct file *file,
+				       char __user *buf, size_t nbytes,
+				       loff_t *ppos)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	cpuset_filetype_t type = cft->private;
 	char *page;
 	ssize_t retval = 0;
@@ -1797,9 +1789,9 @@
 	return retval;
 }
 
-static u64 cpuset_read_u64(struct cgroup *cgrp, struct cftype *cft)
+static u64 cpuset_read_u64(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	cpuset_filetype_t type = cft->private;
 	switch (type) {
 	case FILE_CPU_EXCLUSIVE:
@@ -1828,9 +1820,9 @@
 	return 0;
 }
 
-static s64 cpuset_read_s64(struct cgroup *cgrp, struct cftype *cft)
+static s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	cpuset_filetype_t type = cft->private;
 	switch (type) {
 	case FILE_SCHED_RELAX_DOMAIN_LEVEL:
@@ -1945,11 +1937,12 @@
  *	cgrp:	control group that the new cpuset will be part of
  */
 
-static struct cgroup_subsys_state *cpuset_css_alloc(struct cgroup *cgrp)
+static struct cgroup_subsys_state *
+cpuset_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct cpuset *cs;
 
-	if (!cgrp->parent)
+	if (!parent_css)
 		return &top_cpuset.css;
 
 	cs = kzalloc(sizeof(*cs), GFP_KERNEL);
@@ -1969,12 +1962,12 @@
 	return &cs->css;
 }
 
-static int cpuset_css_online(struct cgroup *cgrp)
+static int cpuset_css_online(struct cgroup_subsys_state *css)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 	struct cpuset *parent = parent_cs(cs);
 	struct cpuset *tmp_cs;
-	struct cgroup *pos_cg;
+	struct cgroup_subsys_state *pos_css;
 
 	if (!parent)
 		return 0;
@@ -1989,7 +1982,7 @@
 
 	number_of_cpusets++;
 
-	if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags))
+	if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags))
 		goto out_unlock;
 
 	/*
@@ -2006,7 +1999,7 @@
 	 * (and likewise for mems) to the new cgroup.
 	 */
 	rcu_read_lock();
-	cpuset_for_each_child(tmp_cs, pos_cg, parent) {
+	cpuset_for_each_child(tmp_cs, pos_css, parent) {
 		if (is_mem_exclusive(tmp_cs) || is_cpu_exclusive(tmp_cs)) {
 			rcu_read_unlock();
 			goto out_unlock;
@@ -2023,9 +2016,15 @@
 	return 0;
 }
 
-static void cpuset_css_offline(struct cgroup *cgrp)
+/*
+ * If the cpuset being removed has its flag 'sched_load_balance'
+ * enabled, then simulate turning sched_load_balance off, which
+ * will call rebuild_sched_domains_locked().
+ */
+
+static void cpuset_css_offline(struct cgroup_subsys_state *css)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 
 	mutex_lock(&cpuset_mutex);
 
@@ -2038,15 +2037,9 @@
 	mutex_unlock(&cpuset_mutex);
 }
 
-/*
- * If the cpuset being removed has its flag 'sched_load_balance'
- * enabled, then simulate turning sched_load_balance off, which
- * will call rebuild_sched_domains_locked().
- */
-
-static void cpuset_css_free(struct cgroup *cgrp)
+static void cpuset_css_free(struct cgroup_subsys_state *css)
 {
-	struct cpuset *cs = cgroup_cs(cgrp);
+	struct cpuset *cs = css_cs(css);
 
 	free_cpumask_var(cs->cpus_allowed);
 	kfree(cs);
@@ -2253,11 +2246,11 @@
 	/* if cpus or mems changed, we need to propagate to descendants */
 	if (cpus_updated || mems_updated) {
 		struct cpuset *cs;
-		struct cgroup *pos_cgrp;
+		struct cgroup_subsys_state *pos_css;
 
 		rcu_read_lock();
-		cpuset_for_each_descendant_pre(cs, pos_cgrp, &top_cpuset) {
-			if (!css_tryget(&cs->css))
+		cpuset_for_each_descendant_pre(cs, pos_css, &top_cpuset) {
+			if (cs == &top_cpuset || !css_tryget(&cs->css))
 				continue;
 			rcu_read_unlock();
 
@@ -2346,7 +2339,7 @@
 
 void cpuset_cpus_allowed_fallback(struct task_struct *tsk)
 {
-	const struct cpuset *cpus_cs;
+	struct cpuset *cpus_cs;
 
 	rcu_read_lock();
 	cpus_cs = effective_cpumask_cpuset(task_cs(tsk));
@@ -2419,7 +2412,7 @@
  * callback_mutex.  If no ancestor is mem_exclusive or mem_hardwall
  * (an unusual configuration), then returns the root cpuset.
  */
-static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
+static struct cpuset *nearest_hardwall_ancestor(struct cpuset *cs)
 {
 	while (!(is_mem_exclusive(cs) || is_mem_hardwall(cs)) && parent_cs(cs))
 		cs = parent_cs(cs);
@@ -2489,7 +2482,7 @@
  */
 int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 {
-	const struct cpuset *cs;	/* current cpuset ancestors */
+	struct cpuset *cs;		/* current cpuset ancestors */
 	int allowed;			/* is allocation in zone z allowed? */
 
 	if (in_interrupt() || (gfp_mask & __GFP_THISNODE))
@@ -2727,7 +2720,7 @@
 		goto out_free;
 
 	rcu_read_lock();
-	css = task_subsys_state(tsk, cpuset_subsys_id);
+	css = task_css(tsk, cpuset_subsys_id);
 	retval = cgroup_path(css->cgroup, buf, PAGE_SIZE);
 	rcu_read_unlock();
 	if (retval < 0)
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index c772061..97b67df 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -116,6 +116,9 @@
 
 	err = alloc_callchain_buffers();
 exit:
+	if (err)
+		atomic_dec(&nr_callchain_events);
+
 	mutex_unlock(&callchain_mutex);
 
 	return err;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index f86599e..2207efc 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -145,6 +145,7 @@
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
 static atomic_t nr_task_events __read_mostly;
+static atomic_t nr_freq_events __read_mostly;
 
 static LIST_HEAD(pmus);
 static DEFINE_MUTEX(pmus_lock);
@@ -340,8 +341,8 @@
 static inline struct perf_cgroup *
 perf_cgroup_from_task(struct task_struct *task)
 {
-	return container_of(task_subsys_state(task, perf_subsys_id),
-			struct perf_cgroup, css);
+	return container_of(task_css(task, perf_subsys_id),
+			    struct perf_cgroup, css);
 }
 
 static inline bool
@@ -591,7 +592,9 @@
 	if (!f.file)
 		return -EBADF;
 
-	css = cgroup_css_from_dir(f.file, perf_subsys_id);
+	rcu_read_lock();
+
+	css = css_from_dir(f.file->f_dentry, &perf_subsys);
 	if (IS_ERR(css)) {
 		ret = PTR_ERR(css);
 		goto out;
@@ -617,6 +620,7 @@
 		ret = -EINVAL;
 	}
 out:
+	rcu_read_unlock();
 	fdput(f);
 	return ret;
 }
@@ -869,12 +873,8 @@
 
 	WARN_ON(!irqs_disabled());
 
-	if (list_empty(&cpuctx->rotation_list)) {
-		int was_empty = list_empty(head);
+	if (list_empty(&cpuctx->rotation_list))
 		list_add(&cpuctx->rotation_list, head);
-		if (was_empty)
-			tick_nohz_full_kick();
-	}
 }
 
 static void get_ctx(struct perf_event_context *ctx)
@@ -1216,6 +1216,9 @@
 	if (sample_type & PERF_SAMPLE_TIME)
 		size += sizeof(data->time);
 
+	if (sample_type & PERF_SAMPLE_IDENTIFIER)
+		size += sizeof(data->id);
+
 	if (sample_type & PERF_SAMPLE_ID)
 		size += sizeof(data->id);
 
@@ -2712,7 +2715,7 @@
 
 		hwc = &event->hw;
 
-		if (needs_unthr && hwc->interrupts == MAX_INTERRUPTS) {
+		if (hwc->interrupts == MAX_INTERRUPTS) {
 			hwc->interrupts = 0;
 			perf_log_throttle(event, 1);
 			event->pmu->start(event, 0);
@@ -2811,10 +2814,11 @@
 #ifdef CONFIG_NO_HZ_FULL
 bool perf_event_can_stop_tick(void)
 {
-	if (list_empty(&__get_cpu_var(rotation_list)))
-		return true;
-	else
+	if (atomic_read(&nr_freq_events) ||
+	    __this_cpu_read(perf_throttled_count))
 		return false;
+	else
+		return true;
 }
 #endif
 
@@ -3128,35 +3132,62 @@
 static void ring_buffer_put(struct ring_buffer *rb);
 static void ring_buffer_detach(struct perf_event *event, struct ring_buffer *rb);
 
+static void unaccount_event_cpu(struct perf_event *event, int cpu)
+{
+	if (event->parent)
+		return;
+
+	if (has_branch_stack(event)) {
+		if (!(event->attach_state & PERF_ATTACH_TASK))
+			atomic_dec(&per_cpu(perf_branch_stack_events, cpu));
+	}
+	if (is_cgroup_event(event))
+		atomic_dec(&per_cpu(perf_cgroup_events, cpu));
+}
+
+static void unaccount_event(struct perf_event *event)
+{
+	if (event->parent)
+		return;
+
+	if (event->attach_state & PERF_ATTACH_TASK)
+		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)
+		atomic_dec(&nr_comm_events);
+	if (event->attr.task)
+		atomic_dec(&nr_task_events);
+	if (event->attr.freq)
+		atomic_dec(&nr_freq_events);
+	if (is_cgroup_event(event))
+		static_key_slow_dec_deferred(&perf_sched_events);
+	if (has_branch_stack(event))
+		static_key_slow_dec_deferred(&perf_sched_events);
+
+	unaccount_event_cpu(event, event->cpu);
+}
+
+static void __free_event(struct perf_event *event)
+{
+	if (!event->parent) {
+		if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
+			put_callchain_buffers();
+	}
+
+	if (event->destroy)
+		event->destroy(event);
+
+	if (event->ctx)
+		put_ctx(event->ctx);
+
+	call_rcu(&event->rcu_head, free_event_rcu);
+}
 static void free_event(struct perf_event *event)
 {
 	irq_work_sync(&event->pending);
 
-	if (!event->parent) {
-		if (event->attach_state & PERF_ATTACH_TASK)
-			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)
-			atomic_dec(&nr_comm_events);
-		if (event->attr.task)
-			atomic_dec(&nr_task_events);
-		if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
-			put_callchain_buffers();
-		if (is_cgroup_event(event)) {
-			atomic_dec(&per_cpu(perf_cgroup_events, event->cpu));
-			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));
-			}
-		}
-	}
+	unaccount_event(event);
 
 	if (event->rb) {
 		struct ring_buffer *rb;
@@ -3180,13 +3211,8 @@
 	if (is_cgroup_event(event))
 		perf_detach_cgroup(event);
 
-	if (event->destroy)
-		event->destroy(event);
 
-	if (event->ctx)
-		put_ctx(event->ctx);
-
-	call_rcu(&event->rcu_head, free_event_rcu);
+	__free_event(event);
 }
 
 int perf_event_release_kernel(struct perf_event *event)
@@ -3544,6 +3570,15 @@
 	case PERF_EVENT_IOC_PERIOD:
 		return perf_event_period(event, (u64 __user *)arg);
 
+	case PERF_EVENT_IOC_ID:
+	{
+		u64 id = primary_event_id(event);
+
+		if (copy_to_user((void __user *)arg, &id, sizeof(id)))
+			return -EFAULT;
+		return 0;
+	}
+
 	case PERF_EVENT_IOC_SET_OUTPUT:
 	{
 		int ret;
@@ -3641,6 +3676,10 @@
 	u64 enabled, running, now;
 
 	rcu_read_lock();
+	rb = rcu_dereference(event->rb);
+	if (!rb)
+		goto unlock;
+
 	/*
 	 * compute total_time_enabled, total_time_running
 	 * based on snapshot values taken when the event
@@ -3651,12 +3690,8 @@
 	 * NMI context
 	 */
 	calc_timer_values(event, &now, &enabled, &running);
-	rb = rcu_dereference(event->rb);
-	if (!rb)
-		goto unlock;
 
 	userpg = rb->user_page;
-
 	/*
 	 * Disable preemption so as to not let the corresponding user-space
 	 * spin too long if we get preempted.
@@ -4251,7 +4286,7 @@
 	if (sample_type & PERF_SAMPLE_TIME)
 		data->time = perf_clock();
 
-	if (sample_type & PERF_SAMPLE_ID)
+	if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER))
 		data->id = primary_event_id(event);
 
 	if (sample_type & PERF_SAMPLE_STREAM_ID)
@@ -4290,6 +4325,9 @@
 
 	if (sample_type & PERF_SAMPLE_CPU)
 		perf_output_put(handle, data->cpu_entry);
+
+	if (sample_type & PERF_SAMPLE_IDENTIFIER)
+		perf_output_put(handle, data->id);
 }
 
 void perf_event__output_id_sample(struct perf_event *event,
@@ -4355,7 +4393,8 @@
 	list_for_each_entry(sub, &leader->sibling_list, group_entry) {
 		n = 0;
 
-		if (sub != event)
+		if ((sub != event) &&
+		    (sub->state == PERF_EVENT_STATE_ACTIVE))
 			sub->pmu->read(sub);
 
 		values[n++] = perf_event_count(sub);
@@ -4402,6 +4441,9 @@
 
 	perf_output_put(handle, *header);
 
+	if (sample_type & PERF_SAMPLE_IDENTIFIER)
+		perf_output_put(handle, data->id);
+
 	if (sample_type & PERF_SAMPLE_IP)
 		perf_output_put(handle, data->ip);
 
@@ -4462,20 +4504,6 @@
 		}
 	}
 
-	if (!event->attr.watermark) {
-		int wakeup_events = event->attr.wakeup_events;
-
-		if (wakeup_events) {
-			struct ring_buffer *rb = handle->rb;
-			int events = local_inc_return(&rb->events);
-
-			if (events >= wakeup_events) {
-				local_sub(wakeup_events, &rb->events);
-				local_inc(&rb->wakeup);
-			}
-		}
-	}
-
 	if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
 		if (data->br_stack) {
 			size_t size;
@@ -4511,16 +4539,31 @@
 		}
 	}
 
-	if (sample_type & PERF_SAMPLE_STACK_USER)
+	if (sample_type & PERF_SAMPLE_STACK_USER) {
 		perf_output_sample_ustack(handle,
 					  data->stack_user_size,
 					  data->regs_user.regs);
+	}
 
 	if (sample_type & PERF_SAMPLE_WEIGHT)
 		perf_output_put(handle, data->weight);
 
 	if (sample_type & PERF_SAMPLE_DATA_SRC)
 		perf_output_put(handle, data->data_src.val);
+
+	if (!event->attr.watermark) {
+		int wakeup_events = event->attr.wakeup_events;
+
+		if (wakeup_events) {
+			struct ring_buffer *rb = handle->rb;
+			int events = local_inc_return(&rb->events);
+
+			if (events >= wakeup_events) {
+				local_sub(wakeup_events, &rb->events);
+				local_inc(&rb->wakeup);
+			}
+		}
+	}
 }
 
 void perf_prepare_sample(struct perf_event_header *header,
@@ -4680,12 +4723,10 @@
 	perf_output_end(&handle);
 }
 
-typedef int  (perf_event_aux_match_cb)(struct perf_event *event, void *data);
 typedef void (perf_event_aux_output_cb)(struct perf_event *event, void *data);
 
 static void
 perf_event_aux_ctx(struct perf_event_context *ctx,
-		   perf_event_aux_match_cb match,
 		   perf_event_aux_output_cb output,
 		   void *data)
 {
@@ -4696,15 +4737,12 @@
 			continue;
 		if (!event_filter_match(event))
 			continue;
-		if (match(event, data))
-			output(event, data);
+		output(event, data);
 	}
 }
 
 static void
-perf_event_aux(perf_event_aux_match_cb match,
-	       perf_event_aux_output_cb output,
-	       void *data,
+perf_event_aux(perf_event_aux_output_cb output, void *data,
 	       struct perf_event_context *task_ctx)
 {
 	struct perf_cpu_context *cpuctx;
@@ -4717,7 +4755,7 @@
 		cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
 		if (cpuctx->unique_pmu != pmu)
 			goto next;
-		perf_event_aux_ctx(&cpuctx->ctx, match, output, data);
+		perf_event_aux_ctx(&cpuctx->ctx, output, data);
 		if (task_ctx)
 			goto next;
 		ctxn = pmu->task_ctx_nr;
@@ -4725,14 +4763,14 @@
 			goto next;
 		ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
 		if (ctx)
-			perf_event_aux_ctx(ctx, match, output, data);
+			perf_event_aux_ctx(ctx, output, data);
 next:
 		put_cpu_ptr(pmu->pmu_cpu_context);
 	}
 
 	if (task_ctx) {
 		preempt_disable();
-		perf_event_aux_ctx(task_ctx, match, output, data);
+		perf_event_aux_ctx(task_ctx, output, data);
 		preempt_enable();
 	}
 	rcu_read_unlock();
@@ -4741,7 +4779,7 @@
 /*
  * task tracking -- fork/exit
  *
- * enabled by: attr.comm | attr.mmap | attr.mmap_data | attr.task
+ * enabled by: attr.comm | attr.mmap | attr.mmap2 | attr.mmap_data | attr.task
  */
 
 struct perf_task_event {
@@ -4759,6 +4797,13 @@
 	} event_id;
 };
 
+static int perf_event_task_match(struct perf_event *event)
+{
+	return event->attr.comm  || event->attr.mmap ||
+	       event->attr.mmap2 || event->attr.mmap_data ||
+	       event->attr.task;
+}
+
 static void perf_event_task_output(struct perf_event *event,
 				   void *data)
 {
@@ -4768,6 +4813,9 @@
 	struct task_struct *task = task_event->task;
 	int ret, size = task_event->event_id.header.size;
 
+	if (!perf_event_task_match(event))
+		return;
+
 	perf_event_header__init_id(&task_event->event_id.header, &sample, event);
 
 	ret = perf_output_begin(&handle, event,
@@ -4790,13 +4838,6 @@
 	task_event->event_id.header.size = size;
 }
 
-static int perf_event_task_match(struct perf_event *event,
-				 void *data __maybe_unused)
-{
-	return event->attr.comm || event->attr.mmap ||
-	       event->attr.mmap_data || event->attr.task;
-}
-
 static void perf_event_task(struct task_struct *task,
 			      struct perf_event_context *task_ctx,
 			      int new)
@@ -4825,8 +4866,7 @@
 		},
 	};
 
-	perf_event_aux(perf_event_task_match,
-		       perf_event_task_output,
+	perf_event_aux(perf_event_task_output,
 		       &task_event,
 		       task_ctx);
 }
@@ -4853,6 +4893,11 @@
 	} event_id;
 };
 
+static int perf_event_comm_match(struct perf_event *event)
+{
+	return event->attr.comm;
+}
+
 static void perf_event_comm_output(struct perf_event *event,
 				   void *data)
 {
@@ -4862,6 +4907,9 @@
 	int size = comm_event->event_id.header.size;
 	int ret;
 
+	if (!perf_event_comm_match(event))
+		return;
+
 	perf_event_header__init_id(&comm_event->event_id.header, &sample, event);
 	ret = perf_output_begin(&handle, event,
 				comm_event->event_id.header.size);
@@ -4883,12 +4931,6 @@
 	comm_event->event_id.header.size = size;
 }
 
-static int perf_event_comm_match(struct perf_event *event,
-				 void *data __maybe_unused)
-{
-	return event->attr.comm;
-}
-
 static void perf_event_comm_event(struct perf_comm_event *comm_event)
 {
 	char comm[TASK_COMM_LEN];
@@ -4903,8 +4945,7 @@
 
 	comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
 
-	perf_event_aux(perf_event_comm_match,
-		       perf_event_comm_output,
+	perf_event_aux(perf_event_comm_output,
 		       comm_event,
 		       NULL);
 }
@@ -4955,6 +4996,9 @@
 
 	const char		*file_name;
 	int			file_size;
+	int			maj, min;
+	u64			ino;
+	u64			ino_generation;
 
 	struct {
 		struct perf_event_header	header;
@@ -4967,6 +5011,17 @@
 	} event_id;
 };
 
+static int perf_event_mmap_match(struct perf_event *event,
+				 void *data)
+{
+	struct perf_mmap_event *mmap_event = data;
+	struct vm_area_struct *vma = mmap_event->vma;
+	int executable = vma->vm_flags & VM_EXEC;
+
+	return (!executable && event->attr.mmap_data) ||
+	       (executable && (event->attr.mmap || event->attr.mmap2));
+}
+
 static void perf_event_mmap_output(struct perf_event *event,
 				   void *data)
 {
@@ -4976,6 +5031,16 @@
 	int size = mmap_event->event_id.header.size;
 	int ret;
 
+	if (!perf_event_mmap_match(event, data))
+		return;
+
+	if (event->attr.mmap2) {
+		mmap_event->event_id.header.type = PERF_RECORD_MMAP2;
+		mmap_event->event_id.header.size += sizeof(mmap_event->maj);
+		mmap_event->event_id.header.size += sizeof(mmap_event->min);
+		mmap_event->event_id.header.size += sizeof(mmap_event->ino);
+	}
+
 	perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
 	ret = perf_output_begin(&handle, event,
 				mmap_event->event_id.header.size);
@@ -4986,6 +5051,14 @@
 	mmap_event->event_id.tid = perf_event_tid(event, current);
 
 	perf_output_put(&handle, mmap_event->event_id);
+
+	if (event->attr.mmap2) {
+		perf_output_put(&handle, mmap_event->maj);
+		perf_output_put(&handle, mmap_event->min);
+		perf_output_put(&handle, mmap_event->ino);
+		perf_output_put(&handle, mmap_event->ino_generation);
+	}
+
 	__output_copy(&handle, mmap_event->file_name,
 				   mmap_event->file_size);
 
@@ -4996,21 +5069,12 @@
 	mmap_event->event_id.header.size = size;
 }
 
-static int perf_event_mmap_match(struct perf_event *event,
-				 void *data)
-{
-	struct perf_mmap_event *mmap_event = data;
-	struct vm_area_struct *vma = mmap_event->vma;
-	int executable = vma->vm_flags & VM_EXEC;
-
-	return (!executable && event->attr.mmap_data) ||
-	       (executable && event->attr.mmap);
-}
-
 static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
 {
 	struct vm_area_struct *vma = mmap_event->vma;
 	struct file *file = vma->vm_file;
+	int maj = 0, min = 0;
+	u64 ino = 0, gen = 0;
 	unsigned int size;
 	char tmp[16];
 	char *buf = NULL;
@@ -5019,6 +5083,8 @@
 	memset(tmp, 0, sizeof(tmp));
 
 	if (file) {
+		struct inode *inode;
+		dev_t dev;
 		/*
 		 * d_path works from the end of the rb backwards, so we
 		 * need to add enough zero bytes after the string to handle
@@ -5034,6 +5100,13 @@
 			name = strncpy(tmp, "//toolong", sizeof(tmp));
 			goto got_name;
 		}
+		inode = file_inode(vma->vm_file);
+		dev = inode->i_sb->s_dev;
+		ino = inode->i_ino;
+		gen = inode->i_generation;
+		maj = MAJOR(dev);
+		min = MINOR(dev);
+
 	} else {
 		if (arch_vma_name(mmap_event->vma)) {
 			name = strncpy(tmp, arch_vma_name(mmap_event->vma),
@@ -5064,14 +5137,17 @@
 
 	mmap_event->file_name = name;
 	mmap_event->file_size = size;
+	mmap_event->maj = maj;
+	mmap_event->min = min;
+	mmap_event->ino = ino;
+	mmap_event->ino_generation = gen;
 
 	if (!(vma->vm_flags & VM_EXEC))
 		mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
 
 	mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
 
-	perf_event_aux(perf_event_mmap_match,
-		       perf_event_mmap_output,
+	perf_event_aux(perf_event_mmap_output,
 		       mmap_event,
 		       NULL);
 
@@ -5101,6 +5177,10 @@
 			.len    = vma->vm_end - vma->vm_start,
 			.pgoff  = (u64)vma->vm_pgoff << PAGE_SHIFT,
 		},
+		/* .maj (attr_mmap2 only) */
+		/* .min (attr_mmap2 only) */
+		/* .ino (attr_mmap2 only) */
+		/* .ino_generation (attr_mmap2 only) */
 	};
 
 	perf_event_mmap_event(&mmap_event);
@@ -5178,6 +5258,7 @@
 			__this_cpu_inc(perf_throttled_count);
 			hwc->interrupts = MAX_INTERRUPTS;
 			perf_log_throttle(event, 0);
+			tick_nohz_full_kick();
 			ret = 1;
 		}
 	}
@@ -6443,6 +6524,44 @@
 	return pmu;
 }
 
+static void account_event_cpu(struct perf_event *event, int cpu)
+{
+	if (event->parent)
+		return;
+
+	if (has_branch_stack(event)) {
+		if (!(event->attach_state & PERF_ATTACH_TASK))
+			atomic_inc(&per_cpu(perf_branch_stack_events, cpu));
+	}
+	if (is_cgroup_event(event))
+		atomic_inc(&per_cpu(perf_cgroup_events, cpu));
+}
+
+static void account_event(struct perf_event *event)
+{
+	if (event->parent)
+		return;
+
+	if (event->attach_state & PERF_ATTACH_TASK)
+		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)
+		atomic_inc(&nr_comm_events);
+	if (event->attr.task)
+		atomic_inc(&nr_task_events);
+	if (event->attr.freq) {
+		if (atomic_inc_return(&nr_freq_events) == 1)
+			tick_nohz_full_kick_all();
+	}
+	if (has_branch_stack(event))
+		static_key_slow_inc(&perf_sched_events.key);
+	if (is_cgroup_event(event))
+		static_key_slow_inc(&perf_sched_events.key);
+
+	account_event_cpu(event, event->cpu);
+}
+
 /*
  * Allocate and initialize a event structure
  */
@@ -6457,7 +6576,7 @@
 	struct pmu *pmu;
 	struct perf_event *event;
 	struct hw_perf_event *hwc;
-	long err;
+	long err = -EINVAL;
 
 	if ((unsigned)cpu >= nr_cpu_ids) {
 		if (!task || cpu != -1)
@@ -6540,49 +6659,35 @@
 	 * we currently do not support PERF_FORMAT_GROUP on inherited events
 	 */
 	if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
-		goto done;
+		goto err_ns;
 
 	pmu = perf_init_event(event);
-
-done:
-	err = 0;
 	if (!pmu)
-		err = -EINVAL;
-	else if (IS_ERR(pmu))
+		goto err_ns;
+	else if (IS_ERR(pmu)) {
 		err = PTR_ERR(pmu);
-
-	if (err) {
-		if (event->ns)
-			put_pid_ns(event->ns);
-		kfree(event);
-		return ERR_PTR(err);
+		goto err_ns;
 	}
 
 	if (!event->parent) {
-		if (event->attach_state & PERF_ATTACH_TASK)
-			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)
-			atomic_inc(&nr_comm_events);
-		if (event->attr.task)
-			atomic_inc(&nr_task_events);
 		if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
 			err = get_callchain_buffers();
-			if (err) {
-				free_event(event);
-				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));
+			if (err)
+				goto err_pmu;
 		}
 	}
 
 	return event;
+
+err_pmu:
+	if (event->destroy)
+		event->destroy(event);
+err_ns:
+	if (event->ns)
+		put_pid_ns(event->ns);
+	kfree(event);
+
+	return ERR_PTR(err);
 }
 
 static int perf_copy_attr(struct perf_event_attr __user *uattr,
@@ -6864,17 +6969,14 @@
 
 	if (flags & PERF_FLAG_PID_CGROUP) {
 		err = perf_cgroup_connect(pid, event, &attr, group_leader);
-		if (err)
-			goto err_alloc;
-		/*
-		 * one more event:
-		 * - that has cgroup constraint on event->cpu
-		 * - that may need work on context switch
-		 */
-		atomic_inc(&per_cpu(perf_cgroup_events, event->cpu));
-		static_key_slow_inc(&perf_sched_events.key);
+		if (err) {
+			__free_event(event);
+			goto err_task;
+		}
 	}
 
+	account_event(event);
+
 	/*
 	 * Special case software events and allow them to be part of
 	 * any hardware group.
@@ -7070,6 +7172,8 @@
 		goto err;
 	}
 
+	account_event(event);
+
 	ctx = find_get_context(event->pmu, task, cpu);
 	if (IS_ERR(ctx)) {
 		err = PTR_ERR(ctx);
@@ -7106,6 +7210,7 @@
 	list_for_each_entry_safe(event, tmp, &src_ctx->event_list,
 				 event_entry) {
 		perf_remove_from_context(event);
+		unaccount_event_cpu(event, src_cpu);
 		put_ctx(src_ctx);
 		list_add(&event->event_entry, &events);
 	}
@@ -7118,6 +7223,7 @@
 		list_del(&event->event_entry);
 		if (event->state >= PERF_EVENT_STATE_OFF)
 			event->state = PERF_EVENT_STATE_INACTIVE;
+		account_event_cpu(event, dst_cpu);
 		perf_install_in_context(dst_ctx, event, dst_cpu);
 		get_ctx(dst_ctx);
 	}
@@ -7798,7 +7904,8 @@
 device_initcall(perf_event_sysfs_init);
 
 #ifdef CONFIG_CGROUP_PERF
-static struct cgroup_subsys_state *perf_cgroup_css_alloc(struct cgroup *cont)
+static struct cgroup_subsys_state *
+perf_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct perf_cgroup *jc;
 
@@ -7815,11 +7922,10 @@
 	return &jc->css;
 }
 
-static void perf_cgroup_css_free(struct cgroup *cont)
+static void perf_cgroup_css_free(struct cgroup_subsys_state *css)
 {
-	struct perf_cgroup *jc;
-	jc = container_of(cgroup_subsys_state(cont, perf_subsys_id),
-			  struct perf_cgroup, css);
+	struct perf_cgroup *jc = container_of(css, struct perf_cgroup, css);
+
 	free_percpu(jc->info);
 	kfree(jc);
 }
@@ -7831,15 +7937,17 @@
 	return 0;
 }
 
-static void perf_cgroup_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static void perf_cgroup_attach(struct cgroup_subsys_state *css,
+			       struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 
-	cgroup_taskset_for_each(task, cgrp, tset)
+	cgroup_taskset_for_each(task, css, tset)
 		task_function_call(task, __perf_cgroup_move, task);
 }
 
-static void perf_cgroup_exit(struct cgroup *cgrp, struct cgroup *old_cgrp,
+static void perf_cgroup_exit(struct cgroup_subsys_state *css,
+			     struct cgroup_subsys_state *old_css,
 			     struct task_struct *task)
 {
 	/*
diff --git a/kernel/fork.c b/kernel/fork.c
index e23bb19..bf46287 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1177,7 +1177,8 @@
 	 * don't allow the creation of threads.
 	 */
 	if ((clone_flags & (CLONE_VM|CLONE_NEWPID)) &&
-	    (task_active_pid_ns(current) != current->nsproxy->pid_ns))
+	    (task_active_pid_ns(current) !=
+	     current->nsproxy->pid_ns_for_children))
 		return ERR_PTR(-EINVAL);
 
 	retval = security_task_create(clone_flags);
@@ -1351,7 +1352,7 @@
 
 	if (pid != &init_struct_pid) {
 		retval = -ENOMEM;
-		pid = alloc_pid(p->nsproxy->pid_ns);
+		pid = alloc_pid(p->nsproxy->pid_ns_for_children);
 		if (!pid)
 			goto bad_fork_cleanup_io;
 	}
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index 6df6149..3e97fb1 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -15,6 +15,7 @@
 #include <linux/lockdep.h>
 #include <linux/export.h>
 #include <linux/sysctl.h>
+#include <linux/utsname.h>
 
 /*
  * The number of tasks checked:
@@ -99,10 +100,14 @@
 	 * Ok, the task did not get scheduled for more than 2 minutes,
 	 * complain:
 	 */
-	printk(KERN_ERR "INFO: task %s:%d blocked for more than "
-			"%ld seconds.\n", t->comm, t->pid, timeout);
-	printk(KERN_ERR "\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
-			" disables this message.\n");
+	pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n",
+		t->comm, t->pid, timeout);
+	pr_err("      %s %s %.*s\n",
+		print_tainted(), init_utsname()->release,
+		(int)strcspn(init_utsname()->version, " "),
+		init_utsname()->version);
+	pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
+		" disables this message.\n");
 	sched_show_task(t);
 	debug_show_held_locks(t);
 
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index 60f48fa..297a924 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -13,6 +13,7 @@
 #include <linux/sort.h>
 #include <linux/err.h>
 #include <linux/static_key.h>
+#include <linux/jump_label_ratelimit.h>
 
 #ifdef HAVE_JUMP_LABEL
 
diff --git a/kernel/lglock.c b/kernel/lglock.c
index 6535a66..86ae2ae 100644
--- a/kernel/lglock.c
+++ b/kernel/lglock.c
@@ -21,7 +21,7 @@
 	arch_spinlock_t *lock;
 
 	preempt_disable();
-	rwlock_acquire_read(&lg->lock_dep_map, 0, 0, _RET_IP_);
+	lock_acquire_shared(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_);
 	lock = this_cpu_ptr(lg->lock);
 	arch_spin_lock(lock);
 }
@@ -31,7 +31,7 @@
 {
 	arch_spinlock_t *lock;
 
-	rwlock_release(&lg->lock_dep_map, 1, _RET_IP_);
+	lock_release(&lg->lock_dep_map, 1, _RET_IP_);
 	lock = this_cpu_ptr(lg->lock);
 	arch_spin_unlock(lock);
 	preempt_enable();
@@ -43,7 +43,7 @@
 	arch_spinlock_t *lock;
 
 	preempt_disable();
-	rwlock_acquire_read(&lg->lock_dep_map, 0, 0, _RET_IP_);
+	lock_acquire_shared(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_);
 	lock = per_cpu_ptr(lg->lock, cpu);
 	arch_spin_lock(lock);
 }
@@ -53,7 +53,7 @@
 {
 	arch_spinlock_t *lock;
 
-	rwlock_release(&lg->lock_dep_map, 1, _RET_IP_);
+	lock_release(&lg->lock_dep_map, 1, _RET_IP_);
 	lock = per_cpu_ptr(lg->lock, cpu);
 	arch_spin_unlock(lock);
 	preempt_enable();
@@ -65,7 +65,7 @@
 	int i;
 
 	preempt_disable();
-	rwlock_acquire(&lg->lock_dep_map, 0, 0, _RET_IP_);
+	lock_acquire_exclusive(&lg->lock_dep_map, 0, 0, NULL, _RET_IP_);
 	for_each_possible_cpu(i) {
 		arch_spinlock_t *lock;
 		lock = per_cpu_ptr(lg->lock, i);
@@ -78,7 +78,7 @@
 {
 	int i;
 
-	rwlock_release(&lg->lock_dep_map, 1, _RET_IP_);
+	lock_release(&lg->lock_dep_map, 1, _RET_IP_);
 	for_each_possible_cpu(i) {
 		arch_spinlock_t *lock;
 		lock = per_cpu_ptr(lg->lock, i);
diff --git a/kernel/module.c b/kernel/module.c
index c6756d1..dc58274 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -136,6 +136,7 @@
 }
 
 static const struct kernel_param_ops param_ops_bool_enable_only = {
+	.flags = KERNEL_PARAM_FL_NOARG,
 	.set = param_set_bool_enable_only,
 	.get = param_get_bool,
 };
@@ -603,7 +604,7 @@
 static ssize_t show_modinfo_##field(struct module_attribute *mattr,   \
 			struct module_kobject *mk, char *buffer)      \
 {                                                                     \
-	return sprintf(buffer, "%s\n", mk->mod->field);               \
+	return scnprintf(buffer, PAGE_SIZE, "%s\n", mk->mod->field);  \
 }                                                                     \
 static int modinfo_##field##_exists(struct module *mod)               \
 {                                                                     \
@@ -1611,6 +1612,14 @@
 	kfree(mod->modinfo_attrs);
 }
 
+static void mod_kobject_put(struct module *mod)
+{
+	DECLARE_COMPLETION_ONSTACK(c);
+	mod->mkobj.kobj_completion = &c;
+	kobject_put(&mod->mkobj.kobj);
+	wait_for_completion(&c);
+}
+
 static int mod_sysfs_init(struct module *mod)
 {
 	int err;
@@ -1638,7 +1647,7 @@
 	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
 				   "%s", mod->name);
 	if (err)
-		kobject_put(&mod->mkobj.kobj);
+		mod_kobject_put(mod);
 
 	/* delay uevent until full sysfs population */
 out:
@@ -1682,7 +1691,7 @@
 out_unreg_holders:
 	kobject_put(mod->holders_dir);
 out_unreg:
-	kobject_put(&mod->mkobj.kobj);
+	mod_kobject_put(mod);
 out:
 	return err;
 }
@@ -1691,7 +1700,7 @@
 {
 	remove_notes_attrs(mod);
 	remove_sect_attrs(mod);
-	kobject_put(&mod->mkobj.kobj);
+	mod_kobject_put(mod);
 }
 
 #else /* !CONFIG_SYSFS */
diff --git a/kernel/mutex.c b/kernel/mutex.c
index a52ee7bb..6d647ae 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -209,11 +209,13 @@
  */
 static inline int mutex_can_spin_on_owner(struct mutex *lock)
 {
+	struct task_struct *owner;
 	int retval = 1;
 
 	rcu_read_lock();
-	if (lock->owner)
-		retval = lock->owner->on_cpu;
+	owner = ACCESS_ONCE(lock->owner);
+	if (owner)
+		retval = owner->on_cpu;
 	rcu_read_unlock();
 	/*
 	 * if lock->owner is not set, the mutex owner may have just acquired
@@ -461,7 +463,7 @@
 			 * performed the optimistic spinning cannot be done.
 			 */
 			if (ACCESS_ONCE(ww->ctx))
-				break;
+				goto slowpath;
 		}
 
 		/*
@@ -472,7 +474,7 @@
 		owner = ACCESS_ONCE(lock->owner);
 		if (owner && !mutex_spin_on_owner(lock, owner)) {
 			mspin_unlock(MLOCK(lock), &node);
-			break;
+			goto slowpath;
 		}
 
 		if ((atomic_read(&lock->count) == 1) &&
@@ -499,7 +501,7 @@
 		 * the owner complete.
 		 */
 		if (!owner && (need_resched() || rt_task(task)))
-			break;
+			goto slowpath;
 
 		/*
 		 * The cpu_relax() call is a compiler barrier which forces
@@ -513,6 +515,10 @@
 #endif
 	spin_lock_mutex(&lock->wait_lock, flags);
 
+	/* once more, can we acquire the lock? */
+	if (MUTEX_SHOW_NO_WAITER(lock) && (atomic_xchg(&lock->count, 0) == 1))
+		goto skip_wait;
+
 	debug_mutex_lock_common(lock, &waiter);
 	debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
 
@@ -520,9 +526,6 @@
 	list_add_tail(&waiter.list, &lock->wait_list);
 	waiter.task = task;
 
-	if (MUTEX_SHOW_NO_WAITER(lock) && (atomic_xchg(&lock->count, -1) == 1))
-		goto done;
-
 	lock_contended(&lock->dep_map, ip);
 
 	for (;;) {
@@ -536,7 +539,7 @@
 		 * other waiters:
 		 */
 		if (MUTEX_SHOW_NO_WAITER(lock) &&
-		   (atomic_xchg(&lock->count, -1) == 1))
+		    (atomic_xchg(&lock->count, -1) == 1))
 			break;
 
 		/*
@@ -561,24 +564,25 @@
 		schedule_preempt_disabled();
 		spin_lock_mutex(&lock->wait_lock, flags);
 	}
-
-done:
-	lock_acquired(&lock->dep_map, ip);
-	/* got the lock - rejoice! */
 	mutex_remove_waiter(lock, &waiter, current_thread_info());
+	/* set it to 0 if there are no waiters left: */
+	if (likely(list_empty(&lock->wait_list)))
+		atomic_set(&lock->count, 0);
+	debug_mutex_free_waiter(&waiter);
+
+skip_wait:
+	/* got the lock - cleanup and rejoice! */
+	lock_acquired(&lock->dep_map, ip);
 	mutex_set_owner(lock);
 
 	if (!__builtin_constant_p(ww_ctx == NULL)) {
-		struct ww_mutex *ww = container_of(lock,
-						      struct ww_mutex,
-						      base);
+		struct ww_mutex *ww = container_of(lock, struct ww_mutex, base);
 		struct mutex_waiter *cur;
 
 		/*
 		 * This branch gets optimized out for the common case,
 		 * and is only important for ww_mutex_lock.
 		 */
-
 		ww_mutex_lock_acquired(ww, ww_ctx);
 		ww->ctx = ww_ctx;
 
@@ -592,15 +596,8 @@
 		}
 	}
 
-	/* set it to 0 if there are no waiters left: */
-	if (likely(list_empty(&lock->wait_list)))
-		atomic_set(&lock->count, 0);
-
 	spin_unlock_mutex(&lock->wait_lock, flags);
-
-	debug_mutex_free_waiter(&waiter);
 	preempt_enable();
-
 	return 0;
 
 err:
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 364ceab..997cbb9 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -29,15 +29,15 @@
 static struct kmem_cache *nsproxy_cachep;
 
 struct nsproxy init_nsproxy = {
-	.count	= ATOMIC_INIT(1),
-	.uts_ns	= &init_uts_ns,
+	.count			= ATOMIC_INIT(1),
+	.uts_ns			= &init_uts_ns,
 #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
-	.ipc_ns	= &init_ipc_ns,
+	.ipc_ns			= &init_ipc_ns,
 #endif
-	.mnt_ns	= NULL,
-	.pid_ns	= &init_pid_ns,
+	.mnt_ns			= NULL,
+	.pid_ns_for_children	= &init_pid_ns,
 #ifdef CONFIG_NET
-	.net_ns	= &init_net,
+	.net_ns			= &init_net,
 #endif
 };
 
@@ -85,9 +85,10 @@
 		goto out_ipc;
 	}
 
-	new_nsp->pid_ns = copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns);
-	if (IS_ERR(new_nsp->pid_ns)) {
-		err = PTR_ERR(new_nsp->pid_ns);
+	new_nsp->pid_ns_for_children =
+		copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);
+	if (IS_ERR(new_nsp->pid_ns_for_children)) {
+		err = PTR_ERR(new_nsp->pid_ns_for_children);
 		goto out_pid;
 	}
 
@@ -100,8 +101,8 @@
 	return new_nsp;
 
 out_net:
-	if (new_nsp->pid_ns)
-		put_pid_ns(new_nsp->pid_ns);
+	if (new_nsp->pid_ns_for_children)
+		put_pid_ns(new_nsp->pid_ns_for_children);
 out_pid:
 	if (new_nsp->ipc_ns)
 		put_ipc_ns(new_nsp->ipc_ns);
@@ -174,8 +175,8 @@
 		put_uts_ns(ns->uts_ns);
 	if (ns->ipc_ns)
 		put_ipc_ns(ns->ipc_ns);
-	if (ns->pid_ns)
-		put_pid_ns(ns->pid_ns);
+	if (ns->pid_ns_for_children)
+		put_pid_ns(ns->pid_ns_for_children);
 	put_net(ns->net_ns);
 	kmem_cache_free(nsproxy_cachep, ns);
 }
diff --git a/kernel/params.c b/kernel/params.c
index 440e65d..501bde4 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -103,8 +103,8 @@
 			    || params[i].level > max_level)
 				return 0;
 			/* No one handled NULL, so do it here. */
-			if (!val && params[i].ops->set != param_set_bool
-			    && params[i].ops->set != param_set_bint)
+			if (!val &&
+			    !(params[i].ops->flags & KERNEL_PARAM_FL_NOARG))
 				return -EINVAL;
 			pr_debug("handling %s with %p\n", param,
 				params[i].ops->set);
@@ -241,7 +241,8 @@
 	}								\
 	int param_get_##name(char *buffer, const struct kernel_param *kp) \
 	{								\
-		return sprintf(buffer, format, *((type *)kp->arg));	\
+		return scnprintf(buffer, PAGE_SIZE, format,		\
+				*((type *)kp->arg));			\
 	}								\
 	struct kernel_param_ops param_ops_##name = {			\
 		.set = param_set_##name,				\
@@ -252,7 +253,7 @@
 	EXPORT_SYMBOL(param_ops_##name)
 
 
-STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
+STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", unsigned long, strict_strtoul);
 STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
 STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul);
 STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol);
@@ -285,7 +286,7 @@
 
 int param_get_charp(char *buffer, const struct kernel_param *kp)
 {
-	return sprintf(buffer, "%s", *((char **)kp->arg));
+	return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg));
 }
 EXPORT_SYMBOL(param_get_charp);
 
@@ -320,6 +321,7 @@
 EXPORT_SYMBOL(param_get_bool);
 
 struct kernel_param_ops param_ops_bool = {
+	.flags = KERNEL_PARAM_FL_NOARG,
 	.set = param_set_bool,
 	.get = param_get_bool,
 };
@@ -370,6 +372,7 @@
 EXPORT_SYMBOL(param_set_bint);
 
 struct kernel_param_ops param_ops_bint = {
+	.flags = KERNEL_PARAM_FL_NOARG,
 	.set = param_set_bint,
 	.get = param_get_int,
 };
@@ -827,7 +830,7 @@
 	struct module_version_attribute *vattr =
 		container_of(mattr, struct module_version_attribute, mattr);
 
-	return sprintf(buf, "%s\n", vattr->version);
+	return scnprintf(buf, PAGE_SIZE, "%s\n", vattr->version);
 }
 
 extern const struct module_version_attribute *__start___modver[];
@@ -912,7 +915,14 @@
 struct kset *module_kset;
 int module_sysfs_initialized;
 
+static void module_kobj_release(struct kobject *kobj)
+{
+	struct module_kobject *mk = to_module_kobject(kobj);
+	complete(mk->kobj_completion);
+}
+
 struct kobj_type module_ktype = {
+	.release   =	module_kobj_release,
 	.sysfs_ops =	&module_sysfs_ops,
 };
 
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 6917e8e..601bb36 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -349,8 +349,8 @@
 	if (ancestor != active)
 		return -EINVAL;
 
-	put_pid_ns(nsproxy->pid_ns);
-	nsproxy->pid_ns = get_pid_ns(new);
+	put_pid_ns(nsproxy->pid_ns_for_children);
+	nsproxy->pid_ns_for_children = get_pid_ns(new);
 	return 0;
 }
 
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index b26f5f1..3085e62 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -39,7 +39,7 @@
 static char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
-int in_suspend __nosavedata;
+__visible int in_suspend __nosavedata;
 
 enum {
 	HIBERNATION_INVALID,
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index ece0422..62ee437 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -210,6 +210,7 @@
 		goto Platform_wake;
 	}
 
+	ftrace_stop();
 	error = disable_nonboot_cpus();
 	if (error || suspend_test(TEST_CPUS))
 		goto Enable_cpus;
@@ -232,6 +233,7 @@
 
  Enable_cpus:
 	enable_nonboot_cpus();
+	ftrace_start();
 
  Platform_wake:
 	if (need_suspend_ops(state) && suspend_ops->wake)
@@ -265,7 +267,6 @@
 			goto Close;
 	}
 	suspend_console();
-	ftrace_stop();
 	suspend_test_start();
 	error = dpm_suspend_start(PMSG_SUSPEND);
 	if (error) {
@@ -285,7 +286,6 @@
 	suspend_test_start();
 	dpm_resume_end(PMSG_RESUME);
 	suspend_test_finish("resume devices");
-	ftrace_start();
 	resume_console();
  Close:
 	if (need_suspend_ops(state) && suspend_ops->end)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 5b5a708..b4e8500 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2226,6 +2226,13 @@
 	struct console *bcon = NULL;
 	struct console_cmdline *c;
 
+	if (console_drivers)
+		for_each_console(bcon)
+			if (WARN(bcon == newcon,
+					"console '%s%d' already registered\n",
+					bcon->name, bcon->index))
+				return;
+
 	/*
 	 * before we register a new CON_BOOT console, make sure we don't
 	 * already have a valid console
diff --git a/kernel/rcu.h b/kernel/rcu.h
index 7f8e759..7713196 100644
--- a/kernel/rcu.h
+++ b/kernel/rcu.h
@@ -67,12 +67,15 @@
 
 extern struct debug_obj_descr rcuhead_debug_descr;
 
-static inline void debug_rcu_head_queue(struct rcu_head *head)
+static inline int debug_rcu_head_queue(struct rcu_head *head)
 {
-	debug_object_activate(head, &rcuhead_debug_descr);
+	int r1;
+
+	r1 = debug_object_activate(head, &rcuhead_debug_descr);
 	debug_object_active_state(head, &rcuhead_debug_descr,
 				  STATE_RCU_HEAD_READY,
 				  STATE_RCU_HEAD_QUEUED);
+	return r1;
 }
 
 static inline void debug_rcu_head_unqueue(struct rcu_head *head)
@@ -83,8 +86,9 @@
 	debug_object_deactivate(head, &rcuhead_debug_descr);
 }
 #else	/* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-static inline void debug_rcu_head_queue(struct rcu_head *head)
+static inline int debug_rcu_head_queue(struct rcu_head *head)
 {
+	return 0;
 }
 
 static inline void debug_rcu_head_unqueue(struct rcu_head *head)
@@ -94,7 +98,7 @@
 
 extern void kfree(const void *);
 
-static inline bool __rcu_reclaim(char *rn, struct rcu_head *head)
+static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head)
 {
 	unsigned long offset = (unsigned long)head->func;
 
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index cce6ba8..33eb462 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -212,43 +212,6 @@
 }
 
 /*
- * fixup_init is called when:
- * - an active object is initialized
- */
-static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
-{
-	struct rcu_head *head = addr;
-
-	switch (state) {
-	case ODEBUG_STATE_ACTIVE:
-		/*
-		 * Ensure that queued callbacks are all executed.
-		 * If we detect that we are nested in a RCU read-side critical
-		 * section, we should simply fail, otherwise we would deadlock.
-		 * In !PREEMPT configurations, there is no way to tell if we are
-		 * in a RCU read-side critical section or not, so we never
-		 * attempt any fixup and just print a warning.
-		 */
-#ifndef CONFIG_PREEMPT
-		WARN_ON_ONCE(1);
-		return 0;
-#endif
-		if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
-		    irqs_disabled()) {
-			WARN_ON_ONCE(1);
-			return 0;
-		}
-		rcu_barrier();
-		rcu_barrier_sched();
-		rcu_barrier_bh();
-		debug_object_init(head, &rcuhead_debug_descr);
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/*
  * fixup_activate is called when:
  * - an active object is activated
  * - an unknown object is activated (might be a statically initialized object)
@@ -268,69 +231,8 @@
 		debug_object_init(head, &rcuhead_debug_descr);
 		debug_object_activate(head, &rcuhead_debug_descr);
 		return 0;
-
-	case ODEBUG_STATE_ACTIVE:
-		/*
-		 * Ensure that queued callbacks are all executed.
-		 * If we detect that we are nested in a RCU read-side critical
-		 * section, we should simply fail, otherwise we would deadlock.
-		 * In !PREEMPT configurations, there is no way to tell if we are
-		 * in a RCU read-side critical section or not, so we never
-		 * attempt any fixup and just print a warning.
-		 */
-#ifndef CONFIG_PREEMPT
-		WARN_ON_ONCE(1);
-		return 0;
-#endif
-		if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
-		    irqs_disabled()) {
-			WARN_ON_ONCE(1);
-			return 0;
-		}
-		rcu_barrier();
-		rcu_barrier_sched();
-		rcu_barrier_bh();
-		debug_object_activate(head, &rcuhead_debug_descr);
-		return 1;
 	default:
-		return 0;
-	}
-}
-
-/*
- * fixup_free is called when:
- * - an active object is freed
- */
-static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
-{
-	struct rcu_head *head = addr;
-
-	switch (state) {
-	case ODEBUG_STATE_ACTIVE:
-		/*
-		 * Ensure that queued callbacks are all executed.
-		 * If we detect that we are nested in a RCU read-side critical
-		 * section, we should simply fail, otherwise we would deadlock.
-		 * In !PREEMPT configurations, there is no way to tell if we are
-		 * in a RCU read-side critical section or not, so we never
-		 * attempt any fixup and just print a warning.
-		 */
-#ifndef CONFIG_PREEMPT
-		WARN_ON_ONCE(1);
-		return 0;
-#endif
-		if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
-		    irqs_disabled()) {
-			WARN_ON_ONCE(1);
-			return 0;
-		}
-		rcu_barrier();
-		rcu_barrier_sched();
-		rcu_barrier_bh();
-		debug_object_free(head, &rcuhead_debug_descr);
 		return 1;
-	default:
-		return 0;
 	}
 }
 
@@ -369,15 +271,13 @@
 
 struct debug_obj_descr rcuhead_debug_descr = {
 	.name = "rcu_head",
-	.fixup_init = rcuhead_fixup_init,
 	.fixup_activate = rcuhead_fixup_activate,
-	.fixup_free = rcuhead_fixup_free,
 };
 EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
 #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE)
-void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp,
+void do_trace_rcu_torture_read(const char *rcutorturename, struct rcu_head *rhp,
 			       unsigned long secs,
 			       unsigned long c_old, unsigned long c)
 {
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index aa34411..9ed6075 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -264,7 +264,7 @@
  */
 static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
 {
-	char *rn = NULL;
+	const char *rn = NULL;
 	struct rcu_head *next, *list;
 	unsigned long flags;
 	RCU_TRACE(int cb_count = 0);
diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index 0cd385ac..280d06c 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -36,7 +36,7 @@
 	RCU_TRACE(unsigned long gp_start); /* Start time for stalls. */
 	RCU_TRACE(unsigned long ticks_this_gp); /* Statistic for stalls. */
 	RCU_TRACE(unsigned long jiffies_stall); /* Jiffies at next stall. */
-	RCU_TRACE(char *name);		/* Name of RCU type. */
+	RCU_TRACE(const char *name);	/* Name of RCU type. */
 };
 
 /* Definition for rcupdate control block. */
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index f4871e5..be63101 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -52,72 +52,78 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");
 
-static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
-static int nfakewriters = 4;	/* # fake writer threads */
-static int stat_interval = 60;	/* Interval between stats, in seconds. */
-				/*  Zero means "only at end of test". */
-static bool verbose;		/* Print more debug info. */
-static bool test_no_idle_hz = true;
-				/* Test RCU support for tickless idle CPUs. */
-static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
-static int stutter = 5;		/* Start/stop testing interval (in sec) */
-static int irqreader = 1;	/* RCU readers from irq (timers). */
-static int fqs_duration;	/* Duration of bursts (us), 0 to disable. */
-static int fqs_holdoff;		/* Hold time within burst (us). */
-static int fqs_stutter = 3;	/* Wait time between bursts (s). */
-static int n_barrier_cbs;	/* Number of callbacks to test RCU barriers. */
-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. */
-static char *torture_type = "rcu"; /* What RCU implementation to torture. */
-
-module_param(nreaders, int, 0444);
-MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
-module_param(nfakewriters, int, 0444);
-MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
-module_param(stat_interval, int, 0644);
-MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
-module_param(verbose, bool, 0444);
-MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
-module_param(test_no_idle_hz, bool, 0444);
-MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
-module_param(shuffle_interval, int, 0444);
-MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
-module_param(stutter, int, 0444);
-MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
-module_param(irqreader, int, 0444);
-MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
+static int fqs_duration;
 module_param(fqs_duration, int, 0444);
-MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us)");
+MODULE_PARM_DESC(fqs_duration, "Duration of fqs bursts (us), 0 to disable");
+static int fqs_holdoff;
 module_param(fqs_holdoff, int, 0444);
 MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)");
+static int fqs_stutter = 3;
 module_param(fqs_stutter, int, 0444);
 MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)");
+static bool gp_exp;
+module_param(gp_exp, bool, 0444);
+MODULE_PARM_DESC(gp_exp, "Use expedited GP wait primitives");
+static bool gp_normal;
+module_param(gp_normal, bool, 0444);
+MODULE_PARM_DESC(gp_normal, "Use normal (non-expedited) GP wait primitives");
+static int irqreader = 1;
+module_param(irqreader, int, 0444);
+MODULE_PARM_DESC(irqreader, "Allow RCU readers from irq handlers");
+static int n_barrier_cbs;
 module_param(n_barrier_cbs, int, 0444);
 MODULE_PARM_DESC(n_barrier_cbs, "# of callbacks/kthreads for barrier testing");
-module_param(onoff_interval, int, 0444);
-MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+static int nfakewriters = 4;
+module_param(nfakewriters, int, 0444);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
+static int nreaders = -1;
+module_param(nreaders, int, 0444);
+MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
+static int object_debug;
+module_param(object_debug, int, 0444);
+MODULE_PARM_DESC(object_debug, "Enable debug-object double call_rcu() testing");
+static int onoff_holdoff;
 module_param(onoff_holdoff, int, 0444);
 MODULE_PARM_DESC(onoff_holdoff, "Time after boot before CPU hotplugs (s)");
+static int onoff_interval;
+module_param(onoff_interval, int, 0444);
+MODULE_PARM_DESC(onoff_interval, "Time between CPU hotplugs (s), 0=disable");
+static int shuffle_interval = 3;
+module_param(shuffle_interval, int, 0444);
+MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
+static int shutdown_secs;
 module_param(shutdown_secs, int, 0444);
-MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), zero to disable.");
+MODULE_PARM_DESC(shutdown_secs, "Shutdown time (s), <= zero to disable.");
+static int stall_cpu;
 module_param(stall_cpu, int, 0444);
 MODULE_PARM_DESC(stall_cpu, "Stall duration (s), zero to disable.");
+static int stall_cpu_holdoff = 10;
 module_param(stall_cpu_holdoff, int, 0444);
 MODULE_PARM_DESC(stall_cpu_holdoff, "Time to wait before starting stall (s).");
+static int stat_interval = 60;
+module_param(stat_interval, int, 0644);
+MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
+static int stutter = 5;
+module_param(stutter, int, 0444);
+MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test");
+static int test_boost = 1;
 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);
-MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
+static int test_boost_duration = 4;
 module_param(test_boost_duration, int, 0444);
 MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds.");
+static int test_boost_interval = 7;
+module_param(test_boost_interval, int, 0444);
+MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds.");
+static bool test_no_idle_hz = true;
+module_param(test_no_idle_hz, bool, 0444);
+MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
+static char *torture_type = "rcu";
 module_param(torture_type, charp, 0444);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, ...)");
+static bool verbose;
+module_param(verbose, bool, 0444);
+MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
 
 #define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
@@ -267,7 +273,7 @@
  * Absorb kthreads into a kernel function that won't return, so that
  * they won't ever access module text or data again.
  */
-static void rcutorture_shutdown_absorb(char *title)
+static void rcutorture_shutdown_absorb(const char *title)
 {
 	if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) {
 		pr_notice(
@@ -337,7 +343,7 @@
 }
 
 static void
-rcu_stutter_wait(char *title)
+rcu_stutter_wait(const char *title)
 {
 	while (stutter_pause_test || !rcutorture_runnable) {
 		if (rcutorture_runnable)
@@ -360,13 +366,14 @@
 	int (*completed)(void);
 	void (*deferred_free)(struct rcu_torture *p);
 	void (*sync)(void);
+	void (*exp_sync)(void);
 	void (*call)(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
 	void (*cb_barrier)(void);
 	void (*fqs)(void);
 	int (*stats)(char *page);
 	int irq_capable;
 	int can_boost;
-	char *name;
+	const char *name;
 };
 
 static struct rcu_torture_ops *cur_ops;
@@ -443,14 +450,20 @@
 	call_rcu(&p->rtort_rcu, rcu_torture_cb);
 }
 
+static void rcu_sync_torture_init(void)
+{
+	INIT_LIST_HEAD(&rcu_torture_removed);
+}
+
 static struct rcu_torture_ops rcu_ops = {
-	.init		= NULL,
+	.init		= rcu_sync_torture_init,
 	.readlock	= rcu_torture_read_lock,
 	.read_delay	= rcu_read_delay,
 	.readunlock	= rcu_torture_read_unlock,
 	.completed	= rcu_torture_completed,
 	.deferred_free	= rcu_torture_deferred_free,
 	.sync		= synchronize_rcu,
+	.exp_sync	= synchronize_rcu_expedited,
 	.call		= call_rcu,
 	.cb_barrier	= rcu_barrier,
 	.fqs		= rcu_force_quiescent_state,
@@ -460,66 +473,6 @@
 	.name		= "rcu"
 };
 
-static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
-{
-	int i;
-	struct rcu_torture *rp;
-	struct rcu_torture *rp1;
-
-	cur_ops->sync();
-	list_add(&p->rtort_free, &rcu_torture_removed);
-	list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
-		i = rp->rtort_pipe_count;
-		if (i > RCU_TORTURE_PIPE_LEN)
-			i = RCU_TORTURE_PIPE_LEN;
-		atomic_inc(&rcu_torture_wcount[i]);
-		if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
-			rp->rtort_mbtest = 0;
-			list_del(&rp->rtort_free);
-			rcu_torture_free(rp);
-		}
-	}
-}
-
-static void rcu_sync_torture_init(void)
-{
-	INIT_LIST_HEAD(&rcu_torture_removed);
-}
-
-static struct rcu_torture_ops rcu_sync_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= rcu_torture_read_lock,
-	.read_delay	= rcu_read_delay,
-	.readunlock	= rcu_torture_read_unlock,
-	.completed	= rcu_torture_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= synchronize_rcu,
-	.call		= NULL,
-	.cb_barrier	= NULL,
-	.fqs		= rcu_force_quiescent_state,
-	.stats		= NULL,
-	.irq_capable	= 1,
-	.can_boost	= rcu_can_boost(),
-	.name		= "rcu_sync"
-};
-
-static struct rcu_torture_ops rcu_expedited_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= rcu_torture_read_lock,
-	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
-	.readunlock	= rcu_torture_read_unlock,
-	.completed	= rcu_no_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= synchronize_rcu_expedited,
-	.call		= NULL,
-	.cb_barrier	= NULL,
-	.fqs		= rcu_force_quiescent_state,
-	.stats		= NULL,
-	.irq_capable	= 1,
-	.can_boost	= rcu_can_boost(),
-	.name		= "rcu_expedited"
-};
-
 /*
  * Definitions for rcu_bh torture testing.
  */
@@ -546,13 +499,14 @@
 }
 
 static struct rcu_torture_ops rcu_bh_ops = {
-	.init		= NULL,
+	.init		= rcu_sync_torture_init,
 	.readlock	= rcu_bh_torture_read_lock,
 	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
 	.readunlock	= rcu_bh_torture_read_unlock,
 	.completed	= rcu_bh_torture_completed,
 	.deferred_free	= rcu_bh_torture_deferred_free,
 	.sync		= synchronize_rcu_bh,
+	.exp_sync	= synchronize_rcu_bh_expedited,
 	.call		= call_rcu_bh,
 	.cb_barrier	= rcu_barrier_bh,
 	.fqs		= rcu_bh_force_quiescent_state,
@@ -561,38 +515,6 @@
 	.name		= "rcu_bh"
 };
 
-static struct rcu_torture_ops rcu_bh_sync_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= rcu_bh_torture_read_lock,
-	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
-	.readunlock	= rcu_bh_torture_read_unlock,
-	.completed	= rcu_bh_torture_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= synchronize_rcu_bh,
-	.call		= NULL,
-	.cb_barrier	= NULL,
-	.fqs		= rcu_bh_force_quiescent_state,
-	.stats		= NULL,
-	.irq_capable	= 1,
-	.name		= "rcu_bh_sync"
-};
-
-static struct rcu_torture_ops rcu_bh_expedited_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= rcu_bh_torture_read_lock,
-	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
-	.readunlock	= rcu_bh_torture_read_unlock,
-	.completed	= rcu_bh_torture_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= synchronize_rcu_bh_expedited,
-	.call		= NULL,
-	.cb_barrier	= NULL,
-	.fqs		= rcu_bh_force_quiescent_state,
-	.stats		= NULL,
-	.irq_capable	= 1,
-	.name		= "rcu_bh_expedited"
-};
-
 /*
  * Definitions for srcu torture testing.
  */
@@ -667,6 +589,11 @@
 	return cnt;
 }
 
+static void srcu_torture_synchronize_expedited(void)
+{
+	synchronize_srcu_expedited(&srcu_ctl);
+}
+
 static struct rcu_torture_ops srcu_ops = {
 	.init		= rcu_sync_torture_init,
 	.readlock	= srcu_torture_read_lock,
@@ -675,45 +602,13 @@
 	.completed	= srcu_torture_completed,
 	.deferred_free	= srcu_torture_deferred_free,
 	.sync		= srcu_torture_synchronize,
+	.exp_sync	= srcu_torture_synchronize_expedited,
 	.call		= srcu_torture_call,
 	.cb_barrier	= srcu_torture_barrier,
 	.stats		= srcu_torture_stats,
 	.name		= "srcu"
 };
 
-static struct rcu_torture_ops srcu_sync_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= srcu_torture_read_lock,
-	.read_delay	= srcu_read_delay,
-	.readunlock	= srcu_torture_read_unlock,
-	.completed	= srcu_torture_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= srcu_torture_synchronize,
-	.call		= NULL,
-	.cb_barrier	= NULL,
-	.stats		= srcu_torture_stats,
-	.name		= "srcu_sync"
-};
-
-static void srcu_torture_synchronize_expedited(void)
-{
-	synchronize_srcu_expedited(&srcu_ctl);
-}
-
-static struct rcu_torture_ops srcu_expedited_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= srcu_torture_read_lock,
-	.read_delay	= srcu_read_delay,
-	.readunlock	= srcu_torture_read_unlock,
-	.completed	= srcu_torture_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= srcu_torture_synchronize_expedited,
-	.call		= NULL,
-	.cb_barrier	= NULL,
-	.stats		= srcu_torture_stats,
-	.name		= "srcu_expedited"
-};
-
 /*
  * Definitions for sched torture testing.
  */
@@ -742,6 +637,8 @@
 	.completed	= rcu_no_completed,
 	.deferred_free	= rcu_sched_torture_deferred_free,
 	.sync		= synchronize_sched,
+	.exp_sync	= synchronize_sched_expedited,
+	.call		= call_rcu_sched,
 	.cb_barrier	= rcu_barrier_sched,
 	.fqs		= rcu_sched_force_quiescent_state,
 	.stats		= NULL,
@@ -749,35 +646,6 @@
 	.name		= "sched"
 };
 
-static struct rcu_torture_ops sched_sync_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= sched_torture_read_lock,
-	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
-	.readunlock	= sched_torture_read_unlock,
-	.completed	= rcu_no_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= synchronize_sched,
-	.cb_barrier	= NULL,
-	.fqs		= rcu_sched_force_quiescent_state,
-	.stats		= NULL,
-	.name		= "sched_sync"
-};
-
-static struct rcu_torture_ops sched_expedited_ops = {
-	.init		= rcu_sync_torture_init,
-	.readlock	= sched_torture_read_lock,
-	.read_delay	= rcu_read_delay,  /* just reuse rcu's version. */
-	.readunlock	= sched_torture_read_unlock,
-	.completed	= rcu_no_completed,
-	.deferred_free	= rcu_sync_torture_deferred_free,
-	.sync		= synchronize_sched_expedited,
-	.cb_barrier	= NULL,
-	.fqs		= rcu_sched_force_quiescent_state,
-	.stats		= NULL,
-	.irq_capable	= 1,
-	.name		= "sched_expedited"
-};
-
 /*
  * RCU torture priority-boost testing.  Runs one real-time thread per
  * CPU for moderate bursts, repeatedly registering RCU callbacks and
@@ -927,9 +795,10 @@
 static int
 rcu_torture_writer(void *arg)
 {
+	bool exp;
 	int i;
-	long oldbatch = rcu_batches_completed();
 	struct rcu_torture *rp;
+	struct rcu_torture *rp1;
 	struct rcu_torture *old_rp;
 	static DEFINE_RCU_RANDOM(rand);
 
@@ -954,10 +823,33 @@
 				i = RCU_TORTURE_PIPE_LEN;
 			atomic_inc(&rcu_torture_wcount[i]);
 			old_rp->rtort_pipe_count++;
-			cur_ops->deferred_free(old_rp);
+			if (gp_normal == gp_exp)
+				exp = !!(rcu_random(&rand) & 0x80);
+			else
+				exp = gp_exp;
+			if (!exp) {
+				cur_ops->deferred_free(old_rp);
+			} else {
+				cur_ops->exp_sync();
+				list_add(&old_rp->rtort_free,
+					 &rcu_torture_removed);
+				list_for_each_entry_safe(rp, rp1,
+							 &rcu_torture_removed,
+							 rtort_free) {
+					i = rp->rtort_pipe_count;
+					if (i > RCU_TORTURE_PIPE_LEN)
+						i = RCU_TORTURE_PIPE_LEN;
+					atomic_inc(&rcu_torture_wcount[i]);
+					if (++rp->rtort_pipe_count >=
+					    RCU_TORTURE_PIPE_LEN) {
+						rp->rtort_mbtest = 0;
+						list_del(&rp->rtort_free);
+						rcu_torture_free(rp);
+					}
+				 }
+			}
 		}
 		rcutorture_record_progress(++rcu_torture_current_version);
-		oldbatch = cur_ops->completed();
 		rcu_stutter_wait("rcu_torture_writer");
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 	VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
@@ -983,10 +875,18 @@
 		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
 		udelay(rcu_random(&rand) & 0x3ff);
 		if (cur_ops->cb_barrier != NULL &&
-		    rcu_random(&rand) % (nfakewriters * 8) == 0)
+		    rcu_random(&rand) % (nfakewriters * 8) == 0) {
 			cur_ops->cb_barrier();
-		else
+		} else if (gp_normal == gp_exp) {
+			if (rcu_random(&rand) & 0x80)
+				cur_ops->sync();
+			else
+				cur_ops->exp_sync();
+		} else if (gp_normal) {
 			cur_ops->sync();
+		} else {
+			cur_ops->exp_sync();
+		}
 		rcu_stutter_wait("rcu_torture_fakewriter");
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
 
@@ -1364,7 +1264,7 @@
 }
 
 static inline void
-rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag)
+rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
 {
 	pr_alert("%s" TORTURE_FLAG
 		 "--- %s: nreaders=%d nfakewriters=%d "
@@ -1534,7 +1434,13 @@
 					 torture_type, cpu);
 			starttime = jiffies;
 			n_online_attempts++;
-			if (cpu_up(cpu) == 0) {
+			ret = cpu_up(cpu);
+			if (ret) {
+				if (verbose)
+					pr_alert("%s" TORTURE_FLAG
+						 "rcu_torture_onoff task: online %d failed: errno %d\n",
+						 torture_type, cpu, ret);
+			} else {
 				if (verbose)
 					pr_alert("%s" TORTURE_FLAG
 						 "rcu_torture_onoff task: onlined %d\n",
@@ -1934,6 +1840,62 @@
 		rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS");
 }
 
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static void rcu_torture_leak_cb(struct rcu_head *rhp)
+{
+}
+
+static void rcu_torture_err_cb(struct rcu_head *rhp)
+{
+	/*
+	 * This -might- happen due to race conditions, but is unlikely.
+	 * The scenario that leads to this happening is that the
+	 * first of the pair of duplicate callbacks is queued,
+	 * someone else starts a grace period that includes that
+	 * callback, then the second of the pair must wait for the
+	 * next grace period.  Unlikely, but can happen.  If it
+	 * does happen, the debug-objects subsystem won't have splatted.
+	 */
+	pr_alert("rcutorture: duplicated callback was invoked.\n");
+}
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
+/*
+ * Verify that double-free causes debug-objects to complain, but only
+ * if CONFIG_DEBUG_OBJECTS_RCU_HEAD=y.  Otherwise, say that the test
+ * cannot be carried out.
+ */
+static void rcu_test_debug_objects(void)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+	struct rcu_head rh1;
+	struct rcu_head rh2;
+
+	init_rcu_head_on_stack(&rh1);
+	init_rcu_head_on_stack(&rh2);
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test starting.\n");
+
+	/* Try to queue the rh2 pair of callbacks for the same grace period. */
+	preempt_disable(); /* Prevent preemption from interrupting test. */
+	rcu_read_lock(); /* Make it impossible to finish a grace period. */
+	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */
+	local_irq_disable(); /* Make it harder to start a new grace period. */
+	call_rcu(&rh2, rcu_torture_leak_cb);
+	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */
+	local_irq_enable();
+	rcu_read_unlock();
+	preempt_enable();
+
+	/* Wait for them all to get done so we can safely return. */
+	rcu_barrier();
+	pr_alert("rcutorture: WARN: Duplicate call_rcu() test complete.\n");
+	destroy_rcu_head_on_stack(&rh1);
+	destroy_rcu_head_on_stack(&rh2);
+#else /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+	pr_alert("rcutorture: !CONFIG_DEBUG_OBJECTS_RCU_HEAD, not testing duplicate call_rcu()\n");
+#endif /* #else #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+}
+
 static int __init
 rcu_torture_init(void)
 {
@@ -1941,11 +1903,9 @@
 	int cpu;
 	int firsterr = 0;
 	int retval;
-	static struct rcu_torture_ops *torture_ops[] =
-		{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,
-		  &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops,
-		  &srcu_ops, &srcu_sync_ops, &srcu_expedited_ops,
-		  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };
+	static struct rcu_torture_ops *torture_ops[] = {
+		&rcu_ops, &rcu_bh_ops, &srcu_ops, &sched_ops,
+	};
 
 	mutex_lock(&fullstop_mutex);
 
@@ -2163,6 +2123,8 @@
 		firsterr = retval;
 		goto unwind;
 	}
+	if (object_debug)
+		rcu_test_debug_objects();
 	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 068de3a..32618b3 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -53,18 +53,38 @@
 #include <linux/delay.h>
 #include <linux/stop_machine.h>
 #include <linux/random.h>
+#include <linux/ftrace_event.h>
+#include <linux/suspend.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
 
 #include "rcu.h"
 
+/*
+ * Strings used in tracepoints need to be exported via the
+ * tracing system such that tools like perf and trace-cmd can
+ * translate the string address pointers to actual text.
+ */
+#define TPS(x)	tracepoint_string(x)
+
 /* Data structures. */
 
 static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
 static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
 
-#define RCU_STATE_INITIALIZER(sname, sabbr, cr) { \
+/*
+ * In order to export the rcu_state name to the tracing tools, it
+ * needs to be added in the __tracepoint_string section.
+ * This requires defining a separate variable tp_<sname>_varname
+ * that points to the string being used, and this will allow
+ * the tracing userspace tools to be able to decipher the string
+ * address to the matching string.
+ */
+#define RCU_STATE_INITIALIZER(sname, sabbr, cr) \
+static char sname##_varname[] = #sname; \
+static const char *tp_##sname##_varname __used __tracepoint_string = sname##_varname; \
+struct rcu_state sname##_state = { \
 	.level = { &sname##_state.node[0] }, \
 	.call = cr, \
 	.fqs_state = RCU_GP_IDLE, \
@@ -75,16 +95,13 @@
 	.orphan_donetail = &sname##_state.orphan_donelist, \
 	.barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
 	.onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \
-	.name = #sname, \
+	.name = sname##_varname, \
 	.abbr = sabbr, \
-}
+}; \
+DEFINE_PER_CPU(struct rcu_data, sname##_data)
 
-struct rcu_state rcu_sched_state =
-	RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);
-DEFINE_PER_CPU(struct rcu_data, rcu_sched_data);
-
-struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh);
-DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
+RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);
+RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh);
 
 static struct rcu_state *rcu_state;
 LIST_HEAD(rcu_struct_flavors);
@@ -178,7 +195,7 @@
 	struct rcu_data *rdp = &per_cpu(rcu_sched_data, cpu);
 
 	if (rdp->passed_quiesce == 0)
-		trace_rcu_grace_period("rcu_sched", rdp->gpnum, "cpuqs");
+		trace_rcu_grace_period(TPS("rcu_sched"), rdp->gpnum, TPS("cpuqs"));
 	rdp->passed_quiesce = 1;
 }
 
@@ -187,7 +204,7 @@
 	struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
 
 	if (rdp->passed_quiesce == 0)
-		trace_rcu_grace_period("rcu_bh", rdp->gpnum, "cpuqs");
+		trace_rcu_grace_period(TPS("rcu_bh"), rdp->gpnum, TPS("cpuqs"));
 	rdp->passed_quiesce = 1;
 }
 
@@ -198,16 +215,20 @@
  */
 void rcu_note_context_switch(int cpu)
 {
-	trace_rcu_utilization("Start context switch");
+	trace_rcu_utilization(TPS("Start context switch"));
 	rcu_sched_qs(cpu);
 	rcu_preempt_note_context_switch(cpu);
-	trace_rcu_utilization("End context switch");
+	trace_rcu_utilization(TPS("End context switch"));
 }
 EXPORT_SYMBOL_GPL(rcu_note_context_switch);
 
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
 	.dynticks_nesting = DYNTICK_TASK_EXIT_IDLE,
 	.dynticks = ATOMIC_INIT(1),
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+	.dynticks_idle_nesting = DYNTICK_TASK_NEST_VALUE,
+	.dynticks_idle = ATOMIC_INIT(1),
+#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
 };
 
 static long blimit = 10;	/* Maximum callbacks per rcu_do_batch. */
@@ -226,7 +247,10 @@
 
 static void rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
 				  struct rcu_data *rdp);
-static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *));
+static void force_qs_rnp(struct rcu_state *rsp,
+			 int (*f)(struct rcu_data *rsp, bool *isidle,
+				  unsigned long *maxj),
+			 bool *isidle, unsigned long *maxj);
 static void force_quiescent_state(struct rcu_state *rsp);
 static int rcu_pending(int cpu);
 
@@ -345,11 +369,11 @@
 static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
 				bool user)
 {
-	trace_rcu_dyntick("Start", oldval, rdtp->dynticks_nesting);
+	trace_rcu_dyntick(TPS("Start"), oldval, rdtp->dynticks_nesting);
 	if (!user && !is_idle_task(current)) {
 		struct task_struct *idle = idle_task(smp_processor_id());
 
-		trace_rcu_dyntick("Error on entry: not idle task", oldval, 0);
+		trace_rcu_dyntick(TPS("Error on entry: not idle task"), oldval, 0);
 		ftrace_dump(DUMP_ORIG);
 		WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
 			  current->pid, current->comm,
@@ -411,6 +435,7 @@
 
 	local_irq_save(flags);
 	rcu_eqs_enter(false);
+	rcu_sysidle_enter(&__get_cpu_var(rcu_dynticks), 0);
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_enter);
@@ -428,27 +453,6 @@
 {
 	rcu_eqs_enter(1);
 }
-
-/**
- * rcu_user_enter_after_irq - inform RCU that we are going to resume userspace
- * after the current irq returns.
- *
- * This is similar to rcu_user_enter() but in the context of a non-nesting
- * irq. After this call, RCU enters into idle mode when the interrupt
- * returns.
- */
-void rcu_user_enter_after_irq(void)
-{
-	unsigned long flags;
-	struct rcu_dynticks *rdtp;
-
-	local_irq_save(flags);
-	rdtp = &__get_cpu_var(rcu_dynticks);
-	/* Ensure this irq is interrupting a non-idle RCU state.  */
-	WARN_ON_ONCE(!(rdtp->dynticks_nesting & DYNTICK_TASK_MASK));
-	rdtp->dynticks_nesting = 1;
-	local_irq_restore(flags);
-}
 #endif /* CONFIG_RCU_USER_QS */
 
 /**
@@ -479,9 +483,10 @@
 	rdtp->dynticks_nesting--;
 	WARN_ON_ONCE(rdtp->dynticks_nesting < 0);
 	if (rdtp->dynticks_nesting)
-		trace_rcu_dyntick("--=", oldval, rdtp->dynticks_nesting);
+		trace_rcu_dyntick(TPS("--="), oldval, rdtp->dynticks_nesting);
 	else
 		rcu_eqs_enter_common(rdtp, oldval, true);
+	rcu_sysidle_enter(rdtp, 1);
 	local_irq_restore(flags);
 }
 
@@ -501,11 +506,11 @@
 	smp_mb__after_atomic_inc();  /* See above. */
 	WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
 	rcu_cleanup_after_idle(smp_processor_id());
-	trace_rcu_dyntick("End", oldval, rdtp->dynticks_nesting);
+	trace_rcu_dyntick(TPS("End"), oldval, rdtp->dynticks_nesting);
 	if (!user && !is_idle_task(current)) {
 		struct task_struct *idle = idle_task(smp_processor_id());
 
-		trace_rcu_dyntick("Error on exit: not idle task",
+		trace_rcu_dyntick(TPS("Error on exit: not idle task"),
 				  oldval, rdtp->dynticks_nesting);
 		ftrace_dump(DUMP_ORIG);
 		WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
@@ -550,6 +555,7 @@
 
 	local_irq_save(flags);
 	rcu_eqs_exit(false);
+	rcu_sysidle_exit(&__get_cpu_var(rcu_dynticks), 0);
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_exit);
@@ -565,28 +571,6 @@
 {
 	rcu_eqs_exit(1);
 }
-
-/**
- * rcu_user_exit_after_irq - inform RCU that we won't resume to userspace
- * idle mode after the current non-nesting irq returns.
- *
- * This is similar to rcu_user_exit() but in the context of an irq.
- * This is called when the irq has interrupted a userspace RCU idle mode
- * context. When the current non-nesting interrupt returns after this call,
- * the CPU won't restore the RCU idle mode.
- */
-void rcu_user_exit_after_irq(void)
-{
-	unsigned long flags;
-	struct rcu_dynticks *rdtp;
-
-	local_irq_save(flags);
-	rdtp = &__get_cpu_var(rcu_dynticks);
-	/* Ensure we are interrupting an RCU idle mode. */
-	WARN_ON_ONCE(rdtp->dynticks_nesting & DYNTICK_TASK_NEST_MASK);
-	rdtp->dynticks_nesting += DYNTICK_TASK_EXIT_IDLE;
-	local_irq_restore(flags);
-}
 #endif /* CONFIG_RCU_USER_QS */
 
 /**
@@ -620,9 +604,10 @@
 	rdtp->dynticks_nesting++;
 	WARN_ON_ONCE(rdtp->dynticks_nesting == 0);
 	if (oldval)
-		trace_rcu_dyntick("++=", oldval, rdtp->dynticks_nesting);
+		trace_rcu_dyntick(TPS("++="), oldval, rdtp->dynticks_nesting);
 	else
 		rcu_eqs_exit_common(rdtp, oldval, true);
+	rcu_sysidle_exit(rdtp, 1);
 	local_irq_restore(flags);
 }
 
@@ -746,9 +731,11 @@
  * credit them with an implicit quiescent state.  Return 1 if this CPU
  * is in dynticks idle mode, which is an extended quiescent state.
  */
-static int dyntick_save_progress_counter(struct rcu_data *rdp)
+static int dyntick_save_progress_counter(struct rcu_data *rdp,
+					 bool *isidle, unsigned long *maxj)
 {
 	rdp->dynticks_snap = atomic_add_return(0, &rdp->dynticks->dynticks);
+	rcu_sysidle_check_cpu(rdp, isidle, maxj);
 	return (rdp->dynticks_snap & 0x1) == 0;
 }
 
@@ -758,7 +745,8 @@
  * idle state since the last call to dyntick_save_progress_counter()
  * for this same CPU, or by virtue of having been offline.
  */
-static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
+static int rcu_implicit_dynticks_qs(struct rcu_data *rdp,
+				    bool *isidle, unsigned long *maxj)
 {
 	unsigned int curr;
 	unsigned int snap;
@@ -775,7 +763,7 @@
 	 * of the current RCU grace period.
 	 */
 	if ((curr & 0x1) == 0 || UINT_CMP_GE(curr, snap + 2)) {
-		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "dti");
+		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("dti"));
 		rdp->dynticks_fqs++;
 		return 1;
 	}
@@ -795,7 +783,7 @@
 		return 0;  /* Grace period is not old enough. */
 	barrier();
 	if (cpu_is_offline(rdp->cpu)) {
-		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl");
+		trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, TPS("ofl"));
 		rdp->offline_fqs++;
 		return 1;
 	}
@@ -1032,7 +1020,7 @@
  * rcu_nocb_wait_gp().
  */
 static void trace_rcu_future_gp(struct rcu_node *rnp, struct rcu_data *rdp,
-				unsigned long c, char *s)
+				unsigned long c, const char *s)
 {
 	trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum,
 				      rnp->completed, c, rnp->level,
@@ -1058,9 +1046,9 @@
 	 * grace period is already marked as needed, return to the caller.
 	 */
 	c = rcu_cbs_completed(rdp->rsp, rnp);
-	trace_rcu_future_gp(rnp, rdp, c, "Startleaf");
+	trace_rcu_future_gp(rnp, rdp, c, TPS("Startleaf"));
 	if (rnp->need_future_gp[c & 0x1]) {
-		trace_rcu_future_gp(rnp, rdp, c, "Prestartleaf");
+		trace_rcu_future_gp(rnp, rdp, c, TPS("Prestartleaf"));
 		return c;
 	}
 
@@ -1074,7 +1062,7 @@
 	if (rnp->gpnum != rnp->completed ||
 	    ACCESS_ONCE(rnp->gpnum) != ACCESS_ONCE(rnp->completed)) {
 		rnp->need_future_gp[c & 0x1]++;
-		trace_rcu_future_gp(rnp, rdp, c, "Startedleaf");
+		trace_rcu_future_gp(rnp, rdp, c, TPS("Startedleaf"));
 		return c;
 	}
 
@@ -1102,7 +1090,7 @@
 	 * recorded, trace and leave.
 	 */
 	if (rnp_root->need_future_gp[c & 0x1]) {
-		trace_rcu_future_gp(rnp, rdp, c, "Prestartedroot");
+		trace_rcu_future_gp(rnp, rdp, c, TPS("Prestartedroot"));
 		goto unlock_out;
 	}
 
@@ -1111,9 +1099,9 @@
 
 	/* If a grace period is not already in progress, start one. */
 	if (rnp_root->gpnum != rnp_root->completed) {
-		trace_rcu_future_gp(rnp, rdp, c, "Startedleafroot");
+		trace_rcu_future_gp(rnp, rdp, c, TPS("Startedleafroot"));
 	} else {
-		trace_rcu_future_gp(rnp, rdp, c, "Startedroot");
+		trace_rcu_future_gp(rnp, rdp, c, TPS("Startedroot"));
 		rcu_start_gp_advanced(rdp->rsp, rnp_root, rdp);
 	}
 unlock_out:
@@ -1137,7 +1125,8 @@
 	rcu_nocb_gp_cleanup(rsp, rnp);
 	rnp->need_future_gp[c & 0x1] = 0;
 	needmore = rnp->need_future_gp[(c + 1) & 0x1];
-	trace_rcu_future_gp(rnp, rdp, c, needmore ? "CleanupMore" : "Cleanup");
+	trace_rcu_future_gp(rnp, rdp, c,
+			    needmore ? TPS("CleanupMore") : TPS("Cleanup"));
 	return needmore;
 }
 
@@ -1205,9 +1194,9 @@
 
 	/* Trace depending on how much we were able to accelerate. */
 	if (!*rdp->nxttail[RCU_WAIT_TAIL])
-		trace_rcu_grace_period(rsp->name, rdp->gpnum, "AccWaitCB");
+		trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("AccWaitCB"));
 	else
-		trace_rcu_grace_period(rsp->name, rdp->gpnum, "AccReadyCB");
+		trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("AccReadyCB"));
 }
 
 /*
@@ -1273,7 +1262,7 @@
 
 		/* Remember that we saw this grace-period completion. */
 		rdp->completed = rnp->completed;
-		trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpuend");
+		trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuend"));
 	}
 
 	if (rdp->gpnum != rnp->gpnum) {
@@ -1283,7 +1272,7 @@
 		 * go looking for one.
 		 */
 		rdp->gpnum = rnp->gpnum;
-		trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpustart");
+		trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpustart"));
 		rdp->passed_quiesce = 0;
 		rdp->qs_pending = !!(rnp->qsmask & rdp->grpmask);
 		zero_cpu_stall_ticks(rdp);
@@ -1315,6 +1304,7 @@
 	struct rcu_data *rdp;
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
+	rcu_bind_gp_kthread();
 	raw_spin_lock_irq(&rnp->lock);
 	rsp->gp_flags = 0; /* Clear all flags: New grace period. */
 
@@ -1326,7 +1316,7 @@
 
 	/* Advance to a new grace period and initialize state. */
 	rsp->gpnum++;
-	trace_rcu_grace_period(rsp->name, rsp->gpnum, "start");
+	trace_rcu_grace_period(rsp->name, rsp->gpnum, TPS("start"));
 	record_gp_stall_check_time(rsp);
 	raw_spin_unlock_irq(&rnp->lock);
 
@@ -1379,16 +1369,25 @@
 int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
 {
 	int fqs_state = fqs_state_in;
+	bool isidle = false;
+	unsigned long maxj;
 	struct rcu_node *rnp = rcu_get_root(rsp);
 
 	rsp->n_force_qs++;
 	if (fqs_state == RCU_SAVE_DYNTICK) {
 		/* Collect dyntick-idle snapshots. */
-		force_qs_rnp(rsp, dyntick_save_progress_counter);
+		if (is_sysidle_rcu_state(rsp)) {
+			isidle = 1;
+			maxj = jiffies - ULONG_MAX / 4;
+		}
+		force_qs_rnp(rsp, dyntick_save_progress_counter,
+			     &isidle, &maxj);
+		rcu_sysidle_report_gp(rsp, isidle, maxj);
 		fqs_state = RCU_FORCE_QS;
 	} else {
 		/* Handle dyntick-idle and offline CPUs. */
-		force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
+		isidle = 0;
+		force_qs_rnp(rsp, rcu_implicit_dynticks_qs, &isidle, &maxj);
 	}
 	/* Clear flag to prevent immediate re-entry. */
 	if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
@@ -1448,7 +1447,7 @@
 	rcu_nocb_gp_set(rnp, nocb);
 
 	rsp->completed = rsp->gpnum; /* Declare grace period done. */
-	trace_rcu_grace_period(rsp->name, rsp->completed, "end");
+	trace_rcu_grace_period(rsp->name, rsp->completed, TPS("end"));
 	rsp->fqs_state = RCU_GP_IDLE;
 	rdp = this_cpu_ptr(rsp->rda);
 	rcu_advance_cbs(rsp, rnp, rdp);  /* Reduce false positives below. */
@@ -1558,10 +1557,12 @@
 
 	/*
 	 * We can't do wakeups while holding the rnp->lock, as that
-	 * could cause possible deadlocks with the rq->lock. Deter
-	 * the wakeup to interrupt context.
+	 * could cause possible deadlocks with the rq->lock. Defer
+	 * the wakeup to interrupt context.  And don't bother waking
+	 * up the running kthread.
 	 */
-	irq_work_queue(&rsp->wakeup_work);
+	if (current != rsp->gp_kthread)
+		irq_work_queue(&rsp->wakeup_work);
 }
 
 /*
@@ -1857,7 +1858,7 @@
 	RCU_TRACE(mask = rdp->grpmask);
 	trace_rcu_grace_period(rsp->name,
 			       rnp->gpnum + 1 - !!(rnp->qsmask & mask),
-			       "cpuofl");
+			       TPS("cpuofl"));
 }
 
 /*
@@ -2044,7 +2045,7 @@
  */
 void rcu_check_callbacks(int cpu, int user)
 {
-	trace_rcu_utilization("Start scheduler-tick");
+	trace_rcu_utilization(TPS("Start scheduler-tick"));
 	increment_cpu_stall_ticks();
 	if (user || rcu_is_cpu_rrupt_from_idle()) {
 
@@ -2077,7 +2078,7 @@
 	rcu_preempt_check_callbacks(cpu);
 	if (rcu_pending(cpu))
 		invoke_rcu_core();
-	trace_rcu_utilization("End scheduler-tick");
+	trace_rcu_utilization(TPS("End scheduler-tick"));
 }
 
 /*
@@ -2087,7 +2088,10 @@
  *
  * The caller must have suppressed start of new grace periods.
  */
-static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
+static void force_qs_rnp(struct rcu_state *rsp,
+			 int (*f)(struct rcu_data *rsp, bool *isidle,
+				  unsigned long *maxj),
+			 bool *isidle, unsigned long *maxj)
 {
 	unsigned long bit;
 	int cpu;
@@ -2110,9 +2114,12 @@
 		cpu = rnp->grplo;
 		bit = 1;
 		for (; cpu <= rnp->grphi; cpu++, bit <<= 1) {
-			if ((rnp->qsmask & bit) != 0 &&
-			    f(per_cpu_ptr(rsp->rda, cpu)))
-				mask |= bit;
+			if ((rnp->qsmask & bit) != 0) {
+				if ((rnp->qsmaskinit & bit) != 0)
+					*isidle = 0;
+				if (f(per_cpu_ptr(rsp->rda, cpu), isidle, maxj))
+					mask |= bit;
+			}
 		}
 		if (mask != 0) {
 
@@ -2208,10 +2215,10 @@
 
 	if (cpu_is_offline(smp_processor_id()))
 		return;
-	trace_rcu_utilization("Start RCU core");
+	trace_rcu_utilization(TPS("Start RCU core"));
 	for_each_rcu_flavor(rsp)
 		__rcu_process_callbacks(rsp);
-	trace_rcu_utilization("End RCU core");
+	trace_rcu_utilization(TPS("End RCU core"));
 }
 
 /*
@@ -2287,6 +2294,13 @@
 }
 
 /*
+ * RCU callback function to leak a callback.
+ */
+static void rcu_leak_callback(struct rcu_head *rhp)
+{
+}
+
+/*
  * Helper function for call_rcu() and friends.  The cpu argument will
  * normally be -1, indicating "currently running CPU".  It may specify
  * a CPU only if that CPU is a no-CBs CPU.  Currently, only _rcu_barrier()
@@ -2300,7 +2314,12 @@
 	struct rcu_data *rdp;
 
 	WARN_ON_ONCE((unsigned long)head & 0x3); /* Misaligned rcu_head! */
-	debug_rcu_head_queue(head);
+	if (debug_rcu_head_queue(head)) {
+		/* Probable double call_rcu(), so leak the callback. */
+		ACCESS_ONCE(head->func) = rcu_leak_callback;
+		WARN_ONCE(1, "__call_rcu(): Leaked duplicate callback\n");
+		return;
+	}
 	head->func = func;
 	head->next = NULL;
 
@@ -2720,7 +2739,7 @@
  * Helper function for _rcu_barrier() tracing.  If tracing is disabled,
  * the compiler is expected to optimize this away.
  */
-static void _rcu_barrier_trace(struct rcu_state *rsp, char *s,
+static void _rcu_barrier_trace(struct rcu_state *rsp, const char *s,
 			       int cpu, unsigned long done)
 {
 	trace_rcu_barrier(rsp->name, s, cpu,
@@ -2785,9 +2804,20 @@
 	 * transition.  The "if" expression below therefore rounds the old
 	 * value up to the next even number and adds two before comparing.
 	 */
-	snap_done = ACCESS_ONCE(rsp->n_barrier_done);
+	snap_done = rsp->n_barrier_done;
 	_rcu_barrier_trace(rsp, "Check", -1, snap_done);
-	if (ULONG_CMP_GE(snap_done, ((snap + 1) & ~0x1) + 2)) {
+
+	/*
+	 * If the value in snap is odd, we needed to wait for the current
+	 * rcu_barrier() to complete, then wait for the next one, in other
+	 * words, we need the value of snap_done to be three larger than
+	 * the value of snap.  On the other hand, if the value in snap is
+	 * even, we only had to wait for the next rcu_barrier() to complete,
+	 * in other words, we need the value of snap_done to be only two
+	 * greater than the value of snap.  The "(snap + 3) & ~0x1" computes
+	 * this for us (thank you, Linus!).
+	 */
+	if (ULONG_CMP_GE(snap_done, (snap + 3) & ~0x1)) {
 		_rcu_barrier_trace(rsp, "EarlyExit", -1, snap_done);
 		smp_mb(); /* caller's subsequent code after above check. */
 		mutex_unlock(&rsp->barrier_mutex);
@@ -2930,6 +2960,7 @@
 	rdp->blimit = blimit;
 	init_callback_list(rdp);  /* Re-enable callbacks on this CPU. */
 	rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
+	rcu_sysidle_init_percpu_data(rdp->dynticks);
 	atomic_set(&rdp->dynticks->dynticks,
 		   (atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
 	raw_spin_unlock(&rnp->lock);		/* irqs remain disabled. */
@@ -2952,7 +2983,7 @@
 			rdp->completed = rnp->completed;
 			rdp->passed_quiesce = 0;
 			rdp->qs_pending = 0;
-			trace_rcu_grace_period(rsp->name, rdp->gpnum, "cpuonl");
+			trace_rcu_grace_period(rsp->name, rdp->gpnum, TPS("cpuonl"));
 		}
 		raw_spin_unlock(&rnp->lock); /* irqs already disabled. */
 		rnp = rnp->parent;
@@ -2982,7 +3013,7 @@
 	struct rcu_node *rnp = rdp->mynode;
 	struct rcu_state *rsp;
 
-	trace_rcu_utilization("Start CPU hotplug");
+	trace_rcu_utilization(TPS("Start CPU hotplug"));
 	switch (action) {
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
@@ -3011,7 +3042,26 @@
 	default:
 		break;
 	}
-	trace_rcu_utilization("End CPU hotplug");
+	trace_rcu_utilization(TPS("End CPU hotplug"));
+	return NOTIFY_OK;
+}
+
+static int rcu_pm_notify(struct notifier_block *self,
+			 unsigned long action, void *hcpu)
+{
+	switch (action) {
+	case PM_HIBERNATION_PREPARE:
+	case PM_SUSPEND_PREPARE:
+		if (nr_cpu_ids <= 256) /* Expediting bad for large systems. */
+			rcu_expedited = 1;
+		break;
+	case PM_POST_HIBERNATION:
+	case PM_POST_SUSPEND:
+		rcu_expedited = 0;
+		break;
+	default:
+		break;
+	}
 	return NOTIFY_OK;
 }
 
@@ -3256,6 +3306,7 @@
 	 * or the scheduler are operational.
 	 */
 	cpu_notifier(rcu_cpu_notify, 0);
+	pm_notifier(rcu_pm_notify, 0);
 	for_each_online_cpu(cpu)
 		rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
 }
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index b383258..5f97eab 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -88,6 +88,14 @@
 				    /* Process level is worth LLONG_MAX/2. */
 	int dynticks_nmi_nesting;   /* Track NMI nesting level. */
 	atomic_t dynticks;	    /* Even value for idle, else odd. */
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+	long long dynticks_idle_nesting;
+				    /* irq/process nesting level from idle. */
+	atomic_t dynticks_idle;	    /* Even value for idle, else odd. */
+				    /*  "Idle" excludes userspace execution. */
+	unsigned long dynticks_idle_jiffies;
+				    /* End of last non-NMI non-idle period. */
+#endif /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
 #ifdef CONFIG_RCU_FAST_NO_HZ
 	bool all_lazy;		    /* Are all CPU's CBs lazy? */
 	unsigned long nonlazy_posted;
@@ -445,7 +453,7 @@
 						/*  for CPU stalls. */
 	unsigned long gp_max;			/* Maximum GP duration in */
 						/*  jiffies. */
-	char *name;				/* Name of structure. */
+	const char *name;			/* Name of structure. */
 	char abbr;				/* Abbreviated name. */
 	struct list_head flavors;		/* List of RCU flavors. */
 	struct irq_work wakeup_work;		/* Postponed wakeups */
@@ -545,6 +553,15 @@
 static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp);
 static void rcu_kick_nohz_cpu(int cpu);
 static bool init_nocb_callback_list(struct rcu_data *rdp);
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq);
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq);
+static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
+				  unsigned long *maxj);
+static bool is_sysidle_rcu_state(struct rcu_state *rsp);
+static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle,
+				  unsigned long maxj);
+static void rcu_bind_gp_kthread(void);
+static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp);
 
 #endif /* #ifndef RCU_TREE_NONCORE */
 
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 769e12e..130c97b 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -28,7 +28,7 @@
 #include <linux/gfp.h>
 #include <linux/oom.h>
 #include <linux/smpboot.h>
-#include <linux/tick.h>
+#include "time/tick-internal.h"
 
 #define RCU_KTHREAD_PRIO 1
 
@@ -110,9 +110,7 @@
 
 #ifdef CONFIG_TREE_PREEMPT_RCU
 
-struct rcu_state rcu_preempt_state =
-	RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu);
-DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data);
+RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu);
 static struct rcu_state *rcu_state = &rcu_preempt_state;
 
 static int rcu_preempted_readers_exp(struct rcu_node *rnp);
@@ -169,7 +167,7 @@
 	struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu);
 
 	if (rdp->passed_quiesce == 0)
-		trace_rcu_grace_period("rcu_preempt", rdp->gpnum, "cpuqs");
+		trace_rcu_grace_period(TPS("rcu_preempt"), rdp->gpnum, TPS("cpuqs"));
 	rdp->passed_quiesce = 1;
 	current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS;
 }
@@ -388,7 +386,7 @@
 		np = rcu_next_node_entry(t, rnp);
 		list_del_init(&t->rcu_node_entry);
 		t->rcu_blocked_node = NULL;
-		trace_rcu_unlock_preempted_task("rcu_preempt",
+		trace_rcu_unlock_preempted_task(TPS("rcu_preempt"),
 						rnp->gpnum, t->pid);
 		if (&t->rcu_node_entry == rnp->gp_tasks)
 			rnp->gp_tasks = np;
@@ -412,7 +410,7 @@
 		 */
 		empty_exp_now = !rcu_preempted_readers_exp(rnp);
 		if (!empty && !rcu_preempt_blocked_readers_cgp(rnp)) {
-			trace_rcu_quiescent_state_report("preempt_rcu",
+			trace_rcu_quiescent_state_report(TPS("preempt_rcu"),
 							 rnp->gpnum,
 							 0, rnp->qsmask,
 							 rnp->level,
@@ -1250,12 +1248,12 @@
 	int spincnt = 0;
 	int more2boost;
 
-	trace_rcu_utilization("Start boost kthread@init");
+	trace_rcu_utilization(TPS("Start boost kthread@init"));
 	for (;;) {
 		rnp->boost_kthread_status = RCU_KTHREAD_WAITING;
-		trace_rcu_utilization("End boost kthread@rcu_wait");
+		trace_rcu_utilization(TPS("End boost kthread@rcu_wait"));
 		rcu_wait(rnp->boost_tasks || rnp->exp_tasks);
-		trace_rcu_utilization("Start boost kthread@rcu_wait");
+		trace_rcu_utilization(TPS("Start boost kthread@rcu_wait"));
 		rnp->boost_kthread_status = RCU_KTHREAD_RUNNING;
 		more2boost = rcu_boost(rnp);
 		if (more2boost)
@@ -1264,14 +1262,14 @@
 			spincnt = 0;
 		if (spincnt > 10) {
 			rnp->boost_kthread_status = RCU_KTHREAD_YIELDING;
-			trace_rcu_utilization("End boost kthread@rcu_yield");
+			trace_rcu_utilization(TPS("End boost kthread@rcu_yield"));
 			schedule_timeout_interruptible(2);
-			trace_rcu_utilization("Start boost kthread@rcu_yield");
+			trace_rcu_utilization(TPS("Start boost kthread@rcu_yield"));
 			spincnt = 0;
 		}
 	}
 	/* NOTREACHED */
-	trace_rcu_utilization("End boost kthread@notreached");
+	trace_rcu_utilization(TPS("End boost kthread@notreached"));
 	return 0;
 }
 
@@ -1419,7 +1417,7 @@
 	int spincnt;
 
 	for (spincnt = 0; spincnt < 10; spincnt++) {
-		trace_rcu_utilization("Start CPU kthread@rcu_wait");
+		trace_rcu_utilization(TPS("Start CPU kthread@rcu_wait"));
 		local_bh_disable();
 		*statusp = RCU_KTHREAD_RUNNING;
 		this_cpu_inc(rcu_cpu_kthread_loops);
@@ -1431,15 +1429,15 @@
 			rcu_kthread_do_work();
 		local_bh_enable();
 		if (*workp == 0) {
-			trace_rcu_utilization("End CPU kthread@rcu_wait");
+			trace_rcu_utilization(TPS("End CPU kthread@rcu_wait"));
 			*statusp = RCU_KTHREAD_WAITING;
 			return;
 		}
 	}
 	*statusp = RCU_KTHREAD_YIELDING;
-	trace_rcu_utilization("Start CPU kthread@rcu_yield");
+	trace_rcu_utilization(TPS("Start CPU kthread@rcu_yield"));
 	schedule_timeout_interruptible(2);
-	trace_rcu_utilization("End CPU kthread@rcu_yield");
+	trace_rcu_utilization(TPS("End CPU kthread@rcu_yield"));
 	*statusp = RCU_KTHREAD_WAITING;
 }
 
@@ -2202,7 +2200,7 @@
 	 * Wait for the grace period.  Do so interruptibly to avoid messing
 	 * up the load average.
 	 */
-	trace_rcu_future_gp(rnp, rdp, c, "StartWait");
+	trace_rcu_future_gp(rnp, rdp, c, TPS("StartWait"));
 	for (;;) {
 		wait_event_interruptible(
 			rnp->nocb_gp_wq[c & 0x1],
@@ -2210,9 +2208,9 @@
 		if (likely(d))
 			break;
 		flush_signals(current);
-		trace_rcu_future_gp(rnp, rdp, c, "ResumeWait");
+		trace_rcu_future_gp(rnp, rdp, c, TPS("ResumeWait"));
 	}
-	trace_rcu_future_gp(rnp, rdp, c, "EndWait");
+	trace_rcu_future_gp(rnp, rdp, c, TPS("EndWait"));
 	smp_mb(); /* Ensure that CB invocation happens after GP end. */
 }
 
@@ -2375,3 +2373,425 @@
 		smp_send_reschedule(cpu);
 #endif /* #ifdef CONFIG_NO_HZ_FULL */
 }
+
+
+#ifdef CONFIG_NO_HZ_FULL_SYSIDLE
+
+/*
+ * Define RCU flavor that holds sysidle state.  This needs to be the
+ * most active flavor of RCU.
+ */
+#ifdef CONFIG_PREEMPT_RCU
+static struct rcu_state *rcu_sysidle_state = &rcu_preempt_state;
+#else /* #ifdef CONFIG_PREEMPT_RCU */
+static struct rcu_state *rcu_sysidle_state = &rcu_sched_state;
+#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+
+static int full_sysidle_state;		/* Current system-idle state. */
+#define RCU_SYSIDLE_NOT		0	/* Some CPU is not idle. */
+#define RCU_SYSIDLE_SHORT	1	/* All CPUs idle for brief period. */
+#define RCU_SYSIDLE_LONG	2	/* All CPUs idle for long enough. */
+#define RCU_SYSIDLE_FULL	3	/* All CPUs idle, ready for sysidle. */
+#define RCU_SYSIDLE_FULL_NOTED	4	/* Actually entered sysidle state. */
+
+/*
+ * Invoked to note exit from irq or task transition to idle.  Note that
+ * usermode execution does -not- count as idle here!  After all, we want
+ * to detect full-system idle states, not RCU quiescent states and grace
+ * periods.  The caller must have disabled interrupts.
+ */
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
+{
+	unsigned long j;
+
+	/* Adjust nesting, check for fully idle. */
+	if (irq) {
+		rdtp->dynticks_idle_nesting--;
+		WARN_ON_ONCE(rdtp->dynticks_idle_nesting < 0);
+		if (rdtp->dynticks_idle_nesting != 0)
+			return;  /* Still not fully idle. */
+	} else {
+		if ((rdtp->dynticks_idle_nesting & DYNTICK_TASK_NEST_MASK) ==
+		    DYNTICK_TASK_NEST_VALUE) {
+			rdtp->dynticks_idle_nesting = 0;
+		} else {
+			rdtp->dynticks_idle_nesting -= DYNTICK_TASK_NEST_VALUE;
+			WARN_ON_ONCE(rdtp->dynticks_idle_nesting < 0);
+			return;  /* Still not fully idle. */
+		}
+	}
+
+	/* Record start of fully idle period. */
+	j = jiffies;
+	ACCESS_ONCE(rdtp->dynticks_idle_jiffies) = j;
+	smp_mb__before_atomic_inc();
+	atomic_inc(&rdtp->dynticks_idle);
+	smp_mb__after_atomic_inc();
+	WARN_ON_ONCE(atomic_read(&rdtp->dynticks_idle) & 0x1);
+}
+
+/*
+ * Unconditionally force exit from full system-idle state.  This is
+ * invoked when a normal CPU exits idle, but must be called separately
+ * for the timekeeping CPU (tick_do_timer_cpu).  The reason for this
+ * is that the timekeeping CPU is permitted to take scheduling-clock
+ * interrupts while the system is in system-idle state, and of course
+ * rcu_sysidle_exit() has no way of distinguishing a scheduling-clock
+ * interrupt from any other type of interrupt.
+ */
+void rcu_sysidle_force_exit(void)
+{
+	int oldstate = ACCESS_ONCE(full_sysidle_state);
+	int newoldstate;
+
+	/*
+	 * Each pass through the following loop attempts to exit full
+	 * system-idle state.  If contention proves to be a problem,
+	 * a trylock-based contention tree could be used here.
+	 */
+	while (oldstate > RCU_SYSIDLE_SHORT) {
+		newoldstate = cmpxchg(&full_sysidle_state,
+				      oldstate, RCU_SYSIDLE_NOT);
+		if (oldstate == newoldstate &&
+		    oldstate == RCU_SYSIDLE_FULL_NOTED) {
+			rcu_kick_nohz_cpu(tick_do_timer_cpu);
+			return; /* We cleared it, done! */
+		}
+		oldstate = newoldstate;
+	}
+	smp_mb(); /* Order initial oldstate fetch vs. later non-idle work. */
+}
+
+/*
+ * Invoked to note entry to irq or task transition from idle.  Note that
+ * usermode execution does -not- count as idle here!  The caller must
+ * have disabled interrupts.
+ */
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
+{
+	/* Adjust nesting, check for already non-idle. */
+	if (irq) {
+		rdtp->dynticks_idle_nesting++;
+		WARN_ON_ONCE(rdtp->dynticks_idle_nesting <= 0);
+		if (rdtp->dynticks_idle_nesting != 1)
+			return; /* Already non-idle. */
+	} else {
+		/*
+		 * Allow for irq misnesting.  Yes, it really is possible
+		 * to enter an irq handler then never leave it, and maybe
+		 * also vice versa.  Handle both possibilities.
+		 */
+		if (rdtp->dynticks_idle_nesting & DYNTICK_TASK_NEST_MASK) {
+			rdtp->dynticks_idle_nesting += DYNTICK_TASK_NEST_VALUE;
+			WARN_ON_ONCE(rdtp->dynticks_idle_nesting <= 0);
+			return; /* Already non-idle. */
+		} else {
+			rdtp->dynticks_idle_nesting = DYNTICK_TASK_EXIT_IDLE;
+		}
+	}
+
+	/* Record end of idle period. */
+	smp_mb__before_atomic_inc();
+	atomic_inc(&rdtp->dynticks_idle);
+	smp_mb__after_atomic_inc();
+	WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks_idle) & 0x1));
+
+	/*
+	 * If we are the timekeeping CPU, we are permitted to be non-idle
+	 * during a system-idle state.  This must be the case, because
+	 * the timekeeping CPU has to take scheduling-clock interrupts
+	 * during the time that the system is transitioning to full
+	 * system-idle state.  This means that the timekeeping CPU must
+	 * invoke rcu_sysidle_force_exit() directly if it does anything
+	 * more than take a scheduling-clock interrupt.
+	 */
+	if (smp_processor_id() == tick_do_timer_cpu)
+		return;
+
+	/* Update system-idle state: We are clearly no longer fully idle! */
+	rcu_sysidle_force_exit();
+}
+
+/*
+ * Check to see if the current CPU is idle.  Note that usermode execution
+ * does not count as idle.  The caller must have disabled interrupts.
+ */
+static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
+				  unsigned long *maxj)
+{
+	int cur;
+	unsigned long j;
+	struct rcu_dynticks *rdtp = rdp->dynticks;
+
+	/*
+	 * If some other CPU has already reported non-idle, if this is
+	 * not the flavor of RCU that tracks sysidle state, or if this
+	 * is an offline or the timekeeping CPU, nothing to do.
+	 */
+	if (!*isidle || rdp->rsp != rcu_sysidle_state ||
+	    cpu_is_offline(rdp->cpu) || rdp->cpu == tick_do_timer_cpu)
+		return;
+	if (rcu_gp_in_progress(rdp->rsp))
+		WARN_ON_ONCE(smp_processor_id() != tick_do_timer_cpu);
+
+	/* Pick up current idle and NMI-nesting counter and check. */
+	cur = atomic_read(&rdtp->dynticks_idle);
+	if (cur & 0x1) {
+		*isidle = false; /* We are not idle! */
+		return;
+	}
+	smp_mb(); /* Read counters before timestamps. */
+
+	/* Pick up timestamps. */
+	j = ACCESS_ONCE(rdtp->dynticks_idle_jiffies);
+	/* If this CPU entered idle more recently, update maxj timestamp. */
+	if (ULONG_CMP_LT(*maxj, j))
+		*maxj = j;
+}
+
+/*
+ * Is this the flavor of RCU that is handling full-system idle?
+ */
+static bool is_sysidle_rcu_state(struct rcu_state *rsp)
+{
+	return rsp == rcu_sysidle_state;
+}
+
+/*
+ * Bind the grace-period kthread for the sysidle flavor of RCU to the
+ * timekeeping CPU.
+ */
+static void rcu_bind_gp_kthread(void)
+{
+	int cpu = ACCESS_ONCE(tick_do_timer_cpu);
+
+	if (cpu < 0 || cpu >= nr_cpu_ids)
+		return;
+	if (raw_smp_processor_id() != cpu)
+		set_cpus_allowed_ptr(current, cpumask_of(cpu));
+}
+
+/*
+ * Return a delay in jiffies based on the number of CPUs, rcu_node
+ * leaf fanout, and jiffies tick rate.  The idea is to allow larger
+ * systems more time to transition to full-idle state in order to
+ * avoid the cache thrashing that otherwise occur on the state variable.
+ * Really small systems (less than a couple of tens of CPUs) should
+ * instead use a single global atomically incremented counter, and later
+ * versions of this will automatically reconfigure themselves accordingly.
+ */
+static unsigned long rcu_sysidle_delay(void)
+{
+	if (nr_cpu_ids <= CONFIG_NO_HZ_FULL_SYSIDLE_SMALL)
+		return 0;
+	return DIV_ROUND_UP(nr_cpu_ids * HZ, rcu_fanout_leaf * 1000);
+}
+
+/*
+ * Advance the full-system-idle state.  This is invoked when all of
+ * the non-timekeeping CPUs are idle.
+ */
+static void rcu_sysidle(unsigned long j)
+{
+	/* Check the current state. */
+	switch (ACCESS_ONCE(full_sysidle_state)) {
+	case RCU_SYSIDLE_NOT:
+
+		/* First time all are idle, so note a short idle period. */
+		ACCESS_ONCE(full_sysidle_state) = RCU_SYSIDLE_SHORT;
+		break;
+
+	case RCU_SYSIDLE_SHORT:
+
+		/*
+		 * Idle for a bit, time to advance to next state?
+		 * cmpxchg failure means race with non-idle, let them win.
+		 */
+		if (ULONG_CMP_GE(jiffies, j + rcu_sysidle_delay()))
+			(void)cmpxchg(&full_sysidle_state,
+				      RCU_SYSIDLE_SHORT, RCU_SYSIDLE_LONG);
+		break;
+
+	case RCU_SYSIDLE_LONG:
+
+		/*
+		 * Do an additional check pass before advancing to full.
+		 * cmpxchg failure means race with non-idle, let them win.
+		 */
+		if (ULONG_CMP_GE(jiffies, j + rcu_sysidle_delay()))
+			(void)cmpxchg(&full_sysidle_state,
+				      RCU_SYSIDLE_LONG, RCU_SYSIDLE_FULL);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*
+ * Found a non-idle non-timekeeping CPU, so kick the system-idle state
+ * back to the beginning.
+ */
+static void rcu_sysidle_cancel(void)
+{
+	smp_mb();
+	ACCESS_ONCE(full_sysidle_state) = RCU_SYSIDLE_NOT;
+}
+
+/*
+ * Update the sysidle state based on the results of a force-quiescent-state
+ * scan of the CPUs' dyntick-idle state.
+ */
+static void rcu_sysidle_report(struct rcu_state *rsp, int isidle,
+			       unsigned long maxj, bool gpkt)
+{
+	if (rsp != rcu_sysidle_state)
+		return;  /* Wrong flavor, ignore. */
+	if (gpkt && nr_cpu_ids <= CONFIG_NO_HZ_FULL_SYSIDLE_SMALL)
+		return;  /* Running state machine from timekeeping CPU. */
+	if (isidle)
+		rcu_sysidle(maxj);    /* More idle! */
+	else
+		rcu_sysidle_cancel(); /* Idle is over. */
+}
+
+/*
+ * Wrapper for rcu_sysidle_report() when called from the grace-period
+ * kthread's context.
+ */
+static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle,
+				  unsigned long maxj)
+{
+	rcu_sysidle_report(rsp, isidle, maxj, true);
+}
+
+/* Callback and function for forcing an RCU grace period. */
+struct rcu_sysidle_head {
+	struct rcu_head rh;
+	int inuse;
+};
+
+static void rcu_sysidle_cb(struct rcu_head *rhp)
+{
+	struct rcu_sysidle_head *rshp;
+
+	/*
+	 * The following memory barrier is needed to replace the
+	 * memory barriers that would normally be in the memory
+	 * allocator.
+	 */
+	smp_mb();  /* grace period precedes setting inuse. */
+
+	rshp = container_of(rhp, struct rcu_sysidle_head, rh);
+	ACCESS_ONCE(rshp->inuse) = 0;
+}
+
+/*
+ * Check to see if the system is fully idle, other than the timekeeping CPU.
+ * The caller must have disabled interrupts.
+ */
+bool rcu_sys_is_idle(void)
+{
+	static struct rcu_sysidle_head rsh;
+	int rss = ACCESS_ONCE(full_sysidle_state);
+
+	if (WARN_ON_ONCE(smp_processor_id() != tick_do_timer_cpu))
+		return false;
+
+	/* Handle small-system case by doing a full scan of CPUs. */
+	if (nr_cpu_ids <= CONFIG_NO_HZ_FULL_SYSIDLE_SMALL) {
+		int oldrss = rss - 1;
+
+		/*
+		 * One pass to advance to each state up to _FULL.
+		 * Give up if any pass fails to advance the state.
+		 */
+		while (rss < RCU_SYSIDLE_FULL && oldrss < rss) {
+			int cpu;
+			bool isidle = true;
+			unsigned long maxj = jiffies - ULONG_MAX / 4;
+			struct rcu_data *rdp;
+
+			/* Scan all the CPUs looking for nonidle CPUs. */
+			for_each_possible_cpu(cpu) {
+				rdp = per_cpu_ptr(rcu_sysidle_state->rda, cpu);
+				rcu_sysidle_check_cpu(rdp, &isidle, &maxj);
+				if (!isidle)
+					break;
+			}
+			rcu_sysidle_report(rcu_sysidle_state,
+					   isidle, maxj, false);
+			oldrss = rss;
+			rss = ACCESS_ONCE(full_sysidle_state);
+		}
+	}
+
+	/* If this is the first observation of an idle period, record it. */
+	if (rss == RCU_SYSIDLE_FULL) {
+		rss = cmpxchg(&full_sysidle_state,
+			      RCU_SYSIDLE_FULL, RCU_SYSIDLE_FULL_NOTED);
+		return rss == RCU_SYSIDLE_FULL;
+	}
+
+	smp_mb(); /* ensure rss load happens before later caller actions. */
+
+	/* If already fully idle, tell the caller (in case of races). */
+	if (rss == RCU_SYSIDLE_FULL_NOTED)
+		return true;
+
+	/*
+	 * If we aren't there yet, and a grace period is not in flight,
+	 * initiate a grace period.  Either way, tell the caller that
+	 * we are not there yet.  We use an xchg() rather than an assignment
+	 * to make up for the memory barriers that would otherwise be
+	 * provided by the memory allocator.
+	 */
+	if (nr_cpu_ids > CONFIG_NO_HZ_FULL_SYSIDLE_SMALL &&
+	    !rcu_gp_in_progress(rcu_sysidle_state) &&
+	    !rsh.inuse && xchg(&rsh.inuse, 1) == 0)
+		call_rcu(&rsh.rh, rcu_sysidle_cb);
+	return false;
+}
+
+/*
+ * Initialize dynticks sysidle state for CPUs coming online.
+ */
+static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
+{
+	rdtp->dynticks_idle_nesting = DYNTICK_TASK_NEST_VALUE;
+}
+
+#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
+
+static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
+{
+}
+
+static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
+{
+}
+
+static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
+				  unsigned long *maxj)
+{
+}
+
+static bool is_sysidle_rcu_state(struct rcu_state *rsp)
+{
+	return false;
+}
+
+static void rcu_bind_gp_kthread(void)
+{
+}
+
+static void rcu_sysidle_report_gp(struct rcu_state *rsp, int isidle,
+				  unsigned long maxj)
+{
+}
+
+static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
+{
+}
+
+#endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 05c39f0..5ac63c9 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -978,13 +978,6 @@
 		rq->skip_clock_update = 1;
 }
 
-static ATOMIC_NOTIFIER_HEAD(task_migration_notifier);
-
-void register_task_migration_notifier(struct notifier_block *n)
-{
-	atomic_notifier_chain_register(&task_migration_notifier, n);
-}
-
 #ifdef CONFIG_SMP
 void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
 {
@@ -1015,18 +1008,10 @@
 	trace_sched_migrate_task(p, new_cpu);
 
 	if (task_cpu(p) != new_cpu) {
-		struct task_migration_notifier tmn;
-
 		if (p->sched_class->migrate_task_rq)
 			p->sched_class->migrate_task_rq(p, new_cpu);
 		p->se.nr_migrations++;
 		perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, NULL, 0);
-
-		tmn.task = p;
-		tmn.from_cpu = task_cpu(p);
-		tmn.to_cpu = new_cpu;
-
-		atomic_notifier_call_chain(&task_migration_notifier, 0, &tmn);
 	}
 
 	__set_task_cpu(p, new_cpu);
@@ -2527,13 +2512,11 @@
  */
 asmlinkage void __sched notrace preempt_schedule(void)
 {
-	struct thread_info *ti = current_thread_info();
-
 	/*
 	 * If there is a non-zero preempt_count or interrupts are disabled,
 	 * we do not want to preempt the current task. Just return..
 	 */
-	if (likely(ti->preempt_count || irqs_disabled()))
+	if (likely(!preemptible()))
 		return;
 
 	do {
@@ -2677,7 +2660,7 @@
 	if (unlikely(!q))
 		return;
 
-	if (unlikely(!nr_exclusive))
+	if (unlikely(nr_exclusive != 1))
 		wake_flags = 0;
 
 	spin_lock_irqsave(&q->lock, flags);
@@ -4964,7 +4947,8 @@
 				SD_BALANCE_FORK |
 				SD_BALANCE_EXEC |
 				SD_SHARE_CPUPOWER |
-				SD_SHARE_PKG_RESOURCES);
+				SD_SHARE_PKG_RESOURCES |
+				SD_PREFER_SIBLING);
 		if (nr_node_ids == 1)
 			pflags &= ~SD_SERIALIZE;
 	}
@@ -5133,18 +5117,23 @@
  * 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_size);
 DEFINE_PER_CPU(int, sd_llc_id);
 
 static void update_top_cache_domain(int cpu)
 {
 	struct sched_domain *sd;
 	int id = cpu;
+	int size = 1;
 
 	sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES);
-	if (sd)
+	if (sd) {
 		id = cpumask_first(sched_domain_span(sd));
+		size = cpumask_weight(sched_domain_span(sd));
+	}
 
 	rcu_assign_pointer(per_cpu(sd_llc, cpu), sd);
+	per_cpu(sd_llc_size, cpu) = size;
 	per_cpu(sd_llc_id, cpu) = id;
 }
 
@@ -5168,6 +5157,13 @@
 			tmp->parent = parent->parent;
 			if (parent->parent)
 				parent->parent->child = tmp;
+			/*
+			 * Transfer SD_PREFER_SIBLING down in case of a
+			 * degenerate parent; the spans match for this
+			 * so the property transfers.
+			 */
+			if (parent->flags & SD_PREFER_SIBLING)
+				tmp->flags |= SD_PREFER_SIBLING;
 			destroy_sched_domain(parent, cpu);
 		} else
 			tmp = tmp->parent;
@@ -6234,8 +6230,9 @@
 		;
 	}
 
+	n = ndoms_cur;
 	if (doms_new == NULL) {
-		ndoms_cur = 0;
+		n = 0;
 		doms_new = &fallback_doms;
 		cpumask_andnot(doms_new[0], cpu_active_mask, cpu_isolated_map);
 		WARN_ON_ONCE(dattr_new);
@@ -6243,7 +6240,7 @@
 
 	/* Build new domains */
 	for (i = 0; i < ndoms_new; i++) {
-		for (j = 0; j < ndoms_cur && !new_topology; j++) {
+		for (j = 0; j < n && !new_topology; j++) {
 			if (cpumask_equal(doms_new[i], doms_cur[j])
 			    && dattrs_equal(dattr_new, i, dattr_cur, j))
 				goto match2;
@@ -6815,7 +6812,7 @@
 	if (unlikely(running))
 		tsk->sched_class->put_prev_task(rq, tsk);
 
-	tg = container_of(task_subsys_state_check(tsk, cpu_cgroup_subsys_id,
+	tg = container_of(task_css_check(tsk, cpu_cgroup_subsys_id,
 				lockdep_is_held(&tsk->sighand->siglock)),
 			  struct task_group, css);
 	tg = autogroup_task_group(tsk, tg);
@@ -7137,23 +7134,22 @@
 
 #ifdef CONFIG_CGROUP_SCHED
 
-/* return corresponding task_group object of a cgroup */
-static inline struct task_group *cgroup_tg(struct cgroup *cgrp)
+static inline struct task_group *css_tg(struct cgroup_subsys_state *css)
 {
-	return container_of(cgroup_subsys_state(cgrp, cpu_cgroup_subsys_id),
-			    struct task_group, css);
+	return css ? container_of(css, struct task_group, css) : NULL;
 }
 
-static struct cgroup_subsys_state *cpu_cgroup_css_alloc(struct cgroup *cgrp)
+static struct cgroup_subsys_state *
+cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 {
-	struct task_group *tg, *parent;
+	struct task_group *parent = css_tg(parent_css);
+	struct task_group *tg;
 
-	if (!cgrp->parent) {
+	if (!parent) {
 		/* This is early initialization for the top cgroup */
 		return &root_task_group.css;
 	}
 
-	parent = cgroup_tg(cgrp->parent);
 	tg = sched_create_group(parent);
 	if (IS_ERR(tg))
 		return ERR_PTR(-ENOMEM);
@@ -7161,41 +7157,38 @@
 	return &tg->css;
 }
 
-static int cpu_cgroup_css_online(struct cgroup *cgrp)
+static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
 {
-	struct task_group *tg = cgroup_tg(cgrp);
-	struct task_group *parent;
+	struct task_group *tg = css_tg(css);
+	struct task_group *parent = css_tg(css_parent(css));
 
-	if (!cgrp->parent)
-		return 0;
-
-	parent = cgroup_tg(cgrp->parent);
-	sched_online_group(tg, parent);
+	if (parent)
+		sched_online_group(tg, parent);
 	return 0;
 }
 
-static void cpu_cgroup_css_free(struct cgroup *cgrp)
+static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
 {
-	struct task_group *tg = cgroup_tg(cgrp);
+	struct task_group *tg = css_tg(css);
 
 	sched_destroy_group(tg);
 }
 
-static void cpu_cgroup_css_offline(struct cgroup *cgrp)
+static void cpu_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
-	struct task_group *tg = cgroup_tg(cgrp);
+	struct task_group *tg = css_tg(css);
 
 	sched_offline_group(tg);
 }
 
-static int cpu_cgroup_can_attach(struct cgroup *cgrp,
+static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css,
 				 struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 
-	cgroup_taskset_for_each(task, cgrp, tset) {
+	cgroup_taskset_for_each(task, css, tset) {
 #ifdef CONFIG_RT_GROUP_SCHED
-		if (!sched_rt_can_attach(cgroup_tg(cgrp), task))
+		if (!sched_rt_can_attach(css_tg(css), task))
 			return -EINVAL;
 #else
 		/* We don't support RT-tasks being in separate groups */
@@ -7206,18 +7199,18 @@
 	return 0;
 }
 
-static void cpu_cgroup_attach(struct cgroup *cgrp,
+static void cpu_cgroup_attach(struct cgroup_subsys_state *css,
 			      struct cgroup_taskset *tset)
 {
 	struct task_struct *task;
 
-	cgroup_taskset_for_each(task, cgrp, tset)
+	cgroup_taskset_for_each(task, css, tset)
 		sched_move_task(task);
 }
 
-static void
-cpu_cgroup_exit(struct cgroup *cgrp, struct cgroup *old_cgrp,
-		struct task_struct *task)
+static void cpu_cgroup_exit(struct cgroup_subsys_state *css,
+			    struct cgroup_subsys_state *old_css,
+			    struct task_struct *task)
 {
 	/*
 	 * cgroup_exit() is called in the copy_process() failure path.
@@ -7231,15 +7224,16 @@
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
-static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
-				u64 shareval)
+static int cpu_shares_write_u64(struct cgroup_subsys_state *css,
+				struct cftype *cftype, u64 shareval)
 {
-	return sched_group_set_shares(cgroup_tg(cgrp), scale_load(shareval));
+	return sched_group_set_shares(css_tg(css), scale_load(shareval));
 }
 
-static u64 cpu_shares_read_u64(struct cgroup *cgrp, struct cftype *cft)
+static u64 cpu_shares_read_u64(struct cgroup_subsys_state *css,
+			       struct cftype *cft)
 {
-	struct task_group *tg = cgroup_tg(cgrp);
+	struct task_group *tg = css_tg(css);
 
 	return (u64) scale_load_down(tg->shares);
 }
@@ -7361,26 +7355,28 @@
 	return cfs_period_us;
 }
 
-static s64 cpu_cfs_quota_read_s64(struct cgroup *cgrp, struct cftype *cft)
+static s64 cpu_cfs_quota_read_s64(struct cgroup_subsys_state *css,
+				  struct cftype *cft)
 {
-	return tg_get_cfs_quota(cgroup_tg(cgrp));
+	return tg_get_cfs_quota(css_tg(css));
 }
 
-static int cpu_cfs_quota_write_s64(struct cgroup *cgrp, struct cftype *cftype,
-				s64 cfs_quota_us)
+static int cpu_cfs_quota_write_s64(struct cgroup_subsys_state *css,
+				   struct cftype *cftype, s64 cfs_quota_us)
 {
-	return tg_set_cfs_quota(cgroup_tg(cgrp), cfs_quota_us);
+	return tg_set_cfs_quota(css_tg(css), cfs_quota_us);
 }
 
-static u64 cpu_cfs_period_read_u64(struct cgroup *cgrp, struct cftype *cft)
+static u64 cpu_cfs_period_read_u64(struct cgroup_subsys_state *css,
+				   struct cftype *cft)
 {
-	return tg_get_cfs_period(cgroup_tg(cgrp));
+	return tg_get_cfs_period(css_tg(css));
 }
 
-static int cpu_cfs_period_write_u64(struct cgroup *cgrp, struct cftype *cftype,
-				u64 cfs_period_us)
+static int cpu_cfs_period_write_u64(struct cgroup_subsys_state *css,
+				    struct cftype *cftype, u64 cfs_period_us)
 {
-	return tg_set_cfs_period(cgroup_tg(cgrp), cfs_period_us);
+	return tg_set_cfs_period(css_tg(css), cfs_period_us);
 }
 
 struct cfs_schedulable_data {
@@ -7461,10 +7457,10 @@
 	return ret;
 }
 
-static int cpu_stats_show(struct cgroup *cgrp, struct cftype *cft,
+static int cpu_stats_show(struct cgroup_subsys_state *css, struct cftype *cft,
 		struct cgroup_map_cb *cb)
 {
-	struct task_group *tg = cgroup_tg(cgrp);
+	struct task_group *tg = css_tg(css);
 	struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
 
 	cb->fill(cb, "nr_periods", cfs_b->nr_periods);
@@ -7477,26 +7473,28 @@
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 #ifdef CONFIG_RT_GROUP_SCHED
-static int cpu_rt_runtime_write(struct cgroup *cgrp, struct cftype *cft,
-				s64 val)
+static int cpu_rt_runtime_write(struct cgroup_subsys_state *css,
+				struct cftype *cft, s64 val)
 {
-	return sched_group_set_rt_runtime(cgroup_tg(cgrp), val);
+	return sched_group_set_rt_runtime(css_tg(css), val);
 }
 
-static s64 cpu_rt_runtime_read(struct cgroup *cgrp, struct cftype *cft)
+static s64 cpu_rt_runtime_read(struct cgroup_subsys_state *css,
+			       struct cftype *cft)
 {
-	return sched_group_rt_runtime(cgroup_tg(cgrp));
+	return sched_group_rt_runtime(css_tg(css));
 }
 
-static int cpu_rt_period_write_uint(struct cgroup *cgrp, struct cftype *cftype,
-		u64 rt_period_us)
+static int cpu_rt_period_write_uint(struct cgroup_subsys_state *css,
+				    struct cftype *cftype, u64 rt_period_us)
 {
-	return sched_group_set_rt_period(cgroup_tg(cgrp), rt_period_us);
+	return sched_group_set_rt_period(css_tg(css), rt_period_us);
 }
 
-static u64 cpu_rt_period_read_uint(struct cgroup *cgrp, struct cftype *cft)
+static u64 cpu_rt_period_read_uint(struct cgroup_subsys_state *css,
+				   struct cftype *cft)
 {
-	return sched_group_rt_period(cgroup_tg(cgrp));
+	return sched_group_rt_period(css_tg(css));
 }
 #endif /* CONFIG_RT_GROUP_SCHED */
 
diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c
index dbb7e2c..f64722f 100644
--- a/kernel/sched/cpuacct.c
+++ b/kernel/sched/cpuacct.c
@@ -33,30 +33,20 @@
 	struct kernel_cpustat __percpu *cpustat;
 };
 
-/* return cpu accounting group corresponding to this container */
-static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
+static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css)
 {
-	return container_of(cgroup_subsys_state(cgrp, cpuacct_subsys_id),
-			    struct cpuacct, css);
+	return css ? container_of(css, struct cpuacct, css) : NULL;
 }
 
 /* return cpu accounting group to which this task belongs */
 static inline struct cpuacct *task_ca(struct task_struct *tsk)
 {
-	return container_of(task_subsys_state(tsk, cpuacct_subsys_id),
-			    struct cpuacct, css);
-}
-
-static inline struct cpuacct *__parent_ca(struct cpuacct *ca)
-{
-	return cgroup_ca(ca->css.cgroup->parent);
+	return css_ca(task_css(tsk, cpuacct_subsys_id));
 }
 
 static inline struct cpuacct *parent_ca(struct cpuacct *ca)
 {
-	if (!ca->css.cgroup->parent)
-		return NULL;
-	return cgroup_ca(ca->css.cgroup->parent);
+	return css_ca(css_parent(&ca->css));
 }
 
 static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage);
@@ -66,11 +56,12 @@
 };
 
 /* create a new cpu accounting group */
-static struct cgroup_subsys_state *cpuacct_css_alloc(struct cgroup *cgrp)
+static struct cgroup_subsys_state *
+cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct cpuacct *ca;
 
-	if (!cgrp->parent)
+	if (!parent_css)
 		return &root_cpuacct.css;
 
 	ca = kzalloc(sizeof(*ca), GFP_KERNEL);
@@ -96,9 +87,9 @@
 }
 
 /* destroy an existing cpu accounting group */
-static void cpuacct_css_free(struct cgroup *cgrp)
+static void cpuacct_css_free(struct cgroup_subsys_state *css)
 {
-	struct cpuacct *ca = cgroup_ca(cgrp);
+	struct cpuacct *ca = css_ca(css);
 
 	free_percpu(ca->cpustat);
 	free_percpu(ca->cpuusage);
@@ -141,9 +132,9 @@
 }
 
 /* return total cpu usage (in nanoseconds) of a group */
-static u64 cpuusage_read(struct cgroup *cgrp, struct cftype *cft)
+static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	struct cpuacct *ca = cgroup_ca(cgrp);
+	struct cpuacct *ca = css_ca(css);
 	u64 totalcpuusage = 0;
 	int i;
 
@@ -153,10 +144,10 @@
 	return totalcpuusage;
 }
 
-static int cpuusage_write(struct cgroup *cgrp, struct cftype *cftype,
-								u64 reset)
+static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
+			  u64 reset)
 {
-	struct cpuacct *ca = cgroup_ca(cgrp);
+	struct cpuacct *ca = css_ca(css);
 	int err = 0;
 	int i;
 
@@ -172,10 +163,10 @@
 	return err;
 }
 
-static int cpuacct_percpu_seq_read(struct cgroup *cgroup, struct cftype *cft,
-				   struct seq_file *m)
+static int cpuacct_percpu_seq_read(struct cgroup_subsys_state *css,
+				   struct cftype *cft, struct seq_file *m)
 {
-	struct cpuacct *ca = cgroup_ca(cgroup);
+	struct cpuacct *ca = css_ca(css);
 	u64 percpu;
 	int i;
 
@@ -192,10 +183,10 @@
 	[CPUACCT_STAT_SYSTEM] = "system",
 };
 
-static int cpuacct_stats_show(struct cgroup *cgrp, struct cftype *cft,
-			      struct cgroup_map_cb *cb)
+static int cpuacct_stats_show(struct cgroup_subsys_state *css,
+			      struct cftype *cft, struct cgroup_map_cb *cb)
 {
-	struct cpuacct *ca = cgroup_ca(cgrp);
+	struct cpuacct *ca = css_ca(css);
 	int cpu;
 	s64 val = 0;
 
@@ -281,7 +272,7 @@
 	while (ca != &root_cpuacct) {
 		kcpustat = this_cpu_ptr(ca->cpustat);
 		kcpustat->cpustat[index] += val;
-		ca = __parent_ca(ca);
+		ca = parent_ca(ca);
 	}
 	rcu_read_unlock();
 }
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index a7959e0..ace34f9 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -121,7 +121,7 @@
 	 * is the only cgroup, then nothing else should be necessary.
 	 *
 	 */
-	__get_cpu_var(kernel_cpustat).cpustat[index] += tmp;
+	__this_cpu_add(kernel_cpustat.cpustat[index], tmp);
 
 	cpuacct_account_field(p, index, tmp);
 }
@@ -378,11 +378,8 @@
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 
 #ifndef __ARCH_HAS_VTIME_TASK_SWITCH
-void vtime_task_switch(struct task_struct *prev)
+void vtime_common_task_switch(struct task_struct *prev)
 {
-	if (!vtime_accounting_enabled())
-		return;
-
 	if (is_idle_task(prev))
 		vtime_account_idle(prev);
 	else
@@ -404,11 +401,8 @@
  * vtime_account().
  */
 #ifndef __ARCH_HAS_VTIME_ACCOUNT
-void vtime_account_irq_enter(struct task_struct *tsk)
+void vtime_common_account_irq_enter(struct task_struct *tsk)
 {
-	if (!vtime_accounting_enabled())
-		return;
-
 	if (!in_interrupt()) {
 		/*
 		 * If we interrupted user, context_tracking_in_user()
@@ -428,7 +422,7 @@
 	}
 	vtime_account_system(tsk);
 }
-EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
+EXPORT_SYMBOL_GPL(vtime_common_account_irq_enter);
 #endif /* __ARCH_HAS_VTIME_ACCOUNT */
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING */
 
@@ -559,12 +553,6 @@
 {
 	cputime_t rtime, stime, utime, total;
 
-	if (vtime_accounting_enabled()) {
-		*ut = curr->utime;
-		*st = curr->stime;
-		return;
-	}
-
 	stime = curr->stime;
 	total = stime + curr->utime;
 
@@ -664,23 +652,17 @@
 
 void vtime_account_system(struct task_struct *tsk)
 {
-	if (!vtime_accounting_enabled())
-		return;
-
 	write_seqlock(&tsk->vtime_seqlock);
 	__vtime_account_system(tsk);
 	write_sequnlock(&tsk->vtime_seqlock);
 }
 
-void vtime_account_irq_exit(struct task_struct *tsk)
+void vtime_gen_account_irq_exit(struct task_struct *tsk)
 {
-	if (!vtime_accounting_enabled())
-		return;
-
 	write_seqlock(&tsk->vtime_seqlock);
+	__vtime_account_system(tsk);
 	if (context_tracking_in_user())
 		tsk->vtime_snap_whence = VTIME_USER;
-	__vtime_account_system(tsk);
 	write_sequnlock(&tsk->vtime_seqlock);
 }
 
@@ -688,12 +670,8 @@
 {
 	cputime_t delta_cpu;
 
-	if (!vtime_accounting_enabled())
-		return;
-
-	delta_cpu = get_vtime_delta(tsk);
-
 	write_seqlock(&tsk->vtime_seqlock);
+	delta_cpu = get_vtime_delta(tsk);
 	tsk->vtime_snap_whence = VTIME_SYS;
 	account_user_time(tsk, delta_cpu, cputime_to_scaled(delta_cpu));
 	write_sequnlock(&tsk->vtime_seqlock);
@@ -701,22 +679,27 @@
 
 void vtime_user_enter(struct task_struct *tsk)
 {
-	if (!vtime_accounting_enabled())
-		return;
-
 	write_seqlock(&tsk->vtime_seqlock);
-	tsk->vtime_snap_whence = VTIME_USER;
 	__vtime_account_system(tsk);
+	tsk->vtime_snap_whence = VTIME_USER;
 	write_sequnlock(&tsk->vtime_seqlock);
 }
 
 void vtime_guest_enter(struct task_struct *tsk)
 {
+	/*
+	 * The flags must be updated under the lock with
+	 * the vtime_snap flush and update.
+	 * That enforces a right ordering and update sequence
+	 * synchronization against the reader (task_gtime())
+	 * that can thus safely catch up with a tickless delta.
+	 */
 	write_seqlock(&tsk->vtime_seqlock);
 	__vtime_account_system(tsk);
 	current->flags |= PF_VCPU;
 	write_sequnlock(&tsk->vtime_seqlock);
 }
+EXPORT_SYMBOL_GPL(vtime_guest_enter);
 
 void vtime_guest_exit(struct task_struct *tsk)
 {
@@ -725,6 +708,7 @@
 	current->flags &= ~PF_VCPU;
 	write_sequnlock(&tsk->vtime_seqlock);
 }
+EXPORT_SYMBOL_GPL(vtime_guest_exit);
 
 void vtime_account_idle(struct task_struct *tsk)
 {
@@ -733,11 +717,6 @@
 	account_idle_time(delta_cpu);
 }
 
-bool vtime_accounting_enabled(void)
-{
-	return context_tracking_active();
-}
-
 void arch_vtime_task_switch(struct task_struct *prev)
 {
 	write_seqlock(&prev->vtime_seqlock);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 68f1609..7f0a5e6 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3018,6 +3018,23 @@
 	return 0;
 }
 
+static void record_wakee(struct task_struct *p)
+{
+	/*
+	 * Rough decay (wiping) for cost saving, don't worry
+	 * about the boundary, really active task won't care
+	 * about the loss.
+	 */
+	if (jiffies > current->wakee_flip_decay_ts + HZ) {
+		current->wakee_flips = 0;
+		current->wakee_flip_decay_ts = jiffies;
+	}
+
+	if (current->last_wakee != p) {
+		current->last_wakee = p;
+		current->wakee_flips++;
+	}
+}
 
 static void task_waking_fair(struct task_struct *p)
 {
@@ -3038,6 +3055,7 @@
 #endif
 
 	se->vruntime -= min_vruntime;
+	record_wakee(p);
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -3156,6 +3174,28 @@
 
 #endif
 
+static int wake_wide(struct task_struct *p)
+{
+	int factor = this_cpu_read(sd_llc_size);
+
+	/*
+	 * Yeah, it's the switching-frequency, could means many wakee or
+	 * rapidly switch, use factor here will just help to automatically
+	 * adjust the loose-degree, so bigger node will lead to more pull.
+	 */
+	if (p->wakee_flips > factor) {
+		/*
+		 * wakee is somewhat hot, it needs certain amount of cpu
+		 * resource, so if waker is far more hot, prefer to leave
+		 * it alone.
+		 */
+		if (current->wakee_flips > (factor * p->wakee_flips))
+			return 1;
+	}
+
+	return 0;
+}
+
 static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 {
 	s64 this_load, load;
@@ -3165,6 +3205,13 @@
 	unsigned long weight;
 	int balanced;
 
+	/*
+	 * If we wake multiple tasks be careful to not bounce
+	 * ourselves around too much.
+	 */
+	if (wake_wide(p))
+		return 0;
+
 	idx	  = sd->wake_idx;
 	this_cpu  = smp_processor_id();
 	prev_cpu  = task_cpu(p);
@@ -4172,47 +4219,48 @@
 }
 
 /*
- * Compute the cpu's hierarchical load factor for each task group.
+ * Compute the hierarchical load factor for cfs_rq and all its ascendants.
  * This needs to be done in a top-down fashion because the load of a child
  * group is a fraction of its parents load.
  */
-static int tg_load_down(struct task_group *tg, void *data)
+static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq)
 {
-	unsigned long load;
-	long cpu = (long)data;
-
-	if (!tg->parent) {
-		load = cpu_rq(cpu)->avg.load_avg_contrib;
-	} else {
-		load = tg->parent->cfs_rq[cpu]->h_load;
-		load = div64_ul(load * tg->se[cpu]->avg.load_avg_contrib,
-				tg->parent->cfs_rq[cpu]->runnable_load_avg + 1);
-	}
-
-	tg->cfs_rq[cpu]->h_load = load;
-
-	return 0;
-}
-
-static void update_h_load(long cpu)
-{
-	struct rq *rq = cpu_rq(cpu);
+	struct rq *rq = rq_of(cfs_rq);
+	struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)];
 	unsigned long now = jiffies;
+	unsigned long load;
 
-	if (rq->h_load_throttle == now)
+	if (cfs_rq->last_h_load_update == now)
 		return;
 
-	rq->h_load_throttle = now;
+	cfs_rq->h_load_next = NULL;
+	for_each_sched_entity(se) {
+		cfs_rq = cfs_rq_of(se);
+		cfs_rq->h_load_next = se;
+		if (cfs_rq->last_h_load_update == now)
+			break;
+	}
 
-	rcu_read_lock();
-	walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
-	rcu_read_unlock();
+	if (!se) {
+		cfs_rq->h_load = rq->avg.load_avg_contrib;
+		cfs_rq->last_h_load_update = now;
+	}
+
+	while ((se = cfs_rq->h_load_next) != NULL) {
+		load = cfs_rq->h_load;
+		load = div64_ul(load * se->avg.load_avg_contrib,
+				cfs_rq->runnable_load_avg + 1);
+		cfs_rq = group_cfs_rq(se);
+		cfs_rq->h_load = load;
+		cfs_rq->last_h_load_update = now;
+	}
 }
 
 static unsigned long task_h_load(struct task_struct *p)
 {
 	struct cfs_rq *cfs_rq = task_cfs_rq(p);
 
+	update_cfs_rq_h_load(cfs_rq);
 	return div64_ul(p->se.avg.load_avg_contrib * cfs_rq->h_load,
 			cfs_rq->runnable_load_avg + 1);
 }
@@ -4221,10 +4269,6 @@
 {
 }
 
-static inline void update_h_load(long cpu)
-{
-}
-
 static unsigned long task_h_load(struct task_struct *p)
 {
 	return p->se.avg.load_avg_contrib;
@@ -4233,50 +4277,56 @@
 
 /********** Helpers for find_busiest_group ************************/
 /*
- * sd_lb_stats - Structure to store the statistics of a sched_domain
- * 		during load balancing.
- */
-struct sd_lb_stats {
-	struct sched_group *busiest; /* Busiest group in this sd */
-	struct sched_group *this;  /* Local group in this sd */
-	unsigned long total_load;  /* Total load of all groups in sd */
-	unsigned long total_pwr;   /*	Total power of all groups in sd */
-	unsigned long avg_load;	   /* Average load across all groups in sd */
-
-	/** Statistics of this group */
-	unsigned long this_load;
-	unsigned long this_load_per_task;
-	unsigned long this_nr_running;
-	unsigned long this_has_capacity;
-	unsigned int  this_idle_cpus;
-
-	/* Statistics of the busiest group */
-	unsigned int  busiest_idle_cpus;
-	unsigned long max_load;
-	unsigned long busiest_load_per_task;
-	unsigned long busiest_nr_running;
-	unsigned long busiest_group_capacity;
-	unsigned long busiest_has_capacity;
-	unsigned int  busiest_group_weight;
-
-	int group_imb; /* Is there imbalance in this sd */
-};
-
-/*
  * sg_lb_stats - stats of a sched_group required for load_balancing
  */
 struct sg_lb_stats {
 	unsigned long avg_load; /*Avg load across the CPUs of the group */
 	unsigned long group_load; /* Total load over the CPUs of the group */
-	unsigned long sum_nr_running; /* Nr tasks running in the group */
 	unsigned long sum_weighted_load; /* Weighted load of group's tasks */
-	unsigned long group_capacity;
-	unsigned long idle_cpus;
-	unsigned long group_weight;
+	unsigned long load_per_task;
+	unsigned long group_power;
+	unsigned int sum_nr_running; /* Nr tasks running in the group */
+	unsigned int group_capacity;
+	unsigned int idle_cpus;
+	unsigned int group_weight;
 	int group_imb; /* Is there an imbalance in the group ? */
 	int group_has_capacity; /* Is there extra capacity in the group? */
 };
 
+/*
+ * sd_lb_stats - Structure to store the statistics of a sched_domain
+ *		 during load balancing.
+ */
+struct sd_lb_stats {
+	struct sched_group *busiest;	/* Busiest group in this sd */
+	struct sched_group *local;	/* Local group in this sd */
+	unsigned long total_load;	/* Total load of all groups in sd */
+	unsigned long total_pwr;	/* Total power of all groups in sd */
+	unsigned long avg_load;	/* Average load across all groups in sd */
+
+	struct sg_lb_stats busiest_stat;/* Statistics of the busiest group */
+	struct sg_lb_stats local_stat;	/* Statistics of the local group */
+};
+
+static inline void init_sd_lb_stats(struct sd_lb_stats *sds)
+{
+	/*
+	 * Skimp on the clearing to avoid duplicate work. We can avoid clearing
+	 * local_stat because update_sg_lb_stats() does a full clear/assignment.
+	 * We must however clear busiest_stat::avg_load because
+	 * update_sd_pick_busiest() reads this before assignment.
+	 */
+	*sds = (struct sd_lb_stats){
+		.busiest = NULL,
+		.local = NULL,
+		.total_load = 0UL,
+		.total_pwr = 0UL,
+		.busiest_stat = {
+			.avg_load = 0UL,
+		},
+	};
+}
+
 /**
  * get_sd_load_idx - Obtain the load index for a given sched domain.
  * @sd: The sched_domain whose load_idx is to be obtained.
@@ -4460,88 +4510,65 @@
 	return 0;
 }
 
-/**
- * update_sg_lb_stats - Update sched_group's statistics for load balancing.
- * @env: The load balancing environment.
- * @group: sched_group whose statistics are to be updated.
- * @load_idx: Load index of sched_domain of this_cpu for load calc.
- * @local_group: Does group contain this_cpu.
- * @balance: Should we balance.
- * @sgs: variable to hold the statistics for this group.
+/*
+ * Group imbalance indicates (and tries to solve) the problem where balancing
+ * groups is inadequate due to tsk_cpus_allowed() constraints.
+ *
+ * Imagine a situation of two groups of 4 cpus each and 4 tasks each with a
+ * cpumask covering 1 cpu of the first group and 3 cpus of the second group.
+ * Something like:
+ *
+ * 	{ 0 1 2 3 } { 4 5 6 7 }
+ * 	        *     * * *
+ *
+ * If we were to balance group-wise we'd place two tasks in the first group and
+ * two tasks in the second group. Clearly this is undesired as it will overload
+ * cpu 3 and leave one of the cpus in the second group unused.
+ *
+ * The current solution to this issue is detecting the skew in the first group
+ * by noticing it has a cpu that is overloaded while the remaining cpus are
+ * idle -- or rather, there's a distinct imbalance in the cpus; see
+ * sg_imbalanced().
+ *
+ * When this is so detected; this group becomes a candidate for busiest; see
+ * update_sd_pick_busiest(). And calculcate_imbalance() and
+ * find_busiest_group() avoid some of the usual balance conditional to allow it
+ * to create an effective group imbalance.
+ *
+ * This is a somewhat tricky proposition since the next run might not find the
+ * group imbalance and decide the groups need to be balanced again. A most
+ * subtle and fragile situation.
  */
-static inline void update_sg_lb_stats(struct lb_env *env,
-			struct sched_group *group, int load_idx,
-			int local_group, int *balance, struct sg_lb_stats *sgs)
+
+struct sg_imb_stats {
+	unsigned long max_nr_running, min_nr_running;
+	unsigned long max_cpu_load, min_cpu_load;
+};
+
+static inline void init_sg_imb_stats(struct sg_imb_stats *sgi)
 {
-	unsigned long nr_running, max_nr_running, min_nr_running;
-	unsigned long load, max_cpu_load, min_cpu_load;
-	unsigned int balance_cpu = -1, first_idle_cpu = 0;
-	unsigned long avg_load_per_task = 0;
-	int i;
+	sgi->max_cpu_load = sgi->max_nr_running = 0UL;
+	sgi->min_cpu_load = sgi->min_nr_running = ~0UL;
+}
 
-	if (local_group)
-		balance_cpu = group_balance_cpu(group);
+static inline void
+update_sg_imb_stats(struct sg_imb_stats *sgi,
+		    unsigned long load, unsigned long nr_running)
+{
+	if (load > sgi->max_cpu_load)
+		sgi->max_cpu_load = load;
+	if (sgi->min_cpu_load > load)
+		sgi->min_cpu_load = load;
 
-	/* Tally up the load of all CPUs in the group */
-	max_cpu_load = 0;
-	min_cpu_load = ~0UL;
-	max_nr_running = 0;
-	min_nr_running = ~0UL;
+	if (nr_running > sgi->max_nr_running)
+		sgi->max_nr_running = nr_running;
+	if (sgi->min_nr_running > nr_running)
+		sgi->min_nr_running = nr_running;
+}
 
-	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
-		struct rq *rq = cpu_rq(i);
-
-		nr_running = rq->nr_running;
-
-		/* Bias balancing toward cpus of our domain */
-		if (local_group) {
-			if (idle_cpu(i) && !first_idle_cpu &&
-					cpumask_test_cpu(i, sched_group_mask(group))) {
-				first_idle_cpu = 1;
-				balance_cpu = i;
-			}
-
-			load = target_load(i, load_idx);
-		} else {
-			load = source_load(i, load_idx);
-			if (load > max_cpu_load)
-				max_cpu_load = load;
-			if (min_cpu_load > load)
-				min_cpu_load = load;
-
-			if (nr_running > max_nr_running)
-				max_nr_running = nr_running;
-			if (min_nr_running > nr_running)
-				min_nr_running = nr_running;
-		}
-
-		sgs->group_load += load;
-		sgs->sum_nr_running += nr_running;
-		sgs->sum_weighted_load += weighted_cpuload(i);
-		if (idle_cpu(i))
-			sgs->idle_cpus++;
-	}
-
-	/*
-	 * First idle cpu or the first cpu(busiest) in this sched group
-	 * is eligible for doing load balancing at this and above
-	 * domains. In the newly idle case, we will allow all the cpu's
-	 * to do the newly idle load balance.
-	 */
-	if (local_group) {
-		if (env->idle != CPU_NEWLY_IDLE) {
-			if (balance_cpu != env->dst_cpu) {
-				*balance = 0;
-				return;
-			}
-			update_group_power(env->sd, env->dst_cpu);
-		} else if (time_after_eq(jiffies, group->sgp->next_update))
-			update_group_power(env->sd, env->dst_cpu);
-	}
-
-	/* Adjust by relative CPU power of the group */
-	sgs->avg_load = (sgs->group_load*SCHED_POWER_SCALE) / group->sgp->power;
-
+static inline int
+sg_imbalanced(struct sg_lb_stats *sgs, struct sg_imb_stats *sgi)
+{
 	/*
 	 * Consider the group unbalanced when the imbalance is larger
 	 * than the average weight of a task.
@@ -4551,17 +4578,71 @@
 	 *      normalized nr_running number somewhere that negates
 	 *      the hierarchy?
 	 */
+	if ((sgi->max_cpu_load - sgi->min_cpu_load) >= sgs->load_per_task &&
+	    (sgi->max_nr_running - sgi->min_nr_running) > 1)
+		return 1;
+
+	return 0;
+}
+
+/**
+ * update_sg_lb_stats - Update sched_group's statistics for load balancing.
+ * @env: The load balancing environment.
+ * @group: sched_group whose statistics are to be updated.
+ * @load_idx: Load index of sched_domain of this_cpu for load calc.
+ * @local_group: Does group contain this_cpu.
+ * @sgs: variable to hold the statistics for this group.
+ */
+static inline void update_sg_lb_stats(struct lb_env *env,
+			struct sched_group *group, int load_idx,
+			int local_group, struct sg_lb_stats *sgs)
+{
+	struct sg_imb_stats sgi;
+	unsigned long nr_running;
+	unsigned long load;
+	int i;
+
+	init_sg_imb_stats(&sgi);
+
+	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
+		struct rq *rq = cpu_rq(i);
+
+		nr_running = rq->nr_running;
+
+		/* Bias balancing toward cpus of our domain */
+		if (local_group) {
+			load = target_load(i, load_idx);
+		} else {
+			load = source_load(i, load_idx);
+			update_sg_imb_stats(&sgi, load, nr_running);
+		}
+
+		sgs->group_load += load;
+		sgs->sum_nr_running += nr_running;
+		sgs->sum_weighted_load += weighted_cpuload(i);
+		if (idle_cpu(i))
+			sgs->idle_cpus++;
+	}
+
+	if (local_group && (env->idle != CPU_NEWLY_IDLE ||
+			time_after_eq(jiffies, group->sgp->next_update)))
+		update_group_power(env->sd, env->dst_cpu);
+
+	/* Adjust by relative CPU power of the group */
+	sgs->group_power = group->sgp->power;
+	sgs->avg_load = (sgs->group_load*SCHED_POWER_SCALE) / sgs->group_power;
+
 	if (sgs->sum_nr_running)
-		avg_load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
+		sgs->load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
 
-	if ((max_cpu_load - min_cpu_load) >= avg_load_per_task &&
-	    (max_nr_running - min_nr_running) > 1)
-		sgs->group_imb = 1;
+	sgs->group_imb = sg_imbalanced(sgs, &sgi);
 
-	sgs->group_capacity = DIV_ROUND_CLOSEST(group->sgp->power,
-						SCHED_POWER_SCALE);
+	sgs->group_capacity =
+		DIV_ROUND_CLOSEST(sgs->group_power, SCHED_POWER_SCALE);
+
 	if (!sgs->group_capacity)
 		sgs->group_capacity = fix_small_capacity(env->sd, group);
+
 	sgs->group_weight = group->group_weight;
 
 	if (sgs->group_capacity > sgs->sum_nr_running)
@@ -4586,7 +4667,7 @@
 				   struct sched_group *sg,
 				   struct sg_lb_stats *sgs)
 {
-	if (sgs->avg_load <= sds->max_load)
+	if (sgs->avg_load <= sds->busiest_stat.avg_load)
 		return false;
 
 	if (sgs->sum_nr_running > sgs->group_capacity)
@@ -4619,11 +4700,11 @@
  * @sds: variable to hold the statistics for this sched_domain.
  */
 static inline void update_sd_lb_stats(struct lb_env *env,
-					int *balance, struct sd_lb_stats *sds)
+					struct sd_lb_stats *sds)
 {
 	struct sched_domain *child = env->sd->child;
 	struct sched_group *sg = env->sd->groups;
-	struct sg_lb_stats sgs;
+	struct sg_lb_stats tmp_sgs;
 	int load_idx, prefer_sibling = 0;
 
 	if (child && child->flags & SD_PREFER_SIBLING)
@@ -4632,17 +4713,17 @@
 	load_idx = get_sd_load_idx(env->sd, env->idle);
 
 	do {
+		struct sg_lb_stats *sgs = &tmp_sgs;
 		int local_group;
 
 		local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
-		memset(&sgs, 0, sizeof(sgs));
-		update_sg_lb_stats(env, sg, load_idx, local_group, balance, &sgs);
+		if (local_group) {
+			sds->local = sg;
+			sgs = &sds->local_stat;
+		}
 
-		if (local_group && !(*balance))
-			return;
-
-		sds->total_load += sgs.group_load;
-		sds->total_pwr += sg->sgp->power;
+		memset(sgs, 0, sizeof(*sgs));
+		update_sg_lb_stats(env, sg, load_idx, local_group, sgs);
 
 		/*
 		 * In case the child domain prefers tasks go to siblings
@@ -4654,26 +4735,17 @@
 		 * heaviest group when it is already under-utilized (possible
 		 * with a large weight task outweighs the tasks on the system).
 		 */
-		if (prefer_sibling && !local_group && sds->this_has_capacity)
-			sgs.group_capacity = min(sgs.group_capacity, 1UL);
+		if (prefer_sibling && !local_group &&
+				sds->local && sds->local_stat.group_has_capacity)
+			sgs->group_capacity = min(sgs->group_capacity, 1U);
 
-		if (local_group) {
-			sds->this_load = sgs.avg_load;
-			sds->this = sg;
-			sds->this_nr_running = sgs.sum_nr_running;
-			sds->this_load_per_task = sgs.sum_weighted_load;
-			sds->this_has_capacity = sgs.group_has_capacity;
-			sds->this_idle_cpus = sgs.idle_cpus;
-		} else if (update_sd_pick_busiest(env, sds, sg, &sgs)) {
-			sds->max_load = sgs.avg_load;
+		/* Now, start updating sd_lb_stats */
+		sds->total_load += sgs->group_load;
+		sds->total_pwr += sgs->group_power;
+
+		if (!local_group && update_sd_pick_busiest(env, sds, sg, sgs)) {
 			sds->busiest = sg;
-			sds->busiest_nr_running = sgs.sum_nr_running;
-			sds->busiest_idle_cpus = sgs.idle_cpus;
-			sds->busiest_group_capacity = sgs.group_capacity;
-			sds->busiest_load_per_task = sgs.sum_weighted_load;
-			sds->busiest_has_capacity = sgs.group_has_capacity;
-			sds->busiest_group_weight = sgs.group_weight;
-			sds->group_imb = sgs.group_imb;
+			sds->busiest_stat = *sgs;
 		}
 
 		sg = sg->next;
@@ -4718,7 +4790,8 @@
 		return 0;
 
 	env->imbalance = DIV_ROUND_CLOSEST(
-		sds->max_load * sds->busiest->sgp->power, SCHED_POWER_SCALE);
+		sds->busiest_stat.avg_load * sds->busiest_stat.group_power,
+		SCHED_POWER_SCALE);
 
 	return 1;
 }
@@ -4736,24 +4809,23 @@
 	unsigned long tmp, pwr_now = 0, pwr_move = 0;
 	unsigned int imbn = 2;
 	unsigned long scaled_busy_load_per_task;
+	struct sg_lb_stats *local, *busiest;
 
-	if (sds->this_nr_running) {
-		sds->this_load_per_task /= sds->this_nr_running;
-		if (sds->busiest_load_per_task >
-				sds->this_load_per_task)
-			imbn = 1;
-	} else {
-		sds->this_load_per_task =
-			cpu_avg_load_per_task(env->dst_cpu);
-	}
+	local = &sds->local_stat;
+	busiest = &sds->busiest_stat;
 
-	scaled_busy_load_per_task = sds->busiest_load_per_task
-					 * SCHED_POWER_SCALE;
-	scaled_busy_load_per_task /= sds->busiest->sgp->power;
+	if (!local->sum_nr_running)
+		local->load_per_task = cpu_avg_load_per_task(env->dst_cpu);
+	else if (busiest->load_per_task > local->load_per_task)
+		imbn = 1;
 
-	if (sds->max_load - sds->this_load + scaled_busy_load_per_task >=
-			(scaled_busy_load_per_task * imbn)) {
-		env->imbalance = sds->busiest_load_per_task;
+	scaled_busy_load_per_task =
+		(busiest->load_per_task * SCHED_POWER_SCALE) /
+		busiest->group_power;
+
+	if (busiest->avg_load - local->avg_load + scaled_busy_load_per_task >=
+	    (scaled_busy_load_per_task * imbn)) {
+		env->imbalance = busiest->load_per_task;
 		return;
 	}
 
@@ -4763,34 +4835,37 @@
 	 * moving them.
 	 */
 
-	pwr_now += sds->busiest->sgp->power *
-			min(sds->busiest_load_per_task, sds->max_load);
-	pwr_now += sds->this->sgp->power *
-			min(sds->this_load_per_task, sds->this_load);
+	pwr_now += busiest->group_power *
+			min(busiest->load_per_task, busiest->avg_load);
+	pwr_now += local->group_power *
+			min(local->load_per_task, local->avg_load);
 	pwr_now /= SCHED_POWER_SCALE;
 
 	/* Amount of load we'd subtract */
-	tmp = (sds->busiest_load_per_task * SCHED_POWER_SCALE) /
-		sds->busiest->sgp->power;
-	if (sds->max_load > tmp)
-		pwr_move += sds->busiest->sgp->power *
-			min(sds->busiest_load_per_task, sds->max_load - tmp);
+	tmp = (busiest->load_per_task * SCHED_POWER_SCALE) /
+		busiest->group_power;
+	if (busiest->avg_load > tmp) {
+		pwr_move += busiest->group_power *
+			    min(busiest->load_per_task,
+				busiest->avg_load - tmp);
+	}
 
 	/* Amount of load we'd add */
-	if (sds->max_load * sds->busiest->sgp->power <
-		sds->busiest_load_per_task * SCHED_POWER_SCALE)
-		tmp = (sds->max_load * sds->busiest->sgp->power) /
-			sds->this->sgp->power;
-	else
-		tmp = (sds->busiest_load_per_task * SCHED_POWER_SCALE) /
-			sds->this->sgp->power;
-	pwr_move += sds->this->sgp->power *
-			min(sds->this_load_per_task, sds->this_load + tmp);
+	if (busiest->avg_load * busiest->group_power <
+	    busiest->load_per_task * SCHED_POWER_SCALE) {
+		tmp = (busiest->avg_load * busiest->group_power) /
+		      local->group_power;
+	} else {
+		tmp = (busiest->load_per_task * SCHED_POWER_SCALE) /
+		      local->group_power;
+	}
+	pwr_move += local->group_power *
+		    min(local->load_per_task, local->avg_load + tmp);
 	pwr_move /= SCHED_POWER_SCALE;
 
 	/* Move if we gain throughput */
 	if (pwr_move > pwr_now)
-		env->imbalance = sds->busiest_load_per_task;
+		env->imbalance = busiest->load_per_task;
 }
 
 /**
@@ -4802,11 +4877,18 @@
 static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
 {
 	unsigned long max_pull, load_above_capacity = ~0UL;
+	struct sg_lb_stats *local, *busiest;
 
-	sds->busiest_load_per_task /= sds->busiest_nr_running;
-	if (sds->group_imb) {
-		sds->busiest_load_per_task =
-			min(sds->busiest_load_per_task, sds->avg_load);
+	local = &sds->local_stat;
+	busiest = &sds->busiest_stat;
+
+	if (busiest->group_imb) {
+		/*
+		 * In the group_imb case we cannot rely on group-wide averages
+		 * to ensure cpu-load equilibrium, look at wider averages. XXX
+		 */
+		busiest->load_per_task =
+			min(busiest->load_per_task, sds->avg_load);
 	}
 
 	/*
@@ -4814,21 +4896,22 @@
 	 * max load less than avg load(as we skip the groups at or below
 	 * its cpu_power, while calculating max_load..)
 	 */
-	if (sds->max_load < sds->avg_load) {
+	if (busiest->avg_load < sds->avg_load) {
 		env->imbalance = 0;
 		return fix_small_imbalance(env, sds);
 	}
 
-	if (!sds->group_imb) {
+	if (!busiest->group_imb) {
 		/*
 		 * Don't want to pull so many tasks that a group would go idle.
+		 * Except of course for the group_imb case, since then we might
+		 * have to drop below capacity to reach cpu-load equilibrium.
 		 */
-		load_above_capacity = (sds->busiest_nr_running -
-						sds->busiest_group_capacity);
+		load_above_capacity =
+			(busiest->sum_nr_running - busiest->group_capacity);
 
 		load_above_capacity *= (SCHED_LOAD_SCALE * SCHED_POWER_SCALE);
-
-		load_above_capacity /= sds->busiest->sgp->power;
+		load_above_capacity /= busiest->group_power;
 	}
 
 	/*
@@ -4838,15 +4921,14 @@
 	 * we also don't want to reduce the group load below the group capacity
 	 * (so that we can implement power-savings policies etc). Thus we look
 	 * for the minimum possible imbalance.
-	 * Be careful of negative numbers as they'll appear as very large values
-	 * with unsigned longs.
 	 */
-	max_pull = min(sds->max_load - sds->avg_load, load_above_capacity);
+	max_pull = min(busiest->avg_load - sds->avg_load, load_above_capacity);
 
 	/* How much load to actually move to equalise the imbalance */
-	env->imbalance = min(max_pull * sds->busiest->sgp->power,
-		(sds->avg_load - sds->this_load) * sds->this->sgp->power)
-			/ SCHED_POWER_SCALE;
+	env->imbalance = min(
+		max_pull * busiest->group_power,
+		(sds->avg_load - local->avg_load) * local->group_power
+	) / SCHED_POWER_SCALE;
 
 	/*
 	 * if *imbalance is less than the average load per runnable task
@@ -4854,9 +4936,8 @@
 	 * a think about bumping its value to force at least one task to be
 	 * moved
 	 */
-	if (env->imbalance < sds->busiest_load_per_task)
+	if (env->imbalance < busiest->load_per_task)
 		return fix_small_imbalance(env, sds);
-
 }
 
 /******* find_busiest_group() helpers end here *********************/
@@ -4872,69 +4953,62 @@
  * to restore balance.
  *
  * @env: The load balancing environment.
- * @balance: Pointer to a variable indicating if this_cpu
- *	is the appropriate cpu to perform load balancing at this_level.
  *
  * Return:	- The busiest group if imbalance exists.
  *		- If no imbalance and user has opted for power-savings balance,
  *		   return the least loaded group whose CPUs can be
  *		   put to idle by rebalancing its tasks onto our group.
  */
-static struct sched_group *
-find_busiest_group(struct lb_env *env, int *balance)
+static struct sched_group *find_busiest_group(struct lb_env *env)
 {
+	struct sg_lb_stats *local, *busiest;
 	struct sd_lb_stats sds;
 
-	memset(&sds, 0, sizeof(sds));
+	init_sd_lb_stats(&sds);
 
 	/*
 	 * Compute the various statistics relavent for load balancing at
 	 * this level.
 	 */
-	update_sd_lb_stats(env, balance, &sds);
-
-	/*
-	 * this_cpu is not the appropriate cpu to perform load balancing at
-	 * this level.
-	 */
-	if (!(*balance))
-		goto ret;
+	update_sd_lb_stats(env, &sds);
+	local = &sds.local_stat;
+	busiest = &sds.busiest_stat;
 
 	if ((env->idle == CPU_IDLE || env->idle == CPU_NEWLY_IDLE) &&
 	    check_asym_packing(env, &sds))
 		return sds.busiest;
 
 	/* There is no busy sibling group to pull tasks from */
-	if (!sds.busiest || sds.busiest_nr_running == 0)
+	if (!sds.busiest || busiest->sum_nr_running == 0)
 		goto out_balanced;
 
 	sds.avg_load = (SCHED_POWER_SCALE * sds.total_load) / sds.total_pwr;
 
 	/*
 	 * If the busiest group is imbalanced the below checks don't
-	 * work because they assumes all things are equal, which typically
+	 * work because they assume all things are equal, which typically
 	 * isn't true due to cpus_allowed constraints and the like.
 	 */
-	if (sds.group_imb)
+	if (busiest->group_imb)
 		goto force_balance;
 
 	/* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
-	if (env->idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
-			!sds.busiest_has_capacity)
+	if (env->idle == CPU_NEWLY_IDLE && local->group_has_capacity &&
+	    !busiest->group_has_capacity)
 		goto force_balance;
 
 	/*
 	 * If the local group is more busy than the selected busiest group
 	 * don't try and pull any tasks.
 	 */
-	if (sds.this_load >= sds.max_load)
+	if (local->avg_load >= busiest->avg_load)
 		goto out_balanced;
 
 	/*
 	 * Don't pull any tasks if this group is already above the domain
 	 * average load.
 	 */
-	if (sds.this_load >= sds.avg_load)
+	if (local->avg_load >= sds.avg_load)
 		goto out_balanced;
 
 	if (env->idle == CPU_IDLE) {
@@ -4944,15 +5018,16 @@
 		 * there is no imbalance between this and busiest group
 		 * wrt to idle cpu's, it is balanced.
 		 */
-		if ((sds.this_idle_cpus <= sds.busiest_idle_cpus + 1) &&
-		    sds.busiest_nr_running <= sds.busiest_group_weight)
+		if ((local->idle_cpus < busiest->idle_cpus) &&
+		    busiest->sum_nr_running <= busiest->group_weight)
 			goto out_balanced;
 	} else {
 		/*
 		 * In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use
 		 * imbalance_pct to be conservative.
 		 */
-		if (100 * sds.max_load <= env->sd->imbalance_pct * sds.this_load)
+		if (100 * busiest->avg_load <=
+				env->sd->imbalance_pct * local->avg_load)
 			goto out_balanced;
 	}
 
@@ -4962,7 +5037,6 @@
 	return sds.busiest;
 
 out_balanced:
-ret:
 	env->imbalance = 0;
 	return NULL;
 }
@@ -4974,10 +5048,10 @@
 				     struct sched_group *group)
 {
 	struct rq *busiest = NULL, *rq;
-	unsigned long max_load = 0;
+	unsigned long busiest_load = 0, busiest_power = 1;
 	int i;
 
-	for_each_cpu(i, sched_group_cpus(group)) {
+	for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
 		unsigned long power = power_of(i);
 		unsigned long capacity = DIV_ROUND_CLOSEST(power,
 							   SCHED_POWER_SCALE);
@@ -4986,9 +5060,6 @@
 		if (!capacity)
 			capacity = fix_small_capacity(env->sd, group);
 
-		if (!cpumask_test_cpu(i, env->cpus))
-			continue;
-
 		rq = cpu_rq(i);
 		wl = weighted_cpuload(i);
 
@@ -5004,11 +5075,15 @@
 		 * the weighted_cpuload() scaled with the cpu power, so that
 		 * the load can be moved away from the cpu that is potentially
 		 * running at a lower capacity.
+		 *
+		 * Thus we're looking for max(wl_i / power_i), crosswise
+		 * multiplication to rid ourselves of the division works out
+		 * to: wl_i * power_j > wl_j * power_i;  where j is our
+		 * previous maximum.
 		 */
-		wl = (wl * SCHED_POWER_SCALE) / power;
-
-		if (wl > max_load) {
-			max_load = wl;
+		if (wl * busiest_power > busiest_load * power) {
+			busiest_load = wl;
+			busiest_power = power;
 			busiest = rq;
 		}
 	}
@@ -5045,13 +5120,47 @@
 
 static int active_load_balance_cpu_stop(void *data);
 
+static int should_we_balance(struct lb_env *env)
+{
+	struct sched_group *sg = env->sd->groups;
+	struct cpumask *sg_cpus, *sg_mask;
+	int cpu, balance_cpu = -1;
+
+	/*
+	 * In the newly idle case, we will allow all the cpu's
+	 * to do the newly idle load balance.
+	 */
+	if (env->idle == CPU_NEWLY_IDLE)
+		return 1;
+
+	sg_cpus = sched_group_cpus(sg);
+	sg_mask = sched_group_mask(sg);
+	/* Try to find first idle cpu */
+	for_each_cpu_and(cpu, sg_cpus, env->cpus) {
+		if (!cpumask_test_cpu(cpu, sg_mask) || !idle_cpu(cpu))
+			continue;
+
+		balance_cpu = cpu;
+		break;
+	}
+
+	if (balance_cpu == -1)
+		balance_cpu = group_balance_cpu(sg);
+
+	/*
+	 * First idle cpu or the first cpu(busiest) in this sched group
+	 * is eligible for doing load balancing at this and above domains.
+	 */
+	return balance_cpu != env->dst_cpu;
+}
+
 /*
  * Check this_cpu to ensure it is balanced within domain. Attempt to move
  * tasks if there is an imbalance.
  */
 static int load_balance(int this_cpu, struct rq *this_rq,
 			struct sched_domain *sd, enum cpu_idle_type idle,
-			int *balance)
+			int *continue_balancing)
 {
 	int ld_moved, cur_ld_moved, active_balance = 0;
 	struct sched_group *group;
@@ -5081,11 +5190,12 @@
 	schedstat_inc(sd, lb_count[idle]);
 
 redo:
-	group = find_busiest_group(&env, balance);
-
-	if (*balance == 0)
+	if (!should_we_balance(&env)) {
+		*continue_balancing = 0;
 		goto out_balanced;
+	}
 
+	group = find_busiest_group(&env);
 	if (!group) {
 		schedstat_inc(sd, lb_nobusyg[idle]);
 		goto out_balanced;
@@ -5114,7 +5224,6 @@
 		env.src_rq    = busiest;
 		env.loop_max  = min(sysctl_sched_nr_migrate, busiest->nr_running);
 
-		update_h_load(env.src_cpu);
 more_balance:
 		local_irq_save(flags);
 		double_rq_lock(env.dst_rq, busiest);
@@ -5298,7 +5407,7 @@
 	rcu_read_lock();
 	for_each_domain(this_cpu, sd) {
 		unsigned long interval;
-		int balance = 1;
+		int continue_balancing = 1;
 
 		if (!(sd->flags & SD_LOAD_BALANCE))
 			continue;
@@ -5306,7 +5415,8 @@
 		if (sd->flags & SD_BALANCE_NEWIDLE) {
 			/* If we've pulled tasks over stop searching: */
 			pulled_task = load_balance(this_cpu, this_rq,
-						   sd, CPU_NEWLY_IDLE, &balance);
+						   sd, CPU_NEWLY_IDLE,
+						   &continue_balancing);
 		}
 
 		interval = msecs_to_jiffies(sd->balance_interval);
@@ -5544,7 +5654,7 @@
  */
 static void rebalance_domains(int cpu, enum cpu_idle_type idle)
 {
-	int balance = 1;
+	int continue_balancing = 1;
 	struct rq *rq = cpu_rq(cpu);
 	unsigned long interval;
 	struct sched_domain *sd;
@@ -5576,7 +5686,7 @@
 		}
 
 		if (time_after_eq(jiffies, sd->last_balance + interval)) {
-			if (load_balance(cpu, rq, sd, idle, &balance)) {
+			if (load_balance(cpu, rq, sd, idle, &continue_balancing)) {
 				/*
 				 * The LBF_SOME_PINNED logic could have changed
 				 * env->dst_cpu, so we can't know our idle
@@ -5599,7 +5709,7 @@
 		 * CPU in our sched group which is doing load balancing more
 		 * actively.
 		 */
-		if (!balance)
+		if (!continue_balancing)
 			break;
 	}
 	rcu_read_unlock();
@@ -5895,11 +6005,9 @@
 	* and ensure we don't carry in an old decay_count if we
 	* switch back.
 	*/
-	if (p->se.avg.decay_count) {
-		struct cfs_rq *cfs_rq = cfs_rq_of(&p->se);
-		__synchronize_entity_decay(&p->se);
-		subtract_blocked_load_contrib(cfs_rq,
-				p->se.avg.load_avg_contrib);
+	if (se->avg.decay_count) {
+		__synchronize_entity_decay(se);
+		subtract_blocked_load_contrib(cfs_rq, se->avg.load_avg_contrib);
 	}
 #endif
 }
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index ef0a7b2..b3c5653 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -285,7 +285,6 @@
 	/* Required to track per-cpu representation of a task_group */
 	u32 tg_runnable_contrib;
 	unsigned long tg_load_contrib;
-#endif /* CONFIG_FAIR_GROUP_SCHED */
 
 	/*
 	 *   h_load = weight * f(tg)
@@ -294,6 +293,9 @@
 	 * this group.
 	 */
 	unsigned long h_load;
+	u64 last_h_load_update;
+	struct sched_entity *h_load_next;
+#endif /* CONFIG_FAIR_GROUP_SCHED */
 #endif /* CONFIG_SMP */
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -429,9 +431,6 @@
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/* list of leaf cfs_rq on this cpu: */
 	struct list_head leaf_cfs_rq_list;
-#ifdef CONFIG_SMP
-	unsigned long h_load_throttle;
-#endif /* CONFIG_SMP */
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 #ifdef CONFIG_RT_GROUP_SCHED
@@ -595,6 +594,7 @@
 }
 
 DECLARE_PER_CPU(struct sched_domain *, sd_llc);
+DECLARE_PER_CPU(int, sd_llc_size);
 DECLARE_PER_CPU(int, sd_llc_id);
 
 struct sched_group_power {
@@ -665,9 +665,9 @@
 /*
  * Return the group to which this tasks belongs.
  *
- * We cannot use task_subsys_state() and friends because the cgroup
- * subsystem changes that value before the cgroup_subsys::attach() method
- * is called, therefore we cannot pin it and might observe the wrong value.
+ * We cannot use task_css() and friends because the cgroup subsystem
+ * changes that value before the cgroup_subsys::attach() method is called,
+ * therefore we cannot pin it and might observe the wrong value.
  *
  * The same is true for autogroup's p->signal->autogroup->tg, the autogroup
  * core changes this before calling sched_move_task().
diff --git a/kernel/smp.c b/kernel/smp.c
index fe9f773..449b707 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -186,25 +186,13 @@
 
 	while (!list_empty(&list)) {
 		struct call_single_data *csd;
-		unsigned int csd_flags;
 
 		csd = list_entry(list.next, struct call_single_data, list);
 		list_del(&csd->list);
 
-		/*
-		 * 'csd' can be invalid after this call if flags == 0
-		 * (when called through generic_exec_single()),
-		 * so save them away before making the call:
-		 */
-		csd_flags = csd->flags;
-
 		csd->func(csd->info);
 
-		/*
-		 * Unlocked CSDs are valid through generic_exec_single():
-		 */
-		if (csd_flags & CSD_FLAG_LOCK)
-			csd_unlock(csd);
+		csd_unlock(csd);
 	}
 }
 
@@ -278,8 +266,6 @@
  * @wait: If true, wait until function has completed.
  *
  * Returns 0 on success, else a negative status code (if no cpus were online).
- * Note that @wait will be implicitly turned on in case of allocation failures,
- * since we fall back to on-stack allocation.
  *
  * Selection preference:
  *	1) current cpu if in @mask
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 70f27e8..2b62fe8 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -105,7 +105,6 @@
 	select RCU_USER_QS
 	select RCU_NOCB_CPU
 	select VIRT_CPU_ACCOUNTING_GEN
-	select CONTEXT_TRACKING_FORCE
 	select IRQ_WORK
 	help
 	 Adaptively try to shutdown the tick whenever possible, even when
@@ -134,6 +133,56 @@
 	 Note the boot CPU will still be kept outside the range to
 	 handle the timekeeping duty.
 
+config NO_HZ_FULL_SYSIDLE
+	bool "Detect full-system idle state for full dynticks system"
+	depends on NO_HZ_FULL
+	default n
+	help
+	 At least one CPU must keep the scheduling-clock tick running for
+	 timekeeping purposes whenever there is a non-idle CPU, where
+	 "non-idle" also includes dynticks CPUs as long as they are
+	 running non-idle tasks.  Because the underlying adaptive-tick
+	 support cannot distinguish between all CPUs being idle and
+	 all CPUs each running a single task in dynticks mode, the
+	 underlying support simply ensures that there is always a CPU
+	 handling the scheduling-clock tick, whether or not all CPUs
+	 are idle.  This Kconfig option enables scalable detection of
+	 the all-CPUs-idle state, thus allowing the scheduling-clock
+	 tick to be disabled when all CPUs are idle.  Note that scalable
+	 detection of the all-CPUs-idle state means that larger systems
+	 will be slower to declare the all-CPUs-idle state.
+
+	 Say Y if you would like to help debug all-CPUs-idle detection.
+
+	 Say N if you are unsure.
+
+config NO_HZ_FULL_SYSIDLE_SMALL
+	int "Number of CPUs above which large-system approach is used"
+	depends on NO_HZ_FULL_SYSIDLE
+	range 1 NR_CPUS
+	default 8
+	help
+	 The full-system idle detection mechanism takes a lazy approach
+	 on large systems, as is required to attain decent scalability.
+	 However, on smaller systems, scalability is not anywhere near as
+	 large a concern as is energy efficiency.  The sysidle subsystem
+	 therefore uses a fast but non-scalable algorithm for small
+	 systems and a lazier but scalable algorithm for large systems.
+	 This Kconfig parameter defines the number of CPUs in the largest
+	 system that will be considered to be "small".
+
+	 The default value will be fine in most cases.	Battery-powered
+	 systems that (1) enable NO_HZ_FULL_SYSIDLE, (2) have larger
+	 numbers of CPUs, and (3) are suffering from battery-lifetime
+	 problems due to long sysidle latencies might wish to experiment
+	 with larger values for this Kconfig parameter.  On the other
+	 hand, they might be even better served by disabling NO_HZ_FULL
+	 entirely, given that NO_HZ_FULL is intended for HPC and
+	 real-time workloads that at present do not tend to be run on
+	 battery-powered systems.
+
+	 Take the default if you are unsure.
+
 config NO_HZ
 	bool "Old Idle dynticks config"
 	depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c
index a326f27..0b479a6 100644
--- a/kernel/time/sched_clock.c
+++ b/kernel/time/sched_clock.c
@@ -121,7 +121,7 @@
 	BUG_ON(bits > 32);
 	WARN_ON(!irqs_disabled());
 	read_sched_clock = read;
-	sched_clock_mask = (1 << bits) - 1;
+	sched_clock_mask = (1ULL << bits) - 1;
 	cd.rate = rate;
 
 	/* calculate the mult/shift to convert counter ticks to ns. */
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index e77edc9..3612fc7 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -23,6 +23,7 @@
 #include <linux/irq_work.h>
 #include <linux/posix-timers.h>
 #include <linux/perf_event.h>
+#include <linux/context_tracking.h>
 
 #include <asm/irq_regs.h>
 
@@ -148,8 +149,8 @@
 }
 
 #ifdef CONFIG_NO_HZ_FULL
-static cpumask_var_t nohz_full_mask;
-bool have_nohz_full_mask;
+cpumask_var_t tick_nohz_full_mask;
+bool tick_nohz_full_running;
 
 static bool can_stop_full_tick(void)
 {
@@ -182,7 +183,8 @@
 		 * Don't allow the user to think they can get
 		 * full NO_HZ with this machine.
 		 */
-		WARN_ONCE(1, "NO_HZ FULL will not work with unstable sched clock");
+		WARN_ONCE(tick_nohz_full_running,
+			  "NO_HZ FULL will not work with unstable sched clock");
 		return false;
 	}
 #endif
@@ -196,7 +198,7 @@
  * Re-evaluate the need for the tick on the current CPU
  * and restart it if necessary.
  */
-void tick_nohz_full_check(void)
+void __tick_nohz_full_check(void)
 {
 	struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 
@@ -210,7 +212,7 @@
 
 static void nohz_full_kick_work_func(struct irq_work *work)
 {
-	tick_nohz_full_check();
+	__tick_nohz_full_check();
 }
 
 static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = {
@@ -229,7 +231,7 @@
 
 static void nohz_full_kick_ipi(void *info)
 {
-	tick_nohz_full_check();
+	__tick_nohz_full_check();
 }
 
 /*
@@ -238,12 +240,13 @@
  */
 void tick_nohz_full_kick_all(void)
 {
-	if (!have_nohz_full_mask)
+	if (!tick_nohz_full_running)
 		return;
 
 	preempt_disable();
-	smp_call_function_many(nohz_full_mask,
+	smp_call_function_many(tick_nohz_full_mask,
 			       nohz_full_kick_ipi, NULL, false);
+	tick_nohz_full_kick();
 	preempt_enable();
 }
 
@@ -252,7 +255,7 @@
  * It might need the tick due to per task/process properties:
  * perf events, posix cpu timers, ...
  */
-void tick_nohz_task_switch(struct task_struct *tsk)
+void __tick_nohz_task_switch(struct task_struct *tsk)
 {
 	unsigned long flags;
 
@@ -268,31 +271,23 @@
 	local_irq_restore(flags);
 }
 
-int tick_nohz_full_cpu(int cpu)
-{
-	if (!have_nohz_full_mask)
-		return 0;
-
-	return cpumask_test_cpu(cpu, nohz_full_mask);
-}
-
 /* Parse the boot-time nohz CPU list from the kernel parameters. */
 static int __init tick_nohz_full_setup(char *str)
 {
 	int cpu;
 
-	alloc_bootmem_cpumask_var(&nohz_full_mask);
-	if (cpulist_parse(str, nohz_full_mask) < 0) {
+	alloc_bootmem_cpumask_var(&tick_nohz_full_mask);
+	if (cpulist_parse(str, tick_nohz_full_mask) < 0) {
 		pr_warning("NOHZ: Incorrect nohz_full cpumask\n");
 		return 1;
 	}
 
 	cpu = smp_processor_id();
-	if (cpumask_test_cpu(cpu, nohz_full_mask)) {
+	if (cpumask_test_cpu(cpu, tick_nohz_full_mask)) {
 		pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu);
-		cpumask_clear_cpu(cpu, nohz_full_mask);
+		cpumask_clear_cpu(cpu, tick_nohz_full_mask);
 	}
-	have_nohz_full_mask = true;
+	tick_nohz_full_running = true;
 
 	return 1;
 }
@@ -310,7 +305,7 @@
 		 * If we handle the timekeeping duty for full dynticks CPUs,
 		 * we can't safely shutdown that CPU.
 		 */
-		if (have_nohz_full_mask && tick_do_timer_cpu == cpu)
+		if (tick_nohz_full_running && tick_do_timer_cpu == cpu)
 			return NOTIFY_BAD;
 		break;
 	}
@@ -329,14 +324,14 @@
 	int err = -1;
 
 #ifdef CONFIG_NO_HZ_FULL_ALL
-	if (!alloc_cpumask_var(&nohz_full_mask, GFP_KERNEL)) {
+	if (!alloc_cpumask_var(&tick_nohz_full_mask, GFP_KERNEL)) {
 		pr_err("NO_HZ: Can't allocate full dynticks cpumask\n");
 		return err;
 	}
 	err = 0;
-	cpumask_setall(nohz_full_mask);
-	cpumask_clear_cpu(smp_processor_id(), nohz_full_mask);
-	have_nohz_full_mask = true;
+	cpumask_setall(tick_nohz_full_mask);
+	cpumask_clear_cpu(smp_processor_id(), tick_nohz_full_mask);
+	tick_nohz_full_running = true;
 #endif
 	return err;
 }
@@ -345,17 +340,18 @@
 {
 	int cpu;
 
-	if (!have_nohz_full_mask) {
+	if (!tick_nohz_full_running) {
 		if (tick_nohz_init_all() < 0)
 			return;
 	}
 
+	for_each_cpu(cpu, tick_nohz_full_mask)
+		context_tracking_cpu_set(cpu);
+
 	cpu_notifier(tick_nohz_cpu_down_callback, 0);
-	cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask);
+	cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), tick_nohz_full_mask);
 	pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf);
 }
-#else
-#define have_nohz_full_mask (0)
 #endif
 
 /*
@@ -733,7 +729,7 @@
 		return false;
 	}
 
-	if (have_nohz_full_mask) {
+	if (tick_nohz_full_enabled()) {
 		/*
 		 * Keep the tick alive to guarantee timekeeping progression
 		 * if there are full dynticks CPUs around
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 3bdf283..61ed862 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -265,10 +265,9 @@
 static int timer_list_show(struct seq_file *m, void *v)
 {
 	struct timer_list_iter *iter = v;
-	u64 now = ktime_to_ns(ktime_get());
 
 	if (iter->cpu == -1 && !iter->second_pass)
-		timer_list_header(m, now);
+		timer_list_header(m, iter->now);
 	else if (!iter->second_pass)
 		print_cpu(m, iter->cpu, iter->now);
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
@@ -298,33 +297,41 @@
 	return;
 }
 
+static void *move_iter(struct timer_list_iter *iter, loff_t offset)
+{
+	for (; offset; offset--) {
+		iter->cpu = cpumask_next(iter->cpu, cpu_online_mask);
+		if (iter->cpu >= nr_cpu_ids) {
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+			if (!iter->second_pass) {
+				iter->cpu = -1;
+				iter->second_pass = true;
+			} else
+				return NULL;
+#else
+			return NULL;
+#endif
+		}
+	}
+	return iter;
+}
+
 static void *timer_list_start(struct seq_file *file, loff_t *offset)
 {
 	struct timer_list_iter *iter = file->private;
 
-	if (!*offset) {
-		iter->cpu = -1;
+	if (!*offset)
 		iter->now = ktime_to_ns(ktime_get());
-	} else if (iter->cpu >= nr_cpu_ids) {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-		if (!iter->second_pass) {
-			iter->cpu = -1;
-			iter->second_pass = true;
-		} else
-			return NULL;
-#else
-		return NULL;
-#endif
-	}
-	return iter;
+	iter->cpu = -1;
+	iter->second_pass = false;
+	return move_iter(iter, *offset);
 }
 
 static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset)
 {
 	struct timer_list_iter *iter = file->private;
-	iter->cpu = cpumask_next(iter->cpu, cpu_online_mask);
 	++*offset;
-	return timer_list_start(file, offset);
+	return move_iter(iter, 1);
 }
 
 static void timer_list_stop(struct seq_file *seq, void *v)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index afaae41..fe39acd 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1022,6 +1022,9 @@
 extern const char *__start___trace_bprintk_fmt[];
 extern const char *__stop___trace_bprintk_fmt[];
 
+extern const char *__start___tracepoint_str[];
+extern const char *__stop___tracepoint_str[];
+
 void trace_printk_init_buffers(void);
 void trace_printk_start_comm(void);
 int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index a9077c1..2900817 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -244,12 +244,31 @@
 {
 	const char **fmt = v;
 	int start_index;
+	int last_index;
 
 	start_index = __stop___trace_bprintk_fmt - __start___trace_bprintk_fmt;
 
 	if (*pos < start_index)
 		return __start___trace_bprintk_fmt + *pos;
 
+	/*
+	 * The __tracepoint_str section is treated the same as the
+	 * __trace_printk_fmt section. The difference is that the
+	 * __trace_printk_fmt section should only be used by trace_printk()
+	 * in a debugging environment, as if anything exists in that section
+	 * the trace_prink() helper buffers are allocated, which would just
+	 * waste space in a production environment.
+	 *
+	 * The __tracepoint_str sections on the other hand are used by
+	 * tracepoints which need to map pointers to their strings to
+	 * the ASCII text for userspace.
+	 */
+	last_index = start_index;
+	start_index = __stop___tracepoint_str - __start___tracepoint_str;
+
+	if (*pos < last_index + start_index)
+		return __start___tracepoint_str + (*pos - last_index);
+
 	return find_next_mod_format(start_index, v, fmt, pos);
 }
 
diff --git a/kernel/wait.c b/kernel/wait.c
index dec68bd..d550920 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -363,8 +363,7 @@
 
 /**
  * wake_up_atomic_t - Wake up a waiter on a atomic_t
- * @word: The word being waited on, a kernel virtual address
- * @bit: The bit of the word being waited on
+ * @p: The atomic_t being waited on, a kernel virtual address
  *
  * Wake up anyone waiting for the atomic_t to go to zero.
  *
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 1241d8c..51c4f34 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -553,14 +553,6 @@
 {
 	set_sample_period();
 
-#ifdef CONFIG_NO_HZ_FULL
-	if (watchdog_user_enabled) {
-		watchdog_user_enabled = 0;
-		pr_warning("Disabled lockup detectors by default for full dynticks\n");
-		pr_warning("You can reactivate it with 'sysctl -w kernel.watchdog=1'\n");
-	}
-#endif
-
 	if (watchdog_user_enabled)
 		watchdog_enable_all_cpus();
 }
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 7f5d4be..29b7985 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -16,9 +16,10 @@
  *
  * This is the generic async execution mechanism.  Work items as are
  * executed in process context.  The worker pool is shared and
- * automatically managed.  There is one worker pool for each CPU and
- * one extra for works which are better served by workers which are
- * not bound to any specific CPU.
+ * automatically managed.  There are two worker pools for each CPU (one for
+ * normal work items and the other for high priority ones) and some extra
+ * pools for workqueues which are not bound to any specific CPU - the
+ * number of these backing pools is dynamic.
  *
  * Please read Documentation/workqueue.txt for details.
  */
@@ -2033,8 +2034,11 @@
  * multiple times.  Does GFP_KERNEL allocations.
  *
  * RETURNS:
- * spin_lock_irq(pool->lock) which may be released and regrabbed
- * multiple times.  Does GFP_KERNEL allocations.
+ * %false if the pool don't need management and the caller can safely start
+ * processing works, %true indicates that the function released pool->lock
+ * and reacquired it to perform some management function and that the
+ * conditions that the caller verified while holding the lock before
+ * calling the function might no longer be true.
  */
 static bool manage_workers(struct worker *worker)
 {
@@ -2201,6 +2205,15 @@
 		dump_stack();
 	}
 
+	/*
+	 * The following prevents a kworker from hogging CPU on !PREEMPT
+	 * kernels, where a requeueing work item waiting for something to
+	 * happen could deadlock with stop_machine as such work item could
+	 * indefinitely requeue itself while all other CPUs are trapped in
+	 * stop_machine.
+	 */
+	cond_resched();
+
 	spin_lock_irq(&pool->lock);
 
 	/* clear cpu intensive status */
@@ -3086,25 +3099,26 @@
 	return wq_dev->wq;
 }
 
-static ssize_t wq_per_cpu_show(struct device *dev,
-			       struct device_attribute *attr, char *buf)
+static ssize_t per_cpu_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
 {
 	struct workqueue_struct *wq = dev_to_wq(dev);
 
 	return scnprintf(buf, PAGE_SIZE, "%d\n", (bool)!(wq->flags & WQ_UNBOUND));
 }
+static DEVICE_ATTR_RO(per_cpu);
 
-static ssize_t wq_max_active_show(struct device *dev,
-				  struct device_attribute *attr, char *buf)
+static ssize_t max_active_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct workqueue_struct *wq = dev_to_wq(dev);
 
 	return scnprintf(buf, PAGE_SIZE, "%d\n", wq->saved_max_active);
 }
 
-static ssize_t wq_max_active_store(struct device *dev,
-				   struct device_attribute *attr,
-				   const char *buf, size_t count)
+static ssize_t max_active_store(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
 {
 	struct workqueue_struct *wq = dev_to_wq(dev);
 	int val;
@@ -3115,12 +3129,14 @@
 	workqueue_set_max_active(wq, val);
 	return count;
 }
+static DEVICE_ATTR_RW(max_active);
 
-static struct device_attribute wq_sysfs_attrs[] = {
-	__ATTR(per_cpu, 0444, wq_per_cpu_show, NULL),
-	__ATTR(max_active, 0644, wq_max_active_show, wq_max_active_store),
-	__ATTR_NULL,
+static struct attribute *wq_sysfs_attrs[] = {
+	&dev_attr_per_cpu.attr,
+	&dev_attr_max_active.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(wq_sysfs);
 
 static ssize_t wq_pool_ids_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -3270,7 +3286,7 @@
 
 static struct bus_type wq_subsys = {
 	.name				= "workqueue",
-	.dev_attrs			= wq_sysfs_attrs,
+	.dev_groups			= wq_sysfs_groups,
 };
 
 static int __init wq_sysfs_init(void)
diff --git a/lib/Kconfig b/lib/Kconfig
index 71d9f81..6556171 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -48,6 +48,16 @@
 config PERCPU_RWSEM
 	boolean
 
+config ARCH_USE_CMPXCHG_LOCKREF
+	bool
+
+config CMPXCHG_LOCKREF
+	def_bool y if ARCH_USE_CMPXCHG_LOCKREF
+	depends on SMP
+	depends on !GENERIC_LOCKBREAK
+	depends on !DEBUG_SPINLOCK
+	depends on !DEBUG_LOCK_ALLOC
+
 config CRC_CCITT
 	tristate "CRC-CCITT functions"
 	help
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1501aa5..444e1c1 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -981,6 +981,25 @@
 	  If you say Y here, some extra kobject debugging messages will be sent
 	  to the syslog. 
 
+config DEBUG_KOBJECT_RELEASE
+	bool "kobject release debugging"
+	depends on DEBUG_KERNEL
+	help
+	  kobjects are reference counted objects.  This means that their
+	  last reference count put is not predictable, and the kobject can
+	  live on past the point at which a driver decides to drop it's
+	  initial reference to the kobject gained on allocation.  An
+	  example of this would be a struct device which has just been
+	  unregistered.
+
+	  However, some buggy drivers assume that after such an operation,
+	  the memory backing the kobject can be immediately freed.  This
+	  goes completely against the principles of a refcounted object.
+
+	  If you say Y here, the kernel will delay the release of kobjects
+	  on the last reference count to improve the visibility of this
+	  kind of kobject release bug.
+
 config HAVE_DEBUG_BUGVERBOSE
 	bool
 
diff --git a/lib/Makefile b/lib/Makefile
index 7baccfd..f2cb308 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,6 +20,7 @@
 lib-$(CONFIG_SMP) += cpumask.o
 
 lib-y	+= kobject.o klist.o
+obj-y	+= lockref.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
 	 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
index 37061ed..bf2c8b1 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -381,19 +381,21 @@
  * debug_object_activate - debug checks when an object is activated
  * @addr:	address of the object
  * @descr:	pointer to an object specific debug description structure
+ * Returns 0 for success, -EINVAL for check failed.
  */
-void debug_object_activate(void *addr, struct debug_obj_descr *descr)
+int debug_object_activate(void *addr, struct debug_obj_descr *descr)
 {
 	enum debug_obj_state state;
 	struct debug_bucket *db;
 	struct debug_obj *obj;
 	unsigned long flags;
+	int ret;
 	struct debug_obj o = { .object = addr,
 			       .state = ODEBUG_STATE_NOTAVAILABLE,
 			       .descr = descr };
 
 	if (!debug_objects_enabled)
-		return;
+		return 0;
 
 	db = get_bucket((unsigned long) addr);
 
@@ -405,23 +407,26 @@
 		case ODEBUG_STATE_INIT:
 		case ODEBUG_STATE_INACTIVE:
 			obj->state = ODEBUG_STATE_ACTIVE;
+			ret = 0;
 			break;
 
 		case ODEBUG_STATE_ACTIVE:
 			debug_print_object(obj, "activate");
 			state = obj->state;
 			raw_spin_unlock_irqrestore(&db->lock, flags);
-			debug_object_fixup(descr->fixup_activate, addr, state);
-			return;
+			ret = debug_object_fixup(descr->fixup_activate, addr, state);
+			return ret ? -EINVAL : 0;
 
 		case ODEBUG_STATE_DESTROYED:
 			debug_print_object(obj, "activate");
+			ret = -EINVAL;
 			break;
 		default:
+			ret = 0;
 			break;
 		}
 		raw_spin_unlock_irqrestore(&db->lock, flags);
-		return;
+		return ret;
 	}
 
 	raw_spin_unlock_irqrestore(&db->lock, flags);
@@ -431,8 +436,11 @@
 	 * true or not.
 	 */
 	if (debug_object_fixup(descr->fixup_activate, addr,
-			   ODEBUG_STATE_NOTAVAILABLE))
+			   ODEBUG_STATE_NOTAVAILABLE)) {
 		debug_print_object(&o, "activate");
+		return -EINVAL;
+	}
+	return 0;
 }
 
 /**
diff --git a/lib/dump_stack.c b/lib/dump_stack.c
index c031541..f23b63f 100644
--- a/lib/dump_stack.c
+++ b/lib/dump_stack.c
@@ -23,7 +23,7 @@
 #ifdef CONFIG_SMP
 static atomic_t dump_lock = ATOMIC_INIT(-1);
 
-void dump_stack(void)
+asmlinkage void dump_stack(void)
 {
 	int was_locked;
 	int old;
@@ -55,7 +55,7 @@
 	preempt_enable();
 }
 #else
-void dump_stack(void)
+asmlinkage void dump_stack(void)
 {
 	__dump_stack();
 }
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 99fec3a..c37aeac 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -309,7 +309,7 @@
 			struct ddebug_query *query, const char *modname)
 {
 	unsigned int i;
-	int rc;
+	int rc = 0;
 
 	/* check we have an even number of words */
 	if (nwords % 2 != 0) {
diff --git a/lib/earlycpio.c b/lib/earlycpio.c
index 7aa7ce2..3eb3e47 100644
--- a/lib/earlycpio.c
+++ b/lib/earlycpio.c
@@ -49,22 +49,23 @@
 
 /**
  * cpio_data find_cpio_data - Search for files in an uncompressed cpio
- * @path:   The directory to search for, including a slash at the end
- * @data:   Pointer to the the cpio archive or a header inside
- * @len:    Remaining length of the cpio based on data pointer
- * @offset: When a matching file is found, this is the offset to the
- *          beginning of the cpio. It can be used to iterate through
- *          the cpio to find all files inside of a directory path
+ * @path:       The directory to search for, including a slash at the end
+ * @data:       Pointer to the the cpio archive or a header inside
+ * @len:        Remaining length of the cpio based on data pointer
+ * @nextoff:    When a matching file is found, this is the offset from the
+ *              beginning of the cpio to the beginning of the next file, not the
+ *              matching file itself. It can be used to iterate through the cpio
+ *              to find all files inside of a directory path.
  *
- * @return: struct cpio_data containing the address, length and
- *          filename (with the directory path cut off) of the found file.
- *          If you search for a filename and not for files in a directory,
- *          pass the absolute path of the filename in the cpio and make sure
- *          the match returned an empty filename string.
+ * @return:     struct cpio_data containing the address, length and
+ *              filename (with the directory path cut off) of the found file.
+ *              If you search for a filename and not for files in a directory,
+ *              pass the absolute path of the filename in the cpio and make sure
+ *              the match returned an empty filename string.
  */
 
 struct cpio_data find_cpio_data(const char *path, void *data,
-					  size_t len,  long *offset)
+				size_t len,  long *nextoff)
 {
 	const size_t cpio_header_len = 8*C_NFIELDS - 2;
 	struct cpio_data cd = { NULL, 0, "" };
@@ -124,7 +125,7 @@
 		if ((ch[C_MODE] & 0170000) == 0100000 &&
 		    ch[C_NAMESIZE] >= mypathsize &&
 		    !memcmp(p, path, mypathsize)) {
-			*offset = (long)nptr - (long)data;
+			*nextoff = (long)nptr - (long)data;
 			if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) {
 				pr_warn(
 				"File %s exceeding MAX_CPIO_FILE_NAME [%d]\n",
diff --git a/lib/kobject.c b/lib/kobject.c
index 4a1f33d..1d46c15 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -545,8 +545,8 @@
 	struct kobj_type *t = get_ktype(kobj);
 	const char *name = kobj->name;
 
-	pr_debug("kobject: '%s' (%p): %s\n",
-		 kobject_name(kobj), kobj, __func__);
+	pr_debug("kobject: '%s' (%p): %s, parent %p\n",
+		 kobject_name(kobj), kobj, __func__, kobj->parent);
 
 	if (t && !t->release)
 		pr_debug("kobject: '%s' (%p): does not have a release() "
@@ -580,9 +580,25 @@
 	}
 }
 
+#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
+static void kobject_delayed_cleanup(struct work_struct *work)
+{
+	kobject_cleanup(container_of(to_delayed_work(work),
+				     struct kobject, release));
+}
+#endif
+
 static void kobject_release(struct kref *kref)
 {
-	kobject_cleanup(container_of(kref, struct kobject, kref));
+	struct kobject *kobj = container_of(kref, struct kobject, kref);
+#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
+	pr_debug("kobject: '%s' (%p): %s, parent %p (delayed)\n",
+		 kobject_name(kobj), kobj, __func__, kobj->parent);
+	INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
+	schedule_delayed_work(&kobj->release, HZ);
+#else
+	kobject_cleanup(kobj);
+#endif
 }
 
 /**
diff --git a/lib/lockref.c b/lib/lockref.c
new file mode 100644
index 0000000..9d76f40
--- /dev/null
+++ b/lib/lockref.c
@@ -0,0 +1,128 @@
+#include <linux/export.h>
+#include <linux/lockref.h>
+
+#ifdef CONFIG_CMPXCHG_LOCKREF
+
+/*
+ * Note that the "cmpxchg()" reloads the "old" value for the
+ * failure case.
+ */
+#define CMPXCHG_LOOP(CODE, SUCCESS) do {					\
+	struct lockref old;							\
+	BUILD_BUG_ON(sizeof(old) != 8);						\
+	old.lock_count = ACCESS_ONCE(lockref->lock_count);			\
+	while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) {  	\
+		struct lockref new = old, prev = old;				\
+		CODE								\
+		old.lock_count = cmpxchg(&lockref->lock_count,			\
+					 old.lock_count, new.lock_count);	\
+		if (likely(old.lock_count == prev.lock_count)) {		\
+			SUCCESS;						\
+		}								\
+		cpu_relax();							\
+	}									\
+} while (0)
+
+#else
+
+#define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0)
+
+#endif
+
+/**
+ * lockref_get - Increments reference count unconditionally
+ * @lockcnt: pointer to lockref structure
+ *
+ * This operation is only valid if you already hold a reference
+ * to the object, so you know the count cannot be zero.
+ */
+void lockref_get(struct lockref *lockref)
+{
+	CMPXCHG_LOOP(
+		new.count++;
+	,
+		return;
+	);
+
+	spin_lock(&lockref->lock);
+	lockref->count++;
+	spin_unlock(&lockref->lock);
+}
+EXPORT_SYMBOL(lockref_get);
+
+/**
+ * lockref_get_not_zero - Increments count unless the count is 0
+ * @lockcnt: pointer to lockref structure
+ * Return: 1 if count updated successfully or 0 if count was zero
+ */
+int lockref_get_not_zero(struct lockref *lockref)
+{
+	int retval;
+
+	CMPXCHG_LOOP(
+		new.count++;
+		if (!old.count)
+			return 0;
+	,
+		return 1;
+	);
+
+	spin_lock(&lockref->lock);
+	retval = 0;
+	if (lockref->count) {
+		lockref->count++;
+		retval = 1;
+	}
+	spin_unlock(&lockref->lock);
+	return retval;
+}
+EXPORT_SYMBOL(lockref_get_not_zero);
+
+/**
+ * lockref_get_or_lock - Increments count unless the count is 0
+ * @lockcnt: pointer to lockref structure
+ * Return: 1 if count updated successfully or 0 if count was zero
+ * and we got the lock instead.
+ */
+int lockref_get_or_lock(struct lockref *lockref)
+{
+	CMPXCHG_LOOP(
+		new.count++;
+		if (!old.count)
+			break;
+	,
+		return 1;
+	);
+
+	spin_lock(&lockref->lock);
+	if (!lockref->count)
+		return 0;
+	lockref->count++;
+	spin_unlock(&lockref->lock);
+	return 1;
+}
+EXPORT_SYMBOL(lockref_get_or_lock);
+
+/**
+ * lockref_put_or_lock - decrements count unless count <= 1 before decrement
+ * @lockcnt: pointer to lockref structure
+ * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken
+ */
+int lockref_put_or_lock(struct lockref *lockref)
+{
+	CMPXCHG_LOOP(
+		new.count--;
+		if (old.count <= 1)
+			break;
+	,
+		return 1;
+	);
+
+	spin_lock(&lockref->lock);
+	if (lockref->count <= 1)
+		return 0;
+	lockref->count--;
+	spin_unlock(&lockref->lock);
+	return 1;
+}
+EXPORT_SYMBOL(lockref_put_or_lock);
diff --git a/lib/lz4/lz4_compress.c b/lib/lz4/lz4_compress.c
index fd94058..28321d8 100644
--- a/lib/lz4/lz4_compress.c
+++ b/lib/lz4/lz4_compress.c
@@ -437,7 +437,7 @@
 exit:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(lz4_compress);
+EXPORT_SYMBOL(lz4_compress);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("LZ4 compressor");
diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c
index d3414ea..411be80 100644
--- a/lib/lz4/lz4_decompress.c
+++ b/lib/lz4/lz4_decompress.c
@@ -299,7 +299,7 @@
 	return ret;
 }
 #ifndef STATIC
-EXPORT_SYMBOL_GPL(lz4_decompress);
+EXPORT_SYMBOL(lz4_decompress);
 #endif
 
 int lz4_decompress_unknownoutputsize(const char *src, size_t src_len,
@@ -319,8 +319,8 @@
 	return ret;
 }
 #ifndef STATIC
-EXPORT_SYMBOL_GPL(lz4_decompress_unknownoutputsize);
+EXPORT_SYMBOL(lz4_decompress_unknownoutputsize);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("LZ4 Decompressor");
 #endif
diff --git a/lib/lz4/lz4hc_compress.c b/lib/lz4/lz4hc_compress.c
index eb1a74f..f344f76 100644
--- a/lib/lz4/lz4hc_compress.c
+++ b/lib/lz4/lz4hc_compress.c
@@ -533,7 +533,7 @@
 exit:
 	return ret;
 }
-EXPORT_SYMBOL_GPL(lz4hc_compress);
+EXPORT_SYMBOL(lz4hc_compress);
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("LZ4HC compressor");
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index d23762e..4e8686c 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -870,13 +870,13 @@
 				swiotlb_full(hwdev, sg->length, dir, 0);
 				swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,
 						       attrs);
-				sgl[0].dma_length = 0;
+				sg_dma_len(sgl) = 0;
 				return 0;
 			}
 			sg->dma_address = phys_to_dma(hwdev, map);
 		} else
 			sg->dma_address = dev_addr;
-		sg->dma_length = sg->length;
+		sg_dma_len(sg) = sg->length;
 	}
 	return nelems;
 }
@@ -904,7 +904,7 @@
 	BUG_ON(dir == DMA_NONE);
 
 	for_each_sg(sgl, sg, nelems, i)
-		unmap_single(hwdev, sg->dma_address, sg->dma_length, dir);
+		unmap_single(hwdev, sg->dma_address, sg_dma_len(sg), dir);
 
 }
 EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
@@ -934,7 +934,7 @@
 
 	for_each_sg(sgl, sg, nelems, i)
 		swiotlb_sync_single(hwdev, sg->dma_address,
-				    sg->dma_length, dir, target);
+				    sg_dma_len(sg), dir, target);
 }
 
 void
diff --git a/mm/Kconfig b/mm/Kconfig
index 8028dcc..6cdd270 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -478,6 +478,30 @@
 
 	  If unsure, say Y to enable frontswap.
 
+config CMA
+	bool "Contiguous Memory Allocator"
+	depends on HAVE_MEMBLOCK
+	select MIGRATION
+	select MEMORY_ISOLATION
+	help
+	  This enables the Contiguous Memory Allocator which allows other
+	  subsystems to allocate big physically-contiguous blocks of memory.
+	  CMA reserves a region of memory and allows only movable pages to
+	  be allocated from it. This way, the kernel can use the memory for
+	  pagecache and when a subsystem requests for contiguous area, the
+	  allocated pages are migrated away to serve the contiguous request.
+
+	  If unsure, say "n".
+
+config CMA_DEBUG
+	bool "CMA debug messages (DEVELOPMENT)"
+	depends on DEBUG_KERNEL && CMA
+	help
+	  Turns on debug messages in CMA.  This produces KERN_DEBUG
+	  messages for every CMA call as well as various messages while
+	  processing calls such as dma_alloc_from_contiguous().
+	  This option does not affect warning and error messages.
+
 config ZBUD
 	tristate
 	default n
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index e04454c..37d9edc 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -180,7 +180,8 @@
 	struct backing_dev_info *bdi = dev_get_drvdata(dev);		\
 									\
 	return snprintf(page, PAGE_SIZE-1, "%lld\n", (long long)expr);	\
-}
+}									\
+static DEVICE_ATTR_RW(name);
 
 BDI_SHOW(read_ahead_kb, K(bdi->ra_pages))
 
@@ -231,14 +232,16 @@
 	return snprintf(page, PAGE_SIZE-1, "%d\n",
 			bdi_cap_stable_pages_required(bdi) ? 1 : 0);
 }
+static DEVICE_ATTR_RO(stable_pages_required);
 
-static struct device_attribute bdi_dev_attrs[] = {
-	__ATTR_RW(read_ahead_kb),
-	__ATTR_RW(min_ratio),
-	__ATTR_RW(max_ratio),
-	__ATTR_RO(stable_pages_required),
-	__ATTR_NULL,
+static struct attribute *bdi_dev_attrs[] = {
+	&dev_attr_read_ahead_kb.attr,
+	&dev_attr_min_ratio.attr,
+	&dev_attr_max_ratio.attr,
+	&dev_attr_stable_pages_required.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(bdi_dev);
 
 static __init int bdi_class_init(void)
 {
@@ -246,7 +249,7 @@
 	if (IS_ERR(bdi_class))
 		return PTR_ERR(bdi_class);
 
-	bdi_class->dev_attrs = bdi_dev_attrs;
+	bdi_class->dev_groups = bdi_dev_groups;
 	bdi_debug_init();
 	return 0;
 }
diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c
index 9cea7de..bda8e44 100644
--- a/mm/hugetlb_cgroup.c
+++ b/mm/hugetlb_cgroup.c
@@ -36,21 +36,13 @@
 static inline
 struct hugetlb_cgroup *hugetlb_cgroup_from_css(struct cgroup_subsys_state *s)
 {
-	return container_of(s, struct hugetlb_cgroup, css);
-}
-
-static inline
-struct hugetlb_cgroup *hugetlb_cgroup_from_cgroup(struct cgroup *cgroup)
-{
-	return hugetlb_cgroup_from_css(cgroup_subsys_state(cgroup,
-							   hugetlb_subsys_id));
+	return s ? container_of(s, struct hugetlb_cgroup, css) : NULL;
 }
 
 static inline
 struct hugetlb_cgroup *hugetlb_cgroup_from_task(struct task_struct *task)
 {
-	return hugetlb_cgroup_from_css(task_subsys_state(task,
-							 hugetlb_subsys_id));
+	return hugetlb_cgroup_from_css(task_css(task, hugetlb_subsys_id));
 }
 
 static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg)
@@ -58,17 +50,15 @@
 	return (h_cg == root_h_cgroup);
 }
 
-static inline struct hugetlb_cgroup *parent_hugetlb_cgroup(struct cgroup *cg)
+static inline struct hugetlb_cgroup *
+parent_hugetlb_cgroup(struct hugetlb_cgroup *h_cg)
 {
-	if (!cg->parent)
-		return NULL;
-	return hugetlb_cgroup_from_cgroup(cg->parent);
+	return hugetlb_cgroup_from_css(css_parent(&h_cg->css));
 }
 
-static inline bool hugetlb_cgroup_have_usage(struct cgroup *cg)
+static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg)
 {
 	int idx;
-	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cg);
 
 	for (idx = 0; idx < hugetlb_max_hstate; idx++) {
 		if ((res_counter_read_u64(&h_cg->hugepage[idx], RES_USAGE)) > 0)
@@ -77,19 +67,18 @@
 	return false;
 }
 
-static struct cgroup_subsys_state *hugetlb_cgroup_css_alloc(struct cgroup *cgroup)
+static struct cgroup_subsys_state *
+hugetlb_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 {
+	struct hugetlb_cgroup *parent_h_cgroup = hugetlb_cgroup_from_css(parent_css);
+	struct hugetlb_cgroup *h_cgroup;
 	int idx;
-	struct cgroup *parent_cgroup;
-	struct hugetlb_cgroup *h_cgroup, *parent_h_cgroup;
 
 	h_cgroup = kzalloc(sizeof(*h_cgroup), GFP_KERNEL);
 	if (!h_cgroup)
 		return ERR_PTR(-ENOMEM);
 
-	parent_cgroup = cgroup->parent;
-	if (parent_cgroup) {
-		parent_h_cgroup = hugetlb_cgroup_from_cgroup(parent_cgroup);
+	if (parent_h_cgroup) {
 		for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
 			res_counter_init(&h_cgroup->hugepage[idx],
 					 &parent_h_cgroup->hugepage[idx]);
@@ -101,11 +90,11 @@
 	return &h_cgroup->css;
 }
 
-static void hugetlb_cgroup_css_free(struct cgroup *cgroup)
+static void hugetlb_cgroup_css_free(struct cgroup_subsys_state *css)
 {
 	struct hugetlb_cgroup *h_cgroup;
 
-	h_cgroup = hugetlb_cgroup_from_cgroup(cgroup);
+	h_cgroup = hugetlb_cgroup_from_css(css);
 	kfree(h_cgroup);
 }
 
@@ -117,15 +106,14 @@
  * page reference and test for page active here. This function
  * cannot fail.
  */
-static void hugetlb_cgroup_move_parent(int idx, struct cgroup *cgroup,
+static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg,
 				       struct page *page)
 {
 	int csize;
 	struct res_counter *counter;
 	struct res_counter *fail_res;
 	struct hugetlb_cgroup *page_hcg;
-	struct hugetlb_cgroup *h_cg   = hugetlb_cgroup_from_cgroup(cgroup);
-	struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(cgroup);
+	struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(h_cg);
 
 	page_hcg = hugetlb_cgroup_from_page(page);
 	/*
@@ -155,8 +143,9 @@
  * Force the hugetlb cgroup to empty the hugetlb resources by moving them to
  * the parent cgroup.
  */
-static void hugetlb_cgroup_css_offline(struct cgroup *cgroup)
+static void hugetlb_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
 	struct hstate *h;
 	struct page *page;
 	int idx = 0;
@@ -165,13 +154,13 @@
 		for_each_hstate(h) {
 			spin_lock(&hugetlb_lock);
 			list_for_each_entry(page, &h->hugepage_activelist, lru)
-				hugetlb_cgroup_move_parent(idx, cgroup, page);
+				hugetlb_cgroup_move_parent(idx, h_cg, page);
 
 			spin_unlock(&hugetlb_lock);
 			idx++;
 		}
 		cond_resched();
-	} while (hugetlb_cgroup_have_usage(cgroup));
+	} while (hugetlb_cgroup_have_usage(h_cg));
 }
 
 int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
@@ -253,14 +242,15 @@
 	return;
 }
 
-static ssize_t hugetlb_cgroup_read(struct cgroup *cgroup, struct cftype *cft,
-				   struct file *file, char __user *buf,
-				   size_t nbytes, loff_t *ppos)
+static ssize_t hugetlb_cgroup_read(struct cgroup_subsys_state *css,
+				   struct cftype *cft, struct file *file,
+				   char __user *buf, size_t nbytes,
+				   loff_t *ppos)
 {
 	u64 val;
 	char str[64];
 	int idx, name, len;
-	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
 
 	idx = MEMFILE_IDX(cft->private);
 	name = MEMFILE_ATTR(cft->private);
@@ -270,12 +260,12 @@
 	return simple_read_from_buffer(buf, nbytes, ppos, str, len);
 }
 
-static int hugetlb_cgroup_write(struct cgroup *cgroup, struct cftype *cft,
-				const char *buffer)
+static int hugetlb_cgroup_write(struct cgroup_subsys_state *css,
+				struct cftype *cft, const char *buffer)
 {
 	int idx, name, ret;
 	unsigned long long val;
-	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
 
 	idx = MEMFILE_IDX(cft->private);
 	name = MEMFILE_ATTR(cft->private);
@@ -300,10 +290,11 @@
 	return ret;
 }
 
-static int hugetlb_cgroup_reset(struct cgroup *cgroup, unsigned int event)
+static int hugetlb_cgroup_reset(struct cgroup_subsys_state *css,
+				unsigned int event)
 {
 	int idx, name, ret = 0;
-	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
+	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
 
 	idx = MEMFILE_IDX(event);
 	name = MEMFILE_ATTR(event);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index c5792a5..3b83957 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -483,10 +483,9 @@
  */
 static DEFINE_MUTEX(memcg_create_mutex);
 
-static inline
 struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *s)
 {
-	return container_of(s, struct mem_cgroup, css);
+	return s ? container_of(s, struct mem_cgroup, css) : NULL;
 }
 
 /* Some nice accessors for the vmpressure. */
@@ -1035,12 +1034,6 @@
 		preempt_enable();
 }
 
-struct mem_cgroup *mem_cgroup_from_cont(struct cgroup *cont)
-{
-	return mem_cgroup_from_css(
-		cgroup_subsys_state(cont, mem_cgroup_subsys_id));
-}
-
 struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
 {
 	/*
@@ -1051,7 +1044,7 @@
 	if (unlikely(!p))
 		return NULL;
 
-	return mem_cgroup_from_css(task_subsys_state(p, mem_cgroup_subsys_id));
+	return mem_cgroup_from_css(task_css(p, mem_cgroup_subsys_id));
 }
 
 struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
@@ -1084,20 +1077,11 @@
 static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root,
 		struct mem_cgroup *last_visited)
 {
-	struct cgroup *prev_cgroup, *next_cgroup;
+	struct cgroup_subsys_state *prev_css, *next_css;
 
-	/*
-	 * Root is not visited by cgroup iterators so it needs an
-	 * explicit visit.
-	 */
-	if (!last_visited)
-		return root;
-
-	prev_cgroup = (last_visited == root) ? NULL
-		: last_visited->css.cgroup;
+	prev_css = last_visited ? &last_visited->css : NULL;
 skip_node:
-	next_cgroup = cgroup_next_descendant_pre(
-			prev_cgroup, root->css.cgroup);
+	next_css = css_next_descendant_pre(prev_css, &root->css);
 
 	/*
 	 * Even if we found a group we have to make sure it is
@@ -1106,13 +1090,13 @@
 	 * last_visited css is safe to use because it is
 	 * protected by css_get and the tree walk is rcu safe.
 	 */
-	if (next_cgroup) {
-		struct mem_cgroup *mem = mem_cgroup_from_cont(
-				next_cgroup);
+	if (next_css) {
+		struct mem_cgroup *mem = mem_cgroup_from_css(next_css);
+
 		if (css_tryget(&mem->css))
 			return mem;
 		else {
-			prev_cgroup = next_cgroup;
+			prev_css = next_css;
 			goto skip_node;
 		}
 	}
@@ -1525,10 +1509,8 @@
 
 int mem_cgroup_swappiness(struct mem_cgroup *memcg)
 {
-	struct cgroup *cgrp = memcg->css.cgroup;
-
 	/* root ? */
-	if (cgrp->parent == NULL)
+	if (!css_parent(&memcg->css))
 		return vm_swappiness;
 
 	return memcg->swappiness;
@@ -1805,12 +1787,11 @@
 	check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, order, NULL);
 	totalpages = mem_cgroup_get_limit(memcg) >> PAGE_SHIFT ? : 1;
 	for_each_mem_cgroup_tree(iter, memcg) {
-		struct cgroup *cgroup = iter->css.cgroup;
-		struct cgroup_iter it;
+		struct css_task_iter it;
 		struct task_struct *task;
 
-		cgroup_iter_start(cgroup, &it);
-		while ((task = cgroup_iter_next(cgroup, &it))) {
+		css_task_iter_start(&iter->css, &it);
+		while ((task = css_task_iter_next(&it))) {
 			switch (oom_scan_process_thread(task, totalpages, NULL,
 							false)) {
 			case OOM_SCAN_SELECT:
@@ -1823,7 +1804,7 @@
 			case OOM_SCAN_CONTINUE:
 				continue;
 			case OOM_SCAN_ABORT:
-				cgroup_iter_end(cgroup, &it);
+				css_task_iter_end(&it);
 				mem_cgroup_iter_break(memcg, iter);
 				if (chosen)
 					put_task_struct(chosen);
@@ -1840,7 +1821,7 @@
 				get_task_struct(chosen);
 			}
 		}
-		cgroup_iter_end(cgroup, &it);
+		css_task_iter_end(&it);
 	}
 
 	if (!chosen)
@@ -2954,10 +2935,10 @@
 }
 
 #ifdef CONFIG_SLABINFO
-static int mem_cgroup_slabinfo_read(struct cgroup *cont, struct cftype *cft,
-					struct seq_file *m)
+static int mem_cgroup_slabinfo_read(struct cgroup_subsys_state *css,
+				    struct cftype *cft, struct seq_file *m)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct memcg_cache_params *params;
 
 	if (!memcg_can_account_kmem(memcg))
@@ -4943,10 +4924,10 @@
  */
 static inline bool __memcg_has_children(struct mem_cgroup *memcg)
 {
-	struct cgroup *pos;
+	struct cgroup_subsys_state *pos;
 
 	/* bounce at first found */
-	cgroup_for_each_child(pos, memcg->css.cgroup)
+	css_for_each_child(pos, &memcg->css)
 		return true;
 	return false;
 }
@@ -5002,9 +4983,10 @@
 	return 0;
 }
 
-static int mem_cgroup_force_empty_write(struct cgroup *cont, unsigned int event)
+static int mem_cgroup_force_empty_write(struct cgroup_subsys_state *css,
+					unsigned int event)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	int ret;
 
 	if (mem_cgroup_is_root(memcg))
@@ -5017,21 +4999,18 @@
 }
 
 
-static u64 mem_cgroup_hierarchy_read(struct cgroup *cont, struct cftype *cft)
+static u64 mem_cgroup_hierarchy_read(struct cgroup_subsys_state *css,
+				     struct cftype *cft)
 {
-	return mem_cgroup_from_cont(cont)->use_hierarchy;
+	return mem_cgroup_from_css(css)->use_hierarchy;
 }
 
-static int mem_cgroup_hierarchy_write(struct cgroup *cont, struct cftype *cft,
-					u64 val)
+static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,
+				      struct cftype *cft, u64 val)
 {
 	int retval = 0;
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
-	struct cgroup *parent = cont->parent;
-	struct mem_cgroup *parent_memcg = NULL;
-
-	if (parent)
-		parent_memcg = mem_cgroup_from_cont(parent);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+	struct mem_cgroup *parent_memcg = mem_cgroup_from_css(css_parent(&memcg->css));
 
 	mutex_lock(&memcg_create_mutex);
 
@@ -5101,11 +5080,11 @@
 	return val << PAGE_SHIFT;
 }
 
-static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
-			       struct file *file, char __user *buf,
-			       size_t nbytes, loff_t *ppos)
+static ssize_t mem_cgroup_read(struct cgroup_subsys_state *css,
+			       struct cftype *cft, struct file *file,
+			       char __user *buf, size_t nbytes, loff_t *ppos)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	char str[64];
 	u64 val;
 	int name, len;
@@ -5138,11 +5117,11 @@
 	return simple_read_from_buffer(buf, nbytes, ppos, str, len);
 }
 
-static int memcg_update_kmem_limit(struct cgroup *cont, u64 val)
+static int memcg_update_kmem_limit(struct cgroup_subsys_state *css, u64 val)
 {
 	int ret = -EINVAL;
 #ifdef CONFIG_MEMCG_KMEM
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	/*
 	 * For simplicity, we won't allow this to be disabled.  It also can't
 	 * be changed if the cgroup has children already, or if tasks had
@@ -5158,7 +5137,7 @@
 	mutex_lock(&memcg_create_mutex);
 	mutex_lock(&set_limit_mutex);
 	if (!memcg->kmem_account_flags && val != RESOURCE_MAX) {
-		if (cgroup_task_count(cont) || memcg_has_children(memcg)) {
+		if (cgroup_task_count(css->cgroup) || memcg_has_children(memcg)) {
 			ret = -EBUSY;
 			goto out;
 		}
@@ -5228,10 +5207,10 @@
  * The user of this function is...
  * RES_LIMIT.
  */
-static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
+static int mem_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
 			    const char *buffer)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	enum res_type type;
 	int name;
 	unsigned long long val;
@@ -5255,7 +5234,7 @@
 		else if (type == _MEMSWAP)
 			ret = mem_cgroup_resize_memsw_limit(memcg, val);
 		else if (type == _KMEM)
-			ret = memcg_update_kmem_limit(cont, val);
+			ret = memcg_update_kmem_limit(css, val);
 		else
 			return -EINVAL;
 		break;
@@ -5283,18 +5262,15 @@
 static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
 		unsigned long long *mem_limit, unsigned long long *memsw_limit)
 {
-	struct cgroup *cgroup;
 	unsigned long long min_limit, min_memsw_limit, tmp;
 
 	min_limit = res_counter_read_u64(&memcg->res, RES_LIMIT);
 	min_memsw_limit = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
-	cgroup = memcg->css.cgroup;
 	if (!memcg->use_hierarchy)
 		goto out;
 
-	while (cgroup->parent) {
-		cgroup = cgroup->parent;
-		memcg = mem_cgroup_from_cont(cgroup);
+	while (css_parent(&memcg->css)) {
+		memcg = mem_cgroup_from_css(css_parent(&memcg->css));
 		if (!memcg->use_hierarchy)
 			break;
 		tmp = res_counter_read_u64(&memcg->res, RES_LIMIT);
@@ -5307,9 +5283,9 @@
 	*memsw_limit = min_memsw_limit;
 }
 
-static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
+static int mem_cgroup_reset(struct cgroup_subsys_state *css, unsigned int event)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	int name;
 	enum res_type type;
 
@@ -5342,17 +5318,17 @@
 	return 0;
 }
 
-static u64 mem_cgroup_move_charge_read(struct cgroup *cgrp,
+static u64 mem_cgroup_move_charge_read(struct cgroup_subsys_state *css,
 					struct cftype *cft)
 {
-	return mem_cgroup_from_cont(cgrp)->move_charge_at_immigrate;
+	return mem_cgroup_from_css(css)->move_charge_at_immigrate;
 }
 
 #ifdef CONFIG_MMU
-static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
+static int mem_cgroup_move_charge_write(struct cgroup_subsys_state *css,
 					struct cftype *cft, u64 val)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	if (val >= (1 << NR_MOVE_TYPE))
 		return -EINVAL;
@@ -5367,7 +5343,7 @@
 	return 0;
 }
 #else
-static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
+static int mem_cgroup_move_charge_write(struct cgroup_subsys_state *css,
 					struct cftype *cft, u64 val)
 {
 	return -ENOSYS;
@@ -5375,13 +5351,13 @@
 #endif
 
 #ifdef CONFIG_NUMA
-static int memcg_numa_stat_show(struct cgroup *cont, struct cftype *cft,
-				      struct seq_file *m)
+static int memcg_numa_stat_show(struct cgroup_subsys_state *css,
+				struct cftype *cft, struct seq_file *m)
 {
 	int nid;
 	unsigned long total_nr, file_nr, anon_nr, unevictable_nr;
 	unsigned long node_nr;
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	total_nr = mem_cgroup_nr_lru_pages(memcg, LRU_ALL);
 	seq_printf(m, "total=%lu", total_nr);
@@ -5426,10 +5402,10 @@
 	BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS);
 }
 
-static int memcg_stat_show(struct cgroup *cont, struct cftype *cft,
+static int memcg_stat_show(struct cgroup_subsys_state *css, struct cftype *cft,
 				 struct seq_file *m)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct mem_cgroup *mi;
 	unsigned int i;
 
@@ -5513,27 +5489,23 @@
 	return 0;
 }
 
-static u64 mem_cgroup_swappiness_read(struct cgroup *cgrp, struct cftype *cft)
+static u64 mem_cgroup_swappiness_read(struct cgroup_subsys_state *css,
+				      struct cftype *cft)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	return mem_cgroup_swappiness(memcg);
 }
 
-static int mem_cgroup_swappiness_write(struct cgroup *cgrp, struct cftype *cft,
-				       u64 val)
+static int mem_cgroup_swappiness_write(struct cgroup_subsys_state *css,
+				       struct cftype *cft, u64 val)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
-	struct mem_cgroup *parent;
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+	struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(&memcg->css));
 
-	if (val > 100)
+	if (val > 100 || !parent)
 		return -EINVAL;
 
-	if (cgrp->parent == NULL)
-		return -EINVAL;
-
-	parent = mem_cgroup_from_cont(cgrp->parent);
-
 	mutex_lock(&memcg_create_mutex);
 
 	/* If under hierarchy, only empty-root can set this value */
@@ -5636,10 +5608,10 @@
 		mem_cgroup_oom_notify_cb(iter);
 }
 
-static int mem_cgroup_usage_register_event(struct cgroup *cgrp,
+static int mem_cgroup_usage_register_event(struct cgroup_subsys_state *css,
 	struct cftype *cft, struct eventfd_ctx *eventfd, const char *args)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct mem_cgroup_thresholds *thresholds;
 	struct mem_cgroup_threshold_ary *new;
 	enum res_type type = MEMFILE_TYPE(cft->private);
@@ -5719,10 +5691,10 @@
 	return ret;
 }
 
-static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp,
+static void mem_cgroup_usage_unregister_event(struct cgroup_subsys_state *css,
 	struct cftype *cft, struct eventfd_ctx *eventfd)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct mem_cgroup_thresholds *thresholds;
 	struct mem_cgroup_threshold_ary *new;
 	enum res_type type = MEMFILE_TYPE(cft->private);
@@ -5798,10 +5770,10 @@
 	mutex_unlock(&memcg->thresholds_lock);
 }
 
-static int mem_cgroup_oom_register_event(struct cgroup *cgrp,
+static int mem_cgroup_oom_register_event(struct cgroup_subsys_state *css,
 	struct cftype *cft, struct eventfd_ctx *eventfd, const char *args)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct mem_cgroup_eventfd_list *event;
 	enum res_type type = MEMFILE_TYPE(cft->private);
 
@@ -5823,10 +5795,10 @@
 	return 0;
 }
 
-static void mem_cgroup_oom_unregister_event(struct cgroup *cgrp,
+static void mem_cgroup_oom_unregister_event(struct cgroup_subsys_state *css,
 	struct cftype *cft, struct eventfd_ctx *eventfd)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	struct mem_cgroup_eventfd_list *ev, *tmp;
 	enum res_type type = MEMFILE_TYPE(cft->private);
 
@@ -5844,10 +5816,10 @@
 	spin_unlock(&memcg_oom_lock);
 }
 
-static int mem_cgroup_oom_control_read(struct cgroup *cgrp,
+static int mem_cgroup_oom_control_read(struct cgroup_subsys_state *css,
 	struct cftype *cft,  struct cgroup_map_cb *cb)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	cb->fill(cb, "oom_kill_disable", memcg->oom_kill_disable);
 
@@ -5858,18 +5830,16 @@
 	return 0;
 }
 
-static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
+static int mem_cgroup_oom_control_write(struct cgroup_subsys_state *css,
 	struct cftype *cft, u64 val)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
-	struct mem_cgroup *parent;
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+	struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(&memcg->css));
 
 	/* cannot set to root cgroup and only 0 and 1 are allowed */
-	if (!cgrp->parent || !((val == 0) || (val == 1)))
+	if (!parent || !((val == 0) || (val == 1)))
 		return -EINVAL;
 
-	parent = mem_cgroup_from_cont(cgrp->parent);
-
 	mutex_lock(&memcg_create_mutex);
 	/* oom-kill-disable is a flag for subhierarchy. */
 	if ((parent->use_hierarchy) || memcg_has_children(memcg)) {
@@ -6228,7 +6198,7 @@
 }
 
 static struct cgroup_subsys_state * __ref
-mem_cgroup_css_alloc(struct cgroup *cont)
+mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct mem_cgroup *memcg;
 	long error = -ENOMEM;
@@ -6243,7 +6213,7 @@
 			goto free_out;
 
 	/* root ? */
-	if (cont->parent == NULL) {
+	if (parent_css == NULL) {
 		root_mem_cgroup = memcg;
 		res_counter_init(&memcg->res, NULL);
 		res_counter_init(&memcg->memsw, NULL);
@@ -6265,17 +6235,16 @@
 }
 
 static int
-mem_cgroup_css_online(struct cgroup *cont)
+mem_cgroup_css_online(struct cgroup_subsys_state *css)
 {
-	struct mem_cgroup *memcg, *parent;
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+	struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(css));
 	int error = 0;
 
-	if (!cont->parent)
+	if (!parent)
 		return 0;
 
 	mutex_lock(&memcg_create_mutex);
-	memcg = mem_cgroup_from_cont(cont);
-	parent = mem_cgroup_from_cont(cont->parent);
 
 	memcg->use_hierarchy = parent->use_hierarchy;
 	memcg->oom_kill_disable = parent->oom_kill_disable;
@@ -6326,9 +6295,9 @@
 		mem_cgroup_iter_invalidate(root_mem_cgroup);
 }
 
-static void mem_cgroup_css_offline(struct cgroup *cont)
+static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	kmem_cgroup_css_offline(memcg);
 
@@ -6338,9 +6307,9 @@
 	vmpressure_cleanup(&memcg->vmpressure);
 }
 
-static void mem_cgroup_css_free(struct cgroup *cont)
+static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	memcg_destroy_kmem(memcg);
 	__mem_cgroup_free(memcg);
@@ -6710,12 +6679,12 @@
 	mem_cgroup_end_move(from);
 }
 
-static int mem_cgroup_can_attach(struct cgroup *cgroup,
+static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
 				 struct cgroup_taskset *tset)
 {
 	struct task_struct *p = cgroup_taskset_first(tset);
 	int ret = 0;
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cgroup);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	unsigned long move_charge_at_immigrate;
 
 	/*
@@ -6757,7 +6726,7 @@
 	return ret;
 }
 
-static void mem_cgroup_cancel_attach(struct cgroup *cgroup,
+static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
 				     struct cgroup_taskset *tset)
 {
 	mem_cgroup_clear_mc();
@@ -6905,7 +6874,7 @@
 	up_read(&mm->mmap_sem);
 }
 
-static void mem_cgroup_move_task(struct cgroup *cont,
+static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
 				 struct cgroup_taskset *tset)
 {
 	struct task_struct *p = cgroup_taskset_first(tset);
@@ -6920,16 +6889,16 @@
 		mem_cgroup_clear_mc();
 }
 #else	/* !CONFIG_MMU */
-static int mem_cgroup_can_attach(struct cgroup *cgroup,
+static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
 				 struct cgroup_taskset *tset)
 {
 	return 0;
 }
-static void mem_cgroup_cancel_attach(struct cgroup *cgroup,
+static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
 				     struct cgroup_taskset *tset)
 {
 }
-static void mem_cgroup_move_task(struct cgroup *cont,
+static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
 				 struct cgroup_taskset *tset)
 {
 }
@@ -6939,15 +6908,15 @@
  * Cgroup retains root cgroups across [un]mount cycles making it necessary
  * to verify sane_behavior flag on each mount attempt.
  */
-static void mem_cgroup_bind(struct cgroup *root)
+static void mem_cgroup_bind(struct cgroup_subsys_state *root_css)
 {
 	/*
 	 * use_hierarchy is forced with sane_behavior.  cgroup core
 	 * guarantees that @root doesn't have any children, so turning it
 	 * on for the root memcg is enough.
 	 */
-	if (cgroup_sane_behavior(root))
-		mem_cgroup_from_cont(root)->use_hierarchy = true;
+	if (cgroup_sane_behavior(root_css->cgroup))
+		mem_cgroup_from_css(root_css)->use_hierarchy = true;
 }
 
 struct cgroup_subsys mem_cgroup_subsys = {
@@ -6969,7 +6938,6 @@
 #ifdef CONFIG_MEMCG_SWAP
 static int __init enable_swap_account(char *s)
 {
-	/* consider enabled if no parameter or 1 is given */
 	if (!strcmp(s, "1"))
 		really_do_swap_account = 1;
 	else if (!strcmp(s, "0"))
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 2c13aa7..55d7c80 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1286,7 +1286,10 @@
 		spin_unlock_irqrestore(&mf_cpu->lock, proc_flags);
 		if (!gotten)
 			break;
-		memory_failure(entry.pfn, entry.trapno, entry.flags);
+		if (entry.flags & MF_SOFT_OFFLINE)
+			soft_offline_page(pfn_to_page(entry.pfn), entry.flags);
+		else
+			memory_failure(entry.pfn, entry.trapno, entry.flags);
 	}
 }
 
diff --git a/mm/memory.c b/mm/memory.c
index af84bc0..b3c6bf9 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4079,6 +4079,7 @@
 
 	return len;
 }
+EXPORT_SYMBOL_GPL(generic_access_phys);
 #endif
 
 /*
diff --git a/mm/mremap.c b/mm/mremap.c
index 457d34e..0843feb 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -15,6 +15,7 @@
 #include <linux/swap.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
+#include <linux/swapops.h>
 #include <linux/highmem.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
@@ -69,6 +70,23 @@
 	return pmd;
 }
 
+static pte_t move_soft_dirty_pte(pte_t pte)
+{
+	/*
+	 * Set soft dirty bit so we can notice
+	 * in userspace the ptes were moved.
+	 */
+#ifdef CONFIG_MEM_SOFT_DIRTY
+	if (pte_present(pte))
+		pte = pte_mksoft_dirty(pte);
+	else if (is_swap_pte(pte))
+		pte = pte_swp_mksoft_dirty(pte);
+	else if (pte_file(pte))
+		pte = pte_file_mksoft_dirty(pte);
+#endif
+	return pte;
+}
+
 static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
 		unsigned long old_addr, unsigned long old_end,
 		struct vm_area_struct *new_vma, pmd_t *new_pmd,
@@ -126,7 +144,8 @@
 			continue;
 		pte = ptep_get_and_clear(mm, old_addr, old_pte);
 		pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr);
-		set_pte_at(mm, new_addr, new_pte, pte_mksoft_dirty(pte));
+		pte = move_soft_dirty_pte(pte);
+		set_pte_at(mm, new_addr, new_pte, pte);
 	}
 
 	arch_leave_lazy_mmu_mode();
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 79e451a..98e75f2 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -288,7 +288,7 @@
 
 /*
  * Simple selection loop. We chose the process with the highest
- * number of 'points'.
+ * number of 'points'.  Returns -1 on scan abort.
  *
  * (not docbooked, we don't want this one cluttering up the manual)
  */
@@ -314,7 +314,7 @@
 			continue;
 		case OOM_SCAN_ABORT:
 			rcu_read_unlock();
-			return ERR_PTR(-1UL);
+			return (struct task_struct *)(-1UL);
 		case OOM_SCAN_OK:
 			break;
 		};
@@ -657,7 +657,7 @@
 		dump_header(NULL, gfp_mask, order, NULL, mpol_mask);
 		panic("Out of memory and no killable processes...\n");
 	}
-	if (PTR_ERR(p) != -1UL) {
+	if (p != (void *)-1UL) {
 		oom_kill_process(p, gfp_mask, order, points, totalpages, NULL,
 				 nodemask, "Out of memory");
 		killed = 1;
diff --git a/mm/rmap.c b/mm/rmap.c
index b2e29ac..07748e6 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -873,9 +873,6 @@
 								vm_flags);
 		if (we_locked)
 			unlock_page(page);
-
-		if (page_test_and_clear_young(page_to_pfn(page)))
-			referenced++;
 	}
 out:
 	return referenced;
diff --git a/mm/slab.h b/mm/slab.h
index 620ceed..a535033 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -162,6 +162,8 @@
 
 static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx)
 {
+	if (!s->memcg_params)
+		return NULL;
 	return s->memcg_params->memcg_caches[idx];
 }
 
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
index 0c1e37d..e0f6283 100644
--- a/mm/vmpressure.c
+++ b/mm/vmpressure.c
@@ -74,15 +74,10 @@
 	return container_of(work, struct vmpressure, work);
 }
 
-static struct vmpressure *cg_to_vmpressure(struct cgroup *cg)
-{
-	return css_to_vmpressure(cgroup_subsys_state(cg, mem_cgroup_subsys_id));
-}
-
 static struct vmpressure *vmpressure_parent(struct vmpressure *vmpr)
 {
-	struct cgroup *cg = vmpressure_to_css(vmpr)->cgroup;
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cg);
+	struct cgroup_subsys_state *css = vmpressure_to_css(vmpr);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
 	memcg = parent_mem_cgroup(memcg);
 	if (!memcg)
@@ -283,7 +278,7 @@
 
 /**
  * vmpressure_register_event() - Bind vmpressure notifications to an eventfd
- * @cg:		cgroup that is interested in vmpressure notifications
+ * @css:	css that is interested in vmpressure notifications
  * @cft:	cgroup control files handle
  * @eventfd:	eventfd context to link notifications with
  * @args:	event arguments (used to set up a pressure level threshold)
@@ -298,10 +293,11 @@
  * cftype).register_event, and then cgroup core will handle everything by
  * itself.
  */
-int vmpressure_register_event(struct cgroup *cg, struct cftype *cft,
-			      struct eventfd_ctx *eventfd, const char *args)
+int vmpressure_register_event(struct cgroup_subsys_state *css,
+			      struct cftype *cft, struct eventfd_ctx *eventfd,
+			      const char *args)
 {
-	struct vmpressure *vmpr = cg_to_vmpressure(cg);
+	struct vmpressure *vmpr = css_to_vmpressure(css);
 	struct vmpressure_event *ev;
 	int level;
 
@@ -329,7 +325,7 @@
 
 /**
  * vmpressure_unregister_event() - Unbind eventfd from vmpressure
- * @cg:		cgroup handle
+ * @css:	css handle
  * @cft:	cgroup control files handle
  * @eventfd:	eventfd context that was used to link vmpressure with the @cg
  *
@@ -341,10 +337,11 @@
  * cftype).unregister_event, and then cgroup core will handle everything
  * by itself.
  */
-void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
+void vmpressure_unregister_event(struct cgroup_subsys_state *css,
+				 struct cftype *cft,
 				 struct eventfd_ctx *eventfd)
 {
-	struct vmpressure *vmpr = cg_to_vmpressure(cg);
+	struct vmpressure *vmpr = css_to_vmpressure(css);
 	struct vmpressure_event *ev;
 
 	mutex_lock(&vmpr->events_lock);
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 688a041..857e1b8 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -432,12 +432,16 @@
 
 	switch (packet_type) {
 	case BATADV_UNICAST:
-		batadv_unicast_prepare_skb(skb, orig_node);
+		if (!batadv_unicast_prepare_skb(skb, orig_node))
+			goto out;
+
 		header_len = sizeof(struct batadv_unicast_packet);
 		break;
 	case BATADV_UNICAST_4ADDR:
-		batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node,
-						 packet_subtype);
+		if (!batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node,
+						      packet_subtype))
+			goto out;
+
 		header_len = sizeof(struct batadv_unicast_4addr_packet);
 		break;
 	default:
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 7ad6ecf..edf623a 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -590,7 +590,7 @@
 
 	bt_class = class_create(THIS_MODULE, "bluetooth");
 
-	return PTR_RET(bt_class);
+	return PTR_ERR_OR_ZERO(bt_class);
 }
 
 void bt_sysfs_cleanup(void)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 69363bd..89659d4 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -71,7 +71,7 @@
 
 		mdst = br_mdb_get(br, skb, vid);
 		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
-		    br_multicast_querier_exists(br))
+		    br_multicast_querier_exists(br, eth_hdr(skb)))
 			br_multicast_deliver(mdst, skb);
 		else
 			br_flood_deliver(br, skb, false);
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 60aca91..ffd5874 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -161,7 +161,7 @@
 	if (!pv)
 		return;
 
-	for_each_set_bit_from(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
+	for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) {
 		f = __br_fdb_get(br, br->dev->dev_addr, vid);
 		if (f && f->is_local && !f->dst)
 			fdb_delete(br, f);
@@ -730,7 +730,7 @@
 		/* VID was specified, so use it. */
 		err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
 	} else {
-		if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
+		if (!pv || bitmap_empty(pv->vlan_bitmap, VLAN_N_VID)) {
 			err = __br_fdb_add(ndm, p, addr, nlh_flags, 0);
 			goto out;
 		}
@@ -739,7 +739,7 @@
 		 * specify a VLAN.  To be nice, add/update entry for every
 		 * vlan on this port.
 		 */
-		for_each_set_bit(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
+		for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
 			err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
 			if (err)
 				goto out;
@@ -817,7 +817,7 @@
 
 		err = __br_fdb_delete(p, addr, vid);
 	} else {
-		if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
+		if (!pv || bitmap_empty(pv->vlan_bitmap, VLAN_N_VID)) {
 			err = __br_fdb_delete(p, addr, 0);
 			goto out;
 		}
@@ -827,7 +827,7 @@
 		 * vlan on this port.
 		 */
 		err = -ENOENT;
-		for_each_set_bit(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
+		for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
 			err &= __br_fdb_delete(p, addr, vid);
 		}
 	}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 8c561c0..a2fd37e 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -102,7 +102,7 @@
 	} else if (is_multicast_ether_addr(dest)) {
 		mdst = br_mdb_get(br, skb, vid);
 		if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
-		    br_multicast_querier_exists(br)) {
+		    br_multicast_querier_exists(br, eth_hdr(skb))) {
 			if ((mdst && mdst->mglist) ||
 			    br_multicast_is_router(br))
 				skb2 = skb;
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 0daae3e..6319c43 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -414,16 +414,20 @@
 	if (!netif_running(br->dev) || br->multicast_disabled)
 		return -EINVAL;
 
-	if (timer_pending(&br->multicast_querier_timer))
-		return -EBUSY;
-
 	ip.proto = entry->addr.proto;
-	if (ip.proto == htons(ETH_P_IP))
+	if (ip.proto == htons(ETH_P_IP)) {
+		if (timer_pending(&br->ip4_querier.timer))
+			return -EBUSY;
+
 		ip.u.ip4 = entry->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
-	else
+	} else {
+		if (timer_pending(&br->ip6_querier.timer))
+			return -EBUSY;
+
 		ip.u.ip6 = entry->addr.u.ip6;
 #endif
+	}
 
 	spin_lock_bh(&br->multicast_lock);
 	mdb = mlock_dereference(br->mdb, br);
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 08e576a..bbcb435 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -33,7 +33,8 @@
 
 #include "br_private.h"
 
-static void br_multicast_start_querier(struct net_bridge *br);
+static void br_multicast_start_querier(struct net_bridge *br,
+				       struct bridge_mcast_query *query);
 unsigned int br_mdb_rehash_seq;
 
 static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
@@ -755,20 +756,35 @@
 {
 }
 
-static void br_multicast_querier_expired(unsigned long data)
+static void br_multicast_querier_expired(struct net_bridge *br,
+					 struct bridge_mcast_query *query)
 {
-	struct net_bridge *br = (void *)data;
-
 	spin_lock(&br->multicast_lock);
 	if (!netif_running(br->dev) || br->multicast_disabled)
 		goto out;
 
-	br_multicast_start_querier(br);
+	br_multicast_start_querier(br, query);
 
 out:
 	spin_unlock(&br->multicast_lock);
 }
 
+static void br_ip4_multicast_querier_expired(unsigned long data)
+{
+	struct net_bridge *br = (void *)data;
+
+	br_multicast_querier_expired(br, &br->ip4_query);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_querier_expired(unsigned long data)
+{
+	struct net_bridge *br = (void *)data;
+
+	br_multicast_querier_expired(br, &br->ip6_query);
+}
+#endif
+
 static void __br_multicast_send_query(struct net_bridge *br,
 				      struct net_bridge_port *port,
 				      struct br_ip *ip)
@@ -789,37 +805,45 @@
 }
 
 static void br_multicast_send_query(struct net_bridge *br,
-				    struct net_bridge_port *port, u32 sent)
+				    struct net_bridge_port *port,
+				    struct bridge_mcast_query *query)
 {
 	unsigned long time;
 	struct br_ip br_group;
+	struct bridge_mcast_querier *querier = NULL;
 
 	if (!netif_running(br->dev) || br->multicast_disabled ||
-	    !br->multicast_querier ||
-	    timer_pending(&br->multicast_querier_timer))
+	    !br->multicast_querier)
 		return;
 
 	memset(&br_group.u, 0, sizeof(br_group.u));
 
-	br_group.proto = htons(ETH_P_IP);
-	__br_multicast_send_query(br, port, &br_group);
-
+	if (port ? (query == &port->ip4_query) :
+		   (query == &br->ip4_query)) {
+		querier = &br->ip4_querier;
+		br_group.proto = htons(ETH_P_IP);
 #if IS_ENABLED(CONFIG_IPV6)
-	br_group.proto = htons(ETH_P_IPV6);
-	__br_multicast_send_query(br, port, &br_group);
+	} else {
+		querier = &br->ip6_querier;
+		br_group.proto = htons(ETH_P_IPV6);
 #endif
+	}
+
+	if (!querier || timer_pending(&querier->timer))
+		return;
+
+	__br_multicast_send_query(br, port, &br_group);
 
 	time = jiffies;
-	time += sent < br->multicast_startup_query_count ?
+	time += query->startup_sent < br->multicast_startup_query_count ?
 		br->multicast_startup_query_interval :
 		br->multicast_query_interval;
-	mod_timer(port ? &port->multicast_query_timer :
-			 &br->multicast_query_timer, time);
+	mod_timer(&query->timer, time);
 }
 
-static void br_multicast_port_query_expired(unsigned long data)
+static void br_multicast_port_query_expired(struct net_bridge_port *port,
+					    struct bridge_mcast_query *query)
 {
-	struct net_bridge_port *port = (void *)data;
 	struct net_bridge *br = port->br;
 
 	spin_lock(&br->multicast_lock);
@@ -827,25 +851,43 @@
 	    port->state == BR_STATE_BLOCKING)
 		goto out;
 
-	if (port->multicast_startup_queries_sent <
-	    br->multicast_startup_query_count)
-		port->multicast_startup_queries_sent++;
+	if (query->startup_sent < br->multicast_startup_query_count)
+		query->startup_sent++;
 
-	br_multicast_send_query(port->br, port,
-				port->multicast_startup_queries_sent);
+	br_multicast_send_query(port->br, port, query);
 
 out:
 	spin_unlock(&br->multicast_lock);
 }
 
+static void br_ip4_multicast_port_query_expired(unsigned long data)
+{
+	struct net_bridge_port *port = (void *)data;
+
+	br_multicast_port_query_expired(port, &port->ip4_query);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_port_query_expired(unsigned long data)
+{
+	struct net_bridge_port *port = (void *)data;
+
+	br_multicast_port_query_expired(port, &port->ip6_query);
+}
+#endif
+
 void br_multicast_add_port(struct net_bridge_port *port)
 {
 	port->multicast_router = 1;
 
 	setup_timer(&port->multicast_router_timer, br_multicast_router_expired,
 		    (unsigned long)port);
-	setup_timer(&port->multicast_query_timer,
-		    br_multicast_port_query_expired, (unsigned long)port);
+	setup_timer(&port->ip4_query.timer, br_ip4_multicast_port_query_expired,
+		    (unsigned long)port);
+#if IS_ENABLED(CONFIG_IPV6)
+	setup_timer(&port->ip6_query.timer, br_ip6_multicast_port_query_expired,
+		    (unsigned long)port);
+#endif
 }
 
 void br_multicast_del_port(struct net_bridge_port *port)
@@ -853,13 +895,13 @@
 	del_timer_sync(&port->multicast_router_timer);
 }
 
-static void __br_multicast_enable_port(struct net_bridge_port *port)
+static void br_multicast_enable(struct bridge_mcast_query *query)
 {
-	port->multicast_startup_queries_sent = 0;
+	query->startup_sent = 0;
 
-	if (try_to_del_timer_sync(&port->multicast_query_timer) >= 0 ||
-	    del_timer(&port->multicast_query_timer))
-		mod_timer(&port->multicast_query_timer, jiffies);
+	if (try_to_del_timer_sync(&query->timer) >= 0 ||
+	    del_timer(&query->timer))
+		mod_timer(&query->timer, jiffies);
 }
 
 void br_multicast_enable_port(struct net_bridge_port *port)
@@ -870,7 +912,10 @@
 	if (br->multicast_disabled || !netif_running(br->dev))
 		goto out;
 
-	__br_multicast_enable_port(port);
+	br_multicast_enable(&port->ip4_query);
+#if IS_ENABLED(CONFIG_IPV6)
+	br_multicast_enable(&port->ip6_query);
+#endif
 
 out:
 	spin_unlock(&br->multicast_lock);
@@ -889,7 +934,10 @@
 	if (!hlist_unhashed(&port->rlist))
 		hlist_del_init_rcu(&port->rlist);
 	del_timer(&port->multicast_router_timer);
-	del_timer(&port->multicast_query_timer);
+	del_timer(&port->ip4_query.timer);
+#if IS_ENABLED(CONFIG_IPV6)
+	del_timer(&port->ip6_query.timer);
+#endif
 	spin_unlock(&br->multicast_lock);
 }
 
@@ -1014,14 +1062,15 @@
 }
 #endif
 
-static void br_multicast_update_querier_timer(struct net_bridge *br,
-					      unsigned long max_delay)
+static void
+br_multicast_update_querier_timer(struct net_bridge *br,
+				  struct bridge_mcast_querier *querier,
+				  unsigned long max_delay)
 {
-	if (!timer_pending(&br->multicast_querier_timer))
-		br->multicast_querier_delay_time = jiffies + max_delay;
+	if (!timer_pending(&querier->timer))
+		querier->delay_time = jiffies + max_delay;
 
-	mod_timer(&br->multicast_querier_timer,
-		  jiffies + br->multicast_querier_interval);
+	mod_timer(&querier->timer, jiffies + br->multicast_querier_interval);
 }
 
 /*
@@ -1074,12 +1123,13 @@
 
 static void br_multicast_query_received(struct net_bridge *br,
 					struct net_bridge_port *port,
+					struct bridge_mcast_querier *querier,
 					int saddr,
 					unsigned long max_delay)
 {
 	if (saddr)
-		br_multicast_update_querier_timer(br, max_delay);
-	else if (timer_pending(&br->multicast_querier_timer))
+		br_multicast_update_querier_timer(br, querier, max_delay);
+	else if (timer_pending(&querier->timer))
 		return;
 
 	br_multicast_mark_router(br, port);
@@ -1129,7 +1179,8 @@
 			    IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
 	}
 
-	br_multicast_query_received(br, port, !!iph->saddr, max_delay);
+	br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
+				    max_delay);
 
 	if (!group)
 		goto out;
@@ -1203,11 +1254,12 @@
 		mld2q = (struct mld2_query *)icmp6_hdr(skb);
 		if (!mld2q->mld2q_nsrcs)
 			group = &mld2q->mld2q_mca;
-		max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
+
+		max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
 	}
 
-	br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
-				    max_delay);
+	br_multicast_query_received(br, port, &br->ip6_querier,
+				    !ipv6_addr_any(&ip6h->saddr), max_delay);
 
 	if (!group)
 		goto out;
@@ -1244,7 +1296,9 @@
 
 static void br_multicast_leave_group(struct net_bridge *br,
 				     struct net_bridge_port *port,
-				     struct br_ip *group)
+				     struct br_ip *group,
+				     struct bridge_mcast_querier *querier,
+				     struct bridge_mcast_query *query)
 {
 	struct net_bridge_mdb_htable *mdb;
 	struct net_bridge_mdb_entry *mp;
@@ -1255,7 +1309,7 @@
 	spin_lock(&br->multicast_lock);
 	if (!netif_running(br->dev) ||
 	    (port && port->state == BR_STATE_DISABLED) ||
-	    timer_pending(&br->multicast_querier_timer))
+	    timer_pending(&querier->timer))
 		goto out;
 
 	mdb = mlock_dereference(br->mdb, br);
@@ -1263,14 +1317,13 @@
 	if (!mp)
 		goto out;
 
-	if (br->multicast_querier &&
-	    !timer_pending(&br->multicast_querier_timer)) {
+	if (br->multicast_querier) {
 		__br_multicast_send_query(br, port, &mp->addr);
 
 		time = jiffies + br->multicast_last_member_count *
 				 br->multicast_last_member_interval;
-		mod_timer(port ? &port->multicast_query_timer :
-				 &br->multicast_query_timer, time);
+
+		mod_timer(&query->timer, time);
 
 		for (p = mlock_dereference(mp->ports, br);
 		     p != NULL;
@@ -1323,7 +1376,6 @@
 			mod_timer(&mp->timer, time);
 		}
 	}
-
 out:
 	spin_unlock(&br->multicast_lock);
 }
@@ -1334,6 +1386,8 @@
 					 __u16 vid)
 {
 	struct br_ip br_group;
+	struct bridge_mcast_query *query = port ? &port->ip4_query :
+						  &br->ip4_query;
 
 	if (ipv4_is_local_multicast(group))
 		return;
@@ -1342,7 +1396,7 @@
 	br_group.proto = htons(ETH_P_IP);
 	br_group.vid = vid;
 
-	br_multicast_leave_group(br, port, &br_group);
+	br_multicast_leave_group(br, port, &br_group, &br->ip4_querier, query);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1352,6 +1406,9 @@
 					 __u16 vid)
 {
 	struct br_ip br_group;
+	struct bridge_mcast_query *query = port ? &port->ip6_query :
+						  &br->ip6_query;
+
 
 	if (!ipv6_is_transient_multicast(group))
 		return;
@@ -1360,7 +1417,7 @@
 	br_group.proto = htons(ETH_P_IPV6);
 	br_group.vid = vid;
 
-	br_multicast_leave_group(br, port, &br_group);
+	br_multicast_leave_group(br, port, &br_group, &br->ip6_querier, query);
 }
 #endif
 
@@ -1622,20 +1679,33 @@
 	return 0;
 }
 
-static void br_multicast_query_expired(unsigned long data)
+static void br_multicast_query_expired(struct net_bridge *br,
+				       struct bridge_mcast_query *query)
+{
+	spin_lock(&br->multicast_lock);
+	if (query->startup_sent < br->multicast_startup_query_count)
+		query->startup_sent++;
+
+	br_multicast_send_query(br, NULL, query);
+	spin_unlock(&br->multicast_lock);
+}
+
+static void br_ip4_multicast_query_expired(unsigned long data)
 {
 	struct net_bridge *br = (void *)data;
 
-	spin_lock(&br->multicast_lock);
-	if (br->multicast_startup_queries_sent <
-	    br->multicast_startup_query_count)
-		br->multicast_startup_queries_sent++;
-
-	br_multicast_send_query(br, NULL, br->multicast_startup_queries_sent);
-
-	spin_unlock(&br->multicast_lock);
+	br_multicast_query_expired(br, &br->ip4_query);
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_query_expired(unsigned long data)
+{
+	struct net_bridge *br = (void *)data;
+
+	br_multicast_query_expired(br, &br->ip6_query);
+}
+#endif
+
 void br_multicast_init(struct net_bridge *br)
 {
 	br->hash_elasticity = 4;
@@ -1654,25 +1724,43 @@
 	br->multicast_querier_interval = 255 * HZ;
 	br->multicast_membership_interval = 260 * HZ;
 
-	br->multicast_querier_delay_time = 0;
+	br->ip4_querier.delay_time = 0;
+#if IS_ENABLED(CONFIG_IPV6)
+	br->ip6_querier.delay_time = 0;
+#endif
 
 	spin_lock_init(&br->multicast_lock);
 	setup_timer(&br->multicast_router_timer,
 		    br_multicast_local_router_expired, 0);
-	setup_timer(&br->multicast_querier_timer,
-		    br_multicast_querier_expired, (unsigned long)br);
-	setup_timer(&br->multicast_query_timer, br_multicast_query_expired,
+	setup_timer(&br->ip4_querier.timer, br_ip4_multicast_querier_expired,
 		    (unsigned long)br);
+	setup_timer(&br->ip4_query.timer, br_ip4_multicast_query_expired,
+		    (unsigned long)br);
+#if IS_ENABLED(CONFIG_IPV6)
+	setup_timer(&br->ip6_querier.timer, br_ip6_multicast_querier_expired,
+		    (unsigned long)br);
+	setup_timer(&br->ip6_query.timer, br_ip6_multicast_query_expired,
+		    (unsigned long)br);
+#endif
 }
 
-void br_multicast_open(struct net_bridge *br)
+static void __br_multicast_open(struct net_bridge *br,
+				struct bridge_mcast_query *query)
 {
-	br->multicast_startup_queries_sent = 0;
+	query->startup_sent = 0;
 
 	if (br->multicast_disabled)
 		return;
 
-	mod_timer(&br->multicast_query_timer, jiffies);
+	mod_timer(&query->timer, jiffies);
+}
+
+void br_multicast_open(struct net_bridge *br)
+{
+	__br_multicast_open(br, &br->ip4_query);
+#if IS_ENABLED(CONFIG_IPV6)
+	__br_multicast_open(br, &br->ip6_query);
+#endif
 }
 
 void br_multicast_stop(struct net_bridge *br)
@@ -1684,8 +1772,12 @@
 	int i;
 
 	del_timer_sync(&br->multicast_router_timer);
-	del_timer_sync(&br->multicast_querier_timer);
-	del_timer_sync(&br->multicast_query_timer);
+	del_timer_sync(&br->ip4_querier.timer);
+	del_timer_sync(&br->ip4_query.timer);
+#if IS_ENABLED(CONFIG_IPV6)
+	del_timer_sync(&br->ip6_querier.timer);
+	del_timer_sync(&br->ip6_query.timer);
+#endif
 
 	spin_lock_bh(&br->multicast_lock);
 	mdb = mlock_dereference(br->mdb, br);
@@ -1788,18 +1880,24 @@
 	return err;
 }
 
-static void br_multicast_start_querier(struct net_bridge *br)
+static void br_multicast_start_querier(struct net_bridge *br,
+				       struct bridge_mcast_query *query)
 {
 	struct net_bridge_port *port;
 
-	br_multicast_open(br);
+	__br_multicast_open(br, query);
 
 	list_for_each_entry(port, &br->port_list, list) {
 		if (port->state == BR_STATE_DISABLED ||
 		    port->state == BR_STATE_BLOCKING)
 			continue;
 
-		__br_multicast_enable_port(port);
+		if (query == &br->ip4_query)
+			br_multicast_enable(&port->ip4_query);
+#if IS_ENABLED(CONFIG_IPV6)
+		else
+			br_multicast_enable(&port->ip6_query);
+#endif
 	}
 }
 
@@ -1834,7 +1932,10 @@
 			goto rollback;
 	}
 
-	br_multicast_start_querier(br);
+	br_multicast_start_querier(br, &br->ip4_query);
+#if IS_ENABLED(CONFIG_IPV6)
+	br_multicast_start_querier(br, &br->ip6_query);
+#endif
 
 unlock:
 	spin_unlock_bh(&br->multicast_lock);
@@ -1857,10 +1958,18 @@
 		goto unlock;
 
 	max_delay = br->multicast_query_response_interval;
-	if (!timer_pending(&br->multicast_querier_timer))
-		br->multicast_querier_delay_time = jiffies + max_delay;
 
-	br_multicast_start_querier(br);
+	if (!timer_pending(&br->ip4_querier.timer))
+		br->ip4_querier.delay_time = jiffies + max_delay;
+
+	br_multicast_start_querier(br, &br->ip4_query);
+
+#if IS_ENABLED(CONFIG_IPV6)
+	if (!timer_pending(&br->ip6_querier.timer))
+		br->ip6_querier.delay_time = jiffies + max_delay;
+
+	br_multicast_start_querier(br, &br->ip6_query);
+#endif
 
 unlock:
 	spin_unlock_bh(&br->multicast_lock);
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 1fc30ab..b9259ef 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -132,7 +132,7 @@
 		else
 			pv = br_get_vlan_info(br);
 
-		if (!pv || bitmap_empty(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN))
+		if (!pv || bitmap_empty(pv->vlan_bitmap, VLAN_N_VID))
 			goto done;
 
 		af = nla_nest_start(skb, IFLA_AF_SPEC);
@@ -140,7 +140,7 @@
 			goto nla_put_failure;
 
 		pvid = br_get_pvid(pv);
-		for_each_set_bit(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
+		for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID) {
 			vinfo.vid = vid;
 			vinfo.flags = 0;
 			if (vid == pvid)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 2f7da41..263ba90 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -66,6 +66,20 @@
 	__u16		vid;
 };
 
+#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+/* our own querier */
+struct bridge_mcast_query {
+	struct timer_list	timer;
+	u32			startup_sent;
+};
+
+/* other querier */
+struct bridge_mcast_querier {
+	struct timer_list		timer;
+	unsigned long			delay_time;
+};
+#endif
+
 struct net_port_vlans {
 	u16				port_idx;
 	u16				pvid;
@@ -162,10 +176,12 @@
 #define BR_FLOOD		0x00000040
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
-	u32				multicast_startup_queries_sent;
+	struct bridge_mcast_query	ip4_query;
+#if IS_ENABLED(CONFIG_IPV6)
+	struct bridge_mcast_query	ip6_query;
+#endif /* IS_ENABLED(CONFIG_IPV6) */
 	unsigned char			multicast_router;
 	struct timer_list		multicast_router_timer;
-	struct timer_list		multicast_query_timer;
 	struct hlist_head		mglist;
 	struct hlist_node		rlist;
 #endif
@@ -258,7 +274,6 @@
 	u32				hash_max;
 
 	u32				multicast_last_member_count;
-	u32				multicast_startup_queries_sent;
 	u32				multicast_startup_query_count;
 
 	unsigned long			multicast_last_member_interval;
@@ -267,15 +282,18 @@
 	unsigned long			multicast_query_interval;
 	unsigned long			multicast_query_response_interval;
 	unsigned long			multicast_startup_query_interval;
-	unsigned long			multicast_querier_delay_time;
 
 	spinlock_t			multicast_lock;
 	struct net_bridge_mdb_htable __rcu *mdb;
 	struct hlist_head		router_list;
 
 	struct timer_list		multicast_router_timer;
-	struct timer_list		multicast_querier_timer;
-	struct timer_list		multicast_query_timer;
+	struct bridge_mcast_querier	ip4_querier;
+	struct bridge_mcast_query	ip4_query;
+#if IS_ENABLED(CONFIG_IPV6)
+	struct bridge_mcast_querier	ip6_querier;
+	struct bridge_mcast_query	ip6_query;
+#endif /* IS_ENABLED(CONFIG_IPV6) */
 #endif
 
 	struct timer_list		hello_timer;
@@ -503,11 +521,27 @@
 		timer_pending(&br->multicast_router_timer));
 }
 
-static inline bool br_multicast_querier_exists(struct net_bridge *br)
+static inline bool
+__br_multicast_querier_exists(struct net_bridge *br,
+			      struct bridge_mcast_querier *querier)
 {
-	return time_is_before_jiffies(br->multicast_querier_delay_time) &&
-	       (br->multicast_querier ||
-		timer_pending(&br->multicast_querier_timer));
+	return time_is_before_jiffies(querier->delay_time) &&
+	       (br->multicast_querier || timer_pending(&querier->timer));
+}
+
+static inline bool br_multicast_querier_exists(struct net_bridge *br,
+					       struct ethhdr *eth)
+{
+	switch (eth->h_proto) {
+	case (htons(ETH_P_IP)):
+		return __br_multicast_querier_exists(br, &br->ip4_querier);
+#if IS_ENABLED(CONFIG_IPV6)
+	case (htons(ETH_P_IPV6)):
+		return __br_multicast_querier_exists(br, &br->ip6_querier);
+#endif
+	default:
+		return false;
+	}
 }
 #else
 static inline int br_multicast_rcv(struct net_bridge *br,
@@ -565,7 +599,8 @@
 {
 	return 0;
 }
-static inline bool br_multicast_querier_exists(struct net_bridge *br)
+static inline bool br_multicast_querier_exists(struct net_bridge *br,
+					       struct ethhdr *eth)
 {
 	return false;
 }
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index bd58b45..9a9ffe7 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -108,7 +108,7 @@
 
 	clear_bit(vid, v->vlan_bitmap);
 	v->num_vlans--;
-	if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) {
+	if (bitmap_empty(v->vlan_bitmap, VLAN_N_VID)) {
 		if (v->port_idx)
 			rcu_assign_pointer(v->parent.port->vlan_info, NULL);
 		else
@@ -122,7 +122,7 @@
 {
 	smp_wmb();
 	v->pvid = 0;
-	bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN);
+	bitmap_zero(v->vlan_bitmap, VLAN_N_VID);
 	if (v->port_idx)
 		rcu_assign_pointer(v->parent.port->vlan_info, NULL);
 	else
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 70f656c..dbd1c78 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -64,7 +64,7 @@
 static int __net_init broute_net_init(struct net *net)
 {
 	net->xt.broute_table = ebt_register_table(net, &broute_table);
-	return PTR_RET(net->xt.broute_table);
+	return PTR_ERR_OR_ZERO(net->xt.broute_table);
 }
 
 static void __net_exit broute_net_exit(struct net *net)
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 3c2e9dc..94b2b70 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -100,7 +100,7 @@
 static int __net_init frame_filter_net_init(struct net *net)
 {
 	net->xt.frame_filter = ebt_register_table(net, &frame_filter);
-	return PTR_RET(net->xt.frame_filter);
+	return PTR_ERR_OR_ZERO(net->xt.frame_filter);
 }
 
 static void __net_exit frame_filter_net_exit(struct net *net)
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index 10871bc..322555a 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -100,7 +100,7 @@
 static int __net_init frame_nat_net_init(struct net *net)
 {
 	net->xt.frame_nat = ebt_register_table(net, &frame_nat);
-	return PTR_RET(net->xt.frame_nat);
+	return PTR_ERR_OR_ZERO(net->xt.frame_nat);
 }
 
 static void __net_exit frame_nat_net_exit(struct net *net)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index b84a1b1..d12e3a9 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -346,14 +346,9 @@
 		if (new_index < 0)
 			new_index = skb_tx_hash(dev, skb);
 
-		if (queue_index != new_index && sk) {
-			struct dst_entry *dst =
-				    rcu_dereference_check(sk->sk_dst_cache, 1);
-
-			if (dst && skb_dst(skb) == dst)
-				sk_tx_queue_set(sk, queue_index);
-
-		}
+		if (queue_index != new_index && sk &&
+		    rcu_access_pointer(sk->sk_dst_cache))
+			sk_tx_queue_set(sk, queue_index);
 
 		queue_index = new_index;
 	}
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 981fed3..707c313 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -60,12 +60,19 @@
 {									\
 	return sprintf(buf, format_string, net->field);			\
 }									\
-static ssize_t show_##field(struct device *dev,				\
+static ssize_t field##_show(struct device *dev,				\
 			    struct device_attribute *attr, char *buf)	\
 {									\
 	return netdev_show(dev, attr, buf, format_##field);		\
-}
+}									\
 
+#define NETDEVICE_SHOW_RO(field, format_string)				\
+NETDEVICE_SHOW(field, format_string);					\
+static DEVICE_ATTR_RO(field)
+
+#define NETDEVICE_SHOW_RW(field, format_string)				\
+NETDEVICE_SHOW(field, format_string);					\
+static DEVICE_ATTR_RW(field)
 
 /* use same locking and permission rules as SIF* ioctl's */
 static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
@@ -96,16 +103,16 @@
 	return ret;
 }
 
-NETDEVICE_SHOW(dev_id, fmt_hex);
-NETDEVICE_SHOW(addr_assign_type, fmt_dec);
-NETDEVICE_SHOW(addr_len, fmt_dec);
-NETDEVICE_SHOW(iflink, fmt_dec);
-NETDEVICE_SHOW(ifindex, fmt_dec);
-NETDEVICE_SHOW(type, fmt_dec);
-NETDEVICE_SHOW(link_mode, fmt_dec);
+NETDEVICE_SHOW_RO(dev_id, fmt_hex);
+NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec);
+NETDEVICE_SHOW_RO(addr_len, fmt_dec);
+NETDEVICE_SHOW_RO(iflink, fmt_dec);
+NETDEVICE_SHOW_RO(ifindex, fmt_dec);
+NETDEVICE_SHOW_RO(type, fmt_dec);
+NETDEVICE_SHOW_RO(link_mode, fmt_dec);
 
 /* use same locking rules as GIFHWADDR ioctl's */
-static ssize_t show_address(struct device *dev, struct device_attribute *attr,
+static ssize_t address_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
 	struct net_device *net = to_net_dev(dev);
@@ -117,15 +124,17 @@
 	read_unlock(&dev_base_lock);
 	return ret;
 }
+static DEVICE_ATTR_RO(address);
 
-static ssize_t show_broadcast(struct device *dev,
-			    struct device_attribute *attr, char *buf)
+static ssize_t broadcast_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct net_device *net = to_net_dev(dev);
 	if (dev_isalive(net))
 		return sysfs_format_mac(buf, net->broadcast, net->addr_len);
 	return -EINVAL;
 }
+static DEVICE_ATTR_RO(broadcast);
 
 static int change_carrier(struct net_device *net, unsigned long new_carrier)
 {
@@ -134,13 +143,13 @@
 	return dev_change_carrier(net, (bool) new_carrier);
 }
 
-static ssize_t store_carrier(struct device *dev, struct device_attribute *attr,
-			 const char *buf, size_t len)
+static ssize_t carrier_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t len)
 {
 	return netdev_store(dev, attr, buf, len, change_carrier);
 }
 
-static ssize_t show_carrier(struct device *dev,
+static ssize_t carrier_show(struct device *dev,
 			    struct device_attribute *attr, char *buf)
 {
 	struct net_device *netdev = to_net_dev(dev);
@@ -149,8 +158,9 @@
 	}
 	return -EINVAL;
 }
+static DEVICE_ATTR_RW(carrier);
 
-static ssize_t show_speed(struct device *dev,
+static ssize_t speed_show(struct device *dev,
 			  struct device_attribute *attr, char *buf)
 {
 	struct net_device *netdev = to_net_dev(dev);
@@ -167,8 +177,9 @@
 	rtnl_unlock();
 	return ret;
 }
+static DEVICE_ATTR_RO(speed);
 
-static ssize_t show_duplex(struct device *dev,
+static ssize_t duplex_show(struct device *dev,
 			   struct device_attribute *attr, char *buf)
 {
 	struct net_device *netdev = to_net_dev(dev);
@@ -198,8 +209,9 @@
 	rtnl_unlock();
 	return ret;
 }
+static DEVICE_ATTR_RO(duplex);
 
-static ssize_t show_dormant(struct device *dev,
+static ssize_t dormant_show(struct device *dev,
 			    struct device_attribute *attr, char *buf)
 {
 	struct net_device *netdev = to_net_dev(dev);
@@ -209,6 +221,7 @@
 
 	return -EINVAL;
 }
+static DEVICE_ATTR_RO(dormant);
 
 static const char *const operstates[] = {
 	"unknown",
@@ -220,7 +233,7 @@
 	"up"
 };
 
-static ssize_t show_operstate(struct device *dev,
+static ssize_t operstate_show(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
 	const struct net_device *netdev = to_net_dev(dev);
@@ -237,35 +250,33 @@
 
 	return sprintf(buf, "%s\n", operstates[operstate]);
 }
+static DEVICE_ATTR_RO(operstate);
 
 /* read-write attributes */
-NETDEVICE_SHOW(mtu, fmt_dec);
 
 static int change_mtu(struct net_device *net, unsigned long new_mtu)
 {
 	return dev_set_mtu(net, (int) new_mtu);
 }
 
-static ssize_t store_mtu(struct device *dev, struct device_attribute *attr,
+static ssize_t mtu_store(struct device *dev, struct device_attribute *attr,
 			 const char *buf, size_t len)
 {
 	return netdev_store(dev, attr, buf, len, change_mtu);
 }
-
-NETDEVICE_SHOW(flags, fmt_hex);
+NETDEVICE_SHOW_RW(mtu, fmt_dec);
 
 static int change_flags(struct net_device *net, unsigned long new_flags)
 {
 	return dev_change_flags(net, (unsigned int) new_flags);
 }
 
-static ssize_t store_flags(struct device *dev, struct device_attribute *attr,
+static ssize_t flags_store(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t len)
 {
 	return netdev_store(dev, attr, buf, len, change_flags);
 }
-
-NETDEVICE_SHOW(tx_queue_len, fmt_ulong);
+NETDEVICE_SHOW_RW(flags, fmt_hex);
 
 static int change_tx_queue_len(struct net_device *net, unsigned long new_len)
 {
@@ -273,7 +284,7 @@
 	return 0;
 }
 
-static ssize_t store_tx_queue_len(struct device *dev,
+static ssize_t tx_queue_len_store(struct device *dev,
 				  struct device_attribute *attr,
 				  const char *buf, size_t len)
 {
@@ -282,8 +293,9 @@
 
 	return netdev_store(dev, attr, buf, len, change_tx_queue_len);
 }
+NETDEVICE_SHOW_RW(tx_queue_len, fmt_ulong);
 
-static ssize_t store_ifalias(struct device *dev, struct device_attribute *attr,
+static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr,
 			     const char *buf, size_t len)
 {
 	struct net_device *netdev = to_net_dev(dev);
@@ -306,7 +318,7 @@
 	return ret < 0 ? ret : len;
 }
 
-static ssize_t show_ifalias(struct device *dev,
+static ssize_t ifalias_show(struct device *dev,
 			    struct device_attribute *attr, char *buf)
 {
 	const struct net_device *netdev = to_net_dev(dev);
@@ -319,8 +331,7 @@
 	rtnl_unlock();
 	return ret;
 }
-
-NETDEVICE_SHOW(group, fmt_dec);
+static DEVICE_ATTR_RW(ifalias);
 
 static int change_group(struct net_device *net, unsigned long new_group)
 {
@@ -328,35 +339,37 @@
 	return 0;
 }
 
-static ssize_t store_group(struct device *dev, struct device_attribute *attr,
-			 const char *buf, size_t len)
+static ssize_t group_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t len)
 {
 	return netdev_store(dev, attr, buf, len, change_group);
 }
+NETDEVICE_SHOW(group, fmt_dec);
+static DEVICE_ATTR(netdev_group, S_IRUGO | S_IWUSR, group_show, group_store);
 
-static struct device_attribute net_class_attributes[] = {
-	__ATTR(addr_assign_type, S_IRUGO, show_addr_assign_type, NULL),
-	__ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
-	__ATTR(dev_id, S_IRUGO, show_dev_id, NULL),
-	__ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias),
-	__ATTR(iflink, S_IRUGO, show_iflink, NULL),
-	__ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
-	__ATTR(type, S_IRUGO, show_type, NULL),
-	__ATTR(link_mode, S_IRUGO, show_link_mode, NULL),
-	__ATTR(address, S_IRUGO, show_address, NULL),
-	__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
-	__ATTR(carrier, S_IRUGO | S_IWUSR, show_carrier, store_carrier),
-	__ATTR(speed, S_IRUGO, show_speed, NULL),
-	__ATTR(duplex, S_IRUGO, show_duplex, NULL),
-	__ATTR(dormant, S_IRUGO, show_dormant, NULL),
-	__ATTR(operstate, S_IRUGO, show_operstate, NULL),
-	__ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu),
-	__ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags),
-	__ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len,
-	       store_tx_queue_len),
-	__ATTR(netdev_group, S_IRUGO | S_IWUSR, show_group, store_group),
-	{}
+static struct attribute *net_class_attrs[] = {
+	&dev_attr_netdev_group.attr,
+	&dev_attr_type.attr,
+	&dev_attr_dev_id.attr,
+	&dev_attr_iflink.attr,
+	&dev_attr_ifindex.attr,
+	&dev_attr_addr_assign_type.attr,
+	&dev_attr_addr_len.attr,
+	&dev_attr_link_mode.attr,
+	&dev_attr_address.attr,
+	&dev_attr_broadcast.attr,
+	&dev_attr_speed.attr,
+	&dev_attr_duplex.attr,
+	&dev_attr_dormant.attr,
+	&dev_attr_operstate.attr,
+	&dev_attr_ifalias.attr,
+	&dev_attr_carrier.attr,
+	&dev_attr_mtu.attr,
+	&dev_attr_flags.attr,
+	&dev_attr_tx_queue_len.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(net_class);
 
 /* Show a given an attribute in the statistics group */
 static ssize_t netstat_show(const struct device *d,
@@ -382,13 +395,13 @@
 
 /* generate a read-only statistics attribute */
 #define NETSTAT_ENTRY(name)						\
-static ssize_t show_##name(struct device *d,				\
+static ssize_t name##_show(struct device *d,				\
 			   struct device_attribute *attr, char *buf) 	\
 {									\
 	return netstat_show(d, attr, buf,				\
 			    offsetof(struct rtnl_link_stats64, name));	\
 }									\
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR_RO(name)
 
 NETSTAT_ENTRY(rx_packets);
 NETSTAT_ENTRY(tx_packets);
@@ -457,6 +470,9 @@
 	.attrs = wireless_attrs,
 };
 #endif
+
+#else /* CONFIG_SYSFS */
+#define net_class_groups	NULL
 #endif /* CONFIG_SYSFS */
 
 #ifdef CONFIG_RPS
@@ -1229,9 +1245,7 @@
 static struct class net_class = {
 	.name = "net",
 	.dev_release = netdev_release,
-#ifdef CONFIG_SYSFS
-	.dev_attrs = net_class_attributes,
-#endif /* CONFIG_SYSFS */
+	.dev_groups = net_class_groups,
 	.dev_uevent = netdev_uevent,
 	.ns_type = &net_ns_type_operations,
 	.namespace = net_namespace,
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index e533259..d9cd627 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -29,12 +29,6 @@
 
 #define PRIOMAP_MIN_SZ		128
 
-static inline struct cgroup_netprio_state *cgrp_netprio_state(struct cgroup *cgrp)
-{
-	return container_of(cgroup_subsys_state(cgrp, net_prio_subsys_id),
-			    struct cgroup_netprio_state, css);
-}
-
 /*
  * Extend @dev->priomap so that it's large enough to accomodate
  * @target_idx.  @dev->priomap.priomap_len > @target_idx after successful
@@ -87,67 +81,70 @@
 
 /**
  * netprio_prio - return the effective netprio of a cgroup-net_device pair
- * @cgrp: cgroup part of the target pair
+ * @css: css part of the target pair
  * @dev: net_device part of the target pair
  *
  * Should be called under RCU read or rtnl lock.
  */
-static u32 netprio_prio(struct cgroup *cgrp, struct net_device *dev)
+static u32 netprio_prio(struct cgroup_subsys_state *css, struct net_device *dev)
 {
 	struct netprio_map *map = rcu_dereference_rtnl(dev->priomap);
+	int id = css->cgroup->id;
 
-	if (map && cgrp->id < map->priomap_len)
-		return map->priomap[cgrp->id];
+	if (map && id < map->priomap_len)
+		return map->priomap[id];
 	return 0;
 }
 
 /**
  * netprio_set_prio - set netprio on a cgroup-net_device pair
- * @cgrp: cgroup part of the target pair
+ * @css: css part of the target pair
  * @dev: net_device part of the target pair
  * @prio: prio to set
  *
- * Set netprio to @prio on @cgrp-@dev pair.  Should be called under rtnl
+ * Set netprio to @prio on @css-@dev pair.  Should be called under rtnl
  * lock and may fail under memory pressure for non-zero @prio.
  */
-static int netprio_set_prio(struct cgroup *cgrp, struct net_device *dev,
-			    u32 prio)
+static int netprio_set_prio(struct cgroup_subsys_state *css,
+			    struct net_device *dev, u32 prio)
 {
 	struct netprio_map *map;
+	int id = css->cgroup->id;
 	int ret;
 
 	/* avoid extending priomap for zero writes */
 	map = rtnl_dereference(dev->priomap);
-	if (!prio && (!map || map->priomap_len <= cgrp->id))
+	if (!prio && (!map || map->priomap_len <= id))
 		return 0;
 
-	ret = extend_netdev_table(dev, cgrp->id);
+	ret = extend_netdev_table(dev, id);
 	if (ret)
 		return ret;
 
 	map = rtnl_dereference(dev->priomap);
-	map->priomap[cgrp->id] = prio;
+	map->priomap[id] = prio;
 	return 0;
 }
 
-static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
+static struct cgroup_subsys_state *
+cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
 {
-	struct cgroup_netprio_state *cs;
+	struct cgroup_subsys_state *css;
 
-	cs = kzalloc(sizeof(*cs), GFP_KERNEL);
-	if (!cs)
+	css = kzalloc(sizeof(*css), GFP_KERNEL);
+	if (!css)
 		return ERR_PTR(-ENOMEM);
 
-	return &cs->css;
+	return css;
 }
 
-static int cgrp_css_online(struct cgroup *cgrp)
+static int cgrp_css_online(struct cgroup_subsys_state *css)
 {
-	struct cgroup *parent = cgrp->parent;
+	struct cgroup_subsys_state *parent_css = css_parent(css);
 	struct net_device *dev;
 	int ret = 0;
 
-	if (!parent)
+	if (!parent_css)
 		return 0;
 
 	rtnl_lock();
@@ -156,9 +153,9 @@
 	 * onlining, there is no need to clear them on offline.
 	 */
 	for_each_netdev(&init_net, dev) {
-		u32 prio = netprio_prio(parent, dev);
+		u32 prio = netprio_prio(parent_css, dev);
 
-		ret = netprio_set_prio(cgrp, dev, prio);
+		ret = netprio_set_prio(css, dev, prio);
 		if (ret)
 			break;
 	}
@@ -166,29 +163,29 @@
 	return ret;
 }
 
-static void cgrp_css_free(struct cgroup *cgrp)
+static void cgrp_css_free(struct cgroup_subsys_state *css)
 {
-	kfree(cgrp_netprio_state(cgrp));
+	kfree(css);
 }
 
-static u64 read_prioidx(struct cgroup *cgrp, struct cftype *cft)
+static u64 read_prioidx(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	return cgrp->id;
+	return css->cgroup->id;
 }
 
-static int read_priomap(struct cgroup *cont, struct cftype *cft,
+static int read_priomap(struct cgroup_subsys_state *css, struct cftype *cft,
 			struct cgroup_map_cb *cb)
 {
 	struct net_device *dev;
 
 	rcu_read_lock();
 	for_each_netdev_rcu(&init_net, dev)
-		cb->fill(cb, dev->name, netprio_prio(cont, dev));
+		cb->fill(cb, dev->name, netprio_prio(css, dev));
 	rcu_read_unlock();
 	return 0;
 }
 
-static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
+static int write_priomap(struct cgroup_subsys_state *css, struct cftype *cft,
 			 const char *buffer)
 {
 	char devname[IFNAMSIZ + 1];
@@ -205,7 +202,7 @@
 
 	rtnl_lock();
 
-	ret = netprio_set_prio(cgrp, dev, prio);
+	ret = netprio_set_prio(css, dev, prio);
 
 	rtnl_unlock();
 	dev_put(dev);
@@ -221,12 +218,13 @@
 	return 0;
 }
 
-static void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static void net_prio_attach(struct cgroup_subsys_state *css,
+			    struct cgroup_taskset *tset)
 {
 	struct task_struct *p;
 	void *v;
 
-	cgroup_taskset_for_each(p, cgrp, tset) {
+	cgroup_taskset_for_each(p, css, tset) {
 		task_lock(p);
 		v = (void *)(unsigned long)task_netprioidx(p);
 		iterate_fd(p->files, 0, update_netprio, v);
diff --git a/net/core/scm.c b/net/core/scm.c
index 03795d0..b4da80b 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -54,7 +54,7 @@
 		return -EINVAL;
 
 	if ((creds->pid == task_tgid_vnr(current) ||
-	     ns_capable(current->nsproxy->pid_ns->user_ns, CAP_SYS_ADMIN)) &&
+	     ns_capable(task_active_pid_ns(current)->user_ns, CAP_SYS_ADMIN)) &&
 	    ((uid_eq(uid, cred->uid)   || uid_eq(uid, cred->euid) ||
 	      uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) &&
 	    ((gid_eq(gid, cred->gid)   || gid_eq(gid, cred->egid) ||
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c
index 13571ea..ef56ab5 100644
--- a/net/ieee802154/wpan-class.c
+++ b/net/ieee802154/wpan-class.c
@@ -36,7 +36,8 @@
 	ret = snprintf(buf, PAGE_SIZE, format_string "\n", args);	\
 	mutex_unlock(&phy->pib_lock);					\
 	return ret;							\
-}
+}									\
+static DEVICE_ATTR_RO(name);
 
 #define MASTER_SHOW(field, format_string)				\
 	MASTER_SHOW_COMPLEX(field, format_string, phy->field)
@@ -66,15 +67,17 @@
 	mutex_unlock(&phy->pib_lock);
 	return len;
 }
+static DEVICE_ATTR_RO(channels_supported);
 
-static struct device_attribute pmib_attrs[] = {
-	__ATTR_RO(current_channel),
-	__ATTR_RO(current_page),
-	__ATTR_RO(channels_supported),
-	__ATTR_RO(transmit_power),
-	__ATTR_RO(cca_mode),
-	{},
+static struct attribute *pmib_attrs[] = {
+	&dev_attr_current_channel.attr,
+	&dev_attr_current_page.attr,
+	&dev_attr_channels_supported.attr,
+	&dev_attr_transmit_power.attr,
+	&dev_attr_cca_mode.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(pmib);
 
 static void wpan_phy_release(struct device *d)
 {
@@ -85,7 +88,7 @@
 static struct class wpan_phy_class = {
 	.name = "ieee802154",
 	.dev_release = wpan_phy_release,
-	.dev_attrs = pmib_attrs,
+	.dev_groups = pmib_groups,
 };
 
 static DEFINE_MUTEX(wpan_phy_mutex);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 4bcabf3..9ee17e3 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -211,14 +211,6 @@
 	return -EINVAL;
 }
 
-static inline int ip_skb_dst_mtu(struct sk_buff *skb)
-{
-	struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
-
-	return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
-	       skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
-}
-
 static int ip_finish_output(struct sk_buff *skb)
 {
 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 51fc2a1..b3ac3c3 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -190,15 +190,14 @@
 	struct ip_tunnel *tunnel;
 	const struct iphdr *iph;
 
-	if (iptunnel_pull_header(skb, 0, tpi.proto))
-		goto drop;
-
 	iph = ip_hdr(skb);
 	tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
 			iph->saddr, iph->daddr, 0);
 	if (tunnel) {
 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
 			goto drop;
+		if (iptunnel_pull_header(skb, 0, tpi.proto))
+			goto drop;
 		return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error);
 	}
 
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index eadab1e..a865f6f 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -48,7 +48,7 @@
 	net->ipv4.arptable_filter =
 		arpt_register_table(net, &packet_filter, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv4.arptable_filter);
+	return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter);
 }
 
 static void __net_exit arptable_filter_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 6b3da5c..50af5b4 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -69,7 +69,7 @@
 	net->ipv4.iptable_filter =
 		ipt_register_table(net, &packet_filter, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv4.iptable_filter);
+	return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter);
 }
 
 static void __net_exit iptable_filter_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index cba5658..0d8cd82 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -107,7 +107,7 @@
 	net->ipv4.iptable_mangle =
 		ipt_register_table(net, &packet_mangler, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv4.iptable_mangle);
+	return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle);
 }
 
 static void __net_exit iptable_mangle_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index 6383273..683bfaf 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -292,7 +292,7 @@
 		return -ENOMEM;
 	net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv4.nat_table);
+	return PTR_ERR_OR_ZERO(net->ipv4.nat_table);
 }
 
 static void __net_exit iptable_nat_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 03d9696..1f82aea 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -48,7 +48,7 @@
 	net->ipv4.iptable_raw =
 		ipt_register_table(net, &packet_raw, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv4.iptable_raw);
+	return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw);
 }
 
 static void __net_exit iptable_raw_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
index b283d8e..f867a8d 100644
--- a/net/ipv4/netfilter/iptable_security.c
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -66,7 +66,7 @@
 	net->ipv4.iptable_security =
 		ipt_register_table(net, &security_table, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv4.iptable_security);
+	return PTR_ERR_OR_ZERO(net->ipv4.iptable_security);
 }
 
 static void __net_exit iptable_security_net_exit(struct net *net)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index dd44e0a..61e60d6 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -571,7 +571,8 @@
 	flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
 			   RT_SCOPE_UNIVERSE,
 			   inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
-			   inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
+			   inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP |
+			    (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
 			   daddr, saddr, 0, 0);
 
 	if (!inet->hdrincl) {
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 5423223..b2f6c74 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1121,6 +1121,13 @@
 					goto wait_for_memory;
 
 				/*
+				 * All packets are restored as if they have
+				 * already been sent.
+				 */
+				if (tp->repair)
+					TCP_SKB_CB(skb)->when = tcp_time_stamp;
+
+				/*
 				 * Check whether we can use HW checksum.
 				 */
 				if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 28af45a..3ca2139 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3535,7 +3535,10 @@
 		++ptr;
 		tp->rx_opt.rcv_tsval = ntohl(*ptr);
 		++ptr;
-		tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset;
+		if (*ptr)
+			tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset;
+		else
+			tp->rx_opt.rcv_tsecr = 0;
 		return true;
 	}
 	return false;
@@ -3560,7 +3563,7 @@
 	}
 
 	tcp_parse_options(skb, &tp->rx_opt, 1, NULL);
-	if (tp->rx_opt.saw_tstamp)
+	if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
 		tp->rx_opt.rcv_tsecr -= tp->tsoffset;
 
 	return true;
@@ -5316,7 +5319,7 @@
 	int saved_clamp = tp->rx_opt.mss_clamp;
 
 	tcp_parse_options(skb, &tp->rx_opt, 0, &foc);
-	if (tp->rx_opt.saw_tstamp)
+	if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
 		tp->rx_opt.rcv_tsecr -= tp->tsoffset;
 
 	if (th->ack) {
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index da14436..8a57d79 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -132,10 +132,10 @@
 	return 0;
 }
 
-static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
+static int tcp_cgroup_write(struct cgroup_subsys_state *css, struct cftype *cft,
 			    const char *buffer)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	unsigned long long val;
 	int ret = 0;
 
@@ -180,9 +180,9 @@
 	return res_counter_read_u64(&tcp->tcp_memory_allocated, RES_USAGE);
 }
 
-static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft)
+static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+	struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 	u64 val;
 
 	switch (cft->private) {
@@ -202,13 +202,13 @@
 	return val;
 }
 
-static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event)
+static int tcp_cgroup_reset(struct cgroup_subsys_state *css, unsigned int event)
 {
 	struct mem_cgroup *memcg;
 	struct tcp_memcontrol *tcp;
 	struct cg_proto *cg_proto;
 
-	memcg = mem_cgroup_from_cont(cont);
+	memcg = mem_cgroup_from_css(css);
 	cg_proto = tcp_prot.proto_cgroup(memcg);
 	if (!cg_proto)
 		return 0;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 92fde8d..170737a 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2670,7 +2670,7 @@
 	int tcp_header_size;
 	int mss;
 
-	skb = alloc_skb(MAX_TCP_HEADER + 15, sk_gfp_atomic(sk, GFP_ATOMIC));
+	skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
 	if (unlikely(!skb)) {
 		dst_release(dst);
 		return NULL;
@@ -2814,6 +2814,8 @@
 
 	if (likely(!tp->repair))
 		tp->rcv_nxt = 0;
+	else
+		tp->rcv_tstamp = tcp_time_stamp;
 	tp->rcv_wup = tp->rcv_nxt;
 	tp->copied_seq = tp->rcv_nxt;
 
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 327a617..baa0f63 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -21,7 +21,6 @@
 static int xfrm4_tunnel_check_size(struct sk_buff *skb)
 {
 	int mtu, ret = 0;
-	struct dst_entry *dst;
 
 	if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
 		goto out;
@@ -29,12 +28,10 @@
 	if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
 		goto out;
 
-	dst = skb_dst(skb);
-	mtu = dst_mtu(dst);
+	mtu = dst_mtu(skb_dst(skb));
 	if (skb->len > mtu) {
 		if (skb->sk)
-			ip_local_error(skb->sk, EMSGSIZE, ip_hdr(skb)->daddr,
-				       inet_sk(skb->sk)->inet_dport, mtu);
+			xfrm_local_error(skb, mtu);
 		else
 			icmp_send(skb, ICMP_DEST_UNREACH,
 				  ICMP_FRAG_NEEDED, htonl(mtu));
@@ -99,3 +96,12 @@
 			    x->outer_mode->afinfo->output_finish,
 			    !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
+
+void xfrm4_local_error(struct sk_buff *skb, u32 mtu)
+{
+	struct iphdr *hdr;
+
+	hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+	ip_local_error(skb->sk, EMSGSIZE, hdr->daddr,
+		       inet_sk(skb->sk)->inet_dport, mtu);
+}
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 9258e75..0b2a064 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -83,6 +83,7 @@
 	.extract_input		= xfrm4_extract_input,
 	.extract_output		= xfrm4_extract_output,
 	.transport_finish	= xfrm4_transport_finish,
+	.local_error		= xfrm4_local_error,
 };
 
 void __init xfrm4_state_init(void)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index da4241c..498ea99 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1126,12 +1126,10 @@
 	if (ifp->flags & IFA_F_OPTIMISTIC)
 		addr_flags |= IFA_F_OPTIMISTIC;
 
-	ift = !max_addresses ||
-	      ipv6_count_addresses(idev) < max_addresses ?
-		ipv6_add_addr(idev, &addr, NULL, tmp_plen,
-			      ipv6_addr_scope(&addr), addr_flags,
-			      tmp_valid_lft, tmp_prefered_lft) : NULL;
-	if (IS_ERR_OR_NULL(ift)) {
+	ift = ipv6_add_addr(idev, &addr, NULL, tmp_plen,
+			    ipv6_addr_scope(&addr), addr_flags,
+			    tmp_valid_lft, tmp_prefered_lft);
+	if (IS_ERR(ift)) {
 		in6_ifa_put(ifp);
 		in6_dev_put(idev);
 		pr_info("%s: retry temporary address regeneration\n", __func__);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index ecd6073..90747f1 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -724,6 +724,11 @@
 		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
 	}
 
+	if (likely(!skb->encapsulation)) {
+		skb_reset_inner_headers(skb);
+		skb->encapsulation = 1;
+	}
+
 	skb_push(skb, gre_hlen);
 	skb_reset_network_header(skb);
 	skb_set_transport_header(skb, sizeof(*ipv6h));
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6e3ddf8..e7ceb6c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -238,6 +238,7 @@
 	hdr->saddr = fl6->saddr;
 	hdr->daddr = *first_hop;
 
+	skb->protocol = htons(ETH_P_IPV6);
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
 
@@ -1057,6 +1058,7 @@
 		/* initialize protocol header pointer */
 		skb->transport_header = skb->network_header + fragheaderlen;
 
+		skb->protocol = htons(ETH_P_IPV6);
 		skb->ip_summed = CHECKSUM_PARTIAL;
 		skb->csum = 0;
 	}
@@ -1359,6 +1361,7 @@
 			/*
 			 *	Fill in the control structures
 			 */
+			skb->protocol = htons(ETH_P_IPV6);
 			skb->ip_summed = CHECKSUM_NONE;
 			skb->csum = 0;
 			/* reserve for fragmentation and ipsec header */
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 1e55866..46ba243 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1027,6 +1027,12 @@
 		init_tel_txopt(&opt, encap_limit);
 		ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
 	}
+
+	if (likely(!skb->encapsulation)) {
+		skb_reset_inner_headers(skb);
+		skb->encapsulation = 1;
+	}
+
 	skb_push(skb, sizeof(struct ipv6hdr));
 	skb_reset_network_header(skb);
 	ipv6h = ipv6_hdr(skb);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 79aa965..04d31c2 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1369,8 +1369,10 @@
 	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
 		return;
 
-	if (!ndopts.nd_opts_rh)
+	if (!ndopts.nd_opts_rh) {
+		ip6_redirect_no_header(skb, dev_net(skb->dev), 0, 0);
 		return;
+	}
 
 	hdr = (u8 *)ndopts.nd_opts_rh;
 	hdr += 8;
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index beb5777..29b44b1 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -61,7 +61,7 @@
 	net->ipv6.ip6table_filter =
 		ip6t_register_table(net, &packet_filter, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv6.ip6table_filter);
+	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_filter);
 }
 
 static void __net_exit ip6table_filter_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index e075399..c705907 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -101,7 +101,7 @@
 	net->ipv6.ip6table_mangle =
 		ip6t_register_table(net, &packet_mangler, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv6.ip6table_mangle);
+	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_mangle);
 }
 
 static void __net_exit ip6table_mangle_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index 6383f90..9b076d2 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -293,7 +293,7 @@
 		return -ENOMEM;
 	net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv6.ip6table_nat);
+	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat);
 }
 
 static void __net_exit ip6table_nat_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 60d1bdd..9a626d8 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -40,7 +40,7 @@
 	net->ipv6.ip6table_raw =
 		ip6t_register_table(net, &packet_raw, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv6.ip6table_raw);
+	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_raw);
 }
 
 static void __net_exit ip6table_raw_net_exit(struct net *net)
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
index db15535..ce88d1d 100644
--- a/net/ipv6/netfilter/ip6table_security.c
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -58,7 +58,7 @@
 	net->ipv6.ip6table_security =
 		ip6t_register_table(net, &security_table, repl);
 	kfree(repl);
-	return PTR_RET(net->ipv6.ip6table_security);
+	return PTR_ERR_OR_ZERO(net->ipv6.ip6table_security);
 }
 
 static void __net_exit ip6table_security_net_exit(struct net *net)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index c45f7a5..cdaed47 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -628,6 +628,7 @@
 		goto error;
 	skb_reserve(skb, hlen);
 
+	skb->protocol = htons(ETH_P_IPV6);
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
 	skb_dst_set(skb, &rt->dst);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 790d9f4..1aeb473 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -490,6 +490,7 @@
 	ipv6_hdr(head)->payload_len = htons(payload_len);
 	ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn);
 	IP6CB(head)->nhoff = nhoff;
+	IP6CB(head)->flags |= IP6SKB_FRAGMENTED;
 
 	/* Yes, and fold redundant checksum back. 8) */
 	if (head->ip_summed == CHECKSUM_COMPLETE)
@@ -524,6 +525,9 @@
 	struct net *net = dev_net(skb_dst(skb)->dev);
 	int evicted;
 
+	if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED)
+		goto fail_hdr;
+
 	IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
 
 	/* Jumbo payload inhibits frag. header */
@@ -544,6 +548,7 @@
 				 ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMOKS);
 
 		IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb);
+		IP6CB(skb)->flags |= IP6SKB_FRAGMENTED;
 		return 1;
 	}
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b70f8979..8d9a93e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1178,6 +1178,27 @@
 }
 EXPORT_SYMBOL_GPL(ip6_redirect);
 
+void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif,
+			    u32 mark)
+{
+	const struct ipv6hdr *iph = ipv6_hdr(skb);
+	const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb);
+	struct dst_entry *dst;
+	struct flowi6 fl6;
+
+	memset(&fl6, 0, sizeof(fl6));
+	fl6.flowi6_oif = oif;
+	fl6.flowi6_mark = mark;
+	fl6.flowi6_flags = 0;
+	fl6.daddr = msg->dest;
+	fl6.saddr = iph->daddr;
+
+	dst = ip6_route_output(net, NULL, &fl6);
+	if (!dst->error)
+		rt6_do_redirect(dst, NULL, skb);
+	dst_release(dst);
+}
+
 void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk)
 {
 	ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index a3437a4..21b25dd 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -645,11 +645,7 @@
 	const struct iphdr *iph;
 	struct ip_tunnel *tunnel;
 
-	if (iptunnel_pull_header(skb, 0, tpi.proto))
-		goto drop;
-
 	iph = ip_hdr(skb);
-
 	tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
 				     iph->saddr, iph->daddr);
 	if (tunnel != NULL) {
@@ -659,6 +655,8 @@
 
 		if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
 			goto drop;
+		if (iptunnel_pull_header(skb, 0, tpi.proto))
+			goto drop;
 		return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error);
 	}
 
@@ -888,6 +886,11 @@
 		ttl = iph6->hop_limit;
 	tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
 
+	if (likely(!skb->encapsulation)) {
+		skb_reset_inner_headers(skb);
+		skb->encapsulation = 1;
+	}
+
 	err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, fl4.daddr,
 			    IPPROTO_IPV6, tos, ttl, df);
 	iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 8755a30..6cd625e 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -34,8 +34,10 @@
 	struct sock *sk = skb->sk;
 
 	if (sk) {
-		proto = sk->sk_protocol;
+		if (sk->sk_family != AF_INET6)
+			return 0;
 
+		proto = sk->sk_protocol;
 		if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
 			return inet6_sk(sk)->dontfrag;
 	}
@@ -54,13 +56,15 @@
 	ipv6_local_rxpmtu(sk, &fl6, mtu);
 }
 
-static void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
+void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
 {
 	struct flowi6 fl6;
+	const struct ipv6hdr *hdr;
 	struct sock *sk = skb->sk;
 
+	hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
 	fl6.fl6_dport = inet_sk(sk)->inet_dport;
-	fl6.daddr = ipv6_hdr(skb)->daddr;
+	fl6.daddr = hdr->daddr;
 
 	ipv6_local_error(sk, EMSGSIZE, &fl6, mtu);
 }
@@ -80,7 +84,7 @@
 		if (xfrm6_local_dontfrag(skb))
 			xfrm6_local_rxpmtu(skb, mtu);
 		else if (skb->sk)
-			xfrm6_local_error(skb, mtu);
+			xfrm_local_error(skb, mtu);
 		else
 			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
 		ret = -EMSGSIZE;
@@ -136,13 +140,18 @@
 {
 	struct dst_entry *dst = skb_dst(skb);
 	struct xfrm_state *x = dst->xfrm;
-	int mtu = ip6_skb_dst_mtu(skb);
+	int mtu;
+
+	if (skb->protocol == htons(ETH_P_IPV6))
+		mtu = ip6_skb_dst_mtu(skb);
+	else
+		mtu = dst_mtu(skb_dst(skb));
 
 	if (skb->len > mtu && xfrm6_local_dontfrag(skb)) {
 		xfrm6_local_rxpmtu(skb, mtu);
 		return -EMSGSIZE;
 	} else if (!skb->local_df && skb->len > mtu && skb->sk) {
-		xfrm6_local_error(skb, mtu);
+		xfrm_local_error(skb, mtu);
 		return -EMSGSIZE;
 	}
 
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index d8c70b8..3fc9701 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -183,6 +183,7 @@
 	.extract_input		= xfrm6_extract_input,
 	.extract_output		= xfrm6_extract_output,
 	.transport_finish	= xfrm6_transport_finish,
+	.local_error		= xfrm6_local_error,
 };
 
 int __init xfrm6_state_init(void)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index ea7b9c2..2d45643 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -36,7 +36,7 @@
 
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 				      const u8 *bssid, const int beacon_int,
-				      struct ieee80211_channel *chan,
+				      struct cfg80211_chan_def *req_chandef,
 				      const u32 basic_rates,
 				      const u16 capability, u64 tsf,
 				      bool creator)
@@ -51,6 +51,7 @@
 	u32 bss_change;
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 	struct cfg80211_chan_def chandef;
+	struct ieee80211_channel *chan;
 	struct beacon_data *presp;
 	int frame_len;
 
@@ -81,7 +82,9 @@
 
 	sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-	chandef = ifibss->chandef;
+	/* make a copy of the chandef, it could be modified below. */
+	chandef = *req_chandef;
+	chan = chandef.chan;
 	if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
 		chandef.width = NL80211_CHAN_WIDTH_20;
 		chandef.center_freq1 = chan->center_freq;
@@ -259,10 +262,12 @@
 	struct cfg80211_bss *cbss =
 		container_of((void *)bss, struct cfg80211_bss, priv);
 	struct ieee80211_supported_band *sband;
+	struct cfg80211_chan_def chandef;
 	u32 basic_rates;
 	int i, j;
 	u16 beacon_int = cbss->beacon_interval;
 	const struct cfg80211_bss_ies *ies;
+	enum nl80211_channel_type chan_type;
 	u64 tsf;
 
 	sdata_assert_lock(sdata);
@@ -270,6 +275,26 @@
 	if (beacon_int < 10)
 		beacon_int = 10;
 
+	switch (sdata->u.ibss.chandef.width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+	case NL80211_CHAN_WIDTH_20:
+	case NL80211_CHAN_WIDTH_40:
+		chan_type = cfg80211_get_chandef_type(&sdata->u.ibss.chandef);
+		cfg80211_chandef_create(&chandef, cbss->channel, chan_type);
+		break;
+	case NL80211_CHAN_WIDTH_5:
+	case NL80211_CHAN_WIDTH_10:
+		cfg80211_chandef_create(&chandef, cbss->channel,
+					NL80211_CHAN_WIDTH_20_NOHT);
+		chandef.width = sdata->u.ibss.chandef.width;
+		break;
+	default:
+		/* fall back to 20 MHz for unsupported modes */
+		cfg80211_chandef_create(&chandef, cbss->channel,
+					NL80211_CHAN_WIDTH_20_NOHT);
+		break;
+	}
+
 	sband = sdata->local->hw.wiphy->bands[cbss->channel->band];
 
 	basic_rates = 0;
@@ -294,7 +319,7 @@
 
 	__ieee80211_sta_join_ibss(sdata, cbss->bssid,
 				  beacon_int,
-				  cbss->channel,
+				  &chandef,
 				  basic_rates,
 				  cbss->capability,
 				  tsf, false);
@@ -736,7 +761,7 @@
 		sdata->drop_unencrypted = 0;
 
 	__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
-				  ifibss->chandef.chan, ifibss->basic_rates,
+				  &ifibss->chandef, ifibss->basic_rates,
 				  capability, 0, true);
 }
 
@@ -1138,6 +1163,7 @@
 	clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
 						BSS_CHANGED_IBSS);
+	ieee80211_vif_release_channel(sdata);
 	synchronize_rcu();
 	kfree(presp);
 
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index f5aed96..f3bbea1 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -828,6 +828,9 @@
 	if (sband->band != IEEE80211_BAND_2GHZ)
 		return;
 
+	if (!(mp->hw->flags & IEEE80211_HW_SUPPORTS_HT_CCK_RATES))
+		return;
+
 	mi->cck_supported = 0;
 	mi->cck_supported_short = 0;
 	for (i = 0; i < 4; i++) {
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f85f8a2..0c741ce 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -364,7 +364,7 @@
 EXPORT_SYMBOL(genl_unregister_ops);
 
 /**
- * genl_register_family - register a generic netlink family
+ * __genl_register_family - register a generic netlink family
  * @family: generic netlink family
  *
  * Registers the specified family after validating it first. Only one
@@ -374,7 +374,7 @@
  *
  * Return 0 on success or a negative error code.
  */
-int genl_register_family(struct genl_family *family)
+int __genl_register_family(struct genl_family *family)
 {
 	int err = -EINVAL;
 
@@ -430,10 +430,10 @@
 errout:
 	return err;
 }
-EXPORT_SYMBOL(genl_register_family);
+EXPORT_SYMBOL(__genl_register_family);
 
 /**
- * genl_register_family_with_ops - register a generic netlink family
+ * __genl_register_family_with_ops - register a generic netlink family
  * @family: generic netlink family
  * @ops: operations to be registered
  * @n_ops: number of elements to register
@@ -457,12 +457,12 @@
  *
  * Return 0 on success or a negative error code.
  */
-int genl_register_family_with_ops(struct genl_family *family,
+int __genl_register_family_with_ops(struct genl_family *family,
 	struct genl_ops *ops, size_t n_ops)
 {
 	int err, i;
 
-	err = genl_register_family(family);
+	err = __genl_register_family(family);
 	if (err)
 		return err;
 
@@ -476,7 +476,7 @@
 	genl_unregister_family(family);
 	return err;
 }
-EXPORT_SYMBOL(genl_register_family_with_ops);
+EXPORT_SYMBOL(__genl_register_family_with_ops);
 
 /**
  * genl_unregister_family - unregister generic netlink family
@@ -544,6 +544,30 @@
 }
 EXPORT_SYMBOL(genlmsg_put);
 
+static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	struct genl_ops *ops = cb->data;
+	int rc;
+
+	genl_lock();
+	rc = ops->dumpit(skb, cb);
+	genl_unlock();
+	return rc;
+}
+
+static int genl_lock_done(struct netlink_callback *cb)
+{
+	struct genl_ops *ops = cb->data;
+	int rc = 0;
+
+	if (ops->done) {
+		genl_lock();
+		rc = ops->done(cb);
+		genl_unlock();
+	}
+	return rc;
+}
+
 static int genl_family_rcv_msg(struct genl_family *family,
 			       struct sk_buff *skb,
 			       struct nlmsghdr *nlh)
@@ -572,15 +596,34 @@
 		return -EPERM;
 
 	if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
-		struct netlink_dump_control c = {
-			.dump = ops->dumpit,
-			.done = ops->done,
-		};
+		int rc;
 
 		if (ops->dumpit == NULL)
 			return -EOPNOTSUPP;
 
-		return netlink_dump_start(net->genl_sock, skb, nlh, &c);
+		if (!family->parallel_ops) {
+			struct netlink_dump_control c = {
+				.module = family->module,
+				.data = ops,
+				.dump = genl_lock_dumpit,
+				.done = genl_lock_done,
+			};
+
+			genl_unlock();
+			rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
+			genl_lock();
+
+		} else {
+			struct netlink_dump_control c = {
+				.module = family->module,
+				.dump = ops->dumpit,
+				.done = ops->done,
+			};
+
+			rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
+		}
+
+		return rc;
 	}
 
 	if (ops->doit == NULL)
@@ -789,10 +832,6 @@
 	struct net *net = sock_net(skb->sk);
 	int chains_to_skip = cb->args[0];
 	int fams_to_skip = cb->args[1];
-	bool need_locking = chains_to_skip || fams_to_skip;
-
-	if (need_locking)
-		genl_lock();
 
 	for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
 		n = 0;
@@ -814,9 +853,6 @@
 	cb->args[0] = i;
 	cb->args[1] = n;
 
-	if (need_locking)
-		genl_unlock();
-
 	return skb->len;
 }
 
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 4b66c75..75c8bbf 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -3259,9 +3259,11 @@
 
 		if (po->tp_version == TPACKET_V3) {
 			lv = sizeof(struct tpacket_stats_v3);
+			st.stats3.tp_packets += st.stats3.tp_drops;
 			data = &st.stats3;
 		} else {
 			lv = sizeof(struct tpacket_stats);
+			st.stats1.tp_packets += st.stats1.tp_drops;
 			data = &st.stats1;
 		}
 
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 1cec5e4..1bacc10 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -576,14 +576,14 @@
 }
 EXPORT_SYMBOL(rfkill_set_states);
 
-static ssize_t rfkill_name_show(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%s\n", rfkill->name);
 }
+static DEVICE_ATTR_RO(name);
 
 static const char *rfkill_get_type_str(enum rfkill_type type)
 {
@@ -611,54 +611,52 @@
 	}
 }
 
-static ssize_t rfkill_type_show(struct device *dev,
-				struct device_attribute *attr,
-				char *buf)
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
 }
+static DEVICE_ATTR_RO(type);
 
-static ssize_t rfkill_idx_show(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
+static ssize_t index_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%d\n", rfkill->idx);
 }
+static DEVICE_ATTR_RO(index);
 
-static ssize_t rfkill_persistent_show(struct device *dev,
-			       struct device_attribute *attr,
-			       char *buf)
+static ssize_t persistent_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%d\n", rfkill->persistent);
 }
+static DEVICE_ATTR_RO(persistent);
 
-static ssize_t rfkill_hard_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
+static ssize_t hard_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%d\n", (rfkill->state & RFKILL_BLOCK_HW) ? 1 : 0 );
 }
+static DEVICE_ATTR_RO(hard);
 
-static ssize_t rfkill_soft_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
+static ssize_t soft_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%d\n", (rfkill->state & RFKILL_BLOCK_SW) ? 1 : 0 );
 }
 
-static ssize_t rfkill_soft_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
+static ssize_t soft_store(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 	unsigned long state;
@@ -680,6 +678,7 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(soft);
 
 static u8 user_state_from_blocked(unsigned long state)
 {
@@ -691,18 +690,16 @@
 	return RFKILL_USER_STATE_UNBLOCKED;
 }
 
-static ssize_t rfkill_state_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 
 	return sprintf(buf, "%d\n", user_state_from_blocked(rfkill->state));
 }
 
-static ssize_t rfkill_state_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
 {
 	struct rfkill *rfkill = to_rfkill(dev);
 	unsigned long state;
@@ -725,32 +722,27 @@
 
 	return count;
 }
+static DEVICE_ATTR_RW(state);
 
-static ssize_t rfkill_claim_show(struct device *dev,
-				 struct device_attribute *attr,
-				 char *buf)
+static ssize_t claim_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
+static DEVICE_ATTR_RO(claim);
 
-static ssize_t rfkill_claim_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
-{
-	return -EOPNOTSUPP;
-}
-
-static struct device_attribute rfkill_dev_attrs[] = {
-	__ATTR(name, S_IRUGO, rfkill_name_show, NULL),
-	__ATTR(type, S_IRUGO, rfkill_type_show, NULL),
-	__ATTR(index, S_IRUGO, rfkill_idx_show, NULL),
-	__ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL),
-	__ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
-	__ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
-	__ATTR(soft, S_IRUGO|S_IWUSR, rfkill_soft_show, rfkill_soft_store),
-	__ATTR(hard, S_IRUGO, rfkill_hard_show, NULL),
-	__ATTR_NULL
+static struct attribute *rfkill_dev_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_type.attr,
+	&dev_attr_index.attr,
+	&dev_attr_persistent.attr,
+	&dev_attr_state.attr,
+	&dev_attr_claim.attr,
+	&dev_attr_soft.attr,
+	&dev_attr_hard.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(rfkill_dev);
 
 static void rfkill_release(struct device *dev)
 {
@@ -830,7 +822,7 @@
 static struct class rfkill_class = {
 	.name		= "rfkill",
 	.dev_release	= rfkill_release,
-	.dev_attrs	= rfkill_dev_attrs,
+	.dev_groups	= rfkill_dev_groups,
 	.dev_uevent	= rfkill_dev_uevent,
 	.suspend	= rfkill_suspend,
 	.resume		= rfkill_resume,
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 3a294eb..867b4a3 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -23,19 +23,18 @@
 #include <net/sock.h>
 #include <net/cls_cgroup.h>
 
-static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp)
+static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state *css)
 {
-	return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id),
-			    struct cgroup_cls_state, css);
+	return css ? container_of(css, struct cgroup_cls_state, css) : NULL;
 }
 
 static inline struct cgroup_cls_state *task_cls_state(struct task_struct *p)
 {
-	return container_of(task_subsys_state(p, net_cls_subsys_id),
-			    struct cgroup_cls_state, css);
+	return css_cls_state(task_css(p, net_cls_subsys_id));
 }
 
-static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
+static struct cgroup_subsys_state *
+cgrp_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct cgroup_cls_state *cs;
 
@@ -45,17 +44,19 @@
 	return &cs->css;
 }
 
-static int cgrp_css_online(struct cgroup *cgrp)
+static int cgrp_css_online(struct cgroup_subsys_state *css)
 {
-	if (cgrp->parent)
-		cgrp_cls_state(cgrp)->classid =
-			cgrp_cls_state(cgrp->parent)->classid;
+	struct cgroup_cls_state *cs = css_cls_state(css);
+	struct cgroup_cls_state *parent = css_cls_state(css_parent(css));
+
+	if (parent)
+		cs->classid = parent->classid;
 	return 0;
 }
 
-static void cgrp_css_free(struct cgroup *cgrp)
+static void cgrp_css_free(struct cgroup_subsys_state *css)
 {
-	kfree(cgrp_cls_state(cgrp));
+	kfree(css_cls_state(css));
 }
 
 static int update_classid(const void *v, struct file *file, unsigned n)
@@ -67,12 +68,13 @@
 	return 0;
 }
 
-static void cgrp_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+static void cgrp_attach(struct cgroup_subsys_state *css,
+			struct cgroup_taskset *tset)
 {
 	struct task_struct *p;
 	void *v;
 
-	cgroup_taskset_for_each(p, cgrp, tset) {
+	cgroup_taskset_for_each(p, css, tset) {
 		task_lock(p);
 		v = (void *)(unsigned long)task_cls_classid(p);
 		iterate_fd(p->files, 0, update_classid, v);
@@ -80,14 +82,15 @@
 	}
 }
 
-static u64 read_classid(struct cgroup *cgrp, struct cftype *cft)
+static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
 {
-	return cgrp_cls_state(cgrp)->classid;
+	return css_cls_state(css)->classid;
 }
 
-static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value)
+static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
+			 u64 value)
 {
-	cgrp_cls_state(cgrp)->classid = (u32) value;
+	css_cls_state(css)->classid = (u32) value;
 	return 0;
 }
 
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 75edcfa..1504bb1 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -207,10 +207,13 @@
 		pgfrom_base -= copy;
 
 		vto = kmap_atomic(*pgto);
-		vfrom = kmap_atomic(*pgfrom);
-		memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
+		if (*pgto != *pgfrom) {
+			vfrom = kmap_atomic(*pgfrom);
+			memcpy(vto + pgto_base, vfrom + pgfrom_base, copy);
+			kunmap_atomic(vfrom);
+		} else
+			memmove(vto + pgto_base, vto + pgfrom_base, copy);
 		flush_dcache_page(*pgto);
-		kunmap_atomic(vfrom);
 		kunmap_atomic(vto);
 
 	} while ((len -= copy) != 0);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index ce8249c..6cc7ddd 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1257,7 +1257,7 @@
 		/* Accept only ACK or NACK message */
 		if (unlikely(msg_errcode(msg))) {
 			sock->state = SS_DISCONNECTING;
-			sk->sk_err = -ECONNREFUSED;
+			sk->sk_err = ECONNREFUSED;
 			retval = TIPC_OK;
 			break;
 		}
@@ -1268,7 +1268,7 @@
 		res = auto_connect(sock, msg);
 		if (res) {
 			sock->state = SS_DISCONNECTING;
-			sk->sk_err = res;
+			sk->sk_err = -res;
 			retval = TIPC_OK;
 			break;
 		}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3fcba69..5f6e982 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2622,8 +2622,8 @@
 
 	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 			     NL80211_CMD_NEW_KEY);
-	if (IS_ERR(hdr))
-		return PTR_ERR(hdr);
+	if (!hdr)
+		return -ENOBUFS;
 
 	cookie.msg = msg;
 	cookie.idx = key_idx;
@@ -6507,6 +6507,9 @@
 					   NL80211_CMD_TESTMODE);
 		struct nlattr *tmdata;
 
+		if (!hdr)
+			break;
+
 		if (nla_put_u32(skb, NL80211_ATTR_WIPHY, phy_idx)) {
 			genlmsg_cancel(skb, hdr);
 			break;
@@ -6951,9 +6954,8 @@
 
 	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 			     NL80211_CMD_REMAIN_ON_CHANNEL);
-
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -ENOBUFS;
 		goto free_msg;
 	}
 
@@ -7251,9 +7253,8 @@
 
 		hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 				     NL80211_CMD_FRAME);
-
-		if (IS_ERR(hdr)) {
-			err = PTR_ERR(hdr);
+		if (!hdr) {
+			err = -ENOBUFS;
 			goto free_msg;
 		}
 	}
@@ -8132,9 +8133,8 @@
 
 	hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
 			     NL80211_CMD_PROBE_CLIENT);
-
-	if (IS_ERR(hdr)) {
-		err = PTR_ERR(hdr);
+	if (!hdr) {
+		err = -ENOBUFS;
 		goto free_msg;
 	}
 
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 81c8a10..20e86a9 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -976,21 +976,19 @@
 			struct net_device *dev, u16 reason, bool wextev)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int err;
+	int err = 0;
 
 	ASSERT_WDEV_LOCK(wdev);
 
 	kfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
-	if (wdev->conn) {
+	if (wdev->conn)
 		err = cfg80211_sme_disconnect(wdev, reason);
-	} else if (!rdev->ops->disconnect) {
+	else if (!rdev->ops->disconnect)
 		cfg80211_mlme_down(rdev, dev);
-		err = 0;
-	} else {
+	else if (wdev->current_bss)
 		err = rdev_disconnect(rdev, dev, reason);
-	}
 
 	return err;
 }
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index a23253e..9ee6bc1 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -30,7 +30,8 @@
 			      char *buf)				\
 {									\
 	return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member);	\
-}
+}									\
+static DEVICE_ATTR_RO(name)
 
 SHOW_FMT(index, "%d", wiphy_idx);
 SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
@@ -42,7 +43,7 @@
 	struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy;
 	return sprintf(buf, "%s\n", dev_name(&wiphy->dev));
 }
-
+static DEVICE_ATTR_RO(name);
 
 static ssize_t addresses_show(struct device *dev,
 			      struct device_attribute *attr,
@@ -60,15 +61,17 @@
 
 	return buf - start;
 }
+static DEVICE_ATTR_RO(addresses);
 
-static struct device_attribute ieee80211_dev_attrs[] = {
-	__ATTR_RO(index),
-	__ATTR_RO(macaddress),
-	__ATTR_RO(address_mask),
-	__ATTR_RO(addresses),
-	__ATTR_RO(name),
-	{}
+static struct attribute *ieee80211_attrs[] = {
+	&dev_attr_index.attr,
+	&dev_attr_macaddress.attr,
+	&dev_attr_address_mask.attr,
+	&dev_attr_addresses.attr,
+	&dev_attr_name.attr,
+	NULL,
 };
+ATTRIBUTE_GROUPS(ieee80211);
 
 static void wiphy_dev_release(struct device *dev)
 {
@@ -146,7 +149,7 @@
 	.name = "ieee80211",
 	.owner = THIS_MODULE,
 	.dev_release = wiphy_dev_release,
-	.dev_attrs = ieee80211_dev_attrs,
+	.dev_groups = ieee80211_groups,
 	.dev_uevent = wiphy_uevent,
 #ifdef CONFIG_PM
 	.suspend = wiphy_suspend,
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index eb4a842..3bb2cdc 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -214,5 +214,26 @@
 	return inner_mode->afinfo->extract_output(x, skb);
 }
 
+void xfrm_local_error(struct sk_buff *skb, int mtu)
+{
+	unsigned int proto;
+	struct xfrm_state_afinfo *afinfo;
+
+	if (skb->protocol == htons(ETH_P_IP))
+		proto = AF_INET;
+	else if (skb->protocol == htons(ETH_P_IPV6))
+		proto = AF_INET6;
+	else
+		return;
+
+	afinfo = xfrm_state_get_afinfo(proto);
+	if (!afinfo)
+		return;
+
+	afinfo->local_error(skb, mtu);
+	xfrm_state_put_afinfo(afinfo);
+}
+
 EXPORT_SYMBOL_GPL(xfrm_output);
 EXPORT_SYMBOL_GPL(xfrm_inner_extract_output);
+EXPORT_SYMBOL_GPL(xfrm_local_error);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e52cab3..f77c371 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -320,10 +320,8 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(list)) != NULL) {
-		dev_put(skb->dev);
+	while ((skb = skb_dequeue(list)) != NULL)
 		kfree_skb(skb);
-	}
 }
 
 /* Rule must be locked. Release descentant resources, announce
@@ -1758,7 +1756,6 @@
 	struct sk_buff *skb;
 	struct sock *sk;
 	struct dst_entry *dst;
-	struct net_device *dev;
 	struct xfrm_policy *pol = (struct xfrm_policy *)arg;
 	struct xfrm_policy_queue *pq = &pol->polq;
 	struct flowi fl;
@@ -1805,7 +1802,6 @@
 		dst = xfrm_lookup(xp_net(pol), skb_dst(skb)->path,
 				  &fl, skb->sk, 0);
 		if (IS_ERR(dst)) {
-			dev_put(skb->dev);
 			kfree_skb(skb);
 			continue;
 		}
@@ -1814,9 +1810,7 @@
 		skb_dst_drop(skb);
 		skb_dst_set(skb, dst);
 
-		dev = skb->dev;
 		err = dst_output(skb);
-		dev_put(dev);
 	}
 
 	return;
@@ -1839,7 +1833,6 @@
 	}
 
 	skb_dst_force(skb);
-	dev_hold(skb->dev);
 
 	spin_lock_bh(&pq->hold_queue.lock);
 
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 78f66fa..54c0acd 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -39,9 +39,6 @@
 
 static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
 
-static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
-static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
-
 static inline unsigned int xfrm_dst_hash(struct net *net,
 					 const xfrm_address_t *daddr,
 					 const xfrm_address_t *saddr,
@@ -1860,7 +1857,7 @@
 }
 EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
 
-static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
+struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
 {
 	struct xfrm_state_afinfo *afinfo;
 	if (unlikely(family >= NPROTO))
@@ -1872,7 +1869,7 @@
 	return afinfo;
 }
 
-static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
+void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
 {
 	rcu_read_unlock();
 }
diff --git a/scripts/coccinelle/api/ptr_ret.cocci b/scripts/coccinelle/api/ptr_ret.cocci
index 2274638..e18f840 100644
--- a/scripts/coccinelle/api/ptr_ret.cocci
+++ b/scripts/coccinelle/api/ptr_ret.cocci
@@ -1,5 +1,5 @@
 ///
-/// Use PTR_RET rather than if(IS_ERR(...)) + PTR_ERR
+/// Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR
 ///
 // Confidence: High
 // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
@@ -7,7 +7,7 @@
 // URL: http://coccinelle.lip6.fr/
 // Options: --no-includes --include-headers
 //
-// Keywords: ERR_PTR, PTR_ERR, PTR_RET
+// Keywords: ERR_PTR, PTR_ERR, PTR_RET, PTR_ERR_OR_ZERO
 // Version min: 2.6.39
 //
 
@@ -21,21 +21,21 @@
 @@
 
 - if (IS_ERR(ptr)) return PTR_ERR(ptr); else return 0;
-+ return PTR_RET(ptr);
++ return PTR_ERR_OR_ZERO(ptr);
 
 @depends on patch@
 expression ptr;
 @@
 
 - if (IS_ERR(ptr)) return PTR_ERR(ptr); return 0;
-+ return PTR_RET(ptr);
++ return PTR_ERR_OR_ZERO(ptr);
 
 @depends on patch@
 expression ptr;
 @@
 
 - (IS_ERR(ptr) ? PTR_ERR(ptr) : 0)
-+ PTR_RET(ptr)
++ PTR_ERR_OR_ZERO(ptr)
 
 @r1 depends on !patch@
 expression ptr;
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 6216434..8247979 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -821,6 +821,7 @@
 {
 	".comment*",
 	".debug*",
+	".cranges",		/* sh64 */
 	".zdebug*",		/* Compressed debug sections. */
 	".GCC-command-line",	/* mn10300 */
 	".GCC.command.line",	/* record-gcc-switches, non mn10300 */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 2e2a0dd..e3a704c 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -666,6 +666,7 @@
 static int param_get_aabool(char *buffer, const struct kernel_param *kp);
 #define param_check_aabool param_check_bool
 static struct kernel_param_ops param_ops_aabool = {
+	.flags = KERNEL_PARAM_FL_NOARG,
 	.set = param_set_aabool,
 	.get = param_get_aabool
 };
@@ -682,6 +683,7 @@
 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
 #define param_check_aalockpolicy param_check_bool
 static struct kernel_param_ops param_ops_aalockpolicy = {
+	.flags = KERNEL_PARAM_FL_NOARG,
 	.set = param_set_aalockpolicy,
 	.get = param_get_aalockpolicy
 };
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index e8aad69..c123628 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -53,22 +53,17 @@
 
 static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
 {
-	return container_of(s, struct dev_cgroup, css);
-}
-
-static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup)
-{
-	return css_to_devcgroup(cgroup_subsys_state(cgroup, devices_subsys_id));
+	return s ? container_of(s, struct dev_cgroup, css) : NULL;
 }
 
 static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
 {
-	return css_to_devcgroup(task_subsys_state(task, devices_subsys_id));
+	return css_to_devcgroup(task_css(task, devices_subsys_id));
 }
 
 struct cgroup_subsys devices_subsys;
 
-static int devcgroup_can_attach(struct cgroup *new_cgrp,
+static int devcgroup_can_attach(struct cgroup_subsys_state *new_css,
 				struct cgroup_taskset *set)
 {
 	struct task_struct *task = cgroup_taskset_first(set);
@@ -193,18 +188,16 @@
 /**
  * devcgroup_online - initializes devcgroup's behavior and exceptions based on
  * 		      parent's
- * @cgroup: cgroup getting online
+ * @css: css getting online
  * returns 0 in case of success, error code otherwise
  */
-static int devcgroup_online(struct cgroup *cgroup)
+static int devcgroup_online(struct cgroup_subsys_state *css)
 {
-	struct dev_cgroup *dev_cgroup, *parent_dev_cgroup = NULL;
+	struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
+	struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css_parent(css));
 	int ret = 0;
 
 	mutex_lock(&devcgroup_mutex);
-	dev_cgroup = cgroup_to_devcgroup(cgroup);
-	if (cgroup->parent)
-		parent_dev_cgroup = cgroup_to_devcgroup(cgroup->parent);
 
 	if (parent_dev_cgroup == NULL)
 		dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
@@ -219,9 +212,9 @@
 	return ret;
 }
 
-static void devcgroup_offline(struct cgroup *cgroup)
+static void devcgroup_offline(struct cgroup_subsys_state *css)
 {
-	struct dev_cgroup *dev_cgroup = cgroup_to_devcgroup(cgroup);
+	struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
 
 	mutex_lock(&devcgroup_mutex);
 	dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
@@ -231,7 +224,8 @@
 /*
  * called from kernel/cgroup.c with cgroup_lock() held.
  */
-static struct cgroup_subsys_state *devcgroup_css_alloc(struct cgroup *cgroup)
+static struct cgroup_subsys_state *
+devcgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 {
 	struct dev_cgroup *dev_cgroup;
 
@@ -244,11 +238,10 @@
 	return &dev_cgroup->css;
 }
 
-static void devcgroup_css_free(struct cgroup *cgroup)
+static void devcgroup_css_free(struct cgroup_subsys_state *css)
 {
-	struct dev_cgroup *dev_cgroup;
+	struct dev_cgroup *dev_cgroup = css_to_devcgroup(css);
 
-	dev_cgroup = cgroup_to_devcgroup(cgroup);
 	__dev_exception_clean(dev_cgroup);
 	kfree(dev_cgroup);
 }
@@ -291,10 +284,10 @@
 		sprintf(str, "%u", m);
 }
 
-static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
-				struct seq_file *m)
+static int devcgroup_seq_read(struct cgroup_subsys_state *css,
+			      struct cftype *cft, struct seq_file *m)
 {
-	struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
+	struct dev_cgroup *devcgroup = css_to_devcgroup(css);
 	struct dev_exception_item *ex;
 	char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
 
@@ -394,12 +387,10 @@
 static int parent_has_perm(struct dev_cgroup *childcg,
 				  struct dev_exception_item *ex)
 {
-	struct cgroup *pcg = childcg->css.cgroup->parent;
-	struct dev_cgroup *parent;
+	struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css));
 
-	if (!pcg)
+	if (!parent)
 		return 1;
-	parent = cgroup_to_devcgroup(pcg);
 	return may_access(parent, ex, childcg->behavior);
 }
 
@@ -451,13 +442,13 @@
 static int propagate_exception(struct dev_cgroup *devcg_root,
 			       struct dev_exception_item *ex)
 {
-	struct cgroup *root = devcg_root->css.cgroup, *pos;
+	struct cgroup_subsys_state *pos;
 	int rc = 0;
 
 	rcu_read_lock();
 
-	cgroup_for_each_descendant_pre(pos, root) {
-		struct dev_cgroup *devcg = cgroup_to_devcgroup(pos);
+	css_for_each_descendant_pre(pos, &devcg_root->css) {
+		struct dev_cgroup *devcg = css_to_devcgroup(pos);
 
 		/*
 		 * Because devcgroup_mutex is held, no devcg will become
@@ -465,7 +456,7 @@
 		 * methods), and online ones are safe to access outside RCU
 		 * read lock without bumping refcnt.
 		 */
-		if (!is_devcg_online(devcg))
+		if (pos == &devcg_root->css || !is_devcg_online(devcg))
 			continue;
 
 		rcu_read_unlock();
@@ -524,15 +515,11 @@
 	char temp[12];		/* 11 + 1 characters needed for a u32 */
 	int count, rc = 0;
 	struct dev_exception_item ex;
-	struct cgroup *p = devcgroup->css.cgroup;
-	struct dev_cgroup *parent = NULL;
+	struct dev_cgroup *parent = css_to_devcgroup(css_parent(&devcgroup->css));
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	if (p->parent)
-		parent = cgroup_to_devcgroup(p->parent);
-
 	memset(&ex, 0, sizeof(ex));
 	b = buffer;
 
@@ -677,13 +664,13 @@
 	return rc;
 }
 
-static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
-				  const char *buffer)
+static int devcgroup_access_write(struct cgroup_subsys_state *css,
+				  struct cftype *cft, const char *buffer)
 {
 	int retval;
 
 	mutex_lock(&devcgroup_mutex);
-	retval = devcgroup_update_access(cgroup_to_devcgroup(cgrp),
+	retval = devcgroup_update_access(css_to_devcgroup(css),
 					 cft->private, buffer);
 	mutex_unlock(&devcgroup_mutex);
 	return retval;
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index ce431e6..5066a37 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -14,12 +14,14 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/dmaengine.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/regs-ac97.h>
 #include <mach/audio.h>
@@ -41,20 +43,20 @@
 	.reset	= pxa2xx_ac97_reset,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = {
-	.name			= "AC97 PCM out",
-	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMR(12),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_out_req = 12;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
+	.addr		= __PREG(PCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.maxburst	= 32,
+	.filter_data	= &pxa2xx_ac97_pcm_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_in = {
-	.name			= "AC97 PCM in",
-	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMR(11),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_in_req = 11;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
+	.addr		= __PREG(PCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.maxburst	= 32,
+	.filter_data	= &pxa2xx_ac97_pcm_in_req,
 };
 
 static struct snd_pcm *pxa2xx_ac97_pcm;
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
index 823359e..a61d7a9 100644
--- a/sound/arm/pxa2xx-pcm-lib.c
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -7,11 +7,13 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/dma.h>
 
@@ -43,6 +45,35 @@
 	size_t period = params_period_bytes(params);
 	pxa_dma_desc *dma_desc;
 	dma_addr_t dma_buff_phys, next_desc_phys;
+	u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
+
+	/* temporary transition hack */
+	switch (rtd->params->addr_width) {
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		dcmd |= DCMD_WIDTH1;
+		break;
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		dcmd |= DCMD_WIDTH2;
+		break;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		dcmd |= DCMD_WIDTH4;
+		break;
+	default:
+		/* can't happen */
+		break;
+	}
+
+	switch (rtd->params->maxburst) {
+	case 8:
+		dcmd |= DCMD_BURST8;
+		break;
+	case 16:
+		dcmd |= DCMD_BURST16;
+		break;
+	case 32:
+		dcmd |= DCMD_BURST32;
+		break;
+	}
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	runtime->dma_bytes = totsize;
@@ -55,14 +86,14 @@
 		dma_desc->ddadr = next_desc_phys;
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			dma_desc->dsadr = dma_buff_phys;
-			dma_desc->dtadr = rtd->params->dev_addr;
+			dma_desc->dtadr = rtd->params->addr;
 		} else {
-			dma_desc->dsadr = rtd->params->dev_addr;
+			dma_desc->dsadr = rtd->params->addr;
 			dma_desc->dtadr = dma_buff_phys;
 		}
 		if (period > totsize)
 			period = totsize;
-		dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
+		dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
 		dma_desc++;
 		dma_buff_phys += period;
 	} while (totsize -= period);
@@ -76,8 +107,10 @@
 {
 	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 
-	if (rtd && rtd->params && rtd->params->drcmr)
-		*rtd->params->drcmr = 0;
+	if (rtd && rtd->params && rtd->params->filter_data) {
+		unsigned long req = *(unsigned long *) rtd->params->filter_data;
+		DRCMR(req) = 0;
+	}
 
 	snd_pcm_set_runtime_buffer(substream, NULL);
 	return 0;
@@ -136,6 +169,7 @@
 int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
 	struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+	unsigned long req;
 
 	if (!prtd || !prtd->params)
 		return 0;
@@ -146,7 +180,8 @@
 	DCSR(prtd->dma_ch) &= ~DCSR_RUN;
 	DCSR(prtd->dma_ch) = 0;
 	DCMD(prtd->dma_ch) = 0;
-	*prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
+	req = *(unsigned long *) prtd->params->filter_data;
+	DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;
 
 	return 0;
 }
@@ -155,7 +190,6 @@
 void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
 {
 	struct snd_pcm_substream *substream = dev_id;
-	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 	int dcsr;
 
 	dcsr = DCSR(dma_ch);
@@ -164,8 +198,8 @@
 	if (dcsr & DCSR_ENDINTR) {
 		snd_pcm_period_elapsed(substream);
 	} else {
-		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-			rtd->params->name, dma_ch, dcsr);
+		printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
+			dma_ch, dcsr);
 		snd_pcm_stream_lock(substream);
 		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
 		snd_pcm_stream_unlock(substream);
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index 26422a3..69a2455 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -11,8 +11,11 @@
  */
 
 #include <linux/module.h>
+#include <linux/dmaengine.h>
+
 #include <sound/core.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "pxa2xx-pcm.h"
 
@@ -40,7 +43,7 @@
 
 	rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		      client->playback_params : client->capture_params;
-	ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW,
+	ret = pxa_request_dma("dma", DMA_PRIO_LOW,
 			      pxa2xx_pcm_dma_irq, substream);
 	if (ret < 0)
 		goto err2;
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
index 65f86b5..2a8fc08 100644
--- a/sound/arm/pxa2xx-pcm.h
+++ b/sound/arm/pxa2xx-pcm.h
@@ -13,14 +13,14 @@
 
 struct pxa2xx_runtime_data {
 	int dma_ch;
-	struct pxa2xx_pcm_dma_params *params;
+	struct snd_dmaengine_dai_dma_data *params;
 	pxa_dma_desc *dma_desc_array;
 	dma_addr_t dma_desc_array_phys;
 };
 
 struct pxa2xx_pcm_client {
-	struct pxa2xx_pcm_dma_params *playback_params;
-	struct pxa2xx_pcm_dma_params *capture_params;
+	struct snd_dmaengine_dai_dma_data *playback_params;
+	struct snd_dmaengine_dai_dma_data *capture_params;
 	int (*startup)(struct snd_pcm_substream *);
 	void (*shutdown)(struct snd_pcm_substream *);
 	int (*prepare)(struct snd_pcm_substream *);
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index c0c2f57..313f22e 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -6,6 +6,9 @@
 	tristate
 	select SND_TIMER
 
+config SND_DMAENGINE_PCM
+	tristate
+
 config SND_HWDEP
 	tristate
 
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 43d4117..5e890cf 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -13,6 +13,8 @@
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
 		pcm_memory.o
 
+snd-pcm-dmaengine-objs := pcm_dmaengine.o
+
 snd-page-alloc-y := memalloc.o
 snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
 
@@ -30,6 +32,7 @@
 obj-$(CONFIG_SND_HRTIMER)	+= snd-hrtimer.o
 obj-$(CONFIG_SND_RTCTIMER)	+= snd-rtctimer.o
 obj-$(CONFIG_SND_PCM)		+= snd-pcm.o snd-page-alloc.o
+obj-$(CONFIG_SND_DMAENGINE_PCM)	+= snd-pcm-dmaengine.o
 obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi.o
 
 obj-$(CONFIG_SND_OSSEMUL)	+= oss/
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/core/pcm_dmaengine.c
similarity index 100%
rename from sound/soc/soc-dmaengine-pcm.c
rename to sound/core/pcm_dmaengine.c
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 82bb029..6e03b46 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -184,7 +184,7 @@
 	do {								\
 		if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {		\
 			xrun_log_show(substream);			\
-			if (printk_ratelimit()) {			\
+			if (snd_printd_ratelimit()) {			\
 				snd_printd("PCM: " fmt, ##args);	\
 			}						\
 			dump_stack_on_xrun(substream);			\
@@ -342,7 +342,7 @@
 		return -EPIPE;
 	}
 	if (pos >= runtime->buffer_size) {
-		if (printk_ratelimit()) {
+		if (snd_printd_ratelimit()) {
 			char name[16];
 			snd_pcm_debug_name(substream, name, sizeof(name));
 			xrun_log_show(substream);
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 11048cc..915b4d7 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -1022,7 +1022,7 @@
 		if (i >= ARRAY_SIZE(fields))
 			continue;
 		snd_info_get_str(item, ptr, sizeof(item));
-		if (strict_strtoull(item, 0, &val))
+		if (kstrtoull(item, 0, &val))
 			continue;
 		if (fields[i].size == sizeof(int))
 			*get_dummy_int_ptr(dummy, fields[i].offset) = val;
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index 2c63865..fe9e6e2 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -49,7 +49,6 @@
 	struct snd_card *card;
 	struct fw_unit *unit;
 	const struct device_info *device_info;
-	struct snd_pcm_substream *pcm;
 	struct mutex mutex;
 	struct cmp_connection connection;
 	struct amdtp_out_stream stream;
@@ -363,8 +362,7 @@
 		return err;
 	pcm->private_data = fwspk;
 	strcpy(pcm->name, fwspk->device_info->short_name);
-	fwspk->pcm = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-	fwspk->pcm->ops = &ops;
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
 	return 0;
 }
 
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 9942691..afef0d7 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -443,8 +443,7 @@
 		for (i = 0; i < 8; ++i)
 			iwave[i] = snd_gf1_peek(gus, bank_pos + i);
 #ifdef CONFIG_SND_DEBUG_ROM
-		printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
-				  8, iwave);
+		printk(KERN_DEBUG "ROM at 0x%06x = %8phC\n", bank_pos, iwave);
 #endif
 		if (strncmp(iwave, "INTRWAVE", 8))
 			continue;	/* first check */
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 103b333..6effe99 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -173,11 +173,7 @@
 
 #endif	/* CONFIG_PNP */
 
-#ifdef OPTi93X
-#define DEV_NAME "opti93x"
-#else
-#define DEV_NAME "opti92x"
-#endif
+#define DEV_NAME KBUILD_MODNAME
 
 static char * snd_opti9xx_names[] = {
 	"unknown",
@@ -1167,7 +1163,7 @@
 
 static struct pnp_card_driver opti9xx_pnpc_driver = {
 	.flags		= PNP_DRIVER_RES_DISABLE,
-	.name		= "opti9xx",
+	.name		= DEV_NAME,
 	.id_table	= snd_opti9xx_pnpids,
 	.probe		= snd_opti9xx_pnp_probe,
 	.remove		= snd_opti9xx_pnp_remove,
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index a59c888..461d94c 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -557,7 +557,6 @@
 	unsigned long flags;
 	int err = 0, n = 0;
 	struct dma_buffparms *dmap = adev->dmap_in;
-	int go;
 
 	if (!(adev->open_mode & OPEN_READ))
 		return -EIO;
@@ -584,7 +583,7 @@
 			spin_unlock_irqrestore(&dmap->lock,flags);
 			return -EAGAIN;
 		}
-		if ((go = adev->go))
+		if (adev->go)
 			timeout = dmabuf_timeout(dmap);
 
 		spin_unlock_irqrestore(&dmap->lock,flags);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 59c5e9c..8de66cc 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -152,14 +152,9 @@
 	  This module is automatically loaded at probing.
 
 config SND_HDA_I915
-	bool "Build Display HD-audio controller/codec power well support for i915 cards"
+	bool
+	default y
 	depends on DRM_I915
-	help
-	  Say Y here to include full HDMI and DisplayPort HD-audio controller/codec
-	  power-well support for Intel Haswell graphics cards based on the i915 driver.
-
-	  Note that this option must be enabled for Intel Haswell C+ stepping machines, otherwise
-	  the GPU audio controller/codecs will not be initialized or damaged when exit from S3 mode.
 
 config SND_HDA_CODEC_CIRRUS
 	bool "Build Cirrus Logic codec support"
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 8a005f0..5b6c4e3 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -666,6 +666,64 @@
 }
 EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
 
+
+/* return DEVLIST_LEN parameter of the given widget */
+static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
+{
+	unsigned int wcaps = get_wcaps(codec, nid);
+	unsigned int parm;
+
+	if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) ||
+	    get_wcaps_type(wcaps) != AC_WID_PIN)
+		return 0;
+
+	parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN);
+	if (parm == -1 && codec->bus->rirb_error)
+		parm = 0;
+	return parm & AC_DEV_LIST_LEN_MASK;
+}
+
+/**
+ * snd_hda_get_devices - copy device list without cache
+ * @codec: the HDA codec
+ * @nid: NID of the pin to parse
+ * @dev_list: device list array
+ * @max_devices: max. number of devices to store
+ *
+ * Copy the device list. This info is dynamic and so not cached.
+ * Currently called only from hda_proc.c, so not exported.
+ */
+int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
+			u8 *dev_list, int max_devices)
+{
+	unsigned int parm;
+	int i, dev_len, devices;
+
+	parm = get_num_devices(codec, nid);
+	if (!parm)	/* not multi-stream capable */
+		return 0;
+
+	dev_len = parm + 1;
+	dev_len = dev_len < max_devices ? dev_len : max_devices;
+
+	devices = 0;
+	while (devices < dev_len) {
+		parm = snd_hda_codec_read(codec, nid, 0,
+					  AC_VERB_GET_DEVICE_LIST, devices);
+		if (parm == -1 && codec->bus->rirb_error)
+			break;
+
+		for (i = 0; i < 8; i++) {
+			dev_list[devices] = (u8)parm;
+			parm >>= 4;
+			devices++;
+			if (devices >= dev_len)
+				break;
+		}
+	}
+	return devices;
+}
+
 /**
  * snd_hda_queue_unsol_event - add an unsolicited event to queue
  * @bus: the BUS
@@ -1216,11 +1274,13 @@
 {
 	struct hda_codec *codec =
 		container_of(work, struct hda_codec, jackpoll_work.work);
-	if (!codec->jackpoll_interval)
-		return;
 
 	snd_hda_jack_set_dirty_all(codec);
 	snd_hda_jack_poll_all(codec);
+
+	if (!codec->jackpoll_interval)
+		return;
+
 	queue_delayed_work(codec->bus->workq, &codec->jackpoll_work,
 			   codec->jackpoll_interval);
 }
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 701c2e0..7aa9870 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -94,6 +94,8 @@
 #define AC_VERB_GET_HDMI_DIP_XMIT		0x0f32
 #define AC_VERB_GET_HDMI_CP_CTRL		0x0f33
 #define AC_VERB_GET_HDMI_CHAN_SLOT		0x0f34
+#define AC_VERB_GET_DEVICE_SEL			0xf35
+#define AC_VERB_GET_DEVICE_LIST			0xf36
 
 /*
  * SET verbs
@@ -133,6 +135,7 @@
 #define AC_VERB_SET_HDMI_DIP_XMIT		0x732
 #define AC_VERB_SET_HDMI_CP_CTRL		0x733
 #define AC_VERB_SET_HDMI_CHAN_SLOT		0x734
+#define AC_VERB_SET_DEVICE_SEL			0x735
 
 /*
  * Parameter IDs
@@ -154,6 +157,7 @@
 #define AC_PAR_GPIO_CAP			0x11
 #define AC_PAR_AMP_OUT_CAP		0x12
 #define AC_PAR_VOL_KNB_CAP		0x13
+#define AC_PAR_DEVLIST_LEN		0x15
 #define AC_PAR_HDMI_LPCM_CAP		0x20
 
 /*
@@ -251,6 +255,11 @@
 #define AC_UNSOL_RES_TAG_SHIFT		26
 #define AC_UNSOL_RES_SUBTAG		(0x1f<<21)
 #define AC_UNSOL_RES_SUBTAG_SHIFT	21
+#define AC_UNSOL_RES_DE			(0x3f<<15)  /* Device Entry
+						     * (for DP1.2 MST)
+						     */
+#define AC_UNSOL_RES_DE_SHIFT		15
+#define AC_UNSOL_RES_IA			(1<<2)	/* Inactive (for DP1.2 MST) */
 #define AC_UNSOL_RES_ELDV		(1<<1)	/* ELD Data valid (for HDMI) */
 #define AC_UNSOL_RES_PD			(1<<0)	/* pinsense detect */
 #define AC_UNSOL_RES_CP_STATE		(1<<1)	/* content protection */
@@ -352,6 +361,10 @@
 #define AC_LPCMCAP_44K			(1<<30)	/* 44.1kHz support */
 #define AC_LPCMCAP_44K_MS		(1<<31)	/* 44.1kHz-multiplies support */
 
+/* Display pin's device list length */
+#define AC_DEV_LIST_LEN_MASK		0x3f
+#define AC_MAX_DEV_LIST_LEN		64
+
 /*
  * Control Parameters
  */
@@ -460,6 +473,11 @@
 #define AC_DEFCFG_PORT_CONN		(0x3<<30)
 #define AC_DEFCFG_PORT_CONN_SHIFT	30
 
+/* Display pin's device list entry */
+#define AC_DE_PD			(1<<0)
+#define AC_DE_ELDV			(1<<1)
+#define AC_DE_IA			(1<<2)
+
 /* device device types (0x0-0xf) */
 enum {
 	AC_JACK_LINE_OUT,
@@ -885,6 +903,7 @@
 	unsigned int pcm_format_first:1; /* PCM format must be set first */
 	unsigned int epss:1;		/* supporting EPSS? */
 	unsigned int cached_write:1;	/* write only to caches */
+	unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
 #ifdef CONFIG_PM
 	unsigned int power_on :1;	/* current (global) power-state */
 	unsigned int d3_stop_clk:1;	/* support D3 operation without BCLK */
@@ -972,6 +991,8 @@
 			  const hda_nid_t *list);
 int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
 			   hda_nid_t nid, int recursive);
+int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
+			u8 *dev_list, int max_devices);
 int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
 				u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
 
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index e3c7ba8..ac41e9c 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -142,6 +142,9 @@
 	val = snd_hda_get_bool_hint(codec, "primary_hp");
 	if (val >= 0)
 		spec->no_primary_hp = !val;
+	val = snd_hda_get_bool_hint(codec, "multi_io");
+	if (val >= 0)
+		spec->no_multi_io = !val;
 	val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
 	if (val >= 0)
 		spec->multi_cap_vol = !!val;
@@ -813,6 +816,8 @@
 
 static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_value *ucontrol);
+static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol);
 
 enum {
 	HDA_CTL_WIDGET_VOL,
@@ -830,7 +835,13 @@
 		.put = hda_gen_mixer_mute_put, /* replaced */
 		.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
 	},
-	HDA_BIND_MUTE(NULL, 0, 0, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_bind_switch_get,
+		.put = hda_gen_bind_mute_put, /* replaced */
+		.private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
+	},
 };
 
 /* add dynamic controls from template */
@@ -937,8 +948,8 @@
 }
 
 /* playback mute control with the software mute bit check */
-static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
-				  struct snd_ctl_elem_value *ucontrol)
+static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_gen_spec *spec = codec->spec;
@@ -949,10 +960,22 @@
 		ucontrol->value.integer.value[0] &= enabled;
 		ucontrol->value.integer.value[1] &= enabled;
 	}
+}
 
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	sync_auto_mute_bits(kcontrol, ucontrol);
 	return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 }
 
+static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	sync_auto_mute_bits(kcontrol, ucontrol);
+	return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol);
+}
+
 /* any ctl assigned to the path with the given index? */
 static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
 {
@@ -1541,7 +1564,8 @@
 					      cfg->speaker_pins,
 					      spec->multiout.extra_out_nid,
 					      spec->speaker_paths);
-			if (fill_mio_first && cfg->line_outs == 1 &&
+			if (!spec->no_multi_io &&
+			    fill_mio_first && cfg->line_outs == 1 &&
 			    cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
 				err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
 				if (!err)
@@ -1554,7 +1578,7 @@
 				   spec->private_dac_nids, spec->out_paths,
 				   spec->main_out_badness);
 
-	if (fill_mio_first &&
+	if (!spec->no_multi_io && fill_mio_first &&
 	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
 		/* try to fill multi-io first */
 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
@@ -1582,7 +1606,8 @@
 			return err;
 		badness += err;
 	}
-	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+	if (!spec->no_multi_io &&
+	    cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
 		err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
 		if (err < 0)
 			return err;
@@ -1600,7 +1625,8 @@
 				check_aamix_out_path(codec, spec->speaker_paths[0]);
 	}
 
-	if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+	if (!spec->no_multi_io &&
+	    cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
 		if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
 			spec->multi_ios = 1; /* give badness */
 
@@ -3724,7 +3750,8 @@
 /* check each pin in the given array; returns true if any of them is plugged */
 static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
 {
-	int i, present = 0;
+	int i;
+	bool present = false;
 
 	for (i = 0; i < num_pins; i++) {
 		hda_nid_t nid = pins[i];
@@ -3733,14 +3760,15 @@
 		/* don't detect pins retasked as inputs */
 		if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
 			continue;
-		present |= snd_hda_jack_detect(codec, nid);
+		if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
+			present = true;
 	}
 	return present;
 }
 
 /* standard HP/line-out auto-mute helper */
 static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
-			bool mute)
+			int *paths, bool mute)
 {
 	struct hda_gen_spec *spec = codec->spec;
 	int i;
@@ -3752,10 +3780,19 @@
 			break;
 
 		if (spec->auto_mute_via_amp) {
+			struct nid_path *path;
+			hda_nid_t mute_nid;
+
+			path = snd_hda_get_path_from_idx(codec, paths[i]);
+			if (!path)
+				continue;
+			mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
+			if (!mute_nid)
+				continue;
 			if (mute)
-				spec->mute_bits |= (1ULL << nid);
+				spec->mute_bits |= (1ULL << mute_nid);
 			else
-				spec->mute_bits &= ~(1ULL << nid);
+				spec->mute_bits &= ~(1ULL << mute_nid);
 			set_pin_eapd(codec, nid, !mute);
 			continue;
 		}
@@ -3786,14 +3823,19 @@
 void snd_hda_gen_update_outputs(struct hda_codec *codec)
 {
 	struct hda_gen_spec *spec = codec->spec;
+	int *paths;
 	int on;
 
 	/* Control HP pins/amps depending on master_mute state;
 	 * in general, HP pins/amps control should be enabled in all cases,
 	 * but currently set only for master_mute, just to be safe
 	 */
+	if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+		paths = spec->out_paths;
+	else
+		paths = spec->hp_paths;
 	do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
-		    spec->autocfg.hp_pins, spec->master_mute);
+		    spec->autocfg.hp_pins, paths, spec->master_mute);
 
 	if (!spec->automute_speaker)
 		on = 0;
@@ -3801,8 +3843,12 @@
 		on = spec->hp_jack_present | spec->line_jack_present;
 	on |= spec->master_mute;
 	spec->speaker_muted = on;
+	if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+		paths = spec->out_paths;
+	else
+		paths = spec->speaker_paths;
 	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
-		    spec->autocfg.speaker_pins, on);
+		    spec->autocfg.speaker_pins, paths, on);
 
 	/* toggle line-out mutes if needed, too */
 	/* if LO is a copy of either HP or Speaker, don't need to handle it */
@@ -3815,8 +3861,9 @@
 		on = spec->hp_jack_present;
 	on |= spec->master_mute;
 	spec->line_out_muted = on;
+	paths = spec->out_paths;
 	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
-		    spec->autocfg.line_out_pins, on);
+		    spec->autocfg.line_out_pins, paths, on);
 }
 EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
 
@@ -3887,7 +3934,7 @@
 		/* don't detect pins retasked as outputs */
 		if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
 			continue;
-		if (snd_hda_jack_detect(codec, pin)) {
+		if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
 			mux_select(codec, 0, spec->am_entry[i].idx);
 			return;
 		}
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index e199a85..48d4402 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -220,6 +220,7 @@
 	unsigned int hp_mic:1; /* Allow HP as a mic-in */
 	unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
 	unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
+	unsigned int no_multi_io:1; /* Don't try multi I/O config */
 	unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
 	unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
 	unsigned int own_eapd_ctl:1; /* set EAPD by own function */
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index ce67608..fe0bda1 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -295,7 +295,7 @@
 	struct snd_hwdep *hwdep = dev_get_drvdata(dev);		\
 	struct hda_codec *codec = hwdep->private_data;		\
 	unsigned long val;					\
-	int err = strict_strtoul(buf, 0, &val);			\
+	int err = kstrtoul(buf, 0, &val);			\
 	if (err < 0)						\
 		return err;					\
 	codec->type = val;					\
@@ -654,7 +654,7 @@
 	p = snd_hda_get_hint(codec, key);
 	if (!p)
 		ret = -ENOENT;
-	else if (strict_strtoul(p, 0, &val))
+	else if (kstrtoul(p, 0, &val))
 		ret = -EINVAL;
 	else {
 		*valp = val;
@@ -751,7 +751,7 @@
 				 struct hda_codec **codecp) \
 { \
 	unsigned long val; \
-	if (!strict_strtoul(buf, 0, &val)) \
+	if (!kstrtoul(buf, 0, &val)) \
 		(*codecp)->name = val; \
 }
 
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 8860dd52..c6c9829 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1160,7 +1160,7 @@
 		goto __skip;
 
 	/* clear STATESTS */
-	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
 
 	/* reset controller */
 	azx_enter_link_reset(chip);
@@ -1242,7 +1242,7 @@
 	}
 
 	/* clear STATESTS */
-	azx_writeb(chip, STATESTS, STATESTS_INT_MASK);
+	azx_writew(chip, STATESTS, STATESTS_INT_MASK);
 
 	/* clear rirb status */
 	azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
@@ -1451,8 +1451,8 @@
 
 #if 0
 	/* clear state status int */
-	if (azx_readb(chip, STATESTS) & 0x04)
-		azx_writeb(chip, STATESTS, 0x04);
+	if (azx_readw(chip, STATESTS) & 0x04)
+		azx_writew(chip, STATESTS, 0x04);
 #endif
 	spin_unlock(&chip->reg_lock);
 	
@@ -2971,6 +2971,10 @@
 	struct snd_card *card = dev_get_drvdata(dev);
 	struct azx *chip = card->private_data;
 
+	/* enable controller wake up event */
+	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) |
+		  STATESTS_INT_MASK);
+
 	azx_stop_chip(chip);
 	azx_enter_link_reset(chip);
 	azx_clear_irq_pending(chip);
@@ -2983,11 +2987,31 @@
 {
 	struct snd_card *card = dev_get_drvdata(dev);
 	struct azx *chip = card->private_data;
+	struct hda_bus *bus;
+	struct hda_codec *codec;
+	int status;
 
 	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
 		hda_display_power(true);
+
+	/* Read STATESTS before controller reset */
+	status = azx_readw(chip, STATESTS);
+
 	azx_init_pci(chip);
 	azx_init_chip(chip, 1);
+
+	bus = chip->bus;
+	if (status && bus) {
+		list_for_each_entry(codec, &bus->codec_list, list)
+			if (status & (1 << codec->addr))
+				queue_delayed_work(codec->bus->workq,
+						   &codec->jackpoll_work, codec->jackpoll_interval);
+	}
+
+	/* disable controller Wake Up event*/
+	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
+			~STATESTS_INT_MASK);
+
 	return 0;
 }
 
@@ -3831,11 +3855,13 @@
 
 	/* Request power well for Haswell HDA controller and codec */
 	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+#ifdef CONFIG_SND_HDA_I915
 		err = hda_i915_init();
 		if (err < 0) {
 			snd_printk(KERN_ERR SFX "Error request power-well from i915\n");
 			goto out_free;
 		}
+#endif
 		hda_display_power(true);
 	}
 
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 3fd2973..05b3e3e 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -194,18 +194,24 @@
 EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
 
 /**
- * snd_hda_jack_detect - query pin Presence Detect status
+ * snd_hda_jack_detect_state - query pin Presence Detect status
  * @codec: the CODEC to sense
  * @nid: the pin NID to sense
  *
- * Query and return the pin's Presence Detect status.
+ * Query and return the pin's Presence Detect status, as either
+ * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM.
  */
-int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
+int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
 {
-	u32 sense = snd_hda_pin_sense(codec, nid);
-	return get_jack_plug_state(sense);
+	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
+	if (jack && jack->phantom_jack)
+		return HDA_JACK_PHANTOM;
+	else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE)
+		return HDA_JACK_PRESENT;
+	else
+		return HDA_JACK_NOT_PRESENT;
 }
-EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
+EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state);
 
 /**
  * snd_hda_jack_detect_enable - enable the jack-detection
@@ -247,8 +253,8 @@
 int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
 				 hda_nid_t gating_nid)
 {
-	struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid);
-	struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid);
+	struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid);
+	struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid);
 
 	if (!gated || !gating)
 		return -EINVAL;
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index ec12abd..379420c 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -75,7 +75,18 @@
 				 hda_nid_t gating_nid);
 
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
-int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
+
+/* the jack state returned from snd_hda_jack_detect_state() */
+enum {
+	HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM,
+};
+
+int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
+
+static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
+{
+	return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
+}
 
 bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
 
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 9760f00..a8cb22e 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -582,6 +582,36 @@
 	print_nid_array(buffer, codec, nid, &codec->nids);
 }
 
+static void print_device_list(struct snd_info_buffer *buffer,
+			    struct hda_codec *codec, hda_nid_t nid)
+{
+	int i, curr = -1;
+	u8 dev_list[AC_MAX_DEV_LIST_LEN];
+	int devlist_len;
+
+	devlist_len = snd_hda_get_devices(codec, nid, dev_list,
+					AC_MAX_DEV_LIST_LEN);
+	snd_iprintf(buffer, "  Devices: %d\n", devlist_len);
+	if (devlist_len <= 0)
+		return;
+
+	curr = snd_hda_codec_read(codec, nid, 0,
+				AC_VERB_GET_DEVICE_SEL, 0);
+
+	for (i = 0; i < devlist_len; i++) {
+		if (i == curr)
+			snd_iprintf(buffer, "    *");
+		else
+			snd_iprintf(buffer, "     ");
+
+		snd_iprintf(buffer,
+			"Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i,
+			!!(dev_list[i] & AC_DE_PD),
+			!!(dev_list[i] & AC_DE_ELDV),
+			!!(dev_list[i] & AC_DE_IA));
+	}
+}
+
 static void print_codec_info(struct snd_info_entry *entry,
 			     struct snd_info_buffer *buffer)
 {
@@ -751,6 +781,9 @@
 				    (wid_caps & AC_WCAP_DELAY) >>
 				    AC_WCAP_DELAY_SHIFT);
 
+		if (wid_type == AC_WID_PIN && codec->dp_mst)
+			print_device_list(buffer, codec, nid);
+
 		if (wid_caps & AC_WCAP_CONN_LIST)
 			print_conn_list(buffer, codec, nid, wid_type,
 					conn, conn_len);
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index d97f0d6..0cbdd87 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -32,7 +32,6 @@
 #include "hda_jack.h"
 #include "hda_generic.h"
 
-#define ENABLE_AD_STATIC_QUIRKS
 
 struct ad198x_spec {
 	struct hda_gen_spec gen;
@@ -43,114 +42,8 @@
 	hda_nid_t eapd_nid;
 
 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-	const struct snd_kcontrol_new *mixers[6];
-	int num_mixers;
-	const struct hda_verb *init_verbs[6];	/* initialization verbs
-						 * don't forget NULL termination!
-						 */
-	unsigned int num_init_verbs;
-
-	/* playback */
-	struct hda_multi_out multiout;	/* playback set-up
-					 * max_channels, dacs must be set
-					 * dig_out_nid and hp_nid are optional
-					 */
-	unsigned int cur_eapd;
-	unsigned int need_dac_fix;
-
-	/* capture */
-	unsigned int num_adc_nids;
-	const hda_nid_t *adc_nids;
-	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
-
-	/* capture source */
-	const struct hda_input_mux *input_mux;
-	const hda_nid_t *capsrc_nids;
-	unsigned int cur_mux[3];
-
-	/* channel model */
-	const struct hda_channel_mode *channel_mode;
-	int num_channel_mode;
-
-	/* PCM information */
-	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
-
-	unsigned int spdif_route;
-
-	unsigned int jack_present: 1;
-	unsigned int inv_jack_detect: 1;/* inverted jack-detection */
-	unsigned int analog_beep: 1;	/* analog beep input present */
-	unsigned int avoid_init_slave_vol:1;
-
-#ifdef CONFIG_PM
-	struct hda_loopback_check loopback;
-#endif
-	/* for virtual master */
-	hda_nid_t vmaster_nid;
-	const char * const *slave_vols;
-	const char * const *slave_sws;
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 };
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-/*
- * input MUX handling (common part)
- */
-static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-
-	return snd_hda_input_mux_info(spec->input_mux, uinfo);
-}
-
-static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
-	return 0;
-}
-
-static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
-				     spec->capsrc_nids[adc_idx],
-				     &spec->cur_mux[adc_idx]);
-}
-
-/*
- * initialization (common callbacks)
- */
-static int ad198x_init(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-	int i;
-
-	for (i = 0; i < spec->num_init_verbs; i++)
-		snd_hda_sequence_write(codec, spec->init_verbs[i]);
-	return 0;
-}
-
-static const char * const ad_slave_pfxs[] = {
-	"Front", "Surround", "Center", "LFE", "Side",
-	"Headphone", "Mono", "Speaker", "IEC958",
-	NULL
-};
-
-static const char * const ad1988_6stack_fp_slave_pfxs[] = {
-	"Front", "Surround", "Center", "LFE", "Side", "IEC958",
-	NULL
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
 /* additional beep mixers; the actual parameters are overwritten at build */
@@ -160,12 +53,6 @@
 	{ } /* end */
 };
 
-static const struct snd_kcontrol_new ad_beep2_mixer[] = {
-	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
-	{ } /* end */
-};
-
 #define set_beep_amp(spec, nid, idx, dir) \
 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
 #else
@@ -181,8 +68,7 @@
 	if (!spec->beep_amp)
 		return 0;
 
-	knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
-	for ( ; knew->name; knew++) {
+	for (knew = ad_beep_mixer ; knew->name; knew++) {
 		int err;
 		struct snd_kcontrol *kctl;
 		kctl = snd_ctl_new1(knew, codec);
@@ -199,268 +85,6 @@
 #define create_beep_ctls(codec)		0
 #endif
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int ad198x_build_controls(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-	struct snd_kcontrol *kctl;
-	unsigned int i;
-	int err;
-
-	for (i = 0; i < spec->num_mixers; i++) {
-		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
-		if (err < 0)
-			return err;
-	}
-	if (spec->multiout.dig_out_nid) {
-		err = snd_hda_create_spdif_out_ctls(codec,
-						    spec->multiout.dig_out_nid,
-						    spec->multiout.dig_out_nid);
-		if (err < 0)
-			return err;
-		err = snd_hda_create_spdif_share_sw(codec,
-						    &spec->multiout);
-		if (err < 0)
-			return err;
-		spec->multiout.share_spdif = 1;
-	} 
-	if (spec->dig_in_nid) {
-		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
-		if (err < 0)
-			return err;
-	}
-
-	/* create beep controls if needed */
-	err = create_beep_ctls(codec);
-	if (err < 0)
-		return err;
-
-	/* if we have no master control, let's create it */
-	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
-		unsigned int vmaster_tlv[4];
-		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-					HDA_OUTPUT, vmaster_tlv);
-		err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
-					  vmaster_tlv,
-					  (spec->slave_vols ?
-					   spec->slave_vols : ad_slave_pfxs),
-					  "Playback Volume",
-					  !spec->avoid_init_slave_vol, NULL);
-		if (err < 0)
-			return err;
-	}
-	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
-					  NULL,
-					  (spec->slave_sws ?
-					   spec->slave_sws : ad_slave_pfxs),
-					  "Playback Switch");
-		if (err < 0)
-			return err;
-	}
-
-	/* assign Capture Source enums to NID */
-	kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
-	if (!kctl)
-		kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
-	for (i = 0; kctl && i < kctl->count; i++) {
-		err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
-		if (err < 0)
-			return err;
-	}
-
-	/* assign IEC958 enums to NID */
-	kctl = snd_hda_find_mixer_ctl(codec,
-			SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
-	if (kctl) {
-		err = snd_hda_add_nid(codec, kctl, 0,
-				      spec->multiout.dig_out_nid);
-		if (err < 0)
-			return err;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
-}
-#endif
-
-/*
- * Analog playback callbacks
- */
-static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
-				    struct hda_codec *codec,
-				    struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
-					     hinfo);
-}
-
-static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-				       struct hda_codec *codec,
-				       unsigned int stream_tag,
-				       unsigned int format,
-				       struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
-						format, substream);
-}
-
-static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-				       struct hda_codec *codec,
-				       struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Digital out
- */
-static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-					struct hda_codec *codec,
-					struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-					 struct hda_codec *codec,
-					 struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-					   struct hda_codec *codec,
-					   unsigned int stream_tag,
-					   unsigned int format,
-					   struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-					     format, substream);
-}
-
-static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-					   struct hda_codec *codec,
-					   struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-/*
- * Analog capture
- */
-static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-				      struct hda_codec *codec,
-				      unsigned int stream_tag,
-				      unsigned int format,
-				      struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
-				   stream_tag, 0, format);
-	return 0;
-}
-
-static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-				      struct hda_codec *codec,
-				      struct snd_pcm_substream *substream)
-{
-	struct ad198x_spec *spec = codec->spec;
-	snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
-	return 0;
-}
-
-/*
- */
-static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 6, /* changed later */
-	.nid = 0, /* fill later */
-	.ops = {
-		.open = ad198x_playback_pcm_open,
-		.prepare = ad198x_playback_pcm_prepare,
-		.cleanup = ad198x_playback_pcm_cleanup,
-	},
-};
-
-static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	.nid = 0, /* fill later */
-	.ops = {
-		.prepare = ad198x_capture_pcm_prepare,
-		.cleanup = ad198x_capture_pcm_cleanup
-	},
-};
-
-static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	.nid = 0, /* fill later */
-	.ops = {
-		.open = ad198x_dig_playback_pcm_open,
-		.close = ad198x_dig_playback_pcm_close,
-		.prepare = ad198x_dig_playback_pcm_prepare,
-		.cleanup = ad198x_dig_playback_pcm_cleanup
-	},
-};
-
-static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
-	.substreams = 1,
-	.channels_min = 2,
-	.channels_max = 2,
-	/* NID is set in alc_build_pcms */
-};
-
-static int ad198x_build_pcms(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-	struct hda_pcm *info = spec->pcm_rec;
-
-	codec->num_pcms = 1;
-	codec->pcm_info = info;
-
-	info->name = "AD198x Analog";
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
-	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
-
-	if (spec->multiout.dig_out_nid) {
-		info++;
-		codec->num_pcms++;
-		codec->spdif_status_reset = 1;
-		info->name = "AD198x Digital";
-		info->pcm_type = HDA_PCM_TYPE_SPDIF;
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
-		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
-		if (spec->dig_in_nid) {
-			info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
-			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
-		}
-	}
-
-	return 0;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
 				hda_nid_t hp)
@@ -507,18 +131,6 @@
 	ad198x_power_eapd(codec);
 }
 
-static void ad198x_free(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-
-	if (!spec)
-		return;
-
-	snd_hda_gen_spec_free(&spec->gen);
-	kfree(spec);
-	snd_hda_detach_beep_device(codec);
-}
-
 #ifdef CONFIG_PM
 static int ad198x_suspend(struct hda_codec *codec)
 {
@@ -527,65 +139,6 @@
 }
 #endif
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const struct hda_codec_ops ad198x_patch_ops = {
-	.build_controls = ad198x_build_controls,
-	.build_pcms = ad198x_build_pcms,
-	.init = ad198x_init,
-	.free = ad198x_free,
-#ifdef CONFIG_PM
-	.check_power_status = ad198x_check_power_status,
-	.suspend = ad198x_suspend,
-#endif
-	.reboot_notify = ad198x_shutup,
-};
-
-
-/*
- * EAPD control
- * the private value = nid
- */
-#define ad198x_eapd_info	snd_ctl_boolean_mono_info
-
-static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-	if (codec->inv_eapd)
-		ucontrol->value.integer.value[0] = ! spec->cur_eapd;
-	else
-		ucontrol->value.integer.value[0] = spec->cur_eapd;
-	return 0;
-}
-
-static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-	hda_nid_t nid = kcontrol->private_value & 0xff;
-	unsigned int eapd;
-	eapd = !!ucontrol->value.integer.value[0];
-	if (codec->inv_eapd)
-		eapd = !eapd;
-	if (eapd == spec->cur_eapd)
-		return 0;
-	spec->cur_eapd = eapd;
-	snd_hda_codec_write_cache(codec, nid,
-				  0, AC_VERB_SET_EAPD_BTLENABLE,
-				  eapd ? 0x02 : 0x00);
-	return 1;
-}
-
-static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_info *uinfo);
-static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol);
-static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
-			      struct snd_ctl_elem_value *ucontrol);
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * Automatic parse of I/O pins from the BIOS configuration
@@ -646,537 +199,6 @@
  * AD1986A specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1986A_SPDIF_OUT	0x02
-#define AD1986A_FRONT_DAC	0x03
-#define AD1986A_SURR_DAC	0x04
-#define AD1986A_CLFE_DAC	0x05
-#define AD1986A_ADC		0x06
-
-static const hda_nid_t ad1986a_dac_nids[3] = {
-	AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
-};
-static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
-static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
-
-static const struct hda_input_mux ad1986a_capture_source = {
-	.num_items = 7,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "CD", 0x1 },
-		{ "Aux", 0x3 },
-		{ "Line", 0x4 },
-		{ "Mix", 0x5 },
-		{ "Mono", 0x6 },
-		{ "Phone", 0x7 },
-	},
-};
-
-
-static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
-	.ops = &snd_hda_bind_vol,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
-		0
-	},
-};
-
-static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
-	.ops = &snd_hda_bind_sw,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
-		0
-	},
-};
-
-/*
- * mixers
- */
-static const struct snd_kcontrol_new ad1986a_mixers[] = {
-	/*
-	 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
-	 */
-	HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
-	HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-/* additional mixers for 3stack mode */
-static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = ad198x_ch_mode_info,
-		.get = ad198x_ch_mode_get,
-		.put = ad198x_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-/* laptop model - 2ch only */
-static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
-
-/* master controls both pins 0x1a and 0x1b */
-static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
-	.ops = &snd_hda_bind_vol,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-		0,
-	},
-};
-
-static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
-	.ops = &snd_hda_bind_sw,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
-		0,
-	},
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-	/* 
-	   HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
-	   HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
-	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-/* laptop-eapd model - 2ch only */
-
-static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Internal Mic", 0x4 },
-		{ "Mix", 0x5 },
-	},
-};
-
-static const struct hda_input_mux ad1986a_automic_capture_source = {
-	.num_items = 2,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Mix", 0x5 },
-	},
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
-	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-	HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "External Amplifier",
-		.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-		.info = ad198x_eapd_info,
-		.get = ad198x_eapd_get,
-		.put = ad198x_eapd_put,
-		.private_value = 0x1b, /* port-D */
-	},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-/* re-connect the mic boost input according to the jack sensing */
-static void ad1986a_automic(struct hda_codec *codec)
-{
-	unsigned int present;
-	present = snd_hda_jack_detect(codec, 0x1f);
-	/* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
-	snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
-			    present ? 0 : 2);
-}
-
-#define AD1986A_MIC_EVENT		0x36
-
-static void ad1986a_automic_unsol_event(struct hda_codec *codec,
-					    unsigned int res)
-{
-	if ((res >> 26) != AD1986A_MIC_EVENT)
-		return;
-	ad1986a_automic(codec);
-}
-
-static int ad1986a_automic_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1986a_automic(codec);
-	return 0;
-}
-
-/* laptop-automute - 2ch only */
-
-static void ad1986a_update_hp(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-	unsigned int mute;
-
-	if (spec->jack_present)
-		mute = HDA_AMP_MUTE; /* mute internal speaker */
-	else
-		/* unmute internal speaker if necessary */
-		mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
-	snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, mute);
-}
-
-static void ad1986a_hp_automute(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-
-	spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
-	if (spec->inv_jack_detect)
-		spec->jack_present = !spec->jack_present;
-	ad1986a_update_hp(codec);
-}
-
-#define AD1986A_HP_EVENT		0x37
-
-static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) != AD1986A_HP_EVENT)
-		return;
-	ad1986a_hp_automute(codec);
-}
-
-static int ad1986a_hp_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1986a_hp_automute(codec);
-	return 0;
-}
-
-/* bind hp and internal speaker mute (with plug check) */
-static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-				    struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-	if (change)
-		ad1986a_update_hp(codec);
-	return change;
-}
-
-static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
-	HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = ad1986a_hp_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
-	},
-	{ } /* end */
-};
-
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1986a_init_verbs[] = {
-	/* Front, Surround, CLFE DAC; mute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* Downmix - off */
-	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* HP, Line-Out, Surround, CLFE selectors */
-	{0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Mono selector */
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Mic selector: Mic 1/2 pin */
-	{0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Line-in selector: Line-in */
-	{0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Mic 1/2 swap */
-	{0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Record selector: mic */
-	{0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Mic, Phone, CD, Aux, Line-In amp; mute as default */
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* PC beep */
-	{0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* HP Pin */
-	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-	/* Front, Surround, CLFE Pins */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	/* Mono Pin */
-	{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	/* Mic Pin */
-	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-	/* Line, Aux, CD, Beep-In Pin */
-	{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	{ } /* end */
-};
-
-static const struct hda_verb ad1986a_ch2_init[] = {
-	/* Surround out -> Line In */
-	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
- 	/* Line-in selectors */
-	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
-	/* CLFE -> Mic in */
-	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-	/* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
-	{ } /* end */
-};
-
-static const struct hda_verb ad1986a_ch4_init[] = {
-	/* Surround out -> Surround */
-	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
-	/* CLFE -> Mic in */
-	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
-	{ } /* end */
-};
-
-static const struct hda_verb ad1986a_ch6_init[] = {
-	/* Surround out -> Surround out */
-	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
-	/* CLFE -> CLFE */
-	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
-	{ } /* end */
-};
-
-static const struct hda_channel_mode ad1986a_modes[3] = {
-	{ 2, ad1986a_ch2_init },
-	{ 4, ad1986a_ch4_init },
-	{ 6, ad1986a_ch6_init },
-};
-
-/* eapd initialization */
-static const struct hda_verb ad1986a_eapd_init_verbs[] = {
-	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
-	{}
-};
-
-static const struct hda_verb ad1986a_automic_verbs[] = {
-	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	/*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
-	{0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
-	{}
-};
-
-/* Ultra initialization */
-static const struct hda_verb ad1986a_ultra_init[] = {
-	/* eapd initialization */
-	{ 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
-	/* CLFE -> Mic in */
-	{ 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
-	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-	{ 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
-	{ } /* end */
-};
-
-/* pin sensing on HP jack */
-static const struct hda_verb ad1986a_hp_init_verbs[] = {
-	{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
-	{}
-};
-
-static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
-					    unsigned int res)
-{
-	switch (res >> 26) {
-	case AD1986A_HP_EVENT:
-		ad1986a_hp_automute(codec);
-		break;
-	case AD1986A_MIC_EVENT:
-		ad1986a_automic(codec);
-		break;
-	}
-}
-
-static int ad1986a_samsung_p50_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1986a_hp_automute(codec);
-	ad1986a_automic(codec);
-	return 0;
-}
-
-
-/* models */
-enum {
-	AD1986A_AUTO,
-	AD1986A_6STACK,
-	AD1986A_3STACK,
-	AD1986A_LAPTOP,
-	AD1986A_LAPTOP_EAPD,
-	AD1986A_LAPTOP_AUTOMUTE,
-	AD1986A_ULTRA,
-	AD1986A_SAMSUNG,
-	AD1986A_SAMSUNG_P50,
-	AD1986A_MODELS
-};
-
-static const char * const ad1986a_models[AD1986A_MODELS] = {
-	[AD1986A_AUTO]		= "auto",
-	[AD1986A_6STACK]	= "6stack",
-	[AD1986A_3STACK]	= "3stack",
-	[AD1986A_LAPTOP]	= "laptop",
-	[AD1986A_LAPTOP_EAPD]	= "laptop-eapd",
-	[AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
-	[AD1986A_ULTRA]		= "ultra",
-	[AD1986A_SAMSUNG]	= "samsung",
-	[AD1986A_SAMSUNG_P50]	= "samsung-p50",
-};
-
-static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
-	SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
-	SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
-	SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
-	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
-	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
-	SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
-	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
-	SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
-	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
-	SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
-	{}
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1986a_loopbacks[] = {
-	{ 0x13, HDA_OUTPUT, 0 }, /* Mic */
-	{ 0x14, HDA_OUTPUT, 0 }, /* Phone */
-	{ 0x15, HDA_OUTPUT, 0 }, /* CD */
-	{ 0x16, HDA_OUTPUT, 0 }, /* Aux */
-	{ 0x17, HDA_OUTPUT, 0 }, /* Line */
-	{ } /* end */
-};
-#endif
-
-static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
-{
-	unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
-	return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 static int alloc_ad_spec(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
@@ -1203,6 +225,11 @@
 
 enum {
 	AD1986A_FIXUP_INV_JACK_DETECT,
+	AD1986A_FIXUP_ULTRA,
+	AD1986A_FIXUP_SAMSUNG,
+	AD1986A_FIXUP_3STACK,
+	AD1986A_FIXUP_LAPTOP,
+	AD1986A_FIXUP_LAPTOP_IMIC,
 };
 
 static const struct hda_fixup ad1986a_fixups[] = {
@@ -1210,16 +237,86 @@
 		.type = HDA_FIXUP_FUNC,
 		.v.func = ad_fixup_inv_jack_detect,
 	},
+	[AD1986A_FIXUP_ULTRA] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x90170110 }, /* speaker */
+			{ 0x1d, 0x90a7013e }, /* int mic */
+			{}
+		},
+	},
+	[AD1986A_FIXUP_SAMSUNG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1b, 0x90170110 }, /* speaker */
+			{ 0x1d, 0x90a7013e }, /* int mic */
+			{ 0x20, 0x411111f0 }, /* N/A */
+			{ 0x24, 0x411111f0 }, /* N/A */
+			{}
+		},
+	},
+	[AD1986A_FIXUP_3STACK] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x02214021 }, /* headphone */
+			{ 0x1b, 0x01014011 }, /* front */
+			{ 0x1c, 0x01013012 }, /* surround */
+			{ 0x1d, 0x01019015 }, /* clfe */
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ 0x1f, 0x02a190f0 }, /* mic */
+			{ 0x20, 0x018130f0 }, /* line-in */
+			{}
+		},
+	},
+	[AD1986A_FIXUP_LAPTOP] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1a, 0x02214021 }, /* headphone */
+			{ 0x1b, 0x90170110 }, /* speaker */
+			{ 0x1c, 0x411111f0 }, /* N/A */
+			{ 0x1d, 0x411111f0 }, /* N/A */
+			{ 0x1e, 0x411111f0 }, /* N/A */
+			{ 0x1f, 0x02a191f0 }, /* mic */
+			{ 0x20, 0x411111f0 }, /* N/A */
+			{}
+		},
+	},
+	[AD1986A_FIXUP_LAPTOP_IMIC] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x1d, 0x90a7013e }, /* int mic */
+			{}
+		},
+		.chained_before = 1,
+		.chain_id = AD1986A_FIXUP_LAPTOP,
+	},
 };
 
 static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+	SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
+	SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
+	SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
+	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
+	SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
+	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
 	SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
+	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
+	SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
+	{}
+};
+
+static const struct hda_model_fixup ad1986a_fixup_models[] = {
+	{ .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
+	{ .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
+	{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
+	{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
 	{}
 };
 
 /*
  */
-static int ad1986a_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1986a(struct hda_codec *codec)
 {
 	int err;
 	struct ad198x_spec *spec;
@@ -1244,7 +341,8 @@
 	 */
 	spec->gen.multiout.no_share_stream = 1;
 
-	snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups);
+	snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
+			   ad1986a_fixups);
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
 	err = ad198x_parse_auto_config(codec);
@@ -1258,330 +356,11 @@
 	return 0;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1986a(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int err, board_config;
-
-	board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
-						  ad1986a_models,
-						  ad1986a_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1986A_AUTO;
-	}
-
-	if (board_config == AD1986A_AUTO)
-		return ad1986a_parse_auto_config(codec);
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	err = snd_hda_attach_beep_device(codec, 0x19);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
-
-	spec->multiout.max_channels = 6;
-	spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
-	spec->multiout.dac_nids = ad1986a_dac_nids;
-	spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
-	spec->num_adc_nids = 1;
-	spec->adc_nids = ad1986a_adc_nids;
-	spec->capsrc_nids = ad1986a_capsrc_nids;
-	spec->input_mux = &ad1986a_capture_source;
-	spec->num_mixers = 1;
-	spec->mixers[0] = ad1986a_mixers;
-	spec->num_init_verbs = 1;
-	spec->init_verbs[0] = ad1986a_init_verbs;
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1986a_loopbacks;
-#endif
-	spec->vmaster_nid = 0x1b;
-	codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
-
-	codec->patch_ops = ad198x_patch_ops;
-
-	/* override some parameters */
-	switch (board_config) {
-	case AD1986A_3STACK:
-		spec->num_mixers = 2;
-		spec->mixers[1] = ad1986a_3st_mixers;
-		spec->num_init_verbs = 2;
-		spec->init_verbs[1] = ad1986a_ch2_init;
-		spec->channel_mode = ad1986a_modes;
-		spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
-		spec->need_dac_fix = 1;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		break;
-	case AD1986A_LAPTOP:
-		spec->mixers[0] = ad1986a_laptop_mixers;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		break;
-	case AD1986A_LAPTOP_EAPD:
-		spec->num_mixers = 3;
-		spec->mixers[0] = ad1986a_laptop_master_mixers;
-		spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-		spec->mixers[2] = ad1986a_laptop_intmic_mixers;
-		spec->num_init_verbs = 2;
-		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		if (!is_jack_available(codec, 0x25))
-			spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
-		break;
-	case AD1986A_SAMSUNG:
-		spec->num_mixers = 2;
-		spec->mixers[0] = ad1986a_laptop_master_mixers;
-		spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-		spec->num_init_verbs = 3;
-		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-		spec->init_verbs[2] = ad1986a_automic_verbs;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		if (!is_jack_available(codec, 0x25))
-			spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1986a_automic_capture_source;
-		codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
-		codec->patch_ops.init = ad1986a_automic_init;
-		break;
-	case AD1986A_SAMSUNG_P50:
-		spec->num_mixers = 2;
-		spec->mixers[0] = ad1986a_automute_master_mixers;
-		spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-		spec->num_init_verbs = 4;
-		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-		spec->init_verbs[2] = ad1986a_automic_verbs;
-		spec->init_verbs[3] = ad1986a_hp_init_verbs;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		if (!is_jack_available(codec, 0x25))
-			spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1986a_automic_capture_source;
-		codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
-		codec->patch_ops.init = ad1986a_samsung_p50_init;
-		break;
-	case AD1986A_LAPTOP_AUTOMUTE:
-		spec->num_mixers = 3;
-		spec->mixers[0] = ad1986a_automute_master_mixers;
-		spec->mixers[1] = ad1986a_laptop_eapd_mixers;
-		spec->mixers[2] = ad1986a_laptop_intmic_mixers;
-		spec->num_init_verbs = 3;
-		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
-		spec->init_verbs[2] = ad1986a_hp_init_verbs;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		if (!is_jack_available(codec, 0x25))
-			spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
-		codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
-		codec->patch_ops.init = ad1986a_hp_init;
-		/* Lenovo N100 seems to report the reversed bit
-		 * for HP jack-sensing
-		 */
-		spec->inv_jack_detect = 1;
-		break;
-	case AD1986A_ULTRA:
-		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
-		spec->num_init_verbs = 2;
-		spec->init_verbs[1] = ad1986a_ultra_init;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
-		spec->multiout.dig_out_nid = 0;
-		break;
-	}
-
-	/* AD1986A has a hardware problem that it can't share a stream
-	 * with multiple output pins.  The copy of front to surrounds
-	 * causes noisy or silent outputs at a certain timing, e.g.
-	 * changing the volume.
-	 * So, let's disable the shared stream.
-	 */
-	spec->multiout.no_share_stream = 1;
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1986a	ad1986a_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
 
 /*
  * AD1983 specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1983_SPDIF_OUT	0x02
-#define AD1983_DAC		0x03
-#define AD1983_ADC		0x04
-
-static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
-static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
-static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
-
-static const struct hda_input_mux ad1983_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Line", 0x1 },
-		{ "Mix", 0x2 },
-		{ "Mix Mono", 0x3 },
-	},
-};
-
-/*
- * SPDIF playback route
- */
-static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-	static const char * const texts[] = { "PCM", "ADC" };
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 2;
-	if (uinfo->value.enumerated.item > 1)
-		uinfo->value.enumerated.item = 1;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-
-	ucontrol->value.enumerated.item[0] = spec->spdif_route;
-	return 0;
-}
-
-static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-
-	if (ucontrol->value.enumerated.item[0] > 1)
-		return -EINVAL;
-	if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
-		spec->spdif_route = ucontrol->value.enumerated.item[0];
-		snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
-					  AC_VERB_SET_CONNECT_SEL,
-					  spec->spdif_route);
-		return 1;
-	}
-	return 0;
-}
-
-static const struct snd_kcontrol_new ad1983_mixers[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_verb ad1983_init_verbs[] = {
-	/* Front, HP, Mono; mute as default */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* Beep, PCM, Mic, Line-In: mute */
-	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* Front, HP selectors; from Mix */
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* Mono selector; from Mix */
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
-	/* Mic selector; Mic */
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Line-in selector: Line-in */
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Mic boost: 0dB */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-	/* Record selector: mic */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* SPDIF route: PCM */
-	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Front Pin */
-	{0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	/* HP Pin */
-	{0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-	/* Mono Pin */
-	{0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	/* Mic Pin */
-	{0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-	/* Line Pin */
-	{0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	{ } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1983_loopbacks[] = {
-	{ 0x12, HDA_OUTPUT, 0 }, /* Mic */
-	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
-	{ } /* end */
-};
-#endif
-
-/* models */
-enum {
-	AD1983_AUTO,
-	AD1983_BASIC,
-	AD1983_MODELS
-};
-
-static const char * const ad1983_models[AD1983_MODELS] = {
-	[AD1983_AUTO]		= "auto",
-	[AD1983_BASIC]		= "basic",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /*
  * SPDIF mux control for AD1983 auto-parser
  */
@@ -1656,7 +435,7 @@
 	return 0;
 }
 
-static int ad1983_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1983(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
 	int err;
@@ -1681,432 +460,11 @@
 	return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1983(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int board_config;
-	int err;
-
-	board_config = snd_hda_check_board_config(codec, AD1983_MODELS,
-						  ad1983_models, NULL);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1983_AUTO;
-	}
-
-	if (board_config == AD1983_AUTO)
-		return ad1983_parse_auto_config(codec);
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	err = snd_hda_attach_beep_device(codec, 0x10);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-	spec->multiout.max_channels = 2;
-	spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
-	spec->multiout.dac_nids = ad1983_dac_nids;
-	spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
-	spec->num_adc_nids = 1;
-	spec->adc_nids = ad1983_adc_nids;
-	spec->capsrc_nids = ad1983_capsrc_nids;
-	spec->input_mux = &ad1983_capture_source;
-	spec->num_mixers = 1;
-	spec->mixers[0] = ad1983_mixers;
-	spec->num_init_verbs = 1;
-	spec->init_verbs[0] = ad1983_init_verbs;
-	spec->spdif_route = 0;
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1983_loopbacks;
-#endif
-	spec->vmaster_nid = 0x05;
-
-	codec->patch_ops = ad198x_patch_ops;
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1983	ad1983_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1981 HD specific
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-#define AD1981_SPDIF_OUT	0x02
-#define AD1981_DAC		0x03
-#define AD1981_ADC		0x04
-
-static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
-static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
-static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
-
-/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
-static const struct hda_input_mux ad1981_capture_source = {
-	.num_items = 7,
-	.items = {
-		{ "Front Mic", 0x0 },
-		{ "Line", 0x1 },
-		{ "Mix", 0x2 },
-		{ "Mix Mono", 0x3 },
-		{ "CD", 0x4 },
-		{ "Mic", 0x6 },
-		{ "Aux", 0x7 },
-	},
-};
-
-static const struct snd_kcontrol_new ad1981_mixers[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	/* identical with AD1983 */
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_verb ad1981_init_verbs[] = {
-	/* Front, HP, Mono; mute as default */
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* Front, HP selectors; from Mix */
-	{0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
-	{0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
-	/* Mono selector; from Mix */
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
-	/* Mic Mixer; select Front Mic */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* Mic boost: 0dB */
-	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* Record selector: Front mic */
-	{0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	/* SPDIF route: PCM */
-	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Front Pin */
-	{0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	/* HP Pin */
-	{0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-	/* Mono Pin */
-	{0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
-	/* Front & Rear Mic Pins */
-	{0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-	/* Line Pin */
-	{0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-	/* Digital Beep */
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
-	/* Line-Out as Input: disabled */
-	{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-	{ } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1981_loopbacks[] = {
-	{ 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
-	{ 0x13, HDA_OUTPUT, 0 }, /* Line */
-	{ 0x1b, HDA_OUTPUT, 0 }, /* Aux */
-	{ 0x1c, HDA_OUTPUT, 0 }, /* Mic */
-	{ 0x1d, HDA_OUTPUT, 0 }, /* CD */
-	{ } /* end */
-};
-#endif
-
-/*
- * Patch for HP nx6320
- *
- * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
- * speaker output enabled _and_ mute-LED off.
- */
-
-#define AD1981_HP_EVENT		0x37
-#define AD1981_MIC_EVENT	0x38
-
-static const struct hda_verb ad1981_hp_init_verbs[] = {
-	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
-	/* pin sensing on HP and Mic jacks */
-	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
-	{0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
-	{}
-};
-
-/* turn on/off EAPD (+ mute HP) as a master switch */
-static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
-				   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-
-	if (! ad198x_eapd_put(kcontrol, ucontrol))
-		return 0;
-	/* change speaker pin appropriately */
-	snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
-	/* toggle HP mute appropriately */
-	snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE,
-				 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
-	return 1;
-}
-
-/* bind volumes of both NID 0x05 and 0x06 */
-static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
-	.ops = &snd_hda_bind_vol,
-	.values = {
-		HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
-		HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
-		0
-	},
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1981_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x06);
-	snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* toggle input of built-in and mic jack appropriately */
-static void ad1981_hp_automic(struct hda_codec *codec)
-{
-	static const struct hda_verb mic_jack_on[] = {
-		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-		{}
-	};
-	static const struct hda_verb mic_jack_off[] = {
-		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
-		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-		{}
-	};
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x08);
-	if (present)
-		snd_hda_sequence_write(codec, mic_jack_on);
-	else
-		snd_hda_sequence_write(codec, mic_jack_off);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1981_hp_unsol_event(struct hda_codec *codec,
-				  unsigned int res)
-{
-	res >>= 26;
-	switch (res) {
-	case AD1981_HP_EVENT:
-		ad1981_hp_automute(codec);
-		break;
-	case AD1981_MIC_EVENT:
-		ad1981_hp_automic(codec);
-		break;
-	}
-}
-
-static const struct hda_input_mux ad1981_hp_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Dock Mic", 0x1 },
-		{ "Mix", 0x2 },
-	},
-};
-
-static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
-	HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
-		.name = "Master Playback Switch",
-		.info = ad198x_eapd_info,
-		.get = ad198x_eapd_get,
-		.put = ad1981_hp_master_sw_put,
-		.private_value = 0x05,
-	},
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-#if 0
-	/* FIXME: analog mic/line loopback doesn't work with my tests...
-	 *        (although recording is OK)
-	 */
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
-	/* FIXME: does this laptop have analog CD connection? */
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-#endif
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-/* initialize jack-sensing, too */
-static int ad1981_hp_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1981_hp_automute(codec);
-	ad1981_hp_automic(codec);
-	return 0;
-}
-
-/* configuration for Toshiba Laptops */
-static const struct hda_verb ad1981_toshiba_init_verbs[] = {
-	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
-	/* pin sensing on HP and Mic jacks */
-	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
-	{0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
-	{}
-};
-
-static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
-	HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
-	{ }
-};
-
-/* configuration for Lenovo Thinkpad T60 */
-static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	/* identical with AD1983 */
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_input_mux ad1981_thinkpad_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Mix", 0x2 },
-		{ "CD", 0x4 },
-	},
-};
-
-/* models */
-enum {
-	AD1981_AUTO,
-	AD1981_BASIC,
-	AD1981_HP,
-	AD1981_THINKPAD,
-	AD1981_TOSHIBA,
-	AD1981_MODELS
-};
-
-static const char * const ad1981_models[AD1981_MODELS] = {
-	[AD1981_AUTO]		= "auto",
-	[AD1981_HP]		= "hp",
-	[AD1981_THINKPAD]	= "thinkpad",
-	[AD1981_BASIC]		= "basic",
-	[AD1981_TOSHIBA]	= "toshiba"
-};
-
-static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
-	SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
-	/* All HP models */
-	SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
-	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
-	/* Lenovo Thinkpad T60/X60/Z6xx */
-	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
-	/* HP nx6320 (reversed SSID, H/W bug) */
-	SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
-	{}
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /* follow EAPD via vmaster hook */
 static void ad_vmaster_eapd_hook(void *private_data, int enabled)
 {
@@ -2172,7 +530,7 @@
 	{}
 };
 
-static int ad1981_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1981(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
 	int err;
@@ -2205,110 +563,6 @@
 	return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1981(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int err, board_config;
-
-	board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
-						  ad1981_models,
-						  ad1981_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1981_AUTO;
-	}
-
-	if (board_config == AD1981_AUTO)
-		return ad1981_parse_auto_config(codec);
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return -ENOMEM;
-	spec = codec->spec;
-
-	err = snd_hda_attach_beep_device(codec, 0x10);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
-
-	spec->multiout.max_channels = 2;
-	spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
-	spec->multiout.dac_nids = ad1981_dac_nids;
-	spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
-	spec->num_adc_nids = 1;
-	spec->adc_nids = ad1981_adc_nids;
-	spec->capsrc_nids = ad1981_capsrc_nids;
-	spec->input_mux = &ad1981_capture_source;
-	spec->num_mixers = 1;
-	spec->mixers[0] = ad1981_mixers;
-	spec->num_init_verbs = 1;
-	spec->init_verbs[0] = ad1981_init_verbs;
-	spec->spdif_route = 0;
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1981_loopbacks;
-#endif
-	spec->vmaster_nid = 0x05;
-
-	codec->patch_ops = ad198x_patch_ops;
-
-	/* override some parameters */
-	switch (board_config) {
-	case AD1981_HP:
-		spec->mixers[0] = ad1981_hp_mixers;
-		spec->num_init_verbs = 2;
-		spec->init_verbs[1] = ad1981_hp_init_verbs;
-		if (!is_jack_available(codec, 0x0a))
-			spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1981_hp_capture_source;
-
-		codec->patch_ops.init = ad1981_hp_init;
-		codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
-		/* set the upper-limit for mixer amp to 0dB for avoiding the
-		 * possible damage by overloading
-		 */
-		snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-					  (1 << AC_AMPCAP_MUTE_SHIFT));
-		break;
-	case AD1981_THINKPAD:
-		spec->mixers[0] = ad1981_thinkpad_mixers;
-		spec->input_mux = &ad1981_thinkpad_capture_source;
-		/* set the upper-limit for mixer amp to 0dB for avoiding the
-		 * possible damage by overloading
-		 */
-		snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-					  (1 << AC_AMPCAP_MUTE_SHIFT));
-		break;
-	case AD1981_TOSHIBA:
-		spec->mixers[0] = ad1981_hp_mixers;
-		spec->mixers[1] = ad1981_toshiba_mixers;
-		spec->num_init_verbs = 2;
-		spec->init_verbs[1] = ad1981_toshiba_init_verbs;
-		spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1981_hp_capture_source;
-		codec->patch_ops.init = ad1981_hp_init;
-		codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
-		break;
-	}
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1981	ad1981_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1988
@@ -2395,90 +649,7 @@
  *      E/F quad mic array
  */
 
-
 #ifdef ENABLE_AD_STATIC_QUIRKS
-/* models */
-enum {
-	AD1988_AUTO,
-	AD1988_6STACK,
-	AD1988_6STACK_DIG,
-	AD1988_3STACK,
-	AD1988_3STACK_DIG,
-	AD1988_LAPTOP,
-	AD1988_LAPTOP_DIG,
-	AD1988_MODEL_LAST,
-};
-
-/* reivision id to check workarounds */
-#define AD1988A_REV2		0x100200
-
-#define is_rev2(codec) \
-	((codec)->vendor_id == 0x11d41988 && \
-	 (codec)->revision_id == AD1988A_REV2)
-
-/*
- * mixers
- */
-
-static const hda_nid_t ad1988_6stack_dac_nids[4] = {
-	0x04, 0x06, 0x05, 0x0a
-};
-
-static const hda_nid_t ad1988_3stack_dac_nids[3] = {
-	0x04, 0x05, 0x0a
-};
-
-/* for AD1988A revision-2, DAC2-4 are swapped */
-static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
-	0x04, 0x05, 0x0a, 0x06
-};
-
-static const hda_nid_t ad1988_alt_dac_nid[1] = {
-	0x03
-};
-
-static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
-	0x04, 0x0a, 0x06
-};
-
-static const hda_nid_t ad1988_adc_nids[3] = {
-	0x08, 0x09, 0x0f
-};
-
-static const hda_nid_t ad1988_capsrc_nids[3] = {
-	0x0c, 0x0d, 0x0e
-};
-
-#define AD1988_SPDIF_OUT		0x02
-#define AD1988_SPDIF_OUT_HDMI	0x0b
-#define AD1988_SPDIF_IN		0x07
-
-static const hda_nid_t ad1989b_slave_dig_outs[] = {
-	AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
-};
-
-static const struct hda_input_mux ad1988_6stack_capture_source = {
-	.num_items = 5,
-	.items = {
-		{ "Front Mic", 0x1 },	/* port-B */
-		{ "Line", 0x2 },	/* port-C */
-		{ "Mic", 0x4 },		/* port-E */
-		{ "CD", 0x5 },
-		{ "Mix", 0x9 },
-	},
-};
-
-static const struct hda_input_mux ad1988_laptop_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic/Line", 0x1 },	/* port-B */
-		{ "CD", 0x5 },
-		{ "Mix", 0x9 },
-	},
-};
-
-/*
- */
 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_info *uinfo)
 {
@@ -2509,569 +680,6 @@
 		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
 	return err;
 }
-
-/* 6-stack mode */
-static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-/* 3-stack mode */
-static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
-	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
-	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = ad198x_ch_mode_info,
-		.get = ad198x_ch_mode_get,
-		.put = ad198x_ch_mode_put,
-	},
-
-	{ } /* end */
-};
-
-/* laptop mode */
-static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
-	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
-	HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
-
-	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "External Amplifier",
-		.subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
-		.info = ad198x_eapd_info,
-		.get = ad198x_eapd_get,
-		.put = ad198x_eapd_put,
-		.private_value = 0x12, /* port-D */
-	},
-
-	{ } /* end */
-};
-
-/* capture */
-static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 3,
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
-					     struct snd_ctl_elem_info *uinfo)
-{
-	static const char * const texts[] = {
-		"PCM", "ADC1", "ADC2", "ADC3"
-	};
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = 4;
-	if (uinfo->value.enumerated.item >= 4)
-		uinfo->value.enumerated.item = 3;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-
-static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
-					    struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	unsigned int sel;
-
-	sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
-				 AC_AMP_GET_INPUT);
-	if (!(sel & 0x80))
-		ucontrol->value.enumerated.item[0] = 0;
-	else {
-		sel = snd_hda_codec_read(codec, 0x0b, 0,
-					 AC_VERB_GET_CONNECT_SEL, 0);
-		if (sel < 3)
-			sel++;
-		else
-			sel = 0;
-		ucontrol->value.enumerated.item[0] = sel;
-	}
-	return 0;
-}
-
-static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
-					    struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	unsigned int val, sel;
-	int change;
-
-	val = ucontrol->value.enumerated.item[0];
-	if (val > 3)
-		return -EINVAL;
-	if (!val) {
-		sel = snd_hda_codec_read(codec, 0x1d, 0,
-					 AC_VERB_GET_AMP_GAIN_MUTE,
-					 AC_AMP_GET_INPUT);
-		change = sel & 0x80;
-		if (change) {
-			snd_hda_codec_write_cache(codec, 0x1d, 0,
-						  AC_VERB_SET_AMP_GAIN_MUTE,
-						  AMP_IN_UNMUTE(0));
-			snd_hda_codec_write_cache(codec, 0x1d, 0,
-						  AC_VERB_SET_AMP_GAIN_MUTE,
-						  AMP_IN_MUTE(1));
-		}
-	} else {
-		sel = snd_hda_codec_read(codec, 0x1d, 0,
-					 AC_VERB_GET_AMP_GAIN_MUTE,
-					 AC_AMP_GET_INPUT | 0x01);
-		change = sel & 0x80;
-		if (change) {
-			snd_hda_codec_write_cache(codec, 0x1d, 0,
-						  AC_VERB_SET_AMP_GAIN_MUTE,
-						  AMP_IN_MUTE(0));
-			snd_hda_codec_write_cache(codec, 0x1d, 0,
-						  AC_VERB_SET_AMP_GAIN_MUTE,
-						  AMP_IN_UNMUTE(1));
-		}
-		sel = snd_hda_codec_read(codec, 0x0b, 0,
-					 AC_VERB_GET_CONNECT_SEL, 0) + 1;
-		change |= sel != val;
-		if (change)
-			snd_hda_codec_write_cache(codec, 0x0b, 0,
-						  AC_VERB_SET_CONNECT_SEL,
-						  val - 1);
-	}
-	return change;
-}
-
-static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
-	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "IEC958 Playback Source",
-		.subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
-		.info = ad1988_spdif_playback_source_info,
-		.get = ad1988_spdif_playback_source_get,
-		.put = ad1988_spdif_playback_source_put,
-	},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
-	HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
-	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-/*
- * initialization verbs
- */
-
-/*
- * for 6-stack (+dig)
- */
-static const struct hda_verb ad1988_6stack_init_verbs[] = {
-	/* Front, Surround, CLFE, side DAC; unmute as default */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-A front headphon path */
-	{0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Port-D line-out path */
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Port-F surround path */
-	{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Port-G CLFE path */
-	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Port-H side path */
-	{0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Mono out path */
-	{0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-	/* Port-B front mic-in path */
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Port-C line-in path */
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Port-E mic-in path */
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Analog CD Input */
-	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-
-	{ }
-};
-
-static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
-	/* Headphone; unmute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-A front headphon path */
-	{0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-	{ }
-};
-
-static const struct hda_verb ad1988_capture_init_verbs[] = {
-	/* mute analog mix */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-	/* select ADCs - front-mic */
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-
-	{ }
-};
-
-static const struct hda_verb ad1988_spdif_init_verbs[] = {
-	/* SPDIF out sel */
-	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-	{0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* SPDIF out pin */
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-
-	{ }
-};
-
-static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
-	/* unmute SPDIF input pin */
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{ }
-};
-
-/* AD1989 has no ADC -> SPDIF route */
-static const struct hda_verb ad1989_spdif_init_verbs[] = {
-	/* SPDIF-1 out pin */
-	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-	/* SPDIF-2/HDMI out pin */
-	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-	{ }
-};
-
-/*
- * verbs for 3stack (+dig)
- */
-static const struct hda_verb ad1988_3stack_ch2_init[] = {
-	/* set port-C to line-in */
-	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
-	/* set port-E to mic-in */
-	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
-	{ } /* end */
-};
-
-static const struct hda_verb ad1988_3stack_ch6_init[] = {
-	/* set port-C to surround out */
-	{ 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	/* set port-E to CLFE out */
-	{ 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-	{ 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	{ } /* end */
-};
-
-static const struct hda_channel_mode ad1988_3stack_modes[2] = {
-	{ 2, ad1988_3stack_ch2_init },
-	{ 6, ad1988_3stack_ch6_init },
-};
-
-static const struct hda_verb ad1988_3stack_init_verbs[] = {
-	/* Front, Surround, CLFE, side DAC; unmute as default */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-A front headphon path */
-	{0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Port-D line-out path */
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Mono out path */
-	{0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-	/* Port-B front mic-in path */
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Port-C line-in/surround path - 6ch mode as default */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
-	{0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* Port-E mic-in/CLFE path - 6ch mode as default */
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
-	{0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* mute analog mix */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-	/* select ADCs - front-mic */
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-	{ }
-};
-
-/*
- * verbs for laptop mode (+dig)
- */
-static const struct hda_verb ad1988_laptop_hp_on[] = {
-	/* unmute port-A and mute port-D */
-	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	{ } /* end */
-};
-static const struct hda_verb ad1988_laptop_hp_off[] = {
-	/* mute port-A and unmute port-D */
-	{ 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-	{ 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
-	{ } /* end */
-};
-
-#define AD1988_HP_EVENT	0x01
-
-static const struct hda_verb ad1988_laptop_init_verbs[] = {
-	/* Front, Surround, CLFE, side DAC; unmute as default */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-A front headphon path */
-	{0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* unsolicited event for pin-sense */
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
-	/* Port-D line-out path + EAPD */
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
-	/* Mono out path */
-	{0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
-	/* Port-B mic-in path */
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Port-C docking station - try to output */
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
-	/* mute analog mix */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-	/* select ADCs - mic */
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-	{ }
-};
-
-static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	if ((res >> 26) != AD1988_HP_EVENT)
-		return;
-	if (snd_hda_jack_detect(codec, 0x11))
-		snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
-	else
-		snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
-} 
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1988_loopbacks[] = {
-	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
-	{ 0x20, HDA_INPUT, 1 }, /* Line */
-	{ 0x20, HDA_INPUT, 4 }, /* Mic */
-	{ 0x20, HDA_INPUT, 6 }, /* CD */
-	{ } /* end */
-};
-#endif
 #endif /* ENABLE_AD_STATIC_QUIRKS */
 
 static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
@@ -3220,7 +828,34 @@
 /*
  */
 
-static int ad1988_parse_auto_config(struct hda_codec *codec)
+enum {
+	AD1988_FIXUP_6STACK_DIG,
+};
+
+static const struct hda_fixup ad1988_fixups[] = {
+	[AD1988_FIXUP_6STACK_DIG] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x11, 0x02214130 }, /* front-hp */
+			{ 0x12, 0x01014010 }, /* line-out */
+			{ 0x14, 0x02a19122 }, /* front-mic */
+			{ 0x15, 0x01813021 }, /* line-in */
+			{ 0x16, 0x01011012 }, /* line-out */
+			{ 0x17, 0x01a19020 }, /* mic */
+			{ 0x1b, 0x0145f1f0 }, /* SPDIF */
+			{ 0x24, 0x01016011 }, /* line-out */
+			{ 0x25, 0x01012013 }, /* line-out */
+			{ }
+		}
+	},
+};
+
+static const struct hda_model_fixup ad1988_fixup_models[] = {
+	{ .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
+	{}
+};
+
+static int patch_ad1988(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
 	int err;
@@ -3234,12 +869,19 @@
 	spec->gen.mixer_merge_nid = 0x21;
 	spec->gen.beep_nid = 0x10;
 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
+	snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
 	err = ad198x_parse_auto_config(codec);
 	if (err < 0)
 		goto error;
 	err = ad1988_add_spdif_mux_ctl(codec);
 	if (err < 0)
 		goto error;
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
 	return 0;
 
  error:
@@ -3247,169 +889,6 @@
 	return err;
 }
 
-/*
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const char * const ad1988_models[AD1988_MODEL_LAST] = {
-	[AD1988_6STACK]		= "6stack",
-	[AD1988_6STACK_DIG]	= "6stack-dig",
-	[AD1988_3STACK]		= "3stack",
-	[AD1988_3STACK_DIG]	= "3stack-dig",
-	[AD1988_LAPTOP]		= "laptop",
-	[AD1988_LAPTOP_DIG]	= "laptop-dig",
-	[AD1988_AUTO]		= "auto",
-};
-
-static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
-	SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
-	SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
-	SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
-	SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
-	{}
-};
-
-static int patch_ad1988(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int err, board_config;
-
-	board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
-						  ad1988_models, ad1988_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1988_AUTO;
-	}
-
-	if (board_config == AD1988_AUTO)
-		return ad1988_parse_auto_config(codec);
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	if (is_rev2(codec))
-		snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
-
-	err = snd_hda_attach_beep_device(codec, 0x10);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-	if (!spec->multiout.hp_nid)
-		spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
-	switch (board_config) {
-	case AD1988_6STACK:
-	case AD1988_6STACK_DIG:
-		spec->multiout.max_channels = 8;
-		spec->multiout.num_dacs = 4;
-		if (is_rev2(codec))
-			spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
-		else
-			spec->multiout.dac_nids = ad1988_6stack_dac_nids;
-		spec->input_mux = &ad1988_6stack_capture_source;
-		spec->num_mixers = 2;
-		if (is_rev2(codec))
-			spec->mixers[0] = ad1988_6stack_mixers1_rev2;
-		else
-			spec->mixers[0] = ad1988_6stack_mixers1;
-		spec->mixers[1] = ad1988_6stack_mixers2;
-		spec->num_init_verbs = 1;
-		spec->init_verbs[0] = ad1988_6stack_init_verbs;
-		if (board_config == AD1988_6STACK_DIG) {
-			spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-			spec->dig_in_nid = AD1988_SPDIF_IN;
-		}
-		break;
-	case AD1988_3STACK:
-	case AD1988_3STACK_DIG:
-		spec->multiout.max_channels = 6;
-		spec->multiout.num_dacs = 3;
-		if (is_rev2(codec))
-			spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
-		else
-			spec->multiout.dac_nids = ad1988_3stack_dac_nids;
-		spec->input_mux = &ad1988_6stack_capture_source;
-		spec->channel_mode = ad1988_3stack_modes;
-		spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
-		spec->num_mixers = 2;
-		if (is_rev2(codec))
-			spec->mixers[0] = ad1988_3stack_mixers1_rev2;
-		else
-			spec->mixers[0] = ad1988_3stack_mixers1;
-		spec->mixers[1] = ad1988_3stack_mixers2;
-		spec->num_init_verbs = 1;
-		spec->init_verbs[0] = ad1988_3stack_init_verbs;
-		if (board_config == AD1988_3STACK_DIG)
-			spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-		break;
-	case AD1988_LAPTOP:
-	case AD1988_LAPTOP_DIG:
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		spec->multiout.dac_nids = ad1988_3stack_dac_nids;
-		spec->input_mux = &ad1988_laptop_capture_source;
-		spec->num_mixers = 1;
-		spec->mixers[0] = ad1988_laptop_mixers;
-		codec->inv_eapd = 1; /* inverted EAPD */
-		spec->num_init_verbs = 1;
-		spec->init_verbs[0] = ad1988_laptop_init_verbs;
-		if (board_config == AD1988_LAPTOP_DIG)
-			spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
-		break;
-	}
-
-	spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
-	spec->adc_nids = ad1988_adc_nids;
-	spec->capsrc_nids = ad1988_capsrc_nids;
-	spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
-	spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
-	if (spec->multiout.dig_out_nid) {
-		if (codec->vendor_id >= 0x11d4989a) {
-			spec->mixers[spec->num_mixers++] =
-				ad1989_spdif_out_mixers;
-			spec->init_verbs[spec->num_init_verbs++] =
-				ad1989_spdif_init_verbs;
-			codec->slave_dig_outs = ad1989b_slave_dig_outs;
-		} else {
-			spec->mixers[spec->num_mixers++] =
-				ad1988_spdif_out_mixers;
-			spec->init_verbs[spec->num_init_verbs++] =
-				ad1988_spdif_init_verbs;
-		}
-	}
-	if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
-		spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
-		spec->init_verbs[spec->num_init_verbs++] =
-			ad1988_spdif_in_init_verbs;
-	}
-
-	codec->patch_ops = ad198x_patch_ops;
-	switch (board_config) {
-	case AD1988_LAPTOP:
-	case AD1988_LAPTOP_DIG:
-		codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
-		break;
-	}
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1988_loopbacks;
-#endif
-	spec->vmaster_nid = 0x04;
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1988	ad1988_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * AD1884 / AD1984
@@ -3423,168 +902,20 @@
  *
  * AD1984 = AD1884 + two digital mic-ins
  *
- * FIXME:
- * For simplicity, we share the single DAC for both HP and line-outs
- * right now.  The inidividual playbacks could be easily implemented,
- * but no build-up framework is given, so far.
+ * AD1883 / AD1884A / AD1984A / AD1984B
+ *
+ * port-B (0x14) - front mic-in
+ * port-E (0x1c) - rear mic-in
+ * port-F (0x16) - CD / ext out
+ * port-C (0x15) - rear line-in
+ * port-D (0x12) - rear line-out
+ * port-A (0x11) - front hp-out
+ *
+ * AD1984A = AD1884A + digital-mic
+ * AD1883 = equivalent with AD1984A
+ * AD1984B = AD1984A + extra SPDIF-out
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1884_dac_nids[1] = {
-	0x04,
-};
-
-static const hda_nid_t ad1884_adc_nids[2] = {
-	0x08, 0x09,
-};
-
-static const hda_nid_t ad1884_capsrc_nids[2] = {
-	0x0c, 0x0d,
-};
-
-#define AD1884_SPDIF_OUT	0x02
-
-static const struct hda_input_mux ad1884_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Front Mic", 0x0 },
-		{ "Mic", 0x1 },
-		{ "CD", 0x2 },
-		{ "Mix", 0x3 },
-	},
-};
-
-static const struct snd_kcontrol_new ad1884_base_mixers[] = {
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	/* SPDIF controls */
-	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		/* identical with ad1983 */
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
-	HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
-			     HDA_INPUT),
-	HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
-			   HDA_INPUT),
-	{ } /* end */
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1884_init_verbs[] = {
-	/* DACs; mute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Port-A (HP) mixer */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-A pin */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* HP selector - select DAC2 */
-	{0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Port-D (Line-out) mixer */
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-D pin */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Mono-out mixer */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Mono-out pin */
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Mono selector */
-	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Port-B (front mic) pin */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* Port-C (rear mic) pin */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* Analog mixer; mute as default */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-	/* SPDIF output selector */
-	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-	{ } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1884_loopbacks[] = {
-	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
-	{ 0x20, HDA_INPUT, 1 }, /* Mic */
-	{ 0x20, HDA_INPUT, 2 }, /* CD */
-	{ 0x20, HDA_INPUT, 4 }, /* Docking */
-	{ } /* end */
-};
-#endif
-
-static const char * const ad1884_slave_vols[] = {
-	"PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
-	"Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
-	NULL
-};
-
-enum {
-	AD1884_AUTO,
-	AD1884_BASIC,
-	AD1884_MODELS
-};
-
-static const char * const ad1884_models[AD1884_MODELS] = {
-	[AD1884_AUTO]		= "auto",
-	[AD1884_BASIC]		= "basic",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /* set the upper-limit for mixer amp to 0dB for avoiding the possible
  * damage by overloading
  */
@@ -3599,14 +930,34 @@
 					  (1 << AC_AMPCAP_MUTE_SHIFT));
 }
 
+/* toggle GPIO1 according to the mute state */
+static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
+{
+	struct hda_codec *codec = private_data;
+	struct ad198x_spec *spec = codec->spec;
+
+	if (spec->eapd_nid)
+		ad_vmaster_eapd_hook(private_data, enabled);
+	snd_hda_codec_update_cache(codec, 0x01, 0,
+				   AC_VERB_SET_GPIO_DATA,
+				   enabled ? 0x00 : 0x02);
+}
+
 static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
 				 const struct hda_fixup *fix, int action)
 {
 	struct ad198x_spec *spec = codec->spec;
+	static const struct hda_verb gpio_init_verbs[] = {
+		{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
+		{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
+		{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
+		{},
+	};
 
 	switch (action) {
 	case HDA_FIXUP_ACT_PRE_PROBE:
-		spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+		spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
+		snd_hda_sequence_write_cache(codec, gpio_init_verbs);
 		break;
 	case HDA_FIXUP_ACT_PROBE:
 		if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
@@ -3617,9 +968,18 @@
 	}
 }
 
+/* set magic COEFs for dmic */
+static const struct hda_verb ad1884_dmic_init_verbs[] = {
+	{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
+	{0x01, AC_VERB_SET_PROC_COEF, 0x08},
+	{}
+};
+
 enum {
 	AD1884_FIXUP_AMP_OVERRIDE,
 	AD1884_FIXUP_HP_EAPD,
+	AD1884_FIXUP_DMIC_COEF,
+	AD1884_FIXUP_HP_TOUCHSMART,
 };
 
 static const struct hda_fixup ad1884_fixups[] = {
@@ -3633,15 +993,27 @@
 		.chained = true,
 		.chain_id = AD1884_FIXUP_AMP_OVERRIDE,
 	},
+	[AD1884_FIXUP_DMIC_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = ad1884_dmic_init_verbs,
+	},
+	[AD1884_FIXUP_HP_TOUCHSMART] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = ad1884_dmic_init_verbs,
+		.chained = true,
+		.chain_id = AD1884_FIXUP_HP_EAPD,
+	},
 };
 
 static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
+	SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
 	SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
+	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF),
 	{}
 };
 
 
-static int ad1884_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1884(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
 	int err;
@@ -3674,1170 +1046,6 @@
 	return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1884_basic(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int err;
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	err = snd_hda_attach_beep_device(codec, 0x10);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-	spec->multiout.max_channels = 2;
-	spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
-	spec->multiout.dac_nids = ad1884_dac_nids;
-	spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
-	spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
-	spec->adc_nids = ad1884_adc_nids;
-	spec->capsrc_nids = ad1884_capsrc_nids;
-	spec->input_mux = &ad1884_capture_source;
-	spec->num_mixers = 1;
-	spec->mixers[0] = ad1884_base_mixers;
-	spec->num_init_verbs = 1;
-	spec->init_verbs[0] = ad1884_init_verbs;
-	spec->spdif_route = 0;
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1884_loopbacks;
-#endif
-	spec->vmaster_nid = 0x04;
-	/* we need to cover all playback volumes */
-	spec->slave_vols = ad1884_slave_vols;
-	/* slaves may contain input volumes, so we can't raise to 0dB blindly */
-	spec->avoid_init_slave_vol = 1;
-
-	codec->patch_ops = ad198x_patch_ops;
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-
-static int patch_ad1884(struct hda_codec *codec)
-{
-	int board_config;
-
-	board_config = snd_hda_check_board_config(codec, AD1884_MODELS,
-						  ad1884_models, NULL);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1884_AUTO;
-	}
-
-	if (board_config == AD1884_AUTO)
-		return ad1884_parse_auto_config(codec);
-	else
-		return patch_ad1884_basic(codec);
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1884	ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-/*
- * Lenovo Thinkpad T61/X61
- */
-static const struct hda_input_mux ad1984_thinkpad_capture_source = {
-	.num_items = 4,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Internal Mic", 0x1 },
-		{ "Mix", 0x3 },
-		{ "Dock Mic", 0x4 },
-	},
-};
-
-
-/*
- * Dell Precision T3400
- */
-static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Front Mic", 0x0 },
-		{ "Line-In", 0x1 },
-		{ "Mix", 0x3 },
-	},
-};
-
-
-static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	/* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
-	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
-	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	/* SPDIF controls */
-	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		/* identical with ad1983 */
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-/* additional verbs */
-static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
-	/* Port-E (docking station mic) pin */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* docking mic boost */
-	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Analog PC Beeper - allow firmware/ACPI beeps */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
-	/* Analog mixer - docking mic; mute as default */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* enable EAPD bit */
-	{0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-	{ } /* end */
-};
-
-/*
- * Dell Precision T3400
- */
-static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-/* Digial MIC ADC NID 0x05 + 0x06 */
-static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
-				   struct hda_codec *codec,
-				   unsigned int stream_tag,
-				   unsigned int format,
-				   struct snd_pcm_substream *substream)
-{
-	snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
-				   stream_tag, 0, format);
-	return 0;
-}
-
-static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
-				   struct hda_codec *codec,
-				   struct snd_pcm_substream *substream)
-{
-	snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
-	return 0;
-}
-
-static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
-	.substreams = 2,
-	.channels_min = 2,
-	.channels_max = 2,
-	.nid = 0x05,
-	.ops = {
-		.prepare = ad1984_pcm_dmic_prepare,
-		.cleanup = ad1984_pcm_dmic_cleanup
-	},
-};
-
-static int ad1984_build_pcms(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec = codec->spec;
-	struct hda_pcm *info;
-	int err;
-
-	err = ad198x_build_pcms(codec);
-	if (err < 0)
-		return err;
-
-	info = spec->pcm_rec + codec->num_pcms;
-	codec->num_pcms++;
-	info->name = "AD1984 Digital Mic";
-	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
-	return 0;
-}
-
-/* models */
-enum {
-	AD1984_AUTO,
-	AD1984_BASIC,
-	AD1984_THINKPAD,
-	AD1984_DELL_DESKTOP,
-	AD1984_MODELS
-};
-
-static const char * const ad1984_models[AD1984_MODELS] = {
-	[AD1984_AUTO]		= "auto",
-	[AD1984_BASIC]		= "basic",
-	[AD1984_THINKPAD]	= "thinkpad",
-	[AD1984_DELL_DESKTOP]	= "dell_desktop",
-};
-
-static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
-	/* Lenovo Thinkpad T61/X61 */
-	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
-	SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
-	SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
-	{}
-};
-
-static int patch_ad1984(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int board_config, err;
-
-	board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
-						  ad1984_models, ad1984_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1984_AUTO;
-	}
-
-	if (board_config == AD1984_AUTO)
-		return ad1884_parse_auto_config(codec);
-
-	err = patch_ad1884_basic(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	switch (board_config) {
-	case AD1984_BASIC:
-		/* additional digital mics */
-		spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
-		codec->patch_ops.build_pcms = ad1984_build_pcms;
-		break;
-	case AD1984_THINKPAD:
-		if (codec->subsystem_id == 0x17aa20fb) {
-			/* Thinpad X300 does not have the ability to do SPDIF,
-			   or attach to docking station to use SPDIF */
-			spec->multiout.dig_out_nid = 0;
-		} else
-			spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
-		spec->input_mux = &ad1984_thinkpad_capture_source;
-		spec->mixers[0] = ad1984_thinkpad_mixers;
-		spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
-		spec->analog_beep = 1;
-		break;
-	case AD1984_DELL_DESKTOP:
-		spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1984_dell_desktop_capture_source;
-		spec->mixers[0] = ad1984_dell_desktop_mixers;
-		break;
-	}
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1984	ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
-/*
- * AD1883 / AD1884A / AD1984A / AD1984B
- *
- * port-B (0x14) - front mic-in
- * port-E (0x1c) - rear mic-in
- * port-F (0x16) - CD / ext out
- * port-C (0x15) - rear line-in
- * port-D (0x12) - rear line-out
- * port-A (0x11) - front hp-out
- *
- * AD1984A = AD1884A + digital-mic
- * AD1883 = equivalent with AD1984A
- * AD1984B = AD1984A + extra SPDIF-out
- *
- * FIXME:
- * We share the single DAC for both HP and line-outs (see AD1884/1984).
- */
-
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1884a_dac_nids[1] = {
-	0x03,
-};
-
-#define ad1884a_adc_nids	ad1884_adc_nids
-#define ad1884a_capsrc_nids	ad1884_capsrc_nids
-
-#define AD1884A_SPDIF_OUT	0x02
-
-static const struct hda_input_mux ad1884a_capture_source = {
-	.num_items = 5,
-	.items = {
-		{ "Front Mic", 0x0 },
-		{ "Mic", 0x4 },
-		{ "Line", 0x1 },
-		{ "CD", 0x2 },
-		{ "Mix", 0x3 },
-	},
-};
-
-static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	/* SPDIF controls */
-	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		/* identical with ad1983 */
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1884a_init_verbs[] = {
-	/* DACs; unmute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	/* Port-A (HP) mixer - route only from analog mixer */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-A pin */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Port-D (Line-out) mixer - route only from analog mixer */
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-D pin */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Mono-out mixer - route only from analog mixer */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Mono-out pin */
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Port-B (front mic) pin */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* Port-C (rear line-in) pin */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	/* Port-E (rear mic) pin */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
-	/* Port-F (CD) pin */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Analog mixer; mute as default */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* capture sources */
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* SPDIF output amp */
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-	{ } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1884a_loopbacks[] = {
-	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
-	{ 0x20, HDA_INPUT, 1 }, /* Mic */
-	{ 0x20, HDA_INPUT, 2 }, /* CD */
-	{ 0x20, HDA_INPUT, 4 }, /* Docking */
-	{ } /* end */
-};
-#endif
-
-/*
- * Laptop model
- *
- * Port A: Headphone jack
- * Port B: MIC jack
- * Port C: Internal MIC
- * Port D: Dock Line Out (if enabled)
- * Port E: Dock Line In (if enabled)
- * Port F: Internal speakers
- */
-
-static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
-					struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-	int mute = (!ucontrol->value.integer.value[0] &&
-		    !ucontrol->value.integer.value[1]);
-	/* toggle GPIO1 according to the mute state */
-	snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-			    mute ? 0x02 : 0x0);
-	return ret;
-}
-
-static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = ad1884a_mobile_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-	},
-	HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	/*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Master Playback Switch",
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = ad1884a_mobile_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-	},
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1884a_hp_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x11);
-	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-			    present ? 0x00 : 0x02);
-}
-
-/* switch to external mic if plugged */
-static void ad1884a_hp_automic(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x14);
-	snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
-			    present ? 0 : 1);
-}
-
-#define AD1884A_HP_EVENT		0x37
-#define AD1884A_MIC_EVENT		0x36
-
-/* unsolicited event for HP jack sensing */
-static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	switch (res >> 26) {
-	case AD1884A_HP_EVENT:
-		ad1884a_hp_automute(codec);
-		break;
-	case AD1884A_MIC_EVENT:
-		ad1884a_hp_automic(codec);
-		break;
-	}
-}
-
-/* initialize jack-sensing, too */
-static int ad1884a_hp_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1884a_hp_automute(codec);
-	ad1884a_hp_automic(codec);
-	return 0;
-}
-
-/* mute internal speaker if HP or docking HP is plugged */
-static void ad1884a_laptop_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x11);
-	if (!present)
-		present = snd_hda_jack_detect(codec, 0x12);
-	snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-	snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
-			    present ? 0x00 : 0x02);
-}
-
-/* switch to external mic if plugged */
-static void ad1884a_laptop_automic(struct hda_codec *codec)
-{
-	unsigned int idx;
-
-	if (snd_hda_jack_detect(codec, 0x14))
-		idx = 0;
-	else if (snd_hda_jack_detect(codec, 0x1c))
-		idx = 4;
-	else
-		idx = 1;
-	snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
-				       unsigned int res)
-{
-	switch (res >> 26) {
-	case AD1884A_HP_EVENT:
-		ad1884a_laptop_automute(codec);
-		break;
-	case AD1884A_MIC_EVENT:
-		ad1884a_laptop_automic(codec);
-		break;
-	}
-}
-
-/* initialize jack-sensing, too */
-static int ad1884a_laptop_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1884a_laptop_automute(codec);
-	ad1884a_laptop_automic(codec);
-	return 0;
-}
-
-/* additional verbs for laptop model */
-static const struct hda_verb ad1884a_laptop_verbs[] = {
-	/* Port-A (HP) pin - always unmuted */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-F (int speaker) mixer - route only from analog mixer */
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-F (int speaker) pin */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* required for compaq 6530s/6531s speaker output */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	/* Port-C pin - internal mic-in */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-	/* Port-D (docking line-out) pin - default unmuted */
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* analog mix */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* unsolicited event for pin-sense */
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-	/* allow to touch GPIO1 (for mute control) */
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-	{ } /* end */
-};
-
-static const struct hda_verb ad1884a_mobile_verbs[] = {
-	/* DACs; unmute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	/* Port-A (HP) mixer - route only from analog mixer */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-A pin */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Port-A (HP) pin - always unmuted */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-B (mic jack) pin */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-	/* Port-C (int mic) pin */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-	/* Port-F (int speaker) mixer - route only from analog mixer */
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-F pin */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Analog mixer; mute as default */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* capture sources */
-	/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* unsolicited event for pin-sense */
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-	/* allow to touch GPIO1 (for mute control) */
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-	{ } /* end */
-};
-
-/*
- * Thinkpad X300
- * 0x11 - HP
- * 0x12 - speaker
- * 0x14 - mic-in
- * 0x17 - built-in mic
- */
-
-static const struct hda_verb ad1984a_thinkpad_verbs[] = {
-	/* HP unmute */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* analog mix */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* turn on EAPD */
-	{0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-	/* unsolicited event for pin-sense */
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-	/* internal mic - dmic */
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* set magic COEFs for dmic */
-	{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-	{0x01, AC_VERB_SET_PROC_COEF, 0x08},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	{ } /* end */
-};
-
-static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
-	.num_items = 3,
-	.items = {
-		{ "Mic", 0x0 },
-		{ "Internal Mic", 0x5 },
-		{ "Mix", 0x3 },
-	},
-};
-
-/* mute internal speaker if HP is plugged */
-static void ad1984a_thinkpad_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x11);
-	snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
-					 unsigned int res)
-{
-	if ((res >> 26) != AD1884A_HP_EVENT)
-		return;
-	ad1984a_thinkpad_automute(codec);
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_thinkpad_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1984a_thinkpad_automute(codec);
-	return 0;
-}
-
-/*
- * Precision R5500
- * 0x12 - HP/line-out
- * 0x13 - speaker (mono)
- * 0x15 - mic-in
- */
-
-static const struct hda_verb ad1984a_precision_verbs[] = {
-	/* Unmute main output path */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
-	/* Analog mixer; mute as default */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	/* Select mic as input */
-	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
-	/* Configure as mic */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
-	/* HP unmute */
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* turn on EAPD */
-	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-	/* unsolicited event for pin-sense */
-	{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-
-/* mute internal speaker if HP is plugged */
-static void ad1984a_precision_automute(struct hda_codec *codec)
-{
-	unsigned int present;
-
-	present = snd_hda_jack_detect(codec, 0x12);
-	snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
-				 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_precision_unsol_event(struct hda_codec *codec,
-					 unsigned int res)
-{
-	if ((res >> 26) != AD1884A_HP_EVENT)
-		return;
-	ad1984a_precision_automute(codec);
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_precision_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1984a_precision_automute(codec);
-	return 0;
-}
-
-
-/*
- * HP Touchsmart
- * port-A (0x11)      - front hp-out
- * port-B (0x14)      - unused
- * port-C (0x15)      - unused
- * port-D (0x12)      - rear line out
- * port-E (0x1c)      - front mic-in
- * port-F (0x16)      - Internal speakers
- * digital-mic (0x17) - Internal mic
- */
-
-static const struct hda_verb ad1984a_touchsmart_verbs[] = {
-	/* DACs; unmute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
-	/* Port-A (HP) mixer - route only from analog mixer */
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-A pin */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	/* Port-A (HP) pin - always unmuted */
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Port-E (int speaker) mixer - route only from analog mixer */
-	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
-	/* Port-E pin */
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	/* Port-F (int speaker) mixer - route only from analog mixer */
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-F pin */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Analog mixer; mute as default */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* capture sources */
-	/* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
-	{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
-	{0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* unsolicited event for pin-sense */
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
-	{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
-	/* allow to touch GPIO1 (for mute control) */
-	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
-	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
-	{0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
-	/* internal mic - dmic */
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	/* set magic COEFs for dmic */
-	{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-	{0x01, AC_VERB_SET_PROC_COEF, 0x08},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
-	HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
-/*	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.subdevice = HDA_SUBDEV_AMP_FLAG,
-		.name = "Master Playback Switch",
-		.info = snd_hda_mixer_amp_switch_info,
-		.get = snd_hda_mixer_amp_switch_get,
-		.put = ad1884a_mobile_master_sw_put,
-		.private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
-	},
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
-	{ } /* end */
-};
-
-/* switch to external mic if plugged */
-static void ad1984a_touchsmart_automic(struct hda_codec *codec)
-{
-	if (snd_hda_jack_detect(codec, 0x1c))
-		snd_hda_codec_write(codec, 0x0c, 0,
-				     AC_VERB_SET_CONNECT_SEL, 0x4);
-	else
-		snd_hda_codec_write(codec, 0x0c, 0,
-				     AC_VERB_SET_CONNECT_SEL, 0x5);
-}
-
-
-/* unsolicited event for HP jack sensing */
-static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
-	unsigned int res)
-{
-	switch (res >> 26) {
-	case AD1884A_HP_EVENT:
-		ad1884a_hp_automute(codec);
-		break;
-	case AD1884A_MIC_EVENT:
-		ad1984a_touchsmart_automic(codec);
-		break;
-	}
-}
-
-/* initialize jack-sensing, too */
-static int ad1984a_touchsmart_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1884a_hp_automute(codec);
-	ad1984a_touchsmart_automic(codec);
-	return 0;
-}
-
-
-/*
- */
-
-enum {
-	AD1884A_AUTO,
-	AD1884A_DESKTOP,
-	AD1884A_LAPTOP,
-	AD1884A_MOBILE,
-	AD1884A_THINKPAD,
-	AD1984A_TOUCHSMART,
-	AD1984A_PRECISION,
-	AD1884A_MODELS
-};
-
-static const char * const ad1884a_models[AD1884A_MODELS] = {
-	[AD1884A_AUTO]		= "auto",
-	[AD1884A_DESKTOP]	= "desktop",
-	[AD1884A_LAPTOP]	= "laptop",
-	[AD1884A_MOBILE]	= "mobile",
-	[AD1884A_THINKPAD]	= "thinkpad",
-	[AD1984A_TOUCHSMART]	= "touchsmart",
-	[AD1984A_PRECISION]	= "precision",
-};
-
-static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
-	SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
-	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
-	SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
-	SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
-	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
-	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
-	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
-	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
-	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
-	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
-	SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
-	{}
-};
-
-static int patch_ad1884a(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int err, board_config;
-
-	board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
-						  ad1884a_models,
-						  ad1884a_cfg_tbl);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1884A_AUTO;
-	}
-
-	if (board_config == AD1884A_AUTO)
-		return ad1884_parse_auto_config(codec);
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	err = snd_hda_attach_beep_device(codec, 0x10);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-	spec->multiout.max_channels = 2;
-	spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
-	spec->multiout.dac_nids = ad1884a_dac_nids;
-	spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
-	spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
-	spec->adc_nids = ad1884a_adc_nids;
-	spec->capsrc_nids = ad1884a_capsrc_nids;
-	spec->input_mux = &ad1884a_capture_source;
-	spec->num_mixers = 1;
-	spec->mixers[0] = ad1884a_base_mixers;
-	spec->num_init_verbs = 1;
-	spec->init_verbs[0] = ad1884a_init_verbs;
-	spec->spdif_route = 0;
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1884a_loopbacks;
-#endif
-	codec->patch_ops = ad198x_patch_ops;
-
-	/* override some parameters */
-	switch (board_config) {
-	case AD1884A_LAPTOP:
-		spec->mixers[0] = ad1884a_laptop_mixers;
-		spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
-		spec->multiout.dig_out_nid = 0;
-		codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
-		codec->patch_ops.init = ad1884a_laptop_init;
-		/* set the upper-limit for mixer amp to 0dB for avoiding the
-		 * possible damage by overloading
-		 */
-		snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-					  (1 << AC_AMPCAP_MUTE_SHIFT));
-		break;
-	case AD1884A_MOBILE:
-		spec->mixers[0] = ad1884a_mobile_mixers;
-		spec->init_verbs[0] = ad1884a_mobile_verbs;
-		spec->multiout.dig_out_nid = 0;
-		codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
-		codec->patch_ops.init = ad1884a_hp_init;
-		/* set the upper-limit for mixer amp to 0dB for avoiding the
-		 * possible damage by overloading
-		 */
-		snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-					  (1 << AC_AMPCAP_MUTE_SHIFT));
-		break;
-	case AD1884A_THINKPAD:
-		spec->mixers[0] = ad1984a_thinkpad_mixers;
-		spec->init_verbs[spec->num_init_verbs++] =
-			ad1984a_thinkpad_verbs;
-		spec->multiout.dig_out_nid = 0;
-		spec->input_mux = &ad1984a_thinkpad_capture_source;
-		codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
-		codec->patch_ops.init = ad1984a_thinkpad_init;
-		break;
-	case AD1984A_PRECISION:
-		spec->mixers[0] = ad1984a_precision_mixers;
-		spec->init_verbs[spec->num_init_verbs++] =
-			ad1984a_precision_verbs;
-		spec->multiout.dig_out_nid = 0;
-		codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
-		codec->patch_ops.init = ad1984a_precision_init;
-		break;
-	case AD1984A_TOUCHSMART:
-		spec->mixers[0] = ad1984a_touchsmart_mixers;
-		spec->init_verbs[0] = ad1984a_touchsmart_verbs;
-		spec->multiout.dig_out_nid = 0;
-		codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
-		codec->patch_ops.init = ad1984a_touchsmart_init;
-		/* set the upper-limit for mixer amp to 0dB for avoiding the
-		 * possible damage by overloading
-		 */
-		snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-					  (1 << AC_AMPCAP_MUTE_SHIFT));
-		break;
-	}
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1884a	ad1884_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-
 /*
  * AD1882 / AD1882A
  *
@@ -4850,299 +1058,7 @@
  * port-G - rear clfe-out (6stack)
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static const hda_nid_t ad1882_dac_nids[3] = {
-	0x04, 0x03, 0x05
-};
-
-static const hda_nid_t ad1882_adc_nids[2] = {
-	0x08, 0x09,
-};
-
-static const hda_nid_t ad1882_capsrc_nids[2] = {
-	0x0c, 0x0d,
-};
-
-#define AD1882_SPDIF_OUT	0x02
-
-/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
-static const struct hda_input_mux ad1882_capture_source = {
-	.num_items = 5,
-	.items = {
-		{ "Front Mic", 0x1 },
-		{ "Mic", 0x4 },
-		{ "Line", 0x2 },
-		{ "CD", 0x3 },
-		{ "Mix", 0x7 },
-	},
-};
-
-/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
-static const struct hda_input_mux ad1882a_capture_source = {
-	.num_items = 5,
-	.items = {
-		{ "Front Mic", 0x1 },
-		{ "Mic", 0x4},
-		{ "Line", 0x2 },
-		{ "Digital Mic", 0x06 },
-		{ "Mix", 0x7 },
-	},
-};
-
-static const struct snd_kcontrol_new ad1882_base_mixers[] = {
-	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
-
-	HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		/* The multiple "Capture Source" controls confuse alsamixer
-		 * So call somewhat different..
-		 */
-		/* .name = "Capture Source", */
-		.name = "Input Source",
-		.count = 2,
-		.info = ad198x_mux_enum_info,
-		.get = ad198x_mux_enum_get,
-		.put = ad198x_mux_enum_put,
-	},
-	/* SPDIF controls */
-	HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
-		/* identical with ad1983 */
-		.info = ad1983_spdif_route_info,
-		.get = ad1983_spdif_route_get,
-		.put = ad1983_spdif_route_put,
-	},
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
-	HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
-	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
-	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-	HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
-	{ } /* end */
-};
-
-static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
-	HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Channel Mode",
-		.info = ad198x_ch_mode_info,
-		.get = ad198x_ch_mode_get,
-		.put = ad198x_ch_mode_put,
-	},
-	{ } /* end */
-};
-
-/* simple auto-mute control for AD1882 3-stack board */
-#define AD1882_HP_EVENT	0x01
-
-static void ad1882_3stack_automute(struct hda_codec *codec)
-{
-	bool mute = snd_hda_jack_detect(codec, 0x11);
-	snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    mute ? 0 : PIN_OUT);
-}
-
-static int ad1882_3stack_automute_init(struct hda_codec *codec)
-{
-	ad198x_init(codec);
-	ad1882_3stack_automute(codec);
-	return 0;
-}
-
-static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-	switch (res >> 26) {
-	case AD1882_HP_EVENT:
-		ad1882_3stack_automute(codec);
-		break;
-	}
-}
-
-static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
-	HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
-	{ } /* end */
-};
-
-static const struct hda_verb ad1882_ch2_init[] = {
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{ } /* end */
-};
-
-static const struct hda_verb ad1882_ch4_init[] = {
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{ } /* end */
-};
-
-static const struct hda_verb ad1882_ch6_init[] = {
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	{ } /* end */
-};
-
-static const struct hda_channel_mode ad1882_modes[3] = {
-	{ 2, ad1882_ch2_init },
-	{ 4, ad1882_ch4_init },
-	{ 6, ad1882_ch6_init },
-};
-
-/*
- * initialization verbs
- */
-static const struct hda_verb ad1882_init_verbs[] = {
-	/* DACs; mute as default */
-	{0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-	/* Port-A (HP) mixer */
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-A pin */
-	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* HP selector - select DAC2 */
-	{0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
-	/* Port-D (Line-out) mixer */
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Port-D pin */
-	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Mono-out mixer */
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-	/* Mono-out pin */
-	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Port-B (front mic) pin */
-	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-	/* Port-C (line-in) pin */
-	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-	/* Port-C mixer - mute as input */
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Port-E (mic-in) pin */
-	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
-	/* Port-E mixer - mute as input */
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	/* Port-F (surround) */
-	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Port-G (CLFE) */
-	{0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-	{0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-	/* Analog mixer; mute as default */
-	/* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
-	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
-	/* Analog Mix output amp */
-	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
-	/* SPDIF output selector */
-	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-	{0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
-	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
-	{ } /* end */
-};
-
-static const struct hda_verb ad1882_3stack_automute_verbs[] = {
-	{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
-	{ } /* end */
-};
-
-#ifdef CONFIG_PM
-static const struct hda_amp_list ad1882_loopbacks[] = {
-	{ 0x20, HDA_INPUT, 0 }, /* Front Mic */
-	{ 0x20, HDA_INPUT, 1 }, /* Mic */
-	{ 0x20, HDA_INPUT, 4 }, /* Line */
-	{ 0x20, HDA_INPUT, 6 }, /* CD */
-	{ } /* end */
-};
-#endif
-
-/* models */
-enum {
-	AD1882_AUTO,
-	AD1882_3STACK,
-	AD1882_6STACK,
-	AD1882_3STACK_AUTOMUTE,
-	AD1882_MODELS
-};
-
-static const char * const ad1882_models[AD1986A_MODELS] = {
-	[AD1882_AUTO]		= "auto",
-	[AD1882_3STACK]		= "3stack",
-	[AD1882_6STACK]		= "6stack",
-	[AD1882_3STACK_AUTOMUTE] = "3stack-automute",
-};
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
-static int ad1882_parse_auto_config(struct hda_codec *codec)
+static int patch_ad1882(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
 	int err;
@@ -5169,110 +1085,20 @@
 	return err;
 }
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int patch_ad1882(struct hda_codec *codec)
-{
-	struct ad198x_spec *spec;
-	int err, board_config;
-
-	board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
-						  ad1882_models, NULL);
-	if (board_config < 0) {
-		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
-		       codec->chip_name);
-		board_config = AD1882_AUTO;
-	}
-
-	if (board_config == AD1882_AUTO)
-		return ad1882_parse_auto_config(codec);
-
-	err = alloc_ad_spec(codec);
-	if (err < 0)
-		return err;
-	spec = codec->spec;
-
-	err = snd_hda_attach_beep_device(codec, 0x10);
-	if (err < 0) {
-		ad198x_free(codec);
-		return err;
-	}
-	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-	spec->multiout.max_channels = 6;
-	spec->multiout.num_dacs = 3;
-	spec->multiout.dac_nids = ad1882_dac_nids;
-	spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
-	spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
-	spec->adc_nids = ad1882_adc_nids;
-	spec->capsrc_nids = ad1882_capsrc_nids;
-	if (codec->vendor_id == 0x11d41882)
-		spec->input_mux = &ad1882_capture_source;
-	else
-		spec->input_mux = &ad1882a_capture_source;
-	spec->num_mixers = 2;
-	spec->mixers[0] = ad1882_base_mixers;
-	if (codec->vendor_id == 0x11d41882)
-		spec->mixers[1] = ad1882_loopback_mixers;
-	else
-		spec->mixers[1] = ad1882a_loopback_mixers;
-	spec->num_init_verbs = 1;
-	spec->init_verbs[0] = ad1882_init_verbs;
-	spec->spdif_route = 0;
-#ifdef CONFIG_PM
-	spec->loopback.amplist = ad1882_loopbacks;
-#endif
-	spec->vmaster_nid = 0x04;
-
-	codec->patch_ops = ad198x_patch_ops;
-
-	/* override some parameters */
-	switch (board_config) {
-	default:
-	case AD1882_3STACK:
-	case AD1882_3STACK_AUTOMUTE:
-		spec->num_mixers = 3;
-		spec->mixers[2] = ad1882_3stack_mixers;
-		spec->channel_mode = ad1882_modes;
-		spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
-		spec->need_dac_fix = 1;
-		spec->multiout.max_channels = 2;
-		spec->multiout.num_dacs = 1;
-		if (board_config != AD1882_3STACK) {
-			spec->init_verbs[spec->num_init_verbs++] =
-				ad1882_3stack_automute_verbs;
-			codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
-			codec->patch_ops.init = ad1882_3stack_automute_init;
-		}
-		break;
-	case AD1882_6STACK:
-		spec->num_mixers = 3;
-		spec->mixers[2] = ad1882_6stack_mixers;
-		break;
-	}
-
-	codec->no_trigger_sense = 1;
-	codec->no_sticky_stream = 1;
-
-	return 0;
-}
-#else /* ENABLE_AD_STATIC_QUIRKS */
-#define patch_ad1882	ad1882_parse_auto_config
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 
 /*
  * patch entries
  */
 static const struct hda_codec_preset snd_hda_preset_analog[] = {
-	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
+	{ .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 },
 	{ .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
-	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
+	{ .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 },
 	{ .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
-	{ .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
-	{ .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
+	{ .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 },
+	{ .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 },
 	{ .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
 	{ .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
-	{ .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
+	{ .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 },
 	{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
 	{ .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
 	{ .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index de00ce1..4edd2d0 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -66,6 +66,8 @@
 	hda_nid_t eapds[4];
 	bool dynamic_eapd;
 
+	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
 #ifdef ENABLE_CXT_STATIC_QUIRKS
 	const struct snd_kcontrol_new *mixers[5];
 	int num_mixers;
@@ -3200,6 +3202,9 @@
 	snd_hda_gen_init(codec);
 	if (!spec->dynamic_eapd)
 		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
+
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
 	return 0;
 }
 
@@ -3224,6 +3229,8 @@
 	CXT_PINCFG_LEMOTE_A1205,
 	CXT_FIXUP_STEREO_DMIC,
 	CXT_FIXUP_INC_MIC_BOOST,
+	CXT_FIXUP_HEADPHONE_MIC_PIN,
+	CXT_FIXUP_HEADPHONE_MIC,
 };
 
 static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
@@ -3246,6 +3253,59 @@
 				  (0 << AC_AMPCAP_MUTE_SHIFT));
 }
 
+static void cxt_update_headset_mode(struct hda_codec *codec)
+{
+	/* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
+	int i;
+	bool mic_mode = false;
+	struct conexant_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+
+	for (i = 0; i < cfg->num_inputs; i++)
+		if (cfg->inputs[i].pin == mux_pin) {
+			mic_mode = !!cfg->inputs[i].is_headphone_mic;
+			break;
+		}
+
+	if (mic_mode) {
+		snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
+		spec->gen.hp_jack_present = false;
+	} else {
+		snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
+		spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
+	}
+
+	snd_hda_gen_update_outputs(codec);
+}
+
+static void cxt_update_headset_mode_hook(struct hda_codec *codec,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	cxt_update_headset_mode(codec);
+}
+
+static void cxt_fixup_headphone_mic(struct hda_codec *codec,
+				    const struct hda_fixup *fix, int action)
+{
+	struct conexant_spec *spec = codec->spec;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
+		break;
+	case HDA_FIXUP_ACT_PROBE:
+		spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
+		spec->gen.automute_hook = cxt_update_headset_mode;
+		break;
+	case HDA_FIXUP_ACT_INIT:
+		cxt_update_headset_mode(codec);
+		break;
+	}
+}
+
+
 /* ThinkPad X200 & co with cxt5051 */
 static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
 	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -3302,6 +3362,19 @@
 		.type = HDA_FIXUP_FUNC,
 		.v.func = cxt5066_increase_mic_boost,
 	},
+	[CXT_FIXUP_HEADPHONE_MIC_PIN] = {
+		.type = HDA_FIXUP_PINS,
+		.chained = true,
+		.chain_id = CXT_FIXUP_HEADPHONE_MIC,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+			{ }
+		}
+	},
+	[CXT_FIXUP_HEADPHONE_MIC] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cxt_fixup_headphone_mic,
+	},
 };
 
 static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3311,6 +3384,7 @@
 
 static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
@@ -3395,7 +3469,8 @@
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
-	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
+				       spec->parse_flags);
 	if (err < 0)
 		goto error;
 
@@ -3416,6 +3491,8 @@
 		codec->bus->allow_bus_reset = 1;
 	}
 
+	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
 	return 0;
 
  error:
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 030ca86..9a58893 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -67,6 +67,8 @@
 	struct delayed_work work;
 	struct snd_kcontrol *eld_ctl;
 	int repoll_count;
+	bool setup; /* the stream has been set up by prepare callback */
+	int channels; /* current number of channels */
 	bool non_pcm;
 	bool chmap_set;		/* channel-map override by ALSA API? */
 	unsigned char chmap[8]; /* ALSA API channel-map */
@@ -551,6 +553,17 @@
 		}
 	}
 
+	if (!ca) {
+		/* if there was no match, select the regular ALSA channel
+		 * allocation with the matching number of channels */
+		for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+			if (channels == channel_allocations[i].channels) {
+				ca = channel_allocations[i].ca_index;
+				break;
+			}
+		}
+	}
+
 	snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf));
 	snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
 		    ca, channels, buf);
@@ -868,18 +881,19 @@
 	return true;
 }
 
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
-				       bool non_pcm,
-				       struct snd_pcm_substream *substream)
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+				       struct hdmi_spec_per_pin *per_pin,
+				       bool non_pcm)
 {
-	struct hdmi_spec *spec = codec->spec;
-	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
 	hda_nid_t pin_nid = per_pin->pin_nid;
-	int channels = substream->runtime->channels;
+	int channels = per_pin->channels;
 	struct hdmi_eld *eld;
 	int ca;
 	union audio_infoframe ai;
 
+	if (!channels)
+		return;
+
 	eld = &per_pin->sink_eld;
 	if (!eld->monitor_present)
 		return;
@@ -959,6 +973,7 @@
 	int pin_nid;
 	int pin_idx;
 	struct hda_jack_tbl *jack;
+	int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
 
 	jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
 	if (!jack)
@@ -967,8 +982,8 @@
 	jack->jack_dirty = 1;
 
 	_snd_printd(SND_PR_VERBOSE,
-		"HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
-		codec->addr, pin_nid,
+		"HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
+		codec->addr, pin_nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
 		!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
 
 	pin_idx = pin_nid_to_pin_index(spec, pin_nid);
@@ -1329,6 +1344,7 @@
 		eld_changed = true;
 	}
 	if (update_eld) {
+		bool old_eld_valid = pin_eld->eld_valid;
 		pin_eld->eld_valid = eld->eld_valid;
 		eld_changed = pin_eld->eld_size != eld->eld_size ||
 			      memcmp(pin_eld->eld_buffer, eld->eld_buffer,
@@ -1338,6 +1354,18 @@
 			       eld->eld_size);
 		pin_eld->eld_size = eld->eld_size;
 		pin_eld->info = eld->info;
+
+		/* Haswell-specific workaround: re-setup when the transcoder is
+		 * changed during the stream playback
+		 */
+		if (codec->vendor_id == 0x80862807 &&
+		    eld->eld_valid && !old_eld_valid && per_pin->setup) {
+			snd_hda_codec_write(codec, pin_nid, 0,
+					    AC_VERB_SET_AMP_GAIN_MUTE,
+					    AMP_OUT_UNMUTE);
+			hdmi_setup_audio_infoframe(codec, per_pin,
+						   per_pin->non_pcm);
+		}
 	}
 	mutex_unlock(&pin_eld->lock);
 
@@ -1510,14 +1538,17 @@
 	hda_nid_t cvt_nid = hinfo->nid;
 	struct hdmi_spec *spec = codec->spec;
 	int pin_idx = hinfo_to_pin_index(spec, hinfo);
-	hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid;
+	struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+	hda_nid_t pin_nid = per_pin->pin_nid;
 	bool non_pcm;
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
+	per_pin->channels = substream->runtime->channels;
+	per_pin->setup = true;
 
 	hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
-	hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
+	hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
 
 	return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
@@ -1557,6 +1588,9 @@
 		snd_hda_spdif_ctls_unassign(codec, pin_idx);
 		per_pin->chmap_set = false;
 		memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
+
+		per_pin->setup = false;
+		per_pin->channels = 0;
 	}
 
 	return 0;
@@ -1692,8 +1726,7 @@
 	per_pin->chmap_set = true;
 	memcpy(per_pin->chmap, chmap, sizeof(chmap));
 	if (prepared)
-		hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
-					   substream);
+		hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
 
 	return 0;
 }
@@ -1781,6 +1814,9 @@
 		struct snd_pcm_chmap *chmap;
 		struct snd_kcontrol *kctl;
 		int i;
+
+		if (!codec->pcm_info[pin_idx].pcm)
+			break;
 		err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
 					     SNDRV_PCM_STREAM_PLAYBACK,
 					     NULL, 0, pin_idx, &chmap);
@@ -1989,8 +2025,10 @@
 		return -EINVAL;
 	}
 	codec->patch_ops = generic_hdmi_patch_ops;
-	if (codec->vendor_id == 0x80862807)
+	if (codec->vendor_id == 0x80862807) {
 		codec->patch_ops.set_power_state = haswell_set_power_state;
+		codec->dp_mst = true;
+	}
 
 	generic_hdmi_init_per_pins(codec);
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f303cd8..9e9378c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -282,6 +282,7 @@
 {
 	alc_auto_setup_eapd(codec, false);
 	msleep(200);
+	snd_hda_shutup_pins(codec);
 }
 
 /* generic EAPD initialization */
@@ -826,7 +827,8 @@
 
 	if (spec && spec->shutup)
 		spec->shutup(codec);
-	snd_hda_shutup_pins(codec);
+	else
+		snd_hda_shutup_pins(codec);
 }
 
 #define alc_free	snd_hda_gen_free
@@ -1853,8 +1855,10 @@
 				       const struct hda_fixup *fix, int action)
 {
 	struct alc_spec *spec = codec->spec;
-	if (action == HDA_FIXUP_ACT_PRE_PROBE)
+	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 		spec->gen.no_primary_hp = 1;
+		spec->gen.no_multi_io = 1;
+	}
 }
 
 static const struct hda_fixup alc882_fixups[] = {
@@ -2533,6 +2537,7 @@
 	ALC269_TYPE_ALC269VD,
 	ALC269_TYPE_ALC280,
 	ALC269_TYPE_ALC282,
+	ALC269_TYPE_ALC283,
 	ALC269_TYPE_ALC284,
 	ALC269_TYPE_ALC286,
 };
@@ -2558,6 +2563,7 @@
 	case ALC269_TYPE_ALC269VB:
 	case ALC269_TYPE_ALC269VD:
 	case ALC269_TYPE_ALC282:
+	case ALC269_TYPE_ALC283:
 	case ALC269_TYPE_ALC286:
 		ssids = alc269_ssids;
 		break;
@@ -2583,15 +2589,81 @@
 {
 	struct alc_spec *spec = codec->spec;
 
-	if (spec->codec_variant != ALC269_TYPE_ALC269VB)
-		return;
-
 	if (spec->codec_variant == ALC269_TYPE_ALC269VB)
 		alc269vb_toggle_power_output(codec, 0);
 	if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
 			(alc_get_coef0(codec) & 0x00ff) == 0x018) {
 		msleep(150);
 	}
+	snd_hda_shutup_pins(codec);
+}
+
+static void alc283_init(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+	bool hp_pin_sense;
+	int val;
+
+	if (!hp_pin)
+		return;
+	hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+	/* Index 0x43 Direct Drive HP AMP LPM Control 1 */
+	/* Headphone capless set to high power mode */
+	alc_write_coef_idx(codec, 0x43, 0x9004);
+
+	snd_hda_codec_write(codec, hp_pin, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+	if (hp_pin_sense)
+		msleep(85);
+
+	snd_hda_codec_write(codec, hp_pin, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+	if (hp_pin_sense)
+		msleep(85);
+	/* Index 0x46 Combo jack auto switch control 2 */
+	/* 3k pull low control for Headset jack. */
+	val = alc_read_coef_idx(codec, 0x46);
+	alc_write_coef_idx(codec, 0x46, val & ~(3 << 12));
+	/* Headphone capless set to normal mode */
+	alc_write_coef_idx(codec, 0x43, 0x9614);
+}
+
+static void alc283_shutup(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+	bool hp_pin_sense;
+	int val;
+
+	if (!hp_pin) {
+		alc269_shutup(codec);
+		return;
+	}
+
+	hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+	alc_write_coef_idx(codec, 0x43, 0x9004);
+
+	snd_hda_codec_write(codec, hp_pin, 0,
+			    AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+	if (hp_pin_sense)
+		msleep(85);
+
+	snd_hda_codec_write(codec, hp_pin, 0,
+			    AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+	val = alc_read_coef_idx(codec, 0x46);
+	alc_write_coef_idx(codec, 0x46, val | (3 << 12));
+
+	if (hp_pin_sense)
+		msleep(85);
+	snd_hda_shutup_pins(codec);
+	alc_write_coef_idx(codec, 0x43, 0x9614);
 }
 
 static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
@@ -2722,6 +2794,7 @@
 	hda_call_check_power_status(codec, 0x01);
 	if (spec->has_alc5505_dsp)
 		alc5505_dsp_resume(codec);
+
 	return 0;
 }
 #endif /* CONFIG_PM */
@@ -3261,6 +3334,28 @@
 	alc_fixup_headset_mode(codec, fix, action);
 }
 
+/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
+static int find_ext_mic_pin(struct hda_codec *codec)
+{
+	struct alc_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+	hda_nid_t nid;
+	unsigned int defcfg;
+	int i;
+
+	for (i = 0; i < cfg->num_inputs; i++) {
+		if (cfg->inputs[i].type != AUTO_PIN_MIC)
+			continue;
+		nid = cfg->inputs[i].pin;
+		defcfg = snd_hda_codec_get_pincfg(codec, nid);
+		if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
+			continue;
+		return nid;
+	}
+
+	return 0;
+}
+
 static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
 				    const struct hda_fixup *fix,
 				    int action)
@@ -3268,11 +3363,12 @@
 	struct alc_spec *spec = codec->spec;
 
 	if (action == HDA_FIXUP_ACT_PROBE) {
-		if (snd_BUG_ON(!spec->gen.am_entry[1].pin ||
-			       !spec->gen.autocfg.hp_pins[0]))
+		int mic_pin = find_ext_mic_pin(codec);
+		int hp_pin = spec->gen.autocfg.hp_pins[0];
+
+		if (snd_BUG_ON(!mic_pin || !hp_pin))
 			return;
-		snd_hda_jack_set_gating_jack(codec, spec->gen.am_entry[1].pin,
-					     spec->gen.autocfg.hp_pins[0]);
+		snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin);
 	}
 }
 
@@ -3308,6 +3404,45 @@
 	}
 }
 
+static void alc283_hp_automute_hook(struct hda_codec *codec,
+				    struct hda_jack_tbl *jack)
+{
+	struct alc_spec *spec = codec->spec;
+	int vref;
+
+	msleep(200);
+	snd_hda_gen_hp_automute(codec, jack);
+
+	vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+
+	msleep(600);
+	snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+			    vref);
+}
+
+static void alc283_chromebook_caps(struct hda_codec *codec)
+{
+	snd_hda_override_wcaps(codec, 0x03, 0);
+}
+
+static void alc283_fixup_chromebook(struct hda_codec *codec,
+				    const struct hda_fixup *fix, int action)
+{
+	struct alc_spec *spec = codec->spec;
+	int val;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		alc283_chromebook_caps(codec);
+		spec->gen.hp_automute_hook = alc283_hp_automute_hook;
+		/* MIC2-VREF control */
+		/* Set to manual mode */
+		val = alc_read_coef_idx(codec, 0x06);
+		alc_write_coef_idx(codec, 0x06, val & ~0x000c);
+		break;
+	}
+}
+
 enum {
 	ALC269_FIXUP_SONY_VAIO,
 	ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -3344,6 +3479,7 @@
 	ALC269_FIXUP_ACER_AC700,
 	ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
 	ALC269VB_FIXUP_ORDISSIMO_EVE2,
+	ALC283_FIXUP_CHROME_BOOK,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -3595,11 +3731,20 @@
 			{ }
 		},
 	},
+	[ALC283_FIXUP_CHROME_BOOK] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc283_fixup_chromebook,
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
+	SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
+	SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
+	SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
+	SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
+	SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
 	SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
 	SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -3637,6 +3782,7 @@
 	SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
 	SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
 	SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+	SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK),
 	SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
 	SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -3655,11 +3801,6 @@
 	SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
 	SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
-	SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-	SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
-	SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
-	SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
-	SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
 	SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
@@ -3670,8 +3811,16 @@
 	SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
-	SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
 	SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
+	SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
+	SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+	SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
 	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 	SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@@ -3840,11 +3989,15 @@
 	case 0x10ec0290:
 		spec->codec_variant = ALC269_TYPE_ALC280;
 		break;
-	case 0x10ec0233:
 	case 0x10ec0282:
-	case 0x10ec0283:
 		spec->codec_variant = ALC269_TYPE_ALC282;
 		break;
+	case 0x10ec0233:
+	case 0x10ec0283:
+		spec->codec_variant = ALC269_TYPE_ALC283;
+		spec->shutup = alc283_shutup;
+		spec->init_hook = alc283_init;
+		break;
 	case 0x10ec0284:
 	case 0x10ec0292:
 		spec->codec_variant = ALC269_TYPE_ALC284;
@@ -3872,7 +4025,8 @@
 	codec->patch_ops.suspend = alc269_suspend;
 	codec->patch_ops.resume = alc269_resume;
 #endif
-	spec->shutup = alc269_shutup;
+	if (!spec->shutup)
+		spec->shutup = alc269_shutup;
 
 	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
 
@@ -4336,6 +4490,7 @@
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
+	SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
 	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
 	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
 	SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 6d1924c..fba0cef 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -158,6 +158,7 @@
 	STAC_D965_VERBS,
 	STAC_DELL_3ST,
 	STAC_DELL_BIOS,
+	STAC_DELL_BIOS_AMIC,
 	STAC_DELL_BIOS_SPDIF,
 	STAC_927X_DELL_DMIC,
 	STAC_927X_VOLKNOB,
@@ -3231,8 +3232,6 @@
 	[STAC_DELL_BIOS] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
-			/* configure the analog microphone on some laptops */
-			{ 0x0c, 0x90a79130 },
 			/* correct the front output jack as a hp out */
 			{ 0x0f, 0x0221101f },
 			/* correct the front input jack as a mic */
@@ -3242,6 +3241,16 @@
 		.chained = true,
 		.chain_id = STAC_927X_DELL_DMIC,
 	},
+	[STAC_DELL_BIOS_AMIC] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			/* configure the analog microphone on some laptops */
+			{ 0x0c, 0x90a79130 },
+			{}
+		},
+		.chained = true,
+		.chain_id = STAC_DELL_BIOS,
+	},
 	[STAC_DELL_BIOS_SPDIF] = {
 		.type = HDA_FIXUP_PINS,
 		.v.pins = (const struct hda_pintbl[]) {
@@ -3270,6 +3279,7 @@
 	{ .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
 	{ .id = STAC_DELL_3ST, .name = "dell-3stack" },
 	{ .id = STAC_DELL_BIOS, .name = "dell-bios" },
+	{ .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
 	{ .id = STAC_927X_VOLKNOB, .name = "volknob" },
 	{}
 };
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index e2481ba..0bc20ef 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -207,9 +207,9 @@
 		return;
 	if (spec->hp_work_active) {
 		snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);
+		codec->jackpoll_interval = 0;
 		cancel_delayed_work_sync(&codec->jackpoll_work);
 		spec->hp_work_active = false;
-		codec->jackpoll_interval = 0;
 	}
 }
 
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 2a8ad9d..bb9ebc5 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -28,6 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/vmalloc.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -198,6 +199,31 @@
 #define RME96_AD1852_VOL_BITS 14
 #define RME96_AD1855_VOL_BITS 10
 
+/* Defines for snd_rme96_trigger */
+#define RME96_TB_START_PLAYBACK 1
+#define RME96_TB_START_CAPTURE 2
+#define RME96_TB_STOP_PLAYBACK 4
+#define RME96_TB_STOP_CAPTURE 8
+#define RME96_TB_RESET_PLAYPOS 16
+#define RME96_TB_RESET_CAPTUREPOS 32
+#define RME96_TB_CLEAR_PLAYBACK_IRQ 64
+#define RME96_TB_CLEAR_CAPTURE_IRQ 128
+#define RME96_RESUME_PLAYBACK	(RME96_TB_START_PLAYBACK)
+#define RME96_RESUME_CAPTURE	(RME96_TB_START_CAPTURE)
+#define RME96_RESUME_BOTH	(RME96_RESUME_PLAYBACK \
+				| RME96_RESUME_CAPTURE)
+#define RME96_START_PLAYBACK	(RME96_TB_START_PLAYBACK \
+				| RME96_TB_RESET_PLAYPOS)
+#define RME96_START_CAPTURE	(RME96_TB_START_CAPTURE \
+				| RME96_TB_RESET_CAPTUREPOS)
+#define RME96_START_BOTH	(RME96_START_PLAYBACK \
+				| RME96_START_CAPTURE)
+#define RME96_STOP_PLAYBACK	(RME96_TB_STOP_PLAYBACK \
+				| RME96_TB_CLEAR_PLAYBACK_IRQ)
+#define RME96_STOP_CAPTURE	(RME96_TB_STOP_CAPTURE \
+				| RME96_TB_CLEAR_CAPTURE_IRQ)
+#define RME96_STOP_BOTH		(RME96_STOP_PLAYBACK \
+				| RME96_STOP_CAPTURE)
 
 struct rme96 {
 	spinlock_t    lock;
@@ -214,6 +240,13 @@
 
 	u8 rev; /* card revision number */
 
+#ifdef CONFIG_PM
+	u32 playback_pointer;
+	u32 capture_pointer;
+	void *playback_suspend_buffer;
+	void *capture_suspend_buffer;
+#endif
+
 	struct snd_pcm_substream *playback_substream;
 	struct snd_pcm_substream *capture_substream;
 
@@ -344,6 +377,8 @@
 {
 	.info =		     (SNDRV_PCM_INFO_MMAP_IOMEM |
 			      SNDRV_PCM_INFO_MMAP_VALID |
+			      SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_RESUME |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE),
 	.formats =	     (SNDRV_PCM_FMTBIT_S16_LE |
@@ -373,6 +408,8 @@
 {
 	.info =		     (SNDRV_PCM_INFO_MMAP_IOMEM |
 			      SNDRV_PCM_INFO_MMAP_VALID |
+			      SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_RESUME |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE),
 	.formats =	     (SNDRV_PCM_FMTBIT_S16_LE |
@@ -402,6 +439,8 @@
 {
 	.info =		     (SNDRV_PCM_INFO_MMAP_IOMEM |
 			      SNDRV_PCM_INFO_MMAP_VALID |
+			      SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_RESUME |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE),
 	.formats =	     (SNDRV_PCM_FMTBIT_S16_LE |
@@ -427,6 +466,8 @@
 {
 	.info =		     (SNDRV_PCM_INFO_MMAP_IOMEM |
 			      SNDRV_PCM_INFO_MMAP_VALID |
+			      SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_RESUME |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE),
 	.formats =	     (SNDRV_PCM_FMTBIT_S16_LE |
@@ -1045,54 +1086,35 @@
 }
 
 static void
-snd_rme96_playback_start(struct rme96 *rme96,
-			 int from_pause)
+snd_rme96_trigger(struct rme96 *rme96,
+		  int op)
 {
-	if (!from_pause) {
+	if (op & RME96_TB_RESET_PLAYPOS)
 		writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
-	}
-
-	rme96->wcreg |= RME96_WCR_START;
-	writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
-}
-
-static void
-snd_rme96_capture_start(struct rme96 *rme96,
-			int from_pause)
-{
-	if (!from_pause) {
+	if (op & RME96_TB_RESET_CAPTUREPOS)
 		writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
+	if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) {
+		rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+		if (rme96->rcreg & RME96_RCR_IRQ)
+			writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
 	}
-
-	rme96->wcreg |= RME96_WCR_START_2;
+	if (op & RME96_TB_CLEAR_CAPTURE_IRQ) {
+		rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
+		if (rme96->rcreg & RME96_RCR_IRQ_2)
+			writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
+	}
+	if (op & RME96_TB_START_PLAYBACK)
+		rme96->wcreg |= RME96_WCR_START;
+	if (op & RME96_TB_STOP_PLAYBACK)
+		rme96->wcreg &= ~RME96_WCR_START;
+	if (op & RME96_TB_START_CAPTURE)
+		rme96->wcreg |= RME96_WCR_START_2;
+	if (op & RME96_TB_STOP_CAPTURE)
+		rme96->wcreg &= ~RME96_WCR_START_2;
 	writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
 }
 
-static void
-snd_rme96_playback_stop(struct rme96 *rme96)
-{
-	/*
-	 * Check if there is an unconfirmed IRQ, if so confirm it, or else
-	 * the hardware will not stop generating interrupts
-	 */
-	rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
-	if (rme96->rcreg & RME96_RCR_IRQ) {
-		writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ);
-	}	
-	rme96->wcreg &= ~RME96_WCR_START;
-	writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
-}
 
-static void
-snd_rme96_capture_stop(struct rme96 *rme96)
-{
-	rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
-	if (rme96->rcreg & RME96_RCR_IRQ_2) {
-		writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ);
-	}	
-	rme96->wcreg &= ~RME96_WCR_START_2;
-	writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
-}
 
 static irqreturn_t
 snd_rme96_interrupt(int irq,
@@ -1155,6 +1177,7 @@
 	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
+	snd_pcm_set_sync(substream);
 	spin_lock_irq(&rme96->lock);	
         if (rme96->playback_substream != NULL) {
 		spin_unlock_irq(&rme96->lock);
@@ -1191,6 +1214,7 @@
 	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
+	snd_pcm_set_sync(substream);
 	runtime->hw = snd_rme96_capture_spdif_info;
         if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG &&
             (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0)
@@ -1222,6 +1246,7 @@
 	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;        
 	
+	snd_pcm_set_sync(substream);
 	spin_lock_irq(&rme96->lock);	
         if (rme96->playback_substream != NULL) {
 		spin_unlock_irq(&rme96->lock);
@@ -1253,6 +1278,7 @@
 	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
+	snd_pcm_set_sync(substream);
 	runtime->hw = snd_rme96_capture_adat_info;
         if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) {
                 /* makes no sense to use analog input. Note that analog
@@ -1288,7 +1314,7 @@
 
 	spin_lock_irq(&rme96->lock);	
 	if (RME96_ISPLAYING(rme96)) {
-		snd_rme96_playback_stop(rme96);
+		snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
 	}
 	rme96->playback_substream = NULL;
 	rme96->playback_periodsize = 0;
@@ -1309,7 +1335,7 @@
 	
 	spin_lock_irq(&rme96->lock);	
 	if (RME96_ISRECORDING(rme96)) {
-		snd_rme96_capture_stop(rme96);
+		snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
 	}
 	rme96->capture_substream = NULL;
 	rme96->capture_periodsize = 0;
@@ -1324,7 +1350,7 @@
 	
 	spin_lock_irq(&rme96->lock);	
 	if (RME96_ISPLAYING(rme96)) {
-		snd_rme96_playback_stop(rme96);
+		snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK);
 	}
 	writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS);
 	spin_unlock_irq(&rme96->lock);
@@ -1338,7 +1364,7 @@
 	
 	spin_lock_irq(&rme96->lock);	
 	if (RME96_ISRECORDING(rme96)) {
-		snd_rme96_capture_stop(rme96);
+		snd_rme96_trigger(rme96, RME96_STOP_CAPTURE);
 	}
 	writel(0, rme96->iobase + RME96_IO_RESET_REC_POS);
 	spin_unlock_irq(&rme96->lock);
@@ -1350,41 +1376,55 @@
 			   int cmd)
 {
 	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+	struct snd_pcm_substream *s;
+	bool sync;
+
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (snd_pcm_substream_chip(s) == rme96)
+			snd_pcm_trigger_done(s, substream);
+	}
+
+	sync = (rme96->playback_substream && rme96->capture_substream) &&
+	       (rme96->playback_substream->group ==
+		rme96->capture_substream->group);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		if (!RME96_ISPLAYING(rme96)) {
-			if (substream != rme96->playback_substream) {
+			if (substream != rme96->playback_substream)
 				return -EBUSY;
-			}
-			snd_rme96_playback_start(rme96, 0);
+			snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
+						 : RME96_START_PLAYBACK);
 		}
 		break;
 
+	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_STOP:
 		if (RME96_ISPLAYING(rme96)) {
-			if (substream != rme96->playback_substream) {
+			if (substream != rme96->playback_substream)
 				return -EBUSY;
-			}
-			snd_rme96_playback_stop(rme96);
+			snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+						 :  RME96_STOP_PLAYBACK);
 		}
 		break;
 
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (RME96_ISPLAYING(rme96)) {
-			snd_rme96_playback_stop(rme96);
-		}
+		if (RME96_ISPLAYING(rme96))
+			snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+						 : RME96_STOP_PLAYBACK);
 		break;
 
+	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!RME96_ISPLAYING(rme96)) {
-			snd_rme96_playback_start(rme96, 1);
-		}
+		if (!RME96_ISPLAYING(rme96))
+			snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
+						 : RME96_RESUME_PLAYBACK);
 		break;
-		
+
 	default:
 		return -EINVAL;
 	}
+
 	return 0;
 }
 
@@ -1393,38 +1433,51 @@
 			  int cmd)
 {
 	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
+	struct snd_pcm_substream *s;
+	bool sync;
+
+	snd_pcm_group_for_each_entry(s, substream) {
+		if (snd_pcm_substream_chip(s) == rme96)
+			snd_pcm_trigger_done(s, substream);
+	}
+
+	sync = (rme96->playback_substream && rme96->capture_substream) &&
+	       (rme96->playback_substream->group ==
+		rme96->capture_substream->group);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		if (!RME96_ISRECORDING(rme96)) {
-			if (substream != rme96->capture_substream) {
+			if (substream != rme96->capture_substream)
 				return -EBUSY;
-			}
-			snd_rme96_capture_start(rme96, 0);
+			snd_rme96_trigger(rme96, sync ? RME96_START_BOTH
+						 : RME96_START_CAPTURE);
 		}
 		break;
 
+	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_STOP:
 		if (RME96_ISRECORDING(rme96)) {
-			if (substream != rme96->capture_substream) {
+			if (substream != rme96->capture_substream)
 				return -EBUSY;
-			}
-			snd_rme96_capture_stop(rme96);
+			snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+						 : RME96_STOP_CAPTURE);
 		}
 		break;
 
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (RME96_ISRECORDING(rme96)) {
-			snd_rme96_capture_stop(rme96);
-		}
+		if (RME96_ISRECORDING(rme96))
+			snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH
+						 : RME96_STOP_CAPTURE);
 		break;
 
+	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!RME96_ISRECORDING(rme96)) {
-			snd_rme96_capture_start(rme96, 1);
-		}
+		if (!RME96_ISRECORDING(rme96))
+			snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
+						 : RME96_RESUME_CAPTURE);
 		break;
-		
+
 	default:
 		return -EINVAL;
 	}
@@ -1505,8 +1558,7 @@
 	        return;
 	}
 	if (rme96->irq >= 0) {
-		snd_rme96_playback_stop(rme96);
-		snd_rme96_capture_stop(rme96);
+		snd_rme96_trigger(rme96, RME96_STOP_BOTH);
 		rme96->areg &= ~RME96_AR_DAC_EN;
 		writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
 		free_irq(rme96->irq, (void *)rme96);
@@ -1520,6 +1572,10 @@
 		pci_release_regions(rme96->pci);
 		rme96->port = 0;
 	}
+#ifdef CONFIG_PM
+	vfree(rme96->playback_suspend_buffer);
+	vfree(rme96->capture_suspend_buffer);
+#endif
 	pci_disable_device(rme96->pci);
 }
 
@@ -1606,8 +1662,7 @@
 	rme96->capture_periodsize = 0;
 	
 	/* make sure playback/capture is stopped, if by some reason active */
-	snd_rme96_playback_stop(rme96);
-	snd_rme96_capture_stop(rme96);
+	snd_rme96_trigger(rme96, RME96_STOP_BOTH);
 	
 	/* set default values in registers */
 	rme96->wcreg =
@@ -2319,6 +2374,87 @@
  * Card initialisation
  */
 
+#ifdef CONFIG_PM
+
+static int
+snd_rme96_suspend(struct pci_dev *pci,
+		  pm_message_t state)
+{
+	struct snd_card *card = pci_get_drvdata(pci);
+	struct rme96 *rme96 = card->private_data;
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+	snd_pcm_suspend(rme96->playback_substream);
+	snd_pcm_suspend(rme96->capture_substream);
+
+	/* save capture & playback pointers */
+	rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS)
+				  & RME96_RCR_AUDIO_ADDR_MASK;
+	rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS)
+				 & RME96_RCR_AUDIO_ADDR_MASK;
+
+	/* save playback and capture buffers */
+	memcpy_fromio(rme96->playback_suspend_buffer,
+		      rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE);
+	memcpy_fromio(rme96->capture_suspend_buffer,
+		      rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE);
+
+	/* disable the DAC  */
+	rme96->areg &= ~RME96_AR_DAC_EN;
+	writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
+
+	pci_disable_device(pci);
+	pci_save_state(pci);
+
+	return 0;
+}
+
+static int
+snd_rme96_resume(struct pci_dev *pci)
+{
+	struct snd_card *card = pci_get_drvdata(pci);
+	struct rme96 *rme96 = card->private_data;
+
+	pci_restore_state(pci);
+	if (pci_enable_device(pci) < 0) {
+		printk(KERN_ERR "rme96: pci_enable_device failed, disabling device\n");
+		snd_card_disconnect(card);
+		return -EIO;
+	}
+
+	/* reset playback and record buffer pointers */
+	writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
+		  + rme96->playback_pointer);
+	writel(0, rme96->iobase + RME96_IO_SET_REC_POS
+		  + rme96->capture_pointer);
+
+	/* restore playback and capture buffers */
+	memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER,
+		    rme96->playback_suspend_buffer, RME96_BUFFER_SIZE);
+	memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER,
+		    rme96->capture_suspend_buffer, RME96_BUFFER_SIZE);
+
+	/* reset the ADC */
+	writel(rme96->areg | RME96_AR_PD2,
+	       rme96->iobase + RME96_IO_ADDITIONAL_REG);
+	writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
+
+	/* reset and enable DAC, restore analog volume */
+	snd_rme96_reset_dac(rme96);
+	rme96->areg |= RME96_AR_DAC_EN;
+	writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
+	if (RME96_HAS_ANALOG_OUT(rme96)) {
+		usleep_range(3000, 10000);
+		snd_rme96_apply_dac_volume(rme96);
+	}
+
+	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+	return 0;
+}
+
+#endif
+
 static void snd_rme96_card_free(struct snd_card *card)
 {
 	snd_rme96_free(card->private_data);
@@ -2355,6 +2491,23 @@
 		return err;
 	}
 	
+#ifdef CONFIG_PM
+	rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+	if (!rme96->playback_suspend_buffer) {
+		snd_printk(KERN_ERR
+			   "Failed to allocate playback suspend buffer!\n");
+		snd_card_free(card);
+		return -ENOMEM;
+	}
+	rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
+	if (!rme96->capture_suspend_buffer) {
+		snd_printk(KERN_ERR
+			   "Failed to allocate capture suspend buffer!\n");
+		snd_card_free(card);
+		return -ENOMEM;
+	}
+#endif
+
 	strcpy(card->driver, "Digi96");
 	switch (rme96->pci->device) {
 	case PCI_DEVICE_ID_RME_DIGI96:
@@ -2397,6 +2550,10 @@
 	.id_table = snd_rme96_ids,
 	.probe = snd_rme96_probe,
 	.remove = snd_rme96_remove,
+#ifdef CONFIG_PM
+	.suspend = snd_rme96_suspend,
+	.resume = snd_rme96_resume,
+#endif
 };
 
 module_pci_driver(rme96_driver);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index bd50193..3cde55b 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -38,6 +38,97 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  */
+
+/* *************    Register Documentation   *******************************************************
+ *
+ * Work in progress! Documentation is based on the code in this file.
+ *
+ * --------- HDSPM_controlRegister ---------
+ * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
+ * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ * :    .    :    .    :    .    :  x .    :  HDSPM_AudioInterruptEnable \_ setting both bits
+ * :    .    :    .    :    .    :    .   x:  HDSPM_Start                /  enables audio IO
+ * :    .    :    .    :    .    :   x.    :  HDSPM_ClockModeMaster - 1: Master, 0: Slave
+ * :    .    :    .    :    .    :    .210 :  HDSPM_LatencyMask - 3 Bit value for latency
+ * :    .    :    .    :    .    :    .    :      0:64, 1:128, 2:256, 3:512,
+ * :    .    :    .    :    .    :    .    :      4:1024, 5:2048, 6:4096, 7:8192
+ * :x   .    :    .    :    .   x:xx  .    :  HDSPM_FrequencyMask
+ * :    .    :    .    :    .    :10  .    :  HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=??
+ * :    .    :    .    :    .   x:    .    :  <MADI> HDSPM_DoubleSpeed
+ * :x   .    :    .    :    .    :    .    :  <MADI> HDSPM_QuadSpeed
+ * :    .  3 :    .  10:  2 .    :    .    :  HDSPM_SyncRefMask :
+ * :    .    :    .   x:    .    :    .    :  HDSPM_SyncRef0
+ * :    .    :    .  x :    .    :    .    :  HDSPM_SyncRef1
+ * :    .    :    .    :  x .    :    .    :  <AES32> HDSPM_SyncRef2
+ * :    .  x :    .    :    .    :    .    :  <AES32> HDSPM_SyncRef3
+ * :    .    :    .  10:    .    :    .    :  <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn
+ * :    .  3 :    .  10:  2 .    :    .    :  <AES32>  0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn?
+ * :    .  x :    .    :    .    :    .    :  <MADIe> HDSPe_FLOAT_FORMAT
+ * :    .    :    .    : x  .    :    .    :  <MADI> HDSPM_InputSelect0 : 0=optical,1=coax
+ * :    .    :    .    :x   .    :    .    :  <MADI> HDSPM_InputSelect1
+ * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
+ * :    .    :    .    :    . x  :    .    :  <MADI> HDSPM_TX_64ch
+ * :    .    :    .    :    . x  :    .    :  <AES32> HDSPM_Emphasis
+ * :    .    :    .    :    .x   :    .    :  <MADI> HDSPM_AutoInp
+ * :    .    :    . x  :    .    :    .    :  <MADI> HDSPM_SMUX
+ * :    .    :    .x   :    .    :    .    :  <MADI> HDSPM_clr_tms
+ * :    .    :   x.    :    .    :    .    :  <MADI> HDSPM_taxi_reset
+ * :    .   x:    .    :    .    :    .    :  <MADI> HDSPM_LineOut
+ * :    .   x:    .    :    .    :    .    :  <AES32> ??????????????????
+ * :    .    :   x.    :    .    :    .    :  <AES32> HDSPM_WCK48
+ * :    .    :    .    :    .x   :    .    :  <AES32> HDSPM_Dolby
+ * :    .    : x  .    :    .    :    .    :  HDSPM_Midi0InterruptEnable
+ * :    .    :x   .    :    .    :    .    :  HDSPM_Midi1InterruptEnable
+ * :    .    :  x .    :    .    :    .    :  HDSPM_Midi2InterruptEnable
+ * :    . x  :    .    :    .    :    .    :  <MADI> HDSPM_Midi3InterruptEnable
+ * :    . x  :    .    :    .    :    .    :  <AES32> HDSPM_DS_DoubleWire
+ * :    .x   :    .    :    .    :    .    :  <AES32> HDSPM_QS_DoubleWire
+ * :   x.    :    .    :    .    :    .    :  <AES32> HDSPM_QS_QuadWire
+ * :    .    :    .    :    .  x :    .    :  <AES32> HDSPM_Professional
+ * : x  .    :    .    :    .    :    .    :  HDSPM_wclk_sel
+ * :    .    :    .    :    .    :    .    :
+ * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number
+ * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit
+ *
+ *
+ *
+ * AIO / RayDAT only
+ *
+ * ------------ HDSPM_WR_SETTINGS ----------
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
+ * :1098.7654:3210.9876:5432.1098:7654.3210:
+ * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
+ * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ * :    .    :    .    :    .    :    .   x: HDSPM_c0Master 1: Master, 0: Slave
+ * :    .    :    .    :    .    :    .  x : HDSPM_c0_SyncRef0
+ * :    .    :    .    :    .    :    . x  : HDSPM_c0_SyncRef1
+ * :    .    :    .    :    .    :    .x   : HDSPM_c0_SyncRef2
+ * :    .    :    .    :    .    :   x.    : HDSPM_c0_SyncRef3
+ * :    .    :    .    :    .    :   3.210 : HDSPM_c0_SyncRefMask:
+ * :    .    :    .    :    .    :    .    :  RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4,
+ * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
+ * :    .    :    .    :    .    :    .    :  AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT,
+ * :    .    :    .    :    .    :    .    :          9:TCO, 10:SyncIn
+ * :    .    :    .    :    .    :    .    :
+ * :    .    :    .    :    .    :    .    :
+ * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte
+ * :1098.7654:3210.9876:5432.1098:7654.3210:
+ * :||||.||||:||||.||||:||||.||||:||||.||||: bit number
+ * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31
+ * :||||.||||:||||.||||:||||.||||:||||.||||:
+ * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit
+ *
+ */
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -95,7 +186,7 @@
 #define HDSPM_controlRegister	     64
 #define HDSPM_interruptConfirmation  96
 #define HDSPM_control2Reg	     256  /* not in specs ???????? */
-#define HDSPM_freqReg                256  /* for AES32 */
+#define HDSPM_freqReg                256  /* for setting arbitrary clock values (DDS feature) */
 #define HDSPM_midiDataOut0	     352  /* just believe in old code */
 #define HDSPM_midiDataOut1	     356
 #define HDSPM_eeprom_wr		     384  /* for AES32 */
@@ -258,6 +349,25 @@
 
 #define HDSPM_wclk_sel (1<<30)
 
+/* additional control register bits for AIO*/
+#define HDSPM_c0_Wck48				0x20 /* also RayDAT */
+#define HDSPM_c0_Input0				0x1000
+#define HDSPM_c0_Input1				0x2000
+#define HDSPM_c0_Spdif_Opt			0x4000
+#define HDSPM_c0_Pro				0x8000
+#define HDSPM_c0_clr_tms			0x10000
+#define HDSPM_c0_AEB1				0x20000
+#define HDSPM_c0_AEB2				0x40000
+#define HDSPM_c0_LineOut			0x80000
+#define HDSPM_c0_AD_GAIN0			0x100000
+#define HDSPM_c0_AD_GAIN1			0x200000
+#define HDSPM_c0_DA_GAIN0			0x400000
+#define HDSPM_c0_DA_GAIN1			0x800000
+#define HDSPM_c0_PH_GAIN0			0x1000000
+#define HDSPM_c0_PH_GAIN1			0x2000000
+#define HDSPM_c0_Sym6db				0x4000000
+
+
 /* --- bit helper defines */
 #define HDSPM_LatencyMask    (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2)
 #define HDSPM_FrequencyMask  (HDSPM_Frequency0|HDSPM_Frequency1|\
@@ -341,11 +451,11 @@
 #define HDSPM_madiLock           (1<<3)	/* MADI Locked =1, no=0 */
 #define HDSPM_madiSync          (1<<18) /* MADI is in sync */
 
-#define HDSPM_tcoLock    0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */
-#define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status */
+#define HDSPM_tcoLockMadi    0x00000020 /* Optional TCO locked status for HDSPe MADI*/
+#define HDSPM_tcoSync    0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/
 
-#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */
-#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */
+#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */
+#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */
 
 #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */
 			/* since 64byte accurate, last 6 bits are not used */
@@ -363,7 +473,7 @@
 					 * Interrupt
 					 */
 #define HDSPM_tco_detect         0x08000000
-#define HDSPM_tco_lock	         0x20000000
+#define HDSPM_tcoLockAes         0x20000000 /* Optional TCO locked status for HDSPe AES */
 
 #define HDSPM_s2_tco_detect      0x00000040
 #define HDSPM_s2_AEBO_D          0x00000080
@@ -461,7 +571,9 @@
 #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6
 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7
 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8
-#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9
+#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9
+#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10
+#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11
 
 /*  status2 */
 /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */
@@ -537,36 +649,39 @@
 /* names for speed modes */
 static char *hdspm_speed_names[] = { "single", "double", "quad" };
 
-static char *texts_autosync_aes_tco[] = { "Word Clock",
+static const char *const texts_autosync_aes_tco[] = { "Word Clock",
 					  "AES1", "AES2", "AES3", "AES4",
 					  "AES5", "AES6", "AES7", "AES8",
-					  "TCO" };
-static char *texts_autosync_aes[] = { "Word Clock",
+					  "TCO", "Sync In"
+};
+static const char *const texts_autosync_aes[] = { "Word Clock",
 				      "AES1", "AES2", "AES3", "AES4",
-				      "AES5", "AES6", "AES7", "AES8" };
-static char *texts_autosync_madi_tco[] = { "Word Clock",
+				      "AES5", "AES6", "AES7", "AES8",
+				      "Sync In"
+};
+static const char *const texts_autosync_madi_tco[] = { "Word Clock",
 					   "MADI", "TCO", "Sync In" };
-static char *texts_autosync_madi[] = { "Word Clock",
+static const char *const texts_autosync_madi[] = { "Word Clock",
 				       "MADI", "Sync In" };
 
-static char *texts_autosync_raydat_tco[] = {
+static const char *const texts_autosync_raydat_tco[] = {
 	"Word Clock",
 	"ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
 	"AES", "SPDIF", "TCO", "Sync In"
 };
-static char *texts_autosync_raydat[] = {
+static const char *const texts_autosync_raydat[] = {
 	"Word Clock",
 	"ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4",
 	"AES", "SPDIF", "Sync In"
 };
-static char *texts_autosync_aio_tco[] = {
+static const char *const texts_autosync_aio_tco[] = {
 	"Word Clock",
 	"ADAT", "AES", "SPDIF", "TCO", "Sync In"
 };
-static char *texts_autosync_aio[] = { "Word Clock",
+static const char *const texts_autosync_aio[] = { "Word Clock",
 				      "ADAT", "AES", "SPDIF", "Sync In" };
 
-static char *texts_freq[] = {
+static const char *const texts_freq[] = {
 	"No Lock",
 	"32 kHz",
 	"44.1 kHz",
@@ -629,7 +744,8 @@
 	"AES.L", "AES.R",
 	"SPDIF.L", "SPDIF.R",
 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
-	"ADAT.7", "ADAT.8"
+	"ADAT.7", "ADAT.8",
+	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_ss[] = {
@@ -638,14 +754,16 @@
 	"SPDIF.L", "SPDIF.R",
 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6",
 	"ADAT.7", "ADAT.8",
-	"Phone.L", "Phone.R"
+	"Phone.L", "Phone.R",
+	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_in_ds[] = {
 	"Analogue.L", "Analogue.R",
 	"AES.L", "AES.R",
 	"SPDIF.L", "SPDIF.R",
-	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_ds[] = {
@@ -653,14 +771,16 @@
 	"AES.L", "AES.R",
 	"SPDIF.L", "SPDIF.R",
 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
-	"Phone.L", "Phone.R"
+	"Phone.L", "Phone.R",
+	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_in_qs[] = {
 	"Analogue.L", "Analogue.R",
 	"AES.L", "AES.R",
 	"SPDIF.L", "SPDIF.R",
-	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4"
+	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
+	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aio_out_qs[] = {
@@ -668,7 +788,8 @@
 	"AES.L", "AES.R",
 	"SPDIF.L", "SPDIF.R",
 	"ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4",
-	"Phone.L", "Phone.R"
+	"Phone.L", "Phone.R",
+	"AEB.1", "AEB.2", "AEB.3", "AEB.4"
 };
 
 static char *texts_ports_aes32[] = {
@@ -745,8 +866,8 @@
 	8, 9,			/* aes in, */
 	10, 11,			/* spdif in */
 	12, 13, 14, 15, 16, 17, 18, 19,	/* ADAT in */
-	-1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1,
+	2, 3, 4, 5,		/* AEB */
+	-1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -760,7 +881,8 @@
 	10, 11,			/* spdif out */
 	12, 13, 14, 15, 16, 17, 18, 19,	/* ADAT out */
 	6, 7,			/* phone out */
-	-1, -1, -1, -1, -1, -1, -1, -1,
+	2, 3, 4, 5,		/* AEB */
+	-1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -773,7 +895,8 @@
 	8, 9,			/* aes in */
 	10, 11,			/* spdif in */
 	12, 14, 16, 18,		/* adat in */
-	-1, -1, -1, -1, -1, -1,
+	2, 3, 4, 5,		/* AEB */
+	-1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -788,7 +911,7 @@
 	10, 11,			/* spdif out */
 	12, 14, 16, 18,		/* adat out */
 	6, 7,			/* phone out */
-	-1, -1, -1, -1,
+	2, 3, 4, 5,		/* AEB */
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -802,7 +925,8 @@
 	8, 9,			/* aes in */
 	10, 11,			/* spdif in */
 	12, 16,			/* adat in */
-	-1, -1, -1, -1, -1, -1, -1, -1,
+	2, 3, 4, 5,		/* AEB */
+	-1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -817,7 +941,8 @@
 	10, 11,			/* spdif out */
 	12, 16,			/* adat out */
 	6, 7,			/* phone out */
-	-1, -1, -1, -1, -1, -1,
+	2, 3, 4, 5,		/* AEB */
+	-1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
 	-1, -1, -1, -1, -1, -1, -1, -1,
@@ -856,11 +981,11 @@
 };
 
 struct hdspm_tco {
-	int input;
-	int framerate;
-	int wordclock;
-	int samplerate;
-	int pull;
+	int input; /* 0: LTC, 1:Video, 2: WC*/
+	int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */
+	int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */
+	int samplerate; /* 0=44.1, 1=48, 2= freq from app */
+	int pull; /*   0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/
 	int term; /* 0 = off, 1 = on */
 };
 
@@ -879,7 +1004,7 @@
 
 	u32 control_register;	/* cached value */
 	u32 control2_register;	/* cached value */
-	u32 settings_register;
+	u32 settings_register;  /* cached value for AIO / RayDat (sync reference, master/slave) */
 
 	struct hdspm_midi midi[4];
 	struct tasklet_struct midi_tasklet;
@@ -941,7 +1066,7 @@
 
 	struct hdspm_tco *tco;  /* NULL if no TCO detected */
 
-	char **texts_autosync;
+	const char *const *texts_autosync;
 	int texts_autosync_items;
 
 	cycles_t last_interrupt;
@@ -976,12 +1101,24 @@
 static inline int hdspm_get_pll_freq(struct hdspm *hdspm);
 static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm);
 static int hdspm_autosync_ref(struct hdspm *hdspm);
+static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out);
 static int snd_hdspm_set_defaults(struct hdspm *hdspm);
 static int hdspm_system_clock_mode(struct hdspm *hdspm);
 static void hdspm_set_sgbuf(struct hdspm *hdspm,
 			    struct snd_pcm_substream *substream,
 			     unsigned int reg, int channels);
 
+static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx);
+static int hdspm_wc_sync_check(struct hdspm *hdspm);
+static int hdspm_tco_sync_check(struct hdspm *hdspm);
+static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
+
+static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index);
+static int hdspm_get_tco_sample_rate(struct hdspm *hdspm);
+static int hdspm_get_wc_sample_rate(struct hdspm *hdspm);
+
+
+
 static inline int HDSPM_bit2freq(int n)
 {
 	static const int bit2freq_tab[] = {
@@ -992,6 +1129,12 @@
 	return bit2freq_tab[n];
 }
 
+static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm)
+{
+	return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type));
+}
+
+
 /* Write/read to/from HDSPM with Adresses in Bytes
    not words but only 32Bit writes are allowed */
 
@@ -1107,14 +1250,11 @@
 		else if (hdspm->control_register &
 				HDSPM_DoubleSpeed)
 			return rate * 2;
-	};
+	}
 	return rate;
 }
 
-static int hdspm_tco_sync_check(struct hdspm *hdspm);
-static int hdspm_sync_in_sync_check(struct hdspm *hdspm);
-
-/* check for external sample rate */
+/* check for external sample rate, returns the sample rate in Hz*/
 static int hdspm_external_sample_rate(struct hdspm *hdspm)
 {
 	unsigned int status, status2, timecode;
@@ -1127,17 +1267,36 @@
 		timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
 		syncref = hdspm_autosync_ref(hdspm);
+		switch (syncref) {
+		case HDSPM_AES32_AUTOSYNC_FROM_WORD:
+		/* Check WC sync and get sample rate */
+			if (hdspm_wc_sync_check(hdspm))
+				return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm));
+			break;
 
-		if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD &&
-				status & HDSPM_AES32_wcLock)
-			return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF);
+		case HDSPM_AES32_AUTOSYNC_FROM_AES1:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES2:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES3:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES4:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES5:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES6:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES7:
+		case HDSPM_AES32_AUTOSYNC_FROM_AES8:
+		/* Check AES sync and get sample rate */
+			if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))
+				return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm,
+							syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1));
+			break;
 
-		if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 &&
-				syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 &&
-				status2 & (HDSPM_LockAES >>
-				(syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)))
-			return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF);
-		return 0;
+
+		case HDSPM_AES32_AUTOSYNC_FROM_TCO:
+		/* Check TCO sync and get sample rate */
+			if (hdspm_tco_sync_check(hdspm))
+				return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm));
+			break;
+		default:
+			return 0;
+		} /* end switch(syncref) */
 		break;
 
 	case MADIface:
@@ -2129,6 +2288,9 @@
 		status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
 		return (status >> 16) & 0xF;
 		break;
+	case AES32:
+		status = hdspm_read(hdspm, HDSPM_statusRegister);
+		return (status >> HDSPM_AES32_wcFreq_bit) & 0xF;
 	default:
 		break;
 	}
@@ -2152,6 +2314,9 @@
 			status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
 			return (status >> 20) & 0xF;
 			break;
+		case AES32:
+			status = hdspm_read(hdspm, HDSPM_statusRegister);
+			return (status >> 1) & 0xF;
 		default:
 			break;
 		}
@@ -2183,6 +2348,23 @@
 	return 0;
 }
 
+/**
+ * Returns the AES sample rate class for the given card.
+ **/
+static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
+{
+	int timecode;
+
+	switch (hdspm->io_type) {
+	case AES32:
+		timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
+		return (timecode >> (4*index)) & 0xF;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
 
 /**
  * Returns the sample rate class for input source <idx> for
@@ -2196,16 +2378,24 @@
 }
 
 #define ENUMERATED_CTL_INFO(info, texts) \
-{ \
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; \
-	uinfo->count = 1; \
-	uinfo->value.enumerated.items = ARRAY_SIZE(texts); \
-	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) \
-		uinfo->value.enumerated.item =	uinfo->value.enumerated.items - 1; \
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); \
-}
+	snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts)
 
 
+/* Helper function to query the external sample rate and return the
+ * corresponding enum to be returned to userspace.
+ */
+static int hdspm_external_rate_to_enum(struct hdspm *hdspm)
+{
+	int rate = hdspm_external_sample_rate(hdspm);
+	int i, selected_rate = 0;
+	for (i = 1; i < 10; i++)
+		if (HDSPM_bit2freq(i) == rate) {
+			selected_rate = i;
+			break;
+		}
+	return selected_rate;
+}
+
 
 #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
@@ -2270,7 +2460,7 @@
 		default:
 			ucontrol->value.enumerated.item[0] =
 				hdspm_get_s1_sample_rate(hdspm,
-						ucontrol->id.index-1);
+						kcontrol->private_value-1);
 		}
 		break;
 
@@ -2289,28 +2479,24 @@
 			ucontrol->value.enumerated.item[0] =
 				hdspm_get_sync_in_sample_rate(hdspm);
 			break;
+		case 11: /* External Rate */
+			ucontrol->value.enumerated.item[0] =
+				hdspm_external_rate_to_enum(hdspm);
+			break;
 		default: /* AES1 to AES8 */
 			ucontrol->value.enumerated.item[0] =
-				hdspm_get_s1_sample_rate(hdspm,
-						kcontrol->private_value-1);
+				hdspm_get_aes_sample_rate(hdspm,
+						kcontrol->private_value -
+						HDSPM_AES32_AUTOSYNC_FROM_AES1);
 			break;
 		}
 		break;
 
 	case MADI:
 	case MADIface:
-		{
-			int rate = hdspm_external_sample_rate(hdspm);
-			int i, selected_rate = 0;
-			for (i = 1; i < 10; i++)
-				if (HDSPM_bit2freq(i) == rate) {
-					selected_rate = i;
-					break;
-				}
-			ucontrol->value.enumerated.item[0] = selected_rate;
-		}
+		ucontrol->value.enumerated.item[0] =
+			hdspm_external_rate_to_enum(hdspm);
 		break;
-
 	default:
 		break;
 	}
@@ -2359,33 +2545,17 @@
  **/
 static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
 {
-	switch (hdspm->io_type) {
-	case AIO:
-	case RayDAT:
-		if (0 == mode)
-			hdspm->settings_register |= HDSPM_c0Master;
-		else
-			hdspm->settings_register &= ~HDSPM_c0Master;
-
-		hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
-		break;
-
-	default:
-		if (0 == mode)
-			hdspm->control_register |= HDSPM_ClockModeMaster;
-		else
-			hdspm->control_register &= ~HDSPM_ClockModeMaster;
-
-		hdspm_write(hdspm, HDSPM_controlRegister,
-				hdspm->control_register);
-	}
+	hdspm_set_toggle_setting(hdspm,
+			(hdspm_is_raydat_or_aio(hdspm)) ?
+			HDSPM_c0Master : HDSPM_ClockModeMaster,
+			(0 == mode));
 }
 
 
 static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol,
 					    struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "Master", "AutoSync" };
+	static const char *const texts[] = { "Master", "AutoSync" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -2809,16 +2979,7 @@
 {
 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = hdspm->texts_autosync_items;
-
-	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-		uinfo->value.enumerated.item =
-			uinfo->value.enumerated.items - 1;
-
-	strcpy(uinfo->value.enumerated.name,
-			hdspm->texts_autosync[uinfo->value.enumerated.item]);
+	snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync);
 
 	return 0;
 }
@@ -2873,19 +3034,20 @@
 
 static int hdspm_autosync_ref(struct hdspm *hdspm)
 {
+	/* This looks at the autosync selected sync reference */
 	if (AES32 == hdspm->io_type) {
-		unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
-		unsigned int syncref =
-			(status >> HDSPM_AES32_syncref_bit) & 0xF;
-		if (syncref == 0)
-			return HDSPM_AES32_AUTOSYNC_FROM_WORD;
-		if (syncref <= 8)
-			return syncref;
-		return HDSPM_AES32_AUTOSYNC_FROM_NONE;
-	} else if (MADI == hdspm->io_type) {
-		/* This looks at the autosync selected sync reference */
-		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
 
+		unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister);
+		unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF;
+		if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) &&
+				(syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) {
+			return syncref;
+		}
+		return HDSPM_AES32_AUTOSYNC_FROM_NONE;
+
+	} else if (MADI == hdspm->io_type) {
+
+		unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
 		switch (status2 & HDSPM_SelSyncRefMask) {
 		case HDSPM_SelSyncRef_WORD:
 			return HDSPM_AUTOSYNC_FROM_WORD;
@@ -2898,7 +3060,7 @@
 		case HDSPM_SelSyncRef_NVALID:
 			return HDSPM_AUTOSYNC_FROM_NONE;
 		default:
-			return 0;
+			return HDSPM_AUTOSYNC_FROM_NONE;
 		}
 
 	}
@@ -2912,31 +3074,15 @@
 	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
 	if (AES32 == hdspm->io_type) {
-		static char *texts[] = { "WordClock", "AES1", "AES2", "AES3",
-			"AES4",	"AES5", "AES6", "AES7", "AES8", "None"};
+		static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3",
+			"AES4",	"AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"};
 
-		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-		uinfo->count = 1;
-		uinfo->value.enumerated.items = 10;
-		if (uinfo->value.enumerated.item >=
-		    uinfo->value.enumerated.items)
-			uinfo->value.enumerated.item =
-				uinfo->value.enumerated.items - 1;
-		strcpy(uinfo->value.enumerated.name,
-				texts[uinfo->value.enumerated.item]);
+		ENUMERATED_CTL_INFO(uinfo, texts);
 	} else if (MADI == hdspm->io_type) {
-		static char *texts[] = {"Word Clock", "MADI", "TCO",
+		static const char *const texts[] = {"Word Clock", "MADI", "TCO",
 			"Sync In", "None" };
 
-		uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-		uinfo->count = 1;
-		uinfo->value.enumerated.items = 5;
-		if (uinfo->value.enumerated.item >=
-				uinfo->value.enumerated.items)
-			uinfo->value.enumerated.item =
-				uinfo->value.enumerated.items - 1;
-		strcpy(uinfo->value.enumerated.name,
-				texts[uinfo->value.enumerated.item]);
+		ENUMERATED_CTL_INFO(uinfo, texts);
 	}
 	return 0;
 }
@@ -2964,7 +3110,7 @@
 static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {"No video", "NTSC", "PAL"};
+	static const char *const texts[] = {"No video", "NTSC", "PAL"};
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3010,7 +3156,7 @@
 static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
+	static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps",
 				"30 fps"};
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
@@ -3027,19 +3173,19 @@
 					HDSPM_TCO1_LTC_Format_MSB)) {
 		case 0:
 			/* 24 fps */
-			ret = 1;
+			ret = fps_24;
 			break;
 		case HDSPM_TCO1_LTC_Format_LSB:
 			/* 25 fps */
-			ret = 2;
+			ret = fps_25;
 			break;
 		case HDSPM_TCO1_LTC_Format_MSB:
-			/* 25 fps */
-			ret = 3;
+			/* 29.97 fps */
+			ret = fps_2997;
 			break;
 		default:
 			/* 30 fps */
-			ret = 4;
+			ret = fps_30;
 			break;
 		}
 	}
@@ -3067,16 +3213,35 @@
 
 static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask)
 {
-	return (hdspm->control_register & regmask) ? 1 : 0;
+	u32 reg;
+
+	if (hdspm_is_raydat_or_aio(hdspm))
+		reg = hdspm->settings_register;
+	else
+		reg = hdspm->control_register;
+
+	return (reg & regmask) ? 1 : 0;
 }
 
 static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out)
 {
+	u32 *reg;
+	u32 target_reg;
+
+	if (hdspm_is_raydat_or_aio(hdspm)) {
+		reg = &(hdspm->settings_register);
+		target_reg = HDSPM_WR_SETTINGS;
+	} else {
+		reg = &(hdspm->control_register);
+		target_reg = HDSPM_controlRegister;
+	}
+
 	if (out)
-		hdspm->control_register |= regmask;
+		*reg |= regmask;
 	else
-		hdspm->control_register &= ~regmask;
-	hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register);
+		*reg &= ~regmask;
+
+	hdspm_write(hdspm, target_reg, *reg);
 
 	return 0;
 }
@@ -3141,7 +3306,7 @@
 static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "optical", "coaxial" };
+	static const char *const texts[] = { "optical", "coaxial" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3203,7 +3368,7 @@
 static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "Single", "Double" };
+	static const char *const texts[] = { "Single", "Double" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3276,7 +3441,7 @@
 static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "Single", "Double", "Quad" };
+	static const char *const texts[] = { "Single", "Double", "Quad" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3313,6 +3478,84 @@
 	return change;
 }
 
+#define HDSPM_CONTROL_TRISTATE(xname, xindex) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	.name = xname, \
+	.private_value = xindex, \
+	.info = snd_hdspm_info_tristate, \
+	.get = snd_hdspm_get_tristate, \
+	.put = snd_hdspm_put_tristate \
+}
+
+static int hdspm_tristate(struct hdspm *hdspm, u32 regmask)
+{
+	u32 reg = hdspm->settings_register & (regmask * 3);
+	return reg / regmask;
+}
+
+static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask)
+{
+	hdspm->settings_register &= ~(regmask * 3);
+	hdspm->settings_register |= (regmask * mode);
+	hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
+
+	return 0;
+}
+
+static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	u32 regmask = kcontrol->private_value;
+
+	static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" };
+	static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" };
+
+	switch (regmask) {
+	case HDSPM_c0_Input0:
+		ENUMERATED_CTL_INFO(uinfo, texts_spdif);
+		break;
+	default:
+		ENUMERATED_CTL_INFO(uinfo, texts_levels);
+		break;
+	}
+	return 0;
+}
+
+static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	u32 regmask = kcontrol->private_value;
+
+	spin_lock_irq(&hdspm->lock);
+	ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask);
+	spin_unlock_irq(&hdspm->lock);
+	return 0;
+}
+
+static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+	u32 regmask = kcontrol->private_value;
+	int change;
+	int val;
+
+	if (!snd_hdspm_use_is_exclusive(hdspm))
+		return -EBUSY;
+	val = ucontrol->value.integer.value[0];
+	if (val < 0)
+		val = 0;
+	if (val > 2)
+		val = 2;
+
+	spin_lock_irq(&hdspm->lock);
+	change = val != hdspm_tristate(hdspm, regmask);
+	hdspm_set_tristate(hdspm, val, regmask);
+	spin_unlock_irq(&hdspm->lock);
+	return change;
+}
+
 #define HDSPM_MADI_SPEEDMODE(xname, xindex) \
 {	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
 	.name = xname, \
@@ -3352,7 +3595,7 @@
 static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol,
 				       struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "Single", "Double", "Quad" };
+	static const char *const texts[] = { "Single", "Double", "Quad" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3587,7 +3830,7 @@
 static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" };
+	static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3595,7 +3838,7 @@
 static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol,
 				     struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "No Lock", "Lock" };
+	static const char *const texts[] = { "No Lock", "Lock" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -3745,9 +3988,18 @@
 	if (hdspm->tco) {
 		switch (hdspm->io_type) {
 		case MADI:
+			status = hdspm_read(hdspm, HDSPM_statusRegister);
+			if (status & HDSPM_tcoLockMadi) {
+				if (status & HDSPM_tcoSync)
+					return 2;
+				else
+					return 1;
+			}
+			return 0;
+			break;
 		case AES32:
 			status = hdspm_read(hdspm, HDSPM_statusRegister);
-			if (status & HDSPM_tcoLock) {
+			if (status & HDSPM_tcoLockAes) {
 				if (status & HDSPM_tcoSync)
 					return 2;
 				else
@@ -3807,7 +4059,8 @@
 		case 5: /* SYNC IN */
 			val = hdspm_sync_in_sync_check(hdspm); break;
 		default:
-			val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1);
+			val = hdspm_s1_sync_check(hdspm,
+					kcontrol->private_value-1);
 		}
 		break;
 
@@ -3975,7 +4228,8 @@
 static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol,
 					  struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "44.1 kHz", "48 kHz" };
+	/* TODO freq from app could be supported here, see tco->samplerate */
+	static const char *const texts[] = { "44.1 kHz", "48 kHz" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -4021,7 +4275,8 @@
 static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol,
 				   struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" };
+	static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %",
+		"+ 4 %", "- 4 %" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -4066,7 +4321,7 @@
 static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol,
 					     struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
+	static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -4112,7 +4367,7 @@
 static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol,
 					  struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "24 fps", "25 fps", "29.97fps",
+	static const char *const texts[] = { "24 fps", "25 fps", "29.97fps",
 		"29.97 dfps", "30 fps", "30 dfps" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
@@ -4159,7 +4414,7 @@
 static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol,
 					  struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[] = { "LTC", "Video", "WCK" };
+	static const char *const texts[] = { "LTC", "Video", "WCK" };
 	ENUMERATED_CTL_INFO(uinfo, texts);
 	return 0;
 }
@@ -4284,7 +4539,6 @@
 	HDSPM_INTERNAL_CLOCK("Internal Clock", 0),
 	HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
 	HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
-	HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
 	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
 	HDSPM_SYNC_CHECK("WC SyncCheck", 0),
@@ -4298,7 +4552,16 @@
 	HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2),
 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3),
 	HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4),
-	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5)
+	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5),
+	HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0),
+	HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt),
+	HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
+	HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1),
+	HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db),
+	HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48),
+	HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0),
+	HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0),
+	HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0)
 
 		/*
 		   HDSPM_INPUT_SELECT("Input Select", 0),
@@ -4335,7 +4598,9 @@
 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5),
 	HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6),
 	HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7),
-	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8)
+	HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8),
+	HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro),
+	HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48)
 };
 
 static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = {
@@ -4345,7 +4610,7 @@
 	HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0),
 	HDSPM_AUTOSYNC_REF("AutoSync Reference", 0),
 	HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
-	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0),
+	HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11),
 	HDSPM_SYNC_CHECK("WC Sync Check", 0),
 	HDSPM_SYNC_CHECK("AES1 Sync Check", 1),
 	HDSPM_SYNC_CHECK("AES2 Sync Check", 2),
@@ -4501,77 +4766,22 @@
  ------------------------------------------------------------*/
 
 static void
-snd_hdspm_proc_read_madi(struct snd_info_entry * entry,
-			 struct snd_info_buffer *buffer)
+snd_hdspm_proc_read_tco(struct snd_info_entry *entry,
+					struct snd_info_buffer *buffer)
 {
 	struct hdspm *hdspm = entry->private_data;
-	unsigned int status, status2, control, freq;
-
-	char *pref_sync_ref;
-	char *autosync_ref;
-	char *system_clock_mode;
-	char *insel;
-	int x, x2;
-
-	/* TCO stuff */
+	unsigned int status, control;
 	int a, ltc, frames, seconds, minutes, hours;
 	unsigned int period;
 	u64 freq_const = 0;
 	u32 rate;
 
+	snd_iprintf(buffer, "--- TCO ---\n");
+
 	status = hdspm_read(hdspm, HDSPM_statusRegister);
-	status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
 	control = hdspm->control_register;
-	freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
 
-	snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
-			hdspm->card_name, hdspm->card->number + 1,
-			hdspm->firmware_rev,
-			(status2 & HDSPM_version0) |
-			(status2 & HDSPM_version1) | (status2 &
-				HDSPM_version2));
 
-	snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
-			(hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
-			hdspm->serial);
-
-	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
-			hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
-
-	snd_iprintf(buffer, "--- System ---\n");
-
-	snd_iprintf(buffer,
-		"IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
-		status & HDSPM_audioIRQPending,
-		(status & HDSPM_midi0IRQPending) ? 1 : 0,
-		(status & HDSPM_midi1IRQPending) ? 1 : 0,
-		hdspm->irq_count);
-	snd_iprintf(buffer,
-		"HW pointer: id = %d, rawptr = %d (%d->%d) "
-		"estimated= %ld (bytes)\n",
-		((status & HDSPM_BufferID) ? 1 : 0),
-		(status & HDSPM_BufferPositionMask),
-		(status & HDSPM_BufferPositionMask) %
-		(2 * (int)hdspm->period_bytes),
-		((status & HDSPM_BufferPositionMask) - 64) %
-		(2 * (int)hdspm->period_bytes),
-		(long) hdspm_hw_pointer(hdspm) * 4);
-
-	snd_iprintf(buffer,
-		"MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
-		hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
-		hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
-		hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
-		hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
-	snd_iprintf(buffer,
-		"MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
-		hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
-		hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
-	snd_iprintf(buffer,
-		"Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
-		"status2=0x%x\n",
-		hdspm->control_register, hdspm->control2_register,
-		status, status2);
 	if (status & HDSPM_tco_detect) {
 		snd_iprintf(buffer, "TCO module detected.\n");
 		a = hdspm_read(hdspm, HDSPM_RD_TCO+4);
@@ -4665,6 +4875,75 @@
 	} else {
 		snd_iprintf(buffer, "No TCO module detected.\n");
 	}
+}
+
+static void
+snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
+			 struct snd_info_buffer *buffer)
+{
+	struct hdspm *hdspm = entry->private_data;
+	unsigned int status, status2, control, freq;
+
+	char *pref_sync_ref;
+	char *autosync_ref;
+	char *system_clock_mode;
+	char *insel;
+	int x, x2;
+
+	status = hdspm_read(hdspm, HDSPM_statusRegister);
+	status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
+	control = hdspm->control_register;
+	freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
+
+	snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
+			hdspm->card_name, hdspm->card->number + 1,
+			hdspm->firmware_rev,
+			(status2 & HDSPM_version0) |
+			(status2 & HDSPM_version1) | (status2 &
+				HDSPM_version2));
+
+	snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n",
+			(hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF,
+			hdspm->serial);
+
+	snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n",
+			hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase);
+
+	snd_iprintf(buffer, "--- System ---\n");
+
+	snd_iprintf(buffer,
+		"IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n",
+		status & HDSPM_audioIRQPending,
+		(status & HDSPM_midi0IRQPending) ? 1 : 0,
+		(status & HDSPM_midi1IRQPending) ? 1 : 0,
+		hdspm->irq_count);
+	snd_iprintf(buffer,
+		"HW pointer: id = %d, rawptr = %d (%d->%d) "
+		"estimated= %ld (bytes)\n",
+		((status & HDSPM_BufferID) ? 1 : 0),
+		(status & HDSPM_BufferPositionMask),
+		(status & HDSPM_BufferPositionMask) %
+		(2 * (int)hdspm->period_bytes),
+		((status & HDSPM_BufferPositionMask) - 64) %
+		(2 * (int)hdspm->period_bytes),
+		(long) hdspm_hw_pointer(hdspm) * 4);
+
+	snd_iprintf(buffer,
+		"MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n",
+		hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF,
+		hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF,
+		hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF,
+		hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF);
+	snd_iprintf(buffer,
+		"MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n",
+		hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF,
+		hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF);
+	snd_iprintf(buffer,
+		"Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, "
+		"status2=0x%x\n",
+		hdspm->control_register, hdspm->control2_register,
+		status, status2);
+
 
 	snd_iprintf(buffer, "--- Settings ---\n");
 
@@ -4768,6 +5047,9 @@
 		(status & HDSPM_RX_64ch) ? "64 channels" :
 		"56 channels");
 
+	/* call readout function for TCO specific status */
+	snd_hdspm_proc_read_tco(entry, buffer);
+
 	snd_iprintf(buffer, "\n");
 }
 
@@ -4909,11 +5191,18 @@
 		autosync_ref = "AES7"; break;
 	case HDSPM_AES32_AUTOSYNC_FROM_AES8:
 		autosync_ref = "AES8"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_TCO:
+		autosync_ref = "TCO"; break;
+	case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN:
+		autosync_ref = "Sync In"; break;
 	default:
 		autosync_ref = "---"; break;
 	}
 	snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref);
 
+	/* call readout function for TCO specific status */
+	snd_hdspm_proc_read_tco(entry, buffer);
+
 	snd_iprintf(buffer, "\n");
 }
 
@@ -5097,7 +5386,7 @@
 
 	case AES32:
 		hdspm->control_register =
-			HDSPM_ClockModeMaster |	/* Master Cloack Mode on */
+			HDSPM_ClockModeMaster |	/* Master Clock Mode on */
 			hdspm_encode_latency(7) | /* latency max=8192samples */
 			HDSPM_SyncRef0 |	/* AES1 is syncclock */
 			HDSPM_LineOut |	/* Analog output in */
@@ -5123,9 +5412,8 @@
 
 	all_in_all_mixer(hdspm, 0 * UNITY_GAIN);
 
-	if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) {
+	if (hdspm_is_raydat_or_aio(hdspm))
 		hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register);
-	}
 
 	/* set a default rate so that the channel map is set up. */
 	hdspm_set_rate(hdspm, 48000, 1);
@@ -5371,6 +5659,16 @@
 	   */
 
 
+	/*  For AES cards, the float format bit is the same as the
+	 *  preferred sync reference. Since we don't want to break
+	 *  sync settings, we have to skip the remaining part of this
+	 *  function.
+	 */
+	if (hdspm->io_type == AES32) {
+		return 0;
+	}
+
+
 	/* Switch to native float format if requested */
 	if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) {
 		if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT))
@@ -6013,7 +6311,7 @@
 				ltc.format = fps_2997;
 				break;
 			default:
-				ltc.format = 30;
+				ltc.format = fps_30;
 				break;
 			}
 			if (i & HDSPM_TCO1_set_drop_frame_flag) {
@@ -6479,10 +6777,6 @@
 		break;
 
 	case AIO:
-		if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
-			snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n");
-		}
-
 		hdspm->ss_in_channels = AIO_IN_SS_CHANNELS;
 		hdspm->ds_in_channels = AIO_IN_DS_CHANNELS;
 		hdspm->qs_in_channels = AIO_IN_QS_CHANNELS;
@@ -6490,6 +6784,20 @@
 		hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS;
 		hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS;
 
+		if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) {
+			snd_printk(KERN_INFO "HDSPM: AEB input board found\n");
+			hdspm->ss_in_channels += 4;
+			hdspm->ds_in_channels += 4;
+			hdspm->qs_in_channels += 4;
+		}
+
+		if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) {
+			snd_printk(KERN_INFO "HDSPM: AEB output board found\n");
+			hdspm->ss_out_channels += 4;
+			hdspm->ds_out_channels += 4;
+			hdspm->qs_out_channels += 4;
+		}
+
 		hdspm->channel_map_out_ss = channel_map_aio_out_ss;
 		hdspm->channel_map_out_ds = channel_map_aio_out_ds;
 		hdspm->channel_map_out_qs = channel_map_aio_out_qs;
@@ -6558,6 +6866,7 @@
 		break;
 
 	case MADI:
+	case AES32:
 		if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) {
 			hdspm->midiPorts++;
 			hdspm->tco = kzalloc(sizeof(struct hdspm_tco),
@@ -6565,7 +6874,7 @@
 			if (NULL != hdspm->tco) {
 				hdspm_tco_write(hdspm);
 			}
-			snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n");
+			snd_printk(KERN_INFO "HDSPM: MADI/AES TCO module found\n");
 		} else {
 			hdspm->tco = NULL;
 		}
@@ -6580,10 +6889,12 @@
 	case AES32:
 		if (hdspm->tco) {
 			hdspm->texts_autosync = texts_autosync_aes_tco;
-			hdspm->texts_autosync_items = 10;
+			hdspm->texts_autosync_items =
+				ARRAY_SIZE(texts_autosync_aes_tco);
 		} else {
 			hdspm->texts_autosync = texts_autosync_aes;
-			hdspm->texts_autosync_items = 9;
+			hdspm->texts_autosync_items =
+				ARRAY_SIZE(texts_autosync_aes);
 		}
 		break;
 
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 45eeaa9..5138b84 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -26,12 +26,9 @@
 config SND_SOC_AC97_BUS
 	bool
 
-config SND_SOC_DMAENGINE_PCM
-	bool
-
 config SND_SOC_GENERIC_DMAENGINE_PCM
 	bool
-	select SND_SOC_DMAENGINE_PCM
+	select SND_DMAENGINE_PCM
 
 # All the supported SoCs
 source "sound/soc/atmel/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index bc02614..61a64d2 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,10 +1,6 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
 
-ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),)
-snd-soc-core-objs += soc-dmaengine-pcm.o
-endif
-
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 endif
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 3fdd87f..e48d38a 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -13,6 +13,7 @@
 config SND_ATMEL_SOC_DMA
 	tristate
 	depends on SND_ATMEL_SOC
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_ATMEL_SOC_SSC
 	tristate
@@ -32,6 +33,26 @@
 	  Say Y if you want to add support for SoC audio on WM8731-based
 	  AT91sam9g20 evaluation board.
 
+config SND_ATMEL_SOC_WM8904
+	tristate "Atmel ASoC driver for boards using WM8904 codec"
+	depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+	select SND_ATMEL_SOC_SSC
+	select SND_ATMEL_SOC_DMA
+	select SND_SOC_WM8904
+	help
+	  Say Y if you want to add support for Atmel ASoC driver for boards using
+	  WM8904 codec.
+
+config SND_AT91_SOC_SAM9X5_WM8731
+	tristate "SoC Audio support for WM8731-based at91sam9x5 board"
+	depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5
+	select SND_ATMEL_SOC_SSC
+	select SND_ATMEL_SOC_DMA
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for audio SoC on an
+	  at91sam9x5 based board that is using WM8731 codec.
+
 config SND_AT91_SOC_AFEB9260
 	tristate "SoC Audio support for AFEB9260 board"
 	depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 41967cc..5baabc8 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -11,6 +11,10 @@
 
 # AT91 Machine Support
 snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
+snd-atmel-soc-wm8904-objs := atmel_wm8904.o
+snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
+obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
+obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index d128265..06082e5 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -91,138 +91,52 @@
 	}
 }
 
-/*--------------------------------------------------------------------------*\
- * DMAENGINE operations
-\*--------------------------------------------------------------------------*/
-static bool filter(struct dma_chan *chan, void *slave)
-{
-	struct at_dma_slave *sl = slave;
-
-	if (sl->dma_dev == chan->device->dev) {
-		chan->private = sl;
-		return true;
-	} else {
-		return false;
-	}
-}
-
 static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
+	struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct atmel_pcm_dma_params *prtd;
 	struct ssc_device *ssc;
-	struct dma_chan *dma_chan;
-	struct dma_slave_config slave_config;
 	int ret;
 
+	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 	ssc = prtd->ssc;
 
-	ret = snd_hwparams_to_dma_slave_config(substream, params,
-			&slave_config);
+	ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
 	if (ret) {
 		pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
 		return ret;
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR;
-		slave_config.dst_maxburst = 1;
+		slave_config->dst_addr = ssc->phybase + SSC_THR;
+		slave_config->dst_maxburst = 1;
 	} else {
-		slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR;
-		slave_config.src_maxburst = 1;
-	}
-
-	dma_chan = snd_dmaengine_pcm_get_chan(substream);
-	if (dmaengine_slave_config(dma_chan, &slave_config)) {
-		pr_err("atmel-pcm: failed to configure dma channel\n");
-		ret = -EBUSY;
-		return ret;
-	}
-
-	return 0;
-}
-
-static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
-	struct snd_pcm_hw_params *params)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct atmel_pcm_dma_params *prtd;
-	struct ssc_device *ssc;
-	struct at_dma_slave *sdata = NULL;
-	int ret;
-
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	ssc = prtd->ssc;
-	if (ssc->pdev)
-		sdata = ssc->pdev->dev.platform_data;
-
-	ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
-	if (ret) {
-		pr_err("atmel-pcm: dmaengine pcm open failed\n");
-		return -EINVAL;
-	}
-
-	ret = atmel_pcm_configure_dma(substream, params, prtd);
-	if (ret) {
-		pr_err("atmel-pcm: failed to configure dmai\n");
-		goto err;
+		slave_config->src_addr = ssc->phybase + SSC_RHR;
+		slave_config->src_maxburst = 1;
 	}
 
 	prtd->dma_intr_handler = atmel_pcm_dma_irq;
 
 	return 0;
-err:
-	snd_dmaengine_pcm_close_release_chan(substream);
-	return ret;
 }
 
-static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct atmel_pcm_dma_params *prtd;
-
-	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-	ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
-	ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
-
-	return 0;
-}
-
-static int atmel_pcm_open(struct snd_pcm_substream *substream)
-{
-	snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware);
-
-	return 0;
-}
-
-static struct snd_pcm_ops atmel_pcm_ops = {
-	.open		= atmel_pcm_open,
-	.close		= snd_dmaengine_pcm_close_release_chan,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= atmel_pcm_hw_params,
-	.prepare	= atmel_pcm_dma_prepare,
-	.trigger	= snd_dmaengine_pcm_trigger,
-	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
-	.mmap		= atmel_pcm_mmap,
-};
-
-static struct snd_soc_platform_driver atmel_soc_platform = {
-	.ops		= &atmel_pcm_ops,
-	.pcm_new	= atmel_pcm_new,
-	.pcm_free	= atmel_pcm_free,
+static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
+	.prepare_slave_config = atmel_pcm_configure_dma,
+	.pcm_hardware = &atmel_pcm_dma_hardware,
+	.prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE,
 };
 
 int atmel_pcm_dma_platform_register(struct device *dev)
 {
-	return snd_soc_register_platform(dev, &atmel_soc_platform);
+	return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
+			SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
 
 void atmel_pcm_dma_platform_unregister(struct device *dev)
 {
-	snd_soc_unregister_platform(dev);
+	snd_dmaengine_pcm_unregister(dev);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister);
 
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index f3fdfa0..0ecf356 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -73,6 +73,7 @@
 	.ssc_disable	= SSC_BIT(CR_TXDIS),
 	.ssc_endx	= SSC_BIT(SR_ENDTX),
 	.ssc_endbuf	= SSC_BIT(SR_TXBUFE),
+	.ssc_error	= SSC_BIT(SR_OVRUN),
 	.pdc_enable	= ATMEL_PDC_TXTEN,
 	.pdc_disable	= ATMEL_PDC_TXTDIS,
 };
@@ -82,6 +83,7 @@
 	.ssc_disable	= SSC_BIT(CR_RXDIS),
 	.ssc_endx	= SSC_BIT(SR_ENDRX),
 	.ssc_endbuf	= SSC_BIT(SR_RXBUFF),
+	.ssc_error	= SSC_BIT(SR_OVRUN),
 	.pdc_enable	= ATMEL_PDC_RXTEN,
 	.pdc_disable	= ATMEL_PDC_RXTDIS,
 };
@@ -196,15 +198,27 @@
 			     struct snd_soc_dai *dai)
 {
 	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
-	int dir_mask;
+	struct atmel_pcm_dma_params *dma_params;
+	int dir, dir_mask;
 
 	pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
 		ssc_readl(ssc_p->ssc->regs, SR));
 
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dir = 0;
 		dir_mask = SSC_DIR_MASK_PLAYBACK;
-	else
+	} else {
+		dir = 1;
 		dir_mask = SSC_DIR_MASK_CAPTURE;
+	}
+
+	dma_params = &ssc_dma_params[dai->id][dir];
+	dma_params->ssc = ssc_p->ssc;
+	dma_params->substream = substream;
+
+	ssc_p->dma_params[dir] = dma_params;
+
+	snd_soc_dai_set_dma_data(dai, substream, dma_params);
 
 	spin_lock_irq(&ssc_p->lock);
 	if (ssc_p->dir_mask & dir_mask) {
@@ -325,7 +339,6 @@
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
 	int id = dai->id;
 	struct atmel_ssc_info *ssc_p = &ssc_info[id];
 	struct atmel_pcm_dma_params *dma_params;
@@ -344,19 +357,7 @@
 	else
 		dir = 1;
 
-	dma_params = &ssc_dma_params[id][dir];
-	dma_params->ssc = ssc_p->ssc;
-	dma_params->substream = substream;
-
-	ssc_p->dma_params[dir] = dma_params;
-
-	/*
-	 * The snd_soc_pcm_stream->dma_data field is only used to communicate
-	 * the appropriate DMA parameters to the pcm driver hw_params()
-	 * function.  It should not be used for other purposes
-	 * as it is common to all substreams.
-	 */
-	snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
+	dma_params = ssc_p->dma_params[dir];
 
 	channels = params_channels(params);
 
@@ -648,6 +649,7 @@
 	dma_params = ssc_p->dma_params[dir];
 
 	ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+	ssc_writel(ssc_p->ssc->regs, IER, dma_params->mask->ssc_error);
 
 	pr_debug("%s enabled SSC_SR=0x%08x\n",
 			dir ? "receive" : "transmit",
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
new file mode 100644
index 0000000..7222380
--- /dev/null
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -0,0 +1,254 @@
+/*
+ * atmel_wm8904 - Atmel ASoC driver for boards with WM8904 codec.
+ *
+ * Copyright (C) 2012 Atmel
+ *
+ * Author: Bo Shen <voice.shen@atmel.com>
+ *
+ * GPLv2 or later
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <sound/soc.h>
+
+#include "../codecs/wm8904.h"
+#include "atmel_ssc_dai.h"
+
+#define MCLK_RATE 32768
+
+static struct clk *mclk;
+
+static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+};
+
+static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK,
+		32768, params_rate(params) * 256);
+	if (ret < 0) {
+		pr_err("%s - failed to set wm8904 codec PLL.", __func__);
+		return ret;
+	}
+
+	/*
+	 * As here wm8904 use FLL output as its system clock
+	 * so calling set_sysclk won't care freq parameter
+	 * then we pass 0
+	 */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8904_CLK_FLL,
+			0, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		pr_err("%s -failed to set wm8904 SYSCLK\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops atmel_asoc_wm8904_ops = {
+	.hw_params = atmel_asoc_wm8904_hw_params,
+};
+
+static int atmel_set_bias_level(struct snd_soc_card *card,
+		struct snd_soc_dapm_context *dapm,
+		enum snd_soc_bias_level level)
+{
+	if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+		switch (level) {
+		case SND_SOC_BIAS_PREPARE:
+			clk_prepare_enable(mclk);
+			break;
+		case SND_SOC_BIAS_OFF:
+			clk_disable_unprepare(mclk);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+};
+
+static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = {
+	.name = "WM8904",
+	.stream_name = "WM8904 PCM",
+	.codec_dai_name = "wm8904-hifi",
+	.dai_fmt = SND_SOC_DAIFMT_I2S
+		| SND_SOC_DAIFMT_NB_NF
+		| SND_SOC_DAIFMT_CBM_CFM,
+	.ops = &atmel_asoc_wm8904_ops,
+};
+
+static struct snd_soc_card atmel_asoc_wm8904_card = {
+	.name = "atmel_asoc_wm8904",
+	.owner = THIS_MODULE,
+	.set_bias_level = atmel_set_bias_level,
+	.dai_link = &atmel_asoc_wm8904_dailink,
+	.num_links = 1,
+	.dapm_widgets = atmel_asoc_wm8904_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(atmel_asoc_wm8904_dapm_widgets),
+	.fully_routed = true,
+};
+
+static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *codec_np, *cpu_np;
+	struct snd_soc_card *card = &atmel_asoc_wm8904_card;
+	struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+	int ret;
+
+	if (!np) {
+		dev_err(&pdev->dev, "only device tree supported\n");
+		return -EINVAL;
+	}
+
+	ret = snd_soc_of_parse_card_name(card, "atmel,model");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse card name\n");
+		return ret;
+	}
+
+	ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse audio routing\n");
+		return ret;
+	}
+
+	cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+	if (!cpu_np) {
+		dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+		ret = -EINVAL;
+		return ret;
+	}
+	dailink->cpu_of_node = cpu_np;
+	dailink->platform_of_node = cpu_np;
+	of_node_put(cpu_np);
+
+	codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+	if (!codec_np) {
+		dev_err(&pdev->dev, "failed to get codec info\n");
+		ret = -EINVAL;
+		return ret;
+	}
+	dailink->codec_of_node = codec_np;
+	of_node_put(codec_np);
+
+	return 0;
+}
+
+static int atmel_asoc_wm8904_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &atmel_asoc_wm8904_card;
+	struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+	struct clk *clk_src;
+	struct pinctrl *pinctrl;
+	int id, ret;
+
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+	if (IS_ERR(pinctrl)) {
+		dev_err(&pdev->dev, "failed to request pinctrl\n");
+		return PTR_ERR(pinctrl);
+	}
+
+	card->dev = &pdev->dev;
+	ret = atmel_asoc_wm8904_dt_init(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to init dt info\n");
+		return ret;
+	}
+
+	id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
+	ret = atmel_ssc_set_audio(id);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to set SSC %d for audio\n", id);
+		return ret;
+	}
+
+	mclk = clk_get(NULL, "pck0");
+	if (IS_ERR(mclk)) {
+		dev_err(&pdev->dev, "failed to get pck0\n");
+		ret = PTR_ERR(mclk);
+		goto err_set_audio;
+	}
+
+	clk_src = clk_get(NULL, "clk32k");
+	if (IS_ERR(clk_src)) {
+		dev_err(&pdev->dev, "failed to get clk32k\n");
+		ret = PTR_ERR(clk_src);
+		goto err_set_audio;
+	}
+
+	ret = clk_set_parent(mclk, clk_src);
+	clk_put(clk_src);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "failed to set MCLK parent\n");
+		goto err_set_audio;
+	}
+
+	dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE);
+	clk_set_rate(mclk, MCLK_RATE);
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed\n");
+		goto err_set_audio;
+	}
+
+	return 0;
+
+err_set_audio:
+	atmel_ssc_put_audio(id);
+	return ret;
+}
+
+static int atmel_asoc_wm8904_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+	int id;
+
+	id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
+
+	snd_soc_unregister_card(card);
+	atmel_ssc_put_audio(id);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = {
+	{ .compatible = "atmel,asoc-wm8904", },
+	{ }
+};
+#endif
+
+static struct platform_driver atmel_asoc_wm8904_driver = {
+	.driver = {
+		.name = "atmel-wm8904-audio",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
+	},
+	.probe = atmel_asoc_wm8904_probe,
+	.remove = atmel_asoc_wm8904_remove,
+};
+
+module_platform_driver(atmel_asoc_wm8904_driver);
+
+/* Module information */
+MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
+MODULE_DESCRIPTION("ALSA SoC machine driver for Atmel EK with WM8904 codec");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
new file mode 100644
index 0000000..992ae38
--- /dev/null
+++ b/sound/soc/atmel/sam9x5_wm8731.c
@@ -0,0 +1,208 @@
+/*
+ * sam9x5_wm8731   --	SoC audio for AT91SAM9X5-based boards
+ *			that are using WM8731 as codec.
+ *
+ *  Copyright (C) 2011 Atmel,
+ *		  Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ *  Copyright (C) 2013 Paratronic,
+ *		  Richard Genoud <richard.genoud@gmail.com>
+ *
+ * Based on sam9g20_wm8731.c by:
+ * Sedji Gaouaou <sedji.gaouaou@atmel.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/of.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm8731.h"
+#include "atmel_ssc_dai.h"
+
+
+#define MCLK_RATE 12288000
+
+#define DRV_NAME "sam9x5-snd-wm8731"
+
+struct sam9x5_drvdata {
+	int ssc_id;
+};
+
+/*
+ * Logic for a wm8731 as connected on a at91sam9x5ek based board.
+ */
+static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct device *dev = rtd->dev;
+	int ret;
+
+	dev_dbg(dev, "ASoC: %s called\n", __func__);
+
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+				     MCLK_RATE, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(dev, "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Audio paths on at91sam9x5ek board:
+ *
+ *  |A| ------------> |      | ---R----> Headphone Jack
+ *  |T| <----\        |  WM  | ---L--/
+ *  |9| ---> CLK <--> | 8731 | <--R----- Line In Jack
+ *  |1| <------------ |      | <--L--/
+ */
+static const struct snd_soc_dapm_widget sam9x5_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In Jack", NULL),
+};
+
+static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *codec_np, *cpu_np;
+	struct snd_soc_card *card;
+	struct snd_soc_dai_link *dai;
+	struct sam9x5_drvdata *priv;
+	int ret;
+
+	if (!np) {
+		dev_err(&pdev->dev, "No device node supplied\n");
+		return -EINVAL;
+	}
+
+	card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai || !card || !priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	card->dev = &pdev->dev;
+	card->owner = THIS_MODULE;
+	card->dai_link = dai;
+	card->num_links = 1;
+	card->dapm_widgets = sam9x5_dapm_widgets;
+	card->num_dapm_widgets = ARRAY_SIZE(sam9x5_dapm_widgets);
+	dai->name = "WM8731";
+	dai->stream_name = "WM8731 PCM";
+	dai->codec_dai_name = "wm8731-hifi";
+	dai->init = sam9x5_wm8731_init;
+	dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+		| SND_SOC_DAIFMT_CBM_CFM;
+
+	ret = snd_soc_of_parse_card_name(card, "atmel,model");
+	if (ret) {
+		dev_err(&pdev->dev, "atmel,model node missing\n");
+		goto out;
+	}
+
+	ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "atmel,audio-routing node missing\n");
+		goto out;
+	}
+
+	codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+	if (!codec_np) {
+		dev_err(&pdev->dev, "atmel,audio-codec node missing\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dai->codec_of_node = codec_np;
+
+	cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+	if (!cpu_np) {
+		dev_err(&pdev->dev, "atmel,ssc-controller node missing\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	dai->cpu_of_node = cpu_np;
+	dai->platform_of_node = cpu_np;
+
+	priv->ssc_id = of_alias_get_id(cpu_np, "ssc");
+
+	ret = atmel_ssc_set_audio(priv->ssc_id);
+	if (ret != 0) {
+		dev_err(&pdev->dev,
+			"ASoC: Failed to set SSC %d for audio: %d\n",
+			ret, priv->ssc_id);
+		goto out;
+	}
+
+	of_node_put(codec_np);
+	of_node_put(cpu_np);
+
+	platform_set_drvdata(pdev, card);
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"ASoC: Platform device allocation failed\n");
+		goto out_put_audio;
+	}
+
+	dev_dbg(&pdev->dev, "ASoC: %s ok\n", __func__);
+
+	return ret;
+
+out_put_audio:
+	atmel_ssc_put_audio(priv->ssc_id);
+out:
+	return ret;
+}
+
+static int sam9x5_wm8731_driver_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct sam9x5_drvdata *priv = card->drvdata;
+
+	snd_soc_unregister_card(card);
+	atmel_ssc_put_audio(priv->ssc_id);
+
+	return 0;
+}
+
+static const struct of_device_id sam9x5_wm8731_of_match[] = {
+	{ .compatible = "atmel,sam9x5-wm8731-audio", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sam9x5_wm8731_of_match);
+
+static struct platform_driver sam9x5_wm8731_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(sam9x5_wm8731_of_match),
+	},
+	.probe = sam9x5_wm8731_driver_probe,
+	.remove = sam9x5_wm8731_driver_remove,
+};
+module_platform_driver(sam9x5_wm8731_driver);
+
+/* Module information */
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
+MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index a497a0c..decba87 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -73,12 +73,14 @@
 
 static struct snd_soc_card db1300_ac97_machine = {
 	.name		= "DB1300_AC97",
+	.owner		= THIS_MODULE,
 	.dai_link	= &db1300_ac97_dai,
 	.num_links	= 1,
 };
 
 static struct snd_soc_card db1550_ac97_machine = {
 	.name		= "DB1550_AC97",
+	.owner		= THIS_MODULE,
 	.dai_link	= &db1200_ac97_dai,
 	.num_links	= 1,
 };
@@ -145,6 +147,7 @@
 
 static struct snd_soc_card db1300_i2s_machine = {
 	.name		= "DB1300_I2S",
+	.owner		= THIS_MODULE,
 	.dai_link	= &db1300_i2s_dai,
 	.num_links	= 1,
 };
@@ -161,6 +164,7 @@
 
 static struct snd_soc_card db1550_i2s_machine = {
 	.name		= "DB1550_I2S",
+	.owner		= THIS_MODULE,
 	.dai_link	= &db1550_i2s_dai,
 	.num_links	= 1,
 };
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index a822ab8..986dcec 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -379,9 +379,6 @@
 	mutex_init(&wd->lock);
 
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!iores)
-		return -ENODEV;
-
 	wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
 	if (IS_ERR(wd->mmio))
 		return PTR_ERR(wd->mmio);
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
index 0c3e22d..a680fdc 100644
--- a/sound/soc/blackfin/bf5xx-ac97.h
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -9,7 +9,6 @@
 #ifndef _BF5XX_AC97_H
 #define _BF5XX_AC97_H
 
-extern struct snd_ac97 *ac97;
 /* Frame format in memory, only support stereo currently */
 struct ac97_frame {
 	u16 ac97_tag;		/* slot 0 */
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index 04491f0..efa75b5 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -363,9 +363,6 @@
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENODEV;
-
 	info->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->regs))
 		return PTR_ERR(info->regs);
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 17ad70b..a57643d 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -376,9 +376,6 @@
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
-		return -ENODEV;
-
 	info->regs = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(info->regs))
 		return PTR_ERR(info->regs);
@@ -411,7 +408,6 @@
 	return 0;
 
 fail_put_lrclk:
-	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 fail_put_sclk:
 	clk_put(info->sclk);
@@ -426,7 +422,6 @@
 	struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
 	snd_soc_unregister_component(&pdev->dev);
-	dev_set_drvdata(&pdev->dev, NULL);
 	clk_put(info->lrclk);
 	clk_put(info->sclk);
 	clk_put(info->mclk);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index badb6fb..15106c0 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -10,6 +10,7 @@
 
 config SND_SOC_ALL_CODECS
 	tristate "Build all ASoC CODEC drivers"
+	depends on COMPILE_TEST
 	select SND_SOC_88PM860X if MFD_88PM860X
 	select SND_SOC_L3
 	select SND_SOC_AB8500_CODEC if ABX500_CORE
@@ -20,6 +21,7 @@
 	select SND_SOC_AD73311
 	select SND_SOC_ADAU1373 if I2C
 	select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+	select SND_SOC_ADAU1701 if I2C
 	select SND_SOC_ADS117X
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
@@ -54,6 +56,8 @@
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
 	select SND_SOC_HDMI_CODEC
+	select SND_SOC_PCM1681 if I2C
+	select SND_SOC_PCM1792A if SPI_MASTER
 	select SND_SOC_PCM3008
 	select SND_SOC_RT5631 if I2C
 	select SND_SOC_RT5640 if I2C
@@ -122,6 +126,7 @@
 	select SND_SOC_WM8994 if MFD_WM8994
 	select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8996 if I2C
+	select SND_SOC_WM8997 if MFD_WM8997
 	select SND_SOC_WM9081 if I2C
 	select SND_SOC_WM9090 if I2C
 	select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@@ -145,8 +150,10 @@
 	tristate
 	default y if SND_SOC_WM5102=y
 	default y if SND_SOC_WM5110=y
+	default y if SND_SOC_WM8997=y
 	default m if SND_SOC_WM5102=m
 	default m if SND_SOC_WM5110=m
+	default m if SND_SOC_WM8997=m
 
 config SND_SOC_WM_HUBS
 	tristate
@@ -198,6 +205,9 @@
 config SND_SOC_AK4535
 	tristate
 
+config SND_SOC_AK4554
+	tristate
+
 config SND_SOC_AK4641
 	tristate
 
@@ -292,6 +302,12 @@
 config SND_SOC_HDMI_CODEC
        tristate
 
+config SND_SOC_PCM1681
+       tristate
+
+config SND_SOC_PCM1792A
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -500,6 +516,9 @@
 config SND_SOC_WM8996
 	tristate
 
+config SND_SOC_WM8997
+	tristate
+
 config SND_SOC_WM9081
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 70fd806..bc12676 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -11,6 +11,7 @@
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4554-objs := ak4554.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
@@ -42,6 +43,8 @@
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-hdmi-codec-objs := hdmi.o
+snd-soc-pcm1681-objs := pcm1681.o
+snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
@@ -114,6 +117,7 @@
 snd-soc-wm8993-objs := wm8993.o
 snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
+snd-soc-wm8997-objs := wm8997.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9090-objs := wm9090.o
 snd-soc-wm9705-objs := wm9705.o
@@ -138,6 +142,7 @@
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4554)	+= snd-soc-ak4554.o
 obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
@@ -171,6 +176,8 @@
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
+obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)	+= snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)	+= snd-soc-rt5640.o
@@ -239,6 +246,7 @@
 obj-$(CONFIG_SND_SOC_WM8993)	+= snd-soc-wm8993.o
 obj-$(CONFIG_SND_SOC_WM8994)	+= snd-soc-wm8994.o
 obj-$(CONFIG_SND_SOC_WM8995)	+= snd-soc-wm8995.o
+obj-$(CONFIG_SND_SOC_WM8997)	+= snd-soc-wm8997.o
 obj-$(CONFIG_SND_SOC_WM9081)	+= snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9090)	+= snd-soc-wm9090.o
 obj-$(CONFIG_SND_SOC_WM9705)	+= snd-soc-wm9705.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index ec73518..8d9ba4b 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -23,6 +23,16 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
+static const struct snd_soc_dapm_widget ac97_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route ac97_routes[] = {
+	{ "AC97 Capture", NULL, "RX" },
+	{ "TX", NULL, "AC97 Playback" },
+};
+
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
@@ -117,6 +127,11 @@
 	.probe = 	ac97_soc_probe,
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
+
+	.dapm_widgets = ac97_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ac97_widgets),
+	.dapm_routes = ac97_routes,
+	.num_dapm_routes = ARRAY_SIZE(ac97_routes),
 };
 
 static int ac97_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 89fcf7d..7257a88 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -96,6 +96,44 @@
 SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
 };
 
+static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_INPUT("CD_L"),
+SND_SOC_DAPM_INPUT("CD_R"),
+SND_SOC_DAPM_INPUT("AUX_L"),
+SND_SOC_DAPM_INPUT("AUX_R"),
+SND_SOC_DAPM_INPUT("LINE_IN_L"),
+SND_SOC_DAPM_INPUT("LINE_IN_R"),
+
+SND_SOC_DAPM_OUTPUT("LFE_OUT"),
+SND_SOC_DAPM_OUTPUT("CENTER_OUT"),
+SND_SOC_DAPM_OUTPUT("LINE_OUT_L"),
+SND_SOC_DAPM_OUTPUT("LINE_OUT_R"),
+SND_SOC_DAPM_OUTPUT("MONO_OUT"),
+SND_SOC_DAPM_OUTPUT("HP_OUT_L"),
+SND_SOC_DAPM_OUTPUT("HP_OUT_R"),
+};
+
+static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
+	{ "Capture", NULL, "MIC1" },
+	{ "Capture", NULL, "MIC2" },
+	{ "Capture", NULL, "CD_L" },
+	{ "Capture", NULL, "CD_R" },
+	{ "Capture", NULL, "AUX_L" },
+	{ "Capture", NULL, "AUX_R" },
+	{ "Capture", NULL, "LINE_IN_L" },
+	{ "Capture", NULL, "LINE_IN_R" },
+
+	{ "LFE_OUT", NULL, "Playback" },
+	{ "CENTER_OUT", NULL, "Playback" },
+	{ "LINE_OUT_L", NULL, "Playback" },
+	{ "LINE_OUT_R", NULL, "Playback" },
+	{ "MONO_OUT", NULL, "Playback" },
+	{ "HP_OUT_L", NULL, "Playback" },
+	{ "HP_OUT_R", NULL, "Playback" },
+};
+
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg)
 {
@@ -253,6 +291,11 @@
 	.reg_cache_step = 2,
 	.write = ac97_write,
 	.read = ac97_read,
+
+	.dapm_widgets = ad1980_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
+	.dapm_routes = ad1980_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes),
 };
 
 static int ad1980_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index b1f2baf..5fac8ad 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -23,6 +23,21 @@
 
 #include "ad73311.h"
 
+static const struct snd_soc_dapm_widget ad73311_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("VINP"),
+SND_SOC_DAPM_INPUT("VINN"),
+SND_SOC_DAPM_OUTPUT("VOUTN"),
+SND_SOC_DAPM_OUTPUT("VOUTP"),
+};
+
+static const struct snd_soc_dapm_route ad73311_dapm_routes[] = {
+	{ "Capture", NULL, "VINP" },
+	{ "Capture", NULL, "VINN" },
+
+	{ "VOUTN", NULL, "Playback" },
+	{ "VOUTP", NULL, "Playback" },
+};
+
 static struct snd_soc_dai_driver ad73311_dai = {
 	.name = "ad73311-hifi",
 	.playback = {
@@ -39,7 +54,12 @@
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ad73311;
+static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
+	.dapm_widgets = ad73311_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
+	.dapm_routes = ad73311_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes),
+};
 
 static int ad73311_probe(struct platform_device *pdev)
 {
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index d1124a5..ebff1128b 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -91,7 +91,7 @@
 #define ADAU1701_OSCIPOW_OPD		0x04
 #define ADAU1701_DACSET_DACINIT		1
 
-#define ADAU1707_CLKDIV_UNSET		(-1UL)
+#define ADAU1707_CLKDIV_UNSET		(-1U)
 
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
@@ -247,21 +247,21 @@
 	    gpio_is_valid(adau1701->gpio_pll_mode[1])) {
 		switch (clkdiv) {
 		case 64:
-			gpio_set_value(adau1701->gpio_pll_mode[0], 0);
-			gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
 			break;
 		case 256:
-			gpio_set_value(adau1701->gpio_pll_mode[0], 0);
-			gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
 			break;
 		case 384:
-			gpio_set_value(adau1701->gpio_pll_mode[0], 1);
-			gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
 			break;
 		case 0:	/* fallback */
 		case 512:
-			gpio_set_value(adau1701->gpio_pll_mode[0], 1);
-			gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
+			gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
 			break;
 		}
 	}
@@ -269,10 +269,10 @@
 	adau1701->pll_clkdiv = clkdiv;
 
 	if (gpio_is_valid(adau1701->gpio_nreset)) {
-		gpio_set_value(adau1701->gpio_nreset, 0);
+		gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
 		/* minimum reset time is 20ns */
 		udelay(1);
-		gpio_set_value(adau1701->gpio_nreset, 1);
+		gpio_set_value_cansleep(adau1701->gpio_nreset, 1);
 		/* power-up time may be as long as 85ms */
 		mdelay(85);
 	}
@@ -734,7 +734,10 @@
 }
 
 static const struct i2c_device_id adau1701_i2c_id[] = {
+	{ "adau1401", 0 },
+	{ "adau1401a", 0 },
 	{ "adau1701", 0 },
+	{ "adau1702", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 3c839cc..15b012d0 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -868,6 +868,12 @@
 }
 
 #if defined(CONFIG_SPI_MASTER)
+static const struct spi_device_id adav80x_spi_id[] = {
+	{ "adav801", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
+
 static int adav80x_spi_probe(struct spi_device *spi)
 {
 	return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
@@ -885,15 +891,16 @@
 	},
 	.probe		= adav80x_spi_probe,
 	.remove		= adav80x_spi_remove,
+	.id_table	= adav80x_spi_id,
 };
 #endif
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static const struct i2c_device_id adav80x_id[] = {
+static const struct i2c_device_id adav80x_i2c_id[] = {
 	{ "adav803", 0 },
 	{ }
 };
-MODULE_DEVICE_TABLE(i2c, adav80x_id);
+MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
 
 static int adav80x_i2c_probe(struct i2c_client *client,
 			     const struct i2c_device_id *id)
@@ -913,7 +920,7 @@
 	},
 	.probe = adav80x_i2c_probe,
 	.remove = adav80x_i2c_remove,
-	.id_table = adav80x_id,
+	.id_table = adav80x_i2c_id,
 };
 #endif
 
diff --git a/sound/soc/codecs/ads117x.c b/sound/soc/codecs/ads117x.c
index 506d474..8f388ed 100644
--- a/sound/soc/codecs/ads117x.c
+++ b/sound/soc/codecs/ads117x.c
@@ -23,6 +23,28 @@
 #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
 #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 
+static const struct snd_soc_dapm_widget ads117x_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("Input1"),
+SND_SOC_DAPM_INPUT("Input2"),
+SND_SOC_DAPM_INPUT("Input3"),
+SND_SOC_DAPM_INPUT("Input4"),
+SND_SOC_DAPM_INPUT("Input5"),
+SND_SOC_DAPM_INPUT("Input6"),
+SND_SOC_DAPM_INPUT("Input7"),
+SND_SOC_DAPM_INPUT("Input8"),
+};
+
+static const struct snd_soc_dapm_route ads117x_dapm_routes[] = {
+	{ "Capture", NULL, "Input1" },
+	{ "Capture", NULL, "Input2" },
+	{ "Capture", NULL, "Input3" },
+	{ "Capture", NULL, "Input4" },
+	{ "Capture", NULL, "Input5" },
+	{ "Capture", NULL, "Input6" },
+	{ "Capture", NULL, "Input7" },
+	{ "Capture", NULL, "Input8" },
+};
+
 static struct snd_soc_dai_driver ads117x_dai = {
 /* ADC */
 	.name = "ads117x-hifi",
@@ -34,7 +56,12 @@
 		.formats = ADS117X_FORMATS,},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ads117x;
+static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
+	.dapm_widgets = ads117x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
+	.dapm_routes = ads117x_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes),
+};
 
 static int ads117x_probe(struct platform_device *pdev)
 {
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index c7cfdf9..71059c0 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -51,6 +51,17 @@
 	struct regmap *regmap;
 };
 
+static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
+SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
+	{ "TXE", NULL, "Playback" },
+	{ "TX", NULL, "TXE" },
+};
+
 static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
 {
@@ -138,29 +149,11 @@
 	if (ret < 0)
 		return ret;
 
-	/* enable transmitter */
-	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
-				 AK4104_TX_TXE, AK4104_TX_TXE);
-	if (ret < 0)
-		return ret;
-
 	return 0;
 }
 
-static int ak4104_hw_free(struct snd_pcm_substream *substream,
-			  struct snd_soc_dai *dai)
-{
-	struct snd_soc_codec *codec = dai->codec;
-	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
-
-	/* disable transmitter */
-	return regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
-				  AK4104_TX_TXE, 0);
-}
-
 static const struct snd_soc_dai_ops ak4101_dai_ops = {
 	.hw_params = ak4104_hw_params,
-	.hw_free = ak4104_hw_free,
 	.set_fmt = ak4104_set_dai_fmt,
 };
 
@@ -214,6 +207,11 @@
 static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
 	.probe =	ak4104_probe,
 	.remove =	ak4104_remove,
+
+	.dapm_widgets = ak4104_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
+	.dapm_routes = ak4104_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
 };
 
 static const struct regmap_config ak4104_regmap = {
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
new file mode 100644
index 0000000..79e9555
--- /dev/null
+++ b/sound/soc/codecs/ak4554.c
@@ -0,0 +1,106 @@
+/*
+ * ak4554.c
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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/module.h>
+#include <sound/soc.h>
+
+/*
+ * ak4554 is very simple DA/AD converter which has no setting register.
+ *
+ * CAUTION
+ *
+ * ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J,
+ * and,   capture  format is SND_SOC_DAIFMT_LEFT_J
+ * on same bit clock, LR clock.
+ * But, this driver doesn't have snd_soc_dai_ops :: set_fmt
+ *
+ * CPU/Codec DAI image
+ *
+ * CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554
+ *					   |
+ * CPU-DAI2 (capture only fmt = LEFT_J) ---+
+ */
+
+static const struct snd_soc_dapm_widget ak4554_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+
+SND_SOC_DAPM_OUTPUT("AOUTL"),
+SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route ak4554_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+
+	{ "AOUTL", NULL, "Playback" },
+	{ "AOUTR", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver ak4554_dai = {
+	.name = "ak4554-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.symmetric_rates = 1,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
+	.dapm_widgets = ak4554_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets),
+	.dapm_routes = ak4554_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes),
+};
+
+static int ak4554_soc_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev,
+				      &soc_codec_dev_ak4554,
+				      &ak4554_dai, 1);
+}
+
+static int ak4554_soc_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct of_device_id ak4554_of_match[] = {
+	{ .compatible = "asahi-kasei,ak4554" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ak4554_of_match);
+
+static struct platform_driver ak4554_driver = {
+	.driver = {
+		.name = "ak4554-adc-dac",
+		.owner = THIS_MODULE,
+		.of_match_table = ak4554_of_match,
+	},
+	.probe	= ak4554_soc_probe,
+	.remove	= ak4554_soc_remove,
+};
+module_platform_driver(ak4554_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SoC AK4554 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
index 1f30398..72e953b 100644
--- a/sound/soc/codecs/ak5386.c
+++ b/sound/soc/codecs/ak5386.c
@@ -22,7 +22,22 @@
 	int reset_gpio;
 };
 
-static struct snd_soc_codec_driver soc_codec_ak5386;
+static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+};
+
+static struct snd_soc_codec_driver soc_codec_ak5386 = {
+	.dapm_widgets = ak5386_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
+	.dapm_routes = ak5386_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
+};
 
 static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			      unsigned int format)
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index de62581..657808b 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -19,6 +19,7 @@
 #include <sound/tlv.h>
 
 #include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/gpio.h>
 #include <linux/mfd/arizona/registers.h>
 
 #include "arizona.h"
@@ -199,9 +200,16 @@
 	if (ret != 0)
 		return ret;
 
-	ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
-	if (ret != 0)
-		return ret;
+	switch (arizona->type) {
+	case WM8997:
+		break;
+	default:
+		ret = snd_soc_dapm_new_controls(&codec->dapm,
+						&arizona_spkr, 1);
+		if (ret != 0)
+			return ret;
+		break;
+	}
 
 	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
 				  "Thermal warning", arizona_thermal_warn,
@@ -223,6 +231,41 @@
 }
 EXPORT_SYMBOL_GPL(arizona_init_spk);
 
+int arizona_init_gpio(struct snd_soc_codec *codec)
+{
+	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+	struct arizona *arizona = priv->arizona;
+	int i;
+
+	switch (arizona->type) {
+	case WM5110:
+		snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
+		break;
+	default:
+		break;
+	}
+
+	snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
+
+	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+		switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
+		case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
+			snd_soc_dapm_enable_pin(&codec->dapm,
+						"DRC1 Signal Activity");
+			break;
+		case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
+			snd_soc_dapm_enable_pin(&codec->dapm,
+						"DRC2 Signal Activity");
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_gpio);
+
 const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
 	"None",
 	"Tone Generator 1",
@@ -517,6 +560,26 @@
 			4, arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
+static const char * const arizona_in_dmic_osr_text[] = {
+	"1.536MHz", "3.072MHz", "6.144MHz",
+};
+
+const struct soc_enum arizona_in_dmic_osr[] = {
+	SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+	SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+	SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+	SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
+			ARRAY_SIZE(arizona_in_dmic_osr_text),
+			arizona_in_dmic_osr_text),
+};
+EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
+
 static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 {
 	struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index b60b08c..9e81b63 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -150,7 +150,8 @@
 	ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \
 	ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux)
 
-#define ARIZONA_MUX_ROUTES(name) \
+#define ARIZONA_MUX_ROUTES(widget, name) \
+	{ widget, NULL, name " Input" }, \
 	ARIZONA_MIXER_INPUT_ROUTES(name " Input")
 
 #define ARIZONA_MIXER_ROUTES(widget, name) \
@@ -198,6 +199,7 @@
 extern const struct soc_enum arizona_lhpf4_mode;
 
 extern const struct soc_enum arizona_ng_hold;
+extern const struct soc_enum arizona_in_dmic_osr[];
 
 extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
 			 struct snd_kcontrol *kcontrol,
@@ -242,6 +244,7 @@
 			   unsigned int Fref, unsigned int Fout);
 
 extern int arizona_init_spk(struct snd_soc_codec *codec);
+extern int arizona_init_gpio(struct snd_soc_codec *codec);
 
 extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index a081d9f..c4cf069 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -15,15 +15,27 @@
 
 #include <sound/soc.h>
 
+static const struct snd_soc_dapm_widget bt_sco_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route bt_sco_routes[] = {
+	{ "Capture", NULL, "RX" },
+	{ "TX", NULL, "Playback" },
+};
+
 static struct snd_soc_dai_driver bt_sco_dai = {
 	.name = "bt-sco-pcm",
 	.playback = {
+		.stream_name = "Playback",
 		.channels_min = 1,
 		.channels_max = 1,
 		.rates = SNDRV_PCM_RATE_8000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 	},
 	.capture = {
+		 .stream_name = "Capture",
 		.channels_min = 1,
 		.channels_max = 1,
 		.rates = SNDRV_PCM_RATE_8000,
@@ -31,7 +43,12 @@
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_bt_sco;
+static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
+	.dapm_widgets = bt_sco_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
+	.dapm_routes = bt_sco_routes,
+	.num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
+};
 
 static int bt_sco_probe(struct platform_device *pdev)
 {
@@ -50,6 +67,9 @@
 	{
 		.name		= "dfbmcs320",
 	},
+	{
+		.name		= "bt-sco",
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 8e47798..83c835d 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -139,6 +139,22 @@
 	struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
+static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+
+SND_SOC_DAPM_OUTPUT("AOUTL"),
+SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route cs4270_dapm_routes[] = {
+	{ "Capture", NULL, "AINA" },
+	{ "Capture", NULL, "AINB" },
+
+	{ "AOUTA", NULL, "Playback" },
+	{ "AOUTB", NULL, "Playback" },
+};
+
 /**
  * struct cs4270_mode_ratios - clock ratio tables
  * @ratio: the ratio of MCLK to the sample rate
@@ -612,6 +628,10 @@
 
 	.controls =		cs4270_snd_controls,
 	.num_controls =		ARRAY_SIZE(cs4270_snd_controls),
+	.dapm_widgets =		cs4270_dapm_widgets,
+	.num_dapm_widgets =	ARRAY_SIZE(cs4270_dapm_widgets),
+	.dapm_routes =		cs4270_dapm_routes,
+	.num_dapm_routes =	ARRAY_SIZE(cs4270_dapm_routes),
 };
 
 /*
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 03036b3..a20f1bb 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -173,6 +173,26 @@
 	bool				enable_soft_reset;
 };
 
+static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINA"),
+SND_SOC_DAPM_INPUT("AINB"),
+
+SND_SOC_DAPM_OUTPUT("AOUTA+"),
+SND_SOC_DAPM_OUTPUT("AOUTA-"),
+SND_SOC_DAPM_OUTPUT("AOUTB+"),
+SND_SOC_DAPM_OUTPUT("AOUTB-"),
+};
+
+static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {
+	{ "Capture", NULL, "AINA" },
+	{ "Capture", NULL, "AINB" },
+
+	{ "AOUTA+", NULL, "Playback" },
+	{ "AOUTA-", NULL, "Playback" },
+	{ "AOUTB+", NULL, "Playback" },
+	{ "AOUTB-", NULL, "Playback" },
+};
+
 /*
  * @freq is the desired MCLK rate
  * MCLK rate should (c) be the sample rate, multiplied by one of the
@@ -576,8 +596,7 @@
 				   CS4271_MODE2_MUTECAEQUB,
 				   CS4271_MODE2_MUTECAEQUB);
 
-	return snd_soc_add_codec_controls(codec, cs4271_snd_controls,
-		ARRAY_SIZE(cs4271_snd_controls));
+	return 0;
 }
 
 static int cs4271_remove(struct snd_soc_codec *codec)
@@ -596,6 +615,13 @@
 	.remove			= cs4271_remove,
 	.suspend		= cs4271_soc_suspend,
 	.resume			= cs4271_soc_resume,
+
+	.controls		= cs4271_snd_controls,
+	.num_controls		= ARRAY_SIZE(cs4271_snd_controls),
+	.dapm_widgets		= cs4271_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(cs4271_dapm_widgets),
+	.dapm_routes		= cs4271_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(cs4271_dapm_routes),
 };
 
 #if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 66967ba..b2090b2 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -50,20 +50,11 @@
 	{"DMIC AIF", NULL, "DMic"},
 };
 
-static int dmic_probe(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
-				  ARRAY_SIZE(dmic_dapm_widgets));
-        snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-	snd_soc_dapm_new_widgets(dapm);
-
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_dmic = {
-	.probe	= dmic_probe,
+	.dapm_widgets = dmic_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(dmic_dapm_widgets),
+	.dapm_routes = intercon,
+	.num_dapm_routes = ARRAY_SIZE(intercon),
 };
 
 static int dmic_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c
index 2bcae2b..68342b1 100644
--- a/sound/soc/codecs/hdmi.c
+++ b/sound/soc/codecs/hdmi.c
@@ -23,11 +23,20 @@
 
 #define DRV_NAME "hdmi-audio-codec"
 
-static struct snd_soc_codec_driver hdmi_codec;
+static const struct snd_soc_dapm_widget hdmi_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route hdmi_routes[] = {
+	{ "Capture", NULL, "RX" },
+	{ "TX", NULL, "Playback" },
+};
 
 static struct snd_soc_dai_driver hdmi_codec_dai = {
 	.name = "hdmi-hifi",
 	.playback = {
+		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 8,
 		.rates = SNDRV_PCM_RATE_32000 |
@@ -37,6 +46,25 @@
 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S24_LE,
 	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_32000 |
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE,
+	},
+
+};
+
+static struct snd_soc_codec_driver hdmi_codec = {
+	.dapm_widgets = hdmi_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
+	.dapm_routes = hdmi_routes,
+	.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c
index 9f9f595..0e5743e 100644
--- a/sound/soc/codecs/lm4857.c
+++ b/sound/soc/codecs/lm4857.c
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 
 #include <sound/core.h>
@@ -23,12 +24,15 @@
 #include <sound/tlv.h>
 
 struct lm4857 {
-	struct i2c_client *i2c;
+	struct regmap *regmap;
 	uint8_t mode;
 };
 
-static const uint8_t lm4857_default_regs[] = {
-	0x00, 0x00, 0x00, 0x00,
+static const struct reg_default lm4857_default_regs[] = {
+	{ 0x0, 0x00 },
+	{ 0x1, 0x00 },
+	{ 0x2, 0x00 },
+	{ 0x3, 0x00 },
 };
 
 /* The register offsets in the cache array */
@@ -42,39 +46,6 @@
 #define LM4857_WAKEUP 5
 #define LM4857_EPGAIN 4
 
-static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg,
-		unsigned int value)
-{
-	uint8_t data;
-	int ret;
-
-	ret = snd_soc_cache_write(codec, reg, value);
-	if (ret < 0)
-		return ret;
-
-	data = (reg << 6) | value;
-	ret = i2c_master_send(codec->control_data, &data, 1);
-	if (ret != 1) {
-		dev_err(codec->dev, "Failed to write register: %d\n", ret);
-		return ret;
-	}
-
-	return 0;
-}
-
-static unsigned int lm4857_read(struct snd_soc_codec *codec,
-		unsigned int reg)
-{
-	unsigned int val;
-	int ret;
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret)
-		return -1;
-
-	return val;
-}
-
 static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -96,7 +67,7 @@
 	lm4857->mode = value;
 
 	if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-		snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6);
+		regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6);
 
 	return 1;
 }
@@ -108,10 +79,11 @@
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6);
+		regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F,
+			lm4857->mode + 6);
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0);
+		regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0);
 		break;
 	default:
 		break;
@@ -171,49 +143,32 @@
 	{"EP", NULL, "IN"},
 };
 
-static int lm4857_probe(struct snd_soc_codec *codec)
-{
-	struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	int ret;
-
-	codec->control_data = lm4857->i2c;
-
-	ret = snd_soc_add_codec_controls(codec, lm4857_controls,
-			ARRAY_SIZE(lm4857_controls));
-	if (ret)
-		return ret;
-
-	ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets,
-			ARRAY_SIZE(lm4857_dapm_widgets));
-	if (ret)
-		return ret;
-
-	ret = snd_soc_dapm_add_routes(dapm, lm4857_routes,
-			ARRAY_SIZE(lm4857_routes));
-	if (ret)
-		return ret;
-
-	snd_soc_dapm_new_widgets(dapm);
-
-	return 0;
-}
-
 static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
-	.write = lm4857_write,
-	.read = lm4857_read,
-	.probe = lm4857_probe,
-	.reg_cache_size = ARRAY_SIZE(lm4857_default_regs),
-	.reg_word_size = sizeof(uint8_t),
-	.reg_cache_default = lm4857_default_regs,
 	.set_bias_level = lm4857_set_bias_level,
+
+	.controls = lm4857_controls,
+	.num_controls = ARRAY_SIZE(lm4857_controls),
+	.dapm_widgets = lm4857_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets),
+	.dapm_routes = lm4857_routes,
+	.num_dapm_routes = ARRAY_SIZE(lm4857_routes),
+};
+
+static const struct regmap_config lm4857_regmap_config = {
+	.val_bits = 6,
+	.reg_bits = 2,
+
+	.max_register = LM4857_CTRL,
+
+	.cache_type = REGCACHE_FLAT,
+	.reg_defaults = lm4857_default_regs,
+	.num_reg_defaults = ARRAY_SIZE(lm4857_default_regs),
 };
 
 static int lm4857_i2c_probe(struct i2c_client *i2c,
 			    const struct i2c_device_id *id)
 {
 	struct lm4857 *lm4857;
-	int ret;
 
 	lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
 	if (!lm4857)
@@ -221,11 +176,11 @@
 
 	i2c_set_clientdata(i2c, lm4857);
 
-	lm4857->i2c = i2c;
+	lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+	if (IS_ERR(lm4857->regmap))
+		return PTR_ERR(lm4857->regmap);
 
-	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
-
-	return ret;
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
 }
 
 static int lm4857_i2c_remove(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c
index a6ac231..31f9156 100644
--- a/sound/soc/codecs/max9768.c
+++ b/sound/soc/codecs/max9768.c
@@ -118,6 +118,18 @@
 	SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio),
 };
 
+static const struct snd_soc_dapm_widget max9768_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN"),
+
+SND_SOC_DAPM_OUTPUT("OUT+"),
+SND_SOC_DAPM_OUTPUT("OUT-"),
+};
+
+static const struct snd_soc_dapm_route max9768_dapm_routes[] = {
+	{ "OUT+", NULL, "IN" },
+	{ "OUT-", NULL, "IN" },
+};
+
 static int max9768_probe(struct snd_soc_codec *codec)
 {
 	struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
@@ -148,6 +160,10 @@
 	.probe = max9768_probe,
 	.controls = max9768_volume,
 	.num_controls = ARRAY_SIZE(max9768_volume),
+	.dapm_widgets = max9768_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max9768_dapm_widgets),
+	.dapm_routes = max9768_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(max9768_dapm_routes),
 };
 
 static const struct regmap_config max9768_i2c_regmap_config = {
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index ad5313f..0569a4c 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2084,8 +2084,9 @@
 
 		pm_wakeup_event(codec->dev, 100);
 
-		schedule_delayed_work(&max98090->jack_work,
-			msecs_to_jiffies(100));
+		queue_delayed_work(system_power_efficient_wq,
+				   &max98090->jack_work,
+				   msecs_to_jiffies(100));
 	}
 
 	if (active & M98090_DRCACT_MASK)
@@ -2132,8 +2133,9 @@
 	snd_soc_jack_report(max98090->jack, 0,
 			    SND_JACK_HEADSET | SND_JACK_BTN_0);
 
-	schedule_delayed_work(&max98090->jack_work,
-		msecs_to_jiffies(100));
+	queue_delayed_work(system_power_efficient_wq,
+			   &max98090->jack_work,
+			   msecs_to_jiffies(100));
 
 	return 0;
 }
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c
index 6b6c74c..29549cd 100644
--- a/sound/soc/codecs/max9877.c
+++ b/sound/soc/codecs/max9877.c
@@ -14,170 +14,21 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
 #include "max9877.h"
 
-static struct i2c_client *i2c;
+static struct regmap *regmap;
 
-static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 };
-
-static void max9877_write_regs(void)
-{
-	unsigned int i;
-	u8 data[6];
-
-	data[0] = MAX9877_INPUT_MODE;
-	for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
-		data[i + 1] = max9877_regs[i];
-
-	if (i2c_master_send(i2c, data, 6) != 6)
-		dev_err(&i2c->dev, "i2c write failed\n");
-}
-
-static int max9877_get_reg(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	unsigned int reg = mc->reg;
-	unsigned int shift = mc->shift;
-	unsigned int mask = mc->max;
-	unsigned int invert = mc->invert;
-
-	ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
-
-	if (invert)
-		ucontrol->value.integer.value[0] =
-			mask - ucontrol->value.integer.value[0];
-
-	return 0;
-}
-
-static int max9877_set_reg(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	unsigned int reg = mc->reg;
-	unsigned int shift = mc->shift;
-	unsigned int mask = mc->max;
-	unsigned int invert = mc->invert;
-	unsigned int val = (ucontrol->value.integer.value[0] & mask);
-
-	if (invert)
-		val = mask - val;
-
-	if (((max9877_regs[reg] >> shift) & mask) == val)
-		return 0;
-
-	max9877_regs[reg] &= ~(mask << shift);
-	max9877_regs[reg] |= val << shift;
-	max9877_write_regs();
-
-	return 1;
-}
-
-static int max9877_get_2reg(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	unsigned int reg = mc->reg;
-	unsigned int reg2 = mc->rreg;
-	unsigned int shift = mc->shift;
-	unsigned int mask = mc->max;
-
-	ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
-	ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask;
-
-	return 0;
-}
-
-static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	struct soc_mixer_control *mc =
-		(struct soc_mixer_control *)kcontrol->private_value;
-	unsigned int reg = mc->reg;
-	unsigned int reg2 = mc->rreg;
-	unsigned int shift = mc->shift;
-	unsigned int mask = mc->max;
-	unsigned int val = (ucontrol->value.integer.value[0] & mask);
-	unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
-	unsigned int change = 0;
-
-	if (((max9877_regs[reg] >> shift) & mask) != val)
-		change = 1;
-
-	if (((max9877_regs[reg2] >> shift) & mask) != val2)
-		change = 1;
-
-	if (change) {
-		max9877_regs[reg] &= ~(mask << shift);
-		max9877_regs[reg] |= val << shift;
-		max9877_regs[reg2] &= ~(mask << shift);
-		max9877_regs[reg2] |= val2 << shift;
-		max9877_write_regs();
-	}
-
-	return change;
-}
-
-static int max9877_get_out_mode(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK;
-
-	if (value)
-		value -= 1;
-
-	ucontrol->value.integer.value[0] = value;
-	return 0;
-}
-
-static int max9877_set_out_mode(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	u8 value = ucontrol->value.integer.value[0];
-
-	value += 1;
-
-	if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value)
-		return 0;
-
-	max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK;
-	max9877_regs[MAX9877_OUTPUT_MODE] |= value;
-	max9877_write_regs();
-	return 1;
-}
-
-static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK);
-
-	value = value >> MAX9877_OSC_OFFSET;
-
-	ucontrol->value.integer.value[0] = value;
-	return 0;
-}
-
-static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol,
-		struct snd_ctl_elem_value *ucontrol)
-{
-	u8 value = ucontrol->value.integer.value[0];
-
-	value = value << MAX9877_OSC_OFFSET;
-	if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value)
-		return 0;
-
-	max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK;
-	max9877_regs[MAX9877_OUTPUT_MODE] |= value;
-	max9877_write_regs();
-	return 1;
-}
+static struct reg_default max9877_regs[] = {
+	{ 0, 0x40 },
+	{ 1, 0x00 },
+	{ 2, 0x00 },
+	{ 3, 0x00 },
+	{ 4, 0x49 },
+};
 
 static const unsigned int max9877_pgain_tlv[] = {
 	TLV_DB_RANGE_HEAD(2),
@@ -212,65 +63,104 @@
 };
 
 static const struct soc_enum max9877_enum[] = {
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode),
-	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
+	SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode),
+			max9877_out_mode),
+	SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET,
+			ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
 };
 
 static const struct snd_kcontrol_new max9877_controls[] = {
-	SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume",
-			MAX9877_INPUT_MODE, 0, 2, 0,
-			max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
-	SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume",
-			MAX9877_INPUT_MODE, 2, 2, 0,
-			max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
-	SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume",
-			MAX9877_SPK_VOLUME, 0, 31, 0,
-			max9877_get_reg, max9877_set_reg, max9877_output_tlv),
-	SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume",
-			MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
-			max9877_get_2reg, max9877_set_2reg, max9877_output_tlv),
-	SOC_SINGLE_EXT("MAX9877 INB Stereo Switch",
-			MAX9877_INPUT_MODE, 4, 1, 1,
-			max9877_get_reg, max9877_set_reg),
-	SOC_SINGLE_EXT("MAX9877 INA Stereo Switch",
-			MAX9877_INPUT_MODE, 5, 1, 1,
-			max9877_get_reg, max9877_set_reg),
-	SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch",
-			MAX9877_INPUT_MODE, 6, 1, 0,
-			max9877_get_reg, max9877_set_reg),
-	SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch",
-			MAX9877_OUTPUT_MODE, 6, 1, 0,
-			max9877_get_reg, max9877_set_reg),
-	SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch",
-			MAX9877_OUTPUT_MODE, 7, 1, 1,
-			max9877_get_reg, max9877_set_reg),
-	SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0],
-			max9877_get_out_mode, max9877_set_out_mode),
-	SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1],
-			max9877_get_osc_mode, max9877_set_osc_mode),
+	SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume",
+		       MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv),
+	SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume",
+		       MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv),
+	SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume",
+		       MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv),
+	SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume",
+			 MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
+			 max9877_output_tlv),
+	SOC_SINGLE("MAX9877 INB Stereo Switch",
+		   MAX9877_INPUT_MODE, 4, 1, 1),
+	SOC_SINGLE("MAX9877 INA Stereo Switch",
+		   MAX9877_INPUT_MODE, 5, 1, 1),
+	SOC_SINGLE("MAX9877 Zero-crossing detection Switch",
+		   MAX9877_INPUT_MODE, 6, 1, 0),
+	SOC_SINGLE("MAX9877 Bypass Mode Switch",
+		   MAX9877_OUTPUT_MODE, 6, 1, 0),
+	SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]),
+	SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]),
 };
 
-/* This function is called from ASoC machine driver */
-int max9877_add_controls(struct snd_soc_codec *codec)
-{
-	return snd_soc_add_codec_controls(codec, max9877_controls,
-			ARRAY_SIZE(max9877_controls));
-}
-EXPORT_SYMBOL_GPL(max9877_add_controls);
+static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("INA1"),
+SND_SOC_DAPM_INPUT("INA2"),
+SND_SOC_DAPM_INPUT("INB1"),
+SND_SOC_DAPM_INPUT("INB2"),
+SND_SOC_DAPM_INPUT("RXIN+"),
+SND_SOC_DAPM_INPUT("RXIN-"),
+
+SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("OUT+"),
+SND_SOC_DAPM_OUTPUT("OUT-"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route max9877_dapm_routes[] = {
+	{ "SHDN", NULL, "INA1" },
+	{ "SHDN", NULL, "INA2" },
+	{ "SHDN", NULL, "INB1" },
+	{ "SHDN", NULL, "INB2" },
+
+	{ "OUT+", NULL, "RXIN+" },
+	{ "OUT+", NULL, "SHDN" },
+
+	{ "OUT-", NULL, "SHDN" },
+	{ "OUT-", NULL, "RXIN-" },
+
+	{ "HPL", NULL, "SHDN" },
+	{ "HPR", NULL, "SHDN" },
+};
+
+static const struct snd_soc_codec_driver max9877_codec = {
+	.controls = max9877_controls,
+	.num_controls = ARRAY_SIZE(max9877_controls),
+
+	.dapm_widgets = max9877_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets),
+	.dapm_routes = max9877_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes),
+};
+
+static const struct regmap_config max9877_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = max9877_regs,
+	.num_reg_defaults = ARRAY_SIZE(max9877_regs),
+	.cache_type = REGCACHE_RBTREE,
+};
 
 static int max9877_i2c_probe(struct i2c_client *client,
 			     const struct i2c_device_id *id)
 {
-	i2c = client;
+	int i;
 
-	max9877_write_regs();
+	regmap = devm_regmap_init_i2c(client, &max9877_regmap);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
 
-	return 0;
+	/* Ensure the device is in reset state */
+	for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
+		regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def);
+
+	return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0);
 }
 
 static int max9877_i2c_remove(struct i2c_client *client)
 {
-	i2c = NULL;
+	snd_soc_unregister_codec(&client->dev);
 
 	return 0;
 }
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index 5402dfb..4d3c8fd 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -94,7 +94,6 @@
 #define AUDIO_DAC_CFS_DLY_B		(1 << 10)
 
 struct mc13783_priv {
-	struct snd_soc_codec codec;
 	struct mc13xxx *mc13xxx;
 
 	enum mc13783_ssi_port adc_ssi_port;
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
new file mode 100644
index 0000000..651ce09
--- /dev/null
+++ b/sound/soc/codecs/pcm1681.c
@@ -0,0 +1,339 @@
+/*
+ * PCM1681 ASoC codec driver
+ *
+ * Copyright (c) StreamUnlimited GmbH 2013
+ *	Marek Belisko <marek.belisko@streamunlimited.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |		\
+			     SNDRV_PCM_FMTBIT_S24_LE)
+
+#define PCM1681_PCM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+			     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+			     SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+			     SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define PCM1681_SOFT_MUTE_ALL		0xff
+#define PCM1681_DEEMPH_RATE_MASK	0x18
+#define PCM1681_DEEMPH_MASK		0x01
+
+#define PCM1681_ATT_CONTROL(X)	(X <= 6 ? X : X + 9) /* Attenuation level */
+#define PCM1681_SOFT_MUTE	0x07	/* Soft mute control register */
+#define PCM1681_DAC_CONTROL	0x08	/* DAC operation control */
+#define PCM1681_FMT_CONTROL	0x09	/* Audio interface data format */
+#define PCM1681_DEEMPH_CONTROL	0x0a	/* De-emphasis control */
+#define PCM1681_ZERO_DETECT_STATUS	0x0e	/* Zero detect status reg */
+
+static const struct reg_default pcm1681_reg_defaults[] = {
+	{ 0x01,	0xff },
+	{ 0x02,	0xff },
+	{ 0x03,	0xff },
+	{ 0x04,	0xff },
+	{ 0x05,	0xff },
+	{ 0x06,	0xff },
+	{ 0x07,	0x00 },
+	{ 0x08,	0x00 },
+	{ 0x09,	0x06 },
+	{ 0x0A,	0x00 },
+	{ 0x0B,	0xff },
+	{ 0x0C,	0x0f },
+	{ 0x0D,	0x00 },
+	{ 0x10,	0xff },
+	{ 0x11,	0xff },
+	{ 0x12,	0x00 },
+	{ 0x13,	0x00 },
+};
+
+static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return !((reg == 0x00) || (reg == 0x0f));
+}
+
+static bool pcm1681_writeable_reg(struct device *dev, unsigned register reg)
+{
+	return pcm1681_accessible_reg(dev, reg) &&
+		(reg != PCM1681_ZERO_DETECT_STATUS);
+}
+
+struct pcm1681_private {
+	struct regmap *regmap;
+	unsigned int format;
+	/* Current deemphasis status */
+	unsigned int deemph;
+	/* Current rate for deemphasis control */
+	unsigned int rate;
+};
+
+static const int pcm1681_deemph[] = { 44100, 48000, 32000 };
+
+static int pcm1681_set_deemph(struct snd_soc_codec *codec)
+{
+	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	int i = 0, val = -1, enable = 0;
+
+	if (priv->deemph)
+		for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++)
+			if (pcm1681_deemph[i] == priv->rate)
+				val = i;
+
+	if (val != -1) {
+		regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+					PCM1681_DEEMPH_RATE_MASK, val);
+		enable = 1;
+	} else
+		enable = 0;
+
+	/* enable/disable deemphasis functionality */
+	return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+					PCM1681_DEEMPH_MASK, enable);
+}
+
+static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = priv->deemph;
+
+	return 0;
+}
+
+static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->deemph = ucontrol->value.enumerated.item[0];
+
+	return pcm1681_set_deemph(codec);
+}
+
+static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			      unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	/* The PCM1681 can only be slave to all clocks */
+	if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+		dev_err(codec->dev, "Invalid clocking mode\n");
+		return -EINVAL;
+	}
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	int val;
+
+	if (mute)
+		val = PCM1681_SOFT_MUTE_ALL;
+	else
+		val = 0;
+
+	return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val);
+}
+
+static int pcm1681_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+	int val = 0, ret;
+	int pcm_format = params_format(params);
+
+	priv->rate = params_rate(params);
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		if (pcm_format == SNDRV_PCM_FORMAT_S24_LE)
+			val = 0x00;
+		else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+			val = 0x03;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		val = 0x04;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		val = 0x05;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val);
+	if (ret < 0)
+		return ret;
+
+	return pcm1681_set_deemph(codec);
+}
+
+static const struct snd_soc_dai_ops pcm1681_dai_ops = {
+	.set_fmt	= pcm1681_set_dai_fmt,
+	.hw_params	= pcm1681_hw_params,
+	.digital_mute	= pcm1681_digital_mute,
+};
+
+static const struct snd_soc_dapm_widget pcm1681_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("VOUT1"),
+SND_SOC_DAPM_OUTPUT("VOUT2"),
+SND_SOC_DAPM_OUTPUT("VOUT3"),
+SND_SOC_DAPM_OUTPUT("VOUT4"),
+SND_SOC_DAPM_OUTPUT("VOUT5"),
+SND_SOC_DAPM_OUTPUT("VOUT6"),
+SND_SOC_DAPM_OUTPUT("VOUT7"),
+SND_SOC_DAPM_OUTPUT("VOUT8"),
+};
+
+static const struct snd_soc_dapm_route pcm1681_dapm_routes[] = {
+	{ "VOUT1", NULL, "Playback" },
+	{ "VOUT2", NULL, "Playback" },
+	{ "VOUT3", NULL, "Playback" },
+	{ "VOUT4", NULL, "Playback" },
+	{ "VOUT5", NULL, "Playback" },
+	{ "VOUT6", NULL, "Playback" },
+	{ "VOUT7", NULL, "Playback" },
+	{ "VOUT8", NULL, "Playback" },
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1);
+
+static const struct snd_kcontrol_new pcm1681_controls[] = {
+	SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+			PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+			PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+			PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume",
+			PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0,
+			0x7f, 0, pcm1681_dac_tlv),
+	SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+			    pcm1681_get_deemph, pcm1681_put_deemph),
+};
+
+static struct snd_soc_dai_driver pcm1681_dai = {
+	.name = "pcm1681-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = PCM1681_PCM_RATES,
+		.formats = PCM1681_PCM_FORMATS,
+	},
+	.ops = &pcm1681_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm1681_dt_ids[] = {
+	{ .compatible = "ti,pcm1681", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
+#endif
+
+static const struct regmap_config pcm1681_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= ARRAY_SIZE(pcm1681_reg_defaults) + 1,
+	.reg_defaults		= pcm1681_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(pcm1681_reg_defaults),
+	.writeable_reg		= pcm1681_writeable_reg,
+	.readable_reg		= pcm1681_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
+	.controls		= pcm1681_controls,
+	.num_controls		= ARRAY_SIZE(pcm1681_controls),
+	.dapm_widgets		= pcm1681_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1681_dapm_widgets),
+	.dapm_routes		= pcm1681_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1681_dapm_routes),
+};
+
+static const struct i2c_device_id pcm1681_i2c_id[] = {
+	{"pcm1681", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id);
+
+static int pcm1681_i2c_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
+{
+	int ret;
+	struct pcm1681_private *priv;
+
+	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap);
+	if (IS_ERR(priv->regmap)) {
+		ret = PTR_ERR(priv->regmap);
+		dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+		return ret;
+	}
+
+	i2c_set_clientdata(client, priv);
+
+	return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm1681,
+		&pcm1681_dai, 1);
+}
+
+static int pcm1681_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static struct i2c_driver pcm1681_i2c_driver = {
+	.driver = {
+		.name	= "pcm1681",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(pcm1681_dt_ids),
+	},
+	.id_table	= pcm1681_i2c_id,
+	.probe		= pcm1681_i2c_probe,
+	.remove		= pcm1681_i2c_remove,
+};
+
+module_i2c_driver(pcm1681_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
new file mode 100644
index 0000000..2a8eccf
--- /dev/null
+++ b/sound/soc/codecs/pcm1792a.c
@@ -0,0 +1,257 @@
+/*
+ * PCM1792A ASoC codec driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ *     Michael Trimarchi <michael@amarulasolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of_device.h>
+
+#include "pcm1792a.h"
+
+#define PCM1792A_DAC_VOL_LEFT	0x10
+#define PCM1792A_DAC_VOL_RIGHT	0x11
+#define PCM1792A_FMT_CONTROL	0x12
+#define PCM1792A_SOFT_MUTE	PCM1792A_FMT_CONTROL
+
+#define PCM1792A_FMT_MASK	0x70
+#define PCM1792A_FMT_SHIFT	4
+#define PCM1792A_MUTE_MASK	0x01
+#define PCM1792A_MUTE_SHIFT	0
+#define PCM1792A_ATLD_ENABLE	(1 << 7)
+
+static const struct reg_default pcm1792a_reg_defaults[] = {
+	{ 0x10, 0xff },
+	{ 0x11, 0xff },
+	{ 0x12, 0x50 },
+	{ 0x13, 0x00 },
+	{ 0x14, 0x00 },
+	{ 0x15, 0x01 },
+	{ 0x16, 0x00 },
+	{ 0x17, 0x00 },
+};
+
+static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg)
+{
+	return reg >= 0x10 && reg <= 0x17;
+}
+
+static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg)
+{
+	bool accessible;
+
+	accessible = pcm1792a_accessible_reg(dev, reg);
+
+	return accessible && reg != 0x16 && reg != 0x17;
+}
+
+struct pcm1792a_private {
+	struct regmap *regmap;
+	unsigned int format;
+	unsigned int rate;
+};
+
+static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->format = format;
+
+	return 0;
+}
+
+static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE,
+				 PCM1792A_MUTE_MASK, !!mute);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
+	int val = 0, ret;
+	int pcm_format = params_format(params);
+
+	priv->rate = params_rate(params);
+
+	switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_RIGHT_J:
+		if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
+		    pcm_format == SNDRV_PCM_FORMAT_S32_LE)
+			val = 0x02;
+		else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+			val = 0x00;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
+		    pcm_format == SNDRV_PCM_FORMAT_S32_LE)
+			val = 0x05;
+		else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+			val = 0x04;
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAI format\n");
+		return -EINVAL;
+	}
+
+	val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE;
+
+	ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL,
+				 PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops pcm1792a_dai_ops = {
+	.set_fmt	= pcm1792a_set_dai_fmt,
+	.hw_params	= pcm1792a_hw_params,
+	.digital_mute	= pcm1792a_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm1792a_controls[] = {
+	SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT,
+			 PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+			 pcm1792a_dac_tlv),
+};
+
+static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("IOUTL+"),
+SND_SOC_DAPM_OUTPUT("IOUTL-"),
+SND_SOC_DAPM_OUTPUT("IOUTR+"),
+SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = {
+	{ "IOUTL+", NULL, "Playback" },
+	{ "IOUTL-", NULL, "Playback" },
+	{ "IOUTR+", NULL, "Playback" },
+	{ "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm1792a_dai = {
+	.name = "pcm1792a-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PCM1792A_RATES,
+		.formats = PCM1792A_FORMATS, },
+	.ops = &pcm1792a_dai_ops,
+};
+
+static const struct of_device_id pcm1792a_of_match[] = {
+	{ .compatible = "ti,pcm1792a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
+
+static const struct regmap_config pcm1792a_regmap = {
+	.reg_bits		= 8,
+	.val_bits		= 8,
+	.max_register		= 24,
+	.reg_defaults		= pcm1792a_reg_defaults,
+	.num_reg_defaults	= ARRAY_SIZE(pcm1792a_reg_defaults),
+	.writeable_reg		= pcm1792a_writeable_reg,
+	.readable_reg		= pcm1792a_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = {
+	.controls		= pcm1792a_controls,
+	.num_controls		= ARRAY_SIZE(pcm1792a_controls),
+	.dapm_widgets		= pcm1792a_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(pcm1792a_dapm_widgets),
+	.dapm_routes		= pcm1792a_dapm_routes,
+	.num_dapm_routes	= ARRAY_SIZE(pcm1792a_dapm_routes),
+};
+
+static int pcm1792a_spi_probe(struct spi_device *spi)
+{
+	struct pcm1792a_private *pcm1792a;
+	int ret;
+
+	pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private),
+				GFP_KERNEL);
+	if (!pcm1792a)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, pcm1792a);
+
+	pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap);
+	if (IS_ERR(pcm1792a->regmap)) {
+		ret = PTR_ERR(pcm1792a->regmap);
+		dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+		return ret;
+	}
+
+	return snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_pcm1792a, &pcm1792a_dai, 1);
+}
+
+static int pcm1792a_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	return 0;
+}
+
+static const struct spi_device_id pcm1792a_spi_ids[] = {
+	{ "pcm1792a", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids);
+
+static struct spi_driver pcm1792a_codec_driver = {
+	.driver = {
+		.name = "pcm1792a",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(pcm1792a_of_match),
+	},
+	.id_table = pcm1792a_spi_ids,
+	.probe = pcm1792a_spi_probe,
+	.remove = pcm1792a_spi_remove,
+};
+
+module_spi_driver(pcm1792a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM1792A driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h
new file mode 100644
index 0000000..7a83d1f
--- /dev/null
+++ b/sound/soc/codecs/pcm1792a.h
@@ -0,0 +1,26 @@
+/*
+ * definitions for PCM1792A
+ *
+ * Copyright 2013 Amarula Solutions
+ *
+  * 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.
+ */
+
+#ifndef __PCM1792A_H__
+#define __PCM1792A_H__
+
+#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
+			SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+			  SNDRV_PCM_FMTBIT_S16_LE)
+
+#endif
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index f2a6282..b6618c4 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -28,7 +28,54 @@
 
 #include "pcm3008.h"
 
-#define PCM3008_VERSION "0.2"
+static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct pcm3008_setup_data *setup = codec->dev->platform_data;
+
+	gpio_set_value_cansleep(setup->pdda_pin,
+				SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol,
+			  int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct pcm3008_setup_data *setup = codec->dev->platform_data;
+
+	gpio_set_value_cansleep(setup->pdad_pin,
+				SND_SOC_DAPM_EVENT_ON(event));
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget pcm3008_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("VINL"),
+SND_SOC_DAPM_INPUT("VINR"),
+
+SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_dac_ev,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_adc_ev,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm3008_dapm_routes[] = {
+	{ "PCM3008 Capture", NULL, "ADC" },
+	{ "ADC", NULL, "VINL" },
+	{ "ADC", NULL, "VINR" },
+
+	{ "DAC", NULL, "PCM3008 Playback" },
+	{ "VOUTL", NULL, "DAC" },
+	{ "VOUTR", NULL, "DAC" },
+};
 
 #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |	\
 		       SNDRV_PCM_RATE_48000)
@@ -51,20 +98,20 @@
 	},
 };
 
-static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
-{
-	gpio_free(setup->dem0_pin);
-	gpio_free(setup->dem1_pin);
-	gpio_free(setup->pdad_pin);
-	gpio_free(setup->pdda_pin);
-}
+static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
+	.dapm_widgets = pcm3008_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets),
+	.dapm_routes = pcm3008_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes),
+};
 
-static int pcm3008_soc_probe(struct snd_soc_codec *codec)
+static int pcm3008_codec_probe(struct platform_device *pdev)
 {
-	struct pcm3008_setup_data *setup = codec->dev->platform_data;
-	int ret = 0;
+	struct pcm3008_setup_data *setup = pdev->dev.platform_data;
+	int ret;
 
-	printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
+	if (!setup)
+		return -EINVAL;
 
 	/* DEM1  DEM0  DE-EMPHASIS_MODE
 	 * Low   Low   De-emphasis 44.1 kHz ON
@@ -74,83 +121,29 @@
 	 */
 
 	/* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
-	ret = gpio_request(setup->dem0_pin, "codec_dem0");
-	if (ret == 0)
-		ret = gpio_direction_output(setup->dem0_pin, 1);
+	ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
+				    GPIOF_OUT_INIT_HIGH, "codec_dem0");
 	if (ret != 0)
-		goto gpio_err;
+		return ret;
 
 	/* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
-	ret = gpio_request(setup->dem1_pin, "codec_dem1");
-	if (ret == 0)
-		ret = gpio_direction_output(setup->dem1_pin, 0);
+	ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
+				    GPIOF_OUT_INIT_LOW, "codec_dem1");
 	if (ret != 0)
-		goto gpio_err;
+		return ret;
 
 	/* Configure PDAD GPIO. */
-	ret = gpio_request(setup->pdad_pin, "codec_pdad");
-	if (ret == 0)
-		ret = gpio_direction_output(setup->pdad_pin, 1);
+	ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
+				    GPIOF_OUT_INIT_LOW, "codec_pdad");
 	if (ret != 0)
-		goto gpio_err;
+		return ret;
 
 	/* Configure PDDA GPIO. */
-	ret = gpio_request(setup->pdda_pin, "codec_pdda");
-	if (ret == 0)
-		ret = gpio_direction_output(setup->pdda_pin, 1);
+	ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
+				    GPIOF_OUT_INIT_LOW, "codec_pdda");
 	if (ret != 0)
-		goto gpio_err;
+		return ret;
 
-	return ret;
-
-gpio_err:
-	pcm3008_gpio_free(setup);
-
-	return ret;
-}
-
-static int pcm3008_soc_remove(struct snd_soc_codec *codec)
-{
-	struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-	pcm3008_gpio_free(setup);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
-{
-	struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-	gpio_set_value(setup->pdad_pin, 0);
-	gpio_set_value(setup->pdda_pin, 0);
-
-	return 0;
-}
-
-static int pcm3008_soc_resume(struct snd_soc_codec *codec)
-{
-	struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-	gpio_set_value(setup->pdad_pin, 1);
-	gpio_set_value(setup->pdda_pin, 1);
-
-	return 0;
-}
-#else
-#define pcm3008_soc_suspend NULL
-#define pcm3008_soc_resume NULL
-#endif
-
-static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
-	.probe = 	pcm3008_soc_probe,
-	.remove = 	pcm3008_soc_remove,
-	.suspend =	pcm3008_soc_suspend,
-	.resume =	pcm3008_soc_resume,
-};
-
-static int pcm3008_codec_probe(struct platform_device *pdev)
-{
 	return snd_soc_register_codec(&pdev->dev,
 			&soc_codec_dev_pcm3008, &pcm3008_dai, 1);
 }
@@ -158,6 +151,7 @@
 static int pcm3008_codec_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_codec(&pdev->dev);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index ce585e3..c26a8f8 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -50,8 +50,6 @@
 
 static struct reg_default init_list[] = {
 	{RT5640_PR_BASE + 0x3d,	0x3600},
-	{RT5640_PR_BASE + 0x1c,	0x0D21},
-	{RT5640_PR_BASE + 0x1b,	0x0000},
 	{RT5640_PR_BASE + 0x12,	0x0aa8},
 	{RT5640_PR_BASE + 0x14,	0x0aaa},
 	{RT5640_PR_BASE + 0x20,	0x6110},
@@ -384,15 +382,11 @@
 
 static const struct snd_kcontrol_new rt5640_snd_controls[] = {
 	/* Speaker Output Volume */
-	SOC_DOUBLE("Speaker Playback Switch", RT5640_SPK_VOL,
-		RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
 	SOC_DOUBLE("Speaker Channel Switch", RT5640_SPK_VOL,
 		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
 	SOC_DOUBLE_TLV("Speaker Playback Volume", RT5640_SPK_VOL,
 		RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 39, 1, out_vol_tlv),
 	/* Headphone Output Volume */
-	SOC_DOUBLE("HP Playback Switch", RT5640_HP_VOL,
-		RT5640_L_MUTE_SFT, RT5640_R_MUTE_SFT, 1, 1),
 	SOC_DOUBLE("HP Channel Switch", RT5640_HP_VOL,
 		RT5640_VOL_L_SFT, RT5640_VOL_R_SFT, 1, 1),
 	SOC_DOUBLE_TLV("HP Playback Volume", RT5640_HP_VOL,
@@ -737,28 +731,21 @@
 			RT5640_M_BST1_MM_SFT, 1, 1),
 };
 
-/* INL/R source */
-static const char * const rt5640_inl_src[] = {
-	"IN2P", "MONOP"
-};
+static const struct snd_kcontrol_new spk_l_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
+		RT5640_L_MUTE_SFT, 1, 1);
 
-static const SOC_ENUM_SINGLE_DECL(
-	rt5640_inl_enum, RT5640_INL_INR_VOL,
-	RT5640_INL_SEL_SFT, rt5640_inl_src);
+static const struct snd_kcontrol_new spk_r_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_SPK_VOL,
+		RT5640_R_MUTE_SFT, 1, 1);
 
-static const struct snd_kcontrol_new rt5640_inl_mux =
-	SOC_DAPM_ENUM("INL source", rt5640_inl_enum);
+static const struct snd_kcontrol_new hp_l_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
+		RT5640_L_MUTE_SFT, 1, 1);
 
-static const char * const rt5640_inr_src[] = {
-	"IN2N", "MONON"
-};
-
-static const SOC_ENUM_SINGLE_DECL(
-	rt5640_inr_enum, RT5640_INL_INR_VOL,
-	RT5640_INR_SEL_SFT, rt5640_inr_src);
-
-static const struct snd_kcontrol_new rt5640_inr_mux =
-	SOC_DAPM_ENUM("INR source", rt5640_inr_enum);
+static const struct snd_kcontrol_new hp_r_enable_control =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5640_HP_VOL,
+		RT5640_R_MUTE_SFT, 1, 1);
 
 /* Stereo ADC source */
 static const char * const rt5640_stereo_adc1_src[] = {
@@ -891,33 +878,6 @@
 static const struct snd_kcontrol_new rt5640_sdi_mux =
 	SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum);
 
-static int spk_event(struct snd_soc_dapm_widget *w,
-	struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
-					0x0001, 0x0001);
-		regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
-					0xf000, 0xf000);
-		break;
-
-	case SND_SOC_DAPM_PRE_PMD:
-		regmap_update_bits(rt5640->regmap, RT5640_PR_BASE + 0x1c,
-					0xf000, 0x0000);
-		regmap_update_bits(rt5640->regmap, RT5640_PWR_DIG1,
-					0x0001, 0x0000);
-		break;
-
-	default:
-		return 0;
-	}
-	return 0;
-}
-
 static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -966,6 +926,117 @@
 	return 0;
 }
 
+void hp_amp_power_on(struct snd_soc_codec *codec)
+{
+	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+	/* depop parameters */
+	regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+		RT5640_CHPUMP_INT_REG1, 0x0700, 0x0200);
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+		RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+		RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+		RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
+	regmap_write(rt5640->regmap, RT5640_PR_BASE + RT5640_HP_DCC_INT1,
+			   0x9f00);
+	/* headphone amp power on */
+	regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+		RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
+	regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+		RT5640_PWR_HA,
+		RT5640_PWR_HA);
+	usleep_range(10000, 15000);
+	regmap_update_bits(rt5640->regmap, RT5640_PWR_ANLG1,
+		RT5640_PWR_FV1 | RT5640_PWR_FV2 ,
+		RT5640_PWR_FV1 | RT5640_PWR_FV2);
+}
+
+static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+{
+	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M2,
+		RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK,
+		RT5640_DEPOP_AUTO | RT5640_DIG_DP_EN);
+	regmap_update_bits(rt5640->regmap, RT5640_CHARGE_PUMP,
+		RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M3,
+		RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+		(RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+		(RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+		(RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+
+	regmap_write(rt5640->regmap, RT5640_PR_BASE +
+		RT5640_MAMP_INT_REG2, 0x1c00);
+	regmap_update_bits(rt5640->regmap, RT5640_DEPOP_M1,
+		RT5640_HP_CP_MASK | RT5640_HP_SG_MASK,
+		RT5640_HP_CP_PD | RT5640_HP_SG_EN);
+	regmap_update_bits(rt5640->regmap, RT5640_PR_BASE +
+		RT5640_CHPUMP_INT_REG1, 0x0700, 0x0400);
+}
+
+static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		rt5640_pmu_depop(codec);
+		rt5640->hp_mute = 0;
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		rt5640->hp_mute = 1;
+		usleep_range(70000, 75000);
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		hp_amp_power_on(codec);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (!rt5640->hp_mute)
+			usleep_range(80000, 85000);
+
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2,
 			RT5640_PWR_PLL_BIT, 0, NULL, 0),
@@ -1005,9 +1076,6 @@
 		RT5640_PWR_IN_L_BIT, 0, NULL, 0),
 	SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL,
 		RT5640_PWR_IN_R_BIT, 0, NULL, 0),
-	/* IN Mux */
-	SND_SOC_DAPM_MUX("INL Mux", SND_SOC_NOPM, 0, 0, &rt5640_inl_mux),
-	SND_SOC_DAPM_MUX("INR Mux", SND_SOC_NOPM, 0, 0, &rt5640_inr_mux),
 	/* REC Mixer */
 	SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0,
 			rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)),
@@ -1158,15 +1226,28 @@
 		rt5640_mono_mix, ARRAY_SIZE(rt5640_mono_mix)),
 	SND_SOC_DAPM_SUPPLY("Improve MONO Amp Drv", RT5640_PWR_ANLG1,
 		RT5640_PWR_MA_BIT, 0, NULL, 0),
-	SND_SOC_DAPM_SUPPLY("Improve HP Amp Drv", RT5640_PWR_ANLG1,
-		SND_SOC_NOPM, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("HP L Amp", RT5640_PWR_ANLG1,
+	SND_SOC_DAPM_SUPPLY_S("Improve HP Amp Drv", 1, SND_SOC_NOPM,
+		0, 0, rt5640_hp_power_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0,
+		rt5640_hp_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SUPPLY("HP L Amp", RT5640_PWR_ANLG1,
 		RT5640_PWR_HP_L_BIT, 0, NULL, 0),
-	SND_SOC_DAPM_PGA("HP R Amp", RT5640_PWR_ANLG1,
+	SND_SOC_DAPM_SUPPLY("HP R Amp", RT5640_PWR_ANLG1,
 		RT5640_PWR_HP_R_BIT, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("Improve SPK Amp Drv", RT5640_PWR_DIG1,
-		SND_SOC_NOPM, 0, spk_event,
-		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+		RT5640_PWR_CLS_D_BIT, 0, NULL, 0),
+
+	/* Output Switch */
+	SND_SOC_DAPM_SWITCH("Speaker L Playback", SND_SOC_NOPM, 0, 0,
+			&spk_l_enable_control),
+	SND_SOC_DAPM_SWITCH("Speaker R Playback", SND_SOC_NOPM, 0, 0,
+			&spk_r_enable_control),
+	SND_SOC_DAPM_SWITCH("HP L Playback", SND_SOC_NOPM, 0, 0,
+			&hp_l_enable_control),
+	SND_SOC_DAPM_SWITCH("HP R Playback", SND_SOC_NOPM, 0, 0,
+			&hp_r_enable_control),
+	SND_SOC_DAPM_POST("HP Post", rt5640_hp_post_event),
 	/* Output Lines */
 	SND_SOC_DAPM_OUTPUT("SPOLP"),
 	SND_SOC_DAPM_OUTPUT("SPOLN"),
@@ -1407,9 +1488,11 @@
 	{"HPO MIX L", "HPO MIX DAC2 Switch", "DAC L2"},
 	{"HPO MIX L", "HPO MIX DAC1 Switch", "DAC L1"},
 	{"HPO MIX L", "HPO MIX HPVOL Switch", "HPOVOL L"},
+	{"HPO MIX L", NULL, "HP L Amp"},
 	{"HPO MIX R", "HPO MIX DAC2 Switch", "DAC R2"},
 	{"HPO MIX R", "HPO MIX DAC1 Switch", "DAC R1"},
 	{"HPO MIX R", "HPO MIX HPVOL Switch", "HPOVOL R"},
+	{"HPO MIX R", NULL, "HP R Amp"},
 
 	{"LOUT MIX", "DAC L1 Switch", "DAC L1"},
 	{"LOUT MIX", "DAC R1 Switch", "DAC R1"},
@@ -1422,13 +1505,15 @@
 	{"Mono MIX", "OUTVOL L Switch", "OUTVOL L"},
 	{"Mono MIX", "BST1 Switch", "BST1"},
 
-	{"HP L Amp", NULL, "HPO MIX L"},
-	{"HP R Amp", NULL, "HPO MIX R"},
+	{"HP Amp", NULL, "HPO MIX L"},
+	{"HP Amp", NULL, "HPO MIX R"},
 
-	{"SPOLP", NULL, "SPOL MIX"},
-	{"SPOLN", NULL, "SPOL MIX"},
-	{"SPORP", NULL, "SPOR MIX"},
-	{"SPORN", NULL, "SPOR MIX"},
+	{"Speaker L Playback", "Switch", "SPOL MIX"},
+	{"Speaker R Playback", "Switch", "SPOR MIX"},
+	{"SPOLP", NULL, "Speaker L Playback"},
+	{"SPOLN", NULL, "Speaker L Playback"},
+	{"SPORP", NULL, "Speaker R Playback"},
+	{"SPORN", NULL, "Speaker R Playback"},
 
 	{"SPOLP", NULL, "Improve SPK Amp Drv"},
 	{"SPOLN", NULL, "Improve SPK Amp Drv"},
@@ -1438,8 +1523,10 @@
 	{"HPOL", NULL, "Improve HP Amp Drv"},
 	{"HPOR", NULL, "Improve HP Amp Drv"},
 
-	{"HPOL", NULL, "HP L Amp"},
-	{"HPOR", NULL, "HP R Amp"},
+	{"HP L Playback", "Switch", "HP Amp"},
+	{"HP R Playback", "Switch", "HP Amp"},
+	{"HPOL", NULL, "HP L Playback"},
+	{"HPOR", NULL, "HP R Playback"},
 	{"LOUTL", NULL, "LOUT MIX"},
 	{"LOUTR", NULL, "LOUT MIX"},
 	{"MONOP", NULL, "Mono MIX"},
@@ -1818,17 +1905,13 @@
 				RT5640_PWR_BG | RT5640_PWR_VREF2,
 				RT5640_PWR_VREF1 | RT5640_PWR_MB |
 				RT5640_PWR_BG | RT5640_PWR_VREF2);
-			mdelay(10);
+			usleep_range(10000, 15000);
 			snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
 				RT5640_PWR_FV1 | RT5640_PWR_FV2,
 				RT5640_PWR_FV1 | RT5640_PWR_FV2);
 			regcache_sync(rt5640->regmap);
 			snd_soc_update_bits(codec, RT5640_DUMMY1,
 						0x0301, 0x0301);
-			snd_soc_update_bits(codec, RT5640_DEPOP_M1,
-						0x001d, 0x0019);
-			snd_soc_update_bits(codec, RT5640_DEPOP_M2,
-						0x2000, 0x2000);
 			snd_soc_update_bits(codec, RT5640_MICBIAS,
 						0x0030, 0x0030);
 		}
@@ -1872,8 +1955,6 @@
 	rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	snd_soc_update_bits(codec, RT5640_DUMMY1, 0x0301, 0x0301);
-	snd_soc_update_bits(codec, RT5640_DEPOP_M1, 0x001d, 0x0019);
-	snd_soc_update_bits(codec, RT5640_DEPOP_M2, 0x2000, 0x2000);
 	snd_soc_update_bits(codec, RT5640_MICBIAS, 0x0030, 0x0030);
 	snd_soc_update_bits(codec, RT5640_DSP_PATH2, 0xfc00, 0x0c00);
 
@@ -2095,6 +2176,8 @@
 		regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
 					RT5640_IN_DF2, RT5640_IN_DF2);
 
+	rt5640->hp_mute = 1;
+
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
 			rt5640_dai, ARRAY_SIZE(rt5640_dai));
 	if (ret < 0)
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h
index c48286d..5e8df25a 100644
--- a/sound/soc/codecs/rt5640.h
+++ b/sound/soc/codecs/rt5640.h
@@ -145,6 +145,8 @@
 
 
 /* Index of Codec Private Register definition */
+#define RT5640_CHPUMP_INT_REG1			0x24
+#define RT5640_MAMP_INT_REG2			0x37
 #define RT5640_3D_SPK				0x63
 #define RT5640_WND_1				0x6c
 #define RT5640_WND_2				0x6d
@@ -153,6 +155,7 @@
 #define RT5640_WND_5				0x70
 #define RT5640_WND_8				0x73
 #define RT5640_DIP_SPK_INF			0x75
+#define RT5640_HP_DCC_INT1			0x77
 #define RT5640_EQ_BW_LOP			0xa0
 #define RT5640_EQ_GN_LOP			0xa1
 #define RT5640_EQ_FC_BP1			0xa2
@@ -1201,6 +1204,14 @@
 #define RT5640_CP_FQ2_SFT			4
 #define RT5640_CP_FQ3_MASK			(0x7)
 #define RT5640_CP_FQ3_SFT			0
+#define RT5640_CP_FQ_1_5_KHZ			0
+#define RT5640_CP_FQ_3_KHZ			1
+#define RT5640_CP_FQ_6_KHZ			2
+#define RT5640_CP_FQ_12_KHZ			3
+#define RT5640_CP_FQ_24_KHZ			4
+#define RT5640_CP_FQ_48_KHZ			5
+#define RT5640_CP_FQ_96_KHZ			6
+#define RT5640_CP_FQ_192_KHZ			7
 
 /* HPOUT charge pump (0x91) */
 #define RT5640_OSW_L_MASK			(0x1 << 11)
@@ -2087,6 +2098,7 @@
 	int pll_out;
 
 	int dmic_en;
+	bool hp_mute;
 };
 
 #endif
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 760e8bf..1f4093f 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -654,16 +654,19 @@
 		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
 			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
 			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP);
+
+		/* if using pll, clk_ctrl must be set after pll power up */
+		snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
 	} else {
+		/* otherwise, clk_ctrl must be set before pll power down */
+		snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+
 		/* power down pll */
 		snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
 			SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
 			0);
 	}
 
-	/* if using pll, clk_ctrl must be set after pll power up */
-	snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
-
 	return 0;
 }
 
@@ -1480,6 +1483,7 @@
 static const struct regmap_config sgtl5000_regmap = {
 	.reg_bits = 16,
 	.val_bits = 16,
+	.reg_stride = 2,
 
 	.max_register = SGTL5000_MAX_REG_OFFSET,
 	.volatile_reg = sgtl5000_volatile,
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 73e205c..38f3b10 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -102,6 +102,16 @@
 	return err;
 }
 
+static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+};
+
+static const struct snd_soc_dapm_route si476x_dapm_routes[] = {
+	{ "Capture", NULL, "LOUT" },
+	{ "Capture", NULL, "ROUT" },
+};
+
 static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
 				    unsigned int fmt)
 {
@@ -260,6 +270,10 @@
 	.probe  = si476x_codec_probe,
 	.read   = si476x_codec_read,
 	.write  = si476x_codec_write,
+	.dapm_widgets = si476x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
+	.dapm_routes = si476x_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes),
 };
 
 static int si476x_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index e9d7881..e3501f4 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -23,11 +23,26 @@
 #include <sound/initval.h>
 #include <linux/of.h>
 
+static const struct snd_soc_dapm_widget dir_widgets[] = {
+	SND_SOC_DAPM_INPUT("spdif-in"),
+};
+
+static const struct snd_soc_dapm_route dir_routes[] = {
+	{ "Capture", NULL, "spdif-in" },
+};
+
 #define STUB_RATES	SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
 			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
-static struct snd_soc_codec_driver soc_codec_spdif_dir;
+static struct snd_soc_codec_driver soc_codec_spdif_dir = {
+	.dapm_widgets = dir_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(dir_widgets),
+	.dapm_routes = dir_routes,
+	.num_dapm_routes = ARRAY_SIZE(dir_routes),
+};
 
 static struct snd_soc_dai_driver dir_stub_dai = {
 	.name		= "dir-hifi",
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index 1828049..a078aa3 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -25,10 +25,24 @@
 #define DRV_NAME "spdif-dit"
 
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
-#define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
+#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
 
+static const struct snd_soc_dapm_widget dit_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("spdif-out"),
+};
 
-static struct snd_soc_codec_driver soc_codec_spdif_dit;
+static const struct snd_soc_dapm_route dit_routes[] = {
+	{ "spdif-out", NULL, "Playback" },
+};
+
+static struct snd_soc_codec_driver soc_codec_spdif_dit = {
+	.dapm_widgets = dit_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(dit_widgets),
+	.dapm_routes = dit_routes,
+	.num_dapm_routes = ARRAY_SIZE(dit_routes),
+};
 
 static struct snd_soc_dai_driver dit_stub_dai = {
 	.name		= "dit-hifi",
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index f8d30e5..492644e 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -561,8 +561,9 @@
 
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
-	snd_soc_cache_sync(codec);
+	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
+	regcache_sync(ssm2602->regmap);
 	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index cfb55fe..06edb39 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -363,16 +363,18 @@
 	}
 
 	if (!sta32x->shutdown)
-		schedule_delayed_work(&sta32x->watchdog_work,
-				      round_jiffies_relative(HZ));
+		queue_delayed_work(system_power_efficient_wq,
+				   &sta32x->watchdog_work,
+				   round_jiffies_relative(HZ));
 }
 
 static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
 {
 	if (sta32x->pdata->needs_esd_watchdog) {
 		sta32x->shutdown = 0;
-		schedule_delayed_work(&sta32x->watchdog_work,
-				      round_jiffies_relative(HZ));
+		queue_delayed_work(system_power_efficient_wq,
+				   &sta32x->watchdog_work,
+				   round_jiffies_relative(HZ));
 	}
 }
 
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index b1f6982..7b8f3d9 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -29,7 +29,7 @@
 /* AIC26 driver private data */
 struct aic26 {
 	struct spi_device *spi;
-	struct snd_soc_codec codec;
+	struct snd_soc_codec *codec;
 	int master;
 	int datfm;
 	int mclk;
@@ -119,6 +119,22 @@
 	return 0;
 }
 
+static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route tlv320aic26_dapm_routes[] = {
+	{ "Capture", NULL, "MICIN" },
+	{ "Capture", NULL, "AUX" },
+
+	{ "HPL", NULL, "Playback" },
+	{ "HPR", NULL, "Playback" },
+};
+
 /* ---------------------------------------------------------------------
  * Digital Audio Interface Operations
  */
@@ -174,9 +190,9 @@
 	dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval);
 	qval = 0;
 	reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
-	aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
+	snd_soc_write(codec, AIC26_REG_PLL_PROG1, reg);
 	reg = dval << 2;
-	aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
+	snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg);
 
 	/* Audio Control 3 (master mode, fsref rate) */
 	reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
@@ -185,13 +201,13 @@
 		reg |= 0x0800;
 	if (fsref == 48000)
 		reg |= 0x2000;
-	aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
 	/* Audio Control 1 (FSref divisor) */
 	reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
 	reg &= ~0x0fff;
 	reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
-	aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
 
 	return 0;
 }
@@ -212,7 +228,7 @@
 		reg |= 0x8080;
 	else
 		reg &= ~0x8080;
-	aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg);
+	snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg);
 
 	return 0;
 }
@@ -330,7 +346,7 @@
 	struct aic26 *aic26 = dev_get_drvdata(dev);
 	int val, amp, freq, len;
 
-	val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+	val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
 	amp = (val >> 12) & 0x7;
 	freq = (125 << ((val >> 8) & 0x7)) >> 1;
 	len = 2 * (1 + ((val >> 4) & 0xf));
@@ -346,9 +362,9 @@
 	struct aic26 *aic26 = dev_get_drvdata(dev);
 	int val;
 
-	val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+	val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
 	val |= 0x8000;
-	aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+	snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
 
 	return count;
 }
@@ -360,25 +376,26 @@
  */
 static int aic26_probe(struct snd_soc_codec *codec)
 {
+	struct aic26 *aic26 = dev_get_drvdata(codec->dev);
 	int ret, err, i, reg;
 
-	dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
+	aic26->codec = codec;
 
 	/* Reset the codec to power on defaults */
-	aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
+	snd_soc_write(codec, AIC26_REG_RESET, 0xBB00);
 
 	/* Power up CODEC */
-	aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
+	snd_soc_write(codec, AIC26_REG_POWER_CTRL, 0);
 
 	/* Audio Control 3 (master mode, fsref rate) */
-	reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
+	reg = snd_soc_read(codec, AIC26_REG_AUDIO_CTRL3);
 	reg &= ~0xf800;
 	reg |= 0x0800; /* set master mode */
-	aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+	snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
 	/* Fill register cache */
 	for (i = 0; i < codec->driver->reg_cache_size; i++)
-		aic26_reg_read(codec, i);
+		snd_soc_read(codec, i);
 
 	/* Register the sysfs files for debugging */
 	/* Create SysFS files */
@@ -401,6 +418,10 @@
 	.write = aic26_reg_write,
 	.reg_cache_size = AIC26_NUM_REGS,
 	.reg_word_size = sizeof(u16),
+	.dapm_widgets = tlv320aic26_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets),
+	.dapm_routes = tlv320aic26_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes),
 };
 
 /* ---------------------------------------------------------------------
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 17df4e3..2ed57d4 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -338,18 +338,6 @@
 	return -EINVAL;
 }
 
-static int aic32x4_add_widgets(struct snd_soc_codec *codec)
-{
-	snd_soc_dapm_new_controls(&codec->dapm, aic32x4_dapm_widgets,
-				  ARRAY_SIZE(aic32x4_dapm_widgets));
-
-	snd_soc_dapm_add_routes(&codec->dapm, aic32x4_dapm_routes,
-				ARRAY_SIZE(aic32x4_dapm_routes));
-
-	snd_soc_dapm_new_widgets(&codec->dapm);
-	return 0;
-}
-
 static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
@@ -683,9 +671,6 @@
 	}
 
 	aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-	snd_soc_add_codec_controls(codec, aic32x4_snd_controls,
-			     ARRAY_SIZE(aic32x4_snd_controls));
-	aic32x4_add_widgets(codec);
 
 	/*
 	 * Workaround: for an unknown reason, the ADC needs to be powered up
@@ -714,6 +699,13 @@
 	.suspend = aic32x4_suspend,
 	.resume = aic32x4_resume,
 	.set_bias_level = aic32x4_set_bias_level,
+
+	.controls = aic32x4_snd_controls,
+	.num_controls = ARRAY_SIZE(aic32x4_snd_controls),
+	.dapm_widgets = aic32x4_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
+	.dapm_routes = aic32x4_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
 };
 
 static int aic32x4_i2c_probe(struct i2c_client *i2c,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index e5b9268..6e3f269 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -138,8 +138,7 @@
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -147,10 +146,9 @@
 	int max = mc->max;
 	unsigned int mask = (1 << fls(max)) - 1;
 	unsigned int invert = mc->invert;
-	unsigned short val, val_mask;
-	int ret;
-	struct snd_soc_dapm_path *path;
-	int found = 0;
+	unsigned short val;
+	struct snd_soc_dapm_update update;
+	int connect, change;
 
 	val = (ucontrol->value.integer.value[0] & mask);
 
@@ -158,42 +156,26 @@
 	if (val)
 		val = mask;
 
+	connect = !!val;
+
 	if (invert)
 		val = mask - val;
-	val_mask = mask << shift;
-	val = val << shift;
 
-	mutex_lock(&widget->codec->mutex);
+	mask <<= shift;
+	val <<= shift;
 
-	if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
-		/* find dapm widget path assoc with kcontrol */
-		list_for_each_entry(path, &widget->dapm->card->paths, list) {
-			if (path->kcontrol != kcontrol)
-				continue;
+	change = snd_soc_test_bits(codec, val, mask, reg);
+	if (change) {
+		update.kcontrol = kcontrol;
+		update.reg = reg;
+		update.mask = mask;
+		update.val = val;
 
-			/* found, now check type */
-			found = 1;
-			if (val)
-				/* new connection */
-				path->connect = invert ? 0 : 1;
-			else
-				/* old connection must be powered down */
-				path->connect = invert ? 1 : 0;
-
-			dapm_mark_dirty(path->source, "tlv320aic3x source");
-			dapm_mark_dirty(path->sink, "tlv320aic3x sink");
-
-			break;
-		}
+		snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect,
+			&update);
 	}
 
-	mutex_unlock(&widget->codec->mutex);
-
-	if (found)
-		snd_soc_dapm_sync(widget->dapm);
-
-	ret = snd_soc_update_bits_locked(widget->codec, reg, val_mask, val);
-	return ret;
+	return change;
 }
 
 /*
@@ -1492,6 +1474,7 @@
 	{ "tlv320aic3x", AIC3X_MODEL_3X },
 	{ "tlv320aic33", AIC3X_MODEL_33 },
 	{ "tlv320aic3007", AIC3X_MODEL_3007 },
+	{ "tlv320aic3106", AIC3X_MODEL_3X },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1582,6 +1565,9 @@
 #if defined(CONFIG_OF)
 static const struct of_device_id tlv320aic3x_of_match[] = {
 	{ .compatible = "ti,tlv320aic3x", },
+	{ .compatible = "ti,tlv320aic33" },
+	{ .compatible = "ti,tlv320aic3007" },
+	{ .compatible = "ti,tlv320aic3106" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 8e6e5b0..1e3884d 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -137,8 +137,6 @@
 
 /* codec private data */
 struct twl4030_priv {
-	struct snd_soc_codec codec;
-
 	unsigned int codec_powered;
 
 	/* reference counts of AIF/APLL users */
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 44621dd..3c79dbb 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -429,7 +429,8 @@
 	struct snd_soc_codec *codec = data;
 	struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
-	schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200));
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->hs_jack.work, msecs_to_jiffies(200));
 
 	return IRQ_HANDLED;
 }
@@ -437,9 +438,7 @@
 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val;
 
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 6d0aa44..c94d4c1 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -325,7 +325,6 @@
 static int uda134x_set_bias_level(struct snd_soc_codec *codec,
 				  enum snd_soc_bias_level level)
 {
-	u8 reg;
 	struct uda134x_platform_data *pd = codec->control_data;
 	int i;
 	u8 *cache = codec->reg_cache;
@@ -334,23 +333,6 @@
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		/* ADC, DAC on */
-		switch (pd->model) {
-		case UDA134X_UDA1340:
-		case UDA134X_UDA1344:
-		case UDA134X_UDA1345:
-			reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
-			uda134x_write(codec, UDA134X_DATA011, reg | 0x03);
-			break;
-		case UDA134X_UDA1341:
-			reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
-			uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
-			break;
-		default:
-			printk(KERN_ERR "UDA134X SoC codec: "
-			       "unsupported model %d\n", pd->model);
-			return -EINVAL;
-		}
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		/* power on */
@@ -362,23 +344,6 @@
 		}
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		/* ADC, DAC power off */
-		switch (pd->model) {
-		case UDA134X_UDA1340:
-		case UDA134X_UDA1344:
-		case UDA134X_UDA1345:
-			reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
-			uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03));
-			break;
-		case UDA134X_UDA1341:
-			reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
-			uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
-			break;
-		default:
-			printk(KERN_ERR "UDA134X SoC codec: "
-			       "unsupported model %d\n", pd->model);
-			return -EINVAL;
-		}
 		break;
 	case SND_SOC_BIAS_OFF:
 		/* power off */
@@ -450,6 +415,37 @@
 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
 };
 
+/* UDA1341 has the DAC/ADC power down in STATUS1 */
+static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
+};
+
+/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
+static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
+	SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
+};
+
+/* Common DAPM widgets */
+static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("VINL1"),
+	SND_SOC_DAPM_INPUT("VINR1"),
+	SND_SOC_DAPM_INPUT("VINL2"),
+	SND_SOC_DAPM_INPUT("VINR2"),
+	SND_SOC_DAPM_OUTPUT("VOUTL"),
+	SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
+	{ "ADC", NULL, "VINL1" },
+	{ "ADC", NULL, "VINR1" },
+	{ "ADC", NULL, "VINL2" },
+	{ "ADC", NULL, "VINR2" },
+	{ "VOUTL", NULL, "DAC" },
+	{ "VOUTR", NULL, "DAC" },
+};
+
 static const struct snd_soc_dai_ops uda134x_dai_ops = {
 	.startup	= uda134x_startup,
 	.shutdown	= uda134x_shutdown,
@@ -485,6 +481,8 @@
 {
 	struct uda134x_priv *uda134x;
 	struct uda134x_platform_data *pd = codec->card->dev->platform_data;
+	const struct snd_soc_dapm_widget *widgets;
+	unsigned num_widgets;
 
 	int ret;
 
@@ -526,6 +524,22 @@
 	else
 		uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+	if (pd->model == UDA134X_UDA1341) {
+		widgets = uda1341_dapm_widgets;
+		num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
+	} else {
+		widgets = uda1340_dapm_widgets;
+		num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
+	}
+
+	ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets);
+	if (ret) {
+		printk(KERN_ERR "%s failed to register dapm controls: %d",
+			__func__, ret);
+		kfree(uda134x);
+		return ret;
+	}
+
 	switch (pd->model) {
 	case UDA134X_UDA1340:
 	case UDA134X_UDA1344:
@@ -599,6 +613,10 @@
 	.read = uda134x_read_reg_cache,
 	.write = uda134x_write,
 	.set_bias_level = uda134x_set_bias_level,
+	.dapm_widgets = uda134x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
+	.dapm_routes = uda134x_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
 };
 
 static int uda134x_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 54cd3da..b7ab2ef 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -290,6 +290,18 @@
 		       snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
 };
 
+static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("RX"),
+
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route wl1273_dapm_routes[] = {
+	{ "Capture", NULL, "RX" },
+
+	{ "TX", NULL, "Playback" },
+};
+
 static int wl1273_startup(struct snd_pcm_substream *substream,
 			  struct snd_soc_dai *dai)
 {
@@ -483,6 +495,11 @@
 static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
 	.probe = wl1273_probe,
 	.remove = wl1273_remove,
+
+	.dapm_widgets = wl1273_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets),
+	.dapm_routes = wl1273_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes),
 };
 
 static int wl1273_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 10adc41..d5ebcb0 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -420,7 +420,7 @@
 		xfer->codec = codec;
 		list_add_tail(&xfer->list, &xfer_list);
 
-		out = kzalloc(len, GFP_KERNEL);
+		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
 		if (!out) {
 			dev_err(codec->dev,
 				"Failed to allocate RX buffer\n");
@@ -429,7 +429,7 @@
 		}
 		xfer->t.rx_buf = out;
 
-		img = kzalloc(len, GFP_KERNEL);
+		img = kzalloc(len, GFP_KERNEL | GFP_DMA);
 		if (!img) {
 			dev_err(codec->dev,
 				"Failed to allocate image buffer\n");
@@ -523,14 +523,14 @@
 	dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
 
 	/* Copy to local buffer first as vmalloc causes problems for dma */
-	img = kzalloc(fw->size, GFP_KERNEL);
+	img = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
 	if (!img) {
 		dev_err(codec->dev, "Failed to allocate image buffer\n");
 		ret = -ENOMEM;
 		goto abort2;
 	}
 
-	out = kzalloc(fw->size, GFP_KERNEL);
+	out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
 	if (!out) {
 		dev_err(codec->dev, "Failed to allocate output buffer\n");
 		ret = -ENOMEM;
@@ -670,14 +670,14 @@
 
 		ret = -ENOMEM;
 		len = pll_rec.length + 8;
-		out = kzalloc(len, GFP_KERNEL);
+		out = kzalloc(len, GFP_KERNEL | GFP_DMA);
 		if (!out) {
 			dev_err(codec->dev,
 				"Failed to allocate RX buffer\n");
 			goto abort;
 		}
 
-		img_swap = kzalloc(len, GFP_KERNEL);
+		img_swap = kzalloc(len, GFP_KERNEL | GFP_DMA);
 		if (!img_swap) {
 			dev_err(codec->dev,
 				"Failed to allocate image buffer\n");
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 282fd23..8bbddc1 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -998,6 +998,8 @@
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
 
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
@@ -1421,9 +1423,6 @@
 	{ "Tone Generator 1", NULL, "TONE" },
 	{ "Tone Generator 2", NULL, "TONE" },
 
-	{ "Mic Mute Mixer", NULL, "Noise Mixer" },
-	{ "Mic Mute Mixer", NULL, "Mic Mixer" },
-
 	{ "AIF1 Capture", NULL, "AIF1TX1" },
 	{ "AIF1 Capture", NULL, "AIF1TX2" },
 	{ "AIF1 Capture", NULL, "AIF1TX3" },
@@ -1499,23 +1498,6 @@
 	{ "IN3L PGA", NULL, "IN3L" },
 	{ "IN3R PGA", NULL, "IN3R" },
 
-	{ "ASRC1L", NULL, "ASRC1L Input" },
-	{ "ASRC1R", NULL, "ASRC1R Input" },
-	{ "ASRC2L", NULL, "ASRC2L Input" },
-	{ "ASRC2R", NULL, "ASRC2R Input" },
-
-	{ "ISRC1DEC1", NULL, "ISRC1DEC1 Input" },
-	{ "ISRC1DEC2", NULL, "ISRC1DEC2 Input" },
-
-	{ "ISRC1INT1", NULL, "ISRC1INT1 Input" },
-	{ "ISRC1INT2", NULL, "ISRC1INT2 Input" },
-
-	{ "ISRC2DEC1", NULL, "ISRC2DEC1 Input" },
-	{ "ISRC2DEC2", NULL, "ISRC2DEC2 Input" },
-
-	{ "ISRC2INT1", NULL, "ISRC2INT1 Input" },
-	{ "ISRC2INT2", NULL, "ISRC2INT2 Input" },
-
 	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
 	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
 	ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
@@ -1567,22 +1549,25 @@
 	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
 	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
 
-	ARIZONA_MUX_ROUTES("ASRC1L"),
-	ARIZONA_MUX_ROUTES("ASRC1R"),
-	ARIZONA_MUX_ROUTES("ASRC2L"),
-	ARIZONA_MUX_ROUTES("ASRC2R"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
 
-	ARIZONA_MUX_ROUTES("ISRC1INT1"),
-	ARIZONA_MUX_ROUTES("ISRC1INT2"),
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
 
-	ARIZONA_MUX_ROUTES("ISRC1DEC1"),
-	ARIZONA_MUX_ROUTES("ISRC1DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
 
-	ARIZONA_MUX_ROUTES("ISRC2INT1"),
-	ARIZONA_MUX_ROUTES("ISRC2INT2"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
 
-	ARIZONA_MUX_ROUTES("ISRC2DEC1"),
-	ARIZONA_MUX_ROUTES("ISRC2DEC2"),
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
 
 	ARIZONA_DSP_ROUTES("DSP1"),
 
@@ -1614,6 +1599,9 @@
 	{ "SPKDAT1R", NULL, "OUT5R" },
 
 	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
 };
 
 static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
@@ -1781,6 +1769,7 @@
 		return ret;
 
 	arizona_init_spk(codec);
+	arizona_init_gpio(codec);
 
 	snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 2e7cb4b..bbd6438 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -58,14 +58,10 @@
 	SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
 
 static const struct snd_kcontrol_new wm5110_snd_controls[] = {
-SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
-	   ARIZONA_IN1_OSR_SHIFT, 1, 0),
-SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
-	   ARIZONA_IN2_OSR_SHIFT, 1, 0),
-SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
-	   ARIZONA_IN3_OSR_SHIFT, 1, 0),
-SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL,
-	   ARIZONA_IN4_OSR_SHIFT, 1, 0),
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+SOC_ENUM("IN3 OSR", arizona_in_dmic_osr[2]),
+SOC_ENUM("IN4 OSR", arizona_in_dmic_osr[3]),
 
 SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
 		     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
@@ -432,6 +428,9 @@
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
 
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
 		   0, NULL, 0, arizona_in_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
@@ -842,9 +841,6 @@
 	{ "Tone Generator 1", NULL, "TONE" },
 	{ "Tone Generator 2", NULL, "TONE" },
 
-	{ "Mic Mute Mixer", NULL, "Noise Mixer" },
-	{ "Mic Mute Mixer", NULL, "Mic Mixer" },
-
 	{ "AIF1 Capture", NULL, "AIF1TX1" },
 	{ "AIF1 Capture", NULL, "AIF1TX2" },
 	{ "AIF1 Capture", NULL, "AIF1TX3" },
@@ -979,10 +975,13 @@
 	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
 	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
 
-	ARIZONA_MUX_ROUTES("ASRC1L"),
-	ARIZONA_MUX_ROUTES("ASRC1R"),
-	ARIZONA_MUX_ROUTES("ASRC2L"),
-	ARIZONA_MUX_ROUTES("ASRC2R"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+	ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+	ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+	ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+	ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
 
 	{ "HPOUT1L", NULL, "OUT1L" },
 	{ "HPOUT1R", NULL, "OUT1R" },
@@ -1006,6 +1005,11 @@
 	{ "SPKDAT2R", NULL, "OUT6R" },
 
 	{ "MICSUPP", NULL, "SYSCLK" },
+
+	{ "DRC1 Signal Activity", NULL, "DRC1L" },
+	{ "DRC1 Signal Activity", NULL, "DRC1R" },
+	{ "DRC2 Signal Activity", NULL, "DRC2L" },
+	{ "DRC2 Signal Activity", NULL, "DRC2R" },
 };
 
 static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
@@ -1170,6 +1174,7 @@
 		return ret;
 
 	arizona_init_spk(codec);
+	arizona_init_gpio(codec);
 
 	snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 0e8b3aa..af1318d 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1301,7 +1301,8 @@
 	if (device_may_wakeup(wm8350->dev))
 		pm_wakeup_event(wm8350->dev, 250);
 
-	schedule_delayed_work(&priv->hpl.work, msecs_to_jiffies(200));
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->hpl.work, msecs_to_jiffies(200));
 
 	return IRQ_HANDLED;
 }
@@ -1318,7 +1319,8 @@
 	if (device_may_wakeup(wm8350->dev))
 		pm_wakeup_event(wm8350->dev, 250);
 
-	schedule_delayed_work(&priv->hpr.work, msecs_to_jiffies(200));
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->hpr.work, msecs_to_jiffies(200));
 
 	return IRQ_HANDLED;
 }
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
index 462f5e4..7b1a6d5 100644
--- a/sound/soc/codecs/wm8727.c
+++ b/sound/soc/codecs/wm8727.c
@@ -23,6 +23,16 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
+static const struct snd_soc_dapm_widget wm8727_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8727_dapm_routes[] = {
+	{ "VOUTL", NULL, "Playback" },
+	{ "VOUTR", NULL, "Playback" },
+};
+
 /*
  * Note this is a simple chip with no configuration interface, sample rate is
  * determined automatically by examining the Master clock and Bit clock ratios
@@ -43,7 +53,12 @@
 		},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8727;
+static struct snd_soc_codec_driver soc_codec_dev_wm8727 = {
+	.dapm_widgets = wm8727_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8727_dapm_widgets),
+	.dapm_routes = wm8727_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8727_dapm_routes),
+};
 
 static int wm8727_probe(struct platform_device *pdev)
 {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 5276062..456bb8c 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -45,6 +45,7 @@
 struct wm8731_priv {
 	struct regmap *regmap;
 	struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
+	const struct snd_pcm_hw_constraint_list *constraints;
 	unsigned int sysclk;
 	int sysclk_type;
 	int playback_fs;
@@ -290,6 +291,36 @@
 	{12000000, 88200, 136, 0xf, 0x1, 0x1},
 };
 
+/* rates constraints */
+static const unsigned int wm8731_rates_12000000[] = {
+	8000, 32000, 44100, 48000, 96000, 88200,
+};
+
+static const unsigned int wm8731_rates_12288000_18432000[] = {
+	8000, 32000, 48000, 96000,
+};
+
+static const unsigned int wm8731_rates_11289600_16934400[] = {
+	8000, 44100, 88200,
+};
+
+static const struct snd_pcm_hw_constraint_list wm8731_constraints_12000000 = {
+	.list = wm8731_rates_12000000,
+	.count = ARRAY_SIZE(wm8731_rates_12000000),
+};
+
+static const
+struct snd_pcm_hw_constraint_list wm8731_constraints_12288000_18432000 = {
+	.list = wm8731_rates_12288000_18432000,
+	.count = ARRAY_SIZE(wm8731_rates_12288000_18432000),
+};
+
+static const
+struct snd_pcm_hw_constraint_list wm8731_constraints_11289600_16934400 = {
+	.list = wm8731_rates_11289600_16934400,
+	.count = ARRAY_SIZE(wm8731_rates_11289600_16934400),
+};
+
 static inline int get_coeff(int mclk, int rate)
 {
 	int i;
@@ -362,17 +393,26 @@
 	}
 
 	switch (freq) {
-	case 11289600:
+	case 0:
+		wm8731->constraints = NULL;
+		break;
 	case 12000000:
+		wm8731->constraints = &wm8731_constraints_12000000;
+		break;
 	case 12288000:
-	case 16934400:
 	case 18432000:
-		wm8731->sysclk = freq;
+		wm8731->constraints = &wm8731_constraints_12288000_18432000;
+		break;
+	case 16934400:
+	case 11289600:
+		wm8731->constraints = &wm8731_constraints_11289600_16934400;
 		break;
 	default:
 		return -EINVAL;
 	}
 
+	wm8731->sysclk = freq;
+
 	snd_soc_dapm_sync(&codec->dapm);
 
 	return 0;
@@ -475,12 +515,26 @@
 	return 0;
 }
 
+static int wm8731_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(dai->codec);
+
+	if (wm8731->constraints)
+		snd_pcm_hw_constraint_list(substream->runtime, 0,
+					   SNDRV_PCM_HW_PARAM_RATE,
+					   wm8731->constraints);
+
+	return 0;
+}
+
 #define WM8731_RATES SNDRV_PCM_RATE_8000_96000
 
 #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
 	SNDRV_PCM_FMTBIT_S24_LE)
 
 static const struct snd_soc_dai_ops wm8731_dai_ops = {
+	.startup	= wm8731_startup,
 	.hw_params	= wm8731_hw_params,
 	.digital_mute	= wm8731_mute,
 	.set_sysclk	= wm8731_set_dai_sysclk,
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 0a4ab4c..d96ebf5 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1456,8 +1456,9 @@
 	if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
 		wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
 		codec->dapm.bias_level = SND_SOC_BIAS_ON;
-		schedule_delayed_work(&codec->dapm.delayed_work,
-			msecs_to_jiffies(caps_charge));
+		queue_delayed_work(system_power_efficient_wq,
+				   &codec->dapm.delayed_work,
+				   msecs_to_jiffies(caps_charge));
 	}
 
 	return 0;
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c
index f1fdbf6..8092495 100644
--- a/sound/soc/codecs/wm8782.c
+++ b/sound/soc/codecs/wm8782.c
@@ -26,6 +26,16 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
+static const struct snd_soc_dapm_widget wm8782_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route wm8782_dapm_routes[] = {
+	{ "Capture", NULL, "AINL" },
+	{ "Capture", NULL, "AINR" },
+};
+
 static struct snd_soc_dai_driver wm8782_dai = {
 	.name = "wm8782",
 	.capture = {
@@ -40,7 +50,12 @@
 	},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8782;
+static struct snd_soc_codec_driver soc_codec_dev_wm8782 = {
+	.dapm_widgets = wm8782_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8782_dapm_widgets),
+	.dapm_routes = wm8782_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8782_dapm_routes),
+};
 
 static int wm8782_probe(struct platform_device *pdev)
 {
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index fa24ced..eebcb1d 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -364,9 +364,7 @@
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	u16 reg;
 	int ret;
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 4c9fb14..4dfa8dc 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1012,7 +1012,7 @@
 	SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
 
 static const struct snd_kcontrol_new liner_mux =
-	SOC_DAPM_ENUM("LINEL Mux", liner_enum);
+	SOC_DAPM_ENUM("LINER Mux", liner_enum);
 
 static const char *sidetone_text[] = {
 	"None", "Left", "Right"
@@ -1202,7 +1202,6 @@
 		break;
 	}
 
-	snd_soc_dapm_new_widgets(dapm);
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 0a4ffdd..f156010 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -263,8 +263,8 @@
 SOC_SINGLE("Noise Gate Threshold", WM8960_NOISEG, 3, 31, 0),
 SOC_SINGLE("Noise Gate Switch", WM8960_NOISEG, 0, 1, 0),
 
-SOC_DOUBLE_R("ADC PCM Capture Volume", WM8960_LINPATH, WM8960_RINPATH,
-	0, 127, 0),
+SOC_DOUBLE_R_TLV("ADC PCM Capture Volume", WM8960_LADC, WM8960_RADC,
+	0, 255, 0, adc_tlv),
 
 SOC_SINGLE_TLV("Left Output Mixer Boost Bypass Volume",
 	       WM8960_BYPASS1, 4, 7, 1, bypass_tlv),
@@ -857,9 +857,9 @@
 	if (pll_div.k) {
 		reg |= 0x20;
 
-		snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
-		snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
-		snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
+		snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
+		snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
+		snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff);
 	}
 	snd_soc_write(codec, WM8960_PLL1, reg);
 
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index e2de9ec..11d80f3 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2621,8 +2621,6 @@
 
 	wm8962->sysclk_rate = freq;
 
-	wm8962_configure_bclk(codec);
-
 	return 0;
 }
 
@@ -3046,8 +3044,9 @@
 
 		pm_wakeup_event(dev, 300);
 
-		schedule_delayed_work(&wm8962->mic_work,
-				      msecs_to_jiffies(250));
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8962->mic_work,
+				   msecs_to_jiffies(250));
 	}
 
 	return IRQ_HANDLED;
@@ -3175,7 +3174,7 @@
 	long int time;
 	int ret;
 
-	ret = strict_strtol(buf, 10, &time);
+	ret = kstrtol(buf, 10, &time);
 	if (ret != 0)
 		return ret;
 
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index ba832b7..86426a1 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -819,8 +819,9 @@
 		 * don't want false reports.
 		 */
 		if (wm8994->jackdet && !wm8994->clk_has_run) {
-			schedule_delayed_work(&wm8994->jackdet_bootstrap,
-					      msecs_to_jiffies(1000));
+			queue_delayed_work(system_power_efficient_wq,
+					   &wm8994->jackdet_bootstrap,
+					   msecs_to_jiffies(1000));
 			wm8994->clk_has_run = true;
 		}
 		break;
@@ -1432,14 +1433,12 @@
 
 #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
 	SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
-		snd_soc_get_volsw, wm8994_put_class_w)
+		snd_soc_dapm_get_volsw, wm8994_put_class_w)
 
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *w = wlist->widgets[0];
-	struct snd_soc_codec *codec = w->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -3487,7 +3486,8 @@
 
 	pm_wakeup_event(codec->dev, 300);
 
-	schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250));
+	queue_delayed_work(system_power_efficient_wq,
+			   &priv->mic_work, msecs_to_jiffies(250));
 
 	return IRQ_HANDLED;
 }
@@ -3575,8 +3575,9 @@
 		/* If nothing present then clear our statuses */
 		dev_dbg(codec->dev, "Detected open circuit\n");
 
-		schedule_delayed_work(&wm8994->open_circuit_work,
-				      msecs_to_jiffies(2500));
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8994->open_circuit_work,
+				   msecs_to_jiffies(2500));
 		return;
 	}
 
@@ -3690,8 +3691,9 @@
 				    WM1811_JACKDET_DB, 0);
 
 		delay = control->pdata.micdet_delay;
-		schedule_delayed_work(&wm8994->mic_work,
-				      msecs_to_jiffies(delay));
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8994->mic_work,
+				   msecs_to_jiffies(delay));
 	} else {
 		dev_dbg(codec->dev, "Jack not detected\n");
 
@@ -3936,8 +3938,9 @@
 	id_delay = wm8994->wm8994->pdata.mic_id_delay;
 
 	if (wm8994->mic_detecting)
-		schedule_delayed_work(&wm8994->mic_complete_work,
-				      msecs_to_jiffies(id_delay));
+		queue_delayed_work(system_power_efficient_wq,
+				   &wm8994->mic_complete_work,
+				   msecs_to_jiffies(id_delay));
 	else
 		wm8958_button_det(codec, reg);
 
@@ -4010,9 +4013,6 @@
 
 	wm8994->micdet_irq = control->pdata.micdet_irq;
 
-	pm_runtime_enable(codec->dev);
-	pm_runtime_idle(codec->dev);
-
 	/* By default use idle_bias_off, will override for WM8994 */
 	codec->dapm.idle_bias_off = 1;
 
@@ -4385,8 +4385,6 @@
 
 	wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-	pm_runtime_disable(codec->dev);
-
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
 		wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
 				&wm8994->fll_locked[i]);
@@ -4445,6 +4443,9 @@
 
 	wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
 
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
 	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
 			wm8994_dai, ARRAY_SIZE(wm8994_dai));
 }
@@ -4452,6 +4453,8 @@
 static int wm8994_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_codec(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
 	return 0;
 }
 
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 90a65c4..da2899e6 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -549,12 +549,9 @@
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *w = wlist->widgets[0];
-	struct snd_soc_codec *codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	int ret;
 
-	codec = w->codec;
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 	wm8995_update_class_w(codec);
 	return ret;
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
new file mode 100644
index 0000000..6ec3de3
--- /dev/null
+++ b/sound/soc/codecs/wm8997.c
@@ -0,0 +1,1175 @@
+/*
+ * wm8997.c  --  WM8997 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm8997.h"
+
+struct wm8997_priv {
+	struct arizona_priv core;
+	struct arizona_fll fll[2];
+};
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+static const struct reg_default wm8997_sysclk_reva_patch[] = {
+	{ 0x301D, 0x7B15 },
+	{ 0x301B, 0x0050 },
+	{ 0x305D, 0x7B17 },
+	{ 0x305B, 0x0050 },
+	{ 0x3001, 0x08FE },
+	{ 0x3003, 0x00F4 },
+	{ 0x3041, 0x08FF },
+	{ 0x3043, 0x0005 },
+	{ 0x3020, 0x0225 },
+	{ 0x3021, 0x0A00 },
+	{ 0x3022, 0xE24D },
+	{ 0x3023, 0x0800 },
+	{ 0x3024, 0xE24D },
+	{ 0x3025, 0xF000 },
+	{ 0x3060, 0x0226 },
+	{ 0x3061, 0x0A00 },
+	{ 0x3062, 0xE252 },
+	{ 0x3063, 0x0800 },
+	{ 0x3064, 0xE252 },
+	{ 0x3065, 0xF000 },
+	{ 0x3116, 0x022B },
+	{ 0x3117, 0xFA00 },
+	{ 0x3110, 0x246C },
+	{ 0x3111, 0x0A03 },
+	{ 0x3112, 0x246E },
+	{ 0x3113, 0x0A03 },
+	{ 0x3114, 0x2470 },
+	{ 0x3115, 0x0A03 },
+	{ 0x3126, 0x246C },
+	{ 0x3127, 0x0A02 },
+	{ 0x3128, 0x246E },
+	{ 0x3129, 0x0A02 },
+	{ 0x312A, 0x2470 },
+	{ 0x312B, 0xFA02 },
+	{ 0x3125, 0x0800 },
+};
+
+static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+	struct regmap *regmap = codec->control_data;
+	const struct reg_default *patch = NULL;
+	int i, patch_size;
+
+	switch (arizona->rev) {
+	case 0:
+		patch = wm8997_sysclk_reva_patch;
+		patch_size = ARRAY_SIZE(wm8997_sysclk_reva_patch);
+		break;
+	default:
+		break;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (patch)
+			for (i = 0; i < patch_size; i++)
+				regmap_write(regmap, patch[i].reg,
+					     patch[i].def);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static const char *wm8997_osr_text[] = {
+	"Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm8997_osr_val[] = {
+	0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm8997_hpout_osr[] = {
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+			      ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+			      wm8997_osr_text, wm8997_osr_val),
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+			      ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+			      wm8997_osr_text, wm8997_osr_val),
+};
+
+#define WM8997_NG_SRC(name, base) \
+	SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
+	SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
+	SOC_SINGLE(name " NG EPOUT Switch",    base, 4, 1, 0), \
+	SOC_SINGLE(name " NG SPKOUT Switch",   base, 6, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
+	SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0)
+
+static const struct snd_kcontrol_new wm8997_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
+	   ARIZONA_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
+	   ARIZONA_IN2_OSR_SHIFT, 1, 0),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+		     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+		     ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+		     ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+		     ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+	       ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+	       ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+	       ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+	       ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21,
+		   ARIZONA_EQ1_ENA_MASK),
+SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21,
+		   ARIZONA_EQ2_ENA_MASK),
+SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21,
+		   ARIZONA_EQ3_ENA_MASK),
+SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21,
+		   ARIZONA_EQ4_ENA_MASK),
+
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+	       24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+		   ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
+SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+
+SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+
+ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+	       ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+	   ARIZONA_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+	   ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	   ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	       ARIZONA_OUT4L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
+
+SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
+SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+	   ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+	       ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+WM8997_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+WM8997_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+WM8997_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L),
+WM8997_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+WM8997_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
+WM8997_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+
+static const char *wm8997_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "EPOUT", "SPKOUT", "SPKDAT1L", "SPKDAT1R",
+};
+
+static const unsigned int wm8997_aec_loopback_values[] = {
+	0, 1, 4, 6, 8, 9,
+};
+
+static const struct soc_enum wm8997_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+			      ARRAY_SIZE(wm8997_aec_loopback_texts),
+			      wm8997_aec_loopback_texts,
+			      wm8997_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
+	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback);
+
+static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
+		    0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+		    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+		    ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+		    ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+		   0, NULL, 0, arizona_in_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+		    ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+		    ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+		    ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+		 ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+		 ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
+		 ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+		 NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+		 NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+		 0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+		 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+		 ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+		 ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+		    ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+		     ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+		    ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+		     ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+		     ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+		    ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+		    ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+		       &wm8997_aec_loopback_mux),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+		   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+		   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
+ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("EPOUTN"),
+SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)	\
+	{ name, "Noise Generator", "Noise Generator" }, \
+	{ name, "Tone Generator 1", "Tone Generator 1" }, \
+	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "Haptics", "HAPTICS" }, \
+	{ name, "AEC", "AEC Loopback" }, \
+	{ name, "IN1L", "IN1L PGA" }, \
+	{ name, "IN1R", "IN1R PGA" }, \
+	{ name, "IN2L", "IN2L PGA" }, \
+	{ name, "IN2R", "IN2R PGA" }, \
+	{ name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
+	{ name, "AIF1RX1", "AIF1RX1" }, \
+	{ name, "AIF1RX2", "AIF1RX2" }, \
+	{ name, "AIF1RX3", "AIF1RX3" }, \
+	{ name, "AIF1RX4", "AIF1RX4" }, \
+	{ name, "AIF1RX5", "AIF1RX5" }, \
+	{ name, "AIF1RX6", "AIF1RX6" }, \
+	{ name, "AIF1RX7", "AIF1RX7" }, \
+	{ name, "AIF1RX8", "AIF1RX8" }, \
+	{ name, "AIF2RX1", "AIF2RX1" }, \
+	{ name, "AIF2RX2", "AIF2RX2" }, \
+	{ name, "SLIMRX1", "SLIMRX1" }, \
+	{ name, "SLIMRX2", "SLIMRX2" }, \
+	{ name, "SLIMRX3", "SLIMRX3" }, \
+	{ name, "SLIMRX4", "SLIMRX4" }, \
+	{ name, "SLIMRX5", "SLIMRX5" }, \
+	{ name, "SLIMRX6", "SLIMRX6" }, \
+	{ name, "SLIMRX7", "SLIMRX7" }, \
+	{ name, "SLIMRX8", "SLIMRX8" }, \
+	{ name, "EQ1", "EQ1" }, \
+	{ name, "EQ2", "EQ2" }, \
+	{ name, "EQ3", "EQ3" }, \
+	{ name, "EQ4", "EQ4" }, \
+	{ name, "DRC1L", "DRC1L" }, \
+	{ name, "DRC1R", "DRC1R" }, \
+	{ name, "LHPF1", "LHPF1" }, \
+	{ name, "LHPF2", "LHPF2" }, \
+	{ name, "LHPF3", "LHPF3" }, \
+	{ name, "LHPF4", "LHPF4" }, \
+	{ name, "ISRC1DEC1", "ISRC1DEC1" }, \
+	{ name, "ISRC1DEC2", "ISRC1DEC2" }, \
+	{ name, "ISRC1INT1", "ISRC1INT1" }, \
+	{ name, "ISRC1INT2", "ISRC1INT2" }, \
+	{ name, "ISRC2DEC1", "ISRC2DEC1" }, \
+	{ name, "ISRC2DEC2", "ISRC2DEC2" }, \
+	{ name, "ISRC2INT1", "ISRC2INT1" }, \
+	{ name, "ISRC2INT2", "ISRC2INT2" }
+
+static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {
+	{ "AIF2 Capture", NULL, "DBVDD2" },
+	{ "AIF2 Playback", NULL, "DBVDD2" },
+
+	{ "OUT1L", NULL, "CPVDD" },
+	{ "OUT1R", NULL, "CPVDD" },
+	{ "OUT3L", NULL, "CPVDD" },
+
+	{ "OUT4L", NULL, "SPKVDD" },
+
+	{ "OUT1L", NULL, "SYSCLK" },
+	{ "OUT1R", NULL, "SYSCLK" },
+	{ "OUT3L", NULL, "SYSCLK" },
+	{ "OUT4L", NULL, "SYSCLK" },
+
+	{ "IN1L", NULL, "SYSCLK" },
+	{ "IN1R", NULL, "SYSCLK" },
+	{ "IN2L", NULL, "SYSCLK" },
+	{ "IN2R", NULL, "SYSCLK" },
+
+	{ "MICBIAS1", NULL, "MICVDD" },
+	{ "MICBIAS2", NULL, "MICVDD" },
+	{ "MICBIAS3", NULL, "MICVDD" },
+
+	{ "Noise Generator", NULL, "SYSCLK" },
+	{ "Tone Generator 1", NULL, "SYSCLK" },
+	{ "Tone Generator 2", NULL, "SYSCLK" },
+
+	{ "Noise Generator", NULL, "NOISE" },
+	{ "Tone Generator 1", NULL, "TONE" },
+	{ "Tone Generator 2", NULL, "TONE" },
+
+	{ "AIF1 Capture", NULL, "AIF1TX1" },
+	{ "AIF1 Capture", NULL, "AIF1TX2" },
+	{ "AIF1 Capture", NULL, "AIF1TX3" },
+	{ "AIF1 Capture", NULL, "AIF1TX4" },
+	{ "AIF1 Capture", NULL, "AIF1TX5" },
+	{ "AIF1 Capture", NULL, "AIF1TX6" },
+	{ "AIF1 Capture", NULL, "AIF1TX7" },
+	{ "AIF1 Capture", NULL, "AIF1TX8" },
+
+	{ "AIF1RX1", NULL, "AIF1 Playback" },
+	{ "AIF1RX2", NULL, "AIF1 Playback" },
+	{ "AIF1RX3", NULL, "AIF1 Playback" },
+	{ "AIF1RX4", NULL, "AIF1 Playback" },
+	{ "AIF1RX5", NULL, "AIF1 Playback" },
+	{ "AIF1RX6", NULL, "AIF1 Playback" },
+	{ "AIF1RX7", NULL, "AIF1 Playback" },
+	{ "AIF1RX8", NULL, "AIF1 Playback" },
+
+	{ "AIF2 Capture", NULL, "AIF2TX1" },
+	{ "AIF2 Capture", NULL, "AIF2TX2" },
+
+	{ "AIF2RX1", NULL, "AIF2 Playback" },
+	{ "AIF2RX2", NULL, "AIF2 Playback" },
+
+	{ "Slim1 Capture", NULL, "SLIMTX1" },
+	{ "Slim1 Capture", NULL, "SLIMTX2" },
+	{ "Slim1 Capture", NULL, "SLIMTX3" },
+	{ "Slim1 Capture", NULL, "SLIMTX4" },
+
+	{ "SLIMRX1", NULL, "Slim1 Playback" },
+	{ "SLIMRX2", NULL, "Slim1 Playback" },
+	{ "SLIMRX3", NULL, "Slim1 Playback" },
+	{ "SLIMRX4", NULL, "Slim1 Playback" },
+
+	{ "Slim2 Capture", NULL, "SLIMTX5" },
+	{ "Slim2 Capture", NULL, "SLIMTX6" },
+
+	{ "SLIMRX5", NULL, "Slim2 Playback" },
+	{ "SLIMRX6", NULL, "Slim2 Playback" },
+
+	{ "Slim3 Capture", NULL, "SLIMTX7" },
+	{ "Slim3 Capture", NULL, "SLIMTX8" },
+
+	{ "SLIMRX7", NULL, "Slim3 Playback" },
+	{ "SLIMRX8", NULL, "Slim3 Playback" },
+
+	{ "AIF1 Playback", NULL, "SYSCLK" },
+	{ "AIF2 Playback", NULL, "SYSCLK" },
+	{ "Slim1 Playback", NULL, "SYSCLK" },
+	{ "Slim2 Playback", NULL, "SYSCLK" },
+	{ "Slim3 Playback", NULL, "SYSCLK" },
+
+	{ "AIF1 Capture", NULL, "SYSCLK" },
+	{ "AIF2 Capture", NULL, "SYSCLK" },
+	{ "Slim1 Capture", NULL, "SYSCLK" },
+	{ "Slim2 Capture", NULL, "SYSCLK" },
+	{ "Slim3 Capture", NULL, "SYSCLK" },
+
+	{ "IN1L PGA", NULL, "IN1L" },
+	{ "IN1R PGA", NULL, "IN1R" },
+
+	{ "IN2L PGA", NULL, "IN2L" },
+	{ "IN2R PGA", NULL, "IN2R" },
+
+	ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+	ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+
+	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+	ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+	ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+
+	ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+	ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+	ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+	ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+	ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+	ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+	ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+	ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+	ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+	ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+	ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+	ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+	ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+	ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+	ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+	ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+	ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+	ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+	ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+	ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
+	ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+	ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+	ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
+	ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
+
+	ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+	ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+
+	ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+	ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+	ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+	ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+	ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+	ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+	ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC2INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+	ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+	ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+	ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+	{ "AEC Loopback", "HPOUT1L", "OUT1L" },
+	{ "AEC Loopback", "HPOUT1R", "OUT1R" },
+	{ "HPOUT1L", NULL, "OUT1L" },
+	{ "HPOUT1R", NULL, "OUT1R" },
+
+	{ "AEC Loopback", "EPOUT", "OUT3L" },
+	{ "EPOUTN", NULL, "OUT3L" },
+	{ "EPOUTP", NULL, "OUT3L" },
+
+	{ "AEC Loopback", "SPKOUT", "OUT4L" },
+	{ "SPKOUTN", NULL, "OUT4L" },
+	{ "SPKOUTP", NULL, "OUT4L" },
+
+	{ "AEC Loopback", "SPKDAT1L", "OUT5L" },
+	{ "AEC Loopback", "SPKDAT1R", "OUT5R" },
+	{ "SPKDAT1L", NULL, "OUT5L" },
+	{ "SPKDAT1R", NULL, "OUT5R" },
+
+	{ "MICSUPP", NULL, "SYSCLK" },
+};
+
+static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm8997_priv *wm8997 = snd_soc_codec_get_drvdata(codec);
+
+	switch (fll_id) {
+	case WM8997_FLL1:
+		return arizona_set_fll(&wm8997->fll[0], source, Fref, Fout);
+	case WM8997_FLL2:
+		return arizona_set_fll(&wm8997->fll[1], source, Fref, Fout);
+	case WM8997_FLL1_REFCLK:
+		return arizona_set_fll_refclk(&wm8997->fll[0], source, Fref,
+					      Fout);
+	case WM8997_FLL2_REFCLK:
+		return arizona_set_fll_refclk(&wm8997->fll[1], source, Fref,
+					      Fout);
+	default:
+		return -EINVAL;
+	}
+}
+
+#define WM8997_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8997_dai[] = {
+	{
+		.name = "wm8997-aif1",
+		.id = 1,
+		.base = ARIZONA_AIF1_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 8,
+			 .rates = WM8997_RATES,
+			 .formats = WM8997_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "wm8997-aif2",
+		.id = 2,
+		.base = ARIZONA_AIF2_BCLK_CTRL,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8997_RATES,
+			 .formats = WM8997_FORMATS,
+		 },
+		.ops = &arizona_dai_ops,
+		.symmetric_rates = 1,
+	},
+	{
+		.name = "wm8997-slim1",
+		.id = 3,
+		.playback = {
+			.stream_name = "Slim1 Playback",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Slim1 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm8997-slim2",
+		.id = 4,
+		.playback = {
+			.stream_name = "Slim2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Slim2 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.ops = &arizona_simple_dai_ops,
+	},
+	{
+		.name = "wm8997-slim3",
+		.id = 5,
+		.playback = {
+			.stream_name = "Slim3 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.capture = {
+			.stream_name = "Slim3 Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8997_RATES,
+			.formats = WM8997_FORMATS,
+		},
+		.ops = &arizona_simple_dai_ops,
+	},
+};
+
+static int wm8997_codec_probe(struct snd_soc_codec *codec)
+{
+	struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	codec->control_data = priv->core.arizona->regmap;
+
+	ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+	if (ret != 0)
+		return ret;
+
+	arizona_init_spk(codec);
+
+	snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+
+	priv->core.arizona->dapm = &codec->dapm;
+
+	return 0;
+}
+
+static int wm8997_codec_remove(struct snd_soc_codec *codec)
+{
+	struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->core.arizona->dapm = NULL;
+
+	return 0;
+}
+
+#define WM8997_DIG_VU 0x0200
+
+static unsigned int wm8997_digital_vu[] = {
+	ARIZONA_DAC_DIGITAL_VOLUME_1L,
+	ARIZONA_DAC_DIGITAL_VOLUME_1R,
+	ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	ARIZONA_DAC_DIGITAL_VOLUME_4L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5L,
+	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
+	.probe = wm8997_codec_probe,
+	.remove = wm8997_codec_remove,
+
+	.idle_bias_off = true,
+
+	.set_sysclk = arizona_set_sysclk,
+	.set_pll = wm8997_set_fll,
+
+	.controls = wm8997_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8997_snd_controls),
+	.dapm_widgets = wm8997_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets),
+	.dapm_routes = wm8997_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes),
+};
+
+static int wm8997_probe(struct platform_device *pdev)
+{
+	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+	struct wm8997_priv *wm8997;
+	int i;
+
+	wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv),
+			      GFP_KERNEL);
+	if (wm8997 == NULL)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, wm8997);
+
+	wm8997->core.arizona = arizona;
+	wm8997->core.num_inputs = 4;
+
+	for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
+		wm8997->fll[i].vco_mult = 1;
+
+	arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+			 &wm8997->fll[0]);
+	arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+			 ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+			 &wm8997->fll[1]);
+
+	/* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+			   ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+	regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+			   ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+	for (i = 0; i < ARRAY_SIZE(wm8997_dai); i++)
+		arizona_init_dai(&wm8997->core, i);
+
+	/* Latch volume update bits */
+	for (i = 0; i < ARRAY_SIZE(wm8997_digital_vu); i++)
+		regmap_update_bits(arizona->regmap, wm8997_digital_vu[i],
+				   WM8997_DIG_VU, WM8997_DIG_VU);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_idle(&pdev->dev);
+
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
+				      wm8997_dai, ARRAY_SIZE(wm8997_dai));
+}
+
+static int wm8997_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	return 0;
+}
+
+static struct platform_driver wm8997_codec_driver = {
+	.driver = {
+		.name = "wm8997-codec",
+		.owner = THIS_MODULE,
+	},
+	.probe = wm8997_probe,
+	.remove = wm8997_remove,
+};
+
+module_platform_driver(wm8997_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8997 driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8997-codec");
diff --git a/sound/soc/codecs/wm8997.h b/sound/soc/codecs/wm8997.h
new file mode 100644
index 0000000..5e91c6a
--- /dev/null
+++ b/sound/soc/codecs/wm8997.h
@@ -0,0 +1,23 @@
+/*
+ * wm8997.h  --  WM8997 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8997_H
+#define _WM8997_H
+
+#include "arizona.h"
+
+#define WM8997_FLL1        1
+#define WM8997_FLL2        2
+#define WM8997_FLL1_REFCLK 3
+#define WM8997_FLL2_REFCLK 4
+
+#endif
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 05252ac..b38f350 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -225,15 +225,8 @@
 		     struct snd_ctl_elem_info *uinfo);
 };
 
-struct wm_coeff {
-	struct device *dev;
-	struct list_head ctl_list;
-	struct regmap *regmap;
-};
-
 struct wm_coeff_ctl {
 	const char *name;
-	struct snd_card *card;
 	struct wm_adsp_alg_region region;
 	struct wm_coeff_ctl_ops ops;
 	struct wm_adsp *adsp;
@@ -378,7 +371,6 @@
 static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
 				  const void *buf, size_t len)
 {
-	struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
 	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
 	struct wm_adsp_alg_region *region = &ctl->region;
 	const struct wm_adsp_region *mem;
@@ -401,7 +393,7 @@
 	if (!scratch)
 		return -ENOMEM;
 
-	ret = regmap_raw_write(wm_coeff->regmap, reg, scratch,
+	ret = regmap_raw_write(adsp->regmap, reg, scratch,
 			       ctl->len);
 	if (ret) {
 		adsp_err(adsp, "Failed to write %zu bytes to %x\n",
@@ -434,7 +426,6 @@
 static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
 				 void *buf, size_t len)
 {
-	struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
 	struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
 	struct wm_adsp_alg_region *region = &ctl->region;
 	const struct wm_adsp_region *mem;
@@ -457,7 +448,7 @@
 	if (!scratch)
 		return -ENOMEM;
 
-	ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len);
+	ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);
 	if (ret) {
 		adsp_err(adsp, "Failed to read %zu bytes from %x\n",
 			 ctl->len, reg);
@@ -481,37 +472,18 @@
 	return 0;
 }
 
-static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff,
-				 struct wm_coeff_ctl *ctl,
-				 const struct snd_kcontrol_new *kctl)
-{
-	int ret;
-	struct snd_kcontrol *kcontrol;
-
-	kcontrol = snd_ctl_new1(kctl, wm_coeff);
-	ret = snd_ctl_add(ctl->card, kcontrol);
-	if (ret < 0) {
-		dev_err(wm_coeff->dev, "Failed to add %s: %d\n",
-			kctl->name, ret);
-		return ret;
-	}
-	ctl->kcontrol = kcontrol;
-	return 0;
-}
-
 struct wmfw_ctl_work {
-	struct wm_coeff *wm_coeff;
+	struct wm_adsp *adsp;
 	struct wm_coeff_ctl *ctl;
 	struct work_struct work;
 };
 
-static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
-			struct wm_coeff_ctl *ctl)
+static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
 {
 	struct snd_kcontrol_new *kcontrol;
 	int ret;
 
-	if (!wm_coeff || !ctl || !ctl->name || !ctl->card)
+	if (!ctl || !ctl->name)
 		return -EINVAL;
 
 	kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
@@ -525,14 +497,17 @@
 	kcontrol->put = wm_coeff_put;
 	kcontrol->private_value = (unsigned long)ctl;
 
-	ret = wm_coeff_add_kcontrol(wm_coeff,
-				    ctl, kcontrol);
+	ret = snd_soc_add_card_controls(adsp->card,
+					kcontrol, 1);
 	if (ret < 0)
 		goto err_kcontrol;
 
 	kfree(kcontrol);
 
-	list_add(&ctl->list, &wm_coeff->ctl_list);
+	ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card,
+						  ctl->name);
+
+	list_add(&ctl->list, &adsp->ctl_list);
 	return 0;
 
 err_kcontrol:
@@ -753,13 +728,12 @@
 	return ret;
 }
 
-static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
+static int wm_coeff_init_control_caches(struct wm_adsp *adsp)
 {
 	struct wm_coeff_ctl *ctl;
 	int ret;
 
-	list_for_each_entry(ctl, &wm_coeff->ctl_list,
-			    list) {
+	list_for_each_entry(ctl, &adsp->ctl_list, list) {
 		if (!ctl->enabled || ctl->set)
 			continue;
 		ret = wm_coeff_read_control(ctl->kcontrol,
@@ -772,13 +746,12 @@
 	return 0;
 }
 
-static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff)
+static int wm_coeff_sync_controls(struct wm_adsp *adsp)
 {
 	struct wm_coeff_ctl *ctl;
 	int ret;
 
-	list_for_each_entry(ctl, &wm_coeff->ctl_list,
-			    list) {
+	list_for_each_entry(ctl, &adsp->ctl_list, list) {
 		if (!ctl->enabled)
 			continue;
 		if (ctl->set) {
@@ -799,15 +772,14 @@
 						      struct wmfw_ctl_work,
 						      work);
 
-	wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl);
+	wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
 	kfree(ctl_work);
 }
 
-static int wm_adsp_create_control(struct snd_soc_codec *codec,
+static int wm_adsp_create_control(struct wm_adsp *dsp,
 				  const struct wm_adsp_alg_region *region)
 
 {
-	struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
 	struct wm_coeff_ctl *ctl;
 	struct wmfw_ctl_work *ctl_work;
 	char *name;
@@ -842,7 +814,7 @@
 	snprintf(name, PAGE_SIZE, "DSP%d %s %x",
 		 dsp->num, region_name, region->alg);
 
-	list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
+	list_for_each_entry(ctl, &dsp->ctl_list,
 			    list) {
 		if (!strcmp(ctl->name, name)) {
 			if (!ctl->enabled)
@@ -866,7 +838,6 @@
 	ctl->set = 0;
 	ctl->ops.xget = wm_coeff_get;
 	ctl->ops.xput = wm_coeff_put;
-	ctl->card = codec->card->snd_card;
 	ctl->adsp = dsp;
 
 	ctl->len = region->len;
@@ -882,7 +853,7 @@
 		goto err_ctl_cache;
 	}
 
-	ctl_work->wm_coeff = dsp->wm_coeff;
+	ctl_work->adsp = dsp;
 	ctl_work->ctl = ctl;
 	INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
 	schedule_work(&ctl_work->work);
@@ -903,7 +874,7 @@
 	return ret;
 }
 
-static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+static int wm_adsp_setup_algs(struct wm_adsp *dsp)
 {
 	struct regmap *regmap = dsp->regmap;
 	struct wmfw_adsp1_id_hdr adsp1_id;
@@ -1091,7 +1062,7 @@
 			if (i + 1 < algs) {
 				region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
 				region->len -= be32_to_cpu(adsp1_alg[i].dm);
-				wm_adsp_create_control(codec, region);
+				wm_adsp_create_control(dsp, region);
 			} else {
 				adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
 					  be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1108,7 +1079,7 @@
 			if (i + 1 < algs) {
 				region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
 				region->len -= be32_to_cpu(adsp1_alg[i].zm);
-				wm_adsp_create_control(codec, region);
+				wm_adsp_create_control(dsp, region);
 			} else {
 				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
 					  be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1137,7 +1108,7 @@
 			if (i + 1 < algs) {
 				region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
 				region->len -= be32_to_cpu(adsp2_alg[i].xm);
-				wm_adsp_create_control(codec, region);
+				wm_adsp_create_control(dsp, region);
 			} else {
 				adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
 					  be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1154,7 +1125,7 @@
 			if (i + 1 < algs) {
 				region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
 				region->len -= be32_to_cpu(adsp2_alg[i].ym);
-				wm_adsp_create_control(codec, region);
+				wm_adsp_create_control(dsp, region);
 			} else {
 				adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
 					  be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1171,7 +1142,7 @@
 			if (i + 1 < algs) {
 				region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
 				region->len -= be32_to_cpu(adsp2_alg[i].zm);
-				wm_adsp_create_control(codec, region);
+				wm_adsp_create_control(dsp, region);
 			} else {
 				adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
 					  be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1391,6 +1362,8 @@
 	int ret;
 	int val;
 
+	dsp->card = codec->card;
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1425,7 +1398,7 @@
 		if (ret != 0)
 			goto err;
 
-		ret = wm_adsp_setup_algs(dsp, codec);
+		ret = wm_adsp_setup_algs(dsp);
 		if (ret != 0)
 			goto err;
 
@@ -1434,12 +1407,12 @@
 			goto err;
 
 		/* Initialize caches for enabled and unset controls */
-		ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+		ret = wm_coeff_init_control_caches(dsp);
 		if (ret != 0)
 			goto err;
 
 		/* Sync set controls */
-		ret = wm_coeff_sync_controls(dsp->wm_coeff);
+		ret = wm_coeff_sync_controls(dsp);
 		if (ret != 0)
 			goto err;
 
@@ -1460,10 +1433,8 @@
 		regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
 				   ADSP1_SYS_ENA, 0);
 
-		list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
-				    list) {
+		list_for_each_entry(ctl, &dsp->ctl_list, list)
 			ctl->enabled = 0;
-		}
 		break;
 
 	default:
@@ -1520,6 +1491,8 @@
 	unsigned int val;
 	int ret;
 
+	dsp->card = codec->card;
+
 	switch (event) {
 	case SND_SOC_DAPM_POST_PMU:
 		/*
@@ -1582,7 +1555,7 @@
 		if (ret != 0)
 			goto err;
 
-		ret = wm_adsp_setup_algs(dsp, codec);
+		ret = wm_adsp_setup_algs(dsp);
 		if (ret != 0)
 			goto err;
 
@@ -1591,12 +1564,12 @@
 			goto err;
 
 		/* Initialize caches for enabled and unset controls */
-		ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+		ret = wm_coeff_init_control_caches(dsp);
 		if (ret != 0)
 			goto err;
 
 		/* Sync set controls */
-		ret = wm_coeff_sync_controls(dsp->wm_coeff);
+		ret = wm_coeff_sync_controls(dsp);
 		if (ret != 0)
 			goto err;
 
@@ -1637,10 +1610,8 @@
 					ret);
 		}
 
-		list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
-				    list) {
+		list_for_each_entry(ctl, &dsp->ctl_list, list)
 			ctl->enabled = 0;
-		}
 
 		while (!list_empty(&dsp->alg_regions)) {
 			alg_region = list_first_entry(&dsp->alg_regions,
@@ -1679,49 +1650,38 @@
 	}
 
 	INIT_LIST_HEAD(&adsp->alg_regions);
-
-	adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff),
-				 GFP_KERNEL);
-	if (!adsp->wm_coeff)
-		return -ENOMEM;
-	adsp->wm_coeff->regmap = adsp->regmap;
-	adsp->wm_coeff->dev = adsp->dev;
-	INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list);
+	INIT_LIST_HEAD(&adsp->ctl_list);
 
 	if (dvfs) {
 		adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
 		if (IS_ERR(adsp->dvfs)) {
 			ret = PTR_ERR(adsp->dvfs);
 			dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
-			goto out_coeff;
+			return ret;
 		}
 
 		ret = regulator_enable(adsp->dvfs);
 		if (ret != 0) {
 			dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
 				ret);
-			goto out_coeff;
+			return ret;
 		}
 
 		ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
 		if (ret != 0) {
 			dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
 				ret);
-			goto out_coeff;
+			return ret;
 		}
 
 		ret = regulator_disable(adsp->dvfs);
 		if (ret != 0) {
 			dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
 				ret);
-			goto out_coeff;
+			return ret;
 		}
 	}
 
 	return 0;
-
-out_coeff:
-	kfree(adsp->wm_coeff);
-	return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 9f922c8..d018dea 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -39,6 +39,7 @@
 	int type;
 	struct device *dev;
 	struct regmap *regmap;
+	struct snd_soc_card *card;
 
 	int base;
 	int sysclk_reg;
@@ -57,7 +58,7 @@
 
 	struct regulator *dvfs;
 
-	struct wm_coeff *wm_coeff;
+	struct list_head ctl_list;
 };
 
 #define WM_ADSP1(wname, num) \
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 2d9e099..8b50e59 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -699,9 +699,7 @@
 static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -721,9 +719,7 @@
 static int class_w_put_double(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	int ret;
 
 	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index 70eb37a..25c31f1 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -421,13 +421,11 @@
 					 dw_i2s_dai, 1);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "not able to register dai\n");
-		goto err_set_drvdata;
+		goto err_clk_disable;
 	}
 
 	return 0;
 
-err_set_drvdata:
-	dev_set_drvdata(&pdev->dev, NULL);
 err_clk_disable:
 	clk_disable(dev->clk);
 err_clk_put:
@@ -440,7 +438,6 @@
 	struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
 	snd_soc_unregister_component(&pdev->dev);
-	dev_set_drvdata(&pdev->dev, NULL);
 
 	clk_put(dev->clk);
 
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index aa43854..704e246 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,6 +1,9 @@
 config SND_SOC_FSL_SSI
 	tristate
 
+config SND_SOC_FSL_SPDIF
+	tristate
+
 config SND_SOC_FSL_UTILS
 	tristate
 
@@ -98,7 +101,7 @@
 
 menuconfig SND_IMX_SOC
 	tristate "SoC Audio for Freescale i.MX CPUs"
-	depends on ARCH_MXC
+	depends on ARCH_MXC || COMPILE_TEST
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the i.MX CPUs.
@@ -109,11 +112,11 @@
 	tristate
 
 config SND_SOC_IMX_PCM_FIQ
-	bool
+	tristate
 	select FIQ
 
 config SND_SOC_IMX_PCM_DMA
-	bool
+	tristate
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_SOC_IMX_AUDMUX
@@ -175,7 +178,6 @@
 	select SND_SOC_IMX_PCM_DMA
 	select SND_SOC_IMX_AUDMUX
 	select SND_SOC_FSL_SSI
-	select SND_SOC_FSL_UTILS
 	help
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  a wm8962 codec.
@@ -187,14 +189,23 @@
 	select SND_SOC_IMX_PCM_DMA
 	select SND_SOC_IMX_AUDMUX
 	select SND_SOC_FSL_SSI
-	select SND_SOC_FSL_UTILS
 	help
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  a sgtl5000 codec.
 
+config SND_SOC_IMX_SPDIF
+	tristate "SoC Audio support for i.MX boards with S/PDIF"
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_FSL_SPDIF
+	select SND_SOC_SPDIF
+	help
+	  SoC Audio support for i.MX boards with S/PDIF
+	  Say Y if you want to add support for SoC audio on an i.MX board with
+	  a S/DPDIF.
+
 config SND_SOC_IMX_MC13783
 	tristate "SoC Audio support for I.MX boards with mc13783"
-	depends on MFD_MC13783
+	depends on MFD_MC13783 && ARM
 	select SND_SOC_IMX_SSI
 	select SND_SOC_IMX_AUDMUX
 	select SND_SOC_MC13783
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index d4b4aa8b..8db705b 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -12,9 +12,11 @@
 
 # Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-spdif-objs := fsl_spdif.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
@@ -43,6 +45,7 @@
 snd-soc-wm1133-ev1-objs := wm1133-ev1.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-wm8962-objs := imx-wm8962.o
+snd-soc-imx-spdif-objs := imx-spdif.o
 snd-soc-imx-mc13783-objs := imx-mc13783.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
@@ -51,4 +54,5 @@
 obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
+obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
 obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
new file mode 100644
index 0000000..3920c3e
--- /dev/null
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -0,0 +1,1225 @@
+/*
+ * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Based on stmp3xxx_spdif_dai.c
+ * Vladimir Barinov <vbarinov@embeddedalley.com>
+ * Copyright 2008 SigmaTel, Inc
+ * Copyright 2008 Embedded Alley Solutions, 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/module.h>
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+#include <linux/bitrev.h>
+#include <linux/regmap.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include <sound/asoundef.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "fsl_spdif.h"
+#include "imx-pcm.h"
+
+#define FSL_SPDIF_TXFIFO_WML	0x8
+#define FSL_SPDIF_RXFIFO_WML	0x8
+
+#define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC)
+#define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL | INT_URX_OV|\
+		INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\
+		INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED)
+
+/* Index list for the values that has if (DPLL Locked) condition */
+static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
+#define SRPC_NODPLL_START1	0x5
+#define SRPC_NODPLL_START2	0xc
+
+#define DEFAULT_RXCLK_SRC	1
+
+/*
+ * SPDIF control structure
+ * Defines channel status, subcode and Q sub
+ */
+struct spdif_mixer_control {
+	/* spinlock to access control data */
+	spinlock_t ctl_lock;
+
+	/* IEC958 channel tx status bit */
+	unsigned char ch_status[4];
+
+	/* User bits */
+	unsigned char subcode[2 * SPDIF_UBITS_SIZE];
+
+	/* Q subcode part of user bits */
+	unsigned char qsub[2 * SPDIF_QSUB_SIZE];
+
+	/* Buffer offset for U/Q */
+	u32 upos;
+	u32 qpos;
+
+	/* Ready buffer index of the two buffers */
+	u32 ready_buf;
+};
+
+struct fsl_spdif_priv {
+	struct spdif_mixer_control fsl_spdif_control;
+	struct snd_soc_dai_driver cpu_dai_drv;
+	struct platform_device *pdev;
+	struct regmap *regmap;
+	bool dpll_locked;
+	u8 txclk_div[SPDIF_TXRATE_MAX];
+	u8 txclk_src[SPDIF_TXRATE_MAX];
+	u8 rxclk_src;
+	struct clk *txclk[SPDIF_TXRATE_MAX];
+	struct clk *rxclk;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+
+	/* The name space will be allocated dynamically */
+	char name[0];
+};
+
+
+/* DPLL locked and lock loss interrupt handler */
+static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 locked;
+
+	regmap_read(regmap, REG_SPDIF_SRPC, &locked);
+	locked &= SRPC_DPLL_LOCKED;
+
+	dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
+			locked ? "locked" : "loss lock");
+
+	spdif_priv->dpll_locked = locked ? true : false;
+}
+
+/* Receiver found illegal symbol interrupt handler */
+static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+
+	dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n");
+
+	if (!spdif_priv->dpll_locked) {
+		/* DPLL unlocked seems no audio stream */
+		regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0);
+	}
+}
+
+/* U/Q Channel receive register full */
+static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 *pos, size, val, reg;
+
+	switch (name) {
+	case 'U':
+		pos = &ctrl->upos;
+		size = SPDIF_UBITS_SIZE;
+		reg = REG_SPDIF_SRU;
+		break;
+	case 'Q':
+		pos = &ctrl->qpos;
+		size = SPDIF_QSUB_SIZE;
+		reg = REG_SPDIF_SRQ;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported channel name\n");
+		return;
+	}
+
+	dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name);
+
+	if (*pos >= size * 2) {
+		*pos = 0;
+	} else if (unlikely((*pos % size) + 3 > size)) {
+		dev_err(&pdev->dev, "User bit receivce buffer overflow\n");
+		return;
+	}
+
+	regmap_read(regmap, reg, &val);
+	ctrl->subcode[*pos++] = val >> 16;
+	ctrl->subcode[*pos++] = val >> 8;
+	ctrl->subcode[*pos++] = val;
+}
+
+/* U/Q Channel sync found */
+static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct platform_device *pdev = spdif_priv->pdev;
+
+	dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n");
+
+	/* U/Q buffer reset */
+	if (ctrl->qpos == 0)
+		return;
+
+	/* Set ready to this buffer */
+	ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1;
+}
+
+/* U/Q Channel framing error */
+static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 val;
+
+	dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n");
+
+	/* Read U/Q data to clear the irq and do buffer reset */
+	regmap_read(regmap, REG_SPDIF_SRU, &val);
+	regmap_read(regmap, REG_SPDIF_SRQ, &val);
+
+	/* Drop this U/Q buffer */
+	ctrl->ready_buf = 0;
+	ctrl->upos = 0;
+	ctrl->qpos = 0;
+}
+
+/* Get spdif interrupt status and clear the interrupt */
+static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 val, val2;
+
+	regmap_read(regmap, REG_SPDIF_SIS, &val);
+	regmap_read(regmap, REG_SPDIF_SIE, &val2);
+
+	regmap_write(regmap, REG_SPDIF_SIC, val & val2);
+
+	return val;
+}
+
+static irqreturn_t spdif_isr(int irq, void *devid)
+{
+	struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 sis;
+
+	sis = spdif_intr_status_clear(spdif_priv);
+
+	if (sis & INT_DPLL_LOCKED)
+		spdif_irq_dpll_lock(spdif_priv);
+
+	if (sis & INT_TXFIFO_UNOV)
+		dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n");
+
+	if (sis & INT_TXFIFO_RESYNC)
+		dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n");
+
+	if (sis & INT_CNEW)
+		dev_dbg(&pdev->dev, "isr: cstatus new\n");
+
+	if (sis & INT_VAL_NOGOOD)
+		dev_dbg(&pdev->dev, "isr: validity flag no good\n");
+
+	if (sis & INT_SYM_ERR)
+		spdif_irq_sym_error(spdif_priv);
+
+	if (sis & INT_BIT_ERR)
+		dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n");
+
+	if (sis & INT_URX_FUL)
+		spdif_irq_uqrx_full(spdif_priv, 'U');
+
+	if (sis & INT_URX_OV)
+		dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n");
+
+	if (sis & INT_QRX_FUL)
+		spdif_irq_uqrx_full(spdif_priv, 'Q');
+
+	if (sis & INT_QRX_OV)
+		dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n");
+
+	if (sis & INT_UQ_SYNC)
+		spdif_irq_uq_sync(spdif_priv);
+
+	if (sis & INT_UQ_ERR)
+		spdif_irq_uq_err(spdif_priv);
+
+	if (sis & INT_RXFIFO_UNOV)
+		dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n");
+
+	if (sis & INT_RXFIFO_RESYNC)
+		dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n");
+
+	if (sis & INT_LOSS_LOCK)
+		spdif_irq_dpll_lock(spdif_priv);
+
+	/* FIXME: Write Tx FIFO to clear TxEm */
+	if (sis & INT_TX_EM)
+		dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n");
+
+	/* FIXME: Read Rx FIFO to clear RxFIFOFul */
+	if (sis & INT_RXFIFO_FUL)
+		dev_dbg(&pdev->dev, "isr: Rx FIFO full\n");
+
+	return IRQ_HANDLED;
+}
+
+static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 val, cycle = 1000;
+
+	regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
+
+	/*
+	 * RESET bit would be cleared after finishing its reset procedure,
+	 * which typically lasts 8 cycles. 1000 cycles will keep it safe.
+	 */
+	do {
+		regmap_read(regmap, REG_SPDIF_SCR, &val);
+	} while ((val & SCR_SOFT_RESET) && cycle--);
+
+	if (cycle)
+		return 0;
+	else
+		return -EBUSY;
+}
+
+static void spdif_set_cstatus(struct spdif_mixer_control *ctrl,
+				u8 mask, u8 cstatus)
+{
+	ctrl->ch_status[3] &= ~mask;
+	ctrl->ch_status[3] |= cstatus & mask;
+}
+
+static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 ch_status;
+
+	ch_status = (bitrev8(ctrl->ch_status[0]) << 16) |
+		(bitrev8(ctrl->ch_status[1]) << 8) |
+		bitrev8(ctrl->ch_status[2]);
+	regmap_write(regmap, REG_SPDIF_STCSCH, ch_status);
+
+	dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status);
+
+	ch_status = bitrev8(ctrl->ch_status[3]) << 16;
+	regmap_write(regmap, REG_SPDIF_STCSCL, ch_status);
+
+	dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status);
+}
+
+/* Set SPDIF PhaseConfig register for rx clock */
+static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
+				enum spdif_gainsel gainsel, int dpll_locked)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	u8 clksrc = spdif_priv->rxclk_src;
+
+	if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX)
+		return -EINVAL;
+
+	regmap_update_bits(regmap, REG_SPDIF_SRPC,
+			SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
+			SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));
+
+	return 0;
+}
+
+static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
+				int sample_rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	unsigned long csfs = 0;
+	u32 stc, mask, rate;
+	u8 clk, div;
+	int ret;
+
+	switch (sample_rate) {
+	case 32000:
+		rate = SPDIF_TXRATE_32000;
+		csfs = IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		rate = SPDIF_TXRATE_44100;
+		csfs = IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		rate = SPDIF_TXRATE_48000;
+		csfs = IEC958_AES3_CON_FS_48000;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate);
+		return -EINVAL;
+	}
+
+	clk = spdif_priv->txclk_src[rate];
+	if (clk >= STC_TXCLK_SRC_MAX) {
+		dev_err(&pdev->dev, "tx clock source is out of range\n");
+		return -EINVAL;
+	}
+
+	div = spdif_priv->txclk_div[rate];
+	if (div == 0) {
+		dev_err(&pdev->dev, "the divisor can't be zero\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * The S/PDIF block needs a clock of 64 * fs * div.  The S/PDIF block
+	 * will divide by (div).  So request 64 * fs * (div+1) which will
+	 * get rounded.
+	 */
+	ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1));
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set tx clock rate\n");
+		return ret;
+	}
+
+	dev_dbg(&pdev->dev, "expected clock rate = %d\n",
+			(64 * sample_rate * div));
+	dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
+			clk_get_rate(spdif_priv->txclk[rate]));
+
+	/* set fs field in consumer channel status */
+	spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);
+
+	/* select clock source and divisor */
+	stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div);
+	mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK;
+	regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
+
+	dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
+
+	return 0;
+}
+
+static int fsl_spdif_startup(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct platform_device *pdev = spdif_priv->pdev;
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 scr, mask, i;
+	int ret;
+
+	/* Reset module and interrupts only for first initialization */
+	if (!cpu_dai->active) {
+		ret = spdif_softreset(spdif_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to soft reset\n");
+			return ret;
+		}
+
+		/* Disable all the interrupts */
+		regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL |
+			SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP |
+			SCR_TXFIFO_FSEL_IF8;
+		mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
+			SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
+			SCR_TXFIFO_FSEL_MASK;
+		for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+			clk_prepare_enable(spdif_priv->txclk[i]);
+	} else {
+		scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
+		mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
+			SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
+		clk_prepare_enable(spdif_priv->rxclk);
+	}
+	regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
+
+	/* Power up SPDIF module */
+	regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
+
+	return 0;
+}
+
+static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 scr, mask, i;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		scr = 0;
+		mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
+			SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
+			SCR_TXFIFO_FSEL_MASK;
+		for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+			clk_disable_unprepare(spdif_priv->txclk[i]);
+	} else {
+		scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
+		mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
+			SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
+		clk_disable_unprepare(spdif_priv->rxclk);
+	}
+	regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
+
+	/* Power down SPDIF module only if tx&rx are both inactive */
+	if (!cpu_dai->active) {
+		spdif_intr_status_clear(spdif_priv);
+		regmap_update_bits(regmap, REG_SPDIF_SCR,
+				SCR_LOW_POWER, SCR_LOW_POWER);
+	}
+}
+
+static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 sample_rate = params_rate(params);
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret  = spdif_set_sample_rate(substream, sample_rate);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
+					__func__, sample_rate);
+			return ret;
+		}
+		spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK,
+				IEC958_AES3_CON_CLOCK_1000PPM);
+		spdif_write_channel_status(spdif_priv);
+	} else {
+		/* Setup rx clock source */
+		ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1);
+	}
+
+	return ret;
+}
+
+static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct regmap *regmap = spdif_priv->regmap;
+	int is_playack = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	u32 intr = is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE;
+	u32 dmaen = is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr);
+		regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0);
+		regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+	.startup = fsl_spdif_startup,
+	.hw_params = fsl_spdif_hw_params,
+	.trigger = fsl_spdif_trigger,
+	.shutdown = fsl_spdif_shutdown,
+};
+
+
+/*
+ * FSL SPDIF IEC958 controller(mixer) functions
+ *
+ *	Channel status get/put control
+ *	User bit value get/put control
+ *	Valid bit value get control
+ *	DPLL lock status get control
+ *	User bit sync mode selection control
+ */
+
+static int fsl_spdif_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *uvalue)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+
+	uvalue->value.iec958.status[0] = ctrl->ch_status[0];
+	uvalue->value.iec958.status[1] = ctrl->ch_status[1];
+	uvalue->value.iec958.status[2] = ctrl->ch_status[2];
+	uvalue->value.iec958.status[3] = ctrl->ch_status[3];
+
+	return 0;
+}
+
+static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *uvalue)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+
+	ctrl->ch_status[0] = uvalue->value.iec958.status[0];
+	ctrl->ch_status[1] = uvalue->value.iec958.status[1];
+	ctrl->ch_status[2] = uvalue->value.iec958.status[2];
+	ctrl->ch_status[3] = uvalue->value.iec958.status[3];
+
+	spdif_write_channel_status(spdif_priv);
+
+	return 0;
+}
+
+/* Get channel status from SPDIF_RX_CCHAN register */
+static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 cstatus, val;
+
+	regmap_read(regmap, REG_SPDIF_SIS, &val);
+	if (!(val & INT_CNEW)) {
+		return -EAGAIN;
+	}
+
+	regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus);
+	ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF;
+	ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF;
+	ucontrol->value.iec958.status[2] = cstatus & 0xFF;
+
+	regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus);
+	ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF;
+	ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF;
+	ucontrol->value.iec958.status[5] = cstatus & 0xFF;
+
+	/* Clear intr */
+	regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW);
+
+	return 0;
+}
+
+/*
+ * Get User bits (subcode) from chip value which readed out
+ * in UChannel register.
+ */
+static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&ctrl->ctl_lock, flags);
+	if (ctrl->ready_buf) {
+		int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
+		memcpy(&ucontrol->value.iec958.subcode[0],
+				&ctrl->subcode[idx], SPDIF_UBITS_SIZE);
+	} else {
+		ret = -EAGAIN;
+	}
+	spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
+
+	return ret;
+}
+
+/* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */
+static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = SPDIF_QSUB_SIZE;
+
+	return 0;
+}
+
+/* Get Q subcode from chip value which readed out in QChannel register */
+static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&ctrl->ctl_lock, flags);
+	if (ctrl->ready_buf) {
+		int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
+		memcpy(&ucontrol->value.bytes.data[0],
+				&ctrl->qsub[idx], SPDIF_QSUB_SIZE);
+	} else {
+		ret = -EAGAIN;
+	}
+	spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
+
+	return ret;
+}
+
+/* Valid bit infomation */
+static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+/* Get valid good bit from interrupt status register */
+static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 val;
+
+	val = regmap_read(regmap, REG_SPDIF_SIS, &val);
+	ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0;
+	regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD);
+
+	return 0;
+}
+
+/* DPLL lock infomation */
+static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 16000;
+	uinfo->value.integer.max = 96000;
+
+	return 0;
+}
+
+static u32 gainsel_multi[GAINSEL_MULTI_MAX] = {
+	24, 16, 12, 8, 6, 4, 3,
+};
+
+/* Get RX data clock rate given the SPDIF bus_clk */
+static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
+				enum spdif_gainsel gainsel)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u64 tmpval64, busclk_freq = 0;
+	u32 freqmeas, phaseconf;
+	u8 clksrc;
+
+	regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas);
+	regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf);
+
+	clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
+	if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
+		/* Get bus clock from system */
+		busclk_freq = clk_get_rate(spdif_priv->rxclk);
+	}
+
+	/* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
+	tmpval64 = (u64) busclk_freq * freqmeas;
+	do_div(tmpval64, gainsel_multi[gainsel] * 1024);
+	do_div(tmpval64, 128 * 1024);
+
+	dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas);
+	dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq);
+	dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64);
+
+	return (int)tmpval64;
+}
+
+/*
+ * Get DPLL lock or not info from stable interrupt status register.
+ * User application must use this control to get locked,
+ * then can do next PCM operation
+ */
+static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);
+
+	if (spdif_priv->dpll_locked)
+		ucontrol->value.integer.value[0] = rate;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+/* User bit sync mode info */
+static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+/*
+ * User bit sync mode:
+ * 1 CD User channel subcode
+ * 0 Non-CD data
+ */
+static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 val;
+
+	regmap_read(regmap, REG_SPDIF_SRCD, &val);
+	ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0;
+
+	return 0;
+}
+
+/*
+ * User bit sync mode:
+ * 1 CD User channel subcode
+ * 0 Non-CD data
+ */
+static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET;
+
+	regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val);
+
+	return 0;
+}
+
+/* FSL SPDIF IEC958 controller defines */
+static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
+	/* Status cchanel controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_WRITE |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_info,
+		.get = fsl_spdif_pb_get,
+		.put = fsl_spdif_pb_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_info,
+		.get = fsl_spdif_capture_get,
+	},
+	/* User bits controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 Subcode Capture Default",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_info,
+		.get = fsl_spdif_subcode_get,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 Q-subcode Capture Default",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_qinfo,
+		.get = fsl_spdif_qget,
+	},
+	/* Valid bit error controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 V-Bit Errors",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_vbit_info,
+		.get = fsl_spdif_vbit_get,
+	},
+	/* DPLL lock info get controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "RX Sample Rate",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_rxrate_info,
+		.get = fsl_spdif_rxrate_get,
+	},
+	/* User bit sync mode set/get controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 USyncMode CDText",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_WRITE |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_usync_info,
+		.get = fsl_spdif_usync_get,
+		.put = fsl_spdif_usync_put,
+	},
+};
+
+static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
+
+	dai->playback_dma_data = &spdif_private->dma_params_tx;
+	dai->capture_dma_data = &spdif_private->dma_params_rx;
+
+	snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
+
+	return 0;
+}
+
+static struct snd_soc_dai_driver fsl_spdif_dai = {
+	.probe = &fsl_spdif_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = FSL_SPDIF_RATES_PLAYBACK,
+		.formats = FSL_SPDIF_FORMATS_PLAYBACK,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = FSL_SPDIF_RATES_CAPTURE,
+		.formats = FSL_SPDIF_FORMATS_CAPTURE,
+	},
+	.ops = &fsl_spdif_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_spdif_component = {
+	.name		= "fsl-spdif",
+};
+
+/* FSL SPDIF REGMAP */
+
+static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_SPDIF_SCR:
+	case REG_SPDIF_SRCD:
+	case REG_SPDIF_SRPC:
+	case REG_SPDIF_SIE:
+	case REG_SPDIF_SIS:
+	case REG_SPDIF_SRL:
+	case REG_SPDIF_SRR:
+	case REG_SPDIF_SRCSH:
+	case REG_SPDIF_SRCSL:
+	case REG_SPDIF_SRU:
+	case REG_SPDIF_SRQ:
+	case REG_SPDIF_STCSCH:
+	case REG_SPDIF_STCSCL:
+	case REG_SPDIF_SRFM:
+	case REG_SPDIF_STC:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_SPDIF_SCR:
+	case REG_SPDIF_SRCD:
+	case REG_SPDIF_SRPC:
+	case REG_SPDIF_SIE:
+	case REG_SPDIF_SIC:
+	case REG_SPDIF_STL:
+	case REG_SPDIF_STR:
+	case REG_SPDIF_STCSCH:
+	case REG_SPDIF_STCSCL:
+	case REG_SPDIF_STC:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config fsl_spdif_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.max_register = REG_SPDIF_STC,
+	.readable_reg = fsl_spdif_readable_reg,
+	.writeable_reg = fsl_spdif_writeable_reg,
+};
+
+static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
+				struct clk *clk, u64 savesub,
+				enum spdif_txrate index)
+{
+	const u32 rate[] = { 32000, 44100, 48000 };
+	u64 rate_ideal, rate_actual, sub;
+	u32 div, arate;
+
+	for (div = 1; div <= 128; div++) {
+		rate_ideal = rate[index] * (div + 1) * 64;
+		rate_actual = clk_round_rate(clk, rate_ideal);
+
+		arate = rate_actual / 64;
+		arate /= div;
+
+		if (arate == rate[index]) {
+			/* We are lucky */
+			savesub = 0;
+			spdif_priv->txclk_div[index] = div;
+			break;
+		} else if (arate / rate[index] == 1) {
+			/* A little bigger than expect */
+			sub = (arate - rate[index]) * 100000;
+			do_div(sub, rate[index]);
+			if (sub < savesub) {
+				savesub = sub;
+				spdif_priv->txclk_div[index] = div;
+			}
+		} else if (rate[index] / arate == 1) {
+			/* A little smaller than expect */
+			sub = (rate[index] - arate) * 100000;
+			do_div(sub, rate[index]);
+			if (sub < savesub) {
+				savesub = sub;
+				spdif_priv->txclk_div[index] = div;
+			}
+		}
+	}
+
+	return savesub;
+}
+
+static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
+				enum spdif_txrate index)
+{
+	const u32 rate[] = { 32000, 44100, 48000 };
+	struct platform_device *pdev = spdif_priv->pdev;
+	struct device *dev = &pdev->dev;
+	u64 savesub = 100000, ret;
+	struct clk *clk;
+	char tmp[16];
+	int i;
+
+	for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
+		sprintf(tmp, "rxtx%d", i);
+		clk = devm_clk_get(&pdev->dev, tmp);
+		if (IS_ERR(clk)) {
+			dev_err(dev, "no rxtx%d clock in devicetree\n", i);
+			return PTR_ERR(clk);
+		}
+		if (!clk_get_rate(clk))
+			continue;
+
+		ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
+		if (savesub == ret)
+			continue;
+
+		savesub = ret;
+		spdif_priv->txclk[index] = clk;
+		spdif_priv->txclk_src[index] = i;
+
+		/* To quick catch a divisor, we allow a 0.1% deviation */
+		if (savesub < 100)
+			break;
+	}
+
+	dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
+			spdif_priv->txclk_src[index], rate[index]);
+	dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate\n",
+			spdif_priv->txclk_div[index], rate[index]);
+
+	return 0;
+}
+
+static int fsl_spdif_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_spdif_priv *spdif_priv;
+	struct spdif_mixer_control *ctrl;
+	struct resource *res;
+	void __iomem *regs;
+	int irq, ret, i;
+
+	if (!np)
+		return -ENODEV;
+
+	spdif_priv = devm_kzalloc(&pdev->dev,
+			sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1,
+			GFP_KERNEL);
+	if (!spdif_priv)
+		return -ENOMEM;
+
+	strcpy(spdif_priv->name, np->name);
+
+	spdif_priv->pdev = pdev;
+
+	/* Initialize this copy of the CPU DAI driver structure */
+	memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
+	spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+
+	/* Get the addresses and IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (IS_ERR(res)) {
+		dev_err(&pdev->dev, "could not determine device resources\n");
+		return PTR_ERR(res);
+	}
+
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+			"core", regs, &fsl_spdif_regmap_config);
+	if (IS_ERR(spdif_priv->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(spdif_priv->regmap);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+			spdif_priv->name, spdif_priv);
+	if (ret) {
+		dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+		return ret;
+	}
+
+	/* Select clock source for rx/tx clock */
+	spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
+	if (IS_ERR(spdif_priv->rxclk)) {
+		dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n");
+		return PTR_ERR(spdif_priv->rxclk);
+	}
+	spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
+
+	for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
+		ret = fsl_spdif_probe_txclk(spdif_priv, i);
+		if (ret)
+			return ret;
+	}
+
+	/* Initial spinlock for control data */
+	ctrl = &spdif_priv->fsl_spdif_control;
+	spin_lock_init(&ctrl->ctl_lock);
+
+	/* Init tx channel status default value */
+	ctrl->ch_status[0] =
+		IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015;
+	ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID;
+	ctrl->ch_status[2] = 0x00;
+	ctrl->ch_status[3] =
+		IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM;
+
+	spdif_priv->dpll_locked = false;
+
+	spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
+	spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+	spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
+	spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
+
+	/* Register with ASoC */
+	dev_set_drvdata(&pdev->dev, spdif_priv);
+
+	ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
+					 &spdif_priv->cpu_dai_drv, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+		return ret;
+	}
+
+	ret = imx_pcm_dma_init(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
+		goto error_component;
+	}
+
+	return ret;
+
+error_component:
+	snd_soc_unregister_component(&pdev->dev);
+
+	return ret;
+}
+
+static int fsl_spdif_remove(struct platform_device *pdev)
+{
+	imx_pcm_dma_exit(pdev);
+	snd_soc_unregister_component(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_spdif_dt_ids[] = {
+	{ .compatible = "fsl,imx35-spdif", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
+
+static struct platform_driver fsl_spdif_driver = {
+	.driver = {
+		.name = "fsl-spdif-dai",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_spdif_dt_ids,
+	},
+	.probe = fsl_spdif_probe,
+	.remove = fsl_spdif_remove,
+};
+
+module_platform_driver(fsl_spdif_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl-spdif-dai");
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
new file mode 100644
index 0000000..b126679
--- /dev/null
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -0,0 +1,191 @@
+/*
+ * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <b42378@freescale.com>
+ *
+ * Based on fsl_ssi.h
+ * Author: Timur Tabi <timur@freescale.com>
+ * Copyright 2007-2008 Freescale Semiconductor, 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.
+ */
+
+#ifndef _FSL_SPDIF_DAI_H
+#define _FSL_SPDIF_DAI_H
+
+/* S/PDIF Register Map */
+#define REG_SPDIF_SCR 			0x0	/* SPDIF Configuration Register */
+#define REG_SPDIF_SRCD		 	0x4	/* CDText Control Register */
+#define REG_SPDIF_SRPC			0x8	/* PhaseConfig Register */
+#define REG_SPDIF_SIE			0xc	/* InterruptEn Register */
+#define REG_SPDIF_SIS			0x10	/* InterruptStat Register */
+#define REG_SPDIF_SIC			0x10	/* InterruptClear Register */
+#define REG_SPDIF_SRL			0x14	/* SPDIFRxLeft Register */
+#define REG_SPDIF_SRR			0x18	/* SPDIFRxRight Register */
+#define REG_SPDIF_SRCSH			0x1c	/* SPDIFRxCChannel_h Register */
+#define REG_SPDIF_SRCSL			0x20	/* SPDIFRxCChannel_l Register */
+#define REG_SPDIF_SRU			0x24	/* UchannelRx Register */
+#define REG_SPDIF_SRQ			0x28	/* QchannelRx Register */
+#define REG_SPDIF_STL			0x2C	/* SPDIFTxLeft Register */
+#define REG_SPDIF_STR			0x30	/* SPDIFTxRight Register */
+#define REG_SPDIF_STCSCH		0x34	/* SPDIFTxCChannelCons_h Register */
+#define REG_SPDIF_STCSCL		0x38	/* SPDIFTxCChannelCons_l Register */
+#define REG_SPDIF_SRFM			0x44	/* FreqMeas Register */
+#define REG_SPDIF_STC			0x50	/* SPDIFTxClk Register */
+
+
+/* SPDIF Configuration register */
+#define SCR_RXFIFO_CTL_OFFSET		23
+#define SCR_RXFIFO_CTL_MASK		(1 << SCR_RXFIFO_CTL_OFFSET)
+#define SCR_RXFIFO_CTL_ZERO		(1 << SCR_RXFIFO_CTL_OFFSET)
+#define SCR_RXFIFO_OFF_OFFSET		22
+#define SCR_RXFIFO_OFF_MASK		(1 << SCR_RXFIFO_OFF_OFFSET)
+#define SCR_RXFIFO_OFF			(1 << SCR_RXFIFO_OFF_OFFSET)
+#define SCR_RXFIFO_RST_OFFSET		21
+#define SCR_RXFIFO_RST_MASK		(1 << SCR_RXFIFO_RST_OFFSET)
+#define SCR_RXFIFO_RST			(1 << SCR_RXFIFO_RST_OFFSET)
+#define SCR_RXFIFO_FSEL_OFFSET		19
+#define SCR_RXFIFO_FSEL_MASK		(0x3 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF0		(0x0 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF4		(0x1 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF8		(0x2 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF12		(0x3 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_AUTOSYNC_OFFSET	18
+#define SCR_RXFIFO_AUTOSYNC_MASK	(1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
+#define SCR_RXFIFO_AUTOSYNC		(1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_AUTOSYNC_OFFSET	17
+#define SCR_TXFIFO_AUTOSYNC_MASK	(1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_AUTOSYNC		(1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_FSEL_OFFSET		15
+#define SCR_TXFIFO_FSEL_MASK		(0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF0		(0x0 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF4		(0x1 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF8		(0x2 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF12		(0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_LOW_POWER			(1 << 13)
+#define SCR_SOFT_RESET			(1 << 12)
+#define SCR_TXFIFO_CTRL_OFFSET		10
+#define SCR_TXFIFO_CTRL_MASK		(0x3 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_ZERO		(0x0 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_NORMAL		(0x1 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_ONESAMPLE	(0x2 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_DMA_RX_EN_OFFSET		9
+#define SCR_DMA_RX_EN_MASK		(1 << SCR_DMA_RX_EN_OFFSET)
+#define SCR_DMA_RX_EN			(1 << SCR_DMA_RX_EN_OFFSET)
+#define SCR_DMA_TX_EN_OFFSET		8
+#define SCR_DMA_TX_EN_MASK		(1 << SCR_DMA_TX_EN_OFFSET)
+#define SCR_DMA_TX_EN			(1 << SCR_DMA_TX_EN_OFFSET)
+#define SCR_VAL_OFFSET			5
+#define SCR_VAL_MASK			(1 << SCR_VAL_OFFSET)
+#define SCR_VAL_CLEAR			(1 << SCR_VAL_OFFSET)
+#define SCR_TXSEL_OFFSET		2
+#define SCR_TXSEL_MASK			(0x7 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_OFF			(0 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_RX			(1 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_NORMAL		(0x5 << SCR_TXSEL_OFFSET)
+#define SCR_USRC_SEL_OFFSET		0x0
+#define SCR_USRC_SEL_MASK		(0x3 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_NONE		(0x0 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_RECV		(0x1 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_CHIP		(0x3 << SCR_USRC_SEL_OFFSET)
+
+/* SPDIF CDText control */
+#define SRCD_CD_USER_OFFSET		1
+#define SRCD_CD_USER			(1 << SRCD_CD_USER_OFFSET)
+
+/* SPDIF Phase Configuration register */
+#define SRPC_DPLL_LOCKED		(1 << 6)
+#define SRPC_CLKSRC_SEL_OFFSET		7
+#define SRPC_CLKSRC_SEL_MASK		(0xf << SRPC_CLKSRC_SEL_OFFSET)
+#define SRPC_CLKSRC_SEL_SET(x)		((x << SRPC_CLKSRC_SEL_OFFSET) & SRPC_CLKSRC_SEL_MASK)
+#define SRPC_CLKSRC_SEL_LOCKED_OFFSET1	5
+#define SRPC_CLKSRC_SEL_LOCKED_OFFSET2	2
+#define SRPC_GAINSEL_OFFSET		3
+#define SRPC_GAINSEL_MASK		(0x7 << SRPC_GAINSEL_OFFSET)
+#define SRPC_GAINSEL_SET(x)		((x << SRPC_GAINSEL_OFFSET) & SRPC_GAINSEL_MASK)
+
+#define SRPC_CLKSRC_MAX			16
+
+enum spdif_gainsel {
+	GAINSEL_MULTI_24 = 0,
+	GAINSEL_MULTI_16,
+	GAINSEL_MULTI_12,
+	GAINSEL_MULTI_8,
+	GAINSEL_MULTI_6,
+	GAINSEL_MULTI_4,
+	GAINSEL_MULTI_3,
+};
+#define GAINSEL_MULTI_MAX		(GAINSEL_MULTI_3 + 1)
+#define SPDIF_DEFAULT_GAINSEL		GAINSEL_MULTI_8
+
+/* SPDIF interrupt mask define */
+#define INT_DPLL_LOCKED			(1 << 20)
+#define INT_TXFIFO_UNOV			(1 << 19)
+#define INT_TXFIFO_RESYNC		(1 << 18)
+#define INT_CNEW			(1 << 17)
+#define INT_VAL_NOGOOD			(1 << 16)
+#define INT_SYM_ERR			(1 << 15)
+#define INT_BIT_ERR			(1 << 14)
+#define INT_URX_FUL			(1 << 10)
+#define INT_URX_OV			(1 << 9)
+#define INT_QRX_FUL			(1 << 8)
+#define INT_QRX_OV			(1 << 7)
+#define INT_UQ_SYNC			(1 << 6)
+#define INT_UQ_ERR			(1 << 5)
+#define INT_RXFIFO_UNOV			(1 << 4)
+#define INT_RXFIFO_RESYNC		(1 << 3)
+#define INT_LOSS_LOCK			(1 << 2)
+#define INT_TX_EM			(1 << 1)
+#define INT_RXFIFO_FUL			(1 << 0)
+
+/* SPDIF Clock register */
+#define STC_SYSCLK_DIV_OFFSET		11
+#define STC_SYSCLK_DIV_MASK		(0x1ff << STC_TXCLK_SRC_OFFSET)
+#define STC_SYSCLK_DIV(x)		((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK)
+#define STC_TXCLK_SRC_OFFSET		8
+#define STC_TXCLK_SRC_MASK		(0x7 << STC_TXCLK_SRC_OFFSET)
+#define STC_TXCLK_SRC_SET(x)		((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK)
+#define STC_TXCLK_ALL_EN_OFFSET		7
+#define STC_TXCLK_ALL_EN_MASK		(1 << STC_TXCLK_ALL_EN_OFFSET)
+#define STC_TXCLK_ALL_EN		(1 << STC_TXCLK_ALL_EN_OFFSET)
+#define STC_TXCLK_DIV_OFFSET		0
+#define STC_TXCLK_DIV_MASK		(0x7ff << STC_TXCLK_DIV_OFFSET)
+#define STC_TXCLK_DIV(x)		((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK)
+#define STC_TXCLK_SRC_MAX		8
+
+/* SPDIF tx rate */
+enum spdif_txrate {
+	SPDIF_TXRATE_32000 = 0,
+	SPDIF_TXRATE_44100,
+	SPDIF_TXRATE_48000,
+};
+#define SPDIF_TXRATE_MAX		(SPDIF_TXRATE_48000 + 1)
+
+
+#define SPDIF_CSTATUS_BYTE		6
+#define SPDIF_UBITS_SIZE		96
+#define SPDIF_QSUB_SIZE			(SPDIF_UBITS_SIZE / 8)
+
+
+#define FSL_SPDIF_RATES_PLAYBACK	(SNDRV_PCM_RATE_32000 |	\
+					 SNDRV_PCM_RATE_44100 |	\
+					 SNDRV_PCM_RATE_48000)
+
+#define FSL_SPDIF_RATES_CAPTURE		(SNDRV_PCM_RATE_16000 | \
+					 SNDRV_PCM_RATE_32000 |	\
+					 SNDRV_PCM_RATE_44100 | \
+					 SNDRV_PCM_RATE_48000 |	\
+					 SNDRV_PCM_RATE_64000 | \
+					 SNDRV_PCM_RATE_96000)
+
+#define FSL_SPDIF_FORMATS_PLAYBACK	(SNDRV_PCM_FMTBIT_S16_LE | \
+					 SNDRV_PCM_FMTBIT_S20_3LE | \
+					 SNDRV_PCM_FMTBIT_S24_LE)
+
+#define FSL_SPDIF_FORMATS_CAPTURE	(SNDRV_PCM_FMTBIT_S24_LE)
+
+#endif /* _FSL_SPDIF_DAI_H */
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2f2d837..c6b7439 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -8,6 +8,26 @@
  * 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.
+ *
+ *
+ * Some notes why imx-pcm-fiq is used instead of DMA on some boards:
+ *
+ * The i.MX SSI core has some nasty limitations in AC97 mode. While most
+ * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
+ * one FIFO which combines all valid receive slots. We cannot even select
+ * which slots we want to receive. The WM9712 with which this driver
+ * was developed with always sends GPIO status data in slot 12 which
+ * we receive in our (PCM-) data stream. The only chance we have is to
+ * manually skip this data in the FIQ handler. With sampling rates different
+ * from 48000Hz not every frame has valid receive data, so the ratio
+ * between pcm data and GPIO status data changes. Our FIQ handler is not
+ * able to handle this, hence this driver only works with 48000Hz sampling
+ * rate.
+ * Reading and writing AC97 registers is another challenge. The core
+ * provides us status bits when the read register is updated with *another*
+ * value. When we read the same register two times (and the register still
+ * contains the same value) these status bits are not set. We work
+ * around this by not polling these bits but only wait a fixed delay.
  */
 
 #include <linux/init.h>
@@ -36,7 +56,7 @@
 #define read_ssi(addr)			 in_be32(addr)
 #define write_ssi(val, addr)		 out_be32(addr, val)
 #define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
-#elif defined ARM
+#else
 #define read_ssi(addr)			 readl(addr)
 #define write_ssi(val, addr)		 writel(val, addr)
 /*
@@ -121,11 +141,14 @@
 
 	bool new_binding;
 	bool ssi_on_imx;
+	bool imx_ac97;
+	bool use_dma;
 	struct clk *clk;
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 	struct snd_dmaengine_dai_dma_data dma_params_rx;
 	struct imx_dma_data filter_data_tx;
 	struct imx_dma_data filter_data_rx;
+	struct imx_pcm_fiq_params fiq_params;
 
 	struct {
 		unsigned int rfrc;
@@ -298,6 +321,102 @@
 	return ret;
 }
 
+static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
+{
+	struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+	u8 i2s_mode;
+	u8 wm;
+	int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+
+	if (ssi_private->imx_ac97)
+		i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
+	else
+		i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+
+	/*
+	 * Section 16.5 of the MPC8610 reference manual says that the SSI needs
+	 * to be disabled before updating the registers we set here.
+	 */
+	write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
+
+	/*
+	 * Program the SSI into I2S Slave Non-Network Synchronous mode. Also
+	 * enable the transmit and receive FIFO.
+	 *
+	 * FIXME: Little-endian samples require a different shift dir
+	 */
+	write_ssi_mask(&ssi->scr,
+		CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
+		CCSR_SSI_SCR_TFR_CLK_DIS |
+		i2s_mode |
+		(synchronous ? CCSR_SSI_SCR_SYN : 0));
+
+	write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+		 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
+		 CCSR_SSI_STCR_TSCKP, &ssi->stcr);
+
+	write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+		 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
+		 CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
+	/*
+	 * The DC and PM bits are only used if the SSI is the clock master.
+	 */
+
+	/*
+	 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
+	 * use FIFO 1. We program the transmit water to signal a DMA transfer
+	 * if there are only two (or fewer) elements left in the FIFO. Two
+	 * elements equals one frame (left channel, right channel). This value,
+	 * however, depends on the depth of the transmit buffer.
+	 *
+	 * We set the watermark on the same level as the DMA burstsize.  For
+	 * fiq it is probably better to use the biggest possible watermark
+	 * size.
+	 */
+	if (ssi_private->use_dma)
+		wm = ssi_private->fifo_depth - 2;
+	else
+		wm = ssi_private->fifo_depth;
+
+	write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
+		CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
+		&ssi->sfcsr);
+
+	/*
+	 * For ac97 interrupts are enabled with the startup of the substream
+	 * because it is also running without an active substream. Normally SSI
+	 * is only enabled when there is a substream.
+	 */
+	if (ssi_private->imx_ac97) {
+		/*
+		 * Setup the clock control register
+		 */
+		write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+				&ssi->stccr);
+		write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+				&ssi->srccr);
+
+		/*
+		 * Enable AC97 mode and startup the SSI
+		 */
+		write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
+				&ssi->sacnt);
+		write_ssi(0xff, &ssi->saccdis);
+		write_ssi(0x300, &ssi->saccen);
+
+		/*
+		 * Enable SSI, Transmit and Receive
+		 */
+		write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
+				CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
+
+		write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
+	}
+
+	return 0;
+}
+
+
 /**
  * fsl_ssi_startup: create a new substream
  *
@@ -319,70 +438,14 @@
 	 * and initialize the SSI registers.
 	 */
 	if (!ssi_private->first_stream) {
-		struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
 		ssi_private->first_stream = substream;
 
 		/*
-		 * Section 16.5 of the MPC8610 reference manual says that the
-		 * SSI needs to be disabled before updating the registers we set
-		 * here.
+		 * fsl_ssi_setup was already called by ac97_init earlier if
+		 * the driver is in ac97 mode.
 		 */
-		write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-
-		/*
-		 * Program the SSI into I2S Slave Non-Network Synchronous mode.
-		 * Also enable the transmit and receive FIFO.
-		 *
-		 * FIXME: Little-endian samples require a different shift dir
-		 */
-		write_ssi_mask(&ssi->scr,
-			CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
-			CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
-			| (synchronous ? CCSR_SSI_SCR_SYN : 0));
-
-		write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
-			 CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
-			 CCSR_SSI_STCR_TSCKP, &ssi->stcr);
-
-		write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
-			 CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
-			 CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
-
-		/*
-		 * The DC and PM bits are only used if the SSI is the clock
-		 * master.
-		 */
-
-		/* Enable the interrupts and DMA requests */
-		write_ssi(SIER_FLAGS, &ssi->sier);
-
-		/*
-		 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
-		 * don't use FIFO 1.  We program the transmit water to signal a
-		 * DMA transfer if there are only two (or fewer) elements left
-		 * in the FIFO.  Two elements equals one frame (left channel,
-		 * right channel).  This value, however, depends on the depth of
-		 * the transmit buffer.
-		 *
-		 * We program the receive FIFO to notify us if at least two
-		 * elements (one frame) have been written to the FIFO.  We could
-		 * make this value larger (and maybe we should), but this way
-		 * data will be written to memory as soon as it's available.
-		 */
-		write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
-			CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2),
-			&ssi->sfcsr);
-
-		/*
-		 * We keep the SSI disabled because if we enable it, then the
-		 * DMA controller will start.  It's not supposed to start until
-		 * the SCR.TE (or SCR.RE) bit is set, but it does anyway.  The
-		 * DMA controller will transfer one "BWC" of data (i.e. the
-		 * amount of data that the MR.BWC bits are set to).  The reason
-		 * this is bad is because at this point, the PCM driver has not
-		 * finished initializing the DMA controller.
-		 */
+		if (!ssi_private->imx_ac97)
+			fsl_ssi_setup(ssi_private);
 	} else {
 		if (synchronous) {
 			struct snd_pcm_runtime *first_runtime =
@@ -492,6 +555,27 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
 	struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+	unsigned int sier_bits;
+
+	/*
+	 *  Enable only the interrupts and DMA requests
+	 *  that are needed for the channel. As the fiq
+	 *  is polling for this bits, we have to ensure
+	 *  that this are aligned with the preallocated
+	 *  buffers
+	 */
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (ssi_private->use_dma)
+			sier_bits = SIER_FLAGS;
+		else
+			sier_bits = CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TFE0_EN;
+	} else {
+		if (ssi_private->use_dma)
+			sier_bits = SIER_FLAGS;
+		else
+			sier_bits = CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_RFF0_EN;
+	}
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -510,12 +594,18 @@
 			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
 		else
 			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
+
+		if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
+					(CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
+			write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
 		break;
 
 	default:
 		return -EINVAL;
 	}
 
+	write_ssi(sier_bits, &ssi->sier);
+
 	return 0;
 }
 
@@ -534,22 +624,13 @@
 		ssi_private->first_stream = ssi_private->second_stream;
 
 	ssi_private->second_stream = NULL;
-
-	/*
-	 * If this is the last active substream, disable the SSI.
-	 */
-	if (!ssi_private->first_stream) {
-		struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
-		write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-	}
 }
 
 static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 {
 	struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
 
-	if (ssi_private->ssi_on_imx) {
+	if (ssi_private->ssi_on_imx && ssi_private->use_dma) {
 		dai->playback_dma_data = &ssi_private->dma_params_tx;
 		dai->capture_dma_data = &ssi_private->dma_params_rx;
 	}
@@ -587,6 +668,133 @@
 	.name		= "fsl-ssi",
 };
 
+/**
+ * fsl_ssi_ac97_trigger: start and stop the AC97 receive/transmit.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the
+ * transfer of data.
+ */
+static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(
+			rtd->cpu_dai);
+	struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_TIE |
+					CCSR_SSI_SIER_TFE0_EN);
+		else
+			write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_RIE |
+					CCSR_SSI_SIER_RFF0_EN);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_TIE |
+					CCSR_SSI_SIER_TFE0_EN, 0);
+		else
+			write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RIE |
+					CCSR_SSI_SIER_RFF0_EN, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
+	else
+		write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = {
+	.startup	= fsl_ssi_startup,
+	.shutdown	= fsl_ssi_shutdown,
+	.trigger	= fsl_ssi_ac97_trigger,
+};
+
+static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
+	.ac97_control = 1,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &fsl_ssi_ac97_dai_ops,
+};
+
+
+static struct fsl_ssi_private *fsl_ac97_data;
+
+static void fsl_ssi_ac97_init(void)
+{
+	fsl_ssi_setup(fsl_ac97_data);
+}
+
+void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+		unsigned short val)
+{
+	struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
+	unsigned int lreg;
+	unsigned int lval;
+
+	if (reg > 0x7f)
+		return;
+
+
+	lreg = reg <<  12;
+	write_ssi(lreg, &ssi->sacadd);
+
+	lval = val << 4;
+	write_ssi(lval , &ssi->sacdat);
+
+	write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK,
+			CCSR_SSI_SACNT_WR);
+	udelay(100);
+}
+
+unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
+		unsigned short reg)
+{
+	struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
+
+	unsigned short val = -1;
+	unsigned int lreg;
+
+	lreg = (reg & 0x7f) <<  12;
+	write_ssi(lreg, &ssi->sacadd);
+	write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK,
+			CCSR_SSI_SACNT_RD);
+
+	udelay(100);
+
+	val = (read_ssi(&ssi->sacdat) >> 4) & 0xffff;
+
+	return val;
+}
+
+static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
+	.read		= fsl_ssi_ac97_read,
+	.write		= fsl_ssi_ac97_write,
+};
+
 /* Show the statistics of a flag only if its interrupt is enabled.  The
  * compiler will optimze this code to a no-op if the interrupt is not
  * enabled.
@@ -663,6 +871,7 @@
 	struct resource res;
 	char name[64];
 	bool shared;
+	bool ac97 = false;
 
 	/* SSIs that are not connected on the board should have a
 	 *      status = "disabled"
@@ -673,14 +882,20 @@
 
 	/* We only support the SSI in "I2S Slave" mode */
 	sprop = of_get_property(np, "fsl,mode", NULL);
-	if (!sprop || strcmp(sprop, "i2s-slave")) {
+	if (!sprop) {
+		dev_err(&pdev->dev, "fsl,mode property is necessary\n");
+		return -EINVAL;
+	}
+	if (!strcmp(sprop, "ac97-slave")) {
+		ac97 = true;
+	} else if (strcmp(sprop, "i2s-slave")) {
 		dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
 		return -ENODEV;
 	}
 
 	/* The DAI name is the last part of the full name of the node. */
 	p = strrchr(np->full_name, '/') + 1;
-	ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+	ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private) + strlen(p),
 			      GFP_KERNEL);
 	if (!ssi_private) {
 		dev_err(&pdev->dev, "could not allocate DAI object\n");
@@ -689,38 +904,41 @@
 
 	strcpy(ssi_private->name, p);
 
-	/* Initialize this copy of the CPU DAI driver structure */
-	memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
-	       sizeof(fsl_ssi_dai_template));
+	ssi_private->use_dma = !of_property_read_bool(np,
+			"fsl,fiq-stream-filter");
+
+	if (ac97) {
+		memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai,
+				sizeof(fsl_ssi_ac97_dai));
+
+		fsl_ac97_data = ssi_private;
+		ssi_private->imx_ac97 = true;
+
+		snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+	} else {
+		/* Initialize this copy of the CPU DAI driver structure */
+		memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+		       sizeof(fsl_ssi_dai_template));
+	}
 	ssi_private->cpu_dai_drv.name = ssi_private->name;
 
 	/* Get the addresses and IRQ */
 	ret = of_address_to_resource(np, 0, &res);
 	if (ret) {
 		dev_err(&pdev->dev, "could not determine device resources\n");
-		goto error_kmalloc;
+		return ret;
 	}
 	ssi_private->ssi = of_iomap(np, 0);
 	if (!ssi_private->ssi) {
 		dev_err(&pdev->dev, "could not map device resources\n");
-		ret = -ENOMEM;
-		goto error_kmalloc;
+		return -ENOMEM;
 	}
 	ssi_private->ssi_phys = res.start;
 
 	ssi_private->irq = irq_of_parse_and_map(np, 0);
 	if (ssi_private->irq == NO_IRQ) {
 		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
-		ret = -ENXIO;
-		goto error_iomap;
-	}
-
-	/* The 'name' should not have any slashes in it. */
-	ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name,
-			  ssi_private);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "could not claim irq %u\n", ssi_private->irq);
-		goto error_irqmap;
+		return -ENXIO;
 	}
 
 	/* Are the RX and the TX clocks locked? */
@@ -739,13 +957,18 @@
 		u32 dma_events[2];
 		ssi_private->ssi_on_imx = true;
 
-		ssi_private->clk = clk_get(&pdev->dev, NULL);
+		ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
 		if (IS_ERR(ssi_private->clk)) {
 			ret = PTR_ERR(ssi_private->clk);
 			dev_err(&pdev->dev, "could not get clock: %d\n", ret);
-			goto error_irq;
+			goto error_irqmap;
 		}
-		clk_prepare_enable(ssi_private->clk);
+		ret = clk_prepare_enable(ssi_private->clk);
+		if (ret) {
+			dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n",
+				ret);
+			goto error_irqmap;
+		}
 
 		/*
 		 * We have burstsize be "fifo_depth - 2" to match the SSI
@@ -763,24 +986,38 @@
 			&ssi_private->filter_data_tx;
 		ssi_private->dma_params_rx.filter_data =
 			&ssi_private->filter_data_rx;
-		/*
-		 * TODO: This is a temporary solution and should be changed
-		 * to use generic DMA binding later when the helplers get in.
-		 */
-		ret = of_property_read_u32_array(pdev->dev.of_node,
+		if (!of_property_read_bool(pdev->dev.of_node, "dmas") &&
+				ssi_private->use_dma) {
+			/*
+			 * FIXME: This is a temporary solution until all
+			 * necessary dma drivers support the generic dma
+			 * bindings.
+			 */
+			ret = of_property_read_u32_array(pdev->dev.of_node,
 					"fsl,ssi-dma-events", dma_events, 2);
-		if (ret) {
-			dev_err(&pdev->dev, "could not get dma events\n");
-			goto error_clk;
+			if (ret && ssi_private->use_dma) {
+				dev_err(&pdev->dev, "could not get dma events but fsl-ssi is configured to use DMA\n");
+				goto error_clk;
+			}
 		}
 
 		shared = of_device_is_compatible(of_get_parent(np),
 			    "fsl,spba-bus");
 
 		imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
-			dma_events[0], shared);
+			dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
 		imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
-			dma_events[1], shared);
+			dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
+	} else if (ssi_private->use_dma) {
+		/* The 'name' should not have any slashes in it. */
+		ret = devm_request_irq(&pdev->dev, ssi_private->irq,
+					fsl_ssi_isr, 0, ssi_private->name,
+					ssi_private);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "could not claim irq %u\n",
+					ssi_private->irq);
+			goto error_irqmap;
+		}
 	}
 
 	/* Initialize the the device_attribute structure */
@@ -794,7 +1031,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "could not create sysfs %s file\n",
 			ssi_private->dev_attr.attr.name);
-		goto error_irq;
+		goto error_clk;
 	}
 
 	/* Register with ASoC */
@@ -808,9 +1045,30 @@
 	}
 
 	if (ssi_private->ssi_on_imx) {
-		ret = imx_pcm_dma_init(pdev);
-		if (ret)
-			goto error_dev;
+		if (!ssi_private->use_dma) {
+
+			/*
+			 * Some boards use an incompatible codec. To get it
+			 * working, we are using imx-fiq-pcm-audio, that
+			 * can handle those codecs. DMA is not possible in this
+			 * situation.
+			 */
+
+			ssi_private->fiq_params.irq = ssi_private->irq;
+			ssi_private->fiq_params.base = ssi_private->ssi;
+			ssi_private->fiq_params.dma_params_rx =
+				&ssi_private->dma_params_rx;
+			ssi_private->fiq_params.dma_params_tx =
+				&ssi_private->dma_params_tx;
+
+			ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
+			if (ret)
+				goto error_dev;
+		} else {
+			ret = imx_pcm_dma_init(pdev);
+			if (ret)
+				goto error_dev;
+		}
 	}
 
 	/*
@@ -845,6 +1103,9 @@
 	}
 
 done:
+	if (ssi_private->imx_ac97)
+		fsl_ssi_ac97_init();
+
 	return 0;
 
 error_dai:
@@ -853,27 +1114,15 @@
 	snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
-	dev_set_drvdata(&pdev->dev, NULL);
 	device_remove_file(&pdev->dev, dev_attr);
 
 error_clk:
-	if (ssi_private->ssi_on_imx) {
+	if (ssi_private->ssi_on_imx)
 		clk_disable_unprepare(ssi_private->clk);
-		clk_put(ssi_private->clk);
-	}
-
-error_irq:
-	free_irq(ssi_private->irq, ssi_private);
 
 error_irqmap:
 	irq_dispose_mapping(ssi_private->irq);
 
-error_iomap:
-	iounmap(ssi_private->ssi);
-
-error_kmalloc:
-	kfree(ssi_private);
-
 	return ret;
 }
 
@@ -883,19 +1132,14 @@
 
 	if (!ssi_private->new_binding)
 		platform_device_unregister(ssi_private->pdev);
-	if (ssi_private->ssi_on_imx) {
+	if (ssi_private->ssi_on_imx)
 		imx_pcm_dma_exit(pdev);
-		clk_disable_unprepare(ssi_private->clk);
-		clk_put(ssi_private->clk);
-	}
 	snd_soc_unregister_component(&pdev->dev);
-	device_remove_file(&pdev->dev, &ssi_private->dev_attr);
-
-	free_irq(ssi_private->irq, ssi_private);
-	irq_dispose_mapping(ssi_private->irq);
-
-	kfree(ssi_private);
 	dev_set_drvdata(&pdev->dev, NULL);
+	device_remove_file(&pdev->dev, &ssi_private->dev_attr);
+	if (ssi_private->ssi_on_imx)
+		clk_disable_unprepare(ssi_private->clk);
+	irq_dispose_mapping(ssi_private->irq);
 
 	return 0;
 }
@@ -919,6 +1163,7 @@
 
 module_platform_driver(fsl_ssi_driver);
 
+MODULE_ALIAS("platform:fsl-ssi-dai");
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index e260f1f..ab17381 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -73,8 +73,11 @@
 	if (!buf)
 		return -ENOMEM;
 
-	if (audmux_clk)
-		clk_prepare_enable(audmux_clk);
+	if (audmux_clk) {
+		ret = clk_prepare_enable(audmux_clk);
+		if (ret)
+			return ret;
+	}
 
 	ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
 	pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
@@ -224,14 +227,19 @@
 int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
 		unsigned int pdcr)
 {
+	int ret;
+
 	if (audmux_type != IMX31_AUDMUX)
 		return -EINVAL;
 
 	if (!audmux_base)
 		return -ENOSYS;
 
-	if (audmux_clk)
-		clk_prepare_enable(audmux_clk);
+	if (audmux_clk) {
+		ret = clk_prepare_enable(audmux_clk);
+		if (ret)
+			return ret;
+	}
 
 	writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
 	writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
@@ -243,6 +251,66 @@
 }
 EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
 
+static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
+		struct device_node *of_node)
+{
+	struct device_node *child;
+
+	for_each_available_child_of_node(of_node, child) {
+		unsigned int port;
+		unsigned int ptcr = 0;
+		unsigned int pdcr = 0;
+		unsigned int pcr = 0;
+		unsigned int val;
+		int ret;
+		int i = 0;
+
+		ret = of_property_read_u32(child, "fsl,audmux-port", &port);
+		if (ret) {
+			dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%s\"\n",
+					child->full_name);
+			continue;
+		}
+		if (!of_property_read_bool(child, "fsl,port-config")) {
+			dev_warn(&pdev->dev, "child node \"%s\" does not have property fsl,port-config\n",
+					child->full_name);
+			continue;
+		}
+
+		for (i = 0; (ret = of_property_read_u32_index(child,
+					"fsl,port-config", i, &val)) == 0;
+				++i) {
+			if (audmux_type == IMX31_AUDMUX) {
+				if (i % 2)
+					pdcr |= val;
+				else
+					ptcr |= val;
+			} else {
+				pcr |= val;
+			}
+		}
+
+		if (ret != -EOVERFLOW) {
+			dev_err(&pdev->dev, "Failed to read u32 at index %d of child %s\n",
+					i, child->full_name);
+			continue;
+		}
+
+		if (audmux_type == IMX31_AUDMUX) {
+			if (i % 2) {
+				dev_err(&pdev->dev, "One pdcr value is missing in child node %s\n",
+						child->full_name);
+				continue;
+			}
+			imx_audmux_v2_configure_port(port, ptcr, pdcr);
+		} else {
+			imx_audmux_v1_configure_port(port, pcr);
+		}
+	}
+
+	return 0;
+}
+
 static int imx_audmux_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -267,6 +335,8 @@
 	if (audmux_type == IMX31_AUDMUX)
 		audmux_debugfs_init();
 
+	imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
+
 	return 0;
 }
 
diff --git a/sound/soc/fsl/imx-audmux.h b/sound/soc/fsl/imx-audmux.h
index b8ff44b..38a4209 100644
--- a/sound/soc/fsl/imx-audmux.h
+++ b/sound/soc/fsl/imx-audmux.h
@@ -1,57 +1,7 @@
 #ifndef __IMX_AUDMUX_H
 #define __IMX_AUDMUX_H
 
-#define MX27_AUDMUX_HPCR1_SSI0		0
-#define MX27_AUDMUX_HPCR2_SSI1		1
-#define MX27_AUDMUX_HPCR3_SSI_PINS_4	2
-#define MX27_AUDMUX_PPCR1_SSI_PINS_1	3
-#define MX27_AUDMUX_PPCR2_SSI_PINS_2	4
-#define MX27_AUDMUX_PPCR3_SSI_PINS_3	5
-
-#define MX31_AUDMUX_PORT1_SSI0		0
-#define MX31_AUDMUX_PORT2_SSI1		1
-#define MX31_AUDMUX_PORT3_SSI_PINS_3	2
-#define MX31_AUDMUX_PORT4_SSI_PINS_4	3
-#define MX31_AUDMUX_PORT5_SSI_PINS_5	4
-#define MX31_AUDMUX_PORT6_SSI_PINS_6	5
-#define MX31_AUDMUX_PORT7_SSI_PINS_7	6
-
-#define MX51_AUDMUX_PORT1_SSI0		0
-#define MX51_AUDMUX_PORT2_SSI1		1
-#define MX51_AUDMUX_PORT3		2
-#define MX51_AUDMUX_PORT4		3
-#define MX51_AUDMUX_PORT5		4
-#define MX51_AUDMUX_PORT6		5
-#define MX51_AUDMUX_PORT7		6
-
-/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
-#define IMX_AUDMUX_V1_PCR_INMMASK(x)	((x) & 0xff)
-#define IMX_AUDMUX_V1_PCR_INMEN		(1 << 8)
-#define IMX_AUDMUX_V1_PCR_TXRXEN	(1 << 10)
-#define IMX_AUDMUX_V1_PCR_SYN		(1 << 12)
-#define IMX_AUDMUX_V1_PCR_RXDSEL(x)	(((x) & 0x7) << 13)
-#define IMX_AUDMUX_V1_PCR_RFCSEL(x)	(((x) & 0xf) << 20)
-#define IMX_AUDMUX_V1_PCR_RCLKDIR	(1 << 24)
-#define IMX_AUDMUX_V1_PCR_RFSDIR	(1 << 25)
-#define IMX_AUDMUX_V1_PCR_TFCSEL(x)	(((x) & 0xf) << 26)
-#define IMX_AUDMUX_V1_PCR_TCLKDIR	(1 << 30)
-#define IMX_AUDMUX_V1_PCR_TFSDIR	(1 << 31)
-
-/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */
-#define IMX_AUDMUX_V2_PTCR_TFSDIR	(1 << 31)
-#define IMX_AUDMUX_V2_PTCR_TFSEL(x)	(((x) & 0xf) << 27)
-#define IMX_AUDMUX_V2_PTCR_TCLKDIR	(1 << 26)
-#define IMX_AUDMUX_V2_PTCR_TCSEL(x)	(((x) & 0xf) << 22)
-#define IMX_AUDMUX_V2_PTCR_RFSDIR	(1 << 21)
-#define IMX_AUDMUX_V2_PTCR_RFSEL(x)	(((x) & 0xf) << 17)
-#define IMX_AUDMUX_V2_PTCR_RCLKDIR	(1 << 16)
-#define IMX_AUDMUX_V2_PTCR_RCSEL(x)	(((x) & 0xf) << 12)
-#define IMX_AUDMUX_V2_PTCR_SYN		(1 << 11)
-
-#define IMX_AUDMUX_V2_PDCR_RXDSEL(x)	(((x) & 0x7) << 13)
-#define IMX_AUDMUX_V2_PDCR_TXRXEN	(1 << 12)
-#define IMX_AUDMUX_V2_PDCR_MODE(x)	(((x) & 0x3) << 8)
-#define IMX_AUDMUX_V2_PDCR_INMMASK(x)	((x) & 0xff)
+#include <dt-bindings/sound/fsl-imx-audmux.h>
 
 int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr);
 
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
index 9df173c..a3d60d4 100644
--- a/sound/soc/fsl/imx-mc13783.c
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -90,6 +90,7 @@
 
 static struct snd_soc_card imx_mc13783 = {
 	.name		= "imx_mc13783",
+	.owner		= THIS_MODULE,
 	.dai_link	= imx_mc13783_dai_mc13783,
 	.num_links	= ARRAY_SIZE(imx_mc13783_dai_mc13783),
 	.dapm_widgets	= imx_mc13783_widget,
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index fde4d2e..4dc1296 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
 #include <linux/types.h>
+#include <linux/module.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -64,7 +65,6 @@
 {
 	return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
 		SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
-		SND_DMAENGINE_PCM_FLAG_NO_DT |
 		SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
@@ -74,3 +74,5 @@
 	snd_dmaengine_pcm_unregister(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_dma_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 310d902..34043c5 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -32,6 +33,7 @@
 #include <linux/platform_data/asoc-imx-ssi.h>
 
 #include "imx-ssi.h"
+#include "imx-pcm.h"
 
 struct imx_pcm_runtime_data {
 	unsigned int period;
@@ -366,9 +368,9 @@
 	.pcm_free	= imx_pcm_fiq_free,
 };
 
-int imx_pcm_fiq_init(struct platform_device *pdev)
+int imx_pcm_fiq_init(struct platform_device *pdev,
+		struct imx_pcm_fiq_params *params)
 {
-	struct imx_ssi *ssi = platform_get_drvdata(pdev);
 	int ret;
 
 	ret = claim_fiq(&fh);
@@ -377,15 +379,15 @@
 		return ret;
 	}
 
-	mxc_set_irq_fiq(ssi->irq, 1);
-	ssi_irq = ssi->irq;
+	mxc_set_irq_fiq(params->irq, 1);
+	ssi_irq = params->irq;
 
-	imx_pcm_fiq = ssi->irq;
+	imx_pcm_fiq = params->irq;
 
-	imx_ssi_fiq_base = (unsigned long)ssi->base;
+	imx_ssi_fiq_base = (unsigned long)params->base;
 
-	ssi->dma_params_tx.maxburst = 4;
-	ssi->dma_params_rx.maxburst = 6;
+	params->dma_params_tx->maxburst = 4;
+	params->dma_params_rx->maxburst = 6;
 
 	ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
 	if (ret)
@@ -406,3 +408,5 @@
 	snd_soc_unregister_platform(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index 67f656c..5d5b733 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -22,17 +22,23 @@
 
 static inline void
 imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
-	int dma, bool shared)
+	int dma, enum sdma_peripheral_type peripheral_type)
 {
 	dma_data->dma_request = dma;
 	dma_data->priority = DMA_PRIO_HIGH;
-	if (shared)
-		dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
-	else
-		dma_data->peripheral_type = IMX_DMATYPE_SSI;
+	dma_data->peripheral_type = peripheral_type;
 }
 
-#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
+struct imx_pcm_fiq_params {
+	int irq;
+	void __iomem *base;
+
+	/* Pointer to original ssi driver to setup tx rx sizes */
+	struct snd_dmaengine_dai_dma_data *dma_params_rx;
+	struct snd_dmaengine_dai_dma_data *dma_params_tx;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)
 int imx_pcm_dma_init(struct platform_device *pdev);
 void imx_pcm_dma_exit(struct platform_device *pdev);
 #else
@@ -46,11 +52,13 @@
 }
 #endif
 
-#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
-int imx_pcm_fiq_init(struct platform_device *pdev);
+#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_FIQ)
+int imx_pcm_fiq_init(struct platform_device *pdev,
+		struct imx_pcm_fiq_params *params);
 void imx_pcm_fiq_exit(struct platform_device *pdev);
 #else
-static inline int imx_pcm_fiq_init(struct platform_device *pdev)
+static inline int imx_pcm_fiq_init(struct platform_device *pdev,
+		struct imx_pcm_fiq_params *params)
 {
 	return -ENODEV;
 }
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 3f726e4..389cbfa 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -129,8 +129,10 @@
 	}
 
 	data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
-	if (IS_ERR(data->codec_clk))
+	if (IS_ERR(data->codec_clk)) {
+		ret = PTR_ERR(data->codec_clk);
 		goto fail;
+	}
 
 	data->clk_frequency = clk_get_rate(data->codec_clk);
 
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
new file mode 100644
index 0000000..816013b
--- /dev/null
+++ b/sound/soc/fsl/imx-spdif.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+
+struct imx_spdif_data {
+	struct snd_soc_dai_link dai[2];
+	struct snd_soc_card card;
+	struct platform_device *txdev;
+	struct platform_device *rxdev;
+};
+
+static int imx_spdif_audio_probe(struct platform_device *pdev)
+{
+	struct device_node *spdif_np, *np = pdev->dev.of_node;
+	struct imx_spdif_data *data;
+	int ret = 0, num_links = 0;
+
+	spdif_np = of_parse_phandle(np, "spdif-controller", 0);
+	if (!spdif_np) {
+		dev_err(&pdev->dev, "failed to find spdif-controller\n");
+		ret = -EINVAL;
+		goto end;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		ret = -ENOMEM;
+		goto end;
+	}
+
+	if (of_property_read_bool(np, "spdif-out")) {
+		data->dai[num_links].name = "S/PDIF TX";
+		data->dai[num_links].stream_name = "S/PDIF PCM Playback";
+		data->dai[num_links].codec_dai_name = "dit-hifi";
+		data->dai[num_links].codec_name = "spdif-dit";
+		data->dai[num_links].cpu_of_node = spdif_np;
+		data->dai[num_links].platform_of_node = spdif_np;
+		num_links++;
+
+		data->txdev = platform_device_register_simple("spdif-dit", -1, NULL, 0);
+		if (IS_ERR(data->txdev)) {
+			ret = PTR_ERR(data->txdev);
+			dev_err(&pdev->dev, "register dit failed: %d\n", ret);
+			goto end;
+		}
+	}
+
+	if (of_property_read_bool(np, "spdif-in")) {
+		data->dai[num_links].name = "S/PDIF RX";
+		data->dai[num_links].stream_name = "S/PDIF PCM Capture";
+		data->dai[num_links].codec_dai_name = "dir-hifi";
+		data->dai[num_links].codec_name = "spdif-dir";
+		data->dai[num_links].cpu_of_node = spdif_np;
+		data->dai[num_links].platform_of_node = spdif_np;
+		num_links++;
+
+		data->rxdev = platform_device_register_simple("spdif-dir", -1, NULL, 0);
+		if (IS_ERR(data->rxdev)) {
+			ret = PTR_ERR(data->rxdev);
+			dev_err(&pdev->dev, "register dir failed: %d\n", ret);
+			goto error_dit;
+		}
+	}
+
+	if (!num_links) {
+		dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
+		goto error_dir;
+	}
+
+	data->card.dev = &pdev->dev;
+	data->card.num_links = num_links;
+	data->card.dai_link = data->dai;
+
+	ret = snd_soc_of_parse_card_name(&data->card, "model");
+	if (ret)
+		goto error_dir;
+
+	ret = snd_soc_register_card(&data->card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret);
+		goto error_dir;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+	goto end;
+
+error_dir:
+	if (data->rxdev)
+		platform_device_unregister(data->rxdev);
+error_dit:
+	if (data->txdev)
+		platform_device_unregister(data->txdev);
+end:
+	if (spdif_np)
+		of_node_put(spdif_np);
+
+	return ret;
+}
+
+static int imx_spdif_audio_remove(struct platform_device *pdev)
+{
+	struct imx_spdif_data *data = platform_get_drvdata(pdev);
+
+	if (data->rxdev)
+		platform_device_unregister(data->rxdev);
+	if (data->txdev)
+		platform_device_unregister(data->txdev);
+
+	snd_soc_unregister_card(&data->card);
+
+	return 0;
+}
+
+static const struct of_device_id imx_spdif_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-spdif", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
+
+static struct platform_driver imx_spdif_driver = {
+	.driver = {
+		.name = "imx-spdif",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_spdif_dt_ids,
+	},
+	.probe = imx_spdif_audio_probe,
+	.remove = imx_spdif_audio_remove,
+};
+
+module_platform_driver(imx_spdif_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-spdif");
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 51be377..f58bcd8 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -571,13 +571,13 @@
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
 	if (res) {
 		imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
-			false);
+			IMX_DMATYPE_SSI);
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
 	if (res) {
 		imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
-			false);
+			IMX_DMATYPE_SSI);
 	}
 
 	platform_set_drvdata(pdev, ssi);
@@ -595,7 +595,12 @@
 		goto failed_register;
 	}
 
-	ret = imx_pcm_fiq_init(pdev);
+	ssi->fiq_params.irq = ssi->irq;
+	ssi->fiq_params.base = ssi->base;
+	ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
+	ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
+
+	ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
 	if (ret)
 		goto failed_pcm_fiq;
 
diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
index d5003ce..fb1616b 100644
--- a/sound/soc/fsl/imx-ssi.h
+++ b/sound/soc/fsl/imx-ssi.h
@@ -209,6 +209,7 @@
 	struct snd_dmaengine_dai_dma_data dma_params_tx;
 	struct imx_dma_data filter_data_tx;
 	struct imx_dma_data filter_data_rx;
+	struct imx_pcm_fiq_params fiq_params;
 
 	int enabled;
 };
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index 52a36a9..1d70e27 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -217,7 +217,8 @@
 	codec_dev = of_find_i2c_device_by_node(codec_np);
 	if (!codec_dev || !codec_dev->driver) {
 		dev_err(&pdev->dev, "failed to find codec platform device\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto fail;
 	}
 
 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 6cf8355..8c49147 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -105,6 +105,7 @@
 static struct platform_driver asoc_simple_card = {
 	.driver = {
 		.name	= "asoc-simple-card",
+		.owner = THIS_MODULE,
 	},
 	.probe		= asoc_simple_card_probe,
 	.remove		= asoc_simple_card_remove,
@@ -112,6 +113,7 @@
 
 module_platform_driver(asoc_simple_card);
 
+MODULE_ALIAS("platform:asoc-simple-card");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("ASoC Simple Sound Card");
 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
index c62d715..78ed4a4 100644
--- a/sound/soc/kirkwood/Kconfig
+++ b/sound/soc/kirkwood/Kconfig
@@ -1,19 +1,15 @@
 config SND_KIRKWOOD_SOC
-	tristate "SoC Audio for the Marvell Kirkwood chip"
-	depends on ARCH_KIRKWOOD
+	tristate "SoC Audio for the Marvell Kirkwood and Dove chips"
+	depends on ARCH_KIRKWOOD || ARCH_DOVE || COMPILE_TEST
 	help
 	  Say Y or M if you want to add support for codecs attached to
 	  the Kirkwood I2S interface. You will also need to select the
 	  audio interfaces to support below.
 
-config SND_KIRKWOOD_SOC_I2S
-	tristate
-
 config SND_KIRKWOOD_SOC_OPENRD
 	tristate "SoC Audio support for Kirkwood Openrd Client"
-	depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE)
+	depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST)
 	depends on I2C
-	select SND_KIRKWOOD_SOC_I2S
 	select SND_SOC_CS42L51
 	help
 	  Say Y if you want to add support for SoC audio on
@@ -21,8 +17,7 @@
 
 config SND_KIRKWOOD_SOC_T5325
 	tristate "SoC Audio support for HP t5325"
-	depends on SND_KIRKWOOD_SOC && MACH_T5325 && I2C
-	select SND_KIRKWOOD_SOC_I2S
+	depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C
 	select SND_SOC_ALC5623
 	help
 	  Say Y if you want to add support for SoC audio on
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
index 3e62ae9..9e78138 100644
--- a/sound/soc/kirkwood/Makefile
+++ b/sound/soc/kirkwood/Makefile
@@ -1,8 +1,6 @@
-snd-soc-kirkwood-objs := kirkwood-dma.o
-snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+snd-soc-kirkwood-objs := kirkwood-dma.o kirkwood-i2s.o
 
 obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
-obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
 
 snd-soc-openrd-objs := kirkwood-openrd.o
 snd-soc-t5325-objs := kirkwood-t5325.o
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index a9f1453..b238434 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -33,11 +33,11 @@
 	 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \
 	 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE)
 
-struct kirkwood_dma_priv {
-	struct snd_pcm_substream *play_stream;
-	struct snd_pcm_substream *rec_stream;
-	struct kirkwood_dma_data *data;
-};
+static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = subs->private_data;
+	return snd_soc_dai_get_drvdata(soc_runtime->cpu_dai);
+}
 
 static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
 	.info = (SNDRV_PCM_INFO_INTERLEAVED |
@@ -51,7 +51,7 @@
 	.rate_max		= 384000,
 	.channels_min		= 1,
 	.channels_max		= 8,
-	.buffer_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+	.buffer_bytes_max	= KIRKWOOD_SND_MAX_BUFFER_BYTES,
 	.period_bytes_min	= KIRKWOOD_SND_MIN_PERIOD_BYTES,
 	.period_bytes_max	= KIRKWOOD_SND_MAX_PERIOD_BYTES,
 	.periods_min		= KIRKWOOD_SND_MIN_PERIODS,
@@ -63,8 +63,7 @@
 
 static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
 {
-	struct kirkwood_dma_priv *prdata = dev_id;
-	struct kirkwood_dma_data *priv = prdata->data;
+	struct kirkwood_dma_data *priv = dev_id;
 	unsigned long mask, status, cause;
 
 	mask = readl(priv->io + KIRKWOOD_INT_MASK);
@@ -89,10 +88,10 @@
 	writel(status, priv->io + KIRKWOOD_INT_CAUSE);
 
 	if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
-		snd_pcm_period_elapsed(prdata->play_stream);
+		snd_pcm_period_elapsed(priv->substream_play);
 
 	if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
-		snd_pcm_period_elapsed(prdata->rec_stream);
+		snd_pcm_period_elapsed(priv->substream_rec);
 
 	return IRQ_HANDLED;
 }
@@ -126,15 +125,10 @@
 {
 	int err;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct snd_soc_platform *platform = soc_runtime->platform;
-	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-	struct kirkwood_dma_data *priv;
-	struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
+	struct kirkwood_dma_data *priv = kirkwood_priv(substream);
 	const struct mbus_dram_target_info *dram;
 	unsigned long addr;
 
-	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
 	snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
 
 	/* Ensure that all constraints linked to dma burst are fulfilled */
@@ -157,21 +151,11 @@
 	if (err < 0)
 		return err;
 
-	if (prdata == NULL) {
-		prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
-		if (prdata == NULL)
-			return -ENOMEM;
-
-		prdata->data = priv;
-
+	if (!priv->substream_play && !priv->substream_rec) {
 		err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
-				  "kirkwood-i2s", prdata);
-		if (err) {
-			kfree(prdata);
+				  "kirkwood-i2s", priv);
+		if (err)
 			return -EBUSY;
-		}
-
-		snd_soc_platform_set_drvdata(platform, prdata);
 
 		/*
 		 * Enable Error interrupts. We're only ack'ing them but
@@ -183,11 +167,11 @@
 	dram = mv_mbus_dram_info();
 	addr = substream->dma_buffer.addr;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		prdata->play_stream = substream;
+		priv->substream_play = substream;
 		kirkwood_dma_conf_mbus_windows(priv->io,
 			KIRKWOOD_PLAYBACK_WIN, addr, dram);
 	} else {
-		prdata->rec_stream = substream;
+		priv->substream_rec = substream;
 		kirkwood_dma_conf_mbus_windows(priv->io,
 			KIRKWOOD_RECORD_WIN, addr, dram);
 	}
@@ -197,27 +181,19 @@
 
 static int kirkwood_dma_close(struct snd_pcm_substream *substream)
 {
-	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-	struct snd_soc_platform *platform = soc_runtime->platform;
-	struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
-	struct kirkwood_dma_data *priv;
+	struct kirkwood_dma_data *priv = kirkwood_priv(substream);
 
-	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
-
-	if (!prdata || !priv)
+	if (!priv)
 		return 0;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		prdata->play_stream = NULL;
+		priv->substream_play = NULL;
 	else
-		prdata->rec_stream = NULL;
+		priv->substream_rec = NULL;
 
-	if (!prdata->play_stream && !prdata->rec_stream) {
+	if (!priv->substream_play && !priv->substream_rec) {
 		writel(0, priv->io + KIRKWOOD_ERR_MASK);
-		free_irq(priv->irq, prdata);
-		kfree(prdata);
-		snd_soc_platform_set_drvdata(platform, NULL);
+		free_irq(priv->irq, priv);
 	}
 
 	return 0;
@@ -243,13 +219,9 @@
 static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-	struct kirkwood_dma_data *priv;
+	struct kirkwood_dma_data *priv = kirkwood_priv(substream);
 	unsigned long size, count;
 
-	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
-
 	/* compute buffer size in term of "words" as requested in specs */
 	size = frames_to_bytes(runtime, runtime->buffer_size);
 	size = (size>>2)-1;
@@ -272,13 +244,9 @@
 static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
 						*substream)
 {
-	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-	struct kirkwood_dma_data *priv;
+	struct kirkwood_dma_data *priv = kirkwood_priv(substream);
 	snd_pcm_uframes_t count;
 
-	priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
-
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		count = bytes_to_frames(substream->runtime,
 			readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
@@ -366,36 +334,8 @@
 	}
 }
 
-static struct snd_soc_platform_driver kirkwood_soc_platform = {
+struct snd_soc_platform_driver kirkwood_soc_platform = {
 	.ops		= &kirkwood_dma_ops,
 	.pcm_new	= kirkwood_dma_new,
 	.pcm_free	= kirkwood_dma_free_dma_buffers,
 };
-
-static int kirkwood_soc_platform_probe(struct platform_device *pdev)
-{
-	return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
-}
-
-static int kirkwood_soc_platform_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_platform(&pdev->dev);
-	return 0;
-}
-
-static struct platform_driver kirkwood_pcm_driver = {
-	.driver = {
-			.name = "kirkwood-pcm-audio",
-			.owner = THIS_MODULE,
-	},
-
-	.probe = kirkwood_soc_platform_probe,
-	.remove = kirkwood_soc_platform_remove,
-};
-
-module_platform_driver(kirkwood_pcm_driver);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
-MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:kirkwood-pcm-audio");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 4c9dad3..7fce340 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -22,13 +22,12 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <linux/platform_data/asoc-kirkwood.h>
+#include <linux/of.h>
+
 #include "kirkwood.h"
 
-#define DRV_NAME	"kirkwood-i2s"
+#define DRV_NAME	"mvebu-audio"
 
-#define KIRKWOOD_I2S_RATES \
-	(SNDRV_PCM_RATE_44100 | \
-	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 #define KIRKWOOD_I2S_FORMATS \
 	(SNDRV_PCM_FMTBIT_S16_LE | \
 	 SNDRV_PCM_FMTBIT_S24_LE | \
@@ -105,14 +104,16 @@
 	uint32_t clks_ctrl;
 
 	if (rate == 44100 || rate == 48000 || rate == 96000) {
-		/* use internal dco for supported rates */
+		/* use internal dco for the supported rates
+		 * defined in kirkwood_i2s_dai */
 		dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
 			__func__, rate);
 		kirkwood_set_dco(priv->io, rate);
 
 		clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
-	} else if (!IS_ERR(priv->extclk)) {
-		/* use optional external clk for other rates */
+	} else {
+		/* use the external clock for the other rates
+		 * defined in kirkwood_i2s_dai_extclk */
 		dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
 			__func__, rate, 256 * rate);
 		clk_set_rate(priv->extclk, 256 * rate);
@@ -199,8 +200,7 @@
 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
 
 		priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
-				    KIRKWOOD_PLAYCTL_I2S_EN |
-				    KIRKWOOD_PLAYCTL_SPDIF_EN |
+				    KIRKWOOD_PLAYCTL_ENABLE_MASK |
 				    KIRKWOOD_PLAYCTL_SIZE_MASK);
 		priv->ctl_play |= ctl_play;
 	} else {
@@ -244,8 +244,7 @@
 	case SNDRV_PCM_TRIGGER_START:
 		/* configure */
 		ctl = priv->ctl_play;
-		value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN |
-				KIRKWOOD_PLAYCTL_SPDIF_EN);
+		value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
 
 		/* enable interrupts */
@@ -267,7 +266,7 @@
 		writel(value, priv->io + KIRKWOOD_INT_MASK);
 
 		/* disable all playbacks */
-		ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+		ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
 		break;
 
@@ -387,7 +386,7 @@
 
 	/* disable playback/record */
 	value = readl(priv->io + KIRKWOOD_PLAYCTL);
-	value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+	value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
 	writel(value, priv->io + KIRKWOOD_PLAYCTL);
 
 	value = readl(priv->io + KIRKWOOD_RECCTL);
@@ -398,11 +397,6 @@
 
 }
 
-static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
-{
-	return 0;
-}
-
 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
 	.startup	= kirkwood_i2s_startup,
 	.trigger	= kirkwood_i2s_trigger,
@@ -413,17 +407,18 @@
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai = {
 	.probe = kirkwood_i2s_probe,
-	.remove = kirkwood_i2s_remove,
 	.playback = {
 		.channels_min = 1,
 		.channels_max = 2,
-		.rates = KIRKWOOD_I2S_RATES,
+		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_96000,
 		.formats = KIRKWOOD_I2S_FORMATS,
 	},
 	.capture = {
 		.channels_min = 1,
 		.channels_max = 2,
-		.rates = KIRKWOOD_I2S_RATES,
+		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+				SNDRV_PCM_RATE_96000,
 		.formats = KIRKWOOD_I2S_FORMATS,
 	},
 	.ops = &kirkwood_i2s_dai_ops,
@@ -431,7 +426,6 @@
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
 	.probe = kirkwood_i2s_probe,
-	.remove = kirkwood_i2s_remove,
 	.playback = {
 		.channels_min = 1,
 		.channels_max = 2,
@@ -461,6 +455,7 @@
 	struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
 	struct kirkwood_dma_data *priv;
 	struct resource *mem;
+	struct device_node *np = pdev->dev.of_node;
 	int err;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -481,14 +476,16 @@
 		return -ENXIO;
 	}
 
-	if (!data) {
-		dev_err(&pdev->dev, "no platform data ?!\n");
+	if (np) {
+		priv->burst = 128;		/* might be 32 or 128 */
+	} else if (data) {
+		priv->burst = data->burst;
+	} else {
+		dev_err(&pdev->dev, "no DT nor platform data ?!\n");
 		return -EINVAL;
 	}
 
-	priv->burst = data->burst;
-
-	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
 	if (IS_ERR(priv->clk)) {
 		dev_err(&pdev->dev, "no clock\n");
 		return PTR_ERR(priv->clk);
@@ -498,10 +495,10 @@
 	if (err < 0)
 		return err;
 
-	priv->extclk = clk_get(&pdev->dev, "extclk");
+	priv->extclk = devm_clk_get(&pdev->dev, "extclk");
 	if (!IS_ERR(priv->extclk)) {
 		if (priv->extclk == priv->clk) {
-			clk_put(priv->extclk);
+			devm_clk_put(&pdev->dev, priv->extclk);
 			priv->extclk = ERR_PTR(-EINVAL);
 		} else {
 			dev_info(&pdev->dev, "found external clock\n");
@@ -515,7 +512,7 @@
 	priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
 
 	/* Select the burst size */
-	if (data->burst == 32) {
+	if (priv->burst == 32) {
 		priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
 	} else {
@@ -525,14 +522,22 @@
 
 	err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
 					 soc_dai, 1);
-	if (!err)
-		return 0;
-	dev_err(&pdev->dev, "snd_soc_register_component failed\n");
-
-	if (!IS_ERR(priv->extclk)) {
-		clk_disable_unprepare(priv->extclk);
-		clk_put(priv->extclk);
+	if (err) {
+		dev_err(&pdev->dev, "snd_soc_register_component failed\n");
+		goto err_component;
 	}
+
+	err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
+	if (err) {
+		dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
+		goto err_platform;
+	}
+	return 0;
+ err_platform:
+	snd_soc_unregister_component(&pdev->dev);
+ err_component:
+	if (!IS_ERR(priv->extclk))
+		clk_disable_unprepare(priv->extclk);
 	clk_disable_unprepare(priv->clk);
 
 	return err;
@@ -542,23 +547,31 @@
 {
 	struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
 
+	snd_soc_unregister_platform(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
-	if (!IS_ERR(priv->extclk)) {
+	if (!IS_ERR(priv->extclk))
 		clk_disable_unprepare(priv->extclk);
-		clk_put(priv->extclk);
-	}
 	clk_disable_unprepare(priv->clk);
 
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id mvebu_audio_of_match[] = {
+	{ .compatible = "marvell,mvebu-audio" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
+#endif
+
 static struct platform_driver kirkwood_i2s_driver = {
 	.probe  = kirkwood_i2s_dev_probe,
 	.remove = kirkwood_i2s_dev_remove,
 	.driver = {
 		.name = DRV_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(mvebu_audio_of_match),
 	},
 };
 
@@ -568,4 +581,4 @@
 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:kirkwood-i2s");
+MODULE_ALIAS("platform:mvebu-audio");
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
index b979c71..025be0e 100644
--- a/sound/soc/kirkwood/kirkwood-openrd.c
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -16,9 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <mach/kirkwood.h>
 #include <linux/platform_data/asoc-kirkwood.h>
-#include <asm/mach-types.h>
 #include "../codecs/cs42l51.h"
 
 static int openrd_client_hw_params(struct snd_pcm_substream *substream,
@@ -54,8 +52,8 @@
 {
 	.name = "CS42L51",
 	.stream_name = "CS42L51 HiFi",
-	.cpu_dai_name = "kirkwood-i2s",
-	.platform_name = "kirkwood-pcm-audio",
+	.cpu_dai_name = "mvebu-audio",
+	.platform_name = "mvebu-audio",
 	.codec_dai_name = "cs42l51-hifi",
 	.codec_name = "cs42l51-codec.0-004a",
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c
index 1d0ed6f..27545b0 100644
--- a/sound/soc/kirkwood/kirkwood-t5325.c
+++ b/sound/soc/kirkwood/kirkwood-t5325.c
@@ -15,9 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <mach/kirkwood.h>
 #include <linux/platform_data/asoc-kirkwood.h>
-#include <asm/mach-types.h>
 #include "../codecs/alc5623.h"
 
 static int t5325_hw_params(struct snd_pcm_substream *substream,
@@ -70,8 +68,8 @@
 {
 	.name = "ALC5621",
 	.stream_name = "ALC5621 HiFi",
-	.cpu_dai_name = "kirkwood-i2s",
-	.platform_name = "kirkwood-pcm-audio",
+	.cpu_dai_name = "mvebu-audio",
+	.platform_name = "mvebu-audio",
 	.codec_dai_name = "alc5621-hifi",
 	.codec_name = "alc562x-codec.0-001a",
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index 4d92637..f8e1ccc 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -54,7 +54,7 @@
 #define KIRKWOOD_PLAYCTL_MONO_OFF		(0<<5)
 #define KIRKWOOD_PLAYCTL_I2S_MUTE		(1<<7)
 #define KIRKWOOD_PLAYCTL_SPDIF_EN		(1<<4)
-#define KIRKWOOD_PLAYCTL_I2S_EN		(1<<3)
+#define KIRKWOOD_PLAYCTL_I2S_EN			(1<<3)
 #define KIRKWOOD_PLAYCTL_SIZE_MASK		(7<<0)
 #define KIRKWOOD_PLAYCTL_SIZE_16		(7<<0)
 #define KIRKWOOD_PLAYCTL_SIZE_16_C		(3<<0)
@@ -62,6 +62,9 @@
 #define KIRKWOOD_PLAYCTL_SIZE_24		(1<<0)
 #define KIRKWOOD_PLAYCTL_SIZE_32		(0<<0)
 
+#define KIRKWOOD_PLAYCTL_ENABLE_MASK		(KIRKWOOD_PLAYCTL_SPDIF_EN | \
+						 KIRKWOOD_PLAYCTL_I2S_EN)
+
 #define KIRKWOOD_PLAY_BUF_ADDR			0x1104
 #define KIRKWOOD_PLAY_BUF_SIZE			0x1108
 #define KIRKWOOD_PLAY_BYTE_COUNT		0x110C
@@ -122,6 +125,8 @@
 #define KIRKWOOD_SND_MAX_PERIODS		16
 #define KIRKWOOD_SND_MIN_PERIOD_BYTES		0x4000
 #define KIRKWOOD_SND_MAX_PERIOD_BYTES		0x4000
+#define KIRKWOOD_SND_MAX_BUFFER_BYTES		(KIRKWOOD_SND_MAX_PERIOD_BYTES \
+						 * KIRKWOOD_SND_MAX_PERIODS)
 
 struct kirkwood_dma_data {
 	void __iomem *io;
@@ -129,8 +134,12 @@
 	struct clk *extclk;
 	uint32_t ctl_play;
 	uint32_t ctl_rec;
+	struct snd_pcm_substream *substream_play;
+	struct snd_pcm_substream *substream_rec;
 	int irq;
 	int burst;
 };
 
+extern struct snd_soc_platform_driver kirkwood_soc_platform;
+
 #endif
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
index 78d321c..219235c 100644
--- a/sound/soc/mxs/Kconfig
+++ b/sound/soc/mxs/Kconfig
@@ -1,6 +1,7 @@
 menuconfig SND_MXS_SOC
 	tristate "SoC Audio for Freescale MXS CPUs"
-	depends on ARCH_MXS
+	depends on ARCH_MXS || COMPILE_TEST
+	depends on COMMON_CLK
 	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	  Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 54511c5..b56b8a0 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -31,7 +31,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <asm/mach-types.h>
 
 #include "mxs-saif.h"
 
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 1b134d7..4bb2737 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -25,7 +25,6 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 #include <sound/soc-dapm.h>
-#include <asm/mach-types.h>
 
 #include "../codecs/sgtl5000.h"
 #include "mxs-saif.h"
@@ -51,18 +50,27 @@
 	}
 
 	/* Sgtl5000 sysclk should be >= 8MHz and <= 27M */
-	if (mclk < 8000000 || mclk > 27000000)
+	if (mclk < 8000000 || mclk > 27000000) {
+		dev_err(codec_dai->dev, "Invalid mclk frequency: %u.%03uMHz\n",
+			mclk / 1000000, mclk / 1000 % 1000);
 		return -EINVAL;
+	}
 
 	/* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */
 	ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0);
-	if (ret)
+	if (ret) {
+		dev_err(codec_dai->dev, "Failed to set sysclk to %u.%03uMHz\n",
+			mclk / 1000000, mclk / 1000 % 1000);
 		return ret;
+	}
 
 	/* The SAIF MCLK should be the same as SGTL5000_SYSCLK */
 	ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0);
-	if (ret)
+	if (ret) {
+		dev_err(cpu_dai->dev, "Failed to set sysclk to %u.%03uMHz\n",
+			mclk / 1000000, mclk / 1000 % 1000);
 		return ret;
+	}
 
 	/* set codec to slave mode */
 	dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -70,13 +78,19 @@
 
 	/* set codec DAI configuration */
 	ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
-	if (ret)
+	if (ret) {
+		dev_err(codec_dai->dev, "Failed to set dai format to %08x\n",
+			dai_format);
 		return ret;
+	}
 
 	/* set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
-	if (ret)
+	if (ret) {
+		dev_err(cpu_dai->dev, "Failed to set dai format to %08x\n",
+			dai_format);
 		return ret;
+	}
 
 	return 0;
 }
@@ -91,11 +105,13 @@
 		.stream_name	= "HiFi Playback",
 		.codec_dai_name	= "sgtl5000",
 		.ops		= &mxs_sgtl5000_hifi_ops,
+		.playback_only	= true,
 	}, {
 		.name		= "HiFi Rx",
 		.stream_name	= "HiFi Capture",
 		.codec_dai_name	= "sgtl5000",
 		.ops		= &mxs_sgtl5000_hifi_ops,
+		.capture_only	= true,
 	},
 };
 
@@ -154,8 +170,10 @@
 	 * should be >= 8MHz and <= 27M.
 	 */
 	ret = mxs_saif_get_mclk(0, 44100 * 256, 44100);
-	if (ret)
+	if (ret) {
+		dev_err(&pdev->dev, "failed to get mclk\n");
 		return ret;
+	}
 
 	card->dev = &pdev->dev;
 	platform_set_drvdata(pdev, card);
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index f4c2417..8987bf9 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -333,9 +333,6 @@
 	spin_lock_init(&nuc900_audio->lock);
 
 	nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!nuc900_audio->res)
-		return ret;
-
 	nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev,
 						   nuc900_audio->res);
 	if (IS_ERR(nuc900_audio->mmio))
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 9f5d55e..daa78a0 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,7 +1,7 @@
 config SND_OMAP_SOC
 	tristate "SoC Audio for the Texas Instruments OMAP chips"
-	depends on ARCH_OMAP && DMA_OMAP
-	select SND_SOC_DMAENGINE_PCM
+	depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST)
+	select SND_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
 	tristate
@@ -26,7 +26,7 @@
 
 config SND_OMAP_SOC_RX51
 	tristate "SoC Audio support for Nokia RX-51"
-	depends on SND_OMAP_SOC && MACH_NOKIA_RX51
+	depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TLV320AIC3X
 	select SND_SOC_TPA6130A2
@@ -87,7 +87,7 @@
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
 	tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-	depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4
+	depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
 	select SND_OMAP_SOC_DMIC
 	select SND_OMAP_SOC_MCPDM
 	select SND_SOC_TWL6040
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 361e4c0..83433fd 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -781,7 +781,7 @@
 	unsigned long val;						\
 	int status;							\
 									\
-	status = strict_strtoul(buf, 0, &val);				\
+	status = kstrtoul(buf, 0, &val);				\
 	if (status)							\
 		return status;						\
 									\
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 70cd5c7..ebb1390 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/twl6040.h>
-#include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/module.h>
 #include <linux/of.h>
 
@@ -166,19 +165,10 @@
 	{"AFMR", NULL, "Line In"},
 };
 
-static inline void twl6040_disconnect_pin(struct snd_soc_dapm_context *dapm,
-					  int connected, char *pin)
-{
-	if (!connected)
-		snd_soc_dapm_disable_pin(dapm, pin);
-}
-
 static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_card *card = codec->card;
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-	struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
 	struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
 	int hs_trim;
 	int ret = 0;
@@ -203,24 +193,6 @@
 		twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
 	}
 
-	/*
-	 * NULL pdata means we booted with DT. In this case the routing is
-	 * provided and the card is fully routed, no need to mark pins.
-	 */
-	if (!pdata)
-		return ret;
-
-	/* Disable not connected paths if not used */
-	twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-	twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
-	twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
-	twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
-	twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator");
-	twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-	twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
-	twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
-	twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
 	return ret;
 }
 
@@ -274,13 +246,18 @@
 
 static int omap_abe_probe(struct platform_device *pdev)
 {
-	struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
 	struct device_node *node = pdev->dev.of_node;
 	struct snd_soc_card *card = &omap_abe_card;
+	struct device_node *dai_node;
 	struct abe_twl6040 *priv;
 	int num_links = 0;
 	int ret = 0;
 
+	if (!node) {
+		dev_err(&pdev->dev, "of node is missing.\n");
+		return -ENODEV;
+	}
+
 	card->dev = &pdev->dev;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
@@ -289,78 +266,50 @@
 
 	priv->dmic_codec_dev = ERR_PTR(-EINVAL);
 
-	if (node) {
-		struct device_node *dai_node;
-
-		if (snd_soc_of_parse_card_name(card, "ti,model")) {
-			dev_err(&pdev->dev, "Card name is not provided\n");
-			return -ENODEV;
-		}
-
-		ret = snd_soc_of_parse_audio_routing(card,
-						"ti,audio-routing");
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Error while parsing DAPM routing\n");
-			return ret;
-		}
-
-		dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
-		if (!dai_node) {
-			dev_err(&pdev->dev, "McPDM node is not provided\n");
-			return -EINVAL;
-		}
-		abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
-		abe_twl6040_dai_links[0].cpu_of_node = dai_node;
-
-		dai_node = of_parse_phandle(node, "ti,dmic", 0);
-		if (dai_node) {
-			num_links = 2;
-			abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
-			abe_twl6040_dai_links[1].cpu_of_node = dai_node;
-
-			priv->dmic_codec_dev = platform_device_register_simple(
-						"dmic-codec", -1, NULL, 0);
-			if (IS_ERR(priv->dmic_codec_dev)) {
-				dev_err(&pdev->dev,
-					"Can't instantiate dmic-codec\n");
-				return PTR_ERR(priv->dmic_codec_dev);
-			}
-		} else {
-			num_links = 1;
-		}
-
-		priv->jack_detection = of_property_read_bool(node,
-							   "ti,jack-detection");
-		of_property_read_u32(node, "ti,mclk-freq",
-				     &priv->mclk_freq);
-		if (!priv->mclk_freq) {
-			dev_err(&pdev->dev, "MCLK frequency not provided\n");
-			ret = -EINVAL;
-			goto err_unregister;
-		}
-
-		omap_abe_card.fully_routed = 1;
-	} else if (pdata) {
-		if (pdata->card_name) {
-			card->name = pdata->card_name;
-		} else {
-			dev_err(&pdev->dev, "Card name is not provided\n");
-			return -ENODEV;
-		}
-
-		if (pdata->has_dmic)
-			num_links = 2;
-		else
-			num_links = 1;
-
-		priv->jack_detection = pdata->jack_detection;
-		priv->mclk_freq = pdata->mclk_freq;
-	} else {
-		dev_err(&pdev->dev, "Missing pdata\n");
+	if (snd_soc_of_parse_card_name(card, "ti,model")) {
+		dev_err(&pdev->dev, "Card name is not provided\n");
 		return -ENODEV;
 	}
 
+	ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
+		return ret;
+	}
+
+	dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+	if (!dai_node) {
+		dev_err(&pdev->dev, "McPDM node is not provided\n");
+		return -EINVAL;
+	}
+	abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
+	abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+
+	dai_node = of_parse_phandle(node, "ti,dmic", 0);
+	if (dai_node) {
+		num_links = 2;
+		abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
+		abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+
+		priv->dmic_codec_dev = platform_device_register_simple(
+						"dmic-codec", -1, NULL, 0);
+		if (IS_ERR(priv->dmic_codec_dev)) {
+			dev_err(&pdev->dev, "Can't instantiate dmic-codec\n");
+			return PTR_ERR(priv->dmic_codec_dev);
+		}
+	} else {
+		num_links = 1;
+	}
+
+	priv->jack_detection = of_property_read_bool(node, "ti,jack-detection");
+	of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
+	if (!priv->mclk_freq) {
+		dev_err(&pdev->dev, "MCLK frequency not provided\n");
+		ret = -EINVAL;
+		goto err_unregister;
+	}
+
+	card->fully_routed = 1;
 
 	if (!priv->mclk_freq) {
 		dev_err(&pdev->dev, "MCLK frequency missing\n");
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 4db1f8e..12e566b 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -480,15 +480,12 @@
 	dmic->dma_data.filter_data = "up_link";
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-	if (!res) {
-		dev_err(dmic->dev, "invalid memory resource\n");
-		ret = -ENODEV;
+	dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dmic->io_base)) {
+		ret = PTR_ERR(dmic->io_base);
 		goto err_put_clk;
 	}
 
-	dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(dmic->io_base))
-		return PTR_ERR(dmic->io_base);
 
 	ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
 					 &omap_dmic_dai, 1);
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 7483efb..6c19bba 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -433,6 +433,11 @@
 		/* Sample rate generator drives the FS */
 		regs->srgr2	|= FSGM;
 		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		/* McBSP slave. FS clock as output */
+		regs->srgr2	|= FSGM;
+		regs->pcr0	|= FSXM;
+		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 		/* McBSP slave */
 		break;
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index a49dc52..90d2a7c 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -480,9 +480,6 @@
 	mcpdm->dma_data[1].filter_data = "up_link";
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-	if (res == NULL)
-		return -ENOMEM;
-
 	mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(mcpdm->io_base))
 		return PTR_ERR(mcpdm->io_base);
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index b358094..4db74a0 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -11,7 +11,7 @@
 config SND_MMP_SOC
 	bool "Soc Audio for Marvell MMP chips"
 	depends on ARCH_MMP
-	select SND_SOC_DMAENGINE_PCM
+	select SND_DMAENGINE_PCM
 	select SND_ARM
 	help
 	  Say Y if you want to add support for codecs attached to
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 4ad7609..5b7d969 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -129,6 +129,7 @@
 /* audio machine driver */
 static struct snd_soc_card brownstone = {
 	.name         = "brownstone",
+	.owner        = THIS_MODULE,
 	.dai_link     = brownstone_wm8994_dai,
 	.num_links    = ARRAY_SIZE(brownstone_wm8994_dai),
 
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 97b711e..bbea778 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -56,8 +56,6 @@
 #include "pxa2xx-ac97.h"
 #include "../codecs/wm9713.h"
 
-#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
-
 #define AC97_GPIO_PULL		0x58
 
 /* Use GPIO8 for rear speaker amplifier */
@@ -133,10 +131,11 @@
 	unsigned short reg;
 
 	/* Add mioa701 specific widgets */
-	snd_soc_dapm_new_controls(dapm, ARRAY_AND_SIZE(mioa701_dapm_widgets));
+	snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets,
+				  ARRAY_SIZE(mioa701_dapm_widgets));
 
 	/* Set up mioa701 specific audio path audio_mapnects */
-	snd_soc_dapm_add_routes(dapm, ARRAY_AND_SIZE(audio_map));
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
 	/* Prepare GPIO8 for rear speaker amplifier */
 	reg = codec->driver->read(codec, AC97_GPIO_CFG);
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 5d57e07..8235e23 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -17,6 +17,7 @@
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-mmp_tdma.h>
 #include <linux/platform_data/mmp_audio.h>
+
 #include <sound/pxa2xx-lib.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -67,7 +68,7 @@
 {
 	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct pxa2xx_pcm_dma_params *dma_params;
+	struct snd_dmaengine_dai_dma_data *dma_params;
 	struct dma_slave_config slave_config;
 	int ret;
 
@@ -80,10 +81,10 @@
 		return ret;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		slave_config.dst_addr     = dma_params->dev_addr;
+		slave_config.dst_addr     = dma_params->addr;
 		slave_config.dst_maxburst = 4;
 	} else {
-		slave_config.src_addr	  = dma_params->dev_addr;
+		slave_config.src_addr	  = dma_params->addr;
 		slave_config.src_maxburst = 4;
 	}
 
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 62142ce..41752a5 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -27,12 +27,15 @@
 #include <linux/slab.h>
 #include <linux/pxa2xx_ssp.h>
 #include <linux/io.h>
+#include <linux/dmaengine.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 #include "mmp-sspa.h"
 
 /*
@@ -40,7 +43,7 @@
  */
 struct sspa_priv {
 	struct ssp_device *sspa;
-	struct pxa2xx_pcm_dma_params *dma_params;
+	struct snd_dmaengine_dai_dma_data *dma_params;
 	struct clk *audio_clk;
 	struct clk *sysclk;
 	int dai_fmt;
@@ -266,7 +269,7 @@
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
 	struct ssp_device *sspa = sspa_priv->sspa;
-	struct pxa2xx_pcm_dma_params *dma_params;
+	struct snd_dmaengine_dai_dma_data *dma_params;
 	u32 sspa_ctrl;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -309,7 +312,7 @@
 	}
 
 	dma_params = &sspa_priv->dma_params[substream->stream];
-	dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+	dma_params->addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
 				(sspa->phys_base + SSPA_TXD) :
 				(sspa->phys_base + SSPA_RXD);
 	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params);
@@ -425,14 +428,12 @@
 		return -ENOMEM;
 
 	priv->dma_params = devm_kzalloc(&pdev->dev,
-			2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL);
+			2 * sizeof(struct snd_dmaengine_dai_dma_data),
+			GFP_KERNEL);
 	if (priv->dma_params == NULL)
 		return -ENOMEM;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (res == NULL)
-		return -ENOMEM;
-
 	priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(priv->sspa->mmio_base))
 		return PTR_ERR(priv->sspa->mmio_base);
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 6f4dd75..a3119a0 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -21,6 +21,8 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/pxa2xx_ssp.h>
+#include <linux/of.h>
+#include <linux/dmaengine.h>
 
 #include <asm/irq.h>
 
@@ -30,9 +32,9 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/hardware.h>
-#include <mach/dma.h>
 
 #include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
@@ -79,27 +81,13 @@
 	__raw_writel(sscr0, ssp->mmio_base + SSCR0);
 }
 
-struct pxa2xx_pcm_dma_data {
-	struct pxa2xx_pcm_dma_params params;
-	char name[20];
-};
-
 static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
-			int out, struct pxa2xx_pcm_dma_params *dma_data)
+			int out, struct snd_dmaengine_dai_dma_data *dma)
 {
-	struct pxa2xx_pcm_dma_data *dma;
-
-	dma = container_of(dma_data, struct pxa2xx_pcm_dma_data, params);
-
-	snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
-			width4 ? "32-bit" : "16-bit", out ? "out" : "in");
-
-	dma->params.name = dma->name;
-	dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx);
-	dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) :
-				  (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
-			(width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
-	dma->params.dev_addr = ssp->phys_base + SSDR;
+	dma->addr_width = width4 ? DMA_SLAVE_BUSWIDTH_4_BYTES :
+				   DMA_SLAVE_BUSWIDTH_2_BYTES;
+	dma->maxburst = 16;
+	dma->addr = ssp->phys_base + SSDR;
 }
 
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
@@ -107,7 +95,7 @@
 {
 	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
 	struct ssp_device *ssp = priv->ssp;
-	struct pxa2xx_pcm_dma_data *dma;
+	struct snd_dmaengine_dai_dma_data *dma;
 	int ret = 0;
 
 	if (!cpu_dai->active) {
@@ -115,10 +103,14 @@
 		pxa_ssp_disable(ssp);
 	}
 
-	dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+	dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
 	if (!dma)
 		return -ENOMEM;
-	snd_soc_dai_set_dma_data(cpu_dai, substream, &dma->params);
+
+	dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+				&ssp->drcmr_tx : &ssp->drcmr_rx;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma);
 
 	return ret;
 }
@@ -559,7 +551,7 @@
 	u32 sspsp;
 	int width = snd_pcm_format_physical_width(params_format(params));
 	int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
-	struct pxa2xx_pcm_dma_params *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 
 	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
@@ -719,6 +711,7 @@
 
 static int pxa_ssp_probe(struct snd_soc_dai *dai)
 {
+	struct device *dev = dai->dev;
 	struct ssp_priv *priv;
 	int ret;
 
@@ -726,10 +719,26 @@
 	if (!priv)
 		return -ENOMEM;
 
-	priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
-	if (priv->ssp == NULL) {
-		ret = -ENODEV;
-		goto err_priv;
+	if (dev->of_node) {
+		struct device_node *ssp_handle;
+
+		ssp_handle = of_parse_phandle(dev->of_node, "port", 0);
+		if (!ssp_handle) {
+			dev_err(dev, "unable to get 'port' phandle\n");
+			return -ENODEV;
+		}
+
+		priv->ssp = pxa_ssp_request_of(ssp_handle, "SoC audio");
+		if (priv->ssp == NULL) {
+			ret = -ENODEV;
+			goto err_priv;
+		}
+	} else {
+		priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
+		if (priv->ssp == NULL) {
+			ret = -ENODEV;
+			goto err_priv;
+		}
 	}
 
 	priv->dai_fmt = (unsigned int) -1;
@@ -798,6 +807,12 @@
 	.name		= "pxa-ssp",
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ssp_of_ids[] = {
+	{ .compatible = "mrvl,pxa-ssp-dai" },
+};
+#endif
+
 static int asoc_ssp_probe(struct platform_device *pdev)
 {
 	return snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
@@ -812,8 +827,9 @@
 
 static struct platform_driver asoc_ssp_driver = {
 	.driver = {
-			.name = "pxa-ssp-dai",
-			.owner = THIS_MODULE,
+		.name = "pxa-ssp-dai",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(pxa_ssp_of_ids),
 	},
 
 	.probe = asoc_ssp_probe,
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 1475515..f1059d9 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -14,15 +14,16 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/dmaengine.h>
 
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-ac97.h>
-#include <mach/dma.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-ac97.h"
@@ -48,44 +49,44 @@
 	.reset	= pxa2xx_ac97_cold_reset,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
-	.name			= "AC97 PCM Stereo out",
-	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMR(12),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_stereo_in_req = 12;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
+	.addr		= __PREG(PCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.maxburst	= 32,
+	.filter_data	= &pxa2xx_ac97_pcm_stereo_in_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = {
-	.name			= "AC97 PCM Stereo in",
-	.dev_addr		= __PREG(PCDR),
-	.drcmr			= &DRCMR(11),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_stereo_out_req = 11;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
+	.addr		= __PREG(PCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.maxburst	= 32,
+	.filter_data	= &pxa2xx_ac97_pcm_stereo_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = {
-	.name			= "AC97 Aux PCM (Slot 5) Mono out",
-	.dev_addr		= __PREG(MODR),
-	.drcmr			= &DRCMR(10),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST16 | DCMD_WIDTH2,
+static unsigned long pxa2xx_ac97_pcm_aux_mono_out_req = 10;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
+	.addr		= __PREG(MODR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_2_BYTES,
+	.maxburst	= 16,
+	.filter_data	= &pxa2xx_ac97_pcm_aux_mono_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = {
-	.name			= "AC97 Aux PCM (Slot 5) Mono in",
-	.dev_addr		= __PREG(MODR),
-	.drcmr			= &DRCMR(9),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH2,
+static unsigned long pxa2xx_ac97_pcm_aux_mono_in_req = 9;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
+	.addr		= __PREG(MODR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_2_BYTES,
+	.maxburst	= 16,
+	.filter_data	= &pxa2xx_ac97_pcm_aux_mono_in_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
-	.name			= "AC97 Mic PCM (Slot 6) Mono in",
-	.dev_addr		= __PREG(MCDR),
-	.drcmr			= &DRCMR(8),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST16 | DCMD_WIDTH2,
+static unsigned long pxa2xx_ac97_pcm_aux_mic_mono_req = 8;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
+	.addr		= __PREG(MCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_2_BYTES,
+	.maxburst	= 16,
+	.filter_data	= &pxa2xx_ac97_pcm_aux_mic_mono_req,
 };
 
 #ifdef CONFIG_PM
@@ -119,7 +120,7 @@
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *cpu_dai)
 {
-	struct pxa2xx_pcm_dma_params *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dma_data = &pxa2xx_ac97_pcm_stereo_out;
@@ -135,7 +136,7 @@
 				     struct snd_pcm_hw_params *params,
 				     struct snd_soc_dai *cpu_dai)
 {
-	struct pxa2xx_pcm_dma_params *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dma_data = &pxa2xx_ac97_pcm_aux_mono_out;
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index f7ca716..d5340a0 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -23,9 +23,9 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/hardware.h>
-#include <mach/dma.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-i2s.h"
@@ -82,20 +82,20 @@
 static struct clk *clk_i2s;
 static int clk_ena = 0;
 
-static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
-	.name			= "I2S PCM Stereo out",
-	.dev_addr		= __PREG(SADR),
-	.drcmr			= &DRCMR(3),
-	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
-				  DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_i2s_pcm_stereo_out_req = 3;
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
+	.addr		= __PREG(SADR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.maxburst	= 32,
+	.filter_data	= &pxa2xx_i2s_pcm_stereo_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
-	.name			= "I2S PCM Stereo in",
-	.dev_addr		= __PREG(SADR),
-	.drcmr			= &DRCMR(2),
-	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
-				  DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_i2s_pcm_stereo_in_req = 2;
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
+	.addr		= __PREG(SADR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.maxburst	= 32,
+	.filter_data	= &pxa2xx_i2s_pcm_stereo_in_req,
 };
 
 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
@@ -163,7 +163,7 @@
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 {
-	struct pxa2xx_pcm_dma_params *dma_data;
+	struct snd_dmaengine_dai_dma_data *dma_data;
 
 	BUG_ON(IS_ERR(clk_i2s));
 	clk_prepare_enable(clk_i2s);
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index ecff116..806da27 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -12,10 +12,13 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "../../arm/pxa2xx-pcm.h"
 
@@ -25,7 +28,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct pxa2xx_runtime_data *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct pxa2xx_pcm_dma_params *dma;
+	struct snd_dmaengine_dai_dma_data *dma;
 	int ret;
 
 	dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -39,7 +42,7 @@
 	 * with different params */
 	if (prtd->params == NULL) {
 		prtd->params = dma;
-		ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+		ret = pxa_request_dma("name", DMA_PRIO_LOW,
 			      pxa2xx_pcm_dma_irq, substream);
 		if (ret < 0)
 			return ret;
@@ -47,7 +50,7 @@
 	} else if (prtd->params != dma) {
 		pxa_free_dma(prtd->dma_ch);
 		prtd->params = dma;
-		ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+		ret = pxa_request_dma("name", DMA_PRIO_LOW,
 			      pxa2xx_pcm_dma_irq, substream);
 		if (ret < 0)
 			return ret;
@@ -131,10 +134,18 @@
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id snd_soc_pxa_audio_match[] = {
+	{ .compatible   = "mrvl,pxa-pcm-audio" },
+	{ }
+};
+#endif
+
 static struct platform_driver pxa_pcm_driver = {
 	.driver = {
-			.name = "pxa-pcm-audio",
-			.owner = THIS_MODULE,
+		.name = "pxa-pcm-audio",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(snd_soc_pxa_audio_match),
 	},
 
 	.probe = pxa2xx_soc_platform_probe,
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c
index f4ea4f6..13c9ee0 100644
--- a/sound/soc/pxa/ttc-dkb.c
+++ b/sound/soc/pxa/ttc-dkb.c
@@ -122,6 +122,7 @@
 /* ttc/td audio machine driver */
 static struct snd_soc_card ttc_dkb_card = {
 	.name = "ttc-dkb-hifi",
+	.owner = THIS_MODULE,
 	.dai_link = ttc_pm860x_hifi_dai,
 	.num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai),
 
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c
index 58cfb1e..945e8ab 100644
--- a/sound/soc/s6000/s6105-ipcam.c
+++ b/sound/soc/s6000/s6105-ipcam.c
@@ -192,7 +192,7 @@
 	.num_links = 1,
 };
 
-static struct s6000_snd_platform_data __initdata s6105_snd_data = {
+static struct s6000_snd_platform_data s6105_snd_data __initdata = {
 	.wide		= 0,
 	.channel_in	= 0,
 	.channel_out	= 1,
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 2dd623f..2acf987 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -404,18 +404,13 @@
 		return -ENXIO;
 	}
 
-	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem_res) {
-		dev_err(&pdev->dev, "Unable to get register resource\n");
-		return -ENXIO;
-	}
-
 	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!irq_res) {
 		dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
 		return -ENXIO;
 	}
 
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res);
 	if (IS_ERR(s3c_ac97.regs))
 		return PTR_ERR(s3c_ac97.regs);
@@ -462,7 +457,7 @@
 	if (ret)
 		goto err5;
 
-	ret = asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
 		goto err6;
@@ -485,7 +480,7 @@
 {
 	struct resource *irq_res;
 
-	asoc_dma_platform_unregister(&pdev->dev);
+	samsung_asoc_dma_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
 	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 21b7926..9338d11 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -90,6 +90,13 @@
 	dma_info.period = prtd->dma_period;
 	dma_info.len = prtd->dma_period*limit;
 
+	if (dma_info.cap == DMA_CYCLIC) {
+		dma_info.buf = pos;
+		prtd->params->ops->prepare(prtd->params->ch, &dma_info);
+		prtd->dma_loaded += limit;
+		return;
+	}
+
 	while (prtd->dma_loaded < limit) {
 		pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
 
@@ -176,6 +183,10 @@
 		prtd->params->ch = prtd->params->ops->request(
 				prtd->params->channel, &req, rtd->cpu_dai->dev,
 				prtd->params->ch_name);
+		if (!prtd->params->ch) {
+			pr_err("Failed to allocate DMA channel\n");
+			return -ENXIO;
+		}
 		prtd->params->ops->config(prtd->params->ch, &config);
 	}
 
@@ -433,17 +444,17 @@
 	.pcm_free	= dma_free_dma_buffers,
 };
 
-int asoc_dma_platform_register(struct device *dev)
+int samsung_asoc_dma_platform_register(struct device *dev)
 {
 	return snd_soc_register_platform(dev, &samsung_asoc_platform);
 }
-EXPORT_SYMBOL_GPL(asoc_dma_platform_register);
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
 
-void asoc_dma_platform_unregister(struct device *dev)
+void samsung_asoc_dma_platform_unregister(struct device *dev)
 {
 	snd_soc_unregister_platform(dev);
 }
-EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister);
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
 
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index 189a7a6..0e86315 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -22,7 +22,7 @@
 	char *ch_name;
 };
 
-int asoc_dma_platform_register(struct device *dev);
-void asoc_dma_platform_unregister(struct device *dev);
+int samsung_asoc_dma_platform_register(struct device *dev);
+void samsung_asoc_dma_platform_unregister(struct device *dev);
 
 #endif
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h
index c0e6d9a..821a502 100644
--- a/sound/soc/samsung/i2s-regs.h
+++ b/sound/soc/samsung/i2s-regs.h
@@ -31,6 +31,10 @@
 #define I2SLVL1ADDR	0x34
 #define I2SLVL2ADDR	0x38
 #define I2SLVL3ADDR	0x3c
+#define I2SSTR1		0x40
+#define I2SVER		0x44
+#define I2SFIC2		0x48
+#define I2STDM		0x4c
 
 #define CON_RSTCLR		(1 << 31)
 #define CON_FRXOFSTATUS		(1 << 26)
@@ -95,24 +99,39 @@
 #define MOD_RXONLY		(1 << 8)
 #define MOD_TXRX		(2 << 8)
 #define MOD_MASK		(3 << 8)
-#define MOD_LR_LLOW		(0 << 7)
-#define MOD_LR_RLOW		(1 << 7)
-#define MOD_SDF_IIS		(0 << 5)
-#define MOD_SDF_MSB		(1 << 5)
-#define MOD_SDF_LSB		(2 << 5)
-#define MOD_SDF_MASK		(3 << 5)
-#define MOD_RCLK_256FS		(0 << 3)
-#define MOD_RCLK_512FS		(1 << 3)
-#define MOD_RCLK_384FS		(2 << 3)
-#define MOD_RCLK_768FS		(3 << 3)
-#define MOD_RCLK_MASK		(3 << 3)
-#define MOD_BCLK_32FS		(0 << 1)
-#define MOD_BCLK_48FS		(1 << 1)
-#define MOD_BCLK_16FS		(2 << 1)
-#define MOD_BCLK_24FS		(3 << 1)
-#define MOD_BCLK_MASK		(3 << 1)
+#define MOD_LRP_SHIFT		7
+#define MOD_LR_LLOW		0
+#define MOD_LR_RLOW		1
+#define MOD_SDF_SHIFT		5
+#define MOD_SDF_IIS		0
+#define MOD_SDF_MSB		1
+#define MOD_SDF_LSB		2
+#define MOD_SDF_MASK		3
+#define MOD_RCLK_SHIFT		3
+#define MOD_RCLK_256FS		0
+#define MOD_RCLK_512FS		1
+#define MOD_RCLK_384FS		2
+#define MOD_RCLK_768FS		3
+#define MOD_RCLK_MASK		3
+#define MOD_BCLK_SHIFT		1
+#define MOD_BCLK_32FS		0
+#define MOD_BCLK_48FS		1
+#define MOD_BCLK_16FS		2
+#define MOD_BCLK_24FS		3
+#define MOD_BCLK_MASK		3
 #define MOD_8BIT		(1 << 0)
 
+#define EXYNOS5420_MOD_LRP_SHIFT	15
+#define EXYNOS5420_MOD_SDF_SHIFT	6
+#define EXYNOS5420_MOD_RCLK_SHIFT	4
+#define EXYNOS5420_MOD_BCLK_SHIFT	0
+#define EXYNOS5420_MOD_BCLK_64FS	4
+#define EXYNOS5420_MOD_BCLK_96FS	5
+#define EXYNOS5420_MOD_BCLK_128FS	6
+#define EXYNOS5420_MOD_BCLK_192FS	7
+#define EXYNOS5420_MOD_BCLK_256FS	8
+#define EXYNOS5420_MOD_BCLK_MASK	0xf
+
 #define MOD_CDCLKCON		(1 << 12)
 
 #define PSR_PSREN		(1 << 15)
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 959c702..b302f3b 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -40,6 +40,7 @@
 
 struct samsung_i2s_dai_data {
 	int dai_type;
+	u32 quirks;
 };
 
 struct i2s_dai {
@@ -198,7 +199,13 @@
 /* Read RCLK of I2S (in multiples of LRCLK) */
 static inline unsigned get_rfs(struct i2s_dai *i2s)
 {
-	u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
+	u32 rfs;
+
+	if (i2s->quirks & QUIRK_SUPPORTS_TDM)
+		rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
+	else
+		rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
+	rfs &= MOD_RCLK_MASK;
 
 	switch (rfs) {
 	case 3:	return 768;
@@ -212,21 +219,26 @@
 static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
 {
 	u32 mod = readl(i2s->addr + I2SMOD);
+	int rfs_shift;
 
-	mod &= ~MOD_RCLK_MASK;
+	if (i2s->quirks & QUIRK_SUPPORTS_TDM)
+		rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
+	else
+		rfs_shift = MOD_RCLK_SHIFT;
+	mod &= ~(MOD_RCLK_MASK << rfs_shift);
 
 	switch (rfs) {
 	case 768:
-		mod |= MOD_RCLK_768FS;
+		mod |= (MOD_RCLK_768FS << rfs_shift);
 		break;
 	case 512:
-		mod |= MOD_RCLK_512FS;
+		mod |= (MOD_RCLK_512FS << rfs_shift);
 		break;
 	case 384:
-		mod |= MOD_RCLK_384FS;
+		mod |= (MOD_RCLK_384FS << rfs_shift);
 		break;
 	default:
-		mod |= MOD_RCLK_256FS;
+		mod |= (MOD_RCLK_256FS << rfs_shift);
 		break;
 	}
 
@@ -236,9 +248,22 @@
 /* Read Bit-Clock of I2S (in multiples of LRCLK) */
 static inline unsigned get_bfs(struct i2s_dai *i2s)
 {
-	u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
+	u32 bfs;
+
+	if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+		bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
+		bfs &= EXYNOS5420_MOD_BCLK_MASK;
+	} else {
+		bfs =  readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
+		bfs &= MOD_BCLK_MASK;
+	}
 
 	switch (bfs) {
+	case 8: return 256;
+	case 7: return 192;
+	case 6: return 128;
+	case 5: return 96;
+	case 4: return 64;
 	case 3: return 24;
 	case 2: return 16;
 	case 1:	return 48;
@@ -250,21 +275,50 @@
 static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
 {
 	u32 mod = readl(i2s->addr + I2SMOD);
+	int bfs_shift;
+	int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
 
-	mod &= ~MOD_BCLK_MASK;
+	if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+		bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
+		mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
+	} else {
+		bfs_shift = MOD_BCLK_SHIFT;
+		mod &= ~(MOD_BCLK_MASK << bfs_shift);
+	}
+
+	/* Non-TDM I2S controllers do not support BCLK > 48 * FS */
+	if (!tdm && bfs > 48) {
+		dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n");
+		return;
+	}
 
 	switch (bfs) {
 	case 48:
-		mod |= MOD_BCLK_48FS;
+		mod |= (MOD_BCLK_48FS << bfs_shift);
 		break;
 	case 32:
-		mod |= MOD_BCLK_32FS;
+		mod |= (MOD_BCLK_32FS << bfs_shift);
 		break;
 	case 24:
-		mod |= MOD_BCLK_24FS;
+		mod |= (MOD_BCLK_24FS << bfs_shift);
 		break;
 	case 16:
-		mod |= MOD_BCLK_16FS;
+		mod |= (MOD_BCLK_16FS << bfs_shift);
+		break;
+	case 64:
+		mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift);
+		break;
+	case 96:
+		mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift);
+		break;
+	case 128:
+		mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift);
+		break;
+	case 192:
+		mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift);
+		break;
+	case 256:
+		mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift);
 		break;
 	default:
 		dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
@@ -491,20 +545,32 @@
 {
 	struct i2s_dai *i2s = to_info(dai);
 	u32 mod = readl(i2s->addr + I2SMOD);
+	int lrp_shift, sdf_shift, sdf_mask, lrp_rlow;
 	u32 tmp = 0;
 
+	if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+		lrp_shift = EXYNOS5420_MOD_LRP_SHIFT;
+		sdf_shift = EXYNOS5420_MOD_SDF_SHIFT;
+	} else {
+		lrp_shift = MOD_LRP_SHIFT;
+		sdf_shift = MOD_SDF_SHIFT;
+	}
+
+	sdf_mask = MOD_SDF_MASK << sdf_shift;
+	lrp_rlow = MOD_LR_RLOW << lrp_shift;
+
 	/* Format is priority */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_RIGHT_J:
-		tmp |= MOD_LR_RLOW;
-		tmp |= MOD_SDF_MSB;
+		tmp |= lrp_rlow;
+		tmp |= (MOD_SDF_MSB << sdf_shift);
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
-		tmp |= MOD_LR_RLOW;
-		tmp |= MOD_SDF_LSB;
+		tmp |= lrp_rlow;
+		tmp |= (MOD_SDF_LSB << sdf_shift);
 		break;
 	case SND_SOC_DAIFMT_I2S:
-		tmp |= MOD_SDF_IIS;
+		tmp |= (MOD_SDF_IIS << sdf_shift);
 		break;
 	default:
 		dev_err(&i2s->pdev->dev, "Format not supported\n");
@@ -519,10 +585,10 @@
 	case SND_SOC_DAIFMT_NB_NF:
 		break;
 	case SND_SOC_DAIFMT_NB_IF:
-		if (tmp & MOD_LR_RLOW)
-			tmp &= ~MOD_LR_RLOW;
+		if (tmp & lrp_rlow)
+			tmp &= ~lrp_rlow;
 		else
-			tmp |= MOD_LR_RLOW;
+			tmp |= lrp_rlow;
 		break;
 	default:
 		dev_err(&i2s->pdev->dev, "Polarity not supported\n");
@@ -544,15 +610,18 @@
 		return -EINVAL;
 	}
 
+	/*
+	 * Don't change the I2S mode if any controller is active on this
+	 * channel.
+	 */
 	if (any_active(i2s) &&
-			((mod & (MOD_SDF_MASK | MOD_LR_RLOW
-				| MOD_SLAVE)) != tmp)) {
+		((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) {
 		dev_err(&i2s->pdev->dev,
 				"%s:%d Other DAI busy\n", __func__, __LINE__);
 		return -EAGAIN;
 	}
 
-	mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+	mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE);
 	mod |= tmp;
 	writel(mod, i2s->addr + I2SMOD);
 
@@ -1007,6 +1076,8 @@
 		if (IS_ERR(i2s->pdev))
 			return NULL;
 
+		i2s->pdev->dev.parent = &pdev->dev;
+
 		platform_set_drvdata(i2s->pdev, i2s);
 		ret = platform_device_add(i2s->pdev);
 		if (ret < 0)
@@ -1018,18 +1089,18 @@
 
 static const struct of_device_id exynos_i2s_match[];
 
-static inline int samsung_i2s_get_driver_data(struct platform_device *pdev)
+static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
+						struct platform_device *pdev)
 {
 #ifdef CONFIG_OF
-	struct samsung_i2s_dai_data *data;
 	if (pdev->dev.of_node) {
 		const struct of_device_id *match;
 		match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
-		data = (struct samsung_i2s_dai_data *) match->data;
-		return data->dai_type;
+		return match->data;
 	} else
 #endif
-		return platform_get_device_id(pdev)->driver_data;
+		return (struct samsung_i2s_dai_data *)
+				platform_get_device_id(pdev)->driver_data;
 }
 
 #ifdef CONFIG_PM_RUNTIME
@@ -1060,13 +1131,13 @@
 	struct resource *res;
 	u32 regs_base, quirks = 0, idma_addr = 0;
 	struct device_node *np = pdev->dev.of_node;
-	enum samsung_dai_type samsung_dai_type;
+	const struct samsung_i2s_dai_data *i2s_dai_data;
 	int ret = 0;
 
 	/* Call during Seconday interface registration */
-	samsung_dai_type = samsung_i2s_get_driver_data(pdev);
+	i2s_dai_data = samsung_i2s_get_driver_data(pdev);
 
-	if (samsung_dai_type == TYPE_SEC) {
+	if (i2s_dai_data->dai_type == TYPE_SEC) {
 		sec_dai = dev_get_drvdata(&pdev->dev);
 		if (!sec_dai) {
 			dev_err(&pdev->dev, "Unable to get drvdata\n");
@@ -1075,7 +1146,7 @@
 		snd_soc_register_component(&sec_dai->pdev->dev,
 					   &samsung_i2s_component,
 					   &sec_dai->i2s_dai_drv, 1);
-		asoc_dma_platform_register(&pdev->dev);
+		samsung_asoc_dma_platform_register(&pdev->dev);
 		return 0;
 	}
 
@@ -1115,15 +1186,7 @@
 			idma_addr = i2s_cfg->idma_addr;
 		}
 	} else {
-		if (of_find_property(np, "samsung,supports-6ch", NULL))
-			quirks |= QUIRK_PRI_6CHAN;
-
-		if (of_find_property(np, "samsung,supports-secdai", NULL))
-			quirks |= QUIRK_SEC_DAI;
-
-		if (of_find_property(np, "samsung,supports-rstclr", NULL))
-			quirks |= QUIRK_NEED_RSTCLR;
-
+		quirks = i2s_dai_data->quirks;
 		if (of_property_read_u32(np, "samsung,idma-addr",
 					 &idma_addr)) {
 			if (quirks & QUIRK_SEC_DAI) {
@@ -1200,7 +1263,7 @@
 
 	pm_runtime_enable(&pdev->dev);
 
-	asoc_dma_platform_register(&pdev->dev);
+	samsung_asoc_dma_platform_register(&pdev->dev);
 
 	return 0;
 err:
@@ -1230,33 +1293,59 @@
 	i2s->pri_dai = NULL;
 	i2s->sec_dai = NULL;
 
-	asoc_dma_platform_unregister(&pdev->dev);
+	samsung_asoc_dma_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
 	return 0;
 }
 
+static const struct samsung_i2s_dai_data i2sv3_dai_type = {
+	.dai_type = TYPE_PRI,
+	.quirks = QUIRK_NO_MUXPSR,
+};
+
+static const struct samsung_i2s_dai_data i2sv5_dai_type = {
+	.dai_type = TYPE_PRI,
+	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
+};
+
+static const struct samsung_i2s_dai_data i2sv6_dai_type = {
+	.dai_type = TYPE_PRI,
+	.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
+			QUIRK_SUPPORTS_TDM,
+};
+
+static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
+	.dai_type = TYPE_PRI,
+};
+
+static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
+	.dai_type = TYPE_SEC,
+};
+
 static struct platform_device_id samsung_i2s_driver_ids[] = {
 	{
 		.name           = "samsung-i2s",
-		.driver_data	= TYPE_PRI,
+		.driver_data    = (kernel_ulong_t)&samsung_dai_type_pri,
 	}, {
 		.name           = "samsung-i2s-sec",
-		.driver_data	= TYPE_SEC,
+		.driver_data    = (kernel_ulong_t)&samsung_dai_type_sec,
 	},
 	{},
 };
 MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
 
 #ifdef CONFIG_OF
-static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
-	[TYPE_PRI] = { TYPE_PRI },
-	[TYPE_SEC] = { TYPE_SEC },
-};
-
 static const struct of_device_id exynos_i2s_match[] = {
-	{ .compatible = "samsung,i2s-v5",
-	  .data = &samsung_i2s_dai_data_array[TYPE_PRI],
+	{
+		.compatible = "samsung,s3c6410-i2s",
+		.data = &i2sv3_dai_type,
+	}, {
+		.compatible = "samsung,s5pv210-i2s",
+		.data = &i2sv5_dai_type,
+	}, {
+		.compatible = "samsung,exynos5420-i2s",
+		.data = &i2sv6_dai_type,
 	},
 	{},
 };
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index 1566afe..e54256f 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -594,7 +594,7 @@
 		goto err5;
 	}
 
-	ret = asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
 		goto err6;
@@ -623,7 +623,7 @@
 	struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
 	struct resource *mem_res;
 
-	asoc_dma_platform_unregister(&pdev->dev);
+	samsung_asoc_dma_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
 	pm_runtime_disable(&pdev->dev);
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index 47e2386..ea885cb 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -176,7 +176,7 @@
 		return ret;
 	}
 
-	ret = asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev);
 	if (ret) {
 		pr_err("failed to register the DMA: %d\n", ret);
 		goto err;
@@ -190,7 +190,7 @@
 
 static int s3c2412_iis_dev_remove(struct platform_device *pdev)
 {
-	asoc_dma_platform_unregister(&pdev->dev);
+	samsung_asoc_dma_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 8b34145..9c8ebd8 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -480,7 +480,7 @@
 		return ret;
 	}
 
-	ret = asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev);
 	if (ret) {
 		pr_err("failed to register the dma: %d\n", ret);
 		goto err;
@@ -494,7 +494,7 @@
 
 static int s3c24xx_iis_dev_remove(struct platform_device *pdev)
 {
-	asoc_dma_platform_unregister(&pdev->dev);
+	samsung_asoc_dma_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 	return 0;
 }
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 581ea4a..5fd7a05 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -11,6 +11,7 @@
 #include <sound/pcm_params.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
  /*
   * Default CFG switch settings to use this driver:
@@ -37,11 +38,19 @@
 /* SMDK has a 16.934MHZ crystal attached to WM8994 */
 #define SMDK_WM8994_FREQ 16934000
 
+struct smdk_wm8994_data {
+	int mclk1_rate;
+};
+
+/* Default SMDKs */
+static struct smdk_wm8994_data smdk_board_data = {
+	.mclk1_rate = SMDK_WM8994_FREQ,
+};
+
 static int smdk_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	unsigned int pll_out;
 	int ret;
@@ -54,18 +63,6 @@
 	else
 		pll_out = params_rate(params) * 256;
 
-	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-					 | SND_SOC_DAIFMT_NB_NF
-					 | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
-	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-					 | SND_SOC_DAIFMT_NB_NF
-					 | SND_SOC_DAIFMT_CBM_CFM);
-	if (ret < 0)
-		return ret;
-
 	ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
 					SMDK_WM8994_FREQ, pll_out);
 	if (ret < 0)
@@ -131,6 +128,8 @@
 		.platform_name = "samsung-i2s.0",
 		.codec_name = "wm8994-codec",
 		.init = smdk_wm8994_init_paiftx,
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM,
 		.ops = &smdk_ops,
 	}, { /* Sec_Fifo Playback i/f */
 		.name = "Sec_FIFO TX",
@@ -139,6 +138,8 @@
 		.codec_dai_name = "wm8994-aif1",
 		.platform_name = "samsung-i2s-sec",
 		.codec_name = "wm8994-codec",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM,
 		.ops = &smdk_ops,
 	},
 };
@@ -150,15 +151,28 @@
 	.num_links = ARRAY_SIZE(smdk_dai),
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_wm8994_of_match[] = {
+	{ .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
+	{},
+};
+MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
+#endif /* CONFIG_OF */
 
 static int smdk_audio_probe(struct platform_device *pdev)
 {
 	int ret;
 	struct device_node *np = pdev->dev.of_node;
 	struct snd_soc_card *card = &smdk;
+	struct smdk_wm8994_data *board;
+	const struct of_device_id *id;
 
 	card->dev = &pdev->dev;
 
+	board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
+	if (!board)
+		return -ENOMEM;
+
 	if (np) {
 		smdk_dai[0].cpu_dai_name = NULL;
 		smdk_dai[0].cpu_of_node = of_parse_phandle(np,
@@ -173,6 +187,12 @@
 		smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node;
 	}
 
+	id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
+	if (id)
+		*board = *((struct smdk_wm8994_data *)id->data);
+
+	platform_set_drvdata(pdev, board);
+
 	ret = snd_soc_register_card(card);
 
 	if (ret)
@@ -190,17 +210,9 @@
 	return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id samsung_wm8994_of_match[] = {
-	{ .compatible = "samsung,smdk-wm8994", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
-#endif /* CONFIG_OF */
-
 static struct platform_driver smdk_audio_driver = {
 	.driver		= {
-		.name	= "smdk-audio",
+		.name	= "smdk-audio-wm8894",
 		.owner	= THIS_MODULE,
 		.of_match_table = of_match_ptr(samsung_wm8994_of_match),
 	},
@@ -212,4 +224,4 @@
 
 MODULE_DESCRIPTION("ALSA SoC SMDK WM8994");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:smdk-audio");
+MODULE_ALIAS("platform:smdk-audio-wm8994");
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 2e5ebb2..28487dc 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -395,7 +395,7 @@
 
 	spin_lock_init(&spdif->lock);
 
-	spdif->pclk = clk_get(&pdev->dev, "spdif");
+	spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
 	if (IS_ERR(spdif->pclk)) {
 		dev_err(&pdev->dev, "failed to get peri-clock\n");
 		ret = -ENOENT;
@@ -403,7 +403,7 @@
 	}
 	clk_prepare_enable(spdif->pclk);
 
-	spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+	spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
 	if (IS_ERR(spdif->sclk)) {
 		dev_err(&pdev->dev, "failed to get internal source clock\n");
 		ret = -ENOENT;
@@ -442,7 +442,7 @@
 
 	spdif->dma_playback = &spdif_stereo_out;
 
-	ret = asoc_dma_platform_register(&pdev->dev);
+	ret = samsung_asoc_dma_platform_register(&pdev->dev);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
 		goto err5;
@@ -457,10 +457,8 @@
 	release_mem_region(mem_res->start, resource_size(mem_res));
 err2:
 	clk_disable_unprepare(spdif->sclk);
-	clk_put(spdif->sclk);
 err1:
 	clk_disable_unprepare(spdif->pclk);
-	clk_put(spdif->pclk);
 err0:
 	return ret;
 }
@@ -470,7 +468,7 @@
 	struct samsung_spdif_info *spdif = &spdif_info;
 	struct resource *mem_res;
 
-	asoc_dma_platform_unregister(&pdev->dev);
+	samsung_asoc_dma_platform_unregister(&pdev->dev);
 	snd_soc_unregister_component(&pdev->dev);
 
 	iounmap(spdif->regs);
@@ -480,9 +478,7 @@
 		release_mem_region(mem_res->start, resource_size(mem_res));
 
 	clk_disable_unprepare(spdif->sclk);
-	clk_put(spdif->sclk);
 	clk_disable_unprepare(spdif->pclk);
-	clk_put(spdif->pclk);
 
 	return 0;
 }
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 6bcb116..56d8ff6 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -34,6 +34,13 @@
 	select SH_DMAE
 	select FW_LOADER
 
+config SND_SOC_RCAR
+	tristate "R-Car series SRU/SCU/SSIU/SSI support"
+	select SND_SIMPLE_CARD
+	select RCAR_CLK_ADG
+	help
+	  This option enables R-Car SUR/SCU/SSIU/SSI sound support
+
 ##
 ## Boards
 ##
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index 849b387..aaf3dcd 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -12,6 +12,9 @@
 obj-$(CONFIG_SND_SOC_SH4_FSI)	+= snd-soc-fsi.o
 obj-$(CONFIG_SND_SOC_SH4_SIU)	+= snd-soc-siu.o
 
+## audio units for R-Car
+obj-$(CONFIG_SND_SOC_RCAR)	+= rcar/
+
 ## boards
 snd-soc-sh7760-ac97-objs	:= sh7760-ac97.o
 snd-soc-migor-objs		:= migor.o
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 3039026..b33ca7c 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -235,6 +235,8 @@
 	struct sh_dmae_slave	slave; /* see fsi_handler_init() */
 	struct work_struct	work;
 	dma_addr_t		dma;
+	int			loop_cnt;
+	int			additional_pos;
 };
 
 struct fsi_clk {
@@ -1289,6 +1291,8 @@
 	io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
 			 BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
 
+	io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */
+	io->additional_pos = 0;
 	io->dma = dma_map_single(dai->dev, runtime->dma_area,
 				 snd_pcm_lib_buffer_bytes(io->substream), dir);
 	return 0;
@@ -1305,11 +1309,15 @@
 	return 0;
 }
 
-static dma_addr_t fsi_dma_get_area(struct fsi_stream *io)
+static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional)
 {
 	struct snd_pcm_runtime *runtime = io->substream->runtime;
+	int period = io->period_pos + additional;
 
-	return io->dma + samples_to_bytes(runtime, io->buff_sample_pos);
+	if (period >= runtime->periods)
+		period = 0;
+
+	return io->dma + samples_to_bytes(runtime, period * io->period_samples);
 }
 
 static void fsi_dma_complete(void *data)
@@ -1321,7 +1329,7 @@
 	enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
 		DMA_TO_DEVICE : DMA_FROM_DEVICE;
 
-	dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io),
+	dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0),
 			samples_to_bytes(runtime, io->period_samples), dir);
 
 	io->buff_sample_pos += io->period_samples;
@@ -1347,7 +1355,7 @@
 	struct snd_pcm_runtime *runtime;
 	enum dma_data_direction dir;
 	int is_play = fsi_stream_is_play(fsi, io);
-	int len;
+	int len, i;
 	dma_addr_t buf;
 
 	if (!fsi_stream_is_working(fsi, io))
@@ -1357,26 +1365,33 @@
 	runtime	= io->substream->runtime;
 	dir	= is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
 	len	= samples_to_bytes(runtime, io->period_samples);
-	buf	= fsi_dma_get_area(io);
 
-	dma_sync_single_for_device(dai->dev, buf, len, dir);
+	for (i = 0; i < io->loop_cnt; i++) {
+		buf	= fsi_dma_get_area(io, io->additional_pos);
 
-	desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
-					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-	if (!desc) {
-		dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
-		return;
+		dma_sync_single_for_device(dai->dev, buf, len, dir);
+
+		desc = dmaengine_prep_slave_single(io->chan, buf, len, dir,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n");
+			return;
+		}
+
+		desc->callback		= fsi_dma_complete;
+		desc->callback_param	= io;
+
+		if (dmaengine_submit(desc) < 0) {
+			dev_err(dai->dev, "tx_submit() fail\n");
+			return;
+		}
+
+		dma_async_issue_pending(io->chan);
+
+		io->additional_pos = 1;
 	}
 
-	desc->callback		= fsi_dma_complete;
-	desc->callback_param	= io;
-
-	if (dmaengine_submit(desc) < 0) {
-		dev_err(dai->dev, "tx_submit() fail\n");
-		return;
-	}
-
-	dma_async_issue_pending(io->chan);
+	io->loop_cnt = 1;
 
 	/*
 	 * FIXME
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
new file mode 100644
index 0000000..0ff492d
--- /dev/null
+++ b/sound/soc/sh/rcar/Makefile
@@ -0,0 +1,2 @@
+snd-soc-rcar-objs	:= core.o gen.o scu.o adg.o ssi.o
+obj-$(CONFIG_SND_SOC_RCAR)	+= snd-soc-rcar.o
\ No newline at end of file
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
new file mode 100644
index 0000000..d80deb7
--- /dev/null
+++ b/sound/soc/sh/rcar/adg.c
@@ -0,0 +1,234 @@
+/*
+ * Helper routines for R-Car sound ADG.
+ *
+ *  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sh_clk.h>
+#include <mach/clock.h>
+#include "rsnd.h"
+
+#define CLKA	0
+#define CLKB	1
+#define CLKC	2
+#define CLKI	3
+#define CLKMAX	4
+
+struct rsnd_adg {
+	struct clk *clk[CLKMAX];
+
+	int rate_of_441khz_div_6;
+	int rate_of_48khz_div_6;
+};
+
+#define for_each_rsnd_clk(pos, adg, i)		\
+	for (i = 0, (pos) = adg->clk[i];	\
+	     i < CLKMAX;			\
+	     i++, (pos) = adg->clk[i])
+#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
+
+static enum rsnd_reg rsnd_adg_ssi_reg_get(int id)
+{
+	enum rsnd_reg reg;
+
+	/*
+	 * SSI 8 is not connected to ADG.
+	 * it works with SSI 7
+	 */
+	if (id == 8)
+		return RSND_REG_MAX;
+
+	if (0 <= id && id <= 3)
+		reg = RSND_REG_AUDIO_CLK_SEL0;
+	else if (4 <= id && id <= 7)
+		reg = RSND_REG_AUDIO_CLK_SEL1;
+	else
+		reg = RSND_REG_AUDIO_CLK_SEL2;
+
+	return reg;
+}
+
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	enum rsnd_reg reg;
+	int id;
+
+	/*
+	 * "mod" = "ssi" here.
+	 * we can get "ssi id" from mod
+	 */
+	id  = rsnd_mod_id(mod);
+	reg = rsnd_adg_ssi_reg_get(id);
+
+	rsnd_write(priv, mod, reg, 0);
+
+	return 0;
+}
+
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct clk *clk;
+	enum rsnd_reg reg;
+	int id, shift, i;
+	u32 data;
+	int sel_table[] = {
+		[CLKA] = 0x1,
+		[CLKB] = 0x2,
+		[CLKC] = 0x3,
+		[CLKI] = 0x0,
+	};
+
+	dev_dbg(dev, "request clock = %d\n", rate);
+
+	/*
+	 * find suitable clock from
+	 * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
+	 */
+	data = 0;
+	for_each_rsnd_clk(clk, adg, i) {
+		if (rate == clk_get_rate(clk)) {
+			data = sel_table[i];
+			goto found_clock;
+		}
+	}
+
+	/*
+	 * find 1/6 clock from BRGA/BRGB
+	 */
+	if (rate == adg->rate_of_441khz_div_6) {
+		data = 0x10;
+		goto found_clock;
+	}
+
+	if (rate == adg->rate_of_48khz_div_6) {
+		data = 0x20;
+		goto found_clock;
+	}
+
+	return -EIO;
+
+found_clock:
+
+	/*
+	 * This "mod" = "ssi" here.
+	 * we can get "ssi id" from mod
+	 */
+	id  = rsnd_mod_id(mod);
+	reg = rsnd_adg_ssi_reg_get(id);
+
+	dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate);
+
+	/*
+	 * Enable SSIx clock
+	 */
+	shift = (id % 4) * 8;
+
+	rsnd_bset(priv, mod, reg,
+		   0xFF << shift,
+		   data << shift);
+
+	return 0;
+}
+
+static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
+{
+	struct clk *clk;
+	unsigned long rate;
+	u32 ckr;
+	int i;
+	int brg_table[] = {
+		[CLKA] = 0x0,
+		[CLKB] = 0x1,
+		[CLKC] = 0x4,
+		[CLKI] = 0x2,
+	};
+
+	/*
+	 * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
+	 * have 44.1kHz or 48kHz base clocks for now.
+	 *
+	 * SSI itself can divide parent clock by 1/1 - 1/16
+	 * So,  BRGA outputs 44.1kHz base parent clock 1/32,
+	 * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
+	 * see
+	 *	rsnd_adg_ssi_clk_try_start()
+	 */
+	ckr = 0;
+	adg->rate_of_441khz_div_6 = 0;
+	adg->rate_of_48khz_div_6  = 0;
+	for_each_rsnd_clk(clk, adg, i) {
+		rate = clk_get_rate(clk);
+
+		if (0 == rate) /* not used */
+			continue;
+
+		/* RBGA */
+		if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) {
+			adg->rate_of_441khz_div_6 = rate / 6;
+			ckr |= brg_table[i] << 20;
+		}
+
+		/* RBGB */
+		if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) {
+			adg->rate_of_48khz_div_6 = rate / 6;
+			ckr |= brg_table[i] << 16;
+		}
+	}
+
+	rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr);
+	rsnd_priv_write(priv, BRRA,  0x00000002); /* 1/6 */
+	rsnd_priv_write(priv, BRRB,  0x00000002); /* 1/6 */
+}
+
+int rsnd_adg_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv)
+{
+	struct rsnd_adg *adg;
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct clk *clk;
+	int i;
+
+	adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
+	if (!adg) {
+		dev_err(dev, "ADG allocate failed\n");
+		return -ENOMEM;
+	}
+
+	adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
+	adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
+	adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
+	adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
+	for_each_rsnd_clk(clk, adg, i) {
+		if (IS_ERR(clk)) {
+			dev_err(dev, "Audio clock failed\n");
+			return -EIO;
+		}
+	}
+
+	rsnd_adg_ssi_clk_init(priv, adg);
+
+	priv->adg = adg;
+
+	dev_dbg(dev, "adg probed\n");
+
+	return 0;
+}
+
+void rsnd_adg_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv)
+{
+	struct rsnd_adg *adg = priv->adg;
+	struct clk *clk;
+	int i;
+
+	for_each_rsnd_clk(clk, adg, i)
+		clk_put(clk);
+}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
new file mode 100644
index 0000000..a357060
--- /dev/null
+++ b/sound/soc/sh/rcar/core.c
@@ -0,0 +1,861 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on fsi.c
+ * Kuninori Morimoto <morimoto.kuninori@renesas.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.
+ */
+
+/*
+ * Renesas R-Car sound device structure
+ *
+ * Gen1
+ *
+ * SRU		: Sound Routing Unit
+ *  - SRC	: Sampling Rate Converter
+ *  - CMD
+ *    - CTU	: Channel Count Conversion Unit
+ *    - MIX	: Mixer
+ *    - DVC	: Digital Volume and Mute Function
+ *  - SSI	: Serial Sound Interface
+ *
+ * Gen2
+ *
+ * SCU		: Sampling Rate Converter Unit
+ *  - SRC	: Sampling Rate Converter
+ *  - CMD
+ *   - CTU	: Channel Count Conversion Unit
+ *   - MIX	: Mixer
+ *   - DVC	: Digital Volume and Mute Function
+ * SSIU		: Serial Sound Interface Unit
+ *  - SSI	: Serial Sound Interface
+ */
+
+/*
+ *	driver data Image
+ *
+ * rsnd_priv
+ *   |
+ *   | ** this depends on Gen1/Gen2
+ *   |
+ *   +- gen
+ *   |
+ *   | ** these depend on data path
+ *   | ** gen and platform data control it
+ *   |
+ *   +- rdai[0]
+ *   |   |		 sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |		 sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   |
+ *   +- rdai[1]
+ *   |   |		 sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |		 sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   ...
+ *   |
+ *   | ** these control ssi
+ *   |
+ *   +- ssi
+ *   |  |
+ *   |  +- ssi[0]
+ *   |  +- ssi[1]
+ *   |  +- ssi[2]
+ *   |  ...
+ *   |
+ *   | ** these control scu
+ *   |
+ *   +- scu
+ *      |
+ *      +- scu[0]
+ *      +- scu[1]
+ *      +- scu[2]
+ *      ...
+ *
+ *
+ * for_each_rsnd_dai(xx, priv, xx)
+ *  rdai[0] => rdai[1] => rdai[2] => ...
+ *
+ * for_each_rsnd_mod(xx, rdai, xx)
+ *  [mod] => [mod] => [mod] => ...
+ *
+ * rsnd_dai_call(xxx, fn )
+ *  [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
+ *
+ */
+#include <linux/pm_runtime.h>
+#include "rsnd.h"
+
+#define RSND_RATES SNDRV_PCM_RATE_8000_96000
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+
+/*
+ *	rsnd_platform functions
+ */
+#define rsnd_platform_call(priv, dai, func, param...)	\
+	(!(priv->info->func) ? -ENODEV :		\
+	 priv->info->func(param))
+
+
+/*
+ *	basic function
+ */
+u32 rsnd_read(struct rsnd_priv *priv,
+	      struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+
+	BUG_ON(!base);
+
+	return ioread32(base);
+}
+
+void rsnd_write(struct rsnd_priv *priv,
+		struct rsnd_mod *mod,
+		enum rsnd_reg reg, u32 data)
+{
+	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	BUG_ON(!base);
+
+	dev_dbg(dev, "w %p : %08x\n", base, data);
+
+	iowrite32(data, base);
+}
+
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
+	       enum rsnd_reg reg, u32 mask, u32 data)
+{
+	void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 val;
+
+	BUG_ON(!base);
+
+	val = ioread32(base);
+	val &= ~mask;
+	val |= data & mask;
+	iowrite32(val, base);
+
+	dev_dbg(dev, "s %p : %08x\n", base, val);
+}
+
+/*
+ *	rsnd_mod functions
+ */
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+	if (!mod || !mod->ops)
+		return "unknown";
+
+	return mod->ops->name;
+}
+
+void rsnd_mod_init(struct rsnd_priv *priv,
+		   struct rsnd_mod *mod,
+		   struct rsnd_mod_ops *ops,
+		   int id)
+{
+	mod->priv	= priv;
+	mod->id		= id;
+	mod->ops	= ops;
+	INIT_LIST_HEAD(&mod->list);
+}
+
+/*
+ *	rsnd_dma functions
+ */
+static void rsnd_dma_continue(struct rsnd_dma *dma)
+{
+	/* push next A or B plane */
+	dma->submit_loop = 1;
+	schedule_work(&dma->work);
+}
+
+void rsnd_dma_start(struct rsnd_dma *dma)
+{
+	/* push both A and B plane*/
+	dma->submit_loop = 2;
+	schedule_work(&dma->work);
+}
+
+void rsnd_dma_stop(struct rsnd_dma *dma)
+{
+	dma->submit_loop = 0;
+	cancel_work_sync(&dma->work);
+	dmaengine_terminate_all(dma->chan);
+}
+
+static void rsnd_dma_complete(void *data)
+{
+	struct rsnd_dma *dma = (struct rsnd_dma *)data;
+	struct rsnd_priv *priv = dma->priv;
+	unsigned long flags;
+
+	rsnd_lock(priv, flags);
+
+	dma->complete(dma);
+
+	if (dma->submit_loop)
+		rsnd_dma_continue(dma);
+
+	rsnd_unlock(priv, flags);
+}
+
+static void rsnd_dma_do_work(struct work_struct *work)
+{
+	struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
+	struct rsnd_priv *priv = dma->priv;
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct dma_async_tx_descriptor *desc;
+	dma_addr_t buf;
+	size_t len;
+	int i;
+
+	for (i = 0; i < dma->submit_loop; i++) {
+
+		if (dma->inquiry(dma, &buf, &len) < 0)
+			return;
+
+		desc = dmaengine_prep_slave_single(
+			dma->chan, buf, len, dma->dir,
+			DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
+			return;
+		}
+
+		desc->callback		= rsnd_dma_complete;
+		desc->callback_param	= dma;
+
+		if (dmaengine_submit(desc) < 0) {
+			dev_err(dev, "dmaengine_submit() fail\n");
+			return;
+		}
+
+	}
+
+	dma_async_issue_pending(dma->chan);
+}
+
+int rsnd_dma_available(struct rsnd_dma *dma)
+{
+	return !!dma->chan;
+}
+
+static bool rsnd_dma_filter(struct dma_chan *chan, void *param)
+{
+	chan->private = param;
+
+	return true;
+}
+
+int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
+		  int is_play, int id,
+		  int (*inquiry)(struct rsnd_dma *dma,
+				  dma_addr_t *buf, int *len),
+		  int (*complete)(struct rsnd_dma *dma))
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	dma_cap_mask_t mask;
+
+	if (dma->chan) {
+		dev_err(dev, "it already has dma channel\n");
+		return -EIO;
+	}
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	dma->slave.shdma_slave.slave_id = id;
+
+	dma->chan = dma_request_channel(mask, rsnd_dma_filter,
+					&dma->slave.shdma_slave);
+	if (!dma->chan) {
+		dev_err(dev, "can't get dma channel\n");
+		return -EIO;
+	}
+
+	dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+	dma->priv = priv;
+	dma->inquiry = inquiry;
+	dma->complete = complete;
+	INIT_WORK(&dma->work, rsnd_dma_do_work);
+
+	return 0;
+}
+
+void  rsnd_dma_quit(struct rsnd_priv *priv,
+		    struct rsnd_dma *dma)
+{
+	if (dma->chan)
+		dma_release_channel(dma->chan);
+
+	dma->chan = NULL;
+}
+
+/*
+ *	rsnd_dai functions
+ */
+#define rsnd_dai_call(rdai, io, fn)			\
+({							\
+	struct rsnd_mod *mod, *n;			\
+	int ret = 0;					\
+	for_each_rsnd_mod(mod, n, io) {			\
+		ret = rsnd_mod_call(mod, fn, rdai, io);	\
+		if (ret < 0)				\
+			break;				\
+	}						\
+	ret;						\
+})
+
+int rsnd_dai_connect(struct rsnd_dai *rdai,
+		     struct rsnd_mod *mod,
+		     struct rsnd_dai_stream *io)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	if (!mod) {
+		dev_err(dev, "NULL mod\n");
+		return -EIO;
+	}
+
+	if (!list_empty(&mod->list)) {
+		dev_err(dev, "%s%d is not empty\n",
+			rsnd_mod_name(mod),
+			rsnd_mod_id(mod));
+		return -EIO;
+	}
+
+	list_add_tail(&mod->list, &io->head);
+
+	return 0;
+}
+
+int rsnd_dai_disconnect(struct rsnd_mod *mod)
+{
+	list_del_init(&mod->list);
+
+	return 0;
+}
+
+int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
+{
+	int id = rdai - priv->rdai;
+
+	if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+		return -EINVAL;
+
+	return id;
+}
+
+struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
+{
+	return priv->rdai + id;
+}
+
+static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
+{
+	struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+	return rsnd_dai_get(priv, dai->id);
+}
+
+int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io)
+{
+	return &rdai->playback == io;
+}
+
+/*
+ *	rsnd_soc_dai functions
+ */
+int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
+{
+	struct snd_pcm_substream *substream = io->substream;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int pos = io->byte_pos + additional;
+
+	pos %= (runtime->periods * io->byte_per_period);
+
+	return pos;
+}
+
+void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
+{
+	io->byte_pos += byte;
+
+	if (io->byte_pos >= io->next_period_byte) {
+		struct snd_pcm_substream *substream = io->substream;
+		struct snd_pcm_runtime *runtime = substream->runtime;
+
+		io->period_pos++;
+		io->next_period_byte += io->byte_per_period;
+
+		if (io->period_pos >= runtime->periods) {
+			io->byte_pos = 0;
+			io->period_pos = 0;
+			io->next_period_byte = io->byte_per_period;
+		}
+
+		snd_pcm_period_elapsed(substream);
+	}
+}
+
+static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
+				struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	if (!list_empty(&io->head))
+		return -EIO;
+
+	INIT_LIST_HEAD(&io->head);
+	io->substream		= substream;
+	io->byte_pos		= 0;
+	io->period_pos		= 0;
+	io->byte_per_period	= runtime->period_size *
+				  runtime->channels *
+				  samples_to_bytes(runtime, 1);
+	io->next_period_byte	= io->byte_per_period;
+
+	return 0;
+}
+
+static
+struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	return  rtd->cpu_dai;
+}
+
+static
+struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
+					struct snd_pcm_substream *substream)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return &rdai->playback;
+	else
+		return &rdai->capture;
+}
+
+static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			    struct snd_soc_dai *dai)
+{
+	struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+	struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv,
+						rsnd_dai_id(priv, rdai),
+						rsnd_dai_is_play(rdai, io));
+	int ssi_id = rsnd_mod_id(mod);
+	int ret;
+	unsigned long flags;
+
+	rsnd_lock(priv, flags);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ret = rsnd_dai_stream_init(io, substream);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_platform_call(priv, dai, start, ssi_id);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_gen_path_init(priv, rdai, io);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_dai_call(rdai, io, init);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_dai_call(rdai, io, start);
+		if (ret < 0)
+			goto dai_trigger_end;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ret = rsnd_dai_call(rdai, io, stop);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_dai_call(rdai, io, quit);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_gen_path_exit(priv, rdai, io);
+		if (ret < 0)
+			goto dai_trigger_end;
+
+		ret = rsnd_platform_call(priv, dai, stop, ssi_id);
+		if (ret < 0)
+			goto dai_trigger_end;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+dai_trigger_end:
+	rsnd_unlock(priv, flags);
+
+	return ret;
+}
+
+static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		rdai->clk_master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		rdai->clk_master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_IF:
+		rdai->bit_clk_inv = 0;
+		rdai->frm_clk_inv = 1;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		rdai->bit_clk_inv = 1;
+		rdai->frm_clk_inv = 0;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		rdai->bit_clk_inv = 1;
+		rdai->frm_clk_inv = 1;
+		break;
+	case SND_SOC_DAIFMT_NB_NF:
+	default:
+		rdai->bit_clk_inv = 0;
+		rdai->frm_clk_inv = 0;
+		break;
+	}
+
+	/* set format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		rdai->sys_delay = 0;
+		rdai->data_alignment = 0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		rdai->sys_delay = 1;
+		rdai->data_alignment = 0;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		rdai->sys_delay = 1;
+		rdai->data_alignment = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+	.trigger	= rsnd_soc_dai_trigger,
+	.set_fmt	= rsnd_soc_dai_set_fmt,
+};
+
+static int rsnd_dai_probe(struct platform_device *pdev,
+			  struct rcar_snd_info *info,
+			  struct rsnd_priv *priv)
+{
+	struct snd_soc_dai_driver *drv;
+	struct rsnd_dai *rdai;
+	struct rsnd_mod *pmod, *cmod;
+	struct device *dev = rsnd_priv_to_dev(priv);
+	int dai_nr;
+	int i;
+
+	/* get max dai nr */
+	for (dai_nr = 0; dai_nr < 32; dai_nr++) {
+		pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
+		cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
+
+		if (!pmod && !cmod)
+			break;
+	}
+
+	if (!dai_nr) {
+		dev_err(dev, "no dai\n");
+		return -EIO;
+	}
+
+	drv  = devm_kzalloc(dev, sizeof(*drv)  * dai_nr, GFP_KERNEL);
+	rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
+	if (!drv || !rdai) {
+		dev_err(dev, "dai allocate failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dai_nr; i++) {
+
+		pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
+		cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
+
+		/*
+		 *	init rsnd_dai
+		 */
+		INIT_LIST_HEAD(&rdai[i].playback.head);
+		INIT_LIST_HEAD(&rdai[i].capture.head);
+
+		snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
+
+		/*
+		 *	init snd_soc_dai_driver
+		 */
+		drv[i].name	= rdai[i].name;
+		drv[i].ops	= &rsnd_soc_dai_ops;
+		if (pmod) {
+			drv[i].playback.rates		= RSND_RATES;
+			drv[i].playback.formats		= RSND_FMTS;
+			drv[i].playback.channels_min	= 2;
+			drv[i].playback.channels_max	= 2;
+		}
+		if (cmod) {
+			drv[i].capture.rates		= RSND_RATES;
+			drv[i].capture.formats		= RSND_FMTS;
+			drv[i].capture.channels_min	= 2;
+			drv[i].capture.channels_max	= 2;
+		}
+
+		dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
+			pmod ? "play"    : " -- ",
+			cmod ? "capture" : "  --   ");
+	}
+
+	priv->dai_nr	= dai_nr;
+	priv->daidrv	= drv;
+	priv->rdai	= rdai;
+
+	return 0;
+}
+
+static void rsnd_dai_remove(struct platform_device *pdev,
+			  struct rsnd_priv *priv)
+{
+}
+
+/*
+ *		pcm ops
+ */
+static struct snd_pcm_hardware rsnd_pcm_hardware = {
+	.info =		SNDRV_PCM_INFO_INTERLEAVED	|
+			SNDRV_PCM_INFO_MMAP		|
+			SNDRV_PCM_INFO_MMAP_VALID	|
+			SNDRV_PCM_INFO_PAUSE,
+	.formats		= RSND_FMTS,
+	.rates			= RSND_RATES,
+	.rate_min		= 8000,
+	.rate_max		= 192000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 64 * 1024,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192,
+	.periods_min		= 1,
+	.periods_max		= 32,
+	.fifo_size		= 256,
+};
+
+static int rsnd_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret = 0;
+
+	snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+
+	return ret;
+}
+
+static int rsnd_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+	struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+	struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+	return bytes_to_frames(runtime, io->byte_pos);
+}
+
+static struct snd_pcm_ops rsnd_pcm_ops = {
+	.open		= rsnd_pcm_open,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= rsnd_hw_params,
+	.hw_free	= snd_pcm_lib_free_pages,
+	.pointer	= rsnd_pointer,
+};
+
+/*
+ *		snd_soc_platform
+ */
+
+#define PREALLOC_BUFFER		(32 * 1024)
+#define PREALLOC_BUFFER_MAX	(32 * 1024)
+
+static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	return snd_pcm_lib_preallocate_pages_for_all(
+		rtd->pcm,
+		SNDRV_DMA_TYPE_DEV,
+		rtd->card->snd_card->dev,
+		PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+}
+
+static void rsnd_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static struct snd_soc_platform_driver rsnd_soc_platform = {
+	.ops		= &rsnd_pcm_ops,
+	.pcm_new	= rsnd_pcm_new,
+	.pcm_free	= rsnd_pcm_free,
+};
+
+static const struct snd_soc_component_driver rsnd_soc_component = {
+	.name		= "rsnd",
+};
+
+/*
+ *	rsnd probe
+ */
+static int rsnd_probe(struct platform_device *pdev)
+{
+	struct rcar_snd_info *info;
+	struct rsnd_priv *priv;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	info = pdev->dev.platform_data;
+	if (!info) {
+		dev_err(dev, "driver needs R-Car sound information\n");
+		return -ENODEV;
+	}
+
+	/*
+	 *	init priv data
+	 */
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(dev, "priv allocate failed\n");
+		return -ENODEV;
+	}
+
+	priv->dev	= dev;
+	priv->info	= info;
+	spin_lock_init(&priv->lock);
+
+	/*
+	 *	init each module
+	 */
+	ret = rsnd_gen_probe(pdev, info, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_scu_probe(pdev, info, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_adg_probe(pdev, info, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_ssi_probe(pdev, info, priv);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_dai_probe(pdev, info, priv);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 *	asoc register
+	 */
+	ret = snd_soc_register_platform(dev, &rsnd_soc_platform);
+	if (ret < 0) {
+		dev_err(dev, "cannot snd soc register\n");
+		return ret;
+	}
+
+	ret = snd_soc_register_component(dev, &rsnd_soc_component,
+					 priv->daidrv, rsnd_dai_nr(priv));
+	if (ret < 0) {
+		dev_err(dev, "cannot snd dai register\n");
+		goto exit_snd_soc;
+	}
+
+	dev_set_drvdata(dev, priv);
+
+	pm_runtime_enable(dev);
+
+	dev_info(dev, "probed\n");
+	return ret;
+
+exit_snd_soc:
+	snd_soc_unregister_platform(dev);
+
+	return ret;
+}
+
+static int rsnd_remove(struct platform_device *pdev)
+{
+	struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	pm_runtime_disable(&pdev->dev);
+
+	/*
+	 *	remove each module
+	 */
+	rsnd_ssi_remove(pdev, priv);
+	rsnd_adg_remove(pdev, priv);
+	rsnd_scu_remove(pdev, priv);
+	rsnd_dai_remove(pdev, priv);
+	rsnd_gen_remove(pdev, priv);
+
+	return 0;
+}
+
+static struct platform_driver rsnd_driver = {
+	.driver	= {
+		.name	= "rcar_sound",
+	},
+	.probe		= rsnd_probe,
+	.remove		= rsnd_remove,
+};
+module_platform_driver(rsnd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car audio driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
new file mode 100644
index 0000000..babb203
--- /dev/null
+++ b/sound/soc/sh/rcar/gen.c
@@ -0,0 +1,280 @@
+/*
+ * Renesas R-Car Gen1 SRU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+struct rsnd_gen_ops {
+	int (*path_init)(struct rsnd_priv *priv,
+			 struct rsnd_dai *rdai,
+			 struct rsnd_dai_stream *io);
+	int (*path_exit)(struct rsnd_priv *priv,
+			 struct rsnd_dai *rdai,
+			 struct rsnd_dai_stream *io);
+};
+
+struct rsnd_gen_reg_map {
+	int index;	/* -1 : not supported */
+	u32 offset_id;	/* offset of ssi0, ssi1, ssi2... */
+	u32 offset_adr;	/* offset of SSICR, SSISR, ... */
+};
+
+struct rsnd_gen {
+	void __iomem *base[RSND_BASE_MAX];
+
+	struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
+	struct rsnd_gen_ops *ops;
+};
+
+#define rsnd_priv_to_gen(p)	((struct rsnd_gen *)(p)->gen)
+
+/*
+ *		Gen2
+ *		will be filled in the future
+ */
+
+/*
+ *		Gen1
+ */
+static int rsnd_gen1_path_init(struct rsnd_priv *priv,
+			       struct rsnd_dai *rdai,
+			       struct rsnd_dai_stream *io)
+{
+	struct rsnd_mod *mod;
+	int ret;
+	int id;
+
+	/*
+	 * Gen1 is created by SRU/SSI, and this SRU is base module of
+	 * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
+	 *
+	 * Easy image is..
+	 *	Gen1 SRU = Gen2 SCU + SSIU + etc
+	 *
+	 * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
+	 * using fixed path.
+	 *
+	 * Then, SSI id = SCU id here
+	 */
+
+	/* get SSI's ID */
+	mod = rsnd_ssi_mod_get_frm_dai(priv,
+				       rsnd_dai_id(priv, rdai),
+				       rsnd_dai_is_play(rdai, io));
+	id = rsnd_mod_id(mod);
+
+	/* SSI */
+	mod = rsnd_ssi_mod_get(priv, id);
+	ret = rsnd_dai_connect(rdai, mod, io);
+	if (ret < 0)
+		return ret;
+
+	/* SCU */
+	mod = rsnd_scu_mod_get(priv, id);
+	ret = rsnd_dai_connect(rdai, mod, io);
+
+	return ret;
+}
+
+static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
+			       struct rsnd_dai *rdai,
+			       struct rsnd_dai_stream *io)
+{
+	struct rsnd_mod *mod, *n;
+	int ret = 0;
+
+	/*
+	 * remove all mod from rdai
+	 */
+	for_each_rsnd_mod(mod, n, io)
+		ret |= rsnd_dai_disconnect(mod);
+
+	return ret;
+}
+
+static struct rsnd_gen_ops rsnd_gen1_ops = {
+	.path_init	= rsnd_gen1_path_init,
+	.path_exit	= rsnd_gen1_path_exit,
+};
+
+#define RSND_GEN1_REG_MAP(g, s, i, oi, oa)				\
+	do {								\
+		(g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;	\
+		(g)->reg_map[RSND_REG_##i].offset_id = oi;		\
+		(g)->reg_map[RSND_REG_##i].offset_adr = oa;		\
+	} while (0)
+
+static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
+{
+	RSND_GEN1_REG_MAP(gen, SRU,	SRC_ROUTE_SEL,	0x0,	0x00);
+	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL0,	0x0,	0x08);
+	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL1,	0x0,	0x0c);
+	RSND_GEN1_REG_MAP(gen, SRU,	SRC_TMG_SEL2,	0x0,	0x10);
+	RSND_GEN1_REG_MAP(gen, SRU,	SRC_CTRL,	0x0,	0xc0);
+	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE0,	0x0,	0xD0);
+	RSND_GEN1_REG_MAP(gen, SRU,	SSI_MODE1,	0x0,	0xD4);
+	RSND_GEN1_REG_MAP(gen, SRU,	BUSIF_MODE,	0x4,	0x20);
+	RSND_GEN1_REG_MAP(gen, SRU,	BUSIF_ADINR,	0x40,	0x214);
+
+	RSND_GEN1_REG_MAP(gen, ADG,	BRRA,		0x0,	0x00);
+	RSND_GEN1_REG_MAP(gen, ADG,	BRRB,		0x0,	0x04);
+	RSND_GEN1_REG_MAP(gen, ADG,	SSICKR,		0x0,	0x08);
+	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL0,	0x0,	0x0c);
+	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL1,	0x0,	0x10);
+	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL3,	0x0,	0x18);
+	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL4,	0x0,	0x1c);
+	RSND_GEN1_REG_MAP(gen, ADG,	AUDIO_CLK_SEL5,	0x0,	0x20);
+
+	RSND_GEN1_REG_MAP(gen, SSI,	SSICR,		0x40,	0x00);
+	RSND_GEN1_REG_MAP(gen, SSI,	SSISR,		0x40,	0x04);
+	RSND_GEN1_REG_MAP(gen, SSI,	SSITDR,		0x40,	0x08);
+	RSND_GEN1_REG_MAP(gen, SSI,	SSIRDR,		0x40,	0x0c);
+	RSND_GEN1_REG_MAP(gen, SSI,	SSIWSR,		0x40,	0x20);
+}
+
+static int rsnd_gen1_probe(struct platform_device *pdev,
+			   struct rcar_snd_info *info,
+			   struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+	struct resource *sru_res;
+	struct resource *adg_res;
+	struct resource *ssi_res;
+
+	/*
+	 * map address
+	 */
+	sru_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
+	adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
+	ssi_res	= platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
+
+	gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
+	gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
+	gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
+	if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
+	    IS_ERR(gen->base[RSND_GEN1_ADG]) ||
+	    IS_ERR(gen->base[RSND_GEN1_SSI]))
+		return -ENODEV;
+
+	gen->ops = &rsnd_gen1_ops;
+	rsnd_gen1_reg_map_init(gen);
+
+	dev_dbg(dev, "Gen1 device probed\n");
+	dev_dbg(dev, "SRU : %08x => %p\n",	sru_res->start,
+						gen->base[RSND_GEN1_SRU]);
+	dev_dbg(dev, "ADG : %08x => %p\n",	adg_res->start,
+						gen->base[RSND_GEN1_ADG]);
+	dev_dbg(dev, "SSI : %08x => %p\n",	ssi_res->start,
+						gen->base[RSND_GEN1_SSI]);
+
+	return 0;
+
+}
+
+static void rsnd_gen1_remove(struct platform_device *pdev,
+			     struct rsnd_priv *priv)
+{
+}
+
+/*
+ *		Gen
+ */
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+	return gen->ops->path_init(priv, rdai, io);
+}
+
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+	return gen->ops->path_exit(priv, rdai, io);
+}
+
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+			       struct rsnd_mod *mod,
+			       enum rsnd_reg reg)
+{
+	struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	int index;
+	u32 offset_id, offset_adr;
+
+	if (reg >= RSND_REG_MAX) {
+		dev_err(dev, "rsnd_reg reg error\n");
+		return NULL;
+	}
+
+	index		= gen->reg_map[reg].index;
+	offset_id	= gen->reg_map[reg].offset_id;
+	offset_adr	= gen->reg_map[reg].offset_adr;
+
+	if (index < 0) {
+		dev_err(dev, "unsupported reg access %d\n", reg);
+		return NULL;
+	}
+
+	if (offset_id && mod)
+		offset_id *= rsnd_mod_id(mod);
+
+	/*
+	 * index/offset were set on gen1/gen2
+	 */
+
+	return gen->base[index] + offset_id + offset_adr;
+}
+
+int rsnd_gen_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_gen *gen;
+	int i;
+
+	gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
+	if (!gen) {
+		dev_err(dev, "GEN allocate failed\n");
+		return -ENOMEM;
+	}
+
+	priv->gen = gen;
+
+	/*
+	 * see
+	 *	rsnd_reg_get()
+	 *	rsnd_gen_probe()
+	 */
+	for (i = 0; i < RSND_REG_MAX; i++)
+		gen->reg_map[i].index = -1;
+
+	/*
+	 *	init each module
+	 */
+	if (rsnd_is_gen1(priv))
+		return rsnd_gen1_probe(pdev, info, priv);
+
+	dev_err(dev, "unknown generation R-Car sound device\n");
+
+	return -ENODEV;
+}
+
+void rsnd_gen_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv)
+{
+	if (rsnd_is_gen1(priv))
+		rsnd_gen1_remove(pdev, priv);
+}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
new file mode 100644
index 0000000..9cc6986
--- /dev/null
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -0,0 +1,302 @@
+/*
+ * Renesas R-Car
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef RSND_H
+#define RSND_H
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sh_dma.h>
+#include <linux/workqueue.h>
+#include <sound/rcar_snd.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+/*
+ *	pseudo register
+ *
+ * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different.
+ * This driver uses pseudo register in order to hide it.
+ * see gen1/gen2 for detail
+ */
+enum rsnd_reg {
+	/* SRU/SCU */
+	RSND_REG_SRC_ROUTE_SEL,
+	RSND_REG_SRC_TMG_SEL0,
+	RSND_REG_SRC_TMG_SEL1,
+	RSND_REG_SRC_TMG_SEL2,
+	RSND_REG_SRC_CTRL,
+	RSND_REG_SSI_MODE0,
+	RSND_REG_SSI_MODE1,
+	RSND_REG_BUSIF_MODE,
+	RSND_REG_BUSIF_ADINR,
+
+	/* ADG */
+	RSND_REG_BRRA,
+	RSND_REG_BRRB,
+	RSND_REG_SSICKR,
+	RSND_REG_AUDIO_CLK_SEL0,
+	RSND_REG_AUDIO_CLK_SEL1,
+	RSND_REG_AUDIO_CLK_SEL2,
+	RSND_REG_AUDIO_CLK_SEL3,
+	RSND_REG_AUDIO_CLK_SEL4,
+	RSND_REG_AUDIO_CLK_SEL5,
+
+	/* SSI */
+	RSND_REG_SSICR,
+	RSND_REG_SSISR,
+	RSND_REG_SSITDR,
+	RSND_REG_SSIRDR,
+	RSND_REG_SSIWSR,
+
+	RSND_REG_MAX,
+};
+
+struct rsnd_priv;
+struct rsnd_mod;
+struct rsnd_dai;
+struct rsnd_dai_stream;
+
+/*
+ *	R-Car basic functions
+ */
+#define rsnd_mod_read(m, r) \
+	rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
+#define rsnd_mod_write(m, r, d) \
+	rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
+#define rsnd_mod_bset(m, r, s, d) \
+	rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
+
+#define rsnd_priv_read(p, r)		rsnd_read(p, NULL, RSND_REG_##r)
+#define rsnd_priv_write(p, r, d)	rsnd_write(p, NULL, RSND_REG_##r, d)
+#define rsnd_priv_bset(p, r, s, d)	rsnd_bset(p, NULL, RSND_REG_##r, s, d)
+
+u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
+		enum rsnd_reg reg, u32 data);
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
+		    u32 mask, u32 data);
+
+/*
+ *	R-Car DMA
+ */
+struct rsnd_dma {
+	struct rsnd_priv	*priv;
+	struct sh_dmae_slave	slave;
+	struct work_struct	work;
+	struct dma_chan		*chan;
+	enum dma_data_direction dir;
+	int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len);
+	int (*complete)(struct rsnd_dma *dma);
+
+	int submit_loop;
+};
+
+void rsnd_dma_start(struct rsnd_dma *dma);
+void rsnd_dma_stop(struct rsnd_dma *dma);
+int rsnd_dma_available(struct rsnd_dma *dma);
+int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
+	int is_play, int id,
+	int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len),
+	int (*complete)(struct rsnd_dma *dma));
+void  rsnd_dma_quit(struct rsnd_priv *priv,
+		    struct rsnd_dma *dma);
+
+
+/*
+ *	R-Car sound mod
+ */
+
+struct rsnd_mod_ops {
+	char *name;
+	int (*init)(struct rsnd_mod *mod,
+		    struct rsnd_dai *rdai,
+		    struct rsnd_dai_stream *io);
+	int (*quit)(struct rsnd_mod *mod,
+		    struct rsnd_dai *rdai,
+		    struct rsnd_dai_stream *io);
+	int (*start)(struct rsnd_mod *mod,
+		     struct rsnd_dai *rdai,
+		     struct rsnd_dai_stream *io);
+	int (*stop)(struct rsnd_mod *mod,
+		    struct rsnd_dai *rdai,
+		    struct rsnd_dai_stream *io);
+};
+
+struct rsnd_mod {
+	int id;
+	struct rsnd_priv *priv;
+	struct rsnd_mod_ops *ops;
+	struct list_head list; /* connect to rsnd_dai playback/capture */
+	struct rsnd_dma dma;
+};
+
+#define rsnd_mod_to_priv(mod) ((mod)->priv)
+#define rsnd_mod_to_dma(mod) (&(mod)->dma)
+#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
+#define rsnd_mod_id(mod) ((mod)->id)
+#define for_each_rsnd_mod(pos, n, io)	\
+	list_for_each_entry_safe(pos, n, &(io)->head, list)
+#define rsnd_mod_call(mod, func, rdai, io)	\
+	(!(mod) ? -ENODEV :			\
+	 !((mod)->ops->func) ? 0 :		\
+	 (mod)->ops->func(mod, rdai, io))
+
+void rsnd_mod_init(struct rsnd_priv *priv,
+		   struct rsnd_mod *mod,
+		   struct rsnd_mod_ops *ops,
+		   int id);
+char *rsnd_mod_name(struct rsnd_mod *mod);
+
+/*
+ *	R-Car sound DAI
+ */
+#define RSND_DAI_NAME_SIZE	16
+struct rsnd_dai_stream {
+	struct list_head head; /* head of rsnd_mod list */
+	struct snd_pcm_substream *substream;
+	int byte_pos;
+	int period_pos;
+	int byte_per_period;
+	int next_period_byte;
+};
+
+struct rsnd_dai {
+	char name[RSND_DAI_NAME_SIZE];
+	struct rsnd_dai_platform_info *info; /* rcar_snd.h */
+	struct rsnd_dai_stream playback;
+	struct rsnd_dai_stream capture;
+
+	int clk_master:1;
+	int bit_clk_inv:1;
+	int frm_clk_inv:1;
+	int sys_delay:1;
+	int data_alignment:1;
+};
+
+#define rsnd_dai_nr(priv) ((priv)->dai_nr)
+#define for_each_rsnd_dai(rdai, priv, i)		\
+	for (i = 0, (rdai) = rsnd_dai_get(priv, i);	\
+	     i < rsnd_dai_nr(priv);			\
+	     i++, (rdai) = rsnd_dai_get(priv, i))
+
+struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
+int rsnd_dai_disconnect(struct rsnd_mod *mod);
+int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
+		     struct rsnd_dai_stream *io);
+int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
+int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
+#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
+#define rsnd_io_to_runtime(io) ((io)->substream->runtime)
+
+void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
+int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+
+/*
+ *	R-Car Gen1/Gen2
+ */
+int rsnd_gen_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv);
+void rsnd_gen_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv);
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io);
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+		       struct rsnd_dai *rdai,
+		       struct rsnd_dai_stream *io);
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+			       struct rsnd_mod *mod,
+			       enum rsnd_reg reg);
+#define rsnd_is_gen1(s)		((s)->info->flags & RSND_GEN1)
+#define rsnd_is_gen2(s)		((s)->info->flags & RSND_GEN2)
+
+/*
+ *	R-Car ADG
+ */
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
+int rsnd_adg_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv);
+void rsnd_adg_remove(struct platform_device *pdev,
+		   struct rsnd_priv *priv);
+
+/*
+ *	R-Car sound priv
+ */
+struct rsnd_priv {
+
+	struct device *dev;
+	struct rcar_snd_info *info;
+	spinlock_t lock;
+
+	/*
+	 * below value will be filled on rsnd_gen_probe()
+	 */
+	void *gen;
+
+	/*
+	 * below value will be filled on rsnd_scu_probe()
+	 */
+	void *scu;
+	int scu_nr;
+
+	/*
+	 * below value will be filled on rsnd_adg_probe()
+	 */
+	void *adg;
+
+	/*
+	 * below value will be filled on rsnd_ssi_probe()
+	 */
+	void *ssiu;
+
+	/*
+	 * below value will be filled on rsnd_dai_probe()
+	 */
+	struct snd_soc_dai_driver *daidrv;
+	struct rsnd_dai *rdai;
+	int dai_nr;
+};
+
+#define rsnd_priv_to_dev(priv)	((priv)->dev)
+#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
+#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
+
+/*
+ *	R-Car SCU
+ */
+int rsnd_scu_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv);
+void rsnd_scu_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_scu_nr(priv) ((priv)->scu_nr)
+
+/*
+ *	R-Car SSI
+ */
+int rsnd_ssi_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+		   struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
+struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
+					  int dai_id, int is_play);
+
+#endif
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
new file mode 100644
index 0000000..184d9008
--- /dev/null
+++ b/sound/soc/sh/rcar/scu.c
@@ -0,0 +1,236 @@
+/*
+ * Renesas R-Car SCU support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 "rsnd.h"
+
+struct rsnd_scu {
+	struct rsnd_scu_platform_info *info; /* rcar_snd.h */
+	struct rsnd_mod mod;
+};
+
+#define rsnd_scu_mode_flags(p) ((p)->info->flags)
+
+/*
+ * ADINR
+ */
+#define OTBL_24		(0 << 16)
+#define OTBL_22		(2 << 16)
+#define OTBL_20		(4 << 16)
+#define OTBL_18		(6 << 16)
+#define OTBL_16		(8 << 16)
+
+
+#define rsnd_mod_to_scu(_mod)	\
+	container_of((_mod), struct rsnd_scu, mod)
+
+#define for_each_rsnd_scu(pos, priv, i)					\
+	for ((i) = 0;							\
+	     ((i) < rsnd_scu_nr(priv)) &&				\
+		     ((pos) = (struct rsnd_scu *)(priv)->scu + i);	\
+	     i++)
+
+static int rsnd_scu_set_route(struct rsnd_priv *priv,
+			      struct rsnd_mod *mod,
+			      struct rsnd_dai *rdai,
+			      struct rsnd_dai_stream *io)
+{
+	struct scu_route_config {
+		u32 mask;
+		int shift;
+	} routes[] = {
+		{ 0xF,  0, }, /* 0 */
+		{ 0xF,  4, }, /* 1 */
+		{ 0xF,  8, }, /* 2 */
+		{ 0x7, 12, }, /* 3 */
+		{ 0x7, 16, }, /* 4 */
+		{ 0x7, 20, }, /* 5 */
+		{ 0x7, 24, }, /* 6 */
+		{ 0x3, 28, }, /* 7 */
+		{ 0x3, 30, }, /* 8 */
+	};
+
+	u32 mask;
+	u32 val;
+	int shift;
+	int id;
+
+	/*
+	 * Gen1 only
+	 */
+	if (!rsnd_is_gen1(priv))
+		return 0;
+
+	id = rsnd_mod_id(mod);
+	if (id < 0 || id > ARRAY_SIZE(routes))
+		return -EIO;
+
+	/*
+	 * SRC_ROUTE_SELECT
+	 */
+	val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
+	val = val		<< routes[id].shift;
+	mask = routes[id].mask	<< routes[id].shift;
+
+	rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
+
+	/*
+	 * SRC_TIMING_SELECT
+	 */
+	shift	= (id % 4) * 8;
+	mask	= 0x1F << shift;
+	if (8 == id) /* SRU8 is very special */
+		val = id << shift;
+	else
+		val = (id + 1) << shift;
+
+	switch (id / 4) {
+	case 0:
+		rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
+		break;
+	case 1:
+		rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
+		break;
+	case 2:
+		rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
+		break;
+	}
+
+	return 0;
+}
+
+static int rsnd_scu_set_mode(struct rsnd_priv *priv,
+			     struct rsnd_mod *mod,
+			     struct rsnd_dai *rdai,
+			     struct rsnd_dai_stream *io)
+{
+	int id = rsnd_mod_id(mod);
+	u32 val;
+
+	if (rsnd_is_gen1(priv)) {
+		val = (1 << id);
+		rsnd_mod_bset(mod, SRC_CTRL, val, val);
+	}
+
+	return 0;
+}
+
+static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
+			      struct rsnd_mod *mod,
+			      struct rsnd_dai *rdai,
+			      struct rsnd_dai_stream *io)
+{
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	u32 adinr = runtime->channels;
+
+	switch (runtime->sample_bits) {
+	case 16:
+		adinr |= OTBL_16;
+		break;
+	case 32:
+		adinr |= OTBL_24;
+		break;
+	default:
+		return -EIO;
+	}
+
+	rsnd_mod_write(mod, BUSIF_MODE, 1);
+	rsnd_mod_write(mod, BUSIF_ADINR, adinr);
+
+	return 0;
+}
+
+static int rsnd_scu_start(struct rsnd_mod *mod,
+			  struct rsnd_dai *rdai,
+			  struct rsnd_dai_stream *io)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 flags = rsnd_scu_mode_flags(scu);
+	int ret;
+
+	/*
+	 * SCU will be used if it has RSND_SCU_USB_HPBIF flags
+	 */
+	if (!(flags & RSND_SCU_USB_HPBIF)) {
+		/* it use PIO transter */
+		dev_dbg(dev, "%s%d is not used\n",
+			rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+		return 0;
+	}
+
+	/* it use DMA transter */
+	ret = rsnd_scu_set_route(priv, mod, rdai, io);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_scu_set_mode(priv, mod, rdai, io);
+	if (ret < 0)
+		return ret;
+
+	ret = rsnd_scu_set_hpbif(priv, mod, rdai, io);
+	if (ret < 0)
+		return ret;
+
+	dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_scu_ops = {
+	.name	= "scu",
+	.start	= rsnd_scu_start,
+};
+
+struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
+{
+	BUG_ON(id < 0 || id >= rsnd_scu_nr(priv));
+
+	return &((struct rsnd_scu *)(priv->scu) + id)->mod;
+}
+
+int rsnd_scu_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_scu *scu;
+	int i, nr;
+
+	/*
+	 * init SCU
+	 */
+	nr	= info->scu_info_nr;
+	scu	= devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
+	if (!scu) {
+		dev_err(dev, "SCU allocate failed\n");
+		return -ENOMEM;
+	}
+
+	priv->scu_nr	= nr;
+	priv->scu	= scu;
+
+	for_each_rsnd_scu(scu, priv, i) {
+		rsnd_mod_init(priv, &scu->mod,
+			      &rsnd_scu_ops, i);
+		scu->info = &info->scu_info[i];
+
+		dev_dbg(dev, "SCU%d probed\n", i);
+	}
+	dev_dbg(dev, "scu probed\n");
+
+	return 0;
+}
+
+void rsnd_scu_remove(struct platform_device *pdev,
+		     struct rsnd_priv *priv)
+{
+}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
new file mode 100644
index 0000000..fae26d3
--- /dev/null
+++ b/sound/soc/sh/rcar/ssi.c
@@ -0,0 +1,728 @@
+/*
+ * Renesas R-Car SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on fsi.c
+ * Kuninori Morimoto <morimoto.kuninori@renesas.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/delay.h>
+#include "rsnd.h"
+#define RSND_SSI_NAME_SIZE 16
+
+/*
+ * SSICR
+ */
+#define	FORCE		(1 << 31)	/* Fixed */
+#define	DMEN		(1 << 28)	/* DMA Enable */
+#define	UIEN		(1 << 27)	/* Underflow Interrupt Enable */
+#define	OIEN		(1 << 26)	/* Overflow Interrupt Enable */
+#define	IIEN		(1 << 25)	/* Idle Mode Interrupt Enable */
+#define	DIEN		(1 << 24)	/* Data Interrupt Enable */
+
+#define	DWL_8		(0 << 19)	/* Data Word Length */
+#define	DWL_16		(1 << 19)	/* Data Word Length */
+#define	DWL_18		(2 << 19)	/* Data Word Length */
+#define	DWL_20		(3 << 19)	/* Data Word Length */
+#define	DWL_22		(4 << 19)	/* Data Word Length */
+#define	DWL_24		(5 << 19)	/* Data Word Length */
+#define	DWL_32		(6 << 19)	/* Data Word Length */
+
+#define	SWL_32		(3 << 16)	/* R/W System Word Length */
+#define	SCKD		(1 << 15)	/* Serial Bit Clock Direction */
+#define	SWSD		(1 << 14)	/* Serial WS Direction */
+#define	SCKP		(1 << 13)	/* Serial Bit Clock Polarity */
+#define	SWSP		(1 << 12)	/* Serial WS Polarity */
+#define	SDTA		(1 << 10)	/* Serial Data Alignment */
+#define	DEL		(1 <<  8)	/* Serial Data Delay */
+#define	CKDV(v)		(v <<  4)	/* Serial Clock Division Ratio */
+#define	TRMD		(1 <<  1)	/* Transmit/Receive Mode Select */
+#define	EN		(1 <<  0)	/* SSI Module Enable */
+
+/*
+ * SSISR
+ */
+#define	UIRQ		(1 << 27)	/* Underflow Error Interrupt Status */
+#define	OIRQ		(1 << 26)	/* Overflow Error Interrupt Status */
+#define	IIRQ		(1 << 25)	/* Idle Mode Interrupt Status */
+#define	DIRQ		(1 << 24)	/* Data Interrupt Status Flag */
+
+/*
+ * SSIWSR
+ */
+#define CONT		(1 << 8)	/* WS Continue Function */
+
+struct rsnd_ssi {
+	struct clk *clk;
+	struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
+	struct rsnd_ssi *parent;
+	struct rsnd_mod mod;
+
+	struct rsnd_dai *rdai;
+	struct rsnd_dai_stream *io;
+	u32 cr_own;
+	u32 cr_clk;
+	u32 cr_etc;
+	int err;
+	int dma_offset;
+	unsigned int usrcnt;
+	unsigned int rate;
+};
+
+struct rsnd_ssiu {
+	u32 ssi_mode0;
+	u32 ssi_mode1;
+
+	int ssi_nr;
+	struct rsnd_ssi *ssi;
+};
+
+#define for_each_rsnd_ssi(pos, priv, i)					\
+	for (i = 0;							\
+	     (i < rsnd_ssi_nr(priv)) &&					\
+		((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
+	     i++)
+
+#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
+#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
+#define rsnd_dma_to_ssi(dma)  rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
+#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
+#define rsnd_ssi_dma_available(ssi) \
+	rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
+#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
+#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
+#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
+#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
+#define rsnd_ssi_to_ssiu(ssi)\
+	(((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
+
+static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
+			       struct rsnd_ssiu *ssiu)
+{
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_ssi *ssi;
+	u32 flags;
+	u32 val;
+	int i;
+
+	/*
+	 * SSI_MODE0
+	 */
+	ssiu->ssi_mode0 = 0;
+	for_each_rsnd_ssi(ssi, priv, i) {
+		flags = rsnd_ssi_mode_flags(ssi);
+
+		/* see also BUSIF_MODE */
+		if (!(flags & RSND_SSI_DEPENDENT)) {
+			ssiu->ssi_mode0 |= (1 << i);
+			dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i);
+		} else {
+			dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i);
+		}
+	}
+
+	/*
+	 * SSI_MODE1
+	 */
+#define ssi_parent_set(p, sync, adg, ext)		\
+	do {						\
+		ssi->parent = ssiu->ssi + p;		\
+		if (flags & RSND_SSI_CLK_FROM_ADG)	\
+			val = adg;			\
+		else					\
+			val = ext;			\
+		if (flags & RSND_SSI_SYNC)		\
+			val |= sync;			\
+	} while (0)
+
+	ssiu->ssi_mode1 = 0;
+	for_each_rsnd_ssi(ssi, priv, i) {
+		flags = rsnd_ssi_mode_flags(ssi);
+
+		if (!(flags & RSND_SSI_CLK_PIN_SHARE))
+			continue;
+
+		val = 0;
+		switch (i) {
+		case 1:
+			ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
+			break;
+		case 2:
+			ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
+			break;
+		case 4:
+			ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
+			break;
+		case 8:
+			ssi_parent_set(7, 0, 0, 0);
+			break;
+		}
+
+		ssiu->ssi_mode1 |= val;
+	}
+}
+
+static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi)
+{
+	struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
+
+	rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
+	rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
+}
+
+static void rsnd_ssi_status_check(struct rsnd_mod *mod,
+				  u32 bit)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 status;
+	int i;
+
+	for (i = 0; i < 1024; i++) {
+		status = rsnd_mod_read(mod, SSISR);
+		if (status & bit)
+			return;
+
+		udelay(50);
+	}
+
+	dev_warn(dev, "status check failed\n");
+}
+
+static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
+				     unsigned int rate)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	int i, j, ret;
+	int adg_clk_div_table[] = {
+		1, 6, /* see adg.c */
+	};
+	int ssi_clk_mul_table[] = {
+		1, 2, 4, 8, 16, 6, 12,
+	};
+	unsigned int main_rate;
+
+	/*
+	 * Find best clock, and try to start ADG
+	 */
+	for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
+		for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+			/*
+			 * this driver is assuming that
+			 * system word is 64fs (= 2 x 32bit)
+			 * see rsnd_ssi_start()
+			 */
+			main_rate = rate / adg_clk_div_table[i]
+				* 32 * 2 * ssi_clk_mul_table[j];
+
+			ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
+			if (0 == ret) {
+				ssi->rate	= rate;
+				ssi->cr_clk	= FORCE | SWL_32 |
+						  SCKD | SWSD | CKDV(j);
+
+				dev_dbg(dev, "ssi%d outputs %u Hz\n",
+					rsnd_mod_id(&ssi->mod), rate);
+
+				return 0;
+			}
+		}
+	}
+
+	dev_err(dev, "unsupported clock rate\n");
+	return -EIO;
+}
+
+static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
+{
+	ssi->rate = 0;
+	ssi->cr_clk = 0;
+	rsnd_adg_ssi_clk_stop(&ssi->mod);
+}
+
+static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
+			      struct rsnd_dai *rdai,
+			      struct rsnd_dai_stream *io)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 cr;
+
+	if (0 == ssi->usrcnt) {
+		clk_enable(ssi->clk);
+
+		if (rsnd_rdai_is_clk_master(rdai)) {
+			struct snd_pcm_runtime *runtime;
+
+			runtime = rsnd_io_to_runtime(io);
+
+			if (rsnd_ssi_clk_from_parent(ssi))
+				rsnd_ssi_hw_start(ssi->parent, rdai, io);
+			else
+				rsnd_ssi_master_clk_start(ssi, runtime->rate);
+		}
+	}
+
+	cr  =	ssi->cr_own	|
+		ssi->cr_clk	|
+		ssi->cr_etc	|
+		EN;
+
+	rsnd_mod_write(&ssi->mod, SSICR, cr);
+
+	ssi->usrcnt++;
+
+	dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod));
+}
+
+static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
+			     struct rsnd_dai *rdai)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	u32 cr;
+
+	if (0 == ssi->usrcnt) /* stop might be called without start */
+		return;
+
+	ssi->usrcnt--;
+
+	if (0 == ssi->usrcnt) {
+		/*
+		 * disable all IRQ,
+		 * and, wait all data was sent
+		 */
+		cr  =	ssi->cr_own	|
+			ssi->cr_clk;
+
+		rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
+		rsnd_ssi_status_check(&ssi->mod, DIRQ);
+
+		/*
+		 * disable SSI,
+		 * and, wait idle state
+		 */
+		rsnd_mod_write(&ssi->mod, SSICR, cr);	/* disabled all */
+		rsnd_ssi_status_check(&ssi->mod, IIRQ);
+
+		if (rsnd_rdai_is_clk_master(rdai)) {
+			if (rsnd_ssi_clk_from_parent(ssi))
+				rsnd_ssi_hw_stop(ssi->parent, rdai);
+			else
+				rsnd_ssi_master_clk_stop(ssi);
+		}
+
+		clk_disable(ssi->clk);
+	}
+
+	dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
+}
+
+/*
+ *	SSI mod common functions
+ */
+static int rsnd_ssi_init(struct rsnd_mod *mod,
+			 struct rsnd_dai *rdai,
+			 struct rsnd_dai_stream *io)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+	u32 cr;
+
+	cr = FORCE;
+
+	/*
+	 * always use 32bit system word for easy clock calculation.
+	 * see also rsnd_ssi_master_clk_enable()
+	 */
+	cr |= SWL_32;
+
+	/*
+	 * init clock settings for SSICR
+	 */
+	switch (runtime->sample_bits) {
+	case 16:
+		cr |= DWL_16;
+		break;
+	case 32:
+		cr |= DWL_24;
+		break;
+	default:
+		return -EIO;
+	}
+
+	if (rdai->bit_clk_inv)
+		cr |= SCKP;
+	if (rdai->frm_clk_inv)
+		cr |= SWSP;
+	if (rdai->data_alignment)
+		cr |= SDTA;
+	if (rdai->sys_delay)
+		cr |= DEL;
+	if (rsnd_dai_is_play(rdai, io))
+		cr |= TRMD;
+
+	/*
+	 * set ssi parameter
+	 */
+	ssi->rdai	= rdai;
+	ssi->io		= io;
+	ssi->cr_own	= cr;
+	ssi->err	= -1; /* ignore 1st error */
+
+	rsnd_ssi_mode_set(ssi);
+
+	dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+	return 0;
+}
+
+static int rsnd_ssi_quit(struct rsnd_mod *mod,
+			 struct rsnd_dai *rdai,
+			 struct rsnd_dai_stream *io)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+	if (ssi->err > 0)
+		dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
+
+	ssi->rdai	= NULL;
+	ssi->io		= NULL;
+	ssi->cr_own	= 0;
+	ssi->err	= 0;
+
+	return 0;
+}
+
+static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
+{
+	/* under/over flow error */
+	if (status & (UIRQ | OIRQ)) {
+		ssi->err++;
+
+		/* clear error status */
+		rsnd_mod_write(&ssi->mod, SSISR, 0);
+	}
+}
+
+/*
+ *		SSI PIO
+ */
+static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
+{
+	struct rsnd_ssi *ssi = data;
+	struct rsnd_dai_stream *io = ssi->io;
+	u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+	irqreturn_t ret = IRQ_NONE;
+
+	if (io && (status & DIRQ)) {
+		struct rsnd_dai *rdai = ssi->rdai;
+		struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+		u32 *buf = (u32 *)(runtime->dma_area +
+				   rsnd_dai_pointer_offset(io, 0));
+
+		rsnd_ssi_record_error(ssi, status);
+
+		/*
+		 * 8/16/32 data can be assesse to TDR/RDR register
+		 * directly as 32bit data
+		 * see rsnd_ssi_init()
+		 */
+		if (rsnd_dai_is_play(rdai, io))
+			rsnd_mod_write(&ssi->mod, SSITDR, *buf);
+		else
+			*buf = rsnd_mod_read(&ssi->mod, SSIRDR);
+
+		rsnd_dai_pointer_update(io, sizeof(*buf));
+
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+			      struct rsnd_dai *rdai,
+			      struct rsnd_dai_stream *io)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	/* enable PIO IRQ */
+	ssi->cr_etc = UIEN | OIEN | DIEN;
+
+	rsnd_ssi_hw_start(ssi, rdai, io);
+
+	dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+	return 0;
+}
+
+static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
+			     struct rsnd_dai *rdai,
+			     struct rsnd_dai_stream *io)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+	dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+	ssi->cr_etc = 0;
+
+	rsnd_ssi_hw_stop(ssi, rdai);
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
+	.name	= "ssi (pio)",
+	.init	= rsnd_ssi_init,
+	.quit	= rsnd_ssi_quit,
+	.start	= rsnd_ssi_pio_start,
+	.stop	= rsnd_ssi_pio_stop,
+};
+
+static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len)
+{
+	struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
+	struct rsnd_dai_stream *io = ssi->io;
+	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+	*len = io->byte_per_period;
+	*buf = runtime->dma_addr +
+		rsnd_dai_pointer_offset(io, ssi->dma_offset + *len);
+	ssi->dma_offset = *len; /* it cares A/B plane */
+
+	return 0;
+}
+
+static int rsnd_ssi_dma_complete(struct rsnd_dma *dma)
+{
+	struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
+	struct rsnd_dai_stream *io = ssi->io;
+	u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+
+	rsnd_ssi_record_error(ssi, status);
+
+	rsnd_dai_pointer_update(ssi->io, io->byte_per_period);
+
+	return 0;
+}
+
+static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
+			      struct rsnd_dai *rdai,
+			      struct rsnd_dai_stream *io)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
+
+	/* enable DMA transfer */
+	ssi->cr_etc = DMEN;
+	ssi->dma_offset = 0;
+
+	rsnd_dma_start(dma);
+
+	rsnd_ssi_hw_start(ssi, ssi->rdai, io);
+
+	/* enable WS continue */
+	if (rsnd_rdai_is_clk_master(rdai))
+		rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+
+	return 0;
+}
+
+static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
+			     struct rsnd_dai *rdai,
+			     struct rsnd_dai_stream *io)
+{
+	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+	struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
+
+	ssi->cr_etc = 0;
+
+	rsnd_ssi_hw_stop(ssi, rdai);
+
+	rsnd_dma_stop(dma);
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
+	.name	= "ssi (dma)",
+	.init	= rsnd_ssi_init,
+	.quit	= rsnd_ssi_quit,
+	.start	= rsnd_ssi_dma_start,
+	.stop	= rsnd_ssi_dma_stop,
+};
+
+/*
+ *		Non SSI
+ */
+static int rsnd_ssi_non(struct rsnd_mod *mod,
+			struct rsnd_dai *rdai,
+			struct rsnd_dai_stream *io)
+{
+	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+	struct device *dev = rsnd_priv_to_dev(priv);
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_non_ops = {
+	.name	= "ssi (non)",
+	.init	= rsnd_ssi_non,
+	.quit	= rsnd_ssi_non,
+	.start	= rsnd_ssi_non,
+	.stop	= rsnd_ssi_non,
+};
+
+/*
+ *		ssi mod function
+ */
+struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
+					  int dai_id, int is_play)
+{
+	struct rsnd_ssi *ssi;
+	int i, has_play;
+
+	is_play = !!is_play;
+
+	for_each_rsnd_ssi(ssi, priv, i) {
+		if (rsnd_ssi_dai_id(ssi) != dai_id)
+			continue;
+
+		has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
+
+		if (is_play == has_play)
+			return &ssi->mod;
+	}
+
+	return NULL;
+}
+
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+{
+	BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv));
+
+	return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
+}
+
+int rsnd_ssi_probe(struct platform_device *pdev,
+		   struct rcar_snd_info *info,
+		   struct rsnd_priv *priv)
+{
+	struct rsnd_ssi_platform_info *pinfo;
+	struct device *dev = rsnd_priv_to_dev(priv);
+	struct rsnd_mod_ops *ops;
+	struct clk *clk;
+	struct rsnd_ssiu *ssiu;
+	struct rsnd_ssi *ssi;
+	char name[RSND_SSI_NAME_SIZE];
+	int i, nr, ret;
+
+	/*
+	 *	init SSI
+	 */
+	nr	= info->ssi_info_nr;
+	ssiu	= devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
+			       GFP_KERNEL);
+	if (!ssiu) {
+		dev_err(dev, "SSI allocate failed\n");
+		return -ENOMEM;
+	}
+
+	priv->ssiu	= ssiu;
+	ssiu->ssi	= (struct rsnd_ssi *)(ssiu + 1);
+	ssiu->ssi_nr	= nr;
+
+	for_each_rsnd_ssi(ssi, priv, i) {
+		pinfo = &info->ssi_info[i];
+
+		snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
+
+		clk = clk_get(dev, name);
+		if (IS_ERR(clk))
+			return PTR_ERR(clk);
+
+		ssi->info	= pinfo;
+		ssi->clk	= clk;
+
+		ops = &rsnd_ssi_non_ops;
+
+		/*
+		 * SSI DMA case
+		 */
+		if (pinfo->dma_id > 0) {
+			ret = rsnd_dma_init(
+				priv, rsnd_mod_to_dma(&ssi->mod),
+				(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY),
+				pinfo->dma_id,
+				rsnd_ssi_dma_inquiry,
+				rsnd_ssi_dma_complete);
+			if (ret < 0)
+				dev_info(dev, "SSI DMA failed. try PIO transter\n");
+			else
+				ops	= &rsnd_ssi_dma_ops;
+
+			dev_dbg(dev, "SSI%d use DMA transfer\n", i);
+		}
+
+		/*
+		 * SSI PIO case
+		 */
+		if (!rsnd_ssi_dma_available(ssi) &&
+		     rsnd_ssi_pio_available(ssi)) {
+			ret = devm_request_irq(dev, pinfo->pio_irq,
+					       &rsnd_ssi_pio_interrupt,
+					       IRQF_SHARED,
+					       dev_name(dev), ssi);
+			if (ret) {
+				dev_err(dev, "SSI request interrupt failed\n");
+				return ret;
+			}
+
+			ops	= &rsnd_ssi_pio_ops;
+
+			dev_dbg(dev, "SSI%d use PIO transfer\n", i);
+		}
+
+		rsnd_mod_init(priv, &ssi->mod, ops, i);
+	}
+
+	rsnd_ssi_mode_init(priv, ssiu);
+
+	dev_dbg(dev, "ssi probed\n");
+
+	return 0;
+}
+
+void rsnd_ssi_remove(struct platform_device *pdev,
+		   struct rsnd_priv *priv)
+{
+	struct rsnd_ssi *ssi;
+	int i;
+
+	for_each_rsnd_ssi(ssi, priv, i) {
+		clk_put(ssi->clk);
+		if (rsnd_ssi_dma_available(ssi))
+			rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
+	}
+
+}
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 06a8000..53c9ecd 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -149,8 +149,9 @@
 					SND_SOC_DAPM_STREAM_STOP);
 		} else {
 			rtd->pop_wait = 1;
-			schedule_delayed_work(&rtd->delayed_work,
-				msecs_to_jiffies(rtd->pmdown_time));
+			queue_delayed_work(system_power_efficient_wq,
+					   &rtd->delayed_work,
+					   msecs_to_jiffies(rtd->pmdown_time));
 		}
 	} else {
 		/* capture streams can be powered down now */
@@ -334,7 +335,7 @@
 	return ret;
 }
 
-static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
+static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
 				struct snd_compr_metadata *metadata)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -347,7 +348,7 @@
 	return ret;
 }
 
-static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
+static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
 				struct snd_compr_metadata *metadata)
 {
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -364,8 +365,8 @@
 	.open		= soc_compr_open,
 	.free		= soc_compr_free,
 	.set_params	= soc_compr_set_params,
-	.set_metadata   = sst_compr_set_metadata,
-	.get_metadata	= sst_compr_get_metadata,
+	.set_metadata   = soc_compr_set_metadata,
+	.get_metadata	= soc_compr_get_metadata,
 	.get_params	= soc_compr_get_params,
 	.trigger	= soc_compr_trigger,
 	.pointer	= soc_compr_pointer,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d82ee38..4d05613 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -30,9 +30,12 @@
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <sound/ac97_codec.h>
 #include <sound/core.h>
 #include <sound/jack.h>
@@ -47,8 +50,6 @@
 
 #define NAME_SIZE	32
 
-static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
-
 #ifdef CONFIG_DEBUG_FS
 struct dentry *snd_soc_debugfs_root;
 EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
@@ -69,6 +70,16 @@
 module_param(pmdown_time, int, 0);
 MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
 
+struct snd_ac97_reset_cfg {
+	struct pinctrl *pctl;
+	struct pinctrl_state *pstate_reset;
+	struct pinctrl_state *pstate_warm_reset;
+	struct pinctrl_state *pstate_run;
+	int gpio_sdata;
+	int gpio_sync;
+	int gpio_reset;
+};
+
 /* returns the minimum number of bytes needed to represent
  * a particular given value */
 static int min_bytes_needed(unsigned long val)
@@ -192,7 +203,7 @@
 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
 	int ret;
 
-	ret = strict_strtol(buf, 10, &rtd->pmdown_time);
+	ret = kstrtol(buf, 10, &rtd->pmdown_time);
 	if (ret)
 		return ret;
 
@@ -237,6 +248,7 @@
 	char *start = buf;
 	unsigned long reg, value;
 	struct snd_soc_codec *codec = file->private_data;
+	int ret;
 
 	buf_size = min(count, (sizeof(buf)-1));
 	if (copy_from_user(buf, user_buf, buf_size))
@@ -248,8 +260,9 @@
 	reg = simple_strtoul(start, &start, 16);
 	while (*start == ' ')
 		start++;
-	if (strict_strtoul(start, 16, &value))
-		return -EINVAL;
+	ret = kstrtoul(start, 16, &value);
+	if (ret)
+		return ret;
 
 	/* Userspace has been fiddling around behind the kernel's back */
 	add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
@@ -530,6 +543,15 @@
 }
 #endif
 
+static void codec2codec_close_delayed_work(struct work_struct *work)
+{
+	/* Currently nothing to do for c2c links
+	 * Since c2c links are internal nodes in the DAPM graph and
+	 * don't interface with the outside world or application layer
+	 * we don't have to do any special handling on close.
+	 */
+}
+
 #ifdef CONFIG_PM_SLEEP
 /* powers down audio subsystem for suspend */
 int snd_soc_suspend(struct device *dev)
@@ -1223,9 +1245,6 @@
 	}
 	rtd->card = card;
 
-	/* Make sure all DAPM widgets are instantiated */
-	snd_soc_dapm_new_widgets(&codec->dapm);
-
 	/* machine controls, routes and widgets are not prefixed */
 	temp = codec->name_prefix;
 	codec->name_prefix = NULL;
@@ -1428,6 +1447,9 @@
 				return ret;
 			}
 		} else {
+			INIT_DELAYED_WORK(&rtd->delayed_work,
+						codec2codec_close_delayed_work);
+
 			/* link the DAI widgets */
 			play_w = codec_dai->playback_widget;
 			capture_w = cpu_dai->capture_widget;
@@ -1718,8 +1740,6 @@
 		snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
 					card->num_dapm_routes);
 
-	snd_soc_dapm_new_widgets(&card->dapm);
-
 	for (i = 0; i < card->num_links; i++) {
 		dai_link = &card->dai_link[i];
 		dai_fmt = dai_link->dai_fmt;
@@ -1798,12 +1818,12 @@
 		}
 	}
 
-	snd_soc_dapm_new_widgets(&card->dapm);
-
 	if (card->fully_routed)
 		list_for_each_entry(codec, &card->codec_dev_list, card_list)
 			snd_soc_dapm_auto_nc_codec_pins(codec);
 
+	snd_soc_dapm_new_widgets(card);
+
 	ret = snd_card_register(card->snd_card);
 	if (ret < 0) {
 		dev_err(card->dev, "ASoC: failed to register soundcard %d\n",
@@ -2080,6 +2100,117 @@
 }
 EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
 
+static struct snd_ac97_reset_cfg snd_ac97_rst_cfg;
+
+static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
+
+	pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset);
+
+	gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1);
+
+	udelay(10);
+
+	gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
+
+	pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
+	msleep(2);
+}
+
+static void snd_soc_ac97_reset(struct snd_ac97 *ac97)
+{
+	struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
+
+	pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset);
+
+	gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
+	gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0);
+	gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0);
+
+	udelay(10);
+
+	gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1);
+
+	pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
+	msleep(2);
+}
+
+static int snd_soc_ac97_parse_pinctl(struct device *dev,
+		struct snd_ac97_reset_cfg *cfg)
+{
+	struct pinctrl *p;
+	struct pinctrl_state *state;
+	int gpio;
+	int ret;
+
+	p = devm_pinctrl_get(dev);
+	if (IS_ERR(p)) {
+		dev_err(dev, "Failed to get pinctrl\n");
+		return PTR_RET(p);
+	}
+	cfg->pctl = p;
+
+	state = pinctrl_lookup_state(p, "ac97-reset");
+	if (IS_ERR(state)) {
+		dev_err(dev, "Can't find pinctrl state ac97-reset\n");
+		return PTR_RET(state);
+	}
+	cfg->pstate_reset = state;
+
+	state = pinctrl_lookup_state(p, "ac97-warm-reset");
+	if (IS_ERR(state)) {
+		dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
+		return PTR_RET(state);
+	}
+	cfg->pstate_warm_reset = state;
+
+	state = pinctrl_lookup_state(p, "ac97-running");
+	if (IS_ERR(state)) {
+		dev_err(dev, "Can't find pinctrl state ac97-running\n");
+		return PTR_RET(state);
+	}
+	cfg->pstate_run = state;
+
+	gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0);
+	if (gpio < 0) {
+		dev_err(dev, "Can't find ac97-sync gpio\n");
+		return gpio;
+	}
+	ret = devm_gpio_request(dev, gpio, "AC97 link sync");
+	if (ret) {
+		dev_err(dev, "Failed requesting ac97-sync gpio\n");
+		return ret;
+	}
+	cfg->gpio_sync = gpio;
+
+	gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1);
+	if (gpio < 0) {
+		dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio);
+		return gpio;
+	}
+	ret = devm_gpio_request(dev, gpio, "AC97 link sdata");
+	if (ret) {
+		dev_err(dev, "Failed requesting ac97-sdata gpio\n");
+		return ret;
+	}
+	cfg->gpio_sdata = gpio;
+
+	gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
+	if (gpio < 0) {
+		dev_err(dev, "Can't find ac97-reset gpio\n");
+		return gpio;
+	}
+	ret = devm_gpio_request(dev, gpio, "AC97 link reset");
+	if (ret) {
+		dev_err(dev, "Failed requesting ac97-reset gpio\n");
+		return ret;
+	}
+	cfg->gpio_reset = gpio;
+
+	return 0;
+}
+
 struct snd_ac97_bus_ops *soc_ac97_ops;
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
@@ -2098,6 +2229,35 @@
 EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
 
 /**
+ * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions
+ *
+ * This function sets the reset and warm_reset properties of ops and parses
+ * the device node of pdev to get pinctrl states and gpio numbers to use.
+ */
+int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+		struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct snd_ac97_reset_cfg cfg;
+	int ret;
+
+	ret = snd_soc_ac97_parse_pinctl(dev, &cfg);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_set_ac97_ops(ops);
+	if (ret)
+		return ret;
+
+	ops->warm_reset = snd_soc_ac97_warm_reset;
+	ops->reset = snd_soc_ac97_reset;
+
+	snd_ac97_rst_cfg = cfg;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
+
+/**
  * snd_soc_free_ac97_codec - free AC97 codec device
  * @codec: audio codec
  *
@@ -2299,6 +2459,22 @@
 	return 0;
 }
 
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+					       const char *name)
+{
+	struct snd_card *card = soc_card->snd_card;
+	struct snd_kcontrol *kctl;
+
+	if (unlikely(!name))
+		return NULL;
+
+	list_for_each_entry(kctl, &card->controls, list)
+		if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
+			return kctl;
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
+
 /**
  * snd_soc_add_codec_controls - add an array of controls to a codec.
  * Convenience function to add a list of controls. Many codecs were
@@ -2541,59 +2717,6 @@
 EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
 
 /**
- * snd_soc_info_enum_ext - external enumerated single mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about an external enumerated
- * single mixer.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo)
-{
-	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-	uinfo->count = 1;
-	uinfo->value.enumerated.items = e->max;
-
-	if (uinfo->value.enumerated.item > e->max - 1)
-		uinfo->value.enumerated.item = e->max - 1;
-	strcpy(uinfo->value.enumerated.name,
-		e->texts[uinfo->value.enumerated.item]);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
-
-/**
- * snd_soc_info_volsw_ext - external single mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about a single external mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
-	struct snd_ctl_elem_info *uinfo)
-{
-	int max = kcontrol->private_value;
-
-	if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
-		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	else
-		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = max;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
-
-/**
  * snd_soc_info_volsw - single mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 4375c9f..c17c14c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -47,6 +47,15 @@
 
 #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
 
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
+	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
+	const char *control,
+	int (*connected)(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink));
+static struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+			 const struct snd_soc_dapm_widget *widget);
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
 	[snd_soc_dapm_pre] = 0,
@@ -73,16 +82,18 @@
 	[snd_soc_dapm_hp] = 10,
 	[snd_soc_dapm_spk] = 10,
 	[snd_soc_dapm_line] = 10,
-	[snd_soc_dapm_post] = 11,
+	[snd_soc_dapm_kcontrol] = 11,
+	[snd_soc_dapm_post] = 12,
 };
 
 static int dapm_down_seq[] = {
 	[snd_soc_dapm_pre] = 0,
-	[snd_soc_dapm_adc] = 1,
-	[snd_soc_dapm_hp] = 2,
-	[snd_soc_dapm_spk] = 2,
-	[snd_soc_dapm_line] = 2,
-	[snd_soc_dapm_out_drv] = 2,
+	[snd_soc_dapm_kcontrol] = 1,
+	[snd_soc_dapm_adc] = 2,
+	[snd_soc_dapm_hp] = 3,
+	[snd_soc_dapm_spk] = 3,
+	[snd_soc_dapm_line] = 3,
+	[snd_soc_dapm_out_drv] = 3,
 	[snd_soc_dapm_pga] = 4,
 	[snd_soc_dapm_switch] = 5,
 	[snd_soc_dapm_mixer_named_ctl] = 5,
@@ -174,36 +185,178 @@
 	return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
-/* get snd_card from DAPM context */
-static inline struct snd_card *dapm_get_snd_card(
-	struct snd_soc_dapm_context *dapm)
-{
-	if (dapm->codec)
-		return dapm->codec->card->snd_card;
-	else if (dapm->platform)
-		return dapm->platform->card->snd_card;
-	else
-		BUG();
+struct dapm_kcontrol_data {
+	unsigned int value;
+	struct snd_soc_dapm_widget *widget;
+	struct list_head paths;
+	struct snd_soc_dapm_widget_list *wlist;
+};
 
-	/* unreachable */
-	return NULL;
+static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
+	struct snd_kcontrol *kcontrol)
+{
+	struct dapm_kcontrol_data *data;
+	struct soc_mixer_control *mc;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		dev_err(widget->dapm->dev,
+				"ASoC: can't allocate kcontrol data for %s\n",
+				widget->name);
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&data->paths);
+
+	switch (widget->id) {
+	case snd_soc_dapm_switch:
+	case snd_soc_dapm_mixer:
+	case snd_soc_dapm_mixer_named_ctl:
+		mc = (struct soc_mixer_control *)kcontrol->private_value;
+
+		if (mc->autodisable) {
+			struct snd_soc_dapm_widget template;
+
+			memset(&template, 0, sizeof(template));
+			template.reg = mc->reg;
+			template.mask = (1 << fls(mc->max)) - 1;
+			template.shift = mc->shift;
+			if (mc->invert)
+				template.off_val = mc->max;
+			else
+				template.off_val = 0;
+			template.on_val = template.off_val;
+			template.id = snd_soc_dapm_kcontrol;
+			template.name = kcontrol->id.name;
+
+			data->value = template.on_val;
+
+			data->widget = snd_soc_dapm_new_control(widget->dapm,
+				&template);
+			if (!data->widget) {
+				kfree(data);
+				return -ENOMEM;
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	kcontrol->private_data = data;
+
+	return 0;
 }
 
-/* get soc_card from DAPM context */
-static inline struct snd_soc_card *dapm_get_soc_card(
-		struct snd_soc_dapm_context *dapm)
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
-	if (dapm->codec)
-		return dapm->codec->card;
-	else if (dapm->platform)
-		return dapm->platform->card;
-	else
-		BUG();
-
-	/* unreachable */
-	return NULL;
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+	kfree(data->widget);
+	kfree(data->wlist);
+	kfree(data);
 }
 
+static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
+	const struct snd_kcontrol *kcontrol)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+	return data->wlist;
+}
+
+static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
+	struct snd_soc_dapm_widget *widget)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *new_wlist;
+	unsigned int n;
+
+	if (data->wlist)
+		n = data->wlist->num_widgets + 1;
+	else
+		n = 1;
+
+	new_wlist = krealloc(data->wlist,
+			sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
+	if (!new_wlist)
+		return -ENOMEM;
+
+	new_wlist->widgets[n - 1] = widget;
+	new_wlist->num_widgets = n;
+
+	data->wlist = new_wlist;
+
+	return 0;
+}
+
+static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
+	struct snd_soc_dapm_path *path)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+	list_add_tail(&path->list_kcontrol, &data->paths);
+
+	if (data->widget) {
+		snd_soc_dapm_add_path(data->widget->dapm, data->widget,
+		    path->source, NULL, NULL);
+	}
+}
+
+static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+	if (!data->widget)
+		return true;
+
+	return data->widget->power;
+}
+
+static struct list_head *dapm_kcontrol_get_path_list(
+	const struct snd_kcontrol *kcontrol)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+	return &data->paths;
+}
+
+#define dapm_kcontrol_for_each_path(path, kcontrol) \
+	list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
+		list_kcontrol)
+
+static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+	return data->value;
+}
+
+static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
+	unsigned int value)
+{
+	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+	if (data->value == value)
+		return false;
+
+	if (data->widget)
+		data->widget->on_val = value;
+
+	data->value = value;
+
+	return true;
+}
+
+/**
+ * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
+ * @kcontrol: The kcontrol
+ */
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
+{
+	return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
+
 static void dapm_reset(struct snd_soc_card *card)
 {
 	struct snd_soc_dapm_widget *w;
@@ -211,6 +364,7 @@
 	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
 
 	list_for_each_entry(w, &card->widgets, list) {
+		w->new_power = w->power;
 		w->power_checked = false;
 		w->inputs = -1;
 		w->outputs = -1;
@@ -428,6 +582,7 @@
 	case snd_soc_dapm_spk:
 	case snd_soc_dapm_line:
 	case snd_soc_dapm_dai_link:
+	case snd_soc_dapm_kcontrol:
 		p->connect = 1;
 	break;
 	/* does affect routing - dynamically connected */
@@ -507,17 +662,12 @@
 	return 0;
 }
 
-static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
-{
-	kfree(kctl->private_data);
-}
-
 /*
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
  */
 static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
-	int kci, struct snd_soc_dapm_path *path)
+	int kci)
 {
 	struct snd_soc_dapm_context *dapm = w->dapm;
 	struct snd_card *card = dapm->card->snd_card;
@@ -525,9 +675,6 @@
 	size_t prefix_len;
 	int shared;
 	struct snd_kcontrol *kcontrol;
-	struct snd_soc_dapm_widget_list *wlist;
-	int wlistentries;
-	size_t wlistsize;
 	bool wname_in_long_name, kcname_in_long_name;
 	char *long_name;
 	const char *name;
@@ -546,25 +693,6 @@
 	shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
 					 &kcontrol);
 
-	if (kcontrol) {
-		wlist = kcontrol->private_data;
-		wlistentries = wlist->num_widgets + 1;
-	} else {
-		wlist = NULL;
-		wlistentries = 1;
-	}
-
-	wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
-			wlistentries * sizeof(struct snd_soc_dapm_widget *);
-	wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
-	if (wlist == NULL) {
-		dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
-			w->name);
-		return -ENOMEM;
-	}
-	wlist->num_widgets = wlistentries;
-	wlist->widgets[wlistentries - 1] = w;
-
 	if (!kcontrol) {
 		if (shared) {
 			wname_in_long_name = false;
@@ -587,7 +715,6 @@
 				kcname_in_long_name = false;
 				break;
 			default:
-				kfree(wlist);
 				return -EINVAL;
 			}
 		}
@@ -602,10 +729,8 @@
 			long_name = kasprintf(GFP_KERNEL, "%s %s",
 				 w->name + prefix_len,
 				 w->kcontrol_news[kci].name);
-			if (long_name == NULL) {
-				kfree(wlist);
+			if (long_name == NULL)
 				return -ENOMEM;
-			}
 
 			name = long_name;
 		} else if (wname_in_long_name) {
@@ -616,23 +741,33 @@
 			name = w->kcontrol_news[kci].name;
 		}
 
-		kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+		kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
 					prefix);
-		kcontrol->private_free = dapm_kcontrol_free;
 		kfree(long_name);
+		if (!kcontrol)
+			return -ENOMEM;
+		kcontrol->private_free = dapm_kcontrol_free;
+
+		ret = dapm_kcontrol_data_alloc(w, kcontrol);
+		if (ret) {
+			snd_ctl_free_one(kcontrol);
+			return ret;
+		}
+
 		ret = snd_ctl_add(card, kcontrol);
 		if (ret < 0) {
 			dev_err(dapm->dev,
 				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
 				w->name, name, ret);
-			kfree(wlist);
 			return ret;
 		}
 	}
 
-	kcontrol->private_data = wlist;
+	ret = dapm_kcontrol_add_widget(kcontrol, w);
+	if (ret)
+		return ret;
+
 	w->kcontrols[kci] = kcontrol;
-	path->kcontrol = kcontrol;
 
 	return 0;
 }
@@ -652,13 +787,15 @@
 				continue;
 
 			if (w->kcontrols[i]) {
-				path->kcontrol = w->kcontrols[i];
+				dapm_kcontrol_add_path(w->kcontrols[i], path);
 				continue;
 			}
 
-			ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
+			ret = dapm_create_or_share_mixmux_kcontrol(w, i);
 			if (ret < 0)
 				return ret;
+
+			dapm_kcontrol_add_path(w->kcontrols[i], path);
 		}
 	}
 
@@ -684,15 +821,12 @@
 		return -EINVAL;
 	}
 
-	path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
-				list_sink);
-
-	ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
+	ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
 	if (ret < 0)
 		return ret;
 
 	list_for_each_entry(path, &w->sources, list_sink)
-		path->kcontrol = w->kcontrols[0];
+		dapm_kcontrol_add_path(w->kcontrols[0], path);
 
 	return 0;
 }
@@ -813,6 +947,7 @@
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_clock_supply:
+	case snd_soc_dapm_kcontrol:
 		return 0;
 	default:
 		break;
@@ -908,6 +1043,7 @@
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_clock_supply:
+	case snd_soc_dapm_kcontrol:
 		return 0;
 	default:
 		break;
@@ -1062,7 +1198,7 @@
 	int ret;
 
 	if (SND_SOC_DAPM_EVENT_ON(event)) {
-		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
 			ret = regulator_allow_bypass(w->regulator, false);
 			if (ret != 0)
 				dev_warn(w->dapm->dev,
@@ -1072,7 +1208,7 @@
 
 		return regulator_enable(w->regulator);
 	} else {
-		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
 			ret = regulator_allow_bypass(w->regulator, true);
 			if (ret != 0)
 				dev_warn(w->dapm->dev,
@@ -1244,10 +1380,9 @@
 	list_add_tail(&new_widget->power_list, list);
 }
 
-static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
+static void dapm_seq_check_event(struct snd_soc_card *card,
 				 struct snd_soc_dapm_widget *w, int event)
 {
-	struct snd_soc_card *card = dapm->card;
 	const char *ev_name;
 	int power, ret;
 
@@ -1281,55 +1416,50 @@
 		return;
 	}
 
-	if (w->power != power)
+	if (w->new_power != power)
 		return;
 
 	if (w->event && (w->event_flags & event)) {
-		pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
+		pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
 			w->name, ev_name);
 		trace_snd_soc_dapm_widget_event_start(w, event);
 		ret = w->event(w, NULL, event);
 		trace_snd_soc_dapm_widget_event_done(w, event);
 		if (ret < 0)
-			dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n",
+			dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
 			       ev_name, w->name, ret);
 	}
 }
 
 /* Apply the coalesced changes from a DAPM sequence */
-static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
+static void dapm_seq_run_coalesced(struct snd_soc_card *card,
 				   struct list_head *pending)
 {
-	struct snd_soc_card *card = dapm->card;
 	struct snd_soc_dapm_widget *w;
-	int reg, power;
+	int reg;
 	unsigned int value = 0;
 	unsigned int mask = 0;
-	unsigned int cur_mask;
 
 	reg = list_first_entry(pending, struct snd_soc_dapm_widget,
 			       power_list)->reg;
 
 	list_for_each_entry(w, pending, power_list) {
-		cur_mask = 1 << w->shift;
 		BUG_ON(reg != w->reg);
+		w->power = w->new_power;
 
-		if (w->invert)
-			power = !w->power;
+		mask |= w->mask << w->shift;
+		if (w->power)
+			value |= w->on_val << w->shift;
 		else
-			power = w->power;
+			value |= w->off_val << w->shift;
 
-		mask |= cur_mask;
-		if (power)
-			value |= cur_mask;
-
-		pop_dbg(dapm->dev, card->pop_time,
+		pop_dbg(w->dapm->dev, card->pop_time,
 			"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
 			w->name, reg, value, mask);
 
 		/* Check for events */
-		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
-		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
+		dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
+		dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
 	}
 
 	if (reg >= 0) {
@@ -1339,7 +1469,7 @@
 		w = list_first_entry(pending, struct snd_soc_dapm_widget,
 				     power_list);
 
-		pop_dbg(dapm->dev, card->pop_time,
+		pop_dbg(w->dapm->dev, card->pop_time,
 			"pop test : Applying 0x%x/0x%x to %x in %dms\n",
 			value, mask, reg, card->pop_time);
 		pop_wait(card->pop_time);
@@ -1347,8 +1477,8 @@
 	}
 
 	list_for_each_entry(w, pending, power_list) {
-		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
-		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
+		dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
+		dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
 	}
 }
 
@@ -1360,8 +1490,8 @@
  * Currently anything that requires more than a single write is not
  * handled.
  */
-static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
-			 struct list_head *list, int event, bool power_up)
+static void dapm_seq_run(struct snd_soc_card *card,
+	struct list_head *list, int event, bool power_up)
 {
 	struct snd_soc_dapm_widget *w, *n;
 	LIST_HEAD(pending);
@@ -1384,7 +1514,7 @@
 		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
 		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
 			if (!list_empty(&pending))
-				dapm_seq_run_coalesced(cur_dapm, &pending);
+				dapm_seq_run_coalesced(card, &pending);
 
 			if (cur_dapm && cur_dapm->seq_notifier) {
 				for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
@@ -1444,7 +1574,7 @@
 	}
 
 	if (!list_empty(&pending))
-		dapm_seq_run_coalesced(cur_dapm, &pending);
+		dapm_seq_run_coalesced(card, &pending);
 
 	if (cur_dapm && cur_dapm->seq_notifier) {
 		for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
@@ -1454,37 +1584,48 @@
 	}
 }
 
-static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
+static void dapm_widget_update(struct snd_soc_card *card)
 {
-	struct snd_soc_dapm_update *update = dapm->update;
-	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_update *update = card->update;
+	struct snd_soc_dapm_widget_list *wlist;
+	struct snd_soc_dapm_widget *w = NULL;
+	unsigned int wi;
 	int ret;
 
-	if (!update)
+	if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
 		return;
 
-	w = update->widget;
+	wlist = dapm_kcontrol_get_wlist(update->kcontrol);
 
-	if (w->event &&
-	    (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
-		ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
-		if (ret != 0)
-			dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
-			       w->name, ret);
+	for (wi = 0; wi < wlist->num_widgets; wi++) {
+		w = wlist->widgets[wi];
+
+		if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
+			ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
+			if (ret != 0)
+				dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
+					   w->name, ret);
+		}
 	}
 
+	if (!w)
+		return;
+
 	ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
 				  update->val);
 	if (ret < 0)
-		dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n",
+		dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
 			w->name, ret);
 
-	if (w->event &&
-	    (w->event_flags & SND_SOC_DAPM_POST_REG)) {
-		ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
-		if (ret != 0)
-			dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
-			       w->name, ret);
+	for (wi = 0; wi < wlist->num_widgets; wi++) {
+		w = wlist->widgets[wi];
+
+		if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
+			ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
+			if (ret != 0)
+				dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
+					   w->name, ret);
+		}
 	}
 }
 
@@ -1596,6 +1737,7 @@
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_clock_supply:
+	case snd_soc_dapm_kcontrol:
 		/* Supplies can't affect their outputs, only their inputs */
 		break;
 	default:
@@ -1612,8 +1754,6 @@
 		dapm_seq_insert(w, up_list, true);
 	else
 		dapm_seq_insert(w, down_list, false);
-
-	w->power = power;
 }
 
 static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
@@ -1647,9 +1787,8 @@
  *  o Input pin to Output pin (bypass, sidetone)
  *  o DAC to ADC (loopback).
  */
-static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
+static int dapm_power_widgets(struct snd_soc_card *card, int event)
 {
-	struct snd_soc_card *card = dapm->card;
 	struct snd_soc_dapm_widget *w;
 	struct snd_soc_dapm_context *d;
 	LIST_HEAD(up_list);
@@ -1689,7 +1828,7 @@
 			break;
 		}
 
-		if (w->power) {
+		if (w->new_power) {
 			d = w->dapm;
 
 			/* Supplies and micbiases only bring the
@@ -1731,29 +1870,29 @@
 	trace_snd_soc_dapm_walk_done(card);
 
 	/* Run all the bias changes in parallel */
-	list_for_each_entry(d, &dapm->card->dapm_list, list)
+	list_for_each_entry(d, &card->dapm_list, list)
 		async_schedule_domain(dapm_pre_sequence_async, d,
 					&async_domain);
 	async_synchronize_full_domain(&async_domain);
 
 	list_for_each_entry(w, &down_list, power_list) {
-		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+		dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
 	}
 
 	list_for_each_entry(w, &up_list, power_list) {
-		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+		dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
 	}
 
 	/* Power down widgets first; try to avoid amplifying pops. */
-	dapm_seq_run(dapm, &down_list, event, false);
+	dapm_seq_run(card, &down_list, event, false);
 
-	dapm_widget_update(dapm);
+	dapm_widget_update(card);
 
 	/* Now power up. */
-	dapm_seq_run(dapm, &up_list, event, true);
+	dapm_seq_run(card, &up_list, event, true);
 
 	/* Run all the bias changes in parallel */
-	list_for_each_entry(d, &dapm->card->dapm_list, list)
+	list_for_each_entry(d, &card->dapm_list, list)
 		async_schedule_domain(dapm_post_sequence_async, d,
 					&async_domain);
 	async_synchronize_full_domain(&async_domain);
@@ -1764,7 +1903,7 @@
 			d->stream_event(d, event);
 	}
 
-	pop_dbg(dapm->dev, card->pop_time,
+	pop_dbg(card->dev, card->pop_time,
 		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
 	pop_wait(card->pop_time);
 
@@ -1799,8 +1938,8 @@
 
 	if (w->reg >= 0)
 		ret += snprintf(buf + ret, PAGE_SIZE - ret,
-				" - R%d(0x%x) bit %d",
-				w->reg, w->reg, w->shift);
+				" - R%d(0x%x) mask 0x%x",
+				w->reg, w->reg, w->mask << w->shift);
 
 	ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
 
@@ -1937,22 +2076,14 @@
 #endif
 
 /* test and update the power status of a mux widget */
-static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_card *card,
 				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
 	struct snd_soc_dapm_path *path;
 	int found = 0;
 
-	if (widget->id != snd_soc_dapm_mux &&
-	    widget->id != snd_soc_dapm_virt_mux &&
-	    widget->id != snd_soc_dapm_value_mux)
-		return -ENODEV;
-
 	/* find dapm widget path assoc with kcontrol */
-	list_for_each_entry(path, &widget->dapm->card->paths, list) {
-		if (path->kcontrol != kcontrol)
-			continue;
-
+	dapm_kcontrol_for_each_path(path, kcontrol) {
 		if (!path->name || !e->texts[mux])
 			continue;
 
@@ -1967,73 +2098,68 @@
 						"mux disconnection");
 			path->connect = 0; /* old connection must be powered down */
 		}
+		dapm_mark_dirty(path->sink, "mux change");
 	}
 
-	if (found) {
-		dapm_mark_dirty(widget, "mux change");
-		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-	}
+	if (found)
+		dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
 
 	return found;
 }
 
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-		struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
+	struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
+	struct snd_soc_dapm_update *update)
 {
-	struct snd_soc_card *card = widget->dapm->card;
+	struct snd_soc_card *card = dapm->card;
 	int ret;
 
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-	ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+	card->update = update;
+	ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
+	card->update = NULL;
 	mutex_unlock(&card->dapm_mutex);
 	if (ret > 0)
-		soc_dpcm_runtime_update(widget);
+		soc_dpcm_runtime_update(card);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
 				   struct snd_kcontrol *kcontrol, int connect)
 {
 	struct snd_soc_dapm_path *path;
 	int found = 0;
 
-	if (widget->id != snd_soc_dapm_mixer &&
-	    widget->id != snd_soc_dapm_mixer_named_ctl &&
-	    widget->id != snd_soc_dapm_switch)
-		return -ENODEV;
-
 	/* find dapm widget path assoc with kcontrol */
-	list_for_each_entry(path, &widget->dapm->card->paths, list) {
-		if (path->kcontrol != kcontrol)
-			continue;
-
-		/* found, now check type */
+	dapm_kcontrol_for_each_path(path, kcontrol) {
 		found = 1;
 		path->connect = connect;
 		dapm_mark_dirty(path->source, "mixer connection");
+		dapm_mark_dirty(path->sink, "mixer update");
 	}
 
-	if (found) {
-		dapm_mark_dirty(widget, "mixer update");
-		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-	}
+	if (found)
+		dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
 
 	return found;
 }
 
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-				struct snd_kcontrol *kcontrol, int connect)
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
+	struct snd_kcontrol *kcontrol, int connect,
+	struct snd_soc_dapm_update *update)
 {
-	struct snd_soc_card *card = widget->dapm->card;
+	struct snd_soc_card *card = dapm->card;
 	int ret;
 
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-	ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+	card->update = update;
+	ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+	card->update = NULL;
 	mutex_unlock(&card->dapm_mutex);
 	if (ret > 0)
-		soc_dpcm_runtime_update(widget);
+		soc_dpcm_runtime_update(card);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
@@ -2112,6 +2238,7 @@
 {
 	list_del(&path->list_sink);
 	list_del(&path->list_source);
+	list_del(&path->list_kcontrol);
 	list_del(&path->list);
 	kfree(path);
 }
@@ -2206,24 +2333,130 @@
 		return 0;
 
 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-	ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+	ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
 	mutex_unlock(&dapm->card->dapm_mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
+	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
+	const char *control,
+	int (*connected)(struct snd_soc_dapm_widget *source,
+			 struct snd_soc_dapm_widget *sink))
+{
+	struct snd_soc_dapm_path *path;
+	int ret;
+
+	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
+	if (!path)
+		return -ENOMEM;
+
+	path->source = wsource;
+	path->sink = wsink;
+	path->connected = connected;
+	INIT_LIST_HEAD(&path->list);
+	INIT_LIST_HEAD(&path->list_kcontrol);
+	INIT_LIST_HEAD(&path->list_source);
+	INIT_LIST_HEAD(&path->list_sink);
+
+	/* check for external widgets */
+	if (wsink->id == snd_soc_dapm_input) {
+		if (wsource->id == snd_soc_dapm_micbias ||
+			wsource->id == snd_soc_dapm_mic ||
+			wsource->id == snd_soc_dapm_line ||
+			wsource->id == snd_soc_dapm_output)
+			wsink->ext = 1;
+	}
+	if (wsource->id == snd_soc_dapm_output) {
+		if (wsink->id == snd_soc_dapm_spk ||
+			wsink->id == snd_soc_dapm_hp ||
+			wsink->id == snd_soc_dapm_line ||
+			wsink->id == snd_soc_dapm_input)
+			wsource->ext = 1;
+	}
+
+	dapm_mark_dirty(wsource, "Route added");
+	dapm_mark_dirty(wsink, "Route added");
+
+	/* connect static paths */
+	if (control == NULL) {
+		list_add(&path->list, &dapm->card->paths);
+		list_add(&path->list_sink, &wsink->sources);
+		list_add(&path->list_source, &wsource->sinks);
+		path->connect = 1;
+		return 0;
+	}
+
+	/* connect dynamic paths */
+	switch (wsink->id) {
+	case snd_soc_dapm_adc:
+	case snd_soc_dapm_dac:
+	case snd_soc_dapm_pga:
+	case snd_soc_dapm_out_drv:
+	case snd_soc_dapm_input:
+	case snd_soc_dapm_output:
+	case snd_soc_dapm_siggen:
+	case snd_soc_dapm_micbias:
+	case snd_soc_dapm_vmid:
+	case snd_soc_dapm_pre:
+	case snd_soc_dapm_post:
+	case snd_soc_dapm_supply:
+	case snd_soc_dapm_regulator_supply:
+	case snd_soc_dapm_clock_supply:
+	case snd_soc_dapm_aif_in:
+	case snd_soc_dapm_aif_out:
+	case snd_soc_dapm_dai_in:
+	case snd_soc_dapm_dai_out:
+	case snd_soc_dapm_dai_link:
+	case snd_soc_dapm_kcontrol:
+		list_add(&path->list, &dapm->card->paths);
+		list_add(&path->list_sink, &wsink->sources);
+		list_add(&path->list_source, &wsource->sinks);
+		path->connect = 1;
+		return 0;
+	case snd_soc_dapm_mux:
+	case snd_soc_dapm_virt_mux:
+	case snd_soc_dapm_value_mux:
+		ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
+			&wsink->kcontrol_news[0]);
+		if (ret != 0)
+			goto err;
+		break;
+	case snd_soc_dapm_switch:
+	case snd_soc_dapm_mixer:
+	case snd_soc_dapm_mixer_named_ctl:
+		ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
+		if (ret != 0)
+			goto err;
+		break;
+	case snd_soc_dapm_hp:
+	case snd_soc_dapm_mic:
+	case snd_soc_dapm_line:
+	case snd_soc_dapm_spk:
+		list_add(&path->list, &dapm->card->paths);
+		list_add(&path->list_sink, &wsink->sources);
+		list_add(&path->list_source, &wsource->sinks);
+		path->connect = 0;
+		return 0;
+	}
+
+	return 0;
+err:
+	kfree(path);
+	return ret;
+}
+
 static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 				  const struct snd_soc_dapm_route *route)
 {
-	struct snd_soc_dapm_path *path;
 	struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
 	struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
 	const char *sink;
-	const char *control = route->control;
 	const char *source;
 	char prefixed_sink[80];
 	char prefixed_source[80];
-	int ret = 0;
+	int ret;
 
 	if (dapm->codec && dapm->codec->name_prefix) {
 		snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
@@ -2271,103 +2504,15 @@
 		return -ENODEV;
 	}
 
-	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
-	if (!path)
-		return -ENOMEM;
-
-	path->source = wsource;
-	path->sink = wsink;
-	path->connected = route->connected;
-	INIT_LIST_HEAD(&path->list);
-	INIT_LIST_HEAD(&path->list_source);
-	INIT_LIST_HEAD(&path->list_sink);
-
-	/* check for external widgets */
-	if (wsink->id == snd_soc_dapm_input) {
-		if (wsource->id == snd_soc_dapm_micbias ||
-			wsource->id == snd_soc_dapm_mic ||
-			wsource->id == snd_soc_dapm_line ||
-			wsource->id == snd_soc_dapm_output)
-			wsink->ext = 1;
-	}
-	if (wsource->id == snd_soc_dapm_output) {
-		if (wsink->id == snd_soc_dapm_spk ||
-			wsink->id == snd_soc_dapm_hp ||
-			wsink->id == snd_soc_dapm_line ||
-			wsink->id == snd_soc_dapm_input)
-			wsource->ext = 1;
-	}
-
-	/* connect static paths */
-	if (control == NULL) {
-		list_add(&path->list, &dapm->card->paths);
-		list_add(&path->list_sink, &wsink->sources);
-		list_add(&path->list_source, &wsource->sinks);
-		path->connect = 1;
-		return 0;
-	}
-
-	/* connect dynamic paths */
-	switch (wsink->id) {
-	case snd_soc_dapm_adc:
-	case snd_soc_dapm_dac:
-	case snd_soc_dapm_pga:
-	case snd_soc_dapm_out_drv:
-	case snd_soc_dapm_input:
-	case snd_soc_dapm_output:
-	case snd_soc_dapm_siggen:
-	case snd_soc_dapm_micbias:
-	case snd_soc_dapm_vmid:
-	case snd_soc_dapm_pre:
-	case snd_soc_dapm_post:
-	case snd_soc_dapm_supply:
-	case snd_soc_dapm_regulator_supply:
-	case snd_soc_dapm_clock_supply:
-	case snd_soc_dapm_aif_in:
-	case snd_soc_dapm_aif_out:
-	case snd_soc_dapm_dai_in:
-	case snd_soc_dapm_dai_out:
-	case snd_soc_dapm_dai_link:
-		list_add(&path->list, &dapm->card->paths);
-		list_add(&path->list_sink, &wsink->sources);
-		list_add(&path->list_source, &wsource->sinks);
-		path->connect = 1;
-		return 0;
-	case snd_soc_dapm_mux:
-	case snd_soc_dapm_virt_mux:
-	case snd_soc_dapm_value_mux:
-		ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
-			&wsink->kcontrol_news[0]);
-		if (ret != 0)
-			goto err;
-		break;
-	case snd_soc_dapm_switch:
-	case snd_soc_dapm_mixer:
-	case snd_soc_dapm_mixer_named_ctl:
-		ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
-		if (ret != 0)
-			goto err;
-		break;
-	case snd_soc_dapm_hp:
-	case snd_soc_dapm_mic:
-	case snd_soc_dapm_line:
-	case snd_soc_dapm_spk:
-		list_add(&path->list, &dapm->card->paths);
-		list_add(&path->list_sink, &wsink->sources);
-		list_add(&path->list_source, &wsource->sinks);
-		path->connect = 0;
-		return 0;
-	}
-
-	dapm_mark_dirty(wsource, "Route added");
-	dapm_mark_dirty(wsink, "Route added");
+	ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
+		route->connected);
+	if (ret)
+		goto err;
 
 	return 0;
-
 err:
 	dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
-		 source, control, sink);
-	kfree(path);
+		 source, route->control, sink);
 	return ret;
 }
 
@@ -2569,14 +2714,14 @@
  *
  * Returns 0 for success.
  */
-int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
+int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
 {
 	struct snd_soc_dapm_widget *w;
 	unsigned int val;
 
-	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 
-	list_for_each_entry(w, &dapm->card->widgets, list)
+	list_for_each_entry(w, &card->widgets, list)
 	{
 		if (w->new)
 			continue;
@@ -2586,7 +2731,7 @@
 						sizeof(struct snd_kcontrol *),
 						GFP_KERNEL);
 			if (!w->kcontrols) {
-				mutex_unlock(&dapm->card->dapm_mutex);
+				mutex_unlock(&card->dapm_mutex);
 				return -ENOMEM;
 			}
 		}
@@ -2612,12 +2757,9 @@
 
 		/* Read the initial power state from the device */
 		if (w->reg >= 0) {
-			val = soc_widget_read(w, w->reg);
-			val &= 1 << w->shift;
-			if (w->invert)
-				val = !val;
-
-			if (val)
+			val = soc_widget_read(w, w->reg) >> w->shift;
+			val &= w->mask;
+			if (val == w->on_val)
 				w->power = 1;
 		}
 
@@ -2627,8 +2769,8 @@
 		dapm_debugfs_add_widget(w);
 	}
 
-	dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
-	mutex_unlock(&dapm->card->dapm_mutex);
+	dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
+	mutex_unlock(&card->dapm_mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2645,8 +2787,8 @@
 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+	struct snd_soc_card *card = codec->card;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
@@ -2654,17 +2796,24 @@
 	int max = mc->max;
 	unsigned int mask = (1 << fls(max)) - 1;
 	unsigned int invert = mc->invert;
+	unsigned int val;
 
 	if (snd_soc_volsw_is_stereo(mc))
-		dev_warn(widget->dapm->dev,
+		dev_warn(codec->dapm.dev,
 			 "ASoC: Control '%s' is stereo, which is not supported\n",
 			 kcontrol->id.name);
 
-	ucontrol->value.integer.value[0] =
-		(snd_soc_read(widget->codec, reg) >> shift) & mask;
+	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+	if (dapm_kcontrol_is_powered(kcontrol))
+		val = (snd_soc_read(codec, reg) >> shift) & mask;
+	else
+		val = dapm_kcontrol_get_value(kcontrol);
+	mutex_unlock(&card->dapm_mutex);
+
 	if (invert)
-		ucontrol->value.integer.value[0] =
-			max - ucontrol->value.integer.value[0];
+		ucontrol->value.integer.value[0] = max - val;
+	else
+		ucontrol->value.integer.value[0] = val;
 
 	return 0;
 }
@@ -2682,9 +2831,7 @@
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct snd_soc_card *card = codec->card;
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
@@ -2696,10 +2843,9 @@
 	unsigned int val;
 	int connect, change;
 	struct snd_soc_dapm_update update;
-	int wi;
 
 	if (snd_soc_volsw_is_stereo(mc))
-		dev_warn(widget->dapm->dev,
+		dev_warn(codec->dapm.dev,
 			 "ASoC: Control '%s' is stereo, which is not supported\n",
 			 kcontrol->id.name);
 
@@ -2708,29 +2854,26 @@
 
 	if (invert)
 		val = max - val;
-	mask = mask << shift;
-	val = val << shift;
 
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-	change = snd_soc_test_bits(widget->codec, reg, mask, val);
+	dapm_kcontrol_set_value(kcontrol, val);
+
+	mask = mask << shift;
+	val = val << shift;
+
+	change = snd_soc_test_bits(codec, reg, mask, val);
 	if (change) {
-		for (wi = 0; wi < wlist->num_widgets; wi++) {
-			widget = wlist->widgets[wi];
+		update.kcontrol = kcontrol;
+		update.reg = reg;
+		update.mask = mask;
+		update.val = val;
 
-			widget->value = val;
+		card->update = &update;
 
-			update.kcontrol = kcontrol;
-			update.widget = widget;
-			update.reg = reg;
-			update.mask = mask;
-			update.val = val;
-			widget->dapm->update = &update;
+		soc_dapm_mixer_update_power(card, kcontrol, connect);
 
-			soc_dapm_mixer_update_power(widget, kcontrol, connect);
-
-			widget->dapm->update = NULL;
-		}
+		card->update = NULL;
 	}
 
 	mutex_unlock(&card->dapm_mutex);
@@ -2750,12 +2893,11 @@
 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val;
 
-	val = snd_soc_read(widget->codec, e->reg);
+	val = snd_soc_read(codec, e->reg);
 	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
 	if (e->shift_l != e->shift_r)
 		ucontrol->value.enumerated.item[1] =
@@ -2777,15 +2919,12 @@
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask;
 	struct snd_soc_dapm_update update;
-	int wi;
 
 	if (ucontrol->value.enumerated.item[0] > e->max - 1)
 		return -EINVAL;
@@ -2801,24 +2940,17 @@
 
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+	change = snd_soc_test_bits(codec, e->reg, mask, val);
 	if (change) {
-		for (wi = 0; wi < wlist->num_widgets; wi++) {
-			widget = wlist->widgets[wi];
+		update.kcontrol = kcontrol;
+		update.reg = e->reg;
+		update.mask = mask;
+		update.val = val;
+		card->update = &update;
 
-			widget->value = val;
+		soc_dapm_mux_update_power(card, kcontrol, mux, e);
 
-			update.kcontrol = kcontrol;
-			update.widget = widget;
-			update.reg = e->reg;
-			update.mask = mask;
-			update.val = val;
-			widget->dapm->update = &update;
-
-			soc_dapm_mux_update_power(widget, kcontrol, mux, e);
-
-			widget->dapm->update = NULL;
-		}
+		card->update = NULL;
 	}
 
 	mutex_unlock(&card->dapm_mutex);
@@ -2836,11 +2968,7 @@
 int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
-	ucontrol->value.enumerated.item[0] = widget->value;
-
+	ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
@@ -2855,30 +2983,22 @@
 int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
 			       struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct snd_soc_card *card = codec->card;
+	unsigned int value;
 	struct soc_enum *e =
 		(struct soc_enum *)kcontrol->private_value;
 	int change;
-	int wi;
 
 	if (ucontrol->value.enumerated.item[0] >= e->max)
 		return -EINVAL;
 
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-	change = widget->value != ucontrol->value.enumerated.item[0];
-	if (change) {
-		for (wi = 0; wi < wlist->num_widgets; wi++) {
-			widget = wlist->widgets[wi];
-
-			widget->value = ucontrol->value.enumerated.item[0];
-
-			soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
-		}
-	}
+	value = ucontrol->value.enumerated.item[0];
+	change = dapm_kcontrol_set_value(kcontrol, value);
+	if (change)
+		soc_dapm_mux_update_power(card, kcontrol, value, e);
 
 	mutex_unlock(&card->dapm_mutex);
 	return change;
@@ -2901,12 +3021,11 @@
 int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int reg_val, val, mux;
 
-	reg_val = snd_soc_read(widget->codec, e->reg);
+	reg_val = snd_soc_read(codec, e->reg);
 	val = (reg_val >> e->shift_l) & e->mask;
 	for (mux = 0; mux < e->max; mux++) {
 		if (val == e->values[mux])
@@ -2942,15 +3061,12 @@
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-	struct snd_soc_codec *codec = widget->codec;
+	struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
 	struct snd_soc_card *card = codec->card;
 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
 	unsigned int val, mux, change;
 	unsigned int mask;
 	struct snd_soc_dapm_update update;
-	int wi;
 
 	if (ucontrol->value.enumerated.item[0] > e->max - 1)
 		return -EINVAL;
@@ -2966,24 +3082,17 @@
 
 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+	change = snd_soc_test_bits(codec, e->reg, mask, val);
 	if (change) {
-		for (wi = 0; wi < wlist->num_widgets; wi++) {
-			widget = wlist->widgets[wi];
+		update.kcontrol = kcontrol;
+		update.reg = e->reg;
+		update.mask = mask;
+		update.val = val;
+		card->update = &update;
 
-			widget->value = val;
+		soc_dapm_mux_update_power(card, kcontrol, mux, e);
 
-			update.kcontrol = kcontrol;
-			update.widget = widget;
-			update.reg = e->reg;
-			update.mask = mask;
-			update.val = val;
-			widget->dapm->update = &update;
-
-			soc_dapm_mux_update_power(widget, kcontrol, mux, e);
-
-			widget->dapm->update = NULL;
-		}
+		card->update = NULL;
 	}
 
 	mutex_unlock(&card->dapm_mutex);
@@ -3080,7 +3189,7 @@
 			return NULL;
 		}
 
-		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
 			ret = regulator_allow_bypass(w->regulator, true);
 			if (ret != 0)
 				dev_warn(w->dapm->dev,
@@ -3127,16 +3236,16 @@
 	case snd_soc_dapm_value_mux:
 		w->power_check = dapm_generic_check_power;
 		break;
-	case snd_soc_dapm_adc:
-	case snd_soc_dapm_aif_out:
 	case snd_soc_dapm_dai_out:
 		w->power_check = dapm_adc_check_power;
 		break;
-	case snd_soc_dapm_dac:
-	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_dai_in:
 		w->power_check = dapm_dac_check_power;
 		break;
+	case snd_soc_dapm_adc:
+	case snd_soc_dapm_aif_out:
+	case snd_soc_dapm_dac:
+	case snd_soc_dapm_aif_in:
 	case snd_soc_dapm_pga:
 	case snd_soc_dapm_out_drv:
 	case snd_soc_dapm_input:
@@ -3152,6 +3261,7 @@
 	case snd_soc_dapm_supply:
 	case snd_soc_dapm_regulator_supply:
 	case snd_soc_dapm_clock_supply:
+	case snd_soc_dapm_kcontrol:
 		w->power_check = dapm_supply_check_power;
 		break;
 	default:
@@ -3416,9 +3526,6 @@
 {
 	struct snd_soc_dapm_widget *dai_w, *w;
 	struct snd_soc_dai *dai;
-	struct snd_soc_dapm_route r;
-
-	memset(&r, 0, sizeof(r));
 
 	/* For each DAI widget... */
 	list_for_each_entry(dai_w, &card->widgets, list) {
@@ -3445,29 +3552,27 @@
 				break;
 			}
 
-			if (!w->sname)
+			if (!w->sname || !strstr(w->sname, dai_w->name))
 				continue;
 
 			if (dai->driver->playback.stream_name &&
 			    strstr(w->sname,
 				   dai->driver->playback.stream_name)) {
-				r.source = dai->playback_widget->name;
-				r.sink = w->name;
 				dev_dbg(dai->dev, "%s -> %s\n",
-					 r.source, r.sink);
+					 dai->playback_widget->name, w->name);
 
-				snd_soc_dapm_add_route(w->dapm, &r);
+				snd_soc_dapm_add_path(w->dapm,
+					dai->playback_widget, w, NULL, NULL);
 			}
 
 			if (dai->driver->capture.stream_name &&
 			    strstr(w->sname,
 				   dai->driver->capture.stream_name)) {
-				r.source = w->name;
-				r.sink = dai->capture_widget->name;
 				dev_dbg(dai->dev, "%s -> %s\n",
-					r.source, r.sink);
+					w->name, dai->capture_widget->name);
 
-				snd_soc_dapm_add_route(w->dapm, &r);
+				snd_soc_dapm_add_path(w->dapm, w,
+					dai->capture_widget, NULL, NULL);
 			}
 		}
 	}
@@ -3529,7 +3634,7 @@
 		}
 	}
 
-	dapm_power_widgets(&rtd->card->dapm, event);
+	dapm_power_widgets(rtd->card, event);
 }
 
 /**
@@ -3798,7 +3903,7 @@
 		if (dapm->bias_level == SND_SOC_BIAS_ON)
 			snd_soc_dapm_set_bias_level(dapm,
 						    SND_SOC_BIAS_PREPARE);
-		dapm_seq_run(dapm, &down_list, 0, false);
+		dapm_seq_run(card, &down_list, 0, false);
 		if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
 			snd_soc_dapm_set_bias_level(dapm,
 						    SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 8ca9ecc..122c0c1 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -158,7 +158,7 @@
 		return -EINVAL;
 	}
 
-	return PTR_RET(codec->control_data);
+	return PTR_ERR_OR_ZERO(codec->control_data);
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
 #else
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 0bb5cccd..71358e3 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -183,8 +183,6 @@
 		list_add(&(pins[i].list), &jack->pins);
 	}
 
-	snd_soc_dapm_new_widgets(&jack->codec->card->dapm);
-
 	/* Update to reflect the last reported status; canned jack
 	 * implementations are likely to set their state before the
 	 * card has an opportunity to associate pins.
@@ -263,7 +261,7 @@
 	if (device_may_wakeup(dev))
 		pm_wakeup_event(dev, gpio->debounce_time + 50);
 
-	schedule_delayed_work(&gpio->work,
+	queue_delayed_work(system_power_efficient_wq, &gpio->work,
 			      msecs_to_jiffies(gpio->debounce_time));
 
 	return IRQ_HANDLED;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index b6c6403..330c9a6 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -411,8 +411,9 @@
 		} else {
 			/* start delayed pop wq here for playback streams */
 			rtd->pop_wait = 1;
-			schedule_delayed_work(&rtd->delayed_work,
-				msecs_to_jiffies(rtd->pmdown_time));
+			queue_delayed_work(system_power_efficient_wq,
+					   &rtd->delayed_work,
+					   msecs_to_jiffies(rtd->pmdown_time));
 		}
 	} else {
 		/* capture streams can be powered down now */
@@ -1832,18 +1833,10 @@
 /* Called by DAPM mixer/mux changes to update audio routing between PCMs and
  * any DAI links.
  */
-int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
+int soc_dpcm_runtime_update(struct snd_soc_card *card)
 {
-	struct snd_soc_card *card;
 	int i, old, new, paths;
 
-	if (widget->codec)
-		card = widget->codec->card;
-	else if (widget->platform)
-		card = widget->platform->card;
-	else
-		return -EINVAL;
-
 	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
 	for (i = 0; i < card->num_rtd; i++) {
 		struct snd_soc_dapm_widget_list *list;
@@ -2027,6 +2020,16 @@
 			capture = 1;
 	}
 
+	if (rtd->dai_link->playback_only) {
+		playback = 1;
+		capture = 0;
+	}
+
+	if (rtd->dai_link->capture_only) {
+		playback = 0;
+		capture = 1;
+	}
+
 	/* create the PCM */
 	if (rtd->dai_link->no_pcm) {
 		snprintf(new_name, sizeof(new_name), "(%s)",
diff --git a/sound/soc/spear/Kconfig b/sound/soc/spear/Kconfig
index 3567d73..0a53053 100644
--- a/sound/soc/spear/Kconfig
+++ b/sound/soc/spear/Kconfig
@@ -1,6 +1,6 @@
 config SND_SPEAR_SOC
 	tristate
-	select SND_SOC_DMAENGINE_PCM
+	select SND_DMAENGINE_PCM
 
 config SND_SPEAR_SPDIF_OUT
 	tristate
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 995b120..8fc653c 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,8 +1,8 @@
 config SND_SOC_TEGRA
 	tristate "SoC Audio for the Tegra System-on-Chip"
-	depends on ARCH_TEGRA && TEGRA20_APB_DMA
+	depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
 	select REGMAP_MMIO
-	select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	  Say Y or M here if you want support for SoC audio on Tegra.
 
@@ -61,7 +61,7 @@
 
 config SND_SOC_TEGRA_RT5640
 	tristate "SoC Audio support for Tegra boards using an RT5640 codec"
-	depends on SND_SOC_TEGRA && I2C
+	depends on SND_SOC_TEGRA && I2C && GPIOLIB
 	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
 	select SND_SOC_RT5640
@@ -71,7 +71,7 @@
 
 config SND_SOC_TEGRA_WM8753
 	tristate "SoC Audio support for Tegra boards using a WM8753 codec"
-	depends on SND_SOC_TEGRA && I2C
+	depends on SND_SOC_TEGRA && I2C && GPIOLIB
 	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
 	select SND_SOC_WM8753
@@ -81,7 +81,7 @@
 
 config SND_SOC_TEGRA_WM8903
 	tristate "SoC Audio support for Tegra boards using a WM8903 codec"
-	depends on SND_SOC_TEGRA && I2C
+	depends on SND_SOC_TEGRA && I2C && GPIOLIB
 	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
 	select SND_SOC_WM8903
@@ -92,7 +92,7 @@
 
 config SND_SOC_TEGRA_WM9712
 	tristate "SoC Audio support for Tegra boards using a WM9712 codec"
-	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+	depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && GPIOLIB
 	select SND_SOC_TEGRA20_AC97
 	select SND_SOC_WM9712
 	help
@@ -110,7 +110,7 @@
 
 config SND_SOC_TEGRA_ALC5632
 	tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-	depends on SND_SOC_TEGRA && I2C
+	depends on SND_SOC_TEGRA && I2C && GPIOLIB
 	select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
 	select SND_SOC_ALC5632
 	help
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 6c48662..ae27bcd 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -334,12 +334,6 @@
 	}
 
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(&pdev->dev, "No memory resource\n");
-		ret = -ENODEV;
-		goto err_clk_put;
-	}
-
 	regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(regs)) {
 		ret = PTR_ERR(regs);
@@ -432,8 +426,6 @@
 
 	return 0;
 
-err_unregister_pcm:
-	tegra_pcm_platform_unregister(&pdev->dev);
 err_unregister_component:
 	snd_soc_unregister_component(&pdev->dev);
 err_asoc_utils_fini:
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 48d05d9..c61ea3a 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -13,8 +13,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index 08794f9..4511c5a 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -99,6 +99,7 @@
 static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = {
 	SND_SOC_DAPM_HP("Headphones", NULL),
 	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
 };
 
 static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index f87fc53..8e774d1 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -28,8 +28,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 05c68aa..734bfcd 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -24,8 +24,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 4bcce8a..e0305a1 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -184,9 +184,6 @@
 	if (irq < 0)
 		return irq;
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r)
-		return -EBUSY;
-
 	drvdata->base = devm_ioremap_resource(&pdev->dev, r);
 	if (IS_ERR(drvdata->base))
 		return PTR_ERR(drvdata->base);
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 8f5cd00..178d1ba 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -52,6 +52,7 @@
 
 static struct snd_soc_card mop500_card = {
 	.name = "MOP500-card",
+	.owner = THIS_MODULE,
 	.probe = NULL,
 	.dai_link = mop500_dai_links,
 	.num_links = ARRAY_SIZE(mop500_dai_links),
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index b9defcd..780bf3f 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -346,10 +346,10 @@
 		if (!memcmp(version, known_fw_versions + i, 2))
 			return 0;
 
-	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "
+	snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %4ph. "
 			"please reconnect to power. if this failure "
 			"still happens, check your firmware installation.",
-			4, version);
+			version);
 	return -EINVAL;
 }
 
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 659950e..93e970f 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -418,6 +418,9 @@
 	struct snd_usb_endpoint *ep;
 	int is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
 
+	if (WARN_ON(!alts))
+		return NULL;
+
 	mutex_lock(&chip->mutex);
 
 	list_for_each_entry(ep, &chip->ep_list, list) {
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 15b151e..b375d58 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -327,6 +327,137 @@
 	return 0;
 }
 
+static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
+					 struct usb_device *dev,
+					 struct usb_interface_descriptor *altsd,
+					 unsigned int attr)
+{
+	struct usb_host_interface *alts;
+	struct usb_interface *iface;
+	unsigned int ep;
+
+	/* Implicit feedback sync EPs consumers are always playback EPs */
+	if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK)
+		return 0;
+
+	switch (subs->stream->chip->usb_id) {
+	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
+	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
+		ep = 0x81;
+		iface = usb_ifnum_to_if(dev, 3);
+
+		if (!iface || iface->num_altsetting == 0)
+			return -EINVAL;
+
+		alts = &iface->altsetting[1];
+		goto add_sync_ep;
+		break;
+	case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+	case USB_ID(0x0763, 0x2081):
+		ep = 0x81;
+		iface = usb_ifnum_to_if(dev, 2);
+
+		if (!iface || iface->num_altsetting == 0)
+			return -EINVAL;
+
+		alts = &iface->altsetting[1];
+		goto add_sync_ep;
+	}
+	if (attr == USB_ENDPOINT_SYNC_ASYNC &&
+	    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
+	    altsd->bInterfaceProtocol == 2 &&
+	    altsd->bNumEndpoints == 1 &&
+	    USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
+	    search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
+				      altsd->bAlternateSetting,
+				      &alts, &ep) >= 0) {
+		goto add_sync_ep;
+	}
+
+	/* No quirk */
+	return 0;
+
+add_sync_ep:
+	subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+						   alts, ep, !subs->direction,
+						   SND_USB_ENDPOINT_TYPE_DATA);
+	if (!subs->sync_endpoint)
+		return -EINVAL;
+
+	subs->data_endpoint->sync_master = subs->sync_endpoint;
+
+	return 0;
+}
+
+static int set_sync_endpoint(struct snd_usb_substream *subs,
+			     struct audioformat *fmt,
+			     struct usb_device *dev,
+			     struct usb_host_interface *alts,
+			     struct usb_interface_descriptor *altsd)
+{
+	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
+	unsigned int ep, attr;
+	bool implicit_fb;
+	int err;
+
+	/* we need a sync pipe in async OUT or adaptive IN mode */
+	/* check the number of EP, since some devices have broken
+	 * descriptors which fool us.  if it has only one EP,
+	 * assume it as adaptive-out or sync-in.
+	 */
+	attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
+
+	err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr);
+	if (err < 0)
+		return err;
+
+	if (altsd->bNumEndpoints < 2)
+		return 0;
+
+	if ((is_playback && attr != USB_ENDPOINT_SYNC_ASYNC) ||
+	    (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE))
+		return 0;
+
+	/* check sync-pipe endpoint */
+	/* ... and check descriptor size before accessing bSynchAddress
+	   because there is a version of the SB Audigy 2 NX firmware lacking
+	   the audio fields in the endpoint descriptors */
+	if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
+	    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+	     get_endpoint(alts, 1)->bSynchAddress != 0)) {
+		snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
+			   dev->devnum, fmt->iface, fmt->altsetting,
+			   get_endpoint(alts, 1)->bmAttributes,
+			   get_endpoint(alts, 1)->bLength,
+			   get_endpoint(alts, 1)->bSynchAddress);
+		return -EINVAL;
+	}
+	ep = get_endpoint(alts, 1)->bEndpointAddress;
+	if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+	    ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
+	     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
+		snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
+			   dev->devnum, fmt->iface, fmt->altsetting,
+			   is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
+		return -EINVAL;
+	}
+
+	implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
+			== USB_ENDPOINT_USAGE_IMPLICIT_FB;
+
+	subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+						   alts, ep, !subs->direction,
+						   implicit_fb ?
+							SND_USB_ENDPOINT_TYPE_DATA :
+							SND_USB_ENDPOINT_TYPE_SYNC);
+	if (!subs->sync_endpoint)
+		return -EINVAL;
+
+	subs->data_endpoint->sync_master = subs->sync_endpoint;
+
+	return 0;
+}
+
 /*
  * find a matching format and set up the interface
  */
@@ -336,9 +467,7 @@
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
 	struct usb_interface *iface;
-	unsigned int ep, attr;
-	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-	int err, implicit_fb = 0;
+	int err;
 
 	iface = usb_ifnum_to_if(dev, fmt->iface);
 	if (WARN_ON(!iface))
@@ -383,118 +512,22 @@
 	subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
 						   alts, fmt->endpoint, subs->direction,
 						   SND_USB_ENDPOINT_TYPE_DATA);
+
 	if (!subs->data_endpoint)
 		return -EINVAL;
 
-	/* we need a sync pipe in async OUT or adaptive IN mode */
-	/* check the number of EP, since some devices have broken
-	 * descriptors which fool us.  if it has only one EP,
-	 * assume it as adaptive-out or sync-in.
-	 */
-	attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
+	err = set_sync_endpoint(subs, fmt, dev, alts, altsd);
+	if (err < 0)
+		return err;
 
-	switch (subs->stream->chip->usb_id) {
-	case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
-	case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
-		if (is_playback) {
-			implicit_fb = 1;
-			ep = 0x81;
-			iface = usb_ifnum_to_if(dev, 3);
-
-			if (!iface || iface->num_altsetting == 0)
-				return -EINVAL;
-
-			alts = &iface->altsetting[1];
-			goto add_sync_ep;
-		}
-		break;
-	case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
-	case USB_ID(0x0763, 0x2081):
-		if (is_playback) {
-			implicit_fb = 1;
-			ep = 0x81;
-			iface = usb_ifnum_to_if(dev, 2);
-
-			if (!iface || iface->num_altsetting == 0)
-				return -EINVAL;
-
-			alts = &iface->altsetting[1];
-			goto add_sync_ep;
-		}
-	}
-	if (is_playback &&
-	    attr == USB_ENDPOINT_SYNC_ASYNC &&
-	    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
-	    altsd->bInterfaceProtocol == 2 &&
-	    altsd->bNumEndpoints == 1 &&
-	    USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
-	    search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
-				      altsd->bAlternateSetting,
-				      &alts, &ep) >= 0) {
-		implicit_fb = 1;
-		goto add_sync_ep;
-	}
-
-	if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
-	     (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
-	    altsd->bNumEndpoints >= 2) {
-		/* check sync-pipe endpoint */
-		/* ... and check descriptor size before accessing bSynchAddress
-		   because there is a version of the SB Audigy 2 NX firmware lacking
-		   the audio fields in the endpoint descriptors */
-		if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC ||
-		    (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-		     get_endpoint(alts, 1)->bSynchAddress != 0 &&
-		     !implicit_fb)) {
-			snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n",
-				   dev->devnum, fmt->iface, fmt->altsetting,
-				   get_endpoint(alts, 1)->bmAttributes,
-				   get_endpoint(alts, 1)->bLength,
-				   get_endpoint(alts, 1)->bSynchAddress);
-			return -EINVAL;
-		}
-		ep = get_endpoint(alts, 1)->bEndpointAddress;
-		if (!implicit_fb &&
-		    get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
-		    (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
-		     (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
-			snd_printk(KERN_ERR "%d:%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n",
-				   dev->devnum, fmt->iface, fmt->altsetting,
-				   is_playback, ep, get_endpoint(alts, 0)->bSynchAddress);
-			return -EINVAL;
-		}
-
-		implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
-				== USB_ENDPOINT_USAGE_IMPLICIT_FB;
-
-add_sync_ep:
-		subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
-							   alts, ep, !subs->direction,
-							   implicit_fb ?
-								SND_USB_ENDPOINT_TYPE_DATA :
-								SND_USB_ENDPOINT_TYPE_SYNC);
-		if (!subs->sync_endpoint)
-			return -EINVAL;
-
-		subs->data_endpoint->sync_master = subs->sync_endpoint;
-	}
-
-	if ((err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt)) < 0)
+	err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt);
+	if (err < 0)
 		return err;
 
 	subs->cur_audiofmt = fmt;
 
 	snd_usb_set_format_quirk(subs, fmt);
 
-#if 0
-	printk(KERN_DEBUG
-	       "setting done: format = %d, rate = %d..%d, channels = %d\n",
-	       fmt->format, fmt->rate_min, fmt->rate_max, fmt->channels);
-	printk(KERN_DEBUG
-	       "  datapipe = 0x%0x, syncpipe = 0x%0x\n",
-	       subs->datapipe, subs->syncpipe);
-#endif
-
 	return 0;
 }
 
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 1f9bbd5..5a51b18 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -305,11 +305,9 @@
 {
 	int	i;
 	for (i = 0; i < URBS_AsyncSeq; ++i) {
-		if (S[i].urb) {
-			usb_kill_urb(S->urb[i]);
-			usb_free_urb(S->urb[i]);
-			S->urb[i] = NULL;
-		}
+		usb_kill_urb(S->urb[i]);
+		usb_free_urb(S->urb[i]);
+		S->urb[i] = NULL;
 	}
 	kfree(S->buffer);
 }
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 07819bf..8fd9ec6 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -79,8 +79,6 @@
 	DNS
 };
 
-static char kvp_send_buffer[4096];
-static char kvp_recv_buffer[4096 * 2];
 static struct sockaddr_nl addr;
 static int in_hand_shake = 1;
 
@@ -1301,6 +1299,7 @@
 	}
 
 	error = kvp_write_file(file, "HWADDR", "", mac_addr);
+	free(mac_addr);
 	if (error)
 		goto setval_error;
 
@@ -1346,7 +1345,6 @@
 		goto setval_error;
 
 setval_done:
-	free(mac_addr);
 	fclose(file);
 
 	/*
@@ -1355,12 +1353,15 @@
 	 */
 
 	snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
-	system(cmd);
+	if (system(cmd)) {
+		syslog(LOG_ERR, "Failed to execute cmd '%s'; error: %d %s",
+				cmd, errno, strerror(errno));
+		return HV_E_FAIL;
+	}
 	return 0;
 
 setval_error:
 	syslog(LOG_ERR, "Failed to write config file");
-	free(mac_addr);
 	fclose(file);
 	return error;
 }
@@ -1391,23 +1392,18 @@
 static int
 netlink_send(int fd, struct cn_msg *msg)
 {
-	struct nlmsghdr *nlh;
+	struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
 	unsigned int size;
 	struct msghdr message;
-	char buffer[64];
 	struct iovec iov[2];
 
-	size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+	size = sizeof(struct cn_msg) + msg->len;
 
-	nlh = (struct nlmsghdr *)buffer;
-	nlh->nlmsg_seq = 0;
-	nlh->nlmsg_pid = getpid();
-	nlh->nlmsg_type = NLMSG_DONE;
-	nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
-	nlh->nlmsg_flags = 0;
+	nlh.nlmsg_pid = getpid();
+	nlh.nlmsg_len = NLMSG_LENGTH(size);
 
-	iov[0].iov_base = nlh;
-	iov[0].iov_len = sizeof(*nlh);
+	iov[0].iov_base = &nlh;
+	iov[0].iov_len = sizeof(nlh);
 
 	iov[1].iov_base = msg;
 	iov[1].iov_len = size;
@@ -1437,10 +1433,22 @@
 	int	pool;
 	char	*if_name;
 	struct hv_kvp_ipaddr_value *kvp_ip_val;
+	char *kvp_send_buffer;
+	char *kvp_recv_buffer;
+	size_t kvp_recv_buffer_len;
 
-	daemon(1, 0);
+	if (daemon(1, 0))
+		return 1;
 	openlog("KVP", 0, LOG_USER);
 	syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
+
+	kvp_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_kvp_msg);
+	kvp_send_buffer = calloc(1, kvp_recv_buffer_len);
+	kvp_recv_buffer = calloc(1, kvp_recv_buffer_len);
+	if (!(kvp_send_buffer && kvp_recv_buffer)) {
+		syslog(LOG_ERR, "Failed to allocate netlink buffers");
+		exit(EXIT_FAILURE);
+	}
 	/*
 	 * Retrieve OS release information.
 	 */
@@ -1514,7 +1522,7 @@
 				continue;
 		}
 
-		len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
+		len = recvfrom(fd, kvp_recv_buffer, kvp_recv_buffer_len, 0,
 				addr_p, &addr_l);
 
 		if (len < 0) {
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
index fea03a3..8611962 100644
--- a/tools/hv/hv_vss_daemon.c
+++ b/tools/hv/hv_vss_daemon.c
@@ -38,8 +38,6 @@
 #include <linux/netlink.h>
 #include <syslog.h>
 
-static char vss_recv_buffer[4096];
-static char vss_send_buffer[4096];
 static struct sockaddr_nl addr;
 
 #ifndef SOL_NETLINK
@@ -107,23 +105,18 @@
 
 static int netlink_send(int fd, struct cn_msg *msg)
 {
-	struct nlmsghdr *nlh;
+	struct nlmsghdr nlh = { .nlmsg_type = NLMSG_DONE };
 	unsigned int size;
 	struct msghdr message;
-	char buffer[64];
 	struct iovec iov[2];
 
-	size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+	size = sizeof(struct cn_msg) + msg->len;
 
-	nlh = (struct nlmsghdr *)buffer;
-	nlh->nlmsg_seq = 0;
-	nlh->nlmsg_pid = getpid();
-	nlh->nlmsg_type = NLMSG_DONE;
-	nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
-	nlh->nlmsg_flags = 0;
+	nlh.nlmsg_pid = getpid();
+	nlh.nlmsg_len = NLMSG_LENGTH(size);
 
-	iov[0].iov_base = nlh;
-	iov[0].iov_len = sizeof(*nlh);
+	iov[0].iov_base = &nlh;
+	iov[0].iov_len = sizeof(nlh);
 
 	iov[1].iov_base = msg;
 	iov[1].iov_len = size;
@@ -147,6 +140,9 @@
 	struct cn_msg	*incoming_cn_msg;
 	int	op;
 	struct hv_vss_msg *vss_msg;
+	char *vss_send_buffer;
+	char *vss_recv_buffer;
+	size_t vss_recv_buffer_len;
 
 	if (daemon(1, 0))
 		return 1;
@@ -154,9 +150,18 @@
 	openlog("Hyper-V VSS", 0, LOG_USER);
 	syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
 
+	vss_recv_buffer_len = NLMSG_HDRLEN + sizeof(struct cn_msg) + sizeof(struct hv_vss_msg);
+	vss_send_buffer = calloc(1, vss_recv_buffer_len);
+	vss_recv_buffer = calloc(1, vss_recv_buffer_len);
+	if (!(vss_send_buffer && vss_recv_buffer)) {
+		syslog(LOG_ERR, "Failed to allocate netlink buffers");
+		exit(EXIT_FAILURE);
+	}
+
 	fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
 	if (fd < 0) {
-		syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
+		syslog(LOG_ERR, "netlink socket creation failed; error:%d %s",
+				errno, strerror(errno));
 		exit(EXIT_FAILURE);
 	}
 	addr.nl_family = AF_NETLINK;
@@ -167,12 +172,16 @@
 
 	error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
 	if (error < 0) {
-		syslog(LOG_ERR, "bind failed; error:%d", error);
+		syslog(LOG_ERR, "bind failed; error:%d %s", errno, strerror(errno));
 		close(fd);
 		exit(EXIT_FAILURE);
 	}
 	nl_group = CN_VSS_IDX;
-	setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
+	if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group)) < 0) {
+		syslog(LOG_ERR, "setsockopt failed; error:%d %s", errno, strerror(errno));
+		close(fd);
+		exit(EXIT_FAILURE);
+	}
 	/*
 	 * Register ourselves with the kernel.
 	 */
@@ -187,7 +196,7 @@
 
 	len = netlink_send(fd, message);
 	if (len < 0) {
-		syslog(LOG_ERR, "netlink_send failed; error:%d", len);
+		syslog(LOG_ERR, "netlink_send failed; error:%d %s", errno, strerror(errno));
 		close(fd);
 		exit(EXIT_FAILURE);
 	}
@@ -199,9 +208,18 @@
 		socklen_t addr_l = sizeof(addr);
 		pfd.events = POLLIN;
 		pfd.revents = 0;
-		poll(&pfd, 1, -1);
 
-		len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
+		if (poll(&pfd, 1, -1) < 0) {
+			syslog(LOG_ERR, "poll failed; error:%d %s", errno, strerror(errno));
+			if (errno == EINVAL) {
+				close(fd);
+				exit(EXIT_FAILURE);
+			}
+			else
+				continue;
+		}
+
+		len = recvfrom(fd, vss_recv_buffer, vss_recv_buffer_len, 0,
 				addr_p, &addr_l);
 
 		if (len < 0) {
@@ -241,7 +259,8 @@
 		vss_msg->error = error;
 		len = netlink_send(fd, incoming_cn_msg);
 		if (len < 0) {
-			syslog(LOG_ERR, "net_link send failed; error:%d", len);
+			syslog(LOG_ERR, "net_link send failed; error:%d %s",
+					errno, strerror(errno));
 			exit(EXIT_FAILURE);
 		}
 	}
diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile
index 280dd82..3dba0a4 100644
--- a/tools/lib/lk/Makefile
+++ b/tools/lib/lk/Makefile
@@ -3,21 +3,6 @@
 CC = $(CROSS_COMPILE)gcc
 AR = $(CROSS_COMPILE)ar
 
-# Makefiles suck: This macro sets a default value of $(2) for the
-# variable named by $(1), unless the variable has been set by
-# environment or command line. This is necessary for CC and AR
-# because make sets default values, so the simpler ?= approach
-# won't work as expected.
-define allow-override
-  $(if $(or $(findstring environment,$(origin $(1))),\
-            $(findstring command line,$(origin $(1)))),,\
-    $(eval $(1) = $(2)))
-endef
-
-# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
-$(call allow-override,CC,$(CROSS_COMPILE)gcc)
-$(call allow-override,AR,$(CROSS_COMPILE)ar)
-
 # guard against environment variables
 LIB_H=
 LIB_OBJS=
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 0b0a907..ca6cb77 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -39,13 +39,8 @@
 bindir = $(prefix)/$(bindir_relative)
 man_dir = $(prefix)/share/man
 man_dir_SQ = '$(subst ','\'',$(man_dir))'
-html_install = $(prefix)/share/kernelshark/html
-html_install_SQ = '$(subst ','\'',$(html_install))'
-img_install = $(prefix)/share/kernelshark/html/images
-img_install_SQ = '$(subst ','\'',$(img_install))'
 
-export man_dir man_dir_SQ html_install html_install_SQ INSTALL
-export img_install img_install_SQ
+export man_dir man_dir_SQ INSTALL
 export DESTDIR DESTDIR_SQ
 
 # copy a bit from Linux kbuild
@@ -65,7 +60,7 @@
 ifneq ($(BUILD_OUTPUT),)
 
 define build_output
-	$(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) 	\
+	$(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) 	\
 	BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
 endef
 
@@ -76,10 +71,7 @@
 
 all: sub-make
 
-gui: force
-	$(call build_output, all_cmd)
-
-$(filter-out gui,$(MAKECMDGOALS)): sub-make
+$(MAKECMDGOALS): sub-make
 
 sub-make: force
 	$(call build_output, $(MAKECMDGOALS))
@@ -189,6 +181,7 @@
 	$(Q)$(call do_compile)
 
 PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
+PEVENT_LIB_OBJS += kbuffer-parse.o
 
 ALL_OBJS = $(PEVENT_LIB_OBJS)
 
@@ -258,9 +251,6 @@
 		$(RM) $@.$$$$
 endef
 
-$(gui_deps): ks_version.h
-$(non_gui_deps): tc_version.h
-
 $(all_deps): .%.d: $(src)/%.c
 	$(Q)$(call check_deps)
 
@@ -300,7 +290,7 @@
 	$(INSTALL) $1 '$(DESTDIR_SQ)$2'
 endef
 
-install_lib: all_cmd install_plugins install_python
+install_lib: all_cmd
 	$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
 
 install: install_lib
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 82b0606..d1c2a6a 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -5450,10 +5450,9 @@
  * If @id is >= 0, then it is used to find the event.
  * else @sys_name and @event_name are used.
  */
-int pevent_register_event_handler(struct pevent *pevent,
-				  int id, char *sys_name, char *event_name,
-				  pevent_event_handler_func func,
-				  void *context)
+int pevent_register_event_handler(struct pevent *pevent, int id,
+				  const char *sys_name, const char *event_name,
+				  pevent_event_handler_func func, void *context)
 {
 	struct event_format *event;
 	struct event_handler *handle;
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 7be7e89..c37b202 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -69,6 +69,7 @@
 };
 
 void trace_seq_init(struct trace_seq *s);
+void trace_seq_reset(struct trace_seq *s);
 void trace_seq_destroy(struct trace_seq *s);
 
 extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
@@ -399,6 +400,7 @@
 
 	int cpus;
 	int long_size;
+	int page_size;
 
 	struct cmdline *cmdlines;
 	struct cmdline_list *cmdlist;
@@ -561,7 +563,8 @@
 			   struct event_format *event, const char *name,
 			   struct pevent_record *record, int err);
 
-int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
+int pevent_register_event_handler(struct pevent *pevent, int id,
+				  const char *sys_name, const char *event_name,
 				  pevent_event_handler_func func, void *context);
 int pevent_register_print_function(struct pevent *pevent,
 				   pevent_func_handler func,
@@ -619,6 +622,16 @@
 	pevent->long_size = long_size;
 }
 
+static inline int pevent_get_page_size(struct pevent *pevent)
+{
+	return pevent->page_size;
+}
+
+static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
+{
+	pevent->page_size = _page_size;
+}
+
 static inline int pevent_is_file_bigendian(struct pevent *pevent)
 {
 	return pevent->file_bigendian;
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
new file mode 100644
index 0000000..dcc6652
--- /dev/null
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -0,0 +1,732 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program 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;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "kbuffer.h"
+
+#define MISSING_EVENTS (1 << 31)
+#define MISSING_STORED (1 << 30)
+
+#define COMMIT_MASK ((1 << 27) - 1)
+
+enum {
+	KBUFFER_FL_HOST_BIG_ENDIAN	= (1<<0),
+	KBUFFER_FL_BIG_ENDIAN		= (1<<1),
+	KBUFFER_FL_LONG_8		= (1<<2),
+	KBUFFER_FL_OLD_FORMAT		= (1<<3),
+};
+
+#define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN)
+
+/** kbuffer
+ * @timestamp		- timestamp of current event
+ * @lost_events		- # of lost events between this subbuffer and previous
+ * @flags		- special flags of the kbuffer
+ * @subbuffer		- pointer to the sub-buffer page
+ * @data		- pointer to the start of data on the sub-buffer page
+ * @index		- index from @data to the @curr event data
+ * @curr		- offset from @data to the start of current event
+ *			   (includes metadata)
+ * @next		- offset from @data to the start of next event
+ * @size		- The size of data on @data
+ * @start		- The offset from @subbuffer where @data lives
+ *
+ * @read_4		- Function to read 4 raw bytes (may swap)
+ * @read_8		- Function to read 8 raw bytes (may swap)
+ * @read_long		- Function to read a long word (4 or 8 bytes with needed swap)
+ */
+struct kbuffer {
+	unsigned long long 	timestamp;
+	long long		lost_events;
+	unsigned long		flags;
+	void			*subbuffer;
+	void			*data;
+	unsigned int		index;
+	unsigned int		curr;
+	unsigned int		next;
+	unsigned int		size;
+	unsigned int		start;
+
+	unsigned int (*read_4)(void *ptr);
+	unsigned long long (*read_8)(void *ptr);
+	unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr);
+	int (*next_event)(struct kbuffer *kbuf);
+};
+
+static void *zmalloc(size_t size)
+{
+	return calloc(1, size);
+}
+
+static int host_is_bigendian(void)
+{
+	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
+	unsigned int *ptr;
+
+	ptr = (unsigned int *)str;
+	return *ptr == 0x01020304;
+}
+
+static int do_swap(struct kbuffer *kbuf)
+{
+	return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
+		ENDIAN_MASK;
+}
+
+static unsigned long long __read_8(void *ptr)
+{
+	unsigned long long data = *(unsigned long long *)ptr;
+
+	return data;
+}
+
+static unsigned long long __read_8_sw(void *ptr)
+{
+	unsigned long long data = *(unsigned long long *)ptr;
+	unsigned long long swap;
+
+	swap = ((data & 0xffULL) << 56) |
+		((data & (0xffULL << 8)) << 40) |
+		((data & (0xffULL << 16)) << 24) |
+		((data & (0xffULL << 24)) << 8) |
+		((data & (0xffULL << 32)) >> 8) |
+		((data & (0xffULL << 40)) >> 24) |
+		((data & (0xffULL << 48)) >> 40) |
+		((data & (0xffULL << 56)) >> 56);
+
+	return swap;
+}
+
+static unsigned int __read_4(void *ptr)
+{
+	unsigned int data = *(unsigned int *)ptr;
+
+	return data;
+}
+
+static unsigned int __read_4_sw(void *ptr)
+{
+	unsigned int data = *(unsigned int *)ptr;
+	unsigned int swap;
+
+	swap = ((data & 0xffULL) << 24) |
+		((data & (0xffULL << 8)) << 8) |
+		((data & (0xffULL << 16)) >> 8) |
+		((data & (0xffULL << 24)) >> 24);
+
+	return swap;
+}
+
+static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
+{
+	return kbuf->read_8(ptr);
+}
+
+static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
+{
+	return kbuf->read_4(ptr);
+}
+
+static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
+{
+	return kbuf->read_8(ptr);
+}
+
+static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
+{
+	return kbuf->read_4(ptr);
+}
+
+static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
+{
+	return kbuf->read_long(kbuf, ptr);
+}
+
+static int calc_index(struct kbuffer *kbuf, void *ptr)
+{
+	return (unsigned long)ptr - (unsigned long)kbuf->data;
+}
+
+static int __next_event(struct kbuffer *kbuf);
+
+/**
+ * kbuffer_alloc - allocat a new kbuffer
+ * @size;	enum to denote size of word
+ * @endian:	enum to denote endianness
+ *
+ * Allocates and returns a new kbuffer.
+ */
+struct kbuffer *
+kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian)
+{
+	struct kbuffer *kbuf;
+	int flags = 0;
+
+	switch (size) {
+	case KBUFFER_LSIZE_4:
+		break;
+	case KBUFFER_LSIZE_8:
+		flags |= KBUFFER_FL_LONG_8;
+		break;
+	default:
+		return NULL;
+	}
+
+	switch (endian) {
+	case KBUFFER_ENDIAN_LITTLE:
+		break;
+	case KBUFFER_ENDIAN_BIG:
+		flags |= KBUFFER_FL_BIG_ENDIAN;
+		break;
+	default:
+		return NULL;
+	}
+
+	kbuf = zmalloc(sizeof(*kbuf));
+	if (!kbuf)
+		return NULL;
+
+	kbuf->flags = flags;
+
+	if (host_is_bigendian())
+		kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
+
+	if (do_swap(kbuf)) {
+		kbuf->read_8 = __read_8_sw;
+		kbuf->read_4 = __read_4_sw;
+	} else {
+		kbuf->read_8 = __read_8;
+		kbuf->read_4 = __read_4;
+	}
+
+	if (kbuf->flags & KBUFFER_FL_LONG_8)
+		kbuf->read_long = __read_long_8;
+	else
+		kbuf->read_long = __read_long_4;
+
+	/* May be changed by kbuffer_set_old_format() */
+	kbuf->next_event = __next_event;
+
+	return kbuf;
+}
+
+/** kbuffer_free - free an allocated kbuffer
+ * @kbuf:	The kbuffer to free
+ *
+ * Can take NULL as a parameter.
+ */
+void kbuffer_free(struct kbuffer *kbuf)
+{
+	free(kbuf);
+}
+
+static unsigned int type4host(struct kbuffer *kbuf,
+			      unsigned int type_len_ts)
+{
+	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+		return (type_len_ts >> 29) & 3;
+	else
+		return type_len_ts & 3;
+}
+
+static unsigned int len4host(struct kbuffer *kbuf,
+			     unsigned int type_len_ts)
+{
+	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+		return (type_len_ts >> 27) & 7;
+	else
+		return (type_len_ts >> 2) & 7;
+}
+
+static unsigned int type_len4host(struct kbuffer *kbuf,
+				  unsigned int type_len_ts)
+{
+	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+		return (type_len_ts >> 27) & ((1 << 5) - 1);
+	else
+		return type_len_ts & ((1 << 5) - 1);
+}
+
+static unsigned int ts4host(struct kbuffer *kbuf,
+			    unsigned int type_len_ts)
+{
+	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
+		return type_len_ts & ((1 << 27) - 1);
+	else
+		return type_len_ts >> 5;
+}
+
+/*
+ * Linux 2.6.30 and earlier (not much ealier) had a different
+ * ring buffer format. It should be obsolete, but we handle it anyway.
+ */
+enum old_ring_buffer_type {
+	OLD_RINGBUF_TYPE_PADDING,
+	OLD_RINGBUF_TYPE_TIME_EXTEND,
+	OLD_RINGBUF_TYPE_TIME_STAMP,
+	OLD_RINGBUF_TYPE_DATA,
+};
+
+static unsigned int old_update_pointers(struct kbuffer *kbuf)
+{
+	unsigned long long extend;
+	unsigned int type_len_ts;
+	unsigned int type;
+	unsigned int len;
+	unsigned int delta;
+	unsigned int length;
+	void *ptr = kbuf->data + kbuf->curr;
+
+	type_len_ts = read_4(kbuf, ptr);
+	ptr += 4;
+
+	type = type4host(kbuf, type_len_ts);
+	len = len4host(kbuf, type_len_ts);
+	delta = ts4host(kbuf, type_len_ts);
+
+	switch (type) {
+	case OLD_RINGBUF_TYPE_PADDING:
+		kbuf->next = kbuf->size;
+		return 0;
+
+	case OLD_RINGBUF_TYPE_TIME_EXTEND:
+		extend = read_4(kbuf, ptr);
+		extend <<= TS_SHIFT;
+		extend += delta;
+		delta = extend;
+		ptr += 4;
+		break;
+
+	case OLD_RINGBUF_TYPE_TIME_STAMP:
+		/* should never happen! */
+		kbuf->curr = kbuf->size;
+		kbuf->next = kbuf->size;
+		kbuf->index = kbuf->size;
+		return -1;
+	default:
+		if (len)
+			length = len * 4;
+		else {
+			length = read_4(kbuf, ptr);
+			length -= 4;
+			ptr += 4;
+		}
+		break;
+	}
+
+	kbuf->timestamp += delta;
+	kbuf->index = calc_index(kbuf, ptr);
+	kbuf->next = kbuf->index + length;
+
+	return type;
+}
+
+static int __old_next_event(struct kbuffer *kbuf)
+{
+	int type;
+
+	do {
+		kbuf->curr = kbuf->next;
+		if (kbuf->next >= kbuf->size)
+			return -1;
+		type = old_update_pointers(kbuf);
+	} while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING);
+
+	return 0;
+}
+
+static unsigned int
+translate_data(struct kbuffer *kbuf, void *data, void **rptr,
+	       unsigned long long *delta, int *length)
+{
+	unsigned long long extend;
+	unsigned int type_len_ts;
+	unsigned int type_len;
+
+	type_len_ts = read_4(kbuf, data);
+	data += 4;
+
+	type_len = type_len4host(kbuf, type_len_ts);
+	*delta = ts4host(kbuf, type_len_ts);
+
+	switch (type_len) {
+	case KBUFFER_TYPE_PADDING:
+		*length = read_4(kbuf, data);
+		data += *length;
+		break;
+
+	case KBUFFER_TYPE_TIME_EXTEND:
+		extend = read_4(kbuf, data);
+		data += 4;
+		extend <<= TS_SHIFT;
+		extend += *delta;
+		*delta = extend;
+		*length = 0;
+		break;
+
+	case KBUFFER_TYPE_TIME_STAMP:
+		data += 12;
+		*length = 0;
+		break;
+	case 0:
+		*length = read_4(kbuf, data) - 4;
+		*length = (*length + 3) & ~3;
+		data += 4;
+		break;
+	default:
+		*length = type_len * 4;
+		break;
+	}
+
+	*rptr = data;
+
+	return type_len;
+}
+
+static unsigned int update_pointers(struct kbuffer *kbuf)
+{
+	unsigned long long delta;
+	unsigned int type_len;
+	int length;
+	void *ptr = kbuf->data + kbuf->curr;
+
+	type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
+
+	kbuf->timestamp += delta;
+	kbuf->index = calc_index(kbuf, ptr);
+	kbuf->next = kbuf->index + length;
+
+	return type_len;
+}
+
+/**
+ * kbuffer_translate_data - read raw data to get a record
+ * @swap:	Set to 1 if bytes in words need to be swapped when read
+ * @data:	The raw data to read
+ * @size:	Address to store the size of the event data.
+ *
+ * Returns a pointer to the event data. To determine the entire
+ * record size (record metadata + data) just add the difference between
+ * @data and the returned value to @size.
+ */
+void *kbuffer_translate_data(int swap, void *data, unsigned int *size)
+{
+	unsigned long long delta;
+	struct kbuffer kbuf;
+	int type_len;
+	int length;
+	void *ptr;
+
+	if (swap) {
+		kbuf.read_8 = __read_8_sw;
+		kbuf.read_4 = __read_4_sw;
+		kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN;
+	} else {
+		kbuf.read_8 = __read_8;
+		kbuf.read_4 = __read_4;
+		kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0;
+	}
+
+	type_len = translate_data(&kbuf, data, &ptr, &delta, &length);
+	switch (type_len) {
+	case KBUFFER_TYPE_PADDING:
+	case KBUFFER_TYPE_TIME_EXTEND:
+	case KBUFFER_TYPE_TIME_STAMP:
+		return NULL;
+	};
+
+	*size = length;
+
+	return ptr;
+}
+
+static int __next_event(struct kbuffer *kbuf)
+{
+	int type;
+
+	do {
+		kbuf->curr = kbuf->next;
+		if (kbuf->next >= kbuf->size)
+			return -1;
+		type = update_pointers(kbuf);
+	} while (type == KBUFFER_TYPE_TIME_EXTEND || type == KBUFFER_TYPE_PADDING);
+
+	return 0;
+}
+
+static int next_event(struct kbuffer *kbuf)
+{
+	return kbuf->next_event(kbuf);
+}
+
+/**
+ * kbuffer_next_event - increment the current pointer
+ * @kbuf:	The kbuffer to read
+ * @ts:		Address to store the next record's timestamp (may be NULL to ignore)
+ *
+ * Increments the pointers into the subbuffer of the kbuffer to point to the
+ * next event so that the next kbuffer_read_event() will return a
+ * new event.
+ *
+ * Returns the data of the next event if a new event exists on the subbuffer,
+ * NULL otherwise.
+ */
+void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts)
+{
+	int ret;
+
+	if (!kbuf || !kbuf->subbuffer)
+		return NULL;
+
+	ret = next_event(kbuf);
+	if (ret < 0)
+		return NULL;
+
+	if (ts)
+		*ts = kbuf->timestamp;
+
+	return kbuf->data + kbuf->index;
+}
+
+/**
+ * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer
+ * @kbuf:	The kbuffer to load
+ * @subbuffer:	The subbuffer to load into @kbuf.
+ *
+ * Load a new subbuffer (page) into @kbuf. This will reset all
+ * the pointers and update the @kbuf timestamp. The next read will
+ * return the first event on @subbuffer.
+ *
+ * Returns 0 on succes, -1 otherwise.
+ */
+int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer)
+{
+	unsigned long long flags;
+	void *ptr = subbuffer;
+
+	if (!kbuf || !subbuffer)
+		return -1;
+
+	kbuf->subbuffer = subbuffer;
+
+	kbuf->timestamp = read_8(kbuf, ptr);
+	ptr += 8;
+
+	kbuf->curr = 0;
+
+	if (kbuf->flags & KBUFFER_FL_LONG_8)
+		kbuf->start = 16;
+	else
+		kbuf->start = 12;
+
+	kbuf->data = subbuffer + kbuf->start;
+
+	flags = read_long(kbuf, ptr);
+	kbuf->size = (unsigned int)flags & COMMIT_MASK;
+
+	if (flags & MISSING_EVENTS) {
+		if (flags & MISSING_STORED) {
+			ptr = kbuf->data + kbuf->size;
+			kbuf->lost_events = read_long(kbuf, ptr);
+		} else
+			kbuf->lost_events = -1;
+	} else
+		kbuf->lost_events = 0;
+
+	kbuf->index = 0;
+	kbuf->next = 0;
+
+	next_event(kbuf);
+
+	return 0;
+}
+
+/**
+ * kbuffer_read_event - read the next event in the kbuffer subbuffer
+ * @kbuf:	The kbuffer to read from
+ * @ts:		The address to store the timestamp of the event (may be NULL to ignore)
+ *
+ * Returns a pointer to the data part of the current event.
+ * NULL if no event is left on the subbuffer.
+ */
+void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts)
+{
+	if (!kbuf || !kbuf->subbuffer)
+		return NULL;
+
+	if (kbuf->curr >= kbuf->size)
+		return NULL;
+
+	if (ts)
+		*ts = kbuf->timestamp;
+	return kbuf->data + kbuf->index;
+}
+
+/**
+ * kbuffer_timestamp - Return the timestamp of the current event
+ * @kbuf:	The kbuffer to read from
+ *
+ * Returns the timestamp of the current (next) event.
+ */
+unsigned long long kbuffer_timestamp(struct kbuffer *kbuf)
+{
+	return kbuf->timestamp;
+}
+
+/**
+ * kbuffer_read_at_offset - read the event that is at offset
+ * @kbuf:	The kbuffer to read from
+ * @offset:	The offset into the subbuffer
+ * @ts:		The address to store the timestamp of the event (may be NULL to ignore)
+ *
+ * The @offset must be an index from the @kbuf subbuffer beginning.
+ * If @offset is bigger than the stored subbuffer, NULL will be returned.
+ *
+ * Returns the data of the record that is at @offset. Note, @offset does
+ * not need to be the start of the record, the offset just needs to be
+ * in the record (or beginning of it).
+ *
+ * Note, the kbuf timestamp and pointers are updated to the
+ * returned record. That is, kbuffer_read_event() will return the same
+ * data and timestamp, and kbuffer_next_event() will increment from
+ * this record.
+ */
+void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
+			     unsigned long long *ts)
+{
+	void *data;
+
+	if (offset < kbuf->start)
+		offset = 0;
+	else
+		offset -= kbuf->start;
+
+	/* Reset the buffer */
+	kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
+
+	while (kbuf->curr < offset) {
+		data = kbuffer_next_event(kbuf, ts);
+		if (!data)
+			break;
+	}
+
+	return data;
+}
+
+/**
+ * kbuffer_subbuffer_size - the size of the loaded subbuffer
+ * @kbuf:	The kbuffer to read from
+ *
+ * Returns the size of the subbuffer. Note, this size is
+ * where the last event resides. The stored subbuffer may actually be
+ * bigger due to padding and such.
+ */
+int kbuffer_subbuffer_size(struct kbuffer *kbuf)
+{
+	return kbuf->size;
+}
+
+/**
+ * kbuffer_curr_index - Return the index of the record
+ * @kbuf:	The kbuffer to read from
+ *
+ * Returns the index from the start of the data part of
+ * the subbuffer to the current location. Note this is not
+ * from the start of the subbuffer. An index of zero will
+ * point to the first record. Use kbuffer_curr_offset() for
+ * the actually offset (that can be used by kbuffer_read_at_offset())
+ */
+int kbuffer_curr_index(struct kbuffer *kbuf)
+{
+	return kbuf->curr;
+}
+
+/**
+ * kbuffer_curr_offset - Return the offset of the record
+ * @kbuf:	The kbuffer to read from
+ *
+ * Returns the offset from the start of the subbuffer to the
+ * current location.
+ */
+int kbuffer_curr_offset(struct kbuffer *kbuf)
+{
+	return kbuf->curr + kbuf->start;
+}
+
+/**
+ * kbuffer_event_size - return the size of the event data
+ * @kbuf:	The kbuffer to read
+ *
+ * Returns the size of the event data (the payload not counting
+ * the meta data of the record) of the current event.
+ */
+int kbuffer_event_size(struct kbuffer *kbuf)
+{
+	return kbuf->next - kbuf->index;
+}
+
+/**
+ * kbuffer_curr_size - return the size of the entire record
+ * @kbuf:	The kbuffer to read
+ *
+ * Returns the size of the entire record (meta data and payload)
+ * of the current event.
+ */
+int kbuffer_curr_size(struct kbuffer *kbuf)
+{
+	return kbuf->next - kbuf->curr;
+}
+
+/**
+ * kbuffer_missed_events - return the # of missed events from last event.
+ * @kbuf: 	The kbuffer to read from
+ *
+ * Returns the # of missed events (if recorded) before the current
+ * event. Note, only events on the beginning of a subbuffer can
+ * have missed events, all other events within the buffer will be
+ * zero.
+ */
+int kbuffer_missed_events(struct kbuffer *kbuf)
+{
+	/* Only the first event can have missed events */
+	if (kbuf->curr)
+		return 0;
+
+	return kbuf->lost_events;
+}
+
+/**
+ * kbuffer_set_old_forma - set the kbuffer to use the old format parsing
+ * @kbuf:	The kbuffer to set
+ *
+ * This is obsolete (or should be). The first kernels to use the
+ * new ring buffer had a slightly different ring buffer format
+ * (2.6.30 and earlier). It is still somewhat supported by kbuffer,
+ * but should not be counted on in the future.
+ */
+void kbuffer_set_old_format(struct kbuffer *kbuf)
+{
+	kbuf->flags |= KBUFFER_FL_OLD_FORMAT;
+
+	kbuf->next_event = __old_next_event;
+}
diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h
new file mode 100644
index 0000000..c831f64
--- /dev/null
+++ b/tools/lib/traceevent/kbuffer.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program 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;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _KBUFFER_H
+#define _KBUFFER_H
+
+#ifndef TS_SHIFT
+#define TS_SHIFT		27
+#endif
+
+enum kbuffer_endian {
+	KBUFFER_ENDIAN_BIG,
+	KBUFFER_ENDIAN_LITTLE,
+};
+
+enum kbuffer_long_size {
+	KBUFFER_LSIZE_4,
+	KBUFFER_LSIZE_8,
+};
+
+enum {
+	KBUFFER_TYPE_PADDING		= 29,
+	KBUFFER_TYPE_TIME_EXTEND	= 30,
+	KBUFFER_TYPE_TIME_STAMP		= 31,
+};
+
+struct kbuffer;
+
+struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
+void kbuffer_free(struct kbuffer *kbuf);
+int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
+void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
+void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
+unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
+
+void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
+
+void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
+
+int kbuffer_curr_index(struct kbuffer *kbuf);
+
+int kbuffer_curr_offset(struct kbuffer *kbuf);
+int kbuffer_curr_size(struct kbuffer *kbuf);
+int kbuffer_event_size(struct kbuffer *kbuf);
+int kbuffer_missed_events(struct kbuffer *kbuf);
+int kbuffer_subbuffer_size(struct kbuffer *kbuf);
+
+void kbuffer_set_old_format(struct kbuffer *kbuf);
+
+#endif /* _K_BUFFER_H */
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
index a57db80..d7f2e68 100644
--- a/tools/lib/traceevent/trace-seq.c
+++ b/tools/lib/traceevent/trace-seq.c
@@ -49,6 +49,19 @@
 }
 
 /**
+ * trace_seq_reset - re-initialize the trace_seq structure
+ * @s: a pointer to the trace_seq structure to reset
+ */
+void trace_seq_reset(struct trace_seq *s)
+{
+	if (!s)
+		return;
+	TRACE_SEQ_CHECK(s);
+	s->len = 0;
+	s->readpos = 0;
+}
+
+/**
  * trace_seq_destroy - free up memory of a trace_seq
  * @s: a pointer to the trace_seq to free the buffer
  *
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 5b3123d..fdfceee 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -3,17 +3,17 @@
 
 NAME
 ----
-perf-diff - Read two perf.data files and display the differential profile
+perf-diff - Read perf.data files and display the differential profile
 
 SYNOPSIS
 --------
 [verse]
-'perf diff' [oldfile] [newfile]
+'perf diff' [baseline file] [data file1] [[data file2] ... ]
 
 DESCRIPTION
 -----------
-This command displays the performance difference amongst two perf.data files
-captured via perf record.
+This command displays the performance difference amongst two or more perf.data
+files captured via perf record.
 
 If no parameters are passed it will assume perf.data.old and perf.data.
 
@@ -75,8 +75,6 @@
 -c::
 --compute::
         Differential computation selection - delta,ratio,wdiff (default is delta).
-        If '+' is specified as a first character, the output is sorted based
-        on the computation results.
         See COMPARISON METHODS section for more info.
 
 -p::
@@ -87,6 +85,63 @@
 --formula::
         Show formula for given computation.
 
+-o::
+--order::
+       Specify compute sorting column number.
+
+COMPARISON
+----------
+The comparison is governed by the baseline file. The baseline perf.data
+file is iterated for samples. All other perf.data files specified on
+the command line are searched for the baseline sample pair. If the pair
+is found, specified computation is made and result is displayed.
+
+All samples from non-baseline perf.data files, that do not match any
+baseline entry, are displayed with empty space within baseline column
+and possible computation results (delta) in their related column.
+
+Example files samples:
+- file A with samples f1, f2, f3, f4,    f6
+- file B with samples     f2,     f4, f5
+- file C with samples f1, f2,         f5
+
+Example output:
+  x - computation takes place for pair
+  b - baseline sample percentage
+
+- perf diff A B C
+
+  baseline/A compute/B compute/C  samples
+  ---------------------------------------
+  b                    x          f1
+  b          x         x          f2
+  b                               f3
+  b          x                    f4
+  b                               f6
+             x         x          f5
+
+- perf diff B A C
+
+  baseline/B compute/A compute/C  samples
+  ---------------------------------------
+  b          x         x          f2
+  b          x                    f4
+  b                    x          f5
+             x         x          f1
+             x                    f3
+             x                    f6
+
+- perf diff C B A
+
+  baseline/C compute/B compute/A  samples
+  ---------------------------------------
+  b                    x          f1
+  b          x         x          f2
+  b          x                    f5
+                       x          f3
+             x         x          f4
+                       x          f6
+
 COMPARISON METHODS
 ------------------
 delta
@@ -96,7 +151,7 @@
   d = A->period_percent - B->period_percent
 
 with:
-  - A/B being matching hist entry from first/second file specified
+  - A/B being matching hist entry from data/baseline file specified
     (or perf.data/perf.data.old) respectively.
 
   - period_percent being the % of the hist entry period value within
@@ -109,24 +164,26 @@
   r = A->period / B->period
 
 with:
-  - A/B being matching hist entry from first/second file specified
+  - A/B being matching hist entry from data/baseline file specified
     (or perf.data/perf.data.old) respectively.
 
   - period being the hist entry period value
 
-wdiff
-~~~~~
+wdiff:WEIGHT-B,WEIGHT-A
+~~~~~~~~~~~~~~~~~~~~~~~
 If specified the 'Weighted diff' column is displayed with value 'd' computed as:
 
    d = B->period * WEIGHT-A - A->period * WEIGHT-B
 
-  - A/B being matching hist entry from first/second file specified
+  - A/B being matching hist entry from data/baseline file specified
     (or perf.data/perf.data.old) respectively.
 
   - period being the hist entry period value
 
   - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
     behind ':' separator like '-c wdiff:1,2'.
+    - WIEGHT-A being the weight of the data file
+    - WIEGHT-B being the weight of the baseline data file
 
 SEE ALSO
 --------
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 326f2cb..ac84db2 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -13,6 +13,7 @@
 	{top|record|report|diff|buildid-list}
 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
 	| --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
+'perf kvm stat [record|report|live] [<options>]
 
 DESCRIPTION
 -----------
@@ -50,6 +51,10 @@
   'perf kvm stat report' reports statistical data which includes events
   handled time, samples, and so on.
 
+  'perf kvm stat live' reports statistical data in a live mode (similar to
+  record + report but with statistical data updated live at a given display
+  rate).
+
 OPTIONS
 -------
 -i::
@@ -85,13 +90,50 @@
 --vcpu=<value>::
        analyze events which occures on this vcpu. (default: all vcpus)
 
---events=<value>::
-       events to be analyzed. Possible values: vmexit, mmio, ioport.
+--event=<value>::
+       event to be analyzed. Possible values: vmexit, mmio, ioport.
        (default: vmexit)
 -k::
 --key=<value>::
        Sorting key. Possible values: sample (default, sort by samples
        number), time (sort by average time).
+-p::
+--pid=::
+    Analyze events only for given process ID(s) (comma separated list).
+
+STAT LIVE OPTIONS
+-----------------
+-d::
+--display::
+        Time in seconds between display updates
+
+-m::
+--mmap-pages=::
+    Number of mmap data pages. Must be a power of two.
+
+-a::
+--all-cpus::
+        System-wide collection from all CPUs.
+
+-p::
+--pid=::
+    Analyze events only for given process ID(s) (comma separated list).
+
+--vcpu=<value>::
+       analyze events which occures on this vcpu. (default: all vcpus)
+
+
+--event=<value>::
+       event to be analyzed. Possible values: vmexit, mmio, ioport.
+       (default: vmexit)
+
+-k::
+--key=<value>::
+       Sorting key. Possible values: sample (default, sort by samples
+       number), time (sort by average time).
+
+--duration=<value>::
+       Show events other than HLT that take longer than duration usecs.
 
 SEE ALSO
 --------
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index d1e39dc..6fce6a6 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,7 +8,7 @@
 SYNOPSIS
 --------
 [verse]
-'perf list' [hw|sw|cache|tracepoint|event_glob]
+'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
 
 DESCRIPTION
 -----------
@@ -29,6 +29,8 @@
  G - guest counting (in KVM guests)
  H - host counting (not in KVM guests)
  p - precise level
+ S - read sample value (PERF_SAMPLE_READ)
+ D - pin the event to the PMU
 
 The 'p' modifier can be used for specifying how precise the instruction
 address should be. The 'p' modifier can be specified multiple times:
@@ -104,6 +106,8 @@
   'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
   block, etc.
 
+. 'pmu' to print the kernel supplied PMU events.
+
 . If none of the above is matched, it will apply the supplied glob to all
   events, printing the ones that match.
 
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 66dab74..2b8097e 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -115,7 +115,7 @@
 --dump-raw-trace::
         Dump raw trace in ASCII.
 
--g [type,min[,limit],order]::
+-g [type,min[,limit],order[,key]]::
 --call-graph::
         Display call chains using type, min percent threshold, optional print
 	limit and order.
@@ -129,12 +129,21 @@
 	- callee: callee based call graph.
 	- caller: inverted caller based call graph.
 
-	Default: fractal,0.5,callee.
+	key can be:
+	- function: compare on functions
+	- address: compare on individual code addresses
+
+	Default: fractal,0.5,callee,function.
 
 -G::
 --inverted::
         alias for inverted caller based call graph.
 
+--ignore-callees=<regex>::
+        Ignore callees of the function(s) matching the given regex.
+        This has the effect of collecting the callers of each such
+        function into one place in the call-graph tree.
+
 --pretty=<key>::
         Pretty printing style.  key: normal, raw
 
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 2fe87fb..73c9759 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -132,6 +132,11 @@
 use --per-core in addition to -a. (system-wide).  The output includes the
 core number and the number of online logical processors on that physical processor.
 
+-D msecs::
+--initial-delay msecs::
+After starting the program, wait msecs before measuring. This is useful to
+filter out the startup phase of the program, which is often very different.
+
 EXAMPLES
 --------
 
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 7fdd190..58d6598 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -155,6 +155,11 @@
 
 	Default: fractal,0.5,callee.
 
+--ignore-callees=<regex>::
+        Ignore callees of the function(s) matching the given regex.
+        This has the effect of collecting the callers of each such
+        function into one place in the call-graph tree.
+
 --percent-limit::
 	Do not show entries which have an overhead under that percent.
 	(Default: 0).
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 68718cc..daccd2c 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -23,25 +23,45 @@
 OPTIONS
 -------
 
+-a::
 --all-cpus::
         System-wide collection from all CPUs.
 
+-e::
+--expr::
+	List of events to show, currently only syscall names.
+	Prefixing with ! shows all syscalls but the ones specified.  You may
+	need to escape it.
+
+-o::
+--output=::
+	Output file name.
+
 -p::
 --pid=::
 	Record events on existing process ID (comma separated list).
 
+-t::
 --tid=::
         Record events on existing thread ID (comma separated list).
 
+-u::
 --uid=::
         Record events in threads owned by uid. Name or number.
 
+-v::
+--verbose=::
+        Verbosity level.
+
+-i::
 --no-inherit::
 	Child tasks do not inherit counters.
 
+-m::
 --mmap-pages=::
 	Number of mmap data pages. Must be a power of two.
 
+-C::
 --cpu::
 Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
 comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
@@ -54,6 +74,10 @@
 --sched:
 	Accrue thread runtime and provide a summary at the end of the session.
 
+-i
+--input
+	Process events from a given perf data file.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 641fccd..c5dc1ad 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -124,7 +124,7 @@
 ifneq ($(OUTPUT),)
   TE_PATH=$(OUTPUT)
 ifneq ($(subdir),)
-  LK_PATH=$(objtree)/lib/lk/
+  LK_PATH=$(OUTPUT)/../lib/lk/
 else
   LK_PATH=$(OUTPUT)
 endif
@@ -281,7 +281,7 @@
 LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
-LIB_H += $(TRACE_EVENT_DIR)event-parse.h
+LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
 LIB_H += util/target.h
 LIB_H += util/rblist.h
 LIB_H += util/intlist.h
@@ -360,6 +360,7 @@
 LIB_OBJS += $(OUTPUT)util/intlist.o
 LIB_OBJS += $(OUTPUT)util/vdso.o
 LIB_OBJS += $(OUTPUT)util/stat.o
+LIB_OBJS += $(OUTPUT)util/record.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
@@ -389,6 +390,10 @@
 LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
 LIB_OBJS += $(OUTPUT)tests/task-exit.o
 LIB_OBJS += $(OUTPUT)tests/sw-clock.o
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
+endif
+LIB_OBJS += $(OUTPUT)tests/code-reading.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -434,6 +439,7 @@
 ifneq ($(OUTPUT),)
   CFLAGS += -I$(OUTPUT)
 endif
+LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
 
 ifdef NO_LIBELF
 EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
@@ -459,6 +465,7 @@
 ifndef NO_LIBUNWIND
   LIB_OBJS += $(OUTPUT)util/unwind.o
 endif
+LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
 
 ifndef NO_LIBAUDIT
   BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
@@ -631,10 +638,10 @@
 	$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-redundant-decls $<
 
 $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
+	$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow -Wno-undef -Wno-switch-default $<
 
 $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
-	$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
+	$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs -Wno-undef -Wno-switch-default $<
 
 $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
 	$(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
@@ -762,17 +769,21 @@
 install-bin: all
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
 	$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
+	$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
+ifndef NO_LIBPERL
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
-	$(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
 	$(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
 	$(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
 	$(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
+endif
+ifndef NO_LIBPYTHON
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
 	$(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
 	$(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
 	$(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
+endif
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
 	$(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
 	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 815841c..8801fe0 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -6,3 +6,5 @@
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
+LIB_H += arch/$(ARCH)/util/tsc.h
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
new file mode 100644
index 0000000..9570c2b
--- /dev/null
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -0,0 +1,59 @@
+#include <stdbool.h>
+#include <errno.h>
+
+#include <linux/perf_event.h>
+
+#include "../../perf.h"
+#include "../../util/types.h"
+#include "../../util/debug.h"
+#include "tsc.h"
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
+{
+	u64 t, quot, rem;
+
+	t = ns - tc->time_zero;
+	quot = t / tc->time_mult;
+	rem  = t % tc->time_mult;
+	return (quot << tc->time_shift) +
+	       (rem << tc->time_shift) / tc->time_mult;
+}
+
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
+{
+	u64 quot, rem;
+
+	quot = cyc >> tc->time_shift;
+	rem  = cyc & ((1 << tc->time_shift) - 1);
+	return tc->time_zero + quot * tc->time_mult +
+	       ((rem * tc->time_mult) >> tc->time_shift);
+}
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc)
+{
+	bool cap_usr_time_zero;
+	u32 seq;
+	int i = 0;
+
+	while (1) {
+		seq = pc->lock;
+		rmb();
+		tc->time_mult = pc->time_mult;
+		tc->time_shift = pc->time_shift;
+		tc->time_zero = pc->time_zero;
+		cap_usr_time_zero = pc->cap_usr_time_zero;
+		rmb();
+		if (pc->lock == seq && !(seq & 1))
+			break;
+		if (++i > 10000) {
+			pr_debug("failed to get perf_event_mmap_page lock\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!cap_usr_time_zero)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
new file mode 100644
index 0000000..a24dec8
--- /dev/null
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -0,0 +1,20 @@
+#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
+#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
+
+#include "../../util/types.h"
+
+struct perf_tsc_conversion {
+	u16 time_shift;
+	u32 time_mult;
+	u64 time_zero;
+};
+
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc);
+
+u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
+u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
+
+#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 25fd3f1..8cdca43 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -117,6 +117,8 @@
 	*src = zalloc(length);
 	if (!*src)
 		die("memory allocation failed - maybe length is too large?\n");
+	/* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */
+	memset(*src, 0, length);
 }
 
 static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault)
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index db491e9..f988d38 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -90,8 +90,7 @@
 	struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool);
 	struct addr_location al;
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample,
-					  symbol__annotate_init) < 0) {
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 		pr_warning("problem processing %d event, skipping it.\n",
 			   event->header.type);
 		return -1;
@@ -195,6 +194,8 @@
 	if (session == NULL)
 		return -ENOMEM;
 
+	machines__set_symbol_filter(&session->machines, symbol__annotate_init);
+
 	if (ann->cpu_list) {
 		ret = perf_session__cpu_bitmap(session, ann->cpu_list,
 					       ann->cpu_bitmap);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 0aac5f3..f28799e 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -18,15 +18,53 @@
 #include "util/util.h"
 
 #include <stdlib.h>
+#include <math.h>
 
-static char const *input_old = "perf.data.old",
-		  *input_new = "perf.data";
-static char	  diff__default_sort_order[] = "dso,symbol";
-static bool  force;
+/* Diff command specific HPP columns. */
+enum {
+	PERF_HPP_DIFF__BASELINE,
+	PERF_HPP_DIFF__PERIOD,
+	PERF_HPP_DIFF__PERIOD_BASELINE,
+	PERF_HPP_DIFF__DELTA,
+	PERF_HPP_DIFF__RATIO,
+	PERF_HPP_DIFF__WEIGHTED_DIFF,
+	PERF_HPP_DIFF__FORMULA,
+
+	PERF_HPP_DIFF__MAX_INDEX
+};
+
+struct diff_hpp_fmt {
+	struct perf_hpp_fmt	 fmt;
+	int			 idx;
+	char			*header;
+	int			 header_width;
+};
+
+struct data__file {
+	struct perf_session	*session;
+	const char		*file;
+	int			 idx;
+	struct hists		*hists;
+	struct diff_hpp_fmt	 fmt[PERF_HPP_DIFF__MAX_INDEX];
+};
+
+static struct data__file *data__files;
+static int data__files_cnt;
+
+#define data__for_each_file_start(i, d, s)	\
+	for (i = s, d = &data__files[s];	\
+	     i < data__files_cnt;		\
+	     i++, d = &data__files[i])
+
+#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
+#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
+
+static char diff__default_sort_order[] = "dso,symbol";
+static bool force;
 static bool show_period;
 static bool show_formula;
 static bool show_baseline_only;
-static bool sort_compute;
+static unsigned int sort_compute;
 
 static s64 compute_wdiff_w1;
 static s64 compute_wdiff_w2;
@@ -46,6 +84,47 @@
 
 static int compute;
 
+static int compute_2_hpp[COMPUTE_MAX] = {
+	[COMPUTE_DELTA]		= PERF_HPP_DIFF__DELTA,
+	[COMPUTE_RATIO]		= PERF_HPP_DIFF__RATIO,
+	[COMPUTE_WEIGHTED_DIFF]	= PERF_HPP_DIFF__WEIGHTED_DIFF,
+};
+
+#define MAX_COL_WIDTH 70
+
+static struct header_column {
+	const char *name;
+	int width;
+} columns[PERF_HPP_DIFF__MAX_INDEX] = {
+	[PERF_HPP_DIFF__BASELINE] = {
+		.name  = "Baseline",
+	},
+	[PERF_HPP_DIFF__PERIOD] = {
+		.name  = "Period",
+		.width = 14,
+	},
+	[PERF_HPP_DIFF__PERIOD_BASELINE] = {
+		.name  = "Base period",
+		.width = 14,
+	},
+	[PERF_HPP_DIFF__DELTA] = {
+		.name  = "Delta",
+		.width = 7,
+	},
+	[PERF_HPP_DIFF__RATIO] = {
+		.name  = "Ratio",
+		.width = 14,
+	},
+	[PERF_HPP_DIFF__WEIGHTED_DIFF] = {
+		.name  = "Weighted diff",
+		.width = 14,
+	},
+	[PERF_HPP_DIFF__FORMULA] = {
+		.name  = "Formula",
+		.width = MAX_COL_WIDTH,
+	}
+};
+
 static int setup_compute_opt_wdiff(char *opt)
 {
 	char *w1_str = opt;
@@ -109,13 +188,6 @@
 		return 0;
 	}
 
-	if (*str == '+') {
-		sort_compute = true;
-		cstr = (char *) ++str;
-		if (!*str)
-			return 0;
-	}
-
 	option = strchr(str, ':');
 	if (option) {
 		unsigned len = option++ - str;
@@ -145,42 +217,42 @@
 	return -EINVAL;
 }
 
-double perf_diff__period_percent(struct hist_entry *he, u64 period)
+static double period_percent(struct hist_entry *he, u64 period)
 {
 	u64 total = he->hists->stats.total_period;
 	return (period * 100.0) / total;
 }
 
-double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
+static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
 {
-	double new_percent = perf_diff__period_percent(he, he->stat.period);
-	double old_percent = perf_diff__period_percent(pair, pair->stat.period);
+	double old_percent = period_percent(he, he->stat.period);
+	double new_percent = period_percent(pair, pair->stat.period);
 
-	he->diff.period_ratio_delta = new_percent - old_percent;
-	he->diff.computed = true;
-	return he->diff.period_ratio_delta;
+	pair->diff.period_ratio_delta = new_percent - old_percent;
+	pair->diff.computed = true;
+	return pair->diff.period_ratio_delta;
 }
 
-double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
+static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
 {
-	double new_period = he->stat.period;
-	double old_period = pair->stat.period;
+	double old_period = he->stat.period ?: 1;
+	double new_period = pair->stat.period;
 
-	he->diff.computed = true;
-	he->diff.period_ratio = new_period / old_period;
-	return he->diff.period_ratio;
+	pair->diff.computed = true;
+	pair->diff.period_ratio = new_period / old_period;
+	return pair->diff.period_ratio;
 }
 
-s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
+static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
 {
-	u64 new_period = he->stat.period;
-	u64 old_period = pair->stat.period;
+	u64 old_period = he->stat.period;
+	u64 new_period = pair->stat.period;
 
-	he->diff.computed = true;
-	he->diff.wdiff = new_period * compute_wdiff_w2 -
-			 old_period * compute_wdiff_w1;
+	pair->diff.computed = true;
+	pair->diff.wdiff = new_period * compute_wdiff_w2 -
+			   old_period * compute_wdiff_w1;
 
-	return he->diff.wdiff;
+	return pair->diff.wdiff;
 }
 
 static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
@@ -189,15 +261,15 @@
 	return scnprintf(buf, size,
 			 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
 			 "(%" PRIu64 " * 100 / %" PRIu64 ")",
-			  he->stat.period, he->hists->stats.total_period,
-			  pair->stat.period, pair->hists->stats.total_period);
+			  pair->stat.period, pair->hists->stats.total_period,
+			  he->stat.period, he->hists->stats.total_period);
 }
 
 static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
 			 char *buf, size_t size)
 {
-	double new_period = he->stat.period;
-	double old_period = pair->stat.period;
+	double old_period = he->stat.period;
+	double new_period = pair->stat.period;
 
 	return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
 }
@@ -205,16 +277,16 @@
 static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
 			 char *buf, size_t size)
 {
-	u64 new_period = he->stat.period;
-	u64 old_period = pair->stat.period;
+	u64 old_period = he->stat.period;
+	u64 new_period = pair->stat.period;
 
 	return scnprintf(buf, size,
 		  "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
 		  new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
 }
 
-int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
-		       char *buf, size_t size)
+static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
+			   char *buf, size_t size)
 {
 	switch (compute) {
 	case COMPUTE_DELTA:
@@ -247,7 +319,7 @@
 {
 	struct addr_location al;
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 		pr_warning("problem processing %d event, skipping it.\n",
 			   event->header.type);
 		return -1;
@@ -299,6 +371,29 @@
 	}
 }
 
+static struct hist_entry*
+get_pair_data(struct hist_entry *he, struct data__file *d)
+{
+	if (hist_entry__has_pairs(he)) {
+		struct hist_entry *pair;
+
+		list_for_each_entry(pair, &he->pairs.head, pairs.node)
+			if (pair->hists == d->hists)
+				return pair;
+	}
+
+	return NULL;
+}
+
+static struct hist_entry*
+get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
+{
+	void *ptr = dfmt - dfmt->idx;
+	struct data__file *d = container_of(ptr, struct data__file, fmt);
+
+	return get_pair_data(he, d);
+}
+
 static void hists__baseline_only(struct hists *hists)
 {
 	struct rb_root *root;
@@ -333,22 +428,24 @@
 
 	next = rb_first(root);
 	while (next != NULL) {
-		struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
-		struct hist_entry *pair = hist_entry__next_pair(he);
+		struct hist_entry *he, *pair;
 
+		he   = rb_entry(next, struct hist_entry, rb_node_in);
 		next = rb_next(&he->rb_node_in);
+
+		pair = get_pair_data(he, &data__files[sort_compute]);
 		if (!pair)
 			continue;
 
 		switch (compute) {
 		case COMPUTE_DELTA:
-			perf_diff__compute_delta(he, pair);
+			compute_delta(he, pair);
 			break;
 		case COMPUTE_RATIO:
-			perf_diff__compute_ratio(he, pair);
+			compute_ratio(he, pair);
 			break;
 		case COMPUTE_WEIGHTED_DIFF:
-			perf_diff__compute_wdiff(he, pair);
+			compute_wdiff(he, pair);
 			break;
 		default:
 			BUG_ON(1);
@@ -367,7 +464,7 @@
 }
 
 static int64_t
-hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
+__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
 			int c)
 {
 	switch (c) {
@@ -399,6 +496,36 @@
 	return 0;
 }
 
+static int64_t
+hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
+			int c)
+{
+	bool pairs_left  = hist_entry__has_pairs(left);
+	bool pairs_right = hist_entry__has_pairs(right);
+	struct hist_entry *p_right, *p_left;
+
+	if (!pairs_left && !pairs_right)
+		return 0;
+
+	if (!pairs_left || !pairs_right)
+		return pairs_left ? -1 : 1;
+
+	p_left  = get_pair_data(left,  &data__files[sort_compute]);
+	p_right = get_pair_data(right, &data__files[sort_compute]);
+
+	if (!p_left && !p_right)
+		return 0;
+
+	if (!p_left || !p_right)
+		return p_left ? -1 : 1;
+
+	/*
+	 * We have 2 entries of same kind, let's
+	 * make the data comparison.
+	 */
+	return __hist_entry__cmp_compute(p_left, p_right, c);
+}
+
 static void insert_hist_entry_by_compute(struct rb_root *root,
 					 struct hist_entry *he,
 					 int c)
@@ -448,75 +575,121 @@
 	}
 }
 
-static void hists__process(struct hists *old, struct hists *new)
+static void hists__process(struct hists *hists)
 {
-	hists__match(new, old);
-
 	if (show_baseline_only)
-		hists__baseline_only(new);
-	else
-		hists__link(new, old);
+		hists__baseline_only(hists);
 
 	if (sort_compute) {
-		hists__precompute(new);
-		hists__compute_resort(new);
+		hists__precompute(hists);
+		hists__compute_resort(hists);
 	} else {
-		hists__output_resort(new);
+		hists__output_resort(hists);
 	}
 
-	hists__fprintf(new, true, 0, 0, 0, stdout);
+	hists__fprintf(hists, true, 0, 0, 0, stdout);
+}
+
+static void data__fprintf(void)
+{
+	struct data__file *d;
+	int i;
+
+	fprintf(stdout, "# Data files:\n");
+
+	data__for_each_file(i, d)
+		fprintf(stdout, "#  [%d] %s %s\n",
+			d->idx, d->file,
+			!d->idx ? "(Baseline)" : "");
+
+	fprintf(stdout, "#\n");
+}
+
+static void data_process(void)
+{
+	struct perf_evlist *evlist_base = data__files[0].session->evlist;
+	struct perf_evsel *evsel_base;
+	bool first = true;
+
+	list_for_each_entry(evsel_base, &evlist_base->entries, node) {
+		struct data__file *d;
+		int i;
+
+		data__for_each_file_new(i, d) {
+			struct perf_evlist *evlist = d->session->evlist;
+			struct perf_evsel *evsel;
+
+			evsel = evsel_match(evsel_base, evlist);
+			if (!evsel)
+				continue;
+
+			d->hists = &evsel->hists;
+
+			hists__match(&evsel_base->hists, &evsel->hists);
+
+			if (!show_baseline_only)
+				hists__link(&evsel_base->hists,
+					    &evsel->hists);
+		}
+
+		fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
+			perf_evsel__name(evsel_base));
+
+		first = false;
+
+		if (verbose || data__files_cnt > 2)
+			data__fprintf();
+
+		hists__process(&evsel_base->hists);
+	}
+}
+
+static void data__free(struct data__file *d)
+{
+	int col;
+
+	for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
+		struct diff_hpp_fmt *fmt = &d->fmt[col];
+
+		free(fmt->header);
+	}
 }
 
 static int __cmd_diff(void)
 {
-	int ret, i;
-#define older (session[0])
-#define newer (session[1])
-	struct perf_session *session[2];
-	struct perf_evlist *evlist_new, *evlist_old;
-	struct perf_evsel *evsel;
-	bool first = true;
+	struct data__file *d;
+	int ret = -EINVAL, i;
 
-	older = perf_session__new(input_old, O_RDONLY, force, false,
-				  &tool);
-	newer = perf_session__new(input_new, O_RDONLY, force, false,
-				  &tool);
-	if (session[0] == NULL || session[1] == NULL)
-		return -ENOMEM;
-
-	for (i = 0; i < 2; ++i) {
-		ret = perf_session__process_events(session[i], &tool);
-		if (ret)
+	data__for_each_file(i, d) {
+		d->session = perf_session__new(d->file, O_RDONLY, force,
+					       false, &tool);
+		if (!d->session) {
+			pr_err("Failed to open %s\n", d->file);
+			ret = -ENOMEM;
 			goto out_delete;
+		}
+
+		ret = perf_session__process_events(d->session, &tool);
+		if (ret) {
+			pr_err("Failed to process %s\n", d->file);
+			goto out_delete;
+		}
+
+		perf_evlist__collapse_resort(d->session->evlist);
 	}
 
-	evlist_old = older->evlist;
-	evlist_new = newer->evlist;
+	data_process();
 
-	perf_evlist__collapse_resort(evlist_old);
-	perf_evlist__collapse_resort(evlist_new);
+ out_delete:
+	data__for_each_file(i, d) {
+		if (d->session)
+			perf_session__delete(d->session);
 
-	list_for_each_entry(evsel, &evlist_new->entries, node) {
-		struct perf_evsel *evsel_old;
-
-		evsel_old = evsel_match(evsel, evlist_old);
-		if (!evsel_old)
-			continue;
-
-		fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
-			perf_evsel__name(evsel));
-
-		first = false;
-
-		hists__process(&evsel_old->hists, &evsel->hists);
+		data__free(d);
 	}
 
-out_delete:
-	for (i = 0; i < 2; ++i)
-		perf_session__delete(session[i]);
+	free(data__files);
 	return ret;
-#undef older
-#undef newer
 }
 
 static const char * const diff_usage[] = {
@@ -555,61 +728,310 @@
 		   "columns '.' is reserved."),
 	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
 		    "Look for files with symbols relative to this directory"),
+	OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
 	OPT_END()
 };
 
-static void ui_init(void)
+static double baseline_percent(struct hist_entry *he)
 {
-	/*
-	 * Display baseline/delta/ratio
-	 * formula/periods columns.
-	 */
-	perf_hpp__column_enable(PERF_HPP__BASELINE);
+	struct hists *hists = he->hists;
+	return 100.0 * he->stat.period / hists->stats.total_period;
+}
 
-	switch (compute) {
-	case COMPUTE_DELTA:
-		perf_hpp__column_enable(PERF_HPP__DELTA);
+static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
+			       struct perf_hpp *hpp, struct hist_entry *he)
+{
+	struct diff_hpp_fmt *dfmt =
+		container_of(fmt, struct diff_hpp_fmt, fmt);
+	double percent = baseline_percent(he);
+	char pfmt[20] = " ";
+
+	if (!he->dummy) {
+		scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
+		return percent_color_snprintf(hpp->buf, hpp->size,
+					      pfmt, percent);
+	} else
+		return scnprintf(hpp->buf, hpp->size, "%*s",
+				 dfmt->header_width, pfmt);
+}
+
+static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
+{
+	double percent = baseline_percent(he);
+	const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+	int ret = 0;
+
+	if (!he->dummy)
+		ret = scnprintf(buf, size, fmt, percent);
+
+	return ret;
+}
+
+static void
+hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
+{
+	switch (idx) {
+	case PERF_HPP_DIFF__PERIOD_BASELINE:
+		scnprintf(buf, size, "%" PRIu64, he->stat.period);
 		break;
-	case COMPUTE_RATIO:
-		perf_hpp__column_enable(PERF_HPP__RATIO);
+
+	default:
 		break;
-	case COMPUTE_WEIGHTED_DIFF:
-		perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
+	}
+}
+
+static void
+hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
+		int idx, char *buf, size_t size)
+{
+	double diff;
+	double ratio;
+	s64 wdiff;
+
+	switch (idx) {
+	case PERF_HPP_DIFF__DELTA:
+		if (pair->diff.computed)
+			diff = pair->diff.period_ratio_delta;
+		else
+			diff = compute_delta(he, pair);
+
+		if (fabs(diff) >= 0.01)
+			scnprintf(buf, size, "%+4.2F%%", diff);
 		break;
+
+	case PERF_HPP_DIFF__RATIO:
+		/* No point for ratio number if we are dummy.. */
+		if (he->dummy)
+			break;
+
+		if (pair->diff.computed)
+			ratio = pair->diff.period_ratio;
+		else
+			ratio = compute_ratio(he, pair);
+
+		if (ratio > 0.0)
+			scnprintf(buf, size, "%14.6F", ratio);
+		break;
+
+	case PERF_HPP_DIFF__WEIGHTED_DIFF:
+		/* No point for wdiff number if we are dummy.. */
+		if (he->dummy)
+			break;
+
+		if (pair->diff.computed)
+			wdiff = pair->diff.wdiff;
+		else
+			wdiff = compute_wdiff(he, pair);
+
+		if (wdiff != 0)
+			scnprintf(buf, size, "%14ld", wdiff);
+		break;
+
+	case PERF_HPP_DIFF__FORMULA:
+		formula_fprintf(he, pair, buf, size);
+		break;
+
+	case PERF_HPP_DIFF__PERIOD:
+		scnprintf(buf, size, "%" PRIu64, pair->stat.period);
+		break;
+
 	default:
 		BUG_ON(1);
 	};
+}
 
-	if (show_formula)
-		perf_hpp__column_enable(PERF_HPP__FORMULA);
+static void
+__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
+		    char *buf, size_t size)
+{
+	struct hist_entry *pair = get_pair_fmt(he, dfmt);
+	int idx = dfmt->idx;
 
-	if (show_period) {
-		perf_hpp__column_enable(PERF_HPP__PERIOD);
-		perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
+	/* baseline is special */
+	if (idx == PERF_HPP_DIFF__BASELINE)
+		hpp__entry_baseline(he, buf, size);
+	else {
+		if (pair)
+			hpp__entry_pair(he, pair, idx, buf, size);
+		else
+			hpp__entry_unpair(he, idx, buf, size);
 	}
 }
 
+static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
+			     struct hist_entry *he)
+{
+	struct diff_hpp_fmt *dfmt =
+		container_of(_fmt, struct diff_hpp_fmt, fmt);
+	char buf[MAX_COL_WIDTH] = " ";
+
+	__hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
+
+	if (symbol_conf.field_sep)
+		return scnprintf(hpp->buf, hpp->size, "%s", buf);
+	else
+		return scnprintf(hpp->buf, hpp->size, "%*s",
+				 dfmt->header_width, buf);
+}
+
+static int hpp__header(struct perf_hpp_fmt *fmt,
+		       struct perf_hpp *hpp)
+{
+	struct diff_hpp_fmt *dfmt =
+		container_of(fmt, struct diff_hpp_fmt, fmt);
+
+	BUG_ON(!dfmt->header);
+	return scnprintf(hpp->buf, hpp->size, dfmt->header);
+}
+
+static int hpp__width(struct perf_hpp_fmt *fmt,
+		      struct perf_hpp *hpp __maybe_unused)
+{
+	struct diff_hpp_fmt *dfmt =
+		container_of(fmt, struct diff_hpp_fmt, fmt);
+
+	BUG_ON(dfmt->header_width <= 0);
+	return dfmt->header_width;
+}
+
+static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
+{
+#define MAX_HEADER_NAME 100
+	char buf_indent[MAX_HEADER_NAME];
+	char buf[MAX_HEADER_NAME];
+	const char *header = NULL;
+	int width = 0;
+
+	BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
+	header = columns[dfmt->idx].name;
+	width  = columns[dfmt->idx].width;
+
+	/* Only our defined HPP fmts should appear here. */
+	BUG_ON(!header);
+
+	if (data__files_cnt > 2)
+		scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
+
+#define NAME (data__files_cnt > 2 ? buf : header)
+	dfmt->header_width = width;
+	width = (int) strlen(NAME);
+	if (dfmt->header_width < width)
+		dfmt->header_width = width;
+
+	scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
+		  dfmt->header_width, NAME);
+
+	dfmt->header = strdup(buf_indent);
+#undef MAX_HEADER_NAME
+#undef NAME
+}
+
+static void data__hpp_register(struct data__file *d, int idx)
+{
+	struct diff_hpp_fmt *dfmt = &d->fmt[idx];
+	struct perf_hpp_fmt *fmt = &dfmt->fmt;
+
+	dfmt->idx = idx;
+
+	fmt->header = hpp__header;
+	fmt->width  = hpp__width;
+	fmt->entry  = hpp__entry_global;
+
+	/* TODO more colors */
+	if (idx == PERF_HPP_DIFF__BASELINE)
+		fmt->color = hpp__color_baseline;
+
+	init_header(d, dfmt);
+	perf_hpp__column_register(fmt);
+}
+
+static void ui_init(void)
+{
+	struct data__file *d;
+	int i;
+
+	data__for_each_file(i, d) {
+
+		/*
+		 * Baseline or compute realted columns:
+		 *
+		 *   PERF_HPP_DIFF__BASELINE
+		 *   PERF_HPP_DIFF__DELTA
+		 *   PERF_HPP_DIFF__RATIO
+		 *   PERF_HPP_DIFF__WEIGHTED_DIFF
+		 */
+		data__hpp_register(d, i ? compute_2_hpp[compute] :
+					  PERF_HPP_DIFF__BASELINE);
+
+		/*
+		 * And the rest:
+		 *
+		 * PERF_HPP_DIFF__FORMULA
+		 * PERF_HPP_DIFF__PERIOD
+		 * PERF_HPP_DIFF__PERIOD_BASELINE
+		 */
+		if (show_formula && i)
+			data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
+
+		if (show_period)
+			data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
+						  PERF_HPP_DIFF__PERIOD_BASELINE);
+	}
+}
+
+static int data_init(int argc, const char **argv)
+{
+	struct data__file *d;
+	static const char *defaults[] = {
+		"perf.data.old",
+		"perf.data",
+	};
+	bool use_default = true;
+	int i;
+
+	data__files_cnt = 2;
+
+	if (argc) {
+		if (argc == 1)
+			defaults[1] = argv[0];
+		else {
+			data__files_cnt = argc;
+			use_default = false;
+		}
+	} else if (symbol_conf.default_guest_vmlinux_name ||
+		   symbol_conf.default_guest_kallsyms) {
+		defaults[0] = "perf.data.host";
+		defaults[1] = "perf.data.guest";
+	}
+
+	if (sort_compute >= (unsigned int) data__files_cnt) {
+		pr_err("Order option out of limit.\n");
+		return -EINVAL;
+	}
+
+	data__files = zalloc(sizeof(*data__files) * data__files_cnt);
+	if (!data__files)
+		return -ENOMEM;
+
+	data__for_each_file(i, d) {
+		d->file = use_default ? defaults[i] : argv[i];
+		d->idx  = i;
+	}
+
+	return 0;
+}
+
 int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	sort_order = diff__default_sort_order;
 	argc = parse_options(argc, argv, options, diff_usage, 0);
-	if (argc) {
-		if (argc > 2)
-			usage_with_options(diff_usage, options);
-		if (argc == 2) {
-			input_old = argv[0];
-			input_new = argv[1];
-		} else
-			input_new = argv[0];
-	} else if (symbol_conf.default_guest_vmlinux_name ||
-		   symbol_conf.default_guest_kallsyms) {
-		input_old = "perf.data.host";
-		input_new = "perf.data.guest";
-	}
 
 	if (symbol__init() < 0)
 		return -1;
 
+	if (data_init(argc, argv) < 0)
+		return -1;
+
 	ui_init();
 
 	if (setup_sorting() < 0)
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 84ad6ab..9b336fd 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -38,8 +38,7 @@
 };
 
 static int perf_event__repipe_synth(struct perf_tool *tool,
-				    union perf_event *event,
-				    struct machine *machine __maybe_unused)
+				    union perf_event *event)
 {
 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
 	uint32_t size;
@@ -65,39 +64,28 @@
 					struct perf_session *session
 					__maybe_unused)
 {
-	return perf_event__repipe_synth(tool, event, NULL);
+	return perf_event__repipe_synth(tool, event);
 }
 
-static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
-					       union perf_event *event)
-{
-	return perf_event__repipe_synth(tool, event, NULL);
-}
-
-static int perf_event__repipe_tracing_data_synth(union perf_event *event,
-						 struct perf_session *session
-						 __maybe_unused)
-{
-	return perf_event__repipe_synth(NULL, event, NULL);
-}
-
-static int perf_event__repipe_attr(union perf_event *event,
-				   struct perf_evlist **pevlist __maybe_unused)
+static int perf_event__repipe_attr(struct perf_tool *tool,
+				   union perf_event *event,
+				   struct perf_evlist **pevlist)
 {
 	int ret;
-	ret = perf_event__process_attr(event, pevlist);
+
+	ret = perf_event__process_attr(tool, event, pevlist);
 	if (ret)
 		return ret;
 
-	return perf_event__repipe_synth(NULL, event, NULL);
+	return perf_event__repipe_synth(tool, event);
 }
 
 static int perf_event__repipe(struct perf_tool *tool,
 			      union perf_event *event,
 			      struct perf_sample *sample __maybe_unused,
-			      struct machine *machine)
+			      struct machine *machine __maybe_unused)
 {
-	return perf_event__repipe_synth(tool, event, machine);
+	return perf_event__repipe_synth(tool, event);
 }
 
 typedef int (*inject_handler)(struct perf_tool *tool,
@@ -119,7 +107,7 @@
 
 	build_id__mark_dso_hit(tool, event, sample, evsel, machine);
 
-	return perf_event__repipe_synth(tool, event, machine);
+	return perf_event__repipe_synth(tool, event);
 }
 
 static int perf_event__repipe_mmap(struct perf_tool *tool,
@@ -148,13 +136,14 @@
 	return err;
 }
 
-static int perf_event__repipe_tracing_data(union perf_event *event,
+static int perf_event__repipe_tracing_data(struct perf_tool *tool,
+					   union perf_event *event,
 					   struct perf_session *session)
 {
 	int err;
 
-	perf_event__repipe_synth(NULL, event, NULL);
-	err = perf_event__process_tracing_data(event, session);
+	perf_event__repipe_synth(tool, event);
+	err = perf_event__process_tracing_data(tool, event, session);
 
 	return err;
 }
@@ -209,7 +198,7 @@
 
 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
-	thread = machine__findnew_thread(machine, event->ip.pid);
+	thread = machine__findnew_thread(machine, sample->pid, sample->pid);
 	if (thread == NULL) {
 		pr_err("problem processing %d event, skipping it.\n",
 		       event->header.type);
@@ -217,7 +206,7 @@
 	}
 
 	thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
-			      event->ip.ip, &al);
+			      sample->ip, &al);
 
 	if (al.map != NULL) {
 		if (!al.map->dso->hit) {
@@ -312,7 +301,9 @@
 	sample_sw.period = sample->period;
 	sample_sw.time	 = sample->time;
 	perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
-				      &sample_sw, false);
+				      evsel->attr.sample_regs_user,
+				      evsel->attr.read_format, &sample_sw,
+				      false);
 	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
 	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
 }
@@ -407,8 +398,8 @@
 			.throttle	= perf_event__repipe,
 			.unthrottle	= perf_event__repipe,
 			.attr		= perf_event__repipe_attr,
-			.event_type	= perf_event__repipe_event_type_synth,
-			.tracing_data	= perf_event__repipe_tracing_data_synth,
+			.tracing_data	= perf_event__repipe_op2_synth,
+			.finished_round	= perf_event__repipe_op2_synth,
 			.build_id	= perf_event__repipe_op2_synth,
 		},
 		.input_name  = "-",
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 0259502..c2dff9c 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -305,7 +305,8 @@
 				struct perf_evsel *evsel,
 				struct machine *machine)
 {
-	struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
+	struct thread *thread = machine__findnew_thread(machine, sample->pid,
+							sample->pid);
 
 	if (thread == NULL) {
 		pr_debug("problem processing %d event, skipping it.\n",
@@ -313,7 +314,7 @@
 		return -1;
 	}
 
-	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
 
 	if (evsel->handler.func != NULL) {
 		tracepoint_handler f = evsel->handler.func;
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 24b78ae..47b3540 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -2,22 +2,26 @@
 #include "perf.h"
 
 #include "util/evsel.h"
+#include "util/evlist.h"
 #include "util/util.h"
 #include "util/cache.h"
 #include "util/symbol.h"
 #include "util/thread.h"
 #include "util/header.h"
 #include "util/session.h"
-
+#include "util/intlist.h"
 #include "util/parse-options.h"
 #include "util/trace-event.h"
 #include "util/debug.h"
 #include <lk/debugfs.h>
 #include "util/tool.h"
 #include "util/stat.h"
+#include "util/top.h"
 
 #include <sys/prctl.h>
+#include <sys/timerfd.h>
 
+#include <termios.h>
 #include <semaphore.h>
 #include <pthread.h>
 #include <math.h>
@@ -82,6 +86,8 @@
 
 struct perf_kvm_stat {
 	struct perf_tool    tool;
+	struct perf_record_opts opts;
+	struct perf_evlist  *evlist;
 	struct perf_session *session;
 
 	const char *file_name;
@@ -96,10 +102,20 @@
 	struct kvm_events_ops *events_ops;
 	key_cmp_fun compare;
 	struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
+
 	u64 total_time;
 	u64 total_count;
+	u64 lost_events;
+	u64 duration;
+
+	const char *pid_str;
+	struct intlist *pid_list;
 
 	struct rb_root result;
+
+	int timerfd;
+	unsigned int display_time;
+	bool live;
 };
 
 
@@ -320,6 +336,28 @@
 		INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
 }
 
+static void clear_events_cache_stats(struct list_head *kvm_events_cache)
+{
+	struct list_head *head;
+	struct kvm_event *event;
+	unsigned int i;
+	int j;
+
+	for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
+		head = &kvm_events_cache[i];
+		list_for_each_entry(event, head, hash_entry) {
+			/* reset stats for event */
+			event->total.time = 0;
+			init_stats(&event->total.stats);
+
+			for (j = 0; j < event->max_vcpu; ++j) {
+				event->vcpu[j].time = 0;
+				init_stats(&event->vcpu[j].stats);
+			}
+		}
+	}
+}
+
 static int kvm_events_hash_fn(u64 key)
 {
 	return key & (EVENTS_CACHE_SIZE - 1);
@@ -436,7 +474,7 @@
 static bool handle_end_event(struct perf_kvm_stat *kvm,
 			     struct vcpu_event_record *vcpu_record,
 			     struct event_key *key,
-			     u64 timestamp)
+			     struct perf_sample *sample)
 {
 	struct kvm_event *event;
 	u64 time_begin, time_diff;
@@ -472,9 +510,25 @@
 	vcpu_record->last_event = NULL;
 	vcpu_record->start_time = 0;
 
-	BUG_ON(timestamp < time_begin);
+	/* seems to happen once in a while during live mode */
+	if (sample->time < time_begin) {
+		pr_debug("End time before begin time; skipping event.\n");
+		return true;
+	}
 
-	time_diff = timestamp - time_begin;
+	time_diff = sample->time - time_begin;
+
+	if (kvm->duration && time_diff > kvm->duration) {
+		char decode[32];
+
+		kvm->events_ops->decode_key(kvm, &event->key, decode);
+		if (strcmp(decode, "HLT")) {
+			pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",
+				 sample->time, sample->pid, vcpu_record->vcpu_id,
+				 decode, time_diff/1000);
+		}
+	}
+
 	return update_kvm_event(event, vcpu, time_diff);
 }
 
@@ -521,7 +575,7 @@
 		return handle_begin_event(kvm, vcpu_record, &key, sample->time);
 
 	if (kvm->events_ops->is_end_event(evsel, sample, &key))
-		return handle_end_event(kvm, vcpu_record, &key, sample->time);
+		return handle_end_event(kvm, vcpu_record, &key, sample);
 
 	return true;
 }
@@ -550,6 +604,8 @@
 GET_EVENT_KEY(time, time);
 COMPARE_EVENT_KEY(count, stats.n);
 COMPARE_EVENT_KEY(mean, stats.mean);
+GET_EVENT_KEY(max, stats.max);
+GET_EVENT_KEY(min, stats.min);
 
 #define DEF_SORT_NAME_KEY(name, compare_key)				\
 	{ #name, compare_kvm_event_ ## compare_key }
@@ -639,43 +695,81 @@
 	return container_of(node, struct kvm_event, rb);
 }
 
-static void print_vcpu_info(int vcpu)
+static void print_vcpu_info(struct perf_kvm_stat *kvm)
 {
+	int vcpu = kvm->trace_vcpu;
+
 	pr_info("Analyze events for ");
 
+	if (kvm->live) {
+		if (kvm->opts.target.system_wide)
+			pr_info("all VMs, ");
+		else if (kvm->opts.target.pid)
+			pr_info("pid(s) %s, ", kvm->opts.target.pid);
+		else
+			pr_info("dazed and confused on what is monitored, ");
+	}
+
 	if (vcpu == -1)
 		pr_info("all VCPUs:\n\n");
 	else
 		pr_info("VCPU %d:\n\n", vcpu);
 }
 
+static void show_timeofday(void)
+{
+	char date[64];
+	struct timeval tv;
+	struct tm ltime;
+
+	gettimeofday(&tv, NULL);
+	if (localtime_r(&tv.tv_sec, &ltime)) {
+		strftime(date, sizeof(date), "%H:%M:%S", &ltime);
+		pr_info("%s.%06ld", date, tv.tv_usec);
+	} else
+		pr_info("00:00:00.000000");
+
+	return;
+}
+
 static void print_result(struct perf_kvm_stat *kvm)
 {
 	char decode[20];
 	struct kvm_event *event;
 	int vcpu = kvm->trace_vcpu;
 
+	if (kvm->live) {
+		puts(CONSOLE_CLEAR);
+		show_timeofday();
+	}
+
 	pr_info("\n\n");
-	print_vcpu_info(vcpu);
+	print_vcpu_info(kvm);
 	pr_info("%20s ", kvm->events_ops->name);
 	pr_info("%10s ", "Samples");
 	pr_info("%9s ", "Samples%");
 
 	pr_info("%9s ", "Time%");
+	pr_info("%10s ", "Min Time");
+	pr_info("%10s ", "Max Time");
 	pr_info("%16s ", "Avg time");
 	pr_info("\n\n");
 
 	while ((event = pop_from_result(&kvm->result))) {
-		u64 ecount, etime;
+		u64 ecount, etime, max, min;
 
 		ecount = get_event_count(event, vcpu);
 		etime = get_event_time(event, vcpu);
+		max = get_event_max(event, vcpu);
+		min = get_event_min(event, vcpu);
 
 		kvm->events_ops->decode_key(kvm, &event->key, decode);
 		pr_info("%20s ", decode);
 		pr_info("%10llu ", (unsigned long long)ecount);
 		pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
 		pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
+		pr_info("%8" PRIu64 "us ", min / 1000);
+		pr_info("%8" PRIu64 "us ", max / 1000);
 		pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
 			kvm_event_rel_stddev(vcpu, event));
 		pr_info("\n");
@@ -683,6 +777,29 @@
 
 	pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
 		kvm->total_count, kvm->total_time / 1e3);
+
+	if (kvm->lost_events)
+		pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);
+}
+
+static int process_lost_event(struct perf_tool *tool,
+			      union perf_event *event __maybe_unused,
+			      struct perf_sample *sample __maybe_unused,
+			      struct machine *machine __maybe_unused)
+{
+	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool);
+
+	kvm->lost_events++;
+	return 0;
+}
+
+static bool skip_sample(struct perf_kvm_stat *kvm,
+			struct perf_sample *sample)
+{
+	if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL)
+		return true;
+
+	return false;
 }
 
 static int process_sample_event(struct perf_tool *tool,
@@ -691,10 +808,14 @@
 				struct perf_evsel *evsel,
 				struct machine *machine)
 {
-	struct thread *thread = machine__findnew_thread(machine, sample->tid);
+	struct thread *thread;
 	struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
 						 tool);
 
+	if (skip_sample(kvm, sample))
+		return 0;
+
+	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
 	if (thread == NULL) {
 		pr_debug("problem processing %d event, skipping it.\n",
 			event->header.type);
@@ -707,10 +828,20 @@
 	return 0;
 }
 
-static int get_cpu_isa(struct perf_session *session)
+static int cpu_isa_config(struct perf_kvm_stat *kvm)
 {
-	char *cpuid = session->header.env.cpuid;
-	int isa;
+	char buf[64], *cpuid;
+	int err, isa;
+
+	if (kvm->live) {
+		err = get_cpuid(buf, sizeof(buf));
+		if (err != 0) {
+			pr_err("Failed to look up CPU type (Intel or AMD)\n");
+			return err;
+		}
+		cpuid = buf;
+	} else
+		cpuid = kvm->session->header.env.cpuid;
 
 	if (strstr(cpuid, "Intel"))
 		isa = 1;
@@ -718,10 +849,361 @@
 		isa = 0;
 	else {
 		pr_err("CPU %s is not supported.\n", cpuid);
-		isa = -ENOTSUP;
+		return -ENOTSUP;
 	}
 
-	return isa;
+	if (isa == 1) {
+		kvm->exit_reasons = vmx_exit_reasons;
+		kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
+		kvm->exit_reasons_isa = "VMX";
+	}
+
+	return 0;
+}
+
+static bool verify_vcpu(int vcpu)
+{
+	if (vcpu != -1 && vcpu < 0) {
+		pr_err("Invalid vcpu:%d.\n", vcpu);
+		return false;
+	}
+
+	return true;
+}
+
+/* keeping the max events to a modest level to keep
+ * the processing of samples per mmap smooth.
+ */
+#define PERF_KVM__MAX_EVENTS_PER_MMAP  25
+
+static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
+				   u64 *mmap_time)
+{
+	union perf_event *event;
+	struct perf_sample sample;
+	s64 n = 0;
+	int err;
+
+	*mmap_time = ULLONG_MAX;
+	while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
+		err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
+		if (err) {
+			pr_err("Failed to parse sample\n");
+			return -1;
+		}
+
+		err = perf_session_queue_event(kvm->session, event, &sample, 0);
+		if (err) {
+			pr_err("Failed to enqueue sample: %d\n", err);
+			return -1;
+		}
+
+		/* save time stamp of our first sample for this mmap */
+		if (n == 0)
+			*mmap_time = sample.time;
+
+		/* limit events per mmap handled all at once */
+		n++;
+		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
+			break;
+	}
+
+	return n;
+}
+
+static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
+{
+	int i, err, throttled = 0;
+	s64 n, ntotal = 0;
+	u64 flush_time = ULLONG_MAX, mmap_time;
+
+	for (i = 0; i < kvm->evlist->nr_mmaps; i++) {
+		n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time);
+		if (n < 0)
+			return -1;
+
+		/* flush time is going to be the minimum of all the individual
+		 * mmap times. Essentially, we flush all the samples queued up
+		 * from the last pass under our minimal start time -- that leaves
+		 * a very small race for samples to come in with a lower timestamp.
+		 * The ioctl to return the perf_clock timestamp should close the
+		 * race entirely.
+		 */
+		if (mmap_time < flush_time)
+			flush_time = mmap_time;
+
+		ntotal += n;
+		if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)
+			throttled = 1;
+	}
+
+	/* flush queue after each round in which we processed events */
+	if (ntotal) {
+		kvm->session->ordered_samples.next_flush = flush_time;
+		err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
+		if (err) {
+			if (kvm->lost_events)
+				pr_info("\nLost events: %" PRIu64 "\n\n",
+					kvm->lost_events);
+			return err;
+		}
+	}
+
+	return throttled;
+}
+
+static volatile int done;
+
+static void sig_handler(int sig __maybe_unused)
+{
+	done = 1;
+}
+
+static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)
+{
+	struct itimerspec new_value;
+	int rc = -1;
+
+	kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
+	if (kvm->timerfd < 0) {
+		pr_err("timerfd_create failed\n");
+		goto out;
+	}
+
+	new_value.it_value.tv_sec = kvm->display_time;
+	new_value.it_value.tv_nsec = 0;
+	new_value.it_interval.tv_sec = kvm->display_time;
+	new_value.it_interval.tv_nsec = 0;
+
+	if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {
+		pr_err("timerfd_settime failed: %d\n", errno);
+		close(kvm->timerfd);
+		goto out;
+	}
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)
+{
+	uint64_t c;
+	int rc;
+
+	rc = read(kvm->timerfd, &c, sizeof(uint64_t));
+	if (rc < 0) {
+		if (errno == EAGAIN)
+			return 0;
+
+		pr_err("Failed to read timer fd: %d\n", errno);
+		return -1;
+	}
+
+	if (rc != sizeof(uint64_t)) {
+		pr_err("Error reading timer fd - invalid size returned\n");
+		return -1;
+	}
+
+	if (c != 1)
+		pr_debug("Missed timer beats: %" PRIu64 "\n", c-1);
+
+	/* update display */
+	sort_result(kvm);
+	print_result(kvm);
+
+	/* reset counts */
+	clear_events_cache_stats(kvm->kvm_events_cache);
+	kvm->total_count = 0;
+	kvm->total_time = 0;
+	kvm->lost_events = 0;
+
+	return 0;
+}
+
+static int fd_set_nonblock(int fd)
+{
+	long arg = 0;
+
+	arg = fcntl(fd, F_GETFL);
+	if (arg < 0) {
+		pr_err("Failed to get current flags for fd %d\n", fd);
+		return -1;
+	}
+
+	if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {
+		pr_err("Failed to set non-block option on fd %d\n", fd);
+		return -1;
+	}
+
+	return 0;
+}
+
+static
+int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save)
+{
+	int c;
+
+	tcsetattr(0, TCSANOW, tc_now);
+	c = getc(stdin);
+	tcsetattr(0, TCSAFLUSH, tc_save);
+
+	if (c == 'q')
+		return 1;
+
+	return 0;
+}
+
+static int kvm_events_live_report(struct perf_kvm_stat *kvm)
+{
+	struct pollfd *pollfds = NULL;
+	int nr_fds, nr_stdin, ret, err = -EINVAL;
+	struct termios tc, save;
+
+	/* live flag must be set first */
+	kvm->live = true;
+
+	ret = cpu_isa_config(kvm);
+	if (ret < 0)
+		return ret;
+
+	if (!verify_vcpu(kvm->trace_vcpu) ||
+	    !select_key(kvm) ||
+	    !register_kvm_events_ops(kvm)) {
+		goto out;
+	}
+
+	init_kvm_event_record(kvm);
+
+	tcgetattr(0, &save);
+	tc = save;
+	tc.c_lflag &= ~(ICANON | ECHO);
+	tc.c_cc[VMIN] = 0;
+	tc.c_cc[VTIME] = 0;
+
+	signal(SIGINT, sig_handler);
+	signal(SIGTERM, sig_handler);
+
+	/* copy pollfds -- need to add timerfd and stdin */
+	nr_fds = kvm->evlist->nr_fds;
+	pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
+	if (!pollfds) {
+		err = -ENOMEM;
+		goto out;
+	}
+	memcpy(pollfds, kvm->evlist->pollfd,
+		sizeof(struct pollfd) * kvm->evlist->nr_fds);
+
+	/* add timer fd */
+	if (perf_kvm__timerfd_create(kvm) < 0) {
+		err = -1;
+		goto out;
+	}
+
+	pollfds[nr_fds].fd = kvm->timerfd;
+	pollfds[nr_fds].events = POLLIN;
+	nr_fds++;
+
+	pollfds[nr_fds].fd = fileno(stdin);
+	pollfds[nr_fds].events = POLLIN;
+	nr_stdin = nr_fds;
+	nr_fds++;
+	if (fd_set_nonblock(fileno(stdin)) != 0)
+		goto out;
+
+	/* everything is good - enable the events and process */
+	perf_evlist__enable(kvm->evlist);
+
+	while (!done) {
+		int rc;
+
+		rc = perf_kvm__mmap_read(kvm);
+		if (rc < 0)
+			break;
+
+		err = perf_kvm__handle_timerfd(kvm);
+		if (err)
+			goto out;
+
+		if (pollfds[nr_stdin].revents & POLLIN)
+			done = perf_kvm__handle_stdin(&tc, &save);
+
+		if (!rc && !done)
+			err = poll(pollfds, nr_fds, 100);
+	}
+
+	perf_evlist__disable(kvm->evlist);
+
+	if (err == 0) {
+		sort_result(kvm);
+		print_result(kvm);
+	}
+
+out:
+	if (kvm->timerfd >= 0)
+		close(kvm->timerfd);
+
+	if (pollfds)
+		free(pollfds);
+
+	return err;
+}
+
+static int kvm_live_open_events(struct perf_kvm_stat *kvm)
+{
+	int err, rc = -1;
+	struct perf_evsel *pos;
+	struct perf_evlist *evlist = kvm->evlist;
+
+	perf_evlist__config(evlist, &kvm->opts);
+
+	/*
+	 * Note: exclude_{guest,host} do not apply here.
+	 *       This command processes KVM tracepoints from host only
+	 */
+	list_for_each_entry(pos, &evlist->entries, node) {
+		struct perf_event_attr *attr = &pos->attr;
+
+		/* make sure these *are* set */
+		attr->sample_type |= PERF_SAMPLE_TID;
+		attr->sample_type |= PERF_SAMPLE_TIME;
+		attr->sample_type |= PERF_SAMPLE_CPU;
+		attr->sample_type |= PERF_SAMPLE_RAW;
+		/* make sure these are *not*; want as small a sample as possible */
+		attr->sample_type &= ~PERF_SAMPLE_PERIOD;
+		attr->sample_type &= ~PERF_SAMPLE_IP;
+		attr->sample_type &= ~PERF_SAMPLE_CALLCHAIN;
+		attr->sample_type &= ~PERF_SAMPLE_ADDR;
+		attr->sample_type &= ~PERF_SAMPLE_READ;
+		attr->mmap = 0;
+		attr->comm = 0;
+		attr->task = 0;
+
+		attr->sample_period = 1;
+
+		attr->watermark = 0;
+		attr->wakeup_events = 1000;
+
+		/* will enable all once we are ready */
+		attr->disabled = 1;
+	}
+
+	err = perf_evlist__open(evlist);
+	if (err < 0) {
+		printf("Couldn't create the events: %s\n", strerror(errno));
+		goto out;
+	}
+
+	if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) {
+		ui__error("Failed to mmap the events: %s\n", strerror(errno));
+		perf_evlist__close(evlist);
+		goto out;
+	}
+
+	rc = 0;
+
+out:
+	return rc;
 }
 
 static int read_events(struct perf_kvm_stat *kvm)
@@ -749,28 +1231,24 @@
 	 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
 	 * traced in the old kernel.
 	 */
-	ret = get_cpu_isa(kvm->session);
-
+	ret = cpu_isa_config(kvm);
 	if (ret < 0)
 		return ret;
 
-	if (ret == 1) {
-		kvm->exit_reasons = vmx_exit_reasons;
-		kvm->exit_reasons_size = ARRAY_SIZE(vmx_exit_reasons);
-		kvm->exit_reasons_isa = "VMX";
-	}
-
 	return perf_session__process_events(kvm->session, &kvm->tool);
 }
 
-static bool verify_vcpu(int vcpu)
+static int parse_target_str(struct perf_kvm_stat *kvm)
 {
-	if (vcpu != -1 && vcpu < 0) {
-		pr_err("Invalid vcpu:%d.\n", vcpu);
-		return false;
+	if (kvm->pid_str) {
+		kvm->pid_list = intlist__new(kvm->pid_str);
+		if (kvm->pid_list == NULL) {
+			pr_err("Error parsing process id string\n");
+			return -EINVAL;
+		}
 	}
 
-	return true;
+	return 0;
 }
 
 static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
@@ -778,6 +1256,9 @@
 	int ret = -EINVAL;
 	int vcpu = kvm->trace_vcpu;
 
+	if (parse_target_str(kvm) != 0)
+		goto exit;
+
 	if (!verify_vcpu(vcpu))
 		goto exit;
 
@@ -801,16 +1282,11 @@
 	return ret;
 }
 
-static const char * const record_args[] = {
-	"record",
-	"-R",
-	"-f",
-	"-m", "1024",
-	"-c", "1",
-	"-e", "kvm:kvm_entry",
-	"-e", "kvm:kvm_exit",
-	"-e", "kvm:kvm_mmio",
-	"-e", "kvm:kvm_pio",
+static const char * const kvm_events_tp[] = {
+	"kvm:kvm_entry",
+	"kvm:kvm_exit",
+	"kvm:kvm_mmio",
+	"kvm:kvm_pio",
 };
 
 #define STRDUP_FAIL_EXIT(s)		\
@@ -826,8 +1302,15 @@
 {
 	unsigned int rec_argc, i, j;
 	const char **rec_argv;
+	const char * const record_args[] = {
+		"record",
+		"-R",
+		"-m", "1024",
+		"-c", "1",
+	};
 
-	rec_argc = ARRAY_SIZE(record_args) + argc + 2;
+	rec_argc = ARRAY_SIZE(record_args) + argc + 2 +
+		   2 * ARRAY_SIZE(kvm_events_tp);
 	rec_argv = calloc(rec_argc + 1, sizeof(char *));
 
 	if (rec_argv == NULL)
@@ -836,6 +1319,11 @@
 	for (i = 0; i < ARRAY_SIZE(record_args); i++)
 		rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);
 
+	for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
+		rec_argv[i++] = "-e";
+		rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);
+	}
+
 	rec_argv[i++] = STRDUP_FAIL_EXIT("-o");
 	rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);
 
@@ -856,6 +1344,8 @@
 		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
 			    "key for sorting: sample(sort by samples number)"
 			    " time (sort by avg time)"),
+		OPT_STRING('p', "pid", &kvm->pid_str, "pid",
+			   "analyze events only for given process id(s)"),
 		OPT_END()
 	};
 
@@ -878,6 +1368,190 @@
 	return kvm_events_report_vcpu(kvm);
 }
 
+static struct perf_evlist *kvm_live_event_list(void)
+{
+	struct perf_evlist *evlist;
+	char *tp, *name, *sys;
+	unsigned int j;
+	int err = -1;
+
+	evlist = perf_evlist__new();
+	if (evlist == NULL)
+		return NULL;
+
+	for (j = 0; j < ARRAY_SIZE(kvm_events_tp); j++) {
+
+		tp = strdup(kvm_events_tp[j]);
+		if (tp == NULL)
+			goto out;
+
+		/* split tracepoint into subsystem and name */
+		sys = tp;
+		name = strchr(tp, ':');
+		if (name == NULL) {
+			pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",
+				kvm_events_tp[j]);
+			free(tp);
+			goto out;
+		}
+		*name = '\0';
+		name++;
+
+		if (perf_evlist__add_newtp(evlist, sys, name, NULL)) {
+			pr_err("Failed to add %s tracepoint to the list\n", kvm_events_tp[j]);
+			free(tp);
+			goto out;
+		}
+
+		free(tp);
+	}
+
+	err = 0;
+
+out:
+	if (err) {
+		perf_evlist__delete(evlist);
+		evlist = NULL;
+	}
+
+	return evlist;
+}
+
+static int kvm_events_live(struct perf_kvm_stat *kvm,
+			   int argc, const char **argv)
+{
+	char errbuf[BUFSIZ];
+	int err;
+
+	const struct option live_options[] = {
+		OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",
+			"record events on existing process id"),
+		OPT_UINTEGER('m', "mmap-pages", &kvm->opts.mmap_pages,
+			"number of mmap data pages"),
+		OPT_INCR('v', "verbose", &verbose,
+			"be more verbose (show counter open errors, etc)"),
+		OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,
+			"system-wide collection from all CPUs"),
+		OPT_UINTEGER('d', "display", &kvm->display_time,
+			"time in seconds between display updates"),
+		OPT_STRING(0, "event", &kvm->report_event, "report event",
+			"event for reporting: vmexit, mmio, ioport"),
+		OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
+			"vcpu id to report"),
+		OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
+			"key for sorting: sample(sort by samples number)"
+			" time (sort by avg time)"),
+		OPT_U64(0, "duration", &kvm->duration,
+		    "show events other than HALT that take longer than duration usecs"),
+		OPT_END()
+	};
+	const char * const live_usage[] = {
+		"perf kvm stat live [<options>]",
+		NULL
+	};
+
+
+	/* event handling */
+	kvm->tool.sample = process_sample_event;
+	kvm->tool.comm   = perf_event__process_comm;
+	kvm->tool.exit   = perf_event__process_exit;
+	kvm->tool.fork   = perf_event__process_fork;
+	kvm->tool.lost   = process_lost_event;
+	kvm->tool.ordered_samples = true;
+	perf_tool__fill_defaults(&kvm->tool);
+
+	/* set defaults */
+	kvm->display_time = 1;
+	kvm->opts.user_interval = 1;
+	kvm->opts.mmap_pages = 512;
+	kvm->opts.target.uses_mmap = false;
+	kvm->opts.target.uid_str = NULL;
+	kvm->opts.target.uid = UINT_MAX;
+
+	symbol__init();
+	disable_buildid_cache();
+
+	use_browser = 0;
+	setup_browser(false);
+
+	if (argc) {
+		argc = parse_options(argc, argv, live_options,
+				     live_usage, 0);
+		if (argc)
+			usage_with_options(live_usage, live_options);
+	}
+
+	kvm->duration *= NSEC_PER_USEC;   /* convert usec to nsec */
+
+	/*
+	 * target related setups
+	 */
+	err = perf_target__validate(&kvm->opts.target);
+	if (err) {
+		perf_target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);
+		ui__warning("%s", errbuf);
+	}
+
+	if (perf_target__none(&kvm->opts.target))
+		kvm->opts.target.system_wide = true;
+
+
+	/*
+	 * generate the event list
+	 */
+	kvm->evlist = kvm_live_event_list();
+	if (kvm->evlist == NULL) {
+		err = -1;
+		goto out;
+	}
+
+	symbol_conf.nr_events = kvm->evlist->nr_entries;
+
+	if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)
+		usage_with_options(live_usage, live_options);
+
+	/*
+	 * perf session
+	 */
+	kvm->session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool);
+	if (kvm->session == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+	kvm->session->evlist = kvm->evlist;
+	perf_session__set_id_hdr_size(kvm->session);
+
+
+	if (perf_target__has_task(&kvm->opts.target))
+		perf_event__synthesize_thread_map(&kvm->tool,
+						  kvm->evlist->threads,
+						  perf_event__process,
+						  &kvm->session->machines.host);
+	else
+		perf_event__synthesize_threads(&kvm->tool, perf_event__process,
+					       &kvm->session->machines.host);
+
+
+	err = kvm_live_open_events(kvm);
+	if (err)
+		goto out;
+
+	err = kvm_events_live_report(kvm);
+
+out:
+	exit_browser(0);
+
+	if (kvm->session)
+		perf_session__delete(kvm->session);
+	kvm->session = NULL;
+	if (kvm->evlist) {
+		perf_evlist__delete_maps(kvm->evlist);
+		perf_evlist__delete(kvm->evlist);
+	}
+
+	return err;
+}
+
 static void print_kvm_stat_usage(void)
 {
 	printf("Usage: perf kvm stat <command>\n\n");
@@ -885,6 +1559,7 @@
 	printf("# Available commands:\n");
 	printf("\trecord: record kvm events\n");
 	printf("\treport: report statistical data of kvm events\n");
+	printf("\tlive:   live reporting of statistical data of kvm events\n");
 
 	printf("\nOtherwise, it is the alias of 'perf stat':\n");
 }
@@ -914,6 +1589,9 @@
 	if (!strncmp(argv[1], "rep", 3))
 		return kvm_events_report(&kvm, argc - 1 , argv + 1);
 
+	if (!strncmp(argv[1], "live", 4))
+		return kvm_events_live(&kvm, argc - 1 , argv + 1);
+
 perf_stat:
 	return cmd_stat(argc, argv, NULL);
 }
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 1948ece..e79f423 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -13,6 +13,7 @@
 
 #include "util/parse-events.h"
 #include "util/cache.h"
+#include "util/pmu.h"
 
 int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 {
@@ -37,6 +38,8 @@
 			else if (strcmp(argv[i], "cache") == 0 ||
 				 strcmp(argv[i], "hwcache") == 0)
 				print_hwcache_events(NULL, false);
+			else if (strcmp(argv[i], "pmu") == 0)
+				print_pmu_events(NULL, false);
 			else if (strcmp(argv[i], "--raw-dump") == 0)
 				print_events(NULL, true);
 			else {
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 76543a4..ee33ba2 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -805,7 +805,8 @@
 				struct perf_evsel *evsel,
 				struct machine *machine)
 {
-	struct thread *thread = machine__findnew_thread(machine, sample->tid);
+	struct thread *thread = machine__findnew_thread(machine, sample->pid,
+							sample->tid);
 
 	if (thread == NULL) {
 		pr_debug("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index a8ff6d2..791b432 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -14,7 +14,6 @@
 struct perf_mem {
 	struct perf_tool	tool;
 	char const		*input_name;
-	symbol_filter_t		annotate_init;
 	bool			hide_unresolved;
 	bool			dump_raw;
 	const char		*cpu_list;
@@ -69,8 +68,7 @@
 	struct addr_location al;
 	const char *fmt;
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample,
-				mem->annotate_init) < 0) {
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 		fprintf(stderr, "problem processing %d event, skipping it.\n",
 				event->header.type);
 		return -1;
@@ -96,7 +94,7 @@
 		symbol_conf.field_sep,
 		sample->tid,
 		symbol_conf.field_sep,
-		event->ip.ip,
+		sample->ip,
 		symbol_conf.field_sep,
 		sample->addr,
 		symbol_conf.field_sep,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ecca62e..a41ac415 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -474,13 +474,6 @@
 			goto out_delete_session;
 		}
 
-		err = perf_event__synthesize_event_types(tool, process_synthesized_event,
-							 machine);
-		if (err < 0) {
-			pr_err("Couldn't synthesize event_types.\n");
-			goto out_delete_session;
-		}
-
 		if (have_tracepoints(&evsel_list->entries)) {
 			/*
 			 * FIXME err <= 0 here actually means that
@@ -904,7 +897,6 @@
 int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	int err = -ENOMEM;
-	struct perf_evsel *pos;
 	struct perf_evlist *evsel_list;
 	struct perf_record *rec = &record;
 	char errbuf[BUFSIZ];
@@ -968,11 +960,6 @@
 	if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
 		usage_with_options(record_usage, record_options);
 
-	list_for_each_entry(pos, &evsel_list->entries, node) {
-		if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
-			goto out_free_fd;
-	}
-
 	if (rec->opts.user_interval != ULLONG_MAX)
 		rec->opts.default_interval = rec->opts.user_interval;
 	if (rec->opts.user_freq != UINT_MAX)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3662047..9725aa3 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -49,7 +49,6 @@
 	bool			mem_mode;
 	struct perf_read_values	show_threads_values;
 	const char		*pretty_printing_style;
-	symbol_filter_t		annotate_init;
 	const char		*cpu_list;
 	const char		*symbol_filter_str;
 	float			min_percent;
@@ -89,7 +88,7 @@
 	if ((sort__has_parent || symbol_conf.use_callchain) &&
 	    sample->callchain) {
 		err = machine__resolve_callchain(machine, evsel, al->thread,
-						 sample, &parent);
+						 sample, &parent, al);
 		if (err)
 			return err;
 	}
@@ -180,7 +179,7 @@
 	if ((sort__has_parent || symbol_conf.use_callchain)
 	    && sample->callchain) {
 		err = machine__resolve_callchain(machine, evsel, al->thread,
-						 sample, &parent);
+						 sample, &parent, al);
 		if (err)
 			return err;
 	}
@@ -254,7 +253,7 @@
 
 	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
 		err = machine__resolve_callchain(machine, evsel, al->thread,
-						 sample, &parent);
+						 sample, &parent, al);
 		if (err)
 			return err;
 	}
@@ -305,8 +304,7 @@
 	struct addr_location al;
 	int ret;
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample,
-					  rep->annotate_init) < 0) {
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 		fprintf(stderr, "problem processing %d event, skipping it.\n",
 			event->header.type);
 		return -1;
@@ -367,7 +365,7 @@
 static int perf_report__setup_sample_type(struct perf_report *rep)
 {
 	struct perf_session *self = rep->session;
-	u64 sample_type = perf_evlist__sample_type(self->evlist);
+	u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
 
 	if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
 		if (sort__has_parent) {
@@ -497,7 +495,7 @@
 		ret = perf_session__cpu_bitmap(session, rep->cpu_list,
 					       rep->cpu_bitmap);
 		if (ret)
-			goto out_delete;
+			return ret;
 	}
 
 	if (use_browser <= 0)
@@ -508,11 +506,11 @@
 
 	ret = perf_report__setup_sample_type(rep);
 	if (ret)
-		goto out_delete;
+		return ret;
 
 	ret = perf_session__process_events(session, &rep->tool);
 	if (ret)
-		goto out_delete;
+		return ret;
 
 	kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
 	kernel_kmap = map__kmap(kernel_map);
@@ -547,7 +545,7 @@
 
 	if (dump_trace) {
 		perf_session__fprintf_nr_events(session, stdout);
-		goto out_delete;
+		return 0;
 	}
 
 	nr_samples = 0;
@@ -572,7 +570,7 @@
 
 	if (nr_samples == 0) {
 		ui__error("The %s file has no samples!\n", session->filename);
-		goto out_delete;
+		return 0;
 	}
 
 	list_for_each_entry(pos, &session->evlist->entries, node)
@@ -598,19 +596,6 @@
 	} else
 		perf_evlist__tty_browse_hists(session->evlist, rep, help);
 
-out_delete:
-	/*
-	 * Speed up the exit process, for large files this can
-	 * take quite a while.
-	 *
-	 * XXX Enable this when using valgrind or if we ever
-	 * librarize this command.
-	 *
-	 * Also experiment with obstacks to see how much speed
-	 * up we'll get here.
-	 *
- 	 * perf_session__delete(session);
- 	 */
 	return ret;
 }
 
@@ -680,12 +665,23 @@
 	}
 
 	/* get the call chain order */
-	if (!strcmp(tok2, "caller"))
+	if (!strncmp(tok2, "caller", strlen("caller")))
 		callchain_param.order = ORDER_CALLER;
-	else if (!strcmp(tok2, "callee"))
+	else if (!strncmp(tok2, "callee", strlen("callee")))
 		callchain_param.order = ORDER_CALLEE;
 	else
 		return -1;
+
+	/* Get the sort key */
+	tok2 = strtok(NULL, ",");
+	if (!tok2)
+		goto setup;
+	if (!strncmp(tok2, "function", strlen("function")))
+		callchain_param.key = CCKEY_FUNCTION;
+	else if (!strncmp(tok2, "address", strlen("address")))
+		callchain_param.key = CCKEY_ADDRESS;
+	else
+		return -1;
 setup:
 	if (callchain_register_param(&callchain_param) < 0) {
 		fprintf(stderr, "Can't register callchain params\n");
@@ -694,6 +690,24 @@
 	return 0;
 }
 
+int
+report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
+				const char *arg, int unset __maybe_unused)
+{
+	if (arg) {
+		int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
+		if (err) {
+			char buf[BUFSIZ];
+			regerror(err, &ignore_callees_regex, buf, sizeof(buf));
+			pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
+			return -1;
+		}
+		have_ignore_callees = 1;
+	}
+
+	return 0;
+}
+
 static int
 parse_branch_mode(const struct option *opt __maybe_unused,
 		  const char *str __maybe_unused, int unset)
@@ -736,7 +750,6 @@
 			.lost		 = perf_event__process_lost,
 			.read		 = process_read_event,
 			.attr		 = perf_event__process_attr,
-			.event_type	 = perf_event__process_event_type,
 			.tracing_data	 = perf_event__process_tracing_data,
 			.build_id	 = perf_event__process_build_id,
 			.ordered_samples = true,
@@ -780,10 +793,13 @@
 	OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
 		    "Only display entries with parent-match"),
 	OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
-		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. "
-		     "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
+		     "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
+		     "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
 	OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
 		    "alias for inverted call graph"),
+	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
+		   "ignore callees of these functions in call graphs",
+		   report_parse_ignore_callees_opt),
 	OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
 		   "only consider symbols in these dsos"),
 	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -853,7 +869,6 @@
 		setup_browser(true);
 	else {
 		use_browser = 0;
-		perf_hpp__column_enable(PERF_HPP__OVERHEAD);
 		perf_hpp__init();
 	}
 
@@ -907,7 +922,8 @@
 	 */
 	if (use_browser == 1 && sort__has_sym) {
 		symbol_conf.priv_size = sizeof(struct annotation);
-		report.annotate_init  = symbol__annotate_init;
+		machines__set_symbol_filter(&session->machines,
+					    symbol__annotate_init);
 		/*
  		 * For searching by name on the "Browse map details".
  		 * providing it only in verbose mode not to bloat too
@@ -931,14 +947,6 @@
 	if (parent_pattern != default_parent_pattern) {
 		if (sort_dimension__add("parent") < 0)
 			goto error;
-
-		/*
-		 * Only show the parent fields if we explicitly
-		 * sort that way. If we only use parent machinery
-		 * for filtering, we don't want it.
-		 */
-		if (!strstr(sort_order, "parent"))
-			sort_parent.elide = 1;
 	}
 
 	if (argc) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index fed9ae4..d8c51b2 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -109,8 +109,9 @@
 	int (*wakeup_event)(struct perf_sched *sched, struct perf_evsel *evsel,
 			    struct perf_sample *sample, struct machine *machine);
 
-	int (*fork_event)(struct perf_sched *sched, struct perf_evsel *evsel,
-			  struct perf_sample *sample);
+	/* PERF_RECORD_FORK event, not sched_process_fork tracepoint */
+	int (*fork_event)(struct perf_sched *sched, union perf_event *event,
+			  struct machine *machine);
 
 	int (*migrate_task_event)(struct perf_sched *sched,
 				  struct perf_evsel *evsel,
@@ -717,22 +718,31 @@
 	return 0;
 }
 
-static int replay_fork_event(struct perf_sched *sched, struct perf_evsel *evsel,
-			     struct perf_sample *sample)
+static int replay_fork_event(struct perf_sched *sched,
+			     union perf_event *event,
+			     struct machine *machine)
 {
-	const char *parent_comm = perf_evsel__strval(evsel, sample, "parent_comm"),
-		   *child_comm  = perf_evsel__strval(evsel, sample, "child_comm");
-	const u32 parent_pid  = perf_evsel__intval(evsel, sample, "parent_pid"),
-		  child_pid  = perf_evsel__intval(evsel, sample, "child_pid");
+	struct thread *child, *parent;
 
-	if (verbose) {
-		printf("sched_fork event %p\n", evsel);
-		printf("... parent: %s/%d\n", parent_comm, parent_pid);
-		printf("...  child: %s/%d\n", child_comm, child_pid);
+	child = machine__findnew_thread(machine, event->fork.pid,
+					event->fork.tid);
+	parent = machine__findnew_thread(machine, event->fork.ppid,
+					 event->fork.ptid);
+
+	if (child == NULL || parent == NULL) {
+		pr_debug("thread does not exist on fork event: child %p, parent %p\n",
+				 child, parent);
+		return 0;
 	}
 
-	register_pid(sched, parent_pid, parent_comm);
-	register_pid(sched, child_pid, child_comm);
+	if (verbose) {
+		printf("fork event\n");
+		printf("... parent: %s/%d\n", parent->comm, parent->tid);
+		printf("...  child: %s/%d\n", child->comm, child->tid);
+	}
+
+	register_pid(sched, parent->tid, parent->comm);
+	register_pid(sched, child->tid, child->comm);
 	return 0;
 }
 
@@ -824,14 +834,6 @@
 	return 0;
 }
 
-static int latency_fork_event(struct perf_sched *sched __maybe_unused,
-			      struct perf_evsel *evsel __maybe_unused,
-			      struct perf_sample *sample __maybe_unused)
-{
-	/* should insert the newcomer */
-	return 0;
-}
-
 static char sched_out_state(u64 prev_state)
 {
 	const char *str = TASK_STATE_TO_CHAR_STR;
@@ -934,8 +936,8 @@
 		return -1;
 	}
 
-	sched_out = machine__findnew_thread(machine, prev_pid);
-	sched_in = machine__findnew_thread(machine, next_pid);
+	sched_out = machine__findnew_thread(machine, 0, prev_pid);
+	sched_in = machine__findnew_thread(machine, 0, next_pid);
 
 	out_events = thread_atoms_search(&sched->atom_root, sched_out, &sched->cmp_pid);
 	if (!out_events) {
@@ -978,7 +980,7 @@
 {
 	const u32 pid	   = perf_evsel__intval(evsel, sample, "pid");
 	const u64 runtime  = perf_evsel__intval(evsel, sample, "runtime");
-	struct thread *thread = machine__findnew_thread(machine, pid);
+	struct thread *thread = machine__findnew_thread(machine, 0, pid);
 	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
 	u64 timestamp = sample->time;
 	int cpu = sample->cpu;
@@ -1016,7 +1018,7 @@
 	if (!success)
 		return 0;
 
-	wakee = machine__findnew_thread(machine, pid);
+	wakee = machine__findnew_thread(machine, 0, pid);
 	atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
 	if (!atoms) {
 		if (thread_atoms_insert(sched, wakee))
@@ -1070,12 +1072,12 @@
 	if (sched->profile_cpu == -1)
 		return 0;
 
-	migrant = machine__findnew_thread(machine, pid);
+	migrant = machine__findnew_thread(machine, 0, pid);
 	atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
 	if (!atoms) {
 		if (thread_atoms_insert(sched, migrant))
 			return -1;
-		register_pid(sched, migrant->pid, migrant->comm);
+		register_pid(sched, migrant->tid, migrant->comm);
 		atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
 		if (!atoms) {
 			pr_err("migration-event: Internal tree error");
@@ -1115,7 +1117,7 @@
 	sched->all_runtime += work_list->total_runtime;
 	sched->all_count   += work_list->nb_atoms;
 
-	ret = printf("  %s:%d ", work_list->thread->comm, work_list->thread->pid);
+	ret = printf("  %s:%d ", work_list->thread->comm, work_list->thread->tid);
 
 	for (i = 0; i < 24 - ret; i++)
 		printf(" ");
@@ -1131,9 +1133,9 @@
 
 static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
 {
-	if (l->thread->pid < r->thread->pid)
+	if (l->thread->tid < r->thread->tid)
 		return -1;
-	if (l->thread->pid > r->thread->pid)
+	if (l->thread->tid > r->thread->tid)
 		return 1;
 
 	return 0;
@@ -1289,8 +1291,8 @@
 		return -1;
 	}
 
-	sched_out = machine__findnew_thread(machine, prev_pid);
-	sched_in = machine__findnew_thread(machine, next_pid);
+	sched_out = machine__findnew_thread(machine, 0, prev_pid);
+	sched_in = machine__findnew_thread(machine, 0, next_pid);
 
 	sched->curr_thread[this_cpu] = sched_in;
 
@@ -1321,7 +1323,7 @@
 			printf("*");
 
 		if (sched->curr_thread[cpu]) {
-			if (sched->curr_thread[cpu]->pid)
+			if (sched->curr_thread[cpu]->tid)
 				printf("%2s ", sched->curr_thread[cpu]->shortname);
 			else
 				printf(".  ");
@@ -1332,7 +1334,7 @@
 	printf("  %12.6f secs ", (double)timestamp/1e9);
 	if (new_shortname) {
 		printf("%s => %s:%d\n",
-			sched_in->shortname, sched_in->comm, sched_in->pid);
+			sched_in->shortname, sched_in->comm, sched_in->tid);
 	} else {
 		printf("\n");
 	}
@@ -1379,28 +1381,23 @@
 	return 0;
 }
 
-static int process_sched_fork_event(struct perf_tool *tool,
-				    struct perf_evsel *evsel,
-				    struct perf_sample *sample,
-				    struct machine *machine __maybe_unused)
+static int perf_sched__process_fork_event(struct perf_tool *tool,
+					  union perf_event *event,
+					  struct perf_sample *sample,
+					  struct machine *machine)
 {
 	struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
 
+	/* run the fork event through the perf machineruy */
+	perf_event__process_fork(tool, event, sample, machine);
+
+	/* and then run additional processing needed for this command */
 	if (sched->tp_handler->fork_event)
-		return sched->tp_handler->fork_event(sched, evsel, sample);
+		return sched->tp_handler->fork_event(sched, event, machine);
 
 	return 0;
 }
 
-static int process_sched_exit_event(struct perf_tool *tool __maybe_unused,
-				    struct perf_evsel *evsel,
-				    struct perf_sample *sample __maybe_unused,
-				    struct machine *machine __maybe_unused)
-{
-	pr_debug("sched_exit event %p\n", evsel);
-	return 0;
-}
-
 static int process_sched_migrate_task_event(struct perf_tool *tool,
 					    struct perf_evsel *evsel,
 					    struct perf_sample *sample,
@@ -1425,15 +1422,8 @@
 						 struct perf_evsel *evsel,
 						 struct machine *machine)
 {
-	struct thread *thread = machine__findnew_thread(machine, sample->tid);
 	int err = 0;
 
-	if (thread == NULL) {
-		pr_debug("problem processing %s event, skipping it.\n",
-			 perf_evsel__name(evsel));
-		return -1;
-	}
-
 	evsel->hists.stats.total_period += sample->period;
 	hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
 
@@ -1445,7 +1435,7 @@
 	return err;
 }
 
-static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
+static int perf_sched__read_events(struct perf_sched *sched,
 				   struct perf_session **psession)
 {
 	const struct perf_evsel_str_handler handlers[] = {
@@ -1453,8 +1443,6 @@
 		{ "sched:sched_stat_runtime", process_sched_runtime_event, },
 		{ "sched:sched_wakeup",	      process_sched_wakeup_event, },
 		{ "sched:sched_wakeup_new",   process_sched_wakeup_event, },
-		{ "sched:sched_process_fork", process_sched_fork_event, },
-		{ "sched:sched_process_exit", process_sched_exit_event, },
 		{ "sched:sched_migrate_task", process_sched_migrate_task_event, },
 	};
 	struct perf_session *session;
@@ -1480,11 +1468,10 @@
 		sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
 	}
 
-	if (destroy)
-		perf_session__delete(session);
-
 	if (psession)
 		*psession = session;
+	else
+		perf_session__delete(session);
 
 	return 0;
 
@@ -1529,8 +1516,11 @@
 	struct perf_session *session;
 
 	setup_pager();
-	if (perf_sched__read_events(sched, false, &session))
+
+	/* save session -- references to threads are held in work_list */
+	if (perf_sched__read_events(sched, &session))
 		return -1;
+
 	perf_sched__sort_lat(sched);
 
 	printf("\n ---------------------------------------------------------------------------------------------------------------\n");
@@ -1565,7 +1555,7 @@
 	sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
 
 	setup_pager();
-	if (perf_sched__read_events(sched, true, NULL))
+	if (perf_sched__read_events(sched, NULL))
 		return -1;
 	print_bad_events(sched);
 	return 0;
@@ -1580,7 +1570,7 @@
 
 	test_calibrations(sched);
 
-	if (perf_sched__read_events(sched, true, NULL))
+	if (perf_sched__read_events(sched, NULL))
 		return -1;
 
 	printf("nr_run_events:        %ld\n", sched->nr_run_events);
@@ -1639,7 +1629,6 @@
 		"-e", "sched:sched_stat_sleep",
 		"-e", "sched:sched_stat_iowait",
 		"-e", "sched:sched_stat_runtime",
-		"-e", "sched:sched_process_exit",
 		"-e", "sched:sched_process_fork",
 		"-e", "sched:sched_wakeup",
 		"-e", "sched:sched_migrate_task",
@@ -1662,28 +1651,29 @@
 	return cmd_record(i, rec_argv, NULL);
 }
 
+static const char default_sort_order[] = "avg, max, switch, runtime";
+static struct perf_sched sched = {
+	.tool = {
+		.sample		 = perf_sched__process_tracepoint_sample,
+		.comm		 = perf_event__process_comm,
+		.lost		 = perf_event__process_lost,
+		.fork		 = perf_sched__process_fork_event,
+		.ordered_samples = true,
+	},
+	.cmp_pid	      = LIST_HEAD_INIT(sched.cmp_pid),
+	.sort_list	      = LIST_HEAD_INIT(sched.sort_list),
+	.start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
+	.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
+	.curr_pid	      = { [0 ... MAX_CPUS - 1] = -1 },
+	.sort_order	      = default_sort_order,
+	.replay_repeat	      = 10,
+	.profile_cpu	      = -1,
+	.next_shortname1      = 'A',
+	.next_shortname2      = '0',
+};
+
 int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-	const char default_sort_order[] = "avg, max, switch, runtime";
-	struct perf_sched sched = {
-		.tool = {
-			.sample		 = perf_sched__process_tracepoint_sample,
-			.comm		 = perf_event__process_comm,
-			.lost		 = perf_event__process_lost,
-			.fork		 = perf_event__process_fork,
-			.ordered_samples = true,
-		},
-		.cmp_pid	      = LIST_HEAD_INIT(sched.cmp_pid),
-		.sort_list	      = LIST_HEAD_INIT(sched.sort_list),
-		.start_work_mutex     = PTHREAD_MUTEX_INITIALIZER,
-		.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
-		.curr_pid	      = { [0 ... MAX_CPUS - 1] = -1 },
-		.sort_order	      = default_sort_order,
-		.replay_repeat	      = 10,
-		.profile_cpu	      = -1,
-		.next_shortname1      = 'A',
-		.next_shortname2      = '0',
-	};
 	const struct option latency_options[] = {
 	OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
 		   "sort by key(s): runtime, switch, avg, max"),
@@ -1729,7 +1719,6 @@
 		.wakeup_event	    = latency_wakeup_event,
 		.switch_event	    = latency_switch_event,
 		.runtime_event	    = latency_runtime_event,
-		.fork_event	    = latency_fork_event,
 		.migrate_task_event = latency_migrate_task_event,
 	};
 	struct trace_sched_handler map_ops  = {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 92d4658..93a34ce 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -24,6 +24,7 @@
 static u64			nr_unordered;
 extern const struct option	record_options[];
 static bool			no_callchain;
+static bool			latency_format;
 static bool			system_wide;
 static const char		*cpu_list;
 static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -65,6 +66,7 @@
 static struct {
 	bool user_set;
 	bool wildcard_set;
+	unsigned int print_ip_opts;
 	u64 fields;
 	u64 invalid_fields;
 } output[PERF_TYPE_MAX] = {
@@ -234,6 +236,7 @@
 {
 	int j;
 	struct perf_evsel *evsel;
+	struct perf_event_attr *attr;
 
 	for (j = 0; j < PERF_TYPE_MAX; ++j) {
 		evsel = perf_session__find_first_evtype(session, j);
@@ -252,6 +255,24 @@
 		if (evsel && output[j].fields &&
 			perf_evsel__check_attr(evsel, session))
 			return -1;
+
+		if (evsel == NULL)
+			continue;
+
+		attr = &evsel->attr;
+
+		output[j].print_ip_opts = 0;
+		if (PRINT_FIELD(IP))
+			output[j].print_ip_opts |= PRINT_IP_OPT_IP;
+
+		if (PRINT_FIELD(SYM))
+			output[j].print_ip_opts |= PRINT_IP_OPT_SYM;
+
+		if (PRINT_FIELD(DSO))
+			output[j].print_ip_opts |= PRINT_IP_OPT_DSO;
+
+		if (PRINT_FIELD(SYMOFFSET))
+			output[j].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
 	}
 
 	return 0;
@@ -381,8 +402,8 @@
 		else
 			printf("\n");
 		perf_evsel__print_ip(evsel, event, sample, machine,
-				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
-				     PRINT_FIELD(SYMOFFSET));
+				     output[attr->type].print_ip_opts,
+				     PERF_MAX_STACK_DEPTH);
 	}
 
 	printf(" => ");
@@ -396,10 +417,10 @@
 
 static void process_event(union perf_event *event, struct perf_sample *sample,
 			  struct perf_evsel *evsel, struct machine *machine,
-			  struct addr_location *al)
+			  struct thread *thread,
+			  struct addr_location *al __maybe_unused)
 {
 	struct perf_event_attr *attr = &evsel->attr;
-	struct thread *thread = al->thread;
 
 	if (output[attr->type].fields == 0)
 		return;
@@ -422,9 +443,10 @@
 			printf(" ");
 		else
 			printf("\n");
+
 		perf_evsel__print_ip(evsel, event, sample, machine,
-				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
-				     PRINT_FIELD(SYMOFFSET));
+				     output[attr->type].print_ip_opts,
+				     PERF_MAX_STACK_DEPTH);
 	}
 
 	printf("\n");
@@ -479,7 +501,8 @@
 				struct machine *machine)
 {
 	struct addr_location al;
-	struct thread *thread = machine__findnew_thread(machine, event->ip.tid);
+	struct thread *thread = machine__findnew_thread(machine, sample->pid,
+							sample->tid);
 
 	if (thread == NULL) {
 		pr_debug("problem processing %d event, skipping it.\n",
@@ -498,7 +521,7 @@
 		return 0;
 	}
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) {
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 		pr_err("problem processing %d event, skipping it.\n",
 		       event->header.type);
 		return -1;
@@ -510,7 +533,7 @@
 	if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
 		return 0;
 
-	scripting_ops->process_event(event, sample, evsel, machine, &al);
+	scripting_ops->process_event(event, sample, evsel, machine, thread, &al);
 
 	evsel->hists.stats.total_period += sample->period;
 	return 0;
@@ -523,7 +546,6 @@
 	.exit		 = perf_event__process_exit,
 	.fork		 = perf_event__process_fork,
 	.attr		 = perf_event__process_attr,
-	.event_type	 = perf_event__process_event_type,
 	.tracing_data	 = perf_event__process_tracing_data,
 	.build_id	 = perf_event__process_build_id,
 	.ordered_samples = true,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 352fbd7..f686d5f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -100,6 +100,7 @@
 static const char		*post_cmd			= NULL;
 static bool			sync_run			= false;
 static unsigned int		interval			= 0;
+static unsigned int		initial_delay			= 0;
 static bool			forever				= false;
 static struct timespec		ref_time;
 static struct cpu_map		*aggr_map;
@@ -254,7 +255,8 @@
 	if (!perf_target__has_task(&target) &&
 	    perf_evsel__is_group_leader(evsel)) {
 		attr->disabled = 1;
-		attr->enable_on_exec = 1;
+		if (!initial_delay)
+			attr->enable_on_exec = 1;
 	}
 
 	return perf_evsel__open_per_thread(evsel, evsel_list->threads);
@@ -414,6 +416,22 @@
 		list_for_each_entry(counter, &evsel_list->entries, node)
 			print_counter_aggr(counter, prefix);
 	}
+
+	fflush(output);
+}
+
+static void handle_initial_delay(void)
+{
+	struct perf_evsel *counter;
+
+	if (initial_delay) {
+		const int ncpus = cpu_map__nr(evsel_list->cpus),
+			nthreads = thread_map__nr(evsel_list->threads);
+
+		usleep(initial_delay * 1000);
+		list_for_each_entry(counter, &evsel_list->entries, node)
+			perf_evsel__enable(counter, ncpus, nthreads);
+	}
 }
 
 static int __run_perf_stat(int argc, const char **argv)
@@ -486,6 +504,7 @@
 
 	if (forks) {
 		perf_evlist__start_workload(evsel_list);
+		handle_initial_delay();
 
 		if (interval) {
 			while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -497,6 +516,7 @@
 		if (WIFSIGNALED(status))
 			psignal(WTERMSIG(status), argv[0]);
 	} else {
+		handle_initial_delay();
 		while (!done) {
 			nanosleep(&ts, NULL);
 			if (interval)
@@ -1419,6 +1439,8 @@
 		     "aggregate counts per processor socket", AGGR_SOCKET),
 	OPT_SET_UINT(0, "per-core", &aggr_mode,
 		     "aggregate counts per physical processor core", AGGR_CORE),
+	OPT_UINTEGER('D', "delay", &initial_delay,
+		     "ms to wait before starting measurement after program start"),
 	OPT_END()
 	};
 	const char * const stat_usage[] = {
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 4536a92..c2e0231 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -12,6 +12,8 @@
  * of the License.
  */
 
+#include <traceevent/event-parse.h>
+
 #include "builtin.h"
 
 #include "util/util.h"
@@ -19,6 +21,7 @@
 #include "util/color.h"
 #include <linux/list.h>
 #include "util/cache.h"
+#include "util/evlist.h"
 #include "util/evsel.h"
 #include <linux/rbtree.h>
 #include "util/symbol.h"
@@ -328,25 +331,6 @@
 	int   success;
 };
 
-/*
- * trace_flag_type is an enumeration that holds different
- * states when a trace occurs. These are:
- *  IRQS_OFF            - interrupts were disabled
- *  IRQS_NOSUPPORT      - arch does not support irqs_disabled_flags
- *  NEED_RESCED         - reschedule is requested
- *  HARDIRQ             - inside an interrupt handler
- *  SOFTIRQ             - inside a softirq handler
- */
-enum trace_flag_type {
-	TRACE_FLAG_IRQS_OFF		= 0x01,
-	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02,
-	TRACE_FLAG_NEED_RESCHED		= 0x04,
-	TRACE_FLAG_HARDIRQ		= 0x08,
-	TRACE_FLAG_SOFTIRQ		= 0x10,
-};
-
-
-
 struct sched_switch {
 	struct trace_entry te;
 	char prev_comm[TASK_COMM_LEN];
@@ -479,6 +463,8 @@
 	}
 }
 
+typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
+				  struct perf_sample *sample);
 
 static int process_sample_event(struct perf_tool *tool __maybe_unused,
 				union perf_event *event __maybe_unused,
@@ -486,8 +472,6 @@
 				struct perf_evsel *evsel,
 				struct machine *machine __maybe_unused)
 {
-	struct trace_entry *te;
-
 	if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
 		if (!first_time || first_time > sample->time)
 			first_time = sample->time;
@@ -495,69 +479,90 @@
 			last_time = sample->time;
 	}
 
-	te = (void *)sample->raw_data;
-	if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
-		char *event_str;
-#ifdef SUPPORT_OLD_POWER_EVENTS
-		struct power_entry_old *peo;
-		peo = (void *)te;
-#endif
-		/*
-		 * FIXME: use evsel, its already mapped from id to perf_evsel,
-		 * remove perf_header__find_event infrastructure bits.
-		 * Mapping all these "power:cpu_idle" strings to the tracepoint
-		 * ID and then just comparing against evsel->attr.config.
-		 *
-		 * e.g.:
-		 *
-		 * if (evsel->attr.config == power_cpu_idle_id)
-		 */
-		event_str = perf_header__find_event(te->type);
+	if (sample->cpu > numcpus)
+		numcpus = sample->cpu;
 
-		if (!event_str)
-			return 0;
-
-		if (sample->cpu > numcpus)
-			numcpus = sample->cpu;
-
-		if (strcmp(event_str, "power:cpu_idle") == 0) {
-			struct power_processor_entry *ppe = (void *)te;
-			if (ppe->state == (u32)PWR_EVENT_EXIT)
-				c_state_end(ppe->cpu_id, sample->time);
-			else
-				c_state_start(ppe->cpu_id, sample->time,
-					      ppe->state);
-		}
-		else if (strcmp(event_str, "power:cpu_frequency") == 0) {
-			struct power_processor_entry *ppe = (void *)te;
-			p_state_change(ppe->cpu_id, sample->time, ppe->state);
-		}
-
-		else if (strcmp(event_str, "sched:sched_wakeup") == 0)
-			sched_wakeup(sample->cpu, sample->time, sample->pid, te);
-
-		else if (strcmp(event_str, "sched:sched_switch") == 0)
-			sched_switch(sample->cpu, sample->time, te);
-
-#ifdef SUPPORT_OLD_POWER_EVENTS
-		if (use_old_power_events) {
-			if (strcmp(event_str, "power:power_start") == 0)
-				c_state_start(peo->cpu_id, sample->time,
-					      peo->value);
-
-			else if (strcmp(event_str, "power:power_end") == 0)
-				c_state_end(sample->cpu, sample->time);
-
-			else if (strcmp(event_str,
-					"power:power_frequency") == 0)
-				p_state_change(peo->cpu_id, sample->time,
-					       peo->value);
-		}
-#endif
+	if (evsel->handler.func != NULL) {
+		tracepoint_handler f = evsel->handler.func;
+		return f(evsel, sample);
 	}
+
 	return 0;
 }
 
+static int
+process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
+			struct perf_sample *sample)
+{
+	struct power_processor_entry *ppe = sample->raw_data;
+
+	if (ppe->state == (u32) PWR_EVENT_EXIT)
+		c_state_end(ppe->cpu_id, sample->time);
+	else
+		c_state_start(ppe->cpu_id, sample->time, ppe->state);
+	return 0;
+}
+
+static int
+process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
+			     struct perf_sample *sample)
+{
+	struct power_processor_entry *ppe = sample->raw_data;
+
+	p_state_change(ppe->cpu_id, sample->time, ppe->state);
+	return 0;
+}
+
+static int
+process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
+			    struct perf_sample *sample)
+{
+	struct trace_entry *te = sample->raw_data;
+
+	sched_wakeup(sample->cpu, sample->time, sample->pid, te);
+	return 0;
+}
+
+static int
+process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
+			    struct perf_sample *sample)
+{
+	struct trace_entry *te = sample->raw_data;
+
+	sched_switch(sample->cpu, sample->time, te);
+	return 0;
+}
+
+#ifdef SUPPORT_OLD_POWER_EVENTS
+static int
+process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
+			   struct perf_sample *sample)
+{
+	struct power_entry_old *peo = sample->raw_data;
+
+	c_state_start(peo->cpu_id, sample->time, peo->value);
+	return 0;
+}
+
+static int
+process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
+			 struct perf_sample *sample)
+{
+	c_state_end(sample->cpu, sample->time);
+	return 0;
+}
+
+static int
+process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
+			       struct perf_sample *sample)
+{
+	struct power_entry_old *peo = sample->raw_data;
+
+	p_state_change(peo->cpu_id, sample->time, peo->value);
+	return 0;
+}
+#endif /* SUPPORT_OLD_POWER_EVENTS */
+
 /*
  * After the last sample we need to wrap up the current C/P state
  * and close out each CPU for these.
@@ -974,6 +979,17 @@
 		.sample		 = process_sample_event,
 		.ordered_samples = true,
 	};
+	const struct perf_evsel_str_handler power_tracepoints[] = {
+		{ "power:cpu_idle",		process_sample_cpu_idle },
+		{ "power:cpu_frequency",	process_sample_cpu_frequency },
+		{ "sched:sched_wakeup",		process_sample_sched_wakeup },
+		{ "sched:sched_switch",		process_sample_sched_switch },
+#ifdef SUPPORT_OLD_POWER_EVENTS
+		{ "power:power_start",		process_sample_power_start },
+		{ "power:power_end",		process_sample_power_end },
+		{ "power:power_frequency",	process_sample_power_frequency },
+#endif
+	};
 	struct perf_session *session = perf_session__new(input_name, O_RDONLY,
 							 0, false, &perf_timechart);
 	int ret = -EINVAL;
@@ -984,6 +1000,12 @@
 	if (!perf_session__has_traces(session, "timechart record"))
 		goto out_delete;
 
+	if (perf_session__set_tracepoints_handlers(session,
+						   power_tracepoints)) {
+		pr_err("Initializing session tracepoint handlers failed\n");
+		goto out_delete;
+	}
+
 	ret = perf_session__process_events(session, &perf_timechart);
 	if (ret)
 		goto out_delete;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e06c4f8..2122141 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -40,6 +40,7 @@
 #include "util/xyarray.h"
 #include "util/sort.h"
 #include "util/intlist.h"
+#include "arch/common.h"
 
 #include "util/debug.h"
 
@@ -102,7 +103,8 @@
 	/*
 	 * We can't annotate with just /proc/kallsyms
 	 */
-	if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
+	if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
+	    !dso__is_kcore(map->dso)) {
 		pr_err("Can't annotate %s: No vmlinux file was found in the "
 		       "path\n", sym->name);
 		sleep(1);
@@ -237,8 +239,6 @@
 	pthread_mutex_unlock(&notes->lock);
 }
 
-static const char		CONSOLE_CLEAR[] = "";
-
 static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
 						     struct addr_location *al,
 						     struct perf_sample *sample)
@@ -689,7 +689,7 @@
 {
 	struct perf_top *top = container_of(tool, struct perf_top, tool);
 	struct symbol *parent = NULL;
-	u64 ip = event->ip.ip;
+	u64 ip = sample->ip;
 	struct addr_location al;
 	int err;
 
@@ -699,10 +699,10 @@
 		if (!seen)
 			seen = intlist__new(NULL);
 
-		if (!intlist__has_entry(seen, event->ip.pid)) {
+		if (!intlist__has_entry(seen, sample->pid)) {
 			pr_err("Can't find guest [%d]'s kernel information\n",
-				event->ip.pid);
-			intlist__add(seen, event->ip.pid);
+				sample->pid);
+			intlist__add(seen, sample->pid);
 		}
 		return;
 	}
@@ -716,8 +716,7 @@
 	if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
 		top->exact_samples++;
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample,
-					  symbol_filter) < 0 ||
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 ||
 	    al.filtered)
 		return;
 
@@ -772,8 +771,7 @@
 		    sample->callchain) {
 			err = machine__resolve_callchain(machine, evsel,
 							 al.thread, sample,
-							 &parent);
-
+							 &parent, &al);
 			if (err)
 				return;
 		}
@@ -838,7 +836,8 @@
 			break;
 		case PERF_RECORD_MISC_GUEST_KERNEL:
 			++top->guest_kernel_samples;
-			machine = perf_session__find_machine(session, event->ip.pid);
+			machine = perf_session__find_machine(session,
+							     sample.pid);
 			break;
 		case PERF_RECORD_MISC_GUEST_USER:
 			++top->guest_us_samples;
@@ -939,6 +938,14 @@
 	if (top->session == NULL)
 		return -ENOMEM;
 
+	machines__set_symbol_filter(&top->session->machines, symbol_filter);
+
+	if (!objdump_path) {
+		ret = perf_session_env__lookup_objdump(&top->session->header.env);
+		if (ret)
+			goto out_delete;
+	}
+
 	ret = perf_top__setup_sample_type(top);
 	if (ret)
 		goto out_delete;
@@ -1102,6 +1109,9 @@
 	OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
 			     "mode[,dump_size]", record_callchain_help,
 			     &parse_callchain_opt, "fp"),
+	OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
+		   "ignore callees of these functions in call graphs",
+		   report_parse_ignore_callees_opt),
 	OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
 		    "Show a column with the sum of periods"),
 	OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1114,6 +1124,8 @@
 		    "Interleave source code with assembly code (default)"),
 	OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
 		    "Display raw encoding of assembly instructions (default)"),
+	OPT_STRING(0, "objdump", &objdump_path, "path",
+		    "objdump binary to use for disassembly and annotations"),
 	OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
 		   "Specify disassembler style (e.g. -M intel for intel syntax)"),
 	OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index ab3ed4a..b6f0725 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,34 +1,331 @@
+#include <traceevent/event-parse.h>
 #include "builtin.h"
 #include "util/color.h"
+#include "util/debug.h"
 #include "util/evlist.h"
 #include "util/machine.h"
+#include "util/session.h"
 #include "util/thread.h"
 #include "util/parse-options.h"
+#include "util/strlist.h"
+#include "util/intlist.h"
 #include "util/thread_map.h"
-#include "event-parse.h"
 
 #include <libaudit.h>
 #include <stdlib.h>
+#include <sys/mman.h>
+#include <linux/futex.h>
+
+static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
+					 unsigned long arg,
+					 u8 arg_idx __maybe_unused,
+					 u8 *arg_mask __maybe_unused)
+{
+	return scnprintf(bf, size, "%#lx", arg);
+}
+
+#define SCA_HEX syscall_arg__scnprintf_hex
+
+static size_t syscall_arg__scnprintf_whence(char *bf, size_t size,
+					    unsigned long arg,
+					    u8 arg_idx __maybe_unused,
+					    u8 *arg_mask __maybe_unused)
+{
+	int whence = arg;
+
+	switch (whence) {
+#define P_WHENCE(n) case SEEK_##n: return scnprintf(bf, size, #n)
+	P_WHENCE(SET);
+	P_WHENCE(CUR);
+	P_WHENCE(END);
+#ifdef SEEK_DATA
+	P_WHENCE(DATA);
+#endif
+#ifdef SEEK_HOLE
+	P_WHENCE(HOLE);
+#endif
+#undef P_WHENCE
+	default: break;
+	}
+
+	return scnprintf(bf, size, "%#x", whence);
+}
+
+#define SCA_WHENCE syscall_arg__scnprintf_whence
+
+static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
+					       unsigned long arg,
+					       u8 arg_idx __maybe_unused,
+					       u8 *arg_mask __maybe_unused)
+{
+	int printed = 0, prot = arg;
+
+	if (prot == PROT_NONE)
+		return scnprintf(bf, size, "NONE");
+#define	P_MMAP_PROT(n) \
+	if (prot & PROT_##n) { \
+		printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+		prot &= ~PROT_##n; \
+	}
+
+	P_MMAP_PROT(EXEC);
+	P_MMAP_PROT(READ);
+	P_MMAP_PROT(WRITE);
+#ifdef PROT_SEM
+	P_MMAP_PROT(SEM);
+#endif
+	P_MMAP_PROT(GROWSDOWN);
+	P_MMAP_PROT(GROWSUP);
+#undef P_MMAP_PROT
+
+	if (prot)
+		printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
+
+	return printed;
+}
+
+#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
+
+static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
+						unsigned long arg, u8 arg_idx __maybe_unused,
+						u8 *arg_mask __maybe_unused)
+{
+	int printed = 0, flags = arg;
+
+#define	P_MMAP_FLAG(n) \
+	if (flags & MAP_##n) { \
+		printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+		flags &= ~MAP_##n; \
+	}
+
+	P_MMAP_FLAG(SHARED);
+	P_MMAP_FLAG(PRIVATE);
+	P_MMAP_FLAG(32BIT);
+	P_MMAP_FLAG(ANONYMOUS);
+	P_MMAP_FLAG(DENYWRITE);
+	P_MMAP_FLAG(EXECUTABLE);
+	P_MMAP_FLAG(FILE);
+	P_MMAP_FLAG(FIXED);
+	P_MMAP_FLAG(GROWSDOWN);
+#ifdef MAP_HUGETLB
+	P_MMAP_FLAG(HUGETLB);
+#endif
+	P_MMAP_FLAG(LOCKED);
+	P_MMAP_FLAG(NONBLOCK);
+	P_MMAP_FLAG(NORESERVE);
+	P_MMAP_FLAG(POPULATE);
+	P_MMAP_FLAG(STACK);
+#ifdef MAP_UNINITIALIZED
+	P_MMAP_FLAG(UNINITIALIZED);
+#endif
+#undef P_MMAP_FLAG
+
+	if (flags)
+		printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+	return printed;
+}
+
+#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
+
+static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
+						      unsigned long arg, u8 arg_idx __maybe_unused,
+						      u8 *arg_mask __maybe_unused)
+{
+	int behavior = arg;
+
+	switch (behavior) {
+#define	P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
+	P_MADV_BHV(NORMAL);
+	P_MADV_BHV(RANDOM);
+	P_MADV_BHV(SEQUENTIAL);
+	P_MADV_BHV(WILLNEED);
+	P_MADV_BHV(DONTNEED);
+	P_MADV_BHV(REMOVE);
+	P_MADV_BHV(DONTFORK);
+	P_MADV_BHV(DOFORK);
+	P_MADV_BHV(HWPOISON);
+#ifdef MADV_SOFT_OFFLINE
+	P_MADV_BHV(SOFT_OFFLINE);
+#endif
+	P_MADV_BHV(MERGEABLE);
+	P_MADV_BHV(UNMERGEABLE);
+#ifdef MADV_HUGEPAGE
+	P_MADV_BHV(HUGEPAGE);
+#endif
+#ifdef MADV_NOHUGEPAGE
+	P_MADV_BHV(NOHUGEPAGE);
+#endif
+#ifdef MADV_DONTDUMP
+	P_MADV_BHV(DONTDUMP);
+#endif
+#ifdef MADV_DODUMP
+	P_MADV_BHV(DODUMP);
+#endif
+#undef P_MADV_PHV
+	default: break;
+	}
+
+	return scnprintf(bf, size, "%#x", behavior);
+}
+
+#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
+
+static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, unsigned long arg,
+					      u8 arg_idx __maybe_unused, u8 *arg_mask)
+{
+	enum syscall_futex_args {
+		SCF_UADDR   = (1 << 0),
+		SCF_OP	    = (1 << 1),
+		SCF_VAL	    = (1 << 2),
+		SCF_TIMEOUT = (1 << 3),
+		SCF_UADDR2  = (1 << 4),
+		SCF_VAL3    = (1 << 5),
+	};
+	int op = arg;
+	int cmd = op & FUTEX_CMD_MASK;
+	size_t printed = 0;
+
+	switch (cmd) {
+#define	P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
+	P_FUTEX_OP(WAIT);	    *arg_mask |= SCF_VAL3|SCF_UADDR2;		  break;
+	P_FUTEX_OP(WAKE);	    *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
+	P_FUTEX_OP(FD);		    *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
+	P_FUTEX_OP(REQUEUE);	    *arg_mask |= SCF_VAL3|SCF_TIMEOUT;	          break;
+	P_FUTEX_OP(CMP_REQUEUE);    *arg_mask |= SCF_TIMEOUT;			  break;
+	P_FUTEX_OP(CMP_REQUEUE_PI); *arg_mask |= SCF_TIMEOUT;			  break;
+	P_FUTEX_OP(WAKE_OP);							  break;
+	P_FUTEX_OP(LOCK_PI);	    *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
+	P_FUTEX_OP(UNLOCK_PI);	    *arg_mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
+	P_FUTEX_OP(TRYLOCK_PI);	    *arg_mask |= SCF_VAL3|SCF_UADDR2;		  break;
+	P_FUTEX_OP(WAIT_BITSET);    *arg_mask |= SCF_UADDR2;			  break;
+	P_FUTEX_OP(WAKE_BITSET);    *arg_mask |= SCF_UADDR2;			  break;
+	P_FUTEX_OP(WAIT_REQUEUE_PI);						  break;
+	default: printed = scnprintf(bf, size, "%#x", cmd);			  break;
+	}
+
+	if (op & FUTEX_PRIVATE_FLAG)
+		printed += scnprintf(bf + printed, size - printed, "|PRIV");
+
+	if (op & FUTEX_CLOCK_REALTIME)
+		printed += scnprintf(bf + printed, size - printed, "|CLKRT");
+
+	return printed;
+}
+
+#define SCA_FUTEX_OP  syscall_arg__scnprintf_futex_op
+
+static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
+					       unsigned long arg,
+					       u8 arg_idx, u8 *arg_mask)
+{
+	int printed = 0, flags = arg;
+
+	if (!(flags & O_CREAT))
+		*arg_mask |= 1 << (arg_idx + 1); /* Mask the mode parm */
+
+	if (flags == 0)
+		return scnprintf(bf, size, "RDONLY");
+#define	P_FLAG(n) \
+	if (flags & O_##n) { \
+		printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+		flags &= ~O_##n; \
+	}
+
+	P_FLAG(APPEND);
+	P_FLAG(ASYNC);
+	P_FLAG(CLOEXEC);
+	P_FLAG(CREAT);
+	P_FLAG(DIRECT);
+	P_FLAG(DIRECTORY);
+	P_FLAG(EXCL);
+	P_FLAG(LARGEFILE);
+	P_FLAG(NOATIME);
+	P_FLAG(NOCTTY);
+#ifdef O_NONBLOCK
+	P_FLAG(NONBLOCK);
+#elif O_NDELAY
+	P_FLAG(NDELAY);
+#endif
+#ifdef O_PATH
+	P_FLAG(PATH);
+#endif
+	P_FLAG(RDWR);
+#ifdef O_DSYNC
+	if ((flags & O_SYNC) == O_SYNC)
+		printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
+	else {
+		P_FLAG(DSYNC);
+	}
+#else
+	P_FLAG(SYNC);
+#endif
+	P_FLAG(TRUNC);
+	P_FLAG(WRONLY);
+#undef P_FLAG
+
+	if (flags)
+		printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+	return printed;
+}
+
+#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
 
 static struct syscall_fmt {
 	const char *name;
 	const char *alias;
+	size_t	   (*arg_scnprintf[6])(char *bf, size_t size, unsigned long arg, u8 arg_idx, u8 *arg_mask);
 	bool	   errmsg;
 	bool	   timeout;
+	bool	   hexret;
 } syscall_fmts[] = {
 	{ .name	    = "access",	    .errmsg = true, },
 	{ .name	    = "arch_prctl", .errmsg = true, .alias = "prctl", },
+	{ .name	    = "brk",	    .hexret = true,
+	  .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
+	{ .name	    = "mmap",	    .hexret = true, },
+	{ .name	    = "connect",    .errmsg = true, },
 	{ .name	    = "fstat",	    .errmsg = true, .alias = "newfstat", },
 	{ .name	    = "fstatat",    .errmsg = true, .alias = "newfstatat", },
-	{ .name	    = "futex",	    .errmsg = true, },
-	{ .name	    = "open",	    .errmsg = true, },
+	{ .name	    = "futex",	    .errmsg = true,
+	  .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
+	{ .name	    = "ioctl",	    .errmsg = true,
+	  .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
+	{ .name	    = "lseek",	    .errmsg = true,
+	  .arg_scnprintf = { [2] = SCA_WHENCE, /* whence */ }, },
+	{ .name	    = "lstat",	    .errmsg = true, .alias = "newlstat", },
+	{ .name     = "madvise",    .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_HEX,	 /* start */
+			     [2] = SCA_MADV_BHV, /* behavior */ }, },
+	{ .name	    = "mmap",	    .hexret = true,
+	  .arg_scnprintf = { [0] = SCA_HEX,	  /* addr */
+			     [2] = SCA_MMAP_PROT, /* prot */
+			     [3] = SCA_MMAP_FLAGS, /* flags */ }, },
+	{ .name	    = "mprotect",   .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_HEX, /* start */
+			     [2] = SCA_MMAP_PROT, /* prot */ }, },
+	{ .name	    = "mremap",	    .hexret = true,
+	  .arg_scnprintf = { [0] = SCA_HEX, /* addr */
+			     [4] = SCA_HEX, /* new_addr */ }, },
+	{ .name	    = "munmap",	    .errmsg = true,
+	  .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
+	{ .name	    = "open",	    .errmsg = true,
+	  .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
+	{ .name	    = "open_by_handle_at", .errmsg = true,
+	  .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
+	{ .name	    = "openat",	    .errmsg = true,
+	  .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
 	{ .name	    = "poll",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "ppoll",	    .errmsg = true, .timeout = true, },
+	{ .name	    = "pread",	    .errmsg = true, .alias = "pread64", },
+	{ .name	    = "pwrite",	    .errmsg = true, .alias = "pwrite64", },
 	{ .name	    = "read",	    .errmsg = true, },
 	{ .name	    = "recvfrom",   .errmsg = true, },
 	{ .name	    = "select",	    .errmsg = true, .timeout = true, },
 	{ .name	    = "socket",	    .errmsg = true, },
 	{ .name	    = "stat",	    .errmsg = true, .alias = "newstat", },
+	{ .name	    = "uname",	    .errmsg = true, .alias = "newuname", },
 };
 
 static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -46,7 +343,10 @@
 struct syscall {
 	struct event_format *tp_format;
 	const char	    *name;
+	bool		    filtered;
 	struct syscall_fmt  *fmt;
+	size_t		    (**arg_scnprintf)(char *bf, size_t size,
+					      unsigned long arg, u8 arg_idx, u8 *args_mask);
 };
 
 static size_t fprintf_duration(unsigned long t, FILE *fp)
@@ -60,7 +360,7 @@
 		printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
 	else
 		printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
-	return printed + fprintf(stdout, "): ");
+	return printed + fprintf(fp, "): ");
 }
 
 struct thread_trace {
@@ -77,7 +377,7 @@
 	return zalloc(sizeof(struct thread_trace));
 }
 
-static struct thread_trace *thread__trace(struct thread *thread)
+static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
 {
 	struct thread_trace *ttrace;
 
@@ -95,12 +395,13 @@
 
 	return ttrace;
 fail:
-	color_fprintf(stdout, PERF_COLOR_RED,
+	color_fprintf(fp, PERF_COLOR_RED,
 		      "WARNING: not enough memory, dropping samples!\n");
 	return NULL;
 }
 
 struct trace {
+	struct perf_tool	tool;
 	int			audit_machine;
 	struct {
 		int		max;
@@ -109,7 +410,12 @@
 	struct perf_record_opts opts;
 	struct machine		host;
 	u64			base_time;
+	FILE			*output;
 	unsigned long		nr_events;
+	struct strlist		*ev_qualifier;
+	bool			not_ev_qualifier;
+	struct intlist		*tid_list;
+	struct intlist		*pid_list;
 	bool			sched;
 	bool			multiple_threads;
 	double			duration_filter;
@@ -142,18 +448,19 @@
 	printed += fprintf_duration(duration, fp);
 
 	if (trace->multiple_threads)
-		printed += fprintf(fp, "%d ", thread->pid);
+		printed += fprintf(fp, "%d ", thread->tid);
 
 	return printed;
 }
 
-static int trace__process_event(struct machine *machine, union perf_event *event)
+static int trace__process_event(struct trace *trace, struct machine *machine,
+				union perf_event *event)
 {
 	int ret = 0;
 
 	switch (event->header.type) {
 	case PERF_RECORD_LOST:
-		color_fprintf(stdout, PERF_COLOR_RED,
+		color_fprintf(trace->output, PERF_COLOR_RED,
 			      "LOST %" PRIu64 " events!\n", event->lost.lost);
 		ret = machine__process_lost_event(machine, event);
 	default:
@@ -164,12 +471,13 @@
 	return ret;
 }
 
-static int trace__tool_process(struct perf_tool *tool __maybe_unused,
+static int trace__tool_process(struct perf_tool *tool,
 			       union perf_event *event,
 			       struct perf_sample *sample __maybe_unused,
 			       struct machine *machine)
 {
-	return trace__process_event(machine, event);
+	struct trace *trace = container_of(tool, struct trace, tool);
+	return trace__process_event(trace, machine, event);
 }
 
 static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
@@ -183,11 +491,11 @@
 	machine__create_kernel_maps(&trace->host);
 
 	if (perf_target__has_task(&trace->opts.target)) {
-		err = perf_event__synthesize_thread_map(NULL, evlist->threads,
+		err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
 							trace__tool_process,
 							&trace->host);
 	} else {
-		err = perf_event__synthesize_threads(NULL, trace__tool_process,
+		err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
 						     &trace->host);
 	}
 
@@ -197,6 +505,26 @@
 	return err;
 }
 
+static int syscall__set_arg_fmts(struct syscall *sc)
+{
+	struct format_field *field;
+	int idx = 0;
+
+	sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
+	if (sc->arg_scnprintf == NULL)
+		return -1;
+
+	for (field = sc->tp_format->format.fields->next; field; field = field->next) {
+		if (sc->fmt && sc->fmt->arg_scnprintf[idx])
+			sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
+		else if (field->flags & FIELD_IS_POINTER)
+			sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
+		++idx;
+	}
+
+	return 0;
+}
+
 static int trace__read_syscall_info(struct trace *trace, int id)
 {
 	char tp_name[128];
@@ -225,6 +553,20 @@
 
 	sc = trace->syscalls.table + id;
 	sc->name = name;
+
+	if (trace->ev_qualifier) {
+		bool in = strlist__find(trace->ev_qualifier, name) != NULL;
+
+		if (!(in ^ trace->not_ev_qualifier)) {
+			sc->filtered = true;
+			/*
+			 * No need to do read tracepoint information since this will be
+			 * filtered out.
+			 */
+			return 0;
+		}
+	}
+
 	sc->fmt  = syscall_fmt__find(sc->name);
 
 	snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
@@ -235,7 +577,10 @@
 		sc->tp_format = event_format__new("syscalls", tp_name);
 	}
 
-	return sc->tp_format != NULL ? 0 : -1;
+	if (sc->tp_format == NULL)
+		return -1;
+
+	return syscall__set_arg_fmts(sc);
 }
 
 static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
@@ -246,11 +591,23 @@
 
 	if (sc->tp_format != NULL) {
 		struct format_field *field;
+		u8 mask = 0, bit = 1;
 
-		for (field = sc->tp_format->format.fields->next; field; field = field->next) {
+		for (field = sc->tp_format->format.fields->next; field;
+		     field = field->next, ++i, bit <<= 1) {
+			if (mask & bit)
+				continue;
+
 			printed += scnprintf(bf + printed, size - printed,
-					     "%s%s: %ld", printed ? ", " : "",
-					     field->name, args[i++]);
+					     "%s%s: ", printed ? ", " : "", field->name);
+
+			if (sc->arg_scnprintf && sc->arg_scnprintf[i]) {
+				printed += sc->arg_scnprintf[i](bf + printed, size - printed,
+								args[i], i, &mask);
+			} else {
+				printed += scnprintf(bf + printed, size - printed,
+						     "%ld", args[i]);
+			}
 		}
 	} else {
 		while (i < 6) {
@@ -274,7 +631,22 @@
 	int id = perf_evsel__intval(evsel, sample, "id");
 
 	if (id < 0) {
-		printf("Invalid syscall %d id, skipping...\n", id);
+
+		/*
+		 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
+		 * before that, leaving at a higher verbosity level till that is
+		 * explained. Reproduced with plain ftrace with:
+		 *
+		 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
+		 * grep "NR -1 " /t/trace_pipe
+		 *
+		 * After generating some load on the machine.
+ 		 */
+		if (verbose > 1) {
+			static u64 n;
+			fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
+				id, perf_evsel__name(evsel), ++n);
+		}
 		return NULL;
 	}
 
@@ -288,10 +660,12 @@
 	return &trace->syscalls.table[id];
 
 out_cant_read:
-	printf("Problems reading syscall %d", id);
-	if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
-		printf("(%s)", trace->syscalls.table[id].name);
-	puts(" information");
+	if (verbose) {
+		fprintf(trace->output, "Problems reading syscall %d", id);
+		if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
+			fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
+		fputs(" information\n", trace->output);
+	}
 	return NULL;
 }
 
@@ -301,16 +675,25 @@
 	char *msg;
 	void *args;
 	size_t printed = 0;
-	struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
+	struct thread *thread;
 	struct syscall *sc = trace__syscall_info(trace, evsel, sample);
-	struct thread_trace *ttrace = thread__trace(thread);
+	struct thread_trace *ttrace;
 
-	if (ttrace == NULL || sc == NULL)
+	if (sc == NULL)
+		return -1;
+
+	if (sc->filtered)
+		return 0;
+
+	thread = machine__findnew_thread(&trace->host, sample->pid,
+					 sample->tid);
+	ttrace = thread__trace(thread, trace->output);
+	if (ttrace == NULL)
 		return -1;
 
 	args = perf_evsel__rawptr(evsel, sample, "args");
 	if (args == NULL) {
-		printf("Problems reading syscall arguments\n");
+		fprintf(trace->output, "Problems reading syscall arguments\n");
 		return -1;
 	}
 
@@ -330,8 +713,8 @@
 
 	if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
 		if (!trace->duration_filter) {
-			trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout);
-			printf("%-70s\n", ttrace->entry_str);
+			trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
+			fprintf(trace->output, "%-70s\n", ttrace->entry_str);
 		}
 	} else
 		ttrace->entry_pending = true;
@@ -344,11 +727,20 @@
 {
 	int ret;
 	u64 duration = 0;
-	struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
-	struct thread_trace *ttrace = thread__trace(thread);
+	struct thread *thread;
 	struct syscall *sc = trace__syscall_info(trace, evsel, sample);
+	struct thread_trace *ttrace;
 
-	if (ttrace == NULL || sc == NULL)
+	if (sc == NULL)
+		return -1;
+
+	if (sc->filtered)
+		return 0;
+
+	thread = machine__findnew_thread(&trace->host, sample->pid,
+					 sample->tid);
+	ttrace = thread__trace(thread, trace->output);
+	if (ttrace == NULL)
 		return -1;
 
 	ret = perf_evsel__intval(evsel, sample, "ret");
@@ -364,28 +756,33 @@
 	} else if (trace->duration_filter)
 		goto out;
 
-	trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout);
+	trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
 
 	if (ttrace->entry_pending) {
-		printf("%-70s", ttrace->entry_str);
+		fprintf(trace->output, "%-70s", ttrace->entry_str);
 	} else {
-		printf(" ... [");
-		color_fprintf(stdout, PERF_COLOR_YELLOW, "continued");
-		printf("]: %s()", sc->name);
+		fprintf(trace->output, " ... [");
+		color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
+		fprintf(trace->output, "]: %s()", sc->name);
 	}
 
-	if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
+	if (sc->fmt == NULL) {
+signed_print:
+		fprintf(trace->output, ") = %d", ret);
+	} else if (ret < 0 && sc->fmt->errmsg) {
 		char bf[256];
 		const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
 			   *e = audit_errno_to_name(-ret);
 
-		printf(") = -1 %s %s", e, emsg);
-	} else if (ret == 0 && sc->fmt && sc->fmt->timeout)
-		printf(") = 0 Timeout");
+		fprintf(trace->output, ") = -1 %s %s", e, emsg);
+	} else if (ret == 0 && sc->fmt->timeout)
+		fprintf(trace->output, ") = 0 Timeout");
+	else if (sc->fmt->hexret)
+		fprintf(trace->output, ") = %#x", ret);
 	else
-		printf(") = %d", ret);
+		goto signed_print;
 
-	putchar('\n');
+	fputc('\n', trace->output);
 out:
 	ttrace->entry_pending = false;
 
@@ -397,8 +794,10 @@
 {
         u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
 	double runtime_ms = (double)runtime / NSEC_PER_MSEC;
-	struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
-	struct thread_trace *ttrace = thread__trace(thread);
+	struct thread *thread = machine__findnew_thread(&trace->host,
+							sample->pid,
+							sample->tid);
+	struct thread_trace *ttrace = thread__trace(thread, trace->output);
 
 	if (ttrace == NULL)
 		goto out_dump;
@@ -408,7 +807,7 @@
 	return 0;
 
 out_dump:
-	printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
+	fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
 	       evsel->name,
 	       perf_evsel__strval(evsel, sample, "comm"),
 	       (pid_t)perf_evsel__intval(evsel, sample, "pid"),
@@ -417,6 +816,72 @@
 	return 0;
 }
 
+static bool skip_sample(struct trace *trace, struct perf_sample *sample)
+{
+	if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
+	    (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
+		return false;
+
+	if (trace->pid_list || trace->tid_list)
+		return true;
+
+	return false;
+}
+
+static int trace__process_sample(struct perf_tool *tool,
+				 union perf_event *event __maybe_unused,
+				 struct perf_sample *sample,
+				 struct perf_evsel *evsel,
+				 struct machine *machine __maybe_unused)
+{
+	struct trace *trace = container_of(tool, struct trace, tool);
+	int err = 0;
+
+	tracepoint_handler handler = evsel->handler.func;
+
+	if (skip_sample(trace, sample))
+		return 0;
+
+	if (trace->base_time == 0)
+		trace->base_time = sample->time;
+
+	if (handler)
+		handler(trace, evsel, sample);
+
+	return err;
+}
+
+static bool
+perf_session__has_tp(struct perf_session *session, const char *name)
+{
+	struct perf_evsel *evsel;
+
+	evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
+
+	return evsel != NULL;
+}
+
+static int parse_target_str(struct trace *trace)
+{
+	if (trace->opts.target.pid) {
+		trace->pid_list = intlist__new(trace->opts.target.pid);
+		if (trace->pid_list == NULL) {
+			pr_err("Error parsing process id string\n");
+			return -EINVAL;
+		}
+	}
+
+	if (trace->opts.target.tid) {
+		trace->tid_list = intlist__new(trace->opts.target.tid);
+		if (trace->tid_list == NULL) {
+			pr_err("Error parsing thread id string\n");
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int trace__run(struct trace *trace, int argc, const char **argv)
 {
 	struct perf_evlist *evlist = perf_evlist__new();
@@ -426,32 +891,32 @@
 	const bool forks = argc > 0;
 
 	if (evlist == NULL) {
-		printf("Not enough memory to run!\n");
+		fprintf(trace->output, "Not enough memory to run!\n");
 		goto out;
 	}
 
 	if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
 	    perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
-		printf("Couldn't read the raw_syscalls tracepoints information!\n");
+		fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
 		goto out_delete_evlist;
 	}
 
 	if (trace->sched &&
 	    perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
 				   trace__sched_stat_runtime)) {
-		printf("Couldn't read the sched_stat_runtime tracepoint information!\n");
+		fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
 		goto out_delete_evlist;
 	}
 
 	err = perf_evlist__create_maps(evlist, &trace->opts.target);
 	if (err < 0) {
-		printf("Problems parsing the target to trace, check your options!\n");
+		fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
 		goto out_delete_evlist;
 	}
 
 	err = trace__symbols_init(trace, evlist);
 	if (err < 0) {
-		printf("Problems initializing symbol libraries!\n");
+		fprintf(trace->output, "Problems initializing symbol libraries!\n");
 		goto out_delete_maps;
 	}
 
@@ -464,20 +929,20 @@
 		err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
 						    argv, false, false);
 		if (err < 0) {
-			printf("Couldn't run the workload!\n");
+			fprintf(trace->output, "Couldn't run the workload!\n");
 			goto out_delete_maps;
 		}
 	}
 
 	err = perf_evlist__open(evlist);
 	if (err < 0) {
-		printf("Couldn't create the events: %s\n", strerror(errno));
+		fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
 		goto out_delete_maps;
 	}
 
 	err = perf_evlist__mmap(evlist, UINT_MAX, false);
 	if (err < 0) {
-		printf("Couldn't mmap the events: %s\n", strerror(errno));
+		fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
 		goto out_close_evlist;
 	}
 
@@ -502,7 +967,7 @@
 
 			err = perf_evlist__parse_sample(evlist, event, &sample);
 			if (err) {
-				printf("Can't parse sample, err = %d, skipping...\n", err);
+				fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
 				continue;
 			}
 
@@ -510,18 +975,18 @@
 				trace->base_time = sample.time;
 
 			if (type != PERF_RECORD_SAMPLE) {
-				trace__process_event(&trace->host, event);
+				trace__process_event(trace, &trace->host, event);
 				continue;
 			}
 
 			evsel = perf_evlist__id2evsel(evlist, sample.id);
 			if (evsel == NULL) {
-				printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
+				fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
 				continue;
 			}
 
 			if (sample.raw_data == NULL) {
-				printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
+				fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
 				       perf_evsel__name(evsel), sample.tid,
 				       sample.cpu, sample.raw_size);
 				continue;
@@ -556,6 +1021,69 @@
 	return err;
 }
 
+static int trace__replay(struct trace *trace)
+{
+	const struct perf_evsel_str_handler handlers[] = {
+		{ "raw_syscalls:sys_enter",  trace__sys_enter, },
+		{ "raw_syscalls:sys_exit",   trace__sys_exit, },
+	};
+
+	struct perf_session *session;
+	int err = -1;
+
+	trace->tool.sample	  = trace__process_sample;
+	trace->tool.mmap	  = perf_event__process_mmap;
+	trace->tool.comm	  = perf_event__process_comm;
+	trace->tool.exit	  = perf_event__process_exit;
+	trace->tool.fork	  = perf_event__process_fork;
+	trace->tool.attr	  = perf_event__process_attr;
+	trace->tool.tracing_data = perf_event__process_tracing_data;
+	trace->tool.build_id	  = perf_event__process_build_id;
+
+	trace->tool.ordered_samples = true;
+	trace->tool.ordering_requires_timestamps = true;
+
+	/* add tid to output */
+	trace->multiple_threads = true;
+
+	if (symbol__init() < 0)
+		return -1;
+
+	session = perf_session__new(input_name, O_RDONLY, 0, false,
+				    &trace->tool);
+	if (session == NULL)
+		return -ENOMEM;
+
+	err = perf_session__set_tracepoints_handlers(session, handlers);
+	if (err)
+		goto out;
+
+	if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
+		pr_err("Data file does not have raw_syscalls:sys_enter events\n");
+		goto out;
+	}
+
+	if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
+		pr_err("Data file does not have raw_syscalls:sys_exit events\n");
+		goto out;
+	}
+
+	err = parse_target_str(trace);
+	if (err != 0)
+		goto out;
+
+	setup_pager();
+
+	err = perf_session__process_events(session, &trace->tool);
+	if (err)
+		pr_err("Failed to process events, error %d", err);
+
+out:
+	perf_session__delete(session);
+
+	return err;
+}
+
 static size_t trace__fprintf_threads_header(FILE *fp)
 {
 	size_t printed;
@@ -593,7 +1121,7 @@
 			color = PERF_COLOR_YELLOW;
 
 		printed += color_fprintf(fp, color, "%20s", thread->comm);
-		printed += fprintf(fp, " - %-5d :%11lu   [", thread->pid, ttrace->nr_events);
+		printed += fprintf(fp, " - %-5d :%11lu   [", thread->tid, ttrace->nr_events);
 		printed += color_fprintf(fp, color, "%5.1f%%", ratio);
 		printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
 	}
@@ -610,6 +1138,23 @@
 	return 0;
 }
 
+static int trace__open_output(struct trace *trace, const char *filename)
+{
+	struct stat st;
+
+	if (!stat(filename, &st) && st.st_size) {
+		char oldname[PATH_MAX];
+
+		scnprintf(oldname, sizeof(oldname), "%s.old", filename);
+		unlink(oldname);
+		rename(filename, oldname);
+	}
+
+	trace->output = fopen(filename, "w");
+
+	return trace->output == NULL ? -errno : 0;
+}
+
 int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	const char * const trace_usage[] = {
@@ -632,26 +1177,34 @@
 			.no_delay      = true,
 			.mmap_pages    = 1024,
 		},
+		.output = stdout,
 	};
+	const char *output_name = NULL;
+	const char *ev_qualifier_str = NULL;
 	const struct option trace_options[] = {
+	OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
+		    "list of events to trace"),
+	OPT_STRING('o', "output", &output_name, "file", "output file name"),
+	OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
 	OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
 		    "trace events on existing process id"),
-	OPT_STRING(0, "tid", &trace.opts.target.tid, "tid",
+	OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
 		    "trace events on existing thread id"),
-	OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide,
+	OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
 		    "system-wide collection from all CPUs"),
-	OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu",
+	OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
 		    "list of cpus to monitor"),
 	OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
 		    "child tasks do not inherit counters"),
-	OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages,
+	OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
 		     "number of mmap data pages"),
-	OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
+	OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
 		   "user to profile"),
 	OPT_CALLBACK(0, "duration", &trace, "float",
 		     "show only events with duration > N.M ms",
 		     trace__set_duration),
 	OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
+	OPT_INCR('v', "verbose", &verbose, "be more verbose"),
 	OPT_END()
 	};
 	int err;
@@ -659,27 +1212,57 @@
 
 	argc = parse_options(argc, argv, trace_options, trace_usage, 0);
 
+	if (output_name != NULL) {
+		err = trace__open_output(&trace, output_name);
+		if (err < 0) {
+			perror("failed to create output file");
+			goto out;
+		}
+	}
+
+	if (ev_qualifier_str != NULL) {
+		const char *s = ev_qualifier_str;
+
+		trace.not_ev_qualifier = *s == '!';
+		if (trace.not_ev_qualifier)
+			++s;
+		trace.ev_qualifier = strlist__new(true, s);
+		if (trace.ev_qualifier == NULL) {
+			fputs("Not enough memory to parse event qualifier",
+			      trace.output);
+			err = -ENOMEM;
+			goto out_close;
+		}
+	}
+
 	err = perf_target__validate(&trace.opts.target);
 	if (err) {
 		perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
-		printf("%s", bf);
-		return err;
+		fprintf(trace.output, "%s", bf);
+		goto out_close;
 	}
 
 	err = perf_target__parse_uid(&trace.opts.target);
 	if (err) {
 		perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
-		printf("%s", bf);
-		return err;
+		fprintf(trace.output, "%s", bf);
+		goto out_close;
 	}
 
 	if (!argc && perf_target__none(&trace.opts.target))
 		trace.opts.target.system_wide = true;
 
-	err = trace__run(&trace, argc, argv);
+	if (input_name)
+		err = trace__replay(&trace);
+	else
+		err = trace__run(&trace, argc, argv);
 
 	if (trace.sched && !err)
-		trace__fprintf_thread_summary(&trace, stdout);
+		trace__fprintf_thread_summary(&trace, trace.output);
 
+out_close:
+	if (output_name != NULL)
+		fclose(trace.output);
+out:
 	return err;
 }
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index b5d9238..214e17e 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -46,6 +46,8 @@
 obj-perf := $(abspath $(obj-perf))/
 endif
 
+LIB_INCLUDE := $(srctree)/tools/lib/
+
 # include ARCH specific config
 -include $(src-perf)/arch/$(ARCH)/Makefile
 
@@ -121,8 +123,7 @@
 
 CFLAGS += -I$(src-perf)/util
 CFLAGS += -I$(src-perf)
-CFLAGS += -I$(TRACE_EVENT_DIR)
-CFLAGS += -I$(srctree)/tools/lib/
+CFLAGS += -I$(LIB_INCLUDE)
 
 CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
 
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 32bd102..cf20187 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -125,6 +125,9 @@
 #ifndef NSEC_PER_SEC
 # define NSEC_PER_SEC			1000000000ULL
 #endif
+#ifndef NSEC_PER_USEC
+# define NSEC_PER_USEC			1000ULL
+#endif
 
 static inline unsigned long long rdclock(void)
 {
diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py
index b11cca5..2225162 100755
--- a/tools/perf/python/twatch.py
+++ b/tools/perf/python/twatch.py
@@ -21,7 +21,7 @@
 	evsel = perf.evsel(task = 1, comm = 1, mmap = 0,
 			   wakeup_events = 1, watermark = 1,
 			   sample_id_all = 1,
-			   sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID)
+			   sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU)
 	evsel.open(cpus = cpus, threads = threads);
 	evlist = perf.evlist(cpus, threads)
 	evlist.add(evsel)
diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling
new file mode 100644
index 0000000..658f5d6
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group-sampling
@@ -0,0 +1,36 @@
+[config]
+command = record
+args    = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
+
+[event-1:base-record]
+fd=1
+group_fd=-1
+sample_type=343
+read_format=12
+inherit=0
+
+[event-2:base-record]
+fd=2
+group_fd=1
+
+# cache-misses
+type=0
+config=3
+
+# default | PERF_SAMPLE_READ
+sample_type=343
+
+# PERF_FORMAT_ID | PERF_FORMAT_GROUP
+read_format=12
+
+mmap=0
+comm=0
+enable_on_exec=0
+disabled=0
+
+# inherit is disabled for group sampling
+inherit=0
+
+# sampling disabled
+sample_freq=0
+sample_period=0
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 35b45f1466..8bbeba3 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -93,6 +93,24 @@
 		.desc = "Test software clock events have valid period values",
 		.func = test__sw_clock_freq,
 	},
+#if defined(__x86_64__) || defined(__i386__)
+	{
+		.desc = "Test converting perf time to TSC",
+		.func = test__perf_time_to_tsc,
+	},
+#endif
+	{
+		.desc = "Test object code reading",
+		.func = test__code_reading,
+	},
+	{
+		.desc = "Test sample parsing",
+		.func = test__sample_parsing,
+	},
+	{
+		.desc = "Test using a dummy software event to keep tracking",
+		.func = test__keep_tracking,
+	},
 	{
 		.func = NULL,
 	},
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
new file mode 100644
index 0000000..6fb781d
--- /dev/null
+++ b/tools/perf/tests/code-reading.c
@@ -0,0 +1,572 @@
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "machine.h"
+#include "event.h"
+#include "thread.h"
+
+#include "tests.h"
+
+#define BUFSZ	1024
+#define READLEN	128
+
+struct state {
+	u64 done[1024];
+	size_t done_cnt;
+};
+
+static unsigned int hex(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	return c - 'A' + 10;
+}
+
+static void read_objdump_line(const char *line, size_t line_len, void **buf,
+			      size_t *len)
+{
+	const char *p;
+	size_t i;
+
+	/* Skip to a colon */
+	p = strchr(line, ':');
+	if (!p)
+		return;
+	i = p + 1 - line;
+
+	/* Read bytes */
+	while (*len) {
+		char c1, c2;
+
+		/* Skip spaces */
+		for (; i < line_len; i++) {
+			if (!isspace(line[i]))
+				break;
+		}
+		/* Get 2 hex digits */
+		if (i >= line_len || !isxdigit(line[i]))
+			break;
+		c1 = line[i++];
+		if (i >= line_len || !isxdigit(line[i]))
+			break;
+		c2 = line[i++];
+		/* Followed by a space */
+		if (i < line_len && line[i] && !isspace(line[i]))
+			break;
+		/* Store byte */
+		*(unsigned char *)*buf = (hex(c1) << 4) | hex(c2);
+		*buf += 1;
+		*len -= 1;
+	}
+}
+
+static int read_objdump_output(FILE *f, void **buf, size_t *len)
+{
+	char *line = NULL;
+	size_t line_len;
+	ssize_t ret;
+	int err = 0;
+
+	while (1) {
+		ret = getline(&line, &line_len, f);
+		if (feof(f))
+			break;
+		if (ret < 0) {
+			pr_debug("getline failed\n");
+			err = -1;
+			break;
+		}
+		read_objdump_line(line, ret, buf, len);
+	}
+
+	free(line);
+
+	return err;
+}
+
+static int read_via_objdump(const char *filename, u64 addr, void *buf,
+			    size_t len)
+{
+	char cmd[PATH_MAX * 2];
+	const char *fmt;
+	FILE *f;
+	int ret;
+
+	fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
+	ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
+		       filename);
+	if (ret <= 0 || (size_t)ret >= sizeof(cmd))
+		return -1;
+
+	pr_debug("Objdump command is: %s\n", cmd);
+
+	/* Ignore objdump errors */
+	strcat(cmd, " 2>/dev/null");
+
+	f = popen(cmd, "r");
+	if (!f) {
+		pr_debug("popen failed\n");
+		return -1;
+	}
+
+	ret = read_objdump_output(f, &buf, &len);
+	if (len) {
+		pr_debug("objdump read too few bytes\n");
+		if (!ret)
+			ret = len;
+	}
+
+	pclose(f);
+
+	return ret;
+}
+
+static int read_object_code(u64 addr, size_t len, u8 cpumode,
+			    struct thread *thread, struct machine *machine,
+			    struct state *state)
+{
+	struct addr_location al;
+	unsigned char buf1[BUFSZ];
+	unsigned char buf2[BUFSZ];
+	size_t ret_len;
+	u64 objdump_addr;
+	int ret;
+
+	pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
+
+	thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr,
+			      &al);
+	if (!al.map || !al.map->dso) {
+		pr_debug("thread__find_addr_map failed\n");
+		return -1;
+	}
+
+	pr_debug("File is: %s\n", al.map->dso->long_name);
+
+	if (al.map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
+	    !dso__is_kcore(al.map->dso)) {
+		pr_debug("Unexpected kernel address - skipping\n");
+		return 0;
+	}
+
+	pr_debug("On file address is: %#"PRIx64"\n", al.addr);
+
+	if (len > BUFSZ)
+		len = BUFSZ;
+
+	/* Do not go off the map */
+	if (addr + len > al.map->end)
+		len = al.map->end - addr;
+
+	/* Read the object code using perf */
+	ret_len = dso__data_read_offset(al.map->dso, machine, al.addr, buf1,
+					len);
+	if (ret_len != len) {
+		pr_debug("dso__data_read_offset failed\n");
+		return -1;
+	}
+
+	/*
+	 * Converting addresses for use by objdump requires more information.
+	 * map__load() does that.  See map__rip_2objdump() for details.
+	 */
+	if (map__load(al.map, NULL))
+		return -1;
+
+	/* objdump struggles with kcore - try each map only once */
+	if (dso__is_kcore(al.map->dso)) {
+		size_t d;
+
+		for (d = 0; d < state->done_cnt; d++) {
+			if (state->done[d] == al.map->start) {
+				pr_debug("kcore map tested already");
+				pr_debug(" - skipping\n");
+				return 0;
+			}
+		}
+		if (state->done_cnt >= ARRAY_SIZE(state->done)) {
+			pr_debug("Too many kcore maps - skipping\n");
+			return 0;
+		}
+		state->done[state->done_cnt++] = al.map->start;
+	}
+
+	/* Read the object code using objdump */
+	objdump_addr = map__rip_2objdump(al.map, al.addr);
+	ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len);
+	if (ret > 0) {
+		/*
+		 * The kernel maps are inaccurate - assume objdump is right in
+		 * that case.
+		 */
+		if (cpumode == PERF_RECORD_MISC_KERNEL ||
+		    cpumode == PERF_RECORD_MISC_GUEST_KERNEL) {
+			len -= ret;
+			if (len) {
+				pr_debug("Reducing len to %zu\n", len);
+			} else if (dso__is_kcore(al.map->dso)) {
+				/*
+				 * objdump cannot handle very large segments
+				 * that may be found in kcore.
+				 */
+				pr_debug("objdump failed for kcore");
+				pr_debug(" - skipping\n");
+				return 0;
+			} else {
+				return -1;
+			}
+		}
+	}
+	if (ret < 0) {
+		pr_debug("read_via_objdump failed\n");
+		return -1;
+	}
+
+	/* The results should be identical */
+	if (memcmp(buf1, buf2, len)) {
+		pr_debug("Bytes read differ from those read by objdump\n");
+		return -1;
+	}
+	pr_debug("Bytes read match those read by objdump\n");
+
+	return 0;
+}
+
+static int process_sample_event(struct machine *machine,
+				struct perf_evlist *evlist,
+				union perf_event *event, struct state *state)
+{
+	struct perf_sample sample;
+	struct thread *thread;
+	u8 cpumode;
+
+	if (perf_evlist__parse_sample(evlist, event, &sample)) {
+		pr_debug("perf_evlist__parse_sample failed\n");
+		return -1;
+	}
+
+	thread = machine__findnew_thread(machine, sample.pid, sample.pid);
+	if (!thread) {
+		pr_debug("machine__findnew_thread failed\n");
+		return -1;
+	}
+
+	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+
+	return read_object_code(sample.ip, READLEN, cpumode, thread, machine,
+				state);
+}
+
+static int process_event(struct machine *machine, struct perf_evlist *evlist,
+			 union perf_event *event, struct state *state)
+{
+	if (event->header.type == PERF_RECORD_SAMPLE)
+		return process_sample_event(machine, evlist, event, state);
+
+	if (event->header.type < PERF_RECORD_MAX)
+		return machine__process_event(machine, event);
+
+	return 0;
+}
+
+static int process_events(struct machine *machine, struct perf_evlist *evlist,
+			  struct state *state)
+{
+	union perf_event *event;
+	int i, ret;
+
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+			ret = process_event(machine, evlist, event, state);
+			if (ret < 0)
+				return ret;
+		}
+	}
+	return 0;
+}
+
+static int comp(const void *a, const void *b)
+{
+	return *(int *)a - *(int *)b;
+}
+
+static void do_sort_something(void)
+{
+	int buf[40960], i;
+
+	for (i = 0; i < (int)ARRAY_SIZE(buf); i++)
+		buf[i] = ARRAY_SIZE(buf) - i - 1;
+
+	qsort(buf, ARRAY_SIZE(buf), sizeof(int), comp);
+
+	for (i = 0; i < (int)ARRAY_SIZE(buf); i++) {
+		if (buf[i] != i) {
+			pr_debug("qsort failed\n");
+			break;
+		}
+	}
+}
+
+static void sort_something(void)
+{
+	int i;
+
+	for (i = 0; i < 10; i++)
+		do_sort_something();
+}
+
+static void syscall_something(void)
+{
+	int pipefd[2];
+	int i;
+
+	for (i = 0; i < 1000; i++) {
+		if (pipe(pipefd) < 0) {
+			pr_debug("pipe failed\n");
+			break;
+		}
+		close(pipefd[1]);
+		close(pipefd[0]);
+	}
+}
+
+static void fs_something(void)
+{
+	const char *test_file_name = "temp-perf-code-reading-test-file--";
+	FILE *f;
+	int i;
+
+	for (i = 0; i < 1000; i++) {
+		f = fopen(test_file_name, "w+");
+		if (f) {
+			fclose(f);
+			unlink(test_file_name);
+		}
+	}
+}
+
+static void do_something(void)
+{
+	fs_something();
+
+	sort_something();
+
+	syscall_something();
+}
+
+enum {
+	TEST_CODE_READING_OK,
+	TEST_CODE_READING_NO_VMLINUX,
+	TEST_CODE_READING_NO_KCORE,
+	TEST_CODE_READING_NO_ACCESS,
+	TEST_CODE_READING_NO_KERNEL_OBJ,
+};
+
+static int do_test_code_reading(bool try_kcore)
+{
+	struct machines machines;
+	struct machine *machine;
+	struct thread *thread;
+	struct perf_record_opts opts = {
+		.mmap_pages	     = UINT_MAX,
+		.user_freq	     = UINT_MAX,
+		.user_interval	     = ULLONG_MAX,
+		.freq		     = 4000,
+		.target		     = {
+			.uses_mmap   = true,
+		},
+	};
+	struct state state = {
+		.done_cnt = 0,
+	};
+	struct thread_map *threads = NULL;
+	struct cpu_map *cpus = NULL;
+	struct perf_evlist *evlist = NULL;
+	struct perf_evsel *evsel = NULL;
+	int err = -1, ret;
+	pid_t pid;
+	struct map *map;
+	bool have_vmlinux, have_kcore, excl_kernel = false;
+
+	pid = getpid();
+
+	machines__init(&machines);
+	machine = &machines.host;
+
+	ret = machine__create_kernel_maps(machine);
+	if (ret < 0) {
+		pr_debug("machine__create_kernel_maps failed\n");
+		goto out_err;
+	}
+
+	/* Force the use of kallsyms instead of vmlinux to try kcore */
+	if (try_kcore)
+		symbol_conf.kallsyms_name = "/proc/kallsyms";
+
+	/* Load kernel map */
+	map = machine->vmlinux_maps[MAP__FUNCTION];
+	ret = map__load(map, NULL);
+	if (ret < 0) {
+		pr_debug("map__load failed\n");
+		goto out_err;
+	}
+	have_vmlinux = dso__is_vmlinux(map->dso);
+	have_kcore = dso__is_kcore(map->dso);
+
+	/* 2nd time through we just try kcore */
+	if (try_kcore && !have_kcore)
+		return TEST_CODE_READING_NO_KCORE;
+
+	/* No point getting kernel events if there is no kernel object */
+	if (!have_vmlinux && !have_kcore)
+		excl_kernel = true;
+
+	threads = thread_map__new_by_tid(pid);
+	if (!threads) {
+		pr_debug("thread_map__new_by_tid failed\n");
+		goto out_err;
+	}
+
+	ret = perf_event__synthesize_thread_map(NULL, threads,
+						perf_event__process, machine);
+	if (ret < 0) {
+		pr_debug("perf_event__synthesize_thread_map failed\n");
+		goto out_err;
+	}
+
+	thread = machine__findnew_thread(machine, pid, pid);
+	if (!thread) {
+		pr_debug("machine__findnew_thread failed\n");
+		goto out_err;
+	}
+
+	cpus = cpu_map__new(NULL);
+	if (!cpus) {
+		pr_debug("cpu_map__new failed\n");
+		goto out_err;
+	}
+
+	while (1) {
+		const char *str;
+
+		evlist = perf_evlist__new();
+		if (!evlist) {
+			pr_debug("perf_evlist__new failed\n");
+			goto out_err;
+		}
+
+		perf_evlist__set_maps(evlist, cpus, threads);
+
+		if (excl_kernel)
+			str = "cycles:u";
+		else
+			str = "cycles";
+		pr_debug("Parsing event '%s'\n", str);
+		ret = parse_events(evlist, str);
+		if (ret < 0) {
+			pr_debug("parse_events failed\n");
+			goto out_err;
+		}
+
+		perf_evlist__config(evlist, &opts);
+
+		evsel = perf_evlist__first(evlist);
+
+		evsel->attr.comm = 1;
+		evsel->attr.disabled = 1;
+		evsel->attr.enable_on_exec = 0;
+
+		ret = perf_evlist__open(evlist);
+		if (ret < 0) {
+			if (!excl_kernel) {
+				excl_kernel = true;
+				perf_evlist__delete(evlist);
+				evlist = NULL;
+				continue;
+			}
+			pr_debug("perf_evlist__open failed\n");
+			goto out_err;
+		}
+		break;
+	}
+
+	ret = perf_evlist__mmap(evlist, UINT_MAX, false);
+	if (ret < 0) {
+		pr_debug("perf_evlist__mmap failed\n");
+		goto out_err;
+	}
+
+	perf_evlist__enable(evlist);
+
+	do_something();
+
+	perf_evlist__disable(evlist);
+
+	ret = process_events(machine, evlist, &state);
+	if (ret < 0)
+		goto out_err;
+
+	if (!have_vmlinux && !have_kcore && !try_kcore)
+		err = TEST_CODE_READING_NO_KERNEL_OBJ;
+	else if (!have_vmlinux && !try_kcore)
+		err = TEST_CODE_READING_NO_VMLINUX;
+	else if (excl_kernel)
+		err = TEST_CODE_READING_NO_ACCESS;
+	else
+		err = TEST_CODE_READING_OK;
+out_err:
+	if (evlist) {
+		perf_evlist__munmap(evlist);
+		perf_evlist__close(evlist);
+		perf_evlist__delete(evlist);
+	}
+	if (cpus)
+		cpu_map__delete(cpus);
+	if (threads)
+		thread_map__delete(threads);
+	machines__destroy_kernel_maps(&machines);
+	machine__delete_threads(machine);
+	machines__exit(&machines);
+
+	return err;
+}
+
+int test__code_reading(void)
+{
+	int ret;
+
+	ret = do_test_code_reading(false);
+	if (!ret)
+		ret = do_test_code_reading(true);
+
+	switch (ret) {
+	case TEST_CODE_READING_OK:
+		return 0;
+	case TEST_CODE_READING_NO_VMLINUX:
+		fprintf(stderr, " (no vmlinux)");
+		return 0;
+	case TEST_CODE_READING_NO_KCORE:
+		fprintf(stderr, " (no kcore)");
+		return 0;
+	case TEST_CODE_READING_NO_ACCESS:
+		fprintf(stderr, " (no access)");
+		return 0;
+	case TEST_CODE_READING_NO_KERNEL_OBJ:
+		fprintf(stderr, " (no kernel obj)");
+		return 0;
+	default:
+		return -1;
+	};
+}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 5eaffa2..dffe055 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -10,14 +10,6 @@
 #include "symbol.h"
 #include "tests.h"
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-	if (!(cond)) { \
-		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-		return -1; \
-	} \
-} while (0)
-
 static char *test_file(int size)
 {
 	static char buf_templ[] = "/tmp/test-XXXXXX";
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index a5d2fcc..9b98c15 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -1,6 +1,6 @@
+#include <traceevent/event-parse.h>
 #include "evsel.h"
 #include "tests.h"
-#include "event-parse.h"
 
 static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
 				  int size, bool should_be_signed)
@@ -49,7 +49,7 @@
 	if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
 		ret = -1;
 
-	if (perf_evsel__test_field(evsel, "prev_state", 8, true))
+	if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
 		ret = -1;
 
 	if (perf_evsel__test_field(evsel, "next_comm", 16, true))
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 89085a9..4228ffc 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -88,7 +88,8 @@
 	for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
 		struct thread *thread;
 
-		thread = machine__findnew_thread(machine, fake_threads[i].pid);
+		thread = machine__findnew_thread(machine, fake_threads[i].pid,
+						 fake_threads[i].pid);
 		if (thread == NULL)
 			goto out;
 
@@ -210,17 +211,15 @@
 	list_for_each_entry(evsel, &evlist->entries, node) {
 		for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
 			const union perf_event event = {
-				.ip = {
-					.header = {
-						.misc = PERF_RECORD_MISC_USER,
-					},
-					.pid = fake_common_samples[k].pid,
-					.ip  = fake_common_samples[k].ip,
+				.header = {
+					.misc = PERF_RECORD_MISC_USER,
 				},
 			};
 
+			sample.pid = fake_common_samples[k].pid;
+			sample.ip = fake_common_samples[k].ip;
 			if (perf_event__preprocess_sample(&event, machine, &al,
-							  &sample, 0) < 0)
+							  &sample) < 0)
 				goto out;
 
 			he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
@@ -234,17 +233,15 @@
 
 		for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
 			const union perf_event event = {
-				.ip = {
-					.header = {
-						.misc = PERF_RECORD_MISC_USER,
-					},
-					.pid = fake_samples[i][k].pid,
-					.ip  = fake_samples[i][k].ip,
+				.header = {
+					.misc = PERF_RECORD_MISC_USER,
 				},
 			};
 
+			sample.pid = fake_samples[i][k].pid;
+			sample.ip = fake_samples[i][k].ip;
 			if (perf_event__preprocess_sample(&event, machine, &al,
-							  &sample, 0) < 0)
+							  &sample) < 0)
 				goto out;
 
 			he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
new file mode 100644
index 0000000..d444ea2
--- /dev/null
+++ b/tools/perf/tests/keep-tracking.c
@@ -0,0 +1,154 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/prctl.h>
+
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "tests.h"
+
+#define CHECK__(x) {				\
+	while ((x) < 0) {			\
+		pr_debug(#x " failed!\n");	\
+		goto out_err;			\
+	}					\
+}
+
+#define CHECK_NOT_NULL__(x) {			\
+	while ((x) == NULL) {			\
+		pr_debug(#x " failed!\n");	\
+		goto out_err;			\
+	}					\
+}
+
+static int find_comm(struct perf_evlist *evlist, const char *comm)
+{
+	union perf_event *event;
+	int i, found;
+
+	found = 0;
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+			if (event->header.type == PERF_RECORD_COMM &&
+			    (pid_t)event->comm.pid == getpid() &&
+			    (pid_t)event->comm.tid == getpid() &&
+			    strcmp(event->comm.comm, comm) == 0)
+				found += 1;
+		}
+	}
+	return found;
+}
+
+/**
+ * test__keep_tracking - test using a dummy software event to keep tracking.
+ *
+ * This function implements a test that checks that tracking events continue
+ * when an event is disabled but a dummy software event is not disabled.  If the
+ * test passes %0 is returned, otherwise %-1 is returned.
+ */
+int test__keep_tracking(void)
+{
+	struct perf_record_opts opts = {
+		.mmap_pages	     = UINT_MAX,
+		.user_freq	     = UINT_MAX,
+		.user_interval	     = ULLONG_MAX,
+		.freq		     = 4000,
+		.target		     = {
+			.uses_mmap   = true,
+		},
+	};
+	struct thread_map *threads = NULL;
+	struct cpu_map *cpus = NULL;
+	struct perf_evlist *evlist = NULL;
+	struct perf_evsel *evsel = NULL;
+	int found, err = -1;
+	const char *comm;
+
+	threads = thread_map__new(-1, getpid(), UINT_MAX);
+	CHECK_NOT_NULL__(threads);
+
+	cpus = cpu_map__new(NULL);
+	CHECK_NOT_NULL__(cpus);
+
+	evlist = perf_evlist__new();
+	CHECK_NOT_NULL__(evlist);
+
+	perf_evlist__set_maps(evlist, cpus, threads);
+
+	CHECK__(parse_events(evlist, "dummy:u"));
+	CHECK__(parse_events(evlist, "cycles:u"));
+
+	perf_evlist__config(evlist, &opts);
+
+	evsel = perf_evlist__first(evlist);
+
+	evsel->attr.comm = 1;
+	evsel->attr.disabled = 1;
+	evsel->attr.enable_on_exec = 0;
+
+	if (perf_evlist__open(evlist) < 0) {
+		fprintf(stderr, " (not supported)");
+		err = 0;
+		goto out_err;
+	}
+
+	CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
+
+	/*
+	 * First, test that a 'comm' event can be found when the event is
+	 * enabled.
+	 */
+
+	perf_evlist__enable(evlist);
+
+	comm = "Test COMM 1";
+	CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
+
+	perf_evlist__disable(evlist);
+
+	found = find_comm(evlist, comm);
+	if (found != 1) {
+		pr_debug("First time, failed to find tracking event.\n");
+		goto out_err;
+	}
+
+	/*
+	 * Secondly, test that a 'comm' event can be found when the event is
+	 * disabled with the dummy event still enabled.
+	 */
+
+	perf_evlist__enable(evlist);
+
+	evsel = perf_evlist__last(evlist);
+
+	CHECK__(perf_evlist__disable_event(evlist, evsel));
+
+	comm = "Test COMM 2";
+	CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
+
+	perf_evlist__disable(evlist);
+
+	found = find_comm(evlist, comm);
+	if (found != 1) {
+		pr_debug("Seconf time, failed to find tracking event.\n");
+		goto out_err;
+	}
+
+	err = 0;
+
+out_err:
+	if (evlist) {
+		perf_evlist__disable(evlist);
+		perf_evlist__munmap(evlist);
+		perf_evlist__close(evlist);
+		perf_evlist__delete(evlist);
+	}
+	if (cpus)
+		cpu_map__delete(cpus);
+	if (threads)
+		thread_map__delete(threads);
+
+	return err;
+}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index c441a28..2ca0abf 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,6 +1,8 @@
 PERF := .
 MK   := Makefile
 
+has = $(shell which $1 2>/dev/null)
+
 # standard single make variable specified
 make_clean_all      := clean all
 make_python_perf_so := python/perf.so
@@ -25,6 +27,13 @@
 make_doc            := doc
 make_perf_o         := perf.o
 make_util_map_o     := util/map.o
+make_install        := install
+make_install_bin    := install-bin
+make_install_doc    := install-doc
+make_install_man    := install-man
+make_install_html   := install-html
+make_install_info   := install-info
+make_install_pdf    := install-pdf
 
 # all the NO_* variable combined
 make_minimal        := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
@@ -50,14 +59,27 @@
 run += make_no_libnuma
 run += make_no_libaudit
 run += make_no_libbionic
-run += make_tags
-run += make_cscope
 run += make_help
 run += make_doc
 run += make_perf_o
 run += make_util_map_o
+run += make_install
+run += make_install_bin
+# FIXME 'install-*' commented out till they're fixed
+# run += make_install_doc
+# run += make_install_man
+# run += make_install_html
+# run += make_install_info
+# run += make_install_pdf
 run += make_minimal
 
+ifneq ($(call has,ctags),)
+run += make_tags
+endif
+ifneq ($(call has,cscope),)
+run += make_cscope
+endif
+
 # $(run_O) contains same portion of $(run) tests with '_O' attached
 # to distinguish O=... tests
 run_O := $(addsuffix _O,$(run))
@@ -84,6 +106,31 @@
 test_make_perf_o     := test -f $(PERF)/perf.o
 test_make_util_map_o := test -f $(PERF)/util/map.o
 
+test_make_install       := test -x $$TMP_DEST/bin/perf
+test_make_install_O     := $(test_make_install)
+test_make_install_bin   := $(test_make_install)
+test_make_install_bin_O := $(test_make_install)
+
+# FIXME nothing gets installed
+test_make_install_man    := test -f $$TMP_DEST/share/man/man1/perf.1
+test_make_install_man_O  := $(test_make_install_man)
+
+# FIXME nothing gets installed
+test_make_install_doc    := $(test_ok)
+test_make_install_doc_O  := $(test_ok)
+
+# FIXME nothing gets installed
+test_make_install_html   := $(test_ok)
+test_make_install_html_O := $(test_ok)
+
+# FIXME nothing gets installed
+test_make_install_info   := $(test_ok)
+test_make_install_info_O := $(test_ok)
+
+# FIXME nothing gets installed
+test_make_install_pdf    := $(test_ok)
+test_make_install_pdf_O  := $(test_ok)
+
 # Kbuild tests only
 #test_make_python_perf_so_O := test -f $$TMP/tools/perf/python/perf.so
 #test_make_perf_o_O         := test -f $$TMP/tools/perf/perf.o
@@ -95,7 +142,7 @@
 test_default = test -x $(PERF)/perf
 test = $(if $(test_$1),$(test_$1),$(test_default))
 
-test_default_O = test -x $$TMP/perf
+test_default_O = test -x $$TMP_O/perf
 test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
 
 all:
@@ -111,23 +158,27 @@
 
 $(run):
 	$(call clean)
-	@cmd="cd $(PERF) && make -f $(MK) $($@)"; \
+	@TMP_DEST=$$(mktemp -d); \
+	cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \
 	echo "- $@: $$cmd" && echo $$cmd > $@ && \
 	( eval $$cmd ) >> $@ 2>&1; \
 	echo "  test: $(call test,$@)"; \
 	$(call test,$@) && \
-	rm -f $@
+	rm -f $@ \
+	rm -rf $$TMP_DEST
 
 $(run_O):
 	$(call clean)
-	@TMP=$$(mktemp -d); \
-	cmd="cd $(PERF) && make -f $(MK) $($(patsubst %_O,%,$@)) O=$$TMP"; \
+	@TMP_O=$$(mktemp -d); \
+	TMP_DEST=$$(mktemp -d); \
+	cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
 	echo "- $@: $$cmd" && echo $$cmd > $@ && \
 	( eval $$cmd ) >> $@ 2>&1 && \
 	echo "  test: $(call test_O,$@)"; \
 	$(call test_O,$@) && \
 	rm -f $@ && \
-	rm -rf $$TMP
+	rm -rf $$TMP_O \
+	rm -rf $$TMP_DEST
 
 all: $(run) $(run_O)
 	@echo OK
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 5b1b5ab..c4185b9 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -72,7 +72,7 @@
 		}
 
 		evsels[i]->attr.wakeup_events = 1;
-		perf_evsel__set_sample_id(evsels[i]);
+		perf_evsel__set_sample_id(evsels[i], false);
 
 		perf_evlist__add(evlist, evsels[i]);
 
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 0275bab..48114d1 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -7,14 +7,6 @@
 #include "tests.h"
 #include <linux/hw_breakpoint.h>
 
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
-	if (!(cond)) { \
-		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
-		return -1; \
-	} \
-} while (0)
-
 #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
 			     PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
 
@@ -460,6 +452,7 @@
 			evsel->attr.exclude_kernel);
 	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
 
 	return 0;
 }
@@ -528,6 +521,7 @@
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* cycles:upp */
 	evsel = perf_evsel__next(evsel);
@@ -543,6 +537,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
 	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	return 0;
 }
@@ -568,6 +563,7 @@
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* cache-references + :u modifier */
 	evsel = perf_evsel__next(evsel);
@@ -582,6 +578,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* cycles:k */
 	evsel = perf_evsel__next(evsel);
@@ -595,6 +592,7 @@
 	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	return 0;
 }
@@ -623,6 +621,7 @@
 		!strcmp(leader->group_name, "group1"));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* group1 cycles:kppp */
 	evsel = perf_evsel__next(evsel);
@@ -639,6 +638,7 @@
 	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
 	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* group2 cycles + G modifier */
 	evsel = leader = perf_evsel__next(evsel);
@@ -656,6 +656,7 @@
 		!strcmp(leader->group_name, "group2"));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* group2 1:3 + G modifier */
 	evsel = perf_evsel__next(evsel);
@@ -669,6 +670,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* instructions:u */
 	evsel = perf_evsel__next(evsel);
@@ -682,6 +684,7 @@
 	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	return 0;
 }
@@ -709,6 +712,7 @@
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* instructions:kp + p */
 	evsel = perf_evsel__next(evsel);
@@ -724,6 +728,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
 	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	return 0;
 }
@@ -750,6 +755,7 @@
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* instructions + G */
 	evsel = perf_evsel__next(evsel);
@@ -764,6 +770,7 @@
 	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
 	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* cycles:G */
 	evsel = leader = perf_evsel__next(evsel);
@@ -780,6 +787,7 @@
 	TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 	TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
 	TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+	TEST_ASSERT_VAL("wrong sample_read", !evsel->sample_read);
 
 	/* instructions:G */
 	evsel = perf_evsel__next(evsel);
@@ -971,6 +979,142 @@
 	return 0;
 }
 
+static int test__leader_sample1(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* cycles - sampling group leader */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
+
+	/* cache-misses - not sampling */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
+
+	/* branch-misses - not sampling */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
+
+	return 0;
+}
+
+static int test__leader_sample2(struct perf_evlist *evlist __maybe_unused)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+
+	/* instructions - sampling group leader */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
+
+	/* branch-misses - not sampling */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+	TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong sample_read", evsel->sample_read);
+
+	return 0;
+}
+
+static int test__checkevent_pinned_modifier(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel = perf_evlist__first(evlist);
+
+	TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+	TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+	TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+	TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+	TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned);
+
+	return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__pinned_group(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel, *leader;
+
+	TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+	/* cycles - group leader */
+	evsel = leader = perf_evlist__first(evlist);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+	TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+	TEST_ASSERT_VAL("wrong pinned", evsel->attr.pinned);
+
+	/* cache-misses - can not be pinned, but will go on with the leader */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
+
+	/* branch-misses - ditto */
+	evsel = perf_evsel__next(evsel);
+	TEST_ASSERT_VAL("wrong config",
+			PERF_COUNT_HW_BRANCH_MISSES == evsel->attr.config);
+	TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
+
+	return 0;
+}
+
 static int count_tracepoints(void)
 {
 	char events_path[PATH_MAX];
@@ -1187,6 +1331,22 @@
 		.name  = "{cycles:G,cache-misses:H}:uG",
 		.check = test__group_gh4,
 	},
+	[38] = {
+		.name  = "{cycles,cache-misses,branch-misses}:S",
+		.check = test__leader_sample1,
+	},
+	[39] = {
+		.name  = "{instructions,branch-misses}:Su",
+		.check = test__leader_sample2,
+	},
+	[40] = {
+		.name  = "instructions:uDp",
+		.check = test__checkevent_pinned_modifier,
+	},
+	[41] = {
+		.name  = "{cycles,cache-misses,branch-misses}:D",
+		.check = test__pinned_group,
+	},
 };
 
 static struct evlist_test test__events_pmu[] = {
@@ -1254,24 +1414,20 @@
 
 static int test_term(struct terms_test *t)
 {
-	struct list_head *terms;
+	struct list_head terms;
 	int ret;
 
-	terms = malloc(sizeof(*terms));
-	if (!terms)
-		return -ENOMEM;
+	INIT_LIST_HEAD(&terms);
 
-	INIT_LIST_HEAD(terms);
-
-	ret = parse_events_terms(terms, t->str);
+	ret = parse_events_terms(&terms, t->str);
 	if (ret) {
 		pr_debug("failed to parse terms '%s', err %d\n",
 			 t->str , ret);
 		return ret;
 	}
 
-	ret = t->check(terms);
-	parse_events__free_terms(terms);
+	ret = t->check(&terms);
+	parse_events__free_terms(&terms);
 
 	return ret;
 }
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
new file mode 100644
index 0000000..0ab61b1
--- /dev/null
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/prctl.h>
+
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "tests.h"
+
+#include "../arch/x86/util/tsc.h"
+
+#define CHECK__(x) {				\
+	while ((x) < 0) {			\
+		pr_debug(#x " failed!\n");	\
+		goto out_err;			\
+	}					\
+}
+
+#define CHECK_NOT_NULL__(x) {			\
+	while ((x) == NULL) {			\
+		pr_debug(#x " failed!\n");	\
+		goto out_err;			\
+	}					\
+}
+
+static u64 rdtsc(void)
+{
+	unsigned int low, high;
+
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+	return low | ((u64)high) << 32;
+}
+
+/**
+ * test__perf_time_to_tsc - test converting perf time to TSC.
+ *
+ * This function implements a test that checks that the conversion of perf time
+ * to and from TSC is consistent with the order of events.  If the test passes
+ * %0 is returned, otherwise %-1 is returned.  If TSC conversion is not
+ * supported then then the test passes but " (not supported)" is printed.
+ */
+int test__perf_time_to_tsc(void)
+{
+	struct perf_record_opts opts = {
+		.mmap_pages	     = UINT_MAX,
+		.user_freq	     = UINT_MAX,
+		.user_interval	     = ULLONG_MAX,
+		.freq		     = 4000,
+		.target		     = {
+			.uses_mmap   = true,
+		},
+		.sample_time	     = true,
+	};
+	struct thread_map *threads = NULL;
+	struct cpu_map *cpus = NULL;
+	struct perf_evlist *evlist = NULL;
+	struct perf_evsel *evsel = NULL;
+	int err = -1, ret, i;
+	const char *comm1, *comm2;
+	struct perf_tsc_conversion tc;
+	struct perf_event_mmap_page *pc;
+	union perf_event *event;
+	u64 test_tsc, comm1_tsc, comm2_tsc;
+	u64 test_time, comm1_time = 0, comm2_time = 0;
+
+	threads = thread_map__new(-1, getpid(), UINT_MAX);
+	CHECK_NOT_NULL__(threads);
+
+	cpus = cpu_map__new(NULL);
+	CHECK_NOT_NULL__(cpus);
+
+	evlist = perf_evlist__new();
+	CHECK_NOT_NULL__(evlist);
+
+	perf_evlist__set_maps(evlist, cpus, threads);
+
+	CHECK__(parse_events(evlist, "cycles:u"));
+
+	perf_evlist__config(evlist, &opts);
+
+	evsel = perf_evlist__first(evlist);
+
+	evsel->attr.comm = 1;
+	evsel->attr.disabled = 1;
+	evsel->attr.enable_on_exec = 0;
+
+	CHECK__(perf_evlist__open(evlist));
+
+	CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false));
+
+	pc = evlist->mmap[0].base;
+	ret = perf_read_tsc_conversion(pc, &tc);
+	if (ret) {
+		if (ret == -EOPNOTSUPP) {
+			fprintf(stderr, " (not supported)");
+			return 0;
+		}
+		goto out_err;
+	}
+
+	perf_evlist__enable(evlist);
+
+	comm1 = "Test COMM 1";
+	CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0));
+
+	test_tsc = rdtsc();
+
+	comm2 = "Test COMM 2";
+	CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0));
+
+	perf_evlist__disable(evlist);
+
+	for (i = 0; i < evlist->nr_mmaps; i++) {
+		while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+			struct perf_sample sample;
+
+			if (event->header.type != PERF_RECORD_COMM ||
+			    (pid_t)event->comm.pid != getpid() ||
+			    (pid_t)event->comm.tid != getpid())
+				continue;
+
+			if (strcmp(event->comm.comm, comm1) == 0) {
+				CHECK__(perf_evsel__parse_sample(evsel, event,
+								 &sample));
+				comm1_time = sample.time;
+			}
+			if (strcmp(event->comm.comm, comm2) == 0) {
+				CHECK__(perf_evsel__parse_sample(evsel, event,
+								 &sample));
+				comm2_time = sample.time;
+			}
+		}
+	}
+
+	if (!comm1_time || !comm2_time)
+		goto out_err;
+
+	test_time = tsc_to_perf_time(test_tsc, &tc);
+	comm1_tsc = perf_time_to_tsc(comm1_time, &tc);
+	comm2_tsc = perf_time_to_tsc(comm2_time, &tc);
+
+	pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n",
+		 comm1_time, comm1_tsc);
+	pr_debug("rdtsc          time %"PRIu64" tsc %"PRIu64"\n",
+		 test_time, test_tsc);
+	pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n",
+		 comm2_time, comm2_tsc);
+
+	if (test_time <= comm1_time ||
+	    test_time >= comm2_time)
+		goto out_err;
+
+	if (test_tsc <= comm1_tsc ||
+	    test_tsc >= comm2_tsc)
+		goto out_err;
+
+	err = 0;
+
+out_err:
+	if (evlist) {
+		perf_evlist__disable(evlist);
+		perf_evlist__munmap(evlist);
+		perf_evlist__close(evlist);
+		perf_evlist__delete(evlist);
+	}
+	if (cpus)
+		cpu_map__delete(cpus);
+	if (threads)
+		thread_map__delete(threads);
+
+	return err;
+}
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
new file mode 100644
index 0000000..77f598d
--- /dev/null
+++ b/tools/perf/tests/sample-parsing.c
@@ -0,0 +1,316 @@
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "util.h"
+#include "event.h"
+#include "evsel.h"
+
+#include "tests.h"
+
+#define COMP(m) do {					\
+	if (s1->m != s2->m) {				\
+		pr_debug("Samples differ at '"#m"'\n");	\
+		return false;				\
+	}						\
+} while (0)
+
+#define MCOMP(m) do {					\
+	if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) {	\
+		pr_debug("Samples differ at '"#m"'\n");	\
+		return false;				\
+	}						\
+} while (0)
+
+static bool samples_same(const struct perf_sample *s1,
+			 const struct perf_sample *s2, u64 type, u64 regs_user,
+			 u64 read_format)
+{
+	size_t i;
+
+	if (type & PERF_SAMPLE_IDENTIFIER)
+		COMP(id);
+
+	if (type & PERF_SAMPLE_IP)
+		COMP(ip);
+
+	if (type & PERF_SAMPLE_TID) {
+		COMP(pid);
+		COMP(tid);
+	}
+
+	if (type & PERF_SAMPLE_TIME)
+		COMP(time);
+
+	if (type & PERF_SAMPLE_ADDR)
+		COMP(addr);
+
+	if (type & PERF_SAMPLE_ID)
+		COMP(id);
+
+	if (type & PERF_SAMPLE_STREAM_ID)
+		COMP(stream_id);
+
+	if (type & PERF_SAMPLE_CPU)
+		COMP(cpu);
+
+	if (type & PERF_SAMPLE_PERIOD)
+		COMP(period);
+
+	if (type & PERF_SAMPLE_READ) {
+		if (read_format & PERF_FORMAT_GROUP)
+			COMP(read.group.nr);
+		else
+			COMP(read.one.value);
+		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+			COMP(read.time_enabled);
+		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+			COMP(read.time_running);
+		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
+		if (read_format & PERF_FORMAT_GROUP) {
+			for (i = 0; i < s1->read.group.nr; i++)
+				MCOMP(read.group.values[i]);
+		} else {
+			COMP(read.one.id);
+		}
+	}
+
+	if (type & PERF_SAMPLE_CALLCHAIN) {
+		COMP(callchain->nr);
+		for (i = 0; i < s1->callchain->nr; i++)
+			COMP(callchain->ips[i]);
+	}
+
+	if (type & PERF_SAMPLE_RAW) {
+		COMP(raw_size);
+		if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
+			pr_debug("Samples differ at 'raw_data'\n");
+			return false;
+		}
+	}
+
+	if (type & PERF_SAMPLE_BRANCH_STACK) {
+		COMP(branch_stack->nr);
+		for (i = 0; i < s1->branch_stack->nr; i++)
+			MCOMP(branch_stack->entries[i]);
+	}
+
+	if (type & PERF_SAMPLE_REGS_USER) {
+		size_t sz = hweight_long(regs_user) * sizeof(u64);
+
+		COMP(user_regs.abi);
+		if (s1->user_regs.abi &&
+		    (!s1->user_regs.regs || !s2->user_regs.regs ||
+		     memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
+			pr_debug("Samples differ at 'user_regs'\n");
+			return false;
+		}
+	}
+
+	if (type & PERF_SAMPLE_STACK_USER) {
+		COMP(user_stack.size);
+		if (memcmp(s1->user_stack.data, s1->user_stack.data,
+			   s1->user_stack.size)) {
+			pr_debug("Samples differ at 'user_stack'\n");
+			return false;
+		}
+	}
+
+	if (type & PERF_SAMPLE_WEIGHT)
+		COMP(weight);
+
+	if (type & PERF_SAMPLE_DATA_SRC)
+		COMP(data_src);
+
+	return true;
+}
+
+static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
+{
+	struct perf_evsel evsel = {
+		.needs_swap = false,
+		.attr = {
+			.sample_type = sample_type,
+			.sample_regs_user = sample_regs_user,
+			.read_format = read_format,
+		},
+	};
+	union perf_event *event;
+	union {
+		struct ip_callchain callchain;
+		u64 data[64];
+	} callchain = {
+		/* 3 ips */
+		.data = {3, 201, 202, 203},
+	};
+	union {
+		struct branch_stack branch_stack;
+		u64 data[64];
+	} branch_stack = {
+		/* 1 branch_entry */
+		.data = {1, 211, 212, 213},
+	};
+	u64 user_regs[64];
+	const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
+	const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
+	struct perf_sample sample = {
+		.ip		= 101,
+		.pid		= 102,
+		.tid		= 103,
+		.time		= 104,
+		.addr		= 105,
+		.id		= 106,
+		.stream_id	= 107,
+		.period		= 108,
+		.weight		= 109,
+		.cpu		= 110,
+		.raw_size	= sizeof(raw_data),
+		.data_src	= 111,
+		.raw_data	= (void *)raw_data,
+		.callchain	= &callchain.callchain,
+		.branch_stack	= &branch_stack.branch_stack,
+		.user_regs	= {
+			.abi	= PERF_SAMPLE_REGS_ABI_64,
+			.regs	= user_regs,
+		},
+		.user_stack	= {
+			.size	= sizeof(data),
+			.data	= (void *)data,
+		},
+		.read		= {
+			.time_enabled = 0x030a59d664fca7deULL,
+			.time_running = 0x011b6ae553eb98edULL,
+		},
+	};
+	struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
+	struct perf_sample sample_out;
+	size_t i, sz, bufsz;
+	int err, ret = -1;
+
+	for (i = 0; i < sizeof(user_regs); i++)
+		*(i + (u8 *)user_regs) = i & 0xfe;
+
+	if (read_format & PERF_FORMAT_GROUP) {
+		sample.read.group.nr     = 4;
+		sample.read.group.values = values;
+	} else {
+		sample.read.one.value = 0x08789faeb786aa87ULL;
+		sample.read.one.id    = 99;
+	}
+
+	sz = perf_event__sample_event_size(&sample, sample_type,
+					   sample_regs_user, read_format);
+	bufsz = sz + 4096; /* Add a bit for overrun checking */
+	event = malloc(bufsz);
+	if (!event) {
+		pr_debug("malloc failed\n");
+		return -1;
+	}
+
+	memset(event, 0xff, bufsz);
+	event->header.type = PERF_RECORD_SAMPLE;
+	event->header.misc = 0;
+	event->header.size = sz;
+
+	err = perf_event__synthesize_sample(event, sample_type,
+					    sample_regs_user, read_format,
+					    &sample, false);
+	if (err) {
+		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
+			 "perf_event__synthesize_sample", sample_type, err);
+		goto out_free;
+	}
+
+	/* The data does not contain 0xff so we use that to check the size */
+	for (i = bufsz; i > 0; i--) {
+		if (*(i - 1 + (u8 *)event) != 0xff)
+			break;
+	}
+	if (i != sz) {
+		pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
+			 i, sz);
+		goto out_free;
+	}
+
+	evsel.sample_size = __perf_evsel__sample_size(sample_type);
+
+	err = perf_evsel__parse_sample(&evsel, event, &sample_out);
+	if (err) {
+		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
+			 "perf_evsel__parse_sample", sample_type, err);
+		goto out_free;
+	}
+
+	if (!samples_same(&sample, &sample_out, sample_type,
+			  sample_regs_user, read_format)) {
+		pr_debug("parsing failed for sample_type %#"PRIx64"\n",
+			 sample_type);
+		goto out_free;
+	}
+
+	ret = 0;
+out_free:
+	free(event);
+	if (ret && read_format)
+		pr_debug("read_format %#"PRIx64"\n", read_format);
+	return ret;
+}
+
+/**
+ * test__sample_parsing - test sample parsing.
+ *
+ * This function implements a test that synthesizes a sample event, parses it
+ * and then checks that the parsed sample matches the original sample.  The test
+ * checks sample format bits separately and together.  If the test passes %0 is
+ * returned, otherwise %-1 is returned.
+ */
+int test__sample_parsing(void)
+{
+	const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
+	u64 sample_type;
+	u64 sample_regs_user;
+	size_t i;
+	int err;
+
+	/*
+	 * Fail the test if it has not been updated when new sample format bits
+	 * were added.
+	 */
+	if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) {
+		pr_debug("sample format has changed - test needs updating\n");
+		return -1;
+	}
+
+	/* Test each sample format bit separately */
+	for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
+	     sample_type <<= 1) {
+		/* Test read_format variations */
+		if (sample_type == PERF_SAMPLE_READ) {
+			for (i = 0; i < ARRAY_SIZE(rf); i++) {
+				err = do_test(sample_type, 0, rf[i]);
+				if (err)
+					return err;
+			}
+			continue;
+		}
+
+		if (sample_type == PERF_SAMPLE_REGS_USER)
+			sample_regs_user = 0x3fff;
+		else
+			sample_regs_user = 0;
+
+		err = do_test(sample_type, sample_regs_user, 0);
+		if (err)
+			return err;
+	}
+
+	/* Test all sample format bits together */
+	sample_type = PERF_SAMPLE_MAX - 1;
+	sample_regs_user = 0x3fff;
+	for (i = 0; i < ARRAY_SIZE(rf); i++) {
+		err = do_test(sample_type, sample_regs_user, rf[i]);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index dd7feae..c048b58 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,14 @@
 #ifndef TESTS_H
 #define TESTS_H
 
+#define TEST_ASSERT_VAL(text, cond)					 \
+do {									 \
+	if (!(cond)) {							 \
+		pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+		return -1;						 \
+	}								 \
+} while (0)
+
 enum {
 	TEST_OK   =  0,
 	TEST_FAIL = -1,
@@ -27,5 +35,9 @@
 int test__bp_signal_overflow(void);
 int test__task_exit(void);
 int test__sw_clock_freq(void);
+int test__perf_time_to_tsc(void);
+int test__code_reading(void);
+int test__sample_parsing(void);
+int test__keep_tracking(void);
 
 #endif /* TESTS_H */
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 7b4c4d2..2bd13ed 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -16,6 +16,8 @@
 	return 0;
 }
 
+#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
+
 int test__vmlinux_matches_kallsyms(void)
 {
 	int err = -1;
@@ -25,6 +27,7 @@
 	struct machine kallsyms, vmlinux;
 	enum map_type type = MAP__FUNCTION;
 	struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
+	u64 mem_start, mem_end;
 
 	/*
 	 * Step 1:
@@ -73,7 +76,7 @@
 		goto out;
 	}
 
-	ref_reloc_sym.addr = sym->start;
+	ref_reloc_sym.addr = UM(sym->start);
 
 	/*
 	 * Step 5:
@@ -123,10 +126,14 @@
 		if (sym->start == sym->end)
 			continue;
 
-		first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
+		mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start);
+		mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end);
+
+		first_pair = machine__find_kernel_symbol(&kallsyms, type,
+							 mem_start, NULL, NULL);
 		pair = first_pair;
 
-		if (pair && pair->start == sym->start) {
+		if (pair && UM(pair->start) == mem_start) {
 next_pair:
 			if (strcmp(sym->name, pair->name) == 0) {
 				/*
@@ -138,12 +145,20 @@
 				 * off the real size. More than that and we
 				 * _really_ have a problem.
 				 */
-				s64 skew = sym->end - pair->end;
-				if (llabs(skew) < page_size)
-					continue;
+				s64 skew = mem_end - UM(pair->end);
+				if (llabs(skew) >= page_size)
+					pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
+						 mem_start, sym->name, mem_end,
+						 UM(pair->end));
 
-				pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
-					 sym->start, sym->name, sym->end, pair->end);
+				/*
+				 * Do not count this as a failure, because we
+				 * could really find a case where it's not
+				 * possible to get proper function end from
+				 * kallsyms.
+				 */
+				continue;
+
 			} else {
 				struct rb_node *nnd;
 detour:
@@ -152,7 +167,7 @@
 				if (nnd) {
 					struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
 
-					if (next->start == sym->start) {
+					if (UM(next->start) == mem_start) {
 						pair = next;
 						goto next_pair;
 					}
@@ -165,10 +180,11 @@
 				}
 
 				pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
-					 sym->start, sym->name, pair->name);
+					 mem_start, sym->name, pair->name);
 			}
 		} else
-			pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
+			pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
+				 mem_start, sym->name);
 
 		err = -1;
 	}
@@ -201,16 +217,19 @@
 	for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
 		struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
 
-		pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
+		mem_start = vmlinux_map->unmap_ip(vmlinux_map, pos->start);
+		mem_end = vmlinux_map->unmap_ip(vmlinux_map, pos->end);
+
+		pair = map_groups__find(&kallsyms.kmaps, type, mem_start);
 		if (pair == NULL || pair->priv)
 			continue;
 
-		if (pair->start == pos->start) {
+		if (pair->start == mem_start) {
 			pair->priv = 1;
 			pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
 				pos->start, pos->end, pos->pgoff, pos->dso->name);
-			if (pos->pgoff != pair->pgoff || pos->end != pair->end)
-				pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
+			if (mem_end != pair->end)
+				pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64,
 					pair->start, pair->end, pair->pgoff);
 			pr_info(" %s\n", pair->dso->name);
 			pair->priv = 1;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index cc64d3f..08545ae 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -428,6 +428,14 @@
 	browser->b.nr_entries = browser->nr_asm_entries;
 }
 
+#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
+
+static int sym_title(struct symbol *sym, struct map *map, char *title,
+		     size_t sz)
+{
+	return snprintf(title, sz, "%s  %s", sym->name, map->dso->long_name);
+}
+
 static bool annotate_browser__callq(struct annotate_browser *browser,
 				    struct perf_evsel *evsel,
 				    struct hist_browser_timer *hbt)
@@ -438,6 +446,7 @@
 	struct annotation *notes;
 	struct symbol *target;
 	u64 ip;
+	char title[SYM_TITLE_MAX_SIZE];
 
 	if (!ins__is_call(dl->ins))
 		return false;
@@ -461,7 +470,8 @@
 
 	pthread_mutex_unlock(&notes->lock);
 	symbol__tui_annotate(target, ms->map, evsel, hbt);
-	ui_browser__show_title(&browser->b, sym->name);
+	sym_title(sym, ms->map, title, sizeof(title));
+	ui_browser__show_title(&browser->b, title);
 	return true;
 }
 
@@ -495,7 +505,7 @@
 
 	dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
 	if (dl == NULL) {
-		ui_helpline__puts("Invallid jump offset");
+		ui_helpline__puts("Invalid jump offset");
 		return true;
 	}
 
@@ -653,8 +663,10 @@
 	const char *help = "Press 'h' for help on key bindings";
 	int delay_secs = hbt ? hbt->refresh : 0;
 	int key;
+	char title[SYM_TITLE_MAX_SIZE];
 
-	if (ui_browser__show(&browser->b, sym->name, help) < 0)
+	sym_title(sym, ms->map, title, sizeof(title));
+	if (ui_browser__show(&browser->b, title, help) < 0)
 		return -1;
 
 	annotate_browser__calc_percent(browser, evsel);
@@ -720,7 +732,7 @@
 		"s             Toggle source code view\n"
 		"/             Search string\n"
 		"r             Run available scripts\n"
-		"?             Search previous string\n");
+		"?             Search string backwards\n");
 			continue;
 		case 'r':
 			{
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index fc0bd38..7ef36c3 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -685,8 +685,10 @@
 	return he->stat._field;						\
 }									\
 									\
-static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp,	\
-					   struct hist_entry *he)	\
+static int								\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+				struct perf_hpp *hpp,			\
+				struct hist_entry *he)			\
 {									\
 	return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb);	\
 }
@@ -701,8 +703,6 @@
 
 void hist_browser__init_hpp(void)
 {
-	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
-
 	perf_hpp__init();
 
 	perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -762,9 +762,9 @@
 			first = false;
 
 			if (fmt->color) {
-				width -= fmt->color(&hpp, entry);
+				width -= fmt->color(fmt, &hpp, entry);
 			} else {
-				width -= fmt->entry(&hpp, entry);
+				width -= fmt->entry(fmt, &hpp, entry);
 				slsmg_printf("%s", s);
 			}
 		}
@@ -1256,7 +1256,7 @@
 		printed += scnprintf(bf + printed, size - printed,
 				    ", Thread: %s(%d)",
 				    (thread->comm_set ? thread->comm : ""),
-				    thread->pid);
+				    thread->tid);
 	if (dso)
 		printed += scnprintf(bf + printed, size - printed,
 				    ", DSO: %s", dso->short_name);
@@ -1579,7 +1579,7 @@
 		    asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
 			     (browser->hists->thread_filter ? "out of" : "into"),
 			     (thread->comm_set ? thread->comm : ""),
-			     thread->pid) > 0)
+			     thread->tid) > 0)
 			zoom_thread = nr_options++;
 
 		if (dso != NULL &&
@@ -1702,7 +1702,7 @@
 			} else {
 				ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
 						   thread->comm_set ? thread->comm : "",
-						   thread->pid);
+						   thread->tid);
 				browser->hists->thread_filter = thread;
 				sort_thread.elide = true;
 				pstack__push(fstack, &browser->hists->thread_filter);
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 9708dd5..2ca66cc 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -91,7 +91,8 @@
 	return he->stat._field;							\
 }										\
 										\
-static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp,			\
+static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,	\
+				       struct perf_hpp *hpp,			\
 				       struct hist_entry *he)			\
 {										\
 	return __hpp__color_fmt(hpp, he, he_get_##_field);			\
@@ -108,8 +109,6 @@
 
 void perf_gtk__init_hpp(void)
 {
-	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
-
 	perf_hpp__init();
 
 	perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -124,6 +123,81 @@
 				perf_gtk__hpp_color_overhead_guest_us;
 }
 
+static void callchain_list__sym_name(struct callchain_list *cl,
+				     char *bf, size_t bfsize)
+{
+	if (cl->ms.sym)
+		scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
+	else
+		scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
+}
+
+static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
+				    GtkTreeIter *parent, int col, u64 total)
+{
+	struct rb_node *nd;
+	bool has_single_node = (rb_first(root) == rb_last(root));
+
+	for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+		struct callchain_node *node;
+		struct callchain_list *chain;
+		GtkTreeIter iter, new_parent;
+		bool need_new_parent;
+		double percent;
+		u64 hits, child_total;
+
+		node = rb_entry(nd, struct callchain_node, rb_node);
+
+		hits = callchain_cumul_hits(node);
+		percent = 100.0 * hits / total;
+
+		new_parent = *parent;
+		need_new_parent = !has_single_node && (node->val_nr > 1);
+
+		list_for_each_entry(chain, &node->val, list) {
+			char buf[128];
+
+			gtk_tree_store_append(store, &iter, &new_parent);
+
+			scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
+			gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+			callchain_list__sym_name(chain, buf, sizeof(buf));
+			gtk_tree_store_set(store, &iter, col, buf, -1);
+
+			if (need_new_parent) {
+				/*
+				 * Only show the top-most symbol in a callchain
+				 * if it's not the only callchain.
+				 */
+				new_parent = iter;
+				need_new_parent = false;
+			}
+		}
+
+		if (callchain_param.mode == CHAIN_GRAPH_REL)
+			child_total = node->children_hit;
+		else
+			child_total = total;
+
+		/* Now 'iter' contains info of the last callchain_list */
+		perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
+					child_total);
+	}
+}
+
+static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
+			     GtkTreeViewColumn *col __maybe_unused,
+			     gpointer user_data __maybe_unused)
+{
+	bool expanded = gtk_tree_view_row_expanded(view, path);
+
+	if (expanded)
+		gtk_tree_view_collapse_row(view, path);
+	else
+		gtk_tree_view_expand_row(view, path, FALSE);
+}
+
 static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
 				 float min_pcnt)
 {
@@ -131,10 +205,11 @@
 	GType col_types[MAX_COLUMNS];
 	GtkCellRenderer *renderer;
 	struct sort_entry *se;
-	GtkListStore *store;
+	GtkTreeStore *store;
 	struct rb_node *nd;
 	GtkWidget *view;
 	int col_idx;
+	int sym_col = -1;
 	int nr_cols;
 	char s[512];
 
@@ -153,10 +228,13 @@
 		if (se->elide)
 			continue;
 
+		if (se == &sort_sym)
+			sym_col = nr_cols;
+
 		col_types[nr_cols++] = G_TYPE_STRING;
 	}
 
-	store = gtk_list_store_newv(nr_cols, col_types);
+	store = gtk_tree_store_newv(nr_cols, col_types);
 
 	view = gtk_tree_view_new();
 
@@ -165,7 +243,7 @@
 	col_idx = 0;
 
 	perf_hpp__for_each_format(fmt) {
-		fmt->header(&hpp);
+		fmt->header(fmt, &hpp);
 
 		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
 							    -1, ltrim(s),
@@ -183,6 +261,18 @@
 							    col_idx++, NULL);
 	}
 
+	for (col_idx = 0; col_idx < nr_cols; col_idx++) {
+		GtkTreeViewColumn *column;
+
+		column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
+		gtk_tree_view_column_set_resizable(column, TRUE);
+
+		if (col_idx == sym_col) {
+			gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
+							  column);
+		}
+	}
+
 	gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
 
 	g_object_unref(GTK_TREE_MODEL(store));
@@ -199,17 +289,17 @@
 		if (percent < min_pcnt)
 			continue;
 
-		gtk_list_store_append(store, &iter);
+		gtk_tree_store_append(store, &iter, NULL);
 
 		col_idx = 0;
 
 		perf_hpp__for_each_format(fmt) {
 			if (fmt->color)
-				fmt->color(&hpp, h);
+				fmt->color(fmt, &hpp, h);
 			else
-				fmt->entry(&hpp, h);
+				fmt->entry(fmt, &hpp, h);
 
-			gtk_list_store_set(store, &iter, col_idx++, s, -1);
+			gtk_tree_store_set(store, &iter, col_idx++, s, -1);
 		}
 
 		list_for_each_entry(se, &hist_entry__sort_list, list) {
@@ -219,10 +309,26 @@
 			se->se_snprintf(h, s, ARRAY_SIZE(s),
 					hists__col_len(hists, se->se_width_idx));
 
-			gtk_list_store_set(store, &iter, col_idx++, s, -1);
+			gtk_tree_store_set(store, &iter, col_idx++, s, -1);
+		}
+
+		if (symbol_conf.use_callchain && sort__has_sym) {
+			u64 total;
+
+			if (callchain_param.mode == CHAIN_GRAPH_REL)
+				total = h->stat.period;
+			else
+				total = hists->stats.total_period;
+
+			perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
+						sym_col, total);
 		}
 	}
 
+	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
+
+	g_signal_connect(view, "row-activated",
+			 G_CALLBACK(on_row_activated), NULL);
 	gtk_container_add(GTK_CONTAINER(window), view);
 }
 
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 4bf91b0..0a19328 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -1,4 +1,5 @@
 #include <math.h>
+#include <linux/compiler.h>
 
 #include "../util/hist.h"
 #include "../util/util.h"
@@ -79,7 +80,8 @@
 }
 
 #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) 		\
-static int hpp__header_##_type(struct perf_hpp *hpp)			\
+static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,	\
+			       struct perf_hpp *hpp)			\
 {									\
 	int len = _min_width;						\
 									\
@@ -92,7 +94,8 @@
 }
 
 #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) 			\
-static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused)	\
+static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused,	\
+			      struct perf_hpp *hpp __maybe_unused)	\
 {									\
 	int len = _min_width;						\
 									\
@@ -110,14 +113,16 @@
 	return he->stat._field;							\
 }										\
 										\
-static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) 	\
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,		\
+			      struct perf_hpp *hpp, struct hist_entry *he) 	\
 {										\
 	return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",			\
 			  (hpp_snprint_fn)percent_color_snprintf, true);	\
 }
 
 #define __HPP_ENTRY_PERCENT_FN(_type, _field)					\
-static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) 	\
+static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,		\
+			      struct perf_hpp *hpp, struct hist_entry *he) 	\
 {										\
 	const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";		\
 	return __hpp__fmt(hpp, he, he_get_##_field, fmt,			\
@@ -130,7 +135,8 @@
 	return he->stat._field;							\
 }										\
 										\
-static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) 	\
+static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,		\
+			      struct perf_hpp *hpp, struct hist_entry *he) 	\
 {										\
 	const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;	\
 	return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false);	\
@@ -157,196 +163,6 @@
 HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
 HPP_RAW_FNS(period, "Period", period, 12, 12)
 
-
-static int hpp__header_baseline(struct perf_hpp *hpp)
-{
-	return scnprintf(hpp->buf, hpp->size, "Baseline");
-}
-
-static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
-{
-	return 8;
-}
-
-static double baseline_percent(struct hist_entry *he)
-{
-	struct hist_entry *pair = hist_entry__next_pair(he);
-	struct hists *pair_hists = pair ? pair->hists : NULL;
-	double percent = 0.0;
-
-	if (pair) {
-		u64 total_period = pair_hists->stats.total_period;
-		u64 base_period  = pair->stat.period;
-
-		percent = 100.0 * base_period / total_period;
-	}
-
-	return percent;
-}
-
-static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	double percent = baseline_percent(he);
-
-	if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
-		return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
-	else
-		return scnprintf(hpp->buf, hpp->size, "        ");
-}
-
-static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	double percent = baseline_percent(he);
-	const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
-
-	if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
-		return scnprintf(hpp->buf, hpp->size, fmt, percent);
-	else
-		return scnprintf(hpp->buf, hpp->size, "            ");
-}
-
-static int hpp__header_period_baseline(struct perf_hpp *hpp)
-{
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
-
-	return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
-}
-
-static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
-{
-	return 12;
-}
-
-static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	struct hist_entry *pair = hist_entry__next_pair(he);
-	u64 period = pair ? pair->stat.period : 0;
-	const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
-
-	return scnprintf(hpp->buf, hpp->size, fmt, period);
-}
-
-static int hpp__header_delta(struct perf_hpp *hpp)
-{
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
-
-	return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
-}
-
-static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
-{
-	return 7;
-}
-
-static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	struct hist_entry *pair = hist_entry__next_pair(he);
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
-	char buf[32] = " ";
-	double diff = 0.0;
-
-	if (pair) {
-		if (he->diff.computed)
-			diff = he->diff.period_ratio_delta;
-		else
-			diff = perf_diff__compute_delta(he, pair);
-	} else
-		diff = perf_diff__period_percent(he, he->stat.period);
-
-	if (fabs(diff) >= 0.01)
-		scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
-
-	return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
-static int hpp__header_ratio(struct perf_hpp *hpp)
-{
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-
-	return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
-}
-
-static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
-{
-	return 14;
-}
-
-static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	struct hist_entry *pair = hist_entry__next_pair(he);
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-	char buf[32] = " ";
-	double ratio = 0.0;
-
-	if (pair) {
-		if (he->diff.computed)
-			ratio = he->diff.period_ratio;
-		else
-			ratio = perf_diff__compute_ratio(he, pair);
-	}
-
-	if (ratio > 0.0)
-		scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
-
-	return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
-static int hpp__header_wdiff(struct perf_hpp *hpp)
-{
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-
-	return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
-}
-
-static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
-{
-	return 14;
-}
-
-static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	struct hist_entry *pair = hist_entry__next_pair(he);
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
-	char buf[32] = " ";
-	s64 wdiff = 0;
-
-	if (pair) {
-		if (he->diff.computed)
-			wdiff = he->diff.wdiff;
-		else
-			wdiff = perf_diff__compute_wdiff(he, pair);
-	}
-
-	if (wdiff != 0)
-		scnprintf(buf, sizeof(buf), "%14ld", wdiff);
-
-	return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
-static int hpp__header_formula(struct perf_hpp *hpp)
-{
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
-
-	return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
-}
-
-static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
-{
-	return 70;
-}
-
-static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
-{
-	struct hist_entry *pair = hist_entry__next_pair(he);
-	const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
-	char buf[96] = " ";
-
-	if (pair)
-		perf_diff__formula(he, pair, buf, sizeof(buf));
-
-	return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
 #define HPP__COLOR_PRINT_FNS(_name)			\
 	{						\
 		.header	= hpp__header_ ## _name,	\
@@ -363,19 +179,13 @@
 	}
 
 struct perf_hpp_fmt perf_hpp__format[] = {
-	HPP__COLOR_PRINT_FNS(baseline),
 	HPP__COLOR_PRINT_FNS(overhead),
 	HPP__COLOR_PRINT_FNS(overhead_sys),
 	HPP__COLOR_PRINT_FNS(overhead_us),
 	HPP__COLOR_PRINT_FNS(overhead_guest_sys),
 	HPP__COLOR_PRINT_FNS(overhead_guest_us),
 	HPP__PRINT_FNS(samples),
-	HPP__PRINT_FNS(period),
-	HPP__PRINT_FNS(period_baseline),
-	HPP__PRINT_FNS(delta),
-	HPP__PRINT_FNS(ratio),
-	HPP__PRINT_FNS(wdiff),
-	HPP__PRINT_FNS(formula)
+	HPP__PRINT_FNS(period)
 };
 
 LIST_HEAD(perf_hpp__list);
@@ -396,6 +206,8 @@
 
 void perf_hpp__init(void)
 {
+	perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
 	if (symbol_conf.show_cpu_utilization) {
 		perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
 		perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
@@ -424,46 +236,6 @@
 	perf_hpp__column_register(&perf_hpp__format[col]);
 }
 
-static inline void advance_hpp(struct perf_hpp *hpp, int inc)
-{
-	hpp->buf  += inc;
-	hpp->size -= inc;
-}
-
-int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
-				bool color)
-{
-	const char *sep = symbol_conf.field_sep;
-	struct perf_hpp_fmt *fmt;
-	char *start = hpp->buf;
-	int ret;
-	bool first = true;
-
-	if (symbol_conf.exclude_other && !he->parent)
-		return 0;
-
-	perf_hpp__for_each_format(fmt) {
-		/*
-		 * If there's no field_sep, we still need
-		 * to display initial '  '.
-		 */
-		if (!sep || !first) {
-			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
-			advance_hpp(hpp, ret);
-		} else
-			first = false;
-
-		if (color && fmt->color)
-			ret = fmt->color(hpp, he);
-		else
-			ret = fmt->entry(hpp, he);
-
-		advance_hpp(hpp, ret);
-	}
-
-	return hpp->buf - start;
-}
-
 int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
 			      struct hists *hists)
 {
@@ -499,7 +271,7 @@
 		if (i)
 			ret += 2;
 
-		ret += fmt->width(&dummy_hpp);
+		ret += fmt->width(fmt, &dummy_hpp);
 	}
 
 	list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ae6a789..47d9a57 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -30,7 +30,6 @@
 		if (fallback_to_pager)
 			setup_pager();
 
-		perf_hpp__column_enable(PERF_HPP__OVERHEAD);
 		perf_hpp__init();
 		break;
 	}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index ae7a754..5b4fb33 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -308,6 +308,47 @@
 	return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
 }
 
+static inline void advance_hpp(struct perf_hpp *hpp, int inc)
+{
+	hpp->buf  += inc;
+	hpp->size -= inc;
+}
+
+static int hist_entry__period_snprintf(struct perf_hpp *hpp,
+				       struct hist_entry *he,
+				       bool color)
+{
+	const char *sep = symbol_conf.field_sep;
+	struct perf_hpp_fmt *fmt;
+	char *start = hpp->buf;
+	int ret;
+	bool first = true;
+
+	if (symbol_conf.exclude_other && !he->parent)
+		return 0;
+
+	perf_hpp__for_each_format(fmt) {
+		/*
+		 * If there's no field_sep, we still need
+		 * to display initial '  '.
+		 */
+		if (!sep || !first) {
+			ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
+			advance_hpp(hpp, ret);
+		} else
+			first = false;
+
+		if (color && fmt->color)
+			ret = fmt->color(fmt, hpp, he);
+		else
+			ret = fmt->entry(fmt, hpp, he);
+
+		advance_hpp(hpp, ret);
+	}
+
+	return hpp->buf - start;
+}
+
 static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 			       struct hists *hists, FILE *fp)
 {
@@ -365,7 +406,7 @@
 		else
 			first = false;
 
-		fmt->header(&dummy_hpp);
+		fmt->header(fmt, &dummy_hpp);
 		fprintf(fp, "%s", bf);
 	}
 
@@ -410,7 +451,7 @@
 		else
 			first = false;
 
-		width = fmt->width(&dummy_hpp);
+		width = fmt->width(fmt, &dummy_hpp);
 		for (i = 0; i < width; i++)
 			fprintf(fp, ".");
 	}
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d102716..bfc5a27 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -110,10 +110,10 @@
 {
 	const char *s = strchr(ops->raw, '+');
 
-	ops->target.addr = strtoll(ops->raw, NULL, 16);
+	ops->target.addr = strtoull(ops->raw, NULL, 16);
 
 	if (s++ != NULL)
-		ops->target.offset = strtoll(s, NULL, 16);
+		ops->target.offset = strtoull(s, NULL, 16);
 	else
 		ops->target.offset = UINT64_MAX;
 
@@ -821,11 +821,55 @@
 	if (dl == NULL)
 		return -1;
 
+	if (dl->ops.target.offset == UINT64_MAX)
+		dl->ops.target.offset = dl->ops.target.addr -
+					map__rip_2objdump(map, sym->start);
+
+	/*
+	 * kcore has no symbols, so add the call target name if it is on the
+	 * same map.
+	 */
+	if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
+		struct symbol *s;
+		u64 ip = dl->ops.target.addr;
+
+		if (ip >= map->start && ip <= map->end) {
+			ip = map->map_ip(map, ip);
+			s = map__find_symbol(map, ip, NULL);
+			if (s && s->start == ip)
+				dl->ops.target.name = strdup(s->name);
+		}
+	}
+
 	disasm__add(&notes->src->source, dl);
 
 	return 0;
 }
 
+static void delete_last_nop(struct symbol *sym)
+{
+	struct annotation *notes = symbol__annotation(sym);
+	struct list_head *list = &notes->src->source;
+	struct disasm_line *dl;
+
+	while (!list_empty(list)) {
+		dl = list_entry(list->prev, struct disasm_line, node);
+
+		if (dl->ins && dl->ins->ops) {
+			if (dl->ins->ops != &nop_ops)
+				return;
+		} else {
+			if (!strstr(dl->line, " nop ") &&
+			    !strstr(dl->line, " nopl ") &&
+			    !strstr(dl->line, " nopw "))
+				return;
+		}
+
+		list_del(&dl->node);
+		disasm_line__free(dl);
+	}
+}
+
 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
 {
 	struct dso *dso = map->dso;
@@ -864,7 +908,8 @@
 		free_filename = false;
 	}
 
-	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
+	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
+	    !dso__is_kcore(dso)) {
 		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
 		char *build_id_msg = NULL;
 
@@ -898,7 +943,7 @@
 	snprintf(command, sizeof(command),
 		 "%s %s%s --start-address=0x%016" PRIx64
 		 " --stop-address=0x%016" PRIx64
-		 " -d %s %s -C %s|grep -v %s|expand",
+		 " -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
 		 objdump_path ? objdump_path : "objdump",
 		 disassembler_style ? "-M " : "",
 		 disassembler_style ? disassembler_style : "",
@@ -918,6 +963,13 @@
 		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
 			break;
 
+	/*
+	 * kallsyms does not have symbol sizes so there may a nop at the end.
+	 * Remove it.
+	 */
+	if (dso__is_kcore(dso))
+		delete_last_nop(sym);
+
 	pclose(file);
 out_free_filename:
 	if (free_filename)
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 5295625..fb58409 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -18,13 +18,14 @@
 
 int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
 			   union perf_event *event,
-			   struct perf_sample *sample __maybe_unused,
+			   struct perf_sample *sample,
 			   struct perf_evsel *evsel __maybe_unused,
 			   struct machine *machine)
 {
 	struct addr_location al;
 	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-	struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
+	struct thread *thread = machine__findnew_thread(machine, sample->pid,
+							sample->pid);
 
 	if (thread == NULL) {
 		pr_err("problem processing %d event, skipping it.\n",
@@ -33,7 +34,7 @@
 	}
 
 	thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
-			      event->ip.ip, &al);
+			      sample->ip, &al);
 
 	if (al.map != NULL)
 		al.map->dso->hit = 1;
@@ -47,7 +48,9 @@
 				       __maybe_unused,
 				       struct machine *machine)
 {
-	struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
+	struct thread *thread = machine__findnew_thread(machine,
+							event->fork.pid,
+							event->fork.tid);
 
 	dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
 		    event->fork.ppid, event->fork.ptid);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 42b6a63..482f680 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -15,19 +15,12 @@
 #include <errno.h>
 #include <math.h>
 
+#include "hist.h"
 #include "util.h"
 #include "callchain.h"
 
 __thread struct callchain_cursor callchain_cursor;
 
-bool ip_callchain__valid(struct ip_callchain *chain,
-			 const union perf_event *event)
-{
-	unsigned int chain_size = event->header.size;
-	chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
-	return chain->nr * sizeof(u64) <= chain_size;
-}
-
 #define chain_for_each_child(child, parent)	\
 	list_for_each_entry(child, &parent->children, siblings)
 
@@ -327,7 +320,8 @@
 	/*
 	 * Lookup in the current node
 	 * If we have a symbol, then compare the start to match
-	 * anywhere inside a function.
+	 * anywhere inside a function, unless function
+	 * mode is disabled.
 	 */
 	list_for_each_entry(cnode, &root->val, list) {
 		struct callchain_cursor_node *node;
@@ -339,7 +333,8 @@
 
 		sym = node->sym;
 
-		if (cnode->ms.sym && sym) {
+		if (cnode->ms.sym && sym &&
+		    callchain_param.key == CCKEY_FUNCTION) {
 			if (cnode->ms.sym->start != sym->start)
 				break;
 		} else if (cnode->ip != node->ip)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 3ee9f67..2b585bc 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -41,12 +41,18 @@
 typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
 				 u64, struct callchain_param *);
 
+enum chain_key {
+	CCKEY_FUNCTION,
+	CCKEY_ADDRESS
+};
+
 struct callchain_param {
 	enum chain_mode 	mode;
 	u32			print_limit;
 	double			min_percent;
 	sort_chain_func_t	sort;
 	enum chain_order	order;
+	enum chain_key		key;
 };
 
 struct callchain_list {
@@ -103,11 +109,6 @@
 int callchain_merge(struct callchain_cursor *cursor,
 		    struct callchain_root *dst, struct callchain_root *src);
 
-struct ip_callchain;
-union perf_event;
-
-bool ip_callchain__valid(struct ip_callchain *chain,
-			 const union perf_event *event);
 /*
  * Initialize a cursor before adding entries inside, but keep
  * the previously allocated entries as a cache.
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 9bed02e..b123bb9 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -41,7 +41,7 @@
 	return map ? map->nr : 1;
 }
 
-static inline bool cpu_map__all(const struct cpu_map *map)
+static inline bool cpu_map__empty(const struct cpu_map *map)
 {
 	return map ? map->map[0] == -1 : true;
 }
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index c4374f0..e3c1ff8 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -78,6 +78,8 @@
 			 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
 		break;
 
+	case DSO_BINARY_TYPE__VMLINUX:
+	case DSO_BINARY_TYPE__GUEST_VMLINUX:
 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
 		snprintf(file, size, "%s%s",
 			 symbol_conf.symfs, dso->long_name);
@@ -93,11 +95,14 @@
 			 dso->long_name);
 		break;
 
+	case DSO_BINARY_TYPE__KCORE:
+	case DSO_BINARY_TYPE__GUEST_KCORE:
+		snprintf(file, size, "%s", dso->long_name);
+		break;
+
 	default:
 	case DSO_BINARY_TYPE__KALLSYMS:
-	case DSO_BINARY_TYPE__VMLINUX:
 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
-	case DSO_BINARY_TYPE__GUEST_VMLINUX:
 	case DSO_BINARY_TYPE__JAVA_JIT:
 	case DSO_BINARY_TYPE__NOT_FOUND:
 		ret = -1;
@@ -419,6 +424,7 @@
 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->data_type   = DSO_BINARY_TYPE__NOT_FOUND;
 		dso->loaded = 0;
+		dso->rel = 0;
 		dso->sorted_by_name = 0;
 		dso->has_build_id = 0;
 		dso->kernel = DSO_TYPE_USER;
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index d51aaf2..b793053 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <linux/rbtree.h>
+#include <stdbool.h>
 #include "types.h"
 #include "map.h"
 
@@ -20,6 +21,8 @@
 	DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
 	DSO_BINARY_TYPE__GUEST_KMODULE,
 	DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+	DSO_BINARY_TYPE__KCORE,
+	DSO_BINARY_TYPE__GUEST_KCORE,
 	DSO_BINARY_TYPE__NOT_FOUND,
 };
 
@@ -84,6 +87,7 @@
 	u8		 lname_alloc:1;
 	u8		 sorted_by_name;
 	u8		 loaded;
+	u8		 rel;
 	u8		 build_id[BUILD_ID_SIZE];
 	const char	 *short_name;
 	char		 *long_name;
@@ -146,4 +150,17 @@
 size_t dso__fprintf_symbols_by_name(struct dso *dso,
 				    enum map_type type, FILE *fp);
 size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
+
+static inline bool dso__is_vmlinux(struct dso *dso)
+{
+	return dso->data_type == DSO_BINARY_TYPE__VMLINUX ||
+	       dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
+}
+
+static inline bool dso__is_kcore(struct dso *dso)
+{
+	return dso->data_type == DSO_BINARY_TYPE__KCORE ||
+	       dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
+}
+
 #endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 5cd13d7..8d51f21 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -595,6 +595,7 @@
 			   struct addr_location *al)
 {
 	struct map_groups *mg = &self->mg;
+	bool load_map = false;
 
 	al->thread = self;
 	al->addr = addr;
@@ -609,11 +610,13 @@
 	if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
 		al->level = 'k';
 		mg = &machine->kmaps;
+		load_map = true;
 	} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
 		al->level = '.';
 	} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
 		al->level = 'g';
 		mg = &machine->kmaps;
+		load_map = true;
 	} else {
 		/*
 		 * 'u' means guest os user space.
@@ -654,18 +657,25 @@
 			mg = &machine->kmaps;
 			goto try_again;
 		}
-	} else
+	} else {
+		/*
+		 * Kernel maps might be changed when loading symbols so loading
+		 * must be done prior to using kernel maps.
+		 */
+		if (load_map)
+			map__load(al->map, machine->symbol_filter);
 		al->addr = al->map->map_ip(al->map, al->addr);
+	}
 }
 
 void thread__find_addr_location(struct thread *thread, struct machine *machine,
 				u8 cpumode, enum map_type type, u64 addr,
-				struct addr_location *al,
-				symbol_filter_t filter)
+				struct addr_location *al)
 {
 	thread__find_addr_map(thread, machine, cpumode, type, addr, al);
 	if (al->map != NULL)
-		al->sym = map__find_symbol(al->map, al->addr, filter);
+		al->sym = map__find_symbol(al->map, al->addr,
+					   machine->symbol_filter);
 	else
 		al->sym = NULL;
 }
@@ -673,11 +683,11 @@
 int perf_event__preprocess_sample(const union perf_event *event,
 				  struct machine *machine,
 				  struct addr_location *al,
-				  struct perf_sample *sample,
-				  symbol_filter_t filter)
+				  struct perf_sample *sample)
 {
 	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
-	struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
+	struct thread *thread = machine__findnew_thread(machine, sample->pid,
+							sample->pid);
 
 	if (thread == NULL)
 		return -1;
@@ -686,7 +696,7 @@
 	    !strlist__has_entry(symbol_conf.comm_list, thread->comm))
 		goto out_filtered;
 
-	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
+	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
 	/*
 	 * Have we already created the kernel maps for this machine?
 	 *
@@ -699,7 +709,7 @@
 		machine__create_kernel_maps(machine);
 
 	thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
-			      event->ip.ip, al);
+			      sample->ip, al);
 	dump_printf(" ...... dso: %s\n",
 		    al->map ? al->map->dso->long_name :
 			al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -717,7 +727,8 @@
 						   dso->long_name)))))
 			goto out_filtered;
 
-		al->sym = map__find_symbol(al->map, al->addr, filter);
+		al->sym = map__find_symbol(al->map, al->addr,
+					   machine->symbol_filter);
 	}
 
 	if (symbol_conf.sym_list &&
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1813895..93130d8 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -8,16 +8,6 @@
 #include "map.h"
 #include "build-id.h"
 
-/*
- * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
- */
-struct ip_event {
-	struct perf_event_header header;
-	u64 ip;
-	u32 pid, tid;
-	unsigned char __more_data[];
-};
-
 struct mmap_event {
 	struct perf_event_header header;
 	u32 pid, tid;
@@ -63,7 +53,8 @@
 	(PERF_SAMPLE_IP | PERF_SAMPLE_TID |		\
 	 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR |		\
 	PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID |	\
-	 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
+	 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD |		\
+	 PERF_SAMPLE_IDENTIFIER)
 
 struct sample_event {
 	struct perf_event_header        header;
@@ -71,6 +62,7 @@
 };
 
 struct regs_dump {
+	u64 abi;
 	u64 *regs;
 };
 
@@ -80,6 +72,23 @@
 	char *data;
 };
 
+struct sample_read_value {
+	u64 value;
+	u64 id;
+};
+
+struct sample_read {
+	u64 time_enabled;
+	u64 time_running;
+	union {
+		struct {
+			u64 nr;
+			struct sample_read_value *values;
+		} group;
+		struct sample_read_value one;
+	};
+};
+
 struct perf_sample {
 	u64 ip;
 	u32 pid, tid;
@@ -97,6 +106,7 @@
 	struct branch_stack *branch_stack;
 	struct regs_dump  user_regs;
 	struct stack_dump user_stack;
+	struct sample_read read;
 };
 
 #define PERF_MEM_DATA_SRC_NONE \
@@ -116,7 +126,7 @@
 enum perf_user_event_type { /* above any possible kernel type */
 	PERF_RECORD_USER_TYPE_START		= 64,
 	PERF_RECORD_HEADER_ATTR			= 64,
-	PERF_RECORD_HEADER_EVENT_TYPE		= 65,
+	PERF_RECORD_HEADER_EVENT_TYPE		= 65, /* depreceated */
 	PERF_RECORD_HEADER_TRACING_DATA		= 66,
 	PERF_RECORD_HEADER_BUILD_ID		= 67,
 	PERF_RECORD_FINISHED_ROUND		= 68,
@@ -148,7 +158,6 @@
 
 union perf_event {
 	struct perf_event_header	header;
-	struct ip_event			ip;
 	struct mmap_event		mmap;
 	struct comm_event		comm;
 	struct fork_event		fork;
@@ -216,12 +225,14 @@
 int perf_event__preprocess_sample(const union perf_event *self,
 				  struct machine *machine,
 				  struct addr_location *al,
-				  struct perf_sample *sample,
-				  symbol_filter_t filter);
+				  struct perf_sample *sample);
 
 const char *perf_event__name(unsigned int id);
 
+size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
+				     u64 sample_regs_user, u64 read_format);
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
+				  u64 sample_regs_user, u64 read_format,
 				  const struct perf_sample *sample,
 				  bool swapped);
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8065ce8..b8727ae 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -14,6 +14,7 @@
 #include "target.h"
 #include "evlist.h"
 #include "evsel.h"
+#include "debug.h"
 #include <unistd.h>
 
 #include "parse-events.h"
@@ -48,26 +49,19 @@
 	return evlist;
 }
 
-void perf_evlist__config(struct perf_evlist *evlist,
-			struct perf_record_opts *opts)
+/**
+ * perf_evlist__set_id_pos - set the positions of event ids.
+ * @evlist: selected event list
+ *
+ * Events with compatible sample types all have the same id_pos
+ * and is_pos.  For convenience, put a copy on evlist.
+ */
+void perf_evlist__set_id_pos(struct perf_evlist *evlist)
 {
-	struct perf_evsel *evsel;
-	/*
-	 * Set the evsel leader links before we configure attributes,
-	 * since some might depend on this info.
-	 */
-	if (opts->group)
-		perf_evlist__set_leader(evlist);
+	struct perf_evsel *first = perf_evlist__first(evlist);
 
-	if (evlist->cpus->map[0] < 0)
-		opts->no_inherit = true;
-
-	list_for_each_entry(evsel, &evlist->entries, node) {
-		perf_evsel__config(evsel, opts);
-
-		if (evlist->nr_entries > 1)
-			perf_evsel__set_sample_id(evsel);
-	}
+	evlist->id_pos = first->id_pos;
+	evlist->is_pos = first->is_pos;
 }
 
 static void perf_evlist__purge(struct perf_evlist *evlist)
@@ -100,15 +94,20 @@
 void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
 {
 	list_add_tail(&entry->node, &evlist->entries);
-	++evlist->nr_entries;
+	if (!evlist->nr_entries++)
+		perf_evlist__set_id_pos(evlist);
 }
 
 void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
 				   struct list_head *list,
 				   int nr_entries)
 {
+	bool set_id_pos = !evlist->nr_entries;
+
 	list_splice_tail(list, &evlist->entries);
 	evlist->nr_entries += nr_entries;
+	if (set_id_pos)
+		perf_evlist__set_id_pos(evlist);
 }
 
 void __perf_evlist__set_leader(struct list_head *list)
@@ -209,6 +208,21 @@
 	return NULL;
 }
 
+struct perf_evsel *
+perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
+				     const char *name)
+{
+	struct perf_evsel *evsel;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) &&
+		    (strcmp(evsel->name, name) == 0))
+			return evsel;
+	}
+
+	return NULL;
+}
+
 int perf_evlist__add_newtp(struct perf_evlist *evlist,
 			   const char *sys, const char *name, void *handler)
 {
@@ -232,7 +246,7 @@
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
-			if (!perf_evsel__is_group_leader(pos))
+			if (!perf_evsel__is_group_leader(pos) || !pos->fd)
 				continue;
 			for (thread = 0; thread < nr_threads; thread++)
 				ioctl(FD(pos, cpu, thread),
@@ -250,7 +264,7 @@
 
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		list_for_each_entry(pos, &evlist->entries, node) {
-			if (!perf_evsel__is_group_leader(pos))
+			if (!perf_evsel__is_group_leader(pos) || !pos->fd)
 				continue;
 			for (thread = 0; thread < nr_threads; thread++)
 				ioctl(FD(pos, cpu, thread),
@@ -259,6 +273,44 @@
 	}
 }
 
+int perf_evlist__disable_event(struct perf_evlist *evlist,
+			       struct perf_evsel *evsel)
+{
+	int cpu, thread, err;
+
+	if (!evsel->fd)
+		return 0;
+
+	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+		for (thread = 0; thread < evlist->threads->nr; thread++) {
+			err = ioctl(FD(evsel, cpu, thread),
+				    PERF_EVENT_IOC_DISABLE, 0);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
+int perf_evlist__enable_event(struct perf_evlist *evlist,
+			      struct perf_evsel *evsel)
+{
+	int cpu, thread, err;
+
+	if (!evsel->fd)
+		return -EINVAL;
+
+	for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+		for (thread = 0; thread < evlist->threads->nr; thread++) {
+			err = ioctl(FD(evsel, cpu, thread),
+				    PERF_EVENT_IOC_ENABLE, 0);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
 static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
 {
 	int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -302,6 +354,24 @@
 {
 	u64 read_data[4] = { 0, };
 	int id_idx = 1; /* The first entry is the counter value */
+	u64 id;
+	int ret;
+
+	ret = ioctl(fd, PERF_EVENT_IOC_ID, &id);
+	if (!ret)
+		goto add;
+
+	if (errno != ENOTTY)
+		return -1;
+
+	/* Legacy way to get event id.. All hail to old kernels! */
+
+	/*
+	 * This way does not work with group format read, so bail
+	 * out in that case.
+	 */
+	if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP)
+		return -1;
 
 	if (!(evsel->attr.read_format & PERF_FORMAT_ID) ||
 	    read(fd, &read_data, sizeof(read_data)) == -1)
@@ -312,25 +382,39 @@
 	if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
 		++id_idx;
 
-	perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]);
+	id = read_data[id_idx];
+
+ add:
+	perf_evlist__id_add(evlist, evsel, cpu, thread, id);
 	return 0;
 }
 
-struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
+struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
 {
 	struct hlist_head *head;
 	struct perf_sample_id *sid;
 	int hash;
 
-	if (evlist->nr_entries == 1)
-		return perf_evlist__first(evlist);
-
 	hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
 	head = &evlist->heads[hash];
 
 	hlist_for_each_entry(sid, head, node)
 		if (sid->id == id)
-			return sid->evsel;
+			return sid;
+
+	return NULL;
+}
+
+struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
+{
+	struct perf_sample_id *sid;
+
+	if (evlist->nr_entries == 1)
+		return perf_evlist__first(evlist);
+
+	sid = perf_evlist__id2sid(evlist, id);
+	if (sid)
+		return sid->evsel;
 
 	if (!perf_evlist__sample_id_all(evlist))
 		return perf_evlist__first(evlist);
@@ -338,6 +422,55 @@
 	return NULL;
 }
 
+static int perf_evlist__event2id(struct perf_evlist *evlist,
+				 union perf_event *event, u64 *id)
+{
+	const u64 *array = event->sample.array;
+	ssize_t n;
+
+	n = (event->header.size - sizeof(event->header)) >> 3;
+
+	if (event->header.type == PERF_RECORD_SAMPLE) {
+		if (evlist->id_pos >= n)
+			return -1;
+		*id = array[evlist->id_pos];
+	} else {
+		if (evlist->is_pos > n)
+			return -1;
+		n -= evlist->is_pos;
+		*id = array[n];
+	}
+	return 0;
+}
+
+static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
+						   union perf_event *event)
+{
+	struct hlist_head *head;
+	struct perf_sample_id *sid;
+	int hash;
+	u64 id;
+
+	if (evlist->nr_entries == 1)
+		return perf_evlist__first(evlist);
+
+	if (perf_evlist__event2id(evlist, event, &id))
+		return NULL;
+
+	/* Synthesized events have an id of zero */
+	if (!id)
+		return perf_evlist__first(evlist);
+
+	hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
+	head = &evlist->heads[hash];
+
+	hlist_for_each_entry(sid, head, node) {
+		if (sid->id == id)
+			return sid->evsel;
+	}
+	return NULL;
+}
+
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 {
 	struct perf_mmap *md = &evlist->mmap[idx];
@@ -403,16 +536,20 @@
 	return event;
 }
 
+static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
+{
+	if (evlist->mmap[idx].base != NULL) {
+		munmap(evlist->mmap[idx].base, evlist->mmap_len);
+		evlist->mmap[idx].base = NULL;
+	}
+}
+
 void perf_evlist__munmap(struct perf_evlist *evlist)
 {
 	int i;
 
-	for (i = 0; i < evlist->nr_mmaps; i++) {
-		if (evlist->mmap[i].base != NULL) {
-			munmap(evlist->mmap[i].base, evlist->mmap_len);
-			evlist->mmap[i].base = NULL;
-		}
-	}
+	for (i = 0; i < evlist->nr_mmaps; i++)
+		__perf_evlist__munmap(evlist, i);
 
 	free(evlist->mmap);
 	evlist->mmap = NULL;
@@ -421,7 +558,7 @@
 static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 {
 	evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
-	if (cpu_map__all(evlist->cpus))
+	if (cpu_map__empty(evlist->cpus))
 		evlist->nr_mmaps = thread_map__nr(evlist->threads);
 	evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
 	return evlist->mmap != NULL ? 0 : -ENOMEM;
@@ -450,6 +587,7 @@
 	int nr_cpus = cpu_map__nr(evlist->cpus);
 	int nr_threads = thread_map__nr(evlist->threads);
 
+	pr_debug2("perf event ring buffer mmapped per cpu\n");
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		int output = -1;
 
@@ -477,12 +615,8 @@
 	return 0;
 
 out_unmap:
-	for (cpu = 0; cpu < nr_cpus; cpu++) {
-		if (evlist->mmap[cpu].base != NULL) {
-			munmap(evlist->mmap[cpu].base, evlist->mmap_len);
-			evlist->mmap[cpu].base = NULL;
-		}
-	}
+	for (cpu = 0; cpu < nr_cpus; cpu++)
+		__perf_evlist__munmap(evlist, cpu);
 	return -1;
 }
 
@@ -492,6 +626,7 @@
 	int thread;
 	int nr_threads = thread_map__nr(evlist->threads);
 
+	pr_debug2("perf event ring buffer mmapped per thread\n");
 	for (thread = 0; thread < nr_threads; thread++) {
 		int output = -1;
 
@@ -517,12 +652,8 @@
 	return 0;
 
 out_unmap:
-	for (thread = 0; thread < nr_threads; thread++) {
-		if (evlist->mmap[thread].base != NULL) {
-			munmap(evlist->mmap[thread].base, evlist->mmap_len);
-			evlist->mmap[thread].base = NULL;
-		}
-	}
+	for (thread = 0; thread < nr_threads; thread++)
+		__perf_evlist__munmap(evlist, thread);
 	return -1;
 }
 
@@ -573,7 +704,7 @@
 			return -ENOMEM;
 	}
 
-	if (cpu_map__all(cpus))
+	if (cpu_map__empty(cpus))
 		return perf_evlist__mmap_per_thread(evlist, prot, mask);
 
 	return perf_evlist__mmap_per_cpu(evlist, prot, mask);
@@ -650,20 +781,66 @@
 
 bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
 {
-	struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
+	struct perf_evsel *pos;
 
-	list_for_each_entry_continue(pos, &evlist->entries, node) {
-		if (first->attr.sample_type != pos->attr.sample_type)
+	if (evlist->nr_entries == 1)
+		return true;
+
+	if (evlist->id_pos < 0 || evlist->is_pos < 0)
+		return false;
+
+	list_for_each_entry(pos, &evlist->entries, node) {
+		if (pos->id_pos != evlist->id_pos ||
+		    pos->is_pos != evlist->is_pos)
 			return false;
 	}
 
 	return true;
 }
 
-u64 perf_evlist__sample_type(struct perf_evlist *evlist)
+u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	if (evlist->combined_sample_type)
+		return evlist->combined_sample_type;
+
+	list_for_each_entry(evsel, &evlist->entries, node)
+		evlist->combined_sample_type |= evsel->attr.sample_type;
+
+	return evlist->combined_sample_type;
+}
+
+u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist)
+{
+	evlist->combined_sample_type = 0;
+	return __perf_evlist__combined_sample_type(evlist);
+}
+
+bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
+{
+	struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
+	u64 read_format = first->attr.read_format;
+	u64 sample_type = first->attr.sample_type;
+
+	list_for_each_entry_continue(pos, &evlist->entries, node) {
+		if (read_format != pos->attr.read_format)
+			return false;
+	}
+
+	/* PERF_SAMPLE_READ imples PERF_FORMAT_ID. */
+	if ((sample_type & PERF_SAMPLE_READ) &&
+	    !(read_format & PERF_FORMAT_ID)) {
+		return false;
+	}
+
+	return true;
+}
+
+u64 perf_evlist__read_format(struct perf_evlist *evlist)
 {
 	struct perf_evsel *first = perf_evlist__first(evlist);
-	return first->attr.sample_type;
+	return first->attr.read_format;
 }
 
 u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
@@ -692,6 +869,9 @@
 
 	if (sample_type & PERF_SAMPLE_CPU)
 		size += sizeof(data->cpu) * 2;
+
+	if (sample_type & PERF_SAMPLE_IDENTIFIER)
+		size += sizeof(data->id);
 out:
 	return size;
 }
@@ -783,13 +963,6 @@
 		fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
 
 		/*
-		 * Do a dummy execvp to get the PLT entry resolved,
-		 * so we avoid the resolver overhead on the real
-		 * execvp call.
-		 */
-		execvp("", (char **)argv);
-
-		/*
 		 * Tell the parent we're ready to go
 		 */
 		close(child_ready_pipe[1]);
@@ -838,7 +1011,7 @@
 int perf_evlist__start_workload(struct perf_evlist *evlist)
 {
 	if (evlist->workload.cork_fd > 0) {
-		char bf;
+		char bf = 0;
 		int ret;
 		/*
 		 * Remove the cork, let it rip!
@@ -857,7 +1030,10 @@
 int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
 			      struct perf_sample *sample)
 {
-	struct perf_evsel *evsel = perf_evlist__first(evlist);
+	struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
+
+	if (!evsel)
+		return -EFAULT;
 	return perf_evsel__parse_sample(evsel, event, sample);
 }
 
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0583d36..880d713 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -32,6 +32,9 @@
 	int		 nr_fds;
 	int		 nr_mmaps;
 	int		 mmap_len;
+	int		 id_pos;
+	int		 is_pos;
+	u64		 combined_sample_type;
 	struct {
 		int	cork_fd;
 		pid_t	pid;
@@ -71,6 +74,10 @@
 struct perf_evsel *
 perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
 
+struct perf_evsel *
+perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
+				     const char *name);
+
 void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
 			 int cpu, int thread, u64 id);
 
@@ -78,11 +85,15 @@
 
 struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
 
+struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
+
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
 int perf_evlist__open(struct perf_evlist *evlist);
 void perf_evlist__close(struct perf_evlist *evlist);
 
+void perf_evlist__set_id_pos(struct perf_evlist *evlist);
+bool perf_can_sample_identifier(void);
 void perf_evlist__config(struct perf_evlist *evlist,
 			 struct perf_record_opts *opts);
 
@@ -99,6 +110,11 @@
 void perf_evlist__disable(struct perf_evlist *evlist);
 void perf_evlist__enable(struct perf_evlist *evlist);
 
+int perf_evlist__disable_event(struct perf_evlist *evlist,
+			       struct perf_evsel *evsel);
+int perf_evlist__enable_event(struct perf_evlist *evlist,
+			      struct perf_evsel *evsel);
+
 void perf_evlist__set_selected(struct perf_evlist *evlist,
 			       struct perf_evsel *evsel);
 
@@ -118,7 +134,9 @@
 void __perf_evlist__set_leader(struct list_head *list);
 void perf_evlist__set_leader(struct perf_evlist *evlist);
 
-u64 perf_evlist__sample_type(struct perf_evlist *evlist);
+u64 perf_evlist__read_format(struct perf_evlist *evlist);
+u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist);
+u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist);
 bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
 u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
 
@@ -127,6 +145,7 @@
 
 bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
+bool perf_evlist__valid_read_format(struct perf_evlist *evlist);
 
 void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
 				   struct list_head *list,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index c9c7494..3612183 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -9,18 +9,20 @@
 
 #include <byteswap.h>
 #include <linux/bitops.h>
-#include "asm/bug.h"
 #include <lk/debugfs.h>
-#include "event-parse.h"
+#include <traceevent/event-parse.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
+#include <sys/resource.h>
+#include "asm/bug.h"
 #include "evsel.h"
 #include "evlist.h"
 #include "util.h"
 #include "cpumap.h"
 #include "thread_map.h"
 #include "target.h"
-#include <linux/hw_breakpoint.h>
-#include <linux/perf_event.h>
 #include "perf_regs.h"
+#include "debug.h"
 
 static struct {
 	bool sample_id_all;
@@ -29,7 +31,7 @@
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
-static int __perf_evsel__sample_size(u64 sample_type)
+int __perf_evsel__sample_size(u64 sample_type)
 {
 	u64 mask = sample_type & PERF_SAMPLE_MASK;
 	int size = 0;
@@ -45,6 +47,72 @@
 	return size;
 }
 
+/**
+ * __perf_evsel__calc_id_pos - calculate id_pos.
+ * @sample_type: sample type
+ *
+ * This function returns the position of the event id (PERF_SAMPLE_ID or
+ * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct
+ * sample_event.
+ */
+static int __perf_evsel__calc_id_pos(u64 sample_type)
+{
+	int idx = 0;
+
+	if (sample_type & PERF_SAMPLE_IDENTIFIER)
+		return 0;
+
+	if (!(sample_type & PERF_SAMPLE_ID))
+		return -1;
+
+	if (sample_type & PERF_SAMPLE_IP)
+		idx += 1;
+
+	if (sample_type & PERF_SAMPLE_TID)
+		idx += 1;
+
+	if (sample_type & PERF_SAMPLE_TIME)
+		idx += 1;
+
+	if (sample_type & PERF_SAMPLE_ADDR)
+		idx += 1;
+
+	return idx;
+}
+
+/**
+ * __perf_evsel__calc_is_pos - calculate is_pos.
+ * @sample_type: sample type
+ *
+ * This function returns the position (counting backwards) of the event id
+ * (PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if
+ * sample_id_all is used there is an id sample appended to non-sample events.
+ */
+static int __perf_evsel__calc_is_pos(u64 sample_type)
+{
+	int idx = 1;
+
+	if (sample_type & PERF_SAMPLE_IDENTIFIER)
+		return 1;
+
+	if (!(sample_type & PERF_SAMPLE_ID))
+		return -1;
+
+	if (sample_type & PERF_SAMPLE_CPU)
+		idx += 1;
+
+	if (sample_type & PERF_SAMPLE_STREAM_ID)
+		idx += 1;
+
+	return idx;
+}
+
+void perf_evsel__calc_id_pos(struct perf_evsel *evsel)
+{
+	evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type);
+	evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type);
+}
+
 void hists__init(struct hists *hists)
 {
 	memset(hists, 0, sizeof(*hists));
@@ -61,6 +129,7 @@
 	if (!(evsel->attr.sample_type & bit)) {
 		evsel->attr.sample_type |= bit;
 		evsel->sample_size += sizeof(u64);
+		perf_evsel__calc_id_pos(evsel);
 	}
 }
 
@@ -70,12 +139,19 @@
 	if (evsel->attr.sample_type & bit) {
 		evsel->attr.sample_type &= ~bit;
 		evsel->sample_size -= sizeof(u64);
+		perf_evsel__calc_id_pos(evsel);
 	}
 }
 
-void perf_evsel__set_sample_id(struct perf_evsel *evsel)
+void perf_evsel__set_sample_id(struct perf_evsel *evsel,
+			       bool can_sample_identifier)
 {
-	perf_evsel__set_sample_bit(evsel, ID);
+	if (can_sample_identifier) {
+		perf_evsel__reset_sample_bit(evsel, ID);
+		perf_evsel__set_sample_bit(evsel, IDENTIFIER);
+	} else {
+		perf_evsel__set_sample_bit(evsel, ID);
+	}
 	evsel->attr.read_format |= PERF_FORMAT_ID;
 }
 
@@ -88,6 +164,7 @@
 	INIT_LIST_HEAD(&evsel->node);
 	hists__init(&evsel->hists);
 	evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
+	perf_evsel__calc_id_pos(evsel);
 }
 
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -246,6 +323,7 @@
 	"major-faults",
 	"alignment-faults",
 	"emulation-faults",
+	"dummy",
 };
 
 static const char *__perf_evsel__sw_name(u64 config)
@@ -490,6 +568,7 @@
 void perf_evsel__config(struct perf_evsel *evsel,
 			struct perf_record_opts *opts)
 {
+	struct perf_evsel *leader = evsel->leader;
 	struct perf_event_attr *attr = &evsel->attr;
 	int track = !evsel->idx; /* only the first counter needs these */
 
@@ -499,6 +578,25 @@
 	perf_evsel__set_sample_bit(evsel, IP);
 	perf_evsel__set_sample_bit(evsel, TID);
 
+	if (evsel->sample_read) {
+		perf_evsel__set_sample_bit(evsel, READ);
+
+		/*
+		 * We need ID even in case of single event, because
+		 * PERF_SAMPLE_READ process ID specific data.
+		 */
+		perf_evsel__set_sample_id(evsel, false);
+
+		/*
+		 * Apply group format only if we belong to group
+		 * with more than one members.
+		 */
+		if (leader->nr_members > 1) {
+			attr->read_format |= PERF_FORMAT_GROUP;
+			attr->inherit = 0;
+		}
+	}
+
 	/*
 	 * We default some events to a 1 default interval. But keep
 	 * it a weak assumption overridable by the user.
@@ -514,6 +612,15 @@
 		}
 	}
 
+	/*
+	 * Disable sampling for all group members other
+	 * than leader in case leader 'leads' the sampling.
+	 */
+	if ((leader != evsel) && leader->sample_read) {
+		attr->sample_freq   = 0;
+		attr->sample_period = 0;
+	}
+
 	if (opts->no_samples)
 		attr->sample_freq = 0;
 
@@ -605,15 +712,15 @@
 	return evsel->fd != NULL ? 0 : -ENOMEM;
 }
 
-int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
-			   const char *filter)
+static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthreads,
+			  int ioc,  void *arg)
 {
 	int cpu, thread;
 
 	for (cpu = 0; cpu < ncpus; cpu++) {
 		for (thread = 0; thread < nthreads; thread++) {
 			int fd = FD(evsel, cpu, thread),
-			    err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
+			    err = ioctl(fd, ioc, arg);
 
 			if (err)
 				return err;
@@ -623,6 +730,21 @@
 	return 0;
 }
 
+int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
+			   const char *filter)
+{
+	return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+				     PERF_EVENT_IOC_SET_FILTER,
+				     (void *)filter);
+}
+
+int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
+{
+	return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+				     PERF_EVENT_IOC_ENABLE,
+				     0);
+}
+
 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
 	evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
@@ -817,12 +939,72 @@
 	return fd;
 }
 
+#define __PRINT_ATTR(fmt, cast, field)  \
+	fprintf(fp, "  %-19s "fmt"\n", #field, cast attr->field)
+
+#define PRINT_ATTR_U32(field)  __PRINT_ATTR("%u" , , field)
+#define PRINT_ATTR_X32(field)  __PRINT_ATTR("%#x", , field)
+#define PRINT_ATTR_U64(field)  __PRINT_ATTR("%" PRIu64, (uint64_t), field)
+#define PRINT_ATTR_X64(field)  __PRINT_ATTR("%#"PRIx64, (uint64_t), field)
+
+#define PRINT_ATTR2N(name1, field1, name2, field2)	\
+	fprintf(fp, "  %-19s %u    %-19s %u\n",		\
+	name1, attr->field1, name2, attr->field2)
+
+#define PRINT_ATTR2(field1, field2) \
+	PRINT_ATTR2N(#field1, field1, #field2, field2)
+
+static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
+{
+	size_t ret = 0;
+
+	ret += fprintf(fp, "%.60s\n", graph_dotted_line);
+	ret += fprintf(fp, "perf_event_attr:\n");
+
+	ret += PRINT_ATTR_U32(type);
+	ret += PRINT_ATTR_U32(size);
+	ret += PRINT_ATTR_X64(config);
+	ret += PRINT_ATTR_U64(sample_period);
+	ret += PRINT_ATTR_U64(sample_freq);
+	ret += PRINT_ATTR_X64(sample_type);
+	ret += PRINT_ATTR_X64(read_format);
+
+	ret += PRINT_ATTR2(disabled, inherit);
+	ret += PRINT_ATTR2(pinned, exclusive);
+	ret += PRINT_ATTR2(exclude_user, exclude_kernel);
+	ret += PRINT_ATTR2(exclude_hv, exclude_idle);
+	ret += PRINT_ATTR2(mmap, comm);
+	ret += PRINT_ATTR2(freq, inherit_stat);
+	ret += PRINT_ATTR2(enable_on_exec, task);
+	ret += PRINT_ATTR2(watermark, precise_ip);
+	ret += PRINT_ATTR2(mmap_data, sample_id_all);
+	ret += PRINT_ATTR2(exclude_host, exclude_guest);
+	ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
+			    "excl.callchain_user", exclude_callchain_user);
+
+	ret += PRINT_ATTR_U32(wakeup_events);
+	ret += PRINT_ATTR_U32(wakeup_watermark);
+	ret += PRINT_ATTR_X32(bp_type);
+	ret += PRINT_ATTR_X64(bp_addr);
+	ret += PRINT_ATTR_X64(config1);
+	ret += PRINT_ATTR_U64(bp_len);
+	ret += PRINT_ATTR_X64(config2);
+	ret += PRINT_ATTR_X64(branch_sample_type);
+	ret += PRINT_ATTR_X64(sample_regs_user);
+	ret += PRINT_ATTR_U32(sample_stack_user);
+
+	ret += fprintf(fp, "%.60s\n", graph_dotted_line);
+
+	return ret;
+}
+
 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
 			      struct thread_map *threads)
 {
 	int cpu, thread;
 	unsigned long flags = 0;
 	int pid = -1, err;
+	enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
 
 	if (evsel->fd == NULL &&
 	    perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
@@ -840,6 +1022,9 @@
 	if (perf_missing_features.sample_id_all)
 		evsel->attr.sample_id_all = 0;
 
+	if (verbose >= 2)
+		perf_event_attr__fprintf(&evsel->attr, stderr);
+
 	for (cpu = 0; cpu < cpus->nr; cpu++) {
 
 		for (thread = 0; thread < threads->nr; thread++) {
@@ -849,6 +1034,9 @@
 				pid = threads->map[thread];
 
 			group_fd = get_group_fd(evsel, cpu, thread);
+retry_open:
+			pr_debug2("perf_event_open: pid %d  cpu %d  group_fd %d  flags %#lx\n",
+				  pid, cpus->map[cpu], group_fd, flags);
 
 			FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
 								     pid,
@@ -858,12 +1046,37 @@
 				err = -errno;
 				goto try_fallback;
 			}
+			set_rlimit = NO_CHANGE;
 		}
 	}
 
 	return 0;
 
 try_fallback:
+	/*
+	 * perf stat needs between 5 and 22 fds per CPU. When we run out
+	 * of them try to increase the limits.
+	 */
+	if (err == -EMFILE && set_rlimit < INCREASED_MAX) {
+		struct rlimit l;
+		int old_errno = errno;
+
+		if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
+			if (set_rlimit == NO_CHANGE)
+				l.rlim_cur = l.rlim_max;
+			else {
+				l.rlim_cur = l.rlim_max + 1000;
+				l.rlim_max = l.rlim_cur;
+			}
+			if (setrlimit(RLIMIT_NOFILE, &l) == 0) {
+				set_rlimit++;
+				errno = old_errno;
+				goto retry_open;
+			}
+		}
+		errno = old_errno;
+	}
+
 	if (err != -EINVAL || cpu > 0 || thread > 0)
 		goto out_close;
 
@@ -951,6 +1164,11 @@
 	array += ((event->header.size -
 		   sizeof(event->header)) / sizeof(u64)) - 1;
 
+	if (type & PERF_SAMPLE_IDENTIFIER) {
+		sample->id = *array;
+		array--;
+	}
+
 	if (type & PERF_SAMPLE_CPU) {
 		u.val64 = *array;
 		if (swapped) {
@@ -994,24 +1212,30 @@
 	return 0;
 }
 
-static bool sample_overlap(const union perf_event *event,
-			   const void *offset, u64 size)
+static inline bool overflow(const void *endp, u16 max_size, const void *offset,
+			    u64 size)
 {
-	const void *base = event;
-
-	if (offset + size > base + event->header.size)
-		return true;
-
-	return false;
+	return size > max_size || offset + size > endp;
 }
 
+#define OVERFLOW_CHECK(offset, size, max_size)				\
+	do {								\
+		if (overflow(endp, (max_size), (offset), (size)))	\
+			return -EFAULT;					\
+	} while (0)
+
+#define OVERFLOW_CHECK_u64(offset) \
+	OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64))
+
 int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
 			     struct perf_sample *data)
 {
 	u64 type = evsel->attr.sample_type;
-	u64 regs_user = evsel->attr.sample_regs_user;
 	bool swapped = evsel->needs_swap;
 	const u64 *array;
+	u16 max_size = event->header.size;
+	const void *endp = (void *)event + max_size;
+	u64 sz;
 
 	/*
 	 * used for cross-endian analysis. See git commit 65014ab3
@@ -1033,11 +1257,22 @@
 
 	array = event->sample.array;
 
+	/*
+	 * The evsel's sample_size is based on PERF_SAMPLE_MASK which includes
+	 * up to PERF_SAMPLE_PERIOD.  After that overflow() must be used to
+	 * check the format does not go past the end of the event.
+	 */
 	if (evsel->sample_size + sizeof(event->header) > event->header.size)
 		return -EFAULT;
 
+	data->id = -1ULL;
+	if (type & PERF_SAMPLE_IDENTIFIER) {
+		data->id = *array;
+		array++;
+	}
+
 	if (type & PERF_SAMPLE_IP) {
-		data->ip = event->ip.ip;
+		data->ip = *array;
 		array++;
 	}
 
@@ -1066,7 +1301,6 @@
 		array++;
 	}
 
-	data->id = -1ULL;
 	if (type & PERF_SAMPLE_ID) {
 		data->id = *array;
 		array++;
@@ -1096,25 +1330,62 @@
 	}
 
 	if (type & PERF_SAMPLE_READ) {
-		fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n");
-		return -1;
+		u64 read_format = evsel->attr.read_format;
+
+		OVERFLOW_CHECK_u64(array);
+		if (read_format & PERF_FORMAT_GROUP)
+			data->read.group.nr = *array;
+		else
+			data->read.one.value = *array;
+
+		array++;
+
+		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
+			OVERFLOW_CHECK_u64(array);
+			data->read.time_enabled = *array;
+			array++;
+		}
+
+		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
+			OVERFLOW_CHECK_u64(array);
+			data->read.time_running = *array;
+			array++;
+		}
+
+		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
+		if (read_format & PERF_FORMAT_GROUP) {
+			const u64 max_group_nr = UINT64_MAX /
+					sizeof(struct sample_read_value);
+
+			if (data->read.group.nr > max_group_nr)
+				return -EFAULT;
+			sz = data->read.group.nr *
+			     sizeof(struct sample_read_value);
+			OVERFLOW_CHECK(array, sz, max_size);
+			data->read.group.values =
+					(struct sample_read_value *)array;
+			array = (void *)array + sz;
+		} else {
+			OVERFLOW_CHECK_u64(array);
+			data->read.one.id = *array;
+			array++;
+		}
 	}
 
 	if (type & PERF_SAMPLE_CALLCHAIN) {
-		if (sample_overlap(event, array, sizeof(data->callchain->nr)))
+		const u64 max_callchain_nr = UINT64_MAX / sizeof(u64);
+
+		OVERFLOW_CHECK_u64(array);
+		data->callchain = (struct ip_callchain *)array++;
+		if (data->callchain->nr > max_callchain_nr)
 			return -EFAULT;
-
-		data->callchain = (struct ip_callchain *)array;
-
-		if (sample_overlap(event, array, data->callchain->nr))
-			return -EFAULT;
-
-		array += 1 + data->callchain->nr;
+		sz = data->callchain->nr * sizeof(u64);
+		OVERFLOW_CHECK(array, sz, max_size);
+		array = (void *)array + sz;
 	}
 
 	if (type & PERF_SAMPLE_RAW) {
-		const u64 *pdata;
-
+		OVERFLOW_CHECK_u64(array);
 		u.val64 = *array;
 		if (WARN_ONCE(swapped,
 			      "Endianness of raw data not corrected!\n")) {
@@ -1123,65 +1394,71 @@
 			u.val32[0] = bswap_32(u.val32[0]);
 			u.val32[1] = bswap_32(u.val32[1]);
 		}
-
-		if (sample_overlap(event, array, sizeof(u32)))
-			return -EFAULT;
-
 		data->raw_size = u.val32[0];
-		pdata = (void *) array + sizeof(u32);
+		array = (void *)array + sizeof(u32);
 
-		if (sample_overlap(event, pdata, data->raw_size))
-			return -EFAULT;
-
-		data->raw_data = (void *) pdata;
-
-		array = (void *)array + data->raw_size + sizeof(u32);
+		OVERFLOW_CHECK(array, data->raw_size, max_size);
+		data->raw_data = (void *)array;
+		array = (void *)array + data->raw_size;
 	}
 
 	if (type & PERF_SAMPLE_BRANCH_STACK) {
-		u64 sz;
+		const u64 max_branch_nr = UINT64_MAX /
+					  sizeof(struct branch_entry);
 
-		data->branch_stack = (struct branch_stack *)array;
-		array++; /* nr */
+		OVERFLOW_CHECK_u64(array);
+		data->branch_stack = (struct branch_stack *)array++;
 
+		if (data->branch_stack->nr > max_branch_nr)
+			return -EFAULT;
 		sz = data->branch_stack->nr * sizeof(struct branch_entry);
-		sz /= sizeof(u64);
-		array += sz;
+		OVERFLOW_CHECK(array, sz, max_size);
+		array = (void *)array + sz;
 	}
 
 	if (type & PERF_SAMPLE_REGS_USER) {
-		/* First u64 tells us if we have any regs in sample. */
-		u64 avail = *array++;
+		OVERFLOW_CHECK_u64(array);
+		data->user_regs.abi = *array;
+		array++;
 
-		if (avail) {
+		if (data->user_regs.abi) {
+			u64 regs_user = evsel->attr.sample_regs_user;
+
+			sz = hweight_long(regs_user) * sizeof(u64);
+			OVERFLOW_CHECK(array, sz, max_size);
 			data->user_regs.regs = (u64 *)array;
-			array += hweight_long(regs_user);
+			array = (void *)array + sz;
 		}
 	}
 
 	if (type & PERF_SAMPLE_STACK_USER) {
-		u64 size = *array++;
+		OVERFLOW_CHECK_u64(array);
+		sz = *array++;
 
 		data->user_stack.offset = ((char *)(array - 1)
 					  - (char *) event);
 
-		if (!size) {
+		if (!sz) {
 			data->user_stack.size = 0;
 		} else {
+			OVERFLOW_CHECK(array, sz, max_size);
 			data->user_stack.data = (char *)array;
-			array += size / sizeof(*array);
+			array = (void *)array + sz;
+			OVERFLOW_CHECK_u64(array);
 			data->user_stack.size = *array++;
 		}
 	}
 
 	data->weight = 0;
 	if (type & PERF_SAMPLE_WEIGHT) {
+		OVERFLOW_CHECK_u64(array);
 		data->weight = *array;
 		array++;
 	}
 
 	data->data_src = PERF_MEM_DATA_SRC_NONE;
 	if (type & PERF_SAMPLE_DATA_SRC) {
+		OVERFLOW_CHECK_u64(array);
 		data->data_src = *array;
 		array++;
 	}
@@ -1189,12 +1466,105 @@
 	return 0;
 }
 
+size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
+				     u64 sample_regs_user, u64 read_format)
+{
+	size_t sz, result = sizeof(struct sample_event);
+
+	if (type & PERF_SAMPLE_IDENTIFIER)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_IP)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_TID)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_TIME)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_ADDR)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_ID)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_STREAM_ID)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_CPU)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_PERIOD)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_READ) {
+		result += sizeof(u64);
+		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+			result += sizeof(u64);
+		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+			result += sizeof(u64);
+		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
+		if (read_format & PERF_FORMAT_GROUP) {
+			sz = sample->read.group.nr *
+			     sizeof(struct sample_read_value);
+			result += sz;
+		} else {
+			result += sizeof(u64);
+		}
+	}
+
+	if (type & PERF_SAMPLE_CALLCHAIN) {
+		sz = (sample->callchain->nr + 1) * sizeof(u64);
+		result += sz;
+	}
+
+	if (type & PERF_SAMPLE_RAW) {
+		result += sizeof(u32);
+		result += sample->raw_size;
+	}
+
+	if (type & PERF_SAMPLE_BRANCH_STACK) {
+		sz = sample->branch_stack->nr * sizeof(struct branch_entry);
+		sz += sizeof(u64);
+		result += sz;
+	}
+
+	if (type & PERF_SAMPLE_REGS_USER) {
+		if (sample->user_regs.abi) {
+			result += sizeof(u64);
+			sz = hweight_long(sample_regs_user) * sizeof(u64);
+			result += sz;
+		} else {
+			result += sizeof(u64);
+		}
+	}
+
+	if (type & PERF_SAMPLE_STACK_USER) {
+		sz = sample->user_stack.size;
+		result += sizeof(u64);
+		if (sz) {
+			result += sz;
+			result += sizeof(u64);
+		}
+	}
+
+	if (type & PERF_SAMPLE_WEIGHT)
+		result += sizeof(u64);
+
+	if (type & PERF_SAMPLE_DATA_SRC)
+		result += sizeof(u64);
+
+	return result;
+}
+
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
+				  u64 sample_regs_user, u64 read_format,
 				  const struct perf_sample *sample,
 				  bool swapped)
 {
 	u64 *array;
-
+	size_t sz;
 	/*
 	 * used for cross-endian analysis. See git commit 65014ab3
 	 * for why this goofiness is needed.
@@ -1203,8 +1573,13 @@
 
 	array = event->sample.array;
 
+	if (type & PERF_SAMPLE_IDENTIFIER) {
+		*array = sample->id;
+		array++;
+	}
+
 	if (type & PERF_SAMPLE_IP) {
-		event->ip.ip = sample->ip;
+		*array = sample->ip;
 		array++;
 	}
 
@@ -1262,6 +1637,97 @@
 		array++;
 	}
 
+	if (type & PERF_SAMPLE_READ) {
+		if (read_format & PERF_FORMAT_GROUP)
+			*array = sample->read.group.nr;
+		else
+			*array = sample->read.one.value;
+		array++;
+
+		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
+			*array = sample->read.time_enabled;
+			array++;
+		}
+
+		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
+			*array = sample->read.time_running;
+			array++;
+		}
+
+		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
+		if (read_format & PERF_FORMAT_GROUP) {
+			sz = sample->read.group.nr *
+			     sizeof(struct sample_read_value);
+			memcpy(array, sample->read.group.values, sz);
+			array = (void *)array + sz;
+		} else {
+			*array = sample->read.one.id;
+			array++;
+		}
+	}
+
+	if (type & PERF_SAMPLE_CALLCHAIN) {
+		sz = (sample->callchain->nr + 1) * sizeof(u64);
+		memcpy(array, sample->callchain, sz);
+		array = (void *)array + sz;
+	}
+
+	if (type & PERF_SAMPLE_RAW) {
+		u.val32[0] = sample->raw_size;
+		if (WARN_ONCE(swapped,
+			      "Endianness of raw data not corrected!\n")) {
+			/*
+			 * Inverse of what is done in perf_evsel__parse_sample
+			 */
+			u.val32[0] = bswap_32(u.val32[0]);
+			u.val32[1] = bswap_32(u.val32[1]);
+			u.val64 = bswap_64(u.val64);
+		}
+		*array = u.val64;
+		array = (void *)array + sizeof(u32);
+
+		memcpy(array, sample->raw_data, sample->raw_size);
+		array = (void *)array + sample->raw_size;
+	}
+
+	if (type & PERF_SAMPLE_BRANCH_STACK) {
+		sz = sample->branch_stack->nr * sizeof(struct branch_entry);
+		sz += sizeof(u64);
+		memcpy(array, sample->branch_stack, sz);
+		array = (void *)array + sz;
+	}
+
+	if (type & PERF_SAMPLE_REGS_USER) {
+		if (sample->user_regs.abi) {
+			*array++ = sample->user_regs.abi;
+			sz = hweight_long(sample_regs_user) * sizeof(u64);
+			memcpy(array, sample->user_regs.regs, sz);
+			array = (void *)array + sz;
+		} else {
+			*array++ = 0;
+		}
+	}
+
+	if (type & PERF_SAMPLE_STACK_USER) {
+		sz = sample->user_stack.size;
+		*array++ = sz;
+		if (sz) {
+			memcpy(array, sample->user_stack.data, sz);
+			array = (void *)array + sz;
+			*array++ = sz;
+		}
+	}
+
+	if (type & PERF_SAMPLE_WEIGHT) {
+		*array = sample->weight;
+		array++;
+	}
+
+	if (type & PERF_SAMPLE_DATA_SRC) {
+		*array = sample->data_src;
+		array++;
+	}
+
 	return 0;
 }
 
@@ -1391,6 +1857,7 @@
 		bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
 		bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
 		bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
+		bit_name(IDENTIFIER),
 		{ .name = NULL, }
 	};
 #undef bit_name
@@ -1482,7 +1949,7 @@
 bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
 			  char *msg, size_t msgsize)
 {
-	if ((err == ENOENT || err == ENXIO) &&
+	if ((err == ENOENT || err == ENXIO || err == ENODEV) &&
 	    evsel->attr.type   == PERF_TYPE_HARDWARE &&
 	    evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
 		/*
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3f156cc..4a7bdc7 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -38,6 +38,9 @@
 	struct hlist_node 	node;
 	u64		 	id;
 	struct perf_evsel	*evsel;
+
+	/* Holds total ID period value for PERF_SAMPLE_READ processing. */
+	u64			period;
 };
 
 /** struct perf_evsel - event selector
@@ -45,6 +48,12 @@
  * @name - Can be set to retain the original event name passed by the user,
  *         so that when showing results in tools such as 'perf stat', we
  *         show the name used, not some alias.
+ * @id_pos: the position of the event id (PERF_SAMPLE_ID or
+ *          PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of
+ *          struct sample_event
+ * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
+ *          PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
+ *          is used there is an id sample appended to non-sample events
  */
 struct perf_evsel {
 	struct list_head	node;
@@ -71,11 +80,14 @@
 	} handler;
 	struct cpu_map		*cpus;
 	unsigned int		sample_size;
+	int			id_pos;
+	int			is_pos;
 	bool 			supported;
 	bool 			needs_swap;
 	/* parse modifier helper */
 	int			exclude_GH;
 	int			nr_members;
+	int			sample_read;
 	struct perf_evsel	*leader;
 	char			*group_name;
 };
@@ -100,6 +112,9 @@
 void perf_evsel__config(struct perf_evsel *evsel,
 			struct perf_record_opts *opts);
 
+int __perf_evsel__sample_size(u64 sample_type);
+void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
+
 bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
 
 #define PERF_EVSEL__MAX_ALIASES 8
@@ -138,10 +153,12 @@
 #define perf_evsel__reset_sample_bit(evsel, bit) \
 	__perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
 
-void perf_evsel__set_sample_id(struct perf_evsel *evsel);
+void perf_evsel__set_sample_id(struct perf_evsel *evsel,
+			       bool use_sample_identifier);
 
 int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
 			   const char *filter);
+int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
 
 int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
 			     struct cpu_map *cpus);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index a4dafbe..a33197a 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -25,41 +25,9 @@
 
 static bool no_buildid_cache = false;
 
-static int trace_event_count;
-static struct perf_trace_event_type *trace_events;
-
 static u32 header_argc;
 static const char **header_argv;
 
-int perf_header__push_event(u64 id, const char *name)
-{
-	struct perf_trace_event_type *nevents;
-
-	if (strlen(name) > MAX_EVENT_NAME)
-		pr_warning("Event %s will be truncated\n", name);
-
-	nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
-	if (nevents == NULL)
-		return -ENOMEM;
-	trace_events = nevents;
-
-	memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
-	trace_events[trace_event_count].event_id = id;
-	strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
-	trace_event_count++;
-	return 0;
-}
-
-char *perf_header__find_event(u64 id)
-{
-	int i;
-	for (i = 0 ; i < trace_event_count; i++) {
-		if (trace_events[i].event_id == id)
-			return trace_events[i].name;
-	}
-	return NULL;
-}
-
 /*
  * magic2 = "PERFILE2"
  * must be a numerical value to let the endianness
@@ -748,18 +716,19 @@
 	char filename[MAXPATHLEN];
 	char *buf = NULL, *p;
 	size_t len = 0;
+	ssize_t sret;
 	u32 i = 0;
 	int ret = -1;
 
 	sprintf(filename, CORE_SIB_FMT, cpu);
 	fp = fopen(filename, "r");
 	if (!fp)
-		return -1;
+		goto try_threads;
 
-	if (getline(&buf, &len, fp) <= 0)
-		goto done;
-
+	sret = getline(&buf, &len, fp);
 	fclose(fp);
+	if (sret <= 0)
+		goto try_threads;
 
 	p = strchr(buf, '\n');
 	if (p)
@@ -775,7 +744,9 @@
 		buf = NULL;
 		len = 0;
 	}
+	ret = 0;
 
+try_threads:
 	sprintf(filename, THRD_SIB_FMT, cpu);
 	fp = fopen(filename, "r");
 	if (!fp)
@@ -2257,7 +2228,7 @@
 
 	sec_size = sizeof(*feat_sec) * nr_sections;
 
-	sec_start = header->data_offset + header->data_size;
+	sec_start = header->feat_offset;
 	lseek(fd, sec_start + sec_size, SEEK_SET);
 
 	for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
@@ -2304,6 +2275,7 @@
 	struct perf_file_attr   f_attr;
 	struct perf_header *header = &session->header;
 	struct perf_evsel *evsel;
+	u64 attr_offset;
 	int err;
 
 	lseek(fd, sizeof(f_header), SEEK_SET);
@@ -2317,7 +2289,7 @@
 		}
 	}
 
-	header->attr_offset = lseek(fd, 0, SEEK_CUR);
+	attr_offset = lseek(fd, 0, SEEK_CUR);
 
 	list_for_each_entry(evsel, &evlist->entries, node) {
 		f_attr = (struct perf_file_attr){
@@ -2334,17 +2306,8 @@
 		}
 	}
 
-	header->event_offset = lseek(fd, 0, SEEK_CUR);
-	header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
-	if (trace_events) {
-		err = do_write(fd, trace_events, header->event_size);
-		if (err < 0) {
-			pr_debug("failed to write perf header events\n");
-			return err;
-		}
-	}
-
 	header->data_offset = lseek(fd, 0, SEEK_CUR);
+	header->feat_offset = header->data_offset + header->data_size;
 
 	if (at_exit) {
 		err = perf_header__adds_write(header, evlist, fd);
@@ -2357,17 +2320,14 @@
 		.size	   = sizeof(f_header),
 		.attr_size = sizeof(f_attr),
 		.attrs = {
-			.offset = header->attr_offset,
+			.offset = attr_offset,
 			.size   = evlist->nr_entries * sizeof(f_attr),
 		},
 		.data = {
 			.offset = header->data_offset,
 			.size	= header->data_size,
 		},
-		.event_types = {
-			.offset = header->event_offset,
-			.size	= header->event_size,
-		},
+		/* event_types is ignored, store zeros */
 	};
 
 	memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
@@ -2417,7 +2377,7 @@
 
 	sec_size = sizeof(*feat_sec) * nr_sections;
 
-	lseek(fd, header->data_offset + header->data_size, SEEK_SET);
+	lseek(fd, header->feat_offset, SEEK_SET);
 
 	err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
 	if (err < 0)
@@ -2523,6 +2483,7 @@
 	/* check for legacy format */
 	ret = memcmp(&magic, __perf_magic1, sizeof(magic));
 	if (ret == 0) {
+		ph->version = PERF_HEADER_VERSION_1;
 		pr_debug("legacy perf.data format\n");
 		if (is_pipe)
 			return try_all_pipe_abis(hdr_sz, ph);
@@ -2544,6 +2505,7 @@
 		return -1;
 
 	ph->needs_swap = true;
+	ph->version = PERF_HEADER_VERSION_2;
 
 	return 0;
 }
@@ -2614,10 +2576,9 @@
 	memcpy(&ph->adds_features, &header->adds_features,
 	       sizeof(ph->adds_features));
 
-	ph->event_offset = header->event_types.offset;
-	ph->event_size   = header->event_types.size;
 	ph->data_offset  = header->data.offset;
 	ph->data_size	 = header->data.size;
+	ph->feat_offset  = header->data.offset + header->data.size;
 	return 0;
 }
 
@@ -2666,19 +2627,17 @@
 	return 0;
 }
 
-static int perf_header__read_pipe(struct perf_session *session, int fd)
+static int perf_header__read_pipe(struct perf_session *session)
 {
 	struct perf_header *header = &session->header;
 	struct perf_pipe_file_header f_header;
 
-	if (perf_file_header__read_pipe(&f_header, header, fd,
+	if (perf_file_header__read_pipe(&f_header, header, session->fd,
 					session->repipe) < 0) {
 		pr_debug("incompatible file format\n");
 		return -EINVAL;
 	}
 
-	session->fd = fd;
-
 	return 0;
 }
 
@@ -2772,20 +2731,21 @@
 	return 0;
 }
 
-int perf_session__read_header(struct perf_session *session, int fd)
+int perf_session__read_header(struct perf_session *session)
 {
 	struct perf_header *header = &session->header;
 	struct perf_file_header	f_header;
 	struct perf_file_attr	f_attr;
 	u64			f_id;
 	int nr_attrs, nr_ids, i, j;
+	int fd = session->fd;
 
 	session->evlist = perf_evlist__new();
 	if (session->evlist == NULL)
 		return -ENOMEM;
 
 	if (session->fd_pipe)
-		return perf_header__read_pipe(session, fd);
+		return perf_header__read_pipe(session);
 
 	if (perf_file_header__read(&f_header, header, fd) < 0)
 		return -EINVAL;
@@ -2839,22 +2799,9 @@
 
 	symbol_conf.nr_events = nr_attrs;
 
-	if (f_header.event_types.size) {
-		lseek(fd, f_header.event_types.offset, SEEK_SET);
-		trace_events = malloc(f_header.event_types.size);
-		if (trace_events == NULL)
-			return -ENOMEM;
-		if (perf_header__getbuffer64(header, fd, trace_events,
-					     f_header.event_types.size))
-			goto out_errno;
-		trace_event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
-	}
-
 	perf_header__process_sections(header, fd, &session->pevent,
 				      perf_file_section__process);
 
-	lseek(fd, header->data_offset, SEEK_SET);
-
 	if (perf_evlist__prepare_tracepoint_events(session->evlist,
 						   session->pevent))
 		goto out_delete_evlist;
@@ -2922,7 +2869,8 @@
 	return err;
 }
 
-int perf_event__process_attr(union perf_event *event,
+int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
+			     union perf_event *event,
 			     struct perf_evlist **pevlist)
 {
 	u32 i, ids, n_ids;
@@ -2961,64 +2909,6 @@
 	return 0;
 }
 
-int perf_event__synthesize_event_type(struct perf_tool *tool,
-				      u64 event_id, char *name,
-				      perf_event__handler_t process,
-				      struct machine *machine)
-{
-	union perf_event ev;
-	size_t size = 0;
-	int err = 0;
-
-	memset(&ev, 0, sizeof(ev));
-
-	ev.event_type.event_type.event_id = event_id;
-	memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
-	strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
-
-	ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
-	size = strlen(ev.event_type.event_type.name);
-	size = PERF_ALIGN(size, sizeof(u64));
-	ev.event_type.header.size = sizeof(ev.event_type) -
-		(sizeof(ev.event_type.event_type.name) - size);
-
-	err = process(tool, &ev, NULL, machine);
-
-	return err;
-}
-
-int perf_event__synthesize_event_types(struct perf_tool *tool,
-				       perf_event__handler_t process,
-				       struct machine *machine)
-{
-	struct perf_trace_event_type *type;
-	int i, err = 0;
-
-	for (i = 0; i < trace_event_count; i++) {
-		type = &trace_events[i];
-
-		err = perf_event__synthesize_event_type(tool, type->event_id,
-							type->name, process,
-							machine);
-		if (err) {
-			pr_debug("failed to create perf header event type\n");
-			return err;
-		}
-	}
-
-	return err;
-}
-
-int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
-				   union perf_event *event)
-{
-	if (perf_header__push_event(event->event_type.event_type.event_id,
-				    event->event_type.event_type.name) < 0)
-		return -ENOMEM;
-
-	return 0;
-}
-
 int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
 					struct perf_evlist *evlist,
 					perf_event__handler_t process)
@@ -3065,7 +2955,8 @@
 	return aligned_size;
 }
 
-int perf_event__process_tracing_data(union perf_event *event,
+int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
+				     union perf_event *event,
 				     struct perf_session *session)
 {
 	ssize_t size_read, padding, size = event->tracing_data.size;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 16a3e83..307c9ae 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -34,6 +34,11 @@
 	HEADER_FEAT_BITS	= 256,
 };
 
+enum perf_header_version {
+	PERF_HEADER_VERSION_1,
+	PERF_HEADER_VERSION_2,
+};
+
 struct perf_file_section {
 	u64 offset;
 	u64 size;
@@ -45,6 +50,7 @@
 	u64				attr_size;
 	struct perf_file_section	attrs;
 	struct perf_file_section	data;
+	/* event_types is ignored */
 	struct perf_file_section	event_types;
 	DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
 };
@@ -84,28 +90,24 @@
 };
 
 struct perf_header {
-	bool			needs_swap;
-	s64			attr_offset;
-	u64			data_offset;
-	u64			data_size;
-	u64			event_offset;
-	u64			event_size;
+	enum perf_header_version	version;
+	bool				needs_swap;
+	u64				data_offset;
+	u64				data_size;
+	u64				feat_offset;
 	DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
-	struct perf_session_env env;
+	struct perf_session_env 	env;
 };
 
 struct perf_evlist;
 struct perf_session;
 
-int perf_session__read_header(struct perf_session *session, int fd);
+int perf_session__read_header(struct perf_session *session);
 int perf_session__write_header(struct perf_session *session,
 			       struct perf_evlist *evlist,
 			       int fd, bool at_exit);
 int perf_header__write_pipe(int fd);
 
-int perf_header__push_event(u64 id, const char *name);
-char *perf_header__find_event(u64 id);
-
 void perf_header__set_feat(struct perf_header *header, int feat);
 void perf_header__clear_feat(struct perf_header *header, int feat);
 bool perf_header__has_feat(const struct perf_header *header, int feat);
@@ -130,22 +132,14 @@
 int perf_event__synthesize_attrs(struct perf_tool *tool,
 				 struct perf_session *session,
 				 perf_event__handler_t process);
-int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist);
-
-int perf_event__synthesize_event_type(struct perf_tool *tool,
-				      u64 event_id, char *name,
-				      perf_event__handler_t process,
-				      struct machine *machine);
-int perf_event__synthesize_event_types(struct perf_tool *tool,
-				       perf_event__handler_t process,
-				       struct machine *machine);
-int perf_event__process_event_type(struct perf_tool *tool,
-				   union perf_event *event);
+int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
+			     struct perf_evlist **pevlist);
 
 int perf_event__synthesize_tracing_data(struct perf_tool *tool,
 					int fd, struct perf_evlist *evlist,
 					perf_event__handler_t process);
-int perf_event__process_tracing_data(union perf_event *event,
+int perf_event__process_tracing_data(struct perf_tool *tool,
+				     union perf_event *event,
 				     struct perf_session *session);
 
 int perf_event__synthesize_build_id(struct perf_tool *tool,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b11a6cf..46a0d35 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -24,7 +24,8 @@
 struct callchain_param	callchain_param = {
 	.mode	= CHAIN_GRAPH_REL,
 	.min_percent = 0.5,
-	.order  = ORDER_CALLEE
+	.order  = ORDER_CALLEE,
+	.key	= CCKEY_FUNCTION
 };
 
 u16 hists__col_len(struct hists *hists, enum hist_column col)
@@ -912,6 +913,7 @@
 		rb_link_node(&he->rb_node_in, parent, p);
 		rb_insert_color(&he->rb_node_in, root);
 		hists__inc_nr_entries(hists, he);
+		he->dummy = true;
 	}
 out:
 	return he;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2d3790f..1329b6b 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -141,10 +141,12 @@
 };
 
 struct perf_hpp_fmt {
-	int (*header)(struct perf_hpp *hpp);
-	int (*width)(struct perf_hpp *hpp);
-	int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
-	int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
+	int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
+	int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
+	int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+		     struct hist_entry *he);
+	int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+		     struct hist_entry *he);
 
 	struct list_head list;
 };
@@ -157,7 +159,7 @@
 extern struct perf_hpp_fmt perf_hpp__format[];
 
 enum {
-	PERF_HPP__BASELINE,
+	/* Matches perf_hpp__format array. */
 	PERF_HPP__OVERHEAD,
 	PERF_HPP__OVERHEAD_SYS,
 	PERF_HPP__OVERHEAD_US,
@@ -165,11 +167,6 @@
 	PERF_HPP__OVERHEAD_GUEST_US,
 	PERF_HPP__SAMPLES,
 	PERF_HPP__PERIOD,
-	PERF_HPP__PERIOD_BASELINE,
-	PERF_HPP__DELTA,
-	PERF_HPP__RATIO,
-	PERF_HPP__WEIGHTED_DIFF,
-	PERF_HPP__FORMULA,
 
 	PERF_HPP__MAX_INDEX
 };
@@ -177,8 +174,6 @@
 void perf_hpp__init(void);
 void perf_hpp__column_register(struct perf_hpp_fmt *format);
 void perf_hpp__column_enable(unsigned col);
-int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
-				bool color);
 
 struct perf_evlist;
 
@@ -245,11 +240,4 @@
 #endif
 
 unsigned int hists__sort_list_width(struct hists *self);
-
-double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
-double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
-s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
-int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
-		       char *buf, size_t size);
-double perf_diff__period_percent(struct hist_entry *he, u64 period);
 #endif	/* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
index 6f19c54..97a8007 100644
--- a/tools/perf/util/include/linux/string.h
+++ b/tools/perf/util/include/linux/string.h
@@ -1,3 +1,4 @@
 #include <string.h>
 
 void *memdup(const void *src, size_t len);
+int str_append(char **s, int *len, const char *a);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index b2ecad6..1dca61f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -25,12 +25,15 @@
 	machine->kmaps.machine = machine;
 	machine->pid = pid;
 
+	machine->symbol_filter = NULL;
+
 	machine->root_dir = strdup(root_dir);
 	if (machine->root_dir == NULL)
 		return -ENOMEM;
 
 	if (pid != HOST_KERNEL_ID) {
-		struct thread *thread = machine__findnew_thread(machine, pid);
+		struct thread *thread = machine__findnew_thread(machine, 0,
+								pid);
 		char comm[64];
 
 		if (thread == NULL)
@@ -95,6 +98,7 @@
 {
 	machine__init(&machines->host, "", HOST_KERNEL_ID);
 	machines->guests = RB_ROOT;
+	machines->symbol_filter = NULL;
 }
 
 void machines__exit(struct machines *machines)
@@ -118,6 +122,8 @@
 		return NULL;
 	}
 
+	machine->symbol_filter = machines->symbol_filter;
+
 	while (*p != NULL) {
 		parent = *p;
 		pos = rb_entry(parent, struct machine, rb_node);
@@ -133,6 +139,21 @@
 	return machine;
 }
 
+void machines__set_symbol_filter(struct machines *machines,
+				 symbol_filter_t symbol_filter)
+{
+	struct rb_node *nd;
+
+	machines->symbol_filter = symbol_filter;
+	machines->host.symbol_filter = symbol_filter;
+
+	for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+		struct machine *machine = rb_entry(nd, struct machine, rb_node);
+
+		machine->symbol_filter = symbol_filter;
+	}
+}
+
 struct machine *machines__find(struct machines *machines, pid_t pid)
 {
 	struct rb_node **p = &machines->guests.rb_node;
@@ -233,7 +254,8 @@
 	return;
 }
 
-static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
+static struct thread *__machine__findnew_thread(struct machine *machine,
+						pid_t pid, pid_t tid,
 						bool create)
 {
 	struct rb_node **p = &machine->threads.rb_node;
@@ -241,23 +263,28 @@
 	struct thread *th;
 
 	/*
-	 * Font-end cache - PID lookups come in blocks,
+	 * Front-end cache - TID lookups come in blocks,
 	 * so most of the time we dont have to look up
 	 * the full rbtree:
 	 */
-	if (machine->last_match && machine->last_match->pid == pid)
+	if (machine->last_match && machine->last_match->tid == tid) {
+		if (pid && pid != machine->last_match->pid_)
+			machine->last_match->pid_ = pid;
 		return machine->last_match;
+	}
 
 	while (*p != NULL) {
 		parent = *p;
 		th = rb_entry(parent, struct thread, rb_node);
 
-		if (th->pid == pid) {
+		if (th->tid == tid) {
 			machine->last_match = th;
+			if (pid && pid != th->pid_)
+				th->pid_ = pid;
 			return th;
 		}
 
-		if (pid < th->pid)
+		if (tid < th->tid)
 			p = &(*p)->rb_left;
 		else
 			p = &(*p)->rb_right;
@@ -266,7 +293,7 @@
 	if (!create)
 		return NULL;
 
-	th = thread__new(pid);
+	th = thread__new(pid, tid);
 	if (th != NULL) {
 		rb_link_node(&th->rb_node, parent, p);
 		rb_insert_color(&th->rb_node, &machine->threads);
@@ -276,19 +303,22 @@
 	return th;
 }
 
-struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
+struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
+				       pid_t tid)
 {
-	return __machine__findnew_thread(machine, pid, true);
+	return __machine__findnew_thread(machine, pid, tid, true);
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t pid)
+struct thread *machine__find_thread(struct machine *machine, pid_t tid)
 {
-	return __machine__findnew_thread(machine, pid, false);
+	return __machine__findnew_thread(machine, 0, tid, false);
 }
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event)
 {
-	struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
+	struct thread *thread = machine__findnew_thread(machine,
+							event->comm.pid,
+							event->comm.tid);
 
 	if (dump_trace)
 		perf_event__fprintf_comm(event, stdout);
@@ -628,10 +658,8 @@
 	struct map *map = machine->vmlinux_maps[type];
 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
 
-	if (ret > 0) {
+	if (ret > 0)
 		dso__set_loaded(map->dso, type);
-		map__reloc_vmlinux(map);
-	}
 
 	return ret;
 }
@@ -808,7 +836,10 @@
 	free(line);
 	fclose(file);
 
-	return machine__set_modules_path(machine);
+	if (machine__set_modules_path(machine) < 0) {
+		pr_debug("Problems setting modules path maps, continuing anyway...\n");
+	}
+	return 0;
 
 out_delete_line:
 	free(line);
@@ -858,6 +889,18 @@
 	}
 }
 
+static bool machine__uses_kcore(struct machine *machine)
+{
+	struct dso *dso;
+
+	list_for_each_entry(dso, &machine->kernel_dsos, node) {
+		if (dso__is_kcore(dso))
+			return true;
+	}
+
+	return false;
+}
+
 static int machine__process_kernel_mmap_event(struct machine *machine,
 					      union perf_event *event)
 {
@@ -866,6 +909,10 @@
 	enum dso_kernel_type kernel_type;
 	bool is_kernel_mmap;
 
+	/* If we have maps from kcore then we do not need or want any others */
+	if (machine__uses_kcore(machine))
+		return 0;
+
 	machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
 	if (machine__is_host(machine))
 		kernel_type = DSO_TYPE_KERNEL;
@@ -969,7 +1016,8 @@
 		return 0;
 	}
 
-	thread = machine__findnew_thread(machine, event->mmap.pid);
+	thread = machine__findnew_thread(machine, event->mmap.pid,
+					 event->mmap.pid);
 	if (thread == NULL)
 		goto out_problem;
 
@@ -994,11 +1042,30 @@
 	return 0;
 }
 
+static void machine__remove_thread(struct machine *machine, struct thread *th)
+{
+	machine->last_match = NULL;
+	rb_erase(&th->rb_node, &machine->threads);
+	/*
+	 * We may have references to this thread, for instance in some hist_entry
+	 * instances, so just move them to a separate list.
+	 */
+	list_add_tail(&th->node, &machine->dead_threads);
+}
+
 int machine__process_fork_event(struct machine *machine, union perf_event *event)
 {
-	struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
-	struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
+	struct thread *thread = machine__find_thread(machine, event->fork.tid);
+	struct thread *parent = machine__findnew_thread(machine,
+							event->fork.ppid,
+							event->fork.ptid);
 
+	/* if a thread currently exists for the thread id remove it */
+	if (thread != NULL)
+		machine__remove_thread(machine, thread);
+
+	thread = machine__findnew_thread(machine, event->fork.pid,
+					 event->fork.tid);
 	if (dump_trace)
 		perf_event__fprintf_task(event, stdout);
 
@@ -1011,18 +1078,8 @@
 	return 0;
 }
 
-static void machine__remove_thread(struct machine *machine, struct thread *th)
-{
-	machine->last_match = NULL;
-	rb_erase(&th->rb_node, &machine->threads);
-	/*
-	 * We may have references to this thread, for instance in some hist_entry
-	 * instances, so just move them to a separate list.
-	 */
-	list_add_tail(&th->node, &machine->dead_threads);
-}
-
-int machine__process_exit_event(struct machine *machine, union perf_event *event)
+int machine__process_exit_event(struct machine *machine __maybe_unused,
+				union perf_event *event)
 {
 	struct thread *thread = machine__find_thread(machine, event->fork.tid);
 
@@ -1030,7 +1087,7 @@
 		perf_event__fprintf_task(event, stdout);
 
 	if (thread != NULL)
-		machine__remove_thread(machine, thread);
+		thread__exited(thread);
 
 	return 0;
 }
@@ -1058,11 +1115,10 @@
 	return ret;
 }
 
-static bool symbol__match_parent_regex(struct symbol *sym)
+static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
 {
-	if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
+	if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
 		return 1;
-
 	return 0;
 }
 
@@ -1094,7 +1150,7 @@
 		 * or else, the symbol is unknown
 		 */
 		thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
-				ip, &al, NULL);
+				ip, &al);
 		if (al.sym)
 			goto found;
 	}
@@ -1112,8 +1168,8 @@
 
 	memset(&al, 0, sizeof(al));
 
-	thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al,
-				   NULL);
+	thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
+				   &al);
 	ams->addr = addr;
 	ams->al_addr = al.addr;
 	ams->sym = al.sym;
@@ -1159,8 +1215,8 @@
 static int machine__resolve_callchain_sample(struct machine *machine,
 					     struct thread *thread,
 					     struct ip_callchain *chain,
-					     struct symbol **parent)
-
+					     struct symbol **parent,
+					     struct addr_location *root_al)
 {
 	u8 cpumode = PERF_RECORD_MISC_USER;
 	unsigned int i;
@@ -1208,11 +1264,18 @@
 
 		al.filtered = false;
 		thread__find_addr_location(thread, machine, cpumode,
-					   MAP__FUNCTION, ip, &al, NULL);
+					   MAP__FUNCTION, ip, &al);
 		if (al.sym != NULL) {
 			if (sort__has_parent && !*parent &&
-			    symbol__match_parent_regex(al.sym))
+			    symbol__match_regex(al.sym, &parent_regex))
 				*parent = al.sym;
+			else if (have_ignore_callees && root_al &&
+			  symbol__match_regex(al.sym, &ignore_callees_regex)) {
+				/* Treat this symbol as the root,
+				   forgetting its callees. */
+				*root_al = al;
+				callchain_cursor_reset(&callchain_cursor);
+			}
 			if (!symbol_conf.use_callchain)
 				break;
 		}
@@ -1237,15 +1300,13 @@
 			       struct perf_evsel *evsel,
 			       struct thread *thread,
 			       struct perf_sample *sample,
-			       struct symbol **parent)
-
+			       struct symbol **parent,
+			       struct addr_location *root_al)
 {
 	int ret;
 
-	callchain_cursor_reset(&callchain_cursor);
-
 	ret = machine__resolve_callchain_sample(machine, thread,
-						sample->callchain, parent);
+						sample->callchain, parent, root_al);
 	if (ret)
 		return ret;
 
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 7794068..0df925b 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -5,6 +5,7 @@
 #include <linux/rbtree.h>
 #include "map.h"
 
+struct addr_location;
 struct branch_stack;
 struct perf_evsel;
 struct perf_sample;
@@ -28,6 +29,7 @@
 	struct list_head  kernel_dsos;
 	struct map_groups kmaps;
 	struct map	  *vmlinux_maps[MAP__NR_TYPES];
+	symbol_filter_t	  symbol_filter;
 };
 
 static inline
@@ -36,7 +38,7 @@
 	return machine->vmlinux_maps[type];
 }
 
-struct thread *machine__find_thread(struct machine *machine, pid_t pid);
+struct thread *machine__find_thread(struct machine *machine, pid_t tid);
 
 int machine__process_comm_event(struct machine *machine, union perf_event *event);
 int machine__process_exit_event(struct machine *machine, union perf_event *event);
@@ -50,6 +52,7 @@
 struct machines {
 	struct machine host;
 	struct rb_root guests;
+	symbol_filter_t symbol_filter;
 };
 
 void machines__init(struct machines *machines);
@@ -67,6 +70,9 @@
 void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
 char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
+void machines__set_symbol_filter(struct machines *machines,
+				 symbol_filter_t symbol_filter);
+
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
 void machine__exit(struct machine *machine);
 void machine__delete_dead_threads(struct machine *machine);
@@ -83,7 +89,8 @@
 			       struct perf_evsel *evsel,
 			       struct thread *thread,
 			       struct perf_sample *sample,
-			       struct symbol **parent);
+			       struct symbol **parent,
+			       struct addr_location *root_al);
 
 /*
  * Default guest kernel is defined by parameter --guestkallsyms
@@ -99,7 +106,8 @@
 	return machine ? machine->pid == HOST_KERNEL_ID : false;
 }
 
-struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
+struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
+				       pid_t tid);
 
 size_t machine__fprintf(struct machine *machine, FILE *fp);
 
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 8bcdf9e..9e8304c 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -182,12 +182,6 @@
 #endif
 		return -1;
 	}
-	/*
-	 * Only applies to the kernel, as its symtabs aren't relative like the
-	 * module ones.
-	 */
-	if (map->dso->kernel)
-		map__reloc_vmlinux(map);
 
 	return 0;
 }
@@ -254,14 +248,18 @@
 
 /*
  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
- * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
+ * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
+ * relative to section start.
  */
 u64 map__rip_2objdump(struct map *map, u64 rip)
 {
-	u64 addr = map->dso->adjust_symbols ?
-			map->unmap_ip(map, rip) :	/* RIP -> IP */
-			rip;
-	return addr;
+	if (!map->dso->adjust_symbols)
+		return rip;
+
+	if (map->dso->rel)
+		return rip - map->pgoff;
+
+	return map->unmap_ip(map, rip);
 }
 
 void map_groups__init(struct map_groups *mg)
@@ -513,35 +511,6 @@
 	return 0;
 }
 
-static u64 map__reloc_map_ip(struct map *map, u64 ip)
-{
-	return ip + (s64)map->pgoff;
-}
-
-static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
-{
-	return ip - (s64)map->pgoff;
-}
-
-void map__reloc_vmlinux(struct map *map)
-{
-	struct kmap *kmap = map__kmap(map);
-	s64 reloc;
-
-	if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
-		return;
-
-	reloc = (kmap->ref_reloc_sym->unrelocated_addr -
-		 kmap->ref_reloc_sym->addr);
-
-	if (!reloc)
-		return;
-
-	map->map_ip   = map__reloc_map_ip;
-	map->unmap_ip = map__reloc_unmap_ip;
-	map->pgoff    = reloc;
-}
-
 void maps__insert(struct rb_root *maps, struct map *map)
 {
 	struct rb_node **p = &maps->rb_node;
@@ -586,3 +555,21 @@
 
 	return NULL;
 }
+
+struct map *maps__first(struct rb_root *maps)
+{
+	struct rb_node *first = rb_first(maps);
+
+	if (first)
+		return rb_entry(first, struct map, rb_node);
+	return NULL;
+}
+
+struct map *maps__next(struct map *map)
+{
+	struct rb_node *next = rb_next(&map->rb_node);
+
+	if (next)
+		return rb_entry(next, struct map, rb_node);
+	return NULL;
+}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index a887f2c..2cc93cb 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -112,6 +112,8 @@
 void maps__insert(struct rb_root *maps, struct map *map);
 void maps__remove(struct rb_root *maps, struct map *map);
 struct map *maps__find(struct rb_root *maps, u64 addr);
+struct map *maps__first(struct rb_root *maps);
+struct map *maps__next(struct map *map);
 void map_groups__init(struct map_groups *mg);
 void map_groups__exit(struct map_groups *mg);
 int map_groups__clone(struct map_groups *mg,
@@ -139,6 +141,17 @@
 	return maps__find(&mg->maps[type], addr);
 }
 
+static inline struct map *map_groups__first(struct map_groups *mg,
+					    enum map_type type)
+{
+	return maps__first(&mg->maps[type]);
+}
+
+static inline struct map *map_groups__next(struct map *map)
+{
+	return maps__next(map);
+}
+
 struct symbol *map_groups__find_symbol(struct map_groups *mg,
 				       enum map_type type, u64 addr,
 				       struct map **mapp,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 995fc25..9812531 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -6,7 +6,7 @@
 #include "parse-options.h"
 #include "parse-events.h"
 #include "exec_cmd.h"
-#include "string.h"
+#include "linux/string.h"
 #include "symbol.h"
 #include "cache.h"
 #include "header.h"
@@ -15,6 +15,7 @@
 #define YY_EXTRA_TYPE int
 #include "parse-events-flex.h"
 #include "pmu.h"
+#include "thread_map.h"
 
 #define MAX_NAME_LEN 100
 
@@ -108,6 +109,10 @@
 		.symbol = "emulation-faults",
 		.alias  = "",
 	},
+	[PERF_COUNT_SW_DUMMY] = {
+		.symbol = "dummy",
+		.alias  = "",
+	},
 };
 
 #define __PERF_EVENT_FIELD(config, name) \
@@ -217,6 +222,29 @@
 	return NULL;
 }
 
+struct tracepoint_path *tracepoint_name_to_path(const char *name)
+{
+	struct tracepoint_path *path = zalloc(sizeof(*path));
+	char *str = strchr(name, ':');
+
+	if (path == NULL || str == NULL) {
+		free(path);
+		return NULL;
+	}
+
+	path->system = strndup(name, str - name);
+	path->name = strdup(str+1);
+
+	if (path->system == NULL || path->name == NULL) {
+		free(path->system);
+		free(path->name);
+		free(path);
+		path = NULL;
+	}
+
+	return path;
+}
+
 const char *event_type(int type)
 {
 	switch (type) {
@@ -241,40 +269,29 @@
 
 
 
-static int __add_event(struct list_head **_list, int *idx,
+static int __add_event(struct list_head *list, int *idx,
 		       struct perf_event_attr *attr,
 		       char *name, struct cpu_map *cpus)
 {
 	struct perf_evsel *evsel;
-	struct list_head *list = *_list;
-
-	if (!list) {
-		list = malloc(sizeof(*list));
-		if (!list)
-			return -ENOMEM;
-		INIT_LIST_HEAD(list);
-	}
 
 	event_attr_init(attr);
 
 	evsel = perf_evsel__new(attr, (*idx)++);
-	if (!evsel) {
-		free(list);
+	if (!evsel)
 		return -ENOMEM;
-	}
 
 	evsel->cpus = cpus;
 	if (name)
 		evsel->name = strdup(name);
 	list_add_tail(&evsel->node, list);
-	*_list = list;
 	return 0;
 }
 
-static int add_event(struct list_head **_list, int *idx,
+static int add_event(struct list_head *list, int *idx,
 		     struct perf_event_attr *attr, char *name)
 {
-	return __add_event(_list, idx, attr, name, NULL);
+	return __add_event(list, idx, attr, name, NULL);
 }
 
 static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -295,7 +312,7 @@
 	return -1;
 }
 
-int parse_events_add_cache(struct list_head **list, int *idx,
+int parse_events_add_cache(struct list_head *list, int *idx,
 			   char *type, char *op_result1, char *op_result2)
 {
 	struct perf_event_attr attr;
@@ -356,31 +373,21 @@
 	return add_event(list, idx, &attr, name);
 }
 
-static int add_tracepoint(struct list_head **listp, int *idx,
+static int add_tracepoint(struct list_head *list, int *idx,
 			  char *sys_name, char *evt_name)
 {
 	struct perf_evsel *evsel;
-	struct list_head *list = *listp;
-
-	if (!list) {
-		list = malloc(sizeof(*list));
-		if (!list)
-			return -ENOMEM;
-		INIT_LIST_HEAD(list);
-	}
 
 	evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
-	if (!evsel) {
-		free(list);
+	if (!evsel)
 		return -ENOMEM;
-	}
 
 	list_add_tail(&evsel->node, list);
-	*listp = list;
+
 	return 0;
 }
 
-static int add_tracepoint_multi_event(struct list_head **list, int *idx,
+static int add_tracepoint_multi_event(struct list_head *list, int *idx,
 				      char *sys_name, char *evt_name)
 {
 	char evt_path[MAXPATHLEN];
@@ -412,7 +419,7 @@
 	return ret;
 }
 
-static int add_tracepoint_event(struct list_head **list, int *idx,
+static int add_tracepoint_event(struct list_head *list, int *idx,
 				char *sys_name, char *evt_name)
 {
 	return strpbrk(evt_name, "*?") ?
@@ -420,7 +427,7 @@
 	       add_tracepoint(list, idx, sys_name, evt_name);
 }
 
-static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
+static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
 				    char *sys_name, char *evt_name)
 {
 	struct dirent *events_ent;
@@ -452,7 +459,7 @@
 	return ret;
 }
 
-int parse_events_add_tracepoint(struct list_head **list, int *idx,
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
 				char *sys, char *event)
 {
 	int ret;
@@ -507,7 +514,7 @@
 	return 0;
 }
 
-int parse_events_add_breakpoint(struct list_head **list, int *idx,
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
 				void *ptr, char *type)
 {
 	struct perf_event_attr attr;
@@ -588,7 +595,7 @@
 	return 0;
 }
 
-int parse_events_add_numeric(struct list_head **list, int *idx,
+int parse_events_add_numeric(struct list_head *list, int *idx,
 			     u32 type, u64 config,
 			     struct list_head *head_config)
 {
@@ -621,7 +628,7 @@
 	return NULL;
 }
 
-int parse_events_add_pmu(struct list_head **list, int *idx,
+int parse_events_add_pmu(struct list_head *list, int *idx,
 			 char *name, struct list_head *head_config)
 {
 	struct perf_event_attr attr;
@@ -664,6 +671,7 @@
 	leader->group_name = name ? strdup(name) : NULL;
 }
 
+/* list_event is assumed to point to malloc'ed memory */
 void parse_events_update_lists(struct list_head *list_event,
 			       struct list_head *list_all)
 {
@@ -684,6 +692,8 @@
 	int eG;
 	int precise;
 	int exclude_GH;
+	int sample_read;
+	int pinned;
 };
 
 static int get_event_modifier(struct event_modifier *mod, char *str,
@@ -695,6 +705,8 @@
 	int eH = evsel ? evsel->attr.exclude_host : 0;
 	int eG = evsel ? evsel->attr.exclude_guest : 0;
 	int precise = evsel ? evsel->attr.precise_ip : 0;
+	int sample_read = 0;
+	int pinned = evsel ? evsel->attr.pinned : 0;
 
 	int exclude = eu | ek | eh;
 	int exclude_GH = evsel ? evsel->exclude_GH : 0;
@@ -727,6 +739,10 @@
 			/* use of precise requires exclude_guest */
 			if (!exclude_GH)
 				eG = 1;
+		} else if (*str == 'S') {
+			sample_read = 1;
+		} else if (*str == 'D') {
+			pinned = 1;
 		} else
 			break;
 
@@ -753,6 +769,9 @@
 	mod->eG = eG;
 	mod->precise = precise;
 	mod->exclude_GH = exclude_GH;
+	mod->sample_read = sample_read;
+	mod->pinned = pinned;
+
 	return 0;
 }
 
@@ -765,7 +784,7 @@
 	char *p = str;
 
 	/* The sizeof includes 0 byte as well. */
-	if (strlen(str) > (sizeof("ukhGHppp") - 1))
+	if (strlen(str) > (sizeof("ukhGHpppSD") - 1))
 		return -1;
 
 	while (*p) {
@@ -803,6 +822,10 @@
 		evsel->attr.exclude_host   = mod.eH;
 		evsel->attr.exclude_guest  = mod.eG;
 		evsel->exclude_GH          = mod.exclude_GH;
+		evsel->sample_read         = mod.sample_read;
+
+		if (perf_evsel__is_group_leader(evsel))
+			evsel->attr.pinned = mod.pinned;
 	}
 
 	return 0;
@@ -820,6 +843,32 @@
 	return 0;
 }
 
+static int parse_events__scanner(const char *str, void *data, int start_token);
+
+static int parse_events_fixup(int ret, const char *str, void *data,
+			      int start_token)
+{
+	char *o = strdup(str);
+	char *s = NULL;
+	char *t = o;
+	char *p;
+	int len = 0;
+
+	if (!o)
+		return ret;
+	while ((p = strsep(&t, ",")) != NULL) {
+		if (s)
+			str_append(&s, &len, ",");
+		str_append(&s, &len, "cpu/");
+		str_append(&s, &len, p);
+		str_append(&s, &len, "/");
+	}
+	free(o);
+	if (!s)
+		return -ENOMEM;
+	return parse_events__scanner(s, data, start_token);
+}
+
 static int parse_events__scanner(const char *str, void *data, int start_token)
 {
 	YY_BUFFER_STATE buffer;
@@ -840,6 +889,8 @@
 	parse_events__flush_buffer(buffer, scanner);
 	parse_events__delete_buffer(buffer, scanner);
 	parse_events_lex_destroy(scanner);
+	if (ret && !strchr(str, '/'))
+		ret = parse_events_fixup(ret, str, data, start_token);
 	return ret;
 }
 
@@ -1026,6 +1077,33 @@
 	return 0;
 }
 
+static bool is_event_supported(u8 type, unsigned config)
+{
+	bool ret = true;
+	struct perf_evsel *evsel;
+	struct perf_event_attr attr = {
+		.type = type,
+		.config = config,
+		.disabled = 1,
+		.exclude_kernel = 1,
+	};
+	struct {
+		struct thread_map map;
+		int threads[1];
+	} tmap = {
+		.map.nr	 = 1,
+		.threads = { 0 },
+	};
+
+	evsel = perf_evsel__new(&attr, 0);
+	if (evsel) {
+		ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+		perf_evsel__delete(evsel);
+	}
+
+	return ret;
+}
+
 static void __print_events_type(u8 type, struct event_symbol *syms,
 				unsigned max)
 {
@@ -1033,14 +1111,16 @@
 	unsigned i;
 
 	for (i = 0; i < max ; i++, syms++) {
+		if (!is_event_supported(type, i))
+			continue;
+
 		if (strlen(syms->alias))
 			snprintf(name, sizeof(name),  "%s OR %s",
 				 syms->symbol, syms->alias);
 		else
 			snprintf(name, sizeof(name), "%s", syms->symbol);
 
-		printf("  %-50s [%s]\n", name,
-			event_type_descriptors[type]);
+		printf("  %-50s [%s]\n", name, event_type_descriptors[type]);
 	}
 }
 
@@ -1069,6 +1149,10 @@
 				if (event_glob != NULL && !strglobmatch(name, event_glob))
 					continue;
 
+				if (!is_event_supported(PERF_TYPE_HW_CACHE,
+							type | (op << 8) | (i << 16)))
+					continue;
+
 				if (name_only)
 					printf("%s ", name);
 				else
@@ -1079,6 +1163,8 @@
 		}
 	}
 
+	if (printed)
+		printf("\n");
 	return printed;
 }
 
@@ -1096,6 +1182,9 @@
 		      (syms->alias && strglobmatch(syms->alias, event_glob))))
 			continue;
 
+		if (!is_event_supported(type, i))
+			continue;
+
 		if (name_only) {
 			printf("%s ", syms->symbol);
 			continue;
@@ -1133,11 +1222,12 @@
 
 	print_hwcache_events(event_glob, name_only);
 
+	print_pmu_events(event_glob, name_only);
+
 	if (event_glob != NULL)
 		return;
 
 	if (!name_only) {
-		printf("\n");
 		printf("  %-50s [%s]\n",
 		       "rNNN",
 		       event_type_descriptors[PERF_TYPE_RAW]);
@@ -1237,6 +1327,4 @@
 
 	list_for_each_entry_safe(term, h, terms, list)
 		free(term);
-
-	free(terms);
 }
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8a48593..f1cb4c4 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -23,6 +23,7 @@
 };
 
 extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
+extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
 extern bool have_tracepoints(struct list_head *evlist);
 
 const char *event_type(int type);
@@ -84,16 +85,16 @@
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events_name(struct list_head *list, char *name);
-int parse_events_add_tracepoint(struct list_head **list, int *idx,
+int parse_events_add_tracepoint(struct list_head *list, int *idx,
 				char *sys, char *event);
-int parse_events_add_numeric(struct list_head **list, int *idx,
+int parse_events_add_numeric(struct list_head *list, int *idx,
 			     u32 type, u64 config,
 			     struct list_head *head_config);
-int parse_events_add_cache(struct list_head **list, int *idx,
+int parse_events_add_cache(struct list_head *list, int *idx,
 			   char *type, char *op_result1, char *op_result2);
-int parse_events_add_breakpoint(struct list_head **list, int *idx,
+int parse_events_add_breakpoint(struct list_head *list, int *idx,
 				void *ptr, char *type);
-int parse_events_add_pmu(struct list_head **list, int *idx,
+int parse_events_add_pmu(struct list_head *list, int *idx,
 			 char *pmu , struct list_head *head_config);
 void parse_events__set_leader(char *name, struct list_head *list);
 void parse_events_update_lists(struct list_head *list_event,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index e9d1134..91346b7 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -82,7 +82,8 @@
 num_raw_hex	[a-fA-F0-9]+
 name		[a-zA-Z_*?][a-zA-Z0-9_*?]*
 name_minus	[a-zA-Z_*?][a-zA-Z0-9\-_*?]*
-modifier_event	[ukhpGH]+
+/* If you add a modifier you need to update check_modifier() */
+modifier_event	[ukhpGHSD]+
 modifier_bp	[rwx]{1,3}
 
 %%
@@ -144,6 +145,7 @@
 cpu-migrations|migrations			{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
 alignment-faults				{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
 emulation-faults				{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+dummy						{ return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
 
 L1-dcache|l1-d|l1d|L1-data		|
 L1-icache|l1-i|l1i|L1-instruction	|
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index afc44c1..4eb67ec 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -22,6 +22,13 @@
 		YYABORT; \
 } while (0)
 
+#define ALLOC_LIST(list) \
+do { \
+	list = malloc(sizeof(*list)); \
+	ABORT_ON(!list);              \
+	INIT_LIST_HEAD(list);         \
+} while (0)
+
 static inc_group_count(struct list_head *list,
 		       struct parse_events_evlist *data)
 {
@@ -196,9 +203,10 @@
 PE_NAME '/' event_config '/'
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3));
 	parse_events__free_terms($3);
 	$$ = list;
 }
@@ -212,11 +220,12 @@
 value_sym '/' event_config '/'
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_numeric(list, &data->idx,
 					  type, config, $3));
 	parse_events__free_terms($3);
 	$$ = list;
@@ -225,11 +234,12 @@
 value_sym sep_slash_dc
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 	int type = $1 >> 16;
 	int config = $1 & 255;
 
-	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_numeric(list, &data->idx,
 					  type, config, NULL));
 	$$ = list;
 }
@@ -238,27 +248,30 @@
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5));
 	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL));
 	$$ = list;
 }
 |
 PE_NAME_CACHE_TYPE
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL));
 	$$ = list;
 }
 
@@ -266,9 +279,10 @@
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
 					     (void *) $2, $4));
 	$$ = list;
 }
@@ -276,9 +290,10 @@
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
 					     (void *) $2, NULL));
 	$$ = list;
 }
@@ -287,9 +302,10 @@
 PE_NAME ':' PE_NAME
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
 	$$ = list;
 }
 
@@ -297,9 +313,10 @@
 PE_VALUE ':' PE_VALUE
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL));
 	$$ = list;
 }
 
@@ -307,9 +324,10 @@
 PE_RAW
 {
 	struct parse_events_evlist *data = _data;
-	struct list_head *list = NULL;
+	struct list_head *list;
 
-	ABORT_ON(parse_events_add_numeric(&list, &data->idx,
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_add_numeric(list, &data->idx,
 					  PERF_TYPE_RAW, $1, NULL));
 	$$ = list;
 }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 4c6f9c4..bc9d806 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -73,7 +73,7 @@
  * located at:
  * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes.
  */
-static int pmu_format(char *name, struct list_head *format)
+static int pmu_format(const char *name, struct list_head *format)
 {
 	struct stat st;
 	char path[PATH_MAX];
@@ -162,7 +162,7 @@
  * Reading the pmu event aliases definition, which should be located at:
  * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
  */
-static int pmu_aliases(char *name, struct list_head *head)
+static int pmu_aliases(const char *name, struct list_head *head)
 {
 	struct stat st;
 	char path[PATH_MAX];
@@ -208,7 +208,7 @@
  * located at:
  * /sys/bus/event_source/devices/<dev>/type as sysfs attribute.
  */
-static int pmu_type(char *name, __u32 *type)
+static int pmu_type(const char *name, __u32 *type)
 {
 	struct stat st;
 	char path[PATH_MAX];
@@ -266,7 +266,7 @@
 	closedir(dir);
 }
 
-static struct cpu_map *pmu_cpumask(char *name)
+static struct cpu_map *pmu_cpumask(const char *name)
 {
 	struct stat st;
 	char path[PATH_MAX];
@@ -293,7 +293,7 @@
 	return cpus;
 }
 
-static struct perf_pmu *pmu_lookup(char *name)
+static struct perf_pmu *pmu_lookup(const char *name)
 {
 	struct perf_pmu *pmu;
 	LIST_HEAD(format);
@@ -330,7 +330,7 @@
 	return pmu;
 }
 
-static struct perf_pmu *pmu_find(char *name)
+static struct perf_pmu *pmu_find(const char *name)
 {
 	struct perf_pmu *pmu;
 
@@ -356,7 +356,7 @@
 	return NULL;
 }
 
-struct perf_pmu *perf_pmu__find(char *name)
+struct perf_pmu *perf_pmu__find(const char *name)
 {
 	struct perf_pmu *pmu;
 
@@ -564,3 +564,76 @@
 	for (b = from; b <= to; b++)
 		set_bit(b, bits);
 }
+
+static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
+			  struct perf_pmu_alias *alias)
+{
+	snprintf(buf, len, "%s/%s/", pmu->name, alias->name);
+	return buf;
+}
+
+static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
+			     struct perf_pmu_alias *alias)
+{
+	snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name);
+	return buf;
+}
+
+static int cmp_string(const void *a, const void *b)
+{
+	const char * const *as = a;
+	const char * const *bs = b;
+	return strcmp(*as, *bs);
+}
+
+void print_pmu_events(const char *event_glob, bool name_only)
+{
+	struct perf_pmu *pmu;
+	struct perf_pmu_alias *alias;
+	char buf[1024];
+	int printed = 0;
+	int len, j;
+	char **aliases;
+
+	pmu = NULL;
+	len = 0;
+	while ((pmu = perf_pmu__scan(pmu)) != NULL)
+		list_for_each_entry(alias, &pmu->aliases, list)
+			len++;
+	aliases = malloc(sizeof(char *) * len);
+	if (!aliases)
+		return;
+	pmu = NULL;
+	j = 0;
+	while ((pmu = perf_pmu__scan(pmu)) != NULL)
+		list_for_each_entry(alias, &pmu->aliases, list) {
+			char *name = format_alias(buf, sizeof(buf), pmu, alias);
+			bool is_cpu = !strcmp(pmu->name, "cpu");
+
+			if (event_glob != NULL &&
+			    !(strglobmatch(name, event_glob) ||
+			      (!is_cpu && strglobmatch(alias->name,
+						       event_glob))))
+				continue;
+			aliases[j] = name;
+			if (is_cpu && !name_only)
+				aliases[j] = format_alias_or(buf, sizeof(buf),
+							      pmu, alias);
+			aliases[j] = strdup(aliases[j]);
+			j++;
+		}
+	len = j;
+	qsort(aliases, len, sizeof(char *), cmp_string);
+	for (j = 0; j < len; j++) {
+		if (name_only) {
+			printf("%s ", aliases[j]);
+			continue;
+		}
+		printf("  %-50s [Kernel PMU event]\n", aliases[j]);
+		free(aliases[j]);
+		printed++;
+	}
+	if (printed)
+		printf("\n");
+	free(aliases);
+}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 32fe55b..6b2cbe2 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -3,6 +3,7 @@
 
 #include <linux/bitops.h>
 #include <linux/perf_event.h>
+#include <stdbool.h>
 
 enum {
 	PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -21,7 +22,7 @@
 	struct list_head list;
 };
 
-struct perf_pmu *perf_pmu__find(char *name);
+struct perf_pmu *perf_pmu__find(const char *name);
 int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
 		     struct list_head *head_terms);
 int perf_pmu__config_terms(struct list_head *formats,
@@ -40,5 +41,7 @@
 
 struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
 
+void print_pmu_events(const char *event_glob, bool name_only);
+
 int perf_pmu__test(void);
 #endif /* __PMU_H */
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 925e0c3..71b5412 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -8,6 +8,26 @@
 #include "cpumap.h"
 #include "thread_map.h"
 
+/*
+ * Support debug printing even though util/debug.c is not linked.  That means
+ * implementing 'verbose' and 'eprintf'.
+ */
+int verbose;
+
+int eprintf(int level, const char *fmt, ...)
+{
+	va_list args;
+	int ret = 0;
+
+	if (verbose >= level) {
+		va_start(args, fmt);
+		ret = vfprintf(stderr, fmt, args);
+		va_end(args);
+	}
+
+	return ret;
+}
+
 /* Define PyVarObject_HEAD_INIT for python 2.5 */
 #ifndef PyVarObject_HEAD_INIT
 # define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
@@ -967,6 +987,7 @@
 	{ "COUNT_SW_PAGE_FAULTS_MAJ",  PERF_COUNT_SW_PAGE_FAULTS_MAJ },
 	{ "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
 	{ "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
+	{ "COUNT_SW_DUMMY",            PERF_COUNT_SW_DUMMY },
 
 	{ "SAMPLE_IP",	      PERF_SAMPLE_IP },
 	{ "SAMPLE_TID",	      PERF_SAMPLE_TID },
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
new file mode 100644
index 0000000..18d73aa
--- /dev/null
+++ b/tools/perf/util/record.c
@@ -0,0 +1,108 @@
+#include "evlist.h"
+#include "evsel.h"
+#include "cpumap.h"
+#include "parse-events.h"
+
+typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
+
+static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
+{
+	struct perf_evlist *evlist;
+	struct perf_evsel *evsel;
+	int err = -EAGAIN, fd;
+
+	evlist = perf_evlist__new();
+	if (!evlist)
+		return -ENOMEM;
+
+	if (parse_events(evlist, str))
+		goto out_delete;
+
+	evsel = perf_evlist__first(evlist);
+
+	fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
+	if (fd < 0)
+		goto out_delete;
+	close(fd);
+
+	fn(evsel);
+
+	fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
+	if (fd < 0) {
+		if (errno == EINVAL)
+			err = -EINVAL;
+		goto out_delete;
+	}
+	close(fd);
+	err = 0;
+
+out_delete:
+	perf_evlist__delete(evlist);
+	return err;
+}
+
+static bool perf_probe_api(setup_probe_fn_t fn)
+{
+	const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
+	struct cpu_map *cpus;
+	int cpu, ret, i = 0;
+
+	cpus = cpu_map__new(NULL);
+	if (!cpus)
+		return false;
+	cpu = cpus->map[0];
+	cpu_map__delete(cpus);
+
+	do {
+		ret = perf_do_probe_api(fn, cpu, try[i++]);
+		if (!ret)
+			return true;
+	} while (ret == -EAGAIN && try[i]);
+
+	return false;
+}
+
+static void perf_probe_sample_identifier(struct perf_evsel *evsel)
+{
+	evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
+}
+
+bool perf_can_sample_identifier(void)
+{
+	return perf_probe_api(perf_probe_sample_identifier);
+}
+
+void perf_evlist__config(struct perf_evlist *evlist,
+			struct perf_record_opts *opts)
+{
+	struct perf_evsel *evsel;
+	bool use_sample_identifier = false;
+
+	/*
+	 * Set the evsel leader links before we configure attributes,
+	 * since some might depend on this info.
+	 */
+	if (opts->group)
+		perf_evlist__set_leader(evlist);
+
+	if (evlist->cpus->map[0] < 0)
+		opts->no_inherit = true;
+
+	list_for_each_entry(evsel, &evlist->entries, node)
+		perf_evsel__config(evsel, opts);
+
+	if (evlist->nr_entries > 1) {
+		struct perf_evsel *first = perf_evlist__first(evlist);
+
+		list_for_each_entry(evsel, &evlist->entries, node) {
+			if (evsel->attr.sample_type == first->attr.sample_type)
+				continue;
+			use_sample_identifier = perf_can_sample_identifier();
+			break;
+		}
+		list_for_each_entry(evsel, &evlist->entries, node)
+			perf_evsel__set_sample_id(evsel, use_sample_identifier);
+	}
+
+	perf_evlist__set_id_pos(evlist);
+}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index eacec85..a85e4ae 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -261,7 +261,8 @@
 				    struct perf_sample *sample,
 				    struct perf_evsel *evsel,
 				    struct machine *machine __maybe_unused,
-				    struct addr_location *al)
+				    struct thread *thread,
+					struct addr_location *al)
 {
 	struct format_field *field;
 	static char handler[256];
@@ -272,7 +273,6 @@
 	int cpu = sample->cpu;
 	void *data = sample->raw_data;
 	unsigned long long nsecs = sample->time;
-	struct thread *thread = al->thread;
 	char *comm = thread->comm;
 
 	dSP;
@@ -351,7 +351,8 @@
 				       struct perf_sample *sample,
 				       struct perf_evsel *evsel,
 				       struct machine *machine __maybe_unused,
-				       struct addr_location *al __maybe_unused)
+				       struct thread *thread __maybe_unused,
+					   struct addr_location *al __maybe_unused)
 {
 	dSP;
 
@@ -377,10 +378,11 @@
 			       struct perf_sample *sample,
 			       struct perf_evsel *evsel,
 			       struct machine *machine,
-			       struct addr_location *al)
+			       struct thread *thread,
+				   struct addr_location *al)
 {
-	perl_process_tracepoint(event, sample, evsel, machine, al);
-	perl_process_event_generic(event, sample, evsel, machine, al);
+	perl_process_tracepoint(event, sample, evsel, machine, thread, al);
+	perl_process_event_generic(event, sample, evsel, machine, thread, al);
 }
 
 static void run_start_sub(void)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index e87aa5d..cc75a3c 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -225,6 +225,7 @@
 				 struct perf_sample *sample,
 				 struct perf_evsel *evsel,
 				 struct machine *machine __maybe_unused,
+				 struct thread *thread,
 				 struct addr_location *al)
 {
 	PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
@@ -238,7 +239,6 @@
 	int cpu = sample->cpu;
 	void *data = sample->raw_data;
 	unsigned long long nsecs = sample->time;
-	struct thread *thread = al->thread;
 	char *comm = thread->comm;
 
 	t = PyTuple_New(MAX_FIELDS);
@@ -345,12 +345,12 @@
 					 struct perf_sample *sample,
 					 struct perf_evsel *evsel,
 					 struct machine *machine __maybe_unused,
+					 struct thread *thread,
 					 struct addr_location *al)
 {
 	PyObject *handler, *retval, *t, *dict;
 	static char handler_name[64];
 	unsigned n = 0;
-	struct thread *thread = al->thread;
 
 	/*
 	 * Use the MAX_FIELDS to make the function expandable, though
@@ -404,17 +404,18 @@
 				 struct perf_sample *sample,
 				 struct perf_evsel *evsel,
 				 struct machine *machine,
+				 struct thread *thread,
 				 struct addr_location *al)
 {
 	switch (evsel->attr.type) {
 	case PERF_TYPE_TRACEPOINT:
 		python_process_tracepoint(perf_event, sample, evsel,
-					  machine, al);
+					  machine, thread, al);
 		break;
 	/* Reserve for future process_hw/sw/raw APIs */
 	default:
 		python_process_general_event(perf_event, sample, evsel,
-					     machine, al);
+					     machine, thread, al);
 	}
 }
 
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index cf1fe01..1fc0c62 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,4 +1,5 @@
 #include <linux/kernel.h>
+#include <traceevent/event-parse.h>
 
 #include <byteswap.h>
 #include <unistd.h>
@@ -12,7 +13,6 @@
 #include "sort.h"
 #include "util.h"
 #include "cpumap.h"
-#include "event-parse.h"
 #include "perf_regs.h"
 #include "vdso.h"
 
@@ -24,7 +24,7 @@
 		self->fd_pipe = true;
 		self->fd = STDIN_FILENO;
 
-		if (perf_session__read_header(self, self->fd) < 0)
+		if (perf_session__read_header(self) < 0)
 			pr_err("incompatible file format (rerun with -v to learn more)");
 
 		return 0;
@@ -56,7 +56,7 @@
 		goto out_close;
 	}
 
-	if (perf_session__read_header(self, self->fd) < 0) {
+	if (perf_session__read_header(self) < 0) {
 		pr_err("incompatible file format (rerun with -v to learn more)");
 		goto out_close;
 	}
@@ -71,6 +71,11 @@
 		goto out_close;
 	}
 
+	if (!perf_evlist__valid_read_format(self->evlist)) {
+		pr_err("non matching read_format");
+		goto out_close;
+	}
+
 	self->size = input_stat.st_size;
 	return 0;
 
@@ -193,7 +198,9 @@
 	vdso__exit();
 }
 
-static int process_event_synth_tracing_data_stub(union perf_event *event
+static int process_event_synth_tracing_data_stub(struct perf_tool *tool
+						 __maybe_unused,
+						 union perf_event *event
 						 __maybe_unused,
 						 struct perf_session *session
 						__maybe_unused)
@@ -202,7 +209,8 @@
 	return 0;
 }
 
-static int process_event_synth_attr_stub(union perf_event *event __maybe_unused,
+static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
+					 union perf_event *event __maybe_unused,
 					 struct perf_evlist **pevlist
 					 __maybe_unused)
 {
@@ -238,18 +246,11 @@
 	return 0;
 }
 
-static int process_event_type_stub(struct perf_tool *tool __maybe_unused,
-				   union perf_event *event __maybe_unused)
-{
-	dump_printf(": unhandled!\n");
-	return 0;
-}
-
 static int process_finished_round(struct perf_tool *tool,
 				  union perf_event *event,
 				  struct perf_session *session);
 
-static void perf_tool__fill_defaults(struct perf_tool *tool)
+void perf_tool__fill_defaults(struct perf_tool *tool)
 {
 	if (tool->sample == NULL)
 		tool->sample = process_event_sample_stub;
@@ -271,8 +272,6 @@
 		tool->unthrottle = process_event_stub;
 	if (tool->attr == NULL)
 		tool->attr = process_event_synth_attr_stub;
-	if (tool->event_type == NULL)
-		tool->event_type = process_event_type_stub;
 	if (tool->tracing_data == NULL)
 		tool->tracing_data = process_event_synth_tracing_data_stub;
 	if (tool->build_id == NULL)
@@ -496,7 +495,7 @@
 				      u64 file_offset);
 
 static int flush_sample_queue(struct perf_session *s,
-			       struct perf_tool *tool)
+		       struct perf_tool *tool)
 {
 	struct ordered_samples *os = &s->ordered_samples;
 	struct list_head *head = &os->samples;
@@ -644,7 +643,7 @@
 
 #define MAX_SAMPLE_BUFFER	(64 * 1024 / sizeof(struct sample_queue))
 
-static int perf_session_queue_event(struct perf_session *s, union perf_event *event,
+int perf_session_queue_event(struct perf_session *s, union perf_event *event,
 				    struct perf_sample *sample, u64 file_offset)
 {
 	struct ordered_samples *os = &s->ordered_samples;
@@ -740,7 +739,7 @@
 				       union perf_event *event,
 				       struct perf_sample *sample)
 {
-	u64 sample_type = perf_evlist__sample_type(session->evlist);
+	u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);
 
 	if (event->header.type != PERF_RECORD_SAMPLE &&
 	    !perf_evlist__sample_id_all(session->evlist)) {
@@ -755,6 +754,36 @@
 		printf("%" PRIu64 " ", sample->time);
 }
 
+static void sample_read__printf(struct perf_sample *sample, u64 read_format)
+{
+	printf("... sample_read:\n");
+
+	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
+		printf("...... time enabled %016" PRIx64 "\n",
+		       sample->read.time_enabled);
+
+	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
+		printf("...... time running %016" PRIx64 "\n",
+		       sample->read.time_running);
+
+	if (read_format & PERF_FORMAT_GROUP) {
+		u64 i;
+
+		printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
+
+		for (i = 0; i < sample->read.group.nr; i++) {
+			struct sample_read_value *value;
+
+			value = &sample->read.group.values[i];
+			printf("..... id %016" PRIx64
+			       ", value %016" PRIx64 "\n",
+			       value->id, value->value);
+		}
+	} else
+		printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
+			sample->read.one.id, sample->read.one.value);
+}
+
 static void dump_event(struct perf_session *session, union perf_event *event,
 		       u64 file_offset, struct perf_sample *sample)
 {
@@ -804,11 +833,15 @@
 
 	if (sample_type & PERF_SAMPLE_DATA_SRC)
 		printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
+
+	if (sample_type & PERF_SAMPLE_READ)
+		sample_read__printf(sample, evsel->attr.read_format);
 }
 
 static struct machine *
 	perf_session__find_machine_for_cpumode(struct perf_session *session,
-					       union perf_event *event)
+					       union perf_event *event,
+					       struct perf_sample *sample)
 {
 	const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 
@@ -820,7 +853,7 @@
 		if (event->header.type == PERF_RECORD_MMAP)
 			pid = event->mmap.pid;
 		else
-			pid = event->ip.pid;
+			pid = sample->pid;
 
 		return perf_session__findnew_machine(session, pid);
 	}
@@ -828,6 +861,75 @@
 	return &session->machines.host;
 }
 
+static int deliver_sample_value(struct perf_session *session,
+				struct perf_tool *tool,
+				union perf_event *event,
+				struct perf_sample *sample,
+				struct sample_read_value *v,
+				struct machine *machine)
+{
+	struct perf_sample_id *sid;
+
+	sid = perf_evlist__id2sid(session->evlist, v->id);
+	if (sid) {
+		sample->id     = v->id;
+		sample->period = v->value - sid->period;
+		sid->period    = v->value;
+	}
+
+	if (!sid || sid->evsel == NULL) {
+		++session->stats.nr_unknown_id;
+		return 0;
+	}
+
+	return tool->sample(tool, event, sample, sid->evsel, machine);
+}
+
+static int deliver_sample_group(struct perf_session *session,
+				struct perf_tool *tool,
+				union  perf_event *event,
+				struct perf_sample *sample,
+				struct machine *machine)
+{
+	int ret = -EINVAL;
+	u64 i;
+
+	for (i = 0; i < sample->read.group.nr; i++) {
+		ret = deliver_sample_value(session, tool, event, sample,
+					   &sample->read.group.values[i],
+					   machine);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int
+perf_session__deliver_sample(struct perf_session *session,
+			     struct perf_tool *tool,
+			     union  perf_event *event,
+			     struct perf_sample *sample,
+			     struct perf_evsel *evsel,
+			     struct machine *machine)
+{
+	/* We know evsel != NULL. */
+	u64 sample_type = evsel->attr.sample_type;
+	u64 read_format = evsel->attr.read_format;
+
+	/* Standard sample delievery. */
+	if (!(sample_type & PERF_SAMPLE_READ))
+		return tool->sample(tool, event, sample, evsel, machine);
+
+	/* For PERF_SAMPLE_READ we have either single or group mode. */
+	if (read_format & PERF_FORMAT_GROUP)
+		return deliver_sample_group(session, tool, event, sample,
+					    machine);
+	else
+		return deliver_sample_value(session, tool, event, sample,
+					    &sample->read.one, machine);
+}
+
 static int perf_session_deliver_event(struct perf_session *session,
 				      union perf_event *event,
 				      struct perf_sample *sample,
@@ -857,7 +959,8 @@
 		hists__inc_nr_events(&evsel->hists, event->header.type);
 	}
 
-	machine = perf_session__find_machine_for_cpumode(session, event);
+	machine = perf_session__find_machine_for_cpumode(session, event,
+							 sample);
 
 	switch (event->header.type) {
 	case PERF_RECORD_SAMPLE:
@@ -870,7 +973,8 @@
 			++session->stats.nr_unprocessable_samples;
 			return 0;
 		}
-		return tool->sample(tool, event, sample, evsel, machine);
+		return perf_session__deliver_sample(session, tool, event,
+						    sample, evsel, machine);
 	case PERF_RECORD_MMAP:
 		return tool->mmap(tool, event, sample, machine);
 	case PERF_RECORD_COMM:
@@ -895,22 +999,6 @@
 	}
 }
 
-static int perf_session__preprocess_sample(struct perf_session *session,
-					   union perf_event *event, struct perf_sample *sample)
-{
-	if (event->header.type != PERF_RECORD_SAMPLE ||
-	    !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
-		return 0;
-
-	if (!ip_callchain__valid(sample->callchain, event)) {
-		pr_debug("call-chain problem with event, skipping it.\n");
-		++session->stats.nr_invalid_chains;
-		session->stats.total_invalid_chains += sample->period;
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
 					    struct perf_tool *tool, u64 file_offset)
 {
@@ -921,16 +1009,14 @@
 	/* These events are processed right away */
 	switch (event->header.type) {
 	case PERF_RECORD_HEADER_ATTR:
-		err = tool->attr(event, &session->evlist);
+		err = tool->attr(tool, event, &session->evlist);
 		if (err == 0)
 			perf_session__set_id_hdr_size(session);
 		return err;
-	case PERF_RECORD_HEADER_EVENT_TYPE:
-		return tool->event_type(tool, event);
 	case PERF_RECORD_HEADER_TRACING_DATA:
 		/* setup for reading amidst mmap */
 		lseek(session->fd, file_offset, SEEK_SET);
-		return tool->tracing_data(event, session);
+		return tool->tracing_data(tool, event, session);
 	case PERF_RECORD_HEADER_BUILD_ID:
 		return tool->build_id(tool, event, session);
 	case PERF_RECORD_FINISHED_ROUND:
@@ -975,10 +1061,6 @@
 	if (ret)
 		return ret;
 
-	/* Preprocess sample records - precheck callchains */
-	if (perf_session__preprocess_sample(session, event, &sample))
-		return 0;
-
 	if (tool->ordered_samples) {
 		ret = perf_session_queue_event(session, event, &sample,
 					       file_offset);
@@ -999,7 +1081,7 @@
 
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 {
-	return machine__findnew_thread(&session->machines.host, pid);
+	return machine__findnew_thread(&session->machines.host, 0, pid);
 }
 
 static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1091,8 +1173,10 @@
 		perf_event_header__bswap(&event->header);
 
 	size = event->header.size;
-	if (size == 0)
-		size = 8;
+	if (size < sizeof(struct perf_event_header)) {
+		pr_err("bad event header size\n");
+		goto out_err;
+	}
 
 	if (size > cur_size) {
 		void *new = realloc(buf, size);
@@ -1161,8 +1245,12 @@
 	if (session->header.needs_swap)
 		perf_event_header__bswap(&event->header);
 
-	if (head + event->header.size > mmap_size)
+	if (head + event->header.size > mmap_size) {
+		/* We're not fetching the event so swap back again */
+		if (session->header.needs_swap)
+			perf_event_header__bswap(&event->header);
 		return NULL;
+	}
 
 	return event;
 }
@@ -1242,7 +1330,7 @@
 
 	size = event->header.size;
 
-	if (size == 0 ||
+	if (size < sizeof(struct perf_event_header) ||
 	    perf_session__process_event(session, event, tool, file_pos) < 0) {
 		pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
 		       file_offset + head, event->header.size,
@@ -1295,12 +1383,15 @@
 
 bool perf_session__has_traces(struct perf_session *session, const char *msg)
 {
-	if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) {
-		pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
-		return false;
+	struct perf_evsel *evsel;
+
+	list_for_each_entry(evsel, &session->evlist->entries, node) {
+		if (evsel->attr.type == PERF_TYPE_TRACEPOINT)
+			return true;
 	}
 
-	return true;
+	pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
+	return false;
 }
 
 int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
@@ -1383,13 +1474,18 @@
 
 void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
 			  struct perf_sample *sample, struct machine *machine,
-			  int print_sym, int print_dso, int print_symoffset)
+			  unsigned int print_opts, unsigned int stack_depth)
 {
 	struct addr_location al;
 	struct callchain_cursor_node *node;
+	int print_ip = print_opts & PRINT_IP_OPT_IP;
+	int print_sym = print_opts & PRINT_IP_OPT_SYM;
+	int print_dso = print_opts & PRINT_IP_OPT_DSO;
+	int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
+	int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
+	char s = print_oneline ? ' ' : '\t';
 
-	if (perf_event__preprocess_sample(event, machine, &al, sample,
-					  NULL) < 0) {
+	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
 		error("problem processing %d event, skipping it.\n",
 			event->header.type);
 		return;
@@ -1397,37 +1493,50 @@
 
 	if (symbol_conf.use_callchain && sample->callchain) {
 
-
 		if (machine__resolve_callchain(machine, evsel, al.thread,
-					       sample, NULL) != 0) {
+					       sample, NULL, NULL) != 0) {
 			if (verbose)
 				error("Failed to resolve callchain. Skipping\n");
 			return;
 		}
 		callchain_cursor_commit(&callchain_cursor);
 
-		while (1) {
+		while (stack_depth) {
 			node = callchain_cursor_current(&callchain_cursor);
 			if (!node)
 				break;
 
-			printf("\t%16" PRIx64, node->ip);
+			if (print_ip)
+				printf("%c%16" PRIx64, s, node->ip);
+
 			if (print_sym) {
 				printf(" ");
-				symbol__fprintf_symname(node->sym, stdout);
+				if (print_symoffset) {
+					al.addr = node->ip;
+					al.map  = node->map;
+					symbol__fprintf_symname_offs(node->sym, &al, stdout);
+				} else
+					symbol__fprintf_symname(node->sym, stdout);
 			}
+
 			if (print_dso) {
 				printf(" (");
 				map__fprintf_dsoname(node->map, stdout);
 				printf(")");
 			}
-			printf("\n");
+
+			if (!print_oneline)
+				printf("\n");
 
 			callchain_cursor_advance(&callchain_cursor);
+
+			stack_depth--;
 		}
 
 	} else {
-		printf("%16" PRIx64, sample->ip);
+		if (print_ip)
+			printf("%16" PRIx64, sample->ip);
+
 		if (print_sym) {
 			printf(" ");
 			if (print_symoffset)
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index f3b235e..3aa75fb 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -37,11 +37,16 @@
 	int			fd;
 	bool			fd_pipe;
 	bool			repipe;
-	char			*cwd;
 	struct ordered_samples	ordered_samples;
 	char			filename[1];
 };
 
+#define PRINT_IP_OPT_IP		(1<<0)
+#define PRINT_IP_OPT_SYM		(1<<1)
+#define PRINT_IP_OPT_DSO		(1<<2)
+#define PRINT_IP_OPT_SYMOFFSET	(1<<3)
+#define PRINT_IP_OPT_ONELINE	(1<<4)
+
 struct perf_tool;
 
 struct perf_session *perf_session__new(const char *filename, int mode,
@@ -57,6 +62,11 @@
 int perf_session__process_events(struct perf_session *self,
 				 struct perf_tool *tool);
 
+int perf_session_queue_event(struct perf_session *s, union perf_event *event,
+			     struct perf_sample *sample, u64 file_offset);
+
+void perf_tool__fill_defaults(struct perf_tool *tool);
+
 int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel,
 				    struct thread *thread,
 				    struct ip_callchain *chain,
@@ -99,7 +109,7 @@
 
 void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
 			  struct perf_sample *sample, struct machine *machine,
-			  int print_sym, int print_dso, int print_symoffset);
+			  unsigned int print_opts, unsigned int stack_depth);
 
 int perf_session__cpu_bitmap(struct perf_session *session,
 			     const char *cpu_list, unsigned long *cpu_bitmap);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 313a5a7..5f118a0 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -7,6 +7,8 @@
 const char	*parent_pattern = default_parent_pattern;
 const char	default_sort_order[] = "comm,dso,symbol";
 const char	*sort_order = default_sort_order;
+regex_t		ignore_callees_regex;
+int		have_ignore_callees = 0;
 int		sort__need_collapse = 0;
 int		sort__has_parent = 0;
 int		sort__has_sym = 0;
@@ -55,14 +57,14 @@
 static int64_t
 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 {
-	return right->thread->pid - left->thread->pid;
+	return right->thread->tid - left->thread->tid;
 }
 
 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
 				       size_t size, unsigned int width)
 {
 	return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
-			      self->thread->comm ?: "", self->thread->pid);
+			      self->thread->comm ?: "", self->thread->tid);
 }
 
 struct sort_entry sort_thread = {
@@ -77,7 +79,7 @@
 static int64_t
 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 {
-	return right->thread->pid - left->thread->pid;
+	return right->thread->tid - left->thread->tid;
 }
 
 static int64_t
@@ -872,6 +874,8 @@
 	DIM(SORT_PARENT, "parent", sort_parent),
 	DIM(SORT_CPU, "cpu", sort_cpu),
 	DIM(SORT_SRCLINE, "srcline", sort_srcline),
+	DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
+	DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
 };
 
 #undef DIM
@@ -891,8 +895,6 @@
 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
 
 static struct sort_dimension memory_sort_dimensions[] = {
-	DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
-	DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
 	DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
 	DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
 	DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 45ac84c..4e80dbd 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -29,6 +29,8 @@
 extern const char default_parent_pattern[];
 extern const char *parent_pattern;
 extern const char default_sort_order[];
+extern regex_t ignore_callees_regex;
+extern int have_ignore_callees;
 extern int sort__need_collapse;
 extern int sort__has_parent;
 extern int sort__has_sym;
@@ -87,6 +89,9 @@
 
 	struct hist_entry_diff	diff;
 
+	/* We are added by hists__add_dummy_entry. */
+	bool			dummy;
+
 	/* XXX These two should move to some tree widget lib */
 	u16			row_offset;
 	u16			nr_rows;
@@ -138,6 +143,8 @@
 	SORT_PARENT,
 	SORT_CPU,
 	SORT_SRCLINE,
+	SORT_LOCAL_WEIGHT,
+	SORT_GLOBAL_WEIGHT,
 
 	/* branch stack specific sort keys */
 	__SORT_BRANCH_STACK,
@@ -149,9 +156,7 @@
 
 	/* memory mode specific sort keys */
 	__SORT_MEMORY_MODE,
-	SORT_LOCAL_WEIGHT = __SORT_MEMORY_MODE,
-	SORT_GLOBAL_WEIGHT,
-	SORT_MEM_DADDR_SYMBOL,
+	SORT_MEM_DADDR_SYMBOL = __SORT_MEMORY_MODE,
 	SORT_MEM_DADDR_DSO,
 	SORT_MEM_LOCKED,
 	SORT_MEM_TLB,
@@ -183,4 +188,6 @@
 extern int sort_dimension__add(const char *);
 void sort__setup_elide(FILE *fp);
 
+int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
+
 #endif	/* __PERF_SORT_H */
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 7c59c28..6506b3d 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -10,6 +10,12 @@
 	delta = val - stats->mean;
 	stats->mean += delta / stats->n;
 	stats->M2 += delta*(val - stats->mean);
+
+	if (val > stats->max)
+		stats->max = val;
+
+	if (val < stats->min)
+		stats->min = val;
 }
 
 double avg_stats(struct stats *stats)
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 588367c..ae8ccd7 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -6,6 +6,7 @@
 struct stats
 {
 	double n, mean, M2;
+	u64 max, min;
 };
 
 void update_stats(struct stats *stats, u64 val);
@@ -13,4 +14,12 @@
 double stddev_stats(struct stats *stats);
 double rel_stddev_stats(double stddev, double avg);
 
+static inline void init_stats(struct stats *stats)
+{
+	stats->n    = 0.0;
+	stats->mean = 0.0;
+	stats->M2   = 0.0;
+	stats->min  = (u64) -1;
+	stats->max  = 0;
+}
 #endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 29c7b2c..f0b0c00 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -387,3 +387,27 @@
 
 	return p;
 }
+
+/**
+ * str_append - reallocate string and append another
+ * @s: pointer to string pointer
+ * @len: pointer to len (initialized)
+ * @a: string to append.
+ */
+int str_append(char **s, int *len, const char *a)
+{
+	int olen = *s ? strlen(*s) : 0;
+	int nlen = olen + strlen(a) + 1;
+	if (*len < nlen) {
+		*len = *len * 2;
+		if (*len < nlen)
+			*len = nlen;
+		*s = realloc(*s, *len);
+		if (!*s)
+			return -ENOMEM;
+		if (olen == 0)
+			**s = 0;
+	}
+	strcat(*s, a);
+	return 0;
+}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4b12bf8..a7b9ab5 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -599,11 +599,13 @@
 	if (dso->kernel == DSO_TYPE_USER) {
 		GElf_Shdr shdr;
 		ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
+				ehdr.e_type == ET_REL ||
 				elf_section_by_name(elf, &ehdr, &shdr,
 						     ".gnu.prelink_undo",
 						     NULL) != NULL);
 	} else {
-		ss->adjust_symbols = 0;
+		ss->adjust_symbols = ehdr.e_type == ET_EXEC ||
+				     ehdr.e_type == ET_REL;
 	}
 
 	ss->name   = strdup(name);
@@ -624,6 +626,37 @@
 	return err;
 }
 
+/**
+ * ref_reloc_sym_not_found - has kernel relocation symbol been found.
+ * @kmap: kernel maps and relocation reference symbol
+ *
+ * This function returns %true if we are dealing with the kernel maps and the
+ * relocation reference symbol has not yet been found.  Otherwise %false is
+ * returned.
+ */
+static bool ref_reloc_sym_not_found(struct kmap *kmap)
+{
+	return kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
+	       !kmap->ref_reloc_sym->unrelocated_addr;
+}
+
+/**
+ * ref_reloc - kernel relocation offset.
+ * @kmap: kernel maps and relocation reference symbol
+ *
+ * This function returns the offset of kernel addresses as determined by using
+ * the relocation reference symbol i.e. if the kernel has not been relocated
+ * then the return value is zero.
+ */
+static u64 ref_reloc(struct kmap *kmap)
+{
+	if (kmap && kmap->ref_reloc_sym &&
+	    kmap->ref_reloc_sym->unrelocated_addr)
+		return kmap->ref_reloc_sym->addr -
+		       kmap->ref_reloc_sym->unrelocated_addr;
+	return 0;
+}
+
 int dso__load_sym(struct dso *dso, struct map *map,
 		  struct symsrc *syms_ss, struct symsrc *runtime_ss,
 		  symbol_filter_t filter, int kmodule)
@@ -642,8 +675,17 @@
 	Elf_Scn *sec, *sec_strndx;
 	Elf *elf;
 	int nr = 0;
+	bool remap_kernel = false, adjust_kernel_syms = false;
 
 	dso->symtab_type = syms_ss->type;
+	dso->rel = syms_ss->ehdr.e_type == ET_REL;
+
+	/*
+	 * Modules may already have symbols from kallsyms, but those symbols
+	 * have the wrong values for the dso maps, so remove them.
+	 */
+	if (kmodule && syms_ss->symtab)
+		symbols__delete(&dso->symbols[map->type]);
 
 	if (!syms_ss->symtab) {
 		syms_ss->symtab  = syms_ss->dynsym;
@@ -681,7 +723,31 @@
 	nr_syms = shdr.sh_size / shdr.sh_entsize;
 
 	memset(&sym, 0, sizeof(sym));
-	dso->adjust_symbols = runtime_ss->adjust_symbols;
+
+	/*
+	 * The kernel relocation symbol is needed in advance in order to adjust
+	 * kernel maps correctly.
+	 */
+	if (ref_reloc_sym_not_found(kmap)) {
+		elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
+			const char *elf_name = elf_sym__name(&sym, symstrs);
+
+			if (strcmp(elf_name, kmap->ref_reloc_sym->name))
+				continue;
+			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
+			break;
+		}
+	}
+
+	dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap);
+	/*
+	 * Initial kernel and module mappings do not map to the dso.  For
+	 * function mappings, flag the fixups.
+	 */
+	if (map->type == MAP__FUNCTION && (dso->kernel || kmodule)) {
+		remap_kernel = true;
+		adjust_kernel_syms = dso->adjust_symbols;
+	}
 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
 		struct symbol *f;
 		const char *elf_name = elf_sym__name(&sym, symstrs);
@@ -690,10 +756,6 @@
 		const char *section_name;
 		bool used_opd = false;
 
-		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
-		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
-			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
-
 		if (!is_label && !elf_sym__is_a(&sym, map->type))
 			continue;
 
@@ -745,20 +807,55 @@
 		    (sym.st_value & 1))
 			--sym.st_value;
 
-		if (dso->kernel != DSO_TYPE_USER || kmodule) {
+		if (dso->kernel || kmodule) {
 			char dso_name[PATH_MAX];
 
+			/* Adjust symbol to map to file offset */
+			if (adjust_kernel_syms)
+				sym.st_value -= shdr.sh_addr - shdr.sh_offset;
+
 			if (strcmp(section_name,
 				   (curr_dso->short_name +
 				    dso->short_name_len)) == 0)
 				goto new_symbol;
 
 			if (strcmp(section_name, ".text") == 0) {
+				/*
+				 * The initial kernel mapping is based on
+				 * kallsyms and identity maps.  Overwrite it to
+				 * map to the kernel dso.
+				 */
+				if (remap_kernel && dso->kernel) {
+					remap_kernel = false;
+					map->start = shdr.sh_addr +
+						     ref_reloc(kmap);
+					map->end = map->start + shdr.sh_size;
+					map->pgoff = shdr.sh_offset;
+					map->map_ip = map__map_ip;
+					map->unmap_ip = map__unmap_ip;
+					/* Ensure maps are correctly ordered */
+					map_groups__remove(kmap->kmaps, map);
+					map_groups__insert(kmap->kmaps, map);
+				}
+
+				/*
+				 * The initial module mapping is based on
+				 * /proc/modules mapped to offset zero.
+				 * Overwrite it to map to the module dso.
+				 */
+				if (remap_kernel && kmodule) {
+					remap_kernel = false;
+					map->pgoff = shdr.sh_offset;
+				}
+
 				curr_map = map;
 				curr_dso = dso;
 				goto new_symbol;
 			}
 
+			if (!kmap)
+				goto new_symbol;
+
 			snprintf(dso_name, sizeof(dso_name),
 				 "%s%s", dso->short_name, section_name);
 
@@ -781,8 +878,16 @@
 					dso__delete(curr_dso);
 					goto out_elf_end;
 				}
-				curr_map->map_ip = identity__map_ip;
-				curr_map->unmap_ip = identity__map_ip;
+				if (adjust_kernel_syms) {
+					curr_map->start = shdr.sh_addr +
+							  ref_reloc(kmap);
+					curr_map->end = curr_map->start +
+							shdr.sh_size;
+					curr_map->pgoff = shdr.sh_offset;
+				} else {
+					curr_map->map_ip = identity__map_ip;
+					curr_map->unmap_ip = identity__map_ip;
+				}
 				curr_dso->symtab_type = dso->symtab_type;
 				map_groups__insert(kmap->kmaps, curr_map);
 				dsos__add(&dso->node, curr_dso);
@@ -846,6 +951,57 @@
 	return err;
 }
 
+static int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data)
+{
+	GElf_Phdr phdr;
+	size_t i, phdrnum;
+	int err;
+	u64 sz;
+
+	if (elf_getphdrnum(elf, &phdrnum))
+		return -1;
+
+	for (i = 0; i < phdrnum; i++) {
+		if (gelf_getphdr(elf, i, &phdr) == NULL)
+			return -1;
+		if (phdr.p_type != PT_LOAD)
+			continue;
+		if (exe) {
+			if (!(phdr.p_flags & PF_X))
+				continue;
+		} else {
+			if (!(phdr.p_flags & PF_R))
+				continue;
+		}
+		sz = min(phdr.p_memsz, phdr.p_filesz);
+		if (!sz)
+			continue;
+		err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
+		    bool *is_64_bit)
+{
+	int err;
+	Elf *elf;
+
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL)
+		return -1;
+
+	if (is_64_bit)
+		*is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
+
+	err = elf_read_maps(elf, exe, mapfn, data);
+
+	elf_end(elf);
+	return err;
+}
+
 void symbol__elf_init(void)
 {
 	elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index a7390cd..3a802c3 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -301,6 +301,13 @@
 	return 0;
 }
 
+int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
+		    mapfn_t mapfn __maybe_unused, void *data __maybe_unused,
+		    bool *is_64_bit __maybe_unused)
+{
+	return -1;
+}
+
 void symbol__elf_init(void)
 {
 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d5528e1..7eb0362 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -87,6 +87,7 @@
 {
 	s64 a;
 	s64 b;
+	size_t na, nb;
 
 	/* Prefer a symbol with non zero length */
 	a = syma->end - syma->start;
@@ -120,11 +121,21 @@
 	else if (a > b)
 		return SYMBOL_B;
 
-	/* If all else fails, choose the symbol with the longest name */
-	if (strlen(syma->name) >= strlen(symb->name))
+	/* Choose the symbol with the longest name */
+	na = strlen(syma->name);
+	nb = strlen(symb->name);
+	if (na > nb)
 		return SYMBOL_A;
-	else
+	else if (na < nb)
 		return SYMBOL_B;
+
+	/* Avoid "SyS" kernel syscall aliases */
+	if (na >= 3 && !strncmp(syma->name, "SyS", 3))
+		return SYMBOL_B;
+	if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10))
+		return SYMBOL_B;
+
+	return SYMBOL_A;
 }
 
 void symbols__fixup_duplicate(struct rb_root *symbols)
@@ -248,7 +259,10 @@
 	if (sym && sym->name) {
 		length = fprintf(fp, "%s", sym->name);
 		if (al) {
-			offset = al->addr - sym->start;
+			if (al->addr < sym->end)
+				offset = al->addr - sym->start;
+			else
+				offset = al->addr - al->map->start - sym->start;
 			length += fprintf(fp, "+0x%lx", offset);
 		}
 		return length;
@@ -316,6 +330,16 @@
 	return NULL;
 }
 
+static struct symbol *symbols__first(struct rb_root *symbols)
+{
+	struct rb_node *n = rb_first(symbols);
+
+	if (n)
+		return rb_entry(n, struct symbol, rb_node);
+
+	return NULL;
+}
+
 struct symbol_name_rb_node {
 	struct rb_node	rb_node;
 	struct symbol	sym;
@@ -386,6 +410,11 @@
 	return symbols__find(&dso->symbols[type], addr);
 }
 
+struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
+{
+	return symbols__first(&dso->symbols[type]);
+}
+
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 					const char *name)
 {
@@ -522,6 +551,53 @@
 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
 }
 
+static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
+					 symbol_filter_t filter)
+{
+	struct map_groups *kmaps = map__kmap(map)->kmaps;
+	struct map *curr_map;
+	struct symbol *pos;
+	int count = 0, moved = 0;
+	struct rb_root *root = &dso->symbols[map->type];
+	struct rb_node *next = rb_first(root);
+
+	while (next) {
+		char *module;
+
+		pos = rb_entry(next, struct symbol, rb_node);
+		next = rb_next(&pos->rb_node);
+
+		module = strchr(pos->name, '\t');
+		if (module)
+			*module = '\0';
+
+		curr_map = map_groups__find(kmaps, map->type, pos->start);
+
+		if (!curr_map || (filter && filter(curr_map, pos))) {
+			rb_erase(&pos->rb_node, root);
+			symbol__delete(pos);
+		} else {
+			pos->start -= curr_map->start - curr_map->pgoff;
+			if (pos->end)
+				pos->end -= curr_map->start - curr_map->pgoff;
+			if (curr_map != map) {
+				rb_erase(&pos->rb_node, root);
+				symbols__insert(
+					&curr_map->dso->symbols[curr_map->type],
+					pos);
+				++moved;
+			} else {
+				++count;
+			}
+		}
+	}
+
+	/* Symbols have been adjusted */
+	dso->adjust_symbols = 1;
+
+	return count + moved;
+}
+
 /*
  * Split the symbols into maps, making sure there are no overlaps, i.e. the
  * kernel range is broken in several maps, named [kernel].N, as we don't have
@@ -663,6 +739,161 @@
 	return restricted;
 }
 
+struct kcore_mapfn_data {
+	struct dso *dso;
+	enum map_type type;
+	struct list_head maps;
+};
+
+static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
+{
+	struct kcore_mapfn_data *md = data;
+	struct map *map;
+
+	map = map__new2(start, md->dso, md->type);
+	if (map == NULL)
+		return -ENOMEM;
+
+	map->end = map->start + len;
+	map->pgoff = pgoff;
+
+	list_add(&map->node, &md->maps);
+
+	return 0;
+}
+
+/*
+ * If kallsyms is referenced by name then we look for kcore in the same
+ * directory.
+ */
+static bool kcore_filename_from_kallsyms_filename(char *kcore_filename,
+						  const char *kallsyms_filename)
+{
+	char *name;
+
+	strcpy(kcore_filename, kallsyms_filename);
+	name = strrchr(kcore_filename, '/');
+	if (!name)
+		return false;
+
+	if (!strcmp(name, "/kallsyms")) {
+		strcpy(name, "/kcore");
+		return true;
+	}
+
+	return false;
+}
+
+static int dso__load_kcore(struct dso *dso, struct map *map,
+			   const char *kallsyms_filename)
+{
+	struct map_groups *kmaps = map__kmap(map)->kmaps;
+	struct machine *machine = kmaps->machine;
+	struct kcore_mapfn_data md;
+	struct map *old_map, *new_map, *replacement_map = NULL;
+	bool is_64_bit;
+	int err, fd;
+	char kcore_filename[PATH_MAX];
+	struct symbol *sym;
+
+	/* This function requires that the map is the kernel map */
+	if (map != machine->vmlinux_maps[map->type])
+		return -EINVAL;
+
+	if (!kcore_filename_from_kallsyms_filename(kcore_filename,
+						   kallsyms_filename))
+		return -EINVAL;
+
+	md.dso = dso;
+	md.type = map->type;
+	INIT_LIST_HEAD(&md.maps);
+
+	fd = open(kcore_filename, O_RDONLY);
+	if (fd < 0)
+		return -EINVAL;
+
+	/* Read new maps into temporary lists */
+	err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
+			      &is_64_bit);
+	if (err)
+		goto out_err;
+
+	if (list_empty(&md.maps)) {
+		err = -EINVAL;
+		goto out_err;
+	}
+
+	/* Remove old maps */
+	old_map = map_groups__first(kmaps, map->type);
+	while (old_map) {
+		struct map *next = map_groups__next(old_map);
+
+		if (old_map != map)
+			map_groups__remove(kmaps, old_map);
+		old_map = next;
+	}
+
+	/* Find the kernel map using the first symbol */
+	sym = dso__first_symbol(dso, map->type);
+	list_for_each_entry(new_map, &md.maps, node) {
+		if (sym && sym->start >= new_map->start &&
+		    sym->start < new_map->end) {
+			replacement_map = new_map;
+			break;
+		}
+	}
+
+	if (!replacement_map)
+		replacement_map = list_entry(md.maps.next, struct map, node);
+
+	/* Add new maps */
+	while (!list_empty(&md.maps)) {
+		new_map = list_entry(md.maps.next, struct map, node);
+		list_del(&new_map->node);
+		if (new_map == replacement_map) {
+			map->start	= new_map->start;
+			map->end	= new_map->end;
+			map->pgoff	= new_map->pgoff;
+			map->map_ip	= new_map->map_ip;
+			map->unmap_ip	= new_map->unmap_ip;
+			map__delete(new_map);
+			/* Ensure maps are correctly ordered */
+			map_groups__remove(kmaps, map);
+			map_groups__insert(kmaps, map);
+		} else {
+			map_groups__insert(kmaps, new_map);
+		}
+	}
+
+	/*
+	 * Set the data type and long name so that kcore can be read via
+	 * dso__data_read_addr().
+	 */
+	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
+		dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE;
+	else
+		dso->data_type = DSO_BINARY_TYPE__KCORE;
+	dso__set_long_name(dso, strdup(kcore_filename));
+
+	close(fd);
+
+	if (map->type == MAP__FUNCTION)
+		pr_debug("Using %s for kernel object code\n", kcore_filename);
+	else
+		pr_debug("Using %s for kernel data\n", kcore_filename);
+
+	return 0;
+
+out_err:
+	while (!list_empty(&md.maps)) {
+		map = list_entry(md.maps.next, struct map, node);
+		list_del(&map->node);
+		map__delete(map);
+	}
+	close(fd);
+	return -EINVAL;
+}
+
 int dso__load_kallsyms(struct dso *dso, const char *filename,
 		       struct map *map, symbol_filter_t filter)
 {
@@ -680,7 +911,10 @@
 	else
 		dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
 
-	return dso__split_kallsyms(dso, map, filter);
+	if (!dso__load_kcore(dso, map, filename))
+		return dso__split_kallsyms_for_kcore(dso, map, filter);
+	else
+		return dso__split_kallsyms(dso, map, filter);
 }
 
 static int dso__load_perf_map(struct dso *dso, struct map *map,
@@ -843,10 +1077,15 @@
 	if (!runtime_ss && syms_ss)
 		runtime_ss = syms_ss;
 
-	if (syms_ss)
-		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0);
-	else
+	if (syms_ss) {
+		int km;
+
+		km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+		     dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+		ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
+	} else {
 		ret = -1;
+	}
 
 	if (ret > 0) {
 		int nr_plt;
@@ -888,8 +1127,11 @@
 	char symfs_vmlinux[PATH_MAX];
 	enum dso_binary_type symtab_type;
 
-	snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
-		 symbol_conf.symfs, vmlinux);
+	if (vmlinux[0] == '/')
+		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
+	else
+		snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
+			 symbol_conf.symfs, vmlinux);
 
 	if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
 		symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
@@ -903,6 +1145,10 @@
 	symsrc__destroy(&ss);
 
 	if (err > 0) {
+		if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
+			dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
+		else
+			dso->data_type = DSO_BINARY_TYPE__VMLINUX;
 		dso__set_long_name(dso, (char *)vmlinux);
 		dso__set_loaded(dso, map->type);
 		pr_debug("Using %s for symbols\n", symfs_vmlinux);
@@ -975,7 +1221,7 @@
 			dso__set_long_name(dso,
 					   strdup(symbol_conf.vmlinux_name));
 			dso->lname_alloc = 1;
-			goto out_fixup;
+			return err;
 		}
 		return err;
 	}
@@ -983,7 +1229,7 @@
 	if (vmlinux_path != NULL) {
 		err = dso__load_vmlinux_path(dso, map, filter);
 		if (err > 0)
-			goto out_fixup;
+			return err;
 	}
 
 	/* do not try local files if a symfs was given */
@@ -1042,9 +1288,8 @@
 		pr_debug("Using %s for symbols\n", kallsyms_filename);
 	free(kallsyms_allocated_filename);
 
-	if (err > 0) {
+	if (err > 0 && !dso__is_kcore(dso)) {
 		dso__set_long_name(dso, strdup("[kernel.kallsyms]"));
-out_fixup:
 		map__fixup_start(map);
 		map__fixup_end(map);
 	}
@@ -1075,7 +1320,7 @@
 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
 			err = dso__load_vmlinux(dso, map,
 				symbol_conf.default_guest_vmlinux_name, filter);
-			goto out_try_fixup;
+			return err;
 		}
 
 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
@@ -1089,13 +1334,9 @@
 	err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
 	if (err > 0)
 		pr_debug("Using %s for symbols\n", kallsyms_filename);
-
-out_try_fixup:
-	if (err > 0) {
-		if (kallsyms_filename != NULL) {
-			machine__mmap_name(machine, path, sizeof(path));
-			dso__set_long_name(dso, strdup(path));
-		}
+	if (err > 0 && !dso__is_kcore(dso)) {
+		machine__mmap_name(machine, path, sizeof(path));
+		dso__set_long_name(dso, strdup(path));
 		map__fixup_start(map);
 		map__fixup_end(map);
 	}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5f720dc..fd5b70e 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -215,6 +215,7 @@
 				u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
 					const char *name);
+struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
 
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
@@ -247,4 +248,8 @@
 void symbols__fixup_end(struct rb_root *symbols);
 void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
 
+typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
+int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
+		    bool *is_64_bit);
+
 #endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 40399cb..e3d4a55 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,17 +7,18 @@
 #include "util.h"
 #include "debug.h"
 
-struct thread *thread__new(pid_t pid)
+struct thread *thread__new(pid_t pid, pid_t tid)
 {
 	struct thread *self = zalloc(sizeof(*self));
 
 	if (self != NULL) {
 		map_groups__init(&self->mg);
-		self->pid = pid;
+		self->pid_ = pid;
+		self->tid = tid;
 		self->ppid = -1;
 		self->comm = malloc(32);
 		if (self->comm)
-			snprintf(self->comm, 32, ":%d", self->pid);
+			snprintf(self->comm, 32, ":%d", self->tid);
 	}
 
 	return self;
@@ -57,7 +58,7 @@
 
 size_t thread__fprintf(struct thread *thread, FILE *fp)
 {
-	return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
+	return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) +
 	       map_groups__fprintf(&thread->mg, verbose, fp);
 }
 
@@ -84,7 +85,7 @@
 		if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
 			return -ENOMEM;
 
-	self->ppid = parent->pid;
+	self->ppid = parent->tid;
 
 	return 0;
 }
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index eeb7ac6..4ebbb40 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -12,10 +12,12 @@
 		struct list_head node;
 	};
 	struct map_groups	mg;
-	pid_t			pid;
+	pid_t			pid_; /* Not all tools update this */
+	pid_t			tid;
 	pid_t			ppid;
 	char			shortname[3];
 	bool			comm_set;
+	bool			dead; /* if set thread has exited */
 	char			*comm;
 	int			comm_len;
 
@@ -24,8 +26,12 @@
 
 struct machine;
 
-struct thread *thread__new(pid_t pid);
+struct thread *thread__new(pid_t pid, pid_t tid);
 void thread__delete(struct thread *self);
+static inline void thread__exited(struct thread *thread)
+{
+	thread->dead = true;
+}
 
 int thread__set_comm(struct thread *self, const char *comm);
 int thread__comm_len(struct thread *self);
@@ -45,6 +51,15 @@
 
 void thread__find_addr_location(struct thread *thread, struct machine *machine,
 				u8 cpumode, enum map_type type, u64 addr,
-				struct addr_location *al,
-				symbol_filter_t filter);
+				struct addr_location *al);
+
+static inline void *thread__priv(struct thread *thread)
+{
+	return thread->priv;
+}
+
+static inline void thread__set_priv(struct thread *thread, void *p)
+{
+	thread->priv = p;
+}
 #endif	/* __PERF_THREAD_H */
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index b0e1aad..62b16b6 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -18,12 +18,9 @@
 typedef int (*event_op)(struct perf_tool *tool, union perf_event *event,
 			struct perf_sample *sample, struct machine *machine);
 
-typedef int (*event_attr_op)(union perf_event *event,
+typedef int (*event_attr_op)(struct perf_tool *tool,
+			     union perf_event *event,
 			     struct perf_evlist **pevlist);
-typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
-
-typedef int (*event_synth_op)(union perf_event *event,
-			      struct perf_session *session);
 
 typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
 			 struct perf_session *session);
@@ -39,8 +36,7 @@
 			throttle,
 			unthrottle;
 	event_attr_op	attr;
-	event_synth_op	tracing_data;
-	event_simple_op	event_type;
+	event_op2	tracing_data;
 	event_op2	finished_round,
 			build_id;
 	bool		ordered_samples;
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index df46be9..b554ffc 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -39,6 +39,8 @@
 	float		   min_percent;
 };
 
+#define CONSOLE_CLEAR ""
+
 size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
 void perf_top__reset_sample_counters(struct perf_top *top);
 #endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 3917eb9..f3c9e55 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -46,65 +46,6 @@
 static int output_fd;
 
 
-static const char *find_debugfs(void)
-{
-	const char *path = perf_debugfs_mount(NULL);
-
-	if (!path)
-		pr_debug("Your kernel does not support the debugfs filesystem");
-
-	return path;
-}
-
-/*
- * Finds the path to the debugfs/tracing
- * Allocates the string and stores it.
- */
-static const char *find_tracing_dir(void)
-{
-	static char *tracing;
-	static int tracing_found;
-	const char *debugfs;
-
-	if (tracing_found)
-		return tracing;
-
-	debugfs = find_debugfs();
-	if (!debugfs)
-		return NULL;
-
-	tracing = malloc(strlen(debugfs) + 9);
-	if (!tracing)
-		return NULL;
-
-	sprintf(tracing, "%s/tracing", debugfs);
-
-	tracing_found = 1;
-	return tracing;
-}
-
-static char *get_tracing_file(const char *name)
-{
-	const char *tracing;
-	char *file;
-
-	tracing = find_tracing_dir();
-	if (!tracing)
-		return NULL;
-
-	file = malloc(strlen(tracing) + strlen(name) + 2);
-	if (!file)
-		return NULL;
-
-	sprintf(file, "%s/%s", tracing, name);
-	return file;
-}
-
-static void put_tracing_file(char *file)
-{
-	free(file);
-}
-
 int bigendian(void)
 {
 	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -160,7 +101,7 @@
 	return err;
 }
 
-static int read_header_files(void)
+static int record_header_files(void)
 {
 	char *path;
 	struct stat st;
@@ -299,7 +240,7 @@
 	return err;
 }
 
-static int read_ftrace_files(struct tracepoint_path *tps)
+static int record_ftrace_files(struct tracepoint_path *tps)
 {
 	char *path;
 	int ret;
@@ -328,7 +269,7 @@
 	return false;
 }
 
-static int read_event_files(struct tracepoint_path *tps)
+static int record_event_files(struct tracepoint_path *tps)
 {
 	struct dirent *dent;
 	struct stat st;
@@ -403,7 +344,7 @@
 	return err;
 }
 
-static int read_proc_kallsyms(void)
+static int record_proc_kallsyms(void)
 {
 	unsigned int size;
 	const char *path = "/proc/kallsyms";
@@ -421,7 +362,7 @@
 	return record_file(path, 4);
 }
 
-static int read_ftrace_printk(void)
+static int record_ftrace_printk(void)
 {
 	unsigned int size;
 	char *path;
@@ -473,12 +414,27 @@
 		if (pos->attr.type != PERF_TYPE_TRACEPOINT)
 			continue;
 		++nr_tracepoints;
+
+		if (pos->name) {
+			ppath->next = tracepoint_name_to_path(pos->name);
+			if (ppath->next)
+				goto next;
+
+			if (strchr(pos->name, ':') == NULL)
+				goto try_id;
+
+			goto error;
+		}
+
+try_id:
 		ppath->next = tracepoint_id_to_path(pos->attr.config);
 		if (!ppath->next) {
+error:
 			pr_debug("No memory to alloc tracepoints list\n");
 			put_tracepoints_path(&path);
 			return NULL;
 		}
+next:
 		ppath = ppath->next;
 	}
 
@@ -520,8 +476,6 @@
 	else
 		buf[0] = 0;
 
-	read_trace_init(buf[0], buf[0]);
-
 	if (write(output_fd, buf, 1) != 1)
 		return -1;
 
@@ -583,19 +537,19 @@
 	err = tracing_data_header();
 	if (err)
 		goto out;
-	err = read_header_files();
+	err = record_header_files();
 	if (err)
 		goto out;
-	err = read_ftrace_files(tps);
+	err = record_ftrace_files(tps);
 	if (err)
 		goto out;
-	err = read_event_files(tps);
+	err = record_event_files(tps);
 	if (err)
 		goto out;
-	err = read_proc_kallsyms();
+	err = record_proc_kallsyms();
 	if (err)
 		goto out;
-	err = read_ftrace_printk();
+	err = record_ftrace_printk();
 
 out:
 	/*
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 4454835..fe7a27d 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -28,12 +28,6 @@
 #include "util.h"
 #include "trace-event.h"
 
-int header_page_size_size;
-int header_page_ts_size;
-int header_page_data_offset;
-
-bool latency_format;
-
 struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
 {
 	struct pevent *pevent = pevent_alloc();
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index af215c0..f211227 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -39,10 +39,6 @@
 
 static int input_fd;
 
-int file_bigendian;
-int host_bigendian;
-static int long_size;
-
 static ssize_t trace_data_size;
 static bool repipe;
 
@@ -216,7 +212,7 @@
 static int read_header_files(struct pevent *pevent)
 {
 	unsigned long long size;
-	char *header_event;
+	char *header_page;
 	char buf[BUFSIZ];
 	int ret = 0;
 
@@ -229,13 +225,26 @@
 	}
 
 	size = read8(pevent);
-	skip(size);
 
-	/*
-	 * The size field in the page is of type long,
-	 * use that instead, since it represents the kernel.
-	 */
-	long_size = header_page_size_size;
+	header_page = malloc(size);
+	if (header_page == NULL)
+		return -1;
+
+	if (do_read(header_page, size) < 0) {
+		pr_debug("did not read header page");
+		free(header_page);
+		return -1;
+	}
+
+	if (!pevent_parse_header_page(pevent, header_page, size,
+				      pevent_get_long_size(pevent))) {
+		/*
+		 * The commit field in the page is of type long,
+		 * use that instead, since it represents the kernel.
+		 */
+		pevent_set_long_size(pevent, pevent->header_page_size_size);
+	}
+	free(header_page);
 
 	if (do_read(buf, 13) < 0)
 		return -1;
@@ -246,14 +255,8 @@
 	}
 
 	size = read8(pevent);
-	header_event = malloc(size);
-	if (header_event == NULL)
-		return -1;
+	skip(size);
 
-	if (do_read(header_event, size) < 0)
-		ret = -1;
-
-	free(header_event);
 	return ret;
 }
 
@@ -349,6 +352,10 @@
 	int show_funcs = 0;
 	int show_printk = 0;
 	ssize_t size = -1;
+	int file_bigendian;
+	int host_bigendian;
+	int file_long_size;
+	int file_page_size;
 	struct pevent *pevent;
 	int err;
 
@@ -391,12 +398,15 @@
 
 	if (do_read(buf, 1) < 0)
 		goto out;
-	long_size = buf[0];
+	file_long_size = buf[0];
 
-	page_size = read4(pevent);
-	if (!page_size)
+	file_page_size = read4(pevent);
+	if (!file_page_size)
 		goto out;
 
+	pevent_set_long_size(pevent, file_long_size);
+	pevent_set_page_size(pevent, file_page_size);
+
 	err = read_header_files(pevent);
 	if (err)
 		goto out;
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 8715a10..95199e4 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -39,7 +39,8 @@
 				      struct perf_sample *sample __maybe_unused,
 				      struct perf_evsel *evsel __maybe_unused,
 				      struct machine *machine __maybe_unused,
-				      struct addr_location *al __maybe_unused)
+				      struct thread *thread __maybe_unused,
+					  struct addr_location *al __maybe_unused)
 {
 }
 
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 1978c39..fafe1a4 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,32 +1,18 @@
 #ifndef _PERF_UTIL_TRACE_EVENT_H
 #define _PERF_UTIL_TRACE_EVENT_H
 
+#include <traceevent/event-parse.h>
 #include "parse-events.h"
-#include "event-parse.h"
 #include "session.h"
 
 struct machine;
 struct perf_sample;
 union perf_event;
 struct perf_tool;
+struct thread;
 
-extern int header_page_size_size;
-extern int header_page_ts_size;
-extern int header_page_data_offset;
-
-extern bool latency_format;
 extern struct pevent *perf_pevent;
 
-enum {
-	RINGBUF_TYPE_PADDING		= 29,
-	RINGBUF_TYPE_TIME_EXTEND	= 30,
-	RINGBUF_TYPE_TIME_STAMP		= 31,
-};
-
-#ifndef TS_SHIFT
-#define TS_SHIFT		27
-#endif
-
 int bigendian(void);
 
 struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
@@ -83,7 +69,8 @@
 			       struct perf_sample *sample,
 			       struct perf_evsel *evsel,
 			       struct machine *machine,
-			       struct addr_location *al);
+			       struct thread *thread,
+				   struct addr_location *al);
 	int (*generate_script) (struct pevent *pevent, const char *outfile);
 };
 
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 958723b..2f891f7 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -473,7 +473,7 @@
 
 	thread__find_addr_location(thread, machine,
 				   PERF_RECORD_MISC_USER,
-				   MAP__FUNCTION, ip, &al, NULL);
+				   MAP__FUNCTION, ip, &al);
 
 	e.ip = ip;
 	e.map = al.map;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 59d868a..6d17b18 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -269,3 +269,95 @@
 	snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
 	set_tracing_events_path(mntpt);
 }
+
+static const char *find_debugfs(void)
+{
+	const char *path = perf_debugfs_mount(NULL);
+
+	if (!path)
+		fprintf(stderr, "Your kernel does not support the debugfs filesystem");
+
+	return path;
+}
+
+/*
+ * Finds the path to the debugfs/tracing
+ * Allocates the string and stores it.
+ */
+const char *find_tracing_dir(void)
+{
+	static char *tracing;
+	static int tracing_found;
+	const char *debugfs;
+
+	if (tracing_found)
+		return tracing;
+
+	debugfs = find_debugfs();
+	if (!debugfs)
+		return NULL;
+
+	tracing = malloc(strlen(debugfs) + 9);
+	if (!tracing)
+		return NULL;
+
+	sprintf(tracing, "%s/tracing", debugfs);
+
+	tracing_found = 1;
+	return tracing;
+}
+
+char *get_tracing_file(const char *name)
+{
+	const char *tracing;
+	char *file;
+
+	tracing = find_tracing_dir();
+	if (!tracing)
+		return NULL;
+
+	file = malloc(strlen(tracing) + strlen(name) + 2);
+	if (!file)
+		return NULL;
+
+	sprintf(file, "%s/%s", tracing, name);
+	return file;
+}
+
+void put_tracing_file(char *file)
+{
+	free(file);
+}
+
+int parse_nsec_time(const char *str, u64 *ptime)
+{
+	u64 time_sec, time_nsec;
+	char *end;
+
+	time_sec = strtoul(str, &end, 10);
+	if (*end != '.' && *end != '\0')
+		return -1;
+
+	if (*end == '.') {
+		int i;
+		char nsec_buf[10];
+
+		if (strlen(++end) > 9)
+			return -1;
+
+		strncpy(nsec_buf, end, 9);
+		nsec_buf[9] = '\0';
+
+		/* make it nsec precision */
+		for (i = strlen(nsec_buf); i < 9; i++)
+			nsec_buf[i] = '0';
+
+		time_nsec = strtoul(nsec_buf, &end, 10);
+		if (*end != '\0')
+			return -1;
+	} else
+		time_nsec = 0;
+
+	*ptime = time_sec * NSEC_PER_SEC + time_nsec;
+	return 0;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 2732fad..a535359 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -80,6 +80,9 @@
 extern char tracing_events_path[];
 extern void perf_debugfs_set_path(const char *mountpoint);
 const char *perf_debugfs_mount(const char *mountpoint);
+const char *find_tracing_dir(void);
+char *get_tracing_file(const char *name);
+void put_tracing_file(char *file);
 
 /* On most systems <limits.h> would have given us this, but
  * not on some systems (e.g. GNU/Hurd).
@@ -205,6 +208,8 @@
 #define NSEC_PER_MSEC	1000000L
 #endif
 
+int parse_nsec_time(const char *str, u64 *ptime);
+
 extern unsigned char sane_ctype[256];
 #define GIT_SPACE		0x01
 #define GIT_DIGIT		0x02
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 17c5ac7..685fc72 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -149,7 +149,7 @@
 {
 	offset >>= 2;
 	BUG_ON(offset > (VGIC_NR_IRQS / 4));
-	if (offset < 4)
+	if (offset < 8)
 		return x->percpu[cpuid] + offset;
 	else
 		return x->shared + offset - 8;
@@ -432,19 +432,13 @@
 static u32 vgic_get_target_reg(struct kvm *kvm, int irq)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
-	struct kvm_vcpu *vcpu;
-	int i, c;
-	unsigned long *bmap;
+	int i;
 	u32 val = 0;
 
 	irq -= VGIC_NR_PRIVATE_IRQS;
 
-	kvm_for_each_vcpu(c, vcpu, kvm) {
-		bmap = vgic_bitmap_get_shared_map(&dist->irq_spi_target[c]);
-		for (i = 0; i < GICD_IRQS_PER_ITARGETSR; i++)
-			if (test_bit(irq + i, bmap))
-				val |= 1 << (c + i * 8);
-	}
+	for (i = 0; i < GICD_IRQS_PER_ITARGETSR; i++)
+		val |= 1 << (dist->irq_spi_cpu[irq + i] + i * 8);
 
 	return val;
 }
@@ -547,8 +541,12 @@
 				struct kvm_exit_mmio *mmio, phys_addr_t offset)
 {
 	u32 val;
-	u32 *reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
-				       vcpu->vcpu_id, offset >> 1);
+	u32 *reg;
+
+	offset >>= 1;
+	reg = vgic_bitmap_get_reg(&vcpu->kvm->arch.vgic.irq_cfg,
+				  vcpu->vcpu_id, offset);
+
 	if (offset & 2)
 		val = *reg >> 16;
 	else
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1580dd4..bf040c4 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -102,28 +102,8 @@
 
 bool kvm_is_mmio_pfn(pfn_t pfn)
 {
-	if (pfn_valid(pfn)) {
-		int reserved;
-		struct page *tail = pfn_to_page(pfn);
-		struct page *head = compound_trans_head(tail);
-		reserved = PageReserved(head);
-		if (head != tail) {
-			/*
-			 * "head" is not a dangling pointer
-			 * (compound_trans_head takes care of that)
-			 * but the hugepage may have been splitted
-			 * from under us (and we may not hold a
-			 * reference count on the head page so it can
-			 * be reused before we run PageReferenced), so
-			 * we've to check PageTail before returning
-			 * what we just read.
-			 */
-			smp_rmb();
-			if (PageTail(tail))
-				return reserved;
-		}
-		return PageReserved(tail);
-	}
+	if (pfn_valid(pfn))
+		return PageReserved(pfn_to_page(pfn));
 
 	return true;
 }
@@ -731,7 +711,10 @@
 	update_memslots(slots, new, kvm->memslots->generation);
 	rcu_assign_pointer(kvm->memslots, slots);
 	synchronize_srcu_expedited(&kvm->srcu);
-	return old_memslots; 
+
+	kvm_arch_memslots_updated(kvm);
+
+	return old_memslots;
 }
 
 /*
@@ -1893,7 +1876,7 @@
  */
 static int create_vcpu_fd(struct kvm_vcpu *vcpu)
 {
-	return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, O_RDWR);
+	return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, O_RDWR | O_CLOEXEC);
 }
 
 /*
@@ -2302,7 +2285,7 @@
 		return ret;
 	}
 
-	ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR);
+	ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
 	if (ret < 0) {
 		ops->destroy(dev);
 		return ret;
@@ -2586,7 +2569,7 @@
 		return r;
 	}
 #endif
-	r = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR);
+	r = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR | O_CLOEXEC);
 	if (r < 0)
 		kvm_put_kvm(kvm);
 
@@ -2812,11 +2795,9 @@
 	kfree(bus);
 }
 
-static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
+static inline int kvm_io_bus_cmp(const struct kvm_io_range *r1,
+                                 const struct kvm_io_range *r2)
 {
-	const struct kvm_io_range *r1 = p1;
-	const struct kvm_io_range *r2 = p2;
-
 	if (r1->addr < r2->addr)
 		return -1;
 	if (r1->addr + r1->len > r2->addr + r2->len)
@@ -2824,6 +2805,11 @@
 	return 0;
 }
 
+static int kvm_io_bus_sort_cmp(const void *p1, const void *p2)
+{
+	return kvm_io_bus_cmp(p1, p2);
+}
+
 static int kvm_io_bus_insert_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev,
 			  gpa_t addr, int len)
 {
@@ -2857,17 +2843,54 @@
 
 	off = range - bus->range;
 
-	while (off > 0 && kvm_io_bus_sort_cmp(&key, &bus->range[off-1]) == 0)
+	while (off > 0 && kvm_io_bus_cmp(&key, &bus->range[off-1]) == 0)
 		off--;
 
 	return off;
 }
 
+static int __kvm_io_bus_write(struct kvm_io_bus *bus,
+			      struct kvm_io_range *range, const void *val)
+{
+	int idx;
+
+	idx = kvm_io_bus_get_first_dev(bus, range->addr, range->len);
+	if (idx < 0)
+		return -EOPNOTSUPP;
+
+	while (idx < bus->dev_count &&
+		kvm_io_bus_cmp(range, &bus->range[idx]) == 0) {
+		if (!kvm_iodevice_write(bus->range[idx].dev, range->addr,
+					range->len, val))
+			return idx;
+		idx++;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 /* kvm_io_bus_write - called under kvm->slots_lock */
 int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 		     int len, const void *val)
 {
-	int idx;
+	struct kvm_io_bus *bus;
+	struct kvm_io_range range;
+	int r;
+
+	range = (struct kvm_io_range) {
+		.addr = addr,
+		.len = len,
+	};
+
+	bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
+	r = __kvm_io_bus_write(bus, &range, val);
+	return r < 0 ? r : 0;
+}
+
+/* kvm_io_bus_write_cookie - called under kvm->slots_lock */
+int kvm_io_bus_write_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+			    int len, const void *val, long cookie)
+{
 	struct kvm_io_bus *bus;
 	struct kvm_io_range range;
 
@@ -2877,14 +2900,35 @@
 	};
 
 	bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
-	idx = kvm_io_bus_get_first_dev(bus, addr, len);
+
+	/* First try the device referenced by cookie. */
+	if ((cookie >= 0) && (cookie < bus->dev_count) &&
+	    (kvm_io_bus_cmp(&range, &bus->range[cookie]) == 0))
+		if (!kvm_iodevice_write(bus->range[cookie].dev, addr, len,
+					val))
+			return cookie;
+
+	/*
+	 * cookie contained garbage; fall back to search and return the
+	 * correct cookie value.
+	 */
+	return __kvm_io_bus_write(bus, &range, val);
+}
+
+static int __kvm_io_bus_read(struct kvm_io_bus *bus, struct kvm_io_range *range,
+			     void *val)
+{
+	int idx;
+
+	idx = kvm_io_bus_get_first_dev(bus, range->addr, range->len);
 	if (idx < 0)
 		return -EOPNOTSUPP;
 
 	while (idx < bus->dev_count &&
-		kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
-		if (!kvm_iodevice_write(bus->range[idx].dev, addr, len, val))
-			return 0;
+		kvm_io_bus_cmp(range, &bus->range[idx]) == 0) {
+		if (!kvm_iodevice_read(bus->range[idx].dev, range->addr,
+				       range->len, val))
+			return idx;
 		idx++;
 	}
 
@@ -2895,7 +2939,24 @@
 int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
 		    int len, void *val)
 {
-	int idx;
+	struct kvm_io_bus *bus;
+	struct kvm_io_range range;
+	int r;
+
+	range = (struct kvm_io_range) {
+		.addr = addr,
+		.len = len,
+	};
+
+	bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
+	r = __kvm_io_bus_read(bus, &range, val);
+	return r < 0 ? r : 0;
+}
+
+/* kvm_io_bus_read_cookie - called under kvm->slots_lock */
+int kvm_io_bus_read_cookie(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+			   int len, void *val, long cookie)
+{
 	struct kvm_io_bus *bus;
 	struct kvm_io_range range;
 
@@ -2905,18 +2966,19 @@
 	};
 
 	bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
-	idx = kvm_io_bus_get_first_dev(bus, addr, len);
-	if (idx < 0)
-		return -EOPNOTSUPP;
 
-	while (idx < bus->dev_count &&
-		kvm_io_bus_sort_cmp(&range, &bus->range[idx]) == 0) {
-		if (!kvm_iodevice_read(bus->range[idx].dev, addr, len, val))
-			return 0;
-		idx++;
-	}
+	/* First try the device referenced by cookie. */
+	if ((cookie >= 0) && (cookie < bus->dev_count) &&
+	    (kvm_io_bus_cmp(&range, &bus->range[cookie]) == 0))
+		if (!kvm_iodevice_read(bus->range[cookie].dev, addr, len,
+				       val))
+			return cookie;
 
-	return -EOPNOTSUPP;
+	/*
+	 * cookie contained garbage; fall back to search and return the
+	 * correct cookie value.
+	 */
+	return __kvm_io_bus_read(bus, &range, val);
 }
 
 /* Caller must hold slots_lock. */